summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Kconfig4
-rw-r--r--drivers/acpi/Kconfig6
-rw-r--r--drivers/acpi/Makefile4
-rw-r--r--drivers/acpi/acpi_apd.c150
-rw-r--r--drivers/acpi/acpi_lpat.c161
-rw-r--r--drivers/acpi/acpi_lpss.c64
-rw-r--r--drivers/acpi/acpi_memhotplug.c8
-rw-r--r--drivers/acpi/acpi_platform.c4
-rw-r--r--drivers/acpi/acpica/acapps.h4
-rw-r--r--drivers/acpi/acpica/accommon.h2
-rw-r--r--drivers/acpi/acpica/acdebug.h2
-rw-r--r--drivers/acpi/acpica/acdispat.h2
-rw-r--r--drivers/acpi/acpica/acevents.h4
-rw-r--r--drivers/acpi/acpica/acglobal.h2
-rw-r--r--drivers/acpi/acpica/achware.h2
-rw-r--r--drivers/acpi/acpica/acinterp.h2
-rw-r--r--drivers/acpi/acpica/aclocal.h2
-rw-r--r--drivers/acpi/acpica/acmacros.h2
-rw-r--r--drivers/acpi/acpica/acnamesp.h2
-rw-r--r--drivers/acpi/acpica/acobject.h2
-rw-r--r--drivers/acpi/acpica/acopcode.h2
-rw-r--r--drivers/acpi/acpica/acparser.h2
-rw-r--r--drivers/acpi/acpica/acpredef.h2
-rw-r--r--drivers/acpi/acpica/acresrc.h2
-rw-r--r--drivers/acpi/acpica/acstruct.h2
-rw-r--r--drivers/acpi/acpica/actables.h2
-rw-r--r--drivers/acpi/acpica/acutils.h2
-rw-r--r--drivers/acpi/acpica/amlcode.h2
-rw-r--r--drivers/acpi/acpica/amlresrc.h2
-rw-r--r--drivers/acpi/acpica/dsargs.c2
-rw-r--r--drivers/acpi/acpica/dscontrol.c2
-rw-r--r--drivers/acpi/acpica/dsfield.c2
-rw-r--r--drivers/acpi/acpica/dsinit.c2
-rw-r--r--drivers/acpi/acpica/dsmethod.c2
-rw-r--r--drivers/acpi/acpica/dsmthdat.c2
-rw-r--r--drivers/acpi/acpica/dsobject.c2
-rw-r--r--drivers/acpi/acpica/dsopcode.c2
-rw-r--r--drivers/acpi/acpica/dsutils.c2
-rw-r--r--drivers/acpi/acpica/dswexec.c2
-rw-r--r--drivers/acpi/acpica/dswload.c2
-rw-r--r--drivers/acpi/acpica/dswload2.c2
-rw-r--r--drivers/acpi/acpica/dswscope.c2
-rw-r--r--drivers/acpi/acpica/dswstate.c2
-rw-r--r--drivers/acpi/acpica/evevent.c2
-rw-r--r--drivers/acpi/acpica/evglock.c2
-rw-r--r--drivers/acpi/acpica/evgpe.c164
-rw-r--r--drivers/acpi/acpica/evgpeblk.c10
-rw-r--r--drivers/acpi/acpica/evgpeinit.c10
-rw-r--r--drivers/acpi/acpica/evgpeutil.c61
-rw-r--r--drivers/acpi/acpica/evhandler.c2
-rw-r--r--drivers/acpi/acpica/evmisc.c2
-rw-r--r--drivers/acpi/acpica/evregion.c2
-rw-r--r--drivers/acpi/acpica/evrgnini.c2
-rw-r--r--drivers/acpi/acpica/evsci.c2
-rw-r--r--drivers/acpi/acpica/evxface.c132
-rw-r--r--drivers/acpi/acpica/evxfevnt.c2
-rw-r--r--drivers/acpi/acpica/evxfgpe.c123
-rw-r--r--drivers/acpi/acpica/evxfregn.c2
-rw-r--r--drivers/acpi/acpica/exconfig.c2
-rw-r--r--drivers/acpi/acpica/exconvrt.c2
-rw-r--r--drivers/acpi/acpica/excreate.c2
-rw-r--r--drivers/acpi/acpica/exdebug.c2
-rw-r--r--drivers/acpi/acpica/exdump.c2
-rw-r--r--drivers/acpi/acpica/exfield.c2
-rw-r--r--drivers/acpi/acpica/exfldio.c2
-rw-r--r--drivers/acpi/acpica/exmisc.c2
-rw-r--r--drivers/acpi/acpica/exmutex.c2
-rw-r--r--drivers/acpi/acpica/exnames.c2
-rw-r--r--drivers/acpi/acpica/exoparg1.c2
-rw-r--r--drivers/acpi/acpica/exoparg2.c2
-rw-r--r--drivers/acpi/acpica/exoparg3.c2
-rw-r--r--drivers/acpi/acpica/exoparg6.c2
-rw-r--r--drivers/acpi/acpica/exprep.c2
-rw-r--r--drivers/acpi/acpica/exregion.c2
-rw-r--r--drivers/acpi/acpica/exresnte.c2
-rw-r--r--drivers/acpi/acpica/exresolv.c2
-rw-r--r--drivers/acpi/acpica/exresop.c2
-rw-r--r--drivers/acpi/acpica/exstore.c2
-rw-r--r--drivers/acpi/acpica/exstoren.c2
-rw-r--r--drivers/acpi/acpica/exstorob.c2
-rw-r--r--drivers/acpi/acpica/exsystem.c2
-rw-r--r--drivers/acpi/acpica/exutils.c2
-rw-r--r--drivers/acpi/acpica/hwacpi.c2
-rw-r--r--drivers/acpi/acpica/hwesleep.c2
-rw-r--r--drivers/acpi/acpica/hwgpe.c10
-rw-r--r--drivers/acpi/acpica/hwpci.c2
-rw-r--r--drivers/acpi/acpica/hwregs.c2
-rw-r--r--drivers/acpi/acpica/hwsleep.c2
-rw-r--r--drivers/acpi/acpica/hwtimer.c2
-rw-r--r--drivers/acpi/acpica/hwvalid.c2
-rw-r--r--drivers/acpi/acpica/hwxface.c2
-rw-r--r--drivers/acpi/acpica/hwxfsleep.c2
-rw-r--r--drivers/acpi/acpica/nsaccess.c2
-rw-r--r--drivers/acpi/acpica/nsalloc.c2
-rw-r--r--drivers/acpi/acpica/nsarguments.c2
-rw-r--r--drivers/acpi/acpica/nsconvert.c2
-rw-r--r--drivers/acpi/acpica/nsdump.c2
-rw-r--r--drivers/acpi/acpica/nsdumpdv.c2
-rw-r--r--drivers/acpi/acpica/nseval.c2
-rw-r--r--drivers/acpi/acpica/nsinit.c2
-rw-r--r--drivers/acpi/acpica/nsload.c2
-rw-r--r--drivers/acpi/acpica/nsnames.c2
-rw-r--r--drivers/acpi/acpica/nsobject.c2
-rw-r--r--drivers/acpi/acpica/nsparse.c2
-rw-r--r--drivers/acpi/acpica/nspredef.c2
-rw-r--r--drivers/acpi/acpica/nsprepkg.c2
-rw-r--r--drivers/acpi/acpica/nsrepair.c2
-rw-r--r--drivers/acpi/acpica/nsrepair2.c2
-rw-r--r--drivers/acpi/acpica/nssearch.c2
-rw-r--r--drivers/acpi/acpica/nsutils.c2
-rw-r--r--drivers/acpi/acpica/nswalk.c2
-rw-r--r--drivers/acpi/acpica/nsxfeval.c2
-rw-r--r--drivers/acpi/acpica/nsxfname.c2
-rw-r--r--drivers/acpi/acpica/nsxfobj.c46
-rw-r--r--drivers/acpi/acpica/psargs.c2
-rw-r--r--drivers/acpi/acpica/psloop.c2
-rw-r--r--drivers/acpi/acpica/psobject.c2
-rw-r--r--drivers/acpi/acpica/psopcode.c2
-rw-r--r--drivers/acpi/acpica/psopinfo.c2
-rw-r--r--drivers/acpi/acpica/psparse.c2
-rw-r--r--drivers/acpi/acpica/psscope.c2
-rw-r--r--drivers/acpi/acpica/pstree.c2
-rw-r--r--drivers/acpi/acpica/psutils.c2
-rw-r--r--drivers/acpi/acpica/pswalk.c2
-rw-r--r--drivers/acpi/acpica/psxface.c2
-rw-r--r--drivers/acpi/acpica/rsaddr.c11
-rw-r--r--drivers/acpi/acpica/rscalc.c2
-rw-r--r--drivers/acpi/acpica/rscreate.c2
-rw-r--r--drivers/acpi/acpica/rsdump.c2
-rw-r--r--drivers/acpi/acpica/rsdumpinfo.c61
-rw-r--r--drivers/acpi/acpica/rsinfo.c2
-rw-r--r--drivers/acpi/acpica/rsio.c2
-rw-r--r--drivers/acpi/acpica/rsirq.c2
-rw-r--r--drivers/acpi/acpica/rslist.c2
-rw-r--r--drivers/acpi/acpica/rsmemory.c2
-rw-r--r--drivers/acpi/acpica/rsmisc.c2
-rw-r--r--drivers/acpi/acpica/rsserial.c2
-rw-r--r--drivers/acpi/acpica/rsutils.c2
-rw-r--r--drivers/acpi/acpica/rsxface.c12
-rw-r--r--drivers/acpi/acpica/tbdata.c2
-rw-r--r--drivers/acpi/acpica/tbfadt.c2
-rw-r--r--drivers/acpi/acpica/tbfind.c2
-rw-r--r--drivers/acpi/acpica/tbinstal.c2
-rw-r--r--drivers/acpi/acpica/tbprint.c2
-rw-r--r--drivers/acpi/acpica/tbutils.c2
-rw-r--r--drivers/acpi/acpica/tbxface.c41
-rw-r--r--drivers/acpi/acpica/tbxfload.c2
-rw-r--r--drivers/acpi/acpica/tbxfroot.c2
-rw-r--r--drivers/acpi/acpica/utaddress.c2
-rw-r--r--drivers/acpi/acpica/utalloc.c2
-rw-r--r--drivers/acpi/acpica/utbuffer.c2
-rw-r--r--drivers/acpi/acpica/utcache.c2
-rw-r--r--drivers/acpi/acpica/utcopy.c2
-rw-r--r--drivers/acpi/acpica/utdebug.c6
-rw-r--r--drivers/acpi/acpica/utdecode.c2
-rw-r--r--drivers/acpi/acpica/utdelete.c2
-rw-r--r--drivers/acpi/acpica/uterror.c2
-rw-r--r--drivers/acpi/acpica/uteval.c2
-rw-r--r--drivers/acpi/acpica/utexcep.c2
-rw-r--r--drivers/acpi/acpica/utfileio.c2
-rw-r--r--drivers/acpi/acpica/utglobal.c2
-rw-r--r--drivers/acpi/acpica/uthex.c2
-rw-r--r--drivers/acpi/acpica/utids.c2
-rw-r--r--drivers/acpi/acpica/utinit.c2
-rw-r--r--drivers/acpi/acpica/utlock.c2
-rw-r--r--drivers/acpi/acpica/utmath.c2
-rw-r--r--drivers/acpi/acpica/utmisc.c2
-rw-r--r--drivers/acpi/acpica/utmutex.c2
-rw-r--r--drivers/acpi/acpica/utobject.c2
-rw-r--r--drivers/acpi/acpica/utosi.c2
-rw-r--r--drivers/acpi/acpica/utownerid.c2
-rw-r--r--drivers/acpi/acpica/utpredef.c2
-rw-r--r--drivers/acpi/acpica/utprint.c2
-rw-r--r--drivers/acpi/acpica/utresrc.c2
-rw-r--r--drivers/acpi/acpica/utstate.c2
-rw-r--r--drivers/acpi/acpica/utstring.c2
-rw-r--r--drivers/acpi/acpica/uttrack.c2
-rw-r--r--drivers/acpi/acpica/utuuid.c2
-rw-r--r--drivers/acpi/acpica/utxface.c2
-rw-r--r--drivers/acpi/acpica/utxferror.c2
-rw-r--r--drivers/acpi/acpica/utxfinit.c2
-rw-r--r--drivers/acpi/acpica/utxfmutex.c2
-rw-r--r--drivers/acpi/apei/apei-base.c32
-rw-r--r--drivers/acpi/device_pm.c2
-rw-r--r--drivers/acpi/ec.c453
-rw-r--r--drivers/acpi/event.c7
-rw-r--r--drivers/acpi/internal.h11
-rw-r--r--drivers/acpi/ioapic.c229
-rw-r--r--drivers/acpi/numa.c12
-rw-r--r--drivers/acpi/pci_irq.c9
-rw-r--r--drivers/acpi/pci_root.c9
-rw-r--r--drivers/acpi/pmic/intel_pmic.c133
-rw-r--r--drivers/acpi/processor_core.c123
-rw-r--r--drivers/acpi/processor_idle.c216
-rw-r--r--drivers/acpi/resource.c353
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/sleep.c2
-rw-r--r--drivers/acpi/video.c27
-rw-r--r--drivers/amba/bus.c47
-rw-r--r--drivers/android/binder.c26
-rw-r--r--drivers/ata/ahci.h6
-rw-r--r--drivers/ata/ahci_da850.c11
-rw-r--r--drivers/ata/ahci_imx.c25
-rw-r--r--drivers/ata/ahci_mvebu.c11
-rw-r--r--drivers/ata/ahci_platform.c11
-rw-r--r--drivers/ata/ahci_st.c11
-rw-r--r--drivers/ata/ahci_sunxi.c11
-rw-r--r--drivers/ata/ahci_tegra.c11
-rw-r--r--drivers/ata/ahci_xgene.c203
-rw-r--r--drivers/ata/libahci_platform.c249
-rw-r--r--drivers/ata/libata-core.c97
-rw-r--r--drivers/ata/libata-eh.c21
-rw-r--r--drivers/ata/libata-scsi.c37
-rw-r--r--drivers/ata/libata.h5
-rw-r--r--drivers/ata/pata_cs5530.c6
-rw-r--r--drivers/ata/pata_of_platform.c10
-rw-r--r--drivers/ata/pata_pdc2027x.c10
-rw-r--r--drivers/ata/pata_platform.c8
-rw-r--r--drivers/ata/sata_dwc_460ex.c116
-rw-r--r--drivers/ata/sata_mv.c6
-rw-r--r--drivers/ata/sata_rcar.c25
-rw-r--r--drivers/ata/sata_sil24.c1
-rw-r--r--drivers/atm/eni.c33
-rw-r--r--drivers/atm/fore200e.c22
-rw-r--r--drivers/atm/he.c125
-rw-r--r--drivers/atm/he.h4
-rw-r--r--drivers/atm/horizon.c24
-rw-r--r--drivers/atm/idt77252.c107
-rw-r--r--drivers/atm/iphase.c54
-rw-r--r--drivers/atm/lanai.c23
-rw-r--r--drivers/atm/nicstar.c60
-rw-r--r--drivers/atm/solos-pci.c26
-rw-r--r--drivers/atm/zatm.c17
-rw-r--r--drivers/base/core.c29
-rw-r--r--drivers/base/cpu.c2
-rw-r--r--drivers/base/firmware_class.c34
-rw-r--r--drivers/base/node.c3
-rw-r--r--drivers/base/power/clock_ops.c4
-rw-r--r--drivers/base/power/common.c18
-rw-r--r--drivers/base/power/domain.c157
-rw-r--r--drivers/base/power/opp.c202
-rw-r--r--drivers/base/power/qos.c4
-rw-r--r--drivers/base/regmap/internal.h10
-rw-r--r--drivers/base/regmap/regmap-ac97.c4
-rw-r--r--drivers/base/regmap/regmap-i2c.c46
-rw-r--r--drivers/base/regmap/regmap.c7
-rw-r--r--drivers/bcma/bcma_private.h18
-rw-r--r--drivers/bcma/driver_chipcommon.c20
-rw-r--r--drivers/bcma/driver_pci.c68
-rw-r--r--drivers/bcma/host_pci.c6
-rw-r--r--drivers/bcma/host_soc.c2
-rw-r--r--drivers/bcma/main.c76
-rw-r--r--drivers/bcma/scan.c67
-rw-r--r--drivers/bcma/sprom.c3
-rw-r--r--drivers/block/Kconfig13
-rw-r--r--drivers/block/brd.c137
-rw-r--r--drivers/block/drbd/drbd_receiver.c2
-rw-r--r--drivers/block/floppy.c17
-rw-r--r--drivers/block/loop.c416
-rw-r--r--drivers/block/loop.h18
-rw-r--r--drivers/block/null_blk.c2
-rw-r--r--drivers/block/nvme-core.c641
-rw-r--r--drivers/block/nvme-scsi.c96
-rw-r--r--drivers/block/osdblk.c2
-rw-r--r--drivers/block/rbd.c218
-rw-r--r--drivers/block/virtio_blk.c12
-rw-r--r--drivers/block/xen-blkback/blkback.c177
-rw-r--r--drivers/block/xen-blkback/common.h12
-rw-r--r--drivers/block/xen-blkback/xenbus.c4
-rw-r--r--drivers/block/xen-blkfront.c6
-rw-r--r--drivers/block/zram/zram_drv.c229
-rw-r--r--drivers/block/zram/zram_drv.h21
-rw-r--r--drivers/bluetooth/ath3k.c10
-rw-r--r--drivers/bluetooth/bfusb.c2
-rw-r--r--drivers/bluetooth/btmrvl_drv.h5
-rw-r--r--drivers/bluetooth/btmrvl_main.c32
-rw-r--r--drivers/bluetooth/btmrvl_sdio.c6
-rw-r--r--drivers/bluetooth/btusb.c710
-rw-r--r--drivers/bluetooth/hci_ath.c15
-rw-r--r--drivers/bus/arm-cci.c4
-rw-r--r--drivers/bus/mvebu-mbus.c286
-rw-r--r--drivers/char/Kconfig9
-rw-r--r--drivers/char/agp/agp.h5
-rw-r--r--drivers/char/agp/generic.c11
-rw-r--r--drivers/char/agp/intel-gtt.c14
-rw-r--r--drivers/char/hpet.c4
-rw-r--r--drivers/char/hw_random/core.c215
-rw-r--r--drivers/char/hw_random/virtio-rng.c1
-rw-r--r--drivers/char/i8k.c316
-rw-r--r--drivers/char/ipmi/ipmi_devintf.c6
-rw-r--r--drivers/char/ipmi/ipmi_msghandler.c102
-rw-r--r--drivers/char/ipmi/ipmi_si_intf.c121
-rw-r--r--drivers/char/ipmi/ipmi_ssif.c6
-rw-r--r--drivers/char/mem.c86
-rw-r--r--drivers/char/random.c8
-rw-r--r--drivers/char/raw.c4
-rw-r--r--drivers/char/tpm/Kconfig15
-rw-r--r--drivers/char/tpm/Makefile5
-rw-r--r--drivers/char/tpm/tpm-chip.c256
-rw-r--r--drivers/char/tpm/tpm-dev.c42
-rw-r--r--drivers/char/tpm/tpm-interface.c265
-rw-r--r--drivers/char/tpm/tpm-sysfs.c29
-rw-r--r--drivers/char/tpm/tpm.h125
-rw-r--r--drivers/char/tpm/tpm2-cmd.c646
-rw-r--r--drivers/char/tpm/tpm_atmel.c25
-rw-r--r--drivers/char/tpm/tpm_crb.c344
-rw-r--r--drivers/char/tpm/tpm_i2c_atmel.c52
-rw-r--r--drivers/char/tpm/tpm_i2c_infineon.c43
-rw-r--r--drivers/char/tpm/tpm_i2c_nuvoton.c69
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.c666
-rw-r--r--drivers/char/tpm/tpm_i2c_stm_st33.h61
-rw-r--r--drivers/char/tpm/tpm_ibmvtpm.c47
-rw-r--r--drivers/char/tpm/tpm_ibmvtpm.h2
-rw-r--r--drivers/char/tpm/tpm_infineon.c51
-rw-r--r--drivers/char/tpm/tpm_nsc.c34
-rw-r--r--drivers/char/tpm/tpm_of.c2
-rw-r--r--drivers/char/tpm/tpm_ppi.c141
-rw-r--r--drivers/char/tpm/tpm_tis.c269
-rw-r--r--drivers/char/tpm/xen-tpmfront.c14
-rw-r--r--drivers/char/virtio_console.c9
-rw-r--r--drivers/clk/Kconfig19
-rw-r--r--drivers/clk/Makefile4
-rw-r--r--drivers/clk/at91/clk-programmable.c2
-rw-r--r--drivers/clk/at91/pmc.c9
-rw-r--r--drivers/clk/bcm/clk-kona.c2
-rw-r--r--drivers/clk/clk-asm9260.c348
-rw-r--r--drivers/clk/clk-cdce706.c700
-rw-r--r--drivers/clk/clk-composite.c29
-rw-r--r--drivers/clk/clk-divider.c228
-rw-r--r--drivers/clk/clk-gate.c18
-rw-r--r--drivers/clk/clk-mux.c16
-rw-r--r--drivers/clk/clk-ppc-corenet.c306
-rw-r--r--drivers/clk/clk-qoriq.c362
-rw-r--r--drivers/clk/clk.c1021
-rw-r--r--drivers/clk/clk.h24
-rw-r--r--drivers/clk/clkdev.c110
-rw-r--r--drivers/clk/hisilicon/clk-hi3620.c2
-rw-r--r--drivers/clk/mmp/clk-mix.c2
-rw-r--r--drivers/clk/pxa/Makefile1
-rw-r--r--drivers/clk/pxa/clk-pxa.c2
-rw-r--r--drivers/clk/pxa/clk-pxa3xx.c364
-rw-r--r--drivers/clk/qcom/Kconfig18
-rw-r--r--drivers/clk/qcom/Makefile4
-rw-r--r--drivers/clk/qcom/clk-pll.c1
-rw-r--r--drivers/clk/qcom/clk-rcg.c10
-rw-r--r--drivers/clk/qcom/clk-rcg2.c6
-rw-r--r--drivers/clk/qcom/clk-regmap-divider.c70
-rw-r--r--drivers/clk/qcom/clk-regmap-divider.h29
-rw-r--r--drivers/clk/qcom/clk-regmap-mux.c59
-rw-r--r--drivers/clk/qcom/clk-regmap-mux.h29
-rw-r--r--drivers/clk/qcom/gcc-ipq806x.c12
-rw-r--r--drivers/clk/qcom/lcc-ipq806x.c473
-rw-r--r--drivers/clk/qcom/lcc-msm8960.c585
-rw-r--r--drivers/clk/rockchip/clk-rk3288.c62
-rw-r--r--drivers/clk/samsung/clk-exynos-audss.c32
-rw-r--r--drivers/clk/samsung/clk-exynos3250.c217
-rw-r--r--drivers/clk/samsung/clk-exynos4.c10
-rw-r--r--drivers/clk/samsung/clk-exynos4415.c216
-rw-r--r--drivers/clk/samsung/clk-exynos5420.c23
-rw-r--r--drivers/clk/samsung/clk-exynos7.c408
-rw-r--r--drivers/clk/samsung/clk.c13
-rw-r--r--drivers/clk/samsung/clk.h3
-rw-r--r--drivers/clk/shmobile/Makefile3
-rw-r--r--drivers/clk/shmobile/clk-div6.c18
-rw-r--r--drivers/clk/shmobile/clk-r8a73a4.c241
-rw-r--r--drivers/clk/shmobile/clk-rcar-gen2.c88
-rw-r--r--drivers/clk/shmobile/clk-sh73a0.c218
-rw-r--r--drivers/clk/st/clk-flexgen.c39
-rw-r--r--drivers/clk/st/clkgen-mux.c14
-rw-r--r--drivers/clk/sunxi/Makefile1
-rw-r--r--drivers/clk/sunxi/clk-factors.c12
-rw-r--r--drivers/clk/sunxi/clk-factors.h7
-rw-r--r--drivers/clk/sunxi/clk-mod0.c224
-rw-r--r--drivers/clk/sunxi/clk-sun6i-ar100.c2
-rw-r--r--drivers/clk/sunxi/clk-sun8i-mbus.c13
-rw-r--r--drivers/clk/sunxi/clk-sun9i-core.c119
-rw-r--r--drivers/clk/sunxi/clk-sun9i-mmc.c219
-rw-r--r--drivers/clk/sunxi/clk-sunxi.c263
-rw-r--r--drivers/clk/tegra/Makefile1
-rw-r--r--drivers/clk/tegra/clk-id.h2
-rw-r--r--drivers/clk/tegra/clk-periph.c14
-rw-r--r--drivers/clk/tegra/clk-pll.c18
-rw-r--r--drivers/clk/tegra/clk-tegra-periph.c18
-rw-r--r--drivers/clk/tegra/clk-tegra114.c10
-rw-r--r--drivers/clk/tegra/clk-tegra124.c168
-rw-r--r--drivers/clk/tegra/clk.c7
-rw-r--r--drivers/clk/ti/Makefile8
-rw-r--r--drivers/clk/ti/clk-3xxx-legacy.c4653
-rw-r--r--drivers/clk/ti/clk-3xxx.c8
-rw-r--r--drivers/clk/ti/clk-44xx.c2
-rw-r--r--drivers/clk/ti/clk-54xx.c2
-rw-r--r--drivers/clk/ti/clk-7xx.c2
-rw-r--r--drivers/clk/ti/clk-816x.c53
-rw-r--r--drivers/clk/ti/clk.c127
-rw-r--r--drivers/clk/ti/clock.h172
-rw-r--r--drivers/clk/ti/composite.c48
-rw-r--r--drivers/clk/ti/divider.c132
-rw-r--r--drivers/clk/ti/dpll.c121
-rw-r--r--drivers/clk/ti/fapll.c410
-rw-r--r--drivers/clk/ti/gate.c163
-rw-r--r--drivers/clk/ti/interface.c98
-rw-r--r--drivers/clk/ti/mux.c70
-rw-r--r--drivers/clk/ux500/clk-prcc.c1
-rw-r--r--drivers/clk/ux500/clk-prcmu.c1
-rw-r--r--drivers/clk/zynq/clkc.c1
-rw-r--r--drivers/clocksource/Kconfig21
-rw-r--r--drivers/clocksource/Makefile9
-rw-r--r--drivers/clocksource/arm_arch_timer.c1
-rw-r--r--drivers/clocksource/asm9260_timer.c220
-rw-r--r--drivers/clocksource/mtk_timer.c9
-rw-r--r--drivers/clocksource/pxa_timer.c2
-rw-r--r--drivers/clocksource/rockchip_timer.c180
-rw-r--r--drivers/clocksource/timer-atlas7.c306
-rw-r--r--drivers/clocksource/timer-digicolor.c199
-rw-r--r--drivers/clocksource/timer-marco.c307
-rw-r--r--drivers/clocksource/versatile.c4
-rw-r--r--drivers/connector/Kconfig2
-rw-r--r--drivers/coresight/coresight-etb10.c14
-rw-r--r--drivers/coresight/coresight-etm3x.c24
-rw-r--r--drivers/coresight/coresight-funnel.c12
-rw-r--r--drivers/coresight/coresight-priv.h2
-rw-r--r--drivers/coresight/coresight-replicator.c2
-rw-r--r--drivers/coresight/coresight-tmc.c12
-rw-r--r--drivers/coresight/coresight-tpiu.c12
-rw-r--r--drivers/coresight/coresight.c11
-rw-r--r--drivers/coresight/of_coresight.c22
-rw-r--r--drivers/cpufreq/Kconfig1
-rw-r--r--drivers/cpufreq/Kconfig.arm44
-rw-r--r--drivers/cpufreq/Kconfig.powerpc2
-rw-r--r--drivers/cpufreq/Kconfig.x8610
-rw-r--r--drivers/cpufreq/Makefile10
-rw-r--r--drivers/cpufreq/cpufreq-dt.c3
-rw-r--r--drivers/cpufreq/cpufreq.c174
-rw-r--r--drivers/cpufreq/cpufreq_stats.c219
-rw-r--r--drivers/cpufreq/exynos-cpufreq.c33
-rw-r--r--drivers/cpufreq/intel_pstate.c55
-rw-r--r--drivers/cpufreq/ls1x-cpufreq.c1
-rw-r--r--drivers/cpufreq/s3c2416-cpufreq.c4
-rw-r--r--drivers/cpufreq/s3c24xx-cpufreq.c10
-rw-r--r--drivers/cpufreq/sfi-cpufreq.c136
-rw-r--r--drivers/cpufreq/speedstep-lib.c3
-rw-r--r--drivers/cpufreq/speedstep-smi.c12
-rw-r--r--drivers/cpuidle/Kconfig.arm1
-rw-r--r--drivers/cpuidle/Kconfig.arm641
-rw-r--r--drivers/cpuidle/cpuidle-arm64.c1
-rw-r--r--drivers/cpuidle/cpuidle-big_little.c4
-rw-r--r--drivers/cpuidle/cpuidle-exynos.c76
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c84
-rw-r--r--drivers/cpuidle/cpuidle.c94
-rw-r--r--drivers/crypto/amcc/crypto4xx_sa.c23
-rw-r--r--drivers/crypto/atmel-aes.c2
-rw-r--r--drivers/crypto/atmel-sha.c50
-rw-r--r--drivers/crypto/atmel-tdes.c2
-rw-r--r--drivers/crypto/bfin_crc.c4
-rw-r--r--drivers/crypto/caam/caamalg.c14
-rw-r--r--drivers/crypto/caam/ctrl.c6
-rw-r--r--drivers/crypto/caam/error.c13
-rw-r--r--drivers/crypto/caam/jr.c37
-rw-r--r--drivers/crypto/caam/sg_sw_sec4.h8
-rw-r--r--drivers/crypto/ccp/ccp-dev.c1
-rw-r--r--drivers/crypto/ixp4xx_crypto.c4
-rw-r--r--drivers/crypto/nx/nx.c6
-rw-r--r--drivers/crypto/omap-aes.c4
-rw-r--r--drivers/crypto/omap-des.c8
-rw-r--r--drivers/crypto/qat/qat_common/adf_accel_devices.h6
-rw-r--r--drivers/crypto/qat/qat_common/adf_aer.c24
-rw-r--r--drivers/crypto/qat/qat_common/adf_cfg.c2
-rw-r--r--drivers/crypto/qat/qat_common/adf_common_drv.h2
-rw-r--r--drivers/crypto/qat/qat_common/adf_ctl_drv.c7
-rw-r--r--drivers/crypto/qat/qat_common/adf_init.c98
-rw-r--r--drivers/crypto/qat/qat_common/adf_transport_internal.h1
-rw-r--r--drivers/crypto/qat/qat_common/icp_qat_hw.h2
-rw-r--r--drivers/crypto/qat/qat_common/qat_algs.c642
-rw-r--r--drivers/crypto/qat/qat_common/qat_crypto.h16
-rw-r--r--drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c19
-rw-r--r--drivers/crypto/qat/qat_dh895xcc/adf_drv.c42
-rw-r--r--drivers/crypto/qce/dma.c6
-rw-r--r--drivers/crypto/qce/sha.c2
-rw-r--r--drivers/crypto/sahara.c2
-rw-r--r--drivers/crypto/talitos.c8
-rw-r--r--drivers/crypto/ux500/cryp/cryp_core.c14
-rw-r--r--drivers/crypto/ux500/hash/hash_core.c2
-rw-r--r--drivers/devfreq/Kconfig13
-rw-r--r--drivers/devfreq/Makefile5
-rw-r--r--drivers/devfreq/devfreq-event.c494
-rw-r--r--drivers/devfreq/event/Kconfig25
-rw-r--r--drivers/devfreq/event/Makefile2
-rw-r--r--drivers/devfreq/event/exynos-ppmu.c374
-rw-r--r--drivers/devfreq/event/exynos-ppmu.h93
-rw-r--r--drivers/devfreq/tegra-devfreq.c718
-rw-r--r--drivers/dma/Kconfig11
-rw-r--r--drivers/dma/Makefile3
-rw-r--r--drivers/dma/acpi-dma.c10
-rw-r--r--drivers/dma/amba-pl08x.c156
-rw-r--r--drivers/dma/at_hdmac.c130
-rw-r--r--drivers/dma/at_hdmac_regs.h3
-rw-r--r--drivers/dma/at_xdmac.c186
-rw-r--r--drivers/dma/bcm2835-dma.c46
-rw-r--r--drivers/dma/coh901318.c153
-rw-r--r--drivers/dma/cppi41.c30
-rw-r--r--drivers/dma/dma-jz4740.c20
-rw-r--r--drivers/dma/dmaengine.c84
-rw-r--r--drivers/dma/dmatest.c35
-rw-r--r--drivers/dma/dw/core.c101
-rw-r--r--drivers/dma/dw/platform.c4
-rw-r--r--drivers/dma/dw/regs.h4
-rw-r--r--drivers/dma/edma.c73
-rw-r--r--drivers/dma/ep93xx_dma.c43
-rw-r--r--drivers/dma/fsl-edma.c123
-rw-r--r--drivers/dma/fsldma.c97
-rw-r--r--drivers/dma/fsldma.h4
-rw-r--r--drivers/dma/img-mdc-dma.c1011
-rw-r--r--drivers/dma/imx-dma.c108
-rw-r--r--drivers/dma/imx-sdma.c150
-rw-r--r--drivers/dma/intel_mid_dma.c25
-rw-r--r--drivers/dma/ioat/dma_v3.c25
-rw-r--r--drivers/dma/ioat/hw.h5
-rw-r--r--drivers/dma/ioat/pci.c5
-rw-r--r--drivers/dma/ipu/ipu_idmac.c96
-rw-r--r--drivers/dma/k3dma.c203
-rw-r--r--drivers/dma/mmp_pdma.c109
-rw-r--r--drivers/dma/mmp_tdma.c85
-rw-r--r--drivers/dma/moxart-dma.c25
-rw-r--r--drivers/dma/mpc512x_dma.c111
-rw-r--r--drivers/dma/mv_xor.c9
-rw-r--r--drivers/dma/mxs-dma.c65
-rw-r--r--drivers/dma/nbpfaxi.c112
-rw-r--r--drivers/dma/of-dma.c4
-rw-r--r--drivers/dma/omap-dma.c69
-rw-r--r--drivers/dma/pch_dma.c8
-rw-r--r--drivers/dma/pl330.c230
-rw-r--r--drivers/dma/qcom_bam_dma.c85
-rw-r--r--drivers/dma/s3c24xx-dma.c73
-rw-r--r--drivers/dma/sa11x0-dma.c157
-rw-r--r--drivers/dma/sh/Kconfig14
-rw-r--r--drivers/dma/sh/Makefile1
-rw-r--r--drivers/dma/sh/rcar-dmac.c1770
-rw-r--r--drivers/dma/sh/rcar-hpbdma.c6
-rw-r--r--drivers/dma/sh/shdma-base.c72
-rw-r--r--drivers/dma/sh/shdmac.c23
-rw-r--r--drivers/dma/sirf-dma.c59
-rw-r--r--drivers/dma/ste_dma40.c63
-rw-r--r--drivers/dma/sun6i-dma.c160
-rw-r--r--drivers/dma/tegra20-apb-dma.c42
-rw-r--r--drivers/dma/timb_dma.c8
-rw-r--r--drivers/dma/txx9dmac.c9
-rw-r--r--drivers/dma/xilinx/xilinx_vdma.c29
-rw-r--r--drivers/edac/Kconfig7
-rw-r--r--drivers/edac/Makefile1
-rw-r--r--drivers/edac/amd64_edac.c10
-rw-r--r--drivers/edac/edac_mc_sysfs.c51
-rw-r--r--drivers/edac/i5100_edac.c5
-rw-r--r--drivers/edac/mce_amd_inj.c2
-rw-r--r--drivers/edac/mpc85xx_edac.c2
-rw-r--r--drivers/edac/mpc85xx_edac.h2
-rw-r--r--drivers/edac/mv64x60_edac.c3
-rw-r--r--drivers/edac/sb_edac.c9
-rw-r--r--drivers/edac/synopsys_edac.c535
-rw-r--r--drivers/extcon/extcon-adc-jack.c1
-rw-r--r--drivers/extcon/extcon-class.c1
-rw-r--r--drivers/extcon/extcon-max77693.c2
-rw-r--r--drivers/firewire/core-transaction.c4
-rw-r--r--drivers/firewire/ohci.c5
-rw-r--r--drivers/firewire/sbp2.c11
-rw-r--r--drivers/firmware/efi/efi.c56
-rw-r--r--drivers/firmware/efi/libstub/Makefile1
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c59
-rw-r--r--drivers/firmware/efi/libstub/efi-stub-helper.c25
-rw-r--r--drivers/firmware/efi/libstub/efistub.h8
-rw-r--r--drivers/firmware/efi/libstub/fdt.c62
-rw-r--r--drivers/gpio/Kconfig35
-rw-r--r--drivers/gpio/Makefile2
-rw-r--r--drivers/gpio/gpio-amd8111.c6
-rw-r--r--drivers/gpio/gpio-dln2.c1
-rw-r--r--drivers/gpio/gpio-dwapb.c53
-rw-r--r--drivers/gpio/gpio-ge.c98
-rw-r--r--drivers/gpio/gpio-generic.c76
-rw-r--r--drivers/gpio/gpio-grgpio.c2
-rw-r--r--drivers/gpio/gpio-max732x.c225
-rw-r--r--drivers/gpio/gpio-mb86s7x.c232
-rw-r--r--drivers/gpio/gpio-mcp23s08.c17
-rw-r--r--drivers/gpio/gpio-mm-lantiq.c42
-rw-r--r--drivers/gpio/gpio-moxart.c101
-rw-r--r--drivers/gpio/gpio-mpc5200.c23
-rw-r--r--drivers/gpio/gpio-mpc8xxx.c70
-rw-r--r--drivers/gpio/gpio-mvebu.c100
-rw-r--r--drivers/gpio/gpio-omap.c39
-rw-r--r--drivers/gpio/gpio-pxa.c55
-rw-r--r--drivers/gpio/gpio-rcar.c75
-rw-r--r--drivers/gpio/gpio-sa1100.c199
-rw-r--r--drivers/gpio/gpio-sch.c89
-rw-r--r--drivers/gpio/gpio-stmpe.c23
-rw-r--r--drivers/gpio/gpio-sx150x.c251
-rw-r--r--drivers/gpio/gpio-tc3589x.c15
-rw-r--r--drivers/gpio/gpio-tz1090-pdc.c2
-rw-r--r--drivers/gpio/gpio-tz1090.c2
-rw-r--r--drivers/gpio/gpio-vf610.c1
-rw-r--r--drivers/gpio/gpio-vx855.c44
-rw-r--r--drivers/gpio/gpio-xgene-sb.c160
-rw-r--r--drivers/gpio/gpio-xilinx.c284
-rw-r--r--drivers/gpio/gpio-zevio.c12
-rw-r--r--drivers/gpio/gpiolib-of.c17
-rw-r--r--drivers/gpio/gpiolib-sysfs.c3
-rw-r--r--drivers/gpio/gpiolib.c8
-rw-r--r--drivers/gpu/Makefile5
-rw-r--r--drivers/gpu/drm/Kconfig6
-rw-r--r--drivers/gpu/drm/Makefile3
-rw-r--r--drivers/gpu/drm/amd/amdkfd/Makefile7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/cik_regs.h13
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_chardev.c39
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device.c243
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c430
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h49
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c135
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c64
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c4
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c7
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c111
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h40
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c44
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c56
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_module.c10
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c321
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c450
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c33
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c32
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_priv.h65
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process.c40
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c40
-rw-r--r--drivers/gpu/drm/amd/amdkfd/kfd_topology.c155
-rw-r--r--drivers/gpu/drm/amd/include/cik_structs.h293
-rw-r--r--drivers/gpu/drm/amd/include/kgd_kfd_interface.h49
-rw-r--r--drivers/gpu/drm/armada/armada_crtc.c5
-rw-r--r--drivers/gpu/drm/ast/ast_fb.c21
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/Kconfig11
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/Makefile7
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c406
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c577
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h213
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c668
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h398
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c319
-rw-r--r--drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c856
-rw-r--r--drivers/gpu/drm/bochs/bochs_fbdev.c14
-rw-r--r--drivers/gpu/drm/bochs/bochs_kms.c5
-rw-r--r--drivers/gpu/drm/bridge/Kconfig8
-rw-r--r--drivers/gpu/drm/bridge/Makefile1
-rw-r--r--drivers/gpu/drm/bridge/dw_hdmi.c1707
-rw-r--r--drivers/gpu/drm/bridge/dw_hdmi.h1034
-rw-r--r--drivers/gpu/drm/bridge/ptn3460.c310
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.c3
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_drv.h3
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_fbdev.c12
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_main.c2
-rw-r--r--drivers/gpu/drm/cirrus/cirrus_mode.c9
-rw-r--r--drivers/gpu/drm/drm_atomic.c751
-rw-r--r--drivers/gpu/drm/drm_atomic_helper.c321
-rw-r--r--drivers/gpu/drm/drm_bridge.c91
-rw-r--r--drivers/gpu/drm/drm_cache.c13
-rw-r--r--drivers/gpu/drm/drm_crtc.c650
-rw-r--r--drivers/gpu/drm/drm_crtc_helper.c2
-rw-r--r--drivers/gpu/drm/drm_crtc_internal.h6
-rw-r--r--drivers/gpu/drm/drm_dp_helper.c31
-rw-r--r--drivers/gpu/drm/drm_drv.c4
-rw-r--r--drivers/gpu/drm/drm_fb_helper.c32
-rw-r--r--drivers/gpu/drm/drm_fops.c89
-rw-r--r--drivers/gpu/drm/drm_info.c24
-rw-r--r--drivers/gpu/drm/drm_internal.h1
-rw-r--r--drivers/gpu/drm/drm_ioctl.c13
-rw-r--r--drivers/gpu/drm/drm_irq.c22
-rw-r--r--drivers/gpu/drm/drm_mipi_dsi.c6
-rw-r--r--drivers/gpu/drm/drm_modes.c183
-rw-r--r--drivers/gpu/drm/drm_plane_helper.c42
-rw-r--r--drivers/gpu/drm/drm_probe_helper.c97
-rw-r--r--drivers/gpu/drm/drm_sysfs.c132
-rw-r--r--drivers/gpu/drm/drm_vma_manager.c3
-rw-r--r--drivers/gpu/drm/exynos/Kconfig25
-rw-r--r--drivers/gpu/drm/exynos/Makefile4
-rw-r--r--drivers/gpu/drm/exynos/exynos7_drm_decon.c990
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.c67
-rw-r--r--drivers/gpu/drm/exynos/exynos_dp_core.h1
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_buf.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.c247
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_crtc.h8
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_dmabuf.h5
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.c4
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_drv.h78
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_encoder.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fbdev.c29
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c14
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimd.c192
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gem.h2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c6
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.c152
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_plane.h18
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_vidi.c132
-rw-r--r--drivers/gpu/drm/exynos/exynos_hdmi.c12
-rw-r--r--drivers/gpu/drm/exynos/exynos_mixer.c165
-rw-r--r--drivers/gpu/drm/gma500/framebuffer.c22
-rw-r--r--drivers/gpu/drm/i2c/adv7511.c3
-rw-r--r--drivers/gpu/drm/i915/Kconfig2
-rw-r--r--drivers/gpu/drm/i915/Makefile5
-rw-r--r--drivers/gpu/drm/i915/i915_cmd_parser.c131
-rw-r--r--drivers/gpu/drm/i915/i915_debugfs.c442
-rw-r--r--drivers/gpu/drm/i915/i915_dma.c49
-rw-r--r--drivers/gpu/drm/i915/i915_drv.c47
-rw-r--r--drivers/gpu/drm/i915/i915_drv.h458
-rw-r--r--drivers/gpu/drm/i915/i915_gem.c701
-rw-r--r--drivers/gpu/drm/i915/i915_gem_batch_pool.c137
-rw-r--r--drivers/gpu/drm/i915/i915_gem_context.c114
-rw-r--r--drivers/gpu/drm/i915/i915_gem_evict.c11
-rw-r--r--drivers/gpu/drm/i915/i915_gem_execbuffer.c145
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.c170
-rw-r--r--drivers/gpu/drm/i915/i915_gem_gtt.h35
-rw-r--r--drivers/gpu/drm/i915/i915_gem_render_state.c2
-rw-r--r--drivers/gpu/drm/i915/i915_gem_stolen.c6
-rw-r--r--drivers/gpu/drm/i915/i915_gem_tiling.c9
-rw-r--r--drivers/gpu/drm/i915/i915_gem_userptr.c20
-rw-r--r--drivers/gpu/drm/i915/i915_gpu_error.c93
-rw-r--r--drivers/gpu/drm/i915/i915_irq.c183
-rw-r--r--drivers/gpu/drm/i915/i915_params.c14
-rw-r--r--drivers/gpu/drm/i915/i915_reg.h410
-rw-r--r--drivers/gpu/drm/i915/i915_suspend.c2
-rw-r--r--drivers/gpu/drm/i915/i915_sysfs.c133
-rw-r--r--drivers/gpu/drm/i915/i915_trace.h69
-rw-r--r--drivers/gpu/drm/i915/intel_atomic.c237
-rw-r--r--drivers/gpu/drm/i915/intel_atomic_plane.c246
-rw-r--r--drivers/gpu/drm/i915/intel_audio.c112
-rw-r--r--drivers/gpu/drm/i915/intel_bios.c45
-rw-r--r--drivers/gpu/drm/i915/intel_bios.h25
-rw-r--r--drivers/gpu/drm/i915/intel_crt.c19
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c130
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2198
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c276
-rw-r--r--drivers/gpu/drm/i915/intel_dp_mst.c19
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h203
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.c835
-rw-r--r--drivers/gpu/drm/i915/intel_dsi.h75
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_cmd.c437
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_cmd.h78
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_panel_vbt.c322
-rw-r--r--drivers/gpu/drm/i915/intel_dsi_pll.c12
-rw-r--r--drivers/gpu/drm/i915/intel_dvo.c23
-rw-r--r--drivers/gpu/drm/i915/intel_fbc.c701
-rw-r--r--drivers/gpu/drm/i915/intel_fbdev.c15
-rw-r--r--drivers/gpu/drm/i915/intel_fifo_underrun.c2
-rw-r--r--drivers/gpu/drm/i915/intel_frontbuffer.c2
-rw-r--r--drivers/gpu/drm/i915/intel_hdmi.c51
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.c385
-rw-r--r--drivers/gpu/drm/i915/intel_lrc.h43
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c19
-rw-r--r--drivers/gpu/drm/i915/intel_overlay.c46
-rw-r--r--drivers/gpu/drm/i915/intel_panel.c18
-rw-r--r--drivers/gpu/drm/i915/intel_pm.c1083
-rw-r--r--drivers/gpu/drm/i915/intel_psr.c308
-rw-r--r--drivers/gpu/drm/i915/intel_renderstate_gen6.c25
-rw-r--r--drivers/gpu/drm/i915/intel_renderstate_gen7.c25
-rw-r--r--drivers/gpu/drm/i915/intel_renderstate_gen8.c25
-rw-r--r--drivers/gpu/drm/i915/intel_renderstate_gen9.c25
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.c289
-rw-r--r--drivers/gpu/drm/i915/intel_ringbuffer.h37
-rw-r--r--drivers/gpu/drm/i915/intel_runtime_pm.c73
-rw-r--r--drivers/gpu/drm/i915/intel_sdvo.c34
-rw-r--r--drivers/gpu/drm/i915/intel_sideband.c30
-rw-r--r--drivers/gpu/drm/i915/intel_sprite.c394
-rw-r--r--drivers/gpu/drm/i915/intel_tv.c13
-rw-r--r--drivers/gpu/drm/i915/intel_uncore.c1148
-rw-r--r--drivers/gpu/drm/imx/Kconfig3
-rw-r--r--drivers/gpu/drm/imx/Makefile2
-rw-r--r--drivers/gpu/drm/imx/dw_hdmi-imx.c258
-rw-r--r--drivers/gpu/drm/imx/imx-drm-core.c87
-rw-r--r--drivers/gpu/drm/imx/imx-drm.h2
-rw-r--r--drivers/gpu/drm/imx/imx-hdmi.c1766
-rw-r--r--drivers/gpu/drm/imx/imx-hdmi.h1032
-rw-r--r--drivers/gpu/drm/imx/imx-ldb.c8
-rw-r--r--drivers/gpu/drm/imx/imx-tve.c28
-rw-r--r--drivers/gpu/drm/imx/ipuv3-crtc.c78
-rw-r--r--drivers/gpu/drm/imx/parallel-display.c7
-rw-r--r--drivers/gpu/drm/mgag200/mgag200_fb.c12
-rw-r--r--drivers/gpu/drm/msm/Kconfig1
-rw-r--r--drivers/gpu/drm/msm/Makefile9
-rw-r--r--drivers/gpu/drm/msm/adreno/a2xx.xml.h6
-rw-r--r--drivers/gpu/drm/msm/adreno/a3xx.xml.h248
-rw-r--r--drivers/gpu/drm/msm/adreno/a4xx.xml.h420
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_common.xml.h6
-rw-r--r--drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h41
-rw-r--r--drivers/gpu/drm/msm/dsi/dsi.xml.h11
-rw-r--r--drivers/gpu/drm/msm/dsi/mmss_cc.xml.h11
-rw-r--r--drivers/gpu/drm/msm/dsi/sfpb.xml.h11
-rw-r--r--drivers/gpu/drm/msm/edp/edp.c208
-rw-r--r--drivers/gpu/drm/msm/edp/edp.h85
-rw-r--r--drivers/gpu/drm/msm/edp/edp.xml.h292
-rw-r--r--drivers/gpu/drm/msm/edp/edp_aux.c268
-rw-r--r--drivers/gpu/drm/msm/edp/edp_bridge.c120
-rw-r--r--drivers/gpu/drm/msm/edp/edp_connector.c161
-rw-r--r--drivers/gpu/drm/msm/edp/edp_ctrl.c1373
-rw-r--r--drivers/gpu/drm/msm/edp/edp_phy.c106
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.c145
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.h9
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi.xml.h106
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_bridge.c14
-rw-r--r--drivers/gpu/drm/msm/hdmi/hdmi_connector.c4
-rw-r--r--drivers/gpu/drm/msm/hdmi/qfprom.xml.h11
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h55
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c65
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c119
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c34
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h19
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c154
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c104
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h245
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c230
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c127
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c56
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h19
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c216
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c5
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_common.xml.h28
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_format.c108
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_kms.c2
-rw-r--r--drivers/gpu/drm/msm/mdp/mdp_kms.h24
-rw-r--r--drivers/gpu/drm/msm/msm_atomic.c50
-rw-r--r--drivers/gpu/drm/msm/msm_drv.c13
-rw-r--r--drivers/gpu/drm/msm/msm_drv.h14
-rw-r--r--drivers/gpu/drm/msm/msm_fb.c4
-rw-r--r--drivers/gpu/drm/msm/msm_fbdev.c13
-rw-r--r--drivers/gpu/drm/msm/msm_kms.h5
-rw-r--r--drivers/gpu/drm/nouveau/Kbuild66
-rw-r--r--drivers/gpu/drm/nouveau/Kconfig2
-rw-r--r--drivers/gpu/drm/nouveau/Makefile400
-rw-r--r--drivers/gpu/drm/nouveau/core/core/client.c271
-rw-r--r--drivers/gpu/drm/nouveau/core/core/engctx.c251
-rw-r--r--drivers/gpu/drm/nouveau/core/core/engine.c68
-rw-r--r--drivers/gpu/drm/nouveau/core/core/enum.c68
-rw-r--r--drivers/gpu/drm/nouveau/core/core/event.c100
-rw-r--r--drivers/gpu/drm/nouveau/core/core/gpuobj.c323
-rw-r--r--drivers/gpu/drm/nouveau/core/core/handle.c224
-rw-r--r--drivers/gpu/drm/nouveau/core/core/ioctl.c530
-rw-r--r--drivers/gpu/drm/nouveau/core/core/mm.c303
-rw-r--r--drivers/gpu/drm/nouveau/core/core/namedb.c203
-rw-r--r--drivers/gpu/drm/nouveau/core/core/notify.c168
-rw-r--r--drivers/gpu/drm/nouveau/core/core/object.c334
-rw-r--r--drivers/gpu/drm/nouveau/core/core/option.c122
-rw-r--r--drivers/gpu/drm/nouveau/core/core/parent.c161
-rw-r--r--drivers/gpu/drm/nouveau/core/core/printk.c98
-rw-r--r--drivers/gpu/drm/nouveau/core/core/ramht.c108
-rw-r--r--drivers/gpu/drm/nouveau/core/core/subdev.c112
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c92
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c111
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc872
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h620
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h606
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nva3.c156
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c172
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/copy/nve0.c176
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc698
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h584
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c188
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c156
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/acpi.c59
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/acpi.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/base.c715
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/ctrl.c205
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/gm100.c150
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv04.c89
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv10.c204
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv20.c131
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv30.c153
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv40.c427
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nv50.c475
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nvc0.c357
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/nve0.c324
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/device/priv.h8
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/base.c242
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/conn.c175
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/conn.h56
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c101
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.c402
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/dport.h75
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/gm107.c107
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/gm204.c114
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c69
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c91
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c91
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c79
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c83
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv04.c205
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.c2017
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv50.h252
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv84.c276
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nv94.c142
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva0.c152
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nva3.c108
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c1313
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nve0.c272
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c107
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outp.c141
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outp.h60
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c302
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h62
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c172
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/priv.h48
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c144
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c58
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c151
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c131
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/disp/vga.c220
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c165
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c165
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c197
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c179
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c168
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/falcon.c278
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/base.c283
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c35
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c656
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h178
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c183
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c37
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c220
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c361
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c541
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h36
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c481
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c975
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c1147
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h18
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctx.h129
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c104
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c63
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c1032
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c565
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c695
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c3347
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c1386
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h202
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c805
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c109
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c360
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c282
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c530
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c1020
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c843
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc335
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc378
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc542
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h473
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc42
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h530
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc42
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h537
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc42
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h537
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc42
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h537
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc696
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc540
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h916
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h1047
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h1047
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h1044
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc40
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h1044
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c117
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c48
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/gm107.c469
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv04.c1388
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv10.c1319
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv108.c224
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv20.c383
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv20.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv25.c166
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c133
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv30.c237
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv34.c167
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv35.c165
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.c536
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv40.h24
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.c1009
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nv50.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c1667
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h270
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c133
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c128
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c115
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c191
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nve4.c347
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c245
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/graph/regs.h274
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c309
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h15
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c141
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c193
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c230
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c102
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/base.c483
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c109
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c143
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h26
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c70
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c78
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c96
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c173
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h17
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c162
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h91
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv04.c146
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv10.c128
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv50.c241
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nv50.h46
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/software/nvc0.c149
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nv84.c92
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nv98.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/vp/nve0.c110
-rw-r--r--drivers/gpu/drm/nouveau/core/engine/xtensa.c176
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/client.h57
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/debug.h20
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/device.h184
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/engctx.h54
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/engine.h57
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/enum.h24
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/event.h35
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/gpuobj.h71
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/handle.h34
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/ioctl.h6
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/mm.h40
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/namedb.h56
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/notify.h37
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/object.h206
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/option.h20
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/parent.h62
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/printk.h32
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/ramht.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/include/core/subdev.h118
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/bsp.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/copy.h13
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/crypt.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/device.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/disp.h36
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/falcon.h83
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/fifo.h126
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/graph.h86
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/mpeg.h63
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/perfmon.h38
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/ppp.h7
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/software.h51
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/vp.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/engine/xtensa.h38
l---------drivers/gpu/drm/nouveau/core/include/nvif/class.h1
l---------drivers/gpu/drm/nouveau/core/include/nvif/event.h1
l---------drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h1
l---------drivers/gpu/drm/nouveau/core/include/nvif/unpack.h1
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bar.h37
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios.h35
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h32
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h13
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h39
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h29
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h46
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h28
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h69
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h48
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h35
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h8
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h48
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h29
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h13
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h22
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h12
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h18
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h47
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h79
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h37
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h145
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h26
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h77
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h14
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h25
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h27
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h19
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/bus.h53
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/clock.h166
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/devinit.h35
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/fb.h159
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h21
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/fuse.h30
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/gpio.h47
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/i2c.h136
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/ibus.h35
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/instmem.h52
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/ltc.h35
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mc.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/mxm.h37
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/pwr.h56
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/therm.h83
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/timer.h64
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/vm.h135
-rw-r--r--drivers/gpu/drm/nouveau/core/include/subdev/volt.h61
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/base.c149
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c54
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c273
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c220
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bar/priv.h32
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c129
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c136
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c109
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/base.c213
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/bit.c52
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/boost.c127
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/conn.c100
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c123
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c235
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/disp.c179
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/dp.c217
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c100
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/fan.c93
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c150
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c161
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/image.c78
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/init.c2227
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/npde.c59
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c69
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/perf.c201
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/pll.c416
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/priv.h25
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c79
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c216
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c270
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c111
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c108
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c114
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c69
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/therm.c215
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/timing.c169
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c112
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/volt.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c76
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c145
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h113
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c95
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c92
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c105
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c59
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c81
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/base.c597
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c680
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c105
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c240
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c559
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c48
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c534
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h20
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c435
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c462
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c500
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pll.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c246
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c89
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/clock/seq.h17
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/base.c99
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h86
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c57
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c173
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c468
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c140
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c111
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c75
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c173
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h23
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c63
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c146
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c64
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c119
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h40
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/base.c159
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c117
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c122
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c70
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c89
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h55
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c44
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c95
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c61
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c139
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c62
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c62
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c76
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h17
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c69
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c78
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c58
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c45
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c45
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c44
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c316
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h33
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c120
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h31
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/priv.h76
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h184
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c152
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c56
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c80
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c61
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c63
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c215
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c67
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c65
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c67
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c55
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c470
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c1024
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c103
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c733
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c1646
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h18
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c94
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c120
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fuse/base.c54
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c81
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c83
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c66
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h9
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/base.c255
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c116
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c129
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c74
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c85
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c74
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h67
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c292
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c114
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/base.c634
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c234
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c221
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c130
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c122
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c135
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h34
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c282
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c108
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c72
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c84
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h58
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c86
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c35
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c86
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/port.h15
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h89
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c103
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c123
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c140
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/base.c157
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c182
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h40
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c137
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c171
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h56
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltc/base.c126
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c236
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c60
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c154
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/base.c169
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c79
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c45
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c54
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c37
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c71
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c59
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c77
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c39
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mc/priv.h38
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/base.c274
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c193
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h22
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c233
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/base.c272
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc70
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h1731
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc70
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h1868
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc70
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h1865
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc70
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h1795
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c69
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c201
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c41
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c50
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c41
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c41
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h44
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/base.c374
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/fan.c287
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c54
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c113
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c122
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c93
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/ic.c121
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c224
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c197
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c268
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c101
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c174
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/priv.h159
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/therm/temp.c264
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/base.c94
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c57
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c264
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h27
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/timer/priv.h6
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/base.c483
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c151
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h19
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c159
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c249
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c240
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c242
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/volt/base.c207
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c199
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c96
-rw-r--r--drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c56
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/Kbuild (renamed from drivers/gpu/drm/nouveau/dispnv04/Makefile)0
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/crtc.c8
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dac.c22
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/dfp.c6
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.c20
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/disp.h6
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/hw.c24
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/hw.h4
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv04.c8
-rw-r--r--drivers/gpu/drm/nouveau/dispnv04/tvnv17.c10
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/class.h573
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/client.h39
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/device.h61
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/driver.h (renamed from drivers/gpu/drm/nouveau/nvif/driver.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/event.h (renamed from drivers/gpu/drm/nouveau/nvif/event.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/ioctl.h (renamed from drivers/gpu/drm/nouveau/nvif/ioctl.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/list.h (renamed from drivers/gpu/drm/nouveau/nvif/list.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/notify.h (renamed from drivers/gpu/drm/nouveau/nvif/notify.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/object.h75
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/os.h (renamed from drivers/gpu/drm/nouveau/core/os.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvif/unpack.h (renamed from drivers/gpu/drm/nouveau/nvif/unpack.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/client.h55
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/debug.h18
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/device.h101
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h62
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h51
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/engine.h56
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/enum.h21
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/event.h34
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h64
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/handle.h34
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h7
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/mm.h40
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h53
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/notify.h38
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/object.h203
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/option.h17
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/os.h4
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/parent.h58
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/printk.h29
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h20
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h119
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h13
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/device.h30
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h32
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h26
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h81
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h126
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h86
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h62
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h7
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h6
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h7
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h34
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h50
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h5
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h35
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h33
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h32
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h29
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h29
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h27
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h21
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h37
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h27
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h44
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h26
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h65
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h39
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h31
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h25
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h6
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h46
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h25
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h20
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h6
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h10
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h16
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h41
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h75
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h35
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h141
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h21
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h72
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h11
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h21
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h23
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h18
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h50
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h161
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h32
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h154
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h28
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h44
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h135
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h32
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h48
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h31
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h28
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h104
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h34
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h53
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h79
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h61
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h (renamed from drivers/gpu/drm/nouveau/core/include/subdev/vga.h)0
-rw-r--r--drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h58
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.c24
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_abi16.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_agp.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bios.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.c126
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_bo.h13
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.c22
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_chan.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.c102
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_connector.h3
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.c11
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_display.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dma.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_dp.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.c69
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_drm.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_encoder.h4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.c44
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fbcon.h1
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_fence.h6
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_gem.c33
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_hwmon.c98
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_nvif.c24
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_platform.c8
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_platform.h5
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_reg.h2
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sgdma.c17
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_sysfs.c4
-rw-r--r--drivers/gpu/drm/nouveau/nouveau_ttm.c66
-rw-r--r--drivers/gpu/drm/nouveau/nv04_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nv50_display.c165
-rw-r--r--drivers/gpu/drm/nouveau/nv84_fence.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvif/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvif/class.h570
-rw-r--r--drivers/gpu/drm/nouveau/nvif/client.c6
-rw-r--r--drivers/gpu/drm/nouveau/nvif/client.h39
-rw-r--r--drivers/gpu/drm/nouveau/nvif/device.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvif/device.h62
-rw-r--r--drivers/gpu/drm/nouveau/nvif/notify.c2
-rw-r--r--drivers/gpu/drm/nouveau/nvif/object.c8
-rw-r--r--drivers/gpu/drm/nouveau/nvif/object.h75
l---------drivers/gpu/drm/nouveau/nvif/os.h1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/Kbuild17
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/client.c266
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/engctx.c239
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/engine.c75
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/enum.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/event.c99
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c316
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/handle.c221
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/ioctl.c526
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/mm.c304
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/namedb.c199
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/notify.c163
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/object.c330
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/option.c121
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/parent.c159
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/printk.c103
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/ramht.c106
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/core/subdev.c120
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/Kbuild19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc864
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc32
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h606
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc32
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h620
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c166
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c173
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c152
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c184
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c60
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/base.c730
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c199
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c358
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c326
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c151
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c89
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c204
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c131
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c153
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c427
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c478
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild29
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c240
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c174
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h58
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c99
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c398
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h75
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c272
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c139
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c1310
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c268
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c103
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c103
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c111
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c148
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c104
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c73
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c69
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c91
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c79
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c83
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c92
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c205
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c2019
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h226
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c142
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c301
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c170
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h42
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c145
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c124
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c139
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c219
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c164
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c176
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c165
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c163
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c195
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h28
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/falcon.c277
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c282
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c487
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c967
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c1138
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c36
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c34
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c650
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h175
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c178
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c215
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c356
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c534
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h36
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild36
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c1390
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h199
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c108
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c806
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c359
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c284
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c529
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c1022
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c842
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c103
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c564
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c62
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c1034
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c694
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h129
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c3345
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc335
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc378
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc342
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h530
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc342
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h537
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc342
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h537
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc342
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h537
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc542
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h473
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5 (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc696
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc340
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h1047
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc340
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h1047
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc340
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h1044
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc340
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h1044
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc540
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h916
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5 (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/macros.fuc (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/os.h (renamed from drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c1678
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h250
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c127
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c134
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c116
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c136
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c190
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c348
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c248
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c116
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c227
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c470
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c1382
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c1315
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c376
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h26
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c158
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c125
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c231
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c159
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c159
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c527
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c999
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h274
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild5
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c94
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c304
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c134
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c185
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c225
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild2
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c110
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild9
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c476
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c108
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c65
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c159
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c148
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c57
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c83
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c130
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h24
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c57
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h90
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s698
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h584
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c149
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c141
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c139
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c122
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c234
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h45
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild1
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c172
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c144
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c219
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c50
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c271
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h30
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild37
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c128
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c135
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c135
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c107
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c206
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c126
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c97
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c122
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c234
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c172
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c215
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c97
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c150
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c159
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c77
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c2247
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c134
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c58
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c68
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c201
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c417
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c134
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h23
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c78
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c211
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c272
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c112
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c72
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c109
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c115
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c70
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c214
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c166
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c111
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c136
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c74
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c58
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c80
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c143
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h111
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c94
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c91
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c104
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild12
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c591
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c47
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c462
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c500
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c680
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c533
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h18
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c429
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c103
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c241
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c561
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h28
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c87
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c245
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c96
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h84
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c65
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c124
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c59
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c172
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c150
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c470
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h22
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c140
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c111
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c77
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c174
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h21
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h34
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild45
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c155
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c115
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c120
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c122
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h28
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c37
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c69
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c37
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c87
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h53
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c70
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c94
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c60
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c140
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c61
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c75
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h14
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c68
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c77
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c57
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c320
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h31
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h74
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h180
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c731
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c1639
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c149
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c55
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c1012
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c101
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c79
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c59
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c72
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c62
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c212
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c64
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c66
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c54
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c465
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h15
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h22
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c119
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c51
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c78
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c64
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c76
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h7
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c251
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c73
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c84
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c73
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c115
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c128
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h64
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild16
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c292
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c113
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c622
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c233
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c279
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c106
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c71
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c219
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c128
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c120
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c133
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h32
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c83
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c85
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c85
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c34
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h87
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c122
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c139
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c102
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c146
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c185
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h36
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c136
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c169
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h54
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c124
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c236
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c59
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c153
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h69
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild11
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c169
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c37
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c58
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c76
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c38
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c37
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c78
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h20
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c44
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c53
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c36
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c72
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h36
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild6
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c480
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c237
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c151
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h19
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c157
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c247
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c241
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c271
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c191
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h22
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c231
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild8
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c268
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/arith.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc370
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h1865
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc470
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h1795
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc570
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h1731
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc370
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h1868
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/host.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/i2c_.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/idle.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/macros.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/os.h (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/perf.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/test.fuc (renamed from drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc)0
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c67
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c40
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c229
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c49
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c200
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h43
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild13
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c367
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c282
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c53
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c113
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c118
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c266
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c174
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c100
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c119
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c225
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c198
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h153
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c259
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild3
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c93
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c56
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c262
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h25
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild4
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c204
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c197
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c96
-rw-r--r--drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c55
-rw-r--r--drivers/gpu/drm/omapdrm/omap_fbdev.c10
-rw-r--r--drivers/gpu/drm/panel/Kconfig2
-rw-r--r--drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c33
-rw-r--r--drivers/gpu/drm/panel/panel-simple.c63
-rw-r--r--drivers/gpu/drm/qxl/qxl_fb.c22
-rw-r--r--drivers/gpu/drm/radeon/Makefile8
-rw-r--r--drivers/gpu/drm/radeon/atombios_dp.c11
-rw-r--r--drivers/gpu/drm/radeon/atombios_encoders.c38
-rw-r--r--drivers/gpu/drm/radeon/btc_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/ci_dpm.c57
-rw-r--r--drivers/gpu/drm/radeon/ci_dpm.h1
-rw-r--r--drivers/gpu/drm/radeon/ci_smc.c2
-rw-r--r--drivers/gpu/drm/radeon/cik.c74
-rw-r--r--drivers/gpu/drm/radeon/cik_reg.h167
-rw-r--r--drivers/gpu/drm/radeon/cik_sdma.c29
-rw-r--r--drivers/gpu/drm/radeon/cikd.h4
-rw-r--r--drivers/gpu/drm/radeon/cypress_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/dce3_1_afmt.c264
-rw-r--r--drivers/gpu/drm/radeon/dce6_afmt.c218
-rw-r--r--drivers/gpu/drm/radeon/evergreen.c14
-rw-r--r--drivers/gpu/drm/radeon/evergreen_cs.c76
-rw-r--r--drivers/gpu/drm/radeon/evergreen_hdmi.c478
-rw-r--r--drivers/gpu/drm/radeon/evergreen_reg.h15
-rw-r--r--drivers/gpu/drm/radeon/evergreend.h5
-rw-r--r--drivers/gpu/drm/radeon/kv_dpm.c19
-rw-r--r--drivers/gpu/drm/radeon/ni.c28
-rw-r--r--drivers/gpu/drm/radeon/ni_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/nid.h4
-rw-r--r--drivers/gpu/drm/radeon/r600.c7
-rw-r--r--drivers/gpu/drm/radeon/r600_dpm.c2
-rw-r--r--drivers/gpu/drm/radeon/r600_hdmi.c399
-rw-r--r--drivers/gpu/drm/radeon/radeon.h15
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.c36
-rw-r--r--drivers/gpu/drm/radeon/radeon_asic.h21
-rw-r--r--drivers/gpu/drm/radeon/radeon_atombios.c1
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.c766
-rw-r--r--drivers/gpu/drm/radeon/radeon_audio.h84
-rw-r--r--drivers/gpu/drm/radeon/radeon_benchmark.c13
-rw-r--r--drivers/gpu/drm/radeon/radeon_connectors.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_cs.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_display.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_drv.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_encoders.c3
-rw-r--r--drivers/gpu/drm/radeon/radeon_fb.c31
-rw-r--r--drivers/gpu/drm/radeon/radeon_gem.c6
-rw-r--r--drivers/gpu/drm/radeon/radeon_i2c.c5
-rw-r--r--drivers/gpu/drm/radeon/radeon_kfd.c283
-rw-r--r--drivers/gpu/drm/radeon/radeon_kfd.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_kms.c16
-rw-r--r--drivers/gpu/drm/radeon/radeon_mode.h4
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.c18
-rw-r--r--drivers/gpu/drm/radeon/radeon_object.h2
-rw-r--r--drivers/gpu/drm/radeon/radeon_pm.c141
-rw-r--r--drivers/gpu/drm/radeon/radeon_test.c8
-rw-r--r--drivers/gpu/drm/radeon/radeon_vm.c6
-rw-r--r--drivers/gpu/drm/radeon/rs600.c7
-rw-r--r--drivers/gpu/drm/radeon/rs690.c7
-rw-r--r--drivers/gpu/drm/radeon/rv770.c5
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.c4
-rw-r--r--drivers/gpu/drm/radeon/rv770_dpm.h2
-rw-r--r--drivers/gpu/drm/radeon/si.c27
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.c75
-rw-r--r--drivers/gpu/drm/radeon/si_dpm.h1
-rw-r--r--drivers/gpu/drm/radeon/sid.h14
-rw-r--r--drivers/gpu/drm/radeon/sumo_dpm.c4
-rw-r--r--drivers/gpu/drm/radeon/sumo_dpm.h3
-rw-r--r--drivers/gpu/drm/radeon/trinity_dpm.c2
-rw-r--r--drivers/gpu/drm/rcar-du/Kconfig2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.c95
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_crtc.h1
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.c6
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_drv.h2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_encoder.c34
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_group.c21
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c2
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c18
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_kms.c15
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_plane.c20
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_regs.h5
-rw-r--r--drivers/gpu/drm/rcar-du/rcar_du_vgacon.c1
-rw-r--r--drivers/gpu/drm/rockchip/Kconfig12
-rw-r--r--drivers/gpu/drm/rockchip/Makefile2
-rw-r--r--drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c341
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_drv.c1
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_gem.c9
-rw-r--r--drivers/gpu/drm/rockchip/rockchip_drm_vop.c1
-rw-r--r--drivers/gpu/drm/shmobile/Kconfig4
-rw-r--r--drivers/gpu/drm/sti/Kconfig3
-rw-r--r--drivers/gpu/drm/sti/Makefile4
-rw-r--r--drivers/gpu/drm/sti/sti_awg_utils.c182
-rw-r--r--drivers/gpu/drm/sti/sti_awg_utils.h34
-rw-r--r--drivers/gpu/drm/sti/sti_drm_crtc.c6
-rw-r--r--drivers/gpu/drm/sti/sti_dvo.c560
-rw-r--r--drivers/gpu/drm/sti/sti_gdp.c11
-rw-r--r--drivers/gpu/drm/sti/sti_hda.c11
-rw-r--r--drivers/gpu/drm/sti/sti_hdmi.c190
-rw-r--r--drivers/gpu/drm/sti/sti_hqvdp.c2
-rw-r--r--drivers/gpu/drm/sti/sti_tvout.c118
-rw-r--r--drivers/gpu/drm/tegra/dc.c1021
-rw-r--r--drivers/gpu/drm/tegra/drm.c140
-rw-r--r--drivers/gpu/drm/tegra/drm.h91
-rw-r--r--drivers/gpu/drm/tegra/dsi.c578
-rw-r--r--drivers/gpu/drm/tegra/fb.c25
-rw-r--r--drivers/gpu/drm/tegra/gem.c39
-rw-r--r--drivers/gpu/drm/tegra/hdmi.c325
-rw-r--r--drivers/gpu/drm/tegra/mipi-phy.c25
-rw-r--r--drivers/gpu/drm/tegra/output.c168
-rw-r--r--drivers/gpu/drm/tegra/rgb.c218
-rw-r--r--drivers/gpu/drm/tegra/sor.c759
-rw-r--r--drivers/gpu/drm/tilcdc/Kconfig2
-rw-r--r--drivers/gpu/drm/udl/udl_fb.c22
-rw-r--r--drivers/gpu/drm/udl/udl_modeset.c9
-rw-r--r--drivers/gpu/drm/udl/udl_transfer.c39
-rw-r--r--drivers/gpu/host1x/bus.c201
-rw-r--r--drivers/gpu/host1x/bus.h4
-rw-r--r--drivers/gpu/host1x/dev.c6
-rw-r--r--drivers/gpu/ipu-v3/ipu-common.c4
-rw-r--r--drivers/gpu/ipu-v3/ipu-dc.c30
-rw-r--r--drivers/gpu/ipu-v3/ipu-di.c121
-rw-r--r--drivers/hid/Kconfig12
-rw-r--r--drivers/hid/Makefile50
-rw-r--r--drivers/hid/hid-betopff.c160
-rw-r--r--drivers/hid/hid-core.c34
-rw-r--r--drivers/hid/hid-hyperv.c2
-rw-r--r--drivers/hid/hid-ids.h12
-rw-r--r--drivers/hid/hid-input.c26
-rw-r--r--drivers/hid/hid-lenovo.c79
-rw-r--r--drivers/hid/hid-lg4ff.c11
-rw-r--r--drivers/hid/hid-logitech-hidpp.c81
-rw-r--r--drivers/hid/hid-microsoft.c4
-rw-r--r--drivers/hid/hid-rmi.c118
-rw-r--r--drivers/hid/hid-saitek.c2
-rw-r--r--drivers/hid/hid-sensor-hub.c8
-rw-r--r--drivers/hid/hid-sony.c6
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c7
-rw-r--r--drivers/hid/usbhid/Makefile12
-rw-r--r--drivers/hid/usbhid/hid-pidff.c6
-rw-r--r--drivers/hid/usbhid/hid-quirks.c1
-rw-r--r--drivers/hid/wacom_sys.c9
-rw-r--r--drivers/hid/wacom_wac.c244
-rw-r--r--drivers/hid/wacom_wac.h17
-rw-r--r--drivers/hsi/clients/nokia-modem.c1
-rw-r--r--drivers/hv/channel.c54
-rw-r--r--drivers/hv/channel_mgmt.c54
-rw-r--r--drivers/hv/connection.c6
-rw-r--r--drivers/hv/hv.c78
-rw-r--r--drivers/hv/hv_balloon.c88
-rw-r--r--drivers/hv/hv_fcopy.c27
-rw-r--r--drivers/hv/hyperv_vmbus.h21
-rw-r--r--drivers/hv/vmbus_drv.c41
-rw-r--r--drivers/hwmon/Kconfig7
-rw-r--r--drivers/hwmon/abx500.c6
-rw-r--r--drivers/hwmon/ad7314.c5
-rw-r--r--drivers/hwmon/adc128d818.c3
-rw-r--r--drivers/hwmon/ads7828.c105
-rw-r--r--drivers/hwmon/ina2xx.c334
-rw-r--r--drivers/hwmon/jc42.c15
-rw-r--r--drivers/hwmon/nct7802.c2
-rw-r--r--drivers/hwmon/pmbus/Kconfig2
-rw-r--r--drivers/hwmon/tmp102.c15
-rw-r--r--drivers/i2c/Kconfig4
-rw-r--r--drivers/i2c/busses/Kconfig23
-rw-r--r--drivers/i2c/busses/Makefile2
-rw-r--r--drivers/i2c/busses/i2c-bcm-iproc.c461
-rw-r--r--drivers/i2c/busses/i2c-cadence.c189
-rw-r--r--drivers/i2c/busses/i2c-designware-baytrail.c160
-rw-r--r--drivers/i2c/busses/i2c-designware-core.c83
-rw-r--r--drivers/i2c/busses/i2c-designware-core.h12
-rw-r--r--drivers/i2c/busses/i2c-designware-pcidrv.c41
-rw-r--r--drivers/i2c/busses/i2c-designware-platdrv.c20
-rw-r--r--drivers/i2c/busses/i2c-imx.c33
-rw-r--r--drivers/i2c/busses/i2c-ocores.c91
-rw-r--r--drivers/i2c/busses/i2c-pmcmsp.c7
-rw-r--r--drivers/i2c/busses/i2c-rk3x.c99
-rw-r--r--drivers/i2c/busses/i2c-s3c2410.c23
-rw-r--r--drivers/i2c/busses/i2c-sh_mobile.c12
-rw-r--r--drivers/i2c/busses/i2c-tegra.c2
-rw-r--r--drivers/i2c/i2c-core.c164
-rw-r--r--drivers/i2c/i2c-slave-eeprom.c4
-rw-r--r--drivers/i2c/muxes/i2c-mux-pca954x.c11
-rw-r--r--drivers/idle/intel_idle.c180
-rw-r--r--drivers/iio/Kconfig5
-rw-r--r--drivers/iio/accel/Kconfig31
-rw-r--r--drivers/iio/accel/Makefile6
-rw-r--r--drivers/iio/accel/hid-sensor-accel-3d.c8
-rw-r--r--drivers/iio/accel/kxcjk-1013.c52
-rw-r--r--drivers/iio/accel/mma8452.c2
-rw-r--r--drivers/iio/accel/mma9551.c637
-rw-r--r--drivers/iio/accel/mma9551_core.c798
-rw-r--r--drivers/iio/accel/mma9551_core.h81
-rw-r--r--drivers/iio/accel/mma9553.c1334
-rw-r--r--drivers/iio/accel/ssp_accel_sensor.c169
-rw-r--r--drivers/iio/adc/Kconfig25
-rw-r--r--drivers/iio/adc/Makefile2
-rw-r--r--drivers/iio/adc/cc10001_adc.c423
-rw-r--r--drivers/iio/adc/qcom-spmi-vadc.c1016
-rw-r--r--drivers/iio/adc/ti_am335x_adc.c16
-rw-r--r--drivers/iio/amplifiers/ad8366.c4
-rw-r--r--drivers/iio/common/Kconfig1
-rw-r--r--drivers/iio/common/Makefile1
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.c75
-rw-r--r--drivers/iio/common/hid-sensors/hid-sensor-trigger.h5
-rw-r--r--drivers/iio/common/ssp_sensors/Kconfig26
-rw-r--r--drivers/iio/common/ssp_sensors/Makefile8
-rw-r--r--drivers/iio/common/ssp_sensors/ssp.h257
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_dev.c712
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_iio.c107
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_iio_sensor.h71
-rw-r--r--drivers/iio/common/ssp_sensors/ssp_spi.c608
-rw-r--r--drivers/iio/common/st_sensors/st_sensors_spi.c2
-rw-r--r--drivers/iio/frequency/ad9523.c2
-rw-r--r--drivers/iio/frequency/adf4350.c7
-rw-r--r--drivers/iio/gyro/Makefile2
-rw-r--r--drivers/iio/gyro/hid-sensor-gyro-3d.c8
-rw-r--r--drivers/iio/gyro/ssp_gyro_sensor.c168
-rw-r--r--drivers/iio/iio_core.h9
-rw-r--r--drivers/iio/imu/Kconfig11
-rw-r--r--drivers/iio/imu/Makefile2
-rw-r--r--drivers/iio/imu/inv_mpu6050/Kconfig1
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_core.c124
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h6
-rw-r--r--drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c39
-rw-r--r--drivers/iio/imu/kmx61.c1595
-rw-r--r--drivers/iio/industrialio-buffer.c410
-rw-r--r--drivers/iio/industrialio-core.c57
-rw-r--r--drivers/iio/industrialio-event.c15
-rw-r--r--drivers/iio/industrialio-triggered-buffer.c13
-rw-r--r--drivers/iio/inkern.c30
-rw-r--r--drivers/iio/kfifo_buf.c87
-rw-r--r--drivers/iio/light/Kconfig24
-rw-r--r--drivers/iio/light/Makefile2
-rw-r--r--drivers/iio/light/cm32181.c2
-rw-r--r--drivers/iio/light/cm3232.c403
-rw-r--r--drivers/iio/light/hid-sensor-als.c9
-rw-r--r--drivers/iio/light/hid-sensor-prox.c10
-rw-r--r--drivers/iio/light/jsa1212.c471
-rw-r--r--drivers/iio/light/lm3533-als.c2
-rw-r--r--drivers/iio/light/tcs3414.c4
-rw-r--r--drivers/iio/magnetometer/Kconfig15
-rw-r--r--drivers/iio/magnetometer/Makefile1
-rw-r--r--drivers/iio/magnetometer/ak09911.c326
-rw-r--r--drivers/iio/magnetometer/ak8975.c505
-rw-r--r--drivers/iio/magnetometer/hid-sensor-magn-3d.c9
-rw-r--r--drivers/iio/orientation/hid-sensor-incl-3d.c9
-rw-r--r--drivers/iio/pressure/bmp280.c150
-rw-r--r--drivers/iio/pressure/hid-sensor-press.c9
-rw-r--r--drivers/iio/proximity/Kconfig17
-rw-r--r--drivers/iio/proximity/Makefile1
-rw-r--r--drivers/iio/proximity/as3935.c18
-rw-r--r--drivers/iio/proximity/sx9500.c752
-rw-r--r--drivers/iio/trigger/iio-trig-sysfs.c2
-rw-r--r--drivers/infiniband/core/ucma.c3
-rw-r--r--drivers/infiniband/core/umem_odp.c3
-rw-r--r--drivers/infiniband/core/uverbs_cmd.c45
-rw-r--r--drivers/infiniband/core/uverbs_main.c2
-rw-r--r--drivers/infiniband/hw/cxgb4/cm.c118
-rw-r--r--drivers/infiniband/hw/cxgb4/cq.c60
-rw-r--r--drivers/infiniband/hw/cxgb4/device.c47
-rw-r--r--drivers/infiniband/hw/cxgb4/ev.c21
-rw-r--r--drivers/infiniband/hw/cxgb4/iw_cxgb4.h29
-rw-r--r--drivers/infiniband/hw/cxgb4/mem.c22
-rw-r--r--drivers/infiniband/hw/cxgb4/qp.c62
-rw-r--r--drivers/infiniband/hw/cxgb4/t4.h126
-rw-r--r--drivers/infiniband/hw/cxgb4/t4fw_ri_api.h812
-rw-r--r--drivers/infiniband/hw/ipath/ipath_fs.c2
-rw-r--r--drivers/infiniband/hw/ipath/ipath_kernel.h3
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_ppc64.c13
-rw-r--r--drivers/infiniband/hw/ipath/ipath_wc_x86_64.c15
-rw-r--r--drivers/infiniband/hw/mlx4/ah.c1
-rw-r--r--drivers/infiniband/hw/mlx4/alias_GUID.c2
-rw-r--r--drivers/infiniband/hw/mlx4/cm.c2
-rw-r--r--drivers/infiniband/hw/mlx4/cq.c64
-rw-r--r--drivers/infiniband/hw/mlx4/mad.c3
-rw-r--r--drivers/infiniband/hw/mlx4/main.c255
-rw-r--r--drivers/infiniband/hw/mlx4/mlx4_ib.h26
-rw-r--r--drivers/infiniband/hw/mlx4/mr.c6
-rw-r--r--drivers/infiniband/hw/mlx4/qp.c96
-rw-r--r--drivers/infiniband/hw/mlx4/srq.c8
-rw-r--r--drivers/infiniband/hw/mlx4/sysfs.c6
-rw-r--r--drivers/infiniband/hw/mlx5/main.c2
-rw-r--r--drivers/infiniband/hw/mlx5/mem.c2
-rw-r--r--drivers/infiniband/hw/mlx5/mr.c1
-rw-r--r--drivers/infiniband/hw/nes/nes_nic.c13
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma.h38
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.c38
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_ah.h6
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.c312
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_hw.h2
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_main.c12
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_sli.h68
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.c241
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_stats.h6
-rw-r--r--drivers/infiniband/hw/ocrdma/ocrdma_verbs.c183
-rw-r--r--drivers/infiniband/hw/qib/qib.h16
-rw-r--r--drivers/infiniband/hw/qib/qib_common.h4
-rw-r--r--drivers/infiniband/hw/qib/qib_debugfs.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_diag.c9
-rw-r--r--drivers/infiniband/hw/qib/qib_driver.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_eeprom.c198
-rw-r--r--drivers/infiniband/hw/qib/qib_file_ops.c26
-rw-r--r--drivers/infiniband/hw/qib/qib_fs.c11
-rw-r--r--drivers/infiniband/hw/qib/qib_iba6120.c15
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7220.c14
-rw-r--r--drivers/infiniband/hw/qib/qib_iba7322.c52
-rw-r--r--drivers/infiniband/hw/qib/qib_init.c12
-rw-r--r--drivers/infiniband/hw/qib/qib_intr.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_keys.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_mad.c20
-rw-r--r--drivers/infiniband/hw/qib/qib_mmap.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_mr.c10
-rw-r--r--drivers/infiniband/hw/qib/qib_pcie.c10
-rw-r--r--drivers/infiniband/hw/qib/qib_qp.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_qsfp.c13
-rw-r--r--drivers/infiniband/hw/qib/qib_rc.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_ruc.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_sd7220.c9
-rw-r--r--drivers/infiniband/hw/qib/qib_sysfs.c28
-rw-r--r--drivers/infiniband/hw/qib/qib_twsi.c5
-rw-r--r--drivers/infiniband/hw/qib/qib_tx.c1
-rw-r--r--drivers/infiniband/hw/qib/qib_ud.c2
-rw-r--r--drivers/infiniband/hw/qib/qib_user_sdma.c8
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs.c15
-rw-r--r--drivers/infiniband/hw/qib/qib_verbs_mcast.c4
-rw-r--r--drivers/infiniband/hw/qib/qib_wc_x86_64.c7
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib.h19
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_cm.c18
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_ib.c27
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_main.c49
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_multicast.c239
-rw-r--r--drivers/infiniband/ulp/ipoib/ipoib_verbs.c22
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.h4
-rw-r--r--drivers/infiniband/ulp/iser/iser_initiator.c16
-rw-r--r--drivers/infiniband/ulp/iser/iser_memory.c9
-rw-r--r--drivers/infiniband/ulp/iser/iser_verbs.c27
-rw-r--r--drivers/infiniband/ulp/isert/ib_isert.c46
-rw-r--r--drivers/infiniband/ulp/srpt/ib_srpt.c4
-rw-r--r--drivers/input/evdev.c71
-rw-r--r--drivers/input/input-mt.c31
-rw-r--r--drivers/input/input.c38
-rw-r--r--drivers/input/joystick/adi.c3
-rw-r--r--drivers/input/keyboard/Kconfig10
-rw-r--r--drivers/input/keyboard/Makefile1
-rw-r--r--drivers/input/keyboard/atakbd.c2
-rw-r--r--drivers/input/keyboard/atkbd.c4
-rw-r--r--drivers/input/keyboard/cap11xx.c1
-rw-r--r--drivers/input/keyboard/gpio_keys.c2
-rw-r--r--drivers/input/keyboard/imx_keypad.c3
-rw-r--r--drivers/input/keyboard/pxa27x_keypad.c9
-rw-r--r--drivers/input/keyboard/sun4i-lradc-keys.c286
-rw-r--r--drivers/input/misc/Kconfig43
-rw-r--r--drivers/input/misc/Makefile4
-rw-r--r--drivers/input/misc/axp20x-pek.c290
-rw-r--r--drivers/input/misc/bfin_rotary.c208
-rw-r--r--drivers/input/misc/drv260x.c1
-rw-r--r--drivers/input/misc/drv2667.c1
-rw-r--r--drivers/input/misc/e3x0-button.c157
-rw-r--r--drivers/input/misc/regulator-haptic.c266
-rw-r--r--drivers/input/misc/soc_button_array.c2
-rw-r--r--drivers/input/misc/tps65218-pwrbutton.c126
-rw-r--r--drivers/input/mouse/Kconfig22
-rw-r--r--drivers/input/mouse/Makefile3
-rw-r--r--drivers/input/mouse/alps.c544
-rw-r--r--drivers/input/mouse/alps.h65
-rw-r--r--drivers/input/mouse/bcm5974.c2
-rw-r--r--drivers/input/mouse/cyapa.c1710
-rw-r--r--drivers/input/mouse/cyapa.h301
-rw-r--r--drivers/input/mouse/cyapa_gen3.c1247
-rw-r--r--drivers/input/mouse/cyapa_gen5.c2777
-rw-r--r--drivers/input/mouse/cypress_ps2.c7
-rw-r--r--drivers/input/mouse/cypress_ps2.h5
-rw-r--r--drivers/input/mouse/elan_i2c.h6
-rw-r--r--drivers/input/mouse/elan_i2c_core.c21
-rw-r--r--drivers/input/mouse/elan_i2c_i2c.c1
-rw-r--r--drivers/input/mouse/elan_i2c_smbus.c3
-rw-r--r--drivers/input/mouse/elantech.c16
-rw-r--r--drivers/input/mouse/focaltech.c398
-rw-r--r--drivers/input/mouse/focaltech.h1
-rw-r--r--drivers/input/mouse/psmouse-base.c36
-rw-r--r--drivers/input/mouse/psmouse.h1
-rw-r--r--drivers/input/mouse/synaptics.c455
-rw-r--r--drivers/input/mouse/synaptics.h19
-rw-r--r--drivers/input/serio/Kconfig10
-rw-r--r--drivers/input/serio/Makefile1
-rw-r--r--drivers/input/serio/gscps2.c2
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h8
-rw-r--r--drivers/input/serio/sun4i-ps2.c340
-rw-r--r--drivers/input/tablet/gtco.c20
-rw-r--r--drivers/input/touchscreen/elants_i2c.c2
-rw-r--r--drivers/input/touchscreen/pixcir_i2c_ts.c2
-rw-r--r--drivers/input/touchscreen/sun4i-ts.c78
-rw-r--r--drivers/input/touchscreen/ti_am335x_tsc.c197
-rw-r--r--drivers/iommu/Kconfig51
-rw-r--r--drivers/iommu/Makefile5
-rw-r--r--drivers/iommu/amd_iommu.c15
-rw-r--r--drivers/iommu/amd_iommu_init.c17
-rw-r--r--drivers/iommu/amd_iommu_proto.h3
-rw-r--r--drivers/iommu/amd_iommu_types.h2
-rw-r--r--drivers/iommu/amd_iommu_v2.c35
-rw-r--r--drivers/iommu/arm-smmu.c935
-rw-r--r--drivers/iommu/fsl_pamu.c216
-rw-r--r--drivers/iommu/fsl_pamu.h15
-rw-r--r--drivers/iommu/fsl_pamu_domain.c173
-rw-r--r--drivers/iommu/intel-iommu.c45
-rw-r--r--drivers/iommu/intel_irq_remapping.c96
-rw-r--r--drivers/iommu/io-pgtable-arm.c986
-rw-r--r--drivers/iommu/io-pgtable.c82
-rw-r--r--drivers/iommu/io-pgtable.h143
-rw-r--r--drivers/iommu/iommu.c7
-rw-r--r--drivers/iommu/iova.c53
-rw-r--r--drivers/iommu/ipmmu-vmsa.c674
-rw-r--r--drivers/iommu/irq_remapping.c74
-rw-r--r--drivers/iommu/irq_remapping.h7
-rw-r--r--drivers/iommu/omap-iommu.c2
-rw-r--r--drivers/iommu/tegra-gart.c3
-rw-r--r--drivers/irqchip/Makefile1
-rw-r--r--drivers/irqchip/irq-digicolor.c120
-rw-r--r--drivers/irqchip/irq-gic-common.c18
-rw-r--r--drivers/irqchip/irq-gic-common.h2
-rw-r--r--drivers/irqchip/irq-gic-v3.c22
-rw-r--r--drivers/irqchip/irq-gic.c9
-rw-r--r--drivers/irqchip/irq-hip04.c9
-rw-r--r--drivers/irqchip/irq-mips-gic.c79
-rw-r--r--drivers/irqchip/irq-mtk-sysirq.c18
-rw-r--r--drivers/irqchip/irq-omap-intc.c22
-rw-r--r--drivers/irqchip/irq-renesas-intc-irqpin.c50
-rw-r--r--drivers/isdn/hardware/eicon/message.c2
-rw-r--r--drivers/isdn/hardware/mISDN/Kconfig2
-rw-r--r--drivers/isdn/hardware/mISDN/mISDNipac.c12
-rw-r--r--drivers/isdn/hardware/mISDN/w6692.c6
-rw-r--r--drivers/isdn/hisax/hfc4s8s_l1.c21
-rw-r--r--drivers/isdn/isdnloop/isdnloop.c64
-rw-r--r--drivers/isdn/sc/init.c15
-rw-r--r--drivers/leds/Kconfig10
-rw-r--r--drivers/leds/Makefile1
-rw-r--r--drivers/leds/led-class-flash.c486
-rw-r--r--drivers/leds/led-class.c9
-rw-r--r--drivers/leds/leds-gpio.c3
-rw-r--r--drivers/leds/leds-mc13783.c4
-rw-r--r--drivers/leds/leds.h3
-rw-r--r--drivers/lguest/Makefile3
-rw-r--r--drivers/lguest/core.c29
-rw-r--r--drivers/lguest/hypercalls.c7
-rw-r--r--drivers/lguest/lg.h26
-rw-r--r--drivers/lguest/lguest_device.c540
-rw-r--r--drivers/lguest/lguest_user.c221
-rw-r--r--drivers/lguest/page_tables.c75
-rw-r--r--drivers/lguest/x86/core.c203
-rw-r--r--drivers/mailbox/Kconfig6
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/mailbox-altera.c388
-rw-r--r--drivers/mailbox/mailbox.c2
-rw-r--r--drivers/mailbox/pcc.c8
-rw-r--r--drivers/mcb/mcb-pci.c18
-rw-r--r--drivers/md/Kconfig10
-rw-r--r--drivers/md/bitmap.c28
-rw-r--r--drivers/md/dm-bufio.c3
-rw-r--r--drivers/md/dm-cache-metadata.c9
-rw-r--r--drivers/md/dm-cache-target.c5
-rw-r--r--drivers/md/dm-crypt.c392
-rw-r--r--drivers/md/dm-io.c6
-rw-r--r--drivers/md/dm-ioctl.c4
-rw-r--r--drivers/md/dm-log-userspace-base.c5
-rw-r--r--drivers/md/dm-mpath.c87
-rw-r--r--drivers/md/dm-raid.c24
-rw-r--r--drivers/md/dm-raid1.c9
-rw-r--r--drivers/md/dm-snap-persistent.c14
-rw-r--r--drivers/md/dm-snap.c4
-rw-r--r--drivers/md/dm-table.c72
-rw-r--r--drivers/md/dm-target.c15
-rw-r--r--drivers/md/dm-thin-metadata.c9
-rw-r--r--drivers/md/dm-thin-metadata.h2
-rw-r--r--drivers/md/dm-thin.c11
-rw-r--r--drivers/md/dm.c373
-rw-r--r--drivers/md/dm.h11
-rw-r--r--drivers/md/faulty.c8
-rw-r--r--drivers/md/linear.c67
-rw-r--r--drivers/md/md.c816
-rw-r--r--drivers/md/md.h57
-rw-r--r--drivers/md/multipath.c22
-rw-r--r--drivers/md/persistent-data/Kconfig2
-rw-r--r--drivers/md/persistent-data/dm-space-map-disk.c4
-rw-r--r--drivers/md/raid0.c29
-rw-r--r--drivers/md/raid1.c55
-rw-r--r--drivers/md/raid1.h3
-rw-r--r--drivers/md/raid10.c52
-rw-r--r--drivers/md/raid10.h3
-rw-r--r--drivers/md/raid5.c342
-rw-r--r--drivers/md/raid5.h1
-rw-r--r--drivers/media/common/Kconfig4
-rw-r--r--drivers/media/common/Makefile1
-rw-r--r--drivers/media/common/btcx-risc.c260
-rw-r--r--drivers/media/common/btcx-risc.h6
-rw-r--r--drivers/media/dvb-core/dvb_net.c88
-rw-r--r--drivers/media/dvb-frontends/Kconfig4
-rw-r--r--drivers/media/dvb-frontends/au8522.h5
-rw-r--r--drivers/media/dvb-frontends/dib8000.c3
-rw-r--r--drivers/media/dvb-frontends/hd29l2.c10
-rw-r--r--drivers/media/dvb-frontends/lg2160.c6
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.c23
-rw-r--r--drivers/media/dvb-frontends/lgdt3305.h6
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.c6
-rw-r--r--drivers/media/dvb-frontends/lgdt330x.h6
-rw-r--r--drivers/media/dvb-frontends/lgdt330x_priv.h6
-rw-r--r--drivers/media/dvb-frontends/mb86a20s.c4
-rw-r--r--drivers/media/dvb-frontends/mn88472.h6
-rw-r--r--drivers/media/dvb-frontends/nxt200x.h6
-rw-r--r--drivers/media/dvb-frontends/or51132.c6
-rw-r--r--drivers/media/dvb-frontends/or51132.h6
-rw-r--r--drivers/media/dvb-frontends/rtl2830.c944
-rw-r--r--drivers/media/dvb-frontends/rtl2830.h79
-rw-r--r--drivers/media/dvb-frontends/rtl2830_priv.h24
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c1336
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h99
-rw-r--r--drivers/media/dvb-frontends/rtl2832_priv.h32
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c1189
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.h57
-rw-r--r--drivers/media/dvb-frontends/s5h1409.c6
-rw-r--r--drivers/media/dvb-frontends/s5h1409.h5
-rw-r--r--drivers/media/dvb-frontends/s5h1411.c5
-rw-r--r--drivers/media/dvb-frontends/s5h1411.h5
-rw-r--r--drivers/media/dvb-frontends/si2168.c317
-rw-r--r--drivers/media/dvb-frontends/si2168.h6
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h3
-rw-r--r--drivers/media/dvb-frontends/stb0899_algo.c5
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.c7
-rw-r--r--drivers/media/dvb-frontends/tc90522.c1
-rw-r--r--drivers/media/i2c/Kconfig9
-rw-r--r--drivers/media/i2c/adv7180.c1010
-rw-r--r--drivers/media/i2c/adv7604.c76
-rw-r--r--drivers/media/i2c/adv7842.c184
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c9
-rw-r--r--drivers/media/i2c/msp3400-driver.c8
-rw-r--r--drivers/media/i2c/mt9m032.c42
-rw-r--r--drivers/media/i2c/mt9p031.c41
-rw-r--r--drivers/media/i2c/mt9t001.c41
-rw-r--r--drivers/media/i2c/mt9v032.c43
-rw-r--r--drivers/media/i2c/s5k4ecgx.c11
-rw-r--r--drivers/media/i2c/s5k5baf.c13
-rw-r--r--drivers/media/i2c/s5k6aa.c46
-rw-r--r--drivers/media/i2c/smiapp-pll.c7
-rw-r--r--drivers/media/i2c/smiapp-pll.h8
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c386
-rw-r--r--drivers/media/i2c/smiapp/smiapp-limits.c6
-rw-r--r--drivers/media/i2c/smiapp/smiapp-limits.h6
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.c14
-rw-r--r--drivers/media/i2c/smiapp/smiapp-quirk.h24
-rw-r--r--drivers/media/i2c/smiapp/smiapp-reg-defs.h6
-rw-r--r--drivers/media/i2c/smiapp/smiapp-reg.h6
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.c6
-rw-r--r--drivers/media/i2c/smiapp/smiapp-regs.h6
-rw-r--r--drivers/media/i2c/smiapp/smiapp.h7
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c82
-rw-r--r--drivers/media/i2c/ths8200.c10
-rw-r--r--drivers/media/mmc/siano/Kconfig2
-rw-r--r--drivers/media/pci/bt8xx/Kconfig4
-rw-r--r--drivers/media/pci/bt8xx/Makefile2
-rw-r--r--drivers/media/pci/bt8xx/bt878.c6
-rw-r--r--drivers/media/pci/bt8xx/btcx-risc.c240
-rw-r--r--drivers/media/pci/bt8xx/btcx-risc.h26
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c324
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c44
-rw-r--r--drivers/media/pci/bt8xx/bttv-gpio.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-if.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-risc.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-vbi.c7
-rw-r--r--drivers/media/pci/bt8xx/bttv.h5
-rw-r--r--drivers/media/pci/bt8xx/bttvp.h20
-rw-r--r--drivers/media/pci/cx23885/Kconfig1
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c43
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c376
-rw-r--r--drivers/media/pci/cx23885/cx23885-i2c.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885.h3
-rw-r--r--drivers/media/pci/cx25821/Kconfig3
-rw-r--r--drivers/media/pci/cx25821/Makefile3
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c113
-rw-r--r--drivers/media/pci/cx25821/cx25821-core.c112
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c685
-rw-r--r--drivers/media/pci/cx25821/cx25821.h48
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c3
-rw-r--r--drivers/media/pci/cx88/cx88-core.c7
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c4
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c7
-rw-r--r--drivers/media/pci/cx88/cx88-tvaudio.c7
-rw-r--r--drivers/media/pci/ivtv/ivtv-irq.c22
-rw-r--r--drivers/media/pci/ivtv/ivtv-udma.c6
-rw-r--r--drivers/media/pci/mantis/mantis_core.c23
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c5
-rw-r--r--drivers/media/pci/smipcie/smipcie.c12
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-core.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-eeprom.c2
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-enc.c6
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-g723.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-jpeg.h4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-tw28.c4
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c48
-rw-r--r--drivers/media/pci/solo6x10/solo6x10.h6
-rw-r--r--drivers/media/pci/sta2x11/Kconfig1
-rw-r--r--drivers/media/pci/ttpci/av7110.c5
-rw-r--r--drivers/media/pci/ttpci/budget-core.c89
-rw-r--r--drivers/media/pci/tw68/tw68.h1
-rw-r--r--drivers/media/platform/Kconfig11
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/am437x/Kconfig11
-rw-r--r--drivers/media/platform/am437x/Makefile3
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.c2776
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe.h283
-rw-r--r--drivers/media/platform/am437x/am437x-vpfe_regs.h140
-rw-r--r--drivers/media/platform/coda/coda-bit.c25
-rw-r--r--drivers/media/platform/coda/coda-common.c165
-rw-r--r--drivers/media/platform/coda/coda.h2
-rw-r--r--drivers/media/platform/coda/coda_regs.h4
-rw-r--r--drivers/media/platform/davinci/Kconfig6
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.h12
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-m2m.c6
-rw-r--r--drivers/media/platform/marvell-ccic/Kconfig3
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c1
-rw-r--r--drivers/media/platform/omap3isp/isp.c3
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c17
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c23
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c21
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c6
-rw-r--r--drivers/media/platform/s5p-tv/mixer_video.c21
-rw-r--r--drivers/media/platform/sh_veu.c35
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c7
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c7
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c94
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c7
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c18
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c162
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c4
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c10
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1.h14
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c81
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c5
-rw-r--r--drivers/media/platform/vsp1/vsp1_regs.h4
-rw-r--r--drivers/media/platform/vsp1/vsp1_rpf.c18
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.h1
-rw-r--r--drivers/media/platform/vsp1/vsp1_wpf.c13
-rw-r--r--drivers/media/radio/radio-aimslab.c4
-rw-r--r--drivers/media/radio/tea575x.c41
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.c16
-rw-r--r--drivers/media/radio/wl128x/fmdrv_rx.h1
-rw-r--r--drivers/media/rc/img-ir/Kconfig15
-rw-r--r--drivers/media/rc/img-ir/Makefile2
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.c84
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.h24
-rw-r--r--drivers/media/rc/img-ir/img-ir-jvc.c8
-rw-r--r--drivers/media/rc/img-ir/img-ir-nec.c24
-rw-r--r--drivers/media/rc/img-ir/img-ir-rc5.c88
-rw-r--r--drivers/media/rc/img-ir/img-ir-rc6.c117
-rw-r--r--drivers/media/rc/img-ir/img-ir-sanyo.c8
-rw-r--r--drivers/media/rc/img-ir/img-ir-sharp.c8
-rw-r--r--drivers/media/rc/img-ir/img-ir-sony.c12
-rw-r--r--drivers/media/rc/lirc_dev.c6
-rw-r--r--drivers/media/rc/rc-main.c14
-rw-r--r--drivers/media/rc/sunxi-cir.c46
-rw-r--r--drivers/media/tuners/mt20xx.c8
-rw-r--r--drivers/media/tuners/mt2131.c5
-rw-r--r--drivers/media/tuners/mt2131.h5
-rw-r--r--drivers/media/tuners/mt2131_priv.h5
-rw-r--r--drivers/media/tuners/mxl5007t.c8
-rw-r--r--drivers/media/tuners/mxl5007t.h9
-rw-r--r--drivers/media/tuners/si2157.c189
-rw-r--r--drivers/media/tuners/si2157_priv.h3
-rw-r--r--drivers/media/tuners/tda18271-fe.c8
-rw-r--r--drivers/media/tuners/tda18271-maps.c8
-rw-r--r--drivers/media/tuners/tda18271-priv.h8
-rw-r--r--drivers/media/tuners/tda827x.c8
-rw-r--r--drivers/media/tuners/tda8290.c8
-rw-r--r--drivers/media/tuners/tda9887.c8
-rw-r--r--drivers/media/tuners/tuner-simple.c8
-rw-r--r--drivers/media/usb/au0828/Kconfig2
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c2
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c122
-rw-r--r--drivers/media/usb/au0828/au0828-video.c976
-rw-r--r--drivers/media/usb/au0828/au0828.h61
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c9
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h10
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb.h2
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvb_usb_core.c1
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c336
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h9
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.c6
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf.h6
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c940
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h27
-rw-r--r--drivers/media/usb/dvb-usb/m920x.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c8
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c14
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c9
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c7
-rw-r--r--drivers/media/usb/gspca/Kconfig10
-rw-r--r--drivers/media/usb/gspca/Makefile2
-rw-r--r--drivers/media/usb/gspca/gspca.c2
-rw-r--r--drivers/media/usb/gspca/ov534.c10
-rw-r--r--drivers/media/usb/gspca/stv06xx/stv06xx.c4
-rw-r--r--drivers/media/usb/gspca/touptek.c731
-rw-r--r--drivers/media/usb/gspca/vc032x.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-audio.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.h9
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ctrl.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ctrl.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debug.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-devattr.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-devattr.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-eeprom.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-eeprom.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-encoder.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c50
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.h13
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-ioread.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-main.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-std.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-std.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-sysfs.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-sysfs.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-util.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.c10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-v4l2.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c11
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-wm8775.c12
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-wm8775.h10
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2.h10
-rw-r--r--drivers/media/usb/pwc/pwc-if.c12
-rw-r--r--drivers/media/usb/s2255/s2255drv.c4
-rw-r--r--drivers/media/usb/siano/Kconfig2
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c5
-rw-r--r--drivers/media/usb/stkwebcam/stk-webcam.c1
-rw-r--r--drivers/media/usb/tm6000/tm6000-video.c3
-rw-r--r--drivers/media/usb/usbvision/usbvision-core.c13
-rw-r--r--drivers/media/usb/usbvision/usbvision-i2c.c8
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c8
-rw-r--r--drivers/media/usb/usbvision/usbvision.h8
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c5
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c19
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c1
-rw-r--r--drivers/media/usb/uvc/uvc_video.c6
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h3
-rw-r--r--drivers/media/usb/zr364xx/zr364xx.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c35
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c8
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c15
-rw-r--r--drivers/media/v4l2-core/videobuf2-vmalloc.c9
-rw-r--r--drivers/memory/fsl-corenet-cf.c36
-rw-r--r--drivers/message/Makefile1
-rw-r--r--drivers/message/i2o/Kconfig121
-rw-r--r--drivers/message/i2o/bus-osm.c176
-rw-r--r--drivers/message/i2o/config-osm.c90
-rw-r--r--drivers/message/i2o/debug.c472
-rw-r--r--drivers/message/i2o/device.c594
-rw-r--r--drivers/message/i2o/driver.c382
-rw-r--r--drivers/message/i2o/exec-osm.c612
-rw-r--r--drivers/message/i2o/i2o_block.c1228
-rw-r--r--drivers/message/i2o/i2o_proc.c2045
-rw-r--r--drivers/message/i2o/i2o_scsi.c814
-rw-r--r--drivers/message/i2o/iop.c1247
-rw-r--r--drivers/message/i2o/memory.c313
-rw-r--r--drivers/message/i2o/pci.c497
-rw-r--r--drivers/mfd/88pm860x-core.c2
-rw-r--r--drivers/mfd/Kconfig39
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/da9063-core.c2
-rw-r--r--drivers/mfd/da9063-i2c.c9
-rw-r--r--drivers/mfd/da9150-core.c413
-rw-r--r--drivers/mfd/davinci_voicecodec.c2
-rw-r--r--drivers/mfd/db8500-prcmu.c9
-rw-r--r--drivers/mfd/dln2.c71
-rw-r--r--drivers/mfd/hi6421-pmic-core.c2
-rw-r--r--drivers/mfd/intel_soc_pmic_core.c3
-rw-r--r--drivers/mfd/intel_soc_pmic_core.h2
-rw-r--r--drivers/mfd/intel_soc_pmic_crc.c2
-rw-r--r--drivers/mfd/lm3533-core.c2
-rw-r--r--drivers/mfd/lpc_sch.c1
-rw-r--r--drivers/mfd/max77686.c29
-rw-r--r--drivers/mfd/mc13xxx-i2c.c2
-rw-r--r--drivers/mfd/mc13xxx-spi.c2
-rw-r--r--drivers/mfd/omap-usb-host.c10
-rw-r--r--drivers/mfd/pcf50633-core.c2
-rw-r--r--drivers/mfd/qcom_rpm.c581
-rw-r--r--drivers/mfd/retu-mfd.c2
-rw-r--r--drivers/mfd/rt5033.c142
-rw-r--r--drivers/mfd/rtsx_usb.c18
-rw-r--r--drivers/mfd/smsc-ece1099.c2
-rw-r--r--drivers/mfd/sun6i-prcm.c14
-rw-r--r--drivers/mfd/tps65217.c2
-rw-r--r--drivers/mfd/tps65218.c2
-rw-r--r--drivers/mfd/twl-core.c8
-rw-r--r--drivers/mfd/twl6040.c4
-rw-r--r--drivers/mfd/wm8994-core.c6
-rw-r--r--drivers/misc/ad525x_dpot-spi.c4
-rw-r--r--drivers/misc/ad525x_dpot.c7
-rw-r--r--drivers/misc/cxl/Makefile5
-rw-r--r--drivers/misc/cxl/cxl.h22
-rw-r--r--drivers/misc/cxl/fault.c11
-rw-r--r--drivers/misc/cxl/file.c7
-rw-r--r--drivers/misc/cxl/irq.c7
-rw-r--r--drivers/misc/cxl/main.c2
-rw-r--r--drivers/misc/cxl/native.c39
-rw-r--r--drivers/misc/cxl/pci.c123
-rw-r--r--drivers/misc/cxl/sysfs.c236
-rw-r--r--drivers/misc/cxl/trace.c13
-rw-r--r--drivers/misc/cxl/trace.h459
-rw-r--r--drivers/misc/enclosure.c108
-rw-r--r--drivers/misc/genwqe/card_base.h1
-rw-r--r--drivers/misc/genwqe/card_sysfs.c1
-rw-r--r--drivers/misc/ioc4.c31
-rw-r--r--drivers/misc/mei/amthif.c14
-rw-r--r--drivers/misc/mei/bus.c69
-rw-r--r--drivers/misc/mei/client.c156
-rw-r--r--drivers/misc/mei/client.h17
-rw-r--r--drivers/misc/mei/debugfs.c32
-rw-r--r--drivers/misc/mei/hbm.c34
-rw-r--r--drivers/misc/mei/hw-me.c5
-rw-r--r--drivers/misc/mei/main.c22
-rw-r--r--drivers/misc/mei/mei_dev.h8
-rw-r--r--drivers/misc/mei/nfc.c2
-rw-r--r--drivers/misc/mei/wd.c1
-rw-r--r--drivers/misc/ti-st/st_core.c24
-rw-r--r--drivers/misc/ti-st/st_kim.c144
-rw-r--r--drivers/misc/ti-st/st_ll.c17
-rw-r--r--drivers/misc/vmw_vmci/vmci_driver.c2
-rw-r--r--drivers/misc/vmw_vmci/vmci_host.c13
-rw-r--r--drivers/misc/vmw_vmci/vmci_queue_pair.c16
-rw-r--r--drivers/mmc/card/block.c6
-rw-r--r--drivers/mmc/card/mmc_test.c18
-rw-r--r--drivers/mmc/core/Makefile2
-rw-r--r--drivers/mmc/core/bus.c4
-rw-r--r--drivers/mmc/core/core.c152
-rw-r--r--drivers/mmc/core/core.h7
-rw-r--r--drivers/mmc/core/host.c65
-rw-r--r--drivers/mmc/core/mmc.c101
-rw-r--r--drivers/mmc/core/mmc_ops.c30
-rw-r--r--drivers/mmc/core/pwrseq.c112
-rw-r--r--drivers/mmc/core/pwrseq.h43
-rw-r--r--drivers/mmc/core/pwrseq_emmc.c101
-rw-r--r--drivers/mmc/core/pwrseq_simple.c145
-rw-r--r--drivers/mmc/core/sd.c27
-rw-r--r--drivers/mmc/core/sdio.c14
-rw-r--r--drivers/mmc/core/sdio_bus.c11
-rw-r--r--drivers/mmc/core/slot-gpio.c182
-rw-r--r--drivers/mmc/core/slot-gpio.h13
-rw-r--r--drivers/mmc/host/Kconfig15
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c113
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.h56
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c2
-rw-r--r--drivers/mmc/host/dw_mmc.c124
-rw-r--r--drivers/mmc/host/dw_mmc.h9
-rw-r--r--drivers/mmc/host/mmci.c7
-rw-r--r--drivers/mmc/host/moxart-mmc.c24
-rw-r--r--drivers/mmc/host/mvsdio.c10
-rw-r--r--drivers/mmc/host/mxs-mmc.c3
-rw-r--r--drivers/mmc/host/omap_hsmmc.c150
-rw-r--r--drivers/mmc/host/rtsx_pci_sdmmc.c542
-rw-r--r--drivers/mmc/host/sdhci-acpi.c13
-rw-r--r--drivers/mmc/host/sdhci-bcm-kona.c4
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c17
-rw-r--r--drivers/mmc/host/sdhci-of-esdhc.c20
-rw-r--r--drivers/mmc/host/sdhci-pci.c7
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c119
-rw-r--r--drivers/mmc/host/sdhci-s3c.c12
-rw-r--r--drivers/mmc/host/sdhci-sirf.c74
-rw-r--r--drivers/mmc/host/sdhci-st.c4
-rw-r--r--drivers/mmc/host/sdhci-tegra.c30
-rw-r--r--drivers/mmc/host/sdhci.c125
-rw-r--r--drivers/mmc/host/sdhci.h1
-rw-r--r--drivers/mmc/host/sdhci_f_sdh30.c237
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c117
-rw-r--r--drivers/mmc/host/sunxi-mmc.c92
-rw-r--r--drivers/mmc/host/tmio_mmc.c15
-rw-r--r--drivers/mmc/host/tmio_mmc.h43
-rw-r--r--drivers/mmc/host/tmio_mmc_dma.c38
-rw-r--r--drivers/mmc/host/tmio_mmc_pio.c61
-rw-r--r--drivers/mmc/host/toshsd.c17
-rw-r--r--drivers/mmc/host/vub300.c4
-rw-r--r--drivers/mtd/bcm47xxpart.c43
-rw-r--r--drivers/mtd/chips/map_ram.c1
-rw-r--r--drivers/mtd/chips/map_rom.c13
-rw-r--r--drivers/mtd/devices/st_spi_fsm.c137
-rw-r--r--drivers/mtd/maps/physmap_of.c10
-rw-r--r--drivers/mtd/mtdblock.c10
-rw-r--r--drivers/mtd/mtdchar.c72
-rw-r--r--drivers/mtd/mtdconcat.c13
-rw-r--r--drivers/mtd/mtdcore.c109
-rw-r--r--drivers/mtd/mtdpart.c1
-rw-r--r--drivers/mtd/nand/Kconfig7
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/ams-delta.c6
-rw-r--r--drivers/mtd/nand/atmel_nand.c31
-rw-r--r--drivers/mtd/nand/denali.c40
-rw-r--r--drivers/mtd/nand/gpmi-nand/gpmi-nand.c9
-rw-r--r--drivers/mtd/nand/hisi504_nand.c891
-rw-r--r--drivers/mtd/nand/jz4740_nand.c29
-rw-r--r--drivers/mtd/nand/nand_base.c31
-rw-r--r--drivers/mtd/nand/nandsim.c7
-rw-r--r--drivers/mtd/nand/omap2.c31
-rw-r--r--drivers/mtd/nand/sunxi_nand.c2
-rw-r--r--drivers/mtd/nftlmount.c18
-rw-r--r--drivers/mtd/spi-nor/fsl-quadspi.c93
-rw-r--r--drivers/mtd/spi-nor/spi-nor.c63
-rw-r--r--drivers/mtd/ubi/block.c247
-rw-r--r--drivers/mtd/ubi/build.c6
-rw-r--r--drivers/mtd/ubi/cdev.c19
-rw-r--r--drivers/mtd/ubi/eba.c56
-rw-r--r--drivers/mtd/ubi/fastmap.c13
-rw-r--r--drivers/mtd/ubi/io.c3
-rw-r--r--drivers/mtd/ubi/kapi.c110
-rw-r--r--drivers/mtd/ubi/misc.c2
-rw-r--r--drivers/mtd/ubi/ubi.h19
-rw-r--r--drivers/mtd/ubi/vtbl.c7
-rw-r--r--drivers/mtd/ubi/wl.c10
-rw-r--r--drivers/net/Kconfig1
-rw-r--r--drivers/net/arcnet/com20020-pci.c24
-rw-r--r--drivers/net/bonding/bond_3ad.c55
-rw-r--r--drivers/net/bonding/bond_main.c121
-rw-r--r--drivers/net/bonding/bond_options.c6
-rw-r--r--drivers/net/caif/caif_hsi.c1
-rw-r--r--drivers/net/can/at91_can.c2
-rw-r--r--drivers/net/can/bfin_can.c1
-rw-r--r--drivers/net/can/c_can/c_can.c2
-rw-r--r--drivers/net/can/cc770/cc770.c1
-rw-r--r--drivers/net/can/dev.c5
-rw-r--r--drivers/net/can/flexcan.c2
-rw-r--r--drivers/net/can/janz-ican3.c7
-rw-r--r--drivers/net/can/m_can/m_can.c1
-rw-r--r--drivers/net/can/pch_can.c1
-rw-r--r--drivers/net/can/rcar_can.c1
-rw-r--r--drivers/net/can/softing/softing_main.c1
-rw-r--r--drivers/net/can/spi/mcp251x.c1
-rw-r--r--drivers/net/can/ti_hecc.c1
-rw-r--r--drivers/net/can/usb/Kconfig22
-rw-r--r--drivers/net/can/usb/ems_usb.c1
-rw-r--r--drivers/net/can/usb/esd_usb2.c1
-rw-r--r--drivers/net/can/usb/kvaser_usb.c723
-rw-r--r--drivers/net/can/usb/peak_usb/Makefile2
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_ucan.h222
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb.c4
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.c83
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_core.h26
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_fd.c1095
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.c20
-rw-r--r--drivers/net/can/usb/peak_usb/pcan_usb_pro.h13
-rw-r--r--drivers/net/can/usb/usb_8dev.c1
-rw-r--r--drivers/net/dsa/bcm_sf2.c88
-rw-r--r--drivers/net/dsa/bcm_sf2_regs.h4
-rw-r--r--drivers/net/dsa/mv88e6131.c3
-rw-r--r--drivers/net/dsa/mv88e6352.c13
-rw-r--r--drivers/net/dsa/mv88e6xxx.c9
-rw-r--r--drivers/net/ethernet/3com/3c589_cs.c7
-rw-r--r--drivers/net/ethernet/3com/typhoon.c4
-rw-r--r--drivers/net/ethernet/agere/et131x.c6
-rw-r--r--drivers/net/ethernet/alteon/acenic.c8
-rw-r--r--drivers/net/ethernet/amd/Kconfig6
-rw-r--r--drivers/net/ethernet/amd/amd8111e.c4
-rw-r--r--drivers/net/ethernet/amd/atarilance.c8
-rw-r--r--drivers/net/ethernet/amd/nmclan_cs.c2
-rw-r--r--drivers/net/ethernet/amd/pcnet32.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c2
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-desc.c32
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-dev.c66
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-drv.c82
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-main.c203
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-mdio.c29
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe-ptp.c12
-rw-r--r--drivers/net/ethernet/amd/xgbe/xgbe.h31
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_hw.c94
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.c113
-rw-r--r--drivers/net/ethernet/apm/xgene/xgene_enet_main.h3
-rw-r--r--drivers/net/ethernet/atheros/atl1c/atl1c_main.c4
-rw-r--r--drivers/net/ethernet/atheros/atl1e/atl1e_main.c9
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl1.c4
-rw-r--r--drivers/net/ethernet/atheros/atlx/atl2.c14
-rw-r--r--drivers/net/ethernet/broadcom/b44.c2
-rw-r--r--drivers/net/ethernet/broadcom/bgmac.c7
-rw-r--r--drivers/net/ethernet/broadcom/bnx2.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x.h6
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c4
-rw-r--r--drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c14
-rw-r--r--drivers/net/ethernet/broadcom/tg3.c31
-rw-r--r--drivers/net/ethernet/brocade/bna/bnad.c4
-rw-r--r--drivers/net/ethernet/cadence/macb.c84
-rw-r--r--drivers/net/ethernet/cadence/macb.h631
-rw-r--r--drivers/net/ethernet/chelsio/cxgb/sge.c4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/mc5.c16
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/sge.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb3/t3_hw.c6
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/Makefile2
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c317
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h41
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4.h169
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c100
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h11
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c1926
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h35
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c1003
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h3
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/l2t.c13
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/sge.c270
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.c1543
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_hw.h24
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_msg.h367
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h1
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_regs.h3392
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4_values.h124
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h101
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h48
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c44
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/sge.c57
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h4
-rw-r--r--drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c43
-rw-r--r--drivers/net/ethernet/cirrus/Kconfig3
-rw-r--r--drivers/net/ethernet/cirrus/ep93xx_eth.c6
-rw-r--r--drivers/net/ethernet/cisco/enic/enic.h16
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.c56
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_dev.h5
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_ethtool.c21
-rw-r--r--drivers/net/ethernet/cisco/enic/enic_main.c179
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_stats.h5
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_wq.c3
-rw-r--r--drivers/net/ethernet/cisco/enic/vnic_wq.h1
-rw-r--r--drivers/net/ethernet/davicom/dm9000.c40
-rw-r--r--drivers/net/ethernet/dec/tulip/winbond-840.c2
-rw-r--r--drivers/net/ethernet/emulex/benet/be.h203
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.c231
-rw-r--r--drivers/net/ethernet/emulex/benet/be_cmds.h218
-rw-r--r--drivers/net/ethernet/emulex/benet/be_ethtool.c16
-rw-r--r--drivers/net/ethernet/emulex/benet/be_hw.h240
-rw-r--r--drivers/net/ethernet/emulex/benet/be_main.c952
-rw-r--r--drivers/net/ethernet/freescale/Kconfig3
-rw-r--r--drivers/net/ethernet/freescale/fec.h3
-rw-r--r--drivers/net/ethernet/freescale/fec_main.c145
-rw-r--r--drivers/net/ethernet/freescale/fec_ptp.c16
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c95
-rw-r--r--drivers/net/ethernet/freescale/fs_enet/fs_enet.h1
-rw-r--r--drivers/net/ethernet/freescale/gianfar.c17
-rw-r--r--drivers/net/ethernet/freescale/gianfar.h2
-rw-r--r--drivers/net/ethernet/freescale/gianfar_ethtool.c2
-rw-r--r--drivers/net/ethernet/freescale/xgmac_mdio.c130
-rw-r--r--drivers/net/ethernet/hisilicon/Kconfig9
-rw-r--r--drivers/net/ethernet/hisilicon/Makefile1
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_eth.c971
-rw-r--r--drivers/net/ethernet/hisilicon/hip04_mdio.c186
-rw-r--r--drivers/net/ethernet/ibm/ehea/ehea_main.c4
-rw-r--r--drivers/net/ethernet/ibm/emac/core.c2
-rw-r--r--drivers/net/ethernet/intel/Kconfig11
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_ethtool.c3
-rw-r--r--drivers/net/ethernet/intel/e1000/e1000_main.c20
-rw-r--r--drivers/net/ethernet/intel/e1000e/e1000.h2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c41
-rw-r--r--drivers/net/ethernet/intel/e1000e/ptp.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_main.c44
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_mbx.c5
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_netdev.c15
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_pf.c7
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_ptp.c3
-rw-r--r--drivers/net/ethernet/intel/fm10k/fm10k_type.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e.h10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq.h2
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h152
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_common.c136
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_debugfs.c1
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ethtool.c43
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_fcoe.c18
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_main.c149
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_prototype.h5
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_ptp.c44
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_txrx.c13
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_type.h10
-rw-r--r--drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c34
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_adminq.h2
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h108
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.c44
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_txrx.h1
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40e_type.h8
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_main.c112
-rw-r--r--drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c6
-rw-r--r--drivers/net/ethernet/intel/igb/igb.h11
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c157
-rw-r--r--drivers/net/ethernet/intel/igb/igb_ptp.c267
-rw-r--r--drivers/net/ethernet/intel/igbvf/netdev.c24
-rw-r--r--drivers/net/ethernet/intel/ixgb/ixgb_main.c4
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe.h5
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_main.c120
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c13
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c16
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_type.h12
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c3
-rw-r--r--drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c90
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf.h36
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c503
-rw-r--r--drivers/net/ethernet/intel/ixgbevf/regs.h10
-rw-r--r--drivers/net/ethernet/jme.c4
-rw-r--r--drivers/net/ethernet/marvell/sky2.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/alloc.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/catas.c294
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/cmd.c422
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_clock.c10
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_cq.c4
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_ethtool.c20
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_main.c12
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_netdev.c182
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_resources.c8
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_rx.c13
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/en_tx.c16
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/eq.c100
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.c144
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/fw.h1
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/icm.c11
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/intf.c62
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/main.c489
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mcg.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4.h34
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mlx4_en.h5
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/mr.c25
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/pd.c7
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/port.c17
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/qp.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/reset.c23
-rw-r--r--drivers/net/ethernet/mellanox/mlx4/resource_tracker.c57
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/alloc.c2
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/debugfs.c6
-rw-r--r--drivers/net/ethernet/mellanox/mlx5/core/main.c13
-rw-r--r--drivers/net/ethernet/micrel/ksz884x.c4
-rw-r--r--drivers/net/ethernet/myricom/myri10ge/myri10ge.c3
-rw-r--r--drivers/net/ethernet/natsemi/ns83820.c4
-rw-r--r--drivers/net/ethernet/neterion/s2io.c4
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-config.c2
-rw-r--r--drivers/net/ethernet/neterion/vxge/vxge-main.c4
-rw-r--r--drivers/net/ethernet/nvidia/forcedeth.c4
-rw-r--r--drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c8
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h11
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c34
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c50
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c24
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c3
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c19
-rw-r--r--drivers/net/ethernet/qlogic/qlge/qlge_main.c32
-rw-r--r--drivers/net/ethernet/realtek/8139cp.c4
-rw-r--r--drivers/net/ethernet/realtek/r8169.c22
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.c48
-rw-r--r--drivers/net/ethernet/renesas/sh_eth.h30
-rw-r--r--drivers/net/ethernet/rocker/rocker.c177
-rw-r--r--drivers/net/ethernet/rocker/rocker.h21
-rw-r--r--drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c69
-rw-r--r--drivers/net/ethernet/smsc/Kconfig10
-rw-r--r--drivers/net/ethernet/smsc/smc91x.h21
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/Makefile2
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c437
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c13
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_main.c26
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c113
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c4
-rw-r--r--drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h1
-rw-r--r--drivers/net/ethernet/sun/niu.c3
-rw-r--r--drivers/net/ethernet/sun/sunvnet.c114
-rw-r--r--drivers/net/ethernet/tehuti/tehuti.c4
-rw-r--r--drivers/net/ethernet/ti/Kconfig29
-rw-r--r--drivers/net/ethernet/ti/Makefile11
-rw-r--r--drivers/net/ethernet/ti/cpsw-common.c55
-rw-r--r--drivers/net/ethernet/ti/cpsw.c111
-rw-r--r--drivers/net/ethernet/ti/cpsw.h2
-rw-r--r--drivers/net/ethernet/ti/cpsw_ale.c26
-rw-r--r--drivers/net/ethernet/ti/cpts.c5
-rw-r--r--drivers/net/ethernet/ti/cpts.h1
-rw-r--r--drivers/net/ethernet/ti/davinci_emac.c56
-rw-r--r--drivers/net/ethernet/ti/netcp.h229
-rw-r--r--drivers/net/ethernet/ti/netcp_core.c2149
-rw-r--r--drivers/net/ethernet/ti/netcp_ethss.c2159
-rw-r--r--drivers/net/ethernet/ti/netcp_sgmii.c131
-rw-r--r--drivers/net/ethernet/ti/netcp_xgbepcsr.c501
-rw-r--r--drivers/net/ethernet/ti/tlan.c14
-rw-r--r--drivers/net/ethernet/tile/tilegx.c5
-rw-r--r--drivers/net/ethernet/tile/tilepro.c5
-rw-r--r--drivers/net/ethernet/via/via-rhine.c9
-rw-r--r--drivers/net/ethernet/via/via-velocity.c4
-rw-r--r--drivers/net/fddi/skfp/smt.c12
-rw-r--r--drivers/net/hyperv/netvsc.c22
-rw-r--r--drivers/net/hyperv/rndis_filter.c24
-rw-r--r--drivers/net/ieee802154/at86rf230.c82
-rw-r--r--drivers/net/ieee802154/cc2520.c37
-rw-r--r--drivers/net/ieee802154/mrf24j40.c6
-rw-r--r--drivers/net/ipvlan/ipvlan.h2
-rw-r--r--drivers/net/ipvlan/ipvlan_core.c2
-rw-r--r--drivers/net/irda/ali-ircc.c11
-rw-r--r--drivers/net/irda/ali-ircc.h5
-rw-r--r--drivers/net/irda/au1k_ir.c3
-rw-r--r--drivers/net/irda/irda-usb.c10
-rw-r--r--drivers/net/irda/irda-usb.h5
-rw-r--r--drivers/net/irda/kingsun-sir.c3
-rw-r--r--drivers/net/irda/ks959-sir.c3
-rw-r--r--drivers/net/irda/mcs7780.c2
-rw-r--r--drivers/net/irda/mcs7780.h1
-rw-r--r--drivers/net/irda/nsc-ircc.c7
-rw-r--r--drivers/net/irda/nsc-ircc.h5
-rw-r--r--drivers/net/irda/sa1100_ir.c2
-rw-r--r--drivers/net/irda/stir4200.c16
-rw-r--r--drivers/net/irda/via-ircc.h4
-rw-r--r--drivers/net/irda/vlsi_ir.c46
-rw-r--r--drivers/net/irda/vlsi_ir.h2
-rw-r--r--drivers/net/macvlan.c6
-rw-r--r--drivers/net/macvtap.c22
-rw-r--r--drivers/net/mii.c12
-rw-r--r--drivers/net/phy/Kconfig2
-rw-r--r--drivers/net/phy/amd-xgbe-phy.c981
-rw-r--r--drivers/net/phy/fixed_phy.c2
-rw-r--r--drivers/net/phy/mdio_bus.c14
-rw-r--r--drivers/net/phy/micrel.c28
-rw-r--r--drivers/net/phy/phy.c3
-rw-r--r--drivers/net/phy/phy_device.c22
-rw-r--r--drivers/net/ppp/ppp_deflate.c2
-rw-r--r--drivers/net/team/team.c12
-rw-r--r--drivers/net/tun.c62
-rw-r--r--drivers/net/usb/Kconfig12
-rw-r--r--drivers/net/usb/hso.c108
-rw-r--r--drivers/net/usb/r8152.c288
-rw-r--r--drivers/net/usb/sr9700.c36
-rw-r--r--drivers/net/usb/sr9700.h66
-rw-r--r--drivers/net/usb/usbnet.c17
-rw-r--r--drivers/net/veth.c9
-rw-r--r--drivers/net/virtio_net.c36
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h3
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c54
-rw-r--r--drivers/net/vmxnet3/vmxnet3_ethtool.c29
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h6
-rw-r--r--drivers/net/vxlan.c462
-rw-r--r--drivers/net/wan/Kconfig6
-rw-r--r--drivers/net/wireless/adm8211.c1
-rw-r--r--drivers/net/wireless/ath/ath.h1
-rw-r--r--drivers/net/wireless/ath/ath10k/Makefile6
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.c14
-rw-r--r--drivers/net/wireless/ath/ath10k/ce.h2
-rw-r--r--drivers/net/wireless/ath/ath10k/core.c322
-rw-r--r--drivers/net/wireless/ath/ath10k/core.h61
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.c122
-rw-r--r--drivers/net/wireless/ath/ath10k/debug.h11
-rw-r--r--drivers/net/wireless/ath/ath10k/debugfs_sta.c243
-rw-r--r--drivers/net/wireless/ath/ath10k/htc.c6
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.c3
-rw-r--r--drivers/net/wireless/ath/ath10k/htt.h87
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_rx.c402
-rw-r--r--drivers/net/wireless/ath/ath10k/htt_tx.c99
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.c58
-rw-r--r--drivers/net/wireless/ath/ath10k/hw.h136
-rw-r--r--drivers/net/wireless/ath/ath10k/mac.c666
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.c170
-rw-r--r--drivers/net/wireless/ath/ath10k/pci.h7
-rw-r--r--drivers/net/wireless/ath/ath10k/rx_desc.h25
-rw-r--r--drivers/net/wireless/ath/ath10k/spectral.c1
-rw-r--r--drivers/net/wireless/ath/ath10k/targaddrs.h5
-rw-r--r--drivers/net/wireless/ath/ath10k/testmode.c5
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.c244
-rw-r--r--drivers/net/wireless/ath/ath10k/thermal.h58
-rw-r--r--drivers/net/wireless/ath/ath10k/trace.h68
-rw-r--r--drivers/net/wireless/ath/ath10k/txrx.c9
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-ops.h1064
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.c2696
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi-tlv.h1444
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.c2238
-rw-r--r--drivers/net/wireless/ath/ath10k/wmi.h449
-rw-r--r--drivers/net/wireless/ath/ath5k/ahb.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/mac80211-ops.c16
-rw-r--r--drivers/net/wireless/ath/ath5k/pcu.c1
-rw-r--r--drivers/net/wireless/ath/ath5k/reset.c2
-rw-r--r--drivers/net/wireless/ath/ath6kl/cfg80211.c17
-rw-r--r--drivers/net/wireless/ath/ath6kl/main.c1
-rw-r--r--drivers/net/wireless/ath/ath9k/ahb.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/ani.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/ar5008_phy.c80
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_calib.c61
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_eeprom.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_hw.c61
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.c47
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_phy.h19
-rw-r--r--drivers/net/wireless/ath/ath9k/ar9003_wow.c315
-rw-r--r--drivers/net/wireless/ath/ath9k/ar953x_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h4
-rw-r--r--drivers/net/wireless/ath/ath9k/ar956x_initvals.h1046
-rw-r--r--drivers/net/wireless/ath/ath9k/ath9k.h15
-rw-r--r--drivers/net/wireless/ath/ath9k/common-spectral.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/debug.c263
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_4k.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_9287.c15
-rw-r--r--drivers/net/wireless/ath/ath9k/eeprom_def.c14
-rw-r--r--drivers/net/wireless/ath/ath9k/gpio.c2
-rw-r--r--drivers/net/wireless/ath/ath9k/htc.h3
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_debug.c23
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_gpio.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_drv_init.c4
-rw-r--r--drivers/net/wireless/ath/ath9k/htc_hst.c6
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.c53
-rw-r--r--drivers/net/wireless/ath/ath9k/hw.h40
-rw-r--r--drivers/net/wireless/ath/ath9k/init.c5
-rw-r--r--drivers/net/wireless/ath/ath9k/link.c16
-rw-r--r--drivers/net/wireless/ath/ath9k/mac.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/main.c9
-rw-r--r--drivers/net/wireless/ath/ath9k/pci.c90
-rw-r--r--drivers/net/wireless/ath/ath9k/recv.c3
-rw-r--r--drivers/net/wireless/ath/ath9k/reg.h129
-rw-r--r--drivers/net/wireless/ath/ath9k/reg_wow.h128
-rw-r--r--drivers/net/wireless/ath/ath9k/wow.c228
-rw-r--r--drivers/net/wireless/ath/ath9k/xmit.c83
-rw-r--r--drivers/net/wireless/ath/carl9170/cmd.c12
-rw-r--r--drivers/net/wireless/ath/carl9170/debug.c24
-rw-r--r--drivers/net/wireless/ath/carl9170/main.c6
-rw-r--r--drivers/net/wireless/ath/dfs_pattern_detector.c2
-rw-r--r--drivers/net/wireless/ath/wcn36xx/dxe.c3
-rw-r--r--drivers/net/wireless/ath/wcn36xx/main.c16
-rw-r--r--drivers/net/wireless/ath/wcn36xx/smd.c73
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.c83
-rw-r--r--drivers/net/wireless/ath/wcn36xx/txrx.h9
-rw-r--r--drivers/net/wireless/ath/wcn36xx/wcn36xx.h20
-rw-r--r--drivers/net/wireless/ath/wil6210/Kconfig9
-rw-r--r--drivers/net/wireless/ath/wil6210/Makefile1
-rw-r--r--drivers/net/wireless/ath/wil6210/cfg80211.c179
-rw-r--r--drivers/net/wireless/ath/wil6210/debugfs.c164
-rw-r--r--drivers/net/wireless/ath/wil6210/ethtool.c46
-rw-r--r--drivers/net/wireless/ath/wil6210/interrupt.c109
-rw-r--r--drivers/net/wireless/ath/wil6210/main.c205
-rw-r--r--drivers/net/wireless/ath/wil6210/netdev.c15
-rw-r--r--drivers/net/wireless/ath/wil6210/pcie_bus.c65
-rw-r--r--drivers/net/wireless/ath/wil6210/rx_reorder.c277
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.c151
-rw-r--r--drivers/net/wireless/ath/wil6210/txrx.h158
-rw-r--r--drivers/net/wireless/ath/wil6210/wil6210.h183
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform.c12
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.c257
-rw-r--r--drivers/net/wireless/ath/wil6210/wil_platform_msm.h24
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.c239
-rw-r--r--drivers/net/wireless/ath/wil6210/wmi.h70
-rw-r--r--drivers/net/wireless/atmel.c12
-rw-r--r--drivers/net/wireless/b43/Kconfig9
-rw-r--r--drivers/net/wireless/b43/Makefile1
-rw-r--r--drivers/net/wireless/b43/b43.h3
-rw-r--r--drivers/net/wireless/b43/main.c75
-rw-r--r--drivers/net/wireless/b43/phy_ac.c92
-rw-r--r--drivers/net/wireless/b43/phy_ac.h38
-rw-r--r--drivers/net/wireless/b43/phy_common.c9
-rw-r--r--drivers/net/wireless/b43/phy_common.h2
-rw-r--r--drivers/net/wireless/b43legacy/main.c2
-rw-r--r--drivers/net/wireless/b43legacy/radio.c19
-rw-r--r--drivers/net/wireless/b43legacy/radio.h1
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c90
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/bus.h24
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c227
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/chip.c15
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/common.c34
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/common.h20
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/commonring.h2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.c42
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/core.h34
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/firmware.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/flowring.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil.h5
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h55
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c54
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/pcie.c12
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.c178
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/sdio.h12
-rw-r--r--drivers/net/wireless/brcm80211/brcmfmac/usb.c6
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/debug.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c2
-rw-r--r--drivers/net/wireless/brcm80211/brcmutil/utils.c32
-rw-r--r--drivers/net/wireless/brcm80211/include/brcm_hw_ids.h12
-rw-r--r--drivers/net/wireless/brcm80211/include/brcmu_utils.h4
-rw-r--r--drivers/net/wireless/cw1200/fwio.c40
-rw-r--r--drivers/net/wireless/cw1200/main.c6
-rw-r--r--drivers/net/wireless/cw1200/pm.c5
-rw-r--r--drivers/net/wireless/cw1200/queue.c4
-rw-r--r--drivers/net/wireless/cw1200/scan.c8
-rw-r--r--drivers/net/wireless/cw1200/sta.c4
-rw-r--r--drivers/net/wireless/hostap/hostap_ap.c2
-rw-r--r--drivers/net/wireless/iwlegacy/3945-mac.c4
-rw-r--r--drivers/net/wireless/iwlegacy/4965-mac.c9
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/main.c31
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tt.c13
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/tx.c2
-rw-r--r--drivers/net/wireless/iwlwifi/dvm/ucode.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-7000.c23
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-8000.c31
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-config.h17
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.c88
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-drv.h1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h43
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw-file.h18
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-fw.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-io.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-modparams.h4
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-nvm-parse.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-prph.h52
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-scd.h41
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-trans.h50
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex.c20
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/coex_legacy.c20
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/constants.h35
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/d3.c51
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c33
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/debugfs.c247
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-power.h20
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h40
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h277
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h39
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw-api.h301
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/fw.c117
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c24
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mac80211.c362
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/mvm.h88
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/nvm.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/ops.c83
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c4
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.c551
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rs.h53
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/rx.c10
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/scan.c68
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/sta.c44
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tdls.c63
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tt.c7
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/tx.c12
-rw-r--r--drivers/net/wireless/iwlwifi/mvm/utils.c79
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/drv.c2
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/internal.h18
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/trans.c78
-rw-r--r--drivers/net/wireless/iwlwifi/pcie/tx.c100
-rw-r--r--drivers/net/wireless/libertas/cfg.c12
-rw-r--r--drivers/net/wireless/mac80211_hwsim.c33
-rw-r--r--drivers/net/wireless/mwifiex/11h.c198
-rw-r--r--drivers/net/wireless/mwifiex/11n.c6
-rw-r--r--drivers/net/wireless/mwifiex/11n.h14
-rw-r--r--drivers/net/wireless/mwifiex/11n_aggr.c15
-rw-r--r--drivers/net/wireless/mwifiex/11n_rxreorder.c16
-rw-r--r--drivers/net/wireless/mwifiex/Makefile2
-rw-r--r--drivers/net/wireless/mwifiex/cfg80211.c951
-rw-r--r--drivers/net/wireless/mwifiex/cfp.c22
-rw-r--r--drivers/net/wireless/mwifiex/cmdevt.c46
-rw-r--r--drivers/net/wireless/mwifiex/debugfs.c281
-rw-r--r--drivers/net/wireless/mwifiex/decl.h55
-rw-r--r--drivers/net/wireless/mwifiex/ethtool.c16
-rw-r--r--drivers/net/wireless/mwifiex/fw.h61
-rw-r--r--drivers/net/wireless/mwifiex/ie.c89
-rw-r--r--drivers/net/wireless/mwifiex/init.c35
-rw-r--r--drivers/net/wireless/mwifiex/ioctl.h11
-rw-r--r--drivers/net/wireless/mwifiex/main.c147
-rw-r--r--drivers/net/wireless/mwifiex/main.h84
-rw-r--r--drivers/net/wireless/mwifiex/pcie.c7
-rw-r--r--drivers/net/wireless/mwifiex/pcie.h3
-rw-r--r--drivers/net/wireless/mwifiex/scan.c16
-rw-r--r--drivers/net/wireless/mwifiex/sdio.c111
-rw-r--r--drivers/net/wireless/mwifiex/sdio.h49
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmd.c24
-rw-r--r--drivers/net/wireless/mwifiex/sta_cmdresp.c7
-rw-r--r--drivers/net/wireless/mwifiex/sta_event.c18
-rw-r--r--drivers/net/wireless/mwifiex/sta_ioctl.c38
-rw-r--r--drivers/net/wireless/mwifiex/sta_rx.c9
-rw-r--r--drivers/net/wireless/mwifiex/sta_tx.c28
-rw-r--r--drivers/net/wireless/mwifiex/tdls.c35
-rw-r--r--drivers/net/wireless/mwifiex/txrx.c2
-rw-r--r--drivers/net/wireless/mwifiex/uap_cmd.c70
-rw-r--r--drivers/net/wireless/mwifiex/uap_event.c50
-rw-r--r--drivers/net/wireless/mwifiex/uap_txrx.c28
-rw-r--r--drivers/net/wireless/mwifiex/usb.c27
-rw-r--r--drivers/net/wireless/mwifiex/usb.h11
-rw-r--r--drivers/net/wireless/mwifiex/util.c222
-rw-r--r--drivers/net/wireless/mwifiex/util.h20
-rw-r--r--drivers/net/wireless/mwifiex/wmm.c3
-rw-r--r--drivers/net/wireless/mwl8k.c12
-rw-r--r--drivers/net/wireless/orinoco/Kconfig3
-rw-r--r--drivers/net/wireless/orinoco/main.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_pci.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_plx.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_tmd.c2
-rw-r--r--drivers/net/wireless/orinoco/orinoco_usb.c4
-rw-r--r--drivers/net/wireless/p54/eeprom.c6
-rw-r--r--drivers/net/wireless/p54/fwio.c9
-rw-r--r--drivers/net/wireless/p54/main.c10
-rw-r--r--drivers/net/wireless/p54/p54pci.c7
-rw-r--r--drivers/net/wireless/p54/txrx.c12
-rw-r--r--drivers/net/wireless/rndis_wlan.c4
-rw-r--r--drivers/net/wireless/rsi/rsi_91x_sdio_ops.c4
-rw-r--r--drivers/net/wireless/rt2x00/Kconfig6
-rw-r--r--drivers/net/wireless/rt2x00/rt2800lib.c12
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00config.c4
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00dev.c18
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00firmware.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00mac.c2
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00queue.c18
-rw-r--r--drivers/net/wireless/rt2x00/rt2x00usb.c8
-rw-r--r--drivers/net/wireless/rtlwifi/base.c156
-rw-r--r--drivers/net/wireless/rtlwifi/base.h4
-rw-r--r--drivers/net/wireless/rtlwifi/core.c72
-rw-r--r--drivers/net/wireless/rtlwifi/core.h42
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c36
-rw-r--r--drivers/net/wireless/rtlwifi/pci.h7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.c36
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/dm.h41
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8188ee/trx.c162
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c45
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h38
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/dm.c1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/dm.h13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/hw.c165
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/phy.c5
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/sw.c30
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ce/trx.c13
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/hw.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/mac.c4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/sw.c28
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192cu/trx.c20
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.c33
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/dm.h38
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/fw.c17
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/fw.h1
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/hw.c2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/sw.c30
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192de/trx.c27
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/dm.c55
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/dm.h16
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/fw.c6
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/hw.c166
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/reg.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/sw.c3
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/trx.c200
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192ee/trx.h12
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/def.h8
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.c7
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/dm.h28
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/sw.c30
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8192se/trx.c23
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.c42
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/dm.h38
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723ae/trx.c162
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.c55
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/dm.h33
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/phy.c25
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/phy.h2
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/sw.c10
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8723be/trx.c162
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/def.h54
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/dm.c58
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/dm.h41
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h4
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/sw.c74
-rw-r--r--drivers/net/wireless/rtlwifi/rtl8821ae/trx.c232
-rw-r--r--drivers/net/wireless/rtlwifi/wifi.h99
-rw-r--r--drivers/net/wireless/ti/wl1251/main.c5
-rw-r--r--drivers/net/wireless/ti/wl12xx/main.c4
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.c88
-rw-r--r--drivers/net/wireless/ti/wl18xx/acx.h46
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.c93
-rw-r--r--drivers/net/wireless/ti/wl18xx/cmd.h27
-rw-r--r--drivers/net/wireless/ti/wl18xx/conf.h23
-rw-r--r--drivers/net/wireless/ti/wl18xx/debugfs.c43
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.c21
-rw-r--r--drivers/net/wireless/ti/wl18xx/event.h14
-rw-r--r--drivers/net/wireless/ti/wl18xx/main.c37
-rw-r--r--drivers/net/wireless/ti/wl18xx/wl18xx.h4
-rw-r--r--drivers/net/wireless/ti/wlcore/acx.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.c20
-rw-r--r--drivers/net/wireless/ti/wlcore/cmd.h8
-rw-r--r--drivers/net/wireless/ti/wlcore/conf.h7
-rw-r--r--drivers/net/wireless/ti/wlcore/debugfs.c9
-rw-r--r--drivers/net/wireless/ti/wlcore/event.c11
-rw-r--r--drivers/net/wireless/ti/wlcore/hw_ops.h48
-rw-r--r--drivers/net/wireless/ti/wlcore/init.c8
-rw-r--r--drivers/net/wireless/ti/wlcore/main.c405
-rw-r--r--drivers/net/wireless/ti/wlcore/ps.c8
-rw-r--r--drivers/net/wireless/ti/wlcore/vendor_cmd.c2
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore.h12
-rw-r--r--drivers/net/wireless/ti/wlcore/wlcore_i.h7
-rw-r--r--drivers/net/xen-netback/common.h1
-rw-r--r--drivers/net/xen-netback/interface.c11
-rw-r--r--drivers/net/xen-netback/netback.c216
-rw-r--r--drivers/net/xen-netfront.c258
-rw-r--r--drivers/nfc/microread/microread.c3
-rw-r--r--drivers/nfc/pn544/i2c.c133
-rw-r--r--drivers/nfc/pn544/pn544.c3
-rw-r--r--drivers/nfc/st21nfca/Makefile2
-rw-r--r--drivers/nfc/st21nfca/i2c.c23
-rw-r--r--drivers/nfc/st21nfca/st21nfca.c186
-rw-r--r--drivers/nfc/st21nfca/st21nfca.h21
-rw-r--r--drivers/nfc/st21nfca/st21nfca_se.c411
-rw-r--r--drivers/nfc/st21nfca/st21nfca_se.h63
-rw-r--r--drivers/nfc/st21nfcb/Makefile2
-rw-r--r--drivers/nfc/st21nfcb/i2c.c19
-rw-r--r--drivers/nfc/st21nfcb/ndlc.c3
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.c11
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb.h2
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb_se.c707
-rw-r--r--drivers/nfc/st21nfcb/st21nfcb_se.h61
-rw-r--r--drivers/of/Kconfig1
-rw-r--r--drivers/of/base.c1
-rw-r--r--drivers/of/fdt.c2
-rw-r--r--drivers/of/of_pci.c3
-rw-r--r--drivers/of/of_reserved_mem.c2
-rw-r--r--drivers/of/platform.c1
-rw-r--r--drivers/of/unittest-data/tests-overlay.dtsi94
-rw-r--r--drivers/of/unittest.c597
-rw-r--r--drivers/parport/parport_atari.c4
-rw-r--r--drivers/pci/access.c87
-rw-r--r--drivers/pci/bus.c18
-rw-r--r--drivers/pci/host-bridge.c8
-rw-r--r--drivers/pci/host/Kconfig4
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-host-generic.c55
-rw-r--r--drivers/pci/host/pci-keystone.c4
-rw-r--r--drivers/pci/host/pci-layerscape.c1
-rw-r--r--drivers/pci/host/pci-mvebu.c15
-rw-r--r--drivers/pci/host/pci-rcar-gen2.c51
-rw-r--r--drivers/pci/host/pci-tegra.c68
-rw-r--r--drivers/pci/host/pci-versatile.c237
-rw-r--r--drivers/pci/host/pci-xgene.c156
-rw-r--r--drivers/pci/host/pcie-designware.c6
-rw-r--r--drivers/pci/host/pcie-rcar.c7
-rw-r--r--drivers/pci/host/pcie-xilinx.c96
-rw-r--r--drivers/pci/hotplug/cpci_hotplug_core.c3
-rw-r--r--drivers/pci/hotplug/pciehp_ctrl.c2
-rw-r--r--drivers/pci/hotplug/sgi_hotplug.c13
-rw-r--r--drivers/pci/msi.c5
-rw-r--r--drivers/pci/pci-acpi.c17
-rw-r--r--drivers/pci/pci-driver.c13
-rw-r--r--drivers/pci/pci.c77
-rw-r--r--drivers/pci/pci.h6
-rw-r--r--drivers/pci/pcie/aer/Kconfig2
-rw-r--r--drivers/pci/pcie/aspm.c12
-rw-r--r--drivers/pci/probe.c10
-rw-r--r--drivers/pci/quirks.c104
-rw-r--r--drivers/pci/rom.c7
-rw-r--r--drivers/pcmcia/Kconfig13
-rw-r--r--drivers/pcmcia/Makefile1
-rw-r--r--drivers/pcmcia/cistpl.c31
-rw-r--r--drivers/pcmcia/cs_internal.h6
-rw-r--r--drivers/pcmcia/ds.c3
-rw-r--r--drivers/pcmcia/rsrc_mgr.c5
-rw-r--r--drivers/pcmcia/rsrc_pci.c173
-rw-r--r--drivers/phy/Kconfig14
-rw-r--r--drivers/phy/Makefile4
-rw-r--r--drivers/phy/phy-armada375-usb2.c4
-rw-r--r--drivers/phy/phy-exynos-mipi-video.c89
-rw-r--r--drivers/phy/phy-miphy28lp.c61
-rw-r--r--drivers/phy/phy-miphy365x.c29
-rw-r--r--drivers/phy/phy-qcom-ufs-i.h159
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-14nm.c201
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-14nm.h177
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-20nm.c257
-rw-r--r--drivers/phy/phy-qcom-ufs-qmp-20nm.h235
-rw-r--r--drivers/phy/phy-qcom-ufs.c745
-rw-r--r--drivers/phy/phy-rockchip-usb.c158
-rw-r--r--drivers/phy/phy-stih407-usb.c25
-rw-r--r--drivers/phy/phy-ti-pipe3.c143
-rw-r--r--drivers/pinctrl/Kconfig18
-rw-r--r--drivers/pinctrl/Makefile4
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c2
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx25.c276
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c122
-rw-r--r--drivers/pinctrl/meson/Makefile2
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.c761
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson.h209
-rw-r--r--drivers/pinctrl/meson/pinctrl-meson8.c1089
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-armada-38x.c6
-rw-r--r--drivers/pinctrl/mvebu/pinctrl-dove.c4
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c2
-rw-r--r--drivers/pinctrl/pinconf-generic.c206
-rw-r--r--drivers/pinctrl/pinconf.c4
-rw-r--r--drivers/pinctrl/pinconf.h22
-rw-r--r--drivers/pinctrl/pinctrl-at91.c108
-rw-r--r--drivers/pinctrl/pinctrl-bcm281xx.c4
-rw-r--r--drivers/pinctrl/pinctrl-falcon.c3
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c50
-rw-r--r--drivers/pinctrl/pinctrl-tz1090-pdc.c2
-rw-r--r--drivers/pinctrl/pinctrl-tz1090.c2
-rw-r--r--drivers/pinctrl/pinctrl-zynq.c1180
-rw-r--r--drivers/pinctrl/qcom/Kconfig8
-rw-r--r--drivers/pinctrl/qcom/Makefile1
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.c17
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm.h10
-rw-r--r--drivers/pinctrl/qcom/pinctrl-msm8916.c1005
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c129
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c29
-rw-r--r--drivers/pinctrl/sh-pfc/Kconfig10
-rw-r--r--drivers/pinctrl/sh-pfc/Makefile2
-rw-r--r--drivers/pinctrl/sh-pfc/core.c18
-rw-r--r--drivers/pinctrl/sh-pfc/core.h2
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-emev2.c1711
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7790.c13
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-r8a7791.c21
-rw-r--r--drivers/pinctrl/sh-pfc/pfc-sh7372.c2645
-rw-r--r--drivers/pinctrl/sh-pfc/pinctrl.c2
-rw-r--r--drivers/pinctrl/sh-pfc/sh_pfc.h2
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.c51
-rw-r--r--drivers/pinctrl/sirf/pinctrl-sirf.h1
-rw-r--r--drivers/pinctrl/sunxi/Kconfig4
-rw-r--r--drivers/pinctrl/sunxi/Makefile1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c5
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c815
-rw-r--r--drivers/platform/x86/Kconfig25
-rw-r--r--drivers/platform/x86/asus-laptop.c97
-rw-r--r--drivers/platform/x86/classmate-laptop.c2
-rw-r--r--drivers/platform/x86/fujitsu-laptop.c7
-rw-r--r--drivers/platform/x86/intel_scu_ipc.c77
-rw-r--r--drivers/platform/x86/samsung-laptop.c146
-rw-r--r--drivers/platform/x86/sony-laptop.c2
-rw-r--r--drivers/platform/x86/thinkpad_acpi.c24
-rw-r--r--drivers/platform/x86/toshiba_acpi.c1025
-rw-r--r--drivers/pnp/driver.c2
-rw-r--r--drivers/pnp/pnpacpi/rsparser.c45
-rw-r--r--drivers/pnp/pnpbios/core.c3
-rw-r--r--drivers/pnp/resource.c6
-rw-r--r--drivers/power/88pm860x_charger.c1
-rw-r--r--drivers/power/Kconfig25
-rw-r--r--drivers/power/Makefile3
-rw-r--r--drivers/power/ab8500_fg.c14
-rw-r--r--drivers/power/bq24190_charger.c4
-rw-r--r--drivers/power/bq27x00_battery.c19
-rw-r--r--drivers/power/charger-manager.c289
-rw-r--r--drivers/power/collie_battery.c24
-rw-r--r--drivers/power/gpio-charger.c4
-rw-r--r--drivers/power/ltc2941-battery-gauge.c547
-rw-r--r--drivers/power/max17042_battery.c2
-rw-r--r--drivers/power/max77693_charger.c753
-rw-r--r--drivers/power/reset/Kconfig26
-rw-r--r--drivers/power/reset/Makefile2
-rw-r--r--drivers/power/reset/arm-versatile-reboot.c49
-rw-r--r--drivers/power/reset/at91-poweroff.c7
-rw-r--r--drivers/power/reset/at91-reset.c28
-rw-r--r--drivers/power/reset/brcmstb-reboot.c41
-rw-r--r--drivers/power/reset/ltc2952-poweroff.c290
-rw-r--r--drivers/power/reset/restart-poweroff.c1
-rw-r--r--drivers/power/reset/rmobile-reset.c91
-rw-r--r--drivers/power/reset/st-poweroff.c17
-rw-r--r--drivers/power/reset/sun6i-reboot.c85
-rw-r--r--drivers/power/reset/vexpress-poweroff.c17
-rw-r--r--drivers/power/rt5033_battery.c177
-rw-r--r--drivers/power/test_power.c33
-rw-r--r--drivers/ps3/ps3-vuart.c5
-rw-r--r--drivers/ps3/sys-manager-core.c6
-rw-r--r--drivers/ps3/vuart.h16
-rw-r--r--drivers/pwm/Kconfig24
-rw-r--r--drivers/pwm/Makefile2
-rw-r--r--drivers/pwm/core.c2
-rw-r--r--drivers/pwm/pwm-atmel-hlcdc.c6
-rw-r--r--drivers/pwm/pwm-img.c249
-rw-r--r--drivers/pwm/pwm-sti.c30
-rw-r--r--drivers/pwm/pwm-sun4i.c366
-rw-r--r--drivers/pwm/pwm-tegra.c2
-rw-r--r--drivers/rapidio/devices/tsi721.c2
-rw-r--r--drivers/rapidio/devices/tsi721.h2
-rw-r--r--drivers/rapidio/devices/tsi721_dma.c8
-rw-r--r--drivers/regulator/Kconfig17
-rw-r--r--drivers/regulator/Makefile2
-rw-r--r--drivers/regulator/axp20x-regulator.c93
-rw-r--r--drivers/regulator/core.c375
-rw-r--r--drivers/regulator/da9211-regulator.c16
-rw-r--r--drivers/regulator/fan53555.c4
-rw-r--r--drivers/regulator/internal.h2
-rw-r--r--drivers/regulator/isl9305.c6
-rw-r--r--drivers/regulator/lp872x.c24
-rw-r--r--drivers/regulator/max14577.c62
-rw-r--r--drivers/regulator/max77686.c70
-rw-r--r--drivers/regulator/max77843.c227
-rw-r--r--drivers/regulator/max8649.c4
-rw-r--r--drivers/regulator/mt6397-regulator.c332
-rw-r--r--drivers/regulator/of_regulator.c11
-rw-r--r--drivers/regulator/pfuze100-regulator.c134
-rw-r--r--drivers/regulator/qcom_rpm-regulator.c16
-rw-r--r--drivers/regulator/rk808-regulator.c6
-rw-r--r--drivers/regulator/rt5033-regulator.c8
-rw-r--r--drivers/regulator/tps65023-regulator.c6
-rw-r--r--drivers/rtc/Kconfig147
-rw-r--r--drivers/rtc/Makefile3
-rw-r--r--drivers/rtc/hctosys.c18
-rw-r--r--drivers/rtc/interface.c22
-rw-r--r--drivers/rtc/rtc-ab-b5ze-s3.c1035
-rw-r--r--drivers/rtc/rtc-armada38x.c320
-rw-r--r--drivers/rtc/rtc-at91sam9.c2
-rw-r--r--drivers/rtc/rtc-dev.c8
-rw-r--r--drivers/rtc/rtc-ds1685.c2250
-rw-r--r--drivers/rtc/rtc-imxdi.c50
-rw-r--r--drivers/rtc/rtc-isl12022.c3
-rw-r--r--drivers/rtc/rtc-isl12057.c351
-rw-r--r--drivers/rtc/rtc-pcf2123.c10
-rw-r--r--drivers/rtc/rtc-rk808.c10
-rw-r--r--drivers/rtc/systohc.c6
-rw-r--r--drivers/s390/block/dasd.c102
-rw-r--r--drivers/s390/block/dasd_int.h3
-rw-r--r--drivers/s390/block/dasd_proc.c21
-rw-r--r--drivers/s390/block/dcssblk.c36
-rw-r--r--drivers/s390/char/hmcdrv_ftp.c6
-rw-r--r--drivers/s390/char/hmcdrv_mod.c1
-rw-r--r--drivers/s390/char/sclp_early.c57
-rw-r--r--drivers/s390/char/tape_34xx.c12
-rw-r--r--drivers/s390/cio/cio.c2
-rw-r--r--drivers/s390/cio/idset.c20
-rw-r--r--drivers/s390/cio/idset.h2
-rw-r--r--drivers/s390/crypto/ap_bus.c144
-rw-r--r--drivers/s390/crypto/ap_bus.h1
-rw-r--r--drivers/s390/crypto/zcrypt_api.h1
-rw-r--r--drivers/s390/crypto/zcrypt_cex4.c33
-rw-r--r--drivers/s390/net/claw.c6
-rw-r--r--drivers/s390/net/ctcm_fsms.c18
-rw-r--r--drivers/s390/net/ctcm_main.c4
-rw-r--r--drivers/s390/net/ctcm_main.h2
-rw-r--r--drivers/s390/net/ctcm_sysfs.c4
-rw-r--r--drivers/s390/net/lcs.c6
-rw-r--r--drivers/s390/net/netiucv.c15
-rw-r--r--drivers/s390/net/qeth_core.h1
-rw-r--r--drivers/s390/net/qeth_core_sys.c45
-rw-r--r--drivers/s390/net/qeth_l2_main.c6
-rw-r--r--drivers/s390/net/qeth_l3_main.c15
-rw-r--r--drivers/s390/net/qeth_l3_sys.c45
-rw-r--r--drivers/scsi/3w-9xxx.c3
-rw-r--r--drivers/scsi/BusLogic.c10
-rw-r--r--drivers/scsi/Kconfig4
-rw-r--r--drivers/scsi/Makefile6
-rw-r--r--drivers/scsi/NCR5380.c20
-rw-r--r--drivers/scsi/advansys.c142
-rw-r--r--drivers/scsi/aha152x.c295
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_core.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_proc.c38
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_proc.c24
-rw-r--r--drivers/scsi/am53c974.c6
-rw-r--r--drivers/scsi/arm/fas216.c6
-rw-r--r--drivers/scsi/atari_NCR5380.c4
-rw-r--r--drivers/scsi/atp870u.c5
-rw-r--r--drivers/scsi/be2iscsi/be_main.c2
-rw-r--r--drivers/scsi/ch.c6
-rw-r--r--drivers/scsi/constants.c275
-rw-r--r--drivers/scsi/csiostor/Makefile2
-rw-r--r--drivers/scsi/csiostor/csio_hw.c1175
-rw-r--r--drivers/scsi/csiostor/csio_hw.h49
-rw-r--r--drivers/scsi/csiostor/csio_hw_chip.h65
-rw-r--r--drivers/scsi/csiostor/csio_hw_t4.c404
-rw-r--r--drivers/scsi/csiostor/csio_hw_t5.c150
-rw-r--r--drivers/scsi/csiostor/csio_init.c15
-rw-r--r--drivers/scsi/csiostor/csio_isr.c2
-rw-r--r--drivers/scsi/csiostor/csio_lnode.c2
-rw-r--r--drivers/scsi/csiostor/csio_mb.c56
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c4
-rw-r--r--drivers/scsi/csiostor/csio_wr.c157
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c41
-rw-r--r--drivers/scsi/dc395x.c79
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c3
-rw-r--r--drivers/scsi/dpt_i2o.c2
-rw-r--r--drivers/scsi/eata_pio.c2
-rw-r--r--drivers/scsi/esas2r/esas2r_init.c5
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c2
-rw-r--r--drivers/scsi/esp_scsi.c2
-rw-r--r--drivers/scsi/gdth_proc.c24
-rw-r--r--drivers/scsi/hpsa.c1796
-rw-r--r--drivers/scsi/hpsa.h61
-rw-r--r--drivers/scsi/hpsa_cmd.h334
-rw-r--r--drivers/scsi/in2000.c18
-rw-r--r--drivers/scsi/ips.c7
-rw-r--r--drivers/scsi/lpfc/lpfc_els.c9
-rw-r--r--drivers/scsi/megaraid.c2
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h66
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c188
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c17
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c109
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h9
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2.h7
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h51
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_ioc.h4
-rw-r--r--drivers/scsi/mpt2sas/mpi/mpi2_tool.h6
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.c52
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_base.h16
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_config.c39
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.c3
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_ctl.h3
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_debug.h3
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c47
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_transport.c3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.c53
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_base.h12
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_config.c39
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.c3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_ctl.h3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_debug.h3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c42
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_transport.c3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c3
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h3
-rw-r--r--drivers/scsi/nsp32.c41
-rw-r--r--drivers/scsi/pcmcia/nsp_cs.c50
-rw-r--r--drivers/scsi/pmcraid.c10
-rw-r--r--drivers/scsi/qla2xxx/qla_dfs.c8
-rw-r--r--drivers/scsi/qla2xxx/tcm_qla2xxx.c4
-rw-r--r--drivers/scsi/scsi.c11
-rw-r--r--drivers/scsi/scsi_debug.c134
-rw-r--r--drivers/scsi/scsi_error.c50
-rw-r--r--drivers/scsi/scsi_lib.c2
-rw-r--r--drivers/scsi/scsi_logging.c485
-rw-r--r--drivers/scsi/scsi_proc.c22
-rw-r--r--drivers/scsi/scsi_scan.c57
-rw-r--r--drivers/scsi/scsi_trace.c6
-rw-r--r--drivers/scsi/sd.c13
-rw-r--r--drivers/scsi/ses.c148
-rw-r--r--drivers/scsi/sg.c72
-rw-r--r--drivers/scsi/sr_ioctl.c11
-rw-r--r--drivers/scsi/st.c7
-rw-r--r--drivers/scsi/storvsc_drv.c190
-rw-r--r--drivers/scsi/ufs/Kconfig13
-rw-r--r--drivers/scsi/ufs/Makefile1
-rw-r--r--drivers/scsi/ufs/ufs-qcom.c1004
-rw-r--r--drivers/scsi/ufs/ufs-qcom.h170
-rw-r--r--drivers/scsi/ufs/ufshcd.c6
-rw-r--r--drivers/scsi/virtio_scsi.c6
-rw-r--r--drivers/scsi/wd33c93.c18
-rw-r--r--drivers/scsi/wd7000.c41
-rw-r--r--drivers/scsi/wd719x.c1
-rw-r--r--drivers/sfi/sfi_core.c4
-rw-r--r--drivers/sh/pm_runtime.c2
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra.c1
-rw-r--r--drivers/soc/tegra/fuse/fuse-tegra30.c9
-rw-r--r--drivers/soc/tegra/pmc.c124
-rw-r--r--drivers/soc/ti/Makefile3
-rw-r--r--drivers/soc/ti/knav_qmss_acc.c2
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c9
-rw-r--r--drivers/spi/Kconfig30
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/spi-atmel.c12
-rw-r--r--drivers/spi/spi-au1550.c4
-rw-r--r--drivers/spi/spi-bcm2835.c4
-rw-r--r--drivers/spi/spi-bcm53xx.c2
-rw-r--r--drivers/spi/spi-bcm63xx.c4
-rw-r--r--drivers/spi/spi-bitbang.c4
-rw-r--r--drivers/spi/spi-butterfly.c4
-rw-r--r--drivers/spi/spi-coldfire-qspi.c5
-rw-r--r--drivers/spi/spi-davinci.c4
-rw-r--r--drivers/spi/spi-dln2.c881
-rw-r--r--drivers/spi/spi-dw-mid.c15
-rw-r--r--drivers/spi/spi-dw-pci.c38
-rw-r--r--drivers/spi/spi-dw.c9
-rw-r--r--drivers/spi/spi-falcon.c12
-rw-r--r--drivers/spi/spi-fsl-cpm.c9
-rw-r--r--drivers/spi/spi-fsl-dspi.c163
-rw-r--r--drivers/spi/spi-fsl-lib.c16
-rw-r--r--drivers/spi/spi-fsl-lib.h4
-rw-r--r--drivers/spi/spi-gpio.c8
-rw-r--r--drivers/spi/spi-img-spfi.c49
-rw-r--r--drivers/spi/spi-imx.c32
-rw-r--r--drivers/spi/spi-lm70llp.c4
-rw-r--r--drivers/spi/spi-meson-spifc.c2
-rw-r--r--drivers/spi/spi-mxs.c5
-rw-r--r--drivers/spi/spi-omap-100k.c5
-rw-r--r--drivers/spi/spi-omap-uwire.c4
-rw-r--r--drivers/spi/spi-omap2-mcspi.c5
-rw-r--r--drivers/spi/spi-orion.c88
-rw-r--r--drivers/spi/spi-pxa2xx-dma.c17
-rw-r--r--drivers/spi/spi-pxa2xx-pxadma.c34
-rw-r--r--drivers/spi/spi-pxa2xx.c207
-rw-r--r--drivers/spi/spi-pxa2xx.h34
-rw-r--r--drivers/spi/spi-qup.c11
-rw-r--r--drivers/spi/spi-rockchip.c6
-rw-r--r--drivers/spi/spi-rspi.c5
-rw-r--r--drivers/spi/spi-s3c64xx.c4
-rw-r--r--drivers/spi/spi-sc18is602.c4
-rw-r--r--drivers/spi/spi-sh-hspi.c5
-rw-r--r--drivers/spi/spi-sh-msiof.c91
-rw-r--r--drivers/spi/spi-sh.c5
-rw-r--r--drivers/spi/spi-sirf.c1
-rw-r--r--drivers/spi/spi-st-ssc4.c504
-rw-r--r--drivers/spi/spi-ti-qspi.c14
-rw-r--r--drivers/spi/spi-topcliff-pch.c4
-rw-r--r--drivers/spi/spi-xilinx.c298
-rw-r--r--drivers/spi/spi.c120
-rw-r--r--drivers/spi/spidev.c125
-rw-r--r--drivers/ssb/driver_gige.c2
-rw-r--r--drivers/ssb/main.c19
-rw-r--r--drivers/staging/Kconfig10
-rw-r--r--drivers/staging/Makefile5
-rw-r--r--drivers/staging/android/Kconfig26
-rw-r--r--drivers/staging/android/Makefile2
-rw-r--r--drivers/staging/android/alarm-dev.c446
-rw-r--r--drivers/staging/android/android_alarm.h41
-rw-r--r--drivers/staging/android/ashmem.c12
-rw-r--r--drivers/staging/android/ion/ion.c3
-rw-r--r--drivers/staging/android/ion/ion_cma_heap.c20
-rw-r--r--drivers/staging/android/ion/ion_heap.c2
-rw-r--r--drivers/staging/android/logger.c808
-rw-r--r--drivers/staging/android/logger.h89
-rw-r--r--drivers/staging/android/lowmemorykiller.c7
-rw-r--r--drivers/staging/android/sync_debug.c3
-rw-r--r--drivers/staging/android/uapi/android_alarm.h62
-rw-r--r--drivers/staging/board/Kconfig2
-rw-r--r--drivers/staging/board/board.c3
-rw-r--r--drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c5
-rw-r--r--drivers/staging/comedi/Kconfig21
-rw-r--r--drivers/staging/comedi/comedi_compat32.c99
-rw-r--r--drivers/staging/comedi/comedi_compat32.h38
-rw-r--r--drivers/staging/comedi/comedi_fops.c467
-rw-r--r--drivers/staging/comedi/comedi_pcmcia.c5
-rw-r--r--drivers/staging/comedi/comedi_pcmcia.h55
-rw-r--r--drivers/staging/comedi/comedi_usb.c3
-rw-r--r--drivers/staging/comedi/comedi_usb.h50
-rw-r--r--drivers/staging/comedi/comedidev.h103
-rw-r--r--drivers/staging/comedi/drivers.c2
-rw-r--r--drivers/staging/comedi/drivers/8253.h92
-rw-r--r--drivers/staging/comedi/drivers/8255.c174
-rw-r--r--drivers/staging/comedi/drivers/8255.h32
-rw-r--r--drivers/staging/comedi/drivers/8255_pci.c65
-rw-r--r--drivers/staging/comedi/drivers/Makefile1
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c2365
-rw-r--r--drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c3
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1032.c78
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_1500.c844
-rw-r--r--drivers/staging/comedi/drivers/addi_apci_3501.c3
-rw-r--r--drivers/staging/comedi/drivers/adl_pci6208.c3
-rw-r--r--drivers/staging/comedi/drivers/adl_pci7x3x.c62
-rw-r--r--drivers/staging/comedi/drivers/adl_pci8164.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9111.c2
-rw-r--r--drivers/staging/comedi/drivers/adl_pci9118.c4
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1710.c665
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1723.c2
-rw-r--r--drivers/staging/comedi/drivers/adv_pci1724.c2
-rw-r--r--drivers/staging/comedi/drivers/aio_iiro_16.c240
-rw-r--r--drivers/staging/comedi/drivers/c6xdigio.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_das16_cs.c5
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas.c2
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidas64.c124
-rw-r--r--drivers/staging/comedi/drivers/cb_pcidda.c10
-rw-r--r--drivers/staging/comedi/drivers/comedi_bond.c1
-rw-r--r--drivers/staging/comedi/drivers/comedi_isadma.c262
-rw-r--r--drivers/staging/comedi/drivers/comedi_isadma.h116
-rw-r--r--drivers/staging/comedi/drivers/comedi_parport.c2
-rw-r--r--drivers/staging/comedi/drivers/dac02.c2
-rw-r--r--drivers/staging/comedi/drivers/das08.c17
-rw-r--r--drivers/staging/comedi/drivers/das08_cs.c5
-rw-r--r--drivers/staging/comedi/drivers/das08_isa.c18
-rw-r--r--drivers/staging/comedi/drivers/das08_pci.c2
-rw-r--r--drivers/staging/comedi/drivers/das16.c469
-rw-r--r--drivers/staging/comedi/drivers/das16m1.c2
-rw-r--r--drivers/staging/comedi/drivers/das1800.c340
-rw-r--r--drivers/staging/comedi/drivers/das6402.c4
-rw-r--r--drivers/staging/comedi/drivers/das800.c2
-rw-r--r--drivers/staging/comedi/drivers/dmm32at.c4
-rw-r--r--drivers/staging/comedi/drivers/dt282x.c231
-rw-r--r--drivers/staging/comedi/drivers/dt3000.c2
-rw-r--r--drivers/staging/comedi/drivers/dt9812.c3
-rw-r--r--drivers/staging/comedi/drivers/dyna_pci10xx.c35
-rw-r--r--drivers/staging/comedi/drivers/gsc_hpdi.c4
-rw-r--r--drivers/staging/comedi/drivers/ii_pci20kc.c2
-rw-r--r--drivers/staging/comedi/drivers/jr3_pci.h5
-rw-r--r--drivers/staging/comedi/drivers/ke_counter.c2
-rw-r--r--drivers/staging/comedi/drivers/me4000.c4
-rw-r--r--drivers/staging/comedi/drivers/me_daq.c5
-rw-r--r--drivers/staging/comedi/drivers/mf6x4.c2
-rw-r--r--drivers/staging/comedi/drivers/mite.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_6527.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_65xx.c30
-rw-r--r--drivers/staging/comedi/drivers/ni_at_a2150.c192
-rw-r--r--drivers/staging/comedi/drivers/ni_at_ao.c3
-rw-r--r--drivers/staging/comedi/drivers/ni_atmio.c2
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_700.c5
-rw-r--r--drivers/staging/comedi/drivers/ni_daq_dio24.c6
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.c16
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc.h8
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_common.c55
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_cs.c15
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_isadma.c149
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_isadma.h23
-rw-r--r--drivers/staging/comedi/drivers/ni_labpc_pci.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_common.c7
-rw-r--r--drivers/staging/comedi/drivers/ni_mio_cs.c9
-rw-r--r--drivers/staging/comedi/drivers/ni_pcidio.c4
-rw-r--r--drivers/staging/comedi/drivers/ni_tio.c43
-rw-r--r--drivers/staging/comedi/drivers/ni_tiocmd.c43
-rw-r--r--drivers/staging/comedi/drivers/ni_usb6501.c3
-rw-r--r--drivers/staging/comedi/drivers/pcl711.c6
-rw-r--r--drivers/staging/comedi/drivers/pcl724.c12
-rw-r--r--drivers/staging/comedi/drivers/pcl726.c7
-rw-r--r--drivers/staging/comedi/drivers/pcl730.c19
-rw-r--r--drivers/staging/comedi/drivers/pcl812.c258
-rw-r--r--drivers/staging/comedi/drivers/pcl816.c240
-rw-r--r--drivers/staging/comedi/drivers/pcl818.c422
-rw-r--r--drivers/staging/comedi/drivers/pcmad.c3
-rw-r--r--drivers/staging/comedi/drivers/pcmda12.c2
-rw-r--r--drivers/staging/comedi/drivers/pcmmio.c2
-rw-r--r--drivers/staging/comedi/drivers/pcmuio.c3
-rw-r--r--drivers/staging/comedi/drivers/quatech_daqp_cs.c12
-rw-r--r--drivers/staging/comedi/drivers/rtd520.c16
-rw-r--r--drivers/staging/comedi/drivers/rti800.c3
-rw-r--r--drivers/staging/comedi/drivers/rti802.c2
-rw-r--r--drivers/staging/comedi/drivers/s626.c2
-rw-r--r--drivers/staging/comedi/drivers/usbdux.c6
-rw-r--r--drivers/staging/comedi/drivers/usbduxfast.c5
-rw-r--r--drivers/staging/comedi/drivers/usbduxsigma.c9
-rw-r--r--drivers/staging/comedi/drivers/vmk80xx.c80
-rw-r--r--drivers/staging/comedi/drivers/z8536.h202
-rw-r--r--drivers/staging/comedi/kcomedilib/kcomedilib_main.c2
-rw-r--r--drivers/staging/comedi/range.c56
-rw-r--r--drivers/staging/cptm1217/Kconfig12
-rw-r--r--drivers/staging/cptm1217/Makefile2
-rw-r--r--drivers/staging/cptm1217/TODO5
-rw-r--r--drivers/staging/cptm1217/clearpad_tm1217.c665
-rw-r--r--drivers/staging/cptm1217/cp_tm1217.h8
-rw-r--r--drivers/staging/dgap/dgap.c38
-rw-r--r--drivers/staging/dgnc/dgnc_driver.c40
-rw-r--r--drivers/staging/dgnc/dgnc_utils.c2
-rw-r--r--drivers/staging/dgnc/digi.h60
-rw-r--r--drivers/staging/dgnc/dpacompat.h12
-rw-r--r--drivers/staging/emxx_udc/Kconfig2
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.c60
-rw-r--r--drivers/staging/emxx_udc/emxx_udc.h1
-rw-r--r--drivers/staging/fbtft/Kconfig169
-rw-r--r--drivers/staging/fbtft/Makefile34
-rw-r--r--drivers/staging/fbtft/README32
-rw-r--r--drivers/staging/fbtft/fb_agm1264k-fl.c462
-rw-r--r--drivers/staging/fbtft/fb_bd663474.c193
-rw-r--r--drivers/staging/fbtft/fb_hx8340bn.c229
-rw-r--r--drivers/staging/fbtft/fb_hx8347d.c181
-rw-r--r--drivers/staging/fbtft/fb_hx8353d.c166
-rw-r--r--drivers/staging/fbtft/fb_ili9320.c234
-rw-r--r--drivers/staging/fbtft/fb_ili9325.c291
-rw-r--r--drivers/staging/fbtft/fb_ili9340.c163
-rw-r--r--drivers/staging/fbtft/fb_ili9341.c179
-rw-r--r--drivers/staging/fbtft/fb_ili9481.c117
-rw-r--r--drivers/staging/fbtft/fb_ili9486.c121
-rw-r--r--drivers/staging/fbtft/fb_pcd8544.c177
-rw-r--r--drivers/staging/fbtft/fb_ra8875.c331
-rw-r--r--drivers/staging/fbtft/fb_s6d02a1.c168
-rw-r--r--drivers/staging/fbtft/fb_s6d1121.c208
-rw-r--r--drivers/staging/fbtft/fb_ssd1289.c206
-rw-r--r--drivers/staging/fbtft/fb_ssd1306.c229
-rw-r--r--drivers/staging/fbtft/fb_ssd1331.c205
-rw-r--r--drivers/staging/fbtft/fb_ssd1351.c258
-rw-r--r--drivers/staging/fbtft/fb_st7735r.c195
-rw-r--r--drivers/staging/fbtft/fb_tinylcd.c124
-rw-r--r--drivers/staging/fbtft/fb_tls8204.c176
-rw-r--r--drivers/staging/fbtft/fb_uc1701.c210
-rw-r--r--drivers/staging/fbtft/fb_upd161704.c206
-rw-r--r--drivers/staging/fbtft/fb_watterott.c324
-rw-r--r--drivers/staging/fbtft/fbtft-bus.c256
-rw-r--r--drivers/staging/fbtft/fbtft-core.c1521
-rw-r--r--drivers/staging/fbtft/fbtft-io.c239
-rw-r--r--drivers/staging/fbtft/fbtft-sysfs.c222
-rw-r--r--drivers/staging/fbtft/fbtft.h447
-rw-r--r--drivers/staging/fbtft/fbtft_device.c1444
-rw-r--r--drivers/staging/fbtft/flexfb.c592
-rw-r--r--drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c111
-rw-r--r--drivers/staging/ft1000/ft1000-usb/ft1000_hw.c8
-rw-r--r--drivers/staging/gdm724x/gdm_lte.c3
-rw-r--r--drivers/staging/gdm724x/gdm_mux.c2
-rw-r--r--drivers/staging/gs_fpgaboot/io.c9
-rw-r--r--drivers/staging/i2o/Kconfig120
-rw-r--r--drivers/staging/i2o/Makefile (renamed from drivers/message/i2o/Makefile)0
-rw-r--r--drivers/staging/i2o/README (renamed from drivers/message/i2o/README)0
-rw-r--r--drivers/staging/i2o/README.ioctl (renamed from drivers/message/i2o/README.ioctl)0
-rw-r--r--drivers/staging/i2o/bus-osm.c176
-rw-r--r--drivers/staging/i2o/config-osm.c90
-rw-r--r--drivers/staging/i2o/core.h (renamed from drivers/message/i2o/core.h)0
-rw-r--r--drivers/staging/i2o/debug.c472
-rw-r--r--drivers/staging/i2o/device.c594
-rw-r--r--drivers/staging/i2o/driver.c382
-rw-r--r--drivers/staging/i2o/exec-osm.c612
-rw-r--r--drivers/staging/i2o/i2o.h988
-rw-r--r--drivers/staging/i2o/i2o_block.c1228
-rw-r--r--drivers/staging/i2o/i2o_block.h (renamed from drivers/message/i2o/i2o_block.h)0
-rw-r--r--drivers/staging/i2o/i2o_config.c (renamed from drivers/message/i2o/i2o_config.c)0
-rw-r--r--drivers/staging/i2o/i2o_proc.c2045
-rw-r--r--drivers/staging/i2o/i2o_scsi.c814
-rw-r--r--drivers/staging/i2o/iop.c1247
-rw-r--r--drivers/staging/i2o/memory.c313
-rw-r--r--drivers/staging/i2o/pci.c497
-rw-r--r--drivers/staging/iio/Documentation/iio_event_monitor.c23
-rw-r--r--drivers/staging/iio/Documentation/ring.txt8
-rw-r--r--drivers/staging/iio/Kconfig4
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_core.c13
-rw-r--r--drivers/staging/iio/accel/lis3l02dq_ring.c2
-rw-r--r--drivers/staging/iio/accel/sca3000_core.c45
-rw-r--r--drivers/staging/iio/accel/sca3000_ring.c29
-rw-r--r--drivers/staging/iio/adc/ad7192.c2
-rw-r--r--drivers/staging/iio/adc/mxs-lradc.c45
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.c17
-rw-r--r--drivers/staging/iio/iio_dummy_evgen.h6
-rw-r--r--drivers/staging/iio/iio_simple_dummy.c210
-rw-r--r--drivers/staging/iio/iio_simple_dummy.h13
-rw-r--r--drivers/staging/iio/iio_simple_dummy_buffer.c12
-rw-r--r--drivers/staging/iio/iio_simple_dummy_events.c66
-rw-r--r--drivers/staging/iio/impedance-analyzer/ad5933.c53
-rw-r--r--drivers/staging/iio/light/isl29028.c4
-rw-r--r--drivers/staging/iio/light/tsl2583.c2
-rw-r--r--drivers/staging/iio/light/tsl2x7x_core.c2
-rw-r--r--drivers/staging/iio/meter/ade7758.h1
-rw-r--r--drivers/staging/iio/meter/ade7758_core.c15
-rw-r--r--drivers/staging/iio/meter/ade7758_ring.c7
-rw-r--r--drivers/staging/iio/meter/ade7759.c2
-rw-r--r--drivers/staging/line6/Kconfig38
-rw-r--r--drivers/staging/line6/Makefile14
-rw-r--r--drivers/staging/line6/audio.c71
-rw-r--r--drivers/staging/line6/audio.h21
-rw-r--r--drivers/staging/line6/capture.c432
-rw-r--r--drivers/staging/line6/capture.h35
-rw-r--r--drivers/staging/line6/driver.c1162
-rw-r--r--drivers/staging/line6/driver.h215
-rw-r--r--drivers/staging/line6/midi.c321
-rw-r--r--drivers/staging/line6/midi.h72
-rw-r--r--drivers/staging/line6/midibuf.c270
-rw-r--r--drivers/staging/line6/midibuf.h38
-rw-r--r--drivers/staging/line6/pcm.c576
-rw-r--r--drivers/staging/line6/pcm.h382
-rw-r--r--drivers/staging/line6/playback.c592
-rw-r--r--drivers/staging/line6/playback.h41
-rw-r--r--drivers/staging/line6/pod.c458
-rw-r--r--drivers/staging/line6/pod.h102
-rw-r--r--drivers/staging/line6/podhd.c154
-rw-r--r--drivers/staging/line6/podhd.h30
-rw-r--r--drivers/staging/line6/revision.h4
-rw-r--r--drivers/staging/line6/toneport.c460
-rw-r--r--drivers/staging/line6/toneport.h52
-rw-r--r--drivers/staging/line6/usbdefs.h116
-rw-r--r--drivers/staging/line6/variax.c235
-rw-r--r--drivers/staging/line6/variax.h72
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs.h3
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h28
-rw-r--r--drivers/staging/lustre/include/linux/libcfs/libcfs_private.h8
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-lnet.h36
-rw-r--r--drivers/staging/lustre/include/linux/lnet/lib-types.h8
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c14
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h2
-rw-r--r--drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c13
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c2
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h14
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c28
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c36
-rw-r--r--drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c4
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-move.c49
-rw-r--r--drivers/staging/lustre/lnet/lnet/lib-ptl.c8
-rw-r--r--drivers/staging/lustre/lnet/lnet/lo.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/module.c2
-rw-r--r--drivers/staging/lustre/lnet/lnet/router.c40
-rw-r--r--drivers/staging/lustre/lnet/lnet/router_proc.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/conctl.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.c2
-rw-r--r--drivers/staging/lustre/lnet/selftest/conrpc.h2
-rw-r--r--drivers/staging/lustre/lnet/selftest/console.c30
-rw-r--r--drivers/staging/lustre/lnet/selftest/framework.c4
-rw-r--r--drivers/staging/lustre/lnet/selftest/module.c50
-rw-r--r--drivers/staging/lustre/lnet/selftest/rpc.c8
-rw-r--r--drivers/staging/lustre/lnet/selftest/selftest.h12
-rw-r--r--drivers/staging/lustre/lnet/selftest/timer.c2
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/fid/fid_request.c4
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_cache.c6
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_internal.h2
-rw-r--r--drivers/staging/lustre/lustre/fld/fld_request.c11
-rw-r--r--drivers/staging/lustre/lustre/fld/lproc_fld.c16
-rw-r--r--drivers/staging/lustre/lustre/include/lclient.h3
-rw-r--r--drivers/staging/lustre/lustre/include/lprocfs_status.h44
-rw-r--r--drivers/staging/lustre/lustre/include/lustre/lustre_idl.h5
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fid.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_fld.h4
-rw-r--r--drivers/staging/lustre/lustre/include/lustre_update.h189
-rw-r--r--drivers/staging/lustre/lustre/lclient/lcommon_cl.c6
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_pool.c36
-rw-r--r--drivers/staging/lustre/lustre/ldlm/ldlm_resource.c7
-rw-r--r--drivers/staging/lustre/lustre/libcfs/debug.c12
-rw-r--r--drivers/staging/lustre/lustre/libcfs/hash.c18
-rw-r--r--drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/libcfs_string.c16
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c7
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c24
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c2
-rw-r--r--drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c4
-rw-r--r--drivers/staging/lustre/lustre/libcfs/module.c8
-rw-r--r--drivers/staging/lustre/lustre/libcfs/nidstrings.c233
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c3
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c20
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c11
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c16
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c48
-rw-r--r--drivers/staging/lustre/lustre/llite/lproc_llite.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c12
-rw-r--r--drivers/staging/lustre/lustre/llite/super25.c141
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c17
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_lock.c1
-rw-r--r--drivers/staging/lustre/lustre/lmv/lmv_obd.c87
-rw-r--r--drivers/staging/lustre/lustre/lmv/lproc_lmv.c4
-rw-r--r--drivers/staging/lustre/lustre/lov/lproc_lov.c20
-rw-r--r--drivers/staging/lustre/lustre/mdc/lproc_mdc.c9
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_lib.c7
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_locks.c1
-rw-r--r--drivers/staging/lustre/lustre/mdc/mdc_request.c62
-rw-r--r--drivers/staging/lustre/lustre/obdclass/cl_object.c5
-rw-r--r--drivers/staging/lustre/lustre/obdclass/class_obd.c2
-rw-r--r--drivers/staging/lustre/lustre/obdclass/genops.c10
-rw-r--r--drivers/staging/lustre/lustre/obdclass/linux/linux-module.c31
-rw-r--r--drivers/staging/lustre/lustre/obdclass/llog_swab.c5
-rw-r--r--drivers/staging/lustre/lustre/obdclass/lprocfs_status.c26
-rw-r--r--drivers/staging/lustre/lustre/obdclass/obd_mount.c5
-rw-r--r--drivers/staging/lustre/lustre/osc/lproc_osc.c77
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_cache.c12
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_internal.h5
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_lock.c12
-rw-r--r--drivers/staging/lustre/lustre/osc/osc_request.c2
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/client.c14
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/layout.c1
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c41
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c23
-rw-r--r--drivers/staging/lustre/lustre/ptlrpc/sec_gc.c2
-rw-r--r--drivers/staging/media/Kconfig6
-rw-r--r--drivers/staging/media/Makefile4
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c6
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c4
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c69
-rw-r--r--drivers/staging/media/lirc/lirc_serial.c10
-rw-r--r--drivers/staging/media/lirc/lirc_zilog.c118
-rw-r--r--drivers/staging/media/mn88472/mn88472.c63
-rw-r--r--drivers/staging/media/mn88472/mn88472_priv.h1
-rw-r--r--drivers/staging/media/omap4iss/iss.c111
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c43
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.h2
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c22
-rw-r--r--drivers/staging/media/omap4iss/iss_regs.h2
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c18
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c16
-rw-r--r--drivers/staging/media/parport/Kconfig69
-rw-r--r--drivers/staging/media/parport/Makefile4
-rw-r--r--drivers/staging/media/parport/bw-qcam.c1177
-rw-r--r--drivers/staging/media/parport/c-qcam.c882
-rw-r--r--drivers/staging/media/parport/pms.c1156
-rw-r--r--drivers/staging/media/parport/w9966.c980
-rw-r--r--drivers/staging/media/tlg2300/Kconfig21
-rw-r--r--drivers/staging/media/tlg2300/Makefile9
-rw-r--r--drivers/staging/media/tlg2300/pd-alsa.c337
-rw-r--r--drivers/staging/media/tlg2300/pd-common.h271
-rw-r--r--drivers/staging/media/tlg2300/pd-dvb.c597
-rw-r--r--drivers/staging/media/tlg2300/pd-main.c553
-rw-r--r--drivers/staging/media/tlg2300/pd-radio.c339
-rw-r--r--drivers/staging/media/tlg2300/pd-video.c1570
-rw-r--r--drivers/staging/media/tlg2300/vendorcmds.h243
-rw-r--r--drivers/staging/media/vino/Kconfig24
-rw-r--r--drivers/staging/media/vino/Makefile3
-rw-r--r--drivers/staging/media/vino/indycam.c378
-rw-r--r--drivers/staging/media/vino/indycam.h93
-rw-r--r--drivers/staging/media/vino/saa7191.c649
-rw-r--r--drivers/staging/media/vino/saa7191.h245
-rw-r--r--drivers/staging/media/vino/vino.c4345
-rw-r--r--drivers/staging/media/vino/vino.h138
-rw-r--r--drivers/staging/mt29f_spinand/Kconfig2
-rw-r--r--drivers/staging/mt29f_spinand/mt29f_spinand.c17
-rw-r--r--drivers/staging/netlogic/xlr_net.c2
-rw-r--r--drivers/staging/nvec/nvec.c11
-rw-r--r--drivers/staging/octeon-usb/octeon-hcd.c2
-rw-r--r--drivers/staging/octeon/ethernet-rx.c2
-rw-r--r--drivers/staging/octeon/ethernet.c2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon.c2
-rw-r--r--drivers/staging/olpc_dcon/olpc_dcon_xo_1.c2
-rw-r--r--drivers/staging/panel/panel.c104
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_ap.c2
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_mlme_ext.c67
-rw-r--r--drivers/staging/rtl8188eu/core/rtw_wlan_util.c7
-rw-r--r--drivers/staging/rtl8188eu/hal/odm.c22
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c36
-rw-r--r--drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c14
-rw-r--r--drivers/staging/rtl8188eu/include/osdep_service.h2
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_cmd.h1
-rw-r--r--drivers/staging/rtl8188eu/include/rtl8188e_hal.h1
-rw-r--r--drivers/staging/rtl8188eu/include/rtw_mlme_ext.h4
-rw-r--r--drivers/staging/rtl8188eu/include/usb_ops_linux.h1
-rw-r--r--drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c27
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.c29
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_cam.h2
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_dm.c4
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.c14
-rw-r--r--drivers/staging/rtl8192e/rtl8192e/rtl_pm.h2
-rw-r--r--drivers/staging/rtl8192e/rtl819x_HTProc.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_module.c4
-rw-r--r--drivers/staging/rtl8192e/rtllib_rx.c127
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c28
-rw-r--r--drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c2
-rw-r--r--drivers/staging/rtl8192u/r8190_rtl8256.c2
-rw-r--r--drivers/staging/rtl8192u/r8192U_dm.c2309
-rw-r--r--drivers/staging/rtl8712/drv_types.h6
-rw-r--r--drivers/staging/rtl8712/osdep_service.h9
-rw-r--r--drivers/staging/rtl8712/recv_linux.c14
-rw-r--r--drivers/staging/rtl8712/recv_osdep.h1
-rw-r--r--drivers/staging/rtl8712/rtl8712_cmd.h12
-rw-r--r--drivers/staging/rtl8712/rtl8712_event.h2
-rw-r--r--drivers/staging/rtl8712/rtl871x_ioctl_linux.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_mlme.c4
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.c525
-rw-r--r--drivers/staging/rtl8712/rtl871x_mp_ioctl.h46
-rw-r--r--drivers/staging/rtl8712/rtl871x_pwrctrl.h22
-rw-r--r--drivers/staging/rtl8712/rtl871x_sta_mgt.c5
-rw-r--r--drivers/staging/rtl8712/rtl871x_xmit.c2
-rw-r--r--drivers/staging/rtl8712/sta_info.h2
-rw-r--r--drivers/staging/rtl8712/usb_intf.c5
-rw-r--r--drivers/staging/rtl8723au/core/rtw_ap.c10
-rw-r--r--drivers/staging/rtl8723au/core/rtw_cmd.c61
-rw-r--r--drivers/staging/rtl8723au/core/rtw_efuse.c32
-rw-r--r--drivers/staging/rtl8723au/core/rtw_xmit.c9
-rw-r--r--drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c8
-rw-r--r--drivers/staging/rtl8723au/hal/odm.c87
-rw-r--r--drivers/staging/rtl8723au/hal/odm_HWConfig.c8
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c62
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c35
-rw-r--r--drivers/staging/rtl8723au/hal/rtl8723au_xmit.c4
-rw-r--r--drivers/staging/rtl8723au/hal/usb_halinit.c14
-rw-r--r--drivers/staging/rtl8723au/include/Hal8723APhyCfg.h55
-rw-r--r--drivers/staging/rtl8723au/include/Hal8723PwrSeq.h46
-rw-r--r--drivers/staging/rtl8723au/include/osdep_intf.h3
-rw-r--r--drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h177
-rw-r--r--drivers/staging/rtl8723au/include/rtl8723a_recv.h4
-rw-r--r--drivers/staging/rtl8723au/include/rtw_cmd.h10
-rw-r--r--drivers/staging/rtl8723au/include/rtw_mlme_ext.h2
-rw-r--r--drivers/staging/rtl8723au/include/wifi.h14
-rw-r--r--drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c13
-rw-r--r--drivers/staging/rtl8723au/os_dep/os_intfs.c2
-rw-r--r--drivers/staging/rtl8723au/os_dep/usb_intf.c170
-rw-r--r--drivers/staging/rts5208/ms.c12
-rw-r--r--drivers/staging/rts5208/rtsx_transport.c12
-rw-r--r--drivers/staging/skein/skein_block.c17
-rw-r--r--drivers/staging/skein/skein_generic.c1
-rw-r--r--drivers/staging/sm7xxfb/Kconfig13
-rw-r--r--drivers/staging/sm7xxfb/Makefile1
-rw-r--r--drivers/staging/sm7xxfb/TODO12
-rw-r--r--drivers/staging/sm7xxfb/sm7xx.h779
-rw-r--r--drivers/staging/sm7xxfb/sm7xxfb.c1024
-rw-r--r--drivers/staging/speakup/i18n.h2
-rw-r--r--drivers/staging/speakup/kobjects.c2
-rw-r--r--drivers/staging/speakup/selection.c2
-rw-r--r--drivers/staging/speakup/speakup_dtlk.c7
-rw-r--r--drivers/staging/speakup/synth.c6
-rw-r--r--drivers/staging/unisys/Kconfig1
-rw-r--r--drivers/staging/unisys/Makefile1
-rw-r--r--drivers/staging/unisys/channels/Kconfig10
-rw-r--r--drivers/staging/unisys/channels/Makefile11
-rw-r--r--drivers/staging/unisys/channels/channel.c219
-rw-r--r--drivers/staging/unisys/channels/chanstub.c75
-rw-r--r--drivers/staging/unisys/channels/chanstub.h23
-rw-r--r--drivers/staging/unisys/common-spar/include/version.h1
-rw-r--r--drivers/staging/unisys/include/timskmod.h4
-rw-r--r--drivers/staging/unisys/uislib/Kconfig2
-rw-r--r--drivers/staging/unisys/uislib/uislib.c755
-rw-r--r--drivers/staging/unisys/uislib/uisqueue.c215
-rw-r--r--drivers/staging/unisys/uislib/uisthread.c1
-rw-r--r--drivers/staging/unisys/uislib/uisutils.c99
-rw-r--r--drivers/staging/unisys/virthba/Kconfig2
-rw-r--r--drivers/staging/unisys/virthba/virthba.c353
-rw-r--r--drivers/staging/unisys/virtpci/virtpci.c61
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel.h69
-rw-r--r--drivers/staging/unisys/visorchannel/visorchannel_funcs.c206
-rw-r--r--drivers/staging/unisys/visorchipset/file.c122
-rw-r--r--drivers/staging/unisys/visorchipset/file.h3
-rw-r--r--drivers/staging/unisys/visorchipset/globals.h2
-rw-r--r--drivers/staging/unisys/visorchipset/testing.h43
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset.h55
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_main.c5
-rw-r--r--drivers/staging/unisys/visorchipset/visorchipset_umode.h2
-rw-r--r--drivers/staging/unisys/visorutil/charqueue.c2
-rw-r--r--drivers/staging/unisys/visorutil/procobjecttree.c21
-rw-r--r--drivers/staging/vt6655/baseband.c343
-rw-r--r--drivers/staging/vt6655/baseband.h17
-rw-r--r--drivers/staging/vt6655/card.c9
-rw-r--r--drivers/staging/vt6655/channel.c18
-rw-r--r--drivers/staging/vt6655/channel.h2
-rw-r--r--drivers/staging/vt6655/device.h25
-rw-r--r--drivers/staging/vt6655/device_main.c172
-rw-r--r--drivers/staging/vt6655/dpc.c15
-rw-r--r--drivers/staging/vt6655/mac.c25
-rw-r--r--drivers/staging/vt6655/mac.h684
-rw-r--r--drivers/staging/vt6655/power.c26
-rw-r--r--drivers/staging/vt6655/rf.c27
-rw-r--r--drivers/staging/vt6655/rf.h8
-rw-r--r--drivers/staging/vt6655/rxtx.c3
-rw-r--r--drivers/staging/vt6655/upc.h8
-rw-r--r--drivers/staging/vt6656/card.c2
-rw-r--r--drivers/staging/vt6656/device.h6
-rw-r--r--drivers/staging/vt6656/dpc.h2
-rw-r--r--drivers/staging/vt6656/main_usb.c3
-rw-r--r--drivers/staging/vt6656/rxtx.c109
-rw-r--r--drivers/staging/wlan-ng/cfg80211.c4
-rw-r--r--drivers/staging/wlan-ng/hfa384x.h6
-rw-r--r--drivers/staging/wlan-ng/hfa384x_usb.c17
-rw-r--r--drivers/staging/wlan-ng/p80211conv.c2
-rw-r--r--drivers/staging/wlan-ng/p80211req.c2
-rw-r--r--drivers/staging/wlan-ng/prism2mgmt.h2
-rw-r--r--drivers/staging/wlan-ng/prism2sta.c4
-rw-r--r--drivers/staging/xgifb/XGI_main_26.c10
-rw-r--r--drivers/target/iscsi/iscsi_target.c105
-rw-r--r--drivers/target/iscsi/iscsi_target_auth.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_configfs.c17
-rw-r--r--drivers/target/iscsi/iscsi_target_core.h883
-rw-r--r--drivers/target/iscsi/iscsi_target_datain_values.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_device.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_erl0.c6
-rw-r--r--drivers/target/iscsi/iscsi_target_erl1.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_erl2.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_login.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_nego.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_nodeattrib.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_parameters.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_seq_pdu_list.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_stat.c4
-rw-r--r--drivers/target/iscsi/iscsi_target_stat.h64
-rw-r--r--drivers/target/iscsi/iscsi_target_tmr.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_tpg.c2
-rw-r--r--drivers/target/iscsi/iscsi_target_tq.c30
-rw-r--r--drivers/target/iscsi/iscsi_target_util.c12
-rw-r--r--drivers/target/iscsi/iscsi_target_util.h1
-rw-r--r--drivers/target/target_core_file.c5
-rw-r--r--drivers/target/target_core_iblock.c5
-rw-r--r--drivers/target/target_core_pr.c25
-rw-r--r--drivers/target/target_core_sbc.c140
-rw-r--r--drivers/target/target_core_spc.c2
-rw-r--r--drivers/target/target_core_user.c4
-rw-r--r--drivers/thermal/int340x_thermal/Makefile1
-rw-r--r--drivers/thermal/int340x_thermal/int3400_thermal.c4
-rw-r--r--drivers/thermal/int340x_thermal/int3402_thermal.c208
-rw-r--r--drivers/thermal/int340x_thermal/int3403_thermal.c208
-rw-r--r--drivers/thermal/int340x_thermal/int340x_thermal_zone.c276
-rw-r--r--drivers/thermal/int340x_thermal/int340x_thermal_zone.h68
-rw-r--r--drivers/thermal/int340x_thermal/processor_thermal_device.c92
-rw-r--r--drivers/thermal/intel_soc_dts_thermal.c46
-rw-r--r--drivers/thermal/of-thermal.c3
-rw-r--r--drivers/thermal/rockchip_thermal.c36
-rw-r--r--drivers/thermal/samsung/Kconfig9
-rw-r--r--drivers/thermal/samsung/Makefile2
-rw-r--r--drivers/thermal/samsung/exynos_thermal_common.c427
-rw-r--r--drivers/thermal/samsung/exynos_thermal_common.h106
-rw-r--r--drivers/thermal/samsung/exynos_tmu.c553
-rw-r--r--drivers/thermal/samsung/exynos_tmu.h77
-rw-r--r--drivers/thermal/samsung/exynos_tmu_data.c264
-rw-r--r--drivers/thermal/step_wise.c4
-rw-r--r--drivers/thermal/thermal_core.c6
-rw-r--r--drivers/tty/amiserial.c2
-rw-r--r--drivers/tty/ehv_bytechan.c1
-rw-r--r--drivers/tty/hvc/hvc_iucv.c31
-rw-r--r--drivers/tty/isicom.c2
-rw-r--r--drivers/tty/n_tty.c254
-rw-r--r--drivers/tty/pty.c31
-rw-r--r--drivers/tty/rocket.c4
-rw-r--r--drivers/tty/serial/8250/8250_core.c230
-rw-r--r--drivers/tty/serial/8250/8250_dma.c6
-rw-r--r--drivers/tty/serial/8250/8250_dw.c11
-rw-r--r--drivers/tty/serial/8250/8250_early.c13
-rw-r--r--drivers/tty/serial/8250/8250_omap.c88
-rw-r--r--drivers/tty/serial/8250/8250_pci.c4
-rw-r--r--drivers/tty/serial/8250/8250_pnp.c8
-rw-r--r--drivers/tty/serial/8250/Kconfig19
-rw-r--r--drivers/tty/serial/Kconfig56
-rw-r--r--drivers/tty/serial/Makefile4
-rw-r--r--drivers/tty/serial/altera_jtaguart.c1
-rw-r--r--drivers/tty/serial/altera_uart.c1
-rw-r--r--drivers/tty/serial/atmel_serial.c153
-rw-r--r--drivers/tty/serial/digicolor-usart.c560
-rw-r--r--drivers/tty/serial/etraxfs-uart.c996
-rw-r--r--drivers/tty/serial/fsl_lpuart.c135
-rw-r--r--drivers/tty/serial/imx.c190
-rw-r--r--drivers/tty/serial/mcf.c7
-rw-r--r--drivers/tty/serial/men_z135_uart.c155
-rw-r--r--drivers/tty/serial/mrst_max3110.c909
-rw-r--r--drivers/tty/serial/mrst_max3110.h61
-rw-r--r--drivers/tty/serial/msm_serial.c27
-rw-r--r--drivers/tty/serial/mxs-auart.c55
-rw-r--r--drivers/tty/serial/of_serial.c13
-rw-r--r--drivers/tty/serial/omap-serial.c37
-rw-r--r--drivers/tty/serial/samsung.c680
-rw-r--r--drivers/tty/serial/samsung.h42
-rw-r--r--drivers/tty/serial/serial_core.c111
-rw-r--r--drivers/tty/serial/sh-sci.c25
-rw-r--r--drivers/tty/serial/sirfsoc_uart.c40
-rw-r--r--drivers/tty/serial/sirfsoc_uart.h4
-rw-r--r--drivers/tty/serial/sprd_serial.c793
-rw-r--r--drivers/tty/serial/xilinx_uartps.c10
-rw-r--r--drivers/tty/sysrq.c23
-rw-r--r--drivers/tty/tty_buffer.c6
-rw-r--r--drivers/tty/tty_ioctl.c3
-rw-r--r--drivers/tty/tty_mutex.c18
-rw-r--r--drivers/tty/vt/vt.c18
-rw-r--r--drivers/uio/Kconfig20
-rw-r--r--drivers/uio/Makefile1
-rw-r--r--drivers/uio/uio_fsl_elbc_gpcm.c499
-rw-r--r--drivers/uio/uio_pci_generic.c3
-rw-r--r--drivers/usb/Kconfig2
-rw-r--r--drivers/usb/Makefile2
-rw-r--r--drivers/usb/chipidea/ci_hdrc_pci.c3
-rw-r--r--drivers/usb/chipidea/udc.c18
-rw-r--r--drivers/usb/class/cdc-acm.c54
-rw-r--r--drivers/usb/core/buffer.c26
-rw-r--r--drivers/usb/core/devio.c63
-rw-r--r--drivers/usb/core/driver.c29
-rw-r--r--drivers/usb/core/hcd.c16
-rw-r--r--drivers/usb/core/hub.c94
-rw-r--r--drivers/usb/core/message.c23
-rw-r--r--drivers/usb/core/otg_whitelist.h5
-rw-r--r--drivers/usb/core/quirks.c4
-rw-r--r--drivers/usb/core/usb.c1
-rw-r--r--drivers/usb/dwc2/Kconfig4
-rw-r--r--drivers/usb/dwc2/core.c2
-rw-r--r--drivers/usb/dwc2/core.h60
-rw-r--r--drivers/usb/dwc2/core_intr.c6
-rw-r--r--drivers/usb/dwc2/gadget.c1191
-rw-r--r--drivers/usb/dwc2/hcd.c100
-rw-r--r--drivers/usb/dwc2/hw.h2
-rw-r--r--drivers/usb/dwc2/platform.c36
-rw-r--r--drivers/usb/dwc3/Kconfig6
-rw-r--r--drivers/usb/dwc3/Makefile1
-rw-r--r--drivers/usb/dwc3/core.c2
-rw-r--r--drivers/usb/dwc3/core.h5
-rw-r--r--drivers/usb/dwc3/dwc3-pci.c178
-rw-r--r--drivers/usb/dwc3/ep0.c2
-rw-r--r--drivers/usb/dwc3/gadget.c82
-rw-r--r--drivers/usb/dwc3/trace.h10
-rw-r--r--drivers/usb/gadget/Kconfig45
-rw-r--r--drivers/usb/gadget/composite.c2
-rw-r--r--drivers/usb/gadget/function/Makefile2
-rw-r--r--drivers/usb/gadget/function/f_fs.c119
-rw-r--r--drivers/usb/gadget/function/f_hid.c2
-rw-r--r--drivers/usb/gadget/function/f_sourcesink.c20
-rw-r--r--drivers/usb/gadget/function/f_uac1.c16
-rw-r--r--drivers/usb/gadget/function/f_uvc.c136
-rw-r--r--drivers/usb/gadget/function/u_ether.c4
-rw-r--r--drivers/usb/gadget/function/u_fs.h25
-rw-r--r--drivers/usb/gadget/function/u_uac1.c3
-rw-r--r--drivers/usb/gadget/function/u_uac1.h1
-rw-r--r--drivers/usb/gadget/function/u_uvc.h52
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.c2468
-rw-r--r--drivers/usb/gadget/function/uvc_configfs.h22
-rw-r--r--drivers/usb/gadget/legacy/Kconfig2
-rw-r--r--drivers/usb/gadget/udc/Kconfig5
-rw-r--r--drivers/usb/gadget/udc/at91_udc.c533
-rw-r--r--drivers/usb/gadget/udc/at91_udc.h10
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.c162
-rw-r--r--drivers/usb/gadget/udc/atmel_usba_udc.h9
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_core.c1
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_ep.c10
-rw-r--r--drivers/usb/gadget/udc/bdc/bdc_udc.c1
-rw-r--r--drivers/usb/gadget/udc/dummy_hcd.c9
-rw-r--r--drivers/usb/gadget/udc/fsl_qe_udc.c2
-rw-r--r--drivers/usb/gadget/udc/fsl_udc_core.c5
-rw-r--r--drivers/usb/gadget/udc/lpc32xx_udc.c12
-rw-r--r--drivers/usb/gadget/udc/mv_udc_core.c3
-rw-r--r--drivers/usb/gadget/udc/net2272.c7
-rw-r--r--drivers/usb/gadget/udc/net2272.h1
-rw-r--r--drivers/usb/gadget/udc/net2280.c533
-rw-r--r--drivers/usb/gadget/udc/net2280.h24
-rw-r--r--drivers/usb/gadget/udc/omap_udc.c1
-rw-r--r--drivers/usb/gadget/udc/pch_udc.c1
-rw-r--r--drivers/usb/gadget/udc/pxa25x_udc.c2
-rw-r--r--drivers/usb/gadget/udc/pxa27x_udc.c2
-rw-r--r--drivers/usb/gadget/udc/r8a66597-udc.c1
-rw-r--r--drivers/usb/gadget/udc/s3c2410_udc.c21
-rw-r--r--drivers/usb/gadget/udc/udc-core.c2
-rw-r--r--drivers/usb/gadget/udc/udc-xilinx.c4
-rw-r--r--drivers/usb/host/Kconfig22
-rw-r--r--drivers/usb/host/Makefile3
-rw-r--r--drivers/usb/host/bcma-hcd.c2
-rw-r--r--drivers/usb/host/ehci-atmel.c102
-rw-r--r--drivers/usb/host/ehci-fsl.c1
-rw-r--r--drivers/usb/host/ehci-grlib.c1
-rw-r--r--drivers/usb/host/ehci-hcd.c6
-rw-r--r--drivers/usb/host/ehci-hub.c8
-rw-r--r--drivers/usb/host/ehci-pci.c27
-rw-r--r--drivers/usb/host/ehci-platform.c92
-rw-r--r--drivers/usb/host/ehci-pmcmsp.c1
-rw-r--r--drivers/usb/host/ehci-ppc-of.c1
-rw-r--r--drivers/usb/host/ehci-sead3.c1
-rw-r--r--drivers/usb/host/ehci-sh.c1
-rw-r--r--drivers/usb/host/ehci-tilegx.c1
-rw-r--r--drivers/usb/host/ehci-xilinx-of.c1
-rw-r--r--drivers/usb/host/ehci.h2
-rw-r--r--drivers/usb/host/fhci-hub.c9
-rw-r--r--drivers/usb/host/fotg210-hcd.c4
-rw-r--r--drivers/usb/host/fusbh200-hcd.c4
-rw-r--r--drivers/usb/host/imx21-hcd.c5
-rw-r--r--drivers/usb/host/isp116x-hcd.c5
-rw-r--r--drivers/usb/host/isp1362-hcd.c8
-rw-r--r--drivers/usb/host/isp1760-hcd.c2268
-rw-r--r--drivers/usb/host/isp1760-hcd.h208
-rw-r--r--drivers/usb/host/isp1760-if.c477
-rw-r--r--drivers/usb/host/max3421-hcd.c6
-rw-r--r--drivers/usb/host/ohci-at91.c132
-rw-r--r--drivers/usb/host/ohci-da8xx.c1
-rw-r--r--drivers/usb/host/ohci-hub.c10
-rw-r--r--drivers/usb/host/ohci-jz4740.c1
-rw-r--r--drivers/usb/host/ohci-platform.c83
-rw-r--r--drivers/usb/host/ohci-ppc-of.c1
-rw-r--r--drivers/usb/host/ohci-s3c2410.c6
-rw-r--r--drivers/usb/host/ohci-sm501.c1
-rw-r--r--drivers/usb/host/ohci-tilegx.c1
-rw-r--r--drivers/usb/host/ohci-tmio.c1
-rw-r--r--drivers/usb/host/oxu210hp-hcd.c10
-rw-r--r--drivers/usb/host/pci-quirks.c46
-rw-r--r--drivers/usb/host/r8a66597-hcd.c13
-rw-r--r--drivers/usb/host/sl811-hcd.c10
-rw-r--r--drivers/usb/host/ssb-hcd.c2
-rw-r--r--drivers/usb/host/u132-hcd.c10
-rw-r--r--drivers/usb/host/uhci-grlib.c1
-rw-r--r--drivers/usb/host/uhci-hub.c5
-rw-r--r--drivers/usb/host/uhci-platform.c1
-rw-r--r--drivers/usb/host/whci/debug.c7
-rw-r--r--drivers/usb/host/xhci-dbg.c2
-rw-r--r--drivers/usb/host/xhci-mem.c31
-rw-r--r--drivers/usb/host/xhci-ring.c12
-rw-r--r--drivers/usb/host/xhci.c78
-rw-r--r--drivers/usb/host/xhci.h12
-rw-r--r--drivers/usb/image/microtek.c4
-rw-r--r--drivers/usb/isp1760/Kconfig59
-rw-r--r--drivers/usb/isp1760/Makefile5
-rw-r--r--drivers/usb/isp1760/isp1760-core.c177
-rw-r--r--drivers/usb/isp1760/isp1760-core.h68
-rw-r--r--drivers/usb/isp1760/isp1760-hcd.c2235
-rw-r--r--drivers/usb/isp1760/isp1760-hcd.h102
-rw-r--r--drivers/usb/isp1760/isp1760-if.c309
-rw-r--r--drivers/usb/isp1760/isp1760-regs.h230
-rw-r--r--drivers/usb/isp1760/isp1760-udc.c1498
-rw-r--r--drivers/usb/isp1760/isp1760-udc.h106
-rw-r--r--drivers/usb/misc/uss720.c12
-rw-r--r--drivers/usb/musb/Kconfig7
-rw-r--r--drivers/usb/musb/blackfin.c2
-rw-r--r--drivers/usb/musb/musb_core.c7
-rw-r--r--drivers/usb/musb/musb_cppi41.c24
-rw-r--r--drivers/usb/musb/musb_debugfs.c2
-rw-r--r--drivers/usb/musb/musb_gadget.c4
-rw-r--r--drivers/usb/musb/musb_gadget_ep0.c2
-rw-r--r--drivers/usb/musb/musb_virthub.c7
-rw-r--r--drivers/usb/phy/Kconfig2
-rw-r--r--drivers/usb/phy/phy-fsl-usb.c35
-rw-r--r--drivers/usb/phy/phy-generic.c150
-rw-r--r--drivers/usb/phy/phy-generic.h10
-rw-r--r--drivers/usb/phy/phy-mxs-usb.c86
-rw-r--r--drivers/usb/phy/phy.c2
-rw-r--r--drivers/usb/renesas_usbhs/common.c25
-rw-r--r--drivers/usb/renesas_usbhs/common.h3
-rw-r--r--drivers/usb/renesas_usbhs/fifo.c25
-rw-r--r--drivers/usb/renesas_usbhs/mod_gadget.c2
-rw-r--r--drivers/usb/renesas_usbhs/mod_host.c3
-rw-r--r--drivers/usb/serial/cp210x.c1
-rw-r--r--drivers/usb/serial/mos7840.c60
-rw-r--r--drivers/usb/serial/option.c60
-rw-r--r--drivers/usb/storage/unusual_devs.h9
-rw-r--r--drivers/usb/storage/unusual_uas.h7
-rw-r--r--drivers/usb/usbip/vhci_hcd.c3
-rw-r--r--drivers/usb/wusbcore/reservation.c5
-rw-r--r--drivers/usb/wusbcore/rh.c4
-rw-r--r--drivers/usb/wusbcore/wa-rpipe.c5
-rw-r--r--drivers/usb/wusbcore/wusbhc.c7
-rw-r--r--drivers/uwb/drp.c2
-rw-r--r--drivers/uwb/lc-dev.c7
-rw-r--r--drivers/uwb/uwb-debug.c16
-rw-r--r--drivers/vfio/pci/vfio_pci.c21
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c60
-rw-r--r--drivers/vfio/pci/vfio_pci_private.h1
-rw-r--r--drivers/vfio/vfio.c119
-rw-r--r--drivers/vfio/vfio_iommu_type1.c80
-rw-r--r--drivers/vhost/net.c92
-rw-r--r--drivers/vhost/scsi.c1068
-rw-r--r--drivers/vhost/vhost.c6
-rw-r--r--drivers/video/console/Kconfig16
-rw-r--r--drivers/video/console/dummycon.c5
-rw-r--r--drivers/video/console/fbcon.c4
-rw-r--r--drivers/video/fbdev/Kconfig5
-rw-r--r--drivers/video/fbdev/atafb.c3
-rw-r--r--drivers/video/fbdev/aty/atyfb_base.c9
-rw-r--r--drivers/video/fbdev/core/fbcvt.c6
-rw-r--r--drivers/video/fbdev/core/fbmon.c103
-rw-r--r--drivers/video/fbdev/core/modedb.c111
-rw-r--r--drivers/video/fbdev/core/syscopyarea.c137
-rw-r--r--drivers/video/fbdev/geode/gx1fb_core.c6
-rw-r--r--drivers/video/fbdev/geode/gxfb_core.c6
-rw-r--r--drivers/video/fbdev/geode/lxfb_core.c6
-rw-r--r--drivers/video/fbdev/hgafb.c3
-rw-r--r--drivers/video/fbdev/mmp/Makefile4
-rw-r--r--drivers/video/fbdev/mmp/fb/Kconfig2
-rw-r--r--drivers/video/fbdev/ocfb.c2
-rw-r--r--drivers/video/fbdev/omap2/displays-new/Kconfig6
-rw-r--r--drivers/video/fbdev/omap2/displays-new/Makefile1
-rw-r--r--drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c2
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-opa362.c285
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c57
-rw-r--r--drivers/video/fbdev/omap2/dss/Makefile2
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c54
-rw-r--r--drivers/video/fbdev/omap2/dss/dpi.c26
-rw-r--r--drivers/video/fbdev/omap2/dss/dsi.c1
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c219
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h22
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.c3
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5.c1
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_phy.c1
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c6
-rw-r--r--drivers/video/fbdev/omap2/dss/omapdss-boot-init.c1
-rw-r--r--drivers/video/fbdev/omap2/dss/pll.c10
-rw-r--r--drivers/video/fbdev/omap2/dss/video-pll.c211
-rw-r--r--drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c7
-rw-r--r--drivers/video/fbdev/pvr2fb.c6
-rw-r--r--drivers/video/fbdev/savage/savagefb.h12
-rw-r--r--drivers/video/fbdev/ssd1307fb.c86
-rw-r--r--drivers/video/fbdev/vt8500lcdfb.c4
-rw-r--r--drivers/video/hdmi.c822
-rw-r--r--drivers/video/vgastate.c82
-rw-r--r--drivers/virtio/Kconfig24
-rw-r--r--drivers/virtio/Makefile3
-rw-r--r--drivers/virtio/virtio.c5
-rw-r--r--drivers/virtio/virtio_balloon.c9
-rw-r--r--drivers/virtio/virtio_mmio.c131
-rw-r--r--drivers/virtio/virtio_pci_common.c94
-rw-r--r--drivers/virtio/virtio_pci_common.h43
-rw-r--r--drivers/virtio/virtio_pci_legacy.c76
-rw-r--r--drivers/virtio/virtio_pci_modern.c695
-rw-r--r--drivers/virtio/virtio_ring.c9
-rw-r--r--drivers/vme/vme.c2
-rw-r--r--drivers/watchdog/Kconfig25
-rw-r--r--drivers/watchdog/Makefile2
-rw-r--r--drivers/watchdog/bcm47xx_wdt.c21
-rw-r--r--drivers/watchdog/da9063_wdt.c32
-rw-r--r--drivers/watchdog/dw_wdt.c32
-rw-r--r--drivers/watchdog/gpio_wdt.c37
-rw-r--r--drivers/watchdog/hpwdt.c2
-rw-r--r--drivers/watchdog/imgpdc_wdt.c289
-rw-r--r--drivers/watchdog/imx2_wdt.c4
-rw-r--r--drivers/watchdog/it87_wdt.c6
-rw-r--r--drivers/watchdog/jz4740_wdt.c10
-rw-r--r--drivers/watchdog/mtk_wdt.c251
-rw-r--r--drivers/watchdog/omap_wdt.c2
-rw-r--r--drivers/watchdog/retu_wdt.c2
-rw-r--r--drivers/watchdog/rt2880_wdt.c9
-rw-r--r--drivers/watchdog/twl4030_wdt.c2
-rw-r--r--drivers/watchdog/w83627hf_wdt.c14
-rw-r--r--drivers/xen/Makefile2
-rw-r--r--drivers/xen/balloon.c86
-rw-r--r--drivers/xen/gntdev.c143
-rw-r--r--drivers/xen/grant-table.c120
-rw-r--r--drivers/xen/manage.c8
-rw-r--r--drivers/xen/preempt.c44
-rw-r--r--drivers/xen/privcmd.c2
-rw-r--r--drivers/xen/tmem.c2
-rw-r--r--drivers/xen/xen-acpi-memhotplug.c8
-rw-r--r--drivers/xen/xen-scsiback.c21
-rw-r--r--drivers/xen/xenbus/xenbus_dev_frontend.c11
4890 files changed, 343607 insertions, 229547 deletions
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 694d5a70d6ce..c0cc96bab9e7 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -36,8 +36,6 @@ source "drivers/message/fusion/Kconfig"
source "drivers/firewire/Kconfig"
-source "drivers/message/i2o/Kconfig"
-
source "drivers/macintosh/Kconfig"
source "drivers/net/Kconfig"
@@ -134,8 +132,6 @@ source "drivers/staging/Kconfig"
source "drivers/platform/Kconfig"
-source "drivers/soc/Kconfig"
-
source "drivers/clk/Kconfig"
source "drivers/hwspinlock/Kconfig"
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index 8951cefb0a96..e6c3ddd92665 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -315,6 +315,12 @@ config ACPI_HOTPLUG_MEMORY
To compile this driver as a module, choose M here:
the module will be called acpi_memhotplug.
+config ACPI_HOTPLUG_IOAPIC
+ bool
+ depends on PCI
+ depends on X86_IO_APIC
+ default y
+
config ACPI_SBS
tristate "Smart Battery System"
depends on X86
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index f74317cc1ca9..623b117ad1a2 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -40,7 +40,7 @@ acpi-$(CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC) += processor_pdc.o
acpi-y += ec.o
acpi-$(CONFIG_ACPI_DOCK) += dock.o
acpi-y += pci_root.o pci_link.o pci_irq.o
-acpi-y += acpi_lpss.o
+acpi-y += acpi_lpss.o acpi_apd.o
acpi-y += acpi_platform.o
acpi-y += acpi_pnp.o
acpi-y += int340x_thermal.o
@@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
ifdef CONFIG_ACPI_VIDEO
acpi-y += video_detect.o
endif
+acpi-y += acpi_lpat.o
# These are (potentially) separate modules
@@ -70,6 +71,7 @@ obj-$(CONFIG_ACPI_PROCESSOR) += processor.o
obj-y += container.o
obj-$(CONFIG_ACPI_THERMAL) += thermal.o
obj-y += acpi_memhotplug.o
+obj-$(CONFIG_ACPI_HOTPLUG_IOAPIC) += ioapic.o
obj-$(CONFIG_ACPI_BATTERY) += battery.o
obj-$(CONFIG_ACPI_SBS) += sbshc.o
obj-$(CONFIG_ACPI_SBS) += sbs.o
diff --git a/drivers/acpi/acpi_apd.c b/drivers/acpi/acpi_apd.c
new file mode 100644
index 000000000000..3984ea96e5f7
--- /dev/null
+++ b/drivers/acpi/acpi_apd.c
@@ -0,0 +1,150 @@
+/*
+ * AMD ACPI support for ACPI2platform device.
+ *
+ * Copyright (c) 2014,2015 AMD Corporation.
+ * Authors: Ken Xue <Ken.Xue@amd.com>
+ * Wu, Jeff <Jeff.Wu@amd.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/clkdev.h>
+#include <linux/acpi.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/pm.h>
+
+#include "internal.h"
+
+ACPI_MODULE_NAME("acpi_apd");
+struct apd_private_data;
+
+/**
+ * ACPI_APD_SYSFS : add device attributes in sysfs
+ * ACPI_APD_PM : attach power domain to device
+ */
+#define ACPI_APD_SYSFS BIT(0)
+#define ACPI_APD_PM BIT(1)
+
+/**
+ * struct apd_device_desc - a descriptor for apd device
+ * @flags: device flags like %ACPI_APD_SYSFS, %ACPI_APD_PM
+ * @fixed_clk_rate: fixed rate input clock source for acpi device;
+ * 0 means no fixed rate input clock source
+ * @setup: a hook routine to set device resource during create platform device
+ *
+ * Device description defined as acpi_device_id.driver_data
+ */
+struct apd_device_desc {
+ unsigned int flags;
+ unsigned int fixed_clk_rate;
+ int (*setup)(struct apd_private_data *pdata);
+};
+
+struct apd_private_data {
+ struct clk *clk;
+ struct acpi_device *adev;
+ const struct apd_device_desc *dev_desc;
+};
+
+#ifdef CONFIG_X86_AMD_PLATFORM_DEVICE
+#define APD_ADDR(desc) ((unsigned long)&desc)
+
+static int acpi_apd_setup(struct apd_private_data *pdata)
+{
+ const struct apd_device_desc *dev_desc = pdata->dev_desc;
+ struct clk *clk = ERR_PTR(-ENODEV);
+
+ if (dev_desc->fixed_clk_rate) {
+ clk = clk_register_fixed_rate(&pdata->adev->dev,
+ dev_name(&pdata->adev->dev),
+ NULL, CLK_IS_ROOT,
+ dev_desc->fixed_clk_rate);
+ clk_register_clkdev(clk, NULL, dev_name(&pdata->adev->dev));
+ pdata->clk = clk;
+ }
+
+ return 0;
+}
+
+static struct apd_device_desc cz_i2c_desc = {
+ .setup = acpi_apd_setup,
+ .fixed_clk_rate = 133000000,
+};
+
+static struct apd_device_desc cz_uart_desc = {
+ .setup = acpi_apd_setup,
+ .fixed_clk_rate = 48000000,
+};
+
+#else
+
+#define APD_ADDR(desc) (0UL)
+
+#endif /* CONFIG_X86_AMD_PLATFORM_DEVICE */
+
+/**
+* Create platform device during acpi scan attach handle.
+* Return value > 0 on success of creating device.
+*/
+static int acpi_apd_create_device(struct acpi_device *adev,
+ const struct acpi_device_id *id)
+{
+ const struct apd_device_desc *dev_desc = (void *)id->driver_data;
+ struct apd_private_data *pdata;
+ struct platform_device *pdev;
+ int ret;
+
+ if (!dev_desc) {
+ pdev = acpi_create_platform_device(adev);
+ return IS_ERR_OR_NULL(pdev) ? PTR_ERR(pdev) : 1;
+ }
+
+ pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+
+ pdata->adev = adev;
+ pdata->dev_desc = dev_desc;
+
+ if (dev_desc->setup) {
+ ret = dev_desc->setup(pdata);
+ if (ret)
+ goto err_out;
+ }
+
+ adev->driver_data = pdata;
+ pdev = acpi_create_platform_device(adev);
+ if (!IS_ERR_OR_NULL(pdev))
+ return 1;
+
+ ret = PTR_ERR(pdev);
+ adev->driver_data = NULL;
+
+ err_out:
+ kfree(pdata);
+ return ret;
+}
+
+static const struct acpi_device_id acpi_apd_device_ids[] = {
+ /* Generic apd devices */
+ { "AMD0010", APD_ADDR(cz_i2c_desc) },
+ { "AMD0020", APD_ADDR(cz_uart_desc) },
+ { "AMD0030", },
+ { }
+};
+
+static struct acpi_scan_handler apd_handler = {
+ .ids = acpi_apd_device_ids,
+ .attach = acpi_apd_create_device,
+};
+
+void __init acpi_apd_init(void)
+{
+ acpi_scan_add_handler(&apd_handler);
+}
diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c
new file mode 100644
index 000000000000..feb61c1630eb
--- /dev/null
+++ b/drivers/acpi/acpi_lpat.c
@@ -0,0 +1,161 @@
+/*
+ * acpi_lpat.c - LPAT table processing functions
+ *
+ * Copyright (C) 2015 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_lpat.h>
+
+/**
+ * acpi_lpat_raw_to_temp(): Return temperature from raw value through
+ * LPAT conversion table
+ *
+ * @lpat_table: the temperature_raw mapping table structure
+ * @raw: the raw value, used as a key to get the temerature from the
+ * above mapping table
+ *
+ * A positive converted temperarure value will be returned on success,
+ * a negative errno will be returned in error cases.
+ */
+int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
+ int raw)
+{
+ int i, delta_temp, delta_raw, temp;
+ struct acpi_lpat *lpat = lpat_table->lpat;
+
+ for (i = 0; i < lpat_table->lpat_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 == lpat_table->lpat_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;
+}
+EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp);
+
+/**
+ * acpi_lpat_temp_to_raw(): Return raw value from temperature through
+ * LPAT conversion table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @temp: the temperature, used as a key to get the raw value from the
+ * above mapping table
+ *
+ * A positive converted temperature value will be returned on success,
+ * a negative errno will be returned in error cases.
+ */
+int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
+ int temp)
+{
+ int i, delta_temp, delta_raw, raw;
+ struct acpi_lpat *lpat = lpat_table->lpat;
+
+ for (i = 0; i < lpat_table->lpat_count - 1; i++) {
+ if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
+ break;
+ }
+
+ if (i == lpat_table->lpat_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;
+}
+EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw);
+
+/**
+ * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present.
+ *
+ * @handle: Handle to acpi device
+ *
+ * Parse LPAT table to a struct of type acpi_lpat_table. On success
+ * it returns a pointer to newly allocated table. This table must
+ * be freed by the caller when finished processing, using a call to
+ * acpi_lpat_free_conversion_table.
+ */
+struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle
+ handle)
+{
+ struct acpi_lpat_conversion_table *lpat_table = NULL;
+ 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 NULL;
+
+ 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 = kcalloc(obj_p->package.count, sizeof(int), 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) {
+ kfree(lpat);
+ goto out;
+ }
+ lpat[i] = (s64)obj_e->integer.value;
+ }
+
+ lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL);
+ if (!lpat_table) {
+ kfree(lpat);
+ goto out;
+ }
+
+ lpat_table->lpat = (struct acpi_lpat *)lpat;
+ lpat_table->lpat_count = obj_p->package.count / 2;
+
+out:
+ kfree(buffer.pointer);
+ return lpat_table;
+}
+EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table);
+
+/**
+ * acpi_lpat_free_conversion_table(): Free LPAT table.
+ *
+ * @lpat_table: the temperature_raw mapping table structure
+ *
+ * Frees the LPAT table previously allocated by a call to
+ * acpi_lpat_get_conversion_table.
+ */
+void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
+ *lpat_table)
+{
+ if (lpat_table) {
+ kfree(lpat_table->lpat);
+ kfree(lpat_table);
+ }
+}
+EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 4f3febf8a589..657964e8ab7e 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, 2014, Intel Corporation
+ * Copyright (C) 2013, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
@@ -60,8 +60,6 @@ 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;
@@ -72,10 +70,8 @@ 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 | LPSS_PROXY_REQ,
+ .flags = LPSS_CLK,
};
struct lpss_private_data {
@@ -109,7 +105,7 @@ static void lpss_uart_setup(struct lpss_private_data *pdata)
}
}
-static void byt_i2c_setup(struct lpss_private_data *pdata)
+static void lpss_deassert_reset(struct lpss_private_data *pdata)
{
unsigned int offset;
u32 val;
@@ -118,9 +114,18 @@ static void byt_i2c_setup(struct lpss_private_data *pdata)
val = readl(pdata->mmio_base + offset);
val |= LPSS_RESETS_RESET_APB | LPSS_RESETS_RESET_FUNC;
writel(val, pdata->mmio_base + offset);
+}
+
+#define LPSS_I2C_ENABLE 0x6c
+
+static void byt_i2c_setup(struct lpss_private_data *pdata)
+{
+ lpss_deassert_reset(pdata);
if (readl(pdata->mmio_base + pdata->dev_desc->prv_offset))
pdata->fixed_clk_rate = 133000000;
+
+ writel(0, pdata->mmio_base + LPSS_I2C_ENABLE);
}
static struct lpss_device_desc lpt_dev_desc = {
@@ -150,28 +155,32 @@ 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 |
- LPSS_DEV_PROXY,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.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 |
- LPSS_DEV_PROXY,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
.prv_offset = 0x400,
};
static struct lpss_device_desc byt_sdio_dev_desc = {
- .flags = LPSS_CLK | LPSS_DEV_PROXY,
+ .flags = LPSS_CLK,
};
static struct lpss_device_desc byt_i2c_dev_desc = {
- .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY,
+ .flags = LPSS_CLK | LPSS_SAVE_CTX,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
};
+static struct lpss_device_desc bsw_spi_dev_desc = {
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .prv_offset = 0x400,
+ .setup = lpss_deassert_reset,
+};
+
#else
#define LPSS_ADDR(desc) (0UL)
@@ -204,7 +213,7 @@ static const struct acpi_device_id acpi_lpss_device_ids[] = {
/* Braswell LPSS devices */
{ "80862288", LPSS_ADDR(byt_pwm_dev_desc) },
{ "8086228A", LPSS_ADDR(byt_uart_dev_desc) },
- { "8086228E", LPSS_ADDR(byt_spi_dev_desc) },
+ { "8086228E", LPSS_ADDR(bsw_spi_dev_desc) },
{ "808622C1", LPSS_ADDR(byt_i2c_dev_desc) },
{ "INT3430", LPSS_ADDR(lpt_dev_desc) },
@@ -313,7 +322,7 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
{
struct lpss_device_desc *dev_desc;
struct lpss_private_data *pdata;
- struct resource_list_entry *rentry;
+ struct resource_entry *rentry;
struct list_head resource_list;
struct platform_device *pdev;
int ret;
@@ -333,13 +342,15 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
goto err_out;
list_for_each_entry(rentry, &resource_list, node)
- if (resource_type(&rentry->res) == IORESOURCE_MEM) {
+ if (resource_type(rentry->res) == IORESOURCE_MEM) {
if (dev_desc->prv_size_override)
pdata->mmio_size = dev_desc->prv_size_override;
else
- pdata->mmio_size = resource_size(&rentry->res);
- pdata->mmio_base = ioremap(rentry->res.start,
+ pdata->mmio_size = resource_size(rentry->res);
+ pdata->mmio_base = ioremap(rentry->res->start,
pdata->mmio_size);
+ if (!pdata->mmio_base)
+ goto err_out;
break;
}
@@ -374,8 +385,6 @@ 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;
}
@@ -600,14 +609,7 @@ static int acpi_lpss_runtime_suspend(struct device *dev)
if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
acpi_lpss_save_ctx(dev, pdata);
- ret = acpi_dev_runtime_suspend(dev);
- if (ret)
- return ret;
-
- if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device)
- return pm_runtime_put_sync_suspend(proxy_device);
-
- return 0;
+ return acpi_dev_runtime_suspend(dev);
}
static int acpi_lpss_runtime_resume(struct device *dev)
@@ -615,12 +617,6 @@ static int acpi_lpss_runtime_resume(struct device *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;
diff --git a/drivers/acpi/acpi_memhotplug.c b/drivers/acpi/acpi_memhotplug.c
index 23e2319ead41..ee28f4d15625 100644
--- a/drivers/acpi/acpi_memhotplug.c
+++ b/drivers/acpi/acpi_memhotplug.c
@@ -101,8 +101,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
/* Can we combine the resource range information? */
if ((info->caching == address64.info.mem.caching) &&
(info->write_protect == address64.info.mem.write_protect) &&
- (info->start_addr + info->length == address64.minimum)) {
- info->length += address64.address_length;
+ (info->start_addr + info->length == address64.address.minimum)) {
+ info->length += address64.address.address_length;
return AE_OK;
}
}
@@ -114,8 +114,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
INIT_LIST_HEAD(&new->list);
new->caching = address64.info.mem.caching;
new->write_protect = address64.info.mem.write_protect;
- new->start_addr = address64.minimum;
- new->length = address64.address_length;
+ new->start_addr = address64.address.minimum;
+ new->length = address64.address.address_length;
list_add_tail(&new->list, &mem_device->res_list);
return AE_OK;
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 6ba8beb6b9d2..1284138e42ab 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -45,7 +45,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
struct platform_device *pdev = NULL;
struct acpi_device *acpi_parent;
struct platform_device_info pdevinfo;
- struct resource_list_entry *rentry;
+ struct resource_entry *rentry;
struct list_head resource_list;
struct resource *resources = NULL;
int count;
@@ -71,7 +71,7 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
}
count = 0;
list_for_each_entry(rentry, &resource_list, node)
- resources[count++] = rentry->res;
+ resources[count++] = *rentry->res;
acpi_dev_free_resource_list(&resource_list);
}
diff --git a/drivers/acpi/acpica/acapps.h b/drivers/acpi/acpica/acapps.h
index 3d2c88289da9..d863016565b5 100644
--- a/drivers/acpi/acpica/acapps.h
+++ b/drivers/acpi/acpica/acapps.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -47,7 +47,7 @@
/* Common info for tool signons */
#define ACPICA_NAME "Intel ACPI Component Architecture"
-#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2014 Intel Corporation"
+#define ACPICA_COPYRIGHT "Copyright (c) 2000 - 2015 Intel Corporation"
#if ACPI_MACHINE_WIDTH == 64
#define ACPI_WIDTH "-64"
diff --git a/drivers/acpi/acpica/accommon.h b/drivers/acpi/acpica/accommon.h
index 6f1c616910ac..853aa2dbdb61 100644
--- a/drivers/acpi/acpica/accommon.h
+++ b/drivers/acpi/acpica/accommon.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdebug.h b/drivers/acpi/acpica/acdebug.h
index 1d026ff1683f..4169bb87a996 100644
--- a/drivers/acpi/acpica/acdebug.h
+++ b/drivers/acpi/acpica/acdebug.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acdispat.h b/drivers/acpi/acpica/acdispat.h
index d3e2cc395d7f..408f04bcaab4 100644
--- a/drivers/acpi/acpica/acdispat.h
+++ b/drivers/acpi/acpica/acdispat.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acevents.h b/drivers/acpi/acpica/acevents.h
index 7a7811a9fc26..228704b78657 100644
--- a/drivers/acpi/acpica/acevents.h
+++ b/drivers/acpi/acpica/acevents.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -143,8 +143,6 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
acpi_status
acpi_ev_walk_gpe_list(acpi_gpe_callback gpe_walk_callback, void *context);
-u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info);
-
acpi_status
acpi_ev_get_gpe_device(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block, void *context);
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index 7f60582d0c8c..a165d25343e8 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/achware.h b/drivers/acpi/acpica/achware.h
index c318d3e27893..196a55244559 100644
--- a/drivers/acpi/acpica/achware.h
+++ b/drivers/acpi/acpica/achware.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acinterp.h b/drivers/acpi/acpica/acinterp.h
index b01f71ce0523..1886bde54b5d 100644
--- a/drivers/acpi/acpica/acinterp.h
+++ b/drivers/acpi/acpica/acinterp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index 680d23bbae7c..7add32e5d8c5 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acmacros.h b/drivers/acpi/acpica/acmacros.h
index 4bceb11c7380..cf607fe69dbd 100644
--- a/drivers/acpi/acpica/acmacros.h
+++ b/drivers/acpi/acpica/acmacros.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acnamesp.h b/drivers/acpi/acpica/acnamesp.h
index ee1c040f321c..952fbe0b7231 100644
--- a/drivers/acpi/acpica/acnamesp.h
+++ b/drivers/acpi/acpica/acnamesp.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acobject.h b/drivers/acpi/acpica/acobject.h
index 8abb393dafab..3e9720e1f34f 100644
--- a/drivers/acpi/acpica/acobject.h
+++ b/drivers/acpi/acpica/acobject.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acopcode.h b/drivers/acpi/acpica/acopcode.h
index dda0e6affcf1..a5f17de45ac6 100644
--- a/drivers/acpi/acpica/acopcode.h
+++ b/drivers/acpi/acpica/acopcode.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acparser.h b/drivers/acpi/acpica/acparser.h
index 6168b85463ed..74a390c6db16 100644
--- a/drivers/acpi/acpica/acparser.h
+++ b/drivers/acpi/acpica/acparser.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acpredef.h b/drivers/acpi/acpica/acpredef.h
index bd3908d26c4f..a972d11c97c9 100644
--- a/drivers/acpi/acpica/acpredef.h
+++ b/drivers/acpi/acpica/acpredef.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acresrc.h b/drivers/acpi/acpica/acresrc.h
index 4b008e8884a1..efc4c7124ccc 100644
--- a/drivers/acpi/acpica/acresrc.h
+++ b/drivers/acpi/acpica/acresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acstruct.h b/drivers/acpi/acpica/acstruct.h
index cf7346110bd8..d14b547b7cd5 100644
--- a/drivers/acpi/acpica/acstruct.h
+++ b/drivers/acpi/acpica/acstruct.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/actables.h b/drivers/acpi/acpica/actables.h
index 1afe46e44dac..1c127a43017b 100644
--- a/drivers/acpi/acpica/actables.h
+++ b/drivers/acpi/acpica/actables.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/acutils.h b/drivers/acpi/acpica/acutils.h
index 486d342e74b6..c2f03e8774ad 100644
--- a/drivers/acpi/acpica/acutils.h
+++ b/drivers/acpi/acpica/acutils.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlcode.h b/drivers/acpi/acpica/amlcode.h
index 5908ccec6aea..3a95068fc119 100644
--- a/drivers/acpi/acpica/amlcode.h
+++ b/drivers/acpi/acpica/amlcode.h
@@ -7,7 +7,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/amlresrc.h b/drivers/acpi/acpica/amlresrc.h
index 3a0beeb86ba5..ee0cdd60b93d 100644
--- a/drivers/acpi/acpica/amlresrc.h
+++ b/drivers/acpi/acpica/amlresrc.h
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsargs.c b/drivers/acpi/acpica/dsargs.c
index 720b1cdda711..3e6989738e85 100644
--- a/drivers/acpi/acpica/dsargs.c
+++ b/drivers/acpi/acpica/dsargs.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dscontrol.c b/drivers/acpi/acpica/dscontrol.c
index 8daf9de82b73..39da9da62bbf 100644
--- a/drivers/acpi/acpica/dscontrol.c
+++ b/drivers/acpi/acpica/dscontrol.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsfield.c b/drivers/acpi/acpica/dsfield.c
index c57666196672..43b40de90484 100644
--- a/drivers/acpi/acpica/dsfield.c
+++ b/drivers/acpi/acpica/dsfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsinit.c b/drivers/acpi/acpica/dsinit.c
index aee5e45f6d35..bbe74bcebbae 100644
--- a/drivers/acpi/acpica/dsinit.c
+++ b/drivers/acpi/acpica/dsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmethod.c b/drivers/acpi/acpica/dsmethod.c
index 3c7f7378b94d..d72565a3c646 100644
--- a/drivers/acpi/acpica/dsmethod.c
+++ b/drivers/acpi/acpica/dsmethod.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsmthdat.c b/drivers/acpi/acpica/dsmthdat.c
index b67522df01ac..2e4c42b377ec 100644
--- a/drivers/acpi/acpica/dsmthdat.c
+++ b/drivers/acpi/acpica/dsmthdat.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsobject.c b/drivers/acpi/acpica/dsobject.c
index a1e7e6b6fcf7..8a7b07b6adc8 100644
--- a/drivers/acpi/acpica/dsobject.c
+++ b/drivers/acpi/acpica/dsobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
index 6c0759c0db47..77244182ff02 100644
--- a/drivers/acpi/acpica/dsopcode.c
+++ b/drivers/acpi/acpica/dsopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dsutils.c b/drivers/acpi/acpica/dsutils.c
index 9f74795e2268..e5ff89bcb3f5 100644
--- a/drivers/acpi/acpica/dsutils.c
+++ b/drivers/acpi/acpica/dsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswexec.c b/drivers/acpi/acpica/dswexec.c
index f7f5107e754d..df54d46225cd 100644
--- a/drivers/acpi/acpica/dswexec.c
+++ b/drivers/acpi/acpica/dswexec.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswload.c b/drivers/acpi/acpica/dswload.c
index 15623da26200..843942fb4be5 100644
--- a/drivers/acpi/acpica/dswload.c
+++ b/drivers/acpi/acpica/dswload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswload2.c b/drivers/acpi/acpica/dswload2.c
index 2ac28d297305..fcaa30c611fb 100644
--- a/drivers/acpi/acpica/dswload2.c
+++ b/drivers/acpi/acpica/dswload2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswscope.c b/drivers/acpi/acpica/dswscope.c
index 9d6e2c1de1f8..43b3ea40c0b6 100644
--- a/drivers/acpi/acpica/dswscope.c
+++ b/drivers/acpi/acpica/dswscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/dswstate.c b/drivers/acpi/acpica/dswstate.c
index 24f7d5ea678a..89ac2022465e 100644
--- a/drivers/acpi/acpica/dswstate.c
+++ b/drivers/acpi/acpica/dswstate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evevent.c b/drivers/acpi/acpica/evevent.c
index c7bffff9ed32..bf6873f95e72 100644
--- a/drivers/acpi/acpica/evevent.c
+++ b/drivers/acpi/acpica/evevent.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evglock.c b/drivers/acpi/acpica/evglock.c
index 3393a73ca0d6..b78dc7c6d5d7 100644
--- a/drivers/acpi/acpica/evglock.c
+++ b/drivers/acpi/acpica/evglock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index aa70154cf4fa..5ed064e8673c 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -114,17 +114,6 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
ACPI_FUNCTION_TRACE(ev_enable_gpe);
- /*
- * We will only allow a GPE to be enabled if it has either an associated
- * method (_Lxx/_Exx) or a handler, or is using the implicit notify
- * feature. Otherwise, the GPE will be immediately disabled by
- * acpi_ev_gpe_dispatch the first time it fires.
- */
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_NONE) {
- return_ACPI_STATUS(AE_NO_HANDLER);
- }
-
/* Clear the GPE (of stale events) */
status = acpi_hw_clear_gpe(gpe_event_info);
@@ -339,7 +328,11 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
{
acpi_status status;
struct acpi_gpe_block_info *gpe_block;
+ struct acpi_namespace_node *gpe_device;
struct acpi_gpe_register_info *gpe_register_info;
+ struct acpi_gpe_event_info *gpe_event_info;
+ u32 gpe_number;
+ struct acpi_gpe_handler_info *gpe_handler_info;
u32 int_status = ACPI_INTERRUPT_NOT_HANDLED;
u8 enabled_status_byte;
u32 status_reg;
@@ -367,6 +360,8 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
gpe_block = gpe_xrupt_list->gpe_block_list_head;
while (gpe_block) {
+ gpe_device = gpe_block->node;
+
/*
* Read all of the 8-bit GPE status and enable registers in this GPE
* block, saving all of them. Find all currently active GP events.
@@ -442,16 +437,68 @@ u32 acpi_ev_gpe_detect(struct acpi_gpe_xrupt_info *gpe_xrupt_list)
/* Examine one GPE bit */
+ gpe_event_info =
+ &gpe_block->
+ event_info[((acpi_size) i *
+ ACPI_GPE_REGISTER_WIDTH) + j];
+ gpe_number =
+ j + gpe_register_info->base_gpe_number;
+
if (enabled_status_byte & (1 << j)) {
- /*
- * Found an active GPE. Dispatch the event to a handler
- * or method.
- */
- int_status |=
- acpi_ev_gpe_dispatch(gpe_block->
- node,
- &gpe_block->
- event_info[((acpi_size) i * ACPI_GPE_REGISTER_WIDTH) + j], j + gpe_register_info->base_gpe_number);
+
+ /* Invoke global event handler if present */
+
+ acpi_gpe_count++;
+ if (acpi_gbl_global_event_handler) {
+ acpi_gbl_global_event_handler
+ (ACPI_EVENT_TYPE_GPE,
+ gpe_device, gpe_number,
+ acpi_gbl_global_event_handler_context);
+ }
+
+ /* Found an active GPE */
+
+ if (ACPI_GPE_DISPATCH_TYPE
+ (gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_RAW_HANDLER) {
+
+ /* Dispatch the event to a raw handler */
+
+ gpe_handler_info =
+ gpe_event_info->dispatch.
+ handler;
+
+ /*
+ * There is no protection around the namespace node
+ * and the GPE handler to ensure a safe destruction
+ * because:
+ * 1. The namespace node is expected to always
+ * exist after loading a table.
+ * 2. The GPE handler is expected to be flushed by
+ * acpi_os_wait_events_complete() before the
+ * destruction.
+ */
+ acpi_os_release_lock
+ (acpi_gbl_gpe_lock, flags);
+ int_status |=
+ gpe_handler_info->
+ address(gpe_device,
+ gpe_number,
+ gpe_handler_info->
+ context);
+ flags =
+ acpi_os_acquire_lock
+ (acpi_gbl_gpe_lock);
+ } else {
+ /*
+ * Dispatch the event to a standard handler or
+ * method.
+ */
+ int_status |=
+ acpi_ev_gpe_dispatch
+ (gpe_device, gpe_event_info,
+ gpe_number);
+ }
}
}
}
@@ -484,52 +531,15 @@ unlock_and_exit:
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
- acpi_status status;
- struct acpi_gpe_event_info *local_gpe_event_info;
+ acpi_status status = AE_OK;
struct acpi_evaluate_info *info;
struct acpi_gpe_notify_info *notify;
ACPI_FUNCTION_TRACE(ev_asynch_execute_gpe_method);
- /* Allocate a local GPE block */
-
- local_gpe_event_info =
- ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_gpe_event_info));
- if (!local_gpe_event_info) {
- ACPI_EXCEPTION((AE_INFO, AE_NO_MEMORY, "while handling a GPE"));
- return_VOID;
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(local_gpe_event_info);
- return_VOID;
- }
-
- /* Must revalidate the gpe_number/gpe_block */
-
- if (!acpi_ev_valid_gpe_event(gpe_event_info)) {
- status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
- ACPI_FREE(local_gpe_event_info);
- return_VOID;
- }
-
- /*
- * Take a snapshot of the GPE info for this level - we copy the info to
- * prevent a race condition with remove_handler/remove_block.
- */
- ACPI_MEMCPY(local_gpe_event_info, gpe_event_info,
- sizeof(struct acpi_gpe_event_info));
-
- status = acpi_ut_release_mutex(ACPI_MTX_EVENTS);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(local_gpe_event_info);
- return_VOID;
- }
-
/* Do the correct dispatch - normal method or implicit notify */
- switch (local_gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
+ switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) {
case ACPI_GPE_DISPATCH_NOTIFY:
/*
* Implicit notify.
@@ -542,7 +552,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* June 2012: Expand implicit notify mechanism to support
* notifies on multiple device objects.
*/
- notify = local_gpe_event_info->dispatch.notify_list;
+ notify = gpe_event_info->dispatch.notify_list;
while (ACPI_SUCCESS(status) && notify) {
status =
acpi_ev_queue_notify_request(notify->device_node,
@@ -566,7 +576,7 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
* _Lxx/_Exx control method that corresponds to this GPE
*/
info->prefix_node =
- local_gpe_event_info->dispatch.method_node;
+ gpe_event_info->dispatch.method_node;
info->flags = ACPI_IGNORE_RETURN_VALUE;
status = acpi_ns_evaluate(info);
@@ -576,25 +586,27 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
if (ACPI_FAILURE(status)) {
ACPI_EXCEPTION((AE_INFO, status,
"while evaluating GPE method [%4.4s]",
- acpi_ut_get_node_name
- (local_gpe_event_info->dispatch.
- method_node)));
+ acpi_ut_get_node_name(gpe_event_info->
+ dispatch.
+ method_node)));
}
break;
default:
- return_VOID; /* Should never happen */
+ goto error_exit; /* Should never happen */
}
/* Defer enabling of GPE until all notify handlers are done */
status = acpi_os_execute(OSL_NOTIFY_HANDLER,
- acpi_ev_asynch_enable_gpe,
- local_gpe_event_info);
- if (ACPI_FAILURE(status)) {
- ACPI_FREE(local_gpe_event_info);
+ acpi_ev_asynch_enable_gpe, gpe_event_info);
+ if (ACPI_SUCCESS(status)) {
+ return_VOID;
}
+
+error_exit:
+ acpi_ev_asynch_enable_gpe(gpe_event_info);
return_VOID;
}
@@ -622,7 +634,6 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
(void)acpi_ev_finish_gpe(gpe_event_info);
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
- ACPI_FREE(gpe_event_info);
return;
}
@@ -692,15 +703,6 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
ACPI_FUNCTION_TRACE(ev_gpe_dispatch);
- /* Invoke global event handler if present */
-
- acpi_gpe_count++;
- if (acpi_gbl_global_event_handler) {
- acpi_gbl_global_event_handler(ACPI_EVENT_TYPE_GPE, gpe_device,
- gpe_number,
- acpi_gbl_global_event_handler_context);
- }
-
/*
* Always disable the GPE so that it does not keep firing before
* any asynchronous activity completes (either from the execution
@@ -741,7 +743,7 @@ acpi_ev_gpe_dispatch(struct acpi_namespace_node *gpe_device,
* If there is neither a handler nor a method, leave the GPE
* disabled.
*/
- switch (gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) {
+ switch (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)) {
case ACPI_GPE_DISPATCH_HANDLER:
/* Invoke the installed handler (at interrupt level) */
diff --git a/drivers/acpi/acpica/evgpeblk.c b/drivers/acpi/acpica/evgpeblk.c
index d86699eea33c..e0f24c504513 100644
--- a/drivers/acpi/acpica/evgpeblk.c
+++ b/drivers/acpi/acpica/evgpeblk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -474,10 +474,12 @@ acpi_ev_initialize_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
* Ignore GPEs that have no corresponding _Lxx/_Exx method
* and GPEs that are used to wake the system
*/
- if (((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_NONE)
- || ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK)
- == ACPI_GPE_DISPATCH_HANDLER)
+ || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_HANDLER)
+ || (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_RAW_HANDLER)
|| (gpe_event_info->flags & ACPI_GPE_CAN_WAKE)) {
continue;
}
diff --git a/drivers/acpi/acpica/evgpeinit.c b/drivers/acpi/acpica/evgpeinit.c
index 7be928379879..8840296d5b20 100644
--- a/drivers/acpi/acpica/evgpeinit.c
+++ b/drivers/acpi/acpica/evgpeinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -401,15 +401,17 @@ acpi_ev_match_gpe_method(acpi_handle obj_handle,
return_ACPI_STATUS(AE_OK);
}
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_HANDLER) {
+ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_HANDLER) ||
+ (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_RAW_HANDLER)) {
/* If there is already a handler, ignore this GPE method */
return_ACPI_STATUS(AE_OK);
}
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_METHOD) {
/*
* If there is already a method, ignore this method. But check
diff --git a/drivers/acpi/acpica/evgpeutil.c b/drivers/acpi/acpica/evgpeutil.c
index 17e4bbfdb096..3a958f3612fe 100644
--- a/drivers/acpi/acpica/evgpeutil.c
+++ b/drivers/acpi/acpica/evgpeutil.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -108,53 +108,6 @@ unlock_and_exit:
/*******************************************************************************
*
- * FUNCTION: acpi_ev_valid_gpe_event
- *
- * PARAMETERS: gpe_event_info - Info for this GPE
- *
- * RETURN: TRUE if the gpe_event is valid
- *
- * DESCRIPTION: Validate a GPE event. DO NOT CALL FROM INTERRUPT LEVEL.
- * Should be called only when the GPE lists are semaphore locked
- * and not subject to change.
- *
- ******************************************************************************/
-
-u8 acpi_ev_valid_gpe_event(struct acpi_gpe_event_info *gpe_event_info)
-{
- struct acpi_gpe_xrupt_info *gpe_xrupt_block;
- struct acpi_gpe_block_info *gpe_block;
-
- ACPI_FUNCTION_ENTRY();
-
- /* No need for spin lock since we are not changing any list elements */
-
- /* Walk the GPE interrupt levels */
-
- gpe_xrupt_block = acpi_gbl_gpe_xrupt_list_head;
- while (gpe_xrupt_block) {
- gpe_block = gpe_xrupt_block->gpe_block_list_head;
-
- /* Walk the GPE blocks on this interrupt level */
-
- while (gpe_block) {
- if ((&gpe_block->event_info[0] <= gpe_event_info) &&
- (&gpe_block->event_info[gpe_block->gpe_count] >
- gpe_event_info)) {
- return (TRUE);
- }
-
- gpe_block = gpe_block->next;
- }
-
- gpe_xrupt_block = gpe_xrupt_block->next;
- }
-
- return (FALSE);
-}
-
-/*******************************************************************************
- *
* FUNCTION: acpi_ev_get_gpe_device
*
* PARAMETERS: GPE_WALK_CALLBACK
@@ -371,8 +324,10 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
ACPI_GPE_REGISTER_WIDTH)
+ j];
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_HANDLER) {
+ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_HANDLER) ||
+ (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_RAW_HANDLER)) {
/* Delete an installed handler block */
@@ -380,10 +335,8 @@ acpi_ev_delete_gpe_handlers(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
gpe_event_info->dispatch.handler = NULL;
gpe_event_info->flags &=
~ACPI_GPE_DISPATCH_MASK;
- } else
- if ((gpe_event_info->
- flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_NOTIFY) {
+ } else if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags)
+ == ACPI_GPE_DISPATCH_NOTIFY) {
/* Delete the implicit notification device list */
diff --git a/drivers/acpi/acpica/evhandler.c b/drivers/acpi/acpica/evhandler.c
index 78ac29351c9e..74e8595f5a2b 100644
--- a/drivers/acpi/acpica/evhandler.c
+++ b/drivers/acpi/acpica/evhandler.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evmisc.c b/drivers/acpi/acpica/evmisc.c
index 24ea3424981b..f7c9dfe7b990 100644
--- a/drivers/acpi/acpica/evmisc.c
+++ b/drivers/acpi/acpica/evmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evregion.c b/drivers/acpi/acpica/evregion.c
index 8eb8575e8c16..9abace3401f9 100644
--- a/drivers/acpi/acpica/evregion.c
+++ b/drivers/acpi/acpica/evregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evrgnini.c b/drivers/acpi/acpica/evrgnini.c
index 1b148a440d67..da323390bb70 100644
--- a/drivers/acpi/acpica/evrgnini.c
+++ b/drivers/acpi/acpica/evrgnini.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evsci.c b/drivers/acpi/acpica/evsci.c
index 29630e303829..0366703d2970 100644
--- a/drivers/acpi/acpica/evsci.c
+++ b/drivers/acpi/acpica/evsci.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxface.c b/drivers/acpi/acpica/evxface.c
index 55a58f3ec8df..81f2d9e87fad 100644
--- a/drivers/acpi/acpica/evxface.c
+++ b/drivers/acpi/acpica/evxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -51,6 +51,16 @@
#define _COMPONENT ACPI_EVENTS
ACPI_MODULE_NAME("evxface")
+#if (!ACPI_REDUCED_HARDWARE)
+/* Local prototypes */
+static acpi_status
+acpi_ev_install_gpe_handler(acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 type,
+ u8 is_raw_handler,
+ acpi_gpe_handler address, void *context);
+
+#endif
/*******************************************************************************
@@ -76,6 +86,7 @@ ACPI_MODULE_NAME("evxface")
* handlers.
*
******************************************************************************/
+
acpi_status
acpi_install_notify_handler(acpi_handle device,
u32 handler_type,
@@ -717,32 +728,37 @@ ACPI_EXPORT_SYMBOL(acpi_remove_fixed_event_handler)
/*******************************************************************************
*
- * FUNCTION: acpi_install_gpe_handler
+ * FUNCTION: acpi_ev_install_gpe_handler
*
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
* defined GPEs)
* gpe_number - The GPE number within the GPE block
* type - Whether this GPE should be treated as an
* edge- or level-triggered interrupt.
+ * is_raw_handler - Whether this GPE should be handled using
+ * the special GPE handler mode.
* address - Address of the handler
* context - Value passed to the handler on each GPE
*
* RETURN: Status
*
- * DESCRIPTION: Install a handler for a General Purpose Event.
+ * DESCRIPTION: Internal function to install a handler for a General Purpose
+ * Event.
*
******************************************************************************/
-acpi_status
-acpi_install_gpe_handler(acpi_handle gpe_device,
- u32 gpe_number,
- u32 type, acpi_gpe_handler address, void *context)
+static acpi_status
+acpi_ev_install_gpe_handler(acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 type,
+ u8 is_raw_handler,
+ acpi_gpe_handler address, void *context)
{
struct acpi_gpe_event_info *gpe_event_info;
struct acpi_gpe_handler_info *handler;
acpi_status status;
acpi_cpu_flags flags;
- ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
+ ACPI_FUNCTION_TRACE(ev_install_gpe_handler);
/* Parameter validation */
@@ -775,8 +791,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
/* Make sure that there isn't a handler there already */
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
- ACPI_GPE_DISPATCH_HANDLER) {
+ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_HANDLER) ||
+ (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
+ ACPI_GPE_DISPATCH_RAW_HANDLER)) {
status = AE_ALREADY_EXISTS;
goto free_and_exit;
}
@@ -793,9 +811,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
* automatically during initialization, in which case it has to be
* disabled now to avoid spurious execution of the handler.
*/
- if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
- (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
- gpe_event_info->runtime_count) {
+ if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
+ ACPI_GPE_DISPATCH_METHOD) ||
+ (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
+ ACPI_GPE_DISPATCH_NOTIFY)) && gpe_event_info->runtime_count) {
handler->originally_enabled = TRUE;
(void)acpi_ev_remove_gpe_reference(gpe_event_info);
@@ -816,7 +835,10 @@ acpi_install_gpe_handler(acpi_handle gpe_device,
gpe_event_info->flags &=
~(ACPI_GPE_XRUPT_TYPE_MASK | ACPI_GPE_DISPATCH_MASK);
- gpe_event_info->flags |= (u8)(type | ACPI_GPE_DISPATCH_HANDLER);
+ gpe_event_info->flags |=
+ (u8)(type |
+ (is_raw_handler ? ACPI_GPE_DISPATCH_RAW_HANDLER :
+ ACPI_GPE_DISPATCH_HANDLER));
acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
@@ -830,10 +852,78 @@ free_and_exit:
goto unlock_and_exit;
}
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_install_gpe_handler
+ *
+ * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
+ * defined GPEs)
+ * gpe_number - The GPE number within the GPE block
+ * type - Whether this GPE should be treated as an
+ * edge- or level-triggered interrupt.
+ * address - Address of the handler
+ * context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for a General Purpose Event.
+ *
+ ******************************************************************************/
+
+acpi_status
+acpi_install_gpe_handler(acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 type, acpi_gpe_handler address, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_gpe_handler);
+
+ status =
+ acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, FALSE,
+ address, context);
+
+ return_ACPI_STATUS(status);
+}
+
ACPI_EXPORT_SYMBOL(acpi_install_gpe_handler)
/*******************************************************************************
*
+ * FUNCTION: acpi_install_gpe_raw_handler
+ *
+ * PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
+ * defined GPEs)
+ * gpe_number - The GPE number within the GPE block
+ * type - Whether this GPE should be treated as an
+ * edge- or level-triggered interrupt.
+ * address - Address of the handler
+ * context - Value passed to the handler on each GPE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Install a handler for a General Purpose Event.
+ *
+ ******************************************************************************/
+acpi_status
+acpi_install_gpe_raw_handler(acpi_handle gpe_device,
+ u32 gpe_number,
+ u32 type, acpi_gpe_handler address, void *context)
+{
+ acpi_status status;
+
+ ACPI_FUNCTION_TRACE(acpi_install_gpe_raw_handler);
+
+ status = acpi_ev_install_gpe_handler(gpe_device, gpe_number, type, TRUE,
+ address, context);
+
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_install_gpe_raw_handler)
+
+/*******************************************************************************
+ *
* FUNCTION: acpi_remove_gpe_handler
*
* PARAMETERS: gpe_device - Namespace node for the GPE (NULL for FADT
@@ -880,8 +970,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
/* Make sure that a handler is indeed installed */
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
- ACPI_GPE_DISPATCH_HANDLER) {
+ if ((ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
+ ACPI_GPE_DISPATCH_HANDLER) &&
+ (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
+ ACPI_GPE_DISPATCH_RAW_HANDLER)) {
status = AE_NOT_EXIST;
goto unlock_and_exit;
}
@@ -896,6 +988,7 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
/* Remove the handler */
handler = gpe_event_info->dispatch.handler;
+ gpe_event_info->dispatch.handler = NULL;
/* Restore Method node (if any), set dispatch flags */
@@ -909,9 +1002,10 @@ acpi_remove_gpe_handler(acpi_handle gpe_device,
* enabled, it should be enabled at this point to restore the
* post-initialization configuration.
*/
- if (((handler->original_flags & ACPI_GPE_DISPATCH_METHOD) ||
- (handler->original_flags & ACPI_GPE_DISPATCH_NOTIFY)) &&
- handler->originally_enabled) {
+ if (((ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
+ ACPI_GPE_DISPATCH_METHOD) ||
+ (ACPI_GPE_DISPATCH_TYPE(handler->original_flags) ==
+ ACPI_GPE_DISPATCH_NOTIFY)) && handler->originally_enabled) {
(void)acpi_ev_add_gpe_reference(gpe_event_info);
}
diff --git a/drivers/acpi/acpica/evxfevnt.c b/drivers/acpi/acpica/evxfevnt.c
index bb8cbf5961bf..df06a23c4197 100644
--- a/drivers/acpi/acpica/evxfevnt.c
+++ b/drivers/acpi/acpica/evxfevnt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/evxfgpe.c b/drivers/acpi/acpica/evxfgpe.c
index e889a5304abd..70eb47e3d724 100644
--- a/drivers/acpi/acpica/evxfgpe.c
+++ b/drivers/acpi/acpica/evxfgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -132,7 +132,7 @@ acpi_status acpi_enable_gpe(acpi_handle gpe_device, u32 gpe_number)
*/
gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
if (gpe_event_info) {
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
+ if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_NONE) {
status = acpi_ev_add_gpe_reference(gpe_event_info);
} else {
@@ -183,6 +183,77 @@ acpi_status acpi_disable_gpe(acpi_handle gpe_device, u32 gpe_number)
ACPI_EXPORT_SYMBOL(acpi_disable_gpe)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_set_gpe
+ *
+ * PARAMETERS: gpe_device - Parent GPE Device. NULL for GPE0/GPE1
+ * gpe_number - GPE level within the GPE block
+ * action - ACPI_GPE_ENABLE or ACPI_GPE_DISABLE
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Enable or disable an individual GPE. This function bypasses
+ * the reference count mechanism used in the acpi_enable_gpe(),
+ * acpi_disable_gpe() interfaces.
+ * This API is typically used by the GPE raw handler mode driver
+ * to switch between the polling mode and the interrupt mode after
+ * the driver has enabled the GPE.
+ * The APIs should be invoked in this order:
+ * acpi_enable_gpe() <- Ensure the reference count > 0
+ * acpi_set_gpe(ACPI_GPE_DISABLE) <- Enter polling mode
+ * acpi_set_gpe(ACPI_GPE_ENABLE) <- Leave polling mode
+ * acpi_disable_gpe() <- Decrease the reference count
+ *
+ * Note: If a GPE is shared by 2 silicon components, then both the drivers
+ * should support GPE polling mode or disabling the GPE for long period
+ * for one driver may break the other. So use it with care since all
+ * firmware _Lxx/_Exx handlers currently rely on the GPE interrupt mode.
+ *
+ ******************************************************************************/
+acpi_status acpi_set_gpe(acpi_handle gpe_device, u32 gpe_number, u8 action)
+{
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_status status;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_set_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ /* Perform the action */
+
+ switch (action) {
+ case ACPI_GPE_ENABLE:
+
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+ break;
+
+ case ACPI_GPE_DISABLE:
+
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_DISABLE);
+ break;
+
+ default:
+
+ status = AE_BAD_PARAMETER;
+ break;
+ }
+
+unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_set_gpe)
/*******************************************************************************
*
@@ -313,7 +384,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
* known as an "implicit notify". Note: The GPE is assumed to be
* level-triggered (for windows compatibility).
*/
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_NONE) {
/*
* This is the first device for implicit notify on this GPE.
@@ -327,7 +398,7 @@ acpi_setup_gpe_for_wake(acpi_handle wake_device,
* If we already have an implicit notify on this GPE, add
* this device to the notify list.
*/
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) ==
+ if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) ==
ACPI_GPE_DISPATCH_NOTIFY) {
/* Ensure that the device is not already in the list */
@@ -530,6 +601,49 @@ unlock_and_exit:
ACPI_EXPORT_SYMBOL(acpi_get_gpe_status)
+/*******************************************************************************
+ *
+ * FUNCTION: acpi_finish_gpe
+ *
+ * PARAMETERS: gpe_device - Namespace node for the GPE Block
+ * (NULL for FADT defined GPEs)
+ * gpe_number - GPE level within the GPE block
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Clear and conditionally reenable a GPE. This completes the GPE
+ * processing. Intended for use by asynchronous host-installed
+ * GPE handlers. The GPE is only reenabled if the enable_for_run bit
+ * is set in the GPE info.
+ *
+ ******************************************************************************/
+acpi_status acpi_finish_gpe(acpi_handle gpe_device, u32 gpe_number)
+{
+ struct acpi_gpe_event_info *gpe_event_info;
+ acpi_status status;
+ acpi_cpu_flags flags;
+
+ ACPI_FUNCTION_TRACE(acpi_finish_gpe);
+
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
+
+ /* Ensure that we have a valid GPE number */
+
+ gpe_event_info = acpi_ev_get_gpe_event_info(gpe_device, gpe_number);
+ if (!gpe_event_info) {
+ status = AE_BAD_PARAMETER;
+ goto unlock_and_exit;
+ }
+
+ status = acpi_ev_finish_gpe(gpe_event_info);
+
+unlock_and_exit:
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
+ return_ACPI_STATUS(status);
+}
+
+ACPI_EXPORT_SYMBOL(acpi_finish_gpe)
+
/******************************************************************************
*
* FUNCTION: acpi_disable_all_gpes
@@ -604,7 +718,6 @@ ACPI_EXPORT_SYMBOL(acpi_enable_all_runtime_gpes)
* all GPE blocks.
*
******************************************************************************/
-
acpi_status acpi_enable_all_wakeup_gpes(void)
{
acpi_status status;
diff --git a/drivers/acpi/acpica/evxfregn.c b/drivers/acpi/acpica/evxfregn.c
index 2d6f187939c7..f21afbab03f7 100644
--- a/drivers/acpi/acpica/evxfregn.c
+++ b/drivers/acpi/acpica/evxfregn.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconfig.c b/drivers/acpi/acpica/exconfig.c
index 7d2949420db7..6e0df2b9d5a4 100644
--- a/drivers/acpi/acpica/exconfig.c
+++ b/drivers/acpi/acpica/exconfig.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exconvrt.c b/drivers/acpi/acpica/exconvrt.c
index c545386fee96..89a976b4ccf2 100644
--- a/drivers/acpi/acpica/exconvrt.c
+++ b/drivers/acpi/acpica/exconvrt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/excreate.c b/drivers/acpi/acpica/excreate.c
index 95d23dabcfbb..aaeea4840aaa 100644
--- a/drivers/acpi/acpica/excreate.c
+++ b/drivers/acpi/acpica/excreate.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdebug.c b/drivers/acpi/acpica/exdebug.c
index 6fbfad47518c..e67d0aca3fe6 100644
--- a/drivers/acpi/acpica/exdebug.c
+++ b/drivers/acpi/acpica/exdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exdump.c b/drivers/acpi/acpica/exdump.c
index 0f23c3f2678e..7c213b6b6472 100644
--- a/drivers/acpi/acpica/exdump.c
+++ b/drivers/acpi/acpica/exdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfield.c b/drivers/acpi/acpica/exfield.c
index b994845ed359..c161dd974f74 100644
--- a/drivers/acpi/acpica/exfield.c
+++ b/drivers/acpi/acpica/exfield.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exfldio.c b/drivers/acpi/acpica/exfldio.c
index 1d1b27a96c5b..49479927e7f7 100644
--- a/drivers/acpi/acpica/exfldio.c
+++ b/drivers/acpi/acpica/exfldio.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmisc.c b/drivers/acpi/acpica/exmisc.c
index 2207e624f538..b56fc9d6f48e 100644
--- a/drivers/acpi/acpica/exmisc.c
+++ b/drivers/acpi/acpica/exmisc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exmutex.c b/drivers/acpi/acpica/exmutex.c
index b49ea2a95f4f..472030f2b5bb 100644
--- a/drivers/acpi/acpica/exmutex.c
+++ b/drivers/acpi/acpica/exmutex.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exnames.c b/drivers/acpi/acpica/exnames.c
index dbb03b544e8c..453b00c30177 100644
--- a/drivers/acpi/acpica/exnames.c
+++ b/drivers/acpi/acpica/exnames.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg1.c b/drivers/acpi/acpica/exoparg1.c
index 1b8e94104407..77930683ab7d 100644
--- a/drivers/acpi/acpica/exoparg1.c
+++ b/drivers/acpi/acpica/exoparg1.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg2.c b/drivers/acpi/acpica/exoparg2.c
index 2ede656ee26a..fcc618aa2061 100644
--- a/drivers/acpi/acpica/exoparg2.c
+++ b/drivers/acpi/acpica/exoparg2.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg3.c b/drivers/acpi/acpica/exoparg3.c
index 363767cf01e5..b813fed95e56 100644
--- a/drivers/acpi/acpica/exoparg3.c
+++ b/drivers/acpi/acpica/exoparg3.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exoparg6.c b/drivers/acpi/acpica/exoparg6.c
index 29e9e99f7fe3..c930edda3f65 100644
--- a/drivers/acpi/acpica/exoparg6.c
+++ b/drivers/acpi/acpica/exoparg6.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exprep.c b/drivers/acpi/acpica/exprep.c
index 118e942005e5..4c2836dc825b 100644
--- a/drivers/acpi/acpica/exprep.c
+++ b/drivers/acpi/acpica/exprep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exregion.c b/drivers/acpi/acpica/exregion.c
index cd5288a257a9..0fe188e238ef 100644
--- a/drivers/acpi/acpica/exregion.c
+++ b/drivers/acpi/acpica/exregion.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresnte.c b/drivers/acpi/acpica/exresnte.c
index ab060261b43e..c7e3b929aa85 100644
--- a/drivers/acpi/acpica/exresnte.c
+++ b/drivers/acpi/acpica/exresnte.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresolv.c b/drivers/acpi/acpica/exresolv.c
index 3cde553bcbe1..b6b7f3af29e4 100644
--- a/drivers/acpi/acpica/exresolv.c
+++ b/drivers/acpi/acpica/exresolv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exresop.c b/drivers/acpi/acpica/exresop.c
index 3af8de3fcea4..d2964af9ad4d 100644
--- a/drivers/acpi/acpica/exresop.c
+++ b/drivers/acpi/acpica/exresop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstore.c b/drivers/acpi/acpica/exstore.c
index daf49f7ea311..a7eee2400ce0 100644
--- a/drivers/acpi/acpica/exstore.c
+++ b/drivers/acpi/acpica/exstore.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstoren.c b/drivers/acpi/acpica/exstoren.c
index 04bd16c08f9e..3101607b4efe 100644
--- a/drivers/acpi/acpica/exstoren.c
+++ b/drivers/acpi/acpica/exstoren.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exstorob.c b/drivers/acpi/acpica/exstorob.c
index fd11018b0168..6fa3c8d8fc5f 100644
--- a/drivers/acpi/acpica/exstorob.c
+++ b/drivers/acpi/acpica/exstorob.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exsystem.c b/drivers/acpi/acpica/exsystem.c
index f7da64123ed5..05450656fe3d 100644
--- a/drivers/acpi/acpica/exsystem.c
+++ b/drivers/acpi/acpica/exsystem.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/exutils.c b/drivers/acpi/acpica/exutils.c
index d9d72dff2a76..3f4225e95d93 100644
--- a/drivers/acpi/acpica/exutils.c
+++ b/drivers/acpi/acpica/exutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwacpi.c b/drivers/acpi/acpica/hwacpi.c
index 1e66d960fc11..e5c5949f9081 100644
--- a/drivers/acpi/acpica/hwacpi.c
+++ b/drivers/acpi/acpica/hwacpi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwesleep.c b/drivers/acpi/acpica/hwesleep.c
index 858fdd6be598..e5599f610808 100644
--- a/drivers/acpi/acpica/hwesleep.c
+++ b/drivers/acpi/acpica/hwesleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 494027f5c067..84bc550f4f1d 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -54,6 +54,10 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
struct acpi_gpe_block_info *gpe_block,
void *context);
+static acpi_status
+acpi_hw_gpe_enable_write(u8 enable_mask,
+ struct acpi_gpe_register_info *gpe_register_info);
+
/******************************************************************************
*
* FUNCTION: acpi_hw_get_gpe_register_bit
@@ -146,7 +150,7 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
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;
+ gpe_register_info->enable_mask = (u8)enable_mask;
}
return (status);
}
@@ -221,7 +225,7 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/* GPE currently handled? */
- if ((gpe_event_info->flags & ACPI_GPE_DISPATCH_MASK) !=
+ if (ACPI_GPE_DISPATCH_TYPE(gpe_event_info->flags) !=
ACPI_GPE_DISPATCH_NONE) {
local_event_status |= ACPI_EVENT_FLAG_HAS_HANDLER;
}
diff --git a/drivers/acpi/acpica/hwpci.c b/drivers/acpi/acpica/hwpci.c
index 6aade8e1d2a1..c5214dec4988 100644
--- a/drivers/acpi/acpica/hwpci.c
+++ b/drivers/acpi/acpica/hwpci.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwregs.c b/drivers/acpi/acpica/hwregs.c
index a4c34d2c556b..3cf77afd142c 100644
--- a/drivers/acpi/acpica/hwregs.c
+++ b/drivers/acpi/acpica/hwregs.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwsleep.c b/drivers/acpi/acpica/hwsleep.c
index d590693eb54e..7d21cae6d602 100644
--- a/drivers/acpi/acpica/hwsleep.c
+++ b/drivers/acpi/acpica/hwsleep.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwtimer.c b/drivers/acpi/acpica/hwtimer.c
index 76ab5c1a814e..675c709a300b 100644
--- a/drivers/acpi/acpica/hwtimer.c
+++ b/drivers/acpi/acpica/hwtimer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwvalid.c b/drivers/acpi/acpica/hwvalid.c
index 6b919127cd9d..2bd33fe56cb3 100644
--- a/drivers/acpi/acpica/hwvalid.c
+++ b/drivers/acpi/acpica/hwvalid.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxface.c b/drivers/acpi/acpica/hwxface.c
index 96d007df65ec..5f97468df8ff 100644
--- a/drivers/acpi/acpica/hwxface.c
+++ b/drivers/acpi/acpica/hwxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/hwxfsleep.c b/drivers/acpi/acpica/hwxfsleep.c
index 6921c7f3d208..3b3767698827 100644
--- a/drivers/acpi/acpica/hwxfsleep.c
+++ b/drivers/acpi/acpica/hwxfsleep.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsaccess.c b/drivers/acpi/acpica/nsaccess.c
index f1249e3463be..24fa19a76d70 100644
--- a/drivers/acpi/acpica/nsaccess.c
+++ b/drivers/acpi/acpica/nsaccess.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsalloc.c b/drivers/acpi/acpica/nsalloc.c
index 607eb9e5150d..e107f929d9cf 100644
--- a/drivers/acpi/acpica/nsalloc.c
+++ b/drivers/acpi/acpica/nsalloc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsarguments.c b/drivers/acpi/acpica/nsarguments.c
index 80fcfc8c9c1b..5d347a71bd0b 100644
--- a/drivers/acpi/acpica/nsarguments.c
+++ b/drivers/acpi/acpica/nsarguments.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsconvert.c b/drivers/acpi/acpica/nsconvert.c
index b55642c4ee58..1a8b39c8d969 100644
--- a/drivers/acpi/acpica/nsconvert.c
+++ b/drivers/acpi/acpica/nsconvert.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdump.c b/drivers/acpi/acpica/nsdump.c
index 3d88ef4a3e0d..80f097eb7381 100644
--- a/drivers/acpi/acpica/nsdump.c
+++ b/drivers/acpi/acpica/nsdump.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsdumpdv.c b/drivers/acpi/acpica/nsdumpdv.c
index 42d37109aa5d..7dc367e6fe09 100644
--- a/drivers/acpi/acpica/nsdumpdv.c
+++ b/drivers/acpi/acpica/nsdumpdv.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nseval.c b/drivers/acpi/acpica/nseval.c
index e634a05974db..7bcc68f57afa 100644
--- a/drivers/acpi/acpica/nseval.c
+++ b/drivers/acpi/acpica/nseval.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsinit.c b/drivers/acpi/acpica/nsinit.c
index a3fb7e4c0809..4a85c4517988 100644
--- a/drivers/acpi/acpica/nsinit.c
+++ b/drivers/acpi/acpica/nsinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsload.c b/drivers/acpi/acpica/nsload.c
index 7c9d0181f341..bd6cd4a81316 100644
--- a/drivers/acpi/acpica/nsload.c
+++ b/drivers/acpi/acpica/nsload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsnames.c b/drivers/acpi/acpica/nsnames.c
index 7eee0a6f02f6..d293d9748036 100644
--- a/drivers/acpi/acpica/nsnames.c
+++ b/drivers/acpi/acpica/nsnames.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsobject.c b/drivers/acpi/acpica/nsobject.c
index a42ee9d6970d..677bc9330e64 100644
--- a/drivers/acpi/acpica/nsobject.c
+++ b/drivers/acpi/acpica/nsobject.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsparse.c b/drivers/acpi/acpica/nsparse.c
index e83cff31754b..c95a119767b5 100644
--- a/drivers/acpi/acpica/nsparse.c
+++ b/drivers/acpi/acpica/nsparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nspredef.c b/drivers/acpi/acpica/nspredef.c
index 392910ffbed9..0eb54315b4be 100644
--- a/drivers/acpi/acpica/nspredef.c
+++ b/drivers/acpi/acpica/nspredef.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsprepkg.c b/drivers/acpi/acpica/nsprepkg.c
index 1b13b921dda9..8b79958b7aca 100644
--- a/drivers/acpi/acpica/nsprepkg.c
+++ b/drivers/acpi/acpica/nsprepkg.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsrepair.c b/drivers/acpi/acpica/nsrepair.c
index 7e417aa5c91e..151fcd95ba84 100644
--- a/drivers/acpi/acpica/nsrepair.c
+++ b/drivers/acpi/acpica/nsrepair.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsrepair2.c b/drivers/acpi/acpica/nsrepair2.c
index b09e6bef72b8..c30672d23878 100644
--- a/drivers/acpi/acpica/nsrepair2.c
+++ b/drivers/acpi/acpica/nsrepair2.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nssearch.c b/drivers/acpi/acpica/nssearch.c
index af1cc42a8aa1..4a9d4a66016e 100644
--- a/drivers/acpi/acpica/nssearch.c
+++ b/drivers/acpi/acpica/nssearch.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsutils.c b/drivers/acpi/acpica/nsutils.c
index 4a5e3f5c0ff7..6ad02008c0c2 100644
--- a/drivers/acpi/acpica/nsutils.c
+++ b/drivers/acpi/acpica/nsutils.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nswalk.c b/drivers/acpi/acpica/nswalk.c
index 4758a1f2ce22..c68609a2bc1b 100644
--- a/drivers/acpi/acpica/nswalk.c
+++ b/drivers/acpi/acpica/nswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index 4bd558bf10d2..b6030a2deee1 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfname.c b/drivers/acpi/acpica/nsxfname.c
index 8c6c11ce9760..d66c326485d8 100644
--- a/drivers/acpi/acpica/nsxfname.c
+++ b/drivers/acpi/acpica/nsxfname.c
@@ -6,7 +6,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/nsxfobj.c b/drivers/acpi/acpica/nsxfobj.c
index dae9401be7a2..793383501f81 100644
--- a/drivers/acpi/acpica/nsxfobj.c
+++ b/drivers/acpi/acpica/nsxfobj.c
@@ -6,7 +6,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -53,50 +53,6 @@ ACPI_MODULE_NAME("nsxfobj")
/*******************************************************************************
*
- * FUNCTION: acpi_get_id
- *
- * PARAMETERS: Handle - Handle of object whose id is desired
- * ret_id - Where the id will be placed
- *
- * RETURN: Status
- *
- * DESCRIPTION: This routine returns the owner id associated with a handle
- *
- ******************************************************************************/
-acpi_status acpi_get_id(acpi_handle handle, acpi_owner_id * ret_id)
-{
- struct acpi_namespace_node *node;
- acpi_status status;
-
- /* Parameter Validation */
-
- if (!ret_id) {
- return (AE_BAD_PARAMETER);
- }
-
- status = acpi_ut_acquire_mutex(ACPI_MTX_NAMESPACE);
- if (ACPI_FAILURE(status)) {
- return (status);
- }
-
- /* Convert and validate the handle */
-
- node = acpi_ns_validate_handle(handle);
- if (!node) {
- (void)acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return (AE_BAD_PARAMETER);
- }
-
- *ret_id = node->owner_id;
-
- status = acpi_ut_release_mutex(ACPI_MTX_NAMESPACE);
- return (status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_get_id)
-
-/*******************************************************************************
- *
* FUNCTION: acpi_get_type
*
* PARAMETERS: handle - Handle of object whose type is desired
diff --git a/drivers/acpi/acpica/psargs.c b/drivers/acpi/acpica/psargs.c
index 314d314340ae..6d038770577b 100644
--- a/drivers/acpi/acpica/psargs.c
+++ b/drivers/acpi/acpica/psargs.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psloop.c b/drivers/acpi/acpica/psloop.c
index b058e2390fdd..90437227d790 100644
--- a/drivers/acpi/acpica/psloop.c
+++ b/drivers/acpi/acpica/psloop.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psobject.c b/drivers/acpi/acpica/psobject.c
index a6885077d59e..2f5ddd806c58 100644
--- a/drivers/acpi/acpica/psobject.c
+++ b/drivers/acpi/acpica/psobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psopcode.c b/drivers/acpi/acpica/psopcode.c
index 1755d2ac5656..1af4a405e351 100644
--- a/drivers/acpi/acpica/psopcode.c
+++ b/drivers/acpi/acpica/psopcode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psopinfo.c b/drivers/acpi/acpica/psopinfo.c
index 0d8d37ffd04d..e18e7c47f482 100644
--- a/drivers/acpi/acpica/psopinfo.c
+++ b/drivers/acpi/acpica/psopinfo.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psparse.c b/drivers/acpi/acpica/psparse.c
index 6d27b597394e..a555f7f7b9a2 100644
--- a/drivers/acpi/acpica/psparse.c
+++ b/drivers/acpi/acpica/psparse.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psscope.c b/drivers/acpi/acpica/psscope.c
index 32d250feea21..9d669cc6cb62 100644
--- a/drivers/acpi/acpica/psscope.c
+++ b/drivers/acpi/acpica/psscope.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pstree.c b/drivers/acpi/acpica/pstree.c
index 0b64181e7720..89984f30addc 100644
--- a/drivers/acpi/acpica/pstree.c
+++ b/drivers/acpi/acpica/pstree.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psutils.c b/drivers/acpi/acpica/psutils.c
index 3cd48802eede..960505ab409a 100644
--- a/drivers/acpi/acpica/psutils.c
+++ b/drivers/acpi/acpica/psutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/pswalk.c b/drivers/acpi/acpica/pswalk.c
index 9cb07e1e76d9..ba5f69171288 100644
--- a/drivers/acpi/acpica/pswalk.c
+++ b/drivers/acpi/acpica/pswalk.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/psxface.c b/drivers/acpi/acpica/psxface.c
index e135acaa5e1c..841a5ea06094 100644
--- a/drivers/acpi/acpica/psxface.c
+++ b/drivers/acpi/acpica/psxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsaddr.c b/drivers/acpi/acpica/rsaddr.c
index 916fd095ff34..66d406e8fe36 100644
--- a/drivers/acpi/acpica/rsaddr.c
+++ b/drivers/acpi/acpica/rsaddr.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -74,7 +74,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address16[5] = {
* Address Translation Offset
* Address Length
*/
- {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.granularity),
+ {ACPI_RSC_MOVE16, ACPI_RS_OFFSET(data.address16.address.granularity),
AML_OFFSET(address16.granularity),
5},
@@ -112,7 +112,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address32[5] = {
* Address Translation Offset
* Address Length
*/
- {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.granularity),
+ {ACPI_RSC_MOVE32, ACPI_RS_OFFSET(data.address32.address.granularity),
AML_OFFSET(address32.granularity),
5},
@@ -150,7 +150,7 @@ struct acpi_rsconvert_info acpi_rs_convert_address64[5] = {
* Address Translation Offset
* Address Length
*/
- {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.granularity),
+ {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.address64.address.granularity),
AML_OFFSET(address64.granularity),
5},
@@ -194,7 +194,8 @@ struct acpi_rsconvert_info acpi_rs_convert_ext_address64[5] = {
* Address Length
* Type-Specific Attribute
*/
- {ACPI_RSC_MOVE64, ACPI_RS_OFFSET(data.ext_address64.granularity),
+ {ACPI_RSC_MOVE64,
+ ACPI_RS_OFFSET(data.ext_address64.address.granularity),
AML_OFFSET(ext_address64.granularity),
6}
};
diff --git a/drivers/acpi/acpica/rscalc.c b/drivers/acpi/acpica/rscalc.c
index 689556744b03..cb739a694931 100644
--- a/drivers/acpi/acpica/rscalc.c
+++ b/drivers/acpi/acpica/rscalc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rscreate.c b/drivers/acpi/acpica/rscreate.c
index 049d9c22a0f9..15434e4c9b34 100644
--- a/drivers/acpi/acpica/rscreate.c
+++ b/drivers/acpi/acpica/rscreate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsdump.c b/drivers/acpi/acpica/rsdump.c
index c3c56b5a9788..1539394c8c52 100644
--- a/drivers/acpi/acpica/rsdump.c
+++ b/drivers/acpi/acpica/rsdump.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsdumpinfo.c b/drivers/acpi/acpica/rsdumpinfo.c
index 2f9332d5c973..b29d9ec63d1b 100644
--- a/drivers/acpi/acpica/rsdumpinfo.c
+++ b/drivers/acpi/acpica/rsdumpinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -183,15 +183,15 @@ struct acpi_rsdump_info acpi_rs_dump_address16[8] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address16),
"16-Bit WORD Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.granularity), "Granularity",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.translation_offset),
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.granularity),
+ "Granularity", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.minimum),
+ "Address Minimum", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.maximum),
+ "Address Maximum", NULL},
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.translation_offset),
"Translation Offset", NULL},
- {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address_length),
+ {ACPI_RSD_UINT16, ACPI_RSD_OFFSET(address16.address.address_length),
"Address Length", NULL},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address16.resource_source), NULL, NULL}
};
@@ -200,15 +200,15 @@ struct acpi_rsdump_info acpi_rs_dump_address32[8] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address32),
"32-Bit DWORD Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.granularity), "Granularity",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.translation_offset),
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.granularity),
+ "Granularity", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.minimum),
+ "Address Minimum", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.maximum),
+ "Address Maximum", NULL},
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.translation_offset),
"Translation Offset", NULL},
- {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address_length),
+ {ACPI_RSD_UINT32, ACPI_RSD_OFFSET(address32.address.address_length),
"Address Length", NULL},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address32.resource_source), NULL, NULL}
};
@@ -217,15 +217,15 @@ struct acpi_rsdump_info acpi_rs_dump_address64[8] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_address64),
"64-Bit QWORD Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.granularity), "Granularity",
- NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.minimum), "Address Minimum",
- NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.maximum), "Address Maximum",
- NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.translation_offset),
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.granularity),
+ "Granularity", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.minimum),
+ "Address Minimum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.maximum),
+ "Address Maximum", NULL},
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.translation_offset),
"Translation Offset", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address_length),
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(address64.address.address_length),
"Address Length", NULL},
{ACPI_RSD_SOURCE, ACPI_RSD_OFFSET(address64.resource_source), NULL, NULL}
};
@@ -234,15 +234,16 @@ struct acpi_rsdump_info acpi_rs_dump_ext_address64[8] = {
{ACPI_RSD_TITLE, ACPI_RSD_TABLE_SIZE(acpi_rs_dump_ext_address64),
"64-Bit Extended Address Space", NULL},
{ACPI_RSD_ADDRESS, 0, NULL, NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.granularity),
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.granularity),
"Granularity", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.minimum),
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.minimum),
"Address Minimum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.maximum),
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.maximum),
"Address Maximum", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.translation_offset),
+ {ACPI_RSD_UINT64,
+ ACPI_RSD_OFFSET(ext_address64.address.translation_offset),
"Translation Offset", NULL},
- {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address_length),
+ {ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.address.address_length),
"Address Length", NULL},
{ACPI_RSD_UINT64, ACPI_RSD_OFFSET(ext_address64.type_specific),
"Type-Specific Attribute", NULL}
diff --git a/drivers/acpi/acpica/rsinfo.c b/drivers/acpi/acpica/rsinfo.c
index 9d3f8a9a24bd..edecfc675979 100644
--- a/drivers/acpi/acpica/rsinfo.c
+++ b/drivers/acpi/acpica/rsinfo.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsio.c b/drivers/acpi/acpica/rsio.c
index 19d64873290a..5adba018bab0 100644
--- a/drivers/acpi/acpica/rsio.c
+++ b/drivers/acpi/acpica/rsio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsirq.c b/drivers/acpi/acpica/rsirq.c
index 3461f7db26df..07cfa70a475b 100644
--- a/drivers/acpi/acpica/rsirq.c
+++ b/drivers/acpi/acpica/rsirq.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rslist.c b/drivers/acpi/acpica/rslist.c
index 77291293af64..50d5be2ee062 100644
--- a/drivers/acpi/acpica/rslist.c
+++ b/drivers/acpi/acpica/rslist.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmemory.c b/drivers/acpi/acpica/rsmemory.c
index eab4483ff5f8..c6b80862030e 100644
--- a/drivers/acpi/acpica/rsmemory.c
+++ b/drivers/acpi/acpica/rsmemory.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsmisc.c b/drivers/acpi/acpica/rsmisc.c
index 41eea4bc089c..1fe49d223663 100644
--- a/drivers/acpi/acpica/rsmisc.c
+++ b/drivers/acpi/acpica/rsmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsserial.c b/drivers/acpi/acpica/rsserial.c
index 9e8407223d95..4c8c6fe6ea74 100644
--- a/drivers/acpi/acpica/rsserial.c
+++ b/drivers/acpi/acpica/rsserial.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsutils.c b/drivers/acpi/acpica/rsutils.c
index 897a5ceb0420..ece3cd60cc6a 100644
--- a/drivers/acpi/acpica/rsutils.c
+++ b/drivers/acpi/acpica/rsutils.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/rsxface.c b/drivers/acpi/acpica/rsxface.c
index 877ab9202133..8e6276df0226 100644
--- a/drivers/acpi/acpica/rsxface.c
+++ b/drivers/acpi/acpica/rsxface.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -60,11 +60,11 @@ ACPI_MODULE_NAME("rsxface")
ACPI_COPY_FIELD(out, in, min_address_fixed); \
ACPI_COPY_FIELD(out, in, max_address_fixed); \
ACPI_COPY_FIELD(out, in, info); \
- ACPI_COPY_FIELD(out, in, granularity); \
- ACPI_COPY_FIELD(out, in, minimum); \
- ACPI_COPY_FIELD(out, in, maximum); \
- ACPI_COPY_FIELD(out, in, translation_offset); \
- ACPI_COPY_FIELD(out, in, address_length); \
+ ACPI_COPY_FIELD(out, in, address.granularity); \
+ ACPI_COPY_FIELD(out, in, address.minimum); \
+ ACPI_COPY_FIELD(out, in, address.maximum); \
+ ACPI_COPY_FIELD(out, in, address.translation_offset); \
+ ACPI_COPY_FIELD(out, in, address.address_length); \
ACPI_COPY_FIELD(out, in, resource_source);
/* Local prototypes */
static acpi_status
diff --git a/drivers/acpi/acpica/tbdata.c b/drivers/acpi/acpica/tbdata.c
index f499c10ceb4a..6a144957aadd 100644
--- a/drivers/acpi/acpica/tbdata.c
+++ b/drivers/acpi/acpica/tbdata.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfadt.c b/drivers/acpi/acpica/tbfadt.c
index 41519a958083..7d2486005e3f 100644
--- a/drivers/acpi/acpica/tbfadt.c
+++ b/drivers/acpi/acpica/tbfadt.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbfind.c b/drivers/acpi/acpica/tbfind.c
index cb947700206c..0b879fcfef67 100644
--- a/drivers/acpi/acpica/tbfind.c
+++ b/drivers/acpi/acpica/tbfind.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbinstal.c b/drivers/acpi/acpica/tbinstal.c
index 755b90c40ddf..9bad45e63a45 100644
--- a/drivers/acpi/acpica/tbinstal.c
+++ b/drivers/acpi/acpica/tbinstal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbprint.c b/drivers/acpi/acpica/tbprint.c
index df3bb20ea325..ef16c06e5091 100644
--- a/drivers/acpi/acpica/tbprint.c
+++ b/drivers/acpi/acpica/tbprint.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbutils.c b/drivers/acpi/acpica/tbutils.c
index 6b1ca9991b90..6559a58439c5 100644
--- a/drivers/acpi/acpica/tbutils.c
+++ b/drivers/acpi/acpica/tbutils.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxface.c b/drivers/acpi/acpica/tbxface.c
index 6482b0ded652..60e94f87f27a 100644
--- a/drivers/acpi/acpica/tbxface.c
+++ b/drivers/acpi/acpica/tbxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -265,45 +265,6 @@ ACPI_EXPORT_SYMBOL(acpi_get_table_header)
/*******************************************************************************
*
- * FUNCTION: acpi_unload_table_id
- *
- * PARAMETERS: id - Owner ID of the table to be removed.
- *
- * RETURN: Status
- *
- * DESCRIPTION: This routine is used to force the unload of a table (by id)
- *
- ******************************************************************************/
-acpi_status acpi_unload_table_id(acpi_owner_id id)
-{
- int i;
- acpi_status status = AE_NOT_EXIST;
-
- ACPI_FUNCTION_TRACE(acpi_unload_table_id);
-
- /* Find table in the global table list */
- for (i = 0; i < acpi_gbl_root_table_list.current_table_count; ++i) {
- if (id != acpi_gbl_root_table_list.tables[i].owner_id) {
- continue;
- }
- /*
- * Delete all namespace objects owned by this table. Note that these
- * objects can appear anywhere in the namespace by virtue of the AML
- * "Scope" operator. Thus, we need to track ownership by an ID, not
- * simply a position within the hierarchy
- */
- acpi_tb_delete_namespace_by_owner(i);
- status = acpi_tb_release_owner_id(i);
- acpi_tb_set_table_loaded_flag(i, FALSE);
- break;
- }
- return_ACPI_STATUS(status);
-}
-
-ACPI_EXPORT_SYMBOL(acpi_unload_table_id)
-
-/*******************************************************************************
- *
* FUNCTION: acpi_get_table_with_size
*
* PARAMETERS: signature - ACPI signature of needed table
diff --git a/drivers/acpi/acpica/tbxfload.c b/drivers/acpi/acpica/tbxfload.c
index ab5308b81aa8..aadb3002a2dd 100644
--- a/drivers/acpi/acpica/tbxfload.c
+++ b/drivers/acpi/acpica/tbxfload.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/tbxfroot.c b/drivers/acpi/acpica/tbxfroot.c
index 43a54af2b548..eac52cf14f1a 100644
--- a/drivers/acpi/acpica/tbxfroot.c
+++ b/drivers/acpi/acpica/tbxfroot.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utaddress.c b/drivers/acpi/acpica/utaddress.c
index a1acec9d2ef3..1279f50da757 100644
--- a/drivers/acpi/acpica/utaddress.c
+++ b/drivers/acpi/acpica/utaddress.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utalloc.c b/drivers/acpi/acpica/utalloc.c
index efac83c606dc..61d8f6d186d1 100644
--- a/drivers/acpi/acpica/utalloc.c
+++ b/drivers/acpi/acpica/utalloc.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utbuffer.c b/drivers/acpi/acpica/utbuffer.c
index 038ea887f562..242bd071f007 100644
--- a/drivers/acpi/acpica/utbuffer.c
+++ b/drivers/acpi/acpica/utbuffer.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcache.c b/drivers/acpi/acpica/utcache.c
index 78fde0aac487..eacc5eee362e 100644
--- a/drivers/acpi/acpica/utcache.c
+++ b/drivers/acpi/acpica/utcache.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utcopy.c b/drivers/acpi/acpica/utcopy.c
index ff601c0f7c7a..c37ec5035f4c 100644
--- a/drivers/acpi/acpica/utcopy.c
+++ b/drivers/acpi/acpica/utcopy.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdebug.c b/drivers/acpi/acpica/utdebug.c
index e516254c63b2..4f3f888d33bb 100644
--- a/drivers/acpi/acpica/utdebug.c
+++ b/drivers/acpi/acpica/utdebug.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -111,8 +111,8 @@ void acpi_ut_track_stack_ptr(void)
* RETURN: Updated pointer to the function name
*
* DESCRIPTION: Remove the "Acpi" prefix from the function name, if present.
- * This allows compiler macros such as __FUNCTION__ to be used
- * with no change to the debug output.
+ * This allows compiler macros such as __func__ to be used with no
+ * change to the debug output.
*
******************************************************************************/
diff --git a/drivers/acpi/acpica/utdecode.c b/drivers/acpi/acpica/utdecode.c
index 40e923e675fc..988e23b7795c 100644
--- a/drivers/acpi/acpica/utdecode.c
+++ b/drivers/acpi/acpica/utdecode.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utdelete.c b/drivers/acpi/acpica/utdelete.c
index a3516de213fa..71fce389fd48 100644
--- a/drivers/acpi/acpica/utdelete.c
+++ b/drivers/acpi/acpica/utdelete.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uterror.c b/drivers/acpi/acpica/uterror.c
index 8e544d4688cd..9ef80f2828e3 100644
--- a/drivers/acpi/acpica/uterror.c
+++ b/drivers/acpi/acpica/uterror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uteval.c b/drivers/acpi/acpica/uteval.c
index 8fed1482d228..6c738fa0cd42 100644
--- a/drivers/acpi/acpica/uteval.c
+++ b/drivers/acpi/acpica/uteval.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utexcep.c b/drivers/acpi/acpica/utexcep.c
index 0403dcaabaf2..743a0ae9fb17 100644
--- a/drivers/acpi/acpica/utexcep.c
+++ b/drivers/acpi/acpica/utexcep.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utfileio.c b/drivers/acpi/acpica/utfileio.c
index 4e263a8cc6f0..7e1168be39fa 100644
--- a/drivers/acpi/acpica/utfileio.c
+++ b/drivers/acpi/acpica/utfileio.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utglobal.c b/drivers/acpi/acpica/utglobal.c
index 77ceac715f28..5e8df9177da4 100644
--- a/drivers/acpi/acpica/utglobal.c
+++ b/drivers/acpi/acpica/utglobal.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uthex.c b/drivers/acpi/acpica/uthex.c
index 9afa9441b183..aa448278ba28 100644
--- a/drivers/acpi/acpica/uthex.c
+++ b/drivers/acpi/acpica/uthex.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utids.c b/drivers/acpi/acpica/utids.c
index 4b12880e5b11..27431cfc1c44 100644
--- a/drivers/acpi/acpica/utids.c
+++ b/drivers/acpi/acpica/utids.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utinit.c b/drivers/acpi/acpica/utinit.c
index 77120ec9ea86..e402e07b4846 100644
--- a/drivers/acpi/acpica/utinit.c
+++ b/drivers/acpi/acpica/utinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utlock.c b/drivers/acpi/acpica/utlock.c
index dc6e96547f18..089f78bbd59b 100644
--- a/drivers/acpi/acpica/utlock.c
+++ b/drivers/acpi/acpica/utlock.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmath.c b/drivers/acpi/acpica/utmath.c
index d44dee6ee10a..f9ff100f0159 100644
--- a/drivers/acpi/acpica/utmath.c
+++ b/drivers/acpi/acpica/utmath.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmisc.c b/drivers/acpi/acpica/utmisc.c
index 2e2bb14e1099..56bbacd576f2 100644
--- a/drivers/acpi/acpica/utmisc.c
+++ b/drivers/acpi/acpica/utmisc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utmutex.c b/drivers/acpi/acpica/utmutex.c
index 82717fff9ffc..37b8b58fcd56 100644
--- a/drivers/acpi/acpica/utmutex.c
+++ b/drivers/acpi/acpica/utmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utobject.c b/drivers/acpi/acpica/utobject.c
index dfa9009bfc87..7d83efe1ea29 100644
--- a/drivers/acpi/acpica/utobject.c
+++ b/drivers/acpi/acpica/utobject.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utosi.c b/drivers/acpi/acpica/utosi.c
index 685766fc6ca8..574cd3118313 100644
--- a/drivers/acpi/acpica/utosi.c
+++ b/drivers/acpi/acpica/utosi.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utownerid.c b/drivers/acpi/acpica/utownerid.c
index 36bec57ebd23..2959217067cb 100644
--- a/drivers/acpi/acpica/utownerid.c
+++ b/drivers/acpi/acpica/utownerid.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utpredef.c b/drivers/acpi/acpica/utpredef.c
index db30caff130a..29e449935a82 100644
--- a/drivers/acpi/acpica/utpredef.c
+++ b/drivers/acpi/acpica/utpredef.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utprint.c b/drivers/acpi/acpica/utprint.c
index 0ce3f5a0dd67..82ca9142e10d 100644
--- a/drivers/acpi/acpica/utprint.c
+++ b/drivers/acpi/acpica/utprint.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index bc1ff820c7dd..b3505dbc715e 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utstate.c b/drivers/acpi/acpica/utstate.c
index 1cc97a752c15..8274cc16edc3 100644
--- a/drivers/acpi/acpica/utstate.c
+++ b/drivers/acpi/acpica/utstate.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utstring.c b/drivers/acpi/acpica/utstring.c
index 6dc54b3c28b0..83b6c52490dc 100644
--- a/drivers/acpi/acpica/utstring.c
+++ b/drivers/acpi/acpica/utstring.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/uttrack.c b/drivers/acpi/acpica/uttrack.c
index 7d0ee969d781..130dd9f96f0f 100644
--- a/drivers/acpi/acpica/uttrack.c
+++ b/drivers/acpi/acpica/uttrack.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utuuid.c b/drivers/acpi/acpica/utuuid.c
index 4dc33130f134..c6149a212149 100644
--- a/drivers/acpi/acpica/utuuid.c
+++ b/drivers/acpi/acpica/utuuid.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 49c873c68756..0929187bdce0 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxferror.c b/drivers/acpi/acpica/utxferror.c
index 88ef77f3cf88..306e785f9418 100644
--- a/drivers/acpi/acpica/utxferror.c
+++ b/drivers/acpi/acpica/utxferror.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index b1fd6886e439..083a76891889 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -5,7 +5,7 @@
*****************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/acpica/utxfmutex.c b/drivers/acpi/acpica/utxfmutex.c
index 2a0f9e04d3a4..f2606af3364c 100644
--- a/drivers/acpi/acpica/utxfmutex.c
+++ b/drivers/acpi/acpica/utxfmutex.c
@@ -5,7 +5,7 @@
******************************************************************************/
/*
- * Copyright (C) 2000 - 2014, Intel Corp.
+ * Copyright (C) 2000 - 2015, Intel Corp.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
diff --git a/drivers/acpi/apei/apei-base.c b/drivers/acpi/apei/apei-base.c
index 2cd7bdd6c8b3..a85ac07f3da3 100644
--- a/drivers/acpi/apei/apei-base.c
+++ b/drivers/acpi/apei/apei-base.c
@@ -449,7 +449,7 @@ int apei_resources_sub(struct apei_resources *resources1,
}
EXPORT_SYMBOL_GPL(apei_resources_sub);
-static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
+static int apei_get_res_callback(__u64 start, __u64 size, void *data)
{
struct apei_resources *resources = data;
return apei_res_add(&resources->iomem, start, size);
@@ -457,7 +457,15 @@ static int apei_get_nvs_callback(__u64 start, __u64 size, void *data)
static int apei_get_nvs_resources(struct apei_resources *resources)
{
- return acpi_nvs_for_each_region(apei_get_nvs_callback, resources);
+ return acpi_nvs_for_each_region(apei_get_res_callback, resources);
+}
+
+int (*arch_apei_filter_addr)(int (*func)(__u64 start, __u64 size,
+ void *data), void *data);
+static int apei_get_arch_resources(struct apei_resources *resources)
+
+{
+ return arch_apei_filter_addr(apei_get_res_callback, resources);
}
/*
@@ -470,7 +478,7 @@ int apei_resources_request(struct apei_resources *resources,
{
struct apei_res *res, *res_bak = NULL;
struct resource *r;
- struct apei_resources nvs_resources;
+ struct apei_resources nvs_resources, arch_res;
int rc;
rc = apei_resources_sub(resources, &apei_resources_all);
@@ -485,10 +493,20 @@ int apei_resources_request(struct apei_resources *resources,
apei_resources_init(&nvs_resources);
rc = apei_get_nvs_resources(&nvs_resources);
if (rc)
- goto res_fini;
+ goto nvs_res_fini;
rc = apei_resources_sub(resources, &nvs_resources);
if (rc)
- goto res_fini;
+ goto nvs_res_fini;
+
+ if (arch_apei_filter_addr) {
+ apei_resources_init(&arch_res);
+ rc = apei_get_arch_resources(&arch_res);
+ if (rc)
+ goto arch_res_fini;
+ rc = apei_resources_sub(resources, &arch_res);
+ if (rc)
+ goto arch_res_fini;
+ }
rc = -EINVAL;
list_for_each_entry(res, &resources->iomem, list) {
@@ -536,7 +554,9 @@ err_unmap_iomem:
break;
release_mem_region(res->start, res->end - res->start);
}
-res_fini:
+arch_res_fini:
+ apei_resources_fini(&arch_res);
+nvs_res_fini:
apei_resources_fini(&nvs_resources);
return rc;
}
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index c0d44d394ca3..735db11a9b00 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -1027,7 +1027,6 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
static struct dev_pm_domain acpi_general_pm_domain = {
.ops = {
-#ifdef CONFIG_PM
.runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume,
#ifdef CONFIG_PM_SLEEP
@@ -1041,7 +1040,6 @@ 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/ec.c b/drivers/acpi/ec.c
index 1b5853f384e2..a8dd2f763382 100644
--- a/drivers/acpi/ec.c
+++ b/drivers/acpi/ec.c
@@ -1,8 +1,8 @@
/*
- * ec.c - ACPI Embedded Controller Driver (v2.2)
+ * ec.c - ACPI Embedded Controller Driver (v3)
*
- * Copyright (C) 2001-2014 Intel Corporation
- * Author: 2014 Lv Zheng <lv.zheng@intel.com>
+ * Copyright (C) 2001-2015 Intel Corporation
+ * Author: 2014, 2015 Lv Zheng <lv.zheng@intel.com>
* 2006, 2007 Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
* 2006 Denis Sadykov <denis.m.sadykov@intel.com>
* 2004 Luming Yu <luming.yu@intel.com>
@@ -71,15 +71,18 @@ enum ec_command {
#define ACPI_EC_DELAY 500 /* Wait 500ms max. during EC ops */
#define ACPI_EC_UDELAY_GLK 1000 /* Wait 1ms max. to get global lock */
#define ACPI_EC_MSI_UDELAY 550 /* Wait 550us for MSI EC */
+#define ACPI_EC_UDELAY_POLL 1000 /* Wait 1ms for EC transaction polling */
#define ACPI_EC_CLEAR_MAX 100 /* Maximum number of events to query
* when trying to clear the EC */
enum {
EC_FLAGS_QUERY_PENDING, /* Query is pending */
- EC_FLAGS_GPE_STORM, /* GPE storm detected */
EC_FLAGS_HANDLERS_INSTALLED, /* Handlers for GPE and
* OpReg are installed */
- EC_FLAGS_BLOCKED, /* Transactions are blocked */
+ EC_FLAGS_STARTED, /* Driver is started */
+ EC_FLAGS_STOPPED, /* Driver is stopped */
+ EC_FLAGS_COMMAND_STORM, /* GPE storms occurred to the
+ * current command processing */
};
#define ACPI_EC_COMMAND_POLL 0x01 /* Available for command byte */
@@ -105,6 +108,7 @@ struct acpi_ec_query_handler {
acpi_handle handle;
void *data;
u8 query_bit;
+ struct kref kref;
};
struct transaction {
@@ -117,8 +121,12 @@ struct transaction {
u8 wlen;
u8 rlen;
u8 flags;
+ unsigned long timestamp;
};
+static int acpi_ec_query(struct acpi_ec *ec, u8 *data);
+static void advance_transaction(struct acpi_ec *ec);
+
struct acpi_ec *boot_ec, *first_ec;
EXPORT_SYMBOL(first_ec);
@@ -129,7 +137,22 @@ static int EC_FLAGS_CLEAR_ON_RESUME; /* Needs acpi_ec_clear() on boot/resume */
static int EC_FLAGS_QUERY_HANDSHAKE; /* Needs QR_EC issued when SCI_EVT set */
/* --------------------------------------------------------------------------
- * Transaction Management
+ * Device Flags
+ * -------------------------------------------------------------------------- */
+
+static bool acpi_ec_started(struct acpi_ec *ec)
+{
+ return test_bit(EC_FLAGS_STARTED, &ec->flags) &&
+ !test_bit(EC_FLAGS_STOPPED, &ec->flags);
+}
+
+static bool acpi_ec_flushed(struct acpi_ec *ec)
+{
+ return ec->reference_count == 1;
+}
+
+/* --------------------------------------------------------------------------
+ * EC Registers
* -------------------------------------------------------------------------- */
static inline u8 acpi_ec_read_status(struct acpi_ec *ec)
@@ -151,6 +174,7 @@ static inline u8 acpi_ec_read_data(struct acpi_ec *ec)
{
u8 x = inb(ec->data_addr);
+ ec->curr->timestamp = jiffies;
pr_debug("EC_DATA(R) = 0x%2.2x\n", x);
return x;
}
@@ -159,12 +183,14 @@ static inline void acpi_ec_write_cmd(struct acpi_ec *ec, u8 command)
{
pr_debug("EC_SC(W) = 0x%2.2x\n", command);
outb(command, ec->command_addr);
+ ec->curr->timestamp = jiffies;
}
static inline void acpi_ec_write_data(struct acpi_ec *ec, u8 data)
{
pr_debug("EC_DATA(W) = 0x%2.2x\n", data);
outb(data, ec->data_addr);
+ ec->curr->timestamp = jiffies;
}
#ifdef DEBUG
@@ -188,6 +214,140 @@ static const char *acpi_ec_cmd_string(u8 cmd)
#define acpi_ec_cmd_string(cmd) "UNDEF"
#endif
+/* --------------------------------------------------------------------------
+ * GPE Registers
+ * -------------------------------------------------------------------------- */
+
+static inline bool acpi_ec_is_gpe_raised(struct acpi_ec *ec)
+{
+ acpi_event_status gpe_status = 0;
+
+ (void)acpi_get_gpe_status(NULL, ec->gpe, &gpe_status);
+ return (gpe_status & ACPI_EVENT_FLAG_SET) ? true : false;
+}
+
+static inline void acpi_ec_enable_gpe(struct acpi_ec *ec, bool open)
+{
+ if (open)
+ acpi_enable_gpe(NULL, ec->gpe);
+ else {
+ BUG_ON(ec->reference_count < 1);
+ acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_ENABLE);
+ }
+ if (acpi_ec_is_gpe_raised(ec)) {
+ /*
+ * On some platforms, EN=1 writes cannot trigger GPE. So
+ * software need to manually trigger a pseudo GPE event on
+ * EN=1 writes.
+ */
+ pr_debug("***** Polling quirk *****\n");
+ advance_transaction(ec);
+ }
+}
+
+static inline void acpi_ec_disable_gpe(struct acpi_ec *ec, bool close)
+{
+ if (close)
+ acpi_disable_gpe(NULL, ec->gpe);
+ else {
+ BUG_ON(ec->reference_count < 1);
+ acpi_set_gpe(NULL, ec->gpe, ACPI_GPE_DISABLE);
+ }
+}
+
+static inline void acpi_ec_clear_gpe(struct acpi_ec *ec)
+{
+ /*
+ * GPE STS is a W1C register, which means:
+ * 1. Software can clear it without worrying about clearing other
+ * GPEs' STS bits when the hardware sets them in parallel.
+ * 2. As long as software can ensure only clearing it when it is
+ * set, hardware won't set it in parallel.
+ * So software can clear GPE in any contexts.
+ * Warning: do not move the check into advance_transaction() as the
+ * EC commands will be sent without GPE raised.
+ */
+ if (!acpi_ec_is_gpe_raised(ec))
+ return;
+ acpi_clear_gpe(NULL, ec->gpe);
+}
+
+/* --------------------------------------------------------------------------
+ * Transaction Management
+ * -------------------------------------------------------------------------- */
+
+static void acpi_ec_submit_request(struct acpi_ec *ec)
+{
+ ec->reference_count++;
+ if (ec->reference_count == 1)
+ acpi_ec_enable_gpe(ec, true);
+}
+
+static void acpi_ec_complete_request(struct acpi_ec *ec)
+{
+ bool flushed = false;
+
+ ec->reference_count--;
+ if (ec->reference_count == 0)
+ acpi_ec_disable_gpe(ec, true);
+ flushed = acpi_ec_flushed(ec);
+ if (flushed)
+ wake_up(&ec->wait);
+}
+
+static void acpi_ec_set_storm(struct acpi_ec *ec, u8 flag)
+{
+ if (!test_bit(flag, &ec->flags)) {
+ acpi_ec_disable_gpe(ec, false);
+ pr_debug("+++++ Polling enabled +++++\n");
+ set_bit(flag, &ec->flags);
+ }
+}
+
+static void acpi_ec_clear_storm(struct acpi_ec *ec, u8 flag)
+{
+ if (test_bit(flag, &ec->flags)) {
+ clear_bit(flag, &ec->flags);
+ acpi_ec_enable_gpe(ec, false);
+ pr_debug("+++++ Polling disabled +++++\n");
+ }
+}
+
+/*
+ * acpi_ec_submit_flushable_request() - Increase the reference count unless
+ * the flush operation is not in
+ * progress
+ * @ec: the EC device
+ *
+ * This function must be used before taking a new action that should hold
+ * the reference count. If this function returns false, then the action
+ * must be discarded or it will prevent the flush operation from being
+ * completed.
+ */
+static bool acpi_ec_submit_flushable_request(struct acpi_ec *ec)
+{
+ if (!acpi_ec_started(ec))
+ return false;
+ acpi_ec_submit_request(ec);
+ return true;
+}
+
+static void acpi_ec_submit_query(struct acpi_ec *ec)
+{
+ if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
+ pr_debug("***** Event started *****\n");
+ schedule_work(&ec->work);
+ }
+}
+
+static void acpi_ec_complete_query(struct acpi_ec *ec)
+{
+ if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
+ clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
+ pr_debug("***** Event stopped *****\n");
+ }
+}
+
static int ec_transaction_completed(struct acpi_ec *ec)
{
unsigned long flags;
@@ -200,7 +360,7 @@ static int ec_transaction_completed(struct acpi_ec *ec)
return ret;
}
-static bool advance_transaction(struct acpi_ec *ec)
+static void advance_transaction(struct acpi_ec *ec)
{
struct transaction *t;
u8 status;
@@ -208,6 +368,12 @@ static bool advance_transaction(struct acpi_ec *ec)
pr_debug("===== %s (%d) =====\n",
in_interrupt() ? "IRQ" : "TASK", smp_processor_id());
+ /*
+ * By always clearing STS before handling all indications, we can
+ * ensure a hardware STS 0->1 change after this clearing can always
+ * trigger a GPE interrupt.
+ */
+ acpi_ec_clear_gpe(ec);
status = acpi_ec_read_status(ec);
t = ec->curr;
if (!t)
@@ -235,12 +401,13 @@ static bool advance_transaction(struct acpi_ec *ec)
t->flags |= ACPI_EC_COMMAND_COMPLETE;
wakeup = true;
}
- return wakeup;
+ goto out;
} else {
if (EC_FLAGS_QUERY_HANDSHAKE &&
!(status & ACPI_EC_FLAG_SCI) &&
(t->command == ACPI_EC_COMMAND_QUERY)) {
t->flags |= ACPI_EC_COMMAND_POLL;
+ acpi_ec_complete_query(ec);
t->rdata[t->ri++] = 0x00;
t->flags |= ACPI_EC_COMMAND_COMPLETE;
pr_debug("***** Command(%s) software completion *****\n",
@@ -249,9 +416,10 @@ static bool advance_transaction(struct acpi_ec *ec)
} else if ((status & ACPI_EC_FLAG_IBF) == 0) {
acpi_ec_write_cmd(ec, t->command);
t->flags |= ACPI_EC_COMMAND_POLL;
+ acpi_ec_complete_query(ec);
} else
goto err;
- return wakeup;
+ goto out;
}
err:
/*
@@ -259,28 +427,27 @@ err:
* otherwise will take a not handled IRQ as a false one.
*/
if (!(status & ACPI_EC_FLAG_SCI)) {
- if (in_interrupt() && t)
- ++t->irq_count;
+ if (in_interrupt() && t) {
+ if (t->irq_count < ec_storm_threshold)
+ ++t->irq_count;
+ /* Allow triggering on 0 threshold */
+ if (t->irq_count == ec_storm_threshold)
+ acpi_ec_set_storm(ec, EC_FLAGS_COMMAND_STORM);
+ }
}
- return wakeup;
+out:
+ if (status & ACPI_EC_FLAG_SCI)
+ acpi_ec_submit_query(ec);
+ if (wakeup && in_interrupt())
+ wake_up(&ec->wait);
}
static void start_transaction(struct acpi_ec *ec)
{
ec->curr->irq_count = ec->curr->wi = ec->curr->ri = 0;
ec->curr->flags = 0;
- (void)advance_transaction(ec);
-}
-
-static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data);
-
-static int ec_check_sci_sync(struct acpi_ec *ec, u8 state)
-{
- if (state & ACPI_EC_FLAG_SCI) {
- if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags))
- return acpi_ec_sync_query(ec, NULL);
- }
- return 0;
+ ec->curr->timestamp = jiffies;
+ advance_transaction(ec);
}
static int ec_poll(struct acpi_ec *ec)
@@ -291,20 +458,25 @@ static int ec_poll(struct acpi_ec *ec)
while (repeat--) {
unsigned long delay = jiffies +
msecs_to_jiffies(ec_delay);
+ unsigned long usecs = ACPI_EC_UDELAY_POLL;
do {
/* don't sleep with disabled interrupts */
if (EC_FLAGS_MSI || irqs_disabled()) {
- udelay(ACPI_EC_MSI_UDELAY);
+ usecs = ACPI_EC_MSI_UDELAY;
+ udelay(usecs);
if (ec_transaction_completed(ec))
return 0;
} else {
if (wait_event_timeout(ec->wait,
ec_transaction_completed(ec),
- msecs_to_jiffies(1)))
+ usecs_to_jiffies(usecs)))
return 0;
}
spin_lock_irqsave(&ec->lock, flags);
- (void)advance_transaction(ec);
+ if (time_after(jiffies,
+ ec->curr->timestamp +
+ usecs_to_jiffies(usecs)))
+ advance_transaction(ec);
spin_unlock_irqrestore(&ec->lock, flags);
} while (time_before(jiffies, delay));
pr_debug("controller reset, restart transaction\n");
@@ -325,21 +497,27 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
udelay(ACPI_EC_MSI_UDELAY);
/* start transaction */
spin_lock_irqsave(&ec->lock, tmp);
+ /* Enable GPE for command processing (IBF=0/OBF=1) */
+ if (!acpi_ec_submit_flushable_request(ec)) {
+ ret = -EINVAL;
+ goto unlock;
+ }
/* following two actions should be kept atomic */
ec->curr = t;
pr_debug("***** Command(%s) started *****\n",
acpi_ec_cmd_string(t->command));
start_transaction(ec);
- if (ec->curr->command == ACPI_EC_COMMAND_QUERY) {
- clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
- pr_debug("***** Event stopped *****\n");
- }
spin_unlock_irqrestore(&ec->lock, tmp);
ret = ec_poll(ec);
spin_lock_irqsave(&ec->lock, tmp);
+ if (t->irq_count == ec_storm_threshold)
+ acpi_ec_clear_storm(ec, EC_FLAGS_COMMAND_STORM);
pr_debug("***** Command(%s) stopped *****\n",
acpi_ec_cmd_string(t->command));
ec->curr = NULL;
+ /* Disable GPE for command processing (IBF=0/OBF=1) */
+ acpi_ec_complete_request(ec);
+unlock:
spin_unlock_irqrestore(&ec->lock, tmp);
return ret;
}
@@ -354,10 +532,6 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
if (t->rdata)
memset(t->rdata, 0, t->rlen);
mutex_lock(&ec->mutex);
- if (test_bit(EC_FLAGS_BLOCKED, &ec->flags)) {
- status = -EINVAL;
- goto unlock;
- }
if (ec->global_lock) {
status = acpi_acquire_global_lock(ACPI_EC_UDELAY_GLK, &glk);
if (ACPI_FAILURE(status)) {
@@ -365,26 +539,11 @@ static int acpi_ec_transaction(struct acpi_ec *ec, struct transaction *t)
goto unlock;
}
}
- /* disable GPE during transaction if storm is detected */
- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
- /* It has to be disabled, so that it doesn't trigger. */
- acpi_disable_gpe(NULL, ec->gpe);
- }
status = acpi_ec_transaction_unlocked(ec, t);
- /* check if we received SCI during transaction */
- ec_check_sci_sync(ec, acpi_ec_read_status(ec));
- if (test_bit(EC_FLAGS_GPE_STORM, &ec->flags)) {
+ if (test_bit(EC_FLAGS_COMMAND_STORM, &ec->flags))
msleep(1);
- /* It is safe to enable the GPE outside of the transaction. */
- acpi_enable_gpe(NULL, ec->gpe);
- } else if (t->irq_count > ec_storm_threshold) {
- pr_info("GPE storm detected(%d GPEs), "
- "transactions will use polling mode\n",
- t->irq_count);
- set_bit(EC_FLAGS_GPE_STORM, &ec->flags);
- }
if (ec->global_lock)
acpi_release_global_lock(glk);
unlock:
@@ -500,7 +659,7 @@ static void acpi_ec_clear(struct acpi_ec *ec)
u8 value = 0;
for (i = 0; i < ACPI_EC_CLEAR_MAX; i++) {
- status = acpi_ec_sync_query(ec, &value);
+ status = acpi_ec_query(ec, &value);
if (status || !value)
break;
}
@@ -511,6 +670,53 @@ static void acpi_ec_clear(struct acpi_ec *ec)
pr_info("%d stale EC events cleared\n", i);
}
+static void acpi_ec_start(struct acpi_ec *ec, bool resuming)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ if (!test_and_set_bit(EC_FLAGS_STARTED, &ec->flags)) {
+ pr_debug("+++++ Starting EC +++++\n");
+ /* Enable GPE for event processing (SCI_EVT=1) */
+ if (!resuming)
+ acpi_ec_submit_request(ec);
+ pr_debug("EC started\n");
+ }
+ spin_unlock_irqrestore(&ec->lock, flags);
+}
+
+static bool acpi_ec_stopped(struct acpi_ec *ec)
+{
+ unsigned long flags;
+ bool flushed;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ flushed = acpi_ec_flushed(ec);
+ spin_unlock_irqrestore(&ec->lock, flags);
+ return flushed;
+}
+
+static void acpi_ec_stop(struct acpi_ec *ec, bool suspending)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ec->lock, flags);
+ if (acpi_ec_started(ec)) {
+ pr_debug("+++++ Stopping EC +++++\n");
+ set_bit(EC_FLAGS_STOPPED, &ec->flags);
+ spin_unlock_irqrestore(&ec->lock, flags);
+ wait_event(ec->wait, acpi_ec_stopped(ec));
+ spin_lock_irqsave(&ec->lock, flags);
+ /* Disable GPE for event processing (SCI_EVT=1) */
+ if (!suspending)
+ acpi_ec_complete_request(ec);
+ clear_bit(EC_FLAGS_STARTED, &ec->flags);
+ clear_bit(EC_FLAGS_STOPPED, &ec->flags);
+ pr_debug("EC stopped\n");
+ }
+ spin_unlock_irqrestore(&ec->lock, flags);
+}
+
void acpi_ec_block_transactions(void)
{
struct acpi_ec *ec = first_ec;
@@ -520,7 +726,7 @@ void acpi_ec_block_transactions(void)
mutex_lock(&ec->mutex);
/* Prevent transactions from being carried out */
- set_bit(EC_FLAGS_BLOCKED, &ec->flags);
+ acpi_ec_stop(ec, true);
mutex_unlock(&ec->mutex);
}
@@ -531,14 +737,11 @@ void acpi_ec_unblock_transactions(void)
if (!ec)
return;
- mutex_lock(&ec->mutex);
/* Allow transactions to be carried out again */
- clear_bit(EC_FLAGS_BLOCKED, &ec->flags);
+ acpi_ec_start(ec, true);
if (EC_FLAGS_CLEAR_ON_RESUME)
acpi_ec_clear(ec);
-
- mutex_unlock(&ec->mutex);
}
void acpi_ec_unblock_transactions_early(void)
@@ -548,36 +751,33 @@ void acpi_ec_unblock_transactions_early(void)
* atomic context during wakeup, so we don't need to acquire the mutex).
*/
if (first_ec)
- clear_bit(EC_FLAGS_BLOCKED, &first_ec->flags);
+ acpi_ec_start(first_ec, true);
}
-static int acpi_ec_query_unlocked(struct acpi_ec *ec, u8 *data)
+/* --------------------------------------------------------------------------
+ Event Management
+ -------------------------------------------------------------------------- */
+static struct acpi_ec_query_handler *
+acpi_ec_get_query_handler(struct acpi_ec_query_handler *handler)
{
- int result;
- u8 d;
- struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
- .wdata = NULL, .rdata = &d,
- .wlen = 0, .rlen = 1};
+ if (handler)
+ kref_get(&handler->kref);
+ return handler;
+}
- if (!ec || !data)
- return -EINVAL;
- /*
- * Query the EC to find out which _Qxx method we need to evaluate.
- * Note that successful completion of the query causes the ACPI_EC_SCI
- * bit to be cleared (and thus clearing the interrupt source).
- */
- result = acpi_ec_transaction_unlocked(ec, &t);
- if (result)
- return result;
- if (!d)
- return -ENODATA;
- *data = d;
- return 0;
+static void acpi_ec_query_handler_release(struct kref *kref)
+{
+ struct acpi_ec_query_handler *handler =
+ container_of(kref, struct acpi_ec_query_handler, kref);
+
+ kfree(handler);
+}
+
+static void acpi_ec_put_query_handler(struct acpi_ec_query_handler *handler)
+{
+ kref_put(&handler->kref, acpi_ec_query_handler_release);
}
-/* --------------------------------------------------------------------------
- Event Management
- -------------------------------------------------------------------------- */
int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
acpi_handle handle, acpi_ec_query_func func,
void *data)
@@ -593,6 +793,7 @@ int acpi_ec_add_query_handler(struct acpi_ec *ec, u8 query_bit,
handler->func = func;
handler->data = data;
mutex_lock(&ec->mutex);
+ kref_init(&handler->kref);
list_add(&handler->node, &ec->list);
mutex_unlock(&ec->mutex);
return 0;
@@ -602,15 +803,18 @@ EXPORT_SYMBOL_GPL(acpi_ec_add_query_handler);
void acpi_ec_remove_query_handler(struct acpi_ec *ec, u8 query_bit)
{
struct acpi_ec_query_handler *handler, *tmp;
+ LIST_HEAD(free_list);
mutex_lock(&ec->mutex);
list_for_each_entry_safe(handler, tmp, &ec->list, node) {
if (query_bit == handler->query_bit) {
- list_del(&handler->node);
- kfree(handler);
+ list_del_init(&handler->node);
+ list_add(&handler->node, &free_list);
}
}
mutex_unlock(&ec->mutex);
+ list_for_each_entry(handler, &free_list, node)
+ acpi_ec_put_query_handler(handler);
}
EXPORT_SYMBOL_GPL(acpi_ec_remove_query_handler);
@@ -626,59 +830,56 @@ static void acpi_ec_run(void *cxt)
else if (handler->handle)
acpi_evaluate_object(handler->handle, NULL, NULL, NULL);
pr_debug("##### Query(0x%02x) stopped #####\n", handler->query_bit);
- kfree(handler);
+ acpi_ec_put_query_handler(handler);
}
-static int acpi_ec_sync_query(struct acpi_ec *ec, u8 *data)
+static int acpi_ec_query(struct acpi_ec *ec, u8 *data)
{
u8 value = 0;
- int status;
- struct acpi_ec_query_handler *handler, *copy;
+ int result;
+ acpi_status status;
+ struct acpi_ec_query_handler *handler;
+ struct transaction t = {.command = ACPI_EC_COMMAND_QUERY,
+ .wdata = NULL, .rdata = &value,
+ .wlen = 0, .rlen = 1};
- status = acpi_ec_query_unlocked(ec, &value);
+ /*
+ * Query the EC to find out which _Qxx method we need to evaluate.
+ * Note that successful completion of the query causes the ACPI_EC_SCI
+ * bit to be cleared (and thus clearing the interrupt source).
+ */
+ result = acpi_ec_transaction(ec, &t);
+ if (result)
+ return result;
if (data)
*data = value;
- if (status)
- return status;
+ if (!value)
+ return -ENODATA;
+ mutex_lock(&ec->mutex);
list_for_each_entry(handler, &ec->list, node) {
if (value == handler->query_bit) {
/* have custom handler for this bit */
- copy = kmalloc(sizeof(*handler), GFP_KERNEL);
- if (!copy)
- return -ENOMEM;
- memcpy(copy, handler, sizeof(*copy));
+ handler = acpi_ec_get_query_handler(handler);
pr_debug("##### Query(0x%02x) scheduled #####\n",
handler->query_bit);
- return acpi_os_execute((copy->func) ?
+ status = acpi_os_execute((handler->func) ?
OSL_NOTIFY_HANDLER : OSL_GPE_HANDLER,
- acpi_ec_run, copy);
+ acpi_ec_run, handler);
+ if (ACPI_FAILURE(status))
+ result = -EBUSY;
+ break;
}
}
- return 0;
-}
-
-static void acpi_ec_gpe_query(void *ec_cxt)
-{
- struct acpi_ec *ec = ec_cxt;
-
- if (!ec)
- return;
- mutex_lock(&ec->mutex);
- acpi_ec_sync_query(ec, NULL);
mutex_unlock(&ec->mutex);
+ return result;
}
-static int ec_check_sci(struct acpi_ec *ec, u8 state)
+static void acpi_ec_gpe_poller(struct work_struct *work)
{
- if (state & ACPI_EC_FLAG_SCI) {
- if (!test_and_set_bit(EC_FLAGS_QUERY_PENDING, &ec->flags)) {
- pr_debug("***** Event started *****\n");
- return acpi_os_execute(OSL_NOTIFY_HANDLER,
- acpi_ec_gpe_query, ec);
- }
- }
- return 0;
+ struct acpi_ec *ec = container_of(work, struct acpi_ec, work);
+
+ acpi_ec_query(ec, NULL);
}
static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
@@ -688,11 +889,9 @@ static u32 acpi_ec_gpe_handler(acpi_handle gpe_device,
struct acpi_ec *ec = data;
spin_lock_irqsave(&ec->lock, flags);
- if (advance_transaction(ec))
- wake_up(&ec->wait);
+ advance_transaction(ec);
spin_unlock_irqrestore(&ec->lock, flags);
- ec_check_sci(ec, acpi_ec_read_status(ec));
- return ACPI_INTERRUPT_HANDLED | ACPI_REENABLE_GPE;
+ return ACPI_INTERRUPT_HANDLED;
}
/* --------------------------------------------------------------------------
@@ -755,6 +954,7 @@ static struct acpi_ec *make_acpi_ec(void)
init_waitqueue_head(&ec->wait);
INIT_LIST_HEAD(&ec->list);
spin_lock_init(&ec->lock);
+ INIT_WORK(&ec->work, acpi_ec_gpe_poller);
return ec;
}
@@ -810,13 +1010,13 @@ static int ec_install_handlers(struct acpi_ec *ec)
if (test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
return 0;
- status = acpi_install_gpe_handler(NULL, ec->gpe,
+ status = acpi_install_gpe_raw_handler(NULL, ec->gpe,
ACPI_GPE_EDGE_TRIGGERED,
&acpi_ec_gpe_handler, ec);
if (ACPI_FAILURE(status))
return -ENODEV;
- acpi_enable_gpe(NULL, ec->gpe);
+ acpi_ec_start(ec, false);
status = acpi_install_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC,
&acpi_ec_space_handler,
@@ -831,7 +1031,7 @@ static int ec_install_handlers(struct acpi_ec *ec)
pr_err("Fail in evaluating the _REG object"
" of EC device. Broken bios is suspected.\n");
} else {
- acpi_disable_gpe(NULL, ec->gpe);
+ acpi_ec_stop(ec, false);
acpi_remove_gpe_handler(NULL, ec->gpe,
&acpi_ec_gpe_handler);
return -ENODEV;
@@ -846,7 +1046,7 @@ static void ec_remove_handlers(struct acpi_ec *ec)
{
if (!test_bit(EC_FLAGS_HANDLERS_INSTALLED, &ec->flags))
return;
- acpi_disable_gpe(NULL, ec->gpe);
+ acpi_ec_stop(ec, false);
if (ACPI_FAILURE(acpi_remove_address_space_handler(ec->handle,
ACPI_ADR_SPACE_EC, &acpi_ec_space_handler)))
pr_err("failed to remove space handler\n");
@@ -903,11 +1103,8 @@ static int acpi_ec_add(struct acpi_device *device)
clear_bit(EC_FLAGS_QUERY_PENDING, &ec->flags);
/* Clear stale _Q events if hardware might require that */
- if (EC_FLAGS_CLEAR_ON_RESUME) {
- mutex_lock(&ec->mutex);
+ if (EC_FLAGS_CLEAR_ON_RESUME)
acpi_ec_clear(ec);
- mutex_unlock(&ec->mutex);
- }
return ret;
}
diff --git a/drivers/acpi/event.c b/drivers/acpi/event.c
index ef2d730734dc..e24ea4e796e4 100644
--- a/drivers/acpi/event.c
+++ b/drivers/acpi/event.c
@@ -100,7 +100,6 @@ int acpi_bus_generate_netlink_event(const char *device_class,
struct acpi_genl_event *event;
void *msg_header;
int size;
- int result;
/* allocate memory */
size = nla_total_size(sizeof(struct acpi_genl_event)) +
@@ -137,11 +136,7 @@ int acpi_bus_generate_netlink_event(const char *device_class,
event->data = data;
/* send multicast genetlink message */
- result = genlmsg_end(skb, msg_header);
- if (result < 0) {
- nlmsg_free(skb);
- return result;
- }
+ genlmsg_end(skb, msg_header);
genlmsg_multicast(&acpi_event_genl_family, skb, 0, 0, GFP_ATOMIC);
return 0;
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 163e82f536fa..56b321aa2b1c 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -35,6 +35,13 @@ void acpi_int340x_thermal_init(void);
int acpi_sysfs_init(void);
void acpi_container_init(void);
void acpi_memory_hotplug_init(void);
+#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
+int acpi_ioapic_add(struct acpi_pci_root *root);
+int acpi_ioapic_remove(struct acpi_pci_root *root);
+#else
+static inline int acpi_ioapic_add(struct acpi_pci_root *root) { return 0; }
+static inline int acpi_ioapic_remove(struct acpi_pci_root *root) { return 0; }
+#endif
#ifdef CONFIG_ACPI_DOCK
void register_dock_dependent_device(struct acpi_device *adev,
acpi_handle dshandle);
@@ -68,6 +75,8 @@ static inline void acpi_debugfs_init(void) { return; }
#endif
void acpi_lpss_init(void);
+void acpi_apd_init(void);
+
acpi_status acpi_hotplug_schedule(struct acpi_device *adev, u32 src);
bool acpi_queue_hotplug_work(struct work_struct *work);
void acpi_device_hotplug(struct acpi_device *adev, u32 src);
@@ -122,11 +131,13 @@ struct acpi_ec {
unsigned long data_addr;
unsigned long global_lock;
unsigned long flags;
+ unsigned long reference_count;
struct mutex mutex;
wait_queue_head_t wait;
struct list_head list;
struct transaction *curr;
spinlock_t lock;
+ struct work_struct work;
};
extern struct acpi_ec *first_ec;
diff --git a/drivers/acpi/ioapic.c b/drivers/acpi/ioapic.c
new file mode 100644
index 000000000000..ccdc8db16bb8
--- /dev/null
+++ b/drivers/acpi/ioapic.c
@@ -0,0 +1,229 @@
+/*
+ * IOAPIC/IOxAPIC/IOSAPIC driver
+ *
+ * Copyright (C) 2009 Fujitsu Limited.
+ * (c) Copyright 2009 Hewlett-Packard Development Company, L.P.
+ *
+ * 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 version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Based on original drivers/pci/ioapic.c
+ * Yinghai Lu <yinghai@kernel.org>
+ * Jiang Liu <jiang.liu@intel.com>
+ */
+
+/*
+ * This driver manages I/O APICs added by hotplug after boot.
+ * We try to claim all I/O APIC devices, but those present at boot were
+ * registered when we parsed the ACPI MADT.
+ */
+
+#define pr_fmt(fmt) "ACPI : IOAPIC: " fmt
+
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/pci.h>
+#include <acpi/acpi.h>
+
+struct acpi_pci_ioapic {
+ acpi_handle root_handle;
+ acpi_handle handle;
+ u32 gsi_base;
+ struct resource res;
+ struct pci_dev *pdev;
+ struct list_head list;
+};
+
+static LIST_HEAD(ioapic_list);
+static DEFINE_MUTEX(ioapic_list_lock);
+
+static acpi_status setup_res(struct acpi_resource *acpi_res, void *data)
+{
+ struct resource *res = data;
+ struct resource_win win;
+
+ res->flags = 0;
+ if (acpi_dev_filter_resource_type(acpi_res, IORESOURCE_MEM) == 0)
+ return AE_OK;
+
+ if (!acpi_dev_resource_memory(acpi_res, res)) {
+ if (acpi_dev_resource_address_space(acpi_res, &win) ||
+ acpi_dev_resource_ext_address_space(acpi_res, &win))
+ *res = win.res;
+ }
+ if ((res->flags & IORESOURCE_PREFETCH) ||
+ (res->flags & IORESOURCE_DISABLED))
+ res->flags = 0;
+
+ return AE_CTRL_TERMINATE;
+}
+
+static bool acpi_is_ioapic(acpi_handle handle, char **type)
+{
+ acpi_status status;
+ struct acpi_device_info *info;
+ char *hid = NULL;
+ bool match = false;
+
+ if (!acpi_has_method(handle, "_GSB"))
+ return false;
+
+ status = acpi_get_object_info(handle, &info);
+ if (ACPI_SUCCESS(status)) {
+ if (info->valid & ACPI_VALID_HID)
+ hid = info->hardware_id.string;
+ if (hid) {
+ if (strcmp(hid, "ACPI0009") == 0) {
+ *type = "IOxAPIC";
+ match = true;
+ } else if (strcmp(hid, "ACPI000A") == 0) {
+ *type = "IOAPIC";
+ match = true;
+ }
+ }
+ kfree(info);
+ }
+
+ return match;
+}
+
+static acpi_status handle_ioapic_add(acpi_handle handle, u32 lvl,
+ void *context, void **rv)
+{
+ acpi_status status;
+ unsigned long long gsi_base;
+ struct acpi_pci_ioapic *ioapic;
+ struct pci_dev *dev = NULL;
+ struct resource *res = NULL;
+ char *type = NULL;
+
+ if (!acpi_is_ioapic(handle, &type))
+ return AE_OK;
+
+ mutex_lock(&ioapic_list_lock);
+ list_for_each_entry(ioapic, &ioapic_list, list)
+ if (ioapic->handle == handle) {
+ mutex_unlock(&ioapic_list_lock);
+ return AE_OK;
+ }
+
+ status = acpi_evaluate_integer(handle, "_GSB", NULL, &gsi_base);
+ if (ACPI_FAILURE(status)) {
+ acpi_handle_warn(handle, "failed to evaluate _GSB method\n");
+ goto exit;
+ }
+
+ ioapic = kzalloc(sizeof(*ioapic), GFP_KERNEL);
+ if (!ioapic) {
+ pr_err("cannot allocate memory for new IOAPIC\n");
+ goto exit;
+ } else {
+ ioapic->root_handle = (acpi_handle)context;
+ ioapic->handle = handle;
+ ioapic->gsi_base = (u32)gsi_base;
+ INIT_LIST_HEAD(&ioapic->list);
+ }
+
+ if (acpi_ioapic_registered(handle, (u32)gsi_base))
+ goto done;
+
+ dev = acpi_get_pci_dev(handle);
+ if (dev && pci_resource_len(dev, 0)) {
+ if (pci_enable_device(dev) < 0)
+ goto exit_put;
+ pci_set_master(dev);
+ if (pci_request_region(dev, 0, type))
+ goto exit_disable;
+ res = &dev->resource[0];
+ ioapic->pdev = dev;
+ } else {
+ pci_dev_put(dev);
+ dev = NULL;
+
+ res = &ioapic->res;
+ acpi_walk_resources(handle, METHOD_NAME__CRS, setup_res, res);
+ if (res->flags == 0) {
+ acpi_handle_warn(handle, "failed to get resource\n");
+ goto exit_free;
+ } else if (request_resource(&iomem_resource, res)) {
+ acpi_handle_warn(handle, "failed to insert resource\n");
+ goto exit_free;
+ }
+ }
+
+ if (acpi_register_ioapic(handle, res->start, (u32)gsi_base)) {
+ acpi_handle_warn(handle, "failed to register IOAPIC\n");
+ goto exit_release;
+ }
+done:
+ list_add(&ioapic->list, &ioapic_list);
+ mutex_unlock(&ioapic_list_lock);
+
+ if (dev)
+ dev_info(&dev->dev, "%s at %pR, GSI %u\n",
+ type, res, (u32)gsi_base);
+ else
+ acpi_handle_info(handle, "%s at %pR, GSI %u\n",
+ type, res, (u32)gsi_base);
+
+ return AE_OK;
+
+exit_release:
+ if (dev)
+ pci_release_region(dev, 0);
+ else
+ release_resource(res);
+exit_disable:
+ if (dev)
+ pci_disable_device(dev);
+exit_put:
+ pci_dev_put(dev);
+exit_free:
+ kfree(ioapic);
+exit:
+ mutex_unlock(&ioapic_list_lock);
+ *(acpi_status *)rv = AE_ERROR;
+ return AE_OK;
+}
+
+int acpi_ioapic_add(struct acpi_pci_root *root)
+{
+ acpi_status status, retval = AE_OK;
+
+ status = acpi_walk_namespace(ACPI_TYPE_DEVICE, root->device->handle,
+ UINT_MAX, handle_ioapic_add, NULL,
+ root->device->handle, (void **)&retval);
+
+ return ACPI_SUCCESS(status) && ACPI_SUCCESS(retval) ? 0 : -ENODEV;
+}
+
+int acpi_ioapic_remove(struct acpi_pci_root *root)
+{
+ int retval = 0;
+ struct acpi_pci_ioapic *ioapic, *tmp;
+
+ mutex_lock(&ioapic_list_lock);
+ list_for_each_entry_safe(ioapic, tmp, &ioapic_list, list) {
+ if (root->device->handle != ioapic->root_handle)
+ continue;
+
+ if (acpi_unregister_ioapic(ioapic->handle, ioapic->gsi_base))
+ retval = -EBUSY;
+
+ if (ioapic->pdev) {
+ pci_release_region(ioapic->pdev, 0);
+ pci_disable_device(ioapic->pdev);
+ pci_dev_put(ioapic->pdev);
+ } else if (ioapic->res.flags && ioapic->res.parent) {
+ release_resource(&ioapic->res);
+ }
+ list_del(&ioapic->list);
+ kfree(ioapic);
+ }
+ mutex_unlock(&ioapic_list_lock);
+
+ return retval;
+}
diff --git a/drivers/acpi/numa.c b/drivers/acpi/numa.c
index 24b5476449a1..1333cbdc3ea2 100644
--- a/drivers/acpi/numa.c
+++ b/drivers/acpi/numa.c
@@ -177,12 +177,7 @@ static int __init slit_valid(struct acpi_table_slit *slit)
static int __init acpi_parse_slit(struct acpi_table_header *table)
{
- struct acpi_table_slit *slit;
-
- if (!table)
- return -EINVAL;
-
- slit = (struct acpi_table_slit *)table;
+ struct acpi_table_slit *slit = (struct acpi_table_slit *)table;
if (!slit_valid(slit)) {
printk(KERN_INFO "ACPI: SLIT table looks invalid. Not used.\n");
@@ -260,11 +255,8 @@ acpi_parse_memory_affinity(struct acpi_subtable_header * header,
static int __init acpi_parse_srat(struct acpi_table_header *table)
{
- struct acpi_table_srat *srat;
- if (!table)
- return -EINVAL;
+ struct acpi_table_srat *srat = (struct acpi_table_srat *)table;
- srat = (struct acpi_table_srat *)table;
acpi_srat_revision = srat->header.revision;
/* Real work done in acpi_table_parse_srat below. */
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index b1def411c0b8..e7f718d6918a 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -485,14 +485,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
if (!pin || !dev->irq_managed || dev->irq <= 0)
return;
- /* Keep IOAPIC pin configuration when suspending */
- if (dev->dev.power.is_prepared)
- return;
-#ifdef CONFIG_PM
- if (dev->dev.power.runtime_status == RPM_SUSPENDING)
- return;
-#endif
-
entry = acpi_pci_irq_lookup(dev, pin);
if (!entry)
return;
@@ -513,5 +505,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
if (gsi >= 0) {
acpi_unregister_gsi(gsi);
dev->irq_managed = 0;
+ dev->irq = 0;
}
}
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index c6bcb8c719d8..68a5f712cd19 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -112,10 +112,10 @@ get_root_bridge_busnr_callback(struct acpi_resource *resource, void *data)
if (ACPI_FAILURE(status))
return AE_OK;
- if ((address.address_length > 0) &&
+ if ((address.address.address_length > 0) &&
(address.resource_type == ACPI_BUS_NUMBER_RANGE)) {
- res->start = address.minimum;
- res->end = address.minimum + address.address_length - 1;
+ res->start = address.address.minimum;
+ res->end = address.address.minimum + address.address.address_length - 1;
}
return AE_OK;
@@ -621,6 +621,7 @@ static int acpi_pci_root_add(struct acpi_device *device,
if (hotadd) {
pcibios_resource_survey_bus(root->bus);
pci_assign_unassigned_root_bus_resources(root->bus);
+ acpi_ioapic_add(root);
}
pci_lock_rescan_remove();
@@ -644,6 +645,8 @@ static void acpi_pci_root_remove(struct acpi_device *device)
pci_stop_root_bus(root->bus);
+ WARN_ON(acpi_ioapic_remove(root));
+
device_set_run_wake(root->bus->bridge, false);
pci_acpi_remove_bus_pm_notifier(device);
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
index a732e5d7e322..bd772cd56494 100644
--- a/drivers/acpi/pmic/intel_pmic.c
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -16,20 +16,15 @@
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
+#include <acpi/acpi_lpat.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 acpi_lpat_conversion_table *lpat_table;
struct regmap *regmap;
struct intel_pmic_opregion_data *data;
};
@@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table,
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)
@@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion,
if (raw_temp < 0)
return raw_temp;
- if (!opregion->lpat) {
+ if (!opregion->lpat_table) {
*value = raw_temp;
return 0;
}
- temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);
+ temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp);
if (temp < 0)
return temp;
@@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
if (!opregion->data->update_aux)
return -ENXIO;
- if (opregion->lpat) {
- raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
- *value);
+ if (opregion->lpat_table) {
+ raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);
if (raw_temp < 0)
return raw_temp;
} else {
@@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
{
acpi_status status;
struct intel_pmic_opregion *opregion;
+ int ret;
if (!dev || !regmap || !d)
return -EINVAL;
@@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
mutex_init(&opregion->lock);
opregion->regmap = regmap;
- pmic_thermal_lpat(opregion, handle, dev);
+ opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
status = acpi_install_address_space_handler(handle,
PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler,
NULL, opregion);
- if (ACPI_FAILURE(status))
- return -ENODEV;
+ if (ACPI_FAILURE(status)) {
+ ret = -ENODEV;
+ goto out_error;
+ }
status = acpi_install_address_space_handler(handle,
PMIC_THERMAL_OPREGION_ID,
@@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
if (ACPI_FAILURE(status)) {
acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler);
- return -ENODEV;
+ ret = -ENODEV;
+ goto out_error;
}
opregion->data = d;
return 0;
+
+out_error:
+ acpi_lpat_free_conversion_table(opregion->lpat_table);
+ return ret;
}
EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
diff --git a/drivers/acpi/processor_core.c b/drivers/acpi/processor_core.c
index 02e48394276c..7962651cdbd4 100644
--- a/drivers/acpi/processor_core.c
+++ b/drivers/acpi/processor_core.c
@@ -4,6 +4,10 @@
*
* Alex Chiang <achiang@hp.com>
* - Unified x86/ia64 implementations
+ *
+ * I/O APIC hotplug support
+ * Yinghai Lu <yinghai@kernel.org>
+ * Jiang Liu <jiang.liu@intel.com>
*/
#include <linux/export.h>
#include <linux/acpi.h>
@@ -12,6 +16,21 @@
#define _COMPONENT ACPI_PROCESSOR_COMPONENT
ACPI_MODULE_NAME("processor_core");
+static struct acpi_table_madt *get_madt_table(void)
+{
+ static struct acpi_table_madt *madt;
+ static int read_madt;
+
+ if (!read_madt) {
+ if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
+ (struct acpi_table_header **)&madt)))
+ madt = NULL;
+ read_madt++;
+ }
+
+ return madt;
+}
+
static int map_lapic_id(struct acpi_subtable_header *entry,
u32 acpi_id, int *apic_id)
{
@@ -67,17 +86,10 @@ static int map_lsapic_id(struct acpi_subtable_header *entry,
static int map_madt_entry(int type, u32 acpi_id)
{
unsigned long madt_end, entry;
- static struct acpi_table_madt *madt;
- static int read_madt;
int phys_id = -1; /* CPU hardware ID */
+ struct acpi_table_madt *madt;
- if (!read_madt) {
- if (ACPI_FAILURE(acpi_get_table(ACPI_SIG_MADT, 0,
- (struct acpi_table_header **)&madt)))
- madt = NULL;
- read_madt++;
- }
-
+ madt = get_madt_table();
if (!madt)
return phys_id;
@@ -203,3 +215,96 @@ int acpi_get_cpuid(acpi_handle handle, int type, u32 acpi_id)
return acpi_map_cpuid(phys_id, acpi_id);
}
EXPORT_SYMBOL_GPL(acpi_get_cpuid);
+
+#ifdef CONFIG_ACPI_HOTPLUG_IOAPIC
+static int get_ioapic_id(struct acpi_subtable_header *entry, u32 gsi_base,
+ u64 *phys_addr, int *ioapic_id)
+{
+ struct acpi_madt_io_apic *ioapic = (struct acpi_madt_io_apic *)entry;
+
+ if (ioapic->global_irq_base != gsi_base)
+ return 0;
+
+ *phys_addr = ioapic->address;
+ *ioapic_id = ioapic->id;
+ return 1;
+}
+
+static int parse_madt_ioapic_entry(u32 gsi_base, u64 *phys_addr)
+{
+ struct acpi_subtable_header *hdr;
+ unsigned long madt_end, entry;
+ struct acpi_table_madt *madt;
+ int apic_id = -1;
+
+ madt = get_madt_table();
+ if (!madt)
+ return apic_id;
+
+ entry = (unsigned long)madt;
+ madt_end = entry + madt->header.length;
+
+ /* Parse all entries looking for a match. */
+ entry += sizeof(struct acpi_table_madt);
+ while (entry + sizeof(struct acpi_subtable_header) < madt_end) {
+ hdr = (struct acpi_subtable_header *)entry;
+ if (hdr->type == ACPI_MADT_TYPE_IO_APIC &&
+ get_ioapic_id(hdr, gsi_base, phys_addr, &apic_id))
+ break;
+ else
+ entry += hdr->length;
+ }
+
+ return apic_id;
+}
+
+static int parse_mat_ioapic_entry(acpi_handle handle, u32 gsi_base,
+ u64 *phys_addr)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ struct acpi_subtable_header *header;
+ union acpi_object *obj;
+ int apic_id = -1;
+
+ if (ACPI_FAILURE(acpi_evaluate_object(handle, "_MAT", NULL, &buffer)))
+ goto exit;
+
+ if (!buffer.length || !buffer.pointer)
+ goto exit;
+
+ obj = buffer.pointer;
+ if (obj->type != ACPI_TYPE_BUFFER ||
+ obj->buffer.length < sizeof(struct acpi_subtable_header))
+ goto exit;
+
+ header = (struct acpi_subtable_header *)obj->buffer.pointer;
+ if (header->type == ACPI_MADT_TYPE_IO_APIC)
+ get_ioapic_id(header, gsi_base, phys_addr, &apic_id);
+
+exit:
+ kfree(buffer.pointer);
+ return apic_id;
+}
+
+/**
+ * acpi_get_ioapic_id - Get IOAPIC ID and physical address matching @gsi_base
+ * @handle: ACPI object for IOAPIC device
+ * @gsi_base: GSI base to match with
+ * @phys_addr: Pointer to store physical address of matching IOAPIC record
+ *
+ * Walk resources returned by ACPI_MAT method, then ACPI MADT table, to search
+ * for an ACPI IOAPIC record matching @gsi_base.
+ * Return IOAPIC id and store physical address in @phys_addr if found a match,
+ * otherwise return <0.
+ */
+int acpi_get_ioapic_id(acpi_handle handle, u32 gsi_base, u64 *phys_addr)
+{
+ int apic_id;
+
+ apic_id = parse_mat_ioapic_entry(handle, gsi_base, phys_addr);
+ if (apic_id == -1)
+ apic_id = parse_madt_ioapic_entry(gsi_base, phys_addr);
+
+ return apic_id;
+}
+#endif /* CONFIG_ACPI_HOTPLUG_IOAPIC */
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 87b704e41877..c6bb9f1257c9 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -681,15 +681,13 @@ static int acpi_idle_bm_check(void)
}
/**
- * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
+ * acpi_idle_do_entry - enter idle state using the appropriate method
* @cx: cstate data
*
* Caller disables interrupt before call and enables interrupt after return.
*/
-static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
+static void acpi_idle_do_entry(struct acpi_processor_cx *cx)
{
- /* Don't trace irqs off for idle */
- stop_critical_timings();
if (cx->entry_method == ACPI_CSTATE_FFH) {
/* Call into architectural FFH based C-state */
acpi_processor_ffh_cstate_enter(cx);
@@ -703,38 +701,9 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
gets asserted in time to freeze execution properly. */
inl(acpi_gbl_FADT.xpm_timer_block.address);
}
- start_critical_timings();
}
/**
- * acpi_idle_enter_c1 - enters an ACPI C1 state-type
- * @dev: the target CPU
- * @drv: cpuidle driver containing cpuidle state info
- * @index: index of target state
- *
- * This is equivalent to the HALT instruction.
- */
-static int acpi_idle_enter_c1(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
-{
- struct acpi_processor *pr;
- struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
-
- pr = __this_cpu_read(processors);
-
- if (unlikely(!pr))
- return -EINVAL;
-
- lapic_timer_state_broadcast(pr, cx, 1);
- acpi_idle_do_entry(cx);
-
- lapic_timer_state_broadcast(pr, cx, 0);
-
- return index;
-}
-
-
-/**
* acpi_idle_play_dead - enters an ACPI state for long-term idle (i.e. off-lining)
* @dev: the target CPU
* @index: the index of suggested state
@@ -761,47 +730,10 @@ static int acpi_idle_play_dead(struct cpuidle_device *dev, int index)
return 0;
}
-/**
- * acpi_idle_enter_simple - enters an ACPI state without BM handling
- * @dev: the target CPU
- * @drv: cpuidle driver with cpuidle state information
- * @index: the index of suggested state
- */
-static int acpi_idle_enter_simple(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static bool acpi_idle_fallback_to_c1(struct acpi_processor *pr)
{
- struct acpi_processor *pr;
- struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
-
- pr = __this_cpu_read(processors);
-
- if (unlikely(!pr))
- return -EINVAL;
-
-#ifdef CONFIG_HOTPLUG_CPU
- if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst &&
- !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
- return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START);
-#endif
-
- /*
- * Must be done before busmaster disable as we might need to
- * access HPET !
- */
- lapic_timer_state_broadcast(pr, cx, 1);
-
- if (cx->type == ACPI_STATE_C3)
- ACPI_FLUSH_CPU_CACHE();
-
- /* Tell the scheduler that we are going deep-idle: */
- sched_clock_idle_sleep_event();
- acpi_idle_do_entry(cx);
-
- sched_clock_idle_wakeup_event(0);
-
- lapic_timer_state_broadcast(pr, cx, 0);
- return index;
+ return IS_ENABLED(CONFIG_HOTPLUG_CPU) && !pr->flags.has_cst &&
+ !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED);
}
static int c3_cpu_count;
@@ -809,87 +741,115 @@ static DEFINE_RAW_SPINLOCK(c3_lock);
/**
* acpi_idle_enter_bm - enters C3 with proper BM handling
- * @dev: the target CPU
- * @drv: cpuidle driver containing state data
- * @index: the index of suggested state
- *
- * If BM is detected, the deepest non-C3 idle state is entered instead.
+ * @pr: Target processor
+ * @cx: Target state context
+ * @timer_bc: Whether or not to change timer mode to broadcast
*/
-static int acpi_idle_enter_bm(struct cpuidle_device *dev,
- struct cpuidle_driver *drv, int index)
+static void acpi_idle_enter_bm(struct acpi_processor *pr,
+ struct acpi_processor_cx *cx, bool timer_bc)
{
- struct acpi_processor *pr;
- struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
-
- pr = __this_cpu_read(processors);
-
- if (unlikely(!pr))
- return -EINVAL;
-
-#ifdef CONFIG_HOTPLUG_CPU
- if ((cx->type != ACPI_STATE_C1) && (num_online_cpus() > 1) &&
- !pr->flags.has_cst &&
- !(acpi_gbl_FADT.flags & ACPI_FADT_C2_MP_SUPPORTED))
- return acpi_idle_enter_c1(dev, drv, CPUIDLE_DRIVER_STATE_START);
-#endif
-
- if (!cx->bm_sts_skip && acpi_idle_bm_check()) {
- if (drv->safe_state_index >= 0) {
- return drv->states[drv->safe_state_index].enter(dev,
- drv, drv->safe_state_index);
- } else {
- acpi_safe_halt();
- return -EBUSY;
- }
- }
-
acpi_unlazy_tlb(smp_processor_id());
- /* Tell the scheduler that we are going deep-idle: */
- sched_clock_idle_sleep_event();
/*
* Must be done before busmaster disable as we might need to
* access HPET !
*/
- lapic_timer_state_broadcast(pr, cx, 1);
+ if (timer_bc)
+ lapic_timer_state_broadcast(pr, cx, 1);
/*
* disable bus master
* bm_check implies we need ARB_DIS
- * !bm_check implies we need cache flush
* bm_control implies whether we can do ARB_DIS
*
* That leaves a case where bm_check is set and bm_control is
* not set. In that case we cannot do much, we enter C3
* without doing anything.
*/
- if (pr->flags.bm_check && pr->flags.bm_control) {
+ if (pr->flags.bm_control) {
raw_spin_lock(&c3_lock);
c3_cpu_count++;
/* Disable bus master arbitration when all CPUs are in C3 */
if (c3_cpu_count == num_online_cpus())
acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 1);
raw_spin_unlock(&c3_lock);
- } else if (!pr->flags.bm_check) {
- ACPI_FLUSH_CPU_CACHE();
}
acpi_idle_do_entry(cx);
/* Re-enable bus master arbitration */
- if (pr->flags.bm_check && pr->flags.bm_control) {
+ if (pr->flags.bm_control) {
raw_spin_lock(&c3_lock);
acpi_write_bit_register(ACPI_BITREG_ARB_DISABLE, 0);
c3_cpu_count--;
raw_spin_unlock(&c3_lock);
}
- sched_clock_idle_wakeup_event(0);
+ if (timer_bc)
+ lapic_timer_state_broadcast(pr, cx, 0);
+}
+
+static int acpi_idle_enter(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
+ struct acpi_processor *pr;
+
+ pr = __this_cpu_read(processors);
+ if (unlikely(!pr))
+ return -EINVAL;
+
+ if (cx->type != ACPI_STATE_C1) {
+ if (acpi_idle_fallback_to_c1(pr) && num_online_cpus() > 1) {
+ index = CPUIDLE_DRIVER_STATE_START;
+ cx = per_cpu(acpi_cstate[index], dev->cpu);
+ } else if (cx->type == ACPI_STATE_C3 && pr->flags.bm_check) {
+ if (cx->bm_sts_skip || !acpi_idle_bm_check()) {
+ acpi_idle_enter_bm(pr, cx, true);
+ return index;
+ } else if (drv->safe_state_index >= 0) {
+ index = drv->safe_state_index;
+ cx = per_cpu(acpi_cstate[index], dev->cpu);
+ } else {
+ acpi_safe_halt();
+ return -EBUSY;
+ }
+ }
+ }
+
+ lapic_timer_state_broadcast(pr, cx, 1);
+
+ if (cx->type == ACPI_STATE_C3)
+ ACPI_FLUSH_CPU_CACHE();
+
+ acpi_idle_do_entry(cx);
lapic_timer_state_broadcast(pr, cx, 0);
+
return index;
}
+static void acpi_idle_enter_freeze(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ struct acpi_processor_cx *cx = per_cpu(acpi_cstate[index], dev->cpu);
+
+ if (cx->type == ACPI_STATE_C3) {
+ struct acpi_processor *pr = __this_cpu_read(processors);
+
+ if (unlikely(!pr))
+ return;
+
+ if (pr->flags.bm_check) {
+ acpi_idle_enter_bm(pr, cx, false);
+ return;
+ } else {
+ ACPI_FLUSH_CPU_CACHE();
+ }
+ }
+ acpi_idle_do_entry(cx);
+}
+
struct cpuidle_driver acpi_idle_driver = {
.name = "acpi_idle",
.owner = THIS_MODULE,
@@ -981,28 +941,22 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
strncpy(state->desc, cx->desc, CPUIDLE_DESC_LEN);
state->exit_latency = cx->latency;
state->target_residency = cx->latency * latency_factor;
+ state->enter = acpi_idle_enter;
state->flags = 0;
- switch (cx->type) {
- case ACPI_STATE_C1:
-
- state->enter = acpi_idle_enter_c1;
- state->enter_dead = acpi_idle_play_dead;
- drv->safe_state_index = count;
- break;
-
- case ACPI_STATE_C2:
- state->enter = acpi_idle_enter_simple;
+ if (cx->type == ACPI_STATE_C1 || cx->type == ACPI_STATE_C2) {
state->enter_dead = acpi_idle_play_dead;
drv->safe_state_index = count;
- break;
-
- case ACPI_STATE_C3:
- state->enter = pr->flags.bm_check ?
- acpi_idle_enter_bm :
- acpi_idle_enter_simple;
- break;
}
+ /*
+ * Halt-induced C1 is not good for ->enter_freeze, because it
+ * re-enables interrupts on exit. Moreover, C1 is generally not
+ * particularly interesting from the suspend-to-idle angle, so
+ * avoid C1 and the situations in which we may need to fall back
+ * to it altogether.
+ */
+ if (cx->type != ACPI_STATE_C1 && !acpi_idle_fallback_to_c1(pr))
+ state->enter_freeze = acpi_idle_enter_freeze;
count++;
if (count == CPUIDLE_STATE_MAX)
diff --git a/drivers/acpi/resource.c b/drivers/acpi/resource.c
index 782a0d15c25f..c723668e3e27 100644
--- a/drivers/acpi/resource.c
+++ b/drivers/acpi/resource.c
@@ -34,21 +34,34 @@
#define valid_IRQ(i) (true)
#endif
-static unsigned long acpi_dev_memresource_flags(u64 len, u8 write_protect,
- bool window)
+static bool acpi_dev_resource_len_valid(u64 start, u64 end, u64 len, bool io)
{
- unsigned long flags = IORESOURCE_MEM;
+ u64 reslen = end - start + 1;
- if (len == 0)
- flags |= IORESOURCE_DISABLED;
+ /*
+ * CHECKME: len might be required to check versus a minimum
+ * length as well. 1 for io is fine, but for memory it does
+ * not make any sense at all.
+ */
+ if (len && reslen && reslen == len && start <= end)
+ return true;
- if (write_protect == ACPI_READ_WRITE_MEMORY)
- flags |= IORESOURCE_MEM_WRITEABLE;
+ pr_debug("ACPI: invalid or unassigned resource %s [%016llx - %016llx] length [%016llx]\n",
+ io ? "io" : "mem", start, end, len);
+
+ return false;
+}
+
+static void acpi_dev_memresource_flags(struct resource *res, u64 len,
+ u8 write_protect)
+{
+ res->flags = IORESOURCE_MEM;
- if (window)
- flags |= IORESOURCE_WINDOW;
+ if (!acpi_dev_resource_len_valid(res->start, res->end, len, false))
+ res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
- return flags;
+ if (write_protect == ACPI_READ_WRITE_MEMORY)
+ res->flags |= IORESOURCE_MEM_WRITEABLE;
}
static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
@@ -56,7 +69,7 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
{
res->start = start;
res->end = start + len - 1;
- res->flags = acpi_dev_memresource_flags(len, write_protect, false);
+ acpi_dev_memresource_flags(res, len, write_protect);
}
/**
@@ -67,6 +80,11 @@ static void acpi_dev_get_memresource(struct resource *res, u64 start, u64 len,
* Check if the given ACPI resource object represents a memory resource and
* if that's the case, use the information in it to populate the generic
* resource object pointed to by @res.
+ *
+ * Return:
+ * 1) false with res->flags setting to zero: not the expected resource type
+ * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
+ * 3) true: valid assigned resource
*/
bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
{
@@ -77,60 +95,52 @@ bool acpi_dev_resource_memory(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_MEMORY24:
memory24 = &ares->data.memory24;
- if (!memory24->minimum && !memory24->address_length)
- return false;
- acpi_dev_get_memresource(res, memory24->minimum,
- memory24->address_length,
+ acpi_dev_get_memresource(res, memory24->minimum << 8,
+ memory24->address_length << 8,
memory24->write_protect);
break;
case ACPI_RESOURCE_TYPE_MEMORY32:
memory32 = &ares->data.memory32;
- if (!memory32->minimum && !memory32->address_length)
- return false;
acpi_dev_get_memresource(res, memory32->minimum,
memory32->address_length,
memory32->write_protect);
break;
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
fixed_memory32 = &ares->data.fixed_memory32;
- if (!fixed_memory32->address && !fixed_memory32->address_length)
- return false;
acpi_dev_get_memresource(res, fixed_memory32->address,
fixed_memory32->address_length,
fixed_memory32->write_protect);
break;
default:
+ res->flags = 0;
return false;
}
- return true;
+
+ return !(res->flags & IORESOURCE_DISABLED);
}
EXPORT_SYMBOL_GPL(acpi_dev_resource_memory);
-static unsigned int acpi_dev_ioresource_flags(u64 start, u64 end, u8 io_decode,
- bool window)
+static void acpi_dev_ioresource_flags(struct resource *res, u64 len,
+ u8 io_decode)
{
- int flags = IORESOURCE_IO;
+ res->flags = IORESOURCE_IO;
- if (io_decode == ACPI_DECODE_16)
- flags |= IORESOURCE_IO_16BIT_ADDR;
+ if (!acpi_dev_resource_len_valid(res->start, res->end, len, true))
+ res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
- if (start > end || end >= 0x10003)
- flags |= IORESOURCE_DISABLED;
+ if (res->end >= 0x10003)
+ res->flags |= IORESOURCE_DISABLED | IORESOURCE_UNSET;
- if (window)
- flags |= IORESOURCE_WINDOW;
-
- return flags;
+ if (io_decode == ACPI_DECODE_16)
+ res->flags |= IORESOURCE_IO_16BIT_ADDR;
}
static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
u8 io_decode)
{
- u64 end = start + len - 1;
-
res->start = start;
- res->end = end;
- res->flags = acpi_dev_ioresource_flags(start, end, io_decode, false);
+ res->end = start + len - 1;
+ acpi_dev_ioresource_flags(res, len, io_decode);
}
/**
@@ -141,6 +151,11 @@ static void acpi_dev_get_ioresource(struct resource *res, u64 start, u64 len,
* Check if the given ACPI resource object represents an I/O resource and
* if that's the case, use the information in it to populate the generic
* resource object pointed to by @res.
+ *
+ * Return:
+ * 1) false with res->flags setting to zero: not the expected resource type
+ * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
+ * 3) true: valid assigned resource
*/
bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
{
@@ -150,135 +165,143 @@ bool acpi_dev_resource_io(struct acpi_resource *ares, struct resource *res)
switch (ares->type) {
case ACPI_RESOURCE_TYPE_IO:
io = &ares->data.io;
- if (!io->minimum && !io->address_length)
- return false;
acpi_dev_get_ioresource(res, io->minimum,
io->address_length,
io->io_decode);
break;
case ACPI_RESOURCE_TYPE_FIXED_IO:
fixed_io = &ares->data.fixed_io;
- if (!fixed_io->address && !fixed_io->address_length)
- return false;
acpi_dev_get_ioresource(res, fixed_io->address,
fixed_io->address_length,
ACPI_DECODE_10);
break;
default:
+ res->flags = 0;
return false;
}
- return true;
+
+ return !(res->flags & IORESOURCE_DISABLED);
}
EXPORT_SYMBOL_GPL(acpi_dev_resource_io);
-/**
- * acpi_dev_resource_address_space - Extract ACPI address space information.
- * @ares: Input ACPI resource object.
- * @res: Output generic resource object.
- *
- * Check if the given ACPI resource object represents an address space resource
- * and if that's the case, use the information in it to populate the generic
- * resource object pointed to by @res.
- */
-bool acpi_dev_resource_address_space(struct acpi_resource *ares,
- struct resource *res)
+static bool acpi_decode_space(struct resource_win *win,
+ struct acpi_resource_address *addr,
+ struct acpi_address64_attribute *attr)
{
- acpi_status status;
- struct acpi_resource_address64 addr;
- bool window;
- u64 len;
- u8 io_decode;
+ u8 iodec = attr->granularity == 0xfff ? ACPI_DECODE_10 : ACPI_DECODE_16;
+ bool wp = addr->info.mem.write_protect;
+ u64 len = attr->address_length;
+ struct resource *res = &win->res;
- switch (ares->type) {
- case ACPI_RESOURCE_TYPE_ADDRESS16:
- case ACPI_RESOURCE_TYPE_ADDRESS32:
- case ACPI_RESOURCE_TYPE_ADDRESS64:
- break;
- default:
- return false;
- }
+ /*
+ * Filter out invalid descriptor according to ACPI Spec 5.0, section
+ * 6.4.3.5 Address Space Resource Descriptors.
+ */
+ if ((addr->min_address_fixed != addr->max_address_fixed && len) ||
+ (addr->min_address_fixed && addr->max_address_fixed && !len))
+ pr_debug("ACPI: Invalid address space min_addr_fix %d, max_addr_fix %d, len %llx\n",
+ addr->min_address_fixed, addr->max_address_fixed, len);
- status = acpi_resource_to_address64(ares, &addr);
- if (ACPI_FAILURE(status))
- return false;
+ res->start = attr->minimum;
+ res->end = attr->maximum;
- res->start = addr.minimum;
- res->end = addr.maximum;
- window = addr.producer_consumer == ACPI_PRODUCER;
+ /*
+ * For bridges that translate addresses across the bridge,
+ * translation_offset is the offset that must be added to the
+ * address on the secondary side to obtain the address on the
+ * primary side. Non-bridge devices must list 0 for all Address
+ * Translation offset bits.
+ */
+ if (addr->producer_consumer == ACPI_PRODUCER) {
+ res->start += attr->translation_offset;
+ res->end += attr->translation_offset;
+ } else if (attr->translation_offset) {
+ pr_debug("ACPI: translation_offset(%lld) is invalid for non-bridge device.\n",
+ attr->translation_offset);
+ }
- switch(addr.resource_type) {
+ switch (addr->resource_type) {
case ACPI_MEMORY_RANGE:
- len = addr.maximum - addr.minimum + 1;
- res->flags = acpi_dev_memresource_flags(len,
- addr.info.mem.write_protect,
- window);
+ acpi_dev_memresource_flags(res, len, wp);
break;
case ACPI_IO_RANGE:
- io_decode = addr.granularity == 0xfff ?
- ACPI_DECODE_10 : ACPI_DECODE_16;
- res->flags = acpi_dev_ioresource_flags(addr.minimum,
- addr.maximum,
- io_decode, window);
+ acpi_dev_ioresource_flags(res, len, iodec);
break;
case ACPI_BUS_NUMBER_RANGE:
res->flags = IORESOURCE_BUS;
break;
default:
- res->flags = 0;
+ return false;
}
- return true;
+ win->offset = attr->translation_offset;
+
+ if (addr->producer_consumer == ACPI_PRODUCER)
+ res->flags |= IORESOURCE_WINDOW;
+
+ if (addr->info.mem.caching == ACPI_PREFETCHABLE_MEMORY)
+ res->flags |= IORESOURCE_PREFETCH;
+
+ return !(res->flags & IORESOURCE_DISABLED);
+}
+
+/**
+ * acpi_dev_resource_address_space - Extract ACPI address space information.
+ * @ares: Input ACPI resource object.
+ * @win: Output generic resource object.
+ *
+ * Check if the given ACPI resource object represents an address space resource
+ * and if that's the case, use the information in it to populate the generic
+ * resource object pointed to by @win.
+ *
+ * Return:
+ * 1) false with win->res.flags setting to zero: not the expected resource type
+ * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned
+ * resource
+ * 3) true: valid assigned resource
+ */
+bool acpi_dev_resource_address_space(struct acpi_resource *ares,
+ struct resource_win *win)
+{
+ struct acpi_resource_address64 addr;
+
+ win->res.flags = 0;
+ if (ACPI_FAILURE(acpi_resource_to_address64(ares, &addr)))
+ return false;
+
+ return acpi_decode_space(win, (struct acpi_resource_address *)&addr,
+ &addr.address);
}
EXPORT_SYMBOL_GPL(acpi_dev_resource_address_space);
/**
* acpi_dev_resource_ext_address_space - Extract ACPI address space information.
* @ares: Input ACPI resource object.
- * @res: Output generic resource object.
+ * @win: Output generic resource object.
*
* Check if the given ACPI resource object represents an extended address space
* resource and if that's the case, use the information in it to populate the
- * generic resource object pointed to by @res.
+ * generic resource object pointed to by @win.
+ *
+ * Return:
+ * 1) false with win->res.flags setting to zero: not the expected resource type
+ * 2) false with IORESOURCE_DISABLED in win->res.flags: valid unassigned
+ * resource
+ * 3) true: valid assigned resource
*/
bool acpi_dev_resource_ext_address_space(struct acpi_resource *ares,
- struct resource *res)
+ struct resource_win *win)
{
struct acpi_resource_extended_address64 *ext_addr;
- bool window;
- u64 len;
- u8 io_decode;
+ win->res.flags = 0;
if (ares->type != ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64)
return false;
ext_addr = &ares->data.ext_address64;
- res->start = ext_addr->minimum;
- res->end = ext_addr->maximum;
- window = ext_addr->producer_consumer == ACPI_PRODUCER;
-
- switch(ext_addr->resource_type) {
- case ACPI_MEMORY_RANGE:
- len = ext_addr->maximum - ext_addr->minimum + 1;
- res->flags = acpi_dev_memresource_flags(len,
- ext_addr->info.mem.write_protect,
- window);
- break;
- case ACPI_IO_RANGE:
- io_decode = ext_addr->granularity == 0xfff ?
- ACPI_DECODE_10 : ACPI_DECODE_16;
- res->flags = acpi_dev_ioresource_flags(ext_addr->minimum,
- ext_addr->maximum,
- io_decode, window);
- break;
- case ACPI_BUS_NUMBER_RANGE:
- res->flags = IORESOURCE_BUS;
- break;
- default:
- res->flags = 0;
- }
-
- return true;
+ return acpi_decode_space(win, (struct acpi_resource_address *)ext_addr,
+ &ext_addr->address);
}
EXPORT_SYMBOL_GPL(acpi_dev_resource_ext_address_space);
@@ -310,7 +333,7 @@ static void acpi_dev_irqresource_disabled(struct resource *res, u32 gsi)
{
res->start = gsi;
res->end = gsi;
- res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED;
+ res->flags = IORESOURCE_IRQ | IORESOURCE_DISABLED | IORESOURCE_UNSET;
}
static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
@@ -369,6 +392,11 @@ static void acpi_dev_get_irqresource(struct resource *res, u32 gsi,
* represented by the resource and populate the generic resource object pointed
* to by @res accordingly. If the registration of the GSI is not successful,
* IORESOURCE_DISABLED will be set it that object's flags.
+ *
+ * Return:
+ * 1) false with res->flags setting to zero: not the expected resource type
+ * 2) false with IORESOURCE_DISABLED in res->flags: valid unassigned resource
+ * 3) true: valid assigned resource
*/
bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
struct resource *res)
@@ -402,6 +430,7 @@ bool acpi_dev_resource_interrupt(struct acpi_resource *ares, int index,
ext_irq->sharable, false);
break;
default:
+ res->flags = 0;
return false;
}
@@ -415,12 +444,7 @@ EXPORT_SYMBOL_GPL(acpi_dev_resource_interrupt);
*/
void acpi_dev_free_resource_list(struct list_head *list)
{
- struct resource_list_entry *rentry, *re;
-
- list_for_each_entry_safe(rentry, re, list, node) {
- list_del(&rentry->node);
- kfree(rentry);
- }
+ resource_list_free(list);
}
EXPORT_SYMBOL_GPL(acpi_dev_free_resource_list);
@@ -432,18 +456,19 @@ struct res_proc_context {
int error;
};
-static acpi_status acpi_dev_new_resource_entry(struct resource *r,
+static acpi_status acpi_dev_new_resource_entry(struct resource_win *win,
struct res_proc_context *c)
{
- struct resource_list_entry *rentry;
+ struct resource_entry *rentry;
- rentry = kmalloc(sizeof(*rentry), GFP_KERNEL);
+ rentry = resource_list_create_entry(NULL, 0);
if (!rentry) {
c->error = -ENOMEM;
return AE_NO_MEMORY;
}
- rentry->res = *r;
- list_add_tail(&rentry->node, c->list);
+ *rentry->res = win->res;
+ rentry->offset = win->offset;
+ resource_list_add_tail(rentry, c->list);
c->count++;
return AE_OK;
}
@@ -452,7 +477,8 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
void *context)
{
struct res_proc_context *c = context;
- struct resource r;
+ struct resource_win win;
+ struct resource *res = &win.res;
int i;
if (c->preproc) {
@@ -467,18 +493,18 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
}
}
- memset(&r, 0, sizeof(r));
+ memset(&win, 0, sizeof(win));
- if (acpi_dev_resource_memory(ares, &r)
- || acpi_dev_resource_io(ares, &r)
- || acpi_dev_resource_address_space(ares, &r)
- || acpi_dev_resource_ext_address_space(ares, &r))
- return acpi_dev_new_resource_entry(&r, c);
+ if (acpi_dev_resource_memory(ares, res)
+ || acpi_dev_resource_io(ares, res)
+ || acpi_dev_resource_address_space(ares, &win)
+ || acpi_dev_resource_ext_address_space(ares, &win))
+ return acpi_dev_new_resource_entry(&win, c);
- for (i = 0; acpi_dev_resource_interrupt(ares, i, &r); i++) {
+ for (i = 0; acpi_dev_resource_interrupt(ares, i, res); i++) {
acpi_status status;
- status = acpi_dev_new_resource_entry(&r, c);
+ status = acpi_dev_new_resource_entry(&win, c);
if (ACPI_FAILURE(status))
return status;
}
@@ -503,7 +529,7 @@ static acpi_status acpi_dev_process_resource(struct acpi_resource *ares,
* returned as the final error code.
*
* The resultant struct resource objects are put on the list pointed to by
- * @list, that must be empty initially, as members of struct resource_list_entry
+ * @list, that must be empty initially, as members of struct resource_entry
* objects. Callers of this routine should use %acpi_dev_free_resource_list() to
* free that list.
*
@@ -538,3 +564,58 @@ int acpi_dev_get_resources(struct acpi_device *adev, struct list_head *list,
return c.count;
}
EXPORT_SYMBOL_GPL(acpi_dev_get_resources);
+
+/**
+ * acpi_dev_filter_resource_type - Filter ACPI resource according to resource
+ * types
+ * @ares: Input ACPI resource object.
+ * @types: Valid resource types of IORESOURCE_XXX
+ *
+ * This is a hepler function to support acpi_dev_get_resources(), which filters
+ * ACPI resource objects according to resource types.
+ */
+int acpi_dev_filter_resource_type(struct acpi_resource *ares,
+ unsigned long types)
+{
+ unsigned long type = 0;
+
+ switch (ares->type) {
+ case ACPI_RESOURCE_TYPE_MEMORY24:
+ case ACPI_RESOURCE_TYPE_MEMORY32:
+ case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
+ type = IORESOURCE_MEM;
+ break;
+ case ACPI_RESOURCE_TYPE_IO:
+ case ACPI_RESOURCE_TYPE_FIXED_IO:
+ type = IORESOURCE_IO;
+ break;
+ case ACPI_RESOURCE_TYPE_IRQ:
+ case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
+ type = IORESOURCE_IRQ;
+ break;
+ case ACPI_RESOURCE_TYPE_DMA:
+ case ACPI_RESOURCE_TYPE_FIXED_DMA:
+ type = IORESOURCE_DMA;
+ break;
+ case ACPI_RESOURCE_TYPE_GENERIC_REGISTER:
+ type = IORESOURCE_REG;
+ break;
+ case ACPI_RESOURCE_TYPE_ADDRESS16:
+ case ACPI_RESOURCE_TYPE_ADDRESS32:
+ case ACPI_RESOURCE_TYPE_ADDRESS64:
+ case ACPI_RESOURCE_TYPE_EXTENDED_ADDRESS64:
+ if (ares->data.address.resource_type == ACPI_MEMORY_RANGE)
+ type = IORESOURCE_MEM;
+ else if (ares->data.address.resource_type == ACPI_IO_RANGE)
+ type = IORESOURCE_IO;
+ else if (ares->data.address.resource_type ==
+ ACPI_BUS_NUMBER_RANGE)
+ type = IORESOURCE_BUS;
+ break;
+ default:
+ break;
+ }
+
+ return (type & types) ? 0 : 1;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_filter_resource_type);
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index dc4d8960684a..bbca7830e18a 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2544,6 +2544,7 @@ int __init acpi_scan_init(void)
acpi_pci_link_init();
acpi_processor_init();
acpi_lpss_init();
+ acpi_apd_init();
acpi_cmos_rtc_init();
acpi_container_init();
acpi_memory_hotplug_init();
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 8aa9254a387f..7f251dd1a687 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -321,7 +321,7 @@ static struct dmi_system_id acpisleep_dmi_table[] __initdata = {
{},
};
-static void acpi_sleep_dmi_check(void)
+static void __init acpi_sleep_dmi_check(void)
{
int year;
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 032db459370f..debd30917010 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -522,6 +522,33 @@ static struct dmi_system_id video_dmi_table[] __initdata = {
DMI_MATCH(DMI_PRODUCT_NAME, "370R4E/370R4V/370R5E/3570RE/370R5V"),
},
},
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1186097 */
+ .callback = video_disable_native_backlight,
+ .ident = "SAMSUNG 3570R/370R/470R/450R/510R/4450RV",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "3570R/370R/470R/450R/510R/4450RV"),
+ },
+ },
+ {
+ /* https://bugzilla.redhat.com/show_bug.cgi?id=1094948 */
+ .callback = video_disable_native_backlight,
+ .ident = "SAMSUNG 730U3E/740U3E",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "730U3E/740U3E"),
+ },
+ },
+ {
+ /* https://bugs.freedesktop.org/show_bug.cgi?id=87286 */
+ .callback = video_disable_native_backlight,
+ .ident = "SAMSUNG 900X3C/900X3D/900X3E/900X4C/900X4D",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "900X3C/900X3D/900X3E/900X4C/900X4D"),
+ },
+ },
{
/* https://bugzilla.redhat.com/show_bug.cgi?id=1163574 */
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 52ddd9fbb55e..f0099360039e 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -18,6 +18,7 @@
#include <linux/pm_domain.h>
#include <linux/amba/bus.h>
#include <linux/sizes.h>
+#include <linux/limits.h>
#include <asm/irq.h>
@@ -43,6 +44,10 @@ static int amba_match(struct device *dev, struct device_driver *drv)
struct amba_device *pcdev = to_amba_device(dev);
struct amba_driver *pcdrv = to_amba_driver(drv);
+ /* When driver_override is set, only bind to the matching driver */
+ if (pcdev->driver_override)
+ return !strcmp(pcdev->driver_override, drv->name);
+
return amba_lookup(pcdrv->id_table, pcdev) != NULL;
}
@@ -59,6 +64,47 @@ static int amba_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval;
}
+static ssize_t driver_override_show(struct device *_dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct amba_device *dev = to_amba_device(_dev);
+
+ if (!dev->driver_override)
+ return 0;
+
+ return sprintf(buf, "%s\n", dev->driver_override);
+}
+
+static ssize_t driver_override_store(struct device *_dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct amba_device *dev = to_amba_device(_dev);
+ char *driver_override, *old = dev->driver_override, *cp;
+
+ if (count > PATH_MAX)
+ return -EINVAL;
+
+ driver_override = kstrndup(buf, count, GFP_KERNEL);
+ if (!driver_override)
+ return -ENOMEM;
+
+ cp = strchr(driver_override, '\n');
+ if (cp)
+ *cp = '\0';
+
+ if (strlen(driver_override)) {
+ dev->driver_override = driver_override;
+ } else {
+ kfree(driver_override);
+ dev->driver_override = NULL;
+ }
+
+ kfree(old);
+
+ return count;
+}
+
#define amba_attr_func(name,fmt,arg...) \
static ssize_t name##_show(struct device *_dev, \
struct device_attribute *attr, char *buf) \
@@ -81,6 +127,7 @@ amba_attr_func(resource, "\t%016llx\t%016llx\t%016lx\n",
static struct device_attribute amba_dev_attrs[] = {
__ATTR_RO(id),
__ATTR_RO(resource),
+ __ATTR_RW(driver_override),
__ATTR_NULL,
};
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index 8c43521d3f11..33b09b6568a4 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -37,6 +37,7 @@
#include <linux/vmalloc.h>
#include <linux/slab.h>
#include <linux/pid_namespace.h>
+#include <linux/security.h>
#ifdef CONFIG_ANDROID_BINDER_IPC_32BIT
#define BINDER_IPC_32BIT 1
@@ -1400,6 +1401,11 @@ static void binder_transaction(struct binder_proc *proc,
return_error = BR_DEAD_REPLY;
goto err_dead_binder;
}
+ if (security_binder_transaction(proc->tsk,
+ target_proc->tsk) < 0) {
+ return_error = BR_FAILED_REPLY;
+ goto err_invalid_target_handle;
+ }
if (!(tr->flags & TF_ONE_WAY) && thread->transaction_stack) {
struct binder_transaction *tmp;
@@ -1551,6 +1557,11 @@ static void binder_transaction(struct binder_proc *proc,
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_for_node_failed;
}
+ if (security_binder_transfer_binder(proc->tsk,
+ target_proc->tsk)) {
+ return_error = BR_FAILED_REPLY;
+ goto err_binder_get_ref_for_node_failed;
+ }
ref = binder_get_ref_for_node(target_proc, node);
if (ref == NULL) {
return_error = BR_FAILED_REPLY;
@@ -1581,6 +1592,11 @@ static void binder_transaction(struct binder_proc *proc,
return_error = BR_FAILED_REPLY;
goto err_binder_get_ref_failed;
}
+ if (security_binder_transfer_binder(proc->tsk,
+ target_proc->tsk)) {
+ return_error = BR_FAILED_REPLY;
+ goto err_binder_get_ref_failed;
+ }
if (ref->node->proc == target_proc) {
if (fp->type == BINDER_TYPE_HANDLE)
fp->type = BINDER_TYPE_BINDER;
@@ -1638,6 +1654,13 @@ static void binder_transaction(struct binder_proc *proc,
return_error = BR_FAILED_REPLY;
goto err_fget_failed;
}
+ if (security_binder_transfer_file(proc->tsk,
+ target_proc->tsk,
+ file) < 0) {
+ fput(file);
+ return_error = BR_FAILED_REPLY;
+ goto err_get_unused_fd_failed;
+ }
target_fd = task_get_unused_fd_flags(target_proc, O_CLOEXEC);
if (target_fd < 0) {
fput(file);
@@ -2675,6 +2698,9 @@ static int binder_ioctl_set_ctx_mgr(struct file *filp)
ret = -EBUSY;
goto out;
}
+ ret = security_binder_set_context_mgr(proc->tsk);
+ if (ret < 0)
+ goto out;
if (uid_valid(binder_context_mgr_uid)) {
if (!uid_eq(binder_context_mgr_uid, curr_euid)) {
pr_err("BINDER_SET_CONTEXT_MGR bad uid %d != %d\n",
diff --git a/drivers/ata/ahci.h b/drivers/ata/ahci.h
index 40f0e34f17af..71262e08648e 100644
--- a/drivers/ata/ahci.h
+++ b/drivers/ata/ahci.h
@@ -333,7 +333,7 @@ struct ahci_host_priv {
u32 em_msg_type; /* EM message type */
bool got_runtime_pm; /* Did we do pm_runtime_get? */
struct clk *clks[AHCI_MAX_CLKS]; /* Optional */
- struct regulator *target_pwr; /* Optional */
+ struct regulator **target_pwrs; /* Optional */
/*
* If platform uses PHYs. There is a 1:1 relation between the port number and
* the PHY position in this array.
@@ -354,6 +354,10 @@ extern int ahci_ignore_sss;
extern struct device_attribute *ahci_shost_attrs[];
extern struct device_attribute *ahci_sdev_attrs[];
+/*
+ * This must be instantiated by the edge drivers. Read the comments
+ * for ATA_BASE_SHT
+ */
#define AHCI_SHT(drv_name) \
ATA_NCQ_SHT(drv_name), \
.can_queue = AHCI_MAX_CMDS - 1, \
diff --git a/drivers/ata/ahci_da850.c b/drivers/ata/ahci_da850.c
index ce8a7a6d6c7f..267a3d3e79f4 100644
--- a/drivers/ata/ahci_da850.c
+++ b/drivers/ata/ahci_da850.c
@@ -16,6 +16,8 @@
#include <linux/ahci_platform.h>
#include "ahci.h"
+#define DRV_NAME "ahci_da850"
+
/* SATA PHY Control Register offset from AHCI base */
#define SATA_P0PHYCR_REG 0x178
@@ -59,6 +61,10 @@ static const struct ata_port_info ahci_da850_port_info = {
.port_ops = &ahci_platform_ops,
};
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int ahci_da850_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -85,7 +91,8 @@ static int ahci_da850_probe(struct platform_device *pdev)
da850_sata_init(dev, pwrdn_reg, hpriv->mmio);
- rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_da850_port_info,
+ &ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -102,7 +109,7 @@ static struct platform_driver ahci_da850_driver = {
.probe = ahci_da850_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "ahci_da850",
+ .name = DRV_NAME,
.pm = &ahci_da850_pm_ops,
},
};
diff --git a/drivers/ata/ahci_imx.c b/drivers/ata/ahci_imx.c
index 35d51c59a370..3f3a7db208ae 100644
--- a/drivers/ata/ahci_imx.c
+++ b/drivers/ata/ahci_imx.c
@@ -28,6 +28,8 @@
#include <linux/libata.h>
#include "ahci.h"
+#define DRV_NAME "ahci-imx"
+
enum {
/* Timer 1-ms Register */
IMX_TIMER1MS = 0x00e0,
@@ -221,11 +223,9 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
if (imxpriv->no_device)
return 0;
- if (hpriv->target_pwr) {
- ret = regulator_enable(hpriv->target_pwr);
- if (ret)
- return ret;
- }
+ ret = ahci_platform_enable_regulators(hpriv);
+ if (ret)
+ return ret;
ret = clk_prepare_enable(imxpriv->sata_ref_clk);
if (ret < 0)
@@ -270,8 +270,7 @@ static int imx_sata_enable(struct ahci_host_priv *hpriv)
disable_clk:
clk_disable_unprepare(imxpriv->sata_ref_clk);
disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ ahci_platform_disable_regulators(hpriv);
return ret;
}
@@ -291,8 +290,7 @@ static void imx_sata_disable(struct ahci_host_priv *hpriv)
clk_disable_unprepare(imxpriv->sata_ref_clk);
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ ahci_platform_disable_regulators(hpriv);
}
static void ahci_imx_error_handler(struct ata_port *ap)
@@ -524,6 +522,10 @@ static u32 imx_ahci_parse_props(struct device *dev,
return reg_value;
}
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int imx_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -620,7 +622,8 @@ static int imx_ahci_probe(struct platform_device *pdev)
reg_val = clk_get_rate(imxpriv->ahb_clk) / 1000;
writel(reg_val, hpriv->mmio + IMX_TIMER1MS);
- ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info);
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_imx_port_info,
+ &ahci_platform_sht);
if (ret)
goto disable_sata;
@@ -678,7 +681,7 @@ static struct platform_driver imx_ahci_driver = {
.probe = imx_ahci_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "ahci-imx",
+ .name = DRV_NAME,
.of_match_table = imx_ahci_of_match,
.pm = &ahci_imx_pm_ops,
},
diff --git a/drivers/ata/ahci_mvebu.c b/drivers/ata/ahci_mvebu.c
index 64bb08432b69..23716dd8a7ec 100644
--- a/drivers/ata/ahci_mvebu.c
+++ b/drivers/ata/ahci_mvebu.c
@@ -19,6 +19,8 @@
#include <linux/platform_device.h>
#include "ahci.h"
+#define DRV_NAME "ahci-mvebu"
+
#define AHCI_VENDOR_SPECIFIC_0_ADDR 0xa0
#define AHCI_VENDOR_SPECIFIC_0_DATA 0xa4
@@ -67,6 +69,10 @@ static const struct ata_port_info ahci_mvebu_port_info = {
.port_ops = &ahci_platform_ops,
};
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int ahci_mvebu_probe(struct platform_device *pdev)
{
struct ahci_host_priv *hpriv;
@@ -88,7 +94,8 @@ static int ahci_mvebu_probe(struct platform_device *pdev)
ahci_mvebu_mbus_config(hpriv, dram);
ahci_mvebu_regret_option(hpriv);
- rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_mvebu_port_info,
+ &ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -114,7 +121,7 @@ static struct platform_driver ahci_mvebu_driver = {
.probe = ahci_mvebu_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "ahci-mvebu",
+ .name = DRV_NAME,
.of_match_table = ahci_mvebu_of_match,
},
};
diff --git a/drivers/ata/ahci_platform.c b/drivers/ata/ahci_platform.c
index 18d539837045..78d6ae0b90c4 100644
--- a/drivers/ata/ahci_platform.c
+++ b/drivers/ata/ahci_platform.c
@@ -22,6 +22,8 @@
#include <linux/ahci_platform.h>
#include "ahci.h"
+#define DRV_NAME "ahci"
+
static const struct ata_port_info ahci_port_info = {
.flags = AHCI_FLAG_COMMON,
.pio_mask = ATA_PIO4,
@@ -29,6 +31,10 @@ static const struct ata_port_info ahci_port_info = {
.port_ops = &ahci_platform_ops,
};
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -46,7 +52,8 @@ static int ahci_probe(struct platform_device *pdev)
if (of_device_is_compatible(dev->of_node, "hisilicon,hisi-ahci"))
hpriv->flags |= AHCI_HFLAG_NO_FBS | AHCI_HFLAG_NO_NCQ;
- rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_port_info,
+ &ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -75,7 +82,7 @@ static struct platform_driver ahci_driver = {
.probe = ahci_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "ahci",
+ .name = DRV_NAME,
.of_match_table = ahci_of_match,
.pm = &ahci_pm_ops,
},
diff --git a/drivers/ata/ahci_st.c b/drivers/ata/ahci_st.c
index 2f9e8317cc16..bc971af262e7 100644
--- a/drivers/ata/ahci_st.c
+++ b/drivers/ata/ahci_st.c
@@ -23,6 +23,8 @@
#include "ahci.h"
+#define DRV_NAME "st_ahci"
+
#define ST_AHCI_OOBR 0xbc
#define ST_AHCI_OOBR_WE BIT(31)
#define ST_AHCI_OOBR_CWMIN_SHIFT 24
@@ -140,6 +142,10 @@ static const struct ata_port_info st_ahci_port_info = {
.port_ops = &st_ahci_port_ops,
};
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int st_ahci_probe(struct platform_device *pdev)
{
struct st_ahci_drv_data *drv_data;
@@ -166,7 +172,8 @@ static int st_ahci_probe(struct platform_device *pdev)
if (err)
return err;
- err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info);
+ err = ahci_platform_init_host(pdev, hpriv, &st_ahci_port_info,
+ &ahci_platform_sht);
if (err) {
ahci_platform_disable_resources(hpriv);
return err;
@@ -229,7 +236,7 @@ MODULE_DEVICE_TABLE(of, st_ahci_match);
static struct platform_driver st_ahci_driver = {
.driver = {
- .name = "st_ahci",
+ .name = DRV_NAME,
.pm = &st_ahci_pm_ops,
.of_match_table = of_match_ptr(st_ahci_match),
},
diff --git a/drivers/ata/ahci_sunxi.c b/drivers/ata/ahci_sunxi.c
index e2e0da539a2f..b26437430163 100644
--- a/drivers/ata/ahci_sunxi.c
+++ b/drivers/ata/ahci_sunxi.c
@@ -27,6 +27,8 @@
#include <linux/regulator/consumer.h>
#include "ahci.h"
+#define DRV_NAME "ahci-sunxi"
+
/* Insmod parameters */
static bool enable_pmp;
module_param(enable_pmp, bool, 0);
@@ -169,6 +171,10 @@ static const struct ata_port_info ahci_sunxi_port_info = {
.port_ops = &ahci_platform_ops,
};
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int ahci_sunxi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -200,7 +206,8 @@ static int ahci_sunxi_probe(struct platform_device *pdev)
if (!enable_pmp)
hpriv->flags |= AHCI_HFLAG_NO_PMP;
- rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info);
+ rc = ahci_platform_init_host(pdev, hpriv, &ahci_sunxi_port_info,
+ &ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -251,7 +258,7 @@ static struct platform_driver ahci_sunxi_driver = {
.probe = ahci_sunxi_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "ahci-sunxi",
+ .name = DRV_NAME,
.of_match_table = ahci_sunxi_of_match,
.pm = &ahci_sunxi_pm_ops,
},
diff --git a/drivers/ata/ahci_tegra.c b/drivers/ata/ahci_tegra.c
index 032904402c95..3a62eb246d80 100644
--- a/drivers/ata/ahci_tegra.c
+++ b/drivers/ata/ahci_tegra.c
@@ -31,6 +31,8 @@
#include "ahci.h"
+#define DRV_NAME "tegra-ahci"
+
#define SATA_CONFIGURATION_0 0x180
#define SATA_CONFIGURATION_EN_FPCI BIT(0)
@@ -289,6 +291,10 @@ static const struct of_device_id tegra_ahci_of_match[] = {
};
MODULE_DEVICE_TABLE(of, tegra_ahci_of_match);
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int tegra_ahci_probe(struct platform_device *pdev)
{
struct ahci_host_priv *hpriv;
@@ -354,7 +360,8 @@ static int tegra_ahci_probe(struct platform_device *pdev)
if (ret)
return ret;
- ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info);
+ ret = ahci_platform_init_host(pdev, hpriv, &ahci_tegra_port_info,
+ &ahci_platform_sht);
if (ret)
goto deinit_controller;
@@ -370,7 +377,7 @@ static struct platform_driver tegra_ahci_driver = {
.probe = tegra_ahci_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "tegra-ahci",
+ .name = DRV_NAME,
.of_match_table = tegra_ahci_of_match,
},
/* LP0 suspend support not implemented */
diff --git a/drivers/ata/ahci_xgene.c b/drivers/ata/ahci_xgene.c
index cbcd20810355..2e8bb603e447 100644
--- a/drivers/ata/ahci_xgene.c
+++ b/drivers/ata/ahci_xgene.c
@@ -30,6 +30,8 @@
#include <linux/phy/phy.h>
#include "ahci.h"
+#define DRV_NAME "xgene-ahci"
+
/* Max # of disk per a controller */
#define MAX_AHCI_CHN_PERCTR 2
@@ -85,6 +87,7 @@ struct xgene_ahci_context {
struct ahci_host_priv *hpriv;
struct device *dev;
u8 last_cmd[MAX_AHCI_CHN_PERCTR]; /* tracking the last command issued*/
+ u32 class[MAX_AHCI_CHN_PERCTR]; /* tracking the class of device */
void __iomem *csr_core; /* Core CSR address of IP */
void __iomem *csr_diag; /* Diag CSR address of IP */
void __iomem *csr_axi; /* AXI CSR address of IP */
@@ -105,17 +108,69 @@ static int xgene_ahci_init_memram(struct xgene_ahci_context *ctx)
}
/**
+ * xgene_ahci_poll_reg_val- Poll a register on a specific value.
+ * @ap : ATA port of interest.
+ * @reg : Register of interest.
+ * @val : Value to be attained.
+ * @interval : waiting interval for polling.
+ * @timeout : timeout for achieving the value.
+ */
+static int xgene_ahci_poll_reg_val(struct ata_port *ap,
+ void __iomem *reg, unsigned
+ int val, unsigned long interval,
+ unsigned long timeout)
+{
+ unsigned long deadline;
+ unsigned int tmp;
+
+ tmp = ioread32(reg);
+ deadline = ata_deadline(jiffies, timeout);
+
+ while (tmp != val && time_before(jiffies, deadline)) {
+ ata_msleep(ap, interval);
+ tmp = ioread32(reg);
+ }
+
+ return tmp;
+}
+
+/**
* xgene_ahci_restart_engine - Restart the dma engine.
* @ap : ATA port of interest
*
- * Restarts the dma engine inside the controller.
+ * Waits for completion of multiple commands and restarts
+ * the DMA engine inside the controller.
*/
static int xgene_ahci_restart_engine(struct ata_port *ap)
{
struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct ahci_port_priv *pp = ap->private_data;
+ void __iomem *port_mmio = ahci_port_base(ap);
+ u32 fbs;
+
+ /*
+ * In case of PMP multiple IDENTIFY DEVICE commands can be
+ * issued inside PxCI. So need to poll PxCI for the
+ * completion of outstanding IDENTIFY DEVICE commands before
+ * we restart the DMA engine.
+ */
+ if (xgene_ahci_poll_reg_val(ap, port_mmio +
+ PORT_CMD_ISSUE, 0x0, 1, 100))
+ return -EBUSY;
ahci_stop_engine(ap);
ahci_start_fis_rx(ap);
+
+ /*
+ * Enable the PxFBS.FBS_EN bit as it
+ * gets cleared due to stopping the engine.
+ */
+ if (pp->fbs_supported) {
+ fbs = readl(port_mmio + PORT_FBS);
+ writel(fbs | PORT_FBS_EN, port_mmio + PORT_FBS);
+ fbs = readl(port_mmio + PORT_FBS);
+ }
+
hpriv->start_engine(ap);
return 0;
@@ -125,11 +180,17 @@ static int xgene_ahci_restart_engine(struct ata_port *ap)
* xgene_ahci_qc_issue - Issue commands to the device
* @qc: Command to issue
*
- * Due to Hardware errata for IDENTIFY DEVICE command and PACKET
- * command of ATAPI protocol set, the controller cannot clear the BSY bit
- * after receiving the PIO setup FIS. This results in the DMA state machine
- * going into the CMFatalErrorUpdate state and locks up. By restarting the
- * DMA engine, it removes the controller out of lock up state.
+ * Due to Hardware errata for IDENTIFY DEVICE command, the controller cannot
+ * clear the BSY bit after receiving the PIO setup FIS. This results in the dma
+ * state machine goes into the CMFatalErrorUpdate state and locks up. By
+ * restarting the dma engine, it removes the controller out of lock up state.
+ *
+ * Due to H/W errata, the controller is unable to save the PMP
+ * field fetched from command header before sending the H2D FIS.
+ * When the device returns the PMP port field in the D2H FIS, there is
+ * a mismatch and results in command completion failure. The
+ * workaround is to write the pmp value to PxFBS.DEV field before issuing
+ * any command to PMP.
*/
static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
{
@@ -137,9 +198,23 @@ static unsigned int xgene_ahci_qc_issue(struct ata_queued_cmd *qc)
struct ahci_host_priv *hpriv = ap->host->private_data;
struct xgene_ahci_context *ctx = hpriv->plat_data;
int rc = 0;
+ u32 port_fbs;
+ void *port_mmio = ahci_port_base(ap);
+
+ /*
+ * Write the pmp value to PxFBS.DEV
+ * for case of Port Mulitplier.
+ */
+ if (ctx->class[ap->port_no] == ATA_DEV_PMP) {
+ port_fbs = readl(port_mmio + PORT_FBS);
+ port_fbs &= ~PORT_FBS_DEV_MASK;
+ port_fbs |= qc->dev->link->pmp << PORT_FBS_DEV_OFFSET;
+ writel(port_fbs, port_mmio + PORT_FBS);
+ }
if (unlikely((ctx->last_cmd[ap->port_no] == ATA_CMD_ID_ATA) ||
- (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET)))
+ (ctx->last_cmd[ap->port_no] == ATA_CMD_PACKET) ||
+ (ctx->last_cmd[ap->port_no] == ATA_CMD_SMART)))
xgene_ahci_restart_engine(ap);
rc = ahci_qc_issue(qc);
@@ -365,16 +440,119 @@ static void xgene_ahci_host_stop(struct ata_host *host)
ahci_platform_disable_resources(hpriv);
}
+/**
+ * xgene_ahci_pmp_softreset - Issue the softreset to the drives connected
+ * to Port Multiplier.
+ * @link: link to reset
+ * @class: Return value to indicate class of device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Due to H/W errata, the controller is unable to save the PMP
+ * field fetched from command header before sending the H2D FIS.
+ * When the device returns the PMP port field in the D2H FIS, there is
+ * a mismatch and results in command completion failure. The workaround
+ * is to write the pmp value to PxFBS.DEV field before issuing any command
+ * to PMP.
+ */
+static int xgene_ahci_pmp_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+ struct ata_port *ap = link->ap;
+ u32 rc;
+ void *port_mmio = ahci_port_base(ap);
+ u32 port_fbs;
+
+ /*
+ * Set PxFBS.DEV field with pmp
+ * value.
+ */
+ port_fbs = readl(port_mmio + PORT_FBS);
+ port_fbs &= ~PORT_FBS_DEV_MASK;
+ port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
+ writel(port_fbs, port_mmio + PORT_FBS);
+
+ rc = ahci_do_softreset(link, class, pmp, deadline, ahci_check_ready);
+
+ return rc;
+}
+
+/**
+ * xgene_ahci_softreset - Issue the softreset to the drive.
+ * @link: link to reset
+ * @class: Return value to indicate class of device
+ * @deadline: deadline jiffies for the operation
+ *
+ * Due to H/W errata, the controller is unable to save the PMP
+ * field fetched from command header before sending the H2D FIS.
+ * When the device returns the PMP port field in the D2H FIS, there is
+ * a mismatch and results in command completion failure. The workaround
+ * is to write the pmp value to PxFBS.DEV field before issuing any command
+ * to PMP. Here is the algorithm to detect PMP :
+ *
+ * 1. Save the PxFBS value
+ * 2. Program PxFBS.DEV with pmp value send by framework. Framework sends
+ * 0xF for both PMP/NON-PMP initially
+ * 3. Issue softreset
+ * 4. If signature class is PMP goto 6
+ * 5. restore the original PxFBS and goto 3
+ * 6. return
+ */
+static int xgene_ahci_softreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
+{
+ int pmp = sata_srst_pmp(link);
+ struct ata_port *ap = link->ap;
+ struct ahci_host_priv *hpriv = ap->host->private_data;
+ struct xgene_ahci_context *ctx = hpriv->plat_data;
+ void *port_mmio = ahci_port_base(ap);
+ u32 port_fbs;
+ u32 port_fbs_save;
+ u32 retry = 1;
+ u32 rc;
+
+ port_fbs_save = readl(port_mmio + PORT_FBS);
+
+ /*
+ * Set PxFBS.DEV field with pmp
+ * value.
+ */
+ port_fbs = readl(port_mmio + PORT_FBS);
+ port_fbs &= ~PORT_FBS_DEV_MASK;
+ port_fbs |= pmp << PORT_FBS_DEV_OFFSET;
+ writel(port_fbs, port_mmio + PORT_FBS);
+
+softreset_retry:
+ rc = ahci_do_softreset(link, class, pmp,
+ deadline, ahci_check_ready);
+
+ ctx->class[ap->port_no] = *class;
+ if (*class != ATA_DEV_PMP) {
+ /*
+ * Retry for normal drives without
+ * setting PxFBS.DEV field with pmp value.
+ */
+ if (retry--) {
+ writel(port_fbs_save, port_mmio + PORT_FBS);
+ goto softreset_retry;
+ }
+ }
+
+ return rc;
+}
+
static struct ata_port_operations xgene_ahci_ops = {
.inherits = &ahci_ops,
.host_stop = xgene_ahci_host_stop,
.hardreset = xgene_ahci_hardreset,
.read_id = xgene_ahci_read_id,
.qc_issue = xgene_ahci_qc_issue,
+ .softreset = xgene_ahci_softreset,
+ .pmp_softreset = xgene_ahci_pmp_softreset
};
static const struct ata_port_info xgene_ahci_port_info = {
- .flags = AHCI_FLAG_COMMON,
+ .flags = AHCI_FLAG_COMMON | ATA_FLAG_PMP,
.pio_mask = ATA_PIO4,
.udma_mask = ATA_UDMA6,
.port_ops = &xgene_ahci_ops,
@@ -446,6 +624,10 @@ static int xgene_ahci_mux_select(struct xgene_ahci_context *ctx)
return val & CFG_SATA_ENET_SELECT_MASK ? -1 : 0;
}
+static struct scsi_host_template ahci_platform_sht = {
+ AHCI_SHT(DRV_NAME),
+};
+
static int xgene_ahci_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -523,7 +705,8 @@ static int xgene_ahci_probe(struct platform_device *pdev)
skip_clk_phy:
hpriv->flags = AHCI_HFLAG_NO_PMP | AHCI_HFLAG_NO_NCQ;
- rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info);
+ rc = ahci_platform_init_host(pdev, hpriv, &xgene_ahci_port_info,
+ &ahci_platform_sht);
if (rc)
goto disable_resources;
@@ -545,7 +728,7 @@ static struct platform_driver xgene_ahci_driver = {
.probe = xgene_ahci_probe,
.remove = ata_platform_remove_one,
.driver = {
- .name = "xgene-ahci",
+ .name = DRV_NAME,
.of_match_table = xgene_ahci_of_match,
},
};
diff --git a/drivers/ata/libahci_platform.c b/drivers/ata/libahci_platform.c
index 0b03f9056692..d89305d289f6 100644
--- a/drivers/ata/libahci_platform.c
+++ b/drivers/ata/libahci_platform.c
@@ -24,6 +24,7 @@
#include <linux/ahci_platform.h>
#include <linux/phy/phy.h>
#include <linux/pm_runtime.h>
+#include <linux/of_platform.h>
#include "ahci.h"
static void ahci_host_stop(struct ata_host *host);
@@ -34,10 +35,6 @@ struct ata_port_operations ahci_platform_ops = {
};
EXPORT_SYMBOL_GPL(ahci_platform_ops);
-static struct scsi_host_template ahci_platform_sht = {
- AHCI_SHT("ahci_platform"),
-};
-
/**
* ahci_platform_enable_phys - Enable PHYs
* @hpriv: host private area to store config values
@@ -54,9 +51,6 @@ static int ahci_platform_enable_phys(struct ahci_host_priv *hpriv)
int rc, i;
for (i = 0; i < hpriv->nports; i++) {
- if (!hpriv->phys[i])
- continue;
-
rc = phy_init(hpriv->phys[i]);
if (rc)
goto disable_phys;
@@ -89,9 +83,6 @@ static void ahci_platform_disable_phys(struct ahci_host_priv *hpriv)
int i;
for (i = 0; i < hpriv->nports; i++) {
- if (!hpriv->phys[i])
- continue;
-
phy_power_off(hpriv->phys[i]);
phy_exit(hpriv->phys[i]);
}
@@ -144,6 +135,59 @@ void ahci_platform_disable_clks(struct ahci_host_priv *hpriv)
EXPORT_SYMBOL_GPL(ahci_platform_disable_clks);
/**
+ * ahci_platform_enable_regulators - Enable regulators
+ * @hpriv: host private area to store config values
+ *
+ * This function enables all the regulators found in
+ * hpriv->target_pwrs, if any. If a regulator fails to be enabled, it
+ * disables all the regulators already enabled in reverse order and
+ * returns an error.
+ *
+ * RETURNS:
+ * 0 on success otherwise a negative error code
+ */
+int ahci_platform_enable_regulators(struct ahci_host_priv *hpriv)
+{
+ int rc, i;
+
+ for (i = 0; i < hpriv->nports; i++) {
+ if (!hpriv->target_pwrs[i])
+ continue;
+
+ rc = regulator_enable(hpriv->target_pwrs[i]);
+ if (rc)
+ goto disable_target_pwrs;
+ }
+
+ return 0;
+
+disable_target_pwrs:
+ while (--i >= 0)
+ if (hpriv->target_pwrs[i])
+ regulator_disable(hpriv->target_pwrs[i]);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ahci_platform_enable_regulators);
+
+/**
+ * ahci_platform_disable_regulators - Disable regulators
+ * @hpriv: host private area to store config values
+ *
+ * This function disables all regulators found in hpriv->target_pwrs.
+ */
+void ahci_platform_disable_regulators(struct ahci_host_priv *hpriv)
+{
+ int i;
+
+ for (i = 0; i < hpriv->nports; i++) {
+ if (!hpriv->target_pwrs[i])
+ continue;
+ regulator_disable(hpriv->target_pwrs[i]);
+ }
+}
+EXPORT_SYMBOL_GPL(ahci_platform_disable_regulators);
+/**
* ahci_platform_enable_resources - Enable platform resources
* @hpriv: host private area to store config values
*
@@ -163,11 +207,9 @@ int ahci_platform_enable_resources(struct ahci_host_priv *hpriv)
{
int rc;
- if (hpriv->target_pwr) {
- rc = regulator_enable(hpriv->target_pwr);
- if (rc)
- return rc;
- }
+ rc = ahci_platform_enable_regulators(hpriv);
+ if (rc)
+ return rc;
rc = ahci_platform_enable_clks(hpriv);
if (rc)
@@ -183,8 +225,8 @@ disable_clks:
ahci_platform_disable_clks(hpriv);
disable_regulator:
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ ahci_platform_disable_regulators(hpriv);
+
return rc;
}
EXPORT_SYMBOL_GPL(ahci_platform_enable_resources);
@@ -205,8 +247,7 @@ void ahci_platform_disable_resources(struct ahci_host_priv *hpriv)
ahci_platform_disable_clks(hpriv);
- if (hpriv->target_pwr)
- regulator_disable(hpriv->target_pwr);
+ ahci_platform_disable_regulators(hpriv);
}
EXPORT_SYMBOL_GPL(ahci_platform_disable_resources);
@@ -222,6 +263,69 @@ static void ahci_platform_put_resources(struct device *dev, void *res)
for (c = 0; c < AHCI_MAX_CLKS && hpriv->clks[c]; c++)
clk_put(hpriv->clks[c]);
+ /*
+ * The regulators are tied to child node device and not to the
+ * SATA device itself. So we can't use devm for automatically
+ * releasing them. We have to do it manually here.
+ */
+ for (c = 0; c < hpriv->nports; c++)
+ if (hpriv->target_pwrs && hpriv->target_pwrs[c])
+ regulator_put(hpriv->target_pwrs[c]);
+
+ kfree(hpriv->target_pwrs);
+}
+
+static int ahci_platform_get_phy(struct ahci_host_priv *hpriv, u32 port,
+ struct device *dev, struct device_node *node)
+{
+ int rc;
+
+ hpriv->phys[port] = devm_of_phy_get(dev, node, NULL);
+
+ if (!IS_ERR(hpriv->phys[port]))
+ return 0;
+
+ rc = PTR_ERR(hpriv->phys[port]);
+ switch (rc) {
+ case -ENOSYS:
+ /* No PHY support. Check if PHY is required. */
+ if (of_find_property(node, "phys", NULL)) {
+ dev_err(dev,
+ "couldn't get PHY in node %s: ENOSYS\n",
+ node->name);
+ break;
+ }
+ case -ENODEV:
+ /* continue normally */
+ hpriv->phys[port] = NULL;
+ rc = 0;
+ break;
+
+ default:
+ dev_err(dev,
+ "couldn't get PHY in node %s: %d\n",
+ node->name, rc);
+
+ break;
+ }
+
+ return rc;
+}
+
+static int ahci_platform_get_regulator(struct ahci_host_priv *hpriv, u32 port,
+ struct device *dev)
+{
+ struct regulator *target_pwr;
+ int rc = 0;
+
+ target_pwr = regulator_get_optional(dev, "target");
+
+ if (!IS_ERR(target_pwr))
+ hpriv->target_pwrs[port] = target_pwr;
+ else
+ rc = PTR_ERR(target_pwr);
+
+ return rc;
}
/**
@@ -246,7 +350,7 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
struct ahci_host_priv *hpriv;
struct clk *clk;
struct device_node *child;
- int i, enabled_ports = 0, rc = -ENOMEM;
+ int i, sz, enabled_ports = 0, rc = -ENOMEM, child_nodes;
u32 mask_port_map = 0;
if (!devres_open_group(dev, NULL, GFP_KERNEL))
@@ -267,14 +371,6 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
goto err_out;
}
- hpriv->target_pwr = devm_regulator_get_optional(dev, "target");
- if (IS_ERR(hpriv->target_pwr)) {
- rc = PTR_ERR(hpriv->target_pwr);
- if (rc == -EPROBE_DEFER)
- goto err_out;
- hpriv->target_pwr = NULL;
- }
-
for (i = 0; i < AHCI_MAX_CLKS; i++) {
/*
* For now we must use clk_get(dev, NULL) for the first clock,
@@ -296,19 +392,33 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
hpriv->clks[i] = clk;
}
- hpriv->nports = of_get_child_count(dev->of_node);
+ hpriv->nports = child_nodes = of_get_child_count(dev->of_node);
- if (hpriv->nports) {
- hpriv->phys = devm_kzalloc(dev,
- hpriv->nports * sizeof(*hpriv->phys),
- GFP_KERNEL);
- if (!hpriv->phys) {
- rc = -ENOMEM;
- goto err_out;
- }
+ /*
+ * If no sub-node was found, we still need to set nports to
+ * one in order to be able to use the
+ * ahci_platform_[en|dis]able_[phys|regulators] functions.
+ */
+ if (!child_nodes)
+ hpriv->nports = 1;
+ sz = hpriv->nports * sizeof(*hpriv->phys);
+ hpriv->phys = devm_kzalloc(dev, sz, GFP_KERNEL);
+ if (!hpriv->phys) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+ sz = hpriv->nports * sizeof(*hpriv->target_pwrs);
+ hpriv->target_pwrs = kzalloc(sz, GFP_KERNEL);
+ if (!hpriv->target_pwrs) {
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ if (child_nodes) {
for_each_child_of_node(dev->of_node, child) {
u32 port;
+ struct platform_device *port_dev __maybe_unused;
if (!of_device_is_available(child))
continue;
@@ -322,17 +432,24 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
dev_warn(dev, "invalid port number %d\n", port);
continue;
}
-
mask_port_map |= BIT(port);
- hpriv->phys[port] = devm_of_phy_get(dev, child, NULL);
- if (IS_ERR(hpriv->phys[port])) {
- rc = PTR_ERR(hpriv->phys[port]);
- dev_err(dev,
- "couldn't get PHY in node %s: %d\n",
- child->name, rc);
- goto err_out;
+#ifdef CONFIG_OF_ADDRESS
+ of_platform_device_create(child, NULL, NULL);
+
+ port_dev = of_find_device_by_node(child);
+
+ if (port_dev) {
+ rc = ahci_platform_get_regulator(hpriv, port,
+ &port_dev->dev);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
}
+#endif
+
+ rc = ahci_platform_get_phy(hpriv, port, dev, child);
+ if (rc)
+ goto err_out;
enabled_ports++;
}
@@ -349,38 +466,14 @@ struct ahci_host_priv *ahci_platform_get_resources(struct platform_device *pdev)
* If no sub-node was found, keep this for device tree
* compatibility
*/
- struct phy *phy = devm_phy_get(dev, "sata-phy");
- if (!IS_ERR(phy)) {
- hpriv->phys = devm_kzalloc(dev, sizeof(*hpriv->phys),
- GFP_KERNEL);
- if (!hpriv->phys) {
- rc = -ENOMEM;
- goto err_out;
- }
-
- hpriv->phys[0] = phy;
- hpriv->nports = 1;
- } else {
- rc = PTR_ERR(phy);
- switch (rc) {
- case -ENOSYS:
- /* No PHY support. Check if PHY is required. */
- if (of_find_property(dev->of_node, "phys", NULL)) {
- dev_err(dev, "couldn't get sata-phy: ENOSYS\n");
- goto err_out;
- }
- case -ENODEV:
- /* continue normally */
- hpriv->phys = NULL;
- break;
-
- default:
- goto err_out;
+ rc = ahci_platform_get_phy(hpriv, 0, dev, dev->of_node);
+ if (rc)
+ goto err_out;
- }
- }
+ rc = ahci_platform_get_regulator(hpriv, 0, dev);
+ if (rc == -EPROBE_DEFER)
+ goto err_out;
}
-
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
hpriv->got_runtime_pm = true;
@@ -399,6 +492,7 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
* @pdev: platform device pointer for the host
* @hpriv: ahci-host private data for the host
* @pi_template: template for the ata_port_info to use
+ * @sht: scsi_host_template to use when registering
*
* This function does all the usual steps needed to bring up an
* ahci-platform host, note any necessary resources (ie clks, phys, etc.)
@@ -409,7 +503,8 @@ EXPORT_SYMBOL_GPL(ahci_platform_get_resources);
*/
int ahci_platform_init_host(struct platform_device *pdev,
struct ahci_host_priv *hpriv,
- const struct ata_port_info *pi_template)
+ const struct ata_port_info *pi_template,
+ struct scsi_host_template *sht)
{
struct device *dev = &pdev->dev;
struct ata_port_info pi = *pi_template;
@@ -493,7 +588,7 @@ int ahci_platform_init_host(struct platform_device *pdev,
ahci_init_controller(host);
ahci_print_info(host, "platform");
- return ahci_host_activate(host, irq, &ahci_platform_sht);
+ return ahci_host_activate(host, irq, sht);
}
EXPORT_SYMBOL_GPL(ahci_platform_init_host);
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index d1a05f9bb91f..4c35f0822d06 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -1585,8 +1585,6 @@ unsigned ata_exec_internal_sg(struct ata_device *dev,
else
tag = 0;
- if (test_and_set_bit(tag, &ap->qc_allocated))
- BUG();
qc = __ata_qc_from_tag(ap, tag);
qc->tag = tag;
@@ -1752,33 +1750,6 @@ unsigned ata_exec_internal(struct ata_device *dev,
}
/**
- * ata_do_simple_cmd - execute simple internal command
- * @dev: Device to which the command is sent
- * @cmd: Opcode to execute
- *
- * Execute a 'simple' command, that only consists of the opcode
- * 'cmd' itself, without filling any other registers
- *
- * LOCKING:
- * Kernel thread context (may sleep).
- *
- * RETURNS:
- * Zero on success, AC_ERR_* mask on failure
- */
-unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd)
-{
- struct ata_taskfile tf;
-
- ata_tf_init(dev, &tf);
-
- tf.command = cmd;
- tf.flags |= ATA_TFLAG_DEVICE;
- tf.protocol = ATA_PROT_NODATA;
-
- return ata_exec_internal(dev, &tf, NULL, DMA_NONE, NULL, 0, 0);
-}
-
-/**
* ata_pio_need_iordy - check if iordy needed
* @adev: ATA device
*
@@ -4749,69 +4720,36 @@ void swap_buf_le16(u16 *buf, unsigned int buf_words)
}
/**
- * ata_qc_new - Request an available ATA command, for queueing
- * @ap: target port
- *
- * Some ATA host controllers may implement a queue depth which is less
- * than ATA_MAX_QUEUE. So we shouldn't allocate a tag which is beyond
- * the hardware limitation.
+ * ata_qc_new_init - Request an available ATA command, and initialize it
+ * @dev: Device from whom we request an available command structure
*
* LOCKING:
* None.
*/
-static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
+struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag)
{
- struct ata_queued_cmd *qc = NULL;
- unsigned int max_queue = ap->host->n_tags;
- unsigned int i, tag;
+ struct ata_port *ap = dev->link->ap;
+ struct ata_queued_cmd *qc;
/* no command while frozen */
if (unlikely(ap->pflags & ATA_PFLAG_FROZEN))
return NULL;
- for (i = 0, tag = ap->last_tag + 1; i < max_queue; i++, tag++) {
- if (ap->flags & ATA_FLAG_LOWTAG)
- tag = i;
- else
- tag = tag < max_queue ? tag : 0;
-
- /* the last tag is reserved for internal command. */
- if (tag == ATA_TAG_INTERNAL)
- continue;
-
- if (!test_and_set_bit(tag, &ap->qc_allocated)) {
- qc = __ata_qc_from_tag(ap, tag);
- qc->tag = tag;
- ap->last_tag = tag;
- break;
- }
+ /* libsas case */
+ if (!ap->scsi_host) {
+ tag = ata_sas_allocate_tag(ap);
+ if (tag < 0)
+ return NULL;
}
- return qc;
-}
-
-/**
- * ata_qc_new_init - Request an available ATA command, and initialize it
- * @dev: Device from whom we request an available command structure
- *
- * LOCKING:
- * None.
- */
-
-struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev)
-{
- struct ata_port *ap = dev->link->ap;
- struct ata_queued_cmd *qc;
-
- qc = ata_qc_new(ap);
- if (qc) {
- qc->scsicmd = NULL;
- qc->ap = ap;
- qc->dev = dev;
+ qc = __ata_qc_from_tag(ap, tag);
+ qc->tag = tag;
+ qc->scsicmd = NULL;
+ qc->ap = ap;
+ qc->dev = dev;
- ata_qc_reinit(qc);
- }
+ ata_qc_reinit(qc);
return qc;
}
@@ -4838,7 +4776,8 @@ void ata_qc_free(struct ata_queued_cmd *qc)
tag = qc->tag;
if (likely(ata_tag_valid(tag))) {
qc->tag = ATA_TAG_POISON;
- clear_bit(tag, &ap->qc_allocated);
+ if (!ap->scsi_host)
+ ata_sas_free_tag(tag, ap);
}
}
diff --git a/drivers/ata/libata-eh.c b/drivers/ata/libata-eh.c
index 8d00c2638bed..d2029a462e2c 100644
--- a/drivers/ata/libata-eh.c
+++ b/drivers/ata/libata-eh.c
@@ -1635,7 +1635,6 @@ unsigned int atapi_eh_request_sense(struct ata_device *dev,
DPRINTK("ATAPI request sense\n");
- /* FIXME: is this needed? */
memset(sense_buf, 0, SCSI_SENSE_BUFFERSIZE);
/* initialize sense_buf with the error register,
@@ -2482,7 +2481,6 @@ static void ata_eh_link_report(struct ata_link *link)
for (tag = 0; tag < ATA_MAX_QUEUE; tag++) {
struct ata_queued_cmd *qc = __ata_qc_from_tag(ap, tag);
struct ata_taskfile *cmd = &qc->tf, *res = &qc->result_tf;
- const u8 *cdb = qc->cdb;
char data_buf[20] = "";
char cdb_buf[70] = "";
@@ -2510,16 +2508,15 @@ static void ata_eh_link_report(struct ata_link *link)
}
if (ata_is_atapi(qc->tf.protocol)) {
- if (qc->scsicmd)
- scsi_print_command(qc->scsicmd);
- else
- snprintf(cdb_buf, sizeof(cdb_buf),
- "cdb %02x %02x %02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x %02x %02x\n ",
- cdb[0], cdb[1], cdb[2], cdb[3],
- cdb[4], cdb[5], cdb[6], cdb[7],
- cdb[8], cdb[9], cdb[10], cdb[11],
- cdb[12], cdb[13], cdb[14], cdb[15]);
+ const u8 *cdb = qc->cdb;
+ size_t cdb_len = qc->dev->cdb_len;
+
+ if (qc->scsicmd) {
+ cdb = qc->scsicmd->cmnd;
+ cdb_len = qc->scsicmd->cmd_len;
+ }
+ __scsi_format_command(cdb_buf, sizeof(cdb_buf),
+ cdb, cdb_len);
} else {
const char *descr = ata_get_cmd_descript(cmd->command);
if (descr)
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 6abd17a85b13..b061ba2c31d8 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -756,7 +756,7 @@ static struct ata_queued_cmd *ata_scsi_qc_new(struct ata_device *dev,
{
struct ata_queued_cmd *qc;
- qc = ata_qc_new_init(dev);
+ qc = ata_qc_new_init(dev, cmd->request->tag);
if (qc) {
qc->scsicmd = cmd;
qc->scsidone = cmd->scsi_done;
@@ -1995,8 +1995,8 @@ static unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf)
VPRINTK("ENTER\n");
- /* set scsi removeable (RMB) bit per ata bit */
- if (ata_id_removeable(args->id))
+ /* set scsi removable (RMB) bit per ata bit */
+ if (ata_id_removable(args->id))
hdr[1] |= (1 << 7);
if (args->dev->class == ATA_DEV_ZAC) {
@@ -3668,6 +3668,9 @@ int ata_scsi_add_hosts(struct ata_host *host, struct scsi_host_template *sht)
*/
shost->max_host_blocked = 1;
+ if (scsi_init_shared_tag_map(shost, host->n_tags))
+ goto err_add;
+
rc = scsi_add_host_with_dma(ap->scsi_host,
&ap->tdev, ap->host->dev);
if (rc)
@@ -4230,3 +4233,31 @@ int ata_sas_queuecmd(struct scsi_cmnd *cmd, struct ata_port *ap)
return rc;
}
EXPORT_SYMBOL_GPL(ata_sas_queuecmd);
+
+int ata_sas_allocate_tag(struct ata_port *ap)
+{
+ unsigned int max_queue = ap->host->n_tags;
+ unsigned int i, tag;
+
+ for (i = 0, tag = ap->sas_last_tag + 1; i < max_queue; i++, tag++) {
+ if (ap->flags & ATA_FLAG_LOWTAG)
+ tag = 1;
+ else
+ tag = tag < max_queue ? tag : 0;
+
+ /* the last tag is reserved for internal command. */
+ if (tag == ATA_TAG_INTERNAL)
+ continue;
+
+ if (!test_and_set_bit(tag, &ap->sas_tag_allocated)) {
+ ap->sas_last_tag = tag;
+ return tag;
+ }
+ }
+ return -1;
+}
+
+void ata_sas_free_tag(unsigned int tag, struct ata_port *ap)
+{
+ clear_bit(tag, &ap->sas_tag_allocated);
+}
diff --git a/drivers/ata/libata.h b/drivers/ata/libata.h
index 5f4e0cca56ec..f840ca18a7c0 100644
--- a/drivers/ata/libata.h
+++ b/drivers/ata/libata.h
@@ -63,7 +63,7 @@ extern struct ata_link *ata_dev_phys_link(struct ata_device *dev);
extern void ata_force_cbl(struct ata_port *ap);
extern u64 ata_tf_to_lba(const struct ata_taskfile *tf);
extern u64 ata_tf_to_lba48(const struct ata_taskfile *tf);
-extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev);
+extern struct ata_queued_cmd *ata_qc_new_init(struct ata_device *dev, int tag);
extern int ata_build_rw_tf(struct ata_taskfile *tf, struct ata_device *dev,
u64 block, u32 n_block, unsigned int tf_flags,
unsigned int tag);
@@ -76,7 +76,6 @@ extern unsigned ata_exec_internal_sg(struct ata_device *dev,
struct ata_taskfile *tf, const u8 *cdb,
int dma_dir, struct scatterlist *sg,
unsigned int n_elem, unsigned long timeout);
-extern unsigned int ata_do_simple_cmd(struct ata_device *dev, u8 cmd);
extern int ata_wait_ready(struct ata_link *link, unsigned long deadline,
int (*check_ready)(struct ata_link *link));
extern int ata_dev_read_id(struct ata_device *dev, unsigned int *p_class,
@@ -145,6 +144,8 @@ extern void ata_scsi_dev_rescan(struct work_struct *work);
extern int ata_bus_probe(struct ata_port *ap);
extern int ata_scsi_user_scan(struct Scsi_Host *shost, unsigned int channel,
unsigned int id, u64 lun);
+int ata_sas_allocate_tag(struct ata_port *ap);
+void ata_sas_free_tag(unsigned int tag, struct ata_port *ap);
/* libata-eh.c */
diff --git a/drivers/ata/pata_cs5530.c b/drivers/ata/pata_cs5530.c
index 48ae4b434474..f9ca72e937ee 100644
--- a/drivers/ata/pata_cs5530.c
+++ b/drivers/ata/pata_cs5530.c
@@ -276,10 +276,8 @@ static int cs5530_init_chip(void)
pci_dev_put(cs5530_0);
return 0;
fail_put:
- if (master_0)
- pci_dev_put(master_0);
- if (cs5530_0)
- pci_dev_put(cs5530_0);
+ pci_dev_put(master_0);
+ pci_dev_put(cs5530_0);
return -ENODEV;
}
diff --git a/drivers/ata/pata_of_platform.c b/drivers/ata/pata_of_platform.c
index dcc408abe171..b6b7af894d9d 100644
--- a/drivers/ata/pata_of_platform.c
+++ b/drivers/ata/pata_of_platform.c
@@ -16,6 +16,12 @@
#include <linux/ata_platform.h>
#include <linux/libata.h>
+#define DRV_NAME "pata_of_platform"
+
+static struct scsi_host_template pata_platform_sht = {
+ ATA_PIO_SHT(DRV_NAME),
+};
+
static int pata_of_platform_probe(struct platform_device *ofdev)
{
int ret;
@@ -63,7 +69,7 @@ static int pata_of_platform_probe(struct platform_device *ofdev)
pio_mask |= (1 << pio_mode) - 1;
return __pata_platform_probe(&ofdev->dev, &io_res, &ctl_res, irq_res,
- reg_shift, pio_mask);
+ reg_shift, pio_mask, &pata_platform_sht);
}
static struct of_device_id pata_of_platform_match[] = {
@@ -74,7 +80,7 @@ MODULE_DEVICE_TABLE(of, pata_of_platform_match);
static struct platform_driver pata_of_platform_driver = {
.driver = {
- .name = "pata_of_platform",
+ .name = DRV_NAME,
.of_match_table = pata_of_platform_match,
},
.probe = pata_of_platform_probe,
diff --git a/drivers/ata/pata_pdc2027x.c b/drivers/ata/pata_pdc2027x.c
index 4d06a5cda987..dca8251b1aea 100644
--- a/drivers/ata/pata_pdc2027x.c
+++ b/drivers/ata/pata_pdc2027x.c
@@ -28,6 +28,7 @@
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/device.h>
+#include <linux/ktime.h>
#include <scsi/scsi.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
@@ -605,7 +606,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
void __iomem *mmio_base = host->iomap[PDC_MMIO_BAR];
u32 scr;
long start_count, end_count;
- struct timeval start_time, end_time;
+ ktime_t start_time, end_time;
long pll_clock, usec_elapsed;
/* Start the test mode */
@@ -616,14 +617,14 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
/* Read current counter value */
start_count = pdc_read_counter(host);
- do_gettimeofday(&start_time);
+ start_time = ktime_get();
/* Let the counter run for 100 ms. */
mdelay(100);
/* Read the counter values again */
end_count = pdc_read_counter(host);
- do_gettimeofday(&end_time);
+ end_time = ktime_get();
/* Stop the test mode */
scr = ioread32(mmio_base + PDC_SYS_CTL);
@@ -632,8 +633,7 @@ static long pdc_detect_pll_input_clock(struct ata_host *host)
ioread32(mmio_base + PDC_SYS_CTL); /* flush */
/* calculate the input clock in Hz */
- usec_elapsed = (end_time.tv_sec - start_time.tv_sec) * 1000000 +
- (end_time.tv_usec - start_time.tv_usec);
+ usec_elapsed = (long) ktime_us_delta(end_time, start_time);
pll_clock = ((start_count - end_count) & 0x3fffffff) / 100 *
(100000000 / usec_elapsed);
diff --git a/drivers/ata/pata_platform.c b/drivers/ata/pata_platform.c
index 1eedfe46d7c8..c503ded87bb8 100644
--- a/drivers/ata/pata_platform.c
+++ b/drivers/ata/pata_platform.c
@@ -78,6 +78,7 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
* @irq_res: Resource representing IRQ and its flags
* @ioport_shift: I/O port shift
* @__pio_mask: PIO mask
+ * @sht: scsi_host_template to use when registering
*
* Register a platform bus IDE interface. Such interfaces are PIO and we
* assume do not support IRQ sharing.
@@ -99,7 +100,8 @@ static void pata_platform_setup_port(struct ata_ioports *ioaddr,
*/
int __pata_platform_probe(struct device *dev, struct resource *io_res,
struct resource *ctl_res, struct resource *irq_res,
- unsigned int ioport_shift, int __pio_mask)
+ unsigned int ioport_shift, int __pio_mask,
+ struct scsi_host_template *sht)
{
struct ata_host *host;
struct ata_port *ap;
@@ -170,7 +172,7 @@ int __pata_platform_probe(struct device *dev, struct resource *io_res,
/* activate */
return ata_host_activate(host, irq, irq ? ata_sff_interrupt : NULL,
- irq_flags, &pata_platform_sht);
+ irq_flags, sht);
}
EXPORT_SYMBOL_GPL(__pata_platform_probe);
@@ -216,7 +218,7 @@ static int pata_platform_probe(struct platform_device *pdev)
return __pata_platform_probe(&pdev->dev, io_res, ctl_res, irq_res,
pp_info ? pp_info->ioport_shift : 0,
- pio_mask);
+ pio_mask, &pata_platform_sht);
}
static struct platform_driver pata_platform_driver = {
diff --git a/drivers/ata/sata_dwc_460ex.c b/drivers/ata/sata_dwc_460ex.c
index 8e8248179d20..fdb0f2879ea7 100644
--- a/drivers/ata/sata_dwc_460ex.c
+++ b/drivers/ata/sata_dwc_460ex.c
@@ -48,6 +48,18 @@
#define DRV_NAME "sata-dwc"
#define DRV_VERSION "1.3"
+#ifndef out_le32
+#define out_le32(a, v) __raw_writel(__cpu_to_le32(v), (void __iomem *)(a))
+#endif
+
+#ifndef in_le32
+#define in_le32(a) __le32_to_cpu(__raw_readl((void __iomem *)(a)))
+#endif
+
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
/* SATA DMA driver Globals */
#define DMA_NUM_CHANS 1
#define DMA_NUM_CHAN_REGS 8
@@ -273,7 +285,7 @@ struct sata_dwc_device {
struct device *dev; /* generic device struct */
struct ata_probe_ent *pe; /* ptr to probe-ent */
struct ata_host *host;
- u8 *reg_base;
+ u8 __iomem *reg_base;
struct sata_dwc_regs *sata_dwc_regs; /* DW Synopsys SATA specific */
int irq_dma;
};
@@ -323,7 +335,9 @@ struct sata_dwc_host_priv {
struct device *dwc_dev;
int dma_channel;
};
-struct sata_dwc_host_priv host_pvt;
+
+static struct sata_dwc_host_priv host_pvt;
+
/*
* Prototypes
*/
@@ -580,9 +594,9 @@ static int map_sg_to_lli(struct scatterlist *sg, int num_elems,
sms_val = 0;
dms_val = 1 + host_pvt.dma_channel;
- dev_dbg(host_pvt.dwc_dev, "%s: sg=%p nelem=%d lli=%p dma_lli=0x%08x"
- " dmadr=0x%08x\n", __func__, sg, num_elems, lli, (u32)dma_lli,
- (u32)dmadr_addr);
+ dev_dbg(host_pvt.dwc_dev,
+ "%s: sg=%p nelem=%d lli=%p dma_lli=0x%pad dmadr=0x%p\n",
+ __func__, sg, num_elems, lli, &dma_lli, dmadr_addr);
bl = get_burst_length_encode(AHB_DMA_BRST_DFLT);
@@ -773,7 +787,7 @@ static void dma_dwc_exit(struct sata_dwc_device *hsdev)
{
dev_dbg(host_pvt.dwc_dev, "%s:\n", __func__);
if (host_pvt.sata_dma_regs) {
- iounmap(host_pvt.sata_dma_regs);
+ iounmap((void __iomem *)host_pvt.sata_dma_regs);
host_pvt.sata_dma_regs = NULL;
}
@@ -818,7 +832,7 @@ static int sata_dwc_scr_read(struct ata_link *link, unsigned int scr, u32 *val)
return -EINVAL;
}
- *val = in_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4));
+ *val = in_le32(link->ap->ioaddr.scr_addr + (scr * 4));
dev_dbg(link->ap->dev, "%s: id=%d reg=%d val=val=0x%08x\n",
__func__, link->ap->print_id, scr, *val);
@@ -834,21 +848,19 @@ static int sata_dwc_scr_write(struct ata_link *link, unsigned int scr, u32 val)
__func__, scr);
return -EINVAL;
}
- out_le32((void *)link->ap->ioaddr.scr_addr + (scr * 4), val);
+ out_le32(link->ap->ioaddr.scr_addr + (scr * 4), val);
return 0;
}
static u32 core_scr_read(unsigned int scr)
{
- return in_le32((void __iomem *)(host_pvt.scr_addr_sstatus) +\
- (scr * 4));
+ return in_le32(host_pvt.scr_addr_sstatus + (scr * 4));
}
static void core_scr_write(unsigned int scr, u32 val)
{
- out_le32((void __iomem *)(host_pvt.scr_addr_sstatus) + (scr * 4),
- val);
+ out_le32(host_pvt.scr_addr_sstatus + (scr * 4), val);
}
static void clear_serror(void)
@@ -856,7 +868,6 @@ static void clear_serror(void)
u32 val;
val = core_scr_read(SCR_ERROR);
core_scr_write(SCR_ERROR, val);
-
}
static void clear_interrupt_bit(struct sata_dwc_device *hsdev, u32 bit)
@@ -1256,24 +1267,24 @@ static void sata_dwc_enable_interrupts(struct sata_dwc_device *hsdev)
static void sata_dwc_setup_port(struct ata_ioports *port, unsigned long base)
{
- port->cmd_addr = (void *)base + 0x00;
- port->data_addr = (void *)base + 0x00;
+ port->cmd_addr = (void __iomem *)base + 0x00;
+ port->data_addr = (void __iomem *)base + 0x00;
- port->error_addr = (void *)base + 0x04;
- port->feature_addr = (void *)base + 0x04;
+ port->error_addr = (void __iomem *)base + 0x04;
+ port->feature_addr = (void __iomem *)base + 0x04;
- port->nsect_addr = (void *)base + 0x08;
+ port->nsect_addr = (void __iomem *)base + 0x08;
- port->lbal_addr = (void *)base + 0x0c;
- port->lbam_addr = (void *)base + 0x10;
- port->lbah_addr = (void *)base + 0x14;
+ port->lbal_addr = (void __iomem *)base + 0x0c;
+ port->lbam_addr = (void __iomem *)base + 0x10;
+ port->lbah_addr = (void __iomem *)base + 0x14;
- port->device_addr = (void *)base + 0x18;
- port->command_addr = (void *)base + 0x1c;
- port->status_addr = (void *)base + 0x1c;
+ port->device_addr = (void __iomem *)base + 0x18;
+ port->command_addr = (void __iomem *)base + 0x1c;
+ port->status_addr = (void __iomem *)base + 0x1c;
- port->altstatus_addr = (void *)base + 0x20;
- port->ctl_addr = (void *)base + 0x20;
+ port->altstatus_addr = (void __iomem *)base + 0x20;
+ port->ctl_addr = (void __iomem *)base + 0x20;
}
/*
@@ -1314,7 +1325,7 @@ static int sata_dwc_port_start(struct ata_port *ap)
for (i = 0; i < SATA_DWC_QCMD_MAX; i++)
hsdevp->cmd_issued[i] = SATA_DWC_CMD_ISSUED_NOT;
- ap->bmdma_prd = 0; /* set these so libata doesn't use them */
+ ap->bmdma_prd = NULL; /* set these so libata doesn't use them */
ap->bmdma_prd_dma = 0;
/*
@@ -1511,8 +1522,8 @@ static void sata_dwc_qc_prep_by_tag(struct ata_queued_cmd *qc, u8 tag)
dma_chan = dma_dwc_xfer_setup(sg, qc->n_elem, hsdevp->llit[tag],
hsdevp->llit_dma[tag],
- (void *__iomem)(&hsdev->sata_dwc_regs->\
- dmadr), qc->dma_dir);
+ (void __iomem *)&hsdev->sata_dwc_regs->dmadr,
+ qc->dma_dir);
if (dma_chan < 0) {
dev_err(ap->dev, "%s: dma_dwc_xfer_setup returns err %d\n",
__func__, dma_chan);
@@ -1585,8 +1596,8 @@ static void sata_dwc_error_handler(struct ata_port *ap)
ata_sff_error_handler(ap);
}
-int sata_dwc_hardreset(struct ata_link *link, unsigned int *class,
- unsigned long deadline)
+static int sata_dwc_hardreset(struct ata_link *link, unsigned int *class,
+ unsigned long deadline)
{
struct sata_dwc_device *hsdev = HSDEV_FROM_AP(link->ap);
int ret;
@@ -1618,7 +1629,7 @@ static struct scsi_host_template sata_dwc_sht = {
* max of 1. This will get fixed in in a future release.
*/
.sg_tablesize = LIBATA_MAX_PRD,
- .can_queue = ATA_DEF_QUEUE, /* ATA_MAX_QUEUE */
+ /* .can_queue = ATA_MAX_QUEUE, */
.dma_boundary = ATA_DMA_BOUNDARY,
};
@@ -1655,7 +1666,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
struct sata_dwc_device *hsdev;
u32 idr, versionr;
char *ver = (char *)&versionr;
- u8 *base = NULL;
+ u8 __iomem *base;
int err = 0;
int irq;
struct ata_host *host;
@@ -1665,12 +1676,12 @@ static int sata_dwc_probe(struct platform_device *ofdev)
u32 dma_chan;
/* Allocate DWC SATA device */
- hsdev = kzalloc(sizeof(*hsdev), GFP_KERNEL);
- if (hsdev == NULL) {
- dev_err(&ofdev->dev, "kmalloc failed for hsdev\n");
- err = -ENOMEM;
- goto error;
- }
+ host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
+ hsdev = devm_kzalloc(&ofdev->dev, sizeof(*hsdev), GFP_KERNEL);
+ if (!host || !hsdev)
+ return -ENOMEM;
+
+ host->private_data = hsdev;
if (of_property_read_u32(np, "dma-channel", &dma_chan)) {
dev_warn(&ofdev->dev, "no dma-channel property set."
@@ -1680,12 +1691,11 @@ static int sata_dwc_probe(struct platform_device *ofdev)
host_pvt.dma_channel = dma_chan;
/* Ioremap SATA registers */
- base = of_iomap(ofdev->dev.of_node, 0);
+ base = of_iomap(np, 0);
if (!base) {
dev_err(&ofdev->dev, "ioremap failed for SATA register"
" address\n");
- err = -ENODEV;
- goto error_kmalloc;
+ return -ENODEV;
}
hsdev->reg_base = base;
dev_dbg(&ofdev->dev, "ioremap done for SATA register address\n");
@@ -1693,16 +1703,6 @@ static int sata_dwc_probe(struct platform_device *ofdev)
/* Synopsys DWC SATA specific Registers */
hsdev->sata_dwc_regs = (void *__iomem)(base + SATA_DWC_REG_OFFSET);
- /* Allocate and fill host */
- host = ata_host_alloc_pinfo(&ofdev->dev, ppi, SATA_DWC_MAX_PORTS);
- if (!host) {
- dev_err(&ofdev->dev, "ata_host_alloc_pinfo failed\n");
- err = -ENOMEM;
- goto error_iomap;
- }
-
- host->private_data = hsdev;
-
/* Setup port */
host->ports[0]->ioaddr.cmd_addr = base;
host->ports[0]->ioaddr.scr_addr = base + SATA_DWC_SCR_OFFSET;
@@ -1716,7 +1716,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
idr, ver[0], ver[1], ver[2]);
/* Get SATA DMA interrupt number */
- irq = irq_of_parse_and_map(ofdev->dev.of_node, 1);
+ irq = irq_of_parse_and_map(np, 1);
if (irq == NO_IRQ) {
dev_err(&ofdev->dev, "no SATA DMA irq\n");
err = -ENODEV;
@@ -1724,7 +1724,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
}
/* Get physical SATA DMA register base address */
- host_pvt.sata_dma_regs = of_iomap(ofdev->dev.of_node, 1);
+ host_pvt.sata_dma_regs = (void *)of_iomap(np, 1);
if (!(host_pvt.sata_dma_regs)) {
dev_err(&ofdev->dev, "ioremap failed for AHBDMA register"
" address\n");
@@ -1744,7 +1744,7 @@ static int sata_dwc_probe(struct platform_device *ofdev)
sata_dwc_enable_interrupts(hsdev);
/* Get SATA interrupt number */
- irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
+ irq = irq_of_parse_and_map(np, 0);
if (irq == NO_IRQ) {
dev_err(&ofdev->dev, "no SATA DMA irq\n");
err = -ENODEV;
@@ -1770,9 +1770,6 @@ error_dma_iomap:
iounmap((void __iomem *)host_pvt.sata_dma_regs);
error_iomap:
iounmap(base);
-error_kmalloc:
- kfree(hsdev);
-error:
return err;
}
@@ -1783,15 +1780,12 @@ static int sata_dwc_remove(struct platform_device *ofdev)
struct sata_dwc_device *hsdev = host->private_data;
ata_host_detach(host);
- dev_set_drvdata(dev, NULL);
/* Free SATA DMA resources */
dma_dwc_exit(hsdev);
iounmap((void __iomem *)host_pvt.sata_dma_regs);
iounmap(hsdev->reg_base);
- kfree(hsdev);
- kfree(host);
dev_dbg(&ofdev->dev, "done\n");
return 0;
}
diff --git a/drivers/ata/sata_mv.c b/drivers/ata/sata_mv.c
index f9a0e34eb111..f8c33e3772b8 100644
--- a/drivers/ata/sata_mv.c
+++ b/drivers/ata/sata_mv.c
@@ -4185,8 +4185,7 @@ err:
clk_disable_unprepare(hpriv->port_clks[port]);
clk_put(hpriv->port_clks[port]);
}
- if (hpriv->port_phys[port])
- phy_power_off(hpriv->port_phys[port]);
+ phy_power_off(hpriv->port_phys[port]);
}
return rc;
@@ -4216,8 +4215,7 @@ static int mv_platform_remove(struct platform_device *pdev)
clk_disable_unprepare(hpriv->port_clks[port]);
clk_put(hpriv->port_clks[port]);
}
- if (hpriv->port_phys[port])
- phy_power_off(hpriv->port_phys[port]);
+ phy_power_off(hpriv->port_phys[port]);
}
return 0;
}
diff --git a/drivers/ata/sata_rcar.c b/drivers/ata/sata_rcar.c
index cb0d2e644af5..d49a5193b7de 100644
--- a/drivers/ata/sata_rcar.c
+++ b/drivers/ata/sata_rcar.c
@@ -2,8 +2,8 @@
* Renesas R-Car SATA driver
*
* Author: Vladimir Barinov <source@cogentembedded.com>
- * Copyright (C) 2013 Cogent Embedded, Inc.
- * Copyright (C) 2013 Renesas Solutions Corp.
+ * Copyright (C) 2013-2015 Cogent Embedded, Inc.
+ * Copyright (C) 2013-2015 Renesas Solutions Corp.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -992,9 +992,30 @@ static int sata_rcar_resume(struct device *dev)
return 0;
}
+static int sata_rcar_restore(struct device *dev)
+{
+ struct ata_host *host = dev_get_drvdata(dev);
+ struct sata_rcar_priv *priv = host->private_data;
+
+ clk_prepare_enable(priv->clk);
+
+ sata_rcar_setup_port(host);
+
+ /* initialize host controller */
+ sata_rcar_init_controller(host);
+
+ ata_host_resume(host);
+
+ return 0;
+}
+
static const struct dev_pm_ops sata_rcar_pm_ops = {
.suspend = sata_rcar_suspend,
.resume = sata_rcar_resume,
+ .freeze = sata_rcar_suspend,
+ .thaw = sata_rcar_resume,
+ .poweroff = sata_rcar_suspend,
+ .restore = sata_rcar_restore,
};
#endif
diff --git a/drivers/ata/sata_sil24.c b/drivers/ata/sata_sil24.c
index ea655949023f..ba2667fa0528 100644
--- a/drivers/ata/sata_sil24.c
+++ b/drivers/ata/sata_sil24.c
@@ -388,6 +388,7 @@ static struct scsi_host_template sil24_sht = {
.can_queue = SIL24_MAX_CMDS,
.sg_tablesize = SIL24_MAX_SGE,
.dma_boundary = ATA_DMA_BOUNDARY,
+ .tag_alloc_policy = BLK_TAG_ALLOC_FIFO,
};
static struct ata_port_operations sil24_ops = {
diff --git a/drivers/atm/eni.c b/drivers/atm/eni.c
index c7fab3ee14ee..6339efd32697 100644
--- a/drivers/atm/eni.c
+++ b/drivers/atm/eni.c
@@ -354,9 +354,9 @@ static int do_rx_dma(struct atm_vcc *vcc,struct sk_buff *skb,
eni_vcc = ENI_VCC(vcc);
paddr = 0; /* GCC, shut up */
if (skb) {
- paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,
- PCI_DMA_FROMDEVICE);
- if (pci_dma_mapping_error(eni_dev->pci_dev, paddr))
+ paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len,
+ DMA_FROM_DEVICE);
+ if (dma_mapping_error(&eni_dev->pci_dev->dev, paddr))
goto dma_map_error;
ENI_PRV_PADDR(skb) = paddr;
if (paddr & 3)
@@ -481,8 +481,8 @@ rx_enqueued++;
trouble:
if (paddr)
- pci_unmap_single(eni_dev->pci_dev,paddr,skb->len,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&eni_dev->pci_dev->dev,paddr,skb->len,
+ DMA_FROM_DEVICE);
dma_map_error:
if (skb) dev_kfree_skb_irq(skb);
return -1;
@@ -758,8 +758,8 @@ rx_dequeued++;
}
eni_vcc->rxing--;
eni_vcc->rx_pos = ENI_PRV_POS(skb) & (eni_vcc->words-1);
- pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(&eni_dev->pci_dev->dev,ENI_PRV_PADDR(skb),skb->len,
+ DMA_TO_DEVICE);
if (!skb->len) dev_kfree_skb_irq(skb);
else {
EVENT("pushing (len=%ld)\n",skb->len,0);
@@ -1112,8 +1112,8 @@ DPRINTK("iovcnt = %d\n",skb_shinfo(skb)->nr_frags);
vcc->dev->number);
return enq_jam;
}
- paddr = pci_map_single(eni_dev->pci_dev,skb->data,skb->len,
- PCI_DMA_TODEVICE);
+ paddr = dma_map_single(&eni_dev->pci_dev->dev,skb->data,skb->len,
+ DMA_TO_DEVICE);
ENI_PRV_PADDR(skb) = paddr;
/* prepare DMA queue entries */
j = 0;
@@ -1226,8 +1226,8 @@ static void dequeue_tx(struct atm_dev *dev)
break;
}
ENI_VCC(vcc)->txing -= ENI_PRV_SIZE(skb);
- pci_unmap_single(eni_dev->pci_dev,ENI_PRV_PADDR(skb),skb->len,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(&eni_dev->pci_dev->dev,ENI_PRV_PADDR(skb),skb->len,
+ DMA_TO_DEVICE);
if (vcc->pop) vcc->pop(vcc,skb);
else dev_kfree_skb_irq(skb);
atomic_inc(&vcc->stats->tx);
@@ -2240,13 +2240,18 @@ static int eni_init_one(struct pci_dev *pci_dev,
if (rc < 0)
goto out;
+ rc = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));
+ if (rc < 0)
+ goto out;
+
rc = -ENOMEM;
eni_dev = kmalloc(sizeof(struct eni_dev), GFP_KERNEL);
if (!eni_dev)
goto err_disable;
zero = &eni_dev->zero;
- zero->addr = pci_alloc_consistent(pci_dev, ENI_ZEROES_SIZE, &zero->dma);
+ zero->addr = dma_alloc_coherent(&pci_dev->dev,
+ ENI_ZEROES_SIZE, &zero->dma, GFP_KERNEL);
if (!zero->addr)
goto err_kfree;
@@ -2277,7 +2282,7 @@ err_eni_release:
err_unregister:
atm_dev_deregister(dev);
err_free_consistent:
- pci_free_consistent(pci_dev, ENI_ZEROES_SIZE, zero->addr, zero->dma);
+ dma_free_coherent(&pci_dev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma);
err_kfree:
kfree(eni_dev);
err_disable:
@@ -2302,7 +2307,7 @@ static void eni_remove_one(struct pci_dev *pdev)
eni_do_release(dev);
atm_dev_deregister(dev);
- pci_free_consistent(pdev, ENI_ZEROES_SIZE, zero->addr, zero->dma);
+ dma_free_coherent(&pdev->dev, ENI_ZEROES_SIZE, zero->addr, zero->dma);
kfree(ed);
pci_disable_device(pdev);
}
diff --git a/drivers/atm/fore200e.c b/drivers/atm/fore200e.c
index d5d9eafbbfcf..75dde903b238 100644
--- a/drivers/atm/fore200e.c
+++ b/drivers/atm/fore200e.c
@@ -425,7 +425,7 @@ static void fore200e_pca_write(u32 val, volatile u32 __iomem *addr)
static u32
fore200e_pca_dma_map(struct fore200e* fore200e, void* virt_addr, int size, int direction)
{
- u32 dma_addr = pci_map_single((struct pci_dev*)fore200e->bus_dev, virt_addr, size, direction);
+ u32 dma_addr = dma_map_single(&((struct pci_dev *) fore200e->bus_dev)->dev, virt_addr, size, direction);
DPRINTK(3, "PCI DVMA mapping: virt_addr = 0x%p, size = %d, direction = %d, --> dma_addr = 0x%08x\n",
virt_addr, size, direction, dma_addr);
@@ -440,7 +440,7 @@ fore200e_pca_dma_unmap(struct fore200e* fore200e, u32 dma_addr, int size, int di
DPRINTK(3, "PCI DVMA unmapping: dma_addr = 0x%08x, size = %d, direction = %d\n",
dma_addr, size, direction);
- pci_unmap_single((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
+ dma_unmap_single(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction);
}
@@ -449,7 +449,7 @@ fore200e_pca_dma_sync_for_cpu(struct fore200e* fore200e, u32 dma_addr, int size,
{
DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_dma_sync_single_for_cpu((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
+ dma_sync_single_for_cpu(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction);
}
static void
@@ -457,7 +457,7 @@ fore200e_pca_dma_sync_for_device(struct fore200e* fore200e, u32 dma_addr, int si
{
DPRINTK(3, "PCI DVMA sync: dma_addr = 0x%08x, size = %d, direction = %d\n", dma_addr, size, direction);
- pci_dma_sync_single_for_device((struct pci_dev*)fore200e->bus_dev, dma_addr, size, direction);
+ dma_sync_single_for_device(&((struct pci_dev *) fore200e->bus_dev)->dev, dma_addr, size, direction);
}
@@ -470,9 +470,10 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
{
/* returned chunks are page-aligned */
chunk->alloc_size = size * nbr;
- chunk->alloc_addr = pci_alloc_consistent((struct pci_dev*)fore200e->bus_dev,
- chunk->alloc_size,
- &chunk->dma_addr);
+ chunk->alloc_addr = dma_alloc_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev,
+ chunk->alloc_size,
+ &chunk->dma_addr,
+ GFP_KERNEL);
if ((chunk->alloc_addr == NULL) || (chunk->dma_addr == 0))
return -ENOMEM;
@@ -488,7 +489,7 @@ fore200e_pca_dma_chunk_alloc(struct fore200e* fore200e, struct chunk* chunk,
static void
fore200e_pca_dma_chunk_free(struct fore200e* fore200e, struct chunk* chunk)
{
- pci_free_consistent((struct pci_dev*)fore200e->bus_dev,
+ dma_free_coherent(&((struct pci_dev *) fore200e->bus_dev)->dev,
chunk->alloc_size,
chunk->alloc_addr,
chunk->dma_addr);
@@ -2707,6 +2708,11 @@ static int fore200e_pca_detect(struct pci_dev *pci_dev,
err = -EINVAL;
goto out;
}
+
+ if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32))) {
+ err = -EINVAL;
+ goto out;
+ }
fore200e = kzalloc(sizeof(struct fore200e), GFP_KERNEL);
if (fore200e == NULL) {
diff --git a/drivers/atm/he.c b/drivers/atm/he.c
index c39702bc279d..93dca2e73bf5 100644
--- a/drivers/atm/he.c
+++ b/drivers/atm/he.c
@@ -359,7 +359,7 @@ static int he_init_one(struct pci_dev *pci_dev,
if (pci_enable_device(pci_dev))
return -EIO;
- if (pci_set_dma_mask(pci_dev, DMA_BIT_MASK(32)) != 0) {
+ if (dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32)) != 0) {
printk(KERN_WARNING "he: no suitable dma available\n");
err = -EIO;
goto init_one_failure;
@@ -533,9 +533,9 @@ static void he_init_tx_lbfp(struct he_dev *he_dev)
static int he_init_tpdrq(struct he_dev *he_dev)
{
- he_dev->tpdrq_base = pci_zalloc_consistent(he_dev->pci_dev,
- CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq),
- &he_dev->tpdrq_phys);
+ he_dev->tpdrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev,
+ CONFIG_TPDRQ_SIZE * sizeof(struct he_tpdrq),
+ &he_dev->tpdrq_phys, GFP_KERNEL);
if (he_dev->tpdrq_base == NULL) {
hprintk("failed to alloc tpdrq\n");
return -ENOMEM;
@@ -796,16 +796,16 @@ static int he_init_group(struct he_dev *he_dev, int group)
}
/* large buffer pool */
- he_dev->rbpl_pool = pci_pool_create("rbpl", he_dev->pci_dev,
+ he_dev->rbpl_pool = dma_pool_create("rbpl", &he_dev->pci_dev->dev,
CONFIG_RBPL_BUFSIZE, 64, 0);
if (he_dev->rbpl_pool == NULL) {
hprintk("unable to create rbpl pool\n");
goto out_free_rbpl_virt;
}
- he_dev->rbpl_base = pci_zalloc_consistent(he_dev->pci_dev,
- CONFIG_RBPL_SIZE * sizeof(struct he_rbp),
- &he_dev->rbpl_phys);
+ he_dev->rbpl_base = dma_zalloc_coherent(&he_dev->pci_dev->dev,
+ CONFIG_RBPL_SIZE * sizeof(struct he_rbp),
+ &he_dev->rbpl_phys, GFP_KERNEL);
if (he_dev->rbpl_base == NULL) {
hprintk("failed to alloc rbpl_base\n");
goto out_destroy_rbpl_pool;
@@ -815,7 +815,7 @@ static int he_init_group(struct he_dev *he_dev, int group)
for (i = 0; i < CONFIG_RBPL_SIZE; ++i) {
- heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL|GFP_DMA, &mapping);
+ heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_KERNEL, &mapping);
if (!heb)
goto out_free_rbpl;
heb->mapping = mapping;
@@ -842,9 +842,9 @@ static int he_init_group(struct he_dev *he_dev, int group)
/* rx buffer ready queue */
- he_dev->rbrq_base = pci_zalloc_consistent(he_dev->pci_dev,
- CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
- &he_dev->rbrq_phys);
+ he_dev->rbrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev,
+ CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
+ &he_dev->rbrq_phys, GFP_KERNEL);
if (he_dev->rbrq_base == NULL) {
hprintk("failed to allocate rbrq\n");
goto out_free_rbpl;
@@ -866,9 +866,9 @@ static int he_init_group(struct he_dev *he_dev, int group)
/* tx buffer ready queue */
- he_dev->tbrq_base = pci_zalloc_consistent(he_dev->pci_dev,
- CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
- &he_dev->tbrq_phys);
+ he_dev->tbrq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev,
+ CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
+ &he_dev->tbrq_phys, GFP_KERNEL);
if (he_dev->tbrq_base == NULL) {
hprintk("failed to allocate tbrq\n");
goto out_free_rbpq_base;
@@ -884,18 +884,18 @@ static int he_init_group(struct he_dev *he_dev, int group)
return 0;
out_free_rbpq_base:
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE *
- sizeof(struct he_rbrq), he_dev->rbrq_base,
- he_dev->rbrq_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE *
+ sizeof(struct he_rbrq), he_dev->rbrq_base,
+ he_dev->rbrq_phys);
out_free_rbpl:
list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
- pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE *
- sizeof(struct he_rbp), he_dev->rbpl_base,
- he_dev->rbpl_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE *
+ sizeof(struct he_rbp), he_dev->rbpl_base,
+ he_dev->rbpl_phys);
out_destroy_rbpl_pool:
- pci_pool_destroy(he_dev->rbpl_pool);
+ dma_pool_destroy(he_dev->rbpl_pool);
out_free_rbpl_virt:
kfree(he_dev->rbpl_virt);
out_free_rbpl_table:
@@ -911,8 +911,11 @@ static int he_init_irq(struct he_dev *he_dev)
/* 2.9.3.5 tail offset for each interrupt queue is located after the
end of the interrupt queue */
- he_dev->irq_base = pci_alloc_consistent(he_dev->pci_dev,
- (CONFIG_IRQ_SIZE+1) * sizeof(struct he_irq), &he_dev->irq_phys);
+ he_dev->irq_base = dma_zalloc_coherent(&he_dev->pci_dev->dev,
+ (CONFIG_IRQ_SIZE + 1)
+ * sizeof(struct he_irq),
+ &he_dev->irq_phys,
+ GFP_KERNEL);
if (he_dev->irq_base == NULL) {
hprintk("failed to allocate irq\n");
return -ENOMEM;
@@ -1419,10 +1422,10 @@ static int he_start(struct atm_dev *dev)
he_init_tpdrq(he_dev);
- he_dev->tpd_pool = pci_pool_create("tpd", he_dev->pci_dev,
- sizeof(struct he_tpd), TPD_ALIGNMENT, 0);
+ he_dev->tpd_pool = dma_pool_create("tpd", &he_dev->pci_dev->dev,
+ sizeof(struct he_tpd), TPD_ALIGNMENT, 0);
if (he_dev->tpd_pool == NULL) {
- hprintk("unable to create tpd pci_pool\n");
+ hprintk("unable to create tpd dma_pool\n");
return -ENOMEM;
}
@@ -1459,9 +1462,9 @@ static int he_start(struct atm_dev *dev)
/* host status page */
- he_dev->hsp = pci_zalloc_consistent(he_dev->pci_dev,
- sizeof(struct he_hsp),
- &he_dev->hsp_phys);
+ he_dev->hsp = dma_zalloc_coherent(&he_dev->pci_dev->dev,
+ sizeof(struct he_hsp),
+ &he_dev->hsp_phys, GFP_KERNEL);
if (he_dev->hsp == NULL) {
hprintk("failed to allocate host status page\n");
return -ENOMEM;
@@ -1558,41 +1561,41 @@ he_stop(struct he_dev *he_dev)
free_irq(he_dev->irq, he_dev);
if (he_dev->irq_base)
- pci_free_consistent(he_dev->pci_dev, (CONFIG_IRQ_SIZE+1)
- * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, (CONFIG_IRQ_SIZE + 1)
+ * sizeof(struct he_irq), he_dev->irq_base, he_dev->irq_phys);
if (he_dev->hsp)
- pci_free_consistent(he_dev->pci_dev, sizeof(struct he_hsp),
- he_dev->hsp, he_dev->hsp_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, sizeof(struct he_hsp),
+ he_dev->hsp, he_dev->hsp_phys);
if (he_dev->rbpl_base) {
list_for_each_entry_safe(heb, next, &he_dev->rbpl_outstanding, entry)
- pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBPL_SIZE
- * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBPL_SIZE
+ * sizeof(struct he_rbp), he_dev->rbpl_base, he_dev->rbpl_phys);
}
kfree(he_dev->rbpl_virt);
kfree(he_dev->rbpl_table);
if (he_dev->rbpl_pool)
- pci_pool_destroy(he_dev->rbpl_pool);
+ dma_pool_destroy(he_dev->rbpl_pool);
if (he_dev->rbrq_base)
- pci_free_consistent(he_dev->pci_dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
- he_dev->rbrq_base, he_dev->rbrq_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_RBRQ_SIZE * sizeof(struct he_rbrq),
+ he_dev->rbrq_base, he_dev->rbrq_phys);
if (he_dev->tbrq_base)
- pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
- he_dev->tbrq_base, he_dev->tbrq_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
+ he_dev->tbrq_base, he_dev->tbrq_phys);
if (he_dev->tpdrq_base)
- pci_free_consistent(he_dev->pci_dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
- he_dev->tpdrq_base, he_dev->tpdrq_phys);
+ dma_free_coherent(&he_dev->pci_dev->dev, CONFIG_TBRQ_SIZE * sizeof(struct he_tbrq),
+ he_dev->tpdrq_base, he_dev->tpdrq_phys);
if (he_dev->tpd_pool)
- pci_pool_destroy(he_dev->tpd_pool);
+ dma_pool_destroy(he_dev->tpd_pool);
if (he_dev->pci_dev) {
pci_read_config_word(he_dev->pci_dev, PCI_COMMAND, &command);
@@ -1610,7 +1613,7 @@ __alloc_tpd(struct he_dev *he_dev)
struct he_tpd *tpd;
dma_addr_t mapping;
- tpd = pci_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC|GFP_DMA, &mapping);
+ tpd = dma_pool_alloc(he_dev->tpd_pool, GFP_ATOMIC, &mapping);
if (tpd == NULL)
return NULL;
@@ -1681,7 +1684,7 @@ he_service_rbrq(struct he_dev *he_dev, int group)
if (!RBRQ_HBUF_ERR(he_dev->rbrq_head)) {
clear_bit(i, he_dev->rbpl_table);
list_del(&heb->entry);
- pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
}
goto next_rbrq_entry;
@@ -1774,7 +1777,7 @@ return_host_buffers:
++pdus_assembled;
list_for_each_entry_safe(heb, next, &he_vcc->buffers, entry)
- pci_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
+ dma_pool_free(he_dev->rbpl_pool, heb, heb->mapping);
INIT_LIST_HEAD(&he_vcc->buffers);
he_vcc->pdu_len = 0;
@@ -1843,10 +1846,10 @@ he_service_tbrq(struct he_dev *he_dev, int group)
for (slot = 0; slot < TPD_MAXIOV; ++slot) {
if (tpd->iovec[slot].addr)
- pci_unmap_single(he_dev->pci_dev,
+ dma_unmap_single(&he_dev->pci_dev->dev,
tpd->iovec[slot].addr,
tpd->iovec[slot].len & TPD_LEN_MASK,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
if (tpd->iovec[slot].len & TPD_LST)
break;
@@ -1861,7 +1864,7 @@ he_service_tbrq(struct he_dev *he_dev, int group)
next_tbrq_entry:
if (tpd)
- pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
+ dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
he_dev->tbrq_head = (struct he_tbrq *)
((unsigned long) he_dev->tbrq_base |
TBRQ_MASK(he_dev->tbrq_head + 1));
@@ -1905,7 +1908,7 @@ he_service_rbpl(struct he_dev *he_dev, int group)
}
he_dev->rbpl_hint = i + 1;
- heb = pci_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC|GFP_DMA, &mapping);
+ heb = dma_pool_alloc(he_dev->rbpl_pool, GFP_ATOMIC, &mapping);
if (!heb)
break;
heb->mapping = mapping;
@@ -2084,10 +2087,10 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid)
*/
for (slot = 0; slot < TPD_MAXIOV; ++slot) {
if (tpd->iovec[slot].addr)
- pci_unmap_single(he_dev->pci_dev,
+ dma_unmap_single(&he_dev->pci_dev->dev,
tpd->iovec[slot].addr,
tpd->iovec[slot].len & TPD_LEN_MASK,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
}
if (tpd->skb) {
if (tpd->vcc->pop)
@@ -2096,7 +2099,7 @@ __enqueue_tpd(struct he_dev *he_dev, struct he_tpd *tpd, unsigned cid)
dev_kfree_skb_any(tpd->skb);
atomic_inc(&tpd->vcc->stats->tx_err);
}
- pci_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
+ dma_pool_free(he_dev->tpd_pool, tpd, TPD_ADDR(tpd->status));
return;
}
}
@@ -2550,8 +2553,8 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb)
}
#ifdef USE_SCATTERGATHER
- tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev, skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE);
+ tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev, skb->data,
+ skb_headlen(skb), DMA_TO_DEVICE);
tpd->iovec[slot].len = skb_headlen(skb);
++slot;
@@ -2579,9 +2582,9 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb)
slot = 0;
}
- tpd->iovec[slot].addr = pci_map_single(he_dev->pci_dev,
+ tpd->iovec[slot].addr = dma_map_single(&he_dev->pci_dev->dev,
(void *) page_address(frag->page) + frag->page_offset,
- frag->size, PCI_DMA_TODEVICE);
+ frag->size, DMA_TO_DEVICE);
tpd->iovec[slot].len = frag->size;
++slot;
@@ -2589,7 +2592,7 @@ he_send(struct atm_vcc *vcc, struct sk_buff *skb)
tpd->iovec[slot - 1].len |= TPD_LST;
#else
- tpd->address0 = pci_map_single(he_dev->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
+ tpd->address0 = dma_map_single(&he_dev->pci_dev->dev, skb->data, skb->len, DMA_TO_DEVICE);
tpd->length0 = skb->len | TPD_LST;
#endif
tpd->status |= TPD_INT;
diff --git a/drivers/atm/he.h b/drivers/atm/he.h
index 110a27d2ecfc..f3f53674ef3f 100644
--- a/drivers/atm/he.h
+++ b/drivers/atm/he.h
@@ -281,7 +281,7 @@ struct he_dev {
int irq_peak;
struct tasklet_struct tasklet;
- struct pci_pool *tpd_pool;
+ struct dma_pool *tpd_pool;
struct list_head outstanding_tpds;
dma_addr_t tpdrq_phys;
@@ -296,7 +296,7 @@ struct he_dev {
struct he_buff **rbpl_virt;
unsigned long *rbpl_table;
unsigned long rbpl_hint;
- struct pci_pool *rbpl_pool;
+ struct dma_pool *rbpl_pool;
dma_addr_t rbpl_phys;
struct he_rbp *rbpl_base, *rbpl_tail;
struct list_head rbpl_outstanding;
diff --git a/drivers/atm/horizon.c b/drivers/atm/horizon.c
index 1dc0519333f2..527bbd595e37 100644
--- a/drivers/atm/horizon.c
+++ b/drivers/atm/horizon.c
@@ -458,12 +458,6 @@ static inline void update_tx_channel_config (hrz_dev * dev, short chan, u8 mode,
return;
}
-static inline u16 query_tx_channel_config (hrz_dev * dev, short chan, u8 mode) {
- wr_regw (dev, TX_CHANNEL_CONFIG_COMMAND_OFF,
- chan * TX_CHANNEL_CONFIG_MULT | mode);
- return rd_regw (dev, TX_CHANNEL_CONFIG_DATA_OFF);
-}
-
/********** dump functions **********/
static inline void dump_skb (char * prefix, unsigned int vc, struct sk_buff * skb) {
@@ -513,16 +507,6 @@ static inline void dump_framer (hrz_dev * dev) {
/* RX channels are 10 bit integers, these fns are quite paranoid */
-static inline int channel_to_vpivci (const u16 channel, short * vpi, int * vci) {
- unsigned short vci_bits = 10 - vpi_bits;
- if ((channel & RX_CHANNEL_MASK) == channel) {
- *vci = channel & ((~0)<<vci_bits);
- *vpi = channel >> vci_bits;
- return channel ? 0 : -EINVAL;
- }
- return -EINVAL;
-}
-
static inline int vpivci_to_channel (u16 * channel, const short vpi, const int vci) {
unsigned short vci_bits = 10 - vpi_bits;
if (0 <= vpi && vpi < 1<<vpi_bits && 0 <= vci && vci < 1<<vci_bits) {
@@ -1260,14 +1244,6 @@ static u32 rx_queue_entry_next (hrz_dev * dev) {
return rx_queue_entry;
}
-/********** handle RX disabled by device **********/
-
-static inline void rx_disabled_handler (hrz_dev * dev) {
- wr_regw (dev, RX_CONFIG_OFF, rd_regw (dev, RX_CONFIG_OFF) | RX_ENABLE);
- // count me please
- PRINTK (KERN_WARNING, "RX was disabled!");
-}
-
/********** handle RX data received by device **********/
// called from IRQ handler
diff --git a/drivers/atm/idt77252.c b/drivers/atm/idt77252.c
index 2b24ed056728..074616b39f4d 100644
--- a/drivers/atm/idt77252.c
+++ b/drivers/atm/idt77252.c
@@ -641,7 +641,8 @@ alloc_scq(struct idt77252_dev *card, int class)
scq = kzalloc(sizeof(struct scq_info), GFP_KERNEL);
if (!scq)
return NULL;
- scq->base = pci_zalloc_consistent(card->pcidev, SCQ_SIZE, &scq->paddr);
+ scq->base = dma_zalloc_coherent(&card->pcidev->dev, SCQ_SIZE,
+ &scq->paddr, GFP_KERNEL);
if (scq->base == NULL) {
kfree(scq);
return NULL;
@@ -669,12 +670,12 @@ free_scq(struct idt77252_dev *card, struct scq_info *scq)
struct sk_buff *skb;
struct atm_vcc *vcc;
- pci_free_consistent(card->pcidev, SCQ_SIZE,
- scq->base, scq->paddr);
+ dma_free_coherent(&card->pcidev->dev, SCQ_SIZE,
+ scq->base, scq->paddr);
while ((skb = skb_dequeue(&scq->transmit))) {
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb->len, DMA_TO_DEVICE);
vcc = ATM_SKB(skb)->vcc;
if (vcc->pop)
@@ -684,8 +685,8 @@ free_scq(struct idt77252_dev *card, struct scq_info *scq)
}
while ((skb = skb_dequeue(&scq->pending))) {
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb->len, DMA_TO_DEVICE);
vcc = ATM_SKB(skb)->vcc;
if (vcc->pop)
@@ -800,8 +801,8 @@ drain_scq(struct idt77252_dev *card, struct vc_map *vc)
if (skb) {
TXPRINTK("%s: freeing skb at %p.\n", card->name, skb);
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb->len, DMA_TO_DEVICE);
vcc = ATM_SKB(skb)->vcc;
@@ -846,8 +847,8 @@ queue_skb(struct idt77252_dev *card, struct vc_map *vc,
tbd = &IDT77252_PRV_TBD(skb);
vcc = ATM_SKB(skb)->vcc;
- IDT77252_PRV_PADDR(skb) = pci_map_single(card->pcidev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ IDT77252_PRV_PADDR(skb) = dma_map_single(&card->pcidev->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
error = -EINVAL;
@@ -924,8 +925,8 @@ done:
return 0;
errout:
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb->len, DMA_TO_DEVICE);
return error;
}
@@ -970,8 +971,8 @@ init_rsq(struct idt77252_dev *card)
{
struct rsq_entry *rsqe;
- card->rsq.base = pci_zalloc_consistent(card->pcidev, RSQSIZE,
- &card->rsq.paddr);
+ card->rsq.base = dma_zalloc_coherent(&card->pcidev->dev, RSQSIZE,
+ &card->rsq.paddr, GFP_KERNEL);
if (card->rsq.base == NULL) {
printk("%s: can't allocate RSQ.\n", card->name);
return -1;
@@ -1001,8 +1002,8 @@ init_rsq(struct idt77252_dev *card)
static void
deinit_rsq(struct idt77252_dev *card)
{
- pci_free_consistent(card->pcidev, RSQSIZE,
- card->rsq.base, card->rsq.paddr);
+ dma_free_coherent(&card->pcidev->dev, RSQSIZE,
+ card->rsq.base, card->rsq.paddr);
}
static void
@@ -1057,9 +1058,9 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
vcc = vc->rx_vcc;
- pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb_end_pointer(skb) - skb->data,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb_end_pointer(skb) - skb->data,
+ DMA_FROM_DEVICE);
if ((vcc->qos.aal == ATM_AAL0) ||
(vcc->qos.aal == ATM_AAL34)) {
@@ -1180,9 +1181,9 @@ dequeue_rx(struct idt77252_dev *card, struct rsq_entry *rsqe)
return;
}
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
skb_end_pointer(skb) - skb->data,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
sb_pool_remove(card, skb);
skb_trim(skb, len);
@@ -1254,9 +1255,9 @@ idt77252_rx_raw(struct idt77252_dev *card)
head = IDT77252_PRV_PADDR(queue) + (queue->data - queue->head - 16);
tail = readl(SAR_REG_RAWCT);
- pci_dma_sync_single_for_cpu(card->pcidev, IDT77252_PRV_PADDR(queue),
- skb_end_offset(queue) - 16,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&card->pcidev->dev, IDT77252_PRV_PADDR(queue),
+ skb_end_offset(queue) - 16,
+ DMA_FROM_DEVICE);
while (head != tail) {
unsigned int vpi, vci;
@@ -1348,11 +1349,11 @@ drop:
if (next) {
card->raw_cell_head = next;
queue = card->raw_cell_head;
- pci_dma_sync_single_for_cpu(card->pcidev,
- IDT77252_PRV_PADDR(queue),
- (skb_end_pointer(queue) -
- queue->data),
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_cpu(&card->pcidev->dev,
+ IDT77252_PRV_PADDR(queue),
+ (skb_end_pointer(queue) -
+ queue->data),
+ DMA_FROM_DEVICE);
} else {
card->raw_cell_head = NULL;
printk("%s: raw cell queue overrun\n",
@@ -1375,8 +1376,8 @@ init_tsq(struct idt77252_dev *card)
{
struct tsq_entry *tsqe;
- card->tsq.base = pci_alloc_consistent(card->pcidev, RSQSIZE,
- &card->tsq.paddr);
+ card->tsq.base = dma_alloc_coherent(&card->pcidev->dev, RSQSIZE,
+ &card->tsq.paddr, GFP_KERNEL);
if (card->tsq.base == NULL) {
printk("%s: can't allocate TSQ.\n", card->name);
return -1;
@@ -1398,8 +1399,8 @@ init_tsq(struct idt77252_dev *card)
static void
deinit_tsq(struct idt77252_dev *card)
{
- pci_free_consistent(card->pcidev, TSQSIZE,
- card->tsq.base, card->tsq.paddr);
+ dma_free_coherent(&card->pcidev->dev, TSQSIZE,
+ card->tsq.base, card->tsq.paddr);
}
static void
@@ -1861,9 +1862,9 @@ add_rx_skb(struct idt77252_dev *card, int queue,
goto outfree;
}
- paddr = pci_map_single(card->pcidev, skb->data,
+ paddr = dma_map_single(&card->pcidev->dev, skb->data,
skb_end_pointer(skb) - skb->data,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
IDT77252_PRV_PADDR(skb) = paddr;
if (push_rx_skb(card, skb, queue)) {
@@ -1875,8 +1876,8 @@ add_rx_skb(struct idt77252_dev *card, int queue,
return;
outunmap:
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb_end_pointer(skb) - skb->data, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb_end_pointer(skb) - skb->data, DMA_FROM_DEVICE);
handle = IDT77252_PRV_POOL(skb);
card->sbpool[POOL_QUEUE(handle)].skb[POOL_INDEX(handle)] = NULL;
@@ -1892,15 +1893,15 @@ recycle_rx_skb(struct idt77252_dev *card, struct sk_buff *skb)
u32 handle = IDT77252_PRV_POOL(skb);
int err;
- pci_dma_sync_single_for_device(card->pcidev, IDT77252_PRV_PADDR(skb),
- skb_end_pointer(skb) - skb->data,
- PCI_DMA_FROMDEVICE);
+ dma_sync_single_for_device(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
+ skb_end_pointer(skb) - skb->data,
+ DMA_FROM_DEVICE);
err = push_rx_skb(card, skb, POOL_QUEUE(handle));
if (err) {
- pci_unmap_single(card->pcidev, IDT77252_PRV_PADDR(skb),
+ dma_unmap_single(&card->pcidev->dev, IDT77252_PRV_PADDR(skb),
skb_end_pointer(skb) - skb->data,
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
sb_pool_remove(card, skb);
dev_kfree_skb(skb);
}
@@ -3058,11 +3059,11 @@ deinit_card(struct idt77252_dev *card)
for (j = 0; j < FBQ_SIZE; j++) {
skb = card->sbpool[i].skb[j];
if (skb) {
- pci_unmap_single(card->pcidev,
+ dma_unmap_single(&card->pcidev->dev,
IDT77252_PRV_PADDR(skb),
(skb_end_pointer(skb) -
skb->data),
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
card->sbpool[i].skb[j] = NULL;
dev_kfree_skb(skb);
}
@@ -3076,8 +3077,8 @@ deinit_card(struct idt77252_dev *card)
vfree(card->vcs);
if (card->raw_cell_hnd) {
- pci_free_consistent(card->pcidev, 2 * sizeof(u32),
- card->raw_cell_hnd, card->raw_cell_paddr);
+ dma_free_coherent(&card->pcidev->dev, 2 * sizeof(u32),
+ card->raw_cell_hnd, card->raw_cell_paddr);
}
if (card->rsq.base) {
@@ -3397,9 +3398,10 @@ static int init_card(struct atm_dev *dev)
writel(0, SAR_REG_GP);
/* Initialize RAW Cell Handle Register */
- card->raw_cell_hnd = pci_zalloc_consistent(card->pcidev,
- 2 * sizeof(u32),
- &card->raw_cell_paddr);
+ card->raw_cell_hnd = dma_zalloc_coherent(&card->pcidev->dev,
+ 2 * sizeof(u32),
+ &card->raw_cell_paddr,
+ GFP_KERNEL);
if (!card->raw_cell_hnd) {
printk("%s: memory allocation failure.\n", card->name);
deinit_card(card);
@@ -3611,6 +3613,11 @@ static int idt77252_init_one(struct pci_dev *pcidev,
return err;
}
+ if ((err = dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)))) {
+ printk("idt77252: can't enable DMA for PCI device at %s\n", pci_name(pcidev));
+ return err;
+ }
+
card = kzalloc(sizeof(struct idt77252_dev), GFP_KERNEL);
if (!card) {
printk("idt77252-%d: can't allocate private data\n", index);
diff --git a/drivers/atm/iphase.c b/drivers/atm/iphase.c
index 4217f29a85e0..924f8e26789d 100644
--- a/drivers/atm/iphase.c
+++ b/drivers/atm/iphase.c
@@ -1185,8 +1185,8 @@ static int rx_pkt(struct atm_dev *dev)
/* Build the DLE structure */
wr_ptr = iadev->rx_dle_q.write;
- wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
- len, PCI_DMA_FROMDEVICE);
+ wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data,
+ len, DMA_FROM_DEVICE);
wr_ptr->local_pkt_addr = buf_addr;
wr_ptr->bytes = len; /* We don't know this do we ?? */
wr_ptr->mode = DMA_INT_ENABLE;
@@ -1306,8 +1306,8 @@ static void rx_dle_intr(struct atm_dev *dev)
u_short length;
struct ia_vcc *ia_vcc;
- pci_unmap_single(iadev->pci, iadev->rx_dle_q.write->sys_pkt_addr,
- len, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&iadev->pci->dev, iadev->rx_dle_q.write->sys_pkt_addr,
+ len, DMA_FROM_DEVICE);
/* no VCC related housekeeping done as yet. lets see */
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
@@ -1430,8 +1430,8 @@ static int rx_init(struct atm_dev *dev)
// spin_lock_init(&iadev->rx_lock);
/* Allocate 4k bytes - more aligned than needed (4k boundary) */
- dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
- &iadev->rx_dle_dma);
+ dle_addr = dma_alloc_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE,
+ &iadev->rx_dle_dma, GFP_KERNEL);
if (!dle_addr) {
printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
goto err_out;
@@ -1631,8 +1631,8 @@ static int rx_init(struct atm_dev *dev)
return 0;
err_free_dle:
- pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
- iadev->rx_dle_dma);
+ dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+ iadev->rx_dle_dma);
err_out:
return -ENOMEM;
}
@@ -1702,8 +1702,8 @@ static void tx_dle_intr(struct atm_dev *dev)
/* Revenge of the 2 dle (skb + trailer) used in ia_pkt_tx() */
if (!((dle - iadev->tx_dle_q.start)%(2*sizeof(struct dle)))) {
- pci_unmap_single(iadev->pci, dle->sys_pkt_addr, skb->len,
- PCI_DMA_TODEVICE);
+ dma_unmap_single(&iadev->pci->dev, dle->sys_pkt_addr, skb->len,
+ DMA_TO_DEVICE);
}
vcc = ATM_SKB(skb)->vcc;
if (!vcc) {
@@ -1917,8 +1917,8 @@ static int tx_init(struct atm_dev *dev)
readw(iadev->seg_reg+SEG_MASK_REG));)
/* Allocate 4k (boundary aligned) bytes */
- dle_addr = pci_alloc_consistent(iadev->pci, DLE_TOTAL_SIZE,
- &iadev->tx_dle_dma);
+ dle_addr = dma_alloc_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE,
+ &iadev->tx_dle_dma, GFP_KERNEL);
if (!dle_addr) {
printk(KERN_ERR DEV_LABEL "can't allocate DLEs\n");
goto err_out;
@@ -1989,8 +1989,10 @@ static int tx_init(struct atm_dev *dev)
goto err_free_tx_bufs;
}
iadev->tx_buf[i].cpcs = cpcs;
- iadev->tx_buf[i].dma_addr = pci_map_single(iadev->pci,
- cpcs, sizeof(*cpcs), PCI_DMA_TODEVICE);
+ iadev->tx_buf[i].dma_addr = dma_map_single(&iadev->pci->dev,
+ cpcs,
+ sizeof(*cpcs),
+ DMA_TO_DEVICE);
}
iadev->desc_tbl = kmalloc(iadev->num_tx_desc *
sizeof(struct desc_tbl_t), GFP_KERNEL);
@@ -2198,14 +2200,14 @@ err_free_tx_bufs:
while (--i >= 0) {
struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
- pci_unmap_single(iadev->pci, desc->dma_addr,
- sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+ dma_unmap_single(&iadev->pci->dev, desc->dma_addr,
+ sizeof(*desc->cpcs), DMA_TO_DEVICE);
kfree(desc->cpcs);
}
kfree(iadev->tx_buf);
err_free_dle:
- pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
- iadev->tx_dle_dma);
+ dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+ iadev->tx_dle_dma);
err_out:
return -ENOMEM;
}
@@ -2476,20 +2478,20 @@ static void ia_free_tx(IADEV *iadev)
for (i = 0; i < iadev->num_tx_desc; i++) {
struct cpcs_trailer_desc *desc = iadev->tx_buf + i;
- pci_unmap_single(iadev->pci, desc->dma_addr,
- sizeof(*desc->cpcs), PCI_DMA_TODEVICE);
+ dma_unmap_single(&iadev->pci->dev, desc->dma_addr,
+ sizeof(*desc->cpcs), DMA_TO_DEVICE);
kfree(desc->cpcs);
}
kfree(iadev->tx_buf);
- pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
- iadev->tx_dle_dma);
+ dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->tx_dle_q.start,
+ iadev->tx_dle_dma);
}
static void ia_free_rx(IADEV *iadev)
{
kfree(iadev->rx_open);
- pci_free_consistent(iadev->pci, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
- iadev->rx_dle_dma);
+ dma_free_coherent(&iadev->pci->dev, DLE_TOTAL_SIZE, iadev->rx_dle_q.start,
+ iadev->rx_dle_dma);
}
static int ia_start(struct atm_dev *dev)
@@ -3009,8 +3011,8 @@ static int ia_pkt_tx (struct atm_vcc *vcc, struct sk_buff *skb) {
/* Build the DLE structure */
wr_ptr = iadev->tx_dle_q.write;
memset((caddr_t)wr_ptr, 0, sizeof(*wr_ptr));
- wr_ptr->sys_pkt_addr = pci_map_single(iadev->pci, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ wr_ptr->sys_pkt_addr = dma_map_single(&iadev->pci->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
wr_ptr->local_pkt_addr = (buf_desc_ptr->buf_start_hi << 16) |
buf_desc_ptr->buf_start_lo;
/* wr_ptr->bytes = swap_byte_order(total_len); didn't seem to affect?? */
diff --git a/drivers/atm/lanai.c b/drivers/atm/lanai.c
index 93eaf8d94492..ce43ae3e87b3 100644
--- a/drivers/atm/lanai.c
+++ b/drivers/atm/lanai.c
@@ -346,7 +346,8 @@ static void lanai_buf_allocate(struct lanai_buffer *buf,
* everything, but the way the lanai uses DMA memory would
* make that a terrific pain. This is much simpler.
*/
- buf->start = pci_alloc_consistent(pci, size, &buf->dmaaddr);
+ buf->start = dma_alloc_coherent(&pci->dev,
+ size, &buf->dmaaddr, GFP_KERNEL);
if (buf->start != NULL) { /* Success */
/* Lanai requires 256-byte alignment of DMA bufs */
APRINTK((buf->dmaaddr & ~0xFFFFFF00) == 0,
@@ -372,8 +373,8 @@ static void lanai_buf_deallocate(struct lanai_buffer *buf,
struct pci_dev *pci)
{
if (buf->start != NULL) {
- pci_free_consistent(pci, lanai_buf_size(buf),
- buf->start, buf->dmaaddr);
+ dma_free_coherent(&pci->dev, lanai_buf_size(buf),
+ buf->start, buf->dmaaddr);
buf->start = buf->end = buf->ptr = NULL;
}
}
@@ -681,15 +682,6 @@ static inline int aal5_size(int size)
return cells * 48;
}
-/* How many bytes can we send if we have "space" space, assuming we have
- * to send full cells
- */
-static inline int aal5_spacefor(int space)
-{
- int cells = space / 48;
- return cells * 48;
-}
-
/* -------------------- FREE AN ATM SKB: */
static inline void lanai_free_skb(struct atm_vcc *atmvcc, struct sk_buff *skb)
@@ -1953,12 +1945,7 @@ static int lanai_pci_start(struct lanai_dev *lanai)
return -ENXIO;
}
pci_set_master(pci);
- if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) != 0) {
- printk(KERN_WARNING DEV_LABEL
- "(itf %d): No suitable DMA available.\n", lanai->number);
- return -EBUSY;
- }
- if (pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) != 0) {
+ if (dma_set_mask_and_coherent(&pci->dev, DMA_BIT_MASK(32)) != 0) {
printk(KERN_WARNING DEV_LABEL
"(itf %d): No suitable DMA available.\n", lanai->number);
return -EBUSY;
diff --git a/drivers/atm/nicstar.c b/drivers/atm/nicstar.c
index 9988ac98b6d8..b7e1cc0a97c8 100644
--- a/drivers/atm/nicstar.c
+++ b/drivers/atm/nicstar.c
@@ -252,10 +252,10 @@ static void nicstar_remove_one(struct pci_dev *pcidev)
free_scq(card, card->scd2vc[j]->scq, card->scd2vc[j]->tx_vcc);
}
idr_destroy(&card->idr);
- pci_free_consistent(card->pcidev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
- card->rsq.org, card->rsq.dma);
- pci_free_consistent(card->pcidev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
- card->tsq.org, card->tsq.dma);
+ dma_free_coherent(&card->pcidev->dev, NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ card->rsq.org, card->rsq.dma);
+ dma_free_coherent(&card->pcidev->dev, NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ card->tsq.org, card->tsq.dma);
free_irq(card->pcidev->irq, card);
iounmap(card->membase);
kfree(card);
@@ -370,8 +370,7 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
ns_init_card_error(card, error);
return error;
}
- if ((pci_set_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0) ||
- (pci_set_consistent_dma_mask(pcidev, DMA_BIT_MASK(32)) != 0)) {
+ if (dma_set_mask_and_coherent(&pcidev->dev, DMA_BIT_MASK(32)) != 0) {
printk(KERN_WARNING
"nicstar%d: No suitable DMA available.\n", i);
error = 2;
@@ -535,9 +534,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
writel(0x00000000, card->membase + VPM);
/* Initialize TSQ */
- card->tsq.org = pci_alloc_consistent(card->pcidev,
- NS_TSQSIZE + NS_TSQ_ALIGNMENT,
- &card->tsq.dma);
+ card->tsq.org = dma_alloc_coherent(&card->pcidev->dev,
+ NS_TSQSIZE + NS_TSQ_ALIGNMENT,
+ &card->tsq.dma, GFP_KERNEL);
if (card->tsq.org == NULL) {
printk("nicstar%d: can't allocate TSQ.\n", i);
error = 10;
@@ -554,9 +553,9 @@ static int ns_init_card(int i, struct pci_dev *pcidev)
PRINTK("nicstar%d: TSQ base at 0x%p.\n", i, card->tsq.base);
/* Initialize RSQ */
- card->rsq.org = pci_alloc_consistent(card->pcidev,
- NS_RSQSIZE + NS_RSQ_ALIGNMENT,
- &card->rsq.dma);
+ card->rsq.org = dma_alloc_coherent(&card->pcidev->dev,
+ NS_RSQSIZE + NS_RSQ_ALIGNMENT,
+ &card->rsq.dma, GFP_KERNEL);
if (card->rsq.org == NULL) {
printk("nicstar%d: can't allocate RSQ.\n", i);
error = 11;
@@ -874,7 +873,8 @@ static scq_info *get_scq(ns_dev *card, int size, u32 scd)
scq = kmalloc(sizeof(scq_info), GFP_KERNEL);
if (!scq)
return NULL;
- scq->org = pci_alloc_consistent(card->pcidev, 2 * size, &scq->dma);
+ scq->org = dma_alloc_coherent(&card->pcidev->dev,
+ 2 * size, &scq->dma, GFP_KERNEL);
if (!scq->org) {
kfree(scq);
return NULL;
@@ -936,10 +936,10 @@ static void free_scq(ns_dev *card, scq_info *scq, struct atm_vcc *vcc)
}
}
kfree(scq->skb);
- pci_free_consistent(card->pcidev,
- 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ?
- VBR_SCQSIZE : CBR_SCQSIZE),
- scq->org, scq->dma);
+ dma_free_coherent(&card->pcidev->dev,
+ 2 * (scq->num_entries == VBR_SCQ_NUM_ENTRIES ?
+ VBR_SCQSIZE : CBR_SCQSIZE),
+ scq->org, scq->dma);
kfree(scq);
}
@@ -957,11 +957,11 @@ static void push_rxbufs(ns_dev * card, struct sk_buff *skb)
handle2 = NULL;
addr2 = 0;
handle1 = skb;
- addr1 = pci_map_single(card->pcidev,
+ addr1 = dma_map_single(&card->pcidev->dev,
skb->data,
(NS_PRV_BUFTYPE(skb) == BUF_SM
? NS_SMSKBSIZE : NS_LGSKBSIZE),
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
NS_PRV_DMA(skb) = addr1; /* save so we can unmap later */
#ifdef GENERAL_DEBUG
@@ -1670,8 +1670,8 @@ static int ns_send(struct atm_vcc *vcc, struct sk_buff *skb)
ATM_SKB(skb)->vcc = vcc;
- NS_PRV_DMA(skb) = pci_map_single(card->pcidev, skb->data,
- skb->len, PCI_DMA_TODEVICE);
+ NS_PRV_DMA(skb) = dma_map_single(&card->pcidev->dev, skb->data,
+ skb->len, DMA_TO_DEVICE);
if (vcc->qos.aal == ATM_AAL5) {
buflen = (skb->len + 47 + 8) / 48 * 48; /* Multiple of 48 */
@@ -1930,10 +1930,10 @@ static void drain_scq(ns_dev * card, scq_info * scq, int pos)
XPRINTK("nicstar%d: freeing skb at 0x%p (index %d).\n",
card->index, skb, i);
if (skb != NULL) {
- pci_unmap_single(card->pcidev,
+ dma_unmap_single(&card->pcidev->dev,
NS_PRV_DMA(skb),
skb->len,
- PCI_DMA_TODEVICE);
+ DMA_TO_DEVICE);
vcc = ATM_SKB(skb)->vcc;
if (vcc && vcc->pop != NULL) {
vcc->pop(vcc, skb);
@@ -1992,16 +1992,16 @@ static void dequeue_rx(ns_dev * card, ns_rsqe * rsqe)
return;
}
idr_remove(&card->idr, id);
- pci_dma_sync_single_for_cpu(card->pcidev,
- NS_PRV_DMA(skb),
- (NS_PRV_BUFTYPE(skb) == BUF_SM
- ? NS_SMSKBSIZE : NS_LGSKBSIZE),
- PCI_DMA_FROMDEVICE);
- pci_unmap_single(card->pcidev,
+ dma_sync_single_for_cpu(&card->pcidev->dev,
+ NS_PRV_DMA(skb),
+ (NS_PRV_BUFTYPE(skb) == BUF_SM
+ ? NS_SMSKBSIZE : NS_LGSKBSIZE),
+ DMA_FROM_DEVICE);
+ dma_unmap_single(&card->pcidev->dev,
NS_PRV_DMA(skb),
(NS_PRV_BUFTYPE(skb) == BUF_SM
? NS_SMSKBSIZE : NS_LGSKBSIZE),
- PCI_DMA_FROMDEVICE);
+ DMA_FROM_DEVICE);
vpi = ns_rsqe_vpi(rsqe);
vci = ns_rsqe_vci(rsqe);
if (vpi >= 1UL << card->vpibits || vci >= 1UL << card->vcibits) {
diff --git a/drivers/atm/solos-pci.c b/drivers/atm/solos-pci.c
index 21b0bc6a9c96..74e18b0a6d89 100644
--- a/drivers/atm/solos-pci.c
+++ b/drivers/atm/solos-pci.c
@@ -785,8 +785,8 @@ static void solos_bh(unsigned long card_arg)
skb = card->rx_skb[port];
card->rx_skb[port] = NULL;
- pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
- RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr,
+ RX_DMA_SIZE, DMA_FROM_DEVICE);
header = (void *)skb->data;
size = le16_to_cpu(header->size);
@@ -872,8 +872,8 @@ static void solos_bh(unsigned long card_arg)
struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC);
if (skb) {
SKB_CB(skb)->dma_addr =
- pci_map_single(card->dev, skb->data,
- RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+ dma_map_single(&card->dev->dev, skb->data,
+ RX_DMA_SIZE, DMA_FROM_DEVICE);
iowrite32(SKB_CB(skb)->dma_addr,
card->config_regs + RX_DMA_ADDR(port));
card->rx_skb[port] = skb;
@@ -1069,8 +1069,8 @@ static uint32_t fpga_tx(struct solos_card *card)
if (tx_pending & 1) {
struct sk_buff *oldskb = card->tx_skb[port];
if (oldskb) {
- pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
- oldskb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&card->dev->dev, SKB_CB(oldskb)->dma_addr,
+ oldskb->len, DMA_TO_DEVICE);
card->tx_skb[port] = NULL;
}
spin_lock(&card->tx_queue_lock);
@@ -1089,8 +1089,8 @@ static uint32_t fpga_tx(struct solos_card *card)
data = card->dma_bounce + (BUF_SIZE * port);
memcpy(data, skb->data, skb->len);
}
- SKB_CB(skb)->dma_addr = pci_map_single(card->dev, data,
- skb->len, PCI_DMA_TODEVICE);
+ SKB_CB(skb)->dma_addr = dma_map_single(&card->dev->dev, data,
+ skb->len, DMA_TO_DEVICE);
card->tx_skb[port] = skb;
iowrite32(SKB_CB(skb)->dma_addr,
card->config_regs + TX_DMA_ADDR(port));
@@ -1210,7 +1210,7 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
goto out;
}
- err = pci_set_dma_mask(dev, DMA_BIT_MASK(32));
+ err = dma_set_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
if (err) {
dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n");
goto out;
@@ -1411,14 +1411,14 @@ static void atm_remove(struct solos_card *card)
skb = card->rx_skb[i];
if (skb) {
- pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
- RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+ dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr,
+ RX_DMA_SIZE, DMA_FROM_DEVICE);
dev_kfree_skb(skb);
}
skb = card->tx_skb[i];
if (skb) {
- pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
- skb->len, PCI_DMA_TODEVICE);
+ dma_unmap_single(&card->dev->dev, SKB_CB(skb)->dma_addr,
+ skb->len, DMA_TO_DEVICE);
dev_kfree_skb(skb);
}
while ((skb = skb_dequeue(&card->tx_queue[i])))
diff --git a/drivers/atm/zatm.c b/drivers/atm/zatm.c
index 969c3c29000c..cecfb943762f 100644
--- a/drivers/atm/zatm.c
+++ b/drivers/atm/zatm.c
@@ -1306,19 +1306,20 @@ static int zatm_start(struct atm_dev *dev)
if (!mbx_entries[i])
continue;
- mbx = pci_alloc_consistent(pdev, 2*MBX_SIZE(i), &mbx_dma);
+ mbx = dma_alloc_coherent(&pdev->dev,
+ 2 * MBX_SIZE(i), &mbx_dma, GFP_KERNEL);
if (!mbx) {
error = -ENOMEM;
goto out;
}
/*
- * Alignment provided by pci_alloc_consistent() isn't enough
+ * Alignment provided by dma_alloc_coherent() isn't enough
* for this device.
*/
if (((unsigned long)mbx ^ mbx_dma) & 0xffff) {
printk(KERN_ERR DEV_LABEL "(itf %d): system "
"bus incompatible with driver\n", dev->number);
- pci_free_consistent(pdev, 2*MBX_SIZE(i), mbx, mbx_dma);
+ dma_free_coherent(&pdev->dev, 2*MBX_SIZE(i), mbx, mbx_dma);
error = -ENODEV;
goto out;
}
@@ -1354,9 +1355,9 @@ out_tx:
kfree(zatm_dev->tx_map);
out:
while (i-- > 0) {
- pci_free_consistent(pdev, 2*MBX_SIZE(i),
- (void *)zatm_dev->mbx_start[i],
- zatm_dev->mbx_dma[i]);
+ dma_free_coherent(&pdev->dev, 2 * MBX_SIZE(i),
+ (void *)zatm_dev->mbx_start[i],
+ zatm_dev->mbx_dma[i]);
}
free_irq(zatm_dev->irq, dev);
goto done;
@@ -1608,6 +1609,10 @@ static int zatm_init_one(struct pci_dev *pci_dev,
if (ret < 0)
goto out_disable;
+ ret = dma_set_mask_and_coherent(&pci_dev->dev, DMA_BIT_MASK(32));
+ if (ret < 0)
+ goto out_disable;
+
zatm_dev->pci_dev = pci_dev;
dev->dev_data = zatm_dev;
zatm_dev->copper = (int)ent->driver_data;
diff --git a/drivers/base/core.c b/drivers/base/core.c
index 97e2baf6e5d8..07304a3b9ee2 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -2080,54 +2080,47 @@ int dev_printk_emit(int level, const struct device *dev, const char *fmt, ...)
}
EXPORT_SYMBOL(dev_printk_emit);
-static int __dev_printk(const char *level, const struct device *dev,
+static void __dev_printk(const char *level, const struct device *dev,
struct va_format *vaf)
{
- if (!dev)
- return printk("%s(NULL device *): %pV", level, vaf);
-
- return dev_printk_emit(level[1] - '0', dev,
- "%s %s: %pV",
- dev_driver_string(dev), dev_name(dev), vaf);
+ if (dev)
+ dev_printk_emit(level[1] - '0', dev, "%s %s: %pV",
+ dev_driver_string(dev), dev_name(dev), vaf);
+ else
+ printk("%s(NULL device *): %pV", level, vaf);
}
-int dev_printk(const char *level, const struct device *dev,
- const char *fmt, ...)
+void dev_printk(const char *level, const struct device *dev,
+ const char *fmt, ...)
{
struct va_format vaf;
va_list args;
- int r;
va_start(args, fmt);
vaf.fmt = fmt;
vaf.va = &args;
- r = __dev_printk(level, dev, &vaf);
+ __dev_printk(level, dev, &vaf);
va_end(args);
-
- return r;
}
EXPORT_SYMBOL(dev_printk);
#define define_dev_printk_level(func, kern_level) \
-int func(const struct device *dev, const char *fmt, ...) \
+void func(const struct device *dev, const char *fmt, ...) \
{ \
struct va_format vaf; \
va_list args; \
- int r; \
\
va_start(args, fmt); \
\
vaf.fmt = fmt; \
vaf.va = &args; \
\
- r = __dev_printk(kern_level, dev, &vaf); \
+ __dev_printk(kern_level, dev, &vaf); \
\
va_end(args); \
- \
- return r; \
} \
EXPORT_SYMBOL(func);
diff --git a/drivers/base/cpu.c b/drivers/base/cpu.c
index f829a4c71749..f160ea44a86d 100644
--- a/drivers/base/cpu.c
+++ b/drivers/base/cpu.c
@@ -245,7 +245,7 @@ static ssize_t print_cpus_offline(struct device *dev,
if (!alloc_cpumask_var(&offline, GFP_KERNEL))
return -ENOMEM;
cpumask_andnot(offline, cpu_possible_mask, cpu_online_mask);
- n = cpulist_scnprintf(buf, len, offline);
+ n = scnprintf(buf, len, "%*pbl", cpumask_pr_args(offline));
free_cpumask_var(offline);
/* display offline cpus >= nr_cpu_ids */
diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c
index 58470c395301..6c5c9edf5ff6 100644
--- a/drivers/base/firmware_class.c
+++ b/drivers/base/firmware_class.c
@@ -94,7 +94,7 @@ static int loading_timeout = 60; /* In seconds */
static inline long firmware_loading_timeout(void)
{
- return loading_timeout > 0 ? loading_timeout * HZ : MAX_SCHEDULE_TIMEOUT;
+ return loading_timeout > 0 ? loading_timeout * HZ : MAX_JIFFY_OFFSET;
}
/* firmware behavior options */
@@ -446,7 +446,6 @@ static int fw_add_devm_name(struct device *dev, const char *name)
*/
#ifdef CONFIG_FW_LOADER_USER_HELPER
struct firmware_priv {
- struct delayed_work timeout_work;
bool nowait;
struct device dev;
struct firmware_buf *buf;
@@ -836,16 +835,6 @@ static struct bin_attribute firmware_attr_data = {
.write = firmware_data_write,
};
-static void firmware_class_timeout_work(struct work_struct *work)
-{
- struct firmware_priv *fw_priv = container_of(work,
- struct firmware_priv, timeout_work.work);
-
- mutex_lock(&fw_lock);
- fw_load_abort(fw_priv);
- mutex_unlock(&fw_lock);
-}
-
static struct firmware_priv *
fw_create_instance(struct firmware *firmware, const char *fw_name,
struct device *device, unsigned int opt_flags)
@@ -855,16 +844,12 @@ fw_create_instance(struct firmware *firmware, const char *fw_name,
fw_priv = kzalloc(sizeof(*fw_priv), GFP_KERNEL);
if (!fw_priv) {
- dev_err(device, "%s: kmalloc failed\n", __func__);
fw_priv = ERR_PTR(-ENOMEM);
goto exit;
}
fw_priv->nowait = !!(opt_flags & FW_OPT_NOWAIT);
fw_priv->fw = firmware;
- INIT_DELAYED_WORK(&fw_priv->timeout_work,
- firmware_class_timeout_work);
-
f_dev = &fw_priv->dev;
device_initialize(f_dev);
@@ -917,16 +902,19 @@ static int _request_firmware_load(struct firmware_priv *fw_priv,
buf->need_uevent = true;
dev_set_uevent_suppress(f_dev, false);
dev_dbg(f_dev, "firmware: requesting %s\n", buf->fw_id);
- if (timeout != MAX_SCHEDULE_TIMEOUT)
- queue_delayed_work(system_power_efficient_wq,
- &fw_priv->timeout_work, timeout);
-
kobject_uevent(&fw_priv->dev.kobj, KOBJ_ADD);
+ } else {
+ timeout = MAX_JIFFY_OFFSET;
}
- retval = wait_for_completion_interruptible(&buf->completion);
+ retval = wait_for_completion_interruptible_timeout(&buf->completion,
+ timeout);
+ if (retval == -ERESTARTSYS || !retval) {
+ mutex_lock(&fw_lock);
+ fw_load_abort(fw_priv);
+ mutex_unlock(&fw_lock);
+ }
- cancel_delayed_work_sync(&fw_priv->timeout_work);
if (is_fw_load_aborted(buf))
retval = -EAGAIN;
else if (!buf->data)
@@ -1194,7 +1182,7 @@ request_firmware(const struct firmware **firmware_p, const char *name,
EXPORT_SYMBOL(request_firmware);
/**
- * request_firmware: - load firmware directly without usermode helper
+ * request_firmware_direct: - load firmware directly without usermode helper
* @firmware_p: pointer to firmware image
* @name: name of firmware file
* @device: device for which firmware is being loaded
diff --git a/drivers/base/node.c b/drivers/base/node.c
index a3b82e9c7f20..36fabe43cd44 100644
--- a/drivers/base/node.c
+++ b/drivers/base/node.c
@@ -605,7 +605,8 @@ static ssize_t print_nodes_state(enum node_states state, char *buf)
{
int n;
- n = nodelist_scnprintf(buf, PAGE_SIZE-2, node_states[state]);
+ n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+ nodemask_pr_args(&node_states[state]));
buf[n++] = '\n';
buf[n] = '\0';
return n;
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index d626576a4f75..7fdd0172605a 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -81,10 +81,8 @@ static int __pm_clk_add(struct device *dev, const char *con_id,
return -EINVAL;
ce = kzalloc(sizeof(*ce), GFP_KERNEL);
- if (!ce) {
- dev_err(dev, "Not enough memory for clock entry.\n");
+ if (!ce)
return -ENOMEM;
- }
if (con_id) {
ce->con_id = kstrdup(con_id, GFP_KERNEL);
diff --git a/drivers/base/power/common.c b/drivers/base/power/common.c
index b0f138806bbc..f32b802b98f4 100644
--- a/drivers/base/power/common.c
+++ b/drivers/base/power/common.c
@@ -19,8 +19,8 @@
* @dev: Device to handle.
*
* If power.subsys_data is NULL, point it to a new object, otherwise increment
- * its reference counter. Return 1 if a new object has been created, otherwise
- * return 0 or error code.
+ * its reference counter. Return 0 if new object has been created or refcount
+ * increased, otherwise negative error code.
*/
int dev_pm_get_subsys_data(struct device *dev)
{
@@ -56,13 +56,11 @@ EXPORT_SYMBOL_GPL(dev_pm_get_subsys_data);
* @dev: Device to handle.
*
* If the reference counter of power.subsys_data is zero after dropping the
- * reference, power.subsys_data is removed. Return 1 if that happens or 0
- * otherwise.
+ * reference, power.subsys_data is removed.
*/
-int dev_pm_put_subsys_data(struct device *dev)
+void dev_pm_put_subsys_data(struct device *dev)
{
struct pm_subsys_data *psd;
- int ret = 1;
spin_lock_irq(&dev->power.lock);
@@ -70,18 +68,14 @@ int dev_pm_put_subsys_data(struct device *dev)
if (!psd)
goto out;
- if (--psd->refcount == 0) {
+ if (--psd->refcount == 0)
dev->power.subsys_data = NULL;
- } else {
+ else
psd = NULL;
- ret = 0;
- }
out:
spin_unlock_irq(&dev->power.lock);
kfree(psd);
-
- return ret;
}
EXPORT_SYMBOL_GPL(dev_pm_put_subsys_data);
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index 0d8780c04a5e..ba4abbe4693c 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -344,14 +344,7 @@ static int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
struct device *dev;
gpd_data = container_of(nb, struct generic_pm_domain_data, nb);
-
- mutex_lock(&gpd_data->lock);
dev = gpd_data->base.dev;
- if (!dev) {
- mutex_unlock(&gpd_data->lock);
- return NOTIFY_DONE;
- }
- mutex_unlock(&gpd_data->lock);
for (;;) {
struct generic_pm_domain *genpd;
@@ -1384,25 +1377,66 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);
#endif /* CONFIG_PM_SLEEP */
-static struct generic_pm_domain_data *__pm_genpd_alloc_dev_data(struct device *dev)
+static struct generic_pm_domain_data *genpd_alloc_dev_data(struct device *dev,
+ struct generic_pm_domain *genpd,
+ struct gpd_timing_data *td)
{
struct generic_pm_domain_data *gpd_data;
+ int ret;
+
+ ret = dev_pm_get_subsys_data(dev);
+ if (ret)
+ return ERR_PTR(ret);
gpd_data = kzalloc(sizeof(*gpd_data), GFP_KERNEL);
- if (!gpd_data)
- return NULL;
+ if (!gpd_data) {
+ ret = -ENOMEM;
+ goto err_put;
+ }
+
+ if (td)
+ gpd_data->td = *td;
- mutex_init(&gpd_data->lock);
+ gpd_data->base.dev = dev;
+ gpd_data->need_restore = -1;
+ gpd_data->td.constraint_changed = true;
+ gpd_data->td.effective_constraint_ns = -1;
gpd_data->nb.notifier_call = genpd_dev_pm_qos_notifier;
- dev_pm_qos_add_notifier(dev, &gpd_data->nb);
+
+ spin_lock_irq(&dev->power.lock);
+
+ if (dev->power.subsys_data->domain_data) {
+ ret = -EINVAL;
+ goto err_free;
+ }
+
+ dev->power.subsys_data->domain_data = &gpd_data->base;
+ dev->pm_domain = &genpd->domain;
+
+ spin_unlock_irq(&dev->power.lock);
+
return gpd_data;
+
+ err_free:
+ spin_unlock_irq(&dev->power.lock);
+ kfree(gpd_data);
+ err_put:
+ dev_pm_put_subsys_data(dev);
+ return ERR_PTR(ret);
}
-static void __pm_genpd_free_dev_data(struct device *dev,
- struct generic_pm_domain_data *gpd_data)
+static void genpd_free_dev_data(struct device *dev,
+ struct generic_pm_domain_data *gpd_data)
{
- dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+ spin_lock_irq(&dev->power.lock);
+
+ dev->pm_domain = NULL;
+ dev->power.subsys_data->domain_data = NULL;
+
+ spin_unlock_irq(&dev->power.lock);
+
kfree(gpd_data);
+ dev_pm_put_subsys_data(dev);
}
/**
@@ -1414,8 +1448,7 @@ static void __pm_genpd_free_dev_data(struct device *dev,
int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
struct gpd_timing_data *td)
{
- struct generic_pm_domain_data *gpd_data_new, *gpd_data = NULL;
- struct pm_domain_data *pdd;
+ struct generic_pm_domain_data *gpd_data;
int ret = 0;
dev_dbg(dev, "%s()\n", __func__);
@@ -1423,9 +1456,9 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
if (IS_ERR_OR_NULL(genpd) || IS_ERR_OR_NULL(dev))
return -EINVAL;
- gpd_data_new = __pm_genpd_alloc_dev_data(dev);
- if (!gpd_data_new)
- return -ENOMEM;
+ gpd_data = genpd_alloc_dev_data(dev, genpd, td);
+ if (IS_ERR(gpd_data))
+ return PTR_ERR(gpd_data);
genpd_acquire_lock(genpd);
@@ -1434,50 +1467,22 @@ int __pm_genpd_add_device(struct generic_pm_domain *genpd, struct device *dev,
goto out;
}
- list_for_each_entry(pdd, &genpd->dev_list, list_node)
- if (pdd->dev == dev) {
- ret = -EINVAL;
- goto out;
- }
-
- ret = dev_pm_get_subsys_data(dev);
+ ret = genpd->attach_dev ? genpd->attach_dev(genpd, dev) : 0;
if (ret)
goto out;
genpd->device_count++;
genpd->max_off_time_changed = true;
- spin_lock_irq(&dev->power.lock);
-
- dev->pm_domain = &genpd->domain;
- if (dev->power.subsys_data->domain_data) {
- gpd_data = to_gpd_data(dev->power.subsys_data->domain_data);
- } else {
- gpd_data = gpd_data_new;
- dev->power.subsys_data->domain_data = &gpd_data->base;
- }
- gpd_data->refcount++;
- if (td)
- gpd_data->td = *td;
-
- spin_unlock_irq(&dev->power.lock);
-
- if (genpd->attach_dev)
- genpd->attach_dev(genpd, dev);
-
- mutex_lock(&gpd_data->lock);
- gpd_data->base.dev = dev;
list_add_tail(&gpd_data->base.list_node, &genpd->dev_list);
- gpd_data->need_restore = -1;
- gpd_data->td.constraint_changed = true;
- gpd_data->td.effective_constraint_ns = -1;
- mutex_unlock(&gpd_data->lock);
out:
genpd_release_lock(genpd);
- if (gpd_data != gpd_data_new)
- __pm_genpd_free_dev_data(dev, gpd_data_new);
+ if (ret)
+ genpd_free_dev_data(dev, gpd_data);
+ else
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb);
return ret;
}
@@ -1504,7 +1509,6 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
{
struct generic_pm_domain_data *gpd_data;
struct pm_domain_data *pdd;
- bool remove = false;
int ret = 0;
dev_dbg(dev, "%s()\n", __func__);
@@ -1514,6 +1518,11 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
|| pd_to_genpd(dev->pm_domain) != genpd)
return -EINVAL;
+ /* The above validation also means we have existing domain_data. */
+ pdd = dev->power.subsys_data->domain_data;
+ gpd_data = to_gpd_data(pdd);
+ dev_pm_qos_remove_notifier(dev, &gpd_data->nb);
+
genpd_acquire_lock(genpd);
if (genpd->prepared_count > 0) {
@@ -1527,58 +1536,22 @@ int pm_genpd_remove_device(struct generic_pm_domain *genpd,
if (genpd->detach_dev)
genpd->detach_dev(genpd, dev);
- spin_lock_irq(&dev->power.lock);
-
- dev->pm_domain = NULL;
- pdd = dev->power.subsys_data->domain_data;
list_del_init(&pdd->list_node);
- gpd_data = to_gpd_data(pdd);
- if (--gpd_data->refcount == 0) {
- dev->power.subsys_data->domain_data = NULL;
- remove = true;
- }
-
- spin_unlock_irq(&dev->power.lock);
-
- mutex_lock(&gpd_data->lock);
- pdd->dev = NULL;
- mutex_unlock(&gpd_data->lock);
genpd_release_lock(genpd);
- dev_pm_put_subsys_data(dev);
- if (remove)
- __pm_genpd_free_dev_data(dev, gpd_data);
+ genpd_free_dev_data(dev, gpd_data);
return 0;
out:
genpd_release_lock(genpd);
+ dev_pm_qos_add_notifier(dev, &gpd_data->nb);
return ret;
}
/**
- * pm_genpd_dev_need_restore - Set/unset the device's "need restore" flag.
- * @dev: Device to set/unset the flag for.
- * @val: The new value of the device's "need restore" flag.
- */
-void pm_genpd_dev_need_restore(struct device *dev, bool val)
-{
- struct pm_subsys_data *psd;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->power.lock, flags);
-
- psd = dev_to_psd(dev);
- if (psd && psd->domain_data)
- to_gpd_data(psd->domain_data)->need_restore = val ? 1 : 0;
-
- spin_unlock_irqrestore(&dev->power.lock, flags);
-}
-EXPORT_SYMBOL_GPL(pm_genpd_dev_need_restore);
-
-/**
* pm_genpd_add_subdomain - Add a subdomain to an I/O PM domain.
* @genpd: Master PM domain to add the subdomain to.
* @subdomain: Subdomain to be added.
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 106c69359306..677fb2843553 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -117,20 +117,20 @@ do { \
} while (0)
/**
- * find_device_opp() - find device_opp struct using device pointer
+ * _find_device_opp() - find device_opp struct using device pointer
* @dev: device pointer used to lookup device OPPs
*
* Search list of device OPPs for one containing matching device. Does a RCU
* reader operation to grab the pointer needed.
*
- * Returns pointer to 'struct device_opp' if found, otherwise -ENODEV or
+ * Return: pointer to 'struct device_opp' if found, otherwise -ENODEV or
* -EINVAL based on type of error.
*
* Locking: This function must be called under rcu_read_lock(). device_opp
* is a RCU protected pointer. This means that device_opp is valid as long
* as we are under RCU lock.
*/
-static struct device_opp *find_device_opp(struct device *dev)
+static struct device_opp *_find_device_opp(struct device *dev)
{
struct device_opp *tmp_dev_opp, *dev_opp = ERR_PTR(-ENODEV);
@@ -153,7 +153,7 @@ static struct device_opp *find_device_opp(struct device *dev)
* dev_pm_opp_get_voltage() - Gets the voltage corresponding to an available opp
* @opp: opp for which voltage has to be returned for
*
- * Return voltage in micro volt corresponding to the opp, else
+ * Return: voltage in micro volt corresponding to the opp, else
* return 0
*
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
@@ -169,6 +169,8 @@ unsigned long dev_pm_opp_get_voltage(struct dev_pm_opp *opp)
struct dev_pm_opp *tmp_opp;
unsigned long v = 0;
+ opp_rcu_lockdep_assert();
+
tmp_opp = rcu_dereference(opp);
if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
pr_err("%s: Invalid parameters\n", __func__);
@@ -183,7 +185,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_voltage);
* dev_pm_opp_get_freq() - Gets the frequency corresponding to an available opp
* @opp: opp for which frequency has to be returned for
*
- * Return frequency in hertz corresponding to the opp, else
+ * Return: frequency in hertz corresponding to the opp, else
* return 0
*
* Locking: This function must be called under rcu_read_lock(). opp is a rcu
@@ -199,6 +201,8 @@ unsigned long dev_pm_opp_get_freq(struct dev_pm_opp *opp)
struct dev_pm_opp *tmp_opp;
unsigned long f = 0;
+ opp_rcu_lockdep_assert();
+
tmp_opp = rcu_dereference(opp);
if (unlikely(IS_ERR_OR_NULL(tmp_opp)) || !tmp_opp->available)
pr_err("%s: Invalid parameters\n", __func__);
@@ -213,7 +217,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_freq);
* dev_pm_opp_get_opp_count() - Get number of opps available in the opp list
* @dev: device for which we do this operation
*
- * This function returns the number of available opps if there are any,
+ * Return: This function returns the number of available opps if there are any,
* else returns 0 if none or the corresponding error value.
*
* Locking: This function takes rcu_read_lock().
@@ -226,7 +230,7 @@ int dev_pm_opp_get_opp_count(struct device *dev)
rcu_read_lock();
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp)) {
count = PTR_ERR(dev_opp);
dev_err(dev, "%s: device OPP not found (%d)\n",
@@ -251,9 +255,9 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_opp_count);
* @freq: frequency to search for
* @available: true/false - match for available opp
*
- * Searches for exact match in the opp list and returns pointer to the matching
- * opp if found, else returns ERR_PTR in case of error and should be handled
- * using IS_ERR. Error return values can be:
+ * Return: Searches for exact match in the opp list and returns pointer to the
+ * matching opp if found, else returns ERR_PTR in case of error and should
+ * be handled using IS_ERR. Error return values can be:
* EINVAL: for bad pointer
* ERANGE: no match found for search
* ENODEV: if device not found in list of registered devices
@@ -280,7 +284,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_exact(struct device *dev,
opp_rcu_lockdep_assert();
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp)) {
int r = PTR_ERR(dev_opp);
dev_err(dev, "%s: device OPP not found (%d)\n", __func__, r);
@@ -307,7 +311,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_exact);
* Search for the matching ceil *available* OPP from a starting freq
* for a device.
*
- * Returns matching *opp and refreshes *freq accordingly, else returns
+ * Return: matching *opp and refreshes *freq accordingly, else returns
* ERR_PTR in case of error and should be handled using IS_ERR. Error return
* values can be:
* EINVAL: for bad pointer
@@ -333,7 +337,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
return ERR_PTR(-EINVAL);
}
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp))
return ERR_CAST(dev_opp);
@@ -357,7 +361,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_ceil);
* Search for the matching floor *available* OPP from a starting freq
* for a device.
*
- * Returns matching *opp and refreshes *freq accordingly, else returns
+ * Return: matching *opp and refreshes *freq accordingly, else returns
* ERR_PTR in case of error and should be handled using IS_ERR. Error return
* values can be:
* EINVAL: for bad pointer
@@ -383,7 +387,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
return ERR_PTR(-EINVAL);
}
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp))
return ERR_CAST(dev_opp);
@@ -403,7 +407,16 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
-static struct device_opp *add_device_opp(struct device *dev)
+/**
+ * _add_device_opp() - Allocate a new device OPP table
+ * @dev: device for which we do this operation
+ *
+ * New device node which uses OPPs - used when multiple devices with OPP tables
+ * are maintained.
+ *
+ * Return: valid device_opp pointer if success, else NULL.
+ */
+static struct device_opp *_add_device_opp(struct device *dev)
{
struct device_opp *dev_opp;
@@ -424,8 +437,35 @@ static struct device_opp *add_device_opp(struct device *dev)
return dev_opp;
}
-static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
- unsigned long u_volt, bool dynamic)
+/**
+ * _opp_add_dynamic() - Allocate a dynamic OPP.
+ * @dev: device for which we do this operation
+ * @freq: Frequency in Hz for this OPP
+ * @u_volt: Voltage in uVolts for this OPP
+ * @dynamic: Dynamically added OPPs.
+ *
+ * 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 and may be removed by dev_pm_opp_remove.
+ *
+ * NOTE: "dynamic" parameter impacts OPPs added by the of_init_opp_table and
+ * freed by of_free_opp_table.
+ *
+ * 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
+ */
+static int _opp_add_dynamic(struct device *dev, unsigned long freq,
+ long u_volt, bool dynamic)
{
struct device_opp *dev_opp = NULL;
struct dev_pm_opp *opp, *new_opp;
@@ -434,10 +474,8 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
/* allocate new OPP node */
new_opp = kzalloc(sizeof(*new_opp), GFP_KERNEL);
- if (!new_opp) {
- dev_warn(dev, "%s: Unable to create new OPP node\n", __func__);
+ if (!new_opp)
return -ENOMEM;
- }
/* Hold our list modification lock here */
mutex_lock(&dev_opp_list_lock);
@@ -449,9 +487,9 @@ static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
new_opp->dynamic = dynamic;
/* Check for existing list for 'dev' */
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp)) {
- dev_opp = add_device_opp(dev);
+ dev_opp = _add_device_opp(dev);
if (!dev_opp) {
ret = -ENOMEM;
goto free_opp;
@@ -519,34 +557,53 @@ free_opp:
* mutex cannot be locked.
*
* Return:
- * 0: On success OR
+ * 0 On success OR
* Duplicate OPPs (both freq and volt are same) and opp->available
- * -EEXIST: Freq are same and volt are different OR
+ * -EEXIST Freq are same and volt are different OR
* Duplicate OPPs (both freq and volt are same) and !opp->available
- * -ENOMEM: Memory allocation failure
+ * -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);
+ return _opp_add_dynamic(dev, freq, u_volt, true);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
-static void kfree_opp_rcu(struct rcu_head *head)
+/**
+ * _kfree_opp_rcu() - Free OPP RCU handler
+ * @head: RCU head
+ */
+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)
+/**
+ * _kfree_device_rcu() - Free device_opp RCU handler
+ * @head: 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_rcu(device_opp, rcu_head);
}
-static void __dev_pm_opp_remove(struct device_opp *dev_opp,
- struct dev_pm_opp *opp)
+/**
+ * _opp_remove() - Remove an OPP from a table definition
+ * @dev_opp: points back to the device_opp struct this opp belongs to
+ * @opp: pointer to the OPP to remove
+ *
+ * This function removes an opp definition from the opp list.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * It is assumed that the caller holds required mutex for an RCU updater
+ * strategy.
+ */
+static void _opp_remove(struct device_opp *dev_opp,
+ struct dev_pm_opp *opp)
{
/*
* Notify the changes in the availability of the operable
@@ -554,12 +611,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp,
*/
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);
+ 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);
+ _kfree_device_rcu);
}
}
@@ -569,6 +626,12 @@ static void __dev_pm_opp_remove(struct device_opp *dev_opp,
* @freq: OPP to remove with matching 'freq'
*
* This function removes an opp from the opp list.
+ *
+ * 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.
*/
void dev_pm_opp_remove(struct device *dev, unsigned long freq)
{
@@ -579,7 +642,7 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
/* Hold our list modification lock here */
mutex_lock(&dev_opp_list_lock);
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp))
goto unlock;
@@ -596,14 +659,14 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
goto unlock;
}
- __dev_pm_opp_remove(dev_opp, opp);
+ _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
+ * _opp_set_availability() - helper to set the availability of an opp
* @dev: device for which we do this operation
* @freq: OPP frequency to modify availability
* @availability_req: availability status requested for this opp
@@ -611,7 +674,7 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
* Set the availability of an OPP with an RCU operation, opp_{enable,disable}
* share a common logic which is isolated here.
*
- * Returns -EINVAL for bad pointers, -ENOMEM if no memory available for the
+ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
* copy operation, returns 0 if no modifcation was done OR modification was
* successful.
*
@@ -621,8 +684,8 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
* that this function is *NOT* called under RCU protection or in contexts where
* mutex locking or synchronize_rcu() blocking calls cannot be used.
*/
-static int opp_set_availability(struct device *dev, unsigned long freq,
- bool availability_req)
+static int _opp_set_availability(struct device *dev, unsigned long freq,
+ bool availability_req)
{
struct device_opp *dev_opp;
struct dev_pm_opp *new_opp, *tmp_opp, *opp = ERR_PTR(-ENODEV);
@@ -630,15 +693,13 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
/* keep the node allocated */
new_opp = kmalloc(sizeof(*new_opp), GFP_KERNEL);
- if (!new_opp) {
- dev_warn(dev, "%s: Unable to create OPP\n", __func__);
+ if (!new_opp)
return -ENOMEM;
- }
mutex_lock(&dev_opp_list_lock);
/* Find the device_opp */
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp)) {
r = PTR_ERR(dev_opp);
dev_warn(dev, "%s: Device OPP not found (%d)\n", __func__, r);
@@ -668,7 +729,7 @@ 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);
- call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
+ call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, _kfree_opp_rcu);
/* Notify the change of the OPP availability */
if (availability_req)
@@ -700,10 +761,14 @@ unlock:
* integrity of the internal data structures. Callers should ensure that
* this function is *NOT* called under RCU protection or in contexts where
* mutex locking or synchronize_rcu() blocking calls cannot be used.
+ *
+ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
+ * copy operation, returns 0 if no modifcation was done OR modification was
+ * successful.
*/
int dev_pm_opp_enable(struct device *dev, unsigned long freq)
{
- return opp_set_availability(dev, freq, true);
+ return _opp_set_availability(dev, freq, true);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
@@ -722,26 +787,41 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_enable);
* integrity of the internal data structures. Callers should ensure that
* this function is *NOT* called under RCU protection or in contexts where
* mutex locking or synchronize_rcu() blocking calls cannot be used.
+ *
+ * Return: -EINVAL for bad pointers, -ENOMEM if no memory available for the
+ * copy operation, returns 0 if no modifcation was done OR modification was
+ * successful.
*/
int dev_pm_opp_disable(struct device *dev, unsigned long freq)
{
- return opp_set_availability(dev, freq, false);
+ return _opp_set_availability(dev, freq, false);
}
EXPORT_SYMBOL_GPL(dev_pm_opp_disable);
/**
* dev_pm_opp_get_notifier() - find notifier_head of the device with opp
* @dev: device pointer used to lookup device OPPs.
+ *
+ * Return: pointer to notifier head if found, otherwise -ENODEV or
+ * -EINVAL based on type of error casted as pointer. value must be checked
+ * with IS_ERR to determine valid pointer or error result.
+ *
+ * Locking: This function must be called under rcu_read_lock(). dev_opp is a RCU
+ * protected pointer. The reason for the same is that the opp pointer which is
+ * returned will remain valid for use with opp_get_{voltage, freq} only while
+ * under the locked area. The pointer returned must be used prior to unlocking
+ * with rcu_read_unlock() to maintain the integrity of the pointer.
*/
struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
{
- struct device_opp *dev_opp = find_device_opp(dev);
+ struct device_opp *dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp))
return ERR_CAST(dev_opp); /* matching type */
return &dev_opp->srcu_head;
}
+EXPORT_SYMBOL_GPL(dev_pm_opp_get_notifier);
#ifdef CONFIG_OF
/**
@@ -749,6 +829,22 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
* @dev: device pointer used to lookup device OPPs.
*
* Register the initial OPP table with the OPP library for given device.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function indirectly 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
+ * -ENODEV when 'operating-points' property is not found or is invalid data
+ * in device node.
+ * -ENODATA when empty 'operating-points' property is found
*/
int of_init_opp_table(struct device *dev)
{
@@ -777,7 +873,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_dynamic(dev, freq, volt, false))
+ if (_opp_add_dynamic(dev, freq, volt, false))
dev_warn(dev, "%s: Failed to add OPP %ld\n",
__func__, freq);
nr -= 2;
@@ -792,6 +888,12 @@ EXPORT_SYMBOL_GPL(of_init_opp_table);
* @dev: device pointer used to lookup device OPPs.
*
* Free OPPs created using static entries present in DT.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function indirectly 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.
*/
void of_free_opp_table(struct device *dev)
{
@@ -799,7 +901,7 @@ void of_free_opp_table(struct device *dev)
struct dev_pm_opp *opp, *tmp;
/* Check for existing list for 'dev' */
- dev_opp = find_device_opp(dev);
+ dev_opp = _find_device_opp(dev);
if (IS_ERR(dev_opp)) {
int error = PTR_ERR(dev_opp);
if (error != -ENODEV)
@@ -816,7 +918,7 @@ void of_free_opp_table(struct device *dev)
/* 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);
+ _opp_remove(dev_opp, opp);
}
mutex_unlock(&dev_opp_list_lock);
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index a8fe4c1a8d07..e56d538d039e 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -64,6 +64,8 @@ enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev, s32 mask)
struct pm_qos_flags *pqf;
s32 val;
+ lockdep_assert_held(&dev->power.lock);
+
if (IS_ERR_OR_NULL(qos))
return PM_QOS_FLAGS_UNDEFINED;
@@ -104,6 +106,8 @@ EXPORT_SYMBOL_GPL(dev_pm_qos_flags);
*/
s32 __dev_pm_qos_read_value(struct device *dev)
{
+ lockdep_assert_held(&dev->power.lock);
+
return IS_ERR_OR_NULL(dev->power.qos) ?
0 : pm_qos_read_value(&dev->power.qos->resume_latency);
}
diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h
index 0da5865df5b1..beb8b27d4621 100644
--- a/drivers/base/regmap/internal.h
+++ b/drivers/base/regmap/internal.h
@@ -51,9 +51,11 @@ struct regmap_async {
struct regmap {
union {
struct mutex mutex;
- spinlock_t spinlock;
+ struct {
+ spinlock_t spinlock;
+ unsigned long spinlock_flags;
+ };
};
- unsigned long spinlock_flags;
regmap_lock lock;
regmap_unlock unlock;
void *lock_arg; /* This is passed to lock/unlock functions */
@@ -233,6 +235,10 @@ int _regmap_raw_write(struct regmap *map, unsigned int reg,
void regmap_async_complete_cb(struct regmap_async *async, int ret);
+enum regmap_endian regmap_get_val_endian(struct device *dev,
+ const struct regmap_bus *bus,
+ const struct regmap_config *config);
+
extern struct regcache_ops regcache_rbtree_ops;
extern struct regcache_ops regcache_lzo_ops;
extern struct regcache_ops regcache_flat_ops;
diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c
index e4c45d2299c1..8d304e2a943d 100644
--- a/drivers/base/regmap/regmap-ac97.c
+++ b/drivers/base/regmap/regmap-ac97.c
@@ -74,8 +74,8 @@ static int regmap_ac97_reg_write(void *context, unsigned int reg,
}
static const struct regmap_bus ac97_regmap_bus = {
- .reg_write = regmap_ac97_reg_write,
- .reg_read = regmap_ac97_reg_read,
+ .reg_write = regmap_ac97_reg_write,
+ .reg_read = regmap_ac97_reg_read,
};
/**
diff --git a/drivers/base/regmap/regmap-i2c.c b/drivers/base/regmap/regmap-i2c.c
index 053150a7f9f2..4b76e33110a2 100644
--- a/drivers/base/regmap/regmap-i2c.c
+++ b/drivers/base/regmap/regmap-i2c.c
@@ -14,6 +14,7 @@
#include <linux/i2c.h>
#include <linux/module.h>
+#include "internal.h"
static int regmap_smbus_byte_reg_read(void *context, unsigned int reg,
unsigned int *val)
@@ -87,6 +88,42 @@ static struct regmap_bus regmap_smbus_word = {
.reg_read = regmap_smbus_word_reg_read,
};
+static int regmap_smbus_word_read_swapped(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+ int ret;
+
+ if (reg > 0xff)
+ return -EINVAL;
+
+ ret = i2c_smbus_read_word_swapped(i2c, reg);
+ if (ret < 0)
+ return ret;
+
+ *val = ret;
+
+ return 0;
+}
+
+static int regmap_smbus_word_write_swapped(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct device *dev = context;
+ struct i2c_client *i2c = to_i2c_client(dev);
+
+ if (val > 0xffff || reg > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_word_swapped(i2c, reg, val);
+}
+
+static struct regmap_bus regmap_smbus_word_swapped = {
+ .reg_write = regmap_smbus_word_write_swapped,
+ .reg_read = regmap_smbus_word_read_swapped,
+};
+
static int regmap_i2c_write(void *context, const void *data, size_t count)
{
struct device *dev = context;
@@ -180,7 +217,14 @@ static const struct regmap_bus *regmap_get_i2c_bus(struct i2c_client *i2c,
else if (config->val_bits == 16 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_WORD_DATA))
- return &regmap_smbus_word;
+ switch (regmap_get_val_endian(&i2c->dev, NULL, config)) {
+ case REGMAP_ENDIAN_LITTLE:
+ return &regmap_smbus_word;
+ case REGMAP_ENDIAN_BIG:
+ return &regmap_smbus_word_swapped;
+ default: /* everything else is not supported */
+ break;
+ }
else if (config->val_bits == 8 && config->reg_bits == 8 &&
i2c_check_functionality(i2c->adapter,
I2C_FUNC_SMBUS_BYTE_DATA))
diff --git a/drivers/base/regmap/regmap.c b/drivers/base/regmap/regmap.c
index d2f8a818d200..f99b098ddabf 100644
--- a/drivers/base/regmap/regmap.c
+++ b/drivers/base/regmap/regmap.c
@@ -473,9 +473,9 @@ static enum regmap_endian regmap_get_reg_endian(const struct regmap_bus *bus,
return REGMAP_ENDIAN_BIG;
}
-static enum regmap_endian regmap_get_val_endian(struct device *dev,
- const struct regmap_bus *bus,
- const struct regmap_config *config)
+enum regmap_endian regmap_get_val_endian(struct device *dev,
+ const struct regmap_bus *bus,
+ const struct regmap_config *config)
{
struct device_node *np;
enum regmap_endian endian;
@@ -513,6 +513,7 @@ static enum regmap_endian regmap_get_val_endian(struct device *dev,
/* Use this if no other value was found */
return REGMAP_ENDIAN_BIG;
}
+EXPORT_SYMBOL_GPL(regmap_get_val_endian);
/**
* regmap_init(): Initialise register map
diff --git a/drivers/bcma/bcma_private.h b/drivers/bcma/bcma_private.h
index 314ae4032f3e..ac6c5fca906d 100644
--- a/drivers/bcma/bcma_private.h
+++ b/drivers/bcma/bcma_private.h
@@ -25,22 +25,18 @@ struct bcma_bus;
bool bcma_wait_value(struct bcma_device *core, u16 reg, u32 mask, u32 value,
int timeout);
void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core);
+void bcma_init_bus(struct bcma_bus *bus);
int bcma_bus_register(struct bcma_bus *bus);
void bcma_bus_unregister(struct bcma_bus *bus);
-int __init bcma_bus_early_register(struct bcma_bus *bus,
- struct bcma_device *core_cc,
- struct bcma_device *core_mips);
+int __init bcma_bus_early_register(struct bcma_bus *bus);
#ifdef CONFIG_PM
int bcma_bus_suspend(struct bcma_bus *bus);
int bcma_bus_resume(struct bcma_bus *bus);
#endif
/* scan.c */
+void bcma_detect_chip(struct bcma_bus *bus);
int bcma_bus_scan(struct bcma_bus *bus);
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
- struct bcma_device_id *match,
- struct bcma_device *core);
-void bcma_init_bus(struct bcma_bus *bus);
/* sprom.c */
int bcma_sprom_get(struct bcma_bus *bus);
@@ -111,6 +107,14 @@ extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc);
void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc);
+#else
+static inline bool bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
+{
+ return false;
+}
+static inline void bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
+{
+}
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
#ifdef CONFIG_BCMA_DRIVER_GPIO
diff --git a/drivers/bcma/driver_chipcommon.c b/drivers/bcma/driver_chipcommon.c
index 19f679667ca4..b7c8a8d4e6d1 100644
--- a/drivers/bcma/driver_chipcommon.c
+++ b/drivers/bcma/driver_chipcommon.c
@@ -79,7 +79,9 @@ static int bcma_chipco_watchdog_ticks_per_ms(struct bcma_drv_cc *cc)
if (cc->capabilities & BCMA_CC_CAP_PMU) {
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706)
- /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP clock */
+ /* 4706 CC and PMU watchdogs are clocked at 1/4 of ALP
+ * clock
+ */
return bcma_chipco_get_alp_clock(cc) / 4000;
else
/* based on 32KHz ILP clock */
@@ -97,7 +99,8 @@ int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc)
wdt.driver_data = cc;
wdt.timer_set = bcma_chipco_watchdog_timer_set_wdt;
wdt.timer_set_ms = bcma_chipco_watchdog_timer_set_ms_wdt;
- wdt.max_timer_ms = bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
+ wdt.max_timer_ms =
+ bcma_chipco_watchdog_get_max_timer(cc) / cc->ticks_per_ms;
pdev = platform_device_register_data(NULL, "bcm47xx-wdt",
cc->core->bus->num, &wdt,
@@ -175,7 +178,6 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
{
u32 maxt;
- enum bcma_clkmode clkmode;
maxt = bcma_chipco_watchdog_get_max_timer(cc);
if (cc->capabilities & BCMA_CC_CAP_PMU) {
@@ -185,8 +187,13 @@ u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks)
ticks = maxt;
bcma_cc_write32(cc, BCMA_CC_PMU_WATCHDOG, ticks);
} else {
- clkmode = ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC;
- bcma_core_set_clockmode(cc->core, clkmode);
+ struct bcma_bus *bus = cc->core->bus;
+
+ if (bus->chipinfo.id != BCMA_CHIP_ID_BCM4707 &&
+ bus->chipinfo.id != BCMA_CHIP_ID_BCM53018)
+ bcma_core_set_clockmode(cc->core,
+ ticks ? BCMA_CLKMODE_FAST : BCMA_CLKMODE_DYNAMIC);
+
if (ticks > maxt)
ticks = maxt;
/* instant NMI */
@@ -335,7 +342,8 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
| BCMA_CC_CORECTL_UARTCLKEN);
}
} else {
- bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
+ bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n",
+ ccrev);
return;
}
diff --git a/drivers/bcma/driver_pci.c b/drivers/bcma/driver_pci.c
index 50329d1057ed..786666488a2d 100644
--- a/drivers/bcma/driver_pci.c
+++ b/drivers/bcma/driver_pci.c
@@ -145,6 +145,47 @@ static u16 bcma_pcie_mdio_writeread(struct bcma_drv_pci *pc, u16 device,
}
/**************************************************
+ * Early init.
+ **************************************************/
+
+static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
+{
+ struct bcma_device *core = pc->core;
+ u16 val16, core_index;
+ uint regoff;
+
+ regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
+ core_index = (u16)core->core_index;
+
+ val16 = pcicore_read16(pc, regoff);
+ if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
+ != core_index) {
+ val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
+ (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
+ pcicore_write16(pc, regoff, val16);
+ }
+}
+
+/*
+ * Apply some early fixes required before accessing SPROM.
+ * See also si_pci_fixcfg.
+ */
+void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
+{
+ if (pc->early_setup_done)
+ return;
+
+ pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+ if (pc->hostmode)
+ goto out;
+
+ bcma_core_pci_fixcfg(pc);
+
+out:
+ pc->early_setup_done = true;
+}
+
+/**************************************************
* Workarounds.
**************************************************/
@@ -175,24 +216,6 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
}
-static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
-{
- struct bcma_device *core = pc->core;
- u16 val16, core_index;
- uint regoff;
-
- regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
- core_index = (u16)core->core_index;
-
- val16 = pcicore_read16(pc, regoff);
- if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
- != core_index) {
- val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
- (val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
- pcicore_write16(pc, regoff, val16);
- }
-}
-
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
@@ -216,7 +239,6 @@ static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
static void bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{
- bcma_core_pci_fixcfg(pc);
bcma_pcicore_serdes_workaround(pc);
bcma_core_pci_config_fixup(pc);
}
@@ -226,13 +248,11 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
if (pc->setup_done)
return;
-#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
- pc->hostmode = bcma_core_pci_is_in_hostmode(pc);
+ bcma_core_pci_early_init(pc);
+
if (pc->hostmode)
bcma_core_pci_hostmode_init(pc);
-#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
-
- if (!pc->hostmode)
+ else
bcma_core_pci_clientmode_init(pc);
}
diff --git a/drivers/bcma/host_pci.c b/drivers/bcma/host_pci.c
index cd9161a8b3a1..53c6a8a58859 100644
--- a/drivers/bcma/host_pci.c
+++ b/drivers/bcma/host_pci.c
@@ -13,10 +13,12 @@
static void bcma_host_pci_switch_core(struct bcma_device *core)
{
+ int win2 = core->bus->host_is_pcie2 ?
+ BCMA_PCIE2_BAR0_WIN2 : BCMA_PCI_BAR0_WIN2;
+
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN,
core->addr);
- pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
- core->wrap);
+ pci_write_config_dword(core->bus->host_pci, win2, core->wrap);
core->bus->mapped_core = core;
bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
}
diff --git a/drivers/bcma/host_soc.c b/drivers/bcma/host_soc.c
index 335cbcfd945b..2dce34789329 100644
--- a/drivers/bcma/host_soc.c
+++ b/drivers/bcma/host_soc.c
@@ -193,7 +193,7 @@ int __init bcma_host_soc_init(struct bcma_soc *soc)
int err;
/* Scan bus and initialize it */
- err = bcma_bus_early_register(bus, &soc->core_cc, &soc->core_mips);
+ err = bcma_bus_early_register(bus);
if (err)
iounmap(bus->mmio);
diff --git a/drivers/bcma/main.c b/drivers/bcma/main.c
index 534e1337766d..38bde6eab8a4 100644
--- a/drivers/bcma/main.c
+++ b/drivers/bcma/main.c
@@ -268,6 +268,18 @@ void bcma_prepare_core(struct bcma_bus *bus, struct bcma_device *core)
}
}
+void bcma_init_bus(struct bcma_bus *bus)
+{
+ mutex_lock(&bcma_buses_mutex);
+ bus->num = bcma_bus_next_num++;
+ mutex_unlock(&bcma_buses_mutex);
+
+ INIT_LIST_HEAD(&bus->cores);
+ bus->nr_cores = 0;
+
+ bcma_detect_chip(bus);
+}
+
static void bcma_register_core(struct bcma_bus *bus, struct bcma_device *core)
{
int err;
@@ -356,12 +368,19 @@ static void bcma_unregister_cores(struct bcma_bus *bus)
struct bcma_device *core, *tmp;
list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ if (!core->dev_registered)
+ continue;
list_del(&core->list);
- if (core->dev_registered)
- device_unregister(&core->dev);
+ device_unregister(&core->dev);
}
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
platform_device_unregister(bus->drv_cc.watchdog);
+
+ /* Now noone uses internally-handled cores, we can free them */
+ list_for_each_entry_safe(core, tmp, &bus->cores, list) {
+ list_del(&core->list);
+ kfree(core);
+ }
}
int bcma_bus_register(struct bcma_bus *bus)
@@ -369,10 +388,6 @@ int bcma_bus_register(struct bcma_bus *bus)
int err;
struct bcma_device *core;
- mutex_lock(&bcma_buses_mutex);
- bus->num = bcma_bus_next_num++;
- mutex_unlock(&bcma_buses_mutex);
-
/* Scan for devices (cores) */
err = bcma_bus_scan(bus);
if (err) {
@@ -387,6 +402,13 @@ int bcma_bus_register(struct bcma_bus *bus)
bcma_core_chipcommon_early_init(&bus->drv_cc);
}
+ /* Early init PCIE core */
+ core = bcma_find_core(bus, BCMA_CORE_PCIE);
+ if (core) {
+ bus->drv_pci[0].core = core;
+ bcma_core_pci_early_init(&bus->drv_pci[0]);
+ }
+
/* Cores providing flash access go before SPROM init */
list_for_each_entry(core, &bus->cores, list) {
if (bcma_is_core_needed_early(core->id.id))
@@ -459,7 +481,6 @@ int bcma_bus_register(struct bcma_bus *bus)
void bcma_bus_unregister(struct bcma_bus *bus)
{
- struct bcma_device *cores[3];
int err;
err = bcma_gpio_unregister(&bus->drv_cc);
@@ -470,46 +491,23 @@ void bcma_bus_unregister(struct bcma_bus *bus)
bcma_core_chipcommon_b_free(&bus->drv_cc_b);
- cores[0] = bcma_find_core(bus, BCMA_CORE_MIPS_74K);
- cores[1] = bcma_find_core(bus, BCMA_CORE_PCIE);
- cores[2] = bcma_find_core(bus, BCMA_CORE_4706_MAC_GBIT_COMMON);
-
bcma_unregister_cores(bus);
-
- kfree(cores[2]);
- kfree(cores[1]);
- kfree(cores[0]);
}
-int __init bcma_bus_early_register(struct bcma_bus *bus,
- struct bcma_device *core_cc,
- struct bcma_device *core_mips)
+/*
+ * This is a special version of bus registration function designed for SoCs.
+ * It scans bus and performs basic initialization of main cores only.
+ * Please note it requires memory allocation, however it won't try to sleep.
+ */
+int __init bcma_bus_early_register(struct bcma_bus *bus)
{
int err;
struct bcma_device *core;
- struct bcma_device_id match;
- match.manuf = BCMA_MANUF_BCM;
- match.id = bcma_cc_core_id(bus);
- match.class = BCMA_CL_SIM;
- match.rev = BCMA_ANY_REV;
-
- /* Scan for chip common core */
- err = bcma_bus_scan_early(bus, &match, core_cc);
- if (err) {
- bcma_err(bus, "Failed to scan for common core: %d\n", err);
- return -1;
- }
-
- match.manuf = BCMA_MANUF_MIPS;
- match.id = BCMA_CORE_MIPS_74K;
- match.class = BCMA_CL_SIM;
- match.rev = BCMA_ANY_REV;
-
- /* Scan for mips core */
- err = bcma_bus_scan_early(bus, &match, core_mips);
+ /* Scan for devices (cores) */
+ err = bcma_bus_scan(bus);
if (err) {
- bcma_err(bus, "Failed to scan for mips core: %d\n", err);
+ bcma_err(bus, "Failed to scan bus: %d\n", err);
return -1;
}
diff --git a/drivers/bcma/scan.c b/drivers/bcma/scan.c
index 917520776879..df806b9c5490 100644
--- a/drivers/bcma/scan.c
+++ b/drivers/bcma/scan.c
@@ -435,15 +435,12 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
return 0;
}
-void bcma_init_bus(struct bcma_bus *bus)
+void bcma_detect_chip(struct bcma_bus *bus)
{
s32 tmp;
struct bcma_chipinfo *chipinfo = &(bus->chipinfo);
char chip_id[8];
- INIT_LIST_HEAD(&bus->cores);
- bus->nr_cores = 0;
-
bcma_scan_switch_core(bus, BCMA_ADDR_BASE);
tmp = bcma_scan_read32(bus, 0, BCMA_CC_ID);
@@ -464,6 +461,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
int err, core_num = 0;
+ /* Skip if bus was already scanned (e.g. during early register) */
+ if (bus->nr_cores)
+ return 0;
+
erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
@@ -522,61 +523,3 @@ out:
return err;
}
-
-int __init bcma_bus_scan_early(struct bcma_bus *bus,
- struct bcma_device_id *match,
- struct bcma_device *core)
-{
- u32 erombase;
- u32 __iomem *eromptr, *eromend;
-
- int err = -ENODEV;
- int core_num = 0;
-
- erombase = bcma_scan_read32(bus, 0, BCMA_CC_EROM);
- if (bus->hosttype == BCMA_HOSTTYPE_SOC) {
- eromptr = ioremap_nocache(erombase, BCMA_CORE_SIZE);
- if (!eromptr)
- return -ENOMEM;
- } else {
- eromptr = bus->mmio;
- }
-
- eromend = eromptr + BCMA_CORE_SIZE / sizeof(u32);
-
- bcma_scan_switch_core(bus, erombase);
-
- while (eromptr < eromend) {
- memset(core, 0, sizeof(*core));
- INIT_LIST_HEAD(&core->list);
- core->bus = bus;
-
- err = bcma_get_next_core(bus, &eromptr, match, core_num, core);
- if (err == -ENODEV) {
- core_num++;
- continue;
- } else if (err == -ENXIO)
- continue;
- else if (err == -ESPIPE)
- break;
- else if (err < 0)
- goto out;
-
- core->core_index = core_num++;
- bus->nr_cores++;
- bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
- core->core_index, bcma_device_name(&core->id),
- core->id.manuf, core->id.id, core->id.rev,
- core->id.class);
-
- list_add_tail(&core->list, &bus->cores);
- err = 0;
- break;
- }
-
-out:
- if (bus->hosttype == BCMA_HOSTTYPE_SOC)
- iounmap(eromptr);
-
- return err;
-}
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
index efb037f9c98a..206edd3ba668 100644
--- a/drivers/bcma/sprom.c
+++ b/drivers/bcma/sprom.c
@@ -579,7 +579,8 @@ int bcma_sprom_get(struct bcma_bus *bus)
u16 offset = BCMA_CC_SPROM;
u16 *sprom;
size_t sprom_sizes[] = { SSB_SPROMSIZE_WORDS_R4,
- SSB_SPROMSIZE_WORDS_R10, };
+ SSB_SPROMSIZE_WORDS_R10,
+ SSB_SPROMSIZE_WORDS_R11, };
int i, err = 0;
if (!bus->drv_cc.core)
diff --git a/drivers/block/Kconfig b/drivers/block/Kconfig
index 014a1cfc41c5..1b8094d4d7af 100644
--- a/drivers/block/Kconfig
+++ b/drivers/block/Kconfig
@@ -393,14 +393,15 @@ config BLK_DEV_RAM_SIZE
The default value is 4096 kilobytes. Only change this if you know
what you are doing.
-config BLK_DEV_XIP
- bool "Support XIP filesystems on RAM block device"
- depends on BLK_DEV_RAM
+config BLK_DEV_RAM_DAX
+ bool "Support Direct Access (DAX) to RAM block devices"
+ depends on BLK_DEV_RAM && FS_DAX
default n
help
- Support XIP filesystems (such as ext2 with XIP support on) on
- top of block ram device. This will slightly enlarge the kernel, and
- will prevent RAM block device backing store memory from being
+ Support filesystems using DAX to access RAM block devices. This
+ avoids double-buffering data in the page cache before copying it
+ to the block device. Answering Y will slightly enlarge the kernel,
+ and will prevent RAM block device backing store memory from being
allocated from highmem (only a problem for highmem systems).
config CDROM_PKTCDVD
diff --git a/drivers/block/brd.c b/drivers/block/brd.c
index 3598110d2cef..64ab4951e9d6 100644
--- a/drivers/block/brd.c
+++ b/drivers/block/brd.c
@@ -97,13 +97,13 @@ static struct page *brd_insert_page(struct brd_device *brd, sector_t sector)
* Must use NOIO because we don't want to recurse back into the
* block or filesystem layers from page reclaim.
*
- * Cannot support XIP and highmem, because our ->direct_access
- * routine for XIP must return memory that is always addressable.
- * If XIP was reworked to use pfns and kmap throughout, this
+ * Cannot support DAX and highmem, because our ->direct_access
+ * routine for DAX must return memory that is always addressable.
+ * If DAX was reworked to use pfns and kmap throughout, this
* restriction might be able to be lifted.
*/
gfp_flags = GFP_NOIO | __GFP_ZERO;
-#ifndef CONFIG_BLK_DEV_XIP
+#ifndef CONFIG_BLK_DEV_RAM_DAX
gfp_flags |= __GFP_HIGHMEM;
#endif
page = alloc_page(gfp_flags);
@@ -369,27 +369,29 @@ static int brd_rw_page(struct block_device *bdev, sector_t sector,
return err;
}
-#ifdef CONFIG_BLK_DEV_XIP
-static int brd_direct_access(struct block_device *bdev, sector_t sector,
- void **kaddr, unsigned long *pfn)
+#ifdef CONFIG_BLK_DEV_RAM_DAX
+static long brd_direct_access(struct block_device *bdev, sector_t sector,
+ void **kaddr, unsigned long *pfn, long size)
{
struct brd_device *brd = bdev->bd_disk->private_data;
struct page *page;
if (!brd)
return -ENODEV;
- if (sector & (PAGE_SECTORS-1))
- return -EINVAL;
- if (sector + PAGE_SECTORS > get_capacity(bdev->bd_disk))
- return -ERANGE;
page = brd_insert_page(brd, sector);
if (!page)
return -ENOSPC;
*kaddr = page_address(page);
*pfn = page_to_pfn(page);
- return 0;
+ /*
+ * TODO: If size > PAGE_SIZE, we could look to see if the next page in
+ * the file happens to be mapped to the next page of physical RAM.
+ */
+ return PAGE_SIZE;
}
+#else
+#define brd_direct_access NULL
#endif
static int brd_ioctl(struct block_device *bdev, fmode_t mode,
@@ -430,27 +432,24 @@ static const struct block_device_operations brd_fops = {
.owner = THIS_MODULE,
.rw_page = brd_rw_page,
.ioctl = brd_ioctl,
-#ifdef CONFIG_BLK_DEV_XIP
.direct_access = brd_direct_access,
-#endif
};
/*
* And now the modules code and kernel interface.
*/
-static int rd_nr;
-int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
-static int max_part;
-static int part_shift;
-static int part_show = 0;
+static int rd_nr = CONFIG_BLK_DEV_RAM_COUNT;
module_param(rd_nr, int, S_IRUGO);
MODULE_PARM_DESC(rd_nr, "Maximum number of brd devices");
+
+int rd_size = CONFIG_BLK_DEV_RAM_SIZE;
module_param(rd_size, int, S_IRUGO);
MODULE_PARM_DESC(rd_size, "Size of each RAM disk in kbytes.");
+
+static int max_part = 1;
module_param(max_part, int, S_IRUGO);
-MODULE_PARM_DESC(max_part, "Maximum number of partitions per RAM disk");
-module_param(part_show, int, S_IRUGO);
-MODULE_PARM_DESC(part_show, "Control RAM disk visibility in /proc/partitions");
+MODULE_PARM_DESC(max_part, "Num Minors to reserve between devices");
+
MODULE_LICENSE("GPL");
MODULE_ALIAS_BLOCKDEV_MAJOR(RAMDISK_MAJOR);
MODULE_ALIAS("rd");
@@ -487,25 +486,33 @@ static struct brd_device *brd_alloc(int i)
brd->brd_queue = blk_alloc_queue(GFP_KERNEL);
if (!brd->brd_queue)
goto out_free_dev;
+
blk_queue_make_request(brd->brd_queue, brd_make_request);
blk_queue_max_hw_sectors(brd->brd_queue, 1024);
blk_queue_bounce_limit(brd->brd_queue, BLK_BOUNCE_ANY);
+ /* This is so fdisk will align partitions on 4k, because of
+ * direct_access API needing 4k alignment, returning a PFN
+ * (This is only a problem on very small devices <= 4M,
+ * otherwise fdisk will align on 1M. Regardless this call
+ * is harmless)
+ */
+ blk_queue_physical_block_size(brd->brd_queue, PAGE_SIZE);
+
brd->brd_queue->limits.discard_granularity = PAGE_SIZE;
brd->brd_queue->limits.max_discard_sectors = UINT_MAX;
brd->brd_queue->limits.discard_zeroes_data = 1;
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, brd->brd_queue);
- disk = brd->brd_disk = alloc_disk(1 << part_shift);
+ disk = brd->brd_disk = alloc_disk(max_part);
if (!disk)
goto out_free_queue;
disk->major = RAMDISK_MAJOR;
- disk->first_minor = i << part_shift;
+ disk->first_minor = i * max_part;
disk->fops = &brd_fops;
disk->private_data = brd;
disk->queue = brd->brd_queue;
- if (!part_show)
- disk->flags |= GENHD_FL_SUPPRESS_PARTITION_INFO;
+ disk->flags = GENHD_FL_EXT_DEVT;
sprintf(disk->disk_name, "ram%d", i);
set_capacity(disk, rd_size * 2);
@@ -527,10 +534,11 @@ static void brd_free(struct brd_device *brd)
kfree(brd);
}
-static struct brd_device *brd_init_one(int i)
+static struct brd_device *brd_init_one(int i, bool *new)
{
struct brd_device *brd;
+ *new = false;
list_for_each_entry(brd, &brd_devices, brd_list) {
if (brd->brd_number == i)
goto out;
@@ -541,6 +549,7 @@ static struct brd_device *brd_init_one(int i)
add_disk(brd->brd_disk);
list_add_tail(&brd->brd_list, &brd_devices);
}
+ *new = true;
out:
return brd;
}
@@ -556,70 +565,46 @@ static struct kobject *brd_probe(dev_t dev, int *part, void *data)
{
struct brd_device *brd;
struct kobject *kobj;
+ bool new;
mutex_lock(&brd_devices_mutex);
- brd = brd_init_one(MINOR(dev) >> part_shift);
+ brd = brd_init_one(MINOR(dev) / max_part, &new);
kobj = brd ? get_disk(brd->brd_disk) : NULL;
mutex_unlock(&brd_devices_mutex);
- *part = 0;
+ if (new)
+ *part = 0;
+
return kobj;
}
static int __init brd_init(void)
{
- int i, nr;
- unsigned long range;
struct brd_device *brd, *next;
+ int i;
/*
* brd module now has a feature to instantiate underlying device
* structure on-demand, provided that there is an access dev node.
- * However, this will not work well with user space tool that doesn't
- * know about such "feature". In order to not break any existing
- * tool, we do the following:
*
- * (1) if rd_nr is specified, create that many upfront, and this
- * also becomes a hard limit.
- * (2) if rd_nr is not specified, create CONFIG_BLK_DEV_RAM_COUNT
- * (default 16) rd device on module load, user can further
- * extend brd device by create dev node themselves and have
- * kernel automatically instantiate actual device on-demand.
+ * (1) if rd_nr is specified, create that many upfront. else
+ * it defaults to CONFIG_BLK_DEV_RAM_COUNT
+ * (2) User can further extend brd devices by create dev node themselves
+ * and have kernel automatically instantiate actual device
+ * on-demand. Example:
+ * mknod /path/devnod_name b 1 X # 1 is the rd major
+ * fdisk -l /path/devnod_name
+ * If (X / max_part) was not already created it will be created
+ * dynamically.
*/
- part_shift = 0;
- if (max_part > 0) {
- part_shift = fls(max_part);
-
- /*
- * Adjust max_part according to part_shift as it is exported
- * to user space so that user can decide correct minor number
- * if [s]he want to create more devices.
- *
- * Note that -1 is required because partition 0 is reserved
- * for the whole disk.
- */
- max_part = (1UL << part_shift) - 1;
- }
-
- if ((1UL << part_shift) > DISK_MAX_PARTS)
- return -EINVAL;
-
- if (rd_nr > 1UL << (MINORBITS - part_shift))
- return -EINVAL;
-
- if (rd_nr) {
- nr = rd_nr;
- range = rd_nr << part_shift;
- } else {
- nr = CONFIG_BLK_DEV_RAM_COUNT;
- range = 1UL << MINORBITS;
- }
-
if (register_blkdev(RAMDISK_MAJOR, "ramdisk"))
return -EIO;
- for (i = 0; i < nr; i++) {
+ if (unlikely(!max_part))
+ max_part = 1;
+
+ for (i = 0; i < rd_nr; i++) {
brd = brd_alloc(i);
if (!brd)
goto out_free;
@@ -631,10 +616,10 @@ static int __init brd_init(void)
list_for_each_entry(brd, &brd_devices, brd_list)
add_disk(brd->brd_disk);
- blk_register_region(MKDEV(RAMDISK_MAJOR, 0), range,
+ blk_register_region(MKDEV(RAMDISK_MAJOR, 0), 1UL << MINORBITS,
THIS_MODULE, brd_probe, NULL, NULL);
- printk(KERN_INFO "brd: module loaded\n");
+ pr_info("brd: module loaded\n");
return 0;
out_free:
@@ -644,21 +629,21 @@ out_free:
}
unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
+ pr_info("brd: module NOT loaded !!!\n");
return -ENOMEM;
}
static void __exit brd_exit(void)
{
- unsigned long range;
struct brd_device *brd, *next;
- range = rd_nr ? rd_nr << part_shift : 1UL << MINORBITS;
-
list_for_each_entry_safe(brd, next, &brd_devices, brd_list)
brd_del_one(brd);
- blk_unregister_region(MKDEV(RAMDISK_MAJOR, 0), range);
+ blk_unregister_region(MKDEV(RAMDISK_MAJOR, 0), 1UL << MINORBITS);
unregister_blkdev(RAMDISK_MAJOR, "ramdisk");
+
+ pr_info("brd: module unloaded\n");
}
module_init(brd_init);
diff --git a/drivers/block/drbd/drbd_receiver.c b/drivers/block/drbd/drbd_receiver.c
index d169b4a79267..cee20354ac37 100644
--- a/drivers/block/drbd/drbd_receiver.c
+++ b/drivers/block/drbd/drbd_receiver.c
@@ -1388,7 +1388,7 @@ int drbd_submit_peer_request(struct drbd_device *device,
list_add_tail(&peer_req->w.list, &device->active_ee);
spin_unlock_irq(&device->resource->req_lock);
if (blkdev_issue_zeroout(device->ldev->backing_bdev,
- sector, data_size >> 9, GFP_NOIO))
+ sector, data_size >> 9, GFP_NOIO, false))
peer_req->flags |= EE_WAS_ERROR;
drbd_endio_write_sec_final(peer_req);
return 0;
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 56d46ffb08e1..a08cda955285 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -4112,6 +4112,13 @@ static ssize_t floppy_cmos_show(struct device *dev,
static DEVICE_ATTR(cmos, S_IRUGO, floppy_cmos_show, NULL);
+static struct attribute *floppy_dev_attrs[] = {
+ &dev_attr_cmos.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(floppy_dev);
+
static void floppy_device_release(struct device *dev)
{
}
@@ -4324,16 +4331,12 @@ static int __init do_floppy_init(void)
floppy_device[drive].name = floppy_device_name;
floppy_device[drive].id = drive;
floppy_device[drive].dev.release = floppy_device_release;
+ floppy_device[drive].dev.groups = floppy_dev_groups;
err = platform_device_register(&floppy_device[drive]);
if (err)
goto out_remove_drives;
- err = device_create_file(&floppy_device[drive].dev,
- &dev_attr_cmos);
- if (err)
- goto out_unreg_platform_dev;
-
/* to be cleaned up... */
disks[drive]->private_data = (void *)(long)drive;
disks[drive]->flags |= GENHD_FL_REMOVABLE;
@@ -4343,13 +4346,10 @@ static int __init do_floppy_init(void)
return 0;
-out_unreg_platform_dev:
- platform_device_unregister(&floppy_device[drive]);
out_remove_drives:
while (drive--) {
if (floppy_available(drive)) {
del_gendisk(disks[drive]);
- device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
platform_device_unregister(&floppy_device[drive]);
}
}
@@ -4594,7 +4594,6 @@ static void __exit floppy_module_exit(void)
if (floppy_available(drive)) {
del_gendisk(disks[drive]);
- device_remove_file(&floppy_device[drive].dev, &dev_attr_cmos);
platform_device_unregister(&floppy_device[drive]);
}
blk_cleanup_queue(disks[drive]->queue);
diff --git a/drivers/block/loop.c b/drivers/block/loop.c
index 6cb1beb47c25..d1f168b73634 100644
--- a/drivers/block/loop.c
+++ b/drivers/block/loop.c
@@ -85,6 +85,8 @@ static DEFINE_MUTEX(loop_index_mutex);
static int max_part;
static int part_shift;
+static struct workqueue_struct *loop_wq;
+
/*
* Transfer functions
*/
@@ -284,12 +286,12 @@ static int do_lo_send_write(struct loop_device *lo, struct bio_vec *bvec,
return ret;
}
-static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
+static int lo_send(struct loop_device *lo, struct request *rq, loff_t pos)
{
int (*do_lo_send)(struct loop_device *, struct bio_vec *, loff_t,
struct page *page);
struct bio_vec bvec;
- struct bvec_iter iter;
+ struct req_iterator iter;
struct page *page = NULL;
int ret = 0;
@@ -303,7 +305,7 @@ static int lo_send(struct loop_device *lo, struct bio *bio, loff_t pos)
do_lo_send = do_lo_send_direct_write;
}
- bio_for_each_segment(bvec, bio, iter) {
+ rq_for_each_segment(bvec, rq, iter) {
ret = do_lo_send(lo, &bvec, pos, page);
if (ret < 0)
break;
@@ -391,19 +393,22 @@ do_lo_receive(struct loop_device *lo,
}
static int
-lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
+lo_receive(struct loop_device *lo, struct request *rq, int bsize, loff_t pos)
{
struct bio_vec bvec;
- struct bvec_iter iter;
+ struct req_iterator iter;
ssize_t s;
- bio_for_each_segment(bvec, bio, iter) {
+ rq_for_each_segment(bvec, rq, iter) {
s = do_lo_receive(lo, &bvec, bsize, pos);
if (s < 0)
return s;
if (s != bvec.bv_len) {
- zero_fill_bio(bio);
+ struct bio *bio;
+
+ __rq_for_each_bio(bio, rq)
+ zero_fill_bio(bio);
break;
}
pos += bvec.bv_len;
@@ -411,106 +416,58 @@ lo_receive(struct loop_device *lo, struct bio *bio, int bsize, loff_t pos)
return 0;
}
-static int do_bio_filebacked(struct loop_device *lo, struct bio *bio)
+static int lo_discard(struct loop_device *lo, struct request *rq, loff_t pos)
{
- loff_t pos;
+ /*
+ * We use punch hole to reclaim the free space used by the
+ * image a.k.a. discard. However we do not support discard if
+ * encryption is enabled, because it may give an attacker
+ * useful information.
+ */
+ struct file *file = lo->lo_backing_file;
+ int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
int ret;
- pos = ((loff_t) bio->bi_iter.bi_sector << 9) + lo->lo_offset;
-
- if (bio_rw(bio) == WRITE) {
- struct file *file = lo->lo_backing_file;
-
- if (bio->bi_rw & REQ_FLUSH) {
- ret = vfs_fsync(file, 0);
- if (unlikely(ret && ret != -EINVAL)) {
- ret = -EIO;
- goto out;
- }
- }
-
- /*
- * We use punch hole to reclaim the free space used by the
- * image a.k.a. discard. However we do not support discard if
- * encryption is enabled, because it may give an attacker
- * useful information.
- */
- if (bio->bi_rw & REQ_DISCARD) {
- struct file *file = lo->lo_backing_file;
- int mode = FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE;
-
- if ((!file->f_op->fallocate) ||
- lo->lo_encrypt_key_size) {
- ret = -EOPNOTSUPP;
- goto out;
- }
- ret = file->f_op->fallocate(file, mode, pos,
- bio->bi_iter.bi_size);
- if (unlikely(ret && ret != -EINVAL &&
- ret != -EOPNOTSUPP))
- ret = -EIO;
- goto out;
- }
-
- ret = lo_send(lo, bio, pos);
-
- if ((bio->bi_rw & REQ_FUA) && !ret) {
- ret = vfs_fsync(file, 0);
- if (unlikely(ret && ret != -EINVAL))
- ret = -EIO;
- }
- } else
- ret = lo_receive(lo, bio, lo->lo_blocksize, pos);
+ if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
+ ret = -EOPNOTSUPP;
+ goto out;
+ }
-out:
+ ret = file->f_op->fallocate(file, mode, pos, blk_rq_bytes(rq));
+ if (unlikely(ret && ret != -EINVAL && ret != -EOPNOTSUPP))
+ ret = -EIO;
+ out:
return ret;
}
-/*
- * Add bio to back of pending list
- */
-static void loop_add_bio(struct loop_device *lo, struct bio *bio)
+static int lo_req_flush(struct loop_device *lo, struct request *rq)
{
- lo->lo_bio_count++;
- bio_list_add(&lo->lo_bio_list, bio);
-}
+ struct file *file = lo->lo_backing_file;
+ int ret = vfs_fsync(file, 0);
+ if (unlikely(ret && ret != -EINVAL))
+ ret = -EIO;
-/*
- * Grab first pending buffer
- */
-static struct bio *loop_get_bio(struct loop_device *lo)
-{
- lo->lo_bio_count--;
- return bio_list_pop(&lo->lo_bio_list);
+ return ret;
}
-static void loop_make_request(struct request_queue *q, struct bio *old_bio)
+static int do_req_filebacked(struct loop_device *lo, struct request *rq)
{
- struct loop_device *lo = q->queuedata;
- int rw = bio_rw(old_bio);
-
- if (rw == READA)
- rw = READ;
+ loff_t pos;
+ int ret;
- BUG_ON(!lo || (rw != READ && rw != WRITE));
+ pos = ((loff_t) blk_rq_pos(rq) << 9) + lo->lo_offset;
- spin_lock_irq(&lo->lo_lock);
- if (lo->lo_state != Lo_bound)
- goto out;
- if (unlikely(rw == WRITE && (lo->lo_flags & LO_FLAGS_READ_ONLY)))
- goto out;
- if (lo->lo_bio_count >= q->nr_congestion_on)
- wait_event_lock_irq(lo->lo_req_wait,
- lo->lo_bio_count < q->nr_congestion_off,
- lo->lo_lock);
- loop_add_bio(lo, old_bio);
- wake_up(&lo->lo_event);
- spin_unlock_irq(&lo->lo_lock);
- return;
+ if (rq->cmd_flags & REQ_WRITE) {
+ if (rq->cmd_flags & REQ_FLUSH)
+ ret = lo_req_flush(lo, rq);
+ else if (rq->cmd_flags & REQ_DISCARD)
+ ret = lo_discard(lo, rq, pos);
+ else
+ ret = lo_send(lo, rq, pos);
+ } else
+ ret = lo_receive(lo, rq, lo->lo_blocksize, pos);
-out:
- spin_unlock_irq(&lo->lo_lock);
- bio_io_error(old_bio);
+ return ret;
}
struct switch_request {
@@ -518,57 +475,26 @@ struct switch_request {
struct completion wait;
};
-static void do_loop_switch(struct loop_device *, struct switch_request *);
-
-static inline void loop_handle_bio(struct loop_device *lo, struct bio *bio)
-{
- if (unlikely(!bio->bi_bdev)) {
- do_loop_switch(lo, bio->bi_private);
- bio_put(bio);
- } else {
- int ret = do_bio_filebacked(lo, bio);
- bio_endio(bio, ret);
- }
-}
-
/*
- * worker thread that handles reads/writes to file backed loop devices,
- * to avoid blocking in our make_request_fn. it also does loop decrypting
- * on reads for block backed loop, as that is too heavy to do from
- * b_end_io context where irqs may be disabled.
- *
- * Loop explanation: loop_clr_fd() sets lo_state to Lo_rundown before
- * calling kthread_stop(). Therefore once kthread_should_stop() is
- * true, make_request will not place any more requests. Therefore
- * once kthread_should_stop() is true and lo_bio is NULL, we are
- * done with the loop.
+ * Do the actual switch; called from the BIO completion routine
*/
-static int loop_thread(void *data)
+static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
{
- struct loop_device *lo = data;
- struct bio *bio;
-
- set_user_nice(current, MIN_NICE);
-
- while (!kthread_should_stop() || !bio_list_empty(&lo->lo_bio_list)) {
-
- wait_event_interruptible(lo->lo_event,
- !bio_list_empty(&lo->lo_bio_list) ||
- kthread_should_stop());
-
- if (bio_list_empty(&lo->lo_bio_list))
- continue;
- spin_lock_irq(&lo->lo_lock);
- bio = loop_get_bio(lo);
- if (lo->lo_bio_count < lo->lo_queue->nr_congestion_off)
- wake_up(&lo->lo_req_wait);
- spin_unlock_irq(&lo->lo_lock);
+ struct file *file = p->file;
+ struct file *old_file = lo->lo_backing_file;
+ struct address_space *mapping;
- BUG_ON(!bio);
- loop_handle_bio(lo, bio);
- }
+ /* if no new file, only flush of queued bios requested */
+ if (!file)
+ return;
- return 0;
+ mapping = file->f_mapping;
+ mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
+ lo->lo_backing_file = file;
+ lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
+ mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
+ lo->old_gfp_mask = mapping_gfp_mask(mapping);
+ mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
}
/*
@@ -579,15 +505,18 @@ static int loop_thread(void *data)
static int loop_switch(struct loop_device *lo, struct file *file)
{
struct switch_request w;
- struct bio *bio = bio_alloc(GFP_KERNEL, 0);
- if (!bio)
- return -ENOMEM;
- init_completion(&w.wait);
+
w.file = file;
- bio->bi_private = &w;
- bio->bi_bdev = NULL;
- loop_make_request(lo->lo_queue, bio);
- wait_for_completion(&w.wait);
+
+ /* freeze queue and wait for completion of scheduled requests */
+ blk_mq_freeze_queue(lo->lo_queue);
+
+ /* do the switch action */
+ do_loop_switch(lo, &w);
+
+ /* unfreeze */
+ blk_mq_unfreeze_queue(lo->lo_queue);
+
return 0;
}
@@ -596,39 +525,10 @@ static int loop_switch(struct loop_device *lo, struct file *file)
*/
static int loop_flush(struct loop_device *lo)
{
- /* loop not yet configured, no running thread, nothing to flush */
- if (!lo->lo_thread)
- return 0;
-
return loop_switch(lo, NULL);
}
/*
- * Do the actual switch; called from the BIO completion routine
- */
-static void do_loop_switch(struct loop_device *lo, struct switch_request *p)
-{
- struct file *file = p->file;
- struct file *old_file = lo->lo_backing_file;
- struct address_space *mapping;
-
- /* if no new file, only flush of queued bios requested */
- if (!file)
- goto out;
-
- mapping = file->f_mapping;
- mapping_set_gfp_mask(old_file->f_mapping, lo->old_gfp_mask);
- lo->lo_backing_file = file;
- lo->lo_blocksize = S_ISBLK(mapping->host->i_mode) ?
- mapping->host->i_bdev->bd_block_size : PAGE_SIZE;
- lo->old_gfp_mask = mapping_gfp_mask(mapping);
- mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
-out:
- complete(&p->wait);
-}
-
-
-/*
* loop_change_fd switched the backing store of a loopback device to
* a new file. This is useful for operating system installers to free up
* the original file and in High Availability environments to switch to
@@ -889,12 +789,9 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
lo->transfer = transfer_none;
lo->ioctl = NULL;
lo->lo_sizelimit = 0;
- lo->lo_bio_count = 0;
lo->old_gfp_mask = mapping_gfp_mask(mapping);
mapping_set_gfp_mask(mapping, lo->old_gfp_mask & ~(__GFP_IO|__GFP_FS));
- bio_list_init(&lo->lo_bio_list);
-
if (!(lo_flags & LO_FLAGS_READ_ONLY) && file->f_op->fsync)
blk_queue_flush(lo->lo_queue, REQ_FLUSH);
@@ -906,14 +803,7 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
set_blocksize(bdev, lo_blocksize);
- lo->lo_thread = kthread_create(loop_thread, lo, "loop%d",
- lo->lo_number);
- if (IS_ERR(lo->lo_thread)) {
- error = PTR_ERR(lo->lo_thread);
- goto out_clr;
- }
lo->lo_state = Lo_bound;
- wake_up_process(lo->lo_thread);
if (part_shift)
lo->lo_flags |= LO_FLAGS_PARTSCAN;
if (lo->lo_flags & LO_FLAGS_PARTSCAN)
@@ -925,18 +815,6 @@ static int loop_set_fd(struct loop_device *lo, fmode_t mode,
bdgrab(bdev);
return 0;
-out_clr:
- loop_sysfs_exit(lo);
- lo->lo_thread = NULL;
- lo->lo_device = NULL;
- lo->lo_backing_file = NULL;
- lo->lo_flags = 0;
- set_capacity(lo->lo_disk, 0);
- invalidate_bdev(bdev);
- bd_set_size(bdev, 0);
- kobject_uevent(&disk_to_dev(bdev->bd_disk)->kobj, KOBJ_CHANGE);
- mapping_set_gfp_mask(mapping, lo->old_gfp_mask);
- lo->lo_state = Lo_unbound;
out_putf:
fput(file);
out:
@@ -1012,11 +890,6 @@ static int loop_clr_fd(struct loop_device *lo)
spin_lock_irq(&lo->lo_lock);
lo->lo_state = Lo_rundown;
- spin_unlock_irq(&lo->lo_lock);
-
- kthread_stop(lo->lo_thread);
-
- spin_lock_irq(&lo->lo_lock);
lo->lo_backing_file = NULL;
spin_unlock_irq(&lo->lo_lock);
@@ -1028,7 +901,6 @@ static int loop_clr_fd(struct loop_device *lo)
lo->lo_offset = 0;
lo->lo_sizelimit = 0;
lo->lo_encrypt_key_size = 0;
- lo->lo_thread = NULL;
memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE);
memset(lo->lo_crypt_name, 0, LO_NAME_SIZE);
memset(lo->lo_file_name, 0, LO_NAME_SIZE);
@@ -1601,6 +1473,105 @@ int loop_unregister_transfer(int number)
EXPORT_SYMBOL(loop_register_transfer);
EXPORT_SYMBOL(loop_unregister_transfer);
+static int loop_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
+{
+ struct loop_cmd *cmd = blk_mq_rq_to_pdu(bd->rq);
+
+ blk_mq_start_request(bd->rq);
+
+ if (cmd->rq->cmd_flags & REQ_WRITE) {
+ struct loop_device *lo = cmd->rq->q->queuedata;
+ bool need_sched = true;
+
+ spin_lock_irq(&lo->lo_lock);
+ if (lo->write_started)
+ need_sched = false;
+ else
+ lo->write_started = true;
+ list_add_tail(&cmd->list, &lo->write_cmd_head);
+ spin_unlock_irq(&lo->lo_lock);
+
+ if (need_sched)
+ queue_work(loop_wq, &lo->write_work);
+ } else {
+ queue_work(loop_wq, &cmd->read_work);
+ }
+
+ return BLK_MQ_RQ_QUEUE_OK;
+}
+
+static void loop_handle_cmd(struct loop_cmd *cmd)
+{
+ const bool write = cmd->rq->cmd_flags & REQ_WRITE;
+ struct loop_device *lo = cmd->rq->q->queuedata;
+ int ret = -EIO;
+
+ if (lo->lo_state != Lo_bound)
+ goto failed;
+
+ if (write && (lo->lo_flags & LO_FLAGS_READ_ONLY))
+ goto failed;
+
+ ret = do_req_filebacked(lo, cmd->rq);
+
+ failed:
+ if (ret)
+ cmd->rq->errors = -EIO;
+ blk_mq_complete_request(cmd->rq);
+}
+
+static void loop_queue_write_work(struct work_struct *work)
+{
+ struct loop_device *lo =
+ container_of(work, struct loop_device, write_work);
+ LIST_HEAD(cmd_list);
+
+ spin_lock_irq(&lo->lo_lock);
+ repeat:
+ list_splice_init(&lo->write_cmd_head, &cmd_list);
+ spin_unlock_irq(&lo->lo_lock);
+
+ while (!list_empty(&cmd_list)) {
+ struct loop_cmd *cmd = list_first_entry(&cmd_list,
+ struct loop_cmd, list);
+ list_del_init(&cmd->list);
+ loop_handle_cmd(cmd);
+ }
+
+ spin_lock_irq(&lo->lo_lock);
+ if (!list_empty(&lo->write_cmd_head))
+ goto repeat;
+ lo->write_started = false;
+ spin_unlock_irq(&lo->lo_lock);
+}
+
+static void loop_queue_read_work(struct work_struct *work)
+{
+ struct loop_cmd *cmd =
+ container_of(work, struct loop_cmd, read_work);
+
+ loop_handle_cmd(cmd);
+}
+
+static int loop_init_request(void *data, struct request *rq,
+ unsigned int hctx_idx, unsigned int request_idx,
+ unsigned int numa_node)
+{
+ struct loop_cmd *cmd = blk_mq_rq_to_pdu(rq);
+
+ cmd->rq = rq;
+ INIT_WORK(&cmd->read_work, loop_queue_read_work);
+
+ return 0;
+}
+
+static struct blk_mq_ops loop_mq_ops = {
+ .queue_rq = loop_queue_rq,
+ .map_queue = blk_mq_map_queue,
+ .init_request = loop_init_request,
+};
+
static int loop_add(struct loop_device **l, int i)
{
struct loop_device *lo;
@@ -1627,16 +1598,28 @@ static int loop_add(struct loop_device **l, int i)
i = err;
err = -ENOMEM;
- lo->lo_queue = blk_alloc_queue(GFP_KERNEL);
- if (!lo->lo_queue)
+ lo->tag_set.ops = &loop_mq_ops;
+ lo->tag_set.nr_hw_queues = 1;
+ lo->tag_set.queue_depth = 128;
+ lo->tag_set.numa_node = NUMA_NO_NODE;
+ lo->tag_set.cmd_size = sizeof(struct loop_cmd);
+ lo->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
+ lo->tag_set.driver_data = lo;
+
+ err = blk_mq_alloc_tag_set(&lo->tag_set);
+ if (err)
goto out_free_idr;
- /*
- * set queue make_request_fn
- */
- blk_queue_make_request(lo->lo_queue, loop_make_request);
+ lo->lo_queue = blk_mq_init_queue(&lo->tag_set);
+ if (IS_ERR_OR_NULL(lo->lo_queue)) {
+ err = PTR_ERR(lo->lo_queue);
+ goto out_cleanup_tags;
+ }
lo->lo_queue->queuedata = lo;
+ INIT_LIST_HEAD(&lo->write_cmd_head);
+ INIT_WORK(&lo->write_work, loop_queue_write_work);
+
disk = lo->lo_disk = alloc_disk(1 << part_shift);
if (!disk)
goto out_free_queue;
@@ -1664,9 +1647,6 @@ static int loop_add(struct loop_device **l, int i)
disk->flags |= GENHD_FL_EXT_DEVT;
mutex_init(&lo->lo_ctl_mutex);
lo->lo_number = i;
- lo->lo_thread = NULL;
- init_waitqueue_head(&lo->lo_event);
- init_waitqueue_head(&lo->lo_req_wait);
spin_lock_init(&lo->lo_lock);
disk->major = LOOP_MAJOR;
disk->first_minor = i << part_shift;
@@ -1680,6 +1660,8 @@ static int loop_add(struct loop_device **l, int i)
out_free_queue:
blk_cleanup_queue(lo->lo_queue);
+out_cleanup_tags:
+ blk_mq_free_tag_set(&lo->tag_set);
out_free_idr:
idr_remove(&loop_index_idr, i);
out_free_dev:
@@ -1692,6 +1674,7 @@ static void loop_remove(struct loop_device *lo)
{
del_gendisk(lo->lo_disk);
blk_cleanup_queue(lo->lo_queue);
+ blk_mq_free_tag_set(&lo->tag_set);
put_disk(lo->lo_disk);
kfree(lo);
}
@@ -1875,6 +1858,13 @@ static int __init loop_init(void)
goto misc_out;
}
+ loop_wq = alloc_workqueue("kloopd",
+ WQ_MEM_RECLAIM | WQ_HIGHPRI | WQ_UNBOUND, 0);
+ if (!loop_wq) {
+ err = -ENOMEM;
+ goto misc_out;
+ }
+
blk_register_region(MKDEV(LOOP_MAJOR, 0), range,
THIS_MODULE, loop_probe, NULL, NULL);
@@ -1912,6 +1902,8 @@ static void __exit loop_exit(void)
blk_unregister_region(MKDEV(LOOP_MAJOR, 0), range);
unregister_blkdev(LOOP_MAJOR, "loop");
+ destroy_workqueue(loop_wq);
+
misc_deregister(&loop_misc);
}
diff --git a/drivers/block/loop.h b/drivers/block/loop.h
index 90df5d6485b6..301c27f8323f 100644
--- a/drivers/block/loop.h
+++ b/drivers/block/loop.h
@@ -11,8 +11,10 @@
#include <linux/bio.h>
#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <uapi/linux/loop.h>
/* Possible states of device */
@@ -52,19 +54,23 @@ struct loop_device {
gfp_t old_gfp_mask;
spinlock_t lo_lock;
- struct bio_list lo_bio_list;
- unsigned int lo_bio_count;
+ struct list_head write_cmd_head;
+ struct work_struct write_work;
+ bool write_started;
int lo_state;
struct mutex lo_ctl_mutex;
- struct task_struct *lo_thread;
- wait_queue_head_t lo_event;
- /* wait queue for incoming requests */
- wait_queue_head_t lo_req_wait;
struct request_queue *lo_queue;
+ struct blk_mq_tag_set tag_set;
struct gendisk *lo_disk;
};
+struct loop_cmd {
+ struct work_struct read_work;
+ struct request *rq;
+ struct list_head list;
+};
+
/* Support for loadable transfer modules */
struct loop_func_table {
int number; /* filter type */
diff --git a/drivers/block/null_blk.c b/drivers/block/null_blk.c
index aa2224aa7caa..65cd61a4145e 100644
--- a/drivers/block/null_blk.c
+++ b/drivers/block/null_blk.c
@@ -579,7 +579,7 @@ static int null_add_dev(void)
sector_div(size, bs);
set_capacity(disk, size);
- disk->flags |= GENHD_FL_EXT_DEVT;
+ disk->flags |= GENHD_FL_EXT_DEVT | GENHD_FL_SUPPRESS_PARTITION_INFO;
disk->major = null_major;
disk->first_minor = nullb->index;
disk->fops = &null_fops;
diff --git a/drivers/block/nvme-core.c b/drivers/block/nvme-core.c
index d826bf3e62c8..ceb32dd52a6c 100644
--- a/drivers/block/nvme-core.c
+++ b/drivers/block/nvme-core.c
@@ -37,17 +37,18 @@
#include <linux/ptrace.h>
#include <linux/sched.h>
#include <linux/slab.h>
+#include <linux/t10-pi.h>
#include <linux/types.h>
#include <scsi/sg.h>
#include <asm-generic/io-64-nonatomic-lo-hi.h>
+#define NVME_MINORS (1U << MINORBITS)
#define NVME_Q_DEPTH 1024
#define NVME_AQ_DEPTH 64
#define SQ_SIZE(depth) (depth * sizeof(struct nvme_command))
#define CQ_SIZE(depth) (depth * sizeof(struct nvme_completion))
#define ADMIN_TIMEOUT (admin_timeout * HZ)
#define SHUTDOWN_TIMEOUT (shutdown_timeout * HZ)
-#define IOD_TIMEOUT (retry_time * HZ)
static unsigned char admin_timeout = 60;
module_param(admin_timeout, byte, 0644);
@@ -57,10 +58,6 @@ unsigned char nvme_io_timeout = 30;
module_param_named(io_timeout, nvme_io_timeout, byte, 0644);
MODULE_PARM_DESC(io_timeout, "timeout in seconds for I/O");
-static unsigned char retry_time = 30;
-module_param(retry_time, byte, 0644);
-MODULE_PARM_DESC(retry_time, "time in seconds to retry failed I/O");
-
static unsigned char shutdown_timeout = 5;
module_param(shutdown_timeout, byte, 0644);
MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown");
@@ -68,6 +65,9 @@ MODULE_PARM_DESC(shutdown_timeout, "timeout in seconds for controller shutdown")
static int nvme_major;
module_param(nvme_major, int, 0);
+static int nvme_char_major;
+module_param(nvme_char_major, int, 0);
+
static int use_threaded_interrupts;
module_param(use_threaded_interrupts, int, 0);
@@ -76,7 +76,8 @@ static LIST_HEAD(dev_list);
static struct task_struct *nvme_thread;
static struct workqueue_struct *nvme_workq;
static wait_queue_head_t nvme_kthread_wait;
-static struct notifier_block nvme_nb;
+
+static struct class *nvme_class;
static void nvme_reset_failed_dev(struct work_struct *ws);
static int nvme_process_cq(struct nvme_queue *nvmeq);
@@ -95,7 +96,6 @@ struct async_cmd_info {
* commands and one for I/O commands).
*/
struct nvme_queue {
- struct llist_node node;
struct device *q_dmadev;
struct nvme_dev *dev;
char irqname[24]; /* nvme4294967295-65535\0 */
@@ -144,8 +144,37 @@ struct nvme_cmd_info {
void *ctx;
int aborted;
struct nvme_queue *nvmeq;
+ struct nvme_iod iod[0];
};
+/*
+ * Max size of iod being embedded in the request payload
+ */
+#define NVME_INT_PAGES 2
+#define NVME_INT_BYTES(dev) (NVME_INT_PAGES * (dev)->page_size)
+
+/*
+ * Will slightly overestimate the number of pages needed. This is OK
+ * as it only leads to a small amount of wasted memory for the lifetime of
+ * the I/O.
+ */
+static int nvme_npages(unsigned size, struct nvme_dev *dev)
+{
+ unsigned nprps = DIV_ROUND_UP(size + dev->page_size, dev->page_size);
+ return DIV_ROUND_UP(8 * nprps, PAGE_SIZE - 8);
+}
+
+static unsigned int nvme_cmd_size(struct nvme_dev *dev)
+{
+ unsigned int ret = sizeof(struct nvme_cmd_info);
+
+ ret += sizeof(struct nvme_iod);
+ ret += sizeof(__le64 *) * nvme_npages(NVME_INT_BYTES(dev), dev);
+ ret += sizeof(struct scatterlist) * NVME_INT_PAGES;
+
+ return ret;
+}
+
static int nvme_admin_init_hctx(struct blk_mq_hw_ctx *hctx, void *data,
unsigned int hctx_idx)
{
@@ -218,6 +247,19 @@ static void nvme_set_info(struct nvme_cmd_info *cmd, void *ctx,
blk_mq_start_request(blk_mq_rq_from_pdu(cmd));
}
+static void *iod_get_private(struct nvme_iod *iod)
+{
+ return (void *) (iod->private & ~0x1UL);
+}
+
+/*
+ * If bit 0 is set, the iod is embedded in the request payload.
+ */
+static bool iod_should_kfree(struct nvme_iod *iod)
+{
+ return (iod->private & 0x01) == 0;
+}
+
/* Special values must be less than 0x1000 */
#define CMD_CTX_BASE ((void *)POISON_POINTER_DELTA)
#define CMD_CTX_CANCELLED (0x30C + CMD_CTX_BASE)
@@ -361,35 +403,53 @@ static __le64 **iod_list(struct nvme_iod *iod)
return ((void *)iod) + iod->offset;
}
-/*
- * Will slightly overestimate the number of pages needed. This is OK
- * as it only leads to a small amount of wasted memory for the lifetime of
- * the I/O.
- */
-static int nvme_npages(unsigned size, struct nvme_dev *dev)
+static inline void iod_init(struct nvme_iod *iod, unsigned nbytes,
+ unsigned nseg, unsigned long private)
{
- unsigned nprps = DIV_ROUND_UP(size + dev->page_size, dev->page_size);
- return DIV_ROUND_UP(8 * nprps, dev->page_size - 8);
+ iod->private = private;
+ iod->offset = offsetof(struct nvme_iod, sg[nseg]);
+ iod->npages = -1;
+ iod->length = nbytes;
+ iod->nents = 0;
}
static struct nvme_iod *
-nvme_alloc_iod(unsigned nseg, unsigned nbytes, struct nvme_dev *dev, gfp_t gfp)
+__nvme_alloc_iod(unsigned nseg, unsigned bytes, struct nvme_dev *dev,
+ unsigned long priv, gfp_t gfp)
{
struct nvme_iod *iod = kmalloc(sizeof(struct nvme_iod) +
- sizeof(__le64 *) * nvme_npages(nbytes, dev) +
+ sizeof(__le64 *) * nvme_npages(bytes, dev) +
sizeof(struct scatterlist) * nseg, gfp);
- if (iod) {
- iod->offset = offsetof(struct nvme_iod, sg[nseg]);
- iod->npages = -1;
- iod->length = nbytes;
- iod->nents = 0;
- iod->first_dma = 0ULL;
- }
+ if (iod)
+ iod_init(iod, bytes, nseg, priv);
return iod;
}
+static struct nvme_iod *nvme_alloc_iod(struct request *rq, struct nvme_dev *dev,
+ gfp_t gfp)
+{
+ unsigned size = !(rq->cmd_flags & REQ_DISCARD) ? blk_rq_bytes(rq) :
+ sizeof(struct nvme_dsm_range);
+ unsigned long mask = 0;
+ struct nvme_iod *iod;
+
+ if (rq->nr_phys_segments <= NVME_INT_PAGES &&
+ size <= NVME_INT_BYTES(dev)) {
+ struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(rq);
+
+ iod = cmd->iod;
+ mask = 0x01;
+ iod_init(iod, size, rq->nr_phys_segments,
+ (unsigned long) rq | 0x01);
+ return iod;
+ }
+
+ return __nvme_alloc_iod(rq->nr_phys_segments, size, dev,
+ (unsigned long) rq, gfp);
+}
+
void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
{
const int last_prp = dev->page_size / 8 - 1;
@@ -405,7 +465,9 @@ void nvme_free_iod(struct nvme_dev *dev, struct nvme_iod *iod)
dma_pool_free(dev->prp_page_pool, prp_list, prp_dma);
prp_dma = next_prp_dma;
}
- kfree(iod);
+
+ if (iod_should_kfree(iod))
+ kfree(iod);
}
static int nvme_error_status(u16 status)
@@ -420,11 +482,120 @@ static int nvme_error_status(u16 status)
}
}
+#ifdef CONFIG_BLK_DEV_INTEGRITY
+static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+ if (be32_to_cpu(pi->ref_tag) == v)
+ pi->ref_tag = cpu_to_be32(p);
+}
+
+static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+ if (be32_to_cpu(pi->ref_tag) == p)
+ pi->ref_tag = cpu_to_be32(v);
+}
+
+/**
+ * nvme_dif_remap - remaps ref tags to bip seed and physical lba
+ *
+ * The virtual start sector is the one that was originally submitted by the
+ * block layer. Due to partitioning, MD/DM cloning, etc. the actual physical
+ * start sector may be different. Remap protection information to match the
+ * physical LBA on writes, and back to the original seed on reads.
+ *
+ * Type 0 and 3 do not have a ref tag, so no remapping required.
+ */
+static void nvme_dif_remap(struct request *req,
+ void (*dif_swap)(u32 p, u32 v, struct t10_pi_tuple *pi))
+{
+ struct nvme_ns *ns = req->rq_disk->private_data;
+ struct bio_integrity_payload *bip;
+ struct t10_pi_tuple *pi;
+ void *p, *pmap;
+ u32 i, nlb, ts, phys, virt;
+
+ if (!ns->pi_type || ns->pi_type == NVME_NS_DPS_PI_TYPE3)
+ return;
+
+ bip = bio_integrity(req->bio);
+ if (!bip)
+ return;
+
+ pmap = kmap_atomic(bip->bip_vec->bv_page) + bip->bip_vec->bv_offset;
+ if (!pmap)
+ return;
+
+ p = pmap;
+ virt = bip_get_seed(bip);
+ phys = nvme_block_nr(ns, blk_rq_pos(req));
+ nlb = (blk_rq_bytes(req) >> ns->lba_shift);
+ ts = ns->disk->integrity->tuple_size;
+
+ for (i = 0; i < nlb; i++, virt++, phys++) {
+ pi = (struct t10_pi_tuple *)p;
+ dif_swap(phys, virt, pi);
+ p += ts;
+ }
+ kunmap_atomic(pmap);
+}
+
+static int nvme_noop_verify(struct blk_integrity_iter *iter)
+{
+ return 0;
+}
+
+static int nvme_noop_generate(struct blk_integrity_iter *iter)
+{
+ return 0;
+}
+
+struct blk_integrity nvme_meta_noop = {
+ .name = "NVME_META_NOOP",
+ .generate_fn = nvme_noop_generate,
+ .verify_fn = nvme_noop_verify,
+};
+
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+ struct blk_integrity integrity;
+
+ switch (ns->pi_type) {
+ case NVME_NS_DPS_PI_TYPE3:
+ integrity = t10_pi_type3_crc;
+ break;
+ case NVME_NS_DPS_PI_TYPE1:
+ case NVME_NS_DPS_PI_TYPE2:
+ integrity = t10_pi_type1_crc;
+ break;
+ default:
+ integrity = nvme_meta_noop;
+ break;
+ }
+ integrity.tuple_size = ns->ms;
+ blk_integrity_register(ns->disk, &integrity);
+ blk_queue_max_integrity_segments(ns->queue, 1);
+}
+#else /* CONFIG_BLK_DEV_INTEGRITY */
+static void nvme_dif_remap(struct request *req,
+ void (*dif_swap)(u32 p, u32 v, struct t10_pi_tuple *pi))
+{
+}
+static void nvme_dif_prep(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_dif_complete(u32 p, u32 v, struct t10_pi_tuple *pi)
+{
+}
+static void nvme_init_integrity(struct nvme_ns *ns)
+{
+}
+#endif
+
static void req_completion(struct nvme_queue *nvmeq, void *ctx,
struct nvme_completion *cqe)
{
struct nvme_iod *iod = ctx;
- struct request *req = iod->private;
+ struct request *req = iod_get_private(iod);
struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
u16 status = le16_to_cpup(&cqe->status) >> 1;
@@ -450,9 +621,16 @@ static void req_completion(struct nvme_queue *nvmeq, void *ctx,
"completing aborted command with status:%04x\n",
status);
- if (iod->nents)
+ if (iod->nents) {
dma_unmap_sg(&nvmeq->dev->pci_dev->dev, iod->sg, iod->nents,
rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ if (blk_integrity_rq(req)) {
+ if (!rq_data_dir(req))
+ nvme_dif_remap(req, nvme_dif_complete);
+ dma_unmap_sg(&nvmeq->dev->pci_dev->dev, iod->meta_sg, 1,
+ rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ }
+ }
nvme_free_iod(nvmeq->dev, iod);
blk_mq_complete_request(req);
@@ -585,7 +763,7 @@ static void nvme_submit_flush(struct nvme_queue *nvmeq, struct nvme_ns *ns,
static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod,
struct nvme_ns *ns)
{
- struct request *req = iod->private;
+ struct request *req = iod_get_private(iod);
struct nvme_command *cmnd;
u16 control = 0;
u32 dsmgmt = 0;
@@ -608,6 +786,24 @@ static int nvme_submit_iod(struct nvme_queue *nvmeq, struct nvme_iod *iod,
cmnd->rw.prp2 = cpu_to_le64(iod->first_dma);
cmnd->rw.slba = cpu_to_le64(nvme_block_nr(ns, blk_rq_pos(req)));
cmnd->rw.length = cpu_to_le16((blk_rq_bytes(req) >> ns->lba_shift) - 1);
+
+ if (blk_integrity_rq(req)) {
+ cmnd->rw.metadata = cpu_to_le64(sg_dma_address(iod->meta_sg));
+ switch (ns->pi_type) {
+ case NVME_NS_DPS_PI_TYPE3:
+ control |= NVME_RW_PRINFO_PRCHK_GUARD;
+ break;
+ case NVME_NS_DPS_PI_TYPE1:
+ case NVME_NS_DPS_PI_TYPE2:
+ control |= NVME_RW_PRINFO_PRCHK_GUARD |
+ NVME_RW_PRINFO_PRCHK_REF;
+ cmnd->rw.reftag = cpu_to_le32(
+ nvme_block_nr(ns, blk_rq_pos(req)));
+ break;
+ }
+ } else if (ns->ms)
+ control |= NVME_RW_PRINFO_PRACT;
+
cmnd->rw.control = cpu_to_le16(control);
cmnd->rw.dsmgmt = cpu_to_le32(dsmgmt);
@@ -626,17 +822,25 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
struct request *req = bd->rq;
struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
struct nvme_iod *iod;
- int psegs = req->nr_phys_segments;
enum dma_data_direction dma_dir;
- unsigned size = !(req->cmd_flags & REQ_DISCARD) ? blk_rq_bytes(req) :
- sizeof(struct nvme_dsm_range);
- iod = nvme_alloc_iod(psegs, size, ns->dev, GFP_ATOMIC);
+ /*
+ * If formated with metadata, require the block layer provide a buffer
+ * unless this namespace is formated such that the metadata can be
+ * stripped/generated by the controller with PRACT=1.
+ */
+ if (ns->ms && !blk_integrity_rq(req)) {
+ if (!(ns->pi_type && ns->ms == 8)) {
+ req->errors = -EFAULT;
+ blk_mq_complete_request(req);
+ return BLK_MQ_RQ_QUEUE_OK;
+ }
+ }
+
+ iod = nvme_alloc_iod(req, ns->dev, GFP_ATOMIC);
if (!iod)
return BLK_MQ_RQ_QUEUE_BUSY;
- iod->private = req;
-
if (req->cmd_flags & REQ_DISCARD) {
void *range;
/*
@@ -651,10 +855,10 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
goto retry_cmd;
iod_list(iod)[0] = (__le64 *)range;
iod->npages = 0;
- } else if (psegs) {
+ } else if (req->nr_phys_segments) {
dma_dir = rq_data_dir(req) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
- sg_init_table(iod->sg, psegs);
+ sg_init_table(iod->sg, req->nr_phys_segments);
iod->nents = blk_rq_map_sg(req->q, req, iod->sg);
if (!iod->nents)
goto error_cmd;
@@ -668,6 +872,21 @@ static int nvme_queue_rq(struct blk_mq_hw_ctx *hctx,
iod->nents, dma_dir);
goto retry_cmd;
}
+ if (blk_integrity_rq(req)) {
+ if (blk_rq_count_integrity_sg(req->q, req->bio) != 1)
+ goto error_cmd;
+
+ sg_init_table(iod->meta_sg, 1);
+ if (blk_rq_map_integrity_sg(
+ req->q, req->bio, iod->meta_sg) != 1)
+ goto error_cmd;
+
+ if (rq_data_dir(req))
+ nvme_dif_remap(req, nvme_dif_prep);
+
+ if (!dma_map_sg(nvmeq->q_dmadev, iod->meta_sg, 1, dma_dir))
+ goto error_cmd;
+ }
}
nvme_set_info(cmd, iod, req_completion);
@@ -760,14 +979,6 @@ static irqreturn_t nvme_irq_check(int irq, void *data)
return IRQ_WAKE_THREAD;
}
-static void nvme_abort_cmd_info(struct nvme_queue *nvmeq, struct nvme_cmd_info *
- cmd_info)
-{
- spin_lock_irq(&nvmeq->q_lock);
- cancel_cmd_info(cmd_info, NULL);
- spin_unlock_irq(&nvmeq->q_lock);
-}
-
struct sync_cmd_info {
struct task_struct *task;
u32 result;
@@ -790,7 +1001,6 @@ static void sync_completion(struct nvme_queue *nvmeq, void *ctx,
static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,
u32 *result, unsigned timeout)
{
- int ret;
struct sync_cmd_info cmdinfo;
struct nvme_cmd_info *cmd_rq = blk_mq_rq_to_pdu(req);
struct nvme_queue *nvmeq = cmd_rq->nvmeq;
@@ -802,29 +1012,12 @@ static int nvme_submit_sync_cmd(struct request *req, struct nvme_command *cmd,
nvme_set_info(cmd_rq, &cmdinfo, sync_completion);
- set_current_state(TASK_KILLABLE);
- ret = nvme_submit_cmd(nvmeq, cmd);
- if (ret) {
- nvme_finish_cmd(nvmeq, req->tag, NULL);
- set_current_state(TASK_RUNNING);
- }
- ret = schedule_timeout(timeout);
-
- /*
- * Ensure that sync_completion has either run, or that it will
- * never run.
- */
- nvme_abort_cmd_info(nvmeq, blk_mq_rq_to_pdu(req));
-
- /*
- * We never got the completion
- */
- if (cmdinfo.status == -EINTR)
- return -EINTR;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ nvme_submit_cmd(nvmeq, cmd);
+ schedule();
if (result)
*result = cmdinfo.result;
-
return cmdinfo.status;
}
@@ -1101,29 +1294,18 @@ static enum blk_eh_timer_return nvme_timeout(struct request *req, bool reserved)
struct nvme_cmd_info *cmd = blk_mq_rq_to_pdu(req);
struct nvme_queue *nvmeq = cmd->nvmeq;
- /*
- * The aborted req will be completed on receiving the abort req.
- * We enable the timer again. If hit twice, it'll cause a device reset,
- * as the device then is in a faulty state.
- */
- int ret = BLK_EH_RESET_TIMER;
-
dev_warn(nvmeq->q_dmadev, "Timeout I/O %d QID %d\n", req->tag,
nvmeq->qid);
-
spin_lock_irq(&nvmeq->q_lock);
- if (!nvmeq->dev->initialized) {
- /*
- * Force cancelled command frees the request, which requires we
- * return BLK_EH_NOT_HANDLED.
- */
- nvme_cancel_queue_ios(nvmeq->hctx, req, nvmeq, reserved);
- ret = BLK_EH_NOT_HANDLED;
- } else
- nvme_abort_req(req);
+ nvme_abort_req(req);
spin_unlock_irq(&nvmeq->q_lock);
- return ret;
+ /*
+ * The aborted req will be completed on receiving the abort req.
+ * We enable the timer again. If hit twice, it'll cause a device reset,
+ * as the device then is in a faulty state.
+ */
+ return BLK_EH_RESET_TIMER;
}
static void nvme_free_queue(struct nvme_queue *nvmeq)
@@ -1137,21 +1319,14 @@ static void nvme_free_queue(struct nvme_queue *nvmeq)
static void nvme_free_queues(struct nvme_dev *dev, int lowest)
{
- LLIST_HEAD(q_list);
- struct nvme_queue *nvmeq, *next;
- struct llist_node *entry;
int i;
for (i = dev->queue_count - 1; i >= lowest; i--) {
struct nvme_queue *nvmeq = dev->queues[i];
- llist_add(&nvmeq->node, &q_list);
dev->queue_count--;
dev->queues[i] = NULL;
- }
- synchronize_rcu();
- entry = llist_del_all(&q_list);
- llist_for_each_entry_safe(nvmeq, next, entry, node)
nvme_free_queue(nvmeq);
+ }
}
/**
@@ -1183,7 +1358,6 @@ static void nvme_clear_queue(struct nvme_queue *nvmeq)
struct blk_mq_hw_ctx *hctx = nvmeq->hctx;
spin_lock_irq(&nvmeq->q_lock);
- nvme_process_cq(nvmeq);
if (hctx && hctx->tags)
blk_mq_tag_busy_iter(hctx, nvme_cancel_queue_ios, nvmeq);
spin_unlock_irq(&nvmeq->q_lock);
@@ -1206,7 +1380,10 @@ static void nvme_disable_queue(struct nvme_dev *dev, int qid)
}
if (!qid && dev->admin_q)
blk_mq_freeze_queue_start(dev->admin_q);
- nvme_clear_queue(nvmeq);
+
+ spin_lock_irq(&nvmeq->q_lock);
+ nvme_process_cq(nvmeq);
+ spin_unlock_irq(&nvmeq->q_lock);
}
static struct nvme_queue *nvme_alloc_queue(struct nvme_dev *dev, int qid,
@@ -1408,7 +1585,7 @@ static int nvme_alloc_admin_tags(struct nvme_dev *dev)
dev->admin_tagset.queue_depth = NVME_AQ_DEPTH - 1;
dev->admin_tagset.timeout = ADMIN_TIMEOUT;
dev->admin_tagset.numa_node = dev_to_node(&dev->pci_dev->dev);
- dev->admin_tagset.cmd_size = sizeof(struct nvme_cmd_info);
+ dev->admin_tagset.cmd_size = nvme_cmd_size(dev);
dev->admin_tagset.driver_data = dev;
if (blk_mq_alloc_tag_set(&dev->admin_tagset))
@@ -1522,7 +1699,7 @@ struct nvme_iod *nvme_map_user_pages(struct nvme_dev *dev, int write,
}
err = -ENOMEM;
- iod = nvme_alloc_iod(count, length, dev, GFP_KERNEL);
+ iod = __nvme_alloc_iod(count, length, dev, 0, GFP_KERNEL);
if (!iod)
goto put_pages;
@@ -1825,13 +2002,24 @@ static int nvme_getgeo(struct block_device *bd, struct hd_geometry *geo)
return 0;
}
+static void nvme_config_discard(struct nvme_ns *ns)
+{
+ u32 logical_block_size = queue_logical_block_size(ns->queue);
+ ns->queue->limits.discard_zeroes_data = 0;
+ ns->queue->limits.discard_alignment = logical_block_size;
+ ns->queue->limits.discard_granularity = logical_block_size;
+ ns->queue->limits.max_discard_sectors = 0xffffffff;
+ queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
+}
+
static int nvme_revalidate_disk(struct gendisk *disk)
{
struct nvme_ns *ns = disk->private_data;
struct nvme_dev *dev = ns->dev;
struct nvme_id_ns *id;
dma_addr_t dma_addr;
- int lbaf;
+ int lbaf, pi_type, old_ms;
+ unsigned short bs;
id = dma_alloc_coherent(&dev->pci_dev->dev, 4096, &dma_addr,
GFP_KERNEL);
@@ -1840,16 +2028,51 @@ static int nvme_revalidate_disk(struct gendisk *disk)
__func__);
return 0;
}
+ if (nvme_identify(dev, ns->ns_id, 0, dma_addr)) {
+ dev_warn(&dev->pci_dev->dev,
+ "identify failed ns:%d, setting capacity to 0\n",
+ ns->ns_id);
+ memset(id, 0, sizeof(*id));
+ }
- if (nvme_identify(dev, ns->ns_id, 0, dma_addr))
- goto free;
-
- lbaf = id->flbas & 0xf;
+ old_ms = ns->ms;
+ lbaf = id->flbas & NVME_NS_FLBAS_LBA_MASK;
ns->lba_shift = id->lbaf[lbaf].ds;
+ ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
+
+ /*
+ * If identify namespace failed, use default 512 byte block size so
+ * block layer can use before failing read/write for 0 capacity.
+ */
+ if (ns->lba_shift == 0)
+ ns->lba_shift = 9;
+ bs = 1 << ns->lba_shift;
+
+ /* XXX: PI implementation requires metadata equal t10 pi tuple size */
+ pi_type = ns->ms == sizeof(struct t10_pi_tuple) ?
+ id->dps & NVME_NS_DPS_PI_MASK : 0;
+
+ if (blk_get_integrity(disk) && (ns->pi_type != pi_type ||
+ ns->ms != old_ms ||
+ bs != queue_logical_block_size(disk->queue) ||
+ (ns->ms && id->flbas & NVME_NS_FLBAS_META_EXT)))
+ blk_integrity_unregister(disk);
+
+ ns->pi_type = pi_type;
+ blk_queue_logical_block_size(ns->queue, bs);
+
+ if (ns->ms && !blk_get_integrity(disk) && (disk->flags & GENHD_FL_UP) &&
+ !(id->flbas & NVME_NS_FLBAS_META_EXT))
+ nvme_init_integrity(ns);
+
+ if (id->ncap == 0 || (ns->ms && !blk_get_integrity(disk)))
+ set_capacity(disk, 0);
+ else
+ set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
+
+ if (dev->oncs & NVME_CTRL_ONCS_DSM)
+ nvme_config_discard(ns);
- blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
- set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
- free:
dma_free_coherent(&dev->pci_dev->dev, 4096, id, dma_addr);
return 0;
}
@@ -1873,8 +2096,7 @@ static int nvme_kthread(void *data)
spin_lock(&dev_list_lock);
list_for_each_entry_safe(dev, next, &dev_list, node) {
int i;
- if (readl(&dev->bar->csts) & NVME_CSTS_CFS &&
- dev->initialized) {
+ if (readl(&dev->bar->csts) & NVME_CSTS_CFS) {
if (work_busy(&dev->reset_work))
continue;
list_del_init(&dev->node);
@@ -1906,30 +2128,16 @@ static int nvme_kthread(void *data)
return 0;
}
-static void nvme_config_discard(struct nvme_ns *ns)
-{
- u32 logical_block_size = queue_logical_block_size(ns->queue);
- ns->queue->limits.discard_zeroes_data = 0;
- ns->queue->limits.discard_alignment = logical_block_size;
- ns->queue->limits.discard_granularity = logical_block_size;
- ns->queue->limits.max_discard_sectors = 0xffffffff;
- queue_flag_set_unlocked(QUEUE_FLAG_DISCARD, ns->queue);
-}
-
-static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid,
- struct nvme_id_ns *id, struct nvme_lba_range_type *rt)
+static void nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid)
{
struct nvme_ns *ns;
struct gendisk *disk;
int node = dev_to_node(&dev->pci_dev->dev);
- int lbaf;
-
- if (rt->attributes & NVME_LBART_ATTRIB_HIDE)
- return NULL;
ns = kzalloc_node(sizeof(*ns), GFP_KERNEL, node);
if (!ns)
- return NULL;
+ return;
+
ns->queue = blk_mq_init_queue(&dev->tagset);
if (IS_ERR(ns->queue))
goto out_free_ns;
@@ -1945,9 +2153,9 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid,
ns->ns_id = nsid;
ns->disk = disk;
- lbaf = id->flbas & 0xf;
- ns->lba_shift = id->lbaf[lbaf].ds;
- ns->ms = le16_to_cpu(id->lbaf[lbaf].ms);
+ ns->lba_shift = 9; /* set to a default value for 512 until disk is validated */
+ list_add_tail(&ns->list, &dev->namespaces);
+
blk_queue_logical_block_size(ns->queue, 1 << ns->lba_shift);
if (dev->max_hw_sectors)
blk_queue_max_hw_sectors(ns->queue, dev->max_hw_sectors);
@@ -1961,21 +2169,26 @@ static struct nvme_ns *nvme_alloc_ns(struct nvme_dev *dev, unsigned nsid,
disk->fops = &nvme_fops;
disk->private_data = ns;
disk->queue = ns->queue;
- disk->driverfs_dev = &dev->pci_dev->dev;
+ disk->driverfs_dev = dev->device;
disk->flags = GENHD_FL_EXT_DEVT;
sprintf(disk->disk_name, "nvme%dn%d", dev->instance, nsid);
- set_capacity(disk, le64_to_cpup(&id->nsze) << (ns->lba_shift - 9));
-
- if (dev->oncs & NVME_CTRL_ONCS_DSM)
- nvme_config_discard(ns);
-
- return ns;
+ /*
+ * Initialize capacity to 0 until we establish the namespace format and
+ * setup integrity extentions if necessary. The revalidate_disk after
+ * add_disk allows the driver to register with integrity if the format
+ * requires it.
+ */
+ set_capacity(disk, 0);
+ nvme_revalidate_disk(ns->disk);
+ add_disk(ns->disk);
+ if (ns->ms)
+ revalidate_disk(ns->disk);
+ return;
out_free_queue:
blk_cleanup_queue(ns->queue);
out_free_ns:
kfree(ns);
- return NULL;
}
static void nvme_create_io_queues(struct nvme_dev *dev)
@@ -2100,22 +2313,20 @@ static int nvme_dev_add(struct nvme_dev *dev)
struct pci_dev *pdev = dev->pci_dev;
int res;
unsigned nn, i;
- struct nvme_ns *ns;
struct nvme_id_ctrl *ctrl;
- struct nvme_id_ns *id_ns;
void *mem;
dma_addr_t dma_addr;
int shift = NVME_CAP_MPSMIN(readq(&dev->bar->cap)) + 12;
- mem = dma_alloc_coherent(&pdev->dev, 8192, &dma_addr, GFP_KERNEL);
+ mem = dma_alloc_coherent(&pdev->dev, 4096, &dma_addr, GFP_KERNEL);
if (!mem)
return -ENOMEM;
res = nvme_identify(dev, 0, 1, dma_addr);
if (res) {
dev_err(&pdev->dev, "Identify Controller failed (%d)\n", res);
- res = -EIO;
- goto out;
+ dma_free_coherent(&dev->pci_dev->dev, 4096, mem, dma_addr);
+ return -EIO;
}
ctrl = mem;
@@ -2141,6 +2352,7 @@ static int nvme_dev_add(struct nvme_dev *dev)
} else
dev->max_hw_sectors = max_hw_sectors;
}
+ dma_free_coherent(&dev->pci_dev->dev, 4096, mem, dma_addr);
dev->tagset.ops = &nvme_mq_ops;
dev->tagset.nr_hw_queues = dev->online_queues - 1;
@@ -2148,38 +2360,17 @@ static int nvme_dev_add(struct nvme_dev *dev)
dev->tagset.numa_node = dev_to_node(&dev->pci_dev->dev);
dev->tagset.queue_depth =
min_t(int, dev->q_depth, BLK_MQ_MAX_DEPTH) - 1;
- dev->tagset.cmd_size = sizeof(struct nvme_cmd_info);
+ dev->tagset.cmd_size = nvme_cmd_size(dev);
dev->tagset.flags = BLK_MQ_F_SHOULD_MERGE;
dev->tagset.driver_data = dev;
if (blk_mq_alloc_tag_set(&dev->tagset))
- goto out;
-
- id_ns = mem;
- for (i = 1; i <= nn; i++) {
- res = nvme_identify(dev, i, 0, dma_addr);
- if (res)
- continue;
-
- if (id_ns->ncap == 0)
- continue;
-
- res = nvme_get_features(dev, NVME_FEAT_LBA_RANGE, i,
- dma_addr + 4096, NULL);
- if (res)
- memset(mem + 4096, 0, 4096);
+ return 0;
- ns = nvme_alloc_ns(dev, i, mem, mem + 4096);
- if (ns)
- list_add_tail(&ns->list, &dev->namespaces);
- }
- list_for_each_entry(ns, &dev->namespaces, list)
- add_disk(ns->disk);
- res = 0;
+ for (i = 1; i <= nn; i++)
+ nvme_alloc_ns(dev, i);
- out:
- dma_free_coherent(&dev->pci_dev->dev, 8192, mem, dma_addr);
- return res;
+ return 0;
}
static int nvme_dev_map(struct nvme_dev *dev)
@@ -2308,8 +2499,6 @@ static struct nvme_delq_ctx *nvme_get_dq(struct nvme_delq_ctx *dq)
static void nvme_del_queue_end(struct nvme_queue *nvmeq)
{
struct nvme_delq_ctx *dq = nvmeq->cmdinfo.ctx;
-
- nvme_clear_queue(nvmeq);
nvme_put_dq(dq);
}
@@ -2452,7 +2641,6 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
int i;
u32 csts = -1;
- dev->initialized = 0;
nvme_dev_list_remove(dev);
if (dev->bar) {
@@ -2463,7 +2651,6 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
for (i = dev->queue_count - 1; i >= 0; i--) {
struct nvme_queue *nvmeq = dev->queues[i];
nvme_suspend_queue(nvmeq);
- nvme_clear_queue(nvmeq);
}
} else {
nvme_disable_io_queues(dev);
@@ -2471,6 +2658,9 @@ static void nvme_dev_shutdown(struct nvme_dev *dev)
nvme_disable_queue(dev, 0);
}
nvme_dev_unmap(dev);
+
+ for (i = dev->queue_count - 1; i >= 0; i--)
+ nvme_clear_queue(dev->queues[i]);
}
static void nvme_dev_remove(struct nvme_dev *dev)
@@ -2478,8 +2668,11 @@ static void nvme_dev_remove(struct nvme_dev *dev)
struct nvme_ns *ns;
list_for_each_entry(ns, &dev->namespaces, list) {
- if (ns->disk->flags & GENHD_FL_UP)
+ if (ns->disk->flags & GENHD_FL_UP) {
+ if (blk_get_integrity(ns->disk))
+ blk_integrity_unregister(ns->disk);
del_gendisk(ns->disk);
+ }
if (!blk_queue_dying(ns->queue)) {
blk_mq_abort_requeue_list(ns->queue);
blk_cleanup_queue(ns->queue);
@@ -2561,6 +2754,7 @@ static void nvme_free_dev(struct kref *kref)
struct nvme_dev *dev = container_of(kref, struct nvme_dev, kref);
pci_dev_put(dev->pci_dev);
+ put_device(dev->device);
nvme_free_namespaces(dev);
nvme_release_instance(dev);
blk_mq_free_tag_set(&dev->tagset);
@@ -2572,11 +2766,27 @@ static void nvme_free_dev(struct kref *kref)
static int nvme_dev_open(struct inode *inode, struct file *f)
{
- struct nvme_dev *dev = container_of(f->private_data, struct nvme_dev,
- miscdev);
- kref_get(&dev->kref);
- f->private_data = dev;
- return 0;
+ struct nvme_dev *dev;
+ int instance = iminor(inode);
+ int ret = -ENODEV;
+
+ spin_lock(&dev_list_lock);
+ list_for_each_entry(dev, &dev_list, node) {
+ if (dev->instance == instance) {
+ if (!dev->admin_q) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
+ if (!kref_get_unless_zero(&dev->kref))
+ break;
+ f->private_data = dev;
+ ret = 0;
+ break;
+ }
+ }
+ spin_unlock(&dev_list_lock);
+
+ return ret;
}
static int nvme_dev_release(struct inode *inode, struct file *f)
@@ -2718,7 +2928,6 @@ static int nvme_dev_resume(struct nvme_dev *dev)
nvme_unfreeze_queues(dev);
nvme_set_irq_hints(dev);
}
- dev->initialized = 1;
return 0;
}
@@ -2749,6 +2958,7 @@ static void nvme_reset_workfn(struct work_struct *work)
dev->reset_workfn(work);
}
+static void nvme_async_probe(struct work_struct *work);
static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
int node, result = -ENOMEM;
@@ -2784,37 +2994,20 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto release;
kref_init(&dev->kref);
- result = nvme_dev_start(dev);
- if (result)
+ dev->device = device_create(nvme_class, &pdev->dev,
+ MKDEV(nvme_char_major, dev->instance),
+ dev, "nvme%d", dev->instance);
+ if (IS_ERR(dev->device)) {
+ result = PTR_ERR(dev->device);
goto release_pools;
+ }
+ get_device(dev->device);
- if (dev->online_queues > 1)
- result = nvme_dev_add(dev);
- if (result)
- goto shutdown;
-
- scnprintf(dev->name, sizeof(dev->name), "nvme%d", dev->instance);
- dev->miscdev.minor = MISC_DYNAMIC_MINOR;
- dev->miscdev.parent = &pdev->dev;
- dev->miscdev.name = dev->name;
- dev->miscdev.fops = &nvme_dev_fops;
- result = misc_register(&dev->miscdev);
- if (result)
- goto remove;
-
- nvme_set_irq_hints(dev);
-
- dev->initialized = 1;
+ INIT_WORK(&dev->probe_work, nvme_async_probe);
+ schedule_work(&dev->probe_work);
return 0;
- remove:
- nvme_dev_remove(dev);
- nvme_dev_remove_admin(dev);
- nvme_free_namespaces(dev);
- shutdown:
- nvme_dev_shutdown(dev);
release_pools:
- nvme_free_queues(dev, 0);
nvme_release_prp_pools(dev);
release:
nvme_release_instance(dev);
@@ -2827,6 +3020,29 @@ static int nvme_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return result;
}
+static void nvme_async_probe(struct work_struct *work)
+{
+ struct nvme_dev *dev = container_of(work, struct nvme_dev, probe_work);
+ int result;
+
+ result = nvme_dev_start(dev);
+ if (result)
+ goto reset;
+
+ if (dev->online_queues > 1)
+ result = nvme_dev_add(dev);
+ if (result)
+ goto reset;
+
+ nvme_set_irq_hints(dev);
+ return;
+ reset:
+ if (!work_busy(&dev->reset_work)) {
+ dev->reset_workfn = nvme_reset_failed_dev;
+ queue_work(nvme_workq, &dev->reset_work);
+ }
+}
+
static void nvme_reset_notify(struct pci_dev *pdev, bool prepare)
{
struct nvme_dev *dev = pci_get_drvdata(pdev);
@@ -2852,11 +3068,12 @@ static void nvme_remove(struct pci_dev *pdev)
spin_unlock(&dev_list_lock);
pci_set_drvdata(pdev, NULL);
+ flush_work(&dev->probe_work);
flush_work(&dev->reset_work);
- misc_deregister(&dev->miscdev);
nvme_dev_shutdown(dev);
nvme_dev_remove(dev);
nvme_dev_remove_admin(dev);
+ device_destroy(nvme_class, MKDEV(nvme_char_major, dev->instance));
nvme_free_queues(dev, 0);
nvme_release_prp_pools(dev);
kref_put(&dev->kref, nvme_free_dev);
@@ -2940,11 +3157,26 @@ static int __init nvme_init(void)
else if (result > 0)
nvme_major = result;
+ result = __register_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme",
+ &nvme_dev_fops);
+ if (result < 0)
+ goto unregister_blkdev;
+ else if (result > 0)
+ nvme_char_major = result;
+
+ nvme_class = class_create(THIS_MODULE, "nvme");
+ if (!nvme_class)
+ goto unregister_chrdev;
+
result = pci_register_driver(&nvme_driver);
if (result)
- goto unregister_blkdev;
+ goto destroy_class;
return 0;
+ destroy_class:
+ class_destroy(nvme_class);
+ unregister_chrdev:
+ __unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
unregister_blkdev:
unregister_blkdev(nvme_major, "nvme");
kill_workq:
@@ -2955,9 +3187,10 @@ static int __init nvme_init(void)
static void __exit nvme_exit(void)
{
pci_unregister_driver(&nvme_driver);
- unregister_hotcpu_notifier(&nvme_nb);
unregister_blkdev(nvme_major, "nvme");
destroy_workqueue(nvme_workq);
+ class_destroy(nvme_class);
+ __unregister_chrdev(nvme_char_major, 0, NVME_MINORS, "nvme");
BUG_ON(nvme_thread && !IS_ERR(nvme_thread));
_nvme_check_size();
}
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c
index 5e78568026c3..e10196e0182d 100644
--- a/drivers/block/nvme-scsi.c
+++ b/drivers/block/nvme-scsi.c
@@ -779,10 +779,8 @@ static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
struct nvme_dev *dev = ns->dev;
dma_addr_t dma_addr;
void *mem;
- struct nvme_id_ctrl *id_ctrl;
int res = SNTI_TRANSLATION_SUCCESS;
int nvme_sc;
- u8 ieee[4];
int xfer_len;
__be32 tmp_id = cpu_to_be32(ns->ns_id);
@@ -793,46 +791,60 @@ static int nvme_trans_device_id_page(struct nvme_ns *ns, struct sg_io_hdr *hdr,
goto out_dma;
}
- /* nvme controller identify */
- nvme_sc = nvme_identify(dev, 0, 1, dma_addr);
- res = nvme_trans_status_code(hdr, nvme_sc);
- if (res)
- goto out_free;
- if (nvme_sc) {
- res = nvme_sc;
- goto out_free;
- }
- id_ctrl = mem;
-
- /* Since SCSI tried to save 4 bits... [SPC-4(r34) Table 591] */
- ieee[0] = id_ctrl->ieee[0] << 4;
- ieee[1] = id_ctrl->ieee[0] >> 4 | id_ctrl->ieee[1] << 4;
- ieee[2] = id_ctrl->ieee[1] >> 4 | id_ctrl->ieee[2] << 4;
- ieee[3] = id_ctrl->ieee[2] >> 4;
-
- memset(inq_response, 0, STANDARD_INQUIRY_LENGTH);
+ memset(inq_response, 0, alloc_len);
inq_response[1] = INQ_DEVICE_IDENTIFICATION_PAGE; /* Page Code */
- inq_response[3] = 20; /* Page Length */
- /* Designation Descriptor start */
- inq_response[4] = 0x01; /* Proto ID=0h | Code set=1h */
- inq_response[5] = 0x03; /* PIV=0b | Asso=00b | Designator Type=3h */
- inq_response[6] = 0x00; /* Rsvd */
- inq_response[7] = 16; /* Designator Length */
- /* Designator start */
- inq_response[8] = 0x60 | ieee[3]; /* NAA=6h | IEEE ID MSB, High nibble*/
- inq_response[9] = ieee[2]; /* IEEE ID */
- inq_response[10] = ieee[1]; /* IEEE ID */
- inq_response[11] = ieee[0]; /* IEEE ID| Vendor Specific ID... */
- inq_response[12] = (dev->pci_dev->vendor & 0xFF00) >> 8;
- inq_response[13] = (dev->pci_dev->vendor & 0x00FF);
- inq_response[14] = dev->serial[0];
- inq_response[15] = dev->serial[1];
- inq_response[16] = dev->model[0];
- inq_response[17] = dev->model[1];
- memcpy(&inq_response[18], &tmp_id, sizeof(u32));
- /* Last 2 bytes are zero */
+ if (readl(&dev->bar->vs) >= NVME_VS(1, 1)) {
+ struct nvme_id_ns *id_ns = mem;
+ void *eui = id_ns->eui64;
+ int len = sizeof(id_ns->eui64);
- xfer_len = min(alloc_len, STANDARD_INQUIRY_LENGTH);
+ nvme_sc = nvme_identify(dev, ns->ns_id, 0, dma_addr);
+ res = nvme_trans_status_code(hdr, nvme_sc);
+ if (res)
+ goto out_free;
+ if (nvme_sc) {
+ res = nvme_sc;
+ goto out_free;
+ }
+
+ if (readl(&dev->bar->vs) >= NVME_VS(1, 2)) {
+ if (bitmap_empty(eui, len * 8)) {
+ eui = id_ns->nguid;
+ len = sizeof(id_ns->nguid);
+ }
+ }
+ if (bitmap_empty(eui, len * 8))
+ goto scsi_string;
+
+ inq_response[3] = 4 + len; /* Page Length */
+ /* Designation Descriptor start */
+ inq_response[4] = 0x01; /* Proto ID=0h | Code set=1h */
+ inq_response[5] = 0x02; /* PIV=0b | Asso=00b | Designator Type=2h */
+ inq_response[6] = 0x00; /* Rsvd */
+ inq_response[7] = len; /* Designator Length */
+ memcpy(&inq_response[8], eui, len);
+ } else {
+ scsi_string:
+ if (alloc_len < 72) {
+ res = nvme_trans_completion(hdr,
+ SAM_STAT_CHECK_CONDITION,
+ ILLEGAL_REQUEST, SCSI_ASC_INVALID_CDB,
+ SCSI_ASCQ_CAUSE_NOT_REPORTABLE);
+ goto out_free;
+ }
+ inq_response[3] = 0x48; /* Page Length */
+ /* Designation Descriptor start */
+ inq_response[4] = 0x03; /* Proto ID=0h | Code set=3h */
+ inq_response[5] = 0x08; /* PIV=0b | Asso=00b | Designator Type=8h */
+ inq_response[6] = 0x00; /* Rsvd */
+ inq_response[7] = 0x44; /* Designator Length */
+
+ sprintf(&inq_response[8], "%04x", dev->pci_dev->vendor);
+ memcpy(&inq_response[12], dev->model, sizeof(dev->model));
+ sprintf(&inq_response[52], "%04x", tmp_id);
+ memcpy(&inq_response[56], dev->serial, sizeof(dev->serial));
+ }
+ xfer_len = alloc_len;
res = nvme_trans_copy_to_user(hdr, inq_response, xfer_len);
out_free:
@@ -1600,7 +1612,7 @@ static inline void nvme_trans_modesel_get_bd_len(u8 *parm_list, u8 cdb10,
/* 10 Byte CDB */
*bd_len = (parm_list[MODE_SELECT_10_BD_OFFSET] << 8) +
parm_list[MODE_SELECT_10_BD_OFFSET + 1];
- *llbaa = parm_list[MODE_SELECT_10_LLBAA_OFFSET] &&
+ *llbaa = parm_list[MODE_SELECT_10_LLBAA_OFFSET] &
MODE_SELECT_10_LLBAA_MASK;
} else {
/* 6 Byte CDB */
@@ -2222,7 +2234,7 @@ static int nvme_trans_inquiry(struct nvme_ns *ns, struct sg_io_hdr *hdr,
page_code = GET_INQ_PAGE_CODE(cmd);
alloc_len = GET_INQ_ALLOC_LENGTH(cmd);
- inq_response = kmalloc(STANDARD_INQUIRY_LENGTH, GFP_KERNEL);
+ inq_response = kmalloc(alloc_len, GFP_KERNEL);
if (inq_response == NULL) {
res = -ENOMEM;
goto out_mem;
diff --git a/drivers/block/osdblk.c b/drivers/block/osdblk.c
index 79aa179305b5..e22942596207 100644
--- a/drivers/block/osdblk.c
+++ b/drivers/block/osdblk.c
@@ -423,7 +423,7 @@ static int osdblk_init_disk(struct osdblk_device *osdev)
}
/* switch queue to TCQ mode; allocate tag map */
- rc = blk_queue_init_tags(q, OSDBLK_MAX_REQ, NULL);
+ rc = blk_queue_init_tags(q, OSDBLK_MAX_REQ, NULL, BLK_TAG_ALLOC_FIFO);
if (rc) {
blk_cleanup_queue(q);
put_disk(disk);
diff --git a/drivers/block/rbd.c b/drivers/block/rbd.c
index 3ec85dfce124..b40af3203089 100644
--- a/drivers/block/rbd.c
+++ b/drivers/block/rbd.c
@@ -38,6 +38,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/module.h>
+#include <linux/blk-mq.h>
#include <linux/fs.h>
#include <linux/blkdev.h>
#include <linux/slab.h>
@@ -340,9 +341,7 @@ struct rbd_device {
char name[DEV_NAME_LEN]; /* blkdev name, e.g. rbd3 */
- struct list_head rq_queue; /* incoming rq queue */
spinlock_t lock; /* queue, flags, open_count */
- struct work_struct rq_work;
struct rbd_image_header header;
unsigned long flags; /* possibly lock protected */
@@ -360,6 +359,9 @@ struct rbd_device {
atomic_t parent_ref;
struct rbd_device *parent;
+ /* Block layer tags. */
+ struct blk_mq_tag_set tag_set;
+
/* protects updating the header */
struct rw_semaphore header_rwsem;
@@ -1817,7 +1819,8 @@ static void rbd_osd_req_callback(struct ceph_osd_request *osd_req,
/*
* We support a 64-bit length, but ultimately it has to be
- * passed to blk_end_request(), which takes an unsigned int.
+ * passed to the block layer, which just supports a 32-bit
+ * length field.
*/
obj_request->xferred = osd_req->r_reply_op_len[0];
rbd_assert(obj_request->xferred < (u64)UINT_MAX);
@@ -2098,32 +2101,26 @@ static void rbd_dev_parent_put(struct rbd_device *rbd_dev)
* If an image has a non-zero parent overlap, get a reference to its
* parent.
*
- * We must get the reference before checking for the overlap to
- * coordinate properly with zeroing the parent overlap in
- * rbd_dev_v2_parent_info() when an image gets flattened. We
- * drop it again if there is no overlap.
- *
* Returns true if the rbd device has a parent with a non-zero
* overlap and a reference for it was successfully taken, or
* false otherwise.
*/
static bool rbd_dev_parent_get(struct rbd_device *rbd_dev)
{
- int counter;
+ int counter = 0;
if (!rbd_dev->parent_spec)
return false;
- counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
- if (counter > 0 && rbd_dev->parent_overlap)
- return true;
-
- /* Image was flattened, but parent is not yet torn down */
+ down_read(&rbd_dev->header_rwsem);
+ if (rbd_dev->parent_overlap)
+ counter = atomic_inc_return_safe(&rbd_dev->parent_ref);
+ up_read(&rbd_dev->header_rwsem);
if (counter < 0)
rbd_warn(rbd_dev, "parent reference overflow");
- return false;
+ return counter > 0;
}
/*
@@ -2281,7 +2278,10 @@ static bool rbd_img_obj_end_request(struct rbd_obj_request *obj_request)
more = obj_request->which < img_request->obj_request_count - 1;
} else {
rbd_assert(img_request->rq != NULL);
- more = blk_end_request(img_request->rq, result, xferred);
+
+ more = blk_update_request(img_request->rq, result, xferred);
+ if (!more)
+ __blk_mq_end_request(img_request->rq, result);
}
return more;
@@ -3310,8 +3310,10 @@ out:
return ret;
}
-static void rbd_handle_request(struct rbd_device *rbd_dev, struct request *rq)
+static void rbd_queue_workfn(struct work_struct *work)
{
+ struct request *rq = blk_mq_rq_from_pdu(work);
+ struct rbd_device *rbd_dev = rq->q->queuedata;
struct rbd_img_request *img_request;
struct ceph_snap_context *snapc = NULL;
u64 offset = (u64)blk_rq_pos(rq) << SECTOR_SHIFT;
@@ -3320,6 +3322,13 @@ static void rbd_handle_request(struct rbd_device *rbd_dev, struct request *rq)
u64 mapping_size;
int result;
+ if (rq->cmd_type != REQ_TYPE_FS) {
+ dout("%s: non-fs request type %d\n", __func__,
+ (int) rq->cmd_type);
+ result = -EIO;
+ goto err;
+ }
+
if (rq->cmd_flags & REQ_DISCARD)
op_type = OBJ_OP_DISCARD;
else if (rq->cmd_flags & REQ_WRITE)
@@ -3365,6 +3374,8 @@ static void rbd_handle_request(struct rbd_device *rbd_dev, struct request *rq)
goto err_rq; /* Shouldn't happen */
}
+ blk_mq_start_request(rq);
+
down_read(&rbd_dev->header_rwsem);
mapping_size = rbd_dev->mapping.size;
if (op_type != OBJ_OP_READ) {
@@ -3410,53 +3421,18 @@ err_rq:
rbd_warn(rbd_dev, "%s %llx at %llx result %d",
obj_op_name(op_type), length, offset, result);
ceph_put_snap_context(snapc);
- blk_end_request_all(rq, result);
+err:
+ blk_mq_end_request(rq, result);
}
-static void rbd_request_workfn(struct work_struct *work)
+static int rbd_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
{
- struct rbd_device *rbd_dev =
- container_of(work, struct rbd_device, rq_work);
- struct request *rq, *next;
- LIST_HEAD(requests);
+ struct request *rq = bd->rq;
+ struct work_struct *work = blk_mq_rq_to_pdu(rq);
- spin_lock_irq(&rbd_dev->lock); /* rq->q->queue_lock */
- list_splice_init(&rbd_dev->rq_queue, &requests);
- spin_unlock_irq(&rbd_dev->lock);
-
- list_for_each_entry_safe(rq, next, &requests, queuelist) {
- list_del_init(&rq->queuelist);
- rbd_handle_request(rbd_dev, rq);
- }
-}
-
-/*
- * Called with q->queue_lock held and interrupts disabled, possibly on
- * the way to schedule(). Do not sleep here!
- */
-static void rbd_request_fn(struct request_queue *q)
-{
- struct rbd_device *rbd_dev = q->queuedata;
- struct request *rq;
- int queued = 0;
-
- rbd_assert(rbd_dev);
-
- while ((rq = blk_fetch_request(q))) {
- /* Ignore any non-FS requests that filter through. */
- if (rq->cmd_type != REQ_TYPE_FS) {
- dout("%s: non-fs request type %d\n", __func__,
- (int) rq->cmd_type);
- __blk_end_request_all(rq, 0);
- continue;
- }
-
- list_add_tail(&rq->queuelist, &rbd_dev->rq_queue);
- queued++;
- }
-
- if (queued)
- queue_work(rbd_wq, &rbd_dev->rq_work);
+ queue_work(rbd_wq, work);
+ return BLK_MQ_RQ_QUEUE_OK;
}
/*
@@ -3517,6 +3493,7 @@ static void rbd_free_disk(struct rbd_device *rbd_dev)
del_gendisk(disk);
if (disk->queue)
blk_cleanup_queue(disk->queue);
+ blk_mq_free_tag_set(&rbd_dev->tag_set);
}
put_disk(disk);
}
@@ -3700,7 +3677,7 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
ret = rbd_dev_header_info(rbd_dev);
if (ret)
- return ret;
+ goto out;
/*
* If there is a parent, see if it has disappeared due to the
@@ -3709,30 +3686,46 @@ static int rbd_dev_refresh(struct rbd_device *rbd_dev)
if (rbd_dev->parent) {
ret = rbd_dev_v2_parent_info(rbd_dev);
if (ret)
- return ret;
+ goto out;
}
if (rbd_dev->spec->snap_id == CEPH_NOSNAP) {
- if (rbd_dev->mapping.size != rbd_dev->header.image_size)
- rbd_dev->mapping.size = rbd_dev->header.image_size;
+ rbd_dev->mapping.size = rbd_dev->header.image_size;
} else {
/* validate mapped snapshot's EXISTS flag */
rbd_exists_validate(rbd_dev);
}
+out:
up_write(&rbd_dev->header_rwsem);
-
- if (mapping_size != rbd_dev->mapping.size)
+ if (!ret && mapping_size != rbd_dev->mapping.size)
rbd_dev_update_size(rbd_dev);
+ return ret;
+}
+
+static int rbd_init_request(void *data, struct request *rq,
+ unsigned int hctx_idx, unsigned int request_idx,
+ unsigned int numa_node)
+{
+ struct work_struct *work = blk_mq_rq_to_pdu(rq);
+
+ INIT_WORK(work, rbd_queue_workfn);
return 0;
}
+static struct blk_mq_ops rbd_mq_ops = {
+ .queue_rq = rbd_queue_rq,
+ .map_queue = blk_mq_map_queue,
+ .init_request = rbd_init_request,
+};
+
static int rbd_init_disk(struct rbd_device *rbd_dev)
{
struct gendisk *disk;
struct request_queue *q;
u64 segment_size;
+ int err;
/* create gendisk info */
disk = alloc_disk(single_major ?
@@ -3750,10 +3743,25 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
disk->fops = &rbd_bd_ops;
disk->private_data = rbd_dev;
- q = blk_init_queue(rbd_request_fn, &rbd_dev->lock);
- if (!q)
+ memset(&rbd_dev->tag_set, 0, sizeof(rbd_dev->tag_set));
+ rbd_dev->tag_set.ops = &rbd_mq_ops;
+ rbd_dev->tag_set.queue_depth = BLKDEV_MAX_RQ;
+ rbd_dev->tag_set.numa_node = NUMA_NO_NODE;
+ rbd_dev->tag_set.flags =
+ BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
+ rbd_dev->tag_set.nr_hw_queues = 1;
+ rbd_dev->tag_set.cmd_size = sizeof(struct work_struct);
+
+ err = blk_mq_alloc_tag_set(&rbd_dev->tag_set);
+ if (err)
goto out_disk;
+ q = blk_mq_init_queue(&rbd_dev->tag_set);
+ if (IS_ERR(q)) {
+ err = PTR_ERR(q);
+ goto out_tag_set;
+ }
+
/* We use the default size, but let's be explicit about it. */
blk_queue_physical_block_size(q, SECTOR_SIZE);
@@ -3779,10 +3787,11 @@ static int rbd_init_disk(struct rbd_device *rbd_dev)
rbd_dev->disk = disk;
return 0;
+out_tag_set:
+ blk_mq_free_tag_set(&rbd_dev->tag_set);
out_disk:
put_disk(disk);
-
- return -ENOMEM;
+ return err;
}
/*
@@ -4039,8 +4048,6 @@ static struct rbd_device *rbd_dev_create(struct rbd_client *rbdc,
return NULL;
spin_lock_init(&rbd_dev->lock);
- INIT_LIST_HEAD(&rbd_dev->rq_queue);
- INIT_WORK(&rbd_dev->rq_work, rbd_request_workfn);
rbd_dev->flags = 0;
atomic_set(&rbd_dev->parent_ref, 0);
INIT_LIST_HEAD(&rbd_dev->node);
@@ -4239,7 +4246,6 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
*/
if (rbd_dev->parent_overlap) {
rbd_dev->parent_overlap = 0;
- smp_mb();
rbd_dev_parent_put(rbd_dev);
pr_info("%s: clone image has been flattened\n",
rbd_dev->disk->disk_name);
@@ -4281,33 +4287,22 @@ static int rbd_dev_v2_parent_info(struct rbd_device *rbd_dev)
}
/*
- * We always update the parent overlap. If it's zero we
- * treat it specially.
+ * We always update the parent overlap. If it's zero we issue
+ * a warning, as we will proceed as if there was no parent.
*/
- rbd_dev->parent_overlap = overlap;
- smp_mb();
if (!overlap) {
-
- /* A null parent_spec indicates it's the initial probe */
-
if (parent_spec) {
- /*
- * The overlap has become zero, so the clone
- * must have been resized down to 0 at some
- * point. Treat this the same as a flatten.
- */
- rbd_dev_parent_put(rbd_dev);
- pr_info("%s: clone image now standalone\n",
- rbd_dev->disk->disk_name);
+ /* refresh, careful to warn just once */
+ if (rbd_dev->parent_overlap)
+ rbd_warn(rbd_dev,
+ "clone now standalone (overlap became 0)");
} else {
- /*
- * For the initial probe, if we find the
- * overlap is zero we just pretend there was
- * no parent image.
- */
- rbd_warn(rbd_dev, "ignoring parent with overlap 0");
+ /* initial probe */
+ rbd_warn(rbd_dev, "clone is standalone (overlap 0)");
}
}
+ rbd_dev->parent_overlap = overlap;
+
out:
ret = 0;
out_err:
@@ -4779,36 +4774,6 @@ static inline size_t next_token(const char **buf)
}
/*
- * Finds the next token in *buf, and if the provided token buffer is
- * big enough, copies the found token into it. The result, if
- * copied, is guaranteed to be terminated with '\0'. Note that *buf
- * must be terminated with '\0' on entry.
- *
- * Returns the length of the token found (not including the '\0').
- * Return value will be 0 if no token is found, and it will be >=
- * token_size if the token would not fit.
- *
- * The *buf pointer will be updated to point beyond the end of the
- * found token. Note that this occurs even if the token buffer is
- * too small to hold it.
- */
-static inline size_t copy_token(const char **buf,
- char *token,
- size_t token_size)
-{
- size_t len;
-
- len = next_token(buf);
- if (len < token_size) {
- memcpy(token, *buf, len);
- *(token + len) = '\0';
- }
- *buf += len;
-
- return len;
-}
-
-/*
* Finds the next token in *buf, dynamically allocates a buffer big
* enough to hold a copy of it, and copies the token into the new
* buffer. The copy is guaranteed to be terminated with '\0'. Note
@@ -5114,10 +5079,7 @@ static void rbd_dev_unprobe(struct rbd_device *rbd_dev)
{
struct rbd_image_header *header;
- /* Drop parent reference unless it's already been done (or none) */
-
- if (rbd_dev->parent_overlap)
- rbd_dev_parent_put(rbd_dev);
+ rbd_dev_parent_put(rbd_dev);
/* Free dynamic fields from the header, then zero it out */
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index cdfbd21e3597..655e570b9b31 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -28,8 +28,7 @@ struct virtio_blk_vq {
char name[VQ_NAME_LEN];
} ____cacheline_aligned_in_smp;
-struct virtio_blk
-{
+struct virtio_blk {
struct virtio_device *vdev;
/* The disk structure for the kernel. */
@@ -52,8 +51,7 @@ struct virtio_blk
struct virtio_blk_vq *vqs;
};
-struct virtblk_req
-{
+struct virtblk_req {
struct request *req;
struct virtio_blk_outhdr out_hdr;
struct virtio_scsi_inhdr in_hdr;
@@ -575,6 +573,12 @@ static int virtblk_probe(struct virtio_device *vdev)
u16 min_io_size;
u8 physical_block_exp, alignment_offset;
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
err = ida_simple_get(&vd_index_ida, 0, minor_to_index(1 << MINORBITS),
GFP_KERNEL);
if (err < 0)
diff --git a/drivers/block/xen-blkback/blkback.c b/drivers/block/xen-blkback/blkback.c
index 63fc7f06a014..2a04d341e598 100644
--- a/drivers/block/xen-blkback/blkback.c
+++ b/drivers/block/xen-blkback/blkback.c
@@ -47,6 +47,7 @@
#include <asm/xen/hypervisor.h>
#include <asm/xen/hypercall.h>
#include <xen/balloon.h>
+#include <xen/grant_table.h>
#include "common.h"
/*
@@ -100,7 +101,7 @@ module_param(log_stats, int, 0644);
#define BLKBACK_INVALID_HANDLE (~0)
-/* Number of free pages to remove on each call to free_xenballooned_pages */
+/* Number of free pages to remove on each call to gnttab_free_pages */
#define NUM_BATCH_FREE_PAGES 10
static inline int get_free_page(struct xen_blkif *blkif, struct page **page)
@@ -111,7 +112,7 @@ static inline int get_free_page(struct xen_blkif *blkif, struct page **page)
if (list_empty(&blkif->free_pages)) {
BUG_ON(blkif->free_pages_num != 0);
spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
- return alloc_xenballooned_pages(1, page, false);
+ return gnttab_alloc_pages(1, page);
}
BUG_ON(blkif->free_pages_num == 0);
page[0] = list_first_entry(&blkif->free_pages, struct page, lru);
@@ -151,14 +152,14 @@ static inline void shrink_free_pagepool(struct xen_blkif *blkif, int num)
blkif->free_pages_num--;
if (++num_pages == NUM_BATCH_FREE_PAGES) {
spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
- free_xenballooned_pages(num_pages, page);
+ gnttab_free_pages(num_pages, page);
spin_lock_irqsave(&blkif->free_pages_lock, flags);
num_pages = 0;
}
}
spin_unlock_irqrestore(&blkif->free_pages_lock, flags);
if (num_pages != 0)
- free_xenballooned_pages(num_pages, page);
+ gnttab_free_pages(num_pages, page);
}
#define vaddr(page) ((unsigned long)pfn_to_kaddr(page_to_pfn(page)))
@@ -262,6 +263,17 @@ static void put_persistent_gnt(struct xen_blkif *blkif,
atomic_dec(&blkif->persistent_gnt_in_use);
}
+static void free_persistent_gnts_unmap_callback(int result,
+ struct gntab_unmap_queue_data *data)
+{
+ struct completion *c = data->data;
+
+ /* BUG_ON used to reproduce existing behaviour,
+ but is this the best way to deal with this? */
+ BUG_ON(result);
+ complete(c);
+}
+
static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
unsigned int num)
{
@@ -269,8 +281,17 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
struct page *pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
struct persistent_gnt *persistent_gnt;
struct rb_node *n;
- int ret = 0;
int segs_to_unmap = 0;
+ struct gntab_unmap_queue_data unmap_data;
+ struct completion unmap_completion;
+
+ init_completion(&unmap_completion);
+
+ unmap_data.data = &unmap_completion;
+ unmap_data.done = &free_persistent_gnts_unmap_callback;
+ unmap_data.pages = pages;
+ unmap_data.unmap_ops = unmap;
+ unmap_data.kunmap_ops = NULL;
foreach_grant_safe(persistent_gnt, n, root, node) {
BUG_ON(persistent_gnt->handle ==
@@ -285,9 +306,11 @@ static void free_persistent_gnts(struct xen_blkif *blkif, struct rb_root *root,
if (++segs_to_unmap == BLKIF_MAX_SEGMENTS_PER_REQUEST ||
!rb_next(&persistent_gnt->node)) {
- ret = gnttab_unmap_refs(unmap, NULL, pages,
- segs_to_unmap);
- BUG_ON(ret);
+
+ unmap_data.count = segs_to_unmap;
+ gnttab_unmap_refs_async(&unmap_data);
+ wait_for_completion(&unmap_completion);
+
put_free_pages(blkif, pages, segs_to_unmap);
segs_to_unmap = 0;
}
@@ -653,18 +676,14 @@ void xen_blkbk_free_caches(struct xen_blkif *blkif)
shrink_free_pagepool(blkif, 0 /* All */);
}
-/*
- * Unmap the grant references, and also remove the M2P over-rides
- * used in the 'pending_req'.
- */
-static void xen_blkbk_unmap(struct xen_blkif *blkif,
- struct grant_page *pages[],
- int num)
+static unsigned int xen_blkbk_unmap_prepare(
+ struct xen_blkif *blkif,
+ struct grant_page **pages,
+ unsigned int num,
+ struct gnttab_unmap_grant_ref *unmap_ops,
+ struct page **unmap_pages)
{
- struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
- struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
unsigned int i, invcount = 0;
- int ret;
for (i = 0; i < num; i++) {
if (pages[i]->persistent_gnt != NULL) {
@@ -674,21 +693,95 @@ static void xen_blkbk_unmap(struct xen_blkif *blkif,
if (pages[i]->handle == BLKBACK_INVALID_HANDLE)
continue;
unmap_pages[invcount] = pages[i]->page;
- gnttab_set_unmap_op(&unmap[invcount], vaddr(pages[i]->page),
+ gnttab_set_unmap_op(&unmap_ops[invcount], vaddr(pages[i]->page),
GNTMAP_host_map, pages[i]->handle);
pages[i]->handle = BLKBACK_INVALID_HANDLE;
- if (++invcount == BLKIF_MAX_SEGMENTS_PER_REQUEST) {
- ret = gnttab_unmap_refs(unmap, NULL, unmap_pages,
- invcount);
+ invcount++;
+ }
+
+ return invcount;
+}
+
+static void xen_blkbk_unmap_and_respond_callback(int result, struct gntab_unmap_queue_data *data)
+{
+ struct pending_req* pending_req = (struct pending_req*) (data->data);
+ struct xen_blkif *blkif = pending_req->blkif;
+
+ /* BUG_ON used to reproduce existing behaviour,
+ but is this the best way to deal with this? */
+ BUG_ON(result);
+
+ put_free_pages(blkif, data->pages, data->count);
+ make_response(blkif, pending_req->id,
+ pending_req->operation, pending_req->status);
+ free_req(blkif, pending_req);
+ /*
+ * Make sure the request is freed before releasing blkif,
+ * or there could be a race between free_req and the
+ * cleanup done in xen_blkif_free during shutdown.
+ *
+ * NB: The fact that we might try to wake up pending_free_wq
+ * before drain_complete (in case there's a drain going on)
+ * it's not a problem with our current implementation
+ * because we can assure there's no thread waiting on
+ * pending_free_wq if there's a drain going on, but it has
+ * to be taken into account if the current model is changed.
+ */
+ if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) {
+ complete(&blkif->drain_complete);
+ }
+ xen_blkif_put(blkif);
+}
+
+static void xen_blkbk_unmap_and_respond(struct pending_req *req)
+{
+ struct gntab_unmap_queue_data* work = &req->gnttab_unmap_data;
+ struct xen_blkif *blkif = req->blkif;
+ struct grant_page **pages = req->segments;
+ unsigned int invcount;
+
+ invcount = xen_blkbk_unmap_prepare(blkif, pages, req->nr_pages,
+ req->unmap, req->unmap_pages);
+
+ work->data = req;
+ work->done = xen_blkbk_unmap_and_respond_callback;
+ work->unmap_ops = req->unmap;
+ work->kunmap_ops = NULL;
+ work->pages = req->unmap_pages;
+ work->count = invcount;
+
+ gnttab_unmap_refs_async(&req->gnttab_unmap_data);
+}
+
+
+/*
+ * Unmap the grant references.
+ *
+ * This could accumulate ops up to the batch size to reduce the number
+ * of hypercalls, but since this is only used in error paths there's
+ * no real need.
+ */
+static void xen_blkbk_unmap(struct xen_blkif *blkif,
+ struct grant_page *pages[],
+ int num)
+{
+ struct gnttab_unmap_grant_ref unmap[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ struct page *unmap_pages[BLKIF_MAX_SEGMENTS_PER_REQUEST];
+ unsigned int invcount = 0;
+ int ret;
+
+ while (num) {
+ unsigned int batch = min(num, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+ invcount = xen_blkbk_unmap_prepare(blkif, pages, batch,
+ unmap, unmap_pages);
+ if (invcount) {
+ ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount);
BUG_ON(ret);
put_free_pages(blkif, unmap_pages, invcount);
- invcount = 0;
}
- }
- if (invcount) {
- ret = gnttab_unmap_refs(unmap, NULL, unmap_pages, invcount);
- BUG_ON(ret);
- put_free_pages(blkif, unmap_pages, invcount);
+ pages += batch;
+ num -= batch;
}
}
@@ -982,32 +1075,8 @@ static void __end_block_io_op(struct pending_req *pending_req, int error)
* the grant references associated with 'request' and provide
* the proper response on the ring.
*/
- if (atomic_dec_and_test(&pending_req->pendcnt)) {
- struct xen_blkif *blkif = pending_req->blkif;
-
- xen_blkbk_unmap(blkif,
- pending_req->segments,
- pending_req->nr_pages);
- make_response(blkif, pending_req->id,
- pending_req->operation, pending_req->status);
- free_req(blkif, pending_req);
- /*
- * Make sure the request is freed before releasing blkif,
- * or there could be a race between free_req and the
- * cleanup done in xen_blkif_free during shutdown.
- *
- * NB: The fact that we might try to wake up pending_free_wq
- * before drain_complete (in case there's a drain going on)
- * it's not a problem with our current implementation
- * because we can assure there's no thread waiting on
- * pending_free_wq if there's a drain going on, but it has
- * to be taken into account if the current model is changed.
- */
- if (atomic_dec_and_test(&blkif->inflight) && atomic_read(&blkif->drain)) {
- complete(&blkif->drain_complete);
- }
- xen_blkif_put(blkif);
- }
+ if (atomic_dec_and_test(&pending_req->pendcnt))
+ xen_blkbk_unmap_and_respond(pending_req);
}
/*
diff --git a/drivers/block/xen-blkback/common.h b/drivers/block/xen-blkback/common.h
index f65b807e3236..375d28851860 100644
--- a/drivers/block/xen-blkback/common.h
+++ b/drivers/block/xen-blkback/common.h
@@ -214,6 +214,15 @@ enum blkif_protocol {
BLKIF_PROTOCOL_X86_64 = 3,
};
+/*
+ * Default protocol if the frontend doesn't specify one.
+ */
+#ifdef CONFIG_X86
+# define BLKIF_PROTOCOL_DEFAULT BLKIF_PROTOCOL_X86_32
+#else
+# define BLKIF_PROTOCOL_DEFAULT BLKIF_PROTOCOL_NATIVE
+#endif
+
struct xen_vbd {
/* What the domain refers to this vbd as. */
blkif_vdev_t handle;
@@ -350,6 +359,9 @@ struct pending_req {
struct grant_page *indirect_pages[MAX_INDIRECT_PAGES];
struct seg_buf seg[MAX_INDIRECT_SEGMENTS];
struct bio *biolist[MAX_INDIRECT_SEGMENTS];
+ struct gnttab_unmap_grant_ref unmap[MAX_INDIRECT_SEGMENTS];
+ struct page *unmap_pages[MAX_INDIRECT_SEGMENTS];
+ struct gntab_unmap_queue_data gnttab_unmap_data;
};
diff --git a/drivers/block/xen-blkback/xenbus.c b/drivers/block/xen-blkback/xenbus.c
index 630a489e757d..e3afe97280b1 100644
--- a/drivers/block/xen-blkback/xenbus.c
+++ b/drivers/block/xen-blkback/xenbus.c
@@ -868,11 +868,11 @@ static int connect_ring(struct backend_info *be)
return err;
}
- be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
+ be->blkif->blk_protocol = BLKIF_PROTOCOL_DEFAULT;
err = xenbus_gather(XBT_NIL, dev->otherend, "protocol",
"%63s", protocol, NULL);
if (err)
- strcpy(protocol, "unspecified, assuming native");
+ strcpy(protocol, "unspecified, assuming default");
else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_NATIVE))
be->blkif->blk_protocol = BLKIF_PROTOCOL_NATIVE;
else if (0 == strcmp(protocol, XEN_IO_PROTO_ABI_X86_32))
diff --git a/drivers/block/xen-blkfront.c b/drivers/block/xen-blkfront.c
index 2236c6f31608..37779e4c4585 100644
--- a/drivers/block/xen-blkfront.c
+++ b/drivers/block/xen-blkfront.c
@@ -1391,7 +1391,7 @@ static int blkfront_probe(struct xenbus_device *dev,
if (major != XENVBD_MAJOR) {
printk(KERN_INFO
"%s: HVM does not support vbd %d as xen block device\n",
- __FUNCTION__, vdevice);
+ __func__, vdevice);
return -ENODEV;
}
}
@@ -1511,7 +1511,7 @@ static int blkif_recover(struct blkfront_info *info)
merge_bio.tail = copy[i].request->biotail;
bio_list_merge(&bio_list, &merge_bio);
copy[i].request->bio = NULL;
- blk_put_request(copy[i].request);
+ blk_end_request_all(copy[i].request, 0);
}
kfree(copy);
@@ -1534,7 +1534,7 @@ static int blkif_recover(struct blkfront_info *info)
req->bio = NULL;
if (req->cmd_flags & (REQ_FLUSH | REQ_FUA))
pr_alert("diskcache flush request found!\n");
- __blk_put_request(info->rq, req);
+ __blk_end_request_all(req, 0);
}
spin_unlock_irq(&info->io_lock);
diff --git a/drivers/block/zram/zram_drv.c b/drivers/block/zram/zram_drv.c
index bd8bda386e02..871bd3550cb0 100644
--- a/drivers/block/zram/zram_drv.c
+++ b/drivers/block/zram/zram_drv.c
@@ -53,9 +53,9 @@ static ssize_t name##_show(struct device *d, \
} \
static DEVICE_ATTR_RO(name);
-static inline int init_done(struct zram *zram)
+static inline bool init_done(struct zram *zram)
{
- return zram->meta != NULL;
+ return zram->disksize;
}
static inline struct zram *dev_to_zram(struct device *dev)
@@ -307,42 +307,67 @@ static inline int valid_io_request(struct zram *zram,
return 1;
}
-static void zram_meta_free(struct zram_meta *meta)
+static void zram_meta_free(struct zram_meta *meta, u64 disksize)
{
+ size_t num_pages = disksize >> PAGE_SHIFT;
+ size_t index;
+
+ /* Free all pages that are still in this zram device */
+ for (index = 0; index < num_pages; index++) {
+ unsigned long handle = meta->table[index].handle;
+
+ if (!handle)
+ continue;
+
+ zs_free(meta->mem_pool, handle);
+ }
+
zs_destroy_pool(meta->mem_pool);
vfree(meta->table);
kfree(meta);
}
-static struct zram_meta *zram_meta_alloc(u64 disksize)
+static struct zram_meta *zram_meta_alloc(int device_id, u64 disksize)
{
size_t num_pages;
+ char pool_name[8];
struct zram_meta *meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+
if (!meta)
- goto out;
+ return NULL;
num_pages = disksize >> PAGE_SHIFT;
meta->table = vzalloc(num_pages * sizeof(*meta->table));
if (!meta->table) {
pr_err("Error allocating zram address table\n");
- goto free_meta;
+ goto out_error;
}
- meta->mem_pool = zs_create_pool(GFP_NOIO | __GFP_HIGHMEM);
+ snprintf(pool_name, sizeof(pool_name), "zram%d", device_id);
+ meta->mem_pool = zs_create_pool(pool_name, GFP_NOIO | __GFP_HIGHMEM);
if (!meta->mem_pool) {
pr_err("Error creating memory pool\n");
- goto free_table;
+ goto out_error;
}
return meta;
-free_table:
+out_error:
vfree(meta->table);
-free_meta:
kfree(meta);
- meta = NULL;
-out:
- return meta;
+ return NULL;
+}
+
+static inline bool zram_meta_get(struct zram *zram)
+{
+ if (atomic_inc_not_zero(&zram->refcount))
+ return true;
+ return false;
+}
+
+static inline void zram_meta_put(struct zram *zram)
+{
+ atomic_dec(&zram->refcount);
}
static void update_position(u32 *index, int *offset, struct bio_vec *bvec)
@@ -503,7 +528,7 @@ out_cleanup:
static inline void update_used_max(struct zram *zram,
const unsigned long pages)
{
- int old_max, cur_max;
+ unsigned long old_max, cur_max;
old_max = atomic_long_read(&zram->stats.max_used_pages);
@@ -704,10 +729,11 @@ static void zram_bio_discard(struct zram *zram, u32 index,
}
}
-static void zram_reset_device(struct zram *zram, bool reset_capacity)
+static void zram_reset_device(struct zram *zram)
{
- size_t index;
struct zram_meta *meta;
+ struct zcomp *comp;
+ u64 disksize;
down_write(&zram->init_lock);
@@ -719,36 +745,30 @@ static void zram_reset_device(struct zram *zram, bool reset_capacity)
}
meta = zram->meta;
- /* Free all pages that are still in this zram device */
- for (index = 0; index < zram->disksize >> PAGE_SHIFT; index++) {
- unsigned long handle = meta->table[index].handle;
- if (!handle)
- continue;
-
- zs_free(meta->mem_pool, handle);
- }
-
- zcomp_destroy(zram->comp);
- zram->max_comp_streams = 1;
+ comp = zram->comp;
+ disksize = zram->disksize;
+ /*
+ * Refcount will go down to 0 eventually and r/w handler
+ * cannot handle further I/O so it will bail out by
+ * check zram_meta_get.
+ */
+ zram_meta_put(zram);
+ /*
+ * We want to free zram_meta in process context to avoid
+ * deadlock between reclaim path and any other locks.
+ */
+ wait_event(zram->io_done, atomic_read(&zram->refcount) == 0);
- zram_meta_free(zram->meta);
- zram->meta = NULL;
/* Reset stats */
memset(&zram->stats, 0, sizeof(zram->stats));
-
zram->disksize = 0;
- if (reset_capacity)
- set_capacity(zram->disk, 0);
+ zram->max_comp_streams = 1;
+ set_capacity(zram->disk, 0);
up_write(&zram->init_lock);
-
- /*
- * Revalidate disk out of the init_lock to avoid lockdep splat.
- * It's okay because disk's capacity is protected by init_lock
- * so that revalidate_disk always sees up-to-date capacity.
- */
- if (reset_capacity)
- revalidate_disk(zram->disk);
+ /* I/O operation under all of CPU are done so let's free */
+ zram_meta_free(meta, disksize);
+ zcomp_destroy(comp);
}
static ssize_t disksize_store(struct device *dev,
@@ -765,7 +785,7 @@ static ssize_t disksize_store(struct device *dev,
return -EINVAL;
disksize = PAGE_ALIGN(disksize);
- meta = zram_meta_alloc(disksize);
+ meta = zram_meta_alloc(zram->disk->first_minor, disksize);
if (!meta)
return -ENOMEM;
@@ -784,6 +804,8 @@ static ssize_t disksize_store(struct device *dev,
goto out_destroy_comp;
}
+ init_waitqueue_head(&zram->io_done);
+ atomic_set(&zram->refcount, 1);
zram->meta = meta;
zram->comp = comp;
zram->disksize = disksize;
@@ -803,7 +825,7 @@ out_destroy_comp:
up_write(&zram->init_lock);
zcomp_destroy(comp);
out_free_meta:
- zram_meta_free(meta);
+ zram_meta_free(meta, disksize);
return err;
}
@@ -821,8 +843,9 @@ static ssize_t reset_store(struct device *dev,
if (!bdev)
return -ENOMEM;
+ mutex_lock(&bdev->bd_mutex);
/* Do not reset an active device! */
- if (bdev->bd_holders) {
+ if (bdev->bd_openers) {
ret = -EBUSY;
goto out;
}
@@ -838,12 +861,16 @@ static ssize_t reset_store(struct device *dev,
/* Make sure all pending I/O is finished */
fsync_bdev(bdev);
+ zram_reset_device(zram);
+
+ mutex_unlock(&bdev->bd_mutex);
+ revalidate_disk(zram->disk);
bdput(bdev);
- zram_reset_device(zram, true);
return len;
out:
+ mutex_unlock(&bdev->bd_mutex);
bdput(bdev);
return ret;
}
@@ -909,23 +936,21 @@ static void zram_make_request(struct request_queue *queue, struct bio *bio)
{
struct zram *zram = queue->queuedata;
- down_read(&zram->init_lock);
- if (unlikely(!init_done(zram)))
+ if (unlikely(!zram_meta_get(zram)))
goto error;
if (!valid_io_request(zram, bio->bi_iter.bi_sector,
bio->bi_iter.bi_size)) {
atomic64_inc(&zram->stats.invalid_io);
- goto error;
+ goto put_zram;
}
__zram_make_request(zram, bio);
- up_read(&zram->init_lock);
-
+ zram_meta_put(zram);
return;
-
+put_zram:
+ zram_meta_put(zram);
error:
- up_read(&zram->init_lock);
bio_io_error(bio);
}
@@ -947,21 +972,19 @@ static void zram_slot_free_notify(struct block_device *bdev,
static int zram_rw_page(struct block_device *bdev, sector_t sector,
struct page *page, int rw)
{
- int offset, err;
+ int offset, err = -EIO;
u32 index;
struct zram *zram;
struct bio_vec bv;
zram = bdev->bd_disk->private_data;
+ if (unlikely(!zram_meta_get(zram)))
+ goto out;
+
if (!valid_io_request(zram, sector, PAGE_SIZE)) {
atomic64_inc(&zram->stats.invalid_io);
- return -EINVAL;
- }
-
- down_read(&zram->init_lock);
- if (unlikely(!init_done(zram))) {
- err = -EIO;
- goto out_unlock;
+ err = -EINVAL;
+ goto put_zram;
}
index = sector >> SECTORS_PER_PAGE_SHIFT;
@@ -972,8 +995,9 @@ static int zram_rw_page(struct block_device *bdev, sector_t sector,
bv.bv_offset = 0;
err = zram_bvec_rw(zram, &bv, index, offset, rw);
-out_unlock:
- up_read(&zram->init_lock);
+put_zram:
+ zram_meta_put(zram);
+out:
/*
* If I/O fails, just return error(ie, non-zero) without
* calling page_endio.
@@ -1039,19 +1063,19 @@ static struct attribute_group zram_disk_attr_group = {
static int create_device(struct zram *zram, int device_id)
{
+ struct request_queue *queue;
int ret = -ENOMEM;
init_rwsem(&zram->init_lock);
- zram->queue = blk_alloc_queue(GFP_KERNEL);
- if (!zram->queue) {
+ queue = blk_alloc_queue(GFP_KERNEL);
+ if (!queue) {
pr_err("Error allocating disk queue for device %d\n",
device_id);
goto out;
}
- blk_queue_make_request(zram->queue, zram_make_request);
- zram->queue->queuedata = zram;
+ blk_queue_make_request(queue, zram_make_request);
/* gendisk structure */
zram->disk = alloc_disk(1);
@@ -1064,7 +1088,8 @@ static int create_device(struct zram *zram, int device_id)
zram->disk->major = zram_major;
zram->disk->first_minor = device_id;
zram->disk->fops = &zram_devops;
- zram->disk->queue = zram->queue;
+ zram->disk->queue = queue;
+ zram->disk->queue->queuedata = zram;
zram->disk->private_data = zram;
snprintf(zram->disk->disk_name, 16, "zram%d", device_id);
@@ -1115,20 +1140,35 @@ out_free_disk:
del_gendisk(zram->disk);
put_disk(zram->disk);
out_free_queue:
- blk_cleanup_queue(zram->queue);
+ blk_cleanup_queue(queue);
out:
return ret;
}
-static void destroy_device(struct zram *zram)
+static void destroy_devices(unsigned int nr)
{
- sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
- &zram_disk_attr_group);
+ struct zram *zram;
+ unsigned int i;
- del_gendisk(zram->disk);
- put_disk(zram->disk);
+ for (i = 0; i < nr; i++) {
+ zram = &zram_devices[i];
+ /*
+ * Remove sysfs first, so no one will perform a disksize
+ * store while we destroy the devices
+ */
+ sysfs_remove_group(&disk_to_dev(zram->disk)->kobj,
+ &zram_disk_attr_group);
+
+ zram_reset_device(zram);
- blk_cleanup_queue(zram->queue);
+ blk_cleanup_queue(zram->disk->queue);
+ del_gendisk(zram->disk);
+ put_disk(zram->disk);
+ }
+
+ kfree(zram_devices);
+ unregister_blkdev(zram_major, "zram");
+ pr_info("Destroyed %u device(s)\n", nr);
}
static int __init zram_init(void)
@@ -1138,64 +1178,39 @@ static int __init zram_init(void)
if (num_devices > max_num_devices) {
pr_warn("Invalid value for num_devices: %u\n",
num_devices);
- ret = -EINVAL;
- goto out;
+ return -EINVAL;
}
zram_major = register_blkdev(0, "zram");
if (zram_major <= 0) {
pr_warn("Unable to get major number\n");
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
/* Allocate the device array and initialize each one */
zram_devices = kzalloc(num_devices * sizeof(struct zram), GFP_KERNEL);
if (!zram_devices) {
- ret = -ENOMEM;
- goto unregister;
+ unregister_blkdev(zram_major, "zram");
+ return -ENOMEM;
}
for (dev_id = 0; dev_id < num_devices; dev_id++) {
ret = create_device(&zram_devices[dev_id], dev_id);
if (ret)
- goto free_devices;
+ goto out_error;
}
- pr_info("Created %u device(s) ...\n", num_devices);
-
+ pr_info("Created %u device(s)\n", num_devices);
return 0;
-free_devices:
- while (dev_id)
- destroy_device(&zram_devices[--dev_id]);
- kfree(zram_devices);
-unregister:
- unregister_blkdev(zram_major, "zram");
-out:
+out_error:
+ destroy_devices(dev_id);
return ret;
}
static void __exit zram_exit(void)
{
- int i;
- struct zram *zram;
-
- for (i = 0; i < num_devices; i++) {
- zram = &zram_devices[i];
-
- destroy_device(zram);
- /*
- * Shouldn't access zram->disk after destroy_device
- * because destroy_device already released zram->disk.
- */
- zram_reset_device(zram, false);
- }
-
- unregister_blkdev(zram_major, "zram");
-
- kfree(zram_devices);
- pr_debug("Cleanup done!\n");
+ destroy_devices(num_devices);
}
module_init(zram_init);
diff --git a/drivers/block/zram/zram_drv.h b/drivers/block/zram/zram_drv.h
index b05a816b09ac..17056e589146 100644
--- a/drivers/block/zram/zram_drv.h
+++ b/drivers/block/zram/zram_drv.h
@@ -100,24 +100,25 @@ struct zram_meta {
struct zram {
struct zram_meta *meta;
- struct request_queue *queue;
- struct gendisk *disk;
struct zcomp *comp;
-
- /* Prevent concurrent execution of device init, reset and R/W request */
+ struct gendisk *disk;
+ /* Prevent concurrent execution of device init */
struct rw_semaphore init_lock;
/*
- * This is the limit on amount of *uncompressed* worth of data
- * we can store in a disk.
+ * the number of pages zram can consume for storing compressed data
*/
- u64 disksize; /* bytes */
+ unsigned long limit_pages;
int max_comp_streams;
+
struct zram_stats stats;
+ atomic_t refcount; /* refcount for zram_meta */
+ /* wait all IO under all of cpu are done */
+ wait_queue_head_t io_done;
/*
- * the number of pages zram can consume for storing compressed data
+ * This is the limit on amount of *uncompressed* worth of data
+ * we can store in a disk.
*/
- unsigned long limit_pages;
-
+ u64 disksize; /* bytes */
char compressor[10];
};
#endif
diff --git a/drivers/bluetooth/ath3k.c b/drivers/bluetooth/ath3k.c
index 1ee27ac18de0..de4c8499cbac 100644
--- a/drivers/bluetooth/ath3k.c
+++ b/drivers/bluetooth/ath3k.c
@@ -108,6 +108,7 @@ static const struct usb_device_id ath3k_table[] = {
{ USB_DEVICE(0x13d3, 0x3393) },
{ USB_DEVICE(0x13d3, 0x3402) },
{ USB_DEVICE(0x13d3, 0x3408) },
+ { USB_DEVICE(0x13d3, 0x3423) },
{ USB_DEVICE(0x13d3, 0x3432) },
/* Atheros AR5BBU12 with sflash firmware */
@@ -162,6 +163,7 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
@@ -174,6 +176,8 @@ static const struct usb_device_id ath3k_blist_tbl[] = {
#define USB_REQ_DFU_DNLOAD 1
#define BULK_SIZE 4096
#define FW_HDR_SIZE 20
+#define TIMEGAP_USEC_MIN 50
+#define TIMEGAP_USEC_MAX 100
static int ath3k_load_firmware(struct usb_device *udev,
const struct firmware *firmware)
@@ -205,6 +209,9 @@ static int ath3k_load_firmware(struct usb_device *udev,
pipe = usb_sndbulkpipe(udev, 0x02);
while (count) {
+ /* workaround the compatibility issue with xHCI controller*/
+ usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX);
+
size = min_t(uint, count, BULK_SIZE);
memcpy(send_buf, firmware->data + sent, size);
@@ -302,6 +309,9 @@ static int ath3k_load_fwfile(struct usb_device *udev,
pipe = usb_sndbulkpipe(udev, 0x02);
while (count) {
+ /* workaround the compatibility issue with xHCI controller*/
+ usleep_range(TIMEGAP_USEC_MIN, TIMEGAP_USEC_MAX);
+
size = min_t(uint, count, BULK_SIZE);
memcpy(send_buf, firmware->data + sent, size);
diff --git a/drivers/bluetooth/bfusb.c b/drivers/bluetooth/bfusb.c
index b2e7e94a6771..fcfb72e9e0ee 100644
--- a/drivers/bluetooth/bfusb.c
+++ b/drivers/bluetooth/bfusb.c
@@ -696,6 +696,8 @@ static int bfusb_probe(struct usb_interface *intf, const struct usb_device_id *i
hdev->flush = bfusb_flush;
hdev->send = bfusb_send_frame;
+ set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
+
if (hci_register_dev(hdev) < 0) {
BT_ERR("Can't register HCI device");
hci_free_dev(hdev);
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 330f8f84928d..e75f8ee2512c 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -28,9 +28,9 @@
#define BTM_UPLD_SIZE 2312
/* Time to wait until Host Sleep state change in millisecond */
-#define WAIT_UNTIL_HS_STATE_CHANGED 5000
+#define WAIT_UNTIL_HS_STATE_CHANGED msecs_to_jiffies(5000)
/* Time to wait for command response in millisecond */
-#define WAIT_UNTIL_CMD_RESP 5000
+#define WAIT_UNTIL_CMD_RESP msecs_to_jiffies(5000)
enum rdwr_status {
RDWR_STATUS_SUCCESS = 0,
@@ -104,6 +104,7 @@ struct btmrvl_private {
#ifdef CONFIG_DEBUG_FS
void *debugfs_data;
#endif
+ bool surprise_removed;
};
#define MRVL_VENDOR_PKT 0xFE
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index 30939c993d94..413597789c61 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -178,6 +178,11 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
struct sk_buff *skb;
struct hci_command_hdr *hdr;
+ if (priv->surprise_removed) {
+ BT_ERR("Card is removed");
+ return -EFAULT;
+ }
+
skb = bt_skb_alloc(HCI_COMMAND_HDR_SIZE + len, GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
@@ -202,10 +207,14 @@ static int btmrvl_send_sync_cmd(struct btmrvl_private *priv, u16 opcode,
wake_up_interruptible(&priv->main_thread.wait_q);
if (!wait_event_interruptible_timeout(priv->adapter->cmd_wait_q,
- priv->adapter->cmd_complete,
- msecs_to_jiffies(WAIT_UNTIL_CMD_RESP)))
+ priv->adapter->cmd_complete ||
+ priv->surprise_removed,
+ WAIT_UNTIL_CMD_RESP))
return -ETIMEDOUT;
+ if (priv->surprise_removed)
+ return -EFAULT;
+
return 0;
}
@@ -287,9 +296,10 @@ int btmrvl_enable_hs(struct btmrvl_private *priv)
}
ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q,
- adapter->hs_state,
- msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
- if (ret < 0) {
+ adapter->hs_state ||
+ priv->surprise_removed,
+ WAIT_UNTIL_HS_STATE_CHANGED);
+ if (ret < 0 || priv->surprise_removed) {
BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d",
ret, adapter->hs_state, adapter->ps_state,
adapter->wakeup_tries);
@@ -538,8 +548,11 @@ static int btmrvl_check_device_tree(struct btmrvl_private *priv)
static int btmrvl_setup(struct hci_dev *hdev)
{
struct btmrvl_private *priv = hci_get_drvdata(hdev);
+ int ret;
- btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+ ret = btmrvl_send_module_cfg_cmd(priv, MODULE_BRINGUP_REQ);
+ if (ret)
+ return ret;
priv->btmrvl_dev.gpio_gap = 0xffff;
@@ -597,7 +610,7 @@ static int btmrvl_service_main_thread(void *data)
add_wait_queue(&thread->wait_q, &wait);
set_current_state(TASK_INTERRUPTIBLE);
- if (kthread_should_stop()) {
+ if (kthread_should_stop() || priv->surprise_removed) {
BT_DBG("main_thread: break from main thread");
break;
}
@@ -616,6 +629,11 @@ static int btmrvl_service_main_thread(void *data)
BT_DBG("main_thread woke up");
+ if (kthread_should_stop() || priv->surprise_removed) {
+ BT_DBG("main_thread: break from main thread");
+ break;
+ }
+
spin_lock_irqsave(&priv->driver_lock, flags);
if (adapter->int_count) {
adapter->int_count = 0;
diff --git a/drivers/bluetooth/btmrvl_sdio.c b/drivers/bluetooth/btmrvl_sdio.c
index 0057c0b7a776..01d6da577eeb 100644
--- a/drivers/bluetooth/btmrvl_sdio.c
+++ b/drivers/bluetooth/btmrvl_sdio.c
@@ -573,7 +573,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
offset += txlen;
} while (true);
- BT_DBG("FW download over, size %d bytes", offset);
+ BT_INFO("FW download over, size %d bytes", offset);
ret = 0;
@@ -798,6 +798,9 @@ static void btmrvl_sdio_interrupt(struct sdio_func *func)
priv = card->priv;
+ if (priv->surprise_removed)
+ return;
+
if (card->reg->int_read_to_clear)
ret = btmrvl_sdio_read_to_clear(card, &ireg);
else
@@ -1466,6 +1469,7 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
btmrvl_sdio_disable_host_int(card);
}
BT_DBG("unregester dev");
+ card->priv->surprise_removed = true;
btmrvl_sdio_unregister_dev(card);
btmrvl_remove_card(card->priv);
}
diff --git a/drivers/bluetooth/btusb.c b/drivers/bluetooth/btusb.c
index 19cf2cf22e87..b87688881143 100644
--- a/drivers/bluetooth/btusb.c
+++ b/drivers/bluetooth/btusb.c
@@ -28,7 +28,7 @@
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
-#define VERSION "0.6"
+#define VERSION "0.7"
static bool disable_scofix;
static bool force_scofix;
@@ -49,11 +49,17 @@ static struct usb_driver btusb_driver;
#define BTUSB_INTEL_BOOT 0x200
#define BTUSB_BCM_PATCHRAM 0x400
#define BTUSB_MARVELL 0x800
+#define BTUSB_SWAVE 0x1000
+#define BTUSB_INTEL_NEW 0x2000
+#define BTUSB_AMP 0x4000
static const struct usb_device_id btusb_table[] = {
/* Generic Bluetooth USB device */
{ USB_DEVICE_INFO(0xe0, 0x01, 0x01) },
+ /* Generic Bluetooth AMP device */
+ { USB_DEVICE_INFO(0xe0, 0x01, 0x04), .driver_info = BTUSB_AMP },
+
/* Apple-specific (Broadcom) devices */
{ USB_VENDOR_AND_INTERFACE_INFO(0x05ac, 0xff, 0x01, 0x01) },
@@ -85,7 +91,7 @@ static const struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x05ac, 0x8281) },
/* AVM BlueFRITZ! USB v2.0 */
- { USB_DEVICE(0x057c, 0x3800) },
+ { USB_DEVICE(0x057c, 0x3800), .driver_info = BTUSB_SWAVE },
/* Bluetooth Ultraport Module from IBM */
{ USB_DEVICE(0x04bf, 0x030a) },
@@ -109,16 +115,24 @@ static const struct usb_device_id btusb_table[] = {
{ USB_DEVICE(0x13d3, 0x3404),
.driver_info = BTUSB_BCM_PATCHRAM },
+ /* Broadcom BCM20702B0 (Dynex/Insignia) */
+ { USB_DEVICE(0x19ff, 0x0239), .driver_info = BTUSB_BCM_PATCHRAM },
+
/* Foxconn - Hon Hai */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0489, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
+ /* Lite-On Technology - Broadcom based */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x04ca, 0xff, 0x01, 0x01),
+ .driver_info = BTUSB_BCM_PATCHRAM },
+
/* Broadcom devices with vendor specific id */
{ USB_VENDOR_AND_INTERFACE_INFO(0x0a5c, 0xff, 0x01, 0x01),
.driver_info = BTUSB_BCM_PATCHRAM },
/* ASUSTek Computer - Broadcom based */
- { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01) },
+ { USB_VENDOR_AND_INTERFACE_INFO(0x0b05, 0xff, 0x01, 0x01),
+ .driver_info = BTUSB_BCM_PATCHRAM },
/* Belkin F8065bf - Broadcom based */
{ USB_VENDOR_AND_INTERFACE_INFO(0x050d, 0xff, 0x01, 0x01) },
@@ -188,6 +202,7 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x13d3, 0x3393), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3402), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3408), .driver_info = BTUSB_ATH3012 },
+ { USB_DEVICE(0x13d3, 0x3423), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x13d3, 0x3432), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU12 with sflash firmware */
@@ -237,6 +252,9 @@ static const struct usb_device_id blacklist_table[] = {
/* CONWISE Technology based adapters with buggy SCO support */
{ USB_DEVICE(0x0e5e, 0x6622), .driver_info = BTUSB_BROKEN_ISOC },
+ /* Roper Class 1 Bluetooth Dongle (Silicon Wave based) */
+ { USB_DEVICE(0x1300, 0x0001), .driver_info = BTUSB_SWAVE },
+
/* Digianswer devices */
{ USB_DEVICE(0x08fd, 0x0001), .driver_info = BTUSB_DIGIANSWER },
{ USB_DEVICE(0x08fd, 0x0002), .driver_info = BTUSB_IGNORE },
@@ -249,13 +267,18 @@ static const struct usb_device_id blacklist_table[] = {
{ USB_DEVICE(0x16d3, 0x0002),
.driver_info = BTUSB_SNIFFER | BTUSB_BROKEN_ISOC },
- /* Intel Bluetooth device */
+ /* Marvell Bluetooth devices */
+ { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL },
+ { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
+
+ /* Intel Bluetooth devices */
{ USB_DEVICE(0x8087, 0x07dc), .driver_info = BTUSB_INTEL },
{ USB_DEVICE(0x8087, 0x0a2a), .driver_info = BTUSB_INTEL },
+ { USB_DEVICE(0x8087, 0x0a2b), .driver_info = BTUSB_INTEL_NEW },
- /* Marvell device */
- { USB_DEVICE(0x1286, 0x2044), .driver_info = BTUSB_MARVELL },
- { USB_DEVICE(0x1286, 0x2046), .driver_info = BTUSB_MARVELL },
+ /* Other Intel Bluetooth devices */
+ { USB_VENDOR_AND_INTERFACE_INFO(0x8087, 0xe0, 0x01, 0x01),
+ .driver_info = BTUSB_IGNORE },
{ } /* Terminating entry */
};
@@ -267,6 +290,11 @@ static const struct usb_device_id blacklist_table[] = {
#define BTUSB_ISOC_RUNNING 2
#define BTUSB_SUSPENDING 3
#define BTUSB_DID_ISO_RESUME 4
+#define BTUSB_BOOTLOADER 5
+#define BTUSB_DOWNLOADING 6
+#define BTUSB_FIRMWARE_LOADED 7
+#define BTUSB_FIRMWARE_FAILED 8
+#define BTUSB_BOOTING 9
struct btusb_data {
struct hci_dev *hdev;
@@ -300,14 +328,26 @@ struct btusb_data {
struct usb_endpoint_descriptor *isoc_rx_ep;
__u8 cmdreq_type;
+ __u8 cmdreq;
unsigned int sco_num;
int isoc_altsetting;
int suspend_count;
+ int (*recv_event)(struct hci_dev *hdev, struct sk_buff *skb);
int (*recv_bulk)(struct btusb_data *data, void *buffer, int count);
};
+static int btusb_wait_on_bit_timeout(void *word, int bit, unsigned long timeout,
+ unsigned mode)
+{
+ might_sleep();
+ if (!test_bit(bit, word))
+ return 0;
+ return out_of_line_wait_on_bit_timeout(word, bit, bit_wait_timeout,
+ mode, timeout);
+}
+
static inline void btusb_free_frags(struct btusb_data *data)
{
unsigned long flags;
@@ -370,7 +410,7 @@ static int btusb_recv_intr(struct btusb_data *data, void *buffer, int count)
if (bt_cb(skb)->expect == 0) {
/* Complete frame */
- hci_recv_frame(data->hdev, skb);
+ data->recv_event(data->hdev, skb);
skb = NULL;
}
}
@@ -952,7 +992,7 @@ static struct urb *alloc_ctrl_urb(struct hci_dev *hdev, struct sk_buff *skb)
}
dr->bRequestType = data->cmdreq_type;
- dr->bRequest = 0;
+ dr->bRequest = data->cmdreq;
dr->wIndex = 0;
dr->wValue = 0;
dr->wLength = __cpu_to_le16(skb->len);
@@ -1290,6 +1330,26 @@ struct intel_version {
u8 fw_patch_num;
} __packed;
+struct intel_boot_params {
+ __u8 status;
+ __u8 otp_format;
+ __u8 otp_content;
+ __u8 otp_patch;
+ __le16 dev_revid;
+ __u8 secure_boot;
+ __u8 key_from_hdr;
+ __u8 key_type;
+ __u8 otp_lock;
+ __u8 api_lock;
+ __u8 debug_lock;
+ bdaddr_t otp_bdaddr;
+ __u8 min_fw_build_nn;
+ __u8 min_fw_build_cw;
+ __u8 min_fw_build_yy;
+ __u8 limited_cce;
+ __u8 unlocked_state;
+} __packed;
+
static const struct firmware *btusb_setup_intel_get_fw(struct hci_dev *hdev,
struct intel_version *ver)
{
@@ -1698,6 +1758,562 @@ exit_mfg_deactivate:
return 0;
}
+static int inject_cmd_complete(struct hci_dev *hdev, __u16 opcode)
+{
+ struct sk_buff *skb;
+ struct hci_event_hdr *hdr;
+ struct hci_ev_cmd_complete *evt;
+
+ skb = bt_skb_alloc(sizeof(*hdr) + sizeof(*evt) + 1, GFP_ATOMIC);
+ if (!skb)
+ return -ENOMEM;
+
+ hdr = (struct hci_event_hdr *)skb_put(skb, sizeof(*hdr));
+ hdr->evt = HCI_EV_CMD_COMPLETE;
+ hdr->plen = sizeof(*evt) + 1;
+
+ evt = (struct hci_ev_cmd_complete *)skb_put(skb, sizeof(*evt));
+ evt->ncmd = 0x01;
+ evt->opcode = cpu_to_le16(opcode);
+
+ *skb_put(skb, 1) = 0x00;
+
+ bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+
+ return hci_recv_frame(hdev, skb);
+}
+
+static int btusb_recv_bulk_intel(struct btusb_data *data, void *buffer,
+ int count)
+{
+ /* When the device is in bootloader mode, then it can send
+ * events via the bulk endpoint. These events are treated the
+ * same way as the ones received from the interrupt endpoint.
+ */
+ if (test_bit(BTUSB_BOOTLOADER, &data->flags))
+ return btusb_recv_intr(data, buffer, count);
+
+ return btusb_recv_bulk(data, buffer, count);
+}
+
+static int btusb_recv_event_intel(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+
+ if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
+ struct hci_event_hdr *hdr = (void *)skb->data;
+
+ /* When the firmware loading completes the device sends
+ * out a vendor specific event indicating the result of
+ * the firmware loading.
+ */
+ if (skb->len == 7 && hdr->evt == 0xff && hdr->plen == 0x05 &&
+ skb->data[2] == 0x06) {
+ if (skb->data[3] != 0x00)
+ test_bit(BTUSB_FIRMWARE_FAILED, &data->flags);
+
+ if (test_and_clear_bit(BTUSB_DOWNLOADING,
+ &data->flags) &&
+ test_bit(BTUSB_FIRMWARE_LOADED, &data->flags)) {
+ smp_mb__after_atomic();
+ wake_up_bit(&data->flags, BTUSB_DOWNLOADING);
+ }
+ }
+
+ /* When switching to the operational firmware the device
+ * sends a vendor specific event indicating that the bootup
+ * completed.
+ */
+ if (skb->len == 9 && hdr->evt == 0xff && hdr->plen == 0x07 &&
+ skb->data[2] == 0x02) {
+ if (test_and_clear_bit(BTUSB_BOOTING, &data->flags)) {
+ smp_mb__after_atomic();
+ wake_up_bit(&data->flags, BTUSB_BOOTING);
+ }
+ }
+ }
+
+ return hci_recv_frame(hdev, skb);
+}
+
+static int btusb_send_frame_intel(struct hci_dev *hdev, struct sk_buff *skb)
+{
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct urb *urb;
+
+ BT_DBG("%s", hdev->name);
+
+ if (!test_bit(HCI_RUNNING, &hdev->flags))
+ return -EBUSY;
+
+ switch (bt_cb(skb)->pkt_type) {
+ case HCI_COMMAND_PKT:
+ if (test_bit(BTUSB_BOOTLOADER, &data->flags)) {
+ struct hci_command_hdr *cmd = (void *)skb->data;
+ __u16 opcode = le16_to_cpu(cmd->opcode);
+
+ /* When in bootloader mode and the command 0xfc09
+ * is received, it needs to be send down the
+ * bulk endpoint. So allocate a bulk URB instead.
+ */
+ if (opcode == 0xfc09)
+ urb = alloc_bulk_urb(hdev, skb);
+ else
+ urb = alloc_ctrl_urb(hdev, skb);
+
+ /* When the 0xfc01 command is issued to boot into
+ * the operational firmware, it will actually not
+ * send a command complete event. To keep the flow
+ * control working inject that event here.
+ */
+ if (opcode == 0xfc01)
+ inject_cmd_complete(hdev, opcode);
+ } else {
+ urb = alloc_ctrl_urb(hdev, skb);
+ }
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ hdev->stat.cmd_tx++;
+ return submit_or_queue_tx_urb(hdev, urb);
+
+ case HCI_ACLDATA_PKT:
+ urb = alloc_bulk_urb(hdev, skb);
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ hdev->stat.acl_tx++;
+ return submit_or_queue_tx_urb(hdev, urb);
+
+ case HCI_SCODATA_PKT:
+ if (hci_conn_num(hdev, SCO_LINK) < 1)
+ return -ENODEV;
+
+ urb = alloc_isoc_urb(hdev, skb);
+ if (IS_ERR(urb))
+ return PTR_ERR(urb);
+
+ hdev->stat.sco_tx++;
+ return submit_tx_urb(hdev, urb);
+ }
+
+ return -EILSEQ;
+}
+
+static int btusb_intel_secure_send(struct hci_dev *hdev, u8 fragment_type,
+ u32 plen, const void *param)
+{
+ while (plen > 0) {
+ struct sk_buff *skb;
+ u8 cmd_param[253], fragment_len = (plen > 252) ? 252 : plen;
+
+ cmd_param[0] = fragment_type;
+ memcpy(cmd_param + 1, param, fragment_len);
+
+ skb = __hci_cmd_sync(hdev, 0xfc09, fragment_len + 1,
+ cmd_param, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ kfree_skb(skb);
+
+ plen -= fragment_len;
+ param += fragment_len;
+ }
+
+ return 0;
+}
+
+static void btusb_intel_version_info(struct hci_dev *hdev,
+ struct intel_version *ver)
+{
+ const char *variant;
+
+ switch (ver->fw_variant) {
+ case 0x06:
+ variant = "Bootloader";
+ break;
+ case 0x23:
+ variant = "Firmware";
+ break;
+ default:
+ return;
+ }
+
+ BT_INFO("%s: %s revision %u.%u build %u week %u %u", hdev->name,
+ variant, ver->fw_revision >> 4, ver->fw_revision & 0x0f,
+ ver->fw_build_num, ver->fw_build_ww, 2000 + ver->fw_build_yy);
+}
+
+static int btusb_setup_intel_new(struct hci_dev *hdev)
+{
+ static const u8 reset_param[] = { 0x00, 0x01, 0x00, 0x01,
+ 0x00, 0x08, 0x04, 0x00 };
+ struct btusb_data *data = hci_get_drvdata(hdev);
+ struct sk_buff *skb;
+ struct intel_version *ver;
+ struct intel_boot_params *params;
+ const struct firmware *fw;
+ const u8 *fw_ptr;
+ char fwname[64];
+ ktime_t calltime, delta, rettime;
+ unsigned long long duration;
+ int err;
+
+ BT_DBG("%s", hdev->name);
+
+ calltime = ktime_get();
+
+ /* Read the Intel version information to determine if the device
+ * is in bootloader mode or if it already has operational firmware
+ * loaded.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc05, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reading Intel version information failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+
+ if (skb->len != sizeof(*ver)) {
+ BT_ERR("%s: Intel version event size mismatch", hdev->name);
+ kfree_skb(skb);
+ return -EILSEQ;
+ }
+
+ ver = (struct intel_version *)skb->data;
+ if (ver->status) {
+ BT_ERR("%s: Intel version command failure (%02x)",
+ hdev->name, ver->status);
+ err = -bt_to_errno(ver->status);
+ kfree_skb(skb);
+ return err;
+ }
+
+ /* The hardware platform number has a fixed value of 0x37 and
+ * for now only accept this single value.
+ */
+ if (ver->hw_platform != 0x37) {
+ BT_ERR("%s: Unsupported Intel hardware platform (%u)",
+ hdev->name, ver->hw_platform);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ /* At the moment only the hardware variant iBT 3.0 (LnP/SfP) is
+ * supported by this firmware loading method. This check has been
+ * put in place to ensure correct forward compatibility options
+ * when newer hardware variants come along.
+ */
+ if (ver->hw_variant != 0x0b) {
+ BT_ERR("%s: Unsupported Intel hardware variant (%u)",
+ hdev->name, ver->hw_variant);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ btusb_intel_version_info(hdev, ver);
+
+ /* The firmware variant determines if the device is in bootloader
+ * mode or is running operational firmware. The value 0x06 identifies
+ * the bootloader and the value 0x23 identifies the operational
+ * firmware.
+ *
+ * When the operational firmware is already present, then only
+ * the check for valid Bluetooth device address is needed. This
+ * determines if the device will be added as configured or
+ * unconfigured controller.
+ *
+ * It is not possible to use the Secure Boot Parameters in this
+ * case since that command is only available in bootloader mode.
+ */
+ if (ver->fw_variant == 0x23) {
+ kfree_skb(skb);
+ clear_bit(BTUSB_BOOTLOADER, &data->flags);
+ btusb_check_bdaddr_intel(hdev);
+ return 0;
+ }
+
+ /* If the device is not in bootloader mode, then the only possible
+ * choice is to return an error and abort the device initialization.
+ */
+ if (ver->fw_variant != 0x06) {
+ BT_ERR("%s: Unsupported Intel firmware variant (%u)",
+ hdev->name, ver->fw_variant);
+ kfree_skb(skb);
+ return -ENODEV;
+ }
+
+ kfree_skb(skb);
+
+ /* Read the secure boot parameters to identify the operating
+ * details of the bootloader.
+ */
+ skb = __hci_cmd_sync(hdev, 0xfc0d, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reading Intel boot parameters failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return PTR_ERR(skb);
+ }
+
+ if (skb->len != sizeof(*params)) {
+ BT_ERR("%s: Intel boot parameters size mismatch", hdev->name);
+ kfree_skb(skb);
+ return -EILSEQ;
+ }
+
+ params = (struct intel_boot_params *)skb->data;
+ if (params->status) {
+ BT_ERR("%s: Intel boot parameters command failure (%02x)",
+ hdev->name, params->status);
+ err = -bt_to_errno(params->status);
+ kfree_skb(skb);
+ return err;
+ }
+
+ BT_INFO("%s: Device revision is %u", hdev->name,
+ le16_to_cpu(params->dev_revid));
+
+ BT_INFO("%s: Secure boot is %s", hdev->name,
+ params->secure_boot ? "enabled" : "disabled");
+
+ BT_INFO("%s: Minimum firmware build %u week %u %u", hdev->name,
+ params->min_fw_build_nn, params->min_fw_build_cw,
+ 2000 + params->min_fw_build_yy);
+
+ /* It is required that every single firmware fragment is acknowledged
+ * with a command complete event. If the boot parameters indicate
+ * that this bootloader does not send them, then abort the setup.
+ */
+ if (params->limited_cce != 0x00) {
+ BT_ERR("%s: Unsupported Intel firmware loading method (%u)",
+ hdev->name, params->limited_cce);
+ kfree_skb(skb);
+ return -EINVAL;
+ }
+
+ /* If the OTP has no valid Bluetooth device address, then there will
+ * also be no valid address for the operational firmware.
+ */
+ if (!bacmp(&params->otp_bdaddr, BDADDR_ANY)) {
+ BT_INFO("%s: No device address configured", hdev->name);
+ set_bit(HCI_QUIRK_INVALID_BDADDR, &hdev->quirks);
+ }
+
+ /* With this Intel bootloader only the hardware variant and device
+ * revision information are used to select the right firmware.
+ *
+ * Currently this bootloader support is limited to hardware variant
+ * iBT 3.0 (LnP/SfP) which is identified by the value 11 (0x0b).
+ */
+ snprintf(fwname, sizeof(fwname), "intel/ibt-11-%u.sfi",
+ le16_to_cpu(params->dev_revid));
+
+ err = request_firmware(&fw, fwname, &hdev->dev);
+ if (err < 0) {
+ BT_ERR("%s: Failed to load Intel firmware file (%d)",
+ hdev->name, err);
+ kfree_skb(skb);
+ return err;
+ }
+
+ BT_INFO("%s: Found device firmware: %s", hdev->name, fwname);
+
+ kfree_skb(skb);
+
+ if (fw->size < 644) {
+ BT_ERR("%s: Invalid size of firmware file (%zu)",
+ hdev->name, fw->size);
+ err = -EBADF;
+ goto done;
+ }
+
+ set_bit(BTUSB_DOWNLOADING, &data->flags);
+
+ /* Start the firmware download transaction with the Init fragment
+ * represented by the 128 bytes of CSS header.
+ */
+ err = btusb_intel_secure_send(hdev, 0x00, 128, fw->data);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware header (%d)",
+ hdev->name, err);
+ goto done;
+ }
+
+ /* Send the 256 bytes of public key information from the firmware
+ * as the PKey fragment.
+ */
+ err = btusb_intel_secure_send(hdev, 0x03, 256, fw->data + 128);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware public key (%d)",
+ hdev->name, err);
+ goto done;
+ }
+
+ /* Send the 256 bytes of signature information from the firmware
+ * as the Sign fragment.
+ */
+ err = btusb_intel_secure_send(hdev, 0x02, 256, fw->data + 388);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware signature (%d)",
+ hdev->name, err);
+ goto done;
+ }
+
+ fw_ptr = fw->data + 644;
+
+ while (fw_ptr - fw->data < fw->size) {
+ struct hci_command_hdr *cmd = (void *)fw_ptr;
+ u8 cmd_len;
+
+ cmd_len = sizeof(*cmd) + cmd->plen;
+
+ /* Send each command from the firmware data buffer as
+ * a single Data fragment.
+ */
+ err = btusb_intel_secure_send(hdev, 0x01, cmd_len, fw_ptr);
+ if (err < 0) {
+ BT_ERR("%s: Failed to send firmware data (%d)",
+ hdev->name, err);
+ goto done;
+ }
+
+ fw_ptr += cmd_len;
+ }
+
+ set_bit(BTUSB_FIRMWARE_LOADED, &data->flags);
+
+ BT_INFO("%s: Waiting for firmware download to complete", hdev->name);
+
+ /* Before switching the device into operational mode and with that
+ * booting the loaded firmware, wait for the bootloader notification
+ * that all fragments have been successfully received.
+ *
+ * When the event processing receives the notification, then the
+ * BTUSB_DOWNLOADING flag will be cleared.
+ *
+ * The firmware loading should not take longer than 5 seconds
+ * and thus just timeout if that happens and fail the setup
+ * of this device.
+ */
+ err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_DOWNLOADING,
+ msecs_to_jiffies(5000),
+ TASK_INTERRUPTIBLE);
+ if (err == 1) {
+ BT_ERR("%s: Firmware loading interrupted", hdev->name);
+ err = -EINTR;
+ goto done;
+ }
+
+ if (err) {
+ BT_ERR("%s: Firmware loading timeout", hdev->name);
+ err = -ETIMEDOUT;
+ goto done;
+ }
+
+ if (test_bit(BTUSB_FIRMWARE_FAILED, &data->flags)) {
+ BT_ERR("%s: Firmware loading failed", hdev->name);
+ err = -ENOEXEC;
+ goto done;
+ }
+
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+
+ BT_INFO("%s: Firmware loaded in %llu usecs", hdev->name, duration);
+
+done:
+ release_firmware(fw);
+
+ if (err < 0)
+ return err;
+
+ calltime = ktime_get();
+
+ set_bit(BTUSB_BOOTING, &data->flags);
+
+ skb = __hci_cmd_sync(hdev, 0xfc01, sizeof(reset_param), reset_param,
+ HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ kfree_skb(skb);
+
+ /* The bootloader will not indicate when the device is ready. This
+ * is done by the operational firmware sending bootup notification.
+ *
+ * Booting into operational firmware should not take longer than
+ * 1 second. However if that happens, then just fail the setup
+ * since something went wrong.
+ */
+ BT_INFO("%s: Waiting for device to boot", hdev->name);
+
+ err = btusb_wait_on_bit_timeout(&data->flags, BTUSB_BOOTING,
+ msecs_to_jiffies(1000),
+ TASK_INTERRUPTIBLE);
+
+ if (err == 1) {
+ BT_ERR("%s: Device boot interrupted", hdev->name);
+ return -EINTR;
+ }
+
+ if (err) {
+ BT_ERR("%s: Device boot timeout", hdev->name);
+ return -ETIMEDOUT;
+ }
+
+ rettime = ktime_get();
+ delta = ktime_sub(rettime, calltime);
+ duration = (unsigned long long) ktime_to_ns(delta) >> 10;
+
+ BT_INFO("%s: Device booted in %llu usecs", hdev->name, duration);
+
+ clear_bit(BTUSB_BOOTLOADER, &data->flags);
+
+ return 0;
+}
+
+static void btusb_hw_error_intel(struct hci_dev *hdev, u8 code)
+{
+ struct sk_buff *skb;
+ u8 type = 0x00;
+
+ BT_ERR("%s: Hardware error 0x%2.2x", hdev->name, code);
+
+ skb = __hci_cmd_sync(hdev, HCI_OP_RESET, 0, NULL, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Reset after hardware error failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return;
+ }
+ kfree_skb(skb);
+
+ skb = __hci_cmd_sync(hdev, 0xfc22, 1, &type, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ BT_ERR("%s: Retrieving Intel exception info failed (%ld)",
+ hdev->name, PTR_ERR(skb));
+ return;
+ }
+
+ if (skb->len != 13) {
+ BT_ERR("%s: Exception info size mismatch", hdev->name);
+ kfree_skb(skb);
+ return;
+ }
+
+ if (skb->data[0] != 0x00) {
+ BT_ERR("%s: Exception info command failure (%02x)",
+ hdev->name, skb->data[0]);
+ kfree_skb(skb);
+ return;
+ }
+
+ BT_ERR("%s: Exception info %s", hdev->name, (char *)(skb->data + 1));
+
+ kfree_skb(skb);
+}
+
static int btusb_set_bdaddr_intel(struct hci_dev *hdev, const bdaddr_t *bdaddr)
{
struct sk_buff *skb;
@@ -1943,6 +2559,31 @@ static int btusb_set_bdaddr_bcm(struct hci_dev *hdev, const bdaddr_t *bdaddr)
return 0;
}
+static int btusb_set_bdaddr_ath3012(struct hci_dev *hdev,
+ const bdaddr_t *bdaddr)
+{
+ struct sk_buff *skb;
+ u8 buf[10];
+ long ret;
+
+ buf[0] = 0x01;
+ buf[1] = 0x01;
+ buf[2] = 0x00;
+ buf[3] = sizeof(bdaddr_t);
+ memcpy(buf + 4, bdaddr, sizeof(bdaddr_t));
+
+ skb = __hci_cmd_sync(hdev, 0xfc0b, sizeof(buf), buf, HCI_INIT_TIMEOUT);
+ if (IS_ERR(skb)) {
+ ret = PTR_ERR(skb);
+ BT_ERR("%s: Change address command failed (%ld)",
+ hdev->name, ret);
+ return ret;
+ }
+ kfree_skb(skb);
+
+ return 0;
+}
+
static int btusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
@@ -2003,7 +2644,13 @@ static int btusb_probe(struct usb_interface *intf,
if (!data->intr_ep || !data->bulk_tx_ep || !data->bulk_rx_ep)
return -ENODEV;
- data->cmdreq_type = USB_TYPE_CLASS;
+ if (id->driver_info & BTUSB_AMP) {
+ data->cmdreq_type = USB_TYPE_CLASS | 0x01;
+ data->cmdreq = 0x2b;
+ } else {
+ data->cmdreq_type = USB_TYPE_CLASS;
+ data->cmdreq = 0x00;
+ }
data->udev = interface_to_usbdev(intf);
data->intf = intf;
@@ -2019,7 +2666,14 @@ static int btusb_probe(struct usb_interface *intf,
init_usb_anchor(&data->isoc_anchor);
spin_lock_init(&data->rxlock);
- data->recv_bulk = btusb_recv_bulk;
+ if (id->driver_info & BTUSB_INTEL_NEW) {
+ data->recv_event = btusb_recv_event_intel;
+ data->recv_bulk = btusb_recv_bulk_intel;
+ set_bit(BTUSB_BOOTLOADER, &data->flags);
+ } else {
+ data->recv_event = hci_recv_frame;
+ data->recv_bulk = btusb_recv_bulk;
+ }
hdev = hci_alloc_dev();
if (!hdev)
@@ -2028,6 +2682,11 @@ static int btusb_probe(struct usb_interface *intf,
hdev->bus = HCI_USB;
hci_set_drvdata(hdev, data);
+ if (id->driver_info & BTUSB_AMP)
+ hdev->dev_type = HCI_AMP;
+ else
+ hdev->dev_type = HCI_BREDR;
+
data->hdev = hdev;
SET_HCIDEV_DEV(hdev, &intf->dev);
@@ -2050,16 +2709,40 @@ static int btusb_probe(struct usb_interface *intf,
if (id->driver_info & BTUSB_INTEL) {
hdev->setup = btusb_setup_intel;
hdev->set_bdaddr = btusb_set_bdaddr_intel;
+ set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+ }
+
+ if (id->driver_info & BTUSB_INTEL_NEW) {
+ hdev->send = btusb_send_frame_intel;
+ hdev->setup = btusb_setup_intel_new;
+ hdev->hw_error = btusb_hw_error_intel;
+ hdev->set_bdaddr = btusb_set_bdaddr_intel;
+ set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
}
if (id->driver_info & BTUSB_MARVELL)
hdev->set_bdaddr = btusb_set_bdaddr_marvell;
+ if (id->driver_info & BTUSB_SWAVE) {
+ set_bit(HCI_QUIRK_FIXUP_INQUIRY_MODE, &hdev->quirks);
+ set_bit(HCI_QUIRK_BROKEN_LOCAL_COMMANDS, &hdev->quirks);
+ }
+
if (id->driver_info & BTUSB_INTEL_BOOT)
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);
- /* Interface numbers are hardcoded in the specification */
- data->isoc = usb_ifnum_to_if(data->udev, 1);
+ if (id->driver_info & BTUSB_ATH3012) {
+ hdev->set_bdaddr = btusb_set_bdaddr_ath3012;
+ set_bit(HCI_QUIRK_STRICT_DUPLICATE_FILTER, &hdev->quirks);
+ }
+
+ if (id->driver_info & BTUSB_AMP) {
+ /* AMP controllers do not support SCO packets */
+ data->isoc = NULL;
+ } else {
+ /* Interface numbers are hardcoded in the specification */
+ data->isoc = usb_ifnum_to_if(data->udev, 1);
+ }
if (!reset)
set_bit(HCI_QUIRK_RESET_ON_CLOSE, &hdev->quirks);
@@ -2153,7 +2836,6 @@ static void btusb_disconnect(struct usb_interface *intf)
else if (data->isoc)
usb_driver_release_interface(&btusb_driver, data->isoc);
- btusb_free_frags(data);
hci_free_dev(hdev);
}
diff --git a/drivers/bluetooth/hci_ath.c b/drivers/bluetooth/hci_ath.c
index 2ff6dfd2d3f0..9c4dcf4c62ea 100644
--- a/drivers/bluetooth/hci_ath.c
+++ b/drivers/bluetooth/hci_ath.c
@@ -51,33 +51,22 @@ struct ath_struct {
static int ath_wakeup_ar3k(struct tty_struct *tty)
{
- struct ktermios ktermios;
int status = tty->driver->ops->tiocmget(tty);
if (status & TIOCM_CTS)
return status;
- /* Disable Automatic RTSCTS */
- ktermios = tty->termios;
- ktermios.c_cflag &= ~CRTSCTS;
- tty_set_termios(tty, &ktermios);
-
/* Clear RTS first */
- status = tty->driver->ops->tiocmget(tty);
+ tty->driver->ops->tiocmget(tty);
tty->driver->ops->tiocmset(tty, 0x00, TIOCM_RTS);
mdelay(20);
/* Set RTS, wake up board */
- status = tty->driver->ops->tiocmget(tty);
+ tty->driver->ops->tiocmget(tty);
tty->driver->ops->tiocmset(tty, TIOCM_RTS, 0x00);
mdelay(20);
status = tty->driver->ops->tiocmget(tty);
-
- /* Enable Automatic RTSCTS */
- ktermios.c_cflag |= CRTSCTS;
- status = tty_set_termios(tty, &ktermios);
-
return status;
}
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 0ce5e2d65a06..84fd66057dad 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -806,8 +806,8 @@ static int cci_pmu_event_init(struct perf_event *event)
static ssize_t pmu_attr_cpumask_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
- int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &pmu->cpus);
-
+ int n = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+ cpumask_pr_args(&pmu->cpus));
buf[n++] = '\n';
buf[n] = '\0';
return n;
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 81bf297f1034..fb9ec6221730 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -58,6 +58,7 @@
#include <linux/debugfs.h>
#include <linux/log2.h>
#include <linux/syscore_ops.h>
+#include <linux/memblock.h>
/*
* DDR target is the same on all platforms.
@@ -69,6 +70,7 @@
*/
#define WIN_CTRL_OFF 0x0000
#define WIN_CTRL_ENABLE BIT(0)
+#define WIN_CTRL_SYNCBARRIER BIT(1)
#define WIN_CTRL_TGT_MASK 0xf0
#define WIN_CTRL_TGT_SHIFT 4
#define WIN_CTRL_ATTR_MASK 0xff00
@@ -82,6 +84,9 @@
#define WIN_REMAP_LOW 0xffff0000
#define WIN_REMAP_HI_OFF 0x000c
+#define UNIT_SYNC_BARRIER_OFF 0x84
+#define UNIT_SYNC_BARRIER_ALL 0xFFFF
+
#define ATTR_HW_COHERENCY (0x1 << 4)
#define DDR_BASE_CS_OFF(n) (0x0000 + ((n) << 3))
@@ -97,7 +102,9 @@
/* Relative to mbusbridge_base */
#define MBUS_BRIDGE_CTRL_OFF 0x0
+#define MBUS_BRIDGE_SIZE_MASK 0xffff0000
#define MBUS_BRIDGE_BASE_OFF 0x4
+#define MBUS_BRIDGE_BASE_MASK 0xffff0000
/* Maximum number of windows, for all known platforms */
#define MBUS_WINS_MAX 20
@@ -106,9 +113,9 @@ 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);
+ unsigned int (*win_remap_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);
@@ -154,6 +161,13 @@ const struct mbus_dram_target_info *mv_mbus_dram_info(void)
}
EXPORT_SYMBOL_GPL(mv_mbus_dram_info);
+/* Checks whether the given window has remap capability */
+static bool mvebu_mbus_window_is_remappable(struct mvebu_mbus_state *mbus,
+ const int win)
+{
+ return mbus->soc->win_remap_offset(win) != MVEBU_MBUS_NO_REMAP;
+}
+
/*
* Functions to manipulate the address decoding windows
*/
@@ -185,9 +199,12 @@ static void mvebu_mbus_read_window(struct mvebu_mbus_state *mbus,
*attr = (ctrlreg & WIN_CTRL_ATTR_MASK) >> WIN_CTRL_ATTR_SHIFT;
if (remap) {
- if (win < mbus->soc->num_remappable_wins) {
- u32 remap_low = readl(addr + WIN_REMAP_LO_OFF);
- u32 remap_hi = readl(addr + WIN_REMAP_HI_OFF);
+ if (mvebu_mbus_window_is_remappable(mbus, win)) {
+ u32 remap_low, remap_hi;
+ void __iomem *addr_rmp = mbus->mbuswins_base +
+ mbus->soc->win_remap_offset(win);
+ remap_low = readl(addr_rmp + WIN_REMAP_LO_OFF);
+ remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF);
*remap = ((u64)remap_hi << 32) | remap_low;
} else
*remap = 0;
@@ -200,10 +217,11 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
void __iomem *addr;
addr = mbus->mbuswins_base + mbus->soc->win_cfg_offset(win);
-
writel(0, addr + WIN_BASE_OFF);
writel(0, addr + WIN_CTRL_OFF);
- if (win < mbus->soc->num_remappable_wins) {
+
+ if (mvebu_mbus_window_is_remappable(mbus, win)) {
+ addr = mbus->mbuswins_base + mbus->soc->win_remap_offset(win);
writel(0, addr + WIN_REMAP_LO_OFF);
writel(0, addr + WIN_REMAP_HI_OFF);
}
@@ -211,14 +229,6 @@ static void mvebu_mbus_disable_window(struct mvebu_mbus_state *mbus,
/* Checks whether the given window number is available */
-/* On Armada XP, 375 and 38x the MBus window 13 has the remap
- * capability, like windows 0 to 7. However, the mvebu-mbus driver
- * isn't currently taking into account this special case, which means
- * that when window 13 is actually used, the remap registers are left
- * to 0, making the device using this MBus window unavailable. The
- * quick fix for stable is to not use window 13. A follow up patch
- * will correctly handle this window.
-*/
static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
const int win)
{
@@ -226,9 +236,6 @@ static int mvebu_mbus_window_is_free(struct mvebu_mbus_state *mbus,
mbus->soc->win_cfg_offset(win);
u32 ctrl = readl(addr + WIN_CTRL_OFF);
- if (win == 13)
- return false;
-
return !(ctrl & WIN_CTRL_ENABLE);
}
@@ -316,17 +323,22 @@ static int mvebu_mbus_setup_window(struct mvebu_mbus_state *mbus,
ctrl = ((size - 1) & WIN_CTRL_SIZE_MASK) |
(attr << WIN_CTRL_ATTR_SHIFT) |
(target << WIN_CTRL_TGT_SHIFT) |
+ WIN_CTRL_SYNCBARRIER |
WIN_CTRL_ENABLE;
writel(base & WIN_BASE_LOW, addr + WIN_BASE_OFF);
writel(ctrl, addr + WIN_CTRL_OFF);
- if (win < mbus->soc->num_remappable_wins) {
+
+ if (mvebu_mbus_window_is_remappable(mbus, win)) {
+ void __iomem *addr_rmp = mbus->mbuswins_base +
+ mbus->soc->win_remap_offset(win);
+
if (remap == MVEBU_MBUS_NO_REMAP)
remap_addr = base;
else
remap_addr = remap;
- writel(remap_addr & WIN_REMAP_LOW, addr + WIN_REMAP_LO_OFF);
- writel(0, addr + WIN_REMAP_HI_OFF);
+ writel(remap_addr & WIN_REMAP_LOW, addr_rmp + WIN_REMAP_LO_OFF);
+ writel(0, addr_rmp + WIN_REMAP_HI_OFF);
}
return 0;
@@ -340,19 +352,27 @@ static int mvebu_mbus_alloc_window(struct mvebu_mbus_state *mbus,
int win;
if (remap == MVEBU_MBUS_NO_REMAP) {
- for (win = mbus->soc->num_remappable_wins;
- win < mbus->soc->num_wins; win++)
+ for (win = 0; win < mbus->soc->num_wins; win++) {
+ if (mvebu_mbus_window_is_remappable(mbus, win))
+ continue;
+
if (mvebu_mbus_window_is_free(mbus, win))
return mvebu_mbus_setup_window(mbus, win, base,
size, remap,
target, attr);
+ }
}
+ for (win = 0; win < mbus->soc->num_wins; win++) {
+ /* Skip window if need remap but is not supported */
+ if ((remap != MVEBU_MBUS_NO_REMAP) &&
+ !mvebu_mbus_window_is_remappable(mbus, win))
+ continue;
- for (win = 0; win < mbus->soc->num_wins; win++)
if (mvebu_mbus_window_is_free(mbus, win))
return mvebu_mbus_setup_window(mbus, win, base, size,
remap, target, attr);
+ }
return -ENOMEM;
}
@@ -464,7 +484,7 @@ static int mvebu_devs_debug_show(struct seq_file *seq, void *v)
((wbase & (u64)(wsize - 1)) != 0))
seq_puts(seq, " (Invalid base/size!!)");
- if (win < mbus->soc->num_remappable_wins) {
+ if (mvebu_mbus_window_is_remappable(mbus, win)) {
seq_printf(seq, " (remap %016llx)\n",
(unsigned long long)wremap);
} else
@@ -490,12 +510,12 @@ static const struct file_operations mvebu_devs_debug_fops = {
* SoC-specific functions and definitions
*/
-static unsigned int orion_mbus_win_offset(int win)
+static unsigned int generic_mbus_win_cfg_offset(int win)
{
return win << 4;
}
-static unsigned int armada_370_xp_mbus_win_offset(int win)
+static unsigned int armada_370_xp_mbus_win_cfg_offset(int win)
{
/* The register layout is a bit annoying and the below code
* tries to cope with it.
@@ -515,7 +535,7 @@ static unsigned int armada_370_xp_mbus_win_offset(int win)
return 0x90 + ((win - 8) << 3);
}
-static unsigned int mv78xx0_mbus_win_offset(int win)
+static unsigned int mv78xx0_mbus_win_cfg_offset(int win)
{
if (win < 8)
return win << 4;
@@ -523,36 +543,140 @@ static unsigned int mv78xx0_mbus_win_offset(int win)
return 0x900 + ((win - 8) << 4);
}
+static unsigned int generic_mbus_win_remap_2_offset(int win)
+{
+ if (win < 2)
+ return generic_mbus_win_cfg_offset(win);
+ else
+ return MVEBU_MBUS_NO_REMAP;
+}
+
+static unsigned int generic_mbus_win_remap_4_offset(int win)
+{
+ if (win < 4)
+ return generic_mbus_win_cfg_offset(win);
+ else
+ return MVEBU_MBUS_NO_REMAP;
+}
+
+static unsigned int generic_mbus_win_remap_8_offset(int win)
+{
+ if (win < 8)
+ return generic_mbus_win_cfg_offset(win);
+ else
+ return MVEBU_MBUS_NO_REMAP;
+}
+
+static unsigned int armada_xp_mbus_win_remap_offset(int win)
+{
+ if (win < 8)
+ return generic_mbus_win_cfg_offset(win);
+ else if (win == 13)
+ return 0xF0 - WIN_REMAP_LO_OFF;
+ else
+ return MVEBU_MBUS_NO_REMAP;
+}
+
+/*
+ * Use the memblock information to find the MBus bridge hole in the
+ * physical address space.
+ */
+static void __init
+mvebu_mbus_find_bridge_hole(uint64_t *start, uint64_t *end)
+{
+ struct memblock_region *r;
+ uint64_t s = 0;
+
+ for_each_memblock(memory, r) {
+ /*
+ * This part of the memory is above 4 GB, so we don't
+ * care for the MBus bridge hole.
+ */
+ if (r->base >= 0x100000000)
+ continue;
+
+ /*
+ * The MBus bridge hole is at the end of the RAM under
+ * the 4 GB limit.
+ */
+ if (r->base + r->size > s)
+ s = r->base + r->size;
+ }
+
+ *start = s;
+ *end = 0x100000000;
+}
+
static void __init
mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
{
int i;
int cs;
+ uint64_t mbus_bridge_base, mbus_bridge_end;
mvebu_mbus_dram_info.mbus_dram_target_id = TARGET_DDR;
+ mvebu_mbus_find_bridge_hole(&mbus_bridge_base, &mbus_bridge_end);
+
for (i = 0, cs = 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));
+ u64 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
+ u64 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
+ u64 end;
+ struct mbus_dram_window *w;
+
+ /* Ignore entries that are not enabled */
+ if (!(size & DDR_SIZE_ENABLED))
+ continue;
/*
- * We only take care of entries for which the chip
- * select is enabled, and that don't have high base
- * address bits set (devices can only access the first
- * 32 bits of the memory).
+ * Ignore entries whose base address is above 2^32,
+ * since devices cannot DMA to such high addresses
*/
- if ((size & DDR_SIZE_ENABLED) &&
- !(base & DDR_BASE_CS_HIGH_MASK)) {
- struct mbus_dram_window *w;
+ if (base & DDR_BASE_CS_HIGH_MASK)
+ continue;
- w = &mvebu_mbus_dram_info.cs[cs++];
- w->cs_index = i;
- w->mbus_attr = 0xf & ~(1 << i);
- if (mbus->hw_io_coherency)
- w->mbus_attr |= ATTR_HW_COHERENCY;
- w->base = base & DDR_BASE_CS_LOW_MASK;
- w->size = (size | ~DDR_SIZE_MASK) + 1;
+ base = base & DDR_BASE_CS_LOW_MASK;
+ size = (size | ~DDR_SIZE_MASK) + 1;
+ end = base + size;
+
+ /*
+ * Adjust base/size of the current CS to make sure it
+ * doesn't overlap with the MBus bridge hole. This is
+ * particularly important for devices that do DMA from
+ * DRAM to a SRAM mapped in a MBus window, such as the
+ * CESA cryptographic engine.
+ */
+
+ /*
+ * The CS is fully enclosed inside the MBus bridge
+ * area, so ignore it.
+ */
+ if (base >= mbus_bridge_base && end <= mbus_bridge_end)
+ continue;
+
+ /*
+ * Beginning of CS overlaps with end of MBus, raise CS
+ * base address, and shrink its size.
+ */
+ if (base >= mbus_bridge_base && end > mbus_bridge_end) {
+ size -= mbus_bridge_end - base;
+ base = mbus_bridge_end;
}
+
+ /*
+ * End of CS overlaps with beginning of MBus, shrink
+ * CS size.
+ */
+ if (base < mbus_bridge_base && end > mbus_bridge_base)
+ size -= end - mbus_bridge_base;
+
+ w = &mvebu_mbus_dram_info.cs[cs++];
+ w->cs_index = i;
+ w->mbus_attr = 0xf & ~(1 << i);
+ if (mbus->hw_io_coherency)
+ w->mbus_attr |= ATTR_HW_COHERENCY;
+ w->base = base;
+ w->size = size;
}
mvebu_mbus_dram_info.num_cs = cs;
}
@@ -632,30 +756,40 @@ 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 = {
+static const struct mvebu_mbus_soc_data armada_370_mbus_data = {
.num_wins = 20,
- .num_remappable_wins = 8,
.has_mbus_bridge = true,
- .win_cfg_offset = armada_370_xp_mbus_win_offset,
+ .win_cfg_offset = armada_370_xp_mbus_win_cfg_offset,
+ .win_remap_offset = generic_mbus_win_remap_8_offset,
+ .setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
+ .show_cpu_target = mvebu_sdram_debug_show_orion,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
+};
+
+static const struct mvebu_mbus_soc_data armada_xp_mbus_data = {
+ .num_wins = 20,
+ .has_mbus_bridge = true,
+ .win_cfg_offset = armada_370_xp_mbus_win_cfg_offset,
+ .win_remap_offset = armada_xp_mbus_win_remap_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
+ .save_cpu_target = mvebu_mbus_default_save_cpu_target,
};
static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
.num_wins = 8,
- .num_remappable_wins = 4,
- .win_cfg_offset = orion_mbus_win_offset,
+ .win_cfg_offset = generic_mbus_win_cfg_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
+ .win_remap_offset = generic_mbus_win_remap_4_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
static const struct mvebu_mbus_soc_data dove_mbus_data = {
.num_wins = 8,
- .num_remappable_wins = 4,
- .win_cfg_offset = orion_mbus_win_offset,
+ .win_cfg_offset = generic_mbus_win_cfg_offset,
.save_cpu_target = mvebu_mbus_dove_save_cpu_target,
+ .win_remap_offset = generic_mbus_win_remap_4_offset,
.setup_cpu_target = mvebu_mbus_dove_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_dove,
};
@@ -666,36 +800,40 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = {
*/
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,
+ .win_cfg_offset = generic_mbus_win_cfg_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
+ .win_remap_offset = generic_mbus_win_remap_4_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
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,
+ .win_cfg_offset = generic_mbus_win_cfg_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
+ .win_remap_offset = generic_mbus_win_remap_2_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
.num_wins = 14,
- .num_remappable_wins = 8,
- .win_cfg_offset = mv78xx0_mbus_win_offset,
+ .win_cfg_offset = mv78xx0_mbus_win_cfg_offset,
.save_cpu_target = mvebu_mbus_default_save_cpu_target,
+ .win_remap_offset = generic_mbus_win_remap_8_offset,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
static const struct of_device_id of_mvebu_mbus_ids[] = {
{ .compatible = "marvell,armada370-mbus",
- .data = &armada_370_xp_mbus_data, },
+ .data = &armada_370_mbus_data, },
+ { .compatible = "marvell,armada375-mbus",
+ .data = &armada_xp_mbus_data, },
+ { .compatible = "marvell,armada380-mbus",
+ .data = &armada_xp_mbus_data, },
{ .compatible = "marvell,armadaxp-mbus",
- .data = &armada_370_xp_mbus_data, },
+ .data = &armada_xp_mbus_data, },
{ .compatible = "marvell,kirkwood-mbus",
.data = &kirkwood_mbus_data, },
{ .compatible = "marvell,dove-mbus",
@@ -802,15 +940,19 @@ static int mvebu_mbus_suspend(void)
for (win = 0; win < s->soc->num_wins; win++) {
void __iomem *addr = s->mbuswins_base +
s->soc->win_cfg_offset(win);
+ void __iomem *addr_rmp;
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)
+ if (!mvebu_mbus_window_is_remappable(s, win))
continue;
- s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF);
- s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF);
+ addr_rmp = s->mbuswins_base +
+ s->soc->win_remap_offset(win);
+
+ s->wins[win].remap_lo = readl(addr_rmp + WIN_REMAP_LO_OFF);
+ s->wins[win].remap_hi = readl(addr_rmp + WIN_REMAP_HI_OFF);
}
s->mbus_bridge_ctrl = readl(s->mbusbridge_base +
@@ -834,15 +976,19 @@ static void mvebu_mbus_resume(void)
for (win = 0; win < s->soc->num_wins; win++) {
void __iomem *addr = s->mbuswins_base +
s->soc->win_cfg_offset(win);
+ void __iomem *addr_rmp;
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)
+ if (!mvebu_mbus_window_is_remappable(s, win))
continue;
- writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF);
- writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF);
+ addr_rmp = s->mbuswins_base +
+ s->soc->win_remap_offset(win);
+
+ writel(s->wins[win].remap_lo, addr_rmp + WIN_REMAP_LO_OFF);
+ writel(s->wins[win].remap_hi, addr_rmp + WIN_REMAP_HI_OFF);
}
}
@@ -857,7 +1003,8 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
phys_addr_t sdramwins_phys_base,
size_t sdramwins_size,
phys_addr_t mbusbridge_phys_base,
- size_t mbusbridge_size)
+ size_t mbusbridge_size,
+ bool is_coherent)
{
int win;
@@ -889,6 +1036,10 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
mbus->soc->setup_cpu_target(mbus);
+ if (is_coherent)
+ writel(UNIT_SYNC_BARRIER_ALL,
+ mbus->mbuswins_base + UNIT_SYNC_BARRIER_OFF);
+
register_syscore_ops(&mvebu_mbus_syscore_ops);
return 0;
@@ -916,7 +1067,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, 0, 0);
+ sdramwins_size, 0, 0, false);
}
#ifdef CONFIG_OF
@@ -1118,7 +1269,8 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
sdramwins_res.start,
resource_size(&sdramwins_res),
mbusbridge_res.start,
- resource_size(&mbusbridge_res));
+ resource_size(&mbusbridge_res),
+ is_coherent);
if (ret)
return ret;
diff --git a/drivers/char/Kconfig b/drivers/char/Kconfig
index efefd12a0f7b..a4af8221751e 100644
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -6,6 +6,15 @@ menu "Character devices"
source "drivers/tty/Kconfig"
+config DEVMEM
+ bool "/dev/mem virtual device support"
+ default y
+ help
+ Say Y here if you want to support the /dev/mem device.
+ The /dev/mem device is used to access areas of physical
+ memory.
+ When in doubt, say "Y".
+
config DEVKMEM
bool "/dev/kmem virtual device support"
default y
diff --git a/drivers/char/agp/agp.h b/drivers/char/agp/agp.h
index b709749c8639..4eb1c772ded7 100644
--- a/drivers/char/agp/agp.h
+++ b/drivers/char/agp/agp.h
@@ -219,7 +219,10 @@ struct agp_bridge_data *agp_generic_find_bridge(struct pci_dev *pdev);
/* generic functions for user-populated AGP memory types */
struct agp_memory *agp_generic_alloc_user(size_t page_count, int type);
void agp_alloc_page_array(size_t size, struct agp_memory *mem);
-void agp_free_page_array(struct agp_memory *mem);
+static inline void agp_free_page_array(struct agp_memory *mem)
+{
+ kvfree(mem->pages);
+}
/* generic routines for agp>=3 */
diff --git a/drivers/char/agp/generic.c b/drivers/char/agp/generic.c
index 0fbccce1cee9..f002fa5d1887 100644
--- a/drivers/char/agp/generic.c
+++ b/drivers/char/agp/generic.c
@@ -98,17 +98,6 @@ void agp_alloc_page_array(size_t size, struct agp_memory *mem)
}
EXPORT_SYMBOL(agp_alloc_page_array);
-void agp_free_page_array(struct agp_memory *mem)
-{
- if (is_vmalloc_addr(mem->pages)) {
- vfree(mem->pages);
- } else {
- kfree(mem->pages);
- }
-}
-EXPORT_SYMBOL(agp_free_page_array);
-
-
static struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages)
{
struct agp_memory *new;
diff --git a/drivers/char/agp/intel-gtt.c b/drivers/char/agp/intel-gtt.c
index 92aa43fa8d70..0b4188b9af7c 100644
--- a/drivers/char/agp/intel-gtt.c
+++ b/drivers/char/agp/intel-gtt.c
@@ -225,7 +225,7 @@ static int i810_insert_dcache_entries(struct agp_memory *mem, off_t pg_start,
intel_private.driver->write_entry(addr,
i, type);
}
- readl(intel_private.gtt+i-1);
+ wmb();
return 0;
}
@@ -329,7 +329,7 @@ static void i810_write_entry(dma_addr_t addr, unsigned int entry,
break;
}
- writel(addr | pte_flags, intel_private.gtt + entry);
+ writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
}
static const struct aper_size_info_fixed intel_fake_agp_sizes[] = {
@@ -735,7 +735,7 @@ static void i830_write_entry(dma_addr_t addr, unsigned int entry,
if (flags == AGP_USER_CACHED_MEMORY)
pte_flags |= I830_PTE_SYSTEM_CACHED;
- writel(addr | pte_flags, intel_private.gtt + entry);
+ writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
}
bool intel_enable_gtt(void)
@@ -858,7 +858,7 @@ void intel_gtt_insert_sg_entries(struct sg_table *st,
j++;
}
}
- readl(intel_private.gtt+j-1);
+ wmb();
}
EXPORT_SYMBOL(intel_gtt_insert_sg_entries);
@@ -875,7 +875,7 @@ static void intel_gtt_insert_pages(unsigned int first_entry,
intel_private.driver->write_entry(addr,
j, flags);
}
- readl(intel_private.gtt+j-1);
+ wmb();
}
static int intel_fake_agp_insert_entries(struct agp_memory *mem,
@@ -938,7 +938,7 @@ void intel_gtt_clear_range(unsigned int first_entry, unsigned int num_entries)
intel_private.driver->write_entry(intel_private.scratch_page_dma,
i, 0);
}
- readl(intel_private.gtt+i-1);
+ wmb();
}
EXPORT_SYMBOL(intel_gtt_clear_range);
@@ -1106,7 +1106,7 @@ static void i965_write_entry(dma_addr_t addr,
/* Shift high bits down */
addr |= (addr >> 28) & 0xf0;
- writel(addr | pte_flags, intel_private.gtt + entry);
+ writel_relaxed(addr | pte_flags, intel_private.gtt + entry);
}
static int i9xx_setup(void)
diff --git a/drivers/char/hpet.c b/drivers/char/hpet.c
index d5d4cd82b9f7..5c0baa9ffc64 100644
--- a/drivers/char/hpet.c
+++ b/drivers/char/hpet.c
@@ -976,8 +976,8 @@ static acpi_status hpet_resources(struct acpi_resource *res, void *data)
status = acpi_resource_to_address64(res, &addr);
if (ACPI_SUCCESS(status)) {
- hdp->hd_phys_address = addr.minimum;
- hdp->hd_address = ioremap(addr.minimum, addr.address_length);
+ hdp->hd_phys_address = addr.address.minimum;
+ hdp->hd_address = ioremap(addr.address.minimum, addr.address.address_length);
if (hpet_is_known(hdp)) {
iounmap(hdp->hd_address);
diff --git a/drivers/char/hw_random/core.c b/drivers/char/hw_random/core.c
index 1500cfd799a7..32a8a867f7f8 100644
--- a/drivers/char/hw_random/core.c
+++ b/drivers/char/hw_random/core.c
@@ -42,6 +42,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/random.h>
+#include <linux/err.h>
#include <asm/uaccess.h>
@@ -53,7 +54,10 @@
static struct hwrng *current_rng;
static struct task_struct *hwrng_fill;
static LIST_HEAD(rng_list);
+/* Protects rng_list and current_rng */
static DEFINE_MUTEX(rng_mutex);
+/* Protects rng read functions, data_avail, rng_buffer and rng_fillbuf */
+static DEFINE_MUTEX(reading_mutex);
static int data_avail;
static u8 *rng_buffer, *rng_fillbuf;
static unsigned short current_quality;
@@ -66,6 +70,8 @@ module_param(default_quality, ushort, 0644);
MODULE_PARM_DESC(default_quality,
"default entropy content of hwrng per mill");
+static void drop_current_rng(void);
+static int hwrng_init(struct hwrng *rng);
static void start_khwrngd(void);
static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
@@ -81,13 +87,83 @@ static void add_early_randomness(struct hwrng *rng)
unsigned char bytes[16];
int bytes_read;
+ mutex_lock(&reading_mutex);
bytes_read = rng_get_data(rng, bytes, sizeof(bytes), 1);
+ mutex_unlock(&reading_mutex);
if (bytes_read > 0)
add_device_randomness(bytes, bytes_read);
}
-static inline int hwrng_init(struct hwrng *rng)
+static inline void cleanup_rng(struct kref *kref)
{
+ struct hwrng *rng = container_of(kref, struct hwrng, ref);
+
+ if (rng->cleanup)
+ rng->cleanup(rng);
+
+ complete(&rng->cleanup_done);
+}
+
+static int set_current_rng(struct hwrng *rng)
+{
+ int err;
+
+ BUG_ON(!mutex_is_locked(&rng_mutex));
+
+ err = hwrng_init(rng);
+ if (err)
+ return err;
+
+ drop_current_rng();
+ current_rng = rng;
+
+ return 0;
+}
+
+static void drop_current_rng(void)
+{
+ BUG_ON(!mutex_is_locked(&rng_mutex));
+ if (!current_rng)
+ return;
+
+ /* decrease last reference for triggering the cleanup */
+ kref_put(&current_rng->ref, cleanup_rng);
+ current_rng = NULL;
+}
+
+/* Returns ERR_PTR(), NULL or refcounted hwrng */
+static struct hwrng *get_current_rng(void)
+{
+ struct hwrng *rng;
+
+ if (mutex_lock_interruptible(&rng_mutex))
+ return ERR_PTR(-ERESTARTSYS);
+
+ rng = current_rng;
+ if (rng)
+ kref_get(&rng->ref);
+
+ mutex_unlock(&rng_mutex);
+ return rng;
+}
+
+static void put_rng(struct hwrng *rng)
+{
+ /*
+ * Hold rng_mutex here so we serialize in case they set_current_rng
+ * on rng again immediately.
+ */
+ mutex_lock(&rng_mutex);
+ if (rng)
+ kref_put(&rng->ref, cleanup_rng);
+ mutex_unlock(&rng_mutex);
+}
+
+static int hwrng_init(struct hwrng *rng)
+{
+ if (kref_get_unless_zero(&rng->ref))
+ goto skip_init;
+
if (rng->init) {
int ret;
@@ -95,6 +171,11 @@ static inline int hwrng_init(struct hwrng *rng)
if (ret)
return ret;
}
+
+ kref_init(&rng->ref);
+ reinit_completion(&rng->cleanup_done);
+
+skip_init:
add_early_randomness(rng);
current_quality = rng->quality ? : default_quality;
@@ -108,12 +189,6 @@ static inline int hwrng_init(struct hwrng *rng)
return 0;
}
-static inline void hwrng_cleanup(struct hwrng *rng)
-{
- if (rng && rng->cleanup)
- rng->cleanup(rng);
-}
-
static int rng_dev_open(struct inode *inode, struct file *filp)
{
/* enforce read-only access to this chrdev */
@@ -128,6 +203,7 @@ static inline int rng_get_data(struct hwrng *rng, u8 *buffer, size_t size,
int wait) {
int present;
+ BUG_ON(!mutex_is_locked(&reading_mutex));
if (rng->read)
return rng->read(rng, (void *)buffer, size, wait);
@@ -148,25 +224,27 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
ssize_t ret = 0;
int err = 0;
int bytes_read, len;
+ struct hwrng *rng;
while (size) {
- if (mutex_lock_interruptible(&rng_mutex)) {
- err = -ERESTARTSYS;
+ rng = get_current_rng();
+ if (IS_ERR(rng)) {
+ err = PTR_ERR(rng);
goto out;
}
-
- if (!current_rng) {
+ if (!rng) {
err = -ENODEV;
- goto out_unlock;
+ goto out;
}
+ mutex_lock(&reading_mutex);
if (!data_avail) {
- bytes_read = rng_get_data(current_rng, rng_buffer,
+ bytes_read = rng_get_data(rng, rng_buffer,
rng_buffer_size(),
!(filp->f_flags & O_NONBLOCK));
if (bytes_read < 0) {
err = bytes_read;
- goto out_unlock;
+ goto out_unlock_reading;
}
data_avail = bytes_read;
}
@@ -174,7 +252,7 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
if (!data_avail) {
if (filp->f_flags & O_NONBLOCK) {
err = -EAGAIN;
- goto out_unlock;
+ goto out_unlock_reading;
}
} else {
len = data_avail;
@@ -186,14 +264,15 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
if (copy_to_user(buf + ret, rng_buffer + data_avail,
len)) {
err = -EFAULT;
- goto out_unlock;
+ goto out_unlock_reading;
}
size -= len;
ret += len;
}
- mutex_unlock(&rng_mutex);
+ mutex_unlock(&reading_mutex);
+ put_rng(rng);
if (need_resched())
schedule_timeout_interruptible(1);
@@ -205,8 +284,10 @@ static ssize_t rng_dev_read(struct file *filp, char __user *buf,
}
out:
return ret ? : err;
-out_unlock:
- mutex_unlock(&rng_mutex);
+
+out_unlock_reading:
+ mutex_unlock(&reading_mutex);
+ put_rng(rng);
goto out;
}
@@ -239,16 +320,9 @@ static ssize_t hwrng_attr_current_store(struct device *dev,
err = -ENODEV;
list_for_each_entry(rng, &rng_list, list) {
if (strcmp(rng->name, buf) == 0) {
- if (rng == current_rng) {
- err = 0;
- break;
- }
- err = hwrng_init(rng);
- if (err)
- break;
- hwrng_cleanup(current_rng);
- current_rng = rng;
err = 0;
+ if (rng != current_rng)
+ err = set_current_rng(rng);
break;
}
}
@@ -261,17 +335,15 @@ static ssize_t hwrng_attr_current_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- int err;
ssize_t ret;
- const char *name = "none";
+ struct hwrng *rng;
- err = mutex_lock_interruptible(&rng_mutex);
- if (err)
- return -ERESTARTSYS;
- if (current_rng)
- name = current_rng->name;
- ret = snprintf(buf, PAGE_SIZE, "%s\n", name);
- mutex_unlock(&rng_mutex);
+ rng = get_current_rng();
+ if (IS_ERR(rng))
+ return PTR_ERR(rng);
+
+ ret = snprintf(buf, PAGE_SIZE, "%s\n", rng ? rng->name : "none");
+ put_rng(rng);
return ret;
}
@@ -305,14 +377,14 @@ static DEVICE_ATTR(rng_available, S_IRUGO,
NULL);
-static void unregister_miscdev(void)
+static void __exit unregister_miscdev(void)
{
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_available);
device_remove_file(rng_miscdev.this_device, &dev_attr_rng_current);
misc_deregister(&rng_miscdev);
}
-static int register_miscdev(void)
+static int __init register_miscdev(void)
{
int err;
@@ -342,15 +414,22 @@ static int hwrng_fillfn(void *unused)
long rc;
while (!kthread_should_stop()) {
- if (!current_rng)
+ struct hwrng *rng;
+
+ rng = get_current_rng();
+ if (IS_ERR(rng) || !rng)
break;
- rc = rng_get_data(current_rng, rng_fillbuf,
+ mutex_lock(&reading_mutex);
+ rc = rng_get_data(rng, rng_fillbuf,
rng_buffer_size(), 1);
+ mutex_unlock(&reading_mutex);
+ put_rng(rng);
if (rc <= 0) {
pr_warn("hwrng: no data available\n");
msleep_interruptible(10000);
continue;
}
+ /* Outside lock, sure, but y'know: randomness. */
add_hwgenerator_randomness((void *)rng_fillbuf, rc,
rc * current_quality * 8 >> 10);
}
@@ -400,23 +479,16 @@ int hwrng_register(struct hwrng *rng)
goto out_unlock;
}
+ init_completion(&rng->cleanup_done);
+ complete(&rng->cleanup_done);
+
old_rng = current_rng;
- if (!old_rng) {
- err = hwrng_init(rng);
- if (err)
- goto out_unlock;
- current_rng = rng;
- }
err = 0;
if (!old_rng) {
- err = register_miscdev();
- if (err) {
- hwrng_cleanup(rng);
- current_rng = NULL;
+ err = set_current_rng(rng);
+ if (err)
goto out_unlock;
- }
}
- INIT_LIST_HEAD(&rng->list);
list_add_tail(&rng->list, &rng_list);
if (old_rng && !rng->init) {
@@ -439,42 +511,49 @@ EXPORT_SYMBOL_GPL(hwrng_register);
void hwrng_unregister(struct hwrng *rng)
{
- int err;
-
mutex_lock(&rng_mutex);
list_del(&rng->list);
if (current_rng == rng) {
- hwrng_cleanup(rng);
- if (list_empty(&rng_list)) {
- current_rng = NULL;
- } else {
- current_rng = list_entry(rng_list.prev, struct hwrng, list);
- err = hwrng_init(current_rng);
- if (err)
- current_rng = NULL;
+ drop_current_rng();
+ if (!list_empty(&rng_list)) {
+ struct hwrng *tail;
+
+ tail = list_entry(rng_list.prev, struct hwrng, list);
+
+ set_current_rng(tail);
}
}
+
if (list_empty(&rng_list)) {
- unregister_miscdev();
+ mutex_unlock(&rng_mutex);
if (hwrng_fill)
kthread_stop(hwrng_fill);
- }
+ } else
+ mutex_unlock(&rng_mutex);
- mutex_unlock(&rng_mutex);
+ wait_for_completion(&rng->cleanup_done);
}
EXPORT_SYMBOL_GPL(hwrng_unregister);
-static void __exit hwrng_exit(void)
+static int __init hwrng_modinit(void)
+{
+ return register_miscdev();
+}
+
+static void __exit hwrng_modexit(void)
{
mutex_lock(&rng_mutex);
BUG_ON(current_rng);
kfree(rng_buffer);
kfree(rng_fillbuf);
mutex_unlock(&rng_mutex);
+
+ unregister_miscdev();
}
-module_exit(hwrng_exit);
+module_init(hwrng_modinit);
+module_exit(hwrng_modexit);
MODULE_DESCRIPTION("H/W Random Number Generator (RNG) driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/hw_random/virtio-rng.c b/drivers/char/hw_random/virtio-rng.c
index 72295ea2fd1c..3fa2f8a009b3 100644
--- a/drivers/char/hw_random/virtio-rng.c
+++ b/drivers/char/hw_random/virtio-rng.c
@@ -39,7 +39,6 @@ struct virtrng_info {
bool hwrng_removed;
};
-
static void random_recv_done(struct virtqueue *vq)
{
struct virtrng_info *vi = vq->vdev->priv;
diff --git a/drivers/char/i8k.c b/drivers/char/i8k.c
index e34a019eb930..24cc4ed9a780 100644
--- a/drivers/char/i8k.c
+++ b/drivers/char/i8k.c
@@ -5,7 +5,8 @@
*
* Hwmon integration:
* Copyright (C) 2011 Jean Delvare <jdelvare@suse.de>
- * Copyright (C) 2013 Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2013, 2014 Guenter Roeck <linux@roeck-us.net>
+ * Copyright (C) 2014 Pali Rohár <pali.rohar@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
@@ -20,6 +21,7 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+#include <linux/delay.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
@@ -41,11 +43,15 @@
#define I8K_SMM_SET_FAN 0x01a3
#define I8K_SMM_GET_FAN 0x00a3
#define I8K_SMM_GET_SPEED 0x02a3
+#define I8K_SMM_GET_FAN_TYPE 0x03a3
+#define I8K_SMM_GET_NOM_SPEED 0x04a3
#define I8K_SMM_GET_TEMP 0x10a3
+#define I8K_SMM_GET_TEMP_TYPE 0x11a3
#define I8K_SMM_GET_DELL_SIG1 0xfea3
#define I8K_SMM_GET_DELL_SIG2 0xffa3
#define I8K_FAN_MULT 30
+#define I8K_FAN_MAX_RPM 30000
#define I8K_MAX_TEMP 127
#define I8K_FN_NONE 0x00
@@ -58,15 +64,13 @@
#define I8K_POWER_AC 0x05
#define I8K_POWER_BATTERY 0x01
-#define I8K_TEMPERATURE_BUG 1
-
static DEFINE_MUTEX(i8k_mutex);
static char bios_version[4];
static struct device *i8k_hwmon_dev;
static u32 i8k_hwmon_flags;
-static int i8k_fan_mult;
-static int i8k_pwm_mult;
-static int i8k_fan_max = I8K_FAN_HIGH;
+static uint i8k_fan_mult = I8K_FAN_MULT;
+static uint i8k_pwm_mult;
+static uint i8k_fan_max = I8K_FAN_HIGH;
#define I8K_HWMON_HAVE_TEMP1 (1 << 0)
#define I8K_HWMON_HAVE_TEMP2 (1 << 1)
@@ -95,13 +99,13 @@ static bool power_status;
module_param(power_status, bool, 0600);
MODULE_PARM_DESC(power_status, "Report power status in /proc/i8k");
-static int fan_mult = I8K_FAN_MULT;
-module_param(fan_mult, int, 0);
-MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with");
+static uint fan_mult;
+module_param(fan_mult, uint, 0);
+MODULE_PARM_DESC(fan_mult, "Factor to multiply fan speed with (default: autodetect)");
-static int fan_max = I8K_FAN_HIGH;
-module_param(fan_max, int, 0);
-MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed");
+static uint fan_max;
+module_param(fan_max, uint, 0);
+MODULE_PARM_DESC(fan_max, "Maximum configurable fan speed (default: autodetect)");
static int i8k_open_fs(struct inode *inode, struct file *file);
static long i8k_ioctl(struct file *, unsigned int, unsigned long);
@@ -276,6 +280,28 @@ static int i8k_get_fan_speed(int fan)
}
/*
+ * Read the fan type.
+ */
+static int i8k_get_fan_type(int fan)
+{
+ struct smm_regs regs = { .eax = I8K_SMM_GET_FAN_TYPE, };
+
+ regs.ebx = fan & 0xff;
+ return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
+/*
+ * Read the fan nominal rpm for specific fan speed.
+ */
+static int i8k_get_fan_nominal_speed(int fan, int speed)
+{
+ struct smm_regs regs = { .eax = I8K_SMM_GET_NOM_SPEED, };
+
+ regs.ebx = (fan & 0xff) | (speed << 8);
+ return i8k_smm(&regs) ? : (regs.eax & 0xffff) * i8k_fan_mult;
+}
+
+/*
* Set the fan speed (off, low, high). Returns the new fan status.
*/
static int i8k_set_fan(int fan, int speed)
@@ -288,42 +314,52 @@ static int i8k_set_fan(int fan, int speed)
return i8k_smm(&regs) ? : i8k_get_fan_status(fan);
}
+static int i8k_get_temp_type(int sensor)
+{
+ struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP_TYPE, };
+
+ regs.ebx = sensor & 0xff;
+ return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
+
/*
* Read the cpu temperature.
*/
-static int i8k_get_temp(int sensor)
+static int _i8k_get_temp(int sensor)
{
- struct smm_regs regs = { .eax = I8K_SMM_GET_TEMP, };
- int rc;
- int temp;
+ struct smm_regs regs = {
+ .eax = I8K_SMM_GET_TEMP,
+ .ebx = sensor & 0xff,
+ };
-#ifdef I8K_TEMPERATURE_BUG
- static int prev[4] = { I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1, I8K_MAX_TEMP+1 };
-#endif
- regs.ebx = sensor & 0xff;
- rc = i8k_smm(&regs);
- if (rc < 0)
- return rc;
+ return i8k_smm(&regs) ? : regs.eax & 0xff;
+}
- temp = regs.eax & 0xff;
+static int i8k_get_temp(int sensor)
+{
+ int temp = _i8k_get_temp(sensor);
-#ifdef I8K_TEMPERATURE_BUG
/*
* Sometimes the temperature sensor returns 0x99, which is out of range.
- * In this case we return (once) the previous cached value. For example:
+ * In this case we retry (once) before returning an error.
# 1003655137 00000058 00005a4b
# 1003655138 00000099 00003a80 <--- 0x99 = 153 degrees
# 1003655139 00000054 00005c52
*/
- if (temp > I8K_MAX_TEMP) {
- temp = prev[sensor];
- prev[sensor] = I8K_MAX_TEMP+1;
- } else {
- prev[sensor] = temp;
+ if (temp == 0x99) {
+ msleep(100);
+ temp = _i8k_get_temp(sensor);
}
+ /*
+ * Return -ENODATA for all invalid temperatures.
+ *
+ * Known instances are the 0x99 value as seen above as well as
+ * 0xc1 (193), which may be returned when trying to read the GPU
+ * temperature if the system supports a GPU and it is currently
+ * turned off.
+ */
if (temp > I8K_MAX_TEMP)
- return -ERANGE;
-#endif
+ return -ENODATA;
return temp;
}
@@ -493,6 +529,29 @@ static int i8k_open_fs(struct inode *inode, struct file *file)
* Hwmon interface
*/
+static ssize_t i8k_hwmon_show_temp_label(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ static const char * const labels[] = {
+ "CPU",
+ "GPU",
+ "SODIMM",
+ "Other",
+ "Ambient",
+ "Other",
+ };
+ int index = to_sensor_dev_attr(devattr)->index;
+ int type;
+
+ type = i8k_get_temp_type(index);
+ if (type < 0)
+ return type;
+ if (type >= ARRAY_SIZE(labels))
+ type = ARRAY_SIZE(labels) - 1;
+ return sprintf(buf, "%s\n", labels[type]);
+}
+
static ssize_t i8k_hwmon_show_temp(struct device *dev,
struct device_attribute *devattr,
char *buf)
@@ -501,13 +560,42 @@ static ssize_t i8k_hwmon_show_temp(struct device *dev,
int temp;
temp = i8k_get_temp(index);
- if (temp == -ERANGE)
- return -EINVAL;
if (temp < 0)
return temp;
return sprintf(buf, "%d\n", temp * 1000);
}
+static ssize_t i8k_hwmon_show_fan_label(struct device *dev,
+ struct device_attribute *devattr,
+ char *buf)
+{
+ static const char * const labels[] = {
+ "Processor Fan",
+ "Motherboard Fan",
+ "Video Fan",
+ "Power Supply Fan",
+ "Chipset Fan",
+ "Other Fan",
+ };
+ int index = to_sensor_dev_attr(devattr)->index;
+ bool dock = false;
+ int type;
+
+ type = i8k_get_fan_type(index);
+ if (type < 0)
+ return type;
+
+ if (type & 0x10) {
+ dock = true;
+ type &= 0x0F;
+ }
+
+ if (type >= ARRAY_SIZE(labels))
+ type = (ARRAY_SIZE(labels) - 1);
+
+ return sprintf(buf, "%s%s\n", (dock ? "Docking " : ""), labels[type]);
+}
+
static ssize_t i8k_hwmon_show_fan(struct device *dev,
struct device_attribute *devattr,
char *buf)
@@ -555,45 +643,66 @@ static ssize_t i8k_hwmon_set_pwm(struct device *dev,
}
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 0);
+static SENSOR_DEVICE_ATTR(temp1_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+ 0);
static SENSOR_DEVICE_ATTR(temp2_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 1);
+static SENSOR_DEVICE_ATTR(temp2_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+ 1);
static SENSOR_DEVICE_ATTR(temp3_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp3_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+ 2);
static SENSOR_DEVICE_ATTR(temp4_input, S_IRUGO, i8k_hwmon_show_temp, NULL, 3);
-static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
- I8K_FAN_LEFT);
+static SENSOR_DEVICE_ATTR(temp4_label, S_IRUGO, i8k_hwmon_show_temp_label, NULL,
+ 3);
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, i8k_hwmon_show_fan, NULL, 0);
+static SENSOR_DEVICE_ATTR(fan1_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+ 0);
static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
- i8k_hwmon_set_pwm, I8K_FAN_LEFT);
+ i8k_hwmon_set_pwm, 0);
static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, i8k_hwmon_show_fan, NULL,
- I8K_FAN_RIGHT);
+ 1);
+static SENSOR_DEVICE_ATTR(fan2_label, S_IRUGO, i8k_hwmon_show_fan_label, NULL,
+ 1);
static SENSOR_DEVICE_ATTR(pwm2, S_IRUGO | S_IWUSR, i8k_hwmon_show_pwm,
- i8k_hwmon_set_pwm, I8K_FAN_RIGHT);
+ i8k_hwmon_set_pwm, 1);
static struct attribute *i8k_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr, /* 0 */
- &sensor_dev_attr_temp2_input.dev_attr.attr, /* 1 */
- &sensor_dev_attr_temp3_input.dev_attr.attr, /* 2 */
- &sensor_dev_attr_temp4_input.dev_attr.attr, /* 3 */
- &sensor_dev_attr_fan1_input.dev_attr.attr, /* 4 */
- &sensor_dev_attr_pwm1.dev_attr.attr, /* 5 */
- &sensor_dev_attr_fan2_input.dev_attr.attr, /* 6 */
- &sensor_dev_attr_pwm2.dev_attr.attr, /* 7 */
+ &sensor_dev_attr_temp1_label.dev_attr.attr, /* 1 */
+ &sensor_dev_attr_temp2_input.dev_attr.attr, /* 2 */
+ &sensor_dev_attr_temp2_label.dev_attr.attr, /* 3 */
+ &sensor_dev_attr_temp3_input.dev_attr.attr, /* 4 */
+ &sensor_dev_attr_temp3_label.dev_attr.attr, /* 5 */
+ &sensor_dev_attr_temp4_input.dev_attr.attr, /* 6 */
+ &sensor_dev_attr_temp4_label.dev_attr.attr, /* 7 */
+ &sensor_dev_attr_fan1_input.dev_attr.attr, /* 8 */
+ &sensor_dev_attr_fan1_label.dev_attr.attr, /* 9 */
+ &sensor_dev_attr_pwm1.dev_attr.attr, /* 10 */
+ &sensor_dev_attr_fan2_input.dev_attr.attr, /* 11 */
+ &sensor_dev_attr_fan2_label.dev_attr.attr, /* 12 */
+ &sensor_dev_attr_pwm2.dev_attr.attr, /* 13 */
NULL
};
static umode_t i8k_is_visible(struct kobject *kobj, struct attribute *attr,
int index)
{
- if (index == 0 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
+ if (index >= 0 && index <= 1 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP1))
return 0;
- if (index == 1 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
+ if (index >= 2 && index <= 3 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP2))
return 0;
- if (index == 2 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
+ if (index >= 4 && index <= 5 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP3))
return 0;
- if (index == 3 && !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
+ if (index >= 6 && index <= 7 &&
+ !(i8k_hwmon_flags & I8K_HWMON_HAVE_TEMP4))
return 0;
- if (index >= 4 && index <= 5 &&
+ if (index >= 8 && index <= 10 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN1))
return 0;
- if (index >= 6 && index <= 7 &&
+ if (index >= 11 && index <= 13 &&
!(i8k_hwmon_flags & I8K_HWMON_HAVE_FAN2))
return 0;
@@ -612,28 +721,28 @@ static int __init i8k_init_hwmon(void)
i8k_hwmon_flags = 0;
- /* CPU temperature attributes, if temperature reading is OK */
- err = i8k_get_temp(0);
- if (err >= 0 || err == -ERANGE)
+ /* CPU temperature attributes, if temperature type is OK */
+ err = i8k_get_temp_type(0);
+ if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP1;
/* check for additional temperature sensors */
- err = i8k_get_temp(1);
- if (err >= 0 || err == -ERANGE)
+ err = i8k_get_temp_type(1);
+ if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP2;
- err = i8k_get_temp(2);
- if (err >= 0 || err == -ERANGE)
+ err = i8k_get_temp_type(2);
+ if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP3;
- err = i8k_get_temp(3);
- if (err >= 0 || err == -ERANGE)
+ err = i8k_get_temp_type(3);
+ if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_TEMP4;
- /* Left fan attributes, if left fan is present */
- err = i8k_get_fan_status(I8K_FAN_LEFT);
+ /* First fan attributes, if fan type is OK */
+ err = i8k_get_fan_type(0);
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN1;
- /* Right fan attributes, if right fan is present */
- err = i8k_get_fan_status(I8K_FAN_RIGHT);
+ /* Second fan attributes, if fan type is OK */
+ err = i8k_get_fan_type(1);
if (err >= 0)
i8k_hwmon_flags |= I8K_HWMON_HAVE_FAN2;
@@ -649,16 +758,15 @@ static int __init i8k_init_hwmon(void)
}
struct i8k_config_data {
- int fan_mult;
- int fan_max;
+ uint fan_mult;
+ uint fan_max;
};
enum i8k_configs {
DELL_LATITUDE_D520,
- DELL_LATITUDE_E6540,
DELL_PRECISION_490,
DELL_STUDIO,
- DELL_XPS_M140,
+ DELL_XPS,
};
static const struct i8k_config_data i8k_config_data[] = {
@@ -666,10 +774,6 @@ static const struct i8k_config_data i8k_config_data[] = {
.fan_mult = 1,
.fan_max = I8K_FAN_TURBO,
},
- [DELL_LATITUDE_E6540] = {
- .fan_mult = 1,
- .fan_max = I8K_FAN_HIGH,
- },
[DELL_PRECISION_490] = {
.fan_mult = 1,
.fan_max = I8K_FAN_TURBO,
@@ -678,7 +782,7 @@ static const struct i8k_config_data i8k_config_data[] = {
.fan_mult = 1,
.fan_max = I8K_FAN_HIGH,
},
- [DELL_XPS_M140] = {
+ [DELL_XPS] = {
.fan_mult = 1,
.fan_max = I8K_FAN_HIGH,
},
@@ -715,22 +819,6 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
.driver_data = (void *)&i8k_config_data[DELL_LATITUDE_D520],
},
{
- .ident = "Dell Latitude E6440",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6440"),
- },
- .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
- },
- {
- .ident = "Dell Latitude E6540",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "Latitude E6540"),
- },
- .driver_data = (void *)&i8k_config_data[DELL_LATITUDE_E6540],
- },
- {
.ident = "Dell Latitude 2",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
@@ -790,12 +878,20 @@ static struct dmi_system_id i8k_dmi_table[] __initdata = {
.driver_data = (void *)&i8k_config_data[DELL_STUDIO],
},
{
+ .ident = "Dell XPS 13",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XPS13"),
+ },
+ .driver_data = (void *)&i8k_config_data[DELL_XPS],
+ },
+ {
.ident = "Dell XPS M140",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "MXC051"),
},
- .driver_data = (void *)&i8k_config_data[DELL_XPS_M140],
+ .driver_data = (void *)&i8k_config_data[DELL_XPS],
},
{ }
};
@@ -808,6 +904,7 @@ MODULE_DEVICE_TABLE(dmi, i8k_dmi_table);
static int __init i8k_probe(void)
{
const struct dmi_system_id *id;
+ int fan, ret;
/*
* Get DMI information
@@ -836,19 +933,40 @@ static int __init i8k_probe(void)
return -ENODEV;
}
- i8k_fan_mult = fan_mult;
- i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
+ /*
+ * Set fan multiplier and maximal fan speed from dmi config
+ * Values specified in module parameters override values from dmi
+ */
id = dmi_first_match(i8k_dmi_table);
if (id && id->driver_data) {
const struct i8k_config_data *conf = id->driver_data;
-
- if (fan_mult == I8K_FAN_MULT && conf->fan_mult)
- i8k_fan_mult = conf->fan_mult;
- if (fan_max == I8K_FAN_HIGH && conf->fan_max)
- i8k_fan_max = conf->fan_max;
+ if (!fan_mult && conf->fan_mult)
+ fan_mult = conf->fan_mult;
+ if (!fan_max && conf->fan_max)
+ fan_max = conf->fan_max;
}
+
+ i8k_fan_max = fan_max ? : I8K_FAN_HIGH; /* Must not be 0 */
i8k_pwm_mult = DIV_ROUND_UP(255, i8k_fan_max);
+ if (!fan_mult) {
+ /*
+ * Autodetect fan multiplier based on nominal rpm
+ * If fan reports rpm value too high then set multiplier to 1
+ */
+ for (fan = 0; fan < 2; ++fan) {
+ ret = i8k_get_fan_nominal_speed(fan, i8k_fan_max);
+ if (ret < 0)
+ continue;
+ if (ret > I8K_FAN_MAX_RPM)
+ i8k_fan_mult = 1;
+ break;
+ }
+ } else {
+ /* Fan multiplier was specified in module param or in dmi */
+ i8k_fan_mult = fan_mult;
+ }
+
return 0;
}
diff --git a/drivers/char/ipmi/ipmi_devintf.c b/drivers/char/ipmi/ipmi_devintf.c
index ec318bf434a6..1786574536b2 100644
--- a/drivers/char/ipmi/ipmi_devintf.c
+++ b/drivers/char/ipmi/ipmi_devintf.c
@@ -157,12 +157,16 @@ static int ipmi_release(struct inode *inode, struct file *file)
{
struct ipmi_file_private *priv = file->private_data;
int rv;
+ struct ipmi_recv_msg *msg, *next;
rv = ipmi_destroy_user(priv->user);
if (rv)
return rv;
- /* FIXME - free the messages in the list. */
+ list_for_each_entry_safe(msg, next, &priv->recv_msgs, link)
+ ipmi_free_recv_msg(msg);
+
+
kfree(priv);
return 0;
diff --git a/drivers/char/ipmi/ipmi_msghandler.c b/drivers/char/ipmi/ipmi_msghandler.c
index 6b65fa4e0c55..9bb592872532 100644
--- a/drivers/char/ipmi/ipmi_msghandler.c
+++ b/drivers/char/ipmi/ipmi_msghandler.c
@@ -1483,14 +1483,10 @@ static inline void format_lan_msg(struct ipmi_smi_msg *smi_msg,
smi_msg->msgid = msgid;
}
-static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers,
- struct ipmi_smi_msg *smi_msg, int priority)
+static struct ipmi_smi_msg *smi_add_send_msg(ipmi_smi_t intf,
+ struct ipmi_smi_msg *smi_msg,
+ int priority)
{
- int run_to_completion = intf->run_to_completion;
- unsigned long flags;
-
- if (!run_to_completion)
- spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
if (intf->curr_msg) {
if (priority > 0)
list_add_tail(&smi_msg->link, &intf->hp_xmit_msgs);
@@ -1500,8 +1496,25 @@ static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers,
} else {
intf->curr_msg = smi_msg;
}
- if (!run_to_completion)
+
+ return smi_msg;
+}
+
+
+static void smi_send(ipmi_smi_t intf, struct ipmi_smi_handlers *handlers,
+ struct ipmi_smi_msg *smi_msg, int priority)
+{
+ int run_to_completion = intf->run_to_completion;
+
+ if (run_to_completion) {
+ smi_msg = smi_add_send_msg(intf, smi_msg, priority);
+ } else {
+ unsigned long flags;
+
+ spin_lock_irqsave(&intf->xmit_msgs_lock, flags);
+ smi_msg = smi_add_send_msg(intf, smi_msg, priority);
spin_unlock_irqrestore(&intf->xmit_msgs_lock, flags);
+ }
if (smi_msg)
handlers->sender(intf->send_info, smi_msg);
@@ -1985,7 +1998,9 @@ static int smi_ipmb_proc_show(struct seq_file *m, void *v)
seq_printf(m, "%x", intf->channels[0].address);
for (i = 1; i < IPMI_MAX_CHANNELS; i++)
seq_printf(m, " %x", intf->channels[i].address);
- return seq_putc(m, '\n');
+ seq_putc(m, '\n');
+
+ return seq_has_overflowed(m);
}
static int smi_ipmb_proc_open(struct inode *inode, struct file *file)
@@ -2004,9 +2019,11 @@ static int smi_version_proc_show(struct seq_file *m, void *v)
{
ipmi_smi_t intf = m->private;
- return seq_printf(m, "%u.%u\n",
- ipmi_version_major(&intf->bmc->id),
- ipmi_version_minor(&intf->bmc->id));
+ seq_printf(m, "%u.%u\n",
+ ipmi_version_major(&intf->bmc->id),
+ ipmi_version_minor(&intf->bmc->id));
+
+ return seq_has_overflowed(m);
}
static int smi_version_proc_open(struct inode *inode, struct file *file)
@@ -2353,11 +2370,28 @@ static struct attribute *bmc_dev_attrs[] = {
&dev_attr_additional_device_support.attr,
&dev_attr_manufacturer_id.attr,
&dev_attr_product_id.attr,
+ &dev_attr_aux_firmware_revision.attr,
+ &dev_attr_guid.attr,
NULL
};
+static umode_t bmc_dev_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct bmc_device *bmc = to_bmc_device(dev);
+ umode_t mode = attr->mode;
+
+ if (attr == &dev_attr_aux_firmware_revision.attr)
+ return bmc->id.aux_firmware_revision_set ? mode : 0;
+ if (attr == &dev_attr_guid.attr)
+ return bmc->guid_set ? mode : 0;
+ return mode;
+}
+
static struct attribute_group bmc_dev_attr_group = {
.attrs = bmc_dev_attrs,
+ .is_visible = bmc_dev_attr_is_visible,
};
static const struct attribute_group *bmc_dev_attr_groups[] = {
@@ -2380,13 +2414,6 @@ cleanup_bmc_device(struct kref *ref)
{
struct bmc_device *bmc = container_of(ref, struct bmc_device, usecount);
- if (bmc->id.aux_firmware_revision_set)
- device_remove_file(&bmc->pdev.dev,
- &dev_attr_aux_firmware_revision);
- if (bmc->guid_set)
- device_remove_file(&bmc->pdev.dev,
- &dev_attr_guid);
-
platform_device_unregister(&bmc->pdev);
}
@@ -2407,33 +2434,6 @@ static void ipmi_bmc_unregister(ipmi_smi_t intf)
mutex_unlock(&ipmidriver_mutex);
}
-static int create_bmc_files(struct bmc_device *bmc)
-{
- int err;
-
- if (bmc->id.aux_firmware_revision_set) {
- err = device_create_file(&bmc->pdev.dev,
- &dev_attr_aux_firmware_revision);
- if (err)
- goto out;
- }
- if (bmc->guid_set) {
- err = device_create_file(&bmc->pdev.dev,
- &dev_attr_guid);
- if (err)
- goto out_aux_firm;
- }
-
- return 0;
-
-out_aux_firm:
- if (bmc->id.aux_firmware_revision_set)
- device_remove_file(&bmc->pdev.dev,
- &dev_attr_aux_firmware_revision);
-out:
- return err;
-}
-
static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
{
int rv;
@@ -2522,15 +2522,6 @@ static int ipmi_bmc_register(ipmi_smi_t intf, int ifnum)
return rv;
}
- rv = create_bmc_files(bmc);
- if (rv) {
- mutex_lock(&ipmidriver_mutex);
- platform_device_unregister(&bmc->pdev);
- mutex_unlock(&ipmidriver_mutex);
-
- return rv;
- }
-
dev_info(intf->si_dev, "Found new BMC (man_id: 0x%6.6x, "
"prod_id: 0x%4.4x, dev_id: 0x%2.2x)\n",
bmc->id.manufacturer_id,
@@ -4212,7 +4203,6 @@ static void need_waiter(ipmi_smi_t intf)
static atomic_t smi_msg_inuse_count = ATOMIC_INIT(0);
static atomic_t recv_msg_inuse_count = ATOMIC_INIT(0);
-/* FIXME - convert these to slabs. */
static void free_smi_msg(struct ipmi_smi_msg *msg)
{
atomic_dec(&smi_msg_inuse_count);
diff --git a/drivers/char/ipmi/ipmi_si_intf.c b/drivers/char/ipmi/ipmi_si_intf.c
index 967b73aa4e66..f6646ed3047e 100644
--- a/drivers/char/ipmi/ipmi_si_intf.c
+++ b/drivers/char/ipmi/ipmi_si_intf.c
@@ -321,6 +321,18 @@ static int try_smi_init(struct smi_info *smi);
static void cleanup_one_si(struct smi_info *to_clean);
static void cleanup_ipmi_si(void);
+#ifdef DEBUG_TIMING
+void debug_timestamp(char *msg)
+{
+ struct timespec64 t;
+
+ getnstimeofday64(&t);
+ pr_debug("**%s: %lld.%9.9ld\n", msg, (long long) t.tv_sec, t.tv_nsec);
+}
+#else
+#define debug_timestamp(x)
+#endif
+
static ATOMIC_NOTIFIER_HEAD(xaction_notifier_list);
static int register_xaction_notifier(struct notifier_block *nb)
{
@@ -358,9 +370,6 @@ static void return_hosed_msg(struct smi_info *smi_info, int cCode)
static enum si_sm_result start_next_msg(struct smi_info *smi_info)
{
int rv;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
if (!smi_info->waiting_msg) {
smi_info->curr_msg = NULL;
@@ -370,10 +379,7 @@ static enum si_sm_result start_next_msg(struct smi_info *smi_info)
smi_info->curr_msg = smi_info->waiting_msg;
smi_info->waiting_msg = NULL;
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Start2: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Start2");
err = atomic_notifier_call_chain(&xaction_notifier_list,
0, smi_info);
if (err & NOTIFY_STOP_MASK) {
@@ -582,12 +588,8 @@ static void check_bt_irq(struct smi_info *smi_info, bool irq_on)
static void handle_transaction_done(struct smi_info *smi_info)
{
struct ipmi_smi_msg *msg;
-#ifdef DEBUG_TIMING
- struct timeval t;
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Done: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Done");
switch (smi_info->si_state) {
case SI_NORMAL:
if (!smi_info->curr_msg)
@@ -929,24 +931,15 @@ static void sender(void *send_info,
struct smi_info *smi_info = send_info;
enum si_sm_result result;
unsigned long flags;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
-
- BUG_ON(smi_info->waiting_msg);
- smi_info->waiting_msg = msg;
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk("**Enqueue: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Enqueue");
if (smi_info->run_to_completion) {
/*
* If we are running to completion, start it and run
* transactions until everything is clear.
*/
- smi_info->curr_msg = smi_info->waiting_msg;
+ smi_info->curr_msg = msg;
smi_info->waiting_msg = NULL;
/*
@@ -964,6 +957,15 @@ static void sender(void *send_info,
}
spin_lock_irqsave(&smi_info->si_lock, flags);
+ /*
+ * The following two lines don't need to be under the lock for
+ * the lock's sake, but they do need SMP memory barriers to
+ * avoid getting things out of order. We are already claiming
+ * the lock, anyway, so just do it under the lock to avoid the
+ * ordering problem.
+ */
+ BUG_ON(smi_info->waiting_msg);
+ smi_info->waiting_msg = msg;
check_start_timer_thread(smi_info);
spin_unlock_irqrestore(&smi_info->si_lock, flags);
}
@@ -989,18 +991,18 @@ static void set_run_to_completion(void *send_info, bool i_run_to_completion)
* we are spinning in kipmid looking for something and not delaying
* between checks
*/
-static inline void ipmi_si_set_not_busy(struct timespec *ts)
+static inline void ipmi_si_set_not_busy(struct timespec64 *ts)
{
ts->tv_nsec = -1;
}
-static inline int ipmi_si_is_busy(struct timespec *ts)
+static inline int ipmi_si_is_busy(struct timespec64 *ts)
{
return ts->tv_nsec != -1;
}
static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
const struct smi_info *smi_info,
- struct timespec *busy_until)
+ struct timespec64 *busy_until)
{
unsigned int max_busy_us = 0;
@@ -1009,12 +1011,13 @@ static inline int ipmi_thread_busy_wait(enum si_sm_result smi_result,
if (max_busy_us == 0 || smi_result != SI_SM_CALL_WITH_DELAY)
ipmi_si_set_not_busy(busy_until);
else if (!ipmi_si_is_busy(busy_until)) {
- getnstimeofday(busy_until);
- timespec_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
+ getnstimeofday64(busy_until);
+ timespec64_add_ns(busy_until, max_busy_us*NSEC_PER_USEC);
} else {
- struct timespec now;
- getnstimeofday(&now);
- if (unlikely(timespec_compare(&now, busy_until) > 0)) {
+ struct timespec64 now;
+
+ getnstimeofday64(&now);
+ if (unlikely(timespec64_compare(&now, busy_until) > 0)) {
ipmi_si_set_not_busy(busy_until);
return 0;
}
@@ -1037,7 +1040,7 @@ static int ipmi_thread(void *data)
struct smi_info *smi_info = data;
unsigned long flags;
enum si_sm_result smi_result;
- struct timespec busy_until;
+ struct timespec64 busy_until;
ipmi_si_set_not_busy(&busy_until);
set_user_nice(current, MAX_NICE);
@@ -1128,15 +1131,10 @@ static void smi_timeout(unsigned long data)
unsigned long jiffies_now;
long time_diff;
long timeout;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
spin_lock_irqsave(&(smi_info->si_lock), flags);
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Timer: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Timer");
+
jiffies_now = jiffies;
time_diff = (((long)jiffies_now - (long)smi_info->last_timeout_jiffies)
* SI_USEC_PER_JIFFY);
@@ -1173,18 +1171,13 @@ static irqreturn_t si_irq_handler(int irq, void *data)
{
struct smi_info *smi_info = data;
unsigned long flags;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_inc_stat(smi_info, interrupts);
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk(KERN_DEBUG "**Interrupt: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("Interrupt");
+
smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
return IRQ_HANDLED;
@@ -2038,18 +2031,13 @@ static u32 ipmi_acpi_gpe(acpi_handle gpe_device,
{
struct smi_info *smi_info = context;
unsigned long flags;
-#ifdef DEBUG_TIMING
- struct timeval t;
-#endif
spin_lock_irqsave(&(smi_info->si_lock), flags);
smi_inc_stat(smi_info, interrupts);
-#ifdef DEBUG_TIMING
- do_gettimeofday(&t);
- printk("**ACPI_GPE: %d.%9.9d\n", t.tv_sec, t.tv_usec);
-#endif
+ debug_timestamp("ACPI_GPE");
+
smi_event_handler(smi_info, 0);
spin_unlock_irqrestore(&(smi_info->si_lock), flags);
@@ -2071,7 +2059,6 @@ static int acpi_gpe_irq_setup(struct smi_info *info)
if (!info->irq)
return 0;
- /* FIXME - is level triggered right? */
status = acpi_install_gpe_handler(NULL,
info->irq,
ACPI_GPE_LEVEL_TRIGGERED,
@@ -2998,7 +2985,9 @@ static int smi_type_proc_show(struct seq_file *m, void *v)
{
struct smi_info *smi = m->private;
- return seq_printf(m, "%s\n", si_to_str[smi->si_type]);
+ seq_printf(m, "%s\n", si_to_str[smi->si_type]);
+
+ return seq_has_overflowed(m);
}
static int smi_type_proc_open(struct inode *inode, struct file *file)
@@ -3060,16 +3049,18 @@ static int smi_params_proc_show(struct seq_file *m, void *v)
{
struct smi_info *smi = m->private;
- return seq_printf(m,
- "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
- si_to_str[smi->si_type],
- addr_space_to_str[smi->io.addr_type],
- smi->io.addr_data,
- smi->io.regspacing,
- smi->io.regsize,
- smi->io.regshift,
- smi->irq,
- smi->slave_addr);
+ seq_printf(m,
+ "%s,%s,0x%lx,rsp=%d,rsi=%d,rsh=%d,irq=%d,ipmb=%d\n",
+ si_to_str[smi->si_type],
+ addr_space_to_str[smi->io.addr_type],
+ smi->io.addr_data,
+ smi->io.regspacing,
+ smi->io.regsize,
+ smi->io.regshift,
+ smi->irq,
+ smi->slave_addr);
+
+ return seq_has_overflowed(m);
}
static int smi_params_proc_open(struct inode *inode, struct file *file)
diff --git a/drivers/char/ipmi/ipmi_ssif.c b/drivers/char/ipmi/ipmi_ssif.c
index 982b96323f82..f6e378dac5f5 100644
--- a/drivers/char/ipmi/ipmi_ssif.c
+++ b/drivers/char/ipmi/ipmi_ssif.c
@@ -1097,8 +1097,6 @@ static int ssif_remove(struct i2c_client *client)
if (!ssif_info)
return 0;
- i2c_set_clientdata(client, NULL);
-
/*
* After this point, we won't deliver anything asychronously
* to the message handler. We can unregister ourself.
@@ -1198,7 +1196,9 @@ static int ssif_detect(struct i2c_client *client, struct i2c_board_info *info)
static int smi_type_proc_show(struct seq_file *m, void *v)
{
- return seq_puts(m, "ssif\n");
+ seq_puts(m, "ssif\n");
+
+ return seq_has_overflowed(m);
}
static int smi_type_proc_open(struct inode *inode, struct file *file)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 4c58333b4257..297110c12635 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -28,7 +28,7 @@
#include <linux/io.h>
#include <linux/aio.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#ifdef CONFIG_IA64
# include <linux/efi.h>
@@ -287,13 +287,24 @@ static unsigned long get_unmapped_area_mem(struct file *file,
return pgoff << PAGE_SHIFT;
}
+/* permit direct mmap, for read, write or exec */
+static unsigned memory_mmap_capabilities(struct file *file)
+{
+ return NOMMU_MAP_DIRECT |
+ NOMMU_MAP_READ | NOMMU_MAP_WRITE | NOMMU_MAP_EXEC;
+}
+
+static unsigned zero_mmap_capabilities(struct file *file)
+{
+ return NOMMU_MAP_COPY;
+}
+
/* can't do an in-place private mapping if there's no MMU */
static inline int private_mapping_ok(struct vm_area_struct *vma)
{
return vma->vm_flags & VM_MAYSHARE;
}
#else
-#define get_unmapped_area_mem NULL
static inline int private_mapping_ok(struct vm_area_struct *vma)
{
@@ -341,7 +352,6 @@ static int mmap_mem(struct file *file, struct vm_area_struct *vma)
return 0;
}
-#ifdef CONFIG_DEVKMEM
static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
{
unsigned long pfn;
@@ -362,9 +372,7 @@ static int mmap_kmem(struct file *file, struct vm_area_struct *vma)
vma->vm_pgoff = pfn;
return mmap_mem(file, vma);
}
-#endif
-#ifdef CONFIG_DEVKMEM
/*
* This function reads the *virtual* memory as seen by the kernel.
*/
@@ -544,9 +552,7 @@ static ssize_t write_kmem(struct file *file, const char __user *buf,
*ppos = p;
return virtr + wrote ? : err;
}
-#endif
-#ifdef CONFIG_DEVPORT
static ssize_t read_port(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
@@ -575,6 +581,7 @@ static ssize_t write_port(struct file *file, const char __user *buf,
return -EFAULT;
while (count-- > 0 && i < 65536) {
char c;
+
if (__get_user(c, tmp)) {
if (tmp > buf)
break;
@@ -587,7 +594,6 @@ static ssize_t write_port(struct file *file, const char __user *buf,
*ppos = i;
return tmp-buf;
}
-#endif
static ssize_t read_null(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
@@ -631,6 +637,7 @@ static ssize_t read_iter_zero(struct kiocb *iocb, struct iov_iter *iter)
while (iov_iter_count(iter)) {
size_t chunk = iov_iter_count(iter), n;
+
if (chunk > PAGE_SIZE)
chunk = PAGE_SIZE; /* Just for latency reasons */
n = iov_iter_zero(chunk, iter);
@@ -715,25 +722,29 @@ static int open_port(struct inode *inode, struct file *filp)
#define open_mem open_port
#define open_kmem open_mem
-static const struct file_operations mem_fops = {
+static const struct file_operations __maybe_unused mem_fops = {
.llseek = memory_lseek,
.read = read_mem,
.write = write_mem,
.mmap = mmap_mem,
.open = open_mem,
+#ifndef CONFIG_MMU
.get_unmapped_area = get_unmapped_area_mem,
+ .mmap_capabilities = memory_mmap_capabilities,
+#endif
};
-#ifdef CONFIG_DEVKMEM
-static const struct file_operations kmem_fops = {
+static const struct file_operations __maybe_unused kmem_fops = {
.llseek = memory_lseek,
.read = read_kmem,
.write = write_kmem,
.mmap = mmap_kmem,
.open = open_kmem,
+#ifndef CONFIG_MMU
.get_unmapped_area = get_unmapped_area_mem,
-};
+ .mmap_capabilities = memory_mmap_capabilities,
#endif
+};
static const struct file_operations null_fops = {
.llseek = null_lseek,
@@ -744,14 +755,12 @@ static const struct file_operations null_fops = {
.splice_write = splice_write_null,
};
-#ifdef CONFIG_DEVPORT
-static const struct file_operations port_fops = {
+static const struct file_operations __maybe_unused port_fops = {
.llseek = memory_lseek,
.read = read_port,
.write = write_port,
.open = open_port,
};
-#endif
static const struct file_operations zero_fops = {
.llseek = zero_lseek,
@@ -760,16 +769,9 @@ static const struct file_operations zero_fops = {
.read_iter = read_iter_zero,
.aio_write = aio_write_zero,
.mmap = mmap_zero,
-};
-
-/*
- * capabilities for /dev/zero
- * - permits private mappings, "copies" are taken of the source of zeros
- * - no writeback happens
- */
-static struct backing_dev_info zero_bdi = {
- .name = "char/mem",
- .capabilities = BDI_CAP_MAP_COPY | BDI_CAP_NO_ACCT_AND_WRITEBACK,
+#ifndef CONFIG_MMU
+ .mmap_capabilities = zero_mmap_capabilities,
+#endif
};
static const struct file_operations full_fops = {
@@ -783,22 +785,24 @@ static const struct memdev {
const char *name;
umode_t mode;
const struct file_operations *fops;
- struct backing_dev_info *dev_info;
+ fmode_t fmode;
} devlist[] = {
- [1] = { "mem", 0, &mem_fops, &directly_mappable_cdev_bdi },
+#ifdef CONFIG_DEVMEM
+ [1] = { "mem", 0, &mem_fops, FMODE_UNSIGNED_OFFSET },
+#endif
#ifdef CONFIG_DEVKMEM
- [2] = { "kmem", 0, &kmem_fops, &directly_mappable_cdev_bdi },
+ [2] = { "kmem", 0, &kmem_fops, FMODE_UNSIGNED_OFFSET },
#endif
- [3] = { "null", 0666, &null_fops, NULL },
+ [3] = { "null", 0666, &null_fops, 0 },
#ifdef CONFIG_DEVPORT
- [4] = { "port", 0, &port_fops, NULL },
+ [4] = { "port", 0, &port_fops, 0 },
#endif
- [5] = { "zero", 0666, &zero_fops, &zero_bdi },
- [7] = { "full", 0666, &full_fops, NULL },
- [8] = { "random", 0666, &random_fops, NULL },
- [9] = { "urandom", 0666, &urandom_fops, NULL },
+ [5] = { "zero", 0666, &zero_fops, 0 },
+ [7] = { "full", 0666, &full_fops, 0 },
+ [8] = { "random", 0666, &random_fops, 0 },
+ [9] = { "urandom", 0666, &urandom_fops, 0 },
#ifdef CONFIG_PRINTK
- [11] = { "kmsg", 0644, &kmsg_fops, NULL },
+ [11] = { "kmsg", 0644, &kmsg_fops, 0 },
#endif
};
@@ -816,12 +820,7 @@ static int memory_open(struct inode *inode, struct file *filp)
return -ENXIO;
filp->f_op = dev->fops;
- if (dev->dev_info)
- filp->f_mapping->backing_dev_info = dev->dev_info;
-
- /* Is /dev/mem or /dev/kmem ? */
- if (dev->dev_info == &directly_mappable_cdev_bdi)
- filp->f_mode |= FMODE_UNSIGNED_OFFSET;
+ filp->f_mode |= dev->fmode;
if (dev->fops->open)
return dev->fops->open(inode, filp);
@@ -846,11 +845,6 @@ static struct class *mem_class;
static int __init chr_dev_init(void)
{
int minor;
- int err;
-
- err = bdi_init(&zero_bdi);
- if (err)
- return err;
if (register_chrdev(MEM_MAJOR, "mem", &memory_fops))
printk("unable to get major %d for memory devs\n", MEM_MAJOR);
diff --git a/drivers/char/random.c b/drivers/char/random.c
index 04645c09fe5e..9cd6968e2f92 100644
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -569,19 +569,19 @@ static void fast_mix(struct fast_pool *f)
__u32 c = f->pool[2], d = f->pool[3];
a += b; c += d;
- b = rol32(a, 6); d = rol32(c, 27);
+ b = rol32(b, 6); d = rol32(d, 27);
d ^= a; b ^= c;
a += b; c += d;
- b = rol32(a, 16); d = rol32(c, 14);
+ b = rol32(b, 16); d = rol32(d, 14);
d ^= a; b ^= c;
a += b; c += d;
- b = rol32(a, 6); d = rol32(c, 27);
+ b = rol32(b, 6); d = rol32(d, 27);
d ^= a; b ^= c;
a += b; c += d;
- b = rol32(a, 16); d = rol32(c, 14);
+ b = rol32(b, 16); d = rol32(d, 14);
d ^= a; b ^= c;
f->pool[0] = a; f->pool[1] = b;
diff --git a/drivers/char/raw.c b/drivers/char/raw.c
index a24891b97547..6e29bf2db536 100644
--- a/drivers/char/raw.c
+++ b/drivers/char/raw.c
@@ -104,11 +104,9 @@ static int raw_release(struct inode *inode, struct file *filp)
mutex_lock(&raw_mutex);
bdev = raw_devices[minor].binding;
- if (--raw_devices[minor].inuse == 0) {
+ if (--raw_devices[minor].inuse == 0)
/* Here inode->i_mapping == bdev->bd_inode->i_mapping */
inode->i_mapping = &inode->i_data;
- inode->i_mapping->backing_dev_info = &default_backing_dev_info;
- }
mutex_unlock(&raw_mutex);
blkdev_put(bdev, filp->f_mode | FMODE_EXCL);
diff --git a/drivers/char/tpm/Kconfig b/drivers/char/tpm/Kconfig
index c54cac3f8bc8..9d4e37549eb2 100644
--- a/drivers/char/tpm/Kconfig
+++ b/drivers/char/tpm/Kconfig
@@ -100,15 +100,15 @@ config TCG_IBMVTPM
will be accessible from within Linux. To compile this driver
as a module, choose M here; the module will be called tpm_ibmvtpm.
-config TCG_ST33_I2C
- tristate "STMicroelectronics ST33 I2C TPM"
+config TCG_TIS_I2C_ST33
+ tristate "TPM Interface Specification 1.2 Interface (I2C - STMicroelectronics)"
depends on I2C
depends on GPIOLIB
---help---
If you have a TPM security chip from STMicroelectronics working with
an I2C bus say Yes and it will be accessible from within Linux.
To compile this driver as a module, choose M here; the module will be
- called tpm_stm_st33_i2c.
+ called tpm_i2c_stm_st33.
config TCG_XEN
tristate "XEN TPM Interface"
@@ -122,4 +122,13 @@ config TCG_XEN
To compile this driver as a module, choose M here; the module
will be called xen-tpmfront.
+config TCG_CRB
+ tristate "TPM 2.0 CRB Interface"
+ depends on X86 && ACPI
+ ---help---
+ If you have a TPM security chip that is compliant with the
+ TCG CRB 2.0 TPM specification say Yes and it will be accessible
+ from within Linux. To compile this driver as a module, choose
+ M here; the module will be called tpm_crb.
+
endif # TCG_TPM
diff --git a/drivers/char/tpm/Makefile b/drivers/char/tpm/Makefile
index 4d85dd681b81..990cf183931d 100644
--- a/drivers/char/tpm/Makefile
+++ b/drivers/char/tpm/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel tpm device drivers.
#
obj-$(CONFIG_TCG_TPM) += tpm.o
-tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o
+tpm-y := tpm-interface.o tpm-dev.o tpm-sysfs.o tpm-chip.o tpm2-cmd.o
tpm-$(CONFIG_ACPI) += tpm_ppi.o
ifdef CONFIG_ACPI
@@ -20,5 +20,6 @@ obj-$(CONFIG_TCG_NSC) += tpm_nsc.o
obj-$(CONFIG_TCG_ATMEL) += tpm_atmel.o
obj-$(CONFIG_TCG_INFINEON) += tpm_infineon.o
obj-$(CONFIG_TCG_IBMVTPM) += tpm_ibmvtpm.o
-obj-$(CONFIG_TCG_ST33_I2C) += tpm_i2c_stm_st33.o
+obj-$(CONFIG_TCG_TIS_I2C_ST33) += tpm_i2c_stm_st33.o
obj-$(CONFIG_TCG_XEN) += xen-tpmfront.o
+obj-$(CONFIG_TCG_CRB) += tpm_crb.o
diff --git a/drivers/char/tpm/tpm-chip.c b/drivers/char/tpm/tpm-chip.c
new file mode 100644
index 000000000000..1d278ccd751f
--- /dev/null
+++ b/drivers/char/tpm/tpm-chip.c
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Leendert van Doorn <leendert@watson.ibm.com>
+ * Dave Safford <safford@watson.ibm.com>
+ * Reiner Sailer <sailer@watson.ibm.com>
+ * Kylene Hall <kjhall@us.ibm.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * TPM chip management routines.
+ *
+ * This program is free software; 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/poll.h>
+#include <linux/slab.h>
+#include <linux/mutex.h>
+#include <linux/spinlock.h>
+#include <linux/freezer.h>
+#include <linux/major.h>
+#include "tpm.h"
+#include "tpm_eventlog.h"
+
+static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
+static LIST_HEAD(tpm_chip_list);
+static DEFINE_SPINLOCK(driver_lock);
+
+struct class *tpm_class;
+dev_t tpm_devt;
+
+/*
+ * tpm_chip_find_get - return tpm_chip for a given chip number
+ * @chip_num the device number for the chip
+ */
+struct tpm_chip *tpm_chip_find_get(int chip_num)
+{
+ struct tpm_chip *pos, *chip = NULL;
+
+ rcu_read_lock();
+ list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
+ if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
+ continue;
+
+ if (try_module_get(pos->pdev->driver->owner)) {
+ chip = pos;
+ break;
+ }
+ }
+ rcu_read_unlock();
+ return chip;
+}
+
+/**
+ * tpm_dev_release() - free chip memory and the device number
+ * @dev: the character device for the TPM chip
+ *
+ * This is used as the release function for the character device.
+ */
+static void tpm_dev_release(struct device *dev)
+{
+ struct tpm_chip *chip = container_of(dev, struct tpm_chip, dev);
+
+ spin_lock(&driver_lock);
+ clear_bit(chip->dev_num, dev_mask);
+ spin_unlock(&driver_lock);
+ kfree(chip);
+}
+
+/**
+ * tpmm_chip_alloc() - allocate a new struct tpm_chip instance
+ * @dev: device to which the chip is associated
+ * @ops: struct tpm_class_ops instance
+ *
+ * Allocates a new struct tpm_chip instance and assigns a free
+ * device number for it. Caller does not have to worry about
+ * freeing the allocated resources. When the devices is removed
+ * devres calls tpmm_chip_remove() to do the job.
+ */
+struct tpm_chip *tpmm_chip_alloc(struct device *dev,
+ const struct tpm_class_ops *ops)
+{
+ struct tpm_chip *chip;
+
+ chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ if (chip == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&chip->tpm_mutex);
+ INIT_LIST_HEAD(&chip->list);
+
+ chip->ops = ops;
+
+ spin_lock(&driver_lock);
+ chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
+ spin_unlock(&driver_lock);
+
+ if (chip->dev_num >= TPM_NUM_DEVICES) {
+ dev_err(dev, "No available tpm device numbers\n");
+ kfree(chip);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ set_bit(chip->dev_num, dev_mask);
+
+ scnprintf(chip->devname, sizeof(chip->devname), "tpm%d", chip->dev_num);
+
+ chip->pdev = dev;
+
+ dev_set_drvdata(dev, chip);
+
+ chip->dev.class = tpm_class;
+ chip->dev.release = tpm_dev_release;
+ chip->dev.parent = chip->pdev;
+
+ if (chip->dev_num == 0)
+ chip->dev.devt = MKDEV(MISC_MAJOR, TPM_MINOR);
+ else
+ chip->dev.devt = MKDEV(MAJOR(tpm_devt), chip->dev_num);
+
+ dev_set_name(&chip->dev, "%s", chip->devname);
+
+ device_initialize(&chip->dev);
+
+ chip->cdev.owner = chip->pdev->driver->owner;
+ cdev_init(&chip->cdev, &tpm_fops);
+
+ return chip;
+}
+EXPORT_SYMBOL_GPL(tpmm_chip_alloc);
+
+static int tpm_dev_add_device(struct tpm_chip *chip)
+{
+ int rc;
+
+ rc = device_add(&chip->dev);
+ if (rc) {
+ dev_err(&chip->dev,
+ "unable to device_register() %s, major %d, minor %d, err=%d\n",
+ chip->devname, MAJOR(chip->dev.devt),
+ MINOR(chip->dev.devt), rc);
+
+ return rc;
+ }
+
+ rc = cdev_add(&chip->cdev, chip->dev.devt, 1);
+ if (rc) {
+ dev_err(&chip->dev,
+ "unable to cdev_add() %s, major %d, minor %d, err=%d\n",
+ chip->devname, MAJOR(chip->dev.devt),
+ MINOR(chip->dev.devt), rc);
+
+ device_unregister(&chip->dev);
+ return rc;
+ }
+
+ return rc;
+}
+
+static void tpm_dev_del_device(struct tpm_chip *chip)
+{
+ cdev_del(&chip->cdev);
+ device_unregister(&chip->dev);
+}
+
+/*
+ * tpm_chip_register() - create a character device for the TPM chip
+ * @chip: TPM chip to use.
+ *
+ * Creates a character device for the TPM chip and adds sysfs interfaces for
+ * the device, PPI and TCPA. As the last step this function adds the
+ * chip to the list of TPM chips available for use.
+ *
+ * NOTE: This function should be only called after the chip initialization
+ * is complete.
+ *
+ * Called from tpm_<specific>.c probe function only for devices
+ * the driver has determined it should claim. Prior to calling
+ * this function the specific probe function has called pci_enable_device
+ * upon errant exit from this function specific probe function should call
+ * pci_disable_device
+ */
+int tpm_chip_register(struct tpm_chip *chip)
+{
+ int rc;
+
+ rc = tpm_dev_add_device(chip);
+ if (rc)
+ return rc;
+
+ /* Populate sysfs for TPM1 devices. */
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+ rc = tpm_sysfs_add_device(chip);
+ if (rc)
+ goto del_misc;
+
+ rc = tpm_add_ppi(chip);
+ if (rc)
+ goto del_sysfs;
+
+ chip->bios_dir = tpm_bios_log_setup(chip->devname);
+ }
+
+ /* Make the chip available. */
+ spin_lock(&driver_lock);
+ list_add_rcu(&chip->list, &tpm_chip_list);
+ spin_unlock(&driver_lock);
+
+ chip->flags |= TPM_CHIP_FLAG_REGISTERED;
+
+ return 0;
+del_sysfs:
+ tpm_sysfs_del_device(chip);
+del_misc:
+ tpm_dev_del_device(chip);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tpm_chip_register);
+
+/*
+ * tpm_chip_unregister() - release the TPM driver
+ * @chip: TPM chip to use.
+ *
+ * Takes the chip first away from the list of available TPM chips and then
+ * cleans up all the resources reserved by tpm_chip_register().
+ *
+ * NOTE: This function should be only called before deinitializing chip
+ * resources.
+ */
+void tpm_chip_unregister(struct tpm_chip *chip)
+{
+ if (!(chip->flags & TPM_CHIP_FLAG_REGISTERED))
+ return;
+
+ spin_lock(&driver_lock);
+ list_del_rcu(&chip->list);
+ spin_unlock(&driver_lock);
+ synchronize_rcu();
+
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2)) {
+ if (chip->bios_dir)
+ tpm_bios_log_teardown(chip->bios_dir);
+ tpm_remove_ppi(chip);
+ tpm_sysfs_del_device(chip);
+ }
+
+ tpm_dev_del_device(chip);
+}
+EXPORT_SYMBOL_GPL(tpm_chip_unregister);
diff --git a/drivers/char/tpm/tpm-dev.c b/drivers/char/tpm/tpm-dev.c
index d9b774e02a1f..de0337ebd658 100644
--- a/drivers/char/tpm/tpm-dev.c
+++ b/drivers/char/tpm/tpm-dev.c
@@ -17,7 +17,6 @@
* License.
*
*/
-#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include "tpm.h"
@@ -54,16 +53,15 @@ static void timeout_work(struct work_struct *work)
static int tpm_open(struct inode *inode, struct file *file)
{
- struct miscdevice *misc = file->private_data;
- struct tpm_chip *chip = container_of(misc, struct tpm_chip,
- vendor.miscdev);
+ struct tpm_chip *chip =
+ container_of(inode->i_cdev, struct tpm_chip, cdev);
struct file_priv *priv;
/* It's assured that the chip will be opened just once,
* by the check of is_open variable, which is protected
* by driver_lock. */
if (test_and_set_bit(0, &chip->is_open)) {
- dev_dbg(chip->dev, "Another process owns this TPM\n");
+ dev_dbg(chip->pdev, "Another process owns this TPM\n");
return -EBUSY;
}
@@ -81,7 +79,7 @@ static int tpm_open(struct inode *inode, struct file *file)
INIT_WORK(&priv->work, timeout_work);
file->private_data = priv;
- get_device(chip->dev);
+ get_device(chip->pdev);
return 0;
}
@@ -168,12 +166,12 @@ static int tpm_release(struct inode *inode, struct file *file)
file->private_data = NULL;
atomic_set(&priv->data_pending, 0);
clear_bit(0, &priv->chip->is_open);
- put_device(priv->chip->dev);
+ put_device(priv->chip->pdev);
kfree(priv);
return 0;
}
-static const struct file_operations tpm_fops = {
+const struct file_operations tpm_fops = {
.owner = THIS_MODULE,
.llseek = no_llseek,
.open = tpm_open,
@@ -182,32 +180,4 @@ static const struct file_operations tpm_fops = {
.release = tpm_release,
};
-int tpm_dev_add_device(struct tpm_chip *chip)
-{
- int rc;
- chip->vendor.miscdev.fops = &tpm_fops;
- if (chip->dev_num == 0)
- chip->vendor.miscdev.minor = TPM_MINOR;
- else
- chip->vendor.miscdev.minor = MISC_DYNAMIC_MINOR;
-
- chip->vendor.miscdev.name = chip->devname;
- chip->vendor.miscdev.parent = chip->dev;
-
- rc = misc_register(&chip->vendor.miscdev);
- if (rc) {
- chip->vendor.miscdev.name = NULL;
- dev_err(chip->dev,
- "unable to misc_register %s, minor %d err=%d\n",
- chip->vendor.miscdev.name,
- chip->vendor.miscdev.minor, rc);
- }
- return rc;
-}
-
-void tpm_dev_del_device(struct tpm_chip *chip)
-{
- if (chip->vendor.miscdev.name)
- misc_deregister(&chip->vendor.miscdev);
-}
diff --git a/drivers/char/tpm/tpm-interface.c b/drivers/char/tpm/tpm-interface.c
index 6af17002a115..e85d3416d899 100644
--- a/drivers/char/tpm/tpm-interface.c
+++ b/drivers/char/tpm/tpm-interface.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2004 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
@@ -47,10 +48,6 @@ module_param_named(suspend_pcr, tpm_suspend_pcr, uint, 0644);
MODULE_PARM_DESC(suspend_pcr,
"PCR to use for dummy writes to faciltate flush on suspend.");
-static LIST_HEAD(tpm_chip_list);
-static DEFINE_SPINLOCK(driver_lock);
-static DECLARE_BITMAP(dev_mask, TPM_NUM_DEVICES);
-
/*
* Array with one entry per ordinal defining the maximum amount
* of time the chip could take to return the result. The ordinal
@@ -346,7 +343,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
if (count == 0)
return -ENODATA;
if (count > bufsiz) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"invalid count value %x %zx\n", count, bufsiz);
return -E2BIG;
}
@@ -355,7 +352,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
rc = chip->ops->send(chip, (u8 *) buf, count);
if (rc < 0) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"tpm_transmit: tpm_send: error %zd\n", rc);
goto out;
}
@@ -363,7 +360,10 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
if (chip->vendor.irq)
goto out_recv;
- stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ stop = jiffies + tpm2_calc_ordinal_duration(chip, ordinal);
+ else
+ stop = jiffies + tpm_calc_ordinal_duration(chip, ordinal);
do {
u8 status = chip->ops->status(chip);
if ((status & chip->ops->req_complete_mask) ==
@@ -371,7 +371,7 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
goto out_recv;
if (chip->ops->req_canceled(chip, status)) {
- dev_err(chip->dev, "Operation Canceled\n");
+ dev_err(chip->pdev, "Operation Canceled\n");
rc = -ECANCELED;
goto out;
}
@@ -381,14 +381,14 @@ ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
} while (time_before(jiffies, stop));
chip->ops->cancel(chip);
- dev_err(chip->dev, "Operation Timed out\n");
+ dev_err(chip->pdev, "Operation Timed out\n");
rc = -ETIME;
goto out;
out_recv:
rc = chip->ops->recv(chip, (u8 *) buf, bufsiz);
if (rc < 0)
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"tpm_transmit: tpm_recv: error %zd\n", rc);
out:
mutex_unlock(&chip->tpm_mutex);
@@ -398,9 +398,10 @@ out:
#define TPM_DIGEST_SIZE 20
#define TPM_RET_CODE_IDX 6
-static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
- int len, const char *desc)
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd,
+ int len, const char *desc)
{
+ struct tpm_output_header *header;
int err;
len = tpm_transmit(chip, (u8 *) cmd, len);
@@ -409,9 +410,12 @@ static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
else if (len < TPM_HEADER_SIZE)
return -EFAULT;
- err = be32_to_cpu(cmd->header.out.return_code);
+ header = cmd;
+
+ err = be32_to_cpu(header->return_code);
if (err != 0 && desc)
- dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
+ dev_err(chip->pdev, "A TPM error (%d) occurred %s\n", err,
+ desc);
return err;
}
@@ -448,7 +452,7 @@ ssize_t tpm_getcap(struct device *dev, __be32 subcap_id, cap_t *cap,
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = subcap_id;
}
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
+ rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, desc);
if (!rc)
*cap = tpm_cmd.params.getcap_out.cap;
return rc;
@@ -464,8 +468,8 @@ void tpm_gen_interrupt(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- "attempting to determine the timeouts");
+ rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+ "attempting to determine the timeouts");
}
EXPORT_SYMBOL_GPL(tpm_gen_interrupt);
@@ -483,9 +487,10 @@ static int tpm_startup(struct tpm_chip *chip, __be16 startup_type)
{
struct tpm_cmd_t start_cmd;
start_cmd.header.in = tpm_startup_header;
+
start_cmd.params.startup_in.startup_type = startup_type;
- return transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
- "attempting to start the TPM");
+ return tpm_transmit_cmd(chip, &start_cmd, TPM_INTERNAL_RESULT_SIZE,
+ "attempting to start the TPM");
}
int tpm_get_timeouts(struct tpm_chip *chip)
@@ -500,12 +505,12 @@ int tpm_get_timeouts(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
+ rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE, NULL);
if (rc == TPM_ERR_INVALID_POSTINIT) {
/* The TPM is not started, we are the first to talk to it.
Execute a startup command. */
- dev_info(chip->dev, "Issuing TPM_STARTUP");
+ dev_info(chip->pdev, "Issuing TPM_STARTUP");
if (tpm_startup(chip, TPM_ST_CLEAR))
return rc;
@@ -513,11 +518,11 @@ int tpm_get_timeouts(struct tpm_chip *chip)
tpm_cmd.params.getcap_in.cap = TPM_CAP_PROP;
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_TIMEOUT;
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+ rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
NULL);
}
if (rc) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"A TPM error (%zd) occurred attempting to determine the timeouts\n",
rc);
goto duration;
@@ -556,7 +561,7 @@ int tpm_get_timeouts(struct tpm_chip *chip)
/* Report adjusted timeouts */
if (chip->vendor.timeout_adjusted) {
- dev_info(chip->dev,
+ dev_info(chip->pdev,
HW_ERR "Adjusting reported timeouts: A %lu->%luus B %lu->%luus C %lu->%luus D %lu->%luus\n",
old_timeout[0], new_timeout[0],
old_timeout[1], new_timeout[1],
@@ -575,8 +580,8 @@ duration:
tpm_cmd.params.getcap_in.subcap_size = cpu_to_be32(4);
tpm_cmd.params.getcap_in.subcap = TPM_CAP_PROP_TIS_DURATION;
- rc = transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
- "attempting to determine the durations");
+ rc = tpm_transmit_cmd(chip, &tpm_cmd, TPM_INTERNAL_RESULT_SIZE,
+ "attempting to determine the durations");
if (rc)
return rc;
@@ -603,7 +608,7 @@ duration:
chip->vendor.duration[TPM_MEDIUM] *= 1000;
chip->vendor.duration[TPM_LONG] *= 1000;
chip->vendor.duration_adjusted = true;
- dev_info(chip->dev, "Adjusting TPM timeout parameters.");
+ dev_info(chip->pdev, "Adjusting TPM timeout parameters.");
}
return 0;
}
@@ -631,32 +636,11 @@ static int tpm_continue_selftest(struct tpm_chip *chip)
struct tpm_cmd_t cmd;
cmd.header.in = continue_selftest_header;
- rc = transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
- "continue selftest");
+ rc = tpm_transmit_cmd(chip, &cmd, CONTINUE_SELFTEST_RESULT_SIZE,
+ "continue selftest");
return rc;
}
-/*
- * tpm_chip_find_get - return tpm_chip for given chip number
- */
-static struct tpm_chip *tpm_chip_find_get(int chip_num)
-{
- struct tpm_chip *pos, *chip = NULL;
-
- rcu_read_lock();
- list_for_each_entry_rcu(pos, &tpm_chip_list, list) {
- if (chip_num != TPM_ANY_NUM && chip_num != pos->dev_num)
- continue;
-
- if (try_module_get(pos->dev->driver->owner)) {
- chip = pos;
- break;
- }
- }
- rcu_read_unlock();
- return chip;
-}
-
#define TPM_ORDINAL_PCRREAD cpu_to_be32(21)
#define READ_PCR_RESULT_SIZE 30
static struct tpm_input_header pcrread_header = {
@@ -672,8 +656,8 @@ int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
cmd.header.in = pcrread_header;
cmd.params.pcrread_in.pcr_idx = cpu_to_be32(pcr_idx);
- rc = transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
- "attempting to read a pcr value");
+ rc = tpm_transmit_cmd(chip, &cmd, READ_PCR_RESULT_SIZE,
+ "attempting to read a pcr value");
if (rc == 0)
memcpy(res_buf, cmd.params.pcrread_out.pcr_result,
@@ -700,7 +684,10 @@ int tpm_pcr_read(u32 chip_num, int pcr_idx, u8 *res_buf)
chip = tpm_chip_find_get(chip_num);
if (chip == NULL)
return -ENODEV;
- rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ rc = tpm2_pcr_read(chip, pcr_idx, res_buf);
+ else
+ rc = tpm_pcr_read_dev(chip, pcr_idx, res_buf);
tpm_chip_put(chip);
return rc;
}
@@ -734,11 +721,17 @@ int tpm_pcr_extend(u32 chip_num, int pcr_idx, const u8 *hash)
if (chip == NULL)
return -ENODEV;
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ rc = tpm2_pcr_extend(chip, pcr_idx, hash);
+ tpm_chip_put(chip);
+ return rc;
+ }
+
cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
memcpy(cmd.params.pcrextend_in.hash, hash, TPM_DIGEST_SIZE);
- rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
- "attempting extend a PCR value");
+ rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+ "attempting extend a PCR value");
tpm_chip_put(chip);
return rc;
@@ -781,7 +774,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
* around 300ms while the self test is ongoing, keep trying
* until the self test duration expires. */
if (rc == -ETIME) {
- dev_info(chip->dev, HW_ERR "TPM command timed out during continue self test");
+ dev_info(chip->pdev, HW_ERR "TPM command timed out during continue self test");
msleep(delay_msec);
continue;
}
@@ -791,7 +784,7 @@ int tpm_do_selftest(struct tpm_chip *chip)
rc = be32_to_cpu(cmd.header.out.return_code);
if (rc == TPM_ERR_DISABLED || rc == TPM_ERR_DEACTIVATED) {
- dev_info(chip->dev,
+ dev_info(chip->pdev,
"TPM is disabled/deactivated (0x%X)\n", rc);
/* TPM is disabled and/or deactivated; driver can
* proceed and TPM does handle commands for
@@ -817,7 +810,7 @@ int tpm_send(u32 chip_num, void *cmd, size_t buflen)
if (chip == NULL)
return -ENODEV;
- rc = transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
+ rc = tpm_transmit_cmd(chip, cmd, buflen, "attempting tpm_cmd");
tpm_chip_put(chip);
return rc;
@@ -884,30 +877,6 @@ again:
}
EXPORT_SYMBOL_GPL(wait_for_tpm_stat);
-void tpm_remove_hardware(struct device *dev)
-{
- struct tpm_chip *chip = dev_get_drvdata(dev);
-
- if (chip == NULL) {
- dev_err(dev, "No device data found\n");
- return;
- }
-
- spin_lock(&driver_lock);
- list_del_rcu(&chip->list);
- spin_unlock(&driver_lock);
- synchronize_rcu();
-
- tpm_dev_del_device(chip);
- tpm_sysfs_del_device(chip);
- tpm_remove_ppi(&dev->kobj);
- tpm_bios_log_teardown(chip->bios_dir);
-
- /* write it this way to be explicit (chip->dev == dev) */
- put_device(chip->dev);
-}
-EXPORT_SYMBOL_GPL(tpm_remove_hardware);
-
#define TPM_ORD_SAVESTATE cpu_to_be32(152)
#define SAVESTATE_RESULT_SIZE 10
@@ -932,20 +901,25 @@ int tpm_pm_suspend(struct device *dev)
if (chip == NULL)
return -ENODEV;
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ tpm2_shutdown(chip, TPM2_SU_STATE);
+ return 0;
+ }
+
/* for buggy tpm, flush pcrs with extend to selected dummy */
if (tpm_suspend_pcr) {
cmd.header.in = pcrextend_header;
cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(tpm_suspend_pcr);
memcpy(cmd.params.pcrextend_in.hash, dummy_hash,
TPM_DIGEST_SIZE);
- rc = transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
- "extending dummy pcr before suspend");
+ rc = tpm_transmit_cmd(chip, &cmd, EXTEND_PCR_RESULT_SIZE,
+ "extending dummy pcr before suspend");
}
/* now do the actual savestate */
for (try = 0; try < TPM_RETRY; try++) {
cmd.header.in = savestate_header;
- rc = transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
+ rc = tpm_transmit_cmd(chip, &cmd, SAVESTATE_RESULT_SIZE, NULL);
/*
* If the TPM indicates that it is too busy to respond to
@@ -963,10 +937,10 @@ int tpm_pm_suspend(struct device *dev)
}
if (rc)
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"Error (%d) sending savestate before suspend\n", rc);
else if (try > 0)
- dev_warn(chip->dev, "TPM savestate took %dms\n",
+ dev_warn(chip->pdev, "TPM savestate took %dms\n",
try * TPM_TIMEOUT_RETRY);
return rc;
@@ -1018,11 +992,17 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
if (chip == NULL)
return -ENODEV;
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ err = tpm2_get_random(chip, out, max);
+ tpm_chip_put(chip);
+ return err;
+ }
+
do {
tpm_cmd.header.in = tpm_getrandom_header;
tpm_cmd.params.getrandom_in.num_bytes = cpu_to_be32(num_bytes);
- err = transmit_cmd(chip, &tpm_cmd,
+ err = tpm_transmit_cmd(chip, &tpm_cmd,
TPM_GETRANDOM_RESULT_SIZE + num_bytes,
"attempting get random");
if (err)
@@ -1041,103 +1021,34 @@ int tpm_get_random(u32 chip_num, u8 *out, size_t max)
}
EXPORT_SYMBOL_GPL(tpm_get_random);
-/* In case vendor provided release function, call it too.*/
-
-void tpm_dev_vendor_release(struct tpm_chip *chip)
+static int __init tpm_init(void)
{
- if (!chip)
- return;
-
- clear_bit(chip->dev_num, dev_mask);
-}
-EXPORT_SYMBOL_GPL(tpm_dev_vendor_release);
-
-
-/*
- * Once all references to platform device are down to 0,
- * release all allocated structures.
- */
-static void tpm_dev_release(struct device *dev)
-{
- struct tpm_chip *chip = dev_get_drvdata(dev);
+ int rc;
- if (!chip)
- return;
+ tpm_class = class_create(THIS_MODULE, "tpm");
+ if (IS_ERR(tpm_class)) {
+ pr_err("couldn't create tpm class\n");
+ return PTR_ERR(tpm_class);
+ }
- tpm_dev_vendor_release(chip);
+ rc = alloc_chrdev_region(&tpm_devt, 0, TPM_NUM_DEVICES, "tpm");
+ if (rc < 0) {
+ pr_err("tpm: failed to allocate char dev region\n");
+ class_destroy(tpm_class);
+ return rc;
+ }
- chip->release(dev);
- kfree(chip);
+ return 0;
}
-/*
- * Called from tpm_<specific>.c probe function only for devices
- * the driver has determined it should claim. Prior to calling
- * this function the specific probe function has called pci_enable_device
- * upon errant exit from this function specific probe function should call
- * pci_disable_device
- */
-struct tpm_chip *tpm_register_hardware(struct device *dev,
- const struct tpm_class_ops *ops)
+static void __exit tpm_exit(void)
{
- struct tpm_chip *chip;
-
- /* Driver specific per-device data */
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
-
- if (chip == NULL)
- return NULL;
-
- mutex_init(&chip->tpm_mutex);
- INIT_LIST_HEAD(&chip->list);
-
- chip->ops = ops;
- chip->dev_num = find_first_zero_bit(dev_mask, TPM_NUM_DEVICES);
-
- if (chip->dev_num >= TPM_NUM_DEVICES) {
- dev_err(dev, "No available tpm device numbers\n");
- goto out_free;
- }
-
- set_bit(chip->dev_num, dev_mask);
-
- scnprintf(chip->devname, sizeof(chip->devname), "%s%d", "tpm",
- chip->dev_num);
-
- chip->dev = get_device(dev);
- chip->release = dev->release;
- dev->release = tpm_dev_release;
- dev_set_drvdata(dev, chip);
-
- if (tpm_dev_add_device(chip))
- goto put_device;
-
- if (tpm_sysfs_add_device(chip))
- goto del_misc;
-
- if (tpm_add_ppi(&dev->kobj))
- goto del_sysfs;
-
- chip->bios_dir = tpm_bios_log_setup(chip->devname);
-
- /* Make chip available */
- spin_lock(&driver_lock);
- list_add_rcu(&chip->list, &tpm_chip_list);
- spin_unlock(&driver_lock);
-
- return chip;
-
-del_sysfs:
- tpm_sysfs_del_device(chip);
-del_misc:
- tpm_dev_del_device(chip);
-put_device:
- put_device(chip->dev);
-out_free:
- kfree(chip);
- return NULL;
+ class_destroy(tpm_class);
+ unregister_chrdev_region(tpm_devt, TPM_NUM_DEVICES);
}
-EXPORT_SYMBOL_GPL(tpm_register_hardware);
+
+subsys_initcall(tpm_init);
+module_exit(tpm_exit);
MODULE_AUTHOR("Leendert van Doorn (leendert@watson.ibm.com)");
MODULE_DESCRIPTION("TPM Driver");
diff --git a/drivers/char/tpm/tpm-sysfs.c b/drivers/char/tpm/tpm-sysfs.c
index 01730a27ae07..ee66fd4673f3 100644
--- a/drivers/char/tpm/tpm-sysfs.c
+++ b/drivers/char/tpm/tpm-sysfs.c
@@ -20,25 +20,6 @@
#include <linux/device.h>
#include "tpm.h"
-/* XXX for now this helper is duplicated in tpm-interface.c */
-static ssize_t transmit_cmd(struct tpm_chip *chip, struct tpm_cmd_t *cmd,
- int len, const char *desc)
-{
- int err;
-
- len = tpm_transmit(chip, (u8 *) cmd, len);
- if (len < 0)
- return len;
- else if (len < TPM_HEADER_SIZE)
- return -EFAULT;
-
- err = be32_to_cpu(cmd->header.out.return_code);
- if (err != 0 && desc)
- dev_err(chip->dev, "A TPM error (%d) occurred %s\n", err, desc);
-
- return err;
-}
-
#define READ_PUBEK_RESULT_SIZE 314
#define TPM_ORD_READPUBEK cpu_to_be32(124)
static struct tpm_input_header tpm_readpubek_header = {
@@ -58,8 +39,8 @@ static ssize_t pubek_show(struct device *dev, struct device_attribute *attr,
struct tpm_chip *chip = dev_get_drvdata(dev);
tpm_cmd.header.in = tpm_readpubek_header;
- err = transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
- "attempting to read the PUBEK");
+ err = tpm_transmit_cmd(chip, &tpm_cmd, READ_PUBEK_RESULT_SIZE,
+ "attempting to read the PUBEK");
if (err)
goto out;
@@ -303,16 +284,16 @@ static const struct attribute_group tpm_dev_group = {
int tpm_sysfs_add_device(struct tpm_chip *chip)
{
int err;
- err = sysfs_create_group(&chip->dev->kobj,
+ err = sysfs_create_group(&chip->pdev->kobj,
&tpm_dev_group);
if (err)
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"failed to create sysfs attributes, %d\n", err);
return err;
}
void tpm_sysfs_del_device(struct tpm_chip *chip)
{
- sysfs_remove_group(&chip->dev->kobj, &tpm_dev_group);
+ sysfs_remove_group(&chip->pdev->kobj, &tpm_dev_group);
}
diff --git a/drivers/char/tpm/tpm.h b/drivers/char/tpm/tpm.h
index e4d0888d2eab..f8319a0860fd 100644
--- a/drivers/char/tpm/tpm.h
+++ b/drivers/char/tpm/tpm.h
@@ -10,23 +10,24 @@
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
* Device driver for TCG/TCPA TPM (trusted platform module).
- * Specifications at www.trustedcomputinggroup.org
+ * Specifications at www.trustedcomputinggroup.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, version 2 of the
* License.
- *
+ *
*/
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/fs.h>
#include <linux/mutex.h>
#include <linux/sched.h>
-#include <linux/miscdevice.h>
#include <linux/platform_device.h>
#include <linux/io.h>
#include <linux/tpm.h>
+#include <linux/acpi.h>
+#include <linux/cdev.h>
enum tpm_const {
TPM_MINOR = 224, /* officially assigned */
@@ -61,6 +62,59 @@ enum tpm_duration {
#define TPM_ERR_INVALID_POSTINIT 38
#define TPM_HEADER_SIZE 10
+
+enum tpm2_const {
+ TPM2_PLATFORM_PCR = 24,
+ TPM2_PCR_SELECT_MIN = ((TPM2_PLATFORM_PCR + 7) / 8),
+ TPM2_TIMEOUT_A = 750,
+ TPM2_TIMEOUT_B = 2000,
+ TPM2_TIMEOUT_C = 200,
+ TPM2_TIMEOUT_D = 30,
+ TPM2_DURATION_SHORT = 20,
+ TPM2_DURATION_MEDIUM = 750,
+ TPM2_DURATION_LONG = 2000,
+};
+
+enum tpm2_structures {
+ TPM2_ST_NO_SESSIONS = 0x8001,
+ TPM2_ST_SESSIONS = 0x8002,
+};
+
+enum tpm2_return_codes {
+ TPM2_RC_INITIALIZE = 0x0100,
+ TPM2_RC_TESTING = 0x090A,
+ TPM2_RC_DISABLED = 0x0120,
+};
+
+enum tpm2_algorithms {
+ TPM2_ALG_SHA1 = 0x0004,
+};
+
+enum tpm2_command_codes {
+ TPM2_CC_FIRST = 0x011F,
+ TPM2_CC_SELF_TEST = 0x0143,
+ TPM2_CC_STARTUP = 0x0144,
+ TPM2_CC_SHUTDOWN = 0x0145,
+ TPM2_CC_GET_CAPABILITY = 0x017A,
+ TPM2_CC_GET_RANDOM = 0x017B,
+ TPM2_CC_PCR_READ = 0x017E,
+ TPM2_CC_PCR_EXTEND = 0x0182,
+ TPM2_CC_LAST = 0x018F,
+};
+
+enum tpm2_permanent_handles {
+ TPM2_RS_PW = 0x40000009,
+};
+
+enum tpm2_capabilities {
+ TPM2_CAP_TPM_PROPERTIES = 6,
+};
+
+enum tpm2_startup_types {
+ TPM2_SU_CLEAR = 0x0000,
+ TPM2_SU_STATE = 0x0001,
+};
+
struct tpm_chip;
struct tpm_vendor_specific {
@@ -73,7 +127,6 @@ struct tpm_vendor_specific {
int region_size;
int have_region;
- struct miscdevice miscdev;
struct list_head list;
int locality;
unsigned long timeout_a, timeout_b, timeout_c, timeout_d; /* jiffies */
@@ -88,15 +141,27 @@ struct tpm_vendor_specific {
u16 manufacturer_id;
};
-#define TPM_VPRIV(c) (c)->vendor.priv
+#define TPM_VPRIV(c) ((c)->vendor.priv)
#define TPM_VID_INTEL 0x8086
#define TPM_VID_WINBOND 0x1050
#define TPM_VID_STM 0x104A
+#define TPM_PPI_VERSION_LEN 3
+
+enum tpm_chip_flags {
+ TPM_CHIP_FLAG_REGISTERED = BIT(0),
+ TPM_CHIP_FLAG_PPI = BIT(1),
+ TPM_CHIP_FLAG_TPM2 = BIT(2),
+};
+
struct tpm_chip {
- struct device *dev; /* Device stuff */
+ struct device *pdev; /* Device stuff */
+ struct device dev;
+ struct cdev cdev;
+
const struct tpm_class_ops *ops;
+ unsigned int flags;
int dev_num; /* /dev/tpm# */
char devname[7];
@@ -109,15 +174,19 @@ struct tpm_chip {
struct dentry **bios_dir;
+#ifdef CONFIG_ACPI
+ acpi_handle acpi_dev_handle;
+ char ppi_version[TPM_PPI_VERSION_LEN + 1];
+#endif /* CONFIG_ACPI */
+
struct list_head list;
- void (*release) (struct device *);
};
#define to_tpm_chip(n) container_of(n, struct tpm_chip, vendor)
static inline void tpm_chip_put(struct tpm_chip *chip)
{
- module_put(chip->dev->driver->owner);
+ module_put(chip->pdev->driver->owner);
}
static inline int tpm_read_index(int base, int index)
@@ -313,40 +382,58 @@ struct tpm_cmd_t {
tpm_cmd_params params;
} __packed;
-ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
+extern struct class *tpm_class;
+extern dev_t tpm_devt;
+extern const struct file_operations tpm_fops;
+ssize_t tpm_getcap(struct device *, __be32, cap_t *, const char *);
ssize_t tpm_transmit(struct tpm_chip *chip, const char *buf,
size_t bufsiz);
+ssize_t tpm_transmit_cmd(struct tpm_chip *chip, void *cmd, int len,
+ const char *desc);
extern int tpm_get_timeouts(struct tpm_chip *);
extern void tpm_gen_interrupt(struct tpm_chip *);
extern int tpm_do_selftest(struct tpm_chip *);
extern unsigned long tpm_calc_ordinal_duration(struct tpm_chip *, u32);
-extern struct tpm_chip* tpm_register_hardware(struct device *,
- const struct tpm_class_ops *ops);
-extern void tpm_dev_vendor_release(struct tpm_chip *);
-extern void tpm_remove_hardware(struct device *);
extern int tpm_pm_suspend(struct device *);
extern int tpm_pm_resume(struct device *);
extern int wait_for_tpm_stat(struct tpm_chip *, u8, unsigned long,
wait_queue_head_t *, bool);
-int tpm_dev_add_device(struct tpm_chip *chip);
-void tpm_dev_del_device(struct tpm_chip *chip);
+struct tpm_chip *tpm_chip_find_get(int chip_num);
+extern struct tpm_chip *tpmm_chip_alloc(struct device *dev,
+ const struct tpm_class_ops *ops);
+extern int tpm_chip_register(struct tpm_chip *chip);
+extern void tpm_chip_unregister(struct tpm_chip *chip);
+
int tpm_sysfs_add_device(struct tpm_chip *chip);
void tpm_sysfs_del_device(struct tpm_chip *chip);
int tpm_pcr_read_dev(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
#ifdef CONFIG_ACPI
-extern int tpm_add_ppi(struct kobject *);
-extern void tpm_remove_ppi(struct kobject *);
+extern int tpm_add_ppi(struct tpm_chip *chip);
+extern void tpm_remove_ppi(struct tpm_chip *chip);
#else
-static inline int tpm_add_ppi(struct kobject *parent)
+static inline int tpm_add_ppi(struct tpm_chip *chip)
{
return 0;
}
-static inline void tpm_remove_ppi(struct kobject *parent)
+static inline void tpm_remove_ppi(struct tpm_chip *chip)
{
}
#endif
+
+int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf);
+int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash);
+int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max);
+ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id,
+ u32 *value, const char *desc);
+
+extern int tpm2_startup(struct tpm_chip *chip, u16 startup_type);
+extern void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type);
+extern unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *, u32);
+extern int tpm2_do_selftest(struct tpm_chip *chip);
+extern int tpm2_gen_interrupt(struct tpm_chip *chip);
+extern int tpm2_probe(struct tpm_chip *chip);
diff --git a/drivers/char/tpm/tpm2-cmd.c b/drivers/char/tpm/tpm2-cmd.c
new file mode 100644
index 000000000000..011909a9be96
--- /dev/null
+++ b/drivers/char/tpm/tpm2-cmd.c
@@ -0,0 +1,646 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * This file contains TPM2 protocol implementations of the commands
+ * used by the kernel internally.
+ *
+ * This program is free software; 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 "tpm.h"
+
+struct tpm2_startup_in {
+ __be16 startup_type;
+} __packed;
+
+struct tpm2_self_test_in {
+ u8 full_test;
+} __packed;
+
+struct tpm2_pcr_read_in {
+ __be32 pcr_selects_cnt;
+ __be16 hash_alg;
+ u8 pcr_select_size;
+ u8 pcr_select[TPM2_PCR_SELECT_MIN];
+} __packed;
+
+struct tpm2_pcr_read_out {
+ __be32 update_cnt;
+ __be32 pcr_selects_cnt;
+ __be16 hash_alg;
+ u8 pcr_select_size;
+ u8 pcr_select[TPM2_PCR_SELECT_MIN];
+ __be32 digests_cnt;
+ __be16 digest_size;
+ u8 digest[TPM_DIGEST_SIZE];
+} __packed;
+
+struct tpm2_null_auth_area {
+ __be32 handle;
+ __be16 nonce_size;
+ u8 attributes;
+ __be16 auth_size;
+} __packed;
+
+struct tpm2_pcr_extend_in {
+ __be32 pcr_idx;
+ __be32 auth_area_size;
+ struct tpm2_null_auth_area auth_area;
+ __be32 digest_cnt;
+ __be16 hash_alg;
+ u8 digest[TPM_DIGEST_SIZE];
+} __packed;
+
+struct tpm2_get_tpm_pt_in {
+ __be32 cap_id;
+ __be32 property_id;
+ __be32 property_cnt;
+} __packed;
+
+struct tpm2_get_tpm_pt_out {
+ u8 more_data;
+ __be32 subcap_id;
+ __be32 property_cnt;
+ __be32 property_id;
+ __be32 value;
+} __packed;
+
+struct tpm2_get_random_in {
+ __be16 size;
+} __packed;
+
+struct tpm2_get_random_out {
+ __be16 size;
+ u8 buffer[TPM_MAX_RNG_DATA];
+} __packed;
+
+union tpm2_cmd_params {
+ struct tpm2_startup_in startup_in;
+ struct tpm2_self_test_in selftest_in;
+ struct tpm2_pcr_read_in pcrread_in;
+ struct tpm2_pcr_read_out pcrread_out;
+ struct tpm2_pcr_extend_in pcrextend_in;
+ struct tpm2_get_tpm_pt_in get_tpm_pt_in;
+ struct tpm2_get_tpm_pt_out get_tpm_pt_out;
+ struct tpm2_get_random_in getrandom_in;
+ struct tpm2_get_random_out getrandom_out;
+};
+
+struct tpm2_cmd {
+ tpm_cmd_header header;
+ union tpm2_cmd_params params;
+} __packed;
+
+/*
+ * Array with one entry per ordinal defining the maximum amount
+ * of time the chip could take to return the result. The values
+ * of the SHORT, MEDIUM, and LONG durations are taken from the
+ * PC Client Profile (PTP) specification.
+ */
+static const u8 tpm2_ordinal_duration[TPM2_CC_LAST - TPM2_CC_FIRST + 1] = {
+ TPM_UNDEFINED, /* 11F */
+ TPM_UNDEFINED, /* 120 */
+ TPM_LONG, /* 121 */
+ TPM_UNDEFINED, /* 122 */
+ TPM_UNDEFINED, /* 123 */
+ TPM_UNDEFINED, /* 124 */
+ TPM_UNDEFINED, /* 125 */
+ TPM_UNDEFINED, /* 126 */
+ TPM_UNDEFINED, /* 127 */
+ TPM_UNDEFINED, /* 128 */
+ TPM_LONG, /* 129 */
+ TPM_UNDEFINED, /* 12a */
+ TPM_UNDEFINED, /* 12b */
+ TPM_UNDEFINED, /* 12c */
+ TPM_UNDEFINED, /* 12d */
+ TPM_UNDEFINED, /* 12e */
+ TPM_UNDEFINED, /* 12f */
+ TPM_UNDEFINED, /* 130 */
+ TPM_UNDEFINED, /* 131 */
+ TPM_UNDEFINED, /* 132 */
+ TPM_UNDEFINED, /* 133 */
+ TPM_UNDEFINED, /* 134 */
+ TPM_UNDEFINED, /* 135 */
+ TPM_UNDEFINED, /* 136 */
+ TPM_UNDEFINED, /* 137 */
+ TPM_UNDEFINED, /* 138 */
+ TPM_UNDEFINED, /* 139 */
+ TPM_UNDEFINED, /* 13a */
+ TPM_UNDEFINED, /* 13b */
+ TPM_UNDEFINED, /* 13c */
+ TPM_UNDEFINED, /* 13d */
+ TPM_MEDIUM, /* 13e */
+ TPM_UNDEFINED, /* 13f */
+ TPM_UNDEFINED, /* 140 */
+ TPM_UNDEFINED, /* 141 */
+ TPM_UNDEFINED, /* 142 */
+ TPM_LONG, /* 143 */
+ TPM_MEDIUM, /* 144 */
+ TPM_UNDEFINED, /* 145 */
+ TPM_UNDEFINED, /* 146 */
+ TPM_UNDEFINED, /* 147 */
+ TPM_UNDEFINED, /* 148 */
+ TPM_UNDEFINED, /* 149 */
+ TPM_UNDEFINED, /* 14a */
+ TPM_UNDEFINED, /* 14b */
+ TPM_UNDEFINED, /* 14c */
+ TPM_UNDEFINED, /* 14d */
+ TPM_LONG, /* 14e */
+ TPM_UNDEFINED, /* 14f */
+ TPM_UNDEFINED, /* 150 */
+ TPM_UNDEFINED, /* 151 */
+ TPM_UNDEFINED, /* 152 */
+ TPM_UNDEFINED, /* 153 */
+ TPM_UNDEFINED, /* 154 */
+ TPM_UNDEFINED, /* 155 */
+ TPM_UNDEFINED, /* 156 */
+ TPM_UNDEFINED, /* 157 */
+ TPM_UNDEFINED, /* 158 */
+ TPM_UNDEFINED, /* 159 */
+ TPM_UNDEFINED, /* 15a */
+ TPM_UNDEFINED, /* 15b */
+ TPM_MEDIUM, /* 15c */
+ TPM_UNDEFINED, /* 15d */
+ TPM_UNDEFINED, /* 15e */
+ TPM_UNDEFINED, /* 15f */
+ TPM_UNDEFINED, /* 160 */
+ TPM_UNDEFINED, /* 161 */
+ TPM_UNDEFINED, /* 162 */
+ TPM_UNDEFINED, /* 163 */
+ TPM_UNDEFINED, /* 164 */
+ TPM_UNDEFINED, /* 165 */
+ TPM_UNDEFINED, /* 166 */
+ TPM_UNDEFINED, /* 167 */
+ TPM_UNDEFINED, /* 168 */
+ TPM_UNDEFINED, /* 169 */
+ TPM_UNDEFINED, /* 16a */
+ TPM_UNDEFINED, /* 16b */
+ TPM_UNDEFINED, /* 16c */
+ TPM_UNDEFINED, /* 16d */
+ TPM_UNDEFINED, /* 16e */
+ TPM_UNDEFINED, /* 16f */
+ TPM_UNDEFINED, /* 170 */
+ TPM_UNDEFINED, /* 171 */
+ TPM_UNDEFINED, /* 172 */
+ TPM_UNDEFINED, /* 173 */
+ TPM_UNDEFINED, /* 174 */
+ TPM_UNDEFINED, /* 175 */
+ TPM_UNDEFINED, /* 176 */
+ TPM_LONG, /* 177 */
+ TPM_UNDEFINED, /* 178 */
+ TPM_UNDEFINED, /* 179 */
+ TPM_MEDIUM, /* 17a */
+ TPM_LONG, /* 17b */
+ TPM_UNDEFINED, /* 17c */
+ TPM_UNDEFINED, /* 17d */
+ TPM_UNDEFINED, /* 17e */
+ TPM_UNDEFINED, /* 17f */
+ TPM_UNDEFINED, /* 180 */
+ TPM_UNDEFINED, /* 181 */
+ TPM_MEDIUM, /* 182 */
+ TPM_UNDEFINED, /* 183 */
+ TPM_UNDEFINED, /* 184 */
+ TPM_MEDIUM, /* 185 */
+ TPM_MEDIUM, /* 186 */
+ TPM_UNDEFINED, /* 187 */
+ TPM_UNDEFINED, /* 188 */
+ TPM_UNDEFINED, /* 189 */
+ TPM_UNDEFINED, /* 18a */
+ TPM_UNDEFINED, /* 18b */
+ TPM_UNDEFINED, /* 18c */
+ TPM_UNDEFINED, /* 18d */
+ TPM_UNDEFINED, /* 18e */
+ TPM_UNDEFINED /* 18f */
+};
+
+#define TPM2_PCR_READ_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_pcr_read_in))
+
+static const struct tpm_input_header tpm2_pcrread_header = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .length = cpu_to_be32(TPM2_PCR_READ_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_PCR_READ)
+};
+
+/**
+ * tpm2_pcr_read() - read a PCR value
+ * @chip: TPM chip to use.
+ * @pcr_idx: index of the PCR to read.
+ * @ref_buf: buffer to store the resulting hash,
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_pcr_read(struct tpm_chip *chip, int pcr_idx, u8 *res_buf)
+{
+ int rc;
+ struct tpm2_cmd cmd;
+ u8 *buf;
+
+ if (pcr_idx >= TPM2_PLATFORM_PCR)
+ return -EINVAL;
+
+ cmd.header.in = tpm2_pcrread_header;
+ cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
+ cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
+ cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
+
+ memset(cmd.params.pcrread_in.pcr_select, 0,
+ sizeof(cmd.params.pcrread_in.pcr_select));
+ cmd.params.pcrread_in.pcr_select[pcr_idx >> 3] = 1 << (pcr_idx & 0x7);
+
+ rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+ "attempting to read a pcr value");
+ if (rc == 0) {
+ buf = cmd.params.pcrread_out.digest;
+ memcpy(res_buf, buf, TPM_DIGEST_SIZE);
+ }
+
+ return rc;
+}
+
+#define TPM2_GET_PCREXTEND_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_pcr_extend_in))
+
+static const struct tpm_input_header tpm2_pcrextend_header = {
+ .tag = cpu_to_be16(TPM2_ST_SESSIONS),
+ .length = cpu_to_be32(TPM2_GET_PCREXTEND_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_PCR_EXTEND)
+};
+
+/**
+ * tpm2_pcr_extend() - extend a PCR value
+ * @chip: TPM chip to use.
+ * @pcr_idx: index of the PCR.
+ * @hash: hash value to use for the extend operation.
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_pcr_extend(struct tpm_chip *chip, int pcr_idx, const u8 *hash)
+{
+ struct tpm2_cmd cmd;
+ int rc;
+
+ cmd.header.in = tpm2_pcrextend_header;
+ cmd.params.pcrextend_in.pcr_idx = cpu_to_be32(pcr_idx);
+ cmd.params.pcrextend_in.auth_area_size =
+ cpu_to_be32(sizeof(struct tpm2_null_auth_area));
+ cmd.params.pcrextend_in.auth_area.handle =
+ cpu_to_be32(TPM2_RS_PW);
+ cmd.params.pcrextend_in.auth_area.nonce_size = 0;
+ cmd.params.pcrextend_in.auth_area.attributes = 0;
+ cmd.params.pcrextend_in.auth_area.auth_size = 0;
+ cmd.params.pcrextend_in.digest_cnt = cpu_to_be32(1);
+ cmd.params.pcrextend_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
+ memcpy(cmd.params.pcrextend_in.digest, hash, TPM_DIGEST_SIZE);
+
+ rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+ "attempting extend a PCR value");
+
+ return rc;
+}
+
+#define TPM2_GETRANDOM_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_get_random_in))
+
+static const struct tpm_input_header tpm2_getrandom_header = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .length = cpu_to_be32(TPM2_GETRANDOM_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_GET_RANDOM)
+};
+
+/**
+ * tpm2_get_random() - get random bytes from the TPM RNG
+ * @chip: TPM chip to use
+ * @out: destination buffer for the random bytes
+ * @max: the max number of bytes to write to @out
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_get_random(struct tpm_chip *chip, u8 *out, size_t max)
+{
+ struct tpm2_cmd cmd;
+ u32 recd;
+ u32 num_bytes;
+ int err;
+ int total = 0;
+ int retries = 5;
+ u8 *dest = out;
+
+ num_bytes = min_t(u32, max, sizeof(cmd.params.getrandom_out.buffer));
+
+ if (!out || !num_bytes ||
+ max > sizeof(cmd.params.getrandom_out.buffer))
+ return -EINVAL;
+
+ do {
+ cmd.header.in = tpm2_getrandom_header;
+ cmd.params.getrandom_in.size = cpu_to_be16(num_bytes);
+
+ err = tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+ "attempting get random");
+ if (err)
+ break;
+
+ recd = min_t(u32, be16_to_cpu(cmd.params.getrandom_out.size),
+ num_bytes);
+ memcpy(dest, cmd.params.getrandom_out.buffer, recd);
+
+ dest += recd;
+ total += recd;
+ num_bytes -= recd;
+ } while (retries-- && total < max);
+
+ return total ? total : -EIO;
+}
+
+#define TPM2_GET_TPM_PT_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_get_tpm_pt_in))
+
+static const struct tpm_input_header tpm2_get_tpm_pt_header = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .length = cpu_to_be32(TPM2_GET_TPM_PT_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_GET_CAPABILITY)
+};
+
+/**
+ * tpm2_get_tpm_pt() - get value of a TPM_CAP_TPM_PROPERTIES type property
+ * @chip: TPM chip to use.
+ * @property_id: property ID.
+ * @value: output variable.
+ * @desc: passed to tpm_transmit_cmd()
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+ssize_t tpm2_get_tpm_pt(struct tpm_chip *chip, u32 property_id, u32 *value,
+ const char *desc)
+{
+ struct tpm2_cmd cmd;
+ int rc;
+
+ cmd.header.in = tpm2_get_tpm_pt_header;
+ cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
+ cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(property_id);
+ cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
+
+ rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), desc);
+ if (!rc)
+ *value = cmd.params.get_tpm_pt_out.value;
+
+ return rc;
+}
+
+#define TPM2_STARTUP_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_startup_in))
+
+static const struct tpm_input_header tpm2_startup_header = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .length = cpu_to_be32(TPM2_STARTUP_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_STARTUP)
+};
+
+/**
+ * tpm2_startup() - send startup command to the TPM chip
+ * @chip: TPM chip to use.
+ * @startup_type startup type. The value is either
+ * TPM_SU_CLEAR or TPM_SU_STATE.
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_startup(struct tpm_chip *chip, u16 startup_type)
+{
+ struct tpm2_cmd cmd;
+
+ cmd.header.in = tpm2_startup_header;
+
+ cmd.params.startup_in.startup_type = cpu_to_be16(startup_type);
+ return tpm_transmit_cmd(chip, &cmd, sizeof(cmd),
+ "attempting to start the TPM");
+}
+EXPORT_SYMBOL_GPL(tpm2_startup);
+
+#define TPM2_SHUTDOWN_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_startup_in))
+
+static const struct tpm_input_header tpm2_shutdown_header = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .length = cpu_to_be32(TPM2_SHUTDOWN_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_SHUTDOWN)
+};
+
+/**
+ * tpm2_shutdown() - send shutdown command to the TPM chip
+ * @chip: TPM chip to use.
+ * @shutdown_type shutdown type. The value is either
+ * TPM_SU_CLEAR or TPM_SU_STATE.
+ */
+void tpm2_shutdown(struct tpm_chip *chip, u16 shutdown_type)
+{
+ struct tpm2_cmd cmd;
+ int rc;
+
+ cmd.header.in = tpm2_shutdown_header;
+ cmd.params.startup_in.startup_type = cpu_to_be16(shutdown_type);
+
+ rc = tpm_transmit_cmd(chip, &cmd, sizeof(cmd), "stopping the TPM");
+
+ /* In places where shutdown command is sent there's no much we can do
+ * except print the error code on a system failure.
+ */
+ if (rc < 0)
+ dev_warn(chip->pdev, "transmit returned %d while stopping the TPM",
+ rc);
+}
+EXPORT_SYMBOL_GPL(tpm2_shutdown);
+
+/*
+ * tpm2_calc_ordinal_duration() - maximum duration for a command
+ * @chip: TPM chip to use.
+ * @ordinal: command code number.
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+unsigned long tpm2_calc_ordinal_duration(struct tpm_chip *chip, u32 ordinal)
+{
+ int index = TPM_UNDEFINED;
+ int duration = 0;
+
+ if (ordinal >= TPM2_CC_FIRST && ordinal <= TPM2_CC_LAST)
+ index = tpm2_ordinal_duration[ordinal - TPM2_CC_FIRST];
+
+ if (index != TPM_UNDEFINED)
+ duration = chip->vendor.duration[index];
+
+ if (duration <= 0)
+ duration = 2 * 60 * HZ;
+
+ return duration;
+}
+EXPORT_SYMBOL_GPL(tpm2_calc_ordinal_duration);
+
+#define TPM2_SELF_TEST_IN_SIZE \
+ (sizeof(struct tpm_input_header) + \
+ sizeof(struct tpm2_self_test_in))
+
+static const struct tpm_input_header tpm2_selftest_header = {
+ .tag = cpu_to_be16(TPM2_ST_NO_SESSIONS),
+ .length = cpu_to_be32(TPM2_SELF_TEST_IN_SIZE),
+ .ordinal = cpu_to_be32(TPM2_CC_SELF_TEST)
+};
+
+/**
+ * tpm2_continue_selftest() - start a self test
+ * @chip: TPM chip to use
+ * @full: test all commands instead of testing only those that were not
+ * previously tested.
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+static int tpm2_start_selftest(struct tpm_chip *chip, bool full)
+{
+ int rc;
+ struct tpm2_cmd cmd;
+
+ cmd.header.in = tpm2_selftest_header;
+ cmd.params.selftest_in.full_test = full;
+
+ rc = tpm_transmit_cmd(chip, &cmd, TPM2_SELF_TEST_IN_SIZE,
+ "continue selftest");
+
+ /* At least some prototype chips seem to give RC_TESTING error
+ * immediately. This is a workaround for that.
+ */
+ if (rc == TPM2_RC_TESTING) {
+ dev_warn(chip->pdev, "Got RC_TESTING, ignoring\n");
+ rc = 0;
+ }
+
+ return rc;
+}
+
+/**
+ * tpm2_do_selftest() - run a full self test
+ * @chip: TPM chip to use
+ *
+ * During the self test TPM2 commands return with the error code RC_TESTING.
+ * Waiting is done by issuing PCR read until it executes successfully.
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_do_selftest(struct tpm_chip *chip)
+{
+ int rc;
+ unsigned int loops;
+ unsigned int delay_msec = 100;
+ unsigned long duration;
+ struct tpm2_cmd cmd;
+ int i;
+
+ duration = tpm2_calc_ordinal_duration(chip, TPM2_CC_SELF_TEST);
+
+ loops = jiffies_to_msecs(duration) / delay_msec;
+
+ rc = tpm2_start_selftest(chip, true);
+ if (rc)
+ return rc;
+
+ for (i = 0; i < loops; i++) {
+ /* Attempt to read a PCR value */
+ cmd.header.in = tpm2_pcrread_header;
+ cmd.params.pcrread_in.pcr_selects_cnt = cpu_to_be32(1);
+ cmd.params.pcrread_in.hash_alg = cpu_to_be16(TPM2_ALG_SHA1);
+ cmd.params.pcrread_in.pcr_select_size = TPM2_PCR_SELECT_MIN;
+ cmd.params.pcrread_in.pcr_select[0] = 0x01;
+ cmd.params.pcrread_in.pcr_select[1] = 0x00;
+ cmd.params.pcrread_in.pcr_select[2] = 0x00;
+
+ rc = tpm_transmit_cmd(chip, (u8 *) &cmd, sizeof(cmd), NULL);
+ if (rc < 0)
+ break;
+
+ rc = be32_to_cpu(cmd.header.out.return_code);
+ if (rc != TPM2_RC_TESTING)
+ break;
+
+ msleep(delay_msec);
+ }
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(tpm2_do_selftest);
+
+/**
+ * tpm2_gen_interrupt() - generate an interrupt
+ * @chip: TPM chip to use
+ *
+ * 0 is returned when the operation is successful. If a negative number is
+ * returned it remarks a POSIX error code. If a positive number is returned
+ * it remarks a TPM error.
+ */
+int tpm2_gen_interrupt(struct tpm_chip *chip)
+{
+ u32 dummy;
+
+ return tpm2_get_tpm_pt(chip, 0x100, &dummy,
+ "attempting to generate an interrupt");
+}
+EXPORT_SYMBOL_GPL(tpm2_gen_interrupt);
+
+/**
+ * tpm2_probe() - probe TPM 2.0
+ * @chip: TPM chip to use
+ *
+ * Send idempotent TPM 2.0 command and see whether TPM 2.0 chip replied based on
+ * the reply tag.
+ */
+int tpm2_probe(struct tpm_chip *chip)
+{
+ struct tpm2_cmd cmd;
+ int rc;
+
+ cmd.header.in = tpm2_get_tpm_pt_header;
+ cmd.params.get_tpm_pt_in.cap_id = cpu_to_be32(TPM2_CAP_TPM_PROPERTIES);
+ cmd.params.get_tpm_pt_in.property_id = cpu_to_be32(0x100);
+ cmd.params.get_tpm_pt_in.property_cnt = cpu_to_be32(1);
+
+ rc = tpm_transmit(chip, (const char *) &cmd, sizeof(cmd));
+ if (rc < 0)
+ return rc;
+ else if (rc < TPM_HEADER_SIZE)
+ return -EFAULT;
+
+ if (be16_to_cpu(cmd.header.out.tag) == TPM2_ST_NO_SESSIONS)
+ chip->flags |= TPM_CHIP_FLAG_TPM2;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(tpm2_probe);
diff --git a/drivers/char/tpm/tpm_atmel.c b/drivers/char/tpm/tpm_atmel.c
index 435c8b9dd2f8..dfadad0916a1 100644
--- a/drivers/char/tpm/tpm_atmel.c
+++ b/drivers/char/tpm/tpm_atmel.c
@@ -49,7 +49,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
for (i = 0; i < 6; i++) {
status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
- dev_err(chip->dev, "error reading header\n");
+ dev_err(chip->pdev, "error reading header\n");
return -EIO;
}
*buf++ = ioread8(chip->vendor.iobase);
@@ -60,12 +60,12 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
size = be32_to_cpu(*native_size);
if (count < size) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"Recv size(%d) less than available space\n", size);
for (; i < size; i++) { /* clear the waiting data anyway */
status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
- dev_err(chip->dev, "error reading data\n");
+ dev_err(chip->pdev, "error reading data\n");
return -EIO;
}
}
@@ -76,7 +76,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
for (; i < size; i++) {
status = ioread8(chip->vendor.iobase + 1);
if ((status & ATML_STATUS_DATA_AVAIL) == 0) {
- dev_err(chip->dev, "error reading data\n");
+ dev_err(chip->pdev, "error reading data\n");
return -EIO;
}
*buf++ = ioread8(chip->vendor.iobase);
@@ -86,7 +86,7 @@ static int tpm_atml_recv(struct tpm_chip *chip, u8 *buf, size_t count)
status = ioread8(chip->vendor.iobase + 1);
if (status & ATML_STATUS_DATA_AVAIL) {
- dev_err(chip->dev, "data available is stuck\n");
+ dev_err(chip->pdev, "data available is stuck\n");
return -EIO;
}
@@ -97,9 +97,9 @@ static int tpm_atml_send(struct tpm_chip *chip, u8 *buf, size_t count)
{
int i;
- dev_dbg(chip->dev, "tpm_atml_send:\n");
+ dev_dbg(chip->pdev, "tpm_atml_send:\n");
for (i = 0; i < count; i++) {
- dev_dbg(chip->dev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
+ dev_dbg(chip->pdev, "%d 0x%x(%d)\n", i, buf[i], buf[i]);
iowrite8(buf[i], chip->vendor.iobase);
}
@@ -138,11 +138,11 @@ static void atml_plat_remove(void)
struct tpm_chip *chip = dev_get_drvdata(&pdev->dev);
if (chip) {
+ tpm_chip_unregister(chip);
if (chip->vendor.have_region)
atmel_release_region(chip->vendor.base,
chip->vendor.region_size);
atmel_put_base_addr(chip->vendor.iobase);
- tpm_remove_hardware(chip->dev);
platform_device_unregister(pdev);
}
}
@@ -183,8 +183,9 @@ static int __init init_atmel(void)
goto err_rel_reg;
}
- if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_atmel))) {
- rc = -ENODEV;
+ chip = tpmm_chip_alloc(&pdev->dev, &tpm_atmel);
+ if (IS_ERR(chip)) {
+ rc = PTR_ERR(chip);
goto err_unreg_dev;
}
@@ -193,6 +194,10 @@ static int __init init_atmel(void)
chip->vendor.have_region = have_region;
chip->vendor.region_size = region_size;
+ rc = tpm_chip_register(chip);
+ if (rc)
+ goto err_unreg_dev;
+
return 0;
err_unreg_dev:
diff --git a/drivers/char/tpm/tpm_crb.c b/drivers/char/tpm/tpm_crb.c
new file mode 100644
index 000000000000..b26ceee3585e
--- /dev/null
+++ b/drivers/char/tpm/tpm_crb.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * Authors:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * This device driver implements the TPM interface as defined in
+ * the TCG CRB 2.0 TPM specification.
+ *
+ * This program is free software; 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/acpi.h>
+#include <linux/highmem.h>
+#include <linux/rculist.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include "tpm.h"
+
+#define ACPI_SIG_TPM2 "TPM2"
+
+static const u8 CRB_ACPI_START_UUID[] = {
+ /* 0000 */ 0xAB, 0x6C, 0xBF, 0x6B, 0x63, 0x54, 0x14, 0x47,
+ /* 0008 */ 0xB7, 0xCD, 0xF0, 0x20, 0x3C, 0x03, 0x68, 0xD4
+};
+
+enum crb_defaults {
+ CRB_ACPI_START_REVISION_ID = 1,
+ CRB_ACPI_START_INDEX = 1,
+};
+
+enum crb_start_method {
+ CRB_SM_ACPI_START = 2,
+ CRB_SM_CRB = 7,
+ CRB_SM_CRB_WITH_ACPI_START = 8,
+};
+
+struct acpi_tpm2 {
+ struct acpi_table_header hdr;
+ u16 platform_class;
+ u16 reserved;
+ u64 control_area_pa;
+ u32 start_method;
+} __packed;
+
+enum crb_ca_request {
+ CRB_CA_REQ_GO_IDLE = BIT(0),
+ CRB_CA_REQ_CMD_READY = BIT(1),
+};
+
+enum crb_ca_status {
+ CRB_CA_STS_ERROR = BIT(0),
+ CRB_CA_STS_TPM_IDLE = BIT(1),
+};
+
+enum crb_start {
+ CRB_START_INVOKE = BIT(0),
+};
+
+enum crb_cancel {
+ CRB_CANCEL_INVOKE = BIT(0),
+};
+
+struct crb_control_area {
+ u32 req;
+ u32 sts;
+ u32 cancel;
+ u32 start;
+ u32 int_enable;
+ u32 int_sts;
+ u32 cmd_size;
+ u64 cmd_pa;
+ u32 rsp_size;
+ u64 rsp_pa;
+} __packed;
+
+enum crb_status {
+ CRB_STS_COMPLETE = BIT(0),
+};
+
+enum crb_flags {
+ CRB_FL_ACPI_START = BIT(0),
+ CRB_FL_CRB_START = BIT(1),
+};
+
+struct crb_priv {
+ unsigned int flags;
+ struct crb_control_area __iomem *cca;
+ u8 __iomem *cmd;
+ u8 __iomem *rsp;
+};
+
+static SIMPLE_DEV_PM_OPS(crb_pm, tpm_pm_suspend, tpm_pm_resume);
+
+static u8 crb_status(struct tpm_chip *chip)
+{
+ struct crb_priv *priv = chip->vendor.priv;
+ u8 sts = 0;
+
+ if ((le32_to_cpu(ioread32(&priv->cca->start)) & CRB_START_INVOKE) !=
+ CRB_START_INVOKE)
+ sts |= CRB_STS_COMPLETE;
+
+ return sts;
+}
+
+static int crb_recv(struct tpm_chip *chip, u8 *buf, size_t count)
+{
+ struct crb_priv *priv = chip->vendor.priv;
+ unsigned int expected;
+
+ /* sanity check */
+ if (count < 6)
+ return -EIO;
+
+ if (le32_to_cpu(ioread32(&priv->cca->sts)) & CRB_CA_STS_ERROR)
+ return -EIO;
+
+ memcpy_fromio(buf, priv->rsp, 6);
+ expected = be32_to_cpup((__be32 *) &buf[2]);
+
+ if (expected > count)
+ return -EIO;
+
+ memcpy_fromio(&buf[6], &priv->rsp[6], expected - 6);
+
+ return expected;
+}
+
+static int crb_do_acpi_start(struct tpm_chip *chip)
+{
+ union acpi_object *obj;
+ int rc;
+
+ obj = acpi_evaluate_dsm(chip->acpi_dev_handle,
+ CRB_ACPI_START_UUID,
+ CRB_ACPI_START_REVISION_ID,
+ CRB_ACPI_START_INDEX,
+ NULL);
+ if (!obj)
+ return -ENXIO;
+ rc = obj->integer.value == 0 ? 0 : -ENXIO;
+ ACPI_FREE(obj);
+ return rc;
+}
+
+static int crb_send(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+ struct crb_priv *priv = chip->vendor.priv;
+ int rc = 0;
+
+ if (len > le32_to_cpu(ioread32(&priv->cca->cmd_size))) {
+ dev_err(&chip->dev,
+ "invalid command count value %x %zx\n",
+ (unsigned int) len,
+ (size_t) le32_to_cpu(ioread32(&priv->cca->cmd_size)));
+ return -E2BIG;
+ }
+
+ memcpy_toio(priv->cmd, buf, len);
+
+ /* Make sure that cmd is populated before issuing start. */
+ wmb();
+
+ if (priv->flags & CRB_FL_CRB_START)
+ iowrite32(cpu_to_le32(CRB_START_INVOKE), &priv->cca->start);
+
+ if (priv->flags & CRB_FL_ACPI_START)
+ rc = crb_do_acpi_start(chip);
+
+ return rc;
+}
+
+static void crb_cancel(struct tpm_chip *chip)
+{
+ struct crb_priv *priv = chip->vendor.priv;
+
+ iowrite32(cpu_to_le32(CRB_CANCEL_INVOKE), &priv->cca->cancel);
+
+ /* Make sure that cmd is populated before issuing cancel. */
+ wmb();
+
+ if ((priv->flags & CRB_FL_ACPI_START) && crb_do_acpi_start(chip))
+ dev_err(&chip->dev, "ACPI Start failed\n");
+
+ iowrite32(0, &priv->cca->cancel);
+}
+
+static bool crb_req_canceled(struct tpm_chip *chip, u8 status)
+{
+ struct crb_priv *priv = chip->vendor.priv;
+ u32 cancel = le32_to_cpu(ioread32(&priv->cca->cancel));
+
+ return (cancel & CRB_CANCEL_INVOKE) == CRB_CANCEL_INVOKE;
+}
+
+static const struct tpm_class_ops tpm_crb = {
+ .status = crb_status,
+ .recv = crb_recv,
+ .send = crb_send,
+ .cancel = crb_cancel,
+ .req_canceled = crb_req_canceled,
+ .req_complete_mask = CRB_STS_COMPLETE,
+ .req_complete_val = CRB_STS_COMPLETE,
+};
+
+static int crb_acpi_add(struct acpi_device *device)
+{
+ struct tpm_chip *chip;
+ struct acpi_tpm2 *buf;
+ struct crb_priv *priv;
+ struct device *dev = &device->dev;
+ acpi_status status;
+ u32 sm;
+ u64 pa;
+ int rc;
+
+ chip = tpmm_chip_alloc(dev, &tpm_crb);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ chip->flags = TPM_CHIP_FLAG_TPM2;
+
+ status = acpi_get_table(ACPI_SIG_TPM2, 1,
+ (struct acpi_table_header **) &buf);
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "failed to get TPM2 ACPI table\n");
+ return -ENODEV;
+ }
+
+ if (buf->hdr.length < sizeof(struct acpi_tpm2)) {
+ dev_err(dev, "TPM2 ACPI table has wrong size");
+ return -EINVAL;
+ }
+
+ priv = (struct crb_priv *) devm_kzalloc(dev, sizeof(struct crb_priv),
+ GFP_KERNEL);
+ if (!priv) {
+ dev_err(dev, "failed to devm_kzalloc for private data\n");
+ return -ENOMEM;
+ }
+
+ sm = le32_to_cpu(buf->start_method);
+
+ /* The reason for the extra quirk is that the PTT in 4th Gen Core CPUs
+ * report only ACPI start but in practice seems to require both
+ * ACPI start and CRB start.
+ */
+ if (sm == CRB_SM_CRB || sm == CRB_SM_CRB_WITH_ACPI_START ||
+ !strcmp(acpi_device_hid(device), "MSFT0101"))
+ priv->flags |= CRB_FL_CRB_START;
+
+ if (sm == CRB_SM_ACPI_START || sm == CRB_SM_CRB_WITH_ACPI_START)
+ priv->flags |= CRB_FL_ACPI_START;
+
+ priv->cca = (struct crb_control_area __iomem *)
+ devm_ioremap_nocache(dev, buf->control_area_pa, 0x1000);
+ if (!priv->cca) {
+ dev_err(dev, "ioremap of the control area failed\n");
+ return -ENOMEM;
+ }
+
+ memcpy_fromio(&pa, &priv->cca->cmd_pa, 8);
+ pa = le64_to_cpu(pa);
+ priv->cmd = devm_ioremap_nocache(dev, le64_to_cpu(pa),
+ ioread32(&priv->cca->cmd_size));
+ if (!priv->cmd) {
+ dev_err(dev, "ioremap of the command buffer failed\n");
+ return -ENOMEM;
+ }
+
+ memcpy_fromio(&pa, &priv->cca->rsp_pa, 8);
+ pa = le64_to_cpu(pa);
+ priv->rsp = devm_ioremap_nocache(dev, le64_to_cpu(pa),
+ ioread32(&priv->cca->rsp_size));
+ if (!priv->rsp) {
+ dev_err(dev, "ioremap of the response buffer failed\n");
+ return -ENOMEM;
+ }
+
+ chip->vendor.priv = priv;
+
+ /* Default timeouts and durations */
+ chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
+ chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
+ chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
+ chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
+ chip->vendor.duration[TPM_SHORT] =
+ msecs_to_jiffies(TPM2_DURATION_SHORT);
+ chip->vendor.duration[TPM_MEDIUM] =
+ msecs_to_jiffies(TPM2_DURATION_MEDIUM);
+ chip->vendor.duration[TPM_LONG] =
+ msecs_to_jiffies(TPM2_DURATION_LONG);
+
+ chip->acpi_dev_handle = device->handle;
+
+ rc = tpm2_do_selftest(chip);
+ if (rc)
+ return rc;
+
+ return tpm_chip_register(chip);
+}
+
+static int crb_acpi_remove(struct acpi_device *device)
+{
+ struct device *dev = &device->dev;
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ tpm_chip_unregister(chip);
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ tpm2_shutdown(chip, TPM2_SU_CLEAR);
+
+ return 0;
+}
+
+static struct acpi_device_id crb_device_ids[] = {
+ {"MSFT0101", 0},
+ {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, crb_device_ids);
+
+static struct acpi_driver crb_acpi_driver = {
+ .name = "tpm_crb",
+ .ids = crb_device_ids,
+ .ops = {
+ .add = crb_acpi_add,
+ .remove = crb_acpi_remove,
+ },
+ .drv = {
+ .pm = &crb_pm,
+ },
+};
+
+module_acpi_driver(crb_acpi_driver);
+MODULE_AUTHOR("Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>");
+MODULE_DESCRIPTION("TPM2 Driver");
+MODULE_VERSION("0.1");
+MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_i2c_atmel.c b/drivers/char/tpm/tpm_i2c_atmel.c
index 77272925dee6..7a0ca78ad3c6 100644
--- a/drivers/char/tpm/tpm_i2c_atmel.c
+++ b/drivers/char/tpm/tpm_i2c_atmel.c
@@ -52,7 +52,7 @@ struct priv_data {
static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
struct priv_data *priv = chip->vendor.priv;
- struct i2c_client *client = to_i2c_client(chip->dev);
+ struct i2c_client *client = to_i2c_client(chip->pdev);
s32 status;
priv->len = 0;
@@ -62,7 +62,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
status = i2c_master_send(client, buf, len);
- dev_dbg(chip->dev,
+ dev_dbg(chip->pdev,
"%s(buf=%*ph len=%0zx) -> sts=%d\n", __func__,
(int)min_t(size_t, 64, len), buf, len, status);
return status;
@@ -71,7 +71,7 @@ static int i2c_atmel_send(struct tpm_chip *chip, u8 *buf, size_t len)
static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
struct priv_data *priv = chip->vendor.priv;
- struct i2c_client *client = to_i2c_client(chip->dev);
+ struct i2c_client *client = to_i2c_client(chip->pdev);
struct tpm_output_header *hdr =
(struct tpm_output_header *)priv->buffer;
u32 expected_len;
@@ -88,7 +88,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
return -ENOMEM;
if (priv->len >= expected_len) {
- dev_dbg(chip->dev,
+ dev_dbg(chip->pdev,
"%s early(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
(int)min_t(size_t, 64, expected_len), buf, count,
expected_len);
@@ -97,7 +97,7 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
}
rc = i2c_master_recv(client, buf, expected_len);
- dev_dbg(chip->dev,
+ dev_dbg(chip->pdev,
"%s reread(buf=%*ph count=%0zx) -> ret=%d\n", __func__,
(int)min_t(size_t, 64, expected_len), buf, count,
expected_len);
@@ -106,13 +106,13 @@ static int i2c_atmel_recv(struct tpm_chip *chip, u8 *buf, size_t count)
static void i2c_atmel_cancel(struct tpm_chip *chip)
{
- dev_err(chip->dev, "TPM operation cancellation was requested, but is not supported");
+ dev_err(chip->pdev, "TPM operation cancellation was requested, but is not supported");
}
static u8 i2c_atmel_read_status(struct tpm_chip *chip)
{
struct priv_data *priv = chip->vendor.priv;
- struct i2c_client *client = to_i2c_client(chip->dev);
+ struct i2c_client *client = to_i2c_client(chip->pdev);
int rc;
/* The TPM fails the I2C read until it is ready, so we do the entire
@@ -125,7 +125,7 @@ static u8 i2c_atmel_read_status(struct tpm_chip *chip)
/* Once the TPM has completed the command the command remains readable
* until another command is issued. */
rc = i2c_master_recv(client, priv->buffer, sizeof(priv->buffer));
- dev_dbg(chip->dev,
+ dev_dbg(chip->pdev,
"%s: sts=%d", __func__, rc);
if (rc <= 0)
return 0;
@@ -153,21 +153,20 @@ static const struct tpm_class_ops i2c_atmel = {
static int i2c_atmel_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- int rc;
struct tpm_chip *chip;
struct device *dev = &client->dev;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
return -ENODEV;
- chip = tpm_register_hardware(dev, &i2c_atmel);
- if (!chip) {
- dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
- return -ENODEV;
- }
+ chip = tpmm_chip_alloc(dev, &i2c_atmel);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
GFP_KERNEL);
+ if (!chip->vendor.priv)
+ return -ENOMEM;
/* Default timeouts */
chip->vendor.timeout_a = msecs_to_jiffies(TPM_I2C_SHORT_TIMEOUT);
@@ -179,33 +178,20 @@ static int i2c_atmel_probe(struct i2c_client *client,
/* There is no known way to probe for this device, and all version
* information seems to be read via TPM commands. Thus we rely on the
* TPM startup process in the common code to detect the device. */
- if (tpm_get_timeouts(chip)) {
- rc = -ENODEV;
- goto out_err;
- }
-
- if (tpm_do_selftest(chip)) {
- rc = -ENODEV;
- goto out_err;
- }
+ if (tpm_get_timeouts(chip))
+ return -ENODEV;
- return 0;
+ if (tpm_do_selftest(chip))
+ return -ENODEV;
-out_err:
- tpm_dev_vendor_release(chip);
- tpm_remove_hardware(chip->dev);
- return rc;
+ return tpm_chip_register(chip);
}
static int i2c_atmel_remove(struct i2c_client *client)
{
struct device *dev = &(client->dev);
struct tpm_chip *chip = dev_get_drvdata(dev);
-
- if (chip)
- tpm_dev_vendor_release(chip);
- tpm_remove_hardware(dev);
- kfree(chip);
+ tpm_chip_unregister(chip);
return 0;
}
diff --git a/drivers/char/tpm/tpm_i2c_infineon.c b/drivers/char/tpm/tpm_i2c_infineon.c
index 472af4bb1b61..33c5f360ab01 100644
--- a/drivers/char/tpm/tpm_i2c_infineon.c
+++ b/drivers/char/tpm/tpm_i2c_infineon.c
@@ -446,7 +446,7 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read first 10 bytes, including tag, paramsize, and result */
size = recv_data(chip, buf, TPM_HEADER_SIZE);
if (size < TPM_HEADER_SIZE) {
- dev_err(chip->dev, "Unable to read header\n");
+ dev_err(chip->pdev, "Unable to read header\n");
goto out;
}
@@ -459,14 +459,14 @@ static int tpm_tis_i2c_recv(struct tpm_chip *chip, u8 *buf, size_t count)
size += recv_data(chip, &buf[TPM_HEADER_SIZE],
expected - TPM_HEADER_SIZE);
if (size < expected) {
- dev_err(chip->dev, "Unable to read remainder of result\n");
+ dev_err(chip->pdev, "Unable to read remainder of result\n");
size = -ETIME;
goto out;
}
wait_for_stat(chip, TPM_STS_VALID, chip->vendor.timeout_c, &status);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
- dev_err(chip->dev, "Error left over data\n");
+ dev_err(chip->pdev, "Error left over data\n");
size = -EIO;
goto out;
}
@@ -581,12 +581,9 @@ static int tpm_tis_i2c_init(struct device *dev)
int rc = 0;
struct tpm_chip *chip;
- chip = tpm_register_hardware(dev, &tpm_tis_i2c);
- if (!chip) {
- dev_err(dev, "could not register hardware\n");
- rc = -ENODEV;
- goto out_err;
- }
+ chip = tpmm_chip_alloc(dev, &tpm_tis_i2c);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
/* Disable interrupts */
chip->vendor.irq = 0;
@@ -600,7 +597,7 @@ static int tpm_tis_i2c_init(struct device *dev)
if (request_locality(chip, 0) != 0) {
dev_err(dev, "could not request locality\n");
rc = -ENODEV;
- goto out_vendor;
+ goto out_err;
}
/* read four bytes from DID_VID register */
@@ -628,21 +625,9 @@ static int tpm_tis_i2c_init(struct device *dev)
tpm_get_timeouts(chip);
tpm_do_selftest(chip);
- return 0;
-
+ return tpm_chip_register(chip);
out_release:
release_locality(chip, chip->vendor.locality, 1);
-
-out_vendor:
- /* close file handles */
- tpm_dev_vendor_release(chip);
-
- /* remove hardware */
- tpm_remove_hardware(chip->dev);
-
- /* reset these pointers, otherwise we oops */
- chip->dev->release = NULL;
- chip->release = NULL;
tpm_dev.client = NULL;
out_err:
return rc;
@@ -712,17 +697,9 @@ static int tpm_tis_i2c_probe(struct i2c_client *client,
static int tpm_tis_i2c_remove(struct i2c_client *client)
{
struct tpm_chip *chip = tpm_dev.chip;
- release_locality(chip, chip->vendor.locality, 1);
- /* close file handles */
- tpm_dev_vendor_release(chip);
-
- /* remove hardware */
- tpm_remove_hardware(chip->dev);
-
- /* reset these pointers, otherwise we oops */
- chip->dev->release = NULL;
- chip->release = NULL;
+ tpm_chip_unregister(chip);
+ release_locality(chip, chip->vendor.locality, 1);
tpm_dev.client = NULL;
return 0;
diff --git a/drivers/char/tpm/tpm_i2c_nuvoton.c b/drivers/char/tpm/tpm_i2c_nuvoton.c
index 7b158efd49f7..9d42b7d78e50 100644
--- a/drivers/char/tpm/tpm_i2c_nuvoton.c
+++ b/drivers/char/tpm/tpm_i2c_nuvoton.c
@@ -96,13 +96,13 @@ static s32 i2c_nuvoton_write_buf(struct i2c_client *client, u8 offset, u8 size,
/* read TPM_STS register */
static u8 i2c_nuvoton_read_status(struct tpm_chip *chip)
{
- struct i2c_client *client = to_i2c_client(chip->dev);
+ struct i2c_client *client = to_i2c_client(chip->pdev);
s32 status;
u8 data;
status = i2c_nuvoton_read_buf(client, TPM_STS, 1, &data);
if (status <= 0) {
- dev_err(chip->dev, "%s() error return %d\n", __func__,
+ dev_err(chip->pdev, "%s() error return %d\n", __func__,
status);
data = TPM_STS_ERR_VAL;
}
@@ -127,13 +127,13 @@ static s32 i2c_nuvoton_write_status(struct i2c_client *client, u8 data)
/* write commandReady to TPM_STS register */
static void i2c_nuvoton_ready(struct tpm_chip *chip)
{
- struct i2c_client *client = to_i2c_client(chip->dev);
+ struct i2c_client *client = to_i2c_client(chip->pdev);
s32 status;
/* this causes the current command to be aborted */
status = i2c_nuvoton_write_status(client, TPM_STS_COMMAND_READY);
if (status < 0)
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"%s() fail to write TPM_STS.commandReady\n", __func__);
}
@@ -212,7 +212,7 @@ static int i2c_nuvoton_wait_for_stat(struct tpm_chip *chip, u8 mask, u8 value,
return 0;
} while (time_before(jiffies, stop));
}
- dev_err(chip->dev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
+ dev_err(chip->pdev, "%s(%02x, %02x) -> timeout\n", __func__, mask,
value);
return -ETIMEDOUT;
}
@@ -240,7 +240,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
&chip->vendor.read_queue) == 0) {
burst_count = i2c_nuvoton_get_burstcount(client, chip);
if (burst_count < 0) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"%s() fail to read burstCount=%d\n", __func__,
burst_count);
return -EIO;
@@ -249,12 +249,12 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
rc = i2c_nuvoton_read_buf(client, TPM_DATA_FIFO_R,
bytes2read, &buf[size]);
if (rc < 0) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"%s() fail on i2c_nuvoton_read_buf()=%d\n",
__func__, rc);
return -EIO;
}
- dev_dbg(chip->dev, "%s(%d):", __func__, bytes2read);
+ dev_dbg(chip->pdev, "%s(%d):", __func__, bytes2read);
size += bytes2read;
}
@@ -264,7 +264,7 @@ static int i2c_nuvoton_recv_data(struct i2c_client *client,
/* Read TPM command results */
static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
{
- struct device *dev = chip->dev;
+ struct device *dev = chip->pdev;
struct i2c_client *client = to_i2c_client(dev);
s32 rc;
int expected, status, burst_count, retries, size = 0;
@@ -334,7 +334,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
break;
}
i2c_nuvoton_ready(chip);
- dev_dbg(chip->dev, "%s() -> %d\n", __func__, size);
+ dev_dbg(chip->pdev, "%s() -> %d\n", __func__, size);
return size;
}
@@ -347,7 +347,7 @@ static int i2c_nuvoton_recv(struct tpm_chip *chip, u8 *buf, size_t count)
*/
static int i2c_nuvoton_send(struct tpm_chip *chip, u8 *buf, size_t len)
{
- struct device *dev = chip->dev;
+ struct device *dev = chip->pdev;
struct i2c_client *client = to_i2c_client(dev);
u32 ordinal;
size_t count = 0;
@@ -530,14 +530,15 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
dev_info(dev, "VID: %04X DID: %02X RID: %02X\n", (u16) vid,
(u8) (vid >> 16), (u8) (vid >> 24));
- chip = tpm_register_hardware(dev, &tpm_i2c);
- if (!chip) {
- dev_err(dev, "%s() error in tpm_register_hardware\n", __func__);
- return -ENODEV;
- }
+ chip = tpmm_chip_alloc(dev, &tpm_i2c);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
chip->vendor.priv = devm_kzalloc(dev, sizeof(struct priv_data),
GFP_KERNEL);
+ if (!chip->vendor.priv)
+ return -ENOMEM;
+
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
@@ -559,7 +560,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
rc = devm_request_irq(dev, chip->vendor.irq,
i2c_nuvoton_int_handler,
IRQF_TRIGGER_LOW,
- chip->vendor.miscdev.name,
+ chip->devname,
chip);
if (rc) {
dev_err(dev, "%s() Unable to request irq: %d for use\n",
@@ -584,7 +585,7 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
TPM_DATA_FIFO_W,
1, (u8 *) (&rc));
if (rc < 0)
- goto out_err;
+ return rc;
/* TPM_STS <- 0x40 (commandReady) */
i2c_nuvoton_ready(chip);
} else {
@@ -594,45 +595,29 @@ static int i2c_nuvoton_probe(struct i2c_client *client,
* only TPM_STS_VALID should be set
*/
if (i2c_nuvoton_read_status(chip) !=
- TPM_STS_VALID) {
- rc = -EIO;
- goto out_err;
- }
+ TPM_STS_VALID)
+ return -EIO;
}
}
}
- if (tpm_get_timeouts(chip)) {
- rc = -ENODEV;
- goto out_err;
- }
-
- if (tpm_do_selftest(chip)) {
- rc = -ENODEV;
- goto out_err;
- }
+ if (tpm_get_timeouts(chip))
+ return -ENODEV;
- return 0;
+ if (tpm_do_selftest(chip))
+ return -ENODEV;
-out_err:
- tpm_dev_vendor_release(chip);
- tpm_remove_hardware(chip->dev);
- return rc;
+ return tpm_chip_register(chip);
}
static int i2c_nuvoton_remove(struct i2c_client *client)
{
struct device *dev = &(client->dev);
struct tpm_chip *chip = dev_get_drvdata(dev);
-
- if (chip)
- tpm_dev_vendor_release(chip);
- tpm_remove_hardware(dev);
- kfree(chip);
+ tpm_chip_unregister(chip);
return 0;
}
-
static const struct i2c_device_id i2c_nuvoton_id[] = {
{I2C_DRIVER_NAME, 0},
{}
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.c b/drivers/char/tpm/tpm_i2c_stm_st33.c
index 4669e3713428..612845b36c29 100644
--- a/drivers/char/tpm/tpm_i2c_stm_st33.c
+++ b/drivers/char/tpm/tpm_i2c_stm_st33.c
@@ -1,6 +1,6 @@
/*
* STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
- * Copyright (C) 2009, 2010 STMicroelectronics
+ * Copyright (C) 2009, 2010, 2014 STMicroelectronics
*
* This 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,11 +12,10 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
*
- * STMicroelectronics version 1.2.0, Copyright (C) 2010
+ * STMicroelectronics version 1.2.1, Copyright (C) 2014
* STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
* This is free software, and you are welcome to redistribute it
* under certain conditions.
@@ -27,7 +26,7 @@
*
* @Synopsis:
* 09/15/2010: First shot driver tpm_tis driver for
- lpc is used as model.
+ * lpc is used as model.
*/
#include <linux/pci.h>
@@ -39,18 +38,38 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/wait.h>
+#include <linux/freezer.h>
#include <linux/string.h>
#include <linux/interrupt.h>
-#include <linux/spinlock.h>
#include <linux/sysfs.h>
#include <linux/gpio.h>
#include <linux/sched.h>
#include <linux/uaccess.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_data/tpm_stm_st33.h>
#include "tpm.h"
-#include "tpm_i2c_stm_st33.h"
+
+#define TPM_ACCESS 0x0
+#define TPM_STS 0x18
+#define TPM_HASH_END 0x20
+#define TPM_DATA_FIFO 0x24
+#define TPM_HASH_DATA 0x24
+#define TPM_HASH_START 0x28
+#define TPM_INTF_CAPABILITY 0x14
+#define TPM_INT_STATUS 0x10
+#define TPM_INT_ENABLE 0x08
+
+#define TPM_DUMMY_BYTE 0xAA
+#define TPM_WRITE_DIRECTION 0x80
+#define TPM_HEADER_SIZE 10
+#define TPM_BUFSIZE 2048
+
+#define LOCALITY0 0
+
enum stm33zp24_access {
TPM_ACCESS_VALID = 0x80,
@@ -82,6 +101,14 @@ enum tis_defaults {
TIS_LONG_TIMEOUT = 2000,
};
+struct tpm_stm_dev {
+ struct i2c_client *client;
+ struct tpm_chip *chip;
+ u8 buf[TPM_BUFSIZE + 1];
+ u32 intrs;
+ int io_lpcpd;
+};
+
/*
* write8_reg
* Send byte to the TIS register according to the ST33ZP24 I2C protocol.
@@ -90,17 +117,12 @@ enum tis_defaults {
* @param: tpm_size, The length of the data
* @return: Returns negative errno, or else the number of bytes written.
*/
-static int write8_reg(struct i2c_client *client, u8 tpm_register,
+static int write8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register,
u8 *tpm_data, u16 tpm_size)
{
- struct st33zp24_platform_data *pin_infos;
-
- pin_infos = client->dev.platform_data;
-
- pin_infos->tpm_i2c_buffer[0][0] = tpm_register;
- memcpy(&pin_infos->tpm_i2c_buffer[0][1], tpm_data, tpm_size);
- return i2c_master_send(client, pin_infos->tpm_i2c_buffer[0],
- tpm_size + 1);
+ tpm_dev->buf[0] = tpm_register;
+ memcpy(tpm_dev->buf + 1, tpm_data, tpm_size);
+ return i2c_master_send(tpm_dev->client, tpm_dev->buf, tpm_size + 1);
} /* write8_reg() */
/*
@@ -111,101 +133,58 @@ static int write8_reg(struct i2c_client *client, u8 tpm_register,
* @param: tpm_size, tpm TPM response size to read.
* @return: number of byte read successfully: should be one if success.
*/
-static int read8_reg(struct i2c_client *client, u8 tpm_register,
+static int read8_reg(struct tpm_stm_dev *tpm_dev, u8 tpm_register,
u8 *tpm_data, int tpm_size)
{
u8 status = 0;
u8 data;
data = TPM_DUMMY_BYTE;
- status = write8_reg(client, tpm_register, &data, 1);
+ status = write8_reg(tpm_dev, tpm_register, &data, 1);
if (status == 2)
- status = i2c_master_recv(client, tpm_data, tpm_size);
+ status = i2c_master_recv(tpm_dev->client, tpm_data, tpm_size);
return status;
} /* read8_reg() */
/*
* I2C_WRITE_DATA
* Send byte to the TIS register according to the ST33ZP24 I2C protocol.
- * @param: client, the chip description
+ * @param: tpm_dev, the chip description
* @param: tpm_register, the tpm tis register where the data should be written
* @param: tpm_data, the tpm_data to write inside the tpm_register
* @param: tpm_size, The length of the data
* @return: number of byte written successfully: should be one if success.
*/
-#define I2C_WRITE_DATA(client, tpm_register, tpm_data, tpm_size) \
- (write8_reg(client, tpm_register | \
+#define I2C_WRITE_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \
+ (write8_reg(tpm_dev, tpm_register | \
TPM_WRITE_DIRECTION, tpm_data, tpm_size))
/*
* I2C_READ_DATA
* Recv byte from the TIS register according to the ST33ZP24 I2C protocol.
- * @param: tpm, the chip description
+ * @param: tpm_dev, the chip description
* @param: tpm_register, the tpm tis register where the data should be read
* @param: tpm_data, the TPM response
* @param: tpm_size, tpm TPM response size to read.
* @return: number of byte read successfully: should be one if success.
*/
-#define I2C_READ_DATA(client, tpm_register, tpm_data, tpm_size) \
- (read8_reg(client, tpm_register, tpm_data, tpm_size))
+#define I2C_READ_DATA(tpm_dev, tpm_register, tpm_data, tpm_size) \
+ (read8_reg(tpm_dev, tpm_register, tpm_data, tpm_size))
/*
* clear_interruption
* clear the TPM interrupt register.
* @param: tpm, the chip description
+ * @return: the TPM_INT_STATUS value
*/
-static void clear_interruption(struct i2c_client *client)
+static u8 clear_interruption(struct tpm_stm_dev *tpm_dev)
{
u8 interrupt;
- I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
- I2C_WRITE_DATA(client, TPM_INT_STATUS, &interrupt, 1);
- I2C_READ_DATA(client, TPM_INT_STATUS, &interrupt, 1);
-} /* clear_interruption() */
-
-/*
- * _wait_for_interrupt_serirq_timeout
- * @param: tpm, the chip description
- * @param: timeout, the timeout of the interrupt
- * @return: the status of the interruption.
- */
-static long _wait_for_interrupt_serirq_timeout(struct tpm_chip *chip,
- unsigned long timeout)
-{
- long status;
- struct i2c_client *client;
- struct st33zp24_platform_data *pin_infos;
-
- client = (struct i2c_client *)TPM_VPRIV(chip);
- pin_infos = client->dev.platform_data;
-
- status = wait_for_completion_interruptible_timeout(
- &pin_infos->irq_detection,
- timeout);
- if (status > 0)
- enable_irq(gpio_to_irq(pin_infos->io_serirq));
- gpio_direction_input(pin_infos->io_serirq);
-
- return status;
-} /* wait_for_interrupt_serirq_timeout() */
-
-static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
- unsigned long timeout)
-{
- int status = 2;
- struct i2c_client *client;
-
- client = (struct i2c_client *)TPM_VPRIV(chip);
- status = _wait_for_interrupt_serirq_timeout(chip, timeout);
- if (!status) {
- status = -EBUSY;
- } else {
- clear_interruption(client);
- if (condition)
- status = 1;
- }
- return status;
-}
+ I2C_READ_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
+ I2C_WRITE_DATA(tpm_dev, TPM_INT_STATUS, &interrupt, 1);
+ return interrupt;
+} /* clear_interruption() */
/*
* tpm_stm_i2c_cancel, cancel is not implemented.
@@ -213,16 +192,14 @@ static int wait_for_serirq_timeout(struct tpm_chip *chip, bool condition,
*/
static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
{
- struct i2c_client *client;
+ struct tpm_stm_dev *tpm_dev;
u8 data;
- client = (struct i2c_client *)TPM_VPRIV(chip);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
data = TPM_STS_COMMAND_READY;
- I2C_WRITE_DATA(client, TPM_STS, &data, 1);
- if (chip->vendor.irq)
- wait_for_serirq_timeout(chip, 1, chip->vendor.timeout_a);
-} /* tpm_stm_i2c_cancel() */
+ I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
+} /* tpm_stm_i2c_cancel() */
/*
* tpm_stm_spi_status return the TPM_STS register
@@ -231,13 +208,14 @@ static void tpm_stm_i2c_cancel(struct tpm_chip *chip)
*/
static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
{
- struct i2c_client *client;
+ struct tpm_stm_dev *tpm_dev;
u8 data;
- client = (struct i2c_client *)TPM_VPRIV(chip);
- I2C_READ_DATA(client, TPM_STS, &data, 1);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
+ I2C_READ_DATA(tpm_dev, TPM_STS, &data, 1);
return data;
-} /* tpm_stm_i2c_status() */
+} /* tpm_stm_i2c_status() */
/*
@@ -247,20 +225,19 @@ static u8 tpm_stm_i2c_status(struct tpm_chip *chip)
*/
static int check_locality(struct tpm_chip *chip)
{
- struct i2c_client *client;
+ struct tpm_stm_dev *tpm_dev;
u8 data;
u8 status;
- client = (struct i2c_client *)TPM_VPRIV(chip);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
- status = I2C_READ_DATA(client, TPM_ACCESS, &data, 1);
+ status = I2C_READ_DATA(tpm_dev, TPM_ACCESS, &data, 1);
if (status && (data &
(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID)) ==
(TPM_ACCESS_ACTIVE_LOCALITY | TPM_ACCESS_VALID))
return chip->vendor.locality;
return -EACCES;
-
} /* check_locality() */
/*
@@ -271,37 +248,31 @@ static int check_locality(struct tpm_chip *chip)
static int request_locality(struct tpm_chip *chip)
{
unsigned long stop;
- long rc;
- struct i2c_client *client;
+ long ret;
+ struct tpm_stm_dev *tpm_dev;
u8 data;
- client = (struct i2c_client *)TPM_VPRIV(chip);
-
if (check_locality(chip) == chip->vendor.locality)
return chip->vendor.locality;
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
data = TPM_ACCESS_REQUEST_USE;
- rc = I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
- if (rc < 0)
+ ret = I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
+ if (ret < 0)
goto end;
- if (chip->vendor.irq) {
- rc = wait_for_serirq_timeout(chip, (check_locality
- (chip) >= 0),
- chip->vendor.timeout_a);
- if (rc > 0)
+ stop = jiffies + chip->vendor.timeout_a;
+
+ /* Request locality is usually effective after the request */
+ do {
+ if (check_locality(chip) >= 0)
return chip->vendor.locality;
- } else {
- stop = jiffies + chip->vendor.timeout_a;
- do {
- if (check_locality(chip) >= 0)
- return chip->vendor.locality;
- msleep(TPM_TIMEOUT);
- } while (time_before(jiffies, stop));
- }
- rc = -EACCES;
+ msleep(TPM_TIMEOUT);
+ } while (time_before(jiffies, stop));
+ ret = -EACCES;
end:
- return rc;
+ return ret;
} /* request_locality() */
/*
@@ -310,13 +281,13 @@ end:
*/
static void release_locality(struct tpm_chip *chip)
{
- struct i2c_client *client;
+ struct tpm_stm_dev *tpm_dev;
u8 data;
- client = (struct i2c_client *)TPM_VPRIV(chip);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
data = TPM_ACCESS_ACTIVE_LOCALITY;
- I2C_WRITE_DATA(client, TPM_ACCESS, &data, 1);
+ I2C_WRITE_DATA(tpm_dev, TPM_ACCESS, &data, 1);
}
/*
@@ -329,19 +300,20 @@ static int get_burstcount(struct tpm_chip *chip)
unsigned long stop;
int burstcnt, status;
u8 tpm_reg, temp;
+ struct tpm_stm_dev *tpm_dev;
- struct i2c_client *client = (struct i2c_client *)TPM_VPRIV(chip);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
stop = jiffies + chip->vendor.timeout_d;
do {
tpm_reg = TPM_STS + 1;
- status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+ status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1);
if (status < 0)
goto end;
tpm_reg = tpm_reg + 1;
burstcnt = temp;
- status = I2C_READ_DATA(client, tpm_reg, &temp, 1);
+ status = I2C_READ_DATA(tpm_dev, tpm_reg, &temp, 1);
if (status < 0)
goto end;
@@ -355,36 +327,107 @@ end:
return -EBUSY;
} /* get_burstcount() */
+static bool wait_for_tpm_stat_cond(struct tpm_chip *chip, u8 mask,
+ bool check_cancel, bool *canceled)
+{
+ u8 status = chip->ops->status(chip);
+
+ *canceled = false;
+ if ((status & mask) == mask)
+ return true;
+ if (check_cancel && chip->ops->req_canceled(chip, status)) {
+ *canceled = true;
+ return true;
+ }
+ return false;
+}
+
+/*
+ * interrupt_to_status
+ * @param: irq_mask, the irq mask value to wait
+ * @return: the corresponding tpm_sts value
+ */
+static u8 interrupt_to_status(u8 irq_mask)
+{
+ u8 status = 0;
+
+ if ((irq_mask & TPM_INTF_STS_VALID_INT) == TPM_INTF_STS_VALID_INT)
+ status |= TPM_STS_VALID;
+ if ((irq_mask & TPM_INTF_DATA_AVAIL_INT) == TPM_INTF_DATA_AVAIL_INT)
+ status |= TPM_STS_DATA_AVAIL;
+ if ((irq_mask & TPM_INTF_CMD_READY_INT) == TPM_INTF_CMD_READY_INT)
+ status |= TPM_STS_COMMAND_READY;
+
+ return status;
+} /* status_to_interrupt() */
+
/*
* wait_for_stat wait for a TPM_STS value
* @param: chip, the tpm chip description
* @param: mask, the value mask to wait
* @param: timeout, the timeout
* @param: queue, the wait queue.
+ * @param: check_cancel, does the command can be cancelled ?
* @return: the tpm status, 0 if success, -ETIME if timeout is reached.
*/
static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
- wait_queue_head_t *queue)
+ wait_queue_head_t *queue, bool check_cancel)
{
unsigned long stop;
- long rc;
- u8 status;
+ int ret;
+ bool canceled = false;
+ bool condition;
+ u32 cur_intrs;
+ u8 interrupt, status;
+ struct tpm_stm_dev *tpm_dev;
- if (chip->vendor.irq) {
- rc = wait_for_serirq_timeout(chip, ((tpm_stm_i2c_status
- (chip) & mask) ==
- mask), timeout);
- if (rc > 0)
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+
+ /* check current status */
+ status = tpm_stm_i2c_status(chip);
+ if ((status & mask) == mask)
+ return 0;
+
+ stop = jiffies + timeout;
+
+ if (chip->vendor.irq) {
+ cur_intrs = tpm_dev->intrs;
+ interrupt = clear_interruption(tpm_dev);
+ enable_irq(chip->vendor.irq);
+
+again:
+ timeout = stop - jiffies;
+ if ((long) timeout <= 0)
+ return -1;
+
+ ret = wait_event_interruptible_timeout(*queue,
+ cur_intrs != tpm_dev->intrs, timeout);
+
+ interrupt |= clear_interruption(tpm_dev);
+ status = interrupt_to_status(interrupt);
+ condition = wait_for_tpm_stat_cond(chip, mask,
+ check_cancel, &canceled);
+
+ if (ret >= 0 && condition) {
+ if (canceled)
+ return -ECANCELED;
return 0;
+ }
+ if (ret == -ERESTARTSYS && freezing(current)) {
+ clear_thread_flag(TIF_SIGPENDING);
+ goto again;
+ }
+ disable_irq_nosync(chip->vendor.irq);
+
} else {
- stop = jiffies + timeout;
do {
msleep(TPM_TIMEOUT);
- status = tpm_stm_i2c_status(chip);
+ status = chip->ops->status(chip);
if ((status & mask) == mask)
return 0;
} while (time_before(jiffies, stop));
}
+
return -ETIME;
} /* wait_for_stat() */
@@ -397,22 +440,24 @@ static int wait_for_stat(struct tpm_chip *chip, u8 mask, unsigned long timeout,
*/
static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
{
- int size = 0, burstcnt, len;
- struct i2c_client *client;
+ int size = 0, burstcnt, len, ret;
+ struct tpm_stm_dev *tpm_dev;
- client = (struct i2c_client *)TPM_VPRIV(chip);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
while (size < count &&
wait_for_stat(chip,
TPM_STS_DATA_AVAIL | TPM_STS_VALID,
chip->vendor.timeout_c,
- &chip->vendor.read_queue)
- == 0) {
+ &chip->vendor.read_queue, true) == 0) {
burstcnt = get_burstcount(chip);
if (burstcnt < 0)
return burstcnt;
len = min_t(int, burstcnt, count - size);
- I2C_READ_DATA(client, TPM_DATA_FIFO, buf + size, len);
+ ret = I2C_READ_DATA(tpm_dev, TPM_DATA_FIFO, buf + size, len);
+ if (ret < 0)
+ return ret;
+
size += len;
}
return size;
@@ -427,15 +472,14 @@ static int recv_data(struct tpm_chip *chip, u8 *buf, size_t count)
static irqreturn_t tpm_ioserirq_handler(int irq, void *dev_id)
{
struct tpm_chip *chip = dev_id;
- struct i2c_client *client;
- struct st33zp24_platform_data *pin_infos;
+ struct tpm_stm_dev *tpm_dev;
- disable_irq_nosync(irq);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
- client = (struct i2c_client *)TPM_VPRIV(chip);
- pin_infos = client->dev.platform_data;
+ tpm_dev->intrs++;
+ wake_up_interruptible(&chip->vendor.read_queue);
+ disable_irq_nosync(chip->vendor.irq);
- complete(&pin_infos->irq_detection);
return IRQ_HANDLED;
} /* tpm_ioserirq_handler() */
@@ -457,13 +501,15 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
int ret;
u8 data;
struct i2c_client *client;
+ struct tpm_stm_dev *tpm_dev;
- if (chip == NULL)
+ if (!chip)
return -EBUSY;
if (len < TPM_HEADER_SIZE)
return -EBUSY;
- client = (struct i2c_client *)TPM_VPRIV(chip);
+ tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+ client = tpm_dev->client;
client->flags = 0;
@@ -476,7 +522,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
tpm_stm_i2c_cancel(chip);
if (wait_for_stat
(chip, TPM_STS_COMMAND_READY, chip->vendor.timeout_b,
- &chip->vendor.int_queue) < 0) {
+ &chip->vendor.read_queue, false) < 0) {
ret = -ETIME;
goto out_err;
}
@@ -487,7 +533,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
if (burstcnt < 0)
return burstcnt;
size = min_t(int, len - i - 1, burstcnt);
- ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf, size);
+ ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + i, size);
if (ret < 0)
goto out_err;
@@ -500,7 +546,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
goto out_err;
}
- ret = I2C_WRITE_DATA(client, TPM_DATA_FIFO, buf + len - 1, 1);
+ ret = I2C_WRITE_DATA(tpm_dev, TPM_DATA_FIFO, buf + len - 1, 1);
if (ret < 0)
goto out_err;
@@ -511,7 +557,7 @@ static int tpm_stm_i2c_send(struct tpm_chip *chip, unsigned char *buf,
}
data = TPM_STS_GO;
- I2C_WRITE_DATA(client, TPM_STS, &data, 1);
+ I2C_WRITE_DATA(tpm_dev, TPM_STS, &data, 1);
return len;
out_err:
@@ -526,7 +572,7 @@ out_err:
* @param: buf, the buffer to store datas.
* @param: count, the number of bytes to send.
* @return: In case of success the number of bytes received.
- * In other case, a < 0 value describing the issue.
+ * In other case, a < 0 value describing the issue.
*/
static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
size_t count)
@@ -534,7 +580,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
int size = 0;
int expected;
- if (chip == NULL)
+ if (!chip)
return -EBUSY;
if (count < TPM_HEADER_SIZE) {
@@ -544,7 +590,7 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
size = recv_data(chip, buf, TPM_HEADER_SIZE);
if (size < TPM_HEADER_SIZE) {
- dev_err(chip->dev, "Unable to read header\n");
+ dev_err(chip->pdev, "Unable to read header\n");
goto out;
}
@@ -555,9 +601,9 @@ static int tpm_stm_i2c_recv(struct tpm_chip *chip, unsigned char *buf,
}
size += recv_data(chip, &buf[TPM_HEADER_SIZE],
- expected - TPM_HEADER_SIZE);
+ expected - TPM_HEADER_SIZE);
if (size < expected) {
- dev_err(chip->dev, "Unable to read remainder of result\n");
+ dev_err(chip->pdev, "Unable to read remainder of result\n");
size = -ETIME;
goto out;
}
@@ -568,7 +614,7 @@ out:
return size;
}
-static bool tpm_st33_i2c_req_canceled(struct tpm_chip *chip, u8 status)
+static bool tpm_stm_i2c_req_canceled(struct tpm_chip *chip, u8 status)
{
return (status == TPM_STS_COMMAND_READY);
}
@@ -580,75 +626,134 @@ static const struct tpm_class_ops st_i2c_tpm = {
.status = tpm_stm_i2c_status,
.req_complete_mask = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
.req_complete_val = TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- .req_canceled = tpm_st33_i2c_req_canceled,
+ .req_canceled = tpm_stm_i2c_req_canceled,
};
-static int interrupts;
-module_param(interrupts, int, 0444);
-MODULE_PARM_DESC(interrupts, "Enable interrupts");
+#ifdef CONFIG_OF
+static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip)
+{
+ struct device_node *pp;
+ struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+ struct i2c_client *client = tpm_dev->client;
+ int gpio;
+ int ret;
+
+ pp = client->dev.of_node;
+ if (!pp) {
+ dev_err(chip->pdev, "No platform data\n");
+ return -ENODEV;
+ }
+
+ /* Get GPIO from device tree */
+ gpio = of_get_named_gpio(pp, "lpcpd-gpios", 0);
+ if (gpio < 0) {
+ dev_err(chip->pdev, "Failed to retrieve lpcpd-gpios from dts.\n");
+ tpm_dev->io_lpcpd = -1;
+ /*
+ * lpcpd pin is not specified. This is not an issue as
+ * power management can be also managed by TPM specific
+ * commands. So leave with a success status code.
+ */
+ return 0;
+ }
+ /* GPIO request and configuration */
+ ret = devm_gpio_request_one(&client->dev, gpio,
+ GPIOF_OUT_INIT_HIGH, "TPM IO LPCPD");
+ if (ret) {
+ dev_err(chip->pdev, "Failed to request lpcpd pin\n");
+ return -ENODEV;
+ }
+ tpm_dev->io_lpcpd = gpio;
+
+ return 0;
+}
+#else
+static int tpm_stm_i2c_of_request_resources(struct tpm_chip *chip)
+{
+ return -ENODEV;
+}
+#endif
-static int power_mgt = 1;
-module_param(power_mgt, int, 0444);
-MODULE_PARM_DESC(power_mgt, "Power Management");
+static int tpm_stm_i2c_request_resources(struct i2c_client *client,
+ struct tpm_chip *chip)
+{
+ struct st33zp24_platform_data *pdata;
+ struct tpm_stm_dev *tpm_dev = (struct tpm_stm_dev *)TPM_VPRIV(chip);
+ int ret;
+
+ pdata = client->dev.platform_data;
+ if (!pdata) {
+ dev_err(chip->pdev, "No platform data\n");
+ return -ENODEV;
+ }
+
+ /* store for late use */
+ tpm_dev->io_lpcpd = pdata->io_lpcpd;
+
+ if (gpio_is_valid(pdata->io_lpcpd)) {
+ ret = devm_gpio_request_one(&client->dev,
+ pdata->io_lpcpd, GPIOF_OUT_INIT_HIGH,
+ "TPM IO_LPCPD");
+ if (ret) {
+ dev_err(chip->pdev, "%s : reset gpio_request failed\n",
+ __FILE__);
+ return ret;
+ }
+ }
+
+ return 0;
+}
/*
- * tpm_st33_i2c_probe initialize the TPM device
+ * tpm_stm_i2c_probe initialize the TPM device
* @param: client, the i2c_client drescription (TPM I2C description).
* @param: id, the i2c_device_id struct.
* @return: 0 in case of success.
* -1 in other case.
*/
static int
-tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
+tpm_stm_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
- int err;
- u8 intmask;
+ int ret;
+ u8 intmask = 0;
struct tpm_chip *chip;
struct st33zp24_platform_data *platform_data;
+ struct tpm_stm_dev *tpm_dev;
- if (client == NULL) {
+ if (!client) {
pr_info("%s: i2c client is NULL. Device not accessible.\n",
__func__);
- err = -ENODEV;
- goto end;
+ return -ENODEV;
}
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
dev_info(&client->dev, "client not i2c capable\n");
- err = -ENODEV;
- goto end;
+ return -ENODEV;
}
- chip = tpm_register_hardware(&client->dev, &st_i2c_tpm);
- if (!chip) {
- dev_info(&client->dev, "fail chip\n");
- err = -ENODEV;
- goto end;
- }
+ tpm_dev = devm_kzalloc(&client->dev, sizeof(struct tpm_stm_dev),
+ GFP_KERNEL);
+ if (!tpm_dev)
+ return -ENOMEM;
- platform_data = client->dev.platform_data;
+ chip = tpmm_chip_alloc(&client->dev, &st_i2c_tpm);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
- if (!platform_data) {
- dev_info(&client->dev, "chip not available\n");
- err = -ENODEV;
- goto _tpm_clean_answer;
- }
+ TPM_VPRIV(chip) = tpm_dev;
+ tpm_dev->client = client;
- platform_data->tpm_i2c_buffer[0] =
- kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
- if (platform_data->tpm_i2c_buffer[0] == NULL) {
- err = -ENOMEM;
- goto _tpm_clean_answer;
- }
- platform_data->tpm_i2c_buffer[1] =
- kmalloc(TPM_BUFSIZE * sizeof(u8), GFP_KERNEL);
- if (platform_data->tpm_i2c_buffer[1] == NULL) {
- err = -ENOMEM;
- goto _tpm_clean_response1;
+ platform_data = client->dev.platform_data;
+ if (!platform_data && client->dev.of_node) {
+ ret = tpm_stm_i2c_of_request_resources(chip);
+ if (ret)
+ goto _tpm_clean_answer;
+ } else if (platform_data) {
+ ret = tpm_stm_i2c_request_resources(client, chip);
+ if (ret)
+ goto _tpm_clean_answer;
}
- TPM_VPRIV(chip) = client;
-
chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
@@ -656,59 +761,44 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
chip->vendor.locality = LOCALITY0;
- if (power_mgt) {
- err = gpio_request(platform_data->io_lpcpd, "TPM IO_LPCPD");
- if (err)
- goto _gpio_init1;
- gpio_set_value(platform_data->io_lpcpd, 1);
- }
+ if (client->irq) {
+ /* INTERRUPT Setup */
+ init_waitqueue_head(&chip->vendor.read_queue);
+ tpm_dev->intrs = 0;
- if (interrupts) {
- init_completion(&platform_data->irq_detection);
if (request_locality(chip) != LOCALITY0) {
- err = -ENODEV;
- goto _tpm_clean_response2;
+ ret = -ENODEV;
+ goto _tpm_clean_answer;
}
- err = gpio_request(platform_data->io_serirq, "TPM IO_SERIRQ");
- if (err)
- goto _gpio_init2;
- clear_interruption(client);
- err = request_irq(gpio_to_irq(platform_data->io_serirq),
- &tpm_ioserirq_handler,
+ clear_interruption(tpm_dev);
+ ret = devm_request_irq(&client->dev, client->irq,
+ tpm_ioserirq_handler,
IRQF_TRIGGER_HIGH,
"TPM SERIRQ management", chip);
- if (err < 0) {
- dev_err(chip->dev , "TPM SERIRQ signals %d not available\n",
- gpio_to_irq(platform_data->io_serirq));
- goto _irq_set;
+ if (ret < 0) {
+ dev_err(chip->pdev, "TPM SERIRQ signals %d not available\n",
+ client->irq);
+ goto _tpm_clean_answer;
}
- err = I2C_READ_DATA(client, TPM_INT_ENABLE, &intmask, 1);
- if (err < 0)
- goto _irq_set;
-
intmask |= TPM_INTF_CMD_READY_INT
- | TPM_INTF_FIFO_AVALAIBLE_INT
- | TPM_INTF_WAKE_UP_READY_INT
- | TPM_INTF_LOCALITY_CHANGE_INT
| TPM_INTF_STS_VALID_INT
| TPM_INTF_DATA_AVAIL_INT;
- err = I2C_WRITE_DATA(client, TPM_INT_ENABLE, &intmask, 1);
- if (err < 0)
- goto _irq_set;
+ ret = I2C_WRITE_DATA(tpm_dev, TPM_INT_ENABLE, &intmask, 1);
+ if (ret < 0)
+ goto _tpm_clean_answer;
intmask = TPM_GLOBAL_INT_ENABLE;
- err = I2C_WRITE_DATA(client, (TPM_INT_ENABLE + 3), &intmask, 1);
- if (err < 0)
- goto _irq_set;
+ ret = I2C_WRITE_DATA(tpm_dev, (TPM_INT_ENABLE + 3),
+ &intmask, 1);
+ if (ret < 0)
+ goto _tpm_clean_answer;
- err = I2C_READ_DATA(client, TPM_INT_STATUS, &intmask, 1);
- if (err < 0)
- goto _irq_set;
+ chip->vendor.irq = client->irq;
- chip->vendor.irq = interrupts;
+ disable_irq_nosync(chip->vendor.irq);
tpm_gen_interrupt(chip);
}
@@ -716,130 +806,106 @@ tpm_st33_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id)
tpm_get_timeouts(chip);
tpm_do_selftest(chip);
- dev_info(chip->dev, "TPM I2C Initialized\n");
- return 0;
-_irq_set:
- free_irq(gpio_to_irq(platform_data->io_serirq), (void *)chip);
-_gpio_init2:
- if (interrupts)
- gpio_free(platform_data->io_serirq);
-_gpio_init1:
- if (power_mgt)
- gpio_free(platform_data->io_lpcpd);
-_tpm_clean_response2:
- kzfree(platform_data->tpm_i2c_buffer[1]);
- platform_data->tpm_i2c_buffer[1] = NULL;
-_tpm_clean_response1:
- kzfree(platform_data->tpm_i2c_buffer[0]);
- platform_data->tpm_i2c_buffer[0] = NULL;
+ return tpm_chip_register(chip);
_tpm_clean_answer:
- tpm_remove_hardware(chip->dev);
-end:
- pr_info("TPM I2C initialisation fail\n");
- return err;
+ dev_info(chip->pdev, "TPM I2C initialisation fail\n");
+ return ret;
}
/*
- * tpm_st33_i2c_remove remove the TPM device
- * @param: client, the i2c_client drescription (TPM I2C description).
- clear_bit(0, &chip->is_open);
+ * tpm_stm_i2c_remove remove the TPM device
+ * @param: client, the i2c_client description (TPM I2C description).
* @return: 0 in case of success.
*/
-static int tpm_st33_i2c_remove(struct i2c_client *client)
+static int tpm_stm_i2c_remove(struct i2c_client *client)
{
- struct tpm_chip *chip = (struct tpm_chip *)i2c_get_clientdata(client);
- struct st33zp24_platform_data *pin_infos =
- ((struct i2c_client *)TPM_VPRIV(chip))->dev.platform_data;
-
- if (pin_infos != NULL) {
- free_irq(pin_infos->io_serirq, chip);
-
- gpio_free(pin_infos->io_serirq);
- gpio_free(pin_infos->io_lpcpd);
-
- tpm_remove_hardware(chip->dev);
+ struct tpm_chip *chip =
+ (struct tpm_chip *) i2c_get_clientdata(client);
- if (pin_infos->tpm_i2c_buffer[1] != NULL) {
- kzfree(pin_infos->tpm_i2c_buffer[1]);
- pin_infos->tpm_i2c_buffer[1] = NULL;
- }
- if (pin_infos->tpm_i2c_buffer[0] != NULL) {
- kzfree(pin_infos->tpm_i2c_buffer[0]);
- pin_infos->tpm_i2c_buffer[0] = NULL;
- }
- }
+ if (chip)
+ tpm_chip_unregister(chip);
return 0;
}
#ifdef CONFIG_PM_SLEEP
/*
- * tpm_st33_i2c_pm_suspend suspend the TPM device
+ * tpm_stm_i2c_pm_suspend suspend the TPM device
* @param: client, the i2c_client drescription (TPM I2C description).
* @param: mesg, the power management message.
* @return: 0 in case of success.
*/
-static int tpm_st33_i2c_pm_suspend(struct device *dev)
+static int tpm_stm_i2c_pm_suspend(struct device *dev)
{
struct st33zp24_platform_data *pin_infos = dev->platform_data;
int ret = 0;
- if (power_mgt) {
+ if (gpio_is_valid(pin_infos->io_lpcpd))
gpio_set_value(pin_infos->io_lpcpd, 0);
- } else {
+ else
ret = tpm_pm_suspend(dev);
- }
+
return ret;
-} /* tpm_st33_i2c_suspend() */
+} /* tpm_stm_i2c_suspend() */
/*
- * tpm_st33_i2c_pm_resume resume the TPM device
+ * tpm_stm_i2c_pm_resume resume the TPM device
* @param: client, the i2c_client drescription (TPM I2C description).
* @return: 0 in case of success.
*/
-static int tpm_st33_i2c_pm_resume(struct device *dev)
+static int tpm_stm_i2c_pm_resume(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
struct st33zp24_platform_data *pin_infos = dev->platform_data;
int ret = 0;
- if (power_mgt) {
+ if (gpio_is_valid(pin_infos->io_lpcpd)) {
gpio_set_value(pin_infos->io_lpcpd, 1);
- ret = wait_for_serirq_timeout(chip,
- (chip->ops->status(chip) &
- TPM_STS_VALID) == TPM_STS_VALID,
- chip->vendor.timeout_b);
+ ret = wait_for_stat(chip,
+ TPM_STS_VALID, chip->vendor.timeout_b,
+ &chip->vendor.read_queue, false);
} else {
ret = tpm_pm_resume(dev);
if (!ret)
tpm_do_selftest(chip);
}
return ret;
-} /* tpm_st33_i2c_pm_resume() */
+} /* tpm_stm_i2c_pm_resume() */
#endif
-static const struct i2c_device_id tpm_st33_i2c_id[] = {
+static const struct i2c_device_id tpm_stm_i2c_id[] = {
{TPM_ST33_I2C, 0},
{}
};
-MODULE_DEVICE_TABLE(i2c, tpm_st33_i2c_id);
-static SIMPLE_DEV_PM_OPS(tpm_st33_i2c_ops, tpm_st33_i2c_pm_suspend,
- tpm_st33_i2c_pm_resume);
-static struct i2c_driver tpm_st33_i2c_driver = {
+MODULE_DEVICE_TABLE(i2c, tpm_stm_i2c_id);
+
+#ifdef CONFIG_OF
+static const struct of_device_id of_st33zp24_i2c_match[] = {
+ { .compatible = "st,st33zp24-i2c", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, of_st33zp24_i2c_match);
+#endif
+
+static SIMPLE_DEV_PM_OPS(tpm_stm_i2c_ops, tpm_stm_i2c_pm_suspend,
+ tpm_stm_i2c_pm_resume);
+
+static struct i2c_driver tpm_stm_i2c_driver = {
.driver = {
- .owner = THIS_MODULE,
- .name = TPM_ST33_I2C,
- .pm = &tpm_st33_i2c_ops,
- },
- .probe = tpm_st33_i2c_probe,
- .remove = tpm_st33_i2c_remove,
- .id_table = tpm_st33_i2c_id
+ .owner = THIS_MODULE,
+ .name = TPM_ST33_I2C,
+ .pm = &tpm_stm_i2c_ops,
+ .of_match_table = of_match_ptr(of_st33zp24_i2c_match),
+ },
+ .probe = tpm_stm_i2c_probe,
+ .remove = tpm_stm_i2c_remove,
+ .id_table = tpm_stm_i2c_id
};
-module_i2c_driver(tpm_st33_i2c_driver);
+module_i2c_driver(tpm_stm_i2c_driver);
MODULE_AUTHOR("Christophe Ricard (tpmsupport@st.com)");
MODULE_DESCRIPTION("STM TPM I2C ST33 Driver");
-MODULE_VERSION("1.2.0");
+MODULE_VERSION("1.2.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/char/tpm/tpm_i2c_stm_st33.h b/drivers/char/tpm/tpm_i2c_stm_st33.h
deleted file mode 100644
index 439a43249aa6..000000000000
--- a/drivers/char/tpm/tpm_i2c_stm_st33.h
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * STMicroelectronics TPM I2C Linux driver for TPM ST33ZP24
- * Copyright (C) 2009, 2010 STMicroelectronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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.
- *
- * STMicroelectronics version 1.2.0, Copyright (C) 2010
- * STMicroelectronics comes with ABSOLUTELY NO WARRANTY.
- * This is free software, and you are welcome to redistribute it
- * under certain conditions.
- *
- * @Author: Christophe RICARD tpmsupport@st.com
- *
- * @File: stm_st33_tpm_i2c.h
- *
- * @Date: 09/15/2010
- */
-#ifndef __STM_ST33_TPM_I2C_MAIN_H__
-#define __STM_ST33_TPM_I2C_MAIN_H__
-
-#define TPM_ACCESS (0x0)
-#define TPM_STS (0x18)
-#define TPM_HASH_END (0x20)
-#define TPM_DATA_FIFO (0x24)
-#define TPM_HASH_DATA (0x24)
-#define TPM_HASH_START (0x28)
-#define TPM_INTF_CAPABILITY (0x14)
-#define TPM_INT_STATUS (0x10)
-#define TPM_INT_ENABLE (0x08)
-
-#define TPM_DUMMY_BYTE 0xAA
-#define TPM_WRITE_DIRECTION 0x80
-#define TPM_HEADER_SIZE 10
-#define TPM_BUFSIZE 2048
-
-#define LOCALITY0 0
-
-#define TPM_ST33_I2C "st33zp24_i2c"
-
-struct st33zp24_platform_data {
- int io_serirq;
- int io_lpcpd;
- struct i2c_client *client;
- u8 *tpm_i2c_buffer[2]; /* 0 Request 1 Response */
- struct completion irq_detection;
- struct mutex lock;
-};
-
-#endif /* __STM_ST33_TPM_I2C_MAIN_H__ */
diff --git a/drivers/char/tpm/tpm_ibmvtpm.c b/drivers/char/tpm/tpm_ibmvtpm.c
index af74c57e5090..b1e53e3aece5 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.c
+++ b/drivers/char/tpm/tpm_ibmvtpm.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2012 IBM Corporation
*
- * Author: Ashley Lai <adlai@us.ibm.com>
+ * Author: Ashley Lai <ashleydlai@gmail.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
@@ -148,7 +148,8 @@ static int tpm_ibmvtpm_send(struct tpm_chip *chip, u8 *buf, size_t count)
crq.len = (u16)count;
crq.data = ibmvtpm->rtce_dma_handle;
- rc = ibmvtpm_send_crq(ibmvtpm->vdev, word[0], word[1]);
+ rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(word[0]),
+ cpu_to_be64(word[1]));
if (rc != H_SUCCESS) {
dev_err(ibmvtpm->dev, "tpm_ibmvtpm_send failed rc=%d\n", rc);
rc = 0;
@@ -186,7 +187,8 @@ static int ibmvtpm_crq_get_rtce_size(struct ibmvtpm_dev *ibmvtpm)
crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_GET_RTCE_BUFFER_SIZE;
- rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+ rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
+ cpu_to_be64(buf[1]));
if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev,
"ibmvtpm_crq_get_rtce_size failed rc=%d\n", rc);
@@ -212,7 +214,8 @@ static int ibmvtpm_crq_get_version(struct ibmvtpm_dev *ibmvtpm)
crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_GET_VERSION;
- rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+ rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
+ cpu_to_be64(buf[1]));
if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev,
"ibmvtpm_crq_get_version failed rc=%d\n", rc);
@@ -270,8 +273,11 @@ static int ibmvtpm_crq_send_init(struct ibmvtpm_dev *ibmvtpm)
static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
{
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+ struct tpm_chip *chip = dev_get_drvdata(ibmvtpm->dev);
int rc = 0;
+ tpm_chip_unregister(chip);
+
free_irq(vdev->irq, ibmvtpm);
do {
@@ -290,8 +296,6 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
kfree(ibmvtpm->rtce_buf);
}
- tpm_remove_hardware(ibmvtpm->dev);
-
kfree(ibmvtpm);
return 0;
@@ -307,6 +311,14 @@ static int tpm_ibmvtpm_remove(struct vio_dev *vdev)
static unsigned long tpm_ibmvtpm_get_desired_dma(struct vio_dev *vdev)
{
struct ibmvtpm_dev *ibmvtpm = ibmvtpm_get_data(&vdev->dev);
+
+ /* ibmvtpm initializes at probe time, so the data we are
+ * asking for may not be set yet. Estimate that 4K required
+ * for TCE-mapped buffer in addition to CRQ.
+ */
+ if (!ibmvtpm)
+ return CRQ_RES_BUF_SIZE + PAGE_SIZE;
+
return CRQ_RES_BUF_SIZE + ibmvtpm->rtce_size;
}
@@ -327,7 +339,8 @@ static int tpm_ibmvtpm_suspend(struct device *dev)
crq.valid = (u8)IBMVTPM_VALID_CMD;
crq.msg = (u8)VTPM_PREPARE_TO_SUSPEND;
- rc = ibmvtpm_send_crq(ibmvtpm->vdev, buf[0], buf[1]);
+ rc = ibmvtpm_send_crq(ibmvtpm->vdev, cpu_to_be64(buf[0]),
+ cpu_to_be64(buf[1]));
if (rc != H_SUCCESS)
dev_err(ibmvtpm->dev,
"tpm_ibmvtpm_suspend failed rc=%d\n", rc);
@@ -472,11 +485,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
case IBMVTPM_VALID_CMD:
switch (crq->msg) {
case VTPM_GET_RTCE_BUFFER_SIZE_RES:
- if (crq->len <= 0) {
+ if (be16_to_cpu(crq->len) <= 0) {
dev_err(ibmvtpm->dev, "Invalid rtce size\n");
return;
}
- ibmvtpm->rtce_size = crq->len;
+ ibmvtpm->rtce_size = be16_to_cpu(crq->len);
ibmvtpm->rtce_buf = kmalloc(ibmvtpm->rtce_size,
GFP_KERNEL);
if (!ibmvtpm->rtce_buf) {
@@ -497,11 +510,11 @@ static void ibmvtpm_crq_process(struct ibmvtpm_crq *crq,
return;
case VTPM_GET_VERSION_RES:
- ibmvtpm->vtpm_version = crq->data;
+ ibmvtpm->vtpm_version = be32_to_cpu(crq->data);
return;
case VTPM_TPM_COMMAND_RES:
/* len of the data in rtce buffer */
- ibmvtpm->res_len = crq->len;
+ ibmvtpm->res_len = be16_to_cpu(crq->len);
wake_up_interruptible(&ibmvtpm->wq);
return;
default:
@@ -555,11 +568,9 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
struct tpm_chip *chip;
int rc = -ENOMEM, rc1;
- chip = tpm_register_hardware(dev, &tpm_ibmvtpm);
- if (!chip) {
- dev_err(dev, "tpm_register_hardware failed\n");
- return -ENODEV;
- }
+ chip = tpmm_chip_alloc(dev, &tpm_ibmvtpm);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
ibmvtpm = kzalloc(sizeof(struct ibmvtpm_dev), GFP_KERNEL);
if (!ibmvtpm) {
@@ -629,7 +640,7 @@ static int tpm_ibmvtpm_probe(struct vio_dev *vio_dev,
if (rc)
goto init_irq_cleanup;
- return rc;
+ return tpm_chip_register(chip);
init_irq_cleanup:
do {
rc1 = plpar_hcall_norets(H_FREE_CRQ, vio_dev->unit_address);
@@ -644,8 +655,6 @@ cleanup:
kfree(ibmvtpm);
}
- tpm_remove_hardware(dev);
-
return rc;
}
diff --git a/drivers/char/tpm/tpm_ibmvtpm.h b/drivers/char/tpm/tpm_ibmvtpm.h
index bd82a791f995..f595f14426bf 100644
--- a/drivers/char/tpm/tpm_ibmvtpm.h
+++ b/drivers/char/tpm/tpm_ibmvtpm.h
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2012 IBM Corporation
*
- * Author: Ashley Lai <adlai@us.ibm.com>
+ * Author: Ashley Lai <ashleydlai@gmail.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
diff --git a/drivers/char/tpm/tpm_infineon.c b/drivers/char/tpm/tpm_infineon.c
index dc0a2554034e..6d492132ad2b 100644
--- a/drivers/char/tpm/tpm_infineon.c
+++ b/drivers/char/tpm/tpm_infineon.c
@@ -195,9 +195,9 @@ static int wait(struct tpm_chip *chip, int wait_for_bit)
}
if (i == TPM_MAX_TRIES) { /* timeout occurs */
if (wait_for_bit == STAT_XFE)
- dev_err(chip->dev, "Timeout in wait(STAT_XFE)\n");
+ dev_err(chip->pdev, "Timeout in wait(STAT_XFE)\n");
if (wait_for_bit == STAT_RDA)
- dev_err(chip->dev, "Timeout in wait(STAT_RDA)\n");
+ dev_err(chip->pdev, "Timeout in wait(STAT_RDA)\n");
return -EIO;
}
return 0;
@@ -220,7 +220,7 @@ static void wait_and_send(struct tpm_chip *chip, u8 sendbyte)
static void tpm_wtx(struct tpm_chip *chip)
{
number_of_wtx++;
- dev_info(chip->dev, "Granting WTX (%02d / %02d)\n",
+ dev_info(chip->pdev, "Granting WTX (%02d / %02d)\n",
number_of_wtx, TPM_MAX_WTX_PACKAGES);
wait_and_send(chip, TPM_VL_VER);
wait_and_send(chip, TPM_CTRL_WTX);
@@ -231,7 +231,7 @@ static void tpm_wtx(struct tpm_chip *chip)
static void tpm_wtx_abort(struct tpm_chip *chip)
{
- dev_info(chip->dev, "Aborting WTX\n");
+ dev_info(chip->pdev, "Aborting WTX\n");
wait_and_send(chip, TPM_VL_VER);
wait_and_send(chip, TPM_CTRL_WTX_ABORT);
wait_and_send(chip, 0x00);
@@ -257,7 +257,7 @@ recv_begin:
}
if (buf[0] != TPM_VL_VER) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"Wrong transport protocol implementation!\n");
return -EIO;
}
@@ -272,7 +272,7 @@ recv_begin:
}
if ((size == 0x6D00) && (buf[1] == 0x80)) {
- dev_err(chip->dev, "Error handling on vendor layer!\n");
+ dev_err(chip->pdev, "Error handling on vendor layer!\n");
return -EIO;
}
@@ -284,7 +284,7 @@ recv_begin:
}
if (buf[1] == TPM_CTRL_WTX) {
- dev_info(chip->dev, "WTX-package received\n");
+ dev_info(chip->pdev, "WTX-package received\n");
if (number_of_wtx < TPM_MAX_WTX_PACKAGES) {
tpm_wtx(chip);
goto recv_begin;
@@ -295,14 +295,14 @@ recv_begin:
}
if (buf[1] == TPM_CTRL_WTX_ABORT_ACK) {
- dev_info(chip->dev, "WTX-abort acknowledged\n");
+ dev_info(chip->pdev, "WTX-abort acknowledged\n");
return size;
}
if (buf[1] == TPM_CTRL_ERROR) {
- dev_err(chip->dev, "ERROR-package received:\n");
+ dev_err(chip->pdev, "ERROR-package received:\n");
if (buf[4] == TPM_INF_NAK)
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"-> Negative acknowledgement"
" - retransmit command!\n");
return -EIO;
@@ -321,7 +321,7 @@ static int tpm_inf_send(struct tpm_chip *chip, u8 * buf, size_t count)
ret = empty_fifo(chip, 1);
if (ret) {
- dev_err(chip->dev, "Timeout while clearing FIFO\n");
+ dev_err(chip->pdev, "Timeout while clearing FIFO\n");
return -EIO;
}
@@ -546,7 +546,14 @@ static int tpm_inf_pnp_probe(struct pnp_dev *dev,
vendorid[0], vendorid[1],
productid[0], productid[1], chipname);
- if (!(chip = tpm_register_hardware(&dev->dev, &tpm_inf)))
+ chip = tpmm_chip_alloc(&dev->dev, &tpm_inf);
+ if (IS_ERR(chip)) {
+ rc = PTR_ERR(chip);
+ goto err_release_region;
+ }
+
+ rc = tpm_chip_register(chip);
+ if (rc)
goto err_release_region;
return 0;
@@ -572,17 +579,15 @@ static void tpm_inf_pnp_remove(struct pnp_dev *dev)
{
struct tpm_chip *chip = pnp_get_drvdata(dev);
- if (chip) {
- if (tpm_dev.iotype == TPM_INF_IO_PORT) {
- release_region(tpm_dev.data_regs, tpm_dev.data_size);
- release_region(tpm_dev.config_port,
- tpm_dev.config_size);
- } else {
- iounmap(tpm_dev.mem_base);
- release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
- }
- tpm_dev_vendor_release(chip);
- tpm_remove_hardware(chip->dev);
+ tpm_chip_unregister(chip);
+
+ if (tpm_dev.iotype == TPM_INF_IO_PORT) {
+ release_region(tpm_dev.data_regs, tpm_dev.data_size);
+ release_region(tpm_dev.config_port,
+ tpm_dev.config_size);
+ } else {
+ iounmap(tpm_dev.mem_base);
+ release_mem_region(tpm_dev.map_base, tpm_dev.map_size);
}
}
diff --git a/drivers/char/tpm/tpm_nsc.c b/drivers/char/tpm/tpm_nsc.c
index 4d0a17ea8cde..289389ecef84 100644
--- a/drivers/char/tpm/tpm_nsc.c
+++ b/drivers/char/tpm/tpm_nsc.c
@@ -113,7 +113,7 @@ static int nsc_wait_for_ready(struct tpm_chip *chip)
}
while (time_before(jiffies, stop));
- dev_info(chip->dev, "wait for ready failed\n");
+ dev_info(chip->pdev, "wait for ready failed\n");
return -EBUSY;
}
@@ -129,12 +129,12 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
return -EIO;
if (wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0) {
- dev_err(chip->dev, "F0 timeout\n");
+ dev_err(chip->pdev, "F0 timeout\n");
return -EIO;
}
if ((data =
inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_NORMAL) {
- dev_err(chip->dev, "not in normal mode (0x%x)\n",
+ dev_err(chip->pdev, "not in normal mode (0x%x)\n",
data);
return -EIO;
}
@@ -143,7 +143,7 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
for (p = buffer; p < &buffer[count]; p++) {
if (wait_for_stat
(chip, NSC_STATUS_OBF, NSC_STATUS_OBF, &data) < 0) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"OBF timeout (while reading data)\n");
return -EIO;
}
@@ -154,11 +154,11 @@ static int tpm_nsc_recv(struct tpm_chip *chip, u8 * buf, size_t count)
if ((data & NSC_STATUS_F0) == 0 &&
(wait_for_stat(chip, NSC_STATUS_F0, NSC_STATUS_F0, &data) < 0)) {
- dev_err(chip->dev, "F0 not set\n");
+ dev_err(chip->pdev, "F0 not set\n");
return -EIO;
}
if ((data = inb(chip->vendor.base + NSC_DATA)) != NSC_COMMAND_EOC) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"expected end of command(0x%x)\n", data);
return -EIO;
}
@@ -189,19 +189,19 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
return -EIO;
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
- dev_err(chip->dev, "IBF timeout\n");
+ dev_err(chip->pdev, "IBF timeout\n");
return -EIO;
}
outb(NSC_COMMAND_NORMAL, chip->vendor.base + NSC_COMMAND);
if (wait_for_stat(chip, NSC_STATUS_IBR, NSC_STATUS_IBR, &data) < 0) {
- dev_err(chip->dev, "IBR timeout\n");
+ dev_err(chip->pdev, "IBR timeout\n");
return -EIO;
}
for (i = 0; i < count; i++) {
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
- dev_err(chip->dev,
+ dev_err(chip->pdev,
"IBF timeout (while writing data)\n");
return -EIO;
}
@@ -209,7 +209,7 @@ static int tpm_nsc_send(struct tpm_chip *chip, u8 * buf, size_t count)
}
if (wait_for_stat(chip, NSC_STATUS_IBF, 0, &data) < 0) {
- dev_err(chip->dev, "IBF timeout\n");
+ dev_err(chip->pdev, "IBF timeout\n");
return -EIO;
}
outb(NSC_COMMAND_EOC, chip->vendor.base + NSC_COMMAND);
@@ -247,10 +247,9 @@ static struct platform_device *pdev = NULL;
static void tpm_nsc_remove(struct device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(dev);
- if ( chip ) {
- release_region(chip->vendor.base, 2);
- tpm_remove_hardware(chip->dev);
- }
+
+ tpm_chip_unregister(chip);
+ release_region(chip->vendor.base, 2);
}
static SIMPLE_DEV_PM_OPS(tpm_nsc_pm, tpm_pm_suspend, tpm_pm_resume);
@@ -307,11 +306,16 @@ static int __init init_nsc(void)
goto err_del_dev;
}
- if (!(chip = tpm_register_hardware(&pdev->dev, &tpm_nsc))) {
+ chip = tpmm_chip_alloc(&pdev->dev, &tpm_nsc);
+ if (IS_ERR(chip)) {
rc = -ENODEV;
goto err_rel_reg;
}
+ rc = tpm_chip_register(chip);
+ if (rc)
+ goto err_rel_reg;
+
dev_dbg(&pdev->dev, "NSC TPM detected\n");
dev_dbg(&pdev->dev,
"NSC LDN 0x%x, SID 0x%x, SRID 0x%x\n",
diff --git a/drivers/char/tpm/tpm_of.c b/drivers/char/tpm/tpm_of.c
index 98ba2bd1a355..c002d1bd9caf 100644
--- a/drivers/char/tpm/tpm_of.c
+++ b/drivers/char/tpm/tpm_of.c
@@ -1,7 +1,7 @@
/*
* Copyright 2012 IBM Corporation
*
- * Author: Ashley Lai <adlai@us.ibm.com>
+ * Author: Ashley Lai <ashleydlai@gmail.com>
*
* Maintained by: <tpmdd-devel@lists.sourceforge.net>
*
diff --git a/drivers/char/tpm/tpm_ppi.c b/drivers/char/tpm/tpm_ppi.c
index 61dcc8011ec7..6ca9b5d78144 100644
--- a/drivers/char/tpm/tpm_ppi.c
+++ b/drivers/char/tpm/tpm_ppi.c
@@ -1,3 +1,22 @@
+/*
+ * Copyright (C) 2012-2014 Intel Corporation
+ *
+ * Authors:
+ * Xiaoyan Zhang <xiaoyan.zhang@intel.com>
+ * Jiang Liu <jiang.liu@linux.intel.com>
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ *
+ * Maintained by: <tpmdd-devel@lists.sourceforge.net>
+ *
+ * This file contains implementation of the sysfs interface for PPI.
+ *
+ * This program is free software; 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/acpi.h>
#include "tpm.h"
@@ -12,7 +31,6 @@
#define PPI_TPM_REQ_MAX 22
#define PPI_VS_REQ_START 128
#define PPI_VS_REQ_END 255
-#define PPI_VERSION_LEN 3
static const u8 tpm_ppi_uuid[] = {
0xA6, 0xFA, 0xDD, 0x3D,
@@ -22,45 +40,22 @@ static const u8 tpm_ppi_uuid[] = {
0x8D, 0x10, 0x08, 0x9D, 0x16, 0x53
};
-static char tpm_ppi_version[PPI_VERSION_LEN + 1];
-static acpi_handle tpm_ppi_handle;
-
-static acpi_status ppi_callback(acpi_handle handle, u32 level, void *context,
- void **return_value)
-{
- union acpi_object *obj;
-
- if (!acpi_check_dsm(handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
- 1 << TPM_PPI_FN_VERSION))
- return AE_OK;
-
- /* Cache version string */
- obj = acpi_evaluate_dsm_typed(handle, tpm_ppi_uuid,
- TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
- NULL, ACPI_TYPE_STRING);
- if (obj) {
- strlcpy(tpm_ppi_version, obj->string.pointer,
- PPI_VERSION_LEN + 1);
- ACPI_FREE(obj);
- }
-
- *return_value = handle;
-
- return AE_CTRL_TERMINATE;
-}
-
static inline union acpi_object *
-tpm_eval_dsm(int func, acpi_object_type type, union acpi_object *argv4)
+tpm_eval_dsm(acpi_handle ppi_handle, int func, acpi_object_type type,
+ union acpi_object *argv4)
{
- BUG_ON(!tpm_ppi_handle);
- return acpi_evaluate_dsm_typed(tpm_ppi_handle, tpm_ppi_uuid,
- TPM_PPI_REVISION_ID, func, argv4, type);
+ BUG_ON(!ppi_handle);
+ return acpi_evaluate_dsm_typed(ppi_handle, tpm_ppi_uuid,
+ TPM_PPI_REVISION_ID,
+ func, argv4, type);
}
static ssize_t tpm_show_ppi_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
- return scnprintf(buf, PAGE_SIZE, "%s\n", tpm_ppi_version);
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ return scnprintf(buf, PAGE_SIZE, "%s\n", chip->ppi_version);
}
static ssize_t tpm_show_ppi_request(struct device *dev,
@@ -68,8 +63,10 @@ static ssize_t tpm_show_ppi_request(struct device *dev,
{
ssize_t size = -EINVAL;
union acpi_object *obj;
+ struct tpm_chip *chip = dev_get_drvdata(dev);
- obj = tpm_eval_dsm(TPM_PPI_FN_GETREQ, ACPI_TYPE_PACKAGE, NULL);
+ obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETREQ,
+ ACPI_TYPE_PACKAGE, NULL);
if (!obj)
return -ENXIO;
@@ -103,14 +100,15 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
int func = TPM_PPI_FN_SUBREQ;
union acpi_object *obj, tmp;
union acpi_object argv4 = ACPI_INIT_DSM_ARGV4(1, &tmp);
+ struct tpm_chip *chip = dev_get_drvdata(dev);
/*
* the function to submit TPM operation request to pre-os environment
* is updated with function index from SUBREQ to SUBREQ2 since PPI
* version 1.1
*/
- if (acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
- 1 << TPM_PPI_FN_SUBREQ2))
+ if (acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
+ TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_SUBREQ2))
func = TPM_PPI_FN_SUBREQ2;
/*
@@ -119,7 +117,7 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
* string/package type. For PPI version 1.0 and 1.1, use buffer type
* for compatibility, and use package type since 1.2 according to spec.
*/
- if (strcmp(tpm_ppi_version, "1.2") < 0) {
+ if (strcmp(chip->ppi_version, "1.2") < 0) {
if (sscanf(buf, "%d", &req) != 1)
return -EINVAL;
argv4.type = ACPI_TYPE_BUFFER;
@@ -131,7 +129,8 @@ static ssize_t tpm_store_ppi_request(struct device *dev,
return -EINVAL;
}
- obj = tpm_eval_dsm(func, ACPI_TYPE_INTEGER, &argv4);
+ obj = tpm_eval_dsm(chip->acpi_dev_handle, func, ACPI_TYPE_INTEGER,
+ &argv4);
if (!obj) {
return -ENXIO;
} else {
@@ -157,6 +156,7 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
.buffer.length = 0,
.buffer.pointer = NULL
};
+ struct tpm_chip *chip = dev_get_drvdata(dev);
static char *info[] = {
"None",
@@ -171,9 +171,10 @@ static ssize_t tpm_show_ppi_transition_action(struct device *dev,
* (e.g. Capella with PPI 1.0) need integer/string/buffer type, so for
* compatibility, define params[3].type as buffer, if PPI version < 1.2
*/
- if (strcmp(tpm_ppi_version, "1.2") < 0)
+ if (strcmp(chip->ppi_version, "1.2") < 0)
obj = &tmp;
- obj = tpm_eval_dsm(TPM_PPI_FN_GETACT, ACPI_TYPE_INTEGER, obj);
+ obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETACT,
+ ACPI_TYPE_INTEGER, obj);
if (!obj) {
return -ENXIO;
} else {
@@ -196,8 +197,10 @@ static ssize_t tpm_show_ppi_response(struct device *dev,
acpi_status status = -EINVAL;
union acpi_object *obj, *ret_obj;
u64 req, res;
+ struct tpm_chip *chip = dev_get_drvdata(dev);
- obj = tpm_eval_dsm(TPM_PPI_FN_GETRSP, ACPI_TYPE_PACKAGE, NULL);
+ obj = tpm_eval_dsm(chip->acpi_dev_handle, TPM_PPI_FN_GETRSP,
+ ACPI_TYPE_PACKAGE, NULL);
if (!obj)
return -ENXIO;
@@ -248,7 +251,8 @@ cleanup:
return status;
}
-static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
+static ssize_t show_ppi_operations(acpi_handle dev_handle, char *buf, u32 start,
+ u32 end)
{
int i;
u32 ret;
@@ -264,14 +268,15 @@ static ssize_t show_ppi_operations(char *buf, u32 start, u32 end)
"User not required",
};
- if (!acpi_check_dsm(tpm_ppi_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
+ if (!acpi_check_dsm(dev_handle, tpm_ppi_uuid, TPM_PPI_REVISION_ID,
1 << TPM_PPI_FN_GETOPR))
return -EPERM;
tmp.integer.type = ACPI_TYPE_INTEGER;
for (i = start; i <= end; i++) {
tmp.integer.value = i;
- obj = tpm_eval_dsm(TPM_PPI_FN_GETOPR, ACPI_TYPE_INTEGER, &argv);
+ obj = tpm_eval_dsm(dev_handle, TPM_PPI_FN_GETOPR,
+ ACPI_TYPE_INTEGER, &argv);
if (!obj) {
return -ENOMEM;
} else {
@@ -291,14 +296,20 @@ static ssize_t tpm_show_ppi_tcg_operations(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return show_ppi_operations(buf, 0, PPI_TPM_REQ_MAX);
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ return show_ppi_operations(chip->acpi_dev_handle, buf, 0,
+ PPI_TPM_REQ_MAX);
}
static ssize_t tpm_show_ppi_vs_operations(struct device *dev,
struct device_attribute *attr,
char *buf)
{
- return show_ppi_operations(buf, PPI_VS_REQ_START, PPI_VS_REQ_END);
+ struct tpm_chip *chip = dev_get_drvdata(dev);
+
+ return show_ppi_operations(chip->acpi_dev_handle, buf, PPI_VS_REQ_START,
+ PPI_VS_REQ_END);
}
static DEVICE_ATTR(version, S_IRUGO, tpm_show_ppi_version, NULL);
@@ -323,16 +334,38 @@ static struct attribute_group ppi_attr_grp = {
.attrs = ppi_attrs
};
-int tpm_add_ppi(struct kobject *parent)
+int tpm_add_ppi(struct tpm_chip *chip)
{
- /* Cache TPM ACPI handle and version string */
- acpi_walk_namespace(ACPI_TYPE_DEVICE, ACPI_ROOT_OBJECT, ACPI_UINT32_MAX,
- ppi_callback, NULL, NULL, &tpm_ppi_handle);
- return tpm_ppi_handle ? sysfs_create_group(parent, &ppi_attr_grp) : 0;
+ union acpi_object *obj;
+ int rc;
+
+ if (!chip->acpi_dev_handle)
+ return 0;
+
+ if (!acpi_check_dsm(chip->acpi_dev_handle, tpm_ppi_uuid,
+ TPM_PPI_REVISION_ID, 1 << TPM_PPI_FN_VERSION))
+ return 0;
+
+ /* Cache PPI version string. */
+ obj = acpi_evaluate_dsm_typed(chip->acpi_dev_handle, tpm_ppi_uuid,
+ TPM_PPI_REVISION_ID, TPM_PPI_FN_VERSION,
+ NULL, ACPI_TYPE_STRING);
+ if (obj) {
+ strlcpy(chip->ppi_version, obj->string.pointer,
+ sizeof(chip->ppi_version));
+ ACPI_FREE(obj);
+ }
+
+ rc = sysfs_create_group(&chip->pdev->kobj, &ppi_attr_grp);
+
+ if (!rc)
+ chip->flags |= TPM_CHIP_FLAG_PPI;
+
+ return rc;
}
-void tpm_remove_ppi(struct kobject *parent)
+void tpm_remove_ppi(struct tpm_chip *chip)
{
- if (tpm_ppi_handle)
- sysfs_remove_group(parent, &ppi_attr_grp);
+ if (chip->flags & TPM_CHIP_FLAG_PPI)
+ sysfs_remove_group(&chip->pdev->kobj, &ppi_attr_grp);
}
diff --git a/drivers/char/tpm/tpm_tis.c b/drivers/char/tpm/tpm_tis.c
index 6f1985496112..f2dffa770b8e 100644
--- a/drivers/char/tpm/tpm_tis.c
+++ b/drivers/char/tpm/tpm_tis.c
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2005, 2006 IBM Corporation
+ * Copyright (C) 2014 Intel Corporation
*
* Authors:
* Leendert van Doorn <leendert@watson.ibm.com>
@@ -64,19 +65,30 @@ enum tis_defaults {
TIS_LONG_TIMEOUT = 2000, /* 2 sec */
};
+
+/* Some timeout values are needed before it is known whether the chip is
+ * TPM 1.0 or TPM 2.0.
+ */
+#define TIS_TIMEOUT_A_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_A)
+#define TIS_TIMEOUT_B_MAX max(TIS_LONG_TIMEOUT, TPM2_TIMEOUT_B)
+#define TIS_TIMEOUT_C_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_C)
+#define TIS_TIMEOUT_D_MAX max(TIS_SHORT_TIMEOUT, TPM2_TIMEOUT_D)
+
#define TPM_ACCESS(l) (0x0000 | ((l) << 12))
#define TPM_INT_ENABLE(l) (0x0008 | ((l) << 12))
#define TPM_INT_VECTOR(l) (0x000C | ((l) << 12))
#define TPM_INT_STATUS(l) (0x0010 | ((l) << 12))
#define TPM_INTF_CAPS(l) (0x0014 | ((l) << 12))
#define TPM_STS(l) (0x0018 | ((l) << 12))
+#define TPM_STS3(l) (0x001b | ((l) << 12))
#define TPM_DATA_FIFO(l) (0x0024 | ((l) << 12))
#define TPM_DID_VID(l) (0x0F00 | ((l) << 12))
#define TPM_RID(l) (0x0F04 | ((l) << 12))
-static LIST_HEAD(tis_chips);
-static DEFINE_MUTEX(tis_lock);
+struct priv_data {
+ bool irq_tested;
+};
#if defined(CONFIG_PNP) && defined(CONFIG_ACPI)
static int is_itpm(struct pnp_dev *dev)
@@ -241,7 +253,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
/* read first 10 bytes, including tag, paramsize, and result */
if ((size =
recv_data(chip, buf, TPM_HEADER_SIZE)) < TPM_HEADER_SIZE) {
- dev_err(chip->dev, "Unable to read header\n");
+ dev_err(chip->pdev, "Unable to read header\n");
goto out;
}
@@ -254,7 +266,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
if ((size +=
recv_data(chip, &buf[TPM_HEADER_SIZE],
expected - TPM_HEADER_SIZE)) < expected) {
- dev_err(chip->dev, "Unable to read remainder of result\n");
+ dev_err(chip->pdev, "Unable to read remainder of result\n");
size = -ETIME;
goto out;
}
@@ -263,7 +275,7 @@ static int tpm_tis_recv(struct tpm_chip *chip, u8 *buf, size_t count)
&chip->vendor.int_queue, false);
status = tpm_tis_status(chip);
if (status & TPM_STS_DATA_AVAIL) { /* retry? */
- dev_err(chip->dev, "Error left over data\n");
+ dev_err(chip->pdev, "Error left over data\n");
size = -EIO;
goto out;
}
@@ -338,15 +350,31 @@ out_err:
return rc;
}
+static void disable_interrupts(struct tpm_chip *chip)
+{
+ u32 intmask;
+
+ intmask =
+ ioread32(chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ intmask &= ~TPM_GLOBAL_INT_ENABLE;
+ iowrite32(intmask,
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ free_irq(chip->vendor.irq, chip);
+ chip->vendor.irq = 0;
+}
+
/*
* If interrupts are used (signaled by an irq set in the vendor structure)
* tpm.c can skip polling for the data to be available as the interrupt is
* waited for here
*/
-static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+static int tpm_tis_send_main(struct tpm_chip *chip, u8 *buf, size_t len)
{
int rc;
u32 ordinal;
+ unsigned long dur;
rc = tpm_tis_send_data(chip, buf, len);
if (rc < 0)
@@ -358,9 +386,14 @@ static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
if (chip->vendor.irq) {
ordinal = be32_to_cpu(*((__be32 *) (buf + 6)));
+
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ dur = tpm2_calc_ordinal_duration(chip, ordinal);
+ else
+ dur = tpm_calc_ordinal_duration(chip, ordinal);
+
if (wait_for_tpm_stat
- (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID,
- tpm_calc_ordinal_duration(chip, ordinal),
+ (chip, TPM_STS_DATA_AVAIL | TPM_STS_VALID, dur,
&chip->vendor.read_queue, false) < 0) {
rc = -ETIME;
goto out_err;
@@ -373,6 +406,30 @@ out_err:
return rc;
}
+static int tpm_tis_send(struct tpm_chip *chip, u8 *buf, size_t len)
+{
+ int rc, irq;
+ struct priv_data *priv = chip->vendor.priv;
+
+ if (!chip->vendor.irq || priv->irq_tested)
+ return tpm_tis_send_main(chip, buf, len);
+
+ /* Verify receipt of the expected IRQ */
+ irq = chip->vendor.irq;
+ chip->vendor.irq = 0;
+ rc = tpm_tis_send_main(chip, buf, len);
+ chip->vendor.irq = irq;
+ if (!priv->irq_tested)
+ msleep(1);
+ if (!priv->irq_tested) {
+ disable_interrupts(chip);
+ dev_err(chip->pdev,
+ FW_BUG "TPM interrupt not working, polling instead\n");
+ }
+ priv->irq_tested = true;
+ return rc;
+}
+
struct tis_vendor_timeout_override {
u32 did_vid;
unsigned long timeout_us[4];
@@ -436,7 +493,7 @@ static int probe_itpm(struct tpm_chip *chip)
rc = tpm_tis_send_data(chip, cmd_getticks, len);
if (rc == 0) {
- dev_info(chip->dev, "Detected an iTPM.\n");
+ dev_info(chip->pdev, "Detected an iTPM.\n");
rc = 1;
} else
rc = -EFAULT;
@@ -505,6 +562,7 @@ static irqreturn_t tis_int_handler(int dummy, void *dev_id)
if (interrupt == 0)
return IRQ_NONE;
+ ((struct priv_data *)chip->vendor.priv)->irq_tested = true;
if (interrupt & TPM_INTF_DATA_AVAIL_INT)
wake_up_interruptible(&chip->vendor.read_queue);
if (interrupt & TPM_INTF_LOCALITY_CHANGE_INT)
@@ -528,27 +586,51 @@ static bool interrupts = true;
module_param(interrupts, bool, 0444);
MODULE_PARM_DESC(interrupts, "Enable interrupts");
-static int tpm_tis_init(struct device *dev, resource_size_t start,
- resource_size_t len, unsigned int irq)
+static void tpm_tis_remove(struct tpm_chip *chip)
+{
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ tpm2_shutdown(chip, TPM2_SU_CLEAR);
+
+ iowrite32(~TPM_GLOBAL_INT_ENABLE &
+ ioread32(chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.
+ locality)),
+ chip->vendor.iobase +
+ TPM_INT_ENABLE(chip->vendor.locality));
+ release_locality(chip, chip->vendor.locality, 1);
+}
+
+static int tpm_tis_init(struct device *dev, acpi_handle acpi_dev_handle,
+ resource_size_t start, resource_size_t len,
+ unsigned int irq)
{
u32 vendor, intfcaps, intmask;
int rc, i, irq_s, irq_e, probe;
struct tpm_chip *chip;
+ struct priv_data *priv;
- if (!(chip = tpm_register_hardware(dev, &tpm_tis)))
- return -ENODEV;
+ priv = devm_kzalloc(dev, sizeof(struct priv_data), GFP_KERNEL);
+ if (priv == NULL)
+ return -ENOMEM;
- chip->vendor.iobase = ioremap(start, len);
- if (!chip->vendor.iobase) {
- rc = -EIO;
- goto out_err;
- }
+ chip = tpmm_chip_alloc(dev, &tpm_tis);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
+
+ chip->vendor.priv = priv;
+#ifdef CONFIG_ACPI
+ chip->acpi_dev_handle = acpi_dev_handle;
+#endif
+
+ chip->vendor.iobase = devm_ioremap(dev, start, len);
+ if (!chip->vendor.iobase)
+ return -EIO;
- /* Default timeouts */
- chip->vendor.timeout_a = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- chip->vendor.timeout_b = msecs_to_jiffies(TIS_LONG_TIMEOUT);
- chip->vendor.timeout_c = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
- chip->vendor.timeout_d = msecs_to_jiffies(TIS_SHORT_TIMEOUT);
+ /* Maximum timeouts */
+ chip->vendor.timeout_a = TIS_TIMEOUT_A_MAX;
+ chip->vendor.timeout_b = TIS_TIMEOUT_B_MAX;
+ chip->vendor.timeout_c = TIS_TIMEOUT_C_MAX;
+ chip->vendor.timeout_d = TIS_TIMEOUT_D_MAX;
if (wait_startup(chip, 0) != 0) {
rc = -ENODEV;
@@ -560,11 +642,15 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
goto out_err;
}
+ rc = tpm2_probe(chip);
+ if (rc)
+ goto out_err;
+
vendor = ioread32(chip->vendor.iobase + TPM_DID_VID(0));
chip->vendor.manufacturer_id = vendor;
- dev_info(dev,
- "1.2 TPM (device-id 0x%X, rev-id %d)\n",
+ dev_info(dev, "%s TPM (device-id 0x%X, rev-id %d)\n",
+ (chip->flags & TPM_CHIP_FLAG_TPM2) ? "2.0" : "1.2",
vendor >> 16, ioread8(chip->vendor.iobase + TPM_RID(0)));
if (!itpm) {
@@ -605,19 +691,6 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
if (intfcaps & TPM_INTF_DATA_AVAIL_INT)
dev_dbg(dev, "\tData Avail Int Support\n");
- /* get the timeouts before testing for irqs */
- if (tpm_get_timeouts(chip)) {
- dev_err(dev, "Could not get TPM timeouts and durations\n");
- rc = -ENODEV;
- goto out_err;
- }
-
- if (tpm_do_selftest(chip)) {
- dev_err(dev, "TPM self test failed\n");
- rc = -ENODEV;
- goto out_err;
- }
-
/* INTERRUPT Setup */
init_waitqueue_head(&chip->vendor.read_queue);
init_waitqueue_head(&chip->vendor.int_queue);
@@ -649,10 +722,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
for (i = irq_s; i <= irq_e && chip->vendor.irq == 0; i++) {
iowrite8(i, chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
- if (request_irq
- (i, tis_int_probe, IRQF_SHARED,
- chip->vendor.miscdev.name, chip) != 0) {
- dev_info(chip->dev,
+ if (devm_request_irq
+ (dev, i, tis_int_probe, IRQF_SHARED,
+ chip->devname, chip) != 0) {
+ dev_info(chip->pdev,
"Unable to request irq: %d for probe\n",
i);
continue;
@@ -673,7 +746,10 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
chip->vendor.probed_irq = 0;
/* Generate Interrupts */
- tpm_gen_interrupt(chip);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2)
+ tpm2_gen_interrupt(chip);
+ else
+ tpm_gen_interrupt(chip);
chip->vendor.irq = chip->vendor.probed_irq;
@@ -690,17 +766,16 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
iowrite32(intmask,
chip->vendor.iobase +
TPM_INT_ENABLE(chip->vendor.locality));
- free_irq(i, chip);
}
}
if (chip->vendor.irq) {
iowrite8(chip->vendor.irq,
chip->vendor.iobase +
TPM_INT_VECTOR(chip->vendor.locality));
- if (request_irq
- (chip->vendor.irq, tis_int_handler, IRQF_SHARED,
- chip->vendor.miscdev.name, chip) != 0) {
- dev_info(chip->dev,
+ if (devm_request_irq
+ (dev, chip->vendor.irq, tis_int_handler, IRQF_SHARED,
+ chip->devname, chip) != 0) {
+ dev_info(chip->pdev,
"Unable to request irq: %d for use\n",
chip->vendor.irq);
chip->vendor.irq = 0;
@@ -719,17 +794,49 @@ static int tpm_tis_init(struct device *dev, resource_size_t start,
}
}
- INIT_LIST_HEAD(&chip->vendor.list);
- mutex_lock(&tis_lock);
- list_add(&chip->vendor.list, &tis_chips);
- mutex_unlock(&tis_lock);
+ if (chip->flags & TPM_CHIP_FLAG_TPM2) {
+ chip->vendor.timeout_a = msecs_to_jiffies(TPM2_TIMEOUT_A);
+ chip->vendor.timeout_b = msecs_to_jiffies(TPM2_TIMEOUT_B);
+ chip->vendor.timeout_c = msecs_to_jiffies(TPM2_TIMEOUT_C);
+ chip->vendor.timeout_d = msecs_to_jiffies(TPM2_TIMEOUT_D);
+ chip->vendor.duration[TPM_SHORT] =
+ msecs_to_jiffies(TPM2_DURATION_SHORT);
+ chip->vendor.duration[TPM_MEDIUM] =
+ msecs_to_jiffies(TPM2_DURATION_MEDIUM);
+ chip->vendor.duration[TPM_LONG] =
+ msecs_to_jiffies(TPM2_DURATION_LONG);
+
+ rc = tpm2_do_selftest(chip);
+ if (rc == TPM2_RC_INITIALIZE) {
+ dev_warn(dev, "Firmware has not started TPM\n");
+ rc = tpm2_startup(chip, TPM2_SU_CLEAR);
+ if (!rc)
+ rc = tpm2_do_selftest(chip);
+ }
+
+ if (rc) {
+ dev_err(dev, "TPM self test failed\n");
+ if (rc > 0)
+ rc = -ENODEV;
+ goto out_err;
+ }
+ } else {
+ if (tpm_get_timeouts(chip)) {
+ dev_err(dev, "Could not get TPM timeouts and durations\n");
+ rc = -ENODEV;
+ goto out_err;
+ }
+ if (tpm_do_selftest(chip)) {
+ dev_err(dev, "TPM self test failed\n");
+ rc = -ENODEV;
+ goto out_err;
+ }
+ }
- return 0;
+ return tpm_chip_register(chip);
out_err:
- if (chip->vendor.iobase)
- iounmap(chip->vendor.iobase);
- tpm_remove_hardware(chip->dev);
+ tpm_tis_remove(chip);
return rc;
}
@@ -764,10 +871,16 @@ static int tpm_tis_resume(struct device *dev)
tpm_tis_reenable_interrupts(chip);
ret = tpm_pm_resume(dev);
- if (!ret)
+ if (ret)
+ return ret;
+
+ /* TPM 1.2 requires self-test on resume. This function actually returns
+ * an error code but for unknown reason it isn't handled.
+ */
+ if (!(chip->flags & TPM_CHIP_FLAG_TPM2))
tpm_do_selftest(chip);
- return ret;
+ return 0;
}
#endif
@@ -779,6 +892,7 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
{
resource_size_t start, len;
unsigned int irq = 0;
+ acpi_handle acpi_dev_handle = NULL;
start = pnp_mem_start(pnp_dev, 0);
len = pnp_mem_len(pnp_dev, 0);
@@ -791,7 +905,12 @@ static int tpm_tis_pnp_init(struct pnp_dev *pnp_dev,
if (is_itpm(pnp_dev))
itpm = true;
- return tpm_tis_init(&pnp_dev->dev, start, len, irq);
+#ifdef CONFIG_ACPI
+ if (pnp_acpi_device(pnp_dev))
+ acpi_dev_handle = pnp_acpi_device(pnp_dev)->handle;
+#endif
+
+ return tpm_tis_init(&pnp_dev->dev, acpi_dev_handle, start, len, irq);
}
static struct pnp_device_id tpm_pnp_tbl[] = {
@@ -811,13 +930,10 @@ MODULE_DEVICE_TABLE(pnp, tpm_pnp_tbl);
static void tpm_tis_pnp_remove(struct pnp_dev *dev)
{
struct tpm_chip *chip = pnp_get_drvdata(dev);
-
- tpm_dev_vendor_release(chip);
-
- kfree(chip);
+ tpm_chip_unregister(chip);
+ tpm_tis_remove(chip);
}
-
static struct pnp_driver tis_pnp_driver = {
.name = "tpm_tis",
.id_table = tpm_pnp_tbl,
@@ -836,7 +952,7 @@ MODULE_PARM_DESC(hid, "Set additional specific HID for this driver to probe");
static struct platform_driver tis_drv = {
.driver = {
- .name = "tpm_tis",
+ .name = "tpm_tis",
.pm = &tpm_tis_pm,
},
};
@@ -862,7 +978,7 @@ static int __init init_tis(void)
rc = PTR_ERR(pdev);
goto err_dev;
}
- rc = tpm_tis_init(&pdev->dev, TIS_MEM_BASE, TIS_MEM_LEN, 0);
+ rc = tpm_tis_init(&pdev->dev, NULL, TIS_MEM_BASE, TIS_MEM_LEN, 0);
if (rc)
goto err_init;
return 0;
@@ -875,31 +991,16 @@ err_dev:
static void __exit cleanup_tis(void)
{
- struct tpm_vendor_specific *i, *j;
struct tpm_chip *chip;
- mutex_lock(&tis_lock);
- list_for_each_entry_safe(i, j, &tis_chips, list) {
- chip = to_tpm_chip(i);
- tpm_remove_hardware(chip->dev);
- iowrite32(~TPM_GLOBAL_INT_ENABLE &
- ioread32(chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.
- locality)),
- chip->vendor.iobase +
- TPM_INT_ENABLE(chip->vendor.locality));
- release_locality(chip, chip->vendor.locality, 1);
- if (chip->vendor.irq)
- free_irq(chip->vendor.irq, chip);
- iounmap(i->iobase);
- list_del(&i->list);
- }
- mutex_unlock(&tis_lock);
#ifdef CONFIG_PNP
if (!force) {
pnp_unregister_driver(&tis_pnp_driver);
return;
}
#endif
+ chip = dev_get_drvdata(&pdev->dev);
+ tpm_chip_unregister(chip);
+ tpm_tis_remove(chip);
platform_device_unregister(pdev);
platform_driver_unregister(&tis_drv);
}
diff --git a/drivers/char/tpm/xen-tpmfront.c b/drivers/char/tpm/xen-tpmfront.c
index 441b44e54226..c3b4f5a5ac10 100644
--- a/drivers/char/tpm/xen-tpmfront.c
+++ b/drivers/char/tpm/xen-tpmfront.c
@@ -175,9 +175,9 @@ static int setup_chip(struct device *dev, struct tpm_private *priv)
{
struct tpm_chip *chip;
- chip = tpm_register_hardware(dev, &tpm_vtpm);
- if (!chip)
- return -ENODEV;
+ chip = tpmm_chip_alloc(dev, &tpm_vtpm);
+ if (IS_ERR(chip))
+ return PTR_ERR(chip);
init_waitqueue_head(&chip->vendor.read_queue);
@@ -286,6 +286,7 @@ static int tpmfront_probe(struct xenbus_device *dev,
const struct xenbus_device_id *id)
{
struct tpm_private *priv;
+ struct tpm_chip *chip;
int rv;
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
@@ -302,21 +303,22 @@ static int tpmfront_probe(struct xenbus_device *dev,
rv = setup_ring(dev, priv);
if (rv) {
- tpm_remove_hardware(&dev->dev);
+ chip = dev_get_drvdata(&dev->dev);
+ tpm_chip_unregister(chip);
ring_free(priv);
return rv;
}
tpm_get_timeouts(priv->chip);
- return rv;
+ return tpm_chip_register(priv->chip);
}
static int tpmfront_remove(struct xenbus_device *dev)
{
struct tpm_chip *chip = dev_get_drvdata(&dev->dev);
struct tpm_private *priv = TPM_VPRIV(chip);
- tpm_remove_hardware(&dev->dev);
+ tpm_chip_unregister(chip);
ring_free(priv);
TPM_VPRIV(chip) = NULL;
return 0;
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index de03df9dd7c9..fae2dbbf5745 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -1986,6 +1986,15 @@ static int virtcons_probe(struct virtio_device *vdev)
bool multiport;
bool early = early_put_chars != NULL;
+ /* We only need a config space if features are offered */
+ if (!vdev->config->get &&
+ (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_SIZE)
+ || virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT))) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
/* Ensure to read early_put_chars now */
barrier();
diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 3f44f292d066..0b474a04730f 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -13,6 +13,7 @@ config COMMON_CLK
bool
select HAVE_CLK_PREPARE
select CLKDEV_LOOKUP
+ select SRCU
---help---
The common clock framework is a single definition of struct
clk, useful across many platforms, as well as an
@@ -101,12 +102,12 @@ config COMMON_CLK_AXI_CLKGEN
Support for the Analog Devices axi-clkgen pcore clock generator for Xilinx
FPGAs. It is commonly used in Analog Devices' reference designs.
-config CLK_PPC_CORENET
- bool "Clock driver for PowerPC corenet platforms"
- depends on PPC_E500MC && OF
+config CLK_QORIQ
+ bool "Clock driver for Freescale QorIQ platforms"
+ depends on (PPC_E500MC || ARM) && OF
---help---
- This adds the clock driver support for Freescale PowerPC corenet
- platforms using common clock framework.
+ This adds the clock driver support for Freescale QorIQ platforms
+ using common clock framework.
config COMMON_CLK_XGENE
bool "Clock driver for APM XGene SoC"
@@ -134,6 +135,14 @@ config COMMON_CLK_PXA
---help---
Sypport for the Marvell PXA SoC.
+config COMMON_CLK_CDCE706
+ tristate "Clock driver for TI CDCE706 clock synthesizer"
+ depends on I2C
+ select REGMAP_I2C
+ select RATIONAL
+ ---help---
+ This driver supports TI CDCE706 programmable 3-PLL clock synthesizer.
+
source "drivers/clk/qcom/Kconfig"
endmenu
diff --git a/drivers/clk/Makefile b/drivers/clk/Makefile
index d5fba5bc6e1b..d478ceb69c5f 100644
--- a/drivers/clk/Makefile
+++ b/drivers/clk/Makefile
@@ -16,9 +16,11 @@ endif
# hardware specific clock types
# please keep this section sorted lexicographically by file/directory path name
+obj-$(CONFIG_MACH_ASM9260) += clk-asm9260.o
obj-$(CONFIG_COMMON_CLK_AXI_CLKGEN) += clk-axi-clkgen.o
obj-$(CONFIG_ARCH_AXXIA) += clk-axm5516.o
obj-$(CONFIG_ARCH_BCM2835) += clk-bcm2835.o
+obj-$(CONFIG_COMMON_CLK_CDCE706) += clk-cdce706.o
obj-$(CONFIG_ARCH_CLPS711X) += clk-clps711x.o
obj-$(CONFIG_ARCH_EFM32) += clk-efm32gg.o
obj-$(CONFIG_ARCH_HIGHBANK) += clk-highbank.o
@@ -30,7 +32,7 @@ obj-$(CONFIG_ARCH_MOXART) += clk-moxart.o
obj-$(CONFIG_ARCH_NOMADIK) += clk-nomadik.o
obj-$(CONFIG_ARCH_NSPIRE) += clk-nspire.o
obj-$(CONFIG_COMMON_CLK_PALMAS) += clk-palmas.o
-obj-$(CONFIG_CLK_PPC_CORENET) += clk-ppc-corenet.o
+obj-$(CONFIG_CLK_QORIQ) += clk-qoriq.o
obj-$(CONFIG_COMMON_CLK_RK808) += clk-rk808.o
obj-$(CONFIG_COMMON_CLK_S2MPS11) += clk-s2mps11.o
obj-$(CONFIG_COMMON_CLK_SI5351) += clk-si5351.o
diff --git a/drivers/clk/at91/clk-programmable.c b/drivers/clk/at91/clk-programmable.c
index bbdb1b985c91..86c8a073dcc3 100644
--- a/drivers/clk/at91/clk-programmable.c
+++ b/drivers/clk/at91/clk-programmable.c
@@ -56,6 +56,8 @@ static unsigned long clk_programmable_recalc_rate(struct clk_hw *hw,
static long clk_programmable_determine_rate(struct clk_hw *hw,
unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_hw)
{
diff --git a/drivers/clk/at91/pmc.c b/drivers/clk/at91/pmc.c
index 386999b4f8eb..f07c8152e5cc 100644
--- a/drivers/clk/at91/pmc.c
+++ b/drivers/clk/at91/pmc.c
@@ -27,6 +27,15 @@
void __iomem *at91_pmc_base;
EXPORT_SYMBOL_GPL(at91_pmc_base);
+void at91rm9200_idle(void)
+{
+ /*
+ * Disable the processor clock. The processor will be automatically
+ * re-enabled by an interrupt or by a reset.
+ */
+ at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
+}
+
void at91sam9_idle(void)
{
at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
diff --git a/drivers/clk/bcm/clk-kona.c b/drivers/clk/bcm/clk-kona.c
index 1c06f6f3a8c5..05abae89262e 100644
--- a/drivers/clk/bcm/clk-kona.c
+++ b/drivers/clk/bcm/clk-kona.c
@@ -1032,6 +1032,8 @@ static long kona_peri_clk_round_rate(struct clk_hw *hw, unsigned long rate,
}
static long kona_peri_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate, struct clk_hw **best_parent)
{
struct kona_clk *bcm_clk = to_kona_clk(hw);
diff --git a/drivers/clk/clk-asm9260.c b/drivers/clk/clk-asm9260.c
new file mode 100644
index 000000000000..88f4ff6916fe
--- /dev/null
+++ b/drivers/clk/clk-asm9260.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright (c) 2014 Oleksij Rempel <linux@rempel-privat.de>.
+ *
+ * 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/clkdev.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/clk-provider.h>
+#include <linux/spinlock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <dt-bindings/clock/alphascale,asm9260.h>
+
+#define HW_AHBCLKCTRL0 0x0020
+#define HW_AHBCLKCTRL1 0x0030
+#define HW_SYSPLLCTRL 0x0100
+#define HW_MAINCLKSEL 0x0120
+#define HW_MAINCLKUEN 0x0124
+#define HW_UARTCLKSEL 0x0128
+#define HW_UARTCLKUEN 0x012c
+#define HW_I2S0CLKSEL 0x0130
+#define HW_I2S0CLKUEN 0x0134
+#define HW_I2S1CLKSEL 0x0138
+#define HW_I2S1CLKUEN 0x013c
+#define HW_WDTCLKSEL 0x0160
+#define HW_WDTCLKUEN 0x0164
+#define HW_CLKOUTCLKSEL 0x0170
+#define HW_CLKOUTCLKUEN 0x0174
+#define HW_CPUCLKDIV 0x017c
+#define HW_SYSAHBCLKDIV 0x0180
+#define HW_I2S0MCLKDIV 0x0190
+#define HW_I2S0SCLKDIV 0x0194
+#define HW_I2S1MCLKDIV 0x0188
+#define HW_I2S1SCLKDIV 0x018c
+#define HW_UART0CLKDIV 0x0198
+#define HW_UART1CLKDIV 0x019c
+#define HW_UART2CLKDIV 0x01a0
+#define HW_UART3CLKDIV 0x01a4
+#define HW_UART4CLKDIV 0x01a8
+#define HW_UART5CLKDIV 0x01ac
+#define HW_UART6CLKDIV 0x01b0
+#define HW_UART7CLKDIV 0x01b4
+#define HW_UART8CLKDIV 0x01b8
+#define HW_UART9CLKDIV 0x01bc
+#define HW_SPI0CLKDIV 0x01c0
+#define HW_SPI1CLKDIV 0x01c4
+#define HW_QUADSPICLKDIV 0x01c8
+#define HW_SSP0CLKDIV 0x01d0
+#define HW_NANDCLKDIV 0x01d4
+#define HW_TRACECLKDIV 0x01e0
+#define HW_CAMMCLKDIV 0x01e8
+#define HW_WDTCLKDIV 0x01ec
+#define HW_CLKOUTCLKDIV 0x01f4
+#define HW_MACCLKDIV 0x01f8
+#define HW_LCDCLKDIV 0x01fc
+#define HW_ADCANACLKDIV 0x0200
+
+static struct clk *clks[MAX_CLKS];
+static struct clk_onecell_data clk_data;
+static DEFINE_SPINLOCK(asm9260_clk_lock);
+
+struct asm9260_div_clk {
+ unsigned int idx;
+ const char *name;
+ const char *parent_name;
+ u32 reg;
+};
+
+struct asm9260_gate_data {
+ unsigned int idx;
+ const char *name;
+ const char *parent_name;
+ u32 reg;
+ u8 bit_idx;
+ unsigned long flags;
+};
+
+struct asm9260_mux_clock {
+ u8 mask;
+ u32 *table;
+ const char *name;
+ const char **parent_names;
+ u8 num_parents;
+ unsigned long offset;
+ unsigned long flags;
+};
+
+static void __iomem *base;
+
+static const struct asm9260_div_clk asm9260_div_clks[] __initconst = {
+ { CLKID_SYS_CPU, "cpu_div", "main_gate", HW_CPUCLKDIV },
+ { CLKID_SYS_AHB, "ahb_div", "cpu_div", HW_SYSAHBCLKDIV },
+
+ /* i2s has two deviders: one for only external mclk and internal
+ * devider for all clks. */
+ { CLKID_SYS_I2S0M, "i2s0m_div", "i2s0_mclk", HW_I2S0MCLKDIV },
+ { CLKID_SYS_I2S1M, "i2s1m_div", "i2s1_mclk", HW_I2S1MCLKDIV },
+ { CLKID_SYS_I2S0S, "i2s0s_div", "i2s0_gate", HW_I2S0SCLKDIV },
+ { CLKID_SYS_I2S1S, "i2s1s_div", "i2s0_gate", HW_I2S1SCLKDIV },
+
+ { CLKID_SYS_UART0, "uart0_div", "uart_gate", HW_UART0CLKDIV },
+ { CLKID_SYS_UART1, "uart1_div", "uart_gate", HW_UART1CLKDIV },
+ { CLKID_SYS_UART2, "uart2_div", "uart_gate", HW_UART2CLKDIV },
+ { CLKID_SYS_UART3, "uart3_div", "uart_gate", HW_UART3CLKDIV },
+ { CLKID_SYS_UART4, "uart4_div", "uart_gate", HW_UART4CLKDIV },
+ { CLKID_SYS_UART5, "uart5_div", "uart_gate", HW_UART5CLKDIV },
+ { CLKID_SYS_UART6, "uart6_div", "uart_gate", HW_UART6CLKDIV },
+ { CLKID_SYS_UART7, "uart7_div", "uart_gate", HW_UART7CLKDIV },
+ { CLKID_SYS_UART8, "uart8_div", "uart_gate", HW_UART8CLKDIV },
+ { CLKID_SYS_UART9, "uart9_div", "uart_gate", HW_UART9CLKDIV },
+
+ { CLKID_SYS_SPI0, "spi0_div", "main_gate", HW_SPI0CLKDIV },
+ { CLKID_SYS_SPI1, "spi1_div", "main_gate", HW_SPI1CLKDIV },
+ { CLKID_SYS_QUADSPI, "quadspi_div", "main_gate", HW_QUADSPICLKDIV },
+ { CLKID_SYS_SSP0, "ssp0_div", "main_gate", HW_SSP0CLKDIV },
+ { CLKID_SYS_NAND, "nand_div", "main_gate", HW_NANDCLKDIV },
+ { CLKID_SYS_TRACE, "trace_div", "main_gate", HW_TRACECLKDIV },
+ { CLKID_SYS_CAMM, "camm_div", "main_gate", HW_CAMMCLKDIV },
+ { CLKID_SYS_MAC, "mac_div", "main_gate", HW_MACCLKDIV },
+ { CLKID_SYS_LCD, "lcd_div", "main_gate", HW_LCDCLKDIV },
+ { CLKID_SYS_ADCANA, "adcana_div", "main_gate", HW_ADCANACLKDIV },
+
+ { CLKID_SYS_WDT, "wdt_div", "wdt_gate", HW_WDTCLKDIV },
+ { CLKID_SYS_CLKOUT, "clkout_div", "clkout_gate", HW_CLKOUTCLKDIV },
+};
+
+static const struct asm9260_gate_data asm9260_mux_gates[] __initconst = {
+ { 0, "main_gate", "main_mux", HW_MAINCLKUEN, 0 },
+ { 0, "uart_gate", "uart_mux", HW_UARTCLKUEN, 0 },
+ { 0, "i2s0_gate", "i2s0_mux", HW_I2S0CLKUEN, 0 },
+ { 0, "i2s1_gate", "i2s1_mux", HW_I2S1CLKUEN, 0 },
+ { 0, "wdt_gate", "wdt_mux", HW_WDTCLKUEN, 0 },
+ { 0, "clkout_gate", "clkout_mux", HW_CLKOUTCLKUEN, 0 },
+};
+static const struct asm9260_gate_data asm9260_ahb_gates[] __initconst = {
+ /* ahb gates */
+ { CLKID_AHB_ROM, "rom", "ahb_div",
+ HW_AHBCLKCTRL0, 1, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_RAM, "ram", "ahb_div",
+ HW_AHBCLKCTRL0, 2, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_GPIO, "gpio", "ahb_div",
+ HW_AHBCLKCTRL0, 4 },
+ { CLKID_AHB_MAC, "mac", "ahb_div",
+ HW_AHBCLKCTRL0, 5 },
+ { CLKID_AHB_EMI, "emi", "ahb_div",
+ HW_AHBCLKCTRL0, 6, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_USB0, "usb0", "ahb_div",
+ HW_AHBCLKCTRL0, 7 },
+ { CLKID_AHB_USB1, "usb1", "ahb_div",
+ HW_AHBCLKCTRL0, 8 },
+ { CLKID_AHB_DMA0, "dma0", "ahb_div",
+ HW_AHBCLKCTRL0, 9 },
+ { CLKID_AHB_DMA1, "dma1", "ahb_div",
+ HW_AHBCLKCTRL0, 10 },
+ { CLKID_AHB_UART0, "uart0", "ahb_div",
+ HW_AHBCLKCTRL0, 11 },
+ { CLKID_AHB_UART1, "uart1", "ahb_div",
+ HW_AHBCLKCTRL0, 12 },
+ { CLKID_AHB_UART2, "uart2", "ahb_div",
+ HW_AHBCLKCTRL0, 13 },
+ { CLKID_AHB_UART3, "uart3", "ahb_div",
+ HW_AHBCLKCTRL0, 14 },
+ { CLKID_AHB_UART4, "uart4", "ahb_div",
+ HW_AHBCLKCTRL0, 15 },
+ { CLKID_AHB_UART5, "uart5", "ahb_div",
+ HW_AHBCLKCTRL0, 16 },
+ { CLKID_AHB_UART6, "uart6", "ahb_div",
+ HW_AHBCLKCTRL0, 17 },
+ { CLKID_AHB_UART7, "uart7", "ahb_div",
+ HW_AHBCLKCTRL0, 18 },
+ { CLKID_AHB_UART8, "uart8", "ahb_div",
+ HW_AHBCLKCTRL0, 19 },
+ { CLKID_AHB_UART9, "uart9", "ahb_div",
+ HW_AHBCLKCTRL0, 20 },
+ { CLKID_AHB_I2S0, "i2s0", "ahb_div",
+ HW_AHBCLKCTRL0, 21 },
+ { CLKID_AHB_I2C0, "i2c0", "ahb_div",
+ HW_AHBCLKCTRL0, 22 },
+ { CLKID_AHB_I2C1, "i2c1", "ahb_div",
+ HW_AHBCLKCTRL0, 23 },
+ { CLKID_AHB_SSP0, "ssp0", "ahb_div",
+ HW_AHBCLKCTRL0, 24 },
+ { CLKID_AHB_IOCONFIG, "ioconf", "ahb_div",
+ HW_AHBCLKCTRL0, 25 },
+ { CLKID_AHB_WDT, "wdt", "ahb_div",
+ HW_AHBCLKCTRL0, 26 },
+ { CLKID_AHB_CAN0, "can0", "ahb_div",
+ HW_AHBCLKCTRL0, 27 },
+ { CLKID_AHB_CAN1, "can1", "ahb_div",
+ HW_AHBCLKCTRL0, 28 },
+ { CLKID_AHB_MPWM, "mpwm", "ahb_div",
+ HW_AHBCLKCTRL0, 29 },
+ { CLKID_AHB_SPI0, "spi0", "ahb_div",
+ HW_AHBCLKCTRL0, 30 },
+ { CLKID_AHB_SPI1, "spi1", "ahb_div",
+ HW_AHBCLKCTRL0, 31 },
+
+ { CLKID_AHB_QEI, "qei", "ahb_div",
+ HW_AHBCLKCTRL1, 0 },
+ { CLKID_AHB_QUADSPI0, "quadspi0", "ahb_div",
+ HW_AHBCLKCTRL1, 1 },
+ { CLKID_AHB_CAMIF, "capmif", "ahb_div",
+ HW_AHBCLKCTRL1, 2 },
+ { CLKID_AHB_LCDIF, "lcdif", "ahb_div",
+ HW_AHBCLKCTRL1, 3 },
+ { CLKID_AHB_TIMER0, "timer0", "ahb_div",
+ HW_AHBCLKCTRL1, 4 },
+ { CLKID_AHB_TIMER1, "timer1", "ahb_div",
+ HW_AHBCLKCTRL1, 5 },
+ { CLKID_AHB_TIMER2, "timer2", "ahb_div",
+ HW_AHBCLKCTRL1, 6 },
+ { CLKID_AHB_TIMER3, "timer3", "ahb_div",
+ HW_AHBCLKCTRL1, 7 },
+ { CLKID_AHB_IRQ, "irq", "ahb_div",
+ HW_AHBCLKCTRL1, 8, CLK_IGNORE_UNUSED},
+ { CLKID_AHB_RTC, "rtc", "ahb_div",
+ HW_AHBCLKCTRL1, 9 },
+ { CLKID_AHB_NAND, "nand", "ahb_div",
+ HW_AHBCLKCTRL1, 10 },
+ { CLKID_AHB_ADC0, "adc0", "ahb_div",
+ HW_AHBCLKCTRL1, 11 },
+ { CLKID_AHB_LED, "led", "ahb_div",
+ HW_AHBCLKCTRL1, 12 },
+ { CLKID_AHB_DAC0, "dac0", "ahb_div",
+ HW_AHBCLKCTRL1, 13 },
+ { CLKID_AHB_LCD, "lcd", "ahb_div",
+ HW_AHBCLKCTRL1, 14 },
+ { CLKID_AHB_I2S1, "i2s1", "ahb_div",
+ HW_AHBCLKCTRL1, 15 },
+ { CLKID_AHB_MAC1, "mac1", "ahb_div",
+ HW_AHBCLKCTRL1, 16 },
+};
+
+static const char __initdata *main_mux_p[] = { NULL, NULL };
+static const char __initdata *i2s0_mux_p[] = { NULL, NULL, "i2s0m_div"};
+static const char __initdata *i2s1_mux_p[] = { NULL, NULL, "i2s1m_div"};
+static const char __initdata *clkout_mux_p[] = { NULL, NULL, "rtc"};
+static u32 three_mux_table[] = {0, 1, 3};
+
+static struct asm9260_mux_clock asm9260_mux_clks[] __initdata = {
+ { 1, three_mux_table, "main_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_MAINCLKSEL, },
+ { 1, three_mux_table, "uart_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_UARTCLKSEL, },
+ { 1, three_mux_table, "wdt_mux", main_mux_p,
+ ARRAY_SIZE(main_mux_p), HW_WDTCLKSEL, },
+ { 3, three_mux_table, "i2s0_mux", i2s0_mux_p,
+ ARRAY_SIZE(i2s0_mux_p), HW_I2S0CLKSEL, },
+ { 3, three_mux_table, "i2s1_mux", i2s1_mux_p,
+ ARRAY_SIZE(i2s1_mux_p), HW_I2S1CLKSEL, },
+ { 3, three_mux_table, "clkout_mux", clkout_mux_p,
+ ARRAY_SIZE(clkout_mux_p), HW_CLKOUTCLKSEL, },
+};
+
+static void __init asm9260_acc_init(struct device_node *np)
+{
+ struct clk *clk;
+ const char *ref_clk, *pll_clk = "pll";
+ u32 rate;
+ int n;
+ u32 accuracy = 0;
+
+ base = of_io_request_and_map(np, 0, np->name);
+ if (!base)
+ panic("%s: unable to map resource", np->name);
+
+ /* register pll */
+ rate = (ioread32(base + HW_SYSPLLCTRL) & 0xffff) * 1000000;
+
+ ref_clk = of_clk_get_parent_name(np, 0);
+ accuracy = clk_get_accuracy(__clk_lookup(ref_clk));
+ clk = clk_register_fixed_rate_with_accuracy(NULL, pll_clk,
+ ref_clk, 0, rate, accuracy);
+
+ if (IS_ERR(clk))
+ panic("%s: can't register REFCLK. Check DT!", np->name);
+
+ for (n = 0; n < ARRAY_SIZE(asm9260_mux_clks); n++) {
+ const struct asm9260_mux_clock *mc = &asm9260_mux_clks[n];
+
+ mc->parent_names[0] = ref_clk;
+ mc->parent_names[1] = pll_clk;
+ clk = clk_register_mux_table(NULL, mc->name, mc->parent_names,
+ mc->num_parents, mc->flags, base + mc->offset,
+ 0, mc->mask, 0, mc->table, &asm9260_clk_lock);
+ }
+
+ /* clock mux gate cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_mux_gates); n++) {
+ const struct asm9260_gate_data *gd = &asm9260_mux_gates[n];
+
+ clk = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags | CLK_SET_RATE_PARENT,
+ base + gd->reg, gd->bit_idx, 0, &asm9260_clk_lock);
+ }
+
+ /* clock div cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_div_clks); n++) {
+ const struct asm9260_div_clk *dc = &asm9260_div_clks[n];
+
+ clks[dc->idx] = clk_register_divider(NULL, dc->name,
+ dc->parent_name, CLK_SET_RATE_PARENT,
+ base + dc->reg, 0, 8, CLK_DIVIDER_ONE_BASED,
+ &asm9260_clk_lock);
+ }
+
+ /* clock ahb gate cells */
+ for (n = 0; n < ARRAY_SIZE(asm9260_ahb_gates); n++) {
+ const struct asm9260_gate_data *gd = &asm9260_ahb_gates[n];
+
+ clks[gd->idx] = clk_register_gate(NULL, gd->name,
+ gd->parent_name, gd->flags, base + gd->reg,
+ gd->bit_idx, 0, &asm9260_clk_lock);
+ }
+
+ /* check for errors on leaf clocks */
+ for (n = 0; n < MAX_CLKS; n++) {
+ if (!IS_ERR(clks[n]))
+ continue;
+
+ pr_err("%s: Unable to register leaf clock %d\n",
+ np->full_name, n);
+ goto fail;
+ }
+
+ /* register clk-provider */
+ clk_data.clks = clks;
+ clk_data.clk_num = MAX_CLKS;
+ of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
+ return;
+fail:
+ iounmap(base);
+}
+CLK_OF_DECLARE(asm9260_acc, "alphascale,asm9260-clock-controller",
+ asm9260_acc_init);
diff --git a/drivers/clk/clk-cdce706.c b/drivers/clk/clk-cdce706.c
new file mode 100644
index 000000000000..c386ad25beb4
--- /dev/null
+++ b/drivers/clk/clk-cdce706.c
@@ -0,0 +1,700 @@
+/*
+ * TI CDCE706 programmable 3-PLL clock synthesizer driver
+ *
+ * Copyright (c) 2014 Cadence Design Systems Inc.
+ *
+ * Reference: http://www.ti.com/lit/ds/symlink/cdce706.pdf
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/rational.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define CDCE706_CLKIN_CLOCK 10
+#define CDCE706_CLKIN_SOURCE 11
+#define CDCE706_PLL_M_LOW(pll) (1 + 3 * (pll))
+#define CDCE706_PLL_N_LOW(pll) (2 + 3 * (pll))
+#define CDCE706_PLL_HI(pll) (3 + 3 * (pll))
+#define CDCE706_PLL_MUX 3
+#define CDCE706_PLL_FVCO 6
+#define CDCE706_DIVIDER(div) (13 + (div))
+#define CDCE706_CLKOUT(out) (19 + (out))
+
+#define CDCE706_CLKIN_CLOCK_MASK 0x10
+#define CDCE706_CLKIN_SOURCE_SHIFT 6
+#define CDCE706_CLKIN_SOURCE_MASK 0xc0
+#define CDCE706_CLKIN_SOURCE_LVCMOS 0x40
+
+#define CDCE706_PLL_MUX_MASK(pll) (0x80 >> (pll))
+#define CDCE706_PLL_LOW_M_MASK 0xff
+#define CDCE706_PLL_LOW_N_MASK 0xff
+#define CDCE706_PLL_HI_M_MASK 0x1
+#define CDCE706_PLL_HI_N_MASK 0x1e
+#define CDCE706_PLL_HI_N_SHIFT 1
+#define CDCE706_PLL_M_MAX 0x1ff
+#define CDCE706_PLL_N_MAX 0xfff
+#define CDCE706_PLL_FVCO_MASK(pll) (0x80 >> (pll))
+#define CDCE706_PLL_FREQ_MIN 80000000
+#define CDCE706_PLL_FREQ_MAX 300000000
+#define CDCE706_PLL_FREQ_HI 180000000
+
+#define CDCE706_DIVIDER_PLL(div) (9 + (div) - ((div) > 2) - ((div) > 4))
+#define CDCE706_DIVIDER_PLL_SHIFT(div) ((div) < 2 ? 5 : 3 * ((div) & 1))
+#define CDCE706_DIVIDER_PLL_MASK(div) (0x7 << CDCE706_DIVIDER_PLL_SHIFT(div))
+#define CDCE706_DIVIDER_DIVIDER_MASK 0x7f
+#define CDCE706_DIVIDER_DIVIDER_MAX 0x7f
+
+#define CDCE706_CLKOUT_DIVIDER_MASK 0x7
+#define CDCE706_CLKOUT_ENABLE_MASK 0x8
+
+static struct regmap_config cdce706_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .val_format_endian = REGMAP_ENDIAN_NATIVE,
+};
+
+#define to_hw_data(phw) (container_of((phw), struct cdce706_hw_data, hw))
+
+struct cdce706_hw_data {
+ struct cdce706_dev_data *dev_data;
+ unsigned idx;
+ unsigned parent;
+ struct clk *clk;
+ struct clk_hw hw;
+ unsigned div;
+ unsigned mul;
+ unsigned mux;
+};
+
+struct cdce706_dev_data {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct clk_onecell_data onecell;
+ struct clk *clks[6];
+ struct clk *clkin_clk[2];
+ const char *clkin_name[2];
+ struct cdce706_hw_data clkin[1];
+ struct cdce706_hw_data pll[3];
+ struct cdce706_hw_data divider[6];
+ struct cdce706_hw_data clkout[6];
+};
+
+static const char * const cdce706_source_name[] = {
+ "clk_in0", "clk_in1",
+};
+
+static const char *cdce706_clkin_name[] = {
+ "clk_in",
+};
+
+static const char * const cdce706_pll_name[] = {
+ "pll1", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_parent_name[] = {
+ "clk_in", "pll1", "pll2", "pll2", "pll3",
+};
+
+static const char *cdce706_divider_name[] = {
+ "p0", "p1", "p2", "p3", "p4", "p5",
+};
+
+static const char * const cdce706_clkout_name[] = {
+ "clk_out0", "clk_out1", "clk_out2", "clk_out3", "clk_out4", "clk_out5",
+};
+
+static int cdce706_reg_read(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned *val)
+{
+ int rc = regmap_read(dev_data->regmap, reg | 0x80, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error reading reg %u", reg);
+ return rc;
+}
+
+static int cdce706_reg_write(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned val)
+{
+ int rc = regmap_write(dev_data->regmap, reg | 0x80, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error writing reg %u", reg);
+ return rc;
+}
+
+static int cdce706_reg_update(struct cdce706_dev_data *dev_data, unsigned reg,
+ unsigned mask, unsigned val)
+{
+ int rc = regmap_update_bits(dev_data->regmap, reg | 0x80, mask, val);
+
+ if (rc < 0)
+ dev_err(&dev_data->client->dev, "error updating reg %u", reg);
+ return rc;
+}
+
+static int cdce706_clkin_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ hwd->parent = index;
+ return 0;
+}
+
+static u8 cdce706_clkin_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static const struct clk_ops cdce706_clkin_ops = {
+ .set_parent = cdce706_clkin_set_parent,
+ .get_parent = cdce706_clkin_get_parent,
+};
+
+static unsigned long cdce706_pll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mux: %d, mul: %u, div: %u\n",
+ __func__, hwd->idx, hwd->mux, hwd->mul, hwd->div);
+
+ if (!hwd->mux) {
+ if (hwd->div && hwd->mul) {
+ u64 res = (u64)parent_rate * hwd->mul;
+
+ do_div(res, hwd->div);
+ return res;
+ }
+ } else {
+ if (hwd->div)
+ return parent_rate / hwd->div;
+ }
+ return 0;
+}
+
+static long cdce706_pll_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ unsigned long mul, div;
+ u64 res;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, rate: %lu, parent_rate: %lu\n",
+ __func__, rate, *parent_rate);
+
+ rational_best_approximation(rate, *parent_rate,
+ CDCE706_PLL_N_MAX, CDCE706_PLL_M_MAX,
+ &mul, &div);
+ hwd->mul = mul;
+ hwd->div = div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mul: %lu, div: %lu\n",
+ __func__, hwd->idx, mul, div);
+
+ res = (u64)*parent_rate * hwd->mul;
+ do_div(res, hwd->div);
+ return res;
+}
+
+static int cdce706_pll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ unsigned long mul = hwd->mul, div = hwd->div;
+ int err;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, pll: %d, mul: %lu, div: %lu\n",
+ __func__, hwd->idx, mul, div);
+
+ err = cdce706_reg_update(hwd->dev_data,
+ CDCE706_PLL_HI(hwd->idx),
+ CDCE706_PLL_HI_M_MASK | CDCE706_PLL_HI_N_MASK,
+ ((div >> 8) & CDCE706_PLL_HI_M_MASK) |
+ ((mul >> (8 - CDCE706_PLL_HI_N_SHIFT)) &
+ CDCE706_PLL_HI_N_MASK));
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_write(hwd->dev_data,
+ CDCE706_PLL_M_LOW(hwd->idx),
+ div & CDCE706_PLL_LOW_M_MASK);
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_write(hwd->dev_data,
+ CDCE706_PLL_N_LOW(hwd->idx),
+ mul & CDCE706_PLL_LOW_N_MASK);
+ if (err < 0)
+ return err;
+
+ err = cdce706_reg_update(hwd->dev_data,
+ CDCE706_PLL_FVCO,
+ CDCE706_PLL_FVCO_MASK(hwd->idx),
+ rate > CDCE706_PLL_FREQ_HI ?
+ CDCE706_PLL_FVCO_MASK(hwd->idx) : 0);
+ return err;
+}
+
+static const struct clk_ops cdce706_pll_ops = {
+ .recalc_rate = cdce706_pll_recalc_rate,
+ .round_rate = cdce706_pll_round_rate,
+ .set_rate = cdce706_pll_set_rate,
+};
+
+static int cdce706_divider_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ if (hwd->parent == index)
+ return 0;
+ hwd->parent = index;
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_DIVIDER_PLL(hwd->idx),
+ CDCE706_DIVIDER_PLL_MASK(hwd->idx),
+ index << CDCE706_DIVIDER_PLL_SHIFT(hwd->idx));
+}
+
+static u8 cdce706_divider_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static unsigned long cdce706_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %u\n",
+ __func__, hwd->idx, hwd->div);
+ if (hwd->div)
+ return parent_rate / hwd->div;
+ return 0;
+}
+
+static long cdce706_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+ struct cdce706_dev_data *cdce = hwd->dev_data;
+ unsigned long mul, div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, rate: %lu, parent_rate: %lu\n",
+ __func__, rate, *parent_rate);
+
+ rational_best_approximation(rate, *parent_rate,
+ 1, CDCE706_DIVIDER_DIVIDER_MAX,
+ &mul, &div);
+ if (!mul)
+ div = CDCE706_DIVIDER_DIVIDER_MAX;
+
+ if (__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT) {
+ unsigned long best_diff = rate;
+ unsigned long best_div = 0;
+ struct clk *gp_clk = cdce->clkin_clk[cdce->clkin[0].parent];
+ unsigned long gp_rate = gp_clk ? clk_get_rate(gp_clk) : 0;
+
+ for (div = CDCE706_PLL_FREQ_MIN / rate; best_diff &&
+ div <= CDCE706_PLL_FREQ_MAX / rate; ++div) {
+ unsigned long n, m;
+ unsigned long diff;
+ unsigned long div_rate;
+ u64 div_rate64;
+
+ if (rate * div < CDCE706_PLL_FREQ_MIN)
+ continue;
+
+ rational_best_approximation(rate * div, gp_rate,
+ CDCE706_PLL_N_MAX,
+ CDCE706_PLL_M_MAX,
+ &n, &m);
+ div_rate64 = (u64)gp_rate * n;
+ do_div(div_rate64, m);
+ do_div(div_rate64, div);
+ div_rate = div_rate64;
+ diff = max(div_rate, rate) - min(div_rate, rate);
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ best_div = div;
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, %lu * %lu / %lu / %lu = %lu\n",
+ __func__, gp_rate, n, m, div, div_rate);
+ }
+ }
+
+ div = best_div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, altering parent rate: %lu -> %lu\n",
+ __func__, *parent_rate, rate * div);
+ *parent_rate = rate * div;
+ }
+ hwd->div = div;
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %lu\n",
+ __func__, hwd->idx, div);
+
+ return *parent_rate / div;
+}
+
+static int cdce706_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ dev_dbg(&hwd->dev_data->client->dev,
+ "%s, divider: %d, div: %u\n",
+ __func__, hwd->idx, hwd->div);
+
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_DIVIDER(hwd->idx),
+ CDCE706_DIVIDER_DIVIDER_MASK,
+ hwd->div);
+}
+
+static const struct clk_ops cdce706_divider_ops = {
+ .set_parent = cdce706_divider_set_parent,
+ .get_parent = cdce706_divider_get_parent,
+ .recalc_rate = cdce706_divider_recalc_rate,
+ .round_rate = cdce706_divider_round_rate,
+ .set_rate = cdce706_divider_set_rate,
+};
+
+static int cdce706_clkout_prepare(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK,
+ CDCE706_CLKOUT_ENABLE_MASK);
+}
+
+static void cdce706_clkout_unprepare(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ cdce706_reg_update(hwd->dev_data, CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK, 0);
+}
+
+static int cdce706_clkout_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ if (hwd->parent == index)
+ return 0;
+ hwd->parent = index;
+ return cdce706_reg_update(hwd->dev_data,
+ CDCE706_CLKOUT(hwd->idx),
+ CDCE706_CLKOUT_ENABLE_MASK, index);
+}
+
+static u8 cdce706_clkout_get_parent(struct clk_hw *hw)
+{
+ struct cdce706_hw_data *hwd = to_hw_data(hw);
+
+ return hwd->parent;
+}
+
+static unsigned long cdce706_clkout_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static long cdce706_clkout_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ *parent_rate = rate;
+ return rate;
+}
+
+static int cdce706_clkout_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ return 0;
+}
+
+static const struct clk_ops cdce706_clkout_ops = {
+ .prepare = cdce706_clkout_prepare,
+ .unprepare = cdce706_clkout_unprepare,
+ .set_parent = cdce706_clkout_set_parent,
+ .get_parent = cdce706_clkout_get_parent,
+ .recalc_rate = cdce706_clkout_recalc_rate,
+ .round_rate = cdce706_clkout_round_rate,
+ .set_rate = cdce706_clkout_set_rate,
+};
+
+static int cdce706_register_hw(struct cdce706_dev_data *cdce,
+ struct cdce706_hw_data *hw, unsigned num_hw,
+ const char * const *clk_names,
+ struct clk_init_data *init)
+{
+ unsigned i;
+
+ for (i = 0; i < num_hw; ++i, ++hw) {
+ init->name = clk_names[i];
+ hw->dev_data = cdce;
+ hw->idx = i;
+ hw->hw.init = init;
+ hw->clk = devm_clk_register(&cdce->client->dev,
+ &hw->hw);
+ if (IS_ERR(hw->clk)) {
+ dev_err(&cdce->client->dev, "Failed to register %s\n",
+ clk_names[i]);
+ return PTR_ERR(hw->clk);
+ }
+ }
+ return 0;
+}
+
+static int cdce706_register_clkin(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_clkin_ops,
+ .parent_names = cdce->clkin_name,
+ .num_parents = ARRAY_SIZE(cdce->clkin_name),
+ };
+ unsigned i;
+ int ret;
+ unsigned clock, source;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->clkin_name); ++i) {
+ struct clk *parent = devm_clk_get(&cdce->client->dev,
+ cdce706_source_name[i]);
+
+ if (IS_ERR(parent)) {
+ cdce->clkin_name[i] = cdce706_source_name[i];
+ } else {
+ cdce->clkin_name[i] = __clk_get_name(parent);
+ cdce->clkin_clk[i] = parent;
+ }
+ }
+
+ ret = cdce706_reg_read(cdce, CDCE706_CLKIN_SOURCE, &source);
+ if (ret < 0)
+ return ret;
+ if ((source & CDCE706_CLKIN_SOURCE_MASK) ==
+ CDCE706_CLKIN_SOURCE_LVCMOS) {
+ ret = cdce706_reg_read(cdce, CDCE706_CLKIN_CLOCK, &clock);
+ if (ret < 0)
+ return ret;
+ cdce->clkin[0].parent = !!(clock & CDCE706_CLKIN_CLOCK_MASK);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->clkin,
+ ARRAY_SIZE(cdce->clkin),
+ cdce706_clkin_name, &init);
+ return ret;
+}
+
+static int cdce706_register_plls(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_pll_ops,
+ .parent_names = cdce706_clkin_name,
+ .num_parents = ARRAY_SIZE(cdce706_clkin_name),
+ };
+ unsigned i;
+ int ret;
+ unsigned mux;
+
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_MUX, &mux);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->pll); ++i) {
+ unsigned m, n, v;
+
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_M_LOW(i), &m);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_N_LOW(i), &n);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_reg_read(cdce, CDCE706_PLL_HI(i), &v);
+ if (ret < 0)
+ return ret;
+ cdce->pll[i].div = m | ((v & CDCE706_PLL_HI_M_MASK) << 8);
+ cdce->pll[i].mul = n | ((v & CDCE706_PLL_HI_N_MASK) <<
+ (8 - CDCE706_PLL_HI_N_SHIFT));
+ cdce->pll[i].mux = mux & CDCE706_PLL_MUX_MASK(i);
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, div: %u, mul: %u, mux: %d\n", __func__, i,
+ cdce->pll[i].div, cdce->pll[i].mul, cdce->pll[i].mux);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->pll,
+ ARRAY_SIZE(cdce->pll),
+ cdce706_pll_name, &init);
+ return ret;
+}
+
+static int cdce706_register_dividers(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_divider_ops,
+ .parent_names = cdce706_divider_parent_name,
+ .num_parents = ARRAY_SIZE(cdce706_divider_parent_name),
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ unsigned i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->divider); ++i) {
+ unsigned val;
+
+ ret = cdce706_reg_read(cdce, CDCE706_DIVIDER_PLL(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->divider[i].parent =
+ (val & CDCE706_DIVIDER_PLL_MASK(i)) >>
+ CDCE706_DIVIDER_PLL_SHIFT(i);
+
+ ret = cdce706_reg_read(cdce, CDCE706_DIVIDER(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->divider[i].div = val & CDCE706_DIVIDER_DIVIDER_MASK;
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, parent: %u, div: %u\n", __func__, i,
+ cdce->divider[i].parent, cdce->divider[i].div);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->divider,
+ ARRAY_SIZE(cdce->divider),
+ cdce706_divider_name, &init);
+ return ret;
+}
+
+static int cdce706_register_clkouts(struct cdce706_dev_data *cdce)
+{
+ struct clk_init_data init = {
+ .ops = &cdce706_clkout_ops,
+ .parent_names = cdce706_divider_name,
+ .num_parents = ARRAY_SIZE(cdce706_divider_name),
+ .flags = CLK_SET_RATE_PARENT,
+ };
+ unsigned i;
+ int ret;
+
+ for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i) {
+ unsigned val;
+
+ ret = cdce706_reg_read(cdce, CDCE706_CLKOUT(i), &val);
+ if (ret < 0)
+ return ret;
+ cdce->clkout[i].parent = val & CDCE706_CLKOUT_DIVIDER_MASK;
+ dev_dbg(&cdce->client->dev,
+ "%s: i: %u, parent: %u\n", __func__, i,
+ cdce->clkout[i].parent);
+ }
+
+ ret = cdce706_register_hw(cdce, cdce->clkout,
+ ARRAY_SIZE(cdce->clkout),
+ cdce706_clkout_name, &init);
+ for (i = 0; i < ARRAY_SIZE(cdce->clkout); ++i)
+ cdce->clks[i] = cdce->clkout[i].clk;
+
+ return ret;
+}
+
+static int cdce706_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct cdce706_dev_data *cdce;
+ int ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ cdce = devm_kzalloc(&client->dev, sizeof(*cdce), GFP_KERNEL);
+ if (!cdce)
+ return -ENOMEM;
+
+ cdce->client = client;
+ cdce->regmap = devm_regmap_init_i2c(client, &cdce706_regmap_config);
+ if (IS_ERR(cdce->regmap)) {
+ dev_err(&client->dev, "Failed to initialize regmap\n");
+ return -EINVAL;
+ }
+
+ i2c_set_clientdata(client, cdce);
+
+ ret = cdce706_register_clkin(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_plls(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_dividers(cdce);
+ if (ret < 0)
+ return ret;
+ ret = cdce706_register_clkouts(cdce);
+ if (ret < 0)
+ return ret;
+ cdce->onecell.clks = cdce->clks;
+ cdce->onecell.clk_num = ARRAY_SIZE(cdce->clks);
+ ret = of_clk_add_provider(client->dev.of_node, of_clk_src_onecell_get,
+ &cdce->onecell);
+
+ return ret;
+}
+
+static int cdce706_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+
+#ifdef CONFIG_OF
+static const struct of_device_id cdce706_dt_match[] = {
+ { .compatible = "ti,cdce706" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, cdce706_dt_match);
+#endif
+
+static const struct i2c_device_id cdce706_id[] = {
+ { "cdce706", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cdce706_id);
+
+static struct i2c_driver cdce706_i2c_driver = {
+ .driver = {
+ .name = "cdce706",
+ .of_match_table = of_match_ptr(cdce706_dt_match),
+ },
+ .probe = cdce706_probe,
+ .remove = cdce706_remove,
+ .id_table = cdce706_id,
+};
+module_i2c_driver(cdce706_i2c_driver);
+
+MODULE_AUTHOR("Max Filippov <jcmvbkbc@gmail.com>");
+MODULE_DESCRIPTION("TI CDCE 706 clock synthesizer driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/clk/clk-composite.c b/drivers/clk/clk-composite.c
index 4386697236a7..956b7e54fa1c 100644
--- a/drivers/clk/clk-composite.c
+++ b/drivers/clk/clk-composite.c
@@ -27,7 +27,7 @@ static u8 clk_composite_get_parent(struct clk_hw *hw)
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *mux_hw = composite->mux_hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->get_parent(mux_hw);
}
@@ -38,7 +38,7 @@ static int clk_composite_set_parent(struct clk_hw *hw, u8 index)
const struct clk_ops *mux_ops = composite->mux_ops;
struct clk_hw *mux_hw = composite->mux_hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->set_parent(mux_hw, index);
}
@@ -50,12 +50,14 @@ static unsigned long clk_composite_recalc_rate(struct clk_hw *hw,
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->recalc_rate(rate_hw, parent_rate);
}
static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
@@ -72,8 +74,10 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
int i;
if (rate_hw && rate_ops && rate_ops->determine_rate) {
- rate_hw->clk = hw->clk;
- return rate_ops->determine_rate(rate_hw, rate, best_parent_rate,
+ __clk_hw_set_clk(rate_hw, hw);
+ return rate_ops->determine_rate(rate_hw, rate, min_rate,
+ max_rate,
+ best_parent_rate,
best_parent_p);
} else if (rate_hw && rate_ops && rate_ops->round_rate &&
mux_hw && mux_ops && mux_ops->set_parent) {
@@ -116,8 +120,9 @@ static long clk_composite_determine_rate(struct clk_hw *hw, unsigned long rate,
return best_rate;
} else if (mux_hw && mux_ops && mux_ops->determine_rate) {
- mux_hw->clk = hw->clk;
- return mux_ops->determine_rate(mux_hw, rate, best_parent_rate,
+ __clk_hw_set_clk(mux_hw, hw);
+ return mux_ops->determine_rate(mux_hw, rate, min_rate,
+ max_rate, best_parent_rate,
best_parent_p);
} else {
pr_err("clk: clk_composite_determine_rate function called, but no mux or rate callback set!\n");
@@ -132,7 +137,7 @@ static long clk_composite_round_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->round_rate(rate_hw, rate, prate);
}
@@ -144,7 +149,7 @@ static int clk_composite_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *rate_ops = composite->rate_ops;
struct clk_hw *rate_hw = composite->rate_hw;
- rate_hw->clk = hw->clk;
+ __clk_hw_set_clk(rate_hw, hw);
return rate_ops->set_rate(rate_hw, rate, parent_rate);
}
@@ -155,7 +160,7 @@ static int clk_composite_is_enabled(struct clk_hw *hw)
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->is_enabled(gate_hw);
}
@@ -166,7 +171,7 @@ static int clk_composite_enable(struct clk_hw *hw)
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->enable(gate_hw);
}
@@ -177,7 +182,7 @@ static void clk_composite_disable(struct clk_hw *hw)
const struct clk_ops *gate_ops = composite->gate_ops;
struct clk_hw *gate_hw = composite->gate_hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
gate_ops->disable(gate_hw);
}
diff --git a/drivers/clk/clk-divider.c b/drivers/clk/clk-divider.c
index c0a842b335c5..db7f8bce7467 100644
--- a/drivers/clk/clk-divider.c
+++ b/drivers/clk/clk-divider.c
@@ -30,7 +30,7 @@
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
-#define div_mask(d) ((1 << ((d)->width)) - 1)
+#define div_mask(width) ((1 << (width)) - 1)
static unsigned int _get_table_maxdiv(const struct clk_div_table *table)
{
@@ -54,15 +54,16 @@ static unsigned int _get_table_mindiv(const struct clk_div_table *table)
return mindiv;
}
-static unsigned int _get_maxdiv(struct clk_divider *divider)
+static unsigned int _get_maxdiv(const struct clk_div_table *table, u8 width,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
- return div_mask(divider);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
- return 1 << div_mask(divider);
- if (divider->table)
- return _get_table_maxdiv(divider->table);
- return div_mask(divider) + 1;
+ if (flags & CLK_DIVIDER_ONE_BASED)
+ return div_mask(width);
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
+ return 1 << div_mask(width);
+ if (table)
+ return _get_table_maxdiv(table);
+ return div_mask(width) + 1;
}
static unsigned int _get_table_div(const struct clk_div_table *table,
@@ -76,14 +77,15 @@ static unsigned int _get_table_div(const struct clk_div_table *table,
return 0;
}
-static unsigned int _get_div(struct clk_divider *divider, unsigned int val)
+static unsigned int _get_div(const struct clk_div_table *table,
+ unsigned int val, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return val;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return 1 << val;
- if (divider->table)
- return _get_table_div(divider->table, val);
+ if (table)
+ return _get_table_div(table, val);
return val + 1;
}
@@ -98,29 +100,28 @@ static unsigned int _get_table_val(const struct clk_div_table *table,
return 0;
}
-static unsigned int _get_val(struct clk_divider *divider, unsigned int div)
+static unsigned int _get_val(const struct clk_div_table *table,
+ unsigned int div, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ONE_BASED)
+ if (flags & CLK_DIVIDER_ONE_BASED)
return div;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __ffs(div);
- if (divider->table)
- return _get_table_val(divider->table, div);
+ if (table)
+ return _get_table_val(table, div);
return div - 1;
}
-static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
- unsigned long parent_rate)
+unsigned long divider_recalc_rate(struct clk_hw *hw, unsigned long parent_rate,
+ unsigned int val,
+ const struct clk_div_table *table,
+ unsigned long flags)
{
- struct clk_divider *divider = to_clk_divider(hw);
- unsigned int div, val;
+ unsigned int div;
- val = clk_readl(divider->reg) >> divider->shift;
- val &= div_mask(divider);
-
- div = _get_div(divider, val);
+ div = _get_div(table, val, flags);
if (!div) {
- WARN(!(divider->flags & CLK_DIVIDER_ALLOW_ZERO),
+ WARN(!(flags & CLK_DIVIDER_ALLOW_ZERO),
"%s: Zero divisor and CLK_DIVIDER_ALLOW_ZERO not set\n",
__clk_get_name(hw->clk));
return parent_rate;
@@ -128,6 +129,20 @@ static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
return DIV_ROUND_UP(parent_rate, div);
}
+EXPORT_SYMBOL_GPL(divider_recalc_rate);
+
+static unsigned long clk_divider_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned int val;
+
+ val = clk_readl(divider->reg) >> divider->shift;
+ val &= div_mask(divider->width);
+
+ return divider_recalc_rate(hw, parent_rate, val, divider->table,
+ divider->flags);
+}
/*
* The reverse of DIV_ROUND_UP: The maximum number which
@@ -146,12 +161,13 @@ static bool _is_valid_table_div(const struct clk_div_table *table,
return false;
}
-static bool _is_valid_div(struct clk_divider *divider, unsigned int div)
+static bool _is_valid_div(const struct clk_div_table *table, unsigned int div,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return is_power_of_2(div);
- if (divider->table)
- return _is_valid_table_div(divider->table, div);
+ if (table)
+ return _is_valid_table_div(table, div);
return true;
}
@@ -191,71 +207,76 @@ static int _round_down_table(const struct clk_div_table *table, int div)
return down;
}
-static int _div_round_up(struct clk_divider *divider,
- unsigned long parent_rate, unsigned long rate)
+static int _div_round_up(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
int div = DIV_ROUND_UP(parent_rate, rate);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
div = __roundup_pow_of_two(div);
- if (divider->table)
- div = _round_up_table(divider->table, div);
+ if (table)
+ div = _round_up_table(table, div);
return div;
}
-static int _div_round_closest(struct clk_divider *divider,
- unsigned long parent_rate, unsigned long rate)
+static int _div_round_closest(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
int up, down, div;
up = down = div = DIV_ROUND_CLOSEST(parent_rate, rate);
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO) {
+ if (flags & CLK_DIVIDER_POWER_OF_TWO) {
up = __roundup_pow_of_two(div);
down = __rounddown_pow_of_two(div);
- } else if (divider->table) {
- up = _round_up_table(divider->table, div);
- down = _round_down_table(divider->table, div);
+ } else if (table) {
+ up = _round_up_table(table, div);
+ down = _round_down_table(table, div);
}
return (up - div) <= (div - down) ? up : down;
}
-static int _div_round(struct clk_divider *divider, unsigned long parent_rate,
- unsigned long rate)
+static int _div_round(const struct clk_div_table *table,
+ unsigned long parent_rate, unsigned long rate,
+ unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
- return _div_round_closest(divider, parent_rate, rate);
+ if (flags & CLK_DIVIDER_ROUND_CLOSEST)
+ return _div_round_closest(table, parent_rate, rate, flags);
- return _div_round_up(divider, parent_rate, rate);
+ return _div_round_up(table, parent_rate, rate, flags);
}
-static bool _is_best_div(struct clk_divider *divider,
- unsigned long rate, unsigned long now, unsigned long best)
+static bool _is_best_div(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
{
- if (divider->flags & CLK_DIVIDER_ROUND_CLOSEST)
+ if (flags & CLK_DIVIDER_ROUND_CLOSEST)
return abs(rate - now) < abs(rate - best);
return now <= rate && now > best;
}
-static int _next_div(struct clk_divider *divider, int div)
+static int _next_div(const struct clk_div_table *table, int div,
+ unsigned long flags)
{
div++;
- if (divider->flags & CLK_DIVIDER_POWER_OF_TWO)
+ if (flags & CLK_DIVIDER_POWER_OF_TWO)
return __roundup_pow_of_two(div);
- if (divider->table)
- return _round_up_table(divider->table, div);
+ if (table)
+ return _round_up_table(table, div);
return div;
}
static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate)
+ unsigned long *best_parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
{
- struct clk_divider *divider = to_clk_divider(hw);
int i, bestdiv = 0;
unsigned long parent_rate, best = 0, now, maxdiv;
unsigned long parent_rate_saved = *best_parent_rate;
@@ -263,19 +284,11 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
if (!rate)
rate = 1;
- /* if read only, just return current value */
- if (divider->flags & CLK_DIVIDER_READ_ONLY) {
- bestdiv = readl(divider->reg) >> divider->shift;
- bestdiv &= div_mask(divider);
- bestdiv = _get_div(divider, bestdiv);
- return bestdiv;
- }
-
- maxdiv = _get_maxdiv(divider);
+ maxdiv = _get_maxdiv(table, width, flags);
if (!(__clk_get_flags(hw->clk) & CLK_SET_RATE_PARENT)) {
parent_rate = *best_parent_rate;
- bestdiv = _div_round(divider, parent_rate, rate);
+ bestdiv = _div_round(table, parent_rate, rate, flags);
bestdiv = bestdiv == 0 ? 1 : bestdiv;
bestdiv = bestdiv > maxdiv ? maxdiv : bestdiv;
return bestdiv;
@@ -287,8 +300,8 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
*/
maxdiv = min(ULONG_MAX / rate, maxdiv);
- for (i = 1; i <= maxdiv; i = _next_div(divider, i)) {
- if (!_is_valid_div(divider, i))
+ for (i = 1; i <= maxdiv; i = _next_div(table, i, flags)) {
+ if (!_is_valid_div(table, i, flags))
continue;
if (rate * i == parent_rate_saved) {
/*
@@ -302,7 +315,7 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
parent_rate = __clk_round_rate(__clk_get_parent(hw->clk),
MULT_ROUND_UP(rate, i));
now = DIV_ROUND_UP(parent_rate, i);
- if (_is_best_div(divider, rate, now, best)) {
+ if (_is_best_div(rate, now, best, flags)) {
bestdiv = i;
best = now;
*best_parent_rate = parent_rate;
@@ -310,48 +323,79 @@ static int clk_divider_bestdiv(struct clk_hw *hw, unsigned long rate,
}
if (!bestdiv) {
- bestdiv = _get_maxdiv(divider);
+ bestdiv = _get_maxdiv(table, width, flags);
*best_parent_rate = __clk_round_rate(__clk_get_parent(hw->clk), 1);
}
return bestdiv;
}
-static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *prate)
+long divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate, const struct clk_div_table *table,
+ u8 width, unsigned long flags)
{
int div;
- div = clk_divider_bestdiv(hw, rate, prate);
+
+ div = clk_divider_bestdiv(hw, rate, prate, table, width, flags);
return DIV_ROUND_UP(*prate, div);
}
+EXPORT_SYMBOL_GPL(divider_round_rate);
-static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
+static long clk_divider_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
{
struct clk_divider *divider = to_clk_divider(hw);
+ int bestdiv;
+
+ /* if read only, just return current value */
+ if (divider->flags & CLK_DIVIDER_READ_ONLY) {
+ bestdiv = readl(divider->reg) >> divider->shift;
+ bestdiv &= div_mask(divider->width);
+ bestdiv = _get_div(divider->table, bestdiv, divider->flags);
+ return bestdiv;
+ }
+
+ return divider_round_rate(hw, rate, prate, divider->table,
+ divider->width, divider->flags);
+}
+
+int divider_get_val(unsigned long rate, unsigned long parent_rate,
+ const struct clk_div_table *table, u8 width,
+ unsigned long flags)
+{
unsigned int div, value;
- unsigned long flags = 0;
- u32 val;
div = DIV_ROUND_UP(parent_rate, rate);
- if (!_is_valid_div(divider, div))
+ if (!_is_valid_div(table, div, flags))
return -EINVAL;
- value = _get_val(divider, div);
+ value = _get_val(table, div, flags);
+
+ return min_t(unsigned int, value, div_mask(width));
+}
+EXPORT_SYMBOL_GPL(divider_get_val);
+
+static int clk_divider_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_divider *divider = to_clk_divider(hw);
+ unsigned int value;
+ unsigned long flags = 0;
+ u32 val;
- if (value > div_mask(divider))
- value = div_mask(divider);
+ value = divider_get_val(rate, parent_rate, divider->table,
+ divider->width, divider->flags);
if (divider->lock)
spin_lock_irqsave(divider->lock, flags);
if (divider->flags & CLK_DIVIDER_HIWORD_MASK) {
- val = div_mask(divider) << (divider->shift + 16);
+ val = div_mask(divider->width) << (divider->shift + 16);
} else {
val = clk_readl(divider->reg);
- val &= ~(div_mask(divider) << divider->shift);
+ val &= ~(div_mask(divider->width) << divider->shift);
}
val |= value << divider->shift;
clk_writel(val, divider->reg);
@@ -463,3 +507,19 @@ struct clk *clk_register_divider_table(struct device *dev, const char *name,
width, clk_divider_flags, table, lock);
}
EXPORT_SYMBOL_GPL(clk_register_divider_table);
+
+void clk_unregister_divider(struct clk *clk)
+{
+ struct clk_divider *div;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ div = to_clk_divider(hw);
+
+ clk_unregister(clk);
+ kfree(div);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_divider);
diff --git a/drivers/clk/clk-gate.c b/drivers/clk/clk-gate.c
index 51fd87fb7ba6..3f0e4200cb5d 100644
--- a/drivers/clk/clk-gate.c
+++ b/drivers/clk/clk-gate.c
@@ -128,7 +128,7 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
struct clk_init_data init;
if (clk_gate_flags & CLK_GATE_HIWORD_MASK) {
- if (bit_idx > 16) {
+ if (bit_idx > 15) {
pr_err("gate bit exceeds LOWORD field\n");
return ERR_PTR(-EINVAL);
}
@@ -162,3 +162,19 @@ struct clk *clk_register_gate(struct device *dev, const char *name,
return clk;
}
EXPORT_SYMBOL_GPL(clk_register_gate);
+
+void clk_unregister_gate(struct clk *clk)
+{
+ struct clk_gate *gate;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ gate = to_clk_gate(hw);
+
+ clk_unregister(clk);
+ kfree(gate);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_gate);
diff --git a/drivers/clk/clk-mux.c b/drivers/clk/clk-mux.c
index 6e1ecf94bf58..69a094c3783d 100644
--- a/drivers/clk/clk-mux.c
+++ b/drivers/clk/clk-mux.c
@@ -177,3 +177,19 @@ struct clk *clk_register_mux(struct device *dev, const char *name,
NULL, lock);
}
EXPORT_SYMBOL_GPL(clk_register_mux);
+
+void clk_unregister_mux(struct clk *clk)
+{
+ struct clk_mux *mux;
+ struct clk_hw *hw;
+
+ hw = __clk_get_hw(clk);
+ if (!hw)
+ return;
+
+ mux = to_clk_mux(hw);
+
+ clk_unregister(clk);
+ kfree(mux);
+}
+EXPORT_SYMBOL_GPL(clk_unregister_mux);
diff --git a/drivers/clk/clk-ppc-corenet.c b/drivers/clk/clk-ppc-corenet.c
deleted file mode 100644
index 0a47d6f49cd6..000000000000
--- a/drivers/clk/clk-ppc-corenet.c
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright 2013 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * clock driver for Freescale PowerPC corenet SoCs.
- */
-#include <linux/clk-provider.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/of_platform.h>
-#include <linux/of.h>
-#include <linux/slab.h>
-
-struct cmux_clk {
- struct clk_hw hw;
- void __iomem *reg;
- u32 flags;
-};
-
-#define PLL_KILL BIT(31)
-#define CLKSEL_SHIFT 27
-#define CLKSEL_ADJUST BIT(0)
-#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
-
-static unsigned int clocks_per_pll;
-
-static int cmux_set_parent(struct clk_hw *hw, u8 idx)
-{
- struct cmux_clk *clk = to_cmux_clk(hw);
- u32 clksel;
-
- clksel = ((idx / clocks_per_pll) << 2) + idx % clocks_per_pll;
- if (clk->flags & CLKSEL_ADJUST)
- clksel += 8;
- clksel = (clksel & 0xf) << CLKSEL_SHIFT;
- iowrite32be(clksel, clk->reg);
-
- return 0;
-}
-
-static u8 cmux_get_parent(struct clk_hw *hw)
-{
- struct cmux_clk *clk = to_cmux_clk(hw);
- u32 clksel;
-
- clksel = ioread32be(clk->reg);
- clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
- if (clk->flags & CLKSEL_ADJUST)
- clksel -= 8;
- clksel = (clksel >> 2) * clocks_per_pll + clksel % 4;
-
- return clksel;
-}
-
-const struct clk_ops cmux_ops = {
- .get_parent = cmux_get_parent,
- .set_parent = cmux_set_parent,
-};
-
-static void __init core_mux_init(struct device_node *np)
-{
- struct clk *clk;
- struct clk_init_data init;
- struct cmux_clk *cmux_clk;
- struct device_node *node;
- int rc, count, i;
- u32 offset;
- const char *clk_name;
- const char **parent_names;
-
- rc = of_property_read_u32(np, "reg", &offset);
- if (rc) {
- pr_err("%s: could not get reg property\n", np->name);
- return;
- }
-
- /* get the input clock source count */
- count = of_property_count_strings(np, "clock-names");
- if (count < 0) {
- pr_err("%s: get clock count error\n", np->name);
- return;
- }
- parent_names = kzalloc((sizeof(char *) * count), GFP_KERNEL);
- if (!parent_names) {
- pr_err("%s: could not allocate parent_names\n", __func__);
- return;
- }
-
- for (i = 0; i < count; i++)
- parent_names[i] = of_clk_get_parent_name(np, i);
-
- cmux_clk = kzalloc(sizeof(struct cmux_clk), GFP_KERNEL);
- if (!cmux_clk) {
- pr_err("%s: could not allocate cmux_clk\n", __func__);
- goto err_name;
- }
- cmux_clk->reg = of_iomap(np, 0);
- if (!cmux_clk->reg) {
- pr_err("%s: could not map register\n", __func__);
- goto err_clk;
- }
-
- node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
- if (node && (offset >= 0x80))
- cmux_clk->flags = CLKSEL_ADJUST;
-
- rc = of_property_read_string_index(np, "clock-output-names",
- 0, &clk_name);
- if (rc) {
- pr_err("%s: read clock names error\n", np->name);
- goto err_clk;
- }
-
- init.name = clk_name;
- init.ops = &cmux_ops;
- init.parent_names = parent_names;
- init.num_parents = count;
- init.flags = 0;
- cmux_clk->hw.init = &init;
-
- clk = clk_register(NULL, &cmux_clk->hw);
- if (IS_ERR(clk)) {
- pr_err("%s: could not register clock\n", clk_name);
- goto err_clk;
- }
-
- rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
- if (rc) {
- pr_err("Could not register clock provider for node:%s\n",
- np->name);
- goto err_clk;
- }
- goto err_name;
-
-err_clk:
- kfree(cmux_clk);
-err_name:
- /* free *_names because they are reallocated when registered */
- kfree(parent_names);
-}
-
-static void __init core_pll_init(struct device_node *np)
-{
- u32 mult;
- int i, rc, count;
- const char *clk_name, *parent_name;
- struct clk_onecell_data *onecell_data;
- struct clk **subclks;
- void __iomem *base;
-
- base = of_iomap(np, 0);
- if (!base) {
- pr_err("clk-ppc: iomap error\n");
- return;
- }
-
- /* get the multiple of PLL */
- mult = ioread32be(base);
-
- /* check if this PLL is disabled */
- if (mult & PLL_KILL) {
- pr_debug("PLL:%s is disabled\n", np->name);
- goto err_map;
- }
- mult = (mult >> 1) & 0x3f;
-
- parent_name = of_clk_get_parent_name(np, 0);
- if (!parent_name) {
- pr_err("PLL: %s must have a parent\n", np->name);
- goto err_map;
- }
-
- count = of_property_count_strings(np, "clock-output-names");
- if (count < 0 || count > 4) {
- pr_err("%s: clock is not supported\n", np->name);
- goto err_map;
- }
-
- /* output clock number per PLL */
- clocks_per_pll = count;
-
- subclks = kzalloc(sizeof(struct clk *) * count, GFP_KERNEL);
- if (!subclks) {
- pr_err("%s: could not allocate subclks\n", __func__);
- goto err_map;
- }
-
- onecell_data = kzalloc(sizeof(struct clk_onecell_data), GFP_KERNEL);
- if (!onecell_data) {
- pr_err("%s: could not allocate onecell_data\n", __func__);
- goto err_clks;
- }
-
- for (i = 0; i < count; i++) {
- rc = of_property_read_string_index(np, "clock-output-names",
- i, &clk_name);
- if (rc) {
- pr_err("%s: could not get clock names\n", np->name);
- goto err_cell;
- }
-
- /*
- * when count == 4, there are 4 output clocks:
- * /1, /2, /3, /4 respectively
- * when count < 4, there are at least 2 output clocks:
- * /1, /2, (/4, if count == 3) respectively.
- */
- if (count == 4)
- subclks[i] = clk_register_fixed_factor(NULL, clk_name,
- parent_name, 0, mult, 1 + i);
- else
-
- subclks[i] = clk_register_fixed_factor(NULL, clk_name,
- parent_name, 0, mult, 1 << i);
-
- if (IS_ERR(subclks[i])) {
- pr_err("%s: could not register clock\n", clk_name);
- goto err_cell;
- }
- }
-
- onecell_data->clks = subclks;
- onecell_data->clk_num = count;
-
- rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
- if (rc) {
- pr_err("Could not register clk provider for node:%s\n",
- np->name);
- goto err_cell;
- }
-
- iounmap(base);
- return;
-err_cell:
- kfree(onecell_data);
-err_clks:
- kfree(subclks);
-err_map:
- iounmap(base);
-}
-
-static void __init sysclk_init(struct device_node *node)
-{
- struct clk *clk;
- const char *clk_name = node->name;
- struct device_node *np = of_get_parent(node);
- u32 rate;
-
- if (!np) {
- pr_err("ppc-clk: could not get parent node\n");
- return;
- }
-
- if (of_property_read_u32(np, "clock-frequency", &rate)) {
- of_node_put(node);
- return;
- }
-
- of_property_read_string(np, "clock-output-names", &clk_name);
-
- clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
- if (!IS_ERR(clk))
- of_clk_add_provider(np, of_clk_src_simple_get, clk);
-}
-
-static const struct of_device_id clk_match[] __initconst = {
- { .compatible = "fsl,qoriq-sysclk-1.0", .data = sysclk_init, },
- { .compatible = "fsl,qoriq-sysclk-2.0", .data = sysclk_init, },
- { .compatible = "fsl,qoriq-core-pll-1.0", .data = core_pll_init, },
- { .compatible = "fsl,qoriq-core-pll-2.0", .data = core_pll_init, },
- { .compatible = "fsl,qoriq-core-mux-1.0", .data = core_mux_init, },
- { .compatible = "fsl,qoriq-core-mux-2.0", .data = core_mux_init, },
- {}
-};
-
-static int __init ppc_corenet_clk_probe(struct platform_device *pdev)
-{
- of_clk_init(clk_match);
-
- return 0;
-}
-
-static const struct of_device_id ppc_clk_ids[] __initconst = {
- { .compatible = "fsl,qoriq-clockgen-1.0", },
- { .compatible = "fsl,qoriq-clockgen-2.0", },
- {}
-};
-
-static struct platform_driver ppc_corenet_clk_driver = {
- .driver = {
- .name = "ppc_corenet_clock",
- .of_match_table = ppc_clk_ids,
- },
- .probe = ppc_corenet_clk_probe,
-};
-
-static int __init ppc_corenet_clk_init(void)
-{
- return platform_driver_register(&ppc_corenet_clk_driver);
-}
-subsys_initcall(ppc_corenet_clk_init);
diff --git a/drivers/clk/clk-qoriq.c b/drivers/clk/clk-qoriq.c
new file mode 100644
index 000000000000..cda90a971e39
--- /dev/null
+++ b/drivers/clk/clk-qoriq.c
@@ -0,0 +1,362 @@
+/*
+ * Copyright 2013 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * clock driver for Freescale QorIQ SoCs.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+struct cmux_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+ unsigned int clk_per_pll;
+ u32 flags;
+};
+
+#define PLL_KILL BIT(31)
+#define CLKSEL_SHIFT 27
+#define CLKSEL_ADJUST BIT(0)
+#define to_cmux_clk(p) container_of(p, struct cmux_clk, hw)
+
+static int cmux_set_parent(struct clk_hw *hw, u8 idx)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ((idx / clk->clk_per_pll) << 2) + idx % clk->clk_per_pll;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel += 8;
+ clksel = (clksel & 0xf) << CLKSEL_SHIFT;
+ iowrite32be(clksel, clk->reg);
+
+ return 0;
+}
+
+static u8 cmux_get_parent(struct clk_hw *hw)
+{
+ struct cmux_clk *clk = to_cmux_clk(hw);
+ u32 clksel;
+
+ clksel = ioread32be(clk->reg);
+ clksel = (clksel >> CLKSEL_SHIFT) & 0xf;
+ if (clk->flags & CLKSEL_ADJUST)
+ clksel -= 8;
+ clksel = (clksel >> 2) * clk->clk_per_pll + clksel % 4;
+
+ return clksel;
+}
+
+static const struct clk_ops cmux_ops = {
+ .get_parent = cmux_get_parent,
+ .set_parent = cmux_set_parent,
+};
+
+static void __init core_mux_init(struct device_node *np)
+{
+ struct clk *clk;
+ struct clk_init_data init;
+ struct cmux_clk *cmux_clk;
+ struct device_node *node;
+ int rc, count, i;
+ u32 offset;
+ const char *clk_name;
+ const char **parent_names;
+ struct of_phandle_args clkspec;
+
+ rc = of_property_read_u32(np, "reg", &offset);
+ if (rc) {
+ pr_err("%s: could not get reg property\n", np->name);
+ return;
+ }
+
+ /* get the input clock source count */
+ count = of_property_count_strings(np, "clock-names");
+ if (count < 0) {
+ pr_err("%s: get clock count error\n", np->name);
+ return;
+ }
+ parent_names = kcalloc(count, sizeof(char *), GFP_KERNEL);
+ if (!parent_names)
+ return;
+
+ for (i = 0; i < count; i++)
+ parent_names[i] = of_clk_get_parent_name(np, i);
+
+ cmux_clk = kzalloc(sizeof(*cmux_clk), GFP_KERNEL);
+ if (!cmux_clk)
+ goto err_name;
+
+ cmux_clk->reg = of_iomap(np, 0);
+ if (!cmux_clk->reg) {
+ pr_err("%s: could not map register\n", __func__);
+ goto err_clk;
+ }
+
+ rc = of_parse_phandle_with_args(np, "clocks", "#clock-cells", 0,
+ &clkspec);
+ if (rc) {
+ pr_err("%s: parse clock node error\n", __func__);
+ goto err_clk;
+ }
+
+ cmux_clk->clk_per_pll = of_property_count_strings(clkspec.np,
+ "clock-output-names");
+ of_node_put(clkspec.np);
+
+ node = of_find_compatible_node(NULL, NULL, "fsl,p4080-clockgen");
+ if (node && (offset >= 0x80))
+ cmux_clk->flags = CLKSEL_ADJUST;
+
+ rc = of_property_read_string_index(np, "clock-output-names",
+ 0, &clk_name);
+ if (rc) {
+ pr_err("%s: read clock names error\n", np->name);
+ goto err_clk;
+ }
+
+ init.name = clk_name;
+ init.ops = &cmux_ops;
+ init.parent_names = parent_names;
+ init.num_parents = count;
+ init.flags = 0;
+ cmux_clk->hw.init = &init;
+
+ clk = clk_register(NULL, &cmux_clk->hw);
+ if (IS_ERR(clk)) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_clk;
+ }
+
+ rc = of_clk_add_provider(np, of_clk_src_simple_get, clk);
+ if (rc) {
+ pr_err("Could not register clock provider for node:%s\n",
+ np->name);
+ goto err_clk;
+ }
+ goto err_name;
+
+err_clk:
+ kfree(cmux_clk);
+err_name:
+ /* free *_names because they are reallocated when registered */
+ kfree(parent_names);
+}
+
+static void __init core_pll_init(struct device_node *np)
+{
+ u32 mult;
+ int i, rc, count;
+ const char *clk_name, *parent_name;
+ struct clk_onecell_data *onecell_data;
+ struct clk **subclks;
+ void __iomem *base;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("iomap error\n");
+ return;
+ }
+
+ /* get the multiple of PLL */
+ mult = ioread32be(base);
+
+ /* check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("PLL:%s is disabled\n", np->name);
+ goto err_map;
+ }
+ mult = (mult >> 1) & 0x3f;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("PLL: %s must have a parent\n", np->name);
+ goto err_map;
+ }
+
+ count = of_property_count_strings(np, "clock-output-names");
+ if (count < 0 || count > 4) {
+ pr_err("%s: clock is not supported\n", np->name);
+ goto err_map;
+ }
+
+ subclks = kcalloc(count, sizeof(struct clk *), GFP_KERNEL);
+ if (!subclks)
+ goto err_map;
+
+ onecell_data = kmalloc(sizeof(*onecell_data), GFP_KERNEL);
+ if (!onecell_data)
+ goto err_clks;
+
+ for (i = 0; i < count; i++) {
+ rc = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (rc) {
+ pr_err("%s: could not get clock names\n", np->name);
+ goto err_cell;
+ }
+
+ /*
+ * when count == 4, there are 4 output clocks:
+ * /1, /2, /3, /4 respectively
+ * when count < 4, there are at least 2 output clocks:
+ * /1, /2, (/4, if count == 3) respectively.
+ */
+ if (count == 4)
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ else
+
+ subclks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 << i);
+
+ if (IS_ERR(subclks[i])) {
+ pr_err("%s: could not register clock\n", clk_name);
+ goto err_cell;
+ }
+ }
+
+ onecell_data->clks = subclks;
+ onecell_data->clk_num = count;
+
+ rc = of_clk_add_provider(np, of_clk_src_onecell_get, onecell_data);
+ if (rc) {
+ pr_err("Could not register clk provider for node:%s\n",
+ np->name);
+ goto err_cell;
+ }
+
+ iounmap(base);
+ return;
+err_cell:
+ kfree(onecell_data);
+err_clks:
+ kfree(subclks);
+err_map:
+ iounmap(base);
+}
+
+static void __init sysclk_init(struct device_node *node)
+{
+ struct clk *clk;
+ const char *clk_name = node->name;
+ struct device_node *np = of_get_parent(node);
+ u32 rate;
+
+ if (!np) {
+ pr_err("could not get parent node\n");
+ return;
+ }
+
+ if (of_property_read_u32(np, "clock-frequency", &rate)) {
+ of_node_put(node);
+ return;
+ }
+
+ of_property_read_string(np, "clock-output-names", &clk_name);
+
+ clk = clk_register_fixed_rate(NULL, clk_name, NULL, CLK_IS_ROOT, rate);
+ if (!IS_ERR(clk))
+ of_clk_add_provider(np, of_clk_src_simple_get, clk);
+}
+
+static void __init pltfrm_pll_init(struct device_node *np)
+{
+ void __iomem *base;
+ uint32_t mult;
+ const char *parent_name, *clk_name;
+ int i, _errno;
+ struct clk_onecell_data *cod;
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ pr_err("%s(): %s: of_iomap() failed\n", __func__, np->name);
+ return;
+ }
+
+ /* Get the multiple of PLL */
+ mult = ioread32be(base);
+
+ iounmap(base);
+
+ /* Check if this PLL is disabled */
+ if (mult & PLL_KILL) {
+ pr_debug("%s(): %s: Disabled\n", __func__, np->name);
+ return;
+ }
+ mult = (mult & GENMASK(6, 1)) >> 1;
+
+ parent_name = of_clk_get_parent_name(np, 0);
+ if (!parent_name) {
+ pr_err("%s(): %s: of_clk_get_parent_name() failed\n",
+ __func__, np->name);
+ return;
+ }
+
+ i = of_property_count_strings(np, "clock-output-names");
+ if (i < 0) {
+ pr_err("%s(): %s: of_property_count_strings(clock-output-names) = %d\n",
+ __func__, np->name, i);
+ return;
+ }
+
+ cod = kmalloc(sizeof(*cod) + i * sizeof(struct clk *), GFP_KERNEL);
+ if (!cod)
+ return;
+ cod->clks = (struct clk **)(cod + 1);
+ cod->clk_num = i;
+
+ for (i = 0; i < cod->clk_num; i++) {
+ _errno = of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+ if (_errno < 0) {
+ pr_err("%s(): %s: of_property_read_string_index(clock-output-names) = %d\n",
+ __func__, np->name, _errno);
+ goto return_clk_unregister;
+ }
+
+ cod->clks[i] = clk_register_fixed_factor(NULL, clk_name,
+ parent_name, 0, mult, 1 + i);
+ if (IS_ERR(cod->clks[i])) {
+ pr_err("%s(): %s: clk_register_fixed_factor(%s) = %ld\n",
+ __func__, np->name,
+ clk_name, PTR_ERR(cod->clks[i]));
+ goto return_clk_unregister;
+ }
+ }
+
+ _errno = of_clk_add_provider(np, of_clk_src_onecell_get, cod);
+ if (_errno < 0) {
+ pr_err("%s(): %s: of_clk_add_provider() = %d\n",
+ __func__, np->name, _errno);
+ goto return_clk_unregister;
+ }
+
+ return;
+
+return_clk_unregister:
+ while (--i >= 0)
+ clk_unregister(cod->clks[i]);
+ kfree(cod);
+}
+
+CLK_OF_DECLARE(qoriq_sysclk_1, "fsl,qoriq-sysclk-1.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_sysclk_2, "fsl,qoriq-sysclk-2.0", sysclk_init);
+CLK_OF_DECLARE(qoriq_core_pll_1, "fsl,qoriq-core-pll-1.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_pll_2, "fsl,qoriq-core-pll-2.0", core_pll_init);
+CLK_OF_DECLARE(qoriq_core_mux_1, "fsl,qoriq-core-mux-1.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_core_mux_2, "fsl,qoriq-core-mux-2.0", core_mux_init);
+CLK_OF_DECLARE(qoriq_pltfrm_pll_1, "fsl,qoriq-platform-pll-1.0", pltfrm_pll_init);
+CLK_OF_DECLARE(qoriq_pltfrm_pll_2, "fsl,qoriq-platform-pll-2.0", pltfrm_pll_init);
diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index d48ac71c6c8b..eb0152961d3c 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -9,7 +9,7 @@
* Standard functionality for the common clock API. See Documentation/clk.txt
*/
-#include <linux/clk-private.h>
+#include <linux/clk-provider.h>
#include <linux/clk/clk-conf.h>
#include <linux/module.h>
#include <linux/mutex.h>
@@ -37,6 +37,55 @@ static HLIST_HEAD(clk_root_list);
static HLIST_HEAD(clk_orphan_list);
static LIST_HEAD(clk_notifier_list);
+static long clk_core_get_accuracy(struct clk_core *clk);
+static unsigned long clk_core_get_rate(struct clk_core *clk);
+static int clk_core_get_phase(struct clk_core *clk);
+static bool clk_core_is_prepared(struct clk_core *clk);
+static bool clk_core_is_enabled(struct clk_core *clk);
+static struct clk_core *clk_core_lookup(const char *name);
+
+/*** private data structures ***/
+
+struct clk_core {
+ const char *name;
+ const struct clk_ops *ops;
+ struct clk_hw *hw;
+ struct module *owner;
+ struct clk_core *parent;
+ const char **parent_names;
+ struct clk_core **parents;
+ u8 num_parents;
+ u8 new_parent_index;
+ unsigned long rate;
+ unsigned long req_rate;
+ unsigned long new_rate;
+ struct clk_core *new_parent;
+ struct clk_core *new_child;
+ unsigned long flags;
+ unsigned int enable_count;
+ unsigned int prepare_count;
+ unsigned long accuracy;
+ int phase;
+ struct hlist_head children;
+ struct hlist_node child_node;
+ struct hlist_node debug_node;
+ struct hlist_head clks;
+ unsigned int notifier_count;
+#ifdef CONFIG_DEBUG_FS
+ struct dentry *dentry;
+#endif
+ struct kref ref;
+};
+
+struct clk {
+ struct clk_core *core;
+ const char *dev_id;
+ const char *con_id;
+ unsigned long min_rate;
+ unsigned long max_rate;
+ struct hlist_node child_node;
+};
+
/*** locking ***/
static void clk_prepare_lock(void)
{
@@ -114,7 +163,8 @@ static struct hlist_head *orphan_list[] = {
NULL,
};
-static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
+static void clk_summary_show_one(struct seq_file *s, struct clk_core *c,
+ int level)
{
if (!c)
return;
@@ -122,14 +172,14 @@ static void clk_summary_show_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "%*s%-*s %11d %12d %11lu %10lu %-3d\n",
level * 3 + 1, "",
30 - level * 3, c->name,
- c->enable_count, c->prepare_count, clk_get_rate(c),
- clk_get_accuracy(c), clk_get_phase(c));
+ c->enable_count, c->prepare_count, clk_core_get_rate(c),
+ clk_core_get_accuracy(c), clk_core_get_phase(c));
}
-static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
+static void clk_summary_show_subtree(struct seq_file *s, struct clk_core *c,
int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -142,7 +192,7 @@ static void clk_summary_show_subtree(struct seq_file *s, struct clk *c,
static int clk_summary_show(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
struct hlist_head **lists = (struct hlist_head **)s->private;
seq_puts(s, " clock enable_cnt prepare_cnt rate accuracy phase\n");
@@ -172,7 +222,7 @@ static const struct file_operations clk_summary_fops = {
.release = single_release,
};
-static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_one(struct seq_file *s, struct clk_core *c, int level)
{
if (!c)
return;
@@ -180,14 +230,14 @@ static void clk_dump_one(struct seq_file *s, struct clk *c, int level)
seq_printf(s, "\"%s\": { ", c->name);
seq_printf(s, "\"enable_count\": %d,", c->enable_count);
seq_printf(s, "\"prepare_count\": %d,", c->prepare_count);
- seq_printf(s, "\"rate\": %lu", clk_get_rate(c));
- seq_printf(s, "\"accuracy\": %lu", clk_get_accuracy(c));
- seq_printf(s, "\"phase\": %d", clk_get_phase(c));
+ seq_printf(s, "\"rate\": %lu", clk_core_get_rate(c));
+ seq_printf(s, "\"accuracy\": %lu", clk_core_get_accuracy(c));
+ seq_printf(s, "\"phase\": %d", clk_core_get_phase(c));
}
-static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
+static void clk_dump_subtree(struct seq_file *s, struct clk_core *c, int level)
{
- struct clk *child;
+ struct clk_core *child;
if (!c)
return;
@@ -204,7 +254,7 @@ static void clk_dump_subtree(struct seq_file *s, struct clk *c, int level)
static int clk_dump(struct seq_file *s, void *data)
{
- struct clk *c;
+ struct clk_core *c;
bool first_node = true;
struct hlist_head **lists = (struct hlist_head **)s->private;
@@ -240,7 +290,7 @@ static const struct file_operations clk_dump_fops = {
.release = single_release,
};
-static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry)
+static int clk_debug_create_one(struct clk_core *clk, struct dentry *pdentry)
{
struct dentry *d;
int ret = -ENOMEM;
@@ -315,7 +365,7 @@ out:
* initialized. Otherwise it bails out early since the debugfs clk tree
* will be created lazily by clk_debug_init as part of a late_initcall.
*/
-static int clk_debug_register(struct clk *clk)
+static int clk_debug_register(struct clk_core *clk)
{
int ret = 0;
@@ -340,16 +390,12 @@ unlock:
* debugfs clk tree if clk->dentry points to debugfs created by
* clk_debug_register in __clk_init.
*/
-static void clk_debug_unregister(struct clk *clk)
+static void clk_debug_unregister(struct clk_core *clk)
{
mutex_lock(&clk_debug_lock);
- if (!clk->dentry)
- goto out;
-
hlist_del_init(&clk->debug_node);
debugfs_remove_recursive(clk->dentry);
clk->dentry = NULL;
-out:
mutex_unlock(&clk_debug_lock);
}
@@ -358,8 +404,9 @@ struct dentry *clk_debugfs_add_file(struct clk_hw *hw, char *name, umode_t mode,
{
struct dentry *d = NULL;
- if (hw->clk->dentry)
- d = debugfs_create_file(name, mode, hw->clk->dentry, data, fops);
+ if (hw->core->dentry)
+ d = debugfs_create_file(name, mode, hw->core->dentry, data,
+ fops);
return d;
}
@@ -379,7 +426,7 @@ EXPORT_SYMBOL_GPL(clk_debugfs_add_file);
*/
static int __init clk_debug_init(void)
{
- struct clk *clk;
+ struct clk_core *clk;
struct dentry *d;
rootdir = debugfs_create_dir("clk", NULL);
@@ -418,22 +465,20 @@ static int __init clk_debug_init(void)
}
late_initcall(clk_debug_init);
#else
-static inline int clk_debug_register(struct clk *clk) { return 0; }
-static inline void clk_debug_reparent(struct clk *clk, struct clk *new_parent)
+static inline int clk_debug_register(struct clk_core *clk) { return 0; }
+static inline void clk_debug_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
}
-static inline void clk_debug_unregister(struct clk *clk)
+static inline void clk_debug_unregister(struct clk_core *clk)
{
}
#endif
/* caller must hold prepare_lock */
-static void clk_unprepare_unused_subtree(struct clk *clk)
+static void clk_unprepare_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
-
- if (!clk)
- return;
+ struct clk_core *child;
hlist_for_each_entry(child, &clk->children, child_node)
clk_unprepare_unused_subtree(child);
@@ -444,7 +489,7 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
if (clk->flags & CLK_IGNORE_UNUSED)
return;
- if (__clk_is_prepared(clk)) {
+ if (clk_core_is_prepared(clk)) {
if (clk->ops->unprepare_unused)
clk->ops->unprepare_unused(clk->hw);
else if (clk->ops->unprepare)
@@ -453,14 +498,11 @@ static void clk_unprepare_unused_subtree(struct clk *clk)
}
/* caller must hold prepare_lock */
-static void clk_disable_unused_subtree(struct clk *clk)
+static void clk_disable_unused_subtree(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long flags;
- if (!clk)
- goto out;
-
hlist_for_each_entry(child, &clk->children, child_node)
clk_disable_unused_subtree(child);
@@ -477,7 +519,7 @@ static void clk_disable_unused_subtree(struct clk *clk)
* sequence. call .disable_unused if available, otherwise fall
* back to .disable
*/
- if (__clk_is_enabled(clk)) {
+ if (clk_core_is_enabled(clk)) {
if (clk->ops->disable_unused)
clk->ops->disable_unused(clk->hw);
else if (clk->ops->disable)
@@ -486,9 +528,6 @@ static void clk_disable_unused_subtree(struct clk *clk)
unlock_out:
clk_enable_unlock(flags);
-
-out:
- return;
}
static bool clk_ignore_unused;
@@ -501,7 +540,7 @@ __setup("clk_ignore_unused", clk_ignore_unused_setup);
static int clk_disable_unused(void)
{
- struct clk *clk;
+ struct clk_core *clk;
if (clk_ignore_unused) {
pr_warn("clk: Not disabling unused clocks\n");
@@ -532,48 +571,65 @@ late_initcall_sync(clk_disable_unused);
const char *__clk_get_name(struct clk *clk)
{
- return !clk ? NULL : clk->name;
+ return !clk ? NULL : clk->core->name;
}
EXPORT_SYMBOL_GPL(__clk_get_name);
struct clk_hw *__clk_get_hw(struct clk *clk)
{
- return !clk ? NULL : clk->hw;
+ return !clk ? NULL : clk->core->hw;
}
EXPORT_SYMBOL_GPL(__clk_get_hw);
u8 __clk_get_num_parents(struct clk *clk)
{
- return !clk ? 0 : clk->num_parents;
+ return !clk ? 0 : clk->core->num_parents;
}
EXPORT_SYMBOL_GPL(__clk_get_num_parents);
struct clk *__clk_get_parent(struct clk *clk)
{
- return !clk ? NULL : clk->parent;
+ if (!clk)
+ return NULL;
+
+ /* TODO: Create a per-user clk and change callers to call clk_put */
+ return !clk->core->parent ? NULL : clk->core->parent->hw->clk;
}
EXPORT_SYMBOL_GPL(__clk_get_parent);
-struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+static struct clk_core *clk_core_get_parent_by_index(struct clk_core *clk,
+ u8 index)
{
if (!clk || index >= clk->num_parents)
return NULL;
else if (!clk->parents)
- return __clk_lookup(clk->parent_names[index]);
+ return clk_core_lookup(clk->parent_names[index]);
else if (!clk->parents[index])
return clk->parents[index] =
- __clk_lookup(clk->parent_names[index]);
+ clk_core_lookup(clk->parent_names[index]);
else
return clk->parents[index];
}
+
+struct clk *clk_get_parent_by_index(struct clk *clk, u8 index)
+{
+ struct clk_core *parent;
+
+ if (!clk)
+ return NULL;
+
+ parent = clk_core_get_parent_by_index(clk->core, index);
+
+ return !parent ? NULL : parent->hw->clk;
+}
EXPORT_SYMBOL_GPL(clk_get_parent_by_index);
unsigned int __clk_get_enable_count(struct clk *clk)
{
- return !clk ? 0 : clk->enable_count;
+ return !clk ? 0 : clk->core->enable_count;
}
-unsigned long __clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate_nolock(struct clk_core *clk)
{
unsigned long ret;
@@ -593,9 +649,17 @@ unsigned long __clk_get_rate(struct clk *clk)
out:
return ret;
}
+
+unsigned long __clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_rate_nolock(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_get_rate);
-static unsigned long __clk_get_accuracy(struct clk *clk)
+static unsigned long __clk_get_accuracy(struct clk_core *clk)
{
if (!clk)
return 0;
@@ -605,11 +669,11 @@ static unsigned long __clk_get_accuracy(struct clk *clk)
unsigned long __clk_get_flags(struct clk *clk)
{
- return !clk ? 0 : clk->flags;
+ return !clk ? 0 : clk->core->flags;
}
EXPORT_SYMBOL_GPL(__clk_get_flags);
-bool __clk_is_prepared(struct clk *clk)
+static bool clk_core_is_prepared(struct clk_core *clk)
{
int ret;
@@ -630,7 +694,15 @@ out:
return !!ret;
}
-bool __clk_is_enabled(struct clk *clk)
+bool __clk_is_prepared(struct clk *clk)
+{
+ if (!clk)
+ return false;
+
+ return clk_core_is_prepared(clk->core);
+}
+
+static bool clk_core_is_enabled(struct clk_core *clk)
{
int ret;
@@ -650,12 +722,21 @@ bool __clk_is_enabled(struct clk *clk)
out:
return !!ret;
}
+
+bool __clk_is_enabled(struct clk *clk)
+{
+ if (!clk)
+ return false;
+
+ return clk_core_is_enabled(clk->core);
+}
EXPORT_SYMBOL_GPL(__clk_is_enabled);
-static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
+static struct clk_core *__clk_lookup_subtree(const char *name,
+ struct clk_core *clk)
{
- struct clk *child;
- struct clk *ret;
+ struct clk_core *child;
+ struct clk_core *ret;
if (!strcmp(clk->name, name))
return clk;
@@ -669,10 +750,10 @@ static struct clk *__clk_lookup_subtree(const char *name, struct clk *clk)
return NULL;
}
-struct clk *__clk_lookup(const char *name)
+static struct clk_core *clk_core_lookup(const char *name)
{
- struct clk *root_clk;
- struct clk *ret;
+ struct clk_core *root_clk;
+ struct clk_core *ret;
if (!name)
return NULL;
@@ -694,42 +775,53 @@ struct clk *__clk_lookup(const char *name)
return NULL;
}
-/*
- * Helper for finding best parent to provide a given frequency. This can be used
- * directly as a determine_rate callback (e.g. for a mux), or from a more
- * complex clock that may combine a mux with other operations.
- */
-long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long *best_parent_rate,
- struct clk_hw **best_parent_p)
+static bool mux_is_better_rate(unsigned long rate, unsigned long now,
+ unsigned long best, unsigned long flags)
{
- struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ if (flags & CLK_MUX_ROUND_CLOSEST)
+ return abs(now - rate) < abs(best - rate);
+
+ return now <= rate && now > best;
+}
+
+static long
+clk_mux_determine_rate_flags(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p,
+ unsigned long flags)
+{
+ struct clk_core *core = hw->core, *parent, *best_parent = NULL;
int i, num_parents;
unsigned long parent_rate, best = 0;
/* if NO_REPARENT flag set, pass through to current parent */
- if (clk->flags & CLK_SET_RATE_NO_REPARENT) {
- parent = clk->parent;
- if (clk->flags & CLK_SET_RATE_PARENT)
- best = __clk_round_rate(parent, rate);
+ if (core->flags & CLK_SET_RATE_NO_REPARENT) {
+ parent = core->parent;
+ if (core->flags & CLK_SET_RATE_PARENT)
+ best = __clk_determine_rate(parent ? parent->hw : NULL,
+ rate, min_rate, max_rate);
else if (parent)
- best = __clk_get_rate(parent);
+ best = clk_core_get_rate_nolock(parent);
else
- best = __clk_get_rate(clk);
+ best = clk_core_get_rate_nolock(core);
goto out;
}
/* find the parent that can provide the fastest rate <= rate */
- num_parents = clk->num_parents;
+ num_parents = core->num_parents;
for (i = 0; i < num_parents; i++) {
- parent = clk_get_parent_by_index(clk, i);
+ parent = clk_core_get_parent_by_index(core, i);
if (!parent)
continue;
- if (clk->flags & CLK_SET_RATE_PARENT)
- parent_rate = __clk_round_rate(parent, rate);
+ if (core->flags & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_determine_rate(parent->hw, rate,
+ min_rate,
+ max_rate);
else
- parent_rate = __clk_get_rate(parent);
- if (parent_rate <= rate && parent_rate > best) {
+ parent_rate = clk_core_get_rate_nolock(parent);
+ if (mux_is_better_rate(rate, parent_rate, best, flags)) {
best_parent = parent;
best = parent_rate;
}
@@ -742,11 +834,63 @@ out:
return best;
}
+
+struct clk *__clk_lookup(const char *name)
+{
+ struct clk_core *core = clk_core_lookup(name);
+
+ return !core ? NULL : core->hw->clk;
+}
+
+static void clk_core_get_boundaries(struct clk_core *clk,
+ unsigned long *min_rate,
+ unsigned long *max_rate)
+{
+ struct clk *clk_user;
+
+ *min_rate = 0;
+ *max_rate = ULONG_MAX;
+
+ hlist_for_each_entry(clk_user, &clk->clks, child_node)
+ *min_rate = max(*min_rate, clk_user->min_rate);
+
+ hlist_for_each_entry(clk_user, &clk->clks, child_node)
+ *max_rate = min(*max_rate, clk_user->max_rate);
+}
+
+/*
+ * Helper for finding best parent to provide a given frequency. This can be used
+ * directly as a determine_rate callback (e.g. for a mux), or from a more
+ * complex clock that may combine a mux with other operations.
+ */
+long __clk_mux_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p)
+{
+ return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
+ best_parent_rate,
+ best_parent_p, 0);
+}
EXPORT_SYMBOL_GPL(__clk_mux_determine_rate);
+long __clk_mux_determine_rate_closest(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_p)
+{
+ return clk_mux_determine_rate_flags(hw, rate, min_rate, max_rate,
+ best_parent_rate,
+ best_parent_p,
+ CLK_MUX_ROUND_CLOSEST);
+}
+EXPORT_SYMBOL_GPL(__clk_mux_determine_rate_closest);
+
/*** clk api ***/
-void __clk_unprepare(struct clk *clk)
+static void clk_core_unprepare(struct clk_core *clk)
{
if (!clk)
return;
@@ -762,7 +906,7 @@ void __clk_unprepare(struct clk *clk)
if (clk->ops->unprepare)
clk->ops->unprepare(clk->hw);
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
}
/**
@@ -782,12 +926,12 @@ void clk_unprepare(struct clk *clk)
return;
clk_prepare_lock();
- __clk_unprepare(clk);
+ clk_core_unprepare(clk->core);
clk_prepare_unlock();
}
EXPORT_SYMBOL_GPL(clk_unprepare);
-int __clk_prepare(struct clk *clk)
+static int clk_core_prepare(struct clk_core *clk)
{
int ret = 0;
@@ -795,14 +939,14 @@ int __clk_prepare(struct clk *clk)
return 0;
if (clk->prepare_count == 0) {
- ret = __clk_prepare(clk->parent);
+ ret = clk_core_prepare(clk->parent);
if (ret)
return ret;
if (clk->ops->prepare) {
ret = clk->ops->prepare(clk->hw);
if (ret) {
- __clk_unprepare(clk->parent);
+ clk_core_unprepare(clk->parent);
return ret;
}
}
@@ -829,15 +973,18 @@ int clk_prepare(struct clk *clk)
{
int ret;
+ if (!clk)
+ return 0;
+
clk_prepare_lock();
- ret = __clk_prepare(clk);
+ ret = clk_core_prepare(clk->core);
clk_prepare_unlock();
return ret;
}
EXPORT_SYMBOL_GPL(clk_prepare);
-static void __clk_disable(struct clk *clk)
+static void clk_core_disable(struct clk_core *clk)
{
if (!clk)
return;
@@ -851,7 +998,15 @@ static void __clk_disable(struct clk *clk)
if (clk->ops->disable)
clk->ops->disable(clk->hw);
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
+}
+
+static void __clk_disable(struct clk *clk)
+{
+ if (!clk)
+ return;
+
+ clk_core_disable(clk->core);
}
/**
@@ -879,7 +1034,7 @@ void clk_disable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_disable);
-static int __clk_enable(struct clk *clk)
+static int clk_core_enable(struct clk_core *clk)
{
int ret = 0;
@@ -890,7 +1045,7 @@ static int __clk_enable(struct clk *clk)
return -ESHUTDOWN;
if (clk->enable_count == 0) {
- ret = __clk_enable(clk->parent);
+ ret = clk_core_enable(clk->parent);
if (ret)
return ret;
@@ -898,7 +1053,7 @@ static int __clk_enable(struct clk *clk)
if (clk->ops->enable) {
ret = clk->ops->enable(clk->hw);
if (ret) {
- __clk_disable(clk->parent);
+ clk_core_disable(clk->parent);
return ret;
}
}
@@ -908,6 +1063,14 @@ static int __clk_enable(struct clk *clk)
return 0;
}
+static int __clk_enable(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_enable(clk->core);
+}
+
/**
* clk_enable - ungate a clock
* @clk: the clk being ungated
@@ -934,17 +1097,13 @@ int clk_enable(struct clk *clk)
}
EXPORT_SYMBOL_GPL(clk_enable);
-/**
- * __clk_round_rate - round the given rate for a clk
- * @clk: round the rate of this clock
- * @rate: the rate which is to be rounded
- *
- * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
- */
-unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+static unsigned long clk_core_round_rate_nolock(struct clk_core *clk,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate)
{
unsigned long parent_rate = 0;
- struct clk *parent;
+ struct clk_core *parent;
struct clk_hw *parent_hw;
if (!clk)
@@ -956,15 +1115,59 @@ unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL;
- return clk->ops->determine_rate(clk->hw, rate, &parent_rate,
- &parent_hw);
+ return clk->ops->determine_rate(clk->hw, rate,
+ min_rate, max_rate,
+ &parent_rate, &parent_hw);
} else if (clk->ops->round_rate)
return clk->ops->round_rate(clk->hw, rate, &parent_rate);
else if (clk->flags & CLK_SET_RATE_PARENT)
- return __clk_round_rate(clk->parent, rate);
+ return clk_core_round_rate_nolock(clk->parent, rate, min_rate,
+ max_rate);
else
return clk->rate;
}
+
+/**
+ * __clk_determine_rate - get the closest rate actually supported by a clock
+ * @hw: determine the rate of this clock
+ * @rate: target rate
+ * @min_rate: returned rate must be greater than this rate
+ * @max_rate: returned rate must be less than this rate
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate and
+ * .determine_rate.
+ */
+unsigned long __clk_determine_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate)
+{
+ if (!hw)
+ return 0;
+
+ return clk_core_round_rate_nolock(hw->core, rate, min_rate, max_rate);
+}
+EXPORT_SYMBOL_GPL(__clk_determine_rate);
+
+/**
+ * __clk_round_rate - round the given rate for a clk
+ * @clk: round the rate of this clock
+ * @rate: the rate which is to be rounded
+ *
+ * Caller must hold prepare_lock. Useful for clk_ops such as .set_rate
+ */
+unsigned long __clk_round_rate(struct clk *clk, unsigned long rate)
+{
+ unsigned long min_rate;
+ unsigned long max_rate;
+
+ if (!clk)
+ return 0;
+
+ clk_core_get_boundaries(clk->core, &min_rate, &max_rate);
+
+ return clk_core_round_rate_nolock(clk->core, rate, min_rate, max_rate);
+}
EXPORT_SYMBOL_GPL(__clk_round_rate);
/**
@@ -980,6 +1183,9 @@ long clk_round_rate(struct clk *clk, unsigned long rate)
{
unsigned long ret;
+ if (!clk)
+ return 0;
+
clk_prepare_lock();
ret = __clk_round_rate(clk, rate);
clk_prepare_unlock();
@@ -1002,22 +1208,21 @@ EXPORT_SYMBOL_GPL(clk_round_rate);
* called if all went well, or NOTIFY_STOP or NOTIFY_BAD immediately if
* a driver returns that.
*/
-static int __clk_notify(struct clk *clk, unsigned long msg,
+static int __clk_notify(struct clk_core *clk, unsigned long msg,
unsigned long old_rate, unsigned long new_rate)
{
struct clk_notifier *cn;
struct clk_notifier_data cnd;
int ret = NOTIFY_DONE;
- cnd.clk = clk;
cnd.old_rate = old_rate;
cnd.new_rate = new_rate;
list_for_each_entry(cn, &clk_notifier_list, node) {
- if (cn->clk == clk) {
+ if (cn->clk->core == clk) {
+ cnd.clk = cn->clk;
ret = srcu_notifier_call_chain(&cn->notifier_head, msg,
&cnd);
- break;
}
}
@@ -1035,10 +1240,10 @@ static int __clk_notify(struct clk *clk, unsigned long msg,
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_accuracies(struct clk *clk)
+static void __clk_recalc_accuracies(struct clk_core *clk)
{
unsigned long parent_accuracy = 0;
- struct clk *child;
+ struct clk_core *child;
if (clk->parent)
parent_accuracy = clk->parent->accuracy;
@@ -1053,6 +1258,20 @@ static void __clk_recalc_accuracies(struct clk *clk)
__clk_recalc_accuracies(child);
}
+static long clk_core_get_accuracy(struct clk_core *clk)
+{
+ unsigned long accuracy;
+
+ clk_prepare_lock();
+ if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE))
+ __clk_recalc_accuracies(clk);
+
+ accuracy = __clk_get_accuracy(clk);
+ clk_prepare_unlock();
+
+ return accuracy;
+}
+
/**
* clk_get_accuracy - return the accuracy of clk
* @clk: the clk whose accuracy is being returned
@@ -1064,20 +1283,15 @@ static void __clk_recalc_accuracies(struct clk *clk)
*/
long clk_get_accuracy(struct clk *clk)
{
- unsigned long accuracy;
-
- clk_prepare_lock();
- if (clk && (clk->flags & CLK_GET_ACCURACY_NOCACHE))
- __clk_recalc_accuracies(clk);
-
- accuracy = __clk_get_accuracy(clk);
- clk_prepare_unlock();
+ if (!clk)
+ return 0;
- return accuracy;
+ return clk_core_get_accuracy(clk->core);
}
EXPORT_SYMBOL_GPL(clk_get_accuracy);
-static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
+static unsigned long clk_recalc(struct clk_core *clk,
+ unsigned long parent_rate)
{
if (clk->ops->recalc_rate)
return clk->ops->recalc_rate(clk->hw, parent_rate);
@@ -1098,11 +1312,11 @@ static unsigned long clk_recalc(struct clk *clk, unsigned long parent_rate)
*
* Caller must hold prepare_lock.
*/
-static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
+static void __clk_recalc_rates(struct clk_core *clk, unsigned long msg)
{
unsigned long old_rate;
unsigned long parent_rate = 0;
- struct clk *child;
+ struct clk_core *child;
old_rate = clk->rate;
@@ -1122,15 +1336,7 @@ static void __clk_recalc_rates(struct clk *clk, unsigned long msg)
__clk_recalc_rates(child, msg);
}
-/**
- * clk_get_rate - return the rate of clk
- * @clk: the clk whose rate is being returned
- *
- * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
- * is set, which means a recalc_rate will be issued.
- * If clk is NULL then returns 0.
- */
-unsigned long clk_get_rate(struct clk *clk)
+static unsigned long clk_core_get_rate(struct clk_core *clk)
{
unsigned long rate;
@@ -1139,14 +1345,32 @@ unsigned long clk_get_rate(struct clk *clk)
if (clk && (clk->flags & CLK_GET_RATE_NOCACHE))
__clk_recalc_rates(clk, 0);
- rate = __clk_get_rate(clk);
+ rate = clk_core_get_rate_nolock(clk);
clk_prepare_unlock();
return rate;
}
+EXPORT_SYMBOL_GPL(clk_core_get_rate);
+
+/**
+ * clk_get_rate - return the rate of clk
+ * @clk: the clk whose rate is being returned
+ *
+ * Simply returns the cached rate of the clk, unless CLK_GET_RATE_NOCACHE flag
+ * is set, which means a recalc_rate will be issued.
+ * If clk is NULL then returns 0.
+ */
+unsigned long clk_get_rate(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_rate(clk->core);
+}
EXPORT_SYMBOL_GPL(clk_get_rate);
-static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
+static int clk_fetch_parent_index(struct clk_core *clk,
+ struct clk_core *parent)
{
int i;
@@ -1160,7 +1384,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
/*
* find index of new parent clock using cached parent ptrs,
* or if not yet cached, use string name comparison and cache
- * them now to avoid future calls to __clk_lookup.
+ * them now to avoid future calls to clk_core_lookup.
*/
for (i = 0; i < clk->num_parents; i++) {
if (clk->parents[i] == parent)
@@ -1170,7 +1394,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
continue;
if (!strcmp(clk->parent_names[i], parent->name)) {
- clk->parents[i] = __clk_lookup(parent->name);
+ clk->parents[i] = clk_core_lookup(parent->name);
return i;
}
}
@@ -1178,7 +1402,7 @@ static int clk_fetch_parent_index(struct clk *clk, struct clk *parent)
return -EINVAL;
}
-static void clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_reparent(struct clk_core *clk, struct clk_core *new_parent)
{
hlist_del(&clk->child_node);
@@ -1195,10 +1419,11 @@ static void clk_reparent(struct clk *clk, struct clk *new_parent)
clk->parent = new_parent;
}
-static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
+static struct clk_core *__clk_set_parent_before(struct clk_core *clk,
+ struct clk_core *parent)
{
unsigned long flags;
- struct clk *old_parent = clk->parent;
+ struct clk_core *old_parent = clk->parent;
/*
* Migrate prepare state between parents and prevent race with
@@ -1218,9 +1443,9 @@ static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
* See also: Comment for clk_set_parent() below.
*/
if (clk->prepare_count) {
- __clk_prepare(parent);
- clk_enable(parent);
- clk_enable(clk);
+ clk_core_prepare(parent);
+ clk_core_enable(parent);
+ clk_core_enable(clk);
}
/* update the clk tree topology */
@@ -1231,25 +1456,27 @@ static struct clk *__clk_set_parent_before(struct clk *clk, struct clk *parent)
return old_parent;
}
-static void __clk_set_parent_after(struct clk *clk, struct clk *parent,
- struct clk *old_parent)
+static void __clk_set_parent_after(struct clk_core *core,
+ struct clk_core *parent,
+ struct clk_core *old_parent)
{
/*
* Finish the migration of prepare state and undo the changes done
* for preventing a race with clk_enable().
*/
- if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(old_parent);
- __clk_unprepare(old_parent);
+ if (core->prepare_count) {
+ clk_core_disable(core);
+ clk_core_disable(old_parent);
+ clk_core_unprepare(old_parent);
}
}
-static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
+static int __clk_set_parent(struct clk_core *clk, struct clk_core *parent,
+ u8 p_index)
{
unsigned long flags;
int ret = 0;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_parent = __clk_set_parent_before(clk, parent);
@@ -1263,9 +1490,9 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
clk_enable_unlock(flags);
if (clk->prepare_count) {
- clk_disable(clk);
- clk_disable(parent);
- __clk_unprepare(parent);
+ clk_core_disable(clk);
+ clk_core_disable(parent);
+ clk_core_unprepare(parent);
}
return ret;
}
@@ -1291,9 +1518,10 @@ static int __clk_set_parent(struct clk *clk, struct clk *parent, u8 p_index)
*
* Caller must hold prepare_lock.
*/
-static int __clk_speculate_rates(struct clk *clk, unsigned long parent_rate)
+static int __clk_speculate_rates(struct clk_core *clk,
+ unsigned long parent_rate)
{
- struct clk *child;
+ struct clk_core *child;
unsigned long new_rate;
int ret = NOTIFY_DONE;
@@ -1319,10 +1547,10 @@ out:
return ret;
}
-static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
- struct clk *new_parent, u8 p_index)
+static void clk_calc_subtree(struct clk_core *clk, unsigned long new_rate,
+ struct clk_core *new_parent, u8 p_index)
{
- struct clk *child;
+ struct clk_core *child;
clk->new_rate = new_rate;
clk->new_parent = new_parent;
@@ -1342,13 +1570,16 @@ static void clk_calc_subtree(struct clk *clk, unsigned long new_rate,
* calculate the new rates returning the topmost clock that has to be
* changed.
*/
-static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
+static struct clk_core *clk_calc_new_rates(struct clk_core *clk,
+ unsigned long rate)
{
- struct clk *top = clk;
- struct clk *old_parent, *parent;
+ struct clk_core *top = clk;
+ struct clk_core *old_parent, *parent;
struct clk_hw *parent_hw;
unsigned long best_parent_rate = 0;
unsigned long new_rate;
+ unsigned long min_rate;
+ unsigned long max_rate;
int p_index = 0;
/* sanity */
@@ -1360,16 +1591,22 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
if (parent)
best_parent_rate = parent->rate;
+ clk_core_get_boundaries(clk, &min_rate, &max_rate);
+
/* find the closest rate and parent clk/rate */
if (clk->ops->determine_rate) {
parent_hw = parent ? parent->hw : NULL;
new_rate = clk->ops->determine_rate(clk->hw, rate,
+ min_rate,
+ max_rate,
&best_parent_rate,
&parent_hw);
- parent = parent_hw ? parent_hw->clk : NULL;
+ parent = parent_hw ? parent_hw->core : NULL;
} else if (clk->ops->round_rate) {
new_rate = clk->ops->round_rate(clk->hw, rate,
&best_parent_rate);
+ if (new_rate < min_rate || new_rate > max_rate)
+ return NULL;
} else if (!parent || !(clk->flags & CLK_SET_RATE_PARENT)) {
/* pass-through clock without adjustable parent */
clk->new_rate = clk->rate;
@@ -1390,7 +1627,7 @@ static struct clk *clk_calc_new_rates(struct clk *clk, unsigned long rate)
}
/* try finding the new parent index */
- if (parent) {
+ if (parent && clk->num_parents > 1) {
p_index = clk_fetch_parent_index(clk, parent);
if (p_index < 0) {
pr_debug("%s: clk %s can not be parent of clk %s\n",
@@ -1414,9 +1651,10 @@ out:
* so that in case of an error we can walk down the whole tree again and
* abort the change.
*/
-static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long event)
+static struct clk_core *clk_propagate_rate_change(struct clk_core *clk,
+ unsigned long event)
{
- struct clk *child, *tmp_clk, *fail_clk = NULL;
+ struct clk_core *child, *tmp_clk, *fail_clk = NULL;
int ret = NOTIFY_DONE;
if (clk->rate == clk->new_rate)
@@ -1451,14 +1689,14 @@ static struct clk *clk_propagate_rate_change(struct clk *clk, unsigned long even
* walk down a subtree and set the new rates notifying the rate
* change on the way
*/
-static void clk_change_rate(struct clk *clk)
+static void clk_change_rate(struct clk_core *clk)
{
- struct clk *child;
+ struct clk_core *child;
struct hlist_node *tmp;
unsigned long old_rate;
unsigned long best_parent_rate = 0;
bool skip_set_rate = false;
- struct clk *old_parent;
+ struct clk_core *old_parent;
old_rate = clk->rate;
@@ -1506,6 +1744,45 @@ static void clk_change_rate(struct clk *clk)
clk_change_rate(clk->new_child);
}
+static int clk_core_set_rate_nolock(struct clk_core *clk,
+ unsigned long req_rate)
+{
+ struct clk_core *top, *fail_clk;
+ unsigned long rate = req_rate;
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ /* bail early if nothing to do */
+ if (rate == clk_core_get_rate_nolock(clk))
+ return 0;
+
+ if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count)
+ return -EBUSY;
+
+ /* calculate new rates and get the topmost changed clock */
+ top = clk_calc_new_rates(clk, rate);
+ if (!top)
+ return -EINVAL;
+
+ /* notify that we are about to change rates */
+ fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
+ if (fail_clk) {
+ pr_debug("%s: failed to set %s rate\n", __func__,
+ fail_clk->name);
+ clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
+ return -EBUSY;
+ }
+
+ /* change the rates */
+ clk_change_rate(top);
+
+ clk->req_rate = req_rate;
+
+ return ret;
+}
+
/**
* clk_set_rate - specify a new rate for clk
* @clk: the clk whose rate is being changed
@@ -1529,8 +1806,7 @@ static void clk_change_rate(struct clk *clk)
*/
int clk_set_rate(struct clk *clk, unsigned long rate)
{
- struct clk *top, *fail_clk;
- int ret = 0;
+ int ret;
if (!clk)
return 0;
@@ -1538,41 +1814,81 @@ int clk_set_rate(struct clk *clk, unsigned long rate)
/* prevent racing with updates to the clock topology */
clk_prepare_lock();
- /* bail early if nothing to do */
- if (rate == clk_get_rate(clk))
- goto out;
+ ret = clk_core_set_rate_nolock(clk->core, rate);
- if ((clk->flags & CLK_SET_RATE_GATE) && clk->prepare_count) {
- ret = -EBUSY;
- goto out;
- }
+ clk_prepare_unlock();
- /* calculate new rates and get the topmost changed clock */
- top = clk_calc_new_rates(clk, rate);
- if (!top) {
- ret = -EINVAL;
- goto out;
- }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(clk_set_rate);
- /* notify that we are about to change rates */
- fail_clk = clk_propagate_rate_change(top, PRE_RATE_CHANGE);
- if (fail_clk) {
- pr_debug("%s: failed to set %s rate\n", __func__,
- fail_clk->name);
- clk_propagate_rate_change(top, ABORT_RATE_CHANGE);
- ret = -EBUSY;
- goto out;
+/**
+ * clk_set_rate_range - set a rate range for a clock source
+ * @clk: clock source
+ * @min: desired minimum clock rate in Hz, inclusive
+ * @max: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
+{
+ int ret = 0;
+
+ if (!clk)
+ return 0;
+
+ if (min > max) {
+ pr_err("%s: clk %s dev %s con %s: invalid range [%lu, %lu]\n",
+ __func__, clk->core->name, clk->dev_id, clk->con_id,
+ min, max);
+ return -EINVAL;
}
- /* change the rates */
- clk_change_rate(top);
+ clk_prepare_lock();
+
+ if (min != clk->min_rate || max != clk->max_rate) {
+ clk->min_rate = min;
+ clk->max_rate = max;
+ ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+ }
-out:
clk_prepare_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(clk_set_rate);
+EXPORT_SYMBOL_GPL(clk_set_rate_range);
+
+/**
+ * clk_set_min_rate - set a minimum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired minimum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_min_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ return clk_set_rate_range(clk, rate, clk->max_rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_min_rate);
+
+/**
+ * clk_set_max_rate - set a maximum clock rate for a clock source
+ * @clk: clock source
+ * @rate: desired maximum clock rate in Hz, inclusive
+ *
+ * Returns success (0) or negative errno.
+ */
+int clk_set_max_rate(struct clk *clk, unsigned long rate)
+{
+ if (!clk)
+ return 0;
+
+ return clk_set_rate_range(clk, clk->min_rate, rate);
+}
+EXPORT_SYMBOL_GPL(clk_set_max_rate);
/**
* clk_get_parent - return the parent of a clk
@@ -1599,11 +1915,11 @@ EXPORT_SYMBOL_GPL(clk_get_parent);
*
* For single-parent clocks without .get_parent, first check to see if the
* .parents array exists, and if so use it to avoid an expensive tree
- * traversal. If .parents does not exist then walk the tree with __clk_lookup.
+ * traversal. If .parents does not exist then walk the tree.
*/
-static struct clk *__clk_init_parent(struct clk *clk)
+static struct clk_core *__clk_init_parent(struct clk_core *clk)
{
- struct clk *ret = NULL;
+ struct clk_core *ret = NULL;
u8 index;
/* handle the trivial cases */
@@ -1613,7 +1929,7 @@ static struct clk *__clk_init_parent(struct clk *clk)
if (clk->num_parents == 1) {
if (IS_ERR_OR_NULL(clk->parent))
- clk->parent = __clk_lookup(clk->parent_names[0]);
+ clk->parent = clk_core_lookup(clk->parent_names[0]);
ret = clk->parent;
goto out;
}
@@ -1627,8 +1943,8 @@ static struct clk *__clk_init_parent(struct clk *clk)
/*
* Do our best to cache parent clocks in clk->parents. This prevents
- * unnecessary and expensive calls to __clk_lookup. We don't set
- * clk->parent here; that is done by the calling function
+ * unnecessary and expensive lookups. We don't set clk->parent here;
+ * that is done by the calling function.
*/
index = clk->ops->get_parent(clk->hw);
@@ -1638,13 +1954,14 @@ static struct clk *__clk_init_parent(struct clk *clk)
kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
- ret = clk_get_parent_by_index(clk, index);
+ ret = clk_core_get_parent_by_index(clk, index);
out:
return ret;
}
-void __clk_reparent(struct clk *clk, struct clk *new_parent)
+static void clk_core_reparent(struct clk_core *clk,
+ struct clk_core *new_parent)
{
clk_reparent(clk, new_parent);
__clk_recalc_accuracies(clk);
@@ -1652,23 +1969,40 @@ void __clk_reparent(struct clk *clk, struct clk *new_parent)
}
/**
- * clk_set_parent - switch the parent of a mux clk
- * @clk: the mux clk whose input we are switching
- * @parent: the new input to clk
+ * clk_has_parent - check if a clock is a possible parent for another
+ * @clk: clock source
+ * @parent: parent clock source
*
- * Re-parent clk to use parent as its new input source. If clk is in
- * prepared state, the clk will get enabled for the duration of this call. If
- * that's not acceptable for a specific clk (Eg: the consumer can't handle
- * that, the reparenting is glitchy in hardware, etc), use the
- * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
- *
- * After successfully changing clk's parent clk_set_parent will update the
- * clk topology, sysfs topology and propagate rate recalculation via
- * __clk_recalc_rates.
+ * This function can be used in drivers that need to check that a clock can be
+ * the parent of another without actually changing the parent.
*
- * Returns 0 on success, -EERROR otherwise.
+ * Returns true if @parent is a possible parent for @clk, false otherwise.
*/
-int clk_set_parent(struct clk *clk, struct clk *parent)
+bool clk_has_parent(struct clk *clk, struct clk *parent)
+{
+ struct clk_core *core, *parent_core;
+ unsigned int i;
+
+ /* NULL clocks should be nops, so return success if either is NULL. */
+ if (!clk || !parent)
+ return true;
+
+ core = clk->core;
+ parent_core = parent->core;
+
+ /* Optimize for the case where the parent is already the parent. */
+ if (core->parent == parent_core)
+ return true;
+
+ for (i = 0; i < core->num_parents; i++)
+ if (strcmp(core->parent_names[i], parent_core->name) == 0)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(clk_has_parent);
+
+static int clk_core_set_parent(struct clk_core *clk, struct clk_core *parent)
{
int ret = 0;
int p_index = 0;
@@ -1728,6 +2062,31 @@ out:
return ret;
}
+
+/**
+ * clk_set_parent - switch the parent of a mux clk
+ * @clk: the mux clk whose input we are switching
+ * @parent: the new input to clk
+ *
+ * Re-parent clk to use parent as its new input source. If clk is in
+ * prepared state, the clk will get enabled for the duration of this call. If
+ * that's not acceptable for a specific clk (Eg: the consumer can't handle
+ * that, the reparenting is glitchy in hardware, etc), use the
+ * CLK_SET_PARENT_GATE flag to allow reparenting only when clk is unprepared.
+ *
+ * After successfully changing clk's parent clk_set_parent will update the
+ * clk topology, sysfs topology and propagate rate recalculation via
+ * __clk_recalc_rates.
+ *
+ * Returns 0 on success, -EERROR otherwise.
+ */
+int clk_set_parent(struct clk *clk, struct clk *parent)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_set_parent(clk->core, parent ? parent->core : NULL);
+}
EXPORT_SYMBOL_GPL(clk_set_parent);
/**
@@ -1764,13 +2123,13 @@ int clk_set_phase(struct clk *clk, int degrees)
clk_prepare_lock();
- if (!clk->ops->set_phase)
+ if (!clk->core->ops->set_phase)
goto out_unlock;
- ret = clk->ops->set_phase(clk->hw, degrees);
+ ret = clk->core->ops->set_phase(clk->core->hw, degrees);
if (!ret)
- clk->phase = degrees;
+ clk->core->phase = degrees;
out_unlock:
clk_prepare_unlock();
@@ -1778,15 +2137,9 @@ out_unlock:
out:
return ret;
}
+EXPORT_SYMBOL_GPL(clk_set_phase);
-/**
- * clk_get_phase - return the phase shift of a clock signal
- * @clk: clock signal source
- *
- * Returns the phase shift of a clock node in degrees, otherwise returns
- * -EERROR.
- */
-int clk_get_phase(struct clk *clk)
+static int clk_core_get_phase(struct clk_core *clk)
{
int ret = 0;
@@ -1800,28 +2153,48 @@ int clk_get_phase(struct clk *clk)
out:
return ret;
}
+EXPORT_SYMBOL_GPL(clk_get_phase);
+
+/**
+ * clk_get_phase - return the phase shift of a clock signal
+ * @clk: clock signal source
+ *
+ * Returns the phase shift of a clock node in degrees, otherwise returns
+ * -EERROR.
+ */
+int clk_get_phase(struct clk *clk)
+{
+ if (!clk)
+ return 0;
+
+ return clk_core_get_phase(clk->core);
+}
/**
* __clk_init - initialize the data structures in a struct clk
* @dev: device initializing this clk, placeholder for now
* @clk: clk being initialized
*
- * Initializes the lists in struct clk, queries the hardware for the
+ * Initializes the lists in struct clk_core, queries the hardware for the
* parent and rate and sets them both.
*/
-int __clk_init(struct device *dev, struct clk *clk)
+static int __clk_init(struct device *dev, struct clk *clk_user)
{
int i, ret = 0;
- struct clk *orphan;
+ struct clk_core *orphan;
struct hlist_node *tmp2;
+ struct clk_core *clk;
+ unsigned long rate;
- if (!clk)
+ if (!clk_user)
return -EINVAL;
+ clk = clk_user->core;
+
clk_prepare_lock();
/* check to see if a clock with this name is already registered */
- if (__clk_lookup(clk->name)) {
+ if (clk_core_lookup(clk->name)) {
pr_debug("%s: clk %s already initialized\n",
__func__, clk->name);
ret = -EEXIST;
@@ -1873,7 +2246,7 @@ int __clk_init(struct device *dev, struct clk *clk)
clk->parents = kcalloc(clk->num_parents, sizeof(struct clk *),
GFP_KERNEL);
/*
- * __clk_lookup returns NULL for parents that have not been
+ * clk_core_lookup returns NULL for parents that have not been
* clk_init'd; thus any access to clk->parents[] must check
* for a NULL pointer. We can always perform lazy lookups for
* missing parents later on.
@@ -1881,7 +2254,7 @@ int __clk_init(struct device *dev, struct clk *clk)
if (clk->parents)
for (i = 0; i < clk->num_parents; i++)
clk->parents[i] =
- __clk_lookup(clk->parent_names[i]);
+ clk_core_lookup(clk->parent_names[i]);
}
clk->parent = __clk_init_parent(clk);
@@ -1936,12 +2309,13 @@ int __clk_init(struct device *dev, struct clk *clk)
* then rate is set to zero.
*/
if (clk->ops->recalc_rate)
- clk->rate = clk->ops->recalc_rate(clk->hw,
- __clk_get_rate(clk->parent));
+ rate = clk->ops->recalc_rate(clk->hw,
+ clk_core_get_rate_nolock(clk->parent));
else if (clk->parent)
- clk->rate = clk->parent->rate;
+ rate = clk->parent->rate;
else
- clk->rate = 0;
+ rate = 0;
+ clk->rate = clk->req_rate = rate;
/*
* walk the list of orphan clocks and reparent any that are children of
@@ -1951,13 +2325,13 @@ int __clk_init(struct device *dev, struct clk *clk)
if (orphan->num_parents && orphan->ops->get_parent) {
i = orphan->ops->get_parent(orphan->hw);
if (!strcmp(clk->name, orphan->parent_names[i]))
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
continue;
}
for (i = 0; i < orphan->num_parents; i++)
if (!strcmp(clk->name, orphan->parent_names[i])) {
- __clk_reparent(orphan, clk);
+ clk_core_reparent(orphan, clk);
break;
}
}
@@ -1983,47 +2357,39 @@ out:
return ret;
}
-/**
- * __clk_register - register a clock and return a cookie.
- *
- * Same as clk_register, except that the .clk field inside hw shall point to a
- * preallocated (generally statically allocated) struct clk. None of the fields
- * of the struct clk need to be initialized.
- *
- * The data pointed to by .init and .clk field shall NOT be marked as init
- * data.
- *
- * __clk_register is only exposed via clk-private.h and is intended for use with
- * very large numbers of clocks that need to be statically initialized. It is
- * a layering violation to include clk-private.h from any code which implements
- * a clock's .ops; as such any statically initialized clock data MUST be in a
- * separate C file from the logic that implements its operations. Returns 0
- * on success, otherwise an error code.
- */
-struct clk *__clk_register(struct device *dev, struct clk_hw *hw)
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id)
{
- int ret;
struct clk *clk;
- clk = hw->clk;
- clk->name = hw->init->name;
- clk->ops = hw->init->ops;
- clk->hw = hw;
- clk->flags = hw->init->flags;
- clk->parent_names = hw->init->parent_names;
- clk->num_parents = hw->init->num_parents;
- if (dev && dev->driver)
- clk->owner = dev->driver->owner;
- else
- clk->owner = NULL;
+ /* This is to allow this function to be chained to others */
+ if (!hw || IS_ERR(hw))
+ return (struct clk *) hw;
- ret = __clk_init(dev, clk);
- if (ret)
- return ERR_PTR(ret);
+ clk = kzalloc(sizeof(*clk), GFP_KERNEL);
+ if (!clk)
+ return ERR_PTR(-ENOMEM);
+
+ clk->core = hw->core;
+ clk->dev_id = dev_id;
+ clk->con_id = con_id;
+ clk->max_rate = ULONG_MAX;
+
+ clk_prepare_lock();
+ hlist_add_head(&clk->child_node, &hw->core->clks);
+ clk_prepare_unlock();
return clk;
}
-EXPORT_SYMBOL_GPL(__clk_register);
+
+void __clk_free_clk(struct clk *clk)
+{
+ clk_prepare_lock();
+ hlist_del(&clk->child_node);
+ clk_prepare_unlock();
+
+ kfree(clk);
+}
/**
* clk_register - allocate a new clock, register it and return an opaque cookie
@@ -2039,7 +2405,7 @@ EXPORT_SYMBOL_GPL(__clk_register);
struct clk *clk_register(struct device *dev, struct clk_hw *hw)
{
int i, ret;
- struct clk *clk;
+ struct clk_core *clk;
clk = kzalloc(sizeof(*clk), GFP_KERNEL);
if (!clk) {
@@ -2048,7 +2414,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
goto fail_out;
}
- clk->name = kstrdup(hw->init->name, GFP_KERNEL);
+ clk->name = kstrdup_const(hw->init->name, GFP_KERNEL);
if (!clk->name) {
pr_err("%s: could not allocate clk->name\n", __func__);
ret = -ENOMEM;
@@ -2060,7 +2426,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
clk->hw = hw;
clk->flags = hw->init->flags;
clk->num_parents = hw->init->num_parents;
- hw->clk = clk;
+ hw->core = clk;
/* allocate local copy in case parent_names is __initdata */
clk->parent_names = kcalloc(clk->num_parents, sizeof(char *),
@@ -2075,7 +2441,7 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
/* copy each string name in case parent_names is __initdata */
for (i = 0; i < clk->num_parents; i++) {
- clk->parent_names[i] = kstrdup(hw->init->parent_names[i],
+ clk->parent_names[i] = kstrdup_const(hw->init->parent_names[i],
GFP_KERNEL);
if (!clk->parent_names[i]) {
pr_err("%s: could not copy parent_names\n", __func__);
@@ -2084,16 +2450,28 @@ struct clk *clk_register(struct device *dev, struct clk_hw *hw)
}
}
- ret = __clk_init(dev, clk);
+ INIT_HLIST_HEAD(&clk->clks);
+
+ hw->clk = __clk_create_clk(hw, NULL, NULL);
+ if (IS_ERR(hw->clk)) {
+ pr_err("%s: could not allocate per-user clk\n", __func__);
+ ret = PTR_ERR(hw->clk);
+ goto fail_parent_names_copy;
+ }
+
+ ret = __clk_init(dev, hw->clk);
if (!ret)
- return clk;
+ return hw->clk;
+
+ __clk_free_clk(hw->clk);
+ hw->clk = NULL;
fail_parent_names_copy:
while (--i >= 0)
- kfree(clk->parent_names[i]);
+ kfree_const(clk->parent_names[i]);
kfree(clk->parent_names);
fail_parent_names:
- kfree(clk->name);
+ kfree_const(clk->name);
fail_name:
kfree(clk);
fail_out:
@@ -2107,15 +2485,15 @@ EXPORT_SYMBOL_GPL(clk_register);
*/
static void __clk_release(struct kref *ref)
{
- struct clk *clk = container_of(ref, struct clk, ref);
+ struct clk_core *clk = container_of(ref, struct clk_core, ref);
int i = clk->num_parents;
kfree(clk->parents);
while (--i >= 0)
- kfree(clk->parent_names[i]);
+ kfree_const(clk->parent_names[i]);
kfree(clk->parent_names);
- kfree(clk->name);
+ kfree_const(clk->name);
kfree(clk);
}
@@ -2165,12 +2543,13 @@ void clk_unregister(struct clk *clk)
if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
return;
- clk_debug_unregister(clk);
+ clk_debug_unregister(clk->core);
clk_prepare_lock();
- if (clk->ops == &clk_nodrv_ops) {
- pr_err("%s: unregistered clock: %s\n", __func__, clk->name);
+ if (clk->core->ops == &clk_nodrv_ops) {
+ pr_err("%s: unregistered clock: %s\n", __func__,
+ clk->core->name);
return;
}
/*
@@ -2178,24 +2557,25 @@ void clk_unregister(struct clk *clk)
* a reference to this clock.
*/
flags = clk_enable_lock();
- clk->ops = &clk_nodrv_ops;
+ clk->core->ops = &clk_nodrv_ops;
clk_enable_unlock(flags);
- if (!hlist_empty(&clk->children)) {
- struct clk *child;
+ if (!hlist_empty(&clk->core->children)) {
+ struct clk_core *child;
struct hlist_node *t;
/* Reparent all children to the orphan list. */
- hlist_for_each_entry_safe(child, t, &clk->children, child_node)
- clk_set_parent(child, NULL);
+ hlist_for_each_entry_safe(child, t, &clk->core->children,
+ child_node)
+ clk_core_set_parent(child, NULL);
}
- hlist_del_init(&clk->child_node);
+ hlist_del_init(&clk->core->child_node);
- if (clk->prepare_count)
+ if (clk->core->prepare_count)
pr_warn("%s: unregistering prepared clock: %s\n",
- __func__, clk->name);
- kref_put(&clk->ref, __clk_release);
+ __func__, clk->core->name);
+ kref_put(&clk->core->ref, __clk_release);
clk_prepare_unlock();
}
@@ -2263,11 +2643,13 @@ EXPORT_SYMBOL_GPL(devm_clk_unregister);
*/
int __clk_get(struct clk *clk)
{
- if (clk) {
- if (!try_module_get(clk->owner))
+ struct clk_core *core = !clk ? NULL : clk->core;
+
+ if (core) {
+ if (!try_module_get(core->owner))
return 0;
- kref_get(&clk->ref);
+ kref_get(&core->ref);
}
return 1;
}
@@ -2280,11 +2662,20 @@ void __clk_put(struct clk *clk)
return;
clk_prepare_lock();
- owner = clk->owner;
- kref_put(&clk->ref, __clk_release);
+
+ hlist_del(&clk->child_node);
+ if (clk->min_rate > clk->core->req_rate ||
+ clk->max_rate < clk->core->req_rate)
+ clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+
+ owner = clk->core->owner;
+ kref_put(&clk->core->ref, __clk_release);
+
clk_prepare_unlock();
module_put(owner);
+
+ kfree(clk);
}
/*** clk rate change notifiers ***/
@@ -2339,7 +2730,7 @@ int clk_notifier_register(struct clk *clk, struct notifier_block *nb)
ret = srcu_notifier_chain_register(&cn->notifier_head, nb);
- clk->notifier_count++;
+ clk->core->notifier_count++;
out:
clk_prepare_unlock();
@@ -2376,7 +2767,7 @@ int clk_notifier_unregister(struct clk *clk, struct notifier_block *nb)
if (cn->clk == clk) {
ret = srcu_notifier_chain_unregister(&cn->notifier_head, nb);
- clk->notifier_count--;
+ clk->core->notifier_count--;
/* XXX the notifier code should handle this better */
if (!cn->notifier_head.head) {
@@ -2506,7 +2897,8 @@ void of_clk_del_provider(struct device_node *np)
}
EXPORT_SYMBOL_GPL(of_clk_del_provider);
-struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
+struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id)
{
struct of_clk_provider *provider;
struct clk *clk = ERR_PTR(-EPROBE_DEFER);
@@ -2515,8 +2907,17 @@ struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec)
list_for_each_entry(provider, &of_clk_providers, link) {
if (provider->node == clkspec->np)
clk = provider->get(clkspec, provider->data);
- if (!IS_ERR(clk))
+ if (!IS_ERR(clk)) {
+ clk = __clk_create_clk(__clk_get_hw(clk), dev_id,
+ con_id);
+
+ if (!IS_ERR(clk) && !__clk_get(clk)) {
+ __clk_free_clk(clk);
+ clk = ERR_PTR(-ENOENT);
+ }
+
break;
+ }
}
return clk;
@@ -2527,7 +2928,7 @@ struct clk *of_clk_get_from_provider(struct of_phandle_args *clkspec)
struct clk *clk;
mutex_lock(&of_clk_mutex);
- clk = __of_clk_get_from_provider(clkspec);
+ clk = __of_clk_get_from_provider(clkspec, NULL, __func__);
mutex_unlock(&of_clk_mutex);
return clk;
diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h
index c798138f023f..ba845408cc3e 100644
--- a/drivers/clk/clk.h
+++ b/drivers/clk/clk.h
@@ -9,9 +9,31 @@
* published by the Free Software Foundation.
*/
+struct clk_hw;
+
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec);
-struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec);
+struct clk *__of_clk_get_from_provider(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id);
void of_clk_lock(void);
void of_clk_unlock(void);
#endif
+
+#ifdef CONFIG_COMMON_CLK
+struct clk *__clk_create_clk(struct clk_hw *hw, const char *dev_id,
+ const char *con_id);
+void __clk_free_clk(struct clk *clk);
+#else
+/* All these casts to avoid ifdefs in clkdev... */
+static inline struct clk *
+__clk_create_clk(struct clk_hw *hw, const char *dev_id, const char *con_id)
+{
+ return (struct clk *)hw;
+}
+static inline void __clk_free_clk(struct clk *clk) { }
+static struct clk_hw *__clk_get_hw(struct clk *clk)
+{
+ return (struct clk_hw *)clk;
+}
+
+#endif
diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c
index da4bda8b7fc7..043fd3633373 100644
--- a/drivers/clk/clkdev.c
+++ b/drivers/clk/clkdev.c
@@ -19,6 +19,7 @@
#include <linux/mutex.h>
#include <linux/clk.h>
#include <linux/clkdev.h>
+#include <linux/clk-provider.h>
#include <linux/of.h>
#include "clk.h"
@@ -28,6 +29,20 @@ static DEFINE_MUTEX(clocks_mutex);
#if defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK)
+static struct clk *__of_clk_get_by_clkspec(struct of_phandle_args *clkspec,
+ const char *dev_id, const char *con_id)
+{
+ struct clk *clk;
+
+ if (!clkspec)
+ return ERR_PTR(-EINVAL);
+
+ of_clk_lock();
+ clk = __of_clk_get_from_provider(clkspec, dev_id, con_id);
+ of_clk_unlock();
+ return clk;
+}
+
/**
* of_clk_get_by_clkspec() - Lookup a clock form a clock provider
* @clkspec: pointer to a clock specifier data structure
@@ -38,22 +53,11 @@ static DEFINE_MUTEX(clocks_mutex);
*/
struct clk *of_clk_get_by_clkspec(struct of_phandle_args *clkspec)
{
- struct clk *clk;
-
- if (!clkspec)
- return ERR_PTR(-EINVAL);
-
- of_clk_lock();
- clk = __of_clk_get_from_provider(clkspec);
-
- if (!IS_ERR(clk) && !__clk_get(clk))
- clk = ERR_PTR(-ENOENT);
-
- of_clk_unlock();
- return clk;
+ return __of_clk_get_by_clkspec(clkspec, NULL, __func__);
}
-struct clk *of_clk_get(struct device_node *np, int index)
+static struct clk *__of_clk_get(struct device_node *np, int index,
+ const char *dev_id, const char *con_id)
{
struct of_phandle_args clkspec;
struct clk *clk;
@@ -67,22 +71,21 @@ struct clk *of_clk_get(struct device_node *np, int index)
if (rc)
return ERR_PTR(rc);
- clk = of_clk_get_by_clkspec(&clkspec);
+ clk = __of_clk_get_by_clkspec(&clkspec, dev_id, con_id);
of_node_put(clkspec.np);
+
return clk;
}
+
+struct clk *of_clk_get(struct device_node *np, int index)
+{
+ return __of_clk_get(np, index, np->full_name, NULL);
+}
EXPORT_SYMBOL(of_clk_get);
-/**
- * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
- * @np: pointer to clock consumer node
- * @name: name of consumer's clock input, or NULL for the first clock reference
- *
- * This function parses the clocks and clock-names properties,
- * and uses them to look up the struct clk from the registered list of clock
- * providers.
- */
-struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+static struct clk *__of_clk_get_by_name(struct device_node *np,
+ const char *dev_id,
+ const char *name)
{
struct clk *clk = ERR_PTR(-ENOENT);
@@ -97,10 +100,10 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
*/
if (name)
index = of_property_match_string(np, "clock-names", name);
- clk = of_clk_get(np, index);
- if (!IS_ERR(clk))
+ clk = __of_clk_get(np, index, dev_id, name);
+ if (!IS_ERR(clk)) {
break;
- else if (name && index >= 0) {
+ } else if (name && index >= 0) {
if (PTR_ERR(clk) != -EPROBE_DEFER)
pr_err("ERROR: could not get clock %s:%s(%i)\n",
np->full_name, name ? name : "", index);
@@ -119,7 +122,33 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
return clk;
}
+
+/**
+ * of_clk_get_by_name() - Parse and lookup a clock referenced by a device node
+ * @np: pointer to clock consumer node
+ * @name: name of consumer's clock input, or NULL for the first clock reference
+ *
+ * This function parses the clocks and clock-names properties,
+ * and uses them to look up the struct clk from the registered list of clock
+ * providers.
+ */
+struct clk *of_clk_get_by_name(struct device_node *np, const char *name)
+{
+ if (!np)
+ return ERR_PTR(-ENOENT);
+
+ return __of_clk_get_by_name(np, np->full_name, name);
+}
EXPORT_SYMBOL(of_clk_get_by_name);
+
+#else /* defined(CONFIG_OF) && defined(CONFIG_COMMON_CLK) */
+
+static struct clk *__of_clk_get_by_name(struct device_node *np,
+ const char *dev_id,
+ const char *name)
+{
+ return ERR_PTR(-ENOENT);
+}
#endif
/*
@@ -168,14 +197,28 @@ static struct clk_lookup *clk_find(const char *dev_id, const char *con_id)
struct clk *clk_get_sys(const char *dev_id, const char *con_id)
{
struct clk_lookup *cl;
+ struct clk *clk = NULL;
mutex_lock(&clocks_mutex);
+
cl = clk_find(dev_id, con_id);
- if (cl && !__clk_get(cl->clk))
+ if (!cl)
+ goto out;
+
+ clk = __clk_create_clk(__clk_get_hw(cl->clk), dev_id, con_id);
+ if (IS_ERR(clk))
+ goto out;
+
+ if (!__clk_get(clk)) {
+ __clk_free_clk(clk);
cl = NULL;
+ goto out;
+ }
+
+out:
mutex_unlock(&clocks_mutex);
- return cl ? cl->clk : ERR_PTR(-ENOENT);
+ return cl ? clk : ERR_PTR(-ENOENT);
}
EXPORT_SYMBOL(clk_get_sys);
@@ -185,10 +228,8 @@ struct clk *clk_get(struct device *dev, const char *con_id)
struct clk *clk;
if (dev) {
- clk = of_clk_get_by_name(dev->of_node, con_id);
- if (!IS_ERR(clk))
- return clk;
- if (PTR_ERR(clk) == -EPROBE_DEFER)
+ clk = __of_clk_get_by_name(dev->of_node, dev_id, con_id);
+ if (!IS_ERR(clk) || PTR_ERR(clk) == -EPROBE_DEFER)
return clk;
}
@@ -331,6 +372,7 @@ int clk_register_clkdev(struct clk *clk, const char *con_id,
return 0;
}
+EXPORT_SYMBOL(clk_register_clkdev);
/**
* clk_register_clkdevs - register a set of clk_lookup for a struct clk
diff --git a/drivers/clk/hisilicon/clk-hi3620.c b/drivers/clk/hisilicon/clk-hi3620.c
index 007144f81f50..2e4f6d432beb 100644
--- a/drivers/clk/hisilicon/clk-hi3620.c
+++ b/drivers/clk/hisilicon/clk-hi3620.c
@@ -295,6 +295,8 @@ static unsigned long mmc_clk_recalc_rate(struct clk_hw *hw,
}
static long mmc_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
diff --git a/drivers/clk/mmp/clk-mix.c b/drivers/clk/mmp/clk-mix.c
index 48fa53c7ce5e..de6a873175d2 100644
--- a/drivers/clk/mmp/clk-mix.c
+++ b/drivers/clk/mmp/clk-mix.c
@@ -202,6 +202,8 @@ error:
}
static long mmp_clk_mix_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/drivers/clk/pxa/Makefile b/drivers/clk/pxa/Makefile
index 38e915344605..38e37bf6b821 100644
--- a/drivers/clk/pxa/Makefile
+++ b/drivers/clk/pxa/Makefile
@@ -1,3 +1,4 @@
obj-y += clk-pxa.o
obj-$(CONFIG_PXA25x) += clk-pxa25x.o
obj-$(CONFIG_PXA27x) += clk-pxa27x.o
+obj-$(CONFIG_PXA3xx) += clk-pxa3xx.o
diff --git a/drivers/clk/pxa/clk-pxa.c b/drivers/clk/pxa/clk-pxa.c
index 4e834753ab09..29cee9e8d4d9 100644
--- a/drivers/clk/pxa/clk-pxa.c
+++ b/drivers/clk/pxa/clk-pxa.c
@@ -46,7 +46,7 @@ static unsigned long cken_recalc_rate(struct clk_hw *hw,
fix = &pclk->lp;
else
fix = &pclk->hp;
- fix->hw.clk = hw->clk;
+ __clk_hw_set_clk(&fix->hw, hw);
return clk_fixed_factor_ops.recalc_rate(&fix->hw, parent_rate);
}
diff --git a/drivers/clk/pxa/clk-pxa3xx.c b/drivers/clk/pxa/clk-pxa3xx.c
new file mode 100644
index 000000000000..39f891bba09a
--- /dev/null
+++ b/drivers/clk/pxa/clk-pxa3xx.c
@@ -0,0 +1,364 @@
+/*
+ * Marvell PXA3xxx family clocks
+ *
+ * Copyright (C) 2014 Robert Jarzmik
+ *
+ * Heavily inspired from former arch/arm/mach-pxa/pxa3xx.c
+ *
+ * This program is free software; 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.
+ *
+ * For non-devicetree platforms. Once pxa is fully converted to devicetree, this
+ * should go away.
+ */
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/of.h>
+#include <mach/smemc.h>
+#include <mach/pxa3xx-regs.h>
+
+#include <dt-bindings/clock/pxa-clock.h>
+#include "clk-pxa.h"
+
+#define KHz 1000
+#define MHz (1000 * 1000)
+
+enum {
+ PXA_CORE_60Mhz = 0,
+ PXA_CORE_RUN,
+ PXA_CORE_TURBO,
+};
+
+enum {
+ PXA_BUS_60Mhz = 0,
+ PXA_BUS_HSS,
+};
+
+/* crystal frequency to HSIO bus frequency multiplier (HSS) */
+static unsigned char hss_mult[4] = { 8, 12, 16, 24 };
+
+/* crystal frequency to static memory controller multiplier (SMCFS) */
+static unsigned int smcfs_mult[8] = { 6, 0, 8, 0, 0, 16, };
+static unsigned int df_clkdiv[4] = { 1, 2, 4, 1 };
+
+static const char * const get_freq_khz[] = {
+ "core", "ring_osc_60mhz", "run", "cpll", "system_bus"
+};
+
+/*
+ * Get the clock frequency as reflected by ACSR and the turbo flag.
+ * We assume these values have been applied via a fcs.
+ * If info is not 0 we also display the current settings.
+ */
+unsigned int pxa3xx_get_clk_frequency_khz(int info)
+{
+ struct clk *clk;
+ unsigned long clks[5];
+ int i;
+
+ for (i = 0; i < 5; i++) {
+ clk = clk_get(NULL, get_freq_khz[i]);
+ if (IS_ERR(clk)) {
+ clks[i] = 0;
+ } else {
+ clks[i] = clk_get_rate(clk);
+ clk_put(clk);
+ }
+ }
+ if (info) {
+ pr_info("RO Mode clock: %ld.%02ldMHz\n",
+ clks[1] / 1000000, (clks[0] % 1000000) / 10000);
+ pr_info("Run Mode clock: %ld.%02ldMHz\n",
+ clks[2] / 1000000, (clks[1] % 1000000) / 10000);
+ pr_info("Turbo Mode clock: %ld.%02ldMHz\n",
+ clks[3] / 1000000, (clks[2] % 1000000) / 10000);
+ pr_info("System bus clock: %ld.%02ldMHz\n",
+ clks[4] / 1000000, (clks[4] % 1000000) / 10000);
+ }
+ return (unsigned int)clks[0];
+}
+
+static unsigned long clk_pxa3xx_ac97_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long ac97_div, rate;
+
+ ac97_div = AC97_DIV;
+
+ /* This may loose precision for some rates but won't for the
+ * standard 24.576MHz.
+ */
+ rate = parent_rate / 2;
+ rate /= ((ac97_div >> 12) & 0x7fff);
+ rate *= (ac97_div & 0xfff);
+
+ return rate;
+}
+PARENTS(clk_pxa3xx_ac97) = { "spll_624mhz" };
+RATE_RO_OPS(clk_pxa3xx_ac97, "ac97");
+
+static unsigned long clk_pxa3xx_smemc_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned long memclkcfg = __raw_readl(MEMCLKCFG);
+
+ return (parent_rate / 48) * smcfs_mult[(acsr >> 23) & 0x7] /
+ df_clkdiv[(memclkcfg >> 16) & 0x3];
+}
+PARENTS(clk_pxa3xx_smemc) = { "spll_624mhz" };
+RATE_RO_OPS(clk_pxa3xx_smemc, "smemc");
+
+static bool pxa3xx_is_ring_osc_forced(void)
+{
+ unsigned long acsr = ACSR;
+
+ return acsr & ACCR_D0CS;
+}
+
+PARENTS(pxa3xx_pbus) = { "ring_osc_60mhz", "spll_624mhz" };
+PARENTS(pxa3xx_32Khz_bus) = { "osc_32_768khz", "osc_32_768khz" };
+PARENTS(pxa3xx_13MHz_bus) = { "osc_13mhz", "osc_13mhz" };
+PARENTS(pxa3xx_ac97_bus) = { "ring_osc_60mhz", "ac97" };
+PARENTS(pxa3xx_sbus) = { "ring_osc_60mhz", "system_bus" };
+PARENTS(pxa3xx_smemcbus) = { "ring_osc_60mhz", "smemc" };
+
+#define CKEN_AB(bit) ((CKEN_ ## bit > 31) ? &CKENA : &CKENB)
+#define PXA3XX_CKEN(dev_id, con_id, parents, mult_lp, div_lp, mult_hp, \
+ div_hp, bit, is_lp, flags) \
+ PXA_CKEN(dev_id, con_id, bit, parents, mult_lp, div_lp, \
+ mult_hp, div_hp, is_lp, CKEN_AB(bit), \
+ (CKEN_ ## bit % 32), flags)
+#define PXA3XX_PBUS_CKEN(dev_id, con_id, bit, mult_lp, div_lp, \
+ mult_hp, div_hp, delay) \
+ PXA3XX_CKEN(dev_id, con_id, pxa3xx_pbus_parents, mult_lp, \
+ div_lp, mult_hp, div_hp, bit, pxa3xx_is_ring_osc_forced, 0)
+#define PXA3XX_CKEN_1RATE(dev_id, con_id, bit, parents) \
+ PXA_CKEN_1RATE(dev_id, con_id, bit, parents, \
+ CKEN_AB(bit), (CKEN_ ## bit % 32), 0)
+
+static struct desc_clk_cken pxa3xx_clocks[] __initdata = {
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.0", NULL, FFUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.1", NULL, BTUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-uart.2", NULL, STUART, 1, 4, 1, 42, 1),
+ PXA3XX_PBUS_CKEN("pxa2xx-i2c.0", NULL, I2C, 2, 5, 1, 19, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-udc", NULL, UDC, 1, 4, 1, 13, 5),
+ PXA3XX_PBUS_CKEN("pxa27x-ohci", NULL, USBH, 1, 4, 1, 13, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-u2d", NULL, USB2, 1, 4, 1, 13, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-pwm.0", NULL, PWM0, 1, 6, 1, 48, 0),
+ PXA3XX_PBUS_CKEN("pxa27x-pwm.1", NULL, PWM1, 1, 6, 1, 48, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.0", NULL, MMC1, 1, 4, 1, 24, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.1", NULL, MMC2, 1, 4, 1, 24, 0),
+ PXA3XX_PBUS_CKEN("pxa2xx-mci.2", NULL, MMC3, 1, 4, 1, 24, 0),
+
+ PXA3XX_CKEN_1RATE("pxa27x-keypad", NULL, KEYPAD,
+ pxa3xx_32Khz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.0", NULL, SSP1, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.1", NULL, SSP2, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.2", NULL, SSP3, pxa3xx_13MHz_bus_parents),
+ PXA3XX_CKEN_1RATE("pxa3xx-ssp.3", NULL, SSP4, pxa3xx_13MHz_bus_parents),
+
+ PXA3XX_CKEN(NULL, "AC97CLK", pxa3xx_ac97_bus_parents, 1, 4, 1, 1, AC97,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN(NULL, "CAMCLK", pxa3xx_sbus_parents, 1, 2, 1, 1, CAMERA,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN("pxa2xx-fb", NULL, pxa3xx_sbus_parents, 1, 1, 1, 1, LCD,
+ pxa3xx_is_ring_osc_forced, 0),
+ PXA3XX_CKEN("pxa2xx-pcmcia", NULL, pxa3xx_smemcbus_parents, 1, 4,
+ 1, 1, SMC, pxa3xx_is_ring_osc_forced, CLK_IGNORE_UNUSED),
+};
+
+static struct desc_clk_cken pxa300_310_clocks[] __initdata = {
+
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
+ PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static struct desc_clk_cken pxa320_clocks[] __initdata = {
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 6, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA320_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_CKEN_1RATE("pxa3xx-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static struct desc_clk_cken pxa93x_clocks[] __initdata = {
+
+ PXA3XX_PBUS_CKEN("pxa3xx-gcu", NULL, PXA300_GCU, 1, 1, 1, 1, 0),
+ PXA3XX_PBUS_CKEN("pxa3xx-nand", NULL, NAND, 1, 2, 1, 4, 0),
+ PXA3XX_CKEN_1RATE("pxa93x-gpio", NULL, GPIO, pxa3xx_13MHz_bus_parents),
+};
+
+static unsigned long clk_pxa3xx_system_bus_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int hss = (acsr >> 14) & 0x3;
+
+ if (pxa3xx_is_ring_osc_forced())
+ return parent_rate;
+ return parent_rate / 48 * hss_mult[hss];
+}
+
+static u8 clk_pxa3xx_system_bus_get_parent(struct clk_hw *hw)
+{
+ if (pxa3xx_is_ring_osc_forced())
+ return PXA_BUS_60Mhz;
+ else
+ return PXA_BUS_HSS;
+}
+
+PARENTS(clk_pxa3xx_system_bus) = { "ring_osc_60mhz", "spll_624mhz" };
+MUX_RO_RATE_RO_OPS(clk_pxa3xx_system_bus, "system_bus");
+
+static unsigned long clk_pxa3xx_core_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ return parent_rate;
+}
+
+static u8 clk_pxa3xx_core_get_parent(struct clk_hw *hw)
+{
+ unsigned long xclkcfg;
+ unsigned int t;
+
+ if (pxa3xx_is_ring_osc_forced())
+ return PXA_CORE_60Mhz;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ if (t)
+ return PXA_CORE_TURBO;
+ return PXA_CORE_RUN;
+}
+PARENTS(clk_pxa3xx_core) = { "ring_osc_60mhz", "run", "cpll" };
+MUX_RO_RATE_RO_OPS(clk_pxa3xx_core, "core");
+
+static unsigned long clk_pxa3xx_run_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
+ unsigned int t, xclkcfg;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ return t ? (parent_rate / xn) * 2 : parent_rate;
+}
+PARENTS(clk_pxa3xx_run) = { "cpll" };
+RATE_RO_OPS(clk_pxa3xx_run, "run");
+
+static unsigned long clk_pxa3xx_cpll_get_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ unsigned long acsr = ACSR;
+ unsigned int xn = (acsr & ACCR_XN_MASK) >> 8;
+ unsigned int xl = acsr & ACCR_XL_MASK;
+ unsigned int t, xclkcfg;
+
+ /* Read XCLKCFG register turbo bit */
+ __asm__ __volatile__("mrc\tp14, 0, %0, c6, c0, 0" : "=r"(xclkcfg));
+ t = xclkcfg & 0x1;
+
+ pr_info("RJK: parent_rate=%lu, xl=%u, xn=%u\n", parent_rate, xl, xn);
+ return t ? parent_rate * xl * xn : parent_rate * xl;
+}
+PARENTS(clk_pxa3xx_cpll) = { "osc_13mhz" };
+RATE_RO_OPS(clk_pxa3xx_cpll, "cpll");
+
+static void __init pxa3xx_register_core(void)
+{
+ clk_register_clk_pxa3xx_cpll();
+ clk_register_clk_pxa3xx_run();
+
+ clkdev_pxa_register(CLK_CORE, "core", NULL,
+ clk_register_clk_pxa3xx_core());
+}
+
+static void __init pxa3xx_register_plls(void)
+{
+ clk_register_fixed_rate(NULL, "osc_13mhz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 13 * MHz);
+ clk_register_fixed_rate(NULL, "osc_32_768khz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 32768);
+ clk_register_fixed_rate(NULL, "ring_osc_120mhz", NULL,
+ CLK_GET_RATE_NOCACHE | CLK_IS_ROOT,
+ 120 * MHz);
+ clk_register_fixed_rate(NULL, "clk_dummy", NULL, CLK_IS_ROOT, 0);
+ clk_register_fixed_factor(NULL, "spll_624mhz", "osc_13mhz", 0, 48, 1);
+ clk_register_fixed_factor(NULL, "ring_osc_60mhz", "ring_osc_120mhz",
+ 0, 1, 2);
+}
+
+#define DUMMY_CLK(_con_id, _dev_id, _parent) \
+ { .con_id = _con_id, .dev_id = _dev_id, .parent = _parent }
+struct dummy_clk {
+ const char *con_id;
+ const char *dev_id;
+ const char *parent;
+};
+static struct dummy_clk dummy_clks[] __initdata = {
+ DUMMY_CLK(NULL, "pxa93x-gpio", "osc_13mhz"),
+ DUMMY_CLK(NULL, "sa1100-rtc", "osc_32_768khz"),
+ DUMMY_CLK("UARTCLK", "pxa2xx-ir", "STUART"),
+ DUMMY_CLK(NULL, "pxa3xx-pwri2c.1", "osc_13mhz"),
+};
+
+static void __init pxa3xx_dummy_clocks_init(void)
+{
+ struct clk *clk;
+ struct dummy_clk *d;
+ const char *name;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dummy_clks); i++) {
+ d = &dummy_clks[i];
+ name = d->dev_id ? d->dev_id : d->con_id;
+ clk = clk_register_fixed_factor(NULL, name, d->parent, 0, 1, 1);
+ clk_register_clkdev(clk, d->con_id, d->dev_id);
+ }
+}
+
+static void __init pxa3xx_base_clocks_init(void)
+{
+ pxa3xx_register_plls();
+ pxa3xx_register_core();
+ clk_register_clk_pxa3xx_system_bus();
+ clk_register_clk_pxa3xx_ac97();
+ clk_register_clk_pxa3xx_smemc();
+ clk_register_gate(NULL, "CLK_POUT", "osc_13mhz", 0,
+ (void __iomem *)&OSCC, 11, 0, NULL);
+}
+
+int __init pxa3xx_clocks_init(void)
+{
+ int ret;
+
+ pxa3xx_base_clocks_init();
+ pxa3xx_dummy_clocks_init();
+ ret = clk_pxa_cken_init(pxa3xx_clocks, ARRAY_SIZE(pxa3xx_clocks));
+ if (ret)
+ return ret;
+ if (cpu_is_pxa320())
+ return clk_pxa_cken_init(pxa320_clocks,
+ ARRAY_SIZE(pxa320_clocks));
+ if (cpu_is_pxa300() || cpu_is_pxa310())
+ return clk_pxa_cken_init(pxa300_310_clocks,
+ ARRAY_SIZE(pxa300_310_clocks));
+ return clk_pxa_cken_init(pxa93x_clocks, ARRAY_SIZE(pxa93x_clocks));
+}
+
+static void __init pxa3xx_dt_clocks_init(struct device_node *np)
+{
+ pxa3xx_clocks_init();
+ clk_pxa_dt_common_init(np);
+}
+CLK_OF_DECLARE(pxa_clks, "marvell,pxa300-clocks", pxa3xx_dt_clocks_init);
diff --git a/drivers/clk/qcom/Kconfig b/drivers/clk/qcom/Kconfig
index 1107351ed346..0d7ab52b7ab0 100644
--- a/drivers/clk/qcom/Kconfig
+++ b/drivers/clk/qcom/Kconfig
@@ -29,6 +29,15 @@ config IPQ_GCC_806X
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, etc.
+config IPQ_LCC_806X
+ tristate "IPQ806x LPASS Clock Controller"
+ select IPQ_GCC_806X
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the LPASS clock controller on ipq806x devices.
+ Say Y if you want to use audio devices such as i2s, pcm,
+ S/PDIF, etc.
+
config MSM_GCC_8660
tristate "MSM8660 Global Clock Controller"
depends on COMMON_CLK_QCOM
@@ -45,6 +54,15 @@ config MSM_GCC_8960
Say Y if you want to use peripheral devices such as UART, SPI,
i2c, USB, SD/eMMC, SATA, PCIe, etc.
+config MSM_LCC_8960
+ tristate "APQ8064/MSM8960 LPASS Clock Controller"
+ select MSM_GCC_8960
+ depends on COMMON_CLK_QCOM
+ help
+ Support for the LPASS clock controller on apq8064/msm8960 devices.
+ Say Y if you want to use audio devices such as i2s, pcm,
+ SLIMBus, etc.
+
config MSM_MMCC_8960
tristate "MSM8960 Multimedia Clock Controller"
select MSM_GCC_8960
diff --git a/drivers/clk/qcom/Makefile b/drivers/clk/qcom/Makefile
index 783cfb24faa4..617826469595 100644
--- a/drivers/clk/qcom/Makefile
+++ b/drivers/clk/qcom/Makefile
@@ -6,13 +6,17 @@ clk-qcom-y += clk-pll.o
clk-qcom-y += clk-rcg.o
clk-qcom-y += clk-rcg2.o
clk-qcom-y += clk-branch.o
+clk-qcom-y += clk-regmap-divider.o
+clk-qcom-y += clk-regmap-mux.o
clk-qcom-y += reset.o
obj-$(CONFIG_APQ_GCC_8084) += gcc-apq8084.o
obj-$(CONFIG_APQ_MMCC_8084) += mmcc-apq8084.o
obj-$(CONFIG_IPQ_GCC_806X) += gcc-ipq806x.o
+obj-$(CONFIG_IPQ_LCC_806X) += lcc-ipq806x.o
obj-$(CONFIG_MSM_GCC_8660) += gcc-msm8660.o
obj-$(CONFIG_MSM_GCC_8960) += gcc-msm8960.o
+obj-$(CONFIG_MSM_LCC_8960) += lcc-msm8960.o
obj-$(CONFIG_MSM_GCC_8974) += gcc-msm8974.o
obj-$(CONFIG_MSM_MMCC_8960) += mmcc-msm8960.o
obj-$(CONFIG_MSM_MMCC_8974) += mmcc-msm8974.o
diff --git a/drivers/clk/qcom/clk-pll.c b/drivers/clk/qcom/clk-pll.c
index 60873a7f45d9..b4325f65a1bf 100644
--- a/drivers/clk/qcom/clk-pll.c
+++ b/drivers/clk/qcom/clk-pll.c
@@ -141,6 +141,7 @@ struct pll_freq_tbl *find_freq(const struct pll_freq_tbl *f, unsigned long rate)
static long
clk_pll_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_pll *pll = to_clk_pll(hw);
diff --git a/drivers/clk/qcom/clk-rcg.c b/drivers/clk/qcom/clk-rcg.c
index 0b93972c8807..0039bd7d3965 100644
--- a/drivers/clk/qcom/clk-rcg.c
+++ b/drivers/clk/qcom/clk-rcg.c
@@ -368,6 +368,7 @@ clk_dyn_rcg_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
static long _freq_tbl_determine_rate(struct clk_hw *hw,
const struct freq_tbl *f, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
unsigned long clk_flags;
@@ -397,22 +398,27 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
}
static long clk_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
+ max_rate, p_rate, p);
}
static long clk_dyn_rcg_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_dyn_rcg *rcg = to_clk_dyn_rcg(hw);
- return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, p_rate, p);
+ return _freq_tbl_determine_rate(hw, rcg->freq_tbl, rate, min_rate,
+ max_rate, p_rate, p);
}
static long clk_rcg_bypass_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg *rcg = to_clk_rcg(hw);
diff --git a/drivers/clk/qcom/clk-rcg2.c b/drivers/clk/qcom/clk-rcg2.c
index 08b8b3729f53..742acfa18d63 100644
--- a/drivers/clk/qcom/clk-rcg2.c
+++ b/drivers/clk/qcom/clk-rcg2.c
@@ -208,6 +208,7 @@ static long _freq_tbl_determine_rate(struct clk_hw *hw,
}
static long clk_rcg2_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -361,6 +362,8 @@ static int clk_edp_pixel_set_rate_and_parent(struct clk_hw *hw,
}
static long clk_edp_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -412,6 +415,7 @@ const struct clk_ops clk_edp_pixel_ops = {
EXPORT_SYMBOL_GPL(clk_edp_pixel_ops);
static long clk_byte_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate, unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p_hw)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
@@ -476,6 +480,8 @@ static const struct frac_entry frac_table_pixel[] = {
};
static long clk_pixel_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *p_rate, struct clk_hw **p)
{
struct clk_rcg2 *rcg = to_clk_rcg2(hw);
diff --git a/drivers/clk/qcom/clk-regmap-divider.c b/drivers/clk/qcom/clk-regmap-divider.c
new file mode 100644
index 000000000000..53484912301e
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-divider.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-divider.h"
+
+static inline struct clk_regmap_div *to_clk_regmap_div(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_regmap_div, clkr);
+}
+
+static long div_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+
+ return divider_round_rate(hw, rate, prate, NULL, divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+static int div_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+ struct clk_regmap *clkr = &divider->clkr;
+ u32 div;
+
+ div = divider_get_val(rate, parent_rate, NULL, divider->width,
+ CLK_DIVIDER_ROUND_CLOSEST);
+
+ return regmap_update_bits(clkr->regmap, divider->reg,
+ (BIT(divider->width) - 1) << divider->shift,
+ div << divider->shift);
+}
+
+static unsigned long div_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_regmap_div *divider = to_clk_regmap_div(hw);
+ struct clk_regmap *clkr = &divider->clkr;
+ u32 div;
+
+ regmap_read(clkr->regmap, divider->reg, &div);
+ div >>= divider->shift;
+ div &= BIT(divider->width) - 1;
+
+ return divider_recalc_rate(hw, parent_rate, div, NULL,
+ CLK_DIVIDER_ROUND_CLOSEST);
+}
+
+const struct clk_ops clk_regmap_div_ops = {
+ .round_rate = div_round_rate,
+ .set_rate = div_set_rate,
+ .recalc_rate = div_recalc_rate,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_div_ops);
diff --git a/drivers/clk/qcom/clk-regmap-divider.h b/drivers/clk/qcom/clk-regmap-divider.h
new file mode 100644
index 000000000000..fc4492e3a827
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-divider.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_DIVIDER_H__
+#define __QCOM_CLK_REGMAP_DIVIDER_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_div {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_regmap_div_ops;
+
+#endif
diff --git a/drivers/clk/qcom/clk-regmap-mux.c b/drivers/clk/qcom/clk-regmap-mux.c
new file mode 100644
index 000000000000..cae3071f384c
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/regmap.h>
+#include <linux/export.h>
+
+#include "clk-regmap-mux.h"
+
+static inline struct clk_regmap_mux *to_clk_regmap_mux(struct clk_hw *hw)
+{
+ return container_of(to_clk_regmap(hw), struct clk_regmap_mux, clkr);
+}
+
+static u8 mux_get_parent(struct clk_hw *hw)
+{
+ struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ unsigned int mask = GENMASK(mux->width - 1, 0);
+ unsigned int val;
+
+ regmap_read(clkr->regmap, mux->reg, &val);
+
+ val >>= mux->shift;
+ val &= mask;
+
+ return val;
+}
+
+static int mux_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_regmap_mux *mux = to_clk_regmap_mux(hw);
+ struct clk_regmap *clkr = to_clk_regmap(hw);
+ unsigned int mask = GENMASK(mux->width + mux->shift - 1, mux->shift);
+ unsigned int val;
+
+ val = index;
+ val <<= mux->shift;
+
+ return regmap_update_bits(clkr->regmap, mux->reg, mask, val);
+}
+
+const struct clk_ops clk_regmap_mux_closest_ops = {
+ .get_parent = mux_get_parent,
+ .set_parent = mux_set_parent,
+ .determine_rate = __clk_mux_determine_rate_closest,
+};
+EXPORT_SYMBOL_GPL(clk_regmap_mux_closest_ops);
diff --git a/drivers/clk/qcom/clk-regmap-mux.h b/drivers/clk/qcom/clk-regmap-mux.h
new file mode 100644
index 000000000000..5cec76154fda
--- /dev/null
+++ b/drivers/clk/qcom/clk-regmap-mux.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __QCOM_CLK_REGMAP_MUX_H__
+#define __QCOM_CLK_REGMAP_MUX_H__
+
+#include <linux/clk-provider.h>
+#include "clk-regmap.h"
+
+struct clk_regmap_mux {
+ u32 reg;
+ u32 shift;
+ u32 width;
+ struct clk_regmap clkr;
+};
+
+extern const struct clk_ops clk_regmap_mux_closest_ops;
+
+#endif
diff --git a/drivers/clk/qcom/gcc-ipq806x.c b/drivers/clk/qcom/gcc-ipq806x.c
index afed5eb0691e..cbdc31dea7f4 100644
--- a/drivers/clk/qcom/gcc-ipq806x.c
+++ b/drivers/clk/qcom/gcc-ipq806x.c
@@ -75,6 +75,17 @@ static struct clk_pll pll3 = {
},
};
+static struct clk_regmap pll4_vote = {
+ .enable_reg = 0x34c0,
+ .enable_mask = BIT(4),
+ .hw.init = &(struct clk_init_data){
+ .name = "pll4_vote",
+ .parent_names = (const char *[]){ "pll4" },
+ .num_parents = 1,
+ .ops = &clk_pll_vote_ops,
+ },
+};
+
static struct clk_pll pll8 = {
.l_reg = 0x3144,
.m_reg = 0x3148,
@@ -2163,6 +2174,7 @@ static struct clk_regmap *gcc_ipq806x_clks[] = {
[PLL0] = &pll0.clkr,
[PLL0_VOTE] = &pll0_vote,
[PLL3] = &pll3.clkr,
+ [PLL4_VOTE] = &pll4_vote,
[PLL8] = &pll8.clkr,
[PLL8_VOTE] = &pll8_vote,
[PLL14] = &pll14.clkr,
diff --git a/drivers/clk/qcom/lcc-ipq806x.c b/drivers/clk/qcom/lcc-ipq806x.c
new file mode 100644
index 000000000000..121ffde25dc3
--- /dev/null
+++ b/drivers/clk/qcom/lcc-ipq806x.c
@@ -0,0 +1,473 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-ipq806x.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+ .l_reg = 0x4,
+ .m_reg = 0x8,
+ .n_reg = 0xc,
+ .config_reg = 0x14,
+ .mode_reg = 0x0,
+ .status_reg = 0x18,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll4",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+static const struct pll_config pll4_config = {
+ .l = 0xf,
+ .m = 0x91,
+ .n = 0xc7,
+ .vco_val = 0x0,
+ .vco_mask = BIT(17) | BIT(16),
+ .pre_div_val = 0x0,
+ .pre_div_mask = BIT(19),
+ .post_div_val = 0x0,
+ .post_div_mask = BIT(21) | BIT(20),
+ .mn_ena_mask = BIT(22),
+ .main_output_mask = BIT(23),
+};
+
+#define P_PXO 0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+ [P_PXO] = 0,
+ [P_PLL4] = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+ "pxo",
+ "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_mi2s[] = {
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1411200, P_PLL4, 4, 2, 139 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 2116800, P_PLL4, 4, 2, 93 },
+ { 2304000, P_PLL4, 4, 2, 85 },
+ { 2822400, P_PLL4, 4, 6, 209 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 3175200, P_PLL4, 4, 1, 31 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 4233600, P_PLL4, 4, 9, 209 },
+ { 4608000, P_PLL4, 4, 3, 64 },
+ { 5644800, P_PLL4, 4, 12, 209 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 6350400, P_PLL4, 4, 2, 31 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 8467200, P_PLL4, 4, 18, 209 },
+ { 9216000, P_PLL4, 4, 3, 32 },
+ { 11289600, P_PLL4, 4, 24, 209 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 12700800, P_PLL4, 4, 27, 209 },
+ { 13824000, P_PLL4, 4, 9, 64 },
+ { 16384000, P_PLL4, 4, 1, 6 },
+ { 16934400, P_PLL4, 4, 41, 238 },
+ { 18432000, P_PLL4, 4, 3, 16 },
+ { 22579200, P_PLL4, 2, 24, 209 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27648000, P_PLL4, 4, 9, 32 },
+ { 33868800, P_PLL4, 4, 41, 119 },
+ { 36864000, P_PLL4, 4, 3, 8 },
+ { 45158400, P_PLL4, 1, 24, 209 },
+ { 49152000, P_PLL4, 4, 1, 2 },
+ { 50803200, P_PLL4, 1, 27, 209 },
+ { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+ .ns_reg = 0x48,
+ .md_reg = 0x4c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_mi2s,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_mi2s_parents[] = {
+ "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+ .reg = 0x48,
+ .shift = 10,
+ .width = 4,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_div_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_div_clk",
+ .parent_names = (const char *[]){ "mi2s_div_clk" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+ .reg = 0x48,
+ .shift = 14,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_clk",
+ .parent_names = (const char *[]){
+ "mi2s_bit_div_clk",
+ "mi2s_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_pcm[] = {
+ { 64000, P_PLL4, 4, 1, 1536 },
+ { 128000, P_PLL4, 4, 1, 768 },
+ { 256000, P_PLL4, 4, 1, 384 },
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { },
+};
+
+static struct clk_rcg pcm_src = {
+ .ns_reg = 0x54,
+ .md_reg = 0x58,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 16,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_pcm,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_branch pcm_clk_out = {
+ .halt_reg = 0x5c,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk_out",
+ .parent_names = (const char *[]){ "pcm_src" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+ .reg = 0x54,
+ .shift = 10,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk",
+ .parent_names = (const char *[]){
+ "pcm_clk_out",
+ "pcm_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_aif_osr[] = {
+ { 22050, P_PLL4, 1, 147, 20480 },
+ { 32000, P_PLL4, 1, 1, 96 },
+ { 44100, P_PLL4, 1, 147, 10240 },
+ { 48000, P_PLL4, 1, 1, 64 },
+ { 88200, P_PLL4, 1, 147, 5120 },
+ { 96000, P_PLL4, 1, 1, 32 },
+ { 176400, P_PLL4, 1, 147, 2560 },
+ { 192000, P_PLL4, 1, 1, 16 },
+ { },
+};
+
+static struct clk_rcg spdif_src = {
+ .ns_reg = 0xcc,
+ .md_reg = 0xd0,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "spdif_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_spdif_parents[] = {
+ "spdif_src",
+};
+
+static struct clk_branch spdif_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "spdif_clk",
+ .parent_names = lcc_spdif_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct freq_tbl clk_tbl_ahbix[] = {
+ { 131072, P_PLL4, 1, 1, 3 },
+ { },
+};
+
+static struct clk_rcg ahbix_clk = {
+ .ns_reg = 0x38,
+ .md_reg = 0x3c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_ahbix,
+ .clkr = {
+ .enable_reg = 0x38,
+ .enable_mask = BIT(10), /* toggle the gfmux to select mn/pxo */
+ .hw.init = &(struct clk_init_data){
+ .name = "ahbix",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_regmap *lcc_ipq806x_clks[] = {
+ [PLL4] = &pll4.clkr,
+ [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+ [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+ [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+ [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+ [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+ [PCM_SRC] = &pcm_src.clkr,
+ [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+ [PCM_CLK] = &pcm_clk.clkr,
+ [SPDIF_SRC] = &spdif_src.clkr,
+ [SPDIF_CLK] = &spdif_clk.clkr,
+ [AHBIX_CLK] = &ahbix_clk.clkr,
+};
+
+static const struct regmap_config lcc_ipq806x_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc lcc_ipq806x_desc = {
+ .config = &lcc_ipq806x_regmap_config,
+ .clks = lcc_ipq806x_clks,
+ .num_clks = ARRAY_SIZE(lcc_ipq806x_clks),
+};
+
+static const struct of_device_id lcc_ipq806x_match_table[] = {
+ { .compatible = "qcom,lcc-ipq8064" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcc_ipq806x_match_table);
+
+static int lcc_ipq806x_probe(struct platform_device *pdev)
+{
+ u32 val;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &lcc_ipq806x_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Configure the rate of PLL4 if the bootloader hasn't already */
+ val = regmap_read(regmap, 0x0, &val);
+ if (!val)
+ clk_pll_configure_sr(&pll4, regmap, &pll4_config, true);
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ regmap_write(regmap, 0xc4, 0x1);
+
+ return qcom_cc_really_probe(pdev, &lcc_ipq806x_desc, regmap);
+}
+
+static int lcc_ipq806x_remove(struct platform_device *pdev)
+{
+ qcom_cc_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver lcc_ipq806x_driver = {
+ .probe = lcc_ipq806x_probe,
+ .remove = lcc_ipq806x_remove,
+ .driver = {
+ .name = "lcc-ipq806x",
+ .owner = THIS_MODULE,
+ .of_match_table = lcc_ipq806x_match_table,
+ },
+};
+module_platform_driver(lcc_ipq806x_driver);
+
+MODULE_DESCRIPTION("QCOM LCC IPQ806x Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-ipq806x");
diff --git a/drivers/clk/qcom/lcc-msm8960.c b/drivers/clk/qcom/lcc-msm8960.c
new file mode 100644
index 000000000000..a75a408cfccd
--- /dev/null
+++ b/drivers/clk/qcom/lcc-msm8960.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/bitops.h>
+#include <linux/err.h>
+#include <linux/platform_device.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/clk-provider.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/clock/qcom,lcc-msm8960.h>
+
+#include "common.h"
+#include "clk-regmap.h"
+#include "clk-pll.h"
+#include "clk-rcg.h"
+#include "clk-branch.h"
+#include "clk-regmap-divider.h"
+#include "clk-regmap-mux.h"
+
+static struct clk_pll pll4 = {
+ .l_reg = 0x4,
+ .m_reg = 0x8,
+ .n_reg = 0xc,
+ .config_reg = 0x14,
+ .mode_reg = 0x0,
+ .status_reg = 0x18,
+ .status_bit = 16,
+ .clkr.hw.init = &(struct clk_init_data){
+ .name = "pll4",
+ .parent_names = (const char *[]){ "pxo" },
+ .num_parents = 1,
+ .ops = &clk_pll_ops,
+ },
+};
+
+#define P_PXO 0
+#define P_PLL4 1
+
+static const u8 lcc_pxo_pll4_map[] = {
+ [P_PXO] = 0,
+ [P_PLL4] = 2,
+};
+
+static const char *lcc_pxo_pll4[] = {
+ "pxo",
+ "pll4_vote",
+};
+
+static struct freq_tbl clk_tbl_aif_osr_492[] = {
+ { 512000, P_PLL4, 4, 1, 240 },
+ { 768000, P_PLL4, 4, 1, 160 },
+ { 1024000, P_PLL4, 4, 1, 120 },
+ { 1536000, P_PLL4, 4, 1, 80 },
+ { 2048000, P_PLL4, 4, 1, 60 },
+ { 3072000, P_PLL4, 4, 1, 40 },
+ { 4096000, P_PLL4, 4, 1, 30 },
+ { 6144000, P_PLL4, 4, 1, 20 },
+ { 8192000, P_PLL4, 4, 1, 15 },
+ { 12288000, P_PLL4, 4, 1, 10 },
+ { 24576000, P_PLL4, 4, 1, 5 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct freq_tbl clk_tbl_aif_osr_393[] = {
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 768000, P_PLL4, 4, 1, 128 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct clk_rcg mi2s_osr_src = {
+ .ns_reg = 0x48,
+ .md_reg = 0x4c,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 24,
+ .m_val_shift = 8,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr_393,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_mi2s_parents[] = {
+ "mi2s_osr_src",
+};
+
+static struct clk_branch mi2s_osr_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(17),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_osr_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_div mi2s_div_clk = {
+ .reg = 0x48,
+ .shift = 10,
+ .width = 4,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_div_clk",
+ .parent_names = lcc_mi2s_parents,
+ .num_parents = 1,
+ .ops = &clk_regmap_div_ops,
+ },
+ },
+};
+
+static struct clk_branch mi2s_bit_div_clk = {
+ .halt_reg = 0x50,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x48,
+ .enable_mask = BIT(15),
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_div_clk",
+ .parent_names = (const char *[]){ "mi2s_div_clk" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux mi2s_bit_clk = {
+ .reg = 0x48,
+ .shift = 14,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "mi2s_bit_clk",
+ .parent_names = (const char *[]){
+ "mi2s_bit_div_clk",
+ "mi2s_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+#define CLK_AIF_OSR_DIV(prefix, _ns, _md, hr) \
+static struct clk_rcg prefix##_osr_src = { \
+ .ns_reg = _ns, \
+ .md_reg = _md, \
+ .mn = { \
+ .mnctr_en_bit = 8, \
+ .mnctr_reset_bit = 7, \
+ .mnctr_mode_shift = 5, \
+ .n_val_shift = 24, \
+ .m_val_shift = 8, \
+ .width = 8, \
+ }, \
+ .p = { \
+ .pre_div_shift = 3, \
+ .pre_div_width = 2, \
+ }, \
+ .s = { \
+ .src_sel_shift = 0, \
+ .parent_map = lcc_pxo_pll4_map, \
+ }, \
+ .freq_tbl = clk_tbl_aif_osr_393, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(9), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_osr_src", \
+ .parent_names = lcc_pxo_pll4, \
+ .num_parents = 2, \
+ .ops = &clk_rcg_ops, \
+ .flags = CLK_SET_RATE_GATE, \
+ }, \
+ }, \
+}; \
+ \
+static const char *lcc_##prefix##_parents[] = { \
+ #prefix "_osr_src", \
+}; \
+ \
+static struct clk_branch prefix##_osr_clk = { \
+ .halt_reg = hr, \
+ .halt_bit = 1, \
+ .halt_check = BRANCH_HALT_ENABLE, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(21), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_osr_clk", \
+ .parent_names = lcc_##prefix##_parents, \
+ .num_parents = 1, \
+ .ops = &clk_branch_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_regmap_div prefix##_div_clk = { \
+ .reg = _ns, \
+ .shift = 10, \
+ .width = 8, \
+ .clkr = { \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_div_clk", \
+ .parent_names = lcc_##prefix##_parents, \
+ .num_parents = 1, \
+ .ops = &clk_regmap_div_ops, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_branch prefix##_bit_div_clk = { \
+ .halt_reg = hr, \
+ .halt_bit = 0, \
+ .halt_check = BRANCH_HALT_ENABLE, \
+ .clkr = { \
+ .enable_reg = _ns, \
+ .enable_mask = BIT(19), \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_bit_div_clk", \
+ .parent_names = (const char *[]){ \
+ #prefix "_div_clk" \
+ }, \
+ .num_parents = 1, \
+ .ops = &clk_branch_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}; \
+ \
+static struct clk_regmap_mux prefix##_bit_clk = { \
+ .reg = _ns, \
+ .shift = 18, \
+ .width = 1, \
+ .clkr = { \
+ .hw.init = &(struct clk_init_data){ \
+ .name = #prefix "_bit_clk", \
+ .parent_names = (const char *[]){ \
+ #prefix "_bit_div_clk", \
+ #prefix "_codec_clk", \
+ }, \
+ .num_parents = 2, \
+ .ops = &clk_regmap_mux_closest_ops, \
+ .flags = CLK_SET_RATE_PARENT, \
+ }, \
+ }, \
+}
+
+CLK_AIF_OSR_DIV(codec_i2s_mic, 0x60, 0x64, 0x68);
+CLK_AIF_OSR_DIV(spare_i2s_mic, 0x78, 0x7c, 0x80);
+CLK_AIF_OSR_DIV(codec_i2s_spkr, 0x6c, 0x70, 0x74);
+CLK_AIF_OSR_DIV(spare_i2s_spkr, 0x84, 0x88, 0x8c);
+
+static struct freq_tbl clk_tbl_pcm_492[] = {
+ { 256000, P_PLL4, 4, 1, 480 },
+ { 512000, P_PLL4, 4, 1, 240 },
+ { 768000, P_PLL4, 4, 1, 160 },
+ { 1024000, P_PLL4, 4, 1, 120 },
+ { 1536000, P_PLL4, 4, 1, 80 },
+ { 2048000, P_PLL4, 4, 1, 60 },
+ { 3072000, P_PLL4, 4, 1, 40 },
+ { 4096000, P_PLL4, 4, 1, 30 },
+ { 6144000, P_PLL4, 4, 1, 20 },
+ { 8192000, P_PLL4, 4, 1, 15 },
+ { 12288000, P_PLL4, 4, 1, 10 },
+ { 24576000, P_PLL4, 4, 1, 5 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct freq_tbl clk_tbl_pcm_393[] = {
+ { 256000, P_PLL4, 4, 1, 384 },
+ { 512000, P_PLL4, 4, 1, 192 },
+ { 768000, P_PLL4, 4, 1, 128 },
+ { 1024000, P_PLL4, 4, 1, 96 },
+ { 1536000, P_PLL4, 4, 1, 64 },
+ { 2048000, P_PLL4, 4, 1, 48 },
+ { 3072000, P_PLL4, 4, 1, 32 },
+ { 4096000, P_PLL4, 4, 1, 24 },
+ { 6144000, P_PLL4, 4, 1, 16 },
+ { 8192000, P_PLL4, 4, 1, 12 },
+ { 12288000, P_PLL4, 4, 1, 8 },
+ { 24576000, P_PLL4, 4, 1, 4 },
+ { 27000000, P_PXO, 1, 0, 0 },
+ { }
+};
+
+static struct clk_rcg pcm_src = {
+ .ns_reg = 0x54,
+ .md_reg = 0x58,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 16,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_pcm_393,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static struct clk_branch pcm_clk_out = {
+ .halt_reg = 0x5c,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0x54,
+ .enable_mask = BIT(11),
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk_out",
+ .parent_names = (const char *[]){ "pcm_src" },
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap_mux pcm_clk = {
+ .reg = 0x54,
+ .shift = 10,
+ .width = 1,
+ .clkr = {
+ .hw.init = &(struct clk_init_data){
+ .name = "pcm_clk",
+ .parent_names = (const char *[]){
+ "pcm_clk_out",
+ "pcm_codec_clk",
+ },
+ .num_parents = 2,
+ .ops = &clk_regmap_mux_closest_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_rcg slimbus_src = {
+ .ns_reg = 0xcc,
+ .md_reg = 0xd0,
+ .mn = {
+ .mnctr_en_bit = 8,
+ .mnctr_reset_bit = 7,
+ .mnctr_mode_shift = 5,
+ .n_val_shift = 16,
+ .m_val_shift = 16,
+ .width = 8,
+ },
+ .p = {
+ .pre_div_shift = 3,
+ .pre_div_width = 2,
+ },
+ .s = {
+ .src_sel_shift = 0,
+ .parent_map = lcc_pxo_pll4_map,
+ },
+ .freq_tbl = clk_tbl_aif_osr_393,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(9),
+ .hw.init = &(struct clk_init_data){
+ .name = "slimbus_src",
+ .parent_names = lcc_pxo_pll4,
+ .num_parents = 2,
+ .ops = &clk_rcg_ops,
+ .flags = CLK_SET_RATE_GATE,
+ },
+ },
+};
+
+static const char *lcc_slimbus_parents[] = {
+ "slimbus_src",
+};
+
+static struct clk_branch audio_slimbus_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 0,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(10),
+ .hw.init = &(struct clk_init_data){
+ .name = "audio_slimbus_clk",
+ .parent_names = lcc_slimbus_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_branch sps_slimbus_clk = {
+ .halt_reg = 0xd4,
+ .halt_bit = 1,
+ .halt_check = BRANCH_HALT_ENABLE,
+ .clkr = {
+ .enable_reg = 0xcc,
+ .enable_mask = BIT(12),
+ .hw.init = &(struct clk_init_data){
+ .name = "sps_slimbus_clk",
+ .parent_names = lcc_slimbus_parents,
+ .num_parents = 1,
+ .ops = &clk_branch_ops,
+ .flags = CLK_SET_RATE_PARENT,
+ },
+ },
+};
+
+static struct clk_regmap *lcc_msm8960_clks[] = {
+ [PLL4] = &pll4.clkr,
+ [MI2S_OSR_SRC] = &mi2s_osr_src.clkr,
+ [MI2S_OSR_CLK] = &mi2s_osr_clk.clkr,
+ [MI2S_DIV_CLK] = &mi2s_div_clk.clkr,
+ [MI2S_BIT_DIV_CLK] = &mi2s_bit_div_clk.clkr,
+ [MI2S_BIT_CLK] = &mi2s_bit_clk.clkr,
+ [PCM_SRC] = &pcm_src.clkr,
+ [PCM_CLK_OUT] = &pcm_clk_out.clkr,
+ [PCM_CLK] = &pcm_clk.clkr,
+ [SLIMBUS_SRC] = &slimbus_src.clkr,
+ [AUDIO_SLIMBUS_CLK] = &audio_slimbus_clk.clkr,
+ [SPS_SLIMBUS_CLK] = &sps_slimbus_clk.clkr,
+ [CODEC_I2S_MIC_OSR_SRC] = &codec_i2s_mic_osr_src.clkr,
+ [CODEC_I2S_MIC_OSR_CLK] = &codec_i2s_mic_osr_clk.clkr,
+ [CODEC_I2S_MIC_DIV_CLK] = &codec_i2s_mic_div_clk.clkr,
+ [CODEC_I2S_MIC_BIT_DIV_CLK] = &codec_i2s_mic_bit_div_clk.clkr,
+ [CODEC_I2S_MIC_BIT_CLK] = &codec_i2s_mic_bit_clk.clkr,
+ [SPARE_I2S_MIC_OSR_SRC] = &spare_i2s_mic_osr_src.clkr,
+ [SPARE_I2S_MIC_OSR_CLK] = &spare_i2s_mic_osr_clk.clkr,
+ [SPARE_I2S_MIC_DIV_CLK] = &spare_i2s_mic_div_clk.clkr,
+ [SPARE_I2S_MIC_BIT_DIV_CLK] = &spare_i2s_mic_bit_div_clk.clkr,
+ [SPARE_I2S_MIC_BIT_CLK] = &spare_i2s_mic_bit_clk.clkr,
+ [CODEC_I2S_SPKR_OSR_SRC] = &codec_i2s_spkr_osr_src.clkr,
+ [CODEC_I2S_SPKR_OSR_CLK] = &codec_i2s_spkr_osr_clk.clkr,
+ [CODEC_I2S_SPKR_DIV_CLK] = &codec_i2s_spkr_div_clk.clkr,
+ [CODEC_I2S_SPKR_BIT_DIV_CLK] = &codec_i2s_spkr_bit_div_clk.clkr,
+ [CODEC_I2S_SPKR_BIT_CLK] = &codec_i2s_spkr_bit_clk.clkr,
+ [SPARE_I2S_SPKR_OSR_SRC] = &spare_i2s_spkr_osr_src.clkr,
+ [SPARE_I2S_SPKR_OSR_CLK] = &spare_i2s_spkr_osr_clk.clkr,
+ [SPARE_I2S_SPKR_DIV_CLK] = &spare_i2s_spkr_div_clk.clkr,
+ [SPARE_I2S_SPKR_BIT_DIV_CLK] = &spare_i2s_spkr_bit_div_clk.clkr,
+ [SPARE_I2S_SPKR_BIT_CLK] = &spare_i2s_spkr_bit_clk.clkr,
+};
+
+static const struct regmap_config lcc_msm8960_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 4,
+ .val_bits = 32,
+ .max_register = 0xfc,
+ .fast_io = true,
+};
+
+static const struct qcom_cc_desc lcc_msm8960_desc = {
+ .config = &lcc_msm8960_regmap_config,
+ .clks = lcc_msm8960_clks,
+ .num_clks = ARRAY_SIZE(lcc_msm8960_clks),
+};
+
+static const struct of_device_id lcc_msm8960_match_table[] = {
+ { .compatible = "qcom,lcc-msm8960" },
+ { .compatible = "qcom,lcc-apq8064" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, lcc_msm8960_match_table);
+
+static int lcc_msm8960_probe(struct platform_device *pdev)
+{
+ u32 val;
+ struct regmap *regmap;
+
+ regmap = qcom_cc_map(pdev, &lcc_msm8960_desc);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
+
+ /* Use the correct frequency plan depending on speed of PLL4 */
+ val = regmap_read(regmap, 0x4, &val);
+ if (val == 0x12) {
+ slimbus_src.freq_tbl = clk_tbl_aif_osr_492;
+ mi2s_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_mic_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ codec_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ spare_i2s_spkr_osr_src.freq_tbl = clk_tbl_aif_osr_492;
+ pcm_src.freq_tbl = clk_tbl_pcm_492;
+ }
+ /* Enable PLL4 source on the LPASS Primary PLL Mux */
+ regmap_write(regmap, 0xc4, 0x1);
+
+ return qcom_cc_really_probe(pdev, &lcc_msm8960_desc, regmap);
+}
+
+static int lcc_msm8960_remove(struct platform_device *pdev)
+{
+ qcom_cc_remove(pdev);
+ return 0;
+}
+
+static struct platform_driver lcc_msm8960_driver = {
+ .probe = lcc_msm8960_probe,
+ .remove = lcc_msm8960_remove,
+ .driver = {
+ .name = "lcc-msm8960",
+ .owner = THIS_MODULE,
+ .of_match_table = lcc_msm8960_match_table,
+ },
+};
+module_platform_driver(lcc_msm8960_driver);
+
+MODULE_DESCRIPTION("QCOM LCC MSM8960 Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:lcc-msm8960");
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 11194b8329fe..05d7a0bc0599 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -190,7 +190,7 @@ PNAME(mux_uart2_p) = { "uart2_src", "uart2_frac", "xin24m" };
PNAME(mux_uart3_p) = { "uart3_src", "uart3_frac", "xin24m" };
PNAME(mux_uart4_p) = { "uart4_src", "uart4_frac", "xin24m" };
PNAME(mux_cif_out_p) = { "cif_src", "xin24m" };
-PNAME(mux_macref_p) = { "mac_src", "ext_gmac" };
+PNAME(mux_mac_p) = { "mac_pll_src", "ext_gmac" };
PNAME(mux_hsadcout_p) = { "hsadc_src", "ext_hsadc" };
PNAME(mux_edp_24m_p) = { "ext_edp_24m", "xin24m" };
PNAME(mux_tspout_p) = { "cpll", "gpll", "npll", "xin27m" };
@@ -535,58 +535,58 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
COMPOSITE(0, "uart0_src", mux_pll_src_cpll_gll_usb_npll_p, 0,
RK3288_CLKSEL_CON(13), 13, 2, MFLAGS, 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 8, GFLAGS),
- COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", 0,
+ COMPOSITE_FRAC(0, "uart0_frac", "uart0_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(17), 0,
RK3288_CLKGATE_CON(1), 9, GFLAGS),
- MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, 0,
+ MUX(SCLK_UART0, "sclk_uart0", mux_uart0_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(13), 8, 2, MFLAGS),
MUX(0, "uart_src", mux_pll_src_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(13), 15, 1, MFLAGS),
COMPOSITE_NOMUX(0, "uart1_src", "uart_src", 0,
RK3288_CLKSEL_CON(14), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 10, GFLAGS),
- COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", 0,
+ COMPOSITE_FRAC(0, "uart1_frac", "uart1_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(18), 0,
RK3288_CLKGATE_CON(1), 11, GFLAGS),
- MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, 0,
+ MUX(SCLK_UART1, "sclk_uart1", mux_uart1_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(14), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart2_src", "uart_src", 0,
RK3288_CLKSEL_CON(15), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", 0,
+ COMPOSITE_FRAC(0, "uart2_frac", "uart2_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(19), 0,
RK3288_CLKGATE_CON(1), 13, GFLAGS),
- MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, 0,
+ MUX(SCLK_UART2, "sclk_uart2", mux_uart2_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(15), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart3_src", "uart_src", 0,
RK3288_CLKSEL_CON(16), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(1), 14, GFLAGS),
- COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", 0,
+ COMPOSITE_FRAC(0, "uart3_frac", "uart3_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(20), 0,
RK3288_CLKGATE_CON(1), 15, GFLAGS),
- MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, 0,
+ MUX(SCLK_UART3, "sclk_uart3", mux_uart3_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(16), 8, 2, MFLAGS),
COMPOSITE_NOMUX(0, "uart4_src", "uart_src", 0,
RK3288_CLKSEL_CON(3), 0, 7, DFLAGS,
RK3288_CLKGATE_CON(2), 12, GFLAGS),
- COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", 0,
+ COMPOSITE_FRAC(0, "uart4_frac", "uart4_src", CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(7), 0,
RK3288_CLKGATE_CON(2), 13, GFLAGS),
- MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, 0,
+ MUX(SCLK_UART4, "sclk_uart4", mux_uart4_p, CLK_SET_RATE_PARENT,
RK3288_CLKSEL_CON(3), 8, 2, MFLAGS),
- COMPOSITE(0, "mac_src", mux_pll_src_npll_cpll_gpll_p, 0,
+ COMPOSITE(0, "mac_pll_src", mux_pll_src_npll_cpll_gpll_p, 0,
RK3288_CLKSEL_CON(21), 0, 2, MFLAGS, 8, 5, DFLAGS,
RK3288_CLKGATE_CON(2), 5, GFLAGS),
- MUX(0, "macref", mux_macref_p, 0,
+ MUX(SCLK_MAC, "mac_clk", mux_mac_p, 0,
RK3288_CLKSEL_CON(21), 4, 1, MFLAGS),
- GATE(0, "sclk_macref_out", "macref", 0,
+ GATE(SCLK_MACREF_OUT, "sclk_macref_out", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 3, GFLAGS),
- GATE(SCLK_MACREF, "sclk_macref", "macref", 0,
+ GATE(SCLK_MACREF, "sclk_macref", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 2, GFLAGS),
- GATE(SCLK_MAC_RX, "sclk_mac_rx", "macref", 0,
+ GATE(SCLK_MAC_RX, "sclk_mac_rx", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 0, GFLAGS),
- GATE(SCLK_MAC_TX, "sclk_mac_tx", "macref", 0,
+ GATE(SCLK_MAC_TX, "sclk_mac_tx", "mac_clk", 0,
RK3288_CLKGATE_CON(5), 1, GFLAGS),
COMPOSITE(0, "hsadc_src", mux_pll_src_cpll_gpll_p, 0,
@@ -598,7 +598,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(0, "jtag", "ext_jtag", 0,
RK3288_CLKGATE_CON(4), 14, GFLAGS),
- COMPOSITE_NODIV(0, "usbphy480m_src", mux_usbphy480m_p, 0,
+ COMPOSITE_NODIV(SCLK_USBPHY480M_SRC, "usbphy480m_src", mux_usbphy480m_p, 0,
RK3288_CLKSEL_CON(13), 11, 2, MFLAGS,
RK3288_CLKGATE_CON(5), 14, GFLAGS),
COMPOSITE_NODIV(SCLK_HSICPHY480M, "sclk_hsicphy480m", mux_hsicphy480m_p, 0,
@@ -704,8 +704,8 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(SCLK_LCDC_PWM0, "sclk_lcdc_pwm0", "xin24m", 0, RK3288_CLKGATE_CON(13), 10, GFLAGS),
GATE(SCLK_LCDC_PWM1, "sclk_lcdc_pwm1", "xin24m", 0, RK3288_CLKGATE_CON(13), 11, GFLAGS),
- GATE(0, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
- GATE(0, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
+ GATE(SCLK_PVTM_CORE, "sclk_pvtm_core", "xin24m", 0, RK3288_CLKGATE_CON(5), 9, GFLAGS),
+ GATE(SCLK_PVTM_GPU, "sclk_pvtm_gpu", "xin24m", 0, RK3288_CLKGATE_CON(5), 10, GFLAGS),
GATE(0, "sclk_mipidsi_24m", "xin24m", 0, RK3288_CLKGATE_CON(5), 15, GFLAGS),
/* sclk_gpu gates */
@@ -805,6 +805,20 @@ static int rk3288_clk_suspend(void)
rk3288_saved_cru_regs[i] =
readl_relaxed(rk3288_cru_base + reg_id);
}
+
+ /*
+ * Switch PLLs other than DPLL (for SDRAM) to slow mode to
+ * avoid crashes on resume. The Mask ROM on the system will
+ * put APLL, CPLL, and GPLL into slow mode at resume time
+ * anyway (which is why we restore them), but we might not
+ * even make it to the Mask ROM if this isn't done at suspend
+ * time.
+ *
+ * NOTE: only APLL truly matters here, but we'll do them all.
+ */
+
+ writel_relaxed(0xf3030000, rk3288_cru_base + RK3288_MODE_CON);
+
return 0;
}
@@ -866,6 +880,14 @@ static void __init rk3288_clk_init(struct device_node *np)
pr_warn("%s: could not register clock hclk_vcodec_pre: %ld\n",
__func__, PTR_ERR(clk));
+ /* Watchdog pclk is controlled by RK3288_SGRF_SOC_CON0[1]. */
+ clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_pd_alive", 0, 1, 1);
+ if (IS_ERR(clk))
+ pr_warn("%s: could not register clock pclk_wdt: %ld\n",
+ __func__, PTR_ERR(clk));
+ else
+ rockchip_clk_add_lookup(clk, PCLK_WDT);
+
rockchip_clk_register_plls(rk3288_pll_clks,
ARRAY_SIZE(rk3288_pll_clks),
RK3288_GRF_SOC_STATUS1);
diff --git a/drivers/clk/samsung/clk-exynos-audss.c b/drivers/clk/samsung/clk-exynos-audss.c
index f2c2ccce49bb..454b02ae486a 100644
--- a/drivers/clk/samsung/clk-exynos-audss.c
+++ b/drivers/clk/samsung/clk-exynos-audss.c
@@ -82,6 +82,26 @@ static const struct of_device_id exynos_audss_clk_of_match[] = {
{},
};
+static void exynos_audss_clk_teardown(void)
+{
+ int i;
+
+ for (i = EXYNOS_MOUT_AUDSS; i < EXYNOS_DOUT_SRP; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_mux(clk_table[i]);
+ }
+
+ for (; i < EXYNOS_SRP_CLK; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_divider(clk_table[i]);
+ }
+
+ for (; i < clk_data.clk_num; i++) {
+ if (!IS_ERR(clk_table[i]))
+ clk_unregister_gate(clk_table[i]);
+ }
+}
+
/* register exynos_audss clocks */
static int exynos_audss_clk_probe(struct platform_device *pdev)
{
@@ -219,10 +239,7 @@ static int exynos_audss_clk_probe(struct platform_device *pdev)
return 0;
unregister:
- for (i = 0; i < clk_data.clk_num; i++) {
- if (!IS_ERR(clk_table[i]))
- clk_unregister(clk_table[i]);
- }
+ exynos_audss_clk_teardown();
if (!IS_ERR(epll))
clk_disable_unprepare(epll);
@@ -232,18 +249,13 @@ unregister:
static int exynos_audss_clk_remove(struct platform_device *pdev)
{
- int i;
-
#ifdef CONFIG_PM_SLEEP
unregister_syscore_ops(&exynos_audss_clk_syscore_ops);
#endif
of_clk_del_provider(pdev->dev.of_node);
- for (i = 0; i < clk_data.clk_num; i++) {
- if (!IS_ERR(clk_table[i]))
- clk_unregister(clk_table[i]);
- }
+ exynos_audss_clk_teardown();
if (!IS_ERR(epll))
clk_disable_unprepare(epll);
diff --git a/drivers/clk/samsung/clk-exynos3250.c b/drivers/clk/samsung/clk-exynos3250.c
index 6e6cca392082..cc4c348d8a24 100644
--- a/drivers/clk/samsung/clk-exynos3250.c
+++ b/drivers/clk/samsung/clk-exynos3250.c
@@ -104,27 +104,6 @@
#define PWR_CTRL1_USE_CORE1_WFI (1 << 1)
#define PWR_CTRL1_USE_CORE0_WFI (1 << 0)
-/* list of PLLs to be registered */
-enum exynos3250_plls {
- apll, mpll, vpll, upll,
- nr_plls
-};
-
-/* list of PLLs in DMC block to be registered */
-enum exynos3250_dmc_plls {
- bpll, epll,
- nr_dmc_plls
-};
-
-static void __iomem *reg_base;
-static void __iomem *dmc_reg_base;
-
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos3250_clk_regs;
-
static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
SRC_LEFTBUS,
DIV_LEFTBUS,
@@ -195,43 +174,6 @@ static unsigned long exynos3250_cmu_clk_regs[] __initdata = {
PWR_CTRL2,
};
-static int exynos3250_clk_suspend(void)
-{
- samsung_clk_save(reg_base, exynos3250_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
- return 0;
-}
-
-static void exynos3250_clk_resume(void)
-{
- samsung_clk_restore(reg_base, exynos3250_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
-}
-
-static struct syscore_ops exynos3250_clk_syscore_ops = {
- .suspend = exynos3250_clk_suspend,
- .resume = exynos3250_clk_resume,
-};
-
-static void exynos3250_clk_sleep_init(void)
-{
- exynos3250_clk_regs =
- samsung_clk_alloc_reg_dump(exynos3250_cmu_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_clk_regs));
- if (!exynos3250_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- goto err;
- }
-
- register_syscore_ops(&exynos3250_clk_syscore_ops);
- return;
-err:
- kfree(exynos3250_clk_regs);
-}
-#else
-static inline void exynos3250_clk_sleep_init(void) { }
-#endif
-
/* list of all parent clock list */
PNAME(mout_vpllsrc_p) = { "fin_pll", };
@@ -782,18 +724,18 @@ static struct samsung_pll_rate_table exynos3250_vpll_rates[] = {
{ /* sentinel */ }
};
-static struct samsung_pll_clock exynos3250_plls[nr_plls] __initdata = {
- [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
- APLL_LOCK, APLL_CON0, NULL),
- [mpll] = PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
- MPLL_LOCK, MPLL_CON0, NULL),
- [vpll] = PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
- VPLL_LOCK, VPLL_CON0, NULL),
- [upll] = PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
- UPLL_LOCK, UPLL_CON0, NULL),
+static struct samsung_pll_clock exynos3250_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, exynos3250_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, exynos3250_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_VPLL, "fout_vpll", "fin_pll",
+ VPLL_LOCK, VPLL_CON0, exynos3250_vpll_rates),
+ PLL(pll_35xx, CLK_FOUT_UPLL, "fout_upll", "fin_pll",
+ UPLL_LOCK, UPLL_CON0, exynos3250_pll_rates),
};
-static void __init exynos3_core_down_clock(void)
+static void __init exynos3_core_down_clock(void __iomem *reg_base)
{
unsigned int tmp;
@@ -814,38 +756,31 @@ static void __init exynos3_core_down_clock(void)
__raw_writel(0x0, reg_base + PWR_CTRL2);
}
+static struct samsung_cmu_info cmu_info __initdata = {
+ .pll_clks = exynos3250_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos3250_plls),
+ .mux_clks = mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(mux_clks),
+ .div_clks = div_clks,
+ .nr_div_clks = ARRAY_SIZE(div_clks),
+ .gate_clks = gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(gate_clks),
+ .fixed_factor_clks = fixed_factor_clks,
+ .nr_fixed_factor_clks = ARRAY_SIZE(fixed_factor_clks),
+ .nr_clk_ids = CLK_NR_CLKS,
+ .clk_regs = exynos3250_cmu_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_clk_regs),
+};
+
static void __init exynos3250_cmu_init(struct device_node *np)
{
struct samsung_clk_provider *ctx;
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
+ ctx = samsung_cmu_register_one(np, &cmu_info);
if (!ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- samsung_clk_register_fixed_factor(ctx, fixed_factor_clks,
- ARRAY_SIZE(fixed_factor_clks));
-
- exynos3250_plls[apll].rate_table = exynos3250_pll_rates;
- exynos3250_plls[mpll].rate_table = exynos3250_pll_rates;
- exynos3250_plls[vpll].rate_table = exynos3250_vpll_rates;
- exynos3250_plls[upll].rate_table = exynos3250_pll_rates;
-
- samsung_clk_register_pll(ctx, exynos3250_plls,
- ARRAY_SIZE(exynos3250_plls), reg_base);
-
- samsung_clk_register_mux(ctx, mux_clks, ARRAY_SIZE(mux_clks));
- samsung_clk_register_div(ctx, div_clks, ARRAY_SIZE(div_clks));
- samsung_clk_register_gate(ctx, gate_clks, ARRAY_SIZE(gate_clks));
-
- exynos3_core_down_clock();
+ return;
- exynos3250_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, ctx);
+ exynos3_core_down_clock(ctx->reg_base);
}
CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
@@ -872,12 +807,6 @@ CLK_OF_DECLARE(exynos3250_cmu, "samsung,exynos3250-cmu", exynos3250_cmu_init);
#define EPLL_CON2 0x111c
#define SRC_EPLL 0x1120
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos3250_dmc_clk_regs;
-
static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
BPLL_LOCK,
BPLL_CON0,
@@ -899,43 +828,6 @@ static unsigned long exynos3250_cmu_dmc_clk_regs[] __initdata = {
SRC_EPLL,
};
-static int exynos3250_dmc_clk_suspend(void)
-{
- samsung_clk_save(dmc_reg_base, exynos3250_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
- return 0;
-}
-
-static void exynos3250_dmc_clk_resume(void)
-{
- samsung_clk_restore(dmc_reg_base, exynos3250_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
-}
-
-static struct syscore_ops exynos3250_dmc_clk_syscore_ops = {
- .suspend = exynos3250_dmc_clk_suspend,
- .resume = exynos3250_dmc_clk_resume,
-};
-
-static void exynos3250_dmc_clk_sleep_init(void)
-{
- exynos3250_dmc_clk_regs =
- samsung_clk_alloc_reg_dump(exynos3250_cmu_dmc_clk_regs,
- ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs));
- if (!exynos3250_dmc_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- goto err;
- }
-
- register_syscore_ops(&exynos3250_dmc_clk_syscore_ops);
- return;
-err:
- kfree(exynos3250_dmc_clk_regs);
-}
-#else
-static inline void exynos3250_dmc_clk_sleep_init(void) { }
-#endif
-
PNAME(mout_epll_p) = { "fin_pll", "fout_epll", };
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(mout_mpll_mif_p) = { "fin_pll", "sclk_mpll_mif", };
@@ -977,43 +869,28 @@ static struct samsung_div_clock dmc_div_clks[] __initdata = {
DIV(CLK_DIV_DMCD, "div_dmcd", "div_dmc", DIV_DMC1, 11, 3),
};
-static struct samsung_pll_clock exynos3250_dmc_plls[nr_dmc_plls] __initdata = {
- [bpll] = PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
- BPLL_LOCK, BPLL_CON0, NULL),
- [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
- EPLL_LOCK, EPLL_CON0, NULL),
+static struct samsung_pll_clock exynos3250_dmc_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_BPLL, "fout_bpll", "fin_pll",
+ BPLL_LOCK, BPLL_CON0, exynos3250_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
+ EPLL_LOCK, EPLL_CON0, exynos3250_epll_rates),
+};
+
+static struct samsung_cmu_info dmc_cmu_info __initdata = {
+ .pll_clks = exynos3250_dmc_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos3250_dmc_plls),
+ .mux_clks = dmc_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(dmc_mux_clks),
+ .div_clks = dmc_div_clks,
+ .nr_div_clks = ARRAY_SIZE(dmc_div_clks),
+ .nr_clk_ids = NR_CLKS_DMC,
+ .clk_regs = exynos3250_cmu_dmc_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos3250_cmu_dmc_clk_regs),
};
static void __init exynos3250_cmu_dmc_init(struct device_node *np)
{
- struct samsung_clk_provider *ctx;
-
- dmc_reg_base = of_iomap(np, 0);
- if (!dmc_reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- ctx = samsung_clk_init(np, dmc_reg_base, NR_CLKS_DMC);
- if (!ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos3250_dmc_plls[bpll].rate_table = exynos3250_pll_rates;
- exynos3250_dmc_plls[epll].rate_table = exynos3250_epll_rates;
-
- pr_err("CLK registering epll bpll: %d, %d, %d, %d\n",
- exynos3250_dmc_plls[bpll].rate_table[0].rate,
- exynos3250_dmc_plls[bpll].rate_table[0].mdiv,
- exynos3250_dmc_plls[bpll].rate_table[0].pdiv,
- exynos3250_dmc_plls[bpll].rate_table[0].sdiv
- );
- samsung_clk_register_pll(ctx, exynos3250_dmc_plls,
- ARRAY_SIZE(exynos3250_dmc_plls), dmc_reg_base);
-
- samsung_clk_register_mux(ctx, dmc_mux_clks, ARRAY_SIZE(dmc_mux_clks));
- samsung_clk_register_div(ctx, dmc_div_clks, ARRAY_SIZE(dmc_div_clks));
-
- exynos3250_dmc_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, ctx);
+ samsung_cmu_register_one(np, &dmc_cmu_info);
}
CLK_OF_DECLARE(exynos3250_cmu_dmc, "samsung,exynos3250-cmu-dmc",
exynos3250_cmu_dmc_init);
diff --git a/drivers/clk/samsung/clk-exynos4.c b/drivers/clk/samsung/clk-exynos4.c
index 88e8c6bbd77f..51462e85675f 100644
--- a/drivers/clk/samsung/clk-exynos4.c
+++ b/drivers/clk/samsung/clk-exynos4.c
@@ -703,12 +703,12 @@ static struct samsung_mux_clock exynos4x12_mux_clks[] __initdata = {
/* list of divider clocks supported in all exynos4 soc's */
static struct samsung_div_clock exynos4_div_clks[] __initdata = {
- DIV(0, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
+ DIV(CLK_DIV_GDL, "div_gdl", "mout_gdl", DIV_LEFTBUS, 0, 3),
DIV(0, "div_gpl", "div_gdl", DIV_LEFTBUS, 4, 3),
DIV(0, "div_clkout_leftbus", "mout_clkout_leftbus",
CLKOUT_CMU_LEFTBUS, 8, 6),
- DIV(0, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
+ DIV(CLK_DIV_GDR, "div_gdr", "mout_gdr", DIV_RIGHTBUS, 0, 3),
DIV(0, "div_gpr", "div_gdr", DIV_RIGHTBUS, 4, 3),
DIV(0, "div_clkout_rightbus", "mout_clkout_rightbus",
CLKOUT_CMU_RIGHTBUS, 8, 6),
@@ -781,10 +781,10 @@ static struct samsung_div_clock exynos4_div_clks[] __initdata = {
CLK_SET_RATE_PARENT, 0),
DIV(0, "div_clkout_top", "mout_clkout_top", CLKOUT_CMU_TOP, 8, 6),
- DIV(0, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
+ DIV(CLK_DIV_ACP, "div_acp", "mout_dmc_bus", DIV_DMC0, 0, 3),
DIV(0, "div_acp_pclk", "div_acp", DIV_DMC0, 4, 3),
DIV(0, "div_dphy", "mout_dphy", DIV_DMC0, 8, 3),
- DIV(0, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
+ DIV(CLK_DIV_DMC, "div_dmc", "mout_dmc_bus", DIV_DMC0, 12, 3),
DIV(0, "div_dmcd", "div_dmc", DIV_DMC0, 16, 3),
DIV(0, "div_dmcp", "div_dmcd", DIV_DMC0, 20, 3),
DIV(0, "div_pwi", "mout_pwi", DIV_DMC1, 8, 4),
@@ -829,7 +829,7 @@ static struct samsung_div_clock exynos4x12_div_clks[] __initdata = {
DIV_F(CLK_DIV_MCUISP1, "div_mcuisp1", "div_mcuisp0", E4X12_DIV_ISP1,
8, 3, CLK_GET_RATE_NOCACHE, 0),
DIV(CLK_SCLK_FIMG2D, "sclk_fimg2d", "mout_g2d", DIV_DMC1, 0, 4),
- DIV(0, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
+ DIV(CLK_DIV_C2C, "div_c2c", "mout_c2c", DIV_DMC1, 4, 3),
DIV(0, "div_c2c_aclk", "div_c2c", DIV_DMC1, 12, 3),
};
diff --git a/drivers/clk/samsung/clk-exynos4415.c b/drivers/clk/samsung/clk-exynos4415.c
index 2123fc251e0f..6c78b09c829f 100644
--- a/drivers/clk/samsung/clk-exynos4415.c
+++ b/drivers/clk/samsung/clk-exynos4415.c
@@ -113,19 +113,6 @@
#define DIV_CPU0 0x14500
#define DIV_CPU1 0x14504
-enum exynos4415_plls {
- apll, epll, g3d_pll, isp_pll, disp_pll,
- nr_plls,
-};
-
-static struct samsung_clk_provider *exynos4415_ctx;
-
-/*
- * Support for CMU save/restore across system suspends
- */
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4415_clk_regs;
-
static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
SRC_LEFTBUS,
DIV_LEFTBUS,
@@ -219,41 +206,6 @@ static unsigned long exynos4415_cmu_clk_regs[] __initdata = {
DIV_CPU1,
};
-static int exynos4415_clk_suspend(void)
-{
- samsung_clk_save(exynos4415_ctx->reg_base, exynos4415_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
-
- return 0;
-}
-
-static void exynos4415_clk_resume(void)
-{
- samsung_clk_restore(exynos4415_ctx->reg_base, exynos4415_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
-}
-
-static struct syscore_ops exynos4415_clk_syscore_ops = {
- .suspend = exynos4415_clk_suspend,
- .resume = exynos4415_clk_resume,
-};
-
-static void exynos4415_clk_sleep_init(void)
-{
- exynos4415_clk_regs =
- samsung_clk_alloc_reg_dump(exynos4415_cmu_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_clk_regs));
- if (!exynos4415_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&exynos4415_clk_syscore_ops);
-}
-#else
-static inline void exynos4415_clk_sleep_init(void) { }
-#endif
-
/* list of all parent clock list */
PNAME(mout_g3d_pllsrc_p) = { "fin_pll", };
@@ -959,56 +911,40 @@ static struct samsung_pll_rate_table exynos4415_epll_rates[] = {
{ /* sentinel */ }
};
-static struct samsung_pll_clock exynos4415_plls[nr_plls] __initdata = {
- [apll] = PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
- APLL_LOCK, APLL_CON0, NULL),
- [epll] = PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
- EPLL_LOCK, EPLL_CON0, NULL),
- [g3d_pll] = PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll",
- "mout_g3d_pllsrc", G3D_PLL_LOCK, G3D_PLL_CON0, NULL),
- [isp_pll] = PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
- ISP_PLL_LOCK, ISP_PLL_CON0, NULL),
- [disp_pll] = PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
- "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, NULL),
+static struct samsung_pll_clock exynos4415_plls[] __initdata = {
+ PLL(pll_35xx, CLK_FOUT_APLL, "fout_apll", "fin_pll",
+ APLL_LOCK, APLL_CON0, exynos4415_pll_rates),
+ PLL(pll_36xx, CLK_FOUT_EPLL, "fout_epll", "fin_pll",
+ EPLL_LOCK, EPLL_CON0, exynos4415_epll_rates),
+ PLL(pll_35xx, CLK_FOUT_G3D_PLL, "fout_g3d_pll", "mout_g3d_pllsrc",
+ G3D_PLL_LOCK, G3D_PLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_ISP_PLL, "fout_isp_pll", "fin_pll",
+ ISP_PLL_LOCK, ISP_PLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_FOUT_DISP_PLL, "fout_disp_pll",
+ "fin_pll", DISP_PLL_LOCK, DISP_PLL_CON0, exynos4415_pll_rates),
+};
+
+static struct samsung_cmu_info cmu_info __initdata = {
+ .pll_clks = exynos4415_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos4415_plls),
+ .mux_clks = exynos4415_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(exynos4415_mux_clks),
+ .div_clks = exynos4415_div_clks,
+ .nr_div_clks = ARRAY_SIZE(exynos4415_div_clks),
+ .gate_clks = exynos4415_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(exynos4415_gate_clks),
+ .fixed_clks = exynos4415_fixed_rate_clks,
+ .nr_fixed_clks = ARRAY_SIZE(exynos4415_fixed_rate_clks),
+ .fixed_factor_clks = exynos4415_fixed_factor_clks,
+ .nr_fixed_factor_clks = ARRAY_SIZE(exynos4415_fixed_factor_clks),
+ .nr_clk_ids = CLK_NR_CLKS,
+ .clk_regs = exynos4415_cmu_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_clk_regs),
};
static void __init exynos4415_cmu_init(struct device_node *np)
{
- void __iomem *reg_base;
-
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- exynos4415_ctx = samsung_clk_init(np, reg_base, CLK_NR_CLKS);
- if (!exynos4415_ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos4415_plls[apll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[epll].rate_table = exynos4415_epll_rates;
- exynos4415_plls[g3d_pll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[isp_pll].rate_table = exynos4415_pll_rates;
- exynos4415_plls[disp_pll].rate_table = exynos4415_pll_rates;
-
- samsung_clk_register_fixed_factor(exynos4415_ctx,
- exynos4415_fixed_factor_clks,
- ARRAY_SIZE(exynos4415_fixed_factor_clks));
- samsung_clk_register_fixed_rate(exynos4415_ctx,
- exynos4415_fixed_rate_clks,
- ARRAY_SIZE(exynos4415_fixed_rate_clks));
-
- samsung_clk_register_pll(exynos4415_ctx, exynos4415_plls,
- ARRAY_SIZE(exynos4415_plls), reg_base);
- samsung_clk_register_mux(exynos4415_ctx, exynos4415_mux_clks,
- ARRAY_SIZE(exynos4415_mux_clks));
- samsung_clk_register_div(exynos4415_ctx, exynos4415_div_clks,
- ARRAY_SIZE(exynos4415_div_clks));
- samsung_clk_register_gate(exynos4415_ctx, exynos4415_gate_clks,
- ARRAY_SIZE(exynos4415_gate_clks));
-
- exynos4415_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, exynos4415_ctx);
+ samsung_cmu_register_one(np, &cmu_info);
}
CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
@@ -1027,16 +963,6 @@ CLK_OF_DECLARE(exynos4415_cmu, "samsung,exynos4415-cmu", exynos4415_cmu_init);
#define SRC_DMC 0x300
#define DIV_DMC1 0x504
-enum exynos4415_dmc_plls {
- mpll, bpll,
- nr_dmc_plls,
-};
-
-static struct samsung_clk_provider *exynos4415_dmc_ctx;
-
-#ifdef CONFIG_PM_SLEEP
-static struct samsung_clk_reg_dump *exynos4415_dmc_clk_regs;
-
static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
MPLL_LOCK,
MPLL_CON0,
@@ -1050,42 +976,6 @@ static unsigned long exynos4415_cmu_dmc_clk_regs[] __initdata = {
DIV_DMC1,
};
-static int exynos4415_dmc_clk_suspend(void)
-{
- samsung_clk_save(exynos4415_dmc_ctx->reg_base,
- exynos4415_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
- return 0;
-}
-
-static void exynos4415_dmc_clk_resume(void)
-{
- samsung_clk_restore(exynos4415_dmc_ctx->reg_base,
- exynos4415_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
-}
-
-static struct syscore_ops exynos4415_dmc_clk_syscore_ops = {
- .suspend = exynos4415_dmc_clk_suspend,
- .resume = exynos4415_dmc_clk_resume,
-};
-
-static void exynos4415_dmc_clk_sleep_init(void)
-{
- exynos4415_dmc_clk_regs =
- samsung_clk_alloc_reg_dump(exynos4415_cmu_dmc_clk_regs,
- ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs));
- if (!exynos4415_dmc_clk_regs) {
- pr_warn("%s: Failed to allocate sleep save data\n", __func__);
- return;
- }
-
- register_syscore_ops(&exynos4415_dmc_clk_syscore_ops);
-}
-#else
-static inline void exynos4415_dmc_clk_sleep_init(void) { }
-#endif /* CONFIG_PM_SLEEP */
-
PNAME(mout_mpll_p) = { "fin_pll", "fout_mpll", };
PNAME(mout_bpll_p) = { "fin_pll", "fout_bpll", };
PNAME(mbpll_p) = { "mout_mpll", "mout_bpll", };
@@ -1107,38 +997,28 @@ static struct samsung_div_clock exynos4415_dmc_div_clks[] __initdata = {
DIV(CLK_DMC_DIV_MPLL_PRE, "div_mpll_pre", "mout_mpll", DIV_DMC1, 8, 2),
};
-static struct samsung_pll_clock exynos4415_dmc_plls[nr_dmc_plls] __initdata = {
- [mpll] = PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
- MPLL_LOCK, MPLL_CON0, NULL),
- [bpll] = PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
- BPLL_LOCK, BPLL_CON0, NULL),
+static struct samsung_pll_clock exynos4415_dmc_plls[] __initdata = {
+ PLL(pll_35xx, CLK_DMC_FOUT_MPLL, "fout_mpll", "fin_pll",
+ MPLL_LOCK, MPLL_CON0, exynos4415_pll_rates),
+ PLL(pll_35xx, CLK_DMC_FOUT_BPLL, "fout_bpll", "fin_pll",
+ BPLL_LOCK, BPLL_CON0, exynos4415_pll_rates),
+};
+
+static struct samsung_cmu_info cmu_dmc_info __initdata = {
+ .pll_clks = exynos4415_dmc_plls,
+ .nr_pll_clks = ARRAY_SIZE(exynos4415_dmc_plls),
+ .mux_clks = exynos4415_dmc_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(exynos4415_dmc_mux_clks),
+ .div_clks = exynos4415_dmc_div_clks,
+ .nr_div_clks = ARRAY_SIZE(exynos4415_dmc_div_clks),
+ .nr_clk_ids = NR_CLKS_DMC,
+ .clk_regs = exynos4415_cmu_dmc_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(exynos4415_cmu_dmc_clk_regs),
};
static void __init exynos4415_cmu_dmc_init(struct device_node *np)
{
- void __iomem *reg_base;
-
- reg_base = of_iomap(np, 0);
- if (!reg_base)
- panic("%s: failed to map registers\n", __func__);
-
- exynos4415_dmc_ctx = samsung_clk_init(np, reg_base, NR_CLKS_DMC);
- if (!exynos4415_dmc_ctx)
- panic("%s: unable to allocate context.\n", __func__);
-
- exynos4415_dmc_plls[mpll].rate_table = exynos4415_pll_rates;
- exynos4415_dmc_plls[bpll].rate_table = exynos4415_pll_rates;
-
- samsung_clk_register_pll(exynos4415_dmc_ctx, exynos4415_dmc_plls,
- ARRAY_SIZE(exynos4415_dmc_plls), reg_base);
- samsung_clk_register_mux(exynos4415_dmc_ctx, exynos4415_dmc_mux_clks,
- ARRAY_SIZE(exynos4415_dmc_mux_clks));
- samsung_clk_register_div(exynos4415_dmc_ctx, exynos4415_dmc_div_clks,
- ARRAY_SIZE(exynos4415_dmc_div_clks));
-
- exynos4415_dmc_clk_sleep_init();
-
- samsung_clk_of_add_provider(np, exynos4415_dmc_ctx);
+ samsung_cmu_register_one(np, &cmu_dmc_info);
}
CLK_OF_DECLARE(exynos4415_cmu_dmc, "samsung,exynos4415-cmu-dmc",
exynos4415_cmu_dmc_init);
diff --git a/drivers/clk/samsung/clk-exynos5420.c b/drivers/clk/samsung/clk-exynos5420.c
index 848d602efc06..07d666cc6a29 100644
--- a/drivers/clk/samsung/clk-exynos5420.c
+++ b/drivers/clk/samsung/clk-exynos5420.c
@@ -635,8 +635,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP3, 0, 1),
MUX(0, "mout_user_aclk400_mscl", mout_user_aclk400_mscl_p,
SRC_TOP3, 4, 1),
- MUX(0, "mout_user_aclk200_disp1", mout_user_aclk200_disp1_p,
- SRC_TOP3, 8, 1),
+ MUX(CLK_MOUT_USER_ACLK200_DISP1, "mout_user_aclk200_disp1",
+ mout_user_aclk200_disp1_p, SRC_TOP3, 8, 1),
MUX(0, "mout_user_aclk200_fsys2", mout_user_aclk200_fsys2_p,
SRC_TOP3, 12, 1),
MUX(0, "mout_user_aclk400_wcore", mout_user_aclk400_wcore_p,
@@ -663,8 +663,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(CLK_MOUT_USER_ACLK333, "mout_user_aclk333", mout_user_aclk333_p,
SRC_TOP4, 28, 1),
- MUX(0, "mout_user_aclk400_disp1", mout_user_aclk400_disp1_p,
- SRC_TOP5, 0, 1),
+ MUX(CLK_MOUT_USER_ACLK400_DISP1, "mout_user_aclk400_disp1",
+ mout_user_aclk400_disp1_p, SRC_TOP5, 0, 1),
MUX(0, "mout_user_aclk66_psgen", mout_user_aclk66_peric_p,
SRC_TOP5, 4, 1),
MUX(0, "mout_user_aclk333_g2d", mout_user_aclk333_g2d_p,
@@ -675,8 +675,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP5, 16, 1),
MUX(0, "mout_user_aclk300_jpeg", mout_user_aclk300_jpeg_p,
SRC_TOP5, 20, 1),
- MUX(0, "mout_user_aclk300_disp1", mout_user_aclk300_disp1_p,
- SRC_TOP5, 24, 1),
+ MUX(CLK_MOUT_USER_ACLK300_DISP1, "mout_user_aclk300_disp1",
+ mout_user_aclk300_disp1_p, SRC_TOP5, 24, 1),
MUX(0, "mout_user_aclk300_gscl", mout_user_aclk300_gscl_p,
SRC_TOP5, 28, 1),
@@ -693,7 +693,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
SRC_TOP10, 0, 1),
MUX(0, "mout_sw_aclk400_mscl", mout_sw_aclk400_mscl_p,
SRC_TOP10, 4, 1),
- MUX(0, "mout_sw_aclk200", mout_sw_aclk200_p, SRC_TOP10, 8, 1),
+ MUX(CLK_MOUT_SW_ACLK200, "mout_sw_aclk200", mout_sw_aclk200_p,
+ SRC_TOP10, 8, 1),
MUX(0, "mout_sw_aclk200_fsys2", mout_sw_aclk200_fsys2_p,
SRC_TOP10, 12, 1),
MUX(0, "mout_sw_aclk400_wcore", mout_sw_aclk400_wcore_p,
@@ -717,8 +718,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(CLK_MOUT_SW_ACLK333, "mout_sw_aclk333", mout_sw_aclk333_p,
SRC_TOP11, 28, 1),
- MUX(0, "mout_sw_aclk400_disp1", mout_sw_aclk400_disp1_p,
- SRC_TOP12, 4, 1),
+ MUX(CLK_MOUT_SW_ACLK400, "mout_sw_aclk400_disp1",
+ mout_sw_aclk400_disp1_p, SRC_TOP12, 4, 1),
MUX(0, "mout_sw_aclk333_g2d", mout_sw_aclk333_g2d_p,
SRC_TOP12, 8, 1),
MUX(0, "mout_sw_aclk266_g2d", mout_sw_aclk266_g2d_p,
@@ -726,8 +727,8 @@ static struct samsung_mux_clock exynos5x_mux_clks[] __initdata = {
MUX(0, "mout_sw_aclk_g3d", mout_sw_aclk_g3d_p, SRC_TOP12, 16, 1),
MUX(0, "mout_sw_aclk300_jpeg", mout_sw_aclk300_jpeg_p,
SRC_TOP12, 20, 1),
- MUX(0, "mout_sw_aclk300_disp1", mout_sw_aclk300_disp1_p,
- SRC_TOP12, 24, 1),
+ MUX(CLK_MOUT_SW_ACLK300, "mout_sw_aclk300_disp1",
+ mout_sw_aclk300_disp1_p, SRC_TOP12, 24, 1),
MUX(0, "mout_sw_aclk300_gscl", mout_sw_aclk300_gscl_p,
SRC_TOP12, 28, 1),
diff --git a/drivers/clk/samsung/clk-exynos7.c b/drivers/clk/samsung/clk-exynos7.c
index ea4483b8d62e..03d36e847b78 100644
--- a/drivers/clk/samsung/clk-exynos7.c
+++ b/drivers/clk/samsung/clk-exynos7.c
@@ -34,6 +34,7 @@
#define DIV_TOPC0 0x0600
#define DIV_TOPC1 0x0604
#define DIV_TOPC3 0x060C
+#define ENABLE_ACLK_TOPC1 0x0804
static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
FFACTOR(0, "ffac_topc_bus0_pll_div2", "mout_bus0_pll_ctrl", 1, 2, 0),
@@ -45,6 +46,7 @@ static struct samsung_fixed_factor_clock topc_fixed_factor_clks[] __initdata = {
};
/* List of parent clocks for Muxes in CMU_TOPC */
+PNAME(mout_aud_pll_ctrl_p) = { "fin_pll", "fout_aud_pll" };
PNAME(mout_bus0_pll_ctrl_p) = { "fin_pll", "fout_bus0_pll" };
PNAME(mout_bus1_pll_ctrl_p) = { "fin_pll", "fout_bus1_pll" };
PNAME(mout_cc_pll_ctrl_p) = { "fin_pll", "fout_cc_pll" };
@@ -104,9 +106,11 @@ static struct samsung_mux_clock topc_mux_clks[] __initdata = {
MUX(0, "mout_sclk_bus0_pll_out", mout_sclk_bus0_pll_out_p,
MUX_SEL_TOPC1, 16, 1),
+ MUX(0, "mout_aud_pll_ctrl", mout_aud_pll_ctrl_p, MUX_SEL_TOPC1, 0, 1),
MUX(0, "mout_aclk_ccore_133", mout_topc_group2, MUX_SEL_TOPC2, 4, 2),
+ MUX(0, "mout_aclk_mscl_532", mout_topc_group2, MUX_SEL_TOPC3, 20, 2),
MUX(0, "mout_aclk_peris_66", mout_topc_group2, MUX_SEL_TOPC3, 24, 2),
};
@@ -114,6 +118,8 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
DIV(DOUT_ACLK_CCORE_133, "dout_aclk_ccore_133", "mout_aclk_ccore_133",
DIV_TOPC0, 4, 4),
+ DIV(DOUT_ACLK_MSCL_532, "dout_aclk_mscl_532", "mout_aclk_mscl_532",
+ DIV_TOPC1, 20, 4),
DIV(DOUT_ACLK_PERIS, "dout_aclk_peris_66", "mout_aclk_peris_66",
DIV_TOPC1, 24, 4),
@@ -125,6 +131,18 @@ static struct samsung_div_clock topc_div_clks[] __initdata = {
DIV_TOPC3, 12, 3),
DIV(DOUT_SCLK_MFC_PLL, "dout_sclk_mfc_pll", "mout_mfc_pll_ctrl",
DIV_TOPC3, 16, 3),
+ DIV(DOUT_SCLK_AUD_PLL, "dout_sclk_aud_pll", "mout_aud_pll_ctrl",
+ DIV_TOPC3, 28, 3),
+};
+
+static struct samsung_pll_rate_table pll1460x_24mhz_tbl[] __initdata = {
+ PLL_36XX_RATE(491520000, 20, 1, 0, 31457),
+ {},
+};
+
+static struct samsung_gate_clock topc_gate_clks[] __initdata = {
+ GATE(ACLK_MSCL_532, "aclk_mscl_532", "dout_aclk_mscl_532",
+ ENABLE_ACLK_TOPC1, 20, 0, 0),
};
static struct samsung_pll_clock topc_pll_clks[] __initdata = {
@@ -136,8 +154,8 @@ static struct samsung_pll_clock topc_pll_clks[] __initdata = {
BUS1_DPLL_CON0, NULL),
PLL(pll_1452x, 0, "fout_mfc_pll", "fin_pll", MFC_PLL_LOCK,
MFC_PLL_CON0, NULL),
- PLL(pll_1460x, 0, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
- AUD_PLL_CON0, NULL),
+ PLL(pll_1460x, FOUT_AUD_PLL, "fout_aud_pll", "fin_pll", AUD_PLL_LOCK,
+ AUD_PLL_CON0, pll1460x_24mhz_tbl),
};
static struct samsung_cmu_info topc_cmu_info __initdata = {
@@ -147,6 +165,8 @@ static struct samsung_cmu_info topc_cmu_info __initdata = {
.nr_mux_clks = ARRAY_SIZE(topc_mux_clks),
.div_clks = topc_div_clks,
.nr_div_clks = ARRAY_SIZE(topc_div_clks),
+ .gate_clks = topc_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(topc_gate_clks),
.fixed_factor_clks = topc_fixed_factor_clks,
.nr_fixed_factor_clks = ARRAY_SIZE(topc_fixed_factor_clks),
.nr_clk_ids = TOPC_NR_CLK,
@@ -166,9 +186,18 @@ CLK_OF_DECLARE(exynos7_clk_topc, "samsung,exynos7-clock-topc",
#define MUX_SEL_TOP00 0x0200
#define MUX_SEL_TOP01 0x0204
#define MUX_SEL_TOP03 0x020C
+#define MUX_SEL_TOP0_PERIC0 0x0230
+#define MUX_SEL_TOP0_PERIC1 0x0234
+#define MUX_SEL_TOP0_PERIC2 0x0238
#define MUX_SEL_TOP0_PERIC3 0x023C
#define DIV_TOP03 0x060C
+#define DIV_TOP0_PERIC0 0x0630
+#define DIV_TOP0_PERIC1 0x0634
+#define DIV_TOP0_PERIC2 0x0638
#define DIV_TOP0_PERIC3 0x063C
+#define ENABLE_SCLK_TOP0_PERIC0 0x0A30
+#define ENABLE_SCLK_TOP0_PERIC1 0x0A34
+#define ENABLE_SCLK_TOP0_PERIC2 0x0A38
#define ENABLE_SCLK_TOP0_PERIC3 0x0A3C
/* List of parent clocks for Muxes in CMU_TOP0 */
@@ -176,6 +205,7 @@ PNAME(mout_bus0_pll_p) = { "fin_pll", "dout_sclk_bus0_pll" };
PNAME(mout_bus1_pll_p) = { "fin_pll", "dout_sclk_bus1_pll" };
PNAME(mout_cc_pll_p) = { "fin_pll", "dout_sclk_cc_pll" };
PNAME(mout_mfc_pll_p) = { "fin_pll", "dout_sclk_mfc_pll" };
+PNAME(mout_aud_pll_p) = { "fin_pll", "dout_sclk_aud_pll" };
PNAME(mout_top0_half_bus0_pll_p) = {"mout_top0_bus0_pll",
"ffac_top0_bus0_pll_div2"};
@@ -189,18 +219,34 @@ PNAME(mout_top0_half_mfc_pll_p) = {"mout_top0_mfc_pll",
PNAME(mout_top0_group1) = {"mout_top0_half_bus0_pll",
"mout_top0_half_bus1_pll", "mout_top0_half_cc_pll",
"mout_top0_half_mfc_pll"};
+PNAME(mout_top0_group3) = {"ioclk_audiocdclk0",
+ "ioclk_audiocdclk1", "ioclk_spdif_extclk",
+ "mout_top0_aud_pll", "mout_top0_half_bus0_pll",
+ "mout_top0_half_bus1_pll"};
+PNAME(mout_top0_group4) = {"ioclk_audiocdclk1", "mout_top0_aud_pll",
+ "mout_top0_half_bus0_pll", "mout_top0_half_bus1_pll"};
static unsigned long top0_clk_regs[] __initdata = {
MUX_SEL_TOP00,
MUX_SEL_TOP01,
MUX_SEL_TOP03,
+ MUX_SEL_TOP0_PERIC0,
+ MUX_SEL_TOP0_PERIC1,
+ MUX_SEL_TOP0_PERIC2,
MUX_SEL_TOP0_PERIC3,
DIV_TOP03,
+ DIV_TOP0_PERIC0,
+ DIV_TOP0_PERIC1,
+ DIV_TOP0_PERIC2,
DIV_TOP0_PERIC3,
+ ENABLE_SCLK_TOP0_PERIC0,
+ ENABLE_SCLK_TOP0_PERIC1,
+ ENABLE_SCLK_TOP0_PERIC2,
ENABLE_SCLK_TOP0_PERIC3,
};
static struct samsung_mux_clock top0_mux_clks[] __initdata = {
+ MUX(0, "mout_top0_aud_pll", mout_aud_pll_p, MUX_SEL_TOP00, 0, 1),
MUX(0, "mout_top0_mfc_pll", mout_mfc_pll_p, MUX_SEL_TOP00, 4, 1),
MUX(0, "mout_top0_cc_pll", mout_cc_pll_p, MUX_SEL_TOP00, 8, 1),
MUX(0, "mout_top0_bus1_pll", mout_bus1_pll_p, MUX_SEL_TOP00, 12, 1),
@@ -218,10 +264,20 @@ static struct samsung_mux_clock top0_mux_clks[] __initdata = {
MUX(0, "mout_aclk_peric1_66", mout_top0_group1, MUX_SEL_TOP03, 12, 2),
MUX(0, "mout_aclk_peric0_66", mout_top0_group1, MUX_SEL_TOP03, 20, 2),
+ MUX(0, "mout_sclk_spdif", mout_top0_group3, MUX_SEL_TOP0_PERIC0, 4, 3),
+ MUX(0, "mout_sclk_pcm1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 8, 2),
+ MUX(0, "mout_sclk_i2s1", mout_top0_group4, MUX_SEL_TOP0_PERIC0, 20, 2),
+
+ MUX(0, "mout_sclk_spi1", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 8, 2),
+ MUX(0, "mout_sclk_spi0", mout_top0_group1, MUX_SEL_TOP0_PERIC1, 20, 2),
+
+ MUX(0, "mout_sclk_spi3", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 8, 2),
+ MUX(0, "mout_sclk_spi2", mout_top0_group1, MUX_SEL_TOP0_PERIC2, 20, 2),
MUX(0, "mout_sclk_uart3", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 4, 2),
MUX(0, "mout_sclk_uart2", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 8, 2),
MUX(0, "mout_sclk_uart1", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 12, 2),
MUX(0, "mout_sclk_uart0", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 16, 2),
+ MUX(0, "mout_sclk_spi4", mout_top0_group1, MUX_SEL_TOP0_PERIC3, 20, 2),
};
static struct samsung_div_clock top0_div_clks[] __initdata = {
@@ -230,13 +286,40 @@ static struct samsung_div_clock top0_div_clks[] __initdata = {
DIV(DOUT_ACLK_PERIC0, "dout_aclk_peric0_66", "mout_aclk_peric0_66",
DIV_TOP03, 20, 6),
+ DIV(0, "dout_sclk_spdif", "mout_sclk_spdif", DIV_TOP0_PERIC0, 4, 4),
+ DIV(0, "dout_sclk_pcm1", "mout_sclk_pcm1", DIV_TOP0_PERIC0, 8, 12),
+ DIV(0, "dout_sclk_i2s1", "mout_sclk_i2s1", DIV_TOP0_PERIC0, 20, 10),
+
+ DIV(0, "dout_sclk_spi1", "mout_sclk_spi1", DIV_TOP0_PERIC1, 8, 12),
+ DIV(0, "dout_sclk_spi0", "mout_sclk_spi0", DIV_TOP0_PERIC1, 20, 12),
+
+ DIV(0, "dout_sclk_spi3", "mout_sclk_spi3", DIV_TOP0_PERIC2, 8, 12),
+ DIV(0, "dout_sclk_spi2", "mout_sclk_spi2", DIV_TOP0_PERIC2, 20, 12),
+
DIV(0, "dout_sclk_uart3", "mout_sclk_uart3", DIV_TOP0_PERIC3, 4, 4),
DIV(0, "dout_sclk_uart2", "mout_sclk_uart2", DIV_TOP0_PERIC3, 8, 4),
DIV(0, "dout_sclk_uart1", "mout_sclk_uart1", DIV_TOP0_PERIC3, 12, 4),
DIV(0, "dout_sclk_uart0", "mout_sclk_uart0", DIV_TOP0_PERIC3, 16, 4),
+ DIV(0, "dout_sclk_spi4", "mout_sclk_spi4", DIV_TOP0_PERIC3, 20, 12),
};
static struct samsung_gate_clock top0_gate_clks[] __initdata = {
+ GATE(CLK_SCLK_SPDIF, "sclk_spdif", "dout_sclk_spdif",
+ ENABLE_SCLK_TOP0_PERIC0, 4, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_PCM1, "sclk_pcm1", "dout_sclk_pcm1",
+ ENABLE_SCLK_TOP0_PERIC0, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_I2S1, "sclk_i2s1", "dout_sclk_i2s1",
+ ENABLE_SCLK_TOP0_PERIC0, 20, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_SCLK_SPI1, "sclk_spi1", "dout_sclk_spi1",
+ ENABLE_SCLK_TOP0_PERIC1, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI0, "sclk_spi0", "dout_sclk_spi0",
+ ENABLE_SCLK_TOP0_PERIC1, 20, CLK_SET_RATE_PARENT, 0),
+
+ GATE(CLK_SCLK_SPI3, "sclk_spi3", "dout_sclk_spi3",
+ ENABLE_SCLK_TOP0_PERIC2, 8, CLK_SET_RATE_PARENT, 0),
+ GATE(CLK_SCLK_SPI2, "sclk_spi2", "dout_sclk_spi2",
+ ENABLE_SCLK_TOP0_PERIC2, 20, CLK_SET_RATE_PARENT, 0),
GATE(CLK_SCLK_UART3, "sclk_uart3", "dout_sclk_uart3",
ENABLE_SCLK_TOP0_PERIC3, 4, 0, 0),
GATE(CLK_SCLK_UART2, "sclk_uart2", "dout_sclk_uart2",
@@ -245,6 +328,8 @@ static struct samsung_gate_clock top0_gate_clks[] __initdata = {
ENABLE_SCLK_TOP0_PERIC3, 12, 0, 0),
GATE(CLK_SCLK_UART0, "sclk_uart0", "dout_sclk_uart0",
ENABLE_SCLK_TOP0_PERIC3, 16, 0, 0),
+ GATE(CLK_SCLK_SPI4, "sclk_spi4", "dout_sclk_spi4",
+ ENABLE_SCLK_TOP0_PERIC3, 20, CLK_SET_RATE_PARENT, 0),
};
static struct samsung_fixed_factor_clock top0_fixed_factor_clks[] __initdata = {
@@ -343,6 +428,8 @@ static struct samsung_mux_clock top1_mux_clks[] __initdata = {
MUX(0, "mout_aclk_fsys0_200", mout_top1_group1, MUX_SEL_TOP13, 28, 2),
MUX(0, "mout_sclk_mmc2", mout_top1_group1, MUX_SEL_TOP1_FSYS0, 24, 2),
+ MUX(0, "mout_sclk_usbdrd300", mout_top1_group1,
+ MUX_SEL_TOP1_FSYS0, 28, 2),
MUX(0, "mout_sclk_mmc1", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 24, 2),
MUX(0, "mout_sclk_mmc0", mout_top1_group1, MUX_SEL_TOP1_FSYS1, 28, 2),
@@ -356,6 +443,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
DIV(DOUT_SCLK_MMC2, "dout_sclk_mmc2", "mout_sclk_mmc2",
DIV_TOP1_FSYS0, 24, 4),
+ DIV(0, "dout_sclk_usbdrd300", "mout_sclk_usbdrd300",
+ DIV_TOP1_FSYS0, 28, 4),
DIV(DOUT_SCLK_MMC1, "dout_sclk_mmc1", "mout_sclk_mmc1",
DIV_TOP1_FSYS1, 24, 4),
@@ -366,6 +455,8 @@ static struct samsung_div_clock top1_div_clks[] __initdata = {
static struct samsung_gate_clock top1_gate_clks[] __initdata = {
GATE(CLK_SCLK_MMC2, "sclk_mmc2", "dout_sclk_mmc2",
ENABLE_SCLK_TOP1_FSYS0, 24, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "sclk_usbdrd300", "dout_sclk_usbdrd300",
+ ENABLE_SCLK_TOP1_FSYS0, 28, 0, 0),
GATE(CLK_SCLK_MMC1, "sclk_mmc1", "dout_sclk_mmc1",
ENABLE_SCLK_TOP1_FSYS1, 24, CLK_SET_RATE_PARENT, 0),
@@ -514,6 +605,7 @@ static void __init exynos7_clk_peric0_init(struct device_node *np)
/* Register Offset definitions for CMU_PERIC1 (0x14C80000) */
#define MUX_SEL_PERIC10 0x0200
#define MUX_SEL_PERIC11 0x0204
+#define MUX_SEL_PERIC12 0x0208
#define ENABLE_PCLK_PERIC1 0x0900
#define ENABLE_SCLK_PERIC10 0x0A00
@@ -525,10 +617,16 @@ PNAME(mout_aclk_peric1_66_p) = { "fin_pll", "dout_aclk_peric1_66" };
PNAME(mout_sclk_uart1_p) = { "fin_pll", "sclk_uart1" };
PNAME(mout_sclk_uart2_p) = { "fin_pll", "sclk_uart2" };
PNAME(mout_sclk_uart3_p) = { "fin_pll", "sclk_uart3" };
+PNAME(mout_sclk_spi0_p) = { "fin_pll", "sclk_spi0" };
+PNAME(mout_sclk_spi1_p) = { "fin_pll", "sclk_spi1" };
+PNAME(mout_sclk_spi2_p) = { "fin_pll", "sclk_spi2" };
+PNAME(mout_sclk_spi3_p) = { "fin_pll", "sclk_spi3" };
+PNAME(mout_sclk_spi4_p) = { "fin_pll", "sclk_spi4" };
static unsigned long peric1_clk_regs[] __initdata = {
MUX_SEL_PERIC10,
MUX_SEL_PERIC11,
+ MUX_SEL_PERIC12,
ENABLE_PCLK_PERIC1,
ENABLE_SCLK_PERIC10,
};
@@ -537,6 +635,16 @@ static struct samsung_mux_clock peric1_mux_clks[] __initdata = {
MUX(0, "mout_aclk_peric1_66_user", mout_aclk_peric1_66_p,
MUX_SEL_PERIC10, 0, 1),
+ MUX_F(0, "mout_sclk_spi0_user", mout_sclk_spi0_p,
+ MUX_SEL_PERIC11, 0, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi1_user", mout_sclk_spi1_p,
+ MUX_SEL_PERIC11, 4, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi2_user", mout_sclk_spi2_p,
+ MUX_SEL_PERIC11, 8, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi3_user", mout_sclk_spi3_p,
+ MUX_SEL_PERIC11, 12, 1, CLK_SET_RATE_PARENT, 0),
+ MUX_F(0, "mout_sclk_spi4_user", mout_sclk_spi4_p,
+ MUX_SEL_PERIC11, 16, 1, CLK_SET_RATE_PARENT, 0),
MUX(0, "mout_sclk_uart1_user", mout_sclk_uart1_p,
MUX_SEL_PERIC11, 20, 1),
MUX(0, "mout_sclk_uart2_user", mout_sclk_uart2_p,
@@ -562,6 +670,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
ENABLE_PCLK_PERIC1, 10, 0, 0),
GATE(PCLK_UART3, "pclk_uart3", "mout_aclk_peric1_66_user",
ENABLE_PCLK_PERIC1, 11, 0, 0),
+ GATE(PCLK_SPI0, "pclk_spi0", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 12, 0, 0),
+ GATE(PCLK_SPI1, "pclk_spi1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 13, 0, 0),
+ GATE(PCLK_SPI2, "pclk_spi2", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 14, 0, 0),
+ GATE(PCLK_SPI3, "pclk_spi3", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 15, 0, 0),
+ GATE(PCLK_SPI4, "pclk_spi4", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 16, 0, 0),
+ GATE(PCLK_I2S1, "pclk_i2s1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 17, CLK_SET_RATE_PARENT, 0),
+ GATE(PCLK_PCM1, "pclk_pcm1", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 18, 0, 0),
+ GATE(PCLK_SPDIF, "pclk_spdif", "mout_aclk_peric1_66_user",
+ ENABLE_PCLK_PERIC1, 19, 0, 0),
GATE(SCLK_UART1, "sclk_uart1_user", "mout_sclk_uart1_user",
ENABLE_SCLK_PERIC10, 9, 0, 0),
@@ -569,6 +693,22 @@ static struct samsung_gate_clock peric1_gate_clks[] __initdata = {
ENABLE_SCLK_PERIC10, 10, 0, 0),
GATE(SCLK_UART3, "sclk_uart3_user", "mout_sclk_uart3_user",
ENABLE_SCLK_PERIC10, 11, 0, 0),
+ GATE(SCLK_SPI0, "sclk_spi0_user", "mout_sclk_spi0_user",
+ ENABLE_SCLK_PERIC10, 12, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI1, "sclk_spi1_user", "mout_sclk_spi1_user",
+ ENABLE_SCLK_PERIC10, 13, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI2, "sclk_spi2_user", "mout_sclk_spi2_user",
+ ENABLE_SCLK_PERIC10, 14, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI3, "sclk_spi3_user", "mout_sclk_spi3_user",
+ ENABLE_SCLK_PERIC10, 15, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPI4, "sclk_spi4_user", "mout_sclk_spi4_user",
+ ENABLE_SCLK_PERIC10, 16, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_I2S1, "sclk_i2s1_user", "sclk_i2s1",
+ ENABLE_SCLK_PERIC10, 17, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_PCM1, "sclk_pcm1_user", "sclk_pcm1",
+ ENABLE_SCLK_PERIC10, 18, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_SPDIF, "sclk_spdif_user", "sclk_spdif",
+ ENABLE_SCLK_PERIC10, 19, CLK_SET_RATE_PARENT, 0),
};
static struct samsung_cmu_info peric1_cmu_info __initdata = {
@@ -647,7 +787,12 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
/* Register Offset definitions for CMU_FSYS0 (0x10E90000) */
#define MUX_SEL_FSYS00 0x0200
#define MUX_SEL_FSYS01 0x0204
+#define MUX_SEL_FSYS02 0x0208
+#define ENABLE_ACLK_FSYS00 0x0800
#define ENABLE_ACLK_FSYS01 0x0804
+#define ENABLE_SCLK_FSYS01 0x0A04
+#define ENABLE_SCLK_FSYS02 0x0A08
+#define ENABLE_SCLK_FSYS04 0x0A10
/*
* List of parent clocks for Muxes in CMU_FSYS0
@@ -655,10 +800,29 @@ CLK_OF_DECLARE(exynos7_clk_peris, "samsung,exynos7-clock-peris",
PNAME(mout_aclk_fsys0_200_p) = { "fin_pll", "dout_aclk_fsys0_200" };
PNAME(mout_sclk_mmc2_p) = { "fin_pll", "sclk_mmc2" };
+PNAME(mout_sclk_usbdrd300_p) = { "fin_pll", "sclk_usbdrd300" };
+PNAME(mout_phyclk_usbdrd300_udrd30_phyclk_p) = { "fin_pll",
+ "phyclk_usbdrd300_udrd30_phyclock" };
+PNAME(mout_phyclk_usbdrd300_udrd30_pipe_pclk_p) = { "fin_pll",
+ "phyclk_usbdrd300_udrd30_pipe_pclk" };
+
+/* fixed rate clocks used in the FSYS0 block */
+struct samsung_fixed_rate_clock fixed_rate_clks_fsys0[] __initdata = {
+ FRATE(0, "phyclk_usbdrd300_udrd30_phyclock", NULL,
+ CLK_IS_ROOT, 60000000),
+ FRATE(0, "phyclk_usbdrd300_udrd30_pipe_pclk", NULL,
+ CLK_IS_ROOT, 125000000),
+};
+
static unsigned long fsys0_clk_regs[] __initdata = {
MUX_SEL_FSYS00,
MUX_SEL_FSYS01,
+ MUX_SEL_FSYS02,
+ ENABLE_ACLK_FSYS00,
ENABLE_ACLK_FSYS01,
+ ENABLE_SCLK_FSYS01,
+ ENABLE_SCLK_FSYS02,
+ ENABLE_SCLK_FSYS04,
};
static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
@@ -666,11 +830,49 @@ static struct samsung_mux_clock fsys0_mux_clks[] __initdata = {
MUX_SEL_FSYS00, 24, 1),
MUX(0, "mout_sclk_mmc2_user", mout_sclk_mmc2_p, MUX_SEL_FSYS01, 24, 1),
+ MUX(0, "mout_sclk_usbdrd300_user", mout_sclk_usbdrd300_p,
+ MUX_SEL_FSYS01, 28, 1),
+
+ MUX(0, "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ mout_phyclk_usbdrd300_udrd30_pipe_pclk_p,
+ MUX_SEL_FSYS02, 24, 1),
+ MUX(0, "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+ mout_phyclk_usbdrd300_udrd30_phyclk_p,
+ MUX_SEL_FSYS02, 28, 1),
};
static struct samsung_gate_clock fsys0_gate_clks[] __initdata = {
+ GATE(ACLK_AXIUS_USBDRD30X_FSYS0X, "aclk_axius_usbdrd30x_fsys0x",
+ "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 19, 0, 0),
+ GATE(ACLK_PDMA1, "aclk_pdma1", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 3, 0, 0),
+ GATE(ACLK_PDMA0, "aclk_pdma0", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS00, 4, 0, 0),
+
+ GATE(ACLK_USBDRD300, "aclk_usbdrd300", "mout_aclk_fsys0_200_user",
+ ENABLE_ACLK_FSYS01, 29, 0, 0),
GATE(ACLK_MMC2, "aclk_mmc2", "mout_aclk_fsys0_200_user",
ENABLE_ACLK_FSYS01, 31, 0, 0),
+
+ GATE(SCLK_USBDRD300_SUSPENDCLK, "sclk_usbdrd300_suspendclk",
+ "mout_sclk_usbdrd300_user",
+ ENABLE_SCLK_FSYS01, 4, 0, 0),
+ GATE(SCLK_USBDRD300_REFCLK, "sclk_usbdrd300_refclk", "fin_pll",
+ ENABLE_SCLK_FSYS01, 8, 0, 0),
+
+ GATE(PHYCLK_USBDRD300_UDRD30_PIPE_PCLK_USER,
+ "phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ "mout_phyclk_usbdrd300_udrd30_pipe_pclk_user",
+ ENABLE_SCLK_FSYS02, 24, 0, 0),
+ GATE(PHYCLK_USBDRD300_UDRD30_PHYCLK_USER,
+ "phyclk_usbdrd300_udrd30_phyclk_user",
+ "mout_phyclk_usbdrd300_udrd30_phyclk_user",
+ ENABLE_SCLK_FSYS02, 28, 0, 0),
+
+ GATE(OSCCLK_PHY_CLKOUT_USB30_PHY, "oscclk_phy_clkout_usb30_phy",
+ "fin_pll",
+ ENABLE_SCLK_FSYS04, 28, 0, 0),
};
static struct samsung_cmu_info fsys0_cmu_info __initdata = {
@@ -741,3 +943,205 @@ static void __init exynos7_clk_fsys1_init(struct device_node *np)
CLK_OF_DECLARE(exynos7_clk_fsys1, "samsung,exynos7-clock-fsys1",
exynos7_clk_fsys1_init);
+
+#define MUX_SEL_MSCL 0x0200
+#define DIV_MSCL 0x0600
+#define ENABLE_ACLK_MSCL 0x0800
+#define ENABLE_PCLK_MSCL 0x0900
+
+/* List of parent clocks for Muxes in CMU_MSCL */
+PNAME(mout_aclk_mscl_532_user_p) = { "fin_pll", "aclk_mscl_532" };
+
+static unsigned long mscl_clk_regs[] __initdata = {
+ MUX_SEL_MSCL,
+ DIV_MSCL,
+ ENABLE_ACLK_MSCL,
+ ENABLE_PCLK_MSCL,
+};
+
+static struct samsung_mux_clock mscl_mux_clks[] __initdata = {
+ MUX(USERMUX_ACLK_MSCL_532, "usermux_aclk_mscl_532",
+ mout_aclk_mscl_532_user_p, MUX_SEL_MSCL, 0, 1),
+};
+static struct samsung_div_clock mscl_div_clks[] __initdata = {
+ DIV(DOUT_PCLK_MSCL, "dout_pclk_mscl", "usermux_aclk_mscl_532",
+ DIV_MSCL, 0, 3),
+};
+static struct samsung_gate_clock mscl_gate_clks[] __initdata = {
+
+ GATE(ACLK_MSCL_0, "aclk_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 31, 0, 0),
+ GATE(ACLK_MSCL_1, "aclk_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 30, 0, 0),
+ GATE(ACLK_JPEG, "aclk_jpeg", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 29, 0, 0),
+ GATE(ACLK_G2D, "aclk_g2d", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 28, 0, 0),
+ GATE(ACLK_LH_ASYNC_SI_MSCL_0, "aclk_lh_async_si_mscl_0",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 27, 0, 0),
+ GATE(ACLK_LH_ASYNC_SI_MSCL_1, "aclk_lh_async_si_mscl_1",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 26, 0, 0),
+ GATE(ACLK_XIU_MSCLX_0, "aclk_xiu_msclx_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 25, 0, 0),
+ GATE(ACLK_XIU_MSCLX_1, "aclk_xiu_msclx_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 24, 0, 0),
+ GATE(ACLK_AXI2ACEL_BRIDGE, "aclk_axi2acel_bridge",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 23, 0, 0),
+ GATE(ACLK_QE_MSCL_0, "aclk_qe_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 22, 0, 0),
+ GATE(ACLK_QE_MSCL_1, "aclk_qe_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 21, 0, 0),
+ GATE(ACLK_QE_JPEG, "aclk_qe_jpeg", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 20, 0, 0),
+ GATE(ACLK_QE_G2D, "aclk_qe_g2d", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 19, 0, 0),
+ GATE(ACLK_PPMU_MSCL_0, "aclk_ppmu_mscl_0", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 18, 0, 0),
+ GATE(ACLK_PPMU_MSCL_1, "aclk_ppmu_mscl_1", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 17, 0, 0),
+ GATE(ACLK_MSCLNP_133, "aclk_msclnp_133", "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 16, 0, 0),
+ GATE(ACLK_AHB2APB_MSCL0P, "aclk_ahb2apb_mscl0p",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 15, 0, 0),
+ GATE(ACLK_AHB2APB_MSCL1P, "aclk_ahb2apb_mscl1p",
+ "usermux_aclk_mscl_532",
+ ENABLE_ACLK_MSCL, 14, 0, 0),
+
+ GATE(PCLK_MSCL_0, "pclk_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 31, 0, 0),
+ GATE(PCLK_MSCL_1, "pclk_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 30, 0, 0),
+ GATE(PCLK_JPEG, "pclk_jpeg", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 29, 0, 0),
+ GATE(PCLK_G2D, "pclk_g2d", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 28, 0, 0),
+ GATE(PCLK_QE_MSCL_0, "pclk_qe_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 27, 0, 0),
+ GATE(PCLK_QE_MSCL_1, "pclk_qe_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 26, 0, 0),
+ GATE(PCLK_QE_JPEG, "pclk_qe_jpeg", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 25, 0, 0),
+ GATE(PCLK_QE_G2D, "pclk_qe_g2d", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 24, 0, 0),
+ GATE(PCLK_PPMU_MSCL_0, "pclk_ppmu_mscl_0", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 23, 0, 0),
+ GATE(PCLK_PPMU_MSCL_1, "pclk_ppmu_mscl_1", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 22, 0, 0),
+ GATE(PCLK_AXI2ACEL_BRIDGE, "pclk_axi2acel_bridge", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 21, 0, 0),
+ GATE(PCLK_PMU_MSCL, "pclk_pmu_mscl", "dout_pclk_mscl",
+ ENABLE_PCLK_MSCL, 20, 0, 0),
+};
+
+static struct samsung_cmu_info mscl_cmu_info __initdata = {
+ .mux_clks = mscl_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(mscl_mux_clks),
+ .div_clks = mscl_div_clks,
+ .nr_div_clks = ARRAY_SIZE(mscl_div_clks),
+ .gate_clks = mscl_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(mscl_gate_clks),
+ .nr_clk_ids = MSCL_NR_CLK,
+ .clk_regs = mscl_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(mscl_clk_regs),
+};
+
+static void __init exynos7_clk_mscl_init(struct device_node *np)
+{
+ samsung_cmu_register_one(np, &mscl_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_mscl, "samsung,exynos7-clock-mscl",
+ exynos7_clk_mscl_init);
+
+/* Register Offset definitions for CMU_AUD (0x114C0000) */
+#define MUX_SEL_AUD 0x0200
+#define DIV_AUD0 0x0600
+#define DIV_AUD1 0x0604
+#define ENABLE_ACLK_AUD 0x0800
+#define ENABLE_PCLK_AUD 0x0900
+#define ENABLE_SCLK_AUD 0x0A00
+
+/*
+ * List of parent clocks for Muxes in CMU_AUD
+ */
+PNAME(mout_aud_pll_user_p) = { "fin_pll", "fout_aud_pll" };
+PNAME(mout_aud_group_p) = { "dout_aud_cdclk", "ioclk_audiocdclk0" };
+
+static unsigned long aud_clk_regs[] __initdata = {
+ MUX_SEL_AUD,
+ DIV_AUD0,
+ DIV_AUD1,
+ ENABLE_ACLK_AUD,
+ ENABLE_PCLK_AUD,
+ ENABLE_SCLK_AUD,
+};
+
+static struct samsung_mux_clock aud_mux_clks[] __initdata = {
+ MUX(0, "mout_sclk_i2s", mout_aud_group_p, MUX_SEL_AUD, 12, 1),
+ MUX(0, "mout_sclk_pcm", mout_aud_group_p, MUX_SEL_AUD, 16, 1),
+ MUX(0, "mout_aud_pll_user", mout_aud_pll_user_p, MUX_SEL_AUD, 20, 1),
+};
+
+static struct samsung_div_clock aud_div_clks[] __initdata = {
+ DIV(0, "dout_aud_ca5", "mout_aud_pll_user", DIV_AUD0, 0, 4),
+ DIV(0, "dout_aclk_aud", "dout_aud_ca5", DIV_AUD0, 4, 4),
+ DIV(0, "dout_aud_pclk_dbg", "dout_aud_ca5", DIV_AUD0, 8, 4),
+
+ DIV(0, "dout_sclk_i2s", "mout_sclk_i2s", DIV_AUD1, 0, 4),
+ DIV(0, "dout_sclk_pcm", "mout_sclk_pcm", DIV_AUD1, 4, 8),
+ DIV(0, "dout_sclk_uart", "dout_aud_cdclk", DIV_AUD1, 12, 4),
+ DIV(0, "dout_sclk_slimbus", "dout_aud_cdclk", DIV_AUD1, 16, 5),
+ DIV(0, "dout_aud_cdclk", "mout_aud_pll_user", DIV_AUD1, 24, 4),
+};
+
+static struct samsung_gate_clock aud_gate_clks[] __initdata = {
+ GATE(SCLK_PCM, "sclk_pcm", "dout_sclk_pcm",
+ ENABLE_SCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+ GATE(SCLK_I2S, "sclk_i2s", "dout_sclk_i2s",
+ ENABLE_SCLK_AUD, 28, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "sclk_uart", "dout_sclk_uart", ENABLE_SCLK_AUD, 29, 0, 0),
+ GATE(0, "sclk_slimbus", "dout_sclk_slimbus",
+ ENABLE_SCLK_AUD, 30, 0, 0),
+
+ GATE(0, "pclk_dbg_aud", "dout_aud_pclk_dbg", ENABLE_PCLK_AUD, 19, 0, 0),
+ GATE(0, "pclk_gpio_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 20, 0, 0),
+ GATE(0, "pclk_wdt1", "dout_aclk_aud", ENABLE_PCLK_AUD, 22, 0, 0),
+ GATE(0, "pclk_wdt0", "dout_aclk_aud", ENABLE_PCLK_AUD, 23, 0, 0),
+ GATE(0, "pclk_slimbus", "dout_aclk_aud", ENABLE_PCLK_AUD, 24, 0, 0),
+ GATE(0, "pclk_uart", "dout_aclk_aud", ENABLE_PCLK_AUD, 25, 0, 0),
+ GATE(PCLK_PCM, "pclk_pcm", "dout_aclk_aud",
+ ENABLE_PCLK_AUD, 26, CLK_SET_RATE_PARENT, 0),
+ GATE(PCLK_I2S, "pclk_i2s", "dout_aclk_aud",
+ ENABLE_PCLK_AUD, 27, CLK_SET_RATE_PARENT, 0),
+ GATE(0, "pclk_timer", "dout_aclk_aud", ENABLE_PCLK_AUD, 28, 0, 0),
+ GATE(0, "pclk_smmu_aud", "dout_aclk_aud", ENABLE_PCLK_AUD, 31, 0, 0),
+
+ GATE(0, "aclk_smmu_aud", "dout_aclk_aud", ENABLE_ACLK_AUD, 27, 0, 0),
+ GATE(0, "aclk_acel_lh_async_si_top", "dout_aclk_aud",
+ ENABLE_ACLK_AUD, 28, 0, 0),
+ GATE(ACLK_ADMA, "aclk_dmac", "dout_aclk_aud", ENABLE_ACLK_AUD, 31, 0, 0),
+};
+
+static struct samsung_cmu_info aud_cmu_info __initdata = {
+ .mux_clks = aud_mux_clks,
+ .nr_mux_clks = ARRAY_SIZE(aud_mux_clks),
+ .div_clks = aud_div_clks,
+ .nr_div_clks = ARRAY_SIZE(aud_div_clks),
+ .gate_clks = aud_gate_clks,
+ .nr_gate_clks = ARRAY_SIZE(aud_gate_clks),
+ .nr_clk_ids = AUD_NR_CLK,
+ .clk_regs = aud_clk_regs,
+ .nr_clk_regs = ARRAY_SIZE(aud_clk_regs),
+};
+
+static void __init exynos7_clk_aud_init(struct device_node *np)
+{
+ samsung_cmu_register_one(np, &aud_cmu_info);
+}
+
+CLK_OF_DECLARE(exynos7_clk_aud, "samsung,exynos7-clock-aud",
+ exynos7_clk_aud_init);
diff --git a/drivers/clk/samsung/clk.c b/drivers/clk/samsung/clk.c
index 4bda54095a16..9e1f88c04fd4 100644
--- a/drivers/clk/samsung/clk.c
+++ b/drivers/clk/samsung/clk.c
@@ -374,19 +374,24 @@ static void samsung_clk_sleep_init(void __iomem *reg_base,
* Common function which registers plls, muxes, dividers and gates
* for each CMU. It also add CMU register list to register cache.
*/
-void __init samsung_cmu_register_one(struct device_node *np,
+struct samsung_clk_provider * __init samsung_cmu_register_one(
+ struct device_node *np,
struct samsung_cmu_info *cmu)
{
void __iomem *reg_base;
struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
- if (!reg_base)
+ if (!reg_base) {
panic("%s: failed to map registers\n", __func__);
+ return NULL;
+ }
ctx = samsung_clk_init(np, reg_base, cmu->nr_clk_ids);
- if (!ctx)
+ if (!ctx) {
panic("%s: unable to alllocate ctx\n", __func__);
+ return ctx;
+ }
if (cmu->pll_clks)
samsung_clk_register_pll(ctx, cmu->pll_clks, cmu->nr_pll_clks,
@@ -410,4 +415,6 @@ void __init samsung_cmu_register_one(struct device_node *np,
cmu->nr_clk_regs);
samsung_clk_of_add_provider(np, ctx);
+
+ return ctx;
}
diff --git a/drivers/clk/samsung/clk.h b/drivers/clk/samsung/clk.h
index 8acabe1f32c4..e4c75383cea7 100644
--- a/drivers/clk/samsung/clk.h
+++ b/drivers/clk/samsung/clk.h
@@ -392,7 +392,8 @@ extern void __init samsung_clk_register_pll(struct samsung_clk_provider *ctx,
struct samsung_pll_clock *pll_list,
unsigned int nr_clk, void __iomem *base);
-extern void __init samsung_cmu_register_one(struct device_node *,
+extern struct samsung_clk_provider __init *samsung_cmu_register_one(
+ struct device_node *,
struct samsung_cmu_info *);
extern unsigned long _get_rate(const char *clk_name);
diff --git a/drivers/clk/shmobile/Makefile b/drivers/clk/shmobile/Makefile
index 960bf22d42ae..0689d7fb2666 100644
--- a/drivers/clk/shmobile/Makefile
+++ b/drivers/clk/shmobile/Makefile
@@ -1,9 +1,12 @@
obj-$(CONFIG_ARCH_EMEV2) += clk-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += clk-rz.o
+obj-$(CONFIG_ARCH_R8A73A4) += clk-r8a73a4.o
obj-$(CONFIG_ARCH_R8A7740) += clk-r8a7740.o
obj-$(CONFIG_ARCH_R8A7779) += clk-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7791) += clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_R8A7793) += clk-rcar-gen2.o
obj-$(CONFIG_ARCH_R8A7794) += clk-rcar-gen2.o
+obj-$(CONFIG_ARCH_SH73A0) += clk-sh73a0.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-div6.o
obj-$(CONFIG_ARCH_SHMOBILE_MULTI) += clk-mstp.o
diff --git a/drivers/clk/shmobile/clk-div6.c b/drivers/clk/shmobile/clk-div6.c
index 639241e31e03..036a692c7219 100644
--- a/drivers/clk/shmobile/clk-div6.c
+++ b/drivers/clk/shmobile/clk-div6.c
@@ -54,12 +54,19 @@ static int cpg_div6_clock_enable(struct clk_hw *hw)
static void cpg_div6_clock_disable(struct clk_hw *hw)
{
struct div6_clock *clock = to_div6_clock(hw);
+ u32 val;
- /* DIV6 clocks require the divisor field to be non-zero when stopping
- * the clock.
+ val = clk_readl(clock->reg);
+ val |= CPG_DIV6_CKSTP;
+ /*
+ * DIV6 clocks require the divisor field to be non-zero when stopping
+ * the clock. However, some clocks (e.g. ZB on sh73a0) fail to be
+ * re-enabled later if the divisor field is changed when stopping the
+ * clock
*/
- clk_writel(clk_readl(clock->reg) | CPG_DIV6_CKSTP | CPG_DIV6_DIV_MASK,
- clock->reg);
+ if (!(val & CPG_DIV6_DIV_MASK))
+ val |= CPG_DIV6_DIV_MASK;
+ clk_writel(val, clock->reg);
}
static int cpg_div6_clock_is_enabled(struct clk_hw *hw)
@@ -83,6 +90,9 @@ static unsigned int cpg_div6_clock_calc_div(unsigned long rate,
{
unsigned int div;
+ if (!rate)
+ rate = 1;
+
div = DIV_ROUND_CLOSEST(parent_rate, rate);
return clamp_t(unsigned int, div, 1, 64);
}
diff --git a/drivers/clk/shmobile/clk-r8a73a4.c b/drivers/clk/shmobile/clk-r8a73a4.c
new file mode 100644
index 000000000000..29b9a0b0012a
--- /dev/null
+++ b/drivers/clk/shmobile/clk-r8a73a4.c
@@ -0,0 +1,241 @@
+/*
+ * r8a73a4 Core CPG Clocks
+ *
+ * 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
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct r8a73a4_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_CKSCR 0xc0
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_FRQCRC 0xe0
+#define CPG_PLL0CR 0xd8
+#define CPG_PLL1CR 0x28
+#define CPG_PLL2CR 0x2c
+#define CPG_PLL2HCR 0xe4
+#define CPG_PLL2SCR 0xf4
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ unsigned int reg;
+ unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "i", CPG_FRQCRA, 20 },
+ { "m3", CPG_FRQCRA, 12 },
+ { "b", CPG_FRQCRA, 8 },
+ { "m1", CPG_FRQCRA, 4 },
+ { "m2", CPG_FRQCRA, 0 },
+ { "zx", CPG_FRQCRB, 12 },
+ { "zs", CPG_FRQCRB, 8 },
+ { "hp", CPG_FRQCRB, 4 },
+ { NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+ { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+ { 12, 10 }, { 0, 0 }
+};
+
+static struct clk * __init
+r8a73a4_cpg_register_clock(struct device_node *np, struct r8a73a4_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ const char *parent_name;
+ unsigned int shift, reg;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+
+ if (!strcmp(name, "main")) {
+ u32 ckscr = clk_readl(cpg->reg + CPG_CKSCR);
+
+ switch ((ckscr >> 28) & 3) {
+ case 0: /* extal1 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ break;
+ case 1: /* extal1 / 2 */
+ parent_name = of_clk_get_parent_name(np, 0);
+ div = 2;
+ break;
+ case 2: /* extal2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ break;
+ case 3: /* extal2 / 2 */
+ parent_name = of_clk_get_parent_name(np, 1);
+ div = 2;
+ break;
+ }
+ } else if (!strcmp(name, "pll0")) {
+ /* PLL0/1 are configurable multiplier clocks. Register them as
+ * fixed factor clocks for now as there's no generic multiplier
+ * clock implementation and we currently have no need to change
+ * the multiplier value.
+ */
+ u32 value = clk_readl(cpg->reg + CPG_PLL0CR);
+
+ parent_name = "main";
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(20))
+ div = 2;
+ } else if (!strcmp(name, "pll1")) {
+ u32 value = clk_readl(cpg->reg + CPG_PLL1CR);
+
+ parent_name = "main";
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ if (value & BIT(7))
+ div = 2;
+ } else if (!strncmp(name, "pll2", 4)) {
+ u32 value, cr;
+
+ switch (name[4]) {
+ case 0:
+ cr = CPG_PLL2CR;
+ break;
+ case 's':
+ cr = CPG_PLL2SCR;
+ break;
+ case 'h':
+ cr = CPG_PLL2HCR;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ value = clk_readl(cpg->reg + cr);
+ switch ((value >> 5) & 7) {
+ case 0:
+ parent_name = "main";
+ div = 2;
+ break;
+ case 1:
+ parent_name = "extal2";
+ div = 2;
+ break;
+ case 3:
+ parent_name = "extal2";
+ div = 4;
+ break;
+ case 4:
+ parent_name = "main";
+ break;
+ case 5:
+ parent_name = "extal2";
+ break;
+ default:
+ pr_warn("%s: unexpected parent of %s\n", __func__,
+ name);
+ return ERR_PTR(-EINVAL);
+ }
+ /* XXX: enable bit? */
+ mult = ((value >> 24) & 0x7f) + 1;
+ } else if (!strcmp(name, "z") || !strcmp(name, "z2")) {
+ u32 shift = 8;
+
+ parent_name = "pll0";
+ if (name[1] == '2') {
+ div = 2;
+ shift = 0;
+ }
+ div *= 32;
+ mult = 0x20 - ((clk_readl(cpg->reg + CPG_FRQCRC) >> shift)
+ & 0x1f);
+ } else {
+ struct div4_clk *c;
+
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name))
+ break;
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+
+ parent_name = "pll1";
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ }
+
+ if (!table) {
+ return clk_register_fixed_factor(NULL, name, parent_name, 0,
+ mult, div);
+ } else {
+ return clk_register_divider_table(NULL, name, parent_name, 0,
+ cpg->reg + reg, shift, 4, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init r8a73a4_cpg_clocks_init(struct device_node *np)
+{
+ struct r8a73a4_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = r8a73a4_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(r8a73a4_cpg_clks, "renesas,r8a73a4-cpg-clocks",
+ r8a73a4_cpg_clocks_init);
diff --git a/drivers/clk/shmobile/clk-rcar-gen2.c b/drivers/clk/shmobile/clk-rcar-gen2.c
index e996425d06a9..acfb6d7dbd6b 100644
--- a/drivers/clk/shmobile/clk-rcar-gen2.c
+++ b/drivers/clk/shmobile/clk-rcar-gen2.c
@@ -33,6 +33,8 @@ struct rcar_gen2_cpg {
#define CPG_FRQCRC 0x000000e0
#define CPG_FRQCRC_ZFC_MASK (0x1f << 8)
#define CPG_FRQCRC_ZFC_SHIFT 8
+#define CPG_ADSPCKCR 0x0000025c
+#define CPG_RCANCKCR 0x00000270
/* -----------------------------------------------------------------------------
* Z Clock
@@ -161,6 +163,88 @@ static struct clk * __init cpg_z_clk_register(struct rcar_gen2_cpg *cpg)
return clk;
}
+static struct clk * __init cpg_rcan_clk_register(struct rcar_gen2_cpg *cpg,
+ struct device_node *np)
+{
+ const char *parent_name = of_clk_get_parent_name(np, 1);
+ struct clk_fixed_factor *fixed;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ fixed = kzalloc(sizeof(*fixed), GFP_KERNEL);
+ if (!fixed)
+ return ERR_PTR(-ENOMEM);
+
+ fixed->mult = 1;
+ fixed->div = 6;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(fixed);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_RCANCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "rcan", &parent_name, 1, NULL, NULL,
+ &fixed->hw, &clk_fixed_factor_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(fixed);
+ }
+
+ return clk;
+}
+
+/* ADSP divisors */
+static const struct clk_div_table cpg_adsp_div_table[] = {
+ { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 },
+ { 5, 12 }, { 6, 16 }, { 7, 18 }, { 8, 24 },
+ { 10, 36 }, { 11, 48 }, { 0, 0 },
+};
+
+static struct clk * __init cpg_adsp_clk_register(struct rcar_gen2_cpg *cpg)
+{
+ const char *parent_name = "pll1";
+ struct clk_divider *div;
+ struct clk_gate *gate;
+ struct clk *clk;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ div->reg = cpg->reg + CPG_ADSPCKCR;
+ div->width = 4;
+ div->table = cpg_adsp_div_table;
+ div->lock = &cpg->lock;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate) {
+ kfree(div);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ gate->reg = cpg->reg + CPG_ADSPCKCR;
+ gate->bit_idx = 8;
+ gate->flags = CLK_GATE_SET_TO_DISABLE;
+ gate->lock = &cpg->lock;
+
+ clk = clk_register_composite(NULL, "adsp", &parent_name, 1, NULL, NULL,
+ &div->hw, &clk_divider_ops,
+ &gate->hw, &clk_gate_ops, 0);
+ if (IS_ERR(clk)) {
+ kfree(gate);
+ kfree(div);
+ }
+
+ return clk;
+}
+
/* -----------------------------------------------------------------------------
* CPG Clock Data
*/
@@ -263,6 +347,10 @@ rcar_gen2_cpg_register_clock(struct device_node *np, struct rcar_gen2_cpg *cpg,
shift = 0;
} else if (!strcmp(name, "z")) {
return cpg_z_clk_register(cpg);
+ } else if (!strcmp(name, "rcan")) {
+ return cpg_rcan_clk_register(cpg, np);
+ } else if (!strcmp(name, "adsp")) {
+ return cpg_adsp_clk_register(cpg);
} else {
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/shmobile/clk-sh73a0.c b/drivers/clk/shmobile/clk-sh73a0.c
new file mode 100644
index 000000000000..cd529cfe412f
--- /dev/null
+++ b/drivers/clk/shmobile/clk-sh73a0.c
@@ -0,0 +1,218 @@
+/*
+ * sh73a0 Core CPG Clocks
+ *
+ * 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
+ * the Free Software Foundation; version 2 of the License.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/clk/shmobile.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/spinlock.h>
+
+struct sh73a0_cpg {
+ struct clk_onecell_data data;
+ spinlock_t lock;
+ void __iomem *reg;
+};
+
+#define CPG_FRQCRA 0x00
+#define CPG_FRQCRB 0x04
+#define CPG_SD0CKCR 0x74
+#define CPG_SD1CKCR 0x78
+#define CPG_SD2CKCR 0x7c
+#define CPG_PLLECR 0xd0
+#define CPG_PLL0CR 0xd8
+#define CPG_PLL1CR 0x28
+#define CPG_PLL2CR 0x2c
+#define CPG_PLL3CR 0xdc
+#define CPG_CKSCR 0xc0
+#define CPG_DSI0PHYCR 0x6c
+#define CPG_DSI1PHYCR 0x70
+
+#define CLK_ENABLE_ON_INIT BIT(0)
+
+struct div4_clk {
+ const char *name;
+ const char *parent;
+ unsigned int reg;
+ unsigned int shift;
+};
+
+static struct div4_clk div4_clks[] = {
+ { "zg", "pll0", CPG_FRQCRA, 16 },
+ { "m3", "pll1", CPG_FRQCRA, 12 },
+ { "b", "pll1", CPG_FRQCRA, 8 },
+ { "m1", "pll1", CPG_FRQCRA, 4 },
+ { "m2", "pll1", CPG_FRQCRA, 0 },
+ { "zx", "pll1", CPG_FRQCRB, 12 },
+ { "hp", "pll1", CPG_FRQCRB, 4 },
+ { NULL, NULL, 0, 0 },
+};
+
+static const struct clk_div_table div4_div_table[] = {
+ { 0, 2 }, { 1, 3 }, { 2, 4 }, { 3, 6 }, { 4, 8 }, { 5, 12 },
+ { 6, 16 }, { 7, 18 }, { 8, 24 }, { 10, 36 }, { 11, 48 },
+ { 12, 7 }, { 0, 0 }
+};
+
+static const struct clk_div_table z_div_table[] = {
+ /* ZSEL == 0 */
+ { 0, 1 }, { 1, 1 }, { 2, 1 }, { 3, 1 }, { 4, 1 }, { 5, 1 },
+ { 6, 1 }, { 7, 1 }, { 8, 1 }, { 9, 1 }, { 10, 1 }, { 11, 1 },
+ { 12, 1 }, { 13, 1 }, { 14, 1 }, { 15, 1 },
+ /* ZSEL == 1 */
+ { 16, 2 }, { 17, 3 }, { 18, 4 }, { 19, 6 }, { 20, 8 }, { 21, 12 },
+ { 22, 16 }, { 24, 24 }, { 27, 48 }, { 0, 0 }
+};
+
+static struct clk * __init
+sh73a0_cpg_register_clock(struct device_node *np, struct sh73a0_cpg *cpg,
+ const char *name)
+{
+ const struct clk_div_table *table = NULL;
+ unsigned int shift, reg, width;
+ const char *parent_name;
+ unsigned int mult = 1;
+ unsigned int div = 1;
+
+ if (!strcmp(name, "main")) {
+ /* extal1, extal1_div2, extal2, extal2_div2 */
+ u32 parent_idx = (clk_readl(cpg->reg + CPG_CKSCR) >> 28) & 3;
+
+ parent_name = of_clk_get_parent_name(np, parent_idx >> 1);
+ div = (parent_idx & 1) + 1;
+ } else if (!strncmp(name, "pll", 3)) {
+ void __iomem *enable_reg = cpg->reg;
+ u32 enable_bit = name[3] - '0';
+
+ parent_name = "main";
+ switch (enable_bit) {
+ case 0:
+ enable_reg += CPG_PLL0CR;
+ break;
+ case 1:
+ enable_reg += CPG_PLL1CR;
+ break;
+ case 2:
+ enable_reg += CPG_PLL2CR;
+ break;
+ case 3:
+ enable_reg += CPG_PLL3CR;
+ break;
+ default:
+ return ERR_PTR(-EINVAL);
+ }
+ if (clk_readl(cpg->reg + CPG_PLLECR) & BIT(enable_bit)) {
+ mult = ((clk_readl(enable_reg) >> 24) & 0x3f) + 1;
+ /* handle CFG bit for PLL1 and PLL2 */
+ if (enable_bit == 1 || enable_bit == 2)
+ if (clk_readl(enable_reg) & BIT(20))
+ mult *= 2;
+ }
+ } else if (!strcmp(name, "dsi0phy") || !strcmp(name, "dsi1phy")) {
+ u32 phy_no = name[3] - '0';
+ void __iomem *dsi_reg = cpg->reg +
+ (phy_no ? CPG_DSI1PHYCR : CPG_DSI0PHYCR);
+
+ parent_name = phy_no ? "dsi1pck" : "dsi0pck";
+ mult = __raw_readl(dsi_reg);
+ if (!(mult & 0x8000))
+ mult = 1;
+ else
+ mult = (mult & 0x3f) + 1;
+ } else if (!strcmp(name, "z")) {
+ parent_name = "pll0";
+ table = z_div_table;
+ reg = CPG_FRQCRB;
+ shift = 24;
+ width = 5;
+ } else {
+ struct div4_clk *c;
+
+ for (c = div4_clks; c->name; c++) {
+ if (!strcmp(name, c->name)) {
+ parent_name = c->parent;
+ table = div4_div_table;
+ reg = c->reg;
+ shift = c->shift;
+ width = 4;
+ break;
+ }
+ }
+ if (!c->name)
+ return ERR_PTR(-EINVAL);
+ }
+
+ if (!table) {
+ return clk_register_fixed_factor(NULL, name, parent_name, 0,
+ mult, div);
+ } else {
+ return clk_register_divider_table(NULL, name, parent_name, 0,
+ cpg->reg + reg, shift, width, 0,
+ table, &cpg->lock);
+ }
+}
+
+static void __init sh73a0_cpg_clocks_init(struct device_node *np)
+{
+ struct sh73a0_cpg *cpg;
+ struct clk **clks;
+ unsigned int i;
+ int num_clks;
+
+ num_clks = of_property_count_strings(np, "clock-output-names");
+ if (num_clks < 0) {
+ pr_err("%s: failed to count clocks\n", __func__);
+ return;
+ }
+
+ cpg = kzalloc(sizeof(*cpg), GFP_KERNEL);
+ clks = kcalloc(num_clks, sizeof(*clks), GFP_KERNEL);
+ if (cpg == NULL || clks == NULL) {
+ /* We're leaking memory on purpose, there's no point in cleaning
+ * up as the system won't boot anyway.
+ */
+ return;
+ }
+
+ spin_lock_init(&cpg->lock);
+
+ cpg->data.clks = clks;
+ cpg->data.clk_num = num_clks;
+
+ cpg->reg = of_iomap(np, 0);
+ if (WARN_ON(cpg->reg == NULL))
+ return;
+
+ /* Set SDHI clocks to a known state */
+ clk_writel(0x108, cpg->reg + CPG_SD0CKCR);
+ clk_writel(0x108, cpg->reg + CPG_SD1CKCR);
+ clk_writel(0x108, cpg->reg + CPG_SD2CKCR);
+
+ for (i = 0; i < num_clks; ++i) {
+ const char *name;
+ struct clk *clk;
+
+ of_property_read_string_index(np, "clock-output-names", i,
+ &name);
+
+ clk = sh73a0_cpg_register_clock(np, cpg, name);
+ if (IS_ERR(clk))
+ pr_err("%s: failed to register %s %s clock (%ld)\n",
+ __func__, np->name, name, PTR_ERR(clk));
+ else
+ cpg->data.clks[i] = clk;
+ }
+
+ of_clk_add_provider(np, of_clk_src_onecell_get, &cpg->data);
+}
+CLK_OF_DECLARE(sh73a0_cpg_clks, "renesas,sh73a0-cpg-clocks",
+ sh73a0_cpg_clocks_init);
diff --git a/drivers/clk/st/clk-flexgen.c b/drivers/clk/st/clk-flexgen.c
index 2282cef9f2ff..bf12a25eb3a2 100644
--- a/drivers/clk/st/clk-flexgen.c
+++ b/drivers/clk/st/clk-flexgen.c
@@ -37,8 +37,8 @@ static int flexgen_enable(struct clk_hw *hw)
struct clk_hw *pgate_hw = &flexgen->pgate.hw;
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
- pgate_hw->clk = hw->clk;
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(pgate_hw, hw);
+ __clk_hw_set_clk(fgate_hw, hw);
clk_gate_ops.enable(pgate_hw);
@@ -54,7 +54,7 @@ static void flexgen_disable(struct clk_hw *hw)
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
/* disable only the final gate */
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(fgate_hw, hw);
clk_gate_ops.disable(fgate_hw);
@@ -66,7 +66,7 @@ static int flexgen_is_enabled(struct clk_hw *hw)
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *fgate_hw = &flexgen->fgate.hw;
- fgate_hw->clk = hw->clk;
+ __clk_hw_set_clk(fgate_hw, hw);
if (!clk_gate_ops.is_enabled(fgate_hw))
return 0;
@@ -79,7 +79,7 @@ static u8 flexgen_get_parent(struct clk_hw *hw)
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *mux_hw = &flexgen->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return clk_mux_ops.get_parent(mux_hw);
}
@@ -89,7 +89,7 @@ static int flexgen_set_parent(struct clk_hw *hw, u8 index)
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *mux_hw = &flexgen->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return clk_mux_ops.set_parent(mux_hw, index);
}
@@ -124,8 +124,8 @@ unsigned long flexgen_recalc_rate(struct clk_hw *hw,
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
unsigned long mid_rate;
- pdiv_hw->clk = hw->clk;
- fdiv_hw->clk = hw->clk;
+ __clk_hw_set_clk(pdiv_hw, hw);
+ __clk_hw_set_clk(fdiv_hw, hw);
mid_rate = clk_divider_ops.recalc_rate(pdiv_hw, parent_rate);
@@ -138,16 +138,27 @@ static int flexgen_set_rate(struct clk_hw *hw, unsigned long rate,
struct flexgen *flexgen = to_flexgen(hw);
struct clk_hw *pdiv_hw = &flexgen->pdiv.hw;
struct clk_hw *fdiv_hw = &flexgen->fdiv.hw;
- unsigned long primary_div = 0;
+ unsigned long div = 0;
int ret = 0;
- pdiv_hw->clk = hw->clk;
- fdiv_hw->clk = hw->clk;
+ __clk_hw_set_clk(pdiv_hw, hw);
+ __clk_hw_set_clk(fdiv_hw, hw);
- primary_div = clk_best_div(parent_rate, rate);
+ div = clk_best_div(parent_rate, rate);
- clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
- ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * primary_div);
+ /*
+ * pdiv is mainly targeted for low freq results, while fdiv
+ * should be used for div <= 64. The other way round can
+ * lead to 'duty cycle' issues.
+ */
+
+ if (div <= 64) {
+ clk_divider_ops.set_rate(pdiv_hw, parent_rate, parent_rate);
+ ret = clk_divider_ops.set_rate(fdiv_hw, rate, rate * div);
+ } else {
+ clk_divider_ops.set_rate(fdiv_hw, parent_rate, parent_rate);
+ ret = clk_divider_ops.set_rate(pdiv_hw, rate, rate * div);
+ }
return ret;
}
diff --git a/drivers/clk/st/clkgen-mux.c b/drivers/clk/st/clkgen-mux.c
index 79dc40b5cc68..9a15ec344a85 100644
--- a/drivers/clk/st/clkgen-mux.c
+++ b/drivers/clk/st/clkgen-mux.c
@@ -94,7 +94,7 @@ static int clkgena_divmux_enable(struct clk_hw *hw)
unsigned long timeout;
int ret = 0;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
ret = clk_mux_ops.set_parent(mux_hw, genamux->muxsel);
if (ret)
@@ -116,7 +116,7 @@ static void clkgena_divmux_disable(struct clk_hw *hw)
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
clk_mux_ops.set_parent(mux_hw, CKGAX_CLKOPSRC_SWITCH_OFF);
}
@@ -126,7 +126,7 @@ static int clkgena_divmux_is_enabled(struct clk_hw *hw)
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return (s8)clk_mux_ops.get_parent(mux_hw) > 0;
}
@@ -136,7 +136,7 @@ u8 clkgena_divmux_get_parent(struct clk_hw *hw)
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *mux_hw = &genamux->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
genamux->muxsel = clk_mux_ops.get_parent(mux_hw);
if ((s8)genamux->muxsel < 0) {
@@ -174,7 +174,7 @@ unsigned long clkgena_divmux_recalc_rate(struct clk_hw *hw,
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.recalc_rate(div_hw, parent_rate);
}
@@ -185,7 +185,7 @@ static int clkgena_divmux_set_rate(struct clk_hw *hw, unsigned long rate,
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.set_rate(div_hw, rate, parent_rate);
}
@@ -196,7 +196,7 @@ static long clkgena_divmux_round_rate(struct clk_hw *hw, unsigned long rate,
struct clkgena_divmux *genamux = to_clkgena_divmux(hw);
struct clk_hw *div_hw = &genamux->div[genamux->muxsel].hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return clk_divider_ops.round_rate(div_hw, rate, prate);
}
diff --git a/drivers/clk/sunxi/Makefile b/drivers/clk/sunxi/Makefile
index a66953c0f430..3a5292e3fcf8 100644
--- a/drivers/clk/sunxi/Makefile
+++ b/drivers/clk/sunxi/Makefile
@@ -8,6 +8,7 @@ obj-y += clk-a20-gmac.o
obj-y += clk-mod0.o
obj-y += clk-sun8i-mbus.o
obj-y += clk-sun9i-core.o
+obj-y += clk-sun9i-mmc.o
obj-$(CONFIG_MFD_SUN6I_PRCM) += \
clk-sun6i-ar100.o clk-sun6i-apb0.o clk-sun6i-apb0-gates.o \
diff --git a/drivers/clk/sunxi/clk-factors.c b/drivers/clk/sunxi/clk-factors.c
index 62e08fb58554..8c20190a3e9f 100644
--- a/drivers/clk/sunxi/clk-factors.c
+++ b/drivers/clk/sunxi/clk-factors.c
@@ -80,6 +80,8 @@ static long clk_factors_round_rate(struct clk_hw *hw, unsigned long rate,
}
static long clk_factors_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_p)
{
@@ -156,9 +158,10 @@ static const struct clk_ops clk_factors_ops = {
.set_rate = clk_factors_set_rate,
};
-struct clk * __init sunxi_factors_register(struct device_node *node,
- const struct factors_data *data,
- spinlock_t *lock)
+struct clk *sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock,
+ void __iomem *reg)
{
struct clk *clk;
struct clk_factors *factors;
@@ -168,11 +171,8 @@ struct clk * __init sunxi_factors_register(struct device_node *node,
struct clk_hw *mux_hw = NULL;
const char *clk_name = node->name;
const char *parents[FACTORS_MAX_PARENTS];
- void __iomem *reg;
int i = 0;
- reg = of_iomap(node, 0);
-
/* if we have a mux, we will have >1 parents */
while (i < FACTORS_MAX_PARENTS &&
(parents[i] = of_clk_get_parent_name(node, i)) != NULL)
diff --git a/drivers/clk/sunxi/clk-factors.h b/drivers/clk/sunxi/clk-factors.h
index 912238fde132..171085ab5513 100644
--- a/drivers/clk/sunxi/clk-factors.h
+++ b/drivers/clk/sunxi/clk-factors.h
@@ -36,8 +36,9 @@ struct clk_factors {
spinlock_t *lock;
};
-struct clk * __init sunxi_factors_register(struct device_node *node,
- const struct factors_data *data,
- spinlock_t *lock);
+struct clk *sunxi_factors_register(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock,
+ void __iomem *reg);
#endif
diff --git a/drivers/clk/sunxi/clk-mod0.c b/drivers/clk/sunxi/clk-mod0.c
index da0524eaee94..ec8f5a1fca09 100644
--- a/drivers/clk/sunxi/clk-mod0.c
+++ b/drivers/clk/sunxi/clk-mod0.c
@@ -17,6 +17,7 @@
#include <linux/clk-provider.h>
#include <linux/clkdev.h>
#include <linux/of_address.h>
+#include <linux/platform_device.h>
#include "clk-factors.h"
@@ -67,7 +68,7 @@ static struct clk_factors_config sun4i_a10_mod0_config = {
.pwidth = 2,
};
-static const struct factors_data sun4i_a10_mod0_data __initconst = {
+static const struct factors_data sun4i_a10_mod0_data = {
.enable = 31,
.mux = 24,
.muxmask = BIT(1) | BIT(0),
@@ -79,15 +80,95 @@ static DEFINE_SPINLOCK(sun4i_a10_mod0_lock);
static void __init sun4i_a10_mod0_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun4i_a10_mod0_lock);
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ /*
+ * This happens with mod0 clk nodes instantiated through
+ * mfd, as those do not have their resources assigned at
+ * CLK_OF_DECLARE time yet, so do not print an error.
+ */
+ return;
+ }
+
+ sunxi_factors_register(node, &sun4i_a10_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
}
CLK_OF_DECLARE(sun4i_a10_mod0, "allwinner,sun4i-a10-mod0-clk", sun4i_a10_mod0_setup);
+static int sun4i_a10_mod0_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct resource *r;
+ void __iomem *reg;
+
+ if (!np)
+ return -ENODEV;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ reg = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(reg))
+ return PTR_ERR(reg);
+
+ sunxi_factors_register(np, &sun4i_a10_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
+ return 0;
+}
+
+static const struct of_device_id sun4i_a10_mod0_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun4i-a10-mod0-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun4i_a10_mod0_clk_driver = {
+ .driver = {
+ .name = "sun4i-a10-mod0-clk",
+ .of_match_table = sun4i_a10_mod0_clk_dt_ids,
+ },
+ .probe = sun4i_a10_mod0_clk_probe,
+};
+module_platform_driver(sun4i_a10_mod0_clk_driver);
+
+static const struct factors_data sun9i_a80_mod0_data __initconst = {
+ .enable = 31,
+ .mux = 24,
+ .muxmask = BIT(3) | BIT(2) | BIT(1) | BIT(0),
+ .table = &sun4i_a10_mod0_config,
+ .getter = sun4i_a10_get_mod0_factors,
+};
+
+static void __init sun9i_a80_mod0_setup(struct device_node *node)
+{
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ pr_err("Could not get registers for mod0-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_mod0_data,
+ &sun4i_a10_mod0_lock, reg);
+}
+CLK_OF_DECLARE(sun9i_a80_mod0, "allwinner,sun9i-a80-mod0-clk", sun9i_a80_mod0_setup);
+
static DEFINE_SPINLOCK(sun5i_a13_mbus_lock);
static void __init sun5i_a13_mbus_setup(struct device_node *node)
{
- struct clk *mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data, &sun5i_a13_mbus_lock);
+ struct clk *mbus;
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for a13-mbus-clk\n");
+ return;
+ }
+
+ mbus = sunxi_factors_register(node, &sun4i_a10_mod0_data,
+ &sun5i_a13_mbus_lock, reg);
/* The MBUS clocks needs to be always enabled */
__clk_get(mbus);
@@ -95,14 +176,10 @@ static void __init sun5i_a13_mbus_setup(struct device_node *node)
}
CLK_OF_DECLARE(sun5i_a13_mbus, "allwinner,sun5i-a13-mbus-clk", sun5i_a13_mbus_setup);
-struct mmc_phase_data {
- u8 offset;
-};
-
struct mmc_phase {
struct clk_hw hw;
+ u8 offset;
void __iomem *reg;
- struct mmc_phase_data *data;
spinlock_t *lock;
};
@@ -118,7 +195,7 @@ static int mmc_get_phase(struct clk_hw *hw)
u8 delay;
value = readl(phase->reg);
- delay = (value >> phase->data->offset) & 0x3;
+ delay = (value >> phase->offset) & 0x3;
if (!delay)
return 180;
@@ -206,8 +283,8 @@ static int mmc_set_phase(struct clk_hw *hw, int degrees)
spin_lock_irqsave(phase->lock, flags);
value = readl(phase->reg);
- value &= ~GENMASK(phase->data->offset + 3, phase->data->offset);
- value |= delay << phase->data->offset;
+ value &= ~GENMASK(phase->offset + 3, phase->offset);
+ value |= delay << phase->offset;
writel(value, phase->reg);
spin_unlock_irqrestore(phase->lock, flags);
@@ -219,66 +296,97 @@ static const struct clk_ops mmc_clk_ops = {
.set_phase = mmc_set_phase,
};
-static void __init sun4i_a10_mmc_phase_setup(struct device_node *node,
- struct mmc_phase_data *data)
+/*
+ * sunxi_mmc_setup - Common setup function for mmc module clocks
+ *
+ * The only difference between module clocks on different platforms is the
+ * width of the mux register bits and the valid values, which are passed in
+ * through struct factors_data. The phase clocks parts are identical.
+ */
+static void __init sunxi_mmc_setup(struct device_node *node,
+ const struct factors_data *data,
+ spinlock_t *lock)
{
- const char *parent_names[1] = { of_clk_get_parent_name(node, 0) };
- struct clk_init_data init = {
- .num_parents = 1,
- .parent_names = parent_names,
- .ops = &mmc_clk_ops,
- };
-
- struct mmc_phase *phase;
- struct clk *clk;
-
- phase = kmalloc(sizeof(*phase), GFP_KERNEL);
- if (!phase)
+ struct clk_onecell_data *clk_data;
+ const char *parent;
+ void __iomem *reg;
+ int i;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (IS_ERR(reg)) {
+ pr_err("Couldn't map the %s clock registers\n", node->name);
return;
+ }
- phase->hw.init = &init;
-
- phase->reg = of_iomap(node, 0);
- if (!phase->reg)
- goto err_free;
-
- phase->data = data;
- phase->lock = &sun4i_a10_mod0_lock;
-
- if (of_property_read_string(node, "clock-output-names", &init.name))
- init.name = node->name;
+ clk_data = kmalloc(sizeof(*clk_data), GFP_KERNEL);
+ if (!clk_data)
+ return;
- clk = clk_register(NULL, &phase->hw);
- if (IS_ERR(clk))
- goto err_unmap;
+ clk_data->clks = kcalloc(3, sizeof(*clk_data->clks), GFP_KERNEL);
+ if (!clk_data->clks)
+ goto err_free_data;
+
+ clk_data->clk_num = 3;
+ clk_data->clks[0] = sunxi_factors_register(node, data, lock, reg);
+ if (!clk_data->clks[0])
+ goto err_free_clks;
+
+ parent = __clk_get_name(clk_data->clks[0]);
+
+ for (i = 1; i < 3; i++) {
+ struct clk_init_data init = {
+ .num_parents = 1,
+ .parent_names = &parent,
+ .ops = &mmc_clk_ops,
+ };
+ struct mmc_phase *phase;
+
+ phase = kmalloc(sizeof(*phase), GFP_KERNEL);
+ if (!phase)
+ continue;
+
+ phase->hw.init = &init;
+ phase->reg = reg;
+ phase->lock = lock;
+
+ if (i == 1)
+ phase->offset = 8;
+ else
+ phase->offset = 20;
+
+ if (of_property_read_string_index(node, "clock-output-names",
+ i, &init.name))
+ init.name = node->name;
+
+ clk_data->clks[i] = clk_register(NULL, &phase->hw);
+ if (IS_ERR(clk_data->clks[i])) {
+ kfree(phase);
+ continue;
+ }
+ }
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ of_clk_add_provider(node, of_clk_src_onecell_get, clk_data);
return;
-err_unmap:
- iounmap(phase->reg);
-err_free:
- kfree(phase);
+err_free_clks:
+ kfree(clk_data->clks);
+err_free_data:
+ kfree(clk_data);
}
+static DEFINE_SPINLOCK(sun4i_a10_mmc_lock);
-static struct mmc_phase_data mmc_output_clk = {
- .offset = 8,
-};
-
-static struct mmc_phase_data mmc_sample_clk = {
- .offset = 20,
-};
-
-static void __init sun4i_a10_mmc_output_setup(struct device_node *node)
+static void __init sun4i_a10_mmc_setup(struct device_node *node)
{
- sun4i_a10_mmc_phase_setup(node, &mmc_output_clk);
+ sunxi_mmc_setup(node, &sun4i_a10_mod0_data, &sun4i_a10_mmc_lock);
}
-CLK_OF_DECLARE(sun4i_a10_mmc_output, "allwinner,sun4i-a10-mmc-output-clk", sun4i_a10_mmc_output_setup);
+CLK_OF_DECLARE(sun4i_a10_mmc, "allwinner,sun4i-a10-mmc-clk", sun4i_a10_mmc_setup);
+
+static DEFINE_SPINLOCK(sun9i_a80_mmc_lock);
-static void __init sun4i_a10_mmc_sample_setup(struct device_node *node)
+static void __init sun9i_a80_mmc_setup(struct device_node *node)
{
- sun4i_a10_mmc_phase_setup(node, &mmc_sample_clk);
+ sunxi_mmc_setup(node, &sun9i_a80_mod0_data, &sun9i_a80_mmc_lock);
}
-CLK_OF_DECLARE(sun4i_a10_mmc_sample, "allwinner,sun4i-a10-mmc-sample-clk", sun4i_a10_mmc_sample_setup);
+CLK_OF_DECLARE(sun9i_a80_mmc, "allwinner,sun9i-a80-mmc-clk", sun9i_a80_mmc_setup);
diff --git a/drivers/clk/sunxi/clk-sun6i-ar100.c b/drivers/clk/sunxi/clk-sun6i-ar100.c
index 3d282fb8f85c..63cf149195ae 100644
--- a/drivers/clk/sunxi/clk-sun6i-ar100.c
+++ b/drivers/clk/sunxi/clk-sun6i-ar100.c
@@ -45,6 +45,8 @@ static unsigned long ar100_recalc_rate(struct clk_hw *hw,
}
static long ar100_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
unsigned long *best_parent_rate,
struct clk_hw **best_parent_clk)
{
diff --git a/drivers/clk/sunxi/clk-sun8i-mbus.c b/drivers/clk/sunxi/clk-sun8i-mbus.c
index ef49786eefd3..14cd026064bf 100644
--- a/drivers/clk/sunxi/clk-sun8i-mbus.c
+++ b/drivers/clk/sunxi/clk-sun8i-mbus.c
@@ -69,8 +69,17 @@ static DEFINE_SPINLOCK(sun8i_a23_mbus_lock);
static void __init sun8i_a23_mbus_setup(struct device_node *node)
{
- struct clk *mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
- &sun8i_a23_mbus_lock);
+ struct clk *mbus;
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for a23-mbus-clk\n");
+ return;
+ }
+
+ mbus = sunxi_factors_register(node, &sun8i_a23_mbus_data,
+ &sun8i_a23_mbus_lock, reg);
/* The MBUS clocks needs to be always enabled */
__clk_get(mbus);
diff --git a/drivers/clk/sunxi/clk-sun9i-core.c b/drivers/clk/sunxi/clk-sun9i-core.c
index 3cb9036d91bb..d8da77d72861 100644
--- a/drivers/clk/sunxi/clk-sun9i-core.c
+++ b/drivers/clk/sunxi/clk-sun9i-core.c
@@ -24,50 +24,51 @@
/**
- * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL1
+ * sun9i_a80_get_pll4_factors() - calculates n, p, m factors for PLL4
* PLL4 rate is calculated as follows
* rate = (parent_rate * n >> p) / (m + 1);
- * parent_rate is always 24Mhz
+ * parent_rate is always 24MHz
*
* p and m are named div1 and div2 in Allwinner's SDK
*/
static void sun9i_a80_get_pll4_factors(u32 *freq, u32 parent_rate,
- u8 *n, u8 *k, u8 *m, u8 *p)
+ u8 *n_ret, u8 *k, u8 *m_ret, u8 *p_ret)
{
- int div;
+ int n;
+ int m = 1;
+ int p = 1;
- /* Normalize value to a 6M multiple */
- div = DIV_ROUND_UP(*freq, 6000000);
+ /* Normalize value to a 6 MHz multiple (24 MHz / 4) */
+ n = DIV_ROUND_UP(*freq, 6000000);
- /* divs above 256 cannot be odd */
- if (div > 256)
- div = round_up(div, 2);
+ /* If n is too large switch to steps of 12 MHz */
+ if (n > 255) {
+ m = 0;
+ n = (n + 1) / 2;
+ }
+
+ /* If n is still too large switch to steps of 24 MHz */
+ if (n > 255) {
+ p = 0;
+ n = (n + 1) / 2;
+ }
- /* divs above 512 must be a multiple of 4 */
- if (div > 512)
- div = round_up(div, 4);
+ /* n must be between 12 and 255 */
+ if (n > 255)
+ n = 255;
+ else if (n < 12)
+ n = 12;
- *freq = 6000000 * div;
+ *freq = ((24000000 * n) >> p) / (m + 1);
/* we were called to round the frequency, we can now return */
- if (n == NULL)
+ if (n_ret == NULL)
return;
- /* p will be 1 for divs under 512 */
- if (div < 512)
- *p = 1;
- else
- *p = 0;
-
- /* m will be 1 if div is odd */
- if (div & 1)
- *m = 1;
- else
- *m = 0;
-
- /* calculate a suitable n based on m and p */
- *n = div / (*p + 1) / (*m + 1);
+ *n_ret = n;
+ *m_ret = m;
+ *p_ret = p;
}
static struct clk_factors_config sun9i_a80_pll4_config = {
@@ -89,7 +90,17 @@ static DEFINE_SPINLOCK(sun9i_a80_pll4_lock);
static void __init sun9i_a80_pll4_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_pll4_data, &sun9i_a80_pll4_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-pll4-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_pll4_data,
+ &sun9i_a80_pll4_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_pll4, "allwinner,sun9i-a80-pll4-clk", sun9i_a80_pll4_setup);
@@ -139,8 +150,18 @@ static DEFINE_SPINLOCK(sun9i_a80_gt_lock);
static void __init sun9i_a80_gt_setup(struct device_node *node)
{
- struct clk *gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
- &sun9i_a80_gt_lock);
+ void __iomem *reg;
+ struct clk *gt;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-gt-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ gt = sunxi_factors_register(node, &sun9i_a80_gt_data,
+ &sun9i_a80_gt_lock, reg);
/* The GT bus clock needs to be always enabled */
__clk_get(gt);
@@ -194,7 +215,17 @@ static DEFINE_SPINLOCK(sun9i_a80_ahb_lock);
static void __init sun9i_a80_ahb_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_ahb_data, &sun9i_a80_ahb_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-ahb-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_ahb_data,
+ &sun9i_a80_ahb_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_ahb, "allwinner,sun9i-a80-ahb-clk", sun9i_a80_ahb_setup);
@@ -210,7 +241,17 @@ static DEFINE_SPINLOCK(sun9i_a80_apb0_lock);
static void __init sun9i_a80_apb0_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_apb0_data, &sun9i_a80_apb0_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-apb0-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_apb0_data,
+ &sun9i_a80_apb0_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_apb0, "allwinner,sun9i-a80-apb0-clk", sun9i_a80_apb0_setup);
@@ -266,6 +307,16 @@ static DEFINE_SPINLOCK(sun9i_a80_apb1_lock);
static void __init sun9i_a80_apb1_setup(struct device_node *node)
{
- sunxi_factors_register(node, &sun9i_a80_apb1_data, &sun9i_a80_apb1_lock);
+ void __iomem *reg;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+ if (!reg) {
+ pr_err("Could not get registers for a80-apb1-clk: %s\n",
+ node->name);
+ return;
+ }
+
+ sunxi_factors_register(node, &sun9i_a80_apb1_data,
+ &sun9i_a80_apb1_lock, reg);
}
CLK_OF_DECLARE(sun9i_a80_apb1, "allwinner,sun9i-a80-apb1-clk", sun9i_a80_apb1_setup);
diff --git a/drivers/clk/sunxi/clk-sun9i-mmc.c b/drivers/clk/sunxi/clk-sun9i-mmc.c
new file mode 100644
index 000000000000..710c273648d7
--- /dev/null
+++ b/drivers/clk/sunxi/clk-sun9i-mmc.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2015 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/clkdev.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/reset.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/spinlock.h>
+
+#define SUN9I_MMC_WIDTH 4
+
+#define SUN9I_MMC_GATE_BIT 16
+#define SUN9I_MMC_RESET_BIT 18
+
+struct sun9i_mmc_clk_data {
+ spinlock_t lock;
+ void __iomem *membase;
+ struct clk *clk;
+ struct reset_control *reset;
+ struct clk_onecell_data clk_data;
+ struct reset_controller_dev rcdev;
+};
+
+static int sun9i_mmc_reset_assert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sun9i_mmc_clk_data *data = container_of(rcdev,
+ struct sun9i_mmc_clk_data,
+ rcdev);
+ unsigned long flags;
+ void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+ u32 val;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(&data->lock, flags);
+
+ val = readl(reg);
+ writel(val & ~BIT(SUN9I_MMC_RESET_BIT), reg);
+
+ spin_unlock_irqrestore(&data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static int sun9i_mmc_reset_deassert(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct sun9i_mmc_clk_data *data = container_of(rcdev,
+ struct sun9i_mmc_clk_data,
+ rcdev);
+ unsigned long flags;
+ void __iomem *reg = data->membase + SUN9I_MMC_WIDTH * id;
+ u32 val;
+
+ clk_prepare_enable(data->clk);
+ spin_lock_irqsave(&data->lock, flags);
+
+ val = readl(reg);
+ writel(val | BIT(SUN9I_MMC_RESET_BIT), reg);
+
+ spin_unlock_irqrestore(&data->lock, flags);
+ clk_disable_unprepare(data->clk);
+
+ return 0;
+}
+
+static struct reset_control_ops sun9i_mmc_reset_ops = {
+ .assert = sun9i_mmc_reset_assert,
+ .deassert = sun9i_mmc_reset_deassert,
+};
+
+static int sun9i_a80_mmc_config_clk_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sun9i_mmc_clk_data *data;
+ struct clk_onecell_data *clk_data;
+ const char *clk_name = np->name;
+ const char *clk_parent;
+ struct resource *r;
+ int count, i, ret;
+
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ spin_lock_init(&data->lock);
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* one clock/reset pair per word */
+ count = DIV_ROUND_UP((r->end - r->start + 1), SUN9I_MMC_WIDTH);
+ data->membase = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(data->membase))
+ return PTR_ERR(data->membase);
+
+ clk_data = &data->clk_data;
+ clk_data->clk_num = count;
+ clk_data->clks = devm_kcalloc(&pdev->dev, count, sizeof(struct clk *),
+ GFP_KERNEL);
+ if (!clk_data->clks)
+ return -ENOMEM;
+
+ data->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(data->clk)) {
+ dev_err(&pdev->dev, "Could not get clock\n");
+ return PTR_ERR(data->clk);
+ }
+
+ data->reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (IS_ERR(data->reset)) {
+ dev_err(&pdev->dev, "Could not get reset control\n");
+ return PTR_ERR(data->reset);
+ }
+
+ ret = reset_control_deassert(data->reset);
+ if (ret) {
+ dev_err(&pdev->dev, "Reset deassert err %d\n", ret);
+ return ret;
+ }
+
+ clk_parent = __clk_get_name(data->clk);
+ for (i = 0; i < count; i++) {
+ of_property_read_string_index(np, "clock-output-names",
+ i, &clk_name);
+
+ clk_data->clks[i] = clk_register_gate(&pdev->dev, clk_name,
+ clk_parent, 0,
+ data->membase + SUN9I_MMC_WIDTH * i,
+ SUN9I_MMC_GATE_BIT, 0,
+ &data->lock);
+
+ if (IS_ERR(clk_data->clks[i])) {
+ ret = PTR_ERR(clk_data->clks[i]);
+ goto err_clk_register;
+ }
+ }
+
+ ret = of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
+ if (ret)
+ goto err_clk_provider;
+
+ data->rcdev.owner = THIS_MODULE;
+ data->rcdev.nr_resets = count;
+ data->rcdev.ops = &sun9i_mmc_reset_ops;
+ data->rcdev.of_node = pdev->dev.of_node;
+
+ ret = reset_controller_register(&data->rcdev);
+ if (ret)
+ goto err_rc_reg;
+
+ platform_set_drvdata(pdev, data);
+
+ return 0;
+
+err_rc_reg:
+ of_clk_del_provider(np);
+
+err_clk_provider:
+ for (i = 0; i < count; i++)
+ clk_unregister(clk_data->clks[i]);
+
+err_clk_register:
+ reset_control_assert(data->reset);
+
+ return ret;
+}
+
+static int sun9i_a80_mmc_config_clk_remove(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sun9i_mmc_clk_data *data = platform_get_drvdata(pdev);
+ struct clk_onecell_data *clk_data = &data->clk_data;
+ int i;
+
+ reset_controller_unregister(&data->rcdev);
+ of_clk_del_provider(np);
+ for (i = 0; i < clk_data->clk_num; i++)
+ clk_unregister(clk_data->clks[i]);
+
+ reset_control_assert(data->reset);
+
+ return 0;
+}
+
+static const struct of_device_id sun9i_a80_mmc_config_clk_dt_ids[] = {
+ { .compatible = "allwinner,sun9i-a80-mmc-config-clk" },
+ { /* sentinel */ }
+};
+
+static struct platform_driver sun9i_a80_mmc_config_clk_driver = {
+ .driver = {
+ .name = "sun9i-a80-mmc-config-clk",
+ .of_match_table = sun9i_a80_mmc_config_clk_dt_ids,
+ },
+ .probe = sun9i_a80_mmc_config_clk_probe,
+ .remove = sun9i_a80_mmc_config_clk_remove,
+};
+module_platform_driver(sun9i_a80_mmc_config_clk_driver);
+
+MODULE_AUTHOR("Chen-Yu Tsai <wens@csie.org>");
+MODULE_DESCRIPTION("Allwinner A80 MMC clock/reset Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/clk/sunxi/clk-sunxi.c b/drivers/clk/sunxi/clk-sunxi.c
index 570202582dcf..379324eb5486 100644
--- a/drivers/clk/sunxi/clk-sunxi.c
+++ b/drivers/clk/sunxi/clk-sunxi.c
@@ -20,11 +20,221 @@
#include <linux/of_address.h>
#include <linux/reset-controller.h>
#include <linux/spinlock.h>
+#include <linux/log2.h>
#include "clk-factors.h"
static DEFINE_SPINLOCK(clk_lock);
+/**
+ * sun6i_a31_ahb1_clk_setup() - Setup function for a31 ahb1 composite clk
+ */
+
+#define SUN6I_AHB1_MAX_PARENTS 4
+#define SUN6I_AHB1_MUX_PARENT_PLL6 3
+#define SUN6I_AHB1_MUX_SHIFT 12
+/* un-shifted mask is what mux_clk expects */
+#define SUN6I_AHB1_MUX_MASK 0x3
+#define SUN6I_AHB1_MUX_GET_PARENT(reg) ((reg >> SUN6I_AHB1_MUX_SHIFT) & \
+ SUN6I_AHB1_MUX_MASK)
+
+#define SUN6I_AHB1_DIV_SHIFT 4
+#define SUN6I_AHB1_DIV_MASK (0x3 << SUN6I_AHB1_DIV_SHIFT)
+#define SUN6I_AHB1_DIV_GET(reg) ((reg & SUN6I_AHB1_DIV_MASK) >> \
+ SUN6I_AHB1_DIV_SHIFT)
+#define SUN6I_AHB1_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_DIV_MASK) | \
+ (div << SUN6I_AHB1_DIV_SHIFT))
+#define SUN6I_AHB1_PLL6_DIV_SHIFT 6
+#define SUN6I_AHB1_PLL6_DIV_MASK (0x3 << SUN6I_AHB1_PLL6_DIV_SHIFT)
+#define SUN6I_AHB1_PLL6_DIV_GET(reg) ((reg & SUN6I_AHB1_PLL6_DIV_MASK) >> \
+ SUN6I_AHB1_PLL6_DIV_SHIFT)
+#define SUN6I_AHB1_PLL6_DIV_SET(reg, div) ((reg & ~SUN6I_AHB1_PLL6_DIV_MASK) | \
+ (div << SUN6I_AHB1_PLL6_DIV_SHIFT))
+
+struct sun6i_ahb1_clk {
+ struct clk_hw hw;
+ void __iomem *reg;
+};
+
+#define to_sun6i_ahb1_clk(_hw) container_of(_hw, struct sun6i_ahb1_clk, hw)
+
+static unsigned long sun6i_ahb1_clk_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
+ unsigned long rate;
+ u32 reg;
+
+ /* Fetch the register value */
+ reg = readl(ahb1->reg);
+
+ /* apply pre-divider first if parent is pll6 */
+ if (SUN6I_AHB1_MUX_GET_PARENT(reg) == SUN6I_AHB1_MUX_PARENT_PLL6)
+ parent_rate /= SUN6I_AHB1_PLL6_DIV_GET(reg) + 1;
+
+ /* clk divider */
+ rate = parent_rate >> SUN6I_AHB1_DIV_GET(reg);
+
+ return rate;
+}
+
+static long sun6i_ahb1_clk_round(unsigned long rate, u8 *divp, u8 *pre_divp,
+ u8 parent, unsigned long parent_rate)
+{
+ u8 div, calcp, calcm = 1;
+
+ /*
+ * clock can only divide, so we will never be able to achieve
+ * frequencies higher than the parent frequency
+ */
+ if (parent_rate && rate > parent_rate)
+ rate = parent_rate;
+
+ div = DIV_ROUND_UP(parent_rate, rate);
+
+ /* calculate pre-divider if parent is pll6 */
+ if (parent == SUN6I_AHB1_MUX_PARENT_PLL6) {
+ if (div < 4)
+ calcp = 0;
+ else if (div / 2 < 4)
+ calcp = 1;
+ else if (div / 4 < 4)
+ calcp = 2;
+ else
+ calcp = 3;
+
+ calcm = DIV_ROUND_UP(div, 1 << calcp);
+ } else {
+ calcp = __roundup_pow_of_two(div);
+ calcp = calcp > 3 ? 3 : calcp;
+ }
+
+ /* we were asked to pass back divider values */
+ if (divp) {
+ *divp = calcp;
+ *pre_divp = calcm - 1;
+ }
+
+ return (parent_rate / calcm) >> calcp;
+}
+
+static long sun6i_ahb1_clk_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long min_rate,
+ unsigned long max_rate,
+ unsigned long *best_parent_rate,
+ struct clk_hw **best_parent_clk)
+{
+ struct clk *clk = hw->clk, *parent, *best_parent = NULL;
+ int i, num_parents;
+ unsigned long parent_rate, best = 0, child_rate, best_child_rate = 0;
+
+ /* find the parent that can help provide the fastest rate <= rate */
+ num_parents = __clk_get_num_parents(clk);
+ for (i = 0; i < num_parents; i++) {
+ parent = clk_get_parent_by_index(clk, i);
+ if (!parent)
+ continue;
+ if (__clk_get_flags(clk) & CLK_SET_RATE_PARENT)
+ parent_rate = __clk_round_rate(parent, rate);
+ else
+ parent_rate = __clk_get_rate(parent);
+
+ child_rate = sun6i_ahb1_clk_round(rate, NULL, NULL, i,
+ parent_rate);
+
+ if (child_rate <= rate && child_rate > best_child_rate) {
+ best_parent = parent;
+ best = parent_rate;
+ best_child_rate = child_rate;
+ }
+ }
+
+ if (best_parent)
+ *best_parent_clk = __clk_get_hw(best_parent);
+ *best_parent_rate = best;
+
+ return best_child_rate;
+}
+
+static int sun6i_ahb1_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct sun6i_ahb1_clk *ahb1 = to_sun6i_ahb1_clk(hw);
+ unsigned long flags;
+ u8 div, pre_div, parent;
+ u32 reg;
+
+ spin_lock_irqsave(&clk_lock, flags);
+
+ reg = readl(ahb1->reg);
+
+ /* need to know which parent is used to apply pre-divider */
+ parent = SUN6I_AHB1_MUX_GET_PARENT(reg);
+ sun6i_ahb1_clk_round(rate, &div, &pre_div, parent, parent_rate);
+
+ reg = SUN6I_AHB1_DIV_SET(reg, div);
+ reg = SUN6I_AHB1_PLL6_DIV_SET(reg, pre_div);
+ writel(reg, ahb1->reg);
+
+ spin_unlock_irqrestore(&clk_lock, flags);
+
+ return 0;
+}
+
+static const struct clk_ops sun6i_ahb1_clk_ops = {
+ .determine_rate = sun6i_ahb1_clk_determine_rate,
+ .recalc_rate = sun6i_ahb1_clk_recalc_rate,
+ .set_rate = sun6i_ahb1_clk_set_rate,
+};
+
+static void __init sun6i_ahb1_clk_setup(struct device_node *node)
+{
+ struct clk *clk;
+ struct sun6i_ahb1_clk *ahb1;
+ struct clk_mux *mux;
+ const char *clk_name = node->name;
+ const char *parents[SUN6I_AHB1_MAX_PARENTS];
+ void __iomem *reg;
+ int i = 0;
+
+ reg = of_io_request_and_map(node, 0, of_node_full_name(node));
+
+ /* we have a mux, we will have >1 parents */
+ while (i < SUN6I_AHB1_MAX_PARENTS &&
+ (parents[i] = of_clk_get_parent_name(node, i)) != NULL)
+ i++;
+
+ of_property_read_string(node, "clock-output-names", &clk_name);
+
+ ahb1 = kzalloc(sizeof(struct sun6i_ahb1_clk), GFP_KERNEL);
+ if (!ahb1)
+ return;
+
+ mux = kzalloc(sizeof(struct clk_mux), GFP_KERNEL);
+ if (!mux) {
+ kfree(ahb1);
+ return;
+ }
+
+ /* set up clock properties */
+ mux->reg = reg;
+ mux->shift = SUN6I_AHB1_MUX_SHIFT;
+ mux->mask = SUN6I_AHB1_MUX_MASK;
+ mux->lock = &clk_lock;
+ ahb1->reg = reg;
+
+ clk = clk_register_composite(NULL, clk_name, parents, i,
+ &mux->hw, &clk_mux_ops,
+ &ahb1->hw, &sun6i_ahb1_clk_ops,
+ NULL, NULL, 0);
+
+ if (!IS_ERR(clk)) {
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ clk_register_clkdev(clk, clk_name, NULL);
+ }
+}
+CLK_OF_DECLARE(sun6i_a31_ahb1, "allwinner,sun6i-a31-ahb1-clk", sun6i_ahb1_clk_setup);
+
/* Maximum number of parents our clocks have */
#define SUNXI_MAX_PARENTS 5
@@ -355,43 +565,6 @@ static void sun7i_a20_get_out_factors(u32 *freq, u32 parent_rate,
}
/**
- * clk_sunxi_mmc_phase_control() - configures MMC clock phase control
- */
-
-void clk_sunxi_mmc_phase_control(struct clk *clk, u8 sample, u8 output)
-{
- #define to_clk_composite(_hw) container_of(_hw, struct clk_composite, hw)
- #define to_clk_factors(_hw) container_of(_hw, struct clk_factors, hw)
-
- struct clk_hw *hw = __clk_get_hw(clk);
- struct clk_composite *composite = to_clk_composite(hw);
- struct clk_hw *rate_hw = composite->rate_hw;
- struct clk_factors *factors = to_clk_factors(rate_hw);
- unsigned long flags = 0;
- u32 reg;
-
- if (factors->lock)
- spin_lock_irqsave(factors->lock, flags);
-
- reg = readl(factors->reg);
-
- /* set sample clock phase control */
- reg &= ~(0x7 << 20);
- reg |= ((sample & 0x7) << 20);
-
- /* set output clock phase control */
- reg &= ~(0x7 << 8);
- reg |= ((output & 0x7) << 8);
-
- writel(reg, factors->reg);
-
- if (factors->lock)
- spin_unlock_irqrestore(factors->lock, flags);
-}
-EXPORT_SYMBOL(clk_sunxi_mmc_phase_control);
-
-
-/**
* sunxi_factors_clk_setup() - Setup function for factor clocks
*/
@@ -413,6 +586,7 @@ static struct clk_factors_config sun6i_a31_pll1_config = {
.kwidth = 2,
.mshift = 0,
.mwidth = 2,
+ .n_start = 1,
};
static struct clk_factors_config sun8i_a23_pll1_config = {
@@ -520,7 +694,16 @@ static const struct factors_data sun7i_a20_out_data __initconst = {
static struct clk * __init sunxi_factors_clk_setup(struct device_node *node,
const struct factors_data *data)
{
- return sunxi_factors_register(node, data, &clk_lock);
+ void __iomem *reg;
+
+ reg = of_iomap(node, 0);
+ if (!reg) {
+ pr_err("Could not get registers for factors-clk: %s\n",
+ node->name);
+ return NULL;
+ }
+
+ return sunxi_factors_register(node, data, &clk_lock, reg);
}
@@ -561,7 +744,7 @@ static void __init sunxi_mux_clk_setup(struct device_node *node,
of_property_read_string(node, "clock-output-names", &clk_name);
clk = clk_register_mux(NULL, clk_name, parents, i,
- CLK_SET_RATE_NO_REPARENT, reg,
+ CLK_SET_RATE_PARENT, reg,
data->shift, SUNXI_MUX_GATE_WIDTH,
0, &clk_lock);
@@ -1217,7 +1400,6 @@ CLK_OF_DECLARE(sun7i_a20_clk_init, "allwinner,sun7i-a20", sun5i_init_clocks);
static const char *sun6i_critical_clocks[] __initdata = {
"cpu",
- "ahb1_sdram",
};
static void __init sun6i_init_clocks(struct device_node *node)
@@ -1226,6 +1408,7 @@ static void __init sun6i_init_clocks(struct device_node *node)
ARRAY_SIZE(sun6i_critical_clocks));
}
CLK_OF_DECLARE(sun6i_a31_clk_init, "allwinner,sun6i-a31", sun6i_init_clocks);
+CLK_OF_DECLARE(sun6i_a31s_clk_init, "allwinner,sun6i-a31s", sun6i_init_clocks);
CLK_OF_DECLARE(sun8i_a23_clk_init, "allwinner,sun8i-a23", sun6i_init_clocks);
static void __init sun9i_init_clocks(struct device_node *node)
diff --git a/drivers/clk/tegra/Makefile b/drivers/clk/tegra/Makefile
index f7dfb72884a4..edb8358fa6ce 100644
--- a/drivers/clk/tegra/Makefile
+++ b/drivers/clk/tegra/Makefile
@@ -15,3 +15,4 @@ obj-$(CONFIG_ARCH_TEGRA_2x_SOC) += clk-tegra20.o
obj-$(CONFIG_ARCH_TEGRA_3x_SOC) += clk-tegra30.o
obj-$(CONFIG_ARCH_TEGRA_114_SOC) += clk-tegra114.o
obj-$(CONFIG_ARCH_TEGRA_124_SOC) += clk-tegra124.o
+obj-$(CONFIG_ARCH_TEGRA_132_SOC) += clk-tegra124.o
diff --git a/drivers/clk/tegra/clk-id.h b/drivers/clk/tegra/clk-id.h
index 0011d547a9f7..60738cc954cb 100644
--- a/drivers/clk/tegra/clk-id.h
+++ b/drivers/clk/tegra/clk-id.h
@@ -64,10 +64,8 @@ enum clk_id {
tegra_clk_disp2,
tegra_clk_dp2,
tegra_clk_dpaux,
- tegra_clk_dsia,
tegra_clk_dsialp,
tegra_clk_dsia_mux,
- tegra_clk_dsib,
tegra_clk_dsiblp,
tegra_clk_dsib_mux,
tegra_clk_dtv,
diff --git a/drivers/clk/tegra/clk-periph.c b/drivers/clk/tegra/clk-periph.c
index 9e899c18af86..d84ae49d0e05 100644
--- a/drivers/clk/tegra/clk-periph.c
+++ b/drivers/clk/tegra/clk-periph.c
@@ -28,7 +28,7 @@ static u8 clk_periph_get_parent(struct clk_hw *hw)
const struct clk_ops *mux_ops = periph->mux_ops;
struct clk_hw *mux_hw = &periph->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->get_parent(mux_hw);
}
@@ -39,7 +39,7 @@ static int clk_periph_set_parent(struct clk_hw *hw, u8 index)
const struct clk_ops *mux_ops = periph->mux_ops;
struct clk_hw *mux_hw = &periph->mux.hw;
- mux_hw->clk = hw->clk;
+ __clk_hw_set_clk(mux_hw, hw);
return mux_ops->set_parent(mux_hw, index);
}
@@ -51,7 +51,7 @@ static unsigned long clk_periph_recalc_rate(struct clk_hw *hw,
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->recalc_rate(div_hw, parent_rate);
}
@@ -63,7 +63,7 @@ static long clk_periph_round_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->round_rate(div_hw, rate, prate);
}
@@ -75,7 +75,7 @@ static int clk_periph_set_rate(struct clk_hw *hw, unsigned long rate,
const struct clk_ops *div_ops = periph->div_ops;
struct clk_hw *div_hw = &periph->divider.hw;
- div_hw->clk = hw->clk;
+ __clk_hw_set_clk(div_hw, hw);
return div_ops->set_rate(div_hw, rate, parent_rate);
}
@@ -86,7 +86,7 @@ static int clk_periph_is_enabled(struct clk_hw *hw)
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->is_enabled(gate_hw);
}
@@ -97,7 +97,7 @@ static int clk_periph_enable(struct clk_hw *hw)
const struct clk_ops *gate_ops = periph->gate_ops;
struct clk_hw *gate_hw = &periph->gate.hw;
- gate_hw->clk = hw->clk;
+ __clk_hw_set_clk(gate_hw, hw);
return gate_ops->enable(gate_hw);
}
diff --git a/drivers/clk/tegra/clk-pll.c b/drivers/clk/tegra/clk-pll.c
index c7c6d8fb32fb..bfef9abdf232 100644
--- a/drivers/clk/tegra/clk-pll.c
+++ b/drivers/clk/tegra/clk-pll.c
@@ -816,7 +816,9 @@ const struct clk_ops tegra_clk_plle_ops = {
.enable = clk_plle_enable,
};
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC)
static int _pll_fixed_mdiv(struct tegra_clk_pll_params *pll_params,
unsigned long parent_rate)
@@ -1505,7 +1507,9 @@ struct clk *tegra_clk_register_plle(const char *name, const char *parent_name,
return clk;
}
-#if defined(CONFIG_ARCH_TEGRA_114_SOC) || defined(CONFIG_ARCH_TEGRA_124_SOC)
+#if defined(CONFIG_ARCH_TEGRA_114_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_124_SOC) || \
+ defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllxc_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_iddq_enable,
@@ -1565,7 +1569,7 @@ struct clk *tegra_clk_register_pllxc(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1665,7 +1669,7 @@ struct clk *tegra_clk_register_pllm(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1706,7 +1710,7 @@ struct clk *tegra_clk_register_pllc(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
@@ -1802,7 +1806,7 @@ struct clk *tegra_clk_register_plle_tegra114(const char *name,
}
#endif
-#ifdef CONFIG_ARCH_TEGRA_124_SOC
+#if defined(CONFIG_ARCH_TEGRA_124_SOC) || defined(CONFIG_ARCH_TEGRA_132_SOC)
static const struct clk_ops tegra_clk_pllss_ops = {
.is_enabled = clk_pll_is_enabled,
.enable = clk_pll_iddq_enable,
@@ -1830,7 +1834,7 @@ struct clk *tegra_clk_register_pllss(const char *name, const char *parent_name,
parent = __clk_lookup(parent_name);
if (!parent) {
WARN(1, "parent clk %s of %s must be registered first\n",
- name, parent_name);
+ parent_name, name);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/clk/tegra/clk-tegra-periph.c b/drivers/clk/tegra/clk-tegra-periph.c
index 37f32c49674e..cef0727b9eec 100644
--- a/drivers/clk/tegra/clk-tegra-periph.c
+++ b/drivers/clk/tegra/clk-tegra-periph.c
@@ -434,10 +434,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("hda", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA, 125, TEGRA_PERIPH_ON_APB, tegra_clk_hda),
MUX("hda2codec_2x", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_HDA2CODEC_2X, 111, TEGRA_PERIPH_ON_APB, tegra_clk_hda2codec_2x),
MUX("vfir", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_VFIR, 7, TEGRA_PERIPH_ON_APB, tegra_clk_vfir),
- MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1),
- MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2),
- MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3),
- MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4),
+ MUX("sdmmc1", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1),
+ MUX("sdmmc2", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2),
+ MUX("sdmmc3", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3),
+ MUX("sdmmc4", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4),
MUX("la", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_LA, 76, TEGRA_PERIPH_ON_APB, tegra_clk_la),
MUX("trace", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_TRACE, 77, TEGRA_PERIPH_ON_APB, tegra_clk_trace),
MUX("owr", mux_pllp_pllc_pllm_clkm, CLK_SOURCE_OWR, 71, TEGRA_PERIPH_ON_APB, tegra_clk_owr),
@@ -470,10 +470,10 @@ static struct tegra_periph_init_data periph_clks[] = {
MUX("adx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_ADX1, 180, TEGRA_PERIPH_ON_APB, tegra_clk_adx1),
MUX("amx1", mux_plla_pllc_pllp_clkm, CLK_SOURCE_AMX1, 185, TEGRA_PERIPH_ON_APB, tegra_clk_amx1),
MUX("vi_sensor2", mux_pllm_pllc2_c_c3_pllp_plla, CLK_SOURCE_VI_SENSOR2, 165, TEGRA_PERIPH_NO_RESET, tegra_clk_vi_sensor2),
- MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, 0, tegra_clk_sdmmc1_8),
- MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, 0, tegra_clk_sdmmc2_8),
- MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, 0, tegra_clk_sdmmc3_8),
- MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, 0, tegra_clk_sdmmc4_8),
+ MUX8("sdmmc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC1, 14, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc1_8),
+ MUX8("sdmmc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC2, 9, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc2_8),
+ MUX8("sdmmc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC3, 69, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc3_8),
+ MUX8("sdmmc4", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SDMMC4, 15, TEGRA_PERIPH_ON_APB, tegra_clk_sdmmc4_8),
MUX8("sbc1", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC1, 41, TEGRA_PERIPH_ON_APB, tegra_clk_sbc1_8),
MUX8("sbc2", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC2, 44, TEGRA_PERIPH_ON_APB, tegra_clk_sbc2_8),
MUX8("sbc3", mux_pllp_pllc2_c_c3_pllm_clkm, CLK_SOURCE_SBC3, 46, TEGRA_PERIPH_ON_APB, tegra_clk_sbc3_8),
@@ -537,8 +537,6 @@ static struct tegra_periph_init_data gate_clks[] = {
GATE("xusb_host", "xusb_host_src", 89, 0, tegra_clk_xusb_host, 0),
GATE("xusb_ss", "xusb_ss_src", 156, 0, tegra_clk_xusb_ss, 0),
GATE("xusb_dev", "xusb_dev_src", 95, 0, tegra_clk_xusb_dev, 0),
- GATE("dsia", "dsia_mux", 48, 0, tegra_clk_dsia, 0),
- GATE("dsib", "dsib_mux", 82, 0, tegra_clk_dsib, 0),
GATE("emc", "emc_mux", 57, 0, tegra_clk_emc, CLK_IGNORE_UNUSED),
GATE("sata_cold", "clk_m", 129, TEGRA_PERIPH_ON_APB, tegra_clk_sata_cold, 0),
GATE("ispb", "clk_m", 3, 0, tegra_clk_ispb, 0),
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index 0b03d2cf7264..d0766423a5d6 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -715,7 +715,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_sbc2_8] = { .dt_id = TEGRA114_CLK_SBC2, .present = true },
[tegra_clk_sbc3_8] = { .dt_id = TEGRA114_CLK_SBC3, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA114_CLK_I2C5, .present = true },
- [tegra_clk_dsia] = { .dt_id = TEGRA114_CLK_DSIA, .present = true },
[tegra_clk_mipi] = { .dt_id = TEGRA114_CLK_MIPI, .present = true },
[tegra_clk_hdmi] = { .dt_id = TEGRA114_CLK_HDMI, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA114_CLK_CSI, .present = true },
@@ -739,7 +738,6 @@ static struct tegra_clk tegra114_clks[tegra_clk_max] __initdata = {
[tegra_clk_dtv] = { .dt_id = TEGRA114_CLK_DTV, .present = true },
[tegra_clk_ndspeed] = { .dt_id = TEGRA114_CLK_NDSPEED, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA114_CLK_I2CSLOW, .present = true },
- [tegra_clk_dsib] = { .dt_id = TEGRA114_CLK_DSIB, .present = true },
[tegra_clk_tsec] = { .dt_id = TEGRA114_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA114_CLK_XUSB_HOST, .present = true },
[tegra_clk_msenc] = { .dt_id = TEGRA114_CLK_MSENC, .present = true },
@@ -1224,6 +1222,14 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
clks[TEGRA114_CLK_DSIB_MUX] = clk;
+ clk = tegra_clk_register_periph_gate("dsia", "dsia_mux", 0, clk_base,
+ 0, 48, periph_clk_enb_refcnt);
+ clks[TEGRA114_CLK_DSIA] = clk;
+
+ clk = tegra_clk_register_periph_gate("dsib", "dsib_mux", 0, clk_base,
+ 0, 82, periph_clk_enb_refcnt);
+ clks[TEGRA114_CLK_DSIB] = clk;
+
/* emc mux */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
ARRAY_SIZE(mux_pllmcp_clkm),
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index f5f9baca7bb6..9a893f2fe8e9 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012, 2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012-2014 NVIDIA CORPORATION. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -28,6 +28,14 @@
#include "clk.h"
#include "clk-id.h"
+/*
+ * TEGRA124_CAR_BANK_COUNT: the number of peripheral clock register
+ * banks present in the Tegra124/132 CAR IP block. The banks are
+ * identified by single letters, e.g.: L, H, U, V, W, X. See
+ * periph_regs[] in drivers/clk/tegra/clk.c
+ */
+#define TEGRA124_CAR_BANK_COUNT 6
+
#define CLK_SOURCE_CSITE 0x1d4
#define CLK_SOURCE_EMC 0x19c
@@ -128,7 +136,6 @@ static unsigned long osc_freq;
static unsigned long pll_ref_freq;
static DEFINE_SPINLOCK(pll_d_lock);
-static DEFINE_SPINLOCK(pll_d2_lock);
static DEFINE_SPINLOCK(pll_e_lock);
static DEFINE_SPINLOCK(pll_re_lock);
static DEFINE_SPINLOCK(pll_u_lock);
@@ -145,11 +152,6 @@ static unsigned long tegra124_input_freq[] = {
[12] = 260000000,
};
-static const char *mux_plld_out0_plld2_out0[] = {
- "pll_d_out0", "pll_d2_out0",
-};
-#define mux_plld_out0_plld2_out0_idx NULL
-
static const char *mux_pllmcp_clkm[] = {
"pll_m", "pll_c", "pll_p", "clk_m", "pll_m_ud", "pll_c2", "pll_c3",
};
@@ -783,7 +785,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_sbc2] = { .dt_id = TEGRA124_CLK_SBC2, .present = true },
[tegra_clk_sbc3] = { .dt_id = TEGRA124_CLK_SBC3, .present = true },
[tegra_clk_i2c5] = { .dt_id = TEGRA124_CLK_I2C5, .present = true },
- [tegra_clk_dsia] = { .dt_id = TEGRA124_CLK_DSIA, .present = true },
[tegra_clk_mipi] = { .dt_id = TEGRA124_CLK_MIPI, .present = true },
[tegra_clk_hdmi] = { .dt_id = TEGRA124_CLK_HDMI, .present = true },
[tegra_clk_csi] = { .dt_id = TEGRA124_CLK_CSI, .present = true },
@@ -809,7 +810,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_soc_therm] = { .dt_id = TEGRA124_CLK_SOC_THERM, .present = true },
[tegra_clk_dtv] = { .dt_id = TEGRA124_CLK_DTV, .present = true },
[tegra_clk_i2cslow] = { .dt_id = TEGRA124_CLK_I2CSLOW, .present = true },
- [tegra_clk_dsib] = { .dt_id = TEGRA124_CLK_DSIB, .present = true },
[tegra_clk_tsec] = { .dt_id = TEGRA124_CLK_TSEC, .present = true },
[tegra_clk_xusb_host] = { .dt_id = TEGRA124_CLK_XUSB_HOST, .present = true },
[tegra_clk_msenc] = { .dt_id = TEGRA124_CLK_MSENC, .present = true },
@@ -949,8 +949,6 @@ static struct tegra_clk tegra124_clks[tegra_clk_max] __initdata = {
[tegra_clk_clk_out_1_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_1_MUX, .present = true },
[tegra_clk_clk_out_2_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_2_MUX, .present = true },
[tegra_clk_clk_out_3_mux] = { .dt_id = TEGRA124_CLK_CLK_OUT_3_MUX, .present = true },
- [tegra_clk_dsia_mux] = { .dt_id = TEGRA124_CLK_DSIA_MUX, .present = true },
- [tegra_clk_dsib_mux] = { .dt_id = TEGRA124_CLK_DSIB_MUX, .present = true },
};
static struct tegra_devclk devclks[] __initdata = {
@@ -1112,17 +1110,17 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
1, 2);
clks[TEGRA124_CLK_XUSB_SS_DIV2] = clk;
- /* dsia mux */
- clk = clk_register_mux(NULL, "dsia_mux", mux_plld_out0_plld2_out0,
- ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
- clk_base + PLLD_BASE, 25, 1, 0, &pll_d_lock);
- clks[TEGRA124_CLK_DSIA_MUX] = clk;
+ clk = clk_register_gate(NULL, "plld_dsi", "plld_out0", 0,
+ clk_base + PLLD_MISC, 30, 0, &pll_d_lock);
+ clks[TEGRA124_CLK_PLLD_DSI] = clk;
+
+ clk = tegra_clk_register_periph_gate("dsia", "plld_dsi", 0, clk_base,
+ 0, 48, periph_clk_enb_refcnt);
+ clks[TEGRA124_CLK_DSIA] = clk;
- /* dsib mux */
- clk = clk_register_mux(NULL, "dsib_mux", mux_plld_out0_plld2_out0,
- ARRAY_SIZE(mux_plld_out0_plld2_out0), 0,
- clk_base + PLLD2_BASE, 25, 1, 0, &pll_d2_lock);
- clks[TEGRA124_CLK_DSIB_MUX] = clk;
+ clk = tegra_clk_register_periph_gate("dsib", "plld_dsi", 0, clk_base,
+ 0, 82, periph_clk_enb_refcnt);
+ clks[TEGRA124_CLK_DSIB] = clk;
/* emc mux */
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
@@ -1351,7 +1349,7 @@ static const struct of_device_id pmc_match[] __initconst = {
{},
};
-static struct tegra_clk_init_table init_table[] __initdata = {
+static struct tegra_clk_init_table common_init_table[] __initdata = {
{TEGRA124_CLK_UARTA, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTB, TEGRA124_CLK_PLL_P, 408000000, 0},
{TEGRA124_CLK_UARTC, TEGRA124_CLK_PLL_P, 408000000, 0},
@@ -1368,6 +1366,8 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA124_CLK_I2S4, TEGRA124_CLK_PLL_A_OUT0, 11289600, 0},
{TEGRA124_CLK_VDE, TEGRA124_CLK_PLL_P, 0, 0},
{TEGRA124_CLK_HOST1X, TEGRA124_CLK_PLL_P, 136000000, 1},
+ {TEGRA124_CLK_DSIALP, TEGRA124_CLK_PLL_P, 68000000, 0},
+ {TEGRA124_CLK_DSIBLP, TEGRA124_CLK_PLL_P, 68000000, 0},
{TEGRA124_CLK_SCLK, TEGRA124_CLK_PLL_P_OUT2, 102000000, 1},
{TEGRA124_CLK_DFLL_SOC, TEGRA124_CLK_PLL_P, 51000000, 1},
{TEGRA124_CLK_DFLL_REF, TEGRA124_CLK_PLL_P, 51000000, 1},
@@ -1385,27 +1385,73 @@ static struct tegra_clk_init_table init_table[] __initdata = {
{TEGRA124_CLK_SATA, TEGRA124_CLK_PLL_P, 104000000, 0},
{TEGRA124_CLK_SATA_OOB, TEGRA124_CLK_PLL_P, 204000000, 0},
{TEGRA124_CLK_EMC, TEGRA124_CLK_CLK_MAX, 0, 1},
- {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_MSELECT, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_CSITE, TEGRA124_CLK_CLK_MAX, 0, 1},
{TEGRA124_CLK_TSENSOR, TEGRA124_CLK_CLK_M, 400000, 0},
+ /* This MUST be the last entry. */
+ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+};
+
+static struct tegra_clk_init_table tegra124_init_table[] __initdata = {
{TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 0},
+ {TEGRA124_CLK_CCLK_G, TEGRA124_CLK_CLK_MAX, 0, 1},
+ /* This MUST be the last entry. */
+ {TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
+};
+
+/* Tegra132 requires the SOC_THERM clock to remain active */
+static struct tegra_clk_init_table tegra132_init_table[] __initdata = {
+ {TEGRA124_CLK_SOC_THERM, TEGRA124_CLK_PLL_P, 51000000, 1},
/* This MUST be the last entry. */
{TEGRA124_CLK_CLK_MAX, TEGRA124_CLK_CLK_MAX, 0, 0},
};
+/**
+ * tegra124_clock_apply_init_table - initialize clocks on Tegra124 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra124 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
static void __init tegra124_clock_apply_init_table(void)
{
- tegra_init_from_table(init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(tegra124_init_table, clks, TEGRA124_CLK_CLK_MAX);
}
-static void __init tegra124_clock_init(struct device_node *np)
+/**
+ * tegra132_clock_apply_init_table - initialize clocks on Tegra132 SoCs
+ *
+ * Program an initial clock rate and enable or disable clocks needed
+ * by the rest of the kernel, for Tegra132 SoCs. It is intended to be
+ * called by assigning a pointer to it to tegra_clk_apply_init_table -
+ * this will be called as an arch_initcall. No return value.
+ */
+static void __init tegra132_clock_apply_init_table(void)
+{
+ tegra_init_from_table(common_init_table, clks, TEGRA124_CLK_CLK_MAX);
+ tegra_init_from_table(tegra132_init_table, clks, TEGRA124_CLK_CLK_MAX);
+}
+
+/**
+ * tegra124_132_clock_init_pre - clock initialization preamble for T124/T132
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most of the clocks controlled by the CAR IP block, along
+ * with a few clocks controlled by the PMC IP block. Everything in
+ * this function should be common to Tegra124 and Tegra132. XXX The
+ * PMC clock initialization should probably be moved to PMC-specific
+ * driver code. No return value.
+ */
+static void __init tegra124_132_clock_init_pre(struct device_node *np)
{
struct device_node *node;
+ u32 plld_base;
clk_base = of_iomap(np, 0);
if (!clk_base) {
- pr_err("ioremap tegra124 CAR failed\n");
+ pr_err("ioremap tegra124/tegra132 CAR failed\n");
return;
}
@@ -1423,7 +1469,8 @@ static void __init tegra124_clock_init(struct device_node *np)
return;
}
- clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX, 6);
+ clks = tegra_clk_init(clk_base, TEGRA124_CLK_CLK_MAX,
+ TEGRA124_CAR_BANK_COUNT);
if (!clks)
return;
@@ -1437,13 +1484,76 @@ static void __init tegra124_clock_init(struct device_node *np)
tegra_audio_clk_init(clk_base, pmc_base, tegra124_clks, &pll_a_params);
tegra_pmc_clk_init(pmc_base, tegra124_clks);
+ /* For Tegra124 & Tegra132, PLLD is the only source for DSIA & DSIB */
+ plld_base = clk_readl(clk_base + PLLD_BASE);
+ plld_base &= ~BIT(25);
+ clk_writel(plld_base, clk_base + PLLD_BASE);
+}
+
+/**
+ * tegra124_132_clock_init_post - clock initialization postamble for T124/T132
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most of the along with a few clocks controlled by the PMC
+ * IP block. Everything in this function should be common to Tegra124
+ * and Tegra132. This function must be called after
+ * tegra124_132_clock_init_pre(), otherwise clk_base and pmc_base will
+ * not be set. No return value.
+ */
+static void __init tegra124_132_clock_init_post(struct device_node *np)
+{
tegra_super_clk_gen4_init(clk_base, pmc_base, tegra124_clks,
- &pll_x_params);
+ &pll_x_params);
tegra_add_of_provider(np);
tegra_register_devclks(devclks, ARRAY_SIZE(devclks));
+ tegra_cpu_car_ops = &tegra124_cpu_car_ops;
+}
+
+/**
+ * tegra124_clock_init - Tegra124-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra124 system-on-chip. Most of
+ * this code is shared between the Tegra124 and Tegra132 SoCs,
+ * although some of the initial clock settings and CPU clocks differ.
+ * Intended to be called by the OF init code when a DT node with the
+ * "nvidia,tegra124-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra124_clock_init(struct device_node *np)
+{
+ tegra124_132_clock_init_pre(np);
tegra_clk_apply_init_table = tegra124_clock_apply_init_table;
+ tegra124_132_clock_init_post(np);
+}
- tegra_cpu_car_ops = &tegra124_cpu_car_ops;
+/**
+ * tegra132_clock_init - Tegra132-specific clock initialization
+ * @np: struct device_node * of the DT node for the SoC CAR IP block
+ *
+ * Register most SoC clocks for the Tegra132 system-on-chip. Most of
+ * this code is shared between the Tegra124 and Tegra132 SoCs,
+ * although some of the initial clock settings and CPU clocks differ.
+ * Intended to be called by the OF init code when a DT node with the
+ * "nvidia,tegra132-car" string is encountered, and declared with
+ * CLK_OF_DECLARE. No return value.
+ */
+static void __init tegra132_clock_init(struct device_node *np)
+{
+ tegra124_132_clock_init_pre(np);
+
+ /*
+ * On Tegra132, these clocks are controlled by the
+ * CLUSTER_clocks IP block, located in the CPU complex
+ */
+ tegra124_clks[tegra_clk_cclk_g].present = false;
+ tegra124_clks[tegra_clk_cclk_lp].present = false;
+ tegra124_clks[tegra_clk_pll_x].present = false;
+ tegra124_clks[tegra_clk_pll_x_out0].present = false;
+
+ tegra_clk_apply_init_table = tegra132_clock_apply_init_table;
+ tegra124_132_clock_init_post(np);
}
CLK_OF_DECLARE(tegra124, "nvidia,tegra124-car", tegra124_clock_init);
+CLK_OF_DECLARE(tegra132, "nvidia,tegra132-car", tegra132_clock_init);
diff --git a/drivers/clk/tegra/clk.c b/drivers/clk/tegra/clk.c
index 97dc8595c3cd..9ddb7547cb43 100644
--- a/drivers/clk/tegra/clk.c
+++ b/drivers/clk/tegra/clk.c
@@ -302,10 +302,13 @@ struct clk ** __init tegra_lookup_dt_id(int clk_id,
tegra_clk_apply_init_table_func tegra_clk_apply_init_table;
-void __init tegra_clocks_apply_init_table(void)
+static int __init tegra_clocks_apply_init_table(void)
{
if (!tegra_clk_apply_init_table)
- return;
+ return 0;
tegra_clk_apply_init_table();
+
+ return 0;
}
+arch_initcall(tegra_clocks_apply_init_table);
diff --git a/drivers/clk/ti/Makefile b/drivers/clk/ti/Makefile
index ed4d0aaf8916..105ffd0f5e79 100644
--- a/drivers/clk/ti/Makefile
+++ b/drivers/clk/ti/Makefile
@@ -1,13 +1,17 @@
-ifneq ($(CONFIG_OF),)
obj-y += clk.o autoidle.o clockdomain.o
clk-common = dpll.o composite.o divider.o gate.o \
fixed-factor.o mux.o apll.o
obj-$(CONFIG_SOC_AM33XX) += $(clk-common) clk-33xx.o
+obj-$(CONFIG_SOC_TI81XX) += $(clk-common) fapll.o clk-816x.o
obj-$(CONFIG_ARCH_OMAP2) += $(clk-common) interface.o clk-2xxx.o
-obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o clk-3xxx.o
+obj-$(CONFIG_ARCH_OMAP3) += $(clk-common) interface.o \
+ clk-3xxx.o
obj-$(CONFIG_ARCH_OMAP4) += $(clk-common) clk-44xx.o
obj-$(CONFIG_SOC_OMAP5) += $(clk-common) clk-54xx.o
obj-$(CONFIG_SOC_DRA7XX) += $(clk-common) clk-7xx.o \
clk-dra7-atl.o
obj-$(CONFIG_SOC_AM43XX) += $(clk-common) clk-43xx.o
+
+ifdef CONFIG_ATAGS
+obj-$(CONFIG_ARCH_OMAP3) += clk-3xxx-legacy.o
endif
diff --git a/drivers/clk/ti/clk-3xxx-legacy.c b/drivers/clk/ti/clk-3xxx-legacy.c
new file mode 100644
index 000000000000..e0732a4c8f26
--- /dev/null
+++ b/drivers/clk/ti/clk-3xxx-legacy.c
@@ -0,0 +1,4653 @@
+/*
+ * OMAP3 Legacy clock data
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@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/clk-provider.h>
+#include <linux/clk/ti.h>
+
+#include "clock.h"
+
+static struct ti_clk_fixed virt_12m_ck_data = {
+ .frequency = 12000000,
+};
+
+static struct ti_clk virt_12m_ck = {
+ .name = "virt_12m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_12m_ck_data,
+};
+
+static struct ti_clk_fixed virt_13m_ck_data = {
+ .frequency = 13000000,
+};
+
+static struct ti_clk virt_13m_ck = {
+ .name = "virt_13m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_13m_ck_data,
+};
+
+static struct ti_clk_fixed virt_19200000_ck_data = {
+ .frequency = 19200000,
+};
+
+static struct ti_clk virt_19200000_ck = {
+ .name = "virt_19200000_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_19200000_ck_data,
+};
+
+static struct ti_clk_fixed virt_26000000_ck_data = {
+ .frequency = 26000000,
+};
+
+static struct ti_clk virt_26000000_ck = {
+ .name = "virt_26000000_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_26000000_ck_data,
+};
+
+static struct ti_clk_fixed virt_38_4m_ck_data = {
+ .frequency = 38400000,
+};
+
+static struct ti_clk virt_38_4m_ck = {
+ .name = "virt_38_4m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_38_4m_ck_data,
+};
+
+static struct ti_clk_fixed virt_16_8m_ck_data = {
+ .frequency = 16800000,
+};
+
+static struct ti_clk virt_16_8m_ck = {
+ .name = "virt_16_8m_ck",
+ .type = TI_CLK_FIXED,
+ .data = &virt_16_8m_ck_data,
+};
+
+static const char *osc_sys_ck_parents[] = {
+ "virt_12m_ck",
+ "virt_13m_ck",
+ "virt_19200000_ck",
+ "virt_26000000_ck",
+ "virt_38_4m_ck",
+ "virt_16_8m_ck",
+};
+
+static struct ti_clk_mux osc_sys_ck_data = {
+ .num_parents = ARRAY_SIZE(osc_sys_ck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_PRM,
+ .parents = osc_sys_ck_parents,
+};
+
+static struct ti_clk osc_sys_ck = {
+ .name = "osc_sys_ck",
+ .type = TI_CLK_MUX,
+ .data = &osc_sys_ck_data,
+};
+
+static struct ti_clk_divider sys_ck_data = {
+ .parent = "osc_sys_ck",
+ .bit_shift = 6,
+ .max_div = 3,
+ .reg = 0x1270,
+ .module = TI_CLKM_PRM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk sys_ck = {
+ .name = "sys_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &sys_ck_data,
+};
+
+static const char *dpll3_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll3_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll3_ck_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd40,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll3_ck_parents,
+ .flags = CLKF_CORE,
+ .freqsel_mask = 0xf0,
+ .div1_mask = 0x7f00,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x5,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff0000,
+ .recal_st_bit = 0x5,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll3_ck = {
+ .name = "dpll3_ck",
+ .clkdm_name = "dpll3_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll3_ck_data,
+};
+
+static struct ti_clk_divider dpll3_m2_ck_data = {
+ .parent = "dpll3_ck",
+ .bit_shift = 27,
+ .max_div = 31,
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll3_m2_ck = {
+ .name = "dpll3_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll3_m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor core_ck_data = {
+ .parent = "dpll3_m2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_ck = {
+ .name = "core_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_ck_data,
+};
+
+static struct ti_clk_divider l3_ick_data = {
+ .parent = "core_ck",
+ .max_div = 3,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk l3_ick = {
+ .name = "l3_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &l3_ick_data,
+};
+
+static struct ti_clk_fixed_factor security_l3_ick_data = {
+ .parent = "l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk security_l3_ick = {
+ .name = "security_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &security_l3_ick_data,
+};
+
+static struct ti_clk_fixed_factor wkup_l4_ick_data = {
+ .parent = "sys_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wkup_l4_ick = {
+ .name = "wkup_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wkup_l4_ick_data,
+};
+
+static struct ti_clk_gate usim_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 9,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usim_ick = {
+ .name = "usim_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usim_ick_data,
+};
+
+static struct ti_clk_gate dss2_alwon_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 1,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss2_alwon_fck = {
+ .name = "dss2_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss2_alwon_fck_data,
+};
+
+static struct ti_clk_divider l4_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 2,
+ .max_div = 3,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk l4_ick = {
+ .name = "l4_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &l4_ick_data,
+};
+
+static struct ti_clk_fixed_factor core_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_l4_ick = {
+ .name = "core_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_l4_ick_data,
+};
+
+static struct ti_clk_gate mmchs2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 25,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs2_ick = {
+ .name = "mmchs2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs2_ick_data,
+};
+
+static const char *dpll4_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll4_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll4_ck_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd44,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll4_ck_parents,
+ .flags = CLKF_PER,
+ .freqsel_mask = 0xf00000,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x2,
+ .auto_recal_bit = 0x13,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x6,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x70000,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x6,
+ .autoidle_mask = 0x38,
+};
+
+static struct ti_clk dpll4_ck = {
+ .name = "dpll4_ck",
+ .clkdm_name = "dpll4_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll4_ck_data,
+};
+
+static struct ti_clk_divider dpll4_m2_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 63,
+ .reg = 0xd48,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m2_ck = {
+ .name = "dpll4_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m2x2_mul_ck_data = {
+ .parent = "dpll4_m2_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m2x2_mul_ck = {
+ .name = "dpll4_m2x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m2x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m2x2_ck_data = {
+ .parent = "dpll4_m2x2_mul_ck",
+ .bit_shift = 0x1b,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m2x2_ck = {
+ .name = "dpll4_m2x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m2x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_alwon_fck_data = {
+ .parent = "dpll4_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_alwon_fck = {
+ .name = "omap_96m_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_alwon_fck_data,
+};
+
+static struct ti_clk_fixed_factor cm_96m_fck_data = {
+ .parent = "omap_96m_alwon_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk cm_96m_fck = {
+ .name = "cm_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &cm_96m_fck_data,
+};
+
+static const char *omap_96m_fck_parents[] = {
+ "cm_96m_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux omap_96m_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(omap_96m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_96m_fck_parents,
+};
+
+static struct ti_clk omap_96m_fck = {
+ .name = "omap_96m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_96m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_96m_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_96m_fck = {
+ .name = "core_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_96m_fck_data,
+};
+
+static struct ti_clk_gate mspro_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 23,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mspro_fck = {
+ .name = "mspro_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mspro_fck_data,
+};
+
+static struct ti_clk_gate dss_ick_3430es2_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xe10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk dss_ick_3430es2 = {
+ .name = "dss_ick",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_ick_3430es2_data,
+};
+
+static struct ti_clk_gate uart4_ick_am35xx_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 23,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart4_ick_am35xx = {
+ .name = "uart4_ick_am35xx",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_ick_am35xx_data,
+};
+
+static struct ti_clk_fixed_factor security_l4_ick2_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk security_l4_ick2 = {
+ .name = "security_l4_ick2",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &security_l4_ick2_data,
+};
+
+static struct ti_clk_gate aes1_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 3,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk aes1_ick = {
+ .name = "aes1_ick",
+ .type = TI_CLK_GATE,
+ .data = &aes1_ick_data,
+};
+
+static const char *dpll5_ck_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll5_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll5_ck_parents),
+ .control_reg = 0xd04,
+ .idlest_reg = 0xd24,
+ .mult_div1_reg = 0xd4c,
+ .autoidle_reg = 0xd34,
+ .module = TI_CLKM_CM,
+ .parents = dpll5_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x19,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x19,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll5_ck = {
+ .name = "dpll5_ck",
+ .clkdm_name = "dpll5_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll5_ck_data,
+};
+
+static struct ti_clk_divider dpll5_m2_ck_data = {
+ .parent = "dpll5_ck",
+ .max_div = 31,
+ .reg = 0xd50,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll5_m2_ck = {
+ .name = "dpll5_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll5_m2_ck_data,
+};
+
+static struct ti_clk_gate usbhost_120m_fck_data = {
+ .parent = "dpll5_m2_ck",
+ .bit_shift = 1,
+ .reg = 0x1400,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk usbhost_120m_fck = {
+ .name = "usbhost_120m_fck",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_120m_fck_data,
+};
+
+static struct ti_clk_fixed_factor cm_96m_d2_fck_data = {
+ .parent = "cm_96m_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk cm_96m_d2_fck = {
+ .name = "cm_96m_d2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &cm_96m_d2_fck_data,
+};
+
+static struct ti_clk_fixed sys_altclk_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk sys_altclk = {
+ .name = "sys_altclk",
+ .type = TI_CLK_FIXED,
+ .data = &sys_altclk_data,
+};
+
+static const char *omap_48m_fck_parents[] = {
+ "cm_96m_d2_fck",
+ "sys_altclk",
+};
+
+static struct ti_clk_mux omap_48m_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(omap_48m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_48m_fck_parents,
+};
+
+static struct ti_clk omap_48m_fck = {
+ .name = "omap_48m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_48m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_48m_fck = {
+ .name = "core_48m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_48m_fck_data,
+};
+
+static struct ti_clk_fixed mcbsp_clks_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk mcbsp_clks = {
+ .name = "mcbsp_clks",
+ .type = TI_CLK_FIXED,
+ .data = &mcbsp_clks_data,
+};
+
+static struct ti_clk_gate mcbsp2_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 0,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor per_96m_fck_data = {
+ .parent = "omap_96m_alwon_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_96m_fck = {
+ .name = "per_96m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_96m_fck_data,
+};
+
+static const char *mcbsp2_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp2_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(mcbsp2_mux_fck_parents),
+ .reg = 0x274,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp2_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp2_fck_data = {
+ .mux = &mcbsp2_mux_fck_data,
+ .gate = &mcbsp2_gate_fck_data,
+};
+
+static struct ti_clk mcbsp2_fck = {
+ .name = "mcbsp2_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp2_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_m2x2_ck_data = {
+ .parent = "dpll3_m2_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_m2x2_ck = {
+ .name = "dpll3_m2x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_m2x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_fck_data = {
+ .parent = "dpll3_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_fck = {
+ .name = "corex2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_fck_data,
+};
+
+static struct ti_clk_gate ssi_ssr_gate_fck_3430es1_data = {
+ .parent = "corex2_fck",
+ .bit_shift = 0,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static int ssi_ssr_div_fck_3430es1_divs[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 6,
+ 0,
+ 8,
+};
+
+static struct ti_clk_divider ssi_ssr_div_fck_3430es1_data = {
+ .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es1_divs),
+ .parent = "corex2_fck",
+ .bit_shift = 8,
+ .dividers = ssi_ssr_div_fck_3430es1_divs,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite ssi_ssr_fck_3430es1_data = {
+ .gate = &ssi_ssr_gate_fck_3430es1_data,
+ .divider = &ssi_ssr_div_fck_3430es1_data,
+};
+
+static struct ti_clk ssi_ssr_fck_3430es1 = {
+ .name = "ssi_ssr_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &ssi_ssr_fck_3430es1_data,
+};
+
+static struct ti_clk_fixed_factor ssi_sst_fck_3430es1_data = {
+ .parent = "ssi_ssr_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_sst_fck_3430es1 = {
+ .name = "ssi_sst_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_sst_fck_3430es1_data,
+};
+
+static struct ti_clk_fixed omap_32k_fck_data = {
+ .frequency = 32768,
+};
+
+static struct ti_clk omap_32k_fck = {
+ .name = "omap_32k_fck",
+ .type = TI_CLK_FIXED,
+ .data = &omap_32k_fck_data,
+};
+
+static struct ti_clk_fixed_factor per_32k_alwon_fck_data = {
+ .parent = "omap_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_32k_alwon_fck = {
+ .name = "per_32k_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_32k_alwon_fck_data,
+};
+
+static struct ti_clk_gate gpio5_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 16,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio5_dbck = {
+ .name = "gpio5_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio5_dbck_data,
+};
+
+static struct ti_clk_gate gpt1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt1_ick = {
+ .name = "gpt1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt1_ick_data,
+};
+
+static struct ti_clk_gate mcspi3_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 20,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi3_fck = {
+ .name = "mcspi3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi3_fck_data,
+};
+
+static struct ti_clk_gate gpt2_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt2_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt2_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(gpt2_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt2_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt2_fck_data = {
+ .mux = &gpt2_mux_fck_data,
+ .gate = &gpt2_gate_fck_data,
+};
+
+static struct ti_clk gpt2_fck = {
+ .name = "gpt2_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt2_fck_data,
+};
+
+static struct ti_clk_gate gpt10_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 11,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt10_ick = {
+ .name = "gpt10_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt10_ick_data,
+};
+
+static struct ti_clk_gate uart2_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 14,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart2_fck = {
+ .name = "uart2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart2_fck_data,
+};
+
+static struct ti_clk_fixed_factor sr_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk sr_l4_ick = {
+ .name = "sr_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &sr_l4_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d8_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 8,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d8_fck = {
+ .name = "omap_96m_d8_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d8_fck_data,
+};
+
+static struct ti_clk_divider dpll4_m5_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 63,
+ .reg = 0xf40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m5_ck = {
+ .name = "dpll4_m5_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m5_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m5x2_mul_ck_data = {
+ .parent = "dpll4_m5_ck",
+ .div = 1,
+ .mult = 2,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dpll4_m5x2_mul_ck = {
+ .name = "dpll4_m5x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m5x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m5x2_ck_data = {
+ .parent = "dpll4_m5x2_mul_ck",
+ .bit_shift = 0x1e,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m5x2_ck = {
+ .name = "dpll4_m5x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m5x2_ck_data,
+};
+
+static struct ti_clk_gate cam_mclk_data = {
+ .parent = "dpll4_m5x2_ck",
+ .bit_shift = 0,
+ .reg = 0xf00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk cam_mclk = {
+ .name = "cam_mclk",
+ .type = TI_CLK_GATE,
+ .data = &cam_mclk_data,
+};
+
+static struct ti_clk_gate mcbsp3_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 1,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *mcbsp3_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp3_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(mcbsp3_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp3_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp3_fck_data = {
+ .mux = &mcbsp3_mux_fck_data,
+ .gate = &mcbsp3_gate_fck_data,
+};
+
+static struct ti_clk mcbsp3_fck = {
+ .name = "mcbsp3_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp3_fck_data,
+};
+
+static struct ti_clk_gate csi2_96m_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 1,
+ .reg = 0xf00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk csi2_96m_fck = {
+ .name = "csi2_96m_fck",
+ .clkdm_name = "cam_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &csi2_96m_fck_data,
+};
+
+static struct ti_clk_gate gpt9_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 10,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt9_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt9_mux_fck_data = {
+ .bit_shift = 7,
+ .num_parents = ARRAY_SIZE(gpt9_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt9_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt9_fck_data = {
+ .mux = &gpt9_mux_fck_data,
+ .gate = &gpt9_gate_fck_data,
+};
+
+static struct ti_clk gpt9_fck = {
+ .name = "gpt9_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt9_fck_data,
+};
+
+static struct ti_clk_divider dpll3_m3_ck_data = {
+ .parent = "dpll3_ck",
+ .bit_shift = 16,
+ .max_div = 31,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll3_m3_ck = {
+ .name = "dpll3_m3_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll3_m3_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_m3x2_mul_ck_data = {
+ .parent = "dpll3_m3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_m3x2_mul_ck = {
+ .name = "dpll3_m3x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_m3x2_mul_ck_data,
+};
+
+static struct ti_clk_gate sr2_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 7,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sr2_fck = {
+ .name = "sr2_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sr2_fck_data,
+};
+
+static struct ti_clk_fixed pclk_ck_data = {
+ .frequency = 27000000,
+};
+
+static struct ti_clk pclk_ck = {
+ .name = "pclk_ck",
+ .type = TI_CLK_FIXED,
+ .data = &pclk_ck_data,
+};
+
+static struct ti_clk_gate wdt2_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 5,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt2_ick = {
+ .name = "wdt2_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt2_ick_data,
+};
+
+static struct ti_clk_fixed_factor core_l3_ick_data = {
+ .parent = "l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_l3_ick = {
+ .name = "core_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_l3_ick_data,
+};
+
+static struct ti_clk_gate mcspi4_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 21,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi4_fck = {
+ .name = "mcspi4_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi4_fck_data,
+};
+
+static struct ti_clk_fixed_factor per_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_48m_fck = {
+ .name = "per_48m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_48m_fck_data,
+};
+
+static struct ti_clk_gate uart4_fck_data = {
+ .parent = "per_48m_fck",
+ .bit_shift = 18,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart4_fck = {
+ .name = "uart4_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_fck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d10_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 10,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d10_fck = {
+ .name = "omap_96m_d10_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d10_fck_data,
+};
+
+static struct ti_clk_gate usim_gate_fck_data = {
+ .parent = "omap_96m_fck",
+ .bit_shift = 9,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor per_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk per_l4_ick = {
+ .name = "per_l4_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &per_l4_ick_data,
+};
+
+static struct ti_clk_gate gpt5_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 6,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt5_ick = {
+ .name = "gpt5_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt5_ick_data,
+};
+
+static struct ti_clk_gate mcspi2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 19,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi2_ick = {
+ .name = "mcspi2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi2_ick_data,
+};
+
+static struct ti_clk_fixed_factor ssi_l4_ick_data = {
+ .parent = "l4_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_l4_ick = {
+ .name = "ssi_l4_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_l4_ick_data,
+};
+
+static struct ti_clk_gate ssi_ick_3430es1_data = {
+ .parent = "ssi_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk ssi_ick_3430es1 = {
+ .name = "ssi_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ssi_ick_3430es1_data,
+};
+
+static struct ti_clk_gate i2c2_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 16,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c2_fck = {
+ .name = "i2c2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c2_fck_data,
+};
+
+static struct ti_clk_divider dpll1_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 19,
+ .max_div = 7,
+ .reg = 0x940,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll1_fck = {
+ .name = "dpll1_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll1_fck_data,
+};
+
+static const char *dpll1_ck_parents[] = {
+ "sys_ck",
+ "dpll1_fck",
+};
+
+static struct ti_clk_dpll dpll1_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll1_ck_parents),
+ .control_reg = 0x904,
+ .idlest_reg = 0x924,
+ .mult_div1_reg = 0x940,
+ .autoidle_reg = 0x934,
+ .module = TI_CLKM_CM,
+ .parents = dpll1_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0xa0,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x7,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x7,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll1_ck = {
+ .name = "dpll1_ck",
+ .clkdm_name = "dpll1_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll1_ck_data,
+};
+
+static struct ti_clk_fixed secure_32k_fck_data = {
+ .frequency = 32768,
+};
+
+static struct ti_clk secure_32k_fck = {
+ .name = "secure_32k_fck",
+ .type = TI_CLK_FIXED,
+ .data = &secure_32k_fck_data,
+};
+
+static struct ti_clk_gate gpio5_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 16,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio5_ick = {
+ .name = "gpio5_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio5_ick_data,
+};
+
+static struct ti_clk_divider dpll4_m4_ck_data = {
+ .parent = "dpll4_ck",
+ .max_div = 32,
+ .reg = 0xe40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m4_ck = {
+ .name = "dpll4_m4_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m4_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m4x2_mul_ck_data = {
+ .parent = "dpll4_m4_ck",
+ .div = 1,
+ .mult = 2,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dpll4_m4x2_mul_ck = {
+ .name = "dpll4_m4x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m4x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m4x2_ck_data = {
+ .parent = "dpll4_m4x2_mul_ck",
+ .bit_shift = 0x1d,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m4x2_ck = {
+ .name = "dpll4_m4x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m4x2_ck_data,
+};
+
+static struct ti_clk_gate dss1_alwon_fck_3430es2_data = {
+ .parent = "dpll4_m4x2_ck",
+ .bit_shift = 0,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dss1_alwon_fck_3430es2 = {
+ .name = "dss1_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss1_alwon_fck_3430es2_data,
+};
+
+static struct ti_clk_gate uart3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 11,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart3_ick = {
+ .name = "uart3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart3_ick_data,
+};
+
+static struct ti_clk_divider dpll4_m3_ck_data = {
+ .parent = "dpll4_ck",
+ .bit_shift = 8,
+ .max_div = 32,
+ .reg = 0xe40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m3_ck = {
+ .name = "dpll4_m3_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m3_ck_data,
+};
+
+static struct ti_clk_gate mcbsp3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 1,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp3_ick = {
+ .name = "mcbsp3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp3_ick_data,
+};
+
+static struct ti_clk_gate gpio3_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 14,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio3_dbck = {
+ .name = "gpio3_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio3_dbck_data,
+};
+
+static struct ti_clk_gate fac_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 8,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk fac_ick = {
+ .name = "fac_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &fac_ick_data,
+};
+
+static struct ti_clk_gate clkout2_src_gate_ck_data = {
+ .parent = "core_ck",
+ .bit_shift = 7,
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static struct ti_clk_fixed_factor dpll4_m3x2_mul_ck_data = {
+ .parent = "dpll4_m3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m3x2_mul_ck = {
+ .name = "dpll4_m3x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m3x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m3x2_ck_data = {
+ .parent = "dpll4_m3x2_mul_ck",
+ .bit_shift = 0x1c,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m3x2_ck = {
+ .name = "dpll4_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m3x2_ck_data,
+};
+
+static const char *omap_54m_fck_parents[] = {
+ "dpll4_m3x2_ck",
+ "sys_altclk",
+};
+
+static struct ti_clk_mux omap_54m_fck_data = {
+ .bit_shift = 5,
+ .num_parents = ARRAY_SIZE(omap_54m_fck_parents),
+ .reg = 0xd40,
+ .module = TI_CLKM_CM,
+ .parents = omap_54m_fck_parents,
+};
+
+static struct ti_clk omap_54m_fck = {
+ .name = "omap_54m_fck",
+ .type = TI_CLK_MUX,
+ .data = &omap_54m_fck_data,
+};
+
+static const char *clkout2_src_mux_ck_parents[] = {
+ "core_ck",
+ "sys_ck",
+ "cm_96m_fck",
+ "omap_54m_fck",
+};
+
+static struct ti_clk_mux clkout2_src_mux_ck_data = {
+ .num_parents = ARRAY_SIZE(clkout2_src_mux_ck_parents),
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .parents = clkout2_src_mux_ck_parents,
+};
+
+static struct ti_clk_composite clkout2_src_ck_data = {
+ .mux = &clkout2_src_mux_ck_data,
+ .gate = &clkout2_src_gate_ck_data,
+};
+
+static struct ti_clk clkout2_src_ck = {
+ .name = "clkout2_src_ck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &clkout2_src_ck_data,
+};
+
+static struct ti_clk_gate i2c1_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 15,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c1_fck = {
+ .name = "i2c1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c1_fck_data,
+};
+
+static struct ti_clk_gate wdt3_fck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 12,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk wdt3_fck = {
+ .name = "wdt3_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt3_fck_data,
+};
+
+static struct ti_clk_gate gpt7_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 8,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt7_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt7_mux_fck_data = {
+ .bit_shift = 5,
+ .num_parents = ARRAY_SIZE(gpt7_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt7_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt7_fck_data = {
+ .mux = &gpt7_mux_fck_data,
+ .gate = &gpt7_gate_fck_data,
+};
+
+static struct ti_clk gpt7_fck = {
+ .name = "gpt7_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt7_fck_data,
+};
+
+static struct ti_clk_gate usb_l4_gate_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 5,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INTERFACE,
+};
+
+static struct ti_clk_divider usb_l4_div_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 4,
+ .max_div = 1,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk_composite usb_l4_ick_data = {
+ .gate = &usb_l4_gate_ick_data,
+ .divider = &usb_l4_div_ick_data,
+};
+
+static struct ti_clk usb_l4_ick = {
+ .name = "usb_l4_ick",
+ .type = TI_CLK_COMPOSITE,
+ .data = &usb_l4_ick_data,
+};
+
+static struct ti_clk_gate uart4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 18,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart4_ick = {
+ .name = "uart4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_ick_data,
+};
+
+static struct ti_clk_fixed dummy_ck_data = {
+ .frequency = 0,
+};
+
+static struct ti_clk dummy_ck = {
+ .name = "dummy_ck",
+ .type = TI_CLK_FIXED,
+ .data = &dummy_ck_data,
+};
+
+static const char *gpt3_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt3_mux_fck_data = {
+ .bit_shift = 1,
+ .num_parents = ARRAY_SIZE(gpt3_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt3_mux_fck_parents,
+};
+
+static struct ti_clk_gate gpt9_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 10,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt9_ick = {
+ .name = "gpt9_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt9_ick_data,
+};
+
+static struct ti_clk_gate gpt10_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 11,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate dss_ick_3430es1_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xe10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk dss_ick_3430es1 = {
+ .name = "dss_ick",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_ick_3430es1_data,
+};
+
+static struct ti_clk_gate gpt11_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 12,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt11_ick = {
+ .name = "gpt11_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt11_ick_data,
+};
+
+static struct ti_clk_divider dpll2_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 19,
+ .max_div = 7,
+ .reg = 0x40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll2_fck = {
+ .name = "dpll2_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll2_fck_data,
+};
+
+static struct ti_clk_gate uart1_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 13,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart1_fck = {
+ .name = "uart1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart1_fck_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_3430es1_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk hsotgusb_ick_3430es1 = {
+ .name = "hsotgusb_ick_3430es1",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_3430es1_data,
+};
+
+static struct ti_clk_gate gpio2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 13,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio2_ick = {
+ .name = "gpio2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio2_ick_data,
+};
+
+static struct ti_clk_gate mmchs1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 24,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs1_ick = {
+ .name = "mmchs1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs1_ick_data,
+};
+
+static struct ti_clk_gate modem_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 31,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk modem_fck = {
+ .name = "modem_fck",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &modem_fck_data,
+};
+
+static struct ti_clk_gate mcbsp4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 2,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp4_ick = {
+ .name = "mcbsp4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp4_ick_data,
+};
+
+static struct ti_clk_gate gpio1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 3,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio1_ick = {
+ .name = "gpio1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio1_ick_data,
+};
+
+static const char *gpt6_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt6_mux_fck_data = {
+ .bit_shift = 4,
+ .num_parents = ARRAY_SIZE(gpt6_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt6_mux_fck_parents,
+};
+
+static struct ti_clk_fixed_factor dpll1_x2_ck_data = {
+ .parent = "dpll1_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll1_x2_ck = {
+ .name = "dpll1_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll1_x2_ck_data,
+};
+
+static struct ti_clk_divider dpll1_x2m2_ck_data = {
+ .parent = "dpll1_x2_ck",
+ .max_div = 31,
+ .reg = 0x944,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll1_x2m2_ck = {
+ .name = "dpll1_x2m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll1_x2m2_ck_data,
+};
+
+static struct ti_clk_fixed_factor mpu_ck_data = {
+ .parent = "dpll1_x2m2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk mpu_ck = {
+ .name = "mpu_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &mpu_ck_data,
+};
+
+static struct ti_clk_divider arm_fck_data = {
+ .parent = "mpu_ck",
+ .max_div = 2,
+ .reg = 0x924,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk arm_fck = {
+ .name = "arm_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &arm_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d3_ck_data = {
+ .parent = "core_ck",
+ .div = 3,
+ .mult = 1,
+};
+
+static struct ti_clk core_d3_ck = {
+ .name = "core_d3_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d3_ck_data,
+};
+
+static struct ti_clk_gate gpt11_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 12,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt11_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt11_mux_fck_data = {
+ .bit_shift = 7,
+ .num_parents = ARRAY_SIZE(gpt11_mux_fck_parents),
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .parents = gpt11_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt11_fck_data = {
+ .mux = &gpt11_mux_fck_data,
+ .gate = &gpt11_gate_fck_data,
+};
+
+static struct ti_clk gpt11_fck = {
+ .name = "gpt11_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt11_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d6_ck_data = {
+ .parent = "core_ck",
+ .div = 6,
+ .mult = 1,
+};
+
+static struct ti_clk core_d6_ck = {
+ .name = "core_d6_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d6_ck_data,
+};
+
+static struct ti_clk_gate uart4_fck_am35xx_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 23,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart4_fck_am35xx = {
+ .name = "uart4_fck_am35xx",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart4_fck_am35xx_data,
+};
+
+static struct ti_clk_gate dpll3_m3x2_ck_data = {
+ .parent = "dpll3_m3x2_mul_ck",
+ .bit_shift = 0xc,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll3_m3x2_ck = {
+ .name = "dpll3_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll3_m3x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_core_alwon_ck_data = {
+ .parent = "dpll3_m3x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_core_alwon_ck = {
+ .name = "emu_core_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_core_alwon_ck_data,
+};
+
+static struct ti_clk_divider dpll4_m6_ck_data = {
+ .parent = "dpll4_ck",
+ .bit_shift = 24,
+ .max_div = 63,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll4_m6_ck = {
+ .name = "dpll4_m6_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll4_m6_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_m6x2_mul_ck_data = {
+ .parent = "dpll4_m6_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_m6x2_mul_ck = {
+ .name = "dpll4_m6x2_mul_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_m6x2_mul_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m6x2_ck_data = {
+ .parent = "dpll4_m6x2_mul_ck",
+ .bit_shift = 0x1f,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m6x2_ck = {
+ .name = "dpll4_m6x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m6x2_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_per_alwon_ck_data = {
+ .parent = "dpll4_m6x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_per_alwon_ck = {
+ .name = "emu_per_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_per_alwon_ck_data,
+};
+
+static struct ti_clk_fixed_factor emu_mpu_alwon_ck_data = {
+ .parent = "mpu_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk emu_mpu_alwon_ck = {
+ .name = "emu_mpu_alwon_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &emu_mpu_alwon_ck_data,
+};
+
+static const char *emu_src_mux_ck_parents[] = {
+ "sys_ck",
+ "emu_core_alwon_ck",
+ "emu_per_alwon_ck",
+ "emu_mpu_alwon_ck",
+};
+
+static struct ti_clk_mux emu_src_mux_ck_data = {
+ .num_parents = ARRAY_SIZE(emu_src_mux_ck_parents),
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .parents = emu_src_mux_ck_parents,
+};
+
+static struct ti_clk emu_src_mux_ck = {
+ .name = "emu_src_mux_ck",
+ .type = TI_CLK_MUX,
+ .data = &emu_src_mux_ck_data,
+};
+
+static struct ti_clk_gate emu_src_ck_data = {
+ .parent = "emu_src_mux_ck",
+ .flags = CLKF_CLKDM,
+};
+
+static struct ti_clk emu_src_ck = {
+ .name = "emu_src_ck",
+ .clkdm_name = "emu_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &emu_src_ck_data,
+};
+
+static struct ti_clk_divider atclk_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 4,
+ .max_div = 3,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk atclk_fck = {
+ .name = "atclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &atclk_fck_data,
+};
+
+static struct ti_clk_gate ipss_ick_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_AM35XX | CLKF_INTERFACE,
+};
+
+static struct ti_clk ipss_ick = {
+ .name = "ipss_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ipss_ick_data,
+};
+
+static struct ti_clk_gate emac_ick_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 1,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk emac_ick = {
+ .name = "emac_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &emac_ick_data,
+};
+
+static struct ti_clk_gate vpfe_ick_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 2,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk vpfe_ick = {
+ .name = "vpfe_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &vpfe_ick_data,
+};
+
+static const char *dpll2_ck_parents[] = {
+ "sys_ck",
+ "dpll2_fck",
+};
+
+static struct ti_clk_dpll dpll2_ck_data = {
+ .num_parents = ARRAY_SIZE(dpll2_ck_parents),
+ .control_reg = 0x4,
+ .idlest_reg = 0x24,
+ .mult_div1_reg = 0x40,
+ .autoidle_reg = 0x34,
+ .module = TI_CLKM_CM,
+ .parents = dpll2_ck_parents,
+ .freqsel_mask = 0xf0,
+ .modes = 0xa2,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x1,
+ .auto_recal_bit = 0x3,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x8,
+ .max_multiplier = 0x7ff,
+ .enable_mask = 0x7,
+ .mult_mask = 0x7ff00,
+ .recal_st_bit = 0x8,
+ .autoidle_mask = 0x7,
+};
+
+static struct ti_clk dpll2_ck = {
+ .name = "dpll2_ck",
+ .clkdm_name = "dpll2_clkdm",
+ .type = TI_CLK_DPLL,
+ .data = &dpll2_ck_data,
+};
+
+static struct ti_clk_divider dpll2_m2_ck_data = {
+ .parent = "dpll2_ck",
+ .max_div = 31,
+ .reg = 0x44,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk dpll2_m2_ck = {
+ .name = "dpll2_m2_ck",
+ .type = TI_CLK_DIVIDER,
+ .data = &dpll2_m2_ck_data,
+};
+
+static const char *mcbsp4_mux_fck_parents[] = {
+ "per_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp4_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(mcbsp4_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp4_mux_fck_parents,
+};
+
+static const char *mcbsp1_mux_fck_parents[] = {
+ "core_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp1_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(mcbsp1_mux_fck_parents),
+ .reg = 0x274,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp1_mux_fck_parents,
+};
+
+static struct ti_clk_gate gpt8_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 9,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate gpt8_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 9,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt8_ick = {
+ .name = "gpt8_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt8_ick_data,
+};
+
+static const char *gpt10_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt10_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(gpt10_mux_fck_parents),
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+ .parents = gpt10_mux_fck_parents,
+};
+
+static struct ti_clk_gate mmchs3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 30,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mmchs3_ick = {
+ .name = "mmchs3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs3_ick_data,
+};
+
+static struct ti_clk_gate gpio3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 14,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio3_ick = {
+ .name = "gpio3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio3_ick_data,
+};
+
+static const char *traceclk_src_fck_parents[] = {
+ "sys_ck",
+ "emu_core_alwon_ck",
+ "emu_per_alwon_ck",
+ "emu_mpu_alwon_ck",
+};
+
+static struct ti_clk_mux traceclk_src_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(traceclk_src_fck_parents),
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .parents = traceclk_src_fck_parents,
+};
+
+static struct ti_clk traceclk_src_fck = {
+ .name = "traceclk_src_fck",
+ .type = TI_CLK_MUX,
+ .data = &traceclk_src_fck_data,
+};
+
+static struct ti_clk_divider traceclk_fck_data = {
+ .parent = "traceclk_src_fck",
+ .bit_shift = 11,
+ .max_div = 7,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk traceclk_fck = {
+ .name = "traceclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &traceclk_fck_data,
+};
+
+static struct ti_clk_gate mcbsp5_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 10,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate sad2d_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 3,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sad2d_ick = {
+ .name = "sad2d_ick",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sad2d_ick_data,
+};
+
+static const char *gpt1_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt1_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(gpt1_mux_fck_parents),
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .parents = gpt1_mux_fck_parents,
+};
+
+static struct ti_clk_gate hecc_ck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk hecc_ck = {
+ .name = "hecc_ck",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hecc_ck_data,
+};
+
+static struct ti_clk_gate gpt1_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 0,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite gpt1_fck_data = {
+ .mux = &gpt1_mux_fck_data,
+ .gate = &gpt1_gate_fck_data,
+};
+
+static struct ti_clk gpt1_fck = {
+ .name = "gpt1_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt1_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m2x2_ck_omap36xx_data = {
+ .parent = "dpll4_m2x2_mul_ck",
+ .bit_shift = 0x1b,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m2x2_ck_omap36xx = {
+ .name = "dpll4_m2x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m2x2_ck_omap36xx_data,
+ .patch = &dpll4_m2x2_ck,
+};
+
+static struct ti_clk_divider gfx_l3_fck_data = {
+ .parent = "l3_ick",
+ .max_div = 7,
+ .reg = 0xb40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk gfx_l3_fck = {
+ .name = "gfx_l3_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &gfx_l3_fck_data,
+};
+
+static struct ti_clk_gate gfx_cg1_ck_data = {
+ .parent = "gfx_l3_fck",
+ .bit_shift = 1,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_cg1_ck = {
+ .name = "gfx_cg1_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_cg1_ck_data,
+};
+
+static struct ti_clk_gate mailboxes_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 7,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mailboxes_ick = {
+ .name = "mailboxes_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mailboxes_ick_data,
+};
+
+static struct ti_clk_gate sha11_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 1,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sha11_ick = {
+ .name = "sha11_ick",
+ .type = TI_CLK_GATE,
+ .data = &sha11_ick_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_am35xx_data = {
+ .parent = "ipss_ick",
+ .bit_shift = 0,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+ .flags = CLKF_AM35XX,
+};
+
+static struct ti_clk hsotgusb_ick_am35xx = {
+ .name = "hsotgusb_ick_am35xx",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_am35xx_data,
+};
+
+static struct ti_clk_gate mmchs3_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 30,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs3_fck = {
+ .name = "mmchs3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs3_fck_data,
+};
+
+static struct ti_clk_divider pclk_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 8,
+ .max_div = 7,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk pclk_fck = {
+ .name = "pclk_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &pclk_fck_data,
+};
+
+static const char *dpll4_ck_omap36xx_parents[] = {
+ "sys_ck",
+ "sys_ck",
+};
+
+static struct ti_clk_dpll dpll4_ck_omap36xx_data = {
+ .num_parents = ARRAY_SIZE(dpll4_ck_omap36xx_parents),
+ .control_reg = 0xd00,
+ .idlest_reg = 0xd20,
+ .mult_div1_reg = 0xd44,
+ .autoidle_reg = 0xd30,
+ .module = TI_CLKM_CM,
+ .parents = dpll4_ck_omap36xx_parents,
+ .modes = 0x82,
+ .div1_mask = 0x7f,
+ .idlest_mask = 0x2,
+ .auto_recal_bit = 0x13,
+ .max_divider = 0x80,
+ .min_divider = 0x1,
+ .recal_en_bit = 0x6,
+ .max_multiplier = 0xfff,
+ .enable_mask = 0x70000,
+ .mult_mask = 0xfff00,
+ .recal_st_bit = 0x6,
+ .autoidle_mask = 0x38,
+ .sddiv_mask = 0xff000000,
+ .dco_mask = 0xe00000,
+ .flags = CLKF_PER | CLKF_J_TYPE,
+};
+
+static struct ti_clk dpll4_ck_omap36xx = {
+ .name = "dpll4_ck",
+ .type = TI_CLK_DPLL,
+ .data = &dpll4_ck_omap36xx_data,
+ .patch = &dpll4_ck,
+};
+
+static struct ti_clk_gate uart3_fck_data = {
+ .parent = "per_48m_fck",
+ .bit_shift = 11,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk uart3_fck = {
+ .name = "uart3_fck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart3_fck_data,
+};
+
+static struct ti_clk_fixed_factor wkup_32k_fck_data = {
+ .parent = "omap_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wkup_32k_fck = {
+ .name = "wkup_32k_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wkup_32k_fck_data,
+};
+
+static struct ti_clk_gate sys_clkout1_data = {
+ .parent = "osc_sys_ck",
+ .bit_shift = 7,
+ .reg = 0xd70,
+ .module = TI_CLKM_PRM,
+};
+
+static struct ti_clk sys_clkout1 = {
+ .name = "sys_clkout1",
+ .type = TI_CLK_GATE,
+ .data = &sys_clkout1_data,
+};
+
+static struct ti_clk_fixed_factor gpmc_fck_data = {
+ .parent = "core_l3_ick",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gpmc_fck = {
+ .name = "gpmc_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gpmc_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d20_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 20,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d20_ck = {
+ .name = "dpll5_m2_d20_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d20_ck_data,
+};
+
+static struct ti_clk_gate dpll4_m5x2_ck_omap36xx_data = {
+ .parent = "dpll4_m5x2_mul_ck",
+ .bit_shift = 0x1e,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_RATE_PARENT | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m5x2_ck_omap36xx = {
+ .name = "dpll4_m5x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m5x2_ck_omap36xx_data,
+ .patch = &dpll4_m5x2_ck,
+};
+
+static struct ti_clk_gate ssi_ssr_gate_fck_3430es2_data = {
+ .parent = "corex2_fck",
+ .bit_shift = 0,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_NO_WAIT,
+};
+
+static struct ti_clk_gate uart1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 13,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart1_ick = {
+ .name = "uart1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart1_ick_data,
+};
+
+static struct ti_clk_gate iva2_ck_data = {
+ .parent = "dpll2_m2_ck",
+ .bit_shift = 0,
+ .reg = 0x0,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk iva2_ck = {
+ .name = "iva2_ck",
+ .clkdm_name = "iva2_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &iva2_ck_data,
+};
+
+static struct ti_clk_gate pka_ick_data = {
+ .parent = "security_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk pka_ick = {
+ .name = "pka_ick",
+ .type = TI_CLK_GATE,
+ .data = &pka_ick_data,
+};
+
+static struct ti_clk_gate gpt12_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 1,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt12_ick = {
+ .name = "gpt12_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt12_ick_data,
+};
+
+static const char *mcbsp5_mux_fck_parents[] = {
+ "core_96m_fck",
+ "mcbsp_clks",
+};
+
+static struct ti_clk_mux mcbsp5_mux_fck_data = {
+ .bit_shift = 4,
+ .num_parents = ARRAY_SIZE(mcbsp5_mux_fck_parents),
+ .reg = 0x2d8,
+ .module = TI_CLKM_SCRM,
+ .parents = mcbsp5_mux_fck_parents,
+};
+
+static struct ti_clk_composite mcbsp5_fck_data = {
+ .mux = &mcbsp5_mux_fck_data,
+ .gate = &mcbsp5_gate_fck_data,
+};
+
+static struct ti_clk mcbsp5_fck = {
+ .name = "mcbsp5_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp5_fck_data,
+};
+
+static struct ti_clk_gate usbhost_48m_fck_data = {
+ .parent = "omap_48m_fck",
+ .bit_shift = 0,
+ .reg = 0x1400,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS,
+};
+
+static struct ti_clk usbhost_48m_fck = {
+ .name = "usbhost_48m_fck",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_48m_fck_data,
+};
+
+static struct ti_clk_gate des1_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 0,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk des1_ick = {
+ .name = "des1_ick",
+ .type = TI_CLK_GATE,
+ .data = &des1_ick_data,
+};
+
+static struct ti_clk_gate sgx_gate_fck_data = {
+ .parent = "core_ck",
+ .bit_shift = 1,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed_factor core_d4_ck_data = {
+ .parent = "core_ck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk core_d4_ck = {
+ .name = "core_d4_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d4_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_192m_alwon_fck_data = {
+ .parent = "dpll4_m2x2_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk omap_192m_alwon_fck = {
+ .name = "omap_192m_alwon_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_192m_alwon_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_d2_ck_data = {
+ .parent = "core_ck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk core_d2_ck = {
+ .name = "core_d2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_d2_ck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_d3_fck_data = {
+ .parent = "corex2_fck",
+ .div = 3,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_d3_fck = {
+ .name = "corex2_d3_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_d3_fck_data,
+};
+
+static struct ti_clk_fixed_factor corex2_d5_fck_data = {
+ .parent = "corex2_fck",
+ .div = 5,
+ .mult = 1,
+};
+
+static struct ti_clk corex2_d5_fck = {
+ .name = "corex2_d5_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &corex2_d5_fck_data,
+};
+
+static const char *sgx_mux_fck_parents[] = {
+ "core_d3_ck",
+ "core_d4_ck",
+ "core_d6_ck",
+ "cm_96m_fck",
+ "omap_192m_alwon_fck",
+ "core_d2_ck",
+ "corex2_d3_fck",
+ "corex2_d5_fck",
+};
+
+static struct ti_clk_mux sgx_mux_fck_data = {
+ .num_parents = ARRAY_SIZE(sgx_mux_fck_parents),
+ .reg = 0xb40,
+ .module = TI_CLKM_CM,
+ .parents = sgx_mux_fck_parents,
+};
+
+static struct ti_clk_composite sgx_fck_data = {
+ .mux = &sgx_mux_fck_data,
+ .gate = &sgx_gate_fck_data,
+};
+
+static struct ti_clk sgx_fck = {
+ .name = "sgx_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &sgx_fck_data,
+};
+
+static struct ti_clk_gate mcspi1_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 18,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi1_fck = {
+ .name = "mcspi1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi1_fck_data,
+};
+
+static struct ti_clk_gate mmchs2_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 25,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs2_fck = {
+ .name = "mmchs2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs2_fck_data,
+};
+
+static struct ti_clk_gate mcspi2_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 19,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mcspi2_fck = {
+ .name = "mcspi2_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi2_fck_data,
+};
+
+static struct ti_clk_gate vpfe_fck_data = {
+ .parent = "pclk_ck",
+ .bit_shift = 10,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk vpfe_fck = {
+ .name = "vpfe_fck",
+ .type = TI_CLK_GATE,
+ .data = &vpfe_fck_data,
+};
+
+static struct ti_clk_gate gpt4_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 5,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate mcbsp1_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 9,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_gate gpt5_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 6,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static const char *gpt5_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt5_mux_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(gpt5_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt5_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt5_fck_data = {
+ .mux = &gpt5_mux_fck_data,
+ .gate = &gpt5_gate_fck_data,
+};
+
+static struct ti_clk gpt5_fck = {
+ .name = "gpt5_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt5_fck_data,
+};
+
+static struct ti_clk_gate ts_fck_data = {
+ .parent = "omap_32k_fck",
+ .bit_shift = 1,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk ts_fck = {
+ .name = "ts_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ts_fck_data,
+};
+
+static struct ti_clk_fixed_factor wdt1_fck_data = {
+ .parent = "secure_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk wdt1_fck = {
+ .name = "wdt1_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &wdt1_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m6x2_ck_omap36xx_data = {
+ .parent = "dpll4_m6x2_mul_ck",
+ .bit_shift = 0x1f,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m6x2_ck_omap36xx = {
+ .name = "dpll4_m6x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m6x2_ck_omap36xx_data,
+ .patch = &dpll4_m6x2_ck,
+};
+
+static const char *gpt4_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt4_mux_fck_data = {
+ .bit_shift = 2,
+ .num_parents = ARRAY_SIZE(gpt4_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt4_mux_fck_parents,
+};
+
+static struct ti_clk_gate usbhost_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0x1410,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_DSS | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usbhost_ick = {
+ .name = "usbhost_ick",
+ .clkdm_name = "usbhost_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbhost_ick_data,
+};
+
+static struct ti_clk_gate mcbsp2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 0,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp2_ick = {
+ .name = "mcbsp2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp2_ick_data,
+};
+
+static struct ti_clk_gate omapctrl_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 6,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk omapctrl_ick = {
+ .name = "omapctrl_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &omapctrl_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d4_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d4_fck = {
+ .name = "omap_96m_d4_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d4_fck_data,
+};
+
+static struct ti_clk_gate gpt6_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 7,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt6_ick = {
+ .name = "gpt6_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt6_ick_data,
+};
+
+static struct ti_clk_gate dpll3_m3x2_ck_omap36xx_data = {
+ .parent = "dpll3_m3x2_mul_ck",
+ .bit_shift = 0xc,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll3_m3x2_ck_omap36xx = {
+ .name = "dpll3_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll3_m3x2_ck_omap36xx_data,
+ .patch = &dpll3_m3x2_ck,
+};
+
+static struct ti_clk_gate i2c3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 17,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c3_ick = {
+ .name = "i2c3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c3_ick_data,
+};
+
+static struct ti_clk_gate gpio6_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 17,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio6_ick = {
+ .name = "gpio6_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio6_ick_data,
+};
+
+static struct ti_clk_gate mspro_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 23,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mspro_ick = {
+ .name = "mspro_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mspro_ick_data,
+};
+
+static struct ti_clk_composite mcbsp1_fck_data = {
+ .mux = &mcbsp1_mux_fck_data,
+ .gate = &mcbsp1_gate_fck_data,
+};
+
+static struct ti_clk mcbsp1_fck = {
+ .name = "mcbsp1_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp1_fck_data,
+};
+
+static struct ti_clk_gate gpt3_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 4,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_fixed rmii_ck_data = {
+ .frequency = 50000000,
+};
+
+static struct ti_clk rmii_ck = {
+ .name = "rmii_ck",
+ .type = TI_CLK_FIXED,
+ .data = &rmii_ck_data,
+};
+
+static struct ti_clk_gate gpt6_gate_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 7,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite gpt6_fck_data = {
+ .mux = &gpt6_mux_fck_data,
+ .gate = &gpt6_gate_fck_data,
+};
+
+static struct ti_clk gpt6_fck = {
+ .name = "gpt6_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt6_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d4_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d4_ck = {
+ .name = "dpll5_m2_d4_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d4_ck_data,
+};
+
+static struct ti_clk_fixed_factor sys_d2_ck_data = {
+ .parent = "sys_ck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk sys_d2_ck = {
+ .name = "sys_d2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &sys_d2_ck_data,
+};
+
+static struct ti_clk_fixed_factor omap_96m_d2_fck_data = {
+ .parent = "omap_96m_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk omap_96m_d2_fck = {
+ .name = "omap_96m_d2_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_96m_d2_fck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d8_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 8,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d8_ck = {
+ .name = "dpll5_m2_d8_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d8_ck_data,
+};
+
+static struct ti_clk_fixed_factor dpll5_m2_d16_ck_data = {
+ .parent = "dpll5_m2_ck",
+ .div = 16,
+ .mult = 1,
+};
+
+static struct ti_clk dpll5_m2_d16_ck = {
+ .name = "dpll5_m2_d16_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll5_m2_d16_ck_data,
+};
+
+static const char *usim_mux_fck_parents[] = {
+ "sys_ck",
+ "sys_d2_ck",
+ "omap_96m_d2_fck",
+ "omap_96m_d4_fck",
+ "omap_96m_d8_fck",
+ "omap_96m_d10_fck",
+ "dpll5_m2_d4_ck",
+ "dpll5_m2_d8_ck",
+ "dpll5_m2_d16_ck",
+ "dpll5_m2_d20_ck",
+};
+
+static struct ti_clk_mux usim_mux_fck_data = {
+ .bit_shift = 3,
+ .num_parents = ARRAY_SIZE(usim_mux_fck_parents),
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .parents = usim_mux_fck_parents,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk_composite usim_fck_data = {
+ .mux = &usim_mux_fck_data,
+ .gate = &usim_gate_fck_data,
+};
+
+static struct ti_clk usim_fck = {
+ .name = "usim_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &usim_fck_data,
+};
+
+static int ssi_ssr_div_fck_3430es2_divs[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 0,
+ 6,
+ 0,
+ 8,
+};
+
+static struct ti_clk_divider ssi_ssr_div_fck_3430es2_data = {
+ .num_dividers = ARRAY_SIZE(ssi_ssr_div_fck_3430es2_divs),
+ .parent = "corex2_fck",
+ .bit_shift = 8,
+ .dividers = ssi_ssr_div_fck_3430es2_divs,
+ .reg = 0xa40,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite ssi_ssr_fck_3430es2_data = {
+ .gate = &ssi_ssr_gate_fck_3430es2_data,
+ .divider = &ssi_ssr_div_fck_3430es2_data,
+};
+
+static struct ti_clk ssi_ssr_fck_3430es2 = {
+ .name = "ssi_ssr_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &ssi_ssr_fck_3430es2_data,
+};
+
+static struct ti_clk_gate dss1_alwon_fck_3430es1_data = {
+ .parent = "dpll4_m4x2_ck",
+ .bit_shift = 0,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SET_RATE_PARENT,
+};
+
+static struct ti_clk dss1_alwon_fck_3430es1 = {
+ .name = "dss1_alwon_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss1_alwon_fck_3430es1_data,
+};
+
+static struct ti_clk_gate gpt3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 4,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt3_ick = {
+ .name = "gpt3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt3_ick_data,
+};
+
+static struct ti_clk_fixed_factor omap_12m_fck_data = {
+ .parent = "omap_48m_fck",
+ .div = 4,
+ .mult = 1,
+};
+
+static struct ti_clk omap_12m_fck = {
+ .name = "omap_12m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &omap_12m_fck_data,
+};
+
+static struct ti_clk_fixed_factor core_12m_fck_data = {
+ .parent = "omap_12m_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk core_12m_fck = {
+ .name = "core_12m_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &core_12m_fck_data,
+};
+
+static struct ti_clk_gate hdq_fck_data = {
+ .parent = "core_12m_fck",
+ .bit_shift = 22,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk hdq_fck = {
+ .name = "hdq_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hdq_fck_data,
+};
+
+static struct ti_clk_gate usbtll_fck_data = {
+ .parent = "dpll5_m2_ck",
+ .bit_shift = 2,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk usbtll_fck = {
+ .name = "usbtll_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbtll_fck_data,
+};
+
+static struct ti_clk_gate hsotgusb_fck_am35xx_data = {
+ .parent = "sys_ck",
+ .bit_shift = 8,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk hsotgusb_fck_am35xx = {
+ .name = "hsotgusb_fck_am35xx",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_fck_am35xx_data,
+};
+
+static struct ti_clk_gate hsotgusb_ick_3430es2_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 4,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSOTGUSB | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk hsotgusb_ick_3430es2 = {
+ .name = "hsotgusb_ick_3430es2",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hsotgusb_ick_3430es2_data,
+};
+
+static struct ti_clk_gate gfx_l3_ck_data = {
+ .parent = "l3_ick",
+ .bit_shift = 0,
+ .reg = 0xb10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_l3_ck = {
+ .name = "gfx_l3_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_l3_ck_data,
+};
+
+static struct ti_clk_fixed_factor gfx_l3_ick_data = {
+ .parent = "gfx_l3_ck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gfx_l3_ick = {
+ .name = "gfx_l3_ick",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gfx_l3_ick_data,
+};
+
+static struct ti_clk_gate mcbsp1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 9,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp1_ick = {
+ .name = "mcbsp1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp1_ick_data,
+};
+
+static struct ti_clk_fixed_factor gpt12_fck_data = {
+ .parent = "secure_32k_fck",
+ .div = 1,
+ .mult = 1,
+};
+
+static struct ti_clk gpt12_fck = {
+ .name = "gpt12_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &gpt12_fck_data,
+};
+
+static struct ti_clk_gate gfx_cg2_ck_data = {
+ .parent = "gfx_l3_fck",
+ .bit_shift = 2,
+ .reg = 0xb00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk gfx_cg2_ck = {
+ .name = "gfx_cg2_ck",
+ .clkdm_name = "gfx_3430es1_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gfx_cg2_ck_data,
+};
+
+static struct ti_clk_gate i2c2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 16,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c2_ick = {
+ .name = "i2c2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c2_ick_data,
+};
+
+static struct ti_clk_gate gpio4_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 15,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio4_dbck = {
+ .name = "gpio4_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio4_dbck_data,
+};
+
+static struct ti_clk_gate i2c3_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 17,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk i2c3_fck = {
+ .name = "i2c3_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c3_fck_data,
+};
+
+static struct ti_clk_composite gpt3_fck_data = {
+ .mux = &gpt3_mux_fck_data,
+ .gate = &gpt3_gate_fck_data,
+};
+
+static struct ti_clk gpt3_fck = {
+ .name = "gpt3_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt3_fck_data,
+};
+
+static struct ti_clk_gate i2c1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 15,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk i2c1_ick = {
+ .name = "i2c1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &i2c1_ick_data,
+};
+
+static struct ti_clk_gate omap_32ksync_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 2,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk omap_32ksync_ick = {
+ .name = "omap_32ksync_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &omap_32ksync_ick_data,
+};
+
+static struct ti_clk_gate aes2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 28,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk aes2_ick = {
+ .name = "aes2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &aes2_ick_data,
+};
+
+static const char *gpt8_mux_fck_parents[] = {
+ "omap_32k_fck",
+ "sys_ck",
+};
+
+static struct ti_clk_mux gpt8_mux_fck_data = {
+ .bit_shift = 6,
+ .num_parents = ARRAY_SIZE(gpt8_mux_fck_parents),
+ .reg = 0x1040,
+ .module = TI_CLKM_CM,
+ .parents = gpt8_mux_fck_parents,
+};
+
+static struct ti_clk_composite gpt8_fck_data = {
+ .mux = &gpt8_mux_fck_data,
+ .gate = &gpt8_gate_fck_data,
+};
+
+static struct ti_clk gpt8_fck = {
+ .name = "gpt8_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt8_fck_data,
+};
+
+static struct ti_clk_gate mcbsp4_gate_fck_data = {
+ .parent = "mcbsp_clks",
+ .bit_shift = 2,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk_composite mcbsp4_fck_data = {
+ .mux = &mcbsp4_mux_fck_data,
+ .gate = &mcbsp4_gate_fck_data,
+};
+
+static struct ti_clk mcbsp4_fck = {
+ .name = "mcbsp4_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &mcbsp4_fck_data,
+};
+
+static struct ti_clk_gate gpio2_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 13,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio2_dbck = {
+ .name = "gpio2_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio2_dbck_data,
+};
+
+static struct ti_clk_gate usbtll_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 2,
+ .reg = 0xa18,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk usbtll_ick = {
+ .name = "usbtll_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &usbtll_ick_data,
+};
+
+static struct ti_clk_gate mcspi4_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 21,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi4_ick = {
+ .name = "mcspi4_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi4_ick_data,
+};
+
+static struct ti_clk_gate dss_96m_fck_data = {
+ .parent = "omap_96m_fck",
+ .bit_shift = 2,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss_96m_fck = {
+ .name = "dss_96m_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_96m_fck_data,
+};
+
+static struct ti_clk_divider rm_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 1,
+ .max_div = 3,
+ .reg = 0xc40,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk rm_ick = {
+ .name = "rm_ick",
+ .type = TI_CLK_DIVIDER,
+ .data = &rm_ick_data,
+};
+
+static struct ti_clk_gate hdq_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 22,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk hdq_ick = {
+ .name = "hdq_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &hdq_ick_data,
+};
+
+static struct ti_clk_fixed_factor dpll3_x2_ck_data = {
+ .parent = "dpll3_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll3_x2_ck = {
+ .name = "dpll3_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll3_x2_ck_data,
+};
+
+static struct ti_clk_gate mad2d_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 3,
+ .reg = 0xa18,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mad2d_ick = {
+ .name = "mad2d_ick",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mad2d_ick_data,
+};
+
+static struct ti_clk_gate fshostusb_fck_data = {
+ .parent = "core_48m_fck",
+ .bit_shift = 5,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk fshostusb_fck = {
+ .name = "fshostusb_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &fshostusb_fck_data,
+};
+
+static struct ti_clk_gate sr1_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 6,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sr1_fck = {
+ .name = "sr1_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sr1_fck_data,
+};
+
+static struct ti_clk_gate des2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 26,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk des2_ick = {
+ .name = "des2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &des2_ick_data,
+};
+
+static struct ti_clk_gate sdrc_ick_data = {
+ .parent = "core_l3_ick",
+ .bit_shift = 1,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sdrc_ick = {
+ .name = "sdrc_ick",
+ .clkdm_name = "core_l3_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sdrc_ick_data,
+};
+
+static struct ti_clk_composite gpt4_fck_data = {
+ .mux = &gpt4_mux_fck_data,
+ .gate = &gpt4_gate_fck_data,
+};
+
+static struct ti_clk gpt4_fck = {
+ .name = "gpt4_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt4_fck_data,
+};
+
+static struct ti_clk_gate dpll4_m3x2_ck_omap36xx_data = {
+ .parent = "dpll4_m3x2_mul_ck",
+ .bit_shift = 0x1c,
+ .reg = 0xd00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_HSDIV | CLKF_SET_BIT_TO_DISABLE,
+};
+
+static struct ti_clk dpll4_m3x2_ck_omap36xx = {
+ .name = "dpll4_m3x2_ck",
+ .type = TI_CLK_GATE,
+ .data = &dpll4_m3x2_ck_omap36xx_data,
+ .patch = &dpll4_m3x2_ck,
+};
+
+static struct ti_clk_gate cpefuse_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 0,
+ .reg = 0xa08,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk cpefuse_fck = {
+ .name = "cpefuse_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &cpefuse_fck_data,
+};
+
+static struct ti_clk_gate mcspi3_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 20,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi3_ick = {
+ .name = "mcspi3_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi3_ick_data,
+};
+
+static struct ti_clk_fixed_factor ssi_sst_fck_3430es2_data = {
+ .parent = "ssi_ssr_fck",
+ .div = 2,
+ .mult = 1,
+};
+
+static struct ti_clk ssi_sst_fck_3430es2 = {
+ .name = "ssi_sst_fck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &ssi_sst_fck_3430es2_data,
+};
+
+static struct ti_clk_gate gpio1_dbck_data = {
+ .parent = "wkup_32k_fck",
+ .bit_shift = 3,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio1_dbck = {
+ .name = "gpio1_dbck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio1_dbck_data,
+};
+
+static struct ti_clk_gate gpt4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 5,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt4_ick = {
+ .name = "gpt4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt4_ick_data,
+};
+
+static struct ti_clk_gate gpt2_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 3,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt2_ick = {
+ .name = "gpt2_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt2_ick_data,
+};
+
+static struct ti_clk_gate mmchs1_fck_data = {
+ .parent = "core_96m_fck",
+ .bit_shift = 24,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk mmchs1_fck = {
+ .name = "mmchs1_fck",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mmchs1_fck_data,
+};
+
+static struct ti_clk_fixed dummy_apb_pclk_data = {
+ .frequency = 0x0,
+};
+
+static struct ti_clk dummy_apb_pclk = {
+ .name = "dummy_apb_pclk",
+ .type = TI_CLK_FIXED,
+ .data = &dummy_apb_pclk_data,
+};
+
+static struct ti_clk_gate gpio6_dbck_data = {
+ .parent = "per_32k_alwon_fck",
+ .bit_shift = 17,
+ .reg = 0x1000,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk gpio6_dbck = {
+ .name = "gpio6_dbck",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio6_dbck_data,
+};
+
+static struct ti_clk_gate uart2_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 14,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk uart2_ick = {
+ .name = "uart2_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &uart2_ick_data,
+};
+
+static struct ti_clk_fixed_factor dpll4_x2_ck_data = {
+ .parent = "dpll4_ck",
+ .div = 1,
+ .mult = 2,
+};
+
+static struct ti_clk dpll4_x2_ck = {
+ .name = "dpll4_x2_ck",
+ .type = TI_CLK_FIXED_FACTOR,
+ .data = &dpll4_x2_ck_data,
+};
+
+static struct ti_clk_gate gpt7_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 8,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpt7_ick = {
+ .name = "gpt7_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpt7_ick_data,
+};
+
+static struct ti_clk_gate dss_tv_fck_data = {
+ .parent = "omap_54m_fck",
+ .bit_shift = 2,
+ .reg = 0xe00,
+ .module = TI_CLKM_CM,
+};
+
+static struct ti_clk dss_tv_fck = {
+ .name = "dss_tv_fck",
+ .clkdm_name = "dss_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &dss_tv_fck_data,
+};
+
+static struct ti_clk_gate mcbsp5_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 10,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcbsp5_ick = {
+ .name = "mcbsp5_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcbsp5_ick_data,
+};
+
+static struct ti_clk_gate mcspi1_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 18,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk mcspi1_ick = {
+ .name = "mcspi1_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &mcspi1_ick_data,
+};
+
+static struct ti_clk_gate d2d_26m_fck_data = {
+ .parent = "sys_ck",
+ .bit_shift = 3,
+ .reg = 0xa00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk d2d_26m_fck = {
+ .name = "d2d_26m_fck",
+ .clkdm_name = "d2d_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &d2d_26m_fck_data,
+};
+
+static struct ti_clk_gate wdt3_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 12,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt3_ick = {
+ .name = "wdt3_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt3_ick_data,
+};
+
+static struct ti_clk_divider pclkx2_fck_data = {
+ .parent = "emu_src_ck",
+ .bit_shift = 6,
+ .max_div = 3,
+ .reg = 0x1140,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_STARTS_AT_ONE,
+};
+
+static struct ti_clk pclkx2_fck = {
+ .name = "pclkx2_fck",
+ .type = TI_CLK_DIVIDER,
+ .data = &pclkx2_fck_data,
+};
+
+static struct ti_clk_gate sha12_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 27,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk sha12_ick = {
+ .name = "sha12_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sha12_ick_data,
+};
+
+static struct ti_clk_gate emac_fck_data = {
+ .parent = "rmii_ck",
+ .bit_shift = 9,
+ .reg = 0x59c,
+ .module = TI_CLKM_SCRM,
+};
+
+static struct ti_clk emac_fck = {
+ .name = "emac_fck",
+ .type = TI_CLK_GATE,
+ .data = &emac_fck_data,
+};
+
+static struct ti_clk_composite gpt10_fck_data = {
+ .mux = &gpt10_mux_fck_data,
+ .gate = &gpt10_gate_fck_data,
+};
+
+static struct ti_clk gpt10_fck = {
+ .name = "gpt10_fck",
+ .type = TI_CLK_COMPOSITE,
+ .data = &gpt10_fck_data,
+};
+
+static struct ti_clk_gate wdt2_fck_data = {
+ .parent = "wkup_32k_fck",
+ .bit_shift = 5,
+ .reg = 0xc00,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk wdt2_fck = {
+ .name = "wdt2_fck",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt2_fck_data,
+};
+
+static struct ti_clk_gate cam_ick_data = {
+ .parent = "l4_ick",
+ .bit_shift = 0,
+ .reg = 0xf10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_NO_WAIT | CLKF_INTERFACE,
+};
+
+static struct ti_clk cam_ick = {
+ .name = "cam_ick",
+ .clkdm_name = "cam_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &cam_ick_data,
+};
+
+static struct ti_clk_gate ssi_ick_3430es2_data = {
+ .parent = "ssi_l4_ick",
+ .bit_shift = 0,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_SSI | CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk ssi_ick_3430es2 = {
+ .name = "ssi_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &ssi_ick_3430es2_data,
+};
+
+static struct ti_clk_gate gpio4_ick_data = {
+ .parent = "per_l4_ick",
+ .bit_shift = 15,
+ .reg = 0x1010,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk gpio4_ick = {
+ .name = "gpio4_ick",
+ .clkdm_name = "per_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &gpio4_ick_data,
+};
+
+static struct ti_clk_gate wdt1_ick_data = {
+ .parent = "wkup_l4_ick",
+ .bit_shift = 4,
+ .reg = 0xc10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk wdt1_ick = {
+ .name = "wdt1_ick",
+ .clkdm_name = "wkup_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &wdt1_ick_data,
+};
+
+static struct ti_clk_gate rng_ick_data = {
+ .parent = "security_l4_ick2",
+ .bit_shift = 2,
+ .reg = 0xa14,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk rng_ick = {
+ .name = "rng_ick",
+ .type = TI_CLK_GATE,
+ .data = &rng_ick_data,
+};
+
+static struct ti_clk_gate icr_ick_data = {
+ .parent = "core_l4_ick",
+ .bit_shift = 29,
+ .reg = 0xa10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_OMAP3 | CLKF_INTERFACE,
+};
+
+static struct ti_clk icr_ick = {
+ .name = "icr_ick",
+ .clkdm_name = "core_l4_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &icr_ick_data,
+};
+
+static struct ti_clk_gate sgx_ick_data = {
+ .parent = "l3_ick",
+ .bit_shift = 0,
+ .reg = 0xb10,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_WAIT,
+};
+
+static struct ti_clk sgx_ick = {
+ .name = "sgx_ick",
+ .clkdm_name = "sgx_clkdm",
+ .type = TI_CLK_GATE,
+ .data = &sgx_ick_data,
+};
+
+static struct ti_clk_divider sys_clkout2_data = {
+ .parent = "clkout2_src_ck",
+ .bit_shift = 3,
+ .max_div = 64,
+ .reg = 0xd70,
+ .module = TI_CLKM_CM,
+ .flags = CLKF_INDEX_POWER_OF_TWO,
+};
+
+static struct ti_clk sys_clkout2 = {
+ .name = "sys_clkout2",
+ .type = TI_CLK_DIVIDER,
+ .data = &sys_clkout2_data,
+};
+
+static struct ti_clk_alias omap34xx_omap36xx_clks[] = {
+ CLK(NULL, "security_l4_ick2", &security_l4_ick2),
+ CLK(NULL, "aes1_ick", &aes1_ick),
+ CLK("omap_rng", "ick", &rng_ick),
+ CLK("omap3-rom-rng", "ick", &rng_ick),
+ CLK(NULL, "sha11_ick", &sha11_ick),
+ CLK(NULL, "des1_ick", &des1_ick),
+ CLK(NULL, "cam_mclk", &cam_mclk),
+ CLK(NULL, "cam_ick", &cam_ick),
+ CLK(NULL, "csi2_96m_fck", &csi2_96m_fck),
+ CLK(NULL, "security_l3_ick", &security_l3_ick),
+ CLK(NULL, "pka_ick", &pka_ick),
+ CLK(NULL, "icr_ick", &icr_ick),
+ CLK(NULL, "des2_ick", &des2_ick),
+ CLK(NULL, "mspro_ick", &mspro_ick),
+ CLK(NULL, "mailboxes_ick", &mailboxes_ick),
+ CLK(NULL, "ssi_l4_ick", &ssi_l4_ick),
+ CLK(NULL, "sr1_fck", &sr1_fck),
+ CLK(NULL, "sr2_fck", &sr2_fck),
+ CLK(NULL, "sr_l4_ick", &sr_l4_ick),
+ CLK(NULL, "dpll2_fck", &dpll2_fck),
+ CLK(NULL, "dpll2_ck", &dpll2_ck),
+ CLK(NULL, "dpll2_m2_ck", &dpll2_m2_ck),
+ CLK(NULL, "iva2_ck", &iva2_ck),
+ CLK(NULL, "modem_fck", &modem_fck),
+ CLK(NULL, "sad2d_ick", &sad2d_ick),
+ CLK(NULL, "mad2d_ick", &mad2d_ick),
+ CLK(NULL, "mspro_fck", &mspro_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_omap3430es2plus_clks[] = {
+ CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es2),
+ CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es2),
+ CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es2),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es2),
+ CLK(NULL, "ssi_ick", &ssi_ick_3430es2),
+ CLK(NULL, "sys_d2_ck", &sys_d2_ck),
+ CLK(NULL, "omap_96m_d2_fck", &omap_96m_d2_fck),
+ CLK(NULL, "omap_96m_d4_fck", &omap_96m_d4_fck),
+ CLK(NULL, "omap_96m_d8_fck", &omap_96m_d8_fck),
+ CLK(NULL, "omap_96m_d10_fck", &omap_96m_d10_fck),
+ CLK(NULL, "dpll5_m2_d4_ck", &dpll5_m2_d4_ck),
+ CLK(NULL, "dpll5_m2_d8_ck", &dpll5_m2_d8_ck),
+ CLK(NULL, "dpll5_m2_d16_ck", &dpll5_m2_d16_ck),
+ CLK(NULL, "dpll5_m2_d20_ck", &dpll5_m2_d20_ck),
+ CLK(NULL, "usim_fck", &usim_fck),
+ CLK(NULL, "usim_ick", &usim_ick),
+ { NULL },
+};
+
+static struct ti_clk_alias omap3xxx_clks[] = {
+ CLK(NULL, "apb_pclk", &dummy_apb_pclk),
+ CLK(NULL, "omap_32k_fck", &omap_32k_fck),
+ CLK(NULL, "virt_12m_ck", &virt_12m_ck),
+ CLK(NULL, "virt_13m_ck", &virt_13m_ck),
+ CLK(NULL, "virt_19200000_ck", &virt_19200000_ck),
+ CLK(NULL, "virt_26000000_ck", &virt_26000000_ck),
+ CLK(NULL, "virt_38_4m_ck", &virt_38_4m_ck),
+ CLK(NULL, "virt_16_8m_ck", &virt_16_8m_ck),
+ CLK(NULL, "osc_sys_ck", &osc_sys_ck),
+ CLK("twl", "fck", &osc_sys_ck),
+ CLK(NULL, "sys_ck", &sys_ck),
+ CLK(NULL, "timer_sys_ck", &sys_ck),
+ CLK(NULL, "dpll4_ck", &dpll4_ck),
+ CLK(NULL, "dpll4_m2_ck", &dpll4_m2_ck),
+ CLK(NULL, "dpll4_m2x2_mul_ck", &dpll4_m2x2_mul_ck),
+ CLK(NULL, "dpll4_m2x2_ck", &dpll4_m2x2_ck),
+ CLK(NULL, "omap_96m_alwon_fck", &omap_96m_alwon_fck),
+ CLK(NULL, "dpll3_ck", &dpll3_ck),
+ CLK(NULL, "dpll3_m3_ck", &dpll3_m3_ck),
+ CLK(NULL, "dpll3_m3x2_mul_ck", &dpll3_m3x2_mul_ck),
+ CLK(NULL, "dpll3_m3x2_ck", &dpll3_m3x2_ck),
+ CLK("etb", "emu_core_alwon_ck", &emu_core_alwon_ck),
+ CLK(NULL, "sys_altclk", &sys_altclk),
+ CLK(NULL, "mcbsp_clks", &mcbsp_clks),
+ CLK(NULL, "sys_clkout1", &sys_clkout1),
+ CLK(NULL, "dpll3_m2_ck", &dpll3_m2_ck),
+ CLK(NULL, "core_ck", &core_ck),
+ CLK(NULL, "dpll1_fck", &dpll1_fck),
+ CLK(NULL, "dpll1_ck", &dpll1_ck),
+ CLK(NULL, "cpufreq_ck", &dpll1_ck),
+ CLK(NULL, "dpll1_x2_ck", &dpll1_x2_ck),
+ CLK(NULL, "dpll1_x2m2_ck", &dpll1_x2m2_ck),
+ CLK(NULL, "dpll3_x2_ck", &dpll3_x2_ck),
+ CLK(NULL, "dpll3_m2x2_ck", &dpll3_m2x2_ck),
+ CLK(NULL, "dpll4_x2_ck", &dpll4_x2_ck),
+ CLK(NULL, "cm_96m_fck", &cm_96m_fck),
+ CLK(NULL, "omap_96m_fck", &omap_96m_fck),
+ CLK(NULL, "dpll4_m3_ck", &dpll4_m3_ck),
+ CLK(NULL, "dpll4_m3x2_mul_ck", &dpll4_m3x2_mul_ck),
+ CLK(NULL, "dpll4_m3x2_ck", &dpll4_m3x2_ck),
+ CLK(NULL, "omap_54m_fck", &omap_54m_fck),
+ CLK(NULL, "cm_96m_d2_fck", &cm_96m_d2_fck),
+ CLK(NULL, "omap_48m_fck", &omap_48m_fck),
+ CLK(NULL, "omap_12m_fck", &omap_12m_fck),
+ CLK(NULL, "dpll4_m4_ck", &dpll4_m4_ck),
+ CLK(NULL, "dpll4_m4x2_mul_ck", &dpll4_m4x2_mul_ck),
+ CLK(NULL, "dpll4_m4x2_ck", &dpll4_m4x2_ck),
+ CLK(NULL, "dpll4_m5_ck", &dpll4_m5_ck),
+ CLK(NULL, "dpll4_m5x2_mul_ck", &dpll4_m5x2_mul_ck),
+ CLK(NULL, "dpll4_m5x2_ck", &dpll4_m5x2_ck),
+ CLK(NULL, "dpll4_m6_ck", &dpll4_m6_ck),
+ CLK(NULL, "dpll4_m6x2_mul_ck", &dpll4_m6x2_mul_ck),
+ CLK(NULL, "dpll4_m6x2_ck", &dpll4_m6x2_ck),
+ CLK("etb", "emu_per_alwon_ck", &emu_per_alwon_ck),
+ CLK(NULL, "clkout2_src_ck", &clkout2_src_ck),
+ CLK(NULL, "sys_clkout2", &sys_clkout2),
+ CLK(NULL, "corex2_fck", &corex2_fck),
+ CLK(NULL, "mpu_ck", &mpu_ck),
+ CLK(NULL, "arm_fck", &arm_fck),
+ CLK("etb", "emu_mpu_alwon_ck", &emu_mpu_alwon_ck),
+ CLK(NULL, "l3_ick", &l3_ick),
+ CLK(NULL, "l4_ick", &l4_ick),
+ CLK(NULL, "rm_ick", &rm_ick),
+ CLK(NULL, "timer_32k_ck", &omap_32k_fck),
+ CLK(NULL, "gpt10_fck", &gpt10_fck),
+ CLK(NULL, "gpt11_fck", &gpt11_fck),
+ CLK(NULL, "core_96m_fck", &core_96m_fck),
+ CLK(NULL, "mmchs2_fck", &mmchs2_fck),
+ CLK(NULL, "mmchs1_fck", &mmchs1_fck),
+ CLK(NULL, "i2c3_fck", &i2c3_fck),
+ CLK(NULL, "i2c2_fck", &i2c2_fck),
+ CLK(NULL, "i2c1_fck", &i2c1_fck),
+ CLK(NULL, "mcbsp5_fck", &mcbsp5_fck),
+ CLK(NULL, "mcbsp1_fck", &mcbsp1_fck),
+ CLK(NULL, "core_48m_fck", &core_48m_fck),
+ CLK(NULL, "mcspi4_fck", &mcspi4_fck),
+ CLK(NULL, "mcspi3_fck", &mcspi3_fck),
+ CLK(NULL, "mcspi2_fck", &mcspi2_fck),
+ CLK(NULL, "mcspi1_fck", &mcspi1_fck),
+ CLK(NULL, "uart2_fck", &uart2_fck),
+ CLK(NULL, "uart1_fck", &uart1_fck),
+ CLK(NULL, "core_12m_fck", &core_12m_fck),
+ CLK("omap_hdq.0", "fck", &hdq_fck),
+ CLK(NULL, "hdq_fck", &hdq_fck),
+ CLK(NULL, "core_l3_ick", &core_l3_ick),
+ CLK(NULL, "sdrc_ick", &sdrc_ick),
+ CLK(NULL, "gpmc_fck", &gpmc_fck),
+ CLK(NULL, "core_l4_ick", &core_l4_ick),
+ CLK("omap_hsmmc.1", "ick", &mmchs2_ick),
+ CLK("omap_hsmmc.0", "ick", &mmchs1_ick),
+ CLK(NULL, "mmchs2_ick", &mmchs2_ick),
+ CLK(NULL, "mmchs1_ick", &mmchs1_ick),
+ CLK("omap_hdq.0", "ick", &hdq_ick),
+ CLK(NULL, "hdq_ick", &hdq_ick),
+ CLK("omap2_mcspi.4", "ick", &mcspi4_ick),
+ CLK("omap2_mcspi.3", "ick", &mcspi3_ick),
+ CLK("omap2_mcspi.2", "ick", &mcspi2_ick),
+ CLK("omap2_mcspi.1", "ick", &mcspi1_ick),
+ CLK(NULL, "mcspi4_ick", &mcspi4_ick),
+ CLK(NULL, "mcspi3_ick", &mcspi3_ick),
+ CLK(NULL, "mcspi2_ick", &mcspi2_ick),
+ CLK(NULL, "mcspi1_ick", &mcspi1_ick),
+ CLK("omap_i2c.3", "ick", &i2c3_ick),
+ CLK("omap_i2c.2", "ick", &i2c2_ick),
+ CLK("omap_i2c.1", "ick", &i2c1_ick),
+ CLK(NULL, "i2c3_ick", &i2c3_ick),
+ CLK(NULL, "i2c2_ick", &i2c2_ick),
+ CLK(NULL, "i2c1_ick", &i2c1_ick),
+ CLK(NULL, "uart2_ick", &uart2_ick),
+ CLK(NULL, "uart1_ick", &uart1_ick),
+ CLK(NULL, "gpt11_ick", &gpt11_ick),
+ CLK(NULL, "gpt10_ick", &gpt10_ick),
+ CLK("omap-mcbsp.5", "ick", &mcbsp5_ick),
+ CLK("omap-mcbsp.1", "ick", &mcbsp1_ick),
+ CLK(NULL, "mcbsp5_ick", &mcbsp5_ick),
+ CLK(NULL, "mcbsp1_ick", &mcbsp1_ick),
+ CLK(NULL, "omapctrl_ick", &omapctrl_ick),
+ CLK(NULL, "dss_tv_fck", &dss_tv_fck),
+ CLK(NULL, "dss_96m_fck", &dss_96m_fck),
+ CLK(NULL, "dss2_alwon_fck", &dss2_alwon_fck),
+ CLK(NULL, "init_60m_fclk", &dummy_ck),
+ CLK(NULL, "gpt1_fck", &gpt1_fck),
+ CLK(NULL, "aes2_ick", &aes2_ick),
+ CLK(NULL, "wkup_32k_fck", &wkup_32k_fck),
+ CLK(NULL, "gpio1_dbck", &gpio1_dbck),
+ CLK(NULL, "sha12_ick", &sha12_ick),
+ CLK(NULL, "wdt2_fck", &wdt2_fck),
+ CLK(NULL, "wkup_l4_ick", &wkup_l4_ick),
+ CLK("omap_wdt", "ick", &wdt2_ick),
+ CLK(NULL, "wdt2_ick", &wdt2_ick),
+ CLK(NULL, "wdt1_ick", &wdt1_ick),
+ CLK(NULL, "gpio1_ick", &gpio1_ick),
+ CLK(NULL, "omap_32ksync_ick", &omap_32ksync_ick),
+ CLK(NULL, "gpt12_ick", &gpt12_ick),
+ CLK(NULL, "gpt1_ick", &gpt1_ick),
+ CLK(NULL, "per_96m_fck", &per_96m_fck),
+ CLK(NULL, "per_48m_fck", &per_48m_fck),
+ CLK(NULL, "uart3_fck", &uart3_fck),
+ CLK(NULL, "gpt2_fck", &gpt2_fck),
+ CLK(NULL, "gpt3_fck", &gpt3_fck),
+ CLK(NULL, "gpt4_fck", &gpt4_fck),
+ CLK(NULL, "gpt5_fck", &gpt5_fck),
+ CLK(NULL, "gpt6_fck", &gpt6_fck),
+ CLK(NULL, "gpt7_fck", &gpt7_fck),
+ CLK(NULL, "gpt8_fck", &gpt8_fck),
+ CLK(NULL, "gpt9_fck", &gpt9_fck),
+ CLK(NULL, "per_32k_alwon_fck", &per_32k_alwon_fck),
+ CLK(NULL, "gpio6_dbck", &gpio6_dbck),
+ CLK(NULL, "gpio5_dbck", &gpio5_dbck),
+ CLK(NULL, "gpio4_dbck", &gpio4_dbck),
+ CLK(NULL, "gpio3_dbck", &gpio3_dbck),
+ CLK(NULL, "gpio2_dbck", &gpio2_dbck),
+ CLK(NULL, "wdt3_fck", &wdt3_fck),
+ CLK(NULL, "per_l4_ick", &per_l4_ick),
+ CLK(NULL, "gpio6_ick", &gpio6_ick),
+ CLK(NULL, "gpio5_ick", &gpio5_ick),
+ CLK(NULL, "gpio4_ick", &gpio4_ick),
+ CLK(NULL, "gpio3_ick", &gpio3_ick),
+ CLK(NULL, "gpio2_ick", &gpio2_ick),
+ CLK(NULL, "wdt3_ick", &wdt3_ick),
+ CLK(NULL, "uart3_ick", &uart3_ick),
+ CLK(NULL, "uart4_ick", &uart4_ick),
+ CLK(NULL, "gpt9_ick", &gpt9_ick),
+ CLK(NULL, "gpt8_ick", &gpt8_ick),
+ CLK(NULL, "gpt7_ick", &gpt7_ick),
+ CLK(NULL, "gpt6_ick", &gpt6_ick),
+ CLK(NULL, "gpt5_ick", &gpt5_ick),
+ CLK(NULL, "gpt4_ick", &gpt4_ick),
+ CLK(NULL, "gpt3_ick", &gpt3_ick),
+ CLK(NULL, "gpt2_ick", &gpt2_ick),
+ CLK("omap-mcbsp.2", "ick", &mcbsp2_ick),
+ CLK("omap-mcbsp.3", "ick", &mcbsp3_ick),
+ CLK("omap-mcbsp.4", "ick", &mcbsp4_ick),
+ CLK(NULL, "mcbsp4_ick", &mcbsp2_ick),
+ CLK(NULL, "mcbsp3_ick", &mcbsp3_ick),
+ CLK(NULL, "mcbsp2_ick", &mcbsp4_ick),
+ CLK(NULL, "mcbsp2_fck", &mcbsp2_fck),
+ CLK(NULL, "mcbsp3_fck", &mcbsp3_fck),
+ CLK(NULL, "mcbsp4_fck", &mcbsp4_fck),
+ CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
+ CLK("etb", "emu_src_ck", &emu_src_ck),
+ CLK(NULL, "emu_src_mux_ck", &emu_src_mux_ck),
+ CLK(NULL, "emu_src_ck", &emu_src_ck),
+ CLK(NULL, "pclk_fck", &pclk_fck),
+ CLK(NULL, "pclkx2_fck", &pclkx2_fck),
+ CLK(NULL, "atclk_fck", &atclk_fck),
+ CLK(NULL, "traceclk_src_fck", &traceclk_src_fck),
+ CLK(NULL, "traceclk_fck", &traceclk_fck),
+ CLK(NULL, "secure_32k_fck", &secure_32k_fck),
+ CLK(NULL, "gpt12_fck", &gpt12_fck),
+ CLK(NULL, "wdt1_fck", &wdt1_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_am35xx_omap3430es2plus_clks[] = {
+ CLK(NULL, "dpll5_ck", &dpll5_ck),
+ CLK(NULL, "dpll5_m2_ck", &dpll5_m2_ck),
+ CLK(NULL, "core_d3_ck", &core_d3_ck),
+ CLK(NULL, "core_d4_ck", &core_d4_ck),
+ CLK(NULL, "core_d6_ck", &core_d6_ck),
+ CLK(NULL, "omap_192m_alwon_fck", &omap_192m_alwon_fck),
+ CLK(NULL, "core_d2_ck", &core_d2_ck),
+ CLK(NULL, "corex2_d3_fck", &corex2_d3_fck),
+ CLK(NULL, "corex2_d5_fck", &corex2_d5_fck),
+ CLK(NULL, "sgx_fck", &sgx_fck),
+ CLK(NULL, "sgx_ick", &sgx_ick),
+ CLK(NULL, "cpefuse_fck", &cpefuse_fck),
+ CLK(NULL, "ts_fck", &ts_fck),
+ CLK(NULL, "usbtll_fck", &usbtll_fck),
+ CLK(NULL, "usbtll_ick", &usbtll_ick),
+ CLK("omap_hsmmc.2", "ick", &mmchs3_ick),
+ CLK(NULL, "mmchs3_ick", &mmchs3_ick),
+ CLK(NULL, "mmchs3_fck", &mmchs3_fck),
+ CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es2),
+ CLK("omapdss_dss", "ick", &dss_ick_3430es2),
+ CLK(NULL, "dss_ick", &dss_ick_3430es2),
+ CLK(NULL, "usbhost_120m_fck", &usbhost_120m_fck),
+ CLK(NULL, "usbhost_48m_fck", &usbhost_48m_fck),
+ CLK(NULL, "usbhost_ick", &usbhost_ick),
+ { NULL },
+};
+
+static struct ti_clk_alias omap3430es1_clks[] = {
+ CLK(NULL, "gfx_l3_ck", &gfx_l3_ck),
+ CLK(NULL, "gfx_l3_fck", &gfx_l3_fck),
+ CLK(NULL, "gfx_l3_ick", &gfx_l3_ick),
+ CLK(NULL, "gfx_cg1_ck", &gfx_cg1_ck),
+ CLK(NULL, "gfx_cg2_ck", &gfx_cg2_ck),
+ CLK(NULL, "d2d_26m_fck", &d2d_26m_fck),
+ CLK(NULL, "fshostusb_fck", &fshostusb_fck),
+ CLK(NULL, "ssi_ssr_fck", &ssi_ssr_fck_3430es1),
+ CLK(NULL, "ssi_sst_fck", &ssi_sst_fck_3430es1),
+ CLK("musb-omap2430", "ick", &hsotgusb_ick_3430es1),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_3430es1),
+ CLK(NULL, "fac_ick", &fac_ick),
+ CLK(NULL, "ssi_ick", &ssi_ick_3430es1),
+ CLK(NULL, "usb_l4_ick", &usb_l4_ick),
+ CLK(NULL, "dss1_alwon_fck", &dss1_alwon_fck_3430es1),
+ CLK("omapdss_dss", "ick", &dss_ick_3430es1),
+ CLK(NULL, "dss_ick", &dss_ick_3430es1),
+ { NULL },
+};
+
+static struct ti_clk_alias omap36xx_clks[] = {
+ CLK(NULL, "uart4_fck", &uart4_fck),
+ { NULL },
+};
+
+static struct ti_clk_alias am35xx_clks[] = {
+ CLK(NULL, "ipss_ick", &ipss_ick),
+ CLK(NULL, "rmii_ck", &rmii_ck),
+ CLK(NULL, "pclk_ck", &pclk_ck),
+ CLK(NULL, "emac_ick", &emac_ick),
+ CLK(NULL, "emac_fck", &emac_fck),
+ CLK("davinci_emac.0", NULL, &emac_ick),
+ CLK("davinci_mdio.0", NULL, &emac_fck),
+ CLK("vpfe-capture", "master", &vpfe_ick),
+ CLK("vpfe-capture", "slave", &vpfe_fck),
+ CLK(NULL, "hsotgusb_ick", &hsotgusb_ick_am35xx),
+ CLK(NULL, "hsotgusb_fck", &hsotgusb_fck_am35xx),
+ CLK(NULL, "hecc_ck", &hecc_ck),
+ CLK(NULL, "uart4_ick", &uart4_ick_am35xx),
+ CLK(NULL, "uart4_fck", &uart4_fck_am35xx),
+ { NULL },
+};
+
+static struct ti_clk *omap36xx_clk_patches[] = {
+ &dpll4_m3x2_ck_omap36xx,
+ &dpll3_m3x2_ck_omap36xx,
+ &dpll4_m6x2_ck_omap36xx,
+ &dpll4_m2x2_ck_omap36xx,
+ &dpll4_m5x2_ck_omap36xx,
+ &dpll4_ck_omap36xx,
+ NULL,
+};
+
+static const char *enable_init_clks[] = {
+ "sdrc_ick",
+ "gpmc_fck",
+ "omapctrl_ick",
+};
+
+static void __init omap3_clk_legacy_common_init(void)
+{
+ omap2_clk_disable_autoidle_all();
+
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ pr_info("Clocking rate (Crystal/Core/MPU): %ld.%01ld/%ld/%ld MHz\n",
+ (clk_get_rate(osc_sys_ck.clk) / 1000000),
+ (clk_get_rate(osc_sys_ck.clk) / 100000) % 10,
+ (clk_get_rate(core_ck.clk) / 1000000),
+ (clk_get_rate(arm_fck.clk) / 1000000));
+}
+
+int __init omap3430es1_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(omap3430es1_clks);
+ r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+
+ return r;
+}
+
+int __init omap3430_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
+
+int __init omap36xx_clk_legacy_init(void)
+{
+ int r;
+
+ ti_clk_patch_legacy_clks(omap36xx_clk_patches);
+ r = ti_clk_register_legacy_clks(omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap34xx_omap36xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
+
+int __init am35xx_clk_legacy_init(void)
+{
+ int r;
+
+ r = ti_clk_register_legacy_clks(am35xx_clks);
+ r |= ti_clk_register_legacy_clks(omap36xx_am35xx_omap3430es2plus_clks);
+ r |= ti_clk_register_legacy_clks(omap3xxx_clks);
+
+ omap3_clk_legacy_common_init();
+ omap3_clk_lock_dpll5();
+
+ return r;
+}
diff --git a/drivers/clk/ti/clk-3xxx.c b/drivers/clk/ti/clk-3xxx.c
index 0d1750a8aea4..383a06e49b09 100644
--- a/drivers/clk/ti/clk-3xxx.c
+++ b/drivers/clk/ti/clk-3xxx.c
@@ -327,7 +327,6 @@ enum {
OMAP3_SOC_OMAP3430_ES1,
OMAP3_SOC_OMAP3430_ES2_PLUS,
OMAP3_SOC_OMAP3630,
- OMAP3_SOC_TI81XX,
};
static int __init omap3xxx_dt_clk_init(int soc_type)
@@ -370,7 +369,7 @@ static int __init omap3xxx_dt_clk_init(int soc_type)
(clk_get_rate(clk_get_sys(NULL, "core_ck")) / 1000000),
(clk_get_rate(clk_get_sys(NULL, "arm_fck")) / 1000000));
- if (soc_type != OMAP3_SOC_TI81XX && soc_type != OMAP3_SOC_OMAP3430_ES1)
+ if (soc_type != OMAP3_SOC_OMAP3430_ES1)
omap3_clk_lock_dpll5();
return 0;
@@ -390,8 +389,3 @@ int __init am35xx_dt_clk_init(void)
{
return omap3xxx_dt_clk_init(OMAP3_SOC_AM35XX);
}
-
-int __init ti81xx_dt_clk_init(void)
-{
- return omap3xxx_dt_clk_init(OMAP3_SOC_TI81XX);
-}
diff --git a/drivers/clk/ti/clk-44xx.c b/drivers/clk/ti/clk-44xx.c
index 02517a8206bd..4f4c87751db5 100644
--- a/drivers/clk/ti/clk-44xx.c
+++ b/drivers/clk/ti/clk-44xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-54xx.c b/drivers/clk/ti/clk-54xx.c
index 5e183993e3ec..14160b223548 100644
--- a/drivers/clk/ti/clk-54xx.c
+++ b/drivers/clk/ti/clk-54xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/io.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-7xx.c b/drivers/clk/ti/clk-7xx.c
index 62ac8f6e480c..ee32f4deebf4 100644
--- a/drivers/clk/ti/clk-7xx.c
+++ b/drivers/clk/ti/clk-7xx.c
@@ -12,7 +12,7 @@
#include <linux/kernel.h>
#include <linux/list.h>
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/clkdev.h>
#include <linux/clk/ti.h>
diff --git a/drivers/clk/ti/clk-816x.c b/drivers/clk/ti/clk-816x.c
new file mode 100644
index 000000000000..9451e651a1ff
--- /dev/null
+++ b/drivers/clk/ti/clk-816x.c
@@ -0,0 +1,53 @@
+/*
+ * This program is free software; 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/list.h>
+#include <linux/clk-provider.h>
+#include <linux/clk/ti.h>
+
+static struct ti_dt_clk dm816x_clks[] = {
+ DT_CLK(NULL, "sys_clkin", "sys_clkin_ck"),
+ DT_CLK(NULL, "timer_sys_ck", "sys_clkin_ck"),
+ DT_CLK(NULL, "sys_32k_ck", "sys_32k_ck"),
+ DT_CLK(NULL, "mpu_ck", "mpu_ck"),
+ DT_CLK(NULL, "timer1_fck", "timer1_fck"),
+ DT_CLK(NULL, "timer2_fck", "timer2_fck"),
+ DT_CLK(NULL, "timer3_fck", "timer3_fck"),
+ DT_CLK(NULL, "timer4_fck", "timer4_fck"),
+ DT_CLK(NULL, "timer5_fck", "timer5_fck"),
+ DT_CLK(NULL, "timer6_fck", "timer6_fck"),
+ DT_CLK(NULL, "timer7_fck", "timer7_fck"),
+ DT_CLK(NULL, "sysclk4_ck", "sysclk4_ck"),
+ DT_CLK(NULL, "sysclk5_ck", "sysclk5_ck"),
+ DT_CLK(NULL, "sysclk6_ck", "sysclk6_ck"),
+ DT_CLK(NULL, "sysclk10_ck", "sysclk10_ck"),
+ DT_CLK(NULL, "sysclk18_ck", "sysclk18_ck"),
+ DT_CLK(NULL, "sysclk24_ck", "sysclk24_ck"),
+ DT_CLK("4a100000.ethernet", "sysclk24_ck", "sysclk24_ck"),
+ { .node_name = NULL },
+};
+
+static const char *enable_init_clks[] = {
+ "ddr_pll_clk1",
+ "ddr_pll_clk2",
+ "ddr_pll_clk3",
+};
+
+int __init ti81xx_dt_clk_init(void)
+{
+ ti_dt_clocks_register(dm816x_clks);
+ omap2_clk_disable_autoidle_all();
+ omap2_clk_enable_init_clocks(enable_init_clks,
+ ARRAY_SIZE(enable_init_clks));
+
+ return 0;
+}
diff --git a/drivers/clk/ti/clk.c b/drivers/clk/ti/clk.c
index 337abe5909e1..e22b95646e09 100644
--- a/drivers/clk/ti/clk.c
+++ b/drivers/clk/ti/clk.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/list.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -183,3 +185,128 @@ void ti_dt_clk_init_retry_clks(void)
retries--;
}
}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+void __init ti_clk_patch_legacy_clks(struct ti_clk **patch)
+{
+ while (*patch) {
+ memcpy((*patch)->patch, *patch, sizeof(**patch));
+ patch++;
+ }
+}
+
+struct clk __init *ti_clk_register_clk(struct ti_clk *setup)
+{
+ struct clk *clk;
+ struct ti_clk_fixed *fixed;
+ struct ti_clk_fixed_factor *fixed_factor;
+ struct clk_hw *clk_hw;
+
+ if (setup->clk)
+ return setup->clk;
+
+ switch (setup->type) {
+ case TI_CLK_FIXED:
+ fixed = setup->data;
+
+ clk = clk_register_fixed_rate(NULL, setup->name, NULL,
+ CLK_IS_ROOT, fixed->frequency);
+ break;
+ case TI_CLK_MUX:
+ clk = ti_clk_register_mux(setup);
+ break;
+ case TI_CLK_DIVIDER:
+ clk = ti_clk_register_divider(setup);
+ break;
+ case TI_CLK_COMPOSITE:
+ clk = ti_clk_register_composite(setup);
+ break;
+ case TI_CLK_FIXED_FACTOR:
+ fixed_factor = setup->data;
+
+ clk = clk_register_fixed_factor(NULL, setup->name,
+ fixed_factor->parent,
+ 0, fixed_factor->mult,
+ fixed_factor->div);
+ break;
+ case TI_CLK_GATE:
+ clk = ti_clk_register_gate(setup);
+ break;
+ case TI_CLK_DPLL:
+ clk = ti_clk_register_dpll(setup);
+ break;
+ default:
+ pr_err("bad type for %s!\n", setup->name);
+ clk = ERR_PTR(-EINVAL);
+ }
+
+ if (!IS_ERR(clk)) {
+ setup->clk = clk;
+ if (setup->clkdm_name) {
+ if (__clk_get_flags(clk) & CLK_IS_BASIC) {
+ pr_warn("can't setup clkdm for basic clk %s\n",
+ setup->name);
+ } else {
+ clk_hw = __clk_get_hw(clk);
+ to_clk_hw_omap(clk_hw)->clkdm_name =
+ setup->clkdm_name;
+ omap2_init_clk_clkdm(clk_hw);
+ }
+ }
+ }
+
+ return clk;
+}
+
+int __init ti_clk_register_legacy_clks(struct ti_clk_alias *clks)
+{
+ struct clk *clk;
+ bool retry;
+ struct ti_clk_alias *retry_clk;
+ struct ti_clk_alias *tmp;
+
+ while (clks->clk) {
+ clk = ti_clk_register_clk(clks->clk);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EAGAIN) {
+ list_add(&clks->link, &retry_list);
+ } else {
+ pr_err("register for %s failed: %ld\n",
+ clks->clk->name, PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ } else {
+ clks->lk.clk = clk;
+ clkdev_add(&clks->lk);
+ }
+ clks++;
+ }
+
+ retry = true;
+
+ while (!list_empty(&retry_list) && retry) {
+ retry = false;
+ list_for_each_entry_safe(retry_clk, tmp, &retry_list, link) {
+ pr_debug("retry-init: %s\n", retry_clk->clk->name);
+ clk = ti_clk_register_clk(retry_clk->clk);
+ if (IS_ERR(clk)) {
+ if (PTR_ERR(clk) == -EAGAIN) {
+ continue;
+ } else {
+ pr_err("register for %s failed: %ld\n",
+ retry_clk->clk->name,
+ PTR_ERR(clk));
+ return PTR_ERR(clk);
+ }
+ } else {
+ retry = true;
+ retry_clk->lk.clk = clk;
+ clkdev_add(&retry_clk->lk);
+ list_del(&retry_clk->link);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
diff --git a/drivers/clk/ti/clock.h b/drivers/clk/ti/clock.h
new file mode 100644
index 000000000000..404158d2d7f8
--- /dev/null
+++ b/drivers/clk/ti/clock.h
@@ -0,0 +1,172 @@
+/*
+ * TI Clock driver internal definitions
+ *
+ * Copyright (C) 2014 Texas Instruments, Inc
+ * Tero Kristo (t-kristo@ti.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __DRIVERS_CLK_TI_CLOCK__
+#define __DRIVERS_CLK_TI_CLOCK__
+
+enum {
+ TI_CLK_FIXED,
+ TI_CLK_MUX,
+ TI_CLK_DIVIDER,
+ TI_CLK_COMPOSITE,
+ TI_CLK_FIXED_FACTOR,
+ TI_CLK_GATE,
+ TI_CLK_DPLL,
+};
+
+/* Global flags */
+#define CLKF_INDEX_POWER_OF_TWO (1 << 0)
+#define CLKF_INDEX_STARTS_AT_ONE (1 << 1)
+#define CLKF_SET_RATE_PARENT (1 << 2)
+#define CLKF_OMAP3 (1 << 3)
+#define CLKF_AM35XX (1 << 4)
+
+/* Gate flags */
+#define CLKF_SET_BIT_TO_DISABLE (1 << 5)
+#define CLKF_INTERFACE (1 << 6)
+#define CLKF_SSI (1 << 7)
+#define CLKF_DSS (1 << 8)
+#define CLKF_HSOTGUSB (1 << 9)
+#define CLKF_WAIT (1 << 10)
+#define CLKF_NO_WAIT (1 << 11)
+#define CLKF_HSDIV (1 << 12)
+#define CLKF_CLKDM (1 << 13)
+
+/* DPLL flags */
+#define CLKF_LOW_POWER_STOP (1 << 5)
+#define CLKF_LOCK (1 << 6)
+#define CLKF_LOW_POWER_BYPASS (1 << 7)
+#define CLKF_PER (1 << 8)
+#define CLKF_CORE (1 << 9)
+#define CLKF_J_TYPE (1 << 10)
+
+#define CLK(dev, con, ck) \
+ { \
+ .lk = { \
+ .dev_id = dev, \
+ .con_id = con, \
+ }, \
+ .clk = ck, \
+ }
+
+struct ti_clk {
+ const char *name;
+ const char *clkdm_name;
+ int type;
+ void *data;
+ struct ti_clk *patch;
+ struct clk *clk;
+};
+
+struct ti_clk_alias {
+ struct ti_clk *clk;
+ struct clk_lookup lk;
+ struct list_head link;
+};
+
+struct ti_clk_fixed {
+ u32 frequency;
+ u16 flags;
+};
+
+struct ti_clk_mux {
+ u8 bit_shift;
+ int num_parents;
+ u16 reg;
+ u8 module;
+ const char **parents;
+ u16 flags;
+};
+
+struct ti_clk_divider {
+ const char *parent;
+ u8 bit_shift;
+ u16 max_div;
+ u16 reg;
+ u8 module;
+ int *dividers;
+ int num_dividers;
+ u16 flags;
+};
+
+struct ti_clk_fixed_factor {
+ const char *parent;
+ u16 div;
+ u16 mult;
+ u16 flags;
+};
+
+struct ti_clk_gate {
+ const char *parent;
+ u8 bit_shift;
+ u16 reg;
+ u8 module;
+ u16 flags;
+};
+
+struct ti_clk_composite {
+ struct ti_clk_divider *divider;
+ struct ti_clk_mux *mux;
+ struct ti_clk_gate *gate;
+ u16 flags;
+};
+
+struct ti_clk_clkdm_gate {
+ const char *parent;
+ u16 flags;
+};
+
+struct ti_clk_dpll {
+ int num_parents;
+ u16 control_reg;
+ u16 idlest_reg;
+ u16 autoidle_reg;
+ u16 mult_div1_reg;
+ u8 module;
+ const char **parents;
+ u16 flags;
+ u8 modes;
+ u32 mult_mask;
+ u32 div1_mask;
+ u32 enable_mask;
+ u32 autoidle_mask;
+ u32 freqsel_mask;
+ u32 idlest_mask;
+ u32 dco_mask;
+ u32 sddiv_mask;
+ u16 max_multiplier;
+ u16 max_divider;
+ u8 min_divider;
+ u8 auto_recal_bit;
+ u8 recal_en_bit;
+ u8 recal_st_bit;
+};
+
+struct clk *ti_clk_register_gate(struct ti_clk *setup);
+struct clk *ti_clk_register_interface(struct ti_clk *setup);
+struct clk *ti_clk_register_mux(struct ti_clk *setup);
+struct clk *ti_clk_register_divider(struct ti_clk *setup);
+struct clk *ti_clk_register_composite(struct ti_clk *setup);
+struct clk *ti_clk_register_dpll(struct ti_clk *setup);
+
+struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup);
+struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup);
+struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup);
+
+void ti_clk_patch_legacy_clks(struct ti_clk **patch);
+struct clk *ti_clk_register_clk(struct ti_clk *setup);
+int ti_clk_register_legacy_clks(struct ti_clk_alias *clks);
+
+#endif
diff --git a/drivers/clk/ti/composite.c b/drivers/clk/ti/composite.c
index 19d8980ba458..3654f61912eb 100644
--- a/drivers/clk/ti/composite.c
+++ b/drivers/clk/ti/composite.c
@@ -23,6 +23,8 @@
#include <linux/clk/ti.h>
#include <linux/list.h>
+#include "clock.h"
+
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -116,8 +118,46 @@ static inline struct clk_hw *_get_hw(struct clk_hw_omap_comp *clk, int idx)
#define to_clk_hw_comp(_hw) container_of(_hw, struct clk_hw_omap_comp, hw)
-static void __init ti_clk_register_composite(struct clk_hw *hw,
- struct device_node *node)
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_composite(struct ti_clk *setup)
+{
+ struct ti_clk_composite *comp;
+ struct clk_hw *gate;
+ struct clk_hw *mux;
+ struct clk_hw *div;
+ int num_parents = 1;
+ const char **parent_names = NULL;
+ struct clk *clk;
+
+ comp = setup->data;
+
+ div = ti_clk_build_component_div(comp->divider);
+ gate = ti_clk_build_component_gate(comp->gate);
+ mux = ti_clk_build_component_mux(comp->mux);
+
+ if (div)
+ parent_names = &comp->divider->parent;
+
+ if (gate)
+ parent_names = &comp->gate->parent;
+
+ if (mux) {
+ num_parents = comp->mux->num_parents;
+ parent_names = comp->mux->parents;
+ }
+
+ clk = clk_register_composite(NULL, setup->name,
+ parent_names, num_parents, mux,
+ &ti_clk_mux_ops, div,
+ &ti_composite_divider_ops, gate,
+ &ti_composite_gate_ops, 0);
+
+ return clk;
+}
+#endif
+
+static void __init _register_composite(struct clk_hw *hw,
+ struct device_node *node)
{
struct clk *clk;
struct clk_hw_omap_comp *cclk = to_clk_hw_comp(hw);
@@ -136,7 +176,7 @@ static void __init ti_clk_register_composite(struct clk_hw *hw,
pr_debug("component %s not ready for %s, retry\n",
cclk->comp_nodes[i]->name, node->name);
if (!ti_clk_retry_init(node, hw,
- ti_clk_register_composite))
+ _register_composite))
return;
goto cleanup;
@@ -216,7 +256,7 @@ static void __init of_ti_composite_clk_setup(struct device_node *node)
for (i = 0; i < num_clks; i++)
cclk->comp_nodes[i] = _get_component_node(node, i);
- ti_clk_register_composite(&cclk->hw, node);
+ _register_composite(&cclk->hw, node);
}
CLK_OF_DECLARE(ti_composite_clock, "ti,composite-clock",
of_ti_composite_clk_setup);
diff --git a/drivers/clk/ti/divider.c b/drivers/clk/ti/divider.c
index bff2b5b8ff59..6211893c0980 100644
--- a/drivers/clk/ti/divider.c
+++ b/drivers/clk/ti/divider.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -301,6 +302,134 @@ static struct clk *_register_divider(struct device *dev, const char *name,
}
static struct clk_div_table *
+_get_div_table_from_setup(struct ti_clk_divider *setup, u8 *width)
+{
+ int valid_div = 0;
+ struct clk_div_table *table;
+ int i;
+ int div;
+ u32 val;
+ u8 flags;
+
+ if (!setup->num_dividers) {
+ /* Clk divider table not provided, determine min/max divs */
+ flags = setup->flags;
+
+ if (flags & CLKF_INDEX_STARTS_AT_ONE)
+ val = 1;
+ else
+ val = 0;
+
+ div = 1;
+
+ while (div < setup->max_div) {
+ if (flags & CLKF_INDEX_POWER_OF_TWO)
+ div <<= 1;
+ else
+ div++;
+ val++;
+ }
+
+ *width = fls(val);
+
+ return NULL;
+ }
+
+ for (i = 0; i < setup->num_dividers; i++)
+ if (setup->dividers[i])
+ valid_div++;
+
+ table = kzalloc(sizeof(*table) * (valid_div + 1), GFP_KERNEL);
+ if (!table)
+ return ERR_PTR(-ENOMEM);
+
+ valid_div = 0;
+ *width = 0;
+
+ for (i = 0; i < setup->num_dividers; i++)
+ if (setup->dividers[i]) {
+ table[valid_div].div = setup->dividers[i];
+ table[valid_div].val = i;
+ valid_div++;
+ *width = i;
+ }
+
+ *width = fls(*width);
+
+ return table;
+}
+
+struct clk_hw *ti_clk_build_component_div(struct ti_clk_divider *setup)
+{
+ struct clk_divider *div;
+ struct clk_omap_reg *reg;
+
+ if (!setup)
+ return NULL;
+
+ div = kzalloc(sizeof(*div), GFP_KERNEL);
+ if (!div)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&div->reg;
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
+ div->flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (setup->flags & CLKF_INDEX_POWER_OF_TWO)
+ div->flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+ div->table = _get_div_table_from_setup(setup, &div->width);
+
+ div->shift = setup->bit_shift;
+
+ return &div->hw;
+}
+
+struct clk *ti_clk_register_divider(struct ti_clk *setup)
+{
+ struct ti_clk_divider *div;
+ struct clk_omap_reg *reg_setup;
+ u32 reg;
+ u8 width;
+ u32 flags = 0;
+ u8 div_flags = 0;
+ struct clk_div_table *table;
+ struct clk *clk;
+
+ div = setup->data;
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ reg_setup->index = div->module;
+ reg_setup->offset = div->reg;
+
+ if (div->flags & CLKF_INDEX_STARTS_AT_ONE)
+ div_flags |= CLK_DIVIDER_ONE_BASED;
+
+ if (div->flags & CLKF_INDEX_POWER_OF_TWO)
+ div_flags |= CLK_DIVIDER_POWER_OF_TWO;
+
+ if (div->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ table = _get_div_table_from_setup(div, &width);
+ if (IS_ERR(table))
+ return (struct clk *)table;
+
+ clk = _register_divider(NULL, setup->name, div->parent,
+ flags, (void __iomem *)reg, div->bit_shift,
+ width, div_flags, table, NULL);
+
+ if (IS_ERR(clk))
+ kfree(table);
+
+ return clk;
+}
+
+static struct clk_div_table *
__init ti_clk_get_div_table(struct device_node *node)
{
struct clk_div_table *table;
@@ -455,7 +584,8 @@ static void __init of_ti_divider_clk_setup(struct device_node *node)
goto cleanup;
clk = _register_divider(NULL, node->name, parent_name, flags, reg,
- shift, width, clk_divider_flags, table, NULL);
+ shift, width, clk_divider_flags, table,
+ NULL);
if (!IS_ERR(clk)) {
of_clk_add_provider(node, of_clk_src_simple_get, clk);
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 85ac0dd501de..81dc4698dc41 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -130,7 +131,7 @@ static const struct clk_ops dpll_x2_ck_ops = {
};
/**
- * ti_clk_register_dpll - low level registration of a DPLL clock
+ * _register_dpll - low level registration of a DPLL clock
* @hw: hardware clock definition for the clock
* @node: device node for the clock
*
@@ -138,8 +139,8 @@ static const struct clk_ops dpll_x2_ck_ops = {
* clk-bypass is missing), the clock is added to retry list and
* the initialization is retried on later stage.
*/
-static void __init ti_clk_register_dpll(struct clk_hw *hw,
- struct device_node *node)
+static void __init _register_dpll(struct clk_hw *hw,
+ struct device_node *node)
{
struct clk_hw_omap *clk_hw = to_clk_hw_omap(hw);
struct dpll_data *dd = clk_hw->dpll_data;
@@ -151,7 +152,7 @@ static void __init ti_clk_register_dpll(struct clk_hw *hw,
if (IS_ERR(dd->clk_ref) || IS_ERR(dd->clk_bypass)) {
pr_debug("clk-ref or clk-bypass missing for %s, retry later\n",
node->name);
- if (!ti_clk_retry_init(node, hw, ti_clk_register_dpll))
+ if (!ti_clk_retry_init(node, hw, _register_dpll))
return;
goto cleanup;
@@ -175,20 +176,118 @@ cleanup:
kfree(clk_hw);
}
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+void __iomem *_get_reg(u8 module, u16 offset)
+{
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ reg_setup->index = module;
+ reg_setup->offset = offset;
+
+ return (void __iomem *)reg;
+}
+
+struct clk *ti_clk_register_dpll(struct ti_clk *setup)
+{
+ struct clk_hw_omap *clk_hw;
+ struct clk_init_data init = { NULL };
+ struct dpll_data *dd;
+ struct clk *clk;
+ struct ti_clk_dpll *dpll;
+ const struct clk_ops *ops = &omap3_dpll_ck_ops;
+ struct clk *clk_ref;
+ struct clk *clk_bypass;
+
+ dpll = setup->data;
+
+ if (dpll->num_parents < 2)
+ return ERR_PTR(-EINVAL);
+
+ clk_ref = clk_get_sys(NULL, dpll->parents[0]);
+ clk_bypass = clk_get_sys(NULL, dpll->parents[1]);
+
+ if (IS_ERR_OR_NULL(clk_ref) || IS_ERR_OR_NULL(clk_bypass))
+ return ERR_PTR(-EAGAIN);
+
+ dd = kzalloc(sizeof(*dd), GFP_KERNEL);
+ clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
+ if (!dd || !clk_hw) {
+ clk = ERR_PTR(-ENOMEM);
+ goto cleanup;
+ }
+
+ clk_hw->dpll_data = dd;
+ clk_hw->ops = &clkhwops_omap3_dpll;
+ clk_hw->hw.init = &init;
+ clk_hw->flags = MEMMAP_ADDRESSING;
+
+ init.name = setup->name;
+ init.ops = ops;
+
+ init.num_parents = dpll->num_parents;
+ init.parent_names = dpll->parents;
+
+ dd->control_reg = _get_reg(dpll->module, dpll->control_reg);
+ dd->idlest_reg = _get_reg(dpll->module, dpll->idlest_reg);
+ dd->mult_div1_reg = _get_reg(dpll->module, dpll->mult_div1_reg);
+ dd->autoidle_reg = _get_reg(dpll->module, dpll->autoidle_reg);
+
+ dd->modes = dpll->modes;
+ dd->div1_mask = dpll->div1_mask;
+ dd->idlest_mask = dpll->idlest_mask;
+ dd->mult_mask = dpll->mult_mask;
+ dd->autoidle_mask = dpll->autoidle_mask;
+ dd->enable_mask = dpll->enable_mask;
+ dd->sddiv_mask = dpll->sddiv_mask;
+ dd->dco_mask = dpll->dco_mask;
+ dd->max_divider = dpll->max_divider;
+ dd->min_divider = dpll->min_divider;
+ dd->max_multiplier = dpll->max_multiplier;
+ dd->auto_recal_bit = dpll->auto_recal_bit;
+ dd->recal_en_bit = dpll->recal_en_bit;
+ dd->recal_st_bit = dpll->recal_st_bit;
+
+ dd->clk_ref = clk_ref;
+ dd->clk_bypass = clk_bypass;
+
+ if (dpll->flags & CLKF_CORE)
+ ops = &omap3_dpll_core_ck_ops;
+
+ if (dpll->flags & CLKF_PER)
+ ops = &omap3_dpll_per_ck_ops;
+
+ if (dpll->flags & CLKF_J_TYPE)
+ dd->flags |= DPLL_J_TYPE;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (!IS_ERR(clk))
+ return clk;
+
+cleanup:
+ kfree(dd);
+ kfree(clk_hw);
+ return clk;
+}
+#endif
+
#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM33XX) || \
defined(CONFIG_SOC_AM43XX)
/**
- * ti_clk_register_dpll_x2 - Registers a DPLLx2 clock
+ * _register_dpll_x2 - Registers a DPLLx2 clock
* @node: device node for this clock
* @ops: clk_ops for this clock
* @hw_ops: clk_hw_ops for this clock
*
* Initializes a DPLL x 2 clock from device tree data.
*/
-static void ti_clk_register_dpll_x2(struct device_node *node,
- const struct clk_ops *ops,
- const struct clk_hw_omap_ops *hw_ops)
+static void _register_dpll_x2(struct device_node *node,
+ const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
{
struct clk *clk;
struct clk_init_data init = { NULL };
@@ -318,7 +417,7 @@ static void __init of_ti_dpll_setup(struct device_node *node,
if (dpll_mode)
dd->modes = dpll_mode;
- ti_clk_register_dpll(&clk_hw->hw, node);
+ _register_dpll(&clk_hw->hw, node);
return;
cleanup:
@@ -332,7 +431,7 @@ cleanup:
defined(CONFIG_SOC_DRA7XX)
static void __init of_ti_omap4_dpll_x2_setup(struct device_node *node)
{
- ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
+ _register_dpll_x2(node, &dpll_x2_ck_ops, &clkhwops_omap4_dpllmx);
}
CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
of_ti_omap4_dpll_x2_setup);
@@ -341,7 +440,7 @@ CLK_OF_DECLARE(ti_omap4_dpll_x2_clock, "ti,omap4-dpll-x2-clock",
#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
static void __init of_ti_am3_dpll_x2_setup(struct device_node *node)
{
- ti_clk_register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
+ _register_dpll_x2(node, &dpll_x2_ck_ops, NULL);
}
CLK_OF_DECLARE(ti_am3_dpll_x2_clock, "ti,am3-dpll-x2-clock",
of_ti_am3_dpll_x2_setup);
diff --git a/drivers/clk/ti/fapll.c b/drivers/clk/ti/fapll.c
new file mode 100644
index 000000000000..6ef89639a9f6
--- /dev/null
+++ b/drivers/clk/ti/fapll.c
@@ -0,0 +1,410 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/clk/ti.h>
+#include <asm/div64.h>
+
+/* FAPLL Control Register PLL_CTRL */
+#define FAPLL_MAIN_LOCK BIT(7)
+#define FAPLL_MAIN_PLLEN BIT(3)
+#define FAPLL_MAIN_BP BIT(2)
+#define FAPLL_MAIN_LOC_CTL BIT(0)
+
+/* FAPLL powerdown register PWD */
+#define FAPLL_PWD_OFFSET 4
+
+#define MAX_FAPLL_OUTPUTS 7
+#define FAPLL_MAX_RETRIES 1000
+
+#define to_fapll(_hw) container_of(_hw, struct fapll_data, hw)
+#define to_synth(_hw) container_of(_hw, struct fapll_synth, hw)
+
+/* The bypass bit is inverted on the ddr_pll.. */
+#define fapll_is_ddr_pll(va) (((u32)(va) & 0xffff) == 0x0440)
+
+/*
+ * The audio_pll_clk1 input is hard wired to the 27MHz bypass clock,
+ * and the audio_pll_clk1 synthesizer is hardwared to 32KiHz output.
+ */
+#define is_ddr_pll_clk1(va) (((u32)(va) & 0xffff) == 0x044c)
+#define is_audio_pll_clk1(va) (((u32)(va) & 0xffff) == 0x04a8)
+
+/* Synthesizer divider register */
+#define SYNTH_LDMDIV1 BIT(8)
+
+/* Synthesizer frequency register */
+#define SYNTH_LDFREQ BIT(31)
+
+struct fapll_data {
+ struct clk_hw hw;
+ void __iomem *base;
+ const char *name;
+ struct clk *clk_ref;
+ struct clk *clk_bypass;
+ struct clk_onecell_data outputs;
+ bool bypass_bit_inverted;
+};
+
+struct fapll_synth {
+ struct clk_hw hw;
+ struct fapll_data *fd;
+ int index;
+ void __iomem *freq;
+ void __iomem *div;
+ const char *name;
+ struct clk *clk_pll;
+};
+
+static bool ti_fapll_clock_is_bypass(struct fapll_data *fd)
+{
+ u32 v = readl_relaxed(fd->base);
+
+ if (fd->bypass_bit_inverted)
+ return !(v & FAPLL_MAIN_BP);
+ else
+ return !!(v & FAPLL_MAIN_BP);
+}
+
+static int ti_fapll_enable(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ v |= (1 << FAPLL_MAIN_PLLEN);
+ writel_relaxed(v, fd->base);
+
+ return 0;
+}
+
+static void ti_fapll_disable(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ v &= ~(1 << FAPLL_MAIN_PLLEN);
+ writel_relaxed(v, fd->base);
+}
+
+static int ti_fapll_is_enabled(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 v = readl_relaxed(fd->base);
+
+ return v & (1 << FAPLL_MAIN_PLLEN);
+}
+
+static unsigned long ti_fapll_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct fapll_data *fd = to_fapll(hw);
+ u32 fapll_n, fapll_p, v;
+ long long rate;
+
+ if (ti_fapll_clock_is_bypass(fd))
+ return parent_rate;
+
+ rate = parent_rate;
+
+ /* PLL pre-divider is P and multiplier is N */
+ v = readl_relaxed(fd->base);
+ fapll_p = (v >> 8) & 0xff;
+ if (fapll_p)
+ do_div(rate, fapll_p);
+ fapll_n = v >> 16;
+ if (fapll_n)
+ rate *= fapll_n;
+
+ return rate;
+}
+
+static u8 ti_fapll_get_parent(struct clk_hw *hw)
+{
+ struct fapll_data *fd = to_fapll(hw);
+
+ if (ti_fapll_clock_is_bypass(fd))
+ return 1;
+
+ return 0;
+}
+
+static struct clk_ops ti_fapll_ops = {
+ .enable = ti_fapll_enable,
+ .disable = ti_fapll_disable,
+ .is_enabled = ti_fapll_is_enabled,
+ .recalc_rate = ti_fapll_recalc_rate,
+ .get_parent = ti_fapll_get_parent,
+};
+
+static int ti_fapll_synth_enable(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ v &= ~(1 << synth->index);
+ writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+
+ return 0;
+}
+
+static void ti_fapll_synth_disable(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ v |= 1 << synth->index;
+ writel_relaxed(v, synth->fd->base + FAPLL_PWD_OFFSET);
+}
+
+static int ti_fapll_synth_is_enabled(struct clk_hw *hw)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 v = readl_relaxed(synth->fd->base + FAPLL_PWD_OFFSET);
+
+ return !(v & (1 << synth->index));
+}
+
+/*
+ * See dm816x TRM chapter 1.10.3 Flying Adder PLL fore more info
+ */
+static unsigned long ti_fapll_synth_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct fapll_synth *synth = to_synth(hw);
+ u32 synth_div_m;
+ long long rate;
+
+ /* The audio_pll_clk1 is hardwired to produce 32.768KiHz clock */
+ if (!synth->div)
+ return 32768;
+
+ /*
+ * PLL in bypass sets the synths in bypass mode too. The PLL rate
+ * can be also be set to 27MHz, so we can't use parent_rate to
+ * check for bypass mode.
+ */
+ if (ti_fapll_clock_is_bypass(synth->fd))
+ return parent_rate;
+
+ rate = parent_rate;
+
+ /*
+ * Synth frequency integer and fractional divider.
+ * Note that the phase output K is 8, so the result needs
+ * to be multiplied by 8.
+ */
+ if (synth->freq) {
+ u32 v, synth_int_div, synth_frac_div, synth_div_freq;
+
+ v = readl_relaxed(synth->freq);
+ synth_int_div = (v >> 24) & 0xf;
+ synth_frac_div = v & 0xffffff;
+ synth_div_freq = (synth_int_div * 10000000) + synth_frac_div;
+ rate *= 10000000;
+ do_div(rate, synth_div_freq);
+ rate *= 8;
+ }
+
+ /* Synth ost-divider M */
+ synth_div_m = readl_relaxed(synth->div) & 0xff;
+ do_div(rate, synth_div_m);
+
+ return rate;
+}
+
+static struct clk_ops ti_fapll_synt_ops = {
+ .enable = ti_fapll_synth_enable,
+ .disable = ti_fapll_synth_disable,
+ .is_enabled = ti_fapll_synth_is_enabled,
+ .recalc_rate = ti_fapll_synth_recalc_rate,
+};
+
+static struct clk * __init ti_fapll_synth_setup(struct fapll_data *fd,
+ void __iomem *freq,
+ void __iomem *div,
+ int index,
+ const char *name,
+ const char *parent,
+ struct clk *pll_clk)
+{
+ struct clk_init_data *init;
+ struct fapll_synth *synth;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ return ERR_PTR(-ENOMEM);
+
+ init->ops = &ti_fapll_synt_ops;
+ init->name = name;
+ init->parent_names = &parent;
+ init->num_parents = 1;
+
+ synth = kzalloc(sizeof(*synth), GFP_KERNEL);
+ if (!synth)
+ goto free;
+
+ synth->fd = fd;
+ synth->index = index;
+ synth->freq = freq;
+ synth->div = div;
+ synth->name = name;
+ synth->hw.init = init;
+ synth->clk_pll = pll_clk;
+
+ return clk_register(NULL, &synth->hw);
+
+free:
+ kfree(synth);
+ kfree(init);
+
+ return ERR_PTR(-ENOMEM);
+}
+
+static void __init ti_fapll_setup(struct device_node *node)
+{
+ struct fapll_data *fd;
+ struct clk_init_data *init = NULL;
+ const char *parent_name[2];
+ struct clk *pll_clk;
+ int i;
+
+ fd = kzalloc(sizeof(*fd), GFP_KERNEL);
+ if (!fd)
+ return;
+
+ fd->outputs.clks = kzalloc(sizeof(struct clk *) *
+ MAX_FAPLL_OUTPUTS + 1,
+ GFP_KERNEL);
+ if (!fd->outputs.clks)
+ goto free;
+
+ init = kzalloc(sizeof(*init), GFP_KERNEL);
+ if (!init)
+ goto free;
+
+ init->ops = &ti_fapll_ops;
+ init->name = node->name;
+
+ init->num_parents = of_clk_get_parent_count(node);
+ if (init->num_parents != 2) {
+ pr_err("%s must have two parents\n", node->name);
+ goto free;
+ }
+
+ parent_name[0] = of_clk_get_parent_name(node, 0);
+ parent_name[1] = of_clk_get_parent_name(node, 1);
+ init->parent_names = parent_name;
+
+ fd->clk_ref = of_clk_get(node, 0);
+ if (IS_ERR(fd->clk_ref)) {
+ pr_err("%s could not get clk_ref\n", node->name);
+ goto free;
+ }
+
+ fd->clk_bypass = of_clk_get(node, 1);
+ if (IS_ERR(fd->clk_bypass)) {
+ pr_err("%s could not get clk_bypass\n", node->name);
+ goto free;
+ }
+
+ fd->base = of_iomap(node, 0);
+ if (!fd->base) {
+ pr_err("%s could not get IO base\n", node->name);
+ goto free;
+ }
+
+ if (fapll_is_ddr_pll(fd->base))
+ fd->bypass_bit_inverted = true;
+
+ fd->name = node->name;
+ fd->hw.init = init;
+
+ /* Register the parent PLL */
+ pll_clk = clk_register(NULL, &fd->hw);
+ if (IS_ERR(pll_clk))
+ goto unmap;
+
+ fd->outputs.clks[0] = pll_clk;
+ fd->outputs.clk_num++;
+
+ /*
+ * Set up the child synthesizers starting at index 1 as the
+ * PLL output is at index 0. We need to check the clock-indices
+ * for numbering in case there are holes in the synth mapping,
+ * and then probe the synth register to see if it has a FREQ
+ * register available.
+ */
+ for (i = 0; i < MAX_FAPLL_OUTPUTS; i++) {
+ const char *output_name;
+ void __iomem *freq, *div;
+ struct clk *synth_clk;
+ int output_instance;
+ u32 v;
+
+ if (of_property_read_string_index(node, "clock-output-names",
+ i, &output_name))
+ continue;
+
+ if (of_property_read_u32_index(node, "clock-indices", i,
+ &output_instance))
+ output_instance = i;
+
+ freq = fd->base + (output_instance * 8);
+ div = freq + 4;
+
+ /* Check for hardwired audio_pll_clk1 */
+ if (is_audio_pll_clk1(freq)) {
+ freq = 0;
+ div = 0;
+ } else {
+ /* Does the synthesizer have a FREQ register? */
+ v = readl_relaxed(freq);
+ if (!v)
+ freq = 0;
+ }
+ synth_clk = ti_fapll_synth_setup(fd, freq, div, output_instance,
+ output_name, node->name,
+ pll_clk);
+ if (IS_ERR(synth_clk))
+ continue;
+
+ fd->outputs.clks[output_instance] = synth_clk;
+ fd->outputs.clk_num++;
+
+ clk_register_clkdev(synth_clk, output_name, NULL);
+ }
+
+ /* Register the child synthesizers as the FAPLL outputs */
+ of_clk_add_provider(node, of_clk_src_onecell_get, &fd->outputs);
+ /* Add clock alias for the outputs */
+
+ kfree(init);
+
+ return;
+
+unmap:
+ iounmap(fd->base);
+free:
+ if (fd->clk_bypass)
+ clk_put(fd->clk_bypass);
+ if (fd->clk_ref)
+ clk_put(fd->clk_ref);
+ kfree(fd->outputs.clks);
+ kfree(fd);
+ kfree(init);
+}
+
+CLK_OF_DECLARE(ti_fapll_clock, "ti,dm816-fapll-clock", ti_fapll_setup);
diff --git a/drivers/clk/ti/gate.c b/drivers/clk/ti/gate.c
index b326d2797feb..d493307b73f4 100644
--- a/drivers/clk/ti/gate.c
+++ b/drivers/clk/ti/gate.c
@@ -22,6 +22,8 @@
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
+
#define to_clk_divider(_hw) container_of(_hw, struct clk_divider, hw)
#undef pr_fmt
@@ -90,63 +92,164 @@ static int omap36xx_gate_clk_enable_with_hsdiv_restore(struct clk_hw *clk)
return ret;
}
-static void __init _of_ti_gate_clk_setup(struct device_node *node,
- const struct clk_ops *ops,
- const struct clk_hw_omap_ops *hw_ops)
+static struct clk *_register_gate(struct device *dev, const char *name,
+ const char *parent_name, unsigned long flags,
+ void __iomem *reg, u8 bit_idx,
+ u8 clk_gate_flags, const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
{
- struct clk *clk;
struct clk_init_data init = { NULL };
struct clk_hw_omap *clk_hw;
- const char *clk_name = node->name;
- const char *parent_name;
- u32 val;
+ struct clk *clk;
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
if (!clk_hw)
- return;
+ return ERR_PTR(-ENOMEM);
clk_hw->hw.init = &init;
- init.name = clk_name;
+ init.name = name;
init.ops = ops;
- if (ops != &omap_gate_clkdm_clk_ops) {
- clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
- if (!clk_hw->enable_reg)
- goto cleanup;
+ clk_hw->enable_reg = reg;
+ clk_hw->enable_bit = bit_idx;
+ clk_hw->ops = hw_ops;
- if (!of_property_read_u32(node, "ti,bit-shift", &val))
- clk_hw->enable_bit = val;
+ clk_hw->flags = MEMMAP_ADDRESSING | clk_gate_flags;
+
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ init.flags = flags;
+
+ clk = clk_register(NULL, &clk_hw->hw);
+
+ if (IS_ERR(clk))
+ kfree(clk_hw);
+
+ return clk;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_gate(struct ti_clk *setup)
+{
+ const struct clk_ops *ops = &omap_gate_clk_ops;
+ const struct clk_hw_omap_ops *hw_ops = NULL;
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+ u32 flags = 0;
+ u8 clk_gate_flags = 0;
+ struct ti_clk_gate *gate;
+
+ gate = setup->data;
+
+ if (gate->flags & CLKF_INTERFACE)
+ return ti_clk_register_interface(setup);
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ if (gate->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ if (gate->flags & CLKF_SET_BIT_TO_DISABLE)
+ clk_gate_flags |= INVERT_ENABLE;
+
+ if (gate->flags & CLKF_HSDIV) {
+ ops = &omap_gate_clk_hsdiv_restore_ops;
+ hw_ops = &clkhwops_wait;
}
- clk_hw->ops = hw_ops;
+ if (gate->flags & CLKF_DSS)
+ hw_ops = &clkhwops_omap3430es2_dss_usbhost_wait;
+
+ if (gate->flags & CLKF_WAIT)
+ hw_ops = &clkhwops_wait;
+
+ if (gate->flags & CLKF_CLKDM)
+ ops = &omap_gate_clkdm_clk_ops;
+
+ if (gate->flags & CLKF_AM35XX)
+ hw_ops = &clkhwops_am35xx_ipss_module_wait;
- clk_hw->flags = MEMMAP_ADDRESSING;
+ reg_setup->index = gate->module;
+ reg_setup->offset = gate->reg;
+
+ return _register_gate(NULL, setup->name, gate->parent, flags,
+ (void __iomem *)reg, gate->bit_shift,
+ clk_gate_flags, ops, hw_ops);
+}
+
+struct clk_hw *ti_clk_build_component_gate(struct ti_clk_gate *setup)
+{
+ struct clk_hw_omap *gate;
+ struct clk_omap_reg *reg;
+ const struct clk_hw_omap_ops *ops = &clkhwops_wait;
+
+ if (!setup)
+ return NULL;
+
+ gate = kzalloc(sizeof(*gate), GFP_KERNEL);
+ if (!gate)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&gate->enable_reg;
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ gate->enable_bit = setup->bit_shift;
+
+ if (setup->flags & CLKF_NO_WAIT)
+ ops = NULL;
+
+ if (setup->flags & CLKF_INTERFACE)
+ ops = &clkhwops_iclk_wait;
+
+ gate->ops = ops;
+ gate->flags = MEMMAP_ADDRESSING;
+
+ return &gate->hw;
+}
+#endif
+
+static void __init _of_ti_gate_clk_setup(struct device_node *node,
+ const struct clk_ops *ops,
+ const struct clk_hw_omap_ops *hw_ops)
+{
+ struct clk *clk;
+ const char *parent_name;
+ void __iomem *reg = NULL;
+ u8 enable_bit = 0;
+ u32 val;
+ u32 flags = 0;
+ u8 clk_gate_flags = 0;
+
+ if (ops != &omap_gate_clkdm_clk_ops) {
+ reg = ti_clk_get_reg_addr(node, 0);
+ if (!reg)
+ return;
+
+ if (!of_property_read_u32(node, "ti,bit-shift", &val))
+ enable_bit = val;
+ }
if (of_clk_get_parent_count(node) != 1) {
- pr_err("%s must have 1 parent\n", clk_name);
- goto cleanup;
+ pr_err("%s must have 1 parent\n", node->name);
+ return;
}
parent_name = of_clk_get_parent_name(node, 0);
- init.parent_names = &parent_name;
- init.num_parents = 1;
if (of_property_read_bool(node, "ti,set-rate-parent"))
- init.flags |= CLK_SET_RATE_PARENT;
+ flags |= CLK_SET_RATE_PARENT;
if (of_property_read_bool(node, "ti,set-bit-to-disable"))
- clk_hw->flags |= INVERT_ENABLE;
+ clk_gate_flags |= INVERT_ENABLE;
- clk = clk_register(NULL, &clk_hw->hw);
+ clk = _register_gate(NULL, node->name, parent_name, flags, reg,
+ enable_bit, clk_gate_flags, ops, hw_ops);
- if (!IS_ERR(clk)) {
+ if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
- return;
- }
-
-cleanup:
- kfree(clk_hw);
}
static void __init
diff --git a/drivers/clk/ti/interface.c b/drivers/clk/ti/interface.c
index 9c3e8c4aaa40..265d91f071c5 100644
--- a/drivers/clk/ti/interface.c
+++ b/drivers/clk/ti/interface.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -31,53 +32,102 @@ static const struct clk_ops ti_interface_clk_ops = {
.is_enabled = &omap2_dflt_clk_is_enabled,
};
-static void __init _of_ti_interface_clk_setup(struct device_node *node,
- const struct clk_hw_omap_ops *ops)
+static struct clk *_register_interface(struct device *dev, const char *name,
+ const char *parent_name,
+ void __iomem *reg, u8 bit_idx,
+ const struct clk_hw_omap_ops *ops)
{
- struct clk *clk;
struct clk_init_data init = { NULL };
struct clk_hw_omap *clk_hw;
- const char *parent_name;
- u32 val;
+ struct clk *clk;
clk_hw = kzalloc(sizeof(*clk_hw), GFP_KERNEL);
if (!clk_hw)
- return;
+ return ERR_PTR(-ENOMEM);
clk_hw->hw.init = &init;
clk_hw->ops = ops;
clk_hw->flags = MEMMAP_ADDRESSING;
+ clk_hw->enable_reg = reg;
+ clk_hw->enable_bit = bit_idx;
- clk_hw->enable_reg = ti_clk_get_reg_addr(node, 0);
- if (!clk_hw->enable_reg)
- goto cleanup;
-
- if (!of_property_read_u32(node, "ti,bit-shift", &val))
- clk_hw->enable_bit = val;
-
- init.name = node->name;
+ init.name = name;
init.ops = &ti_interface_clk_ops;
init.flags = 0;
- parent_name = of_clk_get_parent_name(node, 0);
- if (!parent_name) {
- pr_err("%s must have a parent\n", node->name);
- goto cleanup;
- }
-
init.num_parents = 1;
init.parent_names = &parent_name;
clk = clk_register(NULL, &clk_hw->hw);
- if (!IS_ERR(clk)) {
- of_clk_add_provider(node, of_clk_src_simple_get, clk);
+ if (IS_ERR(clk))
+ kfree(clk_hw);
+ else
omap2_init_clk_hw_omap_clocks(clk);
+
+ return clk;
+}
+
+#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_ATAGS)
+struct clk *ti_clk_register_interface(struct ti_clk *setup)
+{
+ const struct clk_hw_omap_ops *ops = &clkhwops_iclk_wait;
+ u32 reg;
+ struct clk_omap_reg *reg_setup;
+ struct ti_clk_gate *gate;
+
+ gate = setup->data;
+ reg_setup = (struct clk_omap_reg *)&reg;
+ reg_setup->index = gate->module;
+ reg_setup->offset = gate->reg;
+
+ if (gate->flags & CLKF_NO_WAIT)
+ ops = &clkhwops_iclk;
+
+ if (gate->flags & CLKF_HSOTGUSB)
+ ops = &clkhwops_omap3430es2_iclk_hsotgusb_wait;
+
+ if (gate->flags & CLKF_DSS)
+ ops = &clkhwops_omap3430es2_iclk_dss_usbhost_wait;
+
+ if (gate->flags & CLKF_SSI)
+ ops = &clkhwops_omap3430es2_iclk_ssi_wait;
+
+ if (gate->flags & CLKF_AM35XX)
+ ops = &clkhwops_am35xx_ipss_wait;
+
+ return _register_interface(NULL, setup->name, gate->parent,
+ (void __iomem *)reg, gate->bit_shift, ops);
+}
+#endif
+
+static void __init _of_ti_interface_clk_setup(struct device_node *node,
+ const struct clk_hw_omap_ops *ops)
+{
+ struct clk *clk;
+ const char *parent_name;
+ void __iomem *reg;
+ u8 enable_bit = 0;
+ u32 val;
+
+ reg = ti_clk_get_reg_addr(node, 0);
+ if (!reg)
+ return;
+
+ if (!of_property_read_u32(node, "ti,bit-shift", &val))
+ enable_bit = val;
+
+ parent_name = of_clk_get_parent_name(node, 0);
+ if (!parent_name) {
+ pr_err("%s must have a parent\n", node->name);
return;
}
-cleanup:
- kfree(clk_hw);
+ clk = _register_interface(NULL, node->name, parent_name, reg,
+ enable_bit, ops);
+
+ if (!IS_ERR(clk))
+ of_clk_add_provider(node, of_clk_src_simple_get, clk);
}
static void __init of_ti_interface_clk_setup(struct device_node *node)
diff --git a/drivers/clk/ti/mux.c b/drivers/clk/ti/mux.c
index e9d650e51287..728e253606bc 100644
--- a/drivers/clk/ti/mux.c
+++ b/drivers/clk/ti/mux.c
@@ -21,6 +21,7 @@
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/clk/ti.h>
+#include "clock.h"
#undef pr_fmt
#define pr_fmt(fmt) "%s: " fmt, __func__
@@ -144,6 +145,39 @@ static struct clk *_register_mux(struct device *dev, const char *name,
return clk;
}
+struct clk *ti_clk_register_mux(struct ti_clk *setup)
+{
+ struct ti_clk_mux *mux;
+ u32 flags;
+ u8 mux_flags = 0;
+ struct clk_omap_reg *reg_setup;
+ u32 reg;
+ u32 mask;
+
+ reg_setup = (struct clk_omap_reg *)&reg;
+
+ mux = setup->data;
+ flags = CLK_SET_RATE_NO_REPARENT;
+
+ mask = mux->num_parents;
+ if (!(mux->flags & CLKF_INDEX_STARTS_AT_ONE))
+ mask--;
+
+ mask = (1 << fls(mask)) - 1;
+ reg_setup->index = mux->module;
+ reg_setup->offset = mux->reg;
+
+ if (mux->flags & CLKF_INDEX_STARTS_AT_ONE)
+ mux_flags |= CLK_MUX_INDEX_ONE;
+
+ if (mux->flags & CLKF_SET_RATE_PARENT)
+ flags |= CLK_SET_RATE_PARENT;
+
+ return _register_mux(NULL, setup->name, mux->parents, mux->num_parents,
+ flags, (void __iomem *)reg, mux->bit_shift, mask,
+ mux_flags, NULL, NULL);
+}
+
/**
* of_mux_clk_setup - Setup function for simple mux rate clock
* @node: DT node for the clock
@@ -194,8 +228,9 @@ static void of_mux_clk_setup(struct device_node *node)
mask = (1 << fls(mask)) - 1;
- clk = _register_mux(NULL, node->name, parent_names, num_parents, flags,
- reg, shift, mask, clk_mux_flags, NULL, NULL);
+ clk = _register_mux(NULL, node->name, parent_names, num_parents,
+ flags, reg, shift, mask, clk_mux_flags, NULL,
+ NULL);
if (!IS_ERR(clk))
of_clk_add_provider(node, of_clk_src_simple_get, clk);
@@ -205,6 +240,37 @@ cleanup:
}
CLK_OF_DECLARE(mux_clk, "ti,mux-clock", of_mux_clk_setup);
+struct clk_hw *ti_clk_build_component_mux(struct ti_clk_mux *setup)
+{
+ struct clk_mux *mux;
+ struct clk_omap_reg *reg;
+ int num_parents;
+
+ if (!setup)
+ return NULL;
+
+ mux = kzalloc(sizeof(*mux), GFP_KERNEL);
+ if (!mux)
+ return ERR_PTR(-ENOMEM);
+
+ reg = (struct clk_omap_reg *)&mux->reg;
+
+ mux->shift = setup->bit_shift;
+
+ reg->index = setup->module;
+ reg->offset = setup->reg;
+
+ if (setup->flags & CLKF_INDEX_STARTS_AT_ONE)
+ mux->flags |= CLK_MUX_INDEX_ONE;
+
+ num_parents = setup->num_parents;
+
+ mux->mask = num_parents - 1;
+ mux->mask = (1 << fls(mux->mask)) - 1;
+
+ return &mux->hw;
+}
+
static void __init of_ti_composite_mux_clk_setup(struct device_node *node)
{
struct clk_mux *mux;
diff --git a/drivers/clk/ux500/clk-prcc.c b/drivers/clk/ux500/clk-prcc.c
index bd4769a84485..0e950769ed03 100644
--- a/drivers/clk/ux500/clk-prcc.c
+++ b/drivers/clk/ux500/clk-prcc.c
@@ -8,7 +8,6 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clk-private.h>
#include <linux/slab.h>
#include <linux/io.h>
#include <linux/err.h>
diff --git a/drivers/clk/ux500/clk-prcmu.c b/drivers/clk/ux500/clk-prcmu.c
index e2d63bc47436..bf63c96acb1a 100644
--- a/drivers/clk/ux500/clk-prcmu.c
+++ b/drivers/clk/ux500/clk-prcmu.c
@@ -8,7 +8,6 @@
*/
#include <linux/clk-provider.h>
-#include <linux/clk-private.h>
#include <linux/mfd/dbx500-prcmu.h>
#include <linux/slab.h>
#include <linux/io.h>
diff --git a/drivers/clk/zynq/clkc.c b/drivers/clk/zynq/clkc.c
index 9037bebd69f7..f870aad57711 100644
--- a/drivers/clk/zynq/clkc.c
+++ b/drivers/clk/zynq/clkc.c
@@ -303,6 +303,7 @@ static void __init zynq_clk_setup(struct device_node *np)
clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x],
"cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL,
26, 0, &armclk_lock);
+ clk_prepare_enable(clks[cpu_2x]);
clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1,
4 + 2 * tmp);
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index fc01ec27d3c8..68161f7a07d6 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -18,6 +18,9 @@ config CLKBLD_I8253
config CLKSRC_MMIO
bool
+config DIGICOLOR_TIMER
+ bool
+
config DW_APB_TIMER
bool
@@ -26,6 +29,10 @@ config DW_APB_TIMER_OF
select DW_APB_TIMER
select CLKSRC_OF
+config ROCKCHIP_TIMER
+ bool
+ select CLKSRC_OF
+
config ARMADA_370_XP_TIMER
bool
select CLKSRC_OF
@@ -47,12 +54,20 @@ config SUN5I_HSTIMER
select CLKSRC_MMIO
bool
+config TEGRA_TIMER
+ bool
+
config VT8500_TIMER
bool
config CADENCE_TTC_TIMER
bool
+config ASM9260_TIMER
+ bool
+ select CLKSRC_MMIO
+ select CLKSRC_OF
+
config CLKSRC_NOMADIK_MTU
bool
depends on (ARCH_NOMADIK || ARCH_U8500)
@@ -229,4 +244,10 @@ config CLKSRC_MIPS_GIC
depends on MIPS_GIC
select CLKSRC_OF
+config CLKSRC_PXA
+ def_bool y if ARCH_PXA || ARCH_SA1100
+ select CLKSRC_OF if USE_OF
+ help
+ This enables OST0 support available on PXA and SA-11x0
+ platforms.
endmenu
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 94d90b24b56b..752d5c70b0ef 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -10,24 +10,26 @@ obj-$(CONFIG_SH_TIMER_TMU) += sh_tmu.o
obj-$(CONFIG_EM_TIMER_STI) += em_sti.o
obj-$(CONFIG_CLKBLD_I8253) += i8253.o
obj-$(CONFIG_CLKSRC_MMIO) += mmio.o
+obj-$(CONFIG_DIGICOLOR_TIMER) += timer-digicolor.o
obj-$(CONFIG_DW_APB_TIMER) += dw_apb_timer.o
obj-$(CONFIG_DW_APB_TIMER_OF) += dw_apb_timer_of.o
+obj-$(CONFIG_ROCKCHIP_TIMER) += rockchip_timer.o
obj-$(CONFIG_CLKSRC_NOMADIK_MTU) += nomadik-mtu.o
obj-$(CONFIG_CLKSRC_DBX500_PRCMU) += clksrc-dbx500-prcmu.o
obj-$(CONFIG_ARMADA_370_XP_TIMER) += time-armada-370-xp.o
obj-$(CONFIG_ORION_TIMER) += time-orion.o
obj-$(CONFIG_ARCH_BCM2835) += bcm2835_timer.o
obj-$(CONFIG_ARCH_CLPS711X) += clps711x-timer.o
-obj-$(CONFIG_ARCH_MARCO) += timer-marco.o
+obj-$(CONFIG_ARCH_ATLAS7) += timer-atlas7.o
obj-$(CONFIG_ARCH_MOXART) += moxart_timer.o
obj-$(CONFIG_ARCH_MXS) += mxs_timer.o
-obj-$(CONFIG_ARCH_PXA) += pxa_timer.o
+obj-$(CONFIG_CLKSRC_PXA) += pxa_timer.o
obj-$(CONFIG_ARCH_PRIMA2) += timer-prima2.o
obj-$(CONFIG_ARCH_U300) += timer-u300.o
obj-$(CONFIG_SUN4I_TIMER) += sun4i_timer.o
obj-$(CONFIG_SUN5I_HSTIMER) += timer-sun5i.o
obj-$(CONFIG_MESON6_TIMER) += meson6_timer.o
-obj-$(CONFIG_ARCH_TEGRA) += tegra20_timer.o
+obj-$(CONFIG_TEGRA_TIMER) += tegra20_timer.o
obj-$(CONFIG_VT8500_TIMER) += vt8500_timer.o
obj-$(CONFIG_ARCH_NSPIRE) += zevio-timer.o
obj-$(CONFIG_ARCH_BCM_MOBILE) += bcm_kona_timer.o
@@ -48,3 +50,4 @@ obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
obj-$(CONFIG_CLKSRC_MIPS_GIC) += mips-gic-timer.o
+obj-$(CONFIG_ASM9260_TIMER) += asm9260_timer.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 095c1774592c..a3025e7ae35f 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -15,6 +15,7 @@
#include <linux/cpu.h>
#include <linux/cpu_pm.h>
#include <linux/clockchips.h>
+#include <linux/clocksource.h>
#include <linux/interrupt.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
diff --git a/drivers/clocksource/asm9260_timer.c b/drivers/clocksource/asm9260_timer.c
new file mode 100644
index 000000000000..2c9c993727c8
--- /dev/null
+++ b/drivers/clocksource/asm9260_timer.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2014 Oleksij Rempel <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
+ * 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/interrupt.h>
+#include <linux/sched.h>
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/clockchips.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/bitops.h>
+
+#define DRIVER_NAME "asm9260-timer"
+
+/*
+ * this device provide 4 offsets for each register:
+ * 0x0 - plain read write mode
+ * 0x4 - set mode, OR logic.
+ * 0x8 - clr mode, XOR logic.
+ * 0xc - togle mode.
+ */
+#define SET_REG 4
+#define CLR_REG 8
+
+#define HW_IR 0x0000 /* RW. Interrupt */
+#define BM_IR_CR0 BIT(4)
+#define BM_IR_MR3 BIT(3)
+#define BM_IR_MR2 BIT(2)
+#define BM_IR_MR1 BIT(1)
+#define BM_IR_MR0 BIT(0)
+
+#define HW_TCR 0x0010 /* RW. Timer controller */
+/* BM_C*_RST
+ * Timer Counter and the Prescale Counter are synchronously reset on the
+ * next positive edge of PCLK. The counters remain reset until TCR[1] is
+ * returned to zero. */
+#define BM_C3_RST BIT(7)
+#define BM_C2_RST BIT(6)
+#define BM_C1_RST BIT(5)
+#define BM_C0_RST BIT(4)
+/* BM_C*_EN
+ * 1 - Timer Counter and Prescale Counter are enabled for counting
+ * 0 - counters are disabled */
+#define BM_C3_EN BIT(3)
+#define BM_C2_EN BIT(2)
+#define BM_C1_EN BIT(1)
+#define BM_C0_EN BIT(0)
+
+#define HW_DIR 0x0020 /* RW. Direction? */
+/* 00 - count up
+ * 01 - count down
+ * 10 - ?? 2^n/2 */
+#define BM_DIR_COUNT_UP 0
+#define BM_DIR_COUNT_DOWN 1
+#define BM_DIR0_SHIFT 0
+#define BM_DIR1_SHIFT 4
+#define BM_DIR2_SHIFT 8
+#define BM_DIR3_SHIFT 12
+#define BM_DIR_DEFAULT (BM_DIR_COUNT_UP << BM_DIR0_SHIFT | \
+ BM_DIR_COUNT_UP << BM_DIR1_SHIFT | \
+ BM_DIR_COUNT_UP << BM_DIR2_SHIFT | \
+ BM_DIR_COUNT_UP << BM_DIR3_SHIFT)
+
+#define HW_TC0 0x0030 /* RO. Timer counter 0 */
+/* HW_TC*. Timer counter owerflow (0xffff.ffff to 0x0000.0000) do not generate
+ * interrupt. This registers can be used to detect overflow */
+#define HW_TC1 0x0040
+#define HW_TC2 0x0050
+#define HW_TC3 0x0060
+
+#define HW_PR 0x0070 /* RW. prescaler */
+#define BM_PR_DISABLE 0
+#define HW_PC 0x0080 /* RO. Prescaler counter */
+#define HW_MCR 0x0090 /* RW. Match control */
+/* enable interrupt on match */
+#define BM_MCR_INT_EN(n) (1 << (n * 3 + 0))
+/* enable TC reset on match */
+#define BM_MCR_RES_EN(n) (1 << (n * 3 + 1))
+/* enable stop TC on match */
+#define BM_MCR_STOP_EN(n) (1 << (n * 3 + 2))
+
+#define HW_MR0 0x00a0 /* RW. Match reg */
+#define HW_MR1 0x00b0
+#define HW_MR2 0x00C0
+#define HW_MR3 0x00D0
+
+#define HW_CTCR 0x0180 /* Counter control */
+#define BM_CTCR0_SHIFT 0
+#define BM_CTCR1_SHIFT 2
+#define BM_CTCR2_SHIFT 4
+#define BM_CTCR3_SHIFT 6
+#define BM_CTCR_TM 0 /* Timer mode. Every rising PCLK edge. */
+#define BM_CTCR_DEFAULT (BM_CTCR_TM << BM_CTCR0_SHIFT | \
+ BM_CTCR_TM << BM_CTCR1_SHIFT | \
+ BM_CTCR_TM << BM_CTCR2_SHIFT | \
+ BM_CTCR_TM << BM_CTCR3_SHIFT)
+
+static struct asm9260_timer_priv {
+ void __iomem *base;
+ unsigned long ticks_per_jiffy;
+} priv;
+
+static int asm9260_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ /* configure match count for TC0 */
+ writel_relaxed(delta, priv.base + HW_MR0);
+ /* enable TC0 */
+ writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
+ return 0;
+}
+
+static void asm9260_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ /* stop timer0 */
+ writel_relaxed(BM_C0_EN, priv.base + HW_TCR + CLR_REG);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* disable reset and stop on match */
+ writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
+ priv.base + HW_MCR + CLR_REG);
+ /* configure match count for TC0 */
+ writel_relaxed(priv.ticks_per_jiffy, priv.base + HW_MR0);
+ /* enable TC0 */
+ writel_relaxed(BM_C0_EN, priv.base + HW_TCR + SET_REG);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* enable reset and stop on match */
+ writel_relaxed(BM_MCR_RES_EN(0) | BM_MCR_STOP_EN(0),
+ priv.base + HW_MCR + SET_REG);
+ break;
+ default:
+ break;
+ }
+}
+
+static struct clock_event_device event_dev = {
+ .name = DRIVER_NAME,
+ .rating = 200,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_next_event = asm9260_timer_set_next_event,
+ .set_mode = asm9260_timer_set_mode,
+};
+
+static irqreturn_t asm9260_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ evt->event_handler(evt);
+
+ writel_relaxed(BM_IR_MR0, priv.base + HW_IR);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * ---------------------------------------------------------------------------
+ * Timer initialization
+ * ---------------------------------------------------------------------------
+ */
+static void __init asm9260_timer_init(struct device_node *np)
+{
+ int irq;
+ struct clk *clk;
+ int ret;
+ unsigned long rate;
+
+ priv.base = of_io_request_and_map(np, 0, np->name);
+ if (!priv.base)
+ panic("%s: unable to map resource", np->name);
+
+ clk = of_clk_get(np, 0);
+
+ ret = clk_prepare_enable(clk);
+ if (ret)
+ panic("Failed to enable clk!\n");
+
+ irq = irq_of_parse_and_map(np, 0);
+ ret = request_irq(irq, asm9260_timer_interrupt, IRQF_TIMER,
+ DRIVER_NAME, &event_dev);
+ if (ret)
+ panic("Failed to setup irq!\n");
+
+ /* set all timers for count-up */
+ writel_relaxed(BM_DIR_DEFAULT, priv.base + HW_DIR);
+ /* disable divider */
+ writel_relaxed(BM_PR_DISABLE, priv.base + HW_PR);
+ /* make sure all timers use every rising PCLK edge. */
+ writel_relaxed(BM_CTCR_DEFAULT, priv.base + HW_CTCR);
+ /* enable interrupt for TC0 and clean setting for all other lines */
+ writel_relaxed(BM_MCR_INT_EN(0) , priv.base + HW_MCR);
+
+ rate = clk_get_rate(clk);
+ clocksource_mmio_init(priv.base + HW_TC1, DRIVER_NAME, rate,
+ 200, 32, clocksource_mmio_readl_up);
+
+ /* Seems like we can't use counter without match register even if
+ * actions for MR are disabled. So, set MR to max value. */
+ writel_relaxed(0xffffffff, priv.base + HW_MR1);
+ /* enable TC1 */
+ writel_relaxed(BM_C1_EN, priv.base + HW_TCR + SET_REG);
+
+ priv.ticks_per_jiffy = DIV_ROUND_CLOSEST(rate, HZ);
+ event_dev.cpumask = cpumask_of(0);
+ clockevents_config_and_register(&event_dev, rate, 0x2c00, 0xfffffffe);
+}
+CLOCKSOURCE_OF_DECLARE(asm9260_timer, "alphascale,asm9260-timer",
+ asm9260_timer_init);
diff --git a/drivers/clocksource/mtk_timer.c b/drivers/clocksource/mtk_timer.c
index 32a3d25795d3..68ab42356d0e 100644
--- a/drivers/clocksource/mtk_timer.c
+++ b/drivers/clocksource/mtk_timer.c
@@ -224,6 +224,8 @@ static void __init mtk_timer_init(struct device_node *node)
}
rate = clk_get_rate(clk);
+ mtk_timer_global_reset(evt);
+
if (request_irq(evt->dev.irq, mtk_timer_interrupt,
IRQF_TIMER | IRQF_IRQPOLL, "mtk_timer", evt)) {
pr_warn("failed to setup irq %d\n", evt->dev.irq);
@@ -232,8 +234,6 @@ static void __init mtk_timer_init(struct device_node *node)
evt->ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
- mtk_timer_global_reset(evt);
-
/* Configure clock source */
mtk_timer_setup(evt, GPT_CLK_SRC, TIMER_CTRL_OP_FREERUN);
clocksource_mmio_init(evt->gpt_base + TIMER_CNT_REG(GPT_CLK_SRC),
@@ -241,10 +241,11 @@ static void __init mtk_timer_init(struct device_node *node)
/* Configure clock event */
mtk_timer_setup(evt, GPT_CLK_EVT, TIMER_CTRL_OP_REPEAT);
- mtk_timer_enable_irq(evt, GPT_CLK_EVT);
-
clockevents_config_and_register(&evt->dev, rate, 0x3,
0xffffffff);
+
+ mtk_timer_enable_irq(evt, GPT_CLK_EVT);
+
return;
err_clk_disable:
diff --git a/drivers/clocksource/pxa_timer.c b/drivers/clocksource/pxa_timer.c
index 941f3f344e08..d9438af2bbd6 100644
--- a/drivers/clocksource/pxa_timer.c
+++ b/drivers/clocksource/pxa_timer.c
@@ -163,7 +163,7 @@ static struct irqaction pxa_ost0_irq = {
.dev_id = &ckevt_pxa_osmr0,
};
-static void pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
+static void __init pxa_timer_common_init(int irq, unsigned long clock_tick_rate)
{
timer_writel(0, OIER);
timer_writel(OSSR_M0 | OSSR_M1 | OSSR_M2 | OSSR_M3, OSSR);
diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
new file mode 100644
index 000000000000..a35993bafb20
--- /dev/null
+++ b/drivers/clocksource/rockchip_timer.c
@@ -0,0 +1,180 @@
+/*
+ * Rockchip timer support
+ *
+ * Copyright (C) Daniel Lezcano <daniel.lezcano@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/clk.h>
+#include <linux/clockchips.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#define TIMER_NAME "rk_timer"
+
+#define TIMER_LOAD_COUNT0 0x00
+#define TIMER_LOAD_COUNT1 0x04
+#define TIMER_CONTROL_REG 0x10
+#define TIMER_INT_STATUS 0x18
+
+#define TIMER_DISABLE 0x0
+#define TIMER_ENABLE 0x1
+#define TIMER_MODE_FREE_RUNNING (0 << 1)
+#define TIMER_MODE_USER_DEFINED_COUNT (1 << 1)
+#define TIMER_INT_UNMASK (1 << 2)
+
+struct bc_timer {
+ struct clock_event_device ce;
+ void __iomem *base;
+ u32 freq;
+};
+
+static struct bc_timer bc_timer;
+
+static inline struct bc_timer *rk_timer(struct clock_event_device *ce)
+{
+ return container_of(ce, struct bc_timer, ce);
+}
+
+static inline void __iomem *rk_base(struct clock_event_device *ce)
+{
+ return rk_timer(ce)->base;
+}
+
+static inline void rk_timer_disable(struct clock_event_device *ce)
+{
+ writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
+ dsb();
+}
+
+static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
+{
+ writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
+ rk_base(ce) + TIMER_CONTROL_REG);
+ dsb();
+}
+
+static void rk_timer_update_counter(unsigned long cycles,
+ struct clock_event_device *ce)
+{
+ writel_relaxed(cycles, rk_base(ce) + TIMER_LOAD_COUNT0);
+ writel_relaxed(0, rk_base(ce) + TIMER_LOAD_COUNT1);
+ dsb();
+}
+
+static void rk_timer_interrupt_clear(struct clock_event_device *ce)
+{
+ writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
+ dsb();
+}
+
+static inline int rk_timer_set_next_event(unsigned long cycles,
+ struct clock_event_device *ce)
+{
+ rk_timer_disable(ce);
+ rk_timer_update_counter(cycles, ce);
+ rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
+ return 0;
+}
+
+static inline void rk_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *ce)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ rk_timer_disable(ce);
+ rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
+ rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ rk_timer_disable(ce);
+ break;
+ }
+}
+
+static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *ce = dev_id;
+
+ rk_timer_interrupt_clear(ce);
+
+ if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
+ rk_timer_disable(ce);
+
+ ce->event_handler(ce);
+
+ return IRQ_HANDLED;
+}
+
+static void __init rk_timer_init(struct device_node *np)
+{
+ struct clock_event_device *ce = &bc_timer.ce;
+ struct clk *timer_clk;
+ struct clk *pclk;
+ int ret, irq;
+
+ bc_timer.base = of_iomap(np, 0);
+ if (!bc_timer.base) {
+ pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
+ return;
+ }
+
+ pclk = of_clk_get_by_name(np, "pclk");
+ if (IS_ERR(pclk)) {
+ pr_err("Failed to get pclk for '%s'\n", TIMER_NAME);
+ return;
+ }
+
+ if (clk_prepare_enable(pclk)) {
+ pr_err("Failed to enable pclk for '%s'\n", TIMER_NAME);
+ return;
+ }
+
+ timer_clk = of_clk_get_by_name(np, "timer");
+ if (IS_ERR(timer_clk)) {
+ pr_err("Failed to get timer clock for '%s'\n", TIMER_NAME);
+ return;
+ }
+
+ if (clk_prepare_enable(timer_clk)) {
+ pr_err("Failed to enable timer clock\n");
+ return;
+ }
+
+ bc_timer.freq = clk_get_rate(timer_clk);
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (irq == NO_IRQ) {
+ pr_err("Failed to map interrupts for '%s'\n", TIMER_NAME);
+ return;
+ }
+
+ ce->name = TIMER_NAME;
+ ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+ ce->set_next_event = rk_timer_set_next_event;
+ ce->set_mode = rk_timer_set_mode;
+ ce->irq = irq;
+ ce->cpumask = cpumask_of(0);
+ ce->rating = 250;
+
+ rk_timer_interrupt_clear(ce);
+ rk_timer_disable(ce);
+
+ ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
+ if (ret) {
+ pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
+ return;
+ }
+
+ clockevents_config_and_register(ce, bc_timer.freq, 1, UINT_MAX);
+}
+CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
diff --git a/drivers/clocksource/timer-atlas7.c b/drivers/clocksource/timer-atlas7.c
new file mode 100644
index 000000000000..60f9de3438b0
--- /dev/null
+++ b/drivers/clocksource/timer-atlas7.c
@@ -0,0 +1,306 @@
+/*
+ * System timer for CSR SiRFprimaII
+ *
+ * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
+ *
+ * Licensed under GPLv2 or later.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/cpu.h>
+#include <linux/bitops.h>
+#include <linux/irq.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/of.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/sched_clock.h>
+
+#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
+#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
+#define SIRFSOC_TIMER_MATCH_0 0x0018
+#define SIRFSOC_TIMER_MATCH_1 0x001c
+#define SIRFSOC_TIMER_COUNTER_0 0x0048
+#define SIRFSOC_TIMER_COUNTER_1 0x004c
+#define SIRFSOC_TIMER_INTR_STATUS 0x0060
+#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064
+#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068
+#define SIRFSOC_TIMER_64COUNTER_LO 0x006c
+#define SIRFSOC_TIMER_64COUNTER_HI 0x0070
+#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074
+#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078
+#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c
+#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080
+
+#define SIRFSOC_TIMER_REG_CNT 6
+
+static unsigned long atlas7_timer_rate;
+
+static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
+ SIRFSOC_TIMER_WATCHDOG_EN,
+ SIRFSOC_TIMER_32COUNTER_0_CTRL,
+ SIRFSOC_TIMER_32COUNTER_1_CTRL,
+ SIRFSOC_TIMER_64COUNTER_CTRL,
+ SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
+ SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
+};
+
+static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
+
+static void __iomem *sirfsoc_timer_base;
+
+/* disable count and interrupt */
+static inline void sirfsoc_timer_count_disable(int idx)
+{
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
+ sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
+}
+
+/* enable count and interrupt */
+static inline void sirfsoc_timer_count_enable(int idx)
+{
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3,
+ sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
+}
+
+/* timer interrupt handler */
+static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *ce = dev_id;
+ int cpu = smp_processor_id();
+
+ /* clear timer interrupt */
+ writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
+
+ if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
+ sirfsoc_timer_count_disable(cpu);
+
+ ce->event_handler(ce);
+
+ return IRQ_HANDLED;
+}
+
+/* read 64-bit timer counter */
+static cycle_t sirfsoc_timer_read(struct clocksource *cs)
+{
+ u64 cycles;
+
+ writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+ BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+
+ cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
+ cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
+
+ return cycles;
+}
+
+static int sirfsoc_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *ce)
+{
+ int cpu = smp_processor_id();
+
+ /* disable timer first, then modify the related registers */
+ sirfsoc_timer_count_disable(cpu);
+
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
+ 4 * cpu);
+ writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
+ 4 * cpu);
+
+ /* enable the tick */
+ sirfsoc_timer_count_enable(cpu);
+
+ return 0;
+}
+
+static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *ce)
+{
+ switch (mode) {
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* enable in set_next_event */
+ break;
+ default:
+ break;
+ }
+
+ sirfsoc_timer_count_disable(smp_processor_id());
+}
+
+static void sirfsoc_clocksource_suspend(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
+ sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
+}
+
+static void sirfsoc_clocksource_resume(struct clocksource *cs)
+{
+ int i;
+
+ for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
+ writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
+
+ writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
+ sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
+ writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
+ sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
+
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+ BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+}
+
+static struct clock_event_device __percpu *sirfsoc_clockevent;
+
+static struct clocksource sirfsoc_clocksource = {
+ .name = "sirfsoc_clocksource",
+ .rating = 200,
+ .mask = CLOCKSOURCE_MASK(64),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ .read = sirfsoc_timer_read,
+ .suspend = sirfsoc_clocksource_suspend,
+ .resume = sirfsoc_clocksource_resume,
+};
+
+static struct irqaction sirfsoc_timer_irq = {
+ .name = "sirfsoc_timer0",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = sirfsoc_timer_interrupt,
+};
+
+static struct irqaction sirfsoc_timer1_irq = {
+ .name = "sirfsoc_timer1",
+ .flags = IRQF_TIMER | IRQF_NOBALANCING,
+ .handler = sirfsoc_timer_interrupt,
+};
+
+static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
+{
+ int cpu = smp_processor_id();
+ struct irqaction *action;
+
+ if (cpu == 0)
+ action = &sirfsoc_timer_irq;
+ else
+ action = &sirfsoc_timer1_irq;
+
+ ce->irq = action->irq;
+ ce->name = "local_timer";
+ ce->features = CLOCK_EVT_FEAT_ONESHOT;
+ ce->rating = 200;
+ ce->set_mode = sirfsoc_timer_set_mode;
+ ce->set_next_event = sirfsoc_timer_set_next_event;
+ clockevents_calc_mult_shift(ce, atlas7_timer_rate, 60);
+ ce->max_delta_ns = clockevent_delta2ns(-2, ce);
+ ce->min_delta_ns = clockevent_delta2ns(2, ce);
+ ce->cpumask = cpumask_of(cpu);
+
+ action->dev_id = ce;
+ BUG_ON(setup_irq(ce->irq, action));
+ irq_force_affinity(action->irq, cpumask_of(cpu));
+
+ clockevents_register_device(ce);
+ return 0;
+}
+
+static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
+{
+ int cpu = smp_processor_id();
+
+ sirfsoc_timer_count_disable(1);
+
+ if (cpu == 0)
+ remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
+ else
+ remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
+}
+
+static int sirfsoc_cpu_notify(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ /*
+ * Grab cpu pointer in each case to avoid spurious
+ * preemptible warnings
+ */
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_STARTING:
+ sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
+ break;
+ case CPU_DYING:
+ sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block sirfsoc_cpu_nb = {
+ .notifier_call = sirfsoc_cpu_notify,
+};
+
+static void __init sirfsoc_clockevent_init(void)
+{
+ sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
+ BUG_ON(!sirfsoc_clockevent);
+
+ BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
+
+ /* Immediately configure the timer on the boot CPU */
+ sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
+}
+
+/* initialize the kernel jiffy timer source */
+static void __init sirfsoc_atlas7_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+
+ clk = of_clk_get(np, 0);
+ BUG_ON(IS_ERR(clk));
+
+ BUG_ON(clk_prepare_enable(clk));
+
+ atlas7_timer_rate = clk_get_rate(clk);
+
+ /* 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);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
+ writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
+ BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
+
+ /* Clear all interrupts */
+ writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
+
+ BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, atlas7_timer_rate));
+
+ sirfsoc_clockevent_init();
+}
+
+static void __init sirfsoc_of_timer_init(struct device_node *np)
+{
+ sirfsoc_timer_base = of_iomap(np, 0);
+ if (!sirfsoc_timer_base)
+ panic("unable to map timer cpu registers\n");
+
+ sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
+ if (!sirfsoc_timer_irq.irq)
+ panic("No irq passed for timer0 via DT\n");
+
+ sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
+ if (!sirfsoc_timer1_irq.irq)
+ panic("No irq passed for timer1 via DT\n");
+
+ sirfsoc_atlas7_timer_init(np);
+}
+CLOCKSOURCE_OF_DECLARE(sirfsoc_atlas7_timer, "sirf,atlas7-tick", sirfsoc_of_timer_init);
diff --git a/drivers/clocksource/timer-digicolor.c b/drivers/clocksource/timer-digicolor.c
new file mode 100644
index 000000000000..7f8388cfa810
--- /dev/null
+++ b/drivers/clocksource/timer-digicolor.c
@@ -0,0 +1,199 @@
+/*
+ * Conexant Digicolor timer driver
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation Ltd.
+ *
+ * Based on:
+ * Allwinner SoCs hstimer driver
+ *
+ * Copyright (C) 2013 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.
+ */
+
+/*
+ * Conexant Digicolor SoCs have 8 configurable timers, named from "Timer A" to
+ * "Timer H". Timer A is the only one with watchdog support, so it is dedicated
+ * to the watchdog driver. This driver uses Timer B for sched_clock(), and
+ * Timer C for clockevents.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/clk.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqreturn.h>
+#include <linux/sched_clock.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+enum {
+ TIMER_A,
+ TIMER_B,
+ TIMER_C,
+ TIMER_D,
+ TIMER_E,
+ TIMER_F,
+ TIMER_G,
+ TIMER_H,
+};
+
+#define CONTROL(t) ((t)*8)
+#define COUNT(t) ((t)*8 + 4)
+
+#define CONTROL_DISABLE 0
+#define CONTROL_ENABLE BIT(0)
+#define CONTROL_MODE(m) ((m) << 4)
+#define CONTROL_MODE_ONESHOT CONTROL_MODE(1)
+#define CONTROL_MODE_PERIODIC CONTROL_MODE(2)
+
+struct digicolor_timer {
+ struct clock_event_device ce;
+ void __iomem *base;
+ u32 ticks_per_jiffy;
+ int timer_id; /* one of TIMER_* */
+};
+
+struct digicolor_timer *dc_timer(struct clock_event_device *ce)
+{
+ return container_of(ce, struct digicolor_timer, ce);
+}
+
+static inline void dc_timer_disable(struct clock_event_device *ce)
+{
+ struct digicolor_timer *dt = dc_timer(ce);
+ writeb(CONTROL_DISABLE, dt->base + CONTROL(dt->timer_id));
+}
+
+static inline void dc_timer_enable(struct clock_event_device *ce, u32 mode)
+{
+ struct digicolor_timer *dt = dc_timer(ce);
+ writeb(CONTROL_ENABLE | mode, dt->base + CONTROL(dt->timer_id));
+}
+
+static inline void dc_timer_set_count(struct clock_event_device *ce,
+ unsigned long count)
+{
+ struct digicolor_timer *dt = dc_timer(ce);
+ writel(count, dt->base + COUNT(dt->timer_id));
+}
+
+static void digicolor_clkevt_mode(enum clock_event_mode mode,
+ struct clock_event_device *ce)
+{
+ struct digicolor_timer *dt = dc_timer(ce);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ dc_timer_disable(ce);
+ dc_timer_set_count(ce, dt->ticks_per_jiffy);
+ dc_timer_enable(ce, CONTROL_MODE_PERIODIC);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ dc_timer_disable(ce);
+ dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ default:
+ dc_timer_disable(ce);
+ break;
+ }
+}
+
+static int digicolor_clkevt_next_event(unsigned long evt,
+ struct clock_event_device *ce)
+{
+ dc_timer_disable(ce);
+ dc_timer_set_count(ce, evt);
+ dc_timer_enable(ce, CONTROL_MODE_ONESHOT);
+
+ return 0;
+}
+
+static struct digicolor_timer dc_timer_dev = {
+ .ce = {
+ .name = "digicolor_tick",
+ .rating = 340,
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = digicolor_clkevt_mode,
+ .set_next_event = digicolor_clkevt_next_event,
+ },
+ .timer_id = TIMER_C,
+};
+
+static irqreturn_t digicolor_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static u64 digicolor_timer_sched_read(void)
+{
+ return ~readl(dc_timer_dev.base + COUNT(TIMER_B));
+}
+
+static void __init digicolor_timer_init(struct device_node *node)
+{
+ unsigned long rate;
+ struct clk *clk;
+ int ret, irq;
+
+ /*
+ * timer registers are shared with the watchdog timer;
+ * don't map exclusively
+ */
+ dc_timer_dev.base = of_iomap(node, 0);
+ if (!dc_timer_dev.base) {
+ pr_err("Can't map registers");
+ return;
+ }
+
+ irq = irq_of_parse_and_map(node, dc_timer_dev.timer_id);
+ if (irq <= 0) {
+ pr_err("Can't parse IRQ");
+ return;
+ }
+
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("Can't get timer clock");
+ return;
+ }
+ clk_prepare_enable(clk);
+ rate = clk_get_rate(clk);
+ dc_timer_dev.ticks_per_jiffy = DIV_ROUND_UP(rate, HZ);
+
+ writeb(CONTROL_DISABLE, dc_timer_dev.base + CONTROL(TIMER_B));
+ writel(UINT_MAX, dc_timer_dev.base + COUNT(TIMER_B));
+ writeb(CONTROL_ENABLE, dc_timer_dev.base + CONTROL(TIMER_B));
+
+ sched_clock_register(digicolor_timer_sched_read, 32, rate);
+ clocksource_mmio_init(dc_timer_dev.base + COUNT(TIMER_B), node->name,
+ rate, 340, 32, clocksource_mmio_readl_down);
+
+ ret = request_irq(irq, digicolor_timer_interrupt,
+ IRQF_TIMER | IRQF_IRQPOLL, "digicolor_timerC",
+ &dc_timer_dev.ce);
+ if (ret)
+ pr_warn("request of timer irq %d failed (%d)\n", irq, ret);
+
+ dc_timer_dev.ce.cpumask = cpu_possible_mask;
+ dc_timer_dev.ce.irq = irq;
+
+ clockevents_config_and_register(&dc_timer_dev.ce, rate, 0, 0xffffffff);
+}
+CLOCKSOURCE_OF_DECLARE(conexant_digicolor, "cnxt,cx92755-timer",
+ digicolor_timer_init);
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c
deleted file mode 100644
index 361a789d4bee..000000000000
--- a/drivers/clocksource/timer-marco.c
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * System timer for CSR SiRFprimaII
- *
- * Copyright (c) 2011 Cambridge Silicon Radio Limited, a CSR plc group company.
- *
- * Licensed under GPLv2 or later.
- */
-
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/clockchips.h>
-#include <linux/clocksource.h>
-#include <linux/cpu.h>
-#include <linux/bitops.h>
-#include <linux/irq.h>
-#include <linux/clk.h>
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_irq.h>
-#include <linux/of_address.h>
-#include <linux/sched_clock.h>
-
-#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
-#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
-#define SIRFSOC_TIMER_MATCH_0 0x0018
-#define SIRFSOC_TIMER_MATCH_1 0x001c
-#define SIRFSOC_TIMER_COUNTER_0 0x0048
-#define SIRFSOC_TIMER_COUNTER_1 0x004c
-#define SIRFSOC_TIMER_INTR_STATUS 0x0060
-#define SIRFSOC_TIMER_WATCHDOG_EN 0x0064
-#define SIRFSOC_TIMER_64COUNTER_CTRL 0x0068
-#define SIRFSOC_TIMER_64COUNTER_LO 0x006c
-#define SIRFSOC_TIMER_64COUNTER_HI 0x0070
-#define SIRFSOC_TIMER_64COUNTER_LOAD_LO 0x0074
-#define SIRFSOC_TIMER_64COUNTER_LOAD_HI 0x0078
-#define SIRFSOC_TIMER_64COUNTER_RLATCHED_LO 0x007c
-#define SIRFSOC_TIMER_64COUNTER_RLATCHED_HI 0x0080
-
-#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,
- SIRFSOC_TIMER_32COUNTER_1_CTRL,
- SIRFSOC_TIMER_64COUNTER_CTRL,
- SIRFSOC_TIMER_64COUNTER_RLATCHED_LO,
- SIRFSOC_TIMER_64COUNTER_RLATCHED_HI,
-};
-
-static u32 sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT];
-
-static void __iomem *sirfsoc_timer_base;
-
-/* disable count and interrupt */
-static inline void sirfsoc_timer_count_disable(int idx)
-{
- writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) & ~0x7,
- sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
-}
-
-/* enable count and interrupt */
-static inline void sirfsoc_timer_count_enable(int idx)
-{
- writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx) | 0x3,
- sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL + 4 * idx);
-}
-
-/* timer interrupt handler */
-static irqreturn_t sirfsoc_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *ce = dev_id;
- int cpu = smp_processor_id();
-
- /* clear timer interrupt */
- writel_relaxed(BIT(cpu), sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
-
- if (ce->mode == CLOCK_EVT_MODE_ONESHOT)
- sirfsoc_timer_count_disable(cpu);
-
- ce->event_handler(ce);
-
- return IRQ_HANDLED;
-}
-
-/* read 64-bit timer counter */
-static cycle_t sirfsoc_timer_read(struct clocksource *cs)
-{
- u64 cycles;
-
- writel_relaxed((readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
- BIT(0)) & ~BIT(1), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
-
- cycles = readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_HI);
- cycles = (cycles << 32) | readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_RLATCHED_LO);
-
- return cycles;
-}
-
-static int sirfsoc_timer_set_next_event(unsigned long delta,
- struct clock_event_device *ce)
-{
- int cpu = smp_processor_id();
-
- /* disable timer first, then modify the related registers */
- sirfsoc_timer_count_disable(cpu);
-
- writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0 +
- 4 * cpu);
- writel_relaxed(delta, sirfsoc_timer_base + SIRFSOC_TIMER_MATCH_0 +
- 4 * cpu);
-
- /* enable the tick */
- sirfsoc_timer_count_enable(cpu);
-
- return 0;
-}
-
-static void sirfsoc_timer_set_mode(enum clock_event_mode mode,
- struct clock_event_device *ce)
-{
- switch (mode) {
- case CLOCK_EVT_MODE_ONESHOT:
- /* enable in set_next_event */
- break;
- default:
- break;
- }
-
- sirfsoc_timer_count_disable(smp_processor_id());
-}
-
-static void sirfsoc_clocksource_suspend(struct clocksource *cs)
-{
- int i;
-
- for (i = 0; i < SIRFSOC_TIMER_REG_CNT; i++)
- sirfsoc_timer_reg_val[i] = readl_relaxed(sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
-}
-
-static void sirfsoc_clocksource_resume(struct clocksource *cs)
-{
- int i;
-
- for (i = 0; i < SIRFSOC_TIMER_REG_CNT - 2; i++)
- writel_relaxed(sirfsoc_timer_reg_val[i], sirfsoc_timer_base + sirfsoc_timer_reg_list[i]);
-
- writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 2],
- sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
- writel_relaxed(sirfsoc_timer_reg_val[SIRFSOC_TIMER_REG_CNT - 1],
- sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
-
- writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
- BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
-}
-
-static struct clock_event_device __percpu *sirfsoc_clockevent;
-
-static struct clocksource sirfsoc_clocksource = {
- .name = "sirfsoc_clocksource",
- .rating = 200,
- .mask = CLOCKSOURCE_MASK(64),
- .flags = CLOCK_SOURCE_IS_CONTINUOUS,
- .read = sirfsoc_timer_read,
- .suspend = sirfsoc_clocksource_suspend,
- .resume = sirfsoc_clocksource_resume,
-};
-
-static struct irqaction sirfsoc_timer_irq = {
- .name = "sirfsoc_timer0",
- .flags = IRQF_TIMER | IRQF_NOBALANCING,
- .handler = sirfsoc_timer_interrupt,
-};
-
-static struct irqaction sirfsoc_timer1_irq = {
- .name = "sirfsoc_timer1",
- .flags = IRQF_TIMER | IRQF_NOBALANCING,
- .handler = sirfsoc_timer_interrupt,
-};
-
-static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
-{
- int cpu = smp_processor_id();
- struct irqaction *action;
-
- if (cpu == 0)
- action = &sirfsoc_timer_irq;
- else
- action = &sirfsoc_timer1_irq;
-
- ce->irq = action->irq;
- ce->name = "local_timer";
- ce->features = CLOCK_EVT_FEAT_ONESHOT;
- 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_timer_rate, 60);
- ce->max_delta_ns = clockevent_delta2ns(-2, ce);
- ce->min_delta_ns = clockevent_delta2ns(2, ce);
- ce->cpumask = cpumask_of(cpu);
-
- action->dev_id = ce;
- BUG_ON(setup_irq(ce->irq, action));
- irq_force_affinity(action->irq, cpumask_of(cpu));
-
- clockevents_register_device(ce);
- return 0;
-}
-
-static void sirfsoc_local_timer_stop(struct clock_event_device *ce)
-{
- int cpu = smp_processor_id();
-
- sirfsoc_timer_count_disable(1);
-
- if (cpu == 0)
- remove_irq(sirfsoc_timer_irq.irq, &sirfsoc_timer_irq);
- else
- remove_irq(sirfsoc_timer1_irq.irq, &sirfsoc_timer1_irq);
-}
-
-static int sirfsoc_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- /*
- * Grab cpu pointer in each case to avoid spurious
- * preemptible warnings
- */
- switch (action & ~CPU_TASKS_FROZEN) {
- case CPU_STARTING:
- sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
- break;
- case CPU_DYING:
- sirfsoc_local_timer_stop(this_cpu_ptr(sirfsoc_clockevent));
- break;
- }
-
- return NOTIFY_OK;
-}
-
-static struct notifier_block sirfsoc_cpu_nb = {
- .notifier_call = sirfsoc_cpu_notify,
-};
-
-static void __init sirfsoc_clockevent_init(void)
-{
- sirfsoc_clockevent = alloc_percpu(struct clock_event_device);
- BUG_ON(!sirfsoc_clockevent);
-
- BUG_ON(register_cpu_notifier(&sirfsoc_cpu_nb));
-
- /* Immediately configure the timer on the boot CPU */
- sirfsoc_local_timer_setup(this_cpu_ptr(sirfsoc_clockevent));
-}
-
-/* initialize the kernel jiffy timer source */
-static void __init sirfsoc_marco_timer_init(struct device_node *np)
-{
- u32 timer_div;
- struct clk *clk;
-
- clk = of_clk_get(np, 0);
- BUG_ON(IS_ERR(clk));
-
- BUG_ON(clk_prepare_enable(clk));
-
- marco_timer_rate = clk_get_rate(clk);
-
- /* 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);
- writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_HI);
- writel_relaxed(readl_relaxed(sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL) |
- BIT(1) | BIT(0), sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
- writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_0);
- writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_COUNTER_1);
-
- /* Clear all interrupts */
- writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
-
- BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, marco_timer_rate));
-
- sirfsoc_clockevent_init();
-}
-
-static void __init sirfsoc_of_timer_init(struct device_node *np)
-{
- sirfsoc_timer_base = of_iomap(np, 0);
- if (!sirfsoc_timer_base)
- panic("unable to map timer cpu registers\n");
-
- sirfsoc_timer_irq.irq = irq_of_parse_and_map(np, 0);
- if (!sirfsoc_timer_irq.irq)
- panic("No irq passed for timer0 via DT\n");
-
- sirfsoc_timer1_irq.irq = irq_of_parse_and_map(np, 1);
- if (!sirfsoc_timer1_irq.irq)
- panic("No irq passed for timer1 via DT\n");
-
- sirfsoc_marco_timer_init(np);
-}
-CLOCKSOURCE_OF_DECLARE(sirfsoc_marco_timer, "sirf,marco-tick", sirfsoc_of_timer_init );
diff --git a/drivers/clocksource/versatile.c b/drivers/clocksource/versatile.c
index 2798e7492234..0a26d3dde6c0 100644
--- a/drivers/clocksource/versatile.c
+++ b/drivers/clocksource/versatile.c
@@ -36,5 +36,7 @@ static void __init versatile_sched_clock_init(struct device_node *node)
sched_clock_register(versatile_sys_24mhz_read, 32, 24000000);
}
-CLOCKSOURCE_OF_DECLARE(versatile, "arm,vexpress-sysreg",
+CLOCKSOURCE_OF_DECLARE(vexpress, "arm,vexpress-sysreg",
+ versatile_sched_clock_init);
+CLOCKSOURCE_OF_DECLARE(versatile, "arm,versatile-sysreg",
versatile_sched_clock_init);
diff --git a/drivers/connector/Kconfig b/drivers/connector/Kconfig
index 6e6730f9dfd1..3de5f3a9a104 100644
--- a/drivers/connector/Kconfig
+++ b/drivers/connector/Kconfig
@@ -12,7 +12,7 @@ menuconfig CONNECTOR
if CONNECTOR
config PROC_EVENTS
- boolean "Report process events to userspace"
+ bool "Report process events to userspace"
depends on CONNECTOR=y
default y
---help---
diff --git a/drivers/coresight/coresight-etb10.c b/drivers/coresight/coresight-etb10.c
index c922d4aded8a..c9acd406f0d0 100644
--- a/drivers/coresight/coresight-etb10.c
+++ b/drivers/coresight/coresight-etb10.c
@@ -454,7 +454,7 @@ static int etb_probe(struct amba_device *adev, const struct amba_id *id)
if (ret)
return ret;
- drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
+ drvdata->buffer_depth = etb_get_buffer_depth(drvdata);
clk_disable_unprepare(drvdata->clk);
if (drvdata->buffer_depth < 0)
@@ -521,17 +521,7 @@ static struct amba_driver etb_driver = {
.id_table = etb_ids,
};
-static int __init etb_init(void)
-{
- return amba_driver_register(&etb_driver);
-}
-module_init(etb_init);
-
-static void __exit etb_exit(void)
-{
- amba_driver_unregister(&etb_driver);
-}
-module_exit(etb_exit);
+module_amba_driver(etb_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Embedded Trace Buffer driver");
diff --git a/drivers/coresight/coresight-etm3x.c b/drivers/coresight/coresight-etm3x.c
index d9e3ed6aa857..c965f5724abd 100644
--- a/drivers/coresight/coresight-etm3x.c
+++ b/drivers/coresight/coresight-etm3x.c
@@ -34,14 +34,8 @@
#include "coresight-etm.h"
-#ifdef CONFIG_CORESIGHT_SOURCE_ETM_DEFAULT_ENABLE
-static int boot_enable = 1;
-#else
static int boot_enable;
-#endif
-module_param_named(
- boot_enable, boot_enable, int, S_IRUGO
-);
+module_param_named(boot_enable, boot_enable, int, S_IRUGO);
/* The number of ETM/PTM currently registered */
static int etm_count;
@@ -573,7 +567,8 @@ static ssize_t mode_store(struct device *dev,
if (drvdata->mode & ETM_MODE_STALL) {
if (!(drvdata->etmccr & ETMCCR_FIFOFULL)) {
dev_warn(drvdata->dev, "stall mode not supported\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_unlock;
}
drvdata->ctrl |= ETMCR_STALL_MODE;
} else
@@ -582,7 +577,8 @@ static ssize_t mode_store(struct device *dev,
if (drvdata->mode & ETM_MODE_TIMESTAMP) {
if (!(drvdata->etmccer & ETMCCER_TIMESTAMP)) {
dev_warn(drvdata->dev, "timestamp not supported\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto err_unlock;
}
drvdata->ctrl |= ETMCR_TIMESTAMP_EN;
} else
@@ -595,6 +591,10 @@ static ssize_t mode_store(struct device *dev,
spin_unlock(&drvdata->spinlock);
return size;
+
+err_unlock:
+ spin_unlock(&drvdata->spinlock);
+ return ret;
}
static DEVICE_ATTR_RW(mode);
@@ -1743,7 +1743,11 @@ static void etm_init_arch_data(void *info)
static void etm_init_default_data(struct etm_drvdata *drvdata)
{
- static int etm3x_traceid;
+ /*
+ * A trace ID of value 0 is invalid, so let's start at some
+ * random value that fits in 7 bits and will be just as good.
+ */
+ static int etm3x_traceid = 0x10;
u32 flags = (1 << 0 | /* instruction execute*/
3 << 3 | /* ARM instruction */
diff --git a/drivers/coresight/coresight-funnel.c b/drivers/coresight/coresight-funnel.c
index 2108edffe1f4..3db36f70b666 100644
--- a/drivers/coresight/coresight-funnel.c
+++ b/drivers/coresight/coresight-funnel.c
@@ -252,17 +252,7 @@ static struct amba_driver funnel_driver = {
.id_table = funnel_ids,
};
-static int __init funnel_init(void)
-{
- return amba_driver_register(&funnel_driver);
-}
-module_init(funnel_init);
-
-static void __exit funnel_exit(void)
-{
- amba_driver_unregister(&funnel_driver);
-}
-module_exit(funnel_exit);
+module_amba_driver(funnel_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Funnel driver");
diff --git a/drivers/coresight/coresight-priv.h b/drivers/coresight/coresight-priv.h
index 7b3372fca4f6..62fcd98cc7cf 100644
--- a/drivers/coresight/coresight-priv.h
+++ b/drivers/coresight/coresight-priv.h
@@ -57,7 +57,7 @@ extern int etm_readl_cp14(u32 off, unsigned int *val);
extern int etm_writel_cp14(u32 off, u32 val);
#else
static inline int etm_readl_cp14(u32 off, unsigned int *val) { return 0; }
-static inline int etm_writel_cp14(u32 val, u32 off) { return 0; }
+static inline int etm_writel_cp14(u32 off, u32 val) { return 0; }
#endif
#endif
diff --git a/drivers/coresight/coresight-replicator.c b/drivers/coresight/coresight-replicator.c
index a2dfcf903551..cdf05537d574 100644
--- a/drivers/coresight/coresight-replicator.c
+++ b/drivers/coresight/coresight-replicator.c
@@ -87,7 +87,7 @@ static int replicator_probe(struct platform_device *pdev)
return -ENOMEM;
desc->type = CORESIGHT_DEV_TYPE_LINK;
- desc->subtype.sink_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
+ desc->subtype.link_subtype = CORESIGHT_DEV_SUBTYPE_LINK_SPLIT;
desc->ops = &replicator_cs_ops;
desc->pdata = pdev->dev.platform_data;
desc->dev = &pdev->dev;
diff --git a/drivers/coresight/coresight-tmc.c b/drivers/coresight/coresight-tmc.c
index ce2c293f1707..3ff232f9ddf7 100644
--- a/drivers/coresight/coresight-tmc.c
+++ b/drivers/coresight/coresight-tmc.c
@@ -760,17 +760,7 @@ static struct amba_driver tmc_driver = {
.id_table = tmc_ids,
};
-static int __init tmc_init(void)
-{
- return amba_driver_register(&tmc_driver);
-}
-module_init(tmc_init);
-
-static void __exit tmc_exit(void)
-{
- amba_driver_unregister(&tmc_driver);
-}
-module_exit(tmc_exit);
+module_amba_driver(tmc_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Trace Memory Controller driver");
diff --git a/drivers/coresight/coresight-tpiu.c b/drivers/coresight/coresight-tpiu.c
index ae101082791a..3b33af2416bb 100644
--- a/drivers/coresight/coresight-tpiu.c
+++ b/drivers/coresight/coresight-tpiu.c
@@ -201,17 +201,7 @@ static struct amba_driver tpiu_driver = {
.id_table = tpiu_ids,
};
-static int __init tpiu_init(void)
-{
- return amba_driver_register(&tpiu_driver);
-}
-module_init(tpiu_init);
-
-static void __exit tpiu_exit(void)
-{
- amba_driver_unregister(&tpiu_driver);
-}
-module_exit(tpiu_exit);
+module_amba_driver(tpiu_driver);
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CoreSight Trace Port Interface Unit driver");
diff --git a/drivers/coresight/coresight.c b/drivers/coresight/coresight.c
index 6e0181f84425..c5def9382357 100644
--- a/drivers/coresight/coresight.c
+++ b/drivers/coresight/coresight.c
@@ -498,17 +498,18 @@ static int coresight_orphan_match(struct device *dev, void *data)
* Circle throuch all the connection of that component. If we find
* an orphan connection whose name matches @csdev, link it.
*/
- for (i = 0; i < i_csdev->nr_outport; i++) {
+ for (i = 0; i < i_csdev->nr_outport; i++) {
conn = &i_csdev->conns[i];
/* We have found at least one orphan connection */
if (conn->child_dev == NULL) {
/* Does it match this newly added device? */
- if (!strcmp(dev_name(&csdev->dev), conn->child_name))
+ if (!strcmp(dev_name(&csdev->dev), conn->child_name)) {
conn->child_dev = csdev;
- } else {
- /* Too bad, this component still has an orphan */
- still_orphan = true;
+ } else {
+ /* This component still has an orphan */
+ still_orphan = true;
+ }
}
}
diff --git a/drivers/coresight/of_coresight.c b/drivers/coresight/of_coresight.c
index 5030c0734508..c3efa418a86d 100644
--- a/drivers/coresight/of_coresight.c
+++ b/drivers/coresight/of_coresight.c
@@ -93,7 +93,7 @@ static int of_coresight_alloc_memory(struct device *dev,
if (!pdata->outports)
return -ENOMEM;
- /* Children connected to this component via @outport */
+ /* Children connected to this component via @outports */
pdata->child_names = devm_kzalloc(dev, pdata->nr_outport *
sizeof(*pdata->child_names),
GFP_KERNEL);
@@ -117,7 +117,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
struct coresight_platform_data *pdata;
struct of_endpoint endpoint, rendpoint;
struct device *rdev;
- struct device_node *cpu;
+ struct device_node *dn;
struct device_node *ep = NULL;
struct device_node *rparent = NULL;
struct device_node *rport = NULL;
@@ -126,7 +126,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
if (!pdata)
return ERR_PTR(-ENOMEM);
- /* Use device name as debugfs handle */
+ /* Use device name as sysfs handle */
pdata->name = dev_name(dev);
/* Get the number of input and output port for this component */
@@ -174,7 +174,7 @@ struct coresight_platform_data *of_get_coresight_platform_data(
continue;
rdev = of_coresight_get_endpoint_device(rparent);
- if (!dev)
+ if (!rdev)
continue;
pdata->child_names[i] = dev_name(rdev);
@@ -186,14 +186,16 @@ struct coresight_platform_data *of_get_coresight_platform_data(
/* Affinity defaults to CPU0 */
pdata->cpu = 0;
- cpu = of_parse_phandle(node, "cpu", 0);
- if (cpu) {
- const u32 *mpidr;
+ dn = of_parse_phandle(node, "cpu", 0);
+ if (dn) {
+ const u32 *cell;
int len, index;
+ u64 hwid;
- mpidr = of_get_property(cpu, "reg", &len);
- if (mpidr && len == 4) {
- index = get_logical_index(be32_to_cpup(mpidr));
+ cell = of_get_property(dn, "reg", &len);
+ if (cell) {
+ hwid = of_read_number(cell, of_n_addr_cells(dn));
+ index = get_logical_index(hwid);
if (index != -EINVAL)
pdata->cpu = index;
}
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 29b2ef5a68b9..a171fef2c2b6 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -2,6 +2,7 @@ menu "CPU Frequency scaling"
config CPU_FREQ
bool "CPU Frequency scaling"
+ select SRCU
help
CPU Frequency scaling allows you to change the clock speed of
CPUs on the fly. This is a nice method to save power, because
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 0f9a2c3c0e0d..1b06fc4640e2 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -26,13 +26,21 @@ config ARM_VEXPRESS_SPC_CPUFREQ
config ARM_EXYNOS_CPUFREQ
- bool
+ tristate "SAMSUNG EXYNOS CPUfreq Driver"
+ depends on CPU_EXYNOS4210 || SOC_EXYNOS4212 || SOC_EXYNOS4412 || SOC_EXYNOS5250
+ depends on THERMAL
+ help
+ This adds the CPUFreq driver for Samsung EXYNOS platforms.
+ Supported SoC versions are:
+ Exynos4210, Exynos4212, Exynos4412, and Exynos5250.
+
+ If in doubt, say N.
config ARM_EXYNOS4210_CPUFREQ
bool "SAMSUNG EXYNOS4210"
depends on CPU_EXYNOS4210
+ depends on ARM_EXYNOS_CPUFREQ
default y
- select ARM_EXYNOS_CPUFREQ
help
This adds the CPUFreq driver for Samsung EXYNOS4210
SoC (S5PV310 or S5PC210).
@@ -42,8 +50,8 @@ config ARM_EXYNOS4210_CPUFREQ
config ARM_EXYNOS4X12_CPUFREQ
bool "SAMSUNG EXYNOS4x12"
depends on SOC_EXYNOS4212 || SOC_EXYNOS4412
+ depends on ARM_EXYNOS_CPUFREQ
default y
- select ARM_EXYNOS_CPUFREQ
help
This adds the CPUFreq driver for Samsung EXYNOS4X12
SoC (EXYNOS4212 or EXYNOS4412).
@@ -53,28 +61,14 @@ config ARM_EXYNOS4X12_CPUFREQ
config ARM_EXYNOS5250_CPUFREQ
bool "SAMSUNG EXYNOS5250"
depends on SOC_EXYNOS5250
+ depends on ARM_EXYNOS_CPUFREQ
default y
- select ARM_EXYNOS_CPUFREQ
help
This adds the CPUFreq driver for Samsung EXYNOS5250
SoC.
If in doubt, say N.
-config ARM_EXYNOS5440_CPUFREQ
- bool "SAMSUNG EXYNOS5440"
- depends on SOC_EXYNOS5440
- depends on HAVE_CLK && OF
- select PM_OPP
- default y
- help
- This adds the CPUFreq driver for Samsung EXYNOS5440
- SoC. The nature of exynos5440 clock controller is
- different than previous exynos controllers so not using
- the common exynos framework.
-
- If in doubt, say N.
-
config ARM_EXYNOS_CPU_FREQ_BOOST_SW
bool "EXYNOS Frequency Overclocking - Software"
depends on ARM_EXYNOS_CPUFREQ && THERMAL
@@ -90,6 +84,20 @@ config ARM_EXYNOS_CPU_FREQ_BOOST_SW
If in doubt, say N.
+config ARM_EXYNOS5440_CPUFREQ
+ tristate "SAMSUNG EXYNOS5440"
+ depends on SOC_EXYNOS5440
+ depends on HAVE_CLK && OF
+ select PM_OPP
+ default y
+ help
+ This adds the CPUFreq driver for Samsung EXYNOS5440
+ SoC. The nature of exynos5440 clock controller is
+ different than previous exynos controllers so not using
+ the common exynos framework.
+
+ If in doubt, say N.
+
config ARM_HIGHBANK_CPUFREQ
tristate "Calxeda Highbank-based"
depends on ARCH_HIGHBANK && CPUFREQ_DT && REGULATOR
diff --git a/drivers/cpufreq/Kconfig.powerpc b/drivers/cpufreq/Kconfig.powerpc
index 72564b701b4a..7ea24413cee6 100644
--- a/drivers/cpufreq/Kconfig.powerpc
+++ b/drivers/cpufreq/Kconfig.powerpc
@@ -26,7 +26,7 @@ config CPU_FREQ_MAPLE
config PPC_CORENET_CPUFREQ
tristate "CPU frequency scaling driver for Freescale E500MC SoCs"
depends on PPC_E500MC && OF && COMMON_CLK
- select CLK_PPC_CORENET
+ select CLK_QORIQ
help
This adds the CPUFreq driver support for Freescale e500mc,
e5500 and e6500 series SoCs which are capable of changing
diff --git a/drivers/cpufreq/Kconfig.x86 b/drivers/cpufreq/Kconfig.x86
index 89ae88f91895..c59bdcb83217 100644
--- a/drivers/cpufreq/Kconfig.x86
+++ b/drivers/cpufreq/Kconfig.x86
@@ -57,6 +57,16 @@ config X86_ACPI_CPUFREQ_CPB
By enabling this option the acpi_cpufreq driver provides the old
entry in addition to the new boost ones, for compatibility reasons.
+config X86_SFI_CPUFREQ
+ tristate "SFI Performance-States driver"
+ depends on X86_INTEL_MID && SFI
+ help
+ This adds a CPUFreq driver for some Silvermont based Intel Atom
+ architectures like Z34xx and Z35xx which enumerate processor
+ performance states through SFI.
+
+ If in doubt, say N.
+
config ELAN_CPUFREQ
tristate "AMD Elan SC400 and SC410"
depends on MELAN
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index b3ca7b0b2c33..82a1821471fd 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_X86_P4_CLOCKMOD) += p4-clockmod.o
obj-$(CONFIG_X86_CPUFREQ_NFORCE2) += cpufreq-nforce2.o
obj-$(CONFIG_X86_INTEL_PSTATE) += intel_pstate.o
obj-$(CONFIG_X86_AMD_FREQ_SENSITIVITY) += amd_freq_sensitivity.o
+obj-$(CONFIG_X86_SFI_CPUFREQ) += sfi-cpufreq.o
##################################################################################
# ARM SoC drivers
@@ -51,10 +52,11 @@ obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += exynos-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
-obj-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
+obj-$(CONFIG_ARM_EXYNOS_CPUFREQ) += arm-exynos-cpufreq.o
+arm-exynos-cpufreq-y := exynos-cpufreq.o
+arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4210_CPUFREQ) += exynos4210-cpufreq.o
+arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS4X12_CPUFREQ) += exynos4x12-cpufreq.o
+arm-exynos-cpufreq-$(CONFIG_ARM_EXYNOS5250_CPUFREQ) += exynos5250-cpufreq.o
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index fde97d6e31d6..bab67db54b7e 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -320,8 +320,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
{
struct private_data *priv = policy->driver_data;
- if (priv->cdev)
- cpufreq_cooling_unregister(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);
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 46bed4f81cde..28e59a48b35f 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -27,9 +27,21 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
#include <linux/tick.h>
#include <trace/events/power.h>
+/* Macros to iterate over lists */
+/* Iterate over online CPUs policies */
+static LIST_HEAD(cpufreq_policy_list);
+#define for_each_policy(__policy) \
+ list_for_each_entry(__policy, &cpufreq_policy_list, policy_list)
+
+/* Iterate over governors */
+static LIST_HEAD(cpufreq_governor_list);
+#define for_each_governor(__governor) \
+ list_for_each_entry(__governor, &cpufreq_governor_list, governor_list)
+
/**
* The "cpufreq driver" - the arch- or hardware-dependent low
* level driver of CPUFreq support, and its spinlock. This lock
@@ -40,7 +52,6 @@ static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data);
static DEFINE_PER_CPU(struct cpufreq_policy *, cpufreq_cpu_data_fallback);
static DEFINE_RWLOCK(cpufreq_driver_lock);
DEFINE_MUTEX(cpufreq_governor_lock);
-static LIST_HEAD(cpufreq_policy_list);
/* This one keeps track of the previously set governor of a removed CPU */
static DEFINE_PER_CPU(char[CPUFREQ_NAME_LEN], cpufreq_cpu_governor);
@@ -62,7 +73,7 @@ static DECLARE_RWSEM(cpufreq_rwsem);
/* internal prototypes */
static int __cpufreq_governor(struct cpufreq_policy *policy,
unsigned int event);
-static unsigned int __cpufreq_get(unsigned int cpu);
+static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
static void handle_update(struct work_struct *work);
/**
@@ -93,7 +104,6 @@ void disable_cpufreq(void)
{
off = 1;
}
-static LIST_HEAD(cpufreq_governor_list);
static DEFINE_MUTEX(cpufreq_governor_mutex);
bool have_governor_per_policy(void)
@@ -202,7 +212,7 @@ struct cpufreq_policy *cpufreq_cpu_get(unsigned int cpu)
struct cpufreq_policy *policy = NULL;
unsigned long flags;
- if (cpufreq_disabled() || (cpu >= nr_cpu_ids))
+ if (cpu >= nr_cpu_ids)
return NULL;
if (!down_read_trylock(&cpufreq_rwsem))
@@ -229,9 +239,6 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_get);
void cpufreq_cpu_put(struct cpufreq_policy *policy)
{
- if (cpufreq_disabled())
- return;
-
kobject_put(&policy->kobj);
up_read(&cpufreq_rwsem);
}
@@ -249,12 +256,12 @@ EXPORT_SYMBOL_GPL(cpufreq_cpu_put);
* systems as each CPU might be scaled differently. So, use the arch
* per-CPU loops_per_jiffy value wherever possible.
*/
-#ifndef CONFIG_SMP
-static unsigned long l_p_j_ref;
-static unsigned int l_p_j_ref_freq;
-
static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
{
+#ifndef CONFIG_SMP
+ static unsigned long l_p_j_ref;
+ static unsigned int l_p_j_ref_freq;
+
if (ci->flags & CPUFREQ_CONST_LOOPS)
return;
@@ -270,13 +277,8 @@ static void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
pr_debug("scaling loops_per_jiffy to %lu for frequency %u kHz\n",
loops_per_jiffy, ci->new);
}
-}
-#else
-static inline void adjust_jiffies(unsigned long val, struct cpufreq_freqs *ci)
-{
- return;
-}
#endif
+}
static void __cpufreq_notify_transition(struct cpufreq_policy *policy,
struct cpufreq_freqs *freqs, unsigned int state)
@@ -432,11 +434,11 @@ static ssize_t store_boost(struct kobject *kobj, struct attribute *attr,
}
define_one_global_rw(boost);
-static struct cpufreq_governor *__find_governor(const char *str_governor)
+static struct cpufreq_governor *find_governor(const char *str_governor)
{
struct cpufreq_governor *t;
- list_for_each_entry(t, &cpufreq_governor_list, governor_list)
+ for_each_governor(t)
if (!strncasecmp(str_governor, t->name, CPUFREQ_NAME_LEN))
return t;
@@ -463,12 +465,12 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
*policy = CPUFREQ_POLICY_POWERSAVE;
err = 0;
}
- } else if (has_target()) {
+ } else {
struct cpufreq_governor *t;
mutex_lock(&cpufreq_governor_mutex);
- t = __find_governor(str_governor);
+ t = find_governor(str_governor);
if (t == NULL) {
int ret;
@@ -478,7 +480,7 @@ static int cpufreq_parse_governor(char *str_governor, unsigned int *policy,
mutex_lock(&cpufreq_governor_mutex);
if (ret == 0)
- t = __find_governor(str_governor);
+ t = find_governor(str_governor);
}
if (t != NULL) {
@@ -513,8 +515,7 @@ show_one(cpuinfo_transition_latency, cpuinfo.transition_latency);
show_one(scaling_min_freq, min);
show_one(scaling_max_freq, max);
-static ssize_t show_scaling_cur_freq(
- struct cpufreq_policy *policy, char *buf)
+static ssize_t show_scaling_cur_freq(struct cpufreq_policy *policy, char *buf)
{
ssize_t ret;
@@ -563,7 +564,7 @@ store_one(scaling_max_freq, max);
static ssize_t show_cpuinfo_cur_freq(struct cpufreq_policy *policy,
char *buf)
{
- unsigned int cur_freq = __cpufreq_get(policy->cpu);
+ unsigned int cur_freq = __cpufreq_get(policy);
if (!cur_freq)
return sprintf(buf, "<unknown>");
return sprintf(buf, "%u\n", cur_freq);
@@ -639,7 +640,7 @@ static ssize_t show_scaling_available_governors(struct cpufreq_policy *policy,
goto out;
}
- list_for_each_entry(t, &cpufreq_governor_list, governor_list) {
+ for_each_governor(t) {
if (i >= (ssize_t) ((PAGE_SIZE / sizeof(char))
- (CPUFREQ_NAME_LEN + 2)))
goto out;
@@ -902,7 +903,7 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
- while ((drv_attr) && (*drv_attr)) {
+ while (drv_attr && *drv_attr) {
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
if (ret)
return ret;
@@ -936,7 +937,7 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
memcpy(&new_policy, policy, sizeof(*policy));
/* Update governor of new_policy to the governor used before hotplug */
- gov = __find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
+ gov = find_governor(per_cpu(cpufreq_cpu_governor, policy->cpu));
if (gov)
pr_debug("Restoring governor %s for cpu %d\n",
policy->governor->name, policy->cpu);
@@ -958,7 +959,6 @@ static void cpufreq_init_policy(struct cpufreq_policy *policy)
}
}
-#ifdef CONFIG_HOTPLUG_CPU
static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
unsigned int cpu, struct device *dev)
{
@@ -996,7 +996,6 @@ static int cpufreq_add_policy_cpu(struct cpufreq_policy *policy,
return sysfs_create_link(&dev->kobj, &policy->kobj, "cpufreq");
}
-#endif
static struct cpufreq_policy *cpufreq_policy_restore(unsigned int cpu)
{
@@ -1033,6 +1032,8 @@ static struct cpufreq_policy *cpufreq_policy_alloc(void)
init_rwsem(&policy->rwsem);
spin_lock_init(&policy->transition_lock);
init_waitqueue_head(&policy->transition_wait);
+ init_completion(&policy->kobj_unregister);
+ INIT_WORK(&policy->update, handle_update);
return policy;
@@ -1091,15 +1092,9 @@ static int update_policy_cpu(struct cpufreq_policy *policy, unsigned int cpu,
}
down_write(&policy->rwsem);
-
- policy->last_cpu = policy->cpu;
policy->cpu = cpu;
-
up_write(&policy->rwsem);
- blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
- CPUFREQ_UPDATE_POLICY_CPU, policy);
-
return 0;
}
@@ -1110,41 +1105,32 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
struct cpufreq_policy *policy;
unsigned long flags;
bool recover_policy = cpufreq_suspended;
-#ifdef CONFIG_HOTPLUG_CPU
- struct cpufreq_policy *tpolicy;
-#endif
if (cpu_is_offline(cpu))
return 0;
pr_debug("adding CPU %u\n", cpu);
-#ifdef CONFIG_SMP
/* check whether a different CPU already registered this
* CPU because it is in the same boat. */
- policy = cpufreq_cpu_get(cpu);
- if (unlikely(policy)) {
- cpufreq_cpu_put(policy);
+ policy = cpufreq_cpu_get_raw(cpu);
+ if (unlikely(policy))
return 0;
- }
-#endif
if (!down_read_trylock(&cpufreq_rwsem))
return 0;
-#ifdef CONFIG_HOTPLUG_CPU
/* Check if this cpu was hot-unplugged earlier and has siblings */
read_lock_irqsave(&cpufreq_driver_lock, flags);
- list_for_each_entry(tpolicy, &cpufreq_policy_list, policy_list) {
- if (cpumask_test_cpu(cpu, tpolicy->related_cpus)) {
+ for_each_policy(policy) {
+ if (cpumask_test_cpu(cpu, policy->related_cpus)) {
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
- ret = cpufreq_add_policy_cpu(tpolicy, cpu, dev);
+ ret = cpufreq_add_policy_cpu(policy, cpu, dev);
up_read(&cpufreq_rwsem);
return ret;
}
}
read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-#endif
/*
* Restore the saved policy when doing light-weight init and fall back
@@ -1171,9 +1157,6 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
cpumask_copy(policy->cpus, cpumask_of(cpu));
- init_completion(&policy->kobj_unregister);
- INIT_WORK(&policy->update, handle_update);
-
/* call driver. From then on the cpufreq must be able
* to accept all calls to ->verify and ->setpolicy for this CPU
*/
@@ -1371,11 +1354,10 @@ static int __cpufreq_remove_dev_prepare(struct device *dev,
pr_err("%s: Failed to stop governor\n", __func__);
return ret;
}
- }
- if (!cpufreq_driver->setpolicy)
strncpy(per_cpu(cpufreq_cpu_governor, cpu),
policy->governor->name, CPUFREQ_NAME_LEN);
+ }
down_read(&policy->rwsem);
cpus = cpumask_weight(policy->cpus);
@@ -1416,9 +1398,10 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
unsigned long flags;
struct cpufreq_policy *policy;
- read_lock_irqsave(&cpufreq_driver_lock, flags);
+ write_lock_irqsave(&cpufreq_driver_lock, flags);
policy = per_cpu(cpufreq_cpu_data, cpu);
- read_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ per_cpu(cpufreq_cpu_data, cpu) = NULL;
+ write_unlock_irqrestore(&cpufreq_driver_lock, flags);
if (!policy) {
pr_debug("%s: No cpu_data found\n", __func__);
@@ -1473,7 +1456,6 @@ static int __cpufreq_remove_dev_finish(struct device *dev,
}
}
- per_cpu(cpufreq_cpu_data, cpu) = NULL;
return 0;
}
@@ -1510,30 +1492,23 @@ static void handle_update(struct work_struct *work)
/**
* cpufreq_out_of_sync - If actual and saved CPU frequency differs, we're
* in deep trouble.
- * @cpu: cpu number
- * @old_freq: CPU frequency the kernel thinks the CPU runs at
+ * @policy: policy managing CPUs
* @new_freq: CPU frequency the CPU actually runs at
*
* We adjust to current frequency first, and need to clean up later.
* So either call to cpufreq_update_policy() or schedule handle_update()).
*/
-static void cpufreq_out_of_sync(unsigned int cpu, unsigned int old_freq,
+static void cpufreq_out_of_sync(struct cpufreq_policy *policy,
unsigned int new_freq)
{
- struct cpufreq_policy *policy;
struct cpufreq_freqs freqs;
- unsigned long flags;
pr_debug("Warning: CPU frequency out of sync: cpufreq and timing core thinks of %u, is %u kHz\n",
- old_freq, new_freq);
+ policy->cur, new_freq);
- freqs.old = old_freq;
+ freqs.old = policy->cur;
freqs.new = new_freq;
- read_lock_irqsave(&cpufreq_driver_lock, flags);
- policy = per_cpu(cpufreq_cpu_data, cpu);
- read_unlock_irqrestore(&cpufreq_driver_lock, flags);
-
cpufreq_freq_transition_begin(policy, &freqs);
cpufreq_freq_transition_end(policy, &freqs, 0);
}
@@ -1583,22 +1558,21 @@ unsigned int cpufreq_quick_get_max(unsigned int cpu)
}
EXPORT_SYMBOL(cpufreq_quick_get_max);
-static unsigned int __cpufreq_get(unsigned int cpu)
+static unsigned int __cpufreq_get(struct cpufreq_policy *policy)
{
- struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
unsigned int ret_freq = 0;
if (!cpufreq_driver->get)
return ret_freq;
- ret_freq = cpufreq_driver->get(cpu);
+ ret_freq = cpufreq_driver->get(policy->cpu);
if (ret_freq && policy->cur &&
!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) {
/* verify no discrepancy between actual and
saved value exists */
if (unlikely(ret_freq != policy->cur)) {
- cpufreq_out_of_sync(cpu, policy->cur, ret_freq);
+ cpufreq_out_of_sync(policy, ret_freq);
schedule_work(&policy->update);
}
}
@@ -1619,7 +1593,7 @@ unsigned int cpufreq_get(unsigned int cpu)
if (policy) {
down_read(&policy->rwsem);
- ret_freq = __cpufreq_get(cpu);
+ ret_freq = __cpufreq_get(policy);
up_read(&policy->rwsem);
cpufreq_cpu_put(policy);
@@ -1682,7 +1656,7 @@ void cpufreq_suspend(void)
pr_debug("%s: Suspending Governors\n", __func__);
- list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ for_each_policy(policy) {
if (__cpufreq_governor(policy, CPUFREQ_GOV_STOP))
pr_err("%s: Failed to stop governor for policy: %p\n",
__func__, policy);
@@ -1716,7 +1690,7 @@ void cpufreq_resume(void)
pr_debug("%s: Resuming Governors\n", __func__);
- list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ for_each_policy(policy) {
if (cpufreq_driver->resume && cpufreq_driver->resume(policy))
pr_err("%s: Failed to resume driver: %p\n", __func__,
policy);
@@ -2006,10 +1980,6 @@ int cpufreq_driver_target(struct cpufreq_policy *policy,
}
EXPORT_SYMBOL_GPL(cpufreq_driver_target);
-/*
- * when "event" is CPUFREQ_GOV_LIMITS
- */
-
static int __cpufreq_governor(struct cpufreq_policy *policy,
unsigned int event)
{
@@ -2107,7 +2077,7 @@ int cpufreq_register_governor(struct cpufreq_governor *governor)
governor->initialized = 0;
err = -EBUSY;
- if (__find_governor(governor->name) == NULL) {
+ if (!find_governor(governor->name)) {
err = 0;
list_add(&governor->governor_list, &cpufreq_governor_list);
}
@@ -2307,8 +2277,7 @@ int cpufreq_update_policy(unsigned int cpu)
policy->cur = new_policy.cur;
} else {
if (policy->cur != new_policy.cur && has_target())
- cpufreq_out_of_sync(cpu, policy->cur,
- new_policy.cur);
+ cpufreq_out_of_sync(policy, new_policy.cur);
}
}
@@ -2364,7 +2333,7 @@ static int cpufreq_boost_set_sw(int state)
struct cpufreq_policy *policy;
int ret = -EINVAL;
- list_for_each_entry(policy, &cpufreq_policy_list, policy_list) {
+ for_each_policy(policy) {
freq_table = cpufreq_frequency_get_table(policy->cpu);
if (freq_table) {
ret = cpufreq_frequency_table_cpuinfo(policy,
@@ -2454,9 +2423,6 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
pr_debug("trying to register driver %s\n", driver_data->name);
- if (driver_data->setpolicy)
- driver_data->flags |= CPUFREQ_CONST_LOOPS;
-
write_lock_irqsave(&cpufreq_driver_lock, flags);
if (cpufreq_driver) {
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
@@ -2465,6 +2431,9 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
cpufreq_driver = driver_data;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (driver_data->setpolicy)
+ driver_data->flags |= CPUFREQ_CONST_LOOPS;
+
if (cpufreq_boost_supported()) {
/*
* Check if driver provides function to enable boost -
@@ -2485,23 +2454,12 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data)
if (ret)
goto err_boost_unreg;
- if (!(cpufreq_driver->flags & CPUFREQ_STICKY)) {
- int i;
- ret = -ENODEV;
-
- /* check for at least one working CPU */
- for (i = 0; i < nr_cpu_ids; i++)
- if (cpu_possible(i) && per_cpu(cpufreq_cpu_data, i)) {
- ret = 0;
- break;
- }
-
+ if (!(cpufreq_driver->flags & CPUFREQ_STICKY) &&
+ list_empty(&cpufreq_policy_list)) {
/* if all ->init() calls failed, unregister */
- if (ret) {
- pr_debug("no CPU initialized for driver %s\n",
- driver_data->name);
- goto err_if_unreg;
- }
+ pr_debug("%s: No CPU initialized for driver %s\n", __func__,
+ driver_data->name);
+ goto err_if_unreg;
}
register_hotcpu_notifier(&cpufreq_cpu_notifier);
@@ -2556,6 +2514,14 @@ int cpufreq_unregister_driver(struct cpufreq_driver *driver)
}
EXPORT_SYMBOL_GPL(cpufreq_unregister_driver);
+/*
+ * Stop cpufreq at shutdown to make sure it isn't holding any locks
+ * or mutexes when secondary CPUs are halted.
+ */
+static struct syscore_ops cpufreq_syscore_ops = {
+ .shutdown = cpufreq_suspend,
+};
+
static int __init cpufreq_core_init(void)
{
if (cpufreq_disabled())
@@ -2564,6 +2530,8 @@ static int __init cpufreq_core_init(void)
cpufreq_global_kobject = kobject_create();
BUG_ON(!cpufreq_global_kobject);
+ register_syscore_ops(&cpufreq_syscore_ops);
+
return 0;
}
core_initcall(cpufreq_core_init);
diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
index 0cd9b4dcef99..5e370a30a964 100644
--- a/drivers/cpufreq/cpufreq_stats.c
+++ b/drivers/cpufreq/cpufreq_stats.c
@@ -18,7 +18,6 @@
static spinlock_t cpufreq_stats_lock;
struct cpufreq_stats {
- unsigned int cpu;
unsigned int total_trans;
unsigned long long last_time;
unsigned int max_state;
@@ -31,50 +30,33 @@ struct cpufreq_stats {
#endif
};
-static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table);
-
-struct cpufreq_stats_attribute {
- struct attribute attr;
- ssize_t(*show) (struct cpufreq_stats *, char *);
-};
-
-static int cpufreq_stats_update(unsigned int cpu)
+static int cpufreq_stats_update(struct cpufreq_stats *stats)
{
- struct cpufreq_stats *stat;
- unsigned long long cur_time;
+ unsigned long long cur_time = get_jiffies_64();
- cur_time = get_jiffies_64();
spin_lock(&cpufreq_stats_lock);
- stat = per_cpu(cpufreq_stats_table, cpu);
- if (stat->time_in_state)
- stat->time_in_state[stat->last_index] +=
- cur_time - stat->last_time;
- stat->last_time = cur_time;
+ stats->time_in_state[stats->last_index] += cur_time - stats->last_time;
+ stats->last_time = cur_time;
spin_unlock(&cpufreq_stats_lock);
return 0;
}
static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
{
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
- return 0;
- return sprintf(buf, "%d\n",
- per_cpu(cpufreq_stats_table, stat->cpu)->total_trans);
+ return sprintf(buf, "%d\n", policy->stats->total_trans);
}
static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
{
+ struct cpufreq_stats *stats = policy->stats;
ssize_t len = 0;
int i;
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
- return 0;
- cpufreq_stats_update(stat->cpu);
- for (i = 0; i < stat->state_num; i++) {
- len += sprintf(buf + len, "%u %llu\n", stat->freq_table[i],
+
+ cpufreq_stats_update(stats);
+ for (i = 0; i < stats->state_num; i++) {
+ len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
(unsigned long long)
- jiffies_64_to_clock_t(stat->time_in_state[i]));
+ jiffies_64_to_clock_t(stats->time_in_state[i]));
}
return len;
}
@@ -82,38 +64,35 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
{
+ struct cpufreq_stats *stats = policy->stats;
ssize_t len = 0;
int i, j;
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
- if (!stat)
- return 0;
- cpufreq_stats_update(stat->cpu);
len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
len += snprintf(buf + len, PAGE_SIZE - len, " : ");
- for (i = 0; i < stat->state_num; i++) {
+ for (i = 0; i < stats->state_num; i++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
- stat->freq_table[i]);
+ stats->freq_table[i]);
}
if (len >= PAGE_SIZE)
return PAGE_SIZE;
len += snprintf(buf + len, PAGE_SIZE - len, "\n");
- for (i = 0; i < stat->state_num; i++) {
+ for (i = 0; i < stats->state_num; i++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u: ",
- stat->freq_table[i]);
+ stats->freq_table[i]);
- for (j = 0; j < stat->state_num; j++) {
+ for (j = 0; j < stats->state_num; j++) {
if (len >= PAGE_SIZE)
break;
len += snprintf(buf + len, PAGE_SIZE - len, "%9u ",
- stat->trans_table[i*stat->max_state+j]);
+ stats->trans_table[i*stats->max_state+j]);
}
if (len >= PAGE_SIZE)
break;
@@ -142,28 +121,29 @@ static struct attribute_group stats_attr_group = {
.name = "stats"
};
-static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
+static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq)
{
int index;
- for (index = 0; index < stat->max_state; index++)
- if (stat->freq_table[index] == freq)
+ for (index = 0; index < stats->max_state; index++)
+ if (stats->freq_table[index] == freq)
return index;
return -1;
}
static void __cpufreq_stats_free_table(struct cpufreq_policy *policy)
{
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
+ struct cpufreq_stats *stats = policy->stats;
- if (!stat)
+ /* Already freed */
+ if (!stats)
return;
- pr_debug("%s: Free stat table\n", __func__);
+ pr_debug("%s: Free stats table\n", __func__);
sysfs_remove_group(&policy->kobj, &stats_attr_group);
- kfree(stat->time_in_state);
- kfree(stat);
- per_cpu(cpufreq_stats_table, policy->cpu) = NULL;
+ kfree(stats->time_in_state);
+ kfree(stats);
+ policy->stats = NULL;
}
static void cpufreq_stats_free_table(unsigned int cpu)
@@ -174,37 +154,33 @@ static void cpufreq_stats_free_table(unsigned int cpu)
if (!policy)
return;
- if (cpufreq_frequency_get_table(policy->cpu))
- __cpufreq_stats_free_table(policy);
+ __cpufreq_stats_free_table(policy);
cpufreq_cpu_put(policy);
}
static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
{
- unsigned int i, count = 0, ret = 0;
- struct cpufreq_stats *stat;
+ unsigned int i = 0, count = 0, ret = -ENOMEM;
+ struct cpufreq_stats *stats;
unsigned int alloc_size;
unsigned int cpu = policy->cpu;
struct cpufreq_frequency_table *pos, *table;
+ /* We need cpufreq table for creating stats table */
table = cpufreq_frequency_get_table(cpu);
if (unlikely(!table))
return 0;
- if (per_cpu(cpufreq_stats_table, cpu))
- return -EBUSY;
- stat = kzalloc(sizeof(*stat), GFP_KERNEL);
- if ((stat) == NULL)
- return -ENOMEM;
-
- ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
- if (ret)
- goto error_out;
+ /* stats already initialized */
+ if (policy->stats)
+ return -EEXIST;
- stat->cpu = cpu;
- per_cpu(cpufreq_stats_table, cpu) = stat;
+ stats = kzalloc(sizeof(*stats), GFP_KERNEL);
+ if (!stats)
+ return -ENOMEM;
+ /* Find total allocation size */
cpufreq_for_each_valid_entry(pos, table)
count++;
@@ -213,32 +189,40 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
alloc_size += count * count * sizeof(int);
#endif
- stat->max_state = count;
- stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
- if (!stat->time_in_state) {
- ret = -ENOMEM;
- goto error_alloc;
- }
- stat->freq_table = (unsigned int *)(stat->time_in_state + count);
+
+ /* Allocate memory for time_in_state/freq_table/trans_table in one go */
+ stats->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
+ if (!stats->time_in_state)
+ goto free_stat;
+
+ stats->freq_table = (unsigned int *)(stats->time_in_state + count);
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- stat->trans_table = stat->freq_table + count;
+ stats->trans_table = stats->freq_table + count;
#endif
- i = 0;
+
+ stats->max_state = count;
+
+ /* Find valid-unique entries */
cpufreq_for_each_valid_entry(pos, table)
- if (freq_table_get_index(stat, pos->frequency) == -1)
- stat->freq_table[i++] = pos->frequency;
- stat->state_num = i;
- spin_lock(&cpufreq_stats_lock);
- stat->last_time = get_jiffies_64();
- stat->last_index = freq_table_get_index(stat, policy->cur);
- spin_unlock(&cpufreq_stats_lock);
- return 0;
-error_alloc:
- sysfs_remove_group(&policy->kobj, &stats_attr_group);
-error_out:
- kfree(stat);
- per_cpu(cpufreq_stats_table, cpu) = NULL;
+ if (freq_table_get_index(stats, pos->frequency) == -1)
+ stats->freq_table[i++] = pos->frequency;
+
+ stats->state_num = i;
+ stats->last_time = get_jiffies_64();
+ stats->last_index = freq_table_get_index(stats, policy->cur);
+
+ policy->stats = stats;
+ ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
+ if (!ret)
+ return 0;
+
+ /* We failed, release resources */
+ policy->stats = NULL;
+ kfree(stats->time_in_state);
+free_stat:
+ kfree(stats);
+
return ret;
}
@@ -259,30 +243,12 @@ static void cpufreq_stats_create_table(unsigned int cpu)
cpufreq_cpu_put(policy);
}
-static void cpufreq_stats_update_policy_cpu(struct cpufreq_policy *policy)
-{
- struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table,
- policy->last_cpu);
-
- pr_debug("Updating stats_table for new_cpu %u from last_cpu %u\n",
- policy->cpu, policy->last_cpu);
- per_cpu(cpufreq_stats_table, policy->cpu) = per_cpu(cpufreq_stats_table,
- policy->last_cpu);
- per_cpu(cpufreq_stats_table, policy->last_cpu) = NULL;
- stat->cpu = policy->cpu;
-}
-
static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
unsigned long val, void *data)
{
int ret = 0;
struct cpufreq_policy *policy = data;
- if (val == CPUFREQ_UPDATE_POLICY_CPU) {
- cpufreq_stats_update_policy_cpu(policy);
- return 0;
- }
-
if (val == CPUFREQ_CREATE_POLICY)
ret = __cpufreq_stats_create_table(policy);
else if (val == CPUFREQ_REMOVE_POLICY)
@@ -295,35 +261,45 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
unsigned long val, void *data)
{
struct cpufreq_freqs *freq = data;
- struct cpufreq_stats *stat;
+ struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu);
+ struct cpufreq_stats *stats;
int old_index, new_index;
- if (val != CPUFREQ_POSTCHANGE)
+ if (!policy) {
+ pr_err("%s: No policy found\n", __func__);
return 0;
+ }
- stat = per_cpu(cpufreq_stats_table, freq->cpu);
- if (!stat)
- return 0;
+ if (val != CPUFREQ_POSTCHANGE)
+ goto put_policy;
- old_index = stat->last_index;
- new_index = freq_table_get_index(stat, freq->new);
+ if (!policy->stats) {
+ pr_debug("%s: No stats found\n", __func__);
+ goto put_policy;
+ }
- /* We can't do stat->time_in_state[-1]= .. */
- if (old_index == -1 || new_index == -1)
- return 0;
+ stats = policy->stats;
+
+ old_index = stats->last_index;
+ new_index = freq_table_get_index(stats, freq->new);
- cpufreq_stats_update(freq->cpu);
+ /* We can't do stats->time_in_state[-1]= .. */
+ if (old_index == -1 || new_index == -1)
+ goto put_policy;
if (old_index == new_index)
- return 0;
+ goto put_policy;
- spin_lock(&cpufreq_stats_lock);
- stat->last_index = new_index;
+ cpufreq_stats_update(stats);
+
+ stats->last_index = new_index;
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
- stat->trans_table[old_index * stat->max_state + new_index]++;
+ stats->trans_table[old_index * stats->max_state + new_index]++;
#endif
- stat->total_trans++;
- spin_unlock(&cpufreq_stats_lock);
+ stats->total_trans++;
+
+put_policy:
+ cpufreq_cpu_put(policy);
return 0;
}
@@ -374,8 +350,7 @@ static void __exit cpufreq_stats_exit(void)
}
MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
-MODULE_DESCRIPTION("'cpufreq_stats' - A driver to export cpufreq stats "
- "through sysfs filesystem");
+MODULE_DESCRIPTION("Export cpufreq stats via sysfs");
MODULE_LICENSE("GPL");
module_init(cpufreq_stats_init);
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c
index f99a0b0b7c06..5e98c6b1f284 100644
--- a/drivers/cpufreq/exynos-cpufreq.c
+++ b/drivers/cpufreq/exynos-cpufreq.c
@@ -18,10 +18,13 @@
#include <linux/cpufreq.h>
#include <linux/platform_device.h>
#include <linux/of.h>
+#include <linux/cpu_cooling.h>
+#include <linux/cpu.h>
#include "exynos-cpufreq.h"
static struct exynos_dvfs_info *exynos_info;
+static struct thermal_cooling_device *cdev;
static struct regulator *arm_regulator;
static unsigned int locking_frequency;
@@ -156,6 +159,7 @@ static struct cpufreq_driver exynos_driver = {
static int exynos_cpufreq_probe(struct platform_device *pdev)
{
+ struct device_node *cpus, *np;
int ret = -EINVAL;
exynos_info = kzalloc(sizeof(*exynos_info), GFP_KERNEL);
@@ -198,9 +202,36 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
/* Done here as we want to capture boot frequency */
locking_frequency = clk_get_rate(exynos_info->cpu_clk) / 1000;
- if (!cpufreq_register_driver(&exynos_driver))
+ ret = cpufreq_register_driver(&exynos_driver);
+ if (ret)
+ goto err_cpufreq_reg;
+
+ cpus = of_find_node_by_path("/cpus");
+ if (!cpus) {
+ pr_err("failed to find cpus node\n");
+ return 0;
+ }
+
+ np = of_get_next_child(cpus, NULL);
+ if (!np) {
+ pr_err("failed to find cpus child node\n");
+ of_node_put(cpus);
return 0;
+ }
+
+ if (of_find_property(np, "#cooling-cells", NULL)) {
+ cdev = of_cpufreq_cooling_register(np,
+ cpu_present_mask);
+ if (IS_ERR(cdev))
+ pr_err("running cpufreq without cooling device: %ld\n",
+ PTR_ERR(cdev));
+ }
+ of_node_put(np);
+ of_node_put(cpus);
+
+ return 0;
+err_cpufreq_reg:
dev_err(&pdev->dev, "failed to register cpufreq driver\n");
regulator_put(arm_regulator);
err_vdd_arm:
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 742eefba12c2..872c5772c5d3 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -148,6 +148,8 @@ struct perf_limits {
int32_t min_perf;
int max_policy_pct;
int max_sysfs_pct;
+ int min_policy_pct;
+ int min_sysfs_pct;
};
static struct perf_limits limits = {
@@ -159,6 +161,8 @@ static struct perf_limits limits = {
.min_perf = 0,
.max_policy_pct = 100,
.max_sysfs_pct = 100,
+ .min_policy_pct = 0,
+ .min_sysfs_pct = 0,
};
static inline void pid_reset(struct _pid *pid, int setpoint, int busy,
@@ -338,6 +342,33 @@ static void __init intel_pstate_debug_expose_params(void)
return sprintf(buf, "%u\n", limits.object); \
}
+static ssize_t show_turbo_pct(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpudata *cpu;
+ int total, no_turbo, turbo_pct;
+ uint32_t turbo_fp;
+
+ cpu = all_cpu_data[0];
+
+ total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
+ no_turbo = cpu->pstate.max_pstate - cpu->pstate.min_pstate + 1;
+ turbo_fp = div_fp(int_tofp(no_turbo), int_tofp(total));
+ turbo_pct = 100 - fp_toint(mul_fp(turbo_fp, int_tofp(100)));
+ return sprintf(buf, "%u\n", turbo_pct);
+}
+
+static ssize_t show_num_pstates(struct kobject *kobj,
+ struct attribute *attr, char *buf)
+{
+ struct cpudata *cpu;
+ int total;
+
+ cpu = all_cpu_data[0];
+ total = cpu->pstate.turbo_pstate - cpu->pstate.min_pstate + 1;
+ return sprintf(buf, "%u\n", total);
+}
+
static ssize_t show_no_turbo(struct kobject *kobj,
struct attribute *attr, char *buf)
{
@@ -404,7 +435,9 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
ret = sscanf(buf, "%u", &input);
if (ret != 1)
return -EINVAL;
- limits.min_perf_pct = clamp_t(int, input, 0 , 100);
+
+ limits.min_sysfs_pct = clamp_t(int, input, 0 , 100);
+ limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
if (hwp_active)
@@ -418,11 +451,15 @@ show_one(min_perf_pct, min_perf_pct);
define_one_global_rw(no_turbo);
define_one_global_rw(max_perf_pct);
define_one_global_rw(min_perf_pct);
+define_one_global_ro(turbo_pct);
+define_one_global_ro(num_pstates);
static struct attribute *intel_pstate_attributes[] = {
&no_turbo.attr,
&max_perf_pct.attr,
&min_perf_pct.attr,
+ &turbo_pct.attr,
+ &num_pstates.attr,
NULL
};
@@ -825,6 +862,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x46, core_params),
ICPU(0x47, core_params),
ICPU(0x4c, byt_params),
+ ICPU(0x4e, core_params),
ICPU(0x4f, core_params),
ICPU(0x56, core_params),
{}
@@ -887,7 +925,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
if (!policy->cpuinfo.max_freq)
return -ENODEV;
- if (policy->policy == CPUFREQ_POLICY_PERFORMANCE) {
+ if (policy->policy == CPUFREQ_POLICY_PERFORMANCE &&
+ policy->max >= policy->cpuinfo.max_freq) {
+ limits.min_policy_pct = 100;
limits.min_perf_pct = 100;
limits.min_perf = int_tofp(1);
limits.max_policy_pct = 100;
@@ -897,8 +937,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
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_policy_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
+ limits.min_policy_pct = clamp_t(int, limits.min_policy_pct, 0 , 100);
+ limits.min_perf_pct = max(limits.min_policy_pct, limits.min_sysfs_pct);
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
limits.max_policy_pct = (policy->max * 100) / policy->cpuinfo.max_freq;
@@ -978,6 +1019,7 @@ static struct cpufreq_driver intel_pstate_driver = {
static int __initdata no_load;
static int __initdata no_hwp;
+static int __initdata hwp_only;
static unsigned int force_load;
static int intel_pstate_msrs_not_valid(void)
@@ -1175,6 +1217,9 @@ static int __init intel_pstate_init(void)
if (cpu_has(c,X86_FEATURE_HWP) && !no_hwp)
intel_pstate_hwp_enable();
+ if (!hwp_active && hwp_only)
+ goto out;
+
rc = cpufreq_register_driver(&intel_pstate_driver);
if (rc)
goto out;
@@ -1209,6 +1254,8 @@ static int __init intel_pstate_setup(char *str)
no_hwp = 1;
if (!strcmp(str, "force"))
force_load = 1;
+ if (!strcmp(str, "hwp_only"))
+ hwp_only = 1;
return 0;
}
early_param("intel_pstate", intel_pstate_setup);
diff --git a/drivers/cpufreq/ls1x-cpufreq.c b/drivers/cpufreq/ls1x-cpufreq.c
index 25fbd6a1374f..f0913eee2f50 100644
--- a/drivers/cpufreq/ls1x-cpufreq.c
+++ b/drivers/cpufreq/ls1x-cpufreq.c
@@ -210,7 +210,6 @@ out:
static struct platform_driver ls1x_cpufreq_platdrv = {
.driver = {
.name = "ls1x-cpufreq",
- .owner = THIS_MODULE,
},
.probe = ls1x_cpufreq_probe,
.remove = ls1x_cpufreq_remove,
diff --git a/drivers/cpufreq/s3c2416-cpufreq.c b/drivers/cpufreq/s3c2416-cpufreq.c
index 2fd53eaaec20..d6d425773fa4 100644
--- a/drivers/cpufreq/s3c2416-cpufreq.c
+++ b/drivers/cpufreq/s3c2416-cpufreq.c
@@ -263,7 +263,7 @@ out:
}
#ifdef CONFIG_ARM_S3C2416_CPUFREQ_VCORESCALE
-static void __init s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
+static void s3c2416_cpufreq_cfg_regulator(struct s3c2416_data *s3c_freq)
{
int count, v, i, found;
struct cpufreq_frequency_table *pos;
@@ -333,7 +333,7 @@ static struct notifier_block s3c2416_cpufreq_reboot_notifier = {
.notifier_call = s3c2416_cpufreq_reboot_notifier_evt,
};
-static int __init s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
+static int s3c2416_cpufreq_driver_init(struct cpufreq_policy *policy)
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
struct cpufreq_frequency_table *pos;
diff --git a/drivers/cpufreq/s3c24xx-cpufreq.c b/drivers/cpufreq/s3c24xx-cpufreq.c
index d00f1cee4509..733aa5153e74 100644
--- a/drivers/cpufreq/s3c24xx-cpufreq.c
+++ b/drivers/cpufreq/s3c24xx-cpufreq.c
@@ -144,11 +144,6 @@ static void s3c_cpufreq_setfvco(struct s3c_cpufreq_config *cfg)
(cfg->info->set_fvco)(cfg);
}
-static inline void s3c_cpufreq_resume_clocks(void)
-{
- cpu_cur.info->resume_clocks();
-}
-
static inline void s3c_cpufreq_updateclk(struct clk *clk,
unsigned int freq)
{
@@ -417,9 +412,6 @@ static int s3c_cpufreq_resume(struct cpufreq_policy *policy)
last_target = ~0; /* invalidate last_target setting */
- /* first, find out what speed we resumed at. */
- s3c_cpufreq_resume_clocks();
-
/* whilst we will be called later on, we try and re-set the
* cpu frequencies as soon as possible so that we do not end
* up resuming devices and then immediately having to re-set
@@ -454,7 +446,7 @@ static struct cpufreq_driver s3c24xx_driver = {
};
-int __init s3c_cpufreq_register(struct s3c_cpufreq_info *info)
+int s3c_cpufreq_register(struct s3c_cpufreq_info *info)
{
if (!info || !info->name) {
printk(KERN_ERR "%s: failed to pass valid information\n",
diff --git a/drivers/cpufreq/sfi-cpufreq.c b/drivers/cpufreq/sfi-cpufreq.c
new file mode 100644
index 000000000000..ffa3389e535b
--- /dev/null
+++ b/drivers/cpufreq/sfi-cpufreq.c
@@ -0,0 +1,136 @@
+/*
+ * SFI Performance States Driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * Author: Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>
+ * Author: Srinidhi Kasagar <srinidhi.kasagar@intel.com>
+ */
+
+#include <linux/cpufreq.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/sfi.h>
+#include <linux/slab.h>
+#include <linux/smp.h>
+
+#include <asm/msr.h>
+
+struct cpufreq_frequency_table *freq_table;
+static struct sfi_freq_table_entry *sfi_cpufreq_array;
+static int num_freq_table_entries;
+
+static int sfi_parse_freq(struct sfi_table_header *table)
+{
+ struct sfi_table_simple *sb;
+ struct sfi_freq_table_entry *pentry;
+ int totallen;
+
+ sb = (struct sfi_table_simple *)table;
+ num_freq_table_entries = SFI_GET_NUM_ENTRIES(sb,
+ struct sfi_freq_table_entry);
+ if (num_freq_table_entries <= 1) {
+ pr_err("No p-states discovered\n");
+ return -ENODEV;
+ }
+
+ pentry = (struct sfi_freq_table_entry *)sb->pentry;
+ totallen = num_freq_table_entries * sizeof(*pentry);
+
+ sfi_cpufreq_array = kzalloc(totallen, GFP_KERNEL);
+ if (!sfi_cpufreq_array)
+ return -ENOMEM;
+
+ memcpy(sfi_cpufreq_array, pentry, totallen);
+
+ return 0;
+}
+
+static int sfi_cpufreq_target(struct cpufreq_policy *policy, unsigned int index)
+{
+ unsigned int next_perf_state = 0; /* Index into perf table */
+ u32 lo, hi;
+
+ next_perf_state = policy->freq_table[index].driver_data;
+
+ rdmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, &lo, &hi);
+ lo = (lo & ~INTEL_PERF_CTL_MASK) |
+ ((u32) sfi_cpufreq_array[next_perf_state].ctrl_val &
+ INTEL_PERF_CTL_MASK);
+ wrmsr_on_cpu(policy->cpu, MSR_IA32_PERF_CTL, lo, hi);
+
+ return 0;
+}
+
+static int sfi_cpufreq_cpu_init(struct cpufreq_policy *policy)
+{
+ policy->shared_type = CPUFREQ_SHARED_TYPE_HW;
+ policy->cpuinfo.transition_latency = 100000; /* 100us */
+
+ return cpufreq_table_validate_and_show(policy, freq_table);
+}
+
+static struct cpufreq_driver sfi_cpufreq_driver = {
+ .flags = CPUFREQ_CONST_LOOPS,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = sfi_cpufreq_target,
+ .init = sfi_cpufreq_cpu_init,
+ .name = "sfi-cpufreq",
+ .attr = cpufreq_generic_attr,
+};
+
+static int __init sfi_cpufreq_init(void)
+{
+ int ret, i;
+
+ /* parse the freq table from SFI */
+ ret = sfi_table_parse(SFI_SIG_FREQ, NULL, NULL, sfi_parse_freq);
+ if (ret)
+ return ret;
+
+ freq_table = kzalloc(sizeof(*freq_table) *
+ (num_freq_table_entries + 1), GFP_KERNEL);
+ if (!freq_table) {
+ ret = -ENOMEM;
+ goto err_free_array;
+ }
+
+ for (i = 0; i < num_freq_table_entries; i++) {
+ freq_table[i].driver_data = i;
+ freq_table[i].frequency = sfi_cpufreq_array[i].freq_mhz * 1000;
+ }
+ freq_table[i].frequency = CPUFREQ_TABLE_END;
+
+ ret = cpufreq_register_driver(&sfi_cpufreq_driver);
+ if (ret)
+ goto err_free_tbl;
+
+ return ret;
+
+err_free_tbl:
+ kfree(freq_table);
+err_free_array:
+ kfree(sfi_cpufreq_array);
+ return ret;
+}
+late_initcall(sfi_cpufreq_init);
+
+static void __exit sfi_cpufreq_exit(void)
+{
+ cpufreq_unregister_driver(&sfi_cpufreq_driver);
+ kfree(freq_table);
+ kfree(sfi_cpufreq_array);
+}
+module_exit(sfi_cpufreq_exit);
+
+MODULE_AUTHOR("Vishwesh M Rudramuni <vishwesh.m.rudramuni@intel.com>");
+MODULE_DESCRIPTION("SFI Performance-States Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/speedstep-lib.c b/drivers/cpufreq/speedstep-lib.c
index 7047821a7f8a..4ab7a2156672 100644
--- a/drivers/cpufreq/speedstep-lib.c
+++ b/drivers/cpufreq/speedstep-lib.c
@@ -400,6 +400,7 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
pr_debug("previous speed is %u\n", prev_speed);
+ preempt_disable();
local_irq_save(flags);
/* switch to low state */
@@ -464,6 +465,8 @@ unsigned int speedstep_get_freqs(enum speedstep_processor processor,
out:
local_irq_restore(flags);
+ preempt_enable();
+
return ret;
}
EXPORT_SYMBOL_GPL(speedstep_get_freqs);
diff --git a/drivers/cpufreq/speedstep-smi.c b/drivers/cpufreq/speedstep-smi.c
index 5fc96d5d656b..819229e824fb 100644
--- a/drivers/cpufreq/speedstep-smi.c
+++ b/drivers/cpufreq/speedstep-smi.c
@@ -156,6 +156,7 @@ static void speedstep_set_state(unsigned int state)
return;
/* Disable IRQs */
+ preempt_disable();
local_irq_save(flags);
command = (smi_sig & 0xffffff00) | (smi_cmd & 0xff);
@@ -166,9 +167,19 @@ static void speedstep_set_state(unsigned int state)
do {
if (retry) {
+ /*
+ * We need to enable interrupts, otherwise the blockage
+ * won't resolve.
+ *
+ * We disable preemption so that other processes don't
+ * run. If other processes were running, they could
+ * submit more DMA requests, making the blockage worse.
+ */
pr_debug("retry %u, previous result %u, waiting...\n",
retry, result);
+ local_irq_enable();
mdelay(retry * 50);
+ local_irq_disable();
}
retry++;
__asm__ __volatile__(
@@ -185,6 +196,7 @@ static void speedstep_set_state(unsigned int state)
/* enable IRQs */
local_irq_restore(flags);
+ preempt_enable();
if (new_state == state)
pr_debug("change to %u MHz succeeded after %u tries "
diff --git a/drivers/cpuidle/Kconfig.arm b/drivers/cpuidle/Kconfig.arm
index 8c16ab20fb15..8e07c9419153 100644
--- a/drivers/cpuidle/Kconfig.arm
+++ b/drivers/cpuidle/Kconfig.arm
@@ -55,6 +55,7 @@ config ARM_AT91_CPUIDLE
config ARM_EXYNOS_CPUIDLE
bool "Cpu Idle Driver for the Exynos processors"
depends on ARCH_EXYNOS
+ select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
help
Select this to enable cpuidle for Exynos processors
diff --git a/drivers/cpuidle/Kconfig.arm64 b/drivers/cpuidle/Kconfig.arm64
index d0a08ed1b2ee..6effb3656735 100644
--- a/drivers/cpuidle/Kconfig.arm64
+++ b/drivers/cpuidle/Kconfig.arm64
@@ -4,7 +4,6 @@
config ARM64_CPUIDLE
bool "Generic ARM64 CPU idle Driver"
- select ARM64_CPU_SUSPEND
select DT_IDLE_STATES
help
Select this to enable generic cpuidle driver for ARM64.
diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm64.c
index 80704b931ba4..39a2c62716c3 100644
--- a/drivers/cpuidle/cpuidle-arm64.c
+++ b/drivers/cpuidle/cpuidle-arm64.c
@@ -19,7 +19,6 @@
#include <linux/of.h>
#include <asm/cpuidle.h>
-#include <asm/suspend.h>
#include "dt_idle_states.h"
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index e3e225fe6b45..40c34faffe59 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -182,6 +182,10 @@ static int __init bl_idle_init(void)
*/
if (!of_match_node(compatible_machine_match, root))
return -ENODEV;
+
+ if (!mcpm_is_available())
+ return -EUNATCH;
+
/*
* For now the differentiation between little and big cores
* is based on the part number. A7 cores are considered little
diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c
index 4003a3160865..26f5f29fdb03 100644
--- a/drivers/cpuidle/cpuidle-exynos.c
+++ b/drivers/cpuidle/cpuidle-exynos.c
@@ -1,8 +1,11 @@
-/* linux/arch/arm/mach-exynos/cpuidle.c
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+/*
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
+ * Coupled cpuidle support based on the work of:
+ * Colin Cross <ccross@android.com>
+ * Daniel Lezcano <daniel.lezcano@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.
@@ -13,13 +16,49 @@
#include <linux/export.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/platform_data/cpuidle-exynos.h>
#include <asm/proc-fns.h>
#include <asm/suspend.h>
#include <asm/cpuidle.h>
+static atomic_t exynos_idle_barrier;
+
+static struct cpuidle_exynos_data *exynos_cpuidle_pdata;
static void (*exynos_enter_aftr)(void);
+static int exynos_enter_coupled_lowpower(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv,
+ int index)
+{
+ int ret;
+
+ exynos_cpuidle_pdata->pre_enter_aftr();
+
+ /*
+ * Waiting all cpus to reach this point at the same moment
+ */
+ cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
+
+ /*
+ * Both cpus will reach this point at the same time
+ */
+ ret = dev->cpu ? exynos_cpuidle_pdata->cpu1_powerdown()
+ : exynos_cpuidle_pdata->cpu0_enter_aftr();
+ if (ret)
+ index = ret;
+
+ /*
+ * Waiting all cpus to finish the power sequence before going further
+ */
+ cpuidle_coupled_parallel_barrier(dev, &exynos_idle_barrier);
+
+ exynos_cpuidle_pdata->post_enter_aftr();
+
+ return index;
+}
+
static int exynos_enter_lowpower(struct cpuidle_device *dev,
struct cpuidle_driver *drv,
int index)
@@ -55,13 +94,40 @@ static struct cpuidle_driver exynos_idle_driver = {
.safe_state_index = 0,
};
+static struct cpuidle_driver exynos_coupled_idle_driver = {
+ .name = "exynos_coupled_idle",
+ .owner = THIS_MODULE,
+ .states = {
+ [0] = ARM_CPUIDLE_WFI_STATE,
+ [1] = {
+ .enter = exynos_enter_coupled_lowpower,
+ .exit_latency = 5000,
+ .target_residency = 10000,
+ .flags = CPUIDLE_FLAG_COUPLED |
+ CPUIDLE_FLAG_TIMER_STOP,
+ .name = "C1",
+ .desc = "ARM power down",
+ },
+ },
+ .state_count = 2,
+ .safe_state_index = 0,
+};
+
static int exynos_cpuidle_probe(struct platform_device *pdev)
{
int ret;
- exynos_enter_aftr = (void *)(pdev->dev.platform_data);
+ if (of_machine_is_compatible("samsung,exynos4210")) {
+ exynos_cpuidle_pdata = pdev->dev.platform_data;
+
+ ret = cpuidle_register(&exynos_coupled_idle_driver,
+ cpu_possible_mask);
+ } else {
+ exynos_enter_aftr = (void *)(pdev->dev.platform_data);
+
+ ret = cpuidle_register(&exynos_idle_driver, NULL);
+ }
- ret = cpuidle_register(&exynos_idle_driver, NULL);
if (ret) {
dev_err(&pdev->dev, "failed to register cpuidle driver\n");
return ret;
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index aedec0957934..59372077ec7c 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -13,6 +13,7 @@
#include <linux/notifier.h>
#include <linux/clockchips.h>
#include <linux/of.h>
+#include <linux/slab.h>
#include <asm/machdep.h>
#include <asm/firmware.h>
@@ -158,70 +159,83 @@ static int powernv_add_idle_states(void)
struct device_node *power_mgt;
int nr_idle_states = 1; /* Snooze */
int dt_idle_states;
- const __be32 *idle_state_flags;
- const __be32 *idle_state_latency;
- u32 len_flags, flags, latency_ns;
- int i;
+ u32 *latency_ns, *residency_ns, *flags;
+ int i, rc;
/* Currently we have snooze statically defined */
power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
if (!power_mgt) {
pr_warn("opal: PowerMgmt Node not found\n");
- return nr_idle_states;
+ goto out;
}
- idle_state_flags = of_get_property(power_mgt, "ibm,cpu-idle-state-flags", &len_flags);
- if (!idle_state_flags) {
- pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-flags\n");
- return nr_idle_states;
+ /* Read values of any property to determine the num of idle states */
+ dt_idle_states = of_property_count_u32_elems(power_mgt, "ibm,cpu-idle-state-flags");
+ if (dt_idle_states < 0) {
+ pr_warn("cpuidle-powernv: no idle states found in the DT\n");
+ goto out;
}
- idle_state_latency = of_get_property(power_mgt,
- "ibm,cpu-idle-state-latencies-ns", NULL);
- if (!idle_state_latency) {
- pr_warn("DT-PowerMgmt: missing ibm,cpu-idle-state-latencies-ns\n");
- return nr_idle_states;
+ flags = kzalloc(sizeof(*flags) * dt_idle_states, GFP_KERNEL);
+ if (of_property_read_u32_array(power_mgt,
+ "ibm,cpu-idle-state-flags", flags, dt_idle_states)) {
+ pr_warn("cpuidle-powernv : missing ibm,cpu-idle-state-flags in DT\n");
+ goto out_free_flags;
}
- dt_idle_states = len_flags / sizeof(u32);
+ latency_ns = kzalloc(sizeof(*latency_ns) * dt_idle_states, GFP_KERNEL);
+ rc = of_property_read_u32_array(power_mgt,
+ "ibm,cpu-idle-state-latencies-ns", latency_ns, dt_idle_states);
+ if (rc) {
+ pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n");
+ goto out_free_latency;
+ }
- for (i = 0; i < dt_idle_states; i++) {
+ residency_ns = kzalloc(sizeof(*residency_ns) * dt_idle_states, GFP_KERNEL);
+ rc = of_property_read_u32_array(power_mgt,
+ "ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
- flags = be32_to_cpu(idle_state_flags[i]);
+ for (i = 0; i < dt_idle_states; i++) {
- /* Cpuidle accepts exit_latency in us and we estimate
- * target residency to be 10x exit_latency
+ /*
+ * Cpuidle accepts exit_latency and target_residency in us.
+ * Use default target_residency values if f/w does not expose it.
*/
- latency_ns = be32_to_cpu(idle_state_latency[i]);
- if (flags & OPAL_PM_NAP_ENABLED) {
+ if (flags[i] & OPAL_PM_NAP_ENABLED) {
/* 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 = 0;
- powernv_states[nr_idle_states].exit_latency =
- ((unsigned int)latency_ns) / 1000;
- powernv_states[nr_idle_states].target_residency =
- ((unsigned int)latency_ns / 100);
+ powernv_states[nr_idle_states].target_residency = 100;
powernv_states[nr_idle_states].enter = &nap_loop;
- nr_idle_states++;
- }
-
- if (flags & OPAL_PM_SLEEP_ENABLED ||
- flags & OPAL_PM_SLEEP_ENABLED_ER1) {
+ } else if (flags[i] & OPAL_PM_SLEEP_ENABLED ||
+ flags[i] & OPAL_PM_SLEEP_ENABLED_ER1) {
/* 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_TIMER_STOP;
- powernv_states[nr_idle_states].exit_latency =
- ((unsigned int)latency_ns) / 1000;
- powernv_states[nr_idle_states].target_residency =
- ((unsigned int)latency_ns / 100);
+ powernv_states[nr_idle_states].target_residency = 300000;
powernv_states[nr_idle_states].enter = &fastsleep_loop;
- nr_idle_states++;
}
+
+ powernv_states[nr_idle_states].exit_latency =
+ ((unsigned int)latency_ns[i]) / 1000;
+
+ if (!rc) {
+ powernv_states[nr_idle_states].target_residency =
+ ((unsigned int)residency_ns[i]) / 1000;
+ }
+
+ nr_idle_states++;
}
+ kfree(residency_ns);
+out_free_latency:
+ kfree(latency_ns);
+out_free_flags:
+ kfree(flags);
+out:
return nr_idle_states;
}
diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c
index 125150dc6e81..4d534582514e 100644
--- a/drivers/cpuidle/cpuidle.c
+++ b/drivers/cpuidle/cpuidle.c
@@ -19,6 +19,8 @@
#include <linux/ktime.h>
#include <linux/hrtimer.h>
#include <linux/module.h>
+#include <linux/suspend.h>
+#include <linux/tick.h>
#include <trace/events/power.h>
#include "cpuidle.h"
@@ -32,7 +34,6 @@ LIST_HEAD(cpuidle_detected_devices);
static int enabled_devices;
static int off __read_mostly;
static int initialized __read_mostly;
-static bool use_deepest_state __read_mostly;
int cpuidle_disabled(void)
{
@@ -66,36 +67,23 @@ int cpuidle_play_dead(void)
}
/**
- * cpuidle_use_deepest_state - Enable/disable the "deepest idle" mode.
- * @enable: Whether enable or disable the feature.
- *
- * If the "deepest idle" mode is enabled, cpuidle will ignore the governor and
- * always use the state with the greatest exit latency (out of the states that
- * are not disabled).
- *
- * This function can only be called after cpuidle_pause() to avoid races.
- */
-void cpuidle_use_deepest_state(bool enable)
-{
- use_deepest_state = enable;
-}
-
-/**
- * cpuidle_find_deepest_state - Find the state of the greatest exit latency.
- * @drv: cpuidle driver for a given CPU.
- * @dev: cpuidle device for a given CPU.
+ * cpuidle_find_deepest_state - Find deepest state meeting specific conditions.
+ * @drv: cpuidle driver for the given CPU.
+ * @dev: cpuidle device for the given CPU.
+ * @freeze: Whether or not the state should be suitable for suspend-to-idle.
*/
static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
- struct cpuidle_device *dev)
+ struct cpuidle_device *dev, bool freeze)
{
unsigned int latency_req = 0;
- int i, ret = CPUIDLE_DRIVER_STATE_START - 1;
+ int i, ret = freeze ? -1 : CPUIDLE_DRIVER_STATE_START - 1;
for (i = CPUIDLE_DRIVER_STATE_START; i < drv->state_count; i++) {
struct cpuidle_state *s = &drv->states[i];
struct cpuidle_state_usage *su = &dev->states_usage[i];
- if (s->disabled || su->disable || s->exit_latency <= latency_req)
+ if (s->disabled || su->disable || s->exit_latency <= latency_req
+ || (freeze && !s->enter_freeze))
continue;
latency_req = s->exit_latency;
@@ -104,6 +92,63 @@ static int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
return ret;
}
+static void enter_freeze_proper(struct cpuidle_driver *drv,
+ struct cpuidle_device *dev, int index)
+{
+ tick_freeze();
+ /*
+ * The state used here cannot be a "coupled" one, because the "coupled"
+ * cpuidle mechanism enables interrupts and doing that with timekeeping
+ * suspended is generally unsafe.
+ */
+ drv->states[index].enter_freeze(dev, drv, index);
+ WARN_ON(!irqs_disabled());
+ /*
+ * timekeeping_resume() that will be called by tick_unfreeze() for the
+ * last CPU executing it calls functions containing RCU read-side
+ * critical sections, so tell RCU about that.
+ */
+ RCU_NONIDLE(tick_unfreeze());
+}
+
+/**
+ * cpuidle_enter_freeze - Enter an idle state suitable for suspend-to-idle.
+ *
+ * If there are states with the ->enter_freeze callback, find the deepest of
+ * them and enter it with frozen tick. Otherwise, find the deepest state
+ * available and enter it normally.
+ */
+void cpuidle_enter_freeze(void)
+{
+ struct cpuidle_device *dev = __this_cpu_read(cpuidle_devices);
+ struct cpuidle_driver *drv = cpuidle_get_cpu_driver(dev);
+ int index;
+
+ /*
+ * Find the deepest state with ->enter_freeze present, which guarantees
+ * that interrupts won't be enabled when it exits and allows the tick to
+ * be frozen safely.
+ */
+ index = cpuidle_find_deepest_state(drv, dev, true);
+ if (index >= 0) {
+ enter_freeze_proper(drv, dev, index);
+ return;
+ }
+
+ /*
+ * It is not safe to freeze the tick, find the deepest state available
+ * at all and try to enter it normally.
+ */
+ index = cpuidle_find_deepest_state(drv, dev, false);
+ if (index >= 0)
+ cpuidle_enter(drv, dev, index);
+ else
+ arch_cpu_idle();
+
+ /* Interrupts are enabled again here. */
+ local_irq_disable();
+}
+
/**
* cpuidle_enter_state - enter the state and update stats
* @dev: cpuidle device for this cpu
@@ -166,9 +211,6 @@ int cpuidle_select(struct cpuidle_driver *drv, struct cpuidle_device *dev)
if (!drv || !dev || !dev->enabled)
return -EBUSY;
- if (unlikely(use_deepest_state))
- return cpuidle_find_deepest_state(drv, dev);
-
return cpuidle_curr_governor->select(drv, dev);
}
@@ -200,7 +242,7 @@ int cpuidle_enter(struct cpuidle_driver *drv, struct cpuidle_device *dev,
*/
void cpuidle_reflect(struct cpuidle_device *dev, int index)
{
- if (cpuidle_curr_governor->reflect && !unlikely(use_deepest_state))
+ if (cpuidle_curr_governor->reflect)
cpuidle_curr_governor->reflect(dev, index);
}
diff --git a/drivers/crypto/amcc/crypto4xx_sa.c b/drivers/crypto/amcc/crypto4xx_sa.c
index de8a7a48775a..69182e2cc3ea 100644
--- a/drivers/crypto/amcc/crypto4xx_sa.c
+++ b/drivers/crypto/amcc/crypto4xx_sa.c
@@ -34,29 +34,6 @@
#include "crypto4xx_sa.h"
#include "crypto4xx_core.h"
-u32 get_dynamic_sa_offset_iv_field(struct crypto4xx_ctx *ctx)
-{
- u32 offset;
- union dynamic_sa_contents cts;
-
- if (ctx->direction == DIR_INBOUND)
- cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_in))->sa_contents;
- else
- cts.w = ((struct dynamic_sa_ctl *)(ctx->sa_out))->sa_contents;
- offset = cts.bf.key_size
- + cts.bf.inner_size
- + cts.bf.outer_size
- + cts.bf.spi
- + cts.bf.seq_num0
- + cts.bf.seq_num1
- + cts.bf.seq_num_mask0
- + cts.bf.seq_num_mask1
- + cts.bf.seq_num_mask2
- + cts.bf.seq_num_mask3;
-
- return sizeof(struct dynamic_sa_ctl) + offset * 4;
-}
-
u32 get_dynamic_sa_offset_state_ptr_field(struct crypto4xx_ctx *ctx)
{
u32 offset;
diff --git a/drivers/crypto/atmel-aes.c b/drivers/crypto/atmel-aes.c
index 53d1c330f8a8..6597aac9905d 100644
--- a/drivers/crypto/atmel-aes.c
+++ b/drivers/crypto/atmel-aes.c
@@ -673,9 +673,9 @@ err_map_out:
dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
DMA_TO_DEVICE);
err_map_in:
+err_alloc:
free_page((unsigned long)dd->buf_out);
free_page((unsigned long)dd->buf_in);
-err_alloc:
if (err)
pr_err("error: %d\n", err);
return err;
diff --git a/drivers/crypto/atmel-sha.c b/drivers/crypto/atmel-sha.c
index d94f07c78e19..34db04addc18 100644
--- a/drivers/crypto/atmel-sha.c
+++ b/drivers/crypto/atmel-sha.c
@@ -102,10 +102,6 @@ struct atmel_sha_ctx {
struct atmel_sha_dev *dd;
unsigned long flags;
-
- /* fallback stuff */
- struct crypto_shash *fallback;
-
};
#define ATMEL_SHA_QUEUE_LENGTH 50
@@ -974,19 +970,8 @@ static int atmel_sha_digest(struct ahash_request *req)
return atmel_sha_init(req) ?: atmel_sha_finup(req);
}
-static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
+static int atmel_sha_cra_init(struct crypto_tfm *tfm)
{
- struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
- const char *alg_name = crypto_tfm_alg_name(tfm);
-
- /* Allocate a fallback and abort if it failed. */
- tctx->fallback = crypto_alloc_shash(alg_name, 0,
- CRYPTO_ALG_NEED_FALLBACK);
- if (IS_ERR(tctx->fallback)) {
- pr_err("atmel-sha: fallback driver '%s' could not be loaded.\n",
- alg_name);
- return PTR_ERR(tctx->fallback);
- }
crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
sizeof(struct atmel_sha_reqctx) +
SHA_BUFFER_LEN + SHA512_BLOCK_SIZE);
@@ -994,19 +979,6 @@ static int atmel_sha_cra_init_alg(struct crypto_tfm *tfm, const char *alg_base)
return 0;
}
-static int atmel_sha_cra_init(struct crypto_tfm *tfm)
-{
- return atmel_sha_cra_init_alg(tfm, NULL);
-}
-
-static void atmel_sha_cra_exit(struct crypto_tfm *tfm)
-{
- struct atmel_sha_ctx *tctx = crypto_tfm_ctx(tfm);
-
- crypto_free_shash(tctx->fallback);
- tctx->fallback = NULL;
-}
-
static struct ahash_alg sha_1_256_algs[] = {
{
.init = atmel_sha_init,
@@ -1020,14 +992,12 @@ static struct ahash_alg sha_1_256_algs[] = {
.cra_name = "sha1",
.cra_driver_name = "atmel-sha1",
.cra_priority = 100,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA1_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct atmel_sha_ctx),
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
.cra_init = atmel_sha_cra_init,
- .cra_exit = atmel_sha_cra_exit,
}
}
},
@@ -1043,14 +1013,12 @@ static struct ahash_alg sha_1_256_algs[] = {
.cra_name = "sha256",
.cra_driver_name = "atmel-sha256",
.cra_priority = 100,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA256_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct atmel_sha_ctx),
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
.cra_init = atmel_sha_cra_init,
- .cra_exit = atmel_sha_cra_exit,
}
}
},
@@ -1068,14 +1036,12 @@ static struct ahash_alg sha_224_alg = {
.cra_name = "sha224",
.cra_driver_name = "atmel-sha224",
.cra_priority = 100,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA224_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct atmel_sha_ctx),
.cra_alignmask = 0,
.cra_module = THIS_MODULE,
.cra_init = atmel_sha_cra_init,
- .cra_exit = atmel_sha_cra_exit,
}
}
};
@@ -1093,14 +1059,12 @@ static struct ahash_alg sha_384_512_algs[] = {
.cra_name = "sha384",
.cra_driver_name = "atmel-sha384",
.cra_priority = 100,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA384_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct atmel_sha_ctx),
.cra_alignmask = 0x3,
.cra_module = THIS_MODULE,
.cra_init = atmel_sha_cra_init,
- .cra_exit = atmel_sha_cra_exit,
}
}
},
@@ -1116,14 +1080,12 @@ static struct ahash_alg sha_384_512_algs[] = {
.cra_name = "sha512",
.cra_driver_name = "atmel-sha512",
.cra_priority = 100,
- .cra_flags = CRYPTO_ALG_ASYNC |
- CRYPTO_ALG_NEED_FALLBACK,
+ .cra_flags = CRYPTO_ALG_ASYNC,
.cra_blocksize = SHA512_BLOCK_SIZE,
.cra_ctxsize = sizeof(struct atmel_sha_ctx),
.cra_alignmask = 0x3,
.cra_module = THIS_MODULE,
.cra_init = atmel_sha_cra_init,
- .cra_exit = atmel_sha_cra_exit,
}
}
},
diff --git a/drivers/crypto/atmel-tdes.c b/drivers/crypto/atmel-tdes.c
index 5e7c896cde30..258772d9b22f 100644
--- a/drivers/crypto/atmel-tdes.c
+++ b/drivers/crypto/atmel-tdes.c
@@ -376,9 +376,9 @@ err_map_out:
dma_unmap_single(dd->dev, dd->dma_addr_in, dd->buflen,
DMA_TO_DEVICE);
err_map_in:
+err_alloc:
free_page((unsigned long)dd->buf_out);
free_page((unsigned long)dd->buf_in);
-err_alloc:
if (err)
pr_err("error: %d\n", err);
return err;
diff --git a/drivers/crypto/bfin_crc.c b/drivers/crypto/bfin_crc.c
index 9ae149bddb6e..d9af9403ab6c 100644
--- a/drivers/crypto/bfin_crc.c
+++ b/drivers/crypto/bfin_crc.c
@@ -110,7 +110,7 @@ static int sg_count(struct scatterlist *sg_list)
while (!sg_is_last(sg)) {
sg_nents++;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
return sg_nents;
@@ -744,7 +744,7 @@ static int __init bfin_crypto_crc_mod_init(void)
ret = platform_driver_register(&bfin_crypto_crc_driver);
if (ret) {
- pr_info(KERN_ERR "unable to register driver\n");
+ pr_err("unable to register driver\n");
return ret;
}
diff --git a/drivers/crypto/caam/caamalg.c b/drivers/crypto/caam/caamalg.c
index 3187400daf31..29071a156cbe 100644
--- a/drivers/crypto/caam/caamalg.c
+++ b/drivers/crypto/caam/caamalg.c
@@ -2532,7 +2532,7 @@ static void init_ablkcipher_job(u32 *sh_desc, dma_addr_t ptr,
in_options = 0;
} else {
src_dma = edesc->sec4_sg_dma;
- sec4_sg_index += (iv_contig ? 0 : 1) + edesc->src_nents;
+ sec4_sg_index += edesc->src_nents + 1;
in_options = LDST_SGF;
}
append_seq_in_ptr(desc, src_dma, req->nbytes + ivsize, in_options);
@@ -2714,10 +2714,10 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (!all_contig) {
if (!is_gcm) {
sg_to_sec4_sg(req->assoc,
- (assoc_nents ? : 1),
+ assoc_nents,
edesc->sec4_sg +
sec4_sg_index, 0);
- sec4_sg_index += assoc_nents ? : 1;
+ sec4_sg_index += assoc_nents;
}
dma_to_sec4_sg_one(edesc->sec4_sg + sec4_sg_index,
@@ -2726,17 +2726,17 @@ static struct aead_edesc *aead_edesc_alloc(struct aead_request *req,
if (is_gcm) {
sg_to_sec4_sg(req->assoc,
- (assoc_nents ? : 1),
+ assoc_nents,
edesc->sec4_sg +
sec4_sg_index, 0);
- sec4_sg_index += assoc_nents ? : 1;
+ sec4_sg_index += assoc_nents;
}
sg_to_sec4_sg_last(req->src,
- (src_nents ? : 1),
+ src_nents,
edesc->sec4_sg +
sec4_sg_index, 0);
- sec4_sg_index += src_nents ? : 1;
+ sec4_sg_index += src_nents;
}
if (dst_nents) {
sg_to_sec4_sg_last(req->dst, dst_nents,
diff --git a/drivers/crypto/caam/ctrl.c b/drivers/crypto/caam/ctrl.c
index 70f1e6f37336..efba4ccd4fac 100644
--- a/drivers/crypto/caam/ctrl.c
+++ b/drivers/crypto/caam/ctrl.c
@@ -175,13 +175,10 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
{
struct caam_drv_private *ctrlpriv = dev_get_drvdata(ctrldev);
struct caam_ctrl __iomem *ctrl;
- struct rng4tst __iomem *r4tst;
u32 *desc, status, rdsta_val;
int ret = 0, sh_idx;
ctrl = (struct caam_ctrl __iomem *)ctrlpriv->ctrl;
- r4tst = &ctrl->r4tst[0];
-
desc = kmalloc(CAAM_CMD_SZ * 7, GFP_KERNEL);
if (!desc)
return -ENOMEM;
@@ -209,8 +206,7 @@ static int instantiate_rng(struct device *ctrldev, int state_handle_mask,
* without any error (HW optimizations for later
* CAAM eras), then try again.
*/
- rdsta_val =
- rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
+ rdsta_val = rd_reg32(&ctrl->r4tst[0].rdsta) & RDSTA_IFMASK;
if (status || !(rdsta_val & (1 << sh_idx)))
ret = -EAGAIN;
if (ret)
diff --git a/drivers/crypto/caam/error.c b/drivers/crypto/caam/error.c
index 66d73bf54166..33e41ea83fcc 100644
--- a/drivers/crypto/caam/error.c
+++ b/drivers/crypto/caam/error.c
@@ -151,10 +151,15 @@ static void report_ccb_status(struct device *jrdev, const u32 status,
else
snprintf(err_err_code, sizeof(err_err_code), "%02x", err_id);
- dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n",
- status, error, idx_str, idx,
- cha_str, cha_err_code,
- err_str, err_err_code);
+ /*
+ * CCB ICV check failures are part of normal operation life;
+ * we leave the upper layers to do what they want with them.
+ */
+ if (err_id != JRSTA_CCBERR_ERRID_ICVCHK)
+ dev_err(jrdev, "%08x: %s: %s %d: %s%s: %s%s\n",
+ status, error, idx_str, idx,
+ cha_str, cha_err_code,
+ err_str, err_err_code);
}
static void report_jump_status(struct device *jrdev, const u32 status,
diff --git a/drivers/crypto/caam/jr.c b/drivers/crypto/caam/jr.c
index 9b3ef1bc9bd7..b8b5d47acd7a 100644
--- a/drivers/crypto/caam/jr.c
+++ b/drivers/crypto/caam/jr.c
@@ -384,30 +384,28 @@ static int caam_jr_init(struct device *dev)
if (error) {
dev_err(dev, "can't connect JobR %d interrupt (%d)\n",
jrp->ridx, jrp->irq);
- irq_dispose_mapping(jrp->irq);
- jrp->irq = 0;
- return -EINVAL;
+ goto out_kill_deq;
}
error = caam_reset_hw_jr(dev);
if (error)
- return error;
+ goto out_free_irq;
+ error = -ENOMEM;
jrp->inpring = dma_alloc_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH,
&inpbusaddr, GFP_KERNEL);
+ if (!jrp->inpring)
+ goto out_free_irq;
jrp->outring = dma_alloc_coherent(dev, sizeof(struct jr_outentry) *
JOBR_DEPTH, &outbusaddr, GFP_KERNEL);
+ if (!jrp->outring)
+ goto out_free_inpring;
jrp->entinfo = kzalloc(sizeof(struct caam_jrentry_info) * JOBR_DEPTH,
GFP_KERNEL);
-
- if ((jrp->inpring == NULL) || (jrp->outring == NULL) ||
- (jrp->entinfo == NULL)) {
- dev_err(dev, "can't allocate job rings for %d\n",
- jrp->ridx);
- return -ENOMEM;
- }
+ if (!jrp->entinfo)
+ goto out_free_outring;
for (i = 0; i < JOBR_DEPTH; i++)
jrp->entinfo[i].desc_addr_dma = !0;
@@ -434,6 +432,19 @@ static int caam_jr_init(struct device *dev)
(JOBR_INTC_TIME_THLD << JRCFG_ICTT_SHIFT));
return 0;
+
+out_free_outring:
+ dma_free_coherent(dev, sizeof(struct jr_outentry) * JOBR_DEPTH,
+ jrp->outring, outbusaddr);
+out_free_inpring:
+ dma_free_coherent(dev, sizeof(dma_addr_t) * JOBR_DEPTH,
+ jrp->inpring, inpbusaddr);
+ dev_err(dev, "can't allocate job rings for %d\n", jrp->ridx);
+out_free_irq:
+ free_irq(jrp->irq, dev);
+out_kill_deq:
+ tasklet_kill(&jrp->irqtask);
+ return error;
}
@@ -484,8 +495,10 @@ static int caam_jr_probe(struct platform_device *pdev)
/* Now do the platform independent part */
error = caam_jr_init(jrdev); /* now turn on hardware */
- if (error)
+ if (error) {
+ irq_dispose_mapping(jrpriv->irq);
return error;
+ }
jrpriv->dev = jrdev;
spin_lock(&driver_data.jr_alloc_lock);
diff --git a/drivers/crypto/caam/sg_sw_sec4.h b/drivers/crypto/caam/sg_sw_sec4.h
index ce28a563effc..3b918218aa4c 100644
--- a/drivers/crypto/caam/sg_sw_sec4.h
+++ b/drivers/crypto/caam/sg_sw_sec4.h
@@ -37,7 +37,7 @@ sg_to_sec4_sg(struct scatterlist *sg, int sg_count,
dma_to_sec4_sg_one(sec4_sg_ptr, sg_dma_address(sg),
sg_dma_len(sg), offset);
sec4_sg_ptr++;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
sg_count--;
}
return sec4_sg_ptr - 1;
@@ -67,7 +67,7 @@ static inline int __sg_count(struct scatterlist *sg_list, int nbytes,
nbytes -= sg->length;
if (!sg_is_last(sg) && (sg + 1)->length == 0)
*chained = true;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
return sg_nents;
@@ -93,7 +93,7 @@ static int dma_map_sg_chained(struct device *dev, struct scatterlist *sg,
int i;
for (i = 0; i < nents; i++) {
dma_map_sg(dev, sg, 1, dir);
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
} else {
dma_map_sg(dev, sg, nents, dir);
@@ -109,7 +109,7 @@ static int dma_unmap_sg_chained(struct device *dev, struct scatterlist *sg,
int i;
for (i = 0; i < nents; i++) {
dma_unmap_sg(dev, sg, 1, dir);
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
} else {
dma_unmap_sg(dev, sg, nents, dir);
diff --git a/drivers/crypto/ccp/ccp-dev.c b/drivers/crypto/ccp/ccp-dev.c
index c6e6171eb6d3..ca29c120b85f 100644
--- a/drivers/crypto/ccp/ccp-dev.c
+++ b/drivers/crypto/ccp/ccp-dev.c
@@ -583,6 +583,7 @@ bool ccp_queues_suspended(struct ccp_device *ccp)
#ifdef CONFIG_X86
static const struct x86_cpu_id ccp_support[] = {
{ X86_VENDOR_AMD, 22, },
+ { },
};
#endif
diff --git a/drivers/crypto/ixp4xx_crypto.c b/drivers/crypto/ixp4xx_crypto.c
index f757a0f428bd..48f453555f1f 100644
--- a/drivers/crypto/ixp4xx_crypto.c
+++ b/drivers/crypto/ixp4xx_crypto.c
@@ -784,7 +784,7 @@ static struct buffer_desc *chainup_buffers(struct device *dev,
struct buffer_desc *buf, gfp_t flags,
enum dma_data_direction dir)
{
- for (;nbytes > 0; sg = scatterwalk_sg_next(sg)) {
+ for (; nbytes > 0; sg = sg_next(sg)) {
unsigned len = min(nbytes, sg->length);
struct buffer_desc *next_buf;
u32 next_buf_phys;
@@ -982,7 +982,7 @@ static int hmac_inconsistent(struct scatterlist *sg, unsigned start,
break;
offset += sg->length;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
return (start + nbytes > offset + sg->length);
}
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c
index a392465d3e3f..1da6dc59d0dd 100644
--- a/drivers/crypto/nx/nx.c
+++ b/drivers/crypto/nx/nx.c
@@ -177,7 +177,7 @@ struct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst,
break;
offset += sg_src->length;
- sg_src = scatterwalk_sg_next(sg_src);
+ sg_src = sg_next(sg_src);
}
/* start - offset is the number of bytes to advance in the scatterlist
@@ -187,9 +187,9 @@ struct nx_sg *nx_walk_and_build(struct nx_sg *nx_dst,
while (len && (nx_sg - nx_dst) < sglen) {
n = scatterwalk_clamp(&walk, len);
if (!n) {
- /* In cases where we have scatterlist chain scatterwalk_sg_next
+ /* In cases where we have scatterlist chain sg_next
* handles with it properly */
- scatterwalk_start(&walk, scatterwalk_sg_next(walk.sg));
+ scatterwalk_start(&walk, sg_next(walk.sg));
n = scatterwalk_clamp(&walk, len);
}
dst = scatterwalk_map(&walk);
diff --git a/drivers/crypto/omap-aes.c b/drivers/crypto/omap-aes.c
index f79dd410dede..42f95a4326b0 100644
--- a/drivers/crypto/omap-aes.c
+++ b/drivers/crypto/omap-aes.c
@@ -994,7 +994,7 @@ static irqreturn_t omap_aes_irq(int irq, void *dev_id)
scatterwalk_advance(&dd->in_walk, 4);
if (dd->in_sg->length == _calc_walked(in)) {
- dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+ dd->in_sg = sg_next(dd->in_sg);
if (dd->in_sg) {
scatterwalk_start(&dd->in_walk,
dd->in_sg);
@@ -1026,7 +1026,7 @@ static irqreturn_t omap_aes_irq(int irq, void *dev_id)
*dst = omap_aes_read(dd, AES_REG_DATA_N(dd, i));
scatterwalk_advance(&dd->out_walk, 4);
if (dd->out_sg->length == _calc_walked(out)) {
- dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+ dd->out_sg = sg_next(dd->out_sg);
if (dd->out_sg) {
scatterwalk_start(&dd->out_walk,
dd->out_sg);
diff --git a/drivers/crypto/omap-des.c b/drivers/crypto/omap-des.c
index e350f5be4d2e..46307098f8ba 100644
--- a/drivers/crypto/omap-des.c
+++ b/drivers/crypto/omap-des.c
@@ -921,7 +921,7 @@ static irqreturn_t omap_des_irq(int irq, void *dev_id)
scatterwalk_advance(&dd->in_walk, 4);
if (dd->in_sg->length == _calc_walked(in)) {
- dd->in_sg = scatterwalk_sg_next(dd->in_sg);
+ dd->in_sg = sg_next(dd->in_sg);
if (dd->in_sg) {
scatterwalk_start(&dd->in_walk,
dd->in_sg);
@@ -953,7 +953,7 @@ static irqreturn_t omap_des_irq(int irq, void *dev_id)
*dst = omap_des_read(dd, DES_REG_DATA_N(dd, i));
scatterwalk_advance(&dd->out_walk, 4);
if (dd->out_sg->length == _calc_walked(out)) {
- dd->out_sg = scatterwalk_sg_next(dd->out_sg);
+ dd->out_sg = sg_next(dd->out_sg);
if (dd->out_sg) {
scatterwalk_start(&dd->out_walk,
dd->out_sg);
@@ -965,9 +965,9 @@ static irqreturn_t omap_des_irq(int irq, void *dev_id)
}
}
- dd->total -= DES_BLOCK_SIZE;
+ BUG_ON(dd->total < DES_BLOCK_SIZE);
- BUG_ON(dd->total < 0);
+ dd->total -= DES_BLOCK_SIZE;
/* Clear IRQ status */
status &= ~DES_REG_IRQ_DATA_OUT;
diff --git a/drivers/crypto/qat/qat_common/adf_accel_devices.h b/drivers/crypto/qat/qat_common/adf_accel_devices.h
index 2ed425664a16..19c0efa29ab3 100644
--- a/drivers/crypto/qat/qat_common/adf_accel_devices.h
+++ b/drivers/crypto/qat/qat_common/adf_accel_devices.h
@@ -47,7 +47,6 @@
#ifndef ADF_ACCEL_DEVICES_H_
#define ADF_ACCEL_DEVICES_H_
#include <linux/module.h>
-#include <linux/atomic.h>
#include <linux/list.h>
#include <linux/proc_fs.h>
#include <linux/io.h>
@@ -148,6 +147,11 @@ struct adf_hw_device_data {
int (*alloc_irq)(struct adf_accel_dev *accel_dev);
void (*free_irq)(struct adf_accel_dev *accel_dev);
void (*enable_error_correction)(struct adf_accel_dev *accel_dev);
+ int (*init_admin_comms)(struct adf_accel_dev *accel_dev);
+ void (*exit_admin_comms)(struct adf_accel_dev *accel_dev);
+ int (*init_arb)(struct adf_accel_dev *accel_dev);
+ void (*exit_arb)(struct adf_accel_dev *accel_dev);
+ void (*enable_ints)(struct adf_accel_dev *accel_dev);
const char *fw_name;
uint32_t pci_dev_id;
uint32_t fuses;
diff --git a/drivers/crypto/qat/qat_common/adf_aer.c b/drivers/crypto/qat/qat_common/adf_aer.c
index 10ce4a2854ab..fa1fef824de2 100644
--- a/drivers/crypto/qat/qat_common/adf_aer.c
+++ b/drivers/crypto/qat/qat_common/adf_aer.c
@@ -82,28 +82,15 @@ struct adf_reset_dev_data {
struct work_struct reset_work;
};
-#define PPDSTAT_OFFSET 0x7E
static void adf_dev_restore(struct adf_accel_dev *accel_dev)
{
struct pci_dev *pdev = accel_to_pci_dev(accel_dev);
struct pci_dev *parent = pdev->bus->self;
- uint16_t ppdstat = 0, bridge_ctl = 0;
- int pending = 0;
+ uint16_t bridge_ctl = 0;
pr_info("QAT: Resetting device qat_dev%d\n", accel_dev->accel_id);
- pci_read_config_word(pdev, PPDSTAT_OFFSET, &ppdstat);
- pending = ppdstat & PCI_EXP_DEVSTA_TRPND;
- if (pending) {
- int ctr = 0;
-
- do {
- msleep(100);
- pci_read_config_word(pdev, PPDSTAT_OFFSET, &ppdstat);
- pending = ppdstat & PCI_EXP_DEVSTA_TRPND;
- } while (pending && ctr++ < 10);
- }
- if (pending)
+ if (!pci_wait_for_pending_transaction(pdev))
pr_info("QAT: Transaction still in progress. Proceeding\n");
pci_read_config_word(parent, PCI_BRIDGE_CONTROL, &bridge_ctl);
@@ -125,8 +112,9 @@ static void adf_device_reset_worker(struct work_struct *work)
adf_dev_restarting_notify(accel_dev);
adf_dev_stop(accel_dev);
+ adf_dev_shutdown(accel_dev);
adf_dev_restore(accel_dev);
- if (adf_dev_start(accel_dev)) {
+ if (adf_dev_init(accel_dev) || adf_dev_start(accel_dev)) {
/* The device hanged and we can't restart it so stop here */
dev_err(&GET_DEV(accel_dev), "Restart device failed\n");
kfree(reset_data);
@@ -148,8 +136,8 @@ static int adf_dev_aer_schedule_reset(struct adf_accel_dev *accel_dev,
{
struct adf_reset_dev_data *reset_data;
- if (adf_dev_started(accel_dev) &&
- !test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
+ if (!adf_dev_started(accel_dev) ||
+ test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
return 0;
set_bit(ADF_STATUS_RESTARTING, &accel_dev->status);
diff --git a/drivers/crypto/qat/qat_common/adf_cfg.c b/drivers/crypto/qat/qat_common/adf_cfg.c
index aba7f1d043fb..de16da9070a5 100644
--- a/drivers/crypto/qat/qat_common/adf_cfg.c
+++ b/drivers/crypto/qat/qat_common/adf_cfg.c
@@ -50,6 +50,7 @@
#include <linux/seq_file.h>
#include "adf_accel_devices.h"
#include "adf_cfg.h"
+#include "adf_common_drv.h"
static DEFINE_MUTEX(qat_cfg_read_lock);
@@ -159,6 +160,7 @@ void adf_cfg_del_all(struct adf_accel_dev *accel_dev)
down_write(&dev_cfg_data->lock);
adf_cfg_section_del_all(&dev_cfg_data->sec_list);
up_write(&dev_cfg_data->lock);
+ clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
}
/**
diff --git a/drivers/crypto/qat/qat_common/adf_common_drv.h b/drivers/crypto/qat/qat_common/adf_common_drv.h
index 5e8f9d431e5d..a62e485c8786 100644
--- a/drivers/crypto/qat/qat_common/adf_common_drv.h
+++ b/drivers/crypto/qat/qat_common/adf_common_drv.h
@@ -93,7 +93,7 @@ int adf_service_unregister(struct service_hndl *service);
int adf_dev_init(struct adf_accel_dev *accel_dev);
int adf_dev_start(struct adf_accel_dev *accel_dev);
int adf_dev_stop(struct adf_accel_dev *accel_dev);
-int adf_dev_shutdown(struct adf_accel_dev *accel_dev);
+void adf_dev_shutdown(struct adf_accel_dev *accel_dev);
int adf_ctl_dev_register(void);
void adf_ctl_dev_unregister(void);
diff --git a/drivers/crypto/qat/qat_common/adf_ctl_drv.c b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
index 7ee93f881db6..74207a6f0516 100644
--- a/drivers/crypto/qat/qat_common/adf_ctl_drv.c
+++ b/drivers/crypto/qat/qat_common/adf_ctl_drv.c
@@ -282,6 +282,8 @@ static int adf_ctl_stop_devices(uint32_t id)
if (adf_dev_stop(accel_dev)) {
pr_err("QAT: Failed to stop qat_dev%d\n", id);
ret = -EFAULT;
+ } else {
+ adf_dev_shutdown(accel_dev);
}
}
}
@@ -343,7 +345,9 @@ static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd,
if (!adf_dev_started(accel_dev)) {
pr_info("QAT: Starting acceleration device qat_dev%d.\n",
ctl_data->device_id);
- ret = adf_dev_start(accel_dev);
+ ret = adf_dev_init(accel_dev);
+ if (!ret)
+ ret = adf_dev_start(accel_dev);
} else {
pr_info("QAT: Acceleration device qat_dev%d already started.\n",
ctl_data->device_id);
@@ -351,6 +355,7 @@ static int adf_ctl_ioctl_dev_start(struct file *fp, unsigned int cmd,
if (ret) {
pr_err("QAT: Failed to start qat_dev%d\n", ctl_data->device_id);
adf_dev_stop(accel_dev);
+ adf_dev_shutdown(accel_dev);
}
out:
kfree(ctl_data);
diff --git a/drivers/crypto/qat/qat_common/adf_init.c b/drivers/crypto/qat/qat_common/adf_init.c
index 5c0e47a00a87..8f0ca498ab87 100644
--- a/drivers/crypto/qat/qat_common/adf_init.c
+++ b/drivers/crypto/qat/qat_common/adf_init.c
@@ -108,26 +108,47 @@ int adf_service_unregister(struct service_hndl *service)
EXPORT_SYMBOL_GPL(adf_service_unregister);
/**
- * adf_dev_start() - Start acceleration service for the given accel device
- * @accel_dev: Pointer to acceleration device.
+ * adf_dev_init() - Init data structures and services for the given accel device
+ * @accel_dev: Pointer to acceleration device.
*
- * Function notifies all the registered services that the acceleration device
- * is ready to be used.
- * To be used by QAT device specific drivers.
+ * Initialize the ring data structures and the admin comms and arbitration
+ * services.
*
* Return: 0 on success, error code othewise.
*/
-int adf_dev_start(struct adf_accel_dev *accel_dev)
+int adf_dev_init(struct adf_accel_dev *accel_dev)
{
struct service_hndl *service;
struct list_head *list_itr;
struct adf_hw_device_data *hw_data = accel_dev->hw_device;
+ if (!hw_data) {
+ dev_err(&GET_DEV(accel_dev),
+ "QAT: Failed to init device - hw_data not set\n");
+ return -EFAULT;
+ }
+
if (!test_bit(ADF_STATUS_CONFIGURED, &accel_dev->status)) {
pr_info("QAT: Device not configured\n");
return -EFAULT;
}
- set_bit(ADF_STATUS_STARTING, &accel_dev->status);
+
+ if (adf_init_etr_data(accel_dev)) {
+ dev_err(&GET_DEV(accel_dev), "Failed initialize etr\n");
+ return -EFAULT;
+ }
+
+ if (hw_data->init_admin_comms && hw_data->init_admin_comms(accel_dev)) {
+ dev_err(&GET_DEV(accel_dev), "Failed initialize admin comms\n");
+ return -EFAULT;
+ }
+
+ if (hw_data->init_arb && hw_data->init_arb(accel_dev)) {
+ dev_err(&GET_DEV(accel_dev), "Failed initialize hw arbiter\n");
+ return -EFAULT;
+ }
+
+ hw_data->enable_ints(accel_dev);
if (adf_ae_init(accel_dev)) {
pr_err("QAT: Failed to initialise Acceleration Engine\n");
@@ -178,6 +199,27 @@ int adf_dev_start(struct adf_accel_dev *accel_dev)
hw_data->enable_error_correction(accel_dev);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adf_dev_init);
+
+/**
+ * adf_dev_start() - Start acceleration service for the given accel device
+ * @accel_dev: Pointer to acceleration device.
+ *
+ * Function notifies all the registered services that the acceleration device
+ * is ready to be used.
+ * To be used by QAT device specific drivers.
+ *
+ * Return: 0 on success, error code othewise.
+ */
+int adf_dev_start(struct adf_accel_dev *accel_dev)
+{
+ struct service_hndl *service;
+ struct list_head *list_itr;
+
+ set_bit(ADF_STATUS_STARTING, &accel_dev->status);
+
if (adf_ae_start(accel_dev)) {
pr_err("QAT: AE Start Failed\n");
return -EFAULT;
@@ -232,16 +274,15 @@ EXPORT_SYMBOL_GPL(adf_dev_start);
*/
int adf_dev_stop(struct adf_accel_dev *accel_dev)
{
- struct adf_hw_device_data *hw_data = accel_dev->hw_device;
struct service_hndl *service;
struct list_head *list_itr;
- int ret, wait = 0;
+ bool wait = false;
+ int ret;
if (!adf_dev_started(accel_dev) &&
!test_bit(ADF_STATUS_STARTING, &accel_dev->status)) {
return 0;
}
- clear_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
clear_bit(ADF_STATUS_STARTING, &accel_dev->status);
clear_bit(ADF_STATUS_STARTED, &accel_dev->status);
@@ -258,7 +299,7 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
if (!ret) {
clear_bit(accel_dev->accel_id, &service->start_status);
} else if (ret == -EAGAIN) {
- wait = 1;
+ wait = true;
clear_bit(accel_dev->accel_id, &service->start_status);
}
}
@@ -278,13 +319,36 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
if (wait)
msleep(100);
- if (adf_dev_started(accel_dev)) {
+ if (test_bit(ADF_STATUS_AE_STARTED, &accel_dev->status)) {
if (adf_ae_stop(accel_dev))
pr_err("QAT: failed to stop AE\n");
else
clear_bit(ADF_STATUS_AE_STARTED, &accel_dev->status);
}
+ return 0;
+}
+EXPORT_SYMBOL_GPL(adf_dev_stop);
+
+/**
+ * adf_dev_shutdown() - shutdown acceleration services and data strucutures
+ * @accel_dev: Pointer to acceleration device
+ *
+ * Cleanup the ring data structures and the admin comms and arbitration
+ * services.
+ */
+void adf_dev_shutdown(struct adf_accel_dev *accel_dev)
+{
+ struct adf_hw_device_data *hw_data = accel_dev->hw_device;
+ struct service_hndl *service;
+ struct list_head *list_itr;
+
+ if (!hw_data) {
+ dev_err(&GET_DEV(accel_dev),
+ "QAT: Failed to shutdown device - hw_data not set\n");
+ return;
+ }
+
if (test_bit(ADF_STATUS_AE_UCODE_LOADED, &accel_dev->status)) {
if (adf_ae_fw_release(accel_dev))
pr_err("QAT: Failed to release the ucode\n");
@@ -335,9 +399,15 @@ int adf_dev_stop(struct adf_accel_dev *accel_dev)
if (!test_bit(ADF_STATUS_RESTARTING, &accel_dev->status))
adf_cfg_del_all(accel_dev);
- return 0;
+ if (hw_data->exit_arb)
+ hw_data->exit_arb(accel_dev);
+
+ if (hw_data->exit_admin_comms)
+ hw_data->exit_admin_comms(accel_dev);
+
+ adf_cleanup_etr_data(accel_dev);
}
-EXPORT_SYMBOL_GPL(adf_dev_stop);
+EXPORT_SYMBOL_GPL(adf_dev_shutdown);
int adf_dev_restarting_notify(struct adf_accel_dev *accel_dev)
{
diff --git a/drivers/crypto/qat/qat_common/adf_transport_internal.h b/drivers/crypto/qat/qat_common/adf_transport_internal.h
index c40546079981..a4869627fd57 100644
--- a/drivers/crypto/qat/qat_common/adf_transport_internal.h
+++ b/drivers/crypto/qat/qat_common/adf_transport_internal.h
@@ -48,7 +48,6 @@
#define ADF_TRANSPORT_INTRN_H
#include <linux/interrupt.h>
-#include <linux/atomic.h>
#include <linux/spinlock_types.h>
#include "adf_transport.h"
diff --git a/drivers/crypto/qat/qat_common/icp_qat_hw.h b/drivers/crypto/qat/qat_common/icp_qat_hw.h
index 5031f8c10d75..68f191b653b0 100644
--- a/drivers/crypto/qat/qat_common/icp_qat_hw.h
+++ b/drivers/crypto/qat/qat_common/icp_qat_hw.h
@@ -301,5 +301,5 @@ struct icp_qat_hw_cipher_aes256_f8 {
struct icp_qat_hw_cipher_algo_blk {
struct icp_qat_hw_cipher_aes256_f8 aes;
-};
+} __aligned(64);
#endif
diff --git a/drivers/crypto/qat/qat_common/qat_algs.c b/drivers/crypto/qat/qat_common/qat_algs.c
index 19eea1c832ac..1dc5b0a17cf7 100644
--- a/drivers/crypto/qat/qat_common/qat_algs.c
+++ b/drivers/crypto/qat/qat_common/qat_algs.c
@@ -63,15 +63,15 @@
#include "icp_qat_fw.h"
#include "icp_qat_fw_la.h"
-#define QAT_AES_HW_CONFIG_ENC(alg) \
+#define QAT_AES_HW_CONFIG_CBC_ENC(alg) \
ICP_QAT_HW_CIPHER_CONFIG_BUILD(ICP_QAT_HW_CIPHER_CBC_MODE, alg, \
- ICP_QAT_HW_CIPHER_NO_CONVERT, \
- ICP_QAT_HW_CIPHER_ENCRYPT)
+ ICP_QAT_HW_CIPHER_NO_CONVERT, \
+ ICP_QAT_HW_CIPHER_ENCRYPT)
-#define QAT_AES_HW_CONFIG_DEC(alg) \
+#define QAT_AES_HW_CONFIG_CBC_DEC(alg) \
ICP_QAT_HW_CIPHER_CONFIG_BUILD(ICP_QAT_HW_CIPHER_CBC_MODE, alg, \
- ICP_QAT_HW_CIPHER_KEY_CONVERT, \
- ICP_QAT_HW_CIPHER_DECRYPT)
+ ICP_QAT_HW_CIPHER_KEY_CONVERT, \
+ ICP_QAT_HW_CIPHER_DECRYPT)
static atomic_t active_dev;
@@ -102,25 +102,31 @@ struct qat_alg_cd {
};
} __aligned(64);
-#define MAX_AUTH_STATE_SIZE sizeof(struct icp_qat_hw_auth_algo_blk)
-
-struct qat_auth_state {
- uint8_t data[MAX_AUTH_STATE_SIZE + 64];
-} __aligned(64);
-
-struct qat_alg_session_ctx {
+struct qat_alg_aead_ctx {
struct qat_alg_cd *enc_cd;
- dma_addr_t enc_cd_paddr;
struct qat_alg_cd *dec_cd;
+ dma_addr_t enc_cd_paddr;
dma_addr_t dec_cd_paddr;
- struct icp_qat_fw_la_bulk_req enc_fw_req_tmpl;
- struct icp_qat_fw_la_bulk_req dec_fw_req_tmpl;
- struct qat_crypto_instance *inst;
- struct crypto_tfm *tfm;
+ struct icp_qat_fw_la_bulk_req enc_fw_req;
+ struct icp_qat_fw_la_bulk_req dec_fw_req;
struct crypto_shash *hash_tfm;
enum icp_qat_hw_auth_algo qat_hash_alg;
+ struct qat_crypto_instance *inst;
+ struct crypto_tfm *tfm;
uint8_t salt[AES_BLOCK_SIZE];
- spinlock_t lock; /* protects qat_alg_session_ctx struct */
+ spinlock_t lock; /* protects qat_alg_aead_ctx struct */
+};
+
+struct qat_alg_ablkcipher_ctx {
+ struct icp_qat_hw_cipher_algo_blk *enc_cd;
+ struct icp_qat_hw_cipher_algo_blk *dec_cd;
+ dma_addr_t enc_cd_paddr;
+ dma_addr_t dec_cd_paddr;
+ struct icp_qat_fw_la_bulk_req enc_fw_req;
+ struct icp_qat_fw_la_bulk_req dec_fw_req;
+ struct qat_crypto_instance *inst;
+ struct crypto_tfm *tfm;
+ spinlock_t lock; /* protects qat_alg_ablkcipher_ctx struct */
};
static int get_current_node(void)
@@ -144,43 +150,37 @@ static int qat_get_inter_state_size(enum icp_qat_hw_auth_algo qat_hash_alg)
}
static int qat_alg_do_precomputes(struct icp_qat_hw_auth_algo_blk *hash,
- struct qat_alg_session_ctx *ctx,
+ struct qat_alg_aead_ctx *ctx,
const uint8_t *auth_key,
unsigned int auth_keylen)
{
- struct qat_auth_state auth_state;
SHASH_DESC_ON_STACK(shash, ctx->hash_tfm);
struct sha1_state sha1;
struct sha256_state sha256;
struct sha512_state sha512;
int block_size = crypto_shash_blocksize(ctx->hash_tfm);
int digest_size = crypto_shash_digestsize(ctx->hash_tfm);
- uint8_t *ipad = auth_state.data;
- uint8_t *opad = ipad + block_size;
+ char ipad[block_size];
+ char opad[block_size];
__be32 *hash_state_out;
__be64 *hash512_state_out;
int i, offset;
- memzero_explicit(auth_state.data, MAX_AUTH_STATE_SIZE + 64);
+ memset(ipad, 0, block_size);
+ memset(opad, 0, block_size);
shash->tfm = ctx->hash_tfm;
shash->flags = 0x0;
if (auth_keylen > block_size) {
- char buff[SHA512_BLOCK_SIZE];
int ret = crypto_shash_digest(shash, auth_key,
- auth_keylen, buff);
+ auth_keylen, ipad);
if (ret)
return ret;
- memcpy(ipad, buff, digest_size);
- memcpy(opad, buff, digest_size);
- memzero_explicit(ipad + digest_size, block_size - digest_size);
- memzero_explicit(opad + digest_size, block_size - digest_size);
+ memcpy(opad, ipad, digest_size);
} else {
memcpy(ipad, auth_key, auth_keylen);
memcpy(opad, auth_key, auth_keylen);
- memzero_explicit(ipad + auth_keylen, block_size - auth_keylen);
- memzero_explicit(opad + auth_keylen, block_size - auth_keylen);
}
for (i = 0; i < block_size; i++) {
@@ -267,8 +267,6 @@ static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header)
header->comn_req_flags =
ICP_QAT_FW_COMN_FLAGS_BUILD(QAT_COMN_CD_FLD_TYPE_64BIT_ADR,
QAT_COMN_PTR_TYPE_SGL);
- ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
- ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
ICP_QAT_FW_LA_PARTIAL_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_PARTIAL_NONE);
ICP_QAT_FW_LA_CIPH_IV_FLD_FLAG_SET(header->serv_specif_flags,
@@ -279,8 +277,9 @@ static void qat_alg_init_common_hdr(struct icp_qat_fw_comn_req_hdr *header)
ICP_QAT_FW_LA_NO_UPDATE_STATE);
}
-static int qat_alg_init_enc_session(struct qat_alg_session_ctx *ctx,
- int alg, struct crypto_authenc_keys *keys)
+static int qat_alg_aead_init_enc_session(struct qat_alg_aead_ctx *ctx,
+ int alg,
+ struct crypto_authenc_keys *keys)
{
struct crypto_aead *aead_tfm = __crypto_aead_cast(ctx->tfm);
unsigned int digestsize = crypto_aead_crt(aead_tfm)->authsize;
@@ -289,7 +288,7 @@ static int qat_alg_init_enc_session(struct qat_alg_session_ctx *ctx,
struct icp_qat_hw_auth_algo_blk *hash =
(struct icp_qat_hw_auth_algo_blk *)((char *)enc_ctx +
sizeof(struct icp_qat_hw_auth_setup) + keys->enckeylen);
- struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->enc_fw_req_tmpl;
+ struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->enc_fw_req;
struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req_tmpl->cd_pars;
struct icp_qat_fw_comn_req_hdr *header = &req_tmpl->comn_hdr;
void *ptr = &req_tmpl->cd_ctrl;
@@ -297,7 +296,7 @@ static int qat_alg_init_enc_session(struct qat_alg_session_ctx *ctx,
struct icp_qat_fw_auth_cd_ctrl_hdr *hash_cd_ctrl = ptr;
/* CD setup */
- cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_ENC(alg);
+ cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_ENC(alg);
memcpy(cipher->aes.key, keys->enckey, keys->enckeylen);
hash->sha.inner_setup.auth_config.config =
ICP_QAT_HW_AUTH_CONFIG_BUILD(ICP_QAT_HW_AUTH_MODE1,
@@ -311,6 +310,8 @@ static int qat_alg_init_enc_session(struct qat_alg_session_ctx *ctx,
/* Request setup */
qat_alg_init_common_hdr(header);
header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER_HASH;
+ ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
+ ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
ICP_QAT_FW_LA_RET_AUTH_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_RET_AUTH_RES);
ICP_QAT_FW_LA_CMP_AUTH_SET(header->serv_specif_flags,
@@ -356,8 +357,9 @@ static int qat_alg_init_enc_session(struct qat_alg_session_ctx *ctx,
return 0;
}
-static int qat_alg_init_dec_session(struct qat_alg_session_ctx *ctx,
- int alg, struct crypto_authenc_keys *keys)
+static int qat_alg_aead_init_dec_session(struct qat_alg_aead_ctx *ctx,
+ int alg,
+ struct crypto_authenc_keys *keys)
{
struct crypto_aead *aead_tfm = __crypto_aead_cast(ctx->tfm);
unsigned int digestsize = crypto_aead_crt(aead_tfm)->authsize;
@@ -367,7 +369,7 @@ static int qat_alg_init_dec_session(struct qat_alg_session_ctx *ctx,
(struct icp_qat_hw_cipher_algo_blk *)((char *)dec_ctx +
sizeof(struct icp_qat_hw_auth_setup) +
roundup(crypto_shash_digestsize(ctx->hash_tfm), 8) * 2);
- struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->dec_fw_req_tmpl;
+ struct icp_qat_fw_la_bulk_req *req_tmpl = &ctx->dec_fw_req;
struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req_tmpl->cd_pars;
struct icp_qat_fw_comn_req_hdr *header = &req_tmpl->comn_hdr;
void *ptr = &req_tmpl->cd_ctrl;
@@ -379,7 +381,7 @@ static int qat_alg_init_dec_session(struct qat_alg_session_ctx *ctx,
sizeof(struct icp_qat_fw_la_cipher_req_params));
/* CD setup */
- cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_DEC(alg);
+ cipher->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_DEC(alg);
memcpy(cipher->aes.key, keys->enckey, keys->enckeylen);
hash->sha.inner_setup.auth_config.config =
ICP_QAT_HW_AUTH_CONFIG_BUILD(ICP_QAT_HW_AUTH_MODE1,
@@ -394,6 +396,8 @@ static int qat_alg_init_dec_session(struct qat_alg_session_ctx *ctx,
/* Request setup */
qat_alg_init_common_hdr(header);
header->service_cmd_id = ICP_QAT_FW_LA_CMD_HASH_CIPHER;
+ ICP_QAT_FW_LA_DIGEST_IN_BUFFER_SET(header->serv_specif_flags,
+ ICP_QAT_FW_LA_DIGEST_IN_BUFFER);
ICP_QAT_FW_LA_RET_AUTH_SET(header->serv_specif_flags,
ICP_QAT_FW_LA_NO_RET_AUTH_RES);
ICP_QAT_FW_LA_CMP_AUTH_SET(header->serv_specif_flags,
@@ -444,36 +448,91 @@ static int qat_alg_init_dec_session(struct qat_alg_session_ctx *ctx,
return 0;
}
-static int qat_alg_init_sessions(struct qat_alg_session_ctx *ctx,
- const uint8_t *key, unsigned int keylen)
+static void qat_alg_ablkcipher_init_com(struct qat_alg_ablkcipher_ctx *ctx,
+ struct icp_qat_fw_la_bulk_req *req,
+ struct icp_qat_hw_cipher_algo_blk *cd,
+ const uint8_t *key, unsigned int keylen)
{
- struct crypto_authenc_keys keys;
- int alg;
+ struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req->cd_pars;
+ struct icp_qat_fw_comn_req_hdr *header = &req->comn_hdr;
+ struct icp_qat_fw_cipher_cd_ctrl_hdr *cd_ctrl = (void *)&req->cd_ctrl;
- if (crypto_rng_get_bytes(crypto_default_rng, ctx->salt, AES_BLOCK_SIZE))
- return -EFAULT;
+ memcpy(cd->aes.key, key, keylen);
+ qat_alg_init_common_hdr(header);
+ header->service_cmd_id = ICP_QAT_FW_LA_CMD_CIPHER;
+ cd_pars->u.s.content_desc_params_sz =
+ sizeof(struct icp_qat_hw_cipher_algo_blk) >> 3;
+ /* Cipher CD config setup */
+ cd_ctrl->cipher_key_sz = keylen >> 3;
+ cd_ctrl->cipher_state_sz = AES_BLOCK_SIZE >> 3;
+ cd_ctrl->cipher_cfg_offset = 0;
+ ICP_QAT_FW_COMN_CURR_ID_SET(cd_ctrl, ICP_QAT_FW_SLICE_CIPHER);
+ ICP_QAT_FW_COMN_NEXT_ID_SET(cd_ctrl, ICP_QAT_FW_SLICE_DRAM_WR);
+}
- if (crypto_authenc_extractkeys(&keys, key, keylen))
- goto bad_key;
+static void qat_alg_ablkcipher_init_enc(struct qat_alg_ablkcipher_ctx *ctx,
+ int alg, const uint8_t *key,
+ unsigned int keylen)
+{
+ struct icp_qat_hw_cipher_algo_blk *enc_cd = ctx->enc_cd;
+ struct icp_qat_fw_la_bulk_req *req = &ctx->enc_fw_req;
+ struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req->cd_pars;
+
+ qat_alg_ablkcipher_init_com(ctx, req, enc_cd, key, keylen);
+ cd_pars->u.s.content_desc_addr = ctx->enc_cd_paddr;
+ enc_cd->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_ENC(alg);
+}
- switch (keys.enckeylen) {
+static void qat_alg_ablkcipher_init_dec(struct qat_alg_ablkcipher_ctx *ctx,
+ int alg, const uint8_t *key,
+ unsigned int keylen)
+{
+ struct icp_qat_hw_cipher_algo_blk *dec_cd = ctx->dec_cd;
+ struct icp_qat_fw_la_bulk_req *req = &ctx->dec_fw_req;
+ struct icp_qat_fw_comn_req_hdr_cd_pars *cd_pars = &req->cd_pars;
+
+ qat_alg_ablkcipher_init_com(ctx, req, dec_cd, key, keylen);
+ cd_pars->u.s.content_desc_addr = ctx->dec_cd_paddr;
+ dec_cd->aes.cipher_config.val = QAT_AES_HW_CONFIG_CBC_DEC(alg);
+}
+
+static int qat_alg_validate_key(int key_len, int *alg)
+{
+ switch (key_len) {
case AES_KEYSIZE_128:
- alg = ICP_QAT_HW_CIPHER_ALGO_AES128;
+ *alg = ICP_QAT_HW_CIPHER_ALGO_AES128;
break;
case AES_KEYSIZE_192:
- alg = ICP_QAT_HW_CIPHER_ALGO_AES192;
+ *alg = ICP_QAT_HW_CIPHER_ALGO_AES192;
break;
case AES_KEYSIZE_256:
- alg = ICP_QAT_HW_CIPHER_ALGO_AES256;
+ *alg = ICP_QAT_HW_CIPHER_ALGO_AES256;
break;
default:
- goto bad_key;
+ return -EINVAL;
}
+ return 0;
+}
- if (qat_alg_init_enc_session(ctx, alg, &keys))
+static int qat_alg_aead_init_sessions(struct qat_alg_aead_ctx *ctx,
+ const uint8_t *key, unsigned int keylen)
+{
+ struct crypto_authenc_keys keys;
+ int alg;
+
+ if (crypto_rng_get_bytes(crypto_default_rng, ctx->salt, AES_BLOCK_SIZE))
+ return -EFAULT;
+
+ if (crypto_authenc_extractkeys(&keys, key, keylen))
+ goto bad_key;
+
+ if (qat_alg_validate_key(keys.enckeylen, &alg))
+ goto bad_key;
+
+ if (qat_alg_aead_init_enc_session(ctx, alg, &keys))
goto error;
- if (qat_alg_init_dec_session(ctx, alg, &keys))
+ if (qat_alg_aead_init_dec_session(ctx, alg, &keys))
goto error;
return 0;
@@ -484,22 +543,37 @@ error:
return -EFAULT;
}
-static int qat_alg_setkey(struct crypto_aead *tfm, const uint8_t *key,
- unsigned int keylen)
+static int qat_alg_ablkcipher_init_sessions(struct qat_alg_ablkcipher_ctx *ctx,
+ const uint8_t *key,
+ unsigned int keylen)
+{
+ int alg;
+
+ if (qat_alg_validate_key(keylen, &alg))
+ goto bad_key;
+
+ qat_alg_ablkcipher_init_enc(ctx, alg, key, keylen);
+ qat_alg_ablkcipher_init_dec(ctx, alg, key, keylen);
+ return 0;
+bad_key:
+ crypto_tfm_set_flags(ctx->tfm, CRYPTO_TFM_RES_BAD_KEY_LEN);
+ return -EINVAL;
+}
+
+static int qat_alg_aead_setkey(struct crypto_aead *tfm, const uint8_t *key,
+ unsigned int keylen)
{
- struct qat_alg_session_ctx *ctx = crypto_aead_ctx(tfm);
+ struct qat_alg_aead_ctx *ctx = crypto_aead_ctx(tfm);
struct device *dev;
spin_lock(&ctx->lock);
if (ctx->enc_cd) {
/* rekeying */
dev = &GET_DEV(ctx->inst->accel_dev);
- memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
- memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
- memzero_explicit(&ctx->enc_fw_req_tmpl,
- sizeof(struct icp_qat_fw_la_bulk_req));
- memzero_explicit(&ctx->dec_fw_req_tmpl,
- sizeof(struct icp_qat_fw_la_bulk_req));
+ memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+ memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+ memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
+ memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
} else {
/* new key */
int node = get_current_node();
@@ -512,16 +586,14 @@ static int qat_alg_setkey(struct crypto_aead *tfm, const uint8_t *key,
dev = &GET_DEV(inst->accel_dev);
ctx->inst = inst;
- ctx->enc_cd = dma_zalloc_coherent(dev,
- sizeof(struct qat_alg_cd),
+ ctx->enc_cd = dma_zalloc_coherent(dev, sizeof(*ctx->enc_cd),
&ctx->enc_cd_paddr,
GFP_ATOMIC);
if (!ctx->enc_cd) {
spin_unlock(&ctx->lock);
return -ENOMEM;
}
- ctx->dec_cd = dma_zalloc_coherent(dev,
- sizeof(struct qat_alg_cd),
+ ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd),
&ctx->dec_cd_paddr,
GFP_ATOMIC);
if (!ctx->dec_cd) {
@@ -530,18 +602,18 @@ static int qat_alg_setkey(struct crypto_aead *tfm, const uint8_t *key,
}
}
spin_unlock(&ctx->lock);
- if (qat_alg_init_sessions(ctx, key, keylen))
+ if (qat_alg_aead_init_sessions(ctx, key, keylen))
goto out_free_all;
return 0;
out_free_all:
- memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
+ memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
dma_free_coherent(dev, sizeof(struct qat_alg_cd),
ctx->dec_cd, ctx->dec_cd_paddr);
ctx->dec_cd = NULL;
out_free_enc:
- memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
+ memset(ctx->enc_cd, 0, sizeof(struct qat_alg_cd));
dma_free_coherent(dev, sizeof(struct qat_alg_cd),
ctx->enc_cd, ctx->enc_cd_paddr);
ctx->enc_cd = NULL;
@@ -557,7 +629,8 @@ static void qat_alg_free_bufl(struct qat_crypto_instance *inst,
dma_addr_t blp = qat_req->buf.blp;
dma_addr_t blpout = qat_req->buf.bloutp;
size_t sz = qat_req->buf.sz;
- int i, bufs = bl->num_bufs;
+ size_t sz_out = qat_req->buf.sz_out;
+ int i;
for (i = 0; i < bl->num_bufs; i++)
dma_unmap_single(dev, bl->bufers[i].addr,
@@ -567,14 +640,14 @@ static void qat_alg_free_bufl(struct qat_crypto_instance *inst,
kfree(bl);
if (blp != blpout) {
/* If out of place operation dma unmap only data */
- int bufless = bufs - blout->num_mapped_bufs;
+ int bufless = blout->num_bufs - blout->num_mapped_bufs;
- for (i = bufless; i < bufs; i++) {
+ for (i = bufless; i < blout->num_bufs; i++) {
dma_unmap_single(dev, blout->bufers[i].addr,
blout->bufers[i].len,
DMA_BIDIRECTIONAL);
}
- dma_unmap_single(dev, blpout, sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, blpout, sz_out, DMA_TO_DEVICE);
kfree(blout);
}
}
@@ -587,19 +660,20 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
struct qat_crypto_request *qat_req)
{
struct device *dev = &GET_DEV(inst->accel_dev);
- int i, bufs = 0, n = sg_nents(sgl), assoc_n = sg_nents(assoc);
+ int i, bufs = 0, sg_nctr = 0;
+ int n = sg_nents(sgl), assoc_n = sg_nents(assoc);
struct qat_alg_buf_list *bufl;
struct qat_alg_buf_list *buflout = NULL;
dma_addr_t blp;
dma_addr_t bloutp = 0;
struct scatterlist *sg;
- size_t sz = sizeof(struct qat_alg_buf_list) +
+ size_t sz_out, sz = sizeof(struct qat_alg_buf_list) +
((1 + n + assoc_n) * sizeof(struct qat_alg_buf));
if (unlikely(!n))
return -EINVAL;
- bufl = kmalloc_node(sz, GFP_ATOMIC,
+ bufl = kzalloc_node(sz, GFP_ATOMIC,
dev_to_node(&GET_DEV(inst->accel_dev)));
if (unlikely(!bufl))
return -ENOMEM;
@@ -620,15 +694,20 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
goto err;
bufs++;
}
- bufl->bufers[bufs].addr = dma_map_single(dev, iv, ivlen,
- DMA_BIDIRECTIONAL);
- bufl->bufers[bufs].len = ivlen;
- if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr)))
- goto err;
- bufs++;
+ if (ivlen) {
+ bufl->bufers[bufs].addr = dma_map_single(dev, iv, ivlen,
+ DMA_BIDIRECTIONAL);
+ bufl->bufers[bufs].len = ivlen;
+ if (unlikely(dma_mapping_error(dev, bufl->bufers[bufs].addr)))
+ goto err;
+ bufs++;
+ }
for_each_sg(sgl, sg, n, i) {
- int y = i + bufs;
+ int y = sg_nctr + bufs;
+
+ if (!sg->length)
+ continue;
bufl->bufers[y].addr = dma_map_single(dev, sg_virt(sg),
sg->length,
@@ -636,8 +715,9 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
bufl->bufers[y].len = sg->length;
if (unlikely(dma_mapping_error(dev, bufl->bufers[y].addr)))
goto err;
+ sg_nctr++;
}
- bufl->num_bufs = n + bufs;
+ bufl->num_bufs = sg_nctr + bufs;
qat_req->buf.bl = bufl;
qat_req->buf.blp = blp;
qat_req->buf.sz = sz;
@@ -645,11 +725,15 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
if (sgl != sglout) {
struct qat_alg_buf *bufers;
- buflout = kmalloc_node(sz, GFP_ATOMIC,
+ n = sg_nents(sglout);
+ sz_out = sizeof(struct qat_alg_buf_list) +
+ ((1 + n + assoc_n) * sizeof(struct qat_alg_buf));
+ sg_nctr = 0;
+ buflout = kzalloc_node(sz_out, GFP_ATOMIC,
dev_to_node(&GET_DEV(inst->accel_dev)));
if (unlikely(!buflout))
goto err;
- bloutp = dma_map_single(dev, buflout, sz, DMA_TO_DEVICE);
+ bloutp = dma_map_single(dev, buflout, sz_out, DMA_TO_DEVICE);
if (unlikely(dma_mapping_error(dev, bloutp)))
goto err;
bufers = buflout->bufers;
@@ -660,60 +744,62 @@ static int qat_alg_sgl_to_bufl(struct qat_crypto_instance *inst,
bufers[i].addr = bufl->bufers[i].addr;
}
for_each_sg(sglout, sg, n, i) {
- int y = i + bufs;
+ int y = sg_nctr + bufs;
+
+ if (!sg->length)
+ continue;
bufers[y].addr = dma_map_single(dev, sg_virt(sg),
sg->length,
DMA_BIDIRECTIONAL);
- buflout->bufers[y].len = sg->length;
if (unlikely(dma_mapping_error(dev, bufers[y].addr)))
goto err;
+ bufers[y].len = sg->length;
+ sg_nctr++;
}
- buflout->num_bufs = n + bufs;
- buflout->num_mapped_bufs = n;
+ buflout->num_bufs = sg_nctr + bufs;
+ buflout->num_mapped_bufs = sg_nctr;
qat_req->buf.blout = buflout;
qat_req->buf.bloutp = bloutp;
+ qat_req->buf.sz_out = sz_out;
} else {
/* Otherwise set the src and dst to the same address */
qat_req->buf.bloutp = qat_req->buf.blp;
+ qat_req->buf.sz_out = 0;
}
return 0;
err:
dev_err(dev, "Failed to map buf for dma\n");
- for_each_sg(sgl, sg, n + bufs, i) {
- if (!dma_mapping_error(dev, bufl->bufers[i].addr)) {
+ sg_nctr = 0;
+ for (i = 0; i < n + bufs; i++)
+ if (!dma_mapping_error(dev, bufl->bufers[i].addr))
dma_unmap_single(dev, bufl->bufers[i].addr,
bufl->bufers[i].len,
DMA_BIDIRECTIONAL);
- }
- }
+
if (!dma_mapping_error(dev, blp))
dma_unmap_single(dev, blp, sz, DMA_TO_DEVICE);
kfree(bufl);
if (sgl != sglout && buflout) {
- for_each_sg(sglout, sg, n, i) {
- int y = i + bufs;
-
- if (!dma_mapping_error(dev, buflout->bufers[y].addr))
- dma_unmap_single(dev, buflout->bufers[y].addr,
- buflout->bufers[y].len,
+ n = sg_nents(sglout);
+ for (i = bufs; i < n + bufs; i++)
+ if (!dma_mapping_error(dev, buflout->bufers[i].addr))
+ dma_unmap_single(dev, buflout->bufers[i].addr,
+ buflout->bufers[i].len,
DMA_BIDIRECTIONAL);
- }
if (!dma_mapping_error(dev, bloutp))
- dma_unmap_single(dev, bloutp, sz, DMA_TO_DEVICE);
+ dma_unmap_single(dev, bloutp, sz_out, DMA_TO_DEVICE);
kfree(buflout);
}
return -ENOMEM;
}
-void qat_alg_callback(void *resp)
+static void qat_aead_alg_callback(struct icp_qat_fw_la_resp *qat_resp,
+ struct qat_crypto_request *qat_req)
{
- struct icp_qat_fw_la_resp *qat_resp = resp;
- struct qat_crypto_request *qat_req =
- (void *)(__force long)qat_resp->opaque_data;
- struct qat_alg_session_ctx *ctx = qat_req->ctx;
+ struct qat_alg_aead_ctx *ctx = qat_req->aead_ctx;
struct qat_crypto_instance *inst = ctx->inst;
- struct aead_request *areq = qat_req->areq;
+ struct aead_request *areq = qat_req->aead_req;
uint8_t stat_filed = qat_resp->comn_resp.comn_status;
int res = 0, qat_res = ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(stat_filed);
@@ -723,11 +809,35 @@ void qat_alg_callback(void *resp)
areq->base.complete(&areq->base, res);
}
-static int qat_alg_dec(struct aead_request *areq)
+static void qat_ablkcipher_alg_callback(struct icp_qat_fw_la_resp *qat_resp,
+ struct qat_crypto_request *qat_req)
+{
+ struct qat_alg_ablkcipher_ctx *ctx = qat_req->ablkcipher_ctx;
+ struct qat_crypto_instance *inst = ctx->inst;
+ struct ablkcipher_request *areq = qat_req->ablkcipher_req;
+ uint8_t stat_filed = qat_resp->comn_resp.comn_status;
+ int res = 0, qat_res = ICP_QAT_FW_COMN_RESP_CRYPTO_STAT_GET(stat_filed);
+
+ qat_alg_free_bufl(inst, qat_req);
+ if (unlikely(qat_res != ICP_QAT_FW_COMN_STATUS_FLAG_OK))
+ res = -EINVAL;
+ areq->base.complete(&areq->base, res);
+}
+
+void qat_alg_callback(void *resp)
+{
+ struct icp_qat_fw_la_resp *qat_resp = resp;
+ struct qat_crypto_request *qat_req =
+ (void *)(__force long)qat_resp->opaque_data;
+
+ qat_req->cb(qat_resp, qat_req);
+}
+
+static int qat_alg_aead_dec(struct aead_request *areq)
{
struct crypto_aead *aead_tfm = crypto_aead_reqtfm(areq);
struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm);
- struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
struct qat_crypto_request *qat_req = aead_request_ctx(areq);
struct icp_qat_fw_la_cipher_req_params *cipher_param;
struct icp_qat_fw_la_auth_req_params *auth_param;
@@ -741,9 +851,10 @@ static int qat_alg_dec(struct aead_request *areq)
return ret;
msg = &qat_req->req;
- *msg = ctx->dec_fw_req_tmpl;
- qat_req->ctx = ctx;
- qat_req->areq = areq;
+ *msg = ctx->dec_fw_req;
+ qat_req->aead_ctx = ctx;
+ qat_req->aead_req = areq;
+ qat_req->cb = qat_aead_alg_callback;
qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
@@ -766,12 +877,12 @@ static int qat_alg_dec(struct aead_request *areq)
return -EINPROGRESS;
}
-static int qat_alg_enc_internal(struct aead_request *areq, uint8_t *iv,
- int enc_iv)
+static int qat_alg_aead_enc_internal(struct aead_request *areq, uint8_t *iv,
+ int enc_iv)
{
struct crypto_aead *aead_tfm = crypto_aead_reqtfm(areq);
struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm);
- struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
struct qat_crypto_request *qat_req = aead_request_ctx(areq);
struct icp_qat_fw_la_cipher_req_params *cipher_param;
struct icp_qat_fw_la_auth_req_params *auth_param;
@@ -784,9 +895,10 @@ static int qat_alg_enc_internal(struct aead_request *areq, uint8_t *iv,
return ret;
msg = &qat_req->req;
- *msg = ctx->enc_fw_req_tmpl;
- qat_req->ctx = ctx;
- qat_req->areq = areq;
+ *msg = ctx->enc_fw_req;
+ qat_req->aead_ctx = ctx;
+ qat_req->aead_req = areq;
+ qat_req->cb = qat_aead_alg_callback;
qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
@@ -815,31 +927,168 @@ static int qat_alg_enc_internal(struct aead_request *areq, uint8_t *iv,
return -EINPROGRESS;
}
-static int qat_alg_enc(struct aead_request *areq)
+static int qat_alg_aead_enc(struct aead_request *areq)
{
- return qat_alg_enc_internal(areq, areq->iv, 0);
+ return qat_alg_aead_enc_internal(areq, areq->iv, 0);
}
-static int qat_alg_genivenc(struct aead_givcrypt_request *req)
+static int qat_alg_aead_genivenc(struct aead_givcrypt_request *req)
{
struct crypto_aead *aead_tfm = crypto_aead_reqtfm(&req->areq);
struct crypto_tfm *tfm = crypto_aead_tfm(aead_tfm);
- struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
__be64 seq;
memcpy(req->giv, ctx->salt, AES_BLOCK_SIZE);
seq = cpu_to_be64(req->seq);
memcpy(req->giv + AES_BLOCK_SIZE - sizeof(uint64_t),
&seq, sizeof(uint64_t));
- return qat_alg_enc_internal(&req->areq, req->giv, 1);
+ return qat_alg_aead_enc_internal(&req->areq, req->giv, 1);
}
-static int qat_alg_init(struct crypto_tfm *tfm,
- enum icp_qat_hw_auth_algo hash, const char *hash_name)
+static int qat_alg_ablkcipher_setkey(struct crypto_ablkcipher *tfm,
+ const uint8_t *key,
+ unsigned int keylen)
{
- struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_alg_ablkcipher_ctx *ctx = crypto_ablkcipher_ctx(tfm);
+ struct device *dev;
+
+ spin_lock(&ctx->lock);
+ if (ctx->enc_cd) {
+ /* rekeying */
+ dev = &GET_DEV(ctx->inst->accel_dev);
+ memset(ctx->enc_cd, 0, sizeof(*ctx->enc_cd));
+ memset(ctx->dec_cd, 0, sizeof(*ctx->dec_cd));
+ memset(&ctx->enc_fw_req, 0, sizeof(ctx->enc_fw_req));
+ memset(&ctx->dec_fw_req, 0, sizeof(ctx->dec_fw_req));
+ } else {
+ /* new key */
+ int node = get_current_node();
+ struct qat_crypto_instance *inst =
+ qat_crypto_get_instance_node(node);
+ if (!inst) {
+ spin_unlock(&ctx->lock);
+ return -EINVAL;
+ }
+
+ dev = &GET_DEV(inst->accel_dev);
+ ctx->inst = inst;
+ ctx->enc_cd = dma_zalloc_coherent(dev, sizeof(*ctx->enc_cd),
+ &ctx->enc_cd_paddr,
+ GFP_ATOMIC);
+ if (!ctx->enc_cd) {
+ spin_unlock(&ctx->lock);
+ return -ENOMEM;
+ }
+ ctx->dec_cd = dma_zalloc_coherent(dev, sizeof(*ctx->dec_cd),
+ &ctx->dec_cd_paddr,
+ GFP_ATOMIC);
+ if (!ctx->dec_cd) {
+ spin_unlock(&ctx->lock);
+ goto out_free_enc;
+ }
+ }
+ spin_unlock(&ctx->lock);
+ if (qat_alg_ablkcipher_init_sessions(ctx, key, keylen))
+ goto out_free_all;
+
+ return 0;
+
+out_free_all:
+ memset(ctx->dec_cd, 0, sizeof(*ctx->enc_cd));
+ dma_free_coherent(dev, sizeof(*ctx->enc_cd),
+ ctx->dec_cd, ctx->dec_cd_paddr);
+ ctx->dec_cd = NULL;
+out_free_enc:
+ memset(ctx->enc_cd, 0, sizeof(*ctx->dec_cd));
+ dma_free_coherent(dev, sizeof(*ctx->dec_cd),
+ ctx->enc_cd, ctx->enc_cd_paddr);
+ ctx->enc_cd = NULL;
+ return -ENOMEM;
+}
+
+static int qat_alg_ablkcipher_encrypt(struct ablkcipher_request *req)
+{
+ struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(atfm);
+ struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req);
+ struct icp_qat_fw_la_cipher_req_params *cipher_param;
+ struct icp_qat_fw_la_bulk_req *msg;
+ int ret, ctr = 0;
+
+ ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, req->src, req->dst,
+ NULL, 0, qat_req);
+ if (unlikely(ret))
+ return ret;
+
+ msg = &qat_req->req;
+ *msg = ctx->enc_fw_req;
+ qat_req->ablkcipher_ctx = ctx;
+ qat_req->ablkcipher_req = req;
+ qat_req->cb = qat_ablkcipher_alg_callback;
+ qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
+ qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
+ qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
+ cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
+ cipher_param->cipher_length = req->nbytes;
+ cipher_param->cipher_offset = 0;
+ memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE);
+ do {
+ ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg);
+ } while (ret == -EAGAIN && ctr++ < 10);
+
+ if (ret == -EAGAIN) {
+ qat_alg_free_bufl(ctx->inst, qat_req);
+ return -EBUSY;
+ }
+ return -EINPROGRESS;
+}
+
+static int qat_alg_ablkcipher_decrypt(struct ablkcipher_request *req)
+{
+ struct crypto_ablkcipher *atfm = crypto_ablkcipher_reqtfm(req);
+ struct crypto_tfm *tfm = crypto_ablkcipher_tfm(atfm);
+ struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_crypto_request *qat_req = ablkcipher_request_ctx(req);
+ struct icp_qat_fw_la_cipher_req_params *cipher_param;
+ struct icp_qat_fw_la_bulk_req *msg;
+ int ret, ctr = 0;
+
+ ret = qat_alg_sgl_to_bufl(ctx->inst, NULL, req->src, req->dst,
+ NULL, 0, qat_req);
+ if (unlikely(ret))
+ return ret;
+
+ msg = &qat_req->req;
+ *msg = ctx->dec_fw_req;
+ qat_req->ablkcipher_ctx = ctx;
+ qat_req->ablkcipher_req = req;
+ qat_req->cb = qat_ablkcipher_alg_callback;
+ qat_req->req.comn_mid.opaque_data = (uint64_t)(__force long)qat_req;
+ qat_req->req.comn_mid.src_data_addr = qat_req->buf.blp;
+ qat_req->req.comn_mid.dest_data_addr = qat_req->buf.bloutp;
+ cipher_param = (void *)&qat_req->req.serv_specif_rqpars;
+ cipher_param->cipher_length = req->nbytes;
+ cipher_param->cipher_offset = 0;
+ memcpy(cipher_param->u.cipher_IV_array, req->info, AES_BLOCK_SIZE);
+ do {
+ ret = adf_send_message(ctx->inst->sym_tx, (uint32_t *)msg);
+ } while (ret == -EAGAIN && ctr++ < 10);
+
+ if (ret == -EAGAIN) {
+ qat_alg_free_bufl(ctx->inst, qat_req);
+ return -EBUSY;
+ }
+ return -EINPROGRESS;
+}
+
+static int qat_alg_aead_init(struct crypto_tfm *tfm,
+ enum icp_qat_hw_auth_algo hash,
+ const char *hash_name)
+{
+ struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
- memzero_explicit(ctx, sizeof(*ctx));
ctx->hash_tfm = crypto_alloc_shash(hash_name, 0, 0);
if (IS_ERR(ctx->hash_tfm))
return -EFAULT;
@@ -851,24 +1100,24 @@ static int qat_alg_init(struct crypto_tfm *tfm,
return 0;
}
-static int qat_alg_sha1_init(struct crypto_tfm *tfm)
+static int qat_alg_aead_sha1_init(struct crypto_tfm *tfm)
{
- return qat_alg_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, "sha1");
+ return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA1, "sha1");
}
-static int qat_alg_sha256_init(struct crypto_tfm *tfm)
+static int qat_alg_aead_sha256_init(struct crypto_tfm *tfm)
{
- return qat_alg_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, "sha256");
+ return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA256, "sha256");
}
-static int qat_alg_sha512_init(struct crypto_tfm *tfm)
+static int qat_alg_aead_sha512_init(struct crypto_tfm *tfm)
{
- return qat_alg_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, "sha512");
+ return qat_alg_aead_init(tfm, ICP_QAT_HW_AUTH_ALGO_SHA512, "sha512");
}
-static void qat_alg_exit(struct crypto_tfm *tfm)
+static void qat_alg_aead_exit(struct crypto_tfm *tfm)
{
- struct qat_alg_session_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_alg_aead_ctx *ctx = crypto_tfm_ctx(tfm);
struct qat_crypto_instance *inst = ctx->inst;
struct device *dev;
@@ -880,36 +1129,74 @@ static void qat_alg_exit(struct crypto_tfm *tfm)
dev = &GET_DEV(inst->accel_dev);
if (ctx->enc_cd) {
- memzero_explicit(ctx->enc_cd, sizeof(struct qat_alg_cd));
+ memset(ctx->enc_cd, 0, sizeof(struct qat_alg_cd));
dma_free_coherent(dev, sizeof(struct qat_alg_cd),
ctx->enc_cd, ctx->enc_cd_paddr);
}
if (ctx->dec_cd) {
- memzero_explicit(ctx->dec_cd, sizeof(struct qat_alg_cd));
+ memset(ctx->dec_cd, 0, sizeof(struct qat_alg_cd));
dma_free_coherent(dev, sizeof(struct qat_alg_cd),
ctx->dec_cd, ctx->dec_cd_paddr);
}
qat_crypto_put_instance(inst);
}
+static int qat_alg_ablkcipher_init(struct crypto_tfm *tfm)
+{
+ struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+
+ spin_lock_init(&ctx->lock);
+ tfm->crt_ablkcipher.reqsize = sizeof(struct ablkcipher_request) +
+ sizeof(struct qat_crypto_request);
+ ctx->tfm = tfm;
+ return 0;
+}
+
+static void qat_alg_ablkcipher_exit(struct crypto_tfm *tfm)
+{
+ struct qat_alg_ablkcipher_ctx *ctx = crypto_tfm_ctx(tfm);
+ struct qat_crypto_instance *inst = ctx->inst;
+ struct device *dev;
+
+ if (!inst)
+ return;
+
+ dev = &GET_DEV(inst->accel_dev);
+ if (ctx->enc_cd) {
+ memset(ctx->enc_cd, 0,
+ sizeof(struct icp_qat_hw_cipher_algo_blk));
+ dma_free_coherent(dev,
+ sizeof(struct icp_qat_hw_cipher_algo_blk),
+ ctx->enc_cd, ctx->enc_cd_paddr);
+ }
+ if (ctx->dec_cd) {
+ memset(ctx->dec_cd, 0,
+ sizeof(struct icp_qat_hw_cipher_algo_blk));
+ dma_free_coherent(dev,
+ sizeof(struct icp_qat_hw_cipher_algo_blk),
+ ctx->dec_cd, ctx->dec_cd_paddr);
+ }
+ qat_crypto_put_instance(inst);
+}
+
static struct crypto_alg qat_algs[] = { {
.cra_name = "authenc(hmac(sha1),cbc(aes))",
.cra_driver_name = "qat_aes_cbc_hmac_sha1",
.cra_priority = 4001,
.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct qat_alg_session_ctx),
+ .cra_ctxsize = sizeof(struct qat_alg_aead_ctx),
.cra_alignmask = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
- .cra_init = qat_alg_sha1_init,
- .cra_exit = qat_alg_exit,
+ .cra_init = qat_alg_aead_sha1_init,
+ .cra_exit = qat_alg_aead_exit,
.cra_u = {
.aead = {
- .setkey = qat_alg_setkey,
- .decrypt = qat_alg_dec,
- .encrypt = qat_alg_enc,
- .givencrypt = qat_alg_genivenc,
+ .setkey = qat_alg_aead_setkey,
+ .decrypt = qat_alg_aead_dec,
+ .encrypt = qat_alg_aead_enc,
+ .givencrypt = qat_alg_aead_genivenc,
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA1_DIGEST_SIZE,
},
@@ -920,18 +1207,18 @@ static struct crypto_alg qat_algs[] = { {
.cra_priority = 4001,
.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct qat_alg_session_ctx),
+ .cra_ctxsize = sizeof(struct qat_alg_aead_ctx),
.cra_alignmask = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
- .cra_init = qat_alg_sha256_init,
- .cra_exit = qat_alg_exit,
+ .cra_init = qat_alg_aead_sha256_init,
+ .cra_exit = qat_alg_aead_exit,
.cra_u = {
.aead = {
- .setkey = qat_alg_setkey,
- .decrypt = qat_alg_dec,
- .encrypt = qat_alg_enc,
- .givencrypt = qat_alg_genivenc,
+ .setkey = qat_alg_aead_setkey,
+ .decrypt = qat_alg_aead_dec,
+ .encrypt = qat_alg_aead_enc,
+ .givencrypt = qat_alg_aead_genivenc,
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA256_DIGEST_SIZE,
},
@@ -942,22 +1229,44 @@ static struct crypto_alg qat_algs[] = { {
.cra_priority = 4001,
.cra_flags = CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC,
.cra_blocksize = AES_BLOCK_SIZE,
- .cra_ctxsize = sizeof(struct qat_alg_session_ctx),
+ .cra_ctxsize = sizeof(struct qat_alg_aead_ctx),
.cra_alignmask = 0,
.cra_type = &crypto_aead_type,
.cra_module = THIS_MODULE,
- .cra_init = qat_alg_sha512_init,
- .cra_exit = qat_alg_exit,
+ .cra_init = qat_alg_aead_sha512_init,
+ .cra_exit = qat_alg_aead_exit,
.cra_u = {
.aead = {
- .setkey = qat_alg_setkey,
- .decrypt = qat_alg_dec,
- .encrypt = qat_alg_enc,
- .givencrypt = qat_alg_genivenc,
+ .setkey = qat_alg_aead_setkey,
+ .decrypt = qat_alg_aead_dec,
+ .encrypt = qat_alg_aead_enc,
+ .givencrypt = qat_alg_aead_genivenc,
.ivsize = AES_BLOCK_SIZE,
.maxauthsize = SHA512_DIGEST_SIZE,
},
},
+}, {
+ .cra_name = "cbc(aes)",
+ .cra_driver_name = "qat_aes_cbc",
+ .cra_priority = 4001,
+ .cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC,
+ .cra_blocksize = AES_BLOCK_SIZE,
+ .cra_ctxsize = sizeof(struct qat_alg_ablkcipher_ctx),
+ .cra_alignmask = 0,
+ .cra_type = &crypto_ablkcipher_type,
+ .cra_module = THIS_MODULE,
+ .cra_init = qat_alg_ablkcipher_init,
+ .cra_exit = qat_alg_ablkcipher_exit,
+ .cra_u = {
+ .ablkcipher = {
+ .setkey = qat_alg_ablkcipher_setkey,
+ .decrypt = qat_alg_ablkcipher_decrypt,
+ .encrypt = qat_alg_ablkcipher_encrypt,
+ .min_keysize = AES_MIN_KEY_SIZE,
+ .max_keysize = AES_MAX_KEY_SIZE,
+ .ivsize = AES_BLOCK_SIZE,
+ },
+ },
} };
int qat_algs_register(void)
@@ -966,8 +1275,11 @@ int qat_algs_register(void)
int i;
for (i = 0; i < ARRAY_SIZE(qat_algs); i++)
- qat_algs[i].cra_flags = CRYPTO_ALG_TYPE_AEAD |
- CRYPTO_ALG_ASYNC;
+ qat_algs[i].cra_flags =
+ (qat_algs[i].cra_type == &crypto_aead_type) ?
+ CRYPTO_ALG_TYPE_AEAD | CRYPTO_ALG_ASYNC :
+ CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC;
+
return crypto_register_algs(qat_algs, ARRAY_SIZE(qat_algs));
}
return 0;
diff --git a/drivers/crypto/qat/qat_common/qat_crypto.h b/drivers/crypto/qat/qat_common/qat_crypto.h
index ab8468d11ddb..d503007b49e6 100644
--- a/drivers/crypto/qat/qat_common/qat_crypto.h
+++ b/drivers/crypto/qat/qat_common/qat_crypto.h
@@ -72,12 +72,24 @@ struct qat_crypto_request_buffs {
struct qat_alg_buf_list *blout;
dma_addr_t bloutp;
size_t sz;
+ size_t sz_out;
};
+struct qat_crypto_request;
+
struct qat_crypto_request {
struct icp_qat_fw_la_bulk_req req;
- struct qat_alg_session_ctx *ctx;
- struct aead_request *areq;
+ union {
+ struct qat_alg_aead_ctx *aead_ctx;
+ struct qat_alg_ablkcipher_ctx *ablkcipher_ctx;
+ };
+ union {
+ struct aead_request *aead_req;
+ struct ablkcipher_request *ablkcipher_req;
+ };
struct qat_crypto_request_buffs buf;
+ void (*cb)(struct icp_qat_fw_la_resp *resp,
+ struct qat_crypto_request *req);
};
+
#endif
diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
index ef05825cc651..6a735d5c0e37 100644
--- a/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
+++ b/drivers/crypto/qat/qat_dh895xcc/adf_dh895xcc_hw_data.c
@@ -46,6 +46,7 @@
*/
#include <adf_accel_devices.h>
#include "adf_dh895xcc_hw_data.h"
+#include "adf_common_drv.h"
#include "adf_drv.h"
/* Worker thread to service arbiter mappings based on dev SKUs */
@@ -182,6 +183,19 @@ static void adf_enable_error_correction(struct adf_accel_dev *accel_dev)
}
}
+static void adf_enable_ints(struct adf_accel_dev *accel_dev)
+{
+ void __iomem *addr;
+
+ addr = (&GET_BARS(accel_dev)[ADF_DH895XCC_PMISC_BAR])->virt_addr;
+
+ /* Enable bundle and misc interrupts */
+ ADF_CSR_WR(addr, ADF_DH895XCC_SMIAPF0_MASK_OFFSET,
+ ADF_DH895XCC_SMIA0_MASK);
+ ADF_CSR_WR(addr, ADF_DH895XCC_SMIAPF1_MASK_OFFSET,
+ ADF_DH895XCC_SMIA1_MASK);
+}
+
void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
{
hw_data->dev_class = &dh895xcc_class;
@@ -206,6 +220,11 @@ void adf_init_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
hw_data->get_misc_bar_id = get_misc_bar_id;
hw_data->get_sku = get_sku;
hw_data->fw_name = ADF_DH895XCC_FW;
+ hw_data->init_admin_comms = adf_init_admin_comms;
+ hw_data->exit_admin_comms = adf_exit_admin_comms;
+ hw_data->init_arb = adf_init_arb;
+ hw_data->exit_arb = adf_exit_arb;
+ hw_data->enable_ints = adf_enable_ints;
}
void adf_clean_hw_data_dh895xcc(struct adf_hw_device_data *hw_data)
diff --git a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
index 948f66be262b..8ffdb95c9804 100644
--- a/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
+++ b/drivers/crypto/qat/qat_dh895xcc/adf_drv.c
@@ -90,9 +90,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
struct adf_accel_pci *accel_pci_dev = &accel_dev->accel_pci_dev;
int i;
- adf_exit_admin_comms(accel_dev);
- adf_exit_arb(accel_dev);
- adf_cleanup_etr_data(accel_dev);
+ adf_dev_shutdown(accel_dev);
for (i = 0; i < ADF_PCI_MAX_BARS; i++) {
struct adf_bar *bar = &accel_pci_dev->pci_bars[i];
@@ -119,7 +117,7 @@ static void adf_cleanup_accel(struct adf_accel_dev *accel_dev)
kfree(accel_dev);
}
-static int qat_dev_start(struct adf_accel_dev *accel_dev)
+static int adf_dev_configure(struct adf_accel_dev *accel_dev)
{
int cpus = num_online_cpus();
int banks = GET_MAX_BANKS(accel_dev);
@@ -206,7 +204,7 @@ static int qat_dev_start(struct adf_accel_dev *accel_dev)
goto err;
set_bit(ADF_STATUS_CONFIGURED, &accel_dev->status);
- return adf_dev_start(accel_dev);
+ return 0;
err:
dev_err(&GET_DEV(accel_dev), "Failed to start QAT accel dev\n");
return -EINVAL;
@@ -217,7 +215,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
struct adf_accel_dev *accel_dev;
struct adf_accel_pci *accel_pci_dev;
struct adf_hw_device_data *hw_data;
- void __iomem *pmisc_bar_addr = NULL;
char name[ADF_DEVICE_NAME_LENGTH];
unsigned int i, bar_nr;
int ret;
@@ -347,8 +344,6 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
ret = -EFAULT;
goto out_err;
}
- if (i == ADF_DH895XCC_PMISC_BAR)
- pmisc_bar_addr = bar->virt_addr;
}
pci_set_master(pdev);
@@ -358,36 +353,21 @@ static int adf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_err;
}
- if (adf_init_etr_data(accel_dev)) {
- dev_err(&pdev->dev, "Failed initialize etr\n");
- ret = -EFAULT;
- goto out_err;
- }
-
- if (adf_init_admin_comms(accel_dev)) {
- dev_err(&pdev->dev, "Failed initialize admin comms\n");
- ret = -EFAULT;
- goto out_err;
- }
-
- if (adf_init_arb(accel_dev)) {
- dev_err(&pdev->dev, "Failed initialize hw arbiter\n");
- ret = -EFAULT;
- goto out_err;
- }
if (pci_save_state(pdev)) {
dev_err(&pdev->dev, "Failed to save pci state\n");
ret = -ENOMEM;
goto out_err;
}
- /* Enable bundle and misc interrupts */
- ADF_CSR_WR(pmisc_bar_addr, ADF_DH895XCC_SMIAPF0_MASK_OFFSET,
- ADF_DH895XCC_SMIA0_MASK);
- ADF_CSR_WR(pmisc_bar_addr, ADF_DH895XCC_SMIAPF1_MASK_OFFSET,
- ADF_DH895XCC_SMIA1_MASK);
+ ret = adf_dev_configure(accel_dev);
+ if (ret)
+ goto out_err;
+
+ ret = adf_dev_init(accel_dev);
+ if (ret)
+ goto out_err;
- ret = qat_dev_start(accel_dev);
+ ret = adf_dev_start(accel_dev);
if (ret) {
adf_dev_stop(accel_dev);
goto out_err;
diff --git a/drivers/crypto/qce/dma.c b/drivers/crypto/qce/dma.c
index 0fb21e13f247..378cb768647f 100644
--- a/drivers/crypto/qce/dma.c
+++ b/drivers/crypto/qce/dma.c
@@ -64,7 +64,7 @@ int qce_mapsg(struct device *dev, struct scatterlist *sg, int nents,
err = dma_map_sg(dev, sg, 1, dir);
if (!err)
return -EFAULT;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
} else {
err = dma_map_sg(dev, sg, nents, dir);
@@ -81,7 +81,7 @@ void qce_unmapsg(struct device *dev, struct scatterlist *sg, int nents,
if (chained)
while (sg) {
dma_unmap_sg(dev, sg, 1, dir);
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
else
dma_unmap_sg(dev, sg, nents, dir);
@@ -100,7 +100,7 @@ int qce_countsg(struct scatterlist *sglist, int nbytes, bool *chained)
nbytes -= sg->length;
if (!sg_is_last(sg) && (sg + 1)->length == 0 && chained)
*chained = true;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
return nents;
diff --git a/drivers/crypto/qce/sha.c b/drivers/crypto/qce/sha.c
index f3385934eed2..5c5df1d17f90 100644
--- a/drivers/crypto/qce/sha.c
+++ b/drivers/crypto/qce/sha.c
@@ -285,7 +285,7 @@ static int qce_ahash_update(struct ahash_request *req)
break;
len += sg_dma_len(sg);
sg_last = sg;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
if (!sg_last)
diff --git a/drivers/crypto/sahara.c b/drivers/crypto/sahara.c
index 220b92f7eabc..290a7f0a681f 100644
--- a/drivers/crypto/sahara.c
+++ b/drivers/crypto/sahara.c
@@ -940,7 +940,7 @@ static int sahara_walk_and_recalc(struct scatterlist *sg, unsigned int nbytes)
break;
}
nbytes -= sg->length;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
return nbytes;
diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
index 067ec2193d71..ebbae8d3ce0d 100644
--- a/drivers/crypto/talitos.c
+++ b/drivers/crypto/talitos.c
@@ -743,7 +743,7 @@ static int talitos_map_sg(struct device *dev, struct scatterlist *sg,
if (unlikely(chained))
while (sg) {
dma_map_sg(dev, sg, 1, dir);
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
else
dma_map_sg(dev, sg, nents, dir);
@@ -755,7 +755,7 @@ static void talitos_unmap_sg_chain(struct device *dev, struct scatterlist *sg,
{
while (sg) {
dma_unmap_sg(dev, sg, 1, dir);
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
}
@@ -915,7 +915,7 @@ static int sg_to_link_tbl(struct scatterlist *sg, int sg_count,
link_tbl_ptr->j_extent = 0;
link_tbl_ptr++;
cryptlen -= sg_dma_len(sg);
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
/* adjust (decrease) last one (or two) entry's len to cryptlen */
@@ -1102,7 +1102,7 @@ static int sg_count(struct scatterlist *sg_list, int nbytes, bool *chained)
nbytes -= sg->length;
if (!sg_is_last(sg) && (sg + 1)->length == 0)
*chained = true;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
}
return sg_nents;
diff --git a/drivers/crypto/ux500/cryp/cryp_core.c b/drivers/crypto/ux500/cryp/cryp_core.c
index f831bb952b2f..fded0a5cfcd7 100644
--- a/drivers/crypto/ux500/cryp/cryp_core.c
+++ b/drivers/crypto/ux500/cryp/cryp_core.c
@@ -479,13 +479,13 @@ static void cryp_dma_setup_channel(struct cryp_device_data *device_data,
.dst_addr = device_data->phybase + CRYP_DMA_TX_FIFO,
.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
.dst_maxburst = 4,
- };
+ };
struct dma_slave_config cryp2mem = {
.direction = DMA_DEV_TO_MEM,
.src_addr = device_data->phybase + CRYP_DMA_RX_FIFO,
.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES,
.src_maxburst = 4,
- };
+ };
dma_cap_zero(device_data->dma.mask);
dma_cap_set(DMA_SLAVE, device_data->dma.mask);
@@ -606,12 +606,12 @@ static void cryp_dma_done(struct cryp_ctx *ctx)
dev_dbg(ctx->device->dev, "[%s]: ", __func__);
chan = ctx->device->dma.chan_mem2cryp;
- dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(chan);
dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_src,
ctx->device->dma.sg_src_len, DMA_TO_DEVICE);
chan = ctx->device->dma.chan_cryp2mem;
- dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(chan);
dma_unmap_sg(chan->device->dev, ctx->device->dma.sg_dst,
ctx->device->dma.sg_dst_len, DMA_FROM_DEVICE);
}
@@ -814,7 +814,7 @@ static int get_nents(struct scatterlist *sg, int nbytes)
while (nbytes > 0) {
nbytes -= sg->length;
- sg = scatterwalk_sg_next(sg);
+ sg = sg_next(sg);
nents++;
}
@@ -1774,8 +1774,8 @@ static int ux500_cryp_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(ux500_cryp_pm, ux500_cryp_suspend, ux500_cryp_resume);
static const struct of_device_id ux500_cryp_match[] = {
- { .compatible = "stericsson,ux500-cryp" },
- { },
+ { .compatible = "stericsson,ux500-cryp" },
+ { },
};
static struct platform_driver cryp_driver = {
diff --git a/drivers/crypto/ux500/hash/hash_core.c b/drivers/crypto/ux500/hash/hash_core.c
index 70a20871e998..187a8fd7eee7 100644
--- a/drivers/crypto/ux500/hash/hash_core.c
+++ b/drivers/crypto/ux500/hash/hash_core.c
@@ -202,7 +202,7 @@ static void hash_dma_done(struct hash_ctx *ctx)
struct dma_chan *chan;
chan = ctx->device->dma.chan_mem2hash;
- dmaengine_device_control(chan, DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(chan);
dma_unmap_sg(chan->device->dev, ctx->device->dma.sg,
ctx->device->dma.sg_len, DMA_TO_DEVICE);
}
diff --git a/drivers/devfreq/Kconfig b/drivers/devfreq/Kconfig
index faf4e70c42e0..64281bb2f650 100644
--- a/drivers/devfreq/Kconfig
+++ b/drivers/devfreq/Kconfig
@@ -1,5 +1,6 @@
menuconfig PM_DEVFREQ
bool "Generic Dynamic Voltage and Frequency Scaling (DVFS) support"
+ select SRCU
help
A device may have a list of frequencies and voltages available.
devfreq, a generic DVFS framework can be registered for a device
@@ -87,4 +88,16 @@ config ARM_EXYNOS5_BUS_DEVFREQ
It reads PPMU counters of memory controllers and adjusts the
operating frequencies and voltages with OPP support.
+config ARM_TEGRA_DEVFREQ
+ tristate "Tegra DEVFREQ Driver"
+ depends on ARCH_TEGRA_124_SOC
+ select DEVFREQ_GOV_SIMPLE_ONDEMAND
+ select PM_OPP
+ help
+ This adds the DEVFREQ driver for the Tegra family of SoCs.
+ It reads ACTMON counters of memory controllers and adjusts the
+ operating frequencies and voltages with OPP support.
+
+source "drivers/devfreq/event/Kconfig"
+
endif # PM_DEVFREQ
diff --git a/drivers/devfreq/Makefile b/drivers/devfreq/Makefile
index 16138c9e0d58..5134f9ee983d 100644
--- a/drivers/devfreq/Makefile
+++ b/drivers/devfreq/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_PM_DEVFREQ) += devfreq.o
+obj-$(CONFIG_PM_DEVFREQ_EVENT) += devfreq-event.o
obj-$(CONFIG_DEVFREQ_GOV_SIMPLE_ONDEMAND) += governor_simpleondemand.o
obj-$(CONFIG_DEVFREQ_GOV_PERFORMANCE) += governor_performance.o
obj-$(CONFIG_DEVFREQ_GOV_POWERSAVE) += governor_powersave.o
@@ -7,3 +8,7 @@ obj-$(CONFIG_DEVFREQ_GOV_USERSPACE) += governor_userspace.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS4_BUS_DEVFREQ) += exynos/
obj-$(CONFIG_ARM_EXYNOS5_BUS_DEVFREQ) += exynos/
+obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra-devfreq.o
+
+# DEVFREQ Event Drivers
+obj-$(CONFIG_PM_DEVFREQ_EVENT) += event/
diff --git a/drivers/devfreq/devfreq-event.c b/drivers/devfreq/devfreq-event.c
new file mode 100644
index 000000000000..f304a0289eda
--- /dev/null
+++ b/drivers/devfreq/devfreq-event.c
@@ -0,0 +1,494 @@
+/*
+ * devfreq-event: a framework to provide raw data and events of devfreq devices
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ * Author: Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver is based on drivers/devfreq/devfreq.c.
+ */
+
+#include <linux/devfreq-event.h>
+#include <linux/kernel.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/of.h>
+
+static struct class *devfreq_event_class;
+
+/* The list of all devfreq event list */
+static LIST_HEAD(devfreq_event_list);
+static DEFINE_MUTEX(devfreq_event_list_lock);
+
+#define to_devfreq_event(DEV) container_of(DEV, struct devfreq_event_dev, dev)
+
+/**
+ * devfreq_event_enable_edev() - Enable the devfreq-event dev and increase
+ * the enable_count of devfreq-event dev.
+ * @edev : the devfreq-event device
+ *
+ * Note that this function increase the enable_count and enable the
+ * devfreq-event device. The devfreq-event device should be enabled before
+ * using it by devfreq device.
+ */
+int devfreq_event_enable_edev(struct devfreq_event_dev *edev)
+{
+ int ret = 0;
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ mutex_lock(&edev->lock);
+ if (edev->desc->ops && edev->desc->ops->enable
+ && edev->enable_count == 0) {
+ ret = edev->desc->ops->enable(edev);
+ if (ret < 0)
+ goto err;
+ }
+ edev->enable_count++;
+err:
+ mutex_unlock(&edev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_enable_edev);
+
+/**
+ * devfreq_event_disable_edev() - Disable the devfreq-event dev and decrease
+ * the enable_count of the devfreq-event dev.
+ * @edev : the devfreq-event device
+ *
+ * Note that this function decrease the enable_count and disable the
+ * devfreq-event device. After the devfreq-event device is disabled,
+ * devfreq device can't use the devfreq-event device for get/set/reset
+ * operations.
+ */
+int devfreq_event_disable_edev(struct devfreq_event_dev *edev)
+{
+ int ret = 0;
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ mutex_lock(&edev->lock);
+ if (edev->enable_count <= 0) {
+ dev_warn(&edev->dev, "unbalanced enable_count\n");
+ ret = -EIO;
+ goto err;
+ }
+
+ if (edev->desc->ops && edev->desc->ops->disable
+ && edev->enable_count == 1) {
+ ret = edev->desc->ops->disable(edev);
+ if (ret < 0)
+ goto err;
+ }
+ edev->enable_count--;
+err:
+ mutex_unlock(&edev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_disable_edev);
+
+/**
+ * devfreq_event_is_enabled() - Check whether devfreq-event dev is enabled or
+ * not.
+ * @edev : the devfreq-event device
+ *
+ * Note that this function check whether devfreq-event dev is enabled or not.
+ * If return true, the devfreq-event dev is enabeld. If return false, the
+ * devfreq-event dev is disabled.
+ */
+bool devfreq_event_is_enabled(struct devfreq_event_dev *edev)
+{
+ bool enabled = false;
+
+ if (!edev || !edev->desc)
+ return enabled;
+
+ mutex_lock(&edev->lock);
+
+ if (edev->enable_count > 0)
+ enabled = true;
+
+ mutex_unlock(&edev->lock);
+
+ return enabled;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_is_enabled);
+
+/**
+ * devfreq_event_set_event() - Set event to devfreq-event dev to start.
+ * @edev : the devfreq-event device
+ *
+ * Note that this function set the event to the devfreq-event device to start
+ * for getting the event data which could be various event type.
+ */
+int devfreq_event_set_event(struct devfreq_event_dev *edev)
+{
+ int ret;
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ if (!edev->desc->ops || !edev->desc->ops->set_event)
+ return -EINVAL;
+
+ if (!devfreq_event_is_enabled(edev))
+ return -EPERM;
+
+ mutex_lock(&edev->lock);
+ ret = edev->desc->ops->set_event(edev);
+ mutex_unlock(&edev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_set_event);
+
+/**
+ * devfreq_event_get_event() - Get {load|total}_count from devfreq-event dev.
+ * @edev : the devfreq-event device
+ * @edata : the calculated data of devfreq-event device
+ *
+ * Note that this function get the calculated event data from devfreq-event dev
+ * after stoping the progress of whole sequence of devfreq-event dev.
+ */
+int devfreq_event_get_event(struct devfreq_event_dev *edev,
+ struct devfreq_event_data *edata)
+{
+ int ret;
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ if (!edev->desc->ops || !edev->desc->ops->get_event)
+ return -EINVAL;
+
+ if (!devfreq_event_is_enabled(edev))
+ return -EINVAL;
+
+ edata->total_count = edata->load_count = 0;
+
+ mutex_lock(&edev->lock);
+ ret = edev->desc->ops->get_event(edev, edata);
+ if (ret < 0)
+ edata->total_count = edata->load_count = 0;
+ mutex_unlock(&edev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_event);
+
+/**
+ * devfreq_event_reset_event() - Reset all opeations of devfreq-event dev.
+ * @edev : the devfreq-event device
+ *
+ * Note that this function stop all operations of devfreq-event dev and reset
+ * the current event data to make the devfreq-event device into initial state.
+ */
+int devfreq_event_reset_event(struct devfreq_event_dev *edev)
+{
+ int ret = 0;
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ if (!devfreq_event_is_enabled(edev))
+ return -EPERM;
+
+ mutex_lock(&edev->lock);
+ if (edev->desc->ops && edev->desc->ops->reset)
+ ret = edev->desc->ops->reset(edev);
+ mutex_unlock(&edev->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_reset_event);
+
+/**
+ * devfreq_event_get_edev_by_phandle() - Get the devfreq-event dev from
+ * devicetree.
+ * @dev : the pointer to the given device
+ * @index : the index into list of devfreq-event device
+ *
+ * Note that this function return the pointer of devfreq-event device.
+ */
+struct devfreq_event_dev *devfreq_event_get_edev_by_phandle(struct device *dev,
+ int index)
+{
+ struct device_node *node;
+ struct devfreq_event_dev *edev;
+
+ if (!dev->of_node) {
+ dev_err(dev, "device does not have a device node entry\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ node = of_parse_phandle(dev->of_node, "devfreq-events", index);
+ if (!node) {
+ dev_err(dev, "failed to get phandle in %s node\n",
+ dev->of_node->full_name);
+ return ERR_PTR(-ENODEV);
+ }
+
+ mutex_lock(&devfreq_event_list_lock);
+ list_for_each_entry(edev, &devfreq_event_list, node) {
+ if (!strcmp(edev->desc->name, node->name))
+ goto out;
+ }
+ edev = NULL;
+out:
+ mutex_unlock(&devfreq_event_list_lock);
+
+ if (!edev) {
+ dev_err(dev, "unable to get devfreq-event device : %s\n",
+ node->name);
+ of_node_put(node);
+ return ERR_PTR(-ENODEV);
+ }
+
+ of_node_put(node);
+
+ return edev;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_edev_by_phandle);
+
+/**
+ * devfreq_event_get_edev_count() - Get the count of devfreq-event dev
+ * @dev : the pointer to the given device
+ *
+ * Note that this function return the count of devfreq-event devices.
+ */
+int devfreq_event_get_edev_count(struct device *dev)
+{
+ int count;
+
+ if (!dev->of_node) {
+ dev_err(dev, "device does not have a device node entry\n");
+ return -EINVAL;
+ }
+
+ count = of_property_count_elems_of_size(dev->of_node, "devfreq-events",
+ sizeof(u32));
+ if (count < 0 ) {
+ dev_err(dev,
+ "failed to get the count of devfreq-event in %s node\n",
+ dev->of_node->full_name);
+ return count;
+ }
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_get_edev_count);
+
+static void devfreq_event_release_edev(struct device *dev)
+{
+ struct devfreq_event_dev *edev = to_devfreq_event(dev);
+
+ kfree(edev);
+}
+
+/**
+ * devfreq_event_add_edev() - Add new devfreq-event device.
+ * @dev : the device owning the devfreq-event device being created
+ * @desc : the devfreq-event device's decriptor which include essential
+ * data for devfreq-event device.
+ *
+ * Note that this function add new devfreq-event device to devfreq-event class
+ * list and register the device of the devfreq-event device.
+ */
+struct devfreq_event_dev *devfreq_event_add_edev(struct device *dev,
+ struct devfreq_event_desc *desc)
+{
+ struct devfreq_event_dev *edev;
+ static atomic_t event_no = ATOMIC_INIT(0);
+ int ret;
+
+ if (!dev || !desc)
+ return ERR_PTR(-EINVAL);
+
+ if (!desc->name || !desc->ops)
+ return ERR_PTR(-EINVAL);
+
+ if (!desc->ops->set_event || !desc->ops->get_event)
+ return ERR_PTR(-EINVAL);
+
+ edev = kzalloc(sizeof(struct devfreq_event_dev), GFP_KERNEL);
+ if (!edev)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&edev->lock);
+ edev->desc = desc;
+ edev->enable_count = 0;
+ edev->dev.parent = dev;
+ edev->dev.class = devfreq_event_class;
+ edev->dev.release = devfreq_event_release_edev;
+
+ dev_set_name(&edev->dev, "event.%d", atomic_inc_return(&event_no) - 1);
+ ret = device_register(&edev->dev);
+ if (ret < 0) {
+ put_device(&edev->dev);
+ return ERR_PTR(ret);
+ }
+ dev_set_drvdata(&edev->dev, edev);
+
+ INIT_LIST_HEAD(&edev->node);
+
+ mutex_lock(&devfreq_event_list_lock);
+ list_add(&edev->node, &devfreq_event_list);
+ mutex_unlock(&devfreq_event_list_lock);
+
+ return edev;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
+
+/**
+ * devfreq_event_remove_edev() - Remove the devfreq-event device registered.
+ * @dev : the devfreq-event device
+ *
+ * Note that this function remove the registered devfreq-event device.
+ */
+int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
+{
+ if (!edev)
+ return -EINVAL;
+
+ WARN_ON(edev->enable_count);
+
+ mutex_lock(&devfreq_event_list_lock);
+ list_del(&edev->node);
+ mutex_unlock(&devfreq_event_list_lock);
+
+ device_unregister(&edev->dev);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(devfreq_event_remove_edev);
+
+static int devm_devfreq_event_match(struct device *dev, void *res, void *data)
+{
+ struct devfreq_event_dev **r = res;
+
+ if (WARN_ON(!r || !*r))
+ return 0;
+
+ return *r == data;
+}
+
+static void devm_devfreq_event_release(struct device *dev, void *res)
+{
+ devfreq_event_remove_edev(*(struct devfreq_event_dev **)res);
+}
+
+/**
+ * devm_devfreq_event_add_edev() - Resource-managed devfreq_event_add_edev()
+ * @dev : the device owning the devfreq-event device being created
+ * @desc : the devfreq-event device's decriptor which include essential
+ * data for devfreq-event device.
+ *
+ * Note that this function manages automatically the memory of devfreq-event
+ * device using device resource management and simplify the free operation
+ * for memory of devfreq-event device.
+ */
+struct devfreq_event_dev *devm_devfreq_event_add_edev(struct device *dev,
+ struct devfreq_event_desc *desc)
+{
+ struct devfreq_event_dev **ptr, *edev;
+
+ ptr = devres_alloc(devm_devfreq_event_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return ERR_PTR(-ENOMEM);
+
+ edev = devfreq_event_add_edev(dev, desc);
+ if (IS_ERR(edev)) {
+ devres_free(ptr);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ *ptr = edev;
+ devres_add(dev, ptr);
+
+ return edev;
+}
+EXPORT_SYMBOL_GPL(devm_devfreq_event_add_edev);
+
+/**
+ * devm_devfreq_event_remove_edev()- Resource-managed devfreq_event_remove_edev()
+ * @dev : the device owning the devfreq-event device being created
+ * @edev : the devfreq-event device
+ *
+ * Note that this function manages automatically the memory of devfreq-event
+ * device using device resource management.
+ */
+void devm_devfreq_event_remove_edev(struct device *dev,
+ struct devfreq_event_dev *edev)
+{
+ WARN_ON(devres_release(dev, devm_devfreq_event_release,
+ devm_devfreq_event_match, edev));
+}
+EXPORT_SYMBOL_GPL(devm_devfreq_event_remove_edev);
+
+/*
+ * Device attributes for devfreq-event class.
+ */
+static ssize_t name_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct devfreq_event_dev *edev = to_devfreq_event(dev);
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ return sprintf(buf, "%s\n", edev->desc->name);
+}
+static DEVICE_ATTR_RO(name);
+
+static ssize_t enable_count_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct devfreq_event_dev *edev = to_devfreq_event(dev);
+
+ if (!edev || !edev->desc)
+ return -EINVAL;
+
+ return sprintf(buf, "%d\n", edev->enable_count);
+}
+static DEVICE_ATTR_RO(enable_count);
+
+static struct attribute *devfreq_event_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_enable_count.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(devfreq_event);
+
+static int __init devfreq_event_init(void)
+{
+ devfreq_event_class = class_create(THIS_MODULE, "devfreq-event");
+ if (IS_ERR(devfreq_event_class)) {
+ pr_err("%s: couldn't create class\n", __FILE__);
+ return PTR_ERR(devfreq_event_class);
+ }
+
+ devfreq_event_class->dev_groups = devfreq_event_groups;
+
+ return 0;
+}
+subsys_initcall(devfreq_event_init);
+
+static void __exit devfreq_event_exit(void)
+{
+ class_destroy(devfreq_event_class);
+}
+module_exit(devfreq_event_exit);
+
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_DESCRIPTION("DEVFREQ-Event class support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/event/Kconfig b/drivers/devfreq/event/Kconfig
new file mode 100644
index 000000000000..a11720affc31
--- /dev/null
+++ b/drivers/devfreq/event/Kconfig
@@ -0,0 +1,25 @@
+menuconfig PM_DEVFREQ_EVENT
+ bool "DEVFREQ-Event device Support"
+ help
+ The devfreq-event device provide the raw data and events which
+ indicate the current state of devfreq-event device. The provided
+ data from devfreq-event device is used to monitor the state of
+ device and determine the suitable size of resource to reduce the
+ wasted resource.
+
+ The devfreq-event device can support the various type of events
+ (e.g., raw data, utilization, latency, bandwidth). The events
+ may be used by devfreq governor and other subsystem.
+
+if PM_DEVFREQ_EVENT
+
+config DEVFREQ_EVENT_EXYNOS_PPMU
+ bool "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
+ depends on ARCH_EXYNOS
+ select PM_OPP
+ help
+ This add the devfreq-event driver for Exynos SoC. It provides PPMU
+ (Platform Performance Monitoring Unit) counters to estimate the
+ utilization of each module.
+
+endif # PM_DEVFREQ_EVENT
diff --git a/drivers/devfreq/event/Makefile b/drivers/devfreq/event/Makefile
new file mode 100644
index 000000000000..be146ead79cf
--- /dev/null
+++ b/drivers/devfreq/event/Makefile
@@ -0,0 +1,2 @@
+# Exynos DEVFREQ Event Drivers
+obj-$(CONFIG_DEVFREQ_EVENT_EXYNOS_PPMU) += exynos-ppmu.o
diff --git a/drivers/devfreq/event/exynos-ppmu.c b/drivers/devfreq/event/exynos-ppmu.c
new file mode 100644
index 000000000000..ad8347385f53
--- /dev/null
+++ b/drivers/devfreq/event/exynos-ppmu.c
@@ -0,0 +1,374 @@
+/*
+ * exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author : Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This driver is based on drivers/devfreq/exynos/exynos_ppmu.c
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/suspend.h>
+#include <linux/devfreq-event.h>
+
+#include "exynos-ppmu.h"
+
+struct exynos_ppmu_data {
+ void __iomem *base;
+ struct clk *clk;
+};
+
+struct exynos_ppmu {
+ struct devfreq_event_dev **edev;
+ struct devfreq_event_desc *desc;
+ unsigned int num_events;
+
+ struct device *dev;
+ struct mutex lock;
+
+ struct exynos_ppmu_data ppmu;
+};
+
+#define PPMU_EVENT(name) \
+ { "ppmu-event0-"#name, PPMU_PMNCNT0 }, \
+ { "ppmu-event1-"#name, PPMU_PMNCNT1 }, \
+ { "ppmu-event2-"#name, PPMU_PMNCNT2 }, \
+ { "ppmu-event3-"#name, PPMU_PMNCNT3 }
+
+struct __exynos_ppmu_events {
+ char *name;
+ int id;
+} ppmu_events[] = {
+ /* For Exynos3250, Exynos4 and Exynos5260 */
+ PPMU_EVENT(g3d),
+ PPMU_EVENT(fsys),
+
+ /* For Exynos4 SoCs and Exynos3250 */
+ PPMU_EVENT(dmc0),
+ PPMU_EVENT(dmc1),
+ PPMU_EVENT(cpu),
+ PPMU_EVENT(rightbus),
+ PPMU_EVENT(leftbus),
+ PPMU_EVENT(lcd0),
+ PPMU_EVENT(camif),
+
+ /* Only for Exynos3250 and Exynos5260 */
+ PPMU_EVENT(mfc),
+
+ /* Only for Exynos4 SoCs */
+ PPMU_EVENT(mfc-left),
+ PPMU_EVENT(mfc-right),
+
+ /* Only for Exynos5260 SoCs */
+ PPMU_EVENT(drex0-s0),
+ PPMU_EVENT(drex0-s1),
+ PPMU_EVENT(drex1-s0),
+ PPMU_EVENT(drex1-s1),
+ PPMU_EVENT(eagle),
+ PPMU_EVENT(kfc),
+ PPMU_EVENT(isp),
+ PPMU_EVENT(fimc),
+ PPMU_EVENT(gscl),
+ PPMU_EVENT(mscl),
+ PPMU_EVENT(fimd0x),
+ PPMU_EVENT(fimd1x),
+ { /* sentinel */ },
+};
+
+static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
+ if (!strcmp(edev->desc->name, ppmu_events[i].name))
+ return ppmu_events[i].id;
+
+ return -EINVAL;
+}
+
+static int exynos_ppmu_disable(struct devfreq_event_dev *edev)
+{
+ struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+ u32 pmnc;
+
+ /* Disable all counters */
+ __raw_writel(PPMU_CCNT_MASK |
+ PPMU_PMCNT0_MASK |
+ PPMU_PMCNT1_MASK |
+ PPMU_PMCNT2_MASK |
+ PPMU_PMCNT3_MASK,
+ info->ppmu.base + PPMU_CNTENC);
+
+ /* Disable PPMU */
+ pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+ pmnc &= ~PPMU_PMNC_ENABLE_MASK;
+ __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+
+ return 0;
+}
+
+static int exynos_ppmu_set_event(struct devfreq_event_dev *edev)
+{
+ struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+ int id = exynos_ppmu_find_ppmu_id(edev);
+ u32 pmnc, cntens;
+
+ if (id < 0)
+ return id;
+
+ /* Enable specific counter */
+ cntens = __raw_readl(info->ppmu.base + PPMU_CNTENS);
+ cntens |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
+ __raw_writel(cntens, info->ppmu.base + PPMU_CNTENS);
+
+ /* Set the event of Read/Write data count */
+ __raw_writel(PPMU_RO_DATA_CNT | PPMU_WO_DATA_CNT,
+ info->ppmu.base + PPMU_BEVTxSEL(id));
+
+ /* Reset cycle counter/performance counter and enable PPMU */
+ pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+ pmnc &= ~(PPMU_PMNC_ENABLE_MASK
+ | PPMU_PMNC_COUNTER_RESET_MASK
+ | PPMU_PMNC_CC_RESET_MASK);
+ pmnc |= (PPMU_ENABLE << PPMU_PMNC_ENABLE_SHIFT);
+ pmnc |= (PPMU_ENABLE << PPMU_PMNC_COUNTER_RESET_SHIFT);
+ pmnc |= (PPMU_ENABLE << PPMU_PMNC_CC_RESET_SHIFT);
+ __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+
+ return 0;
+}
+
+static int exynos_ppmu_get_event(struct devfreq_event_dev *edev,
+ struct devfreq_event_data *edata)
+{
+ struct exynos_ppmu *info = devfreq_event_get_drvdata(edev);
+ int id = exynos_ppmu_find_ppmu_id(edev);
+ u32 pmnc, cntenc;
+
+ if (id < 0)
+ return -EINVAL;
+
+ /* Disable PPMU */
+ pmnc = __raw_readl(info->ppmu.base + PPMU_PMNC);
+ pmnc &= ~PPMU_PMNC_ENABLE_MASK;
+ __raw_writel(pmnc, info->ppmu.base + PPMU_PMNC);
+
+ /* Read cycle count */
+ edata->total_count = __raw_readl(info->ppmu.base + PPMU_CCNT);
+
+ /* Read performance count */
+ switch (id) {
+ case PPMU_PMNCNT0:
+ case PPMU_PMNCNT1:
+ case PPMU_PMNCNT2:
+ edata->load_count
+ = __raw_readl(info->ppmu.base + PPMU_PMNCT(id));
+ break;
+ case PPMU_PMNCNT3:
+ edata->load_count =
+ ((__raw_readl(info->ppmu.base + PPMU_PMCNT3_HIGH) << 8)
+ | __raw_readl(info->ppmu.base + PPMU_PMCNT3_LOW));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Disable specific counter */
+ cntenc = __raw_readl(info->ppmu.base + PPMU_CNTENC);
+ cntenc |= (PPMU_CCNT_MASK | (PPMU_ENABLE << id));
+ __raw_writel(cntenc, info->ppmu.base + PPMU_CNTENC);
+
+ dev_dbg(&edev->dev, "%s (event: %ld/%ld)\n", edev->desc->name,
+ edata->load_count, edata->total_count);
+
+ return 0;
+}
+
+static struct devfreq_event_ops exynos_ppmu_ops = {
+ .disable = exynos_ppmu_disable,
+ .set_event = exynos_ppmu_set_event,
+ .get_event = exynos_ppmu_get_event,
+};
+
+static int of_get_devfreq_events(struct device_node *np,
+ struct exynos_ppmu *info)
+{
+ struct devfreq_event_desc *desc;
+ struct device *dev = info->dev;
+ struct device_node *events_np, *node;
+ int i, j, count;
+
+ events_np = of_get_child_by_name(np, "events");
+ if (!events_np) {
+ dev_err(dev,
+ "failed to get child node of devfreq-event devices\n");
+ return -EINVAL;
+ }
+
+ count = of_get_child_count(events_np);
+ desc = devm_kzalloc(dev, sizeof(*desc) * count, GFP_KERNEL);
+ if (!desc)
+ return -ENOMEM;
+ info->num_events = count;
+
+ j = 0;
+ for_each_child_of_node(events_np, node) {
+ for (i = 0; i < ARRAY_SIZE(ppmu_events); i++) {
+ if (!ppmu_events[i].name)
+ continue;
+
+ if (!of_node_cmp(node->name, ppmu_events[i].name))
+ break;
+ }
+
+ if (i == ARRAY_SIZE(ppmu_events)) {
+ dev_warn(dev,
+ "don't know how to configure events : %s\n",
+ node->name);
+ continue;
+ }
+
+ desc[j].ops = &exynos_ppmu_ops;
+ desc[j].driver_data = info;
+
+ of_property_read_string(node, "event-name", &desc[j].name);
+
+ j++;
+
+ of_node_put(node);
+ }
+ info->desc = desc;
+
+ of_node_put(events_np);
+
+ return 0;
+}
+
+static int exynos_ppmu_parse_dt(struct exynos_ppmu *info)
+{
+ struct device *dev = info->dev;
+ struct device_node *np = dev->of_node;
+ int ret = 0;
+
+ if (!np) {
+ dev_err(dev, "failed to find devicetree node\n");
+ return -EINVAL;
+ }
+
+ /* Maps the memory mapped IO to control PPMU register */
+ info->ppmu.base = of_iomap(np, 0);
+ if (IS_ERR_OR_NULL(info->ppmu.base)) {
+ dev_err(dev, "failed to map memory region\n");
+ return -ENOMEM;
+ }
+
+ info->ppmu.clk = devm_clk_get(dev, "ppmu");
+ if (IS_ERR(info->ppmu.clk)) {
+ info->ppmu.clk = NULL;
+ dev_warn(dev, "cannot get PPMU clock\n");
+ }
+
+ ret = of_get_devfreq_events(np, info);
+ if (ret < 0) {
+ dev_err(dev, "failed to parse exynos ppmu dt node\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ iounmap(info->ppmu.base);
+
+ return ret;
+}
+
+static int exynos_ppmu_probe(struct platform_device *pdev)
+{
+ struct exynos_ppmu *info;
+ struct devfreq_event_dev **edev;
+ struct devfreq_event_desc *desc;
+ int i, ret = 0, size;
+
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ mutex_init(&info->lock);
+ info->dev = &pdev->dev;
+
+ /* Parse dt data to get resource */
+ ret = exynos_ppmu_parse_dt(info);
+ if (ret < 0) {
+ dev_err(&pdev->dev,
+ "failed to parse devicetree for resource\n");
+ return ret;
+ }
+ desc = info->desc;
+
+ size = sizeof(struct devfreq_event_dev *) * info->num_events;
+ info->edev = devm_kzalloc(&pdev->dev, size, GFP_KERNEL);
+ if (!info->edev) {
+ dev_err(&pdev->dev,
+ "failed to allocate memory devfreq-event devices\n");
+ return -ENOMEM;
+ }
+ edev = info->edev;
+ platform_set_drvdata(pdev, info);
+
+ for (i = 0; i < info->num_events; i++) {
+ edev[i] = devm_devfreq_event_add_edev(&pdev->dev, &desc[i]);
+ if (IS_ERR(edev[i])) {
+ ret = PTR_ERR(edev[i]);
+ dev_err(&pdev->dev,
+ "failed to add devfreq-event device\n");
+ goto err;
+ }
+ }
+
+ clk_prepare_enable(info->ppmu.clk);
+
+ return 0;
+err:
+ iounmap(info->ppmu.base);
+
+ return ret;
+}
+
+static int exynos_ppmu_remove(struct platform_device *pdev)
+{
+ struct exynos_ppmu *info = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(info->ppmu.clk);
+ iounmap(info->ppmu.base);
+
+ return 0;
+}
+
+static struct of_device_id exynos_ppmu_id_match[] = {
+ { .compatible = "samsung,exynos-ppmu", },
+ { /* sentinel */ },
+};
+
+static struct platform_driver exynos_ppmu_driver = {
+ .probe = exynos_ppmu_probe,
+ .remove = exynos_ppmu_remove,
+ .driver = {
+ .name = "exynos-ppmu",
+ .of_match_table = exynos_ppmu_id_match,
+ },
+};
+module_platform_driver(exynos_ppmu_driver);
+
+MODULE_DESCRIPTION("Exynos PPMU(Platform Performance Monitoring Unit) driver");
+MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/devfreq/event/exynos-ppmu.h b/drivers/devfreq/event/exynos-ppmu.h
new file mode 100644
index 000000000000..4e831d48c138
--- /dev/null
+++ b/drivers/devfreq/event/exynos-ppmu.h
@@ -0,0 +1,93 @@
+/*
+ * exynos_ppmu.h - EXYNOS PPMU header file
+ *
+ * Copyright (c) 2015 Samsung Electronics Co., Ltd.
+ * Author : Chanwoo Choi <cw00.choi@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __EXYNOS_PPMU_H__
+#define __EXYNOS_PPMU_H__
+
+enum ppmu_state {
+ PPMU_DISABLE = 0,
+ PPMU_ENABLE,
+};
+
+enum ppmu_counter {
+ PPMU_PMNCNT0 = 0,
+ PPMU_PMNCNT1,
+ PPMU_PMNCNT2,
+ PPMU_PMNCNT3,
+
+ PPMU_PMNCNT_MAX,
+};
+
+enum ppmu_event_type {
+ PPMU_RO_BUSY_CYCLE_CNT = 0x0,
+ PPMU_WO_BUSY_CYCLE_CNT = 0x1,
+ PPMU_RW_BUSY_CYCLE_CNT = 0x2,
+ PPMU_RO_REQUEST_CNT = 0x3,
+ PPMU_WO_REQUEST_CNT = 0x4,
+ PPMU_RO_DATA_CNT = 0x5,
+ PPMU_WO_DATA_CNT = 0x6,
+ PPMU_RO_LATENCY = 0x12,
+ PPMU_WO_LATENCY = 0x16,
+};
+
+enum ppmu_reg {
+ /* PPC control register */
+ PPMU_PMNC = 0x00,
+ PPMU_CNTENS = 0x10,
+ PPMU_CNTENC = 0x20,
+ PPMU_INTENS = 0x30,
+ PPMU_INTENC = 0x40,
+ PPMU_FLAG = 0x50,
+
+ /* Cycle Counter and Performance Event Counter Register */
+ PPMU_CCNT = 0x100,
+ PPMU_PMCNT0 = 0x110,
+ PPMU_PMCNT1 = 0x120,
+ PPMU_PMCNT2 = 0x130,
+ PPMU_PMCNT3_HIGH = 0x140,
+ PPMU_PMCNT3_LOW = 0x150,
+
+ /* Bus Event Generator */
+ PPMU_BEVT0SEL = 0x1000,
+ PPMU_BEVT1SEL = 0x1100,
+ PPMU_BEVT2SEL = 0x1200,
+ PPMU_BEVT3SEL = 0x1300,
+ PPMU_COUNTER_RESET = 0x1810,
+ PPMU_READ_OVERFLOW_CNT = 0x1810,
+ PPMU_READ_UNDERFLOW_CNT = 0x1814,
+ PPMU_WRITE_OVERFLOW_CNT = 0x1850,
+ PPMU_WRITE_UNDERFLOW_CNT = 0x1854,
+ PPMU_READ_PENDING_CNT = 0x1880,
+ PPMU_WRITE_PENDING_CNT = 0x1884
+};
+
+/* PMNC register */
+#define PPMU_PMNC_CC_RESET_SHIFT 2
+#define PPMU_PMNC_COUNTER_RESET_SHIFT 1
+#define PPMU_PMNC_ENABLE_SHIFT 0
+#define PPMU_PMNC_START_MODE_MASK BIT(16)
+#define PPMU_PMNC_CC_DIVIDER_MASK BIT(3)
+#define PPMU_PMNC_CC_RESET_MASK BIT(2)
+#define PPMU_PMNC_COUNTER_RESET_MASK BIT(1)
+#define PPMU_PMNC_ENABLE_MASK BIT(0)
+
+/* CNTENS/CNTENC/INTENS/INTENC/FLAG register */
+#define PPMU_CCNT_MASK BIT(31)
+#define PPMU_PMCNT3_MASK BIT(3)
+#define PPMU_PMCNT2_MASK BIT(2)
+#define PPMU_PMCNT1_MASK BIT(1)
+#define PPMU_PMCNT0_MASK BIT(0)
+
+/* PPMU_PMNCTx/PPMU_BETxSEL registers */
+#define PPMU_PMNCT(x) (PPMU_PMCNT0 + (0x10 * x))
+#define PPMU_BEVTxSEL(x) (PPMU_BEVT0SEL + (0x100 * x))
+
+#endif /* __EXYNOS_PPMU_H__ */
diff --git a/drivers/devfreq/tegra-devfreq.c b/drivers/devfreq/tegra-devfreq.c
new file mode 100644
index 000000000000..34790961af5a
--- /dev/null
+++ b/drivers/devfreq/tegra-devfreq.c
@@ -0,0 +1,718 @@
+/*
+ * A devfreq driver for NVIDIA Tegra SoCs
+ *
+ * Copyright (c) 2014 NVIDIA CORPORATION. All rights reserved.
+ * 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.
+ *
+ * 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/cpufreq.h>
+#include <linux/devfreq.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_opp.h>
+#include <linux/reset.h>
+
+#include "governor.h"
+
+#define ACTMON_GLB_STATUS 0x0
+#define ACTMON_GLB_PERIOD_CTRL 0x4
+
+#define ACTMON_DEV_CTRL 0x0
+#define ACTMON_DEV_CTRL_K_VAL_SHIFT 10
+#define ACTMON_DEV_CTRL_ENB_PERIODIC BIT(18)
+#define ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN BIT(20)
+#define ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN BIT(21)
+#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT 23
+#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT 26
+#define ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN BIT(29)
+#define ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN BIT(30)
+#define ACTMON_DEV_CTRL_ENB BIT(31)
+
+#define ACTMON_DEV_UPPER_WMARK 0x4
+#define ACTMON_DEV_LOWER_WMARK 0x8
+#define ACTMON_DEV_INIT_AVG 0xc
+#define ACTMON_DEV_AVG_UPPER_WMARK 0x10
+#define ACTMON_DEV_AVG_LOWER_WMARK 0x14
+#define ACTMON_DEV_COUNT_WEIGHT 0x18
+#define ACTMON_DEV_AVG_COUNT 0x20
+#define ACTMON_DEV_INTR_STATUS 0x24
+
+#define ACTMON_INTR_STATUS_CLEAR 0xffffffff
+
+#define ACTMON_DEV_INTR_CONSECUTIVE_UPPER BIT(31)
+#define ACTMON_DEV_INTR_CONSECUTIVE_LOWER BIT(30)
+
+#define ACTMON_ABOVE_WMARK_WINDOW 1
+#define ACTMON_BELOW_WMARK_WINDOW 3
+#define ACTMON_BOOST_FREQ_STEP 16000
+
+/* activity counter is incremented every 256 memory transactions, and each
+ * transaction takes 4 EMC clocks for Tegra124; So the COUNT_WEIGHT is
+ * 4 * 256 = 1024.
+ */
+#define ACTMON_COUNT_WEIGHT 0x400
+
+/*
+ * ACTMON_AVERAGE_WINDOW_LOG2: default value for @DEV_CTRL_K_VAL, which
+ * translates to 2 ^ (K_VAL + 1). ex: 2 ^ (6 + 1) = 128
+ */
+#define ACTMON_AVERAGE_WINDOW_LOG2 6
+#define ACTMON_SAMPLING_PERIOD 12 /* ms */
+#define ACTMON_DEFAULT_AVG_BAND 6 /* 1/10 of % */
+
+#define KHZ 1000
+
+/* Assume that the bus is saturated if the utilization is 25% */
+#define BUS_SATURATION_RATIO 25
+
+/**
+ * struct tegra_devfreq_device_config - configuration specific to an ACTMON
+ * device
+ *
+ * Coefficients and thresholds are in %
+ */
+struct tegra_devfreq_device_config {
+ u32 offset;
+ u32 irq_mask;
+
+ unsigned int boost_up_coeff;
+ unsigned int boost_down_coeff;
+ unsigned int boost_up_threshold;
+ unsigned int boost_down_threshold;
+ u32 avg_dependency_threshold;
+};
+
+enum tegra_actmon_device {
+ MCALL = 0,
+ MCCPU,
+};
+
+static struct tegra_devfreq_device_config actmon_device_configs[] = {
+ {
+ /* MCALL */
+ .offset = 0x1c0,
+ .irq_mask = 1 << 26,
+ .boost_up_coeff = 200,
+ .boost_down_coeff = 50,
+ .boost_up_threshold = 60,
+ .boost_down_threshold = 40,
+ },
+ {
+ /* MCCPU */
+ .offset = 0x200,
+ .irq_mask = 1 << 25,
+ .boost_up_coeff = 800,
+ .boost_down_coeff = 90,
+ .boost_up_threshold = 27,
+ .boost_down_threshold = 10,
+ .avg_dependency_threshold = 50000,
+ },
+};
+
+/**
+ * struct tegra_devfreq_device - state specific to an ACTMON device
+ *
+ * Frequencies are in kHz.
+ */
+struct tegra_devfreq_device {
+ const struct tegra_devfreq_device_config *config;
+
+ void __iomem *regs;
+ u32 avg_band_freq;
+ u32 avg_count;
+
+ unsigned long target_freq;
+ unsigned long boost_freq;
+};
+
+struct tegra_devfreq {
+ struct devfreq *devfreq;
+
+ struct platform_device *pdev;
+ struct reset_control *reset;
+ struct clk *clock;
+ void __iomem *regs;
+
+ spinlock_t lock;
+
+ struct clk *emc_clock;
+ unsigned long max_freq;
+ unsigned long cur_freq;
+ struct notifier_block rate_change_nb;
+
+ struct tegra_devfreq_device devices[ARRAY_SIZE(actmon_device_configs)];
+};
+
+struct tegra_actmon_emc_ratio {
+ unsigned long cpu_freq;
+ unsigned long emc_freq;
+};
+
+static struct tegra_actmon_emc_ratio actmon_emc_ratios[] = {
+ { 1400000, ULONG_MAX },
+ { 1200000, 750000 },
+ { 1100000, 600000 },
+ { 1000000, 500000 },
+ { 800000, 375000 },
+ { 500000, 200000 },
+ { 250000, 100000 },
+};
+
+static unsigned long do_percent(unsigned long val, unsigned int pct)
+{
+ return val * pct / 100;
+}
+
+static void tegra_devfreq_update_avg_wmark(struct tegra_devfreq_device *dev)
+{
+ u32 avg = dev->avg_count;
+ u32 band = dev->avg_band_freq * ACTMON_SAMPLING_PERIOD;
+
+ writel(avg + band, dev->regs + ACTMON_DEV_AVG_UPPER_WMARK);
+ avg = max(avg, band);
+ writel(avg - band, dev->regs + ACTMON_DEV_AVG_LOWER_WMARK);
+}
+
+static void tegra_devfreq_update_wmark(struct tegra_devfreq *tegra,
+ struct tegra_devfreq_device *dev)
+{
+ u32 val = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
+
+ writel(do_percent(val, dev->config->boost_up_threshold),
+ dev->regs + ACTMON_DEV_UPPER_WMARK);
+
+ writel(do_percent(val, dev->config->boost_down_threshold),
+ dev->regs + ACTMON_DEV_LOWER_WMARK);
+}
+
+static void actmon_write_barrier(struct tegra_devfreq *tegra)
+{
+ /* ensure the update has reached the ACTMON */
+ wmb();
+ readl(tegra->regs + ACTMON_GLB_STATUS);
+}
+
+static irqreturn_t actmon_isr(int irq, void *data)
+{
+ struct tegra_devfreq *tegra = data;
+ struct tegra_devfreq_device *dev = NULL;
+ unsigned long flags;
+ u32 val;
+ unsigned int i;
+
+ val = readl(tegra->regs + ACTMON_GLB_STATUS);
+
+ for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+ if (val & tegra->devices[i].config->irq_mask) {
+ dev = tegra->devices + i;
+ break;
+ }
+ }
+
+ if (!dev)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&tegra->lock, flags);
+
+ dev->avg_count = readl(dev->regs + ACTMON_DEV_AVG_COUNT);
+ tegra_devfreq_update_avg_wmark(dev);
+
+ val = readl(dev->regs + ACTMON_DEV_INTR_STATUS);
+ if (val & ACTMON_DEV_INTR_CONSECUTIVE_UPPER) {
+ val = readl(dev->regs + ACTMON_DEV_CTRL) |
+ ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN |
+ ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+
+ /*
+ * new_boost = min(old_boost * up_coef + step, max_freq)
+ */
+ dev->boost_freq = do_percent(dev->boost_freq,
+ dev->config->boost_up_coeff);
+ dev->boost_freq += ACTMON_BOOST_FREQ_STEP;
+ if (dev->boost_freq >= tegra->max_freq) {
+ dev->boost_freq = tegra->max_freq;
+ val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
+ }
+ writel(val, dev->regs + ACTMON_DEV_CTRL);
+ } else if (val & ACTMON_DEV_INTR_CONSECUTIVE_LOWER) {
+ val = readl(dev->regs + ACTMON_DEV_CTRL) |
+ ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN |
+ ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+
+ /*
+ * new_boost = old_boost * down_coef
+ * or 0 if (old_boost * down_coef < step / 2)
+ */
+ dev->boost_freq = do_percent(dev->boost_freq,
+ dev->config->boost_down_coeff);
+ if (dev->boost_freq < (ACTMON_BOOST_FREQ_STEP >> 1)) {
+ dev->boost_freq = 0;
+ val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+ }
+ writel(val, dev->regs + ACTMON_DEV_CTRL);
+ }
+
+ if (dev->config->avg_dependency_threshold) {
+ val = readl(dev->regs + ACTMON_DEV_CTRL);
+ if (dev->avg_count >= dev->config->avg_dependency_threshold)
+ val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+ else if (dev->boost_freq == 0)
+ val &= ~ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN;
+ writel(val, dev->regs + ACTMON_DEV_CTRL);
+ }
+
+ writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS);
+
+ actmon_write_barrier(tegra);
+
+ spin_unlock_irqrestore(&tegra->lock, flags);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static unsigned long actmon_cpu_to_emc_rate(struct tegra_devfreq *tegra,
+ unsigned long cpu_freq)
+{
+ unsigned int i;
+ struct tegra_actmon_emc_ratio *ratio = actmon_emc_ratios;
+
+ for (i = 0; i < ARRAY_SIZE(actmon_emc_ratios); i++, ratio++) {
+ if (cpu_freq >= ratio->cpu_freq) {
+ if (ratio->emc_freq >= tegra->max_freq)
+ return tegra->max_freq;
+ else
+ return ratio->emc_freq;
+ }
+ }
+
+ return 0;
+}
+
+static void actmon_update_target(struct tegra_devfreq *tegra,
+ struct tegra_devfreq_device *dev)
+{
+ unsigned long cpu_freq = 0;
+ unsigned long static_cpu_emc_freq = 0;
+ unsigned int avg_sustain_coef;
+ unsigned long flags;
+
+ if (dev->config->avg_dependency_threshold) {
+ cpu_freq = cpufreq_get(0);
+ static_cpu_emc_freq = actmon_cpu_to_emc_rate(tegra, cpu_freq);
+ }
+
+ spin_lock_irqsave(&tegra->lock, flags);
+
+ dev->target_freq = dev->avg_count / ACTMON_SAMPLING_PERIOD;
+ avg_sustain_coef = 100 * 100 / dev->config->boost_up_threshold;
+ dev->target_freq = do_percent(dev->target_freq, avg_sustain_coef);
+ dev->target_freq += dev->boost_freq;
+
+ if (dev->avg_count >= dev->config->avg_dependency_threshold)
+ dev->target_freq = max(dev->target_freq, static_cpu_emc_freq);
+
+ spin_unlock_irqrestore(&tegra->lock, flags);
+}
+
+static irqreturn_t actmon_thread_isr(int irq, void *data)
+{
+ struct tegra_devfreq *tegra = data;
+
+ mutex_lock(&tegra->devfreq->lock);
+ update_devfreq(tegra->devfreq);
+ mutex_unlock(&tegra->devfreq->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int tegra_actmon_rate_notify_cb(struct notifier_block *nb,
+ unsigned long action, void *ptr)
+{
+ struct clk_notifier_data *data = ptr;
+ struct tegra_devfreq *tegra = container_of(nb, struct tegra_devfreq,
+ rate_change_nb);
+ unsigned int i;
+ unsigned long flags;
+
+ spin_lock_irqsave(&tegra->lock, flags);
+
+ switch (action) {
+ case POST_RATE_CHANGE:
+ tegra->cur_freq = data->new_rate / KHZ;
+
+ for (i = 0; i < ARRAY_SIZE(tegra->devices); i++)
+ tegra_devfreq_update_wmark(tegra, tegra->devices + i);
+
+ actmon_write_barrier(tegra);
+ break;
+ case PRE_RATE_CHANGE:
+ /* fall through */
+ case ABORT_RATE_CHANGE:
+ break;
+ };
+
+ spin_unlock_irqrestore(&tegra->lock, flags);
+
+ return NOTIFY_OK;
+}
+
+static void tegra_actmon_configure_device(struct tegra_devfreq *tegra,
+ struct tegra_devfreq_device *dev)
+{
+ u32 val;
+
+ dev->avg_band_freq = tegra->max_freq * ACTMON_DEFAULT_AVG_BAND / KHZ;
+ dev->target_freq = tegra->cur_freq;
+
+ dev->avg_count = tegra->cur_freq * ACTMON_SAMPLING_PERIOD;
+ writel(dev->avg_count, dev->regs + ACTMON_DEV_INIT_AVG);
+
+ tegra_devfreq_update_avg_wmark(dev);
+ tegra_devfreq_update_wmark(tegra, dev);
+
+ writel(ACTMON_COUNT_WEIGHT, dev->regs + ACTMON_DEV_COUNT_WEIGHT);
+ writel(ACTMON_INTR_STATUS_CLEAR, dev->regs + ACTMON_DEV_INTR_STATUS);
+
+ val = 0;
+ val |= ACTMON_DEV_CTRL_ENB_PERIODIC |
+ ACTMON_DEV_CTRL_AVG_ABOVE_WMARK_EN |
+ ACTMON_DEV_CTRL_AVG_BELOW_WMARK_EN;
+ val |= (ACTMON_AVERAGE_WINDOW_LOG2 - 1)
+ << ACTMON_DEV_CTRL_K_VAL_SHIFT;
+ val |= (ACTMON_BELOW_WMARK_WINDOW - 1)
+ << ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_NUM_SHIFT;
+ val |= (ACTMON_ABOVE_WMARK_WINDOW - 1)
+ << ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_NUM_SHIFT;
+ val |= ACTMON_DEV_CTRL_CONSECUTIVE_BELOW_WMARK_EN |
+ ACTMON_DEV_CTRL_CONSECUTIVE_ABOVE_WMARK_EN;
+
+ writel(val, dev->regs + ACTMON_DEV_CTRL);
+
+ actmon_write_barrier(tegra);
+
+ val = readl(dev->regs + ACTMON_DEV_CTRL);
+ val |= ACTMON_DEV_CTRL_ENB;
+ writel(val, dev->regs + ACTMON_DEV_CTRL);
+
+ actmon_write_barrier(tegra);
+}
+
+static int tegra_devfreq_suspend(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct tegra_devfreq *tegra;
+ struct tegra_devfreq_device *actmon_dev;
+ unsigned int i;
+ u32 val;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ tegra = platform_get_drvdata(pdev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+ actmon_dev = &tegra->devices[i];
+
+ val = readl(actmon_dev->regs + ACTMON_DEV_CTRL);
+ val &= ~ACTMON_DEV_CTRL_ENB;
+ writel(val, actmon_dev->regs + ACTMON_DEV_CTRL);
+
+ writel(ACTMON_INTR_STATUS_CLEAR,
+ actmon_dev->regs + ACTMON_DEV_INTR_STATUS);
+
+ actmon_write_barrier(tegra);
+ }
+
+ return 0;
+}
+
+static int tegra_devfreq_resume(struct device *dev)
+{
+ struct platform_device *pdev;
+ struct tegra_devfreq *tegra;
+ struct tegra_devfreq_device *actmon_dev;
+ unsigned int i;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ tegra = platform_get_drvdata(pdev);
+
+ for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+ actmon_dev = &tegra->devices[i];
+
+ tegra_actmon_configure_device(tegra, actmon_dev);
+ }
+
+ return 0;
+}
+
+static int tegra_devfreq_target(struct device *dev, unsigned long *freq,
+ u32 flags)
+{
+ struct platform_device *pdev;
+ struct tegra_devfreq *tegra;
+ struct dev_pm_opp *opp;
+ unsigned long rate = *freq * KHZ;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ tegra = platform_get_drvdata(pdev);
+
+ rcu_read_lock();
+ opp = devfreq_recommended_opp(dev, &rate, flags);
+ if (IS_ERR(opp)) {
+ rcu_read_unlock();
+ dev_err(dev, "Failed to find opp for %lu KHz\n", *freq);
+ return PTR_ERR(opp);
+ }
+ rate = dev_pm_opp_get_freq(opp);
+ rcu_read_unlock();
+
+ /* TODO: Once we have per-user clk constraints, set a floor */
+ clk_set_rate(tegra->emc_clock, rate);
+
+ /* TODO: Set voltage as well */
+
+ return 0;
+}
+
+static int tegra_devfreq_get_dev_status(struct device *dev,
+ struct devfreq_dev_status *stat)
+{
+ struct platform_device *pdev;
+ struct tegra_devfreq *tegra;
+ struct tegra_devfreq_device *actmon_dev;
+
+ pdev = container_of(dev, struct platform_device, dev);
+ tegra = platform_get_drvdata(pdev);
+
+ stat->current_frequency = tegra->cur_freq;
+
+ /* To be used by the tegra governor */
+ stat->private_data = tegra;
+
+ /* The below are to be used by the other governors */
+
+ actmon_dev = &tegra->devices[MCALL];
+
+ /* Number of cycles spent on memory access */
+ stat->busy_time = actmon_dev->avg_count;
+
+ /* The bus can be considered to be saturated way before 100% */
+ stat->busy_time *= 100 / BUS_SATURATION_RATIO;
+
+ /* Number of cycles in a sampling period */
+ stat->total_time = ACTMON_SAMPLING_PERIOD * tegra->cur_freq;
+
+ return 0;
+}
+
+static int tegra_devfreq_get_target(struct devfreq *devfreq,
+ unsigned long *freq)
+{
+ struct devfreq_dev_status stat;
+ struct tegra_devfreq *tegra;
+ struct tegra_devfreq_device *dev;
+ unsigned long target_freq = 0;
+ unsigned int i;
+ int err;
+
+ err = devfreq->profile->get_dev_status(devfreq->dev.parent, &stat);
+ if (err)
+ return err;
+
+ tegra = stat.private_data;
+
+ for (i = 0; i < ARRAY_SIZE(tegra->devices); i++) {
+ dev = &tegra->devices[i];
+
+ actmon_update_target(tegra, dev);
+
+ target_freq = max(target_freq, dev->target_freq);
+ }
+
+ *freq = target_freq;
+
+ return 0;
+}
+
+static int tegra_devfreq_event_handler(struct devfreq *devfreq,
+ unsigned int event, void *data)
+{
+ return 0;
+}
+
+static struct devfreq_governor tegra_devfreq_governor = {
+ .name = "tegra",
+ .get_target_freq = tegra_devfreq_get_target,
+ .event_handler = tegra_devfreq_event_handler,
+};
+
+static struct devfreq_dev_profile tegra_devfreq_profile = {
+ .polling_ms = 0,
+ .target = tegra_devfreq_target,
+ .get_dev_status = tegra_devfreq_get_dev_status,
+};
+
+static int tegra_devfreq_probe(struct platform_device *pdev)
+{
+ struct tegra_devfreq *tegra;
+ struct tegra_devfreq_device *dev;
+ struct resource *res;
+ unsigned long max_freq;
+ unsigned int i;
+ int irq;
+ int err;
+
+ tegra = devm_kzalloc(&pdev->dev, sizeof(*tegra), GFP_KERNEL);
+ if (!tegra)
+ return -ENOMEM;
+
+ spin_lock_init(&tegra->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "Failed to get regs resource\n");
+ return -ENODEV;
+ }
+
+ tegra->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(tegra->regs)) {
+ dev_err(&pdev->dev, "Failed to get IO memory\n");
+ return PTR_ERR(tegra->regs);
+ }
+
+ tegra->reset = devm_reset_control_get(&pdev->dev, "actmon");
+ if (IS_ERR(tegra->reset)) {
+ dev_err(&pdev->dev, "Failed to get reset\n");
+ return PTR_ERR(tegra->reset);
+ }
+
+ tegra->clock = devm_clk_get(&pdev->dev, "actmon");
+ if (IS_ERR(tegra->clock)) {
+ dev_err(&pdev->dev, "Failed to get actmon clock\n");
+ return PTR_ERR(tegra->clock);
+ }
+
+ tegra->emc_clock = devm_clk_get(&pdev->dev, "emc");
+ if (IS_ERR(tegra->emc_clock)) {
+ dev_err(&pdev->dev, "Failed to get emc clock\n");
+ return PTR_ERR(tegra->emc_clock);
+ }
+
+ err = of_init_opp_table(&pdev->dev);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to init operating point table\n");
+ return err;
+ }
+
+ tegra->rate_change_nb.notifier_call = tegra_actmon_rate_notify_cb;
+ err = clk_notifier_register(tegra->emc_clock, &tegra->rate_change_nb);
+ if (err) {
+ dev_err(&pdev->dev,
+ "Failed to register rate change notifier\n");
+ return err;
+ }
+
+ reset_control_assert(tegra->reset);
+
+ err = clk_prepare_enable(tegra->clock);
+ if (err) {
+ reset_control_deassert(tegra->reset);
+ return err;
+ }
+
+ reset_control_deassert(tegra->reset);
+
+ max_freq = clk_round_rate(tegra->emc_clock, ULONG_MAX);
+ tegra->max_freq = max_freq / KHZ;
+
+ clk_set_rate(tegra->emc_clock, max_freq);
+
+ tegra->cur_freq = clk_get_rate(tegra->emc_clock) / KHZ;
+
+ writel(ACTMON_SAMPLING_PERIOD - 1,
+ tegra->regs + ACTMON_GLB_PERIOD_CTRL);
+
+ for (i = 0; i < ARRAY_SIZE(actmon_device_configs); i++) {
+ dev = tegra->devices + i;
+ dev->config = actmon_device_configs + i;
+ dev->regs = tegra->regs + dev->config->offset;
+
+ tegra_actmon_configure_device(tegra, tegra->devices + i);
+ }
+
+ err = devfreq_add_governor(&tegra_devfreq_governor);
+ if (err) {
+ dev_err(&pdev->dev, "Failed to add governor\n");
+ return err;
+ }
+
+ tegra_devfreq_profile.initial_freq = clk_get_rate(tegra->emc_clock);
+ tegra->devfreq = devm_devfreq_add_device(&pdev->dev,
+ &tegra_devfreq_profile,
+ "tegra",
+ NULL);
+
+ irq = platform_get_irq(pdev, 0);
+ err = devm_request_threaded_irq(&pdev->dev, irq, actmon_isr,
+ actmon_thread_isr, IRQF_SHARED,
+ "tegra-devfreq", tegra);
+ if (err) {
+ dev_err(&pdev->dev, "Interrupt request failed\n");
+ return err;
+ }
+
+ platform_set_drvdata(pdev, tegra);
+
+ return 0;
+}
+
+static int tegra_devfreq_remove(struct platform_device *pdev)
+{
+ struct tegra_devfreq *tegra = platform_get_drvdata(pdev);
+
+ clk_notifier_unregister(tegra->emc_clock, &tegra->rate_change_nb);
+
+ clk_disable_unprepare(tegra->clock);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(tegra_devfreq_pm_ops,
+ tegra_devfreq_suspend,
+ tegra_devfreq_resume);
+
+static struct of_device_id tegra_devfreq_of_match[] = {
+ { .compatible = "nvidia,tegra124-actmon" },
+ { },
+};
+
+static struct platform_driver tegra_devfreq_driver = {
+ .probe = tegra_devfreq_probe,
+ .remove = tegra_devfreq_remove,
+ .driver = {
+ .name = "tegra-devfreq",
+ .owner = THIS_MODULE,
+ .of_match_table = tegra_devfreq_of_match,
+ .pm = &tegra_devfreq_pm_ops,
+ },
+};
+module_platform_driver(tegra_devfreq_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Tegra devfreq driver");
+MODULE_AUTHOR("Tomeu Vizoso <tomeu.vizoso@collabora.com>");
+MODULE_DEVICE_TABLE(of, tegra_devfreq_of_match);
diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig
index f2b2c4e87aef..a874b6ec6650 100644
--- a/drivers/dma/Kconfig
+++ b/drivers/dma/Kconfig
@@ -184,7 +184,7 @@ config TEGRA20_APB_DMA
config S3C24XX_DMAC
tristate "Samsung S3C24XX DMA support"
- depends on ARCH_S3C24XX && !S3C24XX_DMA
+ depends on ARCH_S3C24XX
select DMA_ENGINE
select DMA_VIRTUAL_CHANNELS
help
@@ -416,6 +416,15 @@ config NBPFAXI_DMA
help
Support for "Type-AXI" NBPF DMA IPs from Renesas
+config IMG_MDC_DMA
+ tristate "IMG MDC support"
+ depends on MIPS || COMPILE_TEST
+ depends on MFD_SYSCON
+ select DMA_ENGINE
+ select DMA_VIRTUAL_CHANNELS
+ help
+ Enable support for the IMG multi-threaded DMA controller (MDC).
+
config DMA_ENGINE
bool
diff --git a/drivers/dma/Makefile b/drivers/dma/Makefile
index 2022b5451377..f915f61ec574 100644
--- a/drivers/dma/Makefile
+++ b/drivers/dma/Makefile
@@ -19,7 +19,7 @@ obj-$(CONFIG_AT_HDMAC) += at_hdmac.o
obj-$(CONFIG_AT_XDMAC) += at_xdmac.o
obj-$(CONFIG_MX3_IPU) += ipu/
obj-$(CONFIG_TXX9_DMAC) += txx9dmac.o
-obj-$(CONFIG_SH_DMAE_BASE) += sh/
+obj-$(CONFIG_RENESAS_DMA) += sh/
obj-$(CONFIG_COH901318) += coh901318.o coh901318_lli.o
obj-$(CONFIG_AMCC_PPC440SPE_ADMA) += ppc4xx/
obj-$(CONFIG_IMX_SDMA) += imx-sdma.o
@@ -50,3 +50,4 @@ obj-y += xilinx/
obj-$(CONFIG_INTEL_MIC_X100_DMA) += mic_x100_dma.o
obj-$(CONFIG_NBPFAXI_DMA) += nbpfaxi.o
obj-$(CONFIG_DMA_SUN6I) += sun6i-dma.o
+obj-$(CONFIG_IMG_MDC_DMA) += img-mdc-dma.o
diff --git a/drivers/dma/acpi-dma.c b/drivers/dma/acpi-dma.c
index de361a156b34..5a635646e05c 100644
--- a/drivers/dma/acpi-dma.c
+++ b/drivers/dma/acpi-dma.c
@@ -43,7 +43,7 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
{
const struct acpi_csrt_shared_info *si;
struct list_head resource_list;
- struct resource_list_entry *rentry;
+ struct resource_entry *rentry;
resource_size_t mem = 0, irq = 0;
int ret;
@@ -56,10 +56,10 @@ static int acpi_dma_parse_resource_group(const struct acpi_csrt_group *grp,
return 0;
list_for_each_entry(rentry, &resource_list, node) {
- if (resource_type(&rentry->res) == IORESOURCE_MEM)
- mem = rentry->res.start;
- else if (resource_type(&rentry->res) == IORESOURCE_IRQ)
- irq = rentry->res.start;
+ if (resource_type(rentry->res) == IORESOURCE_MEM)
+ mem = rentry->res->start;
+ else if (resource_type(rentry->res) == IORESOURCE_IRQ)
+ irq = rentry->res->start;
}
acpi_dev_free_resource_list(&resource_list);
diff --git a/drivers/dma/amba-pl08x.c b/drivers/dma/amba-pl08x.c
index 1364d00881dd..4a5fd245014e 100644
--- a/drivers/dma/amba-pl08x.c
+++ b/drivers/dma/amba-pl08x.c
@@ -1386,32 +1386,6 @@ static u32 pl08x_get_cctl(struct pl08x_dma_chan *plchan,
return pl08x_cctl(cctl);
}
-static int dma_set_runtime_config(struct dma_chan *chan,
- struct dma_slave_config *config)
-{
- struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
- struct pl08x_driver_data *pl08x = plchan->host;
-
- if (!plchan->slave)
- return -EINVAL;
-
- /* Reject definitely invalid configurations */
- if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
- config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
- return -EINVAL;
-
- if (config->device_fc && pl08x->vd->pl080s) {
- dev_err(&pl08x->adev->dev,
- "%s: PL080S does not support peripheral flow control\n",
- __func__);
- return -EINVAL;
- }
-
- plchan->cfg = *config;
-
- return 0;
-}
-
/*
* Slave transactions callback to the slave device to allow
* synchronization of slave DMA signals with the DMAC enable
@@ -1693,20 +1667,71 @@ static struct dma_async_tx_descriptor *pl08x_prep_dma_cyclic(
return vchan_tx_prep(&plchan->vc, &txd->vd, flags);
}
-static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int pl08x_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ struct pl08x_driver_data *pl08x = plchan->host;
+
+ if (!plchan->slave)
+ return -EINVAL;
+
+ /* Reject definitely invalid configurations */
+ if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
+ config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
+ return -EINVAL;
+
+ if (config->device_fc && pl08x->vd->pl080s) {
+ dev_err(&pl08x->adev->dev,
+ "%s: PL080S does not support peripheral flow control\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ plchan->cfg = *config;
+
+ return 0;
+}
+
+static int pl08x_terminate_all(struct dma_chan *chan)
{
struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
struct pl08x_driver_data *pl08x = plchan->host;
unsigned long flags;
- int ret = 0;
- /* Controls applicable to inactive channels */
- if (cmd == DMA_SLAVE_CONFIG) {
- return dma_set_runtime_config(chan,
- (struct dma_slave_config *)arg);
+ spin_lock_irqsave(&plchan->vc.lock, flags);
+ if (!plchan->phychan && !plchan->at) {
+ spin_unlock_irqrestore(&plchan->vc.lock, flags);
+ return 0;
}
+ plchan->state = PL08X_CHAN_IDLE;
+
+ if (plchan->phychan) {
+ /*
+ * Mark physical channel as free and free any slave
+ * signal
+ */
+ pl08x_phy_free(plchan);
+ }
+ /* Dequeue jobs and free LLIs */
+ if (plchan->at) {
+ pl08x_desc_free(&plchan->at->vd);
+ plchan->at = NULL;
+ }
+ /* Dequeue jobs not yet fired as well */
+ pl08x_free_txd_list(pl08x, plchan);
+
+ spin_unlock_irqrestore(&plchan->vc.lock, flags);
+
+ return 0;
+}
+
+static int pl08x_pause(struct dma_chan *chan)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ unsigned long flags;
+
/*
* Anything succeeds on channels with no physical allocation and
* no queued transfers.
@@ -1717,42 +1742,35 @@ static int pl08x_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
return 0;
}
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- plchan->state = PL08X_CHAN_IDLE;
+ pl08x_pause_phy_chan(plchan->phychan);
+ plchan->state = PL08X_CHAN_PAUSED;
- if (plchan->phychan) {
- /*
- * Mark physical channel as free and free any slave
- * signal
- */
- pl08x_phy_free(plchan);
- }
- /* Dequeue jobs and free LLIs */
- if (plchan->at) {
- pl08x_desc_free(&plchan->at->vd);
- plchan->at = NULL;
- }
- /* Dequeue jobs not yet fired as well */
- pl08x_free_txd_list(pl08x, plchan);
- break;
- case DMA_PAUSE:
- pl08x_pause_phy_chan(plchan->phychan);
- plchan->state = PL08X_CHAN_PAUSED;
- break;
- case DMA_RESUME:
- pl08x_resume_phy_chan(plchan->phychan);
- plchan->state = PL08X_CHAN_RUNNING;
- break;
- default:
- /* Unknown command */
- ret = -ENXIO;
- break;
+ spin_unlock_irqrestore(&plchan->vc.lock, flags);
+
+ return 0;
+}
+
+static int pl08x_resume(struct dma_chan *chan)
+{
+ struct pl08x_dma_chan *plchan = to_pl08x_chan(chan);
+ unsigned long flags;
+
+ /*
+ * Anything succeeds on channels with no physical allocation and
+ * no queued transfers.
+ */
+ spin_lock_irqsave(&plchan->vc.lock, flags);
+ if (!plchan->phychan && !plchan->at) {
+ spin_unlock_irqrestore(&plchan->vc.lock, flags);
+ return 0;
}
+ pl08x_resume_phy_chan(plchan->phychan);
+ plchan->state = PL08X_CHAN_RUNNING;
+
spin_unlock_irqrestore(&plchan->vc.lock, flags);
- return ret;
+ return 0;
}
bool pl08x_filter_id(struct dma_chan *chan, void *chan_id)
@@ -2048,7 +2066,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->memcpy.device_prep_dma_interrupt = pl08x_prep_dma_interrupt;
pl08x->memcpy.device_tx_status = pl08x_dma_tx_status;
pl08x->memcpy.device_issue_pending = pl08x_issue_pending;
- pl08x->memcpy.device_control = pl08x_control;
+ pl08x->memcpy.device_config = pl08x_config;
+ pl08x->memcpy.device_pause = pl08x_pause;
+ pl08x->memcpy.device_resume = pl08x_resume;
+ pl08x->memcpy.device_terminate_all = pl08x_terminate_all;
/* Initialize slave engine */
dma_cap_set(DMA_SLAVE, pl08x->slave.cap_mask);
@@ -2061,7 +2082,10 @@ static int pl08x_probe(struct amba_device *adev, const struct amba_id *id)
pl08x->slave.device_issue_pending = pl08x_issue_pending;
pl08x->slave.device_prep_slave_sg = pl08x_prep_slave_sg;
pl08x->slave.device_prep_dma_cyclic = pl08x_prep_dma_cyclic;
- pl08x->slave.device_control = pl08x_control;
+ pl08x->slave.device_config = pl08x_config;
+ pl08x->slave.device_pause = pl08x_pause;
+ pl08x->slave.device_resume = pl08x_resume;
+ pl08x->slave.device_terminate_all = pl08x_terminate_all;
/* Get the platform data */
pl08x->pd = dev_get_platdata(&adev->dev);
diff --git a/drivers/dma/at_hdmac.c b/drivers/dma/at_hdmac.c
index ca9dd2613283..1e1a4c567542 100644
--- a/drivers/dma/at_hdmac.c
+++ b/drivers/dma/at_hdmac.c
@@ -42,6 +42,11 @@
#define ATC_DEFAULT_CFG (ATC_FIFOCFG_HALFFIFO)
#define ATC_DEFAULT_CTRLB (ATC_SIF(AT_DMA_MEM_IF) \
|ATC_DIF(AT_DMA_MEM_IF))
+#define ATC_DMA_BUSWIDTHS\
+ (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
+ BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
/*
* Initial number of descriptors to allocate for each channel. This could
@@ -972,11 +977,13 @@ err_out:
return NULL;
}
-static int set_runtime_config(struct dma_chan *chan,
- struct dma_slave_config *sconfig)
+static int atc_config(struct dma_chan *chan,
+ struct dma_slave_config *sconfig)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);
+
/* Check if it is chan is configured for slave transfers */
if (!chan->private)
return -EINVAL;
@@ -989,9 +996,28 @@ static int set_runtime_config(struct dma_chan *chan,
return 0;
}
+static int atc_pause(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ int chan_id = atchan->chan_common.chan_id;
+ unsigned long flags;
-static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+ LIST_HEAD(list);
+
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);
+
+ spin_lock_irqsave(&atchan->lock, flags);
+
+ dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
+ set_bit(ATC_IS_PAUSED, &atchan->status);
+
+ spin_unlock_irqrestore(&atchan->lock, flags);
+
+ return 0;
+}
+
+static int atc_resume(struct dma_chan *chan)
{
struct at_dma_chan *atchan = to_at_dma_chan(chan);
struct at_dma *atdma = to_at_dma(chan->device);
@@ -1000,60 +1026,61 @@ static int atc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
LIST_HEAD(list);
- dev_vdbg(chan2dev(chan), "atc_control (%d)\n", cmd);
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);
- if (cmd == DMA_PAUSE) {
- spin_lock_irqsave(&atchan->lock, flags);
+ if (!atc_chan_is_paused(atchan))
+ return 0;
- dma_writel(atdma, CHER, AT_DMA_SUSP(chan_id));
- set_bit(ATC_IS_PAUSED, &atchan->status);
+ spin_lock_irqsave(&atchan->lock, flags);
- spin_unlock_irqrestore(&atchan->lock, flags);
- } else if (cmd == DMA_RESUME) {
- if (!atc_chan_is_paused(atchan))
- return 0;
+ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
+ clear_bit(ATC_IS_PAUSED, &atchan->status);
- spin_lock_irqsave(&atchan->lock, flags);
+ spin_unlock_irqrestore(&atchan->lock, flags);
- dma_writel(atdma, CHDR, AT_DMA_RES(chan_id));
- clear_bit(ATC_IS_PAUSED, &atchan->status);
+ return 0;
+}
- spin_unlock_irqrestore(&atchan->lock, flags);
- } else if (cmd == DMA_TERMINATE_ALL) {
- struct at_desc *desc, *_desc;
- /*
- * This is only called when something went wrong elsewhere, so
- * we don't really care about the data. Just disable the
- * channel. We still have to poll the channel enable bit due
- * to AHB/HSB limitations.
- */
- spin_lock_irqsave(&atchan->lock, flags);
+static int atc_terminate_all(struct dma_chan *chan)
+{
+ struct at_dma_chan *atchan = to_at_dma_chan(chan);
+ struct at_dma *atdma = to_at_dma(chan->device);
+ int chan_id = atchan->chan_common.chan_id;
+ struct at_desc *desc, *_desc;
+ unsigned long flags;
- /* disabling channel: must also remove suspend state */
- dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
+ LIST_HEAD(list);
- /* confirm that this channel is disabled */
- while (dma_readl(atdma, CHSR) & atchan->mask)
- cpu_relax();
+ dev_vdbg(chan2dev(chan), "%s\n", __func__);
- /* active_list entries will end up before queued entries */
- list_splice_init(&atchan->queue, &list);
- list_splice_init(&atchan->active_list, &list);
+ /*
+ * This is only called when something went wrong elsewhere, so
+ * we don't really care about the data. Just disable the
+ * channel. We still have to poll the channel enable bit due
+ * to AHB/HSB limitations.
+ */
+ spin_lock_irqsave(&atchan->lock, flags);
- /* Flush all pending and queued descriptors */
- list_for_each_entry_safe(desc, _desc, &list, desc_node)
- atc_chain_complete(atchan, desc);
+ /* disabling channel: must also remove suspend state */
+ dma_writel(atdma, CHDR, AT_DMA_RES(chan_id) | atchan->mask);
- clear_bit(ATC_IS_PAUSED, &atchan->status);
- /* if channel dedicated to cyclic operations, free it */
- clear_bit(ATC_IS_CYCLIC, &atchan->status);
+ /* confirm that this channel is disabled */
+ while (dma_readl(atdma, CHSR) & atchan->mask)
+ cpu_relax();
- spin_unlock_irqrestore(&atchan->lock, flags);
- } else if (cmd == DMA_SLAVE_CONFIG) {
- return set_runtime_config(chan, (struct dma_slave_config *)arg);
- } else {
- return -ENXIO;
- }
+ /* active_list entries will end up before queued entries */
+ list_splice_init(&atchan->queue, &list);
+ list_splice_init(&atchan->active_list, &list);
+
+ /* Flush all pending and queued descriptors */
+ list_for_each_entry_safe(desc, _desc, &list, desc_node)
+ atc_chain_complete(atchan, desc);
+
+ clear_bit(ATC_IS_PAUSED, &atchan->status);
+ /* if channel dedicated to cyclic operations, free it */
+ clear_bit(ATC_IS_CYCLIC, &atchan->status);
+
+ spin_unlock_irqrestore(&atchan->lock, flags);
return 0;
}
@@ -1505,7 +1532,14 @@ static int __init at_dma_probe(struct platform_device *pdev)
/* controller can do slave DMA: can trigger cyclic transfers */
dma_cap_set(DMA_CYCLIC, atdma->dma_common.cap_mask);
atdma->dma_common.device_prep_dma_cyclic = atc_prep_dma_cyclic;
- atdma->dma_common.device_control = atc_control;
+ atdma->dma_common.device_config = atc_config;
+ atdma->dma_common.device_pause = atc_pause;
+ atdma->dma_common.device_resume = atc_resume;
+ atdma->dma_common.device_terminate_all = atc_terminate_all;
+ atdma->dma_common.src_addr_widths = ATC_DMA_BUSWIDTHS;
+ atdma->dma_common.dst_addr_widths = ATC_DMA_BUSWIDTHS;
+ atdma->dma_common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ atdma->dma_common.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
}
dma_writel(atdma, EN, AT_DMA_ENABLE);
@@ -1622,7 +1656,7 @@ static void atc_suspend_cyclic(struct at_dma_chan *atchan)
if (!atc_chan_is_paused(atchan)) {
dev_warn(chan2dev(chan),
"cyclic channel not paused, should be done by channel user\n");
- atc_control(chan, DMA_PAUSE, 0);
+ atc_pause(chan);
}
/* now preserve additional data for cyclic operations */
diff --git a/drivers/dma/at_hdmac_regs.h b/drivers/dma/at_hdmac_regs.h
index 2787aba60c6b..d6bba6c636c2 100644
--- a/drivers/dma/at_hdmac_regs.h
+++ b/drivers/dma/at_hdmac_regs.h
@@ -232,7 +232,8 @@ enum atc_status {
* @save_dscr: for cyclic operations, preserve next descriptor address in
* the cyclic list on suspend/resume cycle
* @remain_desc: to save remain desc length
- * @dma_sconfig: configuration for slave transfers, passed via DMA_SLAVE_CONFIG
+ * @dma_sconfig: configuration for slave transfers, passed via
+ * .device_config
* @lock: serializes enqueue/dequeue operations to descriptors lists
* @active_list: list of descriptors dmaengine is being running on
* @queue: list of descriptors ready to be submitted to engine
diff --git a/drivers/dma/at_xdmac.c b/drivers/dma/at_xdmac.c
index b60d77a22df6..09e2825a547a 100644
--- a/drivers/dma/at_xdmac.c
+++ b/drivers/dma/at_xdmac.c
@@ -25,6 +25,7 @@
#include <linux/dmapool.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_dma.h>
@@ -174,6 +175,13 @@
#define AT_XDMAC_MAX_CHAN 0x20
+#define AT_XDMAC_DMA_BUSWIDTHS\
+ (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
+ BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |\
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
+
enum atc_status {
AT_XDMAC_CHAN_IS_CYCLIC = 0,
AT_XDMAC_CHAN_IS_PAUSED,
@@ -184,15 +192,15 @@ struct at_xdmac_chan {
struct dma_chan chan;
void __iomem *ch_regs;
u32 mask; /* Channel Mask */
- u32 cfg[3]; /* Channel Configuration Register */
- #define AT_XDMAC_CUR_CFG 0 /* Current channel conf */
- #define AT_XDMAC_DEV_TO_MEM_CFG 1 /* Predifined dev to mem channel conf */
- #define AT_XDMAC_MEM_TO_DEV_CFG 2 /* Predifined mem to dev channel conf */
+ u32 cfg[2]; /* Channel Configuration Register */
+ #define AT_XDMAC_DEV_TO_MEM_CFG 0 /* Predifined dev to mem channel conf */
+ #define AT_XDMAC_MEM_TO_DEV_CFG 1 /* Predifined mem to dev channel conf */
u8 perid; /* Peripheral ID */
u8 perif; /* Peripheral Interface */
u8 memif; /* Memory Interface */
u32 per_src_addr;
u32 per_dst_addr;
+ u32 save_cc;
u32 save_cim;
u32 save_cnda;
u32 save_cndc;
@@ -344,20 +352,13 @@ static void at_xdmac_start_xfer(struct at_xdmac_chan *atchan,
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, reg);
/*
- * When doing memory to memory transfer we need to use the next
+ * When doing non cyclic transfer we need to use the next
* descriptor view 2 since some fields of the configuration register
* depend on transfer size and src/dest addresses.
*/
- if (is_slave_direction(first->direction)) {
+ if (at_xdmac_chan_is_cyclic(atchan)) {
reg = AT_XDMAC_CNDC_NDVIEW_NDV1;
- if (first->direction == DMA_MEM_TO_DEV)
- atchan->cfg[AT_XDMAC_CUR_CFG] =
- atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
- else
- atchan->cfg[AT_XDMAC_CUR_CFG] =
- atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
- at_xdmac_chan_write(atchan, AT_XDMAC_CC,
- atchan->cfg[AT_XDMAC_CUR_CFG]);
+ at_xdmac_chan_write(atchan, AT_XDMAC_CC, first->lld.mbr_cfg);
} else {
/*
* No need to write AT_XDMAC_CC reg, it will be done when the
@@ -561,7 +562,6 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
struct at_xdmac_desc *first = NULL, *prev = NULL;
struct scatterlist *sg;
int i;
- u32 cfg;
unsigned int xfer_size = 0;
if (!sgl)
@@ -583,7 +583,7 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
/* Prepare descriptors. */
for_each_sg(sgl, sg, sg_len, i) {
struct at_xdmac_desc *desc = NULL;
- u32 len, mem;
+ u32 len, mem, dwidth, fixed_dwidth;
len = sg_dma_len(sg);
mem = sg_dma_address(sg);
@@ -608,17 +608,21 @@ at_xdmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
if (direction == DMA_DEV_TO_MEM) {
desc->lld.mbr_sa = atchan->per_src_addr;
desc->lld.mbr_da = mem;
- cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
+ desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_DEV_TO_MEM_CFG];
} else {
desc->lld.mbr_sa = mem;
desc->lld.mbr_da = atchan->per_dst_addr;
- cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
+ desc->lld.mbr_cfg = atchan->cfg[AT_XDMAC_MEM_TO_DEV_CFG];
}
- desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV1 /* next descriptor view */
- | AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */
- | AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */
- | (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */
- | len / (1 << at_xdmac_get_dwidth(cfg)); /* microblock length */
+ dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
+ fixed_dwidth = IS_ALIGNED(len, 1 << dwidth)
+ ? at_xdmac_get_dwidth(desc->lld.mbr_cfg)
+ : AT_XDMAC_CC_DWIDTH_BYTE;
+ desc->lld.mbr_ubc = AT_XDMAC_MBR_UBC_NDV2 /* next descriptor view */
+ | AT_XDMAC_MBR_UBC_NDEN /* next descriptor dst parameter update */
+ | AT_XDMAC_MBR_UBC_NSEN /* next descriptor src parameter update */
+ | (i == sg_len - 1 ? 0 : AT_XDMAC_MBR_UBC_NDE) /* descriptor fetch */
+ | (len >> fixed_dwidth); /* microblock length */
dev_dbg(chan2dev(chan),
"%s: lld: mbr_sa=%pad, mbr_da=%pad, mbr_ubc=0x%08x\n",
__func__, &desc->lld.mbr_sa, &desc->lld.mbr_da, desc->lld.mbr_ubc);
@@ -882,7 +886,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
enum dma_status ret;
int residue;
u32 cur_nda, mask, value;
- u8 dwidth = at_xdmac_get_dwidth(atchan->cfg[AT_XDMAC_CUR_CFG]);
+ u8 dwidth = 0;
ret = dma_cookie_status(chan, cookie, txstate);
if (ret == DMA_COMPLETE)
@@ -912,7 +916,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
*/
mask = AT_XDMAC_CC_TYPE | AT_XDMAC_CC_DSYNC;
value = AT_XDMAC_CC_TYPE_PER_TRAN | AT_XDMAC_CC_DSYNC_PER2MEM;
- if ((atchan->cfg[AT_XDMAC_CUR_CFG] & mask) == value) {
+ if ((desc->lld.mbr_cfg & mask) == value) {
at_xdmac_write(atxdmac, AT_XDMAC_GSWF, atchan->mask);
while (!(at_xdmac_chan_read(atchan, AT_XDMAC_CIS) & AT_XDMAC_CIS_FIS))
cpu_relax();
@@ -926,6 +930,7 @@ at_xdmac_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
*/
descs_list = &desc->descs_list;
list_for_each_entry_safe(desc, _desc, descs_list, desc_node) {
+ dwidth = at_xdmac_get_dwidth(desc->lld.mbr_cfg);
residue -= (desc->lld.mbr_ubc & 0xffffff) << dwidth;
if ((desc->lld.mbr_nda & 0xfffffffc) == cur_nda)
break;
@@ -1107,58 +1112,80 @@ static void at_xdmac_issue_pending(struct dma_chan *chan)
return;
}
-static int at_xdmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int at_xdmac_device_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
+ int ret;
+
+ dev_dbg(chan2dev(chan), "%s\n", __func__);
+
+ spin_lock_bh(&atchan->lock);
+ ret = at_xdmac_set_slave_config(chan, config);
+ spin_unlock_bh(&atchan->lock);
+
+ return ret;
+}
+
+static int at_xdmac_device_pause(struct dma_chan *chan)
{
- struct at_xdmac_desc *desc, *_desc;
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
- int ret = 0;
- dev_dbg(chan2dev(chan), "%s: cmd=%d\n", __func__, cmd);
+ dev_dbg(chan2dev(chan), "%s\n", __func__);
+
+ if (test_and_set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status))
+ return 0;
spin_lock_bh(&atchan->lock);
+ at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
+ while (at_xdmac_chan_read(atchan, AT_XDMAC_CC)
+ & (AT_XDMAC_CC_WRIP | AT_XDMAC_CC_RDIP))
+ cpu_relax();
+ spin_unlock_bh(&atchan->lock);
- switch (cmd) {
- case DMA_PAUSE:
- at_xdmac_write(atxdmac, AT_XDMAC_GRWS, atchan->mask);
- set_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
- break;
+ return 0;
+}
- case DMA_RESUME:
- if (!at_xdmac_chan_is_paused(atchan))
- break;
+static int at_xdmac_device_resume(struct dma_chan *chan)
+{
+ struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
- at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
- clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
- break;
+ dev_dbg(chan2dev(chan), "%s\n", __func__);
- case DMA_TERMINATE_ALL:
- at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
- while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
- cpu_relax();
+ spin_lock_bh(&atchan->lock);
+ if (!at_xdmac_chan_is_paused(atchan))
+ return 0;
+
+ at_xdmac_write(atxdmac, AT_XDMAC_GRWR, atchan->mask);
+ clear_bit(AT_XDMAC_CHAN_IS_PAUSED, &atchan->status);
+ spin_unlock_bh(&atchan->lock);
- /* Cancel all pending transfers. */
- list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
- at_xdmac_remove_xfer(atchan, desc);
+ return 0;
+}
+
+static int at_xdmac_device_terminate_all(struct dma_chan *chan)
+{
+ struct at_xdmac_desc *desc, *_desc;
+ struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
+ struct at_xdmac *atxdmac = to_at_xdmac(atchan->chan.device);
- clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
- break;
+ dev_dbg(chan2dev(chan), "%s\n", __func__);
- case DMA_SLAVE_CONFIG:
- ret = at_xdmac_set_slave_config(chan,
- (struct dma_slave_config *)arg);
- break;
+ spin_lock_bh(&atchan->lock);
+ at_xdmac_write(atxdmac, AT_XDMAC_GD, atchan->mask);
+ while (at_xdmac_read(atxdmac, AT_XDMAC_GS) & atchan->mask)
+ cpu_relax();
- default:
- dev_err(chan2dev(chan),
- "unmanaged or unknown dma control cmd: %d\n", cmd);
- ret = -ENXIO;
- }
+ /* Cancel all pending transfers. */
+ list_for_each_entry_safe(desc, _desc, &atchan->xfers_list, xfer_node)
+ at_xdmac_remove_xfer(atchan, desc);
+ clear_bit(AT_XDMAC_CHAN_IS_CYCLIC, &atchan->status);
spin_unlock_bh(&atchan->lock);
- return ret;
+ return 0;
}
static int at_xdmac_alloc_chan_resources(struct dma_chan *chan)
@@ -1217,27 +1244,6 @@ static void at_xdmac_free_chan_resources(struct dma_chan *chan)
return;
}
-#define AT_XDMAC_DMA_BUSWIDTHS\
- (BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) |\
- BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |\
- BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |\
- BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |\
- BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
-
-static int at_xdmac_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
-
- caps->src_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
- caps->dstn_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = true;
- caps->cmd_terminate = true;
- caps->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
-
- return 0;
-}
-
#ifdef CONFIG_PM
static int atmel_xdmac_prepare(struct device *dev)
{
@@ -1268,9 +1274,10 @@ static int atmel_xdmac_suspend(struct device *dev)
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
struct at_xdmac_chan *atchan = to_at_xdmac_chan(chan);
+ atchan->save_cc = at_xdmac_chan_read(atchan, AT_XDMAC_CC);
if (at_xdmac_chan_is_cyclic(atchan)) {
if (!at_xdmac_chan_is_paused(atchan))
- at_xdmac_control(chan, DMA_PAUSE, 0);
+ at_xdmac_device_pause(chan);
atchan->save_cim = at_xdmac_chan_read(atchan, AT_XDMAC_CIM);
atchan->save_cnda = at_xdmac_chan_read(atchan, AT_XDMAC_CNDA);
atchan->save_cndc = at_xdmac_chan_read(atchan, AT_XDMAC_CNDC);
@@ -1290,7 +1297,6 @@ static int atmel_xdmac_resume(struct device *dev)
struct at_xdmac_chan *atchan;
struct dma_chan *chan, *_chan;
int i;
- u32 cfg;
clk_prepare_enable(atxdmac->clk);
@@ -1305,8 +1311,7 @@ static int atmel_xdmac_resume(struct device *dev)
at_xdmac_write(atxdmac, AT_XDMAC_GE, atxdmac->save_gs);
list_for_each_entry_safe(chan, _chan, &atxdmac->dma.channels, device_node) {
atchan = to_at_xdmac_chan(chan);
- cfg = atchan->cfg[AT_XDMAC_CUR_CFG];
- at_xdmac_chan_write(atchan, AT_XDMAC_CC, cfg);
+ at_xdmac_chan_write(atchan, AT_XDMAC_CC, atchan->save_cc);
if (at_xdmac_chan_is_cyclic(atchan)) {
at_xdmac_chan_write(atchan, AT_XDMAC_CNDA, atchan->save_cnda);
at_xdmac_chan_write(atchan, AT_XDMAC_CNDC, atchan->save_cndc);
@@ -1407,8 +1412,14 @@ static int at_xdmac_probe(struct platform_device *pdev)
atxdmac->dma.device_prep_dma_cyclic = at_xdmac_prep_dma_cyclic;
atxdmac->dma.device_prep_dma_memcpy = at_xdmac_prep_dma_memcpy;
atxdmac->dma.device_prep_slave_sg = at_xdmac_prep_slave_sg;
- atxdmac->dma.device_control = at_xdmac_control;
- atxdmac->dma.device_slave_caps = at_xdmac_device_slave_caps;
+ atxdmac->dma.device_config = at_xdmac_device_config;
+ atxdmac->dma.device_pause = at_xdmac_device_pause;
+ atxdmac->dma.device_resume = at_xdmac_device_resume;
+ atxdmac->dma.device_terminate_all = at_xdmac_device_terminate_all;
+ atxdmac->dma.src_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
+ atxdmac->dma.dst_addr_widths = AT_XDMAC_DMA_BUSWIDTHS;
+ atxdmac->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ atxdmac->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
/* Disable all chans and interrupts. */
at_xdmac_off(atxdmac);
@@ -1507,7 +1518,6 @@ static struct platform_driver at_xdmac_driver = {
.remove = at_xdmac_remove,
.driver = {
.name = "at_xdmac",
- .owner = THIS_MODULE,
.of_match_table = of_match_ptr(atmel_xdmac_dt_ids),
.pm = &atmel_xdmac_dev_pm_ops,
}
diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c
index 918b7b3f766f..0723096fb50a 100644
--- a/drivers/dma/bcm2835-dma.c
+++ b/drivers/dma/bcm2835-dma.c
@@ -436,9 +436,11 @@ static struct dma_async_tx_descriptor *bcm2835_dma_prep_dma_cyclic(
return vchan_tx_prep(&c->vc, &d->vd, flags);
}
-static int bcm2835_dma_slave_config(struct bcm2835_chan *c,
- struct dma_slave_config *cfg)
+static int bcm2835_dma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
+
if ((cfg->direction == DMA_DEV_TO_MEM &&
cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
(cfg->direction == DMA_MEM_TO_DEV &&
@@ -452,8 +454,9 @@ static int bcm2835_dma_slave_config(struct bcm2835_chan *c,
return 0;
}
-static int bcm2835_dma_terminate_all(struct bcm2835_chan *c)
+static int bcm2835_dma_terminate_all(struct dma_chan *chan)
{
+ struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
struct bcm2835_dmadev *d = to_bcm2835_dma_dev(c->vc.chan.device);
unsigned long flags;
int timeout = 10000;
@@ -495,24 +498,6 @@ static int bcm2835_dma_terminate_all(struct bcm2835_chan *c)
return 0;
}
-static int bcm2835_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct bcm2835_chan *c = to_bcm2835_dma_chan(chan);
-
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- return bcm2835_dma_slave_config(c,
- (struct dma_slave_config *)arg);
-
- case DMA_TERMINATE_ALL:
- return bcm2835_dma_terminate_all(c);
-
- default:
- return -ENXIO;
- }
-}
-
static int bcm2835_dma_chan_init(struct bcm2835_dmadev *d, int chan_id, int irq)
{
struct bcm2835_chan *c;
@@ -565,18 +550,6 @@ static struct dma_chan *bcm2835_dma_xlate(struct of_phandle_args *spec,
return chan;
}
-static int bcm2835_dma_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
- caps->dstn_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = false;
- caps->cmd_terminate = true;
-
- return 0;
-}
-
static int bcm2835_dma_probe(struct platform_device *pdev)
{
struct bcm2835_dmadev *od;
@@ -615,9 +588,12 @@ static int bcm2835_dma_probe(struct platform_device *pdev)
od->ddev.device_free_chan_resources = bcm2835_dma_free_chan_resources;
od->ddev.device_tx_status = bcm2835_dma_tx_status;
od->ddev.device_issue_pending = bcm2835_dma_issue_pending;
- od->ddev.device_slave_caps = bcm2835_dma_device_slave_caps;
od->ddev.device_prep_dma_cyclic = bcm2835_dma_prep_dma_cyclic;
- od->ddev.device_control = bcm2835_dma_control;
+ od->ddev.device_config = bcm2835_dma_slave_config;
+ od->ddev.device_terminate_all = bcm2835_dma_terminate_all;
+ od->ddev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ od->ddev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
od->ddev.dev = &pdev->dev;
INIT_LIST_HEAD(&od->ddev.channels);
spin_lock_init(&od->lock);
diff --git a/drivers/dma/coh901318.c b/drivers/dma/coh901318.c
index e88588d8ecd3..fd22dd36985f 100644
--- a/drivers/dma/coh901318.c
+++ b/drivers/dma/coh901318.c
@@ -1690,7 +1690,7 @@ static u32 coh901318_get_bytes_left(struct dma_chan *chan)
* Pauses a transfer without losing data. Enables power save.
* Use this function in conjunction with coh901318_resume.
*/
-static void coh901318_pause(struct dma_chan *chan)
+static int coh901318_pause(struct dma_chan *chan)
{
u32 val;
unsigned long flags;
@@ -1730,12 +1730,13 @@ static void coh901318_pause(struct dma_chan *chan)
enable_powersave(cohc);
spin_unlock_irqrestore(&cohc->lock, flags);
+ return 0;
}
/* Resumes a transfer that has been stopped via 300_dma_stop(..).
Power save is handled.
*/
-static void coh901318_resume(struct dma_chan *chan)
+static int coh901318_resume(struct dma_chan *chan)
{
u32 val;
unsigned long flags;
@@ -1760,6 +1761,7 @@ static void coh901318_resume(struct dma_chan *chan)
}
spin_unlock_irqrestore(&cohc->lock, flags);
+ return 0;
}
bool coh901318_filter_id(struct dma_chan *chan, void *chan_id)
@@ -2114,6 +2116,57 @@ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int coh901318_terminate_all(struct dma_chan *chan)
+{
+ unsigned long flags;
+ struct coh901318_chan *cohc = to_coh901318_chan(chan);
+ struct coh901318_desc *cohd;
+ void __iomem *virtbase = cohc->base->virtbase;
+
+ /* The remainder of this function terminates the transfer */
+ coh901318_pause(chan);
+ spin_lock_irqsave(&cohc->lock, flags);
+
+ /* Clear any pending BE or TC interrupt */
+ if (cohc->id < 32) {
+ writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1);
+ writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1);
+ } else {
+ writel(1 << (cohc->id - 32), virtbase +
+ COH901318_BE_INT_CLEAR2);
+ writel(1 << (cohc->id - 32), virtbase +
+ COH901318_TC_INT_CLEAR2);
+ }
+
+ enable_powersave(cohc);
+
+ while ((cohd = coh901318_first_active_get(cohc))) {
+ /* release the lli allocation*/
+ coh901318_lli_free(&cohc->base->pool, &cohd->lli);
+
+ /* return desc to free-list */
+ coh901318_desc_remove(cohd);
+ coh901318_desc_free(cohc, cohd);
+ }
+
+ while ((cohd = coh901318_first_queued(cohc))) {
+ /* release the lli allocation*/
+ coh901318_lli_free(&cohc->base->pool, &cohd->lli);
+
+ /* return desc to free-list */
+ coh901318_desc_remove(cohd);
+ coh901318_desc_free(cohc, cohd);
+ }
+
+
+ cohc->nbr_active_done = 0;
+ cohc->busy = 0;
+
+ spin_unlock_irqrestore(&cohc->lock, flags);
+
+ return 0;
+}
+
static int coh901318_alloc_chan_resources(struct dma_chan *chan)
{
struct coh901318_chan *cohc = to_coh901318_chan(chan);
@@ -2156,7 +2209,7 @@ coh901318_free_chan_resources(struct dma_chan *chan)
spin_unlock_irqrestore(&cohc->lock, flags);
- dmaengine_terminate_all(chan);
+ coh901318_terminate_all(chan);
}
@@ -2461,8 +2514,8 @@ static const struct burst_table burst_sizes[] = {
},
};
-static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
- struct dma_slave_config *config)
+static int coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
+ struct dma_slave_config *config)
{
struct coh901318_chan *cohc = to_coh901318_chan(chan);
dma_addr_t addr;
@@ -2482,7 +2535,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
maxburst = config->dst_maxburst;
} else {
dev_err(COHC_2_DEV(cohc), "illegal channel mode\n");
- return;
+ return -EINVAL;
}
dev_dbg(COHC_2_DEV(cohc), "configure channel for %d byte transfers\n",
@@ -2528,7 +2581,7 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
default:
dev_err(COHC_2_DEV(cohc),
"bad runtimeconfig: alien address width\n");
- return;
+ return -EINVAL;
}
ctrl |= burst_sizes[i].reg;
@@ -2538,84 +2591,12 @@ static void coh901318_dma_set_runtimeconfig(struct dma_chan *chan,
cohc->addr = addr;
cohc->ctrl = ctrl;
-}
-
-static int
-coh901318_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- unsigned long flags;
- struct coh901318_chan *cohc = to_coh901318_chan(chan);
- struct coh901318_desc *cohd;
- void __iomem *virtbase = cohc->base->virtbase;
-
- if (cmd == DMA_SLAVE_CONFIG) {
- struct dma_slave_config *config =
- (struct dma_slave_config *) arg;
-
- coh901318_dma_set_runtimeconfig(chan, config);
- return 0;
- }
-
- if (cmd == DMA_PAUSE) {
- coh901318_pause(chan);
- return 0;
- }
-
- if (cmd == DMA_RESUME) {
- coh901318_resume(chan);
- return 0;
- }
-
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
-
- /* The remainder of this function terminates the transfer */
- coh901318_pause(chan);
- spin_lock_irqsave(&cohc->lock, flags);
-
- /* Clear any pending BE or TC interrupt */
- if (cohc->id < 32) {
- writel(1 << cohc->id, virtbase + COH901318_BE_INT_CLEAR1);
- writel(1 << cohc->id, virtbase + COH901318_TC_INT_CLEAR1);
- } else {
- writel(1 << (cohc->id - 32), virtbase +
- COH901318_BE_INT_CLEAR2);
- writel(1 << (cohc->id - 32), virtbase +
- COH901318_TC_INT_CLEAR2);
- }
-
- enable_powersave(cohc);
-
- while ((cohd = coh901318_first_active_get(cohc))) {
- /* release the lli allocation*/
- coh901318_lli_free(&cohc->base->pool, &cohd->lli);
-
- /* return desc to free-list */
- coh901318_desc_remove(cohd);
- coh901318_desc_free(cohc, cohd);
- }
-
- while ((cohd = coh901318_first_queued(cohc))) {
- /* release the lli allocation*/
- coh901318_lli_free(&cohc->base->pool, &cohd->lli);
-
- /* return desc to free-list */
- coh901318_desc_remove(cohd);
- coh901318_desc_free(cohc, cohd);
- }
-
-
- cohc->nbr_active_done = 0;
- cohc->busy = 0;
-
- spin_unlock_irqrestore(&cohc->lock, flags);
return 0;
}
-void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
- struct coh901318_base *base)
+static void coh901318_base_init(struct dma_device *dma, const int *pick_chans,
+ struct coh901318_base *base)
{
int chans_i;
int i = 0;
@@ -2717,7 +2698,10 @@ static int __init coh901318_probe(struct platform_device *pdev)
base->dma_slave.device_prep_slave_sg = coh901318_prep_slave_sg;
base->dma_slave.device_tx_status = coh901318_tx_status;
base->dma_slave.device_issue_pending = coh901318_issue_pending;
- base->dma_slave.device_control = coh901318_control;
+ base->dma_slave.device_config = coh901318_dma_set_runtimeconfig;
+ base->dma_slave.device_pause = coh901318_pause;
+ base->dma_slave.device_resume = coh901318_resume;
+ base->dma_slave.device_terminate_all = coh901318_terminate_all;
base->dma_slave.dev = &pdev->dev;
err = dma_async_device_register(&base->dma_slave);
@@ -2737,7 +2721,10 @@ static int __init coh901318_probe(struct platform_device *pdev)
base->dma_memcpy.device_prep_dma_memcpy = coh901318_prep_memcpy;
base->dma_memcpy.device_tx_status = coh901318_tx_status;
base->dma_memcpy.device_issue_pending = coh901318_issue_pending;
- base->dma_memcpy.device_control = coh901318_control;
+ base->dma_memcpy.device_config = coh901318_dma_set_runtimeconfig;
+ base->dma_memcpy.device_pause = coh901318_pause;
+ base->dma_memcpy.device_resume = coh901318_resume;
+ base->dma_memcpy.device_terminate_all = coh901318_terminate_all;
base->dma_memcpy.dev = &pdev->dev;
/*
* This controller can only access address at even 32bit boundaries,
diff --git a/drivers/dma/cppi41.c b/drivers/dma/cppi41.c
index b743adf56465..512cb8e2805e 100644
--- a/drivers/dma/cppi41.c
+++ b/drivers/dma/cppi41.c
@@ -525,12 +525,6 @@ static struct dma_async_tx_descriptor *cppi41_dma_prep_slave_sg(
return &c->txd;
}
-static int cpp41_cfg_chan(struct cppi41_channel *c,
- struct dma_slave_config *cfg)
-{
- return 0;
-}
-
static void cppi41_compute_td_desc(struct cppi41_desc *d)
{
d->pd0 = DESC_TYPE_TEARD << DESC_TYPE;
@@ -647,28 +641,6 @@ static int cppi41_stop_chan(struct dma_chan *chan)
return 0;
}
-static int cppi41_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct cppi41_channel *c = to_cpp41_chan(chan);
- int ret;
-
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- ret = cpp41_cfg_chan(c, (struct dma_slave_config *) arg);
- break;
-
- case DMA_TERMINATE_ALL:
- ret = cppi41_stop_chan(chan);
- break;
-
- default:
- ret = -ENXIO;
- break;
- }
- return ret;
-}
-
static void cleanup_chans(struct cppi41_dd *cdd)
{
while (!list_empty(&cdd->ddev.channels)) {
@@ -953,7 +925,7 @@ static int cppi41_dma_probe(struct platform_device *pdev)
cdd->ddev.device_tx_status = cppi41_dma_tx_status;
cdd->ddev.device_issue_pending = cppi41_dma_issue_pending;
cdd->ddev.device_prep_slave_sg = cppi41_dma_prep_slave_sg;
- cdd->ddev.device_control = cppi41_dma_control;
+ cdd->ddev.device_terminate_all = cppi41_stop_chan;
cdd->ddev.dev = dev;
INIT_LIST_HEAD(&cdd->ddev.channels);
cpp41_dma_info.dma_cap = cdd->ddev.cap_mask;
diff --git a/drivers/dma/dma-jz4740.c b/drivers/dma/dma-jz4740.c
index bdeafeefa5f6..4527a3ebeac4 100644
--- a/drivers/dma/dma-jz4740.c
+++ b/drivers/dma/dma-jz4740.c
@@ -210,7 +210,7 @@ static enum jz4740_dma_transfer_size jz4740_dma_maxburst(u32 maxburst)
}
static int jz4740_dma_slave_config(struct dma_chan *c,
- const struct dma_slave_config *config)
+ struct dma_slave_config *config)
{
struct jz4740_dmaengine_chan *chan = to_jz4740_dma_chan(c);
struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
@@ -290,21 +290,6 @@ static int jz4740_dma_terminate_all(struct dma_chan *c)
return 0;
}
-static int jz4740_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct dma_slave_config *config = (struct dma_slave_config *)arg;
-
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- return jz4740_dma_slave_config(chan, config);
- case DMA_TERMINATE_ALL:
- return jz4740_dma_terminate_all(chan);
- default:
- return -ENOSYS;
- }
-}
-
static int jz4740_dma_start_transfer(struct jz4740_dmaengine_chan *chan)
{
struct jz4740_dma_dev *dmadev = jz4740_dma_chan_get_dev(chan);
@@ -561,7 +546,8 @@ static int jz4740_dma_probe(struct platform_device *pdev)
dd->device_issue_pending = jz4740_dma_issue_pending;
dd->device_prep_slave_sg = jz4740_dma_prep_slave_sg;
dd->device_prep_dma_cyclic = jz4740_dma_prep_dma_cyclic;
- dd->device_control = jz4740_dma_control;
+ dd->device_config = jz4740_dma_slave_config;
+ dd->device_terminate_all = jz4740_dma_terminate_all;
dd->dev = &pdev->dev;
INIT_LIST_HEAD(&dd->channels);
diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c
index e057935e3023..f15712f2fec6 100644
--- a/drivers/dma/dmaengine.c
+++ b/drivers/dma/dmaengine.c
@@ -222,31 +222,35 @@ static void balance_ref_count(struct dma_chan *chan)
*/
static int dma_chan_get(struct dma_chan *chan)
{
- int err = -ENODEV;
struct module *owner = dma_chan_to_owner(chan);
+ int ret;
+ /* The channel is already in use, update client count */
if (chan->client_count) {
__module_get(owner);
- err = 0;
- } else if (try_module_get(owner))
- err = 0;
+ goto out;
+ }
- if (err == 0)
- chan->client_count++;
+ if (!try_module_get(owner))
+ return -ENODEV;
/* allocate upon first client reference */
- if (chan->client_count == 1 && err == 0) {
- int desc_cnt = chan->device->device_alloc_chan_resources(chan);
-
- if (desc_cnt < 0) {
- err = desc_cnt;
- chan->client_count = 0;
- module_put(owner);
- } else if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask))
- balance_ref_count(chan);
+ if (chan->device->device_alloc_chan_resources) {
+ ret = chan->device->device_alloc_chan_resources(chan);
+ if (ret < 0)
+ goto err_out;
}
- return err;
+ if (!dma_has_cap(DMA_PRIVATE, chan->device->cap_mask))
+ balance_ref_count(chan);
+
+out:
+ chan->client_count++;
+ return 0;
+
+err_out:
+ module_put(owner);
+ return ret;
}
/**
@@ -257,11 +261,15 @@ static int dma_chan_get(struct dma_chan *chan)
*/
static void dma_chan_put(struct dma_chan *chan)
{
+ /* This channel is not in use, bail out */
if (!chan->client_count)
- return; /* this channel failed alloc_chan_resources */
+ return;
+
chan->client_count--;
module_put(dma_chan_to_owner(chan));
- if (chan->client_count == 0)
+
+ /* This channel is not in use anymore, free it */
+ if (!chan->client_count && chan->device->device_free_chan_resources)
chan->device->device_free_chan_resources(chan);
}
@@ -471,6 +479,39 @@ static void dma_channel_rebalance(void)
}
}
+int dma_get_slave_caps(struct dma_chan *chan, struct dma_slave_caps *caps)
+{
+ struct dma_device *device;
+
+ if (!chan || !caps)
+ return -EINVAL;
+
+ device = chan->device;
+
+ /* check if the channel supports slave transactions */
+ if (!test_bit(DMA_SLAVE, device->cap_mask.bits))
+ return -ENXIO;
+
+ /*
+ * Check whether it reports it uses the generic slave
+ * capabilities, if not, that means it doesn't support any
+ * kind of slave capabilities reporting.
+ */
+ if (!device->directions)
+ return -ENXIO;
+
+ caps->src_addr_widths = device->src_addr_widths;
+ caps->dst_addr_widths = device->dst_addr_widths;
+ caps->directions = device->directions;
+ caps->residue_granularity = device->residue_granularity;
+
+ caps->cmd_pause = !!device->device_pause;
+ caps->cmd_terminate = !!device->device_terminate_all;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dma_get_slave_caps);
+
static struct dma_chan *private_candidate(const dma_cap_mask_t *mask,
struct dma_device *dev,
dma_filter_fn fn, void *fn_param)
@@ -811,17 +852,16 @@ int dma_async_device_register(struct dma_device *device)
!device->device_prep_dma_sg);
BUG_ON(dma_has_cap(DMA_CYCLIC, device->cap_mask) &&
!device->device_prep_dma_cyclic);
- BUG_ON(dma_has_cap(DMA_SLAVE, device->cap_mask) &&
- !device->device_control);
BUG_ON(dma_has_cap(DMA_INTERLEAVE, device->cap_mask) &&
!device->device_prep_interleaved_dma);
- BUG_ON(!device->device_alloc_chan_resources);
- BUG_ON(!device->device_free_chan_resources);
BUG_ON(!device->device_tx_status);
BUG_ON(!device->device_issue_pending);
BUG_ON(!device->dev);
+ WARN(dma_has_cap(DMA_SLAVE, device->cap_mask) && !device->directions,
+ "this driver doesn't support generic slave capabilities reporting\n");
+
/* note: this only matters in the
* CONFIG_ASYNC_TX_ENABLE_CHANNEL_SWITCH=n case
*/
diff --git a/drivers/dma/dmatest.c b/drivers/dma/dmatest.c
index a8d7809e2f4c..220ee49633e4 100644
--- a/drivers/dma/dmatest.c
+++ b/drivers/dma/dmatest.c
@@ -349,14 +349,14 @@ static void dbg_result(const char *err, unsigned int n, unsigned int src_off,
unsigned long data)
{
pr_debug("%s: result #%u: '%s' with src_off=0x%x dst_off=0x%x len=0x%x (%lu)\n",
- current->comm, n, err, src_off, dst_off, len, data);
+ current->comm, n, err, src_off, dst_off, len, data);
}
-#define verbose_result(err, n, src_off, dst_off, len, data) ({ \
- if (verbose) \
- result(err, n, src_off, dst_off, len, data); \
- else \
- dbg_result(err, n, src_off, dst_off, len, data); \
+#define verbose_result(err, n, src_off, dst_off, len, data) ({ \
+ if (verbose) \
+ result(err, n, src_off, dst_off, len, data); \
+ else \
+ dbg_result(err, n, src_off, dst_off, len, data);\
})
static unsigned long long dmatest_persec(s64 runtime, unsigned int val)
@@ -405,7 +405,6 @@ static int dmatest_func(void *data)
struct dmatest_params *params;
struct dma_chan *chan;
struct dma_device *dev;
- unsigned int src_off, dst_off, len;
unsigned int error_count;
unsigned int failed_tests = 0;
unsigned int total_tests = 0;
@@ -484,6 +483,7 @@ static int dmatest_func(void *data)
struct dmaengine_unmap_data *um;
dma_addr_t srcs[src_cnt];
dma_addr_t *dsts;
+ unsigned int src_off, dst_off, len;
u8 align = 0;
total_tests++;
@@ -502,15 +502,21 @@ static int dmatest_func(void *data)
break;
}
- if (params->noverify) {
+ if (params->noverify)
len = params->buf_size;
+ else
+ len = dmatest_random() % params->buf_size + 1;
+
+ len = (len >> align) << align;
+ if (!len)
+ len = 1 << align;
+
+ total_len += len;
+
+ if (params->noverify) {
src_off = 0;
dst_off = 0;
} else {
- len = dmatest_random() % params->buf_size + 1;
- len = (len >> align) << align;
- if (!len)
- len = 1 << align;
src_off = dmatest_random() % (params->buf_size - len + 1);
dst_off = dmatest_random() % (params->buf_size - len + 1);
@@ -523,11 +529,6 @@ static int dmatest_func(void *data)
params->buf_size);
}
- len = (len >> align) << align;
- if (!len)
- len = 1 << align;
- total_len += len;
-
um = dmaengine_get_unmap_data(dev->dev, src_cnt+dst_cnt,
GFP_KERNEL);
if (!um) {
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 5c062548957c..455b7a4f1e87 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -61,6 +61,13 @@
*/
#define NR_DESCS_PER_CHANNEL 64
+/* The set of bus widths supported by the DMA controller */
+#define DW_DMA_BUSWIDTHS \
+ BIT(DMA_SLAVE_BUSWIDTH_UNDEFINED) | \
+ BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES)
+
/*----------------------------------------------------------------------*/
static struct device *chan2dev(struct dma_chan *chan)
@@ -955,8 +962,7 @@ static inline void convert_burst(u32 *maxburst)
*maxburst = 0;
}
-static int
-set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
+static int dwc_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
@@ -973,16 +979,25 @@ set_runtime_config(struct dma_chan *chan, struct dma_slave_config *sconfig)
return 0;
}
-static inline void dwc_chan_pause(struct dw_dma_chan *dwc)
+static int dwc_pause(struct dma_chan *chan)
{
- u32 cfglo = channel_readl(dwc, CFG_LO);
- unsigned int count = 20; /* timeout iterations */
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ unsigned long flags;
+ unsigned int count = 20; /* timeout iterations */
+ u32 cfglo;
+
+ spin_lock_irqsave(&dwc->lock, flags);
+ cfglo = channel_readl(dwc, CFG_LO);
channel_writel(dwc, CFG_LO, cfglo | DWC_CFGL_CH_SUSP);
while (!(channel_readl(dwc, CFG_LO) & DWC_CFGL_FIFO_EMPTY) && count--)
udelay(2);
dwc->paused = true;
+
+ spin_unlock_irqrestore(&dwc->lock, flags);
+
+ return 0;
}
static inline void dwc_chan_resume(struct dw_dma_chan *dwc)
@@ -994,53 +1009,48 @@ static inline void dwc_chan_resume(struct dw_dma_chan *dwc)
dwc->paused = false;
}
-static int dwc_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int dwc_resume(struct dma_chan *chan)
{
struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
- struct dw_dma *dw = to_dw_dma(chan->device);
- struct dw_desc *desc, *_desc;
unsigned long flags;
- LIST_HEAD(list);
- if (cmd == DMA_PAUSE) {
- spin_lock_irqsave(&dwc->lock, flags);
+ if (!dwc->paused)
+ return 0;
- dwc_chan_pause(dwc);
+ spin_lock_irqsave(&dwc->lock, flags);
- spin_unlock_irqrestore(&dwc->lock, flags);
- } else if (cmd == DMA_RESUME) {
- if (!dwc->paused)
- return 0;
+ dwc_chan_resume(dwc);
- spin_lock_irqsave(&dwc->lock, flags);
+ spin_unlock_irqrestore(&dwc->lock, flags);
- dwc_chan_resume(dwc);
+ return 0;
+}
- spin_unlock_irqrestore(&dwc->lock, flags);
- } else if (cmd == DMA_TERMINATE_ALL) {
- spin_lock_irqsave(&dwc->lock, flags);
+static int dwc_terminate_all(struct dma_chan *chan)
+{
+ struct dw_dma_chan *dwc = to_dw_dma_chan(chan);
+ struct dw_dma *dw = to_dw_dma(chan->device);
+ struct dw_desc *desc, *_desc;
+ unsigned long flags;
+ LIST_HEAD(list);
- clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+ spin_lock_irqsave(&dwc->lock, flags);
- dwc_chan_disable(dw, dwc);
+ clear_bit(DW_DMA_IS_SOFT_LLP, &dwc->flags);
+
+ dwc_chan_disable(dw, dwc);
- dwc_chan_resume(dwc);
+ dwc_chan_resume(dwc);
- /* active_list entries will end up before queued entries */
- list_splice_init(&dwc->queue, &list);
- list_splice_init(&dwc->active_list, &list);
+ /* active_list entries will end up before queued entries */
+ list_splice_init(&dwc->queue, &list);
+ list_splice_init(&dwc->active_list, &list);
- spin_unlock_irqrestore(&dwc->lock, flags);
+ spin_unlock_irqrestore(&dwc->lock, flags);
- /* Flush all pending and queued descriptors */
- list_for_each_entry_safe(desc, _desc, &list, desc_node)
- dwc_descriptor_complete(dwc, desc, false);
- } else if (cmd == DMA_SLAVE_CONFIG) {
- return set_runtime_config(chan, (struct dma_slave_config *)arg);
- } else {
- return -ENXIO;
- }
+ /* Flush all pending and queued descriptors */
+ list_for_each_entry_safe(desc, _desc, &list, desc_node)
+ dwc_descriptor_complete(dwc, desc, false);
return 0;
}
@@ -1551,7 +1561,8 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
}
} else {
dw->nr_masters = pdata->nr_masters;
- memcpy(dw->data_width, pdata->data_width, 4);
+ for (i = 0; i < dw->nr_masters; i++)
+ dw->data_width[i] = pdata->data_width[i];
}
/* Calculate all channel mask before DMA setup */
@@ -1656,13 +1667,23 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
dw->dma.device_free_chan_resources = dwc_free_chan_resources;
dw->dma.device_prep_dma_memcpy = dwc_prep_dma_memcpy;
-
dw->dma.device_prep_slave_sg = dwc_prep_slave_sg;
- dw->dma.device_control = dwc_control;
+
+ dw->dma.device_config = dwc_config;
+ dw->dma.device_pause = dwc_pause;
+ dw->dma.device_resume = dwc_resume;
+ dw->dma.device_terminate_all = dwc_terminate_all;
dw->dma.device_tx_status = dwc_tx_status;
dw->dma.device_issue_pending = dwc_issue_pending;
+ /* DMA capabilities */
+ dw->dma.src_addr_widths = DW_DMA_BUSWIDTHS;
+ dw->dma.dst_addr_widths = DW_DMA_BUSWIDTHS;
+ dw->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV) |
+ BIT(DMA_MEM_TO_MEM);
+ dw->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
err = dma_async_device_register(&dw->dma);
if (err)
goto err_dma_register;
diff --git a/drivers/dma/dw/platform.c b/drivers/dma/dw/platform.c
index 32ea1aca7a0e..6565a361e7e5 100644
--- a/drivers/dma/dw/platform.c
+++ b/drivers/dma/dw/platform.c
@@ -100,7 +100,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
struct dw_dma_platform_data *pdata;
- u32 tmp, arr[4];
+ u32 tmp, arr[DW_DMA_MAX_NR_MASTERS];
if (!np) {
dev_err(&pdev->dev, "Missing DT data\n");
@@ -127,7 +127,7 @@ dw_dma_parse_dt(struct platform_device *pdev)
pdata->block_size = tmp;
if (!of_property_read_u32(np, "dma-masters", &tmp)) {
- if (tmp > 4)
+ if (tmp > DW_DMA_MAX_NR_MASTERS)
return NULL;
pdata->nr_masters = tmp;
diff --git a/drivers/dma/dw/regs.h b/drivers/dma/dw/regs.h
index 848e232f7cc7..241ff2b1402b 100644
--- a/drivers/dma/dw/regs.h
+++ b/drivers/dma/dw/regs.h
@@ -252,7 +252,7 @@ struct dw_dma_chan {
u8 src_master;
u8 dst_master;
- /* configuration passed via DMA_SLAVE_CONFIG */
+ /* configuration passed via .device_config */
struct dma_slave_config dma_sconfig;
};
@@ -285,7 +285,7 @@ struct dw_dma {
/* hardware configuration */
unsigned char nr_masters;
- unsigned char data_width[4];
+ unsigned char data_width[DW_DMA_MAX_NR_MASTERS];
};
static inline struct dw_dma_regs __iomem *__dw_regs(struct dw_dma *dw)
diff --git a/drivers/dma/edma.c b/drivers/dma/edma.c
index b969206439b7..276157f22612 100644
--- a/drivers/dma/edma.c
+++ b/drivers/dma/edma.c
@@ -15,6 +15,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-mapping.h>
+#include <linux/edma.h>
#include <linux/err.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -244,8 +245,9 @@ static void edma_execute(struct edma_chan *echan)
}
}
-static int edma_terminate_all(struct edma_chan *echan)
+static int edma_terminate_all(struct dma_chan *chan)
{
+ struct edma_chan *echan = to_edma_chan(chan);
unsigned long flags;
LIST_HEAD(head);
@@ -273,9 +275,11 @@ static int edma_terminate_all(struct edma_chan *echan)
return 0;
}
-static int edma_slave_config(struct edma_chan *echan,
+static int edma_slave_config(struct dma_chan *chan,
struct dma_slave_config *cfg)
{
+ struct edma_chan *echan = to_edma_chan(chan);
+
if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
return -EINVAL;
@@ -285,8 +289,10 @@ static int edma_slave_config(struct edma_chan *echan,
return 0;
}
-static int edma_dma_pause(struct edma_chan *echan)
+static int edma_dma_pause(struct dma_chan *chan)
{
+ struct edma_chan *echan = to_edma_chan(chan);
+
/* Pause/Resume only allowed with cyclic mode */
if (!echan->edesc || !echan->edesc->cyclic)
return -EINVAL;
@@ -295,8 +301,10 @@ static int edma_dma_pause(struct edma_chan *echan)
return 0;
}
-static int edma_dma_resume(struct edma_chan *echan)
+static int edma_dma_resume(struct dma_chan *chan)
{
+ struct edma_chan *echan = to_edma_chan(chan);
+
/* Pause/Resume only allowed with cyclic mode */
if (!echan->edesc->cyclic)
return -EINVAL;
@@ -305,36 +313,6 @@ static int edma_dma_resume(struct edma_chan *echan)
return 0;
}
-static int edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- int ret = 0;
- struct dma_slave_config *config;
- struct edma_chan *echan = to_edma_chan(chan);
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- edma_terminate_all(echan);
- break;
- case DMA_SLAVE_CONFIG:
- config = (struct dma_slave_config *)arg;
- ret = edma_slave_config(echan, config);
- break;
- case DMA_PAUSE:
- ret = edma_dma_pause(echan);
- break;
-
- case DMA_RESUME:
- ret = edma_dma_resume(echan);
- break;
-
- default:
- ret = -ENOSYS;
- }
-
- return ret;
-}
-
/*
* A PaRAM set configuration abstraction used by other modes
* @chan: Channel who's PaRAM set we're configuring
@@ -557,7 +535,7 @@ static struct dma_async_tx_descriptor *edma_prep_slave_sg(
return vchan_tx_prep(&echan->vchan, &edesc->vdesc, tx_flags);
}
-struct dma_async_tx_descriptor *edma_prep_dma_memcpy(
+static struct dma_async_tx_descriptor *edma_prep_dma_memcpy(
struct dma_chan *chan, dma_addr_t dest, dma_addr_t src,
size_t len, unsigned long tx_flags)
{
@@ -994,19 +972,6 @@ static void __init edma_chan_init(struct edma_cc *ecc,
BIT(DMA_SLAVE_BUSWIDTH_3_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
-static int edma_dma_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = EDMA_DMA_BUSWIDTHS;
- caps->dstn_addr_widths = EDMA_DMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = true;
- caps->cmd_terminate = true;
- caps->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
-
- return 0;
-}
-
static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
struct device *dev)
{
@@ -1017,8 +982,16 @@ static void edma_dma_init(struct edma_cc *ecc, struct dma_device *dma,
dma->device_free_chan_resources = edma_free_chan_resources;
dma->device_issue_pending = edma_issue_pending;
dma->device_tx_status = edma_tx_status;
- dma->device_control = edma_control;
- dma->device_slave_caps = edma_dma_device_slave_caps;
+ dma->device_config = edma_slave_config;
+ dma->device_pause = edma_dma_pause;
+ dma->device_resume = edma_dma_resume;
+ dma->device_terminate_all = edma_terminate_all;
+
+ dma->src_addr_widths = EDMA_DMA_BUSWIDTHS;
+ dma->dst_addr_widths = EDMA_DMA_BUSWIDTHS;
+ dma->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ dma->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
dma->dev = dev;
/*
diff --git a/drivers/dma/ep93xx_dma.c b/drivers/dma/ep93xx_dma.c
index 7650470196c4..24e5290faa32 100644
--- a/drivers/dma/ep93xx_dma.c
+++ b/drivers/dma/ep93xx_dma.c
@@ -144,7 +144,7 @@ struct ep93xx_dma_desc {
* @queue: pending descriptors which are handled next
* @free_list: list of free descriptors which can be used
* @runtime_addr: physical address currently used as dest/src (M2M only). This
- * is set via %DMA_SLAVE_CONFIG before slave operation is
+ * is set via .device_config before slave operation is
* prepared
* @runtime_ctrl: M2M runtime values for the control register.
*
@@ -1164,13 +1164,14 @@ fail:
/**
* ep93xx_dma_terminate_all - terminate all transactions
- * @edmac: channel
+ * @chan: channel
*
* Stops all DMA transactions. All descriptors are put back to the
* @edmac->free_list and callbacks are _not_ called.
*/
-static int ep93xx_dma_terminate_all(struct ep93xx_dma_chan *edmac)
+static int ep93xx_dma_terminate_all(struct dma_chan *chan)
{
+ struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
struct ep93xx_dma_desc *desc, *_d;
unsigned long flags;
LIST_HEAD(list);
@@ -1194,9 +1195,10 @@ static int ep93xx_dma_terminate_all(struct ep93xx_dma_chan *edmac)
return 0;
}
-static int ep93xx_dma_slave_config(struct ep93xx_dma_chan *edmac,
+static int ep93xx_dma_slave_config(struct dma_chan *chan,
struct dma_slave_config *config)
{
+ struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
enum dma_slave_buswidth width;
unsigned long flags;
u32 addr, ctrl;
@@ -1242,36 +1244,6 @@ static int ep93xx_dma_slave_config(struct ep93xx_dma_chan *edmac,
}
/**
- * ep93xx_dma_control - manipulate all pending operations on a channel
- * @chan: channel
- * @cmd: control command to perform
- * @arg: optional argument
- *
- * Controls the channel. Function returns %0 in case of success or negative
- * error in case of failure.
- */
-static int ep93xx_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct ep93xx_dma_chan *edmac = to_ep93xx_dma_chan(chan);
- struct dma_slave_config *config;
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- return ep93xx_dma_terminate_all(edmac);
-
- case DMA_SLAVE_CONFIG:
- config = (struct dma_slave_config *)arg;
- return ep93xx_dma_slave_config(edmac, config);
-
- default:
- break;
- }
-
- return -ENOSYS;
-}
-
-/**
* ep93xx_dma_tx_status - check if a transaction is completed
* @chan: channel
* @cookie: transaction specific cookie
@@ -1352,7 +1324,8 @@ static int __init ep93xx_dma_probe(struct platform_device *pdev)
dma_dev->device_free_chan_resources = ep93xx_dma_free_chan_resources;
dma_dev->device_prep_slave_sg = ep93xx_dma_prep_slave_sg;
dma_dev->device_prep_dma_cyclic = ep93xx_dma_prep_dma_cyclic;
- dma_dev->device_control = ep93xx_dma_control;
+ dma_dev->device_config = ep93xx_dma_slave_config;
+ dma_dev->device_terminate_all = ep93xx_dma_terminate_all;
dma_dev->device_issue_pending = ep93xx_dma_issue_pending;
dma_dev->device_tx_status = ep93xx_dma_tx_status;
diff --git a/drivers/dma/fsl-edma.c b/drivers/dma/fsl-edma.c
index e9ebb89e1711..09e2842d15ec 100644
--- a/drivers/dma/fsl-edma.c
+++ b/drivers/dma/fsl-edma.c
@@ -289,62 +289,69 @@ static void fsl_edma_free_desc(struct virt_dma_desc *vdesc)
kfree(fsl_desc);
}
-static int fsl_edma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int fsl_edma_terminate_all(struct dma_chan *chan)
{
struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
- struct dma_slave_config *cfg = (void *)arg;
unsigned long flags;
LIST_HEAD(head);
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ fsl_edma_disable_request(fsl_chan);
+ fsl_chan->edesc = NULL;
+ vchan_get_all_descriptors(&fsl_chan->vchan, &head);
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
+ return 0;
+}
+
+static int fsl_edma_pause(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (fsl_chan->edesc) {
fsl_edma_disable_request(fsl_chan);
- fsl_chan->edesc = NULL;
- vchan_get_all_descriptors(&fsl_chan->vchan, &head);
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- vchan_dma_desc_free_list(&fsl_chan->vchan, &head);
- return 0;
-
- case DMA_SLAVE_CONFIG:
- fsl_chan->fsc.dir = cfg->direction;
- if (cfg->direction == DMA_DEV_TO_MEM) {
- fsl_chan->fsc.dev_addr = cfg->src_addr;
- fsl_chan->fsc.addr_width = cfg->src_addr_width;
- fsl_chan->fsc.burst = cfg->src_maxburst;
- fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
- } else if (cfg->direction == DMA_MEM_TO_DEV) {
- fsl_chan->fsc.dev_addr = cfg->dst_addr;
- fsl_chan->fsc.addr_width = cfg->dst_addr_width;
- fsl_chan->fsc.burst = cfg->dst_maxburst;
- fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
- } else {
- return -EINVAL;
- }
- return 0;
+ fsl_chan->status = DMA_PAUSED;
+ }
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return 0;
+}
- case DMA_PAUSE:
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- if (fsl_chan->edesc) {
- fsl_edma_disable_request(fsl_chan);
- fsl_chan->status = DMA_PAUSED;
- }
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- return 0;
-
- case DMA_RESUME:
- spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
- if (fsl_chan->edesc) {
- fsl_edma_enable_request(fsl_chan);
- fsl_chan->status = DMA_IN_PROGRESS;
- }
- spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
- return 0;
+static int fsl_edma_resume(struct dma_chan *chan)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+ unsigned long flags;
- default:
- return -ENXIO;
+ spin_lock_irqsave(&fsl_chan->vchan.lock, flags);
+ if (fsl_chan->edesc) {
+ fsl_edma_enable_request(fsl_chan);
+ fsl_chan->status = DMA_IN_PROGRESS;
+ }
+ spin_unlock_irqrestore(&fsl_chan->vchan.lock, flags);
+ return 0;
+}
+
+static int fsl_edma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
+{
+ struct fsl_edma_chan *fsl_chan = to_fsl_edma_chan(chan);
+
+ fsl_chan->fsc.dir = cfg->direction;
+ if (cfg->direction == DMA_DEV_TO_MEM) {
+ fsl_chan->fsc.dev_addr = cfg->src_addr;
+ fsl_chan->fsc.addr_width = cfg->src_addr_width;
+ fsl_chan->fsc.burst = cfg->src_maxburst;
+ fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->src_addr_width);
+ } else if (cfg->direction == DMA_MEM_TO_DEV) {
+ fsl_chan->fsc.dev_addr = cfg->dst_addr;
+ fsl_chan->fsc.addr_width = cfg->dst_addr_width;
+ fsl_chan->fsc.burst = cfg->dst_maxburst;
+ fsl_chan->fsc.attr = fsl_edma_get_tcd_attr(cfg->dst_addr_width);
+ } else {
+ return -EINVAL;
}
+ return 0;
}
static size_t fsl_edma_desc_residue(struct fsl_edma_chan *fsl_chan,
@@ -780,18 +787,6 @@ static void fsl_edma_free_chan_resources(struct dma_chan *chan)
fsl_chan->tcd_pool = NULL;
}
-static int fsl_dma_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = FSL_EDMA_BUSWIDTHS;
- caps->dstn_addr_widths = FSL_EDMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = true;
- caps->cmd_terminate = true;
-
- return 0;
-}
-
static int
fsl_edma_irq_init(struct platform_device *pdev, struct fsl_edma_engine *fsl_edma)
{
@@ -917,9 +912,15 @@ static int fsl_edma_probe(struct platform_device *pdev)
fsl_edma->dma_dev.device_tx_status = fsl_edma_tx_status;
fsl_edma->dma_dev.device_prep_slave_sg = fsl_edma_prep_slave_sg;
fsl_edma->dma_dev.device_prep_dma_cyclic = fsl_edma_prep_dma_cyclic;
- fsl_edma->dma_dev.device_control = fsl_edma_control;
+ fsl_edma->dma_dev.device_config = fsl_edma_slave_config;
+ fsl_edma->dma_dev.device_pause = fsl_edma_pause;
+ fsl_edma->dma_dev.device_resume = fsl_edma_resume;
+ fsl_edma->dma_dev.device_terminate_all = fsl_edma_terminate_all;
fsl_edma->dma_dev.device_issue_pending = fsl_edma_issue_pending;
- fsl_edma->dma_dev.device_slave_caps = fsl_dma_device_slave_caps;
+
+ fsl_edma->dma_dev.src_addr_widths = FSL_EDMA_BUSWIDTHS;
+ fsl_edma->dma_dev.dst_addr_widths = FSL_EDMA_BUSWIDTHS;
+ fsl_edma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
platform_set_drvdata(pdev, fsl_edma);
diff --git a/drivers/dma/fsldma.c b/drivers/dma/fsldma.c
index 38821cdf862b..300f821f1890 100644
--- a/drivers/dma/fsldma.c
+++ b/drivers/dma/fsldma.c
@@ -941,84 +941,56 @@ fail:
return NULL;
}
-/**
- * fsl_dma_prep_slave_sg - prepare descriptors for a DMA_SLAVE transaction
- * @chan: DMA channel
- * @sgl: scatterlist to transfer to/from
- * @sg_len: number of entries in @scatterlist
- * @direction: DMA direction
- * @flags: DMAEngine flags
- * @context: transaction context (ignored)
- *
- * Prepare a set of descriptors for a DMA_SLAVE transaction. Following the
- * DMA_SLAVE API, this gets the device-specific information from the
- * chan->private variable.
- */
-static struct dma_async_tx_descriptor *fsl_dma_prep_slave_sg(
- struct dma_chan *dchan, struct scatterlist *sgl, unsigned int sg_len,
- enum dma_transfer_direction direction, unsigned long flags,
- void *context)
+static int fsl_dma_device_terminate_all(struct dma_chan *dchan)
{
- /*
- * This operation is not supported on the Freescale DMA controller
- *
- * However, we need to provide the function pointer to allow the
- * device_control() method to work.
- */
- return NULL;
-}
-
-static int fsl_dma_device_control(struct dma_chan *dchan,
- enum dma_ctrl_cmd cmd, unsigned long arg)
-{
- struct dma_slave_config *config;
struct fsldma_chan *chan;
- int size;
if (!dchan)
return -EINVAL;
chan = to_fsl_chan(dchan);
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- spin_lock_bh(&chan->desc_lock);
-
- /* Halt the DMA engine */
- dma_halt(chan);
+ spin_lock_bh(&chan->desc_lock);
- /* Remove and free all of the descriptors in the LD queue */
- fsldma_free_desc_list(chan, &chan->ld_pending);
- fsldma_free_desc_list(chan, &chan->ld_running);
- fsldma_free_desc_list(chan, &chan->ld_completed);
- chan->idle = true;
+ /* Halt the DMA engine */
+ dma_halt(chan);
- spin_unlock_bh(&chan->desc_lock);
- return 0;
+ /* Remove and free all of the descriptors in the LD queue */
+ fsldma_free_desc_list(chan, &chan->ld_pending);
+ fsldma_free_desc_list(chan, &chan->ld_running);
+ fsldma_free_desc_list(chan, &chan->ld_completed);
+ chan->idle = true;
- case DMA_SLAVE_CONFIG:
- config = (struct dma_slave_config *)arg;
+ spin_unlock_bh(&chan->desc_lock);
+ return 0;
+}
- /* make sure the channel supports setting burst size */
- if (!chan->set_request_count)
- return -ENXIO;
+static int fsl_dma_device_config(struct dma_chan *dchan,
+ struct dma_slave_config *config)
+{
+ struct fsldma_chan *chan;
+ int size;
- /* we set the controller burst size depending on direction */
- if (config->direction == DMA_MEM_TO_DEV)
- size = config->dst_addr_width * config->dst_maxburst;
- else
- size = config->src_addr_width * config->src_maxburst;
+ if (!dchan)
+ return -EINVAL;
- chan->set_request_count(chan, size);
- return 0;
+ chan = to_fsl_chan(dchan);
- default:
+ /* make sure the channel supports setting burst size */
+ if (!chan->set_request_count)
return -ENXIO;
- }
+ /* we set the controller burst size depending on direction */
+ if (config->direction == DMA_MEM_TO_DEV)
+ size = config->dst_addr_width * config->dst_maxburst;
+ else
+ size = config->src_addr_width * config->src_maxburst;
+
+ chan->set_request_count(chan, size);
return 0;
}
+
/**
* fsl_dma_memcpy_issue_pending - Issue the DMA start command
* @chan : Freescale DMA channel
@@ -1395,10 +1367,15 @@ static int fsldma_of_probe(struct platform_device *op)
fdev->common.device_prep_dma_sg = fsl_dma_prep_sg;
fdev->common.device_tx_status = fsl_tx_status;
fdev->common.device_issue_pending = fsl_dma_memcpy_issue_pending;
- fdev->common.device_prep_slave_sg = fsl_dma_prep_slave_sg;
- fdev->common.device_control = fsl_dma_device_control;
+ fdev->common.device_config = fsl_dma_device_config;
+ fdev->common.device_terminate_all = fsl_dma_device_terminate_all;
fdev->common.dev = &op->dev;
+ fdev->common.src_addr_widths = FSL_DMA_BUSWIDTHS;
+ fdev->common.dst_addr_widths = FSL_DMA_BUSWIDTHS;
+ fdev->common.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ fdev->common.residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+
dma_set_mask(&(op->dev), DMA_BIT_MASK(36));
platform_set_drvdata(op, fdev);
diff --git a/drivers/dma/fsldma.h b/drivers/dma/fsldma.h
index 239c20c84382..31bffccdcc75 100644
--- a/drivers/dma/fsldma.h
+++ b/drivers/dma/fsldma.h
@@ -83,6 +83,10 @@
#define FSL_DMA_DGSR_EOSI 0x02
#define FSL_DMA_DGSR_EOLSI 0x01
+#define FSL_DMA_BUSWIDTHS (BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) | \
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
typedef u64 __bitwise v64;
typedef u32 __bitwise v32;
diff --git a/drivers/dma/img-mdc-dma.c b/drivers/dma/img-mdc-dma.c
new file mode 100644
index 000000000000..ed045a9ad634
--- /dev/null
+++ b/drivers/dma/img-mdc-dma.c
@@ -0,0 +1,1011 @@
+/*
+ * IMG Multi-threaded DMA Controller (MDC)
+ *
+ * Copyright (C) 2009,2012,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/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/dmapool.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_dma.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "dmaengine.h"
+#include "virt-dma.h"
+
+#define MDC_MAX_DMA_CHANNELS 32
+
+#define MDC_GENERAL_CONFIG 0x000
+#define MDC_GENERAL_CONFIG_LIST_IEN BIT(31)
+#define MDC_GENERAL_CONFIG_IEN BIT(29)
+#define MDC_GENERAL_CONFIG_LEVEL_INT BIT(28)
+#define MDC_GENERAL_CONFIG_INC_W BIT(12)
+#define MDC_GENERAL_CONFIG_INC_R BIT(8)
+#define MDC_GENERAL_CONFIG_PHYSICAL_W BIT(7)
+#define MDC_GENERAL_CONFIG_WIDTH_W_SHIFT 4
+#define MDC_GENERAL_CONFIG_WIDTH_W_MASK 0x7
+#define MDC_GENERAL_CONFIG_PHYSICAL_R BIT(3)
+#define MDC_GENERAL_CONFIG_WIDTH_R_SHIFT 0
+#define MDC_GENERAL_CONFIG_WIDTH_R_MASK 0x7
+
+#define MDC_READ_PORT_CONFIG 0x004
+#define MDC_READ_PORT_CONFIG_STHREAD_SHIFT 28
+#define MDC_READ_PORT_CONFIG_STHREAD_MASK 0xf
+#define MDC_READ_PORT_CONFIG_RTHREAD_SHIFT 24
+#define MDC_READ_PORT_CONFIG_RTHREAD_MASK 0xf
+#define MDC_READ_PORT_CONFIG_WTHREAD_SHIFT 16
+#define MDC_READ_PORT_CONFIG_WTHREAD_MASK 0xf
+#define MDC_READ_PORT_CONFIG_BURST_SIZE_SHIFT 4
+#define MDC_READ_PORT_CONFIG_BURST_SIZE_MASK 0xff
+#define MDC_READ_PORT_CONFIG_DREQ_ENABLE BIT(1)
+
+#define MDC_READ_ADDRESS 0x008
+
+#define MDC_WRITE_ADDRESS 0x00c
+
+#define MDC_TRANSFER_SIZE 0x010
+#define MDC_TRANSFER_SIZE_MASK 0xffffff
+
+#define MDC_LIST_NODE_ADDRESS 0x014
+
+#define MDC_CMDS_PROCESSED 0x018
+#define MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT 16
+#define MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK 0x3f
+#define MDC_CMDS_PROCESSED_INT_ACTIVE BIT(8)
+#define MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT 0
+#define MDC_CMDS_PROCESSED_CMDS_DONE_MASK 0x3f
+
+#define MDC_CONTROL_AND_STATUS 0x01c
+#define MDC_CONTROL_AND_STATUS_CANCEL BIT(20)
+#define MDC_CONTROL_AND_STATUS_LIST_EN BIT(4)
+#define MDC_CONTROL_AND_STATUS_EN BIT(0)
+
+#define MDC_ACTIVE_TRANSFER_SIZE 0x030
+
+#define MDC_GLOBAL_CONFIG_A 0x900
+#define MDC_GLOBAL_CONFIG_A_THREAD_ID_WIDTH_SHIFT 16
+#define MDC_GLOBAL_CONFIG_A_THREAD_ID_WIDTH_MASK 0xff
+#define MDC_GLOBAL_CONFIG_A_DMA_CONTEXTS_SHIFT 8
+#define MDC_GLOBAL_CONFIG_A_DMA_CONTEXTS_MASK 0xff
+#define MDC_GLOBAL_CONFIG_A_SYS_DAT_WIDTH_SHIFT 0
+#define MDC_GLOBAL_CONFIG_A_SYS_DAT_WIDTH_MASK 0xff
+
+struct mdc_hw_list_desc {
+ u32 gen_conf;
+ u32 readport_conf;
+ u32 read_addr;
+ u32 write_addr;
+ u32 xfer_size;
+ u32 node_addr;
+ u32 cmds_done;
+ u32 ctrl_status;
+ /*
+ * Not part of the list descriptor, but instead used by the CPU to
+ * traverse the list.
+ */
+ struct mdc_hw_list_desc *next_desc;
+};
+
+struct mdc_tx_desc {
+ struct mdc_chan *chan;
+ struct virt_dma_desc vd;
+ dma_addr_t list_phys;
+ struct mdc_hw_list_desc *list;
+ bool cyclic;
+ bool cmd_loaded;
+ unsigned int list_len;
+ unsigned int list_period_len;
+ size_t list_xfer_size;
+ unsigned int list_cmds_done;
+};
+
+struct mdc_chan {
+ struct mdc_dma *mdma;
+ struct virt_dma_chan vc;
+ struct dma_slave_config config;
+ struct mdc_tx_desc *desc;
+ int irq;
+ unsigned int periph;
+ unsigned int thread;
+ unsigned int chan_nr;
+};
+
+struct mdc_dma_soc_data {
+ void (*enable_chan)(struct mdc_chan *mchan);
+ void (*disable_chan)(struct mdc_chan *mchan);
+};
+
+struct mdc_dma {
+ struct dma_device dma_dev;
+ void __iomem *regs;
+ struct clk *clk;
+ struct dma_pool *desc_pool;
+ struct regmap *periph_regs;
+ spinlock_t lock;
+ unsigned int nr_threads;
+ unsigned int nr_channels;
+ unsigned int bus_width;
+ unsigned int max_burst_mult;
+ unsigned int max_xfer_size;
+ const struct mdc_dma_soc_data *soc;
+ struct mdc_chan channels[MDC_MAX_DMA_CHANNELS];
+};
+
+static inline u32 mdc_readl(struct mdc_dma *mdma, u32 reg)
+{
+ return readl(mdma->regs + reg);
+}
+
+static inline void mdc_writel(struct mdc_dma *mdma, u32 val, u32 reg)
+{
+ writel(val, mdma->regs + reg);
+}
+
+static inline u32 mdc_chan_readl(struct mdc_chan *mchan, u32 reg)
+{
+ return mdc_readl(mchan->mdma, mchan->chan_nr * 0x040 + reg);
+}
+
+static inline void mdc_chan_writel(struct mdc_chan *mchan, u32 val, u32 reg)
+{
+ mdc_writel(mchan->mdma, val, mchan->chan_nr * 0x040 + reg);
+}
+
+static inline struct mdc_chan *to_mdc_chan(struct dma_chan *c)
+{
+ return container_of(to_virt_chan(c), struct mdc_chan, vc);
+}
+
+static inline struct mdc_tx_desc *to_mdc_desc(struct dma_async_tx_descriptor *t)
+{
+ struct virt_dma_desc *vdesc = container_of(t, struct virt_dma_desc, tx);
+
+ return container_of(vdesc, struct mdc_tx_desc, vd);
+}
+
+static inline struct device *mdma2dev(struct mdc_dma *mdma)
+{
+ return mdma->dma_dev.dev;
+}
+
+static inline unsigned int to_mdc_width(unsigned int bytes)
+{
+ return ffs(bytes) - 1;
+}
+
+static inline void mdc_set_read_width(struct mdc_hw_list_desc *ldesc,
+ unsigned int bytes)
+{
+ ldesc->gen_conf |= to_mdc_width(bytes) <<
+ MDC_GENERAL_CONFIG_WIDTH_R_SHIFT;
+}
+
+static inline void mdc_set_write_width(struct mdc_hw_list_desc *ldesc,
+ unsigned int bytes)
+{
+ ldesc->gen_conf |= to_mdc_width(bytes) <<
+ MDC_GENERAL_CONFIG_WIDTH_W_SHIFT;
+}
+
+static void mdc_list_desc_config(struct mdc_chan *mchan,
+ struct mdc_hw_list_desc *ldesc,
+ enum dma_transfer_direction dir,
+ dma_addr_t src, dma_addr_t dst, size_t len)
+{
+ struct mdc_dma *mdma = mchan->mdma;
+ unsigned int max_burst, burst_size;
+
+ ldesc->gen_conf = MDC_GENERAL_CONFIG_IEN | MDC_GENERAL_CONFIG_LIST_IEN |
+ MDC_GENERAL_CONFIG_LEVEL_INT | MDC_GENERAL_CONFIG_PHYSICAL_W |
+ MDC_GENERAL_CONFIG_PHYSICAL_R;
+ ldesc->readport_conf =
+ (mchan->thread << MDC_READ_PORT_CONFIG_STHREAD_SHIFT) |
+ (mchan->thread << MDC_READ_PORT_CONFIG_RTHREAD_SHIFT) |
+ (mchan->thread << MDC_READ_PORT_CONFIG_WTHREAD_SHIFT);
+ ldesc->read_addr = src;
+ ldesc->write_addr = dst;
+ ldesc->xfer_size = len - 1;
+ ldesc->node_addr = 0;
+ ldesc->cmds_done = 0;
+ ldesc->ctrl_status = MDC_CONTROL_AND_STATUS_LIST_EN |
+ MDC_CONTROL_AND_STATUS_EN;
+ ldesc->next_desc = NULL;
+
+ if (IS_ALIGNED(dst, mdma->bus_width) &&
+ IS_ALIGNED(src, mdma->bus_width))
+ max_burst = mdma->bus_width * mdma->max_burst_mult;
+ else
+ max_burst = mdma->bus_width * (mdma->max_burst_mult - 1);
+
+ if (dir == DMA_MEM_TO_DEV) {
+ ldesc->gen_conf |= MDC_GENERAL_CONFIG_INC_R;
+ ldesc->readport_conf |= MDC_READ_PORT_CONFIG_DREQ_ENABLE;
+ mdc_set_read_width(ldesc, mdma->bus_width);
+ mdc_set_write_width(ldesc, mchan->config.dst_addr_width);
+ burst_size = min(max_burst, mchan->config.dst_maxburst *
+ mchan->config.dst_addr_width);
+ } else if (dir == DMA_DEV_TO_MEM) {
+ ldesc->gen_conf |= MDC_GENERAL_CONFIG_INC_W;
+ ldesc->readport_conf |= MDC_READ_PORT_CONFIG_DREQ_ENABLE;
+ mdc_set_read_width(ldesc, mchan->config.src_addr_width);
+ mdc_set_write_width(ldesc, mdma->bus_width);
+ burst_size = min(max_burst, mchan->config.src_maxburst *
+ mchan->config.src_addr_width);
+ } else {
+ ldesc->gen_conf |= MDC_GENERAL_CONFIG_INC_R |
+ MDC_GENERAL_CONFIG_INC_W;
+ mdc_set_read_width(ldesc, mdma->bus_width);
+ mdc_set_write_width(ldesc, mdma->bus_width);
+ burst_size = max_burst;
+ }
+ ldesc->readport_conf |= (burst_size - 1) <<
+ MDC_READ_PORT_CONFIG_BURST_SIZE_SHIFT;
+}
+
+static void mdc_list_desc_free(struct mdc_tx_desc *mdesc)
+{
+ struct mdc_dma *mdma = mdesc->chan->mdma;
+ struct mdc_hw_list_desc *curr, *next;
+ dma_addr_t curr_phys, next_phys;
+
+ curr = mdesc->list;
+ curr_phys = mdesc->list_phys;
+ while (curr) {
+ next = curr->next_desc;
+ next_phys = curr->node_addr;
+ dma_pool_free(mdma->desc_pool, curr, curr_phys);
+ curr = next;
+ curr_phys = next_phys;
+ }
+}
+
+static void mdc_desc_free(struct virt_dma_desc *vd)
+{
+ struct mdc_tx_desc *mdesc = to_mdc_desc(&vd->tx);
+
+ mdc_list_desc_free(mdesc);
+ kfree(mdesc);
+}
+
+static struct dma_async_tx_descriptor *mdc_prep_dma_memcpy(
+ struct dma_chan *chan, dma_addr_t dest, dma_addr_t src, size_t len,
+ unsigned long flags)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ struct mdc_dma *mdma = mchan->mdma;
+ struct mdc_tx_desc *mdesc;
+ struct mdc_hw_list_desc *curr, *prev = NULL;
+ dma_addr_t curr_phys, prev_phys;
+
+ if (!len)
+ return NULL;
+
+ mdesc = kzalloc(sizeof(*mdesc), GFP_NOWAIT);
+ if (!mdesc)
+ return NULL;
+ mdesc->chan = mchan;
+ mdesc->list_xfer_size = len;
+
+ while (len > 0) {
+ size_t xfer_size;
+
+ curr = dma_pool_alloc(mdma->desc_pool, GFP_NOWAIT, &curr_phys);
+ if (!curr)
+ goto free_desc;
+
+ if (prev) {
+ prev->node_addr = curr_phys;
+ prev->next_desc = curr;
+ } else {
+ mdesc->list_phys = curr_phys;
+ mdesc->list = curr;
+ }
+
+ xfer_size = min_t(size_t, mdma->max_xfer_size, len);
+
+ mdc_list_desc_config(mchan, curr, DMA_MEM_TO_MEM, src, dest,
+ xfer_size);
+
+ prev = curr;
+ prev_phys = curr_phys;
+
+ mdesc->list_len++;
+ src += xfer_size;
+ dest += xfer_size;
+ len -= xfer_size;
+ }
+
+ return vchan_tx_prep(&mchan->vc, &mdesc->vd, flags);
+
+free_desc:
+ mdc_desc_free(&mdesc->vd);
+
+ return NULL;
+}
+
+static int mdc_check_slave_width(struct mdc_chan *mchan,
+ enum dma_transfer_direction dir)
+{
+ enum dma_slave_buswidth width;
+
+ if (dir == DMA_MEM_TO_DEV)
+ width = mchan->config.dst_addr_width;
+ else
+ width = mchan->config.src_addr_width;
+
+ switch (width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ case DMA_SLAVE_BUSWIDTH_8_BYTES:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (width > mchan->mdma->bus_width)
+ return -EINVAL;
+
+ return 0;
+}
+
+static struct dma_async_tx_descriptor *mdc_prep_dma_cyclic(
+ struct dma_chan *chan, dma_addr_t buf_addr, size_t buf_len,
+ size_t period_len, enum dma_transfer_direction dir,
+ unsigned long flags)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ struct mdc_dma *mdma = mchan->mdma;
+ struct mdc_tx_desc *mdesc;
+ struct mdc_hw_list_desc *curr, *prev = NULL;
+ dma_addr_t curr_phys, prev_phys;
+
+ if (!buf_len && !period_len)
+ return NULL;
+
+ if (!is_slave_direction(dir))
+ return NULL;
+
+ if (mdc_check_slave_width(mchan, dir) < 0)
+ return NULL;
+
+ mdesc = kzalloc(sizeof(*mdesc), GFP_NOWAIT);
+ if (!mdesc)
+ return NULL;
+ mdesc->chan = mchan;
+ mdesc->cyclic = true;
+ mdesc->list_xfer_size = buf_len;
+ mdesc->list_period_len = DIV_ROUND_UP(period_len,
+ mdma->max_xfer_size);
+
+ while (buf_len > 0) {
+ size_t remainder = min(period_len, buf_len);
+
+ while (remainder > 0) {
+ size_t xfer_size;
+
+ curr = dma_pool_alloc(mdma->desc_pool, GFP_NOWAIT,
+ &curr_phys);
+ if (!curr)
+ goto free_desc;
+
+ if (!prev) {
+ mdesc->list_phys = curr_phys;
+ mdesc->list = curr;
+ } else {
+ prev->node_addr = curr_phys;
+ prev->next_desc = curr;
+ }
+
+ xfer_size = min_t(size_t, mdma->max_xfer_size,
+ remainder);
+
+ if (dir == DMA_MEM_TO_DEV) {
+ mdc_list_desc_config(mchan, curr, dir,
+ buf_addr,
+ mchan->config.dst_addr,
+ xfer_size);
+ } else {
+ mdc_list_desc_config(mchan, curr, dir,
+ mchan->config.src_addr,
+ buf_addr,
+ xfer_size);
+ }
+
+ prev = curr;
+ prev_phys = curr_phys;
+
+ mdesc->list_len++;
+ buf_addr += xfer_size;
+ buf_len -= xfer_size;
+ remainder -= xfer_size;
+ }
+ }
+ prev->node_addr = mdesc->list_phys;
+
+ return vchan_tx_prep(&mchan->vc, &mdesc->vd, flags);
+
+free_desc:
+ mdc_desc_free(&mdesc->vd);
+
+ return NULL;
+}
+
+static struct dma_async_tx_descriptor *mdc_prep_slave_sg(
+ struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ struct mdc_dma *mdma = mchan->mdma;
+ struct mdc_tx_desc *mdesc;
+ struct scatterlist *sg;
+ struct mdc_hw_list_desc *curr, *prev = NULL;
+ dma_addr_t curr_phys, prev_phys;
+ unsigned int i;
+
+ if (!sgl)
+ return NULL;
+
+ if (!is_slave_direction(dir))
+ return NULL;
+
+ if (mdc_check_slave_width(mchan, dir) < 0)
+ return NULL;
+
+ mdesc = kzalloc(sizeof(*mdesc), GFP_NOWAIT);
+ if (!mdesc)
+ return NULL;
+ mdesc->chan = mchan;
+
+ for_each_sg(sgl, sg, sg_len, i) {
+ dma_addr_t buf = sg_dma_address(sg);
+ size_t buf_len = sg_dma_len(sg);
+
+ while (buf_len > 0) {
+ size_t xfer_size;
+
+ curr = dma_pool_alloc(mdma->desc_pool, GFP_NOWAIT,
+ &curr_phys);
+ if (!curr)
+ goto free_desc;
+
+ if (!prev) {
+ mdesc->list_phys = curr_phys;
+ mdesc->list = curr;
+ } else {
+ prev->node_addr = curr_phys;
+ prev->next_desc = curr;
+ }
+
+ xfer_size = min_t(size_t, mdma->max_xfer_size,
+ buf_len);
+
+ if (dir == DMA_MEM_TO_DEV) {
+ mdc_list_desc_config(mchan, curr, dir, buf,
+ mchan->config.dst_addr,
+ xfer_size);
+ } else {
+ mdc_list_desc_config(mchan, curr, dir,
+ mchan->config.src_addr,
+ buf, xfer_size);
+ }
+
+ prev = curr;
+ prev_phys = curr_phys;
+
+ mdesc->list_len++;
+ mdesc->list_xfer_size += xfer_size;
+ buf += xfer_size;
+ buf_len -= xfer_size;
+ }
+ }
+
+ return vchan_tx_prep(&mchan->vc, &mdesc->vd, flags);
+
+free_desc:
+ mdc_desc_free(&mdesc->vd);
+
+ return NULL;
+}
+
+static void mdc_issue_desc(struct mdc_chan *mchan)
+{
+ struct mdc_dma *mdma = mchan->mdma;
+ struct virt_dma_desc *vd;
+ struct mdc_tx_desc *mdesc;
+ u32 val;
+
+ vd = vchan_next_desc(&mchan->vc);
+ if (!vd)
+ return;
+
+ list_del(&vd->node);
+
+ mdesc = to_mdc_desc(&vd->tx);
+ mchan->desc = mdesc;
+
+ dev_dbg(mdma2dev(mdma), "Issuing descriptor on channel %d\n",
+ mchan->chan_nr);
+
+ mdma->soc->enable_chan(mchan);
+
+ val = mdc_chan_readl(mchan, MDC_GENERAL_CONFIG);
+ val |= MDC_GENERAL_CONFIG_LIST_IEN | MDC_GENERAL_CONFIG_IEN |
+ MDC_GENERAL_CONFIG_LEVEL_INT | MDC_GENERAL_CONFIG_PHYSICAL_W |
+ MDC_GENERAL_CONFIG_PHYSICAL_R;
+ mdc_chan_writel(mchan, val, MDC_GENERAL_CONFIG);
+ val = (mchan->thread << MDC_READ_PORT_CONFIG_STHREAD_SHIFT) |
+ (mchan->thread << MDC_READ_PORT_CONFIG_RTHREAD_SHIFT) |
+ (mchan->thread << MDC_READ_PORT_CONFIG_WTHREAD_SHIFT);
+ mdc_chan_writel(mchan, val, MDC_READ_PORT_CONFIG);
+ mdc_chan_writel(mchan, mdesc->list_phys, MDC_LIST_NODE_ADDRESS);
+ val = mdc_chan_readl(mchan, MDC_CONTROL_AND_STATUS);
+ val |= MDC_CONTROL_AND_STATUS_LIST_EN;
+ mdc_chan_writel(mchan, val, MDC_CONTROL_AND_STATUS);
+}
+
+static void mdc_issue_pending(struct dma_chan *chan)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mchan->vc.lock, flags);
+ if (vchan_issue_pending(&mchan->vc) && !mchan->desc)
+ mdc_issue_desc(mchan);
+ spin_unlock_irqrestore(&mchan->vc.lock, flags);
+}
+
+static enum dma_status mdc_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie, struct dma_tx_state *txstate)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ struct mdc_tx_desc *mdesc;
+ struct virt_dma_desc *vd;
+ unsigned long flags;
+ size_t bytes = 0;
+ int ret;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+ if (ret == DMA_COMPLETE)
+ return ret;
+
+ if (!txstate)
+ return ret;
+
+ spin_lock_irqsave(&mchan->vc.lock, flags);
+ vd = vchan_find_desc(&mchan->vc, cookie);
+ if (vd) {
+ mdesc = to_mdc_desc(&vd->tx);
+ bytes = mdesc->list_xfer_size;
+ } else if (mchan->desc && mchan->desc->vd.tx.cookie == cookie) {
+ struct mdc_hw_list_desc *ldesc;
+ u32 val1, val2, done, processed, residue;
+ int i, cmds;
+
+ mdesc = mchan->desc;
+
+ /*
+ * Determine the number of commands that haven't been
+ * processed (handled by the IRQ handler) yet.
+ */
+ do {
+ val1 = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED) &
+ ~MDC_CMDS_PROCESSED_INT_ACTIVE;
+ residue = mdc_chan_readl(mchan,
+ MDC_ACTIVE_TRANSFER_SIZE);
+ val2 = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED) &
+ ~MDC_CMDS_PROCESSED_INT_ACTIVE;
+ } while (val1 != val2);
+
+ done = (val1 >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
+ processed = (val1 >> MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK;
+ cmds = (done - processed) %
+ (MDC_CMDS_PROCESSED_CMDS_DONE_MASK + 1);
+
+ /*
+ * If the command loaded event hasn't been processed yet, then
+ * the difference above includes an extra command.
+ */
+ if (!mdesc->cmd_loaded)
+ cmds--;
+ else
+ cmds += mdesc->list_cmds_done;
+
+ bytes = mdesc->list_xfer_size;
+ ldesc = mdesc->list;
+ for (i = 0; i < cmds; i++) {
+ bytes -= ldesc->xfer_size + 1;
+ ldesc = ldesc->next_desc;
+ }
+ if (ldesc) {
+ if (residue != MDC_TRANSFER_SIZE_MASK)
+ bytes -= ldesc->xfer_size - residue;
+ else
+ bytes -= ldesc->xfer_size + 1;
+ }
+ }
+ spin_unlock_irqrestore(&mchan->vc.lock, flags);
+
+ dma_set_residue(txstate, bytes);
+
+ return ret;
+}
+
+static int mdc_terminate_all(struct dma_chan *chan)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ struct mdc_tx_desc *mdesc;
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock_irqsave(&mchan->vc.lock, flags);
+
+ mdc_chan_writel(mchan, MDC_CONTROL_AND_STATUS_CANCEL,
+ MDC_CONTROL_AND_STATUS);
+
+ mdesc = mchan->desc;
+ mchan->desc = NULL;
+ vchan_get_all_descriptors(&mchan->vc, &head);
+
+ spin_unlock_irqrestore(&mchan->vc.lock, flags);
+
+ if (mdesc)
+ mdc_desc_free(&mdesc->vd);
+ vchan_dma_desc_free_list(&mchan->vc, &head);
+
+ return 0;
+}
+
+static int mdc_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&mchan->vc.lock, flags);
+ mchan->config = *config;
+ spin_unlock_irqrestore(&mchan->vc.lock, flags);
+
+ return 0;
+}
+
+static int mdc_alloc_chan_resources(struct dma_chan *chan)
+{
+ return 0;
+}
+
+static void mdc_free_chan_resources(struct dma_chan *chan)
+{
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+ struct mdc_dma *mdma = mchan->mdma;
+
+ mdc_terminate_all(chan);
+
+ mdma->soc->disable_chan(mchan);
+}
+
+static irqreturn_t mdc_chan_irq(int irq, void *dev_id)
+{
+ struct mdc_chan *mchan = (struct mdc_chan *)dev_id;
+ struct mdc_tx_desc *mdesc;
+ u32 val, processed, done1, done2;
+ unsigned int i;
+
+ spin_lock(&mchan->vc.lock);
+
+ val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
+ processed = (val >> MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK;
+ /*
+ * CMDS_DONE may have incremented between reading CMDS_PROCESSED
+ * and clearing INT_ACTIVE. Re-read CMDS_PROCESSED to ensure we
+ * didn't miss a command completion.
+ */
+ do {
+ val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
+ done1 = (val >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
+ val &= ~((MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK <<
+ MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT) |
+ MDC_CMDS_PROCESSED_INT_ACTIVE);
+ val |= done1 << MDC_CMDS_PROCESSED_CMDS_PROCESSED_SHIFT;
+ mdc_chan_writel(mchan, val, MDC_CMDS_PROCESSED);
+ val = mdc_chan_readl(mchan, MDC_CMDS_PROCESSED);
+ done2 = (val >> MDC_CMDS_PROCESSED_CMDS_DONE_SHIFT) &
+ MDC_CMDS_PROCESSED_CMDS_DONE_MASK;
+ } while (done1 != done2);
+
+ dev_dbg(mdma2dev(mchan->mdma), "IRQ on channel %d\n", mchan->chan_nr);
+
+ mdesc = mchan->desc;
+ if (!mdesc) {
+ dev_warn(mdma2dev(mchan->mdma),
+ "IRQ with no active descriptor on channel %d\n",
+ mchan->chan_nr);
+ goto out;
+ }
+
+ for (i = processed; i != done1;
+ i = (i + 1) % (MDC_CMDS_PROCESSED_CMDS_PROCESSED_MASK + 1)) {
+ /*
+ * The first interrupt in a transfer indicates that the
+ * command list has been loaded, not that a command has
+ * been completed.
+ */
+ if (!mdesc->cmd_loaded) {
+ mdesc->cmd_loaded = true;
+ continue;
+ }
+
+ mdesc->list_cmds_done++;
+ if (mdesc->cyclic) {
+ mdesc->list_cmds_done %= mdesc->list_len;
+ if (mdesc->list_cmds_done % mdesc->list_period_len == 0)
+ vchan_cyclic_callback(&mdesc->vd);
+ } else if (mdesc->list_cmds_done == mdesc->list_len) {
+ mchan->desc = NULL;
+ vchan_cookie_complete(&mdesc->vd);
+ mdc_issue_desc(mchan);
+ break;
+ }
+ }
+out:
+ spin_unlock(&mchan->vc.lock);
+
+ return IRQ_HANDLED;
+}
+
+static struct dma_chan *mdc_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct mdc_dma *mdma = ofdma->of_dma_data;
+ struct dma_chan *chan;
+
+ if (dma_spec->args_count != 3)
+ return NULL;
+
+ list_for_each_entry(chan, &mdma->dma_dev.channels, device_node) {
+ struct mdc_chan *mchan = to_mdc_chan(chan);
+
+ if (!(dma_spec->args[1] & BIT(mchan->chan_nr)))
+ continue;
+ if (dma_get_slave_channel(chan)) {
+ mchan->periph = dma_spec->args[0];
+ mchan->thread = dma_spec->args[2];
+ return chan;
+ }
+ }
+
+ return NULL;
+}
+
+#define PISTACHIO_CR_PERIPH_DMA_ROUTE(ch) (0x120 + 0x4 * ((ch) / 4))
+#define PISTACHIO_CR_PERIPH_DMA_ROUTE_SHIFT(ch) (8 * ((ch) % 4))
+#define PISTACHIO_CR_PERIPH_DMA_ROUTE_MASK 0x3f
+
+static void pistachio_mdc_enable_chan(struct mdc_chan *mchan)
+{
+ struct mdc_dma *mdma = mchan->mdma;
+
+ regmap_update_bits(mdma->periph_regs,
+ PISTACHIO_CR_PERIPH_DMA_ROUTE(mchan->chan_nr),
+ PISTACHIO_CR_PERIPH_DMA_ROUTE_MASK <<
+ PISTACHIO_CR_PERIPH_DMA_ROUTE_SHIFT(mchan->chan_nr),
+ mchan->periph <<
+ PISTACHIO_CR_PERIPH_DMA_ROUTE_SHIFT(mchan->chan_nr));
+}
+
+static void pistachio_mdc_disable_chan(struct mdc_chan *mchan)
+{
+ struct mdc_dma *mdma = mchan->mdma;
+
+ regmap_update_bits(mdma->periph_regs,
+ PISTACHIO_CR_PERIPH_DMA_ROUTE(mchan->chan_nr),
+ PISTACHIO_CR_PERIPH_DMA_ROUTE_MASK <<
+ PISTACHIO_CR_PERIPH_DMA_ROUTE_SHIFT(mchan->chan_nr),
+ 0);
+}
+
+static const struct mdc_dma_soc_data pistachio_mdc_data = {
+ .enable_chan = pistachio_mdc_enable_chan,
+ .disable_chan = pistachio_mdc_disable_chan,
+};
+
+static const struct of_device_id mdc_dma_of_match[] = {
+ { .compatible = "img,pistachio-mdc-dma", .data = &pistachio_mdc_data, },
+ { },
+};
+MODULE_DEVICE_TABLE(of, mdc_dma_of_match);
+
+static int mdc_dma_probe(struct platform_device *pdev)
+{
+ struct mdc_dma *mdma;
+ struct resource *res;
+ const struct of_device_id *match;
+ unsigned int i;
+ u32 val;
+ int ret;
+
+ mdma = devm_kzalloc(&pdev->dev, sizeof(*mdma), GFP_KERNEL);
+ if (!mdma)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, mdma);
+
+ match = of_match_device(mdc_dma_of_match, &pdev->dev);
+ mdma->soc = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mdma->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mdma->regs))
+ return PTR_ERR(mdma->regs);
+
+ mdma->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "img,cr-periph");
+ if (IS_ERR(mdma->periph_regs))
+ return PTR_ERR(mdma->periph_regs);
+
+ mdma->clk = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(mdma->clk))
+ return PTR_ERR(mdma->clk);
+
+ ret = clk_prepare_enable(mdma->clk);
+ if (ret)
+ return ret;
+
+ dma_cap_zero(mdma->dma_dev.cap_mask);
+ dma_cap_set(DMA_SLAVE, mdma->dma_dev.cap_mask);
+ dma_cap_set(DMA_PRIVATE, mdma->dma_dev.cap_mask);
+ dma_cap_set(DMA_CYCLIC, mdma->dma_dev.cap_mask);
+ dma_cap_set(DMA_MEMCPY, mdma->dma_dev.cap_mask);
+
+ val = mdc_readl(mdma, MDC_GLOBAL_CONFIG_A);
+ mdma->nr_channels = (val >> MDC_GLOBAL_CONFIG_A_DMA_CONTEXTS_SHIFT) &
+ MDC_GLOBAL_CONFIG_A_DMA_CONTEXTS_MASK;
+ mdma->nr_threads =
+ 1 << ((val >> MDC_GLOBAL_CONFIG_A_THREAD_ID_WIDTH_SHIFT) &
+ MDC_GLOBAL_CONFIG_A_THREAD_ID_WIDTH_MASK);
+ mdma->bus_width =
+ (1 << ((val >> MDC_GLOBAL_CONFIG_A_SYS_DAT_WIDTH_SHIFT) &
+ MDC_GLOBAL_CONFIG_A_SYS_DAT_WIDTH_MASK)) / 8;
+ /*
+ * Although transfer sizes of up to MDC_TRANSFER_SIZE_MASK + 1 bytes
+ * are supported, this makes it possible for the value reported in
+ * MDC_ACTIVE_TRANSFER_SIZE to be ambiguous - an active transfer size
+ * of MDC_TRANSFER_SIZE_MASK may indicate either that 0 bytes or
+ * MDC_TRANSFER_SIZE_MASK + 1 bytes are remaining. To eliminate this
+ * ambiguity, restrict transfer sizes to one bus-width less than the
+ * actual maximum.
+ */
+ mdma->max_xfer_size = MDC_TRANSFER_SIZE_MASK + 1 - mdma->bus_width;
+
+ of_property_read_u32(pdev->dev.of_node, "dma-channels",
+ &mdma->nr_channels);
+ ret = of_property_read_u32(pdev->dev.of_node,
+ "img,max-burst-multiplier",
+ &mdma->max_burst_mult);
+ if (ret)
+ goto disable_clk;
+
+ mdma->dma_dev.dev = &pdev->dev;
+ mdma->dma_dev.device_prep_slave_sg = mdc_prep_slave_sg;
+ mdma->dma_dev.device_prep_dma_cyclic = mdc_prep_dma_cyclic;
+ mdma->dma_dev.device_prep_dma_memcpy = mdc_prep_dma_memcpy;
+ mdma->dma_dev.device_alloc_chan_resources = mdc_alloc_chan_resources;
+ mdma->dma_dev.device_free_chan_resources = mdc_free_chan_resources;
+ mdma->dma_dev.device_tx_status = mdc_tx_status;
+ mdma->dma_dev.device_issue_pending = mdc_issue_pending;
+ mdma->dma_dev.device_terminate_all = mdc_terminate_all;
+ mdma->dma_dev.device_config = mdc_slave_config;
+
+ mdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ mdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ for (i = 1; i <= mdma->bus_width; i <<= 1) {
+ mdma->dma_dev.src_addr_widths |= BIT(i);
+ mdma->dma_dev.dst_addr_widths |= BIT(i);
+ }
+
+ INIT_LIST_HEAD(&mdma->dma_dev.channels);
+ for (i = 0; i < mdma->nr_channels; i++) {
+ struct mdc_chan *mchan = &mdma->channels[i];
+
+ mchan->mdma = mdma;
+ mchan->chan_nr = i;
+ mchan->irq = platform_get_irq(pdev, i);
+ if (mchan->irq < 0) {
+ ret = mchan->irq;
+ goto disable_clk;
+ }
+ ret = devm_request_irq(&pdev->dev, mchan->irq, mdc_chan_irq,
+ IRQ_TYPE_LEVEL_HIGH,
+ dev_name(&pdev->dev), mchan);
+ if (ret < 0)
+ goto disable_clk;
+
+ mchan->vc.desc_free = mdc_desc_free;
+ vchan_init(&mchan->vc, &mdma->dma_dev);
+ }
+
+ mdma->desc_pool = dmam_pool_create(dev_name(&pdev->dev), &pdev->dev,
+ sizeof(struct mdc_hw_list_desc),
+ 4, 0);
+ if (!mdma->desc_pool) {
+ ret = -ENOMEM;
+ goto disable_clk;
+ }
+
+ ret = dma_async_device_register(&mdma->dma_dev);
+ if (ret)
+ goto disable_clk;
+
+ ret = of_dma_controller_register(pdev->dev.of_node, mdc_of_xlate, mdma);
+ if (ret)
+ goto unregister;
+
+ dev_info(&pdev->dev, "MDC with %u channels and %u threads\n",
+ mdma->nr_channels, mdma->nr_threads);
+
+ return 0;
+
+unregister:
+ dma_async_device_unregister(&mdma->dma_dev);
+disable_clk:
+ clk_disable_unprepare(mdma->clk);
+ return ret;
+}
+
+static int mdc_dma_remove(struct platform_device *pdev)
+{
+ struct mdc_dma *mdma = platform_get_drvdata(pdev);
+ struct mdc_chan *mchan, *next;
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&mdma->dma_dev);
+
+ list_for_each_entry_safe(mchan, next, &mdma->dma_dev.channels,
+ vc.chan.device_node) {
+ list_del(&mchan->vc.chan.device_node);
+
+ synchronize_irq(mchan->irq);
+ devm_free_irq(&pdev->dev, mchan->irq, mchan);
+
+ tasklet_kill(&mchan->vc.task);
+ }
+
+ clk_disable_unprepare(mdma->clk);
+
+ return 0;
+}
+
+static struct platform_driver mdc_dma_driver = {
+ .driver = {
+ .name = "img-mdc-dma",
+ .of_match_table = of_match_ptr(mdc_dma_of_match),
+ },
+ .probe = mdc_dma_probe,
+ .remove = mdc_dma_remove,
+};
+module_platform_driver(mdc_dma_driver);
+
+MODULE_DESCRIPTION("IMG Multi-threaded DMA Controller (MDC) driver");
+MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/imx-dma.c b/drivers/dma/imx-dma.c
index 10bbc0a675b0..eed405976ea9 100644
--- a/drivers/dma/imx-dma.c
+++ b/drivers/dma/imx-dma.c
@@ -230,11 +230,6 @@ static inline int is_imx1_dma(struct imxdma_engine *imxdma)
return imxdma->devtype == IMX1_DMA;
}
-static inline int is_imx21_dma(struct imxdma_engine *imxdma)
-{
- return imxdma->devtype == IMX21_DMA;
-}
-
static inline int is_imx27_dma(struct imxdma_engine *imxdma)
{
return imxdma->devtype == IMX27_DMA;
@@ -669,69 +664,67 @@ out:
}
-static int imxdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int imxdma_terminate_all(struct dma_chan *chan)
{
struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
- struct dma_slave_config *dmaengine_cfg = (void *)arg;
struct imxdma_engine *imxdma = imxdmac->imxdma;
unsigned long flags;
- unsigned int mode = 0;
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- imxdma_disable_hw(imxdmac);
-
- spin_lock_irqsave(&imxdma->lock, flags);
- list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
- list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
- spin_unlock_irqrestore(&imxdma->lock, flags);
- return 0;
- case DMA_SLAVE_CONFIG:
- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
- imxdmac->per_address = dmaengine_cfg->src_addr;
- imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
- imxdmac->word_size = dmaengine_cfg->src_addr_width;
- } else {
- imxdmac->per_address = dmaengine_cfg->dst_addr;
- imxdmac->watermark_level = dmaengine_cfg->dst_maxburst;
- imxdmac->word_size = dmaengine_cfg->dst_addr_width;
- }
- switch (imxdmac->word_size) {
- case DMA_SLAVE_BUSWIDTH_1_BYTE:
- mode = IMX_DMA_MEMSIZE_8;
- break;
- case DMA_SLAVE_BUSWIDTH_2_BYTES:
- mode = IMX_DMA_MEMSIZE_16;
- break;
- default:
- case DMA_SLAVE_BUSWIDTH_4_BYTES:
- mode = IMX_DMA_MEMSIZE_32;
- break;
- }
+ imxdma_disable_hw(imxdmac);
- imxdmac->hw_chaining = 0;
+ spin_lock_irqsave(&imxdma->lock, flags);
+ list_splice_tail_init(&imxdmac->ld_active, &imxdmac->ld_free);
+ list_splice_tail_init(&imxdmac->ld_queue, &imxdmac->ld_free);
+ spin_unlock_irqrestore(&imxdma->lock, flags);
+ return 0;
+}
- imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) |
- ((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) |
- CCR_REN;
- imxdmac->ccr_to_device =
- (IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) |
- ((mode | IMX_DMA_TYPE_FIFO) << 2) | CCR_REN;
- imx_dmav1_writel(imxdma, imxdmac->dma_request,
- DMA_RSSR(imxdmac->channel));
+static int imxdma_config(struct dma_chan *chan,
+ struct dma_slave_config *dmaengine_cfg)
+{
+ struct imxdma_channel *imxdmac = to_imxdma_chan(chan);
+ struct imxdma_engine *imxdma = imxdmac->imxdma;
+ unsigned int mode = 0;
- /* Set burst length */
- imx_dmav1_writel(imxdma, imxdmac->watermark_level *
- imxdmac->word_size, DMA_BLR(imxdmac->channel));
+ if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+ imxdmac->per_address = dmaengine_cfg->src_addr;
+ imxdmac->watermark_level = dmaengine_cfg->src_maxburst;
+ imxdmac->word_size = dmaengine_cfg->src_addr_width;
+ } else {
+ imxdmac->per_address = dmaengine_cfg->dst_addr;
+ imxdmac->watermark_level = dmaengine_cfg->dst_maxburst;
+ imxdmac->word_size = dmaengine_cfg->dst_addr_width;
+ }
- return 0;
+ switch (imxdmac->word_size) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ mode = IMX_DMA_MEMSIZE_8;
+ break;
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ mode = IMX_DMA_MEMSIZE_16;
+ break;
default:
- return -ENOSYS;
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ mode = IMX_DMA_MEMSIZE_32;
+ break;
}
- return -EINVAL;
+ imxdmac->hw_chaining = 0;
+
+ imxdmac->ccr_from_device = (mode | IMX_DMA_TYPE_FIFO) |
+ ((IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) << 2) |
+ CCR_REN;
+ imxdmac->ccr_to_device =
+ (IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR) |
+ ((mode | IMX_DMA_TYPE_FIFO) << 2) | CCR_REN;
+ imx_dmav1_writel(imxdma, imxdmac->dma_request,
+ DMA_RSSR(imxdmac->channel));
+
+ /* Set burst length */
+ imx_dmav1_writel(imxdma, imxdmac->watermark_level *
+ imxdmac->word_size, DMA_BLR(imxdmac->channel));
+
+ return 0;
}
static enum dma_status imxdma_tx_status(struct dma_chan *chan,
@@ -1184,7 +1177,8 @@ static int __init imxdma_probe(struct platform_device *pdev)
imxdma->dma_device.device_prep_dma_cyclic = imxdma_prep_dma_cyclic;
imxdma->dma_device.device_prep_dma_memcpy = imxdma_prep_dma_memcpy;
imxdma->dma_device.device_prep_interleaved_dma = imxdma_prep_dma_interleaved;
- imxdma->dma_device.device_control = imxdma_control;
+ imxdma->dma_device.device_config = imxdma_config;
+ imxdma->dma_device.device_terminate_all = imxdma_terminate_all;
imxdma->dma_device.device_issue_pending = imxdma_issue_pending;
platform_set_drvdata(pdev, imxdma);
diff --git a/drivers/dma/imx-sdma.c b/drivers/dma/imx-sdma.c
index d0df198f62e9..18c0a131e4e4 100644
--- a/drivers/dma/imx-sdma.c
+++ b/drivers/dma/imx-sdma.c
@@ -830,20 +830,29 @@ static int sdma_load_context(struct sdma_channel *sdmac)
return ret;
}
-static void sdma_disable_channel(struct sdma_channel *sdmac)
+static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
+{
+ return container_of(chan, struct sdma_channel, chan);
+}
+
+static int sdma_disable_channel(struct dma_chan *chan)
{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
int channel = sdmac->channel;
writel_relaxed(BIT(channel), sdma->regs + SDMA_H_STATSTOP);
sdmac->status = DMA_ERROR;
+
+ return 0;
}
-static int sdma_config_channel(struct sdma_channel *sdmac)
+static int sdma_config_channel(struct dma_chan *chan)
{
+ struct sdma_channel *sdmac = to_sdma_chan(chan);
int ret;
- sdma_disable_channel(sdmac);
+ sdma_disable_channel(chan);
sdmac->event_mask[0] = 0;
sdmac->event_mask[1] = 0;
@@ -935,11 +944,6 @@ out:
return ret;
}
-static struct sdma_channel *to_sdma_chan(struct dma_chan *chan)
-{
- return container_of(chan, struct sdma_channel, chan);
-}
-
static dma_cookie_t sdma_tx_submit(struct dma_async_tx_descriptor *tx)
{
unsigned long flags;
@@ -1004,7 +1008,7 @@ static void sdma_free_chan_resources(struct dma_chan *chan)
struct sdma_channel *sdmac = to_sdma_chan(chan);
struct sdma_engine *sdma = sdmac->sdma;
- sdma_disable_channel(sdmac);
+ sdma_disable_channel(chan);
if (sdmac->event_id0)
sdma_event_disable(sdmac, sdmac->event_id0);
@@ -1203,35 +1207,24 @@ err_out:
return NULL;
}
-static int sdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int sdma_config(struct dma_chan *chan,
+ struct dma_slave_config *dmaengine_cfg)
{
struct sdma_channel *sdmac = to_sdma_chan(chan);
- struct dma_slave_config *dmaengine_cfg = (void *)arg;
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- sdma_disable_channel(sdmac);
- return 0;
- case DMA_SLAVE_CONFIG:
- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
- sdmac->per_address = dmaengine_cfg->src_addr;
- sdmac->watermark_level = dmaengine_cfg->src_maxburst *
- dmaengine_cfg->src_addr_width;
- sdmac->word_size = dmaengine_cfg->src_addr_width;
- } else {
- sdmac->per_address = dmaengine_cfg->dst_addr;
- sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
- dmaengine_cfg->dst_addr_width;
- sdmac->word_size = dmaengine_cfg->dst_addr_width;
- }
- sdmac->direction = dmaengine_cfg->direction;
- return sdma_config_channel(sdmac);
- default:
- return -ENOSYS;
- }
- return -EINVAL;
+ if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+ sdmac->per_address = dmaengine_cfg->src_addr;
+ sdmac->watermark_level = dmaengine_cfg->src_maxburst *
+ dmaengine_cfg->src_addr_width;
+ sdmac->word_size = dmaengine_cfg->src_addr_width;
+ } else {
+ sdmac->per_address = dmaengine_cfg->dst_addr;
+ sdmac->watermark_level = dmaengine_cfg->dst_maxburst *
+ dmaengine_cfg->dst_addr_width;
+ sdmac->word_size = dmaengine_cfg->dst_addr_width;
+ }
+ sdmac->direction = dmaengine_cfg->direction;
+ return sdma_config_channel(chan);
}
static enum dma_status sdma_tx_status(struct dma_chan *chan,
@@ -1303,15 +1296,15 @@ static void sdma_load_firmware(const struct firmware *fw, void *context)
if (header->ram_code_start + header->ram_code_size > fw->size)
goto err_firmware;
switch (header->version_major) {
- case 1:
- sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
- break;
- case 2:
- sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
- break;
- default:
- dev_err(sdma->dev, "unknown firmware version\n");
- goto err_firmware;
+ case 1:
+ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V1;
+ break;
+ case 2:
+ sdma->script_number = SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V2;
+ break;
+ default:
+ dev_err(sdma->dev, "unknown firmware version\n");
+ goto err_firmware;
}
addr = (void *)header + header->script_addrs_start;
@@ -1479,7 +1472,7 @@ static int sdma_probe(struct platform_device *pdev)
if (ret)
return ret;
- sdma = kzalloc(sizeof(*sdma), GFP_KERNEL);
+ sdma = devm_kzalloc(&pdev->dev, sizeof(*sdma), GFP_KERNEL);
if (!sdma)
return -ENOMEM;
@@ -1488,48 +1481,34 @@ static int sdma_probe(struct platform_device *pdev)
sdma->dev = &pdev->dev;
sdma->drvdata = drvdata;
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
- if (!iores || irq < 0) {
- ret = -EINVAL;
- goto err_irq;
- }
+ if (irq < 0)
+ return irq;
- if (!request_mem_region(iores->start, resource_size(iores), pdev->name)) {
- ret = -EBUSY;
- goto err_request_region;
- }
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ sdma->regs = devm_ioremap_resource(&pdev->dev, iores);
+ if (IS_ERR(sdma->regs))
+ return PTR_ERR(sdma->regs);
sdma->clk_ipg = devm_clk_get(&pdev->dev, "ipg");
- if (IS_ERR(sdma->clk_ipg)) {
- ret = PTR_ERR(sdma->clk_ipg);
- goto err_clk;
- }
+ if (IS_ERR(sdma->clk_ipg))
+ return PTR_ERR(sdma->clk_ipg);
sdma->clk_ahb = devm_clk_get(&pdev->dev, "ahb");
- if (IS_ERR(sdma->clk_ahb)) {
- ret = PTR_ERR(sdma->clk_ahb);
- goto err_clk;
- }
+ if (IS_ERR(sdma->clk_ahb))
+ return PTR_ERR(sdma->clk_ahb);
clk_prepare(sdma->clk_ipg);
clk_prepare(sdma->clk_ahb);
- sdma->regs = ioremap(iores->start, resource_size(iores));
- if (!sdma->regs) {
- ret = -ENOMEM;
- goto err_ioremap;
- }
-
- ret = request_irq(irq, sdma_int_handler, 0, "sdma", sdma);
+ ret = devm_request_irq(&pdev->dev, irq, sdma_int_handler, 0, "sdma",
+ sdma);
if (ret)
- goto err_request_irq;
+ return ret;
sdma->script_addrs = kzalloc(sizeof(*sdma->script_addrs), GFP_KERNEL);
- if (!sdma->script_addrs) {
- ret = -ENOMEM;
- goto err_alloc;
- }
+ if (!sdma->script_addrs)
+ return -ENOMEM;
/* initially no scripts available */
saddr_arr = (s32 *)sdma->script_addrs;
@@ -1600,7 +1579,12 @@ static int sdma_probe(struct platform_device *pdev)
sdma->dma_device.device_tx_status = sdma_tx_status;
sdma->dma_device.device_prep_slave_sg = sdma_prep_slave_sg;
sdma->dma_device.device_prep_dma_cyclic = sdma_prep_dma_cyclic;
- sdma->dma_device.device_control = sdma_control;
+ sdma->dma_device.device_config = sdma_config;
+ sdma->dma_device.device_terminate_all = sdma_disable_channel;
+ sdma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ sdma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ sdma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ sdma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
sdma->dma_device.device_issue_pending = sdma_issue_pending;
sdma->dma_device.dev->dma_parms = &sdma->dma_parms;
dma_set_max_seg_size(sdma->dma_device.dev, 65535);
@@ -1629,38 +1613,22 @@ err_register:
dma_async_device_unregister(&sdma->dma_device);
err_init:
kfree(sdma->script_addrs);
-err_alloc:
- free_irq(irq, sdma);
-err_request_irq:
- iounmap(sdma->regs);
-err_ioremap:
-err_clk:
- release_mem_region(iores->start, resource_size(iores));
-err_request_region:
-err_irq:
- kfree(sdma);
return ret;
}
static int sdma_remove(struct platform_device *pdev)
{
struct sdma_engine *sdma = platform_get_drvdata(pdev);
- struct resource *iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- int irq = platform_get_irq(pdev, 0);
int i;
dma_async_device_unregister(&sdma->dma_device);
kfree(sdma->script_addrs);
- free_irq(irq, sdma);
- iounmap(sdma->regs);
- release_mem_region(iores->start, resource_size(iores));
/* Kill the tasklet */
for (i = 0; i < MAX_DMA_CHANNELS; i++) {
struct sdma_channel *sdmac = &sdma->channel[i];
tasklet_kill(&sdmac->tasklet);
}
- kfree(sdma);
platform_set_drvdata(pdev, NULL);
dev_info(&pdev->dev, "Removed...\n");
diff --git a/drivers/dma/intel_mid_dma.c b/drivers/dma/intel_mid_dma.c
index 1aab8130efa1..5aaead9b56f7 100644
--- a/drivers/dma/intel_mid_dma.c
+++ b/drivers/dma/intel_mid_dma.c
@@ -492,10 +492,10 @@ static enum dma_status intel_mid_dma_tx_status(struct dma_chan *chan,
return ret;
}
-static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
+static int intel_mid_dma_config(struct dma_chan *chan,
+ struct dma_slave_config *slave)
{
struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
- struct dma_slave_config *slave = (struct dma_slave_config *)arg;
struct intel_mid_dma_slave *mid_slave;
BUG_ON(!midc);
@@ -509,28 +509,14 @@ static int dma_slave_control(struct dma_chan *chan, unsigned long arg)
midc->mid_slave = mid_slave;
return 0;
}
-/**
- * intel_mid_dma_device_control - DMA device control
- * @chan: chan for DMA control
- * @cmd: control cmd
- * @arg: cmd arg value
- *
- * Perform DMA control command
- */
-static int intel_mid_dma_device_control(struct dma_chan *chan,
- enum dma_ctrl_cmd cmd, unsigned long arg)
+
+static int intel_mid_dma_terminate_all(struct dma_chan *chan)
{
struct intel_mid_dma_chan *midc = to_intel_mid_dma_chan(chan);
struct middma_device *mid = to_middma_device(chan->device);
struct intel_mid_dma_desc *desc, *_desc;
union intel_mid_dma_cfg_lo cfg_lo;
- if (cmd == DMA_SLAVE_CONFIG)
- return dma_slave_control(chan, arg);
-
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
-
spin_lock_bh(&midc->lock);
if (midc->busy == false) {
spin_unlock_bh(&midc->lock);
@@ -1148,7 +1134,8 @@ static int mid_setup_dma(struct pci_dev *pdev)
dma->common.device_prep_dma_memcpy = intel_mid_dma_prep_memcpy;
dma->common.device_issue_pending = intel_mid_dma_issue_pending;
dma->common.device_prep_slave_sg = intel_mid_dma_prep_slave_sg;
- dma->common.device_control = intel_mid_dma_device_control;
+ dma->common.device_config = intel_mid_dma_config;
+ dma->common.device_terminate_all = intel_mid_dma_terminate_all;
/*enable dma cntrl*/
iowrite32(REG_BIT0, dma->dma_base + DMA_CFG);
diff --git a/drivers/dma/ioat/dma_v3.c b/drivers/dma/ioat/dma_v3.c
index 32eae38291e5..77a6dcf25b98 100644
--- a/drivers/dma/ioat/dma_v3.c
+++ b/drivers/dma/ioat/dma_v3.c
@@ -214,6 +214,11 @@ static bool is_bwd_ioat(struct pci_dev *pdev)
case PCI_DEVICE_ID_INTEL_IOAT_BWD1:
case PCI_DEVICE_ID_INTEL_IOAT_BWD2:
case PCI_DEVICE_ID_INTEL_IOAT_BWD3:
+ /* even though not Atom, BDX-DE has same DMA silicon */
+ case PCI_DEVICE_ID_INTEL_IOAT_BDXDE0:
+ case PCI_DEVICE_ID_INTEL_IOAT_BDXDE1:
+ case PCI_DEVICE_ID_INTEL_IOAT_BDXDE2:
+ case PCI_DEVICE_ID_INTEL_IOAT_BDXDE3:
return true;
default:
return false;
@@ -489,6 +494,7 @@ static void ioat3_eh(struct ioat2_dma_chan *ioat)
struct ioat_chan_common *chan = &ioat->base;
struct pci_dev *pdev = to_pdev(chan);
struct ioat_dma_descriptor *hw;
+ struct dma_async_tx_descriptor *tx;
u64 phys_complete;
struct ioat_ring_ent *desc;
u32 err_handled = 0;
@@ -534,6 +540,16 @@ static void ioat3_eh(struct ioat2_dma_chan *ioat)
dev_err(to_dev(chan), "%s: fatal error (%x:%x)\n",
__func__, chanerr, err_handled);
BUG();
+ } else { /* cleanup the faulty descriptor */
+ tx = &desc->txd;
+ if (tx->cookie) {
+ dma_cookie_complete(tx);
+ dma_descriptor_unmap(tx);
+ if (tx->callback) {
+ tx->callback(tx->callback_param);
+ tx->callback = NULL;
+ }
+ }
}
writel(chanerr, chan->reg_base + IOAT_CHANERR_OFFSET);
@@ -1300,7 +1316,8 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
- if (dma->device_tx_status(dma_chan, cookie, NULL) != DMA_COMPLETE) {
+ if (tmo == 0 ||
+ dma->device_tx_status(dma_chan, cookie, NULL) != DMA_COMPLETE) {
dev_err(dev, "Self-test xor timed out\n");
err = -ENODEV;
goto dma_unmap;
@@ -1366,7 +1383,8 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
- if (dma->device_tx_status(dma_chan, cookie, NULL) != DMA_COMPLETE) {
+ if (tmo == 0 ||
+ dma->device_tx_status(dma_chan, cookie, NULL) != DMA_COMPLETE) {
dev_err(dev, "Self-test validate timed out\n");
err = -ENODEV;
goto dma_unmap;
@@ -1418,7 +1436,8 @@ static int ioat_xor_val_self_test(struct ioatdma_device *device)
tmo = wait_for_completion_timeout(&cmp, msecs_to_jiffies(3000));
- if (dma->device_tx_status(dma_chan, cookie, NULL) != DMA_COMPLETE) {
+ if (tmo == 0 ||
+ dma->device_tx_status(dma_chan, cookie, NULL) != DMA_COMPLETE) {
dev_err(dev, "Self-test 2nd validate timed out\n");
err = -ENODEV;
goto dma_unmap;
diff --git a/drivers/dma/ioat/hw.h b/drivers/dma/ioat/hw.h
index 62f83e983d8d..02177ecf09f8 100644
--- a/drivers/dma/ioat/hw.h
+++ b/drivers/dma/ioat/hw.h
@@ -57,6 +57,11 @@
#define PCI_DEVICE_ID_INTEL_IOAT_BWD2 0x0C52
#define PCI_DEVICE_ID_INTEL_IOAT_BWD3 0x0C53
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE0 0x6f50
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE1 0x6f51
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE2 0x6f52
+#define PCI_DEVICE_ID_INTEL_IOAT_BDXDE3 0x6f53
+
#define IOAT_VER_1_2 0x12 /* Version 1.2 */
#define IOAT_VER_2_0 0x20 /* Version 2.0 */
#define IOAT_VER_3_0 0x30 /* Version 3.0 */
diff --git a/drivers/dma/ioat/pci.c b/drivers/dma/ioat/pci.c
index 1d051cd045db..5501eb072d69 100644
--- a/drivers/dma/ioat/pci.c
+++ b/drivers/dma/ioat/pci.c
@@ -111,6 +111,11 @@ static struct pci_device_id ioat_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD2) },
{ PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BWD3) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDXDE0) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDXDE1) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDXDE2) },
+ { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_IOAT_BDXDE3) },
+
{ 0, }
};
MODULE_DEVICE_TABLE(pci, ioat_pci_tbl);
diff --git a/drivers/dma/ipu/ipu_idmac.c b/drivers/dma/ipu/ipu_idmac.c
index c2b017ad139d..b54f62de9232 100644
--- a/drivers/dma/ipu/ipu_idmac.c
+++ b/drivers/dma/ipu/ipu_idmac.c
@@ -1398,76 +1398,81 @@ static void idmac_issue_pending(struct dma_chan *chan)
*/
}
-static int __idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int idmac_pause(struct dma_chan *chan)
{
struct idmac_channel *ichan = to_idmac_chan(chan);
struct idmac *idmac = to_idmac(chan->device);
struct ipu *ipu = to_ipu(idmac);
struct list_head *list, *tmp;
unsigned long flags;
- int i;
- switch (cmd) {
- case DMA_PAUSE:
- spin_lock_irqsave(&ipu->lock, flags);
- ipu_ic_disable_task(ipu, chan->chan_id);
+ mutex_lock(&ichan->chan_mutex);
- /* Return all descriptors into "prepared" state */
- list_for_each_safe(list, tmp, &ichan->queue)
- list_del_init(list);
+ spin_lock_irqsave(&ipu->lock, flags);
+ ipu_ic_disable_task(ipu, chan->chan_id);
- ichan->sg[0] = NULL;
- ichan->sg[1] = NULL;
+ /* Return all descriptors into "prepared" state */
+ list_for_each_safe(list, tmp, &ichan->queue)
+ list_del_init(list);
- spin_unlock_irqrestore(&ipu->lock, flags);
+ ichan->sg[0] = NULL;
+ ichan->sg[1] = NULL;
- ichan->status = IPU_CHANNEL_INITIALIZED;
- break;
- case DMA_TERMINATE_ALL:
- ipu_disable_channel(idmac, ichan,
- ichan->status >= IPU_CHANNEL_ENABLED);
+ spin_unlock_irqrestore(&ipu->lock, flags);
- tasklet_disable(&ipu->tasklet);
+ ichan->status = IPU_CHANNEL_INITIALIZED;
- /* ichan->queue is modified in ISR, have to spinlock */
- spin_lock_irqsave(&ichan->lock, flags);
- list_splice_init(&ichan->queue, &ichan->free_list);
+ mutex_unlock(&ichan->chan_mutex);
- if (ichan->desc)
- for (i = 0; i < ichan->n_tx_desc; i++) {
- struct idmac_tx_desc *desc = ichan->desc + i;
- if (list_empty(&desc->list))
- /* Descriptor was prepared, but not submitted */
- list_add(&desc->list, &ichan->free_list);
+ return 0;
+}
- async_tx_clear_ack(&desc->txd);
- }
+static int __idmac_terminate_all(struct dma_chan *chan)
+{
+ struct idmac_channel *ichan = to_idmac_chan(chan);
+ struct idmac *idmac = to_idmac(chan->device);
+ struct ipu *ipu = to_ipu(idmac);
+ unsigned long flags;
+ int i;
- ichan->sg[0] = NULL;
- ichan->sg[1] = NULL;
- spin_unlock_irqrestore(&ichan->lock, flags);
+ ipu_disable_channel(idmac, ichan,
+ ichan->status >= IPU_CHANNEL_ENABLED);
- tasklet_enable(&ipu->tasklet);
+ tasklet_disable(&ipu->tasklet);
- ichan->status = IPU_CHANNEL_INITIALIZED;
- break;
- default:
- return -ENOSYS;
- }
+ /* ichan->queue is modified in ISR, have to spinlock */
+ spin_lock_irqsave(&ichan->lock, flags);
+ list_splice_init(&ichan->queue, &ichan->free_list);
+
+ if (ichan->desc)
+ for (i = 0; i < ichan->n_tx_desc; i++) {
+ struct idmac_tx_desc *desc = ichan->desc + i;
+ if (list_empty(&desc->list))
+ /* Descriptor was prepared, but not submitted */
+ list_add(&desc->list, &ichan->free_list);
+
+ async_tx_clear_ack(&desc->txd);
+ }
+
+ ichan->sg[0] = NULL;
+ ichan->sg[1] = NULL;
+ spin_unlock_irqrestore(&ichan->lock, flags);
+
+ tasklet_enable(&ipu->tasklet);
+
+ ichan->status = IPU_CHANNEL_INITIALIZED;
return 0;
}
-static int idmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int idmac_terminate_all(struct dma_chan *chan)
{
struct idmac_channel *ichan = to_idmac_chan(chan);
int ret;
mutex_lock(&ichan->chan_mutex);
- ret = __idmac_control(chan, cmd, arg);
+ ret = __idmac_terminate_all(chan);
mutex_unlock(&ichan->chan_mutex);
@@ -1568,7 +1573,7 @@ static void idmac_free_chan_resources(struct dma_chan *chan)
mutex_lock(&ichan->chan_mutex);
- __idmac_control(chan, DMA_TERMINATE_ALL, 0);
+ __idmac_terminate_all(chan);
if (ichan->status > IPU_CHANNEL_FREE) {
#ifdef DEBUG
@@ -1622,7 +1627,8 @@ static int __init ipu_idmac_init(struct ipu *ipu)
/* Compulsory for DMA_SLAVE fields */
dma->device_prep_slave_sg = idmac_prep_slave_sg;
- dma->device_control = idmac_control;
+ dma->device_pause = idmac_pause;
+ dma->device_terminate_all = idmac_terminate_all;
INIT_LIST_HEAD(&dma->channels);
for (i = 0; i < IPU_CHANNELS_NUM; i++) {
@@ -1655,7 +1661,7 @@ static void ipu_idmac_exit(struct ipu *ipu)
for (i = 0; i < IPU_CHANNELS_NUM; i++) {
struct idmac_channel *ichan = ipu->channel + i;
- idmac_control(&ichan->dma_chan, DMA_TERMINATE_ALL, 0);
+ idmac_terminate_all(&ichan->dma_chan);
}
dma_async_device_unregister(&idmac->dma);
diff --git a/drivers/dma/k3dma.c b/drivers/dma/k3dma.c
index a1de14ab2c51..6f7f43529ccb 100644
--- a/drivers/dma/k3dma.c
+++ b/drivers/dma/k3dma.c
@@ -441,7 +441,7 @@ static struct dma_async_tx_descriptor *k3_dma_prep_memcpy(
num = 0;
if (!c->ccfg) {
- /* default is memtomem, without calling device_control */
+ /* default is memtomem, without calling device_config */
c->ccfg = CX_CFG_SRCINCR | CX_CFG_DSTINCR | CX_CFG_EN;
c->ccfg |= (0xf << 20) | (0xf << 24); /* burst = 16 */
c->ccfg |= (0x3 << 12) | (0x3 << 16); /* width = 64 bit */
@@ -523,112 +523,126 @@ static struct dma_async_tx_descriptor *k3_dma_prep_slave_sg(
return vchan_tx_prep(&c->vc, &ds->vd, flags);
}
-static int k3_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int k3_dma_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ u32 maxburst = 0, val = 0;
+ enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
+
+ if (cfg == NULL)
+ return -EINVAL;
+ c->dir = cfg->direction;
+ if (c->dir == DMA_DEV_TO_MEM) {
+ c->ccfg = CX_CFG_DSTINCR;
+ c->dev_addr = cfg->src_addr;
+ maxburst = cfg->src_maxburst;
+ width = cfg->src_addr_width;
+ } else if (c->dir == DMA_MEM_TO_DEV) {
+ c->ccfg = CX_CFG_SRCINCR;
+ c->dev_addr = cfg->dst_addr;
+ maxburst = cfg->dst_maxburst;
+ width = cfg->dst_addr_width;
+ }
+ switch (width) {
+ case DMA_SLAVE_BUSWIDTH_1_BYTE:
+ case DMA_SLAVE_BUSWIDTH_2_BYTES:
+ case DMA_SLAVE_BUSWIDTH_4_BYTES:
+ case DMA_SLAVE_BUSWIDTH_8_BYTES:
+ val = __ffs(width);
+ break;
+ default:
+ val = 3;
+ break;
+ }
+ c->ccfg |= (val << 12) | (val << 16);
+
+ if ((maxburst == 0) || (maxburst > 16))
+ val = 16;
+ else
+ val = maxburst - 1;
+ c->ccfg |= (val << 20) | (val << 24);
+ c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;
+
+ /* specific request line */
+ c->ccfg |= c->vc.chan.chan_id << 4;
+
+ return 0;
+}
+
+static int k3_dma_terminate_all(struct dma_chan *chan)
{
struct k3_dma_chan *c = to_k3_chan(chan);
struct k3_dma_dev *d = to_k3_dma(chan->device);
- struct dma_slave_config *cfg = (void *)arg;
struct k3_dma_phy *p = c->phy;
unsigned long flags;
- u32 maxburst = 0, val = 0;
- enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
LIST_HEAD(head);
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- if (cfg == NULL)
- return -EINVAL;
- c->dir = cfg->direction;
- if (c->dir == DMA_DEV_TO_MEM) {
- c->ccfg = CX_CFG_DSTINCR;
- c->dev_addr = cfg->src_addr;
- maxburst = cfg->src_maxburst;
- width = cfg->src_addr_width;
- } else if (c->dir == DMA_MEM_TO_DEV) {
- c->ccfg = CX_CFG_SRCINCR;
- c->dev_addr = cfg->dst_addr;
- maxburst = cfg->dst_maxburst;
- width = cfg->dst_addr_width;
- }
- switch (width) {
- case DMA_SLAVE_BUSWIDTH_1_BYTE:
- case DMA_SLAVE_BUSWIDTH_2_BYTES:
- case DMA_SLAVE_BUSWIDTH_4_BYTES:
- case DMA_SLAVE_BUSWIDTH_8_BYTES:
- val = __ffs(width);
- break;
- default:
- val = 3;
- break;
- }
- c->ccfg |= (val << 12) | (val << 16);
+ dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
- if ((maxburst == 0) || (maxburst > 16))
- val = 16;
- else
- val = maxburst - 1;
- c->ccfg |= (val << 20) | (val << 24);
- c->ccfg |= CX_CFG_MEM2PER | CX_CFG_EN;
+ /* Prevent this channel being scheduled */
+ spin_lock(&d->lock);
+ list_del_init(&c->node);
+ spin_unlock(&d->lock);
- /* specific request line */
- c->ccfg |= c->vc.chan.chan_id << 4;
- break;
+ /* Clear the tx descriptor lists */
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vchan_get_all_descriptors(&c->vc, &head);
+ if (p) {
+ /* vchan is assigned to a pchan - stop the channel */
+ k3_dma_terminate_chan(p, d);
+ c->phy = NULL;
+ p->vchan = NULL;
+ p->ds_run = p->ds_done = NULL;
+ }
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ vchan_dma_desc_free_list(&c->vc, &head);
- case DMA_TERMINATE_ALL:
- dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
+ return 0;
+}
- /* Prevent this channel being scheduled */
- spin_lock(&d->lock);
- list_del_init(&c->node);
- spin_unlock(&d->lock);
+static int k3_dma_transfer_pause(struct dma_chan *chan)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ struct k3_dma_phy *p = c->phy;
- /* Clear the tx descriptor lists */
- spin_lock_irqsave(&c->vc.lock, flags);
- vchan_get_all_descriptors(&c->vc, &head);
+ dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
+ if (c->status == DMA_IN_PROGRESS) {
+ c->status = DMA_PAUSED;
if (p) {
- /* vchan is assigned to a pchan - stop the channel */
- k3_dma_terminate_chan(p, d);
- c->phy = NULL;
- p->vchan = NULL;
- p->ds_run = p->ds_done = NULL;
+ k3_dma_pause_dma(p, false);
+ } else {
+ spin_lock(&d->lock);
+ list_del_init(&c->node);
+ spin_unlock(&d->lock);
}
- spin_unlock_irqrestore(&c->vc.lock, flags);
- vchan_dma_desc_free_list(&c->vc, &head);
- break;
+ }
- case DMA_PAUSE:
- dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
- if (c->status == DMA_IN_PROGRESS) {
- c->status = DMA_PAUSED;
- if (p) {
- k3_dma_pause_dma(p, false);
- } else {
- spin_lock(&d->lock);
- list_del_init(&c->node);
- spin_unlock(&d->lock);
- }
- }
- break;
+ return 0;
+}
- case DMA_RESUME:
- dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
- spin_lock_irqsave(&c->vc.lock, flags);
- if (c->status == DMA_PAUSED) {
- c->status = DMA_IN_PROGRESS;
- if (p) {
- k3_dma_pause_dma(p, true);
- } else if (!list_empty(&c->vc.desc_issued)) {
- spin_lock(&d->lock);
- list_add_tail(&c->node, &d->chan_pending);
- spin_unlock(&d->lock);
- }
+static int k3_dma_transfer_resume(struct dma_chan *chan)
+{
+ struct k3_dma_chan *c = to_k3_chan(chan);
+ struct k3_dma_dev *d = to_k3_dma(chan->device);
+ struct k3_dma_phy *p = c->phy;
+ unsigned long flags;
+
+ dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (c->status == DMA_PAUSED) {
+ c->status = DMA_IN_PROGRESS;
+ if (p) {
+ k3_dma_pause_dma(p, true);
+ } else if (!list_empty(&c->vc.desc_issued)) {
+ spin_lock(&d->lock);
+ list_add_tail(&c->node, &d->chan_pending);
+ spin_unlock(&d->lock);
}
- spin_unlock_irqrestore(&c->vc.lock, flags);
- break;
- default:
- return -ENXIO;
}
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+
return 0;
}
@@ -720,7 +734,10 @@ static int k3_dma_probe(struct platform_device *op)
d->slave.device_prep_dma_memcpy = k3_dma_prep_memcpy;
d->slave.device_prep_slave_sg = k3_dma_prep_slave_sg;
d->slave.device_issue_pending = k3_dma_issue_pending;
- d->slave.device_control = k3_dma_control;
+ d->slave.device_config = k3_dma_config;
+ d->slave.device_pause = k3_dma_transfer_pause;
+ d->slave.device_resume = k3_dma_transfer_resume;
+ d->slave.device_terminate_all = k3_dma_terminate_all;
d->slave.copy_align = DMA_ALIGN;
/* init virtual channel */
@@ -787,7 +804,7 @@ static int k3_dma_remove(struct platform_device *op)
}
#ifdef CONFIG_PM_SLEEP
-static int k3_dma_suspend(struct device *dev)
+static int k3_dma_suspend_dev(struct device *dev)
{
struct k3_dma_dev *d = dev_get_drvdata(dev);
u32 stat = 0;
@@ -803,7 +820,7 @@ static int k3_dma_suspend(struct device *dev)
return 0;
}
-static int k3_dma_resume(struct device *dev)
+static int k3_dma_resume_dev(struct device *dev)
{
struct k3_dma_dev *d = dev_get_drvdata(dev);
int ret = 0;
@@ -818,7 +835,7 @@ static int k3_dma_resume(struct device *dev)
}
#endif
-static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend, k3_dma_resume);
+static SIMPLE_DEV_PM_OPS(k3_dma_pmops, k3_dma_suspend_dev, k3_dma_resume_dev);
static struct platform_driver k3_pdma_driver = {
.driver = {
diff --git a/drivers/dma/mmp_pdma.c b/drivers/dma/mmp_pdma.c
index 8b8952f35e6c..8926f271904e 100644
--- a/drivers/dma/mmp_pdma.c
+++ b/drivers/dma/mmp_pdma.c
@@ -683,68 +683,70 @@ fail:
return NULL;
}
-static int mmp_pdma_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int mmp_pdma_config(struct dma_chan *dchan,
+ struct dma_slave_config *cfg)
{
struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
- struct dma_slave_config *cfg = (void *)arg;
- unsigned long flags;
u32 maxburst = 0, addr = 0;
enum dma_slave_buswidth width = DMA_SLAVE_BUSWIDTH_UNDEFINED;
if (!dchan)
return -EINVAL;
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- disable_chan(chan->phy);
- mmp_pdma_free_phy(chan);
- spin_lock_irqsave(&chan->desc_lock, flags);
- mmp_pdma_free_desc_list(chan, &chan->chain_pending);
- mmp_pdma_free_desc_list(chan, &chan->chain_running);
- spin_unlock_irqrestore(&chan->desc_lock, flags);
- chan->idle = true;
- break;
- case DMA_SLAVE_CONFIG:
- if (cfg->direction == DMA_DEV_TO_MEM) {
- chan->dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
- maxburst = cfg->src_maxburst;
- width = cfg->src_addr_width;
- addr = cfg->src_addr;
- } else if (cfg->direction == DMA_MEM_TO_DEV) {
- chan->dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
- maxburst = cfg->dst_maxburst;
- width = cfg->dst_addr_width;
- addr = cfg->dst_addr;
- }
-
- if (width == DMA_SLAVE_BUSWIDTH_1_BYTE)
- chan->dcmd |= DCMD_WIDTH1;
- else if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
- chan->dcmd |= DCMD_WIDTH2;
- else if (width == DMA_SLAVE_BUSWIDTH_4_BYTES)
- chan->dcmd |= DCMD_WIDTH4;
-
- if (maxburst == 8)
- chan->dcmd |= DCMD_BURST8;
- else if (maxburst == 16)
- chan->dcmd |= DCMD_BURST16;
- else if (maxburst == 32)
- chan->dcmd |= DCMD_BURST32;
-
- chan->dir = cfg->direction;
- chan->dev_addr = addr;
- /* FIXME: drivers should be ported over to use the filter
- * function. Once that's done, the following two lines can
- * be removed.
- */
- if (cfg->slave_id)
- chan->drcmr = cfg->slave_id;
- break;
- default:
- return -ENOSYS;
+ if (cfg->direction == DMA_DEV_TO_MEM) {
+ chan->dcmd = DCMD_INCTRGADDR | DCMD_FLOWSRC;
+ maxburst = cfg->src_maxburst;
+ width = cfg->src_addr_width;
+ addr = cfg->src_addr;
+ } else if (cfg->direction == DMA_MEM_TO_DEV) {
+ chan->dcmd = DCMD_INCSRCADDR | DCMD_FLOWTRG;
+ maxburst = cfg->dst_maxburst;
+ width = cfg->dst_addr_width;
+ addr = cfg->dst_addr;
}
+ if (width == DMA_SLAVE_BUSWIDTH_1_BYTE)
+ chan->dcmd |= DCMD_WIDTH1;
+ else if (width == DMA_SLAVE_BUSWIDTH_2_BYTES)
+ chan->dcmd |= DCMD_WIDTH2;
+ else if (width == DMA_SLAVE_BUSWIDTH_4_BYTES)
+ chan->dcmd |= DCMD_WIDTH4;
+
+ if (maxburst == 8)
+ chan->dcmd |= DCMD_BURST8;
+ else if (maxburst == 16)
+ chan->dcmd |= DCMD_BURST16;
+ else if (maxburst == 32)
+ chan->dcmd |= DCMD_BURST32;
+
+ chan->dir = cfg->direction;
+ chan->dev_addr = addr;
+ /* FIXME: drivers should be ported over to use the filter
+ * function. Once that's done, the following two lines can
+ * be removed.
+ */
+ if (cfg->slave_id)
+ chan->drcmr = cfg->slave_id;
+
+ return 0;
+}
+
+static int mmp_pdma_terminate_all(struct dma_chan *dchan)
+{
+ struct mmp_pdma_chan *chan = to_mmp_pdma_chan(dchan);
+ unsigned long flags;
+
+ if (!dchan)
+ return -EINVAL;
+
+ disable_chan(chan->phy);
+ mmp_pdma_free_phy(chan);
+ spin_lock_irqsave(&chan->desc_lock, flags);
+ mmp_pdma_free_desc_list(chan, &chan->chain_pending);
+ mmp_pdma_free_desc_list(chan, &chan->chain_running);
+ spin_unlock_irqrestore(&chan->desc_lock, flags);
+ chan->idle = true;
+
return 0;
}
@@ -1061,7 +1063,8 @@ static int mmp_pdma_probe(struct platform_device *op)
pdev->device.device_prep_slave_sg = mmp_pdma_prep_slave_sg;
pdev->device.device_prep_dma_cyclic = mmp_pdma_prep_dma_cyclic;
pdev->device.device_issue_pending = mmp_pdma_issue_pending;
- pdev->device.device_control = mmp_pdma_control;
+ pdev->device.device_config = mmp_pdma_config;
+ pdev->device.device_terminate_all = mmp_pdma_terminate_all;
pdev->device.copy_align = PDMA_ALIGNMENT;
if (pdev->dev->coherent_dma_mask)
diff --git a/drivers/dma/mmp_tdma.c b/drivers/dma/mmp_tdma.c
index bfb46957c3dc..70c2fa9963cd 100644
--- a/drivers/dma/mmp_tdma.c
+++ b/drivers/dma/mmp_tdma.c
@@ -19,7 +19,6 @@
#include <linux/dmaengine.h>
#include <linux/platform_device.h>
#include <linux/device.h>
-#include <mach/regs-icu.h>
#include <linux/platform_data/dma-mmp_tdma.h>
#include <linux/of_device.h>
#include <linux/of_dma.h>
@@ -164,33 +163,46 @@ static void mmp_tdma_enable_chan(struct mmp_tdma_chan *tdmac)
tdmac->status = DMA_IN_PROGRESS;
}
-static void mmp_tdma_disable_chan(struct mmp_tdma_chan *tdmac)
+static int mmp_tdma_disable_chan(struct dma_chan *chan)
{
+ struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
tdmac->reg_base + TDCR);
tdmac->status = DMA_COMPLETE;
+
+ return 0;
}
-static void mmp_tdma_resume_chan(struct mmp_tdma_chan *tdmac)
+static int mmp_tdma_resume_chan(struct dma_chan *chan)
{
+ struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
writel(readl(tdmac->reg_base + TDCR) | TDCR_CHANEN,
tdmac->reg_base + TDCR);
tdmac->status = DMA_IN_PROGRESS;
+
+ return 0;
}
-static void mmp_tdma_pause_chan(struct mmp_tdma_chan *tdmac)
+static int mmp_tdma_pause_chan(struct dma_chan *chan)
{
+ struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
writel(readl(tdmac->reg_base + TDCR) & ~TDCR_CHANEN,
tdmac->reg_base + TDCR);
tdmac->status = DMA_PAUSED;
+
+ return 0;
}
-static int mmp_tdma_config_chan(struct mmp_tdma_chan *tdmac)
+static int mmp_tdma_config_chan(struct dma_chan *chan)
{
+ struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
unsigned int tdcr = 0;
- mmp_tdma_disable_chan(tdmac);
+ mmp_tdma_disable_chan(chan);
if (tdmac->dir == DMA_MEM_TO_DEV)
tdcr = TDCR_DSTDIR_ADDR_HOLD | TDCR_SRCDIR_ADDR_INC;
@@ -452,42 +464,34 @@ err_out:
return NULL;
}
-static int mmp_tdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int mmp_tdma_terminate_all(struct dma_chan *chan)
{
struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
- struct dma_slave_config *dmaengine_cfg = (void *)arg;
- int ret = 0;
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- mmp_tdma_disable_chan(tdmac);
- /* disable interrupt */
- mmp_tdma_enable_irq(tdmac, false);
- break;
- case DMA_PAUSE:
- mmp_tdma_pause_chan(tdmac);
- break;
- case DMA_RESUME:
- mmp_tdma_resume_chan(tdmac);
- break;
- case DMA_SLAVE_CONFIG:
- if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
- tdmac->dev_addr = dmaengine_cfg->src_addr;
- tdmac->burst_sz = dmaengine_cfg->src_maxburst;
- tdmac->buswidth = dmaengine_cfg->src_addr_width;
- } else {
- tdmac->dev_addr = dmaengine_cfg->dst_addr;
- tdmac->burst_sz = dmaengine_cfg->dst_maxburst;
- tdmac->buswidth = dmaengine_cfg->dst_addr_width;
- }
- tdmac->dir = dmaengine_cfg->direction;
- return mmp_tdma_config_chan(tdmac);
- default:
- ret = -ENOSYS;
+
+ mmp_tdma_disable_chan(chan);
+ /* disable interrupt */
+ mmp_tdma_enable_irq(tdmac, false);
+
+ return 0;
+}
+
+static int mmp_tdma_config(struct dma_chan *chan,
+ struct dma_slave_config *dmaengine_cfg)
+{
+ struct mmp_tdma_chan *tdmac = to_mmp_tdma_chan(chan);
+
+ if (dmaengine_cfg->direction == DMA_DEV_TO_MEM) {
+ tdmac->dev_addr = dmaengine_cfg->src_addr;
+ tdmac->burst_sz = dmaengine_cfg->src_maxburst;
+ tdmac->buswidth = dmaengine_cfg->src_addr_width;
+ } else {
+ tdmac->dev_addr = dmaengine_cfg->dst_addr;
+ tdmac->burst_sz = dmaengine_cfg->dst_maxburst;
+ tdmac->buswidth = dmaengine_cfg->dst_addr_width;
}
+ tdmac->dir = dmaengine_cfg->direction;
- return ret;
+ return mmp_tdma_config_chan(chan);
}
static enum dma_status mmp_tdma_tx_status(struct dma_chan *chan,
@@ -668,7 +672,10 @@ static int mmp_tdma_probe(struct platform_device *pdev)
tdev->device.device_prep_dma_cyclic = mmp_tdma_prep_dma_cyclic;
tdev->device.device_tx_status = mmp_tdma_tx_status;
tdev->device.device_issue_pending = mmp_tdma_issue_pending;
- tdev->device.device_control = mmp_tdma_control;
+ tdev->device.device_config = mmp_tdma_config;
+ tdev->device.device_pause = mmp_tdma_pause_chan;
+ tdev->device.device_resume = mmp_tdma_resume_chan;
+ tdev->device.device_terminate_all = mmp_tdma_terminate_all;
tdev->device.copy_align = TDMA_ALIGNMENT;
dma_set_mask(&pdev->dev, DMA_BIT_MASK(64));
diff --git a/drivers/dma/moxart-dma.c b/drivers/dma/moxart-dma.c
index 53032bac06e0..15cab7d79525 100644
--- a/drivers/dma/moxart-dma.c
+++ b/drivers/dma/moxart-dma.c
@@ -263,28 +263,6 @@ static int moxart_slave_config(struct dma_chan *chan,
return 0;
}
-static int moxart_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- int ret = 0;
-
- switch (cmd) {
- case DMA_PAUSE:
- case DMA_RESUME:
- return -EINVAL;
- case DMA_TERMINATE_ALL:
- moxart_terminate_all(chan);
- break;
- case DMA_SLAVE_CONFIG:
- ret = moxart_slave_config(chan, (struct dma_slave_config *)arg);
- break;
- default:
- ret = -ENOSYS;
- }
-
- return ret;
-}
-
static struct dma_async_tx_descriptor *moxart_prep_slave_sg(
struct dma_chan *chan, struct scatterlist *sgl,
unsigned int sg_len, enum dma_transfer_direction dir,
@@ -531,7 +509,8 @@ static void moxart_dma_init(struct dma_device *dma, struct device *dev)
dma->device_free_chan_resources = moxart_free_chan_resources;
dma->device_issue_pending = moxart_issue_pending;
dma->device_tx_status = moxart_tx_status;
- dma->device_control = moxart_control;
+ dma->device_config = moxart_slave_config;
+ dma->device_terminate_all = moxart_terminate_all;
dma->dev = dev;
INIT_LIST_HEAD(&dma->channels);
diff --git a/drivers/dma/mpc512x_dma.c b/drivers/dma/mpc512x_dma.c
index 01bec4023de2..57d2457545f3 100644
--- a/drivers/dma/mpc512x_dma.c
+++ b/drivers/dma/mpc512x_dma.c
@@ -800,79 +800,69 @@ err_prep:
return NULL;
}
-static int mpc_dma_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int mpc_dma_device_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
{
- struct mpc_dma_chan *mchan;
- struct mpc_dma *mdma;
- struct dma_slave_config *cfg;
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
unsigned long flags;
- mchan = dma_chan_to_mpc_dma_chan(chan);
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- /* Disable channel requests */
- mdma = dma_chan_to_mpc_dma(chan);
-
- spin_lock_irqsave(&mchan->lock, flags);
-
- out_8(&mdma->regs->dmacerq, chan->chan_id);
- list_splice_tail_init(&mchan->prepared, &mchan->free);
- list_splice_tail_init(&mchan->queued, &mchan->free);
- list_splice_tail_init(&mchan->active, &mchan->free);
-
- spin_unlock_irqrestore(&mchan->lock, flags);
+ /*
+ * Software constraints:
+ * - only transfers between a peripheral device and
+ * memory are supported;
+ * - only peripheral devices with 4-byte FIFO access register
+ * are supported;
+ * - minimal transfer chunk is 4 bytes and consequently
+ * source and destination addresses must be 4-byte aligned
+ * and transfer size must be aligned on (4 * maxburst)
+ * boundary;
+ * - during the transfer RAM address is being incremented by
+ * the size of minimal transfer chunk;
+ * - peripheral port's address is constant during the transfer.
+ */
- return 0;
+ if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
+ cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
+ !IS_ALIGNED(cfg->src_addr, 4) ||
+ !IS_ALIGNED(cfg->dst_addr, 4)) {
+ return -EINVAL;
+ }
- case DMA_SLAVE_CONFIG:
- /*
- * Software constraints:
- * - only transfers between a peripheral device and
- * memory are supported;
- * - only peripheral devices with 4-byte FIFO access register
- * are supported;
- * - minimal transfer chunk is 4 bytes and consequently
- * source and destination addresses must be 4-byte aligned
- * and transfer size must be aligned on (4 * maxburst)
- * boundary;
- * - during the transfer RAM address is being incremented by
- * the size of minimal transfer chunk;
- * - peripheral port's address is constant during the transfer.
- */
+ spin_lock_irqsave(&mchan->lock, flags);
- cfg = (void *)arg;
+ mchan->src_per_paddr = cfg->src_addr;
+ mchan->src_tcd_nunits = cfg->src_maxburst;
+ mchan->dst_per_paddr = cfg->dst_addr;
+ mchan->dst_tcd_nunits = cfg->dst_maxburst;
- if (cfg->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
- cfg->dst_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES ||
- !IS_ALIGNED(cfg->src_addr, 4) ||
- !IS_ALIGNED(cfg->dst_addr, 4)) {
- return -EINVAL;
- }
+ /* Apply defaults */
+ if (mchan->src_tcd_nunits == 0)
+ mchan->src_tcd_nunits = 1;
+ if (mchan->dst_tcd_nunits == 0)
+ mchan->dst_tcd_nunits = 1;
- spin_lock_irqsave(&mchan->lock, flags);
+ spin_unlock_irqrestore(&mchan->lock, flags);
- mchan->src_per_paddr = cfg->src_addr;
- mchan->src_tcd_nunits = cfg->src_maxburst;
- mchan->dst_per_paddr = cfg->dst_addr;
- mchan->dst_tcd_nunits = cfg->dst_maxburst;
+ return 0;
+}
- /* Apply defaults */
- if (mchan->src_tcd_nunits == 0)
- mchan->src_tcd_nunits = 1;
- if (mchan->dst_tcd_nunits == 0)
- mchan->dst_tcd_nunits = 1;
+static int mpc_dma_device_terminate_all(struct dma_chan *chan)
+{
+ struct mpc_dma_chan *mchan = dma_chan_to_mpc_dma_chan(chan);
+ struct mpc_dma *mdma = dma_chan_to_mpc_dma(chan);
+ unsigned long flags;
- spin_unlock_irqrestore(&mchan->lock, flags);
+ /* Disable channel requests */
+ spin_lock_irqsave(&mchan->lock, flags);
- return 0;
+ out_8(&mdma->regs->dmacerq, chan->chan_id);
+ list_splice_tail_init(&mchan->prepared, &mchan->free);
+ list_splice_tail_init(&mchan->queued, &mchan->free);
+ list_splice_tail_init(&mchan->active, &mchan->free);
- default:
- /* Unknown command */
- break;
- }
+ spin_unlock_irqrestore(&mchan->lock, flags);
- return -ENXIO;
+ return 0;
}
static int mpc_dma_probe(struct platform_device *op)
@@ -963,7 +953,8 @@ static int mpc_dma_probe(struct platform_device *op)
dma->device_tx_status = mpc_dma_tx_status;
dma->device_prep_dma_memcpy = mpc_dma_prep_memcpy;
dma->device_prep_slave_sg = mpc_dma_prep_slave_sg;
- dma->device_control = mpc_dma_device_control;
+ dma->device_config = mpc_dma_device_config;
+ dma->device_terminate_all = mpc_dma_device_terminate_all;
INIT_LIST_HEAD(&dma->channels);
dma_cap_set(DMA_MEMCPY, dma->cap_mask);
diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index d7ac558c2c1c..b03e8137b918 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -928,14 +928,6 @@ out:
return err;
}
-/* This driver does not implement any of the optional DMA operations. */
-static int
-mv_xor_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- return -ENOSYS;
-}
-
static int mv_xor_channel_remove(struct mv_xor_chan *mv_chan)
{
struct dma_chan *chan, *_chan;
@@ -1008,7 +1000,6 @@ mv_xor_channel_add(struct mv_xor_device *xordev,
dma_dev->device_free_chan_resources = mv_xor_free_chan_resources;
dma_dev->device_tx_status = mv_xor_status;
dma_dev->device_issue_pending = mv_xor_issue_pending;
- dma_dev->device_control = mv_xor_control;
dma_dev->dev = &pdev->dev;
/* set prep routines based on capability */
diff --git a/drivers/dma/mxs-dma.c b/drivers/dma/mxs-dma.c
index 5ea61201dbf0..829ec686dac3 100644
--- a/drivers/dma/mxs-dma.c
+++ b/drivers/dma/mxs-dma.c
@@ -202,8 +202,9 @@ static struct mxs_dma_chan *to_mxs_dma_chan(struct dma_chan *chan)
return container_of(chan, struct mxs_dma_chan, chan);
}
-static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
+static void mxs_dma_reset_chan(struct dma_chan *chan)
{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int chan_id = mxs_chan->chan.chan_id;
@@ -250,8 +251,9 @@ static void mxs_dma_reset_chan(struct mxs_dma_chan *mxs_chan)
mxs_chan->status = DMA_COMPLETE;
}
-static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
+static void mxs_dma_enable_chan(struct dma_chan *chan)
{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int chan_id = mxs_chan->chan.chan_id;
@@ -272,13 +274,16 @@ static void mxs_dma_enable_chan(struct mxs_dma_chan *mxs_chan)
mxs_chan->reset = false;
}
-static void mxs_dma_disable_chan(struct mxs_dma_chan *mxs_chan)
+static void mxs_dma_disable_chan(struct dma_chan *chan)
{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
+
mxs_chan->status = DMA_COMPLETE;
}
-static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
+static int mxs_dma_pause_chan(struct dma_chan *chan)
{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int chan_id = mxs_chan->chan.chan_id;
@@ -291,10 +296,12 @@ static void mxs_dma_pause_chan(struct mxs_dma_chan *mxs_chan)
mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_SET);
mxs_chan->status = DMA_PAUSED;
+ return 0;
}
-static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
+static int mxs_dma_resume_chan(struct dma_chan *chan)
{
+ struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
int chan_id = mxs_chan->chan.chan_id;
@@ -307,6 +314,7 @@ static void mxs_dma_resume_chan(struct mxs_dma_chan *mxs_chan)
mxs_dma->base + HW_APBHX_CHANNEL_CTRL + STMP_OFFSET_REG_CLR);
mxs_chan->status = DMA_IN_PROGRESS;
+ return 0;
}
static dma_cookie_t mxs_dma_tx_submit(struct dma_async_tx_descriptor *tx)
@@ -383,7 +391,7 @@ static irqreturn_t mxs_dma_int_handler(int irq, void *dev_id)
"%s: error in channel %d\n", __func__,
chan);
mxs_chan->status = DMA_ERROR;
- mxs_dma_reset_chan(mxs_chan);
+ mxs_dma_reset_chan(&mxs_chan->chan);
} else if (mxs_chan->status != DMA_COMPLETE) {
if (mxs_chan->flags & MXS_DMA_SG_LOOP) {
mxs_chan->status = DMA_IN_PROGRESS;
@@ -432,7 +440,7 @@ static int mxs_dma_alloc_chan_resources(struct dma_chan *chan)
if (ret)
goto err_clk;
- mxs_dma_reset_chan(mxs_chan);
+ mxs_dma_reset_chan(chan);
dma_async_tx_descriptor_init(&mxs_chan->desc, chan);
mxs_chan->desc.tx_submit = mxs_dma_tx_submit;
@@ -456,7 +464,7 @@ static void mxs_dma_free_chan_resources(struct dma_chan *chan)
struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
struct mxs_dma_engine *mxs_dma = mxs_chan->mxs_dma;
- mxs_dma_disable_chan(mxs_chan);
+ mxs_dma_disable_chan(chan);
free_irq(mxs_chan->chan_irq, mxs_dma);
@@ -651,28 +659,12 @@ err_out:
return NULL;
}
-static int mxs_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int mxs_dma_terminate_all(struct dma_chan *chan)
{
- struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
- int ret = 0;
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- mxs_dma_reset_chan(mxs_chan);
- mxs_dma_disable_chan(mxs_chan);
- break;
- case DMA_PAUSE:
- mxs_dma_pause_chan(mxs_chan);
- break;
- case DMA_RESUME:
- mxs_dma_resume_chan(mxs_chan);
- break;
- default:
- ret = -ENOSYS;
- }
+ mxs_dma_reset_chan(chan);
+ mxs_dma_disable_chan(chan);
- return ret;
+ return 0;
}
static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
@@ -701,13 +693,6 @@ static enum dma_status mxs_dma_tx_status(struct dma_chan *chan,
return mxs_chan->status;
}
-static void mxs_dma_issue_pending(struct dma_chan *chan)
-{
- struct mxs_dma_chan *mxs_chan = to_mxs_dma_chan(chan);
-
- mxs_dma_enable_chan(mxs_chan);
-}
-
static int __init mxs_dma_init(struct mxs_dma_engine *mxs_dma)
{
int ret;
@@ -860,8 +845,14 @@ static int __init mxs_dma_probe(struct platform_device *pdev)
mxs_dma->dma_device.device_tx_status = mxs_dma_tx_status;
mxs_dma->dma_device.device_prep_slave_sg = mxs_dma_prep_slave_sg;
mxs_dma->dma_device.device_prep_dma_cyclic = mxs_dma_prep_dma_cyclic;
- mxs_dma->dma_device.device_control = mxs_dma_control;
- mxs_dma->dma_device.device_issue_pending = mxs_dma_issue_pending;
+ mxs_dma->dma_device.device_pause = mxs_dma_pause_chan;
+ mxs_dma->dma_device.device_resume = mxs_dma_resume_chan;
+ mxs_dma->dma_device.device_terminate_all = mxs_dma_terminate_all;
+ mxs_dma->dma_device.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ mxs_dma->dma_device.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ mxs_dma->dma_device.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ mxs_dma->dma_device.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+ mxs_dma->dma_device.device_issue_pending = mxs_dma_enable_chan;
ret = dma_async_device_register(&mxs_dma->dma_device);
if (ret) {
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index d7d61e1a01c3..88b77c98365d 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -504,7 +504,7 @@ static int nbpf_prep_one(struct nbpf_link_desc *ldesc,
* pauses DMA and reads out data received via DMA as well as those left
* in the Rx FIFO. For this to work with the RAM side using burst
* transfers we enable the SBE bit and terminate the transfer in our
- * DMA_PAUSE handler.
+ * .device_pause handler.
*/
mem_xfer = nbpf_xfer_ds(chan->nbpf, size);
@@ -565,13 +565,6 @@ static void nbpf_configure(struct nbpf_device *nbpf)
nbpf_write(nbpf, NBPF_CTRL, NBPF_CTRL_LVINT);
}
-static void nbpf_pause(struct nbpf_channel *chan)
-{
- nbpf_chan_write(chan, NBPF_CHAN_CTRL, NBPF_CHAN_CTRL_SETSUS);
- /* See comment in nbpf_prep_one() */
- nbpf_chan_write(chan, NBPF_CHAN_CTRL, NBPF_CHAN_CTRL_CLREN);
-}
-
/* Generic part */
/* DMA ENGINE functions */
@@ -837,54 +830,58 @@ static void nbpf_chan_idle(struct nbpf_channel *chan)
}
}
-static int nbpf_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int nbpf_pause(struct dma_chan *dchan)
{
struct nbpf_channel *chan = nbpf_to_chan(dchan);
- struct dma_slave_config *config;
- dev_dbg(dchan->device->dev, "Entry %s(%d)\n", __func__, cmd);
+ dev_dbg(dchan->device->dev, "Entry %s\n", __func__);
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- dev_dbg(dchan->device->dev, "Terminating\n");
- nbpf_chan_halt(chan);
- nbpf_chan_idle(chan);
- break;
+ chan->paused = true;
+ nbpf_chan_write(chan, NBPF_CHAN_CTRL, NBPF_CHAN_CTRL_SETSUS);
+ /* See comment in nbpf_prep_one() */
+ nbpf_chan_write(chan, NBPF_CHAN_CTRL, NBPF_CHAN_CTRL_CLREN);
- case DMA_SLAVE_CONFIG:
- if (!arg)
- return -EINVAL;
- config = (struct dma_slave_config *)arg;
+ return 0;
+}
- /*
- * We could check config->slave_id to match chan->terminal here,
- * but with DT they would be coming from the same source, so
- * such a check would be superflous
- */
+static int nbpf_terminate_all(struct dma_chan *dchan)
+{
+ struct nbpf_channel *chan = nbpf_to_chan(dchan);
- chan->slave_dst_addr = config->dst_addr;
- chan->slave_dst_width = nbpf_xfer_size(chan->nbpf,
- config->dst_addr_width, 1);
- chan->slave_dst_burst = nbpf_xfer_size(chan->nbpf,
- config->dst_addr_width,
- config->dst_maxburst);
- chan->slave_src_addr = config->src_addr;
- chan->slave_src_width = nbpf_xfer_size(chan->nbpf,
- config->src_addr_width, 1);
- chan->slave_src_burst = nbpf_xfer_size(chan->nbpf,
- config->src_addr_width,
- config->src_maxburst);
- break;
+ dev_dbg(dchan->device->dev, "Entry %s\n", __func__);
+ dev_dbg(dchan->device->dev, "Terminating\n");
- case DMA_PAUSE:
- chan->paused = true;
- nbpf_pause(chan);
- break;
+ nbpf_chan_halt(chan);
+ nbpf_chan_idle(chan);
- default:
- return -ENXIO;
- }
+ return 0;
+}
+
+static int nbpf_config(struct dma_chan *dchan,
+ struct dma_slave_config *config)
+{
+ struct nbpf_channel *chan = nbpf_to_chan(dchan);
+
+ dev_dbg(dchan->device->dev, "Entry %s\n", __func__);
+
+ /*
+ * We could check config->slave_id to match chan->terminal here,
+ * but with DT they would be coming from the same source, so
+ * such a check would be superflous
+ */
+
+ chan->slave_dst_addr = config->dst_addr;
+ chan->slave_dst_width = nbpf_xfer_size(chan->nbpf,
+ config->dst_addr_width, 1);
+ chan->slave_dst_burst = nbpf_xfer_size(chan->nbpf,
+ config->dst_addr_width,
+ config->dst_maxburst);
+ chan->slave_src_addr = config->src_addr;
+ chan->slave_src_width = nbpf_xfer_size(chan->nbpf,
+ config->src_addr_width, 1);
+ chan->slave_src_burst = nbpf_xfer_size(chan->nbpf,
+ config->src_addr_width,
+ config->src_maxburst);
return 0;
}
@@ -1072,18 +1069,6 @@ static void nbpf_free_chan_resources(struct dma_chan *dchan)
}
}
-static int nbpf_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = NBPF_DMA_BUSWIDTHS;
- caps->dstn_addr_widths = NBPF_DMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = false;
- caps->cmd_terminate = true;
-
- return 0;
-}
-
static struct dma_chan *nbpf_of_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
@@ -1414,7 +1399,6 @@ static int nbpf_probe(struct platform_device *pdev)
dma_dev->device_prep_dma_memcpy = nbpf_prep_memcpy;
dma_dev->device_tx_status = nbpf_tx_status;
dma_dev->device_issue_pending = nbpf_issue_pending;
- dma_dev->device_slave_caps = nbpf_slave_caps;
/*
* If we drop support for unaligned MEMCPY buffer addresses and / or
@@ -1426,7 +1410,13 @@ static int nbpf_probe(struct platform_device *pdev)
/* Compulsory for DMA_SLAVE fields */
dma_dev->device_prep_slave_sg = nbpf_prep_slave_sg;
- dma_dev->device_control = nbpf_control;
+ dma_dev->device_config = nbpf_config;
+ dma_dev->device_pause = nbpf_pause;
+ dma_dev->device_terminate_all = nbpf_terminate_all;
+
+ dma_dev->src_addr_widths = NBPF_DMA_BUSWIDTHS;
+ dma_dev->dst_addr_widths = NBPF_DMA_BUSWIDTHS;
+ dma_dev->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
platform_set_drvdata(pdev, nbpf);
diff --git a/drivers/dma/of-dma.c b/drivers/dma/of-dma.c
index d5fbeaa1e7ba..ca31f1b45366 100644
--- a/drivers/dma/of-dma.c
+++ b/drivers/dma/of-dma.c
@@ -159,6 +159,10 @@ struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
return ERR_PTR(-ENODEV);
}
+ /* Silently fail if there is not even the "dmas" property */
+ if (!of_find_property(np, "dmas", NULL))
+ return ERR_PTR(-ENODEV);
+
count = of_property_count_strings(np, "dma-names");
if (count < 0) {
pr_err("%s: dma-names property of node '%s' missing or empty\n",
diff --git a/drivers/dma/omap-dma.c b/drivers/dma/omap-dma.c
index c0016a68b446..7dd6dd121681 100644
--- a/drivers/dma/omap-dma.c
+++ b/drivers/dma/omap-dma.c
@@ -948,8 +948,10 @@ static struct dma_async_tx_descriptor *omap_dma_prep_dma_cyclic(
return vchan_tx_prep(&c->vc, &d->vd, flags);
}
-static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *cfg)
+static int omap_dma_slave_config(struct dma_chan *chan, struct dma_slave_config *cfg)
{
+ struct omap_chan *c = to_omap_dma_chan(chan);
+
if (cfg->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
cfg->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
return -EINVAL;
@@ -959,8 +961,9 @@ static int omap_dma_slave_config(struct omap_chan *c, struct dma_slave_config *c
return 0;
}
-static int omap_dma_terminate_all(struct omap_chan *c)
+static int omap_dma_terminate_all(struct dma_chan *chan)
{
+ struct omap_chan *c = to_omap_dma_chan(chan);
struct omap_dmadev *d = to_omap_dma_dev(c->vc.chan.device);
unsigned long flags;
LIST_HEAD(head);
@@ -996,8 +999,10 @@ static int omap_dma_terminate_all(struct omap_chan *c)
return 0;
}
-static int omap_dma_pause(struct omap_chan *c)
+static int omap_dma_pause(struct dma_chan *chan)
{
+ struct omap_chan *c = to_omap_dma_chan(chan);
+
/* Pause/Resume only allowed with cyclic mode */
if (!c->cyclic)
return -EINVAL;
@@ -1010,8 +1015,10 @@ static int omap_dma_pause(struct omap_chan *c)
return 0;
}
-static int omap_dma_resume(struct omap_chan *c)
+static int omap_dma_resume(struct dma_chan *chan)
{
+ struct omap_chan *c = to_omap_dma_chan(chan);
+
/* Pause/Resume only allowed with cyclic mode */
if (!c->cyclic)
return -EINVAL;
@@ -1029,37 +1036,6 @@ static int omap_dma_resume(struct omap_chan *c)
return 0;
}
-static int omap_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct omap_chan *c = to_omap_dma_chan(chan);
- int ret;
-
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- ret = omap_dma_slave_config(c, (struct dma_slave_config *)arg);
- break;
-
- case DMA_TERMINATE_ALL:
- ret = omap_dma_terminate_all(c);
- break;
-
- case DMA_PAUSE:
- ret = omap_dma_pause(c);
- break;
-
- case DMA_RESUME:
- ret = omap_dma_resume(c);
- break;
-
- default:
- ret = -ENXIO;
- break;
- }
-
- return ret;
-}
-
static int omap_dma_chan_init(struct omap_dmadev *od, int dma_sig)
{
struct omap_chan *c;
@@ -1094,19 +1070,6 @@ static void omap_dma_free(struct omap_dmadev *od)
BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES))
-static int omap_dma_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = OMAP_DMA_BUSWIDTHS;
- caps->dstn_addr_widths = OMAP_DMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = true;
- caps->cmd_terminate = true;
- caps->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
-
- return 0;
-}
-
static int omap_dma_probe(struct platform_device *pdev)
{
struct omap_dmadev *od;
@@ -1136,8 +1099,14 @@ static int omap_dma_probe(struct platform_device *pdev)
od->ddev.device_issue_pending = omap_dma_issue_pending;
od->ddev.device_prep_slave_sg = omap_dma_prep_slave_sg;
od->ddev.device_prep_dma_cyclic = omap_dma_prep_dma_cyclic;
- od->ddev.device_control = omap_dma_control;
- od->ddev.device_slave_caps = omap_dma_device_slave_caps;
+ od->ddev.device_config = omap_dma_slave_config;
+ od->ddev.device_pause = omap_dma_pause;
+ od->ddev.device_resume = omap_dma_resume;
+ od->ddev.device_terminate_all = omap_dma_terminate_all;
+ od->ddev.src_addr_widths = OMAP_DMA_BUSWIDTHS;
+ od->ddev.dst_addr_widths = OMAP_DMA_BUSWIDTHS;
+ od->ddev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ od->ddev.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
od->ddev.dev = &pdev->dev;
INIT_LIST_HEAD(&od->ddev.channels);
INIT_LIST_HEAD(&od->pending);
diff --git a/drivers/dma/pch_dma.c b/drivers/dma/pch_dma.c
index 6e0e47d76b23..35c143cb88da 100644
--- a/drivers/dma/pch_dma.c
+++ b/drivers/dma/pch_dma.c
@@ -665,16 +665,12 @@ err_desc_get:
return NULL;
}
-static int pd_device_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int pd_device_terminate_all(struct dma_chan *chan)
{
struct pch_dma_chan *pd_chan = to_pd_chan(chan);
struct pch_dma_desc *desc, *_d;
LIST_HEAD(list);
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
-
spin_lock_irq(&pd_chan->lock);
pdc_set_mode(&pd_chan->chan, DMA_CTL0_DISABLE);
@@ -932,7 +928,7 @@ static int pch_dma_probe(struct pci_dev *pdev,
pd->dma.device_tx_status = pd_tx_status;
pd->dma.device_issue_pending = pd_issue_pending;
pd->dma.device_prep_slave_sg = pd_prep_slave_sg;
- pd->dma.device_control = pd_device_control;
+ pd->dma.device_terminate_all = pd_device_terminate_all;
err = dma_async_device_register(&pd->dma);
if (err) {
diff --git a/drivers/dma/pl330.c b/drivers/dma/pl330.c
index bdf40b530032..0e1f56772855 100644
--- a/drivers/dma/pl330.c
+++ b/drivers/dma/pl330.c
@@ -504,6 +504,9 @@ struct dma_pl330_desc {
enum desc_status status;
+ int bytes_requested;
+ bool last;
+
/* The channel which currently holds this desc */
struct dma_pl330_chan *pchan;
@@ -1048,6 +1051,10 @@ static bool _trigger(struct pl330_thread *thrd)
if (!req)
return true;
+ /* Return if req is running */
+ if (idx == thrd->req_running)
+ return true;
+
desc = req->desc;
ns = desc->rqcfg.nonsecure ? 1 : 0;
@@ -1587,6 +1594,8 @@ static int pl330_update(struct pl330_dmac *pl330)
descdone = thrd->req[active].desc;
thrd->req[active].desc = NULL;
+ thrd->req_running = -1;
+
/* Get going again ASAP */
_start(thrd);
@@ -2086,77 +2095,89 @@ static int pl330_alloc_chan_resources(struct dma_chan *chan)
return 1;
}
-static int pl330_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd, unsigned long arg)
+static int pl330_config(struct dma_chan *chan,
+ struct dma_slave_config *slave_config)
+{
+ struct dma_pl330_chan *pch = to_pchan(chan);
+
+ if (slave_config->direction == DMA_MEM_TO_DEV) {
+ if (slave_config->dst_addr)
+ pch->fifo_addr = slave_config->dst_addr;
+ if (slave_config->dst_addr_width)
+ pch->burst_sz = __ffs(slave_config->dst_addr_width);
+ if (slave_config->dst_maxburst)
+ pch->burst_len = slave_config->dst_maxburst;
+ } else if (slave_config->direction == DMA_DEV_TO_MEM) {
+ if (slave_config->src_addr)
+ pch->fifo_addr = slave_config->src_addr;
+ if (slave_config->src_addr_width)
+ pch->burst_sz = __ffs(slave_config->src_addr_width);
+ if (slave_config->src_maxburst)
+ pch->burst_len = slave_config->src_maxburst;
+ }
+
+ return 0;
+}
+
+static int pl330_terminate_all(struct dma_chan *chan)
{
struct dma_pl330_chan *pch = to_pchan(chan);
struct dma_pl330_desc *desc;
unsigned long flags;
struct pl330_dmac *pl330 = pch->dmac;
- struct dma_slave_config *slave_config;
LIST_HEAD(list);
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- pm_runtime_get_sync(pl330->ddma.dev);
- spin_lock_irqsave(&pch->lock, flags);
+ spin_lock_irqsave(&pch->lock, flags);
+ spin_lock(&pl330->lock);
+ _stop(pch->thread);
+ spin_unlock(&pl330->lock);
+
+ pch->thread->req[0].desc = NULL;
+ pch->thread->req[1].desc = NULL;
+ pch->thread->req_running = -1;
+
+ /* Mark all desc done */
+ list_for_each_entry(desc, &pch->submitted_list, node) {
+ desc->status = FREE;
+ dma_cookie_complete(&desc->txd);
+ }
- spin_lock(&pl330->lock);
- _stop(pch->thread);
- spin_unlock(&pl330->lock);
+ list_for_each_entry(desc, &pch->work_list , node) {
+ desc->status = FREE;
+ dma_cookie_complete(&desc->txd);
+ }
- pch->thread->req[0].desc = NULL;
- pch->thread->req[1].desc = NULL;
- pch->thread->req_running = -1;
+ list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool);
+ list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
+ list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
+ spin_unlock_irqrestore(&pch->lock, flags);
- /* Mark all desc done */
- list_for_each_entry(desc, &pch->submitted_list, node) {
- desc->status = FREE;
- dma_cookie_complete(&desc->txd);
- }
+ return 0;
+}
- list_for_each_entry(desc, &pch->work_list , node) {
- desc->status = FREE;
- dma_cookie_complete(&desc->txd);
- }
+/*
+ * We don't support DMA_RESUME command because of hardware
+ * limitations, so after pausing the channel we cannot restore
+ * it to active state. We have to terminate channel and setup
+ * DMA transfer again. This pause feature was implemented to
+ * allow safely read residue before channel termination.
+ */
+int pl330_pause(struct dma_chan *chan)
+{
+ struct dma_pl330_chan *pch = to_pchan(chan);
+ struct pl330_dmac *pl330 = pch->dmac;
+ unsigned long flags;
- list_for_each_entry(desc, &pch->completed_list , node) {
- desc->status = FREE;
- dma_cookie_complete(&desc->txd);
- }
+ pm_runtime_get_sync(pl330->ddma.dev);
+ spin_lock_irqsave(&pch->lock, flags);
- if (!list_empty(&pch->work_list))
- pm_runtime_put(pl330->ddma.dev);
+ spin_lock(&pl330->lock);
+ _stop(pch->thread);
+ spin_unlock(&pl330->lock);
- list_splice_tail_init(&pch->submitted_list, &pl330->desc_pool);
- list_splice_tail_init(&pch->work_list, &pl330->desc_pool);
- list_splice_tail_init(&pch->completed_list, &pl330->desc_pool);
- spin_unlock_irqrestore(&pch->lock, flags);
- pm_runtime_mark_last_busy(pl330->ddma.dev);
- pm_runtime_put_autosuspend(pl330->ddma.dev);
- break;
- case DMA_SLAVE_CONFIG:
- slave_config = (struct dma_slave_config *)arg;
-
- if (slave_config->direction == DMA_MEM_TO_DEV) {
- if (slave_config->dst_addr)
- pch->fifo_addr = slave_config->dst_addr;
- if (slave_config->dst_addr_width)
- pch->burst_sz = __ffs(slave_config->dst_addr_width);
- if (slave_config->dst_maxburst)
- pch->burst_len = slave_config->dst_maxburst;
- } else if (slave_config->direction == DMA_DEV_TO_MEM) {
- if (slave_config->src_addr)
- pch->fifo_addr = slave_config->src_addr;
- if (slave_config->src_addr_width)
- pch->burst_sz = __ffs(slave_config->src_addr_width);
- if (slave_config->src_maxburst)
- pch->burst_len = slave_config->src_maxburst;
- }
- break;
- default:
- dev_err(pch->dmac->ddma.dev, "Not supported command.\n");
- return -ENXIO;
- }
+ spin_unlock_irqrestore(&pch->lock, flags);
+ pm_runtime_mark_last_busy(pl330->ddma.dev);
+ pm_runtime_put_autosuspend(pl330->ddma.dev);
return 0;
}
@@ -2182,11 +2203,74 @@ static void pl330_free_chan_resources(struct dma_chan *chan)
pm_runtime_put_autosuspend(pch->dmac->ddma.dev);
}
+int pl330_get_current_xferred_count(struct dma_pl330_chan *pch,
+ struct dma_pl330_desc *desc)
+{
+ struct pl330_thread *thrd = pch->thread;
+ struct pl330_dmac *pl330 = pch->dmac;
+ void __iomem *regs = thrd->dmac->base;
+ u32 val, addr;
+
+ pm_runtime_get_sync(pl330->ddma.dev);
+ val = addr = 0;
+ if (desc->rqcfg.src_inc) {
+ val = readl(regs + SA(thrd->id));
+ addr = desc->px.src_addr;
+ } else {
+ val = readl(regs + DA(thrd->id));
+ addr = desc->px.dst_addr;
+ }
+ pm_runtime_mark_last_busy(pch->dmac->ddma.dev);
+ pm_runtime_put_autosuspend(pl330->ddma.dev);
+ return val - addr;
+}
+
static enum dma_status
pl330_tx_status(struct dma_chan *chan, dma_cookie_t cookie,
struct dma_tx_state *txstate)
{
- return dma_cookie_status(chan, cookie, txstate);
+ enum dma_status ret;
+ unsigned long flags;
+ struct dma_pl330_desc *desc, *running = NULL;
+ struct dma_pl330_chan *pch = to_pchan(chan);
+ unsigned int transferred, residual = 0;
+
+ ret = dma_cookie_status(chan, cookie, txstate);
+
+ if (!txstate)
+ return ret;
+
+ if (ret == DMA_COMPLETE)
+ goto out;
+
+ spin_lock_irqsave(&pch->lock, flags);
+
+ if (pch->thread->req_running != -1)
+ running = pch->thread->req[pch->thread->req_running].desc;
+
+ /* Check in pending list */
+ list_for_each_entry(desc, &pch->work_list, node) {
+ if (desc->status == DONE)
+ transferred = desc->bytes_requested;
+ else if (running && desc == running)
+ transferred =
+ pl330_get_current_xferred_count(pch, desc);
+ else
+ transferred = 0;
+ residual += desc->bytes_requested - transferred;
+ if (desc->txd.cookie == cookie) {
+ ret = desc->status;
+ break;
+ }
+ if (desc->last)
+ residual = 0;
+ }
+ spin_unlock_irqrestore(&pch->lock, flags);
+
+out:
+ dma_set_residue(txstate, residual);
+
+ return ret;
}
static void pl330_issue_pending(struct dma_chan *chan)
@@ -2231,12 +2315,14 @@ static dma_cookie_t pl330_tx_submit(struct dma_async_tx_descriptor *tx)
desc->txd.callback = last->txd.callback;
desc->txd.callback_param = last->txd.callback_param;
}
+ last->last = false;
dma_cookie_assign(&desc->txd);
list_move_tail(&desc->node, &pch->submitted_list);
}
+ last->last = true;
cookie = dma_cookie_assign(&last->txd);
list_add_tail(&last->node, &pch->submitted_list);
spin_unlock_irqrestore(&pch->lock, flags);
@@ -2459,6 +2545,7 @@ static struct dma_async_tx_descriptor *pl330_prep_dma_cyclic(
desc->rqtype = direction;
desc->rqcfg.brst_size = pch->burst_sz;
desc->rqcfg.brst_len = 1;
+ desc->bytes_requested = period_len;
fill_px(&desc->px, dst, src, period_len);
if (!first)
@@ -2601,6 +2688,7 @@ pl330_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
desc->rqcfg.brst_size = pch->burst_sz;
desc->rqcfg.brst_len = 1;
desc->rqtype = direction;
+ desc->bytes_requested = sg_dma_len(sg);
}
/* Return the last desc in the chain */
@@ -2623,19 +2711,6 @@ static irqreturn_t pl330_irq_handler(int irq, void *data)
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES)
-static int pl330_dma_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = PL330_DMA_BUSWIDTHS;
- caps->dstn_addr_widths = PL330_DMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = false;
- caps->cmd_terminate = true;
- caps->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
-
- return 0;
-}
-
/*
* Runtime PM callbacks are provided by amba/bus.c driver.
*
@@ -2793,9 +2868,14 @@ pl330_probe(struct amba_device *adev, const struct amba_id *id)
pd->device_prep_dma_cyclic = pl330_prep_dma_cyclic;
pd->device_tx_status = pl330_tx_status;
pd->device_prep_slave_sg = pl330_prep_slave_sg;
- pd->device_control = pl330_control;
+ pd->device_config = pl330_config;
+ pd->device_pause = pl330_pause;
+ pd->device_terminate_all = pl330_terminate_all;
pd->device_issue_pending = pl330_issue_pending;
- pd->device_slave_caps = pl330_dma_device_slave_caps;
+ pd->src_addr_widths = PL330_DMA_BUSWIDTHS;
+ pd->dst_addr_widths = PL330_DMA_BUSWIDTHS;
+ pd->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ pd->residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
ret = dma_async_device_register(pd);
if (ret) {
@@ -2847,7 +2927,7 @@ probe_err3:
/* Flush the channel */
if (pch->thread) {
- pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
+ pl330_terminate_all(&pch->chan);
pl330_free_chan_resources(&pch->chan);
}
}
@@ -2878,7 +2958,7 @@ static int pl330_remove(struct amba_device *adev)
/* Flush the channel */
if (pch->thread) {
- pl330_control(&pch->chan, DMA_TERMINATE_ALL, 0);
+ pl330_terminate_all(&pch->chan);
pl330_free_chan_resources(&pch->chan);
}
}
diff --git a/drivers/dma/qcom_bam_dma.c b/drivers/dma/qcom_bam_dma.c
index 3122a99ec06b..d7a33b3ac466 100644
--- a/drivers/dma/qcom_bam_dma.c
+++ b/drivers/dma/qcom_bam_dma.c
@@ -530,11 +530,18 @@ static void bam_free_chan(struct dma_chan *chan)
* Sets slave configuration for channel
*
*/
-static void bam_slave_config(struct bam_chan *bchan,
- struct dma_slave_config *cfg)
+static int bam_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ unsigned long flag;
+
+ spin_lock_irqsave(&bchan->vc.lock, flag);
memcpy(&bchan->slave, cfg, sizeof(*cfg));
bchan->reconfigure = 1;
+ spin_unlock_irqrestore(&bchan->vc.lock, flag);
+
+ return 0;
}
/**
@@ -627,8 +634,9 @@ err_out:
* No callbacks are done
*
*/
-static void bam_dma_terminate_all(struct bam_chan *bchan)
+static int bam_dma_terminate_all(struct dma_chan *chan)
{
+ struct bam_chan *bchan = to_bam_chan(chan);
unsigned long flag;
LIST_HEAD(head);
@@ -643,56 +651,46 @@ static void bam_dma_terminate_all(struct bam_chan *bchan)
spin_unlock_irqrestore(&bchan->vc.lock, flag);
vchan_dma_desc_free_list(&bchan->vc, &head);
+
+ return 0;
}
/**
- * bam_control - DMA device control
+ * bam_pause - Pause DMA channel
* @chan: dma channel
- * @cmd: control cmd
- * @arg: cmd argument
*
- * Perform DMA control command
+ */
+static int bam_pause(struct dma_chan *chan)
+{
+ struct bam_chan *bchan = to_bam_chan(chan);
+ struct bam_device *bdev = bchan->bdev;
+ unsigned long flag;
+
+ spin_lock_irqsave(&bchan->vc.lock, flag);
+ writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_HALT));
+ bchan->paused = 1;
+ spin_unlock_irqrestore(&bchan->vc.lock, flag);
+
+ return 0;
+}
+
+/**
+ * bam_resume - Resume DMA channel operations
+ * @chan: dma channel
*
*/
-static int bam_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int bam_resume(struct dma_chan *chan)
{
struct bam_chan *bchan = to_bam_chan(chan);
struct bam_device *bdev = bchan->bdev;
- int ret = 0;
unsigned long flag;
- switch (cmd) {
- case DMA_PAUSE:
- spin_lock_irqsave(&bchan->vc.lock, flag);
- writel_relaxed(1, bam_addr(bdev, bchan->id, BAM_P_HALT));
- bchan->paused = 1;
- spin_unlock_irqrestore(&bchan->vc.lock, flag);
- break;
-
- case DMA_RESUME:
- spin_lock_irqsave(&bchan->vc.lock, flag);
- writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_HALT));
- bchan->paused = 0;
- spin_unlock_irqrestore(&bchan->vc.lock, flag);
- break;
-
- case DMA_TERMINATE_ALL:
- bam_dma_terminate_all(bchan);
- break;
-
- case DMA_SLAVE_CONFIG:
- spin_lock_irqsave(&bchan->vc.lock, flag);
- bam_slave_config(bchan, (struct dma_slave_config *)arg);
- spin_unlock_irqrestore(&bchan->vc.lock, flag);
- break;
-
- default:
- ret = -ENXIO;
- break;
- }
+ spin_lock_irqsave(&bchan->vc.lock, flag);
+ writel_relaxed(0, bam_addr(bdev, bchan->id, BAM_P_HALT));
+ bchan->paused = 0;
+ spin_unlock_irqrestore(&bchan->vc.lock, flag);
- return ret;
+ return 0;
}
/**
@@ -1148,7 +1146,10 @@ static int bam_dma_probe(struct platform_device *pdev)
bdev->common.device_alloc_chan_resources = bam_alloc_chan;
bdev->common.device_free_chan_resources = bam_free_chan;
bdev->common.device_prep_slave_sg = bam_prep_slave_sg;
- bdev->common.device_control = bam_control;
+ bdev->common.device_config = bam_slave_config;
+ bdev->common.device_pause = bam_pause;
+ bdev->common.device_resume = bam_resume;
+ bdev->common.device_terminate_all = bam_dma_terminate_all;
bdev->common.device_issue_pending = bam_issue_pending;
bdev->common.device_tx_status = bam_tx_status;
bdev->common.dev = bdev->dev;
@@ -1187,7 +1188,7 @@ static int bam_dma_remove(struct platform_device *pdev)
devm_free_irq(bdev->dev, bdev->irq, bdev);
for (i = 0; i < bdev->num_channels; i++) {
- bam_dma_terminate_all(&bdev->channels[i]);
+ bam_dma_terminate_all(&bdev->channels[i].vc.chan);
tasklet_kill(&bdev->channels[i].vc.task);
dma_free_writecombine(bdev->dev, BAM_DESC_FIFO_SIZE,
diff --git a/drivers/dma/s3c24xx-dma.c b/drivers/dma/s3c24xx-dma.c
index 6941a77521c3..2f91da3db836 100644
--- a/drivers/dma/s3c24xx-dma.c
+++ b/drivers/dma/s3c24xx-dma.c
@@ -384,20 +384,30 @@ static u32 s3c24xx_dma_getbytes_chan(struct s3c24xx_dma_chan *s3cchan)
return tc * txd->width;
}
-static int s3c24xx_dma_set_runtime_config(struct s3c24xx_dma_chan *s3cchan,
+static int s3c24xx_dma_set_runtime_config(struct dma_chan *chan,
struct dma_slave_config *config)
{
- if (!s3cchan->slave)
- return -EINVAL;
+ struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan);
+ unsigned long flags;
+ int ret = 0;
/* Reject definitely invalid configurations */
if (config->src_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES ||
config->dst_addr_width == DMA_SLAVE_BUSWIDTH_8_BYTES)
return -EINVAL;
+ spin_lock_irqsave(&s3cchan->vc.lock, flags);
+
+ if (!s3cchan->slave) {
+ ret = -EINVAL;
+ goto out;
+ }
+
s3cchan->cfg = *config;
- return 0;
+out:
+ spin_unlock_irqrestore(&s3cchan->vc.lock, flags);
+ return ret;
}
/*
@@ -703,8 +713,7 @@ static irqreturn_t s3c24xx_dma_irq(int irq, void *data)
* The DMA ENGINE API
*/
-static int s3c24xx_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int s3c24xx_dma_terminate_all(struct dma_chan *chan)
{
struct s3c24xx_dma_chan *s3cchan = to_s3c24xx_dma_chan(chan);
struct s3c24xx_dma_engine *s3cdma = s3cchan->host;
@@ -713,40 +722,28 @@ static int s3c24xx_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
spin_lock_irqsave(&s3cchan->vc.lock, flags);
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- ret = s3c24xx_dma_set_runtime_config(s3cchan,
- (struct dma_slave_config *)arg);
- break;
- case DMA_TERMINATE_ALL:
- if (!s3cchan->phy && !s3cchan->at) {
- dev_err(&s3cdma->pdev->dev, "trying to terminate already stopped channel %d\n",
- s3cchan->id);
- ret = -EINVAL;
- break;
- }
+ if (!s3cchan->phy && !s3cchan->at) {
+ dev_err(&s3cdma->pdev->dev, "trying to terminate already stopped channel %d\n",
+ s3cchan->id);
+ ret = -EINVAL;
+ goto unlock;
+ }
- s3cchan->state = S3C24XX_DMA_CHAN_IDLE;
+ s3cchan->state = S3C24XX_DMA_CHAN_IDLE;
- /* Mark physical channel as free */
- if (s3cchan->phy)
- s3c24xx_dma_phy_free(s3cchan);
+ /* Mark physical channel as free */
+ if (s3cchan->phy)
+ s3c24xx_dma_phy_free(s3cchan);
- /* Dequeue current job */
- if (s3cchan->at) {
- s3c24xx_dma_desc_free(&s3cchan->at->vd);
- s3cchan->at = NULL;
- }
-
- /* Dequeue jobs not yet fired as well */
- s3c24xx_dma_free_txd_list(s3cdma, s3cchan);
- break;
- default:
- /* Unknown command */
- ret = -ENXIO;
- break;
+ /* Dequeue current job */
+ if (s3cchan->at) {
+ s3c24xx_dma_desc_free(&s3cchan->at->vd);
+ s3cchan->at = NULL;
}
+ /* Dequeue jobs not yet fired as well */
+ s3c24xx_dma_free_txd_list(s3cdma, s3cchan);
+unlock:
spin_unlock_irqrestore(&s3cchan->vc.lock, flags);
return ret;
@@ -1300,7 +1297,8 @@ static int s3c24xx_dma_probe(struct platform_device *pdev)
s3cdma->memcpy.device_prep_dma_memcpy = s3c24xx_dma_prep_memcpy;
s3cdma->memcpy.device_tx_status = s3c24xx_dma_tx_status;
s3cdma->memcpy.device_issue_pending = s3c24xx_dma_issue_pending;
- s3cdma->memcpy.device_control = s3c24xx_dma_control;
+ s3cdma->memcpy.device_config = s3c24xx_dma_set_runtime_config;
+ s3cdma->memcpy.device_terminate_all = s3c24xx_dma_terminate_all;
/* Initialize slave engine for SoC internal dedicated peripherals */
dma_cap_set(DMA_SLAVE, s3cdma->slave.cap_mask);
@@ -1315,7 +1313,8 @@ static int s3c24xx_dma_probe(struct platform_device *pdev)
s3cdma->slave.device_issue_pending = s3c24xx_dma_issue_pending;
s3cdma->slave.device_prep_slave_sg = s3c24xx_dma_prep_slave_sg;
s3cdma->slave.device_prep_dma_cyclic = s3c24xx_dma_prep_dma_cyclic;
- s3cdma->slave.device_control = s3c24xx_dma_control;
+ s3cdma->slave.device_config = s3c24xx_dma_set_runtime_config;
+ s3cdma->slave.device_terminate_all = s3c24xx_dma_terminate_all;
/* Register as many memcpy channels as there are physical channels */
ret = s3c24xx_dma_init_virtual_channels(s3cdma, &s3cdma->memcpy,
diff --git a/drivers/dma/sa11x0-dma.c b/drivers/dma/sa11x0-dma.c
index 96bb62c39c41..5adf5407a8cb 100644
--- a/drivers/dma/sa11x0-dma.c
+++ b/drivers/dma/sa11x0-dma.c
@@ -669,8 +669,10 @@ static struct dma_async_tx_descriptor *sa11x0_dma_prep_dma_cyclic(
return vchan_tx_prep(&c->vc, &txd->vd, DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
}
-static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_config *cfg)
+static int sa11x0_dma_device_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
{
+ struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
u32 ddar = c->ddar & ((0xf << 4) | DDAR_RW);
dma_addr_t addr;
enum dma_slave_buswidth width;
@@ -704,99 +706,101 @@ static int sa11x0_dma_slave_config(struct sa11x0_dma_chan *c, struct dma_slave_c
return 0;
}
-static int sa11x0_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int sa11x0_dma_device_pause(struct dma_chan *chan)
{
struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
struct sa11x0_dma_phy *p;
LIST_HEAD(head);
unsigned long flags;
- int ret;
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- return sa11x0_dma_slave_config(c, (struct dma_slave_config *)arg);
-
- case DMA_TERMINATE_ALL:
- dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
- /* Clear the tx descriptor lists */
- spin_lock_irqsave(&c->vc.lock, flags);
- vchan_get_all_descriptors(&c->vc, &head);
+ dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (c->status == DMA_IN_PROGRESS) {
+ c->status = DMA_PAUSED;
p = c->phy;
if (p) {
- dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
- /* vchan is assigned to a pchan - stop the channel */
- writel(DCSR_RUN | DCSR_IE |
- DCSR_STRTA | DCSR_DONEA |
- DCSR_STRTB | DCSR_DONEB,
- p->base + DMA_DCSR_C);
-
- if (p->txd_load) {
- if (p->txd_load != p->txd_done)
- list_add_tail(&p->txd_load->vd.node, &head);
- p->txd_load = NULL;
- }
- if (p->txd_done) {
- list_add_tail(&p->txd_done->vd.node, &head);
- p->txd_done = NULL;
- }
- c->phy = NULL;
+ writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
+ } else {
spin_lock(&d->lock);
- p->vchan = NULL;
+ list_del_init(&c->node);
spin_unlock(&d->lock);
- tasklet_schedule(&d->task);
}
- spin_unlock_irqrestore(&c->vc.lock, flags);
- vchan_dma_desc_free_list(&c->vc, &head);
- ret = 0;
- break;
+ }
+ spin_unlock_irqrestore(&c->vc.lock, flags);
- case DMA_PAUSE:
- dev_dbg(d->slave.dev, "vchan %p: pause\n", &c->vc);
- spin_lock_irqsave(&c->vc.lock, flags);
- if (c->status == DMA_IN_PROGRESS) {
- c->status = DMA_PAUSED;
+ return 0;
+}
- p = c->phy;
- if (p) {
- writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_C);
- } else {
- spin_lock(&d->lock);
- list_del_init(&c->node);
- spin_unlock(&d->lock);
- }
- }
- spin_unlock_irqrestore(&c->vc.lock, flags);
- ret = 0;
- break;
+static int sa11x0_dma_device_resume(struct dma_chan *chan)
+{
+ struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+ struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+ struct sa11x0_dma_phy *p;
+ LIST_HEAD(head);
+ unsigned long flags;
- case DMA_RESUME:
- dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
- spin_lock_irqsave(&c->vc.lock, flags);
- if (c->status == DMA_PAUSED) {
- c->status = DMA_IN_PROGRESS;
-
- p = c->phy;
- if (p) {
- writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
- } else if (!list_empty(&c->vc.desc_issued)) {
- spin_lock(&d->lock);
- list_add_tail(&c->node, &d->chan_pending);
- spin_unlock(&d->lock);
- }
+ dev_dbg(d->slave.dev, "vchan %p: resume\n", &c->vc);
+ spin_lock_irqsave(&c->vc.lock, flags);
+ if (c->status == DMA_PAUSED) {
+ c->status = DMA_IN_PROGRESS;
+
+ p = c->phy;
+ if (p) {
+ writel(DCSR_RUN | DCSR_IE, p->base + DMA_DCSR_S);
+ } else if (!list_empty(&c->vc.desc_issued)) {
+ spin_lock(&d->lock);
+ list_add_tail(&c->node, &d->chan_pending);
+ spin_unlock(&d->lock);
}
- spin_unlock_irqrestore(&c->vc.lock, flags);
- ret = 0;
- break;
+ }
+ spin_unlock_irqrestore(&c->vc.lock, flags);
- default:
- ret = -ENXIO;
- break;
+ return 0;
+}
+
+static int sa11x0_dma_device_terminate_all(struct dma_chan *chan)
+{
+ struct sa11x0_dma_chan *c = to_sa11x0_dma_chan(chan);
+ struct sa11x0_dma_dev *d = to_sa11x0_dma(chan->device);
+ struct sa11x0_dma_phy *p;
+ LIST_HEAD(head);
+ unsigned long flags;
+
+ dev_dbg(d->slave.dev, "vchan %p: terminate all\n", &c->vc);
+ /* Clear the tx descriptor lists */
+ spin_lock_irqsave(&c->vc.lock, flags);
+ vchan_get_all_descriptors(&c->vc, &head);
+
+ p = c->phy;
+ if (p) {
+ dev_dbg(d->slave.dev, "pchan %u: terminating\n", p->num);
+ /* vchan is assigned to a pchan - stop the channel */
+ writel(DCSR_RUN | DCSR_IE |
+ DCSR_STRTA | DCSR_DONEA |
+ DCSR_STRTB | DCSR_DONEB,
+ p->base + DMA_DCSR_C);
+
+ if (p->txd_load) {
+ if (p->txd_load != p->txd_done)
+ list_add_tail(&p->txd_load->vd.node, &head);
+ p->txd_load = NULL;
+ }
+ if (p->txd_done) {
+ list_add_tail(&p->txd_done->vd.node, &head);
+ p->txd_done = NULL;
+ }
+ c->phy = NULL;
+ spin_lock(&d->lock);
+ p->vchan = NULL;
+ spin_unlock(&d->lock);
+ tasklet_schedule(&d->task);
}
+ spin_unlock_irqrestore(&c->vc.lock, flags);
+ vchan_dma_desc_free_list(&c->vc, &head);
- return ret;
+ return 0;
}
struct sa11x0_dma_channel_desc {
@@ -833,7 +837,10 @@ static int sa11x0_dma_init_dmadev(struct dma_device *dmadev,
dmadev->dev = dev;
dmadev->device_alloc_chan_resources = sa11x0_dma_alloc_chan_resources;
dmadev->device_free_chan_resources = sa11x0_dma_free_chan_resources;
- dmadev->device_control = sa11x0_dma_control;
+ dmadev->device_config = sa11x0_dma_device_config;
+ dmadev->device_pause = sa11x0_dma_device_pause;
+ dmadev->device_resume = sa11x0_dma_device_resume;
+ dmadev->device_terminate_all = sa11x0_dma_device_terminate_all;
dmadev->device_tx_status = sa11x0_dma_tx_status;
dmadev->device_issue_pending = sa11x0_dma_issue_pending;
diff --git a/drivers/dma/sh/Kconfig b/drivers/dma/sh/Kconfig
index 0349125a2e20..8190ad225a1b 100644
--- a/drivers/dma/sh/Kconfig
+++ b/drivers/dma/sh/Kconfig
@@ -2,6 +2,10 @@
# DMA engine configuration for sh
#
+config RENESAS_DMA
+ bool
+ select DMA_ENGINE
+
#
# DMA Engine Helpers
#
@@ -12,7 +16,7 @@ config SH_DMAE_BASE
depends on !SUPERH || SH_DMA
depends on !SH_DMA_API
default y
- select DMA_ENGINE
+ select RENESAS_DMA
help
Enable support for the Renesas SuperH DMA controllers.
@@ -52,3 +56,11 @@ config RCAR_AUDMAC_PP
depends on SH_DMAE_BASE
help
Enable support for the Renesas R-Car Audio DMAC Peripheral Peripheral controllers.
+
+config RCAR_DMAC
+ tristate "Renesas R-Car Gen2 DMA Controller"
+ depends on ARCH_SHMOBILE || COMPILE_TEST
+ select RENESAS_DMA
+ help
+ This driver supports the general purpose DMA controller found in the
+ Renesas R-Car second generation SoCs.
diff --git a/drivers/dma/sh/Makefile b/drivers/dma/sh/Makefile
index 0a5cfdb76e45..2852f9db61a4 100644
--- a/drivers/dma/sh/Makefile
+++ b/drivers/dma/sh/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_SH_DMAE) += shdma.o
obj-$(CONFIG_SUDMAC) += sudmac.o
obj-$(CONFIG_RCAR_HPB_DMAE) += rcar-hpbdma.o
obj-$(CONFIG_RCAR_AUDMAC_PP) += rcar-audmapp.o
+obj-$(CONFIG_RCAR_DMAC) += rcar-dmac.o
diff --git a/drivers/dma/sh/rcar-dmac.c b/drivers/dma/sh/rcar-dmac.c
new file mode 100644
index 000000000000..a18d16cc4795
--- /dev/null
+++ b/drivers/dma/sh/rcar-dmac.c
@@ -0,0 +1,1770 @@
+/*
+ * Renesas R-Car Gen2 DMA Controller Driver
+ *
+ * Copyright (C) 2014 Renesas Electronics Inc.
+ *
+ * Author: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/dma-mapping.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_dma.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+
+#include "../dmaengine.h"
+
+/*
+ * struct rcar_dmac_xfer_chunk - Descriptor for a hardware transfer
+ * @node: entry in the parent's chunks list
+ * @src_addr: device source address
+ * @dst_addr: device destination address
+ * @size: transfer size in bytes
+ */
+struct rcar_dmac_xfer_chunk {
+ struct list_head node;
+
+ dma_addr_t src_addr;
+ dma_addr_t dst_addr;
+ u32 size;
+};
+
+/*
+ * struct rcar_dmac_hw_desc - Hardware descriptor for a transfer chunk
+ * @sar: value of the SAR register (source address)
+ * @dar: value of the DAR register (destination address)
+ * @tcr: value of the TCR register (transfer count)
+ */
+struct rcar_dmac_hw_desc {
+ u32 sar;
+ u32 dar;
+ u32 tcr;
+ u32 reserved;
+} __attribute__((__packed__));
+
+/*
+ * struct rcar_dmac_desc - R-Car Gen2 DMA Transfer Descriptor
+ * @async_tx: base DMA asynchronous transaction descriptor
+ * @direction: direction of the DMA transfer
+ * @xfer_shift: log2 of the transfer size
+ * @chcr: value of the channel configuration register for this transfer
+ * @node: entry in the channel's descriptors lists
+ * @chunks: list of transfer chunks for this transfer
+ * @running: the transfer chunk being currently processed
+ * @nchunks: number of transfer chunks for this transfer
+ * @hwdescs.use: whether the transfer descriptor uses hardware descriptors
+ * @hwdescs.mem: hardware descriptors memory for the transfer
+ * @hwdescs.dma: device address of the hardware descriptors memory
+ * @hwdescs.size: size of the hardware descriptors in bytes
+ * @size: transfer size in bytes
+ * @cyclic: when set indicates that the DMA transfer is cyclic
+ */
+struct rcar_dmac_desc {
+ struct dma_async_tx_descriptor async_tx;
+ enum dma_transfer_direction direction;
+ unsigned int xfer_shift;
+ u32 chcr;
+
+ struct list_head node;
+ struct list_head chunks;
+ struct rcar_dmac_xfer_chunk *running;
+ unsigned int nchunks;
+
+ struct {
+ bool use;
+ struct rcar_dmac_hw_desc *mem;
+ dma_addr_t dma;
+ size_t size;
+ } hwdescs;
+
+ unsigned int size;
+ bool cyclic;
+};
+
+#define to_rcar_dmac_desc(d) container_of(d, struct rcar_dmac_desc, async_tx)
+
+/*
+ * struct rcar_dmac_desc_page - One page worth of descriptors
+ * @node: entry in the channel's pages list
+ * @descs: array of DMA descriptors
+ * @chunks: array of transfer chunk descriptors
+ */
+struct rcar_dmac_desc_page {
+ struct list_head node;
+
+ union {
+ struct rcar_dmac_desc descs[0];
+ struct rcar_dmac_xfer_chunk chunks[0];
+ };
+};
+
+#define RCAR_DMAC_DESCS_PER_PAGE \
+ ((PAGE_SIZE - offsetof(struct rcar_dmac_desc_page, descs)) / \
+ sizeof(struct rcar_dmac_desc))
+#define RCAR_DMAC_XFER_CHUNKS_PER_PAGE \
+ ((PAGE_SIZE - offsetof(struct rcar_dmac_desc_page, chunks)) / \
+ sizeof(struct rcar_dmac_xfer_chunk))
+
+/*
+ * struct rcar_dmac_chan - R-Car Gen2 DMA Controller Channel
+ * @chan: base DMA channel object
+ * @iomem: channel I/O memory base
+ * @index: index of this channel in the controller
+ * @src_xfer_size: size (in bytes) of hardware transfers on the source side
+ * @dst_xfer_size: size (in bytes) of hardware transfers on the destination side
+ * @src_slave_addr: slave source memory address
+ * @dst_slave_addr: slave destination memory address
+ * @mid_rid: hardware MID/RID for the DMA client using this channel
+ * @lock: protects the channel CHCR register and the desc members
+ * @desc.free: list of free descriptors
+ * @desc.pending: list of pending descriptors (submitted with tx_submit)
+ * @desc.active: list of active descriptors (activated with issue_pending)
+ * @desc.done: list of completed descriptors
+ * @desc.wait: list of descriptors waiting for an ack
+ * @desc.running: the descriptor being processed (a member of the active list)
+ * @desc.chunks_free: list of free transfer chunk descriptors
+ * @desc.pages: list of pages used by allocated descriptors
+ */
+struct rcar_dmac_chan {
+ struct dma_chan chan;
+ void __iomem *iomem;
+ unsigned int index;
+
+ unsigned int src_xfer_size;
+ unsigned int dst_xfer_size;
+ dma_addr_t src_slave_addr;
+ dma_addr_t dst_slave_addr;
+ int mid_rid;
+
+ spinlock_t lock;
+
+ struct {
+ struct list_head free;
+ struct list_head pending;
+ struct list_head active;
+ struct list_head done;
+ struct list_head wait;
+ struct rcar_dmac_desc *running;
+
+ struct list_head chunks_free;
+
+ struct list_head pages;
+ } desc;
+};
+
+#define to_rcar_dmac_chan(c) container_of(c, struct rcar_dmac_chan, chan)
+
+/*
+ * struct rcar_dmac - R-Car Gen2 DMA Controller
+ * @engine: base DMA engine object
+ * @dev: the hardware device
+ * @iomem: remapped I/O memory base
+ * @n_channels: number of available channels
+ * @channels: array of DMAC channels
+ * @modules: bitmask of client modules in use
+ */
+struct rcar_dmac {
+ struct dma_device engine;
+ struct device *dev;
+ void __iomem *iomem;
+
+ unsigned int n_channels;
+ struct rcar_dmac_chan *channels;
+
+ unsigned long modules[256 / BITS_PER_LONG];
+};
+
+#define to_rcar_dmac(d) container_of(d, struct rcar_dmac, engine)
+
+/* -----------------------------------------------------------------------------
+ * Registers
+ */
+
+#define RCAR_DMAC_CHAN_OFFSET(i) (0x8000 + 0x80 * (i))
+
+#define RCAR_DMAISTA 0x0020
+#define RCAR_DMASEC 0x0030
+#define RCAR_DMAOR 0x0060
+#define RCAR_DMAOR_PRI_FIXED (0 << 8)
+#define RCAR_DMAOR_PRI_ROUND_ROBIN (3 << 8)
+#define RCAR_DMAOR_AE (1 << 2)
+#define RCAR_DMAOR_DME (1 << 0)
+#define RCAR_DMACHCLR 0x0080
+#define RCAR_DMADPSEC 0x00a0
+
+#define RCAR_DMASAR 0x0000
+#define RCAR_DMADAR 0x0004
+#define RCAR_DMATCR 0x0008
+#define RCAR_DMATCR_MASK 0x00ffffff
+#define RCAR_DMATSR 0x0028
+#define RCAR_DMACHCR 0x000c
+#define RCAR_DMACHCR_CAE (1 << 31)
+#define RCAR_DMACHCR_CAIE (1 << 30)
+#define RCAR_DMACHCR_DPM_DISABLED (0 << 28)
+#define RCAR_DMACHCR_DPM_ENABLED (1 << 28)
+#define RCAR_DMACHCR_DPM_REPEAT (2 << 28)
+#define RCAR_DMACHCR_DPM_INFINITE (3 << 28)
+#define RCAR_DMACHCR_RPT_SAR (1 << 27)
+#define RCAR_DMACHCR_RPT_DAR (1 << 26)
+#define RCAR_DMACHCR_RPT_TCR (1 << 25)
+#define RCAR_DMACHCR_DPB (1 << 22)
+#define RCAR_DMACHCR_DSE (1 << 19)
+#define RCAR_DMACHCR_DSIE (1 << 18)
+#define RCAR_DMACHCR_TS_1B ((0 << 20) | (0 << 3))
+#define RCAR_DMACHCR_TS_2B ((0 << 20) | (1 << 3))
+#define RCAR_DMACHCR_TS_4B ((0 << 20) | (2 << 3))
+#define RCAR_DMACHCR_TS_16B ((0 << 20) | (3 << 3))
+#define RCAR_DMACHCR_TS_32B ((1 << 20) | (0 << 3))
+#define RCAR_DMACHCR_TS_64B ((1 << 20) | (1 << 3))
+#define RCAR_DMACHCR_TS_8B ((1 << 20) | (3 << 3))
+#define RCAR_DMACHCR_DM_FIXED (0 << 14)
+#define RCAR_DMACHCR_DM_INC (1 << 14)
+#define RCAR_DMACHCR_DM_DEC (2 << 14)
+#define RCAR_DMACHCR_SM_FIXED (0 << 12)
+#define RCAR_DMACHCR_SM_INC (1 << 12)
+#define RCAR_DMACHCR_SM_DEC (2 << 12)
+#define RCAR_DMACHCR_RS_AUTO (4 << 8)
+#define RCAR_DMACHCR_RS_DMARS (8 << 8)
+#define RCAR_DMACHCR_IE (1 << 2)
+#define RCAR_DMACHCR_TE (1 << 1)
+#define RCAR_DMACHCR_DE (1 << 0)
+#define RCAR_DMATCRB 0x0018
+#define RCAR_DMATSRB 0x0038
+#define RCAR_DMACHCRB 0x001c
+#define RCAR_DMACHCRB_DCNT(n) ((n) << 24)
+#define RCAR_DMACHCRB_DPTR_MASK (0xff << 16)
+#define RCAR_DMACHCRB_DPTR_SHIFT 16
+#define RCAR_DMACHCRB_DRST (1 << 15)
+#define RCAR_DMACHCRB_DTS (1 << 8)
+#define RCAR_DMACHCRB_SLM_NORMAL (0 << 4)
+#define RCAR_DMACHCRB_SLM_CLK(n) ((8 | (n)) << 4)
+#define RCAR_DMACHCRB_PRI(n) ((n) << 0)
+#define RCAR_DMARS 0x0040
+#define RCAR_DMABUFCR 0x0048
+#define RCAR_DMABUFCR_MBU(n) ((n) << 16)
+#define RCAR_DMABUFCR_ULB(n) ((n) << 0)
+#define RCAR_DMADPBASE 0x0050
+#define RCAR_DMADPBASE_MASK 0xfffffff0
+#define RCAR_DMADPBASE_SEL (1 << 0)
+#define RCAR_DMADPCR 0x0054
+#define RCAR_DMADPCR_DIPT(n) ((n) << 24)
+#define RCAR_DMAFIXSAR 0x0010
+#define RCAR_DMAFIXDAR 0x0014
+#define RCAR_DMAFIXDPBASE 0x0060
+
+/* Hardcode the MEMCPY transfer size to 4 bytes. */
+#define RCAR_DMAC_MEMCPY_XFER_SIZE 4
+
+/* -----------------------------------------------------------------------------
+ * Device access
+ */
+
+static void rcar_dmac_write(struct rcar_dmac *dmac, u32 reg, u32 data)
+{
+ if (reg == RCAR_DMAOR)
+ writew(data, dmac->iomem + reg);
+ else
+ writel(data, dmac->iomem + reg);
+}
+
+static u32 rcar_dmac_read(struct rcar_dmac *dmac, u32 reg)
+{
+ if (reg == RCAR_DMAOR)
+ return readw(dmac->iomem + reg);
+ else
+ return readl(dmac->iomem + reg);
+}
+
+static u32 rcar_dmac_chan_read(struct rcar_dmac_chan *chan, u32 reg)
+{
+ if (reg == RCAR_DMARS)
+ return readw(chan->iomem + reg);
+ else
+ return readl(chan->iomem + reg);
+}
+
+static void rcar_dmac_chan_write(struct rcar_dmac_chan *chan, u32 reg, u32 data)
+{
+ if (reg == RCAR_DMARS)
+ writew(data, chan->iomem + reg);
+ else
+ writel(data, chan->iomem + reg);
+}
+
+/* -----------------------------------------------------------------------------
+ * Initialization and configuration
+ */
+
+static bool rcar_dmac_chan_is_busy(struct rcar_dmac_chan *chan)
+{
+ u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
+
+ return (chcr & (RCAR_DMACHCR_DE | RCAR_DMACHCR_TE)) == RCAR_DMACHCR_DE;
+}
+
+static void rcar_dmac_chan_start_xfer(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_desc *desc = chan->desc.running;
+ u32 chcr = desc->chcr;
+
+ WARN_ON_ONCE(rcar_dmac_chan_is_busy(chan));
+
+ if (chan->mid_rid >= 0)
+ rcar_dmac_chan_write(chan, RCAR_DMARS, chan->mid_rid);
+
+ if (desc->hwdescs.use) {
+ struct rcar_dmac_xfer_chunk *chunk;
+
+ dev_dbg(chan->chan.device->dev,
+ "chan%u: queue desc %p: %u@%pad\n",
+ chan->index, desc, desc->nchunks, &desc->hwdescs.dma);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ rcar_dmac_chan_write(chan, RCAR_DMAFIXDPBASE,
+ desc->hwdescs.dma >> 32);
+#endif
+ rcar_dmac_chan_write(chan, RCAR_DMADPBASE,
+ (desc->hwdescs.dma & 0xfffffff0) |
+ RCAR_DMADPBASE_SEL);
+ rcar_dmac_chan_write(chan, RCAR_DMACHCRB,
+ RCAR_DMACHCRB_DCNT(desc->nchunks - 1) |
+ RCAR_DMACHCRB_DRST);
+
+ /*
+ * Errata: When descriptor memory is accessed through an IOMMU
+ * the DMADAR register isn't initialized automatically from the
+ * first descriptor at beginning of transfer by the DMAC like it
+ * should. Initialize it manually with the destination address
+ * of the first chunk.
+ */
+ chunk = list_first_entry(&desc->chunks,
+ struct rcar_dmac_xfer_chunk, node);
+ rcar_dmac_chan_write(chan, RCAR_DMADAR,
+ chunk->dst_addr & 0xffffffff);
+
+ /*
+ * Program the descriptor stage interrupt to occur after the end
+ * of the first stage.
+ */
+ rcar_dmac_chan_write(chan, RCAR_DMADPCR, RCAR_DMADPCR_DIPT(1));
+
+ chcr |= RCAR_DMACHCR_RPT_SAR | RCAR_DMACHCR_RPT_DAR
+ | RCAR_DMACHCR_RPT_TCR | RCAR_DMACHCR_DPB;
+
+ /*
+ * If the descriptor isn't cyclic enable normal descriptor mode
+ * and the transfer completion interrupt.
+ */
+ if (!desc->cyclic)
+ chcr |= RCAR_DMACHCR_DPM_ENABLED | RCAR_DMACHCR_IE;
+ /*
+ * If the descriptor is cyclic and has a callback enable the
+ * descriptor stage interrupt in infinite repeat mode.
+ */
+ else if (desc->async_tx.callback)
+ chcr |= RCAR_DMACHCR_DPM_INFINITE | RCAR_DMACHCR_DSIE;
+ /*
+ * Otherwise just select infinite repeat mode without any
+ * interrupt.
+ */
+ else
+ chcr |= RCAR_DMACHCR_DPM_INFINITE;
+ } else {
+ struct rcar_dmac_xfer_chunk *chunk = desc->running;
+
+ dev_dbg(chan->chan.device->dev,
+ "chan%u: queue chunk %p: %u@%pad -> %pad\n",
+ chan->index, chunk, chunk->size, &chunk->src_addr,
+ &chunk->dst_addr);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ rcar_dmac_chan_write(chan, RCAR_DMAFIXSAR,
+ chunk->src_addr >> 32);
+ rcar_dmac_chan_write(chan, RCAR_DMAFIXDAR,
+ chunk->dst_addr >> 32);
+#endif
+ rcar_dmac_chan_write(chan, RCAR_DMASAR,
+ chunk->src_addr & 0xffffffff);
+ rcar_dmac_chan_write(chan, RCAR_DMADAR,
+ chunk->dst_addr & 0xffffffff);
+ rcar_dmac_chan_write(chan, RCAR_DMATCR,
+ chunk->size >> desc->xfer_shift);
+
+ chcr |= RCAR_DMACHCR_DPM_DISABLED | RCAR_DMACHCR_IE;
+ }
+
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr | RCAR_DMACHCR_DE);
+}
+
+static int rcar_dmac_init(struct rcar_dmac *dmac)
+{
+ u16 dmaor;
+
+ /* Clear all channels and enable the DMAC globally. */
+ rcar_dmac_write(dmac, RCAR_DMACHCLR, 0x7fff);
+ rcar_dmac_write(dmac, RCAR_DMAOR,
+ RCAR_DMAOR_PRI_FIXED | RCAR_DMAOR_DME);
+
+ dmaor = rcar_dmac_read(dmac, RCAR_DMAOR);
+ if ((dmaor & (RCAR_DMAOR_AE | RCAR_DMAOR_DME)) != RCAR_DMAOR_DME) {
+ dev_warn(dmac->dev, "DMAOR initialization failed.\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors submission
+ */
+
+static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
+{
+ struct rcar_dmac_chan *chan = to_rcar_dmac_chan(tx->chan);
+ struct rcar_dmac_desc *desc = to_rcar_dmac_desc(tx);
+ unsigned long flags;
+ dma_cookie_t cookie;
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ cookie = dma_cookie_assign(tx);
+
+ dev_dbg(chan->chan.device->dev, "chan%u: submit #%d@%p\n",
+ chan->index, tx->cookie, desc);
+
+ list_add_tail(&desc->node, &chan->desc.pending);
+ desc->running = list_first_entry(&desc->chunks,
+ struct rcar_dmac_xfer_chunk, node);
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return cookie;
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors allocation and free
+ */
+
+/*
+ * rcar_dmac_desc_alloc - Allocate a page worth of DMA descriptors
+ * @chan: the DMA channel
+ * @gfp: allocation flags
+ */
+static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
+{
+ struct rcar_dmac_desc_page *page;
+ LIST_HEAD(list);
+ unsigned int i;
+
+ page = (void *)get_zeroed_page(gfp);
+ if (!page)
+ return -ENOMEM;
+
+ for (i = 0; i < RCAR_DMAC_DESCS_PER_PAGE; ++i) {
+ struct rcar_dmac_desc *desc = &page->descs[i];
+
+ dma_async_tx_descriptor_init(&desc->async_tx, &chan->chan);
+ desc->async_tx.tx_submit = rcar_dmac_tx_submit;
+ INIT_LIST_HEAD(&desc->chunks);
+
+ list_add_tail(&desc->node, &list);
+ }
+
+ spin_lock_irq(&chan->lock);
+ list_splice_tail(&list, &chan->desc.free);
+ list_add_tail(&page->node, &chan->desc.pages);
+ spin_unlock_irq(&chan->lock);
+
+ return 0;
+}
+
+/*
+ * rcar_dmac_desc_put - Release a DMA transfer descriptor
+ * @chan: the DMA channel
+ * @desc: the descriptor
+ *
+ * Put the descriptor and its transfer chunk descriptors back in the channel's
+ * free descriptors lists. The descriptor's chunks list will be reinitialized to
+ * an empty list as a result.
+ *
+ * The descriptor must have been removed from the channel's lists before calling
+ * this function.
+ */
+static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
+ struct rcar_dmac_desc *desc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ list_splice_tail_init(&desc->chunks, &chan->desc.chunks_free);
+ list_add_tail(&desc->node, &chan->desc.free);
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+
+static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_desc *desc, *_desc;
+ LIST_HEAD(list);
+
+ /*
+ * We have to temporarily move all descriptors from the wait list to a
+ * local list as iterating over the wait list, even with
+ * list_for_each_entry_safe, isn't safe if we release the channel lock
+ * around the rcar_dmac_desc_put() call.
+ */
+ spin_lock_irq(&chan->lock);
+ list_splice_init(&chan->desc.wait, &list);
+ spin_unlock_irq(&chan->lock);
+
+ list_for_each_entry_safe(desc, _desc, &list, node) {
+ if (async_tx_test_ack(&desc->async_tx)) {
+ list_del(&desc->node);
+ rcar_dmac_desc_put(chan, desc);
+ }
+ }
+
+ if (list_empty(&list))
+ return;
+
+ /* Put the remaining descriptors back in the wait list. */
+ spin_lock_irq(&chan->lock);
+ list_splice(&list, &chan->desc.wait);
+ spin_unlock_irq(&chan->lock);
+}
+
+/*
+ * rcar_dmac_desc_get - Allocate a descriptor for a DMA transfer
+ * @chan: the DMA channel
+ *
+ * Locking: This function must be called in a non-atomic context.
+ *
+ * Return: A pointer to the allocated descriptor or NULL if no descriptor can
+ * be allocated.
+ */
+static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_desc *desc;
+ int ret;
+
+ /* Recycle acked descriptors before attempting allocation. */
+ rcar_dmac_desc_recycle_acked(chan);
+
+ spin_lock_irq(&chan->lock);
+
+ while (list_empty(&chan->desc.free)) {
+ /*
+ * No free descriptors, allocate a page worth of them and try
+ * again, as someone else could race us to get the newly
+ * allocated descriptors. If the allocation fails return an
+ * error.
+ */
+ spin_unlock_irq(&chan->lock);
+ ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
+ if (ret < 0)
+ return NULL;
+ spin_lock_irq(&chan->lock);
+ }
+
+ desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
+ list_del(&desc->node);
+
+ spin_unlock_irq(&chan->lock);
+
+ return desc;
+}
+
+/*
+ * rcar_dmac_xfer_chunk_alloc - Allocate a page worth of transfer chunks
+ * @chan: the DMA channel
+ * @gfp: allocation flags
+ */
+static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
+{
+ struct rcar_dmac_desc_page *page;
+ LIST_HEAD(list);
+ unsigned int i;
+
+ page = (void *)get_zeroed_page(gfp);
+ if (!page)
+ return -ENOMEM;
+
+ for (i = 0; i < RCAR_DMAC_XFER_CHUNKS_PER_PAGE; ++i) {
+ struct rcar_dmac_xfer_chunk *chunk = &page->chunks[i];
+
+ list_add_tail(&chunk->node, &list);
+ }
+
+ spin_lock_irq(&chan->lock);
+ list_splice_tail(&list, &chan->desc.chunks_free);
+ list_add_tail(&page->node, &chan->desc.pages);
+ spin_unlock_irq(&chan->lock);
+
+ return 0;
+}
+
+/*
+ * rcar_dmac_xfer_chunk_get - Allocate a transfer chunk for a DMA transfer
+ * @chan: the DMA channel
+ *
+ * Locking: This function must be called in a non-atomic context.
+ *
+ * Return: A pointer to the allocated transfer chunk descriptor or NULL if no
+ * descriptor can be allocated.
+ */
+static struct rcar_dmac_xfer_chunk *
+rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_xfer_chunk *chunk;
+ int ret;
+
+ spin_lock_irq(&chan->lock);
+
+ while (list_empty(&chan->desc.chunks_free)) {
+ /*
+ * No free descriptors, allocate a page worth of them and try
+ * again, as someone else could race us to get the newly
+ * allocated descriptors. If the allocation fails return an
+ * error.
+ */
+ spin_unlock_irq(&chan->lock);
+ ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
+ if (ret < 0)
+ return NULL;
+ spin_lock_irq(&chan->lock);
+ }
+
+ chunk = list_first_entry(&chan->desc.chunks_free,
+ struct rcar_dmac_xfer_chunk, node);
+ list_del(&chunk->node);
+
+ spin_unlock_irq(&chan->lock);
+
+ return chunk;
+}
+
+static void rcar_dmac_realloc_hwdesc(struct rcar_dmac_chan *chan,
+ struct rcar_dmac_desc *desc, size_t size)
+{
+ /*
+ * dma_alloc_coherent() allocates memory in page size increments. To
+ * avoid reallocating the hardware descriptors when the allocated size
+ * wouldn't change align the requested size to a multiple of the page
+ * size.
+ */
+ size = PAGE_ALIGN(size);
+
+ if (desc->hwdescs.size == size)
+ return;
+
+ if (desc->hwdescs.mem) {
+ dma_free_coherent(chan->chan.device->dev, desc->hwdescs.size,
+ desc->hwdescs.mem, desc->hwdescs.dma);
+ desc->hwdescs.mem = NULL;
+ desc->hwdescs.size = 0;
+ }
+
+ if (!size)
+ return;
+
+ desc->hwdescs.mem = dma_alloc_coherent(chan->chan.device->dev, size,
+ &desc->hwdescs.dma, GFP_NOWAIT);
+ if (!desc->hwdescs.mem)
+ return;
+
+ desc->hwdescs.size = size;
+}
+
+static int rcar_dmac_fill_hwdesc(struct rcar_dmac_chan *chan,
+ struct rcar_dmac_desc *desc)
+{
+ struct rcar_dmac_xfer_chunk *chunk;
+ struct rcar_dmac_hw_desc *hwdesc;
+
+ rcar_dmac_realloc_hwdesc(chan, desc, desc->nchunks * sizeof(*hwdesc));
+
+ hwdesc = desc->hwdescs.mem;
+ if (!hwdesc)
+ return -ENOMEM;
+
+ list_for_each_entry(chunk, &desc->chunks, node) {
+ hwdesc->sar = chunk->src_addr;
+ hwdesc->dar = chunk->dst_addr;
+ hwdesc->tcr = chunk->size >> desc->xfer_shift;
+ hwdesc++;
+ }
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Stop and reset
+ */
+
+static void rcar_dmac_chan_halt(struct rcar_dmac_chan *chan)
+{
+ u32 chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
+
+ chcr &= ~(RCAR_DMACHCR_DSE | RCAR_DMACHCR_DSIE | RCAR_DMACHCR_IE |
+ RCAR_DMACHCR_TE | RCAR_DMACHCR_DE);
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr);
+}
+
+static void rcar_dmac_chan_reinit(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_desc *desc, *_desc;
+ unsigned long flags;
+ LIST_HEAD(descs);
+
+ spin_lock_irqsave(&chan->lock, flags);
+
+ /* Move all non-free descriptors to the local lists. */
+ list_splice_init(&chan->desc.pending, &descs);
+ list_splice_init(&chan->desc.active, &descs);
+ list_splice_init(&chan->desc.done, &descs);
+ list_splice_init(&chan->desc.wait, &descs);
+
+ chan->desc.running = NULL;
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ list_for_each_entry_safe(desc, _desc, &descs, node) {
+ list_del(&desc->node);
+ rcar_dmac_desc_put(chan, desc);
+ }
+}
+
+static void rcar_dmac_stop(struct rcar_dmac *dmac)
+{
+ rcar_dmac_write(dmac, RCAR_DMAOR, 0);
+}
+
+static void rcar_dmac_abort(struct rcar_dmac *dmac)
+{
+ unsigned int i;
+
+ /* Stop all channels. */
+ for (i = 0; i < dmac->n_channels; ++i) {
+ struct rcar_dmac_chan *chan = &dmac->channels[i];
+
+ /* Stop and reinitialize the channel. */
+ spin_lock(&chan->lock);
+ rcar_dmac_chan_halt(chan);
+ spin_unlock(&chan->lock);
+
+ rcar_dmac_chan_reinit(chan);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * Descriptors preparation
+ */
+
+static void rcar_dmac_chan_configure_desc(struct rcar_dmac_chan *chan,
+ struct rcar_dmac_desc *desc)
+{
+ static const u32 chcr_ts[] = {
+ RCAR_DMACHCR_TS_1B, RCAR_DMACHCR_TS_2B,
+ RCAR_DMACHCR_TS_4B, RCAR_DMACHCR_TS_8B,
+ RCAR_DMACHCR_TS_16B, RCAR_DMACHCR_TS_32B,
+ RCAR_DMACHCR_TS_64B,
+ };
+
+ unsigned int xfer_size;
+ u32 chcr;
+
+ switch (desc->direction) {
+ case DMA_DEV_TO_MEM:
+ chcr = RCAR_DMACHCR_DM_INC | RCAR_DMACHCR_SM_FIXED
+ | RCAR_DMACHCR_RS_DMARS;
+ xfer_size = chan->src_xfer_size;
+ break;
+
+ case DMA_MEM_TO_DEV:
+ chcr = RCAR_DMACHCR_DM_FIXED | RCAR_DMACHCR_SM_INC
+ | RCAR_DMACHCR_RS_DMARS;
+ xfer_size = chan->dst_xfer_size;
+ break;
+
+ case DMA_MEM_TO_MEM:
+ default:
+ chcr = RCAR_DMACHCR_DM_INC | RCAR_DMACHCR_SM_INC
+ | RCAR_DMACHCR_RS_AUTO;
+ xfer_size = RCAR_DMAC_MEMCPY_XFER_SIZE;
+ break;
+ }
+
+ desc->xfer_shift = ilog2(xfer_size);
+ desc->chcr = chcr | chcr_ts[desc->xfer_shift];
+}
+
+/*
+ * rcar_dmac_chan_prep_sg - prepare transfer descriptors from an SG list
+ *
+ * Common routine for public (MEMCPY) and slave DMA. The MEMCPY case is also
+ * converted to scatter-gather to guarantee consistent locking and a correct
+ * list manipulation. For slave DMA direction carries the usual meaning, and,
+ * logically, the SG list is RAM and the addr variable contains slave address,
+ * e.g., the FIFO I/O register. For MEMCPY direction equals DMA_MEM_TO_MEM
+ * and the SG list contains only one element and points at the source buffer.
+ */
+static struct dma_async_tx_descriptor *
+rcar_dmac_chan_prep_sg(struct rcar_dmac_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, dma_addr_t dev_addr,
+ enum dma_transfer_direction dir, unsigned long dma_flags,
+ bool cyclic)
+{
+ struct rcar_dmac_xfer_chunk *chunk;
+ struct rcar_dmac_desc *desc;
+ struct scatterlist *sg;
+ unsigned int nchunks = 0;
+ unsigned int max_chunk_size;
+ unsigned int full_size = 0;
+ bool highmem = false;
+ unsigned int i;
+
+ desc = rcar_dmac_desc_get(chan);
+ if (!desc)
+ return NULL;
+
+ desc->async_tx.flags = dma_flags;
+ desc->async_tx.cookie = -EBUSY;
+
+ desc->cyclic = cyclic;
+ desc->direction = dir;
+
+ rcar_dmac_chan_configure_desc(chan, desc);
+
+ max_chunk_size = (RCAR_DMATCR_MASK + 1) << desc->xfer_shift;
+
+ /*
+ * Allocate and fill the transfer chunk descriptors. We own the only
+ * reference to the DMA descriptor, there's no need for locking.
+ */
+ for_each_sg(sgl, sg, sg_len, i) {
+ dma_addr_t mem_addr = sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
+
+ full_size += len;
+
+ while (len) {
+ unsigned int size = min(len, max_chunk_size);
+
+#ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT
+ /*
+ * Prevent individual transfers from crossing 4GB
+ * boundaries.
+ */
+ if (dev_addr >> 32 != (dev_addr + size - 1) >> 32)
+ size = ALIGN(dev_addr, 1ULL << 32) - dev_addr;
+ if (mem_addr >> 32 != (mem_addr + size - 1) >> 32)
+ size = ALIGN(mem_addr, 1ULL << 32) - mem_addr;
+
+ /*
+ * Check if either of the source or destination address
+ * can't be expressed in 32 bits. If so we can't use
+ * hardware descriptor lists.
+ */
+ if (dev_addr >> 32 || mem_addr >> 32)
+ highmem = true;
+#endif
+
+ chunk = rcar_dmac_xfer_chunk_get(chan);
+ if (!chunk) {
+ rcar_dmac_desc_put(chan, desc);
+ return NULL;
+ }
+
+ if (dir == DMA_DEV_TO_MEM) {
+ chunk->src_addr = dev_addr;
+ chunk->dst_addr = mem_addr;
+ } else {
+ chunk->src_addr = mem_addr;
+ chunk->dst_addr = dev_addr;
+ }
+
+ chunk->size = size;
+
+ dev_dbg(chan->chan.device->dev,
+ "chan%u: chunk %p/%p sgl %u@%p, %u/%u %pad -> %pad\n",
+ chan->index, chunk, desc, i, sg, size, len,
+ &chunk->src_addr, &chunk->dst_addr);
+
+ mem_addr += size;
+ if (dir == DMA_MEM_TO_MEM)
+ dev_addr += size;
+
+ len -= size;
+
+ list_add_tail(&chunk->node, &desc->chunks);
+ nchunks++;
+ }
+ }
+
+ desc->nchunks = nchunks;
+ desc->size = full_size;
+
+ /*
+ * Use hardware descriptor lists if possible when more than one chunk
+ * needs to be transferred (otherwise they don't make much sense).
+ *
+ * The highmem check currently covers the whole transfer. As an
+ * optimization we could use descriptor lists for consecutive lowmem
+ * chunks and direct manual mode for highmem chunks. Whether the
+ * performance improvement would be significant enough compared to the
+ * additional complexity remains to be investigated.
+ */
+ desc->hwdescs.use = !highmem && nchunks > 1;
+ if (desc->hwdescs.use) {
+ if (rcar_dmac_fill_hwdesc(chan, desc) < 0)
+ desc->hwdescs.use = false;
+ }
+
+ return &desc->async_tx;
+}
+
+/* -----------------------------------------------------------------------------
+ * DMA engine operations
+ */
+
+static int rcar_dmac_alloc_chan_resources(struct dma_chan *chan)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ int ret;
+
+ INIT_LIST_HEAD(&rchan->desc.chunks_free);
+ INIT_LIST_HEAD(&rchan->desc.pages);
+
+ /* Preallocate descriptors. */
+ ret = rcar_dmac_xfer_chunk_alloc(rchan, GFP_KERNEL);
+ if (ret < 0)
+ return -ENOMEM;
+
+ ret = rcar_dmac_desc_alloc(rchan, GFP_KERNEL);
+ if (ret < 0)
+ return -ENOMEM;
+
+ return pm_runtime_get_sync(chan->device->dev);
+}
+
+static void rcar_dmac_free_chan_resources(struct dma_chan *chan)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ struct rcar_dmac *dmac = to_rcar_dmac(chan->device);
+ struct rcar_dmac_desc_page *page, *_page;
+ struct rcar_dmac_desc *desc;
+ LIST_HEAD(list);
+
+ /* Protect against ISR */
+ spin_lock_irq(&rchan->lock);
+ rcar_dmac_chan_halt(rchan);
+ spin_unlock_irq(&rchan->lock);
+
+ /* Now no new interrupts will occur */
+
+ if (rchan->mid_rid >= 0) {
+ /* The caller is holding dma_list_mutex */
+ clear_bit(rchan->mid_rid, dmac->modules);
+ rchan->mid_rid = -EINVAL;
+ }
+
+ list_splice_init(&rchan->desc.free, &list);
+ list_splice_init(&rchan->desc.pending, &list);
+ list_splice_init(&rchan->desc.active, &list);
+ list_splice_init(&rchan->desc.done, &list);
+ list_splice_init(&rchan->desc.wait, &list);
+
+ list_for_each_entry(desc, &list, node)
+ rcar_dmac_realloc_hwdesc(rchan, desc, 0);
+
+ list_for_each_entry_safe(page, _page, &rchan->desc.pages, node) {
+ list_del(&page->node);
+ free_page((unsigned long)page);
+ }
+
+ pm_runtime_put(chan->device->dev);
+}
+
+static struct dma_async_tx_descriptor *
+rcar_dmac_prep_dma_memcpy(struct dma_chan *chan, dma_addr_t dma_dest,
+ dma_addr_t dma_src, size_t len, unsigned long flags)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ struct scatterlist sgl;
+
+ if (!len)
+ return NULL;
+
+ sg_init_table(&sgl, 1);
+ sg_set_page(&sgl, pfn_to_page(PFN_DOWN(dma_src)), len,
+ offset_in_page(dma_src));
+ sg_dma_address(&sgl) = dma_src;
+ sg_dma_len(&sgl) = len;
+
+ return rcar_dmac_chan_prep_sg(rchan, &sgl, 1, dma_dest,
+ DMA_MEM_TO_MEM, flags, false);
+}
+
+static struct dma_async_tx_descriptor *
+rcar_dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
+ unsigned int sg_len, enum dma_transfer_direction dir,
+ unsigned long flags, void *context)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ dma_addr_t dev_addr;
+
+ /* Someone calling slave DMA on a generic channel? */
+ if (rchan->mid_rid < 0 || !sg_len) {
+ dev_warn(chan->device->dev,
+ "%s: bad parameter: len=%d, id=%d\n",
+ __func__, sg_len, rchan->mid_rid);
+ return NULL;
+ }
+
+ dev_addr = dir == DMA_DEV_TO_MEM
+ ? rchan->src_slave_addr : rchan->dst_slave_addr;
+ return rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, dev_addr,
+ dir, flags, false);
+}
+
+#define RCAR_DMAC_MAX_SG_LEN 32
+
+static struct dma_async_tx_descriptor *
+rcar_dmac_prep_dma_cyclic(struct dma_chan *chan, dma_addr_t buf_addr,
+ size_t buf_len, size_t period_len,
+ enum dma_transfer_direction dir, unsigned long flags)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ struct dma_async_tx_descriptor *desc;
+ struct scatterlist *sgl;
+ dma_addr_t dev_addr;
+ unsigned int sg_len;
+ unsigned int i;
+
+ /* Someone calling slave DMA on a generic channel? */
+ if (rchan->mid_rid < 0 || buf_len < period_len) {
+ dev_warn(chan->device->dev,
+ "%s: bad parameter: buf_len=%zu, period_len=%zu, id=%d\n",
+ __func__, buf_len, period_len, rchan->mid_rid);
+ return NULL;
+ }
+
+ sg_len = buf_len / period_len;
+ if (sg_len > RCAR_DMAC_MAX_SG_LEN) {
+ dev_err(chan->device->dev,
+ "chan%u: sg length %d exceds limit %d",
+ rchan->index, sg_len, RCAR_DMAC_MAX_SG_LEN);
+ return NULL;
+ }
+
+ /*
+ * Allocate the sg list dynamically as it would consume too much stack
+ * space.
+ */
+ sgl = kcalloc(sg_len, sizeof(*sgl), GFP_NOWAIT);
+ if (!sgl)
+ return NULL;
+
+ sg_init_table(sgl, sg_len);
+
+ for (i = 0; i < sg_len; ++i) {
+ dma_addr_t src = buf_addr + (period_len * i);
+
+ sg_set_page(&sgl[i], pfn_to_page(PFN_DOWN(src)), period_len,
+ offset_in_page(src));
+ sg_dma_address(&sgl[i]) = src;
+ sg_dma_len(&sgl[i]) = period_len;
+ }
+
+ dev_addr = dir == DMA_DEV_TO_MEM
+ ? rchan->src_slave_addr : rchan->dst_slave_addr;
+ desc = rcar_dmac_chan_prep_sg(rchan, sgl, sg_len, dev_addr,
+ dir, flags, true);
+
+ kfree(sgl);
+ return desc;
+}
+
+static int rcar_dmac_device_config(struct dma_chan *chan,
+ struct dma_slave_config *cfg)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+
+ /*
+ * We could lock this, but you shouldn't be configuring the
+ * channel, while using it...
+ */
+ rchan->src_slave_addr = cfg->src_addr;
+ rchan->dst_slave_addr = cfg->dst_addr;
+ rchan->src_xfer_size = cfg->src_addr_width;
+ rchan->dst_xfer_size = cfg->dst_addr_width;
+
+ return 0;
+}
+
+static int rcar_dmac_chan_terminate_all(struct dma_chan *chan)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rchan->lock, flags);
+ rcar_dmac_chan_halt(rchan);
+ spin_unlock_irqrestore(&rchan->lock, flags);
+
+ /*
+ * FIXME: No new interrupt can occur now, but the IRQ thread might still
+ * be running.
+ */
+
+ rcar_dmac_chan_reinit(rchan);
+
+ return 0;
+}
+
+static unsigned int rcar_dmac_chan_get_residue(struct rcar_dmac_chan *chan,
+ dma_cookie_t cookie)
+{
+ struct rcar_dmac_desc *desc = chan->desc.running;
+ struct rcar_dmac_xfer_chunk *running = NULL;
+ struct rcar_dmac_xfer_chunk *chunk;
+ unsigned int residue = 0;
+ unsigned int dptr = 0;
+
+ if (!desc)
+ return 0;
+
+ /*
+ * If the cookie doesn't correspond to the currently running transfer
+ * then the descriptor hasn't been processed yet, and the residue is
+ * equal to the full descriptor size.
+ */
+ if (cookie != desc->async_tx.cookie)
+ return desc->size;
+
+ /*
+ * In descriptor mode the descriptor running pointer is not maintained
+ * by the interrupt handler, find the running descriptor from the
+ * descriptor pointer field in the CHCRB register. In non-descriptor
+ * mode just use the running descriptor pointer.
+ */
+ if (desc->hwdescs.use) {
+ dptr = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
+ RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT;
+ WARN_ON(dptr >= desc->nchunks);
+ } else {
+ running = desc->running;
+ }
+
+ /* Compute the size of all chunks still to be transferred. */
+ list_for_each_entry_reverse(chunk, &desc->chunks, node) {
+ if (chunk == running || ++dptr == desc->nchunks)
+ break;
+
+ residue += chunk->size;
+ }
+
+ /* Add the residue for the current chunk. */
+ residue += rcar_dmac_chan_read(chan, RCAR_DMATCR) << desc->xfer_shift;
+
+ return residue;
+}
+
+static enum dma_status rcar_dmac_tx_status(struct dma_chan *chan,
+ dma_cookie_t cookie,
+ struct dma_tx_state *txstate)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ enum dma_status status;
+ unsigned long flags;
+ unsigned int residue;
+
+ status = dma_cookie_status(chan, cookie, txstate);
+ if (status == DMA_COMPLETE || !txstate)
+ return status;
+
+ spin_lock_irqsave(&rchan->lock, flags);
+ residue = rcar_dmac_chan_get_residue(rchan, cookie);
+ spin_unlock_irqrestore(&rchan->lock, flags);
+
+ dma_set_residue(txstate, residue);
+
+ return status;
+}
+
+static void rcar_dmac_issue_pending(struct dma_chan *chan)
+{
+ struct rcar_dmac_chan *rchan = to_rcar_dmac_chan(chan);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rchan->lock, flags);
+
+ if (list_empty(&rchan->desc.pending))
+ goto done;
+
+ /* Append the pending list to the active list. */
+ list_splice_tail_init(&rchan->desc.pending, &rchan->desc.active);
+
+ /*
+ * If no transfer is running pick the first descriptor from the active
+ * list and start the transfer.
+ */
+ if (!rchan->desc.running) {
+ struct rcar_dmac_desc *desc;
+
+ desc = list_first_entry(&rchan->desc.active,
+ struct rcar_dmac_desc, node);
+ rchan->desc.running = desc;
+
+ rcar_dmac_chan_start_xfer(rchan);
+ }
+
+done:
+ spin_unlock_irqrestore(&rchan->lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * IRQ handling
+ */
+
+static irqreturn_t rcar_dmac_isr_desc_stage_end(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_desc *desc = chan->desc.running;
+ unsigned int stage;
+
+ if (WARN_ON(!desc || !desc->cyclic)) {
+ /*
+ * This should never happen, there should always be a running
+ * cyclic descriptor when a descriptor stage end interrupt is
+ * triggered. Warn and return.
+ */
+ return IRQ_NONE;
+ }
+
+ /* Program the interrupt pointer to the next stage. */
+ stage = (rcar_dmac_chan_read(chan, RCAR_DMACHCRB) &
+ RCAR_DMACHCRB_DPTR_MASK) >> RCAR_DMACHCRB_DPTR_SHIFT;
+ rcar_dmac_chan_write(chan, RCAR_DMADPCR, RCAR_DMADPCR_DIPT(stage));
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t rcar_dmac_isr_transfer_end(struct rcar_dmac_chan *chan)
+{
+ struct rcar_dmac_desc *desc = chan->desc.running;
+ irqreturn_t ret = IRQ_WAKE_THREAD;
+
+ if (WARN_ON_ONCE(!desc)) {
+ /*
+ * This should never happen, there should always be a running
+ * descriptor when a transfer end interrupt is triggered. Warn
+ * and return.
+ */
+ return IRQ_NONE;
+ }
+
+ /*
+ * The transfer end interrupt isn't generated for each chunk when using
+ * descriptor mode. Only update the running chunk pointer in
+ * non-descriptor mode.
+ */
+ if (!desc->hwdescs.use) {
+ /*
+ * If we haven't completed the last transfer chunk simply move
+ * to the next one. Only wake the IRQ thread if the transfer is
+ * cyclic.
+ */
+ if (!list_is_last(&desc->running->node, &desc->chunks)) {
+ desc->running = list_next_entry(desc->running, node);
+ if (!desc->cyclic)
+ ret = IRQ_HANDLED;
+ goto done;
+ }
+
+ /*
+ * We've completed the last transfer chunk. If the transfer is
+ * cyclic, move back to the first one.
+ */
+ if (desc->cyclic) {
+ desc->running =
+ list_first_entry(&desc->chunks,
+ struct rcar_dmac_xfer_chunk,
+ node);
+ goto done;
+ }
+ }
+
+ /* The descriptor is complete, move it to the done list. */
+ list_move_tail(&desc->node, &chan->desc.done);
+
+ /* Queue the next descriptor, if any. */
+ if (!list_empty(&chan->desc.active))
+ chan->desc.running = list_first_entry(&chan->desc.active,
+ struct rcar_dmac_desc,
+ node);
+ else
+ chan->desc.running = NULL;
+
+done:
+ if (chan->desc.running)
+ rcar_dmac_chan_start_xfer(chan);
+
+ return ret;
+}
+
+static irqreturn_t rcar_dmac_isr_channel(int irq, void *dev)
+{
+ u32 mask = RCAR_DMACHCR_DSE | RCAR_DMACHCR_TE;
+ struct rcar_dmac_chan *chan = dev;
+ irqreturn_t ret = IRQ_NONE;
+ u32 chcr;
+
+ spin_lock(&chan->lock);
+
+ chcr = rcar_dmac_chan_read(chan, RCAR_DMACHCR);
+ if (chcr & RCAR_DMACHCR_TE)
+ mask |= RCAR_DMACHCR_DE;
+ rcar_dmac_chan_write(chan, RCAR_DMACHCR, chcr & ~mask);
+
+ if (chcr & RCAR_DMACHCR_DSE)
+ ret |= rcar_dmac_isr_desc_stage_end(chan);
+
+ if (chcr & RCAR_DMACHCR_TE)
+ ret |= rcar_dmac_isr_transfer_end(chan);
+
+ spin_unlock(&chan->lock);
+
+ return ret;
+}
+
+static irqreturn_t rcar_dmac_isr_channel_thread(int irq, void *dev)
+{
+ struct rcar_dmac_chan *chan = dev;
+ struct rcar_dmac_desc *desc;
+
+ spin_lock_irq(&chan->lock);
+
+ /* For cyclic transfers notify the user after every chunk. */
+ if (chan->desc.running && chan->desc.running->cyclic) {
+ dma_async_tx_callback callback;
+ void *callback_param;
+
+ desc = chan->desc.running;
+ callback = desc->async_tx.callback;
+ callback_param = desc->async_tx.callback_param;
+
+ if (callback) {
+ spin_unlock_irq(&chan->lock);
+ callback(callback_param);
+ spin_lock_irq(&chan->lock);
+ }
+ }
+
+ /*
+ * Call the callback function for all descriptors on the done list and
+ * move them to the ack wait list.
+ */
+ while (!list_empty(&chan->desc.done)) {
+ desc = list_first_entry(&chan->desc.done, struct rcar_dmac_desc,
+ node);
+ dma_cookie_complete(&desc->async_tx);
+ list_del(&desc->node);
+
+ if (desc->async_tx.callback) {
+ spin_unlock_irq(&chan->lock);
+ /*
+ * We own the only reference to this descriptor, we can
+ * safely dereference it without holding the channel
+ * lock.
+ */
+ desc->async_tx.callback(desc->async_tx.callback_param);
+ spin_lock_irq(&chan->lock);
+ }
+
+ list_add_tail(&desc->node, &chan->desc.wait);
+ }
+
+ spin_unlock_irq(&chan->lock);
+
+ /* Recycle all acked descriptors. */
+ rcar_dmac_desc_recycle_acked(chan);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t rcar_dmac_isr_error(int irq, void *data)
+{
+ struct rcar_dmac *dmac = data;
+
+ if (!(rcar_dmac_read(dmac, RCAR_DMAOR) & RCAR_DMAOR_AE))
+ return IRQ_NONE;
+
+ /*
+ * An unrecoverable error occurred on an unknown channel. Halt the DMAC,
+ * abort transfers on all channels, and reinitialize the DMAC.
+ */
+ rcar_dmac_stop(dmac);
+ rcar_dmac_abort(dmac);
+ rcar_dmac_init(dmac);
+
+ return IRQ_HANDLED;
+}
+
+/* -----------------------------------------------------------------------------
+ * OF xlate and channel filter
+ */
+
+static bool rcar_dmac_chan_filter(struct dma_chan *chan, void *arg)
+{
+ struct rcar_dmac *dmac = to_rcar_dmac(chan->device);
+ struct of_phandle_args *dma_spec = arg;
+
+ /*
+ * FIXME: Using a filter on OF platforms is a nonsense. The OF xlate
+ * function knows from which device it wants to allocate a channel from,
+ * and would be perfectly capable of selecting the channel it wants.
+ * Forcing it to call dma_request_channel() and iterate through all
+ * channels from all controllers is just pointless.
+ */
+ if (chan->device->device_config != rcar_dmac_device_config ||
+ dma_spec->np != chan->device->dev->of_node)
+ return false;
+
+ return !test_and_set_bit(dma_spec->args[0], dmac->modules);
+}
+
+static struct dma_chan *rcar_dmac_of_xlate(struct of_phandle_args *dma_spec,
+ struct of_dma *ofdma)
+{
+ struct rcar_dmac_chan *rchan;
+ struct dma_chan *chan;
+ dma_cap_mask_t mask;
+
+ if (dma_spec->args_count != 1)
+ return NULL;
+
+ /* Only slave DMA channels can be allocated via DT */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ chan = dma_request_channel(mask, rcar_dmac_chan_filter, dma_spec);
+ if (!chan)
+ return NULL;
+
+ rchan = to_rcar_dmac_chan(chan);
+ rchan->mid_rid = dma_spec->args[0];
+
+ return chan;
+}
+
+/* -----------------------------------------------------------------------------
+ * Power management
+ */
+
+#ifdef CONFIG_PM_SLEEP
+static int rcar_dmac_sleep_suspend(struct device *dev)
+{
+ /*
+ * TODO: Wait for the current transfer to complete and stop the device.
+ */
+ return 0;
+}
+
+static int rcar_dmac_sleep_resume(struct device *dev)
+{
+ /* TODO: Resume transfers, if any. */
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM
+static int rcar_dmac_runtime_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int rcar_dmac_runtime_resume(struct device *dev)
+{
+ struct rcar_dmac *dmac = dev_get_drvdata(dev);
+
+ return rcar_dmac_init(dmac);
+}
+#endif
+
+static const struct dev_pm_ops rcar_dmac_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(rcar_dmac_sleep_suspend, rcar_dmac_sleep_resume)
+ SET_RUNTIME_PM_OPS(rcar_dmac_runtime_suspend, rcar_dmac_runtime_resume,
+ NULL)
+};
+
+/* -----------------------------------------------------------------------------
+ * Probe and remove
+ */
+
+static int rcar_dmac_chan_probe(struct rcar_dmac *dmac,
+ struct rcar_dmac_chan *rchan,
+ unsigned int index)
+{
+ struct platform_device *pdev = to_platform_device(dmac->dev);
+ struct dma_chan *chan = &rchan->chan;
+ char pdev_irqname[5];
+ char *irqname;
+ int irq;
+ int ret;
+
+ rchan->index = index;
+ rchan->iomem = dmac->iomem + RCAR_DMAC_CHAN_OFFSET(index);
+ rchan->mid_rid = -EINVAL;
+
+ spin_lock_init(&rchan->lock);
+
+ INIT_LIST_HEAD(&rchan->desc.free);
+ INIT_LIST_HEAD(&rchan->desc.pending);
+ INIT_LIST_HEAD(&rchan->desc.active);
+ INIT_LIST_HEAD(&rchan->desc.done);
+ INIT_LIST_HEAD(&rchan->desc.wait);
+
+ /* Request the channel interrupt. */
+ sprintf(pdev_irqname, "ch%u", index);
+ irq = platform_get_irq_byname(pdev, pdev_irqname);
+ if (irq < 0) {
+ dev_err(dmac->dev, "no IRQ specified for channel %u\n", index);
+ return -ENODEV;
+ }
+
+ irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:%u",
+ dev_name(dmac->dev), index);
+ if (!irqname)
+ return -ENOMEM;
+
+ ret = devm_request_threaded_irq(dmac->dev, irq, rcar_dmac_isr_channel,
+ rcar_dmac_isr_channel_thread, 0,
+ irqname, rchan);
+ if (ret) {
+ dev_err(dmac->dev, "failed to request IRQ %u (%d)\n", irq, ret);
+ return ret;
+ }
+
+ /*
+ * Initialize the DMA engine channel and add it to the DMA engine
+ * channels list.
+ */
+ chan->device = &dmac->engine;
+ dma_cookie_init(chan);
+
+ list_add_tail(&chan->device_node, &dmac->engine.channels);
+
+ return 0;
+}
+
+static int rcar_dmac_parse_of(struct device *dev, struct rcar_dmac *dmac)
+{
+ struct device_node *np = dev->of_node;
+ int ret;
+
+ ret = of_property_read_u32(np, "dma-channels", &dmac->n_channels);
+ if (ret < 0) {
+ dev_err(dev, "unable to read dma-channels property\n");
+ return ret;
+ }
+
+ if (dmac->n_channels <= 0 || dmac->n_channels >= 100) {
+ dev_err(dev, "invalid number of channels %u\n",
+ dmac->n_channels);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int rcar_dmac_probe(struct platform_device *pdev)
+{
+ const enum dma_slave_buswidth widths = DMA_SLAVE_BUSWIDTH_1_BYTE |
+ DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES |
+ DMA_SLAVE_BUSWIDTH_8_BYTES | DMA_SLAVE_BUSWIDTH_16_BYTES |
+ DMA_SLAVE_BUSWIDTH_32_BYTES | DMA_SLAVE_BUSWIDTH_64_BYTES;
+ unsigned int channels_offset = 0;
+ struct dma_device *engine;
+ struct rcar_dmac *dmac;
+ struct resource *mem;
+ unsigned int i;
+ char *irqname;
+ int irq;
+ int ret;
+
+ dmac = devm_kzalloc(&pdev->dev, sizeof(*dmac), GFP_KERNEL);
+ if (!dmac)
+ return -ENOMEM;
+
+ dmac->dev = &pdev->dev;
+ platform_set_drvdata(pdev, dmac);
+
+ ret = rcar_dmac_parse_of(&pdev->dev, dmac);
+ if (ret < 0)
+ return ret;
+
+ /*
+ * A still unconfirmed hardware bug prevents the IPMMU microTLB 0 to be
+ * flushed correctly, resulting in memory corruption. DMAC 0 channel 0
+ * is connected to microTLB 0 on currently supported platforms, so we
+ * can't use it with the IPMMU. As the IOMMU API operates at the device
+ * level we can't disable it selectively, so ignore channel 0 for now if
+ * the device is part of an IOMMU group.
+ */
+ if (pdev->dev.iommu_group) {
+ dmac->n_channels--;
+ channels_offset = 1;
+ }
+
+ dmac->channels = devm_kcalloc(&pdev->dev, dmac->n_channels,
+ sizeof(*dmac->channels), GFP_KERNEL);
+ if (!dmac->channels)
+ return -ENOMEM;
+
+ /* Request resources. */
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dmac->iomem = devm_ioremap_resource(&pdev->dev, mem);
+ if (IS_ERR(dmac->iomem))
+ return PTR_ERR(dmac->iomem);
+
+ irq = platform_get_irq_byname(pdev, "error");
+ if (irq < 0) {
+ dev_err(&pdev->dev, "no error IRQ specified\n");
+ return -ENODEV;
+ }
+
+ irqname = devm_kasprintf(dmac->dev, GFP_KERNEL, "%s:error",
+ dev_name(dmac->dev));
+ if (!irqname)
+ return -ENOMEM;
+
+ ret = devm_request_irq(&pdev->dev, irq, rcar_dmac_isr_error, 0,
+ irqname, dmac);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request IRQ %u (%d)\n",
+ irq, ret);
+ return ret;
+ }
+
+ /* Enable runtime PM and initialize the device. */
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "runtime PM get sync failed (%d)\n", ret);
+ return ret;
+ }
+
+ ret = rcar_dmac_init(dmac);
+ pm_runtime_put(&pdev->dev);
+
+ if (ret) {
+ dev_err(&pdev->dev, "failed to reset device\n");
+ goto error;
+ }
+
+ /* Initialize the channels. */
+ INIT_LIST_HEAD(&dmac->engine.channels);
+
+ for (i = 0; i < dmac->n_channels; ++i) {
+ ret = rcar_dmac_chan_probe(dmac, &dmac->channels[i],
+ i + channels_offset);
+ if (ret < 0)
+ goto error;
+ }
+
+ /* Register the DMAC as a DMA provider for DT. */
+ ret = of_dma_controller_register(pdev->dev.of_node, rcar_dmac_of_xlate,
+ NULL);
+ if (ret < 0)
+ goto error;
+
+ /*
+ * Register the DMA engine device.
+ *
+ * Default transfer size of 32 bytes requires 32-byte alignment.
+ */
+ engine = &dmac->engine;
+ dma_cap_set(DMA_MEMCPY, engine->cap_mask);
+ dma_cap_set(DMA_SLAVE, engine->cap_mask);
+
+ engine->dev = &pdev->dev;
+ engine->copy_align = ilog2(RCAR_DMAC_MEMCPY_XFER_SIZE);
+
+ engine->src_addr_widths = widths;
+ engine->dst_addr_widths = widths;
+ engine->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+ engine->residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
+
+ engine->device_alloc_chan_resources = rcar_dmac_alloc_chan_resources;
+ engine->device_free_chan_resources = rcar_dmac_free_chan_resources;
+ engine->device_prep_dma_memcpy = rcar_dmac_prep_dma_memcpy;
+ engine->device_prep_slave_sg = rcar_dmac_prep_slave_sg;
+ engine->device_prep_dma_cyclic = rcar_dmac_prep_dma_cyclic;
+ engine->device_config = rcar_dmac_device_config;
+ engine->device_terminate_all = rcar_dmac_chan_terminate_all;
+ engine->device_tx_status = rcar_dmac_tx_status;
+ engine->device_issue_pending = rcar_dmac_issue_pending;
+
+ ret = dma_async_device_register(engine);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ of_dma_controller_free(pdev->dev.of_node);
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+}
+
+static int rcar_dmac_remove(struct platform_device *pdev)
+{
+ struct rcar_dmac *dmac = platform_get_drvdata(pdev);
+
+ of_dma_controller_free(pdev->dev.of_node);
+ dma_async_device_unregister(&dmac->engine);
+
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+static void rcar_dmac_shutdown(struct platform_device *pdev)
+{
+ struct rcar_dmac *dmac = platform_get_drvdata(pdev);
+
+ rcar_dmac_stop(dmac);
+}
+
+static const struct of_device_id rcar_dmac_of_ids[] = {
+ { .compatible = "renesas,rcar-dmac", },
+ { /* Sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rcar_dmac_of_ids);
+
+static struct platform_driver rcar_dmac_driver = {
+ .driver = {
+ .pm = &rcar_dmac_pm,
+ .name = "rcar-dmac",
+ .of_match_table = rcar_dmac_of_ids,
+ },
+ .probe = rcar_dmac_probe,
+ .remove = rcar_dmac_remove,
+ .shutdown = rcar_dmac_shutdown,
+};
+
+module_platform_driver(rcar_dmac_driver);
+
+MODULE_DESCRIPTION("R-Car Gen2 DMA Controller Driver");
+MODULE_AUTHOR("Laurent Pinchart <laurent.pinchart@ideasonboard.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/dma/sh/rcar-hpbdma.c b/drivers/dma/sh/rcar-hpbdma.c
index 20a6f6f2a018..749f26ecd3b3 100644
--- a/drivers/dma/sh/rcar-hpbdma.c
+++ b/drivers/dma/sh/rcar-hpbdma.c
@@ -534,6 +534,8 @@ static int hpb_dmae_chan_probe(struct hpb_dmae_device *hpbdev, int id)
static int hpb_dmae_probe(struct platform_device *pdev)
{
+ const enum dma_slave_buswidth widths = DMA_SLAVE_BUSWIDTH_1_BYTE |
+ DMA_SLAVE_BUSWIDTH_2_BYTES | DMA_SLAVE_BUSWIDTH_4_BYTES;
struct hpb_dmae_pdata *pdata = pdev->dev.platform_data;
struct hpb_dmae_device *hpbdev;
struct dma_device *dma_dev;
@@ -595,6 +597,10 @@ static int hpb_dmae_probe(struct platform_device *pdev)
dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
dma_cap_set(DMA_SLAVE, dma_dev->cap_mask);
+ dma_dev->src_addr_widths = widths;
+ dma_dev->dst_addr_widths = widths;
+ dma_dev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+ dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
hpbdev->shdma_dev.ops = &hpb_dmae_ops;
hpbdev->shdma_dev.desc_size = sizeof(struct hpb_desc);
diff --git a/drivers/dma/sh/shdma-base.c b/drivers/dma/sh/shdma-base.c
index 3a2adb131d46..8ee383d339a5 100644
--- a/drivers/dma/sh/shdma-base.c
+++ b/drivers/dma/sh/shdma-base.c
@@ -729,57 +729,50 @@ static struct dma_async_tx_descriptor *shdma_prep_dma_cyclic(
return desc;
}
-static int shdma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int shdma_terminate_all(struct dma_chan *chan)
{
struct shdma_chan *schan = to_shdma_chan(chan);
struct shdma_dev *sdev = to_shdma_dev(chan->device);
const struct shdma_ops *ops = sdev->ops;
- struct dma_slave_config *config;
unsigned long flags;
- int ret;
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- spin_lock_irqsave(&schan->chan_lock, flags);
- ops->halt_channel(schan);
+ spin_lock_irqsave(&schan->chan_lock, flags);
+ ops->halt_channel(schan);
- if (ops->get_partial && !list_empty(&schan->ld_queue)) {
- /* Record partial transfer */
- struct shdma_desc *desc = list_first_entry(&schan->ld_queue,
- struct shdma_desc, node);
- desc->partial = ops->get_partial(schan, desc);
- }
+ if (ops->get_partial && !list_empty(&schan->ld_queue)) {
+ /* Record partial transfer */
+ struct shdma_desc *desc = list_first_entry(&schan->ld_queue,
+ struct shdma_desc, node);
+ desc->partial = ops->get_partial(schan, desc);
+ }
- spin_unlock_irqrestore(&schan->chan_lock, flags);
+ spin_unlock_irqrestore(&schan->chan_lock, flags);
- shdma_chan_ld_cleanup(schan, true);
- break;
- case DMA_SLAVE_CONFIG:
- /*
- * So far only .slave_id is used, but the slave drivers are
- * encouraged to also set a transfer direction and an address.
- */
- if (!arg)
- return -EINVAL;
- /*
- * We could lock this, but you shouldn't be configuring the
- * channel, while using it...
- */
- config = (struct dma_slave_config *)arg;
- ret = shdma_setup_slave(schan, config->slave_id,
- config->direction == DMA_DEV_TO_MEM ?
- config->src_addr : config->dst_addr);
- if (ret < 0)
- return ret;
- break;
- default:
- return -ENXIO;
- }
+ shdma_chan_ld_cleanup(schan, true);
return 0;
}
+static int shdma_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct shdma_chan *schan = to_shdma_chan(chan);
+
+ /*
+ * So far only .slave_id is used, but the slave drivers are
+ * encouraged to also set a transfer direction and an address.
+ */
+ if (!config)
+ return -EINVAL;
+ /*
+ * We could lock this, but you shouldn't be configuring the
+ * channel, while using it...
+ */
+ return shdma_setup_slave(schan, config->slave_id,
+ config->direction == DMA_DEV_TO_MEM ?
+ config->src_addr : config->dst_addr);
+}
+
static void shdma_issue_pending(struct dma_chan *chan)
{
struct shdma_chan *schan = to_shdma_chan(chan);
@@ -1002,7 +995,8 @@ int shdma_init(struct device *dev, struct shdma_dev *sdev,
/* Compulsory for DMA_SLAVE fields */
dma_dev->device_prep_slave_sg = shdma_prep_slave_sg;
dma_dev->device_prep_dma_cyclic = shdma_prep_dma_cyclic;
- dma_dev->device_control = shdma_control;
+ dma_dev->device_config = shdma_config;
+ dma_dev->device_terminate_all = shdma_terminate_all;
dma_dev->dev = dev;
diff --git a/drivers/dma/sh/shdmac.c b/drivers/dma/sh/shdmac.c
index aec8a84784a4..b2431aa30033 100644
--- a/drivers/dma/sh/shdmac.c
+++ b/drivers/dma/sh/shdmac.c
@@ -588,6 +588,7 @@ static void sh_dmae_shutdown(struct platform_device *pdev)
sh_dmae_ctl_stop(shdev);
}
+#ifdef CONFIG_PM
static int sh_dmae_runtime_suspend(struct device *dev)
{
return 0;
@@ -599,8 +600,9 @@ static int sh_dmae_runtime_resume(struct device *dev)
return sh_dmae_rst(shdev);
}
+#endif
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int sh_dmae_suspend(struct device *dev)
{
return 0;
@@ -632,16 +634,12 @@ static int sh_dmae_resume(struct device *dev)
return 0;
}
-#else
-#define sh_dmae_suspend NULL
-#define sh_dmae_resume NULL
#endif
static const struct dev_pm_ops sh_dmae_pm = {
- .suspend = sh_dmae_suspend,
- .resume = sh_dmae_resume,
- .runtime_suspend = sh_dmae_runtime_suspend,
- .runtime_resume = sh_dmae_runtime_resume,
+ SET_SYSTEM_SLEEP_PM_OPS(sh_dmae_suspend, sh_dmae_resume)
+ SET_RUNTIME_PM_OPS(sh_dmae_runtime_suspend, sh_dmae_runtime_resume,
+ NULL)
};
static dma_addr_t sh_dmae_slave_addr(struct shdma_chan *schan)
@@ -684,6 +682,10 @@ MODULE_DEVICE_TABLE(of, sh_dmae_of_match);
static int sh_dmae_probe(struct platform_device *pdev)
{
+ const enum dma_slave_buswidth widths =
+ DMA_SLAVE_BUSWIDTH_1_BYTE | DMA_SLAVE_BUSWIDTH_2_BYTES |
+ DMA_SLAVE_BUSWIDTH_4_BYTES | DMA_SLAVE_BUSWIDTH_8_BYTES |
+ DMA_SLAVE_BUSWIDTH_16_BYTES | DMA_SLAVE_BUSWIDTH_32_BYTES;
const struct sh_dmae_pdata *pdata;
unsigned long chan_flag[SH_DMAE_MAX_CHANNELS] = {};
int chan_irq[SH_DMAE_MAX_CHANNELS];
@@ -746,6 +748,11 @@ static int sh_dmae_probe(struct platform_device *pdev)
return PTR_ERR(shdev->dmars);
}
+ dma_dev->src_addr_widths = widths;
+ dma_dev->dst_addr_widths = widths;
+ dma_dev->directions = BIT(DMA_MEM_TO_DEV) | BIT(DMA_DEV_TO_MEM);
+ dma_dev->residue_granularity = DMA_RESIDUE_GRANULARITY_DESCRIPTOR;
+
if (!pdata->slave_only)
dma_cap_set(DMA_MEMCPY, dma_dev->cap_mask);
if (pdata->slave && pdata->slave_num)
diff --git a/drivers/dma/sirf-dma.c b/drivers/dma/sirf-dma.c
index 3492a5f91d31..d0086e9f2082 100644
--- a/drivers/dma/sirf-dma.c
+++ b/drivers/dma/sirf-dma.c
@@ -281,9 +281,10 @@ static dma_cookie_t sirfsoc_dma_tx_submit(struct dma_async_tx_descriptor *txd)
return cookie;
}
-static int sirfsoc_dma_slave_config(struct sirfsoc_dma_chan *schan,
- struct dma_slave_config *config)
+static int sirfsoc_dma_slave_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
{
+ struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
unsigned long flags;
if ((config->src_addr_width != DMA_SLAVE_BUSWIDTH_4_BYTES) ||
@@ -297,8 +298,9 @@ static int sirfsoc_dma_slave_config(struct sirfsoc_dma_chan *schan,
return 0;
}
-static int sirfsoc_dma_terminate_all(struct sirfsoc_dma_chan *schan)
+static int sirfsoc_dma_terminate_all(struct dma_chan *chan)
{
+ struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
int cid = schan->chan.chan_id;
unsigned long flags;
@@ -327,8 +329,9 @@ static int sirfsoc_dma_terminate_all(struct sirfsoc_dma_chan *schan)
return 0;
}
-static int sirfsoc_dma_pause_chan(struct sirfsoc_dma_chan *schan)
+static int sirfsoc_dma_pause_chan(struct dma_chan *chan)
{
+ struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
int cid = schan->chan.chan_id;
unsigned long flags;
@@ -348,8 +351,9 @@ static int sirfsoc_dma_pause_chan(struct sirfsoc_dma_chan *schan)
return 0;
}
-static int sirfsoc_dma_resume_chan(struct sirfsoc_dma_chan *schan)
+static int sirfsoc_dma_resume_chan(struct dma_chan *chan)
{
+ struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
struct sirfsoc_dma *sdma = dma_chan_to_sirfsoc_dma(&schan->chan);
int cid = schan->chan.chan_id;
unsigned long flags;
@@ -369,30 +373,6 @@ static int sirfsoc_dma_resume_chan(struct sirfsoc_dma_chan *schan)
return 0;
}
-static int sirfsoc_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct dma_slave_config *config;
- struct sirfsoc_dma_chan *schan = dma_chan_to_sirfsoc_dma_chan(chan);
-
- switch (cmd) {
- case DMA_PAUSE:
- return sirfsoc_dma_pause_chan(schan);
- case DMA_RESUME:
- return sirfsoc_dma_resume_chan(schan);
- case DMA_TERMINATE_ALL:
- return sirfsoc_dma_terminate_all(schan);
- case DMA_SLAVE_CONFIG:
- config = (struct dma_slave_config *)arg;
- return sirfsoc_dma_slave_config(schan, config);
-
- default:
- break;
- }
-
- return -ENOSYS;
-}
-
/* Alloc channel resources */
static int sirfsoc_dma_alloc_chan_resources(struct dma_chan *chan)
{
@@ -648,18 +628,6 @@ EXPORT_SYMBOL(sirfsoc_dma_filter_id);
BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) | \
BIT(DMA_SLAVE_BUSWIDTH_8_BYTES))
-static int sirfsoc_dma_device_slave_caps(struct dma_chan *dchan,
- struct dma_slave_caps *caps)
-{
- caps->src_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
- caps->dstn_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
- caps->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
- caps->cmd_pause = true;
- caps->cmd_terminate = true;
-
- return 0;
-}
-
static struct dma_chan *of_dma_sirfsoc_xlate(struct of_phandle_args *dma_spec,
struct of_dma *ofdma)
{
@@ -739,11 +707,16 @@ static int sirfsoc_dma_probe(struct platform_device *op)
dma->device_alloc_chan_resources = sirfsoc_dma_alloc_chan_resources;
dma->device_free_chan_resources = sirfsoc_dma_free_chan_resources;
dma->device_issue_pending = sirfsoc_dma_issue_pending;
- dma->device_control = sirfsoc_dma_control;
+ dma->device_config = sirfsoc_dma_slave_config;
+ dma->device_pause = sirfsoc_dma_pause_chan;
+ dma->device_resume = sirfsoc_dma_resume_chan;
+ dma->device_terminate_all = sirfsoc_dma_terminate_all;
dma->device_tx_status = sirfsoc_dma_tx_status;
dma->device_prep_interleaved_dma = sirfsoc_dma_prep_interleaved;
dma->device_prep_dma_cyclic = sirfsoc_dma_prep_cyclic;
- dma->device_slave_caps = sirfsoc_dma_device_slave_caps;
+ dma->src_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
+ dma->dst_addr_widths = SIRFSOC_DMA_BUSWIDTHS;
+ dma->directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
INIT_LIST_HEAD(&dma->channels);
dma_cap_set(DMA_SLAVE, dma->cap_mask);
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 15d49461c0d2..68aca3334a17 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -1429,11 +1429,17 @@ static bool d40_tx_is_linked(struct d40_chan *d40c)
return is_link;
}
-static int d40_pause(struct d40_chan *d40c)
+static int d40_pause(struct dma_chan *chan)
{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
int res = 0;
unsigned long flags;
+ if (d40c->phy_chan == NULL) {
+ chan_err(d40c, "Channel is not allocated!\n");
+ return -EINVAL;
+ }
+
if (!d40c->busy)
return 0;
@@ -1448,11 +1454,17 @@ static int d40_pause(struct d40_chan *d40c)
return res;
}
-static int d40_resume(struct d40_chan *d40c)
+static int d40_resume(struct dma_chan *chan)
{
+ struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
int res = 0;
unsigned long flags;
+ if (d40c->phy_chan == NULL) {
+ chan_err(d40c, "Channel is not allocated!\n");
+ return -EINVAL;
+ }
+
if (!d40c->busy)
return 0;
@@ -2604,12 +2616,17 @@ static void d40_issue_pending(struct dma_chan *chan)
spin_unlock_irqrestore(&d40c->lock, flags);
}
-static void d40_terminate_all(struct dma_chan *chan)
+static int d40_terminate_all(struct dma_chan *chan)
{
unsigned long flags;
struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
int ret;
+ if (d40c->phy_chan == NULL) {
+ chan_err(d40c, "Channel is not allocated!\n");
+ return -EINVAL;
+ }
+
spin_lock_irqsave(&d40c->lock, flags);
pm_runtime_get_sync(d40c->base->dev);
@@ -2627,6 +2644,7 @@ static void d40_terminate_all(struct dma_chan *chan)
d40c->busy = false;
spin_unlock_irqrestore(&d40c->lock, flags);
+ return 0;
}
static int
@@ -2673,6 +2691,11 @@ static int d40_set_runtime_config(struct dma_chan *chan,
u32 src_maxburst, dst_maxburst;
int ret;
+ if (d40c->phy_chan == NULL) {
+ chan_err(d40c, "Channel is not allocated!\n");
+ return -EINVAL;
+ }
+
src_addr_width = config->src_addr_width;
src_maxburst = config->src_maxburst;
dst_addr_width = config->dst_addr_width;
@@ -2781,35 +2804,6 @@ static int d40_set_runtime_config(struct dma_chan *chan,
return 0;
}
-static int d40_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- struct d40_chan *d40c = container_of(chan, struct d40_chan, chan);
-
- if (d40c->phy_chan == NULL) {
- chan_err(d40c, "Channel is not allocated!\n");
- return -EINVAL;
- }
-
- switch (cmd) {
- case DMA_TERMINATE_ALL:
- d40_terminate_all(chan);
- return 0;
- case DMA_PAUSE:
- return d40_pause(d40c);
- case DMA_RESUME:
- return d40_resume(d40c);
- case DMA_SLAVE_CONFIG:
- return d40_set_runtime_config(chan,
- (struct dma_slave_config *) arg);
- default:
- break;
- }
-
- /* Other commands are unimplemented */
- return -ENXIO;
-}
-
/* Initialization functions */
static void __init d40_chan_init(struct d40_base *base, struct dma_device *dma,
@@ -2870,7 +2864,10 @@ static void d40_ops_init(struct d40_base *base, struct dma_device *dev)
dev->device_free_chan_resources = d40_free_chan_resources;
dev->device_issue_pending = d40_issue_pending;
dev->device_tx_status = d40_tx_status;
- dev->device_control = d40_control;
+ dev->device_config = d40_set_runtime_config;
+ dev->device_pause = d40_pause;
+ dev->device_resume = d40_resume;
+ dev->device_terminate_all = d40_terminate_all;
dev->dev = base->dev;
}
diff --git a/drivers/dma/sun6i-dma.c b/drivers/dma/sun6i-dma.c
index 159f1736a16f..7ebcf9bec698 100644
--- a/drivers/dma/sun6i-dma.c
+++ b/drivers/dma/sun6i-dma.c
@@ -355,38 +355,6 @@ static void sun6i_dma_free_desc(struct virt_dma_desc *vd)
kfree(txd);
}
-static int sun6i_dma_terminate_all(struct sun6i_vchan *vchan)
-{
- struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
- struct sun6i_pchan *pchan = vchan->phy;
- unsigned long flags;
- LIST_HEAD(head);
-
- spin_lock(&sdev->lock);
- list_del_init(&vchan->node);
- spin_unlock(&sdev->lock);
-
- spin_lock_irqsave(&vchan->vc.lock, flags);
-
- vchan_get_all_descriptors(&vchan->vc, &head);
-
- if (pchan) {
- writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE);
- writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE);
-
- vchan->phy = NULL;
- pchan->vchan = NULL;
- pchan->desc = NULL;
- pchan->done = NULL;
- }
-
- spin_unlock_irqrestore(&vchan->vc.lock, flags);
-
- vchan_dma_desc_free_list(&vchan->vc, &head);
-
- return 0;
-}
-
static int sun6i_dma_start_desc(struct sun6i_vchan *vchan)
{
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(vchan->vc.chan.device);
@@ -675,57 +643,92 @@ err_lli_free:
return NULL;
}
-static int sun6i_dma_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int sun6i_dma_config(struct dma_chan *chan,
+ struct dma_slave_config *config)
+{
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+
+ memcpy(&vchan->cfg, config, sizeof(*config));
+
+ return 0;
+}
+
+static int sun6i_dma_pause(struct dma_chan *chan)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ struct sun6i_pchan *pchan = vchan->phy;
+
+ dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc);
+
+ if (pchan) {
+ writel(DMA_CHAN_PAUSE_PAUSE,
+ pchan->base + DMA_CHAN_PAUSE);
+ } else {
+ spin_lock(&sdev->lock);
+ list_del_init(&vchan->node);
+ spin_unlock(&sdev->lock);
+ }
+
+ return 0;
+}
+
+static int sun6i_dma_resume(struct dma_chan *chan)
{
struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
struct sun6i_pchan *pchan = vchan->phy;
unsigned long flags;
- int ret = 0;
- switch (cmd) {
- case DMA_RESUME:
- dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
+ dev_dbg(chan2dev(chan), "vchan %p: resume\n", &vchan->vc);
- spin_lock_irqsave(&vchan->vc.lock, flags);
+ spin_lock_irqsave(&vchan->vc.lock, flags);
- if (pchan) {
- writel(DMA_CHAN_PAUSE_RESUME,
- pchan->base + DMA_CHAN_PAUSE);
- } else if (!list_empty(&vchan->vc.desc_issued)) {
- spin_lock(&sdev->lock);
- list_add_tail(&vchan->node, &sdev->pending);
- spin_unlock(&sdev->lock);
- }
+ if (pchan) {
+ writel(DMA_CHAN_PAUSE_RESUME,
+ pchan->base + DMA_CHAN_PAUSE);
+ } else if (!list_empty(&vchan->vc.desc_issued)) {
+ spin_lock(&sdev->lock);
+ list_add_tail(&vchan->node, &sdev->pending);
+ spin_unlock(&sdev->lock);
+ }
- spin_unlock_irqrestore(&vchan->vc.lock, flags);
- break;
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
- case DMA_PAUSE:
- dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc);
+ return 0;
+}
- if (pchan) {
- writel(DMA_CHAN_PAUSE_PAUSE,
- pchan->base + DMA_CHAN_PAUSE);
- } else {
- spin_lock(&sdev->lock);
- list_del_init(&vchan->node);
- spin_unlock(&sdev->lock);
- }
- break;
-
- case DMA_TERMINATE_ALL:
- ret = sun6i_dma_terminate_all(vchan);
- break;
- case DMA_SLAVE_CONFIG:
- memcpy(&vchan->cfg, (void *)arg, sizeof(struct dma_slave_config));
- break;
- default:
- ret = -ENXIO;
- break;
+static int sun6i_dma_terminate_all(struct dma_chan *chan)
+{
+ struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device);
+ struct sun6i_vchan *vchan = to_sun6i_vchan(chan);
+ struct sun6i_pchan *pchan = vchan->phy;
+ unsigned long flags;
+ LIST_HEAD(head);
+
+ spin_lock(&sdev->lock);
+ list_del_init(&vchan->node);
+ spin_unlock(&sdev->lock);
+
+ spin_lock_irqsave(&vchan->vc.lock, flags);
+
+ vchan_get_all_descriptors(&vchan->vc, &head);
+
+ if (pchan) {
+ writel(DMA_CHAN_ENABLE_STOP, pchan->base + DMA_CHAN_ENABLE);
+ writel(DMA_CHAN_PAUSE_RESUME, pchan->base + DMA_CHAN_PAUSE);
+
+ vchan->phy = NULL;
+ pchan->vchan = NULL;
+ pchan->desc = NULL;
+ pchan->done = NULL;
}
- return ret;
+
+ spin_unlock_irqrestore(&vchan->vc.lock, flags);
+
+ vchan_dma_desc_free_list(&vchan->vc, &head);
+
+ return 0;
}
static enum dma_status sun6i_dma_tx_status(struct dma_chan *chan,
@@ -960,9 +963,20 @@ static int sun6i_dma_probe(struct platform_device *pdev)
sdc->slave.device_issue_pending = sun6i_dma_issue_pending;
sdc->slave.device_prep_slave_sg = sun6i_dma_prep_slave_sg;
sdc->slave.device_prep_dma_memcpy = sun6i_dma_prep_dma_memcpy;
- sdc->slave.device_control = sun6i_dma_control;
sdc->slave.copy_align = 4;
-
+ sdc->slave.device_config = sun6i_dma_config;
+ sdc->slave.device_pause = sun6i_dma_pause;
+ sdc->slave.device_resume = sun6i_dma_resume;
+ sdc->slave.device_terminate_all = sun6i_dma_terminate_all;
+ sdc->slave.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ sdc->slave.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES);
+ sdc->slave.directions = BIT(DMA_DEV_TO_MEM) |
+ BIT(DMA_MEM_TO_DEV);
+ sdc->slave.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST;
sdc->slave.dev = &pdev->dev;
sdc->pchans = devm_kcalloc(&pdev->dev, sdc->cfg->nr_max_channels,
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index d8450c3f35f0..eaf585e8286b 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -723,7 +723,7 @@ end:
return;
}
-static void tegra_dma_terminate_all(struct dma_chan *dc)
+static int tegra_dma_terminate_all(struct dma_chan *dc)
{
struct tegra_dma_channel *tdc = to_tegra_dma_chan(dc);
struct tegra_dma_sg_req *sgreq;
@@ -736,7 +736,7 @@ static void tegra_dma_terminate_all(struct dma_chan *dc)
spin_lock_irqsave(&tdc->lock, flags);
if (list_empty(&tdc->pending_sg_req)) {
spin_unlock_irqrestore(&tdc->lock, flags);
- return;
+ return 0;
}
if (!tdc->busy)
@@ -777,6 +777,7 @@ skip_dma_stop:
dma_desc->cb_count = 0;
}
spin_unlock_irqrestore(&tdc->lock, flags);
+ return 0;
}
static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
@@ -827,25 +828,6 @@ static enum dma_status tegra_dma_tx_status(struct dma_chan *dc,
return ret;
}
-static int tegra_dma_device_control(struct dma_chan *dc, enum dma_ctrl_cmd cmd,
- unsigned long arg)
-{
- switch (cmd) {
- case DMA_SLAVE_CONFIG:
- return tegra_dma_slave_config(dc,
- (struct dma_slave_config *)arg);
-
- case DMA_TERMINATE_ALL:
- tegra_dma_terminate_all(dc);
- return 0;
-
- default:
- break;
- }
-
- return -ENXIO;
-}
-
static inline int get_bus_width(struct tegra_dma_channel *tdc,
enum dma_slave_buswidth slave_bw)
{
@@ -1443,7 +1425,23 @@ static int tegra_dma_probe(struct platform_device *pdev)
tegra_dma_free_chan_resources;
tdma->dma_dev.device_prep_slave_sg = tegra_dma_prep_slave_sg;
tdma->dma_dev.device_prep_dma_cyclic = tegra_dma_prep_dma_cyclic;
- tdma->dma_dev.device_control = tegra_dma_device_control;
+ tdma->dma_dev.src_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
+ tdma->dma_dev.dst_addr_widths = BIT(DMA_SLAVE_BUSWIDTH_1_BYTE) |
+ BIT(DMA_SLAVE_BUSWIDTH_2_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_4_BYTES) |
+ BIT(DMA_SLAVE_BUSWIDTH_8_BYTES);
+ tdma->dma_dev.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV);
+ /*
+ * XXX The hardware appears to support
+ * DMA_RESIDUE_GRANULARITY_BURST-level reporting, but it's
+ * only used by this driver during tegra_dma_terminate_all()
+ */
+ tdma->dma_dev.residue_granularity = DMA_RESIDUE_GRANULARITY_SEGMENT;
+ tdma->dma_dev.device_config = tegra_dma_slave_config;
+ tdma->dma_dev.device_terminate_all = tegra_dma_terminate_all;
tdma->dma_dev.device_tx_status = tegra_dma_tx_status;
tdma->dma_dev.device_issue_pending = tegra_dma_issue_pending;
diff --git a/drivers/dma/timb_dma.c b/drivers/dma/timb_dma.c
index 2407ccf1a64b..c4c3d93fdd1b 100644
--- a/drivers/dma/timb_dma.c
+++ b/drivers/dma/timb_dma.c
@@ -561,8 +561,7 @@ static struct dma_async_tx_descriptor *td_prep_slave_sg(struct dma_chan *chan,
return &td_desc->txd;
}
-static int td_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int td_terminate_all(struct dma_chan *chan)
{
struct timb_dma_chan *td_chan =
container_of(chan, struct timb_dma_chan, chan);
@@ -570,9 +569,6 @@ static int td_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
dev_dbg(chan2dev(chan), "%s: Entry\n", __func__);
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
-
/* first the easy part, put the queue into the free list */
spin_lock_bh(&td_chan->lock);
list_for_each_entry_safe(td_desc, _td_desc, &td_chan->queue,
@@ -697,7 +693,7 @@ static int td_probe(struct platform_device *pdev)
dma_cap_set(DMA_SLAVE, td->dma.cap_mask);
dma_cap_set(DMA_PRIVATE, td->dma.cap_mask);
td->dma.device_prep_slave_sg = td_prep_slave_sg;
- td->dma.device_control = td_control;
+ td->dma.device_terminate_all = td_terminate_all;
td->dma.dev = &pdev->dev;
diff --git a/drivers/dma/txx9dmac.c b/drivers/dma/txx9dmac.c
index 0659ec9c4488..8849318b32b7 100644
--- a/drivers/dma/txx9dmac.c
+++ b/drivers/dma/txx9dmac.c
@@ -901,17 +901,12 @@ txx9dmac_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
return &first->txd;
}
-static int txx9dmac_control(struct dma_chan *chan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int txx9dmac_terminate_all(struct dma_chan *chan)
{
struct txx9dmac_chan *dc = to_txx9dmac_chan(chan);
struct txx9dmac_desc *desc, *_desc;
LIST_HEAD(list);
- /* Only supports DMA_TERMINATE_ALL */
- if (cmd != DMA_TERMINATE_ALL)
- return -EINVAL;
-
dev_vdbg(chan2dev(chan), "terminate_all\n");
spin_lock_bh(&dc->lock);
@@ -1109,7 +1104,7 @@ static int __init txx9dmac_chan_probe(struct platform_device *pdev)
dc->dma.dev = &pdev->dev;
dc->dma.device_alloc_chan_resources = txx9dmac_alloc_chan_resources;
dc->dma.device_free_chan_resources = txx9dmac_free_chan_resources;
- dc->dma.device_control = txx9dmac_control;
+ dc->dma.device_terminate_all = txx9dmac_terminate_all;
dc->dma.device_tx_status = txx9dmac_tx_status;
dc->dma.device_issue_pending = txx9dmac_issue_pending;
if (pdata && pdata->memcpy_chan == ch) {
diff --git a/drivers/dma/xilinx/xilinx_vdma.c b/drivers/dma/xilinx/xilinx_vdma.c
index 4a3a8f3137b3..bdd2a5dd7220 100644
--- a/drivers/dma/xilinx/xilinx_vdma.c
+++ b/drivers/dma/xilinx/xilinx_vdma.c
@@ -1001,13 +1001,17 @@ error:
* xilinx_vdma_terminate_all - Halt the channel and free descriptors
* @chan: Driver specific VDMA Channel pointer
*/
-static void xilinx_vdma_terminate_all(struct xilinx_vdma_chan *chan)
+static int xilinx_vdma_terminate_all(struct dma_chan *dchan)
{
+ struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
+
/* Halt the DMA engine */
xilinx_vdma_halt(chan);
/* Remove and free all of the descriptors in the lists */
xilinx_vdma_free_descriptors(chan);
+
+ return 0;
}
/**
@@ -1075,27 +1079,6 @@ int xilinx_vdma_channel_set_config(struct dma_chan *dchan,
}
EXPORT_SYMBOL(xilinx_vdma_channel_set_config);
-/**
- * xilinx_vdma_device_control - Configure DMA channel of the device
- * @dchan: DMA Channel pointer
- * @cmd: DMA control command
- * @arg: Channel configuration
- *
- * Return: '0' on success and failure value on error
- */
-static int xilinx_vdma_device_control(struct dma_chan *dchan,
- enum dma_ctrl_cmd cmd, unsigned long arg)
-{
- struct xilinx_vdma_chan *chan = to_xilinx_chan(dchan);
-
- if (cmd != DMA_TERMINATE_ALL)
- return -ENXIO;
-
- xilinx_vdma_terminate_all(chan);
-
- return 0;
-}
-
/* -----------------------------------------------------------------------------
* Probe and remove
*/
@@ -1300,7 +1283,7 @@ static int xilinx_vdma_probe(struct platform_device *pdev)
xilinx_vdma_free_chan_resources;
xdev->common.device_prep_interleaved_dma =
xilinx_vdma_dma_prep_interleaved;
- xdev->common.device_control = xilinx_vdma_device_control;
+ xdev->common.device_terminate_all = xilinx_vdma_terminate_all;
xdev->common.device_tx_status = xilinx_vdma_tx_status;
xdev->common.device_issue_pending = xilinx_vdma_issue_pending;
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 49c265255a07..cb59619df23f 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -385,4 +385,11 @@ config EDAC_ALTERA_MC
preloader must initialize the SDRAM before loading
the kernel.
+config EDAC_SYNOPSYS
+ tristate "Synopsys DDR Memory Controller"
+ depends on EDAC_MM_EDAC && ARCH_ZYNQ
+ help
+ Support for error detection and correction on the Synopsys DDR
+ memory controller.
+
endif # EDAC
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index d40c69a04df7..b255f362b1db 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -67,3 +67,4 @@ obj-$(CONFIG_EDAC_OCTEON_LMC) += octeon_edac-lmc.o
obj-$(CONFIG_EDAC_OCTEON_PCI) += octeon_edac-pci.o
obj-$(CONFIG_EDAC_ALTERA_MC) += altera_edac.o
+obj-$(CONFIG_EDAC_SYNOPSYS) += synopsys_edac.o
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index 17638d7cf5c2..5907c1718f8c 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -2174,14 +2174,20 @@ static void __log_bus_error(struct mem_ctl_info *mci, struct err_info *err,
static inline void decode_bus_error(int node_id, struct mce *m)
{
- struct mem_ctl_info *mci = mcis[node_id];
- struct amd64_pvt *pvt = mci->pvt_info;
+ struct mem_ctl_info *mci;
+ struct amd64_pvt *pvt;
u8 ecc_type = (m->status >> 45) & 0x3;
u8 xec = XEC(m->status, 0x1f);
u16 ec = EC(m->status);
u64 sys_addr;
struct err_info err;
+ mci = edac_mc_find(node_id);
+ if (!mci)
+ return;
+
+ pvt = mci->pvt_info;
+
/* Bail out early if this was an 'observed' error */
if (PP(ec) == NBSL_PP_OBS)
return;
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index 670d2829c547..c84eecb191ef 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -157,7 +157,7 @@ struct dev_ch_attribute {
};
#define DEVICE_CHANNEL(_name, _mode, _show, _store, _var) \
- struct dev_ch_attribute dev_attr_legacy_##_name = \
+ static struct dev_ch_attribute dev_attr_legacy_##_name = \
{ __ATTR(_name, _mode, _show, _store), (_var) }
#define to_channel(k) (container_of(k, struct dev_ch_attribute, attr)->channel)
@@ -850,20 +850,20 @@ static const struct file_operations debug_fake_inject_fops = {
#endif
/* default Control file */
-DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
+static DEVICE_ATTR(reset_counters, S_IWUSR, NULL, mci_reset_counters_store);
/* default Attribute files */
-DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
-DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
-DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
-DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
-DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
-DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
-DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
-DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
+static DEVICE_ATTR(mc_name, S_IRUGO, mci_ctl_name_show, NULL);
+static DEVICE_ATTR(size_mb, S_IRUGO, mci_size_mb_show, NULL);
+static DEVICE_ATTR(seconds_since_reset, S_IRUGO, mci_seconds_show, NULL);
+static DEVICE_ATTR(ue_noinfo_count, S_IRUGO, mci_ue_noinfo_show, NULL);
+static DEVICE_ATTR(ce_noinfo_count, S_IRUGO, mci_ce_noinfo_show, NULL);
+static DEVICE_ATTR(ue_count, S_IRUGO, mci_ue_count_show, NULL);
+static DEVICE_ATTR(ce_count, S_IRUGO, mci_ce_count_show, NULL);
+static DEVICE_ATTR(max_location, S_IRUGO, mci_max_location_show, NULL);
/* memory scrubber attribute file */
-DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL);
+static DEVICE_ATTR(sdram_scrub_rate, 0, NULL, NULL);
static struct attribute *mci_attrs[] = {
&dev_attr_reset_counters.attr,
@@ -989,7 +989,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
err = bus_register(mci->bus);
if (err < 0)
- return err;
+ goto fail_free_name;
/* get the /sys/devices/system/edac subsys reference */
mci->dev.type = &mci_attr_type;
@@ -1005,9 +1005,7 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
err = device_add(&mci->dev);
if (err < 0) {
edac_dbg(1, "failure: create device %s\n", dev_name(&mci->dev));
- bus_unregister(mci->bus);
- kfree(mci->bus->name);
- return err;
+ goto fail_unregister_bus;
}
if (mci->set_sdram_scrub_rate || mci->get_sdram_scrub_rate) {
@@ -1015,15 +1013,16 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
dev_attr_sdram_scrub_rate.attr.mode |= S_IRUGO;
dev_attr_sdram_scrub_rate.show = &mci_sdram_scrub_rate_show;
}
+
if (mci->set_sdram_scrub_rate) {
dev_attr_sdram_scrub_rate.attr.mode |= S_IWUSR;
dev_attr_sdram_scrub_rate.store = &mci_sdram_scrub_rate_store;
}
- err = device_create_file(&mci->dev,
- &dev_attr_sdram_scrub_rate);
+
+ err = device_create_file(&mci->dev, &dev_attr_sdram_scrub_rate);
if (err) {
edac_dbg(1, "failure: create sdram_scrub_rate\n");
- goto fail2;
+ goto fail_unregister_dev;
}
}
/*
@@ -1032,8 +1031,9 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
for (i = 0; i < mci->tot_dimms; i++) {
struct dimm_info *dimm = mci->dimms[i];
/* Only expose populated DIMMs */
- if (dimm->nr_pages == 0)
+ if (!dimm->nr_pages)
continue;
+
#ifdef CONFIG_EDAC_DEBUG
edac_dbg(1, "creating dimm%d, located at ", i);
if (edac_debug_level >= 1) {
@@ -1048,14 +1048,14 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
err = edac_create_dimm_object(mci, dimm, i);
if (err) {
edac_dbg(1, "failure: create dimm %d obj\n", i);
- goto fail;
+ goto fail_unregister_dimm;
}
}
#ifdef CONFIG_EDAC_LEGACY_SYSFS
err = edac_create_csrow_objects(mci);
if (err < 0)
- goto fail;
+ goto fail_unregister_dimm;
#endif
#ifdef CONFIG_EDAC_DEBUG
@@ -1063,16 +1063,19 @@ int edac_create_sysfs_mci_device(struct mem_ctl_info *mci)
#endif
return 0;
-fail:
+fail_unregister_dimm:
for (i--; i >= 0; i--) {
struct dimm_info *dimm = mci->dimms[i];
- if (dimm->nr_pages == 0)
+ if (!dimm->nr_pages)
continue;
+
device_unregister(&dimm->dev);
}
-fail2:
+fail_unregister_dev:
device_unregister(&mci->dev);
+fail_unregister_bus:
bus_unregister(mci->bus);
+fail_free_name:
kfree(mci->bus->name);
return err;
}
diff --git a/drivers/edac/i5100_edac.c b/drivers/edac/i5100_edac.c
index 6247d186177e..e9f8a393915a 100644
--- a/drivers/edac/i5100_edac.c
+++ b/drivers/edac/i5100_edac.c
@@ -279,11 +279,6 @@ static inline u32 i5100_recmema_rank(u32 a)
return i5100_nrecmema_rank(a);
}
-static inline u32 i5100_recmema_dm_buf_id(u32 a)
-{
- return i5100_nrecmema_dm_buf_id(a);
-}
-
static inline u32 i5100_recmemb_cas(u32 a)
{
return i5100_nrecmemb_cas(a);
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 0bd91a802c67..f7681b553fd5 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -197,7 +197,7 @@ static int inj_bank_get(void *data, u64 *val)
DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
-struct dfs_node {
+static struct dfs_node {
char *name;
struct dentry *d;
const struct file_operations *fops;
diff --git a/drivers/edac/mpc85xx_edac.c b/drivers/edac/mpc85xx_edac.c
index ffb1a9a15ccd..1fa76a588af3 100644
--- a/drivers/edac/mpc85xx_edac.c
+++ b/drivers/edac/mpc85xx_edac.c
@@ -1,5 +1,5 @@
/*
- * Freescale MPC85xx Memory Controller kenel module
+ * Freescale MPC85xx Memory Controller kernel module
*
* Parts Copyrighted (c) 2013 by Freescale Semiconductor, Inc.
*
diff --git a/drivers/edac/mpc85xx_edac.h b/drivers/edac/mpc85xx_edac.h
index 8c6256436227..4498baf9ce05 100644
--- a/drivers/edac/mpc85xx_edac.h
+++ b/drivers/edac/mpc85xx_edac.h
@@ -1,5 +1,5 @@
/*
- * Freescale MPC85xx Memory Controller kenel module
+ * Freescale MPC85xx Memory Controller kernel module
* Author: Dave Jiang <djiang@mvista.com>
*
* 2006-2007 (c) MontaVista Software, Inc. This file is licensed under
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index 6366e880f978..0574e1bbe45c 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -789,7 +789,8 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev)
ctl = (ctl & 0xff00ffff) | 0x10000;
out_le32(pdata->mc_vbase + MV64X60_SDRAM_ERR_ECC_CNTL, ctl);
- if (edac_mc_add_mc(mci)) {
+ res = edac_mc_add_mc(mci);
+ if (res) {
edac_dbg(3, "failed edac_mc_add_mc()\n");
goto err;
}
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index 63aa6730e89e..1acf57ba4c86 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -2447,7 +2447,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_ibridge_table);
type = IVY_BRIDGE;
break;
- case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA:
+ case PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0:
rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_sbridge_table);
type = SANDY_BRIDGE;
break;
@@ -2460,8 +2460,11 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
type = BROADWELL;
break;
}
- if (unlikely(rc < 0))
+ if (unlikely(rc < 0)) {
+ edac_dbg(0, "couldn't get all devices for 0x%x\n", pdev->device);
goto fail0;
+ }
+
mc = 0;
list_for_each_entry(sbridge_dev, &sbridge_edac_list, list) {
@@ -2474,7 +2477,7 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto fail1;
}
- sbridge_printk(KERN_INFO, "Driver loaded.\n");
+ sbridge_printk(KERN_INFO, "%s\n", SBRIDGE_REVISION);
mutex_unlock(&sbridge_edac_lock);
return 0;
diff --git a/drivers/edac/synopsys_edac.c b/drivers/edac/synopsys_edac.c
new file mode 100644
index 000000000000..1c9691535e13
--- /dev/null
+++ b/drivers/edac/synopsys_edac.c
@@ -0,0 +1,535 @@
+/*
+ * Synopsys DDR ECC Driver
+ * This driver is based on ppc4xx_edac.c drivers
+ *
+ * Copyright (C) 2012 - 2014 Xilinx, 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.
+ *
+ * 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/edac.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include "edac_core.h"
+
+/* Number of cs_rows needed per memory controller */
+#define SYNPS_EDAC_NR_CSROWS 1
+
+/* Number of channels per memory controller */
+#define SYNPS_EDAC_NR_CHANS 1
+
+/* Granularity of reported error in bytes */
+#define SYNPS_EDAC_ERR_GRAIN 1
+
+#define SYNPS_EDAC_MSG_SIZE 256
+
+#define SYNPS_EDAC_MOD_STRING "synps_edac"
+#define SYNPS_EDAC_MOD_VER "1"
+
+/* Synopsys DDR memory controller registers that are relevant to ECC */
+#define CTRL_OFST 0x0
+#define T_ZQ_OFST 0xA4
+
+/* ECC control register */
+#define ECC_CTRL_OFST 0xC4
+/* ECC log register */
+#define CE_LOG_OFST 0xC8
+/* ECC address register */
+#define CE_ADDR_OFST 0xCC
+/* ECC data[31:0] register */
+#define CE_DATA_31_0_OFST 0xD0
+
+/* Uncorrectable error info registers */
+#define UE_LOG_OFST 0xDC
+#define UE_ADDR_OFST 0xE0
+#define UE_DATA_31_0_OFST 0xE4
+
+#define STAT_OFST 0xF0
+#define SCRUB_OFST 0xF4
+
+/* Control register bit field definitions */
+#define CTRL_BW_MASK 0xC
+#define CTRL_BW_SHIFT 2
+
+#define DDRCTL_WDTH_16 1
+#define DDRCTL_WDTH_32 0
+
+/* ZQ register bit field definitions */
+#define T_ZQ_DDRMODE_MASK 0x2
+
+/* ECC control register bit field definitions */
+#define ECC_CTRL_CLR_CE_ERR 0x2
+#define ECC_CTRL_CLR_UE_ERR 0x1
+
+/* ECC correctable/uncorrectable error log register definitions */
+#define LOG_VALID 0x1
+#define CE_LOG_BITPOS_MASK 0xFE
+#define CE_LOG_BITPOS_SHIFT 1
+
+/* ECC correctable/uncorrectable error address register definitions */
+#define ADDR_COL_MASK 0xFFF
+#define ADDR_ROW_MASK 0xFFFF000
+#define ADDR_ROW_SHIFT 12
+#define ADDR_BANK_MASK 0x70000000
+#define ADDR_BANK_SHIFT 28
+
+/* ECC statistic register definitions */
+#define STAT_UECNT_MASK 0xFF
+#define STAT_CECNT_MASK 0xFF00
+#define STAT_CECNT_SHIFT 8
+
+/* ECC scrub register definitions */
+#define SCRUB_MODE_MASK 0x7
+#define SCRUB_MODE_SECDED 0x4
+
+/**
+ * struct ecc_error_info - ECC error log information
+ * @row: Row number
+ * @col: Column number
+ * @bank: Bank number
+ * @bitpos: Bit position
+ * @data: Data causing the error
+ */
+struct ecc_error_info {
+ u32 row;
+ u32 col;
+ u32 bank;
+ u32 bitpos;
+ u32 data;
+};
+
+/**
+ * struct synps_ecc_status - ECC status information to report
+ * @ce_cnt: Correctable error count
+ * @ue_cnt: Uncorrectable error count
+ * @ceinfo: Correctable error log information
+ * @ueinfo: Uncorrectable error log information
+ */
+struct synps_ecc_status {
+ u32 ce_cnt;
+ u32 ue_cnt;
+ struct ecc_error_info ceinfo;
+ struct ecc_error_info ueinfo;
+};
+
+/**
+ * struct synps_edac_priv - DDR memory controller private instance data
+ * @baseaddr: Base address of the DDR controller
+ * @message: Buffer for framing the event specific info
+ * @stat: ECC status information
+ * @ce_cnt: Correctable Error count
+ * @ue_cnt: Uncorrectable Error count
+ */
+struct synps_edac_priv {
+ void __iomem *baseaddr;
+ char message[SYNPS_EDAC_MSG_SIZE];
+ struct synps_ecc_status stat;
+ u32 ce_cnt;
+ u32 ue_cnt;
+};
+
+/**
+ * synps_edac_geterror_info - Get the current ecc error info
+ * @base: Pointer to the base address of the ddr memory controller
+ * @p: Pointer to the synopsys ecc status structure
+ *
+ * Determines there is any ecc error or not
+ *
+ * Return: one if there is no error otherwise returns zero
+ */
+static int synps_edac_geterror_info(void __iomem *base,
+ struct synps_ecc_status *p)
+{
+ u32 regval, clearval = 0;
+
+ regval = readl(base + STAT_OFST);
+ if (!regval)
+ return 1;
+
+ p->ce_cnt = (regval & STAT_CECNT_MASK) >> STAT_CECNT_SHIFT;
+ p->ue_cnt = regval & STAT_UECNT_MASK;
+
+ regval = readl(base + CE_LOG_OFST);
+ if (!(p->ce_cnt && (regval & LOG_VALID)))
+ goto ue_err;
+
+ p->ceinfo.bitpos = (regval & CE_LOG_BITPOS_MASK) >> CE_LOG_BITPOS_SHIFT;
+ regval = readl(base + CE_ADDR_OFST);
+ p->ceinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
+ p->ceinfo.col = regval & ADDR_COL_MASK;
+ p->ceinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
+ p->ceinfo.data = readl(base + CE_DATA_31_0_OFST);
+ edac_dbg(3, "ce bit position: %d data: %d\n", p->ceinfo.bitpos,
+ p->ceinfo.data);
+ clearval = ECC_CTRL_CLR_CE_ERR;
+
+ue_err:
+ regval = readl(base + UE_LOG_OFST);
+ if (!(p->ue_cnt && (regval & LOG_VALID)))
+ goto out;
+
+ regval = readl(base + UE_ADDR_OFST);
+ p->ueinfo.row = (regval & ADDR_ROW_MASK) >> ADDR_ROW_SHIFT;
+ p->ueinfo.col = regval & ADDR_COL_MASK;
+ p->ueinfo.bank = (regval & ADDR_BANK_MASK) >> ADDR_BANK_SHIFT;
+ p->ueinfo.data = readl(base + UE_DATA_31_0_OFST);
+ clearval |= ECC_CTRL_CLR_UE_ERR;
+
+out:
+ writel(clearval, base + ECC_CTRL_OFST);
+ writel(0x0, base + ECC_CTRL_OFST);
+
+ return 0;
+}
+
+/**
+ * synps_edac_handle_error - Handle controller error types CE and UE
+ * @mci: Pointer to the edac memory controller instance
+ * @p: Pointer to the synopsys ecc status structure
+ *
+ * Handles the controller ECC correctable and un correctable error.
+ */
+static void synps_edac_handle_error(struct mem_ctl_info *mci,
+ struct synps_ecc_status *p)
+{
+ struct synps_edac_priv *priv = mci->pvt_info;
+ struct ecc_error_info *pinf;
+
+ if (p->ce_cnt) {
+ pinf = &p->ceinfo;
+ snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+ "DDR ECC error type :%s Row %d Bank %d Col %d ",
+ "CE", pinf->row, pinf->bank, pinf->col);
+ edac_mc_handle_error(HW_EVENT_ERR_CORRECTED, mci,
+ p->ce_cnt, 0, 0, 0, 0, 0, -1,
+ priv->message, "");
+ }
+
+ if (p->ue_cnt) {
+ pinf = &p->ueinfo;
+ snprintf(priv->message, SYNPS_EDAC_MSG_SIZE,
+ "DDR ECC error type :%s Row %d Bank %d Col %d ",
+ "UE", pinf->row, pinf->bank, pinf->col);
+ edac_mc_handle_error(HW_EVENT_ERR_UNCORRECTED, mci,
+ p->ue_cnt, 0, 0, 0, 0, 0, -1,
+ priv->message, "");
+ }
+
+ memset(p, 0, sizeof(*p));
+}
+
+/**
+ * synps_edac_check - Check controller for ECC errors
+ * @mci: Pointer to the edac memory controller instance
+ *
+ * Used to check and post ECC errors. Called by the polling thread
+ */
+static void synps_edac_check(struct mem_ctl_info *mci)
+{
+ struct synps_edac_priv *priv = mci->pvt_info;
+ int status;
+
+ status = synps_edac_geterror_info(priv->baseaddr, &priv->stat);
+ if (status)
+ return;
+
+ priv->ce_cnt += priv->stat.ce_cnt;
+ priv->ue_cnt += priv->stat.ue_cnt;
+ synps_edac_handle_error(mci, &priv->stat);
+
+ edac_dbg(3, "Total error count ce %d ue %d\n",
+ priv->ce_cnt, priv->ue_cnt);
+}
+
+/**
+ * synps_edac_get_dtype - Return the controller memory width
+ * @base: Pointer to the ddr memory controller base address
+ *
+ * Get the EDAC device type width appropriate for the current controller
+ * configuration.
+ *
+ * Return: a device type width enumeration.
+ */
+static enum dev_type synps_edac_get_dtype(const void __iomem *base)
+{
+ enum dev_type dt;
+ u32 width;
+
+ width = readl(base + CTRL_OFST);
+ width = (width & CTRL_BW_MASK) >> CTRL_BW_SHIFT;
+
+ switch (width) {
+ case DDRCTL_WDTH_16:
+ dt = DEV_X2;
+ break;
+ case DDRCTL_WDTH_32:
+ dt = DEV_X4;
+ break;
+ default:
+ dt = DEV_UNKNOWN;
+ }
+
+ return dt;
+}
+
+/**
+ * synps_edac_get_eccstate - Return the controller ecc enable/disable status
+ * @base: Pointer to the ddr memory controller base address
+ *
+ * Get the ECC enable/disable status for the controller
+ *
+ * Return: a ecc status boolean i.e true/false - enabled/disabled.
+ */
+static bool synps_edac_get_eccstate(void __iomem *base)
+{
+ enum dev_type dt;
+ u32 ecctype;
+ bool state = false;
+
+ dt = synps_edac_get_dtype(base);
+ if (dt == DEV_UNKNOWN)
+ return state;
+
+ ecctype = readl(base + SCRUB_OFST) & SCRUB_MODE_MASK;
+ if ((ecctype == SCRUB_MODE_SECDED) && (dt == DEV_X2))
+ state = true;
+
+ return state;
+}
+
+/**
+ * synps_edac_get_memsize - reads the size of the attached memory device
+ *
+ * Return: the memory size in bytes
+ */
+static u32 synps_edac_get_memsize(void)
+{
+ struct sysinfo inf;
+
+ si_meminfo(&inf);
+
+ return inf.totalram * inf.mem_unit;
+}
+
+/**
+ * synps_edac_get_mtype - Returns controller memory type
+ * @base: pointer to the synopsys ecc status structure
+ *
+ * Get the EDAC memory type appropriate for the current controller
+ * configuration.
+ *
+ * Return: a memory type enumeration.
+ */
+static enum mem_type synps_edac_get_mtype(const void __iomem *base)
+{
+ enum mem_type mt;
+ u32 memtype;
+
+ memtype = readl(base + T_ZQ_OFST);
+
+ if (memtype & T_ZQ_DDRMODE_MASK)
+ mt = MEM_DDR3;
+ else
+ mt = MEM_DDR2;
+
+ return mt;
+}
+
+/**
+ * synps_edac_init_csrows - Initialize the cs row data
+ * @mci: Pointer to the edac memory controller instance
+ *
+ * Initializes the chip select rows associated with the EDAC memory
+ * controller instance
+ *
+ * Return: Unconditionally 0.
+ */
+static int synps_edac_init_csrows(struct mem_ctl_info *mci)
+{
+ struct csrow_info *csi;
+ struct dimm_info *dimm;
+ struct synps_edac_priv *priv = mci->pvt_info;
+ u32 size;
+ int row, j;
+
+ for (row = 0; row < mci->nr_csrows; row++) {
+ csi = mci->csrows[row];
+ size = synps_edac_get_memsize();
+
+ for (j = 0; j < csi->nr_channels; j++) {
+ dimm = csi->channels[j]->dimm;
+ dimm->edac_mode = EDAC_FLAG_SECDED;
+ dimm->mtype = synps_edac_get_mtype(priv->baseaddr);
+ dimm->nr_pages = (size >> PAGE_SHIFT) / csi->nr_channels;
+ dimm->grain = SYNPS_EDAC_ERR_GRAIN;
+ dimm->dtype = synps_edac_get_dtype(priv->baseaddr);
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * synps_edac_mc_init - Initialize driver instance
+ * @mci: Pointer to the edac memory controller instance
+ * @pdev: Pointer to the platform_device struct
+ *
+ * Performs initialization of the EDAC memory controller instance and
+ * related driver-private data associated with the memory controller the
+ * instance is bound to.
+ *
+ * Return: Always zero.
+ */
+static int synps_edac_mc_init(struct mem_ctl_info *mci,
+ struct platform_device *pdev)
+{
+ int status;
+ struct synps_edac_priv *priv;
+
+ mci->pdev = &pdev->dev;
+ priv = mci->pvt_info;
+ platform_set_drvdata(pdev, mci);
+
+ /* Initialize controller capabilities and configuration */
+ mci->mtype_cap = MEM_FLAG_DDR3 | MEM_FLAG_DDR2;
+ mci->edac_ctl_cap = EDAC_FLAG_NONE | EDAC_FLAG_SECDED;
+ mci->scrub_cap = SCRUB_HW_SRC;
+ mci->scrub_mode = SCRUB_NONE;
+
+ mci->edac_cap = EDAC_FLAG_SECDED;
+ mci->ctl_name = "synps_ddr_controller";
+ mci->dev_name = SYNPS_EDAC_MOD_STRING;
+ mci->mod_name = SYNPS_EDAC_MOD_VER;
+ mci->mod_ver = "1";
+
+ edac_op_state = EDAC_OPSTATE_POLL;
+ mci->edac_check = synps_edac_check;
+ mci->ctl_page_to_phys = NULL;
+
+ status = synps_edac_init_csrows(mci);
+
+ return status;
+}
+
+/**
+ * synps_edac_mc_probe - Check controller and bind driver
+ * @pdev: Pointer to the platform_device struct
+ *
+ * Probes a specific controller instance for binding with the driver.
+ *
+ * Return: 0 if the controller instance was successfully bound to the
+ * driver; otherwise, < 0 on error.
+ */
+static int synps_edac_mc_probe(struct platform_device *pdev)
+{
+ struct mem_ctl_info *mci;
+ struct edac_mc_layer layers[2];
+ struct synps_edac_priv *priv;
+ int rc;
+ struct resource *res;
+ void __iomem *baseaddr;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ baseaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(baseaddr))
+ return PTR_ERR(baseaddr);
+
+ if (!synps_edac_get_eccstate(baseaddr)) {
+ edac_printk(KERN_INFO, EDAC_MC, "ECC not enabled\n");
+ return -ENXIO;
+ }
+
+ layers[0].type = EDAC_MC_LAYER_CHIP_SELECT;
+ layers[0].size = SYNPS_EDAC_NR_CSROWS;
+ layers[0].is_virt_csrow = true;
+ layers[1].type = EDAC_MC_LAYER_CHANNEL;
+ layers[1].size = SYNPS_EDAC_NR_CHANS;
+ layers[1].is_virt_csrow = false;
+
+ mci = edac_mc_alloc(0, ARRAY_SIZE(layers), layers,
+ sizeof(struct synps_edac_priv));
+ if (!mci) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed memory allocation for mc instance\n");
+ return -ENOMEM;
+ }
+
+ priv = mci->pvt_info;
+ priv->baseaddr = baseaddr;
+ rc = synps_edac_mc_init(mci, pdev);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed to initialize instance\n");
+ goto free_edac_mc;
+ }
+
+ rc = edac_mc_add_mc(mci);
+ if (rc) {
+ edac_printk(KERN_ERR, EDAC_MC,
+ "Failed to register with EDAC core\n");
+ goto free_edac_mc;
+ }
+
+ /*
+ * Start capturing the correctable and uncorrectable errors. A write of
+ * 0 starts the counters.
+ */
+ writel(0x0, baseaddr + ECC_CTRL_OFST);
+ return rc;
+
+free_edac_mc:
+ edac_mc_free(mci);
+
+ return rc;
+}
+
+/**
+ * synps_edac_mc_remove - Unbind driver from controller
+ * @pdev: Pointer to the platform_device struct
+ *
+ * Return: Unconditionally 0
+ */
+static int synps_edac_mc_remove(struct platform_device *pdev)
+{
+ struct mem_ctl_info *mci = platform_get_drvdata(pdev);
+
+ edac_mc_del_mc(&pdev->dev);
+ edac_mc_free(mci);
+
+ return 0;
+}
+
+static struct of_device_id synps_edac_match[] = {
+ { .compatible = "xlnx,zynq-ddrc-a05", },
+ { /* end of table */ }
+};
+
+MODULE_DEVICE_TABLE(of, synps_edac_match);
+
+static struct platform_driver synps_edac_mc_driver = {
+ .driver = {
+ .name = "synopsys-edac",
+ .of_match_table = synps_edac_match,
+ },
+ .probe = synps_edac_mc_probe,
+ .remove = synps_edac_mc_remove,
+};
+
+module_platform_driver(synps_edac_mc_driver);
+
+MODULE_AUTHOR("Xilinx Inc");
+MODULE_DESCRIPTION("Synopsys DDR ECC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/extcon/extcon-adc-jack.c b/drivers/extcon/extcon-adc-jack.c
index 5d7ab577fba9..2bb82e55065a 100644
--- a/drivers/extcon/extcon-adc-jack.c
+++ b/drivers/extcon/extcon-adc-jack.c
@@ -173,6 +173,7 @@ static int adc_jack_remove(struct platform_device *pdev)
free_irq(data->irq, data);
cancel_work_sync(&data->handler.work);
+ iio_channel_release(data->chan);
return 0;
}
diff --git a/drivers/extcon/extcon-class.c b/drivers/extcon/extcon-class.c
index 043dcd9946c9..8319f25b7145 100644
--- a/drivers/extcon/extcon-class.c
+++ b/drivers/extcon/extcon-class.c
@@ -32,7 +32,6 @@
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/of.h>
/*
* extcon_cable_name suggests the standard cable names for commonly used
diff --git a/drivers/extcon/extcon-max77693.c b/drivers/extcon/extcon-max77693.c
index 740a14d35072..af165fd0c6f5 100644
--- a/drivers/extcon/extcon-max77693.c
+++ b/drivers/extcon/extcon-max77693.c
@@ -1033,7 +1033,7 @@ static irqreturn_t max77693_muic_irq_handler(int irq, void *data)
return IRQ_HANDLED;
}
-static struct regmap_config max77693_muic_regmap_config = {
+static const struct regmap_config max77693_muic_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
diff --git a/drivers/firewire/core-transaction.c b/drivers/firewire/core-transaction.c
index eb6935c8ad94..d6a09b9cd8cc 100644
--- a/drivers/firewire/core-transaction.c
+++ b/drivers/firewire/core-transaction.c
@@ -1246,14 +1246,14 @@ static const u32 model_textual_descriptor[] = {
static struct fw_descriptor vendor_id_descriptor = {
.length = ARRAY_SIZE(vendor_textual_descriptor),
- .immediate = 0x03d00d1e,
+ .immediate = 0x03001f11,
.key = 0x81000000,
.data = vendor_textual_descriptor,
};
static struct fw_descriptor model_id_descriptor = {
.length = ARRAY_SIZE(model_textual_descriptor),
- .immediate = 0x17000001,
+ .immediate = 0x17023901,
.key = 0x81000000,
.data = model_textual_descriptor,
};
diff --git a/drivers/firewire/ohci.c b/drivers/firewire/ohci.c
index aff9018d0658..f51d376d10ba 100644
--- a/drivers/firewire/ohci.c
+++ b/drivers/firewire/ohci.c
@@ -718,11 +718,6 @@ static inline unsigned int ar_next_buffer_index(unsigned int index)
return (index + 1) % AR_BUFFERS;
}
-static inline unsigned int ar_prev_buffer_index(unsigned int index)
-{
- return (index - 1 + AR_BUFFERS) % AR_BUFFERS;
-}
-
static inline unsigned int ar_first_buffer_index(struct ar_context *ctx)
{
return ar_next_buffer_index(ctx->last_buffer_index);
diff --git a/drivers/firewire/sbp2.c b/drivers/firewire/sbp2.c
index 64ac8f8f5098..c22606fe3d44 100644
--- a/drivers/firewire/sbp2.c
+++ b/drivers/firewire/sbp2.c
@@ -1463,17 +1463,6 @@ static int sbp2_scsi_queuecommand(struct Scsi_Host *shost,
struct sbp2_command_orb *orb;
int generation, retval = SCSI_MLQUEUE_HOST_BUSY;
- /*
- * Bidirectional commands are not yet implemented, and unknown
- * transfer direction not handled.
- */
- if (cmd->sc_data_direction == DMA_BIDIRECTIONAL) {
- dev_err(lu_dev(lu), "cannot handle bidirectional command\n");
- cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
- return 0;
- }
-
orb = kzalloc(sizeof(*orb), GFP_ATOMIC);
if (orb == NULL)
return SCSI_MLQUEUE_HOST_BUSY;
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index fccb464928c3..3061bb8629dc 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -297,29 +297,15 @@ static __init int match_config_table(efi_guid_t *guid,
return 0;
}
-int __init efi_config_init(efi_config_table_type_t *arch_tables)
+int __init efi_config_parse_tables(void *config_tables, int count, int sz,
+ efi_config_table_type_t *arch_tables)
{
- void *config_tables, *tablep;
- int i, sz;
-
- if (efi_enabled(EFI_64BIT))
- sz = sizeof(efi_config_table_64_t);
- else
- sz = sizeof(efi_config_table_32_t);
-
- /*
- * Let's see what config tables the firmware passed to us.
- */
- config_tables = early_memremap(efi.systab->tables,
- efi.systab->nr_tables * sz);
- if (config_tables == NULL) {
- pr_err("Could not map Configuration table!\n");
- return -ENOMEM;
- }
+ void *tablep;
+ int i;
tablep = config_tables;
pr_info("");
- for (i = 0; i < efi.systab->nr_tables; i++) {
+ for (i = 0; i < count; i++) {
efi_guid_t guid;
unsigned long table;
@@ -332,8 +318,6 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
if (table64 >> 32) {
pr_cont("\n");
pr_err("Table located above 4GB, disabling EFI.\n");
- early_memunmap(config_tables,
- efi.systab->nr_tables * sz);
return -EINVAL;
}
#endif
@@ -348,13 +332,37 @@ int __init efi_config_init(efi_config_table_type_t *arch_tables)
tablep += sz;
}
pr_cont("\n");
- early_memunmap(config_tables, efi.systab->nr_tables * sz);
-
set_bit(EFI_CONFIG_TABLES, &efi.flags);
-
return 0;
}
+int __init efi_config_init(efi_config_table_type_t *arch_tables)
+{
+ void *config_tables;
+ int sz, ret;
+
+ if (efi_enabled(EFI_64BIT))
+ sz = sizeof(efi_config_table_64_t);
+ else
+ sz = sizeof(efi_config_table_32_t);
+
+ /*
+ * Let's see what config tables the firmware passed to us.
+ */
+ config_tables = early_memremap(efi.systab->tables,
+ efi.systab->nr_tables * sz);
+ if (config_tables == NULL) {
+ pr_err("Could not map Configuration table!\n");
+ return -ENOMEM;
+ }
+
+ ret = efi_config_parse_tables(config_tables, efi.systab->nr_tables, sz,
+ arch_tables);
+
+ early_memunmap(config_tables, efi.systab->nr_tables * sz);
+ return ret;
+}
+
#ifdef CONFIG_EFI_VARS_MODULE
static int __init efi_load_efivars(void)
{
diff --git a/drivers/firmware/efi/libstub/Makefile b/drivers/firmware/efi/libstub/Makefile
index 8902f52e0998..280bc0a63365 100644
--- a/drivers/firmware/efi/libstub/Makefile
+++ b/drivers/firmware/efi/libstub/Makefile
@@ -19,6 +19,7 @@ KBUILD_CFLAGS := $(cflags-y) \
$(call cc-option,-fno-stack-protector)
GCOV_PROFILE := n
+KASAN_SANITIZE := n
lib-y := efi-stub-helper.o
lib-$(CONFIG_EFI_ARMSTUB) += arm-stub.o fdt.o
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 2b3814702dcf..dcae482a9a17 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -295,3 +295,62 @@ fail_free_image:
fail:
return EFI_ERROR;
}
+
+/*
+ * This is the base address at which to start allocating virtual memory ranges
+ * for UEFI Runtime Services. This is in the low TTBR0 range so that we can use
+ * any allocation we choose, and eliminate the risk of a conflict after kexec.
+ * The value chosen is the largest non-zero power of 2 suitable for this purpose
+ * both on 32-bit and 64-bit ARM CPUs, to maximize the likelihood that it can
+ * be mapped efficiently.
+ */
+#define EFI_RT_VIRTUAL_BASE 0x40000000
+
+/*
+ * efi_get_virtmap() - create a virtual mapping for the EFI memory map
+ *
+ * This function populates the virt_addr fields of all memory region descriptors
+ * in @memory_map whose EFI_MEMORY_RUNTIME attribute is set. Those descriptors
+ * are also copied to @runtime_map, and their total count is returned in @count.
+ */
+void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
+ unsigned long desc_size, efi_memory_desc_t *runtime_map,
+ int *count)
+{
+ u64 efi_virt_base = EFI_RT_VIRTUAL_BASE;
+ efi_memory_desc_t *out = runtime_map;
+ int l;
+
+ for (l = 0; l < map_size; l += desc_size) {
+ efi_memory_desc_t *in = (void *)memory_map + l;
+ u64 paddr, size;
+
+ if (!(in->attribute & EFI_MEMORY_RUNTIME))
+ continue;
+
+ /*
+ * Make the mapping compatible with 64k pages: this allows
+ * a 4k page size kernel to kexec a 64k page size kernel and
+ * vice versa.
+ */
+ paddr = round_down(in->phys_addr, SZ_64K);
+ size = round_up(in->num_pages * EFI_PAGE_SIZE +
+ in->phys_addr - paddr, SZ_64K);
+
+ /*
+ * Avoid wasting memory on PTEs by choosing a virtual base that
+ * is compatible with section mappings if this region has the
+ * appropriate size and physical alignment. (Sections are 2 MB
+ * on 4k granule kernels)
+ */
+ if (IS_ALIGNED(in->phys_addr, SZ_2M) && size >= SZ_2M)
+ efi_virt_base = round_up(efi_virt_base, SZ_2M);
+
+ in->virt_addr = efi_virt_base + in->phys_addr - paddr;
+ efi_virt_base += size;
+
+ memcpy(out, in, desc_size);
+ out = (void *)out + desc_size;
+ ++*count;
+ }
+}
diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c
index c927bccd92bd..f07d4a67fa76 100644
--- a/drivers/firmware/efi/libstub/efi-stub-helper.c
+++ b/drivers/firmware/efi/libstub/efi-stub-helper.c
@@ -32,6 +32,15 @@
static unsigned long __chunk_size = EFI_READ_CHUNK_SIZE;
+/*
+ * Allow the platform to override the allocation granularity: this allows
+ * systems that have the capability to run with a larger page size to deal
+ * with the allocations for initrd and fdt more efficiently.
+ */
+#ifndef EFI_ALLOC_ALIGN
+#define EFI_ALLOC_ALIGN EFI_PAGE_SIZE
+#endif
+
struct file_info {
efi_file_handle_t *handle;
u64 size;
@@ -150,10 +159,10 @@ efi_status_t efi_high_alloc(efi_system_table_t *sys_table_arg,
* a specific address. We are doing page-based allocations,
* so we must be aligned to a page.
*/
- if (align < EFI_PAGE_SIZE)
- align = EFI_PAGE_SIZE;
+ if (align < EFI_ALLOC_ALIGN)
+ align = EFI_ALLOC_ALIGN;
- nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+ nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
again:
for (i = 0; i < map_size / desc_size; i++) {
efi_memory_desc_t *desc;
@@ -235,10 +244,10 @@ efi_status_t efi_low_alloc(efi_system_table_t *sys_table_arg,
* a specific address. We are doing page-based allocations,
* so we must be aligned to a page.
*/
- if (align < EFI_PAGE_SIZE)
- align = EFI_PAGE_SIZE;
+ if (align < EFI_ALLOC_ALIGN)
+ align = EFI_ALLOC_ALIGN;
- nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+ nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
for (i = 0; i < map_size / desc_size; i++) {
efi_memory_desc_t *desc;
unsigned long m = (unsigned long)map;
@@ -292,7 +301,7 @@ void efi_free(efi_system_table_t *sys_table_arg, unsigned long size,
if (!size)
return;
- nr_pages = round_up(size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+ nr_pages = round_up(size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
efi_call_early(free_pages, addr, nr_pages);
}
@@ -561,7 +570,7 @@ efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
* to the preferred address. If that fails, allocate as low
* as possible while respecting the required alignment.
*/
- nr_pages = round_up(alloc_size, EFI_PAGE_SIZE) / EFI_PAGE_SIZE;
+ nr_pages = round_up(alloc_size, EFI_ALLOC_ALIGN) / EFI_PAGE_SIZE;
status = efi_call_early(allocate_pages,
EFI_ALLOCATE_ADDRESS, EFI_LOADER_DATA,
nr_pages, &efi_addr);
diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
index 304ab295ca1a..47437b16b186 100644
--- a/drivers/firmware/efi/libstub/efistub.h
+++ b/drivers/firmware/efi/libstub/efistub.h
@@ -5,6 +5,10 @@
/* error code which can't be mistaken for valid address */
#define EFI_ERROR (~0UL)
+#undef memcpy
+#undef memset
+#undef memmove
+
void efi_char16_printk(efi_system_table_t *, efi_char16_t *);
efi_status_t efi_open_volume(efi_system_table_t *sys_table_arg, void *__image,
@@ -39,4 +43,8 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
void *get_fdt(efi_system_table_t *sys_table);
+void efi_get_virtmap(efi_memory_desc_t *memory_map, unsigned long map_size,
+ unsigned long desc_size, efi_memory_desc_t *runtime_map,
+ int *count);
+
#endif
diff --git a/drivers/firmware/efi/libstub/fdt.c b/drivers/firmware/efi/libstub/fdt.c
index c846a9608cbd..91da56c4fd54 100644
--- a/drivers/firmware/efi/libstub/fdt.c
+++ b/drivers/firmware/efi/libstub/fdt.c
@@ -14,6 +14,8 @@
#include <linux/libfdt.h>
#include <asm/efi.h>
+#include "efistub.h"
+
efi_status_t update_fdt(efi_system_table_t *sys_table, void *orig_fdt,
unsigned long orig_fdt_size,
void *fdt, int new_fdt_size, char *cmdline_ptr,
@@ -193,9 +195,26 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
unsigned long map_size, desc_size;
u32 desc_ver;
unsigned long mmap_key;
- efi_memory_desc_t *memory_map;
+ efi_memory_desc_t *memory_map, *runtime_map;
unsigned long new_fdt_size;
efi_status_t status;
+ int runtime_entry_count = 0;
+
+ /*
+ * Get a copy of the current memory map that we will use to prepare
+ * the input for SetVirtualAddressMap(). We don't have to worry about
+ * subsequent allocations adding entries, since they could not affect
+ * the number of EFI_MEMORY_RUNTIME regions.
+ */
+ status = efi_get_memory_map(sys_table, &runtime_map, &map_size,
+ &desc_size, &desc_ver, &mmap_key);
+ if (status != EFI_SUCCESS) {
+ pr_efi_err(sys_table, "Unable to retrieve UEFI memory map.\n");
+ return status;
+ }
+
+ pr_efi(sys_table,
+ "Exiting boot services and installing virtual address map...\n");
/*
* Estimate size of new FDT, and allocate memory for it. We
@@ -248,12 +267,48 @@ efi_status_t allocate_new_fdt_and_exit_boot(efi_system_table_t *sys_table,
}
}
+ /*
+ * Update the memory map with virtual addresses. The function will also
+ * populate @runtime_map with copies of just the EFI_MEMORY_RUNTIME
+ * entries so that we can pass it straight into SetVirtualAddressMap()
+ */
+ efi_get_virtmap(memory_map, map_size, desc_size, runtime_map,
+ &runtime_entry_count);
+
/* Now we are ready to exit_boot_services.*/
status = sys_table->boottime->exit_boot_services(handle, mmap_key);
+ if (status == EFI_SUCCESS) {
+ efi_set_virtual_address_map_t *svam;
- if (status == EFI_SUCCESS)
- return status;
+ /* Install the new virtual address map */
+ svam = sys_table->runtime->set_virtual_address_map;
+ status = svam(runtime_entry_count * desc_size, desc_size,
+ desc_ver, runtime_map);
+
+ /*
+ * We are beyond the point of no return here, so if the call to
+ * SetVirtualAddressMap() failed, we need to signal that to the
+ * incoming kernel but proceed normally otherwise.
+ */
+ if (status != EFI_SUCCESS) {
+ int l;
+
+ /*
+ * Set the virtual address field of all
+ * EFI_MEMORY_RUNTIME entries to 0. This will signal
+ * the incoming kernel that no virtual translation has
+ * been installed.
+ */
+ for (l = 0; l < map_size; l += desc_size) {
+ efi_memory_desc_t *p = (void *)memory_map + l;
+
+ if (p->attribute & EFI_MEMORY_RUNTIME)
+ p->virt_addr = 0;
+ }
+ }
+ return EFI_SUCCESS;
+ }
pr_efi_err(sys_table, "Exit boot services failed.\n");
@@ -264,6 +319,7 @@ fail_free_new_fdt:
efi_free(sys_table, new_fdt_size, *new_fdt_addr);
fail:
+ sys_table->boottime->free_pool(runtime_map);
return EFI_LOAD_ERROR;
}
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 633ec216e185..c1e2ca3d9a51 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -197,9 +197,16 @@ config GPIO_F7188X
To compile this driver as a module, choose M here: the module will
be called f7188x-gpio.
+config GPIO_MB86S7X
+ bool "GPIO support for Fujitsu MB86S7x Platforms"
+ depends on ARCH_MB86S7X
+ help
+ Say yes here to support the GPIO controller in Fujitsu MB86S70 SoCs.
+
config GPIO_MOXART
bool "MOXART GPIO support"
depends on ARCH_MOXART
+ select GPIO_GENERIC
help
Select this option to enable GPIO driver for
MOXA ART SoC devices.
@@ -285,6 +292,7 @@ config GPIO_PXA
config GPIO_RCAR
tristate "Renesas R-Car GPIO"
depends on ARM && (ARCH_SHMOBILE || COMPILE_TEST)
+ select GPIOLIB_IRQCHIP
help
Say yes here to support GPIO on Renesas R-Car SoCs.
@@ -365,9 +373,17 @@ config GPIO_XGENE
the generic flash controller's address and data pins. Say yes
here to enable the GFC GPIO functionality.
+config GPIO_XGENE_SB
+ tristate "APM X-Gene GPIO standby controller support"
+ depends on ARCH_XGENE && OF_GPIO
+ select GPIO_GENERIC
+ help
+ This driver supports the GPIO block within the APM X-Gene
+ Standby Domain. Say yes here to enable the GPIO functionality.
+
config GPIO_XILINX
- bool "Xilinx GPIO support"
- depends on PPC_OF || MICROBLAZE || ARCH_ZYNQ
+ tristate "Xilinx GPIO support"
+ depends on OF_GPIO && (PPC || MICROBLAZE || ARCH_ZYNQ || X86)
help
Say yes here to support the Xilinx FPGA GPIO device
@@ -394,25 +410,32 @@ config GPIO_VR41XX
Say yes here to support the NEC VR4100 series General-purpose I/O Uint
config GPIO_SCH
- tristate "Intel SCH/TunnelCreek/Centerton GPIO"
+ tristate "Intel SCH/TunnelCreek/Centerton/Quark X1000 GPIO"
depends on PCI && X86
select MFD_CORE
select LPC_SCH
help
Say yes here to support GPIO interface on Intel Poulsbo SCH,
- Intel Tunnel Creek processor or Intel Centerton processor.
+ Intel Tunnel Creek processor, Intel Centerton processor or
+ Intel Quark X1000 SoC.
+
The Intel SCH contains a total of 14 GPIO pins. Ten GPIOs are
powered by the core power rail and are turned off during sleep
modes (S3 and higher). The remaining four GPIOs are powered by
the Intel SCH suspend power supply. These GPIOs remain
active during S3. The suspend powered GPIOs can be used to wake the
system from the Suspend-to-RAM state.
+
The Intel Tunnel Creek processor has 5 GPIOs powered by the
core power rail and 9 from suspend power supply.
+
The Intel Centerton processor has a total of 30 GPIO pins.
Twenty-one are powered by the core power rail and 9 from the
suspend power supply.
+ The Intel Quark X1000 SoC has 2 GPIOs powered by the core
+ power well and 6 from the suspend power well.
+
config GPIO_ICH
tristate "Intel ICH GPIO"
depends on PCI && X86
@@ -450,6 +473,7 @@ config GPIO_VX855
config GPIO_GE_FPGA
bool "GE FPGA based GPIO"
depends on GE_FPGA
+ select GPIO_GENERIC
help
Support for common GPIO functionality provided on some GE Single Board
Computers.
@@ -519,6 +543,7 @@ config GPIO_MAX7300
config GPIO_MAX732X
tristate "MAX7319, MAX7320-7327 I2C Port Expanders"
depends on I2C
+ select IRQ_DOMAIN
help
Say yes here to support the MAX7319, MAX7320-7327 series of I2C
Port Expanders. Each IO port on these chips has a fixed role of
@@ -613,6 +638,7 @@ config GPIO_RC5T583
config GPIO_SX150X
bool "Semtech SX150x I2C GPIO expander"
depends on I2C=y
+ select GPIOLIB_IRQCHIP
default n
help
Say yes here to provide support for Semtech SX150-series I2C
@@ -624,6 +650,7 @@ config GPIO_SX150X
config GPIO_STMPE
bool "STMPE GPIOs"
depends on MFD_STMPE
+ depends on OF_GPIO
select GPIOLIB_IRQCHIP
help
This enables support for the GPIOs found on the STMPE I/O
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index 81755f1305e6..bdda6a94d2cd 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -48,6 +48,7 @@ obj-$(CONFIG_GPIO_MAX730X) += gpio-max730x.o
obj-$(CONFIG_GPIO_MAX7300) += gpio-max7300.o
obj-$(CONFIG_GPIO_MAX7301) += gpio-max7301.o
obj-$(CONFIG_GPIO_MAX732X) += gpio-max732x.o
+obj-$(CONFIG_GPIO_MB86S7X) += gpio-mb86s7x.o
obj-$(CONFIG_GPIO_MC33880) += gpio-mc33880.o
obj-$(CONFIG_GPIO_MC9S08DZ60) += gpio-mc9s08dz60.o
obj-$(CONFIG_GPIO_MCP23S08) += gpio-mcp23s08.o
@@ -105,6 +106,7 @@ obj-$(CONFIG_GPIO_WM831X) += gpio-wm831x.o
obj-$(CONFIG_GPIO_WM8350) += gpio-wm8350.o
obj-$(CONFIG_GPIO_WM8994) += gpio-wm8994.o
obj-$(CONFIG_GPIO_XGENE) += gpio-xgene.o
+obj-$(CONFIG_GPIO_XGENE_SB) += gpio-xgene-sb.o
obj-$(CONFIG_GPIO_XILINX) += gpio-xilinx.o
obj-$(CONFIG_GPIO_XTENSA) += gpio-xtensa.o
obj-$(CONFIG_GPIO_ZEVIO) += gpio-zevio.o
diff --git a/drivers/gpio/gpio-amd8111.c b/drivers/gpio/gpio-amd8111.c
index d3d2d1099f64..d00d81928fe8 100644
--- a/drivers/gpio/gpio-amd8111.c
+++ b/drivers/gpio/gpio-amd8111.c
@@ -213,6 +213,12 @@ found:
goto out;
}
gp.pm = ioport_map(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+ if (!gp.pm) {
+ dev_err(&pdev->dev, "Couldn't map io port into io memory\n");
+ release_region(gp.pmbase + PMBASE_OFFSET, PMBASE_SIZE);
+ err = -ENOMEM;
+ goto out;
+ }
gp.pdev = pdev;
gp.chip.dev = &pdev->dev;
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
index ce3c1558cb0a..dbdb4de82c6d 100644
--- a/drivers/gpio/gpio-dln2.c
+++ b/drivers/gpio/gpio-dln2.c
@@ -396,6 +396,7 @@ 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;
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index b4eb6a657d34..58faf04fce5d 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -469,15 +469,13 @@ dwapb_gpio_get_pdata_of(struct device *dev)
if (nports == 0)
return ERR_PTR(-ENODEV);
- pdata = kzalloc(sizeof(*pdata), GFP_KERNEL);
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
return ERR_PTR(-ENOMEM);
- pdata->properties = kcalloc(nports, sizeof(*pp), GFP_KERNEL);
- if (!pdata->properties) {
- kfree(pdata);
+ pdata->properties = devm_kcalloc(dev, nports, sizeof(*pp), GFP_KERNEL);
+ if (!pdata->properties)
return ERR_PTR(-ENOMEM);
- }
pdata->nports = nports;
@@ -490,8 +488,6 @@ dwapb_gpio_get_pdata_of(struct device *dev)
pp->idx >= DWAPB_MAX_PORTS) {
dev_err(dev, "missing/invalid port index for %s\n",
port_np->full_name);
- kfree(pdata->properties);
- kfree(pdata);
return ERR_PTR(-EINVAL);
}
@@ -523,15 +519,6 @@ dwapb_gpio_get_pdata_of(struct device *dev)
return pdata;
}
-static inline void dwapb_free_pdata_of(struct dwapb_platform_data *pdata)
-{
- if (!IS_ENABLED(CONFIG_OF_GPIO) || !pdata)
- return;
-
- kfree(pdata->properties);
- kfree(pdata);
-}
-
static int dwapb_gpio_probe(struct platform_device *pdev)
{
unsigned int i;
@@ -540,40 +527,32 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
int err;
struct device *dev = &pdev->dev;
struct dwapb_platform_data *pdata = dev_get_platdata(dev);
- bool is_pdata_alloc = !pdata;
- if (is_pdata_alloc) {
+ if (!pdata) {
pdata = dwapb_gpio_get_pdata_of(dev);
if (IS_ERR(pdata))
return PTR_ERR(pdata);
}
- if (!pdata->nports) {
- err = -ENODEV;
- goto out_err;
- }
+ if (!pdata->nports)
+ return -ENODEV;
gpio = devm_kzalloc(&pdev->dev, sizeof(*gpio), GFP_KERNEL);
- if (!gpio) {
- err = -ENOMEM;
- goto out_err;
- }
+ if (!gpio)
+ return -ENOMEM;
+
gpio->dev = &pdev->dev;
gpio->nr_ports = pdata->nports;
gpio->ports = devm_kcalloc(&pdev->dev, gpio->nr_ports,
sizeof(*gpio->ports), GFP_KERNEL);
- if (!gpio->ports) {
- err = -ENOMEM;
- goto out_err;
- }
+ if (!gpio->ports)
+ return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
gpio->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(gpio->regs)) {
- err = PTR_ERR(gpio->regs);
- goto out_err;
- }
+ if (IS_ERR(gpio->regs))
+ return PTR_ERR(gpio->regs);
for (i = 0; i < gpio->nr_ports; i++) {
err = dwapb_gpio_add_port(gpio, &pdata->properties[i], i);
@@ -582,16 +561,12 @@ static int dwapb_gpio_probe(struct platform_device *pdev)
}
platform_set_drvdata(pdev, gpio);
- goto out_err;
+ return 0;
out_unregister:
dwapb_gpio_unregister(gpio);
dwapb_irq_teardown(gpio);
-out_err:
- if (is_pdata_alloc)
- dwapb_free_pdata_of(pdata);
-
return err;
}
diff --git a/drivers/gpio/gpio-ge.c b/drivers/gpio/gpio-ge.c
index aea5c2a53cc0..f9ac3f351753 100644
--- a/drivers/gpio/gpio-ge.c
+++ b/drivers/gpio/gpio-ge.c
@@ -19,9 +19,12 @@
#include <linux/kernel.h>
#include <linux/io.h>
+#include <linux/slab.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
+#include <linux/of_address.h>
#include <linux/module.h>
+#include <linux/basic_mmio_gpio.h>
#define GEF_GPIO_DIRECT 0x00
#define GEF_GPIO_IN 0x04
@@ -33,53 +36,6 @@
#define GEF_GPIO_OVERRUN 0x1C
#define GEF_GPIO_MODE 0x20
-static void gef_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
- unsigned int data;
-
- data = ioread32be(mmchip->regs + GEF_GPIO_OUT);
- if (value)
- data = data | BIT(offset);
- else
- data = data & ~BIT(offset);
- iowrite32be(data, mmchip->regs + GEF_GPIO_OUT);
-}
-
-static int gef_gpio_dir_in(struct gpio_chip *chip, unsigned offset)
-{
- unsigned int data;
- struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
- data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
- data = data | BIT(offset);
- iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
-
- return 0;
-}
-
-static int gef_gpio_dir_out(struct gpio_chip *chip, unsigned offset, int value)
-{
- unsigned int data;
- struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
- /* Set value before switching to output */
- gef_gpio_set(mmchip->regs + GEF_GPIO_OUT, offset, value);
-
- data = ioread32be(mmchip->regs + GEF_GPIO_DIRECT);
- data = data & ~BIT(offset);
- iowrite32be(data, mmchip->regs + GEF_GPIO_DIRECT);
-
- return 0;
-}
-
-static int gef_gpio_get(struct gpio_chip *chip, unsigned offset)
-{
- struct of_mm_gpio_chip *mmchip = to_of_mm_gpio_chip(chip);
-
- return !!(ioread32be(mmchip->regs + GEF_GPIO_IN) & BIT(offset));
-}
-
static const struct of_device_id gef_gpio_ids[] = {
{
.compatible = "gef,sbc610-gpio",
@@ -99,22 +55,50 @@ static int __init gef_gpio_probe(struct platform_device *pdev)
{
const struct of_device_id *of_id =
of_match_device(gef_gpio_ids, &pdev->dev);
- struct of_mm_gpio_chip *mmchip;
+ struct bgpio_chip *bgc;
+ void __iomem *regs;
+ int ret;
- mmchip = devm_kzalloc(&pdev->dev, sizeof(*mmchip), GFP_KERNEL);
- if (!mmchip)
+ bgc = devm_kzalloc(&pdev->dev, sizeof(*bgc), GFP_KERNEL);
+ if (!bgc)
return -ENOMEM;
+ regs = of_iomap(pdev->dev.of_node, 0);
+ if (!regs)
+ return -ENOMEM;
+
+ ret = bgpio_init(bgc, &pdev->dev, 4, regs + GEF_GPIO_IN,
+ regs + GEF_GPIO_OUT, NULL, NULL,
+ regs + GEF_GPIO_DIRECT, BGPIOF_BIG_ENDIAN_BYTE_ORDER);
+ if (ret) {
+ dev_err(&pdev->dev, "bgpio_init failed\n");
+ goto err0;
+ }
+
/* Setup pointers to chip functions */
- mmchip->gc.ngpio = (u16)(uintptr_t)of_id->data;
- mmchip->gc.of_gpio_n_cells = 2;
- mmchip->gc.direction_input = gef_gpio_dir_in;
- mmchip->gc.direction_output = gef_gpio_dir_out;
- mmchip->gc.get = gef_gpio_get;
- mmchip->gc.set = gef_gpio_set;
+ bgc->gc.label = devm_kstrdup(&pdev->dev, pdev->dev.of_node->full_name,
+ GFP_KERNEL);
+ if (!bgc->gc.label) {
+ ret = -ENOMEM;
+ goto err0;
+ }
+
+ bgc->gc.base = -1;
+ bgc->gc.ngpio = (u16)(uintptr_t)of_id->data;
+ bgc->gc.of_gpio_n_cells = 2;
+ bgc->gc.of_node = pdev->dev.of_node;
/* This function adds a memory mapped GPIO chip */
- return of_mm_gpiochip_add(pdev->dev.of_node, mmchip);
+ ret = gpiochip_add(&bgc->gc);
+ if (ret)
+ goto err0;
+
+ return 0;
+err0:
+ iounmap(regs);
+ pr_err("%s: GPIO chip registration failed\n",
+ pdev->dev.of_node->full_name);
+ return ret;
};
static struct platform_driver gef_gpio_driver = {
diff --git a/drivers/gpio/gpio-generic.c b/drivers/gpio/gpio-generic.c
index 16f6115e5bdb..b92a690f5765 100644
--- a/drivers/gpio/gpio-generic.c
+++ b/drivers/gpio/gpio-generic.c
@@ -190,6 +190,79 @@ static void bgpio_set_set(struct gpio_chip *gc, unsigned int gpio, int val)
spin_unlock_irqrestore(&bgc->lock, flags);
}
+static void bgpio_multiple_get_masks(struct bgpio_chip *bgc,
+ unsigned long *mask, unsigned long *bits,
+ unsigned long *set_mask,
+ unsigned long *clear_mask)
+{
+ int i;
+
+ *set_mask = 0;
+ *clear_mask = 0;
+
+ for (i = 0; i < bgc->bits; i++) {
+ if (*mask == 0)
+ break;
+ if (__test_and_clear_bit(i, mask)) {
+ if (test_bit(i, bits))
+ *set_mask |= bgc->pin2mask(bgc, i);
+ else
+ *clear_mask |= bgc->pin2mask(bgc, i);
+ }
+ }
+}
+
+static void bgpio_set_multiple_single_reg(struct bgpio_chip *bgc,
+ unsigned long *mask,
+ unsigned long *bits,
+ void __iomem *reg)
+{
+ unsigned long flags;
+ unsigned long set_mask, clear_mask;
+
+ spin_lock_irqsave(&bgc->lock, flags);
+
+ bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
+
+ bgc->data |= set_mask;
+ bgc->data &= ~clear_mask;
+
+ bgc->write_reg(reg, bgc->data);
+
+ spin_unlock_irqrestore(&bgc->lock, flags);
+}
+
+static void bgpio_set_multiple(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_dat);
+}
+
+static void bgpio_set_multiple_set(struct gpio_chip *gc, unsigned long *mask,
+ unsigned long *bits)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ bgpio_set_multiple_single_reg(bgc, mask, bits, bgc->reg_set);
+}
+
+static void bgpio_set_multiple_with_clear(struct gpio_chip *gc,
+ unsigned long *mask,
+ unsigned long *bits)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+ unsigned long set_mask, clear_mask;
+
+ bgpio_multiple_get_masks(bgc, mask, bits, &set_mask, &clear_mask);
+
+ if (set_mask)
+ bgc->write_reg(bgc->reg_set, set_mask);
+ if (clear_mask)
+ bgc->write_reg(bgc->reg_clr, clear_mask);
+}
+
static int bgpio_simple_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
return 0;
@@ -354,11 +427,14 @@ static int bgpio_setup_io(struct bgpio_chip *bgc,
bgc->reg_set = set;
bgc->reg_clr = clr;
bgc->gc.set = bgpio_set_with_clear;
+ bgc->gc.set_multiple = bgpio_set_multiple_with_clear;
} else if (set && !clr) {
bgc->reg_set = set;
bgc->gc.set = bgpio_set_set;
+ bgc->gc.set_multiple = bgpio_set_multiple_set;
} else {
bgc->gc.set = bgpio_set;
+ bgc->gc.set_multiple = bgpio_set_multiple;
}
bgc->gc.get = bgpio_get;
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 3a5a71050559..35a02770c8b0 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -121,7 +121,7 @@ static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
{
struct grgpio_priv *priv = grgpio_gc_to_priv(gc);
- if (offset > gc->ngpio)
+ if (offset >= gc->ngpio)
return -ENXIO;
if (priv->lirqs[offset].index < 0)
diff --git a/drivers/gpio/gpio-max732x.c b/drivers/gpio/gpio-max732x.c
index 6c676225b886..a095b2393fe9 100644
--- a/drivers/gpio/gpio-max732x.c
+++ b/drivers/gpio/gpio-max732x.c
@@ -19,8 +19,10 @@
#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/irqdomain.h>
#include <linux/i2c.h>
#include <linux/i2c/max732x.h>
+#include <linux/of.h>
/*
@@ -116,6 +118,22 @@ static const struct i2c_device_id max732x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, max732x_id);
+#ifdef CONFIG_OF
+static const struct of_device_id max732x_of_table[] = {
+ { .compatible = "maxim,max7319" },
+ { .compatible = "maxim,max7320" },
+ { .compatible = "maxim,max7321" },
+ { .compatible = "maxim,max7322" },
+ { .compatible = "maxim,max7323" },
+ { .compatible = "maxim,max7324" },
+ { .compatible = "maxim,max7325" },
+ { .compatible = "maxim,max7326" },
+ { .compatible = "maxim,max7327" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max732x_of_table);
+#endif
+
struct max732x_chip {
struct gpio_chip gpio_chip;
@@ -132,16 +150,22 @@ struct max732x_chip {
uint8_t reg_out[2];
#ifdef CONFIG_GPIO_MAX732X_IRQ
- struct mutex irq_lock;
- int irq_base;
- uint8_t irq_mask;
- uint8_t irq_mask_cur;
- uint8_t irq_trig_raise;
- uint8_t irq_trig_fall;
- uint8_t irq_features;
+ struct irq_domain *irq_domain;
+ struct mutex irq_lock;
+ int irq_base;
+ uint8_t irq_mask;
+ uint8_t irq_mask_cur;
+ uint8_t irq_trig_raise;
+ uint8_t irq_trig_fall;
+ uint8_t irq_features;
#endif
};
+static inline struct max732x_chip *to_max732x(struct gpio_chip *gc)
+{
+ return container_of(gc, struct max732x_chip, gpio_chip);
+}
+
static int max732x_writeb(struct max732x_chip *chip, int group_a, uint8_t val)
{
struct i2c_client *client;
@@ -180,12 +204,10 @@ static inline int is_group_a(struct max732x_chip *chip, unsigned off)
static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
{
- struct max732x_chip *chip;
+ struct max732x_chip *chip = to_max732x(gc);
uint8_t reg_val;
int ret;
- chip = container_of(gc, struct max732x_chip, gpio_chip);
-
ret = max732x_readb(chip, is_group_a(chip, off), &reg_val);
if (ret < 0)
return 0;
@@ -193,18 +215,17 @@ static int max732x_gpio_get_value(struct gpio_chip *gc, unsigned off)
return reg_val & (1u << (off & 0x7));
}
-static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+static void max732x_gpio_set_mask(struct gpio_chip *gc, unsigned off, int mask,
+ int val)
{
- struct max732x_chip *chip;
- uint8_t reg_out, mask = 1u << (off & 0x7);
+ struct max732x_chip *chip = to_max732x(gc);
+ uint8_t reg_out;
int ret;
- chip = container_of(gc, struct max732x_chip, gpio_chip);
-
mutex_lock(&chip->lock);
reg_out = (off > 7) ? chip->reg_out[1] : chip->reg_out[0];
- reg_out = (val) ? reg_out | mask : reg_out & ~mask;
+ reg_out = (reg_out & ~mask) | (val & mask);
ret = max732x_writeb(chip, is_group_a(chip, off), reg_out);
if (ret < 0)
@@ -219,13 +240,31 @@ out:
mutex_unlock(&chip->lock);
}
+static void max732x_gpio_set_value(struct gpio_chip *gc, unsigned off, int val)
+{
+ unsigned base = off & ~0x7;
+ uint8_t mask = 1u << (off & 0x7);
+
+ max732x_gpio_set_mask(gc, base, mask, val << (off & 0x7));
+}
+
+static void max732x_gpio_set_multiple(struct gpio_chip *gc,
+ unsigned long *mask, unsigned long *bits)
+{
+ unsigned mask_lo = mask[0] & 0xff;
+ unsigned mask_hi = (mask[0] >> 8) & 0xff;
+
+ if (mask_lo)
+ max732x_gpio_set_mask(gc, 0, mask_lo, bits[0] & 0xff);
+ if (mask_hi)
+ max732x_gpio_set_mask(gc, 8, mask_hi, (bits[0] >> 8) & 0xff);
+}
+
static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
{
- struct max732x_chip *chip;
+ struct max732x_chip *chip = to_max732x(gc);
unsigned int mask = 1u << off;
- chip = container_of(gc, struct max732x_chip, gpio_chip);
-
if ((mask & chip->dir_input) == 0) {
dev_dbg(&chip->client->dev, "%s port %d is output only\n",
chip->client->name, off);
@@ -245,11 +284,9 @@ static int max732x_gpio_direction_input(struct gpio_chip *gc, unsigned off)
static int max732x_gpio_direction_output(struct gpio_chip *gc,
unsigned off, int val)
{
- struct max732x_chip *chip;
+ struct max732x_chip *chip = to_max732x(gc);
unsigned int mask = 1u << off;
- chip = container_of(gc, struct max732x_chip, gpio_chip);
-
if ((mask & chip->dir_output) == 0) {
dev_dbg(&chip->client->dev, "%s port %d is input only\n",
chip->client->name, off);
@@ -321,24 +358,28 @@ static void max732x_irq_update_mask(struct max732x_chip *chip)
static int max732x_gpio_to_irq(struct gpio_chip *gc, unsigned off)
{
- struct max732x_chip *chip;
+ struct max732x_chip *chip = to_max732x(gc);
- chip = container_of(gc, struct max732x_chip, gpio_chip);
- return chip->irq_base + off;
+ if (chip->irq_domain) {
+ return irq_create_mapping(chip->irq_domain,
+ chip->irq_base + off);
+ } else {
+ return -ENXIO;
+ }
}
static void max732x_irq_mask(struct irq_data *d)
{
struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
- chip->irq_mask_cur &= ~(1 << (d->irq - chip->irq_base));
+ chip->irq_mask_cur &= ~(1 << d->hwirq);
}
static void max732x_irq_unmask(struct irq_data *d)
{
struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
- chip->irq_mask_cur |= 1 << (d->irq - chip->irq_base);
+ chip->irq_mask_cur |= 1 << d->hwirq;
}
static void max732x_irq_bus_lock(struct irq_data *d)
@@ -352,15 +393,25 @@ static void max732x_irq_bus_lock(struct irq_data *d)
static void max732x_irq_bus_sync_unlock(struct irq_data *d)
{
struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
+ uint16_t new_irqs;
+ uint16_t level;
max732x_irq_update_mask(chip);
+
+ new_irqs = chip->irq_trig_fall | chip->irq_trig_raise;
+ while (new_irqs) {
+ level = __ffs(new_irqs);
+ max732x_gpio_direction_input(&chip->gpio_chip, level);
+ new_irqs &= ~(1 << level);
+ }
+
mutex_unlock(&chip->irq_lock);
}
static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
{
struct max732x_chip *chip = irq_data_get_irq_chip_data(d);
- uint16_t off = d->irq - chip->irq_base;
+ uint16_t off = d->hwirq;
uint16_t mask = 1 << off;
if (!(mask & chip->dir_input)) {
@@ -385,7 +436,7 @@ static int max732x_irq_set_type(struct irq_data *d, unsigned int type)
else
chip->irq_trig_raise &= ~mask;
- return max732x_gpio_direction_input(&chip->gpio_chip, off);
+ return 0;
}
static struct irq_chip max732x_irq_chip = {
@@ -441,7 +492,7 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
do {
level = __ffs(pending);
- handle_nested_irq(level + chip->irq_base);
+ handle_nested_irq(irq_find_mapping(chip->irq_domain, level));
pending &= ~(1 << level);
} while (pending);
@@ -449,6 +500,44 @@ static irqreturn_t max732x_irq_handler(int irq, void *devid)
return IRQ_HANDLED;
}
+static int max732x_irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw)
+{
+ struct max732x_chip *chip = h->host_data;
+
+ if (!(chip->dir_input & (1 << hw))) {
+ dev_err(&chip->client->dev,
+ "Attempt to map output line as IRQ line: %lu\n",
+ hw);
+ return -EPERM;
+ }
+
+ irq_set_chip_data(virq, chip);
+ irq_set_chip_and_handler(virq, &max732x_irq_chip,
+ handle_edge_irq);
+ irq_set_nested_thread(virq, 1);
+#ifdef CONFIG_ARM
+ /* ARM needs us to explicitly flag the IRQ as valid
+ * and will set them noprobe when we do so. */
+ set_irq_flags(virq, IRQF_VALID);
+#else
+ irq_set_noprobe(virq);
+#endif
+
+ return 0;
+}
+
+static struct irq_domain_ops max732x_irq_domain_ops = {
+ .map = max732x_irq_map,
+ .xlate = irq_domain_xlate_twocell,
+};
+
+static void max732x_irq_teardown(struct max732x_chip *chip)
+{
+ if (chip->client->irq && chip->irq_domain)
+ irq_domain_remove(chip->irq_domain);
+}
+
static int max732x_irq_setup(struct max732x_chip *chip,
const struct i2c_device_id *id)
{
@@ -457,28 +546,19 @@ static int max732x_irq_setup(struct max732x_chip *chip,
int has_irq = max732x_features[id->driver_data] >> 32;
int ret;
- if (pdata->irq_base && has_irq != INT_NONE) {
- int lvl;
-
- chip->irq_base = pdata->irq_base;
+ if (((pdata && pdata->irq_base) || client->irq)
+ && has_irq != INT_NONE) {
+ if (pdata)
+ chip->irq_base = pdata->irq_base;
chip->irq_features = has_irq;
mutex_init(&chip->irq_lock);
- for (lvl = 0; lvl < chip->gpio_chip.ngpio; lvl++) {
- int irq = lvl + chip->irq_base;
-
- if (!(chip->dir_input & (1 << lvl)))
- continue;
-
- irq_set_chip_data(irq, chip);
- irq_set_chip_and_handler(irq, &max732x_irq_chip,
- handle_edge_irq);
- irq_set_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
+ chip->irq_domain = irq_domain_add_simple(client->dev.of_node,
+ chip->gpio_chip.ngpio, chip->irq_base,
+ &max732x_irq_domain_ops, chip);
+ if (!chip->irq_domain) {
+ dev_err(&client->dev, "Failed to create IRQ domain\n");
+ return -ENOMEM;
}
ret = request_threaded_irq(client->irq,
@@ -498,15 +578,10 @@ static int max732x_irq_setup(struct max732x_chip *chip,
return 0;
out_failed:
- chip->irq_base = 0;
+ max732x_irq_teardown(chip);
return ret;
}
-static void max732x_irq_teardown(struct max732x_chip *chip)
-{
- if (chip->irq_base)
- free_irq(chip->client->irq, chip);
-}
#else /* CONFIG_GPIO_MAX732X_IRQ */
static int max732x_irq_setup(struct max732x_chip *chip,
const struct i2c_device_id *id)
@@ -515,7 +590,7 @@ static int max732x_irq_setup(struct max732x_chip *chip,
struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
int has_irq = max732x_features[id->driver_data] >> 32;
- if (pdata->irq_base && has_irq != INT_NONE)
+ if (((pdata && pdata->irq_base) || client->irq) && has_irq != INT_NONE)
dev_warn(&client->dev, "interrupt support not compiled in\n");
return 0;
@@ -562,6 +637,7 @@ static int max732x_setup_gpio(struct max732x_chip *chip,
if (chip->dir_output) {
gc->direction_output = max732x_gpio_direction_output;
gc->set = max732x_gpio_set_value;
+ gc->set_multiple = max732x_gpio_set_multiple;
}
gc->get = max732x_gpio_get_value;
gc->can_sleep = true;
@@ -574,28 +650,47 @@ static int max732x_setup_gpio(struct max732x_chip *chip,
return port;
}
+static struct max732x_platform_data *of_gpio_max732x(struct device *dev)
+{
+ struct max732x_platform_data *pdata;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ pdata->gpio_base = -1;
+
+ return pdata;
+}
+
static int max732x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct max732x_platform_data *pdata;
+ struct device_node *node;
struct max732x_chip *chip;
struct i2c_client *c;
uint16_t addr_a, addr_b;
int ret, nr_port;
pdata = dev_get_platdata(&client->dev);
- if (pdata == NULL) {
+ node = client->dev.of_node;
+
+ if (!pdata && node)
+ pdata = of_gpio_max732x(&client->dev);
+
+ if (!pdata) {
dev_dbg(&client->dev, "no platform data\n");
return -EINVAL;
}
- chip = devm_kzalloc(&client->dev, sizeof(struct max732x_chip),
- GFP_KERNEL);
+ chip = devm_kzalloc(&client->dev, sizeof(*chip), GFP_KERNEL);
if (chip == NULL)
return -ENOMEM;
chip->client = client;
nr_port = max732x_setup_gpio(chip, id, pdata->gpio_base);
+ chip->gpio_chip.dev = &client->dev;
addr_a = (client->addr & 0x0f) | 0x60;
addr_b = (client->addr & 0x0f) | 0x50;
@@ -643,7 +738,7 @@ static int max732x_probe(struct i2c_client *client,
if (ret)
goto out_failed;
- if (pdata->setup) {
+ if (pdata && pdata->setup) {
ret = pdata->setup(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context);
if (ret < 0)
@@ -664,9 +759,10 @@ static int max732x_remove(struct i2c_client *client)
{
struct max732x_platform_data *pdata = dev_get_platdata(&client->dev);
struct max732x_chip *chip = i2c_get_clientdata(client);
- int ret;
- if (pdata->teardown) {
+ if (pdata && pdata->teardown) {
+ int ret;
+
ret = pdata->teardown(client, chip->gpio_chip.base,
chip->gpio_chip.ngpio, pdata->context);
if (ret < 0) {
@@ -689,8 +785,9 @@ static int max732x_remove(struct i2c_client *client)
static struct i2c_driver max732x_driver = {
.driver = {
- .name = "max732x",
- .owner = THIS_MODULE,
+ .name = "max732x",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(max732x_of_table),
},
.probe = max732x_probe,
.remove = max732x_remove,
diff --git a/drivers/gpio/gpio-mb86s7x.c b/drivers/gpio/gpio-mb86s7x.c
new file mode 100644
index 000000000000..21b1ce5abdfe
--- /dev/null
+++ b/drivers/gpio/gpio-mb86s7x.c
@@ -0,0 +1,232 @@
+/*
+ * linux/drivers/gpio/gpio-mb86s7x.c
+ *
+ * Copyright (C) 2015 Fujitsu Semiconductor Limited
+ * Copyright (C) 2015 Linaro Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/io.h>
+#include <linux/init.h>
+#include <linux/clk.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/of_device.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/slab.h>
+
+/*
+ * Only first 8bits of a register correspond to each pin,
+ * so there are 4 registers for 32 pins.
+ */
+#define PDR(x) (0x0 + x / 8 * 4)
+#define DDR(x) (0x10 + x / 8 * 4)
+#define PFR(x) (0x20 + x / 8 * 4)
+
+#define OFFSET(x) BIT((x) % 8)
+
+struct mb86s70_gpio_chip {
+ struct gpio_chip gc;
+ void __iomem *base;
+ struct clk *clk;
+ spinlock_t lock;
+};
+
+static inline struct mb86s70_gpio_chip *chip_to_mb86s70(struct gpio_chip *gc)
+{
+ return container_of(gc, struct mb86s70_gpio_chip, gc);
+}
+
+static int mb86s70_gpio_request(struct gpio_chip *gc, unsigned gpio)
+{
+ struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&gchip->lock, flags);
+
+ val = readl(gchip->base + PFR(gpio));
+ val &= ~OFFSET(gpio);
+ writel(val, gchip->base + PFR(gpio));
+
+ spin_unlock_irqrestore(&gchip->lock, flags);
+
+ return 0;
+}
+
+static void mb86s70_gpio_free(struct gpio_chip *gc, unsigned gpio)
+{
+ struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ unsigned long flags;
+ u32 val;
+
+ spin_lock_irqsave(&gchip->lock, flags);
+
+ val = readl(gchip->base + PFR(gpio));
+ val |= OFFSET(gpio);
+ writel(val, gchip->base + PFR(gpio));
+
+ spin_unlock_irqrestore(&gchip->lock, flags);
+}
+
+static int mb86s70_gpio_direction_input(struct gpio_chip *gc, unsigned gpio)
+{
+ struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ unsigned long flags;
+ unsigned char val;
+
+ spin_lock_irqsave(&gchip->lock, flags);
+
+ val = readl(gchip->base + DDR(gpio));
+ val &= ~OFFSET(gpio);
+ writel(val, gchip->base + DDR(gpio));
+
+ spin_unlock_irqrestore(&gchip->lock, flags);
+
+ return 0;
+}
+
+static int mb86s70_gpio_direction_output(struct gpio_chip *gc,
+ unsigned gpio, int value)
+{
+ struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ unsigned long flags;
+ unsigned char val;
+
+ spin_lock_irqsave(&gchip->lock, flags);
+
+ val = readl(gchip->base + PDR(gpio));
+ if (value)
+ val |= OFFSET(gpio);
+ else
+ val &= ~OFFSET(gpio);
+ writel(val, gchip->base + PDR(gpio));
+
+ val = readl(gchip->base + DDR(gpio));
+ val |= OFFSET(gpio);
+ writel(val, gchip->base + DDR(gpio));
+
+ spin_unlock_irqrestore(&gchip->lock, flags);
+
+ return 0;
+}
+
+static int mb86s70_gpio_get(struct gpio_chip *gc, unsigned gpio)
+{
+ struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+
+ return !!(readl(gchip->base + PDR(gpio)) & OFFSET(gpio));
+}
+
+static void mb86s70_gpio_set(struct gpio_chip *gc, unsigned gpio, int value)
+{
+ struct mb86s70_gpio_chip *gchip = chip_to_mb86s70(gc);
+ unsigned long flags;
+ unsigned char val;
+
+ spin_lock_irqsave(&gchip->lock, flags);
+
+ val = readl(gchip->base + PDR(gpio));
+ if (value)
+ val |= OFFSET(gpio);
+ else
+ val &= ~OFFSET(gpio);
+ writel(val, gchip->base + PDR(gpio));
+
+ spin_unlock_irqrestore(&gchip->lock, flags);
+}
+
+static int mb86s70_gpio_probe(struct platform_device *pdev)
+{
+ struct mb86s70_gpio_chip *gchip;
+ struct resource *res;
+ int ret;
+
+ gchip = devm_kzalloc(&pdev->dev, sizeof(*gchip), GFP_KERNEL);
+ if (gchip == NULL)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, gchip);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ gchip->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(gchip->base))
+ return PTR_ERR(gchip->base);
+
+ gchip->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(gchip->clk))
+ return PTR_ERR(gchip->clk);
+
+ clk_prepare_enable(gchip->clk);
+
+ spin_lock_init(&gchip->lock);
+
+ gchip->gc.direction_output = mb86s70_gpio_direction_output;
+ gchip->gc.direction_input = mb86s70_gpio_direction_input;
+ gchip->gc.request = mb86s70_gpio_request;
+ gchip->gc.free = mb86s70_gpio_free;
+ gchip->gc.get = mb86s70_gpio_get;
+ gchip->gc.set = mb86s70_gpio_set;
+ gchip->gc.label = dev_name(&pdev->dev);
+ gchip->gc.ngpio = 32;
+ gchip->gc.owner = THIS_MODULE;
+ gchip->gc.dev = &pdev->dev;
+ gchip->gc.base = -1;
+
+ platform_set_drvdata(pdev, gchip);
+
+ ret = gpiochip_add(&gchip->gc);
+ if (ret) {
+ dev_err(&pdev->dev, "couldn't register gpio driver\n");
+ clk_disable_unprepare(gchip->clk);
+ }
+
+ return ret;
+}
+
+static int mb86s70_gpio_remove(struct platform_device *pdev)
+{
+ struct mb86s70_gpio_chip *gchip = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&gchip->gc);
+ clk_disable_unprepare(gchip->clk);
+
+ return 0;
+}
+
+static const struct of_device_id mb86s70_gpio_dt_ids[] = {
+ { .compatible = "fujitsu,mb86s70-gpio" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mb86s70_gpio_dt_ids);
+
+static struct platform_driver mb86s70_gpio_driver = {
+ .driver = {
+ .name = "mb86s70-gpio",
+ .of_match_table = mb86s70_gpio_dt_ids,
+ },
+ .probe = mb86s70_gpio_probe,
+ .remove = mb86s70_gpio_remove,
+};
+
+static int __init mb86s70_gpio_init(void)
+{
+ return platform_driver_register(&mb86s70_gpio_driver);
+}
+module_init(mb86s70_gpio_init);
+
+MODULE_DESCRIPTION("MB86S7x GPIO Driver");
+MODULE_ALIAS("platform:mb86s70-gpio");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-mcp23s08.c b/drivers/gpio/gpio-mcp23s08.c
index da9c316059bc..eea5d7e578c9 100644
--- a/drivers/gpio/gpio-mcp23s08.c
+++ b/drivers/gpio/gpio-mcp23s08.c
@@ -801,9 +801,11 @@ static int mcp230xx_probe(struct i2c_client *client,
client->irq = irq_of_parse_and_map(client->dev.of_node, 0);
} else {
pdata = dev_get_platdata(&client->dev);
- if (!pdata || !gpio_is_valid(pdata->base)) {
- dev_dbg(&client->dev, "invalid platform data\n");
- return -EINVAL;
+ if (!pdata) {
+ pdata = devm_kzalloc(&client->dev,
+ sizeof(struct mcp23s08_platform_data),
+ GFP_KERNEL);
+ pdata->base = -1;
}
}
@@ -924,10 +926,11 @@ static int mcp23s08_probe(struct spi_device *spi)
} else {
type = spi_get_device_id(spi)->driver_data;
pdata = dev_get_platdata(&spi->dev);
- if (!pdata || !gpio_is_valid(pdata->base)) {
- dev_dbg(&spi->dev,
- "invalid or missing platform data\n");
- return -EINVAL;
+ if (!pdata) {
+ pdata = devm_kzalloc(&spi->dev,
+ sizeof(struct mcp23s08_platform_data),
+ GFP_KERNEL);
+ pdata->base = -1;
}
for (addr = 0; addr < ARRAY_SIZE(pdata->chip); addr++) {
diff --git a/drivers/gpio/gpio-mm-lantiq.c b/drivers/gpio/gpio-mm-lantiq.c
index f228b1ce0ce0..f67ef2283d64 100644
--- a/drivers/gpio/gpio-mm-lantiq.c
+++ b/drivers/gpio/gpio-mm-lantiq.c
@@ -104,35 +104,34 @@ static void ltq_mm_save_regs(struct of_mm_gpio_chip *mm_gc)
static int ltq_mm_probe(struct platform_device *pdev)
{
- struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct ltq_mm *chip;
- const __be32 *shadow;
- int ret = 0;
+ u32 shadow;
- if (!res) {
- dev_err(&pdev->dev, "failed to get memory resource\n");
- return -ENOENT;
- }
-
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ platform_set_drvdata(pdev, chip);
+
chip->mmchip.gc.ngpio = 16;
- chip->mmchip.gc.label = "gpio-mm-ltq";
chip->mmchip.gc.direction_output = ltq_mm_dir_out;
chip->mmchip.gc.set = ltq_mm_set;
chip->mmchip.save_regs = ltq_mm_save_regs;
/* store the shadow value if one was passed by the devicetree */
- shadow = of_get_property(pdev->dev.of_node, "lantiq,shadow", NULL);
- if (shadow)
- chip->shadow = be32_to_cpu(*shadow);
-
- ret = of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip);
- if (ret)
- kfree(chip);
- return ret;
+ if (!of_property_read_u32(pdev->dev.of_node, "lantiq,shadow", &shadow))
+ chip->shadow = shadow;
+
+ return of_mm_gpiochip_add(pdev->dev.of_node, &chip->mmchip);
+}
+
+static int ltq_mm_remove(struct platform_device *pdev)
+{
+ struct ltq_mm *chip = platform_get_drvdata(pdev);
+
+ of_mm_gpiochip_remove(&chip->mmchip);
+
+ return 0;
}
static const struct of_device_id ltq_mm_match[] = {
@@ -143,6 +142,7 @@ MODULE_DEVICE_TABLE(of, ltq_mm_match);
static struct platform_driver ltq_mm_driver = {
.probe = ltq_mm_probe,
+ .remove = ltq_mm_remove,
.driver = {
.name = "gpio-mm-ltq",
.of_match_table = ltq_mm_match,
@@ -155,3 +155,9 @@ static int __init ltq_mm_init(void)
}
subsys_initcall(ltq_mm_init);
+
+static void __exit ltq_mm_exit(void)
+{
+ platform_driver_unregister(&ltq_mm_driver);
+}
+module_exit(ltq_mm_exit);
diff --git a/drivers/gpio/gpio-moxart.c b/drivers/gpio/gpio-moxart.c
index 31e2551ed903..c3ab46e595da 100644
--- a/drivers/gpio/gpio-moxart.c
+++ b/drivers/gpio/gpio-moxart.c
@@ -23,21 +23,12 @@
#include <linux/delay.h>
#include <linux/timer.h>
#include <linux/bitops.h>
+#include <linux/basic_mmio_gpio.h>
#define GPIO_DATA_OUT 0x00
#define GPIO_DATA_IN 0x04
#define GPIO_PIN_DIRECTION 0x08
-struct moxart_gpio_chip {
- struct gpio_chip gpio;
- void __iomem *base;
-};
-
-static inline struct moxart_gpio_chip *to_moxart_gpio(struct gpio_chip *chip)
-{
- return container_of(chip, struct moxart_gpio_chip, gpio);
-}
-
static int moxart_gpio_request(struct gpio_chip *chip, unsigned offset)
{
return pinctrl_request_gpio(offset);
@@ -48,90 +39,60 @@ static void moxart_gpio_free(struct gpio_chip *chip, unsigned offset)
pinctrl_free_gpio(offset);
}
-static void moxart_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
-{
- struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
- void __iomem *ioaddr = gc->base + GPIO_DATA_OUT;
- u32 reg = readl(ioaddr);
-
- if (value)
- reg = reg | BIT(offset);
- else
- reg = reg & ~BIT(offset);
-
- writel(reg, ioaddr);
-}
-
static int moxart_gpio_get(struct gpio_chip *chip, unsigned offset)
{
- struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
- u32 ret = readl(gc->base + GPIO_PIN_DIRECTION);
+ struct bgpio_chip *bgc = to_bgpio_chip(chip);
+ u32 ret = bgc->read_reg(bgc->reg_dir);
if (ret & BIT(offset))
- return !!(readl(gc->base + GPIO_DATA_OUT) & BIT(offset));
+ return !!(bgc->read_reg(bgc->reg_set) & BIT(offset));
else
- return !!(readl(gc->base + GPIO_DATA_IN) & BIT(offset));
-}
-
-static int moxart_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
-{
- struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
- void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
-
- writel(readl(ioaddr) & ~BIT(offset), ioaddr);
- return 0;
-}
-
-static int moxart_gpio_direction_output(struct gpio_chip *chip,
- unsigned offset, int value)
-{
- struct moxart_gpio_chip *gc = to_moxart_gpio(chip);
- void __iomem *ioaddr = gc->base + GPIO_PIN_DIRECTION;
-
- moxart_gpio_set(chip, offset, value);
- writel(readl(ioaddr) | BIT(offset), ioaddr);
- return 0;
+ return !!(bgc->read_reg(bgc->reg_dat) & BIT(offset));
}
-static struct gpio_chip moxart_template_chip = {
- .label = "moxart-gpio",
- .request = moxart_gpio_request,
- .free = moxart_gpio_free,
- .direction_input = moxart_gpio_direction_input,
- .direction_output = moxart_gpio_direction_output,
- .set = moxart_gpio_set,
- .get = moxart_gpio_get,
- .ngpio = 32,
- .owner = THIS_MODULE,
-};
-
static int moxart_gpio_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct resource *res;
- struct moxart_gpio_chip *mgc;
+ struct bgpio_chip *bgc;
+ void __iomem *base;
int ret;
- mgc = devm_kzalloc(dev, sizeof(*mgc), GFP_KERNEL);
- if (!mgc)
+ bgc = devm_kzalloc(dev, sizeof(*bgc), GFP_KERNEL);
+ if (!bgc)
return -ENOMEM;
- mgc->gpio = moxart_template_chip;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mgc->base = devm_ioremap_resource(dev, res);
- if (IS_ERR(mgc->base))
- return PTR_ERR(mgc->base);
+ base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
- mgc->gpio.dev = dev;
+ ret = bgpio_init(bgc, dev, 4, base + GPIO_DATA_IN,
+ base + GPIO_DATA_OUT, NULL,
+ base + GPIO_PIN_DIRECTION, NULL, 0);
+ if (ret) {
+ dev_err(&pdev->dev, "bgpio_init failed\n");
+ return ret;
+ }
- ret = gpiochip_add(&mgc->gpio);
+ bgc->gc.label = "moxart-gpio";
+ bgc->gc.request = moxart_gpio_request;
+ bgc->gc.free = moxart_gpio_free;
+ bgc->gc.get = moxart_gpio_get;
+ bgc->data = bgc->read_reg(bgc->reg_set);
+ bgc->gc.base = 0;
+ bgc->gc.ngpio = 32;
+ bgc->gc.dev = dev;
+ bgc->gc.owner = THIS_MODULE;
+
+ ret = gpiochip_add(&bgc->gc);
if (ret) {
dev_err(dev, "%s: gpiochip_add failed\n",
dev->of_node->full_name);
return ret;
}
- return 0;
+ return ret;
}
static const struct of_device_id moxart_gpio_match[] = {
diff --git a/drivers/gpio/gpio-mpc5200.c b/drivers/gpio/gpio-mpc5200.c
index 8ce6c9510035..4c542153e923 100644
--- a/drivers/gpio/gpio-mpc5200.c
+++ b/drivers/gpio/gpio-mpc5200.c
@@ -155,10 +155,12 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev)
struct gpio_chip *gc;
int ret;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ platform_set_drvdata(ofdev, chip);
+
gc = &chip->mmchip.gc;
gc->ngpio = 8;
@@ -181,7 +183,11 @@ static int mpc52xx_wkup_gpiochip_probe(struct platform_device *ofdev)
static int mpc52xx_gpiochip_remove(struct platform_device *ofdev)
{
- return -EBUSY;
+ struct mpc52xx_gpiochip *chip = platform_get_drvdata(ofdev);
+
+ of_mm_gpiochip_remove(&chip->mmchip);
+
+ return 0;
}
static const struct of_device_id mpc52xx_wkup_gpiochip_match[] = {
@@ -314,10 +320,12 @@ static int mpc52xx_simple_gpiochip_probe(struct platform_device *ofdev)
struct mpc52xx_gpio __iomem *regs;
int ret;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&ofdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
+ platform_set_drvdata(ofdev, chip);
+
gc = &chip->mmchip.gc;
gc->ngpio = 32;
@@ -363,11 +371,16 @@ static int __init mpc52xx_gpio_init(void)
return 0;
}
-
/* Make sure we get initialised before anyone else tries to use us */
subsys_initcall(mpc52xx_gpio_init);
-/* No exit call at the moment as we cannot unregister of gpio chips */
+static void __exit mpc52xx_gpio_exit(void)
+{
+ platform_driver_unregister(&mpc52xx_wkup_gpiochip_driver);
+
+ platform_driver_unregister(&mpc52xx_simple_gpiochip_driver);
+}
+module_exit(mpc52xx_gpio_exit);
MODULE_DESCRIPTION("Freescale MPC52xx gpio driver");
MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de");
diff --git a/drivers/gpio/gpio-mpc8xxx.c b/drivers/gpio/gpio-mpc8xxx.c
index d1ff879e6ff2..a6952ba343a8 100644
--- a/drivers/gpio/gpio-mpc8xxx.c
+++ b/drivers/gpio/gpio-mpc8xxx.c
@@ -15,6 +15,7 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
+#include <linux/of_platform.h>
#include <linux/gpio.h>
#include <linux/slab.h>
#include <linux/irq.h>
@@ -39,6 +40,7 @@ struct mpc8xxx_gpio_chip {
*/
u32 data;
struct irq_domain *irq;
+ unsigned int irqn;
const void *of_dev_id_data;
};
@@ -342,20 +344,20 @@ static struct of_device_id mpc8xxx_gpio_ids[] __initdata = {
{}
};
-static void __init mpc8xxx_add_controller(struct device_node *np)
+static int mpc8xxx_probe(struct platform_device *pdev)
{
+ struct device_node *np = pdev->dev.of_node;
struct mpc8xxx_gpio_chip *mpc8xxx_gc;
struct of_mm_gpio_chip *mm_gc;
struct gpio_chip *gc;
const struct of_device_id *id;
- unsigned hwirq;
int ret;
- mpc8xxx_gc = kzalloc(sizeof(*mpc8xxx_gc), GFP_KERNEL);
- if (!mpc8xxx_gc) {
- ret = -ENOMEM;
- goto err;
- }
+ mpc8xxx_gc = devm_kzalloc(&pdev->dev, sizeof(*mpc8xxx_gc), GFP_KERNEL);
+ if (!mpc8xxx_gc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mpc8xxx_gc);
spin_lock_init(&mpc8xxx_gc->lock);
@@ -375,16 +377,16 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
ret = of_mm_gpiochip_add(np, mm_gc);
if (ret)
- goto err;
+ return ret;
- hwirq = irq_of_parse_and_map(np, 0);
- if (hwirq == NO_IRQ)
- goto skip_irq;
+ mpc8xxx_gc->irqn = irq_of_parse_and_map(np, 0);
+ if (mpc8xxx_gc->irqn == NO_IRQ)
+ return 0;
mpc8xxx_gc->irq = irq_domain_add_linear(np, MPC8XXX_GPIO_PINS,
&mpc8xxx_gpio_irq_ops, mpc8xxx_gc);
if (!mpc8xxx_gc->irq)
- goto skip_irq;
+ return 0;
id = of_match_node(mpc8xxx_gpio_ids, np);
if (id)
@@ -394,27 +396,39 @@ static void __init mpc8xxx_add_controller(struct device_node *np)
out_be32(mm_gc->regs + GPIO_IER, 0xffffffff);
out_be32(mm_gc->regs + GPIO_IMR, 0);
- irq_set_handler_data(hwirq, mpc8xxx_gc);
- irq_set_chained_handler(hwirq, mpc8xxx_gpio_irq_cascade);
-
-skip_irq:
- return;
-
-err:
- pr_err("%s: registration failed with status %d\n",
- np->full_name, ret);
- kfree(mpc8xxx_gc);
+ irq_set_handler_data(mpc8xxx_gc->irqn, mpc8xxx_gc);
+ irq_set_chained_handler(mpc8xxx_gc->irqn, mpc8xxx_gpio_irq_cascade);
- return;
+ return 0;
}
-static int __init mpc8xxx_add_gpiochips(void)
+static int mpc8xxx_remove(struct platform_device *pdev)
{
- struct device_node *np;
+ struct mpc8xxx_gpio_chip *mpc8xxx_gc = platform_get_drvdata(pdev);
+
+ if (mpc8xxx_gc->irq) {
+ irq_set_handler_data(mpc8xxx_gc->irqn, NULL);
+ irq_set_chained_handler(mpc8xxx_gc->irqn, NULL);
+ irq_domain_remove(mpc8xxx_gc->irq);
+ }
- for_each_matching_node(np, mpc8xxx_gpio_ids)
- mpc8xxx_add_controller(np);
+ of_mm_gpiochip_remove(&mpc8xxx_gc->mm_gc);
return 0;
}
-arch_initcall(mpc8xxx_add_gpiochips);
+
+static struct platform_driver mpc8xxx_plat_driver = {
+ .probe = mpc8xxx_probe,
+ .remove = mpc8xxx_remove,
+ .driver = {
+ .name = "gpio-mpc8xxx",
+ .of_match_table = mpc8xxx_gpio_ids,
+ },
+};
+
+static int __init mpc8xxx_init(void)
+{
+ return platform_driver_register(&mpc8xxx_plat_driver);
+}
+
+arch_initcall(mpc8xxx_init);
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index 7bc3e9b288f3..d0bc123c7975 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -59,7 +59,7 @@
#define GPIO_LEVEL_MASK_OFF 0x001c
/* The MV78200 has per-CPU registers for edge mask and level mask */
-#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18)
+#define GPIO_EDGE_MASK_MV78200_OFF(cpu) ((cpu) ? 0x30 : 0x18)
#define GPIO_LEVEL_MASK_MV78200_OFF(cpu) ((cpu) ? 0x34 : 0x1C)
/* The Armada XP has per-CPU registers for interrupt cause, interrupt
@@ -69,11 +69,11 @@
#define GPIO_EDGE_MASK_ARMADAXP_OFF(cpu) (0x10 + (cpu) * 0x4)
#define GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu) (0x20 + (cpu) * 0x4)
-#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1
-#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2
+#define MVEBU_GPIO_SOC_VARIANT_ORION 0x1
+#define MVEBU_GPIO_SOC_VARIANT_MV78200 0x2
#define MVEBU_GPIO_SOC_VARIANT_ARMADAXP 0x3
-#define MVEBU_MAX_GPIO_PER_BANK 32
+#define MVEBU_MAX_GPIO_PER_BANK 32
struct mvebu_gpio_chip {
struct gpio_chip chip;
@@ -82,9 +82,9 @@ struct mvebu_gpio_chip {
void __iomem *percpu_membase;
int irqbase;
struct irq_domain *domain;
- int soc_variant;
+ int soc_variant;
- /* Used to preserve GPIO registers accross suspend/resume */
+ /* Used to preserve GPIO registers across suspend/resume */
u32 out_reg;
u32 io_conf_reg;
u32 blink_en_reg;
@@ -107,7 +107,8 @@ static inline void __iomem *mvebu_gpioreg_blink(struct mvebu_gpio_chip *mvchip)
return mvchip->membase + GPIO_BLINK_EN_OFF;
}
-static inline void __iomem *mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
+static inline void __iomem *
+mvebu_gpioreg_io_conf(struct mvebu_gpio_chip *mvchip)
{
return mvchip->membase + GPIO_IO_CONF_OFF;
}
@@ -117,12 +118,14 @@ static inline void __iomem *mvebu_gpioreg_in_pol(struct mvebu_gpio_chip *mvchip)
return mvchip->membase + GPIO_IN_POL_OFF;
}
-static inline void __iomem *mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip)
+static inline void __iomem *
+mvebu_gpioreg_data_in(struct mvebu_gpio_chip *mvchip)
{
return mvchip->membase + GPIO_DATA_IN_OFF;
}
-static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
+static inline void __iomem *
+mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvchip)
{
int cpu;
@@ -132,13 +135,15 @@ static inline void __iomem *mvebu_gpioreg_edge_cause(struct mvebu_gpio_chip *mvc
return mvchip->membase + GPIO_EDGE_CAUSE_OFF;
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
cpu = smp_processor_id();
- return mvchip->percpu_membase + GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu);
+ return mvchip->percpu_membase +
+ GPIO_EDGE_CAUSE_ARMADAXP_OFF(cpu);
default:
BUG();
}
}
-static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip)
+static inline void __iomem *
+mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvchip)
{
int cpu;
@@ -150,7 +155,8 @@ static inline void __iomem *mvebu_gpioreg_edge_mask(struct mvebu_gpio_chip *mvch
return mvchip->membase + GPIO_EDGE_MASK_MV78200_OFF(cpu);
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
cpu = smp_processor_id();
- return mvchip->percpu_membase + GPIO_EDGE_MASK_ARMADAXP_OFF(cpu);
+ return mvchip->percpu_membase +
+ GPIO_EDGE_MASK_ARMADAXP_OFF(cpu);
default:
BUG();
}
@@ -168,7 +174,8 @@ static void __iomem *mvebu_gpioreg_level_mask(struct mvebu_gpio_chip *mvchip)
return mvchip->membase + GPIO_LEVEL_MASK_MV78200_OFF(cpu);
case MVEBU_GPIO_SOC_VARIANT_ARMADAXP:
cpu = smp_processor_id();
- return mvchip->percpu_membase + GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu);
+ return mvchip->percpu_membase +
+ GPIO_LEVEL_MASK_ARMADAXP_OFF(cpu);
default:
BUG();
}
@@ -364,22 +371,22 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
* value of the line or the opposite value.
*
* Level IRQ handlers: DATA_IN is used directly as cause register.
- * Interrupt are masked by LEVEL_MASK registers.
+ * Interrupt are masked by LEVEL_MASK registers.
* Edge IRQ handlers: Change in DATA_IN are latched in EDGE_CAUSE.
- * Interrupt are masked by EDGE_MASK registers.
+ * Interrupt are masked by EDGE_MASK registers.
* Both-edge handlers: Similar to regular Edge handlers, but also swaps
- * the polarity to catch the next line transaction.
- * This is a race condition that might not perfectly
- * work on some use cases.
+ * the polarity to catch the next line transaction.
+ * This is a race condition that might not perfectly
+ * work on some use cases.
*
* Every eight GPIO lines are grouped (OR'ed) before going up to main
* cause register.
*
- * EDGE cause mask
- * data-in /--------| |-----| |----\
- * -----| |----- ---- to main cause reg
- * X \----------------| |----/
- * polarity LEVEL mask
+ * EDGE cause mask
+ * data-in /--------| |-----| |----\
+ * -----| |----- ---- to main cause reg
+ * X \----------------| |----/
+ * polarity LEVEL mask
*
****************************************************************************/
@@ -394,9 +401,8 @@ static int mvebu_gpio_irq_set_type(struct irq_data *d, unsigned int type)
pin = d->hwirq;
u = readl_relaxed(mvebu_gpioreg_io_conf(mvchip)) & (1 << pin);
- if (!u) {
+ if (!u)
return -EINVAL;
- }
type &= IRQ_TYPE_SENSE_MASK;
if (type == IRQ_TYPE_NONE)
@@ -529,13 +535,13 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
(data_in ^ in_pol) & msk ? "hi" : "lo",
in_pol & msk ? "lo" : "hi");
if (!((edg_msk | lvl_msk) & msk)) {
- seq_printf(s, " disabled\n");
+ seq_puts(s, " disabled\n");
continue;
}
if (edg_msk & msk)
- seq_printf(s, " edge ");
+ seq_puts(s, " edge ");
if (lvl_msk & msk)
- seq_printf(s, " level");
+ seq_puts(s, " level");
seq_printf(s, " (%s)\n", cause & msk ? "pending" : "clear ");
}
}
@@ -546,15 +552,15 @@ static void mvebu_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
static const struct of_device_id mvebu_gpio_of_match[] = {
{
.compatible = "marvell,orion-gpio",
- .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_ORION,
},
{
.compatible = "marvell,mv78200-gpio",
- .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_MV78200,
},
{
.compatible = "marvell,armadaxp-gpio",
- .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
+ .data = (void *) MVEBU_GPIO_SOC_VARIANT_ARMADAXP,
},
{
/* sentinel */
@@ -661,6 +667,7 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
unsigned int ngpios;
int soc_variant;
int i, cpu, id;
+ int err;
match = of_match_device(mvebu_gpio_of_match, &pdev->dev);
if (match)
@@ -668,7 +675,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
else
soc_variant = MVEBU_GPIO_SOC_VARIANT_ORION;
- mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip), GFP_KERNEL);
+ mvchip = devm_kzalloc(&pdev->dev, sizeof(struct mvebu_gpio_chip),
+ GFP_KERNEL);
if (!mvchip)
return -ENOMEM;
@@ -767,8 +775,8 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
* interrupt handlers, with each handler dealing with 8 GPIO
* pins. */
for (i = 0; i < 4; i++) {
- int irq;
- irq = platform_get_irq(pdev, i);
+ int irq = platform_get_irq(pdev, i);
+
if (irq < 0)
continue;
irq_set_handler_data(irq, mvchip);
@@ -778,14 +786,16 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
mvchip->irqbase = irq_alloc_descs(-1, 0, ngpios, -1);
if (mvchip->irqbase < 0) {
dev_err(&pdev->dev, "no irqs\n");
- return mvchip->irqbase;
+ err = mvchip->irqbase;
+ goto err_gpiochip_add;
}
gc = irq_alloc_generic_chip("mvebu_gpio_irq", 2, mvchip->irqbase,
mvchip->membase, handle_level_irq);
if (!gc) {
dev_err(&pdev->dev, "Cannot allocate generic irq_chip\n");
- return -ENOMEM;
+ err = -ENOMEM;
+ goto err_gpiochip_add;
}
gc->private = mvchip;
@@ -816,18 +826,26 @@ static int mvebu_gpio_probe(struct platform_device *pdev)
if (!mvchip->domain) {
dev_err(&pdev->dev, "couldn't allocate irq domain %s (DT).\n",
mvchip->chip.label);
- irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
- IRQ_LEVEL | IRQ_NOPROBE);
- kfree(gc);
- return -ENODEV;
+ err = -ENODEV;
+ goto err_generic_chip;
}
return 0;
+
+err_generic_chip:
+ irq_remove_generic_chip(gc, IRQ_MSK(ngpios), IRQ_NOREQUEST,
+ IRQ_LEVEL | IRQ_NOPROBE);
+ kfree(gc);
+
+err_gpiochip_add:
+ gpiochip_remove(&mvchip->chip);
+
+ return err;
}
static struct platform_driver mvebu_gpio_driver = {
.driver = {
- .name = "mvebu-gpio",
+ .name = "mvebu-gpio",
.of_match_table = mvebu_gpio_of_match,
},
.probe = mvebu_gpio_probe,
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 30646cfe0efa..f476ae2eb0b3 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -88,6 +88,8 @@ struct gpio_bank {
#define BANK_USED(bank) (bank->mod_usage || bank->irq_usage)
#define LINE_USED(line, offset) (line & (BIT(offset)))
+static void omap_gpio_unmask_irq(struct irq_data *d);
+
static int omap_irq_to_gpio(struct gpio_bank *bank, unsigned int gpio_irq)
{
return bank->chip.base + gpio_irq;
@@ -477,6 +479,16 @@ static int omap_gpio_is_input(struct gpio_bank *bank, int mask)
return readl_relaxed(reg) & mask;
}
+static void omap_gpio_init_irq(struct gpio_bank *bank, unsigned gpio,
+ unsigned offset)
+{
+ if (!LINE_USED(bank->mod_usage, offset)) {
+ omap_enable_gpio_module(bank, offset);
+ omap_set_gpio_direction(bank, offset, 1);
+ }
+ bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
+}
+
static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
@@ -506,15 +518,11 @@ static int omap_gpio_irq_type(struct irq_data *d, unsigned type)
spin_lock_irqsave(&bank->lock, flags);
offset = GPIO_INDEX(bank, gpio);
retval = omap_set_gpio_triggering(bank, offset, type);
- if (!LINE_USED(bank->mod_usage, offset)) {
- omap_enable_gpio_module(bank, offset);
- omap_set_gpio_direction(bank, offset, 1);
- } else if (!omap_gpio_is_input(bank, BIT(offset))) {
+ omap_gpio_init_irq(bank, gpio, offset);
+ if (!omap_gpio_is_input(bank, BIT(offset))) {
spin_unlock_irqrestore(&bank->lock, flags);
return -EINVAL;
}
-
- bank->irq_usage |= BIT(GPIO_INDEX(bank, gpio));
spin_unlock_irqrestore(&bank->lock, flags);
if (type & (IRQ_TYPE_LEVEL_LOW | IRQ_TYPE_LEVEL_HIGH))
@@ -792,6 +800,24 @@ exit:
pm_runtime_put(bank->dev);
}
+static unsigned int omap_gpio_irq_startup(struct irq_data *d)
+{
+ struct gpio_bank *bank = omap_irq_data_get_bank(d);
+ unsigned int gpio = omap_irq_to_gpio(bank, d->hwirq);
+ unsigned long flags;
+ unsigned offset = GPIO_INDEX(bank, gpio);
+
+ if (!BANK_USED(bank))
+ pm_runtime_get_sync(bank->dev);
+
+ spin_lock_irqsave(&bank->lock, flags);
+ omap_gpio_init_irq(bank, gpio, offset);
+ spin_unlock_irqrestore(&bank->lock, flags);
+ omap_gpio_unmask_irq(d);
+
+ return 0;
+}
+
static void omap_gpio_irq_shutdown(struct irq_data *d)
{
struct gpio_bank *bank = omap_irq_data_get_bank(d);
@@ -1181,6 +1207,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
if (!irqc)
return -ENOMEM;
+ irqc->irq_startup = omap_gpio_irq_startup,
irqc->irq_shutdown = omap_gpio_irq_shutdown,
irqc->irq_ack = omap_gpio_ack_irq,
irqc->irq_mask = omap_gpio_mask_irq,
diff --git a/drivers/gpio/gpio-pxa.c b/drivers/gpio/gpio-pxa.c
index ad3feec0075e..2fdb04b6f101 100644
--- a/drivers/gpio/gpio-pxa.c
+++ b/drivers/gpio/gpio-pxa.c
@@ -17,6 +17,7 @@
#include <linux/gpio.h>
#include <linux/gpio-pxa.h>
#include <linux/init.h>
+#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/irqdomain.h>
#include <linux/irqchip/chained_irq.h>
@@ -27,8 +28,6 @@
#include <linux/syscore_ops.h>
#include <linux/slab.h>
-#include <mach/irqs.h>
-
/*
* We handle the GPIOs by banks, each bank covers up to 32 GPIOs with
* one set of registers. The register offsets are organized below:
@@ -42,9 +41,12 @@
* BANK 4 - 0x0104 0x0110 0x011C 0x0128 0x0134 0x0140 0x014C
* BANK 5 - 0x0108 0x0114 0x0120 0x012C 0x0138 0x0144 0x0150
*
+ * BANK 6 - 0x0200 0x020C 0x0218 0x0224 0x0230 0x023C 0x0248
+ *
* NOTE:
* BANK 3 is only available on PXA27x and later processors.
- * BANK 4 and 5 are only available on PXA935
+ * BANK 4 and 5 are only available on PXA935, PXA1928
+ * BANK 6 is only available on PXA1928
*/
#define GPLR_OFFSET 0x00
@@ -57,7 +59,8 @@
#define GAFR_OFFSET 0x54
#define ED_MASK_OFFSET 0x9C /* GPIO edge detection for AP side */
-#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : 0x100 + (((n) - 3) << 2))
+#define BANK_OFF(n) (((n) < 3) ? (n) << 2 : ((n) > 5 ? 0x200 : 0x100) \
+ + (((n) % 3) << 2))
int pxa_last_gpio;
static int irq_base;
@@ -93,6 +96,7 @@ enum pxa_gpio_type {
PXA93X_GPIO,
MMP_GPIO = 0x10,
MMP2_GPIO,
+ PXA1928_GPIO,
};
struct pxa_gpio_id {
@@ -140,6 +144,11 @@ static struct pxa_gpio_id mmp2_id = {
.gpio_nums = 192,
};
+static struct pxa_gpio_id pxa1928_id = {
+ .type = PXA1928_GPIO,
+ .gpio_nums = 224,
+};
+
#define for_each_gpio_chip(i, c) \
for (i = 0, c = &pxa_gpio_chips[0]; i <= pxa_last_gpio; i += 32, c++)
@@ -487,6 +496,7 @@ static int pxa_gpio_nums(struct platform_device *pdev)
case PXA93X_GPIO:
case MMP_GPIO:
case MMP2_GPIO:
+ case PXA1928_GPIO:
gpio_type = pxa_id->type;
count = pxa_id->gpio_nums - 1;
break;
@@ -506,6 +516,7 @@ static const struct of_device_id pxa_gpio_dt_ids[] = {
{ .compatible = "marvell,pxa93x-gpio", .data = &pxa93x_id, },
{ .compatible = "marvell,mmp-gpio", .data = &mmp_id, },
{ .compatible = "marvell,mmp2-gpio", .data = &mmp2_id, },
+ { .compatible = "marvell,pxa1928-gpio", .data = &pxa1928_id, },
{}
};
@@ -629,19 +640,18 @@ static int pxa_gpio_probe(struct platform_device *pdev)
}
if (!use_of) {
-#ifdef CONFIG_ARCH_PXA
- irq = gpio_to_irq(0);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO0, pxa_gpio_demux_handler);
-
- irq = gpio_to_irq(1);
- irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
- handle_edge_irq);
- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
- irq_set_chained_handler(IRQ_GPIO1, pxa_gpio_demux_handler);
-#endif
+ if (irq0 > 0) {
+ irq = gpio_to_irq(0);
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
+ if (irq1 > 0) {
+ irq = gpio_to_irq(1);
+ irq_set_chip_and_handler(irq, &pxa_muxed_gpio_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+ }
for (irq = gpio_to_irq(gpio_offset);
irq <= gpio_to_irq(pxa_last_gpio); irq++) {
@@ -649,13 +659,13 @@ static int pxa_gpio_probe(struct platform_device *pdev)
handle_edge_irq);
set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
}
- } else {
- if (irq0 > 0)
- irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
- if (irq1 > 0)
- irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
}
+ if (irq0 > 0)
+ irq_set_chained_handler(irq0, pxa_gpio_demux_handler);
+ if (irq1 > 0)
+ irq_set_chained_handler(irq1, pxa_gpio_demux_handler);
+
irq_set_chained_handler(irq_mux, pxa_gpio_demux_handler);
return 0;
}
@@ -668,6 +678,7 @@ static const struct platform_device_id gpio_id_table[] = {
{ "pxa93x-gpio", (unsigned long)&pxa93x_id },
{ "mmp-gpio", (unsigned long)&mmp_id },
{ "mmp2-gpio", (unsigned long)&mmp2_id },
+ { "pxa1928-gpio", (unsigned long)&pxa1928_id },
{ },
};
diff --git a/drivers/gpio/gpio-rcar.c b/drivers/gpio/gpio-rcar.c
index 584484e3f1e3..c49522efa7b3 100644
--- a/drivers/gpio/gpio-rcar.c
+++ b/drivers/gpio/gpio-rcar.c
@@ -21,7 +21,6 @@
#include <linux/io.h>
#include <linux/ioport.h>
#include <linux/irq.h>
-#include <linux/irqdomain.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pinctrl/consumer.h>
@@ -38,7 +37,6 @@ struct gpio_rcar_priv {
struct platform_device *pdev;
struct gpio_chip gpio_chip;
struct irq_chip irq_chip;
- struct irq_domain *irq_domain;
};
#define IOINTSEL 0x00
@@ -82,14 +80,18 @@ static void gpio_rcar_modify_bit(struct gpio_rcar_priv *p, int offs,
static void gpio_rcar_irq_disable(struct irq_data *d)
{
- struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+ gpio_chip);
gpio_rcar_write(p, INTMSK, ~BIT(irqd_to_hwirq(d)));
}
static void gpio_rcar_irq_enable(struct irq_data *d)
{
- struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+ gpio_chip);
gpio_rcar_write(p, MSKCLR, BIT(irqd_to_hwirq(d)));
}
@@ -131,7 +133,9 @@ static void gpio_rcar_config_interrupt_input_mode(struct gpio_rcar_priv *p,
static int gpio_rcar_irq_set_type(struct irq_data *d, unsigned int type)
{
- struct gpio_rcar_priv *p = irq_data_get_irq_chip_data(d);
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct gpio_rcar_priv *p = container_of(gc, struct gpio_rcar_priv,
+ gpio_chip);
unsigned int hwirq = irqd_to_hwirq(d);
dev_dbg(&p->pdev->dev, "sense irq = %d, type = %d\n", hwirq, type);
@@ -175,7 +179,8 @@ static irqreturn_t gpio_rcar_irq_handler(int irq, void *dev_id)
gpio_rcar_read(p, INTMSK))) {
offset = __ffs(pending);
gpio_rcar_write(p, INTCLR, BIT(offset));
- generic_handle_irq(irq_find_mapping(p->irq_domain, offset));
+ generic_handle_irq(irq_find_mapping(p->gpio_chip.irqdomain,
+ offset));
irqs_handled++;
}
@@ -265,29 +270,6 @@ static int gpio_rcar_direction_output(struct gpio_chip *chip, unsigned offset,
return 0;
}
-static int gpio_rcar_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- return irq_create_mapping(gpio_to_priv(chip)->irq_domain, offset);
-}
-
-static int gpio_rcar_irq_domain_map(struct irq_domain *h, unsigned int irq,
- irq_hw_number_t hwirq)
-{
- struct gpio_rcar_priv *p = h->host_data;
-
- dev_dbg(&p->pdev->dev, "map hw irq = %d, irq = %d\n", (int)hwirq, irq);
-
- irq_set_chip_data(irq, h->host_data);
- irq_set_chip_and_handler(irq, &p->irq_chip, handle_level_irq);
- set_irq_flags(irq, IRQF_VALID); /* kill me now */
- return 0;
-}
-
-static struct irq_domain_ops gpio_rcar_irq_domain_ops = {
- .map = gpio_rcar_irq_domain_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
struct gpio_rcar_info {
bool has_both_edge_trigger;
};
@@ -372,10 +354,8 @@ static int gpio_rcar_probe(struct platform_device *pdev)
int ret;
p = devm_kzalloc(dev, sizeof(*p), GFP_KERNEL);
- if (!p) {
- ret = -ENOMEM;
- goto err0;
- }
+ if (!p)
+ return -ENOMEM;
p->pdev = pdev;
spin_lock_init(&p->lock);
@@ -413,7 +393,6 @@ static int gpio_rcar_probe(struct platform_device *pdev)
gpio_chip->get = gpio_rcar_get;
gpio_chip->direction_output = gpio_rcar_direction_output;
gpio_chip->set = gpio_rcar_set;
- gpio_chip->to_irq = gpio_rcar_to_irq;
gpio_chip->label = name;
gpio_chip->dev = dev;
gpio_chip->owner = THIS_MODULE;
@@ -428,16 +407,19 @@ static int gpio_rcar_probe(struct platform_device *pdev)
irq_chip->flags = IRQCHIP_SKIP_SET_WAKE | IRQCHIP_SET_TYPE_MASKED
| IRQCHIP_MASK_ON_SUSPEND;
- p->irq_domain = irq_domain_add_simple(pdev->dev.of_node,
- p->config.number_of_pins,
- p->config.irq_base,
- &gpio_rcar_irq_domain_ops, p);
- if (!p->irq_domain) {
- ret = -ENXIO;
- dev_err(dev, "cannot initialize irq domain\n");
+ ret = gpiochip_add(gpio_chip);
+ if (ret) {
+ dev_err(dev, "failed to add GPIO controller\n");
goto err0;
}
+ ret = gpiochip_irqchip_add(&p->gpio_chip, irq_chip, p->config.irq_base,
+ handle_level_irq, IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(dev, "cannot add irqchip\n");
+ goto err1;
+ }
+
if (devm_request_irq(dev, irq->start, gpio_rcar_irq_handler,
IRQF_SHARED, name, p)) {
dev_err(dev, "failed to request IRQ\n");
@@ -445,17 +427,11 @@ static int gpio_rcar_probe(struct platform_device *pdev)
goto err1;
}
- ret = gpiochip_add(gpio_chip);
- if (ret) {
- dev_err(dev, "failed to add GPIO controller\n");
- goto err1;
- }
-
dev_info(dev, "driving %d GPIOs\n", p->config.number_of_pins);
/* warn in case of mismatch if irq base is specified */
if (p->config.irq_base) {
- ret = irq_find_mapping(p->irq_domain, 0);
+ ret = irq_find_mapping(p->gpio_chip.irqdomain, 0);
if (p->config.irq_base != ret)
dev_warn(dev, "irq base mismatch (%u/%u)\n",
p->config.irq_base, ret);
@@ -471,7 +447,7 @@ static int gpio_rcar_probe(struct platform_device *pdev)
return 0;
err1:
- irq_domain_remove(p->irq_domain);
+ gpiochip_remove(&p->gpio_chip);
err0:
pm_runtime_put(dev);
pm_runtime_disable(dev);
@@ -484,7 +460,6 @@ static int gpio_rcar_remove(struct platform_device *pdev)
gpiochip_remove(&p->gpio_chip);
- irq_domain_remove(p->irq_domain);
pm_runtime_put(&pdev->dev);
pm_runtime_disable(&pdev->dev);
return 0;
diff --git a/drivers/gpio/gpio-sa1100.c b/drivers/gpio/gpio-sa1100.c
index a90be34e4d5c..bec397a60204 100644
--- a/drivers/gpio/gpio-sa1100.c
+++ b/drivers/gpio/gpio-sa1100.c
@@ -11,6 +11,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/io.h>
+#include <linux/syscore_ops.h>
#include <mach/hardware.h>
#include <mach/irqs.h>
@@ -50,7 +51,7 @@ static int sa1100_direction_output(struct gpio_chip *chip, unsigned offset, int
static int sa1100_to_irq(struct gpio_chip *chip, unsigned offset)
{
- return offset < 11 ? (IRQ_GPIO0 + offset) : (IRQ_GPIO11 - 11 + offset);
+ return IRQ_GPIO0 + offset;
}
static struct gpio_chip sa1100_gpio_chip = {
@@ -64,7 +65,203 @@ static struct gpio_chip sa1100_gpio_chip = {
.ngpio = GPIO_MAX + 1,
};
+/*
+ * SA1100 GPIO edge detection for IRQs:
+ * IRQs are generated on Falling-Edge, Rising-Edge, or both.
+ * Use this instead of directly setting GRER/GFER.
+ */
+static int GPIO_IRQ_rising_edge;
+static int GPIO_IRQ_falling_edge;
+static int GPIO_IRQ_mask;
+
+static int sa1100_gpio_type(struct irq_data *d, unsigned int type)
+{
+ unsigned int mask;
+
+ mask = BIT(d->hwirq);
+
+ if (type == IRQ_TYPE_PROBE) {
+ if ((GPIO_IRQ_rising_edge | GPIO_IRQ_falling_edge) & mask)
+ return 0;
+ type = IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING;
+ }
+
+ if (type & IRQ_TYPE_EDGE_RISING)
+ GPIO_IRQ_rising_edge |= mask;
+ else
+ GPIO_IRQ_rising_edge &= ~mask;
+ if (type & IRQ_TYPE_EDGE_FALLING)
+ GPIO_IRQ_falling_edge |= mask;
+ else
+ GPIO_IRQ_falling_edge &= ~mask;
+
+ GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
+ GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
+
+ return 0;
+}
+
+/*
+ * GPIO IRQs must be acknowledged.
+ */
+static void sa1100_gpio_ack(struct irq_data *d)
+{
+ GEDR = BIT(d->hwirq);
+}
+
+static void sa1100_gpio_mask(struct irq_data *d)
+{
+ unsigned int mask = BIT(d->hwirq);
+
+ GPIO_IRQ_mask &= ~mask;
+
+ GRER &= ~mask;
+ GFER &= ~mask;
+}
+
+static void sa1100_gpio_unmask(struct irq_data *d)
+{
+ unsigned int mask = BIT(d->hwirq);
+
+ GPIO_IRQ_mask |= mask;
+
+ GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
+ GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
+}
+
+static int sa1100_gpio_wake(struct irq_data *d, unsigned int on)
+{
+ if (on)
+ PWER |= BIT(d->hwirq);
+ else
+ PWER &= ~BIT(d->hwirq);
+ return 0;
+}
+
+/*
+ * This is for GPIO IRQs
+ */
+static struct irq_chip sa1100_gpio_irq_chip = {
+ .name = "GPIO",
+ .irq_ack = sa1100_gpio_ack,
+ .irq_mask = sa1100_gpio_mask,
+ .irq_unmask = sa1100_gpio_unmask,
+ .irq_set_type = sa1100_gpio_type,
+ .irq_set_wake = sa1100_gpio_wake,
+};
+
+static int sa1100_gpio_irqdomain_map(struct irq_domain *d,
+ unsigned int irq, irq_hw_number_t hwirq)
+{
+ irq_set_chip_and_handler(irq, &sa1100_gpio_irq_chip,
+ handle_edge_irq);
+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
+
+ return 0;
+}
+
+static struct irq_domain_ops sa1100_gpio_irqdomain_ops = {
+ .map = sa1100_gpio_irqdomain_map,
+ .xlate = irq_domain_xlate_onetwocell,
+};
+
+static struct irq_domain *sa1100_gpio_irqdomain;
+
+/*
+ * IRQ 0-11 (GPIO) handler. We enter here with the
+ * irq_controller_lock held, and IRQs disabled. Decode the IRQ
+ * and call the handler.
+ */
+static void
+sa1100_gpio_handler(unsigned int irq, struct irq_desc *desc)
+{
+ unsigned int mask;
+
+ mask = GEDR;
+ do {
+ /*
+ * clear down all currently active IRQ sources.
+ * We will be processing them all.
+ */
+ GEDR = mask;
+
+ irq = IRQ_GPIO0;
+ do {
+ if (mask & 1)
+ generic_handle_irq(irq);
+ mask >>= 1;
+ irq++;
+ } while (mask);
+
+ mask = GEDR;
+ } while (mask);
+}
+
+static int sa1100_gpio_suspend(void)
+{
+ /*
+ * Set the appropriate edges for wakeup.
+ */
+ GRER = PWER & GPIO_IRQ_rising_edge;
+ GFER = PWER & GPIO_IRQ_falling_edge;
+
+ /*
+ * Clear any pending GPIO interrupts.
+ */
+ GEDR = GEDR;
+
+ return 0;
+}
+
+static void sa1100_gpio_resume(void)
+{
+ GRER = GPIO_IRQ_rising_edge & GPIO_IRQ_mask;
+ GFER = GPIO_IRQ_falling_edge & GPIO_IRQ_mask;
+}
+
+static struct syscore_ops sa1100_gpio_syscore_ops = {
+ .suspend = sa1100_gpio_suspend,
+ .resume = sa1100_gpio_resume,
+};
+
+static int __init sa1100_gpio_init_devicefs(void)
+{
+ register_syscore_ops(&sa1100_gpio_syscore_ops);
+ return 0;
+}
+
+device_initcall(sa1100_gpio_init_devicefs);
+
void __init sa1100_init_gpio(void)
{
+ /* clear all GPIO edge detects */
+ GFER = 0;
+ GRER = 0;
+ GEDR = -1;
+
gpiochip_add(&sa1100_gpio_chip);
+
+ sa1100_gpio_irqdomain = irq_domain_add_simple(NULL,
+ 28, IRQ_GPIO0,
+ &sa1100_gpio_irqdomain_ops, NULL);
+
+ /*
+ * Install handlers for GPIO 0-10 edge detect interrupts
+ */
+ irq_set_chained_handler(IRQ_GPIO0_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO1_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO2_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO3_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO4_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO5_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO6_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO7_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO8_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO9_SC, sa1100_gpio_handler);
+ irq_set_chained_handler(IRQ_GPIO10_SC, sa1100_gpio_handler);
+ /*
+ * Install handler for GPIO 11-27 edge detect interrupts
+ */
+ irq_set_chained_handler(IRQ_GPIO11_27, sa1100_gpio_handler);
+
}
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 0a0cf1307d2f..b72906f5b999 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -41,7 +41,7 @@ struct sch_gpio {
unsigned short resume_base;
};
-#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip)
+#define to_sch_gpio(gc) container_of(gc, struct sch_gpio, chip)
static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
unsigned reg)
@@ -63,75 +63,59 @@ static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
return gpio % 8;
}
-static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
+static int sch_gpio_reg_get(struct gpio_chip *gc, unsigned gpio, unsigned reg)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
unsigned short offset, bit;
- u8 enable;
-
- spin_lock(&sch->lock);
+ u8 reg_val;
- offset = sch_gpio_offset(sch, gpio, GEN);
+ offset = sch_gpio_offset(sch, gpio, reg);
bit = sch_gpio_bit(sch, gpio);
- enable = inb(sch->iobase + offset);
- if (!(enable & (1 << bit)))
- outb(enable | (1 << bit), sch->iobase + offset);
+ reg_val = !!(inb(sch->iobase + offset) & BIT(bit));
- spin_unlock(&sch->lock);
+ return reg_val;
}
-static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+static void sch_gpio_reg_set(struct gpio_chip *gc, unsigned gpio, unsigned reg,
+ int val)
{
struct sch_gpio *sch = to_sch_gpio(gc);
- u8 curr_dirs;
unsigned short offset, bit;
+ u8 reg_val;
- spin_lock(&sch->lock);
+ offset = sch_gpio_offset(sch, gpio, reg);
+ bit = sch_gpio_bit(sch, gpio);
- offset = sch_gpio_offset(sch, gpio_num, GIO);
- bit = sch_gpio_bit(sch, gpio_num);
+ reg_val = inb(sch->iobase + offset);
- curr_dirs = inb(sch->iobase + offset);
+ if (val)
+ outb(reg_val | BIT(bit), sch->iobase + offset);
+ else
+ outb((reg_val & ~BIT(bit)), sch->iobase + offset);
+}
- if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), sch->iobase + offset);
+static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
+{
+ struct sch_gpio *sch = to_sch_gpio(gc);
+ spin_lock(&sch->lock);
+ sch_gpio_reg_set(gc, gpio_num, GIO, 1);
spin_unlock(&sch->lock);
return 0;
}
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 = sch_gpio_offset(sch, gpio_num, GLV);
- bit = sch_gpio_bit(sch, gpio_num);
-
- res = !!(inb(sch->iobase + offset) & (1 << bit));
-
- return res;
+ return sch_gpio_reg_get(gc, gpio_num, GLV);
}
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(&sch->lock);
-
- offset = sch_gpio_offset(sch, gpio_num, GLV);
- bit = sch_gpio_bit(sch, gpio_num);
-
- curr_vals = inb(sch->iobase + offset);
-
- if (val)
- outb(curr_vals | (1 << bit), sch->iobase + offset);
- else
- outb((curr_vals & ~(1 << bit)), sch->iobase + offset);
-
+ sch_gpio_reg_set(gc, gpio_num, GLV, val);
spin_unlock(&sch->lock);
}
@@ -139,18 +123,9 @@ 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;
spin_lock(&sch->lock);
-
- offset = sch_gpio_offset(sch, gpio_num, GIO);
- bit = sch_gpio_bit(sch, gpio_num);
-
- curr_dirs = inb(sch->iobase + offset);
- if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), sch->iobase + offset);
-
+ sch_gpio_reg_set(gc, gpio_num, GIO, 0);
spin_unlock(&sch->lock);
/*
@@ -209,13 +184,13 @@ static int sch_gpio_probe(struct platform_device *pdev)
* GPIO7 is configured by the CMC as SLPIOVR
* Enable GPIO[9:8] core powered gpios explicitly
*/
- sch_gpio_enable(sch, 8);
- sch_gpio_enable(sch, 9);
+ sch_gpio_reg_set(&sch->chip, 8, GEN, 1);
+ sch_gpio_reg_set(&sch->chip, 9, GEN, 1);
/*
* SUS_GPIO[2:0] enabled by default
* Enable SUS_GPIO3 resume powered gpio explicitly
*/
- sch_gpio_enable(sch, 13);
+ sch_gpio_reg_set(&sch->chip, 13, GEN, 1);
break;
case PCI_DEVICE_ID_INTEL_ITC_LPC:
@@ -230,6 +205,12 @@ static int sch_gpio_probe(struct platform_device *pdev)
sch->chip.ngpio = 30;
break;
+ case PCI_DEVICE_ID_INTEL_QUARK_X1000_ILB:
+ sch->core_base = 0;
+ sch->resume_base = 2;
+ sch->chip.ngpio = 8;
+ break;
+
default:
return -ENODEV;
}
diff --git a/drivers/gpio/gpio-stmpe.c b/drivers/gpio/gpio-stmpe.c
index 85c5b1974294..dabfb99dddef 100644
--- a/drivers/gpio/gpio-stmpe.c
+++ b/drivers/gpio/gpio-stmpe.c
@@ -30,7 +30,7 @@ struct stmpe_gpio {
struct stmpe *stmpe;
struct device *dev;
struct mutex irq_lock;
- unsigned norequest_mask;
+ u32 norequest_mask;
/* Caches of interrupt control registers for bus_lock */
u8 regs[CACHE_NR_REGS][CACHE_NR_BANKS];
u8 oldregs[CACHE_NR_REGS][CACHE_NR_BANKS];
@@ -340,13 +340,10 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
{
struct stmpe *stmpe = dev_get_drvdata(pdev->dev.parent);
struct device_node *np = pdev->dev.of_node;
- struct stmpe_gpio_platform_data *pdata;
struct stmpe_gpio *stmpe_gpio;
int ret;
int irq = 0;
- pdata = stmpe->pdata->gpio;
-
irq = platform_get_irq(pdev, 0);
stmpe_gpio = kzalloc(sizeof(struct stmpe_gpio), GFP_KERNEL);
@@ -360,19 +357,14 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
stmpe_gpio->chip = template_chip;
stmpe_gpio->chip.ngpio = stmpe->num_gpios;
stmpe_gpio->chip.dev = &pdev->dev;
-#ifdef CONFIG_OF
stmpe_gpio->chip.of_node = np;
-#endif
stmpe_gpio->chip.base = -1;
if (IS_ENABLED(CONFIG_DEBUG_FS))
stmpe_gpio->chip.dbg_show = stmpe_dbg_show;
- if (pdata)
- stmpe_gpio->norequest_mask = pdata->norequest_mask;
- else if (np)
- of_property_read_u32(np, "st,norequest-mask",
- &stmpe_gpio->norequest_mask);
+ of_property_read_u32(np, "st,norequest-mask",
+ &stmpe_gpio->norequest_mask);
if (irq < 0)
dev_info(&pdev->dev,
@@ -414,9 +406,6 @@ static int stmpe_gpio_probe(struct platform_device *pdev)
NULL);
}
- if (pdata && pdata->setup)
- pdata->setup(stmpe, stmpe_gpio->chip.base);
-
platform_set_drvdata(pdev, stmpe_gpio);
return 0;
@@ -433,15 +422,9 @@ static int stmpe_gpio_remove(struct platform_device *pdev)
{
struct stmpe_gpio *stmpe_gpio = platform_get_drvdata(pdev);
struct stmpe *stmpe = stmpe_gpio->stmpe;
- struct stmpe_gpio_platform_data *pdata = stmpe->pdata->gpio;
-
- if (pdata && pdata->remove)
- pdata->remove(stmpe, stmpe_gpio->chip.base);
gpiochip_remove(&stmpe_gpio->chip);
-
stmpe_disable(stmpe, STMPE_BLOCK_GPIO);
-
kfree(stmpe_gpio);
return 0;
diff --git a/drivers/gpio/gpio-sx150x.c b/drivers/gpio/gpio-sx150x.c
index bce6c6108f20..458d9d7952b8 100644
--- a/drivers/gpio/gpio-sx150x.c
+++ b/drivers/gpio/gpio-sx150x.c
@@ -23,23 +23,51 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/i2c/sx150x.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
#define NO_UPDATE_PENDING -1
+/* The chip models of sx150x */
+#define SX150X_456 0
+#define SX150X_789 1
+
+struct sx150x_456_pri {
+ u8 reg_pld_mode;
+ u8 reg_pld_table0;
+ u8 reg_pld_table1;
+ u8 reg_pld_table2;
+ u8 reg_pld_table3;
+ u8 reg_pld_table4;
+ u8 reg_advance;
+};
+
+struct sx150x_789_pri {
+ u8 reg_drain;
+ u8 reg_polarity;
+ u8 reg_clock;
+ u8 reg_misc;
+ u8 reg_reset;
+ u8 ngpios;
+};
+
struct sx150x_device_data {
+ u8 model;
u8 reg_pullup;
u8 reg_pulldn;
- u8 reg_drain;
- u8 reg_polarity;
u8 reg_dir;
u8 reg_data;
u8 reg_irq_mask;
u8 reg_irq_src;
u8 reg_sense;
- u8 reg_clock;
- u8 reg_misc;
- u8 reg_reset;
u8 ngpios;
+ union {
+ struct sx150x_456_pri x456;
+ struct sx150x_789_pri x789;
+ } pri;
};
struct sx150x_chip {
@@ -59,44 +87,79 @@ struct sx150x_chip {
static const struct sx150x_device_data sx150x_devices[] = {
[0] = { /* sx1508q */
- .reg_pullup = 0x03,
- .reg_pulldn = 0x04,
- .reg_drain = 0x05,
- .reg_polarity = 0x06,
- .reg_dir = 0x07,
- .reg_data = 0x08,
- .reg_irq_mask = 0x09,
- .reg_irq_src = 0x0c,
- .reg_sense = 0x0b,
- .reg_clock = 0x0f,
- .reg_misc = 0x10,
- .reg_reset = 0x7d,
- .ngpios = 8
+ .model = SX150X_789,
+ .reg_pullup = 0x03,
+ .reg_pulldn = 0x04,
+ .reg_dir = 0x07,
+ .reg_data = 0x08,
+ .reg_irq_mask = 0x09,
+ .reg_irq_src = 0x0c,
+ .reg_sense = 0x0b,
+ .pri.x789 = {
+ .reg_drain = 0x05,
+ .reg_polarity = 0x06,
+ .reg_clock = 0x0f,
+ .reg_misc = 0x10,
+ .reg_reset = 0x7d,
+ },
+ .ngpios = 8,
},
[1] = { /* sx1509q */
- .reg_pullup = 0x07,
- .reg_pulldn = 0x09,
- .reg_drain = 0x0b,
- .reg_polarity = 0x0d,
- .reg_dir = 0x0f,
- .reg_data = 0x11,
- .reg_irq_mask = 0x13,
- .reg_irq_src = 0x19,
- .reg_sense = 0x17,
- .reg_clock = 0x1e,
- .reg_misc = 0x1f,
- .reg_reset = 0x7d,
- .ngpios = 16
+ .model = SX150X_789,
+ .reg_pullup = 0x07,
+ .reg_pulldn = 0x09,
+ .reg_dir = 0x0f,
+ .reg_data = 0x11,
+ .reg_irq_mask = 0x13,
+ .reg_irq_src = 0x19,
+ .reg_sense = 0x17,
+ .pri.x789 = {
+ .reg_drain = 0x0b,
+ .reg_polarity = 0x0d,
+ .reg_clock = 0x1e,
+ .reg_misc = 0x1f,
+ .reg_reset = 0x7d,
+ },
+ .ngpios = 16
+ },
+ [2] = { /* sx1506q */
+ .model = SX150X_456,
+ .reg_pullup = 0x05,
+ .reg_pulldn = 0x07,
+ .reg_dir = 0x03,
+ .reg_data = 0x01,
+ .reg_irq_mask = 0x09,
+ .reg_irq_src = 0x0f,
+ .reg_sense = 0x0d,
+ .pri.x456 = {
+ .reg_pld_mode = 0x21,
+ .reg_pld_table0 = 0x23,
+ .reg_pld_table1 = 0x25,
+ .reg_pld_table2 = 0x27,
+ .reg_pld_table3 = 0x29,
+ .reg_pld_table4 = 0x2b,
+ .reg_advance = 0xad,
+ },
+ .ngpios = 16
},
};
static const struct i2c_device_id sx150x_id[] = {
{"sx1508q", 0},
{"sx1509q", 1},
+ {"sx1506q", 2},
{}
};
MODULE_DEVICE_TABLE(i2c, sx150x_id);
+static const struct of_device_id sx150x_of_match[] = {
+ { .compatible = "semtech,sx1508q" },
+ { .compatible = "semtech,sx1509q" },
+ { .compatible = "semtech,sx1506q" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, sx150x_of_match);
+
static s32 sx150x_i2c_write(struct i2c_client *client, u8 reg, u8 val)
{
s32 err = i2c_smbus_write_byte_data(client, reg, val);
@@ -191,7 +254,7 @@ static int sx150x_get_io(struct sx150x_chip *chip, unsigned offset)
static void sx150x_set_oscio(struct sx150x_chip *chip, int val)
{
sx150x_i2c_write(chip->client,
- chip->dev_cfg->reg_clock,
+ chip->dev_cfg->pri.x789.reg_clock,
(val ? 0x1f : 0x10));
}
@@ -293,27 +356,11 @@ static int sx150x_gpio_direction_output(struct gpio_chip *gc,
return status;
}
-static int sx150x_gpio_to_irq(struct gpio_chip *gc, unsigned offset)
-{
- struct sx150x_chip *chip;
-
- chip = container_of(gc, struct sx150x_chip, gpio_chip);
-
- if (offset >= chip->dev_cfg->ngpios)
- return -EINVAL;
-
- if (chip->irq_base < 0)
- return -EINVAL;
-
- return chip->irq_base + offset;
-}
-
static void sx150x_irq_mask(struct irq_data *d)
{
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
- unsigned n;
+ unsigned n = d->hwirq;
- n = d->irq - chip->irq_base;
chip->irq_masked |= (1 << n);
chip->irq_update = n;
}
@@ -321,9 +368,8 @@ static void sx150x_irq_mask(struct irq_data *d)
static void sx150x_irq_unmask(struct irq_data *d)
{
struct sx150x_chip *chip = irq_data_get_irq_chip_data(d);
- unsigned n;
+ unsigned n = d->hwirq;
- n = d->irq - chip->irq_base;
chip->irq_masked &= ~(1 << n);
chip->irq_update = n;
}
@@ -336,7 +382,7 @@ static int sx150x_irq_set_type(struct irq_data *d, unsigned int flow_type)
if (flow_type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW))
return -EINVAL;
- n = d->irq - chip->irq_base;
+ n = d->hwirq;
if (flow_type & IRQ_TYPE_EDGE_RISING)
val |= 0x1;
@@ -371,7 +417,9 @@ static irqreturn_t sx150x_irq_thread_fn(int irq, void *dev_id)
val);
for (n = 0; n < 8; ++n) {
if (val & (1 << n)) {
- sub_irq = chip->irq_base + (i * 8) + n;
+ sub_irq = irq_find_mapping(
+ chip->gpio_chip.irqdomain,
+ (i * 8) + n);
handle_nested_irq(sub_irq);
++nhandled;
}
@@ -401,7 +449,7 @@ static void sx150x_irq_bus_sync_unlock(struct irq_data *d)
/* Avoid updates if nothing changed */
if (chip->dev_sense == chip->irq_sense &&
- chip->dev_sense == chip->irq_masked)
+ chip->dev_masked == chip->irq_masked)
goto out;
chip->dev_sense = chip->irq_sense;
@@ -428,15 +476,19 @@ static void sx150x_init_chip(struct sx150x_chip *chip,
chip->client = client;
chip->dev_cfg = &sx150x_devices[driver_data];
+ chip->gpio_chip.dev = &client->dev;
chip->gpio_chip.label = client->name;
chip->gpio_chip.direction_input = sx150x_gpio_direction_input;
chip->gpio_chip.direction_output = sx150x_gpio_direction_output;
chip->gpio_chip.get = sx150x_gpio_get;
chip->gpio_chip.set = sx150x_gpio_set;
- chip->gpio_chip.to_irq = sx150x_gpio_to_irq;
chip->gpio_chip.base = pdata->gpio_base;
chip->gpio_chip.can_sleep = true;
chip->gpio_chip.ngpio = chip->dev_cfg->ngpios;
+#ifdef CONFIG_OF_GPIO
+ chip->gpio_chip.of_node = client->dev.of_node;
+ chip->gpio_chip.of_gpio_n_cells = 2;
+#endif
if (pdata->oscio_is_gpo)
++chip->gpio_chip.ngpio;
@@ -470,13 +522,13 @@ static int sx150x_reset(struct sx150x_chip *chip)
int err;
err = i2c_smbus_write_byte_data(chip->client,
- chip->dev_cfg->reg_reset,
+ chip->dev_cfg->pri.x789.reg_reset,
0x12);
if (err < 0)
return err;
err = i2c_smbus_write_byte_data(chip->client,
- chip->dev_cfg->reg_reset,
+ chip->dev_cfg->pri.x789.reg_reset,
0x34);
return err;
}
@@ -492,9 +544,14 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
return err;
}
- err = sx150x_i2c_write(chip->client,
- chip->dev_cfg->reg_misc,
- 0x01);
+ if (chip->dev_cfg->model == SX150X_789)
+ err = sx150x_i2c_write(chip->client,
+ chip->dev_cfg->pri.x789.reg_misc,
+ 0x01);
+ else
+ err = sx150x_i2c_write(chip->client,
+ chip->dev_cfg->pri.x456.reg_advance,
+ 0x04);
if (err < 0)
return err;
@@ -508,15 +565,27 @@ static int sx150x_init_hw(struct sx150x_chip *chip,
if (err < 0)
return err;
- err = sx150x_init_io(chip, chip->dev_cfg->reg_drain,
- pdata->io_open_drain_ena);
- if (err < 0)
- return err;
+ if (chip->dev_cfg->model == SX150X_789) {
+ err = sx150x_init_io(chip,
+ chip->dev_cfg->pri.x789.reg_drain,
+ pdata->io_open_drain_ena);
+ if (err < 0)
+ return err;
+
+ err = sx150x_init_io(chip,
+ chip->dev_cfg->pri.x789.reg_polarity,
+ pdata->io_polarity);
+ if (err < 0)
+ return err;
+ } else {
+ /* Set all pins to work in normal mode */
+ err = sx150x_init_io(chip,
+ chip->dev_cfg->pri.x456.reg_pld_mode,
+ 0);
+ if (err < 0)
+ return err;
+ }
- err = sx150x_init_io(chip, chip->dev_cfg->reg_polarity,
- pdata->io_polarity);
- if (err < 0)
- return err;
if (pdata->oscio_is_gpo)
sx150x_set_oscio(chip, 0);
@@ -529,31 +598,24 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
int irq_base)
{
int err;
- unsigned n;
- unsigned irq;
chip->irq_summary = irq_summary;
chip->irq_base = irq_base;
- for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
- irq = irq_base + n;
- irq_set_chip_data(irq, chip);
- irq_set_chip_and_handler(irq, &chip->irq_chip, handle_edge_irq);
- irq_set_nested_thread(irq, 1);
-#ifdef CONFIG_ARM
- set_irq_flags(irq, IRQF_VALID);
-#else
- irq_set_noprobe(irq);
-#endif
+ /* Add gpio chip to irq subsystem */
+ err = gpiochip_irqchip_add(&chip->gpio_chip,
+ &chip->irq_chip, chip->irq_base,
+ handle_edge_irq, IRQ_TYPE_EDGE_BOTH);
+ if (err) {
+ dev_err(&chip->client->dev,
+ "could not connect irqchip to gpiochip\n");
+ return err;
}
err = devm_request_threaded_irq(&chip->client->dev,
- irq_summary,
- NULL,
- sx150x_irq_thread_fn,
- IRQF_SHARED | IRQF_TRIGGER_FALLING,
- chip->irq_chip.name,
- chip);
+ irq_summary, NULL, sx150x_irq_thread_fn,
+ IRQF_ONESHOT | IRQF_SHARED | IRQF_TRIGGER_FALLING,
+ chip->irq_chip.name, chip);
if (err < 0) {
chip->irq_summary = -1;
chip->irq_base = -1;
@@ -562,17 +624,6 @@ static int sx150x_install_irq_chip(struct sx150x_chip *chip,
return err;
}
-static void sx150x_remove_irq_chip(struct sx150x_chip *chip)
-{
- unsigned n;
- unsigned irq;
-
- for (n = 0; n < chip->dev_cfg->ngpios; ++n) {
- irq = chip->irq_base + n;
- irq_set_chip_and_handler(irq, NULL, NULL);
- }
-}
-
static int sx150x_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -626,16 +677,14 @@ static int sx150x_remove(struct i2c_client *client)
chip = i2c_get_clientdata(client);
gpiochip_remove(&chip->gpio_chip);
- if (chip->irq_summary >= 0)
- sx150x_remove_irq_chip(chip);
-
return 0;
}
static struct i2c_driver sx150x_driver = {
.driver = {
.name = "sx150x",
- .owner = THIS_MODULE
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(sx150x_of_match),
},
.probe = sx150x_probe,
.remove = sx150x_remove,
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index abdcf58935f5..11aed2671065 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -232,16 +232,13 @@ static irqreturn_t tc3589x_gpio_irq(int irq, void *dev)
static int tc3589x_gpio_probe(struct platform_device *pdev)
{
struct tc3589x *tc3589x = dev_get_drvdata(pdev->dev.parent);
- struct tc3589x_gpio_platform_data *pdata;
struct device_node *np = pdev->dev.of_node;
struct tc3589x_gpio *tc3589x_gpio;
int ret;
int irq;
- pdata = tc3589x->pdata->gpio;
-
- if (!(pdata || np)) {
- dev_err(&pdev->dev, "No platform data or Device Tree found\n");
+ if (!np) {
+ dev_err(&pdev->dev, "No Device Tree node found\n");
return -EINVAL;
}
@@ -305,9 +302,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
irq,
NULL);
- if (pdata && pdata->setup)
- pdata->setup(tc3589x, tc3589x_gpio->chip.base);
-
platform_set_drvdata(pdev, tc3589x_gpio);
return 0;
@@ -316,11 +310,6 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
static int tc3589x_gpio_remove(struct platform_device *pdev)
{
struct tc3589x_gpio *tc3589x_gpio = platform_get_drvdata(pdev);
- struct tc3589x *tc3589x = tc3589x_gpio->tc3589x;
- struct tc3589x_gpio_platform_data *pdata = tc3589x->pdata->gpio;
-
- if (pdata && pdata->remove)
- pdata->remove(tc3589x, tc3589x_gpio->chip.base);
gpiochip_remove(&tc3589x_gpio->chip);
diff --git a/drivers/gpio/gpio-tz1090-pdc.c b/drivers/gpio/gpio-tz1090-pdc.c
index d7536226b847..ede7e403ffde 100644
--- a/drivers/gpio/gpio-tz1090-pdc.c
+++ b/drivers/gpio/gpio-tz1090-pdc.c
@@ -190,7 +190,7 @@ static int tz1090_pdc_gpio_probe(struct platform_device *pdev)
/* Ioremap the registers */
priv->reg = devm_ioremap(&pdev->dev, res_regs->start,
- res_regs->end - res_regs->start);
+ resource_size(res_regs));
if (!priv->reg) {
dev_err(&pdev->dev, "unable to ioremap registers\n");
return -ENOMEM;
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
index e3024bbba447..445660adc898 100644
--- a/drivers/gpio/gpio-tz1090.c
+++ b/drivers/gpio/gpio-tz1090.c
@@ -573,7 +573,7 @@ static int tz1090_gpio_probe(struct platform_device *pdev)
/* Ioremap the registers */
priv.reg = devm_ioremap(&pdev->dev, res_regs->start,
- res_regs->end - res_regs->start);
+ resource_size(res_regs));
if (!priv.reg) {
dev_err(&pdev->dev, "unable to ioremap registers\n");
return -ENOMEM;
diff --git a/drivers/gpio/gpio-vf610.c b/drivers/gpio/gpio-vf610.c
index 4ee4cee832ec..971c73964ef1 100644
--- a/drivers/gpio/gpio-vf610.c
+++ b/drivers/gpio/gpio-vf610.c
@@ -278,7 +278,6 @@ static int vf610_gpio_probe(struct platform_device *pdev)
static struct platform_driver vf610_gpio_driver = {
.driver = {
.name = "gpio-vf610",
- .owner = THIS_MODULE,
.of_match_table = vf610_gpio_dt_ids,
},
.probe = vf610_gpio_probe,
diff --git a/drivers/gpio/gpio-vx855.c b/drivers/gpio/gpio-vx855.c
index 9d21d2fcc327..57b470d5b39e 100644
--- a/drivers/gpio/gpio-vx855.c
+++ b/drivers/gpio/gpio-vx855.c
@@ -52,8 +52,6 @@ struct vx855_gpio {
spinlock_t lock;
u32 io_gpi;
u32 io_gpo;
- bool gpi_reserved;
- bool gpo_reserved;
};
/* resolve a GPIx into the corresponding bit position */
@@ -224,14 +222,13 @@ static int vx855gpio_probe(struct platform_device *pdev)
struct resource *res_gpi;
struct resource *res_gpo;
struct vx855_gpio *vg;
- int ret;
res_gpi = platform_get_resource(pdev, IORESOURCE_IO, 0);
res_gpo = platform_get_resource(pdev, IORESOURCE_IO, 1);
if (!res_gpi || !res_gpo)
return -EBUSY;
- vg = kzalloc(sizeof(*vg), GFP_KERNEL);
+ vg = devm_kzalloc(&pdev->dev, sizeof(*vg), GFP_KERNEL);
if (!vg)
return -ENOMEM;
@@ -250,56 +247,27 @@ static int vx855gpio_probe(struct platform_device *pdev)
* succeed. Ignore and continue.
*/
- if (!request_region(res_gpi->start, resource_size(res_gpi),
- MODULE_NAME "_gpi"))
+ if (!devm_request_region(&pdev->dev, res_gpi->start,
+ resource_size(res_gpi), MODULE_NAME "_gpi"))
dev_warn(&pdev->dev,
"GPI I/O resource busy, probably claimed by ACPI\n");
- else
- vg->gpi_reserved = true;
- if (!request_region(res_gpo->start, resource_size(res_gpo),
- MODULE_NAME "_gpo"))
+ if (!devm_request_region(&pdev->dev, res_gpo->start,
+ resource_size(res_gpo), MODULE_NAME "_gpo"))
dev_warn(&pdev->dev,
"GPO I/O resource busy, probably claimed by ACPI\n");
- else
- vg->gpo_reserved = true;
vx855gpio_gpio_setup(vg);
- ret = gpiochip_add(&vg->gpio);
- if (ret) {
- dev_err(&pdev->dev, "failed to register GPIOs\n");
- goto out_release;
- }
-
- return 0;
-
-out_release:
- if (vg->gpi_reserved)
- release_region(res_gpi->start, resource_size(res_gpi));
- if (vg->gpo_reserved)
- release_region(res_gpi->start, resource_size(res_gpo));
- kfree(vg);
- return ret;
+ return gpiochip_add(&vg->gpio);
}
static int vx855gpio_remove(struct platform_device *pdev)
{
struct vx855_gpio *vg = platform_get_drvdata(pdev);
- struct resource *res;
gpiochip_remove(&vg->gpio);
- if (vg->gpi_reserved) {
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
- release_region(res->start, resource_size(res));
- }
- if (vg->gpo_reserved) {
- res = platform_get_resource(pdev, IORESOURCE_IO, 1);
- release_region(res->start, resource_size(res));
- }
-
- kfree(vg);
return 0;
}
diff --git a/drivers/gpio/gpio-xgene-sb.c b/drivers/gpio/gpio-xgene-sb.c
new file mode 100644
index 000000000000..b6a15c39293e
--- /dev/null
+++ b/drivers/gpio/gpio-xgene-sb.c
@@ -0,0 +1,160 @@
+/*
+ * AppliedMicro X-Gene SoC GPIO-Standby Driver
+ *
+ * Copyright (c) 2014, Applied Micro Circuits Corporation
+ * Author: Tin Huynh <tnhuynh@apm.com>.
+ * Y Vo <yvo@apm.com>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/basic_mmio_gpio.h>
+
+#define XGENE_MAX_GPIO_DS 22
+#define XGENE_MAX_GPIO_DS_IRQ 6
+
+#define GPIO_MASK(x) (1U << ((x) % 32))
+
+#define MPA_GPIO_INT_LVL 0x0290
+#define MPA_GPIO_OE_ADDR 0x029c
+#define MPA_GPIO_OUT_ADDR 0x02a0
+#define MPA_GPIO_IN_ADDR 0x02a4
+#define MPA_GPIO_SEL_LO 0x0294
+
+/**
+ * struct xgene_gpio_sb - GPIO-Standby private data structure.
+ * @bgc: memory-mapped GPIO controllers.
+ * @irq: Mapping GPIO pins and interrupt number
+ * nirq: Number of GPIO pins that supports interrupt
+ */
+struct xgene_gpio_sb {
+ struct bgpio_chip bgc;
+ u32 *irq;
+ u32 nirq;
+};
+
+static inline struct xgene_gpio_sb *to_xgene_gpio_sb(struct gpio_chip *gc)
+{
+ struct bgpio_chip *bgc = to_bgpio_chip(gc);
+
+ return container_of(bgc, struct xgene_gpio_sb, bgc);
+}
+
+static void xgene_gpio_set_bit(struct bgpio_chip *bgc, void __iomem *reg, u32 gpio, int val)
+{
+ u32 data;
+
+ data = bgc->read_reg(reg);
+ if (val)
+ data |= GPIO_MASK(gpio);
+ else
+ data &= ~GPIO_MASK(gpio);
+ bgc->write_reg(reg, data);
+}
+
+static int apm_gpio_sb_to_irq(struct gpio_chip *gc, u32 gpio)
+{
+ struct xgene_gpio_sb *priv = to_xgene_gpio_sb(gc);
+
+ if (priv->irq[gpio])
+ return priv->irq[gpio];
+
+ return -ENXIO;
+}
+
+static int xgene_gpio_sb_probe(struct platform_device *pdev)
+{
+ struct xgene_gpio_sb *priv;
+ u32 ret, i;
+ u32 default_lines[] = {0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D};
+ struct resource *res;
+ void __iomem *regs;
+
+ priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(&pdev->dev, res);
+ if (!regs)
+ return PTR_ERR(regs);
+
+ ret = bgpio_init(&priv->bgc, &pdev->dev, 4,
+ regs + MPA_GPIO_IN_ADDR,
+ regs + MPA_GPIO_OUT_ADDR, NULL,
+ regs + MPA_GPIO_OE_ADDR, NULL, 0);
+ if (ret)
+ return ret;
+
+ priv->bgc.gc.to_irq = apm_gpio_sb_to_irq;
+ priv->bgc.gc.ngpio = XGENE_MAX_GPIO_DS;
+
+ priv->nirq = XGENE_MAX_GPIO_DS_IRQ;
+
+ priv->irq = devm_kzalloc(&pdev->dev, sizeof(u32) * XGENE_MAX_GPIO_DS,
+ GFP_KERNEL);
+ if (!priv->irq)
+ return -ENOMEM;
+ memset(priv->irq, 0, sizeof(u32) * XGENE_MAX_GPIO_DS);
+
+ for (i = 0; i < priv->nirq; i++) {
+ priv->irq[default_lines[i]] = platform_get_irq(pdev, i);
+ xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_SEL_LO,
+ default_lines[i] * 2, 1);
+ xgene_gpio_set_bit(&priv->bgc, regs + MPA_GPIO_INT_LVL, i, 1);
+ }
+
+ platform_set_drvdata(pdev, priv);
+
+ ret = gpiochip_add(&priv->bgc.gc);
+ if (ret)
+ dev_err(&pdev->dev, "failed to register X-Gene GPIO Standby driver\n");
+ else
+ dev_info(&pdev->dev, "X-Gene GPIO Standby driver registered\n");
+
+ return ret;
+}
+
+static int xgene_gpio_sb_remove(struct platform_device *pdev)
+{
+ struct xgene_gpio_sb *priv = platform_get_drvdata(pdev);
+
+ return bgpio_remove(&priv->bgc);
+}
+
+static const struct of_device_id xgene_gpio_sb_of_match[] = {
+ {.compatible = "apm,xgene-gpio-sb", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, xgene_gpio_sb_of_match);
+
+static struct platform_driver xgene_gpio_sb_driver = {
+ .driver = {
+ .name = "xgene-gpio-sb",
+ .of_match_table = xgene_gpio_sb_of_match,
+ },
+ .probe = xgene_gpio_sb_probe,
+ .remove = xgene_gpio_sb_remove,
+};
+module_platform_driver(xgene_gpio_sb_driver);
+
+MODULE_AUTHOR("AppliedMicro");
+MODULE_DESCRIPTION("APM X-Gene GPIO Standby driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpio/gpio-xilinx.c b/drivers/gpio/gpio-xilinx.c
index ba18b06c9a21..61243d177740 100644
--- a/drivers/gpio/gpio-xilinx.c
+++ b/drivers/gpio/gpio-xilinx.c
@@ -30,7 +30,7 @@
#define XGPIO_CHANNEL_OFFSET 0x8
/* Read/Write access to the GPIO registers */
-#ifdef CONFIG_ARCH_ZYNQ
+#if defined(CONFIG_ARCH_ZYNQ) || defined(CONFIG_X86)
# define xgpio_readreg(offset) readl(offset)
# define xgpio_writereg(offset, val) writel(val, offset)
#else
@@ -40,37 +40,66 @@
/**
* struct xgpio_instance - Stores information about GPIO device
- * struct of_mm_gpio_chip mmchip: OF GPIO chip for memory mapped banks
- * gpio_state: GPIO state shadow register
- * gpio_dir: GPIO direction shadow register
- * offset: GPIO channel offset
- * gpio_lock: Lock used for synchronization
+ * @mmchip: OF GPIO chip for memory mapped banks
+ * @gpio_state: GPIO state shadow register
+ * @gpio_dir: GPIO direction shadow register
+ * @gpio_lock: Lock used for synchronization
+ * @inited: True if the port has been inited
*/
struct xgpio_instance {
struct of_mm_gpio_chip mmchip;
- u32 gpio_state;
- u32 gpio_dir;
- u32 offset;
- spinlock_t gpio_lock;
+ unsigned int gpio_width[2];
+ u32 gpio_state[2];
+ u32 gpio_dir[2];
+ spinlock_t gpio_lock[2];
};
+static inline int xgpio_index(struct xgpio_instance *chip, int gpio)
+{
+ if (gpio >= chip->gpio_width[0])
+ return 1;
+
+ return 0;
+}
+
+static inline int xgpio_regoffset(struct xgpio_instance *chip, int gpio)
+{
+ if (xgpio_index(chip, gpio))
+ return XGPIO_CHANNEL_OFFSET;
+
+ return 0;
+}
+
+static inline int xgpio_offset(struct xgpio_instance *chip, int gpio)
+{
+ if (xgpio_index(chip, gpio))
+ return gpio - chip->gpio_width[0];
+
+ return gpio;
+}
+
/**
* xgpio_get - Read the specified signal of the GPIO device.
* @gc: Pointer to gpio_chip device structure.
* @gpio: GPIO signal number.
*
- * This function reads the specified signal of the GPIO device. It returns 0 if
- * the signal clear, 1 if signal is set or negative value on error.
+ * This function reads the specified signal of the GPIO device.
+ *
+ * Return:
+ * 0 if direction of GPIO signals is set as input otherwise it
+ * returns negative error value.
*/
static int xgpio_get(struct gpio_chip *gc, unsigned int gpio)
{
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
+ u32 val;
- void __iomem *regs = mm_gc->regs + chip->offset;
+ val = xgpio_readreg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_regoffset(chip, gpio));
- return !!(xgpio_readreg(regs + XGPIO_DATA_OFFSET) & BIT(gpio));
+ return !!(val & BIT(xgpio_offset(chip, gpio)));
}
/**
@@ -88,20 +117,21 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- void __iomem *regs = mm_gc->regs;
+ int index = xgpio_index(chip, gpio);
+ int offset = xgpio_offset(chip, gpio);
- spin_lock_irqsave(&chip->gpio_lock, flags);
+ spin_lock_irqsave(&chip->gpio_lock[index], flags);
/* Write to GPIO signal and set its direction to output */
if (val)
- chip->gpio_state |= BIT(gpio);
+ chip->gpio_state[index] |= BIT(offset);
else
- chip->gpio_state &= ~BIT(gpio);
+ chip->gpio_state[index] &= ~BIT(offset);
- xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
- chip->gpio_state);
+ xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
- spin_unlock_irqrestore(&chip->gpio_lock, flags);
+ spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
}
/**
@@ -109,9 +139,9 @@ static void xgpio_set(struct gpio_chip *gc, unsigned int gpio, int val)
* @gc: Pointer to gpio_chip device structure.
* @gpio: GPIO signal number.
*
- * This function sets the direction of specified GPIO signal as input.
- * It returns 0 if direction of GPIO signals is set as input otherwise it
- * returns negative error value.
+ * Return:
+ * 0 - if direction of GPIO signals is set as input
+ * otherwise it returns negative error value.
*/
static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
{
@@ -119,15 +149,17 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- void __iomem *regs = mm_gc->regs;
+ int index = xgpio_index(chip, gpio);
+ int offset = xgpio_offset(chip, gpio);
- spin_lock_irqsave(&chip->gpio_lock, flags);
+ spin_lock_irqsave(&chip->gpio_lock[index], flags);
/* Set the GPIO bit in shadow register and set direction as input */
- chip->gpio_dir |= BIT(gpio);
- xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir[index] |= BIT(offset);
+ xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
+ xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
- spin_unlock_irqrestore(&chip->gpio_lock, flags);
+ spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
return 0;
}
@@ -138,8 +170,10 @@ static int xgpio_dir_in(struct gpio_chip *gc, unsigned int gpio)
* @gpio: GPIO signal number.
* @val: Value to be written to specified signal.
*
- * This function sets the direction of specified GPIO signal as output. If all
- * GPIO signals of GPIO chip is configured as input then it returns
+ * This function sets the direction of specified GPIO signal as output.
+ *
+ * Return:
+ * If all GPIO signals of GPIO chip is configured as input then it returns
* error otherwise it returns 0.
*/
static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
@@ -148,80 +182,128 @@ static int xgpio_dir_out(struct gpio_chip *gc, unsigned int gpio, int val)
struct of_mm_gpio_chip *mm_gc = to_of_mm_gpio_chip(gc);
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- void __iomem *regs = mm_gc->regs;
+ int index = xgpio_index(chip, gpio);
+ int offset = xgpio_offset(chip, gpio);
- spin_lock_irqsave(&chip->gpio_lock, flags);
+ spin_lock_irqsave(&chip->gpio_lock[index], flags);
/* Write state of GPIO signal */
if (val)
- chip->gpio_state |= BIT(gpio);
+ chip->gpio_state[index] |= BIT(offset);
else
- chip->gpio_state &= ~BIT(gpio);
- xgpio_writereg(regs + chip->offset + XGPIO_DATA_OFFSET,
- chip->gpio_state);
+ chip->gpio_state[index] &= ~BIT(offset);
+ xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET +
+ xgpio_regoffset(chip, gpio), chip->gpio_state[index]);
/* Clear the GPIO bit in shadow register and set direction as output */
- chip->gpio_dir &= ~BIT(gpio);
- xgpio_writereg(regs + chip->offset + XGPIO_TRI_OFFSET, chip->gpio_dir);
+ chip->gpio_dir[index] &= ~BIT(offset);
+ xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET +
+ xgpio_regoffset(chip, gpio), chip->gpio_dir[index]);
- spin_unlock_irqrestore(&chip->gpio_lock, flags);
+ spin_unlock_irqrestore(&chip->gpio_lock[index], flags);
return 0;
}
/**
* xgpio_save_regs - Set initial values of GPIO pins
- * @mm_gc: pointer to memory mapped GPIO chip structure
+ * @mm_gc: Pointer to memory mapped GPIO chip structure
*/
static void xgpio_save_regs(struct of_mm_gpio_chip *mm_gc)
{
struct xgpio_instance *chip =
container_of(mm_gc, struct xgpio_instance, mmchip);
- xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_DATA_OFFSET,
- chip->gpio_state);
- xgpio_writereg(mm_gc->regs + chip->offset + XGPIO_TRI_OFFSET,
- chip->gpio_dir);
+ xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET, chip->gpio_state[0]);
+ xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET, chip->gpio_dir[0]);
+
+ if (!chip->gpio_width[1])
+ return;
+
+ xgpio_writereg(mm_gc->regs + XGPIO_DATA_OFFSET + XGPIO_TRI_OFFSET,
+ chip->gpio_state[1]);
+ xgpio_writereg(mm_gc->regs + XGPIO_TRI_OFFSET + XGPIO_TRI_OFFSET,
+ chip->gpio_dir[1]);
+}
+
+/**
+ * xgpio_remove - Remove method for the GPIO device.
+ * @pdev: pointer to the platform device
+ *
+ * This function remove gpiochips and frees all the allocated resources.
+ */
+static int xgpio_remove(struct platform_device *pdev)
+{
+ struct xgpio_instance *chip = platform_get_drvdata(pdev);
+
+ of_mm_gpiochip_remove(&chip->mmchip);
+
+ return 0;
}
/**
* xgpio_of_probe - Probe method for the GPIO device.
- * @np: pointer to device tree node
+ * @pdev: pointer to the platform device
*
- * This function probes the GPIO device in the device tree. It initializes the
- * driver data structure. It returns 0, if the driver is bound to the GPIO
- * device, or a negative value if there is an error.
+ * Return:
+ * It returns 0, if the driver is bound to the GPIO device, or
+ * a negative value if there is an error.
*/
-static int xgpio_of_probe(struct device_node *np)
+static int xgpio_probe(struct platform_device *pdev)
{
struct xgpio_instance *chip;
int status = 0;
- const u32 *tree_info;
- u32 ngpio;
+ struct device_node *np = pdev->dev.of_node;
+ u32 is_dual;
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
+ chip = devm_kzalloc(&pdev->dev, sizeof(*chip), GFP_KERNEL);
if (!chip)
return -ENOMEM;
- /* Update GPIO state shadow register with default value */
- of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state);
+ platform_set_drvdata(pdev, chip);
- /* By default, all pins are inputs */
- chip->gpio_dir = 0xFFFFFFFF;
+ /* Update GPIO state shadow register with default value */
+ of_property_read_u32(np, "xlnx,dout-default", &chip->gpio_state[0]);
/* Update GPIO direction shadow register with default value */
- of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir);
+ if (of_property_read_u32(np, "xlnx,tri-default", &chip->gpio_dir[0]))
+ chip->gpio_dir[0] = 0xFFFFFFFF;
/*
* Check device node and parent device node for device width
* and assume default width of 32
*/
- if (of_property_read_u32(np, "xlnx,gpio-width", &ngpio))
- ngpio = 32;
- chip->mmchip.gc.ngpio = (u16)ngpio;
+ if (of_property_read_u32(np, "xlnx,gpio-width", &chip->gpio_width[0]))
+ chip->gpio_width[0] = 32;
+
+ spin_lock_init(&chip->gpio_lock[0]);
+
+ if (of_property_read_u32(np, "xlnx,is-dual", &is_dual))
+ is_dual = 0;
+
+ if (is_dual) {
+ /* Update GPIO state shadow register with default value */
+ of_property_read_u32(np, "xlnx,dout-default-2",
+ &chip->gpio_state[1]);
- spin_lock_init(&chip->gpio_lock);
+ /* Update GPIO direction shadow register with default value */
+ if (of_property_read_u32(np, "xlnx,tri-default-2",
+ &chip->gpio_dir[1]))
+ chip->gpio_dir[1] = 0xFFFFFFFF;
+ /*
+ * Check device node and parent device node for device width
+ * and assume default width of 32
+ */
+ if (of_property_read_u32(np, "xlnx,gpio2-width",
+ &chip->gpio_width[1]))
+ chip->gpio_width[1] = 32;
+
+ spin_lock_init(&chip->gpio_lock[1]);
+ }
+
+ chip->mmchip.gc.ngpio = chip->gpio_width[0] + chip->gpio_width[1];
+ chip->mmchip.gc.dev = &pdev->dev;
chip->mmchip.gc.direction_input = xgpio_dir_in;
chip->mmchip.gc.direction_output = xgpio_dir_out;
chip->mmchip.gc.get = xgpio_get;
@@ -232,63 +314,11 @@ static int xgpio_of_probe(struct device_node *np)
/* Call the OF gpio helper to setup and register the GPIO device */
status = of_mm_gpiochip_add(np, &chip->mmchip);
if (status) {
- kfree(chip);
pr_err("%s: error in probe function with status %d\n",
np->full_name, status);
return status;
}
- pr_info("XGpio: %s: registered, base is %d\n", np->full_name,
- chip->mmchip.gc.base);
-
- tree_info = of_get_property(np, "xlnx,is-dual", NULL);
- if (tree_info && be32_to_cpup(tree_info)) {
- chip = kzalloc(sizeof(*chip), GFP_KERNEL);
- if (!chip)
- return -ENOMEM;
-
- /* Add dual channel offset */
- chip->offset = XGPIO_CHANNEL_OFFSET;
-
- /* Update GPIO state shadow register with default value */
- of_property_read_u32(np, "xlnx,dout-default-2",
- &chip->gpio_state);
-
- /* By default, all pins are inputs */
- chip->gpio_dir = 0xFFFFFFFF;
-
- /* Update GPIO direction shadow register with default value */
- of_property_read_u32(np, "xlnx,tri-default-2", &chip->gpio_dir);
-
- /*
- * Check device node and parent device node for device width
- * and assume default width of 32
- */
- if (of_property_read_u32(np, "xlnx,gpio2-width", &ngpio))
- ngpio = 32;
- chip->mmchip.gc.ngpio = (u16)ngpio;
-
- spin_lock_init(&chip->gpio_lock);
-
- chip->mmchip.gc.direction_input = xgpio_dir_in;
- chip->mmchip.gc.direction_output = xgpio_dir_out;
- chip->mmchip.gc.get = xgpio_get;
- chip->mmchip.gc.set = xgpio_set;
-
- chip->mmchip.save_regs = xgpio_save_regs;
-
- /* Call the OF gpio helper to setup and register the GPIO dev */
- status = of_mm_gpiochip_add(np, &chip->mmchip);
- if (status) {
- kfree(chip);
- pr_err("%s: error in probe function with status %d\n",
- np->full_name, status);
- return status;
- }
- pr_info("XGpio: %s: dual channel registered, base is %d\n",
- np->full_name, chip->mmchip.gc.base);
- }
-
return 0;
}
@@ -297,19 +327,29 @@ static const struct of_device_id xgpio_of_match[] = {
{ /* end of list */ },
};
-static int __init xgpio_init(void)
-{
- struct device_node *np;
+MODULE_DEVICE_TABLE(of, xgpio_of_match);
- for_each_matching_node(np, xgpio_of_match)
- xgpio_of_probe(np);
+static struct platform_driver xgpio_plat_driver = {
+ .probe = xgpio_probe,
+ .remove = xgpio_remove,
+ .driver = {
+ .name = "gpio-xilinx",
+ .of_match_table = xgpio_of_match,
+ },
+};
- return 0;
+static int __init xgpio_init(void)
+{
+ return platform_driver_register(&xgpio_plat_driver);
}
-/* Make sure we get initialized before anyone else tries to use us */
subsys_initcall(xgpio_init);
-/* No exit call at the moment as we cannot unregister of GPIO chips */
+
+static void __exit xgpio_exit(void)
+{
+ platform_driver_unregister(&xgpio_plat_driver);
+}
+module_exit(xgpio_exit);
MODULE_AUTHOR("Xilinx, Inc.");
MODULE_DESCRIPTION("Xilinx GPIO driver");
diff --git a/drivers/gpio/gpio-zevio.c b/drivers/gpio/gpio-zevio.c
index f769cd53f4e4..6f02d7c4cc57 100644
--- a/drivers/gpio/gpio-zevio.c
+++ b/drivers/gpio/gpio-zevio.c
@@ -181,6 +181,8 @@ static int zevio_gpio_probe(struct platform_device *pdev)
if (!controller)
return -ENOMEM;
+ platform_set_drvdata(pdev, controller);
+
/* Copy our reference */
controller->chip.gc = zevio_gpio_chip;
controller->chip.gc.dev = &pdev->dev;
@@ -202,6 +204,15 @@ static int zevio_gpio_probe(struct platform_device *pdev)
return 0;
}
+static int zevio_gpio_remove(struct platform_device *pdev)
+{
+ struct zevio_gpio *controller = platform_get_drvdata(pdev);
+
+ of_mm_gpiochip_remove(&controller->chip);
+
+ return 0;
+}
+
static const struct of_device_id zevio_gpio_of_match[] = {
{ .compatible = "lsi,zevio-gpio", },
{ },
@@ -215,6 +226,7 @@ static struct platform_driver zevio_gpio_driver = {
.of_match_table = zevio_gpio_of_match,
},
.probe = zevio_gpio_probe,
+ .remove = zevio_gpio_remove,
};
module_platform_driver(zevio_gpio_driver);
diff --git a/drivers/gpio/gpiolib-of.c b/drivers/gpio/gpiolib-of.c
index 08261f2b3a82..8cad8e400b44 100644
--- a/drivers/gpio/gpiolib-of.c
+++ b/drivers/gpio/gpiolib-of.c
@@ -210,6 +210,23 @@ err0:
}
EXPORT_SYMBOL(of_mm_gpiochip_add);
+/**
+ * of_mm_gpiochip_remove - Remove memory mapped GPIO chip (bank)
+ * @mm_gc: pointer to the of_mm_gpio_chip allocated structure
+ */
+void of_mm_gpiochip_remove(struct of_mm_gpio_chip *mm_gc)
+{
+ struct gpio_chip *gc = &mm_gc->gc;
+
+ if (!mm_gc)
+ return;
+
+ gpiochip_remove(gc);
+ iounmap(mm_gc->regs);
+ kfree(gc->label);
+}
+EXPORT_SYMBOL(of_mm_gpiochip_remove);
+
#ifdef CONFIG_PINCTRL
static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
diff --git a/drivers/gpio/gpiolib-sysfs.c b/drivers/gpio/gpiolib-sysfs.c
index f62aa115d79a..7722ed53bd65 100644
--- a/drivers/gpio/gpiolib-sysfs.c
+++ b/drivers/gpio/gpiolib-sysfs.c
@@ -648,6 +648,7 @@ int gpiod_export_link(struct device *dev, const char *name,
if (tdev != NULL) {
status = sysfs_create_link(&dev->kobj, &tdev->kobj,
name);
+ put_device(tdev);
} else {
status = -ENODEV;
}
@@ -695,7 +696,7 @@ int gpiod_sysfs_set_active_low(struct gpio_desc *desc, int value)
}
status = sysfs_set_active_low(desc, dev, value);
-
+ put_device(dev);
unlock:
mutex_unlock(&sysfs_lock);
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 568aa2b6bdb0..1ca9295b2c10 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1659,7 +1659,7 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
- static const char *suffixes[] = { "gpios", "gpio" };
+ static const char * const suffixes[] = { "gpios", "gpio" };
char prop_name[32]; /* 32 is max size of property name */
enum of_gpio_flags of_flags;
struct gpio_desc *desc;
@@ -1667,9 +1667,11 @@ static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
if (con_id)
- snprintf(prop_name, 32, "%s-%s", con_id, suffixes[i]);
+ snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
+ suffixes[i]);
else
- snprintf(prop_name, 32, "%s", suffixes[i]);
+ snprintf(prop_name, sizeof(prop_name), "%s",
+ suffixes[i]);
desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
&of_flags);
diff --git a/drivers/gpu/Makefile b/drivers/gpu/Makefile
index 70da9eb52a42..e9ed439a5b65 100644
--- a/drivers/gpu/Makefile
+++ b/drivers/gpu/Makefile
@@ -1,3 +1,6 @@
-obj-y += drm/ vga/
+# drm/tegra depends on host1x, so if both drivers are built-in care must be
+# taken to initialize them in the correct order. Link order is the only way
+# to ensure this currently.
obj-$(CONFIG_TEGRA_HOST1X) += host1x/
+obj-y += drm/ vga/
obj-$(CONFIG_IMX_IPUV3_CORE) += ipu-v3/
diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
index c3413b6adb17..151a050129e7 100644
--- a/drivers/gpu/drm/Kconfig
+++ b/drivers/gpu/drm/Kconfig
@@ -62,12 +62,13 @@ config DRM_TTM
config DRM_GEM_CMA_HELPER
bool
- depends on DRM
+ depends on DRM && HAVE_DMA_ATTRS
help
Choose this if you need the GEM CMA helper functions
config DRM_KMS_CMA_HELPER
bool
+ depends on DRM && HAVE_DMA_ATTRS
select DRM_GEM_CMA_HELPER
select DRM_KMS_FB_HELPER
select FB_SYS_FILLRECT
@@ -110,7 +111,6 @@ config DRM_RADEON
select HWMON
select BACKLIGHT_CLASS_DEVICE
select INTERVAL_TREE
- select MMU_NOTIFIER
help
Choose this option if you have an ATI Radeon graphics card. There
are both PCI and AGP versions. You don't need to choose this to
@@ -183,6 +183,8 @@ source "drivers/gpu/drm/cirrus/Kconfig"
source "drivers/gpu/drm/armada/Kconfig"
+source "drivers/gpu/drm/atmel-hlcdc/Kconfig"
+
source "drivers/gpu/drm/rcar-du/Kconfig"
source "drivers/gpu/drm/shmobile/Kconfig"
diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
index e620807418ea..2c239b99de64 100644
--- a/drivers/gpu/drm/Makefile
+++ b/drivers/gpu/drm/Makefile
@@ -14,7 +14,7 @@ drm-y := drm_auth.o drm_bufs.o drm_cache.o \
drm_info.o drm_debugfs.o drm_encoder_slave.o \
drm_trace_points.o drm_global.o drm_prime.o \
drm_rect.o drm_vma_manager.o drm_flip_work.o \
- drm_modeset_lock.o drm_atomic.o
+ drm_modeset_lock.o drm_atomic.o drm_bridge.o
drm-$(CONFIG_COMPAT) += drm_ioc32.o
drm-$(CONFIG_DRM_GEM_CMA_HELPER) += drm_gem_cma_helper.o
@@ -55,6 +55,7 @@ obj-$(CONFIG_DRM_GMA500) += gma500/
obj-$(CONFIG_DRM_UDL) += udl/
obj-$(CONFIG_DRM_AST) += ast/
obj-$(CONFIG_DRM_ARMADA) += armada/
+obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc/
obj-$(CONFIG_DRM_RCAR_DU) += rcar-du/
obj-$(CONFIG_DRM_SHMOBILE) +=shmobile/
obj-$(CONFIG_DRM_OMAP) += omapdrm/
diff --git a/drivers/gpu/drm/amd/amdkfd/Makefile b/drivers/gpu/drm/amd/amdkfd/Makefile
index 307a309110e6..0f4960148126 100644
--- a/drivers/gpu/drm/amd/amdkfd/Makefile
+++ b/drivers/gpu/drm/amd/amdkfd/Makefile
@@ -7,7 +7,10 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include/
amdkfd-y := kfd_module.o kfd_device.o kfd_chardev.o kfd_topology.o \
kfd_pasid.o kfd_doorbell.o kfd_flat_memory.o \
kfd_process.o kfd_queue.o kfd_mqd_manager.o \
- kfd_kernel_queue.o kfd_packet_manager.o \
- kfd_process_queue_manager.o kfd_device_queue_manager.o
+ kfd_mqd_manager_cik.o kfd_mqd_manager_vi.o \
+ kfd_kernel_queue.o kfd_kernel_queue_cik.o \
+ kfd_kernel_queue_vi.o kfd_packet_manager.o \
+ kfd_process_queue_manager.o kfd_device_queue_manager.o \
+ kfd_device_queue_manager_cik.o kfd_device_queue_manager_vi.o \
obj-$(CONFIG_HSA_AMD) += amdkfd.o
diff --git a/drivers/gpu/drm/amd/amdkfd/cik_regs.h b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
index 607fc5ceadbe..01ff332fabd4 100644
--- a/drivers/gpu/drm/amd/amdkfd/cik_regs.h
+++ b/drivers/gpu/drm/amd/amdkfd/cik_regs.h
@@ -168,6 +168,8 @@
#define IB_ATC_EN (1U << 23)
#define DEFAULT_MIN_IB_AVAIL_SIZE (3U << 20)
+#define AQL_ENABLE 1
+
#define CP_HQD_DEQUEUE_REQUEST 0xC974
#define DEQUEUE_REQUEST_DRAIN 1
#define DEQUEUE_REQUEST_RESET 2
@@ -188,6 +190,17 @@
#define MQD_VMID_MASK (0xf << 0)
#define MQD_CONTROL_PRIV_STATE_EN (1U << 8)
+#define SDMA_RB_VMID(x) (x << 24)
+#define SDMA_RB_ENABLE (1 << 0)
+#define SDMA_RB_SIZE(x) ((x) << 1) /* log2 */
+#define SDMA_RPTR_WRITEBACK_ENABLE (1 << 12)
+#define SDMA_RPTR_WRITEBACK_TIMER(x) ((x) << 16) /* log2 */
+#define SDMA_OFFSET(x) (x << 0)
+#define SDMA_DB_ENABLE (1 << 28)
+#define SDMA_ATC (1 << 0)
+#define SDMA_VA_PTR32 (1 << 4)
+#define SDMA_VA_SHARED_BASE(x) (x << 8)
+
#define GRBM_GFX_INDEX 0x30800
#define INSTANCE_INDEX(x) ((x) << 0)
#define SH_INDEX(x) ((x) << 8)
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
index fcfdf23e1913..5c50aa8a8908 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
@@ -178,6 +178,22 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
return -EFAULT;
}
+ if (args->eop_buffer_address &&
+ !access_ok(VERIFY_WRITE,
+ (const void __user *) args->eop_buffer_address,
+ sizeof(uint32_t))) {
+ pr_debug("kfd: can't access eop buffer");
+ return -EFAULT;
+ }
+
+ if (args->ctx_save_restore_address &&
+ !access_ok(VERIFY_WRITE,
+ (const void __user *) args->ctx_save_restore_address,
+ sizeof(uint32_t))) {
+ pr_debug("kfd: can't access ctx save restore buffer");
+ return -EFAULT;
+ }
+
q_properties->is_interop = false;
q_properties->queue_percent = args->queue_percentage;
q_properties->priority = args->queue_priority;
@@ -185,9 +201,16 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
q_properties->queue_size = args->ring_size;
q_properties->read_ptr = (uint32_t *) args->read_pointer_address;
q_properties->write_ptr = (uint32_t *) args->write_pointer_address;
+ q_properties->eop_ring_buffer_address = args->eop_buffer_address;
+ q_properties->eop_ring_buffer_size = args->eop_buffer_size;
+ q_properties->ctx_save_restore_area_address =
+ args->ctx_save_restore_address;
+ q_properties->ctx_save_restore_area_size = args->ctx_save_restore_size;
if (args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE ||
args->queue_type == KFD_IOC_QUEUE_TYPE_COMPUTE_AQL)
q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
+ else if (args->queue_type == KFD_IOC_QUEUE_TYPE_SDMA)
+ q_properties->type = KFD_QUEUE_TYPE_SDMA;
else
return -ENOTSUPP;
@@ -214,6 +237,11 @@ static int set_queue_properties_from_user(struct queue_properties *q_properties,
pr_debug("Queue Format (%d)\n", q_properties->format);
+ pr_debug("Queue EOP (0x%llX)\n", q_properties->eop_ring_buffer_address);
+
+ pr_debug("Queue CTX save arex (0x%llX)\n",
+ q_properties->ctx_save_restore_area_address);
+
return 0;
}
@@ -235,9 +263,12 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
if (err)
return err;
+ pr_debug("kfd: looking for gpu id 0x%x\n", args->gpu_id);
dev = kfd_device_by_id(args->gpu_id);
- if (dev == NULL)
+ if (dev == NULL) {
+ pr_debug("kfd: gpu id 0x%x was not found\n", args->gpu_id);
return -EINVAL;
+ }
mutex_lock(&p->mutex);
@@ -251,8 +282,8 @@ static int kfd_ioctl_create_queue(struct file *filep, struct kfd_process *p,
p->pasid,
dev->id);
- err = pqm_create_queue(&p->pqm, dev, filep, &q_properties, 0,
- KFD_QUEUE_TYPE_COMPUTE, &queue_id);
+ err = pqm_create_queue(&p->pqm, dev, filep, &q_properties,
+ 0, q_properties.type, &queue_id);
if (err != 0)
goto err_create_queue;
@@ -385,7 +416,7 @@ static int kfd_ioctl_set_memory_policy(struct file *filep,
(args->alternate_policy == KFD_IOC_CACHE_POLICY_COHERENT)
? cache_policy_coherent : cache_policy_noncoherent;
- if (!dev->dqm->set_cache_memory_policy(dev->dqm,
+ if (!dev->dqm->ops.set_cache_memory_policy(dev->dqm,
&pdd->qpd,
default_policy,
alternate_policy,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device.c b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
index 25bc47f3c1cf..5bc32c26b989 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device.c
@@ -31,11 +31,20 @@
#define MQD_SIZE_ALIGNED 768
static const struct kfd_device_info kaveri_device_info = {
+ .asic_family = CHIP_KAVERI,
.max_pasid_bits = 16,
.ih_ring_entry_size = 4 * sizeof(uint32_t),
.mqd_size_aligned = MQD_SIZE_ALIGNED
};
+static const struct kfd_device_info carrizo_device_info = {
+ .asic_family = CHIP_CARRIZO,
+ .max_pasid_bits = 16,
+ .ih_ring_entry_size = 4 * sizeof(uint32_t),
+ .num_of_watch_points = 4,
+ .mqd_size_aligned = MQD_SIZE_ALIGNED
+};
+
struct kfd_deviceid {
unsigned short did;
const struct kfd_device_info *device_info;
@@ -64,9 +73,13 @@ static const struct kfd_deviceid supported_devices[] = {
{ 0x1318, &kaveri_device_info }, /* Kaveri */
{ 0x131B, &kaveri_device_info }, /* Kaveri */
{ 0x131C, &kaveri_device_info }, /* Kaveri */
- { 0x131D, &kaveri_device_info }, /* Kaveri */
+ { 0x131D, &kaveri_device_info } /* Kaveri */
};
+static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
+ unsigned int chunk_size);
+static void kfd_gtt_sa_fini(struct kfd_dev *kfd);
+
static const struct kfd_device_info *lookup_device_info(unsigned short did)
{
size_t i;
@@ -173,16 +186,39 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
size = max_num_of_queues_per_device *
kfd->device_info->mqd_size_aligned;
- /* add another 512KB for all other allocations on gart */
+ /*
+ * calculate max size of runlist packet.
+ * There can be only 2 packets at once
+ */
+ size += (KFD_MAX_NUM_OF_PROCESSES * sizeof(struct pm4_map_process) +
+ max_num_of_queues_per_device *
+ sizeof(struct pm4_map_queues) + sizeof(struct pm4_runlist)) * 2;
+
+ /* Add size of HIQ & DIQ */
+ size += KFD_KERNEL_QUEUE_SIZE * 2;
+
+ /* add another 512KB for all other allocations on gart (HPD, fences) */
size += 512 * 1024;
- if (kfd2kgd->init_sa_manager(kfd->kgd, size)) {
+ if (kfd2kgd->init_gtt_mem_allocation(kfd->kgd, size, &kfd->gtt_mem,
+ &kfd->gtt_start_gpu_addr, &kfd->gtt_start_cpu_ptr)) {
dev_err(kfd_device,
- "Error initializing sa manager for device (%x:%x)\n",
- kfd->pdev->vendor, kfd->pdev->device);
+ "Could not allocate %d bytes for device (%x:%x)\n",
+ size, kfd->pdev->vendor, kfd->pdev->device);
goto out;
}
+ dev_info(kfd_device,
+ "Allocated %d bytes on gart for device(%x:%x)\n",
+ size, kfd->pdev->vendor, kfd->pdev->device);
+
+ /* Initialize GTT sa with 512 byte chunk size */
+ if (kfd_gtt_sa_init(kfd, size, 512) != 0) {
+ dev_err(kfd_device,
+ "Error initializing gtt sub-allocator\n");
+ goto kfd_gtt_sa_init_error;
+ }
+
kfd_doorbell_init(kfd);
if (kfd_topology_add_device(kfd) != 0) {
@@ -209,7 +245,7 @@ bool kgd2kfd_device_init(struct kfd_dev *kfd,
goto device_queue_manager_error;
}
- if (kfd->dqm->start(kfd->dqm) != 0) {
+ if (kfd->dqm->ops.start(kfd->dqm) != 0) {
dev_err(kfd_device,
"Error starting queuen manager for device (%x:%x)\n",
kfd->pdev->vendor, kfd->pdev->device);
@@ -232,7 +268,9 @@ device_queue_manager_error:
device_iommu_pasid_error:
kfd_topology_remove_device(kfd);
kfd_topology_add_device_error:
- kfd2kgd->fini_sa_manager(kfd->kgd);
+ kfd_gtt_sa_fini(kfd);
+kfd_gtt_sa_init_error:
+ kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
dev_err(kfd_device,
"device (%x:%x) NOT added due to errors\n",
kfd->pdev->vendor, kfd->pdev->device);
@@ -246,6 +284,8 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd)
device_queue_manager_uninit(kfd->dqm);
amd_iommu_free_device(kfd->pdev);
kfd_topology_remove_device(kfd);
+ kfd_gtt_sa_fini(kfd);
+ kfd2kgd->free_gtt_mem(kfd->kgd, kfd->gtt_mem);
}
kfree(kfd);
@@ -256,7 +296,7 @@ void kgd2kfd_suspend(struct kfd_dev *kfd)
BUG_ON(kfd == NULL);
if (kfd->init_complete) {
- kfd->dqm->stop(kfd->dqm);
+ kfd->dqm->ops.stop(kfd->dqm);
amd_iommu_set_invalidate_ctx_cb(kfd->pdev, NULL);
amd_iommu_free_device(kfd->pdev);
}
@@ -277,7 +317,7 @@ int kgd2kfd_resume(struct kfd_dev *kfd)
return -ENXIO;
amd_iommu_set_invalidate_ctx_cb(kfd->pdev,
iommu_pasid_shutdown_callback);
- kfd->dqm->start(kfd->dqm);
+ kfd->dqm->ops.start(kfd->dqm);
}
return 0;
@@ -288,3 +328,188 @@ void kgd2kfd_interrupt(struct kfd_dev *kfd, const void *ih_ring_entry)
{
/* Process interrupts / schedule work as necessary */
}
+
+static int kfd_gtt_sa_init(struct kfd_dev *kfd, unsigned int buf_size,
+ unsigned int chunk_size)
+{
+ unsigned int num_of_bits;
+
+ BUG_ON(!kfd);
+ BUG_ON(!kfd->gtt_mem);
+ BUG_ON(buf_size < chunk_size);
+ BUG_ON(buf_size == 0);
+ BUG_ON(chunk_size == 0);
+
+ kfd->gtt_sa_chunk_size = chunk_size;
+ kfd->gtt_sa_num_of_chunks = buf_size / chunk_size;
+
+ num_of_bits = kfd->gtt_sa_num_of_chunks / BITS_PER_BYTE;
+ BUG_ON(num_of_bits == 0);
+
+ kfd->gtt_sa_bitmap = kzalloc(num_of_bits, GFP_KERNEL);
+
+ if (!kfd->gtt_sa_bitmap)
+ return -ENOMEM;
+
+ pr_debug("kfd: gtt_sa_num_of_chunks = %d, gtt_sa_bitmap = %p\n",
+ kfd->gtt_sa_num_of_chunks, kfd->gtt_sa_bitmap);
+
+ mutex_init(&kfd->gtt_sa_lock);
+
+ return 0;
+
+}
+
+static void kfd_gtt_sa_fini(struct kfd_dev *kfd)
+{
+ mutex_destroy(&kfd->gtt_sa_lock);
+ kfree(kfd->gtt_sa_bitmap);
+}
+
+static inline uint64_t kfd_gtt_sa_calc_gpu_addr(uint64_t start_addr,
+ unsigned int bit_num,
+ unsigned int chunk_size)
+{
+ return start_addr + bit_num * chunk_size;
+}
+
+static inline uint32_t *kfd_gtt_sa_calc_cpu_addr(void *start_addr,
+ unsigned int bit_num,
+ unsigned int chunk_size)
+{
+ return (uint32_t *) ((uint64_t) start_addr + bit_num * chunk_size);
+}
+
+int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
+ struct kfd_mem_obj **mem_obj)
+{
+ unsigned int found, start_search, cur_size;
+
+ BUG_ON(!kfd);
+
+ if (size == 0)
+ return -EINVAL;
+
+ if (size > kfd->gtt_sa_num_of_chunks * kfd->gtt_sa_chunk_size)
+ return -ENOMEM;
+
+ *mem_obj = kmalloc(sizeof(struct kfd_mem_obj), GFP_KERNEL);
+ if ((*mem_obj) == NULL)
+ return -ENOMEM;
+
+ pr_debug("kfd: allocated mem_obj = %p for size = %d\n", *mem_obj, size);
+
+ start_search = 0;
+
+ mutex_lock(&kfd->gtt_sa_lock);
+
+kfd_gtt_restart_search:
+ /* Find the first chunk that is free */
+ found = find_next_zero_bit(kfd->gtt_sa_bitmap,
+ kfd->gtt_sa_num_of_chunks,
+ start_search);
+
+ pr_debug("kfd: found = %d\n", found);
+
+ /* If there wasn't any free chunk, bail out */
+ if (found == kfd->gtt_sa_num_of_chunks)
+ goto kfd_gtt_no_free_chunk;
+
+ /* Update fields of mem_obj */
+ (*mem_obj)->range_start = found;
+ (*mem_obj)->range_end = found;
+ (*mem_obj)->gpu_addr = kfd_gtt_sa_calc_gpu_addr(
+ kfd->gtt_start_gpu_addr,
+ found,
+ kfd->gtt_sa_chunk_size);
+ (*mem_obj)->cpu_ptr = kfd_gtt_sa_calc_cpu_addr(
+ kfd->gtt_start_cpu_ptr,
+ found,
+ kfd->gtt_sa_chunk_size);
+
+ pr_debug("kfd: gpu_addr = %p, cpu_addr = %p\n",
+ (uint64_t *) (*mem_obj)->gpu_addr, (*mem_obj)->cpu_ptr);
+
+ /* If we need only one chunk, mark it as allocated and get out */
+ if (size <= kfd->gtt_sa_chunk_size) {
+ pr_debug("kfd: single bit\n");
+ set_bit(found, kfd->gtt_sa_bitmap);
+ goto kfd_gtt_out;
+ }
+
+ /* Otherwise, try to see if we have enough contiguous chunks */
+ cur_size = size - kfd->gtt_sa_chunk_size;
+ do {
+ (*mem_obj)->range_end =
+ find_next_zero_bit(kfd->gtt_sa_bitmap,
+ kfd->gtt_sa_num_of_chunks, ++found);
+ /*
+ * If next free chunk is not contiguous than we need to
+ * restart our search from the last free chunk we found (which
+ * wasn't contiguous to the previous ones
+ */
+ if ((*mem_obj)->range_end != found) {
+ start_search = found;
+ goto kfd_gtt_restart_search;
+ }
+
+ /*
+ * If we reached end of buffer, bail out with error
+ */
+ if (found == kfd->gtt_sa_num_of_chunks)
+ goto kfd_gtt_no_free_chunk;
+
+ /* Check if we don't need another chunk */
+ if (cur_size <= kfd->gtt_sa_chunk_size)
+ cur_size = 0;
+ else
+ cur_size -= kfd->gtt_sa_chunk_size;
+
+ } while (cur_size > 0);
+
+ pr_debug("kfd: range_start = %d, range_end = %d\n",
+ (*mem_obj)->range_start, (*mem_obj)->range_end);
+
+ /* Mark the chunks as allocated */
+ for (found = (*mem_obj)->range_start;
+ found <= (*mem_obj)->range_end;
+ found++)
+ set_bit(found, kfd->gtt_sa_bitmap);
+
+kfd_gtt_out:
+ mutex_unlock(&kfd->gtt_sa_lock);
+ return 0;
+
+kfd_gtt_no_free_chunk:
+ pr_debug("kfd: allocation failed with mem_obj = %p\n", mem_obj);
+ mutex_unlock(&kfd->gtt_sa_lock);
+ kfree(mem_obj);
+ return -ENOMEM;
+}
+
+int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj)
+{
+ unsigned int bit;
+
+ BUG_ON(!kfd);
+
+ /* Act like kfree when trying to free a NULL object */
+ if (!mem_obj)
+ return 0;
+
+ pr_debug("kfd: free mem_obj = %p, range_start = %d, range_end = %d\n",
+ mem_obj, mem_obj->range_start, mem_obj->range_end);
+
+ mutex_lock(&kfd->gtt_sa_lock);
+
+ /* Mark the chunks as free */
+ for (bit = mem_obj->range_start;
+ bit <= mem_obj->range_end;
+ bit++)
+ clear_bit(bit, kfd->gtt_sa_bitmap);
+
+ mutex_unlock(&kfd->gtt_sa_lock);
+
+ kfree(mem_obj);
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
index 0d8694f015c1..910ff8ab9c9c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.c
@@ -26,102 +26,60 @@
#include <linux/types.h>
#include <linux/printk.h>
#include <linux/bitops.h>
+#include <linux/sched.h>
#include "kfd_priv.h"
#include "kfd_device_queue_manager.h"
#include "kfd_mqd_manager.h"
#include "cik_regs.h"
#include "kfd_kernel_queue.h"
-#include "../../radeon/cik_reg.h"
/* Size of the per-pipe EOP queue */
#define CIK_HPD_EOP_BYTES_LOG2 11
#define CIK_HPD_EOP_BYTES (1U << CIK_HPD_EOP_BYTES_LOG2)
-static bool is_mem_initialized;
-
-static int init_memory(struct device_queue_manager *dqm);
static int set_pasid_vmid_mapping(struct device_queue_manager *dqm,
unsigned int pasid, unsigned int vmid);
static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
struct queue *q,
struct qcm_process_device *qpd);
+
static int execute_queues_cpsch(struct device_queue_manager *dqm, bool lock);
static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock);
+static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
+ struct queue *q,
+ struct qcm_process_device *qpd);
-static inline unsigned int get_pipes_num(struct device_queue_manager *dqm)
-{
- BUG_ON(!dqm || !dqm->dev);
- return dqm->dev->shared_resources.compute_pipe_count;
-}
+static void deallocate_sdma_queue(struct device_queue_manager *dqm,
+ unsigned int sdma_queue_id);
-static inline unsigned int get_first_pipe(struct device_queue_manager *dqm)
+static inline
+enum KFD_MQD_TYPE get_mqd_type_from_queue_type(enum kfd_queue_type type)
{
- BUG_ON(!dqm);
- return dqm->dev->shared_resources.first_compute_pipe;
+ if (type == KFD_QUEUE_TYPE_SDMA)
+ return KFD_MQD_TYPE_SDMA;
+ return KFD_MQD_TYPE_CP;
}
-static inline unsigned int get_pipes_num_cpsch(void)
-{
- return PIPE_PER_ME_CP_SCHEDULING;
-}
-
-static inline unsigned int
-get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
+unsigned int get_first_pipe(struct device_queue_manager *dqm)
{
- uint32_t nybble;
-
- nybble = (pdd->lds_base >> 60) & 0x0E;
-
- return nybble;
-
+ BUG_ON(!dqm || !dqm->dev);
+ return dqm->dev->shared_resources.first_compute_pipe;
}
-static inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
+unsigned int get_pipes_num(struct device_queue_manager *dqm)
{
- unsigned int shared_base;
-
- shared_base = (pdd->lds_base >> 16) & 0xFF;
-
- return shared_base;
+ BUG_ON(!dqm || !dqm->dev);
+ return dqm->dev->shared_resources.compute_pipe_count;
}
-static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble);
-static void init_process_memory(struct device_queue_manager *dqm,
- struct qcm_process_device *qpd)
+static inline unsigned int get_pipes_num_cpsch(void)
{
- struct kfd_process_device *pdd;
- unsigned int temp;
-
- BUG_ON(!dqm || !qpd);
-
- pdd = qpd_to_pdd(qpd);
-
- /* check if sh_mem_config register already configured */
- if (qpd->sh_mem_config == 0) {
- qpd->sh_mem_config =
- ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
- DEFAULT_MTYPE(MTYPE_NONCACHED) |
- APE1_MTYPE(MTYPE_NONCACHED);
- qpd->sh_mem_ape1_limit = 0;
- qpd->sh_mem_ape1_base = 0;
- }
-
- if (qpd->pqm->process->is_32bit_user_mode) {
- temp = get_sh_mem_bases_32(pdd);
- qpd->sh_mem_bases = SHARED_BASE(temp);
- qpd->sh_mem_config |= PTR32;
- } else {
- temp = get_sh_mem_bases_nybble_64(pdd);
- qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
- }
-
- pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
- qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
+ return PIPE_PER_ME_CP_SCHEDULING;
}
-static void program_sh_mem_settings(struct device_queue_manager *dqm,
+void program_sh_mem_settings(struct device_queue_manager *dqm,
struct qcm_process_device *qpd)
{
return kfd2kgd->program_sh_mem_settings(dqm->dev->kgd, qpd->vmid,
@@ -200,7 +158,10 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
*allocated_vmid = qpd->vmid;
q->properties.vmid = qpd->vmid;
- retval = create_compute_queue_nocpsch(dqm, q, qpd);
+ if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE)
+ retval = create_compute_queue_nocpsch(dqm, q, qpd);
+ if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+ retval = create_sdma_queue_nocpsch(dqm, q, qpd);
if (retval != 0) {
if (list_empty(&qpd->queues_list)) {
@@ -212,7 +173,11 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
}
list_add(&q->list, &qpd->queues_list);
- dqm->queue_count++;
+ if (q->properties.is_active)
+ dqm->queue_count++;
+
+ if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+ dqm->sdma_queue_count++;
/*
* Unconditionally increment this counter, regardless of the queue's
@@ -229,12 +194,12 @@ static int create_queue_nocpsch(struct device_queue_manager *dqm,
static int allocate_hqd(struct device_queue_manager *dqm, struct queue *q)
{
bool set;
- int pipe, bit;
+ int pipe, bit, i;
set = false;
- for (pipe = dqm->next_pipe_to_allocate; pipe < get_pipes_num(dqm);
- pipe = (pipe + 1) % get_pipes_num(dqm)) {
+ for (pipe = dqm->next_pipe_to_allocate, i = 0; i < get_pipes_num(dqm);
+ pipe = ((pipe + 1) % get_pipes_num(dqm)), ++i) {
if (dqm->allocated_queues[pipe] != 0) {
bit = find_first_bit(
(unsigned long *)&dqm->allocated_queues[pipe],
@@ -275,7 +240,7 @@ static int create_compute_queue_nocpsch(struct device_queue_manager *dqm,
BUG_ON(!dqm || !q || !qpd);
- mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+ mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
if (mqd == NULL)
return -ENOMEM;
@@ -319,28 +284,44 @@ static int destroy_queue_nocpsch(struct device_queue_manager *dqm,
pr_debug("kfd: In Func %s\n", __func__);
mutex_lock(&dqm->lock);
- mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
- if (mqd == NULL) {
- retval = -ENOMEM;
+
+ if (q->properties.type == KFD_QUEUE_TYPE_COMPUTE) {
+ mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
+ if (mqd == NULL) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ deallocate_hqd(dqm, q);
+ } else if (q->properties.type == KFD_QUEUE_TYPE_SDMA) {
+ mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA);
+ if (mqd == NULL) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ dqm->sdma_queue_count--;
+ deallocate_sdma_queue(dqm, q->sdma_id);
+ } else {
+ pr_debug("q->properties.type is invalid (%d)\n",
+ q->properties.type);
+ retval = -EINVAL;
goto out;
}
retval = mqd->destroy_mqd(mqd, q->mqd,
- KFD_PREEMPT_TYPE_WAVEFRONT,
+ KFD_PREEMPT_TYPE_WAVEFRONT_RESET,
QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
q->pipe, q->queue);
if (retval != 0)
goto out;
- deallocate_hqd(dqm, q);
-
mqd->uninit_mqd(mqd, q->mqd, q->mqd_mem_obj);
list_del(&q->list);
if (list_empty(&qpd->queues_list))
deallocate_vmid(dqm, qpd, q);
- dqm->queue_count--;
+ if (q->properties.is_active)
+ dqm->queue_count--;
/*
* Unconditionally decrement this counter, regardless of the queue's
@@ -364,7 +345,8 @@ static int update_queue(struct device_queue_manager *dqm, struct queue *q)
BUG_ON(!dqm || !q || !q->mqd);
mutex_lock(&dqm->lock);
- mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+ mqd = dqm->ops.get_mqd_manager(dqm,
+ get_mqd_type_from_queue_type(q->properties.type));
if (mqd == NULL) {
mutex_unlock(&dqm->lock);
return -ENOMEM;
@@ -415,6 +397,7 @@ static int register_process_nocpsch(struct device_queue_manager *dqm,
struct qcm_process_device *qpd)
{
struct device_process_node *n;
+ int retval;
BUG_ON(!dqm || !qpd);
@@ -429,12 +412,13 @@ static int register_process_nocpsch(struct device_queue_manager *dqm,
mutex_lock(&dqm->lock);
list_add(&n->list, &dqm->queues);
- init_process_memory(dqm, qpd);
+ retval = dqm->ops_asic_specific.register_process(dqm, qpd);
+
dqm->processes_count++;
mutex_unlock(&dqm->lock);
- return 0;
+ return retval;
}
static int unregister_process_nocpsch(struct device_queue_manager *dqm,
@@ -479,48 +463,7 @@ set_pasid_vmid_mapping(struct device_queue_manager *dqm, unsigned int pasid,
vmid);
}
-static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
-{
- /* In 64-bit mode, we can only control the top 3 bits of the LDS,
- * scratch and GPUVM apertures.
- * The hardware fills in the remaining 59 bits according to the
- * following pattern:
- * LDS: X0000000'00000000 - X0000001'00000000 (4GB)
- * Scratch: X0000001'00000000 - X0000002'00000000 (4GB)
- * GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB)
- *
- * (where X/Y is the configurable nybble with the low-bit 0)
- *
- * LDS and scratch will have the same top nybble programmed in the
- * top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
- * GPUVM can have a different top nybble programmed in the
- * top 3 bits of SH_MEM_BASES.SHARED_BASE.
- * We don't bother to support different top nybbles
- * for LDS/Scratch and GPUVM.
- */
-
- BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
- top_address_nybble == 0);
-
- return PRIVATE_BASE(top_address_nybble << 12) |
- SHARED_BASE(top_address_nybble << 12);
-}
-
-static int init_memory(struct device_queue_manager *dqm)
-{
- int i, retval;
-
- for (i = 8; i < 16; i++)
- set_pasid_vmid_mapping(dqm, 0, i);
-
- retval = kfd2kgd->init_memory(dqm->dev->kgd);
- if (retval == 0)
- is_mem_initialized = true;
- return retval;
-}
-
-
-static int init_pipelines(struct device_queue_manager *dqm,
+int init_pipelines(struct device_queue_manager *dqm,
unsigned int pipes_num, unsigned int first_pipe)
{
void *hpdptr;
@@ -539,11 +482,8 @@ static int init_pipelines(struct device_queue_manager *dqm,
* because it contains no data when there are no active queues.
*/
- err = kfd2kgd->allocate_mem(dqm->dev->kgd,
- CIK_HPD_EOP_BYTES * pipes_num,
- PAGE_SIZE,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &dqm->pipeline_mem);
+ err = kfd_gtt_sa_allocate(dqm->dev, CIK_HPD_EOP_BYTES * pipes_num,
+ &dqm->pipeline_mem);
if (err) {
pr_err("kfd: error allocate vidmem num pipes: %d\n",
@@ -556,10 +496,9 @@ static int init_pipelines(struct device_queue_manager *dqm,
memset(hpdptr, 0, CIK_HPD_EOP_BYTES * pipes_num);
- mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_COMPUTE);
+ mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_COMPUTE);
if (mqd == NULL) {
- kfd2kgd->free_mem(dqm->dev->kgd,
- (struct kgd_mem *) dqm->pipeline_mem);
+ kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem);
return -ENOMEM;
}
@@ -579,7 +518,6 @@ static int init_pipelines(struct device_queue_manager *dqm,
return 0;
}
-
static int init_scheduler(struct device_queue_manager *dqm)
{
int retval;
@@ -589,11 +527,6 @@ static int init_scheduler(struct device_queue_manager *dqm)
pr_debug("kfd: In %s\n", __func__);
retval = init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
- if (retval != 0)
- return retval;
-
- retval = init_memory(dqm);
-
return retval;
}
@@ -609,6 +542,7 @@ static int initialize_nocpsch(struct device_queue_manager *dqm)
mutex_init(&dqm->lock);
INIT_LIST_HEAD(&dqm->queues);
dqm->queue_count = dqm->next_pipe_to_allocate = 0;
+ dqm->sdma_queue_count = 0;
dqm->allocated_queues = kcalloc(get_pipes_num(dqm),
sizeof(unsigned int), GFP_KERNEL);
if (!dqm->allocated_queues) {
@@ -620,6 +554,7 @@ static int initialize_nocpsch(struct device_queue_manager *dqm)
dqm->allocated_queues[i] = (1 << QUEUES_PER_PIPE) - 1;
dqm->vmid_bitmap = (1 << VMID_PER_DEVICE) - 1;
+ dqm->sdma_bitmap = (1 << CIK_SDMA_QUEUES) - 1;
init_scheduler(dqm);
return 0;
@@ -637,8 +572,7 @@ static void uninitialize_nocpsch(struct device_queue_manager *dqm)
for (i = 0 ; i < KFD_MQD_TYPE_MAX ; i++)
kfree(dqm->mqds[i]);
mutex_destroy(&dqm->lock);
- kfd2kgd->free_mem(dqm->dev->kgd,
- (struct kgd_mem *) dqm->pipeline_mem);
+ kfd_gtt_sa_free(dqm->dev, dqm->pipeline_mem);
}
static int start_nocpsch(struct device_queue_manager *dqm)
@@ -651,6 +585,77 @@ static int stop_nocpsch(struct device_queue_manager *dqm)
return 0;
}
+static int allocate_sdma_queue(struct device_queue_manager *dqm,
+ unsigned int *sdma_queue_id)
+{
+ int bit;
+
+ if (dqm->sdma_bitmap == 0)
+ return -ENOMEM;
+
+ bit = find_first_bit((unsigned long *)&dqm->sdma_bitmap,
+ CIK_SDMA_QUEUES);
+
+ clear_bit(bit, (unsigned long *)&dqm->sdma_bitmap);
+ *sdma_queue_id = bit;
+
+ return 0;
+}
+
+static void deallocate_sdma_queue(struct device_queue_manager *dqm,
+ unsigned int sdma_queue_id)
+{
+ if (sdma_queue_id >= CIK_SDMA_QUEUES)
+ return;
+ set_bit(sdma_queue_id, (unsigned long *)&dqm->sdma_bitmap);
+}
+
+static void init_sdma_vm(struct device_queue_manager *dqm, struct queue *q,
+ struct qcm_process_device *qpd)
+{
+ uint32_t value = SDMA_ATC;
+
+ if (q->process->is_32bit_user_mode)
+ value |= SDMA_VA_PTR32 | get_sh_mem_bases_32(qpd_to_pdd(qpd));
+ else
+ value |= SDMA_VA_SHARED_BASE(get_sh_mem_bases_nybble_64(
+ qpd_to_pdd(qpd)));
+ q->properties.sdma_vm_addr = value;
+}
+
+static int create_sdma_queue_nocpsch(struct device_queue_manager *dqm,
+ struct queue *q,
+ struct qcm_process_device *qpd)
+{
+ struct mqd_manager *mqd;
+ int retval;
+
+ mqd = dqm->ops.get_mqd_manager(dqm, KFD_MQD_TYPE_SDMA);
+ if (!mqd)
+ return -ENOMEM;
+
+ retval = allocate_sdma_queue(dqm, &q->sdma_id);
+ if (retval != 0)
+ return retval;
+
+ q->properties.sdma_queue_id = q->sdma_id % CIK_SDMA_QUEUES_PER_ENGINE;
+ q->properties.sdma_engine_id = q->sdma_id / CIK_SDMA_ENGINE_NUM;
+
+ pr_debug("kfd: sdma id is: %d\n", q->sdma_id);
+ pr_debug(" sdma queue id: %d\n", q->properties.sdma_queue_id);
+ pr_debug(" sdma engine id: %d\n", q->properties.sdma_engine_id);
+
+ retval = mqd->init_mqd(mqd, &q->mqd, &q->mqd_mem_obj,
+ &q->gart_mqd_addr, &q->properties);
+ if (retval != 0) {
+ deallocate_sdma_queue(dqm, q->sdma_id);
+ return retval;
+ }
+
+ init_sdma_vm(dqm, q, qpd);
+ return 0;
+}
+
/*
* Device Queue Manager implementation for cp scheduler
*/
@@ -692,8 +697,9 @@ static int initialize_cpsch(struct device_queue_manager *dqm)
mutex_init(&dqm->lock);
INIT_LIST_HEAD(&dqm->queues);
dqm->queue_count = dqm->processes_count = 0;
+ dqm->sdma_queue_count = 0;
dqm->active_runlist = false;
- retval = init_pipelines(dqm, get_pipes_num(dqm), 0);
+ retval = dqm->ops_asic_specific.initialize(dqm);
if (retval != 0)
goto fail_init_pipelines;
@@ -724,18 +730,14 @@ static int start_cpsch(struct device_queue_manager *dqm)
pr_debug("kfd: allocating fence memory\n");
/* allocate fence memory on the gart */
- retval = kfd2kgd->allocate_mem(dqm->dev->kgd,
- sizeof(*dqm->fence_addr),
- 32,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &dqm->fence_mem);
+ retval = kfd_gtt_sa_allocate(dqm->dev, sizeof(*dqm->fence_addr),
+ &dqm->fence_mem);
if (retval != 0)
goto fail_allocate_vidmem;
dqm->fence_addr = dqm->fence_mem->cpu_ptr;
dqm->fence_gpu_addr = dqm->fence_mem->gpu_addr;
-
list_for_each_entry(node, &dqm->queues, list)
if (node->qpd->pqm->process && dqm->dev)
kfd_bind_process_to_device(dqm->dev,
@@ -764,8 +766,7 @@ static int stop_cpsch(struct device_queue_manager *dqm)
pdd = qpd_to_pdd(node->qpd);
pdd->bound = false;
}
- kfd2kgd->free_mem(dqm->dev->kgd,
- (struct kgd_mem *) dqm->fence_mem);
+ kfd_gtt_sa_free(dqm->dev, dqm->fence_mem);
pm_uninit(&dqm->packets);
return 0;
@@ -822,12 +823,20 @@ static void destroy_kernel_queue_cpsch(struct device_queue_manager *dqm,
* Unconditionally decrement this counter, regardless of the queue's
* type.
*/
- dqm->total_queue_count++;
+ dqm->total_queue_count--;
pr_debug("Total of %d queues are accountable so far\n",
dqm->total_queue_count);
mutex_unlock(&dqm->lock);
}
+static void select_sdma_engine_id(struct queue *q)
+{
+ static int sdma_id;
+
+ q->sdma_id = sdma_id;
+ sdma_id = (sdma_id + 1) % 2;
+}
+
static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
struct qcm_process_device *qpd, int *allocate_vmid)
{
@@ -850,7 +859,12 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
goto out;
}
- mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
+ if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+ select_sdma_engine_id(q);
+
+ mqd = dqm->ops.get_mqd_manager(dqm,
+ get_mqd_type_from_queue_type(q->properties.type));
+
if (mqd == NULL) {
mutex_unlock(&dqm->lock);
return -ENOMEM;
@@ -867,6 +881,8 @@ static int create_queue_cpsch(struct device_queue_manager *dqm, struct queue *q,
retval = execute_queues_cpsch(dqm, false);
}
+ if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+ dqm->sdma_queue_count++;
/*
* Unconditionally increment this counter, regardless of the queue's
* type or whether the queue is active.
@@ -893,12 +909,20 @@ static int fence_wait_timeout(unsigned int *fence_addr,
pr_err("kfd: qcm fence wait loop timeout expired\n");
return -ETIME;
}
- cpu_relax();
+ schedule();
}
return 0;
}
+static int destroy_sdma_queues(struct device_queue_manager *dqm,
+ unsigned int sdma_engine)
+{
+ return pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_SDMA,
+ KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false,
+ sdma_engine);
+}
+
static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
{
int retval;
@@ -911,6 +935,15 @@ static int destroy_queues_cpsch(struct device_queue_manager *dqm, bool lock)
mutex_lock(&dqm->lock);
if (dqm->active_runlist == false)
goto out;
+
+ pr_debug("kfd: Before destroying queues, sdma queue count is : %u\n",
+ dqm->sdma_queue_count);
+
+ if (dqm->sdma_queue_count > 0) {
+ destroy_sdma_queues(dqm, 0);
+ destroy_sdma_queues(dqm, 1);
+ }
+
retval = pm_send_unmap_queue(&dqm->packets, KFD_QUEUE_TYPE_COMPUTE,
KFD_PREEMPT_TYPE_FILTER_ALL_QUEUES, 0, false, 0);
if (retval != 0)
@@ -982,15 +1015,19 @@ static int destroy_queue_cpsch(struct device_queue_manager *dqm,
/* remove queue from list to prevent rescheduling after preemption */
mutex_lock(&dqm->lock);
-
- mqd = dqm->get_mqd_manager(dqm, KFD_MQD_TYPE_CIK_CP);
+ mqd = dqm->ops.get_mqd_manager(dqm,
+ get_mqd_type_from_queue_type(q->properties.type));
if (!mqd) {
retval = -ENOMEM;
goto failed;
}
+ if (q->properties.type == KFD_QUEUE_TYPE_SDMA)
+ dqm->sdma_queue_count--;
+
list_del(&q->list);
- dqm->queue_count--;
+ if (q->properties.is_active)
+ dqm->queue_count--;
execute_queues_cpsch(dqm, false);
@@ -1028,8 +1065,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm,
void __user *alternate_aperture_base,
uint64_t alternate_aperture_size)
{
- uint32_t default_mtype;
- uint32_t ape1_mtype;
+ bool retval;
pr_debug("kfd: In func %s\n", __func__);
@@ -1066,18 +1102,13 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm,
qpd->sh_mem_ape1_limit = limit >> 16;
}
- default_mtype = (default_policy == cache_policy_coherent) ?
- MTYPE_NONCACHED :
- MTYPE_CACHED;
-
- ape1_mtype = (alternate_policy == cache_policy_coherent) ?
- MTYPE_NONCACHED :
- MTYPE_CACHED;
-
- qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
- | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
- | DEFAULT_MTYPE(default_mtype)
- | APE1_MTYPE(ape1_mtype);
+ retval = dqm->ops_asic_specific.set_cache_memory_policy(
+ dqm,
+ qpd,
+ default_policy,
+ alternate_policy,
+ alternate_aperture_base,
+ alternate_aperture_size);
if ((sched_policy == KFD_SCHED_POLICY_NO_HWS) && (qpd->vmid != 0))
program_sh_mem_settings(dqm, qpd);
@@ -1087,7 +1118,7 @@ static bool set_cache_memory_policy(struct device_queue_manager *dqm,
qpd->sh_mem_ape1_limit);
mutex_unlock(&dqm->lock);
- return true;
+ return retval;
out:
mutex_unlock(&dqm->lock);
@@ -1100,6 +1131,8 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
BUG_ON(!dev);
+ pr_debug("kfd: loading device queue manager\n");
+
dqm = kzalloc(sizeof(struct device_queue_manager), GFP_KERNEL);
if (!dqm)
return NULL;
@@ -1109,40 +1142,50 @@ struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev)
case KFD_SCHED_POLICY_HWS:
case KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION:
/* initialize dqm for cp scheduling */
- dqm->create_queue = create_queue_cpsch;
- dqm->initialize = initialize_cpsch;
- dqm->start = start_cpsch;
- dqm->stop = stop_cpsch;
- dqm->destroy_queue = destroy_queue_cpsch;
- dqm->update_queue = update_queue;
- dqm->get_mqd_manager = get_mqd_manager_nocpsch;
- dqm->register_process = register_process_nocpsch;
- dqm->unregister_process = unregister_process_nocpsch;
- dqm->uninitialize = uninitialize_nocpsch;
- dqm->create_kernel_queue = create_kernel_queue_cpsch;
- dqm->destroy_kernel_queue = destroy_kernel_queue_cpsch;
- dqm->set_cache_memory_policy = set_cache_memory_policy;
+ dqm->ops.create_queue = create_queue_cpsch;
+ dqm->ops.initialize = initialize_cpsch;
+ dqm->ops.start = start_cpsch;
+ dqm->ops.stop = stop_cpsch;
+ dqm->ops.destroy_queue = destroy_queue_cpsch;
+ dqm->ops.update_queue = update_queue;
+ dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch;
+ dqm->ops.register_process = register_process_nocpsch;
+ dqm->ops.unregister_process = unregister_process_nocpsch;
+ dqm->ops.uninitialize = uninitialize_nocpsch;
+ dqm->ops.create_kernel_queue = create_kernel_queue_cpsch;
+ dqm->ops.destroy_kernel_queue = destroy_kernel_queue_cpsch;
+ dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
break;
case KFD_SCHED_POLICY_NO_HWS:
/* initialize dqm for no cp scheduling */
- dqm->start = start_nocpsch;
- dqm->stop = stop_nocpsch;
- dqm->create_queue = create_queue_nocpsch;
- dqm->destroy_queue = destroy_queue_nocpsch;
- dqm->update_queue = update_queue;
- dqm->get_mqd_manager = get_mqd_manager_nocpsch;
- dqm->register_process = register_process_nocpsch;
- dqm->unregister_process = unregister_process_nocpsch;
- dqm->initialize = initialize_nocpsch;
- dqm->uninitialize = uninitialize_nocpsch;
- dqm->set_cache_memory_policy = set_cache_memory_policy;
+ dqm->ops.start = start_nocpsch;
+ dqm->ops.stop = stop_nocpsch;
+ dqm->ops.create_queue = create_queue_nocpsch;
+ dqm->ops.destroy_queue = destroy_queue_nocpsch;
+ dqm->ops.update_queue = update_queue;
+ dqm->ops.get_mqd_manager = get_mqd_manager_nocpsch;
+ dqm->ops.register_process = register_process_nocpsch;
+ dqm->ops.unregister_process = unregister_process_nocpsch;
+ dqm->ops.initialize = initialize_nocpsch;
+ dqm->ops.uninitialize = uninitialize_nocpsch;
+ dqm->ops.set_cache_memory_policy = set_cache_memory_policy;
break;
default:
BUG();
break;
}
- if (dqm->initialize(dqm) != 0) {
+ switch (dev->device_info->asic_family) {
+ case CHIP_CARRIZO:
+ device_queue_manager_init_vi(&dqm->ops_asic_specific);
+ break;
+
+ case CHIP_KAVERI:
+ device_queue_manager_init_cik(&dqm->ops_asic_specific);
+ break;
+ }
+
+ if (dqm->ops.initialize(dqm) != 0) {
kfree(dqm);
return NULL;
}
@@ -1154,7 +1197,6 @@ void device_queue_manager_uninit(struct device_queue_manager *dqm)
{
BUG_ON(!dqm);
- dqm->uninitialize(dqm);
+ dqm->ops.uninitialize(dqm);
kfree(dqm);
}
-
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
index 52035bf0c1cb..488f51d19427 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager.h
@@ -36,6 +36,9 @@
#define KFD_VMID_START_OFFSET (8)
#define VMID_PER_DEVICE CIK_VMID_NUM
#define KFD_DQM_FIRST_PIPE (0)
+#define CIK_SDMA_QUEUES (4)
+#define CIK_SDMA_QUEUES_PER_ENGINE (2)
+#define CIK_SDMA_ENGINE_NUM (2)
struct device_process_node {
struct qcm_process_device *qpd;
@@ -43,7 +46,7 @@ struct device_process_node {
};
/**
- * struct device_queue_manager
+ * struct device_queue_manager_ops
*
* @create_queue: Queue creation routine.
*
@@ -78,15 +81,9 @@ struct device_process_node {
* @set_cache_memory_policy: Sets memory policy (cached/ non cached) for the
* memory apertures.
*
- * This struct is a base class for the kfd queues scheduler in the
- * device level. The device base class should expose the basic operations
- * for queue creation and queue destruction. This base class hides the
- * scheduling mode of the driver and the specific implementation of the
- * concrete device. This class is the only class in the queues scheduler
- * that configures the H/W.
*/
-struct device_queue_manager {
+struct device_queue_manager_ops {
int (*create_queue)(struct device_queue_manager *dqm,
struct queue *q,
struct qcm_process_device *qpd,
@@ -121,7 +118,23 @@ struct device_queue_manager {
enum cache_policy alternate_policy,
void __user *alternate_aperture_base,
uint64_t alternate_aperture_size);
+};
+
+/**
+ * struct device_queue_manager
+ *
+ * This struct is a base class for the kfd queues scheduler in the
+ * device level. The device base class should expose the basic operations
+ * for queue creation and queue destruction. This base class hides the
+ * scheduling mode of the driver and the specific implementation of the
+ * concrete device. This class is the only class in the queues scheduler
+ * that configures the H/W.
+ *
+ */
+struct device_queue_manager {
+ struct device_queue_manager_ops ops;
+ struct device_queue_manager_ops ops_asic_specific;
struct mqd_manager *mqds[KFD_MQD_TYPE_MAX];
struct packet_manager packets;
@@ -130,9 +143,11 @@ struct device_queue_manager {
struct list_head queues;
unsigned int processes_count;
unsigned int queue_count;
+ unsigned int sdma_queue_count;
unsigned int total_queue_count;
unsigned int next_pipe_to_allocate;
unsigned int *allocated_queues;
+ unsigned int sdma_bitmap;
unsigned int vmid_bitmap;
uint64_t pipelines_addr;
struct kfd_mem_obj *pipeline_mem;
@@ -142,6 +157,24 @@ struct device_queue_manager {
bool active_runlist;
};
+void device_queue_manager_init_cik(struct device_queue_manager_ops *ops);
+void device_queue_manager_init_vi(struct device_queue_manager_ops *ops);
+void program_sh_mem_settings(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+int init_pipelines(struct device_queue_manager *dqm,
+ unsigned int pipes_num, unsigned int first_pipe);
+unsigned int get_first_pipe(struct device_queue_manager *dqm);
+unsigned int get_pipes_num(struct device_queue_manager *dqm);
+
+extern inline unsigned int get_sh_mem_bases_32(struct kfd_process_device *pdd)
+{
+ return (pdd->lds_base >> 16) & 0xFF;
+}
+extern inline unsigned int
+get_sh_mem_bases_nybble_64(struct kfd_process_device *pdd)
+{
+ return (pdd->lds_base >> 60) & 0x0E;
+}
#endif /* KFD_DEVICE_QUEUE_MANAGER_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
new file mode 100644
index 000000000000..5469efe0523e
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_cik.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "kfd_device_queue_manager.h"
+#include "cik_regs.h"
+
+static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+ enum cache_policy alternate_policy,
+ void __user *alternate_aperture_base,
+ uint64_t alternate_aperture_size);
+static int register_process_cik(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+static int initialize_cpsch_cik(struct device_queue_manager *dqm);
+
+void device_queue_manager_init_cik(struct device_queue_manager_ops *ops)
+{
+ ops->set_cache_memory_policy = set_cache_memory_policy_cik;
+ ops->register_process = register_process_cik;
+ ops->initialize = initialize_cpsch_cik;
+}
+
+static uint32_t compute_sh_mem_bases_64bit(unsigned int top_address_nybble)
+{
+ /* In 64-bit mode, we can only control the top 3 bits of the LDS,
+ * scratch and GPUVM apertures.
+ * The hardware fills in the remaining 59 bits according to the
+ * following pattern:
+ * LDS: X0000000'00000000 - X0000001'00000000 (4GB)
+ * Scratch: X0000001'00000000 - X0000002'00000000 (4GB)
+ * GPUVM: Y0010000'00000000 - Y0020000'00000000 (1TB)
+ *
+ * (where X/Y is the configurable nybble with the low-bit 0)
+ *
+ * LDS and scratch will have the same top nybble programmed in the
+ * top 3 bits of SH_MEM_BASES.PRIVATE_BASE.
+ * GPUVM can have a different top nybble programmed in the
+ * top 3 bits of SH_MEM_BASES.SHARED_BASE.
+ * We don't bother to support different top nybbles
+ * for LDS/Scratch and GPUVM.
+ */
+
+ BUG_ON((top_address_nybble & 1) || top_address_nybble > 0xE ||
+ top_address_nybble == 0);
+
+ return PRIVATE_BASE(top_address_nybble << 12) |
+ SHARED_BASE(top_address_nybble << 12);
+}
+
+static bool set_cache_memory_policy_cik(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+ enum cache_policy alternate_policy,
+ void __user *alternate_aperture_base,
+ uint64_t alternate_aperture_size)
+{
+ uint32_t default_mtype;
+ uint32_t ape1_mtype;
+
+ default_mtype = (default_policy == cache_policy_coherent) ?
+ MTYPE_NONCACHED :
+ MTYPE_CACHED;
+
+ ape1_mtype = (alternate_policy == cache_policy_coherent) ?
+ MTYPE_NONCACHED :
+ MTYPE_CACHED;
+
+ qpd->sh_mem_config = (qpd->sh_mem_config & PTR32)
+ | ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED)
+ | DEFAULT_MTYPE(default_mtype)
+ | APE1_MTYPE(ape1_mtype);
+
+ return true;
+}
+
+static int register_process_cik(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd)
+{
+ struct kfd_process_device *pdd;
+ unsigned int temp;
+
+ BUG_ON(!dqm || !qpd);
+
+ pdd = qpd_to_pdd(qpd);
+
+ /* check if sh_mem_config register already configured */
+ if (qpd->sh_mem_config == 0) {
+ qpd->sh_mem_config =
+ ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED) |
+ DEFAULT_MTYPE(MTYPE_NONCACHED) |
+ APE1_MTYPE(MTYPE_NONCACHED);
+ qpd->sh_mem_ape1_limit = 0;
+ qpd->sh_mem_ape1_base = 0;
+ }
+
+ if (qpd->pqm->process->is_32bit_user_mode) {
+ temp = get_sh_mem_bases_32(pdd);
+ qpd->sh_mem_bases = SHARED_BASE(temp);
+ qpd->sh_mem_config |= PTR32;
+ } else {
+ temp = get_sh_mem_bases_nybble_64(pdd);
+ qpd->sh_mem_bases = compute_sh_mem_bases_64bit(temp);
+ }
+
+ pr_debug("kfd: is32bit process: %d sh_mem_bases nybble: 0x%X and register 0x%X\n",
+ qpd->pqm->process->is_32bit_user_mode, temp, qpd->sh_mem_bases);
+
+ return 0;
+}
+
+static int initialize_cpsch_cik(struct device_queue_manager *dqm)
+{
+ return init_pipelines(dqm, get_pipes_num(dqm), get_first_pipe(dqm));
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
new file mode 100644
index 000000000000..20553dcd257d
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_device_queue_manager_vi.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "kfd_device_queue_manager.h"
+
+static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+ enum cache_policy alternate_policy,
+ void __user *alternate_aperture_base,
+ uint64_t alternate_aperture_size);
+static int register_process_vi(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd);
+static int initialize_cpsch_vi(struct device_queue_manager *dqm);
+
+void device_queue_manager_init_vi(struct device_queue_manager_ops *ops)
+{
+ pr_warn("amdkfd: VI DQM is not currently supported\n");
+
+ ops->set_cache_memory_policy = set_cache_memory_policy_vi;
+ ops->register_process = register_process_vi;
+ ops->initialize = initialize_cpsch_vi;
+}
+
+static bool set_cache_memory_policy_vi(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd,
+ enum cache_policy default_policy,
+ enum cache_policy alternate_policy,
+ void __user *alternate_aperture_base,
+ uint64_t alternate_aperture_size)
+{
+ return false;
+}
+
+static int register_process_vi(struct device_queue_manager *dqm,
+ struct qcm_process_device *qpd)
+{
+ return -1;
+}
+
+static int initialize_cpsch_vi(struct device_queue_manager *dqm)
+{
+ return 0;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
index b5791a5c7c06..1a9b355dd114 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_doorbell.c
@@ -137,10 +137,6 @@ int kfd_doorbell_mmap(struct kfd_process *process, struct vm_area_struct *vma)
if (dev == NULL)
return -EINVAL;
- /* Find if pdd exists for combination of process and gpu id */
- if (!kfd_get_process_device_data(dev, process, 0))
- return -EINVAL;
-
/* Calculate physical address of doorbell */
address = kfd_get_process_doorbells(dev, process);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
index e64aa99e5e41..35b987574633 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_flat_memory.c
@@ -303,10 +303,11 @@ int kfd_init_apertures(struct kfd_process *process)
while ((dev = kfd_topology_enum_kfd_devices(id)) != NULL &&
id < NUM_OF_SUPPORTED_GPUS) {
- pdd = kfd_get_process_device_data(dev, process, 1);
- if (!pdd)
+ pdd = kfd_create_process_device_data(dev, process);
+ if (pdd == NULL) {
+ pr_err("Failed to create process device data\n");
return -1;
-
+ }
/*
* For 64 bit process aperture will be statically reserved in
* the x86_64 non canonical process address space
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
index 935071410724..e415a2a9207e 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.c
@@ -56,8 +56,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
switch (type) {
case KFD_QUEUE_TYPE_DIQ:
case KFD_QUEUE_TYPE_HIQ:
- kq->mqd = dev->dqm->get_mqd_manager(dev->dqm,
- KFD_MQD_TYPE_CIK_HIQ);
+ kq->mqd = dev->dqm->ops.get_mqd_manager(dev->dqm,
+ KFD_MQD_TYPE_HIQ);
break;
default:
BUG();
@@ -72,23 +72,19 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
if (prop.doorbell_ptr == NULL)
goto err_get_kernel_doorbell;
- retval = kfd2kgd->allocate_mem(dev->kgd,
- queue_size,
- PAGE_SIZE,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &kq->pq);
-
+ retval = kfd_gtt_sa_allocate(dev, queue_size, &kq->pq);
if (retval != 0)
goto err_pq_allocate_vidmem;
kq->pq_kernel_addr = kq->pq->cpu_ptr;
kq->pq_gpu_addr = kq->pq->gpu_addr;
- retval = kfd2kgd->allocate_mem(dev->kgd,
- sizeof(*kq->rptr_kernel),
- 32,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &kq->rptr_mem);
+ retval = kq->ops_asic_specific.initialize(kq, dev, type, queue_size);
+ if (retval == false)
+ goto err_eop_allocate_vidmem;
+
+ retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->rptr_kernel),
+ &kq->rptr_mem);
if (retval != 0)
goto err_rptr_allocate_vidmem;
@@ -96,11 +92,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
kq->rptr_kernel = kq->rptr_mem->cpu_ptr;
kq->rptr_gpu_addr = kq->rptr_mem->gpu_addr;
- retval = kfd2kgd->allocate_mem(dev->kgd,
- sizeof(*kq->wptr_kernel),
- 32,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &kq->wptr_mem);
+ retval = kfd_gtt_sa_allocate(dev, sizeof(*kq->wptr_kernel),
+ &kq->wptr_mem);
if (retval != 0)
goto err_wptr_allocate_vidmem;
@@ -121,6 +114,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
prop.queue_address = kq->pq_gpu_addr;
prop.read_ptr = (uint32_t *) kq->rptr_gpu_addr;
prop.write_ptr = (uint32_t *) kq->wptr_gpu_addr;
+ prop.eop_ring_buffer_address = kq->eop_gpu_addr;
+ prop.eop_ring_buffer_size = PAGE_SIZE;
if (init_queue(&kq->queue, prop) != 0)
goto err_init_queue;
@@ -145,11 +140,8 @@ static bool initialize(struct kernel_queue *kq, struct kfd_dev *dev,
} else {
/* allocate fence for DIQ */
- retval = kfd2kgd->allocate_mem(dev->kgd,
- sizeof(uint32_t),
- 32,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &kq->fence_mem_obj);
+ retval = kfd_gtt_sa_allocate(dev, sizeof(uint32_t),
+ &kq->fence_mem_obj);
if (retval != 0)
goto err_alloc_fence;
@@ -165,11 +157,13 @@ err_alloc_fence:
err_init_mqd:
uninit_queue(kq->queue);
err_init_queue:
- kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->wptr_mem);
+ kfd_gtt_sa_free(dev, kq->wptr_mem);
err_wptr_allocate_vidmem:
- kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->rptr_mem);
+ kfd_gtt_sa_free(dev, kq->rptr_mem);
err_rptr_allocate_vidmem:
- kfd2kgd->free_mem(dev->kgd, (struct kgd_mem *) kq->pq);
+ kfd_gtt_sa_free(dev, kq->eop_mem);
+err_eop_allocate_vidmem:
+ kfd_gtt_sa_free(dev, kq->pq);
err_pq_allocate_vidmem:
pr_err("kfd: error init pq\n");
kfd_release_kernel_doorbell(dev, prop.doorbell_ptr);
@@ -190,10 +184,13 @@ static void uninitialize(struct kernel_queue *kq)
QUEUE_PREEMPT_DEFAULT_TIMEOUT_MS,
kq->queue->pipe,
kq->queue->queue);
+ else if (kq->queue->properties.type == KFD_QUEUE_TYPE_DIQ)
+ kfd_gtt_sa_free(kq->dev, kq->fence_mem_obj);
- kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->rptr_mem);
- kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->wptr_mem);
- kfd2kgd->free_mem(kq->dev->kgd, (struct kgd_mem *) kq->pq);
+ kfd_gtt_sa_free(kq->dev, kq->rptr_mem);
+ kfd_gtt_sa_free(kq->dev, kq->wptr_mem);
+ kq->ops_asic_specific.uninitialize(kq);
+ kfd_gtt_sa_free(kq->dev, kq->pq);
kfd_release_kernel_doorbell(kq->dev,
kq->queue->properties.doorbell_ptr);
uninit_queue(kq->queue);
@@ -265,28 +262,6 @@ static void submit_packet(struct kernel_queue *kq)
kq->pending_wptr);
}
-static int sync_with_hw(struct kernel_queue *kq, unsigned long timeout_ms)
-{
- unsigned long org_timeout_ms;
-
- BUG_ON(!kq);
-
- org_timeout_ms = timeout_ms;
- timeout_ms += jiffies * 1000 / HZ;
- while (*kq->wptr_kernel != *kq->rptr_kernel) {
- if (time_after(jiffies * 1000 / HZ, timeout_ms)) {
- pr_err("kfd: kernel_queue %s timeout expired %lu\n",
- __func__, org_timeout_ms);
- pr_err("kfd: wptr: %d rptr: %d\n",
- *kq->wptr_kernel, *kq->rptr_kernel);
- return -ETIME;
- }
- schedule();
- }
-
- return 0;
-}
-
static void rollback_packet(struct kernel_queue *kq)
{
BUG_ON(!kq);
@@ -304,14 +279,23 @@ struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
if (!kq)
return NULL;
- kq->initialize = initialize;
- kq->uninitialize = uninitialize;
- kq->acquire_packet_buffer = acquire_packet_buffer;
- kq->submit_packet = submit_packet;
- kq->sync_with_hw = sync_with_hw;
- kq->rollback_packet = rollback_packet;
+ kq->ops.initialize = initialize;
+ kq->ops.uninitialize = uninitialize;
+ kq->ops.acquire_packet_buffer = acquire_packet_buffer;
+ kq->ops.submit_packet = submit_packet;
+ kq->ops.rollback_packet = rollback_packet;
+
+ switch (dev->device_info->asic_family) {
+ case CHIP_CARRIZO:
+ kernel_queue_init_vi(&kq->ops_asic_specific);
+ break;
+
+ case CHIP_KAVERI:
+ kernel_queue_init_cik(&kq->ops_asic_specific);
+ break;
+ }
- if (kq->initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
+ if (kq->ops.initialize(kq, dev, type, KFD_KERNEL_QUEUE_SIZE) == false) {
pr_err("kfd: failed to init kernel queue\n");
kfree(kq);
return NULL;
@@ -323,7 +307,7 @@ void kernel_queue_uninit(struct kernel_queue *kq)
{
BUG_ON(!kq);
- kq->uninitialize(kq);
+ kq->ops.uninitialize(kq);
kfree(kq);
}
@@ -335,19 +319,18 @@ static __attribute__((unused)) void test_kq(struct kfd_dev *dev)
BUG_ON(!dev);
- pr_debug("kfd: starting kernel queue test\n");
+ pr_err("kfd: starting kernel queue test\n");
kq = kernel_queue_init(dev, KFD_QUEUE_TYPE_HIQ);
BUG_ON(!kq);
- retval = kq->acquire_packet_buffer(kq, 5, &buffer);
+ retval = kq->ops.acquire_packet_buffer(kq, 5, &buffer);
BUG_ON(retval != 0);
for (i = 0; i < 5; i++)
buffer[i] = kq->nop_packet;
- kq->submit_packet(kq);
- kq->sync_with_hw(kq, 1000);
+ kq->ops.submit_packet(kq);
- pr_debug("kfd: ending kernel queue test\n");
+ pr_err("kfd: ending kernel queue test\n");
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
index dcd2bdb68d44..594053136ee4 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue.h
@@ -28,8 +28,31 @@
#include <linux/types.h>
#include "kfd_priv.h"
-struct kernel_queue {
- /* interface */
+/**
+ * struct kernel_queue_ops
+ *
+ * @initialize: Initialize a kernel queue, including allocations of GART memory
+ * needed for the queue.
+ *
+ * @uninitialize: Uninitialize a kernel queue and free all its memory usages.
+ *
+ * @acquire_packet_buffer: Returns a pointer to the location in the kernel
+ * queue ring buffer where the calling function can write its packet. It is
+ * Guaranteed that there is enough space for that packet. It also updates the
+ * pending write pointer to that location so subsequent calls to
+ * acquire_packet_buffer will get a correct write pointer
+ *
+ * @submit_packet: Update the write pointer and doorbell of a kernel queue.
+ *
+ * @sync_with_hw: Wait until the write pointer and the read pointer of a kernel
+ * queue are equal, which means the CP has read all the submitted packets.
+ *
+ * @rollback_packet: This routine is called if we failed to build an acquired
+ * packet for some reason. It just overwrites the pending wptr with the current
+ * one
+ *
+ */
+struct kernel_queue_ops {
bool (*initialize)(struct kernel_queue *kq, struct kfd_dev *dev,
enum kfd_queue_type type, unsigned int queue_size);
void (*uninitialize)(struct kernel_queue *kq);
@@ -38,9 +61,12 @@ struct kernel_queue {
unsigned int **buffer_ptr);
void (*submit_packet)(struct kernel_queue *kq);
- int (*sync_with_hw)(struct kernel_queue *kq,
- unsigned long timeout_ms);
void (*rollback_packet)(struct kernel_queue *kq);
+};
+
+struct kernel_queue {
+ struct kernel_queue_ops ops;
+ struct kernel_queue_ops ops_asic_specific;
/* data */
struct kfd_dev *dev;
@@ -58,6 +84,9 @@ struct kernel_queue {
struct kfd_mem_obj *pq;
uint64_t pq_gpu_addr;
uint32_t *pq_kernel_addr;
+ struct kfd_mem_obj *eop_mem;
+ uint64_t eop_gpu_addr;
+ uint32_t *eop_kernel_addr;
struct kfd_mem_obj *fence_mem_obj;
uint64_t fence_gpu_addr;
@@ -66,4 +95,7 @@ struct kernel_queue {
struct list_head list;
};
+void kernel_queue_init_cik(struct kernel_queue_ops *ops);
+void kernel_queue_init_vi(struct kernel_queue_ops *ops);
+
#endif /* KFD_KERNEL_QUEUE_H_ */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c
new file mode 100644
index 000000000000..a90eb440b1fb
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_cik.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "kfd_kernel_queue.h"
+
+static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev,
+ enum kfd_queue_type type, unsigned int queue_size);
+static void uninitialize_cik(struct kernel_queue *kq);
+
+void kernel_queue_init_cik(struct kernel_queue_ops *ops)
+{
+ ops->initialize = initialize_cik;
+ ops->uninitialize = uninitialize_cik;
+}
+
+static bool initialize_cik(struct kernel_queue *kq, struct kfd_dev *dev,
+ enum kfd_queue_type type, unsigned int queue_size)
+{
+ return true;
+}
+
+static void uninitialize_cik(struct kernel_queue *kq)
+{
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c
new file mode 100644
index 000000000000..f1d48281e322
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_kernel_queue_vi.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include "kfd_kernel_queue.h"
+
+static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev,
+ enum kfd_queue_type type, unsigned int queue_size);
+static void uninitialize_vi(struct kernel_queue *kq);
+
+void kernel_queue_init_vi(struct kernel_queue_ops *ops)
+{
+ ops->initialize = initialize_vi;
+ ops->uninitialize = uninitialize_vi;
+}
+
+static bool initialize_vi(struct kernel_queue *kq, struct kfd_dev *dev,
+ enum kfd_queue_type type, unsigned int queue_size)
+{
+ int retval;
+
+ retval = kfd_gtt_sa_allocate(dev, PAGE_SIZE, &kq->eop_mem);
+ if (retval != 0)
+ return false;
+
+ kq->eop_gpu_addr = kq->eop_mem->gpu_addr;
+ kq->eop_kernel_addr = kq->eop_mem->cpu_ptr;
+
+ memset(kq->eop_kernel_addr, 0, PAGE_SIZE);
+
+ return true;
+}
+
+static void uninitialize_vi(struct kernel_queue *kq)
+{
+ kfd_gtt_sa_free(kq->dev, kq->eop_mem);
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_module.c b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
index a8be6df85347..3f34ae16f075 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_module.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_module.c
@@ -29,10 +29,10 @@
#define KFD_DRIVER_AUTHOR "AMD Inc. and others"
#define KFD_DRIVER_DESC "Standalone HSA driver for AMD's GPUs"
-#define KFD_DRIVER_DATE "20141113"
+#define KFD_DRIVER_DATE "20150122"
#define KFD_DRIVER_MAJOR 0
#define KFD_DRIVER_MINOR 7
-#define KFD_DRIVER_PATCHLEVEL 0
+#define KFD_DRIVER_PATCHLEVEL 1
const struct kfd2kgd_calls *kfd2kgd;
static const struct kgd2kfd_calls kgd2kfd = {
@@ -48,7 +48,7 @@ static const struct kgd2kfd_calls kgd2kfd = {
int sched_policy = KFD_SCHED_POLICY_HWS;
module_param(sched_policy, int, 0444);
MODULE_PARM_DESC(sched_policy,
- "Kernel cmdline parameter that defines the amdkfd scheduling policy");
+ "Scheduling policy (0 = HWS (Default), 1 = HWS without over-subscription, 2 = Non-HWS (Used for debugging only)");
int max_num_of_queues_per_device = KFD_MAX_NUM_OF_QUEUES_PER_DEVICE_DEFAULT;
module_param(max_num_of_queues_per_device, int, 0444);
@@ -95,10 +95,10 @@ static int __init kfd_module_init(void)
}
/* Verify module parameters */
- if ((max_num_of_queues_per_device < 0) ||
+ if ((max_num_of_queues_per_device < 1) ||
(max_num_of_queues_per_device >
KFD_MAX_NUM_OF_QUEUES_PER_DEVICE)) {
- pr_err("kfd: max_num_of_queues_per_device must be between 0 to KFD_MAX_NUM_OF_QUEUES_PER_DEVICE\n");
+ pr_err("kfd: max_num_of_queues_per_device must be between 1 to KFD_MAX_NUM_OF_QUEUES_PER_DEVICE\n");
return -1;
}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
index 4c3828cf45bf..b1ef1368c3bb 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager.c
@@ -21,326 +21,17 @@
*
*/
-#include <linux/printk.h>
-#include <linux/slab.h>
#include "kfd_priv.h"
-#include "kfd_mqd_manager.h"
-#include "cik_regs.h"
-#include "../../radeon/cik_reg.h"
-
-inline void busy_wait(unsigned long ms)
-{
- while (time_before(jiffies, ms))
- cpu_relax();
-}
-
-static inline struct cik_mqd *get_mqd(void *mqd)
-{
- return (struct cik_mqd *)mqd;
-}
-
-static int init_mqd(struct mqd_manager *mm, void **mqd,
- struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
- struct queue_properties *q)
-{
- uint64_t addr;
- struct cik_mqd *m;
- int retval;
-
- BUG_ON(!mm || !q || !mqd);
-
- pr_debug("kfd: In func %s\n", __func__);
-
- retval = kfd2kgd->allocate_mem(mm->dev->kgd,
- sizeof(struct cik_mqd),
- 256,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) mqd_mem_obj);
-
- if (retval != 0)
- return -ENOMEM;
-
- m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
- addr = (*mqd_mem_obj)->gpu_addr;
-
- memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
-
- m->header = 0xC0310800;
- m->compute_pipelinestat_enable = 1;
- m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
- m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
- m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
- m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
-
- /*
- * Make sure to use the last queue state saved on mqd when the cp
- * reassigns the queue, so when queue is switched on/off (e.g over
- * subscription or quantum timeout) the context will be consistent
- */
- m->cp_hqd_persistent_state =
- DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
-
- m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
- m->cp_mqd_base_addr_lo = lower_32_bits(addr);
- m->cp_mqd_base_addr_hi = upper_32_bits(addr);
-
- m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
- /* Although WinKFD writes this, I suspect it should not be necessary */
- m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
-
- m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
- QUANTUM_DURATION(10);
-
- /*
- * Pipe Priority
- * Identifies the pipe relative priority when this queue is connected
- * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
- * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
- * 0 = CS_LOW (typically below GFX)
- * 1 = CS_MEDIUM (typically between HP3D and GFX
- * 2 = CS_HIGH (typically above HP3D)
- */
- m->cp_hqd_pipe_priority = 1;
- m->cp_hqd_queue_priority = 15;
-
- *mqd = m;
- if (gart_addr != NULL)
- *gart_addr = addr;
- retval = mm->update_mqd(mm, m, q);
-
- return retval;
-}
-
-static void uninit_mqd(struct mqd_manager *mm, void *mqd,
- struct kfd_mem_obj *mqd_mem_obj)
-{
- BUG_ON(!mm || !mqd);
- kfd2kgd->free_mem(mm->dev->kgd, (struct kgd_mem *) mqd_mem_obj);
-}
-
-static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
- uint32_t queue_id, uint32_t __user *wptr)
-{
- return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
-
-}
-
-static int update_mqd(struct mqd_manager *mm, void *mqd,
- struct queue_properties *q)
-{
- struct cik_mqd *m;
-
- BUG_ON(!mm || !q || !mqd);
-
- pr_debug("kfd: In func %s\n", __func__);
-
- m = get_mqd(mqd);
- m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
- DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
-
- /*
- * Calculating queue size which is log base 2 of actual queue size -1
- * dwords and another -1 for ffs
- */
- m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
- - 1 - 1;
- m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
- m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
- m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
- m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
- m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
- DOORBELL_OFFSET(q->doorbell_off);
-
- m->cp_hqd_vmid = q->vmid;
-
- if (q->format == KFD_QUEUE_FORMAT_AQL) {
- m->cp_hqd_iq_rptr = AQL_ENABLE;
- m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
- }
-
- m->cp_hqd_active = 0;
- q->is_active = false;
- if (q->queue_size > 0 &&
- q->queue_address != 0 &&
- q->queue_percent > 0) {
- m->cp_hqd_active = 1;
- q->is_active = true;
- }
-
- return 0;
-}
-
-static int destroy_mqd(struct mqd_manager *mm, void *mqd,
- enum kfd_preempt_type type,
- unsigned int timeout, uint32_t pipe_id,
- uint32_t queue_id)
-{
- return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
- pipe_id, queue_id);
-}
-
-static bool is_occupied(struct mqd_manager *mm, void *mqd,
- uint64_t queue_address, uint32_t pipe_id,
- uint32_t queue_id)
-{
-
- return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
- pipe_id, queue_id);
-
-}
-
-/*
- * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
- * The HIQ queue in Kaveri is using the same MQD structure as all the user mode
- * queues but with different initial values.
- */
-
-static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
- struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
- struct queue_properties *q)
-{
- uint64_t addr;
- struct cik_mqd *m;
- int retval;
-
- BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
-
- pr_debug("kfd: In func %s\n", __func__);
-
- retval = kfd2kgd->allocate_mem(mm->dev->kgd,
- sizeof(struct cik_mqd),
- 256,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) mqd_mem_obj);
-
- if (retval != 0)
- return -ENOMEM;
-
- m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
- addr = (*mqd_mem_obj)->gpu_addr;
-
- memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
-
- m->header = 0xC0310800;
- m->compute_pipelinestat_enable = 1;
- m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
- m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
- m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
- m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
-
- m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
- PRELOAD_REQ;
- m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
- QUANTUM_DURATION(10);
-
- m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
- m->cp_mqd_base_addr_lo = lower_32_bits(addr);
- m->cp_mqd_base_addr_hi = upper_32_bits(addr);
-
- m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
-
- /*
- * Pipe Priority
- * Identifies the pipe relative priority when this queue is connected
- * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
- * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
- * 0 = CS_LOW (typically below GFX)
- * 1 = CS_MEDIUM (typically between HP3D and GFX
- * 2 = CS_HIGH (typically above HP3D)
- */
- m->cp_hqd_pipe_priority = 1;
- m->cp_hqd_queue_priority = 15;
-
- *mqd = m;
- if (gart_addr)
- *gart_addr = addr;
- retval = mm->update_mqd(mm, m, q);
-
- return retval;
-}
-
-static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
- struct queue_properties *q)
-{
- struct cik_mqd *m;
-
- BUG_ON(!mm || !q || !mqd);
-
- pr_debug("kfd: In func %s\n", __func__);
-
- m = get_mqd(mqd);
- m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
- DEFAULT_MIN_AVAIL_SIZE |
- PRIV_STATE |
- KMD_QUEUE;
-
- /*
- * Calculating queue size which is log base 2 of actual queue
- * size -1 dwords
- */
- m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
- - 1 - 1;
- m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
- m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
- m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
- m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
- m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
- DOORBELL_OFFSET(q->doorbell_off);
-
- m->cp_hqd_vmid = q->vmid;
-
- m->cp_hqd_active = 0;
- q->is_active = false;
- if (q->queue_size > 0 &&
- q->queue_address != 0 &&
- q->queue_percent > 0) {
- m->cp_hqd_active = 1;
- q->is_active = true;
- }
-
- return 0;
-}
struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
struct kfd_dev *dev)
{
- struct mqd_manager *mqd;
-
- BUG_ON(!dev);
- BUG_ON(type >= KFD_MQD_TYPE_MAX);
-
- pr_debug("kfd: In func %s\n", __func__);
-
- mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
- if (!mqd)
- return NULL;
-
- mqd->dev = dev;
-
- switch (type) {
- case KFD_MQD_TYPE_CIK_CP:
- case KFD_MQD_TYPE_CIK_COMPUTE:
- mqd->init_mqd = init_mqd;
- mqd->uninit_mqd = uninit_mqd;
- mqd->load_mqd = load_mqd;
- mqd->update_mqd = update_mqd;
- mqd->destroy_mqd = destroy_mqd;
- mqd->is_occupied = is_occupied;
- break;
- case KFD_MQD_TYPE_CIK_HIQ:
- mqd->init_mqd = init_mqd_hiq;
- mqd->uninit_mqd = uninit_mqd;
- mqd->load_mqd = load_mqd;
- mqd->update_mqd = update_mqd_hiq;
- mqd->destroy_mqd = destroy_mqd;
- mqd->is_occupied = is_occupied;
- break;
- default:
- kfree(mqd);
- return NULL;
+ switch (dev->device_info->asic_family) {
+ case CHIP_KAVERI:
+ return mqd_manager_init_cik(type, dev);
+ case CHIP_CARRIZO:
+ return mqd_manager_init_vi(type, dev);
}
- return mqd;
+ return NULL;
}
-
-/* SDMA queues should be implemented here when the cp will supports them */
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
new file mode 100644
index 000000000000..a09e18a339f3
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_cik.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include "kfd_priv.h"
+#include "kfd_mqd_manager.h"
+#include "cik_regs.h"
+#include "cik_structs.h"
+
+static inline struct cik_mqd *get_mqd(void *mqd)
+{
+ return (struct cik_mqd *)mqd;
+}
+
+static int init_mqd(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *q)
+{
+ uint64_t addr;
+ struct cik_mqd *m;
+ int retval;
+
+ BUG_ON(!mm || !q || !mqd);
+
+ pr_debug("kfd: In func %s\n", __func__);
+
+ retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
+ mqd_mem_obj);
+
+ if (retval != 0)
+ return -ENOMEM;
+
+ m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
+ addr = (*mqd_mem_obj)->gpu_addr;
+
+ memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
+
+ m->header = 0xC0310800;
+ m->compute_pipelinestat_enable = 1;
+ m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
+ m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
+ m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
+ m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
+
+ /*
+ * Make sure to use the last queue state saved on mqd when the cp
+ * reassigns the queue, so when queue is switched on/off (e.g over
+ * subscription or quantum timeout) the context will be consistent
+ */
+ m->cp_hqd_persistent_state =
+ DEFAULT_CP_HQD_PERSISTENT_STATE | PRELOAD_REQ;
+
+ m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
+ m->cp_mqd_base_addr_lo = lower_32_bits(addr);
+ m->cp_mqd_base_addr_hi = upper_32_bits(addr);
+
+ m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE | IB_ATC_EN;
+ /* Although WinKFD writes this, I suspect it should not be necessary */
+ m->cp_hqd_ib_control = IB_ATC_EN | DEFAULT_MIN_IB_AVAIL_SIZE;
+
+ m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
+ QUANTUM_DURATION(10);
+
+ /*
+ * Pipe Priority
+ * Identifies the pipe relative priority when this queue is connected
+ * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
+ * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
+ * 0 = CS_LOW (typically below GFX)
+ * 1 = CS_MEDIUM (typically between HP3D and GFX
+ * 2 = CS_HIGH (typically above HP3D)
+ */
+ m->cp_hqd_pipe_priority = 1;
+ m->cp_hqd_queue_priority = 15;
+
+ if (q->format == KFD_QUEUE_FORMAT_AQL)
+ m->cp_hqd_iq_rptr = AQL_ENABLE;
+
+ *mqd = m;
+ if (gart_addr != NULL)
+ *gart_addr = addr;
+ retval = mm->update_mqd(mm, m, q);
+
+ return retval;
+}
+
+static int init_mqd_sdma(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *q)
+{
+ int retval;
+ struct cik_sdma_rlc_registers *m;
+
+ BUG_ON(!mm || !mqd || !mqd_mem_obj);
+
+ retval = kfd_gtt_sa_allocate(mm->dev,
+ sizeof(struct cik_sdma_rlc_registers),
+ mqd_mem_obj);
+
+ if (retval != 0)
+ return -ENOMEM;
+
+ m = (struct cik_sdma_rlc_registers *) (*mqd_mem_obj)->cpu_ptr;
+
+ memset(m, 0, sizeof(struct cik_sdma_rlc_registers));
+
+ *mqd = m;
+ if (gart_addr != NULL)
+ *gart_addr = (*mqd_mem_obj)->gpu_addr;
+
+ retval = mm->update_mqd(mm, m, q);
+
+ return retval;
+}
+
+static void uninit_mqd(struct mqd_manager *mm, void *mqd,
+ struct kfd_mem_obj *mqd_mem_obj)
+{
+ BUG_ON(!mm || !mqd);
+ kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
+}
+
+static void uninit_mqd_sdma(struct mqd_manager *mm, void *mqd,
+ struct kfd_mem_obj *mqd_mem_obj)
+{
+ BUG_ON(!mm || !mqd);
+ kfd_gtt_sa_free(mm->dev, mqd_mem_obj);
+}
+
+static int load_mqd(struct mqd_manager *mm, void *mqd, uint32_t pipe_id,
+ uint32_t queue_id, uint32_t __user *wptr)
+{
+ return kfd2kgd->hqd_load(mm->dev->kgd, mqd, pipe_id, queue_id, wptr);
+}
+
+static int load_mqd_sdma(struct mqd_manager *mm, void *mqd,
+ uint32_t pipe_id, uint32_t queue_id,
+ uint32_t __user *wptr)
+{
+ return kfd2kgd->hqd_sdma_load(mm->dev->kgd, mqd);
+}
+
+static int update_mqd(struct mqd_manager *mm, void *mqd,
+ struct queue_properties *q)
+{
+ struct cik_mqd *m;
+
+ BUG_ON(!mm || !q || !mqd);
+
+ pr_debug("kfd: In func %s\n", __func__);
+
+ m = get_mqd(mqd);
+ m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
+ DEFAULT_MIN_AVAIL_SIZE | PQ_ATC_EN;
+
+ /*
+ * Calculating queue size which is log base 2 of actual queue size -1
+ * dwords and another -1 for ffs
+ */
+ m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
+ - 1 - 1;
+ m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
+ m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
+ m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+ m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+ m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
+ DOORBELL_OFFSET(q->doorbell_off);
+
+ m->cp_hqd_vmid = q->vmid;
+
+ if (q->format == KFD_QUEUE_FORMAT_AQL) {
+ m->cp_hqd_pq_control |= NO_UPDATE_RPTR;
+ }
+
+ m->cp_hqd_active = 0;
+ q->is_active = false;
+ if (q->queue_size > 0 &&
+ q->queue_address != 0 &&
+ q->queue_percent > 0) {
+ m->cp_hqd_active = 1;
+ q->is_active = true;
+ }
+
+ return 0;
+}
+
+static int update_mqd_sdma(struct mqd_manager *mm, void *mqd,
+ struct queue_properties *q)
+{
+ struct cik_sdma_rlc_registers *m;
+
+ BUG_ON(!mm || !mqd || !q);
+
+ m = get_sdma_mqd(mqd);
+ m->sdma_rlc_rb_cntl =
+ SDMA_RB_SIZE((ffs(q->queue_size / sizeof(unsigned int)))) |
+ SDMA_RB_VMID(q->vmid) |
+ SDMA_RPTR_WRITEBACK_ENABLE |
+ SDMA_RPTR_WRITEBACK_TIMER(6);
+
+ m->sdma_rlc_rb_base = lower_32_bits(q->queue_address >> 8);
+ m->sdma_rlc_rb_base_hi = upper_32_bits(q->queue_address >> 8);
+ m->sdma_rlc_rb_rptr_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+ m->sdma_rlc_rb_rptr_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+ m->sdma_rlc_doorbell = SDMA_OFFSET(q->doorbell_off) | SDMA_DB_ENABLE;
+ m->sdma_rlc_virtual_addr = q->sdma_vm_addr;
+
+ m->sdma_engine_id = q->sdma_engine_id;
+ m->sdma_queue_id = q->sdma_queue_id;
+
+ q->is_active = false;
+ if (q->queue_size > 0 &&
+ q->queue_address != 0 &&
+ q->queue_percent > 0) {
+ m->sdma_rlc_rb_cntl |= SDMA_RB_ENABLE;
+ q->is_active = true;
+ }
+
+ return 0;
+}
+
+static int destroy_mqd(struct mqd_manager *mm, void *mqd,
+ enum kfd_preempt_type type,
+ unsigned int timeout, uint32_t pipe_id,
+ uint32_t queue_id)
+{
+ return kfd2kgd->hqd_destroy(mm->dev->kgd, type, timeout,
+ pipe_id, queue_id);
+}
+
+/*
+ * preempt type here is ignored because there is only one way
+ * to preempt sdma queue
+ */
+static int destroy_mqd_sdma(struct mqd_manager *mm, void *mqd,
+ enum kfd_preempt_type type,
+ unsigned int timeout, uint32_t pipe_id,
+ uint32_t queue_id)
+{
+ return kfd2kgd->hqd_sdma_destroy(mm->dev->kgd, mqd, timeout);
+}
+
+static bool is_occupied(struct mqd_manager *mm, void *mqd,
+ uint64_t queue_address, uint32_t pipe_id,
+ uint32_t queue_id)
+{
+
+ return kfd2kgd->hqd_is_occupied(mm->dev->kgd, queue_address,
+ pipe_id, queue_id);
+
+}
+
+static bool is_occupied_sdma(struct mqd_manager *mm, void *mqd,
+ uint64_t queue_address, uint32_t pipe_id,
+ uint32_t queue_id)
+{
+ return kfd2kgd->hqd_sdma_is_occupied(mm->dev->kgd, mqd);
+}
+
+/*
+ * HIQ MQD Implementation, concrete implementation for HIQ MQD implementation.
+ * The HIQ queue in Kaveri is using the same MQD structure as all the user mode
+ * queues but with different initial values.
+ */
+
+static int init_mqd_hiq(struct mqd_manager *mm, void **mqd,
+ struct kfd_mem_obj **mqd_mem_obj, uint64_t *gart_addr,
+ struct queue_properties *q)
+{
+ uint64_t addr;
+ struct cik_mqd *m;
+ int retval;
+
+ BUG_ON(!mm || !q || !mqd || !mqd_mem_obj);
+
+ pr_debug("kfd: In func %s\n", __func__);
+
+ retval = kfd_gtt_sa_allocate(mm->dev, sizeof(struct cik_mqd),
+ mqd_mem_obj);
+
+ if (retval != 0)
+ return -ENOMEM;
+
+ m = (struct cik_mqd *) (*mqd_mem_obj)->cpu_ptr;
+ addr = (*mqd_mem_obj)->gpu_addr;
+
+ memset(m, 0, ALIGN(sizeof(struct cik_mqd), 256));
+
+ m->header = 0xC0310800;
+ m->compute_pipelinestat_enable = 1;
+ m->compute_static_thread_mgmt_se0 = 0xFFFFFFFF;
+ m->compute_static_thread_mgmt_se1 = 0xFFFFFFFF;
+ m->compute_static_thread_mgmt_se2 = 0xFFFFFFFF;
+ m->compute_static_thread_mgmt_se3 = 0xFFFFFFFF;
+
+ m->cp_hqd_persistent_state = DEFAULT_CP_HQD_PERSISTENT_STATE |
+ PRELOAD_REQ;
+ m->cp_hqd_quantum = QUANTUM_EN | QUANTUM_SCALE_1MS |
+ QUANTUM_DURATION(10);
+
+ m->cp_mqd_control = MQD_CONTROL_PRIV_STATE_EN;
+ m->cp_mqd_base_addr_lo = lower_32_bits(addr);
+ m->cp_mqd_base_addr_hi = upper_32_bits(addr);
+
+ m->cp_hqd_ib_control = DEFAULT_MIN_IB_AVAIL_SIZE;
+
+ /*
+ * Pipe Priority
+ * Identifies the pipe relative priority when this queue is connected
+ * to the pipeline. The pipe priority is against the GFX pipe and HP3D.
+ * In KFD we are using a fixed pipe priority set to CS_MEDIUM.
+ * 0 = CS_LOW (typically below GFX)
+ * 1 = CS_MEDIUM (typically between HP3D and GFX
+ * 2 = CS_HIGH (typically above HP3D)
+ */
+ m->cp_hqd_pipe_priority = 1;
+ m->cp_hqd_queue_priority = 15;
+
+ *mqd = m;
+ if (gart_addr)
+ *gart_addr = addr;
+ retval = mm->update_mqd(mm, m, q);
+
+ return retval;
+}
+
+static int update_mqd_hiq(struct mqd_manager *mm, void *mqd,
+ struct queue_properties *q)
+{
+ struct cik_mqd *m;
+
+ BUG_ON(!mm || !q || !mqd);
+
+ pr_debug("kfd: In func %s\n", __func__);
+
+ m = get_mqd(mqd);
+ m->cp_hqd_pq_control = DEFAULT_RPTR_BLOCK_SIZE |
+ DEFAULT_MIN_AVAIL_SIZE |
+ PRIV_STATE |
+ KMD_QUEUE;
+
+ /*
+ * Calculating queue size which is log base 2 of actual queue
+ * size -1 dwords
+ */
+ m->cp_hqd_pq_control |= ffs(q->queue_size / sizeof(unsigned int))
+ - 1 - 1;
+ m->cp_hqd_pq_base_lo = lower_32_bits((uint64_t)q->queue_address >> 8);
+ m->cp_hqd_pq_base_hi = upper_32_bits((uint64_t)q->queue_address >> 8);
+ m->cp_hqd_pq_rptr_report_addr_lo = lower_32_bits((uint64_t)q->read_ptr);
+ m->cp_hqd_pq_rptr_report_addr_hi = upper_32_bits((uint64_t)q->read_ptr);
+ m->cp_hqd_pq_doorbell_control = DOORBELL_EN |
+ DOORBELL_OFFSET(q->doorbell_off);
+
+ m->cp_hqd_vmid = q->vmid;
+
+ m->cp_hqd_active = 0;
+ q->is_active = false;
+ if (q->queue_size > 0 &&
+ q->queue_address != 0 &&
+ q->queue_percent > 0) {
+ m->cp_hqd_active = 1;
+ q->is_active = true;
+ }
+
+ return 0;
+}
+
+struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
+{
+ struct cik_sdma_rlc_registers *m;
+
+ BUG_ON(!mqd);
+
+ m = (struct cik_sdma_rlc_registers *)mqd;
+
+ return m;
+}
+
+struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
+ struct kfd_dev *dev)
+{
+ struct mqd_manager *mqd;
+
+ BUG_ON(!dev);
+ BUG_ON(type >= KFD_MQD_TYPE_MAX);
+
+ pr_debug("kfd: In func %s\n", __func__);
+
+ mqd = kzalloc(sizeof(struct mqd_manager), GFP_KERNEL);
+ if (!mqd)
+ return NULL;
+
+ mqd->dev = dev;
+
+ switch (type) {
+ case KFD_MQD_TYPE_CP:
+ case KFD_MQD_TYPE_COMPUTE:
+ mqd->init_mqd = init_mqd;
+ mqd->uninit_mqd = uninit_mqd;
+ mqd->load_mqd = load_mqd;
+ mqd->update_mqd = update_mqd;
+ mqd->destroy_mqd = destroy_mqd;
+ mqd->is_occupied = is_occupied;
+ break;
+ case KFD_MQD_TYPE_HIQ:
+ mqd->init_mqd = init_mqd_hiq;
+ mqd->uninit_mqd = uninit_mqd;
+ mqd->load_mqd = load_mqd;
+ mqd->update_mqd = update_mqd_hiq;
+ mqd->destroy_mqd = destroy_mqd;
+ mqd->is_occupied = is_occupied;
+ break;
+ case KFD_MQD_TYPE_SDMA:
+ mqd->init_mqd = init_mqd_sdma;
+ mqd->uninit_mqd = uninit_mqd_sdma;
+ mqd->load_mqd = load_mqd_sdma;
+ mqd->update_mqd = update_mqd_sdma;
+ mqd->destroy_mqd = destroy_mqd_sdma;
+ mqd->is_occupied = is_occupied_sdma;
+ break;
+ default:
+ kfree(mqd);
+ return NULL;
+ }
+
+ return mqd;
+}
+
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
new file mode 100644
index 000000000000..b3a7e3ba1e38
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_mqd_manager_vi.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#include <linux/printk.h>
+#include "kfd_priv.h"
+#include "kfd_mqd_manager.h"
+
+struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
+ struct kfd_dev *dev)
+{
+ pr_warn("amdkfd: VI MQD is not currently supported\n");
+ return NULL;
+}
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
index 5ce9233d2004..e2533d875f43 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_packet_manager.c
@@ -97,11 +97,8 @@ static int pm_allocate_runlist_ib(struct packet_manager *pm,
pm_calc_rlib_size(pm, rl_buffer_size, is_over_subscription);
- retval = kfd2kgd->allocate_mem(pm->dqm->dev->kgd,
- *rl_buffer_size,
- PAGE_SIZE,
- KFD_MEMPOOL_SYSTEM_WRITECOMBINE,
- (struct kgd_mem **) &pm->ib_buffer_obj);
+ retval = kfd_gtt_sa_allocate(pm->dqm->dev, *rl_buffer_size,
+ &pm->ib_buffer_obj);
if (retval != 0) {
pr_err("kfd: failed to allocate runlist IB\n");
@@ -351,7 +348,7 @@ int pm_send_set_resources(struct packet_manager *pm,
pr_debug("kfd: In func %s\n", __func__);
mutex_lock(&pm->lock);
- pm->priv_queue->acquire_packet_buffer(pm->priv_queue,
+ pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue,
sizeof(*packet) / sizeof(uint32_t),
(unsigned int **)&packet);
if (packet == NULL) {
@@ -378,8 +375,7 @@ int pm_send_set_resources(struct packet_manager *pm,
packet->queue_mask_lo = lower_32_bits(res->queue_mask);
packet->queue_mask_hi = upper_32_bits(res->queue_mask);
- pm->priv_queue->submit_packet(pm->priv_queue);
- pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+ pm->priv_queue->ops.submit_packet(pm->priv_queue);
mutex_unlock(&pm->lock);
@@ -405,7 +401,7 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues)
packet_size_dwords = sizeof(struct pm4_runlist) / sizeof(uint32_t);
mutex_lock(&pm->lock);
- retval = pm->priv_queue->acquire_packet_buffer(pm->priv_queue,
+ retval = pm->priv_queue->ops.acquire_packet_buffer(pm->priv_queue,
packet_size_dwords, &rl_buffer);
if (retval != 0)
goto fail_acquire_packet_buffer;
@@ -415,15 +411,14 @@ int pm_send_runlist(struct packet_manager *pm, struct list_head *dqm_queues)
if (retval != 0)
goto fail_create_runlist;
- pm->priv_queue->submit_packet(pm->priv_queue);
- pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+ pm->priv_queue->ops.submit_packet(pm->priv_queue);
mutex_unlock(&pm->lock);
return retval;
fail_create_runlist:
- pm->priv_queue->rollback_packet(pm->priv_queue);
+ pm->priv_queue->ops.rollback_packet(pm->priv_queue);
fail_acquire_packet_buffer:
mutex_unlock(&pm->lock);
fail_create_runlist_ib:
@@ -441,7 +436,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
BUG_ON(!pm || !fence_address);
mutex_lock(&pm->lock);
- retval = pm->priv_queue->acquire_packet_buffer(
+ retval = pm->priv_queue->ops.acquire_packet_buffer(
pm->priv_queue,
sizeof(struct pm4_query_status) / sizeof(uint32_t),
(unsigned int **)&packet);
@@ -462,8 +457,7 @@ int pm_send_query_status(struct packet_manager *pm, uint64_t fence_address,
packet->data_hi = upper_32_bits((uint64_t)fence_value);
packet->data_lo = lower_32_bits((uint64_t)fence_value);
- pm->priv_queue->submit_packet(pm->priv_queue);
- pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+ pm->priv_queue->ops.submit_packet(pm->priv_queue);
mutex_unlock(&pm->lock);
return 0;
@@ -485,7 +479,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
BUG_ON(!pm);
mutex_lock(&pm->lock);
- retval = pm->priv_queue->acquire_packet_buffer(
+ retval = pm->priv_queue->ops.acquire_packet_buffer(
pm->priv_queue,
sizeof(struct pm4_unmap_queues) / sizeof(uint32_t),
&buffer);
@@ -540,8 +534,7 @@ int pm_send_unmap_queue(struct packet_manager *pm, enum kfd_queue_type type,
break;
};
- pm->priv_queue->submit_packet(pm->priv_queue);
- pm->priv_queue->sync_with_hw(pm->priv_queue, KFD_HIQ_TIMEOUT);
+ pm->priv_queue->ops.submit_packet(pm->priv_queue);
mutex_unlock(&pm->lock);
return 0;
@@ -557,8 +550,7 @@ void pm_release_ib(struct packet_manager *pm)
mutex_lock(&pm->lock);
if (pm->allocated) {
- kfd2kgd->free_mem(pm->dqm->dev->kgd,
- (struct kgd_mem *) pm->ib_buffer_obj);
+ kfd_gtt_sa_free(pm->dqm->dev, pm->ib_buffer_obj);
pm->allocated = false;
}
mutex_unlock(&pm->lock);
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
index 96dc10e8904a..5a44f2fecf38 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
@@ -103,12 +103,26 @@ enum cache_policy {
cache_policy_noncoherent
};
+enum asic_family_type {
+ CHIP_KAVERI = 0,
+ CHIP_CARRIZO
+};
+
struct kfd_device_info {
+ unsigned int asic_family;
unsigned int max_pasid_bits;
size_t ih_ring_entry_size;
+ uint8_t num_of_watch_points;
uint16_t mqd_size_aligned;
};
+struct kfd_mem_obj {
+ uint32_t range_start;
+ uint32_t range_end;
+ uint64_t gpu_addr;
+ uint32_t *cpu_ptr;
+};
+
struct kfd_dev {
struct kgd_dev *kgd;
@@ -134,6 +148,14 @@ struct kfd_dev {
struct kgd2kfd_shared_resources shared_resources;
+ void *gtt_mem;
+ uint64_t gtt_start_gpu_addr;
+ void *gtt_start_cpu_ptr;
+ void *gtt_sa_bitmap;
+ struct mutex gtt_sa_lock;
+ unsigned int gtt_sa_chunk_size;
+ unsigned int gtt_sa_num_of_chunks;
+
/* QCM Device instance */
struct device_queue_manager *dqm;
@@ -149,12 +171,6 @@ void kgd2kfd_device_exit(struct kfd_dev *kfd);
extern const struct kfd2kgd_calls *kfd2kgd;
-struct kfd_mem_obj {
- void *bo;
- uint64_t gpu_addr;
- uint32_t *cpu_ptr;
-};
-
enum kfd_mempool {
KFD_MEMPOOL_SYSTEM_CACHEABLE = 1,
KFD_MEMPOOL_SYSTEM_WRITECOMBINE = 2,
@@ -272,6 +288,15 @@ struct queue_properties {
bool is_active;
/* Not relevant for user mode queues in cp scheduling */
unsigned int vmid;
+ /* Relevant only for sdma queues*/
+ uint32_t sdma_engine_id;
+ uint32_t sdma_queue_id;
+ uint32_t sdma_vm_addr;
+ /* Relevant only for VI */
+ uint64_t eop_ring_buffer_address;
+ uint32_t eop_ring_buffer_size;
+ uint64_t ctx_save_restore_area_address;
+ uint32_t ctx_save_restore_area_size;
};
/**
@@ -314,6 +339,8 @@ struct queue {
uint32_t pipe;
uint32_t queue;
+ unsigned int sdma_id;
+
struct kfd_process *process;
struct kfd_dev *device;
};
@@ -322,10 +349,10 @@ struct queue {
* Please read the kfd_mqd_manager.h description.
*/
enum KFD_MQD_TYPE {
- KFD_MQD_TYPE_CIK_COMPUTE = 0, /* for no cp scheduling */
- KFD_MQD_TYPE_CIK_HIQ, /* for hiq */
- KFD_MQD_TYPE_CIK_CP, /* for cp queues and diq */
- KFD_MQD_TYPE_CIK_SDMA, /* for sdma queues */
+ KFD_MQD_TYPE_COMPUTE = 0, /* for no cp scheduling */
+ KFD_MQD_TYPE_HIQ, /* for hiq */
+ KFD_MQD_TYPE_CP, /* for cp queues and diq */
+ KFD_MQD_TYPE_SDMA, /* for sdma queues */
KFD_MQD_TYPE_MAX
};
@@ -477,8 +504,9 @@ struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
struct kfd_process *p);
void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid);
struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
- struct kfd_process *p,
- int create_pdd);
+ struct kfd_process *p);
+struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
+ struct kfd_process *p);
/* Process device data iterator */
struct kfd_process_device *kfd_get_first_process_device_data(struct kfd_process *p);
@@ -506,6 +534,13 @@ unsigned int kfd_queue_id_to_doorbell(struct kfd_dev *kfd,
struct kfd_process *process,
unsigned int queue_id);
+/* GTT Sub-Allocator */
+
+int kfd_gtt_sa_allocate(struct kfd_dev *kfd, unsigned int size,
+ struct kfd_mem_obj **mem_obj);
+
+int kfd_gtt_sa_free(struct kfd_dev *kfd, struct kfd_mem_obj *mem_obj);
+
extern struct device *kfd_device;
/* Topology */
@@ -530,6 +565,8 @@ int kfd_init_apertures(struct kfd_process *process);
/* Queue Context Management */
inline uint32_t lower_32(uint64_t x);
inline uint32_t upper_32(uint64_t x);
+struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd);
+inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m);
int init_queue(struct queue **q, struct queue_properties properties);
void uninit_queue(struct queue *q);
@@ -538,6 +575,10 @@ void print_queue(struct queue *q);
struct mqd_manager *mqd_manager_init(enum KFD_MQD_TYPE type,
struct kfd_dev *dev);
+struct mqd_manager *mqd_manager_init_cik(enum KFD_MQD_TYPE type,
+ struct kfd_dev *dev);
+struct mqd_manager *mqd_manager_init_vi(enum KFD_MQD_TYPE type,
+ struct kfd_dev *dev);
struct device_queue_manager *device_queue_manager_init(struct kfd_dev *dev);
void device_queue_manager_uninit(struct device_queue_manager *dqm);
struct kernel_queue *kernel_queue_init(struct kfd_dev *dev,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
index 3c76ef05cbcf..a369c149d172 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
@@ -311,24 +311,29 @@ err_alloc_process:
}
struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
- struct kfd_process *p,
- int create_pdd)
+ struct kfd_process *p)
{
struct kfd_process_device *pdd = NULL;
list_for_each_entry(pdd, &p->per_device_data, per_device_list)
if (pdd->dev == dev)
- return pdd;
-
- if (create_pdd) {
- pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
- if (pdd != NULL) {
- pdd->dev = dev;
- INIT_LIST_HEAD(&pdd->qpd.queues_list);
- INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
- pdd->qpd.dqm = dev->dqm;
- list_add(&pdd->per_device_list, &p->per_device_data);
- }
+ break;
+
+ return pdd;
+}
+
+struct kfd_process_device *kfd_create_process_device_data(struct kfd_dev *dev,
+ struct kfd_process *p)
+{
+ struct kfd_process_device *pdd = NULL;
+
+ pdd = kzalloc(sizeof(*pdd), GFP_KERNEL);
+ if (pdd != NULL) {
+ pdd->dev = dev;
+ INIT_LIST_HEAD(&pdd->qpd.queues_list);
+ INIT_LIST_HEAD(&pdd->qpd.priv_queue_list);
+ pdd->qpd.dqm = dev->dqm;
+ list_add(&pdd->per_device_list, &p->per_device_data);
}
return pdd;
@@ -344,11 +349,14 @@ struct kfd_process_device *kfd_get_process_device_data(struct kfd_dev *dev,
struct kfd_process_device *kfd_bind_process_to_device(struct kfd_dev *dev,
struct kfd_process *p)
{
- struct kfd_process_device *pdd = kfd_get_process_device_data(dev, p, 1);
+ struct kfd_process_device *pdd;
int err;
- if (pdd == NULL)
+ pdd = kfd_get_process_device_data(dev, p);
+ if (!pdd) {
+ pr_err("Process device data doesn't exist\n");
return ERR_PTR(-ENOMEM);
+ }
if (pdd->bound)
return pdd;
@@ -384,7 +392,7 @@ void kfd_unbind_process_from_device(struct kfd_dev *dev, unsigned int pasid)
pqm_uninit(&p->pqm);
- pdd = kfd_get_process_device_data(dev, p, 0);
+ pdd = kfd_get_process_device_data(dev, p);
/*
* Just mark pdd as unbound, because we still need it to call
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
index f37cf5efe642..530b82c4e78b 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_process_queue_manager.c
@@ -128,7 +128,6 @@ static int create_cp_queue(struct process_queue_manager *pqm,
/* let DQM handle it*/
q_properties->vmid = 0;
q_properties->queue_id = qid;
- q_properties->type = KFD_QUEUE_TYPE_COMPUTE;
retval = init_queue(q, *q_properties);
if (retval != 0)
@@ -167,8 +166,11 @@ int pqm_create_queue(struct process_queue_manager *pqm,
q = NULL;
kq = NULL;
- pdd = kfd_get_process_device_data(dev, pqm->process, 1);
- BUG_ON(!pdd);
+ pdd = kfd_get_process_device_data(dev, pqm->process);
+ if (!pdd) {
+ pr_err("Process device data doesn't exist\n");
+ return -1;
+ }
retval = find_available_queue_slot(pqm, qid);
if (retval != 0)
@@ -176,7 +178,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
if (list_empty(&pqm->queues)) {
pdd->qpd.pqm = pqm;
- dev->dqm->register_process(dev->dqm, &pdd->qpd);
+ dev->dqm->ops.register_process(dev->dqm, &pdd->qpd);
}
pqn = kzalloc(sizeof(struct process_queue_node), GFP_KERNEL);
@@ -186,6 +188,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
}
switch (type) {
+ case KFD_QUEUE_TYPE_SDMA:
case KFD_QUEUE_TYPE_COMPUTE:
/* check if there is over subscription */
if ((sched_policy == KFD_SCHED_POLICY_HWS_NO_OVERSUBSCRIPTION) &&
@@ -201,7 +204,7 @@ int pqm_create_queue(struct process_queue_manager *pqm,
goto err_create_queue;
pqn->q = q;
pqn->kq = NULL;
- retval = dev->dqm->create_queue(dev->dqm, q, &pdd->qpd,
+ retval = dev->dqm->ops.create_queue(dev->dqm, q, &pdd->qpd,
&q->properties.vmid);
pr_debug("DQM returned %d for create_queue\n", retval);
print_queue(q);
@@ -215,7 +218,8 @@ int pqm_create_queue(struct process_queue_manager *pqm,
kq->queue->properties.queue_id = *qid;
pqn->kq = kq;
pqn->q = NULL;
- retval = dev->dqm->create_kernel_queue(dev->dqm, kq, &pdd->qpd);
+ retval = dev->dqm->ops.create_kernel_queue(dev->dqm,
+ kq, &pdd->qpd);
break;
default:
BUG();
@@ -245,7 +249,7 @@ err_allocate_pqn:
/* check if queues list is empty unregister process from device */
clear_bit(*qid, pqm->queue_slot_bitmap);
if (list_empty(&pqm->queues))
- dev->dqm->unregister_process(dev->dqm, &pdd->qpd);
+ dev->dqm->ops.unregister_process(dev->dqm, &pdd->qpd);
return retval;
}
@@ -277,19 +281,22 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
dev = pqn->q->device;
BUG_ON(!dev);
- pdd = kfd_get_process_device_data(dev, pqm->process, 1);
- BUG_ON(!pdd);
+ pdd = kfd_get_process_device_data(dev, pqm->process);
+ if (!pdd) {
+ pr_err("Process device data doesn't exist\n");
+ return -1;
+ }
if (pqn->kq) {
/* destroy kernel queue (DIQ) */
dqm = pqn->kq->dev->dqm;
- dqm->destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
+ dqm->ops.destroy_kernel_queue(dqm, pqn->kq, &pdd->qpd);
kernel_queue_uninit(pqn->kq);
}
if (pqn->q) {
dqm = pqn->q->device->dqm;
- retval = dqm->destroy_queue(dqm, &pdd->qpd, pqn->q);
+ retval = dqm->ops.destroy_queue(dqm, &pdd->qpd, pqn->q);
if (retval != 0)
return retval;
@@ -301,7 +308,7 @@ int pqm_destroy_queue(struct process_queue_manager *pqm, unsigned int qid)
clear_bit(qid, pqm->queue_slot_bitmap);
if (list_empty(&pqm->queues))
- dqm->unregister_process(dqm, &pdd->qpd);
+ dqm->ops.unregister_process(dqm, &pdd->qpd);
return retval;
}
@@ -315,14 +322,19 @@ int pqm_update_queue(struct process_queue_manager *pqm, unsigned int qid,
BUG_ON(!pqm);
pqn = get_queue_by_qid(pqm, qid);
- BUG_ON(!pqn);
+ if (!pqn) {
+ pr_debug("amdkfd: No queue %d exists for update operation\n",
+ qid);
+ return -EFAULT;
+ }
pqn->q->properties.queue_address = p->queue_address;
pqn->q->properties.queue_size = p->queue_size;
pqn->q->properties.queue_percent = p->queue_percent;
pqn->q->properties.priority = p->priority;
- retval = pqn->q->device->dqm->update_queue(pqn->q->device->dqm, pqn->q);
+ retval = pqn->q->device->dqm->ops.update_queue(pqn->q->device->dqm,
+ pqn->q);
if (retval != 0)
return retval;
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
index cca1708fd811..498399323a8c 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_topology.c
@@ -27,6 +27,7 @@
#include <linux/acpi.h>
#include <linux/hash.h>
#include <linux/cpufreq.h>
+#include <linux/log2.h>
#include "kfd_priv.h"
#include "kfd_crat.h"
@@ -630,10 +631,10 @@ static struct kobj_type cache_type = {
static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
char *buffer)
{
- ssize_t ret;
struct kfd_topology_device *dev;
char public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE];
uint32_t i;
+ uint32_t log_max_watch_addr;
/* Making sure that the buffer is an empty string */
buffer[0] = 0;
@@ -641,8 +642,10 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
if (strcmp(attr->name, "gpu_id") == 0) {
dev = container_of(attr, struct kfd_topology_device,
attr_gpuid);
- ret = sysfs_show_32bit_val(buffer, dev->gpu_id);
- } else if (strcmp(attr->name, "name") == 0) {
+ return sysfs_show_32bit_val(buffer, dev->gpu_id);
+ }
+
+ if (strcmp(attr->name, "name") == 0) {
dev = container_of(attr, struct kfd_topology_device,
attr_name);
for (i = 0; i < KFD_TOPOLOGY_PUBLIC_NAME_SIZE; i++) {
@@ -652,80 +655,90 @@ static ssize_t node_show(struct kobject *kobj, struct attribute *attr,
break;
}
public_name[KFD_TOPOLOGY_PUBLIC_NAME_SIZE-1] = 0x0;
- ret = sysfs_show_str_val(buffer, public_name);
- } else {
- dev = container_of(attr, struct kfd_topology_device,
- attr_props);
- sysfs_show_32bit_prop(buffer, "cpu_cores_count",
- dev->node_props.cpu_cores_count);
- sysfs_show_32bit_prop(buffer, "simd_count",
- dev->node_props.simd_count);
-
- if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
- pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
- dev->node_props.mem_banks_count,
- dev->mem_bank_count);
- sysfs_show_32bit_prop(buffer, "mem_banks_count",
- dev->mem_bank_count);
- } else {
- sysfs_show_32bit_prop(buffer, "mem_banks_count",
- dev->node_props.mem_banks_count);
- }
+ return sysfs_show_str_val(buffer, public_name);
+ }
- sysfs_show_32bit_prop(buffer, "caches_count",
- dev->node_props.caches_count);
- sysfs_show_32bit_prop(buffer, "io_links_count",
- dev->node_props.io_links_count);
- sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
- dev->node_props.cpu_core_id_base);
- sysfs_show_32bit_prop(buffer, "simd_id_base",
- dev->node_props.simd_id_base);
- sysfs_show_32bit_prop(buffer, "capability",
- dev->node_props.capability);
- sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
- dev->node_props.max_waves_per_simd);
- sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
- dev->node_props.lds_size_in_kb);
- sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
- dev->node_props.gds_size_in_kb);
- sysfs_show_32bit_prop(buffer, "wave_front_size",
- dev->node_props.wave_front_size);
- sysfs_show_32bit_prop(buffer, "array_count",
- dev->node_props.array_count);
- sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
- dev->node_props.simd_arrays_per_engine);
- sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
- dev->node_props.cu_per_simd_array);
- sysfs_show_32bit_prop(buffer, "simd_per_cu",
- dev->node_props.simd_per_cu);
- sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
- dev->node_props.max_slots_scratch_cu);
- sysfs_show_32bit_prop(buffer, "vendor_id",
- dev->node_props.vendor_id);
- sysfs_show_32bit_prop(buffer, "device_id",
- dev->node_props.device_id);
- sysfs_show_32bit_prop(buffer, "location_id",
- dev->node_props.location_id);
-
- if (dev->gpu) {
- sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
- kfd2kgd->get_max_engine_clock_in_mhz(
- dev->gpu->kgd));
- sysfs_show_64bit_prop(buffer, "local_mem_size",
- kfd2kgd->get_vmem_size(dev->gpu->kgd));
-
- sysfs_show_32bit_prop(buffer, "fw_version",
- kfd2kgd->get_fw_version(
- dev->gpu->kgd,
- KGD_ENGINE_MEC1));
+ dev = container_of(attr, struct kfd_topology_device,
+ attr_props);
+ sysfs_show_32bit_prop(buffer, "cpu_cores_count",
+ dev->node_props.cpu_cores_count);
+ sysfs_show_32bit_prop(buffer, "simd_count",
+ dev->node_props.simd_count);
+
+ if (dev->mem_bank_count < dev->node_props.mem_banks_count) {
+ pr_warn("kfd: mem_banks_count truncated from %d to %d\n",
+ dev->node_props.mem_banks_count,
+ dev->mem_bank_count);
+ sysfs_show_32bit_prop(buffer, "mem_banks_count",
+ dev->mem_bank_count);
+ } else {
+ sysfs_show_32bit_prop(buffer, "mem_banks_count",
+ dev->node_props.mem_banks_count);
+ }
+ sysfs_show_32bit_prop(buffer, "caches_count",
+ dev->node_props.caches_count);
+ sysfs_show_32bit_prop(buffer, "io_links_count",
+ dev->node_props.io_links_count);
+ sysfs_show_32bit_prop(buffer, "cpu_core_id_base",
+ dev->node_props.cpu_core_id_base);
+ sysfs_show_32bit_prop(buffer, "simd_id_base",
+ dev->node_props.simd_id_base);
+ sysfs_show_32bit_prop(buffer, "capability",
+ dev->node_props.capability);
+ sysfs_show_32bit_prop(buffer, "max_waves_per_simd",
+ dev->node_props.max_waves_per_simd);
+ sysfs_show_32bit_prop(buffer, "lds_size_in_kb",
+ dev->node_props.lds_size_in_kb);
+ sysfs_show_32bit_prop(buffer, "gds_size_in_kb",
+ dev->node_props.gds_size_in_kb);
+ sysfs_show_32bit_prop(buffer, "wave_front_size",
+ dev->node_props.wave_front_size);
+ sysfs_show_32bit_prop(buffer, "array_count",
+ dev->node_props.array_count);
+ sysfs_show_32bit_prop(buffer, "simd_arrays_per_engine",
+ dev->node_props.simd_arrays_per_engine);
+ sysfs_show_32bit_prop(buffer, "cu_per_simd_array",
+ dev->node_props.cu_per_simd_array);
+ sysfs_show_32bit_prop(buffer, "simd_per_cu",
+ dev->node_props.simd_per_cu);
+ sysfs_show_32bit_prop(buffer, "max_slots_scratch_cu",
+ dev->node_props.max_slots_scratch_cu);
+ sysfs_show_32bit_prop(buffer, "vendor_id",
+ dev->node_props.vendor_id);
+ sysfs_show_32bit_prop(buffer, "device_id",
+ dev->node_props.device_id);
+ sysfs_show_32bit_prop(buffer, "location_id",
+ dev->node_props.location_id);
+
+ if (dev->gpu) {
+ log_max_watch_addr =
+ __ilog2_u32(dev->gpu->device_info->num_of_watch_points);
+
+ if (log_max_watch_addr) {
+ dev->node_props.capability |=
+ HSA_CAP_WATCH_POINTS_SUPPORTED;
+
+ dev->node_props.capability |=
+ ((log_max_watch_addr <<
+ HSA_CAP_WATCH_POINTS_TOTALBITS_SHIFT) &
+ HSA_CAP_WATCH_POINTS_TOTALBITS_MASK);
}
- ret = sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
- cpufreq_quick_get_max(0)/1000);
+ sysfs_show_32bit_prop(buffer, "max_engine_clk_fcompute",
+ kfd2kgd->get_max_engine_clock_in_mhz(
+ dev->gpu->kgd));
+ sysfs_show_64bit_prop(buffer, "local_mem_size",
+ kfd2kgd->get_vmem_size(dev->gpu->kgd));
+
+ sysfs_show_32bit_prop(buffer, "fw_version",
+ kfd2kgd->get_fw_version(
+ dev->gpu->kgd,
+ KGD_ENGINE_MEC1));
}
- return ret;
+ return sysfs_show_32bit_prop(buffer, "max_engine_clk_ccompute",
+ cpufreq_quick_get_max(0)/1000);
}
static const struct sysfs_ops node_ops = {
diff --git a/drivers/gpu/drm/amd/include/cik_structs.h b/drivers/gpu/drm/amd/include/cik_structs.h
new file mode 100644
index 000000000000..749eab94e335
--- /dev/null
+++ b/drivers/gpu/drm/amd/include/cik_structs.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright 2012 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+
+#ifndef CIK_STRUCTS_H_
+#define CIK_STRUCTS_H_
+
+struct cik_mqd {
+ uint32_t header;
+ uint32_t compute_dispatch_initiator;
+ uint32_t compute_dim_x;
+ uint32_t compute_dim_y;
+ uint32_t compute_dim_z;
+ uint32_t compute_start_x;
+ uint32_t compute_start_y;
+ uint32_t compute_start_z;
+ uint32_t compute_num_thread_x;
+ uint32_t compute_num_thread_y;
+ uint32_t compute_num_thread_z;
+ uint32_t compute_pipelinestat_enable;
+ uint32_t compute_perfcount_enable;
+ uint32_t compute_pgm_lo;
+ uint32_t compute_pgm_hi;
+ uint32_t compute_tba_lo;
+ uint32_t compute_tba_hi;
+ uint32_t compute_tma_lo;
+ uint32_t compute_tma_hi;
+ uint32_t compute_pgm_rsrc1;
+ uint32_t compute_pgm_rsrc2;
+ uint32_t compute_vmid;
+ uint32_t compute_resource_limits;
+ uint32_t compute_static_thread_mgmt_se0;
+ uint32_t compute_static_thread_mgmt_se1;
+ uint32_t compute_tmpring_size;
+ uint32_t compute_static_thread_mgmt_se2;
+ uint32_t compute_static_thread_mgmt_se3;
+ uint32_t compute_restart_x;
+ uint32_t compute_restart_y;
+ uint32_t compute_restart_z;
+ uint32_t compute_thread_trace_enable;
+ uint32_t compute_misc_reserved;
+ uint32_t compute_user_data_0;
+ uint32_t compute_user_data_1;
+ uint32_t compute_user_data_2;
+ uint32_t compute_user_data_3;
+ uint32_t compute_user_data_4;
+ uint32_t compute_user_data_5;
+ uint32_t compute_user_data_6;
+ uint32_t compute_user_data_7;
+ uint32_t compute_user_data_8;
+ uint32_t compute_user_data_9;
+ uint32_t compute_user_data_10;
+ uint32_t compute_user_data_11;
+ uint32_t compute_user_data_12;
+ uint32_t compute_user_data_13;
+ uint32_t compute_user_data_14;
+ uint32_t compute_user_data_15;
+ uint32_t cp_compute_csinvoc_count_lo;
+ uint32_t cp_compute_csinvoc_count_hi;
+ uint32_t cp_mqd_base_addr_lo;
+ uint32_t cp_mqd_base_addr_hi;
+ uint32_t cp_hqd_active;
+ uint32_t cp_hqd_vmid;
+ uint32_t cp_hqd_persistent_state;
+ uint32_t cp_hqd_pipe_priority;
+ uint32_t cp_hqd_queue_priority;
+ uint32_t cp_hqd_quantum;
+ uint32_t cp_hqd_pq_base_lo;
+ uint32_t cp_hqd_pq_base_hi;
+ uint32_t cp_hqd_pq_rptr;
+ uint32_t cp_hqd_pq_rptr_report_addr_lo;
+ uint32_t cp_hqd_pq_rptr_report_addr_hi;
+ uint32_t cp_hqd_pq_wptr_poll_addr_lo;
+ uint32_t cp_hqd_pq_wptr_poll_addr_hi;
+ uint32_t cp_hqd_pq_doorbell_control;
+ uint32_t cp_hqd_pq_wptr;
+ uint32_t cp_hqd_pq_control;
+ uint32_t cp_hqd_ib_base_addr_lo;
+ uint32_t cp_hqd_ib_base_addr_hi;
+ uint32_t cp_hqd_ib_rptr;
+ uint32_t cp_hqd_ib_control;
+ uint32_t cp_hqd_iq_timer;
+ uint32_t cp_hqd_iq_rptr;
+ uint32_t cp_hqd_dequeue_request;
+ uint32_t cp_hqd_dma_offload;
+ uint32_t cp_hqd_sema_cmd;
+ uint32_t cp_hqd_msg_type;
+ uint32_t cp_hqd_atomic0_preop_lo;
+ uint32_t cp_hqd_atomic0_preop_hi;
+ uint32_t cp_hqd_atomic1_preop_lo;
+ uint32_t cp_hqd_atomic1_preop_hi;
+ uint32_t cp_hqd_hq_status0;
+ uint32_t cp_hqd_hq_control0;
+ uint32_t cp_mqd_control;
+ uint32_t cp_mqd_query_time_lo;
+ uint32_t cp_mqd_query_time_hi;
+ uint32_t cp_mqd_connect_start_time_lo;
+ uint32_t cp_mqd_connect_start_time_hi;
+ uint32_t cp_mqd_connect_end_time_lo;
+ uint32_t cp_mqd_connect_end_time_hi;
+ uint32_t cp_mqd_connect_end_wf_count;
+ uint32_t cp_mqd_connect_end_pq_rptr;
+ uint32_t cp_mqd_connect_end_pq_wptr;
+ uint32_t cp_mqd_connect_end_ib_rptr;
+ uint32_t reserved_96;
+ uint32_t reserved_97;
+ uint32_t reserved_98;
+ uint32_t reserved_99;
+ uint32_t iqtimer_pkt_header;
+ uint32_t iqtimer_pkt_dw0;
+ uint32_t iqtimer_pkt_dw1;
+ uint32_t iqtimer_pkt_dw2;
+ uint32_t iqtimer_pkt_dw3;
+ uint32_t iqtimer_pkt_dw4;
+ uint32_t iqtimer_pkt_dw5;
+ uint32_t iqtimer_pkt_dw6;
+ uint32_t reserved_108;
+ uint32_t reserved_109;
+ uint32_t reserved_110;
+ uint32_t reserved_111;
+ uint32_t queue_doorbell_id0;
+ uint32_t queue_doorbell_id1;
+ uint32_t queue_doorbell_id2;
+ uint32_t queue_doorbell_id3;
+ uint32_t queue_doorbell_id4;
+ uint32_t queue_doorbell_id5;
+ uint32_t queue_doorbell_id6;
+ uint32_t queue_doorbell_id7;
+ uint32_t queue_doorbell_id8;
+ uint32_t queue_doorbell_id9;
+ uint32_t queue_doorbell_id10;
+ uint32_t queue_doorbell_id11;
+ uint32_t queue_doorbell_id12;
+ uint32_t queue_doorbell_id13;
+ uint32_t queue_doorbell_id14;
+ uint32_t queue_doorbell_id15;
+};
+
+struct cik_sdma_rlc_registers {
+ uint32_t sdma_rlc_rb_cntl;
+ uint32_t sdma_rlc_rb_base;
+ uint32_t sdma_rlc_rb_base_hi;
+ uint32_t sdma_rlc_rb_rptr;
+ uint32_t sdma_rlc_rb_wptr;
+ uint32_t sdma_rlc_rb_wptr_poll_cntl;
+ uint32_t sdma_rlc_rb_wptr_poll_addr_hi;
+ uint32_t sdma_rlc_rb_wptr_poll_addr_lo;
+ uint32_t sdma_rlc_rb_rptr_addr_hi;
+ uint32_t sdma_rlc_rb_rptr_addr_lo;
+ uint32_t sdma_rlc_ib_cntl;
+ uint32_t sdma_rlc_ib_rptr;
+ uint32_t sdma_rlc_ib_offset;
+ uint32_t sdma_rlc_ib_base_lo;
+ uint32_t sdma_rlc_ib_base_hi;
+ uint32_t sdma_rlc_ib_size;
+ uint32_t sdma_rlc_skip_cntl;
+ uint32_t sdma_rlc_context_status;
+ uint32_t sdma_rlc_doorbell;
+ uint32_t sdma_rlc_virtual_addr;
+ uint32_t sdma_rlc_ape1_cntl;
+ uint32_t sdma_rlc_doorbell_log;
+ uint32_t reserved_22;
+ uint32_t reserved_23;
+ uint32_t reserved_24;
+ uint32_t reserved_25;
+ uint32_t reserved_26;
+ uint32_t reserved_27;
+ uint32_t reserved_28;
+ uint32_t reserved_29;
+ uint32_t reserved_30;
+ uint32_t reserved_31;
+ uint32_t reserved_32;
+ uint32_t reserved_33;
+ uint32_t reserved_34;
+ uint32_t reserved_35;
+ uint32_t reserved_36;
+ uint32_t reserved_37;
+ uint32_t reserved_38;
+ uint32_t reserved_39;
+ uint32_t reserved_40;
+ uint32_t reserved_41;
+ uint32_t reserved_42;
+ uint32_t reserved_43;
+ uint32_t reserved_44;
+ uint32_t reserved_45;
+ uint32_t reserved_46;
+ uint32_t reserved_47;
+ uint32_t reserved_48;
+ uint32_t reserved_49;
+ uint32_t reserved_50;
+ uint32_t reserved_51;
+ uint32_t reserved_52;
+ uint32_t reserved_53;
+ uint32_t reserved_54;
+ uint32_t reserved_55;
+ uint32_t reserved_56;
+ uint32_t reserved_57;
+ uint32_t reserved_58;
+ uint32_t reserved_59;
+ uint32_t reserved_60;
+ uint32_t reserved_61;
+ uint32_t reserved_62;
+ uint32_t reserved_63;
+ uint32_t reserved_64;
+ uint32_t reserved_65;
+ uint32_t reserved_66;
+ uint32_t reserved_67;
+ uint32_t reserved_68;
+ uint32_t reserved_69;
+ uint32_t reserved_70;
+ uint32_t reserved_71;
+ uint32_t reserved_72;
+ uint32_t reserved_73;
+ uint32_t reserved_74;
+ uint32_t reserved_75;
+ uint32_t reserved_76;
+ uint32_t reserved_77;
+ uint32_t reserved_78;
+ uint32_t reserved_79;
+ uint32_t reserved_80;
+ uint32_t reserved_81;
+ uint32_t reserved_82;
+ uint32_t reserved_83;
+ uint32_t reserved_84;
+ uint32_t reserved_85;
+ uint32_t reserved_86;
+ uint32_t reserved_87;
+ uint32_t reserved_88;
+ uint32_t reserved_89;
+ uint32_t reserved_90;
+ uint32_t reserved_91;
+ uint32_t reserved_92;
+ uint32_t reserved_93;
+ uint32_t reserved_94;
+ uint32_t reserved_95;
+ uint32_t reserved_96;
+ uint32_t reserved_97;
+ uint32_t reserved_98;
+ uint32_t reserved_99;
+ uint32_t reserved_100;
+ uint32_t reserved_101;
+ uint32_t reserved_102;
+ uint32_t reserved_103;
+ uint32_t reserved_104;
+ uint32_t reserved_105;
+ uint32_t reserved_106;
+ uint32_t reserved_107;
+ uint32_t reserved_108;
+ uint32_t reserved_109;
+ uint32_t reserved_110;
+ uint32_t reserved_111;
+ uint32_t reserved_112;
+ uint32_t reserved_113;
+ uint32_t reserved_114;
+ uint32_t reserved_115;
+ uint32_t reserved_116;
+ uint32_t reserved_117;
+ uint32_t reserved_118;
+ uint32_t reserved_119;
+ uint32_t reserved_120;
+ uint32_t reserved_121;
+ uint32_t reserved_122;
+ uint32_t reserved_123;
+ uint32_t reserved_124;
+ uint32_t reserved_125;
+ uint32_t reserved_126;
+ uint32_t reserved_127;
+ uint32_t sdma_engine_id;
+ uint32_t sdma_queue_id;
+};
+
+
+
+#endif /* CIK_STRUCTS_H_ */
diff --git a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
index 96a512208fad..239bc16a1ddd 100644
--- a/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
+++ b/drivers/gpu/drm/amd/include/kgd_kfd_interface.h
@@ -110,17 +110,10 @@ struct kgd2kfd_calls {
/**
* struct kfd2kgd_calls
*
- * @init_sa_manager: Initialize an instance of the sa manager, used by
- * amdkfd for all system memory allocations that are mapped to the GART
- * address space
+ * @init_gtt_mem_allocation: Allocate a buffer on the gart aperture.
+ * The buffer can be used for mqds, hpds, kernel queue, fence and runlists
*
- * @fini_sa_manager: Releases all memory allocations for amdkfd that are
- * handled by kgd sa manager
- *
- * @allocate_mem: Allocate a buffer from amdkfd's sa manager. The buffer can
- * be used for mqds, hpds, kernel queue, fence and runlists
- *
- * @free_mem: Frees a buffer that was allocated by amdkfd's sa manager
+ * @free_gtt_mem: Frees a buffer that was allocated on the gart aperture
*
* @get_vmem_size: Retrieves (physical) size of VRAM
*
@@ -136,18 +129,23 @@ struct kgd2kfd_calls {
* @set_pasid_vmid_mapping: Exposes pasid/vmid pair to the H/W for no cp
* scheduling mode. Only used for no cp scheduling mode.
*
- * @init_memory: Initializes memory apertures to fixed base/limit address
- * and non cached memory types.
- *
* @init_pipeline: Initialized the compute pipelines.
*
* @hqd_load: Loads the mqd structure to a H/W hqd slot. used only for no cp
* sceduling mode.
*
+ * @hqd_sdma_load: Loads the SDMA mqd structure to a H/W SDMA hqd slot.
+ * used only for no HWS mode.
+ *
* @hqd_is_occupies: Checks if a hqd slot is occupied.
*
* @hqd_destroy: Destructs and preempts the queue assigned to that hqd slot.
*
+ * @hqd_sdma_is_occupied: Checks if an SDMA hqd slot is occupied.
+ *
+ * @hqd_sdma_destroy: Destructs and preempts the SDMA queue assigned to that
+ * SDMA hqd slot.
+ *
* @get_fw_version: Returns FW versions from the header
*
* This structure contains function pointers to services that the kgd driver
@@ -155,13 +153,11 @@ struct kgd2kfd_calls {
*
*/
struct kfd2kgd_calls {
- /* Memory management. */
- int (*init_sa_manager)(struct kgd_dev *kgd, unsigned int size);
- void (*fini_sa_manager)(struct kgd_dev *kgd);
- int (*allocate_mem)(struct kgd_dev *kgd, size_t size, size_t alignment,
- enum kgd_memory_pool pool, struct kgd_mem **mem);
+ int (*init_gtt_mem_allocation)(struct kgd_dev *kgd, size_t size,
+ void **mem_obj, uint64_t *gpu_addr,
+ void **cpu_ptr);
- void (*free_mem)(struct kgd_dev *kgd, struct kgd_mem *mem);
+ void (*free_gtt_mem)(struct kgd_dev *kgd, void *mem_obj);
uint64_t (*get_vmem_size)(struct kgd_dev *kgd);
uint64_t (*get_gpu_clock_counter)(struct kgd_dev *kgd);
@@ -176,25 +172,32 @@ struct kfd2kgd_calls {
int (*set_pasid_vmid_mapping)(struct kgd_dev *kgd, unsigned int pasid,
unsigned int vmid);
- int (*init_memory)(struct kgd_dev *kgd);
int (*init_pipeline)(struct kgd_dev *kgd, uint32_t pipe_id,
uint32_t hpd_size, uint64_t hpd_gpu_addr);
int (*hqd_load)(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr);
+ int (*hqd_sdma_load)(struct kgd_dev *kgd, void *mqd);
+
bool (*hqd_is_occupied)(struct kgd_dev *kgd, uint64_t queue_address,
uint32_t pipe_id, uint32_t queue_id);
int (*hqd_destroy)(struct kgd_dev *kgd, uint32_t reset_type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id);
+
+ bool (*hqd_sdma_is_occupied)(struct kgd_dev *kgd, void *mqd);
+
+ int (*hqd_sdma_destroy)(struct kgd_dev *kgd, void *mqd,
+ unsigned int timeout);
+
uint16_t (*get_fw_version)(struct kgd_dev *kgd,
enum kgd_engine_type type);
};
bool kgd2kfd_init(unsigned interface_version,
- const struct kfd2kgd_calls *f2g,
- const struct kgd2kfd_calls **g2f);
+ const struct kfd2kgd_calls *f2g,
+ const struct kgd2kfd_calls **g2f);
-#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
+#endif /* KGD_KFD_INTERFACE_H_INCLUDED */
diff --git a/drivers/gpu/drm/armada/armada_crtc.c b/drivers/gpu/drm/armada/armada_crtc.c
index e3a7a5078e5c..42d2ffa08716 100644
--- a/drivers/gpu/drm/armada/armada_crtc.c
+++ b/drivers/gpu/drm/armada/armada_crtc.c
@@ -653,10 +653,6 @@ static int armada_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
return 0;
}
-static void armada_drm_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
/* The mode_config.mutex will be held for this call */
static void armada_drm_crtc_disable(struct drm_crtc *crtc)
{
@@ -678,7 +674,6 @@ static const struct drm_crtc_helper_funcs armada_crtc_helper_funcs = {
.mode_fixup = armada_drm_crtc_mode_fixup,
.mode_set = armada_drm_crtc_mode_set,
.mode_set_base = armada_drm_crtc_mode_set_base,
- .load_lut = armada_drm_crtc_load_lut,
.disable = armada_drm_crtc_disable,
};
diff --git a/drivers/gpu/drm/ast/ast_fb.c b/drivers/gpu/drm/ast/ast_fb.c
index 5c60ae524c45..ff68eefae273 100644
--- a/drivers/gpu/drm/ast/ast_fb.c
+++ b/drivers/gpu/drm/ast/ast_fb.c
@@ -335,18 +335,27 @@ int ast_fbdev_init(struct drm_device *dev)
ret = drm_fb_helper_init(dev, &afbdev->helper,
1, 1);
- if (ret) {
- kfree(afbdev);
- return ret;
- }
+ if (ret)
+ goto free;
- drm_fb_helper_single_add_all_connectors(&afbdev->helper);
+ ret = drm_fb_helper_single_add_all_connectors(&afbdev->helper);
+ if (ret)
+ goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
- drm_fb_helper_initial_config(&afbdev->helper, 32);
+ ret = drm_fb_helper_initial_config(&afbdev->helper, 32);
+ if (ret)
+ goto fini;
+
return 0;
+
+fini:
+ drm_fb_helper_fini(&afbdev->helper);
+free:
+ kfree(afbdev);
+ return ret;
}
void ast_fbdev_fini(struct drm_device *dev)
diff --git a/drivers/gpu/drm/atmel-hlcdc/Kconfig b/drivers/gpu/drm/atmel-hlcdc/Kconfig
new file mode 100644
index 000000000000..99b4f0698a30
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Kconfig
@@ -0,0 +1,11 @@
+config DRM_ATMEL_HLCDC
+ tristate "DRM Support for ATMEL HLCDC Display Controller"
+ depends on DRM && OF && COMMON_CLK && MFD_ATMEL_HLCDC && ARM
+ select DRM_GEM_CMA_HELPER
+ select DRM_KMS_HELPER
+ select DRM_KMS_FB_HELPER
+ select DRM_KMS_CMA_HELPER
+ select DRM_PANEL
+ help
+ Choose this option if you have an ATMEL SoC with an HLCDC display
+ controller (i.e. at91sam9n12, at91sam9x5 family or sama5d3 family).
diff --git a/drivers/gpu/drm/atmel-hlcdc/Makefile b/drivers/gpu/drm/atmel-hlcdc/Makefile
new file mode 100644
index 000000000000..10ae426e60bd
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/Makefile
@@ -0,0 +1,7 @@
+atmel-hlcdc-dc-y := atmel_hlcdc_crtc.o \
+ atmel_hlcdc_dc.o \
+ atmel_hlcdc_layer.o \
+ atmel_hlcdc_output.o \
+ atmel_hlcdc_plane.o
+
+obj-$(CONFIG_DRM_ATMEL_HLCDC) += atmel-hlcdc-dc.o
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
new file mode 100644
index 000000000000..b3e3068c6ec0
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_crtc.c
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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/pm.h>
+#include <linux/pm_runtime.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drmP.h>
+
+#include <video/videomode.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Atmel HLCDC CRTC structure
+ *
+ * @base: base DRM CRTC structure
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @event: pointer to the current page flip event
+ * @id: CRTC id (returned by drm_crtc_index)
+ * @dpms: DPMS mode
+ */
+struct atmel_hlcdc_crtc {
+ struct drm_crtc base;
+ struct atmel_hlcdc_dc *dc;
+ struct drm_pending_vblank_event *event;
+ int id;
+ int dpms;
+};
+
+static inline struct atmel_hlcdc_crtc *
+drm_crtc_to_atmel_hlcdc_crtc(struct drm_crtc *crtc)
+{
+ return container_of(crtc, struct atmel_hlcdc_crtc, base);
+}
+
+static void atmel_hlcdc_crtc_dpms(struct drm_crtc *c, int mode)
+{
+ struct drm_device *dev = c->dev;
+ struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+ struct regmap *regmap = crtc->dc->hlcdc->regmap;
+ unsigned int status;
+
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
+ if (crtc->dpms == mode)
+ return;
+
+ pm_runtime_get_sync(dev->dev);
+
+ if (mode != DRM_MODE_DPMS_ON) {
+ regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_DISP);
+ while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+ (status & ATMEL_HLCDC_DISP))
+ cpu_relax();
+
+ regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_SYNC);
+ while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+ (status & ATMEL_HLCDC_SYNC))
+ cpu_relax();
+
+ regmap_write(regmap, ATMEL_HLCDC_DIS, ATMEL_HLCDC_PIXEL_CLK);
+ while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+ (status & ATMEL_HLCDC_PIXEL_CLK))
+ cpu_relax();
+
+ clk_disable_unprepare(crtc->dc->hlcdc->sys_clk);
+
+ pm_runtime_allow(dev->dev);
+ } else {
+ pm_runtime_forbid(dev->dev);
+
+ clk_prepare_enable(crtc->dc->hlcdc->sys_clk);
+
+ regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_PIXEL_CLK);
+ while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+ !(status & ATMEL_HLCDC_PIXEL_CLK))
+ cpu_relax();
+
+
+ regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_SYNC);
+ while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+ !(status & ATMEL_HLCDC_SYNC))
+ cpu_relax();
+
+ regmap_write(regmap, ATMEL_HLCDC_EN, ATMEL_HLCDC_DISP);
+ while (!regmap_read(regmap, ATMEL_HLCDC_SR, &status) &&
+ !(status & ATMEL_HLCDC_DISP))
+ cpu_relax();
+ }
+
+ pm_runtime_put_sync(dev->dev);
+
+ crtc->dpms = mode;
+}
+
+static int atmel_hlcdc_crtc_mode_set(struct drm_crtc *c,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj,
+ int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+ struct regmap *regmap = crtc->dc->hlcdc->regmap;
+ struct drm_plane *plane = c->primary;
+ struct drm_framebuffer *fb;
+ unsigned long mode_rate;
+ struct videomode vm;
+ unsigned long prate;
+ unsigned int cfg;
+ int div;
+
+ if (atmel_hlcdc_dc_mode_valid(crtc->dc, adj) != MODE_OK)
+ return -EINVAL;
+
+ vm.vfront_porch = adj->crtc_vsync_start - adj->crtc_vdisplay;
+ vm.vback_porch = adj->crtc_vtotal - adj->crtc_vsync_end;
+ vm.vsync_len = adj->crtc_vsync_end - adj->crtc_vsync_start;
+ vm.hfront_porch = adj->crtc_hsync_start - adj->crtc_hdisplay;
+ vm.hback_porch = adj->crtc_htotal - adj->crtc_hsync_end;
+ vm.hsync_len = adj->crtc_hsync_end - adj->crtc_hsync_start;
+
+ regmap_write(regmap, ATMEL_HLCDC_CFG(1),
+ (vm.hsync_len - 1) | ((vm.vsync_len - 1) << 16));
+
+ regmap_write(regmap, ATMEL_HLCDC_CFG(2),
+ (vm.vfront_porch - 1) | (vm.vback_porch << 16));
+
+ regmap_write(regmap, ATMEL_HLCDC_CFG(3),
+ (vm.hfront_porch - 1) | ((vm.hback_porch - 1) << 16));
+
+ regmap_write(regmap, ATMEL_HLCDC_CFG(4),
+ (adj->crtc_hdisplay - 1) |
+ ((adj->crtc_vdisplay - 1) << 16));
+
+ cfg = 0;
+
+ prate = clk_get_rate(crtc->dc->hlcdc->sys_clk);
+ mode_rate = mode->crtc_clock * 1000;
+ if ((prate / 2) < mode_rate) {
+ prate *= 2;
+ cfg |= ATMEL_HLCDC_CLKSEL;
+ }
+
+ div = DIV_ROUND_UP(prate, mode_rate);
+ if (div < 2)
+ div = 2;
+
+ cfg |= ATMEL_HLCDC_CLKDIV(div);
+
+ regmap_update_bits(regmap, ATMEL_HLCDC_CFG(0),
+ ATMEL_HLCDC_CLKSEL | ATMEL_HLCDC_CLKDIV_MASK |
+ ATMEL_HLCDC_CLKPOL, cfg);
+
+ cfg = 0;
+
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ cfg |= ATMEL_HLCDC_VSPOL;
+
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ cfg |= ATMEL_HLCDC_HSPOL;
+
+ regmap_update_bits(regmap, ATMEL_HLCDC_CFG(5),
+ ATMEL_HLCDC_HSPOL | ATMEL_HLCDC_VSPOL |
+ ATMEL_HLCDC_VSPDLYS | ATMEL_HLCDC_VSPDLYE |
+ ATMEL_HLCDC_DISPPOL | ATMEL_HLCDC_DISPDLY |
+ ATMEL_HLCDC_VSPSU | ATMEL_HLCDC_VSPHO |
+ ATMEL_HLCDC_GUARDTIME_MASK,
+ cfg);
+
+ fb = plane->fb;
+ plane->fb = old_fb;
+
+ return atmel_hlcdc_plane_update_with_mode(plane, c, fb, 0, 0,
+ adj->hdisplay, adj->vdisplay,
+ x << 16, y << 16,
+ adj->hdisplay << 16,
+ adj->vdisplay << 16,
+ adj);
+}
+
+int atmel_hlcdc_crtc_mode_set_base(struct drm_crtc *c, int x, int y,
+ struct drm_framebuffer *old_fb)
+{
+ struct drm_plane *plane = c->primary;
+ struct drm_framebuffer *fb = plane->fb;
+ struct drm_display_mode *mode = &c->hwmode;
+
+ plane->fb = old_fb;
+
+ return plane->funcs->update_plane(plane, c, fb,
+ 0, 0,
+ mode->hdisplay,
+ mode->vdisplay,
+ x << 16, y << 16,
+ mode->hdisplay << 16,
+ mode->vdisplay << 16);
+}
+
+static void atmel_hlcdc_crtc_prepare(struct drm_crtc *crtc)
+{
+ atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_crtc_commit(struct drm_crtc *crtc)
+{
+ atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+}
+
+static bool atmel_hlcdc_crtc_mode_fixup(struct drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void atmel_hlcdc_crtc_disable(struct drm_crtc *crtc)
+{
+ struct drm_plane *plane;
+
+ atmel_hlcdc_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+ crtc->primary->funcs->disable_plane(crtc->primary);
+
+ drm_for_each_legacy_plane(plane, &crtc->dev->mode_config.plane_list) {
+ if (plane->crtc != crtc)
+ continue;
+
+ plane->funcs->disable_plane(crtc->primary);
+ plane->crtc = NULL;
+ }
+}
+
+static const struct drm_crtc_helper_funcs lcdc_crtc_helper_funcs = {
+ .mode_fixup = atmel_hlcdc_crtc_mode_fixup,
+ .dpms = atmel_hlcdc_crtc_dpms,
+ .mode_set = atmel_hlcdc_crtc_mode_set,
+ .mode_set_base = atmel_hlcdc_crtc_mode_set_base,
+ .prepare = atmel_hlcdc_crtc_prepare,
+ .commit = atmel_hlcdc_crtc_commit,
+ .disable = atmel_hlcdc_crtc_disable,
+};
+
+static void atmel_hlcdc_crtc_destroy(struct drm_crtc *c)
+{
+ struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+
+ drm_crtc_cleanup(c);
+ kfree(crtc);
+}
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *c,
+ struct drm_file *file)
+{
+ struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+ struct drm_pending_vblank_event *event;
+ struct drm_device *dev = c->dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ event = crtc->event;
+ if (event && event->base.file_priv == file) {
+ event->base.destroy(&event->base);
+ drm_vblank_put(dev, crtc->id);
+ crtc->event = NULL;
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+static void atmel_hlcdc_crtc_finish_page_flip(struct atmel_hlcdc_crtc *crtc)
+{
+ struct drm_device *dev = crtc->base.dev;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (crtc->event) {
+ drm_send_vblank_event(dev, crtc->id, crtc->event);
+ drm_vblank_put(dev, crtc->id);
+ crtc->event = NULL;
+ }
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+}
+
+void atmel_hlcdc_crtc_irq(struct drm_crtc *c)
+{
+ drm_handle_vblank(c->dev, 0);
+ atmel_hlcdc_crtc_finish_page_flip(drm_crtc_to_atmel_hlcdc_crtc(c));
+}
+
+static int atmel_hlcdc_crtc_page_flip(struct drm_crtc *c,
+ struct drm_framebuffer *fb,
+ struct drm_pending_vblank_event *event,
+ uint32_t page_flip_flags)
+{
+ struct atmel_hlcdc_crtc *crtc = drm_crtc_to_atmel_hlcdc_crtc(c);
+ struct atmel_hlcdc_plane_update_req req;
+ struct drm_plane *plane = c->primary;
+ struct drm_device *dev = c->dev;
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (crtc->event)
+ ret = -EBUSY;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ if (ret)
+ return ret;
+
+ memset(&req, 0, sizeof(req));
+ req.crtc_x = 0;
+ req.crtc_y = 0;
+ req.crtc_h = c->mode.crtc_vdisplay;
+ req.crtc_w = c->mode.crtc_hdisplay;
+ req.src_x = c->x << 16;
+ req.src_y = c->y << 16;
+ req.src_w = req.crtc_w << 16;
+ req.src_h = req.crtc_h << 16;
+ req.fb = fb;
+
+ ret = atmel_hlcdc_plane_prepare_update_req(plane, &req, &c->hwmode);
+ if (ret)
+ return ret;
+
+ if (event) {
+ drm_vblank_get(c->dev, crtc->id);
+ spin_lock_irqsave(&dev->event_lock, flags);
+ crtc->event = event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ }
+
+ ret = atmel_hlcdc_plane_apply_update_req(plane, &req);
+ if (ret)
+ crtc->event = NULL;
+ else
+ plane->fb = fb;
+
+ return ret;
+}
+
+static const struct drm_crtc_funcs atmel_hlcdc_crtc_funcs = {
+ .page_flip = atmel_hlcdc_crtc_page_flip,
+ .set_config = drm_crtc_helper_set_config,
+ .destroy = atmel_hlcdc_crtc_destroy,
+};
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ struct atmel_hlcdc_planes *planes = dc->planes;
+ struct atmel_hlcdc_crtc *crtc;
+ int ret;
+ int i;
+
+ crtc = kzalloc(sizeof(*crtc), GFP_KERNEL);
+ if (!crtc)
+ return -ENOMEM;
+
+ crtc->dpms = DRM_MODE_DPMS_OFF;
+ crtc->dc = dc;
+
+ ret = drm_crtc_init_with_planes(dev, &crtc->base,
+ &planes->primary->base,
+ planes->cursor ? &planes->cursor->base : NULL,
+ &atmel_hlcdc_crtc_funcs);
+ if (ret < 0)
+ goto fail;
+
+ crtc->id = drm_crtc_index(&crtc->base);
+
+ if (planes->cursor)
+ planes->cursor->base.possible_crtcs = 1 << crtc->id;
+
+ for (i = 0; i < planes->noverlays; i++)
+ planes->overlays[i]->base.possible_crtcs = 1 << crtc->id;
+
+ drm_crtc_helper_add(&crtc->base, &lcdc_crtc_helper_funcs);
+
+ dc->crtc = &crtc->base;
+
+ return 0;
+
+fail:
+ atmel_hlcdc_crtc_destroy(&crtc->base);
+ return ret;
+}
+
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
new file mode 100644
index 000000000000..c1cb17493e0d
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.c
@@ -0,0 +1,577 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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/irq.h>
+#include <linux/irqchip.h>
+#include <linux/module.h>
+#include <linux/pm_runtime.h>
+
+#include "atmel_hlcdc_dc.h"
+
+#define ATMEL_HLCDC_LAYER_IRQS_OFFSET 8
+
+static const struct atmel_hlcdc_layer_desc atmel_hlcdc_sama5d3_layers[] = {
+ {
+ .name = "base",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x40,
+ .id = 0,
+ .type = ATMEL_HLCDC_BASE_LAYER,
+ .nconfigs = 7,
+ .layout = {
+ .xstride = { 2 },
+ .default_color = 3,
+ .general_config = 4,
+ .disc_pos = 5,
+ .disc_size = 6,
+ },
+ },
+ {
+ .name = "overlay1",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x140,
+ .id = 1,
+ .type = ATMEL_HLCDC_OVERLAY_LAYER,
+ .nconfigs = 10,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .xstride = { 4 },
+ .pstride = { 5 },
+ .default_color = 6,
+ .chroma_key = 7,
+ .chroma_key_mask = 8,
+ .general_config = 9,
+ },
+ },
+ {
+ .name = "overlay2",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x240,
+ .id = 2,
+ .type = ATMEL_HLCDC_OVERLAY_LAYER,
+ .nconfigs = 10,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .xstride = { 4 },
+ .pstride = { 5 },
+ .default_color = 6,
+ .chroma_key = 7,
+ .chroma_key_mask = 8,
+ .general_config = 9,
+ },
+ },
+ {
+ .name = "high-end-overlay",
+ .formats = &atmel_hlcdc_plane_rgb_and_yuv_formats,
+ .regs_offset = 0x340,
+ .id = 3,
+ .type = ATMEL_HLCDC_OVERLAY_LAYER,
+ .nconfigs = 42,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .memsize = 4,
+ .xstride = { 5, 7 },
+ .pstride = { 6, 8 },
+ .default_color = 9,
+ .chroma_key = 10,
+ .chroma_key_mask = 11,
+ .general_config = 12,
+ .csc = 14,
+ },
+ },
+ {
+ .name = "cursor",
+ .formats = &atmel_hlcdc_plane_rgb_formats,
+ .regs_offset = 0x440,
+ .id = 4,
+ .type = ATMEL_HLCDC_CURSOR_LAYER,
+ .nconfigs = 10,
+ .max_width = 128,
+ .max_height = 128,
+ .layout = {
+ .pos = 2,
+ .size = 3,
+ .xstride = { 4 },
+ .pstride = { 5 },
+ .default_color = 6,
+ .chroma_key = 7,
+ .chroma_key_mask = 8,
+ .general_config = 9,
+ },
+ },
+};
+
+static const struct atmel_hlcdc_dc_desc atmel_hlcdc_dc_sama5d3 = {
+ .min_width = 0,
+ .min_height = 0,
+ .max_width = 2048,
+ .max_height = 2048,
+ .nlayers = ARRAY_SIZE(atmel_hlcdc_sama5d3_layers),
+ .layers = atmel_hlcdc_sama5d3_layers,
+};
+
+static const struct of_device_id atmel_hlcdc_of_match[] = {
+ {
+ .compatible = "atmel,sama5d3-hlcdc",
+ .data = &atmel_hlcdc_dc_sama5d3,
+ },
+ { /* sentinel */ },
+};
+
+int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
+ struct drm_display_mode *mode)
+{
+ int vfront_porch = mode->vsync_start - mode->vdisplay;
+ int vback_porch = mode->vtotal - mode->vsync_end;
+ int vsync_len = mode->vsync_end - mode->vsync_start;
+ int hfront_porch = mode->hsync_start - mode->hdisplay;
+ int hback_porch = mode->htotal - mode->hsync_end;
+ int hsync_len = mode->hsync_end - mode->hsync_start;
+
+ if (hsync_len > 0x40 || hsync_len < 1)
+ return MODE_HSYNC;
+
+ if (vsync_len > 0x40 || vsync_len < 1)
+ return MODE_VSYNC;
+
+ if (hfront_porch > 0x200 || hfront_porch < 1 ||
+ hback_porch > 0x200 || hback_porch < 1 ||
+ mode->hdisplay < 1)
+ return MODE_H_ILLEGAL;
+
+ if (vfront_porch > 0x40 || vfront_porch < 1 ||
+ vback_porch > 0x40 || vback_porch < 0 ||
+ mode->vdisplay < 1)
+ return MODE_V_ILLEGAL;
+
+ return MODE_OK;
+}
+
+static irqreturn_t atmel_hlcdc_dc_irq_handler(int irq, void *data)
+{
+ struct drm_device *dev = data;
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ unsigned long status;
+ unsigned int imr, isr;
+ int i;
+
+ regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_IMR, &imr);
+ regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+ status = imr & isr;
+ if (!status)
+ return IRQ_NONE;
+
+ if (status & ATMEL_HLCDC_SOF)
+ atmel_hlcdc_crtc_irq(dc->crtc);
+
+ for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
+ struct atmel_hlcdc_layer *layer = dc->layers[i];
+
+ if (!(ATMEL_HLCDC_LAYER_STATUS(i) & status) || !layer)
+ continue;
+
+ atmel_hlcdc_layer_irq(layer);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static struct drm_framebuffer *atmel_hlcdc_fb_create(struct drm_device *dev,
+ struct drm_file *file_priv, struct drm_mode_fb_cmd2 *mode_cmd)
+{
+ return drm_fb_cma_create(dev, file_priv, mode_cmd);
+}
+
+static void atmel_hlcdc_fb_output_poll_changed(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+ if (dc->fbdev) {
+ drm_fbdev_cma_hotplug_event(dc->fbdev);
+ } else {
+ dc->fbdev = drm_fbdev_cma_init(dev, 24,
+ dev->mode_config.num_crtc,
+ dev->mode_config.num_connector);
+ if (IS_ERR(dc->fbdev))
+ dc->fbdev = NULL;
+ }
+}
+
+static const struct drm_mode_config_funcs mode_config_funcs = {
+ .fb_create = atmel_hlcdc_fb_create,
+ .output_poll_changed = atmel_hlcdc_fb_output_poll_changed,
+};
+
+static int atmel_hlcdc_dc_modeset_init(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ struct atmel_hlcdc_planes *planes;
+ int ret;
+ int i;
+
+ drm_mode_config_init(dev);
+
+ ret = atmel_hlcdc_create_outputs(dev);
+ if (ret) {
+ dev_err(dev->dev, "failed to create panel: %d\n", ret);
+ return ret;
+ }
+
+ planes = atmel_hlcdc_create_planes(dev);
+ if (IS_ERR(planes)) {
+ dev_err(dev->dev, "failed to create planes\n");
+ return PTR_ERR(planes);
+ }
+
+ dc->planes = planes;
+
+ dc->layers[planes->primary->layer.desc->id] =
+ &planes->primary->layer;
+
+ if (planes->cursor)
+ dc->layers[planes->cursor->layer.desc->id] =
+ &planes->cursor->layer;
+
+ for (i = 0; i < planes->noverlays; i++)
+ dc->layers[planes->overlays[i]->layer.desc->id] =
+ &planes->overlays[i]->layer;
+
+ ret = atmel_hlcdc_crtc_create(dev);
+ if (ret) {
+ dev_err(dev->dev, "failed to create crtc\n");
+ return ret;
+ }
+
+ dev->mode_config.min_width = dc->desc->min_width;
+ dev->mode_config.min_height = dc->desc->min_height;
+ dev->mode_config.max_width = dc->desc->max_width;
+ dev->mode_config.max_height = dc->desc->max_height;
+ dev->mode_config.funcs = &mode_config_funcs;
+
+ return 0;
+}
+
+static int atmel_hlcdc_dc_load(struct drm_device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev->dev);
+ const struct of_device_id *match;
+ struct atmel_hlcdc_dc *dc;
+ int ret;
+
+ match = of_match_node(atmel_hlcdc_of_match, dev->dev->parent->of_node);
+ if (!match) {
+ dev_err(&pdev->dev, "invalid compatible string\n");
+ return -ENODEV;
+ }
+
+ if (!match->data) {
+ dev_err(&pdev->dev, "invalid hlcdc description\n");
+ return -EINVAL;
+ }
+
+ dc = devm_kzalloc(dev->dev, sizeof(*dc), GFP_KERNEL);
+ if (!dc)
+ return -ENOMEM;
+
+ dc->wq = alloc_ordered_workqueue("atmel-hlcdc-dc", 0);
+ if (!dc->wq)
+ return -ENOMEM;
+
+ dc->desc = match->data;
+ dc->hlcdc = dev_get_drvdata(dev->dev->parent);
+ dev->dev_private = dc;
+
+ ret = clk_prepare_enable(dc->hlcdc->periph_clk);
+ if (ret) {
+ dev_err(dev->dev, "failed to enable periph_clk\n");
+ goto err_destroy_wq;
+ }
+
+ pm_runtime_enable(dev->dev);
+
+ ret = atmel_hlcdc_dc_modeset_init(dev);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to initialize mode setting\n");
+ goto err_periph_clk_disable;
+ }
+
+ ret = drm_vblank_init(dev, 1);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to initialize vblank\n");
+ goto err_periph_clk_disable;
+ }
+
+ pm_runtime_get_sync(dev->dev);
+ ret = drm_irq_install(dev, dc->hlcdc->irq);
+ pm_runtime_put_sync(dev->dev);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to install IRQ handler\n");
+ goto err_periph_clk_disable;
+ }
+
+ platform_set_drvdata(pdev, dev);
+
+ drm_kms_helper_poll_init(dev);
+
+ /* force connectors detection */
+ drm_helper_hpd_irq_event(dev);
+
+ return 0;
+
+err_periph_clk_disable:
+ pm_runtime_disable(dev->dev);
+ clk_disable_unprepare(dc->hlcdc->periph_clk);
+
+err_destroy_wq:
+ destroy_workqueue(dc->wq);
+
+ return ret;
+}
+
+static void atmel_hlcdc_dc_unload(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+ if (dc->fbdev)
+ drm_fbdev_cma_fini(dc->fbdev);
+ flush_workqueue(dc->wq);
+ drm_kms_helper_poll_fini(dev);
+ drm_mode_config_cleanup(dev);
+ drm_vblank_cleanup(dev);
+
+ pm_runtime_get_sync(dev->dev);
+ drm_irq_uninstall(dev);
+ pm_runtime_put_sync(dev->dev);
+
+ dev->dev_private = NULL;
+
+ pm_runtime_disable(dev->dev);
+ clk_disable_unprepare(dc->hlcdc->periph_clk);
+ destroy_workqueue(dc->wq);
+}
+
+static int atmel_hlcdc_dc_connector_plug_all(struct drm_device *dev)
+{
+ struct drm_connector *connector, *failed;
+ int ret;
+
+ mutex_lock(&dev->mode_config.mutex);
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ ret = drm_connector_register(connector);
+ if (ret) {
+ failed = connector;
+ goto err;
+ }
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+ return 0;
+
+err:
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (failed == connector)
+ break;
+
+ drm_connector_unregister(connector);
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+
+ return ret;
+}
+
+static void atmel_hlcdc_dc_connector_unplug_all(struct drm_device *dev)
+{
+ mutex_lock(&dev->mode_config.mutex);
+ drm_connector_unplug_all(dev);
+ mutex_unlock(&dev->mode_config.mutex);
+}
+
+static void atmel_hlcdc_dc_preclose(struct drm_device *dev,
+ struct drm_file *file)
+{
+ struct drm_crtc *crtc;
+
+ list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
+ atmel_hlcdc_crtc_cancel_page_flip(crtc, file);
+}
+
+static void atmel_hlcdc_dc_lastclose(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+ drm_fbdev_cma_restore_mode(dc->fbdev);
+}
+
+static int atmel_hlcdc_dc_irq_postinstall(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ unsigned int cfg = 0;
+ int i;
+
+ /* Enable interrupts on activated layers */
+ for (i = 0; i < ATMEL_HLCDC_MAX_LAYERS; i++) {
+ if (dc->layers[i])
+ cfg |= ATMEL_HLCDC_LAYER_STATUS(i);
+ }
+
+ regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, cfg);
+
+ return 0;
+}
+
+static void atmel_hlcdc_dc_irq_uninstall(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ unsigned int isr;
+
+ regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, 0xffffffff);
+ regmap_read(dc->hlcdc->regmap, ATMEL_HLCDC_ISR, &isr);
+}
+
+static int atmel_hlcdc_dc_enable_vblank(struct drm_device *dev, int crtc)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+ /* Enable SOF (Start Of Frame) interrupt for vblank counting */
+ regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IER, ATMEL_HLCDC_SOF);
+
+ return 0;
+}
+
+static void atmel_hlcdc_dc_disable_vblank(struct drm_device *dev, int crtc)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+
+ regmap_write(dc->hlcdc->regmap, ATMEL_HLCDC_IDR, ATMEL_HLCDC_SOF);
+}
+
+static const struct file_operations fops = {
+ .owner = THIS_MODULE,
+ .open = drm_open,
+ .release = drm_release,
+ .unlocked_ioctl = drm_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = drm_compat_ioctl,
+#endif
+ .poll = drm_poll,
+ .read = drm_read,
+ .llseek = no_llseek,
+ .mmap = drm_gem_cma_mmap,
+};
+
+static struct drm_driver atmel_hlcdc_dc_driver = {
+ .driver_features = DRIVER_HAVE_IRQ | DRIVER_GEM | DRIVER_MODESET,
+ .preclose = atmel_hlcdc_dc_preclose,
+ .lastclose = atmel_hlcdc_dc_lastclose,
+ .irq_handler = atmel_hlcdc_dc_irq_handler,
+ .irq_preinstall = atmel_hlcdc_dc_irq_uninstall,
+ .irq_postinstall = atmel_hlcdc_dc_irq_postinstall,
+ .irq_uninstall = atmel_hlcdc_dc_irq_uninstall,
+ .get_vblank_counter = drm_vblank_count,
+ .enable_vblank = atmel_hlcdc_dc_enable_vblank,
+ .disable_vblank = atmel_hlcdc_dc_disable_vblank,
+ .gem_free_object = drm_gem_cma_free_object,
+ .gem_vm_ops = &drm_gem_cma_vm_ops,
+ .dumb_create = drm_gem_cma_dumb_create,
+ .dumb_map_offset = drm_gem_cma_dumb_map_offset,
+ .dumb_destroy = drm_gem_dumb_destroy,
+ .fops = &fops,
+ .name = "atmel-hlcdc",
+ .desc = "Atmel HLCD Controller DRM",
+ .date = "20141504",
+ .major = 1,
+ .minor = 0,
+};
+
+static int atmel_hlcdc_dc_drm_probe(struct platform_device *pdev)
+{
+ struct drm_device *ddev;
+ int ret;
+
+ ddev = drm_dev_alloc(&atmel_hlcdc_dc_driver, &pdev->dev);
+ if (!ddev)
+ return -ENOMEM;
+
+ ret = drm_dev_set_unique(ddev, dev_name(ddev->dev));
+ if (ret)
+ goto err_unref;
+
+ ret = atmel_hlcdc_dc_load(ddev);
+ if (ret)
+ goto err_unref;
+
+ ret = drm_dev_register(ddev, 0);
+ if (ret)
+ goto err_unload;
+
+ ret = atmel_hlcdc_dc_connector_plug_all(ddev);
+ if (ret)
+ goto err_unregister;
+
+ return 0;
+
+err_unregister:
+ drm_dev_unregister(ddev);
+
+err_unload:
+ atmel_hlcdc_dc_unload(ddev);
+
+err_unref:
+ drm_dev_unref(ddev);
+
+ return ret;
+}
+
+static int atmel_hlcdc_dc_drm_remove(struct platform_device *pdev)
+{
+ struct drm_device *ddev = platform_get_drvdata(pdev);
+
+ atmel_hlcdc_dc_connector_unplug_all(ddev);
+ drm_dev_unregister(ddev);
+ atmel_hlcdc_dc_unload(ddev);
+ drm_dev_unref(ddev);
+
+ return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_dc_of_match[] = {
+ { .compatible = "atmel,hlcdc-display-controller" },
+ { },
+};
+
+static struct platform_driver atmel_hlcdc_dc_platform_driver = {
+ .probe = atmel_hlcdc_dc_drm_probe,
+ .remove = atmel_hlcdc_dc_drm_remove,
+ .driver = {
+ .name = "atmel-hlcdc-display-controller",
+ .of_match_table = atmel_hlcdc_dc_of_match,
+ },
+};
+module_platform_driver(atmel_hlcdc_dc_platform_driver);
+
+MODULE_AUTHOR("Jean-Jacques Hiblot <jjhiblot@traphandler.com>");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC Display Controller DRM Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:atmel-hlcdc-dc");
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
new file mode 100644
index 000000000000..7bc96af3397a
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_dc.h
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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 DRM_ATMEL_HLCDC_H
+#define DRM_ATMEL_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/irqdomain.h>
+#include <linux/pwm.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_fb_cma_helper.h>
+#include <drm/drm_gem_cma_helper.h>
+#include <drm/drm_panel.h>
+#include <drm/drmP.h>
+
+#include "atmel_hlcdc_layer.h"
+
+#define ATMEL_HLCDC_MAX_LAYERS 5
+
+/**
+ * Atmel HLCDC Display Controller description structure.
+ *
+ * This structure describe the HLCDC IP capabilities and depends on the
+ * HLCDC IP version (or Atmel SoC family).
+ *
+ * @min_width: minimum width supported by the Display Controller
+ * @min_height: minimum height supported by the Display Controller
+ * @max_width: maximum width supported by the Display Controller
+ * @max_height: maximum height supported by the Display Controller
+ * @layers: a layer description table describing available layers
+ * @nlayers: layer description table size
+ */
+struct atmel_hlcdc_dc_desc {
+ int min_width;
+ int min_height;
+ int max_width;
+ int max_height;
+ const struct atmel_hlcdc_layer_desc *layers;
+ int nlayers;
+};
+
+/**
+ * Atmel HLCDC Plane properties.
+ *
+ * This structure stores plane property definitions.
+ *
+ * @alpha: alpha blending (or transparency) property
+ * @rotation: rotation property
+ */
+struct atmel_hlcdc_plane_properties {
+ struct drm_property *alpha;
+ struct drm_property *rotation;
+};
+
+/**
+ * Atmel HLCDC Plane.
+ *
+ * @base: base DRM plane structure
+ * @layer: HLCDC layer structure
+ * @properties: pointer to the property definitions structure
+ * @rotation: current rotation status
+ */
+struct atmel_hlcdc_plane {
+ struct drm_plane base;
+ struct atmel_hlcdc_layer layer;
+ struct atmel_hlcdc_plane_properties *properties;
+ unsigned int rotation;
+};
+
+static inline struct atmel_hlcdc_plane *
+drm_plane_to_atmel_hlcdc_plane(struct drm_plane *p)
+{
+ return container_of(p, struct atmel_hlcdc_plane, base);
+}
+
+static inline struct atmel_hlcdc_plane *
+atmel_hlcdc_layer_to_plane(struct atmel_hlcdc_layer *l)
+{
+ return container_of(l, struct atmel_hlcdc_plane, layer);
+}
+
+/**
+ * Atmel HLCDC Plane update request structure.
+ *
+ * @crtc_x: x position of the plane relative to the CRTC
+ * @crtc_y: y position of the plane relative to the CRTC
+ * @crtc_w: visible width of the plane
+ * @crtc_h: visible height of the plane
+ * @src_x: x buffer position
+ * @src_y: y buffer position
+ * @src_w: buffer width
+ * @src_h: buffer height
+ * @fb: framebuffer object object
+ * @bpp: bytes per pixel deduced from pixel_format
+ * @offsets: offsets to apply to the GEM buffers
+ * @xstride: value to add to the pixel pointer between each line
+ * @pstride: value to add to the pixel pointer between each pixel
+ * @nplanes: number of planes (deduced from pixel_format)
+ */
+struct atmel_hlcdc_plane_update_req {
+ int crtc_x;
+ int crtc_y;
+ unsigned int crtc_w;
+ unsigned int crtc_h;
+ uint32_t src_x;
+ uint32_t src_y;
+ uint32_t src_w;
+ uint32_t src_h;
+ struct drm_framebuffer *fb;
+
+ /* These fields are private and should not be touched */
+ int bpp[ATMEL_HLCDC_MAX_PLANES];
+ unsigned int offsets[ATMEL_HLCDC_MAX_PLANES];
+ int xstride[ATMEL_HLCDC_MAX_PLANES];
+ int pstride[ATMEL_HLCDC_MAX_PLANES];
+ int nplanes;
+};
+
+/**
+ * Atmel HLCDC Planes.
+ *
+ * This structure stores the instantiated HLCDC Planes and can be accessed by
+ * the HLCDC Display Controller or the HLCDC CRTC.
+ *
+ * @primary: primary plane
+ * @cursor: hardware cursor plane
+ * @overlays: overlay plane table
+ * @noverlays: number of overlay planes
+ */
+struct atmel_hlcdc_planes {
+ struct atmel_hlcdc_plane *primary;
+ struct atmel_hlcdc_plane *cursor;
+ struct atmel_hlcdc_plane **overlays;
+ int noverlays;
+};
+
+/**
+ * Atmel HLCDC Display Controller.
+ *
+ * @desc: HLCDC Display Controller description
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @fbdev: framebuffer device attached to the Display Controller
+ * @crtc: CRTC provided by the display controller
+ * @planes: instantiated planes
+ * @layers: active HLCDC layer
+ * @wq: display controller workqueue
+ */
+struct atmel_hlcdc_dc {
+ const struct atmel_hlcdc_dc_desc *desc;
+ struct atmel_hlcdc *hlcdc;
+ struct drm_fbdev_cma *fbdev;
+ struct drm_crtc *crtc;
+ struct atmel_hlcdc_planes *planes;
+ struct atmel_hlcdc_layer *layers[ATMEL_HLCDC_MAX_LAYERS];
+ struct workqueue_struct *wq;
+};
+
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats;
+extern struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats;
+
+int atmel_hlcdc_dc_mode_valid(struct atmel_hlcdc_dc *dc,
+ struct drm_display_mode *mode);
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev);
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+ struct atmel_hlcdc_plane_update_req *req,
+ const struct drm_display_mode *mode);
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+ struct atmel_hlcdc_plane_update_req *req);
+
+int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w,
+ unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h,
+ const struct drm_display_mode *mode);
+
+void atmel_hlcdc_crtc_irq(struct drm_crtc *c);
+
+void atmel_hlcdc_crtc_cancel_page_flip(struct drm_crtc *crtc,
+ struct drm_file *file);
+
+int atmel_hlcdc_crtc_create(struct drm_device *dev);
+
+int atmel_hlcdc_create_outputs(struct drm_device *dev);
+
+#endif /* DRM_ATMEL_HLCDC_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
new file mode 100644
index 000000000000..e79bd9ba474b
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.c
@@ -0,0 +1,668 @@
+/*
+ * 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/dma-mapping.h>
+#include <linux/interrupt.h>
+
+#include "atmel_hlcdc_dc.h"
+
+static void
+atmel_hlcdc_layer_fb_flip_release(struct drm_flip_work *work, void *val)
+{
+ struct atmel_hlcdc_layer_fb_flip *flip = val;
+
+ if (flip->fb)
+ drm_framebuffer_unreference(flip->fb);
+ kfree(flip);
+}
+
+static void
+atmel_hlcdc_layer_fb_flip_destroy(struct atmel_hlcdc_layer_fb_flip *flip)
+{
+ if (flip->fb)
+ drm_framebuffer_unreference(flip->fb);
+ kfree(flip->task);
+ kfree(flip);
+}
+
+static void
+atmel_hlcdc_layer_fb_flip_release_queue(struct atmel_hlcdc_layer *layer,
+ struct atmel_hlcdc_layer_fb_flip *flip)
+{
+ int i;
+
+ if (!flip)
+ return;
+
+ for (i = 0; i < layer->max_planes; i++) {
+ if (!flip->dscrs[i])
+ break;
+
+ flip->dscrs[i]->status = 0;
+ flip->dscrs[i] = NULL;
+ }
+
+ drm_flip_work_queue_task(&layer->gc, flip->task);
+ drm_flip_work_commit(&layer->gc, layer->wq);
+}
+
+static void atmel_hlcdc_layer_update_reset(struct atmel_hlcdc_layer *layer,
+ int id)
+{
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct atmel_hlcdc_layer_update_slot *slot;
+
+ if (id < 0 || id > 1)
+ return;
+
+ slot = &upd->slots[id];
+ bitmap_clear(slot->updated_configs, 0, layer->desc->nconfigs);
+ memset(slot->configs, 0,
+ sizeof(*slot->configs) * layer->desc->nconfigs);
+
+ if (slot->fb_flip) {
+ atmel_hlcdc_layer_fb_flip_release_queue(layer, slot->fb_flip);
+ slot->fb_flip = NULL;
+ }
+}
+
+static void atmel_hlcdc_layer_update_apply(struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct regmap *regmap = layer->hlcdc->regmap;
+ struct atmel_hlcdc_layer_update_slot *slot;
+ struct atmel_hlcdc_layer_fb_flip *fb_flip;
+ struct atmel_hlcdc_dma_channel_dscr *dscr;
+ unsigned int cfg;
+ u32 action = 0;
+ int i = 0;
+
+ if (upd->pending < 0 || upd->pending > 1)
+ return;
+
+ slot = &upd->slots[upd->pending];
+
+ for_each_set_bit(cfg, slot->updated_configs, layer->desc->nconfigs) {
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_CFG(layer, cfg),
+ slot->configs[cfg]);
+ action |= ATMEL_HLCDC_LAYER_UPDATE;
+ }
+
+ fb_flip = slot->fb_flip;
+
+ if (!fb_flip->fb)
+ goto apply;
+
+ if (dma->status == ATMEL_HLCDC_LAYER_DISABLED) {
+ for (i = 0; i < fb_flip->ngems; i++) {
+ dscr = fb_flip->dscrs[i];
+ dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
+ ATMEL_HLCDC_LAYER_DMA_IRQ |
+ ATMEL_HLCDC_LAYER_ADD_IRQ |
+ ATMEL_HLCDC_LAYER_DONE_IRQ;
+
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_PLANE_ADDR(i),
+ dscr->addr);
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_PLANE_CTRL(i),
+ dscr->ctrl);
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_PLANE_NEXT(i),
+ dscr->next);
+ }
+
+ action |= ATMEL_HLCDC_LAYER_DMA_CHAN;
+ dma->status = ATMEL_HLCDC_LAYER_ENABLED;
+ } else {
+ for (i = 0; i < fb_flip->ngems; i++) {
+ dscr = fb_flip->dscrs[i];
+ dscr->ctrl = ATMEL_HLCDC_LAYER_DFETCH |
+ ATMEL_HLCDC_LAYER_DMA_IRQ |
+ ATMEL_HLCDC_LAYER_DSCR_IRQ |
+ ATMEL_HLCDC_LAYER_DONE_IRQ;
+
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_PLANE_HEAD(i),
+ dscr->next);
+ }
+
+ action |= ATMEL_HLCDC_LAYER_A2Q;
+ }
+
+ /* Release unneeded descriptors */
+ for (i = fb_flip->ngems; i < layer->max_planes; i++) {
+ fb_flip->dscrs[i]->status = 0;
+ fb_flip->dscrs[i] = NULL;
+ }
+
+ dma->queue = fb_flip;
+ slot->fb_flip = NULL;
+
+apply:
+ if (action)
+ regmap_write(regmap,
+ desc->regs_offset + ATMEL_HLCDC_LAYER_CHER,
+ action);
+
+ atmel_hlcdc_layer_update_reset(layer, upd->pending);
+
+ upd->pending = -1;
+}
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+ struct regmap *regmap = layer->hlcdc->regmap;
+ struct atmel_hlcdc_layer_fb_flip *flip;
+ unsigned long flags;
+ unsigned int isr, imr;
+ unsigned int status;
+ unsigned int plane_status;
+ u32 flip_status;
+
+ int i;
+
+ regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IMR, &imr);
+ regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
+ status = imr & isr;
+ if (!status)
+ return;
+
+ spin_lock_irqsave(&layer->lock, flags);
+
+ flip = dma->queue ? dma->queue : dma->cur;
+
+ if (!flip) {
+ spin_unlock_irqrestore(&layer->lock, flags);
+ return;
+ }
+
+ /*
+ * Set LOADED and DONE flags: they'll be cleared if at least one
+ * memory plane is not LOADED or DONE.
+ */
+ flip_status = ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED |
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
+ for (i = 0; i < flip->ngems; i++) {
+ plane_status = (status >> (8 * i));
+
+ if (plane_status &
+ (ATMEL_HLCDC_LAYER_ADD_IRQ |
+ ATMEL_HLCDC_LAYER_DSCR_IRQ) &
+ ~flip->dscrs[i]->ctrl) {
+ flip->dscrs[i]->status |=
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
+ flip->dscrs[i]->ctrl |=
+ ATMEL_HLCDC_LAYER_ADD_IRQ |
+ ATMEL_HLCDC_LAYER_DSCR_IRQ;
+ }
+
+ if (plane_status &
+ ATMEL_HLCDC_LAYER_DONE_IRQ &
+ ~flip->dscrs[i]->ctrl) {
+ flip->dscrs[i]->status |=
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
+ flip->dscrs[i]->ctrl |=
+ ATMEL_HLCDC_LAYER_DONE_IRQ;
+ }
+
+ if (plane_status & ATMEL_HLCDC_LAYER_OVR_IRQ)
+ flip->dscrs[i]->status |=
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
+
+ /*
+ * Clear LOADED and DONE flags if the memory plane is either
+ * not LOADED or not DONE.
+ */
+ if (!(flip->dscrs[i]->status &
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED))
+ flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED;
+
+ if (!(flip->dscrs[i]->status &
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE))
+ flip_status &= ~ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE;
+
+ /*
+ * An overrun on one memory plane impact the whole framebuffer
+ * transfer, hence we set the OVERRUN flag as soon as there's
+ * one memory plane reporting such an overrun.
+ */
+ flip_status |= flip->dscrs[i]->status &
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN;
+ }
+
+ /* Get changed bits */
+ flip_status ^= flip->status;
+ flip->status |= flip_status;
+
+ if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED) {
+ atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
+ dma->cur = dma->queue;
+ dma->queue = NULL;
+ }
+
+ if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE) {
+ atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
+ dma->cur = NULL;
+ }
+
+ if (flip_status & ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN) {
+ regmap_write(regmap,
+ desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+ ATMEL_HLCDC_LAYER_RST);
+ if (dma->queue)
+ atmel_hlcdc_layer_fb_flip_release_queue(layer,
+ dma->queue);
+
+ if (dma->cur)
+ atmel_hlcdc_layer_fb_flip_release_queue(layer,
+ dma->cur);
+
+ dma->cur = NULL;
+ dma->queue = NULL;
+ }
+
+ if (!dma->queue) {
+ atmel_hlcdc_layer_update_apply(layer);
+
+ if (!dma->cur)
+ dma->status = ATMEL_HLCDC_LAYER_DISABLED;
+ }
+
+ spin_unlock_irqrestore(&layer->lock, flags);
+}
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct regmap *regmap = layer->hlcdc->regmap;
+ const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+ unsigned long flags;
+ unsigned int isr;
+
+ spin_lock_irqsave(&layer->lock, flags);
+
+ /* Disable the layer */
+ regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+ ATMEL_HLCDC_LAYER_RST | ATMEL_HLCDC_LAYER_A2Q |
+ ATMEL_HLCDC_LAYER_UPDATE);
+
+ /* Clear all pending interrupts */
+ regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR, &isr);
+
+ /* Discard current and queued framebuffer transfers. */
+ if (dma->cur) {
+ atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->cur);
+ dma->cur = NULL;
+ }
+
+ if (dma->queue) {
+ atmel_hlcdc_layer_fb_flip_release_queue(layer, dma->queue);
+ dma->queue = NULL;
+ }
+
+ /*
+ * Then discard the pending update request (if any) to prevent
+ * DMA irq handler from restarting the DMA channel after it has
+ * been disabled.
+ */
+ if (upd->pending >= 0) {
+ atmel_hlcdc_layer_update_reset(layer, upd->pending);
+ upd->pending = -1;
+ }
+
+ dma->status = ATMEL_HLCDC_LAYER_DISABLED;
+
+ spin_unlock_irqrestore(&layer->lock, flags);
+
+ return 0;
+}
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct regmap *regmap = layer->hlcdc->regmap;
+ struct atmel_hlcdc_layer_fb_flip *fb_flip;
+ struct atmel_hlcdc_layer_update_slot *slot;
+ unsigned long flags;
+ int i, j = 0;
+
+ fb_flip = kzalloc(sizeof(*fb_flip), GFP_KERNEL);
+ if (!fb_flip)
+ return -ENOMEM;
+
+ fb_flip->task = drm_flip_work_allocate_task(fb_flip, GFP_KERNEL);
+ if (!fb_flip->task) {
+ kfree(fb_flip);
+ return -ENOMEM;
+ }
+
+ spin_lock_irqsave(&layer->lock, flags);
+
+ upd->next = upd->pending ? 0 : 1;
+
+ slot = &upd->slots[upd->next];
+
+ for (i = 0; i < layer->max_planes * 4; i++) {
+ if (!dma->dscrs[i].status) {
+ fb_flip->dscrs[j++] = &dma->dscrs[i];
+ dma->dscrs[i].status =
+ ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED;
+ if (j == layer->max_planes)
+ break;
+ }
+ }
+
+ if (j < layer->max_planes) {
+ for (i = 0; i < j; i++)
+ fb_flip->dscrs[i]->status = 0;
+ }
+
+ if (j < layer->max_planes) {
+ spin_unlock_irqrestore(&layer->lock, flags);
+ atmel_hlcdc_layer_fb_flip_destroy(fb_flip);
+ return -EBUSY;
+ }
+
+ slot->fb_flip = fb_flip;
+
+ if (upd->pending >= 0) {
+ memcpy(slot->configs,
+ upd->slots[upd->pending].configs,
+ layer->desc->nconfigs * sizeof(u32));
+ memcpy(slot->updated_configs,
+ upd->slots[upd->pending].updated_configs,
+ DIV_ROUND_UP(layer->desc->nconfigs,
+ BITS_PER_BYTE * sizeof(unsigned long)) *
+ sizeof(unsigned long));
+ slot->fb_flip->fb = upd->slots[upd->pending].fb_flip->fb;
+ if (upd->slots[upd->pending].fb_flip->fb) {
+ slot->fb_flip->fb =
+ upd->slots[upd->pending].fb_flip->fb;
+ slot->fb_flip->ngems =
+ upd->slots[upd->pending].fb_flip->ngems;
+ drm_framebuffer_reference(slot->fb_flip->fb);
+ }
+ } else {
+ regmap_bulk_read(regmap,
+ layer->desc->regs_offset +
+ ATMEL_HLCDC_LAYER_CFG(layer, 0),
+ upd->slots[upd->next].configs,
+ layer->desc->nconfigs);
+ }
+
+ spin_unlock_irqrestore(&layer->lock, flags);
+
+ return 0;
+}
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+
+ atmel_hlcdc_layer_update_reset(layer, upd->next);
+ upd->next = -1;
+}
+
+void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
+ struct drm_framebuffer *fb,
+ unsigned int *offsets)
+{
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct atmel_hlcdc_layer_fb_flip *fb_flip;
+ struct atmel_hlcdc_layer_update_slot *slot;
+ struct atmel_hlcdc_dma_channel_dscr *dscr;
+ struct drm_framebuffer *old_fb;
+ int nplanes = 0;
+ int i;
+
+ if (upd->next < 0 || upd->next > 1)
+ return;
+
+ if (fb)
+ nplanes = drm_format_num_planes(fb->pixel_format);
+
+ if (nplanes > layer->max_planes)
+ return;
+
+ slot = &upd->slots[upd->next];
+
+ fb_flip = slot->fb_flip;
+ old_fb = slot->fb_flip->fb;
+
+ for (i = 0; i < nplanes; i++) {
+ struct drm_gem_cma_object *gem;
+
+ dscr = slot->fb_flip->dscrs[i];
+ gem = drm_fb_cma_get_gem_obj(fb, i);
+ dscr->addr = gem->paddr + offsets[i];
+ }
+
+ fb_flip->ngems = nplanes;
+ fb_flip->fb = fb;
+
+ if (fb)
+ drm_framebuffer_reference(fb);
+
+ if (old_fb)
+ drm_framebuffer_unreference(old_fb);
+}
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+ u32 mask, u32 val)
+{
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct atmel_hlcdc_layer_update_slot *slot;
+
+ if (upd->next < 0 || upd->next > 1)
+ return;
+
+ if (cfg >= layer->desc->nconfigs)
+ return;
+
+ slot = &upd->slots[upd->next];
+ slot->configs[cfg] &= ~mask;
+ slot->configs[cfg] |= (val & mask);
+ set_bit(cfg, slot->updated_configs);
+}
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ struct atmel_hlcdc_layer_update_slot *slot;
+ unsigned long flags;
+
+ if (upd->next < 0 || upd->next > 1)
+ return;
+
+ slot = &upd->slots[upd->next];
+
+ spin_lock_irqsave(&layer->lock, flags);
+
+ /*
+ * Release pending update request and replace it by the new one.
+ */
+ if (upd->pending >= 0)
+ atmel_hlcdc_layer_update_reset(layer, upd->pending);
+
+ upd->pending = upd->next;
+ upd->next = -1;
+
+ if (!dma->queue)
+ atmel_hlcdc_layer_update_apply(layer);
+
+ spin_unlock_irqrestore(&layer->lock, flags);
+
+
+ upd->next = -1;
+}
+
+static int atmel_hlcdc_layer_dma_init(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ dma_addr_t dma_addr;
+ int i;
+
+ dma->dscrs = dma_alloc_coherent(dev->dev,
+ layer->max_planes * 4 *
+ sizeof(*dma->dscrs),
+ &dma_addr, GFP_KERNEL);
+ if (!dma->dscrs)
+ return -ENOMEM;
+
+ for (i = 0; i < layer->max_planes * 4; i++) {
+ struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+ dscr->next = dma_addr + (i * sizeof(*dscr));
+ }
+
+ return 0;
+}
+
+static void atmel_hlcdc_layer_dma_cleanup(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer)
+{
+ struct atmel_hlcdc_layer_dma_channel *dma = &layer->dma;
+ int i;
+
+ for (i = 0; i < layer->max_planes * 4; i++) {
+ struct atmel_hlcdc_dma_channel_dscr *dscr = &dma->dscrs[i];
+
+ dscr->status = 0;
+ }
+
+ dma_free_coherent(dev->dev, layer->max_planes * 4 *
+ sizeof(*dma->dscrs), dma->dscrs,
+ dma->dscrs[0].next);
+}
+
+static int atmel_hlcdc_layer_update_init(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer,
+ const struct atmel_hlcdc_layer_desc *desc)
+{
+ struct atmel_hlcdc_layer_update *upd = &layer->update;
+ int updated_size;
+ void *buffer;
+ int i;
+
+ updated_size = DIV_ROUND_UP(desc->nconfigs,
+ BITS_PER_BYTE *
+ sizeof(unsigned long));
+
+ buffer = devm_kzalloc(dev->dev,
+ ((desc->nconfigs * sizeof(u32)) +
+ (updated_size * sizeof(unsigned long))) * 2,
+ GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ for (i = 0; i < 2; i++) {
+ upd->slots[i].updated_configs = buffer;
+ buffer += updated_size * sizeof(unsigned long);
+ upd->slots[i].configs = buffer;
+ buffer += desc->nconfigs * sizeof(u32);
+ }
+
+ upd->pending = -1;
+ upd->next = -1;
+
+ return 0;
+}
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer,
+ const struct atmel_hlcdc_layer_desc *desc)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ struct regmap *regmap = dc->hlcdc->regmap;
+ unsigned int tmp;
+ int ret;
+ int i;
+
+ layer->hlcdc = dc->hlcdc;
+ layer->wq = dc->wq;
+ layer->desc = desc;
+
+ regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+ ATMEL_HLCDC_LAYER_RST);
+ for (i = 0; i < desc->formats->nformats; i++) {
+ int nplanes = drm_format_num_planes(desc->formats->formats[i]);
+
+ if (nplanes > layer->max_planes)
+ layer->max_planes = nplanes;
+ }
+
+ spin_lock_init(&layer->lock);
+ drm_flip_work_init(&layer->gc, desc->name,
+ atmel_hlcdc_layer_fb_flip_release);
+ ret = atmel_hlcdc_layer_dma_init(dev, layer);
+ if (ret)
+ return ret;
+
+ ret = atmel_hlcdc_layer_update_init(dev, layer, desc);
+ if (ret)
+ return ret;
+
+ /* Flush Status Register */
+ regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+ 0xffffffff);
+ regmap_read(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_ISR,
+ &tmp);
+
+ tmp = 0;
+ for (i = 0; i < layer->max_planes; i++)
+ tmp |= (ATMEL_HLCDC_LAYER_DMA_IRQ |
+ ATMEL_HLCDC_LAYER_DSCR_IRQ |
+ ATMEL_HLCDC_LAYER_ADD_IRQ |
+ ATMEL_HLCDC_LAYER_DONE_IRQ |
+ ATMEL_HLCDC_LAYER_OVR_IRQ) << (8 * i);
+
+ regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IER, tmp);
+
+ return 0;
+}
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer)
+{
+ const struct atmel_hlcdc_layer_desc *desc = layer->desc;
+ struct regmap *regmap = layer->hlcdc->regmap;
+
+ regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_IDR,
+ 0xffffffff);
+ regmap_write(regmap, desc->regs_offset + ATMEL_HLCDC_LAYER_CHDR,
+ ATMEL_HLCDC_LAYER_RST);
+
+ atmel_hlcdc_layer_dma_cleanup(dev, layer);
+ drm_flip_work_cleanup(&layer->gc);
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
new file mode 100644
index 000000000000..27e56c0862ec
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_layer.h
@@ -0,0 +1,398 @@
+/*
+ * 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 DRM_ATMEL_HLCDC_LAYER_H
+#define DRM_ATMEL_HLCDC_LAYER_H
+
+#include <linux/mfd/atmel-hlcdc.h>
+
+#include <drm/drm_crtc.h>
+#include <drm/drm_flip_work.h>
+#include <drm/drmP.h>
+
+#define ATMEL_HLCDC_LAYER_CHER 0x0
+#define ATMEL_HLCDC_LAYER_CHDR 0x4
+#define ATMEL_HLCDC_LAYER_CHSR 0x8
+#define ATMEL_HLCDC_LAYER_DMA_CHAN BIT(0)
+#define ATMEL_HLCDC_LAYER_UPDATE BIT(1)
+#define ATMEL_HLCDC_LAYER_A2Q BIT(2)
+#define ATMEL_HLCDC_LAYER_RST BIT(8)
+
+#define ATMEL_HLCDC_LAYER_IER 0xc
+#define ATMEL_HLCDC_LAYER_IDR 0x10
+#define ATMEL_HLCDC_LAYER_IMR 0x14
+#define ATMEL_HLCDC_LAYER_ISR 0x18
+#define ATMEL_HLCDC_LAYER_DFETCH BIT(0)
+#define ATMEL_HLCDC_LAYER_LFETCH BIT(1)
+#define ATMEL_HLCDC_LAYER_DMA_IRQ BIT(2)
+#define ATMEL_HLCDC_LAYER_DSCR_IRQ BIT(3)
+#define ATMEL_HLCDC_LAYER_ADD_IRQ BIT(4)
+#define ATMEL_HLCDC_LAYER_DONE_IRQ BIT(5)
+#define ATMEL_HLCDC_LAYER_OVR_IRQ BIT(6)
+
+#define ATMEL_HLCDC_LAYER_PLANE_HEAD(n) (((n) * 0x10) + 0x1c)
+#define ATMEL_HLCDC_LAYER_PLANE_ADDR(n) (((n) * 0x10) + 0x20)
+#define ATMEL_HLCDC_LAYER_PLANE_CTRL(n) (((n) * 0x10) + 0x24)
+#define ATMEL_HLCDC_LAYER_PLANE_NEXT(n) (((n) * 0x10) + 0x28)
+#define ATMEL_HLCDC_LAYER_CFG(p, c) (((c) * 4) + ((p)->max_planes * 0x10) + 0x1c)
+
+#define ATMEL_HLCDC_LAYER_DMA_CFG_ID 0
+#define ATMEL_HLCDC_LAYER_DMA_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_DMA_CFG_ID)
+#define ATMEL_HLCDC_LAYER_DMA_SIF BIT(0)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_MASK GENMASK(5, 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_SINGLE (0 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR4 (1 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR8 (2 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16 (3 << 4)
+#define ATMEL_HLCDC_LAYER_DMA_DLBO BIT(8)
+#define ATMEL_HLCDC_LAYER_DMA_ROTDIS BIT(12)
+#define ATMEL_HLCDC_LAYER_DMA_LOCKDIS BIT(13)
+
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG_ID 1
+#define ATMEL_HLCDC_LAYER_FORMAT_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, ATMEL_HLCDC_LAYER_FORMAT_CFG_ID)
+#define ATMEL_HLCDC_LAYER_RGB (0 << 0)
+#define ATMEL_HLCDC_LAYER_CLUT (1 << 0)
+#define ATMEL_HLCDC_LAYER_YUV (2 << 0)
+#define ATMEL_HLCDC_RGB_MODE(m) (((m) & 0xf) << 4)
+#define ATMEL_HLCDC_CLUT_MODE(m) (((m) & 0x3) << 8)
+#define ATMEL_HLCDC_YUV_MODE(m) (((m) & 0xf) << 12)
+#define ATMEL_HLCDC_YUV422ROT BIT(16)
+#define ATMEL_HLCDC_YUV422SWP BIT(17)
+#define ATMEL_HLCDC_DSCALEOPT BIT(20)
+
+#define ATMEL_HLCDC_XRGB4444_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(0))
+#define ATMEL_HLCDC_ARGB4444_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(1))
+#define ATMEL_HLCDC_RGBA4444_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(2))
+#define ATMEL_HLCDC_RGB565_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(3))
+#define ATMEL_HLCDC_ARGB1555_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(4))
+#define ATMEL_HLCDC_XRGB8888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(9))
+#define ATMEL_HLCDC_RGB888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(10))
+#define ATMEL_HLCDC_ARGB8888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(12))
+#define ATMEL_HLCDC_RGBA8888_MODE (ATMEL_HLCDC_LAYER_RGB | ATMEL_HLCDC_RGB_MODE(13))
+
+#define ATMEL_HLCDC_AYUV_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(0))
+#define ATMEL_HLCDC_YUYV_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(1))
+#define ATMEL_HLCDC_UYVY_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(2))
+#define ATMEL_HLCDC_YVYU_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(3))
+#define ATMEL_HLCDC_VYUY_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(4))
+#define ATMEL_HLCDC_NV61_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(5))
+#define ATMEL_HLCDC_YUV422_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(6))
+#define ATMEL_HLCDC_NV21_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(7))
+#define ATMEL_HLCDC_YUV420_MODE (ATMEL_HLCDC_LAYER_YUV | ATMEL_HLCDC_YUV_MODE(8))
+
+#define ATMEL_HLCDC_LAYER_POS_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pos)
+#define ATMEL_HLCDC_LAYER_SIZE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.size)
+#define ATMEL_HLCDC_LAYER_MEMSIZE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.memsize)
+#define ATMEL_HLCDC_LAYER_XSTRIDE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.xstride)
+#define ATMEL_HLCDC_LAYER_PSTRIDE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.pstride)
+#define ATMEL_HLCDC_LAYER_DFLTCOLOR_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.default_color)
+#define ATMEL_HLCDC_LAYER_CRKEY_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key)
+#define ATMEL_HLCDC_LAYER_CRKEY_MASK_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.chroma_key_mask)
+
+#define ATMEL_HLCDC_LAYER_GENERAL_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.general_config)
+#define ATMEL_HLCDC_LAYER_CRKEY BIT(0)
+#define ATMEL_HLCDC_LAYER_INV BIT(1)
+#define ATMEL_HLCDC_LAYER_ITER2BL BIT(2)
+#define ATMEL_HLCDC_LAYER_ITER BIT(3)
+#define ATMEL_HLCDC_LAYER_REVALPHA BIT(4)
+#define ATMEL_HLCDC_LAYER_GAEN BIT(5)
+#define ATMEL_HLCDC_LAYER_LAEN BIT(6)
+#define ATMEL_HLCDC_LAYER_OVR BIT(7)
+#define ATMEL_HLCDC_LAYER_DMA BIT(8)
+#define ATMEL_HLCDC_LAYER_REP BIT(9)
+#define ATMEL_HLCDC_LAYER_DSTKEY BIT(10)
+#define ATMEL_HLCDC_LAYER_DISCEN BIT(11)
+#define ATMEL_HLCDC_LAYER_GA_SHIFT 16
+#define ATMEL_HLCDC_LAYER_GA_MASK GENMASK(23, ATMEL_HLCDC_LAYER_GA_SHIFT)
+
+#define ATMEL_HLCDC_LAYER_CSC_CFG(p, o) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.csc + o)
+
+#define ATMEL_HLCDC_LAYER_DISC_POS_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_pos)
+
+#define ATMEL_HLCDC_LAYER_DISC_SIZE_CFG(p) ATMEL_HLCDC_LAYER_CFG(p, (p)->desc->layout.disc_size)
+
+#define ATMEL_HLCDC_MAX_PLANES 3
+
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_RESERVED BIT(0)
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_LOADED BIT(1)
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_DONE BIT(2)
+#define ATMEL_HLCDC_DMA_CHANNEL_DSCR_OVERRUN BIT(3)
+
+/**
+ * Atmel HLCDC Layer registers layout structure
+ *
+ * Each HLCDC layer has its own register organization and a given register
+ * can be placed differently on 2 different layers depending on its
+ * capabilities.
+ * This structure stores common registers layout for a given layer and is
+ * used by HLCDC layer code to choose the appropriate register to write to
+ * or to read from.
+ *
+ * For all fields, a value of zero means "unsupported".
+ *
+ * See Atmel's datasheet for a detailled description of these registers.
+ *
+ * @xstride: xstride registers
+ * @pstride: pstride registers
+ * @pos: position register
+ * @size: displayed size register
+ * @memsize: memory size register
+ * @default_color: default color register
+ * @chroma_key: chroma key register
+ * @chroma_key_mask: chroma key mask register
+ * @general_config: general layer config register
+ * @disc_pos: discard area position register
+ * @disc_size: discard area size register
+ * @csc: color space conversion register
+ */
+struct atmel_hlcdc_layer_cfg_layout {
+ int xstride[ATMEL_HLCDC_MAX_PLANES];
+ int pstride[ATMEL_HLCDC_MAX_PLANES];
+ int pos;
+ int size;
+ int memsize;
+ int default_color;
+ int chroma_key;
+ int chroma_key_mask;
+ int general_config;
+ int disc_pos;
+ int disc_size;
+ int csc;
+};
+
+/**
+ * Atmel HLCDC framebuffer flip structure
+ *
+ * This structure is allocated when someone asked for a layer update (most
+ * likely a DRM plane update, either primary, overlay or cursor plane) and
+ * released when the layer do not need to reference the framebuffer object
+ * anymore (i.e. the layer was disabled or updated).
+ *
+ * @dscrs: DMA descriptors
+ * @fb: the referenced framebuffer object
+ * @ngems: number of GEM objects referenced by the fb element
+ * @status: fb flip operation status
+ */
+struct atmel_hlcdc_layer_fb_flip {
+ struct atmel_hlcdc_dma_channel_dscr *dscrs[ATMEL_HLCDC_MAX_PLANES];
+ struct drm_flip_task *task;
+ struct drm_framebuffer *fb;
+ int ngems;
+ u32 status;
+};
+
+/**
+ * Atmel HLCDC DMA descriptor structure
+ *
+ * This structure is used by the HLCDC DMA engine to schedule a DMA transfer.
+ *
+ * The structure fields must remain in this specific order, because they're
+ * used by the HLCDC DMA engine, which expect them in this order.
+ * HLCDC DMA descriptors must be aligned on 64 bits.
+ *
+ * @addr: buffer DMA address
+ * @ctrl: DMA transfer options
+ * @next: next DMA descriptor to fetch
+ * @gem_flip: the attached gem_flip operation
+ */
+struct atmel_hlcdc_dma_channel_dscr {
+ dma_addr_t addr;
+ u32 ctrl;
+ dma_addr_t next;
+ u32 status;
+} __aligned(sizeof(u64));
+
+/**
+ * Atmel HLCDC layer types
+ */
+enum atmel_hlcdc_layer_type {
+ ATMEL_HLCDC_BASE_LAYER,
+ ATMEL_HLCDC_OVERLAY_LAYER,
+ ATMEL_HLCDC_CURSOR_LAYER,
+ ATMEL_HLCDC_PP_LAYER,
+};
+
+/**
+ * Atmel HLCDC Supported formats structure
+ *
+ * This structure list all the formats supported by a given layer.
+ *
+ * @nformats: number of supported formats
+ * @formats: supported formats
+ */
+struct atmel_hlcdc_formats {
+ int nformats;
+ uint32_t *formats;
+};
+
+/**
+ * Atmel HLCDC Layer description structure
+ *
+ * This structure describe the capabilities provided by a given layer.
+ *
+ * @name: layer name
+ * @type: layer type
+ * @id: layer id
+ * @regs_offset: offset of the layer registers from the HLCDC registers base
+ * @nconfigs: number of config registers provided by this layer
+ * @formats: supported formats
+ * @layout: config registers layout
+ * @max_width: maximum width supported by this layer (0 means unlimited)
+ * @max_height: maximum height supported by this layer (0 means unlimited)
+ */
+struct atmel_hlcdc_layer_desc {
+ const char *name;
+ enum atmel_hlcdc_layer_type type;
+ int id;
+ int regs_offset;
+ int nconfigs;
+ struct atmel_hlcdc_formats *formats;
+ struct atmel_hlcdc_layer_cfg_layout layout;
+ int max_width;
+ int max_height;
+};
+
+/**
+ * Atmel HLCDC Layer Update Slot structure
+ *
+ * This structure stores layer update requests to be applied on next frame.
+ * This is the base structure behind the atomic layer update infrastructure.
+ *
+ * Atomic layer update provides a way to update all layer's parameters
+ * simultaneously. This is needed to avoid incompatible sequential updates
+ * like this one:
+ * 1) update layer format from RGB888 (1 plane/buffer) to YUV422
+ * (2 planes/buffers)
+ * 2) the format update is applied but the DMA channel for the second
+ * plane/buffer is not enabled
+ * 3) enable the DMA channel for the second plane
+ *
+ * @fb_flip: fb_flip object
+ * @updated_configs: bitmask used to record modified configs
+ * @configs: new config values
+ */
+struct atmel_hlcdc_layer_update_slot {
+ struct atmel_hlcdc_layer_fb_flip *fb_flip;
+ unsigned long *updated_configs;
+ u32 *configs;
+};
+
+/**
+ * Atmel HLCDC Layer Update structure
+ *
+ * This structure provides a way to queue layer update requests.
+ *
+ * At a given time there is at most:
+ * - one pending update request, which means the update request has been
+ * committed (or validated) and is waiting for the DMA channel(s) to be
+ * available
+ * - one request being prepared, which means someone started a layer update
+ * but has not committed it yet. There cannot be more than one started
+ * request, because the update lock is taken when starting a layer update
+ * and release when committing or rolling back the request.
+ *
+ * @slots: update slots. One is used for pending request and the other one
+ * for started update request
+ * @pending: the pending slot index or -1 if no request is pending
+ * @next: the started update slot index or -1 no update has been started
+ */
+struct atmel_hlcdc_layer_update {
+ struct atmel_hlcdc_layer_update_slot slots[2];
+ int pending;
+ int next;
+};
+
+enum atmel_hlcdc_layer_dma_channel_status {
+ ATMEL_HLCDC_LAYER_DISABLED,
+ ATMEL_HLCDC_LAYER_ENABLED,
+ ATMEL_HLCDC_LAYER_DISABLING,
+};
+
+/**
+ * Atmel HLCDC Layer DMA channel structure
+ *
+ * This structure stores information on the DMA channel associated to a
+ * given layer.
+ *
+ * @status: DMA channel status
+ * @cur: current framebuffer
+ * @queue: next framebuffer
+ * @dscrs: allocated DMA descriptors
+ */
+struct atmel_hlcdc_layer_dma_channel {
+ enum atmel_hlcdc_layer_dma_channel_status status;
+ struct atmel_hlcdc_layer_fb_flip *cur;
+ struct atmel_hlcdc_layer_fb_flip *queue;
+ struct atmel_hlcdc_dma_channel_dscr *dscrs;
+};
+
+/**
+ * Atmel HLCDC Layer structure
+ *
+ * This structure stores information on the layer instance.
+ *
+ * @desc: layer description
+ * @max_planes: maximum planes/buffers that can be associated with this layer.
+ * This depends on the supported formats.
+ * @hlcdc: pointer to the atmel_hlcdc structure provided by the MFD device
+ * @dma: dma channel
+ * @gc: fb flip garbage collector
+ * @update: update handler
+ * @lock: layer lock
+ */
+struct atmel_hlcdc_layer {
+ const struct atmel_hlcdc_layer_desc *desc;
+ int max_planes;
+ struct atmel_hlcdc *hlcdc;
+ struct workqueue_struct *wq;
+ struct drm_flip_work gc;
+ struct atmel_hlcdc_layer_dma_channel dma;
+ struct atmel_hlcdc_layer_update update;
+ spinlock_t lock;
+};
+
+void atmel_hlcdc_layer_irq(struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_init(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer,
+ const struct atmel_hlcdc_layer_desc *desc);
+
+void atmel_hlcdc_layer_cleanup(struct drm_device *dev,
+ struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_disable(struct atmel_hlcdc_layer *layer);
+
+int atmel_hlcdc_layer_update_start(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_cfg(struct atmel_hlcdc_layer *layer, int cfg,
+ u32 mask, u32 val);
+
+void atmel_hlcdc_layer_update_set_fb(struct atmel_hlcdc_layer *layer,
+ struct drm_framebuffer *fb,
+ unsigned int *offsets);
+
+void atmel_hlcdc_layer_update_set_finished(struct atmel_hlcdc_layer *layer,
+ void (*finished)(void *data),
+ void *finished_data);
+
+void atmel_hlcdc_layer_update_rollback(struct atmel_hlcdc_layer *layer);
+
+void atmel_hlcdc_layer_update_commit(struct atmel_hlcdc_layer *layer);
+
+#endif /* DRM_ATMEL_HLCDC_LAYER_H */
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
new file mode 100644
index 000000000000..c402192362c5
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_output.c
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2014 Traphandler
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Jean-Jacques Hiblot <jjhiblot@traphandler.com>
+ * 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/of_graph.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_panel.h>
+
+#include "atmel_hlcdc_dc.h"
+
+/**
+ * Atmel HLCDC RGB output mode
+ */
+enum atmel_hlcdc_connector_rgb_mode {
+ ATMEL_HLCDC_CONNECTOR_RGB444,
+ ATMEL_HLCDC_CONNECTOR_RGB565,
+ ATMEL_HLCDC_CONNECTOR_RGB666,
+ ATMEL_HLCDC_CONNECTOR_RGB888,
+};
+
+/**
+ * Atmel HLCDC RGB connector structure
+ *
+ * This structure stores RGB slave device information.
+ *
+ * @connector: DRM connector
+ * @encoder: DRM encoder
+ * @dc: pointer to the atmel_hlcdc_dc structure
+ * @dpms: current DPMS mode
+ */
+struct atmel_hlcdc_rgb_output {
+ struct drm_connector connector;
+ struct drm_encoder encoder;
+ struct atmel_hlcdc_dc *dc;
+ int dpms;
+};
+
+static inline struct atmel_hlcdc_rgb_output *
+drm_connector_to_atmel_hlcdc_rgb_output(struct drm_connector *connector)
+{
+ return container_of(connector, struct atmel_hlcdc_rgb_output,
+ connector);
+}
+
+static inline struct atmel_hlcdc_rgb_output *
+drm_encoder_to_atmel_hlcdc_rgb_output(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct atmel_hlcdc_rgb_output, encoder);
+}
+
+/**
+ * Atmel HLCDC Panel device structure
+ *
+ * This structure is specialization of the slave device structure to
+ * interface with drm panels.
+ *
+ * @base: base slave device fields
+ * @panel: drm panel attached to this slave device
+ */
+struct atmel_hlcdc_panel {
+ struct atmel_hlcdc_rgb_output base;
+ struct drm_panel *panel;
+};
+
+static inline struct atmel_hlcdc_panel *
+atmel_hlcdc_rgb_output_to_panel(struct atmel_hlcdc_rgb_output *output)
+{
+ return container_of(output, struct atmel_hlcdc_panel, base);
+}
+
+static void atmel_hlcdc_panel_encoder_dpms(struct drm_encoder *encoder,
+ int mode)
+{
+ struct atmel_hlcdc_rgb_output *rgb =
+ drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
+ struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
+
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
+ if (mode == rgb->dpms)
+ return;
+
+ if (mode != DRM_MODE_DPMS_ON)
+ drm_panel_disable(panel->panel);
+ else
+ drm_panel_enable(panel->panel);
+
+ rgb->dpms = mode;
+}
+
+static bool
+atmel_hlcdc_panel_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
+{
+ return true;
+}
+
+static void atmel_hlcdc_panel_encoder_prepare(struct drm_encoder *encoder)
+{
+ atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+}
+
+static void atmel_hlcdc_panel_encoder_commit(struct drm_encoder *encoder)
+{
+ atmel_hlcdc_panel_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+}
+
+static void
+atmel_hlcdc_rgb_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
+{
+ struct atmel_hlcdc_rgb_output *rgb =
+ drm_encoder_to_atmel_hlcdc_rgb_output(encoder);
+ struct drm_display_info *info = &rgb->connector.display_info;
+ unsigned int cfg;
+
+ cfg = 0;
+
+ if (info->num_bus_formats) {
+ switch (info->bus_formats[0]) {
+ case MEDIA_BUS_FMT_RGB666_1X18:
+ cfg |= ATMEL_HLCDC_CONNECTOR_RGB666 << 8;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ cfg |= ATMEL_HLCDC_CONNECTOR_RGB888 << 8;
+ break;
+ default:
+ break;
+ }
+ }
+
+ regmap_update_bits(rgb->dc->hlcdc->regmap, ATMEL_HLCDC_CFG(5),
+ ATMEL_HLCDC_MODE_MASK,
+ cfg);
+}
+
+static struct drm_encoder_helper_funcs atmel_hlcdc_panel_encoder_helper_funcs = {
+ .dpms = atmel_hlcdc_panel_encoder_dpms,
+ .mode_fixup = atmel_hlcdc_panel_encoder_mode_fixup,
+ .prepare = atmel_hlcdc_panel_encoder_prepare,
+ .commit = atmel_hlcdc_panel_encoder_commit,
+ .mode_set = atmel_hlcdc_rgb_encoder_mode_set,
+};
+
+static void atmel_hlcdc_rgb_encoder_destroy(struct drm_encoder *encoder)
+{
+ drm_encoder_cleanup(encoder);
+ memset(encoder, 0, sizeof(*encoder));
+}
+
+static const struct drm_encoder_funcs atmel_hlcdc_panel_encoder_funcs = {
+ .destroy = atmel_hlcdc_rgb_encoder_destroy,
+};
+
+static int atmel_hlcdc_panel_get_modes(struct drm_connector *connector)
+{
+ struct atmel_hlcdc_rgb_output *rgb =
+ drm_connector_to_atmel_hlcdc_rgb_output(connector);
+ struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
+
+ return panel->panel->funcs->get_modes(panel->panel);
+}
+
+static int atmel_hlcdc_rgb_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct atmel_hlcdc_rgb_output *rgb =
+ drm_connector_to_atmel_hlcdc_rgb_output(connector);
+
+ return atmel_hlcdc_dc_mode_valid(rgb->dc, mode);
+}
+
+
+
+static struct drm_encoder *
+atmel_hlcdc_rgb_best_encoder(struct drm_connector *connector)
+{
+ struct atmel_hlcdc_rgb_output *rgb =
+ drm_connector_to_atmel_hlcdc_rgb_output(connector);
+
+ return &rgb->encoder;
+}
+
+static struct drm_connector_helper_funcs atmel_hlcdc_panel_connector_helper_funcs = {
+ .get_modes = atmel_hlcdc_panel_get_modes,
+ .mode_valid = atmel_hlcdc_rgb_mode_valid,
+ .best_encoder = atmel_hlcdc_rgb_best_encoder,
+};
+
+static enum drm_connector_status
+atmel_hlcdc_panel_connector_detect(struct drm_connector *connector, bool force)
+{
+ return connector_status_connected;
+}
+
+static void
+atmel_hlcdc_panel_connector_destroy(struct drm_connector *connector)
+{
+ struct atmel_hlcdc_rgb_output *rgb =
+ drm_connector_to_atmel_hlcdc_rgb_output(connector);
+ struct atmel_hlcdc_panel *panel = atmel_hlcdc_rgb_output_to_panel(rgb);
+
+ drm_panel_detach(panel->panel);
+ drm_connector_cleanup(connector);
+}
+
+static const struct drm_connector_funcs atmel_hlcdc_panel_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .detect = atmel_hlcdc_panel_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = atmel_hlcdc_panel_connector_destroy,
+};
+
+static int atmel_hlcdc_create_panel_output(struct drm_device *dev,
+ struct of_endpoint *ep)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ struct device_node *np;
+ struct drm_panel *p = NULL;
+ struct atmel_hlcdc_panel *panel;
+ int ret;
+
+ np = of_graph_get_remote_port_parent(ep->local_node);
+ if (!np)
+ return -EINVAL;
+
+ p = of_drm_find_panel(np);
+ of_node_put(np);
+
+ if (!p)
+ return -EPROBE_DEFER;
+
+ panel = devm_kzalloc(dev->dev, sizeof(*panel), GFP_KERNEL);
+ if (!panel)
+ return -EINVAL;
+
+ panel->base.dpms = DRM_MODE_DPMS_OFF;
+
+ panel->base.dc = dc;
+
+ drm_encoder_helper_add(&panel->base.encoder,
+ &atmel_hlcdc_panel_encoder_helper_funcs);
+ ret = drm_encoder_init(dev, &panel->base.encoder,
+ &atmel_hlcdc_panel_encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
+ if (ret)
+ return ret;
+
+ panel->base.connector.dpms = DRM_MODE_DPMS_OFF;
+ panel->base.connector.polled = DRM_CONNECTOR_POLL_CONNECT;
+ drm_connector_helper_add(&panel->base.connector,
+ &atmel_hlcdc_panel_connector_helper_funcs);
+ ret = drm_connector_init(dev, &panel->base.connector,
+ &atmel_hlcdc_panel_connector_funcs,
+ DRM_MODE_CONNECTOR_LVDS);
+ if (ret)
+ goto err_encoder_cleanup;
+
+ drm_mode_connector_attach_encoder(&panel->base.connector,
+ &panel->base.encoder);
+ panel->base.encoder.possible_crtcs = 0x1;
+
+ drm_panel_attach(p, &panel->base.connector);
+ panel->panel = p;
+
+ return 0;
+
+err_encoder_cleanup:
+ drm_encoder_cleanup(&panel->base.encoder);
+
+ return ret;
+}
+
+int atmel_hlcdc_create_outputs(struct drm_device *dev)
+{
+ struct device_node *port_np, *np;
+ struct of_endpoint ep;
+ int ret;
+
+ port_np = of_get_child_by_name(dev->dev->of_node, "port");
+ if (!port_np)
+ return -EINVAL;
+
+ np = of_get_child_by_name(port_np, "endpoint");
+ of_node_put(port_np);
+
+ if (!np)
+ return -EINVAL;
+
+ ret = of_graph_parse_endpoint(np, &ep);
+ of_node_put(port_np);
+
+ if (ret)
+ return ret;
+
+ /* We currently only support panel output */
+ return atmel_hlcdc_create_panel_output(dev, &ep);
+}
diff --git a/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
new file mode 100644
index 000000000000..c5892dcfd745
--- /dev/null
+++ b/drivers/gpu/drm/atmel-hlcdc/atmel_hlcdc_plane.c
@@ -0,0 +1,856 @@
+/*
+ * 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 "atmel_hlcdc_dc.h"
+
+#define SUBPIXEL_MASK 0xffff
+
+static uint32_t rgb_formats[] = {
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_RGBA8888,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_formats = {
+ .formats = rgb_formats,
+ .nformats = ARRAY_SIZE(rgb_formats),
+};
+
+static uint32_t rgb_and_yuv_formats[] = {
+ DRM_FORMAT_XRGB4444,
+ DRM_FORMAT_ARGB4444,
+ DRM_FORMAT_RGBA4444,
+ DRM_FORMAT_ARGB1555,
+ DRM_FORMAT_RGB565,
+ DRM_FORMAT_RGB888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_RGBA8888,
+ DRM_FORMAT_AYUV,
+ DRM_FORMAT_YUYV,
+ DRM_FORMAT_UYVY,
+ DRM_FORMAT_YVYU,
+ DRM_FORMAT_VYUY,
+ DRM_FORMAT_NV21,
+ DRM_FORMAT_NV61,
+ DRM_FORMAT_YUV422,
+ DRM_FORMAT_YUV420,
+};
+
+struct atmel_hlcdc_formats atmel_hlcdc_plane_rgb_and_yuv_formats = {
+ .formats = rgb_and_yuv_formats,
+ .nformats = ARRAY_SIZE(rgb_and_yuv_formats),
+};
+
+static int atmel_hlcdc_format_to_plane_mode(u32 format, u32 *mode)
+{
+ switch (format) {
+ case DRM_FORMAT_XRGB4444:
+ *mode = ATMEL_HLCDC_XRGB4444_MODE;
+ break;
+ case DRM_FORMAT_ARGB4444:
+ *mode = ATMEL_HLCDC_ARGB4444_MODE;
+ break;
+ case DRM_FORMAT_RGBA4444:
+ *mode = ATMEL_HLCDC_RGBA4444_MODE;
+ break;
+ case DRM_FORMAT_RGB565:
+ *mode = ATMEL_HLCDC_RGB565_MODE;
+ break;
+ case DRM_FORMAT_RGB888:
+ *mode = ATMEL_HLCDC_RGB888_MODE;
+ break;
+ case DRM_FORMAT_ARGB1555:
+ *mode = ATMEL_HLCDC_ARGB1555_MODE;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ *mode = ATMEL_HLCDC_XRGB8888_MODE;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ *mode = ATMEL_HLCDC_ARGB8888_MODE;
+ break;
+ case DRM_FORMAT_RGBA8888:
+ *mode = ATMEL_HLCDC_RGBA8888_MODE;
+ break;
+ case DRM_FORMAT_AYUV:
+ *mode = ATMEL_HLCDC_AYUV_MODE;
+ break;
+ case DRM_FORMAT_YUYV:
+ *mode = ATMEL_HLCDC_YUYV_MODE;
+ break;
+ case DRM_FORMAT_UYVY:
+ *mode = ATMEL_HLCDC_UYVY_MODE;
+ break;
+ case DRM_FORMAT_YVYU:
+ *mode = ATMEL_HLCDC_YVYU_MODE;
+ break;
+ case DRM_FORMAT_VYUY:
+ *mode = ATMEL_HLCDC_VYUY_MODE;
+ break;
+ case DRM_FORMAT_NV21:
+ *mode = ATMEL_HLCDC_NV21_MODE;
+ break;
+ case DRM_FORMAT_NV61:
+ *mode = ATMEL_HLCDC_NV61_MODE;
+ break;
+ case DRM_FORMAT_YUV420:
+ *mode = ATMEL_HLCDC_YUV420_MODE;
+ break;
+ case DRM_FORMAT_YUV422:
+ *mode = ATMEL_HLCDC_YUV422_MODE;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ return 0;
+}
+
+static bool atmel_hlcdc_format_embedds_alpha(u32 format)
+{
+ int i;
+
+ for (i = 0; i < sizeof(format); i++) {
+ char tmp = (format >> (8 * i)) & 0xff;
+
+ if (tmp == 'A')
+ return true;
+ }
+
+ return false;
+}
+
+static u32 heo_downscaling_xcoef[] = {
+ 0x11343311,
+ 0x000000f7,
+ 0x1635300c,
+ 0x000000f9,
+ 0x1b362c08,
+ 0x000000fb,
+ 0x1f372804,
+ 0x000000fe,
+ 0x24382400,
+ 0x00000000,
+ 0x28371ffe,
+ 0x00000004,
+ 0x2c361bfb,
+ 0x00000008,
+ 0x303516f9,
+ 0x0000000c,
+};
+
+static u32 heo_downscaling_ycoef[] = {
+ 0x00123737,
+ 0x00173732,
+ 0x001b382d,
+ 0x001f3928,
+ 0x00243824,
+ 0x0028391f,
+ 0x002d381b,
+ 0x00323717,
+};
+
+static u32 heo_upscaling_xcoef[] = {
+ 0xf74949f7,
+ 0x00000000,
+ 0xf55f33fb,
+ 0x000000fe,
+ 0xf5701efe,
+ 0x000000ff,
+ 0xf87c0dff,
+ 0x00000000,
+ 0x00800000,
+ 0x00000000,
+ 0x0d7cf800,
+ 0x000000ff,
+ 0x1e70f5ff,
+ 0x000000fe,
+ 0x335ff5fe,
+ 0x000000fb,
+};
+
+static u32 heo_upscaling_ycoef[] = {
+ 0x00004040,
+ 0x00075920,
+ 0x00056f0c,
+ 0x00027b03,
+ 0x00008000,
+ 0x00037b02,
+ 0x000c6f05,
+ 0x00205907,
+};
+
+static void
+atmel_hlcdc_plane_update_pos_and_size(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_update_req *req)
+{
+ const struct atmel_hlcdc_layer_cfg_layout *layout =
+ &plane->layer.desc->layout;
+
+ if (layout->size)
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ layout->size,
+ 0xffffffff,
+ (req->crtc_w - 1) |
+ ((req->crtc_h - 1) << 16));
+
+ if (layout->memsize)
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ layout->memsize,
+ 0xffffffff,
+ (req->src_w - 1) |
+ ((req->src_h - 1) << 16));
+
+ if (layout->pos)
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ layout->pos,
+ 0xffffffff,
+ req->crtc_x |
+ (req->crtc_y << 16));
+
+ /* TODO: rework the rescaling part */
+ if (req->crtc_w != req->src_w || req->crtc_h != req->src_h) {
+ u32 factor_reg = 0;
+
+ if (req->crtc_w != req->src_w) {
+ int i;
+ u32 factor;
+ u32 *coeff_tab = heo_upscaling_xcoef;
+ u32 max_memsize;
+
+ if (req->crtc_w < req->src_w)
+ coeff_tab = heo_downscaling_xcoef;
+ for (i = 0; i < ARRAY_SIZE(heo_upscaling_xcoef); i++)
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ 17 + i,
+ 0xffffffff,
+ coeff_tab[i]);
+ factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+ req->crtc_w;
+ factor++;
+ max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+ 2048;
+ if (max_memsize > req->src_w)
+ factor--;
+ factor_reg |= factor | 0x80000000;
+ }
+
+ if (req->crtc_h != req->src_h) {
+ int i;
+ u32 factor;
+ u32 *coeff_tab = heo_upscaling_ycoef;
+ u32 max_memsize;
+
+ if (req->crtc_w < req->src_w)
+ coeff_tab = heo_downscaling_ycoef;
+ for (i = 0; i < ARRAY_SIZE(heo_upscaling_ycoef); i++)
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ 33 + i,
+ 0xffffffff,
+ coeff_tab[i]);
+ factor = ((8 * 256 * req->src_w) - (256 * 4)) /
+ req->crtc_w;
+ factor++;
+ max_memsize = ((factor * req->crtc_w) + (256 * 4)) /
+ 2048;
+ if (max_memsize > req->src_w)
+ factor--;
+ factor_reg |= (factor << 16) | 0x80000000;
+ }
+
+ atmel_hlcdc_layer_update_cfg(&plane->layer, 13, 0xffffffff,
+ factor_reg);
+ }
+}
+
+static void
+atmel_hlcdc_plane_update_general_settings(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_update_req *req)
+{
+ const struct atmel_hlcdc_layer_cfg_layout *layout =
+ &plane->layer.desc->layout;
+ unsigned int cfg = ATMEL_HLCDC_LAYER_DMA;
+
+ if (plane->base.type != DRM_PLANE_TYPE_PRIMARY) {
+ cfg |= ATMEL_HLCDC_LAYER_OVR | ATMEL_HLCDC_LAYER_ITER2BL |
+ ATMEL_HLCDC_LAYER_ITER;
+
+ if (atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format))
+ cfg |= ATMEL_HLCDC_LAYER_LAEN;
+ else
+ cfg |= ATMEL_HLCDC_LAYER_GAEN;
+ }
+
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ ATMEL_HLCDC_LAYER_DMA_CFG_ID,
+ ATMEL_HLCDC_LAYER_DMA_BLEN_MASK,
+ ATMEL_HLCDC_LAYER_DMA_BLEN_INCR16);
+
+ atmel_hlcdc_layer_update_cfg(&plane->layer, layout->general_config,
+ ATMEL_HLCDC_LAYER_ITER2BL |
+ ATMEL_HLCDC_LAYER_ITER |
+ ATMEL_HLCDC_LAYER_GAEN |
+ ATMEL_HLCDC_LAYER_LAEN |
+ ATMEL_HLCDC_LAYER_OVR |
+ ATMEL_HLCDC_LAYER_DMA, cfg);
+}
+
+static void atmel_hlcdc_plane_update_format(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_update_req *req)
+{
+ u32 cfg;
+ int ret;
+
+ ret = atmel_hlcdc_format_to_plane_mode(req->fb->pixel_format, &cfg);
+ if (ret)
+ return;
+
+ if ((req->fb->pixel_format == DRM_FORMAT_YUV422 ||
+ req->fb->pixel_format == DRM_FORMAT_NV61) &&
+ (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))))
+ cfg |= ATMEL_HLCDC_YUV422ROT;
+
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ ATMEL_HLCDC_LAYER_FORMAT_CFG_ID,
+ 0xffffffff,
+ cfg);
+
+ /*
+ * Rotation optimization is not working on RGB888 (rotation is still
+ * working but without any optimization).
+ */
+ if (req->fb->pixel_format == DRM_FORMAT_RGB888)
+ cfg = ATMEL_HLCDC_LAYER_DMA_ROTDIS;
+ else
+ cfg = 0;
+
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ ATMEL_HLCDC_LAYER_DMA_CFG_ID,
+ ATMEL_HLCDC_LAYER_DMA_ROTDIS, cfg);
+}
+
+static void atmel_hlcdc_plane_update_buffers(struct atmel_hlcdc_plane *plane,
+ struct atmel_hlcdc_plane_update_req *req)
+{
+ struct atmel_hlcdc_layer *layer = &plane->layer;
+ const struct atmel_hlcdc_layer_cfg_layout *layout =
+ &layer->desc->layout;
+ int i;
+
+ atmel_hlcdc_layer_update_set_fb(&plane->layer, req->fb, req->offsets);
+
+ for (i = 0; i < req->nplanes; i++) {
+ if (layout->xstride[i]) {
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ layout->xstride[i],
+ 0xffffffff,
+ req->xstride[i]);
+ }
+
+ if (layout->pstride[i]) {
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ layout->pstride[i],
+ 0xffffffff,
+ req->pstride[i]);
+ }
+ }
+}
+
+static int atmel_hlcdc_plane_check_update_req(struct drm_plane *p,
+ struct atmel_hlcdc_plane_update_req *req,
+ const struct drm_display_mode *mode)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+ const struct atmel_hlcdc_layer_cfg_layout *layout =
+ &plane->layer.desc->layout;
+
+ if (!layout->size &&
+ (mode->hdisplay != req->crtc_w ||
+ mode->vdisplay != req->crtc_h))
+ return -EINVAL;
+
+ if (plane->layer.desc->max_height &&
+ req->crtc_h > plane->layer.desc->max_height)
+ return -EINVAL;
+
+ if (plane->layer.desc->max_width &&
+ req->crtc_w > plane->layer.desc->max_width)
+ return -EINVAL;
+
+ if ((req->crtc_h != req->src_h || req->crtc_w != req->src_w) &&
+ (!layout->memsize ||
+ atmel_hlcdc_format_embedds_alpha(req->fb->pixel_format)))
+ return -EINVAL;
+
+ if (req->crtc_x < 0 || req->crtc_y < 0)
+ return -EINVAL;
+
+ if (req->crtc_w + req->crtc_x > mode->hdisplay ||
+ req->crtc_h + req->crtc_y > mode->vdisplay)
+ return -EINVAL;
+
+ return 0;
+}
+
+int atmel_hlcdc_plane_prepare_update_req(struct drm_plane *p,
+ struct atmel_hlcdc_plane_update_req *req,
+ const struct drm_display_mode *mode)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+ unsigned int patched_crtc_w;
+ unsigned int patched_crtc_h;
+ unsigned int patched_src_w;
+ unsigned int patched_src_h;
+ unsigned int tmp;
+ int x_offset = 0;
+ int y_offset = 0;
+ int hsub = 1;
+ int vsub = 1;
+ int i;
+
+ if ((req->src_x | req->src_y | req->src_w | req->src_h) &
+ SUBPIXEL_MASK)
+ return -EINVAL;
+
+ req->src_x >>= 16;
+ req->src_y >>= 16;
+ req->src_w >>= 16;
+ req->src_h >>= 16;
+
+ req->nplanes = drm_format_num_planes(req->fb->pixel_format);
+ if (req->nplanes > ATMEL_HLCDC_MAX_PLANES)
+ return -EINVAL;
+
+ /*
+ * Swap width and size in case of 90 or 270 degrees rotation
+ */
+ if (plane->rotation & (BIT(DRM_ROTATE_90) | BIT(DRM_ROTATE_270))) {
+ tmp = req->crtc_w;
+ req->crtc_w = req->crtc_h;
+ req->crtc_h = tmp;
+ tmp = req->src_w;
+ req->src_w = req->src_h;
+ req->src_h = tmp;
+ }
+
+ if (req->crtc_x + req->crtc_w > mode->hdisplay)
+ patched_crtc_w = mode->hdisplay - req->crtc_x;
+ else
+ patched_crtc_w = req->crtc_w;
+
+ if (req->crtc_x < 0) {
+ patched_crtc_w += req->crtc_x;
+ x_offset = -req->crtc_x;
+ req->crtc_x = 0;
+ }
+
+ if (req->crtc_y + req->crtc_h > mode->vdisplay)
+ patched_crtc_h = mode->vdisplay - req->crtc_y;
+ else
+ patched_crtc_h = req->crtc_h;
+
+ if (req->crtc_y < 0) {
+ patched_crtc_h += req->crtc_y;
+ y_offset = -req->crtc_y;
+ req->crtc_y = 0;
+ }
+
+ patched_src_w = DIV_ROUND_CLOSEST(patched_crtc_w * req->src_w,
+ req->crtc_w);
+ patched_src_h = DIV_ROUND_CLOSEST(patched_crtc_h * req->src_h,
+ req->crtc_h);
+
+ hsub = drm_format_horz_chroma_subsampling(req->fb->pixel_format);
+ vsub = drm_format_vert_chroma_subsampling(req->fb->pixel_format);
+
+ for (i = 0; i < req->nplanes; i++) {
+ unsigned int offset = 0;
+ int xdiv = i ? hsub : 1;
+ int ydiv = i ? vsub : 1;
+
+ req->bpp[i] = drm_format_plane_cpp(req->fb->pixel_format, i);
+ if (!req->bpp[i])
+ return -EINVAL;
+
+ switch (plane->rotation & 0xf) {
+ case BIT(DRM_ROTATE_90):
+ offset = ((y_offset + req->src_y + patched_src_w - 1) /
+ ydiv) * req->fb->pitches[i];
+ offset += ((x_offset + req->src_x) / xdiv) *
+ req->bpp[i];
+ req->xstride[i] = ((patched_src_w - 1) / ydiv) *
+ req->fb->pitches[i];
+ req->pstride[i] = -req->fb->pitches[i] - req->bpp[i];
+ break;
+ case BIT(DRM_ROTATE_180):
+ offset = ((y_offset + req->src_y + patched_src_h - 1) /
+ ydiv) * req->fb->pitches[i];
+ offset += ((x_offset + req->src_x + patched_src_w - 1) /
+ xdiv) * req->bpp[i];
+ req->xstride[i] = ((((patched_src_w - 1) / xdiv) - 1) *
+ req->bpp[i]) - req->fb->pitches[i];
+ req->pstride[i] = -2 * req->bpp[i];
+ break;
+ case BIT(DRM_ROTATE_270):
+ offset = ((y_offset + req->src_y) / ydiv) *
+ req->fb->pitches[i];
+ offset += ((x_offset + req->src_x + patched_src_h - 1) /
+ xdiv) * req->bpp[i];
+ req->xstride[i] = -(((patched_src_w - 1) / ydiv) *
+ req->fb->pitches[i]) -
+ (2 * req->bpp[i]);
+ req->pstride[i] = req->fb->pitches[i] - req->bpp[i];
+ break;
+ case BIT(DRM_ROTATE_0):
+ default:
+ offset = ((y_offset + req->src_y) / ydiv) *
+ req->fb->pitches[i];
+ offset += ((x_offset + req->src_x) / xdiv) *
+ req->bpp[i];
+ req->xstride[i] = req->fb->pitches[i] -
+ ((patched_src_w / xdiv) *
+ req->bpp[i]);
+ req->pstride[i] = 0;
+ break;
+ }
+
+ req->offsets[i] = offset + req->fb->offsets[i];
+ }
+
+ req->src_w = patched_src_w;
+ req->src_h = patched_src_h;
+ req->crtc_w = patched_crtc_w;
+ req->crtc_h = patched_crtc_h;
+
+ return atmel_hlcdc_plane_check_update_req(p, req, mode);
+}
+
+int atmel_hlcdc_plane_apply_update_req(struct drm_plane *p,
+ struct atmel_hlcdc_plane_update_req *req)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+ int ret;
+
+ ret = atmel_hlcdc_layer_update_start(&plane->layer);
+ if (ret)
+ return ret;
+
+ atmel_hlcdc_plane_update_pos_and_size(plane, req);
+ atmel_hlcdc_plane_update_general_settings(plane, req);
+ atmel_hlcdc_plane_update_format(plane, req);
+ atmel_hlcdc_plane_update_buffers(plane, req);
+
+ atmel_hlcdc_layer_update_commit(&plane->layer);
+
+ return 0;
+}
+
+int atmel_hlcdc_plane_update_with_mode(struct drm_plane *p,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w,
+ unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h,
+ const struct drm_display_mode *mode)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+ struct atmel_hlcdc_plane_update_req req;
+ int ret = 0;
+
+ memset(&req, 0, sizeof(req));
+ req.crtc_x = crtc_x;
+ req.crtc_y = crtc_y;
+ req.crtc_w = crtc_w;
+ req.crtc_h = crtc_h;
+ req.src_x = src_x;
+ req.src_y = src_y;
+ req.src_w = src_w;
+ req.src_h = src_h;
+ req.fb = fb;
+
+ ret = atmel_hlcdc_plane_prepare_update_req(&plane->base, &req, mode);
+ if (ret)
+ return ret;
+
+ if (!req.crtc_h || !req.crtc_w)
+ return atmel_hlcdc_layer_disable(&plane->layer);
+
+ return atmel_hlcdc_plane_apply_update_req(&plane->base, &req);
+}
+
+static int atmel_hlcdc_plane_update(struct drm_plane *p,
+ struct drm_crtc *crtc,
+ struct drm_framebuffer *fb,
+ int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h)
+{
+ return atmel_hlcdc_plane_update_with_mode(p, crtc, fb, crtc_x, crtc_y,
+ crtc_w, crtc_h, src_x, src_y,
+ src_w, src_h, &crtc->hwmode);
+}
+
+static int atmel_hlcdc_plane_disable(struct drm_plane *p)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+ return atmel_hlcdc_layer_disable(&plane->layer);
+}
+
+static void atmel_hlcdc_plane_destroy(struct drm_plane *p)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+
+ if (plane->base.fb)
+ drm_framebuffer_unreference(plane->base.fb);
+
+ atmel_hlcdc_layer_cleanup(p->dev, &plane->layer);
+
+ drm_plane_cleanup(p);
+ devm_kfree(p->dev->dev, plane);
+}
+
+static int atmel_hlcdc_plane_set_alpha(struct atmel_hlcdc_plane *plane,
+ u8 alpha)
+{
+ atmel_hlcdc_layer_update_start(&plane->layer);
+ atmel_hlcdc_layer_update_cfg(&plane->layer,
+ plane->layer.desc->layout.general_config,
+ ATMEL_HLCDC_LAYER_GA_MASK,
+ alpha << ATMEL_HLCDC_LAYER_GA_SHIFT);
+ atmel_hlcdc_layer_update_commit(&plane->layer);
+
+ return 0;
+}
+
+static int atmel_hlcdc_plane_set_rotation(struct atmel_hlcdc_plane *plane,
+ unsigned int rotation)
+{
+ plane->rotation = rotation;
+
+ return 0;
+}
+
+static int atmel_hlcdc_plane_set_property(struct drm_plane *p,
+ struct drm_property *property,
+ uint64_t value)
+{
+ struct atmel_hlcdc_plane *plane = drm_plane_to_atmel_hlcdc_plane(p);
+ struct atmel_hlcdc_plane_properties *props = plane->properties;
+
+ if (property == props->alpha)
+ atmel_hlcdc_plane_set_alpha(plane, value);
+ else if (property == props->rotation)
+ atmel_hlcdc_plane_set_rotation(plane, value);
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+static void atmel_hlcdc_plane_init_properties(struct atmel_hlcdc_plane *plane,
+ const struct atmel_hlcdc_layer_desc *desc,
+ struct atmel_hlcdc_plane_properties *props)
+{
+ struct regmap *regmap = plane->layer.hlcdc->regmap;
+
+ if (desc->type == ATMEL_HLCDC_OVERLAY_LAYER ||
+ desc->type == ATMEL_HLCDC_CURSOR_LAYER) {
+ drm_object_attach_property(&plane->base.base,
+ props->alpha, 255);
+
+ /* Set default alpha value */
+ regmap_update_bits(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_GENERAL_CFG(&plane->layer),
+ ATMEL_HLCDC_LAYER_GA_MASK,
+ ATMEL_HLCDC_LAYER_GA_MASK);
+ }
+
+ if (desc->layout.xstride && desc->layout.pstride)
+ drm_object_attach_property(&plane->base.base,
+ props->rotation,
+ BIT(DRM_ROTATE_0));
+
+ if (desc->layout.csc) {
+ /*
+ * TODO: decare a "yuv-to-rgb-conv-factors" property to let
+ * userspace modify these factors (using a BLOB property ?).
+ */
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 0),
+ 0x4c900091);
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 1),
+ 0x7a5f5090);
+ regmap_write(regmap,
+ desc->regs_offset +
+ ATMEL_HLCDC_LAYER_CSC_CFG(&plane->layer, 2),
+ 0x40040890);
+ }
+}
+
+static struct drm_plane_funcs layer_plane_funcs = {
+ .update_plane = atmel_hlcdc_plane_update,
+ .disable_plane = atmel_hlcdc_plane_disable,
+ .set_property = atmel_hlcdc_plane_set_property,
+ .destroy = atmel_hlcdc_plane_destroy,
+};
+
+static struct atmel_hlcdc_plane *
+atmel_hlcdc_plane_create(struct drm_device *dev,
+ const struct atmel_hlcdc_layer_desc *desc,
+ struct atmel_hlcdc_plane_properties *props)
+{
+ struct atmel_hlcdc_plane *plane;
+ enum drm_plane_type type;
+ int ret;
+
+ plane = devm_kzalloc(dev->dev, sizeof(*plane), GFP_KERNEL);
+ if (!plane)
+ return ERR_PTR(-ENOMEM);
+
+ ret = atmel_hlcdc_layer_init(dev, &plane->layer, desc);
+ if (ret)
+ return ERR_PTR(ret);
+
+ if (desc->type == ATMEL_HLCDC_BASE_LAYER)
+ type = DRM_PLANE_TYPE_PRIMARY;
+ else if (desc->type == ATMEL_HLCDC_CURSOR_LAYER)
+ type = DRM_PLANE_TYPE_CURSOR;
+ else
+ type = DRM_PLANE_TYPE_OVERLAY;
+
+ ret = drm_universal_plane_init(dev, &plane->base, 0,
+ &layer_plane_funcs,
+ desc->formats->formats,
+ desc->formats->nformats, type);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Set default property values*/
+ atmel_hlcdc_plane_init_properties(plane, desc, props);
+
+ return plane;
+}
+
+static struct atmel_hlcdc_plane_properties *
+atmel_hlcdc_plane_create_properties(struct drm_device *dev)
+{
+ struct atmel_hlcdc_plane_properties *props;
+
+ props = devm_kzalloc(dev->dev, sizeof(*props), GFP_KERNEL);
+ if (!props)
+ return ERR_PTR(-ENOMEM);
+
+ props->alpha = drm_property_create_range(dev, 0, "alpha", 0, 255);
+ if (!props->alpha)
+ return ERR_PTR(-ENOMEM);
+
+ props->rotation = drm_mode_create_rotation_property(dev,
+ BIT(DRM_ROTATE_0) |
+ BIT(DRM_ROTATE_90) |
+ BIT(DRM_ROTATE_180) |
+ BIT(DRM_ROTATE_270));
+ if (!props->rotation)
+ return ERR_PTR(-ENOMEM);
+
+ return props;
+}
+
+struct atmel_hlcdc_planes *
+atmel_hlcdc_create_planes(struct drm_device *dev)
+{
+ struct atmel_hlcdc_dc *dc = dev->dev_private;
+ struct atmel_hlcdc_plane_properties *props;
+ struct atmel_hlcdc_planes *planes;
+ const struct atmel_hlcdc_layer_desc *descs = dc->desc->layers;
+ int nlayers = dc->desc->nlayers;
+ int i;
+
+ planes = devm_kzalloc(dev->dev, sizeof(*planes), GFP_KERNEL);
+ if (!planes)
+ return ERR_PTR(-ENOMEM);
+
+ for (i = 0; i < nlayers; i++) {
+ if (descs[i].type == ATMEL_HLCDC_OVERLAY_LAYER)
+ planes->noverlays++;
+ }
+
+ if (planes->noverlays) {
+ planes->overlays = devm_kzalloc(dev->dev,
+ planes->noverlays *
+ sizeof(*planes->overlays),
+ GFP_KERNEL);
+ if (!planes->overlays)
+ return ERR_PTR(-ENOMEM);
+ }
+
+ props = atmel_hlcdc_plane_create_properties(dev);
+ if (IS_ERR(props))
+ return ERR_CAST(props);
+
+ planes->noverlays = 0;
+ for (i = 0; i < nlayers; i++) {
+ struct atmel_hlcdc_plane *plane;
+
+ if (descs[i].type == ATMEL_HLCDC_PP_LAYER)
+ continue;
+
+ plane = atmel_hlcdc_plane_create(dev, &descs[i], props);
+ if (IS_ERR(plane))
+ return ERR_CAST(plane);
+
+ plane->properties = props;
+
+ switch (descs[i].type) {
+ case ATMEL_HLCDC_BASE_LAYER:
+ if (planes->primary)
+ return ERR_PTR(-EINVAL);
+ planes->primary = plane;
+ break;
+
+ case ATMEL_HLCDC_OVERLAY_LAYER:
+ planes->overlays[planes->noverlays++] = plane;
+ break;
+
+ case ATMEL_HLCDC_CURSOR_LAYER:
+ if (planes->cursor)
+ return ERR_PTR(-EINVAL);
+ planes->cursor = plane;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return planes;
+}
diff --git a/drivers/gpu/drm/bochs/bochs_fbdev.c b/drivers/gpu/drm/bochs/bochs_fbdev.c
index 61dbf09dff5d..976d9798dc99 100644
--- a/drivers/gpu/drm/bochs/bochs_fbdev.c
+++ b/drivers/gpu/drm/bochs/bochs_fbdev.c
@@ -207,12 +207,22 @@ int bochs_fbdev_init(struct bochs_device *bochs)
if (ret)
return ret;
- drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
+ ret = drm_fb_helper_single_add_all_connectors(&bochs->fb.helper);
+ if (ret)
+ goto fini;
+
drm_helper_disable_unused_functions(bochs->dev);
- drm_fb_helper_initial_config(&bochs->fb.helper, 32);
+
+ ret = drm_fb_helper_initial_config(&bochs->fb.helper, 32);
+ if (ret)
+ goto fini;
bochs->fb.initialized = true;
return 0;
+
+fini:
+ drm_fb_helper_fini(&bochs->fb.helper);
+ return ret;
}
void bochs_fbdev_fini(struct bochs_device *bochs)
diff --git a/drivers/gpu/drm/bochs/bochs_kms.c b/drivers/gpu/drm/bochs/bochs_kms.c
index 85f0f8cf1fb8..26bcd03a8cb6 100644
--- a/drivers/gpu/drm/bochs/bochs_kms.c
+++ b/drivers/gpu/drm/bochs/bochs_kms.c
@@ -18,10 +18,6 @@ MODULE_PARM_DESC(defy, "default y resolution");
/* ---------------------------------------------------------------------- */
-static void bochs_crtc_load_lut(struct drm_crtc *crtc)
-{
-}
-
static void bochs_crtc_dpms(struct drm_crtc *crtc, int mode)
{
switch (mode) {
@@ -144,7 +140,6 @@ static const struct drm_crtc_helper_funcs bochs_helper_funcs = {
.mode_set_base = bochs_crtc_mode_set_base,
.prepare = bochs_crtc_prepare,
.commit = bochs_crtc_commit,
- .load_lut = bochs_crtc_load_lut,
};
static void bochs_crtc_init(struct drm_device *dev)
diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 884923f982d9..f38bbcdf929b 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -1,5 +1,13 @@
+config DRM_DW_HDMI
+ tristate
+ depends on DRM
+ select DRM_KMS_HELPER
+
config DRM_PTN3460
tristate "PTN3460 DP/LVDS bridge"
depends on DRM
+ depends on OF
select DRM_KMS_HELPER
+ select DRM_PANEL
---help---
+ ptn3460 eDP-LVDS bridge chip driver.
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index b4733e1fbd2e..d8a8cfd12fbb 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -1,3 +1,4 @@
ccflags-y := -Iinclude/drm
obj-$(CONFIG_DRM_PTN3460) += ptn3460.o
+obj-$(CONFIG_DRM_DW_HDMI) += dw_hdmi.o
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.c b/drivers/gpu/drm/bridge/dw_hdmi.c
new file mode 100644
index 000000000000..cd6a70647e32
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_hdmi.c
@@ -0,0 +1,1707 @@
+/*
+ * Copyright (C) 2011-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.
+ *
+ * Designware High-Definition Multimedia Interface (HDMI) driver
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ */
+#include <linux/module.h>
+#include <linux/irq.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/hdmi.h>
+#include <linux/of_device.h>
+
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include "dw_hdmi.h"
+
+#define HDMI_EDID_LEN 512
+
+#define RGB 0
+#define YCBCR444 1
+#define YCBCR422_16BITS 2
+#define YCBCR422_8BITS 3
+#define XVYCC444 4
+
+enum hdmi_datamap {
+ RGB444_8B = 0x01,
+ RGB444_10B = 0x03,
+ RGB444_12B = 0x05,
+ RGB444_16B = 0x07,
+ YCbCr444_8B = 0x09,
+ YCbCr444_10B = 0x0B,
+ YCbCr444_12B = 0x0D,
+ YCbCr444_16B = 0x0F,
+ YCbCr422_8B = 0x16,
+ YCbCr422_10B = 0x14,
+ YCbCr422_12B = 0x12,
+};
+
+static const u16 csc_coeff_default[3][4] = {
+ { 0x2000, 0x0000, 0x0000, 0x0000 },
+ { 0x0000, 0x2000, 0x0000, 0x0000 },
+ { 0x0000, 0x0000, 0x2000, 0x0000 }
+};
+
+static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
+ { 0x2000, 0x6926, 0x74fd, 0x010e },
+ { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
+ { 0x2000, 0x0000, 0x38b4, 0x7e3b }
+};
+
+static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
+ { 0x2000, 0x7106, 0x7a02, 0x00a7 },
+ { 0x2000, 0x3264, 0x0000, 0x7e6d },
+ { 0x2000, 0x0000, 0x3b61, 0x7e25 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
+ { 0x2591, 0x1322, 0x074b, 0x0000 },
+ { 0x6535, 0x2000, 0x7acc, 0x0200 },
+ { 0x6acd, 0x7534, 0x2000, 0x0200 }
+};
+
+static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
+ { 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
+ { 0x62f0, 0x2000, 0x7d11, 0x0200 },
+ { 0x6756, 0x78ab, 0x2000, 0x0200 }
+};
+
+struct hdmi_vmode {
+ bool mdvi;
+ bool mhsyncpolarity;
+ bool mvsyncpolarity;
+ bool minterlaced;
+ bool mdataenablepolarity;
+
+ unsigned int mpixelclock;
+ unsigned int mpixelrepetitioninput;
+ unsigned int mpixelrepetitionoutput;
+};
+
+struct hdmi_data_info {
+ unsigned int enc_in_format;
+ unsigned int enc_out_format;
+ unsigned int enc_color_depth;
+ unsigned int colorimetry;
+ unsigned int pix_repet_factor;
+ unsigned int hdcp_enable;
+ struct hdmi_vmode video_mode;
+};
+
+struct dw_hdmi {
+ struct drm_connector connector;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+
+ enum dw_hdmi_devtype dev_type;
+ struct device *dev;
+ struct clk *isfr_clk;
+ struct clk *iahb_clk;
+
+ struct hdmi_data_info hdmi_data;
+ const struct dw_hdmi_plat_data *plat_data;
+
+ int vic;
+
+ u8 edid[HDMI_EDID_LEN];
+ bool cable_plugin;
+
+ bool phy_enabled;
+ struct drm_display_mode previous_mode;
+
+ struct regmap *regmap;
+ struct i2c_adapter *ddc;
+ void __iomem *regs;
+
+ unsigned int sample_rate;
+ int ratio;
+
+ void (*write)(struct dw_hdmi *hdmi, u8 val, int offset);
+ u8 (*read)(struct dw_hdmi *hdmi, int offset);
+};
+
+static void dw_hdmi_writel(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writel(val, hdmi->regs + (offset << 2));
+}
+
+static u8 dw_hdmi_readl(struct dw_hdmi *hdmi, int offset)
+{
+ return readl(hdmi->regs + (offset << 2));
+}
+
+static void dw_hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ writeb(val, hdmi->regs + offset);
+}
+
+static u8 dw_hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return readb(hdmi->regs + offset);
+}
+
+static inline void hdmi_writeb(struct dw_hdmi *hdmi, u8 val, int offset)
+{
+ hdmi->write(hdmi, val, offset);
+}
+
+static inline u8 hdmi_readb(struct dw_hdmi *hdmi, int offset)
+{
+ return hdmi->read(hdmi, offset);
+}
+
+static void hdmi_modb(struct dw_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
+{
+ u8 val = hdmi_readb(hdmi, reg) & ~mask;
+
+ val |= data & mask;
+ hdmi_writeb(hdmi, val, reg);
+}
+
+static void hdmi_mask_writeb(struct dw_hdmi *hdmi, u8 data, unsigned int reg,
+ u8 shift, u8 mask)
+{
+ hdmi_modb(hdmi, data << shift, mask, reg);
+}
+
+static void hdmi_set_clock_regenerator_n(struct dw_hdmi *hdmi,
+ unsigned int value)
+{
+ hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
+ hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
+ hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
+
+ /* nshift factor = 0 */
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
+}
+
+static void hdmi_regenerate_cts(struct dw_hdmi *hdmi, unsigned int cts)
+{
+ /* Must be set/cleared first */
+ hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+
+ hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
+ hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
+ hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
+ HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
+}
+
+static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
+ unsigned int ratio)
+{
+ unsigned int n = (128 * freq) / 1000;
+
+ switch (freq) {
+ case 32000:
+ if (pixel_clk == 25170000)
+ n = (ratio == 150) ? 9152 : 4576;
+ else if (pixel_clk == 27020000)
+ n = (ratio == 150) ? 8192 : 4096;
+ else if (pixel_clk == 74170000 || pixel_clk == 148350000)
+ n = 11648;
+ else
+ n = 4096;
+ break;
+
+ case 44100:
+ if (pixel_clk == 25170000)
+ n = 7007;
+ else if (pixel_clk == 74170000)
+ n = 17836;
+ else if (pixel_clk == 148350000)
+ n = (ratio == 150) ? 17836 : 8918;
+ else
+ n = 6272;
+ break;
+
+ case 48000:
+ if (pixel_clk == 25170000)
+ n = (ratio == 150) ? 9152 : 6864;
+ else if (pixel_clk == 27020000)
+ n = (ratio == 150) ? 8192 : 6144;
+ else if (pixel_clk == 74170000)
+ n = 11648;
+ else if (pixel_clk == 148350000)
+ n = (ratio == 150) ? 11648 : 5824;
+ else
+ n = 6144;
+ break;
+
+ case 88200:
+ n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
+ break;
+
+ case 96000:
+ n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
+ break;
+
+ case 176400:
+ n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
+ break;
+
+ case 192000:
+ n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
+ break;
+
+ default:
+ break;
+ }
+
+ return n;
+}
+
+static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
+ unsigned int ratio)
+{
+ unsigned int cts = 0;
+
+ pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
+ pixel_clk, ratio);
+
+ switch (freq) {
+ case 32000:
+ if (pixel_clk == 297000000) {
+ cts = 222750;
+ break;
+ }
+ case 48000:
+ case 96000:
+ case 192000:
+ switch (pixel_clk) {
+ case 25200000:
+ case 27000000:
+ case 54000000:
+ case 74250000:
+ case 148500000:
+ cts = pixel_clk / 1000;
+ break;
+ case 297000000:
+ cts = 247500;
+ break;
+ /*
+ * All other TMDS clocks are not supported by
+ * DWC_hdmi_tx. The TMDS clocks divided or
+ * multiplied by 1,001 coefficients are not
+ * supported.
+ */
+ default:
+ break;
+ }
+ break;
+ case 44100:
+ case 88200:
+ case 176400:
+ switch (pixel_clk) {
+ case 25200000:
+ cts = 28000;
+ break;
+ case 27000000:
+ cts = 30000;
+ break;
+ case 54000000:
+ cts = 60000;
+ break;
+ case 74250000:
+ cts = 82500;
+ break;
+ case 148500000:
+ cts = 165000;
+ break;
+ case 297000000:
+ cts = 247500;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ if (ratio == 100)
+ return cts;
+ return (cts * ratio) / 100;
+}
+
+static void hdmi_set_clk_regenerator(struct dw_hdmi *hdmi,
+ unsigned long pixel_clk)
+{
+ unsigned int clk_n, clk_cts;
+
+ clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
+ hdmi->ratio);
+ clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
+ hdmi->ratio);
+
+ if (!clk_cts) {
+ dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
+ __func__, pixel_clk);
+ return;
+ }
+
+ dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
+ __func__, hdmi->sample_rate, hdmi->ratio,
+ pixel_clk, clk_n, clk_cts);
+
+ hdmi_set_clock_regenerator_n(hdmi, clk_n);
+ hdmi_regenerate_cts(hdmi, clk_cts);
+}
+
+static void hdmi_init_clk_regenerator(struct dw_hdmi *hdmi)
+{
+ hdmi_set_clk_regenerator(hdmi, 74250000);
+}
+
+static void hdmi_clk_regenerator_update_pixel_clock(struct dw_hdmi *hdmi)
+{
+ hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
+}
+
+/*
+ * this submodule is responsible for the video data synchronization.
+ * for example, for RGB 4:4:4 input, the data map is defined as
+ * pin{47~40} <==> R[7:0]
+ * pin{31~24} <==> G[7:0]
+ * pin{15~8} <==> B[7:0]
+ */
+static void hdmi_video_sample(struct dw_hdmi *hdmi)
+{
+ int color_format = 0;
+ u8 val;
+
+ if (hdmi->hdmi_data.enc_in_format == RGB) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x01;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x03;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x05;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_format = 0x07;
+ else
+ return;
+ } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x09;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x0B;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x0D;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_format = 0x0F;
+ else
+ return;
+ } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_format = 0x16;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_format = 0x14;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_format = 0x12;
+ else
+ return;
+ }
+
+ val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
+ ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
+ HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
+ hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
+
+ /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
+ val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
+ hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
+ hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
+ hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
+ hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
+ hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
+ hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
+ hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
+}
+
+static int is_color_space_conversion(struct dw_hdmi *hdmi)
+{
+ return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
+}
+
+static int is_color_space_decimation(struct dw_hdmi *hdmi)
+{
+ if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
+ return 0;
+ if (hdmi->hdmi_data.enc_in_format == RGB ||
+ hdmi->hdmi_data.enc_in_format == YCBCR444)
+ return 1;
+ return 0;
+}
+
+static int is_color_space_interpolation(struct dw_hdmi *hdmi)
+{
+ if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
+ return 0;
+ if (hdmi->hdmi_data.enc_out_format == RGB ||
+ hdmi->hdmi_data.enc_out_format == YCBCR444)
+ return 1;
+ return 0;
+}
+
+static void dw_hdmi_update_csc_coeffs(struct dw_hdmi *hdmi)
+{
+ const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
+ unsigned i;
+ u32 csc_scale = 1;
+
+ if (is_color_space_conversion(hdmi)) {
+ if (hdmi->hdmi_data.enc_out_format == RGB) {
+ if (hdmi->hdmi_data.colorimetry ==
+ HDMI_COLORIMETRY_ITU_601)
+ csc_coeff = &csc_coeff_rgb_out_eitu601;
+ else
+ csc_coeff = &csc_coeff_rgb_out_eitu709;
+ } else if (hdmi->hdmi_data.enc_in_format == RGB) {
+ if (hdmi->hdmi_data.colorimetry ==
+ HDMI_COLORIMETRY_ITU_601)
+ csc_coeff = &csc_coeff_rgb_in_eitu601;
+ else
+ csc_coeff = &csc_coeff_rgb_in_eitu709;
+ csc_scale = 0;
+ }
+ }
+
+ /* The CSC registers are sequential, alternating MSB then LSB */
+ for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
+ u16 coeff_a = (*csc_coeff)[0][i];
+ u16 coeff_b = (*csc_coeff)[1][i];
+ u16 coeff_c = (*csc_coeff)[2][i];
+
+ hdmi_writeb(hdmi, coeff_a & 0xff, HDMI_CSC_COEF_A1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c & 0xff, HDMI_CSC_COEF_C1_LSB + i * 2);
+ hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
+ }
+
+ hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
+ HDMI_CSC_SCALE);
+}
+
+static void hdmi_video_csc(struct dw_hdmi *hdmi)
+{
+ int color_depth = 0;
+ int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
+ int decimation = 0;
+
+ /* YCC422 interpolation to 444 mode */
+ if (is_color_space_interpolation(hdmi))
+ interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
+ else if (is_color_space_decimation(hdmi))
+ decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
+
+ if (hdmi->hdmi_data.enc_color_depth == 8)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 10)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 12)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
+ else if (hdmi->hdmi_data.enc_color_depth == 16)
+ color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
+ else
+ return;
+
+ /* Configure the CSC registers */
+ hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
+ hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
+ HDMI_CSC_SCALE);
+
+ dw_hdmi_update_csc_coeffs(hdmi);
+}
+
+/*
+ * HDMI video packetizer is used to packetize the data.
+ * for example, if input is YCC422 mode or repeater is used,
+ * data should be repacked this module can be bypassed.
+ */
+static void hdmi_video_packetize(struct dw_hdmi *hdmi)
+{
+ unsigned int color_depth = 0;
+ unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
+ unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
+ struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
+ u8 val, vp_conf;
+
+ if (hdmi_data->enc_out_format == RGB ||
+ hdmi_data->enc_out_format == YCBCR444) {
+ if (!hdmi_data->enc_color_depth) {
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ } else if (hdmi_data->enc_color_depth == 8) {
+ color_depth = 4;
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
+ } else if (hdmi_data->enc_color_depth == 10) {
+ color_depth = 5;
+ } else if (hdmi_data->enc_color_depth == 12) {
+ color_depth = 6;
+ } else if (hdmi_data->enc_color_depth == 16) {
+ color_depth = 7;
+ } else {
+ return;
+ }
+ } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
+ if (!hdmi_data->enc_color_depth ||
+ hdmi_data->enc_color_depth == 8)
+ remap_size = HDMI_VP_REMAP_YCC422_16bit;
+ else if (hdmi_data->enc_color_depth == 10)
+ remap_size = HDMI_VP_REMAP_YCC422_20bit;
+ else if (hdmi_data->enc_color_depth == 12)
+ remap_size = HDMI_VP_REMAP_YCC422_24bit;
+ else
+ return;
+ output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
+ } else {
+ return;
+ }
+
+ /* set the packetizer registers */
+ val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
+ HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
+ ((hdmi_data->pix_repet_factor <<
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
+ hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
+
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
+
+ /* Data from pixel repeater block */
+ if (hdmi_data->pix_repet_factor > 1) {
+ vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
+ } else { /* data from packetizer block */
+ vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
+ }
+
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_PR_EN_MASK |
+ HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
+
+ hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
+ HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
+
+ hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
+
+ if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_ENABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_ENABLE;
+ } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
+ vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
+ HDMI_VP_CONF_PP_EN_DISABLE |
+ HDMI_VP_CONF_YCC422_EN_DISABLE;
+ } else {
+ return;
+ }
+
+ hdmi_modb(hdmi, vp_conf,
+ HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
+ HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
+
+ hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
+ HDMI_VP_STUFF_PP_STUFFING_MASK |
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
+
+ hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
+ HDMI_VP_CONF);
+}
+
+static inline void hdmi_phy_test_clear(struct dw_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
+ HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_enable(struct dw_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
+ HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_clock(struct dw_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
+ HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
+}
+
+static inline void hdmi_phy_test_din(struct dw_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
+}
+
+static inline void hdmi_phy_test_dout(struct dw_hdmi *hdmi,
+ unsigned char bit)
+{
+ hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
+}
+
+static bool hdmi_phy_wait_i2c_done(struct dw_hdmi *hdmi, int msec)
+{
+ u32 val;
+
+ while ((val = hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
+ if (msec-- == 0)
+ return false;
+ udelay(1000);
+ }
+ hdmi_writeb(hdmi, val, HDMI_IH_I2CMPHY_STAT0);
+
+ return true;
+}
+
+static void __hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
+{
+ hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
+ hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
+ hdmi_writeb(hdmi, (unsigned char)(data >> 8),
+ HDMI_PHY_I2CM_DATAO_1_ADDR);
+ hdmi_writeb(hdmi, (unsigned char)(data >> 0),
+ HDMI_PHY_I2CM_DATAO_0_ADDR);
+ hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
+ HDMI_PHY_I2CM_OPERATION_ADDR);
+ hdmi_phy_wait_i2c_done(hdmi, 1000);
+}
+
+static int hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
+ unsigned char addr)
+{
+ __hdmi_phy_i2c_write(hdmi, data, addr);
+ return 0;
+}
+
+static void dw_hdmi_phy_enable_power(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_PDZ_OFFSET,
+ HDMI_PHY_CONF0_PDZ_MASK);
+}
+
+static void dw_hdmi_phy_enable_tmds(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_ENTMDS_OFFSET,
+ HDMI_PHY_CONF0_ENTMDS_MASK);
+}
+
+static void dw_hdmi_phy_enable_spare(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SPARECTRL_OFFSET,
+ HDMI_PHY_CONF0_SPARECTRL_MASK);
+}
+
+static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
+ HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
+}
+
+static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
+ HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
+}
+
+static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
+ HDMI_PHY_CONF0_SELDATAENPOL_MASK);
+}
+
+static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
+{
+ hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
+ HDMI_PHY_CONF0_SELDIPIF_OFFSET,
+ HDMI_PHY_CONF0_SELDIPIF_MASK);
+}
+
+static int hdmi_phy_configure(struct dw_hdmi *hdmi, unsigned char prep,
+ unsigned char res, int cscon)
+{
+ unsigned res_idx, i;
+ u8 val, msec;
+ const struct dw_hdmi_mpll_config *mpll_config =
+ hdmi->plat_data->mpll_cfg;
+ const struct dw_hdmi_curr_ctrl *curr_ctrl = hdmi->plat_data->cur_ctr;
+ const struct dw_hdmi_sym_term *sym_term = hdmi->plat_data->sym_term;
+
+ if (prep)
+ return -EINVAL;
+
+ switch (res) {
+ case 0: /* color resolution 0 is 8 bit colour depth */
+ case 8:
+ res_idx = DW_HDMI_RES_8;
+ break;
+ case 10:
+ res_idx = DW_HDMI_RES_10;
+ break;
+ case 12:
+ res_idx = DW_HDMI_RES_12;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Enable csc path */
+ if (cscon)
+ val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
+ else
+ val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
+
+ hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
+
+ /* gen2 tx power off */
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+
+ /* gen2 pddq */
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+ /* PHY reset */
+ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
+ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
+
+ hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
+
+ hdmi_phy_test_clear(hdmi, 1);
+ hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
+ HDMI_PHY_I2CM_SLAVE_ADDR);
+ hdmi_phy_test_clear(hdmi, 0);
+
+ /* PLL/MPLL Cfg - always match on final entry */
+ for (i = 0; mpll_config[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ mpll_config[i].mpixelclock)
+ break;
+
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
+ hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
+
+ for (i = 0; curr_ctrl[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ curr_ctrl[i].mpixelclock)
+ break;
+
+ if (curr_ctrl[i].mpixelclock == (~0UL)) {
+ dev_err(hdmi->dev, "Pixel clock %d - unsupported by HDMI\n",
+ hdmi->hdmi_data.video_mode.mpixelclock);
+ return -EINVAL;
+ }
+
+ /* CURRCTRL */
+ hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
+
+ hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
+ hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
+
+ for (i = 0; sym_term[i].mpixelclock != (~0UL); i++)
+ if (hdmi->hdmi_data.video_mode.mpixelclock <=
+ sym_term[i].mpixelclock)
+ break;
+
+ /* RESISTANCE TERM 133Ohm Cfg */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].term, 0x19); /* TXTERM */
+ /* PREEMP Cgf 0.00 */
+ hdmi_phy_i2c_write(hdmi, sym_term[i].sym_ctr, 0x09); /* CKSYMTXCTRL */
+
+ /* TX/CK LVL 10 */
+ hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
+ /* REMOVE CLK TERM */
+ hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
+
+ dw_hdmi_phy_enable_power(hdmi, 1);
+
+ /* toggle TMDS enable */
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 1);
+
+ /* gen2 tx power on */
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+ if (hdmi->dev_type == RK3288_HDMI)
+ dw_hdmi_phy_enable_spare(hdmi, 1);
+
+ /*Wait for PHY PLL lock */
+ msec = 5;
+ do {
+ val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
+ if (!val)
+ break;
+
+ if (msec == 0) {
+ dev_err(hdmi->dev, "PHY PLL not locked\n");
+ return -ETIMEDOUT;
+ }
+
+ udelay(1000);
+ msec--;
+ } while (1);
+
+ return 0;
+}
+
+static int dw_hdmi_phy_init(struct dw_hdmi *hdmi)
+{
+ int i, ret;
+ bool cscon = false;
+
+ /*check csc whether needed activated in HDMI mode */
+ cscon = (is_color_space_conversion(hdmi) &&
+ !hdmi->hdmi_data.video_mode.mdvi);
+
+ /* HDMI Phy spec says to do the phy initialization sequence twice */
+ for (i = 0; i < 2; i++) {
+ dw_hdmi_phy_sel_data_en_pol(hdmi, 1);
+ dw_hdmi_phy_sel_interface_control(hdmi, 0);
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
+
+ /* Enable CSC */
+ ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
+ if (ret)
+ return ret;
+ }
+
+ hdmi->phy_enabled = true;
+ return 0;
+}
+
+static void hdmi_tx_hdcp_config(struct dw_hdmi *hdmi)
+{
+ u8 de;
+
+ if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
+ de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
+ else
+ de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
+
+ /* disable rx detect */
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
+ HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
+
+ hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
+
+ hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
+}
+
+static void hdmi_config_AVI(struct dw_hdmi *hdmi)
+{
+ u8 val, pix_fmt, under_scan;
+ u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
+ bool aspect_16_9;
+
+ aspect_16_9 = false; /* FIXME */
+
+ /* AVI Data Byte 1 */
+ if (hdmi->hdmi_data.enc_out_format == YCBCR444)
+ pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
+ else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
+ pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
+ else
+ pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
+
+ under_scan = HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
+
+ /*
+ * Active format identification data is present in the AVI InfoFrame.
+ * Under scan info, no bar data
+ */
+ val = pix_fmt | under_scan |
+ HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
+ HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
+
+ hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
+
+ /* AVI Data Byte 2 -Set the Aspect Ratio */
+ if (aspect_16_9) {
+ act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
+ coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
+ } else {
+ act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
+ coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
+ }
+
+ /* Set up colorimetry */
+ if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
+ if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+ ext_colorimetry =
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+ else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
+ ext_colorimetry =
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
+ } else if (hdmi->hdmi_data.enc_out_format != RGB) {
+ if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
+ else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
+ ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+ } else { /* Carries no data */
+ colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
+ ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
+ }
+
+ val = colorimetry | coded_ratio | act_ratio;
+ hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
+
+ /* AVI Data Byte 3 */
+ val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
+ HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
+ HDMI_FC_AVICONF2_SCALING_NONE;
+ hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
+
+ /* AVI Data Byte 4 */
+ hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
+
+ /* AVI Data Byte 5- set up input and output pixel repetition */
+ val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
+ ((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
+ HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
+ HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
+ hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
+
+ /* IT Content and quantization range = don't care */
+ val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
+ HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
+ hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
+
+ /* AVI Data Bytes 6-13 */
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
+ hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
+}
+
+static void hdmi_av_composer(struct dw_hdmi *hdmi,
+ const struct drm_display_mode *mode)
+{
+ u8 inv_val;
+ struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
+ int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
+
+ vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
+ vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
+ vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+ vmode->mpixelclock = mode->clock * 1000;
+
+ dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
+
+ /* Set up HDMI_FC_INVIDCONF */
+ inv_val = (hdmi->hdmi_data.hdcp_enable ?
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
+
+ inv_val |= (vmode->mvsyncpolarity ?
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
+
+ inv_val |= (vmode->mhsyncpolarity ?
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
+
+ inv_val |= (vmode->mdataenablepolarity ?
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
+
+ if (hdmi->vic == 39)
+ inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
+ else
+ inv_val |= (vmode->minterlaced ?
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
+
+ inv_val |= (vmode->minterlaced ?
+ HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
+ HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
+
+ inv_val |= (vmode->mdvi ?
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
+
+ hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
+
+ /* Set up horizontal active pixel width */
+ hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
+ hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
+
+ /* Set up vertical active lines */
+ hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
+ hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
+
+ /* Set up horizontal blanking pixel region width */
+ hblank = mode->htotal - mode->hdisplay;
+ hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
+ hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
+
+ /* Set up vertical blanking pixel region width */
+ vblank = mode->vtotal - mode->vdisplay;
+ hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
+
+ /* Set up HSYNC active edge delay width (in pixel clks) */
+ h_de_hs = mode->hsync_start - mode->hdisplay;
+ hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
+ hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
+
+ /* Set up VSYNC active edge delay (in lines) */
+ v_de_vs = mode->vsync_start - mode->vdisplay;
+ hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
+
+ /* Set up HSYNC active pulse width (in pixel clks) */
+ hsync_len = mode->hsync_end - mode->hsync_start;
+ hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
+ hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
+
+ /* Set up VSYNC active edge delay (in lines) */
+ vsync_len = mode->vsync_end - mode->vsync_start;
+ hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
+}
+
+static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi)
+{
+ if (!hdmi->phy_enabled)
+ return;
+
+ dw_hdmi_phy_enable_tmds(hdmi, 0);
+ dw_hdmi_phy_enable_power(hdmi, 0);
+
+ hdmi->phy_enabled = false;
+}
+
+/* HDMI Initialization Step B.4 */
+static void dw_hdmi_enable_video_path(struct dw_hdmi *hdmi)
+{
+ u8 clkdis;
+
+ /* control period minimum duration */
+ hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
+ hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
+ hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
+
+ /* Set to fill TMDS data channels */
+ hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
+ hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
+ hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
+
+ /* Enable pixel clock and tmds data path */
+ clkdis = 0x7F;
+ clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
+ hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+ clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
+ hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+
+ /* Enable csc path */
+ if (is_color_space_conversion(hdmi)) {
+ clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
+ hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
+ }
+}
+
+static void hdmi_enable_audio_clk(struct dw_hdmi *hdmi)
+{
+ hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
+}
+
+/* Workaround to clear the overflow condition */
+static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
+{
+ int count;
+ u8 val;
+
+ /* TMDS software reset */
+ hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
+
+ val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
+ if (hdmi->dev_type == IMX6DL_HDMI) {
+ hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+ return;
+ }
+
+ for (count = 0; count < 4; count++)
+ hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
+}
+
+static void hdmi_enable_overflow_interrupts(struct dw_hdmi *hdmi)
+{
+ hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
+ hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
+}
+
+static void hdmi_disable_overflow_interrupts(struct dw_hdmi *hdmi)
+{
+ hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
+ HDMI_IH_MUTE_FC_STAT2);
+}
+
+static int dw_hdmi_setup(struct dw_hdmi *hdmi, struct drm_display_mode *mode)
+{
+ int ret;
+
+ hdmi_disable_overflow_interrupts(hdmi);
+
+ hdmi->vic = drm_match_cea_mode(mode);
+
+ if (!hdmi->vic) {
+ dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
+ hdmi->hdmi_data.video_mode.mdvi = true;
+ } else {
+ dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
+ hdmi->hdmi_data.video_mode.mdvi = false;
+ }
+
+ if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
+ (hdmi->vic == 21) || (hdmi->vic == 22) ||
+ (hdmi->vic == 2) || (hdmi->vic == 3) ||
+ (hdmi->vic == 17) || (hdmi->vic == 18))
+ hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
+ else
+ hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
+
+ if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
+ (hdmi->vic == 12) || (hdmi->vic == 13) ||
+ (hdmi->vic == 14) || (hdmi->vic == 15) ||
+ (hdmi->vic == 25) || (hdmi->vic == 26) ||
+ (hdmi->vic == 27) || (hdmi->vic == 28) ||
+ (hdmi->vic == 29) || (hdmi->vic == 30) ||
+ (hdmi->vic == 35) || (hdmi->vic == 36) ||
+ (hdmi->vic == 37) || (hdmi->vic == 38))
+ hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
+ else
+ hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
+
+ hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
+
+ /* TODO: Get input format from IPU (via FB driver interface) */
+ hdmi->hdmi_data.enc_in_format = RGB;
+
+ hdmi->hdmi_data.enc_out_format = RGB;
+
+ hdmi->hdmi_data.enc_color_depth = 8;
+ hdmi->hdmi_data.pix_repet_factor = 0;
+ hdmi->hdmi_data.hdcp_enable = 0;
+ hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
+
+ /* HDMI Initialization Step B.1 */
+ hdmi_av_composer(hdmi, mode);
+
+ /* HDMI Initializateion Step B.2 */
+ ret = dw_hdmi_phy_init(hdmi);
+ if (ret)
+ return ret;
+
+ /* HDMI Initialization Step B.3 */
+ dw_hdmi_enable_video_path(hdmi);
+
+ /* not for DVI mode */
+ if (hdmi->hdmi_data.video_mode.mdvi) {
+ dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
+ } else {
+ dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
+
+ /* HDMI Initialization Step E - Configure audio */
+ hdmi_clk_regenerator_update_pixel_clock(hdmi);
+ hdmi_enable_audio_clk(hdmi);
+
+ /* HDMI Initialization Step F - Configure AVI InfoFrame */
+ hdmi_config_AVI(hdmi);
+ }
+
+ hdmi_video_packetize(hdmi);
+ hdmi_video_csc(hdmi);
+ hdmi_video_sample(hdmi);
+ hdmi_tx_hdcp_config(hdmi);
+
+ dw_hdmi_clear_overflow(hdmi);
+ if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
+ hdmi_enable_overflow_interrupts(hdmi);
+
+ return 0;
+}
+
+/* Wait until we are registered to enable interrupts */
+static int dw_hdmi_fb_registered(struct dw_hdmi *hdmi)
+{
+ hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
+ HDMI_PHY_I2CM_INT_ADDR);
+
+ hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
+ HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
+ HDMI_PHY_I2CM_CTLINT_ADDR);
+
+ /* enable cable hot plug irq */
+ hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
+
+ /* Clear Hotplug interrupts */
+ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+ return 0;
+}
+
+static void initialize_hdmi_ih_mutes(struct dw_hdmi *hdmi)
+{
+ u8 ih_mute;
+
+ /*
+ * Boot up defaults are:
+ * HDMI_IH_MUTE = 0x03 (disabled)
+ * HDMI_IH_MUTE_* = 0x00 (enabled)
+ *
+ * Disable top level interrupt bits in HDMI block
+ */
+ ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
+ HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
+
+ hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+
+ /* by default mask all interrupts */
+ hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
+ hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
+ hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
+ hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
+ hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
+ hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
+ hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
+ hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
+ hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
+ hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
+ hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
+ hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
+ hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
+ hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
+ hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
+
+ /* Disable interrupts in the IH_MUTE_* registers */
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
+ hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
+
+ /* Enable top level interrupt bits in HDMI block */
+ ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
+ hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
+}
+
+static void dw_hdmi_poweron(struct dw_hdmi *hdmi)
+{
+ dw_hdmi_setup(hdmi, &hdmi->previous_mode);
+}
+
+static void dw_hdmi_poweroff(struct dw_hdmi *hdmi)
+{
+ dw_hdmi_phy_disable(hdmi);
+}
+
+static void dw_hdmi_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_setup(hdmi, mode);
+
+ /* Store the display mode for plugin/DKMS poweron events */
+ memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
+}
+
+static bool dw_hdmi_bridge_mode_fixup(struct drm_bridge *bridge,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_bridge_disable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweroff(hdmi);
+}
+
+static void dw_hdmi_bridge_enable(struct drm_bridge *bridge)
+{
+ struct dw_hdmi *hdmi = bridge->driver_private;
+
+ dw_hdmi_poweron(hdmi);
+}
+
+static void dw_hdmi_bridge_nop(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
+static enum drm_connector_status
+dw_hdmi_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+ connector);
+
+ return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
+ connector_status_connected : connector_status_disconnected;
+}
+
+static int dw_hdmi_connector_get_modes(struct drm_connector *connector)
+{
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+ connector);
+ struct edid *edid;
+ int ret;
+
+ if (!hdmi->ddc)
+ return 0;
+
+ edid = drm_get_edid(connector, hdmi->ddc);
+ if (edid) {
+ dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
+ edid->width_cm, edid->height_cm);
+
+ drm_mode_connector_update_edid_property(connector, edid);
+ ret = drm_add_edid_modes(connector, edid);
+ kfree(edid);
+ } else {
+ dev_dbg(hdmi->dev, "failed to get edid\n");
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct dw_hdmi *hdmi = container_of(connector,
+ struct dw_hdmi, connector);
+ enum drm_mode_status mode_status = MODE_OK;
+
+ if (hdmi->plat_data->mode_valid)
+ mode_status = hdmi->plat_data->mode_valid(connector, mode);
+
+ return mode_status;
+}
+
+static struct drm_encoder *dw_hdmi_connector_best_encoder(struct drm_connector
+ *connector)
+{
+ struct dw_hdmi *hdmi = container_of(connector, struct dw_hdmi,
+ connector);
+
+ return hdmi->encoder;
+}
+
+static void dw_hdmi_connector_destroy(struct drm_connector *connector)
+{
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs dw_hdmi_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = dw_hdmi_connector_detect,
+ .destroy = dw_hdmi_connector_destroy,
+};
+
+static struct drm_connector_helper_funcs dw_hdmi_connector_helper_funcs = {
+ .get_modes = dw_hdmi_connector_get_modes,
+ .mode_valid = dw_hdmi_connector_mode_valid,
+ .best_encoder = dw_hdmi_connector_best_encoder,
+};
+
+struct drm_bridge_funcs dw_hdmi_bridge_funcs = {
+ .enable = dw_hdmi_bridge_enable,
+ .disable = dw_hdmi_bridge_disable,
+ .pre_enable = dw_hdmi_bridge_nop,
+ .post_disable = dw_hdmi_bridge_nop,
+ .mode_set = dw_hdmi_bridge_mode_set,
+ .mode_fixup = dw_hdmi_bridge_mode_fixup,
+};
+
+static irqreturn_t dw_hdmi_hardirq(int irq, void *dev_id)
+{
+ struct dw_hdmi *hdmi = dev_id;
+ u8 intr_stat;
+
+ intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+ if (intr_stat)
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
+}
+
+static irqreturn_t dw_hdmi_irq(int irq, void *dev_id)
+{
+ struct dw_hdmi *hdmi = dev_id;
+ u8 intr_stat;
+ u8 phy_int_pol;
+
+ intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
+
+ phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
+
+ if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
+ if (phy_int_pol & HDMI_PHY_HPD) {
+ dev_dbg(hdmi->dev, "EVENT=plugin\n");
+
+ hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+ dw_hdmi_poweron(hdmi);
+ } else {
+ dev_dbg(hdmi->dev, "EVENT=plugout\n");
+
+ hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
+ HDMI_PHY_POL0);
+
+ dw_hdmi_poweroff(hdmi);
+ }
+ drm_helper_hpd_irq_event(hdmi->connector.dev);
+ }
+
+ hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+ return IRQ_HANDLED;
+}
+
+static int dw_hdmi_register(struct drm_device *drm, struct dw_hdmi *hdmi)
+{
+ struct drm_encoder *encoder = hdmi->encoder;
+ struct drm_bridge *bridge;
+ int ret;
+
+ bridge = devm_kzalloc(drm->dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge) {
+ DRM_ERROR("Failed to allocate drm bridge\n");
+ return -ENOMEM;
+ }
+
+ hdmi->bridge = bridge;
+ bridge->driver_private = hdmi;
+ bridge->funcs = &dw_hdmi_bridge_funcs;
+ ret = drm_bridge_attach(drm, bridge);
+ if (ret) {
+ DRM_ERROR("Failed to initialize bridge with drm\n");
+ return -EINVAL;
+ }
+
+ encoder->bridge = bridge;
+ hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_helper_add(&hdmi->connector,
+ &dw_hdmi_connector_helper_funcs);
+ drm_connector_init(drm, &hdmi->connector, &dw_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+
+ hdmi->connector.encoder = encoder;
+
+ drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
+
+ return 0;
+}
+
+int dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data, struct drm_encoder *encoder,
+ struct resource *iores, int irq,
+ const struct dw_hdmi_plat_data *plat_data)
+{
+ struct drm_device *drm = data;
+ struct device_node *np = dev->of_node;
+ struct device_node *ddc_node;
+ struct dw_hdmi *hdmi;
+ int ret;
+ u32 val = 1;
+
+ hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ hdmi->plat_data = plat_data;
+ hdmi->dev = dev;
+ hdmi->dev_type = plat_data->dev_type;
+ hdmi->sample_rate = 48000;
+ hdmi->ratio = 100;
+ hdmi->encoder = encoder;
+
+ of_property_read_u32(np, "reg-io-width", &val);
+
+ switch (val) {
+ case 4:
+ hdmi->write = dw_hdmi_writel;
+ hdmi->read = dw_hdmi_readl;
+ break;
+ case 1:
+ hdmi->write = dw_hdmi_writeb;
+ hdmi->read = dw_hdmi_readb;
+ break;
+ default:
+ dev_err(dev, "reg-io-width must be 1 or 4\n");
+ return -EINVAL;
+ }
+
+ ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
+ if (ddc_node) {
+ hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
+ of_node_put(ddc_node);
+ if (!hdmi->ddc) {
+ dev_dbg(hdmi->dev, "failed to read ddc node\n");
+ return -EPROBE_DEFER;
+ }
+
+ } else {
+ dev_dbg(hdmi->dev, "no ddc property found\n");
+ }
+
+ hdmi->regs = devm_ioremap_resource(dev, iores);
+ if (IS_ERR(hdmi->regs))
+ return PTR_ERR(hdmi->regs);
+
+ hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
+ if (IS_ERR(hdmi->isfr_clk)) {
+ ret = PTR_ERR(hdmi->isfr_clk);
+ dev_err(hdmi->dev, "Unable to get HDMI isfr clk: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(hdmi->isfr_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI isfr clock: %d\n", ret);
+ return ret;
+ }
+
+ hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
+ if (IS_ERR(hdmi->iahb_clk)) {
+ ret = PTR_ERR(hdmi->iahb_clk);
+ dev_err(hdmi->dev, "Unable to get HDMI iahb clk: %d\n", ret);
+ goto err_isfr;
+ }
+
+ ret = clk_prepare_enable(hdmi->iahb_clk);
+ if (ret) {
+ dev_err(hdmi->dev, "Cannot enable HDMI iahb clock: %d\n", ret);
+ goto err_isfr;
+ }
+
+ /* Product and revision IDs */
+ dev_info(dev,
+ "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
+ hdmi_readb(hdmi, HDMI_DESIGN_ID),
+ hdmi_readb(hdmi, HDMI_REVISION_ID),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
+ hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
+
+ initialize_hdmi_ih_mutes(hdmi);
+
+ ret = devm_request_threaded_irq(dev, irq, dw_hdmi_hardirq,
+ dw_hdmi_irq, IRQF_SHARED,
+ dev_name(dev), hdmi);
+ if (ret)
+ goto err_iahb;
+
+ /*
+ * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
+ * N and cts values before enabling phy
+ */
+ hdmi_init_clk_regenerator(hdmi);
+
+ /*
+ * Configure registers related to HDMI interrupt
+ * generation before registering IRQ.
+ */
+ hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
+
+ /* Clear Hotplug interrupts */
+ hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
+
+ ret = dw_hdmi_fb_registered(hdmi);
+ if (ret)
+ goto err_iahb;
+
+ ret = dw_hdmi_register(drm, hdmi);
+ if (ret)
+ goto err_iahb;
+
+ /* Unmute interrupts */
+ hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
+
+ dev_set_drvdata(dev, hdmi);
+
+ return 0;
+
+err_iahb:
+ clk_disable_unprepare(hdmi->iahb_clk);
+err_isfr:
+ clk_disable_unprepare(hdmi->isfr_clk);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_bind);
+
+void dw_hdmi_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct dw_hdmi *hdmi = dev_get_drvdata(dev);
+
+ /* Disable all interrupts */
+ hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
+
+ hdmi->connector.funcs->destroy(&hdmi->connector);
+ hdmi->encoder->funcs->destroy(hdmi->encoder);
+
+ clk_disable_unprepare(hdmi->iahb_clk);
+ clk_disable_unprepare(hdmi->isfr_clk);
+ i2c_put_adapter(hdmi->ddc);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_unbind);
+
+MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("DW HDMI transmitter driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dw-hdmi");
diff --git a/drivers/gpu/drm/bridge/dw_hdmi.h b/drivers/gpu/drm/bridge/dw_hdmi.h
new file mode 100644
index 000000000000..175dbc89a824
--- /dev/null
+++ b/drivers/gpu/drm/bridge/dw_hdmi.h
@@ -0,0 +1,1034 @@
+/*
+ * Copyright (C) 2011 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef __IMX_HDMI_H__
+#define __IMX_HDMI_H__
+
+/* Identification Registers */
+#define HDMI_DESIGN_ID 0x0000
+#define HDMI_REVISION_ID 0x0001
+#define HDMI_PRODUCT_ID0 0x0002
+#define HDMI_PRODUCT_ID1 0x0003
+#define HDMI_CONFIG0_ID 0x0004
+#define HDMI_CONFIG1_ID 0x0005
+#define HDMI_CONFIG2_ID 0x0006
+#define HDMI_CONFIG3_ID 0x0007
+
+/* Interrupt Registers */
+#define HDMI_IH_FC_STAT0 0x0100
+#define HDMI_IH_FC_STAT1 0x0101
+#define HDMI_IH_FC_STAT2 0x0102
+#define HDMI_IH_AS_STAT0 0x0103
+#define HDMI_IH_PHY_STAT0 0x0104
+#define HDMI_IH_I2CM_STAT0 0x0105
+#define HDMI_IH_CEC_STAT0 0x0106
+#define HDMI_IH_VP_STAT0 0x0107
+#define HDMI_IH_I2CMPHY_STAT0 0x0108
+#define HDMI_IH_AHBDMAAUD_STAT0 0x0109
+
+#define HDMI_IH_MUTE_FC_STAT0 0x0180
+#define HDMI_IH_MUTE_FC_STAT1 0x0181
+#define HDMI_IH_MUTE_FC_STAT2 0x0182
+#define HDMI_IH_MUTE_AS_STAT0 0x0183
+#define HDMI_IH_MUTE_PHY_STAT0 0x0184
+#define HDMI_IH_MUTE_I2CM_STAT0 0x0185
+#define HDMI_IH_MUTE_CEC_STAT0 0x0186
+#define HDMI_IH_MUTE_VP_STAT0 0x0187
+#define HDMI_IH_MUTE_I2CMPHY_STAT0 0x0188
+#define HDMI_IH_MUTE_AHBDMAAUD_STAT0 0x0189
+#define HDMI_IH_MUTE 0x01FF
+
+/* Video Sample Registers */
+#define HDMI_TX_INVID0 0x0200
+#define HDMI_TX_INSTUFFING 0x0201
+#define HDMI_TX_GYDATA0 0x0202
+#define HDMI_TX_GYDATA1 0x0203
+#define HDMI_TX_RCRDATA0 0x0204
+#define HDMI_TX_RCRDATA1 0x0205
+#define HDMI_TX_BCBDATA0 0x0206
+#define HDMI_TX_BCBDATA1 0x0207
+
+/* Video Packetizer Registers */
+#define HDMI_VP_STATUS 0x0800
+#define HDMI_VP_PR_CD 0x0801
+#define HDMI_VP_STUFF 0x0802
+#define HDMI_VP_REMAP 0x0803
+#define HDMI_VP_CONF 0x0804
+#define HDMI_VP_STAT 0x0805
+#define HDMI_VP_INT 0x0806
+#define HDMI_VP_MASK 0x0807
+#define HDMI_VP_POL 0x0808
+
+/* Frame Composer Registers */
+#define HDMI_FC_INVIDCONF 0x1000
+#define HDMI_FC_INHACTV0 0x1001
+#define HDMI_FC_INHACTV1 0x1002
+#define HDMI_FC_INHBLANK0 0x1003
+#define HDMI_FC_INHBLANK1 0x1004
+#define HDMI_FC_INVACTV0 0x1005
+#define HDMI_FC_INVACTV1 0x1006
+#define HDMI_FC_INVBLANK 0x1007
+#define HDMI_FC_HSYNCINDELAY0 0x1008
+#define HDMI_FC_HSYNCINDELAY1 0x1009
+#define HDMI_FC_HSYNCINWIDTH0 0x100A
+#define HDMI_FC_HSYNCINWIDTH1 0x100B
+#define HDMI_FC_VSYNCINDELAY 0x100C
+#define HDMI_FC_VSYNCINWIDTH 0x100D
+#define HDMI_FC_INFREQ0 0x100E
+#define HDMI_FC_INFREQ1 0x100F
+#define HDMI_FC_INFREQ2 0x1010
+#define HDMI_FC_CTRLDUR 0x1011
+#define HDMI_FC_EXCTRLDUR 0x1012
+#define HDMI_FC_EXCTRLSPAC 0x1013
+#define HDMI_FC_CH0PREAM 0x1014
+#define HDMI_FC_CH1PREAM 0x1015
+#define HDMI_FC_CH2PREAM 0x1016
+#define HDMI_FC_AVICONF3 0x1017
+#define HDMI_FC_GCP 0x1018
+#define HDMI_FC_AVICONF0 0x1019
+#define HDMI_FC_AVICONF1 0x101A
+#define HDMI_FC_AVICONF2 0x101B
+#define HDMI_FC_AVIVID 0x101C
+#define HDMI_FC_AVIETB0 0x101D
+#define HDMI_FC_AVIETB1 0x101E
+#define HDMI_FC_AVISBB0 0x101F
+#define HDMI_FC_AVISBB1 0x1020
+#define HDMI_FC_AVIELB0 0x1021
+#define HDMI_FC_AVIELB1 0x1022
+#define HDMI_FC_AVISRB0 0x1023
+#define HDMI_FC_AVISRB1 0x1024
+#define HDMI_FC_AUDICONF0 0x1025
+#define HDMI_FC_AUDICONF1 0x1026
+#define HDMI_FC_AUDICONF2 0x1027
+#define HDMI_FC_AUDICONF3 0x1028
+#define HDMI_FC_VSDIEEEID0 0x1029
+#define HDMI_FC_VSDSIZE 0x102A
+#define HDMI_FC_VSDIEEEID1 0x1030
+#define HDMI_FC_VSDIEEEID2 0x1031
+#define HDMI_FC_VSDPAYLOAD0 0x1032
+#define HDMI_FC_VSDPAYLOAD1 0x1033
+#define HDMI_FC_VSDPAYLOAD2 0x1034
+#define HDMI_FC_VSDPAYLOAD3 0x1035
+#define HDMI_FC_VSDPAYLOAD4 0x1036
+#define HDMI_FC_VSDPAYLOAD5 0x1037
+#define HDMI_FC_VSDPAYLOAD6 0x1038
+#define HDMI_FC_VSDPAYLOAD7 0x1039
+#define HDMI_FC_VSDPAYLOAD8 0x103A
+#define HDMI_FC_VSDPAYLOAD9 0x103B
+#define HDMI_FC_VSDPAYLOAD10 0x103C
+#define HDMI_FC_VSDPAYLOAD11 0x103D
+#define HDMI_FC_VSDPAYLOAD12 0x103E
+#define HDMI_FC_VSDPAYLOAD13 0x103F
+#define HDMI_FC_VSDPAYLOAD14 0x1040
+#define HDMI_FC_VSDPAYLOAD15 0x1041
+#define HDMI_FC_VSDPAYLOAD16 0x1042
+#define HDMI_FC_VSDPAYLOAD17 0x1043
+#define HDMI_FC_VSDPAYLOAD18 0x1044
+#define HDMI_FC_VSDPAYLOAD19 0x1045
+#define HDMI_FC_VSDPAYLOAD20 0x1046
+#define HDMI_FC_VSDPAYLOAD21 0x1047
+#define HDMI_FC_VSDPAYLOAD22 0x1048
+#define HDMI_FC_VSDPAYLOAD23 0x1049
+#define HDMI_FC_SPDVENDORNAME0 0x104A
+#define HDMI_FC_SPDVENDORNAME1 0x104B
+#define HDMI_FC_SPDVENDORNAME2 0x104C
+#define HDMI_FC_SPDVENDORNAME3 0x104D
+#define HDMI_FC_SPDVENDORNAME4 0x104E
+#define HDMI_FC_SPDVENDORNAME5 0x104F
+#define HDMI_FC_SPDVENDORNAME6 0x1050
+#define HDMI_FC_SPDVENDORNAME7 0x1051
+#define HDMI_FC_SDPPRODUCTNAME0 0x1052
+#define HDMI_FC_SDPPRODUCTNAME1 0x1053
+#define HDMI_FC_SDPPRODUCTNAME2 0x1054
+#define HDMI_FC_SDPPRODUCTNAME3 0x1055
+#define HDMI_FC_SDPPRODUCTNAME4 0x1056
+#define HDMI_FC_SDPPRODUCTNAME5 0x1057
+#define HDMI_FC_SDPPRODUCTNAME6 0x1058
+#define HDMI_FC_SDPPRODUCTNAME7 0x1059
+#define HDMI_FC_SDPPRODUCTNAME8 0x105A
+#define HDMI_FC_SDPPRODUCTNAME9 0x105B
+#define HDMI_FC_SDPPRODUCTNAME10 0x105C
+#define HDMI_FC_SDPPRODUCTNAME11 0x105D
+#define HDMI_FC_SDPPRODUCTNAME12 0x105E
+#define HDMI_FC_SDPPRODUCTNAME13 0x105F
+#define HDMI_FC_SDPPRODUCTNAME14 0x1060
+#define HDMI_FC_SPDPRODUCTNAME15 0x1061
+#define HDMI_FC_SPDDEVICEINF 0x1062
+#define HDMI_FC_AUDSCONF 0x1063
+#define HDMI_FC_AUDSSTAT 0x1064
+#define HDMI_FC_DATACH0FILL 0x1070
+#define HDMI_FC_DATACH1FILL 0x1071
+#define HDMI_FC_DATACH2FILL 0x1072
+#define HDMI_FC_CTRLQHIGH 0x1073
+#define HDMI_FC_CTRLQLOW 0x1074
+#define HDMI_FC_ACP0 0x1075
+#define HDMI_FC_ACP28 0x1076
+#define HDMI_FC_ACP27 0x1077
+#define HDMI_FC_ACP26 0x1078
+#define HDMI_FC_ACP25 0x1079
+#define HDMI_FC_ACP24 0x107A
+#define HDMI_FC_ACP23 0x107B
+#define HDMI_FC_ACP22 0x107C
+#define HDMI_FC_ACP21 0x107D
+#define HDMI_FC_ACP20 0x107E
+#define HDMI_FC_ACP19 0x107F
+#define HDMI_FC_ACP18 0x1080
+#define HDMI_FC_ACP17 0x1081
+#define HDMI_FC_ACP16 0x1082
+#define HDMI_FC_ACP15 0x1083
+#define HDMI_FC_ACP14 0x1084
+#define HDMI_FC_ACP13 0x1085
+#define HDMI_FC_ACP12 0x1086
+#define HDMI_FC_ACP11 0x1087
+#define HDMI_FC_ACP10 0x1088
+#define HDMI_FC_ACP9 0x1089
+#define HDMI_FC_ACP8 0x108A
+#define HDMI_FC_ACP7 0x108B
+#define HDMI_FC_ACP6 0x108C
+#define HDMI_FC_ACP5 0x108D
+#define HDMI_FC_ACP4 0x108E
+#define HDMI_FC_ACP3 0x108F
+#define HDMI_FC_ACP2 0x1090
+#define HDMI_FC_ACP1 0x1091
+#define HDMI_FC_ISCR1_0 0x1092
+#define HDMI_FC_ISCR1_16 0x1093
+#define HDMI_FC_ISCR1_15 0x1094
+#define HDMI_FC_ISCR1_14 0x1095
+#define HDMI_FC_ISCR1_13 0x1096
+#define HDMI_FC_ISCR1_12 0x1097
+#define HDMI_FC_ISCR1_11 0x1098
+#define HDMI_FC_ISCR1_10 0x1099
+#define HDMI_FC_ISCR1_9 0x109A
+#define HDMI_FC_ISCR1_8 0x109B
+#define HDMI_FC_ISCR1_7 0x109C
+#define HDMI_FC_ISCR1_6 0x109D
+#define HDMI_FC_ISCR1_5 0x109E
+#define HDMI_FC_ISCR1_4 0x109F
+#define HDMI_FC_ISCR1_3 0x10A0
+#define HDMI_FC_ISCR1_2 0x10A1
+#define HDMI_FC_ISCR1_1 0x10A2
+#define HDMI_FC_ISCR2_15 0x10A3
+#define HDMI_FC_ISCR2_14 0x10A4
+#define HDMI_FC_ISCR2_13 0x10A5
+#define HDMI_FC_ISCR2_12 0x10A6
+#define HDMI_FC_ISCR2_11 0x10A7
+#define HDMI_FC_ISCR2_10 0x10A8
+#define HDMI_FC_ISCR2_9 0x10A9
+#define HDMI_FC_ISCR2_8 0x10AA
+#define HDMI_FC_ISCR2_7 0x10AB
+#define HDMI_FC_ISCR2_6 0x10AC
+#define HDMI_FC_ISCR2_5 0x10AD
+#define HDMI_FC_ISCR2_4 0x10AE
+#define HDMI_FC_ISCR2_3 0x10AF
+#define HDMI_FC_ISCR2_2 0x10B0
+#define HDMI_FC_ISCR2_1 0x10B1
+#define HDMI_FC_ISCR2_0 0x10B2
+#define HDMI_FC_DATAUTO0 0x10B3
+#define HDMI_FC_DATAUTO1 0x10B4
+#define HDMI_FC_DATAUTO2 0x10B5
+#define HDMI_FC_DATMAN 0x10B6
+#define HDMI_FC_DATAUTO3 0x10B7
+#define HDMI_FC_RDRB0 0x10B8
+#define HDMI_FC_RDRB1 0x10B9
+#define HDMI_FC_RDRB2 0x10BA
+#define HDMI_FC_RDRB3 0x10BB
+#define HDMI_FC_RDRB4 0x10BC
+#define HDMI_FC_RDRB5 0x10BD
+#define HDMI_FC_RDRB6 0x10BE
+#define HDMI_FC_RDRB7 0x10BF
+#define HDMI_FC_STAT0 0x10D0
+#define HDMI_FC_INT0 0x10D1
+#define HDMI_FC_MASK0 0x10D2
+#define HDMI_FC_POL0 0x10D3
+#define HDMI_FC_STAT1 0x10D4
+#define HDMI_FC_INT1 0x10D5
+#define HDMI_FC_MASK1 0x10D6
+#define HDMI_FC_POL1 0x10D7
+#define HDMI_FC_STAT2 0x10D8
+#define HDMI_FC_INT2 0x10D9
+#define HDMI_FC_MASK2 0x10DA
+#define HDMI_FC_POL2 0x10DB
+#define HDMI_FC_PRCONF 0x10E0
+
+#define HDMI_FC_GMD_STAT 0x1100
+#define HDMI_FC_GMD_EN 0x1101
+#define HDMI_FC_GMD_UP 0x1102
+#define HDMI_FC_GMD_CONF 0x1103
+#define HDMI_FC_GMD_HB 0x1104
+#define HDMI_FC_GMD_PB0 0x1105
+#define HDMI_FC_GMD_PB1 0x1106
+#define HDMI_FC_GMD_PB2 0x1107
+#define HDMI_FC_GMD_PB3 0x1108
+#define HDMI_FC_GMD_PB4 0x1109
+#define HDMI_FC_GMD_PB5 0x110A
+#define HDMI_FC_GMD_PB6 0x110B
+#define HDMI_FC_GMD_PB7 0x110C
+#define HDMI_FC_GMD_PB8 0x110D
+#define HDMI_FC_GMD_PB9 0x110E
+#define HDMI_FC_GMD_PB10 0x110F
+#define HDMI_FC_GMD_PB11 0x1110
+#define HDMI_FC_GMD_PB12 0x1111
+#define HDMI_FC_GMD_PB13 0x1112
+#define HDMI_FC_GMD_PB14 0x1113
+#define HDMI_FC_GMD_PB15 0x1114
+#define HDMI_FC_GMD_PB16 0x1115
+#define HDMI_FC_GMD_PB17 0x1116
+#define HDMI_FC_GMD_PB18 0x1117
+#define HDMI_FC_GMD_PB19 0x1118
+#define HDMI_FC_GMD_PB20 0x1119
+#define HDMI_FC_GMD_PB21 0x111A
+#define HDMI_FC_GMD_PB22 0x111B
+#define HDMI_FC_GMD_PB23 0x111C
+#define HDMI_FC_GMD_PB24 0x111D
+#define HDMI_FC_GMD_PB25 0x111E
+#define HDMI_FC_GMD_PB26 0x111F
+#define HDMI_FC_GMD_PB27 0x1120
+
+#define HDMI_FC_DBGFORCE 0x1200
+#define HDMI_FC_DBGAUD0CH0 0x1201
+#define HDMI_FC_DBGAUD1CH0 0x1202
+#define HDMI_FC_DBGAUD2CH0 0x1203
+#define HDMI_FC_DBGAUD0CH1 0x1204
+#define HDMI_FC_DBGAUD1CH1 0x1205
+#define HDMI_FC_DBGAUD2CH1 0x1206
+#define HDMI_FC_DBGAUD0CH2 0x1207
+#define HDMI_FC_DBGAUD1CH2 0x1208
+#define HDMI_FC_DBGAUD2CH2 0x1209
+#define HDMI_FC_DBGAUD0CH3 0x120A
+#define HDMI_FC_DBGAUD1CH3 0x120B
+#define HDMI_FC_DBGAUD2CH3 0x120C
+#define HDMI_FC_DBGAUD0CH4 0x120D
+#define HDMI_FC_DBGAUD1CH4 0x120E
+#define HDMI_FC_DBGAUD2CH4 0x120F
+#define HDMI_FC_DBGAUD0CH5 0x1210
+#define HDMI_FC_DBGAUD1CH5 0x1211
+#define HDMI_FC_DBGAUD2CH5 0x1212
+#define HDMI_FC_DBGAUD0CH6 0x1213
+#define HDMI_FC_DBGAUD1CH6 0x1214
+#define HDMI_FC_DBGAUD2CH6 0x1215
+#define HDMI_FC_DBGAUD0CH7 0x1216
+#define HDMI_FC_DBGAUD1CH7 0x1217
+#define HDMI_FC_DBGAUD2CH7 0x1218
+#define HDMI_FC_DBGTMDS0 0x1219
+#define HDMI_FC_DBGTMDS1 0x121A
+#define HDMI_FC_DBGTMDS2 0x121B
+
+/* HDMI Source PHY Registers */
+#define HDMI_PHY_CONF0 0x3000
+#define HDMI_PHY_TST0 0x3001
+#define HDMI_PHY_TST1 0x3002
+#define HDMI_PHY_TST2 0x3003
+#define HDMI_PHY_STAT0 0x3004
+#define HDMI_PHY_INT0 0x3005
+#define HDMI_PHY_MASK0 0x3006
+#define HDMI_PHY_POL0 0x3007
+
+/* HDMI Master PHY Registers */
+#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020
+#define HDMI_PHY_I2CM_ADDRESS_ADDR 0x3021
+#define HDMI_PHY_I2CM_DATAO_1_ADDR 0x3022
+#define HDMI_PHY_I2CM_DATAO_0_ADDR 0x3023
+#define HDMI_PHY_I2CM_DATAI_1_ADDR 0x3024
+#define HDMI_PHY_I2CM_DATAI_0_ADDR 0x3025
+#define HDMI_PHY_I2CM_OPERATION_ADDR 0x3026
+#define HDMI_PHY_I2CM_INT_ADDR 0x3027
+#define HDMI_PHY_I2CM_CTLINT_ADDR 0x3028
+#define HDMI_PHY_I2CM_DIV_ADDR 0x3029
+#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR 0x302a
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR 0x302b
+#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR 0x302c
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR 0x302d
+#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR 0x302e
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR 0x302f
+#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR 0x3030
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR 0x3031
+#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR 0x3032
+
+/* Audio Sampler Registers */
+#define HDMI_AUD_CONF0 0x3100
+#define HDMI_AUD_CONF1 0x3101
+#define HDMI_AUD_INT 0x3102
+#define HDMI_AUD_CONF2 0x3103
+#define HDMI_AUD_N1 0x3200
+#define HDMI_AUD_N2 0x3201
+#define HDMI_AUD_N3 0x3202
+#define HDMI_AUD_CTS1 0x3203
+#define HDMI_AUD_CTS2 0x3204
+#define HDMI_AUD_CTS3 0x3205
+#define HDMI_AUD_INPUTCLKFS 0x3206
+#define HDMI_AUD_SPDIFINT 0x3302
+#define HDMI_AUD_CONF0_HBR 0x3400
+#define HDMI_AUD_HBR_STATUS 0x3401
+#define HDMI_AUD_HBR_INT 0x3402
+#define HDMI_AUD_HBR_POL 0x3403
+#define HDMI_AUD_HBR_MASK 0x3404
+
+/*
+ * Generic Parallel Audio Interface Registers
+ * Not used as GPAUD interface is not enabled in hw
+ */
+#define HDMI_GP_CONF0 0x3500
+#define HDMI_GP_CONF1 0x3501
+#define HDMI_GP_CONF2 0x3502
+#define HDMI_GP_STAT 0x3503
+#define HDMI_GP_INT 0x3504
+#define HDMI_GP_MASK 0x3505
+#define HDMI_GP_POL 0x3506
+
+/* Audio DMA Registers */
+#define HDMI_AHB_DMA_CONF0 0x3600
+#define HDMI_AHB_DMA_START 0x3601
+#define HDMI_AHB_DMA_STOP 0x3602
+#define HDMI_AHB_DMA_THRSLD 0x3603
+#define HDMI_AHB_DMA_STRADDR0 0x3604
+#define HDMI_AHB_DMA_STRADDR1 0x3605
+#define HDMI_AHB_DMA_STRADDR2 0x3606
+#define HDMI_AHB_DMA_STRADDR3 0x3607
+#define HDMI_AHB_DMA_STPADDR0 0x3608
+#define HDMI_AHB_DMA_STPADDR1 0x3609
+#define HDMI_AHB_DMA_STPADDR2 0x360a
+#define HDMI_AHB_DMA_STPADDR3 0x360b
+#define HDMI_AHB_DMA_BSTADDR0 0x360c
+#define HDMI_AHB_DMA_BSTADDR1 0x360d
+#define HDMI_AHB_DMA_BSTADDR2 0x360e
+#define HDMI_AHB_DMA_BSTADDR3 0x360f
+#define HDMI_AHB_DMA_MBLENGTH0 0x3610
+#define HDMI_AHB_DMA_MBLENGTH1 0x3611
+#define HDMI_AHB_DMA_STAT 0x3612
+#define HDMI_AHB_DMA_INT 0x3613
+#define HDMI_AHB_DMA_MASK 0x3614
+#define HDMI_AHB_DMA_POL 0x3615
+#define HDMI_AHB_DMA_CONF1 0x3616
+#define HDMI_AHB_DMA_BUFFSTAT 0x3617
+#define HDMI_AHB_DMA_BUFFINT 0x3618
+#define HDMI_AHB_DMA_BUFFMASK 0x3619
+#define HDMI_AHB_DMA_BUFFPOL 0x361a
+
+/* Main Controller Registers */
+#define HDMI_MC_SFRDIV 0x4000
+#define HDMI_MC_CLKDIS 0x4001
+#define HDMI_MC_SWRSTZ 0x4002
+#define HDMI_MC_OPCTRL 0x4003
+#define HDMI_MC_FLOWCTRL 0x4004
+#define HDMI_MC_PHYRSTZ 0x4005
+#define HDMI_MC_LOCKONCLOCK 0x4006
+#define HDMI_MC_HEACPHY_RST 0x4007
+
+/* Color Space Converter Registers */
+#define HDMI_CSC_CFG 0x4100
+#define HDMI_CSC_SCALE 0x4101
+#define HDMI_CSC_COEF_A1_MSB 0x4102
+#define HDMI_CSC_COEF_A1_LSB 0x4103
+#define HDMI_CSC_COEF_A2_MSB 0x4104
+#define HDMI_CSC_COEF_A2_LSB 0x4105
+#define HDMI_CSC_COEF_A3_MSB 0x4106
+#define HDMI_CSC_COEF_A3_LSB 0x4107
+#define HDMI_CSC_COEF_A4_MSB 0x4108
+#define HDMI_CSC_COEF_A4_LSB 0x4109
+#define HDMI_CSC_COEF_B1_MSB 0x410A
+#define HDMI_CSC_COEF_B1_LSB 0x410B
+#define HDMI_CSC_COEF_B2_MSB 0x410C
+#define HDMI_CSC_COEF_B2_LSB 0x410D
+#define HDMI_CSC_COEF_B3_MSB 0x410E
+#define HDMI_CSC_COEF_B3_LSB 0x410F
+#define HDMI_CSC_COEF_B4_MSB 0x4110
+#define HDMI_CSC_COEF_B4_LSB 0x4111
+#define HDMI_CSC_COEF_C1_MSB 0x4112
+#define HDMI_CSC_COEF_C1_LSB 0x4113
+#define HDMI_CSC_COEF_C2_MSB 0x4114
+#define HDMI_CSC_COEF_C2_LSB 0x4115
+#define HDMI_CSC_COEF_C3_MSB 0x4116
+#define HDMI_CSC_COEF_C3_LSB 0x4117
+#define HDMI_CSC_COEF_C4_MSB 0x4118
+#define HDMI_CSC_COEF_C4_LSB 0x4119
+
+/* HDCP Encryption Engine Registers */
+#define HDMI_A_HDCPCFG0 0x5000
+#define HDMI_A_HDCPCFG1 0x5001
+#define HDMI_A_HDCPOBS0 0x5002
+#define HDMI_A_HDCPOBS1 0x5003
+#define HDMI_A_HDCPOBS2 0x5004
+#define HDMI_A_HDCPOBS3 0x5005
+#define HDMI_A_APIINTCLR 0x5006
+#define HDMI_A_APIINTSTAT 0x5007
+#define HDMI_A_APIINTMSK 0x5008
+#define HDMI_A_VIDPOLCFG 0x5009
+#define HDMI_A_OESSWCFG 0x500A
+#define HDMI_A_TIMER1SETUP0 0x500B
+#define HDMI_A_TIMER1SETUP1 0x500C
+#define HDMI_A_TIMER2SETUP0 0x500D
+#define HDMI_A_TIMER2SETUP1 0x500E
+#define HDMI_A_100MSCFG 0x500F
+#define HDMI_A_2SCFG0 0x5010
+#define HDMI_A_2SCFG1 0x5011
+#define HDMI_A_5SCFG0 0x5012
+#define HDMI_A_5SCFG1 0x5013
+#define HDMI_A_SRMVERLSB 0x5014
+#define HDMI_A_SRMVERMSB 0x5015
+#define HDMI_A_SRMCTRL 0x5016
+#define HDMI_A_SFRSETUP 0x5017
+#define HDMI_A_I2CHSETUP 0x5018
+#define HDMI_A_INTSETUP 0x5019
+#define HDMI_A_PRESETUP 0x501A
+#define HDMI_A_SRM_BASE 0x5020
+
+/* CEC Engine Registers */
+#define HDMI_CEC_CTRL 0x7D00
+#define HDMI_CEC_STAT 0x7D01
+#define HDMI_CEC_MASK 0x7D02
+#define HDMI_CEC_POLARITY 0x7D03
+#define HDMI_CEC_INT 0x7D04
+#define HDMI_CEC_ADDR_L 0x7D05
+#define HDMI_CEC_ADDR_H 0x7D06
+#define HDMI_CEC_TX_CNT 0x7D07
+#define HDMI_CEC_RX_CNT 0x7D08
+#define HDMI_CEC_TX_DATA0 0x7D10
+#define HDMI_CEC_TX_DATA1 0x7D11
+#define HDMI_CEC_TX_DATA2 0x7D12
+#define HDMI_CEC_TX_DATA3 0x7D13
+#define HDMI_CEC_TX_DATA4 0x7D14
+#define HDMI_CEC_TX_DATA5 0x7D15
+#define HDMI_CEC_TX_DATA6 0x7D16
+#define HDMI_CEC_TX_DATA7 0x7D17
+#define HDMI_CEC_TX_DATA8 0x7D18
+#define HDMI_CEC_TX_DATA9 0x7D19
+#define HDMI_CEC_TX_DATA10 0x7D1a
+#define HDMI_CEC_TX_DATA11 0x7D1b
+#define HDMI_CEC_TX_DATA12 0x7D1c
+#define HDMI_CEC_TX_DATA13 0x7D1d
+#define HDMI_CEC_TX_DATA14 0x7D1e
+#define HDMI_CEC_TX_DATA15 0x7D1f
+#define HDMI_CEC_RX_DATA0 0x7D20
+#define HDMI_CEC_RX_DATA1 0x7D21
+#define HDMI_CEC_RX_DATA2 0x7D22
+#define HDMI_CEC_RX_DATA3 0x7D23
+#define HDMI_CEC_RX_DATA4 0x7D24
+#define HDMI_CEC_RX_DATA5 0x7D25
+#define HDMI_CEC_RX_DATA6 0x7D26
+#define HDMI_CEC_RX_DATA7 0x7D27
+#define HDMI_CEC_RX_DATA8 0x7D28
+#define HDMI_CEC_RX_DATA9 0x7D29
+#define HDMI_CEC_RX_DATA10 0x7D2a
+#define HDMI_CEC_RX_DATA11 0x7D2b
+#define HDMI_CEC_RX_DATA12 0x7D2c
+#define HDMI_CEC_RX_DATA13 0x7D2d
+#define HDMI_CEC_RX_DATA14 0x7D2e
+#define HDMI_CEC_RX_DATA15 0x7D2f
+#define HDMI_CEC_LOCK 0x7D30
+#define HDMI_CEC_WKUPCTRL 0x7D31
+
+/* I2C Master Registers (E-DDC) */
+#define HDMI_I2CM_SLAVE 0x7E00
+#define HDMI_I2CMESS 0x7E01
+#define HDMI_I2CM_DATAO 0x7E02
+#define HDMI_I2CM_DATAI 0x7E03
+#define HDMI_I2CM_OPERATION 0x7E04
+#define HDMI_I2CM_INT 0x7E05
+#define HDMI_I2CM_CTLINT 0x7E06
+#define HDMI_I2CM_DIV 0x7E07
+#define HDMI_I2CM_SEGADDR 0x7E08
+#define HDMI_I2CM_SOFTRSTZ 0x7E09
+#define HDMI_I2CM_SEGPTR 0x7E0A
+#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR 0x7E0B
+#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x7E0C
+#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR 0x7E0D
+#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x7E0E
+#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR 0x7E0F
+#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR 0x7E10
+#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR 0x7E11
+#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
+
+enum {
+/* IH_FC_INT2 field values */
+ HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
+ HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+ HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_FC_STAT2 field values */
+ HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
+ HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+ HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_PHY_STAT0 field values */
+ HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
+ HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
+ HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
+ HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
+ HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
+ HDMI_IH_PHY_STAT0_HPD = 0x1,
+
+/* IH_MUTE_I2CMPHY_STAT0 field values */
+ HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
+ HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
+
+/* IH_AHBDMAAUD_STAT0 field values */
+ HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
+ HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
+ HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
+ HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+ HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE_FC_STAT2 field values */
+ HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
+ HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+ HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* IH_MUTE_AHBDMAAUD_STAT0 field values */
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
+ HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
+
+/* IH_MUTE field values */
+ HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
+ HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
+
+/* TX_INVID0 field values */
+ HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
+ HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
+ HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
+ HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
+ HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
+
+/* TX_INSTUFFING field values */
+ HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
+ HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
+ HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
+ HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
+ HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
+
+/* VP_PR_CD field values */
+ HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
+ HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
+ HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
+
+/* VP_STUFF field values */
+ HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
+ HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
+ HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
+ HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
+ HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
+ HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
+ HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
+ HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
+ HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
+ HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
+ HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
+ HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
+ HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
+ HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
+ HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
+
+/* VP_CONF field values */
+ HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
+ HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
+ HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
+ HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
+ HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
+ HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
+ HDMI_VP_CONF_PR_EN_MASK = 0x10,
+ HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
+ HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
+ HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
+ HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
+ HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
+ HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
+ HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
+ HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
+ HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
+ HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
+ HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
+ HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
+
+/* VP_REMAP field values */
+ HDMI_VP_REMAP_MASK = 0x3,
+ HDMI_VP_REMAP_YCC422_24bit = 0x2,
+ HDMI_VP_REMAP_YCC422_20bit = 0x1,
+ HDMI_VP_REMAP_YCC422_16bit = 0x0,
+
+/* FC_INVIDCONF field values */
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
+ HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
+ HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
+ HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
+ HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
+ HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
+ HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
+ HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
+ HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
+ HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
+ HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
+ HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
+
+/* FC_AUDICONF0 field values */
+ HDMI_FC_AUDICONF0_CC_OFFSET = 4,
+ HDMI_FC_AUDICONF0_CC_MASK = 0x70,
+ HDMI_FC_AUDICONF0_CT_OFFSET = 0,
+ HDMI_FC_AUDICONF0_CT_MASK = 0xF,
+
+/* FC_AUDICONF1 field values */
+ HDMI_FC_AUDICONF1_SS_OFFSET = 3,
+ HDMI_FC_AUDICONF1_SS_MASK = 0x18,
+ HDMI_FC_AUDICONF1_SF_OFFSET = 0,
+ HDMI_FC_AUDICONF1_SF_MASK = 0x7,
+
+/* FC_AUDICONF3 field values */
+ HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
+ HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
+ HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
+ HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
+ HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
+ HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
+
+/* FC_AUDSCHNLS0 field values */
+ HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
+ HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
+ HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
+
+/* FC_AUDSCHNLS3-6 field values */
+ HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
+ HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
+ HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
+ HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
+ HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
+ HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
+
+ HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
+ HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
+ HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
+ HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
+ HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
+ HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
+
+/* HDMI_FC_AUDSCHNLS7 field values */
+ HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
+
+/* HDMI_FC_AUDSCHNLS8 field values */
+ HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
+ HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
+ HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
+ HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
+
+/* FC_AUDSCONF field values */
+ HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
+ HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
+ HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
+ HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
+ HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
+ HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
+
+/* FC_STAT2 field values */
+ HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
+ HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
+ HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_INT2 field values */
+ HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
+ HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
+ HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_MASK2 field values */
+ HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
+ HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
+ HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
+
+/* FC_PRCONF field values */
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
+ HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
+ HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
+ HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
+
+/* FC_AVICONF0-FC_AVICONF3 field values */
+ HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
+ HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
+ HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
+ HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
+ HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
+ HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
+ HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
+ HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
+ HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
+ HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
+ HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
+ HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
+ HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
+ HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
+ HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
+ HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
+
+ HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
+ HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
+ HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
+ HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
+ HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
+ HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
+ HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
+ HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
+ HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
+ HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
+ HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
+ HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
+ HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
+ HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
+
+ HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
+ HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
+ HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
+ HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
+ HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
+ HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
+ HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
+ HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
+ HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
+ HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
+ HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
+ HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
+ HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
+
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
+ HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
+ HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
+ HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
+ HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
+
+/* FC_DBGFORCE field values */
+ HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
+ HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
+
+/* PHY_CONF0 field values */
+ HDMI_PHY_CONF0_PDZ_MASK = 0x80,
+ HDMI_PHY_CONF0_PDZ_OFFSET = 7,
+ HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
+ HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
+ HDMI_PHY_CONF0_SPARECTRL_MASK = 0x20,
+ HDMI_PHY_CONF0_SPARECTRL_OFFSET = 5,
+ HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
+ HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
+ HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
+ HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
+ HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
+ HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
+ HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
+ HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
+ HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
+ HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
+
+/* PHY_TST0 field values */
+ HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
+ HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
+ HDMI_PHY_TST0_TSTEN_MASK = 0x10,
+ HDMI_PHY_TST0_TSTEN_OFFSET = 4,
+ HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
+ HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
+
+/* PHY_STAT0 field values */
+ HDMI_PHY_RX_SENSE3 = 0x80,
+ HDMI_PHY_RX_SENSE2 = 0x40,
+ HDMI_PHY_RX_SENSE1 = 0x20,
+ HDMI_PHY_RX_SENSE0 = 0x10,
+ HDMI_PHY_HPD = 0x02,
+ HDMI_PHY_TX_PHY_LOCK = 0x01,
+
+/* PHY_I2CM_SLAVE_ADDR field values */
+ HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
+ HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
+
+/* PHY_I2CM_OPERATION_ADDR field values */
+ HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
+ HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
+
+/* HDMI_PHY_I2CM_INT_ADDR */
+ HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
+ HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
+
+/* HDMI_PHY_I2CM_CTLINT_ADDR */
+ HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
+ HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
+ HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
+ HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
+
+/* AUD_CTS3 field values */
+ HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
+ HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
+ HDMI_AUD_CTS3_N_SHIFT_1 = 0,
+ HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
+ HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
+ HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
+ HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
+ HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
+ /* note that the CTS3 MANUAL bit has been removed
+ from our part. Can't set it, will read as 0. */
+ HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
+ HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
+
+/* AHB_DMA_CONF0 field values */
+ HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
+ HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
+ HDMI_AHB_DMA_CONF0_HBR = 0x10,
+ HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
+ HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
+ HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
+ HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
+ HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
+ HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
+ HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
+ HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
+
+/* HDMI_AHB_DMA_START field values */
+ HDMI_AHB_DMA_START_START_OFFSET = 0,
+ HDMI_AHB_DMA_START_START_MASK = 0x01,
+
+/* HDMI_AHB_DMA_STOP field values */
+ HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
+ HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
+
+/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
+ HDMI_AHB_DMA_DONE = 0x80,
+ HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
+ HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
+ HDMI_AHB_DMA_ERROR = 0x10,
+ HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
+ HDMI_AHB_DMA_FIFO_FULL = 0x02,
+ HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
+
+/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
+ HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
+ HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
+
+/* MC_CLKDIS field values */
+ HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
+ HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
+ HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
+ HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
+ HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
+ HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
+ HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
+
+/* MC_SWRSTZ field values */
+ HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
+
+/* MC_FLOWCTRL field values */
+ HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
+ HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
+ HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
+
+/* MC_PHYRSTZ field values */
+ HDMI_MC_PHYRSTZ_ASSERT = 0x0,
+ HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
+
+/* MC_HEACPHY_RST field values */
+ HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
+ HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
+
+/* CSC_CFG field values */
+ HDMI_CSC_CFG_INTMODE_MASK = 0x30,
+ HDMI_CSC_CFG_INTMODE_OFFSET = 4,
+ HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
+ HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
+ HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
+ HDMI_CSC_CFG_DECMODE_MASK = 0x3,
+ HDMI_CSC_CFG_DECMODE_OFFSET = 0,
+ HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
+ HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
+ HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
+ HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
+
+/* CSC_SCALE field values */
+ HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
+ HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
+ HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
+ HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
+ HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
+ HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
+
+/* A_HDCPCFG0 field values */
+ HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
+ HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
+ HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
+ HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
+ HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
+ HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
+ HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
+ HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
+ HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
+ HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
+ HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
+ HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
+ HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
+ HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
+ HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
+ HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
+ HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
+ HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
+ HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
+ HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
+ HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
+ HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
+ HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
+ HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
+
+/* A_HDCPCFG1 field values */
+ HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
+ HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
+ HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
+ HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
+ HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
+ HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
+ HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
+ HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
+ HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
+
+/* A_VIDPOLCFG field values */
+ HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
+ HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
+ HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
+ HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
+ HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
+ HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
+ HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
+ HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
+ HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
+ HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
+ HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
+};
+
+#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/gpu/drm/bridge/ptn3460.c b/drivers/gpu/drm/bridge/ptn3460.c
index d466696ed5e8..826833e396f0 100644
--- a/drivers/gpu/drm/bridge/ptn3460.c
+++ b/drivers/gpu/drm/bridge/ptn3460.c
@@ -13,20 +13,23 @@
* GNU General Public License for more details.
*/
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
-#include <linux/i2c.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
+#include <linux/of_graph.h>
-#include "drmP.h"
-#include "drm_edid.h"
-#include "drm_crtc.h"
-#include "drm_crtc_helper.h"
+#include <drm/drm_panel.h>
#include "bridge/ptn3460.h"
+#include "drm_crtc.h"
+#include "drm_crtc_helper.h"
+#include "drm_edid.h"
+#include "drmP.h"
+
#define PTN3460_EDID_ADDR 0x0
#define PTN3460_EDID_EMULATION_ADDR 0x84
#define PTN3460_EDID_ENABLE_EMULATION 0
@@ -36,15 +39,27 @@
struct ptn3460_bridge {
struct drm_connector connector;
struct i2c_client *client;
- struct drm_encoder *encoder;
- struct drm_bridge *bridge;
+ struct drm_bridge bridge;
struct edid *edid;
- int gpio_pd_n;
- int gpio_rst_n;
+ struct drm_panel *panel;
+ struct gpio_desc *gpio_pd_n;
+ struct gpio_desc *gpio_rst_n;
u32 edid_emulation;
bool enabled;
};
+static inline struct ptn3460_bridge *
+ bridge_to_ptn3460(struct drm_bridge *bridge)
+{
+ return container_of(bridge, struct ptn3460_bridge, bridge);
+}
+
+static inline struct ptn3460_bridge *
+ connector_to_ptn3460(struct drm_connector *connector)
+{
+ return container_of(connector, struct ptn3460_bridge, connector);
+}
+
static int ptn3460_read_bytes(struct ptn3460_bridge *ptn_bridge, char addr,
u8 *buf, int len)
{
@@ -92,7 +107,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_SRAM_LOAD_ADDR,
ptn_bridge->edid_emulation);
if (ret) {
- DRM_ERROR("Failed to transfer edid to sram, ret=%d\n", ret);
+ DRM_ERROR("Failed to transfer EDID to sram, ret=%d\n", ret);
return ret;
}
@@ -102,7 +117,7 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
ret = ptn3460_write_byte(ptn_bridge, PTN3460_EDID_EMULATION_ADDR, val);
if (ret) {
- DRM_ERROR("Failed to write edid value, ret=%d\n", ret);
+ DRM_ERROR("Failed to write EDID value, ret=%d\n", ret);
return ret;
}
@@ -111,19 +126,21 @@ static int ptn3460_select_edid(struct ptn3460_bridge *ptn_bridge)
static void ptn3460_pre_enable(struct drm_bridge *bridge)
{
- struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+ struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
int ret;
if (ptn_bridge->enabled)
return;
- if (gpio_is_valid(ptn_bridge->gpio_pd_n))
- gpio_set_value(ptn_bridge->gpio_pd_n, 1);
+ gpiod_set_value(ptn_bridge->gpio_pd_n, 1);
+
+ gpiod_set_value(ptn_bridge->gpio_rst_n, 0);
+ usleep_range(10, 20);
+ gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
- if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
- gpio_set_value(ptn_bridge->gpio_rst_n, 0);
- udelay(10);
- gpio_set_value(ptn_bridge->gpio_rst_n, 1);
+ if (drm_panel_prepare(ptn_bridge->panel)) {
+ DRM_ERROR("failed to prepare panel\n");
+ return;
}
/*
@@ -135,73 +152,67 @@ static void ptn3460_pre_enable(struct drm_bridge *bridge)
ret = ptn3460_select_edid(ptn_bridge);
if (ret)
- DRM_ERROR("Select edid failed ret=%d\n", ret);
+ DRM_ERROR("Select EDID failed ret=%d\n", ret);
ptn_bridge->enabled = true;
}
static void ptn3460_enable(struct drm_bridge *bridge)
{
+ struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
+
+ if (drm_panel_enable(ptn_bridge->panel)) {
+ DRM_ERROR("failed to enable panel\n");
+ return;
+ }
}
static void ptn3460_disable(struct drm_bridge *bridge)
{
- struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
+ struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
if (!ptn_bridge->enabled)
return;
ptn_bridge->enabled = false;
- if (gpio_is_valid(ptn_bridge->gpio_rst_n))
- gpio_set_value(ptn_bridge->gpio_rst_n, 1);
+ if (drm_panel_disable(ptn_bridge->panel)) {
+ DRM_ERROR("failed to disable panel\n");
+ return;
+ }
- if (gpio_is_valid(ptn_bridge->gpio_pd_n))
- gpio_set_value(ptn_bridge->gpio_pd_n, 0);
+ gpiod_set_value(ptn_bridge->gpio_rst_n, 1);
+ gpiod_set_value(ptn_bridge->gpio_pd_n, 0);
}
static void ptn3460_post_disable(struct drm_bridge *bridge)
{
-}
+ struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
-void ptn3460_bridge_destroy(struct drm_bridge *bridge)
-{
- struct ptn3460_bridge *ptn_bridge = bridge->driver_private;
-
- drm_bridge_cleanup(bridge);
- if (gpio_is_valid(ptn_bridge->gpio_pd_n))
- gpio_free(ptn_bridge->gpio_pd_n);
- if (gpio_is_valid(ptn_bridge->gpio_rst_n))
- gpio_free(ptn_bridge->gpio_rst_n);
- /* Nothing else to free, we've got devm allocated memory */
+ if (drm_panel_unprepare(ptn_bridge->panel)) {
+ DRM_ERROR("failed to unprepare panel\n");
+ return;
+ }
}
-struct drm_bridge_funcs ptn3460_bridge_funcs = {
- .pre_enable = ptn3460_pre_enable,
- .enable = ptn3460_enable,
- .disable = ptn3460_disable,
- .post_disable = ptn3460_post_disable,
- .destroy = ptn3460_bridge_destroy,
-};
-
-int ptn3460_get_modes(struct drm_connector *connector)
+static int ptn3460_get_modes(struct drm_connector *connector)
{
struct ptn3460_bridge *ptn_bridge;
u8 *edid;
- int ret, num_modes;
+ int ret, num_modes = 0;
bool power_off;
- ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+ ptn_bridge = connector_to_ptn3460(connector);
if (ptn_bridge->edid)
return drm_add_edid_modes(connector, ptn_bridge->edid);
power_off = !ptn_bridge->enabled;
- ptn3460_pre_enable(ptn_bridge->bridge);
+ ptn3460_pre_enable(&ptn_bridge->bridge);
edid = kmalloc(EDID_LENGTH, GFP_KERNEL);
if (!edid) {
- DRM_ERROR("Failed to allocate edid\n");
+ DRM_ERROR("Failed to allocate EDID\n");
return 0;
}
@@ -209,7 +220,6 @@ int ptn3460_get_modes(struct drm_connector *connector)
EDID_LENGTH);
if (ret) {
kfree(edid);
- num_modes = 0;
goto out;
}
@@ -220,124 +230,188 @@ int ptn3460_get_modes(struct drm_connector *connector)
out:
if (power_off)
- ptn3460_disable(ptn_bridge->bridge);
+ ptn3460_disable(&ptn_bridge->bridge);
return num_modes;
}
-struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
+static struct drm_encoder *ptn3460_best_encoder(struct drm_connector *connector)
{
- struct ptn3460_bridge *ptn_bridge;
-
- ptn_bridge = container_of(connector, struct ptn3460_bridge, connector);
+ struct ptn3460_bridge *ptn_bridge = connector_to_ptn3460(connector);
- return ptn_bridge->encoder;
+ return ptn_bridge->bridge.encoder;
}
-struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
+static struct drm_connector_helper_funcs ptn3460_connector_helper_funcs = {
.get_modes = ptn3460_get_modes,
.best_encoder = ptn3460_best_encoder,
};
-enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
+static enum drm_connector_status ptn3460_detect(struct drm_connector *connector,
bool force)
{
return connector_status_connected;
}
-void ptn3460_connector_destroy(struct drm_connector *connector)
+static void ptn3460_connector_destroy(struct drm_connector *connector)
{
drm_connector_cleanup(connector);
}
-struct drm_connector_funcs ptn3460_connector_funcs = {
+static struct drm_connector_funcs ptn3460_connector_funcs = {
.dpms = drm_helper_connector_dpms,
.fill_modes = drm_helper_probe_single_connector_modes,
.detect = ptn3460_detect,
.destroy = ptn3460_connector_destroy,
};
-int ptn3460_init(struct drm_device *dev, struct drm_encoder *encoder,
- struct i2c_client *client, struct device_node *node)
+int ptn3460_bridge_attach(struct drm_bridge *bridge)
{
+ struct ptn3460_bridge *ptn_bridge = bridge_to_ptn3460(bridge);
int ret;
- struct drm_bridge *bridge;
- struct ptn3460_bridge *ptn_bridge;
- bridge = devm_kzalloc(dev->dev, sizeof(*bridge), GFP_KERNEL);
- if (!bridge) {
- DRM_ERROR("Failed to allocate drm bridge\n");
- return -ENOMEM;
+ if (!bridge->encoder) {
+ DRM_ERROR("Parent encoder object not found");
+ return -ENODEV;
+ }
+
+ ptn_bridge->connector.polled = DRM_CONNECTOR_POLL_HPD;
+ ret = drm_connector_init(bridge->dev, &ptn_bridge->connector,
+ &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+ if (ret) {
+ DRM_ERROR("Failed to initialize connector with drm\n");
+ return ret;
}
+ drm_connector_helper_add(&ptn_bridge->connector,
+ &ptn3460_connector_helper_funcs);
+ drm_connector_register(&ptn_bridge->connector);
+ drm_mode_connector_attach_encoder(&ptn_bridge->connector,
+ bridge->encoder);
- ptn_bridge = devm_kzalloc(dev->dev, sizeof(*ptn_bridge), GFP_KERNEL);
+ if (ptn_bridge->panel)
+ drm_panel_attach(ptn_bridge->panel, &ptn_bridge->connector);
+
+ drm_helper_hpd_irq_event(ptn_bridge->connector.dev);
+
+ return ret;
+}
+
+static struct drm_bridge_funcs ptn3460_bridge_funcs = {
+ .pre_enable = ptn3460_pre_enable,
+ .enable = ptn3460_enable,
+ .disable = ptn3460_disable,
+ .post_disable = ptn3460_post_disable,
+ .attach = ptn3460_bridge_attach,
+};
+
+static int ptn3460_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct ptn3460_bridge *ptn_bridge;
+ struct device_node *endpoint, *panel_node;
+ int ret;
+
+ ptn_bridge = devm_kzalloc(dev, sizeof(*ptn_bridge), GFP_KERNEL);
if (!ptn_bridge) {
- DRM_ERROR("Failed to allocate ptn bridge\n");
return -ENOMEM;
}
- ptn_bridge->client = client;
- ptn_bridge->encoder = encoder;
- ptn_bridge->bridge = bridge;
- ptn_bridge->gpio_pd_n = of_get_named_gpio(node, "powerdown-gpio", 0);
- if (gpio_is_valid(ptn_bridge->gpio_pd_n)) {
- ret = gpio_request_one(ptn_bridge->gpio_pd_n,
- GPIOF_OUT_INIT_HIGH, "PTN3460_PD_N");
- if (ret) {
- DRM_ERROR("Request powerdown-gpio failed (%d)\n", ret);
- return ret;
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint) {
+ panel_node = of_graph_get_remote_port_parent(endpoint);
+ if (panel_node) {
+ ptn_bridge->panel = of_drm_find_panel(panel_node);
+ of_node_put(panel_node);
+ if (!ptn_bridge->panel)
+ return -EPROBE_DEFER;
}
}
- ptn_bridge->gpio_rst_n = of_get_named_gpio(node, "reset-gpio", 0);
- if (gpio_is_valid(ptn_bridge->gpio_rst_n)) {
- /*
- * Request the reset pin low to avoid the bridge being
- * initialized prematurely
- */
- ret = gpio_request_one(ptn_bridge->gpio_rst_n,
- GPIOF_OUT_INIT_LOW, "PTN3460_RST_N");
- if (ret) {
- DRM_ERROR("Request reset-gpio failed (%d)\n", ret);
- gpio_free(ptn_bridge->gpio_pd_n);
- return ret;
- }
+ ptn_bridge->client = client;
+
+ ptn_bridge->gpio_pd_n = devm_gpiod_get(&client->dev, "powerdown");
+ if (IS_ERR(ptn_bridge->gpio_pd_n)) {
+ ret = PTR_ERR(ptn_bridge->gpio_pd_n);
+ dev_err(dev, "cannot get gpio_pd_n %d\n", ret);
+ return ret;
}
- ret = of_property_read_u32(node, "edid-emulation",
- &ptn_bridge->edid_emulation);
+ ret = gpiod_direction_output(ptn_bridge->gpio_pd_n, 1);
if (ret) {
- DRM_ERROR("Can't read edid emulation value\n");
- goto err;
+ DRM_ERROR("cannot configure gpio_pd_n\n");
+ return ret;
}
- ret = drm_bridge_init(dev, bridge, &ptn3460_bridge_funcs);
+ ptn_bridge->gpio_rst_n = devm_gpiod_get(&client->dev, "reset");
+ if (IS_ERR(ptn_bridge->gpio_rst_n)) {
+ ret = PTR_ERR(ptn_bridge->gpio_rst_n);
+ DRM_ERROR("cannot get gpio_rst_n %d\n", ret);
+ return ret;
+ }
+ /*
+ * Request the reset pin low to avoid the bridge being
+ * initialized prematurely
+ */
+ ret = gpiod_direction_output(ptn_bridge->gpio_rst_n, 0);
if (ret) {
- DRM_ERROR("Failed to initialize bridge with drm\n");
- goto err;
+ DRM_ERROR("cannot configure gpio_rst_n\n");
+ return ret;
}
- bridge->driver_private = ptn_bridge;
- encoder->bridge = bridge;
+ ret = of_property_read_u32(dev->of_node, "edid-emulation",
+ &ptn_bridge->edid_emulation);
+ if (ret) {
+ dev_err(dev, "Can't read EDID emulation value\n");
+ return ret;
+ }
- ret = drm_connector_init(dev, &ptn_bridge->connector,
- &ptn3460_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+ ptn_bridge->bridge.funcs = &ptn3460_bridge_funcs;
+ ptn_bridge->bridge.of_node = dev->of_node;
+ ret = drm_bridge_add(&ptn_bridge->bridge);
if (ret) {
- DRM_ERROR("Failed to initialize connector with drm\n");
- goto err;
+ DRM_ERROR("Failed to add bridge\n");
+ return ret;
}
- drm_connector_helper_add(&ptn_bridge->connector,
- &ptn3460_connector_helper_funcs);
- drm_connector_register(&ptn_bridge->connector);
- drm_mode_connector_attach_encoder(&ptn_bridge->connector, encoder);
+
+ i2c_set_clientdata(client, ptn_bridge);
return 0;
+}
-err:
- if (gpio_is_valid(ptn_bridge->gpio_pd_n))
- gpio_free(ptn_bridge->gpio_pd_n);
- if (gpio_is_valid(ptn_bridge->gpio_rst_n))
- gpio_free(ptn_bridge->gpio_rst_n);
- return ret;
+static int ptn3460_remove(struct i2c_client *client)
+{
+ struct ptn3460_bridge *ptn_bridge = i2c_get_clientdata(client);
+
+ drm_bridge_remove(&ptn_bridge->bridge);
+
+ return 0;
}
-EXPORT_SYMBOL(ptn3460_init);
+
+static const struct i2c_device_id ptn3460_i2c_table[] = {
+ {"nxp,ptn3460", 0},
+ {},
+};
+MODULE_DEVICE_TABLE(i2c, ptn3460_i2c_table);
+
+static const struct of_device_id ptn3460_match[] = {
+ { .compatible = "nxp,ptn3460" },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ptn3460_match);
+
+static struct i2c_driver ptn3460_driver = {
+ .id_table = ptn3460_i2c_table,
+ .probe = ptn3460_probe,
+ .remove = ptn3460_remove,
+ .driver = {
+ .name = "nxp,ptn3460",
+ .owner = THIS_MODULE,
+ .of_match_table = ptn3460_match,
+ },
+};
+module_i2c_driver(ptn3460_driver);
+
+MODULE_AUTHOR("Sean Paul <seanpaul@chromium.org>");
+MODULE_DESCRIPTION("NXP ptn3460 eDP-LVDS converter driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.c b/drivers/gpu/drm/cirrus/cirrus_drv.c
index c2a1cba1e984..b9140032962d 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.c
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.c
@@ -16,9 +16,12 @@
#include "cirrus_drv.h"
int cirrus_modeset = -1;
+int cirrus_bpp = 24;
MODULE_PARM_DESC(modeset, "Disable/Enable modesetting");
module_param_named(modeset, cirrus_modeset, int, 0400);
+MODULE_PARM_DESC(bpp, "Max bits-per-pixel (default:24)");
+module_param_named(bpp, cirrus_bpp, int, 0400);
/*
* This is the generic driver code. This binds the driver to the drm core,
diff --git a/drivers/gpu/drm/cirrus/cirrus_drv.h b/drivers/gpu/drm/cirrus/cirrus_drv.h
index 693a4565c4ff..705061537a27 100644
--- a/drivers/gpu/drm/cirrus/cirrus_drv.h
+++ b/drivers/gpu/drm/cirrus/cirrus_drv.h
@@ -262,4 +262,7 @@ static inline void cirrus_bo_unreserve(struct cirrus_bo *bo)
int cirrus_bo_push_sysram(struct cirrus_bo *bo);
int cirrus_bo_pin(struct cirrus_bo *bo, u32 pl_flag, u64 *gpu_addr);
+
+extern int cirrus_bpp;
+
#endif /* __CIRRUS_DRV_H__ */
diff --git a/drivers/gpu/drm/cirrus/cirrus_fbdev.c b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
index 502a89eb54b5..13ddf1c4bb8e 100644
--- a/drivers/gpu/drm/cirrus/cirrus_fbdev.c
+++ b/drivers/gpu/drm/cirrus/cirrus_fbdev.c
@@ -317,17 +317,17 @@ int cirrus_fbdev_init(struct cirrus_device *cdev)
ret = drm_fb_helper_init(cdev->dev, &gfbdev->helper,
cdev->num_crtc, CIRRUSFB_CONN_LIMIT);
- if (ret) {
- kfree(gfbdev);
+ if (ret)
+ return ret;
+
+ ret = drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
+ if (ret)
return ret;
- }
- drm_fb_helper_single_add_all_connectors(&gfbdev->helper);
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(cdev->dev);
- drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
- return 0;
+ return drm_fb_helper_initial_config(&gfbdev->helper, bpp_sel);
}
void cirrus_fbdev_fini(struct cirrus_device *cdev)
diff --git a/drivers/gpu/drm/cirrus/cirrus_main.c b/drivers/gpu/drm/cirrus/cirrus_main.c
index 4c2d68e9102d..e4b976658087 100644
--- a/drivers/gpu/drm/cirrus/cirrus_main.c
+++ b/drivers/gpu/drm/cirrus/cirrus_main.c
@@ -320,6 +320,8 @@ bool cirrus_check_framebuffer(struct cirrus_device *cdev, int width, int height,
const int max_pitch = 0x1FF << 3; /* (4096 - 1) & ~111b bytes */
const int max_size = cdev->mc.vram_size;
+ if (bpp > cirrus_bpp)
+ return false;
if (bpp > 32)
return false;
diff --git a/drivers/gpu/drm/cirrus/cirrus_mode.c b/drivers/gpu/drm/cirrus/cirrus_mode.c
index 99d4a74ffeaf..61385f2298bf 100644
--- a/drivers/gpu/drm/cirrus/cirrus_mode.c
+++ b/drivers/gpu/drm/cirrus/cirrus_mode.c
@@ -501,8 +501,13 @@ static int cirrus_vga_get_modes(struct drm_connector *connector)
int count;
/* Just add a static list of modes */
- count = drm_add_modes_noedid(connector, 1280, 1024);
- drm_set_preferred_mode(connector, 1024, 768);
+ if (cirrus_bpp <= 24) {
+ count = drm_add_modes_noedid(connector, 1280, 1024);
+ drm_set_preferred_mode(connector, 1024, 768);
+ } else {
+ count = drm_add_modes_noedid(connector, 800, 600);
+ drm_set_preferred_mode(connector, 800, 600);
+ }
return count;
}
diff --git a/drivers/gpu/drm/drm_atomic.c b/drivers/gpu/drm/drm_atomic.c
index ff5f034cc405..c2e9c5283136 100644
--- a/drivers/gpu/drm/drm_atomic.c
+++ b/drivers/gpu/drm/drm_atomic.c
@@ -56,6 +56,11 @@ drm_atomic_state_alloc(struct drm_device *dev)
if (!state)
return NULL;
+ /* TODO legacy paths should maybe do a better job about
+ * setting this appropriately?
+ */
+ state->allow_modeset = true;
+
state->num_connector = ACCESS_ONCE(dev->mode_config.num_connector);
state->crtcs = kcalloc(dev->mode_config.num_crtc,
@@ -129,6 +134,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
connector->funcs->atomic_destroy_state(connector,
state->connector_states[i]);
+ state->connector_states[i] = NULL;
}
for (i = 0; i < config->num_crtc; i++) {
@@ -139,6 +145,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
crtc->funcs->atomic_destroy_state(crtc,
state->crtc_states[i]);
+ state->crtc_states[i] = NULL;
}
for (i = 0; i < config->num_total_plane; i++) {
@@ -149,6 +156,7 @@ void drm_atomic_state_clear(struct drm_atomic_state *state)
plane->funcs->atomic_destroy_state(plane,
state->plane_states[i]);
+ state->plane_states[i] = NULL;
}
}
EXPORT_SYMBOL(drm_atomic_state_clear);
@@ -217,6 +225,83 @@ drm_atomic_get_crtc_state(struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_get_crtc_state);
/**
+ * drm_atomic_crtc_set_property - set property on CRTC
+ * @crtc: the drm CRTC to set a property on
+ * @state: the state object to update with the new property value
+ * @property: the property to set
+ * @val: the new property value
+ *
+ * Use this instead of calling crtc->atomic_set_property directly.
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_set_property() for driver properties. To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_crtc_set_property(struct drm_crtc *crtc,
+ struct drm_crtc_state *state, struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ /* FIXME: Mode prop is missing, which also controls ->enable. */
+ if (property == config->prop_active) {
+ state->active = val;
+ } else if (crtc->funcs->atomic_set_property)
+ return crtc->funcs->atomic_set_property(crtc, state, property, val);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(drm_atomic_crtc_set_property);
+
+/*
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_get_property() for driver properties. To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ */
+int drm_atomic_crtc_get_property(struct drm_crtc *crtc,
+ const struct drm_crtc_state *state,
+ struct drm_property *property, uint64_t *val)
+{
+ if (crtc->funcs->atomic_get_property)
+ return crtc->funcs->atomic_get_property(crtc, state, property, val);
+ return -EINVAL;
+}
+
+/**
+ * drm_atomic_crtc_check - check crtc state
+ * @crtc: crtc to check
+ * @state: crtc state to check
+ *
+ * Provides core sanity checks for crtc state.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static int drm_atomic_crtc_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ /* NOTE: we explicitly don't enforce constraints such as primary
+ * layer covering entire screen, since that is something we want
+ * to allow (on hw that supports it). For hw that does not, it
+ * should be checked in driver's crtc->atomic_check() vfunc.
+ *
+ * TODO: Add generic modeset state checks once we support those.
+ */
+
+ if (state->active && !state->enable) {
+ DRM_DEBUG_KMS("[CRTC:%d] active without enabled\n",
+ crtc->base.id);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
* drm_atomic_get_plane_state - get plane state
* @state: global atomic state object
* @plane: plane to get state object for
@@ -272,6 +357,185 @@ drm_atomic_get_plane_state(struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_get_plane_state);
/**
+ * drm_atomic_plane_set_property - set property on plane
+ * @plane: the drm plane to set a property on
+ * @state: the state object to update with the new property value
+ * @property: the property to set
+ * @val: the new property value
+ *
+ * Use this instead of calling plane->atomic_set_property directly.
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_set_property() for driver properties. To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_plane_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state, struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_fb_id) {
+ struct drm_framebuffer *fb = drm_framebuffer_lookup(dev, val);
+ drm_atomic_set_fb_for_plane(state, fb);
+ if (fb)
+ drm_framebuffer_unreference(fb);
+ } else if (property == config->prop_crtc_id) {
+ struct drm_crtc *crtc = drm_crtc_find(dev, val);
+ return drm_atomic_set_crtc_for_plane(state, crtc);
+ } else if (property == config->prop_crtc_x) {
+ state->crtc_x = U642I64(val);
+ } else if (property == config->prop_crtc_y) {
+ state->crtc_y = U642I64(val);
+ } else if (property == config->prop_crtc_w) {
+ state->crtc_w = val;
+ } else if (property == config->prop_crtc_h) {
+ state->crtc_h = val;
+ } else if (property == config->prop_src_x) {
+ state->src_x = val;
+ } else if (property == config->prop_src_y) {
+ state->src_y = val;
+ } else if (property == config->prop_src_w) {
+ state->src_w = val;
+ } else if (property == config->prop_src_h) {
+ state->src_h = val;
+ } else if (property == config->rotation_property) {
+ state->rotation = val;
+ } else if (plane->funcs->atomic_set_property) {
+ return plane->funcs->atomic_set_property(plane, state,
+ property, val);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_atomic_plane_set_property);
+
+/*
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_get_property() for driver properties. To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ */
+static int
+drm_atomic_plane_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_fb_id) {
+ *val = (state->fb) ? state->fb->base.id : 0;
+ } else if (property == config->prop_crtc_id) {
+ *val = (state->crtc) ? state->crtc->base.id : 0;
+ } else if (property == config->prop_crtc_x) {
+ *val = I642U64(state->crtc_x);
+ } else if (property == config->prop_crtc_y) {
+ *val = I642U64(state->crtc_y);
+ } else if (property == config->prop_crtc_w) {
+ *val = state->crtc_w;
+ } else if (property == config->prop_crtc_h) {
+ *val = state->crtc_h;
+ } else if (property == config->prop_src_x) {
+ *val = state->src_x;
+ } else if (property == config->prop_src_y) {
+ *val = state->src_y;
+ } else if (property == config->prop_src_w) {
+ *val = state->src_w;
+ } else if (property == config->prop_src_h) {
+ *val = state->src_h;
+ } else if (plane->funcs->atomic_get_property) {
+ return plane->funcs->atomic_get_property(plane, state, property, val);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * drm_atomic_plane_check - check plane state
+ * @plane: plane to check
+ * @state: plane state to check
+ *
+ * Provides core sanity checks for plane state.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+static int drm_atomic_plane_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ unsigned int fb_width, fb_height;
+ unsigned int i;
+
+ /* either *both* CRTC and FB must be set, or neither */
+ if (WARN_ON(state->crtc && !state->fb)) {
+ DRM_DEBUG_KMS("CRTC set but no FB\n");
+ return -EINVAL;
+ } else if (WARN_ON(state->fb && !state->crtc)) {
+ DRM_DEBUG_KMS("FB set but no CRTC\n");
+ return -EINVAL;
+ }
+
+ /* if disabled, we don't care about the rest of the state: */
+ if (!state->crtc)
+ return 0;
+
+ /* Check whether this plane is usable on this CRTC */
+ if (!(plane->possible_crtcs & drm_crtc_mask(state->crtc))) {
+ DRM_DEBUG_KMS("Invalid crtc for plane\n");
+ return -EINVAL;
+ }
+
+ /* Check whether this plane supports the fb pixel format. */
+ for (i = 0; i < plane->format_count; i++)
+ if (state->fb->pixel_format == plane->format_types[i])
+ break;
+ if (i == plane->format_count) {
+ DRM_DEBUG_KMS("Invalid pixel format %s\n",
+ drm_get_format_name(state->fb->pixel_format));
+ return -EINVAL;
+ }
+
+ /* Give drivers some help against integer overflows */
+ if (state->crtc_w > INT_MAX ||
+ state->crtc_x > INT_MAX - (int32_t) state->crtc_w ||
+ state->crtc_h > INT_MAX ||
+ state->crtc_y > INT_MAX - (int32_t) state->crtc_h) {
+ DRM_DEBUG_KMS("Invalid CRTC coordinates %ux%u+%d+%d\n",
+ state->crtc_w, state->crtc_h,
+ state->crtc_x, state->crtc_y);
+ return -ERANGE;
+ }
+
+ fb_width = state->fb->width << 16;
+ fb_height = state->fb->height << 16;
+
+ /* Make sure source coordinates are inside the fb. */
+ if (state->src_w > fb_width ||
+ state->src_x > fb_width - state->src_w ||
+ state->src_h > fb_height ||
+ state->src_y > fb_height - state->src_h) {
+ DRM_DEBUG_KMS("Invalid source coordinates "
+ "%u.%06ux%u.%06u+%u.%06u+%u.%06u\n",
+ state->src_w >> 16, ((state->src_w & 0xffff) * 15625) >> 10,
+ state->src_h >> 16, ((state->src_h & 0xffff) * 15625) >> 10,
+ state->src_x >> 16, ((state->src_x & 0xffff) * 15625) >> 10,
+ state->src_y >> 16, ((state->src_y & 0xffff) * 15625) >> 10);
+ return -ENOSPC;
+ }
+
+ return 0;
+}
+
+/**
* drm_atomic_get_connector_state - get connector state
* @state: global atomic state object
* @connector: connector to get state object for
@@ -343,9 +607,113 @@ drm_atomic_get_connector_state(struct drm_atomic_state *state,
EXPORT_SYMBOL(drm_atomic_get_connector_state);
/**
+ * drm_atomic_connector_set_property - set property on connector.
+ * @connector: the drm connector to set a property on
+ * @state: the state object to update with the new property value
+ * @property: the property to set
+ * @val: the new property value
+ *
+ * Use this instead of calling connector->atomic_set_property directly.
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_set_property() for driver properties. To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ *
+ * RETURNS:
+ * Zero on success, error code on failure
+ */
+int drm_atomic_connector_set_property(struct drm_connector *connector,
+ struct drm_connector_state *state, struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_crtc_id) {
+ struct drm_crtc *crtc = drm_crtc_find(dev, val);
+ return drm_atomic_set_crtc_for_connector(state, crtc);
+ } else if (property == config->dpms_property) {
+ /* setting DPMS property requires special handling, which
+ * is done in legacy setprop path for us. Disallow (for
+ * now?) atomic writes to DPMS property:
+ */
+ return -EINVAL;
+ } else if (connector->funcs->atomic_set_property) {
+ return connector->funcs->atomic_set_property(connector,
+ state, property, val);
+ } else {
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL(drm_atomic_connector_set_property);
+
+/*
+ * This function handles generic/core properties and calls out to
+ * driver's ->atomic_get_property() for driver properties. To ensure
+ * consistent behavior you must call this function rather than the
+ * driver hook directly.
+ */
+static int
+drm_atomic_connector_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = connector->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+
+ if (property == config->prop_crtc_id) {
+ *val = (state->crtc) ? state->crtc->base.id : 0;
+ } else if (property == config->dpms_property) {
+ *val = connector->dpms;
+ } else if (connector->funcs->atomic_get_property) {
+ return connector->funcs->atomic_get_property(connector,
+ state, property, val);
+ } else {
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int drm_atomic_get_property(struct drm_mode_object *obj,
+ struct drm_property *property, uint64_t *val)
+{
+ struct drm_device *dev = property->dev;
+ int ret;
+
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CONNECTOR: {
+ struct drm_connector *connector = obj_to_connector(obj);
+ WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));
+ ret = drm_atomic_connector_get_property(connector,
+ connector->state, property, val);
+ break;
+ }
+ case DRM_MODE_OBJECT_CRTC: {
+ struct drm_crtc *crtc = obj_to_crtc(obj);
+ WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
+ ret = drm_atomic_crtc_get_property(crtc,
+ crtc->state, property, val);
+ break;
+ }
+ case DRM_MODE_OBJECT_PLANE: {
+ struct drm_plane *plane = obj_to_plane(obj);
+ WARN_ON(!drm_modeset_is_locked(&plane->mutex));
+ ret = drm_atomic_plane_get_property(plane,
+ plane->state, property, val);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+/**
* drm_atomic_set_crtc_for_plane - set crtc for plane
- * @state: the incoming atomic state
- * @plane: the plane whose incoming state to update
+ * @plane_state: the plane whose incoming state to update
* @crtc: crtc to use for the plane
*
* Changing the assigned crtc for a plane requires us to grab the lock and state
@@ -358,16 +726,12 @@ EXPORT_SYMBOL(drm_atomic_get_connector_state);
* sequence must be restarted. All other errors are fatal.
*/
int
-drm_atomic_set_crtc_for_plane(struct drm_atomic_state *state,
- struct drm_plane *plane, struct drm_crtc *crtc)
+drm_atomic_set_crtc_for_plane(struct drm_plane_state *plane_state,
+ struct drm_crtc *crtc)
{
- struct drm_plane_state *plane_state =
- drm_atomic_get_plane_state(state, plane);
+ struct drm_plane *plane = plane_state->plane;
struct drm_crtc_state *crtc_state;
- if (WARN_ON(IS_ERR(plane_state)))
- return PTR_ERR(plane_state);
-
if (plane_state->crtc) {
crtc_state = drm_atomic_get_crtc_state(plane_state->state,
plane_state->crtc);
@@ -583,14 +947,63 @@ EXPORT_SYMBOL(drm_atomic_legacy_backoff);
*/
int drm_atomic_check_only(struct drm_atomic_state *state)
{
- struct drm_mode_config *config = &state->dev->mode_config;
+ struct drm_device *dev = state->dev;
+ struct drm_mode_config *config = &dev->mode_config;
+ int nplanes = config->num_total_plane;
+ int ncrtcs = config->num_crtc;
+ int i, ret = 0;
DRM_DEBUG_KMS("checking %p\n", state);
+ for (i = 0; i < nplanes; i++) {
+ struct drm_plane *plane = state->planes[i];
+
+ if (!plane)
+ continue;
+
+ ret = drm_atomic_plane_check(plane, state->plane_states[i]);
+ if (ret) {
+ DRM_DEBUG_KMS("[PLANE:%d] atomic core check failed\n",
+ plane->base.id);
+ return ret;
+ }
+ }
+
+ for (i = 0; i < ncrtcs; i++) {
+ struct drm_crtc *crtc = state->crtcs[i];
+
+ if (!crtc)
+ continue;
+
+ ret = drm_atomic_crtc_check(crtc, state->crtc_states[i]);
+ if (ret) {
+ DRM_DEBUG_KMS("[CRTC:%d] atomic core check failed\n",
+ crtc->base.id);
+ return ret;
+ }
+ }
+
if (config->funcs->atomic_check)
- return config->funcs->atomic_check(state->dev, state);
- else
- return 0;
+ ret = config->funcs->atomic_check(state->dev, state);
+
+ if (!state->allow_modeset) {
+ for (i = 0; i < ncrtcs; i++) {
+ struct drm_crtc *crtc = state->crtcs[i];
+ struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+ if (!crtc)
+ continue;
+
+ if (crtc_state->mode_changed ||
+ crtc_state->active_changed) {
+ DRM_DEBUG_KMS("[CRTC:%d] requires full modeset\n",
+ crtc->base.id);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return ret;
}
EXPORT_SYMBOL(drm_atomic_check_only);
@@ -655,3 +1068,315 @@ int drm_atomic_async_commit(struct drm_atomic_state *state)
return config->funcs->atomic_commit(state->dev, state, true);
}
EXPORT_SYMBOL(drm_atomic_async_commit);
+
+/*
+ * The big monstor ioctl
+ */
+
+static struct drm_pending_vblank_event *create_vblank_event(
+ struct drm_device *dev, struct drm_file *file_priv, uint64_t user_data)
+{
+ struct drm_pending_vblank_event *e = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ if (file_priv->event_space < sizeof e->event) {
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ goto out;
+ }
+ file_priv->event_space -= sizeof e->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+
+ e = kzalloc(sizeof *e, GFP_KERNEL);
+ if (e == NULL) {
+ spin_lock_irqsave(&dev->event_lock, flags);
+ file_priv->event_space += sizeof e->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ goto out;
+ }
+
+ e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
+ e->event.base.length = sizeof e->event;
+ e->event.user_data = user_data;
+ e->base.event = &e->event.base;
+ e->base.file_priv = file_priv;
+ e->base.destroy = (void (*) (struct drm_pending_event *)) kfree;
+
+out:
+ return e;
+}
+
+static void destroy_vblank_event(struct drm_device *dev,
+ struct drm_file *file_priv, struct drm_pending_vblank_event *e)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->event_lock, flags);
+ file_priv->event_space += sizeof e->event;
+ spin_unlock_irqrestore(&dev->event_lock, flags);
+ kfree(e);
+}
+
+static int atomic_set_prop(struct drm_atomic_state *state,
+ struct drm_mode_object *obj, struct drm_property *prop,
+ uint64_t prop_value)
+{
+ struct drm_mode_object *ref;
+ int ret;
+
+ if (!drm_property_change_valid_get(prop, prop_value, &ref))
+ return -EINVAL;
+
+ switch (obj->type) {
+ case DRM_MODE_OBJECT_CONNECTOR: {
+ struct drm_connector *connector = obj_to_connector(obj);
+ struct drm_connector_state *connector_state;
+
+ connector_state = drm_atomic_get_connector_state(state, connector);
+ if (IS_ERR(connector_state)) {
+ ret = PTR_ERR(connector_state);
+ break;
+ }
+
+ ret = drm_atomic_connector_set_property(connector,
+ connector_state, prop, prop_value);
+ break;
+ }
+ case DRM_MODE_OBJECT_CRTC: {
+ struct drm_crtc *crtc = obj_to_crtc(obj);
+ struct drm_crtc_state *crtc_state;
+
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state)) {
+ ret = PTR_ERR(crtc_state);
+ break;
+ }
+
+ ret = drm_atomic_crtc_set_property(crtc,
+ crtc_state, prop, prop_value);
+ break;
+ }
+ case DRM_MODE_OBJECT_PLANE: {
+ struct drm_plane *plane = obj_to_plane(obj);
+ struct drm_plane_state *plane_state;
+
+ plane_state = drm_atomic_get_plane_state(state, plane);
+ if (IS_ERR(plane_state)) {
+ ret = PTR_ERR(plane_state);
+ break;
+ }
+
+ ret = drm_atomic_plane_set_property(plane,
+ plane_state, prop, prop_value);
+ break;
+ }
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ drm_property_change_valid_put(prop, ref);
+ return ret;
+}
+
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv)
+{
+ struct drm_mode_atomic *arg = data;
+ uint32_t __user *objs_ptr = (uint32_t __user *)(unsigned long)(arg->objs_ptr);
+ uint32_t __user *count_props_ptr = (uint32_t __user *)(unsigned long)(arg->count_props_ptr);
+ uint32_t __user *props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
+ uint64_t __user *prop_values_ptr = (uint64_t __user *)(unsigned long)(arg->prop_values_ptr);
+ unsigned int copied_objs, copied_props;
+ struct drm_atomic_state *state;
+ struct drm_modeset_acquire_ctx ctx;
+ struct drm_plane *plane;
+ unsigned plane_mask = 0;
+ int ret = 0;
+ unsigned int i, j;
+
+ /* disallow for drivers not supporting atomic: */
+ if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+ return -EINVAL;
+
+ /* disallow for userspace that has not enabled atomic cap (even
+ * though this may be a bit overkill, since legacy userspace
+ * wouldn't know how to call this ioctl)
+ */
+ if (!file_priv->atomic)
+ return -EINVAL;
+
+ if (arg->flags & ~DRM_MODE_ATOMIC_FLAGS)
+ return -EINVAL;
+
+ if (arg->reserved)
+ return -EINVAL;
+
+ if ((arg->flags & DRM_MODE_PAGE_FLIP_ASYNC) &&
+ !dev->mode_config.async_page_flip)
+ return -EINVAL;
+
+ /* can't test and expect an event at the same time. */
+ if ((arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) &&
+ (arg->flags & DRM_MODE_PAGE_FLIP_EVENT))
+ return -EINVAL;
+
+ drm_modeset_acquire_init(&ctx, 0);
+
+ state = drm_atomic_state_alloc(dev);
+ if (!state)
+ return -ENOMEM;
+
+ state->acquire_ctx = &ctx;
+ state->allow_modeset = !!(arg->flags & DRM_MODE_ATOMIC_ALLOW_MODESET);
+
+retry:
+ copied_objs = 0;
+ copied_props = 0;
+
+ for (i = 0; i < arg->count_objs; i++) {
+ uint32_t obj_id, count_props;
+ struct drm_mode_object *obj;
+
+ if (get_user(obj_id, objs_ptr + copied_objs)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ obj = drm_mode_object_find(dev, obj_id, DRM_MODE_OBJECT_ANY);
+ if (!obj || !obj->properties) {
+ ret = -ENOENT;
+ goto fail;
+ }
+
+ if (obj->type == DRM_MODE_OBJECT_PLANE) {
+ plane = obj_to_plane(obj);
+ plane_mask |= (1 << drm_plane_index(plane));
+ plane->old_fb = plane->fb;
+ }
+
+ if (get_user(count_props, count_props_ptr + copied_objs)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ copied_objs++;
+
+ for (j = 0; j < count_props; j++) {
+ uint32_t prop_id;
+ uint64_t prop_value;
+ struct drm_property *prop;
+
+ if (get_user(prop_id, props_ptr + copied_props)) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ prop = drm_property_find(dev, prop_id);
+ if (!prop) {
+ ret = -ENOENT;
+ goto fail;
+ }
+
+ if (copy_from_user(&prop_value,
+ prop_values_ptr + copied_props,
+ sizeof(prop_value))) {
+ ret = -EFAULT;
+ goto fail;
+ }
+
+ ret = atomic_set_prop(state, obj, prop, prop_value);
+ if (ret)
+ goto fail;
+
+ copied_props++;
+ }
+ }
+
+ if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+ int ncrtcs = dev->mode_config.num_crtc;
+
+ for (i = 0; i < ncrtcs; i++) {
+ struct drm_crtc_state *crtc_state = state->crtc_states[i];
+ struct drm_pending_vblank_event *e;
+
+ if (!crtc_state)
+ continue;
+
+ e = create_vblank_event(dev, file_priv, arg->user_data);
+ if (!e) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ crtc_state->event = e;
+ }
+ }
+
+ if (arg->flags & DRM_MODE_ATOMIC_TEST_ONLY) {
+ ret = drm_atomic_check_only(state);
+ /* _check_only() does not free state, unlike _commit() */
+ drm_atomic_state_free(state);
+ } else if (arg->flags & DRM_MODE_ATOMIC_NONBLOCK) {
+ ret = drm_atomic_async_commit(state);
+ } else {
+ ret = drm_atomic_commit(state);
+ }
+
+ /* if succeeded, fixup legacy plane crtc/fb ptrs before dropping
+ * locks (ie. while it is still safe to deref plane->state). We
+ * need to do this here because the driver entry points cannot
+ * distinguish between legacy and atomic ioctls.
+ */
+ drm_for_each_plane_mask(plane, dev, plane_mask) {
+ if (ret == 0) {
+ struct drm_framebuffer *new_fb = plane->state->fb;
+ if (new_fb)
+ drm_framebuffer_reference(new_fb);
+ plane->fb = new_fb;
+ plane->crtc = plane->state->crtc;
+ } else {
+ plane->old_fb = NULL;
+ }
+ if (plane->old_fb) {
+ drm_framebuffer_unreference(plane->old_fb);
+ plane->old_fb = NULL;
+ }
+ }
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ return ret;
+
+fail:
+ if (ret == -EDEADLK)
+ goto backoff;
+
+ if (arg->flags & DRM_MODE_PAGE_FLIP_EVENT) {
+ int ncrtcs = dev->mode_config.num_crtc;
+
+ for (i = 0; i < ncrtcs; i++) {
+ struct drm_crtc_state *crtc_state = state->crtc_states[i];
+
+ if (!crtc_state)
+ continue;
+
+ destroy_vblank_event(dev, file_priv, crtc_state->event);
+ crtc_state->event = NULL;
+ }
+ }
+
+ drm_atomic_state_free(state);
+
+ drm_modeset_drop_locks(&ctx);
+ drm_modeset_acquire_fini(&ctx);
+
+ return ret;
+
+backoff:
+ drm_atomic_state_clear(state);
+ drm_modeset_backoff(&ctx);
+
+ goto retry;
+}
diff --git a/drivers/gpu/drm/drm_atomic_helper.c b/drivers/gpu/drm/drm_atomic_helper.c
index bbdbe4721573..7e3a52b97c7d 100644
--- a/drivers/gpu/drm/drm_atomic_helper.c
+++ b/drivers/gpu/drm/drm_atomic_helper.c
@@ -297,13 +297,22 @@ mode_fixup(struct drm_atomic_state *state)
}
}
-
- ret = funcs->mode_fixup(encoder, &crtc_state->mode,
- &crtc_state->adjusted_mode);
- if (!ret) {
- DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
- encoder->base.id, encoder->name);
- return -EINVAL;
+ if (funcs->atomic_check) {
+ ret = funcs->atomic_check(encoder, crtc_state,
+ conn_state);
+ if (ret) {
+ DRM_DEBUG_KMS("[ENCODER:%d:%s] check failed\n",
+ encoder->base.id, encoder->name);
+ return ret;
+ }
+ } else {
+ ret = funcs->mode_fixup(encoder, &crtc_state->mode,
+ &crtc_state->adjusted_mode);
+ if (!ret) {
+ DRM_DEBUG_KMS("[ENCODER:%d:%s] fixup failed\n",
+ encoder->base.id, encoder->name);
+ return -EINVAL;
+ }
}
}
@@ -330,7 +339,35 @@ mode_fixup(struct drm_atomic_state *state)
return 0;
}
-static int
+static bool
+needs_modeset(struct drm_crtc_state *state)
+{
+ return state->mode_changed || state->active_changed;
+}
+
+/**
+ * drm_atomic_helper_check - validate state object for modeset changes
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Check the state object to see if the requested state is physically possible.
+ * This does all the crtc and connector related computations for an atomic
+ * update. It computes and updates crtc_state->mode_changed, adds any additional
+ * connectors needed for full modesets and calls down into ->mode_fixup
+ * functions of the driver backend.
+ *
+ * IMPORTANT:
+ *
+ * Drivers which update ->mode_changed (e.g. in their ->atomic_check hooks if a
+ * plane update can't be done without a full modeset) _must_ call this function
+ * afterwards after that change. It is permitted to call this function multiple
+ * times for the same update, e.g. when the ->atomic_check functions depend upon
+ * the adjusted dotclock for fifo space allocation and watermark computation.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int
drm_atomic_helper_check_modeset(struct drm_device *dev,
struct drm_atomic_state *state)
{
@@ -382,12 +419,27 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
crtc = state->crtcs[i];
crtc_state = state->crtc_states[i];
- if (!crtc || !crtc_state->mode_changed)
+ if (!crtc)
continue;
- DRM_DEBUG_KMS("[CRTC:%d] needs full modeset, enable: %c\n",
+ /*
+ * We must set ->active_changed after walking connectors for
+ * otherwise an update that only changes active would result in
+ * a full modeset because update_connector_routing force that.
+ */
+ if (crtc->state->active != crtc_state->active) {
+ DRM_DEBUG_KMS("[CRTC:%d] active changed\n",
+ crtc->base.id);
+ crtc_state->active_changed = true;
+ }
+
+ if (!needs_modeset(crtc_state))
+ continue;
+
+ DRM_DEBUG_KMS("[CRTC:%d] needs all connectors, enable: %c, active: %c\n",
crtc->base.id,
- crtc_state->enable ? 'y' : 'n');
+ crtc_state->enable ? 'y' : 'n',
+ crtc_state->active ? 'y' : 'n');
ret = drm_atomic_add_affected_connectors(state, crtc);
if (ret != 0)
@@ -406,23 +458,23 @@ drm_atomic_helper_check_modeset(struct drm_device *dev,
return mode_fixup(state);
}
+EXPORT_SYMBOL(drm_atomic_helper_check_modeset);
/**
- * drm_atomic_helper_check - validate state object
+ * drm_atomic_helper_check - validate state object for modeset changes
* @dev: DRM device
* @state: the driver state object
*
* Check the state object to see if the requested state is physically possible.
- * Only crtcs and planes have check callbacks, so for any additional (global)
- * checking that a driver needs it can simply wrap that around this function.
- * Drivers without such needs can directly use this as their ->atomic_check()
- * callback.
+ * This does all the plane update related checks using by calling into the
+ * ->atomic_check hooks provided by the driver.
*
* RETURNS
* Zero for success or -errno
*/
-int drm_atomic_helper_check(struct drm_device *dev,
- struct drm_atomic_state *state)
+int
+drm_atomic_helper_check_planes(struct drm_device *dev,
+ struct drm_atomic_state *state)
{
int nplanes = dev->mode_config.num_total_plane;
int ncrtcs = dev->mode_config.num_crtc;
@@ -445,7 +497,7 @@ int drm_atomic_helper_check(struct drm_device *dev,
ret = funcs->atomic_check(plane, plane_state);
if (ret) {
- DRM_DEBUG_KMS("[PLANE:%d] atomic check failed\n",
+ DRM_DEBUG_KMS("[PLANE:%d] atomic driver check failed\n",
plane->base.id);
return ret;
}
@@ -465,16 +517,49 @@ int drm_atomic_helper_check(struct drm_device *dev,
ret = funcs->atomic_check(crtc, state->crtc_states[i]);
if (ret) {
- DRM_DEBUG_KMS("[CRTC:%d] atomic check failed\n",
+ DRM_DEBUG_KMS("[CRTC:%d] atomic driver check failed\n",
crtc->base.id);
return ret;
}
}
+ return ret;
+}
+EXPORT_SYMBOL(drm_atomic_helper_check_planes);
+
+/**
+ * drm_atomic_helper_check - validate state object
+ * @dev: DRM device
+ * @state: the driver state object
+ *
+ * Check the state object to see if the requested state is physically possible.
+ * Only crtcs and planes have check callbacks, so for any additional (global)
+ * checking that a driver needs it can simply wrap that around this function.
+ * Drivers without such needs can directly use this as their ->atomic_check()
+ * callback.
+ *
+ * This just wraps the two parts of the state checking for planes and modeset
+ * state in the default order: First it calls drm_atomic_helper_check_modeset()
+ * and then drm_atomic_helper_check_planes(). The assumption is that the
+ * ->atomic_check functions depend upon an updated adjusted_mode.clock to
+ * e.g. properly compute watermarks.
+ *
+ * RETURNS
+ * Zero for success or -errno
+ */
+int drm_atomic_helper_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ int ret;
+
ret = drm_atomic_helper_check_modeset(dev, state);
if (ret)
return ret;
+ ret = drm_atomic_helper_check_planes(dev, state);
+ if (ret)
+ return ret;
+
return ret;
}
EXPORT_SYMBOL(drm_atomic_helper_check);
@@ -490,6 +575,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
struct drm_connector *connector;
struct drm_encoder_helper_funcs *funcs;
struct drm_encoder *encoder;
+ struct drm_crtc_state *old_crtc_state;
old_conn_state = old_state->connector_states[i];
connector = old_state->connectors[i];
@@ -499,6 +585,11 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
if (!old_conn_state || !old_conn_state->crtc)
continue;
+ old_crtc_state = old_state->crtc_states[drm_crtc_index(old_conn_state->crtc)];
+
+ if (!old_crtc_state->active)
+ continue;
+
encoder = old_conn_state->best_encoder;
/* We shouldn't get this far if we didn't previously have
@@ -509,6 +600,9 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs = encoder->helper_private;
+ DRM_DEBUG_KMS("disabling [ENCODER:%d:%s]\n",
+ encoder->base.id, encoder->name);
+
/*
* Each encoder has at most one connector (since we always steal
* it away), so we won't call call disable hooks twice.
@@ -517,7 +611,7 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
encoder->bridge->funcs->disable(encoder->bridge);
/* Right function depends upon target state. */
- if (connector->state->crtc)
+ if (connector->state->crtc && funcs->prepare)
funcs->prepare(encoder);
else if (funcs->disable)
funcs->disable(encoder);
@@ -531,17 +625,26 @@ disable_outputs(struct drm_device *dev, struct drm_atomic_state *old_state)
for (i = 0; i < ncrtcs; i++) {
struct drm_crtc_helper_funcs *funcs;
struct drm_crtc *crtc;
+ struct drm_crtc_state *old_crtc_state;
crtc = old_state->crtcs[i];
+ old_crtc_state = old_state->crtc_states[i];
/* Shut down everything that needs a full modeset. */
- if (!crtc || !crtc->state->mode_changed)
+ if (!crtc || !needs_modeset(crtc->state))
+ continue;
+
+ if (!old_crtc_state->active)
continue;
funcs = crtc->helper_private;
+ DRM_DEBUG_KMS("disabling [CRTC:%d]\n",
+ crtc->base.id);
+
+
/* Right function depends upon target state. */
- if (crtc->state->enable)
+ if (crtc->state->enable && funcs->prepare)
funcs->prepare(crtc);
else if (funcs->disable)
funcs->disable(crtc);
@@ -620,8 +723,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
funcs = crtc->helper_private;
- if (crtc->state->enable)
+ if (crtc->state->enable) {
+ DRM_DEBUG_KMS("modeset on [CRTC:%d]\n",
+ crtc->base.id);
+
funcs->mode_set_nofb(crtc);
+ }
}
for (i = 0; i < old_state->num_connector; i++) {
@@ -642,6 +749,12 @@ crtc_set_mode(struct drm_device *dev, struct drm_atomic_state *old_state)
mode = &new_crtc_state->mode;
adjusted_mode = &new_crtc_state->adjusted_mode;
+ if (!new_crtc_state->mode_changed)
+ continue;
+
+ DRM_DEBUG_KMS("modeset on [ENCODER:%d:%s]\n",
+ encoder->base.id, encoder->name);
+
/*
* Each encoder has at most one connector (since we always steal
* it away), so we won't call call mode_set hooks twice.
@@ -694,13 +807,23 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
crtc = old_state->crtcs[i];
/* Need to filter out CRTCs where only planes change. */
- if (!crtc || !crtc->state->mode_changed)
+ if (!crtc || !needs_modeset(crtc->state))
+ continue;
+
+ if (!crtc->state->active)
continue;
funcs = crtc->helper_private;
- if (crtc->state->enable)
- funcs->commit(crtc);
+ if (crtc->state->enable) {
+ DRM_DEBUG_KMS("enabling [CRTC:%d]\n",
+ crtc->base.id);
+
+ if (funcs->enable)
+ funcs->enable(crtc);
+ else
+ funcs->commit(crtc);
+ }
}
for (i = 0; i < old_state->num_connector; i++) {
@@ -713,9 +836,15 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
if (!connector || !connector->state->best_encoder)
continue;
+ if (!connector->state->crtc->state->active)
+ continue;
+
encoder = connector->state->best_encoder;
funcs = encoder->helper_private;
+ DRM_DEBUG_KMS("enabling [ENCODER:%d:%s]\n",
+ encoder->base.id, encoder->name);
+
/*
* Each encoder has at most one connector (since we always steal
* it away), so we won't call call enable hooks twice.
@@ -723,7 +852,10 @@ void drm_atomic_helper_commit_post_planes(struct drm_device *dev,
if (encoder->bridge)
encoder->bridge->funcs->pre_enable(encoder->bridge);
- funcs->commit(encoder);
+ if (funcs->enable)
+ funcs->enable(encoder);
+ else
+ funcs->commit(encoder);
if (encoder->bridge)
encoder->bridge->funcs->enable(encoder->bridge);
@@ -813,6 +945,11 @@ drm_atomic_helper_wait_for_vblanks(struct drm_device *dev,
if (!crtc->state->enable)
continue;
+ /* Legacy cursor ioctls are completely unsynced, and userspace
+ * relies on that (by doing tons of cursor updates). */
+ if (old_state->legacy_cursor_update)
+ continue;
+
if (!framebuffer_changed(dev, old_state, crtc))
continue;
@@ -1053,12 +1190,19 @@ void drm_atomic_helper_commit_planes(struct drm_device *dev,
funcs = plane->helper_private;
- if (!funcs || !funcs->atomic_update)
+ if (!funcs)
continue;
old_plane_state = old_state->plane_states[i];
- funcs->atomic_update(plane, old_plane_state);
+ /*
+ * Special-case disabling the plane if drivers support it.
+ */
+ if (drm_atomic_plane_disabling(plane, old_plane_state) &&
+ funcs->atomic_disable)
+ funcs->atomic_disable(plane, old_plane_state);
+ else
+ funcs->atomic_update(plane, old_plane_state);
}
for (i = 0; i < ncrtcs; i++) {
@@ -1222,7 +1366,7 @@ retry:
goto fail;
}
- ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
+ ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
if (ret != 0)
goto fail;
drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1239,6 +1383,9 @@ retry:
if (ret != 0)
goto fail;
+ if (plane == crtc->cursor)
+ state->legacy_cursor_update = true;
+
/* Driver takes ownership of state on successful commit. */
return 0;
fail:
@@ -1301,7 +1448,7 @@ retry:
goto fail;
}
- ret = drm_atomic_set_crtc_for_plane(state, plane, NULL);
+ ret = drm_atomic_set_crtc_for_plane(plane_state, NULL);
if (ret != 0)
goto fail;
drm_atomic_set_fb_for_plane(plane_state, NULL);
@@ -1314,6 +1461,9 @@ retry:
plane_state->src_h = 0;
plane_state->src_w = 0;
+ if (plane == plane->crtc->cursor)
+ state->legacy_cursor_update = true;
+
ret = drm_atomic_commit(state);
if (ret != 0)
goto fail;
@@ -1463,8 +1613,9 @@ retry:
WARN_ON(set->num_connectors);
crtc_state->enable = false;
+ crtc_state->active = false;
- ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, NULL);
+ ret = drm_atomic_set_crtc_for_plane(primary_state, NULL);
if (ret != 0)
goto fail;
@@ -1477,9 +1628,10 @@ retry:
WARN_ON(!set->num_connectors);
crtc_state->enable = true;
+ crtc_state->active = true;
drm_mode_copy(&crtc_state->mode, set->mode);
- ret = drm_atomic_set_crtc_for_plane(state, crtc->primary, crtc);
+ ret = drm_atomic_set_crtc_for_plane(primary_state, crtc);
if (ret != 0)
goto fail;
drm_atomic_set_fb_for_plane(primary_state, set->fb);
@@ -1558,8 +1710,8 @@ retry:
goto fail;
}
- ret = crtc->funcs->atomic_set_property(crtc, crtc_state,
- property, val);
+ ret = drm_atomic_crtc_set_property(crtc, crtc_state,
+ property, val);
if (ret)
goto fail;
@@ -1617,8 +1769,8 @@ retry:
goto fail;
}
- ret = plane->funcs->atomic_set_property(plane, plane_state,
- property, val);
+ ret = drm_atomic_plane_set_property(plane, plane_state,
+ property, val);
if (ret)
goto fail;
@@ -1676,8 +1828,8 @@ retry:
goto fail;
}
- ret = connector->funcs->atomic_set_property(connector, connector_state,
- property, val);
+ ret = drm_atomic_connector_set_property(connector, connector_state,
+ property, val);
if (ret)
goto fail;
@@ -1751,7 +1903,7 @@ retry:
goto fail;
}
- ret = drm_atomic_set_crtc_for_plane(state, plane, crtc);
+ ret = drm_atomic_set_crtc_for_plane(plane_state, crtc);
if (ret != 0)
goto fail;
drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -1789,6 +1941,83 @@ backoff:
EXPORT_SYMBOL(drm_atomic_helper_page_flip);
/**
+ * drm_atomic_helper_connector_dpms() - connector dpms helper implementation
+ * @connector: affected connector
+ * @mode: DPMS mode
+ *
+ * This is the main helper function provided by the atomic helper framework for
+ * implementing the legacy DPMS connector interface. It computes the new desired
+ * ->active state for the corresponding CRTC (if the connector is enabled) and
+ * updates it.
+ */
+void drm_atomic_helper_connector_dpms(struct drm_connector *connector,
+ int mode)
+{
+ struct drm_mode_config *config = &connector->dev->mode_config;
+ struct drm_atomic_state *state;
+ struct drm_crtc_state *crtc_state;
+ struct drm_crtc *crtc;
+ struct drm_connector *tmp_connector;
+ int ret;
+ bool active = false;
+
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
+ connector->dpms = mode;
+ crtc = connector->state->crtc;
+
+ if (!crtc)
+ return;
+
+ /* FIXME: ->dpms has no return value so can't forward the -ENOMEM. */
+ state = drm_atomic_state_alloc(connector->dev);
+ if (!state)
+ return;
+
+ state->acquire_ctx = drm_modeset_legacy_acquire_ctx(crtc);
+retry:
+ crtc_state = drm_atomic_get_crtc_state(state, crtc);
+ if (IS_ERR(crtc_state))
+ return;
+
+ WARN_ON(!drm_modeset_is_locked(&config->connection_mutex));
+
+ list_for_each_entry(tmp_connector, &config->connector_list, head) {
+ if (connector->state->crtc != crtc)
+ continue;
+
+ if (connector->dpms == DRM_MODE_DPMS_ON) {
+ active = true;
+ break;
+ }
+ }
+ crtc_state->active = active;
+
+ ret = drm_atomic_commit(state);
+ if (ret != 0)
+ goto fail;
+
+ /* Driver takes ownership of state on successful async commit. */
+ return;
+fail:
+ if (ret == -EDEADLK)
+ goto backoff;
+
+ drm_atomic_state_free(state);
+
+ WARN(1, "Driver bug: Changing ->active failed with ret=%i\n", ret);
+
+ return;
+backoff:
+ drm_atomic_state_clear(state);
+ drm_atomic_legacy_backoff(state);
+
+ goto retry;
+}
+EXPORT_SYMBOL(drm_atomic_helper_connector_dpms);
+
+/**
* DOC: atomic state reset and initialization
*
* Both the drm core and the atomic helpers assume that there is always the full
@@ -1814,6 +2043,9 @@ void drm_atomic_helper_crtc_reset(struct drm_crtc *crtc)
{
kfree(crtc->state);
crtc->state = kzalloc(sizeof(*crtc->state), GFP_KERNEL);
+
+ if (crtc->state)
+ crtc->state->crtc = crtc;
}
EXPORT_SYMBOL(drm_atomic_helper_crtc_reset);
@@ -1836,6 +2068,7 @@ drm_atomic_helper_crtc_duplicate_state(struct drm_crtc *crtc)
if (state) {
state->mode_changed = false;
+ state->active_changed = false;
state->planes_changed = false;
state->event = NULL;
}
@@ -1873,6 +2106,9 @@ void drm_atomic_helper_plane_reset(struct drm_plane *plane)
kfree(plane->state);
plane->state = kzalloc(sizeof(*plane->state), GFP_KERNEL);
+
+ if (plane->state)
+ plane->state->plane = plane;
}
EXPORT_SYMBOL(drm_atomic_helper_plane_reset);
@@ -1930,6 +2166,9 @@ void drm_atomic_helper_connector_reset(struct drm_connector *connector)
{
kfree(connector->state);
connector->state = kzalloc(sizeof(*connector->state), GFP_KERNEL);
+
+ if (connector->state)
+ connector->state->connector = connector;
}
EXPORT_SYMBOL(drm_atomic_helper_connector_reset);
diff --git a/drivers/gpu/drm/drm_bridge.c b/drivers/gpu/drm/drm_bridge.c
new file mode 100644
index 000000000000..d1187e571c6d
--- /dev/null
+++ b/drivers/gpu/drm/drm_bridge.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., 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, sub license,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <linux/err.h>
+#include <linux/module.h>
+
+#include <drm/drm_crtc.h>
+
+#include "drm/drmP.h"
+
+static DEFINE_MUTEX(bridge_lock);
+static LIST_HEAD(bridge_list);
+
+int drm_bridge_add(struct drm_bridge *bridge)
+{
+ mutex_lock(&bridge_lock);
+ list_add_tail(&bridge->list, &bridge_list);
+ mutex_unlock(&bridge_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_bridge_add);
+
+void drm_bridge_remove(struct drm_bridge *bridge)
+{
+ mutex_lock(&bridge_lock);
+ list_del_init(&bridge->list);
+ mutex_unlock(&bridge_lock);
+}
+EXPORT_SYMBOL(drm_bridge_remove);
+
+extern int drm_bridge_attach(struct drm_device *dev, struct drm_bridge *bridge)
+{
+ if (!dev || !bridge)
+ return -EINVAL;
+
+ if (bridge->dev)
+ return -EBUSY;
+
+ bridge->dev = dev;
+
+ if (bridge->funcs->attach)
+ return bridge->funcs->attach(bridge);
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_bridge_attach);
+
+#ifdef CONFIG_OF
+struct drm_bridge *of_drm_find_bridge(struct device_node *np)
+{
+ struct drm_bridge *bridge;
+
+ mutex_lock(&bridge_lock);
+
+ list_for_each_entry(bridge, &bridge_list, list) {
+ if (bridge->of_node == np) {
+ mutex_unlock(&bridge_lock);
+ return bridge;
+ }
+ }
+
+ mutex_unlock(&bridge_lock);
+ return NULL;
+}
+EXPORT_SYMBOL(of_drm_find_bridge);
+#endif
+
+MODULE_AUTHOR("Ajay Kumar <ajaykumar.rs@samsung.com>");
+MODULE_DESCRIPTION("DRM bridge infrastructure");
+MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/drm_cache.c b/drivers/gpu/drm/drm_cache.c
index a6b690626a6b..9a62d7a53553 100644
--- a/drivers/gpu/drm/drm_cache.c
+++ b/drivers/gpu/drm/drm_cache.c
@@ -32,6 +32,7 @@
#include <drm/drmP.h>
#if defined(CONFIG_X86)
+#include <asm/smp.h>
/*
* clflushopt is an unordered instruction which needs fencing with mfence or
@@ -64,12 +65,6 @@ static void drm_cache_flush_clflush(struct page *pages[],
drm_clflush_page(*pages++);
mb();
}
-
-static void
-drm_clflush_ipi_handler(void *null)
-{
- wbinvd();
-}
#endif
void
@@ -82,7 +77,7 @@ drm_clflush_pages(struct page *pages[], unsigned long num_pages)
return;
}
- if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+ if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n");
#elif defined(__powerpc__)
@@ -121,7 +116,7 @@ drm_clflush_sg(struct sg_table *st)
return;
}
- if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+ if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n");
#else
printk(KERN_ERR "Architecture has no drm_cache.c support\n");
@@ -144,7 +139,7 @@ drm_clflush_virt_range(void *addr, unsigned long length)
return;
}
- if (on_each_cpu(drm_clflush_ipi_handler, NULL, 1) != 0)
+ if (wbinvd_on_all_cpus())
printk(KERN_ERR "Timed out waiting for cache flush.\n");
#else
printk(KERN_ERR "Architecture has no drm_cache.c support\n");
diff --git a/drivers/gpu/drm/drm_crtc.c b/drivers/gpu/drm/drm_crtc.c
index 5213da499d39..6b6b07ff720b 100644
--- a/drivers/gpu/drm/drm_crtc.c
+++ b/drivers/gpu/drm/drm_crtc.c
@@ -38,6 +38,7 @@
#include <drm/drm_edid.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_modeset_lock.h>
+#include <drm/drm_atomic.h>
#include "drm_crtc_internal.h"
#include "drm_internal.h"
@@ -61,8 +62,8 @@ static struct drm_framebuffer *add_framebuffer_internal(struct drm_device *dev,
/*
* Global properties
*/
-static const struct drm_prop_enum_list drm_dpms_enum_list[] =
-{ { DRM_MODE_DPMS_ON, "On" },
+static const struct drm_prop_enum_list drm_dpms_enum_list[] = {
+ { DRM_MODE_DPMS_ON, "On" },
{ DRM_MODE_DPMS_STANDBY, "Standby" },
{ DRM_MODE_DPMS_SUSPEND, "Suspend" },
{ DRM_MODE_DPMS_OFF, "Off" }
@@ -70,8 +71,7 @@ static const struct drm_prop_enum_list drm_dpms_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_dpms_name, drm_dpms_enum_list)
-static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_plane_type_enum_list[] = {
{ DRM_PLANE_TYPE_OVERLAY, "Overlay" },
{ DRM_PLANE_TYPE_PRIMARY, "Primary" },
{ DRM_PLANE_TYPE_CURSOR, "Cursor" },
@@ -80,8 +80,7 @@ static const struct drm_prop_enum_list drm_plane_type_enum_list[] =
/*
* Optional properties
*/
-static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_scaling_mode_enum_list[] = {
{ DRM_MODE_SCALE_NONE, "None" },
{ DRM_MODE_SCALE_FULLSCREEN, "Full" },
{ DRM_MODE_SCALE_CENTER, "Center" },
@@ -97,8 +96,7 @@ static const struct drm_prop_enum_list drm_aspect_ratio_enum_list[] = {
/*
* Non-global properties, but "required" for certain connectors.
*/
-static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
{ DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
@@ -106,8 +104,7 @@ static const struct drm_prop_enum_list drm_dvi_i_select_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_dvi_i_select_name, drm_dvi_i_select_enum_list)
-static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_DVID, "DVI-D" }, /* DVI-I */
{ DRM_MODE_SUBCONNECTOR_DVIA, "DVI-A" }, /* DVI-I */
@@ -116,8 +113,7 @@ static const struct drm_prop_enum_list drm_dvi_i_subconnector_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_dvi_i_subconnector_name,
drm_dvi_i_subconnector_enum_list)
-static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_tv_select_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Automatic, "Automatic" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
{ DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
@@ -127,8 +123,7 @@ static const struct drm_prop_enum_list drm_tv_select_enum_list[] =
DRM_ENUM_NAME_FN(drm_get_tv_select_name, drm_tv_select_enum_list)
-static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_tv_subconnector_enum_list[] = {
{ DRM_MODE_SUBCONNECTOR_Unknown, "Unknown" }, /* DVI-I and TV-out */
{ DRM_MODE_SUBCONNECTOR_Composite, "Composite" }, /* TV-out */
{ DRM_MODE_SUBCONNECTOR_SVIDEO, "SVIDEO" }, /* TV-out */
@@ -154,8 +149,8 @@ struct drm_conn_prop_enum_list {
/*
* Connector and encoder types.
*/
-static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
-{ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
+static struct drm_conn_prop_enum_list drm_connector_enum_list[] = {
+ { DRM_MODE_CONNECTOR_Unknown, "Unknown" },
{ DRM_MODE_CONNECTOR_VGA, "VGA" },
{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
@@ -174,8 +169,8 @@ static struct drm_conn_prop_enum_list drm_connector_enum_list[] =
{ DRM_MODE_CONNECTOR_DSI, "DSI" },
};
-static const struct drm_prop_enum_list drm_encoder_enum_list[] =
-{ { DRM_MODE_ENCODER_NONE, "None" },
+static const struct drm_prop_enum_list drm_encoder_enum_list[] = {
+ { DRM_MODE_ENCODER_NONE, "None" },
{ DRM_MODE_ENCODER_DAC, "DAC" },
{ DRM_MODE_ENCODER_TMDS, "TMDS" },
{ DRM_MODE_ENCODER_LVDS, "LVDS" },
@@ -185,8 +180,7 @@ static const struct drm_prop_enum_list drm_encoder_enum_list[] =
{ DRM_MODE_ENCODER_DPMST, "DP MST" },
};
-static const struct drm_prop_enum_list drm_subpixel_enum_list[] =
-{
+static const struct drm_prop_enum_list drm_subpixel_enum_list[] = {
{ SubPixelUnknown, "Unknown" },
{ SubPixelHorizontalRGB, "Horizontal RGB" },
{ SubPixelHorizontalBGR, "Horizontal BGR" },
@@ -697,6 +691,10 @@ int drm_crtc_init_with_planes(struct drm_device *dev, struct drm_crtc *crtc,
if (cursor)
cursor->possible_crtcs = 1 << drm_crtc_index(crtc);
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+ drm_object_attach_property(&crtc->base, config->prop_active, 0);
+ }
+
return 0;
}
EXPORT_SYMBOL(drm_crtc_init_with_planes);
@@ -768,6 +766,40 @@ static void drm_mode_remove(struct drm_connector *connector,
}
/**
+ * drm_display_info_set_bus_formats - set the supported bus formats
+ * @info: display info to store bus formats in
+ * @formats: array containing the supported bus formats
+ * @num_formats: the number of entries in the fmts array
+ *
+ * Store the supported bus formats in display info structure.
+ * See MEDIA_BUS_FMT_* definitions in include/uapi/linux/media-bus-format.h for
+ * a full list of available formats.
+ */
+int drm_display_info_set_bus_formats(struct drm_display_info *info,
+ const u32 *formats,
+ unsigned int num_formats)
+{
+ u32 *fmts = NULL;
+
+ if (!formats && num_formats)
+ return -EINVAL;
+
+ if (formats && num_formats) {
+ fmts = kmemdup(formats, sizeof(*formats) * num_formats,
+ GFP_KERNEL);
+ if (!fmts)
+ return -ENOMEM;
+ }
+
+ kfree(info->bus_formats);
+ info->bus_formats = fmts;
+ info->num_bus_formats = num_formats;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_display_info_set_bus_formats);
+
+/**
* drm_connector_get_cmdline_mode - reads the user's cmdline mode
* @connector: connector to quwery
*
@@ -837,6 +869,7 @@ int drm_connector_init(struct drm_device *dev,
const struct drm_connector_funcs *funcs,
int connector_type)
{
+ struct drm_mode_config *config = &dev->mode_config;
int ret;
struct ida *connector_ida =
&drm_connector_enum_list[connector_type].ida;
@@ -875,16 +908,20 @@ int drm_connector_init(struct drm_device *dev,
/* We should add connectors at the end to avoid upsetting the connector
* index too much. */
- list_add_tail(&connector->head, &dev->mode_config.connector_list);
- dev->mode_config.num_connector++;
+ list_add_tail(&connector->head, &config->connector_list);
+ config->num_connector++;
if (connector_type != DRM_MODE_CONNECTOR_VIRTUAL)
drm_object_attach_property(&connector->base,
- dev->mode_config.edid_property,
+ config->edid_property,
0);
drm_object_attach_property(&connector->base,
- dev->mode_config.dpms_property, 0);
+ config->dpms_property, 0);
+
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+ drm_object_attach_property(&connector->base, config->prop_crtc_id, 0);
+ }
connector->debugfs_entry = NULL;
@@ -924,6 +961,7 @@ void drm_connector_cleanup(struct drm_connector *connector)
ida_remove(&drm_connector_enum_list[connector->connector_type].ida,
connector->connector_type_id);
+ kfree(connector->display_info.bus_formats);
drm_mode_object_put(dev, &connector->base);
kfree(connector->name);
connector->name = NULL;
@@ -1028,61 +1066,6 @@ void drm_connector_unplug_all(struct drm_device *dev)
EXPORT_SYMBOL(drm_connector_unplug_all);
/**
- * drm_bridge_init - initialize a drm transcoder/bridge
- * @dev: drm device
- * @bridge: transcoder/bridge to set up
- * @funcs: bridge function table
- *
- * Initialises a preallocated bridge. Bridges should be
- * subclassed as part of driver connector objects.
- *
- * Returns:
- * Zero on success, error code on failure.
- */
-int drm_bridge_init(struct drm_device *dev, struct drm_bridge *bridge,
- const struct drm_bridge_funcs *funcs)
-{
- int ret;
-
- drm_modeset_lock_all(dev);
-
- ret = drm_mode_object_get(dev, &bridge->base, DRM_MODE_OBJECT_BRIDGE);
- if (ret)
- goto out;
-
- bridge->dev = dev;
- bridge->funcs = funcs;
-
- list_add_tail(&bridge->head, &dev->mode_config.bridge_list);
- dev->mode_config.num_bridge++;
-
- out:
- drm_modeset_unlock_all(dev);
- return ret;
-}
-EXPORT_SYMBOL(drm_bridge_init);
-
-/**
- * drm_bridge_cleanup - cleans up an initialised bridge
- * @bridge: bridge to cleanup
- *
- * Cleans up the bridge but doesn't free the object.
- */
-void drm_bridge_cleanup(struct drm_bridge *bridge)
-{
- struct drm_device *dev = bridge->dev;
-
- drm_modeset_lock_all(dev);
- drm_mode_object_put(dev, &bridge->base);
- list_del(&bridge->head);
- dev->mode_config.num_bridge--;
- drm_modeset_unlock_all(dev);
-
- memset(bridge, 0, sizeof(*bridge));
-}
-EXPORT_SYMBOL(drm_bridge_cleanup);
-
-/**
* drm_encoder_init - Init a preallocated encoder
* @dev: drm device
* @encoder: the encoder to init
@@ -1142,6 +1125,7 @@ EXPORT_SYMBOL(drm_encoder_init);
void drm_encoder_cleanup(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
+
drm_modeset_lock_all(dev);
drm_mode_object_put(dev, &encoder->base);
kfree(encoder->name);
@@ -1174,6 +1158,7 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
const uint32_t *formats, uint32_t format_count,
enum drm_plane_type type)
{
+ struct drm_mode_config *config = &dev->mode_config;
int ret;
ret = drm_mode_object_get(dev, &plane->base, DRM_MODE_OBJECT_PLANE);
@@ -1185,8 +1170,8 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
plane->base.properties = &plane->properties;
plane->dev = dev;
plane->funcs = funcs;
- plane->format_types = kmalloc(sizeof(uint32_t) * format_count,
- GFP_KERNEL);
+ plane->format_types = kmalloc_array(format_count, sizeof(uint32_t),
+ GFP_KERNEL);
if (!plane->format_types) {
DRM_DEBUG_KMS("out of memory when allocating plane\n");
drm_mode_object_put(dev, &plane->base);
@@ -1198,15 +1183,28 @@ int drm_universal_plane_init(struct drm_device *dev, struct drm_plane *plane,
plane->possible_crtcs = possible_crtcs;
plane->type = type;
- list_add_tail(&plane->head, &dev->mode_config.plane_list);
- dev->mode_config.num_total_plane++;
+ list_add_tail(&plane->head, &config->plane_list);
+ config->num_total_plane++;
if (plane->type == DRM_PLANE_TYPE_OVERLAY)
- dev->mode_config.num_overlay_plane++;
+ config->num_overlay_plane++;
drm_object_attach_property(&plane->base,
- dev->mode_config.plane_type_property,
+ config->plane_type_property,
plane->type);
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+ drm_object_attach_property(&plane->base, config->prop_fb_id, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_id, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_x, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_y, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_w, 0);
+ drm_object_attach_property(&plane->base, config->prop_crtc_h, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_x, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_y, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_w, 0);
+ drm_object_attach_property(&plane->base, config->prop_src_h, 0);
+ }
+
return 0;
}
EXPORT_SYMBOL(drm_universal_plane_init);
@@ -1328,50 +1326,115 @@ void drm_plane_force_disable(struct drm_plane *plane)
}
EXPORT_SYMBOL(drm_plane_force_disable);
-static int drm_mode_create_standard_connector_properties(struct drm_device *dev)
+static int drm_mode_create_standard_properties(struct drm_device *dev)
{
- struct drm_property *edid;
- struct drm_property *dpms;
- struct drm_property *dev_path;
+ struct drm_property *prop;
/*
* Standard properties (apply to all connectors)
*/
- edid = drm_property_create(dev, DRM_MODE_PROP_BLOB |
+ prop = drm_property_create(dev, DRM_MODE_PROP_BLOB |
DRM_MODE_PROP_IMMUTABLE,
"EDID", 0);
- dev->mode_config.edid_property = edid;
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.edid_property = prop;
- dpms = drm_property_create_enum(dev, 0,
+ prop = drm_property_create_enum(dev, 0,
"DPMS", drm_dpms_enum_list,
ARRAY_SIZE(drm_dpms_enum_list));
- dev->mode_config.dpms_property = dpms;
-
- dev_path = drm_property_create(dev,
- DRM_MODE_PROP_BLOB |
- DRM_MODE_PROP_IMMUTABLE,
- "PATH", 0);
- dev->mode_config.path_property = dev_path;
-
- dev->mode_config.tile_property = drm_property_create(dev,
- DRM_MODE_PROP_BLOB |
- DRM_MODE_PROP_IMMUTABLE,
- "TILE", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.dpms_property = prop;
- return 0;
-}
+ prop = drm_property_create(dev,
+ DRM_MODE_PROP_BLOB |
+ DRM_MODE_PROP_IMMUTABLE,
+ "PATH", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.path_property = prop;
-static int drm_mode_create_standard_plane_properties(struct drm_device *dev)
-{
- struct drm_property *type;
+ prop = drm_property_create(dev,
+ DRM_MODE_PROP_BLOB |
+ DRM_MODE_PROP_IMMUTABLE,
+ "TILE", 0);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.tile_property = prop;
- /*
- * Standard properties (apply to all planes)
- */
- type = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
+ prop = drm_property_create_enum(dev, DRM_MODE_PROP_IMMUTABLE,
"type", drm_plane_type_enum_list,
ARRAY_SIZE(drm_plane_type_enum_list));
- dev->mode_config.plane_type_property = type;
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.plane_type_property = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "SRC_X", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_x = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "SRC_Y", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_y = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "SRC_W", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_w = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "SRC_H", 0, UINT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_src_h = prop;
+
+ prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CRTC_X", INT_MIN, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_x = prop;
+
+ prop = drm_property_create_signed_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CRTC_Y", INT_MIN, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_y = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CRTC_W", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_w = prop;
+
+ prop = drm_property_create_range(dev, DRM_MODE_PROP_ATOMIC,
+ "CRTC_H", 0, INT_MAX);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_h = prop;
+
+ prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+ "FB_ID", DRM_MODE_OBJECT_FB);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_fb_id = prop;
+
+ prop = drm_property_create_object(dev, DRM_MODE_PROP_ATOMIC,
+ "CRTC_ID", DRM_MODE_OBJECT_CRTC);
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_crtc_id = prop;
+
+ prop = drm_property_create_bool(dev, DRM_MODE_PROP_ATOMIC,
+ "ACTIVE");
+ if (!prop)
+ return -ENOMEM;
+ dev->mode_config.prop_active = prop;
return 0;
}
@@ -1597,16 +1660,14 @@ static int drm_mode_group_init(struct drm_device *dev, struct drm_mode_group *gr
total_objects += dev->mode_config.num_crtc;
total_objects += dev->mode_config.num_connector;
total_objects += dev->mode_config.num_encoder;
- total_objects += dev->mode_config.num_bridge;
- group->id_list = kzalloc(total_objects * sizeof(uint32_t), GFP_KERNEL);
+ group->id_list = kcalloc(total_objects, sizeof(uint32_t), GFP_KERNEL);
if (!group->id_list)
return -ENOMEM;
group->num_crtcs = 0;
group->num_connectors = 0;
group->num_encoders = 0;
- group->num_bridges = 0;
return 0;
}
@@ -1626,10 +1687,10 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
struct drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector *connector;
- struct drm_bridge *bridge;
int ret;
- if ((ret = drm_mode_group_init(dev, group)))
+ ret = drm_mode_group_init(dev, group);
+ if (ret)
return ret;
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
@@ -1643,11 +1704,6 @@ int drm_mode_group_init_legacy_group(struct drm_device *dev,
group->id_list[group->num_crtcs + group->num_encoders +
group->num_connectors++] = connector->base.id;
- list_for_each_entry(bridge, &dev->mode_config.bridge_list, head)
- group->id_list[group->num_crtcs + group->num_encoders +
- group->num_connectors + group->num_bridges++] =
- bridge->base.id;
-
return 0;
}
EXPORT_SYMBOL(drm_mode_group_init_legacy_group);
@@ -1996,6 +2052,44 @@ static struct drm_encoder *drm_connector_get_encoder(struct drm_connector *conne
return connector->encoder;
}
+/* helper for getconnector and getproperties ioctls */
+static int get_properties(struct drm_mode_object *obj, bool atomic,
+ uint32_t __user *prop_ptr, uint64_t __user *prop_values,
+ uint32_t *arg_count_props)
+{
+ int props_count;
+ int i, ret, copied;
+
+ props_count = obj->properties->count;
+ if (!atomic)
+ props_count -= obj->properties->atomic_count;
+
+ if ((*arg_count_props >= props_count) && props_count) {
+ for (i = 0, copied = 0; copied < props_count; i++) {
+ struct drm_property *prop = obj->properties->properties[i];
+ uint64_t val;
+
+ if ((prop->flags & DRM_MODE_PROP_ATOMIC) && !atomic)
+ continue;
+
+ ret = drm_object_property_get_value(obj, prop, &val);
+ if (ret)
+ return ret;
+
+ if (put_user(prop->base.id, prop_ptr + copied))
+ return -EFAULT;
+
+ if (put_user(val, prop_values + copied))
+ return -EFAULT;
+
+ copied++;
+ }
+ }
+ *arg_count_props = props_count;
+
+ return 0;
+}
+
/**
* drm_mode_getconnector - get connector configuration
* @dev: drm device for the ioctl
@@ -2017,15 +2111,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
struct drm_encoder *encoder;
struct drm_display_mode *mode;
int mode_count = 0;
- int props_count = 0;
int encoders_count = 0;
int ret = 0;
int copied = 0;
int i;
struct drm_mode_modeinfo u_mode;
struct drm_mode_modeinfo __user *mode_ptr;
- uint32_t __user *prop_ptr;
- uint64_t __user *prop_values;
uint32_t __user *encoder_ptr;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
@@ -2043,13 +2134,9 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
goto out;
}
- props_count = connector->properties.count;
-
- for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++) {
- if (connector->encoder_ids[i] != 0) {
+ for (i = 0; i < DRM_CONNECTOR_MAX_ENCODER; i++)
+ if (connector->encoder_ids[i] != 0)
encoders_count++;
- }
- }
if (out_resp->count_modes == 0) {
connector->funcs->fill_modes(connector,
@@ -2069,14 +2156,13 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out_resp->mm_height = connector->display_info.height_mm;
out_resp->subpixel = connector->display_info.subpixel_order;
out_resp->connection = connector->status;
- drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
+ drm_modeset_lock(&dev->mode_config.connection_mutex, NULL);
encoder = drm_connector_get_encoder(connector);
if (encoder)
out_resp->encoder_id = encoder->base.id;
else
out_resp->encoder_id = 0;
- drm_modeset_unlock(&dev->mode_config.connection_mutex);
/*
* This ioctl is called twice, once to determine how much space is
@@ -2100,26 +2186,12 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
}
out_resp->count_modes = mode_count;
- if ((out_resp->count_props >= props_count) && props_count) {
- copied = 0;
- prop_ptr = (uint32_t __user *)(unsigned long)(out_resp->props_ptr);
- prop_values = (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr);
- for (i = 0; i < connector->properties.count; i++) {
- if (put_user(connector->properties.ids[i],
- prop_ptr + copied)) {
- ret = -EFAULT;
- goto out;
- }
-
- if (put_user(connector->properties.values[i],
- prop_values + copied)) {
- ret = -EFAULT;
- goto out;
- }
- copied++;
- }
- }
- out_resp->count_props = props_count;
+ ret = get_properties(&connector->base, file_priv->atomic,
+ (uint32_t __user *)(unsigned long)(out_resp->props_ptr),
+ (uint64_t __user *)(unsigned long)(out_resp->prop_values_ptr),
+ &out_resp->count_props);
+ if (ret)
+ goto out;
if ((out_resp->count_encoders >= encoders_count) && encoders_count) {
copied = 0;
@@ -2138,6 +2210,7 @@ int drm_mode_getconnector(struct drm_device *dev, void *data,
out_resp->count_encoders = encoders_count;
out:
+ drm_modeset_unlock(&dev->mode_config.connection_mutex);
mutex_unlock(&dev->mode_config.mutex);
return ret;
@@ -2529,7 +2602,7 @@ int drm_mode_setplane(struct drm_device *dev, void *data,
*
* This is a little helper to wrap internal calls to the ->set_config driver
* interface. The only thing it adds is correct refcounting dance.
- *
+ *
* Returns:
* Zero on success, negative errno on failure.
*/
@@ -2569,6 +2642,27 @@ int drm_mode_set_config_internal(struct drm_mode_set *set)
EXPORT_SYMBOL(drm_mode_set_config_internal);
/**
+ * drm_crtc_get_hv_timing - Fetches hdisplay/vdisplay for given mode
+ * @mode: mode to query
+ * @hdisplay: hdisplay value to fill in
+ * @vdisplay: vdisplay value to fill in
+ *
+ * The vdisplay value will be doubled if the specified mode is a stereo mode of
+ * the appropriate layout.
+ */
+void drm_crtc_get_hv_timing(const struct drm_display_mode *mode,
+ int *hdisplay, int *vdisplay)
+{
+ struct drm_display_mode adjusted;
+
+ drm_mode_copy(&adjusted, mode);
+ drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE_ONLY);
+ *hdisplay = adjusted.crtc_hdisplay;
+ *vdisplay = adjusted.crtc_vdisplay;
+}
+EXPORT_SYMBOL(drm_crtc_get_hv_timing);
+
+/**
* drm_crtc_check_viewport - Checks that a framebuffer is big enough for the
* CRTC viewport
* @crtc: CRTC that framebuffer will be displayed on
@@ -2585,16 +2679,7 @@ int drm_crtc_check_viewport(const struct drm_crtc *crtc,
{
int hdisplay, vdisplay;
- hdisplay = mode->hdisplay;
- vdisplay = mode->vdisplay;
-
- if (drm_mode_is_stereo(mode)) {
- struct drm_display_mode adjusted = *mode;
-
- drm_mode_set_crtcinfo(&adjusted, CRTC_STEREO_DOUBLE);
- hdisplay = adjusted.crtc_hdisplay;
- vdisplay = adjusted.crtc_vdisplay;
- }
+ drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
if (crtc->invert_dimensions)
swap(hdisplay, vdisplay);
@@ -2690,6 +2775,12 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
+ mode->status = drm_mode_validate_basic(mode);
+ if (mode->status != MODE_OK) {
+ ret = -EINVAL;
+ goto out;
+ }
+
drm_mode_set_crtcinfo(mode, CRTC_INTERLACE_HALVE_V);
ret = drm_crtc_check_viewport(crtc, crtc_req->x, crtc_req->y,
@@ -2721,9 +2812,9 @@ int drm_mode_setcrtc(struct drm_device *dev, void *data,
goto out;
}
- connector_set = kmalloc(crtc_req->count_connectors *
- sizeof(struct drm_connector *),
- GFP_KERNEL);
+ connector_set = kmalloc_array(crtc_req->count_connectors,
+ sizeof(struct drm_connector *),
+ GFP_KERNEL);
if (!connector_set) {
ret = -ENOMEM;
goto out;
@@ -2968,6 +3059,7 @@ int drm_mode_cursor2_ioctl(struct drm_device *dev,
void *data, struct drm_file *file_priv)
{
struct drm_mode_cursor2 *req = data;
+
return drm_mode_cursor_common(dev, req, file_priv);
}
@@ -3415,7 +3507,7 @@ int drm_mode_dirtyfb_ioctl(struct drm_device *dev,
ret = -EINVAL;
goto out_err1;
}
- clips = kzalloc(num_clips * sizeof(*clips), GFP_KERNEL);
+ clips = kcalloc(num_clips, sizeof(*clips), GFP_KERNEL);
if (!clips) {
ret = -ENOMEM;
goto out_err1;
@@ -3516,7 +3608,8 @@ struct drm_property *drm_property_create(struct drm_device *dev, int flags,
property->dev = dev;
if (num_values) {
- property->values = kzalloc(sizeof(uint64_t)*num_values, GFP_KERNEL);
+ property->values = kcalloc(num_values, sizeof(uint64_t),
+ GFP_KERNEL);
if (!property->values)
goto fail;
}
@@ -3665,7 +3758,7 @@ static struct drm_property *property_create_range(struct drm_device *dev,
}
/**
- * drm_property_create_range - create a new ranged property type
+ * drm_property_create_range - create a new unsigned ranged property type
* @dev: drm device
* @flags: flags specifying the property type
* @name: name of the property
@@ -3676,8 +3769,8 @@ static struct drm_property *property_create_range(struct drm_device *dev,
* object with drm_object_attach_property. The returned property object must be
* freed with drm_property_destroy.
*
- * Userspace is allowed to set any integer value in the (min, max) range
- * inclusive.
+ * Userspace is allowed to set any unsigned integer value in the (min, max)
+ * range inclusive.
*
* Returns:
* A pointer to the newly created property on success, NULL on failure.
@@ -3691,6 +3784,24 @@ struct drm_property *drm_property_create_range(struct drm_device *dev, int flags
}
EXPORT_SYMBOL(drm_property_create_range);
+/**
+ * drm_property_create_signed_range - create a new signed ranged property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @min: minimum value of the property
+ * @max: maximum value of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is allowed to set any signed integer value in the (min, max)
+ * range inclusive.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
int flags, const char *name,
int64_t min, int64_t max)
@@ -3700,6 +3811,23 @@ struct drm_property *drm_property_create_signed_range(struct drm_device *dev,
}
EXPORT_SYMBOL(drm_property_create_signed_range);
+/**
+ * drm_property_create_object - create a new object property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ * @type: object type from DRM_MODE_OBJECT_* defines
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * Userspace is only allowed to set this to any property value of the given
+ * @type. Only useful for atomic properties, which is enforced.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
struct drm_property *drm_property_create_object(struct drm_device *dev,
int flags, const char *name, uint32_t type)
{
@@ -3707,6 +3835,9 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
flags |= DRM_MODE_PROP_OBJECT;
+ if (WARN_ON(!(flags & DRM_MODE_PROP_ATOMIC)))
+ return NULL;
+
property = drm_property_create(dev, flags, name, 1);
if (!property)
return NULL;
@@ -3718,6 +3849,28 @@ struct drm_property *drm_property_create_object(struct drm_device *dev,
EXPORT_SYMBOL(drm_property_create_object);
/**
+ * drm_property_create_bool - create a new boolean property type
+ * @dev: drm device
+ * @flags: flags specifying the property type
+ * @name: name of the property
+ *
+ * This creates a new generic drm property which can then be attached to a drm
+ * object with drm_object_attach_property. The returned property object must be
+ * freed with drm_property_destroy.
+ *
+ * This is implemented as a ranged property with only {0, 1} as valid values.
+ *
+ * Returns:
+ * A pointer to the newly created property on success, NULL on failure.
+ */
+struct drm_property *drm_property_create_bool(struct drm_device *dev, int flags,
+ const char *name)
+{
+ return drm_property_create_range(dev, flags, name, 0, 1);
+}
+EXPORT_SYMBOL(drm_property_create_bool);
+
+/**
* drm_property_add_enum - add a possible value to an enumeration property
* @property: enumeration property to change
* @index: index of the new enumeration
@@ -3822,9 +3975,11 @@ void drm_object_attach_property(struct drm_mode_object *obj,
return;
}
- obj->properties->ids[count] = property->base.id;
+ obj->properties->properties[count] = property;
obj->properties->values[count] = init_val;
obj->properties->count++;
+ if (property->flags & DRM_MODE_PROP_ATOMIC)
+ obj->properties->atomic_count++;
}
EXPORT_SYMBOL(drm_object_attach_property);
@@ -3847,7 +4002,7 @@ int drm_object_property_set_value(struct drm_mode_object *obj,
int i;
for (i = 0; i < obj->properties->count; i++) {
- if (obj->properties->ids[i] == property->base.id) {
+ if (obj->properties->properties[i] == property) {
obj->properties->values[i] = val;
return 0;
}
@@ -3876,8 +4031,16 @@ int drm_object_property_get_value(struct drm_mode_object *obj,
{
int i;
+ /* read-only properties bypass atomic mechanism and still store
+ * their value in obj->properties->values[].. mostly to avoid
+ * having to deal w/ EDID and similar props in atomic paths:
+ */
+ if (drm_core_check_feature(property->dev, DRIVER_ATOMIC) &&
+ !(property->flags & DRM_MODE_PROP_IMMUTABLE))
+ return drm_atomic_get_property(obj, property, val);
+
for (i = 0; i < obj->properties->count; i++) {
- if (obj->properties->ids[i] == property->base.id) {
+ if (obj->properties->properties[i] == property) {
*val = obj->properties->values[i];
return 0;
}
@@ -4057,7 +4220,7 @@ int drm_mode_getblob_ioctl(struct drm_device *dev,
if (out_resp->length == blob->length) {
blob_ptr = (void __user *)(unsigned long)out_resp->data;
- if (copy_to_user(blob_ptr, blob->data, blob->length)){
+ if (copy_to_user(blob_ptr, blob->data, blob->length)) {
ret = -EFAULT;
goto done;
}
@@ -4193,25 +4356,38 @@ int drm_mode_connector_update_edid_property(struct drm_connector *connector,
}
EXPORT_SYMBOL(drm_mode_connector_update_edid_property);
-static bool drm_property_change_is_valid(struct drm_property *property,
- uint64_t value)
+/* Some properties could refer to dynamic refcnt'd objects, or things that
+ * need special locking to handle lifetime issues (ie. to ensure the prop
+ * value doesn't become invalid part way through the property update due to
+ * race). The value returned by reference via 'obj' should be passed back
+ * to drm_property_change_valid_put() after the property is set (and the
+ * object to which the property is attached has a chance to take it's own
+ * reference).
+ */
+bool drm_property_change_valid_get(struct drm_property *property,
+ uint64_t value, struct drm_mode_object **ref)
{
+ int i;
+
if (property->flags & DRM_MODE_PROP_IMMUTABLE)
return false;
+ *ref = NULL;
+
if (drm_property_type_is(property, DRM_MODE_PROP_RANGE)) {
if (value < property->values[0] || value > property->values[1])
return false;
return true;
} else if (drm_property_type_is(property, DRM_MODE_PROP_SIGNED_RANGE)) {
int64_t svalue = U642I64(value);
+
if (svalue < U642I64(property->values[0]) ||
svalue > U642I64(property->values[1]))
return false;
return true;
} else if (drm_property_type_is(property, DRM_MODE_PROP_BITMASK)) {
- int i;
uint64_t valid_mask = 0;
+
for (i = 0; i < property->num_values; i++)
valid_mask |= (1ULL << property->values[i]);
return !(value & ~valid_mask);
@@ -4219,25 +4395,40 @@ static bool drm_property_change_is_valid(struct drm_property *property,
/* Only the driver knows */
return true;
} else if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
- struct drm_mode_object *obj;
/* a zero value for an object property translates to null: */
if (value == 0)
return true;
- /*
- * NOTE: use _object_find() directly to bypass restriction on
- * looking up refcnt'd objects (ie. fb's). For a refcnt'd
- * object this could race against object finalization, so it
- * simply tells us that the object *was* valid. Which is good
- * enough.
- */
- obj = _object_find(property->dev, value, property->values[0]);
- return obj != NULL;
- } else {
- int i;
- for (i = 0; i < property->num_values; i++)
- if (property->values[i] == value)
+
+ /* handle refcnt'd objects specially: */
+ if (property->values[0] == DRM_MODE_OBJECT_FB) {
+ struct drm_framebuffer *fb;
+ fb = drm_framebuffer_lookup(property->dev, value);
+ if (fb) {
+ *ref = &fb->base;
return true;
- return false;
+ } else {
+ return false;
+ }
+ } else {
+ return _object_find(property->dev, value, property->values[0]) != NULL;
+ }
+ }
+
+ for (i = 0; i < property->num_values; i++)
+ if (property->values[i] == value)
+ return true;
+ return false;
+}
+
+void drm_property_change_valid_put(struct drm_property *property,
+ struct drm_mode_object *ref)
+{
+ if (!ref)
+ return;
+
+ if (drm_property_type_is(property, DRM_MODE_PROP_OBJECT)) {
+ if (property->values[0] == DRM_MODE_OBJECT_FB)
+ drm_framebuffer_unreference(obj_to_fb(ref));
}
}
@@ -4356,11 +4547,6 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
struct drm_mode_obj_get_properties *arg = data;
struct drm_mode_object *obj;
int ret = 0;
- int i;
- int copied = 0;
- int props_count = 0;
- uint32_t __user *props_ptr;
- uint64_t __user *prop_values_ptr;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
@@ -4377,30 +4563,11 @@ int drm_mode_obj_get_properties_ioctl(struct drm_device *dev, void *data,
goto out;
}
- props_count = obj->properties->count;
+ ret = get_properties(obj, file_priv->atomic,
+ (uint32_t __user *)(unsigned long)(arg->props_ptr),
+ (uint64_t __user *)(unsigned long)(arg->prop_values_ptr),
+ &arg->count_props);
- /* This ioctl is called twice, once to determine how much space is
- * needed, and the 2nd time to fill it. */
- if ((arg->count_props >= props_count) && props_count) {
- copied = 0;
- props_ptr = (uint32_t __user *)(unsigned long)(arg->props_ptr);
- prop_values_ptr = (uint64_t __user *)(unsigned long)
- (arg->prop_values_ptr);
- for (i = 0; i < props_count; i++) {
- if (put_user(obj->properties->ids[i],
- props_ptr + copied)) {
- ret = -EFAULT;
- goto out;
- }
- if (put_user(obj->properties->values[i],
- prop_values_ptr + copied)) {
- ret = -EFAULT;
- goto out;
- }
- copied++;
- }
- }
- arg->count_props = props_count;
out:
drm_modeset_unlock_all(dev);
return ret;
@@ -4429,8 +4596,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
struct drm_mode_object *arg_obj;
struct drm_mode_object *prop_obj;
struct drm_property *property;
- int ret = -EINVAL;
- int i;
+ int i, ret = -EINVAL;
+ struct drm_mode_object *ref;
if (!drm_core_check_feature(dev, DRIVER_MODESET))
return -EINVAL;
@@ -4446,7 +4613,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
goto out;
for (i = 0; i < arg_obj->properties->count; i++)
- if (arg_obj->properties->ids[i] == arg->prop_id)
+ if (arg_obj->properties->properties[i]->base.id == arg->prop_id)
break;
if (i == arg_obj->properties->count)
@@ -4460,7 +4627,7 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
}
property = obj_to_property(prop_obj);
- if (!drm_property_change_is_valid(property, arg->value))
+ if (!drm_property_change_valid_get(property, arg->value, &ref))
goto out;
switch (arg_obj->type) {
@@ -4477,6 +4644,8 @@ int drm_mode_obj_set_property_ioctl(struct drm_device *dev, void *data,
break;
}
+ drm_property_change_valid_put(property, ref);
+
out:
drm_modeset_unlock_all(dev);
return ret;
@@ -4526,7 +4695,8 @@ int drm_mode_crtc_set_gamma_size(struct drm_crtc *crtc,
{
crtc->gamma_size = gamma_size;
- crtc->gamma_store = kzalloc(gamma_size * sizeof(uint16_t) * 3, GFP_KERNEL);
+ crtc->gamma_store = kcalloc(gamma_size, sizeof(uint16_t) * 3,
+ GFP_KERNEL);
if (!crtc->gamma_store) {
crtc->gamma_size = 0;
return -ENOMEM;
@@ -4741,23 +4911,23 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
ret = -ENOMEM;
spin_lock_irqsave(&dev->event_lock, flags);
- if (file_priv->event_space < sizeof e->event) {
+ if (file_priv->event_space < sizeof(e->event)) {
spin_unlock_irqrestore(&dev->event_lock, flags);
goto out;
}
- file_priv->event_space -= sizeof e->event;
+ file_priv->event_space -= sizeof(e->event);
spin_unlock_irqrestore(&dev->event_lock, flags);
- e = kzalloc(sizeof *e, GFP_KERNEL);
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL) {
spin_lock_irqsave(&dev->event_lock, flags);
- file_priv->event_space += sizeof e->event;
+ file_priv->event_space += sizeof(e->event);
spin_unlock_irqrestore(&dev->event_lock, flags);
goto out;
}
e->event.base.type = DRM_EVENT_FLIP_COMPLETE;
- e->event.base.length = sizeof e->event;
+ e->event.base.length = sizeof(e->event);
e->event.user_data = page_flip->user_data;
e->base.event = &e->event.base;
e->base.file_priv = file_priv;
@@ -4770,7 +4940,7 @@ int drm_mode_page_flip_ioctl(struct drm_device *dev,
if (ret) {
if (page_flip->flags & DRM_MODE_PAGE_FLIP_EVENT) {
spin_lock_irqsave(&dev->event_lock, flags);
- file_priv->event_space += sizeof e->event;
+ file_priv->event_space += sizeof(e->event);
spin_unlock_irqrestore(&dev->event_lock, flags);
kfree(e);
}
@@ -5211,7 +5381,6 @@ void drm_mode_config_init(struct drm_device *dev)
INIT_LIST_HEAD(&dev->mode_config.fb_list);
INIT_LIST_HEAD(&dev->mode_config.crtc_list);
INIT_LIST_HEAD(&dev->mode_config.connector_list);
- INIT_LIST_HEAD(&dev->mode_config.bridge_list);
INIT_LIST_HEAD(&dev->mode_config.encoder_list);
INIT_LIST_HEAD(&dev->mode_config.property_list);
INIT_LIST_HEAD(&dev->mode_config.property_blob_list);
@@ -5220,8 +5389,7 @@ void drm_mode_config_init(struct drm_device *dev)
idr_init(&dev->mode_config.tile_idr);
drm_modeset_lock_all(dev);
- drm_mode_create_standard_connector_properties(dev);
- drm_mode_create_standard_plane_properties(dev);
+ drm_mode_create_standard_properties(dev);
drm_modeset_unlock_all(dev);
/* Just to be sure */
@@ -5252,7 +5420,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
struct drm_connector *connector, *ot;
struct drm_crtc *crtc, *ct;
struct drm_encoder *encoder, *enct;
- struct drm_bridge *bridge, *brt;
struct drm_framebuffer *fb, *fbt;
struct drm_property *property, *pt;
struct drm_property_blob *blob, *bt;
@@ -5263,11 +5430,6 @@ void drm_mode_config_cleanup(struct drm_device *dev)
encoder->funcs->destroy(encoder);
}
- list_for_each_entry_safe(bridge, brt,
- &dev->mode_config.bridge_list, head) {
- bridge->funcs->destroy(bridge);
- }
-
list_for_each_entry_safe(connector, ot,
&dev->mode_config.connector_list, head) {
connector->funcs->destroy(connector);
diff --git a/drivers/gpu/drm/drm_crtc_helper.c b/drivers/gpu/drm/drm_crtc_helper.c
index d552708409de..b1979e7bdc88 100644
--- a/drivers/gpu/drm/drm_crtc_helper.c
+++ b/drivers/gpu/drm/drm_crtc_helper.c
@@ -946,6 +946,7 @@ int drm_helper_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mod
crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
if (!crtc_state)
return -ENOMEM;
+ crtc_state->crtc = crtc;
crtc_state->enable = true;
crtc_state->planes_changed = true;
@@ -1005,6 +1006,7 @@ int drm_helper_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state)
return -ENOMEM;
+ plane_state->plane = plane;
plane_state->crtc = crtc;
drm_atomic_set_fb_for_plane(plane_state, crtc->primary->fb);
diff --git a/drivers/gpu/drm/drm_crtc_internal.h b/drivers/gpu/drm/drm_crtc_internal.h
index a2945ee6d675..247dc8b62564 100644
--- a/drivers/gpu/drm/drm_crtc_internal.h
+++ b/drivers/gpu/drm/drm_crtc_internal.h
@@ -36,3 +36,9 @@ int drm_mode_object_get(struct drm_device *dev,
void drm_mode_object_put(struct drm_device *dev,
struct drm_mode_object *object);
+/* drm_atomic.c */
+int drm_atomic_get_property(struct drm_mode_object *obj,
+ struct drm_property *property, uint64_t *val);
+int drm_mode_atomic_ioctl(struct drm_device *dev,
+ void *data, struct drm_file *file_priv);
+
diff --git a/drivers/gpu/drm/drm_dp_helper.c b/drivers/gpu/drm/drm_dp_helper.c
index 79968e39c8d0..f1283878ff6d 100644
--- a/drivers/gpu/drm/drm_dp_helper.c
+++ b/drivers/gpu/drm/drm_dp_helper.c
@@ -354,6 +354,37 @@ int drm_dp_link_power_up(struct drm_dp_aux *aux, struct drm_dp_link *link)
EXPORT_SYMBOL(drm_dp_link_power_up);
/**
+ * drm_dp_link_power_down() - power down a DisplayPort link
+ * @aux: DisplayPort AUX channel
+ * @link: pointer to a structure containing the link configuration
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int drm_dp_link_power_down(struct drm_dp_aux *aux, struct drm_dp_link *link)
+{
+ u8 value;
+ int err;
+
+ /* DP_SET_POWER register is only available on DPCD v1.1 and later */
+ if (link->revision < 0x11)
+ return 0;
+
+ err = drm_dp_dpcd_readb(aux, DP_SET_POWER, &value);
+ if (err < 0)
+ return err;
+
+ value &= ~DP_SET_POWER_MASK;
+ value |= DP_SET_POWER_D3;
+
+ err = drm_dp_dpcd_writeb(aux, DP_SET_POWER, value);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+EXPORT_SYMBOL(drm_dp_link_power_down);
+
+/**
* drm_dp_link_configure() - configure a DisplayPort link
* @aux: DisplayPort AUX channel
* @link: pointer to a structure containing the link configuration
diff --git a/drivers/gpu/drm/drm_drv.c b/drivers/gpu/drm/drm_drv.c
index 4f41377b0b80..d51213464672 100644
--- a/drivers/gpu/drm/drm_drv.c
+++ b/drivers/gpu/drm/drm_drv.c
@@ -40,15 +40,19 @@
unsigned int drm_debug = 0; /* 1 to enable debug output */
EXPORT_SYMBOL(drm_debug);
+bool drm_atomic = 0;
+
MODULE_AUTHOR(CORE_AUTHOR);
MODULE_DESCRIPTION(CORE_DESC);
MODULE_LICENSE("GPL and additional rights");
MODULE_PARM_DESC(debug, "Enable debug output");
+MODULE_PARM_DESC(atomic, "Enable experimental atomic KMS API");
MODULE_PARM_DESC(vblankoffdelay, "Delay until vblank irq auto-disable [msecs] (0: never disable, <0: disable immediately)");
MODULE_PARM_DESC(timestamp_precision_usec, "Max. error on timestamps [usecs]");
MODULE_PARM_DESC(timestamp_monotonic, "Use monotonic timestamps");
module_param_named(debug, drm_debug, int, 0600);
+module_param_named_unsafe(atomic, drm_atomic, bool, 0600);
static DEFINE_SPINLOCK(drm_minor_lock);
static struct idr drm_minors_idr;
diff --git a/drivers/gpu/drm/drm_fb_helper.c b/drivers/gpu/drm/drm_fb_helper.c
index cf775a4449c1..1e6a0c760c5d 100644
--- a/drivers/gpu/drm/drm_fb_helper.c
+++ b/drivers/gpu/drm/drm_fb_helper.c
@@ -145,6 +145,31 @@ int drm_fb_helper_add_one_connector(struct drm_fb_helper *fb_helper, struct drm_
}
EXPORT_SYMBOL(drm_fb_helper_add_one_connector);
+static void remove_from_modeset(struct drm_mode_set *set,
+ struct drm_connector *connector)
+{
+ int i, j;
+
+ for (i = 0; i < set->num_connectors; i++) {
+ if (set->connectors[i] == connector)
+ break;
+ }
+
+ if (i == set->num_connectors)
+ return;
+
+ for (j = i + 1; j < set->num_connectors; j++) {
+ set->connectors[j - 1] = set->connectors[j];
+ }
+ set->num_connectors--;
+
+ /* because i915 is pissy about this..
+ * TODO maybe need to makes sure we set it back to !=NULL somewhere?
+ */
+ if (set->num_connectors == 0)
+ set->fb = NULL;
+}
+
int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
struct drm_connector *connector)
{
@@ -167,6 +192,11 @@ int drm_fb_helper_remove_one_connector(struct drm_fb_helper *fb_helper,
}
fb_helper->connector_count--;
kfree(fb_helper_connector);
+
+ /* also cleanup dangling references to the connector: */
+ for (i = 0; i < fb_helper->crtc_count; i++)
+ remove_from_modeset(&fb_helper->crtc_info[i].mode_set, connector);
+
return 0;
}
EXPORT_SYMBOL(drm_fb_helper_remove_one_connector);
@@ -1692,7 +1722,7 @@ out:
* RETURNS:
* Zero if everything went ok, nonzero otherwise.
*/
-bool drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
+int drm_fb_helper_initial_config(struct drm_fb_helper *fb_helper, int bpp_sel)
{
struct drm_device *dev = fb_helper->dev;
int count = 0;
diff --git a/drivers/gpu/drm/drm_fops.c b/drivers/gpu/drm/drm_fops.c
index 0b9514b6cd64..076dd606b580 100644
--- a/drivers/gpu/drm/drm_fops.c
+++ b/drivers/gpu/drm/drm_fops.c
@@ -478,64 +478,59 @@ int drm_release(struct inode *inode, struct file *filp)
}
EXPORT_SYMBOL(drm_release);
-static bool
-drm_dequeue_event(struct drm_file *file_priv,
- size_t total, size_t max, struct drm_pending_event **out)
+ssize_t drm_read(struct file *filp, char __user *buffer,
+ size_t count, loff_t *offset)
{
+ struct drm_file *file_priv = filp->private_data;
struct drm_device *dev = file_priv->minor->dev;
- struct drm_pending_event *e;
- unsigned long flags;
- bool ret = false;
-
- spin_lock_irqsave(&dev->event_lock, flags);
+ ssize_t ret = 0;
- *out = NULL;
- if (list_empty(&file_priv->event_list))
- goto out;
- e = list_first_entry(&file_priv->event_list,
- struct drm_pending_event, link);
- if (e->event->length + total > max)
- goto out;
+ if (!access_ok(VERIFY_WRITE, buffer, count))
+ return -EFAULT;
- file_priv->event_space += e->event->length;
- list_del(&e->link);
- *out = e;
- ret = true;
+ spin_lock_irq(&dev->event_lock);
+ for (;;) {
+ if (list_empty(&file_priv->event_list)) {
+ if (ret)
+ break;
-out:
- spin_unlock_irqrestore(&dev->event_lock, flags);
- return ret;
-}
-
-ssize_t drm_read(struct file *filp, char __user *buffer,
- size_t count, loff_t *offset)
-{
- struct drm_file *file_priv = filp->private_data;
- struct drm_pending_event *e;
- size_t total;
- ssize_t ret;
+ if (filp->f_flags & O_NONBLOCK) {
+ ret = -EAGAIN;
+ break;
+ }
- if ((filp->f_flags & O_NONBLOCK) == 0) {
- ret = wait_event_interruptible(file_priv->event_wait,
- !list_empty(&file_priv->event_list));
- if (ret < 0)
- return ret;
- }
+ spin_unlock_irq(&dev->event_lock);
+ ret = wait_event_interruptible(file_priv->event_wait,
+ !list_empty(&file_priv->event_list));
+ spin_lock_irq(&dev->event_lock);
+ if (ret < 0)
+ break;
+
+ ret = 0;
+ } else {
+ struct drm_pending_event *e;
+
+ e = list_first_entry(&file_priv->event_list,
+ struct drm_pending_event, link);
+ if (e->event->length + ret > count)
+ break;
+
+ if (__copy_to_user_inatomic(buffer + ret,
+ e->event, e->event->length)) {
+ if (ret == 0)
+ ret = -EFAULT;
+ break;
+ }
- total = 0;
- while (drm_dequeue_event(file_priv, total, count, &e)) {
- if (copy_to_user(buffer + total,
- e->event, e->event->length)) {
- total = -EFAULT;
+ file_priv->event_space += e->event->length;
+ ret += e->event->length;
+ list_del(&e->link);
e->destroy(e);
- break;
}
-
- total += e->event->length;
- e->destroy(e);
}
+ spin_unlock_irq(&dev->event_lock);
- return total ?: -EAGAIN;
+ return ret;
}
EXPORT_SYMBOL(drm_read);
diff --git a/drivers/gpu/drm/drm_info.c b/drivers/gpu/drm/drm_info.c
index 51efebd434f3..f1b32f91d941 100644
--- a/drivers/gpu/drm/drm_info.c
+++ b/drivers/gpu/drm/drm_info.c
@@ -153,30 +153,6 @@ int drm_bufs_info(struct seq_file *m, void *data)
}
/**
- * Called when "/proc/dri/.../vblank" is read.
- */
-int drm_vblank_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = (struct drm_info_node *) m->private;
- struct drm_device *dev = node->minor->dev;
- int crtc;
-
- mutex_lock(&dev->struct_mutex);
- for (crtc = 0; crtc < dev->num_crtcs; crtc++) {
- seq_printf(m, "CRTC %d enable: %d\n",
- crtc, atomic_read(&dev->vblank[crtc].refcount));
- seq_printf(m, "CRTC %d counter: %d\n",
- crtc, drm_vblank_count(dev, crtc));
- seq_printf(m, "CRTC %d last wait: %d\n",
- crtc, dev->vblank[crtc].last_wait);
- seq_printf(m, "CRTC %d in modeset: %d\n",
- crtc, dev->vblank[crtc].inmodeset);
- }
- mutex_unlock(&dev->struct_mutex);
- return 0;
-}
-
-/**
* Called when "/proc/dri/.../clients" is read.
*
*/
diff --git a/drivers/gpu/drm/drm_internal.h b/drivers/gpu/drm/drm_internal.h
index 7cc0a3516871..12a61d706827 100644
--- a/drivers/gpu/drm/drm_internal.h
+++ b/drivers/gpu/drm/drm_internal.h
@@ -55,7 +55,6 @@ void drm_prime_remove_buf_handle_locked(struct drm_prime_file_private *prime_fpr
int drm_name_info(struct seq_file *m, void *data);
int drm_vm_info(struct seq_file *m, void *data);
int drm_bufs_info(struct seq_file *m, void *data);
-int drm_vblank_info(struct seq_file *m, void *data);
int drm_clients_info(struct seq_file *m, void* data);
int drm_gem_name_info(struct seq_file *m, void *data);
diff --git a/drivers/gpu/drm/drm_ioctl.c b/drivers/gpu/drm/drm_ioctl.c
index 00587a1e3c83..3785d66721f2 100644
--- a/drivers/gpu/drm/drm_ioctl.c
+++ b/drivers/gpu/drm/drm_ioctl.c
@@ -32,6 +32,7 @@
#include <drm/drm_core.h>
#include "drm_legacy.h"
#include "drm_internal.h"
+#include "drm_crtc_internal.h"
#include <linux/pci.h>
#include <linux/export.h>
@@ -345,6 +346,17 @@ drm_setclientcap(struct drm_device *dev, void *data, struct drm_file *file_priv)
return -EINVAL;
file_priv->universal_planes = req->value;
break;
+ case DRM_CLIENT_CAP_ATOMIC:
+ /* for now, hide behind experimental drm.atomic moduleparam */
+ if (!drm_atomic)
+ return -EINVAL;
+ if (!drm_core_check_feature(dev, DRIVER_ATOMIC))
+ return -EINVAL;
+ if (req->value > 1)
+ return -EINVAL;
+ file_priv->atomic = req->value;
+ file_priv->universal_planes = req->value;
+ break;
default:
return -EINVAL;
}
@@ -620,6 +632,7 @@ static const struct drm_ioctl_desc drm_ioctls[] = {
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_GETPROPERTIES, drm_mode_obj_get_properties_ioctl, DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_OBJ_SETPROPERTY, drm_mode_obj_set_property_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
DRM_IOCTL_DEF(DRM_IOCTL_MODE_CURSOR2, drm_mode_cursor2_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
+ DRM_IOCTL_DEF(DRM_IOCTL_MODE_ATOMIC, drm_mode_atomic_ioctl, DRM_MASTER|DRM_CONTROL_ALLOW|DRM_UNLOCKED),
};
#define DRM_CORE_IOCTL_COUNT ARRAY_SIZE( drm_ioctls )
diff --git a/drivers/gpu/drm/drm_irq.c b/drivers/gpu/drm/drm_irq.c
index 4d79dad9d44f..10574a0c3a55 100644
--- a/drivers/gpu/drm/drm_irq.c
+++ b/drivers/gpu/drm/drm_irq.c
@@ -185,8 +185,15 @@ static void vblank_disable_and_save(struct drm_device *dev, int crtc)
return;
}
- dev->driver->disable_vblank(dev, crtc);
- vblank->enabled = false;
+ /*
+ * Only disable vblank interrupts if they're enabled. This avoids
+ * calling the ->disable_vblank() operation in atomic context with the
+ * hardware potentially runtime suspended.
+ */
+ if (vblank->enabled) {
+ dev->driver->disable_vblank(dev, crtc);
+ vblank->enabled = false;
+ }
/* No further vblank irq's will be processed after
* this point. Get current hardware vblank count and
@@ -778,7 +785,7 @@ static struct timeval get_drm_timestamp(void)
/**
* drm_get_last_vbltimestamp - retrieve raw timestamp for the most recent
- * vblank interval
+ * vblank interval
* @dev: DRM device
* @crtc: which CRTC's vblank timestamp to retrieve
* @tvblank: Pointer to target struct timeval which should receive the timestamp
@@ -933,6 +940,7 @@ void drm_send_vblank_event(struct drm_device *dev, int crtc,
{
struct timeval now;
unsigned int seq;
+
if (crtc >= 0) {
seq = drm_vblank_count_and_time(dev, crtc, &now);
} else {
@@ -1422,7 +1430,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
unsigned int seq;
int ret;
- e = kzalloc(sizeof *e, GFP_KERNEL);
+ e = kzalloc(sizeof(*e), GFP_KERNEL);
if (e == NULL) {
ret = -ENOMEM;
goto err_put;
@@ -1431,7 +1439,7 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
e->pipe = pipe;
e->base.pid = current->pid;
e->event.base.type = DRM_EVENT_VBLANK;
- e->event.base.length = sizeof e->event;
+ e->event.base.length = sizeof(e->event);
e->event.user_data = vblwait->request.signal;
e->base.event = &e->event.base;
e->base.file_priv = file_priv;
@@ -1451,12 +1459,12 @@ static int drm_queue_vblank_event(struct drm_device *dev, int pipe,
goto err_unlock;
}
- if (file_priv->event_space < sizeof e->event) {
+ if (file_priv->event_space < sizeof(e->event)) {
ret = -EBUSY;
goto err_unlock;
}
- file_priv->event_space -= sizeof e->event;
+ file_priv->event_space -= sizeof(e->event);
seq = drm_vblank_count_and_time(dev, pipe, &now);
if ((vblwait->request.type & _DRM_VBLANK_NEXTONMISS) &&
diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c
index c0644bb865f2..2d5ca8eec13a 100644
--- a/drivers/gpu/drm/drm_mipi_dsi.c
+++ b/drivers/gpu/drm/drm_mipi_dsi.c
@@ -323,8 +323,6 @@ EXPORT_SYMBOL(mipi_dsi_packet_format_is_long);
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
const struct mipi_dsi_msg *msg)
{
- const u8 *tx = msg->tx_buf;
-
if (!packet || !msg)
return -EINVAL;
@@ -353,8 +351,10 @@ int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
packet->header[2] = (msg->tx_len >> 8) & 0xff;
packet->payload_length = msg->tx_len;
- packet->payload = tx;
+ packet->payload = msg->tx_buf;
} else {
+ const u8 *tx = msg->tx_buf;
+
packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
}
diff --git a/drivers/gpu/drm/drm_modes.c b/drivers/gpu/drm/drm_modes.c
index 6d8b941c8200..487d0e35c134 100644
--- a/drivers/gpu/drm/drm_modes.c
+++ b/drivers/gpu/drm/drm_modes.c
@@ -615,6 +615,46 @@ void drm_display_mode_from_videomode(const struct videomode *vm,
}
EXPORT_SYMBOL_GPL(drm_display_mode_from_videomode);
+/**
+ * drm_display_mode_to_videomode - fill in @vm using @dmode,
+ * @dmode: drm_display_mode structure to use as source
+ * @vm: videomode structure to use as destination
+ *
+ * Fills out @vm using the display mode specified in @dmode.
+ */
+void drm_display_mode_to_videomode(const struct drm_display_mode *dmode,
+ struct videomode *vm)
+{
+ vm->hactive = dmode->hdisplay;
+ vm->hfront_porch = dmode->hsync_start - dmode->hdisplay;
+ vm->hsync_len = dmode->hsync_end - dmode->hsync_start;
+ vm->hback_porch = dmode->htotal - dmode->hsync_end;
+
+ vm->vactive = dmode->vdisplay;
+ vm->vfront_porch = dmode->vsync_start - dmode->vdisplay;
+ vm->vsync_len = dmode->vsync_end - dmode->vsync_start;
+ vm->vback_porch = dmode->vtotal - dmode->vsync_end;
+
+ vm->pixelclock = dmode->clock * 1000;
+
+ vm->flags = 0;
+ if (dmode->flags & DRM_MODE_FLAG_PHSYNC)
+ vm->flags |= DISPLAY_FLAGS_HSYNC_HIGH;
+ else if (dmode->flags & DRM_MODE_FLAG_NHSYNC)
+ vm->flags |= DISPLAY_FLAGS_HSYNC_LOW;
+ if (dmode->flags & DRM_MODE_FLAG_PVSYNC)
+ vm->flags |= DISPLAY_FLAGS_VSYNC_HIGH;
+ else if (dmode->flags & DRM_MODE_FLAG_NVSYNC)
+ vm->flags |= DISPLAY_FLAGS_VSYNC_LOW;
+ if (dmode->flags & DRM_MODE_FLAG_INTERLACE)
+ vm->flags |= DISPLAY_FLAGS_INTERLACED;
+ if (dmode->flags & DRM_MODE_FLAG_DBLSCAN)
+ vm->flags |= DISPLAY_FLAGS_DOUBLESCAN;
+ if (dmode->flags & DRM_MODE_FLAG_DBLCLK)
+ vm->flags |= DISPLAY_FLAGS_DOUBLECLK;
+}
+EXPORT_SYMBOL_GPL(drm_display_mode_to_videomode);
+
#ifdef CONFIG_OF
/**
* of_get_drm_display_mode - get a drm_display_mode from devicetree
@@ -739,6 +779,8 @@ EXPORT_SYMBOL(drm_mode_vrefresh);
* - The CRTC_STEREO_DOUBLE flag can be used to compute the timings for
* buffers containing two eyes (only adjust the timings when needed, eg. for
* "frame packing" or "side by side full").
+ * - The CRTC_NO_DBLSCAN and CRTC_NO_VSCAN flags request that adjustment *not*
+ * be performed for doublescan and vscan > 1 modes respectively.
*/
void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
{
@@ -765,18 +807,22 @@ void drm_mode_set_crtcinfo(struct drm_display_mode *p, int adjust_flags)
}
}
- if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
- p->crtc_vdisplay *= 2;
- p->crtc_vsync_start *= 2;
- p->crtc_vsync_end *= 2;
- p->crtc_vtotal *= 2;
+ if (!(adjust_flags & CRTC_NO_DBLSCAN)) {
+ if (p->flags & DRM_MODE_FLAG_DBLSCAN) {
+ p->crtc_vdisplay *= 2;
+ p->crtc_vsync_start *= 2;
+ p->crtc_vsync_end *= 2;
+ p->crtc_vtotal *= 2;
+ }
}
- if (p->vscan > 1) {
- p->crtc_vdisplay *= p->vscan;
- p->crtc_vsync_start *= p->vscan;
- p->crtc_vsync_end *= p->vscan;
- p->crtc_vtotal *= p->vscan;
+ if (!(adjust_flags & CRTC_NO_VSCAN)) {
+ if (p->vscan > 1) {
+ p->crtc_vdisplay *= p->vscan;
+ p->crtc_vsync_start *= p->vscan;
+ p->crtc_vsync_end *= p->vscan;
+ p->crtc_vtotal *= p->vscan;
+ }
}
if (adjust_flags & CRTC_STEREO_DOUBLE) {
@@ -906,9 +952,40 @@ bool drm_mode_equal_no_clocks_no_stereo(const struct drm_display_mode *mode1,
EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
/**
+ * drm_mode_validate_basic - make sure the mode is somewhat sane
+ * @mode: mode to check
+ *
+ * Check that the mode timings are at least somewhat reasonable.
+ * Any hardware specific limits are left up for each driver to check.
+ *
+ * Returns:
+ * The mode status
+ */
+enum drm_mode_status
+drm_mode_validate_basic(const struct drm_display_mode *mode)
+{
+ if (mode->clock == 0)
+ return MODE_CLOCK_LOW;
+
+ if (mode->hdisplay == 0 ||
+ mode->hsync_start < mode->hdisplay ||
+ mode->hsync_end < mode->hsync_start ||
+ mode->htotal < mode->hsync_end)
+ return MODE_H_ILLEGAL;
+
+ if (mode->vdisplay == 0 ||
+ mode->vsync_start < mode->vdisplay ||
+ mode->vsync_end < mode->vsync_start ||
+ mode->vtotal < mode->vsync_end)
+ return MODE_V_ILLEGAL;
+
+ return MODE_OK;
+}
+EXPORT_SYMBOL(drm_mode_validate_basic);
+
+/**
* drm_mode_validate_size - make sure modes adhere to size constraints
- * @dev: DRM device
- * @mode_list: list of modes to check
+ * @mode: mode to check
* @maxX: maximum width
* @maxY: maximum height
*
@@ -916,23 +993,80 @@ EXPORT_SYMBOL(drm_mode_equal_no_clocks_no_stereo);
* limitations of the DRM device/connector. If a mode is too big its status
* member is updated with the appropriate validation failure code. The list
* itself is not changed.
+ *
+ * Returns:
+ * The mode status
*/
-void drm_mode_validate_size(struct drm_device *dev,
- struct list_head *mode_list,
- int maxX, int maxY)
+enum drm_mode_status
+drm_mode_validate_size(const struct drm_display_mode *mode,
+ int maxX, int maxY)
{
- struct drm_display_mode *mode;
+ if (maxX > 0 && mode->hdisplay > maxX)
+ return MODE_VIRTUAL_X;
- list_for_each_entry(mode, mode_list, head) {
- if (maxX > 0 && mode->hdisplay > maxX)
- mode->status = MODE_VIRTUAL_X;
+ if (maxY > 0 && mode->vdisplay > maxY)
+ return MODE_VIRTUAL_Y;
- if (maxY > 0 && mode->vdisplay > maxY)
- mode->status = MODE_VIRTUAL_Y;
- }
+ return MODE_OK;
}
EXPORT_SYMBOL(drm_mode_validate_size);
+#define MODE_STATUS(status) [MODE_ ## status + 3] = #status
+
+static const char * const drm_mode_status_names[] = {
+ MODE_STATUS(OK),
+ MODE_STATUS(HSYNC),
+ MODE_STATUS(VSYNC),
+ MODE_STATUS(H_ILLEGAL),
+ MODE_STATUS(V_ILLEGAL),
+ MODE_STATUS(BAD_WIDTH),
+ MODE_STATUS(NOMODE),
+ MODE_STATUS(NO_INTERLACE),
+ MODE_STATUS(NO_DBLESCAN),
+ MODE_STATUS(NO_VSCAN),
+ MODE_STATUS(MEM),
+ MODE_STATUS(VIRTUAL_X),
+ MODE_STATUS(VIRTUAL_Y),
+ MODE_STATUS(MEM_VIRT),
+ MODE_STATUS(NOCLOCK),
+ MODE_STATUS(CLOCK_HIGH),
+ MODE_STATUS(CLOCK_LOW),
+ MODE_STATUS(CLOCK_RANGE),
+ MODE_STATUS(BAD_HVALUE),
+ MODE_STATUS(BAD_VVALUE),
+ MODE_STATUS(BAD_VSCAN),
+ MODE_STATUS(HSYNC_NARROW),
+ MODE_STATUS(HSYNC_WIDE),
+ MODE_STATUS(HBLANK_NARROW),
+ MODE_STATUS(HBLANK_WIDE),
+ MODE_STATUS(VSYNC_NARROW),
+ MODE_STATUS(VSYNC_WIDE),
+ MODE_STATUS(VBLANK_NARROW),
+ MODE_STATUS(VBLANK_WIDE),
+ MODE_STATUS(PANEL),
+ MODE_STATUS(INTERLACE_WIDTH),
+ MODE_STATUS(ONE_WIDTH),
+ MODE_STATUS(ONE_HEIGHT),
+ MODE_STATUS(ONE_SIZE),
+ MODE_STATUS(NO_REDUCED),
+ MODE_STATUS(NO_STEREO),
+ MODE_STATUS(UNVERIFIED),
+ MODE_STATUS(BAD),
+ MODE_STATUS(ERROR),
+};
+
+#undef MODE_STATUS
+
+static const char *drm_get_mode_status_name(enum drm_mode_status status)
+{
+ int index = status + 3;
+
+ if (WARN_ON(index < 0 || index >= ARRAY_SIZE(drm_mode_status_names)))
+ return "";
+
+ return drm_mode_status_names[index];
+}
+
/**
* drm_mode_prune_invalid - remove invalid modes from mode list
* @dev: DRM device
@@ -954,8 +1088,9 @@ void drm_mode_prune_invalid(struct drm_device *dev,
list_del(&mode->head);
if (verbose) {
drm_mode_debug_printmodeline(mode);
- DRM_DEBUG_KMS("Not using %s mode %d\n",
- mode->name, mode->status);
+ DRM_DEBUG_KMS("Not using %s mode: %s\n",
+ mode->name,
+ drm_get_mode_status_name(mode->status));
}
drm_mode_destroy(dev, mode);
}
diff --git a/drivers/gpu/drm/drm_plane_helper.c b/drivers/gpu/drm/drm_plane_helper.c
index 18a1ac6ac22f..5ba5792bfdba 100644
--- a/drivers/gpu/drm/drm_plane_helper.c
+++ b/drivers/gpu/drm/drm_plane_helper.c
@@ -142,6 +142,17 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
{
int hscale, vscale;
+ if (!fb) {
+ *visible = false;
+ return 0;
+ }
+
+ /* crtc should only be NULL when disabling (i.e., !fb) */
+ if (WARN_ON(!crtc)) {
+ *visible = false;
+ return 0;
+ }
+
if (!crtc->enabled && !can_update_disabled) {
DRM_DEBUG_KMS("Cannot update plane of a disabled CRTC.\n");
return -EINVAL;
@@ -155,11 +166,6 @@ int drm_plane_helper_check_update(struct drm_plane *plane,
return -ERANGE;
}
- if (!fb) {
- *visible = false;
- return 0;
- }
-
*visible = drm_rect_clip_scaled(src, dest, clip, hscale, vscale);
if (!*visible)
/*
@@ -429,7 +435,8 @@ int drm_plane_helper_commit(struct drm_plane *plane,
goto out;
}
- if (plane_funcs->prepare_fb && plane_state->fb) {
+ if (plane_funcs->prepare_fb && plane_state->fb &&
+ plane_state->fb != old_fb) {
ret = plane_funcs->prepare_fb(plane, plane_state->fb);
if (ret)
goto out;
@@ -443,13 +450,28 @@ int drm_plane_helper_commit(struct drm_plane *plane,
crtc_funcs[i]->atomic_begin(crtc[i]);
}
- plane_funcs->atomic_update(plane, plane_state);
+ /*
+ * Drivers may optionally implement the ->atomic_disable callback, so
+ * special-case that here.
+ */
+ if (drm_atomic_plane_disabling(plane, plane_state) &&
+ plane_funcs->atomic_disable)
+ plane_funcs->atomic_disable(plane, plane_state);
+ else
+ plane_funcs->atomic_update(plane, plane_state);
for (i = 0; i < 2; i++) {
if (crtc_funcs[i] && crtc_funcs[i]->atomic_flush)
crtc_funcs[i]->atomic_flush(crtc[i]);
}
+ /*
+ * If we only moved the plane and didn't change fb's, there's no need to
+ * wait for vblank.
+ */
+ if (plane->state->fb == old_fb)
+ goto out;
+
for (i = 0; i < 2; i++) {
if (!crtc[i])
continue;
@@ -478,7 +500,7 @@ out:
}
/**
- * drm_plane_helper_update() - Helper for primary plane update
+ * drm_plane_helper_update() - Transitional helper for plane update
* @plane: plane object to update
* @crtc: owning CRTC of owning plane
* @fb: framebuffer to flip onto plane
@@ -517,6 +539,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state)
return -ENOMEM;
+ plane_state->plane = plane;
plane_state->crtc = crtc;
drm_atomic_set_fb_for_plane(plane_state, fb);
@@ -534,7 +557,7 @@ int drm_plane_helper_update(struct drm_plane *plane, struct drm_crtc *crtc,
EXPORT_SYMBOL(drm_plane_helper_update);
/**
- * drm_plane_helper_disable() - Helper for primary plane disable
+ * drm_plane_helper_disable() - Transitional helper for plane disable
* @plane: plane to disable
*
* Provides a default plane disable handler using the atomic plane update
@@ -563,6 +586,7 @@ int drm_plane_helper_disable(struct drm_plane *plane)
plane_state = kzalloc(sizeof(*plane_state), GFP_KERNEL);
if (!plane_state)
return -ENOMEM;
+ plane_state->plane = plane;
plane_state->crtc = NULL;
drm_atomic_set_fb_for_plane(plane_state, NULL);
diff --git a/drivers/gpu/drm/drm_probe_helper.c b/drivers/gpu/drm/drm_probe_helper.c
index 7483a47de8e4..6591d48c1b9d 100644
--- a/drivers/gpu/drm/drm_probe_helper.c
+++ b/drivers/gpu/drm/drm_probe_helper.c
@@ -58,28 +58,23 @@
static bool drm_kms_helper_poll = true;
module_param_named(poll, drm_kms_helper_poll, bool, 0600);
-static void drm_mode_validate_flag(struct drm_connector *connector,
- int flags)
+static enum drm_mode_status
+drm_mode_validate_flag(const struct drm_display_mode *mode,
+ int flags)
{
- struct drm_display_mode *mode;
+ if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
+ !(flags & DRM_MODE_FLAG_INTERLACE))
+ return MODE_NO_INTERLACE;
- if (flags == (DRM_MODE_FLAG_DBLSCAN | DRM_MODE_FLAG_INTERLACE |
- DRM_MODE_FLAG_3D_MASK))
- return;
+ if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
+ !(flags & DRM_MODE_FLAG_DBLSCAN))
+ return MODE_NO_DBLESCAN;
- list_for_each_entry(mode, &connector->modes, head) {
- if ((mode->flags & DRM_MODE_FLAG_INTERLACE) &&
- !(flags & DRM_MODE_FLAG_INTERLACE))
- mode->status = MODE_NO_INTERLACE;
- if ((mode->flags & DRM_MODE_FLAG_DBLSCAN) &&
- !(flags & DRM_MODE_FLAG_DBLSCAN))
- mode->status = MODE_NO_DBLESCAN;
- if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
- !(flags & DRM_MODE_FLAG_3D_MASK))
- mode->status = MODE_NO_STEREO;
- }
+ if ((mode->flags & DRM_MODE_FLAG_3D_MASK) &&
+ !(flags & DRM_MODE_FLAG_3D_MASK))
+ return MODE_NO_STEREO;
- return;
+ return MODE_OK;
}
static int drm_helper_probe_add_cmdline_mode(struct drm_connector *connector)
@@ -108,6 +103,7 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
int count = 0;
int mode_flags = 0;
bool verbose_prune = true;
+ enum drm_connector_status old_status;
WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
@@ -126,7 +122,33 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
if (connector->funcs->force)
connector->funcs->force(connector);
} else {
+ old_status = connector->status;
+
connector->status = connector->funcs->detect(connector, true);
+
+ /*
+ * Normally either the driver's hpd code or the poll loop should
+ * pick up any changes and fire the hotplug event. But if
+ * userspace sneaks in a probe, we might miss a change. Hence
+ * check here, and if anything changed start the hotplug code.
+ */
+ if (old_status != connector->status) {
+ DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %d to %d\n",
+ connector->base.id,
+ connector->name,
+ old_status, connector->status);
+
+ /*
+ * The hotplug event code might call into the fb
+ * helpers, and so expects that we do not hold any
+ * locks. Fire up the poll struct instead, it will
+ * disable itself again.
+ */
+ dev->mode_config.delayed_event = true;
+ if (dev->mode_config.poll_enabled)
+ schedule_delayed_work(&dev->mode_config.output_poll_work,
+ 0);
+ }
}
/* Re-enable polling in case the global poll config changed. */
@@ -164,18 +186,22 @@ static int drm_helper_probe_single_connector_modes_merge_bits(struct drm_connect
drm_mode_connector_list_update(connector, merge_type_bits);
- if (maxX && maxY)
- drm_mode_validate_size(dev, &connector->modes, maxX, maxY);
-
if (connector->interlace_allowed)
mode_flags |= DRM_MODE_FLAG_INTERLACE;
if (connector->doublescan_allowed)
mode_flags |= DRM_MODE_FLAG_DBLSCAN;
if (connector->stereo_allowed)
mode_flags |= DRM_MODE_FLAG_3D_MASK;
- drm_mode_validate_flag(connector, mode_flags);
list_for_each_entry(mode, &connector->modes, head) {
+ mode->status = drm_mode_validate_basic(mode);
+
+ if (mode->status == MODE_OK)
+ mode->status = drm_mode_validate_size(mode, maxX, maxY);
+
+ if (mode->status == MODE_OK)
+ mode->status = drm_mode_validate_flag(mode, mode_flags);
+
if (mode->status == MODE_OK && connector_funcs->mode_valid)
mode->status = connector_funcs->mode_valid(connector,
mode);
@@ -275,10 +301,14 @@ static void output_poll_execute(struct work_struct *work)
struct drm_device *dev = container_of(delayed_work, struct drm_device, mode_config.output_poll_work);
struct drm_connector *connector;
enum drm_connector_status old_status;
- bool repoll = false, changed = false;
+ bool repoll = false, changed;
+
+ /* Pick up any changes detected by the probe functions. */
+ changed = dev->mode_config.delayed_event;
+ dev->mode_config.delayed_event = false;
if (!drm_kms_helper_poll)
- return;
+ goto out;
mutex_lock(&dev->mode_config.mutex);
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -305,6 +335,24 @@ static void output_poll_execute(struct work_struct *work)
if (old_status != connector->status) {
const char *old, *new;
+ /*
+ * The poll work sets force=false when calling detect so
+ * that drivers can avoid to do disruptive tests (e.g.
+ * when load detect cycles could cause flickering on
+ * other, running displays). This bears the risk that we
+ * flip-flop between unknown here in the poll work and
+ * the real state when userspace forces a full detect
+ * call after receiving a hotplug event due to this
+ * change.
+ *
+ * Hence clamp an unknown detect status to the old
+ * value.
+ */
+ if (connector->status == connector_status_unknown) {
+ connector->status = old_status;
+ continue;
+ }
+
old = drm_get_connector_status_name(old_status);
new = drm_get_connector_status_name(connector->status);
@@ -320,6 +368,7 @@ static void output_poll_execute(struct work_struct *work)
mutex_unlock(&dev->mode_config.mutex);
+out:
if (changed)
drm_kms_helper_hotplug_event(dev);
diff --git a/drivers/gpu/drm/drm_sysfs.c b/drivers/gpu/drm/drm_sysfs.c
index cc3d6d6d67e0..5c99d3773212 100644
--- a/drivers/gpu/drm/drm_sysfs.c
+++ b/drivers/gpu/drm/drm_sysfs.c
@@ -339,19 +339,51 @@ static ssize_t select_subconnector_show(struct device *device,
drm_get_dvi_i_select_name((int)subconnector));
}
-static struct device_attribute connector_attrs[] = {
- __ATTR_RO(status),
- __ATTR_RO(enabled),
- __ATTR_RO(dpms),
- __ATTR_RO(modes),
+static DEVICE_ATTR_RO(status);
+static DEVICE_ATTR_RO(enabled);
+static DEVICE_ATTR_RO(dpms);
+static DEVICE_ATTR_RO(modes);
+
+static struct attribute *connector_dev_attrs[] = {
+ &dev_attr_status.attr,
+ &dev_attr_enabled.attr,
+ &dev_attr_dpms.attr,
+ &dev_attr_modes.attr,
+ NULL
};
/* These attributes are for both DVI-I connectors and all types of tv-out. */
-static struct device_attribute connector_attrs_opt1[] = {
- __ATTR_RO(subconnector),
- __ATTR_RO(select_subconnector),
+static DEVICE_ATTR_RO(subconnector);
+static DEVICE_ATTR_RO(select_subconnector);
+
+static struct attribute *connector_opt_dev_attrs[] = {
+ &dev_attr_subconnector.attr,
+ &dev_attr_select_subconnector.attr,
+ NULL
};
+static umode_t connector_opt_dev_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
+{
+ struct device *dev = kobj_to_dev(kobj);
+ struct drm_connector *connector = to_drm_connector(dev);
+
+ /*
+ * In the long run it maybe a good idea to make one set of
+ * optionals per connector type.
+ */
+ switch (connector->connector_type) {
+ case DRM_MODE_CONNECTOR_DVII:
+ case DRM_MODE_CONNECTOR_Composite:
+ case DRM_MODE_CONNECTOR_SVIDEO:
+ case DRM_MODE_CONNECTOR_Component:
+ case DRM_MODE_CONNECTOR_TV:
+ return attr->mode;
+ }
+
+ return 0;
+}
+
static struct bin_attribute edid_attr = {
.attr.name = "edid",
.attr.mode = 0444,
@@ -359,6 +391,27 @@ static struct bin_attribute edid_attr = {
.read = edid_show,
};
+static struct bin_attribute *connector_bin_attrs[] = {
+ &edid_attr,
+ NULL
+};
+
+static const struct attribute_group connector_dev_group = {
+ .attrs = connector_dev_attrs,
+ .bin_attrs = connector_bin_attrs,
+};
+
+static const struct attribute_group connector_opt_dev_group = {
+ .attrs = connector_opt_dev_attrs,
+ .is_visible = connector_opt_dev_is_visible,
+};
+
+static const struct attribute_group *connector_dev_groups[] = {
+ &connector_dev_group,
+ &connector_opt_dev_group,
+ NULL
+};
+
/**
* drm_sysfs_connector_add - add a connector to sysfs
* @connector: connector to add
@@ -371,73 +424,27 @@ static struct bin_attribute edid_attr = {
int drm_sysfs_connector_add(struct drm_connector *connector)
{
struct drm_device *dev = connector->dev;
- int attr_cnt = 0;
- int opt_cnt = 0;
- int i;
- int ret;
if (connector->kdev)
return 0;
- connector->kdev = device_create(drm_class, dev->primary->kdev,
- 0, connector, "card%d-%s",
- dev->primary->index, connector->name);
+ connector->kdev =
+ device_create_with_groups(drm_class, dev->primary->kdev, 0,
+ connector, connector_dev_groups,
+ "card%d-%s", dev->primary->index,
+ connector->name);
DRM_DEBUG("adding \"%s\" to sysfs\n",
connector->name);
if (IS_ERR(connector->kdev)) {
DRM_ERROR("failed to register connector device: %ld\n", PTR_ERR(connector->kdev));
- ret = PTR_ERR(connector->kdev);
- goto out;
- }
-
- /* Standard attributes */
-
- for (attr_cnt = 0; attr_cnt < ARRAY_SIZE(connector_attrs); attr_cnt++) {
- ret = device_create_file(connector->kdev, &connector_attrs[attr_cnt]);
- if (ret)
- goto err_out_files;
+ return PTR_ERR(connector->kdev);
}
- /* Optional attributes */
- /*
- * In the long run it maybe a good idea to make one set of
- * optionals per connector type.
- */
- switch (connector->connector_type) {
- case DRM_MODE_CONNECTOR_DVII:
- case DRM_MODE_CONNECTOR_Composite:
- case DRM_MODE_CONNECTOR_SVIDEO:
- case DRM_MODE_CONNECTOR_Component:
- case DRM_MODE_CONNECTOR_TV:
- for (opt_cnt = 0; opt_cnt < ARRAY_SIZE(connector_attrs_opt1); opt_cnt++) {
- ret = device_create_file(connector->kdev, &connector_attrs_opt1[opt_cnt]);
- if (ret)
- goto err_out_files;
- }
- break;
- default:
- break;
- }
-
- ret = sysfs_create_bin_file(&connector->kdev->kobj, &edid_attr);
- if (ret)
- goto err_out_files;
-
/* Let userspace know we have a new connector */
drm_sysfs_hotplug_event(dev);
return 0;
-
-err_out_files:
- for (i = 0; i < opt_cnt; i++)
- device_remove_file(connector->kdev, &connector_attrs_opt1[i]);
- for (i = 0; i < attr_cnt; i++)
- device_remove_file(connector->kdev, &connector_attrs[i]);
- device_unregister(connector->kdev);
-
-out:
- return ret;
}
/**
@@ -455,16 +462,11 @@ out:
*/
void drm_sysfs_connector_remove(struct drm_connector *connector)
{
- int i;
-
if (!connector->kdev)
return;
DRM_DEBUG("removing \"%s\" from sysfs\n",
connector->name);
- for (i = 0; i < ARRAY_SIZE(connector_attrs); i++)
- device_remove_file(connector->kdev, &connector_attrs[i]);
- sysfs_remove_bin_file(&connector->kdev->kobj, &edid_attr);
device_unregister(connector->kdev);
connector->kdev = NULL;
}
diff --git a/drivers/gpu/drm/drm_vma_manager.c b/drivers/gpu/drm/drm_vma_manager.c
index 63b471205072..68c1f32fb086 100644
--- a/drivers/gpu/drm/drm_vma_manager.c
+++ b/drivers/gpu/drm/drm_vma_manager.c
@@ -50,8 +50,7 @@
*
* You must not use multiple offset managers on a single address_space.
* Otherwise, mm-core will be unable to tear down memory mappings as the VM will
- * no longer be linear. Please use VM_NONLINEAR in that case and implement your
- * own offset managers.
+ * no longer be linear.
*
* This offset manager works on page-based addresses. That is, every argument
* and return code (with the exception of drm_vma_node_offset_addr()) is given
diff --git a/drivers/gpu/drm/exynos/Kconfig b/drivers/gpu/drm/exynos/Kconfig
index 7f9f6f9e9b7e..a5e74612100e 100644
--- a/drivers/gpu/drm/exynos/Kconfig
+++ b/drivers/gpu/drm/exynos/Kconfig
@@ -6,23 +6,15 @@ config DRM_EXYNOS
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
select VIDEOMODE_HELPERS
help
Choose this option if you have a Samsung SoC EXYNOS chipset.
If M is selected the module will be called exynosdrm.
config DRM_EXYNOS_IOMMU
- bool "EXYNOS DRM IOMMU Support"
+ bool
depends on DRM_EXYNOS && EXYNOS_IOMMU && ARM_DMA_USE_IOMMU
- help
- Choose this option if you want to use IOMMU feature for DRM.
-
-config DRM_EXYNOS_DMABUF
- bool "EXYNOS DRM DMABUF"
- depends on DRM_EXYNOS
- help
- Choose this option if you want to use DMABUF feature for DRM.
+ default y
config DRM_EXYNOS_FIMD
bool "Exynos DRM FIMD"
@@ -32,9 +24,16 @@ config DRM_EXYNOS_FIMD
help
Choose this option if you want to use Exynos FIMD for DRM.
+config DRM_EXYNOS7_DECON
+ bool "Exynos DRM DECON"
+ depends on DRM_EXYNOS
+ select FB_MODE_HELPERS
+ help
+ Choose this option if you want to use Exynos DECON for DRM.
+
config DRM_EXYNOS_DPI
bool "EXYNOS DRM parallel output support"
- depends on DRM_EXYNOS_FIMD
+ depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
select DRM_PANEL
default n
help
@@ -42,7 +41,7 @@ config DRM_EXYNOS_DPI
config DRM_EXYNOS_DSI
bool "EXYNOS DRM MIPI-DSI driver support"
- depends on DRM_EXYNOS_FIMD
+ depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7_DECON)
select DRM_MIPI_DSI
select DRM_PANEL
default n
@@ -51,7 +50,7 @@ config DRM_EXYNOS_DSI
config DRM_EXYNOS_DP
bool "EXYNOS DRM DP driver support"
- depends on DRM_EXYNOS_FIMD && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
+ depends on (DRM_EXYNOS_FIMD || DRM_EXYNOS7DECON) && ARCH_EXYNOS && (DRM_PTN3460=n || DRM_PTN3460=y || DRM_PTN3460=DRM_EXYNOS)
default DRM_EXYNOS
select DRM_PANEL
help
diff --git a/drivers/gpu/drm/exynos/Makefile b/drivers/gpu/drm/exynos/Makefile
index 33ae3652b8da..cc90679cfc06 100644
--- a/drivers/gpu/drm/exynos/Makefile
+++ b/drivers/gpu/drm/exynos/Makefile
@@ -6,11 +6,11 @@ ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/exynos
exynosdrm-y := exynos_drm_drv.o exynos_drm_encoder.o \
exynos_drm_crtc.o exynos_drm_fbdev.o exynos_drm_fb.o \
exynos_drm_buf.o exynos_drm_gem.o exynos_drm_core.o \
- exynos_drm_plane.o
+ exynos_drm_plane.o exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_IOMMU) += exynos_drm_iommu.o
-exynosdrm-$(CONFIG_DRM_EXYNOS_DMABUF) += exynos_drm_dmabuf.o
exynosdrm-$(CONFIG_DRM_EXYNOS_FIMD) += exynos_drm_fimd.o
+exynosdrm-$(CONFIG_DRM_EXYNOS7_DECON) += exynos7_drm_decon.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DPI) += exynos_drm_dpi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DSI) += exynos_drm_dsi.o
exynosdrm-$(CONFIG_DRM_EXYNOS_DP) += exynos_dp_core.o exynos_dp_reg.o
diff --git a/drivers/gpu/drm/exynos/exynos7_drm_decon.c b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
new file mode 100644
index 000000000000..63f02e2380ae
--- /dev/null
+++ b/drivers/gpu/drm/exynos/exynos7_drm_decon.c
@@ -0,0 +1,990 @@
+/* drivers/gpu/drm/exynos/exynos7_drm_decon.c
+ *
+ * Copyright (C) 2014 Samsung Electronics Co.Ltd
+ * Authors:
+ * Akshu Agarwal <akshua@gmail.com>
+ * Ajay Kumar <ajaykumar.rs@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+#include <drm/drmP.h>
+#include <drm/exynos_drm.h>
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+
+#include <video/of_display_timing.h>
+#include <video/of_videomode.h>
+#include <video/exynos7_decon.h>
+
+#include "exynos_drm_crtc.h"
+#include "exynos_drm_drv.h"
+#include "exynos_drm_fbdev.h"
+#include "exynos_drm_iommu.h"
+
+/*
+ * DECON stands for Display and Enhancement controller.
+ */
+
+#define DECON_DEFAULT_FRAMERATE 60
+#define MIN_FB_WIDTH_FOR_16WORD_BURST 128
+
+#define WINDOWS_NR 2
+
+struct decon_win_data {
+ unsigned int ovl_x;
+ unsigned int ovl_y;
+ unsigned int offset_x;
+ unsigned int offset_y;
+ unsigned int ovl_width;
+ unsigned int ovl_height;
+ unsigned int fb_width;
+ unsigned int fb_height;
+ unsigned int bpp;
+ unsigned int pixel_format;
+ dma_addr_t dma_addr;
+ bool enabled;
+ bool resume;
+};
+
+struct decon_context {
+ struct device *dev;
+ struct drm_device *drm_dev;
+ struct exynos_drm_crtc *crtc;
+ struct clk *pclk;
+ struct clk *aclk;
+ struct clk *eclk;
+ struct clk *vclk;
+ void __iomem *regs;
+ struct decon_win_data win_data[WINDOWS_NR];
+ unsigned int default_win;
+ unsigned long irq_flags;
+ bool i80_if;
+ bool suspended;
+ int pipe;
+ wait_queue_head_t wait_vsync_queue;
+ atomic_t wait_vsync_event;
+
+ struct exynos_drm_panel_info panel;
+ struct exynos_drm_display *display;
+};
+
+static const struct of_device_id decon_driver_dt_match[] = {
+ {.compatible = "samsung,exynos7-decon"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, decon_driver_dt_match);
+
+static void decon_wait_for_vblank(struct exynos_drm_crtc *crtc)
+{
+ struct decon_context *ctx = crtc->ctx;
+
+ if (ctx->suspended)
+ return;
+
+ atomic_set(&ctx->wait_vsync_event, 1);
+
+ /*
+ * wait for DECON to signal VSYNC interrupt or return after
+ * timeout which is set to 50ms (refresh rate of 20).
+ */
+ if (!wait_event_timeout(ctx->wait_vsync_queue,
+ !atomic_read(&ctx->wait_vsync_event),
+ HZ/20))
+ DRM_DEBUG_KMS("vblank wait timed out.\n");
+}
+
+static void decon_clear_channel(struct decon_context *ctx)
+{
+ int win, ch_enabled = 0;
+
+ DRM_DEBUG_KMS("%s\n", __FILE__);
+
+ /* Check if any channel is enabled. */
+ for (win = 0; win < WINDOWS_NR; win++) {
+ u32 val = readl(ctx->regs + WINCON(win));
+
+ if (val & WINCONx_ENWIN) {
+ val &= ~WINCONx_ENWIN;
+ writel(val, ctx->regs + WINCON(win));
+ ch_enabled = 1;
+ }
+ }
+
+ /* Wait for vsync, as disable channel takes effect at next vsync */
+ if (ch_enabled) {
+ unsigned int state = ctx->suspended;
+
+ ctx->suspended = 0;
+ decon_wait_for_vblank(ctx->crtc);
+ ctx->suspended = state;
+ }
+}
+
+static int decon_ctx_initialize(struct decon_context *ctx,
+ struct drm_device *drm_dev)
+{
+ struct exynos_drm_private *priv = drm_dev->dev_private;
+
+ ctx->drm_dev = drm_dev;
+ ctx->pipe = priv->pipe++;
+
+ /* attach this sub driver to iommu mapping if supported. */
+ if (is_drm_iommu_supported(ctx->drm_dev)) {
+ int ret;
+
+ /*
+ * If any channel is already active, iommu will throw
+ * a PAGE FAULT when enabled. So clear any channel if enabled.
+ */
+ decon_clear_channel(ctx);
+ ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
+ if (ret) {
+ DRM_ERROR("drm_iommu_attach failed.\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void decon_ctx_remove(struct decon_context *ctx)
+{
+ /* detach this sub driver from iommu mapping if supported. */
+ if (is_drm_iommu_supported(ctx->drm_dev))
+ drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
+}
+
+static u32 decon_calc_clkdiv(struct decon_context *ctx,
+ const struct drm_display_mode *mode)
+{
+ unsigned long ideal_clk = mode->htotal * mode->vtotal * mode->vrefresh;
+ u32 clkdiv;
+
+ /* Find the clock divider value that gets us closest to ideal_clk */
+ clkdiv = DIV_ROUND_UP(clk_get_rate(ctx->vclk), ideal_clk);
+
+ return (clkdiv < 0x100) ? clkdiv : 0xff;
+}
+
+static bool decon_mode_fixup(struct exynos_drm_crtc *crtc,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ if (adjusted_mode->vrefresh == 0)
+ adjusted_mode->vrefresh = DECON_DEFAULT_FRAMERATE;
+
+ return true;
+}
+
+static void decon_commit(struct exynos_drm_crtc *crtc)
+{
+ struct decon_context *ctx = crtc->ctx;
+ struct drm_display_mode *mode = &crtc->base.mode;
+ u32 val, clkdiv;
+
+ if (ctx->suspended)
+ return;
+
+ /* nothing to do if we haven't set the mode yet */
+ if (mode->htotal == 0 || mode->vtotal == 0)
+ return;
+
+ if (!ctx->i80_if) {
+ int vsync_len, vbpd, vfpd, hsync_len, hbpd, hfpd;
+ /* setup vertical timing values. */
+ vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start;
+ vbpd = mode->crtc_vtotal - mode->crtc_vsync_end;
+ vfpd = mode->crtc_vsync_start - mode->crtc_vdisplay;
+
+ val = VIDTCON0_VBPD(vbpd - 1) | VIDTCON0_VFPD(vfpd - 1);
+ writel(val, ctx->regs + VIDTCON0);
+
+ val = VIDTCON1_VSPW(vsync_len - 1);
+ writel(val, ctx->regs + VIDTCON1);
+
+ /* setup horizontal timing values. */
+ hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start;
+ hbpd = mode->crtc_htotal - mode->crtc_hsync_end;
+ hfpd = mode->crtc_hsync_start - mode->crtc_hdisplay;
+
+ /* setup horizontal timing values. */
+ val = VIDTCON2_HBPD(hbpd - 1) | VIDTCON2_HFPD(hfpd - 1);
+ writel(val, ctx->regs + VIDTCON2);
+
+ val = VIDTCON3_HSPW(hsync_len - 1);
+ writel(val, ctx->regs + VIDTCON3);
+ }
+
+ /* setup horizontal and vertical display size. */
+ val = VIDTCON4_LINEVAL(mode->vdisplay - 1) |
+ VIDTCON4_HOZVAL(mode->hdisplay - 1);
+ writel(val, ctx->regs + VIDTCON4);
+
+ writel(mode->vdisplay - 1, ctx->regs + LINECNT_OP_THRESHOLD);
+
+ /*
+ * fields of register with prefix '_F' would be updated
+ * at vsync(same as dma start)
+ */
+ val = VIDCON0_ENVID | VIDCON0_ENVID_F;
+ writel(val, ctx->regs + VIDCON0);
+
+ clkdiv = decon_calc_clkdiv(ctx, mode);
+ if (clkdiv > 1) {
+ val = VCLKCON1_CLKVAL_NUM_VCLK(clkdiv - 1);
+ writel(val, ctx->regs + VCLKCON1);
+ writel(val, ctx->regs + VCLKCON2);
+ }
+
+ val = readl(ctx->regs + DECON_UPDATE);
+ val |= DECON_UPDATE_STANDALONE_F;
+ writel(val, ctx->regs + DECON_UPDATE);
+}
+
+static int decon_enable_vblank(struct exynos_drm_crtc *crtc)
+{
+ struct decon_context *ctx = crtc->ctx;
+ u32 val;
+
+ if (ctx->suspended)
+ return -EPERM;
+
+ if (!test_and_set_bit(0, &ctx->irq_flags)) {
+ val = readl(ctx->regs + VIDINTCON0);
+
+ val |= VIDINTCON0_INT_ENABLE;
+
+ if (!ctx->i80_if) {
+ val |= VIDINTCON0_INT_FRAME;
+ val &= ~VIDINTCON0_FRAMESEL0_MASK;
+ val |= VIDINTCON0_FRAMESEL0_VSYNC;
+ }
+
+ writel(val, ctx->regs + VIDINTCON0);
+ }
+
+ return 0;
+}
+
+static void decon_disable_vblank(struct exynos_drm_crtc *crtc)
+{
+ struct decon_context *ctx = crtc->ctx;
+ u32 val;
+
+ if (ctx->suspended)
+ return;
+
+ if (test_and_clear_bit(0, &ctx->irq_flags)) {
+ val = readl(ctx->regs + VIDINTCON0);
+
+ val &= ~VIDINTCON0_INT_ENABLE;
+ if (!ctx->i80_if)
+ val &= ~VIDINTCON0_INT_FRAME;
+
+ writel(val, ctx->regs + VIDINTCON0);
+ }
+}
+
+static void decon_win_mode_set(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
+{
+ struct decon_context *ctx = crtc->ctx;
+ struct decon_win_data *win_data;
+ int win, padding;
+
+ if (!plane) {
+ DRM_ERROR("plane is NULL\n");
+ return;
+ }
+
+ win = plane->zpos;
+ if (win == DEFAULT_ZPOS)
+ win = ctx->default_win;
+
+ if (win < 0 || win >= WINDOWS_NR)
+ return;
+
+
+ win_data = &ctx->win_data[win];
+
+ padding = (plane->pitch / (plane->bpp >> 3)) - plane->fb_width;
+ win_data->offset_x = plane->fb_x;
+ win_data->offset_y = plane->fb_y;
+ win_data->fb_width = plane->fb_width + padding;
+ win_data->fb_height = plane->fb_height;
+ win_data->ovl_x = plane->crtc_x;
+ win_data->ovl_y = plane->crtc_y;
+ win_data->ovl_width = plane->crtc_width;
+ win_data->ovl_height = plane->crtc_height;
+ win_data->dma_addr = plane->dma_addr[0];
+ win_data->bpp = plane->bpp;
+ win_data->pixel_format = plane->pixel_format;
+
+ DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
+ win_data->offset_x, win_data->offset_y);
+ DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+ win_data->ovl_width, win_data->ovl_height);
+ DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
+ DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
+ plane->fb_width, plane->crtc_width);
+}
+
+static void decon_win_set_pixfmt(struct decon_context *ctx, unsigned int win)
+{
+ struct decon_win_data *win_data = &ctx->win_data[win];
+ unsigned long val;
+
+ val = readl(ctx->regs + WINCON(win));
+ val &= ~WINCONx_BPPMODE_MASK;
+
+ switch (win_data->pixel_format) {
+ case DRM_FORMAT_RGB565:
+ val |= WINCONx_BPPMODE_16BPP_565;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_XRGB8888:
+ val |= WINCONx_BPPMODE_24BPP_xRGB;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_XBGR8888:
+ val |= WINCONx_BPPMODE_24BPP_xBGR;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_RGBX8888:
+ val |= WINCONx_BPPMODE_24BPP_RGBx;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_BGRX8888:
+ val |= WINCONx_BPPMODE_24BPP_BGRx;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_ARGB8888:
+ val |= WINCONx_BPPMODE_32BPP_ARGB | WINCONx_BLD_PIX |
+ WINCONx_ALPHA_SEL;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_ABGR8888:
+ val |= WINCONx_BPPMODE_32BPP_ABGR | WINCONx_BLD_PIX |
+ WINCONx_ALPHA_SEL;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_RGBA8888:
+ val |= WINCONx_BPPMODE_32BPP_RGBA | WINCONx_BLD_PIX |
+ WINCONx_ALPHA_SEL;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ case DRM_FORMAT_BGRA8888:
+ val |= WINCONx_BPPMODE_32BPP_BGRA | WINCONx_BLD_PIX |
+ WINCONx_ALPHA_SEL;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ default:
+ DRM_DEBUG_KMS("invalid pixel size so using unpacked 24bpp.\n");
+
+ val |= WINCONx_BPPMODE_24BPP_xRGB;
+ val |= WINCONx_BURSTLEN_16WORD;
+ break;
+ }
+
+ DRM_DEBUG_KMS("bpp = %d\n", win_data->bpp);
+
+ /*
+ * In case of exynos, setting dma-burst to 16Word causes permanent
+ * tearing for very small buffers, e.g. cursor buffer. Burst Mode
+ * switching which is based on plane size is not recommended as
+ * plane size varies a lot towards the end of the screen and rapid
+ * movement causes unstable DMA which results into iommu crash/tear.
+ */
+
+ if (win_data->fb_width < MIN_FB_WIDTH_FOR_16WORD_BURST) {
+ val &= ~WINCONx_BURSTLEN_MASK;
+ val |= WINCONx_BURSTLEN_8WORD;
+ }
+
+ writel(val, ctx->regs + WINCON(win));
+}
+
+static void decon_win_set_colkey(struct decon_context *ctx, unsigned int win)
+{
+ unsigned int keycon0 = 0, keycon1 = 0;
+
+ keycon0 = ~(WxKEYCON0_KEYBL_EN | WxKEYCON0_KEYEN_F |
+ WxKEYCON0_DIRCON) | WxKEYCON0_COMPKEY(0);
+
+ keycon1 = WxKEYCON1_COLVAL(0xffffffff);
+
+ writel(keycon0, ctx->regs + WKEYCON0_BASE(win));
+ writel(keycon1, ctx->regs + WKEYCON1_BASE(win));
+}
+
+/**
+ * shadow_protect_win() - disable updating values from shadow registers at vsync
+ *
+ * @win: window to protect registers for
+ * @protect: 1 to protect (disable updates)
+ */
+static void decon_shadow_protect_win(struct decon_context *ctx,
+ int win, bool protect)
+{
+ u32 bits, val;
+
+ bits = SHADOWCON_WINx_PROTECT(win);
+
+ val = readl(ctx->regs + SHADOWCON);
+ if (protect)
+ val |= bits;
+ else
+ val &= ~bits;
+ writel(val, ctx->regs + SHADOWCON);
+}
+
+static void decon_win_commit(struct exynos_drm_crtc *crtc, int zpos)
+{
+ struct decon_context *ctx = crtc->ctx;
+ struct drm_display_mode *mode = &crtc->base.mode;
+ struct decon_win_data *win_data;
+ int win = zpos;
+ unsigned long val, alpha;
+ unsigned int last_x;
+ unsigned int last_y;
+
+ if (ctx->suspended)
+ return;
+
+ if (win == DEFAULT_ZPOS)
+ win = ctx->default_win;
+
+ if (win < 0 || win >= WINDOWS_NR)
+ return;
+
+ win_data = &ctx->win_data[win];
+
+ /* If suspended, enable this on resume */
+ if (ctx->suspended) {
+ win_data->resume = true;
+ return;
+ }
+
+ /*
+ * SHADOWCON/PRTCON register is used for enabling timing.
+ *
+ * for example, once only width value of a register is set,
+ * if the dma is started then decon hardware could malfunction so
+ * with protect window setting, the register fields with prefix '_F'
+ * wouldn't be updated at vsync also but updated once unprotect window
+ * is set.
+ */
+
+ /* protect windows */
+ decon_shadow_protect_win(ctx, win, true);
+
+ /* buffer start address */
+ val = (unsigned long)win_data->dma_addr;
+ writel(val, ctx->regs + VIDW_BUF_START(win));
+
+ /* buffer size */
+ writel(win_data->fb_width, ctx->regs + VIDW_WHOLE_X(win));
+ writel(win_data->fb_height, ctx->regs + VIDW_WHOLE_Y(win));
+
+ /* offset from the start of the buffer to read */
+ writel(win_data->offset_x, ctx->regs + VIDW_OFFSET_X(win));
+ writel(win_data->offset_y, ctx->regs + VIDW_OFFSET_Y(win));
+
+ DRM_DEBUG_KMS("start addr = 0x%lx\n",
+ (unsigned long)win_data->dma_addr);
+ DRM_DEBUG_KMS("ovl_width = %d, ovl_height = %d\n",
+ win_data->ovl_width, win_data->ovl_height);
+
+ /*
+ * OSD position.
+ * In case the window layout goes of LCD layout, DECON fails.
+ */
+ if ((win_data->ovl_x + win_data->ovl_width) > mode->hdisplay)
+ win_data->ovl_x = mode->hdisplay - win_data->ovl_width;
+ if ((win_data->ovl_y + win_data->ovl_height) > mode->vdisplay)
+ win_data->ovl_y = mode->vdisplay - win_data->ovl_height;
+
+ val = VIDOSDxA_TOPLEFT_X(win_data->ovl_x) |
+ VIDOSDxA_TOPLEFT_Y(win_data->ovl_y);
+ writel(val, ctx->regs + VIDOSD_A(win));
+
+ last_x = win_data->ovl_x + win_data->ovl_width;
+ if (last_x)
+ last_x--;
+ last_y = win_data->ovl_y + win_data->ovl_height;
+ if (last_y)
+ last_y--;
+
+ val = VIDOSDxB_BOTRIGHT_X(last_x) | VIDOSDxB_BOTRIGHT_Y(last_y);
+
+ writel(val, ctx->regs + VIDOSD_B(win));
+
+ DRM_DEBUG_KMS("osd pos: tx = %d, ty = %d, bx = %d, by = %d\n",
+ win_data->ovl_x, win_data->ovl_y, last_x, last_y);
+
+ /* OSD alpha */
+ alpha = VIDOSDxC_ALPHA0_R_F(0x0) |
+ VIDOSDxC_ALPHA0_G_F(0x0) |
+ VIDOSDxC_ALPHA0_B_F(0x0);
+
+ writel(alpha, ctx->regs + VIDOSD_C(win));
+
+ alpha = VIDOSDxD_ALPHA1_R_F(0xff) |
+ VIDOSDxD_ALPHA1_G_F(0xff) |
+ VIDOSDxD_ALPHA1_B_F(0xff);
+
+ writel(alpha, ctx->regs + VIDOSD_D(win));
+
+ decon_win_set_pixfmt(ctx, win);
+
+ /* hardware window 0 doesn't support color key. */
+ if (win != 0)
+ decon_win_set_colkey(ctx, win);
+
+ /* wincon */
+ val = readl(ctx->regs + WINCON(win));
+ val |= WINCONx_TRIPLE_BUF_MODE;
+ val |= WINCONx_ENWIN;
+ writel(val, ctx->regs + WINCON(win));
+
+ /* Enable DMA channel and unprotect windows */
+ decon_shadow_protect_win(ctx, win, false);
+
+ val = readl(ctx->regs + DECON_UPDATE);
+ val |= DECON_UPDATE_STANDALONE_F;
+ writel(val, ctx->regs + DECON_UPDATE);
+
+ win_data->enabled = true;
+}
+
+static void decon_win_disable(struct exynos_drm_crtc *crtc, int zpos)
+{
+ struct decon_context *ctx = crtc->ctx;
+ struct decon_win_data *win_data;
+ int win = zpos;
+ u32 val;
+
+ if (win == DEFAULT_ZPOS)
+ win = ctx->default_win;
+
+ if (win < 0 || win >= WINDOWS_NR)
+ return;
+
+ win_data = &ctx->win_data[win];
+
+ if (ctx->suspended) {
+ /* do not resume this window*/
+ win_data->resume = false;
+ return;
+ }
+
+ /* protect windows */
+ decon_shadow_protect_win(ctx, win, true);
+
+ /* wincon */
+ val = readl(ctx->regs + WINCON(win));
+ val &= ~WINCONx_ENWIN;
+ writel(val, ctx->regs + WINCON(win));
+
+ /* unprotect windows */
+ decon_shadow_protect_win(ctx, win, false);
+
+ val = readl(ctx->regs + DECON_UPDATE);
+ val |= DECON_UPDATE_STANDALONE_F;
+ writel(val, ctx->regs + DECON_UPDATE);
+
+ win_data->enabled = false;
+}
+
+static void decon_window_suspend(struct decon_context *ctx)
+{
+ struct decon_win_data *win_data;
+ int i;
+
+ for (i = 0; i < WINDOWS_NR; i++) {
+ win_data = &ctx->win_data[i];
+ win_data->resume = win_data->enabled;
+ if (win_data->enabled)
+ decon_win_disable(ctx->crtc, i);
+ }
+}
+
+static void decon_window_resume(struct decon_context *ctx)
+{
+ struct decon_win_data *win_data;
+ int i;
+
+ for (i = 0; i < WINDOWS_NR; i++) {
+ win_data = &ctx->win_data[i];
+ win_data->enabled = win_data->resume;
+ win_data->resume = false;
+ }
+}
+
+static void decon_apply(struct decon_context *ctx)
+{
+ struct decon_win_data *win_data;
+ int i;
+
+ for (i = 0; i < WINDOWS_NR; i++) {
+ win_data = &ctx->win_data[i];
+ if (win_data->enabled)
+ decon_win_commit(ctx->crtc, i);
+ else
+ decon_win_disable(ctx->crtc, i);
+ }
+
+ decon_commit(ctx->crtc);
+}
+
+static void decon_init(struct decon_context *ctx)
+{
+ u32 val;
+
+ writel(VIDCON0_SWRESET, ctx->regs + VIDCON0);
+
+ val = VIDOUTCON0_DISP_IF_0_ON;
+ if (!ctx->i80_if)
+ val |= VIDOUTCON0_RGBIF;
+ writel(val, ctx->regs + VIDOUTCON0);
+
+ writel(VCLKCON0_CLKVALUP | VCLKCON0_VCLKFREE, ctx->regs + VCLKCON0);
+
+ if (!ctx->i80_if)
+ writel(VIDCON1_VCLK_HOLD, ctx->regs + VIDCON1(0));
+}
+
+static int decon_poweron(struct decon_context *ctx)
+{
+ int ret;
+
+ if (!ctx->suspended)
+ return 0;
+
+ ctx->suspended = false;
+
+ pm_runtime_get_sync(ctx->dev);
+
+ ret = clk_prepare_enable(ctx->pclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the pclk [%d]\n", ret);
+ goto pclk_err;
+ }
+
+ ret = clk_prepare_enable(ctx->aclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the aclk [%d]\n", ret);
+ goto aclk_err;
+ }
+
+ ret = clk_prepare_enable(ctx->eclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the eclk [%d]\n", ret);
+ goto eclk_err;
+ }
+
+ ret = clk_prepare_enable(ctx->vclk);
+ if (ret < 0) {
+ DRM_ERROR("Failed to prepare_enable the vclk [%d]\n", ret);
+ goto vclk_err;
+ }
+
+ decon_init(ctx);
+
+ /* if vblank was enabled status, enable it again. */
+ if (test_and_clear_bit(0, &ctx->irq_flags)) {
+ ret = decon_enable_vblank(ctx->crtc);
+ if (ret) {
+ DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
+ goto err;
+ }
+ }
+
+ decon_window_resume(ctx);
+
+ decon_apply(ctx);
+
+ return 0;
+
+err:
+ clk_disable_unprepare(ctx->vclk);
+vclk_err:
+ clk_disable_unprepare(ctx->eclk);
+eclk_err:
+ clk_disable_unprepare(ctx->aclk);
+aclk_err:
+ clk_disable_unprepare(ctx->pclk);
+pclk_err:
+ ctx->suspended = true;
+ return ret;
+}
+
+static int decon_poweroff(struct decon_context *ctx)
+{
+ if (ctx->suspended)
+ return 0;
+
+ /*
+ * We need to make sure that all windows are disabled before we
+ * suspend that connector. Otherwise we might try to scan from
+ * a destroyed buffer later.
+ */
+ decon_window_suspend(ctx);
+
+ clk_disable_unprepare(ctx->vclk);
+ clk_disable_unprepare(ctx->eclk);
+ clk_disable_unprepare(ctx->aclk);
+ clk_disable_unprepare(ctx->pclk);
+
+ pm_runtime_put_sync(ctx->dev);
+
+ ctx->suspended = true;
+ return 0;
+}
+
+static void decon_dpms(struct exynos_drm_crtc *crtc, int mode)
+{
+ DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
+
+ switch (mode) {
+ case DRM_MODE_DPMS_ON:
+ decon_poweron(crtc->ctx);
+ break;
+ case DRM_MODE_DPMS_STANDBY:
+ case DRM_MODE_DPMS_SUSPEND:
+ case DRM_MODE_DPMS_OFF:
+ decon_poweroff(crtc->ctx);
+ break;
+ default:
+ DRM_DEBUG_KMS("unspecified mode %d\n", mode);
+ break;
+ }
+}
+
+static struct exynos_drm_crtc_ops decon_crtc_ops = {
+ .dpms = decon_dpms,
+ .mode_fixup = decon_mode_fixup,
+ .commit = decon_commit,
+ .enable_vblank = decon_enable_vblank,
+ .disable_vblank = decon_disable_vblank,
+ .wait_for_vblank = decon_wait_for_vblank,
+ .win_mode_set = decon_win_mode_set,
+ .win_commit = decon_win_commit,
+ .win_disable = decon_win_disable,
+};
+
+
+static irqreturn_t decon_irq_handler(int irq, void *dev_id)
+{
+ struct decon_context *ctx = (struct decon_context *)dev_id;
+ u32 val, clear_bit;
+
+ val = readl(ctx->regs + VIDINTCON1);
+
+ clear_bit = ctx->i80_if ? VIDINTCON1_INT_I80 : VIDINTCON1_INT_FRAME;
+ if (val & clear_bit)
+ writel(clear_bit, ctx->regs + VIDINTCON1);
+
+ /* check the crtc is detached already from encoder */
+ if (ctx->pipe < 0 || !ctx->drm_dev)
+ goto out;
+
+ if (!ctx->i80_if) {
+ drm_handle_vblank(ctx->drm_dev, ctx->pipe);
+ exynos_drm_crtc_finish_pageflip(ctx->drm_dev, ctx->pipe);
+
+ /* set wait vsync event to zero and wake up queue. */
+ if (atomic_read(&ctx->wait_vsync_event)) {
+ atomic_set(&ctx->wait_vsync_event, 0);
+ wake_up(&ctx->wait_vsync_queue);
+ }
+ }
+out:
+ return IRQ_HANDLED;
+}
+
+static int decon_bind(struct device *dev, struct device *master, void *data)
+{
+ struct decon_context *ctx = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ int ret;
+
+ ret = decon_ctx_initialize(ctx, drm_dev);
+ if (ret) {
+ DRM_ERROR("decon_ctx_initialize failed.\n");
+ return ret;
+ }
+
+ ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+ EXYNOS_DISPLAY_TYPE_LCD,
+ &decon_crtc_ops, ctx);
+ if (IS_ERR(ctx->crtc)) {
+ decon_ctx_remove(ctx);
+ return PTR_ERR(ctx->crtc);
+ }
+
+ if (ctx->display)
+ exynos_drm_create_enc_conn(drm_dev, ctx->display);
+
+ return 0;
+
+}
+
+static void decon_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct decon_context *ctx = dev_get_drvdata(dev);
+
+ decon_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
+
+ if (ctx->display)
+ exynos_dpi_remove(ctx->display);
+
+ decon_ctx_remove(ctx);
+}
+
+static const struct component_ops decon_component_ops = {
+ .bind = decon_bind,
+ .unbind = decon_unbind,
+};
+
+static int decon_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct decon_context *ctx;
+ struct device_node *i80_if_timings;
+ struct resource *res;
+ int ret;
+
+ if (!dev->of_node)
+ return -ENODEV;
+
+ ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
+ EXYNOS_DISPLAY_TYPE_LCD);
+ if (ret)
+ return ret;
+
+ ctx->dev = dev;
+ ctx->suspended = true;
+
+ i80_if_timings = of_get_child_by_name(dev->of_node, "i80-if-timings");
+ if (i80_if_timings)
+ ctx->i80_if = true;
+ of_node_put(i80_if_timings);
+
+ ctx->regs = of_iomap(dev->of_node, 0);
+ if (IS_ERR(ctx->regs)) {
+ ret = PTR_ERR(ctx->regs);
+ goto err_del_component;
+ }
+
+ ctx->pclk = devm_clk_get(dev, "pclk_decon0");
+ if (IS_ERR(ctx->pclk)) {
+ dev_err(dev, "failed to get bus clock pclk\n");
+ ret = PTR_ERR(ctx->pclk);
+ goto err_iounmap;
+ }
+
+ ctx->aclk = devm_clk_get(dev, "aclk_decon0");
+ if (IS_ERR(ctx->aclk)) {
+ dev_err(dev, "failed to get bus clock aclk\n");
+ ret = PTR_ERR(ctx->aclk);
+ goto err_iounmap;
+ }
+
+ ctx->eclk = devm_clk_get(dev, "decon0_eclk");
+ if (IS_ERR(ctx->eclk)) {
+ dev_err(dev, "failed to get eclock\n");
+ ret = PTR_ERR(ctx->eclk);
+ goto err_iounmap;
+ }
+
+ ctx->vclk = devm_clk_get(dev, "decon0_vclk");
+ if (IS_ERR(ctx->vclk)) {
+ dev_err(dev, "failed to get vclock\n");
+ ret = PTR_ERR(ctx->vclk);
+ goto err_iounmap;
+ }
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_IRQ,
+ ctx->i80_if ? "lcd_sys" : "vsync");
+ if (!res) {
+ dev_err(dev, "irq request failed.\n");
+ ret = -ENXIO;
+ goto err_iounmap;
+ }
+
+ ret = devm_request_irq(dev, res->start, decon_irq_handler,
+ 0, "drm_decon", ctx);
+ if (ret) {
+ dev_err(dev, "irq request failed.\n");
+ goto err_iounmap;
+ }
+
+ init_waitqueue_head(&ctx->wait_vsync_queue);
+ atomic_set(&ctx->wait_vsync_event, 0);
+
+ platform_set_drvdata(pdev, ctx);
+
+ ctx->display = exynos_dpi_probe(dev);
+ if (IS_ERR(ctx->display)) {
+ ret = PTR_ERR(ctx->display);
+ goto err_iounmap;
+ }
+
+ pm_runtime_enable(dev);
+
+ ret = component_add(dev, &decon_component_ops);
+ if (ret)
+ goto err_disable_pm_runtime;
+
+ return ret;
+
+err_disable_pm_runtime:
+ pm_runtime_disable(dev);
+
+err_iounmap:
+ iounmap(ctx->regs);
+
+err_del_component:
+ exynos_drm_component_del(dev, EXYNOS_DEVICE_TYPE_CRTC);
+ return ret;
+}
+
+static int decon_remove(struct platform_device *pdev)
+{
+ struct decon_context *ctx = dev_get_drvdata(&pdev->dev);
+
+ pm_runtime_disable(&pdev->dev);
+
+ iounmap(ctx->regs);
+
+ component_del(&pdev->dev, &decon_component_ops);
+ exynos_drm_component_del(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC);
+
+ return 0;
+}
+
+struct platform_driver decon_driver = {
+ .probe = decon_probe,
+ .remove = decon_remove,
+ .driver = {
+ .name = "exynos-decon",
+ .of_match_table = decon_driver_dt_match,
+ },
+};
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.c b/drivers/gpu/drm/exynos/exynos_dp_core.c
index 34d46aa75416..bf17a60b40ed 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.c
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.c
@@ -18,6 +18,7 @@
#include <linux/interrupt.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
+#include <linux/of_graph.h>
#include <linux/gpio.h>
#include <linux/component.h>
#include <linux/phy/phy.h>
@@ -993,32 +994,20 @@ static struct drm_connector_helper_funcs exynos_dp_connector_helper_funcs = {
.best_encoder = exynos_dp_best_encoder,
};
-static bool find_bridge(const char *compat, struct bridge_init *bridge)
-{
- bridge->client = NULL;
- bridge->node = of_find_compatible_node(NULL, NULL, compat);
- if (!bridge->node)
- return false;
-
- bridge->client = of_find_i2c_device_by_node(bridge->node);
- if (!bridge->client)
- return false;
-
- return true;
-}
-
/* returns the number of bridges attached */
-static int exynos_drm_attach_lcd_bridge(struct drm_device *dev,
+static int exynos_drm_attach_lcd_bridge(struct exynos_dp_device *dp,
struct drm_encoder *encoder)
{
- struct bridge_init bridge;
int ret;
- if (find_bridge("nxp,ptn3460", &bridge)) {
- ret = ptn3460_init(dev, encoder, bridge.client, bridge.node);
- if (!ret)
- return 1;
+ encoder->bridge = dp->bridge;
+ dp->bridge->encoder = encoder;
+ ret = drm_bridge_attach(encoder->dev, dp->bridge);
+ if (ret) {
+ DRM_ERROR("Failed to attach bridge to drm\n");
+ return ret;
}
+
return 0;
}
@@ -1032,9 +1021,11 @@ static int exynos_dp_create_connector(struct exynos_drm_display *display,
dp->encoder = encoder;
/* Pre-empt DP connector creation if there's a bridge */
- ret = exynos_drm_attach_lcd_bridge(dp->drm_dev, encoder);
- if (ret)
- return 0;
+ if (dp->bridge) {
+ ret = exynos_drm_attach_lcd_bridge(dp, encoder);
+ if (!ret)
+ return 0;
+ }
connector->polled = DRM_CONNECTOR_POLL_HPD;
@@ -1067,10 +1058,8 @@ static void exynos_dp_phy_exit(struct exynos_dp_device *dp)
phy_power_off(dp->phy);
}
-static void exynos_dp_poweron(struct exynos_drm_display *display)
+static void exynos_dp_poweron(struct exynos_dp_device *dp)
{
- struct exynos_dp_device *dp = display_to_dp(display);
-
if (dp->dpms_mode == DRM_MODE_DPMS_ON)
return;
@@ -1085,13 +1074,11 @@ static void exynos_dp_poweron(struct exynos_drm_display *display)
exynos_dp_phy_init(dp);
exynos_dp_init_dp(dp);
enable_irq(dp->irq);
- exynos_dp_commit(display);
+ exynos_dp_commit(&dp->display);
}
-static void exynos_dp_poweroff(struct exynos_drm_display *display)
+static void exynos_dp_poweroff(struct exynos_dp_device *dp)
{
- struct exynos_dp_device *dp = display_to_dp(display);
-
if (dp->dpms_mode != DRM_MODE_DPMS_ON)
return;
@@ -1119,12 +1106,12 @@ static void exynos_dp_dpms(struct exynos_drm_display *display, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
- exynos_dp_poweron(display);
+ exynos_dp_poweron(dp);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- exynos_dp_poweroff(display);
+ exynos_dp_poweroff(dp);
break;
default:
break;
@@ -1241,7 +1228,7 @@ static int exynos_dp_bind(struct device *dev, struct device *master, void *data)
}
}
- if (!dp->panel) {
+ if (!dp->panel && !dp->bridge) {
ret = exynos_dp_dt_parse_panel(dp);
if (ret)
return ret;
@@ -1325,7 +1312,7 @@ static const struct component_ops exynos_dp_ops = {
static int exynos_dp_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
- struct device_node *panel_node;
+ struct device_node *panel_node, *bridge_node, *endpoint;
struct exynos_dp_device *dp;
int ret;
@@ -1351,6 +1338,18 @@ static int exynos_dp_probe(struct platform_device *pdev)
return -EPROBE_DEFER;
}
+ endpoint = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (endpoint) {
+ bridge_node = of_graph_get_remote_port_parent(endpoint);
+ if (bridge_node) {
+ dp->bridge = of_drm_find_bridge(bridge_node);
+ of_node_put(bridge_node);
+ if (!dp->bridge)
+ return -EPROBE_DEFER;
+ } else
+ return -EPROBE_DEFER;
+ }
+
ret = component_add(&pdev->dev, &exynos_dp_ops);
if (ret)
exynos_drm_component_del(&pdev->dev,
diff --git a/drivers/gpu/drm/exynos/exynos_dp_core.h b/drivers/gpu/drm/exynos/exynos_dp_core.h
index 164f171168e7..a4e799679669 100644
--- a/drivers/gpu/drm/exynos/exynos_dp_core.h
+++ b/drivers/gpu/drm/exynos/exynos_dp_core.h
@@ -153,6 +153,7 @@ struct exynos_dp_device {
struct drm_connector connector;
struct drm_encoder *encoder;
struct drm_panel *panel;
+ struct drm_bridge *bridge;
struct clk *clock;
unsigned int irq;
void __iomem *reg_base;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_buf.c b/drivers/gpu/drm/exynos/exynos_drm_buf.c
index 9c8088462c26..24994ba10e28 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_buf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_buf.c
@@ -63,11 +63,11 @@ static int lowlevel_buffer_allocate(struct drm_device *dev,
return -ENOMEM;
}
- buf->kvaddr = (void __iomem *)dma_alloc_attrs(dev->dev,
+ buf->cookie = dma_alloc_attrs(dev->dev,
buf->size,
&buf->dma_addr, GFP_KERNEL,
&buf->dma_attrs);
- if (!buf->kvaddr) {
+ if (!buf->cookie) {
DRM_ERROR("failed to allocate buffer.\n");
ret = -ENOMEM;
goto err_free;
@@ -132,7 +132,7 @@ static void lowlevel_buffer_deallocate(struct drm_device *dev,
buf->sgt = NULL;
if (!is_drm_iommu_supported(dev)) {
- dma_free_attrs(dev->dev, buf->size, buf->kvaddr,
+ dma_free_attrs(dev->dev, buf->size, buf->cookie,
(dma_addr_t)buf->dma_addr, &buf->dma_attrs);
drm_free_large(buf->pages);
} else
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.c b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
index 45026e693225..48ccab7fdf63 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.c
@@ -20,43 +20,9 @@
#include "exynos_drm_encoder.h"
#include "exynos_drm_plane.h"
-#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc,\
- drm_crtc)
-
-enum exynos_crtc_mode {
- CRTC_MODE_NORMAL, /* normal mode */
- CRTC_MODE_BLANK, /* The private plane of crtc is blank */
-};
-
-/*
- * Exynos specific crtc structure.
- *
- * @drm_crtc: crtc object.
- * @manager: the manager associated with this crtc
- * @pipe: a crtc index created at load() with a new crtc object creation
- * and the crtc object would be set to private->crtc array
- * to get a crtc object corresponding to this pipe from private->crtc
- * array when irq interrupt occurred. the reason of using this pipe is that
- * drm framework doesn't support multiple irq yet.
- * we can refer to the crtc to current hardware interrupt occurred through
- * this pipe value.
- * @dpms: store the crtc dpms value
- * @mode: store the crtc mode value
- */
-struct exynos_drm_crtc {
- struct drm_crtc drm_crtc;
- struct exynos_drm_manager *manager;
- unsigned int pipe;
- unsigned int dpms;
- enum exynos_crtc_mode mode;
- wait_queue_head_t pending_flip_queue;
- atomic_t pending_flip;
-};
-
static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct exynos_drm_manager *manager = exynos_crtc->manager;
DRM_DEBUG_KMS("crtc[%d] mode[%d]\n", crtc->base.id, mode);
@@ -74,8 +40,8 @@ static void exynos_drm_crtc_dpms(struct drm_crtc *crtc, int mode)
drm_crtc_vblank_off(crtc);
}
- if (manager->ops->dpms)
- manager->ops->dpms(manager, mode);
+ if (exynos_crtc->ops->dpms)
+ exynos_crtc->ops->dpms(exynos_crtc, mode);
exynos_crtc->dpms = mode;
@@ -91,16 +57,15 @@ static void exynos_drm_crtc_prepare(struct drm_crtc *crtc)
static void exynos_drm_crtc_commit(struct drm_crtc *crtc)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct exynos_drm_manager *manager = exynos_crtc->manager;
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(crtc->primary);
exynos_drm_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
- exynos_plane_commit(crtc->primary);
-
- if (manager->ops->commit)
- manager->ops->commit(manager);
+ if (exynos_crtc->ops->win_commit)
+ exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
- exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_ON);
+ if (exynos_crtc->ops->commit)
+ exynos_crtc->ops->commit(exynos_crtc);
}
static bool
@@ -109,10 +74,10 @@ exynos_drm_crtc_mode_fixup(struct drm_crtc *crtc,
struct drm_display_mode *adjusted_mode)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct exynos_drm_manager *manager = exynos_crtc->manager;
- if (manager->ops->mode_fixup)
- return manager->ops->mode_fixup(manager, mode, adjusted_mode);
+ if (exynos_crtc->ops->mode_fixup)
+ return exynos_crtc->ops->mode_fixup(exynos_crtc, mode,
+ adjusted_mode);
return true;
}
@@ -122,11 +87,10 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode, int x, int y,
struct drm_framebuffer *old_fb)
{
- struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- struct exynos_drm_manager *manager = exynos_crtc->manager;
struct drm_framebuffer *fb = crtc->primary->fb;
unsigned int crtc_w;
unsigned int crtc_h;
+ int ret;
/*
* copy the mode data adjusted by mode_fixup() into crtc->mode
@@ -134,24 +98,25 @@ exynos_drm_crtc_mode_set(struct drm_crtc *crtc, struct drm_display_mode *mode,
*/
memcpy(&crtc->mode, adjusted_mode, sizeof(*adjusted_mode));
+ ret = exynos_check_plane(crtc->primary, fb);
+ if (ret < 0)
+ return ret;
+
crtc_w = fb->width - x;
crtc_h = fb->height - y;
+ exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
+ crtc_w, crtc_h, x, y, crtc_w, crtc_h);
- if (manager->ops->mode_set)
- manager->ops->mode_set(manager, &crtc->mode);
-
- return exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
- crtc_w, crtc_h, x, y, crtc_w, crtc_h);
+ return 0;
}
-static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
+static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
struct drm_framebuffer *old_fb)
{
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct drm_framebuffer *fb = crtc->primary->fb;
unsigned int crtc_w;
unsigned int crtc_h;
- int ret;
/* when framebuffer changing is requested, crtc's dpms should be on */
if (exynos_crtc->dpms > DRM_MODE_DPMS_ON) {
@@ -162,20 +127,8 @@ static int exynos_drm_crtc_mode_set_commit(struct drm_crtc *crtc, int x, int y,
crtc_w = fb->width - x;
crtc_h = fb->height - y;
- ret = exynos_plane_mode_set(crtc->primary, crtc, fb, 0, 0,
- crtc_w, crtc_h, x, y, crtc_w, crtc_h);
- if (ret)
- return ret;
-
- exynos_drm_crtc_commit(crtc);
-
- return 0;
-}
-
-static int exynos_drm_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- return exynos_drm_crtc_mode_set_commit(crtc, x, y, old_fb);
+ return exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
+ crtc_w, crtc_h, x, y, crtc_w, crtc_h);
}
static void exynos_drm_crtc_disable(struct drm_crtc *crtc)
@@ -214,6 +167,7 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
struct exynos_drm_private *dev_priv = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
struct drm_framebuffer *old_fb = crtc->primary->fb;
+ unsigned int crtc_w, crtc_h;
int ret = -EINVAL;
/* when the page flip is requested, crtc's dpms should be on */
@@ -245,8 +199,11 @@ static int exynos_drm_crtc_page_flip(struct drm_crtc *crtc,
spin_unlock_irq(&dev->event_lock);
crtc->primary->fb = fb;
- ret = exynos_drm_crtc_mode_set_commit(crtc, crtc->x, crtc->y,
- NULL);
+ crtc_w = fb->width - crtc->x;
+ crtc_h = fb->height - crtc->y;
+ ret = exynos_update_plane(crtc->primary, crtc, fb, 0, 0,
+ crtc_w, crtc_h, crtc->x, crtc->y,
+ crtc_w, crtc_h);
if (ret) {
crtc->primary->fb = old_fb;
@@ -275,116 +232,61 @@ static void exynos_drm_crtc_destroy(struct drm_crtc *crtc)
kfree(exynos_crtc);
}
-static int exynos_drm_crtc_set_property(struct drm_crtc *crtc,
- struct drm_property *property,
- uint64_t val)
-{
- struct drm_device *dev = crtc->dev;
- struct exynos_drm_private *dev_priv = dev->dev_private;
- struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
-
- if (property == dev_priv->crtc_mode_property) {
- enum exynos_crtc_mode mode = val;
-
- if (mode == exynos_crtc->mode)
- return 0;
-
- exynos_crtc->mode = mode;
-
- switch (mode) {
- case CRTC_MODE_NORMAL:
- exynos_drm_crtc_commit(crtc);
- break;
- case CRTC_MODE_BLANK:
- exynos_plane_dpms(crtc->primary, DRM_MODE_DPMS_OFF);
- break;
- default:
- break;
- }
-
- return 0;
- }
-
- return -EINVAL;
-}
-
static struct drm_crtc_funcs exynos_crtc_funcs = {
.set_config = drm_crtc_helper_set_config,
.page_flip = exynos_drm_crtc_page_flip,
.destroy = exynos_drm_crtc_destroy,
- .set_property = exynos_drm_crtc_set_property,
-};
-
-static const struct drm_prop_enum_list mode_names[] = {
- { CRTC_MODE_NORMAL, "normal" },
- { CRTC_MODE_BLANK, "blank" },
};
-static void exynos_drm_crtc_attach_mode_property(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct exynos_drm_private *dev_priv = dev->dev_private;
- struct drm_property *prop;
-
- prop = dev_priv->crtc_mode_property;
- if (!prop) {
- prop = drm_property_create_enum(dev, 0, "mode", mode_names,
- ARRAY_SIZE(mode_names));
- if (!prop)
- return;
-
- dev_priv->crtc_mode_property = prop;
- }
-
- drm_object_attach_property(&crtc->base, prop, 0);
-}
-
-int exynos_drm_crtc_create(struct exynos_drm_manager *manager)
+struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+ int pipe,
+ enum exynos_drm_output_type type,
+ struct exynos_drm_crtc_ops *ops,
+ void *ctx)
{
struct exynos_drm_crtc *exynos_crtc;
struct drm_plane *plane;
- struct exynos_drm_private *private = manager->drm_dev->dev_private;
+ struct exynos_drm_private *private = drm_dev->dev_private;
struct drm_crtc *crtc;
int ret;
exynos_crtc = kzalloc(sizeof(*exynos_crtc), GFP_KERNEL);
if (!exynos_crtc)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
init_waitqueue_head(&exynos_crtc->pending_flip_queue);
atomic_set(&exynos_crtc->pending_flip, 0);
exynos_crtc->dpms = DRM_MODE_DPMS_OFF;
- exynos_crtc->manager = manager;
- exynos_crtc->pipe = manager->pipe;
- plane = exynos_plane_init(manager->drm_dev, 1 << manager->pipe,
+ exynos_crtc->pipe = pipe;
+ exynos_crtc->type = type;
+ exynos_crtc->ops = ops;
+ exynos_crtc->ctx = ctx;
+ plane = exynos_plane_init(drm_dev, 1 << pipe,
DRM_PLANE_TYPE_PRIMARY);
if (IS_ERR(plane)) {
ret = PTR_ERR(plane);
goto err_plane;
}
- manager->crtc = &exynos_crtc->drm_crtc;
- crtc = &exynos_crtc->drm_crtc;
+ crtc = &exynos_crtc->base;
- private->crtc[manager->pipe] = crtc;
+ private->crtc[pipe] = crtc;
- ret = drm_crtc_init_with_planes(manager->drm_dev, crtc, plane, NULL,
+ ret = drm_crtc_init_with_planes(drm_dev, crtc, plane, NULL,
&exynos_crtc_funcs);
if (ret < 0)
goto err_crtc;
drm_crtc_helper_add(crtc, &exynos_crtc_helper_funcs);
- exynos_drm_crtc_attach_mode_property(crtc);
-
- return 0;
+ return exynos_crtc;
err_crtc:
plane->funcs->destroy(plane);
err_plane:
kfree(exynos_crtc);
- return ret;
+ return ERR_PTR(ret);
}
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
@@ -392,13 +294,12 @@ int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe)
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);
- struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return -EPERM;
- if (manager->ops->enable_vblank)
- manager->ops->enable_vblank(manager);
+ if (exynos_crtc->ops->enable_vblank)
+ exynos_crtc->ops->enable_vblank(exynos_crtc);
return 0;
}
@@ -408,13 +309,12 @@ void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe)
struct exynos_drm_private *private = dev->dev_private;
struct exynos_drm_crtc *exynos_crtc =
to_exynos_crtc(private->crtc[pipe]);
- struct exynos_drm_manager *manager = exynos_crtc->manager;
if (exynos_crtc->dpms != DRM_MODE_DPMS_ON)
return;
- if (manager->ops->disable_vblank)
- manager->ops->disable_vblank(manager);
+ if (exynos_crtc->ops->disable_vblank)
+ exynos_crtc->ops->disable_vblank(exynos_crtc);
}
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
@@ -443,42 +343,9 @@ void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev->event_lock, flags);
}
-void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
- struct exynos_drm_overlay *overlay)
-{
- struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
- if (manager->ops->win_mode_set)
- manager->ops->win_mode_set(manager, overlay);
-}
-
-void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos)
-{
- struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
- if (manager->ops->win_commit)
- manager->ops->win_commit(manager, zpos);
-}
-
-void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos)
-{
- struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
- if (manager->ops->win_enable)
- manager->ops->win_enable(manager, zpos);
-}
-
-void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos)
-{
- struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
-
- if (manager->ops->win_disable)
- manager->ops->win_disable(manager, zpos);
-}
-
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
{
- struct exynos_drm_manager *manager;
+ struct exynos_drm_crtc *exynos_crtc;
struct drm_device *dev = fb->dev;
struct drm_crtc *crtc;
@@ -487,15 +354,15 @@ void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb)
* for all encoders.
*/
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
- manager = to_exynos_crtc(crtc)->manager;
+ exynos_crtc = to_exynos_crtc(crtc);
/*
* wait for vblank interrupt
* - this makes sure that overlay data are updated to
* real hardware.
*/
- if (manager->ops->wait_for_vblank)
- manager->ops->wait_for_vblank(manager);
+ if (exynos_crtc->ops->wait_for_vblank)
+ exynos_crtc->ops->wait_for_vblank(exynos_crtc);
}
}
@@ -508,8 +375,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
struct exynos_drm_crtc *exynos_crtc;
exynos_crtc = to_exynos_crtc(crtc);
- if (exynos_crtc->manager->type == out_type)
- return exynos_crtc->manager->pipe;
+ if (exynos_crtc->type == out_type)
+ return exynos_crtc->pipe;
}
return -EPERM;
@@ -517,8 +384,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
{
- struct exynos_drm_manager *manager = to_exynos_crtc(crtc)->manager;
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
- if (manager->ops->te_handler)
- manager->ops->te_handler(manager);
+ if (exynos_crtc->ops->te_handler)
+ exynos_crtc->ops->te_handler(exynos_crtc);
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_crtc.h b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
index e353d353836f..6258b800aab8 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_crtc.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_crtc.h
@@ -17,14 +17,18 @@
#include "exynos_drm_drv.h"
-int exynos_drm_crtc_create(struct exynos_drm_manager *manager);
+struct exynos_drm_crtc *exynos_drm_crtc_create(struct drm_device *drm_dev,
+ int pipe,
+ enum exynos_drm_output_type type,
+ struct exynos_drm_crtc_ops *ops,
+ void *context);
int exynos_drm_crtc_enable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_disable_vblank(struct drm_device *dev, int pipe);
void exynos_drm_crtc_finish_pageflip(struct drm_device *dev, int pipe);
void exynos_drm_crtc_complete_scanout(struct drm_framebuffer *fb);
void exynos_drm_crtc_plane_mode_set(struct drm_crtc *crtc,
- struct exynos_drm_overlay *overlay);
+ struct exynos_drm_plane *plane);
void exynos_drm_crtc_plane_commit(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_enable(struct drm_crtc *crtc, int zpos);
void exynos_drm_crtc_plane_disable(struct drm_crtc *crtc, int zpos);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
index 60192ed544f0..3833bf8ca025 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.c
@@ -279,7 +279,3 @@ err_buf_detach:
return ERR_PTR(ret);
}
-
-MODULE_AUTHOR("Inki Dae <inki.dae@samsung.com>");
-MODULE_DESCRIPTION("Samsung SoC DRM DMABUF Module");
-MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
index 49acfafb4fdb..886de9ff484d 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_dmabuf.h
@@ -12,14 +12,9 @@
#ifndef _EXYNOS_DRM_DMABUF_H_
#define _EXYNOS_DRM_DMABUF_H_
-#ifdef CONFIG_DRM_EXYNOS_DMABUF
struct dma_buf *exynos_dmabuf_prime_export(struct drm_device *drm_dev,
struct drm_gem_object *obj, int flags);
struct drm_gem_object *exynos_dmabuf_prime_import(struct drm_device *drm_dev,
struct dma_buf *dma_buf);
-#else
-#define exynos_dmabuf_prime_export NULL
-#define exynos_dmabuf_prime_import NULL
-#endif
#endif
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.c b/drivers/gpu/drm/exynos/exynos_drm_drv.c
index 1bcbe07cecfc..90168d7cf66a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.c
@@ -556,6 +556,9 @@ static struct platform_driver *const exynos_drm_kms_drivers[] = {
#ifdef CONFIG_DRM_EXYNOS_FIMD
&fimd_driver,
#endif
+#ifdef CONFIG_DRM_EXYNOS7_DECON
+ &decon_driver,
+#endif
#ifdef CONFIG_DRM_EXYNOS_DP
&dp_driver,
#endif
@@ -612,6 +615,7 @@ static const char * const strings[] = {
"samsung,exynos3",
"samsung,exynos4",
"samsung,exynos5",
+ "samsung,exynos7",
};
static struct platform_driver exynos_drm_platform_driver = {
diff --git a/drivers/gpu/drm/exynos/exynos_drm_drv.h b/drivers/gpu/drm/exynos/exynos_drm_drv.h
index 2e5063488c50..9afd390d4674 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_drv.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_drv.h
@@ -23,6 +23,9 @@
#define MAX_FB_BUFFER 4
#define DEFAULT_ZPOS -1
+#define to_exynos_crtc(x) container_of(x, struct exynos_drm_crtc, base)
+#define to_exynos_plane(x) container_of(x, struct exynos_drm_plane, base)
+
/* This enumerates device type. */
enum exynos_drm_device_type {
EXYNOS_DEVICE_TYPE_NONE,
@@ -44,6 +47,7 @@ enum exynos_drm_output_type {
/*
* Exynos drm common overlay structure.
*
+ * @base: plane object
* @fb_x: offset x on a framebuffer to be displayed.
* - the unit is screen coordinates.
* @fb_y: offset y on a framebuffer to be displayed.
@@ -73,11 +77,14 @@ enum exynos_drm_output_type {
* @local_path: in case of lcd type, local path mode on or off.
* @transparency: transparency on or off.
* @activated: activated or not.
+ * @enabled: enabled or not.
*
* this structure is common to exynos SoC and its contents would be copied
* to hardware specific overlay info.
*/
-struct exynos_drm_overlay {
+
+struct exynos_drm_plane {
+ struct drm_plane base;
unsigned int fb_x;
unsigned int fb_y;
unsigned int fb_width;
@@ -104,6 +111,7 @@ struct exynos_drm_overlay {
bool local_path:1;
bool transparency:1;
bool activated:1;
+ bool enabled:1;
};
/*
@@ -155,11 +163,10 @@ struct exynos_drm_display {
};
/*
- * Exynos drm manager ops
+ * Exynos drm crtc ops
*
* @dpms: control device power.
* @mode_fixup: fix mode data before applying it
- * @mode_set: set the given mode to the manager
* @commit: set current hw specific display mode to hw.
* @enable_vblank: specific driver callback for enabling vblank interrupt.
* @disable_vblank: specific driver callback for disabling vblank interrupt.
@@ -172,44 +179,49 @@ struct exynos_drm_display {
* @te_handler: trigger to transfer video image at the tearing effect
* synchronization signal if there is a page flip request.
*/
-struct exynos_drm_manager;
-struct exynos_drm_manager_ops {
- void (*dpms)(struct exynos_drm_manager *mgr, int mode);
- bool (*mode_fixup)(struct exynos_drm_manager *mgr,
+struct exynos_drm_crtc;
+struct exynos_drm_crtc_ops {
+ void (*dpms)(struct exynos_drm_crtc *crtc, int mode);
+ bool (*mode_fixup)(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode);
- void (*mode_set)(struct exynos_drm_manager *mgr,
- const struct drm_display_mode *mode);
- void (*commit)(struct exynos_drm_manager *mgr);
- int (*enable_vblank)(struct exynos_drm_manager *mgr);
- void (*disable_vblank)(struct exynos_drm_manager *mgr);
- void (*wait_for_vblank)(struct exynos_drm_manager *mgr);
- void (*win_mode_set)(struct exynos_drm_manager *mgr,
- struct exynos_drm_overlay *overlay);
- void (*win_commit)(struct exynos_drm_manager *mgr, int zpos);
- void (*win_enable)(struct exynos_drm_manager *mgr, int zpos);
- void (*win_disable)(struct exynos_drm_manager *mgr, int zpos);
- void (*te_handler)(struct exynos_drm_manager *mgr);
+ void (*commit)(struct exynos_drm_crtc *crtc);
+ int (*enable_vblank)(struct exynos_drm_crtc *crtc);
+ void (*disable_vblank)(struct exynos_drm_crtc *crtc);
+ void (*wait_for_vblank)(struct exynos_drm_crtc *crtc);
+ void (*win_mode_set)(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane);
+ void (*win_commit)(struct exynos_drm_crtc *crtc, int zpos);
+ void (*win_enable)(struct exynos_drm_crtc *crtc, int zpos);
+ void (*win_disable)(struct exynos_drm_crtc *crtc, int zpos);
+ void (*te_handler)(struct exynos_drm_crtc *crtc);
};
/*
- * Exynos drm common manager structure, maps 1:1 with a crtc
+ * Exynos specific crtc structure.
*
- * @list: the list entry for this manager
+ * @base: crtc object.
* @type: one of EXYNOS_DISPLAY_TYPE_LCD and HDMI.
- * @drm_dev: pointer to the drm device
- * @crtc: crtc object.
- * @pipe: the pipe number for this crtc/manager
+ * @pipe: a crtc index created at load() with a new crtc object creation
+ * and the crtc object would be set to private->crtc array
+ * to get a crtc object corresponding to this pipe from private->crtc
+ * array when irq interrupt occurred. the reason of using this pipe is that
+ * drm framework doesn't support multiple irq yet.
+ * we can refer to the crtc to current hardware interrupt occurred through
+ * this pipe value.
+ * @dpms: store the crtc dpms value
* @ops: pointer to callbacks for exynos drm specific functionality
- * @ctx: A pointer to the manager's implementation specific context
+ * @ctx: A pointer to the crtc's implementation specific context
*/
-struct exynos_drm_manager {
- struct list_head list;
- enum exynos_drm_output_type type;
- struct drm_device *drm_dev;
- struct drm_crtc *crtc;
- int pipe;
- struct exynos_drm_manager_ops *ops;
+struct exynos_drm_crtc {
+ struct drm_crtc base;
+ enum exynos_drm_output_type type;
+ unsigned int pipe;
+ unsigned int dpms;
+ wait_queue_head_t pending_flip_queue;
+ atomic_t pending_flip;
+ struct exynos_drm_crtc_ops *ops;
+ void *ctx;
};
struct exynos_drm_g2d_private {
@@ -246,7 +258,6 @@ struct exynos_drm_private {
*/
struct drm_crtc *crtc[MAX_CRTC];
struct drm_property *plane_zpos_property;
- struct drm_property *crtc_mode_property;
unsigned long da_start;
unsigned long da_space_size;
@@ -333,6 +344,7 @@ void exynos_drm_component_del(struct device *dev,
enum exynos_drm_device_type dev_type);
extern struct platform_driver fimd_driver;
+extern struct platform_driver decon_driver;
extern struct platform_driver dp_driver;
extern struct platform_driver dsi_driver;
extern struct platform_driver mixer_driver;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_encoder.c b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
index 7e282e3d6038..57de0bdc5a3b 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_encoder.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_encoder.c
@@ -102,7 +102,7 @@ static void exynos_drm_encoder_disable(struct drm_encoder *encoder)
/* all planes connected to this encoder should be also disabled. */
drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
- if (plane->crtc == encoder->crtc)
+ if (plane->crtc && (plane->crtc == encoder->crtc))
plane->funcs->disable_plane(plane);
}
}
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
index e12ea90c6237..84f8dfe1c5ec 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fbdev.c
@@ -79,9 +79,9 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
struct drm_framebuffer *fb)
{
struct fb_info *fbi = helper->fbdev;
- struct drm_device *dev = helper->dev;
struct exynos_drm_gem_buf *buffer;
unsigned int size = fb->width * fb->height * (fb->bits_per_pixel >> 3);
+ unsigned int nr_pages;
unsigned long offset;
drm_fb_helper_fill_fix(fbi, fb->pitches[0], fb->depth);
@@ -94,25 +94,14 @@ static int exynos_drm_fbdev_update(struct drm_fb_helper *helper,
return -EFAULT;
}
- /* map pages with kernel virtual space. */
+ nr_pages = buffer->size >> PAGE_SHIFT;
+
+ buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
+ nr_pages, VM_MAP,
+ pgprot_writecombine(PAGE_KERNEL));
if (!buffer->kvaddr) {
- if (is_drm_iommu_supported(dev)) {
- unsigned int nr_pages = buffer->size >> PAGE_SHIFT;
-
- buffer->kvaddr = (void __iomem *) vmap(buffer->pages,
- nr_pages, VM_MAP,
- pgprot_writecombine(PAGE_KERNEL));
- } else {
- phys_addr_t dma_addr = buffer->dma_addr;
- if (dma_addr)
- buffer->kvaddr = (void __iomem *)phys_to_virt(dma_addr);
- else
- buffer->kvaddr = (void __iomem *)NULL;
- }
- if (!buffer->kvaddr) {
- DRM_ERROR("failed to map pages to kernel space.\n");
- return -EIO;
- }
+ DRM_ERROR("failed to map pages to kernel space.\n");
+ return -EIO;
}
/* buffer count to framebuffer always is 1 at booting time. */
@@ -313,7 +302,7 @@ static void exynos_drm_fbdev_destroy(struct drm_device *dev,
struct exynos_drm_gem_obj *exynos_gem_obj = exynos_fbd->exynos_gem_obj;
struct drm_framebuffer *fb;
- if (is_drm_iommu_supported(dev) && exynos_gem_obj->buffer->kvaddr)
+ if (exynos_gem_obj->buffer->kvaddr)
vunmap(exynos_gem_obj->buffer->kvaddr);
/* release drm framebuffer and real buffer */
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 835b6af00970..842d6b8dc3c4 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -461,7 +461,6 @@ static int fimc_src_set_fmt_order(struct fimc_context *ctx, u32 fmt)
cfg |= EXYNOS_MSCTRL_C_INT_IN_3PLANE;
break;
case DRM_FORMAT_NV12:
- case DRM_FORMAT_NV12MT:
case DRM_FORMAT_NV16:
cfg |= (EXYNOS_MSCTRL_ORDER2P_LSB_CBCR |
EXYNOS_MSCTRL_C_INT_IN_2PLANE);
@@ -511,7 +510,6 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt)
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV12:
case DRM_FORMAT_NV21:
- case DRM_FORMAT_NV12MT:
cfg |= EXYNOS_MSCTRL_INFORMAT_YCBCR420;
break;
default:
@@ -524,10 +522,7 @@ static int fimc_src_set_fmt(struct device *dev, u32 fmt)
cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
cfg &= ~EXYNOS_CIDMAPARAM_R_MODE_MASK;
- if (fmt == DRM_FORMAT_NV12MT)
- cfg |= EXYNOS_CIDMAPARAM_R_MODE_64X32;
- else
- cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
+ cfg |= EXYNOS_CIDMAPARAM_R_MODE_LINEAR;
fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
@@ -812,7 +807,6 @@ static int fimc_dst_set_fmt_order(struct fimc_context *ctx, u32 fmt)
cfg |= EXYNOS_CIOCTRL_YCBCR_3PLANE;
break;
case DRM_FORMAT_NV12:
- case DRM_FORMAT_NV12MT:
case DRM_FORMAT_NV16:
cfg |= EXYNOS_CIOCTRL_ORDER2P_LSB_CBCR;
cfg |= EXYNOS_CIOCTRL_YCBCR_2PLANE;
@@ -867,7 +861,6 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
case DRM_FORMAT_YUV420:
case DRM_FORMAT_YVU420:
case DRM_FORMAT_NV12:
- case DRM_FORMAT_NV12MT:
case DRM_FORMAT_NV21:
cfg |= EXYNOS_CITRGFMT_OUTFORMAT_YCBCR420;
break;
@@ -883,10 +876,7 @@ static int fimc_dst_set_fmt(struct device *dev, u32 fmt)
cfg = fimc_read(ctx, EXYNOS_CIDMAPARAM);
cfg &= ~EXYNOS_CIDMAPARAM_W_MODE_MASK;
- if (fmt == DRM_FORMAT_NV12MT)
- cfg |= EXYNOS_CIDMAPARAM_W_MODE_64X32;
- else
- cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
+ cfg |= EXYNOS_CIDMAPARAM_W_MODE_LINEAR;
fimc_write(ctx, cfg, EXYNOS_CIDMAPARAM);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimd.c b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
index e5810d13bf9c..925fc69af1a0 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimd.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimd.c
@@ -157,14 +157,13 @@ struct fimd_win_data {
};
struct fimd_context {
- struct exynos_drm_manager manager;
struct device *dev;
struct drm_device *drm_dev;
+ struct exynos_drm_crtc *crtc;
struct clk *bus_clk;
struct clk *lcd_clk;
void __iomem *regs;
struct regmap *sysreg;
- struct drm_display_mode mode;
struct fimd_win_data win_data[WINDOWS_NR];
unsigned int default_win;
unsigned long irq_flags;
@@ -185,11 +184,6 @@ struct fimd_context {
struct exynos_drm_display *display;
};
-static inline struct fimd_context *mgr_to_fimd(struct exynos_drm_manager *mgr)
-{
- return container_of(mgr, struct fimd_context, manager);
-}
-
static const struct of_device_id fimd_driver_dt_match[] = {
{ .compatible = "samsung,s3c6400-fimd",
.data = &s3c64xx_fimd_driver_data },
@@ -214,9 +208,9 @@ static inline struct fimd_driver_data *drm_fimd_get_driver_data(
return (struct fimd_driver_data *)of_id->data;
}
-static void fimd_wait_for_vblank(struct exynos_drm_manager *mgr)
+static void fimd_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
if (ctx->suspended)
return;
@@ -259,9 +253,8 @@ static void fimd_enable_shadow_channel_path(struct fimd_context *ctx, int win,
writel(val, ctx->regs + SHADOWCON);
}
-static void fimd_clear_channel(struct exynos_drm_manager *mgr)
+static void fimd_clear_channel(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
int win, ch_enabled = 0;
DRM_DEBUG_KMS("%s\n", __FILE__);
@@ -286,38 +279,42 @@ static void fimd_clear_channel(struct exynos_drm_manager *mgr)
unsigned int state = ctx->suspended;
ctx->suspended = 0;
- fimd_wait_for_vblank(mgr);
+ fimd_wait_for_vblank(ctx->crtc);
ctx->suspended = state;
}
}
-static int fimd_mgr_initialize(struct exynos_drm_manager *mgr,
+static int fimd_ctx_initialize(struct fimd_context *ctx,
struct drm_device *drm_dev)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
struct exynos_drm_private *priv;
priv = drm_dev->dev_private;
- mgr->drm_dev = ctx->drm_dev = drm_dev;
- mgr->pipe = ctx->pipe = priv->pipe++;
+ ctx->drm_dev = drm_dev;
+ ctx->pipe = priv->pipe++;
/* attach this sub driver to iommu mapping if supported. */
if (is_drm_iommu_supported(ctx->drm_dev)) {
+ int ret;
+
/*
* If any channel is already active, iommu will throw
* a PAGE FAULT when enabled. So clear any channel if enabled.
*/
- fimd_clear_channel(mgr);
- drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
+ fimd_clear_channel(ctx);
+ ret = drm_iommu_attach_device(ctx->drm_dev, ctx->dev);
+ if (ret) {
+ DRM_ERROR("drm_iommu_attach failed.\n");
+ return ret;
+ }
+
}
return 0;
}
-static void fimd_mgr_remove(struct exynos_drm_manager *mgr)
+static void fimd_ctx_remove(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
-
/* detach this sub driver from iommu mapping if supported. */
if (is_drm_iommu_supported(ctx->drm_dev))
drm_iommu_detach_device(ctx->drm_dev, ctx->dev);
@@ -343,7 +340,7 @@ static u32 fimd_calc_clkdiv(struct fimd_context *ctx,
return (clkdiv < 0x100) ? clkdiv : 0xff;
}
-static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
+static bool fimd_mode_fixup(struct exynos_drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
@@ -353,18 +350,10 @@ static bool fimd_mode_fixup(struct exynos_drm_manager *mgr,
return true;
}
-static void fimd_mode_set(struct exynos_drm_manager *mgr,
- const struct drm_display_mode *in_mode)
-{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
-
- drm_mode_copy(&ctx->mode, in_mode);
-}
-
-static void fimd_commit(struct exynos_drm_manager *mgr)
+static void fimd_commit(struct exynos_drm_crtc *crtc)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
- struct drm_display_mode *mode = &ctx->mode;
+ struct fimd_context *ctx = crtc->ctx;
+ struct drm_display_mode *mode = &crtc->base.mode;
struct fimd_driver_data *driver_data = ctx->driver_data;
void *timing_base = ctx->regs + driver_data->timing_base;
u32 val, clkdiv;
@@ -461,9 +450,9 @@ static void fimd_commit(struct exynos_drm_manager *mgr)
writel(val, ctx->regs + VIDCON0);
}
-static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
+static int fimd_enable_vblank(struct exynos_drm_crtc *crtc)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
u32 val;
if (ctx->suspended)
@@ -493,9 +482,9 @@ static int fimd_enable_vblank(struct exynos_drm_manager *mgr)
return 0;
}
-static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
+static void fimd_disable_vblank(struct exynos_drm_crtc *crtc)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
u32 val;
if (ctx->suspended)
@@ -517,45 +506,45 @@ static void fimd_disable_vblank(struct exynos_drm_manager *mgr)
}
}
-static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
- struct exynos_drm_overlay *overlay)
+static void fimd_win_mode_set(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data;
int win;
unsigned long offset;
- if (!overlay) {
- DRM_ERROR("overlay is NULL\n");
+ if (!plane) {
+ DRM_ERROR("plane is NULL\n");
return;
}
- win = overlay->zpos;
+ win = plane->zpos;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win >= WINDOWS_NR)
return;
- offset = overlay->fb_x * (overlay->bpp >> 3);
- offset += overlay->fb_y * overlay->pitch;
+ offset = plane->fb_x * (plane->bpp >> 3);
+ offset += plane->fb_y * plane->pitch;
- DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+ DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
win_data = &ctx->win_data[win];
- win_data->offset_x = overlay->crtc_x;
- win_data->offset_y = overlay->crtc_y;
- win_data->ovl_width = overlay->crtc_width;
- win_data->ovl_height = overlay->crtc_height;
- win_data->fb_width = overlay->fb_width;
- win_data->fb_height = overlay->fb_height;
- win_data->dma_addr = overlay->dma_addr[0] + offset;
- win_data->bpp = overlay->bpp;
- win_data->pixel_format = overlay->pixel_format;
- win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
- (overlay->bpp >> 3);
- win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+ win_data->offset_x = plane->crtc_x;
+ win_data->offset_y = plane->crtc_y;
+ win_data->ovl_width = plane->crtc_width;
+ win_data->ovl_height = plane->crtc_height;
+ win_data->fb_width = plane->fb_width;
+ win_data->fb_height = plane->fb_height;
+ win_data->dma_addr = plane->dma_addr[0] + offset;
+ win_data->bpp = plane->bpp;
+ win_data->pixel_format = plane->pixel_format;
+ win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
+ (plane->bpp >> 3);
+ win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
DRM_DEBUG_KMS("offset_x = %d, offset_y = %d\n",
win_data->offset_x, win_data->offset_y);
@@ -563,7 +552,7 @@ static void fimd_win_mode_set(struct exynos_drm_manager *mgr,
win_data->ovl_width, win_data->ovl_height);
DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
- overlay->fb_width, overlay->crtc_width);
+ plane->fb_width, plane->crtc_width);
}
static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
@@ -623,8 +612,8 @@ static void fimd_win_set_pixfmt(struct fimd_context *ctx, unsigned int win)
/*
* In case of exynos, setting dma-burst to 16Word causes permanent
* tearing for very small buffers, e.g. cursor buffer. Burst Mode
- * switching which is based on overlay size is not recommended as
- * overlay size varies alot towards the end of the screen and rapid
+ * switching which is based on plane size is not recommended as
+ * plane size varies alot towards the end of the screen and rapid
* movement causes unstable DMA which results into iommu crash/tear.
*/
@@ -676,9 +665,9 @@ static void fimd_shadow_protect_win(struct fimd_context *ctx,
writel(val, ctx->regs + reg);
}
-static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
+static void fimd_win_commit(struct exynos_drm_crtc *crtc, int zpos)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data;
int win = zpos;
unsigned long val, alpha, size;
@@ -799,9 +788,9 @@ static void fimd_win_commit(struct exynos_drm_manager *mgr, int zpos)
atomic_set(&ctx->win_updated, 1);
}
-static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
+static void fimd_win_disable(struct exynos_drm_crtc *crtc, int zpos)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
struct fimd_win_data *win_data;
int win = zpos;
@@ -833,9 +822,8 @@ static void fimd_win_disable(struct exynos_drm_manager *mgr, int zpos)
win_data->enabled = false;
}
-static void fimd_window_suspend(struct exynos_drm_manager *mgr)
+static void fimd_window_suspend(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
struct fimd_win_data *win_data;
int i;
@@ -843,13 +831,12 @@ static void fimd_window_suspend(struct exynos_drm_manager *mgr)
win_data = &ctx->win_data[i];
win_data->resume = win_data->enabled;
if (win_data->enabled)
- fimd_win_disable(mgr, i);
+ fimd_win_disable(ctx->crtc, i);
}
}
-static void fimd_window_resume(struct exynos_drm_manager *mgr)
+static void fimd_window_resume(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
struct fimd_win_data *win_data;
int i;
@@ -860,26 +847,24 @@ static void fimd_window_resume(struct exynos_drm_manager *mgr)
}
}
-static void fimd_apply(struct exynos_drm_manager *mgr)
+static void fimd_apply(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
struct fimd_win_data *win_data;
int i;
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
if (win_data->enabled)
- fimd_win_commit(mgr, i);
+ fimd_win_commit(ctx->crtc, i);
else
- fimd_win_disable(mgr, i);
+ fimd_win_disable(ctx->crtc, i);
}
- fimd_commit(mgr);
+ fimd_commit(ctx->crtc);
}
-static int fimd_poweron(struct exynos_drm_manager *mgr)
+static int fimd_poweron(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
int ret;
if (!ctx->suspended)
@@ -903,16 +888,16 @@ static int fimd_poweron(struct exynos_drm_manager *mgr)
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags)) {
- ret = fimd_enable_vblank(mgr);
+ ret = fimd_enable_vblank(ctx->crtc);
if (ret) {
DRM_ERROR("Failed to re-enable vblank [%d]\n", ret);
goto enable_vblank_err;
}
}
- fimd_window_resume(mgr);
+ fimd_window_resume(ctx);
- fimd_apply(mgr);
+ fimd_apply(ctx);
return 0;
@@ -925,10 +910,8 @@ bus_clk_err:
return ret;
}
-static int fimd_poweroff(struct exynos_drm_manager *mgr)
+static int fimd_poweroff(struct fimd_context *ctx)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
-
if (ctx->suspended)
return 0;
@@ -937,7 +920,7 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
* suspend that connector. Otherwise we might try to scan from
* a destroyed buffer later.
*/
- fimd_window_suspend(mgr);
+ fimd_window_suspend(ctx);
clk_disable_unprepare(ctx->lcd_clk);
clk_disable_unprepare(ctx->bus_clk);
@@ -948,18 +931,18 @@ static int fimd_poweroff(struct exynos_drm_manager *mgr)
return 0;
}
-static void fimd_dpms(struct exynos_drm_manager *mgr, int mode)
+static void fimd_dpms(struct exynos_drm_crtc *crtc, int mode)
{
DRM_DEBUG_KMS("%s, %d\n", __FILE__, mode);
switch (mode) {
case DRM_MODE_DPMS_ON:
- fimd_poweron(mgr);
+ fimd_poweron(crtc->ctx);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- fimd_poweroff(mgr);
+ fimd_poweroff(crtc->ctx);
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -996,9 +979,9 @@ static void fimd_trigger(struct device *dev)
atomic_set(&ctx->triggering, 0);
}
-static void fimd_te_handler(struct exynos_drm_manager *mgr)
+static void fimd_te_handler(struct exynos_drm_crtc *crtc)
{
- struct fimd_context *ctx = mgr_to_fimd(mgr);
+ struct fimd_context *ctx = crtc->ctx;
/* Checks the crtc is detached already from encoder */
if (ctx->pipe < 0 || !ctx->drm_dev)
@@ -1021,10 +1004,9 @@ static void fimd_te_handler(struct exynos_drm_manager *mgr)
drm_handle_vblank(ctx->drm_dev, ctx->pipe);
}
-static struct exynos_drm_manager_ops fimd_manager_ops = {
+static struct exynos_drm_crtc_ops fimd_crtc_ops = {
.dpms = fimd_dpms,
.mode_fixup = fimd_mode_fixup,
- .mode_set = fimd_mode_set,
.commit = fimd_commit,
.enable_vblank = fimd_enable_vblank,
.disable_vblank = fimd_disable_vblank,
@@ -1074,9 +1056,22 @@ static int fimd_bind(struct device *dev, struct device *master, void *data)
{
struct fimd_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
+ int ret;
+
+ ret = fimd_ctx_initialize(ctx, drm_dev);
+ if (ret) {
+ DRM_ERROR("fimd_ctx_initialize failed.\n");
+ return ret;
+ }
+
+ ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+ EXYNOS_DISPLAY_TYPE_LCD,
+ &fimd_crtc_ops, ctx);
+ if (IS_ERR(ctx->crtc)) {
+ fimd_ctx_remove(ctx);
+ return PTR_ERR(ctx->crtc);
+ }
- fimd_mgr_initialize(&ctx->manager, drm_dev);
- exynos_drm_crtc_create(&ctx->manager);
if (ctx->display)
exynos_drm_create_enc_conn(drm_dev, ctx->display);
@@ -1089,12 +1084,12 @@ static void fimd_unbind(struct device *dev, struct device *master,
{
struct fimd_context *ctx = dev_get_drvdata(dev);
- fimd_dpms(&ctx->manager, DRM_MODE_DPMS_OFF);
+ fimd_dpms(ctx->crtc, DRM_MODE_DPMS_OFF);
if (ctx->display)
exynos_dpi_remove(ctx->display);
- fimd_mgr_remove(&ctx->manager);
+ fimd_ctx_remove(ctx);
}
static const struct component_ops fimd_component_ops = {
@@ -1108,7 +1103,7 @@ static int fimd_probe(struct platform_device *pdev)
struct fimd_context *ctx;
struct device_node *i80_if_timings;
struct resource *res;
- int ret = -EINVAL;
+ int ret;
if (!dev->of_node)
return -ENODEV;
@@ -1117,11 +1112,8 @@ static int fimd_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ctx->manager.type = EXYNOS_DISPLAY_TYPE_LCD;
- ctx->manager.ops = &fimd_manager_ops;
-
ret = exynos_drm_component_add(dev, EXYNOS_DEVICE_TYPE_CRTC,
- ctx->manager.type);
+ EXYNOS_DISPLAY_TYPE_LCD);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gem.h b/drivers/gpu/drm/exynos/exynos_drm_gem.h
index ec58fe9c40df..308173cb4f0a 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gem.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_gem.h
@@ -22,6 +22,7 @@
/*
* exynos drm gem buffer structure.
*
+ * @cookie: cookie returned by dma_alloc_attrs
* @kvaddr: kernel virtual address to allocated memory region.
* *userptr: user space address.
* @dma_addr: bus address(accessed by dma) to allocated memory region.
@@ -35,6 +36,7 @@
* VM_PFNMAP or not.
*/
struct exynos_drm_gem_buf {
+ void *cookie;
void __iomem *kvaddr;
unsigned long userptr;
dma_addr_t dma_addr;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index 0261468c8019..8040ed2a831f 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -542,9 +542,6 @@ static int gsc_src_set_fmt(struct device *dev, u32 fmt)
cfg |= (GSC_IN_CHROMA_ORDER_CBCR |
GSC_IN_YUV420_2P);
break;
- case DRM_FORMAT_NV12MT:
- cfg |= (GSC_IN_TILE_C_16x8 | GSC_IN_TILE_MODE);
- break;
default:
dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
return -EINVAL;
@@ -809,9 +806,6 @@ static int gsc_dst_set_fmt(struct device *dev, u32 fmt)
cfg |= (GSC_OUT_CHROMA_ORDER_CBCR |
GSC_OUT_YUV420_2P);
break;
- case DRM_FORMAT_NV12MT:
- cfg |= (GSC_OUT_TILE_C_16x8 | GSC_OUT_TILE_MODE);
- break;
default:
dev_err(ippdrv->dev, "inavlid target yuv order 0x%x.\n", fmt);
return -EINVAL;
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.c b/drivers/gpu/drm/exynos/exynos_drm_plane.c
index c7045a663763..a5616872eee7 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.c
@@ -12,25 +12,17 @@
#include <drm/drmP.h>
#include <drm/exynos_drm.h>
+#include <drm/drm_plane_helper.h>
#include "exynos_drm_drv.h"
#include "exynos_drm_crtc.h"
#include "exynos_drm_fb.h"
#include "exynos_drm_gem.h"
#include "exynos_drm_plane.h"
-#define to_exynos_plane(x) container_of(x, struct exynos_plane, base)
-
-struct exynos_plane {
- struct drm_plane base;
- struct exynos_drm_overlay overlay;
- bool enabled;
-};
-
static const uint32_t formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_ARGB8888,
DRM_FORMAT_NV12,
- DRM_FORMAT_NV12MT,
};
/*
@@ -69,16 +61,9 @@ static int exynos_plane_get_size(int start, unsigned length, unsigned last)
return size;
}
-int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h)
+int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb)
{
- struct exynos_plane *exynos_plane = to_exynos_plane(plane);
- struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
- unsigned int actual_w;
- unsigned int actual_h;
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
int nr;
int i;
@@ -91,12 +76,26 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
return -EFAULT;
}
- overlay->dma_addr[i] = buffer->dma_addr;
+ exynos_plane->dma_addr[i] = buffer->dma_addr;
DRM_DEBUG_KMS("buffer: %d, dma_addr = 0x%lx\n",
- i, (unsigned long)overlay->dma_addr[i]);
+ i, (unsigned long)exynos_plane->dma_addr[i]);
}
+ return 0;
+}
+
+void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h)
+{
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ unsigned int actual_w;
+ unsigned int actual_h;
+
actual_w = exynos_plane_get_size(crtc_x, crtc_w, crtc->mode.hdisplay);
actual_h = exynos_plane_get_size(crtc_y, crtc_h, crtc->mode.vdisplay);
@@ -113,98 +112,79 @@ int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
}
/* set drm framebuffer data. */
- overlay->fb_x = src_x;
- overlay->fb_y = src_y;
- overlay->fb_width = fb->width;
- overlay->fb_height = fb->height;
- overlay->src_width = src_w;
- overlay->src_height = src_h;
- overlay->bpp = fb->bits_per_pixel;
- overlay->pitch = fb->pitches[0];
- overlay->pixel_format = fb->pixel_format;
-
- /* set overlay range to be displayed. */
- overlay->crtc_x = crtc_x;
- overlay->crtc_y = crtc_y;
- overlay->crtc_width = actual_w;
- overlay->crtc_height = actual_h;
+ exynos_plane->fb_x = src_x;
+ exynos_plane->fb_y = src_y;
+ exynos_plane->fb_width = fb->width;
+ exynos_plane->fb_height = fb->height;
+ exynos_plane->src_width = src_w;
+ exynos_plane->src_height = src_h;
+ exynos_plane->bpp = fb->bits_per_pixel;
+ exynos_plane->pitch = fb->pitches[0];
+ exynos_plane->pixel_format = fb->pixel_format;
+
+ /* set plane range to be displayed. */
+ exynos_plane->crtc_x = crtc_x;
+ exynos_plane->crtc_y = crtc_y;
+ exynos_plane->crtc_width = actual_w;
+ exynos_plane->crtc_height = actual_h;
/* set drm mode data. */
- overlay->mode_width = crtc->mode.hdisplay;
- overlay->mode_height = crtc->mode.vdisplay;
- overlay->refresh = crtc->mode.vrefresh;
- overlay->scan_flag = crtc->mode.flags;
+ exynos_plane->mode_width = crtc->mode.hdisplay;
+ exynos_plane->mode_height = crtc->mode.vdisplay;
+ exynos_plane->refresh = crtc->mode.vrefresh;
+ exynos_plane->scan_flag = crtc->mode.flags;
- DRM_DEBUG_KMS("overlay : offset_x/y(%d,%d), width/height(%d,%d)",
- overlay->crtc_x, overlay->crtc_y,
- overlay->crtc_width, overlay->crtc_height);
+ DRM_DEBUG_KMS("plane : offset_x/y(%d,%d), width/height(%d,%d)",
+ exynos_plane->crtc_x, exynos_plane->crtc_y,
+ exynos_plane->crtc_width, exynos_plane->crtc_height);
plane->crtc = crtc;
- exynos_drm_crtc_plane_mode_set(crtc, overlay);
-
- return 0;
-}
-
-void exynos_plane_commit(struct drm_plane *plane)
-{
- struct exynos_plane *exynos_plane = to_exynos_plane(plane);
- struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-
- exynos_drm_crtc_plane_commit(plane->crtc, overlay->zpos);
+ if (exynos_crtc->ops->win_mode_set)
+ exynos_crtc->ops->win_mode_set(exynos_crtc, exynos_plane);
}
-void exynos_plane_dpms(struct drm_plane *plane, int mode)
-{
- struct exynos_plane *exynos_plane = to_exynos_plane(plane);
- struct exynos_drm_overlay *overlay = &exynos_plane->overlay;
-
- if (mode == DRM_MODE_DPMS_ON) {
- if (exynos_plane->enabled)
- return;
-
- exynos_drm_crtc_plane_enable(plane->crtc, overlay->zpos);
- exynos_plane->enabled = true;
- } else {
- if (!exynos_plane->enabled)
- return;
-
- exynos_drm_crtc_plane_disable(plane->crtc, overlay->zpos);
- exynos_plane->enabled = false;
- }
-}
-
-static int
+int
exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
struct drm_framebuffer *fb, int crtc_x, int crtc_y,
unsigned int crtc_w, unsigned int crtc_h,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
+
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
int ret;
- ret = exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
- crtc_w, crtc_h, src_x >> 16, src_y >> 16,
- src_w >> 16, src_h >> 16);
+ ret = exynos_check_plane(plane, fb);
if (ret < 0)
return ret;
- exynos_plane_commit(plane);
- exynos_plane_dpms(plane, DRM_MODE_DPMS_ON);
+ exynos_plane_mode_set(plane, crtc, fb, crtc_x, crtc_y,
+ crtc_w, crtc_h, src_x >> 16, src_y >> 16,
+ src_w >> 16, src_h >> 16);
+
+ if (exynos_crtc->ops->win_commit)
+ exynos_crtc->ops->win_commit(exynos_crtc, exynos_plane->zpos);
return 0;
}
static int exynos_disable_plane(struct drm_plane *plane)
{
- exynos_plane_dpms(plane, DRM_MODE_DPMS_OFF);
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
+ struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(plane->crtc);
+
+ if (exynos_crtc->ops->win_disable)
+ exynos_crtc->ops->win_disable(exynos_crtc,
+ exynos_plane->zpos);
return 0;
}
static void exynos_plane_destroy(struct drm_plane *plane)
{
- struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
exynos_disable_plane(plane);
drm_plane_cleanup(plane);
@@ -216,11 +196,11 @@ static int exynos_plane_set_property(struct drm_plane *plane,
uint64_t val)
{
struct drm_device *dev = plane->dev;
- struct exynos_plane *exynos_plane = to_exynos_plane(plane);
+ struct exynos_drm_plane *exynos_plane = to_exynos_plane(plane);
struct exynos_drm_private *dev_priv = dev->dev_private;
if (property == dev_priv->plane_zpos_property) {
- exynos_plane->overlay.zpos = val;
+ exynos_plane->zpos = val;
return 0;
}
@@ -257,10 +237,10 @@ struct drm_plane *exynos_plane_init(struct drm_device *dev,
unsigned long possible_crtcs,
enum drm_plane_type type)
{
- struct exynos_plane *exynos_plane;
+ struct exynos_drm_plane *exynos_plane;
int err;
- exynos_plane = kzalloc(sizeof(struct exynos_plane), GFP_KERNEL);
+ exynos_plane = kzalloc(sizeof(struct exynos_drm_plane), GFP_KERNEL);
if (!exynos_plane)
return ERR_PTR(-ENOMEM);
@@ -274,7 +254,7 @@ struct drm_plane *exynos_plane_init(struct drm_device *dev,
}
if (type == DRM_PLANE_TYPE_PRIMARY)
- exynos_plane->overlay.zpos = DEFAULT_ZPOS;
+ exynos_plane->zpos = DEFAULT_ZPOS;
else
exynos_plane_attach_zpos_property(&exynos_plane->base);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_plane.h b/drivers/gpu/drm/exynos/exynos_drm_plane.h
index 0d1986b115f8..9d3c374e7b3e 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_plane.h
+++ b/drivers/gpu/drm/exynos/exynos_drm_plane.h
@@ -9,13 +9,17 @@
*
*/
-int exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h);
-void exynos_plane_commit(struct drm_plane *plane);
-void exynos_plane_dpms(struct drm_plane *plane, int mode);
+int exynos_check_plane(struct drm_plane *plane, struct drm_framebuffer *fb);
+void exynos_plane_mode_set(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h);
+int exynos_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h);
struct drm_plane *exynos_plane_init(struct drm_device *dev,
unsigned long possible_crtcs,
enum drm_plane_type type);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_vidi.c b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
index 45899fb63272..b886972b5888 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_vidi.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_vidi.c
@@ -47,11 +47,10 @@ struct vidi_win_data {
};
struct vidi_context {
- struct exynos_drm_manager manager;
struct exynos_drm_display display;
struct platform_device *pdev;
struct drm_device *drm_dev;
- struct drm_crtc *crtc;
+ struct exynos_drm_crtc *crtc;
struct drm_encoder *encoder;
struct drm_connector connector;
struct vidi_win_data win_data[WINDOWS_NR];
@@ -68,11 +67,6 @@ struct vidi_context {
int pipe;
};
-static inline struct vidi_context *manager_to_vidi(struct exynos_drm_manager *m)
-{
- return container_of(m, struct vidi_context, manager);
-}
-
static inline struct vidi_context *display_to_vidi(struct exynos_drm_display *d)
{
return container_of(d, struct vidi_context, display);
@@ -103,34 +97,22 @@ static const char fake_edid_info[] = {
0x00, 0x00, 0x00, 0x06
};
-static void vidi_apply(struct exynos_drm_manager *mgr)
+static void vidi_apply(struct vidi_context *ctx)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
- struct exynos_drm_manager_ops *mgr_ops = mgr->ops;
+ struct exynos_drm_crtc_ops *crtc_ops = ctx->crtc->ops;
struct vidi_win_data *win_data;
int i;
for (i = 0; i < WINDOWS_NR; i++) {
win_data = &ctx->win_data[i];
- if (win_data->enabled && (mgr_ops && mgr_ops->win_commit))
- mgr_ops->win_commit(mgr, i);
+ if (win_data->enabled && (crtc_ops && crtc_ops->win_commit))
+ crtc_ops->win_commit(ctx->crtc, i);
}
-
- if (mgr_ops && mgr_ops->commit)
- mgr_ops->commit(mgr);
}
-static void vidi_commit(struct exynos_drm_manager *mgr)
+static int vidi_enable_vblank(struct exynos_drm_crtc *crtc)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
-
- if (ctx->suspended)
- return;
-}
-
-static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
-{
- struct vidi_context *ctx = manager_to_vidi(mgr);
+ struct vidi_context *ctx = crtc->ctx;
if (ctx->suspended)
return -EPERM;
@@ -143,16 +125,16 @@ static int vidi_enable_vblank(struct exynos_drm_manager *mgr)
/*
* in case of page flip request, vidi_finish_pageflip function
* will not be called because direct_vblank is true and then
- * that function will be called by manager_ops->win_commit callback
+ * that function will be called by crtc_ops->win_commit callback
*/
schedule_work(&ctx->work);
return 0;
}
-static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
+static void vidi_disable_vblank(struct exynos_drm_crtc *crtc)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
+ struct vidi_context *ctx = crtc->ctx;
if (ctx->suspended)
return;
@@ -161,44 +143,44 @@ static void vidi_disable_vblank(struct exynos_drm_manager *mgr)
ctx->vblank_on = false;
}
-static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
- struct exynos_drm_overlay *overlay)
+static void vidi_win_mode_set(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
+ struct vidi_context *ctx = crtc->ctx;
struct vidi_win_data *win_data;
int win;
unsigned long offset;
- if (!overlay) {
- DRM_ERROR("overlay is NULL\n");
+ if (!plane) {
+ DRM_ERROR("plane is NULL\n");
return;
}
- win = overlay->zpos;
+ win = plane->zpos;
if (win == DEFAULT_ZPOS)
win = ctx->default_win;
if (win < 0 || win >= WINDOWS_NR)
return;
- offset = overlay->fb_x * (overlay->bpp >> 3);
- offset += overlay->fb_y * overlay->pitch;
+ offset = plane->fb_x * (plane->bpp >> 3);
+ offset += plane->fb_y * plane->pitch;
- DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, overlay->pitch);
+ DRM_DEBUG_KMS("offset = 0x%lx, pitch = %x\n", offset, plane->pitch);
win_data = &ctx->win_data[win];
- win_data->offset_x = overlay->crtc_x;
- win_data->offset_y = overlay->crtc_y;
- win_data->ovl_width = overlay->crtc_width;
- win_data->ovl_height = overlay->crtc_height;
- win_data->fb_width = overlay->fb_width;
- win_data->fb_height = overlay->fb_height;
- win_data->dma_addr = overlay->dma_addr[0] + offset;
- win_data->bpp = overlay->bpp;
- win_data->buf_offsize = (overlay->fb_width - overlay->crtc_width) *
- (overlay->bpp >> 3);
- win_data->line_size = overlay->crtc_width * (overlay->bpp >> 3);
+ win_data->offset_x = plane->crtc_x;
+ win_data->offset_y = plane->crtc_y;
+ win_data->ovl_width = plane->crtc_width;
+ win_data->ovl_height = plane->crtc_height;
+ win_data->fb_width = plane->fb_width;
+ win_data->fb_height = plane->fb_height;
+ win_data->dma_addr = plane->dma_addr[0] + offset;
+ win_data->bpp = plane->bpp;
+ win_data->buf_offsize = (plane->fb_width - plane->crtc_width) *
+ (plane->bpp >> 3);
+ win_data->line_size = plane->crtc_width * (plane->bpp >> 3);
/*
* some parts of win_data should be transferred to user side
@@ -211,12 +193,12 @@ static void vidi_win_mode_set(struct exynos_drm_manager *mgr,
win_data->ovl_width, win_data->ovl_height);
DRM_DEBUG_KMS("paddr = 0x%lx\n", (unsigned long)win_data->dma_addr);
DRM_DEBUG_KMS("fb_width = %d, crtc_width = %d\n",
- overlay->fb_width, overlay->crtc_width);
+ plane->fb_width, plane->crtc_width);
}
-static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
+static void vidi_win_commit(struct exynos_drm_crtc *crtc, int zpos)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
+ struct vidi_context *ctx = crtc->ctx;
struct vidi_win_data *win_data;
int win = zpos;
@@ -239,9 +221,9 @@ static void vidi_win_commit(struct exynos_drm_manager *mgr, int zpos)
schedule_work(&ctx->work);
}
-static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
+static void vidi_win_disable(struct exynos_drm_crtc *crtc, int zpos)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
+ struct vidi_context *ctx = crtc->ctx;
struct vidi_win_data *win_data;
int win = zpos;
@@ -257,10 +239,8 @@ static void vidi_win_disable(struct exynos_drm_manager *mgr, int zpos)
/* TODO. */
}
-static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
+static int vidi_power_on(struct vidi_context *ctx, bool enable)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
-
DRM_DEBUG_KMS("%s\n", __FILE__);
if (enable != false && enable != true)
@@ -271,9 +251,9 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
/* if vblank was enabled status, enable it again. */
if (test_and_clear_bit(0, &ctx->irq_flags))
- vidi_enable_vblank(mgr);
+ vidi_enable_vblank(ctx->crtc);
- vidi_apply(mgr);
+ vidi_apply(ctx);
} else {
ctx->suspended = true;
}
@@ -281,9 +261,9 @@ static int vidi_power_on(struct exynos_drm_manager *mgr, bool enable)
return 0;
}
-static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
+static void vidi_dpms(struct exynos_drm_crtc *crtc, int mode)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
+ struct vidi_context *ctx = crtc->ctx;
DRM_DEBUG_KMS("%d\n", mode);
@@ -291,12 +271,12 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
- vidi_power_on(mgr, true);
+ vidi_power_on(ctx, true);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- vidi_power_on(mgr, false);
+ vidi_power_on(ctx, false);
break;
default:
DRM_DEBUG_KMS("unspecified mode %d\n", mode);
@@ -306,21 +286,19 @@ static void vidi_dpms(struct exynos_drm_manager *mgr, int mode)
mutex_unlock(&ctx->lock);
}
-static int vidi_mgr_initialize(struct exynos_drm_manager *mgr,
+static int vidi_ctx_initialize(struct vidi_context *ctx,
struct drm_device *drm_dev)
{
- struct vidi_context *ctx = manager_to_vidi(mgr);
struct exynos_drm_private *priv = drm_dev->dev_private;
- mgr->drm_dev = ctx->drm_dev = drm_dev;
- mgr->pipe = ctx->pipe = priv->pipe++;
+ ctx->drm_dev = drm_dev;
+ ctx->pipe = priv->pipe++;
return 0;
}
-static struct exynos_drm_manager_ops vidi_manager_ops = {
+static struct exynos_drm_crtc_ops vidi_crtc_ops = {
.dpms = vidi_dpms,
- .commit = vidi_commit,
.enable_vblank = vidi_enable_vblank,
.disable_vblank = vidi_disable_vblank,
.win_mode_set = vidi_win_mode_set,
@@ -565,21 +543,21 @@ static int vidi_bind(struct device *dev, struct device *master, void *data)
{
struct vidi_context *ctx = dev_get_drvdata(dev);
struct drm_device *drm_dev = data;
- struct drm_crtc *crtc = ctx->crtc;
int ret;
- vidi_mgr_initialize(&ctx->manager, drm_dev);
+ vidi_ctx_initialize(ctx, drm_dev);
- ret = exynos_drm_crtc_create(&ctx->manager);
- if (ret) {
+ ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+ EXYNOS_DISPLAY_TYPE_VIDI,
+ &vidi_crtc_ops, ctx);
+ if (IS_ERR(ctx->crtc)) {
DRM_ERROR("failed to create crtc.\n");
- return ret;
+ return PTR_ERR(ctx->crtc);
}
ret = exynos_drm_create_enc_conn(drm_dev, &ctx->display);
if (ret) {
- crtc->funcs->destroy(crtc);
- DRM_ERROR("failed to create encoder and connector.\n");
+ ctx->crtc->base.funcs->destroy(&ctx->crtc->base);
return ret;
}
@@ -605,15 +583,13 @@ static int vidi_probe(struct platform_device *pdev)
if (!ctx)
return -ENOMEM;
- ctx->manager.type = EXYNOS_DISPLAY_TYPE_VIDI;
- ctx->manager.ops = &vidi_manager_ops;
ctx->display.type = EXYNOS_DISPLAY_TYPE_VIDI;
ctx->display.ops = &vidi_display_ops;
ctx->default_win = 0;
ctx->pdev = pdev;
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
- ctx->manager.type);
+ EXYNOS_DISPLAY_TYPE_VIDI);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/exynos/exynos_hdmi.c b/drivers/gpu/drm/exynos/exynos_hdmi.c
index 98051e8e855a..229b3613c60b 100644
--- a/drivers/gpu/drm/exynos/exynos_hdmi.c
+++ b/drivers/gpu/drm/exynos/exynos_hdmi.c
@@ -2032,9 +2032,8 @@ static void hdmi_commit(struct exynos_drm_display *display)
hdmi_conf_apply(hdata);
}
-static void hdmi_poweron(struct exynos_drm_display *display)
+static void hdmi_poweron(struct hdmi_context *hdata)
{
- struct hdmi_context *hdata = display_to_hdmi(display);
struct hdmi_resources *res = &hdata->res;
mutex_lock(&hdata->hdmi_mutex);
@@ -2060,12 +2059,11 @@ static void hdmi_poweron(struct exynos_drm_display *display)
clk_prepare_enable(res->sclk_hdmi);
hdmiphy_poweron(hdata);
- hdmi_commit(display);
+ hdmi_commit(&hdata->display);
}
-static void hdmi_poweroff(struct exynos_drm_display *display)
+static void hdmi_poweroff(struct hdmi_context *hdata)
{
- struct hdmi_context *hdata = display_to_hdmi(display);
struct hdmi_resources *res = &hdata->res;
mutex_lock(&hdata->hdmi_mutex);
@@ -2109,7 +2107,7 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
switch (mode) {
case DRM_MODE_DPMS_ON:
- hdmi_poweron(display);
+ hdmi_poweron(hdata);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
@@ -2128,7 +2126,7 @@ static void hdmi_dpms(struct exynos_drm_display *display, int mode)
if (funcs && funcs->dpms)
(*funcs->dpms)(crtc, mode);
- hdmi_poweroff(display);
+ hdmi_poweroff(hdata);
break;
default:
DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
diff --git a/drivers/gpu/drm/exynos/exynos_mixer.c b/drivers/gpu/drm/exynos/exynos_mixer.c
index 064ed6597def..3518bc4654c5 100644
--- a/drivers/gpu/drm/exynos/exynos_mixer.c
+++ b/drivers/gpu/drm/exynos/exynos_mixer.c
@@ -72,6 +72,7 @@ struct mixer_resources {
spinlock_t reg_slock;
struct clk *mixer;
struct clk *vp;
+ struct clk *hdmi;
struct clk *sclk_mixer;
struct clk *sclk_hdmi;
struct clk *mout_mixer;
@@ -84,10 +85,10 @@ enum mixer_version_id {
};
struct mixer_context {
- struct exynos_drm_manager manager;
struct platform_device *pdev;
struct device *dev;
struct drm_device *drm_dev;
+ struct exynos_drm_crtc *crtc;
int pipe;
bool interlace;
bool powered;
@@ -103,11 +104,6 @@ struct mixer_context {
atomic_t wait_vsync_event;
};
-static inline struct mixer_context *mgr_to_mixer(struct exynos_drm_manager *mgr)
-{
- return container_of(mgr, struct mixer_context, manager);
-}
-
struct mixer_drv_data {
enum mixer_version_id version;
bool is_vp_enabled;
@@ -417,8 +413,6 @@ static void vp_video_buffer(struct mixer_context *ctx, int win)
win_data = &ctx->win_data[win];
switch (win_data->pixel_format) {
- case DRM_FORMAT_NV12MT:
- tiled_mode = true;
case DRM_FORMAT_NV12:
crcb_mode = false;
buf_num = 2;
@@ -587,8 +581,8 @@ static void mixer_graph_buffer(struct mixer_context *ctx, int win)
/* setup display size */
if (ctx->mxr_ver == MXR_VER_128_0_0_184 &&
win == MIXER_DEFAULT_WIN) {
- val = MXR_MXR_RES_HEIGHT(win_data->fb_height);
- val |= MXR_MXR_RES_WIDTH(win_data->fb_width);
+ val = MXR_MXR_RES_HEIGHT(win_data->mode_height);
+ val |= MXR_MXR_RES_WIDTH(win_data->mode_width);
mixer_reg_write(res, MXR_RESOLUTION, val);
}
@@ -774,6 +768,12 @@ static int mixer_resources_init(struct mixer_context *mixer_ctx)
return -ENODEV;
}
+ mixer_res->hdmi = devm_clk_get(dev, "hdmi");
+ if (IS_ERR(mixer_res->hdmi)) {
+ dev_err(dev, "failed to get clock 'hdmi'\n");
+ return PTR_ERR(mixer_res->hdmi);
+ }
+
mixer_res->sclk_hdmi = devm_clk_get(dev, "sclk_hdmi");
if (IS_ERR(mixer_res->sclk_hdmi)) {
dev_err(dev, "failed to get clock 'sclk_hdmi'\n");
@@ -854,16 +854,15 @@ static int vp_resources_init(struct mixer_context *mixer_ctx)
return 0;
}
-static int mixer_initialize(struct exynos_drm_manager *mgr,
+static int mixer_initialize(struct mixer_context *mixer_ctx,
struct drm_device *drm_dev)
{
int ret;
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
struct exynos_drm_private *priv;
priv = drm_dev->dev_private;
- mgr->drm_dev = mixer_ctx->drm_dev = drm_dev;
- mgr->pipe = mixer_ctx->pipe = priv->pipe++;
+ mixer_ctx->drm_dev = drm_dev;
+ mixer_ctx->pipe = priv->pipe++;
/* acquire resources: regs, irqs, clocks */
ret = mixer_resources_init(mixer_ctx);
@@ -887,17 +886,15 @@ static int mixer_initialize(struct exynos_drm_manager *mgr,
return drm_iommu_attach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
}
-static void mixer_mgr_remove(struct exynos_drm_manager *mgr)
+static void mixer_ctx_remove(struct mixer_context *mixer_ctx)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
-
if (is_drm_iommu_supported(mixer_ctx->drm_dev))
drm_iommu_detach_device(mixer_ctx->drm_dev, mixer_ctx->dev);
}
-static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
+static int mixer_enable_vblank(struct exynos_drm_crtc *crtc)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+ struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
if (!mixer_ctx->powered) {
@@ -912,34 +909,34 @@ static int mixer_enable_vblank(struct exynos_drm_manager *mgr)
return 0;
}
-static void mixer_disable_vblank(struct exynos_drm_manager *mgr)
+static void mixer_disable_vblank(struct exynos_drm_crtc *crtc)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+ struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
/* disable vsync interrupt */
mixer_reg_writemask(res, MXR_INT_EN, 0, MXR_INT_EN_VSYNC);
}
-static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
- struct exynos_drm_overlay *overlay)
+static void mixer_win_mode_set(struct exynos_drm_crtc *crtc,
+ struct exynos_drm_plane *plane)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+ struct mixer_context *mixer_ctx = crtc->ctx;
struct hdmi_win_data *win_data;
int win;
- if (!overlay) {
- DRM_ERROR("overlay is NULL\n");
+ if (!plane) {
+ DRM_ERROR("plane is NULL\n");
return;
}
DRM_DEBUG_KMS("set [%d]x[%d] at (%d,%d) to [%d]x[%d] at (%d,%d)\n",
- overlay->fb_width, overlay->fb_height,
- overlay->fb_x, overlay->fb_y,
- overlay->crtc_width, overlay->crtc_height,
- overlay->crtc_x, overlay->crtc_y);
+ plane->fb_width, plane->fb_height,
+ plane->fb_x, plane->fb_y,
+ plane->crtc_width, plane->crtc_height,
+ plane->crtc_x, plane->crtc_y);
- win = overlay->zpos;
+ win = plane->zpos;
if (win == DEFAULT_ZPOS)
win = MIXER_DEFAULT_WIN;
@@ -950,32 +947,32 @@ static void mixer_win_mode_set(struct exynos_drm_manager *mgr,
win_data = &mixer_ctx->win_data[win];
- win_data->dma_addr = overlay->dma_addr[0];
- win_data->chroma_dma_addr = overlay->dma_addr[1];
- win_data->pixel_format = overlay->pixel_format;
- win_data->bpp = overlay->bpp;
+ win_data->dma_addr = plane->dma_addr[0];
+ win_data->chroma_dma_addr = plane->dma_addr[1];
+ win_data->pixel_format = plane->pixel_format;
+ win_data->bpp = plane->bpp;
- win_data->crtc_x = overlay->crtc_x;
- win_data->crtc_y = overlay->crtc_y;
- win_data->crtc_width = overlay->crtc_width;
- win_data->crtc_height = overlay->crtc_height;
+ win_data->crtc_x = plane->crtc_x;
+ win_data->crtc_y = plane->crtc_y;
+ win_data->crtc_width = plane->crtc_width;
+ win_data->crtc_height = plane->crtc_height;
- win_data->fb_x = overlay->fb_x;
- win_data->fb_y = overlay->fb_y;
- win_data->fb_width = overlay->fb_width;
- win_data->fb_height = overlay->fb_height;
- win_data->src_width = overlay->src_width;
- win_data->src_height = overlay->src_height;
+ win_data->fb_x = plane->fb_x;
+ win_data->fb_y = plane->fb_y;
+ win_data->fb_width = plane->fb_width;
+ win_data->fb_height = plane->fb_height;
+ win_data->src_width = plane->src_width;
+ win_data->src_height = plane->src_height;
- win_data->mode_width = overlay->mode_width;
- win_data->mode_height = overlay->mode_height;
+ win_data->mode_width = plane->mode_width;
+ win_data->mode_height = plane->mode_height;
- win_data->scan_flags = overlay->scan_flag;
+ win_data->scan_flags = plane->scan_flag;
}
-static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
+static void mixer_win_commit(struct exynos_drm_crtc *crtc, int zpos)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+ struct mixer_context *mixer_ctx = crtc->ctx;
int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
DRM_DEBUG_KMS("win: %d\n", win);
@@ -995,9 +992,9 @@ static void mixer_win_commit(struct exynos_drm_manager *mgr, int zpos)
mixer_ctx->win_data[win].enabled = true;
}
-static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
+static void mixer_win_disable(struct exynos_drm_crtc *crtc, int zpos)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+ struct mixer_context *mixer_ctx = crtc->ctx;
struct mixer_resources *res = &mixer_ctx->mixer_res;
int win = zpos == DEFAULT_ZPOS ? MIXER_DEFAULT_WIN : zpos;
unsigned long flags;
@@ -1023,9 +1020,9 @@ static void mixer_win_disable(struct exynos_drm_manager *mgr, int zpos)
mixer_ctx->win_data[win].enabled = false;
}
-static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
+static void mixer_wait_for_vblank(struct exynos_drm_crtc *crtc)
{
- struct mixer_context *mixer_ctx = mgr_to_mixer(mgr);
+ struct mixer_context *mixer_ctx = crtc->ctx;
int err;
mutex_lock(&mixer_ctx->mixer_mutex);
@@ -1035,7 +1032,7 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
}
mutex_unlock(&mixer_ctx->mixer_mutex);
- err = drm_vblank_get(mgr->crtc->dev, mixer_ctx->pipe);
+ err = drm_vblank_get(mixer_ctx->drm_dev, mixer_ctx->pipe);
if (err < 0) {
DRM_DEBUG_KMS("failed to acquire vblank counter\n");
return;
@@ -1052,26 +1049,24 @@ static void mixer_wait_for_vblank(struct exynos_drm_manager *mgr)
HZ/20))
DRM_DEBUG_KMS("vblank wait timed out.\n");
- drm_vblank_put(mgr->crtc->dev, mixer_ctx->pipe);
+ drm_vblank_put(mixer_ctx->drm_dev, mixer_ctx->pipe);
}
-static void mixer_window_suspend(struct exynos_drm_manager *mgr)
+static void mixer_window_suspend(struct mixer_context *ctx)
{
- struct mixer_context *ctx = mgr_to_mixer(mgr);
struct hdmi_win_data *win_data;
int i;
for (i = 0; i < MIXER_WIN_NR; i++) {
win_data = &ctx->win_data[i];
win_data->resume = win_data->enabled;
- mixer_win_disable(mgr, i);
+ mixer_win_disable(ctx->crtc, i);
}
- mixer_wait_for_vblank(mgr);
+ mixer_wait_for_vblank(ctx->crtc);
}
-static void mixer_window_resume(struct exynos_drm_manager *mgr)
+static void mixer_window_resume(struct mixer_context *ctx)
{
- struct mixer_context *ctx = mgr_to_mixer(mgr);
struct hdmi_win_data *win_data;
int i;
@@ -1080,13 +1075,12 @@ static void mixer_window_resume(struct exynos_drm_manager *mgr)
win_data->enabled = win_data->resume;
win_data->resume = false;
if (win_data->enabled)
- mixer_win_commit(mgr, i);
+ mixer_win_commit(ctx->crtc, i);
}
}
-static void mixer_poweron(struct exynos_drm_manager *mgr)
+static void mixer_poweron(struct mixer_context *ctx)
{
- struct mixer_context *ctx = mgr_to_mixer(mgr);
struct mixer_resources *res = &ctx->mixer_res;
mutex_lock(&ctx->mixer_mutex);
@@ -1100,6 +1094,7 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
pm_runtime_get_sync(ctx->dev);
clk_prepare_enable(res->mixer);
+ clk_prepare_enable(res->hdmi);
if (ctx->vp_enabled) {
clk_prepare_enable(res->vp);
if (ctx->has_sclk)
@@ -1115,12 +1110,11 @@ static void mixer_poweron(struct exynos_drm_manager *mgr)
mixer_reg_write(res, MXR_INT_EN, ctx->int_en);
mixer_win_reset(ctx);
- mixer_window_resume(mgr);
+ mixer_window_resume(ctx);
}
-static void mixer_poweroff(struct exynos_drm_manager *mgr)
+static void mixer_poweroff(struct mixer_context *ctx)
{
- struct mixer_context *ctx = mgr_to_mixer(mgr);
struct mixer_resources *res = &ctx->mixer_res;
mutex_lock(&ctx->mixer_mutex);
@@ -1131,7 +1125,7 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
mutex_unlock(&ctx->mixer_mutex);
mixer_stop(ctx);
- mixer_window_suspend(mgr);
+ mixer_window_suspend(ctx);
ctx->int_en = mixer_reg_read(res, MXR_INT_EN);
@@ -1139,6 +1133,7 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
ctx->powered = false;
mutex_unlock(&ctx->mixer_mutex);
+ clk_disable_unprepare(res->hdmi);
clk_disable_unprepare(res->mixer);
if (ctx->vp_enabled) {
clk_disable_unprepare(res->vp);
@@ -1149,16 +1144,16 @@ static void mixer_poweroff(struct exynos_drm_manager *mgr)
pm_runtime_put_sync(ctx->dev);
}
-static void mixer_dpms(struct exynos_drm_manager *mgr, int mode)
+static void mixer_dpms(struct exynos_drm_crtc *crtc, int mode)
{
switch (mode) {
case DRM_MODE_DPMS_ON:
- mixer_poweron(mgr);
+ mixer_poweron(crtc->ctx);
break;
case DRM_MODE_DPMS_STANDBY:
case DRM_MODE_DPMS_SUSPEND:
case DRM_MODE_DPMS_OFF:
- mixer_poweroff(mgr);
+ mixer_poweroff(crtc->ctx);
break;
default:
DRM_DEBUG_KMS("unknown dpms mode: %d\n", mode);
@@ -1186,7 +1181,7 @@ int mixer_check_mode(struct drm_display_mode *mode)
return -EINVAL;
}
-static struct exynos_drm_manager_ops mixer_manager_ops = {
+static struct exynos_drm_crtc_ops mixer_crtc_ops = {
.dpms = mixer_dpms,
.enable_vblank = mixer_enable_vblank,
.disable_vblank = mixer_disable_vblank,
@@ -1257,24 +1252,31 @@ static int mixer_bind(struct device *dev, struct device *manager, void *data)
struct drm_device *drm_dev = data;
int ret;
- ret = mixer_initialize(&ctx->manager, drm_dev);
+ ret = mixer_initialize(ctx, drm_dev);
if (ret)
return ret;
- ret = exynos_drm_crtc_create(&ctx->manager);
- if (ret) {
- mixer_mgr_remove(&ctx->manager);
- return ret;
+ ctx->crtc = exynos_drm_crtc_create(drm_dev, ctx->pipe,
+ EXYNOS_DISPLAY_TYPE_HDMI,
+ &mixer_crtc_ops, ctx);
+ if (IS_ERR(ctx->crtc)) {
+ mixer_ctx_remove(ctx);
+ ret = PTR_ERR(ctx->crtc);
+ goto free_ctx;
}
return 0;
+
+free_ctx:
+ devm_kfree(dev, ctx);
+ return ret;
}
static void mixer_unbind(struct device *dev, struct device *master, void *data)
{
struct mixer_context *ctx = dev_get_drvdata(dev);
- mixer_mgr_remove(&ctx->manager);
+ mixer_ctx_remove(ctx);
}
static const struct component_ops mixer_component_ops = {
@@ -1297,9 +1299,6 @@ static int mixer_probe(struct platform_device *pdev)
mutex_init(&ctx->mixer_mutex);
- ctx->manager.type = EXYNOS_DISPLAY_TYPE_HDMI;
- ctx->manager.ops = &mixer_manager_ops;
-
if (dev->of_node) {
const struct of_device_id *match;
@@ -1321,7 +1320,7 @@ static int mixer_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ctx);
ret = exynos_drm_component_add(&pdev->dev, EXYNOS_DEVICE_TYPE_CRTC,
- ctx->manager.type);
+ EXYNOS_DISPLAY_TYPE_HDMI);
if (ret)
return ret;
diff --git a/drivers/gpu/drm/gma500/framebuffer.c b/drivers/gpu/drm/gma500/framebuffer.c
index ddd90ddbc200..2d42ce6d3757 100644
--- a/drivers/gpu/drm/gma500/framebuffer.c
+++ b/drivers/gpu/drm/gma500/framebuffer.c
@@ -593,6 +593,7 @@ int psb_fbdev_init(struct drm_device *dev)
{
struct psb_fbdev *fbdev;
struct drm_psb_private *dev_priv = dev->dev_private;
+ int ret;
fbdev = kzalloc(sizeof(struct psb_fbdev), GFP_KERNEL);
if (!fbdev) {
@@ -604,16 +605,29 @@ int psb_fbdev_init(struct drm_device *dev)
drm_fb_helper_prepare(dev, &fbdev->psb_fb_helper, &psb_fb_helper_funcs);
- drm_fb_helper_init(dev, &fbdev->psb_fb_helper, dev_priv->ops->crtcs,
- INTELFB_CONN_LIMIT);
+ ret = drm_fb_helper_init(dev, &fbdev->psb_fb_helper,
+ dev_priv->ops->crtcs, INTELFB_CONN_LIMIT);
+ if (ret)
+ goto free;
- drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper);
+ ret = drm_fb_helper_single_add_all_connectors(&fbdev->psb_fb_helper);
+ if (ret)
+ goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
- drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32);
+ ret = drm_fb_helper_initial_config(&fbdev->psb_fb_helper, 32);
+ if (ret)
+ goto fini;
+
return 0;
+
+fini:
+ drm_fb_helper_fini(&fbdev->psb_fb_helper);
+free:
+ kfree(fbdev);
+ return ret;
}
static void psb_fbdev_fini(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i2c/adv7511.c b/drivers/gpu/drm/i2c/adv7511.c
index faf1c0c5ab2e..fa140e04d5fa 100644
--- a/drivers/gpu/drm/i2c/adv7511.c
+++ b/drivers/gpu/drm/i2c/adv7511.c
@@ -644,9 +644,6 @@ static int adv7511_encoder_mode_valid(struct drm_encoder *encoder,
if (mode->clock > 165000)
return MODE_CLOCK_HIGH;
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- return MODE_NO_INTERLACE;
-
return MODE_OK;
}
diff --git a/drivers/gpu/drm/i915/Kconfig b/drivers/gpu/drm/i915/Kconfig
index 4e39ab34eb1c..74acca9bcd9d 100644
--- a/drivers/gpu/drm/i915/Kconfig
+++ b/drivers/gpu/drm/i915/Kconfig
@@ -11,6 +11,8 @@ config DRM_I915
select SHMEM
select TMPFS
select DRM_KMS_HELPER
+ select DRM_PANEL
+ select DRM_MIPI_DSI
# i915 depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
select BACKLIGHT_LCD_SUPPORT if ACPI
diff --git a/drivers/gpu/drm/i915/Makefile b/drivers/gpu/drm/i915/Makefile
index e4083e41a600..f01922591679 100644
--- a/drivers/gpu/drm/i915/Makefile
+++ b/drivers/gpu/drm/i915/Makefile
@@ -19,6 +19,7 @@ i915-$(CONFIG_DEBUG_FS) += i915_debugfs.o
# GEM code
i915-y += i915_cmd_parser.o \
+ i915_gem_batch_pool.o \
i915_gem_context.o \
i915_gem_render_state.o \
i915_gem_debug.o \
@@ -47,6 +48,7 @@ i915-y += intel_renderstate_gen6.o \
i915-y += intel_audio.o \
intel_bios.o \
intel_display.o \
+ intel_fbc.o \
intel_fifo_underrun.o \
intel_frontbuffer.o \
intel_modes.o \
@@ -64,11 +66,12 @@ i915-y += dvo_ch7017.o \
dvo_ns2501.o \
dvo_sil164.o \
dvo_tfp410.o \
+ intel_atomic.o \
+ intel_atomic_plane.o \
intel_crt.o \
intel_ddi.o \
intel_dp.o \
intel_dp_mst.o \
- intel_dsi_cmd.o \
intel_dsi.o \
intel_dsi_pll.o \
intel_dsi_panel_vbt.o \
diff --git a/drivers/gpu/drm/i915/i915_cmd_parser.c b/drivers/gpu/drm/i915/i915_cmd_parser.c
index 22c992a78ac6..806e812340d0 100644
--- a/drivers/gpu/drm/i915/i915_cmd_parser.c
+++ b/drivers/gpu/drm/i915/i915_cmd_parser.c
@@ -152,6 +152,7 @@ static const struct drm_i915_cmd_descriptor render_cmds[] = {
CMD( MI_PREDICATE, SMI, F, 1, S ),
CMD( MI_TOPOLOGY_FILTER, SMI, F, 1, S ),
CMD( MI_DISPLAY_FLIP, SMI, !F, 0xFF, R ),
+ CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_SET_CONTEXT, SMI, !F, 0xFF, R ),
CMD( MI_URB_CLEAR, SMI, !F, 0xFF, S ),
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0x3F, B,
@@ -210,6 +211,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = {
CMD( MI_SET_PREDICATE, SMI, F, 1, S ),
CMD( MI_RS_CONTROL, SMI, F, 1, S ),
CMD( MI_URB_ATOMIC_ALLOC, SMI, F, 1, S ),
+ CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_RS_CONTEXT, SMI, F, 1, S ),
CMD( MI_LOAD_SCAN_LINES_INCL, SMI, !F, 0x3F, M ),
CMD( MI_LOAD_SCAN_LINES_EXCL, SMI, !F, 0x3F, R ),
@@ -229,6 +231,7 @@ static const struct drm_i915_cmd_descriptor hsw_render_cmds[] = {
static const struct drm_i915_cmd_descriptor video_cmds[] = {
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
+ CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B,
.bits = {{
.offset = 0,
@@ -272,6 +275,7 @@ static const struct drm_i915_cmd_descriptor video_cmds[] = {
static const struct drm_i915_cmd_descriptor vecs_cmds[] = {
CMD( MI_ARB_ON_OFF, SMI, F, 1, R ),
+ CMD( MI_SET_APPID, SMI, F, 1, S ),
CMD( MI_STORE_DWORD_IMM, SMI, !F, 0xFF, B,
.bits = {{
.offset = 0,
@@ -401,6 +405,7 @@ static const struct drm_i915_cmd_table hsw_blt_ring_cmds[] = {
#define REG64(addr) (addr), (addr + sizeof(u32))
static const u32 gen7_render_regs[] = {
+ REG64(GPGPU_THREADS_DISPATCHED),
REG64(HS_INVOCATION_COUNT),
REG64(DS_INVOCATION_COUNT),
REG64(IA_VERTICES_COUNT),
@@ -481,13 +486,17 @@ static u32 gen7_bsd_get_cmd_length_mask(u32 cmd_header)
u32 client = (cmd_header & INSTR_CLIENT_MASK) >> INSTR_CLIENT_SHIFT;
u32 subclient =
(cmd_header & INSTR_SUBCLIENT_MASK) >> INSTR_SUBCLIENT_SHIFT;
+ u32 op = (cmd_header & INSTR_26_TO_24_MASK) >> INSTR_26_TO_24_SHIFT;
if (client == INSTR_MI_CLIENT)
return 0x3F;
else if (client == INSTR_RC_CLIENT) {
- if (subclient == INSTR_MEDIA_SUBCLIENT)
- return 0xFFF;
- else
+ if (subclient == INSTR_MEDIA_SUBCLIENT) {
+ if (op == 6)
+ return 0xFFFF;
+ else
+ return 0xFFF;
+ } else
return 0xFF;
}
@@ -716,13 +725,13 @@ int i915_cmd_parser_init_ring(struct intel_engine_cs *ring)
BUG_ON(!validate_cmds_sorted(ring, cmd_tables, cmd_table_count));
BUG_ON(!validate_regs_sorted(ring));
- if (hash_empty(ring->cmd_hash)) {
- ret = init_hash_table(ring, cmd_tables, cmd_table_count);
- if (ret) {
- DRM_ERROR("CMD: cmd_parser_init failed!\n");
- fini_hash_table(ring);
- return ret;
- }
+ WARN_ON(!hash_empty(ring->cmd_hash));
+
+ ret = init_hash_table(ring, cmd_tables, cmd_table_count);
+ if (ret) {
+ DRM_ERROR("CMD: cmd_parser_init failed!\n");
+ fini_hash_table(ring);
+ return ret;
}
ring->needs_cmd_parser = true;
@@ -840,6 +849,69 @@ finish:
return (u32*)addr;
}
+/* Returns a vmap'd pointer to dest_obj, which the caller must unmap */
+static u32 *copy_batch(struct drm_i915_gem_object *dest_obj,
+ struct drm_i915_gem_object *src_obj,
+ u32 batch_start_offset,
+ u32 batch_len)
+{
+ int ret = 0;
+ int needs_clflush = 0;
+ u32 *src_base, *dest_base = NULL;
+ u32 *src_addr, *dest_addr;
+ u32 offset = batch_start_offset / sizeof(*dest_addr);
+ u32 end = batch_start_offset + batch_len;
+
+ if (end > dest_obj->base.size || end > src_obj->base.size)
+ return ERR_PTR(-E2BIG);
+
+ ret = i915_gem_obj_prepare_shmem_read(src_obj, &needs_clflush);
+ if (ret) {
+ DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
+ return ERR_PTR(ret);
+ }
+
+ src_base = vmap_batch(src_obj);
+ if (!src_base) {
+ DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
+ ret = -ENOMEM;
+ goto unpin_src;
+ }
+
+ src_addr = src_base + offset;
+
+ if (needs_clflush)
+ drm_clflush_virt_range((char *)src_addr, batch_len);
+
+ ret = i915_gem_object_set_to_cpu_domain(dest_obj, true);
+ if (ret) {
+ DRM_DEBUG_DRIVER("CMD: Failed to set batch CPU domain\n");
+ goto unmap_src;
+ }
+
+ dest_base = vmap_batch(dest_obj);
+ if (!dest_base) {
+ DRM_DEBUG_DRIVER("CMD: Failed to vmap shadow batch\n");
+ ret = -ENOMEM;
+ goto unmap_src;
+ }
+
+ dest_addr = dest_base + offset;
+
+ if (batch_start_offset != 0)
+ memset((u8 *)dest_base, 0, batch_start_offset);
+
+ memcpy(dest_addr, src_addr, batch_len);
+ memset((u8 *)dest_addr + batch_len, 0, dest_obj->base.size - end);
+
+unmap_src:
+ vunmap(src_base);
+unpin_src:
+ i915_gem_object_unpin_pages(src_obj);
+
+ return ret ? ERR_PTR(ret) : dest_base;
+}
+
/**
* i915_needs_cmd_parser() - should a given ring use software command parsing?
* @ring: the ring in question
@@ -956,7 +1028,9 @@ static bool check_cmd(const struct intel_engine_cs *ring,
* i915_parse_cmds() - parse a submitted batch buffer for privilege violations
* @ring: the ring on which the batch is to execute
* @batch_obj: the batch buffer in question
+ * @shadow_batch_obj: copy of the batch buffer in question
* @batch_start_offset: byte offset in the batch at which execution starts
+ * @batch_len: length of the commands in batch_obj
* @is_master: is the submitting process the drm master?
*
* Parses the specified batch buffer looking for privilege violations as
@@ -967,33 +1041,38 @@ static bool check_cmd(const struct intel_engine_cs *ring,
*/
int i915_parse_cmds(struct intel_engine_cs *ring,
struct drm_i915_gem_object *batch_obj,
+ struct drm_i915_gem_object *shadow_batch_obj,
u32 batch_start_offset,
+ u32 batch_len,
bool is_master)
{
int ret = 0;
u32 *cmd, *batch_base, *batch_end;
struct drm_i915_cmd_descriptor default_desc = { 0 };
- int needs_clflush = 0;
bool oacontrol_set = false; /* OACONTROL tracking. See check_cmd() */
- ret = i915_gem_obj_prepare_shmem_read(batch_obj, &needs_clflush);
+ ret = i915_gem_obj_ggtt_pin(shadow_batch_obj, 4096, 0);
if (ret) {
- DRM_DEBUG_DRIVER("CMD: failed to prep read\n");
- return ret;
+ DRM_DEBUG_DRIVER("CMD: Failed to pin shadow batch\n");
+ return -1;
}
- batch_base = vmap_batch(batch_obj);
- if (!batch_base) {
- DRM_DEBUG_DRIVER("CMD: Failed to vmap batch\n");
- i915_gem_object_unpin_pages(batch_obj);
- return -ENOMEM;
+ batch_base = copy_batch(shadow_batch_obj, batch_obj,
+ batch_start_offset, batch_len);
+ if (IS_ERR(batch_base)) {
+ DRM_DEBUG_DRIVER("CMD: Failed to copy batch\n");
+ i915_gem_object_ggtt_unpin(shadow_batch_obj);
+ return PTR_ERR(batch_base);
}
- if (needs_clflush)
- drm_clflush_virt_range((char *)batch_base, batch_obj->base.size);
-
cmd = batch_base + (batch_start_offset / sizeof(*cmd));
- batch_end = cmd + (batch_obj->base.size / sizeof(*batch_end));
+
+ /*
+ * We use the batch length as size because the shadow object is as
+ * large or larger and copy_batch() will write MI_NOPs to the extra
+ * space. Parsing should be faster in some cases this way.
+ */
+ batch_end = cmd + (batch_len / sizeof(*batch_end));
while (cmd < batch_end) {
const struct drm_i915_cmd_descriptor *desc;
@@ -1053,8 +1132,7 @@ int i915_parse_cmds(struct intel_engine_cs *ring,
}
vunmap(batch_base);
-
- i915_gem_object_unpin_pages(batch_obj);
+ i915_gem_object_ggtt_unpin(shadow_batch_obj);
return ret;
}
@@ -1076,6 +1154,7 @@ int i915_cmd_parser_get_version(void)
* hardware parsing enabled (so does not allow new use cases).
* 2. Allow access to the MI_PREDICATE_SRC0 and
* MI_PREDICATE_SRC1 registers.
+ * 3. Allow access to the GPGPU_THREADS_DISPATCHED register.
*/
- return 2;
+ return 3;
}
diff --git a/drivers/gpu/drm/i915/i915_debugfs.c b/drivers/gpu/drm/i915/i915_debugfs.c
index 779a275eb1fd..96e811fe24ca 100644
--- a/drivers/gpu/drm/i915/i915_debugfs.c
+++ b/drivers/gpu/drm/i915/i915_debugfs.c
@@ -96,9 +96,7 @@ static int i915_capabilities(struct seq_file *m, void *data)
static const char *get_pin_flag(struct drm_i915_gem_object *obj)
{
- if (obj->user_pin_count > 0)
- return "P";
- else if (i915_gem_obj_is_pinned(obj))
+ if (i915_gem_obj_is_pinned(obj))
return "p";
else
return " ";
@@ -125,7 +123,7 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
struct i915_vma *vma;
int pin_count = 0;
- seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %u %u %u%s%s%s",
+ seq_printf(m, "%pK: %s%s%s %8zdKiB %02x %02x %x %x %x%s%s%s",
&obj->base,
get_pin_flag(obj),
get_tiling_flag(obj),
@@ -133,9 +131,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
obj->base.size / 1024,
obj->base.read_domains,
obj->base.write_domain,
- obj->last_read_seqno,
- obj->last_write_seqno,
- obj->last_fenced_seqno,
+ i915_gem_request_get_seqno(obj->last_read_req),
+ i915_gem_request_get_seqno(obj->last_write_req),
+ i915_gem_request_get_seqno(obj->last_fenced_req),
i915_cache_level_str(to_i915(obj->base.dev), obj->cache_level),
obj->dirty ? " dirty" : "",
obj->madv == I915_MADV_DONTNEED ? " purgeable" : "");
@@ -154,8 +152,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
seq_puts(m, " (pp");
else
seq_puts(m, " (g");
- seq_printf(m, "gtt offset: %08lx, size: %08lx)",
- vma->node.start, vma->node.size);
+ seq_printf(m, "gtt offset: %08lx, size: %08lx, type: %u)",
+ vma->node.start, vma->node.size,
+ vma->ggtt_view.type);
}
if (obj->stolen)
seq_printf(m, " (stolen: %08lx)", obj->stolen->start);
@@ -168,8 +167,9 @@ describe_obj(struct seq_file *m, struct drm_i915_gem_object *obj)
*t = '\0';
seq_printf(m, " (%s mappable)", s);
}
- if (obj->ring != NULL)
- seq_printf(m, " (%s)", obj->ring->name);
+ if (obj->last_read_req != NULL)
+ seq_printf(m, " (%s)",
+ i915_gem_request_get_ring(obj->last_read_req)->name);
if (obj->frontbuffer_bits)
seq_printf(m, " (frontbuffer: 0x%03x)", obj->frontbuffer_bits);
}
@@ -336,7 +336,7 @@ static int per_file_stats(int id, void *ptr, void *data)
if (ppgtt->file_priv != stats->file_priv)
continue;
- if (obj->ring) /* XXX per-vma statistic */
+ if (obj->active) /* XXX per-vma statistic */
stats->active += obj->base.size;
else
stats->inactive += obj->base.size;
@@ -346,7 +346,7 @@ static int per_file_stats(int id, void *ptr, void *data)
} else {
if (i915_gem_obj_ggtt_bound(obj)) {
stats->global += obj->base.size;
- if (obj->ring)
+ if (obj->active)
stats->active += obj->base.size;
else
stats->inactive += obj->base.size;
@@ -360,6 +360,33 @@ static int per_file_stats(int id, void *ptr, void *data)
return 0;
}
+#define print_file_stats(m, name, stats) \
+ seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n", \
+ name, \
+ stats.count, \
+ stats.total, \
+ stats.active, \
+ stats.inactive, \
+ stats.global, \
+ stats.shared, \
+ stats.unbound)
+
+static void print_batch_pool_stats(struct seq_file *m,
+ struct drm_i915_private *dev_priv)
+{
+ struct drm_i915_gem_object *obj;
+ struct file_stats stats;
+
+ memset(&stats, 0, sizeof(stats));
+
+ list_for_each_entry(obj,
+ &dev_priv->mm.batch_pool.cache_list,
+ batch_pool_list)
+ per_file_stats(0, obj, &stats);
+
+ print_file_stats(m, "batch pool", stats);
+}
+
#define count_vmas(list, member) do { \
list_for_each_entry(vma, list, member) { \
size += i915_gem_obj_ggtt_size(vma->obj); \
@@ -442,6 +469,9 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
dev_priv->gtt.mappable_end - dev_priv->gtt.base.start);
seq_putc(m, '\n');
+ print_batch_pool_stats(m, dev_priv);
+
+ seq_putc(m, '\n');
list_for_each_entry_reverse(file, &dev->filelist, lhead) {
struct file_stats stats;
struct task_struct *task;
@@ -459,15 +489,7 @@ static int i915_gem_object_info(struct seq_file *m, void* data)
*/
rcu_read_lock();
task = pid_task(file->pid, PIDTYPE_PID);
- seq_printf(m, "%s: %u objects, %zu bytes (%zu active, %zu inactive, %zu global, %zu shared, %zu unbound)\n",
- task ? task->comm : "<unknown>",
- stats.count,
- stats.total,
- stats.active,
- stats.inactive,
- stats.global,
- stats.shared,
- stats.unbound);
+ print_file_stats(m, task ? task->comm : "<unknown>", stats);
rcu_read_unlock();
}
@@ -543,14 +565,16 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
seq_printf(m, "Flip pending (waiting for vsync) on pipe %c (plane %c)\n",
pipe, plane);
}
- if (work->flip_queued_ring) {
- seq_printf(m, "Flip queued on %s at seqno %u, next seqno %u [current breadcrumb %u], completed? %d\n",
- work->flip_queued_ring->name,
- work->flip_queued_seqno,
+ if (work->flip_queued_req) {
+ struct intel_engine_cs *ring =
+ i915_gem_request_get_ring(work->flip_queued_req);
+
+ seq_printf(m, "Flip queued on %s at seqno %x, next seqno %x [current breadcrumb %x], completed? %d\n",
+ ring->name,
+ i915_gem_request_get_seqno(work->flip_queued_req),
dev_priv->next_seqno,
- work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
- i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
- work->flip_queued_seqno));
+ ring->get_seqno(ring, true),
+ i915_gem_request_completed(work->flip_queued_req, true));
} else
seq_printf(m, "Flip not associated with any ring\n");
seq_printf(m, "Flip queued on frame %d, (was ready on frame %d), now %d\n",
@@ -582,6 +606,36 @@ static int i915_gem_pageflip_info(struct seq_file *m, void *data)
return 0;
}
+static int i915_gem_batch_pool_info(struct seq_file *m, void *data)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_gem_object *obj;
+ int count = 0;
+ int ret;
+
+ ret = mutex_lock_interruptible(&dev->struct_mutex);
+ if (ret)
+ return ret;
+
+ seq_puts(m, "cache:\n");
+ list_for_each_entry(obj,
+ &dev_priv->mm.batch_pool.cache_list,
+ batch_pool_list) {
+ seq_puts(m, " ");
+ describe_obj(m, obj);
+ seq_putc(m, '\n');
+ count++;
+ }
+
+ seq_printf(m, "total: %d\n", count);
+
+ mutex_unlock(&dev->struct_mutex);
+
+ return 0;
+}
+
static int i915_gem_request_info(struct seq_file *m, void *data)
{
struct drm_info_node *node = m->private;
@@ -604,7 +658,7 @@ static int i915_gem_request_info(struct seq_file *m, void *data)
list_for_each_entry(gem_request,
&ring->request_list,
list) {
- seq_printf(m, " %d @ %d\n",
+ seq_printf(m, " %x @ %d\n",
gem_request->seqno,
(int) (jiffies - gem_request->emitted_jiffies));
}
@@ -622,7 +676,7 @@ static void i915_ring_seqno_info(struct seq_file *m,
struct intel_engine_cs *ring)
{
if (ring->get_seqno) {
- seq_printf(m, "Current sequence (%s): %u\n",
+ seq_printf(m, "Current sequence (%s): %x\n",
ring->name, ring->get_seqno(ring, false));
}
}
@@ -1051,7 +1105,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
if (ret)
goto out;
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
reqf = I915_READ(GEN6_RPNSWREQ);
reqf &= ~GEN6_TURBO_DISABLE;
@@ -1059,7 +1113,7 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
reqf >>= 24;
else
reqf >>= 25;
- reqf *= GT_FREQUENCY_MULTIPLIER;
+ reqf = intel_gpu_freq(dev_priv, reqf);
rpmodectl = I915_READ(GEN6_RP_CONTROL);
rpinclimit = I915_READ(GEN6_RP_UP_THRESHOLD);
@@ -1076,9 +1130,9 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
cagf = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
else
cagf = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
- cagf *= GT_FREQUENCY_MULTIPLIER;
+ cagf = intel_gpu_freq(dev_priv, cagf);
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
mutex_unlock(&dev->struct_mutex);
if (IS_GEN6(dev) || IS_GEN7(dev)) {
@@ -1124,18 +1178,18 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
max_freq = (rp_state_cap & 0xff0000) >> 16;
seq_printf(m, "Lowest (RPN) frequency: %dMHz\n",
- max_freq * GT_FREQUENCY_MULTIPLIER);
+ intel_gpu_freq(dev_priv, max_freq));
max_freq = (rp_state_cap & 0xff00) >> 8;
seq_printf(m, "Nominal (RP1) frequency: %dMHz\n",
- max_freq * GT_FREQUENCY_MULTIPLIER);
+ intel_gpu_freq(dev_priv, max_freq));
max_freq = rp_state_cap & 0xff;
seq_printf(m, "Max non-overclocked (RP0) frequency: %dMHz\n",
- max_freq * GT_FREQUENCY_MULTIPLIER);
+ intel_gpu_freq(dev_priv, max_freq));
seq_printf(m, "Max overclocked frequency: %dMHz\n",
- dev_priv->rps.max_freq * GT_FREQUENCY_MULTIPLIER);
+ intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
} else if (IS_VALLEYVIEW(dev)) {
u32 freq_sts;
@@ -1145,16 +1199,17 @@ static int i915_frequency_info(struct seq_file *m, void *unused)
seq_printf(m, "DDR freq: %d MHz\n", dev_priv->mem_freq);
seq_printf(m, "max GPU freq: %d MHz\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq));
+ intel_gpu_freq(dev_priv, dev_priv->rps.max_freq));
seq_printf(m, "min GPU freq: %d MHz\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq));
+ intel_gpu_freq(dev_priv, dev_priv->rps.min_freq));
- seq_printf(m, "efficient (RPe) frequency: %d MHz\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
+ seq_printf(m,
+ "efficient (RPe) frequency: %d MHz\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
seq_printf(m, "current GPU freq: %d MHz\n",
- vlv_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
+ intel_gpu_freq(dev_priv, (freq_sts >> 8) & 0xff));
mutex_unlock(&dev_priv->rps.hw_lock);
} else {
seq_puts(m, "no P-state info available\n");
@@ -1165,6 +1220,53 @@ out:
return ret;
}
+static int i915_hangcheck_info(struct seq_file *m, void *unused)
+{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_engine_cs *ring;
+ u64 acthd[I915_NUM_RINGS];
+ u32 seqno[I915_NUM_RINGS];
+ int i;
+
+ if (!i915.enable_hangcheck) {
+ seq_printf(m, "Hangcheck disabled\n");
+ return 0;
+ }
+
+ intel_runtime_pm_get(dev_priv);
+
+ for_each_ring(ring, dev_priv, i) {
+ seqno[i] = ring->get_seqno(ring, false);
+ acthd[i] = intel_ring_get_active_head(ring);
+ }
+
+ intel_runtime_pm_put(dev_priv);
+
+ if (delayed_work_pending(&dev_priv->gpu_error.hangcheck_work)) {
+ seq_printf(m, "Hangcheck active, fires in %dms\n",
+ jiffies_to_msecs(dev_priv->gpu_error.hangcheck_work.timer.expires -
+ jiffies));
+ } else
+ seq_printf(m, "Hangcheck inactive\n");
+
+ for_each_ring(ring, dev_priv, i) {
+ seq_printf(m, "%s:\n", ring->name);
+ seq_printf(m, "\tseqno = %x [current %x]\n",
+ ring->hangcheck.seqno, seqno[i]);
+ seq_printf(m, "\tACTHD = 0x%08llx [current 0x%08llx]\n",
+ (long long)ring->hangcheck.acthd,
+ (long long)acthd[i]);
+ seq_printf(m, "\tmax ACTHD = 0x%08llx\n",
+ (long long)ring->hangcheck.max_acthd);
+ seq_printf(m, "\tscore = %d\n", ring->hangcheck.score);
+ seq_printf(m, "\taction = %d\n", ring->hangcheck.action);
+ }
+
+ return 0;
+}
+
static int ironlake_drpc_info(struct seq_file *m)
{
struct drm_info_node *node = m->private;
@@ -1234,14 +1336,31 @@ static int ironlake_drpc_info(struct seq_file *m)
return 0;
}
-static int vlv_drpc_info(struct seq_file *m)
+static int i915_forcewake_domains(struct seq_file *m, void *data)
{
+ struct drm_info_node *node = m->private;
+ struct drm_device *dev = node->minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_uncore_forcewake_domain *fw_domain;
+ int i;
+ spin_lock_irq(&dev_priv->uncore.lock);
+ for_each_fw_domain(fw_domain, dev_priv, i) {
+ seq_printf(m, "%s.wake_count = %u\n",
+ intel_uncore_forcewake_domain_to_str(i),
+ fw_domain->wake_count);
+ }
+ spin_unlock_irq(&dev_priv->uncore.lock);
+
+ return 0;
+}
+
+static int vlv_drpc_info(struct seq_file *m)
+{
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 rpmodectl1, rcctl1, pw_status;
- unsigned fw_rendercount = 0, fw_mediacount = 0;
intel_runtime_pm_get(dev_priv);
@@ -1273,22 +1392,11 @@ static int vlv_drpc_info(struct seq_file *m)
seq_printf(m, "Media RC6 residency since boot: %u\n",
I915_READ(VLV_GT_MEDIA_RC6));
- spin_lock_irq(&dev_priv->uncore.lock);
- fw_rendercount = dev_priv->uncore.fw_rendercount;
- fw_mediacount = dev_priv->uncore.fw_mediacount;
- spin_unlock_irq(&dev_priv->uncore.lock);
-
- seq_printf(m, "Forcewake Render Count = %u\n", fw_rendercount);
- seq_printf(m, "Forcewake Media Count = %u\n", fw_mediacount);
-
-
- return 0;
+ return i915_forcewake_domains(m, NULL);
}
-
static int gen6_drpc_info(struct seq_file *m)
{
-
struct drm_info_node *node = m->private;
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1302,7 +1410,7 @@ static int gen6_drpc_info(struct seq_file *m)
intel_runtime_pm_get(dev_priv);
spin_lock_irq(&dev_priv->uncore.lock);
- forcewake_count = dev_priv->uncore.forcewake_count;
+ forcewake_count = dev_priv->uncore.fw_domain[FW_DOMAIN_ID_RENDER].wake_count;
spin_unlock_irq(&dev_priv->uncore.lock);
if (forcewake_count) {
@@ -1617,7 +1725,7 @@ static int i915_ring_freq_table(struct seq_file *m, void *unused)
GEN6_PCODE_READ_MIN_FREQ_TABLE,
&ia_freq);
seq_printf(m, "%d\t\t%d\t\t\t\t%d\n",
- gpu_freq * GT_FREQUENCY_MULTIPLIER,
+ intel_gpu_freq(dev_priv, gpu_freq),
((ia_freq >> 0) & 0xff) * 100,
((ia_freq >> 8) & 0xff) * 100);
}
@@ -1874,7 +1982,7 @@ static int i915_execlists(struct seq_file *m, void *data)
intel_runtime_pm_get(dev_priv);
for_each_ring(ring, dev_priv, ring_id) {
- struct intel_ctx_submit_request *head_req = NULL;
+ struct drm_i915_gem_request *head_req = NULL;
int count = 0;
unsigned long flags;
@@ -1907,7 +2015,7 @@ static int i915_execlists(struct seq_file *m, void *data)
list_for_each(cursor, &ring->execlist_queue)
count++;
head_req = list_first_entry_or_null(&ring->execlist_queue,
- struct intel_ctx_submit_request, execlist_link);
+ struct drm_i915_gem_request, execlist_link);
spin_unlock_irqrestore(&ring->execlist_lock, flags);
seq_printf(m, "\t%d requests in queue\n", count);
@@ -1930,30 +2038,6 @@ static int i915_execlists(struct seq_file *m, void *data)
return 0;
}
-static int i915_gen6_forcewake_count_info(struct seq_file *m, void *data)
-{
- struct drm_info_node *node = m->private;
- struct drm_device *dev = node->minor->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned forcewake_count = 0, fw_rendercount = 0, fw_mediacount = 0;
-
- spin_lock_irq(&dev_priv->uncore.lock);
- if (IS_VALLEYVIEW(dev)) {
- fw_rendercount = dev_priv->uncore.fw_rendercount;
- fw_mediacount = dev_priv->uncore.fw_mediacount;
- } else
- forcewake_count = dev_priv->uncore.forcewake_count;
- spin_unlock_irq(&dev_priv->uncore.lock);
-
- if (IS_VALLEYVIEW(dev)) {
- seq_printf(m, "fw_rendercount = %u\n", fw_rendercount);
- seq_printf(m, "fw_mediacount = %u\n", fw_mediacount);
- } else
- seq_printf(m, "forcewake count = %u\n", forcewake_count);
-
- return 0;
-}
-
static const char *swizzle_string(unsigned swizzle)
{
switch (swizzle) {
@@ -2155,6 +2239,8 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
struct drm_device *dev = node->minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 psrperf = 0;
+ u32 stat[3];
+ enum pipe pipe;
bool enabled = false;
intel_runtime_pm_get(dev_priv);
@@ -2169,14 +2255,39 @@ static int i915_edp_psr_status(struct seq_file *m, void *data)
seq_printf(m, "Re-enable work scheduled: %s\n",
yesno(work_busy(&dev_priv->psr.work.work)));
- enabled = HAS_PSR(dev) &&
- I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
- seq_printf(m, "HW Enabled & Active bit: %s\n", yesno(enabled));
+ if (HAS_PSR(dev)) {
+ if (HAS_DDI(dev))
+ enabled = I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+ else {
+ for_each_pipe(dev_priv, pipe) {
+ stat[pipe] = I915_READ(VLV_PSRSTAT(pipe)) &
+ VLV_EDP_PSR_CURR_STATE_MASK;
+ if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+ (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+ enabled = true;
+ }
+ }
+ }
+ seq_printf(m, "HW Enabled & Active bit: %s", yesno(enabled));
+
+ if (!HAS_DDI(dev))
+ for_each_pipe(dev_priv, pipe) {
+ if ((stat[pipe] == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+ (stat[pipe] == VLV_EDP_PSR_ACTIVE_SF_UPDATE))
+ seq_printf(m, " pipe %c", pipe_name(pipe));
+ }
+ seq_puts(m, "\n");
+
+ seq_printf(m, "Link standby: %s\n",
+ yesno((bool)dev_priv->psr.link_standby));
- if (HAS_PSR(dev))
+ /* CHV PSR has no kind of performance counter */
+ if (HAS_PSR(dev) && HAS_DDI(dev)) {
psrperf = I915_READ(EDP_PSR_PERF_CNT(dev)) &
EDP_PSR_PERF_CNT_MASK;
- seq_printf(m, "Performance_Counter: %u\n", psrperf);
+
+ seq_printf(m, "Performance_Counter: %u\n", psrperf);
+ }
mutex_unlock(&dev_priv->psr.lock);
intel_runtime_pm_put(dev_priv);
@@ -2319,10 +2430,18 @@ static const char *power_domain_str(enum intel_display_power_domain domain)
return "AUDIO";
case POWER_DOMAIN_PLLS:
return "PLLS";
+ case POWER_DOMAIN_AUX_A:
+ return "AUX_A";
+ case POWER_DOMAIN_AUX_B:
+ return "AUX_B";
+ case POWER_DOMAIN_AUX_C:
+ return "AUX_C";
+ case POWER_DOMAIN_AUX_D:
+ return "AUX_D";
case POWER_DOMAIN_INIT:
return "INIT";
default:
- WARN_ON(1);
+ MISSING_CASE(domain);
return "?";
}
}
@@ -2547,7 +2666,8 @@ static int i915_display_info(struct seq_file *m, void *unused)
seq_printf(m, "CRTC %d: pipe: %c, active=%s (size=%dx%d)\n",
crtc->base.base.id, pipe_name(crtc->pipe),
- yesno(crtc->active), crtc->config.pipe_src_w, crtc->config.pipe_src_h);
+ yesno(crtc->active), crtc->config->pipe_src_w,
+ crtc->config->pipe_src_h);
if (crtc->active) {
intel_crtc_info(m, crtc);
@@ -2718,6 +2838,9 @@ static int i915_ddb_info(struct seq_file *m, void *unused)
enum pipe pipe;
int plane;
+ if (INTEL_INFO(dev)->gen < 9)
+ return 0;
+
drm_modeset_lock_all(dev);
ddb = &dev_priv->wm.skl_hw.ddb;
@@ -2830,7 +2953,7 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_pipe_crc *pipe_crc = &dev_priv->pipe_crc[info->pipe];
char buf[PIPE_CRC_BUFFER_LEN];
- int head, tail, n_entries, n;
+ int n_entries;
ssize_t bytes_read;
/*
@@ -2862,36 +2985,39 @@ i915_pipe_crc_read(struct file *filep, char __user *user_buf, size_t count,
}
/* We now have one or more entries to read */
- head = pipe_crc->head;
- tail = pipe_crc->tail;
- n_entries = min((size_t)CIRC_CNT(head, tail, INTEL_PIPE_CRC_ENTRIES_NR),
- count / PIPE_CRC_LINE_LEN);
- spin_unlock_irq(&pipe_crc->lock);
+ n_entries = count / PIPE_CRC_LINE_LEN;
bytes_read = 0;
- n = 0;
- do {
- struct intel_pipe_crc_entry *entry = &pipe_crc->entries[tail];
+ while (n_entries > 0) {
+ struct intel_pipe_crc_entry *entry =
+ &pipe_crc->entries[pipe_crc->tail];
int ret;
+ if (CIRC_CNT(pipe_crc->head, pipe_crc->tail,
+ INTEL_PIPE_CRC_ENTRIES_NR) < 1)
+ break;
+
+ BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR);
+ pipe_crc->tail = (pipe_crc->tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
+
bytes_read += snprintf(buf, PIPE_CRC_BUFFER_LEN,
"%8u %8x %8x %8x %8x %8x\n",
entry->frame, entry->crc[0],
entry->crc[1], entry->crc[2],
entry->crc[3], entry->crc[4]);
- ret = copy_to_user(user_buf + n * PIPE_CRC_LINE_LEN,
- buf, PIPE_CRC_LINE_LEN);
+ spin_unlock_irq(&pipe_crc->lock);
+
+ ret = copy_to_user(user_buf, buf, PIPE_CRC_LINE_LEN);
if (ret == PIPE_CRC_LINE_LEN)
return -EFAULT;
- BUILD_BUG_ON_NOT_POWER_OF_2(INTEL_PIPE_CRC_ENTRIES_NR);
- tail = (tail + 1) & (INTEL_PIPE_CRC_ENTRIES_NR - 1);
- n++;
- } while (--n_entries);
+ user_buf += PIPE_CRC_LINE_LEN;
+ n_entries--;
+
+ spin_lock_irq(&pipe_crc->lock);
+ }
- spin_lock_irq(&pipe_crc->lock);
- pipe_crc->tail = tail;
spin_unlock_irq(&pipe_crc->lock);
return bytes_read;
@@ -3072,6 +3198,12 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
*val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_C_VLV;
need_stable_symbols = true;
break;
+ case INTEL_PIPE_CRC_SOURCE_DP_D:
+ if (!IS_CHERRYVIEW(dev))
+ return -EINVAL;
+ *val = PIPE_CRC_ENABLE | PIPE_CRC_SOURCE_DP_D_VLV;
+ need_stable_symbols = true;
+ break;
case INTEL_PIPE_CRC_SOURCE_NONE:
*val = 0;
break;
@@ -3092,11 +3224,19 @@ static int vlv_pipe_crc_ctl_reg(struct drm_device *dev,
uint32_t tmp = I915_READ(PORT_DFT2_G4X);
tmp |= DC_BALANCE_RESET_VLV;
- if (pipe == PIPE_A)
+ switch (pipe) {
+ case PIPE_A:
tmp |= PIPE_A_SCRAMBLE_RESET;
- else
+ break;
+ case PIPE_B:
tmp |= PIPE_B_SCRAMBLE_RESET;
-
+ break;
+ case PIPE_C:
+ tmp |= PIPE_C_SCRAMBLE_RESET;
+ break;
+ default:
+ return -EINVAL;
+ }
I915_WRITE(PORT_DFT2_G4X, tmp);
}
@@ -3185,10 +3325,19 @@ static void vlv_undo_pipe_scramble_reset(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t tmp = I915_READ(PORT_DFT2_G4X);
- if (pipe == PIPE_A)
+ switch (pipe) {
+ case PIPE_A:
tmp &= ~PIPE_A_SCRAMBLE_RESET;
- else
+ break;
+ case PIPE_B:
tmp &= ~PIPE_B_SCRAMBLE_RESET;
+ break;
+ case PIPE_C:
+ tmp &= ~PIPE_C_SCRAMBLE_RESET;
+ break;
+ default:
+ return;
+ }
if (!(tmp & PIPE_SCRAMBLE_RESET_MASK))
tmp &= ~DC_BALANCE_RESET_VLV;
I915_WRITE(PORT_DFT2_G4X, tmp);
@@ -3252,9 +3401,9 @@ static void hsw_trans_edp_pipe_A_crc_wa(struct drm_device *dev)
* relevant on hsw with pipe A when using the always-on power well
* routing.
*/
- if (crtc->config.cpu_transcoder == TRANSCODER_EDP &&
- !crtc->config.pch_pfit.enabled) {
- crtc->config.pch_pfit.force_thru = true;
+ if (crtc->config->cpu_transcoder == TRANSCODER_EDP &&
+ !crtc->config->pch_pfit.enabled) {
+ crtc->config->pch_pfit.force_thru = true;
intel_display_power_get(dev_priv,
POWER_DOMAIN_PIPE_PANEL_FITTER(PIPE_A));
@@ -3278,8 +3427,8 @@ static void hsw_undo_trans_edp_pipe_A_crc_wa(struct drm_device *dev)
* relevant on hsw with pipe A when using the always-on power well
* routing.
*/
- if (crtc->config.pch_pfit.force_thru) {
- crtc->config.pch_pfit.force_thru = false;
+ if (crtc->config->pch_pfit.force_thru) {
+ crtc->config->pch_pfit.force_thru = false;
dev_priv->display.crtc_disable(&crtc->base);
dev_priv->display.crtc_enable(&crtc->base);
@@ -3359,13 +3508,15 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
/* none -> real source transition */
if (source) {
+ struct intel_pipe_crc_entry *entries;
+
DRM_DEBUG_DRIVER("collecting CRCs for pipe %c, %s\n",
pipe_name(pipe), pipe_crc_source_name(source));
- pipe_crc->entries = kzalloc(sizeof(*pipe_crc->entries) *
- INTEL_PIPE_CRC_ENTRIES_NR,
- GFP_KERNEL);
- if (!pipe_crc->entries)
+ entries = kcalloc(INTEL_PIPE_CRC_ENTRIES_NR,
+ sizeof(pipe_crc->entries[0]),
+ GFP_KERNEL);
+ if (!entries)
return -ENOMEM;
/*
@@ -3377,6 +3528,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
hsw_disable_ips(crtc);
spin_lock_irq(&pipe_crc->lock);
+ kfree(pipe_crc->entries);
+ pipe_crc->entries = entries;
pipe_crc->head = 0;
pipe_crc->tail = 0;
spin_unlock_irq(&pipe_crc->lock);
@@ -3404,6 +3557,8 @@ static int pipe_crc_set_source(struct drm_device *dev, enum pipe pipe,
spin_lock_irq(&pipe_crc->lock);
entries = pipe_crc->entries;
pipe_crc->entries = NULL;
+ pipe_crc->head = 0;
+ pipe_crc->tail = 0;
spin_unlock_irq(&pipe_crc->lock);
kfree(entries);
@@ -3826,6 +3981,17 @@ i915_wedged_set(void *data, u64 val)
struct drm_device *dev = data;
struct drm_i915_private *dev_priv = dev->dev_private;
+ /*
+ * There is no safeguard against this debugfs entry colliding
+ * with the hangcheck calling same i915_handle_error() in
+ * parallel, causing an explosion. For now we assume that the
+ * test harness is responsible enough not to inject gpu hangs
+ * while it is writing to 'i915_wedged'
+ */
+
+ if (i915_reset_in_progress(&dev_priv->gpu_error))
+ return -EAGAIN;
+
intel_runtime_pm_get(dev_priv);
i915_handle_error(dev, val,
@@ -4012,10 +4178,7 @@ i915_max_freq_get(void *data, u64 *val)
if (ret)
return ret;
- if (IS_VALLEYVIEW(dev))
- *val = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
- else
- *val = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+ *val = intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
@@ -4044,12 +4207,12 @@ i915_max_freq_set(void *data, u64 val)
* Turbo will still be enabled, but won't go above the set value.
*/
if (IS_VALLEYVIEW(dev)) {
- val = vlv_freq_opcode(dev_priv, val);
+ val = intel_freq_opcode(dev_priv, val);
hw_max = dev_priv->rps.max_freq;
hw_min = dev_priv->rps.min_freq;
} else {
- do_div(val, GT_FREQUENCY_MULTIPLIER);
+ val = intel_freq_opcode(dev_priv, val);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = dev_priv->rps.max_freq;
@@ -4093,10 +4256,7 @@ i915_min_freq_get(void *data, u64 *val)
if (ret)
return ret;
- if (IS_VALLEYVIEW(dev))
- *val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
- else
- *val = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+ *val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
mutex_unlock(&dev_priv->rps.hw_lock);
return 0;
@@ -4125,12 +4285,12 @@ i915_min_freq_set(void *data, u64 val)
* Turbo will still be enabled, but won't go below the set value.
*/
if (IS_VALLEYVIEW(dev)) {
- val = vlv_freq_opcode(dev_priv, val);
+ val = intel_freq_opcode(dev_priv, val);
hw_max = dev_priv->rps.max_freq;
hw_min = dev_priv->rps.min_freq;
} else {
- do_div(val, GT_FREQUENCY_MULTIPLIER);
+ val = intel_freq_opcode(dev_priv, val);
rp_state_cap = I915_READ(GEN6_RP_STATE_CAP);
hw_max = dev_priv->rps.max_freq;
@@ -4222,7 +4382,8 @@ static int i915_forcewake_open(struct inode *inode, struct file *file)
if (INTEL_INFO(dev)->gen < 6)
return 0;
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_runtime_pm_get(dev_priv);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
return 0;
}
@@ -4235,7 +4396,8 @@ static int i915_forcewake_release(struct inode *inode, struct file *file)
if (INTEL_INFO(dev)->gen < 6)
return 0;
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+ intel_runtime_pm_put(dev_priv);
return 0;
}
@@ -4296,7 +4458,9 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_gem_hws_blt", i915_hws_info, 0, (void *)BCS},
{"i915_gem_hws_bsd", i915_hws_info, 0, (void *)VCS},
{"i915_gem_hws_vebox", i915_hws_info, 0, (void *)VECS},
+ {"i915_gem_batch_pool", i915_gem_batch_pool_info, 0},
{"i915_frequency_info", i915_frequency_info, 0},
+ {"i915_hangcheck_info", i915_hangcheck_info, 0},
{"i915_drpc_info", i915_drpc_info, 0},
{"i915_emon_status", i915_emon_status, 0},
{"i915_ring_freq_table", i915_ring_freq_table, 0},
@@ -4308,7 +4472,7 @@ static const struct drm_info_list i915_debugfs_list[] = {
{"i915_context_status", i915_context_status, 0},
{"i915_dump_lrc", i915_dump_lrc, 0},
{"i915_execlists", i915_execlists, 0},
- {"i915_gen6_forcewake_count", i915_gen6_forcewake_count_info, 0},
+ {"i915_forcewake_domains", i915_forcewake_domains, 0},
{"i915_swizzle_info", i915_swizzle_info, 0},
{"i915_ppgtt_info", i915_ppgtt_info, 0},
{"i915_llc", i915_llc, 0},
diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index ecee3bcc8772..1a46787129e7 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -92,6 +92,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_VEBOX:
value = intel_ring_initialized(&dev_priv->ring[VECS]);
break;
+ case I915_PARAM_HAS_BSD2:
+ value = intel_ring_initialized(&dev_priv->ring[VCS2]);
+ break;
case I915_PARAM_HAS_RELAXED_FENCING:
value = 1;
break;
@@ -143,6 +146,9 @@ static int i915_getparam(struct drm_device *dev, void *data,
case I915_PARAM_HAS_COHERENT_PHYS_GTT:
value = 1;
break;
+ case I915_PARAM_MMAP_VERSION:
+ value = 1;
+ break;
default:
DRM_DEBUG("Unknown parameter %d\n", param->param);
return -EINVAL;
@@ -598,6 +604,17 @@ static void intel_device_info_runtime_init(struct drm_device *dev)
info->num_pipes = 0;
}
}
+
+ if (IS_CHERRYVIEW(dev)) {
+ u32 fuse, mask_eu;
+
+ fuse = I915_READ(CHV_FUSE_GT);
+ mask_eu = fuse & (CHV_FGT_EU_DIS_SS0_R0_MASK |
+ CHV_FGT_EU_DIS_SS0_R1_MASK |
+ CHV_FGT_EU_DIS_SS1_R0_MASK |
+ CHV_FGT_EU_DIS_SS1_R1_MASK);
+ info->eu_total = 16 - hweight32(mask_eu);
+ }
}
/**
@@ -773,6 +790,14 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
goto out_freewq;
}
+ dev_priv->gpu_error.hangcheck_wq =
+ alloc_ordered_workqueue("i915-hangcheck", 0);
+ if (dev_priv->gpu_error.hangcheck_wq == NULL) {
+ DRM_ERROR("Failed to create our hangcheck workqueue.\n");
+ ret = -ENOMEM;
+ goto out_freedpwq;
+ }
+
intel_irq_init(dev_priv);
intel_uncore_sanitize(dev);
@@ -830,6 +855,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
intel_runtime_pm_enable(dev_priv);
+ i915_audio_component_init(dev_priv);
+
return 0;
out_power_well:
@@ -845,6 +872,8 @@ out_gem_unload:
intel_teardown_gmbus(dev);
intel_teardown_mchbar(dev);
pm_qos_remove_request(&dev_priv->pm_qos);
+ destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
+out_freedpwq:
destroy_workqueue(dev_priv->dp_wq);
out_freewq:
destroy_workqueue(dev_priv->wq);
@@ -870,6 +899,8 @@ int i915_driver_unload(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
+ i915_audio_component_cleanup(dev_priv);
+
ret = i915_gem_suspend(dev);
if (ret) {
DRM_ERROR("failed to idle hardware: %d\n", ret);
@@ -913,8 +944,7 @@ int i915_driver_unload(struct drm_device *dev)
}
/* Free error state after interrupts are fully disabled. */
- del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
- cancel_work_sync(&dev_priv->gpu_error.work);
+ cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
i915_destroy_error_state(dev);
if (dev->pdev->msi_enabled)
@@ -928,6 +958,7 @@ int i915_driver_unload(struct drm_device *dev)
mutex_lock(&dev->struct_mutex);
i915_gem_cleanup_ringbuffer(dev);
+ i915_gem_batch_pool_fini(&dev_priv->mm.batch_pool);
i915_gem_context_fini(dev);
mutex_unlock(&dev->struct_mutex);
i915_gem_cleanup_stolen(dev);
@@ -938,6 +969,7 @@ int i915_driver_unload(struct drm_device *dev)
destroy_workqueue(dev_priv->dp_wq);
destroy_workqueue(dev_priv->wq);
+ destroy_workqueue(dev_priv->gpu_error.hangcheck_wq);
pm_qos_remove_request(&dev_priv->pm_qos);
i915_global_gtt_cleanup(dev);
@@ -1004,6 +1036,13 @@ void i915_driver_postclose(struct drm_device *dev, struct drm_file *file)
kfree(file_priv);
}
+static int
+i915_gem_reject_pin_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ return -ENODEV;
+}
+
const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY),
DRM_IOCTL_DEF_DRV(I915_FLUSH, drm_noop, DRM_AUTH),
@@ -1025,8 +1064,8 @@ const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_GEM_INIT, drm_noop, DRM_AUTH|DRM_MASTER|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER, i915_gem_execbuffer, DRM_AUTH|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_EXECBUFFER2, i915_gem_execbuffer2, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
- DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
- DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_unpin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(I915_GEM_PIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
+ DRM_IOCTL_DEF_DRV(I915_GEM_UNPIN, i915_gem_reject_pin_ioctl, DRM_AUTH|DRM_ROOT_ONLY|DRM_UNLOCKED),
DRM_IOCTL_DEF_DRV(I915_GEM_BUSY, i915_gem_busy_ioctl, DRM_AUTH|DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_SET_CACHING, i915_gem_set_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_GET_CACHING, i915_gem_get_caching_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
@@ -1055,6 +1094,8 @@ const struct drm_ioctl_desc i915_ioctls[] = {
DRM_IOCTL_DEF_DRV(I915_REG_READ, i915_reg_read_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GET_RESET_STATS, i915_get_reset_stats_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
DRM_IOCTL_DEF_DRV(I915_GEM_USERPTR, i915_gem_userptr_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_GETPARAM, i915_gem_context_getparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
+ DRM_IOCTL_DEF_DRV(I915_GEM_CONTEXT_SETPARAM, i915_gem_context_setparam_ioctl, DRM_UNLOCKED|DRM_RENDER_ALLOW),
};
int i915_max_ioctl = ARRAY_SIZE(i915_ioctls);
diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index 574057cd1d09..8039cec71fc2 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -462,19 +462,13 @@ void intel_detect_pch(struct drm_device *dev)
} else if (id == INTEL_PCH_LPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_LPT;
DRM_DEBUG_KMS("Found LynxPoint PCH\n");
- WARN_ON(!IS_HASWELL(dev));
- WARN_ON(IS_HSW_ULT(dev));
- } else if (IS_BROADWELL(dev)) {
- dev_priv->pch_type = PCH_LPT;
- dev_priv->pch_id =
- INTEL_PCH_LPT_LP_DEVICE_ID_TYPE;
- DRM_DEBUG_KMS("This is Broadwell, assuming "
- "LynxPoint LP PCH\n");
+ WARN_ON(!IS_HASWELL(dev) && !IS_BROADWELL(dev));
+ WARN_ON(IS_HSW_ULT(dev) || IS_BDW_ULT(dev));
} else if (id == INTEL_PCH_LPT_LP_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_LPT;
DRM_DEBUG_KMS("Found LynxPoint LP PCH\n");
- WARN_ON(!IS_HASWELL(dev));
- WARN_ON(!IS_HSW_ULT(dev));
+ WARN_ON(!IS_HASWELL(dev) && !IS_BROADWELL(dev));
+ WARN_ON(!IS_HSW_ULT(dev) && !IS_BDW_ULT(dev));
} else if (id == INTEL_PCH_SPT_DEVICE_ID_TYPE) {
dev_priv->pch_type = PCH_SPT;
DRM_DEBUG_KMS("Found SunrisePoint PCH\n");
@@ -841,6 +835,8 @@ int i915_reset(struct drm_device *dev)
return ret;
}
+ intel_overlay_reset(dev_priv);
+
/* Ok, now get things going again... */
/*
@@ -940,8 +936,7 @@ static int i915_pm_suspend(struct device *dev)
static int i915_pm_suspend_late(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
/*
* We have a suspedn ordering issue with the snd-hda driver also
@@ -960,8 +955,7 @@ static int i915_pm_suspend_late(struct device *dev)
static int i915_pm_resume_early(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
@@ -971,8 +965,7 @@ static int i915_pm_resume_early(struct device *dev)
static int i915_pm_resume(struct device *dev)
{
- struct pci_dev *pdev = to_pci_dev(dev);
- struct drm_device *drm_dev = pci_get_drvdata(pdev);
+ struct drm_device *drm_dev = dev_to_i915(dev)->dev;
if (drm_dev->switch_power_state == DRM_SWITCH_POWER_OFF)
return 0;
@@ -1299,7 +1292,9 @@ static int vlv_suspend_complete(struct drm_i915_private *dev_priv)
err = vlv_allow_gt_wake(dev_priv, false);
if (err)
goto err2;
- vlv_save_gunit_s0ix_state(dev_priv);
+
+ if (!IS_CHERRYVIEW(dev_priv->dev))
+ vlv_save_gunit_s0ix_state(dev_priv);
err = vlv_force_gfx_clock(dev_priv, false);
if (err)
@@ -1330,7 +1325,8 @@ static int vlv_resume_prepare(struct drm_i915_private *dev_priv,
*/
ret = vlv_force_gfx_clock(dev_priv, true);
- vlv_restore_gunit_s0ix_state(dev_priv);
+ if (!IS_CHERRYVIEW(dev_priv->dev))
+ vlv_restore_gunit_s0ix_state(dev_priv);
err = vlv_allow_gt_wake(dev_priv, true);
if (!ret)
@@ -1363,8 +1359,6 @@ static int intel_runtime_suspend(struct device *device)
if (WARN_ON_ONCE(!HAS_RUNTIME_PM(dev)))
return -ENODEV;
- assert_force_wake_inactive(dev_priv);
-
DRM_DEBUG_KMS("Suspending device\n");
/*
@@ -1402,7 +1396,8 @@ static int intel_runtime_suspend(struct device *device)
return ret;
}
- del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
+ cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
+ intel_uncore_forcewake_reset(dev, false);
dev_priv->pm.suspended = true;
/*
@@ -1430,6 +1425,8 @@ static int intel_runtime_suspend(struct device *device)
intel_opregion_notify_adapter(dev, PCI_D3hot);
}
+ assert_forcewakes_inactive(dev_priv);
+
DRM_DEBUG_KMS("Device suspended\n");
return 0;
}
@@ -1640,6 +1637,14 @@ static int __init i915_init(void)
#endif
}
+ /*
+ * FIXME: Note that we're lying to the DRM core here so that we can get access
+ * to the atomic ioctl and the atomic properties. Only plane operations on
+ * a single CRTC will actually work.
+ */
+ if (i915.nuclear_pageflip)
+ driver.driver_features |= DRIVER_ATOMIC;
+
return drm_pci_init(&driver, &i915_pci_driver);
}
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index e9f891c432f8..8727086cf48c 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -55,10 +55,51 @@
#define DRIVER_NAME "i915"
#define DRIVER_DESC "Intel Graphics"
-#define DRIVER_DATE "20141121"
+#define DRIVER_DATE "20150130"
#undef WARN_ON
-#define WARN_ON(x) WARN(x, "WARN_ON(" #x ")")
+/* Many gcc seem to no see through this and fall over :( */
+#if 0
+#define WARN_ON(x) ({ \
+ bool __i915_warn_cond = (x); \
+ if (__builtin_constant_p(__i915_warn_cond)) \
+ BUILD_BUG_ON(__i915_warn_cond); \
+ WARN(__i915_warn_cond, "WARN_ON(" #x ")"); })
+#else
+#define WARN_ON(x) WARN((x), "WARN_ON(" #x ")")
+#endif
+
+#define MISSING_CASE(x) WARN(1, "Missing switch case (%lu) in %s\n", \
+ (long) (x), __func__);
+
+/* Use I915_STATE_WARN(x) and I915_STATE_WARN_ON() (rather than WARN() and
+ * WARN_ON()) for hw state sanity checks to check for unexpected conditions
+ * which may not necessarily be a user visible problem. This will either
+ * WARN() or DRM_ERROR() depending on the verbose_checks moduleparam, to
+ * enable distros and users to tailor their preferred amount of i915 abrt
+ * spam.
+ */
+#define I915_STATE_WARN(condition, format...) ({ \
+ int __ret_warn_on = !!(condition); \
+ if (unlikely(__ret_warn_on)) { \
+ if (i915.verbose_state_checks) \
+ WARN(1, format); \
+ else \
+ DRM_ERROR(format); \
+ } \
+ unlikely(__ret_warn_on); \
+})
+
+#define I915_STATE_WARN_ON(condition) ({ \
+ int __ret_warn_on = !!(condition); \
+ if (unlikely(__ret_warn_on)) { \
+ if (i915.verbose_state_checks) \
+ WARN(1, "WARN_ON(" #condition ")\n"); \
+ else \
+ DRM_ERROR("WARN_ON(" #condition ")\n"); \
+ } \
+ unlikely(__ret_warn_on); \
+})
enum pipe {
INVALID_PIPE = -1,
@@ -143,6 +184,10 @@ enum intel_display_power_domain {
POWER_DOMAIN_VGA,
POWER_DOMAIN_AUDIO,
POWER_DOMAIN_PLLS,
+ POWER_DOMAIN_AUX_A,
+ POWER_DOMAIN_AUX_B,
+ POWER_DOMAIN_AUX_C,
+ POWER_DOMAIN_AUX_D,
POWER_DOMAIN_INIT,
POWER_DOMAIN_NUM,
@@ -458,8 +503,8 @@ struct drm_i915_error_state {
struct intel_connector;
struct intel_encoder;
-struct intel_crtc_config;
-struct intel_plane_config;
+struct intel_crtc_state;
+struct intel_initial_plane_config;
struct intel_crtc;
struct intel_limit;
struct dpll;
@@ -497,10 +542,11 @@ struct drm_i915_display_funcs {
/* Returns the active state of the crtc, and if the crtc is active,
* fills out the pipe-config with the hw state. */
bool (*get_pipe_config)(struct intel_crtc *,
- struct intel_crtc_config *);
- void (*get_plane_config)(struct intel_crtc *,
- struct intel_plane_config *);
- int (*crtc_compute_clock)(struct intel_crtc *crtc);
+ struct intel_crtc_state *);
+ void (*get_initial_plane_config)(struct intel_crtc *,
+ struct intel_initial_plane_config *);
+ int (*crtc_compute_clock)(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state);
void (*crtc_enable)(struct drm_crtc *crtc);
void (*crtc_disable)(struct drm_crtc *crtc);
void (*off)(struct drm_crtc *crtc);
@@ -533,11 +579,28 @@ struct drm_i915_display_funcs {
void (*enable_backlight)(struct intel_connector *connector);
};
+enum forcewake_domain_id {
+ FW_DOMAIN_ID_RENDER = 0,
+ FW_DOMAIN_ID_BLITTER,
+ FW_DOMAIN_ID_MEDIA,
+
+ FW_DOMAIN_ID_COUNT
+};
+
+enum forcewake_domains {
+ FORCEWAKE_RENDER = (1 << FW_DOMAIN_ID_RENDER),
+ FORCEWAKE_BLITTER = (1 << FW_DOMAIN_ID_BLITTER),
+ FORCEWAKE_MEDIA = (1 << FW_DOMAIN_ID_MEDIA),
+ FORCEWAKE_ALL = (FORCEWAKE_RENDER |
+ FORCEWAKE_BLITTER |
+ FORCEWAKE_MEDIA)
+};
+
struct intel_uncore_funcs {
void (*force_wake_get)(struct drm_i915_private *dev_priv,
- int fw_engine);
+ enum forcewake_domains domains);
void (*force_wake_put)(struct drm_i915_private *dev_priv,
- int fw_engine);
+ enum forcewake_domains domains);
uint8_t (*mmio_readb)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
uint16_t (*mmio_readw)(struct drm_i915_private *dev_priv, off_t offset, bool trace);
@@ -560,14 +623,31 @@ struct intel_uncore {
struct intel_uncore_funcs funcs;
unsigned fifo_count;
- unsigned forcewake_count;
-
- unsigned fw_rendercount;
- unsigned fw_mediacount;
- unsigned fw_blittercount;
-
- struct timer_list force_wake_timer;
-};
+ enum forcewake_domains fw_domains;
+
+ struct intel_uncore_forcewake_domain {
+ struct drm_i915_private *i915;
+ enum forcewake_domain_id id;
+ unsigned wake_count;
+ struct timer_list timer;
+ u32 reg_set;
+ u32 val_set;
+ u32 val_clear;
+ u32 reg_ack;
+ u32 reg_post;
+ u32 val_reset;
+ } fw_domain[FW_DOMAIN_ID_COUNT];
+};
+
+/* Iterate over initialised fw domains */
+#define for_each_fw_domain_mask(domain__, mask__, dev_priv__, i__) \
+ for ((i__) = 0, (domain__) = &(dev_priv__)->uncore.fw_domain[0]; \
+ (i__) < FW_DOMAIN_ID_COUNT; \
+ (i__)++, (domain__) = &(dev_priv__)->uncore.fw_domain[i__]) \
+ if (((mask__) & (dev_priv__)->uncore.fw_domains) & (1 << (i__)))
+
+#define for_each_fw_domain(domain__, dev_priv__, i__) \
+ for_each_fw_domain_mask(domain__, FORCEWAKE_ALL, dev_priv__, i__)
#define DEV_INFO_FOR_EACH_FLAG(func, sep) \
func(is_mobile) sep \
@@ -612,6 +692,7 @@ struct intel_device_info {
int trans_offsets[I915_MAX_TRANSCODERS];
int palette_offsets[I915_MAX_PIPES];
int cursor_offsets[I915_MAX_PIPES];
+ unsigned int eu_total;
};
#undef DEFINE_FLAG
@@ -637,6 +718,11 @@ struct i915_ctx_hang_stats {
/* Time when this context was last blamed for a GPU reset */
unsigned long guilty_ts;
+ /* If the contexts causes a second GPU hang within this time,
+ * it is permanently banned from submitting any more work.
+ */
+ unsigned long ban_period_seconds;
+
/* This context is banned to submit more work */
bool banned;
};
@@ -679,7 +765,7 @@ struct intel_context {
struct {
struct drm_i915_gem_object *state;
struct intel_ringbuffer *ringbuf;
- int unpin_count;
+ int pin_count;
} engine[I915_NUM_RINGS];
struct list_head link;
@@ -730,11 +816,33 @@ struct i915_fbc {
} no_fbc_reason;
};
-struct i915_drrs {
- struct intel_connector *connector;
+/**
+ * HIGH_RR is the highest eDP panel refresh rate read from EDID
+ * LOW_RR is the lowest eDP panel refresh rate found from EDID
+ * parsing for same resolution.
+ */
+enum drrs_refresh_rate_type {
+ DRRS_HIGH_RR,
+ DRRS_LOW_RR,
+ DRRS_MAX_RR, /* RR count */
+};
+
+enum drrs_support_type {
+ DRRS_NOT_SUPPORTED = 0,
+ STATIC_DRRS_SUPPORT = 1,
+ SEAMLESS_DRRS_SUPPORT = 2
};
struct intel_dp;
+struct i915_drrs {
+ struct mutex mutex;
+ struct delayed_work work;
+ struct intel_dp *dp;
+ unsigned busy_frontbuffer_bits;
+ enum drrs_refresh_rate_type refresh_rate_type;
+ enum drrs_support_type type;
+};
+
struct i915_psr {
struct mutex lock;
bool sink_support;
@@ -743,6 +851,7 @@ struct i915_psr {
bool active;
struct delayed_work work;
unsigned busy_frontbuffer_bits;
+ bool link_standby;
};
enum intel_pch {
@@ -1130,6 +1239,11 @@ struct intel_l3_parity {
int which_slice;
};
+struct i915_gem_batch_pool {
+ struct drm_device *dev;
+ struct list_head cache_list;
+};
+
struct i915_gem_mm {
/** Memory allocator for GTT stolen memory */
struct drm_mm stolen;
@@ -1143,6 +1257,13 @@ struct i915_gem_mm {
*/
struct list_head unbound_list;
+ /*
+ * A pool of objects to use as shadow copies of client batch buffers
+ * when the command parser is enabled. Prevents the client from
+ * modifying the batch contents after software parsing.
+ */
+ struct i915_gem_batch_pool batch_pool;
+
/** Usable portion of the GTT for GEM */
unsigned long stolen_base; /* limited to low memory (32-bit) */
@@ -1224,14 +1345,13 @@ struct i915_gpu_error {
/* Hang gpu twice in this window and your context gets banned */
#define DRM_I915_CTX_BAN_PERIOD DIV_ROUND_UP(8*DRM_I915_HANGCHECK_PERIOD, 1000)
- struct timer_list hangcheck_timer;
+ struct workqueue_struct *hangcheck_wq;
+ struct delayed_work hangcheck_work;
/* For reset and error_state handling. */
spinlock_t lock;
/* Protected by the above dev->gpu_error.lock. */
struct drm_i915_error_state *first_error;
- struct work_struct work;
-
unsigned long missed_irq_rings;
@@ -1301,10 +1421,11 @@ struct ddi_vbt_port_info {
uint8_t supports_dp:1;
};
-enum drrs_support_type {
- DRRS_NOT_SUPPORTED = 0,
- STATIC_DRRS_SUPPORT = 1,
- SEAMLESS_DRRS_SUPPORT = 2
+enum psr_lines_to_wait {
+ PSR_0_LINES_TO_WAIT = 0,
+ PSR_1_LINE_TO_WAIT,
+ PSR_4_LINES_TO_WAIT,
+ PSR_8_LINES_TO_WAIT
};
struct intel_vbt_data {
@@ -1336,6 +1457,15 @@ struct intel_vbt_data {
struct edp_power_seq edp_pps;
struct {
+ bool full_link;
+ bool require_aux_wakeup;
+ int idle_frames;
+ enum psr_lines_to_wait lines_to_wait;
+ int tp1_wakeup_time;
+ int tp2_tp3_wakeup_time;
+ } psr;
+
+ struct {
u16 pwm_freq_hz;
bool present;
bool active_low_pwm;
@@ -1698,6 +1828,9 @@ struct drm_i915_private {
struct drm_property *broadcast_rgb_property;
struct drm_property *force_audio_property;
+ /* hda/i915 audio component */
+ bool audio_component_registered;
+
uint32_t hw_context_size;
struct list_head context_list;
@@ -1770,6 +1903,8 @@ struct drm_i915_private {
void (*stop_ring)(struct intel_engine_cs *ring);
} gt;
+ uint32_t request_uniq;
+
/*
* NOTE: This is the dri1/ums dungeon, don't add stuff here. Your patch
* will be rejected. Instead look for a better place.
@@ -1781,6 +1916,11 @@ static inline struct drm_i915_private *to_i915(const struct drm_device *dev)
return dev->dev_private;
}
+static inline struct drm_i915_private *dev_to_i915(struct device *dev)
+{
+ return to_i915(dev_get_drvdata(dev));
+}
+
/* Iterate over initialised rings */
#define for_each_ring(ring__, dev_priv__, i__) \
for ((i__) = 0; (i__) < I915_NUM_RINGS; (i__)++) \
@@ -1853,6 +1993,8 @@ struct drm_i915_gem_object {
/** Used in execbuf to temporarily hold a ref */
struct list_head obj_exec_link;
+ struct list_head batch_pool_list;
+
/**
* This is set if the object is on the active lists (has pending
* rendering and so a non-zero seqno), and is not set if it i s on
@@ -1912,6 +2054,7 @@ struct drm_i915_gem_object {
*/
unsigned long gt_ro:1;
unsigned int cache_level:3;
+ unsigned int cache_dirty:1;
unsigned int has_dma_mapping:1;
@@ -1924,13 +2067,11 @@ struct drm_i915_gem_object {
void *dma_buf_vmapping;
int vmapping_count;
- struct intel_engine_cs *ring;
-
/** Breadcrumb of last rendering to the buffer. */
- uint32_t last_read_seqno;
- uint32_t last_write_seqno;
+ struct drm_i915_gem_request *last_read_req;
+ struct drm_i915_gem_request *last_write_req;
/** Breadcrumb of last fenced GPU access to the buffer. */
- uint32_t last_fenced_seqno;
+ struct drm_i915_gem_request *last_fenced_req;
/** Current tiling stride for the object, if it's tiled. */
uint32_t stride;
@@ -1941,10 +2082,6 @@ struct drm_i915_gem_object {
/** Record of address bit 17 of each page at last unbind. */
unsigned long *bit_17;
- /** User space pin count and filp owning the pin */
- unsigned long user_pin_count;
- struct drm_file *pin_filp;
-
union {
/** for phy allocated objects */
struct drm_dma_handle *phys_handle;
@@ -1973,11 +2110,17 @@ void i915_gem_track_fb(struct drm_i915_gem_object *old,
* The request queue allows us to note sequence numbers that have been emitted
* and may be associated with active buffers to be retired.
*
- * By keeping this list, we can avoid having to do questionable
- * sequence-number comparisons on buffer last_rendering_seqnos, and associate
- * an emission time with seqnos for tracking how far ahead of the GPU we are.
+ * By keeping this list, we can avoid having to do questionable sequence
+ * number comparisons on buffer last_read|write_seqno. It also allows an
+ * emission time to be associated with the request for tracking how far ahead
+ * of the GPU the submission is.
+ *
+ * The requests are reference counted, so upon creation they should have an
+ * initial reference taken using kref_init
*/
struct drm_i915_gem_request {
+ struct kref ref;
+
/** On Which ring this request was generated */
struct intel_engine_cs *ring;
@@ -1987,10 +2130,26 @@ struct drm_i915_gem_request {
/** Position in the ringbuffer of the start of the request */
u32 head;
- /** Position in the ringbuffer of the end of the request */
+ /**
+ * Position in the ringbuffer of the start of the postfix.
+ * This is required to calculate the maximum available ringbuffer
+ * space without overwriting the postfix.
+ */
+ u32 postfix;
+
+ /** Position in the ringbuffer of the end of the whole request */
u32 tail;
- /** Context related to this request */
+ /**
+ * Context related to this request
+ * Contexts are refcounted, so when this request is associated with a
+ * context, we must increment the context's refcount, to guarantee that
+ * it persists while any request is linked to it. Requests themselves
+ * are also refcounted, so the request will only be freed when the last
+ * reference to it is dismissed, and the code in
+ * i915_gem_request_free() will then decrement the refcount on the
+ * context.
+ */
struct intel_context *ctx;
/** Batch buffer related to this request if any */
@@ -2005,8 +2164,75 @@ struct drm_i915_gem_request {
struct drm_i915_file_private *file_priv;
/** file_priv list entry for this request */
struct list_head client_list;
+
+ uint32_t uniq;
+
+ /**
+ * The ELSP only accepts two elements at a time, so we queue
+ * context/tail pairs on a given queue (ring->execlist_queue) until the
+ * hardware is available. The queue serves a double purpose: we also use
+ * it to keep track of the up to 2 contexts currently in the hardware
+ * (usually one in execution and the other queued up by the GPU): We
+ * only remove elements from the head of the queue when the hardware
+ * informs us that an element has been completed.
+ *
+ * All accesses to the queue are mediated by a spinlock
+ * (ring->execlist_lock).
+ */
+
+ /** Execlist link in the submission queue.*/
+ struct list_head execlist_link;
+
+ /** Execlists no. of times this request has been sent to the ELSP */
+ int elsp_submitted;
+
};
+void i915_gem_request_free(struct kref *req_ref);
+
+static inline uint32_t
+i915_gem_request_get_seqno(struct drm_i915_gem_request *req)
+{
+ return req ? req->seqno : 0;
+}
+
+static inline struct intel_engine_cs *
+i915_gem_request_get_ring(struct drm_i915_gem_request *req)
+{
+ return req ? req->ring : NULL;
+}
+
+static inline void
+i915_gem_request_reference(struct drm_i915_gem_request *req)
+{
+ kref_get(&req->ref);
+}
+
+static inline void
+i915_gem_request_unreference(struct drm_i915_gem_request *req)
+{
+ WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
+ kref_put(&req->ref, i915_gem_request_free);
+}
+
+static inline void i915_gem_request_assign(struct drm_i915_gem_request **pdst,
+ struct drm_i915_gem_request *src)
+{
+ if (src)
+ i915_gem_request_reference(src);
+
+ if (*pdst)
+ i915_gem_request_unreference(*pdst);
+
+ *pdst = src;
+}
+
+/*
+ * XXX: i915_gem_request_completed should be here but currently needs the
+ * definition of i915_seqno_passed() which is below. It will be moved in
+ * a later patch when the call to i915_seqno_passed() is obsoleted...
+ */
+
struct drm_i915_file_private {
struct drm_i915_private *dev_priv;
struct drm_file *file;
@@ -2159,8 +2385,8 @@ struct drm_i915_cmd_table {
#define IS_HSW_EARLY_SDV(dev) (IS_HASWELL(dev) && \
(INTEL_DEVID(dev) & 0xFF00) == 0x0C00)
#define IS_BDW_ULT(dev) (IS_BROADWELL(dev) && \
- ((INTEL_DEVID(dev) & 0xf) == 0x2 || \
- (INTEL_DEVID(dev) & 0xf) == 0x6 || \
+ ((INTEL_DEVID(dev) & 0xf) == 0x6 || \
+ (INTEL_DEVID(dev) & 0xf) == 0xb || \
(INTEL_DEVID(dev) & 0xf) == 0xe))
#define IS_BDW_GT3(dev) (IS_BROADWELL(dev) && \
(INTEL_DEVID(dev) & 0x00F0) == 0x0020)
@@ -2240,7 +2466,9 @@ struct drm_i915_cmd_table {
#define HAS_DDI(dev) (INTEL_INFO(dev)->has_ddi)
#define HAS_FPGA_DBG_UNCLAIMED(dev) (INTEL_INFO(dev)->has_fpga_dbg)
-#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev))
+#define HAS_PSR(dev) (IS_HASWELL(dev) || IS_BROADWELL(dev) || \
+ IS_VALLEYVIEW(dev) || IS_CHERRYVIEW(dev) || \
+ IS_SKYLAKE(dev))
#define HAS_RUNTIME_PM(dev) (IS_GEN6(dev) || IS_HASWELL(dev) || \
IS_BROADWELL(dev) || IS_VALLEYVIEW(dev))
#define HAS_RC6(dev) (INTEL_INFO(dev)->gen >= 6)
@@ -2310,6 +2538,8 @@ struct i915_params {
bool disable_vtd_wa;
int use_mmio_flip;
bool mmio_debug;
+ bool verbose_state_checks;
+ bool nuclear_pageflip;
};
extern struct i915_params i915 __read_mostly;
@@ -2354,6 +2584,12 @@ extern void intel_uncore_init(struct drm_device *dev);
extern void intel_uncore_check_errors(struct drm_device *dev);
extern void intel_uncore_fini(struct drm_device *dev);
extern void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore);
+const char *intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id);
+void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
+ enum forcewake_domains domains);
+void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
+ enum forcewake_domains domains);
+void assert_forcewakes_inactive(struct drm_i915_private *dev_priv);
void
i915_enable_pipestat(struct drm_i915_private *dev_priv, enum pipe pipe,
@@ -2410,10 +2646,6 @@ int i915_gem_execbuffer(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_execbuffer2(struct drm_device *dev, void *data,
struct drm_file *file_priv);
-int i915_gem_pin_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
-int i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file_priv);
int i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int i915_gem_get_caching_ioctl(struct drm_device *dev, void *data,
@@ -2458,10 +2690,23 @@ void i915_gem_vma_destroy(struct i915_vma *vma);
#define PIN_GLOBAL 0x4
#define PIN_OFFSET_BIAS 0x8
#define PIN_OFFSET_MASK (~4095)
+int __must_check i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ uint32_t alignment,
+ uint64_t flags,
+ const struct i915_ggtt_view *view);
+static inline
int __must_check i915_gem_object_pin(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
uint32_t alignment,
- uint64_t flags);
+ uint64_t flags)
+{
+ return i915_gem_object_pin_view(obj, vm, alignment, flags,
+ &i915_ggtt_view_normal);
+}
+
+int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
+ u32 flags);
int __must_check i915_vma_unbind(struct i915_vma *vma);
int i915_gem_object_put_pages(struct drm_i915_gem_object *obj);
void i915_gem_release_all_mmaps(struct drm_i915_private *dev_priv);
@@ -2510,6 +2755,18 @@ i915_seqno_passed(uint32_t seq1, uint32_t seq2)
return (int32_t)(seq1 - seq2) >= 0;
}
+static inline bool i915_gem_request_completed(struct drm_i915_gem_request *req,
+ bool lazy_coherency)
+{
+ u32 seqno;
+
+ BUG_ON(req == NULL);
+
+ seqno = req->ring->get_seqno(req->ring, lazy_coherency);
+
+ return i915_seqno_passed(seqno, req->seqno);
+}
+
int __must_check i915_gem_get_seqno(struct drm_device *dev, u32 *seqno);
int __must_check i915_gem_set_seqno(struct drm_device *dev, u32 seqno);
int __must_check i915_gem_object_get_fence(struct drm_i915_gem_object *obj);
@@ -2525,7 +2782,7 @@ bool i915_gem_retire_requests(struct drm_device *dev);
void i915_gem_retire_requests_ring(struct intel_engine_cs *ring);
int __must_check i915_gem_check_wedge(struct i915_gpu_error *error,
bool interruptible);
-int __must_check i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno);
+int __must_check i915_gem_check_olr(struct drm_i915_gem_request *req);
static inline bool i915_reset_in_progress(struct i915_gpu_error *error)
{
@@ -2568,17 +2825,15 @@ int __must_check i915_gpu_idle(struct drm_device *dev);
int __must_check i915_gem_suspend(struct drm_device *dev);
int __i915_add_request(struct intel_engine_cs *ring,
struct drm_file *file,
- struct drm_i915_gem_object *batch_obj,
- u32 *seqno);
-#define i915_add_request(ring, seqno) \
- __i915_add_request(ring, NULL, NULL, seqno)
-int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
+ struct drm_i915_gem_object *batch_obj);
+#define i915_add_request(ring) \
+ __i915_add_request(ring, NULL, NULL)
+int __i915_wait_request(struct drm_i915_gem_request *req,
unsigned reset_counter,
bool interruptible,
s64 *timeout,
struct drm_i915_file_private *file_priv);
-int __must_check i915_wait_seqno(struct intel_engine_cs *ring,
- uint32_t seqno);
+int __must_check i915_wait_request(struct drm_i915_gem_request *req);
int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
int __must_check
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj,
@@ -2612,18 +2867,51 @@ struct dma_buf *i915_gem_prime_export(struct drm_device *dev,
void i915_gem_restore_fences(struct drm_device *dev);
+unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
+ struct i915_address_space *vm,
+ enum i915_ggtt_view_type view);
+static inline
unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
- struct i915_address_space *vm);
+ struct i915_address_space *vm)
+{
+ return i915_gem_obj_offset_view(o, vm, I915_GGTT_VIEW_NORMAL);
+}
bool i915_gem_obj_bound_any(struct drm_i915_gem_object *o);
+bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
+ struct i915_address_space *vm,
+ enum i915_ggtt_view_type view);
+static inline
bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
- struct i915_address_space *vm);
+ struct i915_address_space *vm)
+{
+ return i915_gem_obj_bound_view(o, vm, I915_GGTT_VIEW_NORMAL);
+}
+
unsigned long i915_gem_obj_size(struct drm_i915_gem_object *o,
struct i915_address_space *vm);
+struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view);
+static inline
struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm);
+ struct i915_address_space *vm)
+{
+ return i915_gem_obj_to_vma_view(obj, vm, &i915_ggtt_view_normal);
+}
+
+struct i915_vma *
+i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view);
+
+static inline
struct i915_vma *
i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm);
+ struct i915_address_space *vm)
+{
+ return i915_gem_obj_lookup_or_create_vma_view(obj, vm,
+ &i915_ggtt_view_normal);
+}
struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj);
static inline bool i915_gem_obj_is_pinned(struct drm_i915_gem_object *obj) {
@@ -2720,6 +3008,10 @@ int i915_gem_context_create_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file);
+int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
+int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file_priv);
/* i915_gem_evict.c */
int __must_check i915_gem_evict_something(struct drm_device *dev,
@@ -2805,6 +3097,13 @@ void i915_destroy_error_state(struct drm_device *dev);
void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone);
const char *i915_cache_level_str(struct drm_i915_private *i915, int type);
+/* i915_gem_batch_pool.c */
+void i915_gem_batch_pool_init(struct drm_device *dev,
+ struct i915_gem_batch_pool *pool);
+void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool);
+struct drm_i915_gem_object*
+i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool, size_t size);
+
/* i915_cmd_parser.c */
int i915_cmd_parser_get_version(void);
int i915_cmd_parser_init_ring(struct intel_engine_cs *ring);
@@ -2812,7 +3111,9 @@ void i915_cmd_parser_fini_ring(struct intel_engine_cs *ring);
bool i915_needs_cmd_parser(struct intel_engine_cs *ring);
int i915_parse_cmds(struct intel_engine_cs *ring,
struct drm_i915_gem_object *batch_obj,
+ struct drm_i915_gem_object *shadow_batch_obj,
u32 batch_start_offset,
+ u32 batch_len,
bool is_master);
/* i915_suspend.c */
@@ -2892,9 +3193,6 @@ extern void intel_modeset_setup_hw_state(struct drm_device *dev,
bool force_restore);
extern void i915_redisable_vga(struct drm_device *dev);
extern void i915_redisable_vga_power_on(struct drm_device *dev);
-extern bool intel_fbc_enabled(struct drm_device *dev);
-extern void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
-extern void intel_disable_fbc(struct drm_device *dev);
extern bool ironlake_set_drps(struct drm_device *dev, u8 val);
extern void intel_init_pch_refclk(struct drm_device *dev);
extern void gen6_set_rps(struct drm_device *dev, u8 val);
@@ -2923,20 +3221,12 @@ extern void intel_display_print_error_state(struct drm_i915_error_state_buf *e,
struct drm_device *dev,
struct intel_display_error_state *error);
-/* On SNB platform, before reading ring registers forcewake bit
- * must be set to prevent GT core from power down and stale values being
- * returned.
- */
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine);
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine);
-void assert_force_wake_inactive(struct drm_i915_private *dev_priv);
-
int sandybridge_pcode_read(struct drm_i915_private *dev_priv, u32 mbox, u32 *val);
int sandybridge_pcode_write(struct drm_i915_private *dev_priv, u32 mbox, u32 val);
/* intel_sideband.c */
-u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr);
-void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val);
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr);
+void vlv_punit_write(struct drm_i915_private *dev_priv, u32 addr, u32 val);
u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr);
u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg);
void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
@@ -2957,15 +3247,8 @@ void intel_sbi_write(struct drm_i915_private *dev_priv, u16 reg, u32 value,
u32 vlv_flisdsi_read(struct drm_i915_private *dev_priv, u32 reg);
void vlv_flisdsi_write(struct drm_i915_private *dev_priv, u32 reg, u32 val);
-int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val);
-int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val);
-
-#define FORCEWAKE_RENDER (1 << 0)
-#define FORCEWAKE_MEDIA (1 << 1)
-#define FORCEWAKE_BLITTER (1 << 2)
-#define FORCEWAKE_ALL (FORCEWAKE_RENDER | FORCEWAKE_MEDIA | \
- FORCEWAKE_BLITTER)
-
+int intel_gpu_freq(struct drm_i915_private *dev_priv, int val);
+int intel_freq_opcode(struct drm_i915_private *dev_priv, int val);
#define I915_READ8(reg) dev_priv->uncore.funcs.mmio_readb(dev_priv, (reg), true)
#define I915_WRITE8(reg, val) dev_priv->uncore.funcs.mmio_writeb(dev_priv, (reg), (val), true)
@@ -3070,4 +3353,11 @@ wait_remaining_ms_from_jiffies(unsigned long timestamp_jiffies, int to_wait_ms)
}
}
+static inline void i915_trace_irq_get(struct intel_engine_cs *ring,
+ struct drm_i915_gem_request *req)
+{
+ if (ring->trace_irq_req == NULL && ring->irq_get(ring))
+ i915_gem_request_assign(&ring->trace_irq_req, req);
+}
+
#endif
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 76354d3ba925..e5daad5f75fb 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -39,8 +39,7 @@
#include <linux/dma-buf.h>
static void i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj);
-static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
- bool force);
+static void i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj);
static __must_check int
i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
bool readonly);
@@ -153,12 +152,6 @@ int i915_mutex_lock_interruptible(struct drm_device *dev)
return 0;
}
-static inline bool
-i915_gem_object_is_inactive(struct drm_i915_gem_object *obj)
-{
- return i915_gem_obj_bound_any(obj) && !obj->active;
-}
-
int
i915_gem_get_aperture_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
@@ -1157,19 +1150,18 @@ i915_gem_check_wedge(struct i915_gpu_error *error,
}
/*
- * Compare seqno against outstanding lazy request. Emit a request if they are
- * equal.
+ * Compare arbitrary request against outstanding lazy request. Emit on match.
*/
int
-i915_gem_check_olr(struct intel_engine_cs *ring, u32 seqno)
+i915_gem_check_olr(struct drm_i915_gem_request *req)
{
int ret;
- BUG_ON(!mutex_is_locked(&ring->dev->struct_mutex));
+ WARN_ON(!mutex_is_locked(&req->ring->dev->struct_mutex));
ret = 0;
- if (seqno == ring->outstanding_lazy_seqno)
- ret = i915_add_request(ring, NULL);
+ if (req == req->ring->outstanding_lazy_request)
+ ret = i915_add_request(req->ring);
return ret;
}
@@ -1194,10 +1186,9 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv)
}
/**
- * __i915_wait_seqno - wait until execution of seqno has finished
- * @ring: the ring expected to report seqno
- * @seqno: duh!
- * @reset_counter: reset sequence associated with the given seqno
+ * __i915_wait_request - wait until execution of request has finished
+ * @req: duh!
+ * @reset_counter: reset sequence associated with the given request
* @interruptible: do an interruptible wait (normally yes)
* @timeout: in - how long to wait (NULL forever); out - how much time remaining
*
@@ -1208,15 +1199,16 @@ static bool can_wait_boost(struct drm_i915_file_private *file_priv)
* reset_counter _must_ be read before, and an appropriate smp_rmb must be
* inserted.
*
- * Returns 0 if the seqno was found within the alloted time. Else returns the
+ * Returns 0 if the request was found within the alloted time. Else returns the
* errno with remaining time filled in timeout argument.
*/
-int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
+int __i915_wait_request(struct drm_i915_gem_request *req,
unsigned reset_counter,
bool interruptible,
s64 *timeout,
struct drm_i915_file_private *file_priv)
{
+ struct intel_engine_cs *ring = i915_gem_request_get_ring(req);
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
const bool irq_test_in_progress =
@@ -1228,7 +1220,7 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
WARN(!intel_irqs_enabled(dev_priv), "IRQs disabled");
- if (i915_seqno_passed(ring->get_seqno(ring, true), seqno))
+ if (i915_gem_request_completed(req, true))
return 0;
timeout_expire = timeout ?
@@ -1246,7 +1238,7 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
return -ENODEV;
/* Record current time in case interrupted by signal, or wedged */
- trace_i915_gem_request_wait_begin(ring, seqno);
+ trace_i915_gem_request_wait_begin(req);
before = ktime_get_raw_ns();
for (;;) {
struct timer_list timer;
@@ -1265,7 +1257,7 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
break;
}
- if (i915_seqno_passed(ring->get_seqno(ring, false), seqno)) {
+ if (i915_gem_request_completed(req, false)) {
ret = 0;
break;
}
@@ -1297,7 +1289,7 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
}
}
now = ktime_get_raw_ns();
- trace_i915_gem_request_wait_end(ring, seqno);
+ trace_i915_gem_request_wait_end(req);
if (!irq_test_in_progress)
ring->irq_put(ring);
@@ -1324,32 +1316,40 @@ int __i915_wait_seqno(struct intel_engine_cs *ring, u32 seqno,
}
/**
- * Waits for a sequence number to be signaled, and cleans up the
+ * Waits for a request to be signaled, and cleans up the
* request and object lists appropriately for that event.
*/
int
-i915_wait_seqno(struct intel_engine_cs *ring, uint32_t seqno)
+i915_wait_request(struct drm_i915_gem_request *req)
{
- struct drm_device *dev = ring->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- bool interruptible = dev_priv->mm.interruptible;
+ struct drm_device *dev;
+ struct drm_i915_private *dev_priv;
+ bool interruptible;
unsigned reset_counter;
int ret;
+ BUG_ON(req == NULL);
+
+ dev = req->ring->dev;
+ dev_priv = dev->dev_private;
+ interruptible = dev_priv->mm.interruptible;
+
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
- BUG_ON(seqno == 0);
ret = i915_gem_check_wedge(&dev_priv->gpu_error, interruptible);
if (ret)
return ret;
- ret = i915_gem_check_olr(ring, seqno);
+ ret = i915_gem_check_olr(req);
if (ret)
return ret;
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
- return __i915_wait_seqno(ring, seqno, reset_counter, interruptible,
- NULL, NULL);
+ i915_gem_request_reference(req);
+ ret = __i915_wait_request(req, reset_counter,
+ interruptible, NULL, NULL);
+ i915_gem_request_unreference(req);
+ return ret;
}
static int
@@ -1361,11 +1361,11 @@ i915_gem_object_wait_rendering__tail(struct drm_i915_gem_object *obj)
/* Manually manage the write flush as we may have not yet
* retired the buffer.
*
- * Note that the last_write_seqno is always the earlier of
- * the two (read/write) seqno, so if we haved successfully waited,
+ * Note that the last_write_req is always the earlier of
+ * the two (read/write) requests, so if we haved successfully waited,
* we know we have passed the last write.
*/
- obj->last_write_seqno = 0;
+ i915_gem_request_assign(&obj->last_write_req, NULL);
return 0;
}
@@ -1378,15 +1378,14 @@ static __must_check int
i915_gem_object_wait_rendering(struct drm_i915_gem_object *obj,
bool readonly)
{
- struct intel_engine_cs *ring = obj->ring;
- u32 seqno;
+ struct drm_i915_gem_request *req;
int ret;
- seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
- if (seqno == 0)
+ req = readonly ? obj->last_write_req : obj->last_read_req;
+ if (!req)
return 0;
- ret = i915_wait_seqno(ring, seqno);
+ ret = i915_wait_request(req);
if (ret)
return ret;
@@ -1401,33 +1400,33 @@ i915_gem_object_wait_rendering__nonblocking(struct drm_i915_gem_object *obj,
struct drm_i915_file_private *file_priv,
bool readonly)
{
+ struct drm_i915_gem_request *req;
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_engine_cs *ring = obj->ring;
unsigned reset_counter;
- u32 seqno;
int ret;
BUG_ON(!mutex_is_locked(&dev->struct_mutex));
BUG_ON(!dev_priv->mm.interruptible);
- seqno = readonly ? obj->last_write_seqno : obj->last_read_seqno;
- if (seqno == 0)
+ req = readonly ? obj->last_write_req : obj->last_read_req;
+ if (!req)
return 0;
ret = i915_gem_check_wedge(&dev_priv->gpu_error, true);
if (ret)
return ret;
- ret = i915_gem_check_olr(ring, seqno);
+ ret = i915_gem_check_olr(req);
if (ret)
return ret;
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+ i915_gem_request_reference(req);
mutex_unlock(&dev->struct_mutex);
- ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL,
- file_priv);
+ ret = __i915_wait_request(req, reset_counter, true, NULL, file_priv);
mutex_lock(&dev->struct_mutex);
+ i915_gem_request_unreference(req);
if (ret)
return ret;
@@ -1481,18 +1480,10 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
if (ret)
goto unref;
- if (read_domains & I915_GEM_DOMAIN_GTT) {
+ if (read_domains & I915_GEM_DOMAIN_GTT)
ret = i915_gem_object_set_to_gtt_domain(obj, write_domain != 0);
-
- /* Silently promote "you're not bound, there was nothing to do"
- * to success, since the client was just asking us to
- * make sure everything was done.
- */
- if (ret == -EINVAL)
- ret = 0;
- } else {
+ else
ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
- }
unref:
drm_gem_object_unreference(&obj->base);
@@ -1524,7 +1515,7 @@ i915_gem_sw_finish_ioctl(struct drm_device *dev, void *data,
/* Pinned buffers may be scanout, so flush the cache */
if (obj->pin_display)
- i915_gem_object_flush_cpu_write_domain(obj, true);
+ i915_gem_object_flush_cpu_write_domain(obj);
drm_gem_object_unreference(&obj->base);
unlock:
@@ -1557,6 +1548,12 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
struct drm_gem_object *obj;
unsigned long addr;
+ if (args->flags & ~(I915_MMAP_WC))
+ return -EINVAL;
+
+ if (args->flags & I915_MMAP_WC && !cpu_has_pat)
+ return -ENODEV;
+
obj = drm_gem_object_lookup(dev, file, args->handle);
if (obj == NULL)
return -ENOENT;
@@ -1572,6 +1569,19 @@ i915_gem_mmap_ioctl(struct drm_device *dev, void *data,
addr = vm_mmap(obj->filp, 0, args->size,
PROT_READ | PROT_WRITE, MAP_SHARED,
args->offset);
+ if (args->flags & I915_MMAP_WC) {
+ struct mm_struct *mm = current->mm;
+ struct vm_area_struct *vma;
+
+ down_write(&mm->mmap_sem);
+ vma = find_vma(mm, addr);
+ if (vma)
+ vma->vm_page_prot =
+ pgprot_writecombine(vm_get_page_prot(vma->vm_flags));
+ else
+ addr = -ENOMEM;
+ up_write(&mm->mmap_sem);
+ }
drm_gem_object_unreference_unlocked(obj);
if (IS_ERR((void *)addr))
return addr;
@@ -2256,14 +2266,18 @@ static void
i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
struct intel_engine_cs *ring)
{
- u32 seqno = intel_ring_get_seqno(ring);
+ struct drm_i915_gem_request *req;
+ struct intel_engine_cs *old_ring;
BUG_ON(ring == NULL);
- if (obj->ring != ring && obj->last_write_seqno) {
- /* Keep the seqno relative to the current ring */
- obj->last_write_seqno = seqno;
+
+ req = intel_ring_get_request(ring);
+ old_ring = i915_gem_request_get_ring(obj->last_read_req);
+
+ if (old_ring != ring && obj->last_write_req) {
+ /* Keep the request relative to the current ring */
+ i915_gem_request_assign(&obj->last_write_req, req);
}
- obj->ring = ring;
/* Add a reference if we're newly entering the active list. */
if (!obj->active) {
@@ -2273,7 +2287,7 @@ i915_gem_object_move_to_active(struct drm_i915_gem_object *obj,
list_move_tail(&obj->ring_list, &ring->active_list);
- obj->last_read_seqno = seqno;
+ i915_gem_request_assign(&obj->last_read_req, req);
}
void i915_vma_move_to_active(struct i915_vma *vma,
@@ -2286,29 +2300,25 @@ void i915_vma_move_to_active(struct i915_vma *vma,
static void
i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- struct i915_address_space *vm;
struct i915_vma *vma;
BUG_ON(obj->base.write_domain & ~I915_GEM_GPU_DOMAINS);
BUG_ON(!obj->active);
- list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
- vma = i915_gem_obj_to_vma(obj, vm);
- if (vma && !list_empty(&vma->mm_list))
- list_move_tail(&vma->mm_list, &vm->inactive_list);
+ list_for_each_entry(vma, &obj->vma_list, vma_link) {
+ if (!list_empty(&vma->mm_list))
+ list_move_tail(&vma->mm_list, &vma->vm->inactive_list);
}
intel_fb_obj_flush(obj, true);
list_del_init(&obj->ring_list);
- obj->ring = NULL;
- obj->last_read_seqno = 0;
- obj->last_write_seqno = 0;
+ i915_gem_request_assign(&obj->last_read_req, NULL);
+ i915_gem_request_assign(&obj->last_write_req, NULL);
obj->base.write_domain = 0;
- obj->last_fenced_seqno = 0;
+ i915_gem_request_assign(&obj->last_fenced_req, NULL);
obj->active = 0;
drm_gem_object_unreference(&obj->base);
@@ -2319,13 +2329,10 @@ i915_gem_object_move_to_inactive(struct drm_i915_gem_object *obj)
static void
i915_gem_object_retire(struct drm_i915_gem_object *obj)
{
- struct intel_engine_cs *ring = obj->ring;
-
- if (ring == NULL)
+ if (obj->last_read_req == NULL)
return;
- if (i915_seqno_passed(ring->get_seqno(ring, true),
- obj->last_read_seqno))
+ if (i915_gem_request_completed(obj->last_read_req, true))
i915_gem_object_move_to_inactive(obj);
}
@@ -2401,22 +2408,20 @@ i915_gem_get_seqno(struct drm_device *dev, u32 *seqno)
int __i915_add_request(struct intel_engine_cs *ring,
struct drm_file *file,
- struct drm_i915_gem_object *obj,
- u32 *out_seqno)
+ struct drm_i915_gem_object *obj)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
struct drm_i915_gem_request *request;
struct intel_ringbuffer *ringbuf;
- u32 request_ring_position, request_start;
+ u32 request_start;
int ret;
- request = ring->preallocated_lazy_request;
+ request = ring->outstanding_lazy_request;
if (WARN_ON(request == NULL))
return -ENOMEM;
if (i915.enable_execlists) {
- struct intel_context *ctx = request->ctx;
- ringbuf = ctx->engine[ring->id].ringbuf;
+ ringbuf = request->ctx->engine[ring->id].ringbuf;
} else
ringbuf = ring->buffer;
@@ -2429,7 +2434,7 @@ int __i915_add_request(struct intel_engine_cs *ring,
* what.
*/
if (i915.enable_execlists) {
- ret = logical_ring_flush_all_caches(ringbuf);
+ ret = logical_ring_flush_all_caches(ringbuf, request->ctx);
if (ret)
return ret;
} else {
@@ -2443,10 +2448,10 @@ int __i915_add_request(struct intel_engine_cs *ring,
* GPU processing the request, we never over-estimate the
* position of the head.
*/
- request_ring_position = intel_ring_get_tail(ringbuf);
+ request->postfix = intel_ring_get_tail(ringbuf);
if (i915.enable_execlists) {
- ret = ring->emit_request(ringbuf);
+ ret = ring->emit_request(ringbuf, request);
if (ret)
return ret;
} else {
@@ -2455,10 +2460,8 @@ int __i915_add_request(struct intel_engine_cs *ring,
return ret;
}
- request->seqno = intel_ring_get_seqno(ring);
- request->ring = ring;
request->head = request_start;
- request->tail = request_ring_position;
+ request->tail = intel_ring_get_tail(ringbuf);
/* Whilst this request exists, batch_obj will be on the
* active_list, and so will hold the active reference. Only when this
@@ -2491,9 +2494,8 @@ int __i915_add_request(struct intel_engine_cs *ring,
spin_unlock(&file_priv->mm.lock);
}
- trace_i915_gem_request_add(ring, request->seqno);
- ring->outstanding_lazy_seqno = 0;
- ring->preallocated_lazy_request = NULL;
+ trace_i915_gem_request_add(request);
+ ring->outstanding_lazy_request = NULL;
i915_queue_hangcheck(ring->dev);
@@ -2503,8 +2505,6 @@ int __i915_add_request(struct intel_engine_cs *ring,
round_jiffies_up_relative(HZ));
intel_mark_busy(dev_priv->dev);
- if (out_seqno)
- *out_seqno = request->seqno;
return 0;
}
@@ -2532,7 +2532,8 @@ static bool i915_context_is_banned(struct drm_i915_private *dev_priv,
if (ctx->hang_stats.banned)
return true;
- if (elapsed <= DRM_I915_CTX_BAN_PERIOD) {
+ if (ctx->hang_stats.ban_period_seconds &&
+ elapsed <= ctx->hang_stats.ban_period_seconds) {
if (!i915_gem_context_is_default(ctx)) {
DRM_DEBUG("context hanging too fast, banning!\n");
return true;
@@ -2568,33 +2569,39 @@ static void i915_set_reset_status(struct drm_i915_private *dev_priv,
static void i915_gem_free_request(struct drm_i915_gem_request *request)
{
- struct intel_context *ctx = request->ctx;
-
list_del(&request->list);
i915_gem_request_remove_from_client(request);
+ i915_gem_request_unreference(request);
+}
+
+void i915_gem_request_free(struct kref *req_ref)
+{
+ struct drm_i915_gem_request *req = container_of(req_ref,
+ typeof(*req), ref);
+ struct intel_context *ctx = req->ctx;
+
if (ctx) {
if (i915.enable_execlists) {
- struct intel_engine_cs *ring = request->ring;
+ struct intel_engine_cs *ring = req->ring;
if (ctx != ring->default_context)
intel_lr_context_unpin(ring, ctx);
}
+
i915_gem_context_unreference(ctx);
}
- kfree(request);
+
+ kfree(req);
}
struct drm_i915_gem_request *
i915_gem_find_active_request(struct intel_engine_cs *ring)
{
struct drm_i915_gem_request *request;
- u32 completed_seqno;
-
- completed_seqno = ring->get_seqno(ring, false);
list_for_each_entry(request, &ring->request_list, list) {
- if (i915_seqno_passed(completed_seqno, request->seqno))
+ if (i915_gem_request_completed(request, false))
continue;
return request;
@@ -2641,15 +2648,18 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
* pinned in place.
*/
while (!list_empty(&ring->execlist_queue)) {
- struct intel_ctx_submit_request *submit_req;
+ struct drm_i915_gem_request *submit_req;
submit_req = list_first_entry(&ring->execlist_queue,
- struct intel_ctx_submit_request,
+ struct drm_i915_gem_request,
execlist_link);
list_del(&submit_req->execlist_link);
intel_runtime_pm_put(dev_priv);
- i915_gem_context_unreference(submit_req->ctx);
- kfree(submit_req);
+
+ if (submit_req->ctx != ring->default_context)
+ intel_lr_context_unpin(ring, submit_req->ctx);
+
+ i915_gem_request_unreference(submit_req);
}
/*
@@ -2669,10 +2679,8 @@ static void i915_gem_reset_ring_cleanup(struct drm_i915_private *dev_priv,
i915_gem_free_request(request);
}
- /* These may not have been flush before the reset, do so now */
- kfree(ring->preallocated_lazy_request);
- ring->preallocated_lazy_request = NULL;
- ring->outstanding_lazy_seqno = 0;
+ /* This may not have been flushed before the reset, so clean it now */
+ i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
}
void i915_gem_restore_fences(struct drm_device *dev)
@@ -2724,15 +2732,11 @@ void i915_gem_reset(struct drm_device *dev)
void
i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
{
- uint32_t seqno;
-
if (list_empty(&ring->request_list))
return;
WARN_ON(i915_verify_lists(ring->dev));
- seqno = ring->get_seqno(ring, true);
-
/* Move any buffers on the active list that are no longer referenced
* by the ringbuffer to the flushing/inactive lists as appropriate,
* before we free the context associated with the requests.
@@ -2744,7 +2748,7 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
struct drm_i915_gem_object,
ring_list);
- if (!i915_seqno_passed(seqno, obj->last_read_seqno))
+ if (!i915_gem_request_completed(obj->last_read_req, true))
break;
i915_gem_object_move_to_inactive(obj);
@@ -2759,10 +2763,10 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
struct drm_i915_gem_request,
list);
- if (!i915_seqno_passed(seqno, request->seqno))
+ if (!i915_gem_request_completed(request, true))
break;
- trace_i915_gem_request_retire(ring, request->seqno);
+ trace_i915_gem_request_retire(request);
/* This is one of the few common intersection points
* between legacy ringbuffer submission and execlists:
@@ -2780,15 +2784,15 @@ i915_gem_retire_requests_ring(struct intel_engine_cs *ring)
* of tail of the request to update the last known position
* of the GPU head.
*/
- ringbuf->last_retired_head = request->tail;
+ ringbuf->last_retired_head = request->postfix;
i915_gem_free_request(request);
}
- if (unlikely(ring->trace_irq_seqno &&
- i915_seqno_passed(seqno, ring->trace_irq_seqno))) {
+ if (unlikely(ring->trace_irq_req &&
+ i915_gem_request_completed(ring->trace_irq_req, true))) {
ring->irq_put(ring);
- ring->trace_irq_seqno = 0;
+ i915_gem_request_assign(&ring->trace_irq_req, NULL);
}
WARN_ON(i915_verify_lists(ring->dev));
@@ -2860,14 +2864,17 @@ i915_gem_idle_work_handler(struct work_struct *work)
static int
i915_gem_object_flush_active(struct drm_i915_gem_object *obj)
{
+ struct intel_engine_cs *ring;
int ret;
if (obj->active) {
- ret = i915_gem_check_olr(obj->ring, obj->last_read_seqno);
+ ring = i915_gem_request_get_ring(obj->last_read_req);
+
+ ret = i915_gem_check_olr(obj->last_read_req);
if (ret)
return ret;
- i915_gem_retire_requests_ring(obj->ring);
+ i915_gem_retire_requests_ring(ring);
}
return 0;
@@ -2901,9 +2908,8 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_gem_wait *args = data;
struct drm_i915_gem_object *obj;
- struct intel_engine_cs *ring = NULL;
+ struct drm_i915_gem_request *req;
unsigned reset_counter;
- u32 seqno = 0;
int ret = 0;
if (args->flags != 0)
@@ -2924,13 +2930,10 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
if (ret)
goto out;
- if (obj->active) {
- seqno = obj->last_read_seqno;
- ring = obj->ring;
- }
+ if (!obj->active || !obj->last_read_req)
+ goto out;
- if (seqno == 0)
- goto out;
+ req = obj->last_read_req;
/* Do this after OLR check to make sure we make forward progress polling
* on this IOCTL with a timeout <=0 (like busy ioctl)
@@ -2942,10 +2945,15 @@ i915_gem_wait_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
drm_gem_object_unreference(&obj->base);
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+ i915_gem_request_reference(req);
mutex_unlock(&dev->struct_mutex);
- return __i915_wait_seqno(ring, seqno, reset_counter, true,
- &args->timeout_ns, file->driver_priv);
+ ret = __i915_wait_request(req, reset_counter, true, &args->timeout_ns,
+ file->driver_priv);
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_request_unreference(req);
+ mutex_unlock(&dev->struct_mutex);
+ return ret;
out:
drm_gem_object_unreference(&obj->base);
@@ -2969,10 +2977,12 @@ int
i915_gem_object_sync(struct drm_i915_gem_object *obj,
struct intel_engine_cs *to)
{
- struct intel_engine_cs *from = obj->ring;
+ struct intel_engine_cs *from;
u32 seqno;
int ret, idx;
+ from = i915_gem_request_get_ring(obj->last_read_req);
+
if (from == NULL || to == from)
return 0;
@@ -2981,24 +2991,25 @@ i915_gem_object_sync(struct drm_i915_gem_object *obj,
idx = intel_ring_sync_index(from, to);
- seqno = obj->last_read_seqno;
+ seqno = i915_gem_request_get_seqno(obj->last_read_req);
/* Optimization: Avoid semaphore sync when we are sure we already
* waited for an object with higher seqno */
if (seqno <= from->semaphore.sync_seqno[idx])
return 0;
- ret = i915_gem_check_olr(obj->ring, seqno);
+ ret = i915_gem_check_olr(obj->last_read_req);
if (ret)
return ret;
- trace_i915_gem_ring_sync_to(from, to, seqno);
+ trace_i915_gem_ring_sync_to(from, to, obj->last_read_req);
ret = to->semaphore.sync_to(to, from, seqno);
if (!ret)
- /* We use last_read_seqno because sync_to()
+ /* We use last_read_req because sync_to()
* might have just caused seqno wrap under
* the radar.
*/
- from->semaphore.sync_seqno[idx] = obj->last_read_seqno;
+ from->semaphore.sync_seqno[idx] =
+ i915_gem_request_get_seqno(obj->last_read_req);
return ret;
}
@@ -3054,10 +3065,8 @@ int i915_vma_unbind(struct i915_vma *vma)
* cause memory corruption through use-after-free.
*/
- /* Throw away the active reference before moving to the unbound list */
- i915_gem_object_retire(obj);
-
- if (i915_is_ggtt(vma->vm)) {
+ if (i915_is_ggtt(vma->vm) &&
+ vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
i915_gem_object_finish_gtt(obj);
/* release the fence reg _after_ flushing */
@@ -3071,8 +3080,15 @@ int i915_vma_unbind(struct i915_vma *vma)
vma->unbind_vma(vma);
list_del_init(&vma->mm_list);
- if (i915_is_ggtt(vma->vm))
- obj->map_and_fenceable = false;
+ if (i915_is_ggtt(vma->vm)) {
+ if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL) {
+ obj->map_and_fenceable = false;
+ } else if (vma->ggtt_view.pages) {
+ sg_free_table(vma->ggtt_view.pages);
+ kfree(vma->ggtt_view.pages);
+ vma->ggtt_view.pages = NULL;
+ }
+ }
drm_mm_remove_node(&vma->node);
i915_gem_vma_destroy(vma);
@@ -3080,6 +3096,10 @@ int i915_vma_unbind(struct i915_vma *vma)
/* Since the unbound list is global, only move to that list if
* no more VMAs exist. */
if (list_empty(&obj->vma_list)) {
+ /* Throw away the active reference before
+ * moving to the unbound list. */
+ i915_gem_object_retire(obj);
+
i915_gem_gtt_finish_object(obj);
list_move_tail(&obj->global_list, &dev_priv->mm.unbound_list);
}
@@ -3148,6 +3168,13 @@ static void i965_write_fence_reg(struct drm_device *dev, int reg,
u32 size = i915_gem_obj_ggtt_size(obj);
uint64_t val;
+ /* Adjust fence size to match tiled area */
+ if (obj->tiling_mode != I915_TILING_NONE) {
+ uint32_t row_size = obj->stride *
+ (obj->tiling_mode == I915_TILING_Y ? 32 : 8);
+ size = (size / row_size) * row_size;
+ }
+
val = (uint64_t)((i915_gem_obj_ggtt_offset(obj) + size - 4096) &
0xfffff000) << 32;
val |= i915_gem_obj_ggtt_offset(obj) & 0xfffff000;
@@ -3263,17 +3290,12 @@ static void i915_gem_write_fence(struct drm_device *dev, int reg,
"bogus fence setup with stride: 0x%x, tiling mode: %i\n",
obj->stride, obj->tiling_mode);
- switch (INTEL_INFO(dev)->gen) {
- case 9:
- case 8:
- case 7:
- case 6:
- case 5:
- case 4: i965_write_fence_reg(dev, reg, obj); break;
- case 3: i915_write_fence_reg(dev, reg, obj); break;
- case 2: i830_write_fence_reg(dev, reg, obj); break;
- default: BUG();
- }
+ if (IS_GEN2(dev))
+ i830_write_fence_reg(dev, reg, obj);
+ else if (IS_GEN3(dev))
+ i915_write_fence_reg(dev, reg, obj);
+ else if (INTEL_INFO(dev)->gen >= 4)
+ i965_write_fence_reg(dev, reg, obj);
/* And similarly be paranoid that no direct access to this region
* is reordered to before the fence is installed.
@@ -3312,12 +3334,12 @@ static void i915_gem_object_update_fence(struct drm_i915_gem_object *obj,
static int
i915_gem_object_wait_fence(struct drm_i915_gem_object *obj)
{
- if (obj->last_fenced_seqno) {
- int ret = i915_wait_seqno(obj->ring, obj->last_fenced_seqno);
+ if (obj->last_fenced_req) {
+ int ret = i915_wait_request(obj->last_fenced_req);
if (ret)
return ret;
- obj->last_fenced_seqno = 0;
+ i915_gem_request_assign(&obj->last_fenced_req, NULL);
}
return 0;
@@ -3490,7 +3512,8 @@ static struct i915_vma *
i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
struct i915_address_space *vm,
unsigned alignment,
- uint64_t flags)
+ uint64_t flags,
+ const struct i915_ggtt_view *view)
{
struct drm_device *dev = obj->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -3540,7 +3563,7 @@ i915_gem_object_bind_to_vm(struct drm_i915_gem_object *obj,
i915_gem_object_pin_pages(obj);
- vma = i915_gem_obj_lookup_or_create_vma(obj, vm);
+ vma = i915_gem_obj_lookup_or_create_vma_view(obj, vm, view);
if (IS_ERR(vma))
goto err_unpin;
@@ -3570,15 +3593,19 @@ search_free:
if (ret)
goto err_remove_node;
+ trace_i915_vma_bind(vma, flags);
+ ret = i915_vma_bind(vma, obj->cache_level,
+ flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
+ if (ret)
+ goto err_finish_gtt;
+
list_move_tail(&obj->global_list, &dev_priv->mm.bound_list);
list_add_tail(&vma->mm_list, &vm->inactive_list);
- trace_i915_vma_bind(vma, flags);
- vma->bind_vma(vma, obj->cache_level,
- flags & PIN_GLOBAL ? GLOBAL_BIND : 0);
-
return vma;
+err_finish_gtt:
+ i915_gem_gtt_finish_object(obj);
err_remove_node:
drm_mm_remove_node(&vma->node);
err_free_vma:
@@ -3615,11 +3642,14 @@ i915_gem_clflush_object(struct drm_i915_gem_object *obj,
* snooping behaviour occurs naturally as the result of our domain
* tracking.
*/
- if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level))
+ if (!force && cpu_cache_is_coherent(obj->base.dev, obj->cache_level)) {
+ obj->cache_dirty = true;
return false;
+ }
trace_i915_gem_object_clflush(obj);
drm_clflush_sg(obj->pages);
+ obj->cache_dirty = false;
return true;
}
@@ -3655,15 +3685,14 @@ i915_gem_object_flush_gtt_write_domain(struct drm_i915_gem_object *obj)
/** Flushes the CPU write domain for the object if it's dirty. */
static void
-i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
- bool force)
+i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj)
{
uint32_t old_write_domain;
if (obj->base.write_domain != I915_GEM_DOMAIN_CPU)
return;
- if (i915_gem_clflush_object(obj, force))
+ if (i915_gem_clflush_object(obj, obj->pin_display))
i915_gem_chipset_flush(obj->base.dev);
old_write_domain = obj->base.write_domain;
@@ -3685,15 +3714,10 @@ i915_gem_object_flush_cpu_write_domain(struct drm_i915_gem_object *obj,
int
i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
{
- struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
- struct i915_vma *vma = i915_gem_obj_to_ggtt(obj);
uint32_t old_write_domain, old_read_domains;
+ struct i915_vma *vma;
int ret;
- /* Not valid to be called on unbound objects. */
- if (vma == NULL)
- return -EINVAL;
-
if (obj->base.write_domain == I915_GEM_DOMAIN_GTT)
return 0;
@@ -3702,7 +3726,20 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
return ret;
i915_gem_object_retire(obj);
- i915_gem_object_flush_cpu_write_domain(obj, false);
+
+ /* Flush and acquire obj->pages so that we are coherent through
+ * direct access in memory with previous cached writes through
+ * shmemfs and that our cache domain tracking remains valid.
+ * For example, if the obj->filp was moved to swap without us
+ * being notified and releasing the pages, we would mistakenly
+ * continue to assume that the obj remained out of the CPU cached
+ * domain.
+ */
+ ret = i915_gem_object_get_pages(obj);
+ if (ret)
+ return ret;
+
+ i915_gem_object_flush_cpu_write_domain(obj);
/* Serialise direct access to this object with the barriers for
* coherent writes from the GPU, by effectively invalidating the
@@ -3733,9 +3770,10 @@ i915_gem_object_set_to_gtt_domain(struct drm_i915_gem_object *obj, bool write)
old_write_domain);
/* And bump the LRU for this access */
- if (i915_gem_object_is_inactive(obj))
+ vma = i915_gem_obj_to_ggtt(obj);
+ if (vma && drm_mm_node_allocated(&vma->node) && !obj->active)
list_move_tail(&vma->mm_list,
- &dev_priv->gtt.base.inactive_list);
+ &to_i915(obj->base.dev)->gtt.base.inactive_list);
return 0;
}
@@ -3781,36 +3819,23 @@ int i915_gem_object_set_cache_level(struct drm_i915_gem_object *obj,
}
list_for_each_entry(vma, &obj->vma_list, vma_link)
- if (drm_mm_node_allocated(&vma->node))
- vma->bind_vma(vma, cache_level,
- vma->bound & GLOBAL_BIND);
+ if (drm_mm_node_allocated(&vma->node)) {
+ ret = i915_vma_bind(vma, cache_level,
+ vma->bound & GLOBAL_BIND);
+ if (ret)
+ return ret;
+ }
}
list_for_each_entry(vma, &obj->vma_list, vma_link)
vma->node.color = cache_level;
obj->cache_level = cache_level;
- if (cpu_write_needs_clflush(obj)) {
- u32 old_read_domains, old_write_domain;
-
- /* If we're coming from LLC cached, then we haven't
- * actually been tracking whether the data is in the
- * CPU cache or not, since we only allow one bit set
- * in obj->write_domain and have been skipping the clflushes.
- * Just set it to the CPU cache for now.
- */
- i915_gem_object_retire(obj);
- WARN_ON(obj->base.write_domain & ~I915_GEM_DOMAIN_CPU);
-
- old_read_domains = obj->base.read_domains;
- old_write_domain = obj->base.write_domain;
-
- obj->base.read_domains = I915_GEM_DOMAIN_CPU;
- obj->base.write_domain = I915_GEM_DOMAIN_CPU;
-
- trace_i915_gem_object_change_domain(obj,
- old_read_domains,
- old_write_domain);
+ if (obj->cache_dirty &&
+ obj->base.write_domain != I915_GEM_DOMAIN_CPU &&
+ cpu_write_needs_clflush(obj)) {
+ if (i915_gem_clflush_object(obj, true))
+ i915_gem_chipset_flush(obj->base.dev);
}
return 0;
@@ -3902,18 +3927,14 @@ static bool is_pin_display(struct drm_i915_gem_object *obj)
if (!vma)
return false;
- /* There are 3 sources that pin objects:
+ /* There are 2 sources that pin objects:
* 1. The display engine (scanouts, sprites, cursors);
* 2. Reservations for execbuffer;
- * 3. The user.
*
* We can ignore reservations as we hold the struct_mutex and
- * are only called outside of the reservation path. The user
- * can only increment pin_count once, and so if after
- * subtracting the potential reference by the user, any pin_count
- * remains, it must be due to another use by the display engine.
+ * are only called outside of the reservation path.
*/
- return vma->pin_count - !!obj->user_pin_count;
+ return vma->pin_count;
}
/*
@@ -3930,7 +3951,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
bool was_pin_display;
int ret;
- if (pipelined != obj->ring) {
+ if (pipelined != i915_gem_request_get_ring(obj->last_read_req)) {
ret = i915_gem_object_sync(obj, pipelined);
if (ret)
return ret;
@@ -3964,7 +3985,7 @@ i915_gem_object_pin_to_display_plane(struct drm_i915_gem_object *obj,
if (ret)
goto err_unpin_display;
- i915_gem_object_flush_cpu_write_domain(obj, true);
+ i915_gem_object_flush_cpu_write_domain(obj);
old_write_domain = obj->base.write_domain;
old_read_domains = obj->base.read_domains;
@@ -4082,10 +4103,8 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_i915_file_private *file_priv = file->driver_priv;
unsigned long recent_enough = jiffies - msecs_to_jiffies(20);
- struct drm_i915_gem_request *request;
- struct intel_engine_cs *ring = NULL;
+ struct drm_i915_gem_request *request, *target = NULL;
unsigned reset_counter;
- u32 seqno = 0;
int ret;
ret = i915_gem_wait_for_error(&dev_priv->gpu_error);
@@ -4101,19 +4120,24 @@ i915_gem_ring_throttle(struct drm_device *dev, struct drm_file *file)
if (time_after_eq(request->emitted_jiffies, recent_enough))
break;
- ring = request->ring;
- seqno = request->seqno;
+ target = request;
}
reset_counter = atomic_read(&dev_priv->gpu_error.reset_counter);
+ if (target)
+ i915_gem_request_reference(target);
spin_unlock(&file_priv->mm.lock);
- if (seqno == 0)
+ if (target == NULL)
return 0;
- ret = __i915_wait_seqno(ring, seqno, reset_counter, true, NULL, NULL);
+ ret = __i915_wait_request(target, reset_counter, true, NULL, NULL);
if (ret == 0)
queue_delayed_work(dev_priv->wq, &dev_priv->mm.retire_work, 0);
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_request_unreference(target);
+ mutex_unlock(&dev->struct_mutex);
+
return ret;
}
@@ -4137,10 +4161,11 @@ i915_vma_misplaced(struct i915_vma *vma, uint32_t alignment, uint64_t flags)
}
int
-i915_gem_object_pin(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm,
- uint32_t alignment,
- uint64_t flags)
+i915_gem_object_pin_view(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ uint32_t alignment,
+ uint64_t flags,
+ const struct i915_ggtt_view *view)
{
struct drm_i915_private *dev_priv = obj->base.dev->dev_private;
struct i915_vma *vma;
@@ -4156,7 +4181,7 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
if (WARN_ON((flags & (PIN_MAPPABLE | PIN_GLOBAL)) == PIN_MAPPABLE))
return -EINVAL;
- vma = i915_gem_obj_to_vma(obj, vm);
+ vma = i915_gem_obj_to_vma_view(obj, vm, view);
if (vma) {
if (WARN_ON(vma->pin_count == DRM_I915_GEM_OBJECT_MAX_PIN_COUNT))
return -EBUSY;
@@ -4166,7 +4191,8 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
"bo is already pinned with incorrect alignment:"
" offset=%lx, req.alignment=%x, req.map_and_fenceable=%d,"
" obj->map_and_fenceable=%d\n",
- i915_gem_obj_offset(obj, vm), alignment,
+ i915_gem_obj_offset_view(obj, vm, view->type),
+ alignment,
!!(flags & PIN_MAPPABLE),
obj->map_and_fenceable);
ret = i915_vma_unbind(vma);
@@ -4179,13 +4205,17 @@ i915_gem_object_pin(struct drm_i915_gem_object *obj,
bound = vma ? vma->bound : 0;
if (vma == NULL || !drm_mm_node_allocated(&vma->node)) {
- vma = i915_gem_object_bind_to_vm(obj, vm, alignment, flags);
+ vma = i915_gem_object_bind_to_vm(obj, vm, alignment,
+ flags, view);
if (IS_ERR(vma))
return PTR_ERR(vma);
}
- if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND))
- vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
+ if (flags & PIN_GLOBAL && !(vma->bound & GLOBAL_BIND)) {
+ ret = i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND);
+ if (ret)
+ return ret;
+ }
if ((bound ^ vma->bound) & GLOBAL_BIND) {
bool mappable, fenceable;
@@ -4257,102 +4287,6 @@ i915_gem_object_unpin_fence(struct drm_i915_gem_object *obj)
}
int
-i915_gem_pin_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file)
-{
- struct drm_i915_gem_pin *args = data;
- struct drm_i915_gem_object *obj;
- int ret;
-
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- return -ENODEV;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
- if (&obj->base == NULL) {
- ret = -ENOENT;
- goto unlock;
- }
-
- if (obj->madv != I915_MADV_WILLNEED) {
- DRM_DEBUG("Attempting to pin a purgeable buffer\n");
- ret = -EFAULT;
- goto out;
- }
-
- if (obj->pin_filp != NULL && obj->pin_filp != file) {
- DRM_DEBUG("Already pinned in i915_gem_pin_ioctl(): %d\n",
- args->handle);
- ret = -EINVAL;
- goto out;
- }
-
- if (obj->user_pin_count == ULONG_MAX) {
- ret = -EBUSY;
- goto out;
- }
-
- if (obj->user_pin_count == 0) {
- ret = i915_gem_obj_ggtt_pin(obj, args->alignment, PIN_MAPPABLE);
- if (ret)
- goto out;
- }
-
- obj->user_pin_count++;
- obj->pin_filp = file;
-
- args->offset = i915_gem_obj_ggtt_offset(obj);
-out:
- drm_gem_object_unreference(&obj->base);
-unlock:
- mutex_unlock(&dev->struct_mutex);
- return ret;
-}
-
-int
-i915_gem_unpin_ioctl(struct drm_device *dev, void *data,
- struct drm_file *file)
-{
- struct drm_i915_gem_pin *args = data;
- struct drm_i915_gem_object *obj;
- int ret;
-
- if (drm_core_check_feature(dev, DRIVER_MODESET))
- return -ENODEV;
-
- ret = i915_mutex_lock_interruptible(dev);
- if (ret)
- return ret;
-
- obj = to_intel_bo(drm_gem_object_lookup(dev, file, args->handle));
- if (&obj->base == NULL) {
- ret = -ENOENT;
- goto unlock;
- }
-
- if (obj->pin_filp != file) {
- DRM_DEBUG("Not pinned by caller in i915_gem_pin_ioctl(): %d\n",
- args->handle);
- ret = -EINVAL;
- goto out;
- }
- obj->user_pin_count--;
- if (obj->user_pin_count == 0) {
- obj->pin_filp = NULL;
- i915_gem_object_ggtt_unpin(obj);
- }
-
-out:
- drm_gem_object_unreference(&obj->base);
-unlock:
- mutex_unlock(&dev->struct_mutex);
- return ret;
-}
-
-int
i915_gem_busy_ioctl(struct drm_device *dev, void *data,
struct drm_file *file)
{
@@ -4378,9 +4312,11 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
ret = i915_gem_object_flush_active(obj);
args->busy = obj->active;
- if (obj->ring) {
+ if (obj->last_read_req) {
+ struct intel_engine_cs *ring;
BUILD_BUG_ON(I915_NUM_RINGS > 16);
- args->busy |= intel_ring_flag(obj->ring) << 16;
+ ring = i915_gem_request_get_ring(obj->last_read_req);
+ args->busy |= intel_ring_flag(ring) << 16;
}
drm_gem_object_unreference(&obj->base);
@@ -4460,6 +4396,7 @@ void i915_gem_object_init(struct drm_i915_gem_object *obj,
INIT_LIST_HEAD(&obj->ring_list);
INIT_LIST_HEAD(&obj->obj_exec_link);
INIT_LIST_HEAD(&obj->vma_list);
+ INIT_LIST_HEAD(&obj->batch_pool_list);
obj->ops = ops;
@@ -4615,12 +4552,13 @@ void i915_gem_free_object(struct drm_gem_object *gem_obj)
intel_runtime_pm_put(dev_priv);
}
-struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm)
+struct i915_vma *i915_gem_obj_to_vma_view(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view)
{
struct i915_vma *vma;
list_for_each_entry(vma, &obj->vma_list, vma_link)
- if (vma->vm == vm)
+ if (vma->vm == vm && vma->ggtt_view.type == view->type)
return vma;
return NULL;
@@ -4676,10 +4614,15 @@ i915_gem_suspend(struct drm_device *dev)
i915_gem_stop_ringbuffers(dev);
mutex_unlock(&dev->struct_mutex);
- del_timer_sync(&dev_priv->gpu_error.hangcheck_timer);
+ cancel_delayed_work_sync(&dev_priv->gpu_error.hangcheck_work);
cancel_delayed_work_sync(&dev_priv->mm.retire_work);
flush_delayed_work(&dev_priv->mm.idle_work);
+ /* Assert that we sucessfully flushed all the work and
+ * reset the GPU back to its idle, low power state.
+ */
+ WARN_ON(dev_priv->mm.busy);
+
return 0;
err:
@@ -4791,14 +4734,6 @@ int i915_gem_init_rings(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
int ret;
- /*
- * At least 830 can leave some of the unused rings
- * "active" (ie. head != tail) after resume which
- * will prevent c3 entry. Makes sure all unused rings
- * are totally idle.
- */
- init_unused_rings(dev);
-
ret = intel_init_render_ring_buffer(dev);
if (ret)
return ret;
@@ -4851,6 +4786,7 @@ int
i915_gem_init_hw(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_engine_cs *ring;
int ret, i;
if (INTEL_INFO(dev)->gen < 6 && !intel_enable_gtt())
@@ -4877,32 +4813,35 @@ i915_gem_init_hw(struct drm_device *dev)
i915_gem_init_swizzling(dev);
- ret = dev_priv->gt.init_rings(dev);
- if (ret)
- return ret;
+ /*
+ * At least 830 can leave some of the unused rings
+ * "active" (ie. head != tail) after resume which
+ * will prevent c3 entry. Makes sure all unused rings
+ * are totally idle.
+ */
+ init_unused_rings(dev);
+
+ for_each_ring(ring, dev_priv, i) {
+ ret = ring->init_hw(ring);
+ if (ret)
+ return ret;
+ }
for (i = 0; i < NUM_L3_SLICES(dev); i++)
i915_gem_l3_remap(&dev_priv->ring[RCS], i);
- /*
- * XXX: Contexts should only be initialized once. Doing a switch to the
- * default context switch however is something we'd like to do after
- * reset or thaw (the latter may not actually be necessary for HW, but
- * goes with our code better). Context switching requires rings (for
- * the do_switch), but before enabling PPGTT. So don't move this.
- */
- ret = i915_gem_context_enable(dev_priv);
+ ret = i915_ppgtt_init_hw(dev);
if (ret && ret != -EIO) {
- DRM_ERROR("Context enable failed %d\n", ret);
+ DRM_ERROR("PPGTT enable failed %d\n", ret);
i915_gem_cleanup_ringbuffer(dev);
-
- return ret;
}
- ret = i915_ppgtt_init_hw(dev);
+ ret = i915_gem_context_enable(dev_priv);
if (ret && ret != -EIO) {
- DRM_ERROR("PPGTT enable failed %d\n", ret);
+ DRM_ERROR("Context enable failed %d\n", ret);
i915_gem_cleanup_ringbuffer(dev);
+
+ return ret;
}
return ret;
@@ -4939,18 +4878,18 @@ int i915_gem_init(struct drm_device *dev)
}
ret = i915_gem_init_userptr(dev);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ if (ret)
+ goto out_unlock;
i915_gem_init_global_gtt(dev);
ret = i915_gem_context_init(dev);
- if (ret) {
- mutex_unlock(&dev->struct_mutex);
- return ret;
- }
+ if (ret)
+ goto out_unlock;
+
+ ret = dev_priv->gt.init_rings(dev);
+ if (ret)
+ goto out_unlock;
ret = i915_gem_init_hw(dev);
if (ret == -EIO) {
@@ -4962,6 +4901,8 @@ int i915_gem_init(struct drm_device *dev)
atomic_set_mask(I915_WEDGED, &dev_priv->gpu_error.reset_counter);
ret = 0;
}
+
+out_unlock:
mutex_unlock(&dev->struct_mutex);
return ret;
@@ -5062,6 +5003,8 @@ i915_gem_load(struct drm_device *dev)
dev_priv->mm.oom_notifier.notifier_call = i915_gem_shrinker_oom;
register_oom_notifier(&dev_priv->mm.oom_notifier);
+ i915_gem_batch_pool_init(dev, &dev_priv->mm.batch_pool);
+
mutex_init(&dev_priv->fb_tracking.lock);
}
@@ -5155,7 +5098,7 @@ static bool mutex_is_locked_by(struct mutex *mutex, struct task_struct *task)
if (!mutex_is_locked(mutex))
return false;
-#if defined(CONFIG_SMP) && !defined(CONFIG_DEBUG_MUTEXES)
+#if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_MUTEXES)
return mutex->owner == task;
#else
/* Since UP may be pre-empted, we cannot assume that we own the lock */
@@ -5222,8 +5165,9 @@ i915_gem_shrinker_count(struct shrinker *shrinker, struct shrink_control *sc)
}
/* All the new VM stuff */
-unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
- struct i915_address_space *vm)
+unsigned long i915_gem_obj_offset_view(struct drm_i915_gem_object *o,
+ struct i915_address_space *vm,
+ enum i915_ggtt_view_type view)
{
struct drm_i915_private *dev_priv = o->base.dev->dev_private;
struct i915_vma *vma;
@@ -5231,7 +5175,7 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
WARN_ON(vm == &dev_priv->mm.aliasing_ppgtt->base);
list_for_each_entry(vma, &o->vma_list, vma_link) {
- if (vma->vm == vm)
+ if (vma->vm == vm && vma->ggtt_view.type == view)
return vma->node.start;
}
@@ -5240,13 +5184,16 @@ unsigned long i915_gem_obj_offset(struct drm_i915_gem_object *o,
return -1;
}
-bool i915_gem_obj_bound(struct drm_i915_gem_object *o,
- struct i915_address_space *vm)
+bool i915_gem_obj_bound_view(struct drm_i915_gem_object *o,
+ struct i915_address_space *vm,
+ enum i915_ggtt_view_type view)
{
struct i915_vma *vma;
list_for_each_entry(vma, &o->vma_list, vma_link)
- if (vma->vm == vm && drm_mm_node_allocated(&vma->node))
+ if (vma->vm == vm &&
+ vma->ggtt_view.type == view &&
+ drm_mm_node_allocated(&vma->node))
return true;
return false;
@@ -5378,11 +5325,13 @@ i915_gem_shrinker_oom(struct notifier_block *nb, unsigned long event, void *ptr)
struct i915_vma *i915_gem_obj_to_ggtt(struct drm_i915_gem_object *obj)
{
+ struct i915_address_space *ggtt = i915_obj_to_ggtt(obj);
struct i915_vma *vma;
- vma = list_first_entry(&obj->vma_list, typeof(*vma), vma_link);
- if (vma->vm != i915_obj_to_ggtt(obj))
- return NULL;
+ list_for_each_entry(vma, &obj->vma_list, vma_link)
+ if (vma->vm == ggtt &&
+ vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
+ return vma;
- return vma;
+ return NULL;
}
diff --git a/drivers/gpu/drm/i915/i915_gem_batch_pool.c b/drivers/gpu/drm/i915/i915_gem_batch_pool.c
new file mode 100644
index 000000000000..c690170a1c4f
--- /dev/null
+++ b/drivers/gpu/drm/i915/i915_gem_batch_pool.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
+ * IN THE SOFTWARE.
+ *
+ */
+
+#include "i915_drv.h"
+
+/**
+ * DOC: batch pool
+ *
+ * In order to submit batch buffers as 'secure', the software command parser
+ * must ensure that a batch buffer cannot be modified after parsing. It does
+ * this by copying the user provided batch buffer contents to a kernel owned
+ * buffer from which the hardware will actually execute, and by carefully
+ * managing the address space bindings for such buffers.
+ *
+ * The batch pool framework provides a mechanism for the driver to manage a
+ * set of scratch buffers to use for this purpose. The framework can be
+ * extended to support other uses cases should they arise.
+ */
+
+/**
+ * i915_gem_batch_pool_init() - initialize a batch buffer pool
+ * @dev: the drm device
+ * @pool: the batch buffer pool
+ */
+void i915_gem_batch_pool_init(struct drm_device *dev,
+ struct i915_gem_batch_pool *pool)
+{
+ pool->dev = dev;
+ INIT_LIST_HEAD(&pool->cache_list);
+}
+
+/**
+ * i915_gem_batch_pool_fini() - clean up a batch buffer pool
+ * @pool: the pool to clean up
+ *
+ * Note: Callers must hold the struct_mutex.
+ */
+void i915_gem_batch_pool_fini(struct i915_gem_batch_pool *pool)
+{
+ WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
+
+ while (!list_empty(&pool->cache_list)) {
+ struct drm_i915_gem_object *obj =
+ list_first_entry(&pool->cache_list,
+ struct drm_i915_gem_object,
+ batch_pool_list);
+
+ WARN_ON(obj->active);
+
+ list_del_init(&obj->batch_pool_list);
+ drm_gem_object_unreference(&obj->base);
+ }
+}
+
+/**
+ * i915_gem_batch_pool_get() - select a buffer from the pool
+ * @pool: the batch buffer pool
+ * @size: the minimum desired size of the returned buffer
+ *
+ * Finds or allocates a batch buffer in the pool with at least the requested
+ * size. The caller is responsible for any domain, active/inactive, or
+ * purgeability management for the returned buffer.
+ *
+ * Note: Callers must hold the struct_mutex
+ *
+ * Return: the selected batch buffer object
+ */
+struct drm_i915_gem_object *
+i915_gem_batch_pool_get(struct i915_gem_batch_pool *pool,
+ size_t size)
+{
+ struct drm_i915_gem_object *obj = NULL;
+ struct drm_i915_gem_object *tmp, *next;
+
+ WARN_ON(!mutex_is_locked(&pool->dev->struct_mutex));
+
+ list_for_each_entry_safe(tmp, next,
+ &pool->cache_list, batch_pool_list) {
+
+ if (tmp->active)
+ continue;
+
+ /* While we're looping, do some clean up */
+ if (tmp->madv == __I915_MADV_PURGED) {
+ list_del(&tmp->batch_pool_list);
+ drm_gem_object_unreference(&tmp->base);
+ continue;
+ }
+
+ /*
+ * Select a buffer that is at least as big as needed
+ * but not 'too much' bigger. A better way to do this
+ * might be to bucket the pool objects based on size.
+ */
+ if (tmp->base.size >= size &&
+ tmp->base.size <= (2 * size)) {
+ obj = tmp;
+ break;
+ }
+ }
+
+ if (!obj) {
+ obj = i915_gem_alloc_object(pool->dev, size);
+ if (!obj)
+ return ERR_PTR(-ENOMEM);
+
+ list_add_tail(&obj->batch_pool_list, &pool->cache_list);
+ }
+ else
+ /* Keep list in LRU order */
+ list_move_tail(&obj->batch_pool_list, &pool->cache_list);
+
+ obj->madv = I915_MADV_WILLNEED;
+
+ return obj;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_context.c b/drivers/gpu/drm/i915/i915_gem_context.c
index d011ec82ef1e..8603bf48d3ee 100644
--- a/drivers/gpu/drm/i915/i915_gem_context.c
+++ b/drivers/gpu/drm/i915/i915_gem_context.c
@@ -222,6 +222,8 @@ __create_hw_context(struct drm_device *dev,
* is no remap info, it will be a NOP. */
ctx->remap_slice = (1 << NUM_L3_SLICES(dev)) - 1;
+ ctx->hang_stats.ban_period_seconds = DRM_I915_CTX_BAN_PERIOD;
+
return ctx;
err_out:
@@ -408,14 +410,25 @@ int i915_gem_context_enable(struct drm_i915_private *dev_priv)
BUG_ON(!dev_priv->ring[RCS].default_context);
- if (i915.enable_execlists)
- return 0;
+ if (i915.enable_execlists) {
+ for_each_ring(ring, dev_priv, i) {
+ if (ring->init_context) {
+ ret = ring->init_context(ring,
+ ring->default_context);
+ if (ret) {
+ DRM_ERROR("ring init context: %d\n",
+ ret);
+ return ret;
+ }
+ }
+ }
- for_each_ring(ring, dev_priv, i) {
- ret = i915_switch_context(ring, ring->default_context);
- if (ret)
- return ret;
- }
+ } else
+ for_each_ring(ring, dev_priv, i) {
+ ret = i915_switch_context(ring, ring->default_context);
+ if (ret)
+ return ret;
+ }
return 0;
}
@@ -611,9 +624,14 @@ static int do_switch(struct intel_engine_cs *ring,
goto unpin_out;
vma = i915_gem_obj_to_ggtt(to->legacy_hw_ctx.rcs_state);
- if (!(vma->bound & GLOBAL_BIND))
- vma->bind_vma(vma, to->legacy_hw_ctx.rcs_state->cache_level,
- GLOBAL_BIND);
+ if (!(vma->bound & GLOBAL_BIND)) {
+ ret = i915_vma_bind(vma,
+ to->legacy_hw_ctx.rcs_state->cache_level,
+ GLOBAL_BIND);
+ /* This shouldn't ever fail. */
+ if (WARN_ONCE(ret, "GGTT context bind failed!"))
+ goto unpin_out;
+ }
if (!to->legacy_hw_ctx.initialized || i915_gem_context_is_default(to))
hw_flags |= MI_RESTORE_INHIBIT;
@@ -651,7 +669,8 @@ static int do_switch(struct intel_engine_cs *ring,
* swapped, but there is no way to do that yet.
*/
from->legacy_hw_ctx.rcs_state->dirty = 1;
- BUG_ON(from->legacy_hw_ctx.rcs_state->ring != ring);
+ BUG_ON(i915_gem_request_get_ring(
+ from->legacy_hw_ctx.rcs_state->last_read_req) != ring);
/* obj is kept alive until the next request by its active ref */
i915_gem_object_ggtt_unpin(from->legacy_hw_ctx.rcs_state);
@@ -671,10 +690,6 @@ done:
if (ret)
DRM_ERROR("ring init context: %d\n", ret);
}
-
- ret = i915_gem_render_state_init(ring);
- if (ret)
- DRM_ERROR("init render state: %d\n", ret);
}
return 0;
@@ -779,3 +794,72 @@ int i915_gem_context_destroy_ioctl(struct drm_device *dev, void *data,
DRM_DEBUG_DRIVER("HW context %d destroyed\n", args->ctx_id);
return 0;
}
+
+int i915_gem_context_getparam_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_i915_file_private *file_priv = file->driver_priv;
+ struct drm_i915_gem_context_param *args = data;
+ struct intel_context *ctx;
+ int ret;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
+ ctx = i915_gem_context_get(file_priv, args->ctx_id);
+ if (IS_ERR(ctx)) {
+ mutex_unlock(&dev->struct_mutex);
+ return PTR_ERR(ctx);
+ }
+
+ args->size = 0;
+ switch (args->param) {
+ case I915_CONTEXT_PARAM_BAN_PERIOD:
+ args->value = ctx->hang_stats.ban_period_seconds;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
+
+int i915_gem_context_setparam_ioctl(struct drm_device *dev, void *data,
+ struct drm_file *file)
+{
+ struct drm_i915_file_private *file_priv = file->driver_priv;
+ struct drm_i915_gem_context_param *args = data;
+ struct intel_context *ctx;
+ int ret;
+
+ ret = i915_mutex_lock_interruptible(dev);
+ if (ret)
+ return ret;
+
+ ctx = i915_gem_context_get(file_priv, args->ctx_id);
+ if (IS_ERR(ctx)) {
+ mutex_unlock(&dev->struct_mutex);
+ return PTR_ERR(ctx);
+ }
+
+ switch (args->param) {
+ case I915_CONTEXT_PARAM_BAN_PERIOD:
+ if (args->size)
+ ret = -EINVAL;
+ else if (args->value < ctx->hang_stats.ban_period_seconds &&
+ !capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ctx->hang_stats.ban_period_seconds = args->value;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 886ff2ee7a28..e3a49d94da3a 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -50,11 +50,12 @@ mark_free(struct i915_vma *vma, struct list_head *unwind)
* i915_gem_evict_something - Evict vmas to make room for binding a new one
* @dev: drm_device
* @vm: address space to evict from
- * @size: size of the desired free space
+ * @min_size: size of the desired free space
* @alignment: alignment constraint of the desired free space
* @cache_level: cache_level for the desired space
- * @mappable: whether the free space must be mappable
- * @nonblocking: whether evicting active objects is allowed or not
+ * @start: start (inclusive) of the range from which to evict objects
+ * @end: end (exclusive) of the range from which to evict objects
+ * @flags: additional flags to control the eviction algorithm
*
* This function will try to evict vmas until a free space satisfying the
* requirements is found. Callers must check first whether any such hole exists
@@ -196,7 +197,6 @@ found:
/**
* i915_gem_evict_vm - Evict all idle vmas from a vm
- *
* @vm: Address space to cleanse
* @do_idle: Boolean directing whether to idle first.
*
@@ -214,6 +214,7 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
struct i915_vma *vma, *next;
int ret;
+ WARN_ON(!mutex_is_locked(&vm->dev->struct_mutex));
trace_i915_gem_evict_vm(vm);
if (do_idle) {
@@ -222,6 +223,8 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
return ret;
i915_gem_retire_requests(vm->dev);
+
+ WARN_ON(!list_empty(&vm->active_list));
}
list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list)
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 11738316394a..b773368fc62c 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -37,6 +37,7 @@
#define __EXEC_OBJECT_HAS_FENCE (1<<30)
#define __EXEC_OBJECT_NEEDS_MAP (1<<29)
#define __EXEC_OBJECT_NEEDS_BIAS (1<<28)
+#define __EXEC_OBJECT_PURGEABLE (1<<27)
#define BATCH_OFFSET_BIAS (256*1024)
@@ -223,7 +224,12 @@ i915_gem_execbuffer_unreserve_vma(struct i915_vma *vma)
if (entry->flags & __EXEC_OBJECT_HAS_PIN)
vma->pin_count--;
- entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE | __EXEC_OBJECT_HAS_PIN);
+ if (entry->flags & __EXEC_OBJECT_PURGEABLE)
+ obj->madv = I915_MADV_DONTNEED;
+
+ entry->flags &= ~(__EXEC_OBJECT_HAS_FENCE |
+ __EXEC_OBJECT_HAS_PIN |
+ __EXEC_OBJECT_PURGEABLE);
}
static void eb_destroy(struct eb_vmas *eb)
@@ -357,9 +363,12 @@ i915_gem_execbuffer_relocate_entry(struct drm_i915_gem_object *obj,
* through the ppgtt for non_secure batchbuffers. */
if (unlikely(IS_GEN6(dev) &&
reloc->write_domain == I915_GEM_DOMAIN_INSTRUCTION &&
- !(target_vma->bound & GLOBAL_BIND)))
- target_vma->bind_vma(target_vma, target_i915_obj->cache_level,
- GLOBAL_BIND);
+ !(target_vma->bound & GLOBAL_BIND))) {
+ ret = i915_vma_bind(target_vma, target_i915_obj->cache_level,
+ GLOBAL_BIND);
+ if (WARN_ONCE(ret, "Unexpected failure to bind target VMA!"))
+ return ret;
+ }
/* Validate that the target is in a valid r/w GPU domain */
if (unlikely(reloc->write_domain & (reloc->write_domain - 1))) {
@@ -943,7 +952,7 @@ void
i915_gem_execbuffer_move_to_active(struct list_head *vmas,
struct intel_engine_cs *ring)
{
- u32 seqno = intel_ring_get_seqno(ring);
+ struct drm_i915_gem_request *req = intel_ring_get_request(ring);
struct i915_vma *vma;
list_for_each_entry(vma, vmas, exec_list) {
@@ -960,7 +969,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
i915_vma_move_to_active(vma, ring);
if (obj->base.write_domain) {
obj->dirty = 1;
- obj->last_write_seqno = seqno;
+ i915_gem_request_assign(&obj->last_write_req, req);
intel_fb_obj_invalidate(obj, ring);
@@ -968,7 +977,7 @@ i915_gem_execbuffer_move_to_active(struct list_head *vmas,
obj->base.write_domain &= ~I915_GEM_GPU_DOMAINS;
}
if (entry->flags & EXEC_OBJECT_NEEDS_FENCE) {
- obj->last_fenced_seqno = seqno;
+ i915_gem_request_assign(&obj->last_fenced_req, req);
if (entry->flags & __EXEC_OBJECT_HAS_FENCE) {
struct drm_i915_private *dev_priv = to_i915(ring->dev);
list_move_tail(&dev_priv->fence_regs[obj->fence_reg].lru_list,
@@ -990,7 +999,7 @@ i915_gem_execbuffer_retire_commands(struct drm_device *dev,
ring->gpu_caches_dirty = true;
/* Add a breadcrumb for the completion of the batch buffer */
- (void)__i915_add_request(ring, file, obj, NULL);
+ (void)__i915_add_request(ring, file, obj);
}
static int
@@ -1060,6 +1069,67 @@ i915_emit_box(struct intel_engine_cs *ring,
return 0;
}
+static struct drm_i915_gem_object*
+i915_gem_execbuffer_parse(struct intel_engine_cs *ring,
+ struct drm_i915_gem_exec_object2 *shadow_exec_entry,
+ struct eb_vmas *eb,
+ struct drm_i915_gem_object *batch_obj,
+ u32 batch_start_offset,
+ u32 batch_len,
+ bool is_master,
+ u32 *flags)
+{
+ struct drm_i915_private *dev_priv = to_i915(batch_obj->base.dev);
+ struct drm_i915_gem_object *shadow_batch_obj;
+ bool need_reloc = false;
+ int ret;
+
+ shadow_batch_obj = i915_gem_batch_pool_get(&dev_priv->mm.batch_pool,
+ batch_obj->base.size);
+ if (IS_ERR(shadow_batch_obj))
+ return shadow_batch_obj;
+
+ ret = i915_parse_cmds(ring,
+ batch_obj,
+ shadow_batch_obj,
+ batch_start_offset,
+ batch_len,
+ is_master);
+ if (ret) {
+ if (ret == -EACCES)
+ return batch_obj;
+ } else {
+ struct i915_vma *vma;
+
+ memset(shadow_exec_entry, 0, sizeof(*shadow_exec_entry));
+
+ vma = i915_gem_obj_to_ggtt(shadow_batch_obj);
+ vma->exec_entry = shadow_exec_entry;
+ vma->exec_entry->flags = __EXEC_OBJECT_PURGEABLE;
+ drm_gem_object_reference(&shadow_batch_obj->base);
+ i915_gem_execbuffer_reserve_vma(vma, ring, &need_reloc);
+ list_add_tail(&vma->exec_list, &eb->vmas);
+
+ shadow_batch_obj->base.pending_read_domains =
+ batch_obj->base.pending_read_domains;
+
+ /*
+ * Set the DISPATCH_SECURE bit to remove the NON_SECURE
+ * bit from MI_BATCH_BUFFER_START commands issued in the
+ * dispatch_execbuffer implementations. We specifically
+ * don't want that set when the command parser is
+ * enabled.
+ *
+ * FIXME: with aliasing ppgtt, buffers that should only
+ * be in ggtt still end up in the aliasing ppgtt. remove
+ * this check when that is fixed.
+ */
+ if (USES_FULL_PPGTT(dev))
+ *flags |= I915_DISPATCH_SECURE;
+ }
+
+ return ret ? ERR_PTR(ret) : shadow_batch_obj;
+}
int
i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
@@ -1208,7 +1278,7 @@ i915_gem_ringbuffer_submission(struct drm_device *dev, struct drm_file *file,
return ret;
}
- trace_i915_gem_ring_dispatch(ring, intel_ring_get_seqno(ring), flags);
+ trace_i915_gem_ring_dispatch(intel_ring_get_request(ring), flags);
i915_gem_execbuffer_move_to_active(vmas, ring);
i915_gem_execbuffer_retire_commands(dev, file, ring, batch_obj);
@@ -1277,6 +1347,7 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
struct drm_i915_private *dev_priv = dev->dev_private;
struct eb_vmas *eb;
struct drm_i915_gem_object *batch_obj;
+ struct drm_i915_gem_exec_object2 shadow_exec_entry;
struct intel_engine_cs *ring;
struct intel_context *ctx;
struct i915_address_space *vm;
@@ -1309,13 +1380,35 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
return -EINVAL;
}
+ if (((args->flags & I915_EXEC_RING_MASK) != I915_EXEC_BSD) &&
+ ((args->flags & I915_EXEC_BSD_MASK) != 0)) {
+ DRM_DEBUG("execbuf with non bsd ring but with invalid "
+ "bsd dispatch flags: %d\n", (int)(args->flags));
+ return -EINVAL;
+ }
+
if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_DEFAULT)
ring = &dev_priv->ring[RCS];
else if ((args->flags & I915_EXEC_RING_MASK) == I915_EXEC_BSD) {
if (HAS_BSD2(dev)) {
int ring_id;
- ring_id = gen8_dispatch_bsd_ring(dev, file);
- ring = &dev_priv->ring[ring_id];
+
+ switch (args->flags & I915_EXEC_BSD_MASK) {
+ case I915_EXEC_BSD_DEFAULT:
+ ring_id = gen8_dispatch_bsd_ring(dev, file);
+ ring = &dev_priv->ring[ring_id];
+ break;
+ case I915_EXEC_BSD_RING1:
+ ring = &dev_priv->ring[VCS];
+ break;
+ case I915_EXEC_BSD_RING2:
+ ring = &dev_priv->ring[VCS2];
+ break;
+ default:
+ DRM_DEBUG("execbuf with unknown bsd ring: %d\n",
+ (int)(args->flags & I915_EXEC_BSD_MASK));
+ return -EINVAL;
+ }
} else
ring = &dev_priv->ring[VCS];
} else
@@ -1393,28 +1486,24 @@ i915_gem_do_execbuffer(struct drm_device *dev, void *data,
ret = -EINVAL;
goto err;
}
- batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
if (i915_needs_cmd_parser(ring)) {
- ret = i915_parse_cmds(ring,
- batch_obj,
- args->batch_start_offset,
- file->is_master);
- if (ret) {
- if (ret != -EACCES)
- goto err;
- } else {
- /*
- * XXX: Actually do this when enabling batch copy...
- *
- * Set the DISPATCH_SECURE bit to remove the NON_SECURE bit
- * from MI_BATCH_BUFFER_START commands issued in the
- * dispatch_execbuffer implementations. We specifically don't
- * want that set when the command parser is enabled.
- */
+ batch_obj = i915_gem_execbuffer_parse(ring,
+ &shadow_exec_entry,
+ eb,
+ batch_obj,
+ args->batch_start_offset,
+ args->batch_len,
+ file->is_master,
+ &flags);
+ if (IS_ERR(batch_obj)) {
+ ret = PTR_ERR(batch_obj);
+ goto err;
}
}
+ batch_obj->base.pending_read_domains |= I915_GEM_DOMAIN_COMMAND;
+
/* snb/ivb/vlv conflate the "batch in ppgtt" bit with the "non-secure
* batch" bit. Hence we need to pin secure batches into the global gtt.
* hsw should have this fixed, but bdw mucks it up again. */
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.c b/drivers/gpu/drm/i915/i915_gem_gtt.c
index 171f6eafdeee..746f77fb57a3 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.c
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.c
@@ -30,6 +30,68 @@
#include "i915_trace.h"
#include "intel_drv.h"
+/**
+ * DOC: Global GTT views
+ *
+ * Background and previous state
+ *
+ * Historically objects could exists (be bound) in global GTT space only as
+ * singular instances with a view representing all of the object's backing pages
+ * in a linear fashion. This view will be called a normal view.
+ *
+ * To support multiple views of the same object, where the number of mapped
+ * pages is not equal to the backing store, or where the layout of the pages
+ * is not linear, concept of a GGTT view was added.
+ *
+ * One example of an alternative view is a stereo display driven by a single
+ * image. In this case we would have a framebuffer looking like this
+ * (2x2 pages):
+ *
+ * 12
+ * 34
+ *
+ * Above would represent a normal GGTT view as normally mapped for GPU or CPU
+ * rendering. In contrast, fed to the display engine would be an alternative
+ * view which could look something like this:
+ *
+ * 1212
+ * 3434
+ *
+ * In this example both the size and layout of pages in the alternative view is
+ * different from the normal view.
+ *
+ * Implementation and usage
+ *
+ * GGTT views are implemented using VMAs and are distinguished via enum
+ * i915_ggtt_view_type and struct i915_ggtt_view.
+ *
+ * A new flavour of core GEM functions which work with GGTT bound objects were
+ * added with the _view suffix. They take the struct i915_ggtt_view parameter
+ * encapsulating all metadata required to implement a view.
+ *
+ * As a helper for callers which are only interested in the normal view,
+ * globally const i915_ggtt_view_normal singleton instance exists. All old core
+ * GEM API functions, the ones not taking the view parameter, are operating on,
+ * or with the normal GGTT view.
+ *
+ * Code wanting to add or use a new GGTT view needs to:
+ *
+ * 1. Add a new enum with a suitable name.
+ * 2. Extend the metadata in the i915_ggtt_view structure if required.
+ * 3. Add support to i915_get_vma_pages().
+ *
+ * New views are required to build a scatter-gather table from within the
+ * i915_get_vma_pages function. This table is stored in the vma.ggtt_view and
+ * exists for the lifetime of an VMA.
+ *
+ * Core API is designed to have copy semantics which means that passed in
+ * struct i915_ggtt_view does not need to be persistent (left around after
+ * calling the core API functions).
+ *
+ */
+
+const struct i915_ggtt_view i915_ggtt_view_normal;
+
static void bdw_setup_private_ppat(struct drm_i915_private *dev_priv);
static void chv_setup_private_ppat(struct drm_i915_private *dev_priv);
@@ -40,8 +102,6 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
has_aliasing_ppgtt = INTEL_INFO(dev)->gen >= 6;
has_full_ppgtt = INTEL_INFO(dev)->gen >= 7;
- if (IS_GEN8(dev))
- has_full_ppgtt = false; /* XXX why? */
/*
* We don't allow disabling PPGTT for gen9+ as it's a requirement for
@@ -72,7 +132,10 @@ static int sanitize_enable_ppgtt(struct drm_device *dev, int enable_ppgtt)
return 0;
}
- return has_aliasing_ppgtt ? 1 : 0;
+ if (INTEL_INFO(dev)->gen >= 8 && i915.enable_execlists)
+ return 2;
+ else
+ return has_aliasing_ppgtt ? 1 : 0;
}
@@ -132,7 +195,7 @@ static gen6_gtt_pte_t snb_pte_encode(dma_addr_t addr,
pte |= GEN6_PTE_UNCACHED;
break;
default:
- WARN_ON(1);
+ MISSING_CASE(level);
}
return pte;
@@ -156,7 +219,7 @@ static gen6_gtt_pte_t ivb_pte_encode(dma_addr_t addr,
pte |= GEN6_PTE_UNCACHED;
break;
default:
- WARN_ON(1);
+ MISSING_CASE(level);
}
return pte;
@@ -1102,10 +1165,8 @@ static int __hw_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
if (INTEL_INFO(dev)->gen < 8)
return gen6_ppgtt_init(ppgtt);
- else if (IS_GEN8(dev) || IS_GEN9(dev))
- return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
else
- BUG();
+ return gen8_ppgtt_init(ppgtt, dev_priv->gtt.base.total);
}
int i915_ppgtt_init(struct drm_device *dev, struct i915_hw_ppgtt *ppgtt)
{
@@ -1146,7 +1207,7 @@ int i915_ppgtt_init_hw(struct drm_device *dev)
else if (INTEL_INFO(dev)->gen >= 8)
gen8_ppgtt_enable(dev);
else
- WARN_ON(1);
+ MISSING_CASE(INTEL_INFO(dev)->gen);
if (ppgtt) {
for_each_ring(ring, dev_priv, i) {
@@ -1341,9 +1402,12 @@ void i915_gem_restore_gtt_mappings(struct drm_device *dev)
/* The bind_vma code tries to be smart about tracking mappings.
* Unfortunately above, we've just wiped out the mappings
* without telling our object about it. So we need to fake it.
+ *
+ * Bind is not expected to fail since this is only called on
+ * resume and assumption is all requirements exist already.
*/
vma->bound &= ~GLOBAL_BIND;
- vma->bind_vma(vma, obj->cache_level, GLOBAL_BIND);
+ WARN_ON(i915_vma_bind(vma, obj->cache_level, GLOBAL_BIND));
}
@@ -1538,7 +1602,7 @@ static void i915_ggtt_bind_vma(struct i915_vma *vma,
AGP_USER_MEMORY : AGP_USER_CACHED_MEMORY;
BUG_ON(!i915_is_ggtt(vma->vm));
- intel_gtt_insert_sg_entries(vma->obj->pages, entry, flags);
+ intel_gtt_insert_sg_entries(vma->ggtt_view.pages, entry, flags);
vma->bound = GLOBAL_BIND;
}
@@ -1588,7 +1652,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
if (!dev_priv->mm.aliasing_ppgtt || flags & GLOBAL_BIND) {
if (!(vma->bound & GLOBAL_BIND) ||
(cache_level != obj->cache_level)) {
- vma->vm->insert_entries(vma->vm, obj->pages,
+ vma->vm->insert_entries(vma->vm, vma->ggtt_view.pages,
vma->node.start,
cache_level, flags);
vma->bound |= GLOBAL_BIND;
@@ -1600,7 +1664,7 @@ static void ggtt_bind_vma(struct i915_vma *vma,
(cache_level != obj->cache_level))) {
struct i915_hw_ppgtt *appgtt = dev_priv->mm.aliasing_ppgtt;
appgtt->base.insert_entries(&appgtt->base,
- vma->obj->pages,
+ vma->ggtt_view.pages,
vma->node.start,
cache_level, flags);
vma->bound |= LOCAL_BIND;
@@ -2165,7 +2229,8 @@ int i915_gem_gtt_init(struct drm_device *dev)
}
static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm)
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view)
{
struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
if (vma == NULL)
@@ -2176,12 +2241,9 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
INIT_LIST_HEAD(&vma->exec_list);
vma->vm = vm;
vma->obj = obj;
+ vma->ggtt_view = *view;
- switch (INTEL_INFO(vm->dev)->gen) {
- case 9:
- case 8:
- case 7:
- case 6:
+ if (INTEL_INFO(vm->dev)->gen >= 6) {
if (i915_is_ggtt(vm)) {
vma->unbind_vma = ggtt_unbind_vma;
vma->bind_vma = ggtt_bind_vma;
@@ -2189,39 +2251,73 @@ static struct i915_vma *__i915_gem_vma_create(struct drm_i915_gem_object *obj,
vma->unbind_vma = ppgtt_unbind_vma;
vma->bind_vma = ppgtt_bind_vma;
}
- break;
- case 5:
- case 4:
- case 3:
- case 2:
+ } else {
BUG_ON(!i915_is_ggtt(vm));
vma->unbind_vma = i915_ggtt_unbind_vma;
vma->bind_vma = i915_ggtt_bind_vma;
- break;
- default:
- BUG();
}
- /* Keep GGTT vmas first to make debug easier */
- if (i915_is_ggtt(vm))
- list_add(&vma->vma_link, &obj->vma_list);
- else {
- list_add_tail(&vma->vma_link, &obj->vma_list);
+ list_add_tail(&vma->vma_link, &obj->vma_list);
+ if (!i915_is_ggtt(vm))
i915_ppgtt_get(i915_vm_to_ppgtt(vm));
- }
return vma;
}
struct i915_vma *
-i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
- struct i915_address_space *vm)
+i915_gem_obj_lookup_or_create_vma_view(struct drm_i915_gem_object *obj,
+ struct i915_address_space *vm,
+ const struct i915_ggtt_view *view)
{
struct i915_vma *vma;
- vma = i915_gem_obj_to_vma(obj, vm);
+ vma = i915_gem_obj_to_vma_view(obj, vm, view);
if (!vma)
- vma = __i915_gem_vma_create(obj, vm);
+ vma = __i915_gem_vma_create(obj, vm, view);
return vma;
}
+
+static inline
+int i915_get_vma_pages(struct i915_vma *vma)
+{
+ if (vma->ggtt_view.pages)
+ return 0;
+
+ if (vma->ggtt_view.type == I915_GGTT_VIEW_NORMAL)
+ vma->ggtt_view.pages = vma->obj->pages;
+ else
+ WARN_ONCE(1, "GGTT view %u not implemented!\n",
+ vma->ggtt_view.type);
+
+ if (!vma->ggtt_view.pages) {
+ DRM_ERROR("Failed to get pages for VMA view type %u!\n",
+ vma->ggtt_view.type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * i915_vma_bind - Sets up PTEs for an VMA in it's corresponding address space.
+ * @vma: VMA to map
+ * @cache_level: mapping cache level
+ * @flags: flags like global or local mapping
+ *
+ * DMA addresses are taken from the scatter-gather table of this object (or of
+ * this VMA in case of non-default GGTT views) and PTE entries set up.
+ * Note that DMA addresses are also the only part of the SG table we care about.
+ */
+int i915_vma_bind(struct i915_vma *vma, enum i915_cache_level cache_level,
+ u32 flags)
+{
+ int ret = i915_get_vma_pages(vma);
+
+ if (ret)
+ return ret;
+
+ vma->bind_vma(vma, cache_level, flags);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/i915_gem_gtt.h b/drivers/gpu/drm/i915/i915_gem_gtt.h
index beaf4bcfdac8..e377c7d27bd4 100644
--- a/drivers/gpu/drm/i915/i915_gem_gtt.h
+++ b/drivers/gpu/drm/i915/i915_gem_gtt.h
@@ -109,7 +109,20 @@ typedef gen8_gtt_pte_t gen8_ppgtt_pde_t;
#define GEN8_PPAT_ELLC_OVERRIDE (0<<2)
#define GEN8_PPAT(i, x) ((uint64_t) (x) << ((i) * 8))
+enum i915_ggtt_view_type {
+ I915_GGTT_VIEW_NORMAL = 0,
+};
+
+struct i915_ggtt_view {
+ enum i915_ggtt_view_type type;
+
+ struct sg_table *pages;
+};
+
+extern const struct i915_ggtt_view i915_ggtt_view_normal;
+
enum i915_cache_level;
+
/**
* A VMA represents a GEM BO that is bound into an address space. Therefore, a
* VMA's presence cannot be guaranteed before binding, or after unbinding the
@@ -129,6 +142,15 @@ struct i915_vma {
#define PTE_READ_ONLY (1<<2)
unsigned int bound : 4;
+ /**
+ * Support different GGTT views into the same object.
+ * This means there can be multiple VMA mappings per object and per VM.
+ * i915_ggtt_view_type is used to distinguish between those entries.
+ * The default one of zero (I915_GGTT_VIEW_NORMAL) is default and also
+ * assumed in GEM functions which take no ggtt view parameter.
+ */
+ struct i915_ggtt_view ggtt_view;
+
/** This object's place on the active/inactive lists */
struct list_head mm_list;
@@ -146,11 +168,10 @@ struct i915_vma {
/**
* How many users have pinned this object in GTT space. The following
- * users can each hold at most one reference: pwrite/pread, pin_ioctl
- * (via user_pin_count), execbuffer (objects are not allowed multiple
- * times for the same batchbuffer), and the framebuffer code. When
- * switching/pageflipping, the framebuffer code has at most two buffers
- * pinned per crtc.
+ * users can each hold at most one reference: pwrite/pread, execbuffer
+ * (objects are not allowed multiple times for the same batchbuffer),
+ * and the framebuffer code. When switching/pageflipping, the
+ * framebuffer code has at most two buffers pinned per crtc.
*
* In the worst case this is 1 + 1 + 1 + 2*2 = 7. That would fit into 3
* bits with absolutely no headroom. So use 4 bits. */
@@ -182,7 +203,7 @@ struct i915_address_space {
* List of objects currently involved in rendering.
*
* Includes buffers having the contents of their GPU caches
- * flushed, not necessarily primitives. last_rendering_seqno
+ * flushed, not necessarily primitives. last_read_req
* represents when the rendering involved will be completed.
*
* A reference is held on the buffer while on this list.
@@ -193,7 +214,7 @@ struct i915_address_space {
* LRU list of objects which are not in the ringbuffer and
* are ready to unbind, but are still in the GTT.
*
- * last_rendering_seqno is 0 while an object is in this list.
+ * last_read_req is NULL while an object is in this list.
*
* A reference is not held on the buffer while on this list,
* as merely being GTT-bound shouldn't prevent its being
diff --git a/drivers/gpu/drm/i915/i915_gem_render_state.c b/drivers/gpu/drm/i915/i915_gem_render_state.c
index 98dcd94acba8..521548a08578 100644
--- a/drivers/gpu/drm/i915/i915_gem_render_state.c
+++ b/drivers/gpu/drm/i915/i915_gem_render_state.c
@@ -173,7 +173,7 @@ int i915_gem_render_state_init(struct intel_engine_cs *ring)
i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
- ret = __i915_add_request(ring, NULL, so.obj, NULL);
+ ret = __i915_add_request(ring, NULL, so.obj);
/* __i915_add_request moves object to inactive if it fails */
out:
i915_gem_render_state_fini(&so);
diff --git a/drivers/gpu/drm/i915/i915_gem_stolen.c b/drivers/gpu/drm/i915/i915_gem_stolen.c
index a2045848bd1a..9c6f93ec886b 100644
--- a/drivers/gpu/drm/i915/i915_gem_stolen.c
+++ b/drivers/gpu/drm/i915/i915_gem_stolen.c
@@ -485,10 +485,8 @@ i915_gem_object_create_stolen_for_preallocated(struct drm_device *dev,
stolen_offset, gtt_offset, size);
/* KISS and expect everything to be page-aligned */
- BUG_ON(stolen_offset & 4095);
- BUG_ON(size & 4095);
-
- if (WARN_ON(size == 0))
+ if (WARN_ON(size == 0) || WARN_ON(size & 4095) ||
+ WARN_ON(stolen_offset & 4095))
return NULL;
stolen = kzalloc(sizeof(*stolen), GFP_KERNEL);
diff --git a/drivers/gpu/drm/i915/i915_gem_tiling.c b/drivers/gpu/drm/i915/i915_gem_tiling.c
index 4727a4e2c87c..6377b22269ad 100644
--- a/drivers/gpu/drm/i915/i915_gem_tiling.c
+++ b/drivers/gpu/drm/i915/i915_gem_tiling.c
@@ -335,9 +335,10 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
return -EINVAL;
}
+ mutex_lock(&dev->struct_mutex);
if (i915_gem_obj_is_pinned(obj) || obj->framebuffer_references) {
- drm_gem_object_unreference_unlocked(&obj->base);
- return -EBUSY;
+ ret = -EBUSY;
+ goto err;
}
if (args->tiling_mode == I915_TILING_NONE) {
@@ -369,7 +370,6 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
}
}
- mutex_lock(&dev->struct_mutex);
if (args->tiling_mode != obj->tiling_mode ||
args->stride != obj->stride) {
/* We need to rebind the object if its current allocation
@@ -399,7 +399,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
}
obj->fence_dirty =
- obj->last_fenced_seqno ||
+ obj->last_fenced_req ||
obj->fence_reg != I915_FENCE_REG_NONE;
obj->tiling_mode = args->tiling_mode;
@@ -424,6 +424,7 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
obj->bit_17 = NULL;
}
+err:
drm_gem_object_unreference(&obj->base);
mutex_unlock(&dev->struct_mutex);
diff --git a/drivers/gpu/drm/i915/i915_gem_userptr.c b/drivers/gpu/drm/i915/i915_gem_userptr.c
index d182058383a9..1719078c763a 100644
--- a/drivers/gpu/drm/i915/i915_gem_userptr.c
+++ b/drivers/gpu/drm/i915/i915_gem_userptr.c
@@ -113,7 +113,10 @@ restart:
continue;
obj = mo->obj;
- drm_gem_object_reference(&obj->base);
+
+ if (!kref_get_unless_zero(&obj->base.refcount))
+ continue;
+
spin_unlock(&mn->lock);
cancel_userptr(obj);
@@ -149,7 +152,20 @@ static void i915_gem_userptr_mn_invalidate_range_start(struct mmu_notifier *_mn,
it = interval_tree_iter_first(&mn->objects, start, end);
if (it != NULL) {
obj = container_of(it, struct i915_mmu_object, it)->obj;
- drm_gem_object_reference(&obj->base);
+
+ /* The mmu_object is released late when destroying the
+ * GEM object so it is entirely possible to gain a
+ * reference on an object in the process of being freed
+ * since our serialisation is via the spinlock and not
+ * the struct_mutex - and consequently use it after it
+ * is freed and then double free it.
+ */
+ if (!kref_get_unless_zero(&obj->base.refcount)) {
+ spin_unlock(&mn->lock);
+ serial = 0;
+ continue;
+ }
+
serial = mn->serial;
}
spin_unlock(&mn->lock);
diff --git a/drivers/gpu/drm/i915/i915_gpu_error.c b/drivers/gpu/drm/i915/i915_gpu_error.c
index cdaee6ce05f8..48ddbf44c862 100644
--- a/drivers/gpu/drm/i915/i915_gpu_error.c
+++ b/drivers/gpu/drm/i915/i915_gpu_error.c
@@ -670,8 +670,8 @@ static void capture_bo(struct drm_i915_error_buffer *err,
err->size = obj->base.size;
err->name = obj->base.name;
- err->rseqno = obj->last_read_seqno;
- err->wseqno = obj->last_write_seqno;
+ err->rseqno = i915_gem_request_get_seqno(obj->last_read_req);
+ err->wseqno = i915_gem_request_get_seqno(obj->last_write_req);
err->gtt_offset = vma->node.start;
err->read_domains = obj->base.read_domains;
err->write_domain = obj->base.write_domain;
@@ -679,13 +679,12 @@ static void capture_bo(struct drm_i915_error_buffer *err,
err->pinned = 0;
if (i915_gem_obj_is_pinned(obj))
err->pinned = 1;
- if (obj->user_pin_count > 0)
- err->pinned = -1;
err->tiling = obj->tiling_mode;
err->dirty = obj->dirty;
err->purgeable = obj->madv != I915_MADV_WILLNEED;
err->userptr = obj->userptr.mm != NULL;
- err->ring = obj->ring ? obj->ring->id : -1;
+ err->ring = obj->last_read_req ?
+ i915_gem_request_get_ring(obj->last_read_req)->id : -1;
err->cache_level = obj->cache_level;
}
@@ -719,10 +718,8 @@ static u32 capture_pinned_bo(struct drm_i915_error_buffer *err,
break;
list_for_each_entry(vma, &obj->vma_list, vma_link)
- if (vma->vm == vm && vma->pin_count > 0) {
+ if (vma->vm == vm && vma->pin_count > 0)
capture_bo(err++, vma);
- break;
- }
}
return err - first;
@@ -767,32 +764,21 @@ static void i915_gem_record_fences(struct drm_device *dev,
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
- /* Fences */
- switch (INTEL_INFO(dev)->gen) {
- case 9:
- case 8:
- case 7:
- case 6:
- for (i = 0; i < dev_priv->num_fence_regs; i++)
- error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 + (i * 8));
- break;
- case 5:
- case 4:
- for (i = 0; i < 16; i++)
- error->fence[i] = I915_READ64(FENCE_REG_965_0 + (i * 8));
- break;
- case 3:
- if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
- for (i = 0; i < 8; i++)
- error->fence[i+8] = I915_READ(FENCE_REG_945_8 + (i * 4));
- case 2:
+ if (IS_GEN3(dev) || IS_GEN2(dev)) {
for (i = 0; i < 8; i++)
error->fence[i] = I915_READ(FENCE_REG_830_0 + (i * 4));
- break;
-
- default:
- BUG();
- }
+ if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev))
+ for (i = 0; i < 8; i++)
+ error->fence[i+8] = I915_READ(FENCE_REG_945_8 +
+ (i * 4));
+ } else if (IS_GEN5(dev) || IS_GEN4(dev))
+ for (i = 0; i < 16; i++)
+ error->fence[i] = I915_READ64(FENCE_REG_965_0 +
+ (i * 8));
+ else if (INTEL_INFO(dev)->gen >= 6)
+ for (i = 0; i < dev_priv->num_fence_regs; i++)
+ error->fence[i] = I915_READ64(FENCE_REG_SANDYBRIDGE_0 +
+ (i * 8));
}
@@ -926,9 +912,13 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->vm_info.gfx_mode = I915_READ(RING_MODE_GEN7(ring));
- switch (INTEL_INFO(dev)->gen) {
- case 9:
- case 8:
+ if (IS_GEN6(dev))
+ ering->vm_info.pp_dir_base =
+ I915_READ(RING_PP_DIR_BASE_READ(ring));
+ else if (IS_GEN7(dev))
+ ering->vm_info.pp_dir_base =
+ I915_READ(RING_PP_DIR_BASE(ring));
+ else if (INTEL_INFO(dev)->gen >= 8)
for (i = 0; i < 4; i++) {
ering->vm_info.pdp[i] =
I915_READ(GEN8_RING_PDP_UDW(ring, i));
@@ -936,16 +926,6 @@ static void i915_record_ring_state(struct drm_device *dev,
ering->vm_info.pdp[i] |=
I915_READ(GEN8_RING_PDP_LDW(ring, i));
}
- break;
- case 7:
- ering->vm_info.pp_dir_base =
- I915_READ(RING_PP_DIR_BASE(ring));
- break;
- case 6:
- ering->vm_info.pp_dir_base =
- I915_READ(RING_PP_DIR_BASE_READ(ring));
- break;
- }
}
}
@@ -1072,7 +1052,7 @@ static void i915_gem_record_rings(struct drm_device *dev,
erq = &error->ring[i].requests[count++];
erq->seqno = request->seqno;
erq->jiffies = request->emitted_jiffies;
- erq->tail = request->tail;
+ erq->tail = request->postfix;
}
}
}
@@ -1097,10 +1077,8 @@ static void i915_gem_capture_vm(struct drm_i915_private *dev_priv,
list_for_each_entry(obj, &dev_priv->mm.bound_list, global_list) {
list_for_each_entry(vma, &obj->vma_list, vma_link)
- if (vma->vm == vm && vma->pin_count > 0) {
+ if (vma->vm == vm && vma->pin_count > 0)
i++;
- break;
- }
}
error->pinned_bo_count[ndx] = i - error->active_bo_count[ndx];
@@ -1378,26 +1356,15 @@ void i915_get_extra_instdone(struct drm_device *dev, uint32_t *instdone)
struct drm_i915_private *dev_priv = dev->dev_private;
memset(instdone, 0, sizeof(*instdone) * I915_NUM_INSTDONE_REG);
- switch (INTEL_INFO(dev)->gen) {
- case 2:
- case 3:
+ if (IS_GEN2(dev) || IS_GEN3(dev))
instdone[0] = I915_READ(INSTDONE);
- break;
- case 4:
- case 5:
- case 6:
+ else if (IS_GEN4(dev) || IS_GEN5(dev) || IS_GEN6(dev)) {
instdone[0] = I915_READ(INSTDONE_I965);
instdone[1] = I915_READ(INSTDONE1);
- break;
- default:
- WARN_ONCE(1, "Unsupported platform\n");
- case 7:
- case 8:
- case 9:
+ } else if (INTEL_INFO(dev)->gen >= 7) {
instdone[0] = I915_READ(GEN7_INSTDONE_1);
instdone[1] = I915_READ(GEN7_SC_INSTDONE);
instdone[2] = I915_READ(GEN7_SAMPLER_INSTDONE);
instdone[3] = I915_READ(GEN7_ROW_INSTDONE);
- break;
}
}
diff --git a/drivers/gpu/drm/i915/i915_irq.c b/drivers/gpu/drm/i915/i915_irq.c
index b051a238baf9..ede5bbbd8a08 100644
--- a/drivers/gpu/drm/i915/i915_irq.c
+++ b/drivers/gpu/drm/i915/i915_irq.c
@@ -45,7 +45,7 @@
* and related files, but that will be described in separate chapters.
*/
-static const u32 hpd_ibx[] = {
+static const u32 hpd_ibx[HPD_NUM_PINS] = {
[HPD_CRT] = SDE_CRT_HOTPLUG,
[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG,
[HPD_PORT_B] = SDE_PORTB_HOTPLUG,
@@ -53,7 +53,7 @@ static const u32 hpd_ibx[] = {
[HPD_PORT_D] = SDE_PORTD_HOTPLUG
};
-static const u32 hpd_cpt[] = {
+static const u32 hpd_cpt[HPD_NUM_PINS] = {
[HPD_CRT] = SDE_CRT_HOTPLUG_CPT,
[HPD_SDVO_B] = SDE_SDVOB_HOTPLUG_CPT,
[HPD_PORT_B] = SDE_PORTB_HOTPLUG_CPT,
@@ -61,7 +61,7 @@ static const u32 hpd_cpt[] = {
[HPD_PORT_D] = SDE_PORTD_HOTPLUG_CPT
};
-static const u32 hpd_mask_i915[] = {
+static const u32 hpd_mask_i915[HPD_NUM_PINS] = {
[HPD_CRT] = CRT_HOTPLUG_INT_EN,
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_EN,
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_EN,
@@ -70,7 +70,7 @@ static const u32 hpd_mask_i915[] = {
[HPD_PORT_D] = PORTD_HOTPLUG_INT_EN
};
-static const u32 hpd_status_g4x[] = {
+static const u32 hpd_status_g4x[HPD_NUM_PINS] = {
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_G4X,
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_G4X,
@@ -79,7 +79,7 @@ static const u32 hpd_status_g4x[] = {
[HPD_PORT_D] = PORTD_HOTPLUG_INT_STATUS
};
-static const u32 hpd_status_i915[] = { /* i915 and valleyview are the same */
+static const u32 hpd_status_i915[HPD_NUM_PINS] = { /* i915 and valleyview are the same */
[HPD_CRT] = CRT_HOTPLUG_INT_STATUS,
[HPD_SDVO_B] = SDVOB_HOTPLUG_INT_STATUS_I915,
[HPD_SDVO_C] = SDVOC_HOTPLUG_INT_STATUS_I915,
@@ -183,6 +183,8 @@ static void ilk_update_gt_irq(struct drm_i915_private *dev_priv,
{
assert_spin_locked(&dev_priv->irq_lock);
+ WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
if (WARN_ON(!intel_irqs_enabled(dev_priv)))
return;
@@ -229,6 +231,8 @@ static void snb_update_pm_irq(struct drm_i915_private *dev_priv,
{
uint32_t new_val;
+ WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
assert_spin_locked(&dev_priv->irq_lock);
new_val = dev_priv->pm_irq_mask;
@@ -348,6 +352,8 @@ void ibx_display_interrupt_update(struct drm_i915_private *dev_priv,
sdeimr &= ~interrupt_mask;
sdeimr |= (~enabled_irq_mask & interrupt_mask);
+ WARN_ON(enabled_irq_mask & ~interrupt_mask);
+
assert_spin_locked(&dev_priv->irq_lock);
if (WARN_ON(!intel_irqs_enabled(dev_priv)))
@@ -587,7 +593,7 @@ static u32 i915_get_vblank_counter(struct drm_device *dev, int pipe)
struct intel_crtc *intel_crtc =
to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
const struct drm_display_mode *mode =
- &intel_crtc->config.adjusted_mode;
+ &intel_crtc->config->base.adjusted_mode;
htotal = mode->crtc_htotal;
hsync_start = mode->crtc_hsync_start;
@@ -658,7 +664,7 @@ static int __intel_get_crtc_scanline(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+ const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
enum pipe pipe = crtc->pipe;
int position, vtotal;
@@ -685,7 +691,7 @@ static int i915_get_crtc_scanoutpos(struct drm_device *dev, int pipe,
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- const struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+ const struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
int position;
int vbl_start, vbl_end, hsync_start, htotal, vtotal;
bool in_vbl = true;
@@ -843,7 +849,7 @@ static int i915_get_vblank_timestamp(struct drm_device *dev, int pipe,
return drm_calc_vbltimestamp_from_scanoutpos(dev, pipe, max_error,
vblank_time, flags,
crtc,
- &to_intel_crtc(crtc)->config.adjusted_mode);
+ &to_intel_crtc(crtc)->config->base.adjusted_mode);
}
static bool intel_hpd_irq_event(struct drm_device *dev,
@@ -873,7 +879,7 @@ static void i915_digport_work_func(struct work_struct *work)
container_of(work, struct drm_i915_private, dig_port_work);
u32 long_port_mask, short_port_mask;
struct intel_digital_port *intel_dig_port;
- int i, ret;
+ int i;
u32 old_bits = 0;
spin_lock_irq(&dev_priv->irq_lock);
@@ -897,9 +903,11 @@ static void i915_digport_work_func(struct work_struct *work)
valid = true;
if (valid) {
+ enum irqreturn ret;
+
ret = intel_dig_port->hpd_pulse(intel_dig_port, long_hpd);
- if (ret == true) {
- /* if we get true fallback to old school hpd */
+ if (ret == IRQ_NONE) {
+ /* fall back to old school hpd */
old_bits |= (1 << intel_dig_port->base.hpd_pin);
}
}
@@ -1033,7 +1041,7 @@ static void notify_ring(struct drm_device *dev,
if (!intel_ring_initialized(ring))
return;
- trace_i915_gem_request_complete(ring);
+ trace_i915_gem_request_notify(ring);
wake_up_all(&ring->irq_queue);
}
@@ -1399,14 +1407,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (rcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring);
if (rcs & GT_CONTEXT_SWITCH_INTERRUPT)
- intel_execlists_handle_ctx_events(ring);
+ intel_lrc_irq_handler(ring);
bcs = tmp >> GEN8_BCS_IRQ_SHIFT;
ring = &dev_priv->ring[BCS];
if (bcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring);
if (bcs & GT_CONTEXT_SWITCH_INTERRUPT)
- intel_execlists_handle_ctx_events(ring);
+ intel_lrc_irq_handler(ring);
} else
DRM_ERROR("The master control interrupt lied (GT0)!\n");
}
@@ -1422,14 +1430,14 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (vcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring);
if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
- intel_execlists_handle_ctx_events(ring);
+ intel_lrc_irq_handler(ring);
vcs = tmp >> GEN8_VCS2_IRQ_SHIFT;
ring = &dev_priv->ring[VCS2];
if (vcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring);
if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
- intel_execlists_handle_ctx_events(ring);
+ intel_lrc_irq_handler(ring);
} else
DRM_ERROR("The master control interrupt lied (GT1)!\n");
}
@@ -1456,7 +1464,7 @@ static irqreturn_t gen8_gt_irq_handler(struct drm_device *dev,
if (vcs & GT_RENDER_USER_INTERRUPT)
notify_ring(dev, ring);
if (vcs & GT_CONTEXT_SWITCH_INTERRUPT)
- intel_execlists_handle_ctx_events(ring);
+ intel_lrc_irq_handler(ring);
} else
DRM_ERROR("The master control interrupt lied (GT3)!\n");
}
@@ -1516,7 +1524,7 @@ static inline enum port get_port_from_pin(enum hpd_pin pin)
static inline void intel_hpd_irq_handler(struct drm_device *dev,
u32 hotplug_trigger,
u32 dig_hotplug_reg,
- const u32 *hpd)
+ const u32 hpd[HPD_NUM_PINS])
{
struct drm_i915_private *dev_priv = dev->dev_private;
int i;
@@ -1884,6 +1892,9 @@ static irqreturn_t valleyview_irq_handler(int irq, void *arg)
u32 iir, gt_iir, pm_iir;
irqreturn_t ret = IRQ_NONE;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
while (true) {
/* Find, clear, then process each source of interrupt */
@@ -1928,6 +1939,9 @@ static irqreturn_t cherryview_irq_handler(int irq, void *arg)
u32 master_ctl, iir;
irqreturn_t ret = IRQ_NONE;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
for (;;) {
master_ctl = I915_READ(GEN8_MASTER_IRQ) & ~GEN8_MASTER_IRQ_CONTROL;
iir = I915_READ(VLV_IIR);
@@ -2200,6 +2214,9 @@ static irqreturn_t ironlake_irq_handler(int irq, void *arg)
u32 de_iir, gt_iir, de_ier, sde_ier = 0;
irqreturn_t ret = IRQ_NONE;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
/* We get interrupts on unclaimed registers, so check for this before we
* do any I915_{READ,WRITE}. */
intel_uncore_check_errors(dev);
@@ -2271,6 +2288,9 @@ static irqreturn_t gen8_irq_handler(int irq, void *arg)
enum pipe pipe;
u32 aux_mask = GEN8_AUX_CHANNEL_A;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
if (IS_GEN9(dev))
aux_mask |= GEN9_AUX_CHANNEL_B | GEN9_AUX_CHANNEL_C |
GEN9_AUX_CHANNEL_D;
@@ -2413,19 +2433,15 @@ static void i915_error_wake_up(struct drm_i915_private *dev_priv,
}
/**
- * i915_error_work_func - do process context error handling work
- * @work: work struct
+ * i915_reset_and_wakeup - do process context error handling work
*
* Fire an error uevent so userspace can see that a hang or error
* was detected.
*/
-static void i915_error_work_func(struct work_struct *work)
+static void i915_reset_and_wakeup(struct drm_device *dev)
{
- struct i915_gpu_error *error = container_of(work, struct i915_gpu_error,
- work);
- struct drm_i915_private *dev_priv =
- container_of(error, struct drm_i915_private, gpu_error);
- struct drm_device *dev = dev_priv->dev;
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ struct i915_gpu_error *error = &dev_priv->gpu_error;
char *error_event[] = { I915_ERROR_UEVENT "=1", NULL };
char *reset_event[] = { I915_RESET_UEVENT "=1", NULL };
char *reset_done_event[] = { I915_ERROR_UEVENT "=0", NULL };
@@ -2592,10 +2608,10 @@ static void i915_report_and_clear_eir(struct drm_device *dev)
}
/**
- * i915_handle_error - handle an error interrupt
+ * i915_handle_error - handle a gpu error
* @dev: drm device
*
- * Do some basic checking of regsiter state at error interrupt time and
+ * Do some basic checking of regsiter state at error time and
* dump it to the syslog. Also call i915_capture_error_state() to make
* sure we get a record and make it available in debugfs. Fire a uevent
* so userspace knows something bad happened (should trigger collection
@@ -2620,9 +2636,9 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
&dev_priv->gpu_error.reset_counter);
/*
- * Wakeup waiting processes so that the reset work function
- * i915_error_work_func doesn't deadlock trying to grab various
- * locks. By bumping the reset counter first, the woken
+ * Wakeup waiting processes so that the reset function
+ * i915_reset_and_wakeup doesn't deadlock trying to grab
+ * various locks. By bumping the reset counter first, the woken
* processes will see a reset in progress and back off,
* releasing their locks and then wait for the reset completion.
* We must do this for _all_ gpu waiters that might hold locks
@@ -2635,13 +2651,7 @@ void i915_handle_error(struct drm_device *dev, bool wedged,
i915_error_wake_up(dev_priv, false);
}
- /*
- * Our reset work can grab modeset locks (since it needs to reset the
- * state of outstanding pagelips). Hence it must not be run on our own
- * dev-priv->wq work queue for otherwise the flush_work in the pageflip
- * code will deadlock.
- */
- schedule_work(&dev_priv->gpu_error.work);
+ i915_reset_and_wakeup(dev);
}
/* Called from drm generic code, passed 'crtc' which
@@ -2769,18 +2779,18 @@ static void gen8_disable_vblank(struct drm_device *dev, int pipe)
spin_unlock_irqrestore(&dev_priv->irq_lock, irqflags);
}
-static u32
-ring_last_seqno(struct intel_engine_cs *ring)
+static struct drm_i915_gem_request *
+ring_last_request(struct intel_engine_cs *ring)
{
return list_entry(ring->request_list.prev,
- struct drm_i915_gem_request, list)->seqno;
+ struct drm_i915_gem_request, list);
}
static bool
-ring_idle(struct intel_engine_cs *ring, u32 seqno)
+ring_idle(struct intel_engine_cs *ring)
{
return (list_empty(&ring->request_list) ||
- i915_seqno_passed(seqno, ring_last_seqno(ring)));
+ i915_gem_request_completed(ring_last_request(ring), false));
}
static bool
@@ -2966,7 +2976,7 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
return HANGCHECK_HUNG;
}
-/**
+/*
* This is called when the chip hasn't reported back with completed
* batchbuffers in a long time. We keep track per ring seqno progress and
* if there are no progress, hangcheck score for that ring is increased.
@@ -2974,10 +2984,12 @@ ring_stuck(struct intel_engine_cs *ring, u64 acthd)
* we kick the ring. If we see no progress on three subsequent calls
* we assume chip is wedged and try to fix it by resetting the chip.
*/
-static void i915_hangcheck_elapsed(unsigned long data)
+static void i915_hangcheck_elapsed(struct work_struct *work)
{
- struct drm_device *dev = (struct drm_device *)data;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_i915_private *dev_priv =
+ container_of(work, typeof(*dev_priv),
+ gpu_error.hangcheck_work.work);
+ struct drm_device *dev = dev_priv->dev;
struct intel_engine_cs *ring;
int i;
int busy_count = 0, rings_hung = 0;
@@ -3000,7 +3012,7 @@ static void i915_hangcheck_elapsed(unsigned long data)
acthd = intel_ring_get_active_head(ring);
if (ring->hangcheck.seqno == seqno) {
- if (ring_idle(ring, seqno)) {
+ if (ring_idle(ring)) {
ring->hangcheck.action = HANGCHECK_IDLE;
if (waitqueue_active(&ring->irq_queue)) {
@@ -3091,17 +3103,18 @@ static void i915_hangcheck_elapsed(unsigned long data)
void i915_queue_hangcheck(struct drm_device *dev)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct timer_list *timer = &dev_priv->gpu_error.hangcheck_timer;
+ struct i915_gpu_error *e = &to_i915(dev)->gpu_error;
if (!i915.enable_hangcheck)
return;
- /* Don't continually defer the hangcheck, but make sure it is active */
- if (timer_pending(timer))
- return;
- mod_timer(timer,
- round_jiffies_up(jiffies + DRM_I915_HANGCHECK_JIFFIES));
+ /* Don't continually defer the hangcheck so that it is always run at
+ * least once after work has been scheduled on any ring. Otherwise,
+ * we will ignore a hung ring if a second ring is kept busy.
+ */
+
+ queue_delayed_work(e->hangcheck_wq, &e->hangcheck_work,
+ round_jiffies_up_relative(DRM_I915_HANGCHECK_JIFFIES));
}
static void ibx_irq_reset(struct drm_device *dev)
@@ -3770,6 +3783,9 @@ static irqreturn_t i8xx_irq_handler(int irq, void *arg)
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
iir = I915_READ16(IIR);
if (iir == 0)
return IRQ_NONE;
@@ -3950,6 +3966,9 @@ static irqreturn_t i915_irq_handler(int irq, void *arg)
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
int pipe, ret = IRQ_NONE;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
iir = I915_READ(IIR);
do {
bool irq_received = (iir & ~flip_mask) != 0;
@@ -4139,26 +4158,24 @@ static void i915_hpd_irq_setup(struct drm_device *dev)
assert_spin_locked(&dev_priv->irq_lock);
- if (I915_HAS_HOTPLUG(dev)) {
- hotplug_en = I915_READ(PORT_HOTPLUG_EN);
- hotplug_en &= ~HOTPLUG_INT_EN_MASK;
- /* Note HDMI and DP share hotplug bits */
- /* enable bits are the same for all generations */
- for_each_intel_encoder(dev, intel_encoder)
- if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
- hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
- /* Programming the CRT detection parameters tends
- to generate a spurious hotplug event about three
- seconds later. So just do it once.
- */
- if (IS_G4X(dev))
- hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
- hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
- hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
-
- /* Ignore TV since it's buggy */
- I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
- }
+ hotplug_en = I915_READ(PORT_HOTPLUG_EN);
+ hotplug_en &= ~HOTPLUG_INT_EN_MASK;
+ /* Note HDMI and DP share hotplug bits */
+ /* enable bits are the same for all generations */
+ for_each_intel_encoder(dev, intel_encoder)
+ if (dev_priv->hpd_stats[intel_encoder->hpd_pin].hpd_mark == HPD_ENABLED)
+ hotplug_en |= hpd_mask_i915[intel_encoder->hpd_pin];
+ /* Programming the CRT detection parameters tends
+ to generate a spurious hotplug event about three
+ seconds later. So just do it once.
+ */
+ if (IS_G4X(dev))
+ hotplug_en |= CRT_HOTPLUG_ACTIVATION_PERIOD_64;
+ hotplug_en &= ~CRT_HOTPLUG_VOLTAGE_COMPARE_MASK;
+ hotplug_en |= CRT_HOTPLUG_VOLTAGE_COMPARE_50;
+
+ /* Ignore TV since it's buggy */
+ I915_WRITE(PORT_HOTPLUG_EN, hotplug_en);
}
static irqreturn_t i965_irq_handler(int irq, void *arg)
@@ -4172,6 +4189,9 @@ static irqreturn_t i965_irq_handler(int irq, void *arg)
I915_DISPLAY_PLANE_A_FLIP_PENDING_INTERRUPT |
I915_DISPLAY_PLANE_B_FLIP_PENDING_INTERRUPT;
+ if (!intel_irqs_enabled(dev_priv))
+ return IRQ_NONE;
+
iir = I915_READ(IIR);
for (;;) {
@@ -4336,7 +4356,6 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
INIT_WORK(&dev_priv->hotplug_work, i915_hotplug_work_func);
INIT_WORK(&dev_priv->dig_port_work, i915_digport_work_func);
- INIT_WORK(&dev_priv->gpu_error.work, i915_error_work_func);
INIT_WORK(&dev_priv->rps.work, gen6_pm_rps_work);
INIT_WORK(&dev_priv->l3_parity.error_work, ivybridge_parity_work);
@@ -4347,9 +4366,8 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
else
dev_priv->pm_rps_events = GEN6_PM_RPS_EVENTS;
- setup_timer(&dev_priv->gpu_error.hangcheck_timer,
- i915_hangcheck_elapsed,
- (unsigned long) dev);
+ INIT_DELAYED_WORK(&dev_priv->gpu_error.hangcheck_work,
+ i915_hangcheck_elapsed);
INIT_DELAYED_WORK(&dev_priv->hotplug_reenable_work,
intel_hpd_irq_reenable_work);
@@ -4422,14 +4440,14 @@ void intel_irq_init(struct drm_i915_private *dev_priv)
dev->driver->irq_postinstall = i915_irq_postinstall;
dev->driver->irq_uninstall = i915_irq_uninstall;
dev->driver->irq_handler = i915_irq_handler;
- dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
} else {
dev->driver->irq_preinstall = i965_irq_preinstall;
dev->driver->irq_postinstall = i965_irq_postinstall;
dev->driver->irq_uninstall = i965_irq_uninstall;
dev->driver->irq_handler = i965_irq_handler;
- dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
}
+ if (I915_HAS_HOTPLUG(dev_priv))
+ dev_priv->display.hpd_irq_setup = i915_hpd_irq_setup;
dev->driver->enable_vblank = i915_enable_vblank;
dev->driver->disable_vblank = i915_disable_vblank;
}
@@ -4523,6 +4541,7 @@ void intel_runtime_pm_disable_interrupts(struct drm_i915_private *dev_priv)
{
dev_priv->dev->driver->irq_uninstall(dev_priv->dev);
dev_priv->pm.irqs_enabled = false;
+ synchronize_irq(dev_priv->dev->irq);
}
/**
diff --git a/drivers/gpu/drm/i915/i915_params.c b/drivers/gpu/drm/i915/i915_params.c
index c91cb2033cc5..44f2262a5553 100644
--- a/drivers/gpu/drm/i915/i915_params.c
+++ b/drivers/gpu/drm/i915/i915_params.c
@@ -35,7 +35,7 @@ struct i915_params i915 __read_mostly = {
.vbt_sdvo_panel_type = -1,
.enable_rc6 = -1,
.enable_fbc = -1,
- .enable_execlists = 0,
+ .enable_execlists = -1,
.enable_hangcheck = true,
.enable_ppgtt = -1,
.enable_psr = 0,
@@ -51,6 +51,8 @@ struct i915_params i915 __read_mostly = {
.disable_vtd_wa = 0,
.use_mmio_flip = 0,
.mmio_debug = 0,
+ .verbose_state_checks = 1,
+ .nuclear_pageflip = 0,
};
module_param_named(modeset, i915.modeset, int, 0400);
@@ -122,7 +124,7 @@ MODULE_PARM_DESC(enable_ppgtt,
module_param_named(enable_execlists, i915.enable_execlists, int, 0400);
MODULE_PARM_DESC(enable_execlists,
"Override execlists usage. "
- "(-1=auto, 0=disabled [default], 1=enabled)");
+ "(-1=auto [default], 0=disabled, 1=enabled)");
module_param_named(enable_psr, i915.enable_psr, int, 0600);
MODULE_PARM_DESC(enable_psr, "Enable PSR (default: false)");
@@ -173,3 +175,11 @@ module_param_named(mmio_debug, i915.mmio_debug, bool, 0600);
MODULE_PARM_DESC(mmio_debug,
"Enable the MMIO debug code (default: false). This may negatively "
"affect performance.");
+
+module_param_named(verbose_state_checks, i915.verbose_state_checks, bool, 0600);
+MODULE_PARM_DESC(verbose_state_checks,
+ "Enable verbose logs (ie. WARN_ON()) in case of unexpected hw state conditions.");
+
+module_param_named_unsafe(nuclear_pageflip, i915.nuclear_pageflip, bool, 0600);
+MODULE_PARM_DESC(nuclear_pageflip,
+ "Force atomic modeset functionality; only planes work for now (default: false).");
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h
index 172de3b3433b..33b3d0a24071 100644
--- a/drivers/gpu/drm/i915/i915_reg.h
+++ b/drivers/gpu/drm/i915/i915_reg.h
@@ -31,6 +31,8 @@
#define _PORT(port, a, b) ((a) + (port)*((b)-(a)))
#define _PIPE3(pipe, a, b, c) ((pipe) == PIPE_A ? (a) : \
(pipe) == PIPE_B ? (b) : (c))
+#define _PORT3(port, a, b, c) ((port) == PORT_A ? (a) : \
+ (port) == PORT_B ? (b) : (c))
#define _MASKED_FIELD(mask, value) ({ \
if (__builtin_constant_p(mask)) \
@@ -217,6 +219,8 @@
#define INSTR_SUBCLIENT_SHIFT 27
#define INSTR_SUBCLIENT_MASK 0x18000000
#define INSTR_MEDIA_SUBCLIENT 0x2
+#define INSTR_26_TO_24_MASK 0x7000000
+#define INSTR_26_TO_24_SHIFT 24
/*
* Memory interface instructions used by the kernel
@@ -246,6 +250,7 @@
#define MI_BATCH_BUFFER_END MI_INSTR(0x0a, 0)
#define MI_SUSPEND_FLUSH MI_INSTR(0x0b, 0)
#define MI_SUSPEND_FLUSH_EN (1<<0)
+#define MI_SET_APPID MI_INSTR(0x0e, 0)
#define MI_OVERLAY_FLIP MI_INSTR(0x11, 0)
#define MI_OVERLAY_CONTINUE (0x0<<21)
#define MI_OVERLAY_ON (0x1<<21)
@@ -303,8 +308,9 @@
#define MI_SEMAPHORE_POLL (1<<15)
#define MI_SEMAPHORE_SAD_GTE_SDD (1<<12)
#define MI_STORE_DWORD_IMM MI_INSTR(0x20, 1)
-#define MI_STORE_DWORD_IMM_GEN8 MI_INSTR(0x20, 2)
-#define MI_MEM_VIRTUAL (1 << 22) /* 965+ only */
+#define MI_STORE_DWORD_IMM_GEN4 MI_INSTR(0x20, 2)
+#define MI_MEM_VIRTUAL (1 << 22) /* 945,g33,965 */
+#define MI_USE_GGTT (1 << 22) /* g4x+ */
#define MI_STORE_DWORD_INDEX MI_INSTR(0x21, 1)
#define MI_STORE_DWORD_INDEX_SHIFT 2
/* Official intel docs are somewhat sloppy concerning MI_LOAD_REGISTER_IMM:
@@ -470,17 +476,18 @@
*/
#define BCS_SWCTRL 0x22200
-#define HS_INVOCATION_COUNT 0x2300
-#define DS_INVOCATION_COUNT 0x2308
-#define IA_VERTICES_COUNT 0x2310
-#define IA_PRIMITIVES_COUNT 0x2318
-#define VS_INVOCATION_COUNT 0x2320
-#define GS_INVOCATION_COUNT 0x2328
-#define GS_PRIMITIVES_COUNT 0x2330
-#define CL_INVOCATION_COUNT 0x2338
-#define CL_PRIMITIVES_COUNT 0x2340
-#define PS_INVOCATION_COUNT 0x2348
-#define PS_DEPTH_COUNT 0x2350
+#define GPGPU_THREADS_DISPATCHED 0x2290
+#define HS_INVOCATION_COUNT 0x2300
+#define DS_INVOCATION_COUNT 0x2308
+#define IA_VERTICES_COUNT 0x2310
+#define IA_PRIMITIVES_COUNT 0x2318
+#define VS_INVOCATION_COUNT 0x2320
+#define GS_INVOCATION_COUNT 0x2328
+#define GS_PRIMITIVES_COUNT 0x2330
+#define CL_INVOCATION_COUNT 0x2338
+#define CL_PRIMITIVES_COUNT 0x2340
+#define PS_INVOCATION_COUNT 0x2348
+#define PS_DEPTH_COUNT 0x2350
/* There are the 4 64-bit counter registers, one for each stream output */
#define GEN7_SO_NUM_PRIMS_WRITTEN(n) (0x5200 + (n) * 8)
@@ -598,6 +605,15 @@ enum punit_power_well {
#define PUNIT_FUSE_BUS2 0xf6 /* bits 47:40 */
#define PUNIT_FUSE_BUS1 0xf5 /* bits 55:48 */
+#define FB_GFX_FMAX_AT_VMAX_FUSE 0x136
+#define FB_GFX_FREQ_FUSE_MASK 0xff
+#define FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT 24
+#define FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT 16
+#define FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT 8
+
+#define FB_GFX_FMIN_AT_VMIN_FUSE 0x137
+#define FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT 8
+
#define PUNIT_GPU_STATUS_REG 0xdb
#define PUNIT_GPU_STATUS_MAX_FREQ_SHIFT 16
#define PUNIT_GPU_STATUS_MAX_FREQ_MASK 0xff
@@ -1464,6 +1480,17 @@ enum punit_power_well {
#define GEN8_RC_SEMA_IDLE_MSG_DISABLE (1 << 12)
#define GEN8_FF_DOP_CLOCK_GATE_DISABLE (1<<10)
+/* Fuse readout registers for GT */
+#define CHV_FUSE_GT (VLV_DISPLAY_BASE + 0x2168)
+#define CHV_FGT_EU_DIS_SS0_R0_SHIFT 16
+#define CHV_FGT_EU_DIS_SS0_R0_MASK (0xf << CHV_FGT_EU_DIS_SS0_R0_SHIFT)
+#define CHV_FGT_EU_DIS_SS0_R1_SHIFT 20
+#define CHV_FGT_EU_DIS_SS0_R1_MASK (0xf << CHV_FGT_EU_DIS_SS0_R1_SHIFT)
+#define CHV_FGT_EU_DIS_SS1_R0_SHIFT 24
+#define CHV_FGT_EU_DIS_SS1_R0_MASK (0xf << CHV_FGT_EU_DIS_SS1_R0_SHIFT)
+#define CHV_FGT_EU_DIS_SS1_R1_SHIFT 28
+#define CHV_FGT_EU_DIS_SS1_R1_MASK (0xf << CHV_FGT_EU_DIS_SS1_R1_SHIFT)
+
#define GEN6_BSD_SLEEP_PSMI_CONTROL 0x12050
#define GEN6_BSD_SLEEP_MSG_DISABLE (1 << 0)
#define GEN6_BSD_SLEEP_FLUSH_DISABLE (1 << 2)
@@ -1509,7 +1536,7 @@ enum punit_power_well {
#define I915_ISP_INTERRUPT (1<<22)
#define I915_LPE_PIPE_B_INTERRUPT (1<<21)
#define I915_LPE_PIPE_A_INTERRUPT (1<<20)
-#define I915_MIPIB_INTERRUPT (1<<19)
+#define I915_MIPIC_INTERRUPT (1<<19)
#define I915_MIPIA_INTERRUPT (1<<18)
#define I915_PIPE_CONTROL_NOTIFY_INTERRUPT (1<<18)
#define I915_DISPLAY_PORT_INTERRUPT (1<<17)
@@ -2539,6 +2566,42 @@ enum punit_power_well {
#define PIPESRC(trans) _TRANSCODER2(trans, _PIPEASRC)
#define PIPE_MULT(trans) _TRANSCODER2(trans, _PIPE_MULT_A)
+/* VLV eDP PSR registers */
+#define _PSRCTLA (VLV_DISPLAY_BASE + 0x60090)
+#define _PSRCTLB (VLV_DISPLAY_BASE + 0x61090)
+#define VLV_EDP_PSR_ENABLE (1<<0)
+#define VLV_EDP_PSR_RESET (1<<1)
+#define VLV_EDP_PSR_MODE_MASK (7<<2)
+#define VLV_EDP_PSR_MODE_HW_TIMER (1<<3)
+#define VLV_EDP_PSR_MODE_SW_TIMER (1<<2)
+#define VLV_EDP_PSR_SINGLE_FRAME_UPDATE (1<<7)
+#define VLV_EDP_PSR_ACTIVE_ENTRY (1<<8)
+#define VLV_EDP_PSR_SRC_TRANSMITTER_STATE (1<<9)
+#define VLV_EDP_PSR_DBL_FRAME (1<<10)
+#define VLV_EDP_PSR_FRAME_COUNT_MASK (0xff<<16)
+#define VLV_EDP_PSR_IDLE_FRAME_SHIFT 16
+#define VLV_PSRCTL(pipe) _PIPE(pipe, _PSRCTLA, _PSRCTLB)
+
+#define _VSCSDPA (VLV_DISPLAY_BASE + 0x600a0)
+#define _VSCSDPB (VLV_DISPLAY_BASE + 0x610a0)
+#define VLV_EDP_PSR_SDP_FREQ_MASK (3<<30)
+#define VLV_EDP_PSR_SDP_FREQ_ONCE (1<<31)
+#define VLV_EDP_PSR_SDP_FREQ_EVFRAME (1<<30)
+#define VLV_VSCSDP(pipe) _PIPE(pipe, _VSCSDPA, _VSCSDPB)
+
+#define _PSRSTATA (VLV_DISPLAY_BASE + 0x60094)
+#define _PSRSTATB (VLV_DISPLAY_BASE + 0x61094)
+#define VLV_EDP_PSR_LAST_STATE_MASK (7<<3)
+#define VLV_EDP_PSR_CURR_STATE_MASK 7
+#define VLV_EDP_PSR_DISABLED (0<<0)
+#define VLV_EDP_PSR_INACTIVE (1<<0)
+#define VLV_EDP_PSR_IN_TRANS_TO_ACTIVE (2<<0)
+#define VLV_EDP_PSR_ACTIVE_NORFB_UP (3<<0)
+#define VLV_EDP_PSR_ACTIVE_SF_UPDATE (4<<0)
+#define VLV_EDP_PSR_EXIT (5<<0)
+#define VLV_EDP_PSR_IN_TRANS (1<<7)
+#define VLV_PSRSTAT(pipe) _PIPE(pipe, _PSRSTATA, _PSRSTATB)
+
/* HSW+ eDP PSR registers */
#define EDP_PSR_BASE(dev) (IS_HASWELL(dev) ? 0x64800 : 0x6f800)
#define EDP_PSR_CTL(dev) (EDP_PSR_BASE(dev) + 0)
@@ -2762,7 +2825,8 @@ enum punit_power_well {
#define DC_BALANCE_RESET (1 << 25)
#define PORT_DFT2_G4X (dev_priv->info.display_mmio_offset + 0x61154)
#define DC_BALANCE_RESET_VLV (1 << 31)
-#define PIPE_SCRAMBLE_RESET_MASK (0x3 << 0)
+#define PIPE_SCRAMBLE_RESET_MASK ((1 << 14) | (0x3 << 0))
+#define PIPE_C_SCRAMBLE_RESET (1 << 14) /* chv */
#define PIPE_B_SCRAMBLE_RESET (1 << 1)
#define PIPE_A_SCRAMBLE_RESET (1 << 0)
@@ -3704,6 +3768,11 @@ enum punit_power_well {
#define DP_AUX_CH_CTL_PRECHARGE_TEST (1 << 11)
#define DP_AUX_CH_CTL_BIT_CLOCK_2X_MASK (0x7ff)
#define DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT 0
+#define DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL (1 << 14)
+#define DP_AUX_CH_CTL_FS_DATA_AUX_REG_SKL (1 << 13)
+#define DP_AUX_CH_CTL_GTC_DATA_AUX_REG_SKL (1 << 12)
+#define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL_MASK (1f << 5)
+#define DP_AUX_CH_CTL_FW_SYNC_PULSE_SKL(c) (((c) - 1) << 5)
#define DP_AUX_CH_CTL_SYNC_PULSE_SKL(c) ((c) - 1)
/*
@@ -5158,6 +5227,9 @@ enum punit_power_well {
#define COMMON_SLICE_CHICKEN2 0x7014
# define GEN8_CSC2_SBE_VUE_CACHE_CONSERVATIVE (1<<0)
+#define HIZ_CHICKEN 0x7018
+# define CHV_HZ_8X8_MODE_IN_1X (1<<15)
+
#define GEN7_L3SQCREG1 0xB010
#define VLV_B0_WA_L3SQCREG1_VALUE 0x00D30000
@@ -6005,6 +6077,13 @@ enum punit_power_well {
#define GEN6_PMINTRMSK 0xA168
#define GEN8_PMINTR_REDIRECT_TO_NON_DISP (1<<31)
#define VLV_PWRDWNUPCTL 0xA294
+#define GEN9_MEDIA_PG_IDLE_HYSTERESIS 0xA0C4
+#define GEN9_RENDER_PG_IDLE_HYSTERESIS 0xA0C8
+#define GEN9_PG_ENABLE 0xA210
+
+#define VLV_CHICKEN_3 (VLV_DISPLAY_BASE + 0x7040C)
+#define PIXEL_OVERLAP_CNT_MASK (3 << 30)
+#define PIXEL_OVERLAP_CNT_SHIFT 30
#define GEN6_PMISR 0x44020
#define GEN6_PMIMR 0x44024 /* rps_lock */
@@ -6119,6 +6198,7 @@ enum punit_power_well {
#define HSW_ROW_CHICKEN3_L3_GLOBAL_ATOMICS_DISABLE (1 << 6)
#define HALF_SLICE_CHICKEN3 0xe184
+#define HSW_SAMPLE_C_PERFORMANCE (1<<9)
#define GEN8_CENTROID_PIXEL_OPT_DIS (1<<8)
#define GEN8_SAMPLER_POWER_BYPASS_DIS (1<<1)
@@ -6631,29 +6711,31 @@ enum punit_power_well {
#define PIPE_CSC_POSTOFF_ME(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_ME, _PIPE_B_CSC_POSTOFF_ME)
#define PIPE_CSC_POSTOFF_LO(pipe) _PIPE(pipe, _PIPE_A_CSC_POSTOFF_LO, _PIPE_B_CSC_POSTOFF_LO)
-/* VLV MIPI registers */
+/* MIPI DSI registers */
+
+#define _MIPI_PORT(port, a, c) _PORT3(port, a, 0, c) /* ports A and C only */
#define _MIPIA_PORT_CTRL (VLV_DISPLAY_BASE + 0x61190)
-#define _MIPIB_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700)
-#define MIPI_PORT_CTRL(tc) _TRANSCODER(tc, _MIPIA_PORT_CTRL, \
- _MIPIB_PORT_CTRL)
-#define DPI_ENABLE (1 << 31) /* A + B */
+#define _MIPIC_PORT_CTRL (VLV_DISPLAY_BASE + 0x61700)
+#define MIPI_PORT_CTRL(port) _MIPI_PORT(port, _MIPIA_PORT_CTRL, _MIPIC_PORT_CTRL)
+#define DPI_ENABLE (1 << 31) /* A + C */
#define MIPIA_MIPI4DPHY_DELAY_COUNT_SHIFT 27
#define MIPIA_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 27)
+#define DUAL_LINK_MODE_SHIFT 26
#define DUAL_LINK_MODE_MASK (1 << 26)
#define DUAL_LINK_MODE_FRONT_BACK (0 << 26)
#define DUAL_LINK_MODE_PIXEL_ALTERNATIVE (1 << 26)
-#define DITHERING_ENABLE (1 << 25) /* A + B */
+#define DITHERING_ENABLE (1 << 25) /* A + C */
#define FLOPPED_HSTX (1 << 23)
#define DE_INVERT (1 << 19) /* XXX */
#define MIPIA_FLISDSI_DELAY_COUNT_SHIFT 18
#define MIPIA_FLISDSI_DELAY_COUNT_MASK (0xf << 18)
#define AFE_LATCHOUT (1 << 17)
#define LP_OUTPUT_HOLD (1 << 16)
-#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15
-#define MIPIB_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15)
-#define MIPIB_MIPI4DPHY_DELAY_COUNT_SHIFT 11
-#define MIPIB_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11)
+#define MIPIC_FLISDSI_DELAY_COUNT_HIGH_SHIFT 15
+#define MIPIC_FLISDSI_DELAY_COUNT_HIGH_MASK (1 << 15)
+#define MIPIC_MIPI4DPHY_DELAY_COUNT_SHIFT 11
+#define MIPIC_MIPI4DPHY_DELAY_COUNT_MASK (0xf << 11)
#define CSB_SHIFT 9
#define CSB_MASK (3 << 9)
#define CSB_20MHZ (0 << 9)
@@ -6662,10 +6744,10 @@ enum punit_power_well {
#define BANDGAP_MASK (1 << 8)
#define BANDGAP_PNW_CIRCUIT (0 << 8)
#define BANDGAP_LNC_CIRCUIT (1 << 8)
-#define MIPIB_FLISDSI_DELAY_COUNT_LOW_SHIFT 5
-#define MIPIB_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5)
-#define TEARING_EFFECT_DELAY (1 << 4) /* A + B */
-#define TEARING_EFFECT_SHIFT 2 /* A + B */
+#define MIPIC_FLISDSI_DELAY_COUNT_LOW_SHIFT 5
+#define MIPIC_FLISDSI_DELAY_COUNT_LOW_MASK (7 << 5)
+#define TEARING_EFFECT_DELAY (1 << 4) /* A + C */
+#define TEARING_EFFECT_SHIFT 2 /* A + C */
#define TEARING_EFFECT_MASK (3 << 2)
#define TEARING_EFFECT_OFF (0 << 2)
#define TEARING_EFFECT_DSI (1 << 2)
@@ -6677,9 +6759,9 @@ enum punit_power_well {
#define LANE_CONFIGURATION_DUAL_LINK_B (2 << 0)
#define _MIPIA_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61194)
-#define _MIPIB_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704)
-#define MIPI_TEARING_CTRL(tc) _TRANSCODER(tc, \
- _MIPIA_TEARING_CTRL, _MIPIB_TEARING_CTRL)
+#define _MIPIC_TEARING_CTRL (VLV_DISPLAY_BASE + 0x61704)
+#define MIPI_TEARING_CTRL(port) _MIPI_PORT(port, \
+ _MIPIA_TEARING_CTRL, _MIPIC_TEARING_CTRL)
#define TEARING_EFFECT_DELAY_SHIFT 0
#define TEARING_EFFECT_DELAY_MASK (0xffff << 0)
@@ -6689,9 +6771,9 @@ enum punit_power_well {
/* MIPI DSI Controller and D-PHY registers */
#define _MIPIA_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb000)
-#define _MIPIB_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800)
-#define MIPI_DEVICE_READY(tc) _TRANSCODER(tc, _MIPIA_DEVICE_READY, \
- _MIPIB_DEVICE_READY)
+#define _MIPIC_DEVICE_READY (dev_priv->mipi_mmio_base + 0xb800)
+#define MIPI_DEVICE_READY(port) _MIPI_PORT(port, _MIPIA_DEVICE_READY, \
+ _MIPIC_DEVICE_READY)
#define BUS_POSSESSION (1 << 3) /* set to give bus to receiver */
#define ULPS_STATE_MASK (3 << 1)
#define ULPS_STATE_ENTER (2 << 1)
@@ -6700,13 +6782,13 @@ enum punit_power_well {
#define DEVICE_READY (1 << 0)
#define _MIPIA_INTR_STAT (dev_priv->mipi_mmio_base + 0xb004)
-#define _MIPIB_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804)
-#define MIPI_INTR_STAT(tc) _TRANSCODER(tc, _MIPIA_INTR_STAT, \
- _MIPIB_INTR_STAT)
+#define _MIPIC_INTR_STAT (dev_priv->mipi_mmio_base + 0xb804)
+#define MIPI_INTR_STAT(port) _MIPI_PORT(port, _MIPIA_INTR_STAT, \
+ _MIPIC_INTR_STAT)
#define _MIPIA_INTR_EN (dev_priv->mipi_mmio_base + 0xb008)
-#define _MIPIB_INTR_EN (dev_priv->mipi_mmio_base + 0xb808)
-#define MIPI_INTR_EN(tc) _TRANSCODER(tc, _MIPIA_INTR_EN, \
- _MIPIB_INTR_EN)
+#define _MIPIC_INTR_EN (dev_priv->mipi_mmio_base + 0xb808)
+#define MIPI_INTR_EN(port) _MIPI_PORT(port, _MIPIA_INTR_EN, \
+ _MIPIC_INTR_EN)
#define TEARING_EFFECT (1 << 31)
#define SPL_PKT_SENT_INTERRUPT (1 << 30)
#define GEN_READ_DATA_AVAIL (1 << 29)
@@ -6741,9 +6823,9 @@ enum punit_power_well {
#define RXSOT_ERROR (1 << 0)
#define _MIPIA_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb00c)
-#define _MIPIB_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c)
-#define MIPI_DSI_FUNC_PRG(tc) _TRANSCODER(tc, _MIPIA_DSI_FUNC_PRG, \
- _MIPIB_DSI_FUNC_PRG)
+#define _MIPIC_DSI_FUNC_PRG (dev_priv->mipi_mmio_base + 0xb80c)
+#define MIPI_DSI_FUNC_PRG(port) _MIPI_PORT(port, _MIPIA_DSI_FUNC_PRG, \
+ _MIPIC_DSI_FUNC_PRG)
#define CMD_MODE_DATA_WIDTH_MASK (7 << 13)
#define CMD_MODE_NOT_SUPPORTED (0 << 13)
#define CMD_MODE_DATA_WIDTH_16_BIT (1 << 13)
@@ -6765,93 +6847,93 @@ enum punit_power_well {
#define DATA_LANES_PRG_REG_MASK (7 << 0)
#define _MIPIA_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb010)
-#define _MIPIB_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810)
-#define MIPI_HS_TX_TIMEOUT(tc) _TRANSCODER(tc, _MIPIA_HS_TX_TIMEOUT, \
- _MIPIB_HS_TX_TIMEOUT)
+#define _MIPIC_HS_TX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb810)
+#define MIPI_HS_TX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_HS_TX_TIMEOUT, \
+ _MIPIC_HS_TX_TIMEOUT)
#define HIGH_SPEED_TX_TIMEOUT_COUNTER_MASK 0xffffff
#define _MIPIA_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb014)
-#define _MIPIB_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814)
-#define MIPI_LP_RX_TIMEOUT(tc) _TRANSCODER(tc, _MIPIA_LP_RX_TIMEOUT, \
- _MIPIB_LP_RX_TIMEOUT)
+#define _MIPIC_LP_RX_TIMEOUT (dev_priv->mipi_mmio_base + 0xb814)
+#define MIPI_LP_RX_TIMEOUT(port) _MIPI_PORT(port, _MIPIA_LP_RX_TIMEOUT, \
+ _MIPIC_LP_RX_TIMEOUT)
#define LOW_POWER_RX_TIMEOUT_COUNTER_MASK 0xffffff
#define _MIPIA_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb018)
-#define _MIPIB_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818)
-#define MIPI_TURN_AROUND_TIMEOUT(tc) _TRANSCODER(tc, \
- _MIPIA_TURN_AROUND_TIMEOUT, _MIPIB_TURN_AROUND_TIMEOUT)
+#define _MIPIC_TURN_AROUND_TIMEOUT (dev_priv->mipi_mmio_base + 0xb818)
+#define MIPI_TURN_AROUND_TIMEOUT(port) _MIPI_PORT(port, \
+ _MIPIA_TURN_AROUND_TIMEOUT, _MIPIC_TURN_AROUND_TIMEOUT)
#define TURN_AROUND_TIMEOUT_MASK 0x3f
#define _MIPIA_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb01c)
-#define _MIPIB_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c)
-#define MIPI_DEVICE_RESET_TIMER(tc) _TRANSCODER(tc, \
- _MIPIA_DEVICE_RESET_TIMER, _MIPIB_DEVICE_RESET_TIMER)
+#define _MIPIC_DEVICE_RESET_TIMER (dev_priv->mipi_mmio_base + 0xb81c)
+#define MIPI_DEVICE_RESET_TIMER(port) _MIPI_PORT(port, \
+ _MIPIA_DEVICE_RESET_TIMER, _MIPIC_DEVICE_RESET_TIMER)
#define DEVICE_RESET_TIMER_MASK 0xffff
#define _MIPIA_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb020)
-#define _MIPIB_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820)
-#define MIPI_DPI_RESOLUTION(tc) _TRANSCODER(tc, _MIPIA_DPI_RESOLUTION, \
- _MIPIB_DPI_RESOLUTION)
+#define _MIPIC_DPI_RESOLUTION (dev_priv->mipi_mmio_base + 0xb820)
+#define MIPI_DPI_RESOLUTION(port) _MIPI_PORT(port, _MIPIA_DPI_RESOLUTION, \
+ _MIPIC_DPI_RESOLUTION)
#define VERTICAL_ADDRESS_SHIFT 16
#define VERTICAL_ADDRESS_MASK (0xffff << 16)
#define HORIZONTAL_ADDRESS_SHIFT 0
#define HORIZONTAL_ADDRESS_MASK 0xffff
#define _MIPIA_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb024)
-#define _MIPIB_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824)
-#define MIPI_DBI_FIFO_THROTTLE(tc) _TRANSCODER(tc, \
- _MIPIA_DBI_FIFO_THROTTLE, _MIPIB_DBI_FIFO_THROTTLE)
+#define _MIPIC_DBI_FIFO_THROTTLE (dev_priv->mipi_mmio_base + 0xb824)
+#define MIPI_DBI_FIFO_THROTTLE(port) _MIPI_PORT(port, \
+ _MIPIA_DBI_FIFO_THROTTLE, _MIPIC_DBI_FIFO_THROTTLE)
#define DBI_FIFO_EMPTY_HALF (0 << 0)
#define DBI_FIFO_EMPTY_QUARTER (1 << 0)
#define DBI_FIFO_EMPTY_7_LOCATIONS (2 << 0)
/* regs below are bits 15:0 */
#define _MIPIA_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb028)
-#define _MIPIB_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828)
-#define MIPI_HSYNC_PADDING_COUNT(tc) _TRANSCODER(tc, \
- _MIPIA_HSYNC_PADDING_COUNT, _MIPIB_HSYNC_PADDING_COUNT)
+#define _MIPIC_HSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb828)
+#define MIPI_HSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \
+ _MIPIA_HSYNC_PADDING_COUNT, _MIPIC_HSYNC_PADDING_COUNT)
#define _MIPIA_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb02c)
-#define _MIPIB_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c)
-#define MIPI_HBP_COUNT(tc) _TRANSCODER(tc, _MIPIA_HBP_COUNT, \
- _MIPIB_HBP_COUNT)
+#define _MIPIC_HBP_COUNT (dev_priv->mipi_mmio_base + 0xb82c)
+#define MIPI_HBP_COUNT(port) _MIPI_PORT(port, _MIPIA_HBP_COUNT, \
+ _MIPIC_HBP_COUNT)
#define _MIPIA_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb030)
-#define _MIPIB_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830)
-#define MIPI_HFP_COUNT(tc) _TRANSCODER(tc, _MIPIA_HFP_COUNT, \
- _MIPIB_HFP_COUNT)
+#define _MIPIC_HFP_COUNT (dev_priv->mipi_mmio_base + 0xb830)
+#define MIPI_HFP_COUNT(port) _MIPI_PORT(port, _MIPIA_HFP_COUNT, \
+ _MIPIC_HFP_COUNT)
#define _MIPIA_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb034)
-#define _MIPIB_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834)
-#define MIPI_HACTIVE_AREA_COUNT(tc) _TRANSCODER(tc, \
- _MIPIA_HACTIVE_AREA_COUNT, _MIPIB_HACTIVE_AREA_COUNT)
+#define _MIPIC_HACTIVE_AREA_COUNT (dev_priv->mipi_mmio_base + 0xb834)
+#define MIPI_HACTIVE_AREA_COUNT(port) _MIPI_PORT(port, \
+ _MIPIA_HACTIVE_AREA_COUNT, _MIPIC_HACTIVE_AREA_COUNT)
#define _MIPIA_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb038)
-#define _MIPIB_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838)
-#define MIPI_VSYNC_PADDING_COUNT(tc) _TRANSCODER(tc, \
- _MIPIA_VSYNC_PADDING_COUNT, _MIPIB_VSYNC_PADDING_COUNT)
+#define _MIPIC_VSYNC_PADDING_COUNT (dev_priv->mipi_mmio_base + 0xb838)
+#define MIPI_VSYNC_PADDING_COUNT(port) _MIPI_PORT(port, \
+ _MIPIA_VSYNC_PADDING_COUNT, _MIPIC_VSYNC_PADDING_COUNT)
#define _MIPIA_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb03c)
-#define _MIPIB_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c)
-#define MIPI_VBP_COUNT(tc) _TRANSCODER(tc, _MIPIA_VBP_COUNT, \
- _MIPIB_VBP_COUNT)
+#define _MIPIC_VBP_COUNT (dev_priv->mipi_mmio_base + 0xb83c)
+#define MIPI_VBP_COUNT(port) _MIPI_PORT(port, _MIPIA_VBP_COUNT, \
+ _MIPIC_VBP_COUNT)
#define _MIPIA_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb040)
-#define _MIPIB_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840)
-#define MIPI_VFP_COUNT(tc) _TRANSCODER(tc, _MIPIA_VFP_COUNT, \
- _MIPIB_VFP_COUNT)
+#define _MIPIC_VFP_COUNT (dev_priv->mipi_mmio_base + 0xb840)
+#define MIPI_VFP_COUNT(port) _MIPI_PORT(port, _MIPIA_VFP_COUNT, \
+ _MIPIC_VFP_COUNT)
#define _MIPIA_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb044)
-#define _MIPIB_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844)
-#define MIPI_HIGH_LOW_SWITCH_COUNT(tc) _TRANSCODER(tc, \
- _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIB_HIGH_LOW_SWITCH_COUNT)
+#define _MIPIC_HIGH_LOW_SWITCH_COUNT (dev_priv->mipi_mmio_base + 0xb844)
+#define MIPI_HIGH_LOW_SWITCH_COUNT(port) _MIPI_PORT(port, \
+ _MIPIA_HIGH_LOW_SWITCH_COUNT, _MIPIC_HIGH_LOW_SWITCH_COUNT)
/* regs above are bits 15:0 */
#define _MIPIA_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb048)
-#define _MIPIB_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848)
-#define MIPI_DPI_CONTROL(tc) _TRANSCODER(tc, _MIPIA_DPI_CONTROL, \
- _MIPIB_DPI_CONTROL)
+#define _MIPIC_DPI_CONTROL (dev_priv->mipi_mmio_base + 0xb848)
+#define MIPI_DPI_CONTROL(port) _MIPI_PORT(port, _MIPIA_DPI_CONTROL, \
+ _MIPIC_DPI_CONTROL)
#define DPI_LP_MODE (1 << 6)
#define BACKLIGHT_OFF (1 << 5)
#define BACKLIGHT_ON (1 << 4)
@@ -6861,30 +6943,30 @@ enum punit_power_well {
#define SHUTDOWN (1 << 0)
#define _MIPIA_DPI_DATA (dev_priv->mipi_mmio_base + 0xb04c)
-#define _MIPIB_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c)
-#define MIPI_DPI_DATA(tc) _TRANSCODER(tc, _MIPIA_DPI_DATA, \
- _MIPIB_DPI_DATA)
+#define _MIPIC_DPI_DATA (dev_priv->mipi_mmio_base + 0xb84c)
+#define MIPI_DPI_DATA(port) _MIPI_PORT(port, _MIPIA_DPI_DATA, \
+ _MIPIC_DPI_DATA)
#define COMMAND_BYTE_SHIFT 0
#define COMMAND_BYTE_MASK (0x3f << 0)
#define _MIPIA_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb050)
-#define _MIPIB_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850)
-#define MIPI_INIT_COUNT(tc) _TRANSCODER(tc, _MIPIA_INIT_COUNT, \
- _MIPIB_INIT_COUNT)
+#define _MIPIC_INIT_COUNT (dev_priv->mipi_mmio_base + 0xb850)
+#define MIPI_INIT_COUNT(port) _MIPI_PORT(port, _MIPIA_INIT_COUNT, \
+ _MIPIC_INIT_COUNT)
#define MASTER_INIT_TIMER_SHIFT 0
#define MASTER_INIT_TIMER_MASK (0xffff << 0)
#define _MIPIA_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb054)
-#define _MIPIB_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854)
-#define MIPI_MAX_RETURN_PKT_SIZE(tc) _TRANSCODER(tc, \
- _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIB_MAX_RETURN_PKT_SIZE)
+#define _MIPIC_MAX_RETURN_PKT_SIZE (dev_priv->mipi_mmio_base + 0xb854)
+#define MIPI_MAX_RETURN_PKT_SIZE(port) _MIPI_PORT(port, \
+ _MIPIA_MAX_RETURN_PKT_SIZE, _MIPIC_MAX_RETURN_PKT_SIZE)
#define MAX_RETURN_PKT_SIZE_SHIFT 0
#define MAX_RETURN_PKT_SIZE_MASK (0x3ff << 0)
#define _MIPIA_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb058)
-#define _MIPIB_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858)
-#define MIPI_VIDEO_MODE_FORMAT(tc) _TRANSCODER(tc, \
- _MIPIA_VIDEO_MODE_FORMAT, _MIPIB_VIDEO_MODE_FORMAT)
+#define _MIPIC_VIDEO_MODE_FORMAT (dev_priv->mipi_mmio_base + 0xb858)
+#define MIPI_VIDEO_MODE_FORMAT(port) _MIPI_PORT(port, \
+ _MIPIA_VIDEO_MODE_FORMAT, _MIPIC_VIDEO_MODE_FORMAT)
#define RANDOM_DPI_DISPLAY_RESOLUTION (1 << 4)
#define DISABLE_VIDEO_BTA (1 << 3)
#define IP_TG_CONFIG (1 << 2)
@@ -6893,9 +6975,9 @@ enum punit_power_well {
#define VIDEO_MODE_BURST (3 << 0)
#define _MIPIA_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb05c)
-#define _MIPIB_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c)
-#define MIPI_EOT_DISABLE(tc) _TRANSCODER(tc, _MIPIA_EOT_DISABLE, \
- _MIPIB_EOT_DISABLE)
+#define _MIPIC_EOT_DISABLE (dev_priv->mipi_mmio_base + 0xb85c)
+#define MIPI_EOT_DISABLE(port) _MIPI_PORT(port, _MIPIA_EOT_DISABLE, \
+ _MIPIC_EOT_DISABLE)
#define LP_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 7)
#define HS_RX_TIMEOUT_ERROR_RECOVERY_DISABLE (1 << 6)
#define LOW_CONTENTION_RECOVERY_DISABLE (1 << 5)
@@ -6906,32 +6988,32 @@ enum punit_power_well {
#define EOT_DISABLE (1 << 0)
#define _MIPIA_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb060)
-#define _MIPIB_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860)
-#define MIPI_LP_BYTECLK(tc) _TRANSCODER(tc, _MIPIA_LP_BYTECLK, \
- _MIPIB_LP_BYTECLK)
+#define _MIPIC_LP_BYTECLK (dev_priv->mipi_mmio_base + 0xb860)
+#define MIPI_LP_BYTECLK(port) _MIPI_PORT(port, _MIPIA_LP_BYTECLK, \
+ _MIPIC_LP_BYTECLK)
#define LP_BYTECLK_SHIFT 0
#define LP_BYTECLK_MASK (0xffff << 0)
/* bits 31:0 */
#define _MIPIA_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb064)
-#define _MIPIB_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864)
-#define MIPI_LP_GEN_DATA(tc) _TRANSCODER(tc, _MIPIA_LP_GEN_DATA, \
- _MIPIB_LP_GEN_DATA)
+#define _MIPIC_LP_GEN_DATA (dev_priv->mipi_mmio_base + 0xb864)
+#define MIPI_LP_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_LP_GEN_DATA, \
+ _MIPIC_LP_GEN_DATA)
/* bits 31:0 */
#define _MIPIA_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb068)
-#define _MIPIB_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868)
-#define MIPI_HS_GEN_DATA(tc) _TRANSCODER(tc, _MIPIA_HS_GEN_DATA, \
- _MIPIB_HS_GEN_DATA)
+#define _MIPIC_HS_GEN_DATA (dev_priv->mipi_mmio_base + 0xb868)
+#define MIPI_HS_GEN_DATA(port) _MIPI_PORT(port, _MIPIA_HS_GEN_DATA, \
+ _MIPIC_HS_GEN_DATA)
#define _MIPIA_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb06c)
-#define _MIPIB_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c)
-#define MIPI_LP_GEN_CTRL(tc) _TRANSCODER(tc, _MIPIA_LP_GEN_CTRL, \
- _MIPIB_LP_GEN_CTRL)
+#define _MIPIC_LP_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb86c)
+#define MIPI_LP_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_LP_GEN_CTRL, \
+ _MIPIC_LP_GEN_CTRL)
#define _MIPIA_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb070)
-#define _MIPIB_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870)
-#define MIPI_HS_GEN_CTRL(tc) _TRANSCODER(tc, _MIPIA_HS_GEN_CTRL, \
- _MIPIB_HS_GEN_CTRL)
+#define _MIPIC_HS_GEN_CTRL (dev_priv->mipi_mmio_base + 0xb870)
+#define MIPI_HS_GEN_CTRL(port) _MIPI_PORT(port, _MIPIA_HS_GEN_CTRL, \
+ _MIPIC_HS_GEN_CTRL)
#define LONG_PACKET_WORD_COUNT_SHIFT 8
#define LONG_PACKET_WORD_COUNT_MASK (0xffff << 8)
#define SHORT_PACKET_PARAM_SHIFT 8
@@ -6943,9 +7025,9 @@ enum punit_power_well {
/* data type values, see include/video/mipi_display.h */
#define _MIPIA_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb074)
-#define _MIPIB_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874)
-#define MIPI_GEN_FIFO_STAT(tc) _TRANSCODER(tc, _MIPIA_GEN_FIFO_STAT, \
- _MIPIB_GEN_FIFO_STAT)
+#define _MIPIC_GEN_FIFO_STAT (dev_priv->mipi_mmio_base + 0xb874)
+#define MIPI_GEN_FIFO_STAT(port) _MIPI_PORT(port, _MIPIA_GEN_FIFO_STAT, \
+ _MIPIC_GEN_FIFO_STAT)
#define DPI_FIFO_EMPTY (1 << 28)
#define DBI_FIFO_EMPTY (1 << 27)
#define LP_CTRL_FIFO_EMPTY (1 << 26)
@@ -6962,17 +7044,17 @@ enum punit_power_well {
#define HS_DATA_FIFO_FULL (1 << 0)
#define _MIPIA_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb078)
-#define _MIPIB_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878)
-#define MIPI_HS_LP_DBI_ENABLE(tc) _TRANSCODER(tc, \
- _MIPIA_HS_LS_DBI_ENABLE, _MIPIB_HS_LS_DBI_ENABLE)
+#define _MIPIC_HS_LS_DBI_ENABLE (dev_priv->mipi_mmio_base + 0xb878)
+#define MIPI_HS_LP_DBI_ENABLE(port) _MIPI_PORT(port, \
+ _MIPIA_HS_LS_DBI_ENABLE, _MIPIC_HS_LS_DBI_ENABLE)
#define DBI_HS_LP_MODE_MASK (1 << 0)
#define DBI_LP_MODE (1 << 0)
#define DBI_HS_MODE (0 << 0)
#define _MIPIA_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb080)
-#define _MIPIB_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880)
-#define MIPI_DPHY_PARAM(tc) _TRANSCODER(tc, _MIPIA_DPHY_PARAM, \
- _MIPIB_DPHY_PARAM)
+#define _MIPIC_DPHY_PARAM (dev_priv->mipi_mmio_base + 0xb880)
+#define MIPI_DPHY_PARAM(port) _MIPI_PORT(port, _MIPIA_DPHY_PARAM, \
+ _MIPIC_DPHY_PARAM)
#define EXIT_ZERO_COUNT_SHIFT 24
#define EXIT_ZERO_COUNT_MASK (0x3f << 24)
#define TRAIL_COUNT_SHIFT 16
@@ -6984,36 +7066,36 @@ enum punit_power_well {
/* bits 31:0 */
#define _MIPIA_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb084)
-#define _MIPIB_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884)
-#define MIPI_DBI_BW_CTRL(tc) _TRANSCODER(tc, _MIPIA_DBI_BW_CTRL, \
- _MIPIB_DBI_BW_CTRL)
+#define _MIPIC_DBI_BW_CTRL (dev_priv->mipi_mmio_base + 0xb884)
+#define MIPI_DBI_BW_CTRL(port) _MIPI_PORT(port, _MIPIA_DBI_BW_CTRL, \
+ _MIPIC_DBI_BW_CTRL)
#define _MIPIA_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
+ 0xb088)
-#define _MIPIB_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
+#define _MIPIC_CLK_LANE_SWITCH_TIME_CNT (dev_priv->mipi_mmio_base \
+ 0xb888)
-#define MIPI_CLK_LANE_SWITCH_TIME_CNT(tc) _TRANSCODER(tc, \
- _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIB_CLK_LANE_SWITCH_TIME_CNT)
+#define MIPI_CLK_LANE_SWITCH_TIME_CNT(port) _MIPI_PORT(port, \
+ _MIPIA_CLK_LANE_SWITCH_TIME_CNT, _MIPIC_CLK_LANE_SWITCH_TIME_CNT)
#define LP_HS_SSW_CNT_SHIFT 16
#define LP_HS_SSW_CNT_MASK (0xffff << 16)
#define HS_LP_PWR_SW_CNT_SHIFT 0
#define HS_LP_PWR_SW_CNT_MASK (0xffff << 0)
#define _MIPIA_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb08c)
-#define _MIPIB_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c)
-#define MIPI_STOP_STATE_STALL(tc) _TRANSCODER(tc, \
- _MIPIA_STOP_STATE_STALL, _MIPIB_STOP_STATE_STALL)
+#define _MIPIC_STOP_STATE_STALL (dev_priv->mipi_mmio_base + 0xb88c)
+#define MIPI_STOP_STATE_STALL(port) _MIPI_PORT(port, \
+ _MIPIA_STOP_STATE_STALL, _MIPIC_STOP_STATE_STALL)
#define STOP_STATE_STALL_COUNTER_SHIFT 0
#define STOP_STATE_STALL_COUNTER_MASK (0xff << 0)
#define _MIPIA_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb090)
-#define _MIPIB_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890)
-#define MIPI_INTR_STAT_REG_1(tc) _TRANSCODER(tc, \
- _MIPIA_INTR_STAT_REG_1, _MIPIB_INTR_STAT_REG_1)
+#define _MIPIC_INTR_STAT_REG_1 (dev_priv->mipi_mmio_base + 0xb890)
+#define MIPI_INTR_STAT_REG_1(port) _MIPI_PORT(port, \
+ _MIPIA_INTR_STAT_REG_1, _MIPIC_INTR_STAT_REG_1)
#define _MIPIA_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb094)
-#define _MIPIB_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894)
-#define MIPI_INTR_EN_REG_1(tc) _TRANSCODER(tc, _MIPIA_INTR_EN_REG_1, \
- _MIPIB_INTR_EN_REG_1)
+#define _MIPIC_INTR_EN_REG_1 (dev_priv->mipi_mmio_base + 0xb894)
+#define MIPI_INTR_EN_REG_1(port) _MIPI_PORT(port, _MIPIA_INTR_EN_REG_1, \
+ _MIPIC_INTR_EN_REG_1)
#define RX_CONTENTION_DETECTED (1 << 0)
/* XXX: only pipe A ?!? */
@@ -7032,9 +7114,9 @@ enum punit_power_well {
/* MIPI adapter registers */
#define _MIPIA_CTRL (dev_priv->mipi_mmio_base + 0xb104)
-#define _MIPIB_CTRL (dev_priv->mipi_mmio_base + 0xb904)
-#define MIPI_CTRL(tc) _TRANSCODER(tc, _MIPIA_CTRL, \
- _MIPIB_CTRL)
+#define _MIPIC_CTRL (dev_priv->mipi_mmio_base + 0xb904)
+#define MIPI_CTRL(port) _MIPI_PORT(port, _MIPIA_CTRL, \
+ _MIPIC_CTRL)
#define ESCAPE_CLOCK_DIVIDER_SHIFT 5 /* A only */
#define ESCAPE_CLOCK_DIVIDER_MASK (3 << 5)
#define ESCAPE_CLOCK_DIVIDER_1 (0 << 5)
@@ -7047,24 +7129,24 @@ enum punit_power_well {
#define RGB_FLIP_TO_BGR (1 << 2)
#define _MIPIA_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb108)
-#define _MIPIB_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908)
-#define MIPI_DATA_ADDRESS(tc) _TRANSCODER(tc, _MIPIA_DATA_ADDRESS, \
- _MIPIB_DATA_ADDRESS)
+#define _MIPIC_DATA_ADDRESS (dev_priv->mipi_mmio_base + 0xb908)
+#define MIPI_DATA_ADDRESS(port) _MIPI_PORT(port, _MIPIA_DATA_ADDRESS, \
+ _MIPIC_DATA_ADDRESS)
#define DATA_MEM_ADDRESS_SHIFT 5
#define DATA_MEM_ADDRESS_MASK (0x7ffffff << 5)
#define DATA_VALID (1 << 0)
#define _MIPIA_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb10c)
-#define _MIPIB_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c)
-#define MIPI_DATA_LENGTH(tc) _TRANSCODER(tc, _MIPIA_DATA_LENGTH, \
- _MIPIB_DATA_LENGTH)
+#define _MIPIC_DATA_LENGTH (dev_priv->mipi_mmio_base + 0xb90c)
+#define MIPI_DATA_LENGTH(port) _MIPI_PORT(port, _MIPIA_DATA_LENGTH, \
+ _MIPIC_DATA_LENGTH)
#define DATA_LENGTH_SHIFT 0
#define DATA_LENGTH_MASK (0xfffff << 0)
#define _MIPIA_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb110)
-#define _MIPIB_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910)
-#define MIPI_COMMAND_ADDRESS(tc) _TRANSCODER(tc, \
- _MIPIA_COMMAND_ADDRESS, _MIPIB_COMMAND_ADDRESS)
+#define _MIPIC_COMMAND_ADDRESS (dev_priv->mipi_mmio_base + 0xb910)
+#define MIPI_COMMAND_ADDRESS(port) _MIPI_PORT(port, \
+ _MIPIA_COMMAND_ADDRESS, _MIPIC_COMMAND_ADDRESS)
#define COMMAND_MEM_ADDRESS_SHIFT 5
#define COMMAND_MEM_ADDRESS_MASK (0x7ffffff << 5)
#define AUTO_PWG_ENABLE (1 << 2)
@@ -7072,22 +7154,22 @@ enum punit_power_well {
#define COMMAND_VALID (1 << 0)
#define _MIPIA_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb114)
-#define _MIPIB_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914)
-#define MIPI_COMMAND_LENGTH(tc) _TRANSCODER(tc, _MIPIA_COMMAND_LENGTH, \
- _MIPIB_COMMAND_LENGTH)
+#define _MIPIC_COMMAND_LENGTH (dev_priv->mipi_mmio_base + 0xb914)
+#define MIPI_COMMAND_LENGTH(port) _MIPI_PORT(port, _MIPIA_COMMAND_LENGTH, \
+ _MIPIC_COMMAND_LENGTH)
#define COMMAND_LENGTH_SHIFT(n) (8 * (n)) /* n: 0...3 */
#define COMMAND_LENGTH_MASK(n) (0xff << (8 * (n)))
#define _MIPIA_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb118)
-#define _MIPIB_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918)
-#define MIPI_READ_DATA_RETURN(tc, n) \
- (_TRANSCODER(tc, _MIPIA_READ_DATA_RETURN0, _MIPIB_READ_DATA_RETURN0) \
+#define _MIPIC_READ_DATA_RETURN0 (dev_priv->mipi_mmio_base + 0xb918)
+#define MIPI_READ_DATA_RETURN(port, n) \
+ (_MIPI_PORT(port, _MIPIA_READ_DATA_RETURN0, _MIPIC_READ_DATA_RETURN0) \
+ 4 * (n)) /* n: 0...7 */
#define _MIPIA_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb138)
-#define _MIPIB_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938)
-#define MIPI_READ_DATA_VALID(tc) _TRANSCODER(tc, \
- _MIPIA_READ_DATA_VALID, _MIPIB_READ_DATA_VALID)
+#define _MIPIC_READ_DATA_VALID (dev_priv->mipi_mmio_base + 0xb938)
+#define MIPI_READ_DATA_VALID(port) _MIPI_PORT(port, \
+ _MIPIA_READ_DATA_VALID, _MIPIC_READ_DATA_VALID)
#define READ_DATA_VALID(n) (1 << (n))
/* For UMS only (deprecated): */
diff --git a/drivers/gpu/drm/i915/i915_suspend.c b/drivers/gpu/drm/i915/i915_suspend.c
index 26368822a33f..9f19ed38cdc3 100644
--- a/drivers/gpu/drm/i915/i915_suspend.c
+++ b/drivers/gpu/drm/i915/i915_suspend.c
@@ -264,7 +264,7 @@ static void i915_restore_display(struct drm_device *dev)
}
/* only restore FBC info on the platform that supports FBC*/
- intel_disable_fbc(dev);
+ intel_fbc_disable(dev);
/* restore FBC interval */
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev))
diff --git a/drivers/gpu/drm/i915/i915_sysfs.c b/drivers/gpu/drm/i915/i915_sysfs.c
index 4a5af695307e..49f5ade0edb7 100644
--- a/drivers/gpu/drm/i915/i915_sysfs.c
+++ b/drivers/gpu/drm/i915/i915_sysfs.c
@@ -49,14 +49,14 @@ static u32 calc_residency(struct drm_device *dev, const u32 reg)
/* On VLV and CHV, residency time is in CZ units rather than 1.28us */
if (IS_VALLEYVIEW(dev)) {
- u32 reg, czcount_30ns;
+ u32 clk_reg, czcount_30ns;
if (IS_CHERRYVIEW(dev))
- reg = CHV_CLK_CTL1;
+ clk_reg = CHV_CLK_CTL1;
else
- reg = VLV_CLK_CTL2;
+ clk_reg = VLV_CLK_CTL2;
- czcount_30ns = I915_READ(reg) >> CLK_CTL2_CZCOUNT_30NS_SHIFT;
+ czcount_30ns = I915_READ(clk_reg) >> CLK_CTL2_CZCOUNT_30NS_SHIFT;
if (!czcount_30ns) {
WARN(!czcount_30ns, "bogus CZ count value");
@@ -116,8 +116,6 @@ show_rc6p_ms(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = dev_to_drm_minor(kdev);
u32 rc6p_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6p);
- if (IS_VALLEYVIEW(dminor->dev))
- rc6p_residency = 0;
return snprintf(buf, PAGE_SIZE, "%u\n", rc6p_residency);
}
@@ -126,8 +124,6 @@ show_rc6pp_ms(struct device *kdev, struct device_attribute *attr, char *buf)
{
struct drm_minor *dminor = dev_to_drm_minor(kdev);
u32 rc6pp_residency = calc_residency(dminor->dev, GEN6_GT_GFX_RC6pp);
- if (IS_VALLEYVIEW(dminor->dev))
- rc6pp_residency = 0;
return snprintf(buf, PAGE_SIZE, "%u\n", rc6pp_residency);
}
@@ -285,7 +281,7 @@ static struct bin_attribute dpf_attrs_1 = {
.private = (void *)1
};
-static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
+static ssize_t gt_act_freq_mhz_show(struct device *kdev,
struct device_attribute *attr, char *buf)
{
struct drm_minor *minor = dev_to_drm_minor(kdev);
@@ -301,9 +297,14 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
if (IS_VALLEYVIEW(dev_priv->dev)) {
u32 freq;
freq = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
- ret = vlv_gpu_freq(dev_priv, (freq >> 8) & 0xff);
+ ret = intel_gpu_freq(dev_priv, (freq >> 8) & 0xff);
} else {
- ret = dev_priv->rps.cur_freq * GT_FREQUENCY_MULTIPLIER;
+ u32 rpstat = I915_READ(GEN6_RPSTAT1);
+ if (IS_HASWELL(dev_priv) || IS_BROADWELL(dev_priv))
+ ret = (rpstat & HSW_CAGF_MASK) >> HSW_CAGF_SHIFT;
+ else
+ ret = (rpstat & GEN6_CAGF_MASK) >> GEN6_CAGF_SHIFT;
+ ret = intel_gpu_freq(dev_priv, ret);
}
mutex_unlock(&dev_priv->rps.hw_lock);
@@ -312,6 +313,27 @@ static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
}
+static ssize_t gt_cur_freq_mhz_show(struct device *kdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct drm_minor *minor = dev_to_drm_minor(kdev);
+ struct drm_device *dev = minor->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ int ret;
+
+ flush_delayed_work(&dev_priv->rps.delayed_resume_work);
+
+ intel_runtime_pm_get(dev_priv);
+
+ mutex_lock(&dev_priv->rps.hw_lock);
+ ret = intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq);
+ mutex_unlock(&dev_priv->rps.hw_lock);
+
+ intel_runtime_pm_put(dev_priv);
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", ret);
+}
+
static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
struct device_attribute *attr, char *buf)
{
@@ -319,8 +341,9 @@ static ssize_t vlv_rpe_freq_mhz_show(struct device *kdev,
struct drm_device *dev = minor->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- return snprintf(buf, PAGE_SIZE, "%d\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
+ return snprintf(buf, PAGE_SIZE,
+ "%d\n",
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq));
}
static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute *attr, char *buf)
@@ -333,10 +356,7 @@ static ssize_t gt_max_freq_mhz_show(struct device *kdev, struct device_attribute
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
mutex_lock(&dev_priv->rps.hw_lock);
- if (IS_VALLEYVIEW(dev_priv->dev))
- ret = vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
- else
- ret = dev_priv->rps.max_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+ ret = intel_gpu_freq(dev_priv, dev_priv->rps.max_freq_softlimit);
mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -360,10 +380,7 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
mutex_lock(&dev_priv->rps.hw_lock);
- if (IS_VALLEYVIEW(dev_priv->dev))
- val = vlv_freq_opcode(dev_priv, val);
- else
- val /= GT_FREQUENCY_MULTIPLIER;
+ val = intel_freq_opcode(dev_priv, val);
if (val < dev_priv->rps.min_freq ||
val > dev_priv->rps.max_freq ||
@@ -374,21 +391,21 @@ static ssize_t gt_max_freq_mhz_store(struct device *kdev,
if (val > dev_priv->rps.rp0_freq)
DRM_DEBUG("User requested overclocking to %d\n",
- val * GT_FREQUENCY_MULTIPLIER);
+ intel_gpu_freq(dev_priv, val));
dev_priv->rps.max_freq_softlimit = val;
- if (dev_priv->rps.cur_freq > val) {
- if (IS_VALLEYVIEW(dev))
- valleyview_set_rps(dev, val);
- else
- gen6_set_rps(dev, val);
- } else if (!IS_VALLEYVIEW(dev)) {
- /* We still need gen6_set_rps to process the new max_delay and
- * update the interrupt limits even though frequency request is
- * unchanged. */
- gen6_set_rps(dev, dev_priv->rps.cur_freq);
- }
+ val = clamp_t(int, dev_priv->rps.cur_freq,
+ dev_priv->rps.min_freq_softlimit,
+ dev_priv->rps.max_freq_softlimit);
+
+ /* We still need *_set_rps to process the new max_delay and
+ * update the interrupt limits and PMINTRMSK even though
+ * frequency request may be unchanged. */
+ if (IS_VALLEYVIEW(dev))
+ valleyview_set_rps(dev, val);
+ else
+ gen6_set_rps(dev, val);
mutex_unlock(&dev_priv->rps.hw_lock);
@@ -405,10 +422,7 @@ static ssize_t gt_min_freq_mhz_show(struct device *kdev, struct device_attribute
flush_delayed_work(&dev_priv->rps.delayed_resume_work);
mutex_lock(&dev_priv->rps.hw_lock);
- if (IS_VALLEYVIEW(dev_priv->dev))
- ret = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
- else
- ret = dev_priv->rps.min_freq_softlimit * GT_FREQUENCY_MULTIPLIER;
+ ret = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq_softlimit);
mutex_unlock(&dev_priv->rps.hw_lock);
return snprintf(buf, PAGE_SIZE, "%d\n", ret);
@@ -432,10 +446,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
mutex_lock(&dev_priv->rps.hw_lock);
- if (IS_VALLEYVIEW(dev))
- val = vlv_freq_opcode(dev_priv, val);
- else
- val /= GT_FREQUENCY_MULTIPLIER;
+ val = intel_freq_opcode(dev_priv, val);
if (val < dev_priv->rps.min_freq ||
val > dev_priv->rps.max_freq ||
@@ -446,17 +457,17 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
dev_priv->rps.min_freq_softlimit = val;
- if (dev_priv->rps.cur_freq < val) {
- if (IS_VALLEYVIEW(dev))
- valleyview_set_rps(dev, val);
- else
- gen6_set_rps(dev, val);
- } else if (!IS_VALLEYVIEW(dev)) {
- /* We still need gen6_set_rps to process the new min_delay and
- * update the interrupt limits even though frequency request is
- * unchanged. */
- gen6_set_rps(dev, dev_priv->rps.cur_freq);
- }
+ val = clamp_t(int, dev_priv->rps.cur_freq,
+ dev_priv->rps.min_freq_softlimit,
+ dev_priv->rps.max_freq_softlimit);
+
+ /* We still need *_set_rps to process the new min_delay and
+ * update the interrupt limits and PMINTRMSK even though
+ * frequency request may be unchanged. */
+ if (IS_VALLEYVIEW(dev))
+ valleyview_set_rps(dev, val);
+ else
+ gen6_set_rps(dev, val);
mutex_unlock(&dev_priv->rps.hw_lock);
@@ -464,6 +475,7 @@ static ssize_t gt_min_freq_mhz_store(struct device *kdev,
}
+static DEVICE_ATTR(gt_act_freq_mhz, S_IRUGO, gt_act_freq_mhz_show, NULL);
static DEVICE_ATTR(gt_cur_freq_mhz, S_IRUGO, gt_cur_freq_mhz_show, NULL);
static DEVICE_ATTR(gt_max_freq_mhz, S_IRUGO | S_IWUSR, gt_max_freq_mhz_show, gt_max_freq_mhz_store);
static DEVICE_ATTR(gt_min_freq_mhz, S_IRUGO | S_IWUSR, gt_min_freq_mhz_show, gt_min_freq_mhz_store);
@@ -494,19 +506,22 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
if (attr == &dev_attr_gt_RP0_freq_mhz) {
if (IS_VALLEYVIEW(dev))
- val = vlv_gpu_freq(dev_priv, dev_priv->rps.rp0_freq);
+ val = intel_gpu_freq(dev_priv, dev_priv->rps.rp0_freq);
else
- val = ((rp_state_cap & 0x0000ff) >> 0) * GT_FREQUENCY_MULTIPLIER;
+ val = intel_gpu_freq(dev_priv,
+ ((rp_state_cap & 0x0000ff) >> 0));
} else if (attr == &dev_attr_gt_RP1_freq_mhz) {
if (IS_VALLEYVIEW(dev))
- val = vlv_gpu_freq(dev_priv, dev_priv->rps.rp1_freq);
+ val = intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq);
else
- val = ((rp_state_cap & 0x00ff00) >> 8) * GT_FREQUENCY_MULTIPLIER;
+ val = intel_gpu_freq(dev_priv,
+ ((rp_state_cap & 0x00ff00) >> 8));
} else if (attr == &dev_attr_gt_RPn_freq_mhz) {
if (IS_VALLEYVIEW(dev))
- val = vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq);
+ val = intel_gpu_freq(dev_priv, dev_priv->rps.min_freq);
else
- val = ((rp_state_cap & 0xff0000) >> 16) * GT_FREQUENCY_MULTIPLIER;
+ val = intel_gpu_freq(dev_priv,
+ ((rp_state_cap & 0xff0000) >> 16));
} else {
BUG();
}
@@ -514,6 +529,7 @@ static ssize_t gt_rp_mhz_show(struct device *kdev, struct device_attribute *attr
}
static const struct attribute *gen6_attrs[] = {
+ &dev_attr_gt_act_freq_mhz.attr,
&dev_attr_gt_cur_freq_mhz.attr,
&dev_attr_gt_max_freq_mhz.attr,
&dev_attr_gt_min_freq_mhz.attr,
@@ -524,6 +540,7 @@ static const struct attribute *gen6_attrs[] = {
};
static const struct attribute *vlv_attrs[] = {
+ &dev_attr_gt_act_freq_mhz.attr,
&dev_attr_gt_cur_freq_mhz.attr,
&dev_attr_gt_max_freq_mhz.attr,
&dev_attr_gt_min_freq_mhz.attr,
diff --git a/drivers/gpu/drm/i915/i915_trace.h b/drivers/gpu/drm/i915/i915_trace.h
index 751d4ad14d62..6058a01b4443 100644
--- a/drivers/gpu/drm/i915/i915_trace.h
+++ b/drivers/gpu/drm/i915/i915_trace.h
@@ -328,8 +328,8 @@ TRACE_EVENT(i915_gem_evict_vm,
TRACE_EVENT(i915_gem_ring_sync_to,
TP_PROTO(struct intel_engine_cs *from,
struct intel_engine_cs *to,
- u32 seqno),
- TP_ARGS(from, to, seqno),
+ struct drm_i915_gem_request *req),
+ TP_ARGS(from, to, req),
TP_STRUCT__entry(
__field(u32, dev)
@@ -342,7 +342,7 @@ TRACE_EVENT(i915_gem_ring_sync_to,
__entry->dev = from->dev->primary->index;
__entry->sync_from = from->id;
__entry->sync_to = to->id;
- __entry->seqno = seqno;
+ __entry->seqno = i915_gem_request_get_seqno(req);
),
TP_printk("dev=%u, sync-from=%u, sync-to=%u, seqno=%u",
@@ -352,8 +352,8 @@ TRACE_EVENT(i915_gem_ring_sync_to,
);
TRACE_EVENT(i915_gem_ring_dispatch,
- TP_PROTO(struct intel_engine_cs *ring, u32 seqno, u32 flags),
- TP_ARGS(ring, seqno, flags),
+ TP_PROTO(struct drm_i915_gem_request *req, u32 flags),
+ TP_ARGS(req, flags),
TP_STRUCT__entry(
__field(u32, dev)
@@ -363,11 +363,13 @@ TRACE_EVENT(i915_gem_ring_dispatch,
),
TP_fast_assign(
+ struct intel_engine_cs *ring =
+ i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index;
__entry->ring = ring->id;
- __entry->seqno = seqno;
+ __entry->seqno = i915_gem_request_get_seqno(req);
__entry->flags = flags;
- i915_trace_irq_get(ring, seqno);
+ i915_trace_irq_get(ring, req);
),
TP_printk("dev=%u, ring=%u, seqno=%u, flags=%x",
@@ -398,31 +400,36 @@ TRACE_EVENT(i915_gem_ring_flush,
);
DECLARE_EVENT_CLASS(i915_gem_request,
- TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
- TP_ARGS(ring, seqno),
+ TP_PROTO(struct drm_i915_gem_request *req),
+ TP_ARGS(req),
TP_STRUCT__entry(
__field(u32, dev)
__field(u32, ring)
+ __field(u32, uniq)
__field(u32, seqno)
),
TP_fast_assign(
+ struct intel_engine_cs *ring =
+ i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index;
__entry->ring = ring->id;
- __entry->seqno = seqno;
+ __entry->uniq = req ? req->uniq : 0;
+ __entry->seqno = i915_gem_request_get_seqno(req);
),
- TP_printk("dev=%u, ring=%u, seqno=%u",
- __entry->dev, __entry->ring, __entry->seqno)
+ TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u",
+ __entry->dev, __entry->ring, __entry->uniq,
+ __entry->seqno)
);
DEFINE_EVENT(i915_gem_request, i915_gem_request_add,
- TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
- TP_ARGS(ring, seqno)
+ TP_PROTO(struct drm_i915_gem_request *req),
+ TP_ARGS(req)
);
-TRACE_EVENT(i915_gem_request_complete,
+TRACE_EVENT(i915_gem_request_notify,
TP_PROTO(struct intel_engine_cs *ring),
TP_ARGS(ring),
@@ -443,17 +450,23 @@ TRACE_EVENT(i915_gem_request_complete,
);
DEFINE_EVENT(i915_gem_request, i915_gem_request_retire,
- TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
- TP_ARGS(ring, seqno)
+ TP_PROTO(struct drm_i915_gem_request *req),
+ TP_ARGS(req)
+);
+
+DEFINE_EVENT(i915_gem_request, i915_gem_request_complete,
+ TP_PROTO(struct drm_i915_gem_request *req),
+ TP_ARGS(req)
);
TRACE_EVENT(i915_gem_request_wait_begin,
- TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
- TP_ARGS(ring, seqno),
+ TP_PROTO(struct drm_i915_gem_request *req),
+ TP_ARGS(req),
TP_STRUCT__entry(
__field(u32, dev)
__field(u32, ring)
+ __field(u32, uniq)
__field(u32, seqno)
__field(bool, blocking)
),
@@ -465,20 +478,24 @@ TRACE_EVENT(i915_gem_request_wait_begin,
* less desirable.
*/
TP_fast_assign(
+ struct intel_engine_cs *ring =
+ i915_gem_request_get_ring(req);
__entry->dev = ring->dev->primary->index;
__entry->ring = ring->id;
- __entry->seqno = seqno;
- __entry->blocking = mutex_is_locked(&ring->dev->struct_mutex);
+ __entry->uniq = req ? req->uniq : 0;
+ __entry->seqno = i915_gem_request_get_seqno(req);
+ __entry->blocking =
+ mutex_is_locked(&ring->dev->struct_mutex);
),
- TP_printk("dev=%u, ring=%u, seqno=%u, blocking=%s",
- __entry->dev, __entry->ring, __entry->seqno,
- __entry->blocking ? "yes (NB)" : "no")
+ TP_printk("dev=%u, ring=%u, uniq=%u, seqno=%u, blocking=%s",
+ __entry->dev, __entry->ring, __entry->uniq,
+ __entry->seqno, __entry->blocking ? "yes (NB)" : "no")
);
DEFINE_EVENT(i915_gem_request, i915_gem_request_wait_end,
- TP_PROTO(struct intel_engine_cs *ring, u32 seqno),
- TP_ARGS(ring, seqno)
+ TP_PROTO(struct drm_i915_gem_request *req),
+ TP_ARGS(req)
);
DECLARE_EVENT_CLASS(i915_ring,
diff --git a/drivers/gpu/drm/i915/intel_atomic.c b/drivers/gpu/drm/i915/intel_atomic.c
new file mode 100644
index 000000000000..19a9dd5408f3
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright © 2015 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * DOC: atomic modeset support
+ *
+ * The functions here implement the state management and hardware programming
+ * dispatch required by the atomic modeset infrastructure.
+ * See intel_atomic_plane.c for the plane-specific atomic functionality.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "intel_drv.h"
+
+
+/**
+ * intel_atomic_check - validate state object
+ * @dev: drm device
+ * @state: state to validate
+ */
+int intel_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ int nplanes = dev->mode_config.num_total_plane;
+ int ncrtcs = dev->mode_config.num_crtc;
+ int nconnectors = dev->mode_config.num_connector;
+ enum pipe nuclear_pipe = INVALID_PIPE;
+ int ret;
+ int i;
+ bool not_nuclear = false;
+
+ /*
+ * FIXME: At the moment, we only support "nuclear pageflip" on a
+ * single CRTC. Cross-crtc updates will be added later.
+ */
+ for (i = 0; i < nplanes; i++) {
+ struct intel_plane *plane = to_intel_plane(state->planes[i]);
+ if (!plane)
+ continue;
+
+ if (nuclear_pipe == INVALID_PIPE) {
+ nuclear_pipe = plane->pipe;
+ } else if (nuclear_pipe != plane->pipe) {
+ DRM_DEBUG_KMS("i915 only support atomic plane operations on a single CRTC at the moment\n");
+ return -EINVAL;
+ }
+ }
+
+ /*
+ * FIXME: We only handle planes for now; make sure there are no CRTC's
+ * or connectors involved.
+ */
+ state->allow_modeset = false;
+ for (i = 0; i < ncrtcs; i++) {
+ struct intel_crtc *crtc = to_intel_crtc(state->crtcs[i]);
+ if (crtc && crtc->pipe != nuclear_pipe)
+ not_nuclear = true;
+ }
+ for (i = 0; i < nconnectors; i++)
+ if (state->connectors[i] != NULL)
+ not_nuclear = true;
+
+ if (not_nuclear) {
+ DRM_DEBUG_KMS("i915 only supports atomic plane operations at the moment\n");
+ return -EINVAL;
+ }
+
+ ret = drm_atomic_helper_check_planes(dev, state);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
+
+/**
+ * intel_atomic_commit - commit validated state object
+ * @dev: DRM device
+ * @state: the top-level driver state object
+ * @async: asynchronous commit
+ *
+ * This function commits a top-level state object that has been validated
+ * with drm_atomic_helper_check().
+ *
+ * FIXME: Atomic modeset support for i915 is not yet complete. At the moment
+ * we can only handle plane-related operations and do not yet support
+ * asynchronous commit.
+ *
+ * RETURNS
+ * Zero for success or -errno.
+ */
+int intel_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async)
+{
+ int ret;
+ int i;
+
+ if (async) {
+ DRM_DEBUG_KMS("i915 does not yet support async commit\n");
+ return -EINVAL;
+ }
+
+ ret = drm_atomic_helper_prepare_planes(dev, state);
+ if (ret)
+ return ret;
+
+ /* Point of no return */
+
+ /*
+ * FIXME: The proper sequence here will eventually be:
+ *
+ * drm_atomic_helper_swap_state(dev, state)
+ * drm_atomic_helper_commit_pre_planes(dev, state);
+ * drm_atomic_helper_commit_planes(dev, state);
+ * drm_atomic_helper_commit_post_planes(dev, state);
+ * drm_atomic_helper_wait_for_vblanks(dev, state);
+ * drm_atomic_helper_cleanup_planes(dev, state);
+ * drm_atomic_state_free(state);
+ *
+ * once we have full atomic modeset. For now, just manually update
+ * plane states to avoid clobbering good states with dummy states
+ * while nuclear pageflipping.
+ */
+ for (i = 0; i < dev->mode_config.num_total_plane; i++) {
+ struct drm_plane *plane = state->planes[i];
+
+ if (!plane)
+ continue;
+
+ plane->state->state = state;
+ swap(state->plane_states[i], plane->state);
+ plane->state->state = NULL;
+ }
+ drm_atomic_helper_commit_planes(dev, state);
+ drm_atomic_helper_wait_for_vblanks(dev, state);
+ drm_atomic_helper_cleanup_planes(dev, state);
+ drm_atomic_state_free(state);
+
+ return 0;
+}
+
+/**
+ * intel_connector_atomic_get_property - fetch connector property value
+ * @connector: connector to fetch property for
+ * @state: state containing the property value
+ * @property: property to look up
+ * @val: pointer to write property value into
+ *
+ * The DRM core does not store shadow copies of properties for
+ * atomic-capable drivers. This entrypoint is used to fetch
+ * the current value of a driver-specific connector property.
+ */
+int
+intel_connector_atomic_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ int i;
+
+ /*
+ * TODO: We only have atomic modeset for planes at the moment, so the
+ * crtc/connector code isn't quite ready yet. Until it's ready,
+ * continue to look up all property values in the DRM's shadow copy
+ * in obj->properties->values[].
+ *
+ * When the crtc/connector state work matures, this function should
+ * be updated to read the values out of the state structure instead.
+ */
+ for (i = 0; i < connector->base.properties->count; i++) {
+ if (connector->base.properties->properties[i] == property) {
+ *val = connector->base.properties->values[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * intel_crtc_duplicate_state - duplicate crtc state
+ * @crtc: drm crtc
+ *
+ * Allocates and returns a copy of the crtc state (both common and
+ * Intel-specific) for the specified crtc.
+ *
+ * Returns: The newly allocated crtc state, or NULL on failure.
+ */
+struct drm_crtc_state *
+intel_crtc_duplicate_state(struct drm_crtc *crtc)
+{
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ if (WARN_ON(!intel_crtc->config))
+ return kzalloc(sizeof(*intel_crtc->config), GFP_KERNEL);
+
+ return kmemdup(intel_crtc->config, sizeof(*intel_crtc->config),
+ GFP_KERNEL);
+}
+
+/**
+ * intel_crtc_destroy_state - destroy crtc state
+ * @crtc: drm crtc
+ *
+ * Destroys the crtc state (both common and Intel-specific) for the
+ * specified crtc.
+ */
+void
+intel_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ drm_atomic_helper_crtc_destroy_state(crtc, state);
+}
diff --git a/drivers/gpu/drm/i915/intel_atomic_plane.c b/drivers/gpu/drm/i915/intel_atomic_plane.c
new file mode 100644
index 000000000000..9e6f727dfd19
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_atomic_plane.c
@@ -0,0 +1,246 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * DOC: atomic plane helpers
+ *
+ * The functions here are used by the atomic plane helper functions to
+ * implement legacy plane updates (i.e., drm_plane->update_plane() and
+ * drm_plane->disable_plane()). This allows plane updates to use the
+ * atomic state infrastructure and perform plane updates as separate
+ * prepare/check/commit/cleanup steps.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_plane_helper.h>
+#include "intel_drv.h"
+
+/**
+ * intel_create_plane_state - create plane state object
+ * @plane: drm plane
+ *
+ * Allocates a fresh plane state for the given plane and sets some of
+ * the state values to sensible initial values.
+ *
+ * Returns: A newly allocated plane state, or NULL on failure
+ */
+struct intel_plane_state *
+intel_create_plane_state(struct drm_plane *plane)
+{
+ struct intel_plane_state *state;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ state->base.plane = plane;
+ state->base.rotation = BIT(DRM_ROTATE_0);
+
+ return state;
+}
+
+/**
+ * intel_plane_duplicate_state - duplicate plane state
+ * @plane: drm plane
+ *
+ * Allocates and returns a copy of the plane state (both common and
+ * Intel-specific) for the specified plane.
+ *
+ * Returns: The newly allocated plane state, or NULL on failure.
+ */
+struct drm_plane_state *
+intel_plane_duplicate_state(struct drm_plane *plane)
+{
+ struct drm_plane_state *state;
+ struct intel_plane_state *intel_state;
+
+ if (WARN_ON(!plane->state))
+ intel_state = intel_create_plane_state(plane);
+ else
+ intel_state = kmemdup(plane->state, sizeof(*intel_state),
+ GFP_KERNEL);
+
+ if (!intel_state)
+ return NULL;
+
+ state = &intel_state->base;
+ if (state->fb)
+ drm_framebuffer_reference(state->fb);
+
+ return state;
+}
+
+/**
+ * intel_plane_destroy_state - destroy plane state
+ * @plane: drm plane
+ * @state: state object to destroy
+ *
+ * Destroys the plane state (both common and Intel-specific) for the
+ * specified plane.
+ */
+void
+intel_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ drm_atomic_helper_plane_destroy_state(plane, state);
+}
+
+static int intel_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct drm_crtc *crtc = state->crtc;
+ struct intel_crtc *intel_crtc;
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct intel_plane_state *intel_state = to_intel_plane_state(state);
+
+ crtc = crtc ? crtc : plane->crtc;
+ intel_crtc = to_intel_crtc(crtc);
+
+ /*
+ * Both crtc and plane->crtc could be NULL if we're updating a
+ * property while the plane is disabled. We don't actually have
+ * anything driver-specific we need to test in that case, so
+ * just return success.
+ */
+ if (!crtc)
+ return 0;
+
+ /*
+ * The original src/dest coordinates are stored in state->base, but
+ * we want to keep another copy internal to our driver that we can
+ * clip/modify ourselves.
+ */
+ intel_state->src.x1 = state->src_x;
+ intel_state->src.y1 = state->src_y;
+ intel_state->src.x2 = state->src_x + state->src_w;
+ intel_state->src.y2 = state->src_y + state->src_h;
+ intel_state->dst.x1 = state->crtc_x;
+ intel_state->dst.y1 = state->crtc_y;
+ intel_state->dst.x2 = state->crtc_x + state->crtc_w;
+ intel_state->dst.y2 = state->crtc_y + state->crtc_h;
+
+ /* Clip all planes to CRTC size, or 0x0 if CRTC is disabled */
+ intel_state->clip.x1 = 0;
+ intel_state->clip.y1 = 0;
+ intel_state->clip.x2 =
+ intel_crtc->active ? intel_crtc->config->pipe_src_w : 0;
+ intel_state->clip.y2 =
+ intel_crtc->active ? intel_crtc->config->pipe_src_h : 0;
+
+ /*
+ * Disabling a plane is always okay; we just need to update
+ * fb tracking in a special way since cleanup_fb() won't
+ * get called by the plane helpers.
+ */
+ if (state->fb == NULL && plane->state->fb != NULL) {
+ /*
+ * 'prepare' is never called when plane is being disabled, so
+ * we need to handle frontbuffer tracking as a special case
+ */
+ intel_crtc->atomic.disabled_planes |=
+ (1 << drm_plane_index(plane));
+ }
+
+ return intel_plane->check_plane(plane, intel_state);
+}
+
+static void intel_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ struct intel_plane_state *intel_state =
+ to_intel_plane_state(plane->state);
+
+ /* Don't disable an already disabled plane */
+ if (!plane->state->fb && !old_state->fb)
+ return;
+
+ intel_plane->commit_plane(plane, intel_state);
+}
+
+const struct drm_plane_helper_funcs intel_plane_helper_funcs = {
+ .prepare_fb = intel_prepare_plane_fb,
+ .cleanup_fb = intel_cleanup_plane_fb,
+ .atomic_check = intel_plane_atomic_check,
+ .atomic_update = intel_plane_atomic_update,
+};
+
+/**
+ * intel_plane_atomic_get_property - fetch plane property value
+ * @plane: plane to fetch property for
+ * @state: state containing the property value
+ * @property: property to look up
+ * @val: pointer to write property value into
+ *
+ * The DRM core does not store shadow copies of properties for
+ * atomic-capable drivers. This entrypoint is used to fetch
+ * the current value of a driver-specific plane property.
+ */
+int
+intel_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val)
+{
+ struct drm_mode_config *config = &plane->dev->mode_config;
+
+ if (property == config->rotation_property) {
+ *val = state->rotation;
+ } else {
+ DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * intel_plane_atomic_set_property - set plane property value
+ * @plane: plane to set property for
+ * @state: state to update property value in
+ * @property: property to set
+ * @val: value to set property to
+ *
+ * Writes the specified property value for a plane into the provided atomic
+ * state object.
+ *
+ * Returns 0 on success, -EINVAL on unrecognized properties
+ */
+int
+intel_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t val)
+{
+ struct drm_mode_config *config = &plane->dev->mode_config;
+
+ if (property == config->rotation_property) {
+ state->rotation = val;
+ } else {
+ DRM_DEBUG_KMS("Unknown plane property '%s'\n", property->name);
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/i915/intel_audio.c b/drivers/gpu/drm/i915/intel_audio.c
index 2c7ed5cb29c0..2396cc702d18 100644
--- a/drivers/gpu/drm/i915/intel_audio.c
+++ b/drivers/gpu/drm/i915/intel_audio.c
@@ -22,6 +22,9 @@
*/
#include <linux/kernel.h>
+#include <linux/component.h>
+#include <drm/i915_component.h>
+#include "intel_drv.h"
#include <drm/drmP.h>
#include <drm/drm_edid.h>
@@ -397,7 +400,7 @@ void intel_audio_codec_enable(struct intel_encoder *intel_encoder)
{
struct drm_encoder *encoder = &intel_encoder->base;
struct intel_crtc *crtc = to_intel_crtc(encoder->crtc);
- struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
struct drm_connector *connector;
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -461,3 +464,110 @@ void intel_init_audio(struct drm_device *dev)
dev_priv->display.audio_codec_disable = ilk_audio_codec_disable;
}
}
+
+static void i915_audio_component_get_power(struct device *dev)
+{
+ intel_display_power_get(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+}
+
+static void i915_audio_component_put_power(struct device *dev)
+{
+ intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
+}
+
+/* Get CDCLK in kHz */
+static int i915_audio_component_get_cdclk_freq(struct device *dev)
+{
+ struct drm_i915_private *dev_priv = dev_to_i915(dev);
+ int ret;
+
+ if (WARN_ON_ONCE(!HAS_DDI(dev_priv)))
+ return -ENODEV;
+
+ intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
+ ret = intel_ddi_get_cdclk_freq(dev_priv);
+ intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
+
+ return ret;
+}
+
+static const struct i915_audio_component_ops i915_audio_component_ops = {
+ .owner = THIS_MODULE,
+ .get_power = i915_audio_component_get_power,
+ .put_power = i915_audio_component_put_power,
+ .get_cdclk_freq = i915_audio_component_get_cdclk_freq,
+};
+
+static int i915_audio_component_bind(struct device *i915_dev,
+ struct device *hda_dev, void *data)
+{
+ struct i915_audio_component *acomp = data;
+
+ if (WARN_ON(acomp->ops || acomp->dev))
+ return -EEXIST;
+
+ acomp->ops = &i915_audio_component_ops;
+ acomp->dev = i915_dev;
+
+ return 0;
+}
+
+static void i915_audio_component_unbind(struct device *i915_dev,
+ struct device *hda_dev, void *data)
+{
+ struct i915_audio_component *acomp = data;
+
+ acomp->ops = NULL;
+ acomp->dev = NULL;
+}
+
+static const struct component_ops i915_audio_component_bind_ops = {
+ .bind = i915_audio_component_bind,
+ .unbind = i915_audio_component_unbind,
+};
+
+/**
+ * i915_audio_component_init - initialize and register the audio component
+ * @dev_priv: i915 device instance
+ *
+ * This will register with the component framework a child component which
+ * will bind dynamically to the snd_hda_intel driver's corresponding master
+ * component when the latter is registered. During binding the child
+ * initializes an instance of struct i915_audio_component which it receives
+ * from the master. The master can then start to use the interface defined by
+ * this struct. Each side can break the binding at any point by deregistering
+ * its own component after which each side's component unbind callback is
+ * called.
+ *
+ * We ignore any error during registration and continue with reduced
+ * functionality (i.e. without HDMI audio).
+ */
+void i915_audio_component_init(struct drm_i915_private *dev_priv)
+{
+ int ret;
+
+ ret = component_add(dev_priv->dev->dev, &i915_audio_component_bind_ops);
+ if (ret < 0) {
+ DRM_ERROR("failed to add audio component (%d)\n", ret);
+ /* continue with reduced functionality */
+ return;
+ }
+
+ dev_priv->audio_component_registered = true;
+}
+
+/**
+ * i915_audio_component_cleanup - deregister the audio component
+ * @dev_priv: i915 device instance
+ *
+ * Deregisters the audio component, breaking any existing binding to the
+ * corresponding snd_hda_intel driver's master component.
+ */
+void i915_audio_component_cleanup(struct drm_i915_private *dev_priv)
+{
+ if (!dev_priv->audio_component_registered)
+ return;
+
+ component_del(dev_priv->dev->dev, &i915_audio_component_bind_ops);
+ dev_priv->audio_component_registered = false;
+}
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c
index a4bd90f36a03..3f178258d9f9 100644
--- a/drivers/gpu/drm/i915/intel_bios.c
+++ b/drivers/gpu/drm/i915/intel_bios.c
@@ -664,6 +664,50 @@ parse_edp(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
}
}
+static void
+parse_psr(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
+{
+ struct bdb_psr *psr;
+ struct psr_table *psr_table;
+
+ psr = find_section(bdb, BDB_PSR);
+ if (!psr) {
+ DRM_DEBUG_KMS("No PSR BDB found.\n");
+ return;
+ }
+
+ psr_table = &psr->psr_table[panel_type];
+
+ dev_priv->vbt.psr.full_link = psr_table->full_link;
+ dev_priv->vbt.psr.require_aux_wakeup = psr_table->require_aux_to_wakeup;
+
+ /* Allowed VBT values goes from 0 to 15 */
+ dev_priv->vbt.psr.idle_frames = psr_table->idle_frames < 0 ? 0 :
+ psr_table->idle_frames > 15 ? 15 : psr_table->idle_frames;
+
+ switch (psr_table->lines_to_wait) {
+ case 0:
+ dev_priv->vbt.psr.lines_to_wait = PSR_0_LINES_TO_WAIT;
+ break;
+ case 1:
+ dev_priv->vbt.psr.lines_to_wait = PSR_1_LINE_TO_WAIT;
+ break;
+ case 2:
+ dev_priv->vbt.psr.lines_to_wait = PSR_4_LINES_TO_WAIT;
+ break;
+ case 3:
+ dev_priv->vbt.psr.lines_to_wait = PSR_8_LINES_TO_WAIT;
+ break;
+ default:
+ DRM_DEBUG_KMS("VBT has unknown PSR lines to wait %u\n",
+ psr_table->lines_to_wait);
+ break;
+ }
+
+ dev_priv->vbt.psr.tp1_wakeup_time = psr_table->tp1_wakeup_time;
+ dev_priv->vbt.psr.tp2_tp3_wakeup_time = psr_table->tp2_tp3_wakeup_time;
+}
+
static u8 *goto_next_sequence(u8 *data, int *size)
{
u16 len;
@@ -1241,6 +1285,7 @@ intel_parse_bios(struct drm_device *dev)
parse_device_mapping(dev_priv, bdb);
parse_driver_features(dev_priv, bdb);
parse_edp(dev_priv, bdb);
+ parse_psr(dev_priv, bdb);
parse_mipi(dev_priv, bdb);
parse_ddi_ports(dev_priv, bdb);
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h
index 7603765c91fc..a6a8710f665f 100644
--- a/drivers/gpu/drm/i915/intel_bios.h
+++ b/drivers/gpu/drm/i915/intel_bios.h
@@ -80,7 +80,7 @@ struct vbios_data {
#define BDB_EXT_MMIO_REGS 6
#define BDB_SWF_IO 7
#define BDB_SWF_MMIO 8
-#define BDB_DOT_CLOCK_TABLE 9
+#define BDB_PSR 9
#define BDB_MODE_REMOVAL_TABLE 10
#define BDB_CHILD_DEVICE_TABLE 11
#define BDB_DRIVER_FEATURES 12
@@ -556,6 +556,26 @@ struct bdb_edp {
u16 edp_t3_optimization;
} __packed;
+struct psr_table {
+ /* Feature bits */
+ u8 full_link:1;
+ u8 require_aux_to_wakeup:1;
+ u8 feature_bits_rsvd:6;
+
+ /* Wait times */
+ u8 idle_frames:4;
+ u8 lines_to_wait:3;
+ u8 wait_times_rsvd:1;
+
+ /* TP wake up time in multiple of 100 */
+ u16 tp1_wakeup_time;
+ u16 tp2_tp3_wakeup_time;
+} __packed;
+
+struct bdb_psr {
+ struct psr_table psr_table[16];
+} __packed;
+
void intel_setup_bios(struct drm_device *dev);
int intel_parse_bios(struct drm_device *dev);
@@ -798,7 +818,8 @@ struct mipi_config {
#define DUAL_LINK_PIXEL_ALT 2
u16 dual_link:2;
u16 lane_cnt:2;
- u16 rsvd3:12;
+ u16 pixel_overlap:3;
+ u16 rsvd3:9;
u16 rsvd4;
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index a9af9a4866db..e66e17af0a56 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -28,6 +28,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
@@ -110,31 +111,31 @@ static unsigned int intel_crt_get_flags(struct intel_encoder *encoder)
}
static void intel_crt_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = encoder->base.dev;
int dotclock;
- pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder);
+ pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
dotclock = pipe_config->port_clock;
if (HAS_PCH_SPLIT(dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = dotclock;
}
static void hsw_crt_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
intel_ddi_get_config(encoder, pipe_config);
- pipe_config->adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
+ pipe_config->base.adjusted_mode.flags &= ~(DRM_MODE_FLAG_PHSYNC |
DRM_MODE_FLAG_NHSYNC |
DRM_MODE_FLAG_PVSYNC |
DRM_MODE_FLAG_NVSYNC);
- pipe_config->adjusted_mode.flags |= intel_crt_get_flags(encoder);
+ pipe_config->base.adjusted_mode.flags |= intel_crt_get_flags(encoder);
}
static void hsw_crt_pre_enable(struct intel_encoder *encoder)
@@ -157,7 +158,7 @@ static void intel_crt_set_dpms(struct intel_encoder *encoder, int mode)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crt *crt = intel_encoder_to_crt(encoder);
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
u32 adpa;
if (INTEL_INFO(dev)->gen >= 5)
@@ -303,7 +304,7 @@ intel_crt_mode_valid(struct drm_connector *connector,
}
static bool intel_crt_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = encoder->base.dev;
@@ -792,6 +793,8 @@ static const struct drm_connector_funcs intel_crt_connector_funcs = {
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = intel_crt_destroy,
.set_property = intel_crt_set_property,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+ .atomic_get_property = intel_connector_atomic_get_property,
};
static const struct drm_connector_helper_funcs intel_crt_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e6b45cd150d3..f14e8a2a022d 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -128,15 +128,15 @@ static const struct ddi_buf_trans bdw_ddi_translations_hdmi[] = {
};
static const struct ddi_buf_trans skl_ddi_translations_dp[] = {
- { 0x00000018, 0x000000a0 },
- { 0x00004014, 0x00000098 },
+ { 0x00000018, 0x000000a2 },
+ { 0x00004014, 0x0000009B },
{ 0x00006012, 0x00000088 },
- { 0x00008010, 0x00000080 },
- { 0x00000018, 0x00000098 },
+ { 0x00008010, 0x00000087 },
+ { 0x00000018, 0x0000009B },
{ 0x00004014, 0x00000088 },
- { 0x00006012, 0x00000080 },
+ { 0x00006012, 0x00000087 },
{ 0x00000018, 0x00000088 },
- { 0x00004014, 0x00000080 },
+ { 0x00004014, 0x00000087 },
};
static const struct ddi_buf_trans skl_ddi_translations_hdmi[] = {
@@ -328,7 +328,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
/* Enable the PCH Receiver FDI PLL */
rx_ctl_val = dev_priv->fdi_rx_config | FDI_RX_ENHANCE_FRAME_ENABLE |
FDI_RX_PLL_ENABLE |
- FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+ FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
POSTING_READ(_FDI_RXA_CTL);
udelay(220);
@@ -338,8 +338,8 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
I915_WRITE(_FDI_RXA_CTL, rx_ctl_val);
/* Configure Port Clock Select */
- I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config.ddi_pll_sel);
- WARN_ON(intel_crtc->config.ddi_pll_sel != PORT_CLK_SEL_SPLL);
+ I915_WRITE(PORT_CLK_SEL(PORT_E), intel_crtc->config->ddi_pll_sel);
+ WARN_ON(intel_crtc->config->ddi_pll_sel != PORT_CLK_SEL_SPLL);
/* Start the training iterating through available voltages and emphasis,
* testing each value twice. */
@@ -357,7 +357,7 @@ void hsw_fdi_link_train(struct drm_crtc *crtc)
* port reversal bit */
I915_WRITE(DDI_BUF_CTL(PORT_E),
DDI_BUF_CTL_ENABLE |
- ((intel_crtc->config.fdi_lanes - 1) << 1) |
+ ((intel_crtc->config->fdi_lanes - 1) << 1) |
DDI_BUF_TRANS_SELECT(i / 2));
POSTING_READ(DDI_BUF_CTL(PORT_E));
@@ -732,7 +732,7 @@ static int skl_calc_wrpll_link(struct drm_i915_private *dev_priv,
static void skl_ddi_clock_get(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
int link_clock = 0;
@@ -768,15 +768,15 @@ static void skl_ddi_clock_get(struct intel_encoder *encoder,
pipe_config->port_clock = link_clock;
if (pipe_config->has_dp_encoder)
- pipe_config->adjusted_mode.crtc_clock =
+ pipe_config->base.adjusted_mode.crtc_clock =
intel_dotclock_calculate(pipe_config->port_clock,
&pipe_config->dp_m_n);
else
- pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+ pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
}
static void hsw_ddi_clock_get(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
int link_clock = 0;
@@ -820,21 +820,26 @@ static void hsw_ddi_clock_get(struct intel_encoder *encoder,
pipe_config->port_clock = link_clock * 2;
if (pipe_config->has_pch_encoder)
- pipe_config->adjusted_mode.crtc_clock =
+ pipe_config->base.adjusted_mode.crtc_clock =
intel_dotclock_calculate(pipe_config->port_clock,
&pipe_config->fdi_m_n);
else if (pipe_config->has_dp_encoder)
- pipe_config->adjusted_mode.crtc_clock =
+ pipe_config->base.adjusted_mode.crtc_clock =
intel_dotclock_calculate(pipe_config->port_clock,
&pipe_config->dp_m_n);
else
- pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+ pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
}
void intel_ddi_clock_get(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
- hsw_ddi_clock_get(encoder, pipe_config);
+ struct drm_device *dev = encoder->base.dev;
+
+ if (INTEL_INFO(dev)->gen <= 8)
+ hsw_ddi_clock_get(encoder, pipe_config);
+ else
+ skl_ddi_clock_get(encoder, pipe_config);
}
static void
@@ -904,6 +909,7 @@ hsw_ddi_calculate_wrpll(int clock /* in Hz */,
static bool
hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder,
int clock)
{
@@ -918,16 +924,16 @@ hsw_ddi_pll_select(struct intel_crtc *intel_crtc,
WRPLL_DIVIDER_REFERENCE(r2) | WRPLL_DIVIDER_FEEDBACK(n2) |
WRPLL_DIVIDER_POST(p);
- intel_crtc->new_config->dpll_hw_state.wrpll = val;
+ crtc_state->dpll_hw_state.wrpll = val;
- pll = intel_get_shared_dpll(intel_crtc);
+ pll = intel_get_shared_dpll(intel_crtc, crtc_state);
if (pll == NULL) {
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(intel_crtc->pipe));
return false;
}
- intel_crtc->new_config->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
+ crtc_state->ddi_pll_sel = PORT_CLK_SEL_WRPLL(pll->id);
}
return true;
@@ -1090,6 +1096,7 @@ found:
static bool
skl_ddi_pll_select(struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *crtc_state,
struct intel_encoder *intel_encoder,
int clock)
{
@@ -1139,11 +1146,11 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
} else /* eDP */
return true;
- intel_crtc->new_config->dpll_hw_state.ctrl1 = ctrl1;
- intel_crtc->new_config->dpll_hw_state.cfgcr1 = cfgcr1;
- intel_crtc->new_config->dpll_hw_state.cfgcr2 = cfgcr2;
+ crtc_state->dpll_hw_state.ctrl1 = ctrl1;
+ crtc_state->dpll_hw_state.cfgcr1 = cfgcr1;
+ crtc_state->dpll_hw_state.cfgcr2 = cfgcr2;
- pll = intel_get_shared_dpll(intel_crtc);
+ pll = intel_get_shared_dpll(intel_crtc, crtc_state);
if (pll == NULL) {
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(intel_crtc->pipe));
@@ -1151,7 +1158,7 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
}
/* shared DPLL id 0 is DPLL 1 */
- intel_crtc->new_config->ddi_pll_sel = pll->id + 1;
+ crtc_state->ddi_pll_sel = pll->id + 1;
return true;
}
@@ -1163,17 +1170,20 @@ skl_ddi_pll_select(struct intel_crtc *intel_crtc,
* For private DPLLs, compute_config() should do the selection for us. This
* function should be folded into compute_config() eventually.
*/
-bool intel_ddi_pll_select(struct intel_crtc *intel_crtc)
+bool intel_ddi_pll_select(struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = intel_crtc->base.dev;
struct intel_encoder *intel_encoder =
intel_ddi_get_crtc_new_encoder(intel_crtc);
- int clock = intel_crtc->new_config->port_clock;
+ int clock = crtc_state->port_clock;
if (IS_SKYLAKE(dev))
- return skl_ddi_pll_select(intel_crtc, intel_encoder, clock);
+ return skl_ddi_pll_select(intel_crtc, crtc_state,
+ intel_encoder, clock);
else
- return hsw_ddi_pll_select(intel_crtc, intel_encoder, clock);
+ return hsw_ddi_pll_select(intel_crtc, crtc_state,
+ intel_encoder, clock);
}
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
@@ -1181,13 +1191,13 @@ void intel_ddi_set_pipe_settings(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
int type = intel_encoder->type;
uint32_t temp;
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP || type == INTEL_OUTPUT_DP_MST) {
temp = TRANS_MSA_SYNC_CLK;
- switch (intel_crtc->config.pipe_bpp) {
+ switch (intel_crtc->config->pipe_bpp) {
case 18:
temp |= TRANS_MSA_6_BPC;
break;
@@ -1212,7 +1222,7 @@ void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
uint32_t temp;
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (state == true)
@@ -1230,7 +1240,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = intel_crtc->pipe;
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
enum port port = intel_ddi_get_encoder_port(intel_encoder);
int type = intel_encoder->type;
uint32_t temp;
@@ -1239,7 +1249,7 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
temp = TRANS_DDI_FUNC_ENABLE;
temp |= TRANS_DDI_SELECT_PORT(port);
- switch (intel_crtc->config.pipe_bpp) {
+ switch (intel_crtc->config->pipe_bpp) {
case 18:
temp |= TRANS_DDI_BPC_6;
break;
@@ -1256,9 +1266,9 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
BUG();
}
- if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
+ if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_PVSYNC)
temp |= TRANS_DDI_PVSYNC;
- if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
+ if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_PHSYNC)
temp |= TRANS_DDI_PHSYNC;
if (cpu_transcoder == TRANSCODER_EDP) {
@@ -1269,8 +1279,8 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
* using motion blur mitigation (which we don't
* support). */
if (IS_HASWELL(dev) &&
- (intel_crtc->config.pch_pfit.enabled ||
- intel_crtc->config.pch_pfit.force_thru))
+ (intel_crtc->config->pch_pfit.enabled ||
+ intel_crtc->config->pch_pfit.force_thru))
temp |= TRANS_DDI_EDP_INPUT_A_ONOFF;
else
temp |= TRANS_DDI_EDP_INPUT_A_ON;
@@ -1288,14 +1298,14 @@ void intel_ddi_enable_transcoder_func(struct drm_crtc *crtc)
}
if (type == INTEL_OUTPUT_HDMI) {
- if (intel_crtc->config.has_hdmi_sink)
+ if (intel_crtc->config->has_hdmi_sink)
temp |= TRANS_DDI_MODE_SELECT_HDMI;
else
temp |= TRANS_DDI_MODE_SELECT_DVI;
} else if (type == INTEL_OUTPUT_ANALOG) {
temp |= TRANS_DDI_MODE_SELECT_FDI;
- temp |= (intel_crtc->config.fdi_lanes - 1) << 1;
+ temp |= (intel_crtc->config->fdi_lanes - 1) << 1;
} else if (type == INTEL_OUTPUT_DISPLAYPORT ||
type == INTEL_OUTPUT_EDP) {
@@ -1445,7 +1455,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
struct drm_i915_private *dev_priv = crtc->dev->dev_private;
struct intel_encoder *intel_encoder = intel_ddi_get_crtc_encoder(crtc);
enum port port = intel_ddi_get_encoder_port(intel_encoder);
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
if (cpu_transcoder != TRANSCODER_EDP)
I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1455,7 +1465,7 @@ void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc)
void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc)
{
struct drm_i915_private *dev_priv = intel_crtc->base.dev->dev_private;
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
if (cpu_transcoder != TRANSCODER_EDP)
I915_WRITE(TRANS_CLK_SEL(cpu_transcoder),
@@ -1477,7 +1487,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
}
if (IS_SKYLAKE(dev)) {
- uint32_t dpll = crtc->config.ddi_pll_sel;
+ uint32_t dpll = crtc->config->ddi_pll_sel;
uint32_t val;
/*
@@ -1492,7 +1502,7 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
val &= ~(DPLL_CTRL1_HDMI_MODE(dpll) |
DPLL_CTRL1_SSC(dpll) |
DPLL_CRTL1_LINK_RATE_MASK(dpll));
- val |= crtc->config.dpll_hw_state.ctrl1 << (dpll * 6);
+ val |= crtc->config->dpll_hw_state.ctrl1 << (dpll * 6);
I915_WRITE(DPLL_CTRL1, val);
POSTING_READ(DPLL_CTRL1);
@@ -1509,8 +1519,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
I915_WRITE(DPLL_CTRL2, val);
} else {
- WARN_ON(crtc->config.ddi_pll_sel == PORT_CLK_SEL_NONE);
- I915_WRITE(PORT_CLK_SEL(port), crtc->config.ddi_pll_sel);
+ WARN_ON(crtc->config->ddi_pll_sel == PORT_CLK_SEL_NONE);
+ I915_WRITE(PORT_CLK_SEL(port), crtc->config->ddi_pll_sel);
}
if (type == INTEL_OUTPUT_DISPLAYPORT || type == INTEL_OUTPUT_EDP) {
@@ -1527,8 +1537,8 @@ static void intel_ddi_pre_enable(struct intel_encoder *intel_encoder)
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
intel_hdmi->set_infoframes(encoder,
- crtc->config.has_hdmi_sink,
- &crtc->config.adjusted_mode);
+ crtc->config->has_hdmi_sink,
+ &crtc->config->base.adjusted_mode);
}
}
@@ -1600,9 +1610,10 @@ static void intel_enable_ddi(struct intel_encoder *intel_encoder)
intel_edp_backlight_on(intel_dp);
intel_psr_enable(intel_dp);
+ intel_edp_drrs_enable(intel_dp);
}
- if (intel_crtc->config.has_audio) {
+ if (intel_crtc->config->has_audio) {
intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
intel_audio_codec_enable(intel_encoder);
}
@@ -1617,7 +1628,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (intel_crtc->config.has_audio) {
+ if (intel_crtc->config->has_audio) {
intel_audio_codec_disable(intel_encoder);
intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
}
@@ -1625,6 +1636,7 @@ static void intel_disable_ddi(struct intel_encoder *intel_encoder)
if (type == INTEL_OUTPUT_EDP) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
+ intel_edp_drrs_disable(intel_dp);
intel_psr_disable(intel_dp);
intel_edp_backlight_off(intel_dp);
}
@@ -2022,14 +2034,13 @@ static void intel_ddi_hot_plug(struct intel_encoder *intel_encoder)
}
void intel_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
struct intel_hdmi *intel_hdmi;
u32 temp, flags = 0;
- struct drm_device *dev = dev_priv->dev;
temp = I915_READ(TRANS_DDI_FUNC_CTL(cpu_transcoder));
if (temp & TRANS_DDI_PHSYNC)
@@ -2041,7 +2052,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
else
flags |= DRM_MODE_FLAG_NVSYNC;
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
switch (temp & TRANS_DDI_BPC_MASK) {
case TRANS_DDI_BPC_6:
@@ -2106,10 +2117,7 @@ void intel_ddi_get_config(struct intel_encoder *encoder,
dev_priv->vbt.edp_bpp = pipe_config->pipe_bpp;
}
- if (INTEL_INFO(dev)->gen <= 8)
- hsw_ddi_clock_get(encoder, pipe_config);
- else
- skl_ddi_clock_get(encoder, pipe_config);
+ intel_ddi_clock_get(encoder, pipe_config);
}
static void intel_ddi_destroy(struct drm_encoder *encoder)
@@ -2119,7 +2127,7 @@ static void intel_ddi_destroy(struct drm_encoder *encoder)
}
static bool intel_ddi_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
int type = encoder->type;
int port = intel_ddi_get_encoder_port(encoder);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index e7a16f119a29..3117679299a6 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -37,6 +37,7 @@
#include <drm/i915_drm.h>
#include "i915_drv.h"
#include "i915_trace.h"
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_plane_helper.h>
@@ -76,9 +77,9 @@ static const uint32_t intel_cursor_formats[] = {
static void intel_crtc_update_cursor(struct drm_crtc *crtc, bool on);
static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
static int intel_set_mode(struct drm_crtc *crtc, struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *old_fb);
@@ -95,9 +96,11 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc);
static void haswell_set_pipeconf(struct drm_crtc *crtc);
static void intel_set_pipe_csc(struct drm_crtc *crtc);
static void vlv_prepare_pll(struct intel_crtc *crtc,
- const struct intel_crtc_config *pipe_config);
+ const struct intel_crtc_state *pipe_config);
static void chv_prepare_pll(struct intel_crtc *crtc,
- const struct intel_crtc_config *pipe_config);
+ const struct intel_crtc_state *pipe_config);
+static void intel_begin_crtc_commit(struct drm_crtc *crtc);
+static void intel_finish_crtc_commit(struct drm_crtc *crtc);
static struct intel_encoder *intel_find_encoder(struct intel_connector *connector, int pipe)
{
@@ -895,7 +898,7 @@ bool intel_crtc_active(struct drm_crtc *crtc)
* properly reconstruct framebuffers.
*/
return intel_crtc->active && crtc->primary->fb &&
- intel_crtc->config.adjusted_mode.crtc_clock;
+ intel_crtc->config->base.adjusted_mode.crtc_clock;
}
enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
@@ -904,7 +907,7 @@ enum transcoder intel_pipe_to_cpu_transcoder(struct drm_i915_private *dev_priv,
struct drm_crtc *crtc = dev_priv->pipe_to_crtc_mapping[pipe];
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- return intel_crtc->config.cpu_transcoder;
+ return intel_crtc->config->cpu_transcoder;
}
static bool pipe_dsl_stopped(struct drm_device *dev, enum pipe pipe)
@@ -946,7 +949,7 @@ static void intel_wait_for_pipe_off(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
enum pipe pipe = crtc->pipe;
if (INTEL_INFO(dev)->gen >= 4) {
@@ -1024,7 +1027,7 @@ void assert_pll(struct drm_i915_private *dev_priv,
reg = DPLL(pipe);
val = I915_READ(reg);
cur_state = !!(val & DPLL_VCO_ENABLE);
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"PLL state assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
}
@@ -1040,7 +1043,7 @@ static void assert_dsi_pll(struct drm_i915_private *dev_priv, bool state)
mutex_unlock(&dev_priv->dpio_lock);
cur_state = val & DSI_PLL_VCO_EN;
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"DSI PLL state assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
}
@@ -1052,10 +1055,10 @@ intel_crtc_to_shared_dpll(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- if (crtc->config.shared_dpll < 0)
+ if (crtc->config->shared_dpll < 0)
return NULL;
- return &dev_priv->shared_dplls[crtc->config.shared_dpll];
+ return &dev_priv->shared_dplls[crtc->config->shared_dpll];
}
/* For ILK+ */
@@ -1071,7 +1074,7 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
return;
cur_state = pll->get_hw_state(dev_priv, pll, &hw_state);
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"%s assertion failure (expected %s, current %s)\n",
pll->name, state_string(state), state_string(cur_state));
}
@@ -1095,7 +1098,7 @@ static void assert_fdi_tx(struct drm_i915_private *dev_priv,
val = I915_READ(reg);
cur_state = !!(val & FDI_TX_ENABLE);
}
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"FDI TX state assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
}
@@ -1112,7 +1115,7 @@ static void assert_fdi_rx(struct drm_i915_private *dev_priv,
reg = FDI_RX_CTL(pipe);
val = I915_READ(reg);
cur_state = !!(val & FDI_RX_ENABLE);
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"FDI RX state assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
}
@@ -1135,7 +1138,7 @@ static void assert_fdi_tx_pll_enabled(struct drm_i915_private *dev_priv,
reg = FDI_TX_CTL(pipe);
val = I915_READ(reg);
- WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
+ I915_STATE_WARN(!(val & FDI_TX_PLL_ENABLE), "FDI TX PLL assertion failure, should be active but is disabled\n");
}
void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
@@ -1148,7 +1151,7 @@ void assert_fdi_rx_pll(struct drm_i915_private *dev_priv,
reg = FDI_RX_CTL(pipe);
val = I915_READ(reg);
cur_state = !!(val & FDI_RX_PLL_ENABLE);
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"FDI RX PLL assertion failure (expected %s, current %s)\n",
state_string(state), state_string(cur_state));
}
@@ -1190,7 +1193,7 @@ void assert_panel_unlocked(struct drm_i915_private *dev_priv,
((val & PANEL_UNLOCK_MASK) == PANEL_UNLOCK_REGS))
locked = false;
- WARN(panel_pipe == pipe && locked,
+ I915_STATE_WARN(panel_pipe == pipe && locked,
"panel assertion failure, pipe %c regs locked\n",
pipe_name(pipe));
}
@@ -1206,7 +1209,7 @@ static void assert_cursor(struct drm_i915_private *dev_priv,
else
cur_state = I915_READ(CURCNTR(pipe)) & CURSOR_MODE;
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"cursor on pipe %c assertion failure (expected %s, current %s)\n",
pipe_name(pipe), state_string(state), state_string(cur_state));
}
@@ -1236,7 +1239,7 @@ void assert_pipe(struct drm_i915_private *dev_priv,
cur_state = !!(val & PIPECONF_ENABLE);
}
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"pipe %c assertion failure (expected %s, current %s)\n",
pipe_name(pipe), state_string(state), state_string(cur_state));
}
@@ -1251,7 +1254,7 @@ static void assert_plane(struct drm_i915_private *dev_priv,
reg = DSPCNTR(plane);
val = I915_READ(reg);
cur_state = !!(val & DISPLAY_PLANE_ENABLE);
- WARN(cur_state != state,
+ I915_STATE_WARN(cur_state != state,
"plane %c assertion failure (expected %s, current %s)\n",
plane_name(plane), state_string(state), state_string(cur_state));
}
@@ -1271,7 +1274,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
if (INTEL_INFO(dev)->gen >= 4) {
reg = DSPCNTR(pipe);
val = I915_READ(reg);
- WARN(val & DISPLAY_PLANE_ENABLE,
+ I915_STATE_WARN(val & DISPLAY_PLANE_ENABLE,
"plane %c assertion failure, should be disabled but not\n",
plane_name(pipe));
return;
@@ -1283,7 +1286,7 @@ static void assert_planes_disabled(struct drm_i915_private *dev_priv,
val = I915_READ(reg);
cur_pipe = (val & DISPPLANE_SEL_PIPE_MASK) >>
DISPPLANE_SEL_PIPE_SHIFT;
- WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
+ I915_STATE_WARN((val & DISPLAY_PLANE_ENABLE) && pipe == cur_pipe,
"plane %c assertion failure, should be off on pipe %c but is still active\n",
plane_name(i), pipe_name(pipe));
}
@@ -1299,7 +1302,7 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
if (INTEL_INFO(dev)->gen >= 9) {
for_each_sprite(pipe, sprite) {
val = I915_READ(PLANE_CTL(pipe, sprite));
- WARN(val & PLANE_CTL_ENABLE,
+ I915_STATE_WARN(val & PLANE_CTL_ENABLE,
"plane %d assertion failure, should be off on pipe %c but is still active\n",
sprite, pipe_name(pipe));
}
@@ -1307,20 +1310,20 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
for_each_sprite(pipe, sprite) {
reg = SPCNTR(pipe, sprite);
val = I915_READ(reg);
- WARN(val & SP_ENABLE,
+ I915_STATE_WARN(val & SP_ENABLE,
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
sprite_name(pipe, sprite), pipe_name(pipe));
}
} else if (INTEL_INFO(dev)->gen >= 7) {
reg = SPRCTL(pipe);
val = I915_READ(reg);
- WARN(val & SPRITE_ENABLE,
+ I915_STATE_WARN(val & SPRITE_ENABLE,
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
plane_name(pipe), pipe_name(pipe));
} else if (INTEL_INFO(dev)->gen >= 5) {
reg = DVSCNTR(pipe);
val = I915_READ(reg);
- WARN(val & DVS_ENABLE,
+ I915_STATE_WARN(val & DVS_ENABLE,
"sprite %c assertion failure, should be off on pipe %c but is still active\n",
plane_name(pipe), pipe_name(pipe));
}
@@ -1328,7 +1331,7 @@ static void assert_sprites_disabled(struct drm_i915_private *dev_priv,
static void assert_vblank_disabled(struct drm_crtc *crtc)
{
- if (WARN_ON(drm_crtc_vblank_get(crtc) == 0))
+ if (I915_STATE_WARN_ON(drm_crtc_vblank_get(crtc) == 0))
drm_crtc_vblank_put(crtc);
}
@@ -1337,12 +1340,12 @@ static void ibx_assert_pch_refclk_enabled(struct drm_i915_private *dev_priv)
u32 val;
bool enabled;
- WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
+ I915_STATE_WARN_ON(!(HAS_PCH_IBX(dev_priv->dev) || HAS_PCH_CPT(dev_priv->dev)));
val = I915_READ(PCH_DREF_CONTROL);
enabled = !!(val & (DREF_SSC_SOURCE_MASK | DREF_NONSPREAD_SOURCE_MASK |
DREF_SUPERSPREAD_SOURCE_MASK));
- WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
+ I915_STATE_WARN(!enabled, "PCH refclk assertion failure, should be active but is disabled\n");
}
static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
@@ -1355,7 +1358,7 @@ static void assert_pch_transcoder_disabled(struct drm_i915_private *dev_priv,
reg = PCH_TRANSCONF(pipe);
val = I915_READ(reg);
enabled = !!(val & TRANS_ENABLE);
- WARN(enabled,
+ I915_STATE_WARN(enabled,
"transcoder assertion failed, should be off on pipe %c but is still active\n",
pipe_name(pipe));
}
@@ -1435,11 +1438,11 @@ static void assert_pch_dp_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, int reg, u32 port_sel)
{
u32 val = I915_READ(reg);
- WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
+ I915_STATE_WARN(dp_pipe_enabled(dev_priv, pipe, port_sel, val),
"PCH DP (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
- WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
+ I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & DP_PORT_EN) == 0
&& (val & DP_PIPEB_SELECT),
"IBX PCH dp port still using transcoder B\n");
}
@@ -1448,11 +1451,11 @@ static void assert_pch_hdmi_disabled(struct drm_i915_private *dev_priv,
enum pipe pipe, int reg)
{
u32 val = I915_READ(reg);
- WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
+ I915_STATE_WARN(hdmi_pipe_enabled(dev_priv, pipe, val),
"PCH HDMI (0x%08x) enabled on transcoder %c, should be disabled\n",
reg, pipe_name(pipe));
- WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
+ I915_STATE_WARN(HAS_PCH_IBX(dev_priv->dev) && (val & SDVO_ENABLE) == 0
&& (val & SDVO_PIPE_B_SELECT),
"IBX PCH hdmi port still using transcoder B\n");
}
@@ -1469,13 +1472,13 @@ static void assert_pch_ports_disabled(struct drm_i915_private *dev_priv,
reg = PCH_ADPA;
val = I915_READ(reg);
- WARN(adpa_pipe_enabled(dev_priv, pipe, val),
+ I915_STATE_WARN(adpa_pipe_enabled(dev_priv, pipe, val),
"PCH VGA enabled on transcoder %c, should be disabled\n",
pipe_name(pipe));
reg = PCH_LVDS;
val = I915_READ(reg);
- WARN(lvds_pipe_enabled(dev_priv, pipe, val),
+ I915_STATE_WARN(lvds_pipe_enabled(dev_priv, pipe, val),
"PCH LVDS enabled on transcoder %c, should be disabled\n",
pipe_name(pipe));
@@ -1505,7 +1508,7 @@ static void intel_init_dpio(struct drm_device *dev)
}
static void vlv_enable_pll(struct intel_crtc *crtc,
- const struct intel_crtc_config *pipe_config)
+ const struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1544,7 +1547,7 @@ static void vlv_enable_pll(struct intel_crtc *crtc,
}
static void chv_enable_pll(struct intel_crtc *crtc,
- const struct intel_crtc_config *pipe_config)
+ const struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1599,7 +1602,7 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int reg = DPLL(crtc->pipe);
- u32 dpll = crtc->config.dpll_hw_state.dpll;
+ u32 dpll = crtc->config->dpll_hw_state.dpll;
assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -1629,7 +1632,7 @@ static void i9xx_enable_pll(struct intel_crtc *crtc)
if (INTEL_INFO(dev)->gen >= 4) {
I915_WRITE(DPLL_MD(crtc->pipe),
- crtc->config.dpll_hw_state.dpll_md);
+ crtc->config->dpll_hw_state.dpll_md);
} else {
/* The pixel multiplier can only be updated once the
* DPLL is enabled and the clocks are stable.
@@ -2034,7 +2037,7 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
else
assert_pll_enabled(dev_priv, pipe);
else {
- if (crtc->config.has_pch_encoder) {
+ if (crtc->config->has_pch_encoder) {
/* if driving the PCH, we need FDI enabled */
assert_fdi_rx_pll_enabled(dev_priv, pch_transcoder);
assert_fdi_tx_pll_enabled(dev_priv,
@@ -2068,7 +2071,7 @@ static void intel_enable_pipe(struct intel_crtc *crtc)
static void intel_disable_pipe(struct intel_crtc *crtc)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
- enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
enum pipe pipe = crtc->pipe;
int reg;
u32 val;
@@ -2090,7 +2093,7 @@ static void intel_disable_pipe(struct intel_crtc *crtc)
* Double wide has implications for planes
* so best keep it disabled when not needed.
*/
- if (crtc->config.double_wide)
+ if (crtc->config->double_wide)
val &= ~PIPECONF_DOUBLE_WIDE;
/* Don't disable pipe or pipe PLLs if needed */
@@ -2165,7 +2168,8 @@ static void intel_disable_primary_hw_plane(struct drm_plane *plane,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- assert_pipe_enabled(dev_priv, intel_crtc->pipe);
+ if (WARN_ON(!intel_crtc->active))
+ return;
if (!intel_crtc->primary_enabled)
return;
@@ -2185,11 +2189,12 @@ static bool need_vtd_wa(struct drm_device *dev)
return false;
}
-static int intel_align_height(struct drm_device *dev, int height, bool tiled)
+int
+intel_fb_align_height(struct drm_device *dev, int height, unsigned int tiling)
{
int tile_height;
- tile_height = tiled ? (IS_GEN2(dev) ? 16 : 8) : 1;
+ tile_height = tiling ? (IS_GEN2(dev) ? 16 : 8) : 1;
return ALIGN(height, tile_height);
}
@@ -2312,7 +2317,7 @@ unsigned long intel_gen4_compute_page_offset(int *x, int *y,
}
}
-int intel_format_to_fourcc(int format)
+static int i9xx_format_to_fourcc(int format)
{
switch (format) {
case DISPPLANE_8BPP:
@@ -2333,26 +2338,58 @@ int intel_format_to_fourcc(int format)
}
}
-static bool intel_alloc_plane_obj(struct intel_crtc *crtc,
- struct intel_plane_config *plane_config)
+static int skl_format_to_fourcc(int format, bool rgb_order, bool alpha)
+{
+ switch (format) {
+ case PLANE_CTL_FORMAT_RGB_565:
+ return DRM_FORMAT_RGB565;
+ default:
+ case PLANE_CTL_FORMAT_XRGB_8888:
+ if (rgb_order) {
+ if (alpha)
+ return DRM_FORMAT_ABGR8888;
+ else
+ return DRM_FORMAT_XBGR8888;
+ } else {
+ if (alpha)
+ return DRM_FORMAT_ARGB8888;
+ else
+ return DRM_FORMAT_XRGB8888;
+ }
+ case PLANE_CTL_FORMAT_XRGB_2101010:
+ if (rgb_order)
+ return DRM_FORMAT_XBGR2101010;
+ else
+ return DRM_FORMAT_XRGB2101010;
+ }
+}
+
+static bool
+intel_alloc_plane_obj(struct intel_crtc *crtc,
+ struct intel_initial_plane_config *plane_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_gem_object *obj = NULL;
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
- u32 base = plane_config->base;
+ u32 base_aligned = round_down(plane_config->base, PAGE_SIZE);
+ u32 size_aligned = round_up(plane_config->base + plane_config->size,
+ PAGE_SIZE);
+
+ size_aligned -= base_aligned;
if (plane_config->size == 0)
return false;
- obj = i915_gem_object_create_stolen_for_preallocated(dev, base, base,
- plane_config->size);
+ obj = i915_gem_object_create_stolen_for_preallocated(dev,
+ base_aligned,
+ base_aligned,
+ size_aligned);
if (!obj)
return false;
- if (plane_config->tiled) {
- obj->tiling_mode = I915_TILING_X;
+ obj->tiling_mode = plane_config->tiling;
+ if (obj->tiling_mode == I915_TILING_X)
obj->stride = crtc->base.primary->fb->pitches[0];
- }
mode_cmd.pixel_format = crtc->base.primary->fb->pixel_format;
mode_cmd.width = crtc->base.primary->fb->width;
@@ -2379,8 +2416,9 @@ out_unref_obj:
return false;
}
-static void intel_find_plane_obj(struct intel_crtc *intel_crtc,
- struct intel_plane_config *plane_config)
+static void
+intel_find_plane_obj(struct intel_crtc *intel_crtc,
+ struct intel_initial_plane_config *plane_config)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -2468,13 +2506,13 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
* which should always be the user's requested size.
*/
I915_WRITE(DSPSIZE(plane),
- ((intel_crtc->config.pipe_src_h - 1) << 16) |
- (intel_crtc->config.pipe_src_w - 1));
+ ((intel_crtc->config->pipe_src_h - 1) << 16) |
+ (intel_crtc->config->pipe_src_w - 1));
I915_WRITE(DSPPOS(plane), 0);
} else if (IS_CHERRYVIEW(dev) && plane == PLANE_B) {
I915_WRITE(PRIMSIZE(plane),
- ((intel_crtc->config.pipe_src_h - 1) << 16) |
- (intel_crtc->config.pipe_src_w - 1));
+ ((intel_crtc->config->pipe_src_h - 1) << 16) |
+ (intel_crtc->config->pipe_src_w - 1));
I915_WRITE(PRIMPOS(plane), 0);
I915_WRITE(PRIMCNSTALPHA(plane), 0);
}
@@ -2529,17 +2567,17 @@ static void i9xx_update_primary_plane(struct drm_crtc *crtc,
intel_crtc->dspaddr_offset = linear_offset;
}
- if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
+ if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) {
dspcntr |= DISPPLANE_ROTATE_180;
- x += (intel_crtc->config.pipe_src_w - 1);
- y += (intel_crtc->config.pipe_src_h - 1);
+ x += (intel_crtc->config->pipe_src_w - 1);
+ y += (intel_crtc->config->pipe_src_h - 1);
/* Finding the last pixel of the last line of the display
data and adding to linear_offset*/
linear_offset +=
- (intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
- (intel_crtc->config.pipe_src_w - 1) * pixel_size;
+ (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] +
+ (intel_crtc->config->pipe_src_w - 1) * pixel_size;
}
I915_WRITE(reg, dspcntr);
@@ -2631,18 +2669,18 @@ static void ironlake_update_primary_plane(struct drm_crtc *crtc,
pixel_size,
fb->pitches[0]);
linear_offset -= intel_crtc->dspaddr_offset;
- if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180)) {
+ if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180)) {
dspcntr |= DISPPLANE_ROTATE_180;
if (!IS_HASWELL(dev) && !IS_BROADWELL(dev)) {
- x += (intel_crtc->config.pipe_src_w - 1);
- y += (intel_crtc->config.pipe_src_h - 1);
+ x += (intel_crtc->config->pipe_src_w - 1);
+ y += (intel_crtc->config->pipe_src_h - 1);
/* Finding the last pixel of the last line of the display
data and adding to linear_offset*/
linear_offset +=
- (intel_crtc->config.pipe_src_h - 1) * fb->pitches[0] +
- (intel_crtc->config.pipe_src_w - 1) * pixel_size;
+ (intel_crtc->config->pipe_src_h - 1) * fb->pitches[0] +
+ (intel_crtc->config->pipe_src_w - 1) * pixel_size;
}
}
@@ -2693,10 +2731,19 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
case DRM_FORMAT_XRGB8888:
plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
break;
+ case DRM_FORMAT_ARGB8888:
+ plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
+ plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+ break;
case DRM_FORMAT_XBGR8888:
plane_ctl |= PLANE_CTL_ORDER_RGBX;
plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
break;
+ case DRM_FORMAT_ABGR8888:
+ plane_ctl |= PLANE_CTL_ORDER_RGBX;
+ plane_ctl |= PLANE_CTL_FORMAT_XRGB_8888;
+ plane_ctl |= PLANE_CTL_ALPHA_SW_PREMULTIPLY;
+ break;
case DRM_FORMAT_XRGB2101010:
plane_ctl |= PLANE_CTL_FORMAT_XRGB_2101010;
break;
@@ -2728,7 +2775,7 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
}
plane_ctl |= PLANE_CTL_PLANE_GAMMA_DISABLE;
- if (to_intel_plane(crtc->primary)->rotation == BIT(DRM_ROTATE_180))
+ if (crtc->primary->state->rotation == BIT(DRM_ROTATE_180))
plane_ctl |= PLANE_CTL_ROTATE_180;
I915_WRITE(PLANE_CTL(pipe, 0), plane_ctl);
@@ -2741,8 +2788,8 @@ static void skylake_update_primary_plane(struct drm_crtc *crtc,
I915_WRITE(PLANE_POS(pipe, 0), 0);
I915_WRITE(PLANE_OFFSET(pipe, 0), (y << 16) | x);
I915_WRITE(PLANE_SIZE(pipe, 0),
- (intel_crtc->config.pipe_src_h - 1) << 16 |
- (intel_crtc->config.pipe_src_w - 1));
+ (intel_crtc->config->pipe_src_h - 1) << 16 |
+ (intel_crtc->config->pipe_src_w - 1));
I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
I915_WRITE(PLANE_SURF(pipe, 0), i915_gem_obj_ggtt_offset(obj));
@@ -2938,85 +2985,20 @@ static void intel_update_pipe_size(struct intel_crtc *crtc)
* then update the pipesrc and pfit state, even on the flip path.
*/
- adjusted_mode = &crtc->config.adjusted_mode;
+ adjusted_mode = &crtc->config->base.adjusted_mode;
I915_WRITE(PIPESRC(crtc->pipe),
((adjusted_mode->crtc_hdisplay - 1) << 16) |
(adjusted_mode->crtc_vdisplay - 1));
- if (!crtc->config.pch_pfit.enabled &&
+ if (!crtc->config->pch_pfit.enabled &&
(intel_pipe_has_type(crtc, INTEL_OUTPUT_LVDS) ||
intel_pipe_has_type(crtc, INTEL_OUTPUT_EDP))) {
I915_WRITE(PF_CTL(crtc->pipe), 0);
I915_WRITE(PF_WIN_POS(crtc->pipe), 0);
I915_WRITE(PF_WIN_SZ(crtc->pipe), 0);
}
- crtc->config.pipe_src_w = adjusted_mode->crtc_hdisplay;
- crtc->config.pipe_src_h = adjusted_mode->crtc_vdisplay;
-}
-
-static int
-intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *fb)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_framebuffer *old_fb = crtc->primary->fb;
- struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
- int ret;
-
- if (intel_crtc_has_pending_flip(crtc)) {
- DRM_ERROR("pipe is still busy with an old pageflip\n");
- return -EBUSY;
- }
-
- /* no fb bound */
- if (!fb) {
- DRM_ERROR("No FB bound\n");
- return 0;
- }
-
- if (intel_crtc->plane > INTEL_INFO(dev)->num_pipes) {
- DRM_ERROR("no plane for crtc: plane %c, num_pipes %d\n",
- plane_name(intel_crtc->plane),
- INTEL_INFO(dev)->num_pipes);
- return -EINVAL;
- }
-
- mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL);
- if (ret == 0)
- i915_gem_track_fb(old_obj, intel_fb_obj(fb),
- INTEL_FRONTBUFFER_PRIMARY(pipe));
- mutex_unlock(&dev->struct_mutex);
- if (ret != 0) {
- DRM_ERROR("pin & fence failed\n");
- return ret;
- }
-
- dev_priv->display.update_primary_plane(crtc, fb, x, y);
-
- if (intel_crtc->active)
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
-
- crtc->primary->fb = fb;
- crtc->x = x;
- crtc->y = y;
-
- if (old_fb) {
- if (intel_crtc->active && old_fb != fb)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
- mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(old_obj);
- mutex_unlock(&dev->struct_mutex);
- }
-
- mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
- mutex_unlock(&dev->struct_mutex);
-
- return 0;
+ crtc->config->pipe_src_w = adjusted_mode->crtc_hdisplay;
+ crtc->config->pipe_src_h = adjusted_mode->crtc_vdisplay;
}
static void intel_fdi_normal_train(struct drm_crtc *crtc)
@@ -3063,7 +3045,7 @@ static void intel_fdi_normal_train(struct drm_crtc *crtc)
static bool pipe_has_enabled_pch(struct intel_crtc *crtc)
{
return crtc->base.enabled && crtc->active &&
- crtc->config.has_pch_encoder;
+ crtc->config->has_pch_encoder;
}
static void ivb_modeset_global_resources(struct drm_device *dev)
@@ -3118,7 +3100,7 @@ static void ironlake_fdi_link_train(struct drm_crtc *crtc)
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
temp &= ~FDI_DP_PORT_WIDTH_MASK;
- temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
I915_WRITE(reg, temp | FDI_TX_ENABLE);
@@ -3216,7 +3198,7 @@ static void gen6_fdi_link_train(struct drm_crtc *crtc)
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
temp &= ~FDI_DP_PORT_WIDTH_MASK;
- temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
temp &= ~FDI_LINK_TRAIN_NONE;
temp |= FDI_LINK_TRAIN_PATTERN_1;
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
@@ -3367,7 +3349,7 @@ static void ivb_manual_fdi_link_train(struct drm_crtc *crtc)
reg = FDI_TX_CTL(pipe);
temp = I915_READ(reg);
temp &= ~FDI_DP_PORT_WIDTH_MASK;
- temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
temp |= FDI_LINK_TRAIN_PATTERN_1_IVB;
temp &= ~FDI_LINK_TRAIN_VOL_EMP_MASK;
temp |= snb_b_fdi_train_param[j/2];
@@ -3455,7 +3437,7 @@ static void ironlake_fdi_pll_enable(struct intel_crtc *intel_crtc)
reg = FDI_RX_CTL(pipe);
temp = I915_READ(reg);
temp &= ~(FDI_DP_PORT_WIDTH_MASK | (0x7 << 16));
- temp |= FDI_DP_PORT_WIDTH(intel_crtc->config.fdi_lanes);
+ temp |= FDI_DP_PORT_WIDTH(intel_crtc->config->fdi_lanes);
temp |= (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) << 11;
I915_WRITE(reg, temp | FDI_RX_PLL_ENABLE);
@@ -3639,7 +3621,7 @@ static void lpt_program_iclkip(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
+ int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
u32 divsel, phaseinc, auxdiv, phasedir = 0;
u32 temp;
@@ -3728,7 +3710,7 @@ static void ironlake_pch_transcoder_set_timings(struct intel_crtc *crtc,
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = crtc->config->cpu_transcoder;
I915_WRITE(PCH_TRANS_HTOTAL(pch_transcoder),
I915_READ(HTOTAL(cpu_transcoder)));
@@ -3774,7 +3756,7 @@ static void ivybridge_update_fdi_bc_bifurcation(struct intel_crtc *intel_crtc)
case PIPE_A:
break;
case PIPE_B:
- if (intel_crtc->config.fdi_lanes > 2)
+ if (intel_crtc->config->fdi_lanes > 2)
WARN_ON(I915_READ(SOUTH_CHICKEN1) & FDI_BC_BIFURCATION_SELECT);
else
cpt_enable_fdi_bc_bifurcation(dev);
@@ -3826,7 +3808,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
temp = I915_READ(PCH_DPLL_SEL);
temp |= TRANS_DPLL_ENABLE(pipe);
sel = TRANS_DPLLB_SEL(pipe);
- if (intel_crtc->config.shared_dpll == DPLL_ID_PCH_PLL_B)
+ if (intel_crtc->config->shared_dpll == DPLL_ID_PCH_PLL_B)
temp |= sel;
else
temp &= ~sel;
@@ -3849,7 +3831,7 @@ static void ironlake_pch_enable(struct drm_crtc *crtc)
intel_fdi_normal_train(crtc);
/* For PCH DP, enable TRANS_DP_CTL */
- if (HAS_PCH_CPT(dev) && intel_crtc->config.has_dp_encoder) {
+ if (HAS_PCH_CPT(dev) && intel_crtc->config->has_dp_encoder) {
u32 bpc = (I915_READ(PIPECONF(pipe)) & PIPECONF_BPC_MASK) >> 5;
reg = TRANS_DP_CTL(pipe);
temp = I915_READ(reg);
@@ -3890,7 +3872,7 @@ static void lpt_pch_enable(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
assert_pch_transcoder_disabled(dev_priv, TRANSCODER_A);
@@ -3920,10 +3902,11 @@ void intel_put_shared_dpll(struct intel_crtc *crtc)
WARN_ON(pll->active);
}
- crtc->config.shared_dpll = DPLL_ID_PRIVATE;
+ crtc->config->shared_dpll = DPLL_ID_PRIVATE;
}
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
+struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *dev_priv = crtc->base.dev->dev_private;
struct intel_shared_dpll *pll;
@@ -3949,7 +3932,7 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
if (pll->new_config->crtc_mask == 0)
continue;
- if (memcmp(&crtc->new_config->dpll_hw_state,
+ if (memcmp(&crtc_state->dpll_hw_state,
&pll->new_config->hw_state,
sizeof(pll->new_config->hw_state)) == 0) {
DRM_DEBUG_KMS("CRTC:%d sharing existing %s (crtc mask 0x%08x, ative %d)\n",
@@ -3974,9 +3957,9 @@ struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc)
found:
if (pll->new_config->crtc_mask == 0)
- pll->new_config->hw_state = crtc->new_config->dpll_hw_state;
+ pll->new_config->hw_state = crtc_state->dpll_hw_state;
- crtc->new_config->shared_dpll = i;
+ crtc_state->shared_dpll = i;
DRM_DEBUG_DRIVER("using %s for pipe %c\n", pll->name,
pipe_name(crtc->pipe));
@@ -4073,10 +4056,10 @@ static void skylake_pfit_enable(struct intel_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = crtc->pipe;
- if (crtc->config.pch_pfit.enabled) {
+ if (crtc->config->pch_pfit.enabled) {
I915_WRITE(PS_CTL(pipe), PS_ENABLE);
- I915_WRITE(PS_WIN_POS(pipe), crtc->config.pch_pfit.pos);
- I915_WRITE(PS_WIN_SZ(pipe), crtc->config.pch_pfit.size);
+ I915_WRITE(PS_WIN_POS(pipe), crtc->config->pch_pfit.pos);
+ I915_WRITE(PS_WIN_SZ(pipe), crtc->config->pch_pfit.size);
}
}
@@ -4086,7 +4069,7 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = crtc->pipe;
- if (crtc->config.pch_pfit.enabled) {
+ if (crtc->config->pch_pfit.enabled) {
/* Force use of hard-coded filter coefficients
* as some pre-programmed values are broken,
* e.g. x201.
@@ -4096,12 +4079,12 @@ static void ironlake_pfit_enable(struct intel_crtc *crtc)
PF_PIPE_SEL_IVB(pipe));
else
I915_WRITE(PF_CTL(pipe), PF_ENABLE | PF_FILTER_MED_3x3);
- I915_WRITE(PF_WIN_POS(pipe), crtc->config.pch_pfit.pos);
- I915_WRITE(PF_WIN_SZ(pipe), crtc->config.pch_pfit.size);
+ I915_WRITE(PF_WIN_POS(pipe), crtc->config->pch_pfit.pos);
+ I915_WRITE(PF_WIN_SZ(pipe), crtc->config->pch_pfit.size);
}
}
-static void intel_enable_planes(struct drm_crtc *crtc)
+static void intel_enable_sprite_planes(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
@@ -4115,7 +4098,7 @@ static void intel_enable_planes(struct drm_crtc *crtc)
}
}
-static void intel_disable_planes(struct drm_crtc *crtc)
+static void intel_disable_sprite_planes(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
enum pipe pipe = to_intel_crtc(crtc)->pipe;
@@ -4125,7 +4108,7 @@ static void intel_disable_planes(struct drm_crtc *crtc)
drm_for_each_legacy_plane(plane, &dev->mode_config.plane_list) {
intel_plane = to_intel_plane(plane);
if (intel_plane->pipe == pipe)
- intel_plane_disable(&intel_plane->base);
+ plane->funcs->disable_plane(plane);
}
}
@@ -4134,7 +4117,7 @@ void hsw_enable_ips(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (!crtc->config.ips_enabled)
+ if (!crtc->config->ips_enabled)
return;
/* We can only enable IPS after we enable a plane and wait for a vblank */
@@ -4167,7 +4150,7 @@ void hsw_disable_ips(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (!crtc->config.ips_enabled)
+ if (!crtc->config->ips_enabled)
return;
assert_plane_enabled(dev_priv, crtc->plane);
@@ -4216,7 +4199,7 @@ static void intel_crtc_load_lut(struct drm_crtc *crtc)
/* Workaround : Do not read or write the pipe palette/gamma data while
* GAMMA_MODE is configured for split gamma and IPS_CTL has IPS enabled.
*/
- if (IS_HASWELL(dev) && intel_crtc->config.ips_enabled &&
+ if (IS_HASWELL(dev) && intel_crtc->config->ips_enabled &&
((I915_READ(GAMMA_MODE(pipe)) & GAMMA_MODE_MODE_MASK) ==
GAMMA_MODE_MODE_SPLIT)) {
hsw_disable_ips(intel_crtc);
@@ -4259,14 +4242,14 @@ static void intel_crtc_enable_planes(struct drm_crtc *crtc)
int pipe = intel_crtc->pipe;
intel_enable_primary_hw_plane(crtc->primary, crtc);
- intel_enable_planes(crtc);
+ intel_enable_sprite_planes(crtc);
intel_crtc_update_cursor(crtc, true);
intel_crtc_dpms_overlay(intel_crtc, true);
hsw_enable_ips(intel_crtc);
mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
+ intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex);
/*
@@ -4288,13 +4271,13 @@ static void intel_crtc_disable_planes(struct drm_crtc *crtc)
intel_crtc_wait_for_pending_flips(crtc);
if (dev_priv->fbc.plane == plane)
- intel_disable_fbc(dev);
+ intel_fbc_disable(dev);
hsw_disable_ips(intel_crtc);
intel_crtc_dpms_overlay(intel_crtc, false);
intel_crtc_update_cursor(crtc, false);
- intel_disable_planes(crtc);
+ intel_disable_sprite_planes(crtc);
intel_disable_primary_hw_plane(crtc->primary, crtc);
/*
@@ -4318,17 +4301,17 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
if (intel_crtc->active)
return;
- if (intel_crtc->config.has_pch_encoder)
+ if (intel_crtc->config->has_pch_encoder)
intel_prepare_shared_dpll(intel_crtc);
- if (intel_crtc->config.has_dp_encoder)
+ if (intel_crtc->config->has_dp_encoder)
intel_dp_set_m_n(intel_crtc);
intel_set_pipe_timings(intel_crtc);
- if (intel_crtc->config.has_pch_encoder) {
+ if (intel_crtc->config->has_pch_encoder) {
intel_cpu_transcoder_set_m_n(intel_crtc,
- &intel_crtc->config.fdi_m_n, NULL);
+ &intel_crtc->config->fdi_m_n, NULL);
}
ironlake_set_pipeconf(crtc);
@@ -4342,7 +4325,7 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
if (encoder->pre_enable)
encoder->pre_enable(encoder);
- if (intel_crtc->config.has_pch_encoder) {
+ if (intel_crtc->config->has_pch_encoder) {
/* Note: FDI PLL enabling _must_ be done before we enable the
* cpu pipes, hence this is separate from all the other fdi/pch
* enabling. */
@@ -4363,18 +4346,18 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
- if (intel_crtc->config.has_pch_encoder)
+ if (intel_crtc->config->has_pch_encoder)
ironlake_pch_enable(crtc);
+ assert_vblank_disabled(crtc);
+ drm_crtc_vblank_on(crtc);
+
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->enable(encoder);
if (HAS_PCH_CPT(dev))
cpt_verify_modeset(dev, intel_crtc->pipe);
- assert_vblank_disabled(crtc);
- drm_crtc_vblank_on(crtc);
-
intel_crtc_enable_planes(crtc);
}
@@ -4429,19 +4412,19 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
if (intel_crtc_to_shared_dpll(intel_crtc))
intel_enable_shared_dpll(intel_crtc);
- if (intel_crtc->config.has_dp_encoder)
+ if (intel_crtc->config->has_dp_encoder)
intel_dp_set_m_n(intel_crtc);
intel_set_pipe_timings(intel_crtc);
- if (intel_crtc->config.cpu_transcoder != TRANSCODER_EDP) {
- I915_WRITE(PIPE_MULT(intel_crtc->config.cpu_transcoder),
- intel_crtc->config.pixel_multiplier - 1);
+ if (intel_crtc->config->cpu_transcoder != TRANSCODER_EDP) {
+ I915_WRITE(PIPE_MULT(intel_crtc->config->cpu_transcoder),
+ intel_crtc->config->pixel_multiplier - 1);
}
- if (intel_crtc->config.has_pch_encoder) {
+ if (intel_crtc->config->has_pch_encoder) {
intel_cpu_transcoder_set_m_n(intel_crtc,
- &intel_crtc->config.fdi_m_n, NULL);
+ &intel_crtc->config->fdi_m_n, NULL);
}
haswell_set_pipeconf(crtc);
@@ -4455,7 +4438,7 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
if (encoder->pre_enable)
encoder->pre_enable(encoder);
- if (intel_crtc->config.has_pch_encoder) {
+ if (intel_crtc->config->has_pch_encoder) {
intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
true);
dev_priv->display.fdi_link_train(crtc);
@@ -4480,20 +4463,20 @@ static void haswell_crtc_enable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
- if (intel_crtc->config.has_pch_encoder)
+ if (intel_crtc->config->has_pch_encoder)
lpt_pch_enable(crtc);
- if (intel_crtc->config.dp_encoder_is_mst)
+ if (intel_crtc->config->dp_encoder_is_mst)
intel_ddi_set_vc_payload_alloc(crtc, true);
+ assert_vblank_disabled(crtc);
+ drm_crtc_vblank_on(crtc);
+
for_each_encoder_on_crtc(dev, crtc, encoder) {
encoder->enable(encoder);
intel_opregion_notify_encoder(encoder, true);
}
- assert_vblank_disabled(crtc);
- drm_crtc_vblank_on(crtc);
-
/* If we change the relative order between pipe/planes enabling, we need
* to change the workaround. */
haswell_mode_set_planes_workaround(intel_crtc);
@@ -4508,7 +4491,7 @@ static void skylake_pfit_disable(struct intel_crtc *crtc)
/* To avoid upsetting the power well on haswell only disable the pfit if
* it's in use. The hw state code will make sure we get this right. */
- if (crtc->config.pch_pfit.enabled) {
+ if (crtc->config->pch_pfit.enabled) {
I915_WRITE(PS_CTL(pipe), 0);
I915_WRITE(PS_WIN_POS(pipe), 0);
I915_WRITE(PS_WIN_SZ(pipe), 0);
@@ -4523,7 +4506,7 @@ static void ironlake_pfit_disable(struct intel_crtc *crtc)
/* To avoid upsetting the power well on haswell only disable the pfit if
* it's in use. The hw state code will make sure we get this right. */
- if (crtc->config.pch_pfit.enabled) {
+ if (crtc->config->pch_pfit.enabled) {
I915_WRITE(PF_CTL(pipe), 0);
I915_WRITE(PF_WIN_POS(pipe), 0);
I915_WRITE(PF_WIN_SZ(pipe), 0);
@@ -4544,13 +4527,13 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
intel_crtc_disable_planes(crtc);
- drm_crtc_vblank_off(crtc);
- assert_vblank_disabled(crtc);
-
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->disable(encoder);
- if (intel_crtc->config.has_pch_encoder)
+ drm_crtc_vblank_off(crtc);
+ assert_vblank_disabled(crtc);
+
+ if (intel_crtc->config->has_pch_encoder)
intel_set_pch_fifo_underrun_reporting(dev_priv, pipe, false);
intel_disable_pipe(intel_crtc);
@@ -4561,7 +4544,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
if (encoder->post_disable)
encoder->post_disable(encoder);
- if (intel_crtc->config.has_pch_encoder) {
+ if (intel_crtc->config->has_pch_encoder) {
ironlake_fdi_disable(crtc);
ironlake_disable_pch_transcoder(dev_priv, pipe);
@@ -4591,7 +4574,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
+ intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex);
}
@@ -4601,27 +4584,27 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
struct intel_encoder *encoder;
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
if (!intel_crtc->active)
return;
intel_crtc_disable_planes(crtc);
- drm_crtc_vblank_off(crtc);
- assert_vblank_disabled(crtc);
-
for_each_encoder_on_crtc(dev, crtc, encoder) {
intel_opregion_notify_encoder(encoder, false);
encoder->disable(encoder);
}
- if (intel_crtc->config.has_pch_encoder)
+ drm_crtc_vblank_off(crtc);
+ assert_vblank_disabled(crtc);
+
+ if (intel_crtc->config->has_pch_encoder)
intel_set_pch_fifo_underrun_reporting(dev_priv, TRANSCODER_A,
false);
intel_disable_pipe(intel_crtc);
- if (intel_crtc->config.dp_encoder_is_mst)
+ if (intel_crtc->config->dp_encoder_is_mst)
intel_ddi_set_vc_payload_alloc(crtc, false);
intel_ddi_disable_transcoder_func(dev_priv, cpu_transcoder);
@@ -4633,7 +4616,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
intel_ddi_disable_pipe_clock(intel_crtc);
- if (intel_crtc->config.has_pch_encoder) {
+ if (intel_crtc->config->has_pch_encoder) {
lpt_disable_pch_transcoder(dev_priv);
intel_ddi_fdi_disable(crtc);
}
@@ -4646,7 +4629,7 @@ static void haswell_crtc_disable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
+ intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex);
if (intel_crtc_to_shared_dpll(intel_crtc))
@@ -4664,9 +4647,9 @@ static void i9xx_pfit_enable(struct intel_crtc *crtc)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc_config *pipe_config = &crtc->config;
+ struct intel_crtc_state *pipe_config = crtc->config;
- if (!crtc->config.gmch_pfit.control)
+ if (!pipe_config->gmch_pfit.control)
return;
/*
@@ -4745,8 +4728,8 @@ static unsigned long get_crtc_power_domains(struct drm_crtc *crtc)
mask = BIT(POWER_DOMAIN_PIPE(pipe));
mask |= BIT(POWER_DOMAIN_TRANSCODER(transcoder));
- if (intel_crtc->config.pch_pfit.enabled ||
- intel_crtc->config.pch_pfit.force_thru)
+ if (intel_crtc->config->pch_pfit.enabled ||
+ intel_crtc->config->pch_pfit.force_thru)
mask |= BIT(POWER_DOMAIN_PIPE_PANEL_FITTER(pipe));
for_each_encoder_on_crtc(dev, crtc, intel_encoder)
@@ -4909,7 +4892,7 @@ static void cherryview_set_cdclk(struct drm_device *dev, int cdclk)
cmd = 0;
break;
default:
- WARN_ON(1);
+ MISSING_CASE(cdclk);
return;
}
@@ -4970,7 +4953,7 @@ static int intel_mode_max_pixclk(struct drm_i915_private *dev_priv)
for_each_intel_crtc(dev, intel_crtc) {
if (intel_crtc->new_enabled)
max_pixclk = max(max_pixclk,
- intel_crtc->new_config->adjusted_mode.crtc_clock);
+ intel_crtc->new_config->base.adjusted_mode.crtc_clock);
}
return max_pixclk;
@@ -5038,12 +5021,12 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
if (!is_dsi) {
if (IS_CHERRYVIEW(dev))
- chv_prepare_pll(intel_crtc, &intel_crtc->config);
+ chv_prepare_pll(intel_crtc, intel_crtc->config);
else
- vlv_prepare_pll(intel_crtc, &intel_crtc->config);
+ vlv_prepare_pll(intel_crtc, intel_crtc->config);
}
- if (intel_crtc->config.has_dp_encoder)
+ if (intel_crtc->config->has_dp_encoder)
intel_dp_set_m_n(intel_crtc);
intel_set_pipe_timings(intel_crtc);
@@ -5067,9 +5050,9 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
if (!is_dsi) {
if (IS_CHERRYVIEW(dev))
- chv_enable_pll(intel_crtc, &intel_crtc->config);
+ chv_enable_pll(intel_crtc, intel_crtc->config);
else
- vlv_enable_pll(intel_crtc, &intel_crtc->config);
+ vlv_enable_pll(intel_crtc, intel_crtc->config);
}
for_each_encoder_on_crtc(dev, crtc, encoder)
@@ -5083,12 +5066,12 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
- for_each_encoder_on_crtc(dev, crtc, encoder)
- encoder->enable(encoder);
-
assert_vblank_disabled(crtc);
drm_crtc_vblank_on(crtc);
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ encoder->enable(encoder);
+
intel_crtc_enable_planes(crtc);
/* Underruns don't raise interrupts, so check manually. */
@@ -5100,8 +5083,8 @@ static void i9xx_set_pll_dividers(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- I915_WRITE(FP0(crtc->pipe), crtc->config.dpll_hw_state.fp0);
- I915_WRITE(FP1(crtc->pipe), crtc->config.dpll_hw_state.fp1);
+ I915_WRITE(FP0(crtc->pipe), crtc->config->dpll_hw_state.fp0);
+ I915_WRITE(FP1(crtc->pipe), crtc->config->dpll_hw_state.fp1);
}
static void i9xx_crtc_enable(struct drm_crtc *crtc)
@@ -5119,7 +5102,7 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
i9xx_set_pll_dividers(intel_crtc);
- if (intel_crtc->config.has_dp_encoder)
+ if (intel_crtc->config->has_dp_encoder)
intel_dp_set_m_n(intel_crtc);
intel_set_pipe_timings(intel_crtc);
@@ -5144,12 +5127,12 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
intel_enable_pipe(intel_crtc);
- for_each_encoder_on_crtc(dev, crtc, encoder)
- encoder->enable(encoder);
-
assert_vblank_disabled(crtc);
drm_crtc_vblank_on(crtc);
+ for_each_encoder_on_crtc(dev, crtc, encoder)
+ encoder->enable(encoder);
+
intel_crtc_enable_planes(crtc);
/*
@@ -5171,7 +5154,7 @@ static void i9xx_pfit_disable(struct intel_crtc *crtc)
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- if (!crtc->config.gmch_pfit.control)
+ if (!crtc->config->gmch_pfit.control)
return;
assert_pipe_disabled(dev_priv, crtc->pipe);
@@ -5221,12 +5204,12 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
*/
intel_wait_for_vblank(dev, pipe);
- drm_crtc_vblank_off(crtc);
- assert_vblank_disabled(crtc);
-
for_each_encoder_on_crtc(dev, crtc, encoder)
encoder->disable(encoder);
+ drm_crtc_vblank_off(crtc);
+ assert_vblank_disabled(crtc);
+
intel_disable_pipe(intel_crtc);
i9xx_pfit_disable(intel_crtc);
@@ -5251,7 +5234,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
intel_update_watermarks(crtc);
mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
+ intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex);
}
@@ -5309,8 +5292,6 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
struct drm_device *dev = crtc->dev;
struct drm_connector *connector;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_i915_gem_object *old_obj = intel_fb_obj(crtc->primary->fb);
- enum pipe pipe = to_intel_crtc(crtc)->pipe;
/* crtc should still be enabled when we disable it. */
WARN_ON(!crtc->enabled);
@@ -5318,14 +5299,7 @@ static void intel_crtc_disable(struct drm_crtc *crtc)
dev_priv->display.crtc_disable(crtc);
dev_priv->display.off(crtc);
- if (crtc->primary->fb) {
- mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(old_obj);
- i915_gem_track_fb(old_obj, NULL,
- INTEL_FRONTBUFFER_PRIMARY(pipe));
- mutex_unlock(&dev->struct_mutex);
- crtc->primary->fb = NULL;
- }
+ crtc->primary->funcs->disable_plane(crtc->primary);
/* Update computed state. */
list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
@@ -5382,25 +5356,25 @@ static void intel_connector_check_state(struct intel_connector *connector)
if (connector->mst_port)
return;
- WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
+ I915_STATE_WARN(connector->base.dpms == DRM_MODE_DPMS_OFF,
"wrong connector dpms state\n");
- WARN(connector->base.encoder != &encoder->base,
+ I915_STATE_WARN(connector->base.encoder != &encoder->base,
"active connector not linked to encoder\n");
if (encoder) {
- WARN(!encoder->connectors_active,
+ I915_STATE_WARN(!encoder->connectors_active,
"encoder->connectors_active not set\n");
encoder_enabled = encoder->get_hw_state(encoder, &pipe);
- WARN(!encoder_enabled, "encoder not enabled\n");
- if (WARN_ON(!encoder->base.crtc))
+ I915_STATE_WARN(!encoder_enabled, "encoder not enabled\n");
+ if (I915_STATE_WARN_ON(!encoder->base.crtc))
return;
crtc = encoder->base.crtc;
- WARN(!crtc->enabled, "crtc not enabled\n");
- WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
- WARN(pipe != to_intel_crtc(crtc)->pipe,
+ I915_STATE_WARN(!crtc->enabled, "crtc not enabled\n");
+ I915_STATE_WARN(!to_intel_crtc(crtc)->active, "crtc not active\n");
+ I915_STATE_WARN(pipe != to_intel_crtc(crtc)->pipe,
"encoder active on the wrong pipe\n");
}
}
@@ -5438,7 +5412,7 @@ bool intel_connector_get_hw_state(struct intel_connector *connector)
}
static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *pipe_B_crtc =
@@ -5479,7 +5453,7 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
return true;
case PIPE_C:
if (!pipe_has_enabled_pch(pipe_B_crtc) ||
- pipe_B_crtc->config.fdi_lanes <= 2) {
+ pipe_B_crtc->config->fdi_lanes <= 2) {
if (pipe_config->fdi_lanes > 2) {
DRM_DEBUG_KMS("invalid shared fdi lane config on pipe %c: %i lanes\n",
pipe_name(pipe), pipe_config->fdi_lanes);
@@ -5497,10 +5471,10 @@ static bool ironlake_check_fdi_lanes(struct drm_device *dev, enum pipe pipe,
#define RETRY 1
static int ironlake_fdi_compute_config(struct intel_crtc *intel_crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = intel_crtc->base.dev;
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
int lane, link_bw, fdi_dotclock;
bool setup_ok, needs_recompute = false;
@@ -5543,7 +5517,7 @@ retry:
}
static void hsw_compute_ips_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
pipe_config->ips_enabled = i915.enable_ips &&
hsw_crtc_supports_ips(crtc) &&
@@ -5551,11 +5525,11 @@ static void hsw_compute_ips_config(struct intel_crtc *crtc,
}
static int intel_crtc_compute_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
/* FIXME should check pixel clock limits on all platforms */
if (INTEL_INFO(dev)->gen < 4) {
@@ -5800,30 +5774,31 @@ static uint32_t i9xx_dpll_compute_fp(struct dpll *dpll)
}
static void i9xx_update_pll_dividers(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
intel_clock_t *reduced_clock)
{
struct drm_device *dev = crtc->base.dev;
u32 fp, fp2 = 0;
if (IS_PINEVIEW(dev)) {
- fp = pnv_dpll_compute_fp(&crtc->new_config->dpll);
+ fp = pnv_dpll_compute_fp(&crtc_state->dpll);
if (reduced_clock)
fp2 = pnv_dpll_compute_fp(reduced_clock);
} else {
- fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll);
+ fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
if (reduced_clock)
fp2 = i9xx_dpll_compute_fp(reduced_clock);
}
- crtc->new_config->dpll_hw_state.fp0 = fp;
+ crtc_state->dpll_hw_state.fp0 = fp;
crtc->lowfreq_avail = false;
if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
reduced_clock && i915.powersave) {
- crtc->new_config->dpll_hw_state.fp1 = fp2;
+ crtc_state->dpll_hw_state.fp1 = fp2;
crtc->lowfreq_avail = true;
} else {
- crtc->new_config->dpll_hw_state.fp1 = fp;
+ crtc_state->dpll_hw_state.fp1 = fp;
}
}
@@ -5876,7 +5851,7 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
int pipe = crtc->pipe;
- enum transcoder transcoder = crtc->config.cpu_transcoder;
+ enum transcoder transcoder = crtc->config->cpu_transcoder;
if (INTEL_INFO(dev)->gen >= 5) {
I915_WRITE(PIPE_DATA_M1(transcoder), TU_SIZE(m_n->tu) | m_n->gmch_m);
@@ -5888,7 +5863,7 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
* registers are not unnecessarily accessed).
*/
if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
- crtc->config.has_drrs) {
+ crtc->config->has_drrs) {
I915_WRITE(PIPE_DATA_M2(transcoder),
TU_SIZE(m2_n2->tu) | m2_n2->gmch_m);
I915_WRITE(PIPE_DATA_N2(transcoder), m2_n2->gmch_n);
@@ -5905,15 +5880,15 @@ static void intel_cpu_transcoder_set_m_n(struct intel_crtc *crtc,
void intel_dp_set_m_n(struct intel_crtc *crtc)
{
- if (crtc->config.has_pch_encoder)
- intel_pch_transcoder_set_m_n(crtc, &crtc->config.dp_m_n);
+ if (crtc->config->has_pch_encoder)
+ intel_pch_transcoder_set_m_n(crtc, &crtc->config->dp_m_n);
else
- intel_cpu_transcoder_set_m_n(crtc, &crtc->config.dp_m_n,
- &crtc->config.dp_m2_n2);
+ intel_cpu_transcoder_set_m_n(crtc, &crtc->config->dp_m_n,
+ &crtc->config->dp_m2_n2);
}
static void vlv_update_pll(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
u32 dpll, dpll_md;
@@ -5936,7 +5911,7 @@ static void vlv_update_pll(struct intel_crtc *crtc,
}
static void vlv_prepare_pll(struct intel_crtc *crtc,
- const struct intel_crtc_config *pipe_config)
+ const struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -5997,7 +5972,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW10(pipe),
0x00d0000f);
- if (crtc->config.has_dp_encoder) {
+ if (pipe_config->has_dp_encoder) {
/* Use SSC source */
if (pipe == PIPE_A)
vlv_dpio_write(dev_priv, pipe, VLV_PLL_DW5(pipe),
@@ -6027,7 +6002,7 @@ static void vlv_prepare_pll(struct intel_crtc *crtc,
}
static void chv_update_pll(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
pipe_config->dpll_hw_state.dpll = DPLL_SSC_REF_CLOCK_CHV |
DPLL_REFA_CLK_ENABLE_VLV | DPLL_VGA_MODE_DIS |
@@ -6040,7 +6015,7 @@ static void chv_update_pll(struct intel_crtc *crtc,
}
static void chv_prepare_pll(struct intel_crtc *crtc,
- const struct intel_crtc_config *pipe_config)
+ const struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6125,7 +6100,7 @@ void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
{
struct intel_crtc *crtc =
to_intel_crtc(intel_get_crtc_for_pipe(dev, pipe));
- struct intel_crtc_config pipe_config = {
+ struct intel_crtc_state pipe_config = {
.pixel_multiplier = 1,
.dpll = *dpll,
};
@@ -6158,6 +6133,7 @@ void vlv_force_pll_off(struct drm_device *dev, enum pipe pipe)
}
static void i9xx_update_pll(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
intel_clock_t *reduced_clock,
int num_connectors)
{
@@ -6165,9 +6141,9 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpll;
bool is_sdvo;
- struct dpll *clock = &crtc->new_config->dpll;
+ struct dpll *clock = &crtc_state->dpll;
- i9xx_update_pll_dividers(crtc, reduced_clock);
+ i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
is_sdvo = intel_pipe_will_have_type(crtc, INTEL_OUTPUT_SDVO) ||
intel_pipe_will_have_type(crtc, INTEL_OUTPUT_HDMI);
@@ -6180,14 +6156,14 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
dpll |= DPLLB_MODE_DAC_SERIAL;
if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
- dpll |= (crtc->new_config->pixel_multiplier - 1)
+ dpll |= (crtc_state->pixel_multiplier - 1)
<< SDVO_MULTIPLIER_SHIFT_HIRES;
}
if (is_sdvo)
dpll |= DPLL_SDVO_HIGH_SPEED;
- if (crtc->new_config->has_dp_encoder)
+ if (crtc_state->has_dp_encoder)
dpll |= DPLL_SDVO_HIGH_SPEED;
/* compute bitmask from p1 value */
@@ -6215,7 +6191,7 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
if (INTEL_INFO(dev)->gen >= 4)
dpll |= (6 << PLL_LOAD_PULSE_PHASE_SHIFT);
- if (crtc->new_config->sdvo_tv_clock)
+ if (crtc_state->sdvo_tv_clock)
dpll |= PLL_REF_INPUT_TVCLKINBC;
else if (intel_pipe_will_have_type(crtc, INTEL_OUTPUT_LVDS) &&
intel_panel_use_ssc(dev_priv) && num_connectors < 2)
@@ -6224,25 +6200,26 @@ static void i9xx_update_pll(struct intel_crtc *crtc,
dpll |= PLL_REF_INPUT_DREFCLK;
dpll |= DPLL_VCO_ENABLE;
- crtc->new_config->dpll_hw_state.dpll = dpll;
+ crtc_state->dpll_hw_state.dpll = dpll;
if (INTEL_INFO(dev)->gen >= 4) {
- u32 dpll_md = (crtc->new_config->pixel_multiplier - 1)
+ u32 dpll_md = (crtc_state->pixel_multiplier - 1)
<< DPLL_MD_UDI_MULTIPLIER_SHIFT;
- crtc->new_config->dpll_hw_state.dpll_md = dpll_md;
+ crtc_state->dpll_hw_state.dpll_md = dpll_md;
}
}
static void i8xx_update_pll(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
intel_clock_t *reduced_clock,
int num_connectors)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpll;
- struct dpll *clock = &crtc->new_config->dpll;
+ struct dpll *clock = &crtc_state->dpll;
- i9xx_update_pll_dividers(crtc, reduced_clock);
+ i9xx_update_pll_dividers(crtc, crtc_state, reduced_clock);
dpll = DPLL_VGA_MODE_DIS;
@@ -6267,7 +6244,7 @@ static void i8xx_update_pll(struct intel_crtc *crtc,
dpll |= PLL_REF_INPUT_DREFCLK;
dpll |= DPLL_VCO_ENABLE;
- crtc->new_config->dpll_hw_state.dpll = dpll;
+ crtc_state->dpll_hw_state.dpll = dpll;
}
static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
@@ -6275,9 +6252,9 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum pipe pipe = intel_crtc->pipe;
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
+ &intel_crtc->config->base.adjusted_mode;
uint32_t crtc_vtotal, crtc_vblank_end;
int vsyncshift = 0;
@@ -6335,12 +6312,12 @@ static void intel_set_pipe_timings(struct intel_crtc *intel_crtc)
* always be the user's requested size.
*/
I915_WRITE(PIPESRC(pipe),
- ((intel_crtc->config.pipe_src_w - 1) << 16) |
- (intel_crtc->config.pipe_src_h - 1));
+ ((intel_crtc->config->pipe_src_w - 1) << 16) |
+ (intel_crtc->config->pipe_src_h - 1));
}
static void intel_get_pipe_timings(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6348,56 +6325,56 @@ static void intel_get_pipe_timings(struct intel_crtc *crtc,
uint32_t tmp;
tmp = I915_READ(HTOTAL(cpu_transcoder));
- pipe_config->adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
- pipe_config->adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_hdisplay = (tmp & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_htotal = ((tmp >> 16) & 0xffff) + 1;
tmp = I915_READ(HBLANK(cpu_transcoder));
- pipe_config->adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
- pipe_config->adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_hblank_start = (tmp & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_hblank_end = ((tmp >> 16) & 0xffff) + 1;
tmp = I915_READ(HSYNC(cpu_transcoder));
- pipe_config->adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
- pipe_config->adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_hsync_start = (tmp & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_hsync_end = ((tmp >> 16) & 0xffff) + 1;
tmp = I915_READ(VTOTAL(cpu_transcoder));
- pipe_config->adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
- pipe_config->adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_vdisplay = (tmp & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_vtotal = ((tmp >> 16) & 0xffff) + 1;
tmp = I915_READ(VBLANK(cpu_transcoder));
- pipe_config->adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
- pipe_config->adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_vblank_start = (tmp & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_vblank_end = ((tmp >> 16) & 0xffff) + 1;
tmp = I915_READ(VSYNC(cpu_transcoder));
- pipe_config->adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
- pipe_config->adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_vsync_start = (tmp & 0xffff) + 1;
+ pipe_config->base.adjusted_mode.crtc_vsync_end = ((tmp >> 16) & 0xffff) + 1;
if (I915_READ(PIPECONF(cpu_transcoder)) & PIPECONF_INTERLACE_MASK) {
- pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
- pipe_config->adjusted_mode.crtc_vtotal += 1;
- pipe_config->adjusted_mode.crtc_vblank_end += 1;
+ pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_INTERLACE;
+ pipe_config->base.adjusted_mode.crtc_vtotal += 1;
+ pipe_config->base.adjusted_mode.crtc_vblank_end += 1;
}
tmp = I915_READ(PIPESRC(crtc->pipe));
pipe_config->pipe_src_h = (tmp & 0xffff) + 1;
pipe_config->pipe_src_w = ((tmp >> 16) & 0xffff) + 1;
- pipe_config->requested_mode.vdisplay = pipe_config->pipe_src_h;
- pipe_config->requested_mode.hdisplay = pipe_config->pipe_src_w;
+ pipe_config->base.mode.vdisplay = pipe_config->pipe_src_h;
+ pipe_config->base.mode.hdisplay = pipe_config->pipe_src_w;
}
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
- mode->hdisplay = pipe_config->adjusted_mode.crtc_hdisplay;
- mode->htotal = pipe_config->adjusted_mode.crtc_htotal;
- mode->hsync_start = pipe_config->adjusted_mode.crtc_hsync_start;
- mode->hsync_end = pipe_config->adjusted_mode.crtc_hsync_end;
+ mode->hdisplay = pipe_config->base.adjusted_mode.crtc_hdisplay;
+ mode->htotal = pipe_config->base.adjusted_mode.crtc_htotal;
+ mode->hsync_start = pipe_config->base.adjusted_mode.crtc_hsync_start;
+ mode->hsync_end = pipe_config->base.adjusted_mode.crtc_hsync_end;
- mode->vdisplay = pipe_config->adjusted_mode.crtc_vdisplay;
- mode->vtotal = pipe_config->adjusted_mode.crtc_vtotal;
- mode->vsync_start = pipe_config->adjusted_mode.crtc_vsync_start;
- mode->vsync_end = pipe_config->adjusted_mode.crtc_vsync_end;
+ mode->vdisplay = pipe_config->base.adjusted_mode.crtc_vdisplay;
+ mode->vtotal = pipe_config->base.adjusted_mode.crtc_vtotal;
+ mode->vsync_start = pipe_config->base.adjusted_mode.crtc_vsync_start;
+ mode->vsync_end = pipe_config->base.adjusted_mode.crtc_vsync_end;
- mode->flags = pipe_config->adjusted_mode.flags;
+ mode->flags = pipe_config->base.adjusted_mode.flags;
- mode->clock = pipe_config->adjusted_mode.crtc_clock;
- mode->flags |= pipe_config->adjusted_mode.flags;
+ mode->clock = pipe_config->base.adjusted_mode.crtc_clock;
+ mode->flags |= pipe_config->base.adjusted_mode.flags;
}
static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
@@ -6412,17 +6389,17 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
(intel_crtc->pipe == PIPE_B && dev_priv->quirks & QUIRK_PIPEB_FORCE))
pipeconf |= I915_READ(PIPECONF(intel_crtc->pipe)) & PIPECONF_ENABLE;
- if (intel_crtc->config.double_wide)
+ if (intel_crtc->config->double_wide)
pipeconf |= PIPECONF_DOUBLE_WIDE;
/* only g4x and later have fancy bpc/dither controls */
if (IS_G4X(dev) || IS_VALLEYVIEW(dev)) {
/* Bspec claims that we can't use dithering for 30bpp pipes. */
- if (intel_crtc->config.dither && intel_crtc->config.pipe_bpp != 30)
+ if (intel_crtc->config->dither && intel_crtc->config->pipe_bpp != 30)
pipeconf |= PIPECONF_DITHER_EN |
PIPECONF_DITHER_TYPE_SP;
- switch (intel_crtc->config.pipe_bpp) {
+ switch (intel_crtc->config->pipe_bpp) {
case 18:
pipeconf |= PIPECONF_6BPC;
break;
@@ -6447,7 +6424,7 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
}
}
- if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+ if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
if (INTEL_INFO(dev)->gen < 4 ||
intel_pipe_has_type(intel_crtc, INTEL_OUTPUT_SDVO))
pipeconf |= PIPECONF_INTERLACE_W_FIELD_INDICATION;
@@ -6456,14 +6433,15 @@ static void i9xx_set_pipeconf(struct intel_crtc *intel_crtc)
} else
pipeconf |= PIPECONF_PROGRESSIVE;
- if (IS_VALLEYVIEW(dev) && intel_crtc->config.limited_color_range)
+ if (IS_VALLEYVIEW(dev) && intel_crtc->config->limited_color_range)
pipeconf |= PIPECONF_COLOR_RANGE_SELECT;
I915_WRITE(PIPECONF(intel_crtc->pipe), pipeconf);
POSTING_READ(PIPECONF(intel_crtc->pipe));
}
-static int i9xx_crtc_compute_clock(struct intel_crtc *crtc)
+static int i9xx_crtc_compute_clock(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6495,7 +6473,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc)
if (is_dsi)
return 0;
- if (!crtc->new_config->clock_set) {
+ if (!crtc_state->clock_set) {
refclk = i9xx_get_refclk(crtc, num_connectors);
/*
@@ -6506,7 +6484,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc)
*/
limit = intel_limit(crtc, refclk);
ok = dev_priv->display.find_dpll(limit, crtc,
- crtc->new_config->port_clock,
+ crtc_state->port_clock,
refclk, NULL, &clock);
if (!ok) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
@@ -6527,23 +6505,23 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc)
&reduced_clock);
}
/* Compat-code for transition, will disappear. */
- crtc->new_config->dpll.n = clock.n;
- crtc->new_config->dpll.m1 = clock.m1;
- crtc->new_config->dpll.m2 = clock.m2;
- crtc->new_config->dpll.p1 = clock.p1;
- crtc->new_config->dpll.p2 = clock.p2;
+ crtc_state->dpll.n = clock.n;
+ crtc_state->dpll.m1 = clock.m1;
+ crtc_state->dpll.m2 = clock.m2;
+ crtc_state->dpll.p1 = clock.p1;
+ crtc_state->dpll.p2 = clock.p2;
}
if (IS_GEN2(dev)) {
- i8xx_update_pll(crtc,
+ i8xx_update_pll(crtc, crtc_state,
has_reduced_clock ? &reduced_clock : NULL,
num_connectors);
} else if (IS_CHERRYVIEW(dev)) {
- chv_update_pll(crtc, crtc->new_config);
+ chv_update_pll(crtc, crtc_state);
} else if (IS_VALLEYVIEW(dev)) {
- vlv_update_pll(crtc, crtc->new_config);
+ vlv_update_pll(crtc, crtc_state);
} else {
- i9xx_update_pll(crtc,
+ i9xx_update_pll(crtc, crtc_state,
has_reduced_clock ? &reduced_clock : NULL,
num_connectors);
}
@@ -6552,7 +6530,7 @@ static int i9xx_crtc_compute_clock(struct intel_crtc *crtc)
}
static void i9xx_get_pfit_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6582,7 +6560,7 @@ static void i9xx_get_pfit_config(struct intel_crtc *crtc,
}
static void vlv_crtc_clock_get(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6611,8 +6589,9 @@ static void vlv_crtc_clock_get(struct intel_crtc *crtc,
pipe_config->port_clock = clock.dot / 5;
}
-static void i9xx_get_plane_config(struct intel_crtc *crtc,
- struct intel_plane_config *plane_config)
+static void
+i9xx_get_initial_plane_config(struct intel_crtc *crtc,
+ struct intel_initial_plane_config *plane_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6620,27 +6599,30 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
int pipe = crtc->pipe, plane = crtc->plane;
int fourcc, pixel_format;
int aligned_height;
+ struct drm_framebuffer *fb;
+ struct intel_framebuffer *intel_fb;
- crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
- if (!crtc->base.primary->fb) {
+ intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+ if (!intel_fb) {
DRM_DEBUG_KMS("failed to alloc fb\n");
return;
}
+ fb = &intel_fb->base;
+
val = I915_READ(DSPCNTR(plane));
if (INTEL_INFO(dev)->gen >= 4)
if (val & DISPPLANE_TILED)
- plane_config->tiled = true;
+ plane_config->tiling = I915_TILING_X;
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
- fourcc = intel_format_to_fourcc(pixel_format);
- crtc->base.primary->fb->pixel_format = fourcc;
- crtc->base.primary->fb->bits_per_pixel =
- drm_format_plane_cpp(fourcc, 0) * 8;
+ fourcc = i9xx_format_to_fourcc(pixel_format);
+ fb->pixel_format = fourcc;
+ fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
if (INTEL_INFO(dev)->gen >= 4) {
- if (plane_config->tiled)
+ if (plane_config->tiling)
offset = I915_READ(DSPTILEOFF(plane));
else
offset = I915_READ(DSPLINOFF(plane));
@@ -6651,29 +6633,27 @@ static void i9xx_get_plane_config(struct intel_crtc *crtc,
plane_config->base = base;
val = I915_READ(PIPESRC(pipe));
- crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
- crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
+ fb->width = ((val >> 16) & 0xfff) + 1;
+ fb->height = ((val >> 0) & 0xfff) + 1;
val = I915_READ(DSPSTRIDE(pipe));
- crtc->base.primary->fb->pitches[0] = val & 0xffffffc0;
+ fb->pitches[0] = val & 0xffffffc0;
- aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
- plane_config->tiled);
+ aligned_height = intel_fb_align_height(dev, fb->height,
+ plane_config->tiling);
- plane_config->size = PAGE_ALIGN(crtc->base.primary->fb->pitches[0] *
- aligned_height);
+ plane_config->size = fb->pitches[0] * aligned_height;
- DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
- pipe, plane, crtc->base.primary->fb->width,
- crtc->base.primary->fb->height,
- crtc->base.primary->fb->bits_per_pixel, base,
- crtc->base.primary->fb->pitches[0],
+ DRM_DEBUG_KMS("pipe/plane %c/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+ pipe_name(pipe), plane, fb->width, fb->height,
+ fb->bits_per_pixel, base, fb->pitches[0],
plane_config->size);
+ crtc->base.primary->fb = fb;
}
static void chv_crtc_clock_get(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -6703,7 +6683,7 @@ static void chv_crtc_clock_get(struct intel_crtc *crtc,
}
static bool i9xx_get_pipe_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7183,7 +7163,7 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc)
val = 0;
- switch (intel_crtc->config.pipe_bpp) {
+ switch (intel_crtc->config->pipe_bpp) {
case 18:
val |= PIPECONF_6BPC;
break;
@@ -7201,15 +7181,15 @@ static void ironlake_set_pipeconf(struct drm_crtc *crtc)
BUG();
}
- if (intel_crtc->config.dither)
+ if (intel_crtc->config->dither)
val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
- if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+ if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
val |= PIPECONF_INTERLACED_ILK;
else
val |= PIPECONF_PROGRESSIVE;
- if (intel_crtc->config.limited_color_range)
+ if (intel_crtc->config->limited_color_range)
val |= PIPECONF_COLOR_RANGE_SELECT;
I915_WRITE(PIPECONF(pipe), val);
@@ -7238,7 +7218,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc)
* consideration.
*/
- if (intel_crtc->config.limited_color_range)
+ if (intel_crtc->config->limited_color_range)
coeff = ((235 - 16) * (1 << 12) / 255) & 0xff8; /* 0.xxx... */
/*
@@ -7262,7 +7242,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc)
if (INTEL_INFO(dev)->gen > 6) {
uint16_t postoff = 0;
- if (intel_crtc->config.limited_color_range)
+ if (intel_crtc->config->limited_color_range)
postoff = (16 * (1 << 12) / 255) & 0x1fff;
I915_WRITE(PIPE_CSC_POSTOFF_HI(pipe), postoff);
@@ -7273,7 +7253,7 @@ static void intel_set_pipe_csc(struct drm_crtc *crtc)
} else {
uint32_t mode = CSC_MODE_YUV_TO_RGB;
- if (intel_crtc->config.limited_color_range)
+ if (intel_crtc->config->limited_color_range)
mode |= CSC_BLACK_SCREEN_OFFSET;
I915_WRITE(PIPE_CSC_MODE(pipe), mode);
@@ -7286,15 +7266,15 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
enum pipe pipe = intel_crtc->pipe;
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
uint32_t val;
val = 0;
- if (IS_HASWELL(dev) && intel_crtc->config.dither)
+ if (IS_HASWELL(dev) && intel_crtc->config->dither)
val |= (PIPECONF_DITHER_EN | PIPECONF_DITHER_TYPE_SP);
- if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
+ if (intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE)
val |= PIPECONF_INTERLACED_ILK;
else
val |= PIPECONF_PROGRESSIVE;
@@ -7308,7 +7288,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
if (IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
val = 0;
- switch (intel_crtc->config.pipe_bpp) {
+ switch (intel_crtc->config->pipe_bpp) {
case 18:
val |= PIPEMISC_DITHER_6_BPC;
break;
@@ -7326,7 +7306,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
BUG();
}
- if (intel_crtc->config.dither)
+ if (intel_crtc->config->dither)
val |= PIPEMISC_DITHER_ENABLE | PIPEMISC_DITHER_TYPE_SP;
I915_WRITE(PIPEMISC(pipe), val);
@@ -7334,6 +7314,7 @@ static void haswell_set_pipeconf(struct drm_crtc *crtc)
}
static bool ironlake_compute_clocks(struct drm_crtc *crtc,
+ struct intel_crtc_state *crtc_state,
intel_clock_t *clock,
bool *has_reduced_clock,
intel_clock_t *reduced_clock)
@@ -7356,7 +7337,7 @@ static bool ironlake_compute_clocks(struct drm_crtc *crtc,
*/
limit = intel_limit(intel_crtc, refclk);
ret = dev_priv->display.find_dpll(limit, intel_crtc,
- intel_crtc->new_config->port_clock,
+ crtc_state->port_clock,
refclk, NULL, clock);
if (!ret)
return false;
@@ -7395,6 +7376,7 @@ static bool ironlake_needs_fb_cb_tune(struct dpll *dpll, int factor)
}
static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
+ struct intel_crtc_state *crtc_state,
u32 *fp,
intel_clock_t *reduced_clock, u32 *fp2)
{
@@ -7432,10 +7414,10 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
dev_priv->vbt.lvds_ssc_freq == 100000) ||
(HAS_PCH_IBX(dev) && intel_is_dual_link_lvds(dev)))
factor = 25;
- } else if (intel_crtc->new_config->sdvo_tv_clock)
+ } else if (crtc_state->sdvo_tv_clock)
factor = 20;
- if (ironlake_needs_fb_cb_tune(&intel_crtc->new_config->dpll, factor))
+ if (ironlake_needs_fb_cb_tune(&crtc_state->dpll, factor))
*fp |= FP_CB_TUNE;
if (fp2 && (reduced_clock->m < factor * reduced_clock->n))
@@ -7448,20 +7430,20 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
else
dpll |= DPLLB_MODE_DAC_SERIAL;
- dpll |= (intel_crtc->new_config->pixel_multiplier - 1)
+ dpll |= (crtc_state->pixel_multiplier - 1)
<< PLL_REF_SDVO_HDMI_MULTIPLIER_SHIFT;
if (is_sdvo)
dpll |= DPLL_SDVO_HIGH_SPEED;
- if (intel_crtc->new_config->has_dp_encoder)
+ if (crtc_state->has_dp_encoder)
dpll |= DPLL_SDVO_HIGH_SPEED;
/* compute bitmask from p1 value */
- dpll |= (1 << (intel_crtc->new_config->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
+ dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA01_P1_POST_DIV_SHIFT;
/* also FPA1 */
- dpll |= (1 << (intel_crtc->new_config->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
+ dpll |= (1 << (crtc_state->dpll.p1 - 1)) << DPLL_FPA1_P1_POST_DIV_SHIFT;
- switch (intel_crtc->new_config->dpll.p2) {
+ switch (crtc_state->dpll.p2) {
case 5:
dpll |= DPLL_DAC_SERIAL_P2_CLOCK_DIV_5;
break;
@@ -7484,7 +7466,8 @@ static uint32_t ironlake_compute_dpll(struct intel_crtc *intel_crtc,
return dpll | DPLL_VCO_ENABLE;
}
-static int ironlake_crtc_compute_clock(struct intel_crtc *crtc)
+static int ironlake_crtc_compute_clock(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state)
{
struct drm_device *dev = crtc->base.dev;
intel_clock_t clock, reduced_clock;
@@ -7498,39 +7481,39 @@ static int ironlake_crtc_compute_clock(struct intel_crtc *crtc)
WARN(!(HAS_PCH_IBX(dev) || HAS_PCH_CPT(dev)),
"Unexpected PCH type %d\n", INTEL_PCH_TYPE(dev));
- ok = ironlake_compute_clocks(&crtc->base, &clock,
+ ok = ironlake_compute_clocks(&crtc->base, crtc_state, &clock,
&has_reduced_clock, &reduced_clock);
- if (!ok && !crtc->new_config->clock_set) {
+ if (!ok && !crtc_state->clock_set) {
DRM_ERROR("Couldn't find PLL settings for mode!\n");
return -EINVAL;
}
/* Compat-code for transition, will disappear. */
- if (!crtc->new_config->clock_set) {
- crtc->new_config->dpll.n = clock.n;
- crtc->new_config->dpll.m1 = clock.m1;
- crtc->new_config->dpll.m2 = clock.m2;
- crtc->new_config->dpll.p1 = clock.p1;
- crtc->new_config->dpll.p2 = clock.p2;
+ if (!crtc_state->clock_set) {
+ crtc_state->dpll.n = clock.n;
+ crtc_state->dpll.m1 = clock.m1;
+ crtc_state->dpll.m2 = clock.m2;
+ crtc_state->dpll.p1 = clock.p1;
+ crtc_state->dpll.p2 = clock.p2;
}
/* CPU eDP is the only output that doesn't need a PCH PLL of its own. */
- if (crtc->new_config->has_pch_encoder) {
- fp = i9xx_dpll_compute_fp(&crtc->new_config->dpll);
+ if (crtc_state->has_pch_encoder) {
+ fp = i9xx_dpll_compute_fp(&crtc_state->dpll);
if (has_reduced_clock)
fp2 = i9xx_dpll_compute_fp(&reduced_clock);
- dpll = ironlake_compute_dpll(crtc,
+ dpll = ironlake_compute_dpll(crtc, crtc_state,
&fp, &reduced_clock,
has_reduced_clock ? &fp2 : NULL);
- crtc->new_config->dpll_hw_state.dpll = dpll;
- crtc->new_config->dpll_hw_state.fp0 = fp;
+ crtc_state->dpll_hw_state.dpll = dpll;
+ crtc_state->dpll_hw_state.fp0 = fp;
if (has_reduced_clock)
- crtc->new_config->dpll_hw_state.fp1 = fp2;
+ crtc_state->dpll_hw_state.fp1 = fp2;
else
- crtc->new_config->dpll_hw_state.fp1 = fp;
+ crtc_state->dpll_hw_state.fp1 = fp;
- pll = intel_get_shared_dpll(crtc);
+ pll = intel_get_shared_dpll(crtc, crtc_state);
if (pll == NULL) {
DRM_DEBUG_DRIVER("failed to find PLL for pipe %c\n",
pipe_name(crtc->pipe));
@@ -7584,7 +7567,7 @@ static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
* registers are not unnecessarily read).
*/
if (m2_n2 && INTEL_INFO(dev)->gen < 8 &&
- crtc->config.has_drrs) {
+ crtc->config->has_drrs) {
m2_n2->link_m = I915_READ(PIPE_LINK_M2(transcoder));
m2_n2->link_n = I915_READ(PIPE_LINK_N2(transcoder));
m2_n2->gmch_m = I915_READ(PIPE_DATA_M2(transcoder))
@@ -7605,9 +7588,9 @@ static void intel_cpu_transcoder_get_m_n(struct intel_crtc *crtc,
}
void intel_dp_get_m_n(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
- if (crtc->config.has_pch_encoder)
+ if (pipe_config->has_pch_encoder)
intel_pch_transcoder_get_m_n(crtc, &pipe_config->dp_m_n);
else
intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
@@ -7616,14 +7599,14 @@ void intel_dp_get_m_n(struct intel_crtc *crtc,
}
static void ironlake_get_fdi_m_n_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
intel_cpu_transcoder_get_m_n(crtc, pipe_config->cpu_transcoder,
&pipe_config->fdi_m_n, NULL);
}
static void skylake_get_pfit_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7638,8 +7621,80 @@ static void skylake_get_pfit_config(struct intel_crtc *crtc,
}
}
+static void
+skylake_get_initial_plane_config(struct intel_crtc *crtc,
+ struct intel_initial_plane_config *plane_config)
+{
+ struct drm_device *dev = crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 val, base, offset, stride_mult;
+ int pipe = crtc->pipe;
+ int fourcc, pixel_format;
+ int aligned_height;
+ struct drm_framebuffer *fb;
+ struct intel_framebuffer *intel_fb;
+
+ intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+ if (!intel_fb) {
+ DRM_DEBUG_KMS("failed to alloc fb\n");
+ return;
+ }
+
+ fb = &intel_fb->base;
+
+ val = I915_READ(PLANE_CTL(pipe, 0));
+ if (val & PLANE_CTL_TILED_MASK)
+ plane_config->tiling = I915_TILING_X;
+
+ pixel_format = val & PLANE_CTL_FORMAT_MASK;
+ fourcc = skl_format_to_fourcc(pixel_format,
+ val & PLANE_CTL_ORDER_RGBX,
+ val & PLANE_CTL_ALPHA_MASK);
+ fb->pixel_format = fourcc;
+ fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
+
+ base = I915_READ(PLANE_SURF(pipe, 0)) & 0xfffff000;
+ plane_config->base = base;
+
+ offset = I915_READ(PLANE_OFFSET(pipe, 0));
+
+ val = I915_READ(PLANE_SIZE(pipe, 0));
+ fb->height = ((val >> 16) & 0xfff) + 1;
+ fb->width = ((val >> 0) & 0x1fff) + 1;
+
+ val = I915_READ(PLANE_STRIDE(pipe, 0));
+ switch (plane_config->tiling) {
+ case I915_TILING_NONE:
+ stride_mult = 64;
+ break;
+ case I915_TILING_X:
+ stride_mult = 512;
+ break;
+ default:
+ MISSING_CASE(plane_config->tiling);
+ goto error;
+ }
+ fb->pitches[0] = (val & 0x3ff) * stride_mult;
+
+ aligned_height = intel_fb_align_height(dev, fb->height,
+ plane_config->tiling);
+
+ plane_config->size = fb->pitches[0] * aligned_height;
+
+ DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+ pipe_name(pipe), fb->width, fb->height,
+ fb->bits_per_pixel, base, fb->pitches[0],
+ plane_config->size);
+
+ crtc->base.primary->fb = fb;
+ return;
+
+error:
+ kfree(fb);
+}
+
static void ironlake_get_pfit_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7662,68 +7717,71 @@ static void ironlake_get_pfit_config(struct intel_crtc *crtc,
}
}
-static void ironlake_get_plane_config(struct intel_crtc *crtc,
- struct intel_plane_config *plane_config)
+static void
+ironlake_get_initial_plane_config(struct intel_crtc *crtc,
+ struct intel_initial_plane_config *plane_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
u32 val, base, offset;
- int pipe = crtc->pipe, plane = crtc->plane;
+ int pipe = crtc->pipe;
int fourcc, pixel_format;
int aligned_height;
+ struct drm_framebuffer *fb;
+ struct intel_framebuffer *intel_fb;
- crtc->base.primary->fb = kzalloc(sizeof(struct intel_framebuffer), GFP_KERNEL);
- if (!crtc->base.primary->fb) {
+ intel_fb = kzalloc(sizeof(*intel_fb), GFP_KERNEL);
+ if (!intel_fb) {
DRM_DEBUG_KMS("failed to alloc fb\n");
return;
}
- val = I915_READ(DSPCNTR(plane));
+ fb = &intel_fb->base;
+
+ val = I915_READ(DSPCNTR(pipe));
if (INTEL_INFO(dev)->gen >= 4)
if (val & DISPPLANE_TILED)
- plane_config->tiled = true;
+ plane_config->tiling = I915_TILING_X;
pixel_format = val & DISPPLANE_PIXFORMAT_MASK;
- fourcc = intel_format_to_fourcc(pixel_format);
- crtc->base.primary->fb->pixel_format = fourcc;
- crtc->base.primary->fb->bits_per_pixel =
- drm_format_plane_cpp(fourcc, 0) * 8;
+ fourcc = i9xx_format_to_fourcc(pixel_format);
+ fb->pixel_format = fourcc;
+ fb->bits_per_pixel = drm_format_plane_cpp(fourcc, 0) * 8;
- base = I915_READ(DSPSURF(plane)) & 0xfffff000;
+ base = I915_READ(DSPSURF(pipe)) & 0xfffff000;
if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
- offset = I915_READ(DSPOFFSET(plane));
+ offset = I915_READ(DSPOFFSET(pipe));
} else {
- if (plane_config->tiled)
- offset = I915_READ(DSPTILEOFF(plane));
+ if (plane_config->tiling)
+ offset = I915_READ(DSPTILEOFF(pipe));
else
- offset = I915_READ(DSPLINOFF(plane));
+ offset = I915_READ(DSPLINOFF(pipe));
}
plane_config->base = base;
val = I915_READ(PIPESRC(pipe));
- crtc->base.primary->fb->width = ((val >> 16) & 0xfff) + 1;
- crtc->base.primary->fb->height = ((val >> 0) & 0xfff) + 1;
+ fb->width = ((val >> 16) & 0xfff) + 1;
+ fb->height = ((val >> 0) & 0xfff) + 1;
val = I915_READ(DSPSTRIDE(pipe));
- crtc->base.primary->fb->pitches[0] = val & 0xffffffc0;
+ fb->pitches[0] = val & 0xffffffc0;
- aligned_height = intel_align_height(dev, crtc->base.primary->fb->height,
- plane_config->tiled);
+ aligned_height = intel_fb_align_height(dev, fb->height,
+ plane_config->tiling);
- plane_config->size = PAGE_ALIGN(crtc->base.primary->fb->pitches[0] *
- aligned_height);
+ plane_config->size = fb->pitches[0] * aligned_height;
- DRM_DEBUG_KMS("pipe/plane %d/%d with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
- pipe, plane, crtc->base.primary->fb->width,
- crtc->base.primary->fb->height,
- crtc->base.primary->fb->bits_per_pixel, base,
- crtc->base.primary->fb->pitches[0],
+ DRM_DEBUG_KMS("pipe %c with fb: size=%dx%d@%d, offset=%x, pitch %d, size 0x%x\n",
+ pipe_name(pipe), fb->width, fb->height,
+ fb->bits_per_pixel, base, fb->pitches[0],
plane_config->size);
+
+ crtc->base.primary->fb = fb;
}
static bool ironlake_get_pipe_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -7810,24 +7868,24 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
struct intel_crtc *crtc;
for_each_intel_crtc(dev, crtc)
- WARN(crtc->active, "CRTC for pipe %c enabled\n",
+ I915_STATE_WARN(crtc->active, "CRTC for pipe %c enabled\n",
pipe_name(crtc->pipe));
- WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
- WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
- WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
- WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
- WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
- WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
+ I915_STATE_WARN(I915_READ(HSW_PWR_WELL_DRIVER), "Power well on\n");
+ I915_STATE_WARN(I915_READ(SPLL_CTL) & SPLL_PLL_ENABLE, "SPLL enabled\n");
+ I915_STATE_WARN(I915_READ(WRPLL_CTL1) & WRPLL_PLL_ENABLE, "WRPLL1 enabled\n");
+ I915_STATE_WARN(I915_READ(WRPLL_CTL2) & WRPLL_PLL_ENABLE, "WRPLL2 enabled\n");
+ I915_STATE_WARN(I915_READ(PCH_PP_STATUS) & PP_ON, "Panel power on\n");
+ I915_STATE_WARN(I915_READ(BLC_PWM_CPU_CTL2) & BLM_PWM_ENABLE,
"CPU PWM1 enabled\n");
if (IS_HASWELL(dev))
- WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
+ I915_STATE_WARN(I915_READ(HSW_BLC_PWM2_CTL) & BLM_PWM_ENABLE,
"CPU PWM2 enabled\n");
- WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
+ I915_STATE_WARN(I915_READ(BLC_PWM_PCH_CTL1) & BLM_PCH_PWM_ENABLE,
"PCH PWM1 enabled\n");
- WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
+ I915_STATE_WARN(I915_READ(UTIL_PIN_CTL) & UTIL_PIN_ENABLE,
"Utility pin enabled\n");
- WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
+ I915_STATE_WARN(I915_READ(PCH_GTC_CTL) & PCH_GTC_ENABLE, "PCH GTC enabled\n");
/*
* In theory we can still leave IRQs enabled, as long as only the HPD
@@ -7835,7 +7893,7 @@ static void assert_can_disable_lcpll(struct drm_i915_private *dev_priv)
* gen-specific and since we only disable LCPLL after we fully disable
* the interrupts, the check below should be enough.
*/
- WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
+ I915_STATE_WARN(intel_irqs_enabled(dev_priv), "IRQs enabled\n");
}
static uint32_t hsw_read_dcomp(struct drm_i915_private *dev_priv)
@@ -7933,19 +7991,8 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
/*
* Make sure we're not on PC8 state before disabling PC8, otherwise
* we'll hang the machine. To prevent PC8 state, just enable force_wake.
- *
- * The other problem is that hsw_restore_lcpll() is called as part of
- * the runtime PM resume sequence, so we can't just call
- * gen6_gt_force_wake_get() because that function calls
- * intel_runtime_pm_get(), and we can't change the runtime PM refcount
- * while we are on the resume sequence. So to solve this problem we have
- * to call special forcewake code that doesn't touch runtime PM and
- * doesn't enable the forcewake delayed work.
*/
- spin_lock_irq(&dev_priv->uncore.lock);
- if (dev_priv->uncore.forcewake_count++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
- spin_unlock_irq(&dev_priv->uncore.lock);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
if (val & LCPLL_POWER_DOWN_ALLOW) {
val &= ~LCPLL_POWER_DOWN_ALLOW;
@@ -7975,11 +8022,7 @@ static void hsw_restore_lcpll(struct drm_i915_private *dev_priv)
DRM_ERROR("Switching back to LCPLL failed\n");
}
- /* See the big comment above. */
- spin_lock_irq(&dev_priv->uncore.lock);
- if (--dev_priv->uncore.forcewake_count == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
- spin_unlock_irq(&dev_priv->uncore.lock);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
/*
@@ -8041,9 +8084,10 @@ void hsw_disable_pc8(struct drm_i915_private *dev_priv)
intel_prepare_ddi(dev);
}
-static int haswell_crtc_compute_clock(struct intel_crtc *crtc)
+static int haswell_crtc_compute_clock(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state)
{
- if (!intel_ddi_pll_select(crtc))
+ if (!intel_ddi_pll_select(crtc, crtc_state))
return -EINVAL;
crtc->lowfreq_avail = false;
@@ -8053,14 +8097,23 @@ static int haswell_crtc_compute_clock(struct intel_crtc *crtc)
static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
- u32 temp;
+ u32 temp, dpll_ctl1;
temp = I915_READ(DPLL_CTRL2) & DPLL_CTRL2_DDI_CLK_SEL_MASK(port);
pipe_config->ddi_pll_sel = temp >> (port * 3 + 1);
switch (pipe_config->ddi_pll_sel) {
+ case SKL_DPLL0:
+ /*
+ * On SKL the eDP DPLL (DPLL0 as we don't use SSC) is not part
+ * of the shared DPLL framework and thus needs to be read out
+ * separately
+ */
+ dpll_ctl1 = I915_READ(DPLL_CTRL1);
+ pipe_config->dpll_hw_state.ctrl1 = dpll_ctl1 & 0x3f;
+ break;
case SKL_DPLL1:
pipe_config->shared_dpll = DPLL_ID_SKL_DPLL1;
break;
@@ -8075,7 +8128,7 @@ static void skylake_get_ddi_pll(struct drm_i915_private *dev_priv,
static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
enum port port,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
pipe_config->ddi_pll_sel = I915_READ(PORT_CLK_SEL(port));
@@ -8090,7 +8143,7 @@ static void haswell_get_ddi_pll(struct drm_i915_private *dev_priv,
}
static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8132,7 +8185,7 @@ static void haswell_get_ddi_port_state(struct intel_crtc *crtc,
}
static bool haswell_get_pipe_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8286,7 +8339,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
cntl |= CURSOR_MODE_256_ARGB_AX;
break;
default:
- WARN_ON(1);
+ MISSING_CASE(intel_crtc->cursor_width);
return;
}
cntl |= pipe << 28; /* Connect to correct pipe */
@@ -8295,7 +8348,7 @@ static void i9xx_update_cursor(struct drm_crtc *crtc, u32 base)
cntl |= CURSOR_PIPE_CSC_ENABLE;
}
- if (to_intel_plane(crtc->cursor)->rotation == BIT(DRM_ROTATE_180))
+ if (crtc->cursor->state->rotation == BIT(DRM_ROTATE_180))
cntl |= CURSOR_ROTATE_180;
if (intel_crtc->cursor_cntl != cntl) {
@@ -8326,10 +8379,10 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
if (on)
base = intel_crtc->cursor_addr;
- if (x >= intel_crtc->config.pipe_src_w)
+ if (x >= intel_crtc->config->pipe_src_w)
base = 0;
- if (y >= intel_crtc->config.pipe_src_h)
+ if (y >= intel_crtc->config->pipe_src_h)
base = 0;
if (x < 0) {
@@ -8357,7 +8410,7 @@ static void intel_crtc_update_cursor(struct drm_crtc *crtc,
/* ILK+ do this automagically */
if (HAS_GMCH_DISPLAY(dev) &&
- to_intel_plane(crtc->cursor)->rotation == BIT(DRM_ROTATE_180)) {
+ crtc->cursor->state->rotation == BIT(DRM_ROTATE_180)) {
base += (intel_crtc->cursor_height *
intel_crtc->cursor_width - 1) * 4;
}
@@ -8405,109 +8458,6 @@ static bool cursor_size_ok(struct drm_device *dev,
return true;
}
-static int intel_crtc_cursor_set_obj(struct drm_crtc *crtc,
- struct drm_i915_gem_object *obj,
- uint32_t width, uint32_t height)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = to_i915(dev);
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum pipe pipe = intel_crtc->pipe;
- unsigned old_width;
- uint32_t addr;
- int ret;
-
- /* if we want to turn off the cursor ignore width and height */
- if (!obj) {
- DRM_DEBUG_KMS("cursor off\n");
- addr = 0;
- mutex_lock(&dev->struct_mutex);
- goto finish;
- }
-
- /* we only need to pin inside GTT if cursor is non-phy */
- mutex_lock(&dev->struct_mutex);
- if (!INTEL_INFO(dev)->cursor_needs_physical) {
- unsigned alignment;
-
- /*
- * Global gtt pte registers are special registers which actually
- * forward writes to a chunk of system memory. Which means that
- * there is no risk that the register values disappear as soon
- * as we call intel_runtime_pm_put(), so it is correct to wrap
- * only the pin/unpin/fence and not more.
- */
- intel_runtime_pm_get(dev_priv);
-
- /* Note that the w/a also requires 2 PTE of padding following
- * the bo. We currently fill all unused PTE with the shadow
- * page and so we should always have valid PTE following the
- * cursor preventing the VT-d warning.
- */
- alignment = 0;
- if (need_vtd_wa(dev))
- alignment = 64*1024;
-
- ret = i915_gem_object_pin_to_display_plane(obj, alignment, NULL);
- if (ret) {
- DRM_DEBUG_KMS("failed to move cursor bo into the GTT\n");
- intel_runtime_pm_put(dev_priv);
- goto fail_locked;
- }
-
- ret = i915_gem_object_put_fence(obj);
- if (ret) {
- DRM_DEBUG_KMS("failed to release fence for cursor");
- intel_runtime_pm_put(dev_priv);
- goto fail_unpin;
- }
-
- addr = i915_gem_obj_ggtt_offset(obj);
-
- intel_runtime_pm_put(dev_priv);
- } else {
- int align = IS_I830(dev) ? 16 * 1024 : 256;
- ret = i915_gem_object_attach_phys(obj, align);
- if (ret) {
- DRM_DEBUG_KMS("failed to attach phys object\n");
- goto fail_locked;
- }
- addr = obj->phys_handle->busaddr;
- }
-
- finish:
- if (intel_crtc->cursor_bo) {
- if (!INTEL_INFO(dev)->cursor_needs_physical)
- i915_gem_object_unpin_from_display_plane(intel_crtc->cursor_bo);
- }
-
- i915_gem_track_fb(intel_crtc->cursor_bo, obj,
- INTEL_FRONTBUFFER_CURSOR(pipe));
- mutex_unlock(&dev->struct_mutex);
-
- old_width = intel_crtc->cursor_width;
-
- intel_crtc->cursor_addr = addr;
- intel_crtc->cursor_bo = obj;
- intel_crtc->cursor_width = width;
- intel_crtc->cursor_height = height;
-
- if (intel_crtc->active) {
- if (old_width != width)
- intel_update_watermarks(crtc);
- intel_crtc_update_cursor(crtc, intel_crtc->cursor_bo != NULL);
-
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_CURSOR(pipe));
- }
-
- return 0;
-fail_unpin:
- i915_gem_object_unpin_from_display_plane(obj);
-fail_locked:
- mutex_unlock(&dev->struct_mutex);
- return ret;
-}
-
static void intel_crtc_gamma_set(struct drm_crtc *crtc, u16 *red, u16 *green,
u16 *blue, uint32_t start, uint32_t size)
{
@@ -8730,7 +8680,7 @@ retry:
intel_crtc = to_intel_crtc(crtc);
intel_crtc->new_enabled = true;
- intel_crtc->new_config = &intel_crtc->config;
+ intel_crtc->new_config = intel_crtc->config;
old->dpms_mode = connector->dpms;
old->load_detect_temp = true;
old->release_fb = NULL;
@@ -8771,7 +8721,7 @@ retry:
fail:
intel_crtc->new_enabled = crtc->enabled;
if (intel_crtc->new_enabled)
- intel_crtc->new_config = &intel_crtc->config;
+ intel_crtc->new_config = intel_crtc->config;
else
intel_crtc->new_config = NULL;
fail_unlock:
@@ -8817,7 +8767,7 @@ void intel_release_load_detect_pipe(struct drm_connector *connector,
}
static int i9xx_pll_refclk(struct drm_device *dev,
- const struct intel_crtc_config *pipe_config)
+ const struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpll = pipe_config->dpll_hw_state.dpll;
@@ -8834,7 +8784,7 @@ static int i9xx_pll_refclk(struct drm_device *dev,
/* Returns the clock of the currently programmed mode of the given pipe. */
static void i9xx_crtc_clock_get(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -8941,7 +8891,7 @@ int intel_dotclock_calculate(int link_freq,
}
static void ironlake_pch_clock_get(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
@@ -8954,7 +8904,7 @@ static void ironlake_pch_clock_get(struct intel_crtc *crtc,
* agree once we know their relationship in the encoder's
* get_config() function.
*/
- pipe_config->adjusted_mode.crtc_clock =
+ pipe_config->base.adjusted_mode.crtc_clock =
intel_dotclock_calculate(intel_fdi_link_freq(dev) * 10000,
&pipe_config->fdi_m_n);
}
@@ -8965,9 +8915,9 @@ struct drm_display_mode *intel_crtc_mode_get(struct drm_device *dev,
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum transcoder cpu_transcoder = intel_crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = intel_crtc->config->cpu_transcoder;
struct drm_display_mode *mode;
- struct intel_crtc_config pipe_config;
+ struct intel_crtc_state pipe_config;
int htot = I915_READ(HTOTAL(cpu_transcoder));
int hsync = I915_READ(HSYNC(cpu_transcoder));
int vtot = I915_READ(VTOTAL(cpu_transcoder));
@@ -9082,6 +9032,14 @@ out:
intel_runtime_pm_put(dev_priv);
}
+static void intel_crtc_set_state(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state)
+{
+ kfree(crtc->config);
+ crtc->config = crtc_state;
+ crtc->base.state = &crtc_state->base;
+}
+
static void intel_crtc_destroy(struct drm_crtc *crtc)
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
@@ -9098,6 +9056,7 @@ static void intel_crtc_destroy(struct drm_crtc *crtc)
kfree(work);
}
+ intel_crtc_set_state(intel_crtc, NULL);
drm_crtc_cleanup(crtc);
kfree(intel_crtc);
@@ -9115,7 +9074,10 @@ static void intel_unpin_work_fn(struct work_struct *__work)
drm_gem_object_unreference(&work->pending_flip_obj->base);
drm_gem_object_unreference(&work->old_fb_obj->base);
- intel_update_fbc(dev);
+ intel_fbc_update(dev);
+
+ if (work->flip_queued_req)
+ i915_gem_request_assign(&work->flip_queued_req, NULL);
mutex_unlock(&dev->struct_mutex);
intel_frontbuffer_flip_complete(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
@@ -9511,25 +9473,53 @@ static bool use_mmio_flip(struct intel_engine_cs *ring,
else if (i915.enable_execlists)
return true;
else
- return ring != obj->ring;
+ return ring != i915_gem_request_get_ring(obj->last_read_req);
}
-static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
+static void skl_do_mmio_flip(struct intel_crtc *intel_crtc)
+{
+ struct drm_device *dev = intel_crtc->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = intel_crtc->base.primary->fb;
+ struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
+ struct drm_i915_gem_object *obj = intel_fb->obj;
+ const enum pipe pipe = intel_crtc->pipe;
+ u32 ctl, stride;
+
+ ctl = I915_READ(PLANE_CTL(pipe, 0));
+ ctl &= ~PLANE_CTL_TILED_MASK;
+ if (obj->tiling_mode == I915_TILING_X)
+ ctl |= PLANE_CTL_TILED_X;
+
+ /*
+ * The stride is either expressed as a multiple of 64 bytes chunks for
+ * linear buffers or in number of tiles for tiled buffers.
+ */
+ stride = fb->pitches[0] >> 6;
+ if (obj->tiling_mode == I915_TILING_X)
+ stride = fb->pitches[0] >> 9; /* X tiles are 512 bytes wide */
+
+ /*
+ * Both PLANE_CTL and PLANE_STRIDE are not updated on vblank but on
+ * PLANE_SURF updates, the update is then guaranteed to be atomic.
+ */
+ I915_WRITE(PLANE_CTL(pipe, 0), ctl);
+ I915_WRITE(PLANE_STRIDE(pipe, 0), stride);
+
+ I915_WRITE(PLANE_SURF(pipe, 0), intel_crtc->unpin_work->gtt_offset);
+ POSTING_READ(PLANE_SURF(pipe, 0));
+}
+
+static void ilk_do_mmio_flip(struct intel_crtc *intel_crtc)
{
struct drm_device *dev = intel_crtc->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_framebuffer *intel_fb =
to_intel_framebuffer(intel_crtc->base.primary->fb);
struct drm_i915_gem_object *obj = intel_fb->obj;
- bool atomic_update;
- u32 start_vbl_count;
u32 dspcntr;
u32 reg;
- intel_mark_page_flip_active(intel_crtc);
-
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
reg = DSPCNTR(intel_crtc->plane);
dspcntr = I915_READ(reg);
@@ -9544,26 +9534,50 @@ static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
intel_crtc->unpin_work->gtt_offset);
POSTING_READ(DSPSURF(intel_crtc->plane));
+}
+
+/*
+ * XXX: This is the temporary way to update the plane registers until we get
+ * around to using the usual plane update functions for MMIO flips
+ */
+static void intel_do_mmio_flip(struct intel_crtc *intel_crtc)
+{
+ struct drm_device *dev = intel_crtc->base.dev;
+ bool atomic_update;
+ u32 start_vbl_count;
+
+ intel_mark_page_flip_active(intel_crtc);
+
+ atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
+
+ if (INTEL_INFO(dev)->gen >= 9)
+ skl_do_mmio_flip(intel_crtc);
+ else
+ /* use_mmio_flip() retricts MMIO flips to ilk+ */
+ ilk_do_mmio_flip(intel_crtc);
+
if (atomic_update)
intel_pipe_update_end(intel_crtc, start_vbl_count);
}
static void intel_mmio_flip_work_func(struct work_struct *work)
{
- struct intel_crtc *intel_crtc =
+ struct intel_crtc *crtc =
container_of(work, struct intel_crtc, mmio_flip.work);
- struct intel_engine_cs *ring;
- uint32_t seqno;
-
- seqno = intel_crtc->mmio_flip.seqno;
- ring = intel_crtc->mmio_flip.ring;
+ struct intel_mmio_flip *mmio_flip;
- if (seqno)
- WARN_ON(__i915_wait_seqno(ring, seqno,
- intel_crtc->reset_counter,
- false, NULL, NULL) != 0);
+ mmio_flip = &crtc->mmio_flip;
+ if (mmio_flip->req)
+ WARN_ON(__i915_wait_request(mmio_flip->req,
+ crtc->reset_counter,
+ false, NULL, NULL) != 0);
- intel_do_mmio_flip(intel_crtc);
+ intel_do_mmio_flip(crtc);
+ if (mmio_flip->req) {
+ mutex_lock(&crtc->base.dev->struct_mutex);
+ i915_gem_request_assign(&mmio_flip->req, NULL);
+ mutex_unlock(&crtc->base.dev->struct_mutex);
+ }
}
static int intel_queue_mmio_flip(struct drm_device *dev,
@@ -9575,8 +9589,8 @@ static int intel_queue_mmio_flip(struct drm_device *dev,
{
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- intel_crtc->mmio_flip.seqno = obj->last_write_seqno;
- intel_crtc->mmio_flip.ring = obj->ring;
+ i915_gem_request_assign(&intel_crtc->mmio_flip.req,
+ obj->last_write_req);
schedule_work(&intel_crtc->mmio_flip.work);
@@ -9671,9 +9685,8 @@ static bool __intel_pageflip_stall_check(struct drm_device *dev,
return false;
if (work->flip_ready_vblank == 0) {
- if (work->flip_queued_ring &&
- !i915_seqno_passed(work->flip_queued_ring->get_seqno(work->flip_queued_ring, true),
- work->flip_queued_seqno))
+ if (work->flip_queued_req &&
+ !i915_gem_request_completed(work->flip_queued_req, true))
return false;
work->flip_ready_vblank = drm_vblank_count(dev, intel_crtc->pipe);
@@ -9726,6 +9739,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
struct drm_framebuffer *old_fb = crtc->primary->fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_plane *primary = crtc->primary;
enum pipe pipe = intel_crtc->pipe;
struct intel_unpin_work *work;
struct intel_engine_cs *ring;
@@ -9818,7 +9832,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
} else if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev)) {
ring = &dev_priv->ring[BCS];
} else if (INTEL_INFO(dev)->gen >= 7) {
- ring = obj->ring;
+ ring = i915_gem_request_get_ring(obj->last_read_req);
if (ring == NULL || ring->id != RCS)
ring = &dev_priv->ring[BCS];
} else {
@@ -9838,16 +9852,16 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
if (ret)
goto cleanup_unpin;
- work->flip_queued_seqno = obj->last_write_seqno;
- work->flip_queued_ring = obj->ring;
+ i915_gem_request_assign(&work->flip_queued_req,
+ obj->last_write_req);
} else {
ret = dev_priv->display.queue_flip(dev, crtc, fb, obj, ring,
page_flip_flags);
if (ret)
goto cleanup_unpin;
- work->flip_queued_seqno = intel_ring_get_seqno(ring);
- work->flip_queued_ring = ring;
+ i915_gem_request_assign(&work->flip_queued_req,
+ intel_ring_get_request(ring));
}
work->flip_queued_vblank = drm_vblank_count(dev, intel_crtc->pipe);
@@ -9856,7 +9870,7 @@ static int intel_crtc_page_flip(struct drm_crtc *crtc,
i915_gem_track_fb(work->old_fb_obj, obj,
INTEL_FRONTBUFFER_PRIMARY(pipe));
- intel_disable_fbc(dev);
+ intel_fbc_disable(dev);
intel_frontbuffer_flip_prepare(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
mutex_unlock(&dev->struct_mutex);
@@ -9884,8 +9898,7 @@ free_work:
if (ret == -EIO) {
out_hang:
- intel_crtc_wait_for_pending_flips(crtc);
- ret = intel_pipe_set_base(crtc, crtc->x, crtc->y, fb);
+ ret = intel_plane_restore(primary);
if (ret == 0 && event) {
spin_lock_irq(&dev->event_lock);
drm_send_vblank_event(dev, pipe, event);
@@ -9898,6 +9911,8 @@ out_hang:
static struct drm_crtc_helper_funcs intel_helper_funcs = {
.mode_set_base_atomic = intel_pipe_set_base_atomic,
.load_lut = intel_crtc_load_lut,
+ .atomic_begin = intel_begin_crtc_commit,
+ .atomic_flush = intel_finish_crtc_commit,
};
/**
@@ -9927,7 +9942,7 @@ static void intel_modeset_update_staged_output_state(struct drm_device *dev)
crtc->new_enabled = crtc->base.enabled;
if (crtc->new_enabled)
- crtc->new_config = &crtc->config;
+ crtc->new_config = crtc->config;
else
crtc->new_config = NULL;
}
@@ -9960,7 +9975,7 @@ static void intel_modeset_commit_output_state(struct drm_device *dev)
static void
connected_sink_compute_bpp(struct intel_connector *connector,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
int bpp = pipe_config->pipe_bpp;
@@ -9987,7 +10002,7 @@ connected_sink_compute_bpp(struct intel_connector *connector,
static int
compute_baseline_pipe_bpp(struct intel_crtc *crtc,
struct drm_framebuffer *fb,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = crtc->base.dev;
struct intel_connector *connector;
@@ -10056,7 +10071,7 @@ static void intel_dump_crtc_timings(const struct drm_display_mode *mode)
}
static void intel_dump_pipe_config(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
const char *context)
{
DRM_DEBUG_KMS("[CRTC:%d]%s config for pipe %c\n", crtc->base.base.id,
@@ -10090,10 +10105,10 @@ static void intel_dump_pipe_config(struct intel_crtc *crtc,
pipe_config->has_infoframe);
DRM_DEBUG_KMS("requested mode:\n");
- drm_mode_debug_printmodeline(&pipe_config->requested_mode);
+ drm_mode_debug_printmodeline(&pipe_config->base.mode);
DRM_DEBUG_KMS("adjusted mode:\n");
- drm_mode_debug_printmodeline(&pipe_config->adjusted_mode);
- intel_dump_crtc_timings(&pipe_config->adjusted_mode);
+ drm_mode_debug_printmodeline(&pipe_config->base.adjusted_mode);
+ intel_dump_crtc_timings(&pipe_config->base.adjusted_mode);
DRM_DEBUG_KMS("port clock: %d\n", pipe_config->port_clock);
DRM_DEBUG_KMS("pipe src size: %dx%d\n",
pipe_config->pipe_src_w, pipe_config->pipe_src_h);
@@ -10192,14 +10207,14 @@ static bool check_digital_port_conflicts(struct drm_device *dev)
return true;
}
-static struct intel_crtc_config *
+static struct intel_crtc_state *
intel_modeset_pipe_config(struct drm_crtc *crtc,
struct drm_framebuffer *fb,
struct drm_display_mode *mode)
{
struct drm_device *dev = crtc->dev;
struct intel_encoder *encoder;
- struct intel_crtc_config *pipe_config;
+ struct intel_crtc_state *pipe_config;
int plane_bpp, ret = -EINVAL;
bool retry = true;
@@ -10217,8 +10232,8 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
if (!pipe_config)
return ERR_PTR(-ENOMEM);
- drm_mode_copy(&pipe_config->adjusted_mode, mode);
- drm_mode_copy(&pipe_config->requested_mode, mode);
+ drm_mode_copy(&pipe_config->base.adjusted_mode, mode);
+ drm_mode_copy(&pipe_config->base.mode, mode);
pipe_config->cpu_transcoder =
(enum transcoder) to_intel_crtc(crtc)->pipe;
@@ -10229,13 +10244,13 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
* positive or negative polarity is requested, treat this as meaning
* negative polarity.
*/
- if (!(pipe_config->adjusted_mode.flags &
+ if (!(pipe_config->base.adjusted_mode.flags &
(DRM_MODE_FLAG_PHSYNC | DRM_MODE_FLAG_NHSYNC)))
- pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC;
+ pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NHSYNC;
- if (!(pipe_config->adjusted_mode.flags &
+ if (!(pipe_config->base.adjusted_mode.flags &
(DRM_MODE_FLAG_PVSYNC | DRM_MODE_FLAG_NVSYNC)))
- pipe_config->adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
+ pipe_config->base.adjusted_mode.flags |= DRM_MODE_FLAG_NVSYNC;
/* Compute a starting value for pipe_config->pipe_bpp taking the source
* plane pixel format and any sink constraints into account. Returns the
@@ -10254,9 +10269,9 @@ intel_modeset_pipe_config(struct drm_crtc *crtc,
* computation to clearly distinguish it from the adjusted mode, which
* can be changed by the connectors in the below retry loop.
*/
- drm_mode_set_crtcinfo(&pipe_config->requested_mode, CRTC_STEREO_DOUBLE);
- pipe_config->pipe_src_w = pipe_config->requested_mode.crtc_hdisplay;
- pipe_config->pipe_src_h = pipe_config->requested_mode.crtc_vdisplay;
+ drm_crtc_get_hv_timing(&pipe_config->base.mode,
+ &pipe_config->pipe_src_w,
+ &pipe_config->pipe_src_h);
encoder_retry:
/* Ensure the port clock defaults are reset when retrying. */
@@ -10264,7 +10279,8 @@ encoder_retry:
pipe_config->pixel_multiplier = 1;
/* Fill in default crtc timings, allow encoders to overwrite them. */
- drm_mode_set_crtcinfo(&pipe_config->adjusted_mode, CRTC_STEREO_DOUBLE);
+ drm_mode_set_crtcinfo(&pipe_config->base.adjusted_mode,
+ CRTC_STEREO_DOUBLE);
/* Pass our mode to the connectors and the CRTC to give them a chance to
* adjust it according to limitations or connector properties, and also
@@ -10284,7 +10300,7 @@ encoder_retry:
/* Set default port clock if not overwritten by the encoder. Needs to be
* done afterwards in case the encoder adjusts the mode. */
if (!pipe_config->port_clock)
- pipe_config->port_clock = pipe_config->adjusted_mode.crtc_clock
+ pipe_config->port_clock = pipe_config->base.adjusted_mode.crtc_clock
* pipe_config->pixel_multiplier;
ret = intel_crtc_compute_config(to_intel_crtc(crtc), pipe_config);
@@ -10441,7 +10457,7 @@ intel_modeset_update_state(struct drm_device *dev, unsigned prepare_pipes)
for_each_intel_crtc(dev, intel_crtc) {
WARN_ON(intel_crtc->base.enabled != intel_crtc_in_use(&intel_crtc->base));
WARN_ON(intel_crtc->new_config &&
- intel_crtc->new_config != &intel_crtc->config);
+ intel_crtc->new_config != intel_crtc->config);
WARN_ON(intel_crtc->base.enabled != !!intel_crtc->new_config);
}
@@ -10493,8 +10509,8 @@ static bool intel_fuzzy_clock_check(int clock1, int clock2)
static bool
intel_pipe_config_compare(struct drm_device *dev,
- struct intel_crtc_config *current_config,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *current_config,
+ struct intel_crtc_state *pipe_config)
{
#define PIPE_CONF_CHECK_X(name) \
if (current_config->name != pipe_config->name) { \
@@ -10585,19 +10601,19 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_I_ALT(dp_m_n.tu, dp_m2_n2.tu);
}
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_hdisplay);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_htotal);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_start);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_hblank_end);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_start);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_hsync_end);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hdisplay);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_htotal);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_start);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hblank_end);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_start);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_hsync_end);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_vdisplay);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_vtotal);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_start);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_vblank_end);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_start);
- PIPE_CONF_CHECK_I(adjusted_mode.crtc_vsync_end);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vdisplay);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vtotal);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_start);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vblank_end);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_start);
+ PIPE_CONF_CHECK_I(base.adjusted_mode.crtc_vsync_end);
PIPE_CONF_CHECK_I(pixel_multiplier);
PIPE_CONF_CHECK_I(has_hdmi_sink);
@@ -10608,17 +10624,17 @@ intel_pipe_config_compare(struct drm_device *dev,
PIPE_CONF_CHECK_I(has_audio);
- PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
DRM_MODE_FLAG_INTERLACE);
if (!PIPE_CONF_QUIRK(PIPE_CONFIG_QUIRK_MODE_SYNC_FLAGS)) {
- PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
DRM_MODE_FLAG_PHSYNC);
- PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
DRM_MODE_FLAG_NHSYNC);
- PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
DRM_MODE_FLAG_PVSYNC);
- PIPE_CONF_CHECK_FLAGS(adjusted_mode.flags,
+ PIPE_CONF_CHECK_FLAGS(base.adjusted_mode.flags,
DRM_MODE_FLAG_NVSYNC);
}
@@ -10668,7 +10684,7 @@ intel_pipe_config_compare(struct drm_device *dev,
if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5)
PIPE_CONF_CHECK_I(pipe_bpp);
- PIPE_CONF_CHECK_CLOCK_FUZZY(adjusted_mode.crtc_clock);
+ PIPE_CONF_CHECK_CLOCK_FUZZY(base.adjusted_mode.crtc_clock);
PIPE_CONF_CHECK_CLOCK_FUZZY(port_clock);
#undef PIPE_CONF_CHECK_X
@@ -10742,7 +10758,7 @@ check_connector_state(struct drm_device *dev)
* ->get_hw_state callbacks. */
intel_connector_check_state(connector);
- WARN(&connector->new_encoder->base != connector->base.encoder,
+ I915_STATE_WARN(&connector->new_encoder->base != connector->base.encoder,
"connector's staged encoder doesn't match current encoder\n");
}
}
@@ -10762,9 +10778,9 @@ check_encoder_state(struct drm_device *dev)
encoder->base.base.id,
encoder->base.name);
- WARN(&encoder->new_crtc->base != encoder->base.crtc,
+ I915_STATE_WARN(&encoder->new_crtc->base != encoder->base.crtc,
"encoder's stage crtc doesn't match current crtc\n");
- WARN(encoder->connectors_active && !encoder->base.crtc,
+ I915_STATE_WARN(encoder->connectors_active && !encoder->base.crtc,
"encoder's active_connectors set, but no crtc\n");
list_for_each_entry(connector, &dev->mode_config.connector_list,
@@ -10783,19 +10799,19 @@ check_encoder_state(struct drm_device *dev)
if (!enabled && encoder->base.encoder_type == DRM_MODE_ENCODER_DPMST)
continue;
- WARN(!!encoder->base.crtc != enabled,
+ I915_STATE_WARN(!!encoder->base.crtc != enabled,
"encoder's enabled state mismatch "
"(expected %i, found %i)\n",
!!encoder->base.crtc, enabled);
- WARN(active && !encoder->base.crtc,
+ I915_STATE_WARN(active && !encoder->base.crtc,
"active encoder with no crtc\n");
- WARN(encoder->connectors_active != active,
+ I915_STATE_WARN(encoder->connectors_active != active,
"encoder's computed active state doesn't match tracked active state "
"(expected %i, found %i)\n", active, encoder->connectors_active);
active = encoder->get_hw_state(encoder, &pipe);
- WARN(active != encoder->connectors_active,
+ I915_STATE_WARN(active != encoder->connectors_active,
"encoder's hw state doesn't match sw tracking "
"(expected %i, found %i)\n",
encoder->connectors_active, active);
@@ -10804,7 +10820,7 @@ check_encoder_state(struct drm_device *dev)
continue;
tracked_pipe = to_intel_crtc(encoder->base.crtc)->pipe;
- WARN(active && pipe != tracked_pipe,
+ I915_STATE_WARN(active && pipe != tracked_pipe,
"active encoder's pipe doesn't match"
"(expected %i, found %i)\n",
tracked_pipe, pipe);
@@ -10818,7 +10834,7 @@ check_crtc_state(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc;
struct intel_encoder *encoder;
- struct intel_crtc_config pipe_config;
+ struct intel_crtc_state pipe_config;
for_each_intel_crtc(dev, crtc) {
bool enabled = false;
@@ -10829,7 +10845,7 @@ check_crtc_state(struct drm_device *dev)
DRM_DEBUG_KMS("[CRTC:%d]\n",
crtc->base.base.id);
- WARN(crtc->active && !crtc->base.enabled,
+ I915_STATE_WARN(crtc->active && !crtc->base.enabled,
"active crtc, but not enabled in sw tracking\n");
for_each_intel_encoder(dev, encoder) {
@@ -10840,10 +10856,10 @@ check_crtc_state(struct drm_device *dev)
active = true;
}
- WARN(active != crtc->active,
+ I915_STATE_WARN(active != crtc->active,
"crtc's computed active state doesn't match tracked active state "
"(expected %i, found %i)\n", active, crtc->active);
- WARN(enabled != crtc->base.enabled,
+ I915_STATE_WARN(enabled != crtc->base.enabled,
"crtc's computed enabled state doesn't match tracked enabled state "
"(expected %i, found %i)\n", enabled, crtc->base.enabled);
@@ -10863,16 +10879,16 @@ check_crtc_state(struct drm_device *dev)
encoder->get_config(encoder, &pipe_config);
}
- WARN(crtc->active != active,
+ I915_STATE_WARN(crtc->active != active,
"crtc active state doesn't match with hw state "
"(expected %i, found %i)\n", crtc->active, active);
if (active &&
- !intel_pipe_config_compare(dev, &crtc->config, &pipe_config)) {
- WARN(1, "pipe state doesn't match!\n");
+ !intel_pipe_config_compare(dev, crtc->config, &pipe_config)) {
+ I915_STATE_WARN(1, "pipe state doesn't match!\n");
intel_dump_pipe_config(crtc, &pipe_config,
"[hw state]");
- intel_dump_pipe_config(crtc, &crtc->config,
+ intel_dump_pipe_config(crtc, crtc->config,
"[sw state]");
}
}
@@ -10897,14 +10913,14 @@ check_shared_dpll_state(struct drm_device *dev)
active = pll->get_hw_state(dev_priv, pll, &dpll_hw_state);
- WARN(pll->active > hweight32(pll->config.crtc_mask),
+ I915_STATE_WARN(pll->active > hweight32(pll->config.crtc_mask),
"more active pll users than references: %i vs %i\n",
pll->active, hweight32(pll->config.crtc_mask));
- WARN(pll->active && !pll->on,
+ I915_STATE_WARN(pll->active && !pll->on,
"pll in active use but not on in sw tracking\n");
- WARN(pll->on && !pll->active,
+ I915_STATE_WARN(pll->on && !pll->active,
"pll in on but not on in use in sw tracking\n");
- WARN(pll->on != active,
+ I915_STATE_WARN(pll->on != active,
"pll on state mismatch (expected %i, found %i)\n",
pll->on, active);
@@ -10914,14 +10930,14 @@ check_shared_dpll_state(struct drm_device *dev)
if (crtc->active && intel_crtc_to_shared_dpll(crtc) == pll)
active_crtcs++;
}
- WARN(pll->active != active_crtcs,
+ I915_STATE_WARN(pll->active != active_crtcs,
"pll active crtcs mismatch (expected %i, found %i)\n",
pll->active, active_crtcs);
- WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
+ I915_STATE_WARN(hweight32(pll->config.crtc_mask) != enabled_crtcs,
"pll enabled crtcs mismatch (expected %i, found %i)\n",
hweight32(pll->config.crtc_mask), enabled_crtcs);
- WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
+ I915_STATE_WARN(pll->on && memcmp(&pll->config.hw_state, &dpll_hw_state,
sizeof(dpll_hw_state)),
"pll hw state mismatch\n");
}
@@ -10937,16 +10953,16 @@ intel_modeset_check_state(struct drm_device *dev)
check_shared_dpll_state(dev);
}
-void ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
+void ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
int dotclock)
{
/*
* FDI already provided one idea for the dotclock.
* Yell if the encoder disagrees.
*/
- WARN(!intel_fuzzy_clock_check(pipe_config->adjusted_mode.crtc_clock, dotclock),
+ WARN(!intel_fuzzy_clock_check(pipe_config->base.adjusted_mode.crtc_clock, dotclock),
"FDI dotclock and encoder dotclock mismatch, fdi: %i, encoder: %i\n",
- pipe_config->adjusted_mode.crtc_clock, dotclock);
+ pipe_config->base.adjusted_mode.crtc_clock, dotclock);
}
static void update_scanline_offset(struct intel_crtc *crtc)
@@ -10972,7 +10988,7 @@ static void update_scanline_offset(struct intel_crtc *crtc)
* one to the value.
*/
if (IS_GEN2(dev)) {
- const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+ const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
int vtotal;
vtotal = mode->crtc_vtotal;
@@ -10987,7 +11003,7 @@ static void update_scanline_offset(struct intel_crtc *crtc)
crtc->scanline_offset = 1;
}
-static struct intel_crtc_config *
+static struct intel_crtc_state *
intel_modeset_compute_config(struct drm_crtc *crtc,
struct drm_display_mode *mode,
struct drm_framebuffer *fb,
@@ -10995,7 +11011,7 @@ intel_modeset_compute_config(struct drm_crtc *crtc,
unsigned *prepare_pipes,
unsigned *disable_pipes)
{
- struct intel_crtc_config *pipe_config = NULL;
+ struct intel_crtc_state *pipe_config = NULL;
intel_modeset_affected_pipes(crtc, modeset_pipes,
prepare_pipes, disable_pipes);
@@ -11020,10 +11036,40 @@ out:
return pipe_config;
}
+static int __intel_set_mode_setup_plls(struct drm_device *dev,
+ unsigned modeset_pipes,
+ unsigned disable_pipes)
+{
+ struct drm_i915_private *dev_priv = to_i915(dev);
+ unsigned clear_pipes = modeset_pipes | disable_pipes;
+ struct intel_crtc *intel_crtc;
+ int ret = 0;
+
+ if (!dev_priv->display.crtc_compute_clock)
+ return 0;
+
+ ret = intel_shared_dpll_start_config(dev_priv, clear_pipes);
+ if (ret)
+ goto done;
+
+ for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
+ struct intel_crtc_state *state = intel_crtc->new_config;
+ ret = dev_priv->display.crtc_compute_clock(intel_crtc,
+ state);
+ if (ret) {
+ intel_shared_dpll_abort_config(dev_priv);
+ goto done;
+ }
+ }
+
+done:
+ return ret;
+}
+
static int __intel_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *fb,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
unsigned modeset_pipes,
unsigned prepare_pipes,
unsigned disable_pipes)
@@ -11057,21 +11103,9 @@ static int __intel_set_mode(struct drm_crtc *crtc,
prepare_pipes &= ~disable_pipes;
}
- if (dev_priv->display.crtc_compute_clock) {
- unsigned clear_pipes = modeset_pipes | disable_pipes;
-
- ret = intel_shared_dpll_start_config(dev_priv, clear_pipes);
- if (ret)
- goto done;
-
- for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
- ret = dev_priv->display.crtc_compute_clock(intel_crtc);
- if (ret) {
- intel_shared_dpll_abort_config(dev_priv);
- goto done;
- }
- }
- }
+ ret = __intel_set_mode_setup_plls(dev, modeset_pipes, disable_pipes);
+ if (ret)
+ goto done;
for_each_intel_crtc_masked(dev, disable_pipes, intel_crtc)
intel_crtc_disable(&intel_crtc->base);
@@ -11092,8 +11126,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
crtc->mode = *mode;
/* mode_set/enable/disable functions rely on a correct pipe
* config. */
- to_intel_crtc(crtc)->config = *pipe_config;
- to_intel_crtc(crtc)->new_config = &to_intel_crtc(crtc)->config;
+ intel_crtc_set_state(to_intel_crtc(crtc), pipe_config);
/*
* Calculate and store various constants which
@@ -11101,7 +11134,7 @@ static int __intel_set_mode(struct drm_crtc *crtc,
* timestamping. They are derived from true hwmode.
*/
drm_calc_timestamping_constants(crtc,
- &pipe_config->adjusted_mode);
+ &pipe_config->base.adjusted_mode);
}
/* Only after disabling all output pipelines that will be changed can we
@@ -11114,26 +11147,15 @@ static int __intel_set_mode(struct drm_crtc *crtc,
* on the DPLL.
*/
for_each_intel_crtc_masked(dev, modeset_pipes, intel_crtc) {
- struct drm_framebuffer *old_fb = crtc->primary->fb;
- struct drm_i915_gem_object *old_obj = intel_fb_obj(old_fb);
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct drm_plane *primary = intel_crtc->base.primary;
+ int vdisplay, hdisplay;
- mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(crtc->primary, fb, NULL);
- if (ret != 0) {
- DRM_ERROR("pin & fence failed\n");
- mutex_unlock(&dev->struct_mutex);
- goto done;
- }
- if (old_fb)
- intel_unpin_fb_obj(old_obj);
- i915_gem_track_fb(old_obj, obj,
- INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
- mutex_unlock(&dev->struct_mutex);
-
- crtc->primary->fb = fb;
- crtc->x = x;
- crtc->y = y;
+ drm_crtc_get_hv_timing(mode, &hdisplay, &vdisplay);
+ ret = primary->funcs->update_plane(primary, &intel_crtc->base,
+ fb, 0, 0,
+ hdisplay, vdisplay,
+ x << 16, y << 16,
+ hdisplay << 16, vdisplay << 16);
}
/* Now enable the clocks, plane, pipe, and connectors that we set up. */
@@ -11148,7 +11170,6 @@ done:
if (ret && crtc->enabled)
crtc->mode = *saved_mode;
- kfree(pipe_config);
kfree(saved_mode);
return ret;
}
@@ -11156,7 +11177,7 @@ done:
static int intel_set_mode_pipes(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *fb,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
unsigned modeset_pipes,
unsigned prepare_pipes,
unsigned disable_pipes)
@@ -11176,7 +11197,7 @@ static int intel_set_mode(struct drm_crtc *crtc,
struct drm_display_mode *mode,
int x, int y, struct drm_framebuffer *fb)
{
- struct intel_crtc_config *pipe_config;
+ struct intel_crtc_state *pipe_config;
unsigned modeset_pipes, prepare_pipes, disable_pipes;
pipe_config = intel_modeset_compute_config(crtc, mode, fb,
@@ -11271,7 +11292,7 @@ static void intel_set_config_restore_state(struct drm_device *dev,
crtc->new_enabled = config->save_crtc_enabled[count++];
if (crtc->new_enabled)
- crtc->new_config = &crtc->config;
+ crtc->new_config = crtc->config;
else
crtc->new_config = NULL;
}
@@ -11483,7 +11504,7 @@ intel_modeset_stage_output_state(struct drm_device *dev,
}
if (crtc->new_enabled)
- crtc->new_config = &crtc->config;
+ crtc->new_config = crtc->config;
else
crtc->new_config = NULL;
}
@@ -11520,7 +11541,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
struct drm_device *dev;
struct drm_mode_set save_set;
struct intel_set_config *config;
- struct intel_crtc_config *pipe_config;
+ struct intel_crtc_state *pipe_config;
unsigned modeset_pipes, prepare_pipes, disable_pipes;
int ret;
@@ -11577,7 +11598,7 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
goto fail;
} else if (pipe_config) {
if (pipe_config->has_audio !=
- to_intel_crtc(set->crtc)->config.has_audio)
+ to_intel_crtc(set->crtc)->config->has_audio)
config->mode_changed = true;
/*
@@ -11601,11 +11622,14 @@ static int intel_crtc_set_config(struct drm_mode_set *set)
disable_pipes);
} else if (config->fb_changed) {
struct intel_crtc *intel_crtc = to_intel_crtc(set->crtc);
+ struct drm_plane *primary = set->crtc->primary;
+ int vdisplay, hdisplay;
- intel_crtc_wait_for_pending_flips(set->crtc);
-
- ret = intel_pipe_set_base(set->crtc,
- set->x, set->y, set->fb);
+ drm_crtc_get_hv_timing(set->mode, &hdisplay, &vdisplay);
+ ret = primary->funcs->update_plane(primary, set->crtc, set->fb,
+ 0, 0, hdisplay, vdisplay,
+ set->x << 16, set->y << 16,
+ hdisplay << 16, vdisplay << 16);
/*
* We need to make sure the primary plane is re-enabled if it
@@ -11660,6 +11684,8 @@ static const struct drm_crtc_funcs intel_crtc_funcs = {
.set_config = intel_crtc_set_config,
.destroy = intel_crtc_destroy,
.page_flip = intel_crtc_page_flip,
+ .atomic_duplicate_state = intel_crtc_duplicate_state,
+ .atomic_destroy_state = intel_crtc_destroy_state,
};
static bool ibx_pch_dpll_get_hw_state(struct drm_i915_private *dev_priv,
@@ -11762,93 +11788,149 @@ static void intel_shared_dpll_init(struct drm_device *dev)
BUG_ON(dev_priv->num_shared_dpll > I915_NUM_PLLS);
}
-static int
-intel_primary_plane_disable(struct drm_plane *plane)
+/**
+ * intel_prepare_plane_fb - Prepare fb for usage on plane
+ * @plane: drm plane to prepare for
+ * @fb: framebuffer to prepare for presentation
+ *
+ * Prepares a framebuffer for usage on a display plane. Generally this
+ * involves pinning the underlying object and updating the frontbuffer tracking
+ * bits. Some older platforms need special physical address handling for
+ * cursor planes.
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int
+intel_prepare_plane_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb)
{
struct drm_device *dev = plane->dev;
- struct intel_crtc *intel_crtc;
+ struct intel_plane *intel_plane = to_intel_plane(plane);
+ enum pipe pipe = intel_plane->pipe;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
+ unsigned frontbuffer_bits = 0;
+ int ret = 0;
- if (!plane->fb)
+ if (!obj)
return 0;
- BUG_ON(!plane->crtc);
+ switch (plane->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ frontbuffer_bits = INTEL_FRONTBUFFER_PRIMARY(pipe);
+ break;
+ case DRM_PLANE_TYPE_CURSOR:
+ frontbuffer_bits = INTEL_FRONTBUFFER_CURSOR(pipe);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ frontbuffer_bits = INTEL_FRONTBUFFER_SPRITE(pipe);
+ break;
+ }
- intel_crtc = to_intel_crtc(plane->crtc);
+ mutex_lock(&dev->struct_mutex);
- /*
- * Even though we checked plane->fb above, it's still possible that
- * the primary plane has been implicitly disabled because the crtc
- * coordinates given weren't visible, or because we detected
- * that it was 100% covered by a sprite plane. Or, the CRTC may be
- * off and we've set a fb, but haven't actually turned on the CRTC yet.
- * In either case, we need to unpin the FB and let the fb pointer get
- * updated, but otherwise we don't need to touch the hardware.
- */
- if (!intel_crtc->primary_enabled)
- goto disable_unpin;
+ if (plane->type == DRM_PLANE_TYPE_CURSOR &&
+ INTEL_INFO(dev)->cursor_needs_physical) {
+ int align = IS_I830(dev) ? 16 * 1024 : 256;
+ ret = i915_gem_object_attach_phys(obj, align);
+ if (ret)
+ DRM_DEBUG_KMS("failed to attach phys object\n");
+ } else {
+ ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
+ }
- intel_crtc_wait_for_pending_flips(plane->crtc);
- intel_disable_primary_hw_plane(plane, plane->crtc);
+ if (ret == 0)
+ i915_gem_track_fb(old_obj, obj, frontbuffer_bits);
-disable_unpin:
- mutex_lock(&dev->struct_mutex);
- i915_gem_track_fb(intel_fb_obj(plane->fb), NULL,
- INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe));
- intel_unpin_fb_obj(intel_fb_obj(plane->fb));
mutex_unlock(&dev->struct_mutex);
- plane->fb = NULL;
- return 0;
+ return ret;
+}
+
+/**
+ * intel_cleanup_plane_fb - Cleans up an fb after plane use
+ * @plane: drm plane to clean up for
+ * @fb: old framebuffer that was on plane
+ *
+ * Cleans up a framebuffer that has just been removed from a plane.
+ */
+void
+intel_cleanup_plane_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb)
+{
+ struct drm_device *dev = plane->dev;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+
+ if (WARN_ON(!obj))
+ return;
+
+ if (plane->type != DRM_PLANE_TYPE_CURSOR ||
+ !INTEL_INFO(dev)->cursor_needs_physical) {
+ mutex_lock(&dev->struct_mutex);
+ intel_unpin_fb_obj(obj);
+ mutex_unlock(&dev->struct_mutex);
+ }
}
static int
intel_check_primary_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct drm_crtc *crtc = state->crtc;
- struct drm_framebuffer *fb = state->fb;
+ struct drm_device *dev = plane->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = state->base.crtc;
+ struct intel_crtc *intel_crtc;
+ struct drm_framebuffer *fb = state->base.fb;
struct drm_rect *dest = &state->dst;
struct drm_rect *src = &state->src;
const struct drm_rect *clip = &state->clip;
+ int ret;
- return drm_plane_helper_check_update(plane, crtc, fb,
- src, dest, clip,
- DRM_PLANE_HELPER_NO_SCALING,
- DRM_PLANE_HELPER_NO_SCALING,
- false, true, &state->visible);
-}
+ crtc = crtc ? crtc : plane->crtc;
+ intel_crtc = to_intel_crtc(crtc);
-static int
-intel_prepare_primary_plane(struct drm_plane *plane,
- struct intel_plane_state *state)
-{
- struct drm_crtc *crtc = state->crtc;
- struct drm_framebuffer *fb = state->fb;
- struct drm_device *dev = crtc->dev;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
- int ret;
+ ret = drm_plane_helper_check_update(plane, crtc, fb,
+ src, dest, clip,
+ DRM_PLANE_HELPER_NO_SCALING,
+ DRM_PLANE_HELPER_NO_SCALING,
+ false, true, &state->visible);
+ if (ret)
+ return ret;
- intel_crtc_wait_for_pending_flips(crtc);
+ if (intel_crtc->active) {
+ intel_crtc->atomic.wait_for_flips = true;
- if (intel_crtc_has_pending_flip(crtc)) {
- DRM_ERROR("pipe is still busy with an old pageflip\n");
- return -EBUSY;
- }
+ /*
+ * FBC does not work on some platforms for rotated
+ * planes, so disable it when rotation is not 0 and
+ * update it when rotation is set back to 0.
+ *
+ * FIXME: This is redundant with the fbc update done in
+ * the primary plane enable function except that that
+ * one is done too late. We eventually need to unify
+ * this.
+ */
+ if (intel_crtc->primary_enabled &&
+ INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+ dev_priv->fbc.plane == intel_crtc->plane &&
+ state->base.rotation != BIT(DRM_ROTATE_0)) {
+ intel_crtc->atomic.disable_fbc = true;
+ }
- if (old_obj != obj) {
- mutex_lock(&dev->struct_mutex);
- ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
- if (ret == 0)
- i915_gem_track_fb(old_obj, obj,
- INTEL_FRONTBUFFER_PRIMARY(pipe));
- mutex_unlock(&dev->struct_mutex);
- if (ret != 0) {
- DRM_DEBUG_KMS("pin & fence failed\n");
- return ret;
+ if (state->visible) {
+ /*
+ * BDW signals flip done immediately if the plane
+ * is disabled, even if the plane enable is already
+ * armed to occur at the next vblank :(
+ */
+ if (IS_BROADWELL(dev) && !intel_crtc->primary_enabled)
+ intel_crtc->atomic.wait_vblank = true;
}
+
+ intel_crtc->atomic.fb_bits |=
+ INTEL_FRONTBUFFER_PRIMARY(intel_crtc->pipe);
+
+ intel_crtc->atomic.update_fbc = true;
}
return 0;
@@ -11858,53 +11940,26 @@ static void
intel_commit_primary_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct drm_crtc *crtc = state->crtc;
- struct drm_framebuffer *fb = state->fb;
- struct drm_device *dev = crtc->dev;
+ struct drm_crtc *crtc = state->base.crtc;
+ struct drm_framebuffer *fb = state->base.fb;
+ struct drm_device *dev = plane->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_framebuffer *old_fb = plane->fb;
+ struct intel_crtc *intel_crtc;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct drm_i915_gem_object *old_obj = intel_fb_obj(plane->fb);
struct intel_plane *intel_plane = to_intel_plane(plane);
struct drm_rect *src = &state->src;
- crtc->primary->fb = fb;
+ crtc = crtc ? crtc : plane->crtc;
+ intel_crtc = to_intel_crtc(crtc);
+
+ plane->fb = fb;
crtc->x = src->x1 >> 16;
crtc->y = src->y1 >> 16;
- intel_plane->crtc_x = state->orig_dst.x1;
- intel_plane->crtc_y = state->orig_dst.y1;
- intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
- intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
- intel_plane->src_x = state->orig_src.x1;
- intel_plane->src_y = state->orig_src.y1;
- intel_plane->src_w = drm_rect_width(&state->orig_src);
- intel_plane->src_h = drm_rect_height(&state->orig_src);
intel_plane->obj = obj;
if (intel_crtc->active) {
- /*
- * FBC does not work on some platforms for rotated
- * planes, so disable it when rotation is not 0 and
- * update it when rotation is set back to 0.
- *
- * FIXME: This is redundant with the fbc update done in
- * the primary plane enable function except that that
- * one is done too late. We eventually need to unify
- * this.
- */
- if (intel_crtc->primary_enabled &&
- INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
- dev_priv->fbc.plane == intel_crtc->plane &&
- intel_plane->rotation != BIT(DRM_ROTATE_0)) {
- intel_disable_fbc(dev);
- }
-
if (state->visible) {
- bool was_enabled = intel_crtc->primary_enabled;
-
/* FIXME: kill this fastboot hack */
intel_update_pipe_size(intel_crtc);
@@ -11912,14 +11967,6 @@ intel_commit_primary_plane(struct drm_plane *plane,
dev_priv->display.update_primary_plane(crtc, plane->fb,
crtc->x, crtc->y);
-
- /*
- * BDW signals flip done immediately if the plane
- * is disabled, even if the plane enable is already
- * armed to occur at the next vblank :(
- */
- if (IS_BROADWELL(dev) && !was_enabled)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
} else {
/*
* If clipping results in a non-visible primary plane,
@@ -11930,90 +11977,129 @@ intel_commit_primary_plane(struct drm_plane *plane,
*/
intel_disable_primary_hw_plane(plane, crtc);
}
+ }
+}
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_PRIMARY(pipe));
+static void intel_begin_crtc_commit(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct intel_plane *intel_plane;
+ struct drm_plane *p;
+ unsigned fb_bits = 0;
+
+ /* Track fb's for any planes being disabled */
+ list_for_each_entry(p, &dev->mode_config.plane_list, head) {
+ intel_plane = to_intel_plane(p);
+
+ if (intel_crtc->atomic.disabled_planes &
+ (1 << drm_plane_index(p))) {
+ switch (p->type) {
+ case DRM_PLANE_TYPE_PRIMARY:
+ fb_bits = INTEL_FRONTBUFFER_PRIMARY(intel_plane->pipe);
+ break;
+ case DRM_PLANE_TYPE_CURSOR:
+ fb_bits = INTEL_FRONTBUFFER_CURSOR(intel_plane->pipe);
+ break;
+ case DRM_PLANE_TYPE_OVERLAY:
+ fb_bits = INTEL_FRONTBUFFER_SPRITE(intel_plane->pipe);
+ break;
+ }
- mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
- mutex_unlock(&dev->struct_mutex);
+ mutex_lock(&dev->struct_mutex);
+ i915_gem_track_fb(intel_fb_obj(p->fb), NULL, fb_bits);
+ mutex_unlock(&dev->struct_mutex);
+ }
}
- if (old_fb && old_fb != fb) {
- if (intel_crtc->active)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
+ if (intel_crtc->atomic.wait_for_flips)
+ intel_crtc_wait_for_pending_flips(crtc);
- mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(old_obj);
- mutex_unlock(&dev->struct_mutex);
- }
+ if (intel_crtc->atomic.disable_fbc)
+ intel_fbc_disable(dev);
+
+ if (intel_crtc->atomic.pre_disable_primary)
+ intel_pre_disable_primary(crtc);
+
+ if (intel_crtc->atomic.update_wm)
+ intel_update_watermarks(crtc);
+
+ intel_runtime_pm_get(dev_priv);
+
+ /* Perform vblank evasion around commit operation */
+ if (intel_crtc->active)
+ intel_crtc->atomic.evade =
+ intel_pipe_update_start(intel_crtc,
+ &intel_crtc->atomic.start_vbl_count);
}
-static int
-intel_primary_plane_setplane(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h)
+static void intel_finish_crtc_commit(struct drm_crtc *crtc)
{
- struct intel_plane_state state;
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int ret;
-
- state.crtc = crtc;
- state.fb = fb;
+ struct drm_plane *p;
- /* sample coordinates in 16.16 fixed point */
- state.src.x1 = src_x;
- state.src.x2 = src_x + src_w;
- state.src.y1 = src_y;
- state.src.y2 = src_y + src_h;
+ if (intel_crtc->atomic.evade)
+ intel_pipe_update_end(intel_crtc,
+ intel_crtc->atomic.start_vbl_count);
- /* integer pixels */
- state.dst.x1 = crtc_x;
- state.dst.x2 = crtc_x + crtc_w;
- state.dst.y1 = crtc_y;
- state.dst.y2 = crtc_y + crtc_h;
+ intel_runtime_pm_put(dev_priv);
- state.clip.x1 = 0;
- state.clip.y1 = 0;
- state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
- state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
+ if (intel_crtc->atomic.wait_vblank)
+ intel_wait_for_vblank(dev, intel_crtc->pipe);
- state.orig_src = state.src;
- state.orig_dst = state.dst;
+ intel_frontbuffer_flip(dev, intel_crtc->atomic.fb_bits);
- ret = intel_check_primary_plane(plane, &state);
- if (ret)
- return ret;
+ if (intel_crtc->atomic.update_fbc) {
+ mutex_lock(&dev->struct_mutex);
+ intel_fbc_update(dev);
+ mutex_unlock(&dev->struct_mutex);
+ }
- ret = intel_prepare_primary_plane(plane, &state);
- if (ret)
- return ret;
+ if (intel_crtc->atomic.post_enable_primary)
+ intel_post_enable_primary(crtc);
- intel_commit_primary_plane(plane, &state);
+ drm_for_each_legacy_plane(p, &dev->mode_config.plane_list)
+ if (intel_crtc->atomic.update_sprite_watermarks & drm_plane_index(p))
+ intel_update_sprite_watermarks(p, crtc, 0, 0, 0,
+ false, false);
- return 0;
+ memset(&intel_crtc->atomic, 0, sizeof(intel_crtc->atomic));
}
-/* Common destruction function for both primary and cursor planes */
-static void intel_plane_destroy(struct drm_plane *plane)
+/**
+ * intel_plane_destroy - destroy a plane
+ * @plane: plane to destroy
+ *
+ * Common destruction function for all types of planes (primary, cursor,
+ * sprite).
+ */
+void intel_plane_destroy(struct drm_plane *plane)
{
struct intel_plane *intel_plane = to_intel_plane(plane);
drm_plane_cleanup(plane);
kfree(intel_plane);
}
-static const struct drm_plane_funcs intel_primary_plane_funcs = {
- .update_plane = intel_primary_plane_setplane,
- .disable_plane = intel_primary_plane_disable,
+const struct drm_plane_funcs intel_plane_funcs = {
+ .update_plane = drm_plane_helper_update,
+ .disable_plane = drm_plane_helper_disable,
.destroy = intel_plane_destroy,
- .set_property = intel_plane_set_property
+ .set_property = drm_atomic_helper_plane_set_property,
+ .atomic_get_property = intel_plane_atomic_get_property,
+ .atomic_set_property = intel_plane_atomic_set_property,
+ .atomic_duplicate_state = intel_plane_duplicate_state,
+ .atomic_destroy_state = intel_plane_destroy_state,
+
};
static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
int pipe)
{
struct intel_plane *primary;
+ struct intel_plane_state *state;
const uint32_t *intel_primary_formats;
int num_formats;
@@ -12021,11 +12107,19 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
if (primary == NULL)
return NULL;
+ state = intel_create_plane_state(&primary->base);
+ if (!state) {
+ kfree(primary);
+ return NULL;
+ }
+ primary->base.state = &state->base;
+
primary->can_scale = false;
primary->max_downscale = 1;
primary->pipe = pipe;
primary->plane = pipe;
- primary->rotation = BIT(DRM_ROTATE_0);
+ primary->check_plane = intel_check_primary_plane;
+ primary->commit_plane = intel_commit_primary_plane;
if (HAS_FBC(dev) && INTEL_INFO(dev)->gen < 4)
primary->plane = !pipe;
@@ -12038,7 +12132,7 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
}
drm_universal_plane_init(dev, &primary->base, 0,
- &intel_primary_plane_funcs,
+ &intel_plane_funcs,
intel_primary_formats, num_formats,
DRM_PLANE_TYPE_PRIMARY);
@@ -12051,38 +12145,32 @@ static struct drm_plane *intel_primary_plane_create(struct drm_device *dev,
if (dev->mode_config.rotation_property)
drm_object_attach_property(&primary->base.base,
dev->mode_config.rotation_property,
- primary->rotation);
+ state->base.rotation);
}
- return &primary->base;
-}
+ drm_plane_helper_add(&primary->base, &intel_plane_helper_funcs);
-static int
-intel_cursor_plane_disable(struct drm_plane *plane)
-{
- if (!plane->fb)
- return 0;
-
- BUG_ON(!plane->crtc);
-
- return intel_crtc_cursor_set_obj(plane->crtc, NULL, 0, 0);
+ return &primary->base;
}
static int
intel_check_cursor_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct drm_crtc *crtc = state->crtc;
- struct drm_device *dev = crtc->dev;
- struct drm_framebuffer *fb = state->fb;
+ struct drm_crtc *crtc = state->base.crtc;
+ struct drm_device *dev = plane->dev;
+ struct drm_framebuffer *fb = state->base.fb;
struct drm_rect *dest = &state->dst;
struct drm_rect *src = &state->src;
const struct drm_rect *clip = &state->clip;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- int crtc_w, crtc_h;
+ struct intel_crtc *intel_crtc;
unsigned stride;
int ret;
+ crtc = crtc ? crtc : plane->crtc;
+ intel_crtc = to_intel_crtc(crtc);
+
ret = drm_plane_helper_check_update(plane, crtc, fb,
src, dest, clip,
DRM_PLANE_HELPER_NO_SCALING,
@@ -12094,25 +12182,21 @@ intel_check_cursor_plane(struct drm_plane *plane,
/* if we want to turn off the cursor ignore width and height */
if (!obj)
- return 0;
+ goto finish;
/* Check for which cursor types we support */
- crtc_w = drm_rect_width(&state->orig_dst);
- crtc_h = drm_rect_height(&state->orig_dst);
- if (!cursor_size_ok(dev, crtc_w, crtc_h)) {
- DRM_DEBUG("Cursor dimension not supported\n");
+ if (!cursor_size_ok(dev, state->base.crtc_w, state->base.crtc_h)) {
+ DRM_DEBUG("Cursor dimension %dx%d not supported\n",
+ state->base.crtc_w, state->base.crtc_h);
return -EINVAL;
}
- stride = roundup_pow_of_two(crtc_w) * 4;
- if (obj->base.size < stride * crtc_h) {
+ stride = roundup_pow_of_two(state->base.crtc_w) * 4;
+ if (obj->base.size < stride * state->base.crtc_h) {
DRM_DEBUG_KMS("buffer is too small\n");
return -ENOMEM;
}
- if (fb == crtc->cursor->fb)
- return 0;
-
/* we only need to pin inside GTT if cursor is non-phy */
mutex_lock(&dev->struct_mutex);
if (!INTEL_INFO(dev)->cursor_needs_physical && obj->tiling_mode) {
@@ -12121,113 +12205,84 @@ intel_check_cursor_plane(struct drm_plane *plane,
}
mutex_unlock(&dev->struct_mutex);
+finish:
+ if (intel_crtc->active) {
+ if (intel_crtc->cursor_width != state->base.crtc_w)
+ intel_crtc->atomic.update_wm = true;
+
+ intel_crtc->atomic.fb_bits |=
+ INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe);
+ }
+
return ret;
}
-static int
+static void
intel_commit_cursor_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct drm_crtc *crtc = state->crtc;
- struct drm_framebuffer *fb = state->fb;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_crtc *crtc = state->base.crtc;
+ struct drm_device *dev = plane->dev;
+ struct intel_crtc *intel_crtc;
struct intel_plane *intel_plane = to_intel_plane(plane);
- struct intel_framebuffer *intel_fb = to_intel_framebuffer(fb);
- struct drm_i915_gem_object *obj = intel_fb->obj;
- int crtc_w, crtc_h;
-
- crtc->cursor_x = state->orig_dst.x1;
- crtc->cursor_y = state->orig_dst.y1;
-
- intel_plane->crtc_x = state->orig_dst.x1;
- intel_plane->crtc_y = state->orig_dst.y1;
- intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
- intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
- intel_plane->src_x = state->orig_src.x1;
- intel_plane->src_y = state->orig_src.y1;
- intel_plane->src_w = drm_rect_width(&state->orig_src);
- intel_plane->src_h = drm_rect_height(&state->orig_src);
- intel_plane->obj = obj;
-
- if (fb != crtc->cursor->fb) {
- crtc_w = drm_rect_width(&state->orig_dst);
- crtc_h = drm_rect_height(&state->orig_dst);
- return intel_crtc_cursor_set_obj(crtc, obj, crtc_w, crtc_h);
- } else {
- intel_crtc_update_cursor(crtc, state->visible);
-
- intel_frontbuffer_flip(crtc->dev,
- INTEL_FRONTBUFFER_CURSOR(intel_crtc->pipe));
-
- return 0;
- }
-}
-
-static int
-intel_cursor_plane_update(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h)
-{
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_plane_state state;
- int ret;
+ struct drm_i915_gem_object *obj = intel_fb_obj(state->base.fb);
+ uint32_t addr;
- state.crtc = crtc;
- state.fb = fb;
+ crtc = crtc ? crtc : plane->crtc;
+ intel_crtc = to_intel_crtc(crtc);
- /* sample coordinates in 16.16 fixed point */
- state.src.x1 = src_x;
- state.src.x2 = src_x + src_w;
- state.src.y1 = src_y;
- state.src.y2 = src_y + src_h;
+ plane->fb = state->base.fb;
+ crtc->cursor_x = state->base.crtc_x;
+ crtc->cursor_y = state->base.crtc_y;
- /* integer pixels */
- state.dst.x1 = crtc_x;
- state.dst.x2 = crtc_x + crtc_w;
- state.dst.y1 = crtc_y;
- state.dst.y2 = crtc_y + crtc_h;
+ intel_plane->obj = obj;
- state.clip.x1 = 0;
- state.clip.y1 = 0;
- state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
- state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
+ if (intel_crtc->cursor_bo == obj)
+ goto update;
- state.orig_src = state.src;
- state.orig_dst = state.dst;
+ if (!obj)
+ addr = 0;
+ else if (!INTEL_INFO(dev)->cursor_needs_physical)
+ addr = i915_gem_obj_ggtt_offset(obj);
+ else
+ addr = obj->phys_handle->busaddr;
- ret = intel_check_cursor_plane(plane, &state);
- if (ret)
- return ret;
+ intel_crtc->cursor_addr = addr;
+ intel_crtc->cursor_bo = obj;
+update:
+ intel_crtc->cursor_width = state->base.crtc_w;
+ intel_crtc->cursor_height = state->base.crtc_h;
- return intel_commit_cursor_plane(plane, &state);
+ if (intel_crtc->active)
+ intel_crtc_update_cursor(crtc, state->visible);
}
-static const struct drm_plane_funcs intel_cursor_plane_funcs = {
- .update_plane = intel_cursor_plane_update,
- .disable_plane = intel_cursor_plane_disable,
- .destroy = intel_plane_destroy,
- .set_property = intel_plane_set_property,
-};
-
static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
int pipe)
{
struct intel_plane *cursor;
+ struct intel_plane_state *state;
cursor = kzalloc(sizeof(*cursor), GFP_KERNEL);
if (cursor == NULL)
return NULL;
+ state = intel_create_plane_state(&cursor->base);
+ if (!state) {
+ kfree(cursor);
+ return NULL;
+ }
+ cursor->base.state = &state->base;
+
cursor->can_scale = false;
cursor->max_downscale = 1;
cursor->pipe = pipe;
cursor->plane = pipe;
- cursor->rotation = BIT(DRM_ROTATE_0);
+ cursor->check_plane = intel_check_cursor_plane;
+ cursor->commit_plane = intel_commit_cursor_plane;
drm_universal_plane_init(dev, &cursor->base, 0,
- &intel_cursor_plane_funcs,
+ &intel_plane_funcs,
intel_cursor_formats,
ARRAY_SIZE(intel_cursor_formats),
DRM_PLANE_TYPE_CURSOR);
@@ -12241,9 +12296,11 @@ static struct drm_plane *intel_cursor_plane_create(struct drm_device *dev,
if (dev->mode_config.rotation_property)
drm_object_attach_property(&cursor->base.base,
dev->mode_config.rotation_property,
- cursor->rotation);
+ state->base.rotation);
}
+ drm_plane_helper_add(&cursor->base, &intel_plane_helper_funcs);
+
return &cursor->base;
}
@@ -12251,6 +12308,7 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc;
+ struct intel_crtc_state *crtc_state = NULL;
struct drm_plane *primary = NULL;
struct drm_plane *cursor = NULL;
int i, ret;
@@ -12259,6 +12317,11 @@ static void intel_crtc_init(struct drm_device *dev, int pipe)
if (intel_crtc == NULL)
return;
+ crtc_state = kzalloc(sizeof(*crtc_state), GFP_KERNEL);
+ if (!crtc_state)
+ goto fail;
+ intel_crtc_set_state(intel_crtc, crtc_state);
+
primary = intel_primary_plane_create(dev, pipe);
if (!primary)
goto fail;
@@ -12311,6 +12374,7 @@ fail:
drm_plane_cleanup(primary);
if (cursor)
drm_plane_cleanup(cursor);
+ kfree(crtc_state);
kfree(intel_crtc);
}
@@ -12383,28 +12447,6 @@ static bool has_edp_a(struct drm_device *dev)
return true;
}
-const char *intel_output_name(int output)
-{
- static const char *names[] = {
- [INTEL_OUTPUT_UNUSED] = "Unused",
- [INTEL_OUTPUT_ANALOG] = "Analog",
- [INTEL_OUTPUT_DVO] = "DVO",
- [INTEL_OUTPUT_SDVO] = "SDVO",
- [INTEL_OUTPUT_LVDS] = "LVDS",
- [INTEL_OUTPUT_TVOUT] = "TV",
- [INTEL_OUTPUT_HDMI] = "HDMI",
- [INTEL_OUTPUT_DISPLAYPORT] = "DisplayPort",
- [INTEL_OUTPUT_EDP] = "eDP",
- [INTEL_OUTPUT_DSI] = "DSI",
- [INTEL_OUTPUT_UNKNOWN] = "Unknown",
- };
-
- if (output < 0 || output >= ARRAY_SIZE(names) || !names[output])
- return "Invalid";
-
- return names[output];
-}
-
static bool intel_crt_present(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -12428,6 +12470,7 @@ static void intel_setup_outputs(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
+ struct drm_connector *connector;
bool dpd_is_edp = false;
intel_lvds_init(dev);
@@ -12491,14 +12534,16 @@ static void intel_setup_outputs(struct drm_device *dev)
* eDP ports. Consult the VBT as well as DP_DETECTED to
* detect eDP ports.
*/
- if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED)
+ if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIB) & SDVO_DETECTED &&
+ !intel_dp_is_edp(dev, PORT_B))
intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIB,
PORT_B);
if (I915_READ(VLV_DISPLAY_BASE + DP_B) & DP_DETECTED ||
intel_dp_is_edp(dev, PORT_B))
intel_dp_init(dev, VLV_DISPLAY_BASE + DP_B, PORT_B);
- if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED)
+ if (I915_READ(VLV_DISPLAY_BASE + GEN4_HDMIC) & SDVO_DETECTED &&
+ !intel_dp_is_edp(dev, PORT_C))
intel_hdmi_init(dev, VLV_DISPLAY_BASE + GEN4_HDMIC,
PORT_C);
if (I915_READ(VLV_DISPLAY_BASE + DP_C) & DP_DETECTED ||
@@ -12556,6 +12601,37 @@ static void intel_setup_outputs(struct drm_device *dev)
if (SUPPORTS_TV(dev))
intel_tv_init(dev);
+ /*
+ * FIXME: We don't have full atomic support yet, but we want to be
+ * able to enable/test plane updates via the atomic interface in the
+ * meantime. However as soon as we flip DRIVER_ATOMIC on, the DRM core
+ * will take some atomic codepaths to lookup properties during
+ * drmModeGetConnector() that unconditionally dereference
+ * connector->state.
+ *
+ * We create a dummy connector state here for each connector to ensure
+ * the DRM core doesn't try to dereference a NULL connector->state.
+ * The actual connector properties will never be updated or contain
+ * useful information, but since we're doing this specifically for
+ * testing/debug of the plane operations (and only when a specific
+ * kernel module option is given), that shouldn't really matter.
+ *
+ * Once atomic support for crtc's + connectors lands, this loop should
+ * be removed since we'll be setting up real connector state, which
+ * will contain Intel-specific properties.
+ */
+ if (drm_core_check_feature(dev, DRIVER_ATOMIC)) {
+ list_for_each_entry(connector,
+ &dev->mode_config.connector_list,
+ head) {
+ if (!WARN_ON(connector->state)) {
+ connector->state =
+ kzalloc(sizeof(*connector->state),
+ GFP_KERNEL);
+ }
+ }
+ }
+
intel_psr_init(dev);
for_each_intel_encoder(dev, encoder) {
@@ -12696,8 +12772,8 @@ static int intel_framebuffer_init(struct drm_device *dev,
if (mode_cmd->offsets[0] != 0)
return -EINVAL;
- aligned_height = intel_align_height(dev, mode_cmd->height,
- obj->tiling_mode);
+ aligned_height = intel_fb_align_height(dev, mode_cmd->height,
+ obj->tiling_mode);
/* FIXME drm helper for size checks (especially planar formats)? */
if (obj->base.size < aligned_height * mode_cmd->pitches[0])
return -EINVAL;
@@ -12739,6 +12815,8 @@ static inline void intel_fbdev_output_poll_changed(struct drm_device *dev)
static const struct drm_mode_config_funcs intel_mode_funcs = {
.fb_create = intel_user_framebuffer_create,
.output_poll_changed = intel_fbdev_output_poll_changed,
+ .atomic_check = intel_atomic_check,
+ .atomic_commit = intel_atomic_commit,
};
/* Set up chip specific display functions */
@@ -12757,23 +12835,32 @@ static void intel_init_display(struct drm_device *dev)
else
dev_priv->display.find_dpll = i9xx_find_best_dpll;
- if (HAS_DDI(dev)) {
+ if (INTEL_INFO(dev)->gen >= 9) {
dev_priv->display.get_pipe_config = haswell_get_pipe_config;
- dev_priv->display.get_plane_config = ironlake_get_plane_config;
+ dev_priv->display.get_initial_plane_config =
+ skylake_get_initial_plane_config;
dev_priv->display.crtc_compute_clock =
haswell_crtc_compute_clock;
dev_priv->display.crtc_enable = haswell_crtc_enable;
dev_priv->display.crtc_disable = haswell_crtc_disable;
dev_priv->display.off = ironlake_crtc_off;
- if (INTEL_INFO(dev)->gen >= 9)
- dev_priv->display.update_primary_plane =
- skylake_update_primary_plane;
- else
- dev_priv->display.update_primary_plane =
- ironlake_update_primary_plane;
+ dev_priv->display.update_primary_plane =
+ skylake_update_primary_plane;
+ } else if (HAS_DDI(dev)) {
+ dev_priv->display.get_pipe_config = haswell_get_pipe_config;
+ dev_priv->display.get_initial_plane_config =
+ ironlake_get_initial_plane_config;
+ dev_priv->display.crtc_compute_clock =
+ haswell_crtc_compute_clock;
+ dev_priv->display.crtc_enable = haswell_crtc_enable;
+ dev_priv->display.crtc_disable = haswell_crtc_disable;
+ dev_priv->display.off = ironlake_crtc_off;
+ dev_priv->display.update_primary_plane =
+ ironlake_update_primary_plane;
} else if (HAS_PCH_SPLIT(dev)) {
dev_priv->display.get_pipe_config = ironlake_get_pipe_config;
- dev_priv->display.get_plane_config = ironlake_get_plane_config;
+ dev_priv->display.get_initial_plane_config =
+ ironlake_get_initial_plane_config;
dev_priv->display.crtc_compute_clock =
ironlake_crtc_compute_clock;
dev_priv->display.crtc_enable = ironlake_crtc_enable;
@@ -12783,7 +12870,8 @@ static void intel_init_display(struct drm_device *dev)
ironlake_update_primary_plane;
} else if (IS_VALLEYVIEW(dev)) {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
- dev_priv->display.get_plane_config = i9xx_get_plane_config;
+ dev_priv->display.get_initial_plane_config =
+ i9xx_get_initial_plane_config;
dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
dev_priv->display.crtc_enable = valleyview_crtc_enable;
dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -12792,7 +12880,8 @@ static void intel_init_display(struct drm_device *dev)
i9xx_update_primary_plane;
} else {
dev_priv->display.get_pipe_config = i9xx_get_pipe_config;
- dev_priv->display.get_plane_config = i9xx_get_plane_config;
+ dev_priv->display.get_initial_plane_config =
+ i9xx_get_initial_plane_config;
dev_priv->display.crtc_compute_clock = i9xx_crtc_compute_clock;
dev_priv->display.crtc_enable = i9xx_crtc_enable;
dev_priv->display.crtc_disable = i9xx_crtc_disable;
@@ -13019,6 +13108,9 @@ static struct intel_quirk intel_quirks[] = {
/* HP Chromebook 14 (Celeron 2955U) */
{ 0x0a06, 0x103c, 0x21ed, quirk_backlight_present },
+
+ /* Dell Chromebook 11 */
+ { 0x0a06, 0x1028, 0x0a35, quirk_backlight_present },
};
static void intel_init_quirks(struct drm_device *dev)
@@ -13147,7 +13239,7 @@ void intel_modeset_init(struct drm_device *dev)
intel_setup_outputs(dev);
/* Just in case the BIOS is doing something questionable. */
- intel_disable_fbc(dev);
+ intel_fbc_disable(dev);
drm_modeset_lock_all(dev);
intel_modeset_setup_hw_state(dev, false);
@@ -13164,8 +13256,8 @@ void intel_modeset_init(struct drm_device *dev)
* can even allow for smooth boot transitions if the BIOS
* fb is large enough for the active pipe configuration.
*/
- if (dev_priv->display.get_plane_config) {
- dev_priv->display.get_plane_config(crtc,
+ if (dev_priv->display.get_initial_plane_config) {
+ dev_priv->display.get_initial_plane_config(crtc,
&crtc->plane_config);
/*
* If the fb is shared between multiple heads, we'll
@@ -13229,7 +13321,7 @@ static void intel_sanitize_crtc(struct intel_crtc *crtc)
u32 reg;
/* Clear any frame start delays used for debugging left by the BIOS */
- reg = PIPECONF(crtc->config.cpu_transcoder);
+ reg = PIPECONF(crtc->config->cpu_transcoder);
I915_WRITE(reg, I915_READ(reg) & ~PIPECONF_FRAME_START_DELAY_MASK);
/* restore vblank interrupts to correct state */
@@ -13433,12 +13525,12 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
int i;
for_each_intel_crtc(dev, crtc) {
- memset(&crtc->config, 0, sizeof(crtc->config));
+ memset(crtc->config, 0, sizeof(*crtc->config));
- crtc->config.quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
+ crtc->config->quirks |= PIPE_CONFIG_QUIRK_INHERITED_MODE;
crtc->active = dev_priv->display.get_pipe_config(crtc,
- &crtc->config);
+ crtc->config);
crtc->base.enabled = crtc->active;
crtc->primary_enabled = primary_get_hw_state(crtc);
@@ -13475,7 +13567,7 @@ static void intel_modeset_readout_hw_state(struct drm_device *dev)
if (encoder->get_hw_state(encoder, &pipe)) {
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
encoder->base.crtc = &crtc->base;
- encoder->get_config(encoder, &crtc->config);
+ encoder->get_config(encoder, crtc->config);
} else {
encoder->base.crtc = NULL;
}
@@ -13525,7 +13617,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
*/
for_each_intel_crtc(dev, crtc) {
if (crtc->active && i915.fastboot) {
- intel_mode_from_pipe_config(&crtc->base.mode, &crtc->config);
+ intel_mode_from_pipe_config(&crtc->base.mode,
+ crtc->config);
DRM_DEBUG_KMS("[CRTC:%d] found active mode: ",
crtc->base.base.id);
drm_mode_debug_printmodeline(&crtc->base.mode);
@@ -13540,7 +13633,8 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
for_each_pipe(dev_priv, pipe) {
crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
intel_sanitize_crtc(crtc);
- intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
+ intel_dump_pipe_config(crtc, crtc->config,
+ "[setup_hw_state]");
}
for (i = 0; i < dev_priv->num_shared_dpll; i++) {
@@ -13664,7 +13758,7 @@ void intel_modeset_cleanup(struct drm_device *dev)
intel_unregister_dsm_handler();
- intel_disable_fbc(dev);
+ intel_fbc_disable(dev);
ironlake_teardown_rc6(dev);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 5cecc20efa71..a74aaf9242b9 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -31,6 +31,7 @@
#include <linux/notifier.h>
#include <linux/reboot.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
@@ -1074,7 +1075,7 @@ intel_dp_connector_unregister(struct intel_connector *intel_connector)
}
static void
-skl_edp_set_pll_config(struct intel_crtc_config *pipe_config, int link_bw)
+skl_edp_set_pll_config(struct intel_crtc_state *pipe_config, int link_bw)
{
u32 ctrl1;
@@ -1101,7 +1102,7 @@ skl_edp_set_pll_config(struct intel_crtc_config *pipe_config, int link_bw)
}
static void
-hsw_dp_set_ddi_pll_sel(struct intel_crtc_config *pipe_config, int link_bw)
+hsw_dp_set_ddi_pll_sel(struct intel_crtc_state *pipe_config, int link_bw)
{
switch (link_bw) {
case DP_LINK_BW_1_62:
@@ -1118,7 +1119,7 @@ hsw_dp_set_ddi_pll_sel(struct intel_crtc_config *pipe_config, int link_bw)
static void
intel_dp_set_clock(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config, int link_bw)
+ struct intel_crtc_state *pipe_config, int link_bw)
{
struct drm_device *dev = encoder->base.dev;
const struct dp_link_dpll *divisor = NULL;
@@ -1151,11 +1152,11 @@ intel_dp_set_clock(struct intel_encoder *encoder,
bool
intel_dp_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *intel_crtc = encoder->new_crtc;
@@ -1269,7 +1270,7 @@ found:
&pipe_config->dp_m_n);
if (intel_connector->panel.downclock_mode != NULL &&
- intel_dp->drrs_state.type == SEAMLESS_DRRS_SUPPORT) {
+ dev_priv->drrs.type == SEAMLESS_DRRS_SUPPORT) {
pipe_config->has_drrs = true;
intel_link_compute_m_n(bpp, lane_count,
intel_connector->panel.downclock_mode->clock,
@@ -1295,11 +1296,12 @@ static void ironlake_set_pll_cpu_edp(struct intel_dp *intel_dp)
struct drm_i915_private *dev_priv = dev->dev_private;
u32 dpa_ctl;
- DRM_DEBUG_KMS("eDP PLL enable for clock %d\n", crtc->config.port_clock);
+ DRM_DEBUG_KMS("eDP PLL enable for clock %d\n",
+ crtc->config->port_clock);
dpa_ctl = I915_READ(DP_A);
dpa_ctl &= ~DP_PLL_FREQ_MASK;
- if (crtc->config.port_clock == 162000) {
+ if (crtc->config->port_clock == 162000) {
/* For a long time we've carried around a ILK-DevA w/a for the
* 160MHz clock. If we're really unlucky, it's still required.
*/
@@ -1324,7 +1326,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
enum port port = dp_to_dig_port(intel_dp)->port;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
/*
* There are four kinds of DP registers:
@@ -1352,7 +1354,7 @@ static void intel_dp_prepare(struct intel_encoder *encoder)
intel_dp->DP |= DP_VOLTAGE_0_4 | DP_PRE_EMPHASIS_0;
intel_dp->DP |= DP_PORT_WIDTH(intel_dp->lane_count);
- if (crtc->config.has_audio)
+ if (crtc->config->has_audio)
intel_dp->DP |= DP_AUDIO_OUTPUT_ENABLE;
/* Split out the IBX/CPU vs CPT settings */
@@ -1558,7 +1560,7 @@ void intel_edp_panel_vdd_on(struct intel_dp *intel_dp)
vdd = edp_panel_vdd_on(intel_dp);
pps_unlock(intel_dp);
- WARN(!vdd, "eDP port %c VDD already requested on\n",
+ I915_STATE_WARN(!vdd, "eDP port %c VDD already requested on\n",
port_name(dp_to_dig_port(intel_dp)->port));
}
@@ -1642,7 +1644,7 @@ static void edp_panel_vdd_off(struct intel_dp *intel_dp, bool sync)
if (!is_edp(intel_dp))
return;
- WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
+ I915_STATE_WARN(!intel_dp->want_panel_vdd, "eDP port %c VDD not forced on",
port_name(dp_to_dig_port(intel_dp)->port));
intel_dp->want_panel_vdd = false;
@@ -2013,7 +2015,7 @@ static bool intel_dp_get_hw_state(struct intel_encoder *encoder,
}
static void intel_dp_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
u32 tmp, flags = 0;
@@ -2050,7 +2052,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
flags |= DRM_MODE_FLAG_NVSYNC;
}
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
if (!HAS_PCH_SPLIT(dev) && !IS_VALLEYVIEW(dev) &&
tmp & DP_COLOR_RANGE_16_235)
@@ -2073,7 +2075,7 @@ static void intel_dp_get_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv->dev) && port != PORT_A)
ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = dotclock;
if (is_edp(intel_dp) && dev_priv->vbt.edp_bpp &&
pipe_config->pipe_bpp > dev_priv->vbt.edp_bpp) {
@@ -2102,9 +2104,12 @@ static void intel_disable_dp(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- if (crtc->config.has_audio)
+ if (crtc->config->has_audio)
intel_audio_codec_disable(encoder);
+ if (HAS_PSR(dev) && !HAS_DDI(dev))
+ intel_psr_disable(intel_dp);
+
/* Make sure the panel is off before trying to change the mode. But also
* ensure that we have vdd while we switch off the panel. */
intel_edp_panel_vdd_on(intel_dp);
@@ -2309,7 +2314,7 @@ static void intel_enable_dp(struct intel_encoder *encoder)
intel_dp_complete_link_train(intel_dp);
intel_dp_stop_link_train(intel_dp);
- if (crtc->config.has_audio) {
+ if (crtc->config->has_audio) {
DRM_DEBUG_DRIVER("Enabling DP audio on pipe %c\n",
pipe_name(crtc->pipe));
intel_audio_codec_enable(encoder);
@@ -2329,6 +2334,7 @@ static void vlv_enable_dp(struct intel_encoder *encoder)
struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
intel_edp_backlight_on(intel_dp);
+ intel_psr_enable(intel_dp);
}
static void g4x_pre_enable_dp(struct intel_encoder *encoder)
@@ -3515,8 +3521,6 @@ intel_dp_link_down(struct intel_dp *intel_dp)
enum port port = intel_dig_port->port;
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc =
- to_intel_crtc(intel_dig_port->base.base.crtc);
uint32_t DP = intel_dp->DP;
if (WARN_ON(HAS_DDI(dev)))
@@ -3541,8 +3545,6 @@ intel_dp_link_down(struct intel_dp *intel_dp)
if (HAS_PCH_IBX(dev) &&
I915_READ(intel_dp->output_reg) & DP_PIPEB_SELECT) {
- struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
-
/* Hardware workaround: leaving our transcoder select
* set to transcoder B while it's off will prevent the
* corresponding HDMI output on transcoder A.
@@ -3553,18 +3555,7 @@ intel_dp_link_down(struct intel_dp *intel_dp)
*/
DP &= ~DP_PIPEB_SELECT;
I915_WRITE(intel_dp->output_reg, DP);
-
- /* Changes to enable or select take place the vblank
- * after being written.
- */
- if (WARN_ON(crtc == NULL)) {
- /* We should never try to disable a port without a crtc
- * attached. For paranoia keep the code around for a
- * bit. */
- POSTING_READ(intel_dp->output_reg);
- msleep(50);
- } else
- intel_wait_for_vblank(dev, intel_crtc->pipe);
+ POSTING_READ(intel_dp->output_reg);
}
DP &= ~DP_AUDIO_OUTPUT_ENABLE;
@@ -3769,7 +3760,7 @@ go_again:
intel_dp_stop_link_train(intel_dp);
}
- DRM_DEBUG_KMS("got esi %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+ DRM_DEBUG_KMS("got esi %3ph\n", esi);
ret = drm_dp_mst_hpd_irq(&intel_dp->mst_mgr, esi, &handled);
if (handled) {
@@ -3785,7 +3776,7 @@ go_again:
bret = intel_dp_get_sink_irq_esi(intel_dp, esi);
if (bret == true) {
- DRM_DEBUG_KMS("got esi2 %02x %02x %02x\n", esi[0], esi[1], esi[2]);
+ DRM_DEBUG_KMS("got esi2 %3ph\n", esi);
goto go_again;
}
} else
@@ -4306,7 +4297,6 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
drm_dp_aux_unregister(&intel_dp->aux);
intel_dp_mst_encoder_cleanup(intel_dig_port);
- drm_encoder_cleanup(encoder);
if (is_edp(intel_dp)) {
cancel_delayed_work_sync(&intel_dp->panel_vdd_work);
/*
@@ -4322,6 +4312,7 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder)
intel_dp->edp_notifier.notifier_call = NULL;
}
}
+ drm_encoder_cleanup(encoder);
kfree(intel_dig_port);
}
@@ -4396,7 +4387,9 @@ static const struct drm_connector_funcs intel_dp_connector_funcs = {
.force = intel_dp_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_set_property,
+ .atomic_get_property = intel_connector_atomic_get_property,
.destroy = intel_dp_connector_destroy,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs intel_dp_connector_helper_funcs = {
@@ -4416,7 +4409,7 @@ intel_dp_hot_plug(struct intel_encoder *intel_encoder)
return;
}
-bool
+enum irqreturn
intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
{
struct intel_dp *intel_dp = &intel_dig_port->dp;
@@ -4424,7 +4417,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
enum intel_display_power_domain power_domain;
- bool ret = true;
+ enum irqreturn ret = IRQ_NONE;
if (intel_dig_port->base.type != INTEL_OUTPUT_EDP)
intel_dig_port->base.type = INTEL_OUTPUT_DISPLAYPORT;
@@ -4438,7 +4431,7 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
*/
DRM_DEBUG_KMS("ignoring long hpd on eDP port %c\n",
port_name(intel_dig_port->port));
- return false;
+ return IRQ_HANDLED;
}
DRM_DEBUG_KMS("got hpd irq on port %c - %s\n",
@@ -4483,7 +4476,9 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
drm_modeset_unlock(&dev->mode_config.connection_mutex);
}
}
- ret = false;
+
+ ret = IRQ_HANDLED;
+
goto put_power;
mst_fail:
/* if we were in MST mode, and device is not there get out of MST mode */
@@ -4741,39 +4736,34 @@ intel_dp_init_panel_power_sequencer_registers(struct drm_device *dev,
I915_READ(pp_div_reg));
}
-void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
+static void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_encoder *encoder;
- struct intel_dp *intel_dp = NULL;
- struct intel_crtc_config *config = NULL;
+ struct intel_digital_port *dig_port = NULL;
+ struct intel_dp *intel_dp = dev_priv->drrs.dp;
+ struct intel_crtc_state *config = NULL;
struct intel_crtc *intel_crtc = NULL;
- struct intel_connector *intel_connector = dev_priv->drrs.connector;
u32 reg, val;
- enum edp_drrs_refresh_rate_type index = DRRS_HIGH_RR;
+ enum drrs_refresh_rate_type index = DRRS_HIGH_RR;
if (refresh_rate <= 0) {
DRM_DEBUG_KMS("Refresh rate should be positive non-zero.\n");
return;
}
- if (intel_connector == NULL) {
- DRM_DEBUG_KMS("DRRS supported for eDP only.\n");
+ if (intel_dp == NULL) {
+ DRM_DEBUG_KMS("DRRS not supported.\n");
return;
}
/*
- * FIXME: This needs proper synchronization with psr state. But really
- * hard to tell without seeing the user of this function of this code.
- * Check locking and ordering once that lands.
+ * FIXME: This needs proper synchronization with psr state for some
+ * platforms that cannot have PSR and DRRS enabled at the same time.
*/
- if (INTEL_INFO(dev)->gen < 8 && intel_psr_is_enabled(dev)) {
- DRM_DEBUG_KMS("DRRS is disabled as PSR is enabled\n");
- return;
- }
- encoder = intel_attached_encoder(&intel_connector->base);
- intel_dp = enc_to_intel_dp(&encoder->base);
+ dig_port = dp_to_dig_port(intel_dp);
+ encoder = &dig_port->base;
intel_crtc = encoder->new_crtc;
if (!intel_crtc) {
@@ -4781,17 +4771,18 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
return;
}
- config = &intel_crtc->config;
+ config = intel_crtc->config;
- if (intel_dp->drrs_state.type < SEAMLESS_DRRS_SUPPORT) {
+ if (dev_priv->drrs.type < SEAMLESS_DRRS_SUPPORT) {
DRM_DEBUG_KMS("Only Seamless DRRS supported.\n");
return;
}
- if (intel_connector->panel.downclock_mode->vrefresh == refresh_rate)
+ if (intel_dp->attached_connector->panel.downclock_mode->vrefresh ==
+ refresh_rate)
index = DRRS_LOW_RR;
- if (index == intel_dp->drrs_state.refresh_rate_type) {
+ if (index == dev_priv->drrs.refresh_rate_type) {
DRM_DEBUG_KMS(
"DRRS requested for previously set RR...ignoring\n");
return;
@@ -4803,7 +4794,7 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
}
if (INTEL_INFO(dev)->gen > 6 && INTEL_INFO(dev)->gen < 8) {
- reg = PIPECONF(intel_crtc->config.cpu_transcoder);
+ reg = PIPECONF(intel_crtc->config->cpu_transcoder);
val = I915_READ(reg);
if (index > DRRS_HIGH_RR) {
val |= PIPECONF_EDP_RR_MODE_SWITCH;
@@ -4814,30 +4805,154 @@ void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate)
I915_WRITE(reg, val);
}
+ dev_priv->drrs.refresh_rate_type = index;
+
+ DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+}
+
+void intel_edp_drrs_enable(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_crtc *crtc = dig_port->base.base.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ if (!intel_crtc->config->has_drrs) {
+ DRM_DEBUG_KMS("Panel doesn't support DRRS\n");
+ return;
+ }
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ if (WARN_ON(dev_priv->drrs.dp)) {
+ DRM_ERROR("DRRS already enabled\n");
+ goto unlock;
+ }
+
+ dev_priv->drrs.busy_frontbuffer_bits = 0;
+
+ dev_priv->drrs.dp = intel_dp;
+
+unlock:
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+void intel_edp_drrs_disable(struct intel_dp *intel_dp)
+{
+ struct drm_device *dev = intel_dp_to_dev(intel_dp);
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_crtc *crtc = dig_port->base.base.crtc;
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+
+ if (!intel_crtc->config->has_drrs)
+ return;
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ if (!dev_priv->drrs.dp) {
+ mutex_unlock(&dev_priv->drrs.mutex);
+ return;
+ }
+
+ if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR)
+ intel_dp_set_drrs_state(dev_priv->dev,
+ intel_dp->attached_connector->panel.
+ fixed_mode->vrefresh);
+
+ dev_priv->drrs.dp = NULL;
+ mutex_unlock(&dev_priv->drrs.mutex);
+
+ cancel_delayed_work_sync(&dev_priv->drrs.work);
+}
+
+static void intel_edp_drrs_downclock_work(struct work_struct *work)
+{
+ struct drm_i915_private *dev_priv =
+ container_of(work, typeof(*dev_priv), drrs.work.work);
+ struct intel_dp *intel_dp;
+
+ mutex_lock(&dev_priv->drrs.mutex);
+
+ intel_dp = dev_priv->drrs.dp;
+
+ if (!intel_dp)
+ goto unlock;
+
/*
- * mutex taken to ensure that there is no race between differnt
- * drrs calls trying to update refresh rate. This scenario may occur
- * in future when idleness detection based DRRS in kernel and
- * possible calls from user space to set differnt RR are made.
+ * The delayed work can race with an invalidate hence we need to
+ * recheck.
*/
- mutex_lock(&intel_dp->drrs_state.mutex);
+ if (dev_priv->drrs.busy_frontbuffer_bits)
+ goto unlock;
- intel_dp->drrs_state.refresh_rate_type = index;
+ if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR)
+ intel_dp_set_drrs_state(dev_priv->dev,
+ intel_dp->attached_connector->panel.
+ downclock_mode->vrefresh);
- mutex_unlock(&intel_dp->drrs_state.mutex);
+unlock:
- DRM_DEBUG_KMS("eDP Refresh Rate set to : %dHz\n", refresh_rate);
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+void intel_edp_drrs_invalidate(struct drm_device *dev,
+ unsigned frontbuffer_bits)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ enum pipe pipe;
+
+ if (!dev_priv->drrs.dp)
+ return;
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+ pipe = to_intel_crtc(crtc)->pipe;
+
+ if (dev_priv->drrs.refresh_rate_type == DRRS_LOW_RR) {
+ cancel_delayed_work_sync(&dev_priv->drrs.work);
+ intel_dp_set_drrs_state(dev_priv->dev,
+ dev_priv->drrs.dp->attached_connector->panel.
+ fixed_mode->vrefresh);
+ }
+
+ frontbuffer_bits &= INTEL_FRONTBUFFER_ALL_MASK(pipe);
+
+ dev_priv->drrs.busy_frontbuffer_bits |= frontbuffer_bits;
+ mutex_unlock(&dev_priv->drrs.mutex);
+}
+
+void intel_edp_drrs_flush(struct drm_device *dev,
+ unsigned frontbuffer_bits)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc;
+ enum pipe pipe;
+
+ if (!dev_priv->drrs.dp)
+ return;
+
+ mutex_lock(&dev_priv->drrs.mutex);
+ crtc = dp_to_dig_port(dev_priv->drrs.dp)->base.base.crtc;
+ pipe = to_intel_crtc(crtc)->pipe;
+ dev_priv->drrs.busy_frontbuffer_bits &= ~frontbuffer_bits;
+
+ cancel_delayed_work_sync(&dev_priv->drrs.work);
+
+ if (dev_priv->drrs.refresh_rate_type != DRRS_LOW_RR &&
+ !dev_priv->drrs.busy_frontbuffer_bits)
+ schedule_delayed_work(&dev_priv->drrs.work,
+ msecs_to_jiffies(1000));
+ mutex_unlock(&dev_priv->drrs.mutex);
}
static struct drm_display_mode *
-intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
- struct intel_connector *intel_connector,
- struct drm_display_mode *fixed_mode)
+intel_dp_drrs_init(struct intel_connector *intel_connector,
+ struct drm_display_mode *fixed_mode)
{
struct drm_connector *connector = &intel_connector->base;
- struct intel_dp *intel_dp = &intel_dig_port->dp;
- struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_device *dev = connector->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct drm_display_mode *downclock_mode = NULL;
@@ -4859,13 +4974,13 @@ intel_dp_drrs_init(struct intel_digital_port *intel_dig_port,
return NULL;
}
- dev_priv->drrs.connector = intel_connector;
+ INIT_DELAYED_WORK(&dev_priv->drrs.work, intel_edp_drrs_downclock_work);
- mutex_init(&intel_dp->drrs_state.mutex);
+ mutex_init(&dev_priv->drrs.mutex);
- intel_dp->drrs_state.type = dev_priv->vbt.drrs_type;
+ dev_priv->drrs.type = dev_priv->vbt.drrs_type;
- intel_dp->drrs_state.refresh_rate_type = DRRS_HIGH_RR;
+ dev_priv->drrs.refresh_rate_type = DRRS_HIGH_RR;
DRM_DEBUG_KMS("seamless DRRS supported for eDP panel.\n");
return downclock_mode;
}
@@ -4885,7 +5000,7 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
struct edid *edid;
enum pipe pipe = INVALID_PIPE;
- intel_dp->drrs_state.type = DRRS_NOT_SUPPORTED;
+ dev_priv->drrs.type = DRRS_NOT_SUPPORTED;
if (!is_edp(intel_dp))
return true;
@@ -4934,7 +5049,6 @@ static bool intel_edp_init_connector(struct intel_dp *intel_dp,
if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
fixed_mode = drm_mode_duplicate(dev, scan);
downclock_mode = intel_dp_drrs_init(
- intel_dig_port,
intel_connector, fixed_mode);
break;
}
@@ -5086,7 +5200,7 @@ intel_dp_init_connector(struct intel_digital_port *intel_dig_port,
intel_dp_aux_init(intel_dp, intel_connector);
/* init MST on ports that can support it */
- if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
+ if (IS_HASWELL(dev) || IS_BROADWELL(dev) || INTEL_INFO(dev)->gen >= 9) {
if (port == PORT_B || port == PORT_C || port == PORT_D) {
intel_dp_mst_encoder_init(intel_dig_port,
intel_connector->base.base.id);
diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c
index 7f8c6a66680a..9f67a379a9a5 100644
--- a/drivers/gpu/drm/i915/intel_dp_mst.c
+++ b/drivers/gpu/drm/i915/intel_dp_mst.c
@@ -26,11 +26,12 @@
#include <drm/drmP.h>
#include "i915_drv.h"
#include "intel_drv.h"
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc_helper.h>
#include <drm/drm_edid.h>
static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
struct intel_digital_port *intel_dig_port = intel_mst->primary;
@@ -38,7 +39,7 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder,
struct drm_device *dev = encoder->base.dev;
int bpp;
int lane_count, slots;
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct intel_connector *found = NULL, *intel_connector;
int mst_pbn;
@@ -157,7 +158,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
if (intel_dp->active_mst_links == 0) {
enum port port = intel_ddi_get_encoder_port(encoder);
- I915_WRITE(PORT_CLK_SEL(port), intel_crtc->config.ddi_pll_sel);
+ I915_WRITE(PORT_CLK_SEL(port),
+ intel_crtc->config->ddi_pll_sel);
intel_ddi_init_dp_buf_reg(&intel_dig_port->base);
@@ -170,7 +172,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder)
}
ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr,
- intel_mst->port, intel_crtc->config.pbn, &slots);
+ intel_mst->port,
+ intel_crtc->config->pbn, &slots);
if (ret == false) {
DRM_ERROR("failed to allocate vcpi\n");
return;
@@ -216,14 +219,14 @@ static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder,
}
static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base);
struct intel_digital_port *intel_dig_port = intel_mst->primary;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- enum transcoder cpu_transcoder = crtc->config.cpu_transcoder;
+ enum transcoder cpu_transcoder = pipe_config->cpu_transcoder;
u32 temp, flags = 0;
pipe_config->has_dp_encoder = true;
@@ -254,7 +257,7 @@ static void intel_dp_mst_enc_get_config(struct intel_encoder *encoder,
default:
break;
}
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
intel_dp_get_m_n(crtc, pipe_config);
intel_ddi_clock_get(&intel_dig_port->base, pipe_config);
@@ -311,7 +314,9 @@ static const struct drm_connector_funcs intel_dp_mst_connector_funcs = {
.detect = intel_dp_mst_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_dp_mst_set_property,
+ .atomic_get_property = intel_connector_atomic_get_property,
.destroy = intel_dp_mst_connector_destroy,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static int intel_dp_mst_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 3b40a17b8852..eef79ccd0b7c 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -143,7 +143,7 @@ struct intel_encoder {
bool connectors_active;
void (*hot_plug)(struct intel_encoder *);
bool (*compute_config)(struct intel_encoder *,
- struct intel_crtc_config *);
+ struct intel_crtc_state *);
void (*pre_pll_enable)(struct intel_encoder *);
void (*pre_enable)(struct intel_encoder *);
void (*enable)(struct intel_encoder *);
@@ -159,7 +159,7 @@ struct intel_encoder {
* pre-filled the pipe config. Note that intel_encoder->base.crtc must
* be set correctly before calling this function. */
void (*get_config)(struct intel_encoder *,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
/*
* Called during system suspend after all pending requests for the
* encoder are flushed (for example for DP AUX transactions) and
@@ -244,23 +244,28 @@ typedef struct dpll {
} intel_clock_t;
struct intel_plane_state {
- struct drm_crtc *crtc;
- struct drm_framebuffer *fb;
+ struct drm_plane_state base;
struct drm_rect src;
struct drm_rect dst;
struct drm_rect clip;
- struct drm_rect orig_src;
- struct drm_rect orig_dst;
bool visible;
+
+ /*
+ * used only for sprite planes to determine when to implicitly
+ * enable/disable the primary plane
+ */
+ bool hides_primary;
};
-struct intel_plane_config {
- bool tiled;
+struct intel_initial_plane_config {
+ unsigned int tiling;
int size;
u32 base;
};
-struct intel_crtc_config {
+struct intel_crtc_state {
+ struct drm_crtc_state base;
+
/**
* quirks - bitfield with hw state readout quirks
*
@@ -273,16 +278,6 @@ struct intel_crtc_config {
#define PIPE_CONFIG_QUIRK_INHERITED_MODE (1<<1) /* mode inherited from firmware */
unsigned long quirks;
- /* User requested mode, only valid as a starting point to
- * compute adjusted_mode, except in the case of (S)DVO where
- * it's also for the output timings of the (S)DVO chip.
- * adjusted_mode will then correspond to the S(DVO) chip's
- * preferred input timings. */
- struct drm_display_mode requested_mode;
- /* Actual pipe timings ie. what we program into the pipe timing
- * registers. adjusted_mode.crtc_clock is the pipe pixel clock. */
- struct drm_display_mode adjusted_mode;
-
/* Pipe source size (ie. panel fitter input size)
* All planes will be positioned inside this space,
* and get clipped at the edges. */
@@ -406,8 +401,7 @@ struct intel_pipe_wm {
};
struct intel_mmio_flip {
- u32 seqno;
- struct intel_engine_cs *ring;
+ struct drm_i915_gem_request *req;
struct work_struct work;
};
@@ -417,6 +411,32 @@ struct skl_pipe_wm {
uint32_t linetime;
};
+/*
+ * Tracking of operations that need to be performed at the beginning/end of an
+ * atomic commit, outside the atomic section where interrupts are disabled.
+ * These are generally operations that grab mutexes or might otherwise sleep
+ * and thus can't be run with interrupts disabled.
+ */
+struct intel_crtc_atomic_commit {
+ /* vblank evasion */
+ bool evade;
+ unsigned start_vbl_count;
+
+ /* Sleepable operations to perform before commit */
+ bool wait_for_flips;
+ bool disable_fbc;
+ bool pre_disable_primary;
+ bool update_wm;
+ unsigned disabled_planes;
+
+ /* Sleepable operations to perform after commit */
+ unsigned fb_bits;
+ bool wait_vblank;
+ bool update_fbc;
+ bool post_enable_primary;
+ unsigned update_sprite_watermarks;
+};
+
struct intel_crtc {
struct drm_crtc base;
enum pipe pipe;
@@ -448,9 +468,9 @@ struct intel_crtc {
uint32_t cursor_size;
uint32_t cursor_base;
- struct intel_plane_config plane_config;
- struct intel_crtc_config config;
- struct intel_crtc_config *new_config;
+ struct intel_initial_plane_config plane_config;
+ struct intel_crtc_state *config;
+ struct intel_crtc_state *new_config;
bool new_enabled;
/* reset counter value when the last flip was submitted */
@@ -470,6 +490,8 @@ struct intel_crtc {
int scanline_offset;
struct intel_mmio_flip mmio_flip;
+
+ struct intel_crtc_atomic_commit atomic;
};
struct intel_plane_wm_parameters {
@@ -487,11 +509,6 @@ struct intel_plane {
struct drm_i915_gem_object *obj;
bool can_scale;
int max_downscale;
- int crtc_x, crtc_y;
- unsigned int crtc_w, crtc_h;
- uint32_t src_x, src_y;
- uint32_t src_w, src_h;
- unsigned int rotation;
/* Since we need to change the watermarks before/after
* enabling/disabling the planes, we need to store the parameters here
@@ -500,6 +517,12 @@ struct intel_plane {
*/
struct intel_plane_wm_parameters wm;
+ /*
+ * NOTE: Do not place new plane state fields here (e.g., when adding
+ * new plane properties). New runtime state should now be placed in
+ * the intel_plane_state structure and accessed via drm_plane->state.
+ */
+
void (*update_plane)(struct drm_plane *plane,
struct drm_crtc *crtc,
struct drm_framebuffer *fb,
@@ -510,6 +533,10 @@ struct intel_plane {
uint32_t src_w, uint32_t src_h);
void (*disable_plane)(struct drm_plane *plane,
struct drm_crtc *crtc);
+ int (*check_plane)(struct drm_plane *plane,
+ struct intel_plane_state *state);
+ void (*commit_plane)(struct drm_plane *plane,
+ struct intel_plane_state *state);
int (*update_colorkey)(struct drm_plane *plane,
struct drm_intel_sprite_colorkey *key);
void (*get_colorkey)(struct drm_plane *plane,
@@ -540,6 +567,7 @@ struct cxsr_latency {
#define to_intel_encoder(x) container_of(x, struct intel_encoder, base)
#define to_intel_framebuffer(x) container_of(x, struct intel_framebuffer, base)
#define to_intel_plane(x) container_of(x, struct intel_plane, base)
+#define to_intel_plane_state(x) container_of(x, struct intel_plane_state, base)
#define intel_fb_obj(x) (x ? to_intel_framebuffer(x)->obj : NULL)
struct intel_hdmi {
@@ -564,17 +592,6 @@ struct intel_hdmi {
struct intel_dp_mst_encoder;
#define DP_MAX_DOWNSTREAM_PORTS 0x10
-/**
- * HIGH_RR is the highest eDP panel refresh rate read from EDID
- * LOW_RR is the lowest eDP panel refresh rate found from EDID
- * parsing for same resolution.
- */
-enum edp_drrs_refresh_rate_type {
- DRRS_HIGH_RR,
- DRRS_LOW_RR,
- DRRS_MAX_RR, /* RR count */
-};
-
struct intel_dp {
uint32_t output_reg;
uint32_t aux_ch_ctl_reg;
@@ -630,12 +647,6 @@ struct intel_dp {
bool has_aux_irq,
int send_bytes,
uint32_t aux_clock_divider);
- struct {
- enum drrs_support_type type;
- enum edp_drrs_refresh_rate_type refresh_rate_type;
- struct mutex mutex;
- } drrs_state;
-
};
struct intel_digital_port {
@@ -644,7 +655,7 @@ struct intel_digital_port {
u32 saved_port_bits;
struct intel_dp dp;
struct intel_hdmi hdmi;
- bool (*hpd_pulse)(struct intel_digital_port *, bool);
+ enum irqreturn (*hpd_pulse)(struct intel_digital_port *, bool);
};
struct intel_dp_mst_encoder {
@@ -708,8 +719,7 @@ struct intel_unpin_work {
#define INTEL_FLIP_COMPLETE 2
u32 flip_count;
u32 gtt_offset;
- struct intel_engine_cs *flip_queued_ring;
- u32 flip_queued_seqno;
+ struct drm_i915_gem_request *flip_queued_req;
int flip_queued_vblank;
int flip_ready_vblank;
bool enable_stall_check;
@@ -826,17 +836,18 @@ void intel_ddi_disable_transcoder_func(struct drm_i915_private *dev_priv,
enum transcoder cpu_transcoder);
void intel_ddi_enable_pipe_clock(struct intel_crtc *intel_crtc);
void intel_ddi_disable_pipe_clock(struct intel_crtc *intel_crtc);
-bool intel_ddi_pll_select(struct intel_crtc *crtc);
+bool intel_ddi_pll_select(struct intel_crtc *crtc,
+ struct intel_crtc_state *crtc_state);
void intel_ddi_set_pipe_settings(struct drm_crtc *crtc);
void intel_ddi_prepare_link_retrain(struct drm_encoder *encoder);
bool intel_ddi_connector_get_hw_state(struct intel_connector *intel_connector);
void intel_ddi_fdi_disable(struct drm_crtc *crtc);
void intel_ddi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
void intel_ddi_init_dp_buf_reg(struct intel_encoder *encoder);
void intel_ddi_clock_get(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
void intel_ddi_set_vc_payload_alloc(struct drm_crtc *crtc, bool state);
/* intel_frontbuffer.c */
@@ -866,6 +877,8 @@ void intel_frontbuffer_flip(struct drm_device *dev,
intel_frontbuffer_flush(dev, frontbuffer_bits);
}
+int intel_fb_align_height(struct drm_device *dev, int height,
+ unsigned int tiling);
void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
@@ -873,9 +886,11 @@ void intel_fb_obj_flush(struct drm_i915_gem_object *obj, bool retire);
void intel_init_audio(struct drm_device *dev);
void intel_audio_codec_enable(struct intel_encoder *encoder);
void intel_audio_codec_disable(struct intel_encoder *encoder);
+void i915_audio_component_init(struct drm_i915_private *dev_priv);
+void i915_audio_component_cleanup(struct drm_i915_private *dev_priv);
/* intel_display.c */
-const char *intel_output_name(int output);
+extern const struct drm_plane_funcs intel_plane_funcs;
bool intel_has_pending_fb_unpin(struct drm_device *dev);
int intel_pch_rawclk(struct drm_device *dev);
void intel_mark_busy(struct drm_device *dev);
@@ -926,6 +941,18 @@ void intel_prepare_page_flip(struct drm_device *dev, int plane);
void intel_finish_page_flip(struct drm_device *dev, int pipe);
void intel_finish_page_flip_plane(struct drm_device *dev, int plane);
void intel_check_page_flip(struct drm_device *dev, int pipe);
+int intel_prepare_plane_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb);
+void intel_cleanup_plane_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb);
+int intel_plane_atomic_get_property(struct drm_plane *plane,
+ const struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t *val);
+int intel_plane_atomic_set_property(struct drm_plane *plane,
+ struct drm_plane_state *state,
+ struct drm_property *property,
+ uint64_t val);
/* shared dpll functions */
struct intel_shared_dpll *intel_crtc_to_shared_dpll(struct intel_crtc *crtc);
@@ -934,7 +961,8 @@ void assert_shared_dpll(struct drm_i915_private *dev_priv,
bool state);
#define assert_shared_dpll_enabled(d, p) assert_shared_dpll(d, p, true)
#define assert_shared_dpll_disabled(d, p) assert_shared_dpll(d, p, false)
-struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc);
+struct intel_shared_dpll *intel_get_shared_dpll(struct intel_crtc *crtc,
+ struct intel_crtc_state *state);
void intel_put_shared_dpll(struct intel_crtc *crtc);
void vlv_force_pll_on(struct drm_device *dev, enum pipe pipe,
@@ -964,11 +992,11 @@ void intel_finish_reset(struct drm_device *dev);
void hsw_enable_pc8(struct drm_i915_private *dev_priv);
void hsw_disable_pc8(struct drm_i915_private *dev_priv);
void intel_dp_get_m_n(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
void intel_dp_set_m_n(struct intel_crtc *crtc);
int intel_dotclock_calculate(int link_freq, const struct intel_link_m_n *m_n);
void
-ironlake_check_encoder_dotclock(const struct intel_crtc_config *pipe_config,
+ironlake_check_encoder_dotclock(const struct intel_crtc_state *pipe_config,
int dotclock);
bool intel_crtc_active(struct drm_crtc *crtc);
void hsw_enable_ips(struct intel_crtc *crtc);
@@ -976,8 +1004,7 @@ void hsw_disable_ips(struct intel_crtc *crtc);
enum intel_display_power_domain
intel_display_port_power_domain(struct intel_encoder *intel_encoder);
void intel_mode_from_pipe_config(struct drm_display_mode *mode,
- struct intel_crtc_config *pipe_config);
-int intel_format_to_fourcc(int format);
+ struct intel_crtc_state *pipe_config);
void intel_crtc_wait_for_pending_flips(struct drm_crtc *crtc);
void intel_modeset_preclose(struct drm_device *dev, struct drm_file *file);
@@ -993,16 +1020,15 @@ void intel_dp_encoder_destroy(struct drm_encoder *encoder);
void intel_dp_check_link_status(struct intel_dp *intel_dp);
int intel_dp_sink_crc(struct intel_dp *intel_dp, u8 *crc);
bool intel_dp_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
bool intel_dp_is_edp(struct drm_device *dev, enum port port);
-bool intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
- bool long_hpd);
+enum irqreturn intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port,
+ bool long_hpd);
void intel_edp_backlight_on(struct intel_dp *intel_dp);
void intel_edp_backlight_off(struct intel_dp *intel_dp);
void intel_edp_panel_vdd_on(struct intel_dp *intel_dp);
void intel_edp_panel_on(struct intel_dp *intel_dp);
void intel_edp_panel_off(struct intel_dp *intel_dp);
-void intel_dp_set_drrs_state(struct drm_device *dev, int refresh_rate);
void intel_dp_add_properties(struct intel_dp *intel_dp, struct drm_connector *connector);
void intel_dp_mst_suspend(struct drm_device *dev);
void intel_dp_mst_resume(struct drm_device *dev);
@@ -1011,6 +1037,18 @@ void intel_dp_hot_plug(struct intel_encoder *intel_encoder);
void vlv_power_sequencer_reset(struct drm_i915_private *dev_priv);
uint32_t intel_dp_pack_aux(const uint8_t *src, int src_bytes);
void intel_dp_unpack_aux(uint32_t src, uint8_t *dst, int dst_bytes);
+int intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
+ struct drm_framebuffer *fb, int crtc_x, int crtc_y,
+ unsigned int crtc_w, unsigned int crtc_h,
+ uint32_t src_x, uint32_t src_y,
+ uint32_t src_w, uint32_t src_h);
+int intel_disable_plane(struct drm_plane *plane);
+void intel_plane_destroy(struct drm_plane *plane);
+void intel_edp_drrs_enable(struct intel_dp *intel_dp);
+void intel_edp_drrs_disable(struct intel_dp *intel_dp);
+void intel_edp_drrs_invalidate(struct drm_device *dev,
+ unsigned frontbuffer_bits);
+void intel_edp_drrs_flush(struct drm_device *dev, unsigned frontbuffer_bits);
/* intel_dp_mst.c */
int intel_dp_mst_encoder_init(struct intel_digital_port *intel_dig_port, int conn_id);
@@ -1054,13 +1092,20 @@ static inline void intel_fbdev_restore_mode(struct drm_device *dev)
}
#endif
+/* intel_fbc.c */
+bool intel_fbc_enabled(struct drm_device *dev);
+void intel_fbc_update(struct drm_device *dev);
+void intel_fbc_init(struct drm_i915_private *dev_priv);
+void intel_fbc_disable(struct drm_device *dev);
+void bdw_fbc_sw_flush(struct drm_device *dev, u32 value);
+
/* intel_hdmi.c */
void intel_hdmi_init(struct drm_device *dev, int hdmi_reg, enum port port);
void intel_hdmi_init_connector(struct intel_digital_port *intel_dig_port,
struct intel_connector *intel_connector);
struct intel_hdmi *enc_to_intel_hdmi(struct drm_encoder *encoder);
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config);
+ struct intel_crtc_state *pipe_config);
/* intel_lvds.c */
@@ -1084,6 +1129,7 @@ int intel_overlay_put_image(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int intel_overlay_attrs(struct drm_device *dev, void *data,
struct drm_file *file_priv);
+void intel_overlay_reset(struct drm_i915_private *dev_priv);
/* intel_panel.c */
@@ -1094,10 +1140,10 @@ void intel_panel_fini(struct intel_panel *panel);
void intel_fixed_panel_mode(const struct drm_display_mode *fixed_mode,
struct drm_display_mode *adjusted_mode);
void intel_pch_panel_fitting(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
int fitting_mode);
void intel_gmch_panel_fitting(struct intel_crtc *crtc,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
int fitting_mode);
void intel_panel_set_backlight_acpi(struct intel_connector *connector,
u32 level, u32 max);
@@ -1116,7 +1162,6 @@ void intel_backlight_unregister(struct drm_device *dev);
/* intel_psr.c */
-bool intel_psr_is_enabled(struct drm_device *dev);
void intel_psr_enable(struct intel_dp *intel_dp);
void intel_psr_disable(struct intel_dp *intel_dp);
void intel_psr_invalidate(struct drm_device *dev,
@@ -1160,8 +1205,6 @@ void intel_update_sprite_watermarks(struct drm_plane *plane,
bool enabled, bool scaled);
void intel_init_pm(struct drm_device *dev);
void intel_pm_setup(struct drm_device *dev);
-bool intel_fbc_enabled(struct drm_device *dev);
-void intel_update_fbc(struct drm_device *dev);
void intel_gpu_ips_init(struct drm_i915_private *dev_priv);
void intel_gpu_ips_teardown(void);
void intel_init_gt_powersave(struct drm_device *dev);
@@ -1192,7 +1235,6 @@ int intel_plane_set_property(struct drm_plane *plane,
struct drm_property *prop,
uint64_t val);
int intel_plane_restore(struct drm_plane *plane);
-void intel_plane_disable(struct drm_plane *plane);
int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv);
int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
@@ -1200,8 +1242,31 @@ int intel_sprite_get_colorkey(struct drm_device *dev, void *data,
bool intel_pipe_update_start(struct intel_crtc *crtc,
uint32_t *start_vbl_count);
void intel_pipe_update_end(struct intel_crtc *crtc, u32 start_vbl_count);
+void intel_post_enable_primary(struct drm_crtc *crtc);
+void intel_pre_disable_primary(struct drm_crtc *crtc);
/* intel_tv.c */
void intel_tv_init(struct drm_device *dev);
+/* intel_atomic.c */
+int intel_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state);
+int intel_atomic_commit(struct drm_device *dev,
+ struct drm_atomic_state *state,
+ bool async);
+int intel_connector_atomic_get_property(struct drm_connector *connector,
+ const struct drm_connector_state *state,
+ struct drm_property *property,
+ uint64_t *val);
+struct drm_crtc_state *intel_crtc_duplicate_state(struct drm_crtc *crtc);
+void intel_crtc_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state);
+
+/* intel_atomic_plane.c */
+struct intel_plane_state *intel_create_plane_state(struct drm_plane *plane);
+struct drm_plane_state *intel_plane_duplicate_state(struct drm_plane *plane);
+void intel_plane_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state);
+extern const struct drm_plane_helper_funcs intel_plane_helper_funcs;
+
#endif /* __INTEL_DRV_H__ */
diff --git a/drivers/gpu/drm/i915/intel_dsi.c b/drivers/gpu/drm/i915/intel_dsi.c
index 0b184079de14..10ab68457ca8 100644
--- a/drivers/gpu/drm/i915/intel_dsi.c
+++ b/drivers/gpu/drm/i915/intel_dsi.c
@@ -24,24 +24,219 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/i915_drm.h>
+#include <drm/drm_panel.h>
+#include <drm/drm_mipi_dsi.h>
#include <linux/slab.h>
#include "i915_drv.h"
#include "intel_drv.h"
#include "intel_dsi.h"
-#include "intel_dsi_cmd.h"
-/* the sub-encoders aka panel drivers */
-static const struct intel_dsi_device intel_dsi_devices[] = {
+static const struct {
+ u16 panel_id;
+ struct drm_panel * (*init)(struct intel_dsi *intel_dsi, u16 panel_id);
+} intel_dsi_drivers[] = {
{
.panel_id = MIPI_DSI_GENERIC_PANEL_ID,
- .name = "vbt-generic-dsi-vid-mode-display",
- .dev_ops = &vbt_generic_dsi_display_ops,
+ .init = vbt_panel_init,
},
};
+static void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi, enum port port)
+{
+ struct drm_encoder *encoder = &intel_dsi->base.base;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 mask;
+
+ mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
+ LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
+
+ if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & mask) == mask, 100))
+ DRM_ERROR("DPI FIFOs are not empty\n");
+}
+
+static void write_data(struct drm_i915_private *dev_priv, u32 reg,
+ const u8 *data, u32 len)
+{
+ u32 i, j;
+
+ for (i = 0; i < len; i += 4) {
+ u32 val = 0;
+
+ for (j = 0; j < min_t(u32, len - i, 4); j++)
+ val |= *data++ << 8 * j;
+
+ I915_WRITE(reg, val);
+ }
+}
+
+static void read_data(struct drm_i915_private *dev_priv, u32 reg,
+ u8 *data, u32 len)
+{
+ u32 i, j;
+
+ for (i = 0; i < len; i += 4) {
+ u32 val = I915_READ(reg);
+
+ for (j = 0; j < min_t(u32, len - i, 4); j++)
+ *data++ = val >> 8 * j;
+ }
+}
+
+static ssize_t intel_dsi_host_transfer(struct mipi_dsi_host *host,
+ const struct mipi_dsi_msg *msg)
+{
+ struct intel_dsi_host *intel_dsi_host = to_intel_dsi_host(host);
+ struct drm_device *dev = intel_dsi_host->intel_dsi->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ enum port port = intel_dsi_host->port;
+ struct mipi_dsi_packet packet;
+ ssize_t ret;
+ const u8 *header, *data;
+ u32 data_reg, data_mask, ctrl_reg, ctrl_mask;
+
+ ret = mipi_dsi_create_packet(&packet, msg);
+ if (ret < 0)
+ return ret;
+
+ header = packet.header;
+ data = packet.payload;
+
+ if (msg->flags & MIPI_DSI_MSG_USE_LPM) {
+ data_reg = MIPI_LP_GEN_DATA(port);
+ data_mask = LP_DATA_FIFO_FULL;
+ ctrl_reg = MIPI_LP_GEN_CTRL(port);
+ ctrl_mask = LP_CTRL_FIFO_FULL;
+ } else {
+ data_reg = MIPI_HS_GEN_DATA(port);
+ data_mask = HS_DATA_FIFO_FULL;
+ ctrl_reg = MIPI_HS_GEN_CTRL(port);
+ ctrl_mask = HS_CTRL_FIFO_FULL;
+ }
+
+ /* note: this is never true for reads */
+ if (packet.payload_length) {
+
+ if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & data_mask) == 0, 50))
+ DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
+
+ write_data(dev_priv, data_reg, packet.payload,
+ packet.payload_length);
+ }
+
+ if (msg->rx_len) {
+ I915_WRITE(MIPI_INTR_STAT(port), GEN_READ_DATA_AVAIL);
+ }
+
+ if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(port)) & ctrl_mask) == 0, 50)) {
+ DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
+ }
+
+ I915_WRITE(ctrl_reg, header[2] << 16 | header[1] << 8 | header[0]);
+
+ /* ->rx_len is set only for reads */
+ if (msg->rx_len) {
+ data_mask = GEN_READ_DATA_AVAIL;
+ if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & data_mask) == data_mask, 50))
+ DRM_ERROR("Timeout waiting for read data.\n");
+
+ read_data(dev_priv, data_reg, msg->rx_buf, msg->rx_len);
+ }
+
+ /* XXX: fix for reads and writes */
+ return 4 + packet.payload_length;
+}
+
+static int intel_dsi_host_attach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *dsi)
+{
+ return 0;
+}
+
+static int intel_dsi_host_detach(struct mipi_dsi_host *host,
+ struct mipi_dsi_device *dsi)
+{
+ return 0;
+}
+
+static const struct mipi_dsi_host_ops intel_dsi_host_ops = {
+ .attach = intel_dsi_host_attach,
+ .detach = intel_dsi_host_detach,
+ .transfer = intel_dsi_host_transfer,
+};
+
+static struct intel_dsi_host *intel_dsi_host_init(struct intel_dsi *intel_dsi,
+ enum port port)
+{
+ struct intel_dsi_host *host;
+ struct mipi_dsi_device *device;
+
+ host = kzalloc(sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return NULL;
+
+ host->base.ops = &intel_dsi_host_ops;
+ host->intel_dsi = intel_dsi;
+ host->port = port;
+
+ /*
+ * We should call mipi_dsi_host_register(&host->base) here, but we don't
+ * have a host->dev, and we don't have OF stuff either. So just use the
+ * dsi framework as a library and hope for the best. Create the dsi
+ * devices by ourselves here too. Need to be careful though, because we
+ * don't initialize any of the driver model devices here.
+ */
+ device = kzalloc(sizeof(*device), GFP_KERNEL);
+ if (!device) {
+ kfree(host);
+ return NULL;
+ }
+
+ device->host = &host->base;
+ host->device = device;
+
+ return host;
+}
+
+/*
+ * send a video mode command
+ *
+ * XXX: commands with data in MIPI_DPI_DATA?
+ */
+static int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs,
+ enum port port)
+{
+ struct drm_encoder *encoder = &intel_dsi->base.base;
+ struct drm_device *dev = encoder->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 mask;
+
+ /* XXX: pipe, hs */
+ if (hs)
+ cmd &= ~DPI_LP_MODE;
+ else
+ cmd |= DPI_LP_MODE;
+
+ /* clear bit */
+ I915_WRITE(MIPI_INTR_STAT(port), SPL_PKT_SENT_INTERRUPT);
+
+ /* XXX: old code skips write if control unchanged */
+ if (cmd == I915_READ(MIPI_DPI_CONTROL(port)))
+ DRM_ERROR("Same special packet %02x twice in a row.\n", cmd);
+
+ I915_WRITE(MIPI_DPI_CONTROL(port), cmd);
+
+ mask = SPL_PKT_SENT_INTERRUPT;
+ if (wait_for((I915_READ(MIPI_INTR_STAT(port)) & mask) == mask, 100))
+ DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
+
+ return 0;
+}
+
static void band_gap_reset(struct drm_i915_private *dev_priv)
{
mutex_lock(&dev_priv->dpio_lock);
@@ -56,12 +251,6 @@ static void band_gap_reset(struct drm_i915_private *dev_priv)
mutex_unlock(&dev_priv->dpio_lock);
}
-static struct intel_dsi *intel_attached_dsi(struct drm_connector *connector)
-{
- return container_of(intel_attached_encoder(connector),
- struct intel_dsi, base);
-}
-
static inline bool is_vid_mode(struct intel_dsi *intel_dsi)
{
return intel_dsi->operation_mode == INTEL_DSI_VIDEO_MODE;
@@ -78,14 +267,13 @@ static void intel_dsi_hot_plug(struct intel_encoder *encoder)
}
static bool intel_dsi_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *config)
+ struct intel_crtc_state *config)
{
struct intel_dsi *intel_dsi = container_of(encoder, struct intel_dsi,
base);
struct intel_connector *intel_connector = intel_dsi->attached_connector;
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
- struct drm_display_mode *adjusted_mode = &config->adjusted_mode;
- struct drm_display_mode *mode = &config->requested_mode;
+ struct drm_display_mode *adjusted_mode = &config->base.adjusted_mode;
DRM_DEBUG_KMS("\n");
@@ -95,18 +283,65 @@ static bool intel_dsi_compute_config(struct intel_encoder *encoder,
/* DSI uses short packets for sync events, so clear mode flags for DSI */
adjusted_mode->flags = 0;
- if (intel_dsi->dev.dev_ops->mode_fixup)
- return intel_dsi->dev.dev_ops->mode_fixup(&intel_dsi->dev,
- mode, adjusted_mode);
-
return true;
}
+static void intel_dsi_port_enable(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
+ u32 temp;
+
+ if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+ temp = I915_READ(VLV_CHICKEN_3);
+ temp &= ~PIXEL_OVERLAP_CNT_MASK |
+ intel_dsi->pixel_overlap <<
+ PIXEL_OVERLAP_CNT_SHIFT;
+ I915_WRITE(VLV_CHICKEN_3, temp);
+ }
+
+ for_each_dsi_port(port, intel_dsi->ports) {
+ temp = I915_READ(MIPI_PORT_CTRL(port));
+ temp &= ~LANE_CONFIGURATION_MASK;
+ temp &= ~DUAL_LINK_MODE_MASK;
+
+ if (intel_dsi->ports == ((1 << PORT_A) | (1 << PORT_C))) {
+ temp |= (intel_dsi->dual_link - 1)
+ << DUAL_LINK_MODE_SHIFT;
+ temp |= intel_crtc->pipe ?
+ LANE_CONFIGURATION_DUAL_LINK_B :
+ LANE_CONFIGURATION_DUAL_LINK_A;
+ }
+ /* assert ip_tg_enable signal */
+ I915_WRITE(MIPI_PORT_CTRL(port), temp | DPI_ENABLE);
+ POSTING_READ(MIPI_PORT_CTRL(port));
+ }
+}
+
+static void intel_dsi_port_disable(struct intel_encoder *encoder)
+{
+ struct drm_device *dev = encoder->base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
+ u32 temp;
+
+ for_each_dsi_port(port, intel_dsi->ports) {
+ /* de-assert ip_tg_enable signal */
+ temp = I915_READ(MIPI_PORT_CTRL(port));
+ I915_WRITE(MIPI_PORT_CTRL(port), temp & ~DPI_ENABLE);
+ POSTING_READ(MIPI_PORT_CTRL(port));
+ }
+}
+
static void intel_dsi_device_ready(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
- int pipe = intel_crtc->pipe;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
u32 val;
DRM_DEBUG_KMS("\n");
@@ -120,48 +355,51 @@ static void intel_dsi_device_ready(struct intel_encoder *encoder)
/* bandgap reset is needed after everytime we do power gate */
band_gap_reset(dev_priv);
- I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_ENTER);
- usleep_range(2500, 3000);
+ for_each_dsi_port(port, intel_dsi->ports) {
+
+ I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_ENTER);
+ usleep_range(2500, 3000);
- val = I915_READ(MIPI_PORT_CTRL(pipe));
- I915_WRITE(MIPI_PORT_CTRL(pipe), val | LP_OUTPUT_HOLD);
- usleep_range(1000, 1500);
+ /* Enable MIPI PHY transparent latch
+ * Common bit for both MIPI Port A & MIPI Port C
+ * No similar bit in MIPI Port C reg
+ */
+ val = I915_READ(MIPI_PORT_CTRL(PORT_A));
+ I915_WRITE(MIPI_PORT_CTRL(PORT_A), val | LP_OUTPUT_HOLD);
+ usleep_range(1000, 1500);
- I915_WRITE(MIPI_DEVICE_READY(pipe), ULPS_STATE_EXIT);
- usleep_range(2500, 3000);
+ I915_WRITE(MIPI_DEVICE_READY(port), ULPS_STATE_EXIT);
+ usleep_range(2500, 3000);
- I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY);
- usleep_range(2500, 3000);
+ I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY);
+ usleep_range(2500, 3000);
+ }
}
static void intel_dsi_enable(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
- int pipe = intel_crtc->pipe;
- u32 temp;
+ enum port port;
DRM_DEBUG_KMS("\n");
- if (is_cmd_mode(intel_dsi))
- I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(pipe), 8 * 4);
- else {
+ if (is_cmd_mode(intel_dsi)) {
+ for_each_dsi_port(port, intel_dsi->ports)
+ I915_WRITE(MIPI_MAX_RETURN_PKT_SIZE(port), 8 * 4);
+ } else {
msleep(20); /* XXX */
- dpi_send_cmd(intel_dsi, TURN_ON, DPI_LP_MODE_EN);
+ for_each_dsi_port(port, intel_dsi->ports)
+ dpi_send_cmd(intel_dsi, TURN_ON, false, port);
msleep(100);
- if (intel_dsi->dev.dev_ops->enable)
- intel_dsi->dev.dev_ops->enable(&intel_dsi->dev);
+ drm_panel_enable(intel_dsi->panel);
- wait_for_dsi_fifo_empty(intel_dsi);
+ for_each_dsi_port(port, intel_dsi->ports)
+ wait_for_dsi_fifo_empty(intel_dsi, port);
- /* assert ip_tg_enable signal */
- temp = I915_READ(MIPI_PORT_CTRL(pipe)) & ~LANE_CONFIGURATION_MASK;
- temp = temp | intel_dsi->port_bits;
- I915_WRITE(MIPI_PORT_CTRL(pipe), temp | DPI_ENABLE);
- POSTING_READ(MIPI_PORT_CTRL(pipe));
+ intel_dsi_port_enable(encoder);
}
}
@@ -172,6 +410,7 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
enum pipe pipe = intel_crtc->pipe;
+ enum port port;
u32 tmp;
DRM_DEBUG_KMS("\n");
@@ -183,7 +422,7 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
I915_WRITE(DPLL(pipe), tmp);
/* update the hw state for DPLL */
- intel_crtc->config.dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV |
+ intel_crtc->config->dpll_hw_state.dpll = DPLL_INTEGRATED_CLOCK_VLV |
DPLL_REFA_CLK_ENABLE_VLV;
tmp = I915_READ(DSPCLK_GATE_D);
@@ -195,13 +434,10 @@ static void intel_dsi_pre_enable(struct intel_encoder *encoder)
msleep(intel_dsi->panel_on_delay);
- if (intel_dsi->dev.dev_ops->panel_reset)
- intel_dsi->dev.dev_ops->panel_reset(&intel_dsi->dev);
+ drm_panel_prepare(intel_dsi->panel);
- if (intel_dsi->dev.dev_ops->send_otp_cmds)
- intel_dsi->dev.dev_ops->send_otp_cmds(&intel_dsi->dev);
-
- wait_for_dsi_fifo_empty(intel_dsi);
+ for_each_dsi_port(port, intel_dsi->ports)
+ wait_for_dsi_fifo_empty(intel_dsi, port);
/* Enable port in pre-enable phase itself because as per hw team
* recommendation, port should be enabled befor plane & pipe */
@@ -221,12 +457,14 @@ static void intel_dsi_enable_nop(struct intel_encoder *encoder)
static void intel_dsi_pre_disable(struct intel_encoder *encoder)
{
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
DRM_DEBUG_KMS("\n");
if (is_vid_mode(intel_dsi)) {
/* Send Shutdown command to the panel in LP mode */
- dpi_send_cmd(intel_dsi, SHUTDOWN, DPI_LP_MODE_EN);
+ for_each_dsi_port(port, intel_dsi->ports)
+ dpi_send_cmd(intel_dsi, SHUTDOWN, false, port);
msleep(10);
}
}
@@ -235,77 +473,85 @@ static void intel_dsi_disable(struct intel_encoder *encoder)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
- int pipe = intel_crtc->pipe;
+ enum port port;
u32 temp;
DRM_DEBUG_KMS("\n");
if (is_vid_mode(intel_dsi)) {
- wait_for_dsi_fifo_empty(intel_dsi);
-
- /* de-assert ip_tg_enable signal */
- temp = I915_READ(MIPI_PORT_CTRL(pipe));
- I915_WRITE(MIPI_PORT_CTRL(pipe), temp & ~DPI_ENABLE);
- POSTING_READ(MIPI_PORT_CTRL(pipe));
+ for_each_dsi_port(port, intel_dsi->ports)
+ wait_for_dsi_fifo_empty(intel_dsi, port);
+ intel_dsi_port_disable(encoder);
msleep(2);
}
- /* Panel commands can be sent when clock is in LP11 */
- I915_WRITE(MIPI_DEVICE_READY(pipe), 0x0);
-
- temp = I915_READ(MIPI_CTRL(pipe));
- temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
- I915_WRITE(MIPI_CTRL(pipe), temp |
- intel_dsi->escape_clk_div <<
- ESCAPE_CLOCK_DIVIDER_SHIFT);
+ for_each_dsi_port(port, intel_dsi->ports) {
+ /* Panel commands can be sent when clock is in LP11 */
+ I915_WRITE(MIPI_DEVICE_READY(port), 0x0);
- I915_WRITE(MIPI_EOT_DISABLE(pipe), CLOCKSTOP);
+ temp = I915_READ(MIPI_CTRL(port));
+ temp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+ I915_WRITE(MIPI_CTRL(port), temp |
+ intel_dsi->escape_clk_div <<
+ ESCAPE_CLOCK_DIVIDER_SHIFT);
- temp = I915_READ(MIPI_DSI_FUNC_PRG(pipe));
- temp &= ~VID_MODE_FORMAT_MASK;
- I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), temp);
+ I915_WRITE(MIPI_EOT_DISABLE(port), CLOCKSTOP);
- I915_WRITE(MIPI_DEVICE_READY(pipe), 0x1);
+ temp = I915_READ(MIPI_DSI_FUNC_PRG(port));
+ temp &= ~VID_MODE_FORMAT_MASK;
+ I915_WRITE(MIPI_DSI_FUNC_PRG(port), temp);
+ I915_WRITE(MIPI_DEVICE_READY(port), 0x1);
+ }
/* if disable packets are sent before sending shutdown packet then in
* some next enable sequence send turn on packet error is observed */
- if (intel_dsi->dev.dev_ops->disable)
- intel_dsi->dev.dev_ops->disable(&intel_dsi->dev);
+ drm_panel_disable(intel_dsi->panel);
- wait_for_dsi_fifo_empty(intel_dsi);
+ for_each_dsi_port(port, intel_dsi->ports)
+ wait_for_dsi_fifo_empty(intel_dsi, port);
}
static void intel_dsi_clear_device_ready(struct intel_encoder *encoder)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
- int pipe = intel_crtc->pipe;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ enum port port;
u32 val;
DRM_DEBUG_KMS("\n");
-
- I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER);
- usleep_range(2000, 2500);
-
- I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_EXIT);
- usleep_range(2000, 2500);
-
- I915_WRITE(MIPI_DEVICE_READY(pipe), DEVICE_READY | ULPS_STATE_ENTER);
- usleep_range(2000, 2500);
-
- if (wait_for(((I915_READ(MIPI_PORT_CTRL(pipe)) & AFE_LATCHOUT)
- == 0x00000), 30))
- DRM_ERROR("DSI LP not going Low\n");
-
- val = I915_READ(MIPI_PORT_CTRL(pipe));
- I915_WRITE(MIPI_PORT_CTRL(pipe), val & ~LP_OUTPUT_HOLD);
- usleep_range(1000, 1500);
-
- I915_WRITE(MIPI_DEVICE_READY(pipe), 0x00);
- usleep_range(2000, 2500);
+ for_each_dsi_port(port, intel_dsi->ports) {
+
+ I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+ ULPS_STATE_ENTER);
+ usleep_range(2000, 2500);
+
+ I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+ ULPS_STATE_EXIT);
+ usleep_range(2000, 2500);
+
+ I915_WRITE(MIPI_DEVICE_READY(port), DEVICE_READY |
+ ULPS_STATE_ENTER);
+ usleep_range(2000, 2500);
+
+ /* Wait till Clock lanes are in LP-00 state for MIPI Port A
+ * only. MIPI Port C has no similar bit for checking
+ */
+ if (wait_for(((I915_READ(MIPI_PORT_CTRL(PORT_A)) & AFE_LATCHOUT)
+ == 0x00000), 30))
+ DRM_ERROR("DSI LP not going Low\n");
+
+ /* Disable MIPI PHY transparent latch
+ * Common bit for both MIPI Port A & MIPI Port C
+ */
+ val = I915_READ(MIPI_PORT_CTRL(PORT_A));
+ I915_WRITE(MIPI_PORT_CTRL(PORT_A), val & ~LP_OUTPUT_HOLD);
+ usleep_range(1000, 1500);
+
+ I915_WRITE(MIPI_DEVICE_READY(port), 0x00);
+ usleep_range(2000, 2500);
+ }
vlv_disable_dsi_pll(encoder);
}
@@ -326,8 +572,7 @@ static void intel_dsi_post_disable(struct intel_encoder *encoder)
val &= ~DPOUNIT_CLOCK_GATE_DISABLE;
I915_WRITE(DSPCLK_GATE_D, val);
- if (intel_dsi->dev.dev_ops->disable_panel_power)
- intel_dsi->dev.dev_ops->disable_panel_power(&intel_dsi->dev);
+ drm_panel_unprepare(intel_dsi->panel);
msleep(intel_dsi->panel_off_delay);
msleep(intel_dsi->panel_pwr_cycle_delay);
@@ -337,9 +582,11 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
enum pipe *pipe)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(&encoder->base);
+ struct drm_device *dev = encoder->base.dev;
enum intel_display_power_domain power_domain;
- u32 port, func;
- enum pipe p;
+ u32 dpi_enabled, func;
+ enum port port;
DRM_DEBUG_KMS("\n");
@@ -348,13 +595,23 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
return false;
/* XXX: this only works for one DSI output */
- for (p = PIPE_A; p <= PIPE_B; p++) {
- port = I915_READ(MIPI_PORT_CTRL(p));
- func = I915_READ(MIPI_DSI_FUNC_PRG(p));
-
- if ((port & DPI_ENABLE) || (func & CMD_MODE_DATA_WIDTH_MASK)) {
- if (I915_READ(MIPI_DEVICE_READY(p)) & DEVICE_READY) {
- *pipe = p;
+ for_each_dsi_port(port, intel_dsi->ports) {
+ func = I915_READ(MIPI_DSI_FUNC_PRG(port));
+ dpi_enabled = I915_READ(MIPI_PORT_CTRL(port)) &
+ DPI_ENABLE;
+
+ /* Due to some hardware limitations on BYT, MIPI Port C DPI
+ * Enable bit does not get set. To check whether DSI Port C
+ * was enabled in BIOS, check the Pipe B enable bit
+ */
+ if (IS_VALLEYVIEW(dev) && !IS_CHERRYVIEW(dev) &&
+ (port == PORT_C))
+ dpi_enabled = I915_READ(PIPECONF(PIPE_B)) &
+ PIPECONF_ENABLE;
+
+ if (dpi_enabled || (func & CMD_MODE_DATA_WIDTH_MASK)) {
+ if (I915_READ(MIPI_DEVICE_READY(port)) & DEVICE_READY) {
+ *pipe = port == PORT_A ? PIPE_A : PIPE_B;
return true;
}
}
@@ -364,7 +621,7 @@ static bool intel_dsi_get_hw_state(struct intel_encoder *encoder,
}
static void intel_dsi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
u32 pclk;
DRM_DEBUG_KMS("\n");
@@ -379,7 +636,7 @@ static void intel_dsi_get_config(struct intel_encoder *encoder,
if (!pclk)
return;
- pipe_config->adjusted_mode.crtc_clock = pclk;
+ pipe_config->base.adjusted_mode.crtc_clock = pclk;
pipe_config->port_clock = pclk;
}
@@ -389,7 +646,6 @@ intel_dsi_mode_valid(struct drm_connector *connector,
{
struct intel_connector *intel_connector = to_intel_connector(connector);
struct drm_display_mode *fixed_mode = intel_connector->panel.fixed_mode;
- struct intel_dsi *intel_dsi = intel_attached_dsi(connector);
DRM_DEBUG_KMS("\n");
@@ -405,7 +661,7 @@ intel_dsi_mode_valid(struct drm_connector *connector,
return MODE_PANEL;
}
- return intel_dsi->dev.dev_ops->mode_valid(&intel_dsi->dev, mode);
+ return MODE_OK;
}
/* return txclkesc cycles in terms of divider and duration in us */
@@ -437,8 +693,8 @@ static void set_dsi_timings(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
- int pipe = intel_crtc->pipe;
- unsigned int bpp = intel_crtc->config.pipe_bpp;
+ enum port port;
+ unsigned int bpp = intel_crtc->config->pipe_bpp;
unsigned int lane_count = intel_dsi->lane_count;
u16 hactive, hfp, hsync, hbp, vfp, vsync, vbp;
@@ -448,6 +704,15 @@ static void set_dsi_timings(struct drm_encoder *encoder,
hsync = mode->hsync_end - mode->hsync_start;
hbp = mode->htotal - mode->hsync_end;
+ if (intel_dsi->dual_link) {
+ hactive /= 2;
+ if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+ hactive += intel_dsi->pixel_overlap;
+ hfp /= 2;
+ hsync /= 2;
+ hbp /= 2;
+ }
+
vfp = mode->vsync_start - mode->vdisplay;
vsync = mode->vsync_end - mode->vsync_start;
vbp = mode->vtotal - mode->vsync_end;
@@ -460,18 +725,20 @@ static void set_dsi_timings(struct drm_encoder *encoder,
intel_dsi->burst_mode_ratio);
hbp = txbyteclkhs(hbp, bpp, lane_count, intel_dsi->burst_mode_ratio);
- I915_WRITE(MIPI_HACTIVE_AREA_COUNT(pipe), hactive);
- I915_WRITE(MIPI_HFP_COUNT(pipe), hfp);
+ for_each_dsi_port(port, intel_dsi->ports) {
+ I915_WRITE(MIPI_HACTIVE_AREA_COUNT(port), hactive);
+ I915_WRITE(MIPI_HFP_COUNT(port), hfp);
- /* meaningful for video mode non-burst sync pulse mode only, can be zero
- * for non-burst sync events and burst modes */
- I915_WRITE(MIPI_HSYNC_PADDING_COUNT(pipe), hsync);
- I915_WRITE(MIPI_HBP_COUNT(pipe), hbp);
+ /* meaningful for video mode non-burst sync pulse mode only,
+ * can be zero for non-burst sync events and burst modes */
+ I915_WRITE(MIPI_HSYNC_PADDING_COUNT(port), hsync);
+ I915_WRITE(MIPI_HBP_COUNT(port), hbp);
- /* vertical values are in terms of lines */
- I915_WRITE(MIPI_VFP_COUNT(pipe), vfp);
- I915_WRITE(MIPI_VSYNC_PADDING_COUNT(pipe), vsync);
- I915_WRITE(MIPI_VBP_COUNT(pipe), vbp);
+ /* vertical values are in terms of lines */
+ I915_WRITE(MIPI_VFP_COUNT(port), vfp);
+ I915_WRITE(MIPI_VSYNC_PADDING_COUNT(port), vsync);
+ I915_WRITE(MIPI_VBP_COUNT(port), vbp);
+ }
}
static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
@@ -482,33 +749,44 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
- int pipe = intel_crtc->pipe;
- unsigned int bpp = intel_crtc->config.pipe_bpp;
+ &intel_crtc->config->base.adjusted_mode;
+ enum port port;
+ unsigned int bpp = intel_crtc->config->pipe_bpp;
u32 val, tmp;
+ u16 mode_hdisplay;
- DRM_DEBUG_KMS("pipe %c\n", pipe_name(pipe));
+ DRM_DEBUG_KMS("pipe %c\n", pipe_name(intel_crtc->pipe));
- /* escape clock divider, 20MHz, shared for A and C. device ready must be
- * off when doing this! txclkesc? */
- tmp = I915_READ(MIPI_CTRL(0));
- tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
- I915_WRITE(MIPI_CTRL(0), tmp | ESCAPE_CLOCK_DIVIDER_1);
+ mode_hdisplay = adjusted_mode->hdisplay;
- /* read request priority is per pipe */
- tmp = I915_READ(MIPI_CTRL(pipe));
- tmp &= ~READ_REQUEST_PRIORITY_MASK;
- I915_WRITE(MIPI_CTRL(pipe), tmp | READ_REQUEST_PRIORITY_HIGH);
+ if (intel_dsi->dual_link) {
+ mode_hdisplay /= 2;
+ if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+ mode_hdisplay += intel_dsi->pixel_overlap;
+ }
- /* XXX: why here, why like this? handling in irq handler?! */
- I915_WRITE(MIPI_INTR_STAT(pipe), 0xffffffff);
- I915_WRITE(MIPI_INTR_EN(pipe), 0xffffffff);
+ for_each_dsi_port(port, intel_dsi->ports) {
+ /* escape clock divider, 20MHz, shared for A and C.
+ * device ready must be off when doing this! txclkesc? */
+ tmp = I915_READ(MIPI_CTRL(PORT_A));
+ tmp &= ~ESCAPE_CLOCK_DIVIDER_MASK;
+ I915_WRITE(MIPI_CTRL(PORT_A), tmp | ESCAPE_CLOCK_DIVIDER_1);
- I915_WRITE(MIPI_DPHY_PARAM(pipe), intel_dsi->dphy_reg);
+ /* read request priority is per pipe */
+ tmp = I915_READ(MIPI_CTRL(port));
+ tmp &= ~READ_REQUEST_PRIORITY_MASK;
+ I915_WRITE(MIPI_CTRL(port), tmp | READ_REQUEST_PRIORITY_HIGH);
- I915_WRITE(MIPI_DPI_RESOLUTION(pipe),
- adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
- adjusted_mode->hdisplay << HORIZONTAL_ADDRESS_SHIFT);
+ /* XXX: why here, why like this? handling in irq handler?! */
+ I915_WRITE(MIPI_INTR_STAT(port), 0xffffffff);
+ I915_WRITE(MIPI_INTR_EN(port), 0xffffffff);
+
+ I915_WRITE(MIPI_DPHY_PARAM(port), intel_dsi->dphy_reg);
+
+ I915_WRITE(MIPI_DPI_RESOLUTION(port),
+ adjusted_mode->vdisplay << VERTICAL_ADDRESS_SHIFT |
+ mode_hdisplay << HORIZONTAL_ADDRESS_SHIFT);
+ }
set_dsi_timings(encoder, adjusted_mode);
@@ -522,95 +800,102 @@ static void intel_dsi_prepare(struct intel_encoder *intel_encoder)
/* XXX: cross-check bpp vs. pixel format? */
val |= intel_dsi->pixel_format;
}
- I915_WRITE(MIPI_DSI_FUNC_PRG(pipe), val);
-
- /* timeouts for recovery. one frame IIUC. if counter expires, EOT and
- * stop state. */
-
- /*
- * In burst mode, value greater than one DPI line Time in byte clock
- * (txbyteclkhs) To timeout this timer 1+ of the above said value is
- * recommended.
- *
- * In non-burst mode, Value greater than one DPI frame time in byte
- * clock(txbyteclkhs) To timeout this timer 1+ of the above said value
- * is recommended.
- *
- * In DBI only mode, value greater than one DBI frame time in byte
- * clock(txbyteclkhs) To timeout this timer 1+ of the above said value
- * is recommended.
- */
-
- if (is_vid_mode(intel_dsi) &&
- intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
- I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
- txbyteclkhs(adjusted_mode->htotal, bpp,
- intel_dsi->lane_count,
- intel_dsi->burst_mode_ratio) + 1);
- } else {
- I915_WRITE(MIPI_HS_TX_TIMEOUT(pipe),
- txbyteclkhs(adjusted_mode->vtotal *
- adjusted_mode->htotal,
- bpp, intel_dsi->lane_count,
- intel_dsi->burst_mode_ratio) + 1);
- }
- I915_WRITE(MIPI_LP_RX_TIMEOUT(pipe), intel_dsi->lp_rx_timeout);
- I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(pipe), intel_dsi->turn_arnd_val);
- I915_WRITE(MIPI_DEVICE_RESET_TIMER(pipe), intel_dsi->rst_timer_val);
-
- /* dphy stuff */
- /* in terms of low power clock */
- I915_WRITE(MIPI_INIT_COUNT(pipe), txclkesc(intel_dsi->escape_clk_div, 100));
-
- val = 0;
+ tmp = 0;
if (intel_dsi->eotp_pkt == 0)
- val |= EOT_DISABLE;
-
+ tmp |= EOT_DISABLE;
if (intel_dsi->clock_stop)
- val |= CLOCKSTOP;
-
- /* recovery disables */
- I915_WRITE(MIPI_EOT_DISABLE(pipe), val);
-
- /* in terms of low power clock */
- I915_WRITE(MIPI_INIT_COUNT(pipe), intel_dsi->init_count);
-
- /* in terms of txbyteclkhs. actual high to low switch +
- * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
- *
- * XXX: write MIPI_STOP_STATE_STALL?
- */
- I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(pipe),
- intel_dsi->hs_to_lp_count);
-
- /* XXX: low power clock equivalence in terms of byte clock. the number
- * of byte clocks occupied in one low power clock. based on txbyteclkhs
- * and txclkesc. txclkesc time / txbyteclk time * (105 +
- * MIPI_STOP_STATE_STALL) / 105.???
- */
- I915_WRITE(MIPI_LP_BYTECLK(pipe), intel_dsi->lp_byte_clk);
-
- /* the bw essential for transmitting 16 long packets containing 252
- * bytes meant for dcs write memory command is programmed in this
- * register in terms of byte clocks. based on dsi transfer rate and the
- * number of lanes configured the time taken to transmit 16 long packets
- * in a dsi stream varies. */
- I915_WRITE(MIPI_DBI_BW_CTRL(pipe), intel_dsi->bw_timer);
-
- I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(pipe),
- intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
- intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
-
- if (is_vid_mode(intel_dsi))
- /* Some panels might have resolution which is not a multiple of
- * 64 like 1366 x 768. Enable RANDOM resolution support for such
- * panels by default */
- I915_WRITE(MIPI_VIDEO_MODE_FORMAT(pipe),
- intel_dsi->video_frmt_cfg_bits |
- intel_dsi->video_mode_format |
- IP_TG_CONFIG |
- RANDOM_DPI_DISPLAY_RESOLUTION);
+ tmp |= CLOCKSTOP;
+
+ for_each_dsi_port(port, intel_dsi->ports) {
+ I915_WRITE(MIPI_DSI_FUNC_PRG(port), val);
+
+ /* timeouts for recovery. one frame IIUC. if counter expires,
+ * EOT and stop state. */
+
+ /*
+ * In burst mode, value greater than one DPI line Time in byte
+ * clock (txbyteclkhs) To timeout this timer 1+ of the above
+ * said value is recommended.
+ *
+ * In non-burst mode, Value greater than one DPI frame time in
+ * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
+ * said value is recommended.
+ *
+ * In DBI only mode, value greater than one DBI frame time in
+ * byte clock(txbyteclkhs) To timeout this timer 1+ of the above
+ * said value is recommended.
+ */
+
+ if (is_vid_mode(intel_dsi) &&
+ intel_dsi->video_mode_format == VIDEO_MODE_BURST) {
+ I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
+ txbyteclkhs(adjusted_mode->htotal, bpp,
+ intel_dsi->lane_count,
+ intel_dsi->burst_mode_ratio) + 1);
+ } else {
+ I915_WRITE(MIPI_HS_TX_TIMEOUT(port),
+ txbyteclkhs(adjusted_mode->vtotal *
+ adjusted_mode->htotal,
+ bpp, intel_dsi->lane_count,
+ intel_dsi->burst_mode_ratio) + 1);
+ }
+ I915_WRITE(MIPI_LP_RX_TIMEOUT(port), intel_dsi->lp_rx_timeout);
+ I915_WRITE(MIPI_TURN_AROUND_TIMEOUT(port),
+ intel_dsi->turn_arnd_val);
+ I915_WRITE(MIPI_DEVICE_RESET_TIMER(port),
+ intel_dsi->rst_timer_val);
+
+ /* dphy stuff */
+
+ /* in terms of low power clock */
+ I915_WRITE(MIPI_INIT_COUNT(port),
+ txclkesc(intel_dsi->escape_clk_div, 100));
+
+
+ /* recovery disables */
+ I915_WRITE(MIPI_EOT_DISABLE(port), val);
+
+ /* in terms of low power clock */
+ I915_WRITE(MIPI_INIT_COUNT(port), intel_dsi->init_count);
+
+ /* in terms of txbyteclkhs. actual high to low switch +
+ * MIPI_STOP_STATE_STALL * MIPI_LP_BYTECLK.
+ *
+ * XXX: write MIPI_STOP_STATE_STALL?
+ */
+ I915_WRITE(MIPI_HIGH_LOW_SWITCH_COUNT(port),
+ intel_dsi->hs_to_lp_count);
+
+ /* XXX: low power clock equivalence in terms of byte clock.
+ * the number of byte clocks occupied in one low power clock.
+ * based on txbyteclkhs and txclkesc.
+ * txclkesc time / txbyteclk time * (105 + MIPI_STOP_STATE_STALL
+ * ) / 105.???
+ */
+ I915_WRITE(MIPI_LP_BYTECLK(port), intel_dsi->lp_byte_clk);
+
+ /* the bw essential for transmitting 16 long packets containing
+ * 252 bytes meant for dcs write memory command is programmed in
+ * this register in terms of byte clocks. based on dsi transfer
+ * rate and the number of lanes configured the time taken to
+ * transmit 16 long packets in a dsi stream varies. */
+ I915_WRITE(MIPI_DBI_BW_CTRL(port), intel_dsi->bw_timer);
+
+ I915_WRITE(MIPI_CLK_LANE_SWITCH_TIME_CNT(port),
+ intel_dsi->clk_lp_to_hs_count << LP_HS_SSW_CNT_SHIFT |
+ intel_dsi->clk_hs_to_lp_count << HS_LP_PWR_SW_CNT_SHIFT);
+
+ if (is_vid_mode(intel_dsi))
+ /* Some panels might have resolution which is not a
+ * multiple of 64 like 1366 x 768. Enable RANDOM
+ * resolution support for such panels by default */
+ I915_WRITE(MIPI_VIDEO_MODE_FORMAT(port),
+ intel_dsi->video_frmt_cfg_bits |
+ intel_dsi->video_mode_format |
+ IP_TG_CONFIG |
+ RANDOM_DPI_DISPLAY_RESOLUTION);
+ }
}
static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
@@ -625,20 +910,7 @@ static void intel_dsi_pre_pll_enable(struct intel_encoder *encoder)
static enum drm_connector_status
intel_dsi_detect(struct drm_connector *connector, bool force)
{
- struct intel_dsi *intel_dsi = intel_attached_dsi(connector);
- struct intel_encoder *intel_encoder = &intel_dsi->base;
- enum intel_display_power_domain power_domain;
- enum drm_connector_status connector_status;
- struct drm_i915_private *dev_priv = intel_encoder->base.dev->dev_private;
-
- DRM_DEBUG_KMS("\n");
- power_domain = intel_display_port_power_domain(intel_encoder);
-
- intel_display_power_get(dev_priv, power_domain);
- connector_status = intel_dsi->dev.dev_ops->detect(&intel_dsi->dev);
- intel_display_power_put(dev_priv, power_domain);
-
- return connector_status;
+ return connector_status_connected;
}
static int intel_dsi_get_modes(struct drm_connector *connector)
@@ -664,7 +936,7 @@ static int intel_dsi_get_modes(struct drm_connector *connector)
return 1;
}
-static void intel_dsi_destroy(struct drm_connector *connector)
+static void intel_dsi_connector_destroy(struct drm_connector *connector)
{
struct intel_connector *intel_connector = to_intel_connector(connector);
@@ -674,8 +946,20 @@ static void intel_dsi_destroy(struct drm_connector *connector)
kfree(connector);
}
+static void intel_dsi_encoder_destroy(struct drm_encoder *encoder)
+{
+ struct intel_dsi *intel_dsi = enc_to_intel_dsi(encoder);
+
+ if (intel_dsi->panel) {
+ drm_panel_detach(intel_dsi->panel);
+ /* XXX: Logically this call belongs in the panel driver. */
+ drm_panel_remove(intel_dsi->panel);
+ }
+ intel_encoder_destroy(encoder);
+}
+
static const struct drm_encoder_funcs intel_dsi_funcs = {
- .destroy = intel_encoder_destroy,
+ .destroy = intel_dsi_encoder_destroy,
};
static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs = {
@@ -687,8 +971,10 @@ static const struct drm_connector_helper_funcs intel_dsi_connector_helper_funcs
static const struct drm_connector_funcs intel_dsi_connector_funcs = {
.dpms = intel_connector_dpms,
.detect = intel_dsi_detect,
- .destroy = intel_dsi_destroy,
+ .destroy = intel_dsi_connector_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .atomic_get_property = intel_connector_atomic_get_property,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
void intel_dsi_init(struct drm_device *dev)
@@ -698,9 +984,9 @@ void intel_dsi_init(struct drm_device *dev)
struct drm_encoder *encoder;
struct intel_connector *intel_connector;
struct drm_connector *connector;
- struct drm_display_mode *fixed_mode = NULL;
+ struct drm_display_mode *scan, *fixed_mode = NULL;
struct drm_i915_private *dev_priv = dev->dev_private;
- const struct intel_dsi_device *dsi;
+ enum port port;
unsigned int i;
DRM_DEBUG_KMS("\n");
@@ -748,22 +1034,43 @@ void intel_dsi_init(struct drm_device *dev)
intel_connector->get_hw_state = intel_connector_get_hw_state;
intel_connector->unregister = intel_connector_unregister;
- for (i = 0; i < ARRAY_SIZE(intel_dsi_devices); i++) {
- dsi = &intel_dsi_devices[i];
- intel_dsi->dev = *dsi;
+ /* Pipe A maps to MIPI DSI port A, pipe B maps to MIPI DSI port C */
+ if (dev_priv->vbt.dsi.config->dual_link) {
+ /* XXX: does dual link work on either pipe? */
+ intel_encoder->crtc_mask = (1 << PIPE_A);
+ intel_dsi->ports = ((1 << PORT_A) | (1 << PORT_C));
+ } else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIA) {
+ intel_encoder->crtc_mask = (1 << PIPE_A);
+ intel_dsi->ports = (1 << PORT_A);
+ } else if (dev_priv->vbt.dsi.port == DVO_PORT_MIPIC) {
+ intel_encoder->crtc_mask = (1 << PIPE_B);
+ intel_dsi->ports = (1 << PORT_C);
+ }
- if (dsi->dev_ops->init(&intel_dsi->dev))
+ /* Create a DSI host (and a device) for each port. */
+ for_each_dsi_port(port, intel_dsi->ports) {
+ struct intel_dsi_host *host;
+
+ host = intel_dsi_host_init(intel_dsi, port);
+ if (!host)
+ goto err;
+
+ intel_dsi->dsi_hosts[port] = host;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(intel_dsi_drivers); i++) {
+ intel_dsi->panel = intel_dsi_drivers[i].init(intel_dsi,
+ intel_dsi_drivers[i].panel_id);
+ if (intel_dsi->panel)
break;
}
- if (i == ARRAY_SIZE(intel_dsi_devices)) {
+ if (!intel_dsi->panel) {
DRM_DEBUG_KMS("no device found\n");
goto err;
}
intel_encoder->type = INTEL_OUTPUT_DSI;
- intel_encoder->crtc_mask = (1 << 0); /* XXX */
-
intel_encoder->cloneable = 0;
drm_connector_init(dev, connector, &intel_dsi_connector_funcs,
DRM_MODE_CONNECTOR_DSI);
@@ -778,13 +1085,23 @@ void intel_dsi_init(struct drm_device *dev)
drm_connector_register(connector);
- fixed_mode = dsi->dev_ops->get_modes(&intel_dsi->dev);
+ drm_panel_attach(intel_dsi->panel, connector);
+
+ mutex_lock(&dev->mode_config.mutex);
+ drm_panel_get_modes(intel_dsi->panel);
+ list_for_each_entry(scan, &connector->probed_modes, head) {
+ if ((scan->type & DRM_MODE_TYPE_PREFERRED)) {
+ fixed_mode = drm_mode_duplicate(dev, scan);
+ break;
+ }
+ }
+ mutex_unlock(&dev->mode_config.mutex);
+
if (!fixed_mode) {
DRM_DEBUG_KMS("no fixed mode\n");
goto err;
}
- fixed_mode->type |= DRM_MODE_TYPE_PREFERRED;
intel_panel_init(&intel_connector->panel, fixed_mode, NULL);
return;
diff --git a/drivers/gpu/drm/i915/intel_dsi.h b/drivers/gpu/drm/i915/intel_dsi.h
index 657eb5c1b9d8..2784ac442368 100644
--- a/drivers/gpu/drm/i915/intel_dsi.h
+++ b/drivers/gpu/drm/i915/intel_dsi.h
@@ -26,58 +26,27 @@
#include <drm/drmP.h>
#include <drm/drm_crtc.h>
+#include <drm/drm_mipi_dsi.h>
#include "intel_drv.h"
-struct intel_dsi_device {
- unsigned int panel_id;
- const char *name;
- const struct intel_dsi_dev_ops *dev_ops;
- void *dev_priv;
-};
-
-struct intel_dsi_dev_ops {
- bool (*init)(struct intel_dsi_device *dsi);
-
- void (*panel_reset)(struct intel_dsi_device *dsi);
-
- void (*disable_panel_power)(struct intel_dsi_device *dsi);
-
- /* one time programmable commands if needed */
- void (*send_otp_cmds)(struct intel_dsi_device *dsi);
-
- /* This callback must be able to assume DSI commands can be sent */
- void (*enable)(struct intel_dsi_device *dsi);
-
- /* This callback must be able to assume DSI commands can be sent */
- void (*disable)(struct intel_dsi_device *dsi);
-
- int (*mode_valid)(struct intel_dsi_device *dsi,
- struct drm_display_mode *mode);
-
- bool (*mode_fixup)(struct intel_dsi_device *dsi,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-
- void (*mode_set)(struct intel_dsi_device *dsi,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode);
-
- enum drm_connector_status (*detect)(struct intel_dsi_device *dsi);
+/* Dual Link support */
+#define DSI_DUAL_LINK_NONE 0
+#define DSI_DUAL_LINK_FRONT_BACK 1
+#define DSI_DUAL_LINK_PIXEL_ALT 2
- bool (*get_hw_state)(struct intel_dsi_device *dev);
-
- struct drm_display_mode *(*get_modes)(struct intel_dsi_device *dsi);
-
- void (*destroy) (struct intel_dsi_device *dsi);
-};
+struct intel_dsi_host;
struct intel_dsi {
struct intel_encoder base;
- struct intel_dsi_device dev;
+ struct drm_panel *panel;
+ struct intel_dsi_host *dsi_hosts[I915_MAX_PORTS];
struct intel_connector *attached_connector;
+ /* bit mask of ports being driven */
+ u16 ports;
+
/* if true, use HS mode, otherwise LP */
bool hs;
@@ -101,6 +70,8 @@ struct intel_dsi {
u8 clock_stop;
u8 escape_clk_div;
+ u8 dual_link;
+ u8 pixel_overlap;
u32 port_bits;
u32 bw_timer;
u32 dphy_reg;
@@ -127,6 +98,24 @@ struct intel_dsi {
u16 panel_pwr_cycle_delay;
};
+struct intel_dsi_host {
+ struct mipi_dsi_host base;
+ struct intel_dsi *intel_dsi;
+ enum port port;
+
+ /* our little hack */
+ struct mipi_dsi_device *device;
+};
+
+static inline struct intel_dsi_host *to_intel_dsi_host(struct mipi_dsi_host *h)
+{
+ return container_of(h, struct intel_dsi_host, base);
+}
+
+#define for_each_dsi_port(__port, __ports_mask) \
+ for ((__port) = PORT_A; (__port) < I915_MAX_PORTS; (__port)++) \
+ if ((__ports_mask) & (1 << (__port)))
+
static inline struct intel_dsi *enc_to_intel_dsi(struct drm_encoder *encoder)
{
return container_of(encoder, struct intel_dsi, base.base);
@@ -136,6 +125,6 @@ extern void vlv_enable_dsi_pll(struct intel_encoder *encoder);
extern void vlv_disable_dsi_pll(struct intel_encoder *encoder);
extern u32 vlv_get_dsi_pclk(struct intel_encoder *encoder, int pipe_bpp);
-extern struct intel_dsi_dev_ops vbt_generic_dsi_display_ops;
+struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id);
#endif /* _INTEL_DSI_H */
diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.c b/drivers/gpu/drm/i915/intel_dsi_cmd.c
deleted file mode 100644
index f4767fd2ebeb..000000000000
--- a/drivers/gpu/drm/i915/intel_dsi_cmd.c
+++ /dev/null
@@ -1,437 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Author: Jani Nikula <jani.nikula@intel.com>
- */
-
-#include <linux/export.h>
-#include <drm/drmP.h>
-#include <drm/drm_crtc.h>
-#include <video/mipi_display.h>
-#include "i915_drv.h"
-#include "intel_drv.h"
-#include "intel_dsi.h"
-#include "intel_dsi_cmd.h"
-
-/*
- * XXX: MIPI_DATA_ADDRESS, MIPI_DATA_LENGTH, MIPI_COMMAND_LENGTH, and
- * MIPI_COMMAND_ADDRESS registers.
- *
- * Apparently these registers provide a MIPI adapter level way to send (lots of)
- * commands and data to the receiver, without having to write the commands and
- * data to MIPI_{HS,LP}_GEN_{CTRL,DATA} registers word by word.
- *
- * Presumably for anything other than MIPI_DCS_WRITE_MEMORY_START and
- * MIPI_DCS_WRITE_MEMORY_CONTINUE (which are used to update the external
- * framebuffer in command mode displays) these are just an optimization that can
- * come later.
- *
- * For memory writes, these should probably be used for performance.
- */
-
-static void print_stat(struct intel_dsi *intel_dsi)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 val;
-
- val = I915_READ(MIPI_INTR_STAT(pipe));
-
-#define STAT_BIT(val, bit) (val) & (bit) ? " " #bit : ""
- DRM_DEBUG_KMS("MIPI_INTR_STAT(%d) = %08x"
- "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
- "\n", pipe, val,
- STAT_BIT(val, TEARING_EFFECT),
- STAT_BIT(val, SPL_PKT_SENT_INTERRUPT),
- STAT_BIT(val, GEN_READ_DATA_AVAIL),
- STAT_BIT(val, LP_GENERIC_WR_FIFO_FULL),
- STAT_BIT(val, HS_GENERIC_WR_FIFO_FULL),
- STAT_BIT(val, RX_PROT_VIOLATION),
- STAT_BIT(val, RX_INVALID_TX_LENGTH),
- STAT_BIT(val, ACK_WITH_NO_ERROR),
- STAT_BIT(val, TURN_AROUND_ACK_TIMEOUT),
- STAT_BIT(val, LP_RX_TIMEOUT),
- STAT_BIT(val, HS_TX_TIMEOUT),
- STAT_BIT(val, DPI_FIFO_UNDERRUN),
- STAT_BIT(val, LOW_CONTENTION),
- STAT_BIT(val, HIGH_CONTENTION),
- STAT_BIT(val, TXDSI_VC_ID_INVALID),
- STAT_BIT(val, TXDSI_DATA_TYPE_NOT_RECOGNISED),
- STAT_BIT(val, TXCHECKSUM_ERROR),
- STAT_BIT(val, TXECC_MULTIBIT_ERROR),
- STAT_BIT(val, TXECC_SINGLE_BIT_ERROR),
- STAT_BIT(val, TXFALSE_CONTROL_ERROR),
- STAT_BIT(val, RXDSI_VC_ID_INVALID),
- STAT_BIT(val, RXDSI_DATA_TYPE_NOT_REGOGNISED),
- STAT_BIT(val, RXCHECKSUM_ERROR),
- STAT_BIT(val, RXECC_MULTIBIT_ERROR),
- STAT_BIT(val, RXECC_SINGLE_BIT_ERROR),
- STAT_BIT(val, RXFALSE_CONTROL_ERROR),
- STAT_BIT(val, RXHS_RECEIVE_TIMEOUT_ERROR),
- STAT_BIT(val, RX_LP_TX_SYNC_ERROR),
- STAT_BIT(val, RXEXCAPE_MODE_ENTRY_ERROR),
- STAT_BIT(val, RXEOT_SYNC_ERROR),
- STAT_BIT(val, RXSOT_SYNC_ERROR),
- STAT_BIT(val, RXSOT_ERROR));
-#undef STAT_BIT
-}
-
-enum dsi_type {
- DSI_DCS,
- DSI_GENERIC,
-};
-
-/* enable or disable command mode hs transmissions */
-void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 temp;
- u32 mask = DBI_FIFO_EMPTY;
-
- if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 50))
- DRM_ERROR("Timeout waiting for DBI FIFO empty\n");
-
- temp = I915_READ(MIPI_HS_LP_DBI_ENABLE(pipe));
- temp &= DBI_HS_LP_MODE_MASK;
- I915_WRITE(MIPI_HS_LP_DBI_ENABLE(pipe), enable ? DBI_HS_MODE : DBI_LP_MODE);
-
- intel_dsi->hs = enable;
-}
-
-static int dsi_vc_send_short(struct intel_dsi *intel_dsi, int channel,
- u8 data_type, u16 data)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 ctrl_reg;
- u32 ctrl;
- u32 mask;
-
- DRM_DEBUG_KMS("channel %d, data_type %d, data %04x\n",
- channel, data_type, data);
-
- if (intel_dsi->hs) {
- ctrl_reg = MIPI_HS_GEN_CTRL(pipe);
- mask = HS_CTRL_FIFO_FULL;
- } else {
- ctrl_reg = MIPI_LP_GEN_CTRL(pipe);
- mask = LP_CTRL_FIFO_FULL;
- }
-
- if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50)) {
- DRM_ERROR("Timeout waiting for HS/LP CTRL FIFO !full\n");
- print_stat(intel_dsi);
- }
-
- /*
- * Note: This function is also used for long packets, with length passed
- * as data, since SHORT_PACKET_PARAM_SHIFT ==
- * LONG_PACKET_WORD_COUNT_SHIFT.
- */
- ctrl = data << SHORT_PACKET_PARAM_SHIFT |
- channel << VIRTUAL_CHANNEL_SHIFT |
- data_type << DATA_TYPE_SHIFT;
-
- I915_WRITE(ctrl_reg, ctrl);
-
- return 0;
-}
-
-static int dsi_vc_send_long(struct intel_dsi *intel_dsi, int channel,
- u8 data_type, const u8 *data, int len)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 data_reg;
- int i, j, n;
- u32 mask;
-
- DRM_DEBUG_KMS("channel %d, data_type %d, len %04x\n",
- channel, data_type, len);
-
- if (intel_dsi->hs) {
- data_reg = MIPI_HS_GEN_DATA(pipe);
- mask = HS_DATA_FIFO_FULL;
- } else {
- data_reg = MIPI_LP_GEN_DATA(pipe);
- mask = LP_DATA_FIFO_FULL;
- }
-
- if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == 0, 50))
- DRM_ERROR("Timeout waiting for HS/LP DATA FIFO !full\n");
-
- for (i = 0; i < len; i += n) {
- u32 val = 0;
- n = min_t(int, len - i, 4);
-
- for (j = 0; j < n; j++)
- val |= *data++ << 8 * j;
-
- I915_WRITE(data_reg, val);
- /* XXX: check for data fifo full, once that is set, write 4
- * dwords, then wait for not set, then continue. */
- }
-
- return dsi_vc_send_short(intel_dsi, channel, data_type, len);
-}
-
-static int dsi_vc_write_common(struct intel_dsi *intel_dsi,
- int channel, const u8 *data, int len,
- enum dsi_type type)
-{
- int ret;
-
- if (len == 0) {
- BUG_ON(type == DSI_GENERIC);
- ret = dsi_vc_send_short(intel_dsi, channel,
- MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM,
- 0);
- } else if (len == 1) {
- ret = dsi_vc_send_short(intel_dsi, channel,
- type == DSI_GENERIC ?
- MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM :
- MIPI_DSI_DCS_SHORT_WRITE, data[0]);
- } else if (len == 2) {
- ret = dsi_vc_send_short(intel_dsi, channel,
- type == DSI_GENERIC ?
- MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM :
- MIPI_DSI_DCS_SHORT_WRITE_PARAM,
- (data[1] << 8) | data[0]);
- } else {
- ret = dsi_vc_send_long(intel_dsi, channel,
- type == DSI_GENERIC ?
- MIPI_DSI_GENERIC_LONG_WRITE :
- MIPI_DSI_DCS_LONG_WRITE, data, len);
- }
-
- return ret;
-}
-
-int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
- const u8 *data, int len)
-{
- return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_DCS);
-}
-
-int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel,
- const u8 *data, int len)
-{
- return dsi_vc_write_common(intel_dsi, channel, data, len, DSI_GENERIC);
-}
-
-static int dsi_vc_dcs_send_read_request(struct intel_dsi *intel_dsi,
- int channel, u8 dcs_cmd)
-{
- return dsi_vc_send_short(intel_dsi, channel, MIPI_DSI_DCS_READ,
- dcs_cmd);
-}
-
-static int dsi_vc_generic_send_read_request(struct intel_dsi *intel_dsi,
- int channel, u8 *reqdata,
- int reqlen)
-{
- u16 data;
- u8 data_type;
-
- switch (reqlen) {
- case 0:
- data_type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
- data = 0;
- break;
- case 1:
- data_type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
- data = reqdata[0];
- break;
- case 2:
- data_type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
- data = (reqdata[1] << 8) | reqdata[0];
- break;
- default:
- BUG();
- }
-
- return dsi_vc_send_short(intel_dsi, channel, data_type, data);
-}
-
-static int dsi_read_data_return(struct intel_dsi *intel_dsi,
- u8 *buf, int buflen)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- int i, len = 0;
- u32 data_reg, val;
-
- if (intel_dsi->hs) {
- data_reg = MIPI_HS_GEN_DATA(pipe);
- } else {
- data_reg = MIPI_LP_GEN_DATA(pipe);
- }
-
- while (len < buflen) {
- val = I915_READ(data_reg);
- for (i = 0; i < 4 && len < buflen; i++, len++)
- buf[len] = val >> 8 * i;
- }
-
- return len;
-}
-
-int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
- u8 *buf, int buflen)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 mask;
- int ret;
-
- /*
- * XXX: should issue multiple read requests and reads if request is
- * longer than MIPI_MAX_RETURN_PKT_SIZE
- */
-
- I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL);
-
- ret = dsi_vc_dcs_send_read_request(intel_dsi, channel, dcs_cmd);
- if (ret)
- return ret;
-
- mask = GEN_READ_DATA_AVAIL;
- if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50))
- DRM_ERROR("Timeout waiting for read data.\n");
-
- ret = dsi_read_data_return(intel_dsi, buf, buflen);
- if (ret < 0)
- return ret;
-
- if (ret != buflen)
- return -EIO;
-
- return 0;
-}
-
-int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
- u8 *reqdata, int reqlen, u8 *buf, int buflen)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 mask;
- int ret;
-
- /*
- * XXX: should issue multiple read requests and reads if request is
- * longer than MIPI_MAX_RETURN_PKT_SIZE
- */
-
- I915_WRITE(MIPI_INTR_STAT(pipe), GEN_READ_DATA_AVAIL);
-
- ret = dsi_vc_generic_send_read_request(intel_dsi, channel, reqdata,
- reqlen);
- if (ret)
- return ret;
-
- mask = GEN_READ_DATA_AVAIL;
- if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 50))
- DRM_ERROR("Timeout waiting for read data.\n");
-
- ret = dsi_read_data_return(intel_dsi, buf, buflen);
- if (ret < 0)
- return ret;
-
- if (ret != buflen)
- return -EIO;
-
- return 0;
-}
-
-/*
- * send a video mode command
- *
- * XXX: commands with data in MIPI_DPI_DATA?
- */
-int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 mask;
-
- /* XXX: pipe, hs */
- if (hs)
- cmd &= ~DPI_LP_MODE;
- else
- cmd |= DPI_LP_MODE;
-
- /* clear bit */
- I915_WRITE(MIPI_INTR_STAT(pipe), SPL_PKT_SENT_INTERRUPT);
-
- /* XXX: old code skips write if control unchanged */
- if (cmd == I915_READ(MIPI_DPI_CONTROL(pipe)))
- DRM_ERROR("Same special packet %02x twice in a row.\n", cmd);
-
- I915_WRITE(MIPI_DPI_CONTROL(pipe), cmd);
-
- mask = SPL_PKT_SENT_INTERRUPT;
- if (wait_for((I915_READ(MIPI_INTR_STAT(pipe)) & mask) == mask, 100))
- DRM_ERROR("Video mode command 0x%08x send failed.\n", cmd);
-
- return 0;
-}
-
-void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi)
-{
- struct drm_encoder *encoder = &intel_dsi->base.base;
- struct drm_device *dev = encoder->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- enum pipe pipe = intel_crtc->pipe;
- u32 mask;
-
- mask = LP_CTRL_FIFO_EMPTY | HS_CTRL_FIFO_EMPTY |
- LP_DATA_FIFO_EMPTY | HS_DATA_FIFO_EMPTY;
-
- if (wait_for((I915_READ(MIPI_GEN_FIFO_STAT(pipe)) & mask) == mask, 100))
- DRM_ERROR("DPI FIFOs are not empty\n");
-}
diff --git a/drivers/gpu/drm/i915/intel_dsi_cmd.h b/drivers/gpu/drm/i915/intel_dsi_cmd.h
index 46aa1acc00eb..886779030f1a 100644
--- a/drivers/gpu/drm/i915/intel_dsi_cmd.h
+++ b/drivers/gpu/drm/i915/intel_dsi_cmd.h
@@ -33,81 +33,7 @@
#include "intel_drv.h"
#include "intel_dsi.h"
-#define DPI_LP_MODE_EN false
-#define DPI_HS_MODE_EN true
-
-void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable);
-
-int dsi_vc_dcs_write(struct intel_dsi *intel_dsi, int channel,
- const u8 *data, int len);
-
-int dsi_vc_generic_write(struct intel_dsi *intel_dsi, int channel,
- const u8 *data, int len);
-
-int dsi_vc_dcs_read(struct intel_dsi *intel_dsi, int channel, u8 dcs_cmd,
- u8 *buf, int buflen);
-
-int dsi_vc_generic_read(struct intel_dsi *intel_dsi, int channel,
- u8 *reqdata, int reqlen, u8 *buf, int buflen);
-
-int dpi_send_cmd(struct intel_dsi *intel_dsi, u32 cmd, bool hs);
-void wait_for_dsi_fifo_empty(struct intel_dsi *intel_dsi);
-
-/* XXX: questionable write helpers */
-static inline int dsi_vc_dcs_write_0(struct intel_dsi *intel_dsi,
- int channel, u8 dcs_cmd)
-{
- return dsi_vc_dcs_write(intel_dsi, channel, &dcs_cmd, 1);
-}
-
-static inline int dsi_vc_dcs_write_1(struct intel_dsi *intel_dsi,
- int channel, u8 dcs_cmd, u8 param)
-{
- u8 buf[2] = { dcs_cmd, param };
- return dsi_vc_dcs_write(intel_dsi, channel, buf, 2);
-}
-
-static inline int dsi_vc_generic_write_0(struct intel_dsi *intel_dsi,
- int channel)
-{
- return dsi_vc_generic_write(intel_dsi, channel, NULL, 0);
-}
-
-static inline int dsi_vc_generic_write_1(struct intel_dsi *intel_dsi,
- int channel, u8 param)
-{
- return dsi_vc_generic_write(intel_dsi, channel, &param, 1);
-}
-
-static inline int dsi_vc_generic_write_2(struct intel_dsi *intel_dsi,
- int channel, u8 param1, u8 param2)
-{
- u8 buf[2] = { param1, param2 };
- return dsi_vc_generic_write(intel_dsi, channel, buf, 2);
-}
-
-/* XXX: questionable read helpers */
-static inline int dsi_vc_generic_read_0(struct intel_dsi *intel_dsi,
- int channel, u8 *buf, int buflen)
-{
- return dsi_vc_generic_read(intel_dsi, channel, NULL, 0, buf, buflen);
-}
-
-static inline int dsi_vc_generic_read_1(struct intel_dsi *intel_dsi,
- int channel, u8 param, u8 *buf,
- int buflen)
-{
- return dsi_vc_generic_read(intel_dsi, channel, &param, 1, buf, buflen);
-}
-
-static inline int dsi_vc_generic_read_2(struct intel_dsi *intel_dsi,
- int channel, u8 param1, u8 param2,
- u8 *buf, int buflen)
-{
- u8 req[2] = { param1, param2 };
-
- return dsi_vc_generic_read(intel_dsi, channel, req, 2, buf, buflen);
-}
-
+void dsi_hs_mode_enable(struct intel_dsi *intel_dsi, bool enable,
+ enum port port);
#endif /* _INTEL_DSI_DSI_H */
diff --git a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
index f6bdd44069ce..d2cd8d5b27a1 100644
--- a/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
+++ b/drivers/gpu/drm/i915/intel_dsi_panel_vbt.c
@@ -28,6 +28,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include <drm/i915_drm.h>
+#include <drm/drm_panel.h>
#include <linux/slab.h>
#include <video/mipi_display.h>
#include <asm/intel-mid.h>
@@ -35,7 +36,16 @@
#include "i915_drv.h"
#include "intel_drv.h"
#include "intel_dsi.h"
-#include "intel_dsi_cmd.h"
+
+struct vbt_panel {
+ struct drm_panel panel;
+ struct intel_dsi *intel_dsi;
+};
+
+static inline struct vbt_panel *to_vbt_panel(struct drm_panel *panel)
+{
+ return container_of(panel, struct vbt_panel, panel);
+}
#define MIPI_TRANSFER_MODE_SHIFT 0
#define MIPI_VIRTUAL_CHANNEL_SHIFT 1
@@ -94,34 +104,59 @@ static struct gpio_table gtable[] = {
{ GPIO_NC_11_PCONF0, GPIO_NC_11_PAD, 0}
};
-static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data)
+static inline enum port intel_dsi_seq_port_to_port(u8 port)
{
- u8 type, byte, mode, vc, port;
- u16 len;
-
- byte = *data++;
- mode = (byte >> MIPI_TRANSFER_MODE_SHIFT) & 0x1;
- vc = (byte >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 0x3;
- port = (byte >> MIPI_PORT_SHIFT) & 0x3;
+ return port ? PORT_C : PORT_A;
+}
- /* LP or HS mode */
- intel_dsi->hs = mode;
+static const u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi,
+ const u8 *data)
+{
+ struct mipi_dsi_device *dsi_device;
+ u8 type, flags, seq_port;
+ u16 len;
+ enum port port;
- /* get packet type and increment the pointer */
+ flags = *data++;
type = *data++;
len = *((u16 *) data);
data += 2;
+ seq_port = (flags >> MIPI_PORT_SHIFT) & 3;
+
+ /* For DSI single link on Port A & C, the seq_port value which is
+ * parsed from Sequence Block#53 of VBT has been set to 0
+ * Now, read/write of packets for the DSI single link on Port A and
+ * Port C will based on the DVO port from VBT block 2.
+ */
+ if (intel_dsi->ports == (1 << PORT_C))
+ port = PORT_C;
+ else
+ port = intel_dsi_seq_port_to_port(seq_port);
+
+ dsi_device = intel_dsi->dsi_hosts[port]->device;
+ if (!dsi_device) {
+ DRM_DEBUG_KMS("no dsi device for port %c\n", port_name(port));
+ goto out;
+ }
+
+ if ((flags >> MIPI_TRANSFER_MODE_SHIFT) & 1)
+ dsi_device->mode_flags &= ~MIPI_DSI_MODE_LPM;
+ else
+ dsi_device->mode_flags |= MIPI_DSI_MODE_LPM;
+
+ dsi_device->channel = (flags >> MIPI_VIRTUAL_CHANNEL_SHIFT) & 3;
+
switch (type) {
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
- dsi_vc_generic_write_0(intel_dsi, vc);
+ mipi_dsi_generic_write(dsi_device, NULL, 0);
break;
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
- dsi_vc_generic_write_1(intel_dsi, vc, *data);
+ mipi_dsi_generic_write(dsi_device, data, 1);
break;
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
- dsi_vc_generic_write_2(intel_dsi, vc, *data, *(data + 1));
+ mipi_dsi_generic_write(dsi_device, data, 2);
break;
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
@@ -129,30 +164,31 @@ static u8 *mipi_exec_send_packet(struct intel_dsi *intel_dsi, u8 *data)
DRM_DEBUG_DRIVER("Generic Read not yet implemented or used\n");
break;
case MIPI_DSI_GENERIC_LONG_WRITE:
- dsi_vc_generic_write(intel_dsi, vc, data, len);
+ mipi_dsi_generic_write(dsi_device, data, len);
break;
case MIPI_DSI_DCS_SHORT_WRITE:
- dsi_vc_dcs_write_0(intel_dsi, vc, *data);
+ mipi_dsi_dcs_write_buffer(dsi_device, data, 1);
break;
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
- dsi_vc_dcs_write_1(intel_dsi, vc, *data, *(data + 1));
+ mipi_dsi_dcs_write_buffer(dsi_device, data, 2);
break;
case MIPI_DSI_DCS_READ:
DRM_DEBUG_DRIVER("DCS Read not yet implemented or used\n");
break;
case MIPI_DSI_DCS_LONG_WRITE:
- dsi_vc_dcs_write(intel_dsi, vc, data, len);
+ mipi_dsi_dcs_write_buffer(dsi_device, data, len);
break;
}
+out:
data += len;
return data;
}
-static u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, u8 *data)
+static const u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, const u8 *data)
{
- u32 delay = *((u32 *) data);
+ u32 delay = *((const u32 *) data);
usleep_range(delay, delay + 10);
data += 4;
@@ -160,7 +196,7 @@ static u8 *mipi_exec_delay(struct intel_dsi *intel_dsi, u8 *data)
return data;
}
-static u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, u8 *data)
+static const u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, const u8 *data)
{
u8 gpio, action;
u16 function, pad;
@@ -193,7 +229,8 @@ static u8 *mipi_exec_gpio(struct intel_dsi *intel_dsi, u8 *data)
return data;
}
-typedef u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi, u8 *data);
+typedef const u8 * (*fn_mipi_elem_exec)(struct intel_dsi *intel_dsi,
+ const u8 *data);
static const fn_mipi_elem_exec exec_elem[] = {
NULL, /* reserved */
mipi_exec_send_packet,
@@ -217,13 +254,12 @@ static const char * const seq_name[] = {
"MIPI_SEQ_DEASSERT_RESET"
};
-static void generic_exec_sequence(struct intel_dsi *intel_dsi, char *sequence)
+static void generic_exec_sequence(struct intel_dsi *intel_dsi, const u8 *data)
{
- u8 *data = sequence;
fn_mipi_elem_exec mipi_elem_exec;
int index;
- if (!sequence)
+ if (!data)
return;
DRM_DEBUG_DRIVER("Starting MIPI sequence - %s\n", seq_name[*data]);
@@ -256,14 +292,103 @@ static void generic_exec_sequence(struct intel_dsi *intel_dsi, char *sequence)
}
}
-static bool generic_init(struct intel_dsi_device *dsi)
+static int vbt_panel_prepare(struct drm_panel *panel)
+{
+ struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+ struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+ struct drm_device *dev = intel_dsi->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const u8 *sequence;
+
+ sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET];
+ generic_exec_sequence(intel_dsi, sequence);
+
+ sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
+ generic_exec_sequence(intel_dsi, sequence);
+
+ return 0;
+}
+
+static int vbt_panel_unprepare(struct drm_panel *panel)
+{
+ struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+ struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+ struct drm_device *dev = intel_dsi->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const u8 *sequence;
+
+ sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET];
+ generic_exec_sequence(intel_dsi, sequence);
+
+ return 0;
+}
+
+static int vbt_panel_enable(struct drm_panel *panel)
+{
+ struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+ struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+ struct drm_device *dev = intel_dsi->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const u8 *sequence;
+
+ sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON];
+ generic_exec_sequence(intel_dsi, sequence);
+
+ return 0;
+}
+
+static int vbt_panel_disable(struct drm_panel *panel)
+{
+ struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+ struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+ struct drm_device *dev = intel_dsi->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ const u8 *sequence;
+
+ sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_OFF];
+ generic_exec_sequence(intel_dsi, sequence);
+
+ return 0;
+}
+
+static int vbt_panel_get_modes(struct drm_panel *panel)
+{
+ struct vbt_panel *vbt_panel = to_vbt_panel(panel);
+ struct intel_dsi *intel_dsi = vbt_panel->intel_dsi;
+ struct drm_device *dev = intel_dsi->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_display_mode *mode;
+
+ if (!panel->connector)
+ return 0;
+
+ mode = drm_mode_duplicate(dev, dev_priv->vbt.lfp_lvds_vbt_mode);
+ if (!mode)
+ return 0;
+
+ mode->type |= DRM_MODE_TYPE_PREFERRED;
+
+ drm_mode_probed_add(panel->connector, mode);
+
+ return 1;
+}
+
+static const struct drm_panel_funcs vbt_panel_funcs = {
+ .disable = vbt_panel_disable,
+ .unprepare = vbt_panel_unprepare,
+ .prepare = vbt_panel_prepare,
+ .enable = vbt_panel_enable,
+ .get_modes = vbt_panel_get_modes,
+};
+
+struct drm_panel *vbt_panel_init(struct intel_dsi *intel_dsi, u16 panel_id)
{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
struct drm_device *dev = intel_dsi->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct mipi_config *mipi_config = dev_priv->vbt.dsi.config;
struct mipi_pps_data *pps = dev_priv->vbt.dsi.pps;
struct drm_display_mode *mode = dev_priv->vbt.lfp_lvds_vbt_mode;
+ struct vbt_panel *vbt_panel;
u32 bits_per_pixel = 24;
u32 tlpx_ns, extra_byte_count, bitrate, tlpx_ui;
u32 ui_num, ui_den;
@@ -273,6 +398,7 @@ static bool generic_init(struct intel_dsi_device *dsi)
u32 lp_to_hs_switch, hs_to_lp_switch;
u32 pclk, computed_ddr;
u16 burst_mode_ratio;
+ enum port port;
DRM_DEBUG_KMS("\n");
@@ -280,6 +406,8 @@ static bool generic_init(struct intel_dsi_device *dsi)
intel_dsi->clock_stop = mipi_config->enable_clk_stop ? 1 : 0;
intel_dsi->lane_count = mipi_config->lane_cnt + 1;
intel_dsi->pixel_format = mipi_config->videomode_color_format << 7;
+ intel_dsi->dual_link = mipi_config->dual_link;
+ intel_dsi->pixel_overlap = mipi_config->pixel_overlap;
if (intel_dsi->pixel_format == VID_MODE_FORMAT_RGB666)
bits_per_pixel = 18;
@@ -299,6 +427,20 @@ static bool generic_init(struct intel_dsi_device *dsi)
pclk = mode->clock;
+ /* In dual link mode each port needs half of pixel clock */
+ if (intel_dsi->dual_link) {
+ pclk = pclk / 2;
+
+ /* we can enable pixel_overlap if needed by panel. In this
+ * case we need to increase the pixelclock for extra pixels
+ */
+ if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK) {
+ pclk += DIV_ROUND_UP(mode->vtotal *
+ intel_dsi->pixel_overlap *
+ 60, 1000);
+ }
+ }
+
/* Burst Mode Ratio
* Target ddr frequency from VBT / non burst ddr freq
* multiply by 100 to preserve remainder
@@ -311,7 +453,7 @@ static bool generic_init(struct intel_dsi_device *dsi)
if (mipi_config->target_burst_mode_freq <
computed_ddr) {
DRM_ERROR("Burst mode freq is less than computed\n");
- return false;
+ return NULL;
}
burst_mode_ratio = DIV_ROUND_UP(
@@ -321,7 +463,7 @@ static bool generic_init(struct intel_dsi_device *dsi)
pclk = DIV_ROUND_UP(pclk * burst_mode_ratio, 100);
} else {
DRM_ERROR("Burst mode target is not set\n");
- return false;
+ return NULL;
}
} else
burst_mode_ratio = 100;
@@ -493,6 +635,12 @@ static bool generic_init(struct intel_dsi_device *dsi)
DRM_DEBUG_KMS("Clockstop %s\n", intel_dsi->clock_stop ?
"disabled" : "enabled");
DRM_DEBUG_KMS("Mode %s\n", intel_dsi->operation_mode ? "command" : "video");
+ if (intel_dsi->dual_link == DSI_DUAL_LINK_FRONT_BACK)
+ DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_FRONT_BACK\n");
+ else if (intel_dsi->dual_link == DSI_DUAL_LINK_PIXEL_ALT)
+ DRM_DEBUG_KMS("Dual link: DSI_DUAL_LINK_PIXEL_ALT\n");
+ else
+ DRM_DEBUG_KMS("Dual link: NONE\n");
DRM_DEBUG_KMS("Pixel Format %d\n", intel_dsi->pixel_format);
DRM_DEBUG_KMS("TLPX %d\n", intel_dsi->escape_clk_div);
DRM_DEBUG_KMS("LP RX Timeout 0x%x\n", intel_dsi->lp_rx_timeout);
@@ -516,110 +664,18 @@ static bool generic_init(struct intel_dsi_device *dsi)
intel_dsi->panel_off_delay = pps->panel_off_delay / 10;
intel_dsi->panel_pwr_cycle_delay = pps->panel_power_cycle_delay / 10;
- return true;
-}
-
-static int generic_mode_valid(struct intel_dsi_device *dsi,
- struct drm_display_mode *mode)
-{
- return MODE_OK;
-}
-
-static bool generic_mode_fixup(struct intel_dsi_device *dsi,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode) {
- return true;
-}
-
-static void generic_panel_reset(struct intel_dsi_device *dsi)
-{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
- struct drm_device *dev = intel_dsi->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_ASSERT_RESET];
-
- generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_disable_panel_power(struct intel_dsi_device *dsi)
-{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
- struct drm_device *dev = intel_dsi->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DEASSERT_RESET];
-
- generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_send_otp_cmds(struct intel_dsi_device *dsi)
-{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
- struct drm_device *dev = intel_dsi->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_INIT_OTP];
-
- generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_enable(struct intel_dsi_device *dsi)
-{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
- struct drm_device *dev = intel_dsi->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_ON];
-
- generic_exec_sequence(intel_dsi, sequence);
-}
-
-static void generic_disable(struct intel_dsi_device *dsi)
-{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
- struct drm_device *dev = intel_dsi->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ /* This is cheating a bit with the cleanup. */
+ vbt_panel = devm_kzalloc(dev->dev, sizeof(*vbt_panel), GFP_KERNEL);
- char *sequence = dev_priv->vbt.dsi.sequence[MIPI_SEQ_DISPLAY_OFF];
+ vbt_panel->intel_dsi = intel_dsi;
+ drm_panel_init(&vbt_panel->panel);
+ vbt_panel->panel.funcs = &vbt_panel_funcs;
+ drm_panel_add(&vbt_panel->panel);
- generic_exec_sequence(intel_dsi, sequence);
-}
-
-static enum drm_connector_status generic_detect(struct intel_dsi_device *dsi)
-{
- return connector_status_connected;
-}
-
-static bool generic_get_hw_state(struct intel_dsi_device *dev)
-{
- return true;
-}
-
-static struct drm_display_mode *generic_get_modes(struct intel_dsi_device *dsi)
-{
- struct intel_dsi *intel_dsi = container_of(dsi, struct intel_dsi, dev);
- struct drm_device *dev = intel_dsi->base.base.dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
+ /* a regular driver would get the device in probe */
+ for_each_dsi_port(port, intel_dsi->ports) {
+ mipi_dsi_attach(intel_dsi->dsi_hosts[port]->device);
+ }
- dev_priv->vbt.lfp_lvds_vbt_mode->type |= DRM_MODE_TYPE_PREFERRED;
- return dev_priv->vbt.lfp_lvds_vbt_mode;
+ return &vbt_panel->panel;
}
-
-static void generic_destroy(struct intel_dsi_device *dsi) { }
-
-/* Callbacks. We might not need them all. */
-struct intel_dsi_dev_ops vbt_generic_dsi_display_ops = {
- .init = generic_init,
- .mode_valid = generic_mode_valid,
- .mode_fixup = generic_mode_fixup,
- .panel_reset = generic_panel_reset,
- .disable_panel_power = generic_disable_panel_power,
- .send_otp_cmds = generic_send_otp_cmds,
- .enable = generic_enable,
- .disable = generic_disable,
- .detect = generic_detect,
- .get_hw_state = generic_get_hw_state,
- .get_modes = generic_get_modes,
- .destroy = generic_destroy,
-};
diff --git a/drivers/gpu/drm/i915/intel_dsi_pll.c b/drivers/gpu/drm/i915/intel_dsi_pll.c
index fa7a6ca34cd6..3622d0bafdf8 100644
--- a/drivers/gpu/drm/i915/intel_dsi_pll.c
+++ b/drivers/gpu/drm/i915/intel_dsi_pll.c
@@ -241,7 +241,11 @@ static void vlv_configure_dsi_pll(struct intel_encoder *encoder)
return;
}
- dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+ if (intel_dsi->ports & (1 << PORT_A))
+ dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI0_DSIPLL;
+
+ if (intel_dsi->ports & (1 << PORT_C))
+ dsi_mnp.dsi_pll_ctrl |= DSI_PLL_CLK_GATE_DSI1_DSIPLL;
DRM_DEBUG_KMS("dsi pll div %08x, ctrl %08x\n",
dsi_mnp.dsi_pll_div, dsi_mnp.dsi_pll_ctrl);
@@ -269,12 +273,14 @@ void vlv_enable_dsi_pll(struct intel_encoder *encoder)
tmp |= DSI_PLL_VCO_EN;
vlv_cck_write(dev_priv, CCK_REG_DSI_PLL_CONTROL, tmp);
- mutex_unlock(&dev_priv->dpio_lock);
+ if (wait_for(vlv_cck_read(dev_priv, CCK_REG_DSI_PLL_CONTROL) &
+ DSI_PLL_LOCK, 20)) {
- if (wait_for(I915_READ(PIPECONF(PIPE_A)) & PIPECONF_DSI_PLL_LOCKED, 20)) {
+ mutex_unlock(&dev_priv->dpio_lock);
DRM_ERROR("DSI PLL lock failed\n");
return;
}
+ mutex_unlock(&dev_priv->dpio_lock);
DRM_DEBUG_KMS("DSI PLL locked\n");
}
diff --git a/drivers/gpu/drm/i915/intel_dvo.c b/drivers/gpu/drm/i915/intel_dvo.c
index e40e3df33517..d8579510beb0 100644
--- a/drivers/gpu/drm/i915/intel_dvo.c
+++ b/drivers/gpu/drm/i915/intel_dvo.c
@@ -27,6 +27,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include "intel_drv.h"
#include <drm/i915_drm.h>
@@ -144,7 +145,7 @@ static bool intel_dvo_get_hw_state(struct intel_encoder *encoder,
}
static void intel_dvo_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_i915_private *dev_priv = encoder->base.dev->dev_private;
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
@@ -160,9 +161,9 @@ static void intel_dvo_get_config(struct intel_encoder *encoder,
else
flags |= DRM_MODE_FLAG_NVSYNC;
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
- pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+ pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
}
static void intel_disable_dvo(struct intel_encoder *encoder)
@@ -186,8 +187,8 @@ static void intel_enable_dvo(struct intel_encoder *encoder)
u32 temp = I915_READ(dvo_reg);
intel_dvo->dev.dev_ops->mode_set(&intel_dvo->dev,
- &crtc->config.requested_mode,
- &crtc->config.adjusted_mode);
+ &crtc->config->base.mode,
+ &crtc->config->base.adjusted_mode);
I915_WRITE(dvo_reg, temp | DVO_ENABLE);
I915_READ(dvo_reg);
@@ -200,7 +201,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
{
struct intel_dvo *intel_dvo = intel_attached_dvo(connector);
struct drm_crtc *crtc;
- struct intel_crtc_config *config;
+ struct intel_crtc_state *config;
/* dvo supports only 2 dpms states. */
if (mode != DRM_MODE_DPMS_ON)
@@ -221,7 +222,7 @@ static void intel_dvo_dpms(struct drm_connector *connector, int mode)
/* We call connector dpms manually below in case pipe dpms doesn't
* change due to cloning. */
if (mode == DRM_MODE_DPMS_ON) {
- config = &to_intel_crtc(crtc)->config;
+ config = to_intel_crtc(crtc)->config;
intel_dvo->base.connectors_active = true;
@@ -261,10 +262,10 @@ intel_dvo_mode_valid(struct drm_connector *connector,
}
static bool intel_dvo_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
/* If we have timings from the BIOS for the panel, put them in
* to the adjusted mode. The CRTC will be set up for this mode,
@@ -295,7 +296,7 @@ static void intel_dvo_pre_enable(struct intel_encoder *encoder)
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
- struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
struct intel_dvo *intel_dvo = enc_to_dvo(encoder);
int pipe = crtc->pipe;
u32 dvo_val;
@@ -390,6 +391,8 @@ static const struct drm_connector_funcs intel_dvo_connector_funcs = {
.detect = intel_dvo_detect,
.destroy = intel_dvo_destroy,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .atomic_get_property = intel_connector_atomic_get_property,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs intel_dvo_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_fbc.c b/drivers/gpu/drm/i915/intel_fbc.c
new file mode 100644
index 000000000000..624d1d92d284
--- /dev/null
+++ b/drivers/gpu/drm/i915/intel_fbc.c
@@ -0,0 +1,701 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+/**
+ * DOC: Frame Buffer Compression (FBC)
+ *
+ * FBC tries to save memory bandwidth (and so power consumption) by
+ * compressing the amount of memory used by the display. It is total
+ * transparent to user space and completely handled in the kernel.
+ *
+ * The benefits of FBC are mostly visible with solid backgrounds and
+ * variation-less patterns. It comes from keeping the memory footprint small
+ * and having fewer memory pages opened and accessed for refreshing the display.
+ *
+ * i915 is responsible to reserve stolen memory for FBC and configure its
+ * offset on proper registers. The hardware takes care of all
+ * compress/decompress. However there are many known cases where we have to
+ * forcibly disable it to allow proper screen updates.
+ */
+
+#include "intel_drv.h"
+#include "i915_drv.h"
+
+static void i8xx_fbc_disable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 fbc_ctl;
+
+ dev_priv->fbc.enabled = false;
+
+ /* Disable compression */
+ fbc_ctl = I915_READ(FBC_CONTROL);
+ if ((fbc_ctl & FBC_CTL_EN) == 0)
+ return;
+
+ fbc_ctl &= ~FBC_CTL_EN;
+ I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+ /* Wait for compressing bit to clear */
+ if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
+ DRM_DEBUG_KMS("FBC idle timed out\n");
+ return;
+ }
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+}
+
+static void i8xx_fbc_enable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->primary->fb;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ int cfb_pitch;
+ int i;
+ u32 fbc_ctl;
+
+ dev_priv->fbc.enabled = true;
+
+ cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
+ if (fb->pitches[0] < cfb_pitch)
+ cfb_pitch = fb->pitches[0];
+
+ /* FBC_CTL wants 32B or 64B units */
+ if (IS_GEN2(dev))
+ cfb_pitch = (cfb_pitch / 32) - 1;
+ else
+ cfb_pitch = (cfb_pitch / 64) - 1;
+
+ /* Clear old tags */
+ for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
+ I915_WRITE(FBC_TAG + (i * 4), 0);
+
+ if (IS_GEN4(dev)) {
+ u32 fbc_ctl2;
+
+ /* Set it up... */
+ fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
+ fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
+ I915_WRITE(FBC_CONTROL2, fbc_ctl2);
+ I915_WRITE(FBC_FENCE_OFF, crtc->y);
+ }
+
+ /* enable it... */
+ fbc_ctl = I915_READ(FBC_CONTROL);
+ fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
+ fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
+ if (IS_I945GM(dev))
+ fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
+ fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
+ fbc_ctl |= obj->fence_reg;
+ I915_WRITE(FBC_CONTROL, fbc_ctl);
+
+ DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
+ cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
+}
+
+static bool i8xx_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
+}
+
+static void g4x_fbc_enable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->primary->fb;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ u32 dpfc_ctl;
+
+ dev_priv->fbc.enabled = true;
+
+ dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
+ if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+ dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+ else
+ dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+ dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
+
+ I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
+
+ /* enable it... */
+ I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+ DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
+}
+
+static void g4x_fbc_disable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpfc_ctl;
+
+ dev_priv->fbc.enabled = false;
+
+ /* Disable compression */
+ dpfc_ctl = I915_READ(DPFC_CONTROL);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(DPFC_CONTROL, dpfc_ctl);
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+ }
+}
+
+static bool g4x_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
+static void snb_fbc_blit_update(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 blt_ecoskpd;
+
+ /* Make sure blitter notifies FBC of writes */
+
+ /* Blitter is part of Media powerwell on VLV. No impact of
+ * his param in other platforms for now */
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_MEDIA);
+
+ blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
+ blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
+ GEN6_BLITTER_LOCK_SHIFT;
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
+ GEN6_BLITTER_LOCK_SHIFT);
+ I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
+ POSTING_READ(GEN6_BLITTER_ECOSKPD);
+
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_MEDIA);
+}
+
+static void ilk_fbc_enable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->primary->fb;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ u32 dpfc_ctl;
+
+ dev_priv->fbc.enabled = true;
+
+ dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
+ if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+ dev_priv->fbc.threshold++;
+
+ switch (dev_priv->fbc.threshold) {
+ case 4:
+ case 3:
+ dpfc_ctl |= DPFC_CTL_LIMIT_4X;
+ break;
+ case 2:
+ dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+ break;
+ case 1:
+ dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+ break;
+ }
+ dpfc_ctl |= DPFC_CTL_FENCE_EN;
+ if (IS_GEN5(dev))
+ dpfc_ctl |= obj->fence_reg;
+
+ I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
+ I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
+ /* enable it... */
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+ if (IS_GEN6(dev)) {
+ I915_WRITE(SNB_DPFC_CTL_SA,
+ SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+ snb_fbc_blit_update(dev);
+ }
+
+ DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
+}
+
+static void ilk_fbc_disable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ u32 dpfc_ctl;
+
+ dev_priv->fbc.enabled = false;
+
+ /* Disable compression */
+ dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
+ if (dpfc_ctl & DPFC_CTL_EN) {
+ dpfc_ctl &= ~DPFC_CTL_EN;
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
+
+ DRM_DEBUG_KMS("disabled FBC\n");
+ }
+}
+
+static bool ilk_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
+}
+
+static void gen7_fbc_enable(struct drm_crtc *crtc)
+{
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_framebuffer *fb = crtc->primary->fb;
+ struct drm_i915_gem_object *obj = intel_fb_obj(fb);
+ struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ u32 dpfc_ctl;
+
+ dev_priv->fbc.enabled = true;
+
+ dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
+ if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
+ dev_priv->fbc.threshold++;
+
+ switch (dev_priv->fbc.threshold) {
+ case 4:
+ case 3:
+ dpfc_ctl |= DPFC_CTL_LIMIT_4X;
+ break;
+ case 2:
+ dpfc_ctl |= DPFC_CTL_LIMIT_2X;
+ break;
+ case 1:
+ dpfc_ctl |= DPFC_CTL_LIMIT_1X;
+ break;
+ }
+
+ dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
+
+ if (dev_priv->fbc.false_color)
+ dpfc_ctl |= FBC_CTL_FALSE_COLOR;
+
+ I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
+
+ if (IS_IVYBRIDGE(dev)) {
+ /* WaFbcAsynchFlipDisableFbcQueue:ivb */
+ I915_WRITE(ILK_DISPLAY_CHICKEN1,
+ I915_READ(ILK_DISPLAY_CHICKEN1) |
+ ILK_FBCQ_DIS);
+ } else {
+ /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
+ I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
+ I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
+ HSW_FBCQ_DIS);
+ }
+
+ I915_WRITE(SNB_DPFC_CTL_SA,
+ SNB_CPU_FENCE_ENABLE | obj->fence_reg);
+ I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
+
+ snb_fbc_blit_update(dev);
+
+ DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
+}
+
+/**
+ * intel_fbc_enabled - Is FBC enabled?
+ * @dev: the drm_device
+ *
+ * This function is used to verify the current state of FBC.
+ * FIXME: This should be tracked in the plane config eventually
+ * instead of queried at runtime for most callers.
+ */
+bool intel_fbc_enabled(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ return dev_priv->fbc.enabled;
+}
+
+void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!IS_GEN8(dev))
+ return;
+
+ if (!intel_fbc_enabled(dev))
+ return;
+
+ I915_WRITE(MSG_FBC_REND_STATE, value);
+}
+
+static void intel_fbc_work_fn(struct work_struct *__work)
+{
+ struct intel_fbc_work *work =
+ container_of(to_delayed_work(__work),
+ struct intel_fbc_work, work);
+ struct drm_device *dev = work->crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ mutex_lock(&dev->struct_mutex);
+ if (work == dev_priv->fbc.fbc_work) {
+ /* Double check that we haven't switched fb without cancelling
+ * the prior work.
+ */
+ if (work->crtc->primary->fb == work->fb) {
+ dev_priv->display.enable_fbc(work->crtc);
+
+ dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
+ dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
+ dev_priv->fbc.y = work->crtc->y;
+ }
+
+ dev_priv->fbc.fbc_work = NULL;
+ }
+ mutex_unlock(&dev->struct_mutex);
+
+ kfree(work);
+}
+
+static void intel_fbc_cancel_work(struct drm_i915_private *dev_priv)
+{
+ if (dev_priv->fbc.fbc_work == NULL)
+ return;
+
+ DRM_DEBUG_KMS("cancelling pending FBC enable\n");
+
+ /* Synchronisation is provided by struct_mutex and checking of
+ * dev_priv->fbc.fbc_work, so we can perform the cancellation
+ * entirely asynchronously.
+ */
+ if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
+ /* tasklet was killed before being run, clean up */
+ kfree(dev_priv->fbc.fbc_work);
+
+ /* Mark the work as no longer wanted so that if it does
+ * wake-up (because the work was already running and waiting
+ * for our mutex), it will discover that is no longer
+ * necessary to run.
+ */
+ dev_priv->fbc.fbc_work = NULL;
+}
+
+static void intel_fbc_enable(struct drm_crtc *crtc)
+{
+ struct intel_fbc_work *work;
+ struct drm_device *dev = crtc->dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (!dev_priv->display.enable_fbc)
+ return;
+
+ intel_fbc_cancel_work(dev_priv);
+
+ work = kzalloc(sizeof(*work), GFP_KERNEL);
+ if (work == NULL) {
+ DRM_ERROR("Failed to allocate FBC work structure\n");
+ dev_priv->display.enable_fbc(crtc);
+ return;
+ }
+
+ work->crtc = crtc;
+ work->fb = crtc->primary->fb;
+ INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
+
+ dev_priv->fbc.fbc_work = work;
+
+ /* Delay the actual enabling to let pageflipping cease and the
+ * display to settle before starting the compression. Note that
+ * this delay also serves a second purpose: it allows for a
+ * vblank to pass after disabling the FBC before we attempt
+ * to modify the control registers.
+ *
+ * A more complicated solution would involve tracking vblanks
+ * following the termination of the page-flipping sequence
+ * and indeed performing the enable as a co-routine and not
+ * waiting synchronously upon the vblank.
+ *
+ * WaFbcWaitForVBlankBeforeEnable:ilk,snb
+ */
+ schedule_delayed_work(&work->work, msecs_to_jiffies(50));
+}
+
+/**
+ * intel_fbc_disable - disable FBC
+ * @dev: the drm_device
+ *
+ * This function disables FBC.
+ */
+void intel_fbc_disable(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_fbc_cancel_work(dev_priv);
+
+ if (!dev_priv->display.disable_fbc)
+ return;
+
+ dev_priv->display.disable_fbc(dev);
+ dev_priv->fbc.plane = -1;
+}
+
+static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
+ enum no_fbc_reason reason)
+{
+ if (dev_priv->fbc.no_fbc_reason == reason)
+ return false;
+
+ dev_priv->fbc.no_fbc_reason = reason;
+ return true;
+}
+
+/**
+ * intel_fbc_update - enable/disable FBC as needed
+ * @dev: the drm_device
+ *
+ * Set up the framebuffer compression hardware at mode set time. We
+ * enable it if possible:
+ * - plane A only (on pre-965)
+ * - no pixel mulitply/line duplication
+ * - no alpha buffer discard
+ * - no dual wide
+ * - framebuffer <= max_hdisplay in width, max_vdisplay in height
+ *
+ * We can't assume that any compression will take place (worst case),
+ * so the compressed buffer has to be the same size as the uncompressed
+ * one. It also must reside (along with the line length buffer) in
+ * stolen memory.
+ *
+ * We need to enable/disable FBC on a global basis.
+ */
+void intel_fbc_update(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = NULL, *tmp_crtc;
+ struct intel_crtc *intel_crtc;
+ struct drm_framebuffer *fb;
+ struct drm_i915_gem_object *obj;
+ const struct drm_display_mode *adjusted_mode;
+ unsigned int max_width, max_height;
+
+ if (!HAS_FBC(dev)) {
+ set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
+ return;
+ }
+
+ if (!i915.powersave) {
+ if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
+ return;
+ }
+
+ /*
+ * If FBC is already on, we just have to verify that we can
+ * keep it that way...
+ * Need to disable if:
+ * - more than one pipe is active
+ * - changing FBC params (stride, fence, mode)
+ * - new fb is too large to fit in compressed buffer
+ * - going to an unsupported config (interlace, pixel multiply, etc.)
+ */
+ for_each_crtc(dev, tmp_crtc) {
+ if (intel_crtc_active(tmp_crtc) &&
+ to_intel_crtc(tmp_crtc)->primary_enabled) {
+ if (crtc) {
+ if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
+ DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
+ goto out_disable;
+ }
+ crtc = tmp_crtc;
+ }
+ }
+
+ if (!crtc || crtc->primary->fb == NULL) {
+ if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
+ DRM_DEBUG_KMS("no output, disabling\n");
+ goto out_disable;
+ }
+
+ intel_crtc = to_intel_crtc(crtc);
+ fb = crtc->primary->fb;
+ obj = intel_fb_obj(fb);
+ adjusted_mode = &intel_crtc->config->base.adjusted_mode;
+
+ if (i915.enable_fbc < 0) {
+ if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
+ DRM_DEBUG_KMS("disabled per chip default\n");
+ goto out_disable;
+ }
+ if (!i915.enable_fbc) {
+ if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
+ DRM_DEBUG_KMS("fbc disabled per module param\n");
+ goto out_disable;
+ }
+ if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
+ (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
+ if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
+ DRM_DEBUG_KMS("mode incompatible with compression, "
+ "disabling\n");
+ goto out_disable;
+ }
+
+ if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
+ max_width = 4096;
+ max_height = 4096;
+ } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
+ max_width = 4096;
+ max_height = 2048;
+ } else {
+ max_width = 2048;
+ max_height = 1536;
+ }
+ if (intel_crtc->config->pipe_src_w > max_width ||
+ intel_crtc->config->pipe_src_h > max_height) {
+ if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
+ DRM_DEBUG_KMS("mode too large for compression, disabling\n");
+ goto out_disable;
+ }
+ if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
+ intel_crtc->plane != PLANE_A) {
+ if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
+ DRM_DEBUG_KMS("plane not A, disabling compression\n");
+ goto out_disable;
+ }
+
+ /* The use of a CPU fence is mandatory in order to detect writes
+ * by the CPU to the scanout and trigger updates to the FBC.
+ */
+ if (obj->tiling_mode != I915_TILING_X ||
+ obj->fence_reg == I915_FENCE_REG_NONE) {
+ if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
+ DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
+ goto out_disable;
+ }
+ if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
+ crtc->primary->state->rotation != BIT(DRM_ROTATE_0)) {
+ if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
+ DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
+ goto out_disable;
+ }
+
+ /* If the kernel debugger is active, always disable compression */
+ if (in_dbg_master())
+ goto out_disable;
+
+ if (i915_gem_stolen_setup_compression(dev, obj->base.size,
+ drm_format_plane_cpp(fb->pixel_format, 0))) {
+ if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
+ DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
+ goto out_disable;
+ }
+
+ /* If the scanout has not changed, don't modify the FBC settings.
+ * Note that we make the fundamental assumption that the fb->obj
+ * cannot be unpinned (and have its GTT offset and fence revoked)
+ * without first being decoupled from the scanout and FBC disabled.
+ */
+ if (dev_priv->fbc.plane == intel_crtc->plane &&
+ dev_priv->fbc.fb_id == fb->base.id &&
+ dev_priv->fbc.y == crtc->y)
+ return;
+
+ if (intel_fbc_enabled(dev)) {
+ /* We update FBC along two paths, after changing fb/crtc
+ * configuration (modeswitching) and after page-flipping
+ * finishes. For the latter, we know that not only did
+ * we disable the FBC at the start of the page-flip
+ * sequence, but also more than one vblank has passed.
+ *
+ * For the former case of modeswitching, it is possible
+ * to switch between two FBC valid configurations
+ * instantaneously so we do need to disable the FBC
+ * before we can modify its control registers. We also
+ * have to wait for the next vblank for that to take
+ * effect. However, since we delay enabling FBC we can
+ * assume that a vblank has passed since disabling and
+ * that we can safely alter the registers in the deferred
+ * callback.
+ *
+ * In the scenario that we go from a valid to invalid
+ * and then back to valid FBC configuration we have
+ * no strict enforcement that a vblank occurred since
+ * disabling the FBC. However, along all current pipe
+ * disabling paths we do need to wait for a vblank at
+ * some point. And we wait before enabling FBC anyway.
+ */
+ DRM_DEBUG_KMS("disabling active FBC for update\n");
+ intel_fbc_disable(dev);
+ }
+
+ intel_fbc_enable(crtc);
+ dev_priv->fbc.no_fbc_reason = FBC_OK;
+ return;
+
+out_disable:
+ /* Multiple disables should be harmless */
+ if (intel_fbc_enabled(dev)) {
+ DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
+ intel_fbc_disable(dev);
+ }
+ i915_gem_stolen_cleanup_compression(dev);
+}
+
+/**
+ * intel_fbc_init - Initialize FBC
+ * @dev_priv: the i915 device
+ *
+ * This function might be called during PM init process.
+ */
+void intel_fbc_init(struct drm_i915_private *dev_priv)
+{
+ if (!HAS_FBC(dev_priv)) {
+ dev_priv->fbc.enabled = false;
+ return;
+ }
+
+ if (INTEL_INFO(dev_priv)->gen >= 7) {
+ dev_priv->display.fbc_enabled = ilk_fbc_enabled;
+ dev_priv->display.enable_fbc = gen7_fbc_enable;
+ dev_priv->display.disable_fbc = ilk_fbc_disable;
+ } else if (INTEL_INFO(dev_priv)->gen >= 5) {
+ dev_priv->display.fbc_enabled = ilk_fbc_enabled;
+ dev_priv->display.enable_fbc = ilk_fbc_enable;
+ dev_priv->display.disable_fbc = ilk_fbc_disable;
+ } else if (IS_GM45(dev_priv)) {
+ dev_priv->display.fbc_enabled = g4x_fbc_enabled;
+ dev_priv->display.enable_fbc = g4x_fbc_enable;
+ dev_priv->display.disable_fbc = g4x_fbc_disable;
+ } else {
+ dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
+ dev_priv->display.enable_fbc = i8xx_fbc_enable;
+ dev_priv->display.disable_fbc = i8xx_fbc_disable;
+
+ /* This value was pulled out of someone's hat */
+ I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
+ }
+
+ dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
+}
diff --git a/drivers/gpu/drm/i915/intel_fbdev.c b/drivers/gpu/drm/i915/intel_fbdev.c
index 850cf7d6578c..3001a8674611 100644
--- a/drivers/gpu/drm/i915/intel_fbdev.c
+++ b/drivers/gpu/drm/i915/intel_fbdev.c
@@ -443,7 +443,7 @@ retry:
DRM_DEBUG_KMS("looking for current mode on connector %s\n",
connector->name);
intel_mode_from_pipe_config(&encoder->crtc->hwmode,
- &to_intel_crtc(encoder->crtc)->config);
+ to_intel_crtc(encoder->crtc)->config);
modes[i] = &encoder->crtc->hwmode;
}
crtcs[i] = new_crtc;
@@ -531,7 +531,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
struct intel_framebuffer *fb = NULL;
struct drm_crtc *crtc;
struct intel_crtc *intel_crtc;
- struct intel_plane_config *plane_config = NULL;
+ struct intel_initial_plane_config *plane_config = NULL;
unsigned int max_size = 0;
if (!i915.fastboot)
@@ -581,7 +581,7 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
* pipe. Note we need to use the selected fb's pitch and bpp
* rather than the current pipe's, since they differ.
*/
- cur_size = intel_crtc->config.adjusted_mode.crtc_hdisplay;
+ cur_size = intel_crtc->config->base.adjusted_mode.crtc_hdisplay;
cur_size = cur_size * fb->base.bits_per_pixel / 8;
if (fb->base.pitches[0] < cur_size) {
DRM_DEBUG_KMS("fb not wide enough for plane %c (%d vs %d)\n",
@@ -592,13 +592,14 @@ static bool intel_fbdev_init_bios(struct drm_device *dev,
break;
}
- cur_size = intel_crtc->config.adjusted_mode.crtc_vdisplay;
- cur_size = ALIGN(cur_size, plane_config->tiled ? (IS_GEN2(dev) ? 16 : 8) : 1);
+ cur_size = intel_crtc->config->base.adjusted_mode.crtc_vdisplay;
+ cur_size = intel_fb_align_height(dev, cur_size,
+ plane_config->tiling);
cur_size *= fb->base.pitches[0];
DRM_DEBUG_KMS("pipe %c area: %dx%d, bpp: %d, size: %d\n",
pipe_name(intel_crtc->pipe),
- intel_crtc->config.adjusted_mode.crtc_hdisplay,
- intel_crtc->config.adjusted_mode.crtc_vdisplay,
+ intel_crtc->config->base.adjusted_mode.crtc_hdisplay,
+ intel_crtc->config->base.adjusted_mode.crtc_vdisplay,
fb->base.bits_per_pixel,
cur_size);
diff --git a/drivers/gpu/drm/i915/intel_fifo_underrun.c b/drivers/gpu/drm/i915/intel_fifo_underrun.c
index 77af512d2d35..04e248dd2259 100644
--- a/drivers/gpu/drm/i915/intel_fifo_underrun.c
+++ b/drivers/gpu/drm/i915/intel_fifo_underrun.c
@@ -341,7 +341,7 @@ bool intel_set_pch_fifo_underrun_reporting(struct drm_i915_private *dev_priv,
}
/**
- * intel_pch_fifo_underrun_irq_handler - handle PCH fifo underrun interrupt
+ * intel_cpu_fifo_underrun_irq_handler - handle CPU fifo underrun interrupt
* @dev_priv: i915 device instance
* @pipe: (CPU) pipe to set state for
*
diff --git a/drivers/gpu/drm/i915/intel_frontbuffer.c b/drivers/gpu/drm/i915/intel_frontbuffer.c
index 79f6d72179c5..73cb6e036445 100644
--- a/drivers/gpu/drm/i915/intel_frontbuffer.c
+++ b/drivers/gpu/drm/i915/intel_frontbuffer.c
@@ -157,6 +157,7 @@ void intel_fb_obj_invalidate(struct drm_i915_gem_object *obj,
intel_mark_fb_busy(dev, obj->frontbuffer_bits, ring);
intel_psr_invalidate(dev, obj->frontbuffer_bits);
+ intel_edp_drrs_invalidate(dev, obj->frontbuffer_bits);
}
/**
@@ -182,6 +183,7 @@ void intel_frontbuffer_flush(struct drm_device *dev,
intel_mark_fb_busy(dev, frontbuffer_bits, NULL);
+ intel_edp_drrs_flush(dev, frontbuffer_bits);
intel_psr_flush(dev, frontbuffer_bits);
/*
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 3abc2000fce9..995c5b261f4f 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -31,6 +31,7 @@
#include <linux/delay.h>
#include <linux/hdmi.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include "intel_drv.h"
@@ -337,13 +338,13 @@ static void hsw_write_infoframe(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
u32 data_reg;
int i;
u32 val = I915_READ(ctl_reg);
data_reg = hsw_infoframe_data_reg(type,
- intel_crtc->config.cpu_transcoder,
+ intel_crtc->config->cpu_transcoder,
dev_priv);
if (data_reg == 0)
return;
@@ -371,7 +372,7 @@ static bool hsw_infoframe_enabled(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
u32 val = I915_READ(ctl_reg);
return val & (VIDEO_DIP_ENABLE_AVI_HSW | VIDEO_DIP_ENABLE_SPD_HSW |
@@ -436,7 +437,7 @@ static void intel_hdmi_set_avi_infoframe(struct drm_encoder *encoder,
}
if (intel_hdmi->rgb_quant_range_selectable) {
- if (intel_crtc->config.limited_color_range)
+ if (intel_crtc->config->limited_color_range)
frame.avi.quantization_range =
HDMI_QUANTIZATION_RANGE_LIMITED;
else
@@ -672,7 +673,7 @@ static void hsw_set_infoframes(struct drm_encoder *encoder,
struct drm_i915_private *dev_priv = encoder->dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(encoder);
- u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config.cpu_transcoder);
+ u32 reg = HSW_TVIDEO_DIP_CTL(intel_crtc->config->cpu_transcoder);
u32 val = I915_READ(reg);
assert_hdmi_port_disabled(intel_hdmi);
@@ -700,7 +701,7 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
- struct drm_display_mode *adjusted_mode = &crtc->config.adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &crtc->config->base.adjusted_mode;
u32 hdmi_val;
hdmi_val = SDVO_ENCODING_HDMI;
@@ -711,12 +712,12 @@ static void intel_hdmi_prepare(struct intel_encoder *encoder)
if (adjusted_mode->flags & DRM_MODE_FLAG_PHSYNC)
hdmi_val |= SDVO_HSYNC_ACTIVE_HIGH;
- if (crtc->config.pipe_bpp > 24)
+ if (crtc->config->pipe_bpp > 24)
hdmi_val |= HDMI_COLOR_FORMAT_12bpc;
else
hdmi_val |= SDVO_COLOR_FORMAT_8bpc;
- if (crtc->config.has_hdmi_sink)
+ if (crtc->config->has_hdmi_sink)
hdmi_val |= HDMI_MODE_SELECT_HDMI;
if (HAS_PCH_CPT(dev))
@@ -759,7 +760,7 @@ static bool intel_hdmi_get_hw_state(struct intel_encoder *encoder,
}
static void intel_hdmi_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_device *dev = encoder->base.dev;
@@ -792,7 +793,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
tmp & HDMI_COLOR_RANGE_16_235)
pipe_config->limited_color_range = true;
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
if ((tmp & SDVO_COLOR_FORMAT_MASK) == HDMI_COLOR_FORMAT_12bpc)
dotclock = pipe_config->port_clock * 2 / 3;
@@ -802,7 +803,7 @@ static void intel_hdmi_get_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv->dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = dotclock;
}
static void intel_enable_hdmi(struct intel_encoder *encoder)
@@ -814,7 +815,7 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
u32 temp;
u32 enable_bits = SDVO_ENABLE;
- if (intel_crtc->config.has_audio)
+ if (intel_crtc->config->has_audio)
enable_bits |= SDVO_AUDIO_ENABLE;
temp = I915_READ(intel_hdmi->hdmi_reg);
@@ -845,8 +846,8 @@ static void intel_enable_hdmi(struct intel_encoder *encoder)
POSTING_READ(intel_hdmi->hdmi_reg);
}
- if (intel_crtc->config.has_audio) {
- WARN_ON(!intel_crtc->config.has_hdmi_sink);
+ if (intel_crtc->config->has_audio) {
+ WARN_ON(!intel_crtc->config->has_hdmi_sink);
DRM_DEBUG_DRIVER("Enabling HDMI audio on pipe %c\n",
pipe_name(intel_crtc->pipe));
intel_audio_codec_enable(encoder);
@@ -866,7 +867,7 @@ static void intel_disable_hdmi(struct intel_encoder *encoder)
u32 temp;
u32 enable_bits = SDVO_ENABLE | SDVO_AUDIO_ENABLE;
- if (crtc->config.has_audio)
+ if (crtc->config->has_audio)
intel_audio_codec_disable(encoder);
temp = I915_READ(intel_hdmi->hdmi_reg);
@@ -975,12 +976,12 @@ static bool hdmi_12bpc_possible(struct intel_crtc *crtc)
}
bool intel_hdmi_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct drm_device *dev = encoder->base.dev;
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
- int clock_12bpc = pipe_config->adjusted_mode.crtc_clock * 3 / 2;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ int clock_12bpc = pipe_config->base.adjusted_mode.crtc_clock * 3 / 2;
int portclock_limit = hdmi_portclock_limit(intel_hdmi, false);
int desired_bpp;
@@ -1252,12 +1253,12 @@ static void intel_hdmi_pre_enable(struct intel_encoder *encoder)
struct intel_hdmi *intel_hdmi = enc_to_intel_hdmi(&encoder->base);
struct intel_crtc *intel_crtc = to_intel_crtc(encoder->base.crtc);
struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
+ &intel_crtc->config->base.adjusted_mode;
intel_hdmi_prepare(encoder);
intel_hdmi->set_infoframes(&encoder->base,
- intel_crtc->config.has_hdmi_sink,
+ intel_crtc->config->has_hdmi_sink,
adjusted_mode);
}
@@ -1270,7 +1271,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
struct intel_crtc *intel_crtc =
to_intel_crtc(encoder->base.crtc);
struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
+ &intel_crtc->config->base.adjusted_mode;
enum dpio_channel port = vlv_dport_to_channel(dport);
int pipe = intel_crtc->pipe;
u32 val;
@@ -1302,7 +1303,7 @@ static void vlv_hdmi_pre_enable(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpio_lock);
intel_hdmi->set_infoframes(&encoder->base,
- intel_crtc->config.has_hdmi_sink,
+ intel_crtc->config->has_hdmi_sink,
adjusted_mode);
intel_enable_hdmi(encoder);
@@ -1467,7 +1468,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
struct intel_crtc *intel_crtc =
to_intel_crtc(encoder->base.crtc);
struct drm_display_mode *adjusted_mode =
- &intel_crtc->config.adjusted_mode;
+ &intel_crtc->config->base.adjusted_mode;
enum dpio_channel ch = vlv_dport_to_channel(dport);
int pipe = intel_crtc->pipe;
int data, i;
@@ -1593,7 +1594,7 @@ static void chv_hdmi_pre_enable(struct intel_encoder *encoder)
mutex_unlock(&dev_priv->dpio_lock);
intel_hdmi->set_infoframes(&encoder->base,
- intel_crtc->config.has_hdmi_sink,
+ intel_crtc->config->has_hdmi_sink,
adjusted_mode);
intel_enable_hdmi(encoder);
@@ -1614,7 +1615,9 @@ static const struct drm_connector_funcs intel_hdmi_connector_funcs = {
.force = intel_hdmi_force,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_hdmi_set_property,
+ .atomic_get_property = intel_connector_atomic_get_property,
.destroy = intel_hdmi_destroy,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs intel_hdmi_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_lrc.c b/drivers/gpu/drm/i915/intel_lrc.c
index e588376227ea..e8d3da9f3373 100644
--- a/drivers/gpu/drm/i915/intel_lrc.c
+++ b/drivers/gpu/drm/i915/intel_lrc.c
@@ -212,8 +212,7 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
* @enable_execlists: value of i915.enable_execlists module parameter.
*
* Only certain platforms support Execlists (the prerequisites being
- * support for Logical Ring Contexts and Aliasing PPGTT or better),
- * and only when enabled via module parameter.
+ * support for Logical Ring Contexts and Aliasing PPGTT or better).
*
* Return: 1 if Execlists is supported and has to be enabled.
*/
@@ -284,7 +283,6 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
struct drm_i915_private *dev_priv = dev->dev_private;
uint64_t temp = 0;
uint32_t desc[4];
- unsigned long flags;
/* XXX: You must always write both descriptors in the order below. */
if (ctx_obj1)
@@ -298,63 +296,17 @@ static void execlists_elsp_write(struct intel_engine_cs *ring,
desc[3] = (u32)(temp >> 32);
desc[2] = (u32)temp;
- /* Set Force Wakeup bit to prevent GT from entering C6 while ELSP writes
- * are in progress.
- *
- * The other problem is that we can't just call gen6_gt_force_wake_get()
- * because that function calls intel_runtime_pm_get(), which might sleep.
- * Instead, we do the runtime_pm_get/put when creating/destroying requests.
- */
- spin_lock_irqsave(&dev_priv->uncore.lock, flags);
- if (IS_CHERRYVIEW(dev) || INTEL_INFO(dev)->gen >= 9) {
- if (dev_priv->uncore.fw_rendercount++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_RENDER);
- if (dev_priv->uncore.fw_mediacount++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_MEDIA);
- if (INTEL_INFO(dev)->gen >= 9) {
- if (dev_priv->uncore.fw_blittercount++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_BLITTER);
- }
- } else {
- if (dev_priv->uncore.forcewake_count++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_ALL);
- }
- spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
-
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
I915_WRITE(RING_ELSP(ring), desc[1]);
I915_WRITE(RING_ELSP(ring), desc[0]);
I915_WRITE(RING_ELSP(ring), desc[3]);
+
/* The context is automatically loaded after the following */
I915_WRITE(RING_ELSP(ring), desc[2]);
/* ELSP is a wo register, so use another nearby reg for posting instead */
POSTING_READ(RING_EXECLIST_STATUS(ring));
-
- /* Release Force Wakeup (see the big comment above). */
- spin_lock_irqsave(&dev_priv->uncore.lock, flags);
- if (IS_CHERRYVIEW(dev) || INTEL_INFO(dev)->gen >= 9) {
- if (--dev_priv->uncore.fw_rendercount == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_RENDER);
- if (--dev_priv->uncore.fw_mediacount == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_MEDIA);
- if (INTEL_INFO(dev)->gen >= 9) {
- if (--dev_priv->uncore.fw_blittercount == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_BLITTER);
- }
- } else {
- if (--dev_priv->uncore.forcewake_count == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_ALL);
- }
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, flags);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
static int execlists_update_context(struct drm_i915_gem_object *ctx_obj,
@@ -405,8 +357,8 @@ static void execlists_submit_contexts(struct intel_engine_cs *ring,
static void execlists_context_unqueue(struct intel_engine_cs *ring)
{
- struct intel_ctx_submit_request *req0 = NULL, *req1 = NULL;
- struct intel_ctx_submit_request *cursor = NULL, *tmp = NULL;
+ struct drm_i915_gem_request *req0 = NULL, *req1 = NULL;
+ struct drm_i915_gem_request *cursor = NULL, *tmp = NULL;
assert_spin_locked(&ring->execlist_lock);
@@ -446,12 +398,12 @@ static void execlists_context_unqueue(struct intel_engine_cs *ring)
static bool execlists_check_remove_request(struct intel_engine_cs *ring,
u32 request_id)
{
- struct intel_ctx_submit_request *head_req;
+ struct drm_i915_gem_request *head_req;
assert_spin_locked(&ring->execlist_lock);
head_req = list_first_entry_or_null(&ring->execlist_queue,
- struct intel_ctx_submit_request,
+ struct drm_i915_gem_request,
execlist_link);
if (head_req != NULL) {
@@ -474,13 +426,13 @@ static bool execlists_check_remove_request(struct intel_engine_cs *ring,
}
/**
- * intel_execlists_handle_ctx_events() - handle Context Switch interrupts
+ * intel_lrc_irq_handler() - handle Context Switch interrupts
* @ring: Engine Command Streamer to handle.
*
* Check the unread Context Status Buffers and manage the submission of new
* contexts to the ELSP accordingly.
*/
-void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
+void intel_lrc_irq_handler(struct intel_engine_cs *ring)
{
struct drm_i915_private *dev_priv = ring->dev->dev_private;
u32 status_pointer;
@@ -535,24 +487,35 @@ void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring)
static int execlists_context_queue(struct intel_engine_cs *ring,
struct intel_context *to,
- u32 tail)
+ u32 tail,
+ struct drm_i915_gem_request *request)
{
- struct intel_ctx_submit_request *req = NULL, *cursor;
+ struct drm_i915_gem_request *cursor;
struct drm_i915_private *dev_priv = ring->dev->dev_private;
unsigned long flags;
int num_elements = 0;
- req = kzalloc(sizeof(*req), GFP_KERNEL);
- if (req == NULL)
- return -ENOMEM;
- req->ctx = to;
- i915_gem_context_reference(req->ctx);
-
if (to != ring->default_context)
intel_lr_context_pin(ring, to);
- req->ring = ring;
- req->tail = tail;
+ if (!request) {
+ /*
+ * If there isn't a request associated with this submission,
+ * create one as a temporary holder.
+ */
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
+ request->ring = ring;
+ request->ctx = to;
+ kref_init(&request->ref);
+ request->uniq = dev_priv->request_uniq++;
+ i915_gem_context_reference(request->ctx);
+ } else {
+ i915_gem_request_reference(request);
+ WARN_ON(to != request->ctx);
+ }
+ request->tail = tail;
intel_runtime_pm_get(dev_priv);
@@ -563,10 +526,10 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
break;
if (num_elements > 2) {
- struct intel_ctx_submit_request *tail_req;
+ struct drm_i915_gem_request *tail_req;
tail_req = list_last_entry(&ring->execlist_queue,
- struct intel_ctx_submit_request,
+ struct drm_i915_gem_request,
execlist_link);
if (to == tail_req->ctx) {
@@ -578,7 +541,7 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
}
}
- list_add_tail(&req->execlist_link, &ring->execlist_queue);
+ list_add_tail(&request->execlist_link, &ring->execlist_queue);
if (num_elements == 0)
execlists_context_unqueue(ring);
@@ -587,7 +550,8 @@ static int execlists_context_queue(struct intel_engine_cs *ring,
return 0;
}
-static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
+static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx)
{
struct intel_engine_cs *ring = ringbuf->ring;
uint32_t flush_domains;
@@ -597,7 +561,8 @@ static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
if (ring->gpu_caches_dirty)
flush_domains = I915_GEM_GPU_DOMAINS;
- ret = ring->emit_flush(ringbuf, I915_GEM_GPU_DOMAINS, flush_domains);
+ ret = ring->emit_flush(ringbuf, ctx,
+ I915_GEM_GPU_DOMAINS, flush_domains);
if (ret)
return ret;
@@ -606,6 +571,7 @@ static int logical_ring_invalidate_all_caches(struct intel_ringbuffer *ringbuf)
}
static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
struct list_head *vmas)
{
struct intel_engine_cs *ring = ringbuf->ring;
@@ -633,7 +599,7 @@ static int execlists_move_to_gpu(struct intel_ringbuffer *ringbuf,
/* Unconditionally invalidate gpu caches and ensure that we do flush
* any residual writes from the previous batch.
*/
- return logical_ring_invalidate_all_caches(ringbuf);
+ return logical_ring_invalidate_all_caches(ringbuf, ctx);
}
/**
@@ -713,13 +679,13 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
return -EINVAL;
}
- ret = execlists_move_to_gpu(ringbuf, vmas);
+ ret = execlists_move_to_gpu(ringbuf, ctx, vmas);
if (ret)
return ret;
if (ring == &dev_priv->ring[RCS] &&
instp_mode != dev_priv->relative_constants_mode) {
- ret = intel_logical_ring_begin(ringbuf, 4);
+ ret = intel_logical_ring_begin(ringbuf, ctx, 4);
if (ret)
return ret;
@@ -732,7 +698,7 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
dev_priv->relative_constants_mode = instp_mode;
}
- ret = ring->emit_bb_start(ringbuf, exec_start, flags);
+ ret = ring->emit_bb_start(ringbuf, ctx, exec_start, flags);
if (ret)
return ret;
@@ -744,7 +710,7 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
void intel_execlists_retire_requests(struct intel_engine_cs *ring)
{
- struct intel_ctx_submit_request *req, *tmp;
+ struct drm_i915_gem_request *req, *tmp;
struct drm_i915_private *dev_priv = ring->dev->dev_private;
unsigned long flags;
struct list_head retired_list;
@@ -766,9 +732,8 @@ void intel_execlists_retire_requests(struct intel_engine_cs *ring)
if (ctx_obj && (ctx != ring->default_context))
intel_lr_context_unpin(ring, ctx);
intel_runtime_pm_put(dev_priv);
- i915_gem_context_unreference(req->ctx);
list_del(&req->execlist_link);
- kfree(req);
+ i915_gem_request_unreference(req);
}
}
@@ -794,7 +759,8 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring)
I915_WRITE_MODE(ring, _MASKED_BIT_DISABLE(STOP_RING));
}
-int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx)
{
struct intel_engine_cs *ring = ringbuf->ring;
int ret;
@@ -802,7 +768,7 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
if (!ring->gpu_caches_dirty)
return 0;
- ret = ring->emit_flush(ringbuf, 0, I915_GEM_GPU_DOMAINS);
+ ret = ring->emit_flush(ringbuf, ctx, 0, I915_GEM_GPU_DOMAINS);
if (ret)
return ret;
@@ -819,17 +785,18 @@ int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf)
* on a queue waiting for the ELSP to be ready to accept a new context submission. At that
* point, the tail *inside* the context is updated and the ELSP written to.
*/
-void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf)
+void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
+ struct drm_i915_gem_request *request)
{
struct intel_engine_cs *ring = ringbuf->ring;
- struct intel_context *ctx = ringbuf->FIXME_lrc_ctx;
intel_logical_ring_advance(ringbuf);
if (intel_ring_stopped(ring))
return;
- execlists_context_queue(ring, ctx, ringbuf->tail);
+ execlists_context_queue(ring, ctx, ringbuf->tail, request);
}
static int intel_lr_context_pin(struct intel_engine_cs *ring,
@@ -840,11 +807,11 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
int ret = 0;
WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
- if (ctx->engine[ring->id].unpin_count++ == 0) {
+ if (ctx->engine[ring->id].pin_count++ == 0) {
ret = i915_gem_obj_ggtt_pin(ctx_obj,
GEN8_LR_CONTEXT_ALIGN, 0);
if (ret)
- goto reset_unpin_count;
+ goto reset_pin_count;
ret = intel_pin_and_map_ringbuffer_obj(ring->dev, ringbuf);
if (ret)
@@ -855,8 +822,8 @@ static int intel_lr_context_pin(struct intel_engine_cs *ring,
unpin_ctx_obj:
i915_gem_object_ggtt_unpin(ctx_obj);
-reset_unpin_count:
- ctx->engine[ring->id].unpin_count = 0;
+reset_pin_count:
+ ctx->engine[ring->id].pin_count = 0;
return ret;
}
@@ -869,47 +836,55 @@ void intel_lr_context_unpin(struct intel_engine_cs *ring,
if (ctx_obj) {
WARN_ON(!mutex_is_locked(&ring->dev->struct_mutex));
- if (--ctx->engine[ring->id].unpin_count == 0) {
+ if (--ctx->engine[ring->id].pin_count == 0) {
intel_unpin_ringbuffer_obj(ringbuf);
i915_gem_object_ggtt_unpin(ctx_obj);
}
}
}
-static int logical_ring_alloc_seqno(struct intel_engine_cs *ring,
- struct intel_context *ctx)
+static int logical_ring_alloc_request(struct intel_engine_cs *ring,
+ struct intel_context *ctx)
{
+ struct drm_i915_gem_request *request;
+ struct drm_i915_private *dev_private = ring->dev->dev_private;
int ret;
- if (ring->outstanding_lazy_seqno)
+ if (ring->outstanding_lazy_request)
return 0;
- if (ring->preallocated_lazy_request == NULL) {
- struct drm_i915_gem_request *request;
-
- request = kmalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL)
- return -ENOMEM;
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
- if (ctx != ring->default_context) {
- ret = intel_lr_context_pin(ring, ctx);
- if (ret) {
- kfree(request);
- return ret;
- }
+ if (ctx != ring->default_context) {
+ ret = intel_lr_context_pin(ring, ctx);
+ if (ret) {
+ kfree(request);
+ return ret;
}
+ }
- /* Hold a reference to the context this request belongs to
- * (we will need it when the time comes to emit/retire the
- * request).
- */
- request->ctx = ctx;
- i915_gem_context_reference(request->ctx);
+ kref_init(&request->ref);
+ request->ring = ring;
+ request->uniq = dev_private->request_uniq++;
- ring->preallocated_lazy_request = request;
+ ret = i915_gem_get_seqno(ring->dev, &request->seqno);
+ if (ret) {
+ intel_lr_context_unpin(ring, ctx);
+ kfree(request);
+ return ret;
}
- return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+ /* Hold a reference to the context this request belongs to
+ * (we will need it when the time comes to emit/retire the
+ * request).
+ */
+ request->ctx = ctx;
+ i915_gem_context_reference(request->ctx);
+
+ ring->outstanding_lazy_request = request;
+ return 0;
}
static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
@@ -917,42 +892,42 @@ static int logical_ring_wait_request(struct intel_ringbuffer *ringbuf,
{
struct intel_engine_cs *ring = ringbuf->ring;
struct drm_i915_gem_request *request;
- u32 seqno = 0;
int ret;
- if (ringbuf->last_retired_head != -1) {
- ringbuf->head = ringbuf->last_retired_head;
- ringbuf->last_retired_head = -1;
-
- ringbuf->space = intel_ring_space(ringbuf);
- if (ringbuf->space >= bytes)
- return 0;
- }
+ if (intel_ring_space(ringbuf) >= bytes)
+ return 0;
list_for_each_entry(request, &ring->request_list, list) {
+ /*
+ * The request queue is per-engine, so can contain requests
+ * from multiple ringbuffers. Here, we must ignore any that
+ * aren't from the ringbuffer we're considering.
+ */
+ struct intel_context *ctx = request->ctx;
+ if (ctx->engine[ring->id].ringbuf != ringbuf)
+ continue;
+
+ /* Would completion of this request free enough space? */
if (__intel_ring_space(request->tail, ringbuf->tail,
ringbuf->size) >= bytes) {
- seqno = request->seqno;
break;
}
}
- if (seqno == 0)
+ if (&request->list == &ring->request_list)
return -ENOSPC;
- ret = i915_wait_seqno(ring, seqno);
+ ret = i915_wait_request(request);
if (ret)
return ret;
i915_gem_retire_requests_ring(ring);
- ringbuf->head = ringbuf->last_retired_head;
- ringbuf->last_retired_head = -1;
- ringbuf->space = intel_ring_space(ringbuf);
- return 0;
+ return intel_ring_space(ringbuf) >= bytes ? 0 : -ENOSPC;
}
static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
int bytes)
{
struct intel_engine_cs *ring = ringbuf->ring;
@@ -966,7 +941,7 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
return ret;
/* Force the context submission in case we have been skipping it */
- intel_logical_ring_advance_and_submit(ringbuf);
+ intel_logical_ring_advance_and_submit(ringbuf, ctx, NULL);
/* With GEM the hangcheck timer should kick us out of the loop,
* leaving it early runs the risk of corrupting GEM state (due
@@ -975,13 +950,10 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
* case by choosing an insanely large timeout. */
end = jiffies + 60 * HZ;
+ ret = 0;
do {
- ringbuf->head = I915_READ_HEAD(ring);
- ringbuf->space = intel_ring_space(ringbuf);
- if (ringbuf->space >= bytes) {
- ret = 0;
+ if (intel_ring_space(ringbuf) >= bytes)
break;
- }
msleep(1);
@@ -1004,13 +976,14 @@ static int logical_ring_wait_for_space(struct intel_ringbuffer *ringbuf,
return ret;
}
-static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
+static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx)
{
uint32_t __iomem *virt;
int rem = ringbuf->size - ringbuf->tail;
if (ringbuf->space < rem) {
- int ret = logical_ring_wait_for_space(ringbuf, rem);
+ int ret = logical_ring_wait_for_space(ringbuf, ctx, rem);
if (ret)
return ret;
@@ -1022,23 +995,24 @@ static int logical_ring_wrap_buffer(struct intel_ringbuffer *ringbuf)
iowrite32(MI_NOOP, virt++);
ringbuf->tail = 0;
- ringbuf->space = intel_ring_space(ringbuf);
+ intel_ring_update_space(ringbuf);
return 0;
}
-static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
+static int logical_ring_prepare(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx, int bytes)
{
int ret;
if (unlikely(ringbuf->tail + bytes > ringbuf->effective_size)) {
- ret = logical_ring_wrap_buffer(ringbuf);
+ ret = logical_ring_wrap_buffer(ringbuf, ctx);
if (unlikely(ret))
return ret;
}
if (unlikely(ringbuf->space < bytes)) {
- ret = logical_ring_wait_for_space(ringbuf, bytes);
+ ret = logical_ring_wait_for_space(ringbuf, ctx, bytes);
if (unlikely(ret))
return ret;
}
@@ -1059,7 +1033,8 @@ static int logical_ring_prepare(struct intel_ringbuffer *ringbuf, int bytes)
*
* Return: non-zero if the ringbuffer is not ready to be written to.
*/
-int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx, int num_dwords)
{
struct intel_engine_cs *ring = ringbuf->ring;
struct drm_device *dev = ring->dev;
@@ -1071,12 +1046,12 @@ int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords)
if (ret)
return ret;
- ret = logical_ring_prepare(ringbuf, num_dwords * sizeof(uint32_t));
+ ret = logical_ring_prepare(ringbuf, ctx, num_dwords * sizeof(uint32_t));
if (ret)
return ret;
/* Preallocate the olr before touching the ring */
- ret = logical_ring_alloc_seqno(ring, ringbuf->FIXME_lrc_ctx);
+ ret = logical_ring_alloc_request(ring, ctx);
if (ret)
return ret;
@@ -1093,15 +1068,15 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring,
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_workarounds *w = &dev_priv->workarounds;
- if (WARN_ON(w->count == 0))
+ if (WARN_ON_ONCE(w->count == 0))
return 0;
ring->gpu_caches_dirty = true;
- ret = logical_ring_flush_all_caches(ringbuf);
+ ret = logical_ring_flush_all_caches(ringbuf, ctx);
if (ret)
return ret;
- ret = intel_logical_ring_begin(ringbuf, w->count * 2 + 2);
+ ret = intel_logical_ring_begin(ringbuf, ctx, w->count * 2 + 2);
if (ret)
return ret;
@@ -1115,7 +1090,7 @@ static int intel_logical_ring_workarounds_emit(struct intel_engine_cs *ring,
intel_logical_ring_advance(ringbuf);
ring->gpu_caches_dirty = true;
- ret = logical_ring_flush_all_caches(ringbuf);
+ ret = logical_ring_flush_all_caches(ringbuf, ctx);
if (ret)
return ret;
@@ -1134,6 +1109,7 @@ static int gen8_init_common_ring(struct intel_engine_cs *ring)
_MASKED_BIT_DISABLE(GFX_REPLAY_MODE) |
_MASKED_BIT_ENABLE(GFX_RUN_LIST_ENABLE));
POSTING_READ(RING_MODE_GEN7(ring));
+ ring->next_context_status_buffer = 0;
DRM_DEBUG_DRIVER("Execlists enabled for %s\n", ring->name);
memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
@@ -1159,22 +1135,19 @@ static int gen8_init_render_ring(struct intel_engine_cs *ring)
*/
I915_WRITE(MI_MODE, _MASKED_BIT_ENABLE(ASYNC_FLIP_PERF_DISABLE));
- ret = intel_init_pipe_control(ring);
- if (ret)
- return ret;
-
I915_WRITE(INSTPM, _MASKED_BIT_ENABLE(INSTPM_FORCE_ORDERING));
return init_workarounds_ring(ring);
}
static int gen8_emit_bb_start(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
u64 offset, unsigned flags)
{
bool ppgtt = !(flags & I915_DISPATCH_SECURE);
int ret;
- ret = intel_logical_ring_begin(ringbuf, 4);
+ ret = intel_logical_ring_begin(ringbuf, ctx, 4);
if (ret)
return ret;
@@ -1222,6 +1195,7 @@ static void gen8_logical_ring_put_irq(struct intel_engine_cs *ring)
}
static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
u32 invalidate_domains,
u32 unused)
{
@@ -1231,21 +1205,23 @@ static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
uint32_t cmd;
int ret;
- ret = intel_logical_ring_begin(ringbuf, 4);
+ ret = intel_logical_ring_begin(ringbuf, ctx, 4);
if (ret)
return ret;
cmd = MI_FLUSH_DW + 1;
- if (ring == &dev_priv->ring[VCS]) {
- if (invalidate_domains & I915_GEM_GPU_DOMAINS)
- cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
- MI_FLUSH_DW_STORE_INDEX |
- MI_FLUSH_DW_OP_STOREDW;
- } else {
- if (invalidate_domains & I915_GEM_DOMAIN_RENDER)
- cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
- MI_FLUSH_DW_OP_STOREDW;
+ /* We always require a command barrier so that subsequent
+ * commands, such as breadcrumb interrupts, are strictly ordered
+ * wrt the contents of the write cache being flushed to memory
+ * (and thus being coherent from the CPU).
+ */
+ cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+
+ if (invalidate_domains & I915_GEM_GPU_DOMAINS) {
+ cmd |= MI_INVALIDATE_TLB;
+ if (ring == &dev_priv->ring[VCS])
+ cmd |= MI_INVALIDATE_BSD;
}
intel_logical_ring_emit(ringbuf, cmd);
@@ -1260,6 +1236,7 @@ static int gen8_emit_flush(struct intel_ringbuffer *ringbuf,
}
static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
u32 invalidate_domains,
u32 flush_domains)
{
@@ -1286,7 +1263,7 @@ static int gen8_emit_flush_render(struct intel_ringbuffer *ringbuf,
flags |= PIPE_CONTROL_GLOBAL_GTT_IVB;
}
- ret = intel_logical_ring_begin(ringbuf, 6);
+ ret = intel_logical_ring_begin(ringbuf, ctx, 6);
if (ret)
return ret;
@@ -1311,17 +1288,18 @@ static void gen8_set_seqno(struct intel_engine_cs *ring, u32 seqno)
intel_write_status_page(ring, I915_GEM_HWS_INDEX, seqno);
}
-static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
+static int gen8_emit_request(struct intel_ringbuffer *ringbuf,
+ struct drm_i915_gem_request *request)
{
struct intel_engine_cs *ring = ringbuf->ring;
u32 cmd;
int ret;
- ret = intel_logical_ring_begin(ringbuf, 6);
+ ret = intel_logical_ring_begin(ringbuf, request->ctx, 6);
if (ret)
return ret;
- cmd = MI_STORE_DWORD_IMM_GEN8;
+ cmd = MI_STORE_DWORD_IMM_GEN4;
cmd |= MI_GLOBAL_GTT;
intel_logical_ring_emit(ringbuf, cmd);
@@ -1329,14 +1307,27 @@ static int gen8_emit_request(struct intel_ringbuffer *ringbuf)
(ring->status_page.gfx_addr +
(I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT)));
intel_logical_ring_emit(ringbuf, 0);
- intel_logical_ring_emit(ringbuf, ring->outstanding_lazy_seqno);
+ intel_logical_ring_emit(ringbuf,
+ i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_logical_ring_emit(ringbuf, MI_USER_INTERRUPT);
intel_logical_ring_emit(ringbuf, MI_NOOP);
- intel_logical_ring_advance_and_submit(ringbuf);
+ intel_logical_ring_advance_and_submit(ringbuf, request->ctx, request);
return 0;
}
+static int gen8_init_rcs_context(struct intel_engine_cs *ring,
+ struct intel_context *ctx)
+{
+ int ret;
+
+ ret = intel_logical_ring_workarounds_emit(ring, ctx);
+ if (ret)
+ return ret;
+
+ return intel_lr_context_render_state_init(ring, ctx);
+}
+
/**
* intel_logical_ring_cleanup() - deallocate the Engine Command Streamer
*
@@ -1354,8 +1345,7 @@ void intel_logical_ring_cleanup(struct intel_engine_cs *ring)
intel_logical_ring_stop(ring);
WARN_ON((I915_READ_MODE(ring) & MODE_IDLE) == 0);
- ring->preallocated_lazy_request = NULL;
- ring->outstanding_lazy_seqno = 0;
+ i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
if (ring->cleanup)
ring->cleanup(ring);
@@ -1383,18 +1373,11 @@ static int logical_ring_init(struct drm_device *dev, struct intel_engine_cs *rin
INIT_LIST_HEAD(&ring->execlist_queue);
INIT_LIST_HEAD(&ring->execlist_retired_req_list);
spin_lock_init(&ring->execlist_lock);
- ring->next_context_status_buffer = 0;
ret = i915_cmd_parser_init_ring(ring);
if (ret)
return ret;
- if (ring->init) {
- ret = ring->init(ring);
- if (ret)
- return ret;
- }
-
ret = intel_lr_context_deferred_create(ring->default_context, ring);
return ret;
@@ -1404,6 +1387,7 @@ static int logical_render_ring_init(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *ring = &dev_priv->ring[RCS];
+ int ret;
ring->name = "render ring";
ring->id = RCS;
@@ -1415,8 +1399,8 @@ static int logical_render_ring_init(struct drm_device *dev)
if (HAS_L3_DPF(dev))
ring->irq_keep_mask |= GT_RENDER_L3_PARITY_ERROR_INTERRUPT;
- ring->init = gen8_init_render_ring;
- ring->init_context = intel_logical_ring_workarounds_emit;
+ ring->init_hw = gen8_init_render_ring;
+ ring->init_context = gen8_init_rcs_context;
ring->cleanup = intel_fini_pipe_control;
ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno;
@@ -1426,7 +1410,12 @@ static int logical_render_ring_init(struct drm_device *dev)
ring->irq_put = gen8_logical_ring_put_irq;
ring->emit_bb_start = gen8_emit_bb_start;
- return logical_ring_init(dev, ring);
+ ring->dev = dev;
+ ret = logical_ring_init(dev, ring);
+ if (ret)
+ return ret;
+
+ return intel_init_pipe_control(ring);
}
static int logical_bsd_ring_init(struct drm_device *dev)
@@ -1442,7 +1431,7 @@ static int logical_bsd_ring_init(struct drm_device *dev)
ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS1_IRQ_SHIFT;
- ring->init = gen8_init_common_ring;
+ ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request;
@@ -1467,7 +1456,7 @@ static int logical_bsd2_ring_init(struct drm_device *dev)
ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VCS2_IRQ_SHIFT;
- ring->init = gen8_init_common_ring;
+ ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request;
@@ -1492,7 +1481,7 @@ static int logical_blt_ring_init(struct drm_device *dev)
ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_BCS_IRQ_SHIFT;
- ring->init = gen8_init_common_ring;
+ ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request;
@@ -1517,7 +1506,7 @@ static int logical_vebox_ring_init(struct drm_device *dev)
ring->irq_keep_mask =
GT_CONTEXT_SWITCH_INTERRUPT << GEN8_VECS_IRQ_SHIFT;
- ring->init = gen8_init_common_ring;
+ ring->init_hw = gen8_init_common_ring;
ring->get_seqno = gen8_get_seqno;
ring->set_seqno = gen8_set_seqno;
ring->emit_request = gen8_emit_request;
@@ -1609,6 +1598,7 @@ int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
return 0;
ret = ring->emit_bb_start(ringbuf,
+ ctx,
so.ggtt_offset,
I915_DISPATCH_SECURE);
if (ret)
@@ -1616,7 +1606,7 @@ int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
i915_vma_move_to_active(i915_gem_obj_to_ggtt(so.obj), ring);
- ret = __i915_add_request(ring, file, so.obj, NULL);
+ ret = __i915_add_request(ring, file, so.obj);
/* intel_logical_ring_add_request moves object to inactive if it
* fails */
out:
@@ -1763,6 +1753,7 @@ void intel_lr_context_free(struct intel_context *ctx)
intel_unpin_ringbuffer_obj(ringbuf);
i915_gem_object_ggtt_unpin(ctx_obj);
}
+ WARN_ON(ctx->engine[ring->id].pin_count);
intel_destroy_ringbuffer_obj(ringbuf);
kfree(ringbuf);
drm_gem_object_unreference(&ctx_obj->base);
@@ -1835,8 +1826,7 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
int ret;
WARN_ON(ctx->legacy_hw_ctx.rcs_state != NULL);
- if (ctx->engine[ring->id].state)
- return 0;
+ WARN_ON(ctx->engine[ring->id].state);
context_size = round_up(get_lr_context_size(ring), 4096);
@@ -1866,14 +1856,13 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
}
ringbuf->ring = ring;
- ringbuf->FIXME_lrc_ctx = ctx;
ringbuf->size = 32 * PAGE_SIZE;
ringbuf->effective_size = ringbuf->size;
ringbuf->head = 0;
ringbuf->tail = 0;
- ringbuf->space = ringbuf->size;
ringbuf->last_retired_head = -1;
+ intel_ring_update_space(ringbuf);
if (ringbuf->obj == NULL) {
ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
@@ -1907,21 +1896,17 @@ int intel_lr_context_deferred_create(struct intel_context *ctx,
if (ctx == ring->default_context)
lrc_setup_hardware_status_page(ring, ctx_obj);
-
- if (ring->id == RCS && !ctx->rcs_initialized) {
+ else if (ring->id == RCS && !ctx->rcs_initialized) {
if (ring->init_context) {
ret = ring->init_context(ring, ctx);
- if (ret)
+ if (ret) {
DRM_ERROR("ring init context: %d\n", ret);
+ ctx->engine[ring->id].ringbuf = NULL;
+ ctx->engine[ring->id].state = NULL;
+ goto error;
+ }
}
- ret = intel_lr_context_render_state_init(ring, ctx);
- if (ret) {
- DRM_ERROR("Init render state failed: %d\n", ret);
- ctx->engine[ring->id].ringbuf = NULL;
- ctx->engine[ring->id].state = NULL;
- goto error;
- }
ctx->rcs_initialized = true;
}
diff --git a/drivers/gpu/drm/i915/intel_lrc.h b/drivers/gpu/drm/i915/intel_lrc.h
index 14b216b9be7f..6f2d7da594f6 100644
--- a/drivers/gpu/drm/i915/intel_lrc.h
+++ b/drivers/gpu/drm/i915/intel_lrc.h
@@ -38,8 +38,12 @@ void intel_logical_ring_stop(struct intel_engine_cs *ring);
void intel_logical_ring_cleanup(struct intel_engine_cs *ring);
int intel_logical_rings_init(struct drm_device *dev);
-int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf);
-void intel_logical_ring_advance_and_submit(struct intel_ringbuffer *ringbuf);
+int logical_ring_flush_all_caches(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx);
+void intel_logical_ring_advance_and_submit(
+ struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
+ struct drm_i915_gem_request *request);
/**
* intel_logical_ring_advance() - advance the ringbuffer tail
* @ringbuf: Ringbuffer to advance.
@@ -61,7 +65,9 @@ static inline void intel_logical_ring_emit(struct intel_ringbuffer *ringbuf,
iowrite32(data, ringbuf->virtual_start + ringbuf->tail);
ringbuf->tail += 4;
}
-int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf, int num_dwords);
+int intel_logical_ring_begin(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
+ int num_dwords);
/* Logical Ring Contexts */
int intel_lr_context_render_state_init(struct intel_engine_cs *ring,
@@ -83,36 +89,7 @@ int intel_execlists_submission(struct drm_device *dev, struct drm_file *file,
u64 exec_start, u32 flags);
u32 intel_execlists_ctx_id(struct drm_i915_gem_object *ctx_obj);
-/**
- * struct intel_ctx_submit_request - queued context submission request
- * @ctx: Context to submit to the ELSP.
- * @ring: Engine to submit it to.
- * @tail: how far in the context's ringbuffer this request goes to.
- * @execlist_link: link in the submission queue.
- * @work: workqueue for processing this request in a bottom half.
- * @elsp_submitted: no. of times this request has been sent to the ELSP.
- *
- * The ELSP only accepts two elements at a time, so we queue context/tail
- * pairs on a given queue (ring->execlist_queue) until the hardware is
- * available. The queue serves a double purpose: we also use it to keep track
- * of the up to 2 contexts currently in the hardware (usually one in execution
- * and the other queued up by the GPU): We only remove elements from the head
- * of the queue when the hardware informs us that an element has been
- * completed.
- *
- * All accesses to the queue are mediated by a spinlock (ring->execlist_lock).
- */
-struct intel_ctx_submit_request {
- struct intel_context *ctx;
- struct intel_engine_cs *ring;
- u32 tail;
-
- struct list_head execlist_link;
-
- int elsp_submitted;
-};
-
-void intel_execlists_handle_ctx_events(struct intel_engine_cs *ring);
+void intel_lrc_irq_handler(struct intel_engine_cs *ring);
void intel_execlists_retire_requests(struct intel_engine_cs *ring);
#endif /* _INTEL_LRC_H_ */
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index 14654d628ca4..071b96d6e146 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -32,6 +32,7 @@
#include <linux/i2c.h>
#include <linux/slab.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include "intel_drv.h"
@@ -93,7 +94,7 @@ static bool intel_lvds_get_hw_state(struct intel_encoder *encoder,
}
static void intel_lvds_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -115,7 +116,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
else
flags |= DRM_MODE_FLAG_PVSYNC;
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
/* gen2/3 store dither state in pfit control, needs to match */
if (INTEL_INFO(dev)->gen < 4) {
@@ -129,7 +130,7 @@ static void intel_lvds_get_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev_priv->dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = dotclock;
}
static void intel_pre_enable_lvds(struct intel_encoder *encoder)
@@ -139,7 +140,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
const struct drm_display_mode *adjusted_mode =
- &crtc->config.adjusted_mode;
+ &crtc->config->base.adjusted_mode;
int pipe = crtc->pipe;
u32 temp;
@@ -167,7 +168,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
/* set the corresponsding LVDS_BORDER bit */
temp &= ~LVDS_BORDER_ENABLE;
- temp |= crtc->config.gmch_pfit.lvds_border_bits;
+ temp |= crtc->config->gmch_pfit.lvds_border_bits;
/* Set the B0-B3 data pairs corresponding to whether we're going to
* set the DPLLs for dual-channel mode or not.
*/
@@ -190,7 +191,7 @@ static void intel_pre_enable_lvds(struct intel_encoder *encoder)
if (INTEL_INFO(dev)->gen == 4) {
/* Bspec wording suggests that LVDS port dithering only exists
* for 18bpp panels. */
- if (crtc->config.dither && crtc->config.pipe_bpp == 18)
+ if (crtc->config->dither && crtc->config->pipe_bpp == 18)
temp |= LVDS_ENABLE_DITHER;
else
temp &= ~LVDS_ENABLE_DITHER;
@@ -277,14 +278,14 @@ intel_lvds_mode_valid(struct drm_connector *connector,
}
static bool intel_lvds_compute_config(struct intel_encoder *intel_encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = intel_encoder->base.dev;
struct intel_lvds_encoder *lvds_encoder =
to_lvds_encoder(&intel_encoder->base);
struct intel_connector *intel_connector =
&lvds_encoder->attached_connector->base;
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
struct intel_crtc *intel_crtc = lvds_encoder->base.new_crtc;
unsigned int lvds_bpp;
@@ -531,7 +532,9 @@ static const struct drm_connector_funcs intel_lvds_connector_funcs = {
.detect = intel_lvds_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_lvds_set_property,
+ .atomic_get_property = intel_connector_atomic_get_property,
.destroy = intel_lvds_destroy,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_encoder_funcs intel_lvds_enc_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_overlay.c b/drivers/gpu/drm/i915/intel_overlay.c
index dc2f4f26c961..f93dfc174495 100644
--- a/drivers/gpu/drm/i915/intel_overlay.c
+++ b/drivers/gpu/drm/i915/intel_overlay.c
@@ -182,7 +182,7 @@ struct intel_overlay {
u32 flip_addr;
struct drm_i915_gem_object *reg_bo;
/* flip handling */
- uint32_t last_flip_req;
+ struct drm_i915_gem_request *last_flip_req;
void (*flip_tail)(struct intel_overlay *);
};
@@ -217,17 +217,19 @@ static int intel_overlay_do_wait_request(struct intel_overlay *overlay,
int ret;
BUG_ON(overlay->last_flip_req);
- ret = i915_add_request(ring, &overlay->last_flip_req);
+ i915_gem_request_assign(&overlay->last_flip_req,
+ ring->outstanding_lazy_request);
+ ret = i915_add_request(ring);
if (ret)
return ret;
overlay->flip_tail = tail;
- ret = i915_wait_seqno(ring, overlay->last_flip_req);
+ ret = i915_wait_request(overlay->last_flip_req);
if (ret)
return ret;
i915_gem_retire_requests(dev);
- overlay->last_flip_req = 0;
+ i915_gem_request_assign(&overlay->last_flip_req, NULL);
return 0;
}
@@ -286,7 +288,10 @@ static int intel_overlay_continue(struct intel_overlay *overlay,
intel_ring_emit(ring, flip_addr);
intel_ring_advance(ring);
- return i915_add_request(ring, &overlay->last_flip_req);
+ WARN_ON(overlay->last_flip_req);
+ i915_gem_request_assign(&overlay->last_flip_req,
+ ring->outstanding_lazy_request);
+ return i915_add_request(ring);
}
static void intel_overlay_release_old_vid_tail(struct intel_overlay *overlay)
@@ -361,23 +366,20 @@ static int intel_overlay_off(struct intel_overlay *overlay)
* We have to be careful not to repeat work forever an make forward progess. */
static int intel_overlay_recover_from_interrupt(struct intel_overlay *overlay)
{
- struct drm_device *dev = overlay->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct intel_engine_cs *ring = &dev_priv->ring[RCS];
int ret;
- if (overlay->last_flip_req == 0)
+ if (overlay->last_flip_req == NULL)
return 0;
- ret = i915_wait_seqno(ring, overlay->last_flip_req);
+ ret = i915_wait_request(overlay->last_flip_req);
if (ret)
return ret;
- i915_gem_retire_requests(dev);
+ i915_gem_retire_requests(overlay->dev);
if (overlay->flip_tail)
overlay->flip_tail(overlay);
- overlay->last_flip_req = 0;
+ i915_gem_request_assign(&overlay->last_flip_req, NULL);
return 0;
}
@@ -392,6 +394,8 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
struct intel_engine_cs *ring = &dev_priv->ring[RCS];
int ret;
+ WARN_ON(!mutex_is_locked(&dev->struct_mutex));
+
/* Only wait if there is actually an old frame to release to
* guarantee forward progress.
*/
@@ -422,6 +426,22 @@ static int intel_overlay_release_old_vid(struct intel_overlay *overlay)
return 0;
}
+void intel_overlay_reset(struct drm_i915_private *dev_priv)
+{
+ struct intel_overlay *overlay = dev_priv->overlay;
+
+ if (!overlay)
+ return;
+
+ intel_overlay_release_old_vid(overlay);
+
+ overlay->last_flip_req = NULL;
+ overlay->old_xscale = 0;
+ overlay->old_yscale = 0;
+ overlay->crtc = NULL;
+ overlay->active = false;
+}
+
struct put_image_params {
int format;
short dst_x;
@@ -836,7 +856,7 @@ static int check_overlay_possible_on_crtc(struct intel_overlay *overlay,
return -EINVAL;
/* can't use the overlay with double wide pipe */
- if (crtc->config.double_wide)
+ if (crtc->config->double_wide)
return -EINVAL;
return 0;
diff --git a/drivers/gpu/drm/i915/intel_panel.c b/drivers/gpu/drm/i915/intel_panel.c
index 4d63839bd9b4..d8686ce89160 100644
--- a/drivers/gpu/drm/i915/intel_panel.c
+++ b/drivers/gpu/drm/i915/intel_panel.c
@@ -98,13 +98,13 @@ intel_find_panel_downclock(struct drm_device *dev,
/* adjusted_mode has been preset to be the panel's fixed mode */
void
intel_pch_panel_fitting(struct intel_crtc *intel_crtc,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
int fitting_mode)
{
struct drm_display_mode *adjusted_mode;
int x, y, width, height;
- adjusted_mode = &pipe_config->adjusted_mode;
+ adjusted_mode = &pipe_config->base.adjusted_mode;
x = y = width = height = 0;
@@ -223,10 +223,10 @@ static inline u32 panel_fitter_scaling(u32 source, u32 target)
return (FACTOR * ratio + FACTOR/2) / FACTOR;
}
-static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
+static void i965_scale_aspect(struct intel_crtc_state *pipe_config,
u32 *pfit_control)
{
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
u32 scaled_width = adjusted_mode->hdisplay *
pipe_config->pipe_src_h;
u32 scaled_height = pipe_config->pipe_src_w *
@@ -243,11 +243,11 @@ static void i965_scale_aspect(struct intel_crtc_config *pipe_config,
*pfit_control |= PFIT_ENABLE | PFIT_SCALING_AUTO;
}
-static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
+static void i9xx_scale_aspect(struct intel_crtc_state *pipe_config,
u32 *pfit_control, u32 *pfit_pgm_ratios,
u32 *border)
{
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
u32 scaled_width = adjusted_mode->hdisplay *
pipe_config->pipe_src_h;
u32 scaled_height = pipe_config->pipe_src_w *
@@ -301,14 +301,14 @@ static void i9xx_scale_aspect(struct intel_crtc_config *pipe_config,
}
void intel_gmch_panel_fitting(struct intel_crtc *intel_crtc,
- struct intel_crtc_config *pipe_config,
+ struct intel_crtc_state *pipe_config,
int fitting_mode)
{
struct drm_device *dev = intel_crtc->base.dev;
u32 pfit_control = 0, pfit_pgm_ratios = 0, border = 0;
struct drm_display_mode *adjusted_mode;
- adjusted_mode = &pipe_config->adjusted_mode;
+ adjusted_mode = &pipe_config->base.adjusted_mode;
/* Native modes don't need fitting */
if (adjusted_mode->hdisplay == pipe_config->pipe_src_w &&
@@ -962,7 +962,7 @@ void intel_panel_enable_backlight(struct intel_connector *connector)
WARN_ON(panel->backlight.max == 0);
- if (panel->backlight.level == 0) {
+ if (panel->backlight.level <= panel->backlight.min) {
panel->backlight.level = panel->backlight.max;
if (panel->backlight.device)
panel->backlight.device->props.brightness =
diff --git a/drivers/gpu/drm/i915/intel_pm.c b/drivers/gpu/drm/i915/intel_pm.c
index bf814a64582a..24d77ddcc5f4 100644
--- a/drivers/gpu/drm/i915/intel_pm.c
+++ b/drivers/gpu/drm/i915/intel_pm.c
@@ -52,17 +52,6 @@
#define INTEL_RC6p_ENABLE (1<<1)
#define INTEL_RC6pp_ENABLE (1<<2)
-/* FBC, or Frame Buffer Compression, is a technique employed to compress the
- * framebuffer contents in-memory, aiming at reducing the required bandwidth
- * during in-memory transfers and, therefore, reduce the power packet.
- *
- * The benefits of FBC are mostly visible with solid backgrounds and
- * variation-less patterns.
- *
- * FBC-related functionality can be enabled by the means of the
- * i915.i915_enable_fbc parameter
- */
-
static void gen9_init_clock_gating(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -87,614 +76,6 @@ static void gen9_init_clock_gating(struct drm_device *dev)
_MASKED_BIT_ENABLE(GEN8_4x4_STC_OPTIMIZATION_DISABLE));
}
-static void i8xx_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 fbc_ctl;
-
- dev_priv->fbc.enabled = false;
-
- /* Disable compression */
- fbc_ctl = I915_READ(FBC_CONTROL);
- if ((fbc_ctl & FBC_CTL_EN) == 0)
- return;
-
- fbc_ctl &= ~FBC_CTL_EN;
- I915_WRITE(FBC_CONTROL, fbc_ctl);
-
- /* Wait for compressing bit to clear */
- if (wait_for((I915_READ(FBC_STATUS) & FBC_STAT_COMPRESSING) == 0, 10)) {
- DRM_DEBUG_KMS("FBC idle timed out\n");
- return;
- }
-
- DRM_DEBUG_KMS("disabled FBC\n");
-}
-
-static void i8xx_enable_fbc(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->primary->fb;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int cfb_pitch;
- int i;
- u32 fbc_ctl;
-
- dev_priv->fbc.enabled = true;
-
- cfb_pitch = dev_priv->fbc.size / FBC_LL_SIZE;
- if (fb->pitches[0] < cfb_pitch)
- cfb_pitch = fb->pitches[0];
-
- /* FBC_CTL wants 32B or 64B units */
- if (IS_GEN2(dev))
- cfb_pitch = (cfb_pitch / 32) - 1;
- else
- cfb_pitch = (cfb_pitch / 64) - 1;
-
- /* Clear old tags */
- for (i = 0; i < (FBC_LL_SIZE / 32) + 1; i++)
- I915_WRITE(FBC_TAG + (i * 4), 0);
-
- if (IS_GEN4(dev)) {
- u32 fbc_ctl2;
-
- /* Set it up... */
- fbc_ctl2 = FBC_CTL_FENCE_DBL | FBC_CTL_IDLE_IMM | FBC_CTL_CPU_FENCE;
- fbc_ctl2 |= FBC_CTL_PLANE(intel_crtc->plane);
- I915_WRITE(FBC_CONTROL2, fbc_ctl2);
- I915_WRITE(FBC_FENCE_OFF, crtc->y);
- }
-
- /* enable it... */
- fbc_ctl = I915_READ(FBC_CONTROL);
- fbc_ctl &= 0x3fff << FBC_CTL_INTERVAL_SHIFT;
- fbc_ctl |= FBC_CTL_EN | FBC_CTL_PERIODIC;
- if (IS_I945GM(dev))
- fbc_ctl |= FBC_CTL_C3_IDLE; /* 945 needs special SR handling */
- fbc_ctl |= (cfb_pitch & 0xff) << FBC_CTL_STRIDE_SHIFT;
- fbc_ctl |= obj->fence_reg;
- I915_WRITE(FBC_CONTROL, fbc_ctl);
-
- DRM_DEBUG_KMS("enabled FBC, pitch %d, yoff %d, plane %c\n",
- cfb_pitch, crtc->y, plane_name(intel_crtc->plane));
-}
-
-static bool i8xx_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return I915_READ(FBC_CONTROL) & FBC_CTL_EN;
-}
-
-static void g4x_enable_fbc(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->primary->fb;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- u32 dpfc_ctl;
-
- dev_priv->fbc.enabled = true;
-
- dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane) | DPFC_SR_EN;
- if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
- dpfc_ctl |= DPFC_CTL_LIMIT_2X;
- else
- dpfc_ctl |= DPFC_CTL_LIMIT_1X;
- dpfc_ctl |= DPFC_CTL_FENCE_EN | obj->fence_reg;
-
- I915_WRITE(DPFC_FENCE_YOFF, crtc->y);
-
- /* enable it... */
- I915_WRITE(DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
- DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
-}
-
-static void g4x_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpfc_ctl;
-
- dev_priv->fbc.enabled = false;
-
- /* Disable compression */
- dpfc_ctl = I915_READ(DPFC_CONTROL);
- if (dpfc_ctl & DPFC_CTL_EN) {
- dpfc_ctl &= ~DPFC_CTL_EN;
- I915_WRITE(DPFC_CONTROL, dpfc_ctl);
-
- DRM_DEBUG_KMS("disabled FBC\n");
- }
-}
-
-static bool g4x_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return I915_READ(DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-static void sandybridge_blit_fbc_update(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 blt_ecoskpd;
-
- /* Make sure blitter notifies FBC of writes */
-
- /* Blitter is part of Media powerwell on VLV. No impact of
- * his param in other platforms for now */
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_MEDIA);
-
- blt_ecoskpd = I915_READ(GEN6_BLITTER_ECOSKPD);
- blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY <<
- GEN6_BLITTER_LOCK_SHIFT;
- I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
- blt_ecoskpd |= GEN6_BLITTER_FBC_NOTIFY;
- I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
- blt_ecoskpd &= ~(GEN6_BLITTER_FBC_NOTIFY <<
- GEN6_BLITTER_LOCK_SHIFT);
- I915_WRITE(GEN6_BLITTER_ECOSKPD, blt_ecoskpd);
- POSTING_READ(GEN6_BLITTER_ECOSKPD);
-
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_MEDIA);
-}
-
-static void ironlake_enable_fbc(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->primary->fb;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- u32 dpfc_ctl;
-
- dev_priv->fbc.enabled = true;
-
- dpfc_ctl = DPFC_CTL_PLANE(intel_crtc->plane);
- if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
- dev_priv->fbc.threshold++;
-
- switch (dev_priv->fbc.threshold) {
- case 4:
- case 3:
- dpfc_ctl |= DPFC_CTL_LIMIT_4X;
- break;
- case 2:
- dpfc_ctl |= DPFC_CTL_LIMIT_2X;
- break;
- case 1:
- dpfc_ctl |= DPFC_CTL_LIMIT_1X;
- break;
- }
- dpfc_ctl |= DPFC_CTL_FENCE_EN;
- if (IS_GEN5(dev))
- dpfc_ctl |= obj->fence_reg;
-
- I915_WRITE(ILK_DPFC_FENCE_YOFF, crtc->y);
- I915_WRITE(ILK_FBC_RT_BASE, i915_gem_obj_ggtt_offset(obj) | ILK_FBC_RT_VALID);
- /* enable it... */
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
- if (IS_GEN6(dev)) {
- I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | obj->fence_reg);
- I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
- sandybridge_blit_fbc_update(dev);
- }
-
- DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
-}
-
-static void ironlake_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- u32 dpfc_ctl;
-
- dev_priv->fbc.enabled = false;
-
- /* Disable compression */
- dpfc_ctl = I915_READ(ILK_DPFC_CONTROL);
- if (dpfc_ctl & DPFC_CTL_EN) {
- dpfc_ctl &= ~DPFC_CTL_EN;
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl);
-
- DRM_DEBUG_KMS("disabled FBC\n");
- }
-}
-
-static bool ironlake_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return I915_READ(ILK_DPFC_CONTROL) & DPFC_CTL_EN;
-}
-
-static void gen7_enable_fbc(struct drm_crtc *crtc)
-{
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_framebuffer *fb = crtc->primary->fb;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- u32 dpfc_ctl;
-
- dev_priv->fbc.enabled = true;
-
- dpfc_ctl = IVB_DPFC_CTL_PLANE(intel_crtc->plane);
- if (drm_format_plane_cpp(fb->pixel_format, 0) == 2)
- dev_priv->fbc.threshold++;
-
- switch (dev_priv->fbc.threshold) {
- case 4:
- case 3:
- dpfc_ctl |= DPFC_CTL_LIMIT_4X;
- break;
- case 2:
- dpfc_ctl |= DPFC_CTL_LIMIT_2X;
- break;
- case 1:
- dpfc_ctl |= DPFC_CTL_LIMIT_1X;
- break;
- }
-
- dpfc_ctl |= IVB_DPFC_CTL_FENCE_EN;
-
- if (dev_priv->fbc.false_color)
- dpfc_ctl |= FBC_CTL_FALSE_COLOR;
-
- I915_WRITE(ILK_DPFC_CONTROL, dpfc_ctl | DPFC_CTL_EN);
-
- if (IS_IVYBRIDGE(dev)) {
- /* WaFbcAsynchFlipDisableFbcQueue:ivb */
- I915_WRITE(ILK_DISPLAY_CHICKEN1,
- I915_READ(ILK_DISPLAY_CHICKEN1) |
- ILK_FBCQ_DIS);
- } else {
- /* WaFbcAsynchFlipDisableFbcQueue:hsw,bdw */
- I915_WRITE(CHICKEN_PIPESL_1(intel_crtc->pipe),
- I915_READ(CHICKEN_PIPESL_1(intel_crtc->pipe)) |
- HSW_FBCQ_DIS);
- }
-
- I915_WRITE(SNB_DPFC_CTL_SA,
- SNB_CPU_FENCE_ENABLE | obj->fence_reg);
- I915_WRITE(DPFC_CPU_FENCE_OFFSET, crtc->y);
-
- sandybridge_blit_fbc_update(dev);
-
- DRM_DEBUG_KMS("enabled fbc on plane %c\n", plane_name(intel_crtc->plane));
-}
-
-bool intel_fbc_enabled(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- return dev_priv->fbc.enabled;
-}
-
-void bdw_fbc_sw_flush(struct drm_device *dev, u32 value)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (!IS_GEN8(dev))
- return;
-
- if (!intel_fbc_enabled(dev))
- return;
-
- I915_WRITE(MSG_FBC_REND_STATE, value);
-}
-
-static void intel_fbc_work_fn(struct work_struct *__work)
-{
- struct intel_fbc_work *work =
- container_of(to_delayed_work(__work),
- struct intel_fbc_work, work);
- struct drm_device *dev = work->crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- mutex_lock(&dev->struct_mutex);
- if (work == dev_priv->fbc.fbc_work) {
- /* Double check that we haven't switched fb without cancelling
- * the prior work.
- */
- if (work->crtc->primary->fb == work->fb) {
- dev_priv->display.enable_fbc(work->crtc);
-
- dev_priv->fbc.plane = to_intel_crtc(work->crtc)->plane;
- dev_priv->fbc.fb_id = work->crtc->primary->fb->base.id;
- dev_priv->fbc.y = work->crtc->y;
- }
-
- dev_priv->fbc.fbc_work = NULL;
- }
- mutex_unlock(&dev->struct_mutex);
-
- kfree(work);
-}
-
-static void intel_cancel_fbc_work(struct drm_i915_private *dev_priv)
-{
- if (dev_priv->fbc.fbc_work == NULL)
- return;
-
- DRM_DEBUG_KMS("cancelling pending FBC enable\n");
-
- /* Synchronisation is provided by struct_mutex and checking of
- * dev_priv->fbc.fbc_work, so we can perform the cancellation
- * entirely asynchronously.
- */
- if (cancel_delayed_work(&dev_priv->fbc.fbc_work->work))
- /* tasklet was killed before being run, clean up */
- kfree(dev_priv->fbc.fbc_work);
-
- /* Mark the work as no longer wanted so that if it does
- * wake-up (because the work was already running and waiting
- * for our mutex), it will discover that is no longer
- * necessary to run.
- */
- dev_priv->fbc.fbc_work = NULL;
-}
-
-static void intel_enable_fbc(struct drm_crtc *crtc)
-{
- struct intel_fbc_work *work;
- struct drm_device *dev = crtc->dev;
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- if (!dev_priv->display.enable_fbc)
- return;
-
- intel_cancel_fbc_work(dev_priv);
-
- work = kzalloc(sizeof(*work), GFP_KERNEL);
- if (work == NULL) {
- DRM_ERROR("Failed to allocate FBC work structure\n");
- dev_priv->display.enable_fbc(crtc);
- return;
- }
-
- work->crtc = crtc;
- work->fb = crtc->primary->fb;
- INIT_DELAYED_WORK(&work->work, intel_fbc_work_fn);
-
- dev_priv->fbc.fbc_work = work;
-
- /* Delay the actual enabling to let pageflipping cease and the
- * display to settle before starting the compression. Note that
- * this delay also serves a second purpose: it allows for a
- * vblank to pass after disabling the FBC before we attempt
- * to modify the control registers.
- *
- * A more complicated solution would involve tracking vblanks
- * following the termination of the page-flipping sequence
- * and indeed performing the enable as a co-routine and not
- * waiting synchronously upon the vblank.
- *
- * WaFbcWaitForVBlankBeforeEnable:ilk,snb
- */
- schedule_delayed_work(&work->work, msecs_to_jiffies(50));
-}
-
-void intel_disable_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
-
- intel_cancel_fbc_work(dev_priv);
-
- if (!dev_priv->display.disable_fbc)
- return;
-
- dev_priv->display.disable_fbc(dev);
- dev_priv->fbc.plane = -1;
-}
-
-static bool set_no_fbc_reason(struct drm_i915_private *dev_priv,
- enum no_fbc_reason reason)
-{
- if (dev_priv->fbc.no_fbc_reason == reason)
- return false;
-
- dev_priv->fbc.no_fbc_reason = reason;
- return true;
-}
-
-/**
- * intel_update_fbc - enable/disable FBC as needed
- * @dev: the drm_device
- *
- * Set up the framebuffer compression hardware at mode set time. We
- * enable it if possible:
- * - plane A only (on pre-965)
- * - no pixel mulitply/line duplication
- * - no alpha buffer discard
- * - no dual wide
- * - framebuffer <= max_hdisplay in width, max_vdisplay in height
- *
- * We can't assume that any compression will take place (worst case),
- * so the compressed buffer has to be the same size as the uncompressed
- * one. It also must reside (along with the line length buffer) in
- * stolen memory.
- *
- * We need to enable/disable FBC on a global basis.
- */
-void intel_update_fbc(struct drm_device *dev)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- struct drm_crtc *crtc = NULL, *tmp_crtc;
- struct intel_crtc *intel_crtc;
- struct drm_framebuffer *fb;
- struct drm_i915_gem_object *obj;
- const struct drm_display_mode *adjusted_mode;
- unsigned int max_width, max_height;
-
- if (!HAS_FBC(dev)) {
- set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED);
- return;
- }
-
- if (!i915.powersave) {
- if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
- DRM_DEBUG_KMS("fbc disabled per module param\n");
- return;
- }
-
- /*
- * If FBC is already on, we just have to verify that we can
- * keep it that way...
- * Need to disable if:
- * - more than one pipe is active
- * - changing FBC params (stride, fence, mode)
- * - new fb is too large to fit in compressed buffer
- * - going to an unsupported config (interlace, pixel multiply, etc.)
- */
- for_each_crtc(dev, tmp_crtc) {
- if (intel_crtc_active(tmp_crtc) &&
- to_intel_crtc(tmp_crtc)->primary_enabled) {
- if (crtc) {
- if (set_no_fbc_reason(dev_priv, FBC_MULTIPLE_PIPES))
- DRM_DEBUG_KMS("more than one pipe active, disabling compression\n");
- goto out_disable;
- }
- crtc = tmp_crtc;
- }
- }
-
- if (!crtc || crtc->primary->fb == NULL) {
- if (set_no_fbc_reason(dev_priv, FBC_NO_OUTPUT))
- DRM_DEBUG_KMS("no output, disabling\n");
- goto out_disable;
- }
-
- intel_crtc = to_intel_crtc(crtc);
- fb = crtc->primary->fb;
- obj = intel_fb_obj(fb);
- adjusted_mode = &intel_crtc->config.adjusted_mode;
-
- if (i915.enable_fbc < 0) {
- if (set_no_fbc_reason(dev_priv, FBC_CHIP_DEFAULT))
- DRM_DEBUG_KMS("disabled per chip default\n");
- goto out_disable;
- }
- if (!i915.enable_fbc) {
- if (set_no_fbc_reason(dev_priv, FBC_MODULE_PARAM))
- DRM_DEBUG_KMS("fbc disabled per module param\n");
- goto out_disable;
- }
- if ((adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE) ||
- (adjusted_mode->flags & DRM_MODE_FLAG_DBLSCAN)) {
- if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
- DRM_DEBUG_KMS("mode incompatible with compression, "
- "disabling\n");
- goto out_disable;
- }
-
- if (INTEL_INFO(dev)->gen >= 8 || IS_HASWELL(dev)) {
- max_width = 4096;
- max_height = 4096;
- } else if (IS_G4X(dev) || INTEL_INFO(dev)->gen >= 5) {
- max_width = 4096;
- max_height = 2048;
- } else {
- max_width = 2048;
- max_height = 1536;
- }
- if (intel_crtc->config.pipe_src_w > max_width ||
- intel_crtc->config.pipe_src_h > max_height) {
- if (set_no_fbc_reason(dev_priv, FBC_MODE_TOO_LARGE))
- DRM_DEBUG_KMS("mode too large for compression, disabling\n");
- goto out_disable;
- }
- if ((INTEL_INFO(dev)->gen < 4 || HAS_DDI(dev)) &&
- intel_crtc->plane != PLANE_A) {
- if (set_no_fbc_reason(dev_priv, FBC_BAD_PLANE))
- DRM_DEBUG_KMS("plane not A, disabling compression\n");
- goto out_disable;
- }
-
- /* The use of a CPU fence is mandatory in order to detect writes
- * by the CPU to the scanout and trigger updates to the FBC.
- */
- if (obj->tiling_mode != I915_TILING_X ||
- obj->fence_reg == I915_FENCE_REG_NONE) {
- if (set_no_fbc_reason(dev_priv, FBC_NOT_TILED))
- DRM_DEBUG_KMS("framebuffer not tiled or fenced, disabling compression\n");
- goto out_disable;
- }
- if (INTEL_INFO(dev)->gen <= 4 && !IS_G4X(dev) &&
- to_intel_plane(crtc->primary)->rotation != BIT(DRM_ROTATE_0)) {
- if (set_no_fbc_reason(dev_priv, FBC_UNSUPPORTED_MODE))
- DRM_DEBUG_KMS("Rotation unsupported, disabling\n");
- goto out_disable;
- }
-
- /* If the kernel debugger is active, always disable compression */
- if (in_dbg_master())
- goto out_disable;
-
- if (i915_gem_stolen_setup_compression(dev, obj->base.size,
- drm_format_plane_cpp(fb->pixel_format, 0))) {
- if (set_no_fbc_reason(dev_priv, FBC_STOLEN_TOO_SMALL))
- DRM_DEBUG_KMS("framebuffer too large, disabling compression\n");
- goto out_disable;
- }
-
- /* If the scanout has not changed, don't modify the FBC settings.
- * Note that we make the fundamental assumption that the fb->obj
- * cannot be unpinned (and have its GTT offset and fence revoked)
- * without first being decoupled from the scanout and FBC disabled.
- */
- if (dev_priv->fbc.plane == intel_crtc->plane &&
- dev_priv->fbc.fb_id == fb->base.id &&
- dev_priv->fbc.y == crtc->y)
- return;
-
- if (intel_fbc_enabled(dev)) {
- /* We update FBC along two paths, after changing fb/crtc
- * configuration (modeswitching) and after page-flipping
- * finishes. For the latter, we know that not only did
- * we disable the FBC at the start of the page-flip
- * sequence, but also more than one vblank has passed.
- *
- * For the former case of modeswitching, it is possible
- * to switch between two FBC valid configurations
- * instantaneously so we do need to disable the FBC
- * before we can modify its control registers. We also
- * have to wait for the next vblank for that to take
- * effect. However, since we delay enabling FBC we can
- * assume that a vblank has passed since disabling and
- * that we can safely alter the registers in the deferred
- * callback.
- *
- * In the scenario that we go from a valid to invalid
- * and then back to valid FBC configuration we have
- * no strict enforcement that a vblank occurred since
- * disabling the FBC. However, along all current pipe
- * disabling paths we do need to wait for a vblank at
- * some point. And we wait before enabling FBC anyway.
- */
- DRM_DEBUG_KMS("disabling active FBC for update\n");
- intel_disable_fbc(dev);
- }
-
- intel_enable_fbc(crtc);
- dev_priv->fbc.no_fbc_reason = FBC_OK;
- return;
-
-out_disable:
- /* Multiple disables should be harmless */
- if (intel_fbc_enabled(dev)) {
- DRM_DEBUG_KMS("unsupported config, disabling FBC\n");
- intel_disable_fbc(dev);
- }
- i915_gem_stolen_cleanup_compression(dev);
-}
-
static void i915_pineview_get_mem_freq(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1157,7 +538,7 @@ static void pineview_update_wm(struct drm_crtc *unused_crtc)
int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
int clock;
- adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+ adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
clock = adjusted_mode->crtc_clock;
/* Display SR */
@@ -1226,10 +607,10 @@ static bool g4x_compute_wm0(struct drm_device *dev,
return false;
}
- adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+ adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
clock = adjusted_mode->crtc_clock;
htotal = adjusted_mode->crtc_htotal;
- hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
+ hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
pixel_size = crtc->primary->fb->bits_per_pixel / 8;
/* Use the small buffer method to calculate plane watermark */
@@ -1313,10 +694,10 @@ static bool g4x_compute_srwm(struct drm_device *dev,
}
crtc = intel_get_crtc_for_plane(dev, plane);
- adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+ adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
clock = adjusted_mode->crtc_clock;
htotal = adjusted_mode->crtc_htotal;
- hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
+ hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
pixel_size = crtc->primary->fb->bits_per_pixel / 8;
line_time_us = max(htotal * 1000 / clock, 1);
@@ -1347,7 +728,7 @@ static bool vlv_compute_drain_latency(struct drm_crtc *crtc,
{
struct drm_device *dev = crtc->dev;
int entries;
- int clock = to_intel_crtc(crtc)->config.adjusted_mode.crtc_clock;
+ int clock = to_intel_crtc(crtc)->config->base.adjusted_mode.crtc_clock;
if (WARN(clock == 0, "Pixel clock is zero!\n"))
return false;
@@ -1677,10 +1058,10 @@ static void i965_update_wm(struct drm_crtc *unused_crtc)
/* self-refresh has much higher latency */
static const int sr_latency_ns = 12000;
const struct drm_display_mode *adjusted_mode =
- &to_intel_crtc(crtc)->config.adjusted_mode;
+ &to_intel_crtc(crtc)->config->base.adjusted_mode;
int clock = adjusted_mode->crtc_clock;
int htotal = adjusted_mode->crtc_htotal;
- int hdisplay = to_intel_crtc(crtc)->config.pipe_src_w;
+ int hdisplay = to_intel_crtc(crtc)->config->pipe_src_w;
int pixel_size = crtc->primary->fb->bits_per_pixel / 8;
unsigned long line_time_us;
int entries;
@@ -1762,7 +1143,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
if (IS_GEN2(dev))
cpp = 4;
- adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+ adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
wm_info, fifo_size, cpp,
pessimal_latency_ns);
@@ -1784,7 +1165,7 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
if (IS_GEN2(dev))
cpp = 4;
- adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+ adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
planeb_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
wm_info, fifo_size, cpp,
pessimal_latency_ns);
@@ -1823,10 +1204,10 @@ static void i9xx_update_wm(struct drm_crtc *unused_crtc)
/* self-refresh has much higher latency */
static const int sr_latency_ns = 6000;
const struct drm_display_mode *adjusted_mode =
- &to_intel_crtc(enabled)->config.adjusted_mode;
+ &to_intel_crtc(enabled)->config->base.adjusted_mode;
int clock = adjusted_mode->crtc_clock;
int htotal = adjusted_mode->crtc_htotal;
- int hdisplay = to_intel_crtc(enabled)->config.pipe_src_w;
+ int hdisplay = to_intel_crtc(enabled)->config->pipe_src_w;
int pixel_size = enabled->primary->fb->bits_per_pixel / 8;
unsigned long line_time_us;
int entries;
@@ -1879,7 +1260,7 @@ static void i845_update_wm(struct drm_crtc *unused_crtc)
if (crtc == NULL)
return;
- adjusted_mode = &to_intel_crtc(crtc)->config.adjusted_mode;
+ adjusted_mode = &to_intel_crtc(crtc)->config->base.adjusted_mode;
planea_wm = intel_calculate_wm(adjusted_mode->crtc_clock,
&i845_wm_info,
dev_priv->display.get_fifo_size(dev, 0),
@@ -1898,17 +1279,17 @@ static uint32_t ilk_pipe_pixel_rate(struct drm_device *dev,
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
uint32_t pixel_rate;
- pixel_rate = intel_crtc->config.adjusted_mode.crtc_clock;
+ pixel_rate = intel_crtc->config->base.adjusted_mode.crtc_clock;
/* We only use IF-ID interlacing. If we ever use PF-ID we'll need to
* adjust the pixel_rate here. */
- if (intel_crtc->config.pch_pfit.enabled) {
+ if (intel_crtc->config->pch_pfit.enabled) {
uint64_t pipe_w, pipe_h, pfit_w, pfit_h;
- uint32_t pfit_size = intel_crtc->config.pch_pfit.size;
+ uint32_t pfit_size = intel_crtc->config->pch_pfit.size;
- pipe_w = intel_crtc->config.pipe_src_w;
- pipe_h = intel_crtc->config.pipe_src_h;
+ pipe_w = intel_crtc->config->pipe_src_w;
+ pipe_h = intel_crtc->config->pipe_src_h;
pfit_w = (pfit_size >> 16) & 0xFFFF;
pfit_h = pfit_size & 0xFFFF;
if (pipe_w < pfit_w)
@@ -2261,7 +1642,7 @@ hsw_compute_linetime_wm(struct drm_device *dev, struct drm_crtc *crtc)
{
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct drm_display_mode *mode = &intel_crtc->config.adjusted_mode;
+ struct drm_display_mode *mode = &intel_crtc->config->base.adjusted_mode;
u32 linetime, ips_linetime;
if (!intel_crtc_active(crtc))
@@ -2521,11 +1902,11 @@ static void ilk_compute_wm_parameters(struct drm_crtc *crtc,
return;
p->active = true;
- p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
+ p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
p->pixel_rate = ilk_pipe_pixel_rate(dev, crtc);
p->pri.bytes_per_pixel = crtc->primary->fb->bits_per_pixel / 8;
p->cur.bytes_per_pixel = 4;
- p->pri.horiz_pixels = intel_crtc->config.pipe_src_w;
+ p->pri.horiz_pixels = intel_crtc->config->pipe_src_w;
p->cur.horiz_pixels = intel_crtc->cursor_width;
/* TODO: for now, assume primary and cursor planes are always enabled. */
p->pri.enabled = true;
@@ -3174,10 +2555,10 @@ skl_allocate_pipe_ddb(struct drm_crtc *crtc,
}
-static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_config *config)
+static uint32_t skl_pipe_pixel_rate(const struct intel_crtc_state *config)
{
/* TODO: Take into account the scalers once we support them */
- return config->adjusted_mode.crtc_clock;
+ return config->base.adjusted_mode.crtc_clock;
}
/*
@@ -3265,8 +2646,8 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
p->active = intel_crtc_active(crtc);
if (p->active) {
- p->pipe_htotal = intel_crtc->config.adjusted_mode.crtc_htotal;
- p->pixel_rate = skl_pipe_pixel_rate(&intel_crtc->config);
+ p->pipe_htotal = intel_crtc->config->base.adjusted_mode.crtc_htotal;
+ p->pixel_rate = skl_pipe_pixel_rate(intel_crtc->config);
/*
* For now, assume primary and cursor planes are always enabled.
@@ -3274,8 +2655,8 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
p->plane[0].enabled = true;
p->plane[0].bytes_per_pixel =
crtc->primary->fb->bits_per_pixel / 8;
- p->plane[0].horiz_pixels = intel_crtc->config.pipe_src_w;
- p->plane[0].vert_pixels = intel_crtc->config.pipe_src_h;
+ p->plane[0].horiz_pixels = intel_crtc->config->pipe_src_w;
+ p->plane[0].vert_pixels = intel_crtc->config->pipe_src_h;
p->cursor.enabled = true;
p->cursor.bytes_per_pixel = 4;
@@ -3286,7 +2667,8 @@ static void skl_compute_wm_pipe_parameters(struct drm_crtc *crtc,
list_for_each_entry(plane, &dev->mode_config.plane_list, head) {
struct intel_plane *intel_plane = to_intel_plane(plane);
- if (intel_plane->pipe == pipe)
+ if (intel_plane->pipe == pipe &&
+ plane->type == DRM_PLANE_TYPE_OVERLAY)
p->plane[i++] = intel_plane->wm;
}
}
@@ -3621,9 +3003,8 @@ static void skl_flush_wm_values(struct drm_i915_private *dev_priv,
skl_ddb_entry_size(&cur_ddb->pipe[pipe])) {
skl_wm_flush_pipe(dev_priv, pipe, 2);
intel_wait_for_vblank(dev, pipe);
+ reallocated[pipe] = true;
}
-
- reallocated[pipe] = true;
}
/*
@@ -4418,8 +3799,8 @@ static void vlv_set_rps_idle(struct drm_i915_private *dev_priv)
{
struct drm_device *dev = dev_priv->dev;
- /* Latest VLV doesn't need to force the gfx clock */
- if (dev->pdev->revision >= 0xd) {
+ /* CHV and latest VLV don't need to force the gfx clock */
+ if (IS_CHERRYVIEW(dev) || dev->pdev->revision >= 0xd) {
valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
return;
}
@@ -4458,9 +3839,7 @@ void gen6_rps_idle(struct drm_i915_private *dev_priv)
mutex_lock(&dev_priv->rps.hw_lock);
if (dev_priv->rps.enabled) {
- if (IS_CHERRYVIEW(dev))
- valleyview_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
- else if (IS_VALLEYVIEW(dev))
+ if (IS_VALLEYVIEW(dev))
vlv_set_rps_idle(dev_priv);
else
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
@@ -4502,7 +3881,7 @@ void valleyview_set_rps(struct drm_device *dev, u8 val)
I915_WRITE(GEN6_PMINTRMSK, gen6_rps_pm_mask(dev_priv, val));
dev_priv->rps.cur_freq = val;
- trace_intel_gpu_freq_change(vlv_gpu_freq(dev_priv, val));
+ trace_intel_gpu_freq_change(intel_gpu_freq(dev_priv, val));
}
static void gen9_disable_rps(struct drm_device *dev)
@@ -4510,6 +3889,7 @@ static void gen9_disable_rps(struct drm_device *dev)
struct drm_i915_private *dev_priv = dev->dev_private;
I915_WRITE(GEN6_RC_CONTROL, 0);
+ I915_WRITE(GEN9_PG_ENABLE, 0);
}
static void gen6_disable_rps(struct drm_device *dev)
@@ -4533,11 +3913,11 @@ static void valleyview_disable_rps(struct drm_device *dev)
/* we're doing forcewake before Disabling RC6,
* This what the BIOS expects when going into suspend */
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
I915_WRITE(GEN6_RC_CONTROL, 0);
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
static void intel_print_rc6_info(struct drm_device *dev, u32 mode)
@@ -4625,7 +4005,10 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
&ddcc_status);
if (0 == ret)
dev_priv->rps.efficient_freq =
- (ddcc_status >> 8) & 0xff;
+ clamp_t(u8,
+ ((ddcc_status >> 8) & 0xff),
+ dev_priv->rps.min_freq,
+ dev_priv->rps.max_freq);
}
/* Preserve min/max settings in case of re-init */
@@ -4643,9 +4026,39 @@ static void gen6_init_rps_frequencies(struct drm_device *dev)
}
}
+/* See the Gen9_GT_PM_Programming_Guide doc for the below */
static void gen9_enable_rps(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+ gen6_init_rps_frequencies(dev);
+
+ I915_WRITE(GEN6_RPNSWREQ, 0xc800000);
+ I915_WRITE(GEN6_RC_VIDEO_FREQ, 0xc800000);
+
+ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 0xf4240);
+ I915_WRITE(GEN6_RP_INTERRUPT_LIMITS, 0x12060000);
+ I915_WRITE(GEN6_RP_UP_THRESHOLD, 0xe808);
+ I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 0x3bd08);
+ I915_WRITE(GEN6_RP_UP_EI, 0x101d0);
+ I915_WRITE(GEN6_RP_DOWN_EI, 0x55730);
+ I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 0xa);
+ I915_WRITE(GEN6_PMINTRMSK, 0x6);
+ I915_WRITE(GEN6_RP_CONTROL, GEN6_RP_MEDIA_TURBO |
+ GEN6_RP_MEDIA_HW_MODE | GEN6_RP_MEDIA_IS_GFX |
+ GEN6_RP_ENABLE | GEN6_RP_UP_BUSY_AVG |
+ GEN6_RP_DOWN_IDLE_AVG);
+
+ gen6_enable_rps_interrupts(dev);
+
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
+}
+
+static void gen9_enable_rc6(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_engine_cs *ring;
uint32_t rc6_mask = 0;
int unused;
@@ -4655,7 +4068,7 @@ static void gen9_enable_rps(struct drm_device *dev)
/* 1b: Get forcewake during program sequence. Although the driver
* hasn't enabled a state yet where we need forcewake, BIOS may have.*/
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
/* 2a: Disable RC states. */
I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -4669,6 +4082,10 @@ static void gen9_enable_rps(struct drm_device *dev)
I915_WRITE(GEN6_RC_SLEEP, 0);
I915_WRITE(GEN6_RC6_THRESHOLD, 37500); /* 37.5/125ms per EI */
+ /* 2c: Program Coarse Power Gating Policies. */
+ I915_WRITE(GEN9_MEDIA_PG_IDLE_HYSTERESIS, 25);
+ I915_WRITE(GEN9_RENDER_PG_IDLE_HYSTERESIS, 25);
+
/* 3a: Enable RC6 */
if (intel_enable_rc6(dev) & INTEL_RC6_ENABLE)
rc6_mask = GEN6_RC_CTL_RC6_ENABLE;
@@ -4678,7 +4095,10 @@ static void gen9_enable_rps(struct drm_device *dev)
GEN6_RC_CTL_EI_MODE(1) |
rc6_mask);
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ /* 3b: Enable Coarse Power Gating only when RC6 is enabled */
+ I915_WRITE(GEN9_PG_ENABLE, (rc6_mask & GEN6_RC_CTL_RC6_ENABLE) ? 3 : 0);
+
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
@@ -4694,7 +4114,7 @@ static void gen8_enable_rps(struct drm_device *dev)
/* 1c & 1d: Get forcewake during program sequence. Although the driver
* hasn't enabled a state yet where we need forcewake, BIOS may have.*/
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
/* 2a: Disable RC states. */
I915_WRITE(GEN6_RC_CONTROL, 0);
@@ -4761,7 +4181,7 @@ static void gen8_enable_rps(struct drm_device *dev)
dev_priv->rps.power = HIGH_POWER; /* force a reset */
gen6_set_rps(dev_priv->dev, dev_priv->rps.min_freq_softlimit);
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
static void gen6_enable_rps(struct drm_device *dev)
@@ -4789,7 +4209,7 @@ static void gen6_enable_rps(struct drm_device *dev)
I915_WRITE(GTFIFODBG, gtfifodbg);
}
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
/* Initialize rps frequencies */
gen6_init_rps_frequencies(dev);
@@ -4869,7 +4289,7 @@ static void gen6_enable_rps(struct drm_device *dev)
DRM_ERROR("Couldn't fix incorrect rc6 voltage\n");
}
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
static void __gen6_update_ring_freq(struct drm_device *dev)
@@ -4956,11 +4376,35 @@ void gen6_update_ring_freq(struct drm_device *dev)
static int cherryview_rps_max_freq(struct drm_i915_private *dev_priv)
{
+ struct drm_device *dev = dev_priv->dev;
u32 val, rp0;
- val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
- rp0 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) & PUNIT_GPU_STATUS_MAX_FREQ_MASK;
+ if (dev->pdev->revision >= 0x20) {
+ val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
+ switch (INTEL_INFO(dev)->eu_total) {
+ case 8:
+ /* (2 * 4) config */
+ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS4EU_FUSE_SHIFT);
+ break;
+ case 12:
+ /* (2 * 6) config */
+ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS6EU_FUSE_SHIFT);
+ break;
+ case 16:
+ /* (2 * 8) config */
+ default:
+ /* Setting (2 * 8) Min RP0 for any other combination */
+ rp0 = (val >> FB_GFX_FMAX_AT_VMAX_2SS8EU_FUSE_SHIFT);
+ break;
+ }
+ rp0 = (rp0 & FB_GFX_FREQ_FUSE_MASK);
+ } else {
+ /* For pre-production hardware */
+ val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
+ rp0 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) &
+ PUNIT_GPU_STATUS_MAX_FREQ_MASK;
+ }
return rp0;
}
@@ -4976,20 +4420,36 @@ static int cherryview_rps_rpe_freq(struct drm_i915_private *dev_priv)
static int cherryview_rps_guar_freq(struct drm_i915_private *dev_priv)
{
+ struct drm_device *dev = dev_priv->dev;
u32 val, rp1;
- val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
- rp1 = (val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) & PUNIT_GPU_STATUS_MAX_FREQ_MASK;
-
+ if (dev->pdev->revision >= 0x20) {
+ val = vlv_punit_read(dev_priv, FB_GFX_FMAX_AT_VMAX_FUSE);
+ rp1 = (val & FB_GFX_FREQ_FUSE_MASK);
+ } else {
+ /* For pre-production hardware */
+ val = vlv_punit_read(dev_priv, PUNIT_REG_GPU_FREQ_STS);
+ rp1 = ((val >> PUNIT_GPU_STATUS_MAX_FREQ_SHIFT) &
+ PUNIT_GPU_STATUS_MAX_FREQ_MASK);
+ }
return rp1;
}
static int cherryview_rps_min_freq(struct drm_i915_private *dev_priv)
{
+ struct drm_device *dev = dev_priv->dev;
u32 val, rpn;
- val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
- rpn = (val >> PUNIT_GPU_STATIS_GFX_MIN_FREQ_SHIFT) & PUNIT_GPU_STATUS_GFX_MIN_FREQ_MASK;
+ if (dev->pdev->revision >= 0x20) {
+ val = vlv_punit_read(dev_priv, FB_GFX_FMIN_AT_VMIN_FUSE);
+ rpn = ((val >> FB_GFX_FMIN_AT_VMIN_FUSE_SHIFT) &
+ FB_GFX_FREQ_FUSE_MASK);
+ } else { /* For pre-production hardware */
+ val = vlv_punit_read(dev_priv, PUNIT_GPU_STATUS_REG);
+ rpn = ((val >> PUNIT_GPU_STATIS_GFX_MIN_FREQ_SHIFT) &
+ PUNIT_GPU_STATUS_GFX_MIN_FREQ_MASK);
+ }
+
return rpn;
}
@@ -5160,22 +4620,22 @@ static void valleyview_init_gt_powersave(struct drm_device *dev)
dev_priv->rps.max_freq = valleyview_rps_max_freq(dev_priv);
dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.max_freq),
dev_priv->rps.max_freq);
dev_priv->rps.efficient_freq = valleyview_rps_rpe_freq(dev_priv);
DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
dev_priv->rps.efficient_freq);
dev_priv->rps.rp1_freq = valleyview_rps_guar_freq(dev_priv);
DRM_DEBUG_DRIVER("RP1(Guar Freq) GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
dev_priv->rps.rp1_freq);
dev_priv->rps.min_freq = valleyview_rps_min_freq(dev_priv);
DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
dev_priv->rps.min_freq);
/* Preserve min/max settings in case of re-init */
@@ -5229,22 +4689,22 @@ static void cherryview_init_gt_powersave(struct drm_device *dev)
dev_priv->rps.max_freq = cherryview_rps_max_freq(dev_priv);
dev_priv->rps.rp0_freq = dev_priv->rps.max_freq;
DRM_DEBUG_DRIVER("max GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.max_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.max_freq),
dev_priv->rps.max_freq);
dev_priv->rps.efficient_freq = cherryview_rps_rpe_freq(dev_priv);
DRM_DEBUG_DRIVER("RPe GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
dev_priv->rps.efficient_freq);
dev_priv->rps.rp1_freq = cherryview_rps_guar_freq(dev_priv);
DRM_DEBUG_DRIVER("RP1(Guar) GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.rp1_freq),
dev_priv->rps.rp1_freq);
dev_priv->rps.min_freq = cherryview_rps_min_freq(dev_priv);
DRM_DEBUG_DRIVER("min GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.min_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.min_freq),
dev_priv->rps.min_freq);
WARN_ONCE((dev_priv->rps.max_freq |
@@ -5288,7 +4748,10 @@ static void cherryview_enable_rps(struct drm_device *dev)
/* 1a & 1b: Get forcewake during program sequence. Although the driver
* hasn't enabled a state yet where we need forcewake, BIOS may have.*/
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+
+ /* Disable RC states. */
+ I915_WRITE(GEN6_RC_CONTROL, 0);
/* 2a: Program RC6 thresholds.*/
I915_WRITE(GEN6_RC6_WAKE_RATE_LIMIT, 40 << 16);
@@ -5299,7 +4762,8 @@ static void cherryview_enable_rps(struct drm_device *dev)
I915_WRITE(RING_MAX_IDLE(ring->mmio_base), 10);
I915_WRITE(GEN6_RC_SLEEP, 0);
- I915_WRITE(GEN6_RC6_THRESHOLD, 50000); /* 50/125ms per EI */
+ /* TO threshold set to 1750 us ( 0x557 * 1.28 us) */
+ I915_WRITE(GEN6_RC6_THRESHOLD, 0x557);
/* allows RC6 residency counter to work */
I915_WRITE(VLV_COUNTER_CONTROL,
@@ -5313,11 +4777,12 @@ static void cherryview_enable_rps(struct drm_device *dev)
/* 3: Enable RC6 */
if ((intel_enable_rc6(dev) & INTEL_RC6_ENABLE) &&
(pcbr >> VLV_PCBR_ADDR_SHIFT))
- rc6_mode = GEN6_RC_CTL_EI_MODE(1);
+ rc6_mode = GEN7_RC_CTL_TO_MODE;
I915_WRITE(GEN6_RC_CONTROL, rc6_mode);
/* 4 Program defaults and thresholds for RPS*/
+ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
I915_WRITE(GEN6_RP_UP_EI, 66000);
@@ -5325,14 +4790,10 @@ static void cherryview_enable_rps(struct drm_device *dev)
I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
- /* WaDisablePwrmtrEvent:chv (pre-production hw) */
- I915_WRITE(0xA80C, I915_READ(0xA80C) & 0x00ffffff);
- I915_WRITE(0xA810, I915_READ(0xA810) & 0xffffff00);
-
/* 5: Enable RPS */
I915_WRITE(GEN6_RP_CONTROL,
GEN6_RP_MEDIA_HW_NORMAL_MODE |
- GEN6_RP_MEDIA_IS_GFX | /* WaSetMaskForGfxBusyness:chv (pre-production hw ?) */
+ GEN6_RP_MEDIA_IS_GFX |
GEN6_RP_ENABLE |
GEN6_RP_UP_BUSY_AVG |
GEN6_RP_DOWN_IDLE_AVG);
@@ -5347,16 +4808,16 @@ static void cherryview_enable_rps(struct drm_device *dev)
dev_priv->rps.cur_freq = (val >> 8) & 0xff;
DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
dev_priv->rps.cur_freq);
DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
dev_priv->rps.efficient_freq);
valleyview_set_rps(dev_priv->dev, dev_priv->rps.efficient_freq);
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
static void valleyview_enable_rps(struct drm_device *dev)
@@ -5377,15 +4838,18 @@ static void valleyview_enable_rps(struct drm_device *dev)
}
/* If VLV, Forcewake all wells, else re-direct to regular path */
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
+ /* Disable RC states. */
+ I915_WRITE(GEN6_RC_CONTROL, 0);
+
+ I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 1000000);
I915_WRITE(GEN6_RP_UP_THRESHOLD, 59400);
I915_WRITE(GEN6_RP_DOWN_THRESHOLD, 245000);
I915_WRITE(GEN6_RP_UP_EI, 66000);
I915_WRITE(GEN6_RP_DOWN_EI, 350000);
I915_WRITE(GEN6_RP_IDLE_HYSTERSIS, 10);
- I915_WRITE(GEN6_RP_DOWN_TIMEOUT, 0xf4240);
I915_WRITE(GEN6_RP_CONTROL,
GEN6_RP_MEDIA_TURBO |
@@ -5428,16 +4892,16 @@ static void valleyview_enable_rps(struct drm_device *dev)
dev_priv->rps.cur_freq = (val >> 8) & 0xff;
DRM_DEBUG_DRIVER("current GPU freq: %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.cur_freq),
dev_priv->rps.cur_freq);
DRM_DEBUG_DRIVER("setting GPU freq to %d MHz (%u)\n",
- vlv_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
+ intel_gpu_freq(dev_priv, dev_priv->rps.efficient_freq),
dev_priv->rps.efficient_freq);
valleyview_set_rps(dev_priv->dev, dev_priv->rps.efficient_freq);
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
}
void ironlake_teardown_rc6(struct drm_device *dev)
@@ -5673,146 +5137,27 @@ unsigned long i915_mch_val(struct drm_i915_private *dev_priv)
return ((m * x) / 127) - b;
}
-static u16 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
+static int _pxvid_to_vd(u8 pxvid)
+{
+ if (pxvid == 0)
+ return 0;
+
+ if (pxvid >= 8 && pxvid < 31)
+ pxvid = 31;
+
+ return (pxvid + 2) * 125;
+}
+
+static u32 pvid_to_extvid(struct drm_i915_private *dev_priv, u8 pxvid)
{
struct drm_device *dev = dev_priv->dev;
- static const struct v_table {
- u16 vd; /* in .1 mil */
- u16 vm; /* in .1 mil */
- } v_table[] = {
- { 0, 0, },
- { 375, 0, },
- { 500, 0, },
- { 625, 0, },
- { 750, 0, },
- { 875, 0, },
- { 1000, 0, },
- { 1125, 0, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4125, 3000, },
- { 4250, 3125, },
- { 4375, 3250, },
- { 4500, 3375, },
- { 4625, 3500, },
- { 4750, 3625, },
- { 4875, 3750, },
- { 5000, 3875, },
- { 5125, 4000, },
- { 5250, 4125, },
- { 5375, 4250, },
- { 5500, 4375, },
- { 5625, 4500, },
- { 5750, 4625, },
- { 5875, 4750, },
- { 6000, 4875, },
- { 6125, 5000, },
- { 6250, 5125, },
- { 6375, 5250, },
- { 6500, 5375, },
- { 6625, 5500, },
- { 6750, 5625, },
- { 6875, 5750, },
- { 7000, 5875, },
- { 7125, 6000, },
- { 7250, 6125, },
- { 7375, 6250, },
- { 7500, 6375, },
- { 7625, 6500, },
- { 7750, 6625, },
- { 7875, 6750, },
- { 8000, 6875, },
- { 8125, 7000, },
- { 8250, 7125, },
- { 8375, 7250, },
- { 8500, 7375, },
- { 8625, 7500, },
- { 8750, 7625, },
- { 8875, 7750, },
- { 9000, 7875, },
- { 9125, 8000, },
- { 9250, 8125, },
- { 9375, 8250, },
- { 9500, 8375, },
- { 9625, 8500, },
- { 9750, 8625, },
- { 9875, 8750, },
- { 10000, 8875, },
- { 10125, 9000, },
- { 10250, 9125, },
- { 10375, 9250, },
- { 10500, 9375, },
- { 10625, 9500, },
- { 10750, 9625, },
- { 10875, 9750, },
- { 11000, 9875, },
- { 11125, 10000, },
- { 11250, 10125, },
- { 11375, 10250, },
- { 11500, 10375, },
- { 11625, 10500, },
- { 11750, 10625, },
- { 11875, 10750, },
- { 12000, 10875, },
- { 12125, 11000, },
- { 12250, 11125, },
- { 12375, 11250, },
- { 12500, 11375, },
- { 12625, 11500, },
- { 12750, 11625, },
- { 12875, 11750, },
- { 13000, 11875, },
- { 13125, 12000, },
- { 13250, 12125, },
- { 13375, 12250, },
- { 13500, 12375, },
- { 13625, 12500, },
- { 13750, 12625, },
- { 13875, 12750, },
- { 14000, 12875, },
- { 14125, 13000, },
- { 14250, 13125, },
- { 14375, 13250, },
- { 14500, 13375, },
- { 14625, 13500, },
- { 14750, 13625, },
- { 14875, 13750, },
- { 15000, 13875, },
- { 15125, 14000, },
- { 15250, 14125, },
- { 15375, 14250, },
- { 15500, 14375, },
- { 15625, 14500, },
- { 15750, 14625, },
- { 15875, 14750, },
- { 16000, 14875, },
- { 16125, 15000, },
- };
+ const int vd = _pxvid_to_vd(pxvid);
+ const int vm = vd - 1125;
+
if (INTEL_INFO(dev)->is_mobile)
- return v_table[pxvid].vm;
- else
- return v_table[pxvid].vd;
+ return vm > 0 ? vm : 0;
+
+ return vd;
}
static void __i915_update_gfx_val(struct drm_i915_private *dev_priv)
@@ -6264,7 +5609,9 @@ static void intel_gen6_powersave_work(struct work_struct *work)
} else if (IS_VALLEYVIEW(dev)) {
valleyview_enable_rps(dev);
} else if (INTEL_INFO(dev)->gen >= 9) {
+ gen9_enable_rc6(dev);
gen9_enable_rps(dev);
+ __gen6_update_ring_freq(dev);
} else if (IS_BROADWELL(dev)) {
gen8_enable_rps(dev);
__gen6_update_ring_freq(dev);
@@ -6710,6 +6057,10 @@ static void haswell_init_clock_gating(struct drm_device *dev)
I915_WRITE(GEN7_GT_MODE,
_MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4));
+ /* WaSampleCChickenBitEnable:hsw */
+ I915_WRITE(HALF_SLICE_CHICKEN3,
+ _MASKED_BIT_ENABLE(HSW_SAMPLE_C_PERFORMANCE));
+
/* WaSwitchSolVfFArbitrationPriority:hsw */
I915_WRITE(GAM_ECOCHK, I915_READ(GAM_ECOCHK) | HSW_ECOCHK_ARB_PRIO_SOL);
@@ -6880,6 +6231,17 @@ static void valleyview_init_clock_gating(struct drm_device *dev)
_MASKED_BIT_ENABLE(PIXEL_SUBSPAN_COLLECT_OPT_DISABLE));
/*
+ * BSpec recommends 8x4 when MSAA is used,
+ * however in practice 16x4 seems fastest.
+ *
+ * Note that PS/WM thread counts depend on the WIZ hashing
+ * disable bit, which we don't touch here, but it's good
+ * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+ */
+ I915_WRITE(GEN7_GT_MODE,
+ _MASKED_FIELD(GEN6_WIZ_HASHING_MASK, GEN6_WIZ_HASHING_16x4));
+
+ /*
* WaIncreaseL3CreditsForVLVB0:vlv
* This is the hardware default actually.
*/
@@ -7043,43 +6405,12 @@ void intel_suspend_hw(struct drm_device *dev)
lpt_suspend_hw(dev);
}
-static void intel_init_fbc(struct drm_i915_private *dev_priv)
-{
- if (!HAS_FBC(dev_priv)) {
- dev_priv->fbc.enabled = false;
- return;
- }
-
- if (INTEL_INFO(dev_priv)->gen >= 7) {
- dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
- dev_priv->display.enable_fbc = gen7_enable_fbc;
- dev_priv->display.disable_fbc = ironlake_disable_fbc;
- } else if (INTEL_INFO(dev_priv)->gen >= 5) {
- dev_priv->display.fbc_enabled = ironlake_fbc_enabled;
- dev_priv->display.enable_fbc = ironlake_enable_fbc;
- dev_priv->display.disable_fbc = ironlake_disable_fbc;
- } else if (IS_GM45(dev_priv)) {
- dev_priv->display.fbc_enabled = g4x_fbc_enabled;
- dev_priv->display.enable_fbc = g4x_enable_fbc;
- dev_priv->display.disable_fbc = g4x_disable_fbc;
- } else {
- dev_priv->display.fbc_enabled = i8xx_fbc_enabled;
- dev_priv->display.enable_fbc = i8xx_enable_fbc;
- dev_priv->display.disable_fbc = i8xx_disable_fbc;
-
- /* This value was pulled out of someone's hat */
- I915_WRITE(FBC_CONTROL, 500 << FBC_CTL_INTERVAL_SHIFT);
- }
-
- dev_priv->fbc.enabled = dev_priv->display.fbc_enabled(dev_priv->dev);
-}
-
/* Set up chip specific power management-related functions */
void intel_init_pm(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- intel_init_fbc(dev_priv);
+ intel_fbc_init(dev_priv);
/* For cxsr */
if (IS_PINEVIEW(dev))
@@ -7285,28 +6616,24 @@ static int chv_freq_opcode(struct drm_i915_private *dev_priv, int val)
return DIV_ROUND_CLOSEST(val * 2 * mul, czclk_freq) * 2;
}
-int vlv_gpu_freq(struct drm_i915_private *dev_priv, int val)
+int intel_gpu_freq(struct drm_i915_private *dev_priv, int val)
{
- int ret = -1;
-
if (IS_CHERRYVIEW(dev_priv->dev))
- ret = chv_gpu_freq(dev_priv, val);
+ return chv_gpu_freq(dev_priv, val);
else if (IS_VALLEYVIEW(dev_priv->dev))
- ret = byt_gpu_freq(dev_priv, val);
-
- return ret;
+ return byt_gpu_freq(dev_priv, val);
+ else
+ return val * GT_FREQUENCY_MULTIPLIER;
}
-int vlv_freq_opcode(struct drm_i915_private *dev_priv, int val)
+int intel_freq_opcode(struct drm_i915_private *dev_priv, int val)
{
- int ret = -1;
-
if (IS_CHERRYVIEW(dev_priv->dev))
- ret = chv_freq_opcode(dev_priv, val);
+ return chv_freq_opcode(dev_priv, val);
else if (IS_VALLEYVIEW(dev_priv->dev))
- ret = byt_freq_opcode(dev_priv, val);
-
- return ret;
+ return byt_freq_opcode(dev_priv, val);
+ else
+ return val / GT_FREQUENCY_MULTIPLIER;
}
void intel_pm_setup(struct drm_device *dev)
diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c
index 716b8a961eea..b9f40c2e0af7 100644
--- a/drivers/gpu/drm/i915/intel_psr.c
+++ b/drivers/gpu/drm/i915/intel_psr.c
@@ -61,14 +61,15 @@ static bool is_edp_psr(struct intel_dp *intel_dp)
return intel_dp->psr_dpcd[0] & DP_PSR_IS_SUPPORTED;
}
-bool intel_psr_is_enabled(struct drm_device *dev)
+static bool vlv_is_psr_active_on_pipe(struct drm_device *dev, int pipe)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ uint32_t val;
- if (!HAS_PSR(dev))
- return false;
-
- return I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE;
+ val = I915_READ(VLV_PSRSTAT(pipe)) &
+ VLV_EDP_PSR_CURR_STATE_MASK;
+ return (val == VLV_EDP_PSR_ACTIVE_NORFB_UP) ||
+ (val == VLV_EDP_PSR_ACTIVE_SF_UPDATE);
}
static void intel_psr_write_vsc(struct intel_dp *intel_dp,
@@ -78,8 +79,8 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp,
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(dig_port->base.base.crtc);
- u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config.cpu_transcoder);
- u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config.cpu_transcoder);
+ u32 ctl_reg = HSW_TVIDEO_DIP_CTL(crtc->config->cpu_transcoder);
+ u32 data_reg = HSW_TVIDEO_DIP_VSC_DATA(crtc->config->cpu_transcoder);
uint32_t *data = (uint32_t *) vsc_psr;
unsigned int i;
@@ -100,7 +101,23 @@ static void intel_psr_write_vsc(struct intel_dp *intel_dp,
POSTING_READ(ctl_reg);
}
-static void intel_psr_setup_vsc(struct intel_dp *intel_dp)
+static void vlv_psr_setup_vsc(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = intel_dig_port->base.base.crtc;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ uint32_t val;
+
+ /* VLV auto-generate VSC package as per EDP 1.3 spec, Table 3.10 */
+ val = I915_READ(VLV_VSCSDP(pipe));
+ val &= ~VLV_EDP_PSR_SDP_FREQ_MASK;
+ val |= VLV_EDP_PSR_SDP_FREQ_EVFRAME;
+ I915_WRITE(VLV_VSCSDP(pipe), val);
+}
+
+static void hsw_psr_setup_vsc(struct intel_dp *intel_dp)
{
struct edp_vsc_psr psr_vsc;
@@ -113,14 +130,20 @@ static void intel_psr_setup_vsc(struct intel_dp *intel_dp)
intel_psr_write_vsc(intel_dp, &psr_vsc);
}
-static void intel_psr_enable_sink(struct intel_dp *intel_dp)
+static void vlv_psr_enable_sink(struct intel_dp *intel_dp)
+{
+ drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
+ DP_PSR_ENABLE);
+}
+
+static void hsw_psr_enable_sink(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t aux_clock_divider;
+ uint32_t aux_data_reg, aux_ctl_reg;
int precharge = 0x3;
- bool only_standby = false;
static const uint8_t aux_msg[] = {
[0] = DP_AUX_NATIVE_WRITE << 4,
[1] = DP_SET_POWER >> 8,
@@ -134,49 +157,96 @@ static void intel_psr_enable_sink(struct intel_dp *intel_dp)
aux_clock_divider = intel_dp->get_aux_clock_divider(intel_dp, 0);
- if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
- only_standby = true;
-
/* Enable PSR in sink */
- if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby)
+ if (dev_priv->psr.link_standby)
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
- DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
+ DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
else
drm_dp_dpcd_writeb(&intel_dp->aux, DP_PSR_EN_CFG,
- DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE);
+ DP_PSR_ENABLE & ~DP_PSR_MAIN_LINK_ACTIVE);
+
+ aux_data_reg = (INTEL_INFO(dev)->gen >= 9) ?
+ DPA_AUX_CH_DATA1 : EDP_PSR_AUX_DATA1(dev);
+ aux_ctl_reg = (INTEL_INFO(dev)->gen >= 9) ?
+ DPA_AUX_CH_CTL : EDP_PSR_AUX_CTL(dev);
/* Setup AUX registers */
for (i = 0; i < sizeof(aux_msg); i += 4)
- I915_WRITE(EDP_PSR_AUX_DATA1(dev) + i,
+ I915_WRITE(aux_data_reg + i,
intel_dp_pack_aux(&aux_msg[i], sizeof(aux_msg) - i));
- I915_WRITE(EDP_PSR_AUX_CTL(dev),
+ if (INTEL_INFO(dev)->gen >= 9) {
+ uint32_t val;
+
+ val = I915_READ(aux_ctl_reg);
+ val &= ~DP_AUX_CH_CTL_TIME_OUT_MASK;
+ val |= DP_AUX_CH_CTL_TIME_OUT_1600us;
+ val &= ~DP_AUX_CH_CTL_MESSAGE_SIZE_MASK;
+ val |= (sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT);
+ /* Use hardcoded data values for PSR */
+ val &= ~DP_AUX_CH_CTL_PSR_DATA_AUX_REG_SKL;
+ I915_WRITE(aux_ctl_reg, val);
+ } else {
+ I915_WRITE(aux_ctl_reg,
DP_AUX_CH_CTL_TIME_OUT_400us |
(sizeof(aux_msg) << DP_AUX_CH_CTL_MESSAGE_SIZE_SHIFT) |
(precharge << DP_AUX_CH_CTL_PRECHARGE_2US_SHIFT) |
(aux_clock_divider << DP_AUX_CH_CTL_BIT_CLOCK_2X_SHIFT));
+ }
}
-static void intel_psr_enable_source(struct intel_dp *intel_dp)
+static void vlv_psr_enable_source(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dig_port->base.base.crtc;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+
+ /* Transition from PSR_state 0 to PSR_state 1, i.e. PSR Inactive */
+ I915_WRITE(VLV_PSRCTL(pipe),
+ VLV_EDP_PSR_MODE_SW_TIMER |
+ VLV_EDP_PSR_SRC_TRANSMITTER_STATE |
+ VLV_EDP_PSR_ENABLE);
+}
+
+static void vlv_psr_activate(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+ struct drm_crtc *crtc = dig_port->base.base.crtc;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+
+ /* Let's do the transition from PSR_state 1 to PSR_state 2
+ * that is PSR transition to active - static frame transmission.
+ * Then Hardware is responsible for the transition to PSR_state 3
+ * that is PSR active - no Remote Frame Buffer (RFB) update.
+ */
+ I915_WRITE(VLV_PSRCTL(pipe), I915_READ(VLV_PSRCTL(pipe)) |
+ VLV_EDP_PSR_ACTIVE_ENTRY);
+}
+
+static void hsw_psr_enable_source(struct intel_dp *intel_dp)
{
struct intel_digital_port *dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
uint32_t max_sleep_time = 0x1f;
- uint32_t idle_frames = 1;
+ /* Lately it was identified that depending on panel idle frame count
+ * calculated at HW can be off by 1. So let's use what came
+ * from VBT + 1 and at minimum 2 to be on the safe side.
+ */
+ uint32_t idle_frames = dev_priv->vbt.psr.idle_frames ?
+ dev_priv->vbt.psr.idle_frames + 1 : 2;
uint32_t val = 0x0;
const uint32_t link_entry_time = EDP_PSR_MIN_LINK_ENTRY_TIME_8_LINES;
- bool only_standby = false;
-
- if (IS_BROADWELL(dev) && dig_port->port != PORT_A)
- only_standby = true;
- if (intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT || only_standby) {
+ if (dev_priv->psr.link_standby) {
val |= EDP_PSR_LINK_STANDBY;
val |= EDP_PSR_TP2_TP3_TIME_0us;
val |= EDP_PSR_TP1_TIME_0us;
val |= EDP_PSR_SKIP_AUX_EXIT;
- val |= IS_BROADWELL(dev) ? BDW_PSR_SINGLE_FRAME : 0;
} else
val |= EDP_PSR_LINK_DISABLE;
@@ -211,27 +281,24 @@ static bool intel_psr_match_conditions(struct intel_dp *intel_dp)
return false;
}
- /* Below limitations aren't valid for Broadwell */
- if (IS_BROADWELL(dev))
- goto out;
-
- if (I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config.cpu_transcoder)) &
- S3D_ENABLE) {
+ if (IS_HASWELL(dev) &&
+ I915_READ(HSW_STEREO_3D_CTL(intel_crtc->config->cpu_transcoder)) &
+ S3D_ENABLE) {
DRM_DEBUG_KMS("PSR condition failed: Stereo 3D is Enabled\n");
return false;
}
- if (intel_crtc->config.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
+ if (IS_HASWELL(dev) &&
+ intel_crtc->config->base.adjusted_mode.flags & DRM_MODE_FLAG_INTERLACE) {
DRM_DEBUG_KMS("PSR condition failed: Interlaced is Enabled\n");
return false;
}
- out:
dev_priv->psr.source_ok = true;
return true;
}
-static void intel_psr_do_enable(struct intel_dp *intel_dp)
+static void intel_psr_activate(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
@@ -242,7 +309,14 @@ static void intel_psr_do_enable(struct intel_dp *intel_dp)
lockdep_assert_held(&dev_priv->psr.lock);
/* Enable/Re-enable PSR on the host */
- intel_psr_enable_source(intel_dp);
+ if (HAS_DDI(dev))
+ /* On HSW+ after we enable PSR on source it will activate it
+ * as soon as it match configure idle_frame count. So
+ * we just actually enable it here on activation time.
+ */
+ hsw_psr_enable_source(intel_dp);
+ else
+ vlv_psr_activate(intel_dp);
dev_priv->psr.active = true;
}
@@ -278,39 +352,79 @@ void intel_psr_enable(struct intel_dp *intel_dp)
if (!intel_psr_match_conditions(intel_dp))
goto unlock;
+ /* First we check VBT, but we must respect sink and source
+ * known restrictions */
+ dev_priv->psr.link_standby = dev_priv->vbt.psr.full_link;
+ if ((intel_dp->psr_dpcd[1] & DP_PSR_NO_TRAIN_ON_EXIT) ||
+ (IS_BROADWELL(dev) && intel_dig_port->port != PORT_A))
+ dev_priv->psr.link_standby = true;
+
dev_priv->psr.busy_frontbuffer_bits = 0;
- intel_psr_setup_vsc(intel_dp);
+ if (HAS_DDI(dev)) {
+ hsw_psr_setup_vsc(intel_dp);
+
+ /* Avoid continuous PSR exit by masking memup and hpd */
+ I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
+ EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
- /* Avoid continuous PSR exit by masking memup and hpd */
- I915_WRITE(EDP_PSR_DEBUG_CTL(dev), EDP_PSR_DEBUG_MASK_MEMUP |
- EDP_PSR_DEBUG_MASK_HPD | EDP_PSR_DEBUG_MASK_LPSP);
+ /* Enable PSR on the panel */
+ hsw_psr_enable_sink(intel_dp);
- /* Enable PSR on the panel */
- intel_psr_enable_sink(intel_dp);
+ if (INTEL_INFO(dev)->gen >= 9)
+ intel_psr_activate(intel_dp);
+ } else {
+ vlv_psr_setup_vsc(intel_dp);
+
+ /* Enable PSR on the panel */
+ vlv_psr_enable_sink(intel_dp);
+
+ /* On HSW+ enable_source also means go to PSR entry/active
+ * state as soon as idle_frame achieved and here would be
+ * to soon. However on VLV enable_source just enable PSR
+ * but let it on inactive state. So we might do this prior
+ * to active transition, i.e. here.
+ */
+ vlv_psr_enable_source(intel_dp);
+ }
dev_priv->psr.enabled = intel_dp;
unlock:
mutex_unlock(&dev_priv->psr.lock);
}
-/**
- * intel_psr_disable - Disable PSR
- * @intel_dp: Intel DP
- *
- * This function needs to be called before disabling pipe.
- */
-void intel_psr_disable(struct intel_dp *intel_dp)
+static void vlv_psr_disable(struct intel_dp *intel_dp)
{
struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
struct drm_device *dev = intel_dig_port->base.base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_crtc *intel_crtc =
+ to_intel_crtc(intel_dig_port->base.base.crtc);
+ uint32_t val;
- mutex_lock(&dev_priv->psr.lock);
- if (!dev_priv->psr.enabled) {
- mutex_unlock(&dev_priv->psr.lock);
- return;
+ if (dev_priv->psr.active) {
+ /* Put VLV PSR back to PSR_state 0 that is PSR Disabled. */
+ if (wait_for((I915_READ(VLV_PSRSTAT(intel_crtc->pipe)) &
+ VLV_EDP_PSR_IN_TRANS) == 0, 1))
+ WARN(1, "PSR transition took longer than expected\n");
+
+ val = I915_READ(VLV_PSRCTL(intel_crtc->pipe));
+ val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+ val &= ~VLV_EDP_PSR_ENABLE;
+ val &= ~VLV_EDP_PSR_MODE_MASK;
+ I915_WRITE(VLV_PSRCTL(intel_crtc->pipe), val);
+
+ dev_priv->psr.active = false;
+ } else {
+ WARN_ON(vlv_is_psr_active_on_pipe(dev, intel_crtc->pipe));
}
+}
+
+static void hsw_psr_disable(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
if (dev_priv->psr.active) {
I915_WRITE(EDP_PSR_CTL(dev),
@@ -325,6 +439,30 @@ void intel_psr_disable(struct intel_dp *intel_dp)
} else {
WARN_ON(I915_READ(EDP_PSR_CTL(dev)) & EDP_PSR_ENABLE);
}
+}
+
+/**
+ * intel_psr_disable - Disable PSR
+ * @intel_dp: Intel DP
+ *
+ * This function needs to be called before disabling pipe.
+ */
+void intel_psr_disable(struct intel_dp *intel_dp)
+{
+ struct intel_digital_port *intel_dig_port = dp_to_dig_port(intel_dp);
+ struct drm_device *dev = intel_dig_port->base.base.dev;
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ mutex_lock(&dev_priv->psr.lock);
+ if (!dev_priv->psr.enabled) {
+ mutex_unlock(&dev_priv->psr.lock);
+ return;
+ }
+
+ if (HAS_DDI(dev))
+ hsw_psr_disable(intel_dp);
+ else
+ vlv_psr_disable(intel_dp);
dev_priv->psr.enabled = NULL;
mutex_unlock(&dev_priv->psr.lock);
@@ -337,18 +475,27 @@ static void intel_psr_work(struct work_struct *work)
struct drm_i915_private *dev_priv =
container_of(work, typeof(*dev_priv), psr.work.work);
struct intel_dp *intel_dp = dev_priv->psr.enabled;
+ struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
/* We have to make sure PSR is ready for re-enable
* otherwise it keeps disabled until next full enable/disable cycle.
* PSR might take some time to get fully disabled
* and be ready for re-enable.
*/
- if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
- EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
- DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
- return;
+ if (HAS_DDI(dev_priv->dev)) {
+ if (wait_for((I915_READ(EDP_PSR_STATUS_CTL(dev_priv->dev)) &
+ EDP_PSR_STATUS_STATE_MASK) == 0, 50)) {
+ DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
+ return;
+ }
+ } else {
+ if (wait_for((I915_READ(VLV_PSRSTAT(pipe)) &
+ VLV_EDP_PSR_IN_TRANS) == 0, 1)) {
+ DRM_ERROR("Timed out waiting for PSR Idle for re-enable\n");
+ return;
+ }
}
-
mutex_lock(&dev_priv->psr.lock);
intel_dp = dev_priv->psr.enabled;
@@ -363,7 +510,7 @@ static void intel_psr_work(struct work_struct *work)
if (dev_priv->psr.busy_frontbuffer_bits)
goto unlock;
- intel_psr_do_enable(intel_dp);
+ intel_psr_activate(intel_dp);
unlock:
mutex_unlock(&dev_priv->psr.lock);
}
@@ -371,17 +518,47 @@ unlock:
static void intel_psr_exit(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_dp *intel_dp = dev_priv->psr.enabled;
+ struct drm_crtc *crtc = dp_to_dig_port(intel_dp)->base.base.crtc;
+ enum pipe pipe = to_intel_crtc(crtc)->pipe;
+ u32 val;
- if (dev_priv->psr.active) {
- u32 val = I915_READ(EDP_PSR_CTL(dev));
+ if (!dev_priv->psr.active)
+ return;
+
+ if (HAS_DDI(dev)) {
+ val = I915_READ(EDP_PSR_CTL(dev));
WARN_ON(!(val & EDP_PSR_ENABLE));
I915_WRITE(EDP_PSR_CTL(dev), val & ~EDP_PSR_ENABLE);
dev_priv->psr.active = false;
+ } else {
+ val = I915_READ(VLV_PSRCTL(pipe));
+
+ /* Here we do the transition from PSR_state 3 to PSR_state 5
+ * directly once PSR State 4 that is active with single frame
+ * update can be skipped. PSR_state 5 that is PSR exit then
+ * Hardware is responsible to transition back to PSR_state 1
+ * that is PSR inactive. Same state after
+ * vlv_edp_psr_enable_source.
+ */
+ val &= ~VLV_EDP_PSR_ACTIVE_ENTRY;
+ I915_WRITE(VLV_PSRCTL(pipe), val);
+
+ /* Send AUX wake up - Spec says after transitioning to PSR
+ * active we have to send AUX wake up by writing 01h in DPCD
+ * 600h of sink device.
+ * XXX: This might slow down the transition, but without this
+ * HW doesn't complete the transition to PSR_state 1 and we
+ * never get the screen updated.
+ */
+ drm_dp_dpcd_writeb(&intel_dp->aux, DP_SET_POWER,
+ DP_SET_POWER_D0);
}
+ dev_priv->psr.active = false;
}
/**
@@ -459,6 +636,15 @@ void intel_psr_flush(struct drm_device *dev,
(frontbuffer_bits & INTEL_FRONTBUFFER_SPRITE(pipe)))
intel_psr_exit(dev);
+ /*
+ * On Valleyview and Cherryview we don't use hardware tracking so
+ * any plane updates or cursor moves don't result in a PSR
+ * invalidating. Which means we need to manually fake this in
+ * software for all flushes, not just when we've seen a preceding
+ * invalidation through frontbuffer rendering. */
+ if (!HAS_DDI(dev))
+ intel_psr_exit(dev);
+
if (!dev_priv->psr.active && !dev_priv->psr.busy_frontbuffer_bits)
schedule_delayed_work(&dev_priv->psr.work,
msecs_to_jiffies(100));
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen6.c b/drivers/gpu/drm/i915/intel_renderstate_gen6.c
index 56c1429d8a60..11c8e7b3dd7c 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen6.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen6.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
#include "intel_renderstate.h"
static const u32 gen6_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen7.c b/drivers/gpu/drm/i915/intel_renderstate_gen7.c
index 419e35a7b0ff..655180646152 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen7.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen7.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
#include "intel_renderstate.h"
static const u32 gen7_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen8.c b/drivers/gpu/drm/i915/intel_renderstate_gen8.c
index 78011d73fa9f..95288a34c15d 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen8.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen8.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
#include "intel_renderstate.h"
static const u32 gen8_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_renderstate_gen9.c b/drivers/gpu/drm/i915/intel_renderstate_gen9.c
index 875075373807..16a7ec273bd9 100644
--- a/drivers/gpu/drm/i915/intel_renderstate_gen9.c
+++ b/drivers/gpu/drm/i915/intel_renderstate_gen9.c
@@ -1,3 +1,28 @@
+/*
+ * Copyright © 2014 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Generated by: intel-gpu-tools-1.8-220-g01153e7
+ */
+
#include "intel_renderstate.h"
static const u32 gen9_null_state_relocs[] = {
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.c b/drivers/gpu/drm/i915/intel_ringbuffer.c
index c7bc93d28d84..e5b3c6dbd467 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.c
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.c
@@ -52,16 +52,27 @@ intel_ring_initialized(struct intel_engine_cs *ring)
int __intel_ring_space(int head, int tail, int size)
{
- int space = head - (tail + I915_RING_FREE_SPACE);
- if (space < 0)
+ int space = head - tail;
+ if (space <= 0)
space += size;
- return space;
+ return space - I915_RING_FREE_SPACE;
+}
+
+void intel_ring_update_space(struct intel_ringbuffer *ringbuf)
+{
+ if (ringbuf->last_retired_head != -1) {
+ ringbuf->head = ringbuf->last_retired_head;
+ ringbuf->last_retired_head = -1;
+ }
+
+ ringbuf->space = __intel_ring_space(ringbuf->head & HEAD_ADDR,
+ ringbuf->tail, ringbuf->size);
}
int intel_ring_space(struct intel_ringbuffer *ringbuf)
{
- return __intel_ring_space(ringbuf->head & HEAD_ADDR,
- ringbuf->tail, ringbuf->size);
+ intel_ring_update_space(ringbuf);
+ return ringbuf->space;
}
bool intel_ring_stopped(struct intel_engine_cs *ring)
@@ -528,7 +539,7 @@ static int init_ring_common(struct intel_engine_cs *ring)
struct drm_i915_gem_object *obj = ringbuf->obj;
int ret = 0;
- gen6_gt_force_wake_get(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL);
if (!stop_ring(ring)) {
/* G45 ring initialization often fails to reset head to zero */
@@ -592,15 +603,15 @@ static int init_ring_common(struct intel_engine_cs *ring)
goto out;
}
+ ringbuf->last_retired_head = -1;
ringbuf->head = I915_READ_HEAD(ring);
ringbuf->tail = I915_READ_TAIL(ring) & TAIL_ADDR;
- ringbuf->space = intel_ring_space(ringbuf);
- ringbuf->last_retired_head = -1;
+ intel_ring_update_space(ringbuf);
memset(&ring->hangcheck, 0, sizeof(ring->hangcheck));
out:
- gen6_gt_force_wake_put(dev_priv, FORCEWAKE_ALL);
+ intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL);
return ret;
}
@@ -627,8 +638,7 @@ intel_init_pipe_control(struct intel_engine_cs *ring)
{
int ret;
- if (ring->scratch.obj)
- return 0;
+ WARN_ON(ring->scratch.obj);
ring->scratch.obj = i915_gem_alloc_object(ring->dev, 4096);
if (ring->scratch.obj == NULL) {
@@ -672,7 +682,7 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring,
struct drm_i915_private *dev_priv = dev->dev_private;
struct i915_workarounds *w = &dev_priv->workarounds;
- if (WARN_ON(w->count == 0))
+ if (WARN_ON_ONCE(w->count == 0))
return 0;
ring->gpu_caches_dirty = true;
@@ -703,6 +713,22 @@ static int intel_ring_workarounds_emit(struct intel_engine_cs *ring,
return 0;
}
+static int intel_rcs_ctx_init(struct intel_engine_cs *ring,
+ struct intel_context *ctx)
+{
+ int ret;
+
+ ret = intel_ring_workarounds_emit(ring, ctx);
+ if (ret != 0)
+ return ret;
+
+ ret = i915_gem_render_state_init(ring);
+ if (ret)
+ DRM_ERROR("init render state: %d\n", ret);
+
+ return ret;
+}
+
static int wa_add(struct drm_i915_private *dev_priv,
const u32 addr, const u32 mask, const u32 val)
{
@@ -762,11 +788,24 @@ static int bdw_init_workarounds(struct intel_engine_cs *ring)
* workaround for for a possible hang in the unlikely event a TLB
* invalidation occurs during a PSD flush.
*/
+ /* WaForceEnableNonCoherent:bdw */
+ /* WaHdcDisableFetchWhenMasked:bdw */
/* WaDisableFenceDestinationToSLM:bdw (GT3 pre-production) */
WA_SET_BIT_MASKED(HDC_CHICKEN0,
HDC_FORCE_NON_COHERENT |
+ HDC_DONOT_FETCH_MEM_WHEN_MASKED |
(IS_BDW_GT3(dev) ? HDC_FENCE_DEST_SLM_DISABLE : 0));
+ /* From the Haswell PRM, Command Reference: Registers, CACHE_MODE_0:
+ * "The Hierarchical Z RAW Stall Optimization allows non-overlapping
+ * polygons in the same 8x4 pixel/sample area to be processed without
+ * stalling waiting for the earlier ones to write to Hierarchical Z
+ * buffer."
+ *
+ * This optimization is off by default for Broadwell; turn it on.
+ */
+ WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
+
/* Wa4x4STCOptimizationDisable:bdw */
WA_SET_BIT_MASKED(CACHE_MODE_1,
GEN8_4x4_STC_OPTIMIZATION_DISABLE);
@@ -807,6 +846,30 @@ static int chv_init_workarounds(struct intel_engine_cs *ring)
HDC_FORCE_NON_COHERENT |
HDC_DONOT_FETCH_MEM_WHEN_MASKED);
+ /* According to the CACHE_MODE_0 default value documentation, some
+ * CHV platforms disable this optimization by default. Turn it on.
+ */
+ WA_CLR_BIT_MASKED(CACHE_MODE_0_GEN7, HIZ_RAW_STALL_OPT_DISABLE);
+
+ /* Wa4x4STCOptimizationDisable:chv */
+ WA_SET_BIT_MASKED(CACHE_MODE_1,
+ GEN8_4x4_STC_OPTIMIZATION_DISABLE);
+
+ /* Improve HiZ throughput on CHV. */
+ WA_SET_BIT_MASKED(HIZ_CHICKEN, CHV_HZ_8X8_MODE_IN_1X);
+
+ /*
+ * BSpec recommends 8x4 when MSAA is used,
+ * however in practice 16x4 seems fastest.
+ *
+ * Note that PS/WM thread counts depend on the WIZ hashing
+ * disable bit, which we don't touch here, but it's good
+ * to keep in mind (see 3DSTATE_PS and 3DSTATE_WM).
+ */
+ WA_SET_FIELD_MASKED(GEN7_GT_MODE,
+ GEN6_WIZ_HASHING_MASK,
+ GEN6_WIZ_HASHING_16x4);
+
return 0;
}
@@ -861,12 +924,6 @@ static int init_render_ring(struct intel_engine_cs *ring)
_MASKED_BIT_ENABLE(GFX_TLB_INVALIDATE_EXPLICIT) |
_MASKED_BIT_ENABLE(GFX_REPLAY_MODE));
- if (INTEL_INFO(dev)->gen >= 5) {
- ret = intel_init_pipe_control(ring);
- if (ret)
- return ret;
- }
-
if (IS_GEN6(dev)) {
/* From the Sandybridge PRM, volume 1 part 3, page 24:
* "If this bit is set, STCunit will have LRA as replacement
@@ -918,17 +975,20 @@ static int gen8_rcs_signal(struct intel_engine_cs *signaller,
return ret;
for_each_ring(waiter, dev_priv, i) {
+ u32 seqno;
u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
continue;
+ seqno = i915_gem_request_get_seqno(
+ signaller->outstanding_lazy_request);
intel_ring_emit(signaller, GFX_OP_PIPE_CONTROL(6));
intel_ring_emit(signaller, PIPE_CONTROL_GLOBAL_GTT_IVB |
PIPE_CONTROL_QW_WRITE |
PIPE_CONTROL_FLUSH_ENABLE);
intel_ring_emit(signaller, lower_32_bits(gtt_offset));
intel_ring_emit(signaller, upper_32_bits(gtt_offset));
- intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+ intel_ring_emit(signaller, seqno);
intel_ring_emit(signaller, 0);
intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
MI_SEMAPHORE_TARGET(waiter->id));
@@ -956,16 +1016,19 @@ static int gen8_xcs_signal(struct intel_engine_cs *signaller,
return ret;
for_each_ring(waiter, dev_priv, i) {
+ u32 seqno;
u64 gtt_offset = signaller->semaphore.signal_ggtt[i];
if (gtt_offset == MI_SEMAPHORE_SYNC_INVALID)
continue;
+ seqno = i915_gem_request_get_seqno(
+ signaller->outstanding_lazy_request);
intel_ring_emit(signaller, (MI_FLUSH_DW + 1) |
MI_FLUSH_DW_OP_STOREDW);
intel_ring_emit(signaller, lower_32_bits(gtt_offset) |
MI_FLUSH_DW_USE_GTT);
intel_ring_emit(signaller, upper_32_bits(gtt_offset));
- intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+ intel_ring_emit(signaller, seqno);
intel_ring_emit(signaller, MI_SEMAPHORE_SIGNAL |
MI_SEMAPHORE_TARGET(waiter->id));
intel_ring_emit(signaller, 0);
@@ -994,9 +1057,11 @@ static int gen6_signal(struct intel_engine_cs *signaller,
for_each_ring(useless, dev_priv, i) {
u32 mbox_reg = signaller->semaphore.mbox.signal[i];
if (mbox_reg != GEN6_NOSYNC) {
+ u32 seqno = i915_gem_request_get_seqno(
+ signaller->outstanding_lazy_request);
intel_ring_emit(signaller, MI_LOAD_REGISTER_IMM(1));
intel_ring_emit(signaller, mbox_reg);
- intel_ring_emit(signaller, signaller->outstanding_lazy_seqno);
+ intel_ring_emit(signaller, seqno);
}
}
@@ -1031,7 +1096,8 @@ gen6_add_request(struct intel_engine_cs *ring)
intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+ intel_ring_emit(ring,
+ i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, MI_USER_INTERRUPT);
__intel_ring_advance(ring);
@@ -1149,7 +1215,8 @@ pc_render_add_request(struct intel_engine_cs *ring)
PIPE_CONTROL_WRITE_FLUSH |
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE);
intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
- intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+ intel_ring_emit(ring,
+ i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, 0);
PIPE_CONTROL_FLUSH(ring, scratch_addr);
scratch_addr += 2 * CACHELINE_BYTES; /* write to separate cachelines */
@@ -1168,7 +1235,8 @@ pc_render_add_request(struct intel_engine_cs *ring)
PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE |
PIPE_CONTROL_NOTIFY);
intel_ring_emit(ring, ring->scratch.gtt_offset | PIPE_CONTROL_GLOBAL_GTT);
- intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+ intel_ring_emit(ring,
+ i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, 0);
__intel_ring_advance(ring);
@@ -1408,7 +1476,8 @@ i9xx_add_request(struct intel_engine_cs *ring)
intel_ring_emit(ring, MI_STORE_DWORD_INDEX);
intel_ring_emit(ring, I915_GEM_HWS_INDEX << MI_STORE_DWORD_INDEX_SHIFT);
- intel_ring_emit(ring, ring->outstanding_lazy_seqno);
+ intel_ring_emit(ring,
+ i915_gem_request_get_seqno(ring->outstanding_lazy_request));
intel_ring_emit(ring, MI_USER_INTERRUPT);
__intel_ring_advance(ring);
@@ -1789,15 +1858,15 @@ int intel_alloc_ringbuffer_obj(struct drm_device *dev,
static int intel_init_ring_buffer(struct drm_device *dev,
struct intel_engine_cs *ring)
{
- struct intel_ringbuffer *ringbuf = ring->buffer;
+ struct intel_ringbuffer *ringbuf;
int ret;
- if (ringbuf == NULL) {
- ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
- if (!ringbuf)
- return -ENOMEM;
- ring->buffer = ringbuf;
- }
+ WARN_ON(ring->buffer);
+
+ ringbuf = kzalloc(sizeof(*ringbuf), GFP_KERNEL);
+ if (!ringbuf)
+ return -ENOMEM;
+ ring->buffer = ringbuf;
ring->dev = dev;
INIT_LIST_HEAD(&ring->active_list);
@@ -1820,21 +1889,21 @@ static int intel_init_ring_buffer(struct drm_device *dev,
goto error;
}
- if (ringbuf->obj == NULL) {
- ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
- if (ret) {
- DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
- ring->name, ret);
- goto error;
- }
+ WARN_ON(ringbuf->obj);
- ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
- if (ret) {
- DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
- ring->name, ret);
- intel_destroy_ringbuffer_obj(ringbuf);
- goto error;
- }
+ ret = intel_alloc_ringbuffer_obj(dev, ringbuf);
+ if (ret) {
+ DRM_ERROR("Failed to allocate ringbuffer %s: %d\n",
+ ring->name, ret);
+ goto error;
+ }
+
+ ret = intel_pin_and_map_ringbuffer_obj(dev, ringbuf);
+ if (ret) {
+ DRM_ERROR("Failed to pin and map ringbuffer %s: %d\n",
+ ring->name, ret);
+ intel_destroy_ringbuffer_obj(ringbuf);
+ goto error;
}
/* Workaround an erratum on the i830 which causes a hang if
@@ -1849,10 +1918,6 @@ static int intel_init_ring_buffer(struct drm_device *dev,
if (ret)
goto error;
- ret = ring->init(ring);
- if (ret)
- goto error;
-
return 0;
error:
@@ -1877,8 +1942,7 @@ void intel_cleanup_ring_buffer(struct intel_engine_cs *ring)
intel_unpin_ringbuffer_obj(ringbuf);
intel_destroy_ringbuffer_obj(ringbuf);
- ring->preallocated_lazy_request = NULL;
- ring->outstanding_lazy_seqno = 0;
+ i915_gem_request_assign(&ring->outstanding_lazy_request, NULL);
if (ring->cleanup)
ring->cleanup(ring);
@@ -1895,38 +1959,27 @@ static int intel_ring_wait_request(struct intel_engine_cs *ring, int n)
{
struct intel_ringbuffer *ringbuf = ring->buffer;
struct drm_i915_gem_request *request;
- u32 seqno = 0;
int ret;
- if (ringbuf->last_retired_head != -1) {
- ringbuf->head = ringbuf->last_retired_head;
- ringbuf->last_retired_head = -1;
-
- ringbuf->space = intel_ring_space(ringbuf);
- if (ringbuf->space >= n)
- return 0;
- }
+ if (intel_ring_space(ringbuf) >= n)
+ return 0;
list_for_each_entry(request, &ring->request_list, list) {
- if (__intel_ring_space(request->tail, ringbuf->tail,
+ if (__intel_ring_space(request->postfix, ringbuf->tail,
ringbuf->size) >= n) {
- seqno = request->seqno;
break;
}
}
- if (seqno == 0)
+ if (&request->list == &ring->request_list)
return -ENOSPC;
- ret = i915_wait_seqno(ring, seqno);
+ ret = i915_wait_request(request);
if (ret)
return ret;
i915_gem_retire_requests_ring(ring);
- ringbuf->head = ringbuf->last_retired_head;
- ringbuf->last_retired_head = -1;
- ringbuf->space = intel_ring_space(ringbuf);
return 0;
}
@@ -1952,14 +2005,14 @@ static int ring_wait_for_space(struct intel_engine_cs *ring, int n)
* case by choosing an insanely large timeout. */
end = jiffies + 60 * HZ;
+ ret = 0;
trace_i915_ring_wait_begin(ring);
do {
+ if (intel_ring_space(ringbuf) >= n)
+ break;
ringbuf->head = I915_READ_HEAD(ring);
- ringbuf->space = intel_ring_space(ringbuf);
- if (ringbuf->space >= n) {
- ret = 0;
+ if (intel_ring_space(ringbuf) >= n)
break;
- }
msleep(1);
@@ -2000,19 +2053,19 @@ static int intel_wrap_ring_buffer(struct intel_engine_cs *ring)
iowrite32(MI_NOOP, virt++);
ringbuf->tail = 0;
- ringbuf->space = intel_ring_space(ringbuf);
+ intel_ring_update_space(ringbuf);
return 0;
}
int intel_ring_idle(struct intel_engine_cs *ring)
{
- u32 seqno;
+ struct drm_i915_gem_request *req;
int ret;
/* We need to add any requests required to flush the objects and ring */
- if (ring->outstanding_lazy_seqno) {
- ret = i915_add_request(ring, NULL);
+ if (ring->outstanding_lazy_request) {
+ ret = i915_add_request(ring);
if (ret)
return ret;
}
@@ -2021,30 +2074,39 @@ int intel_ring_idle(struct intel_engine_cs *ring)
if (list_empty(&ring->request_list))
return 0;
- seqno = list_entry(ring->request_list.prev,
+ req = list_entry(ring->request_list.prev,
struct drm_i915_gem_request,
- list)->seqno;
+ list);
- return i915_wait_seqno(ring, seqno);
+ return i915_wait_request(req);
}
static int
-intel_ring_alloc_seqno(struct intel_engine_cs *ring)
+intel_ring_alloc_request(struct intel_engine_cs *ring)
{
- if (ring->outstanding_lazy_seqno)
+ int ret;
+ struct drm_i915_gem_request *request;
+ struct drm_i915_private *dev_private = ring->dev->dev_private;
+
+ if (ring->outstanding_lazy_request)
return 0;
- if (ring->preallocated_lazy_request == NULL) {
- struct drm_i915_gem_request *request;
+ request = kzalloc(sizeof(*request), GFP_KERNEL);
+ if (request == NULL)
+ return -ENOMEM;
- request = kmalloc(sizeof(*request), GFP_KERNEL);
- if (request == NULL)
- return -ENOMEM;
+ kref_init(&request->ref);
+ request->ring = ring;
+ request->uniq = dev_private->request_uniq++;
- ring->preallocated_lazy_request = request;
+ ret = i915_gem_get_seqno(ring->dev, &request->seqno);
+ if (ret) {
+ kfree(request);
+ return ret;
}
- return i915_gem_get_seqno(ring->dev, &ring->outstanding_lazy_seqno);
+ ring->outstanding_lazy_request = request;
+ return 0;
}
static int __intel_ring_prepare(struct intel_engine_cs *ring,
@@ -2084,7 +2146,7 @@ int intel_ring_begin(struct intel_engine_cs *ring,
return ret;
/* Preallocate the olr before touching the ring */
- ret = intel_ring_alloc_seqno(ring);
+ ret = intel_ring_alloc_request(ring);
if (ret)
return ret;
@@ -2119,7 +2181,7 @@ void intel_ring_init_seqno(struct intel_engine_cs *ring, u32 seqno)
struct drm_device *dev = ring->dev;
struct drm_i915_private *dev_priv = dev->dev_private;
- BUG_ON(ring->outstanding_lazy_seqno);
+ BUG_ON(ring->outstanding_lazy_request);
if (INTEL_INFO(dev)->gen == 6 || INTEL_INFO(dev)->gen == 7) {
I915_WRITE(RING_SYNC_0(ring->mmio_base), 0);
@@ -2178,6 +2240,14 @@ static int gen6_bsd_ring_flush(struct intel_engine_cs *ring,
cmd = MI_FLUSH_DW;
if (INTEL_INFO(ring->dev)->gen >= 8)
cmd += 1;
+
+ /* We always require a command barrier so that subsequent
+ * commands, such as breadcrumb interrupts, are strictly ordered
+ * wrt the contents of the write cache being flushed to memory
+ * (and thus being coherent from the CPU).
+ */
+ cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+
/*
* Bspec vol 1c.5 - video engine command streamer:
* "If ENABLED, all TLBs will be invalidated once the flush
@@ -2185,8 +2255,8 @@ static int gen6_bsd_ring_flush(struct intel_engine_cs *ring,
* Post-Sync Operation field is a value of 1h or 3h."
*/
if (invalidate & I915_GEM_GPU_DOMAINS)
- cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD |
- MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+ cmd |= MI_INVALIDATE_TLB | MI_INVALIDATE_BSD;
+
intel_ring_emit(ring, cmd);
intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
if (INTEL_INFO(ring->dev)->gen >= 8) {
@@ -2282,6 +2352,14 @@ static int gen6_ring_flush(struct intel_engine_cs *ring,
cmd = MI_FLUSH_DW;
if (INTEL_INFO(ring->dev)->gen >= 8)
cmd += 1;
+
+ /* We always require a command barrier so that subsequent
+ * commands, such as breadcrumb interrupts, are strictly ordered
+ * wrt the contents of the write cache being flushed to memory
+ * (and thus being coherent from the CPU).
+ */
+ cmd |= MI_FLUSH_DW_STORE_INDEX | MI_FLUSH_DW_OP_STOREDW;
+
/*
* Bspec vol 1c.3 - blitter engine command streamer:
* "If ENABLED, all TLBs will be invalidated once the flush
@@ -2289,8 +2367,7 @@ static int gen6_ring_flush(struct intel_engine_cs *ring,
* Post-Sync Operation field is a value of 1h or 3h."
*/
if (invalidate & I915_GEM_DOMAIN_RENDER)
- cmd |= MI_INVALIDATE_TLB | MI_FLUSH_DW_STORE_INDEX |
- MI_FLUSH_DW_OP_STOREDW;
+ cmd |= MI_INVALIDATE_TLB;
intel_ring_emit(ring, cmd);
intel_ring_emit(ring, I915_GEM_HWS_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT);
if (INTEL_INFO(ring->dev)->gen >= 8) {
@@ -2341,7 +2418,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
}
}
- ring->init_context = intel_ring_workarounds_emit;
+ ring->init_context = intel_rcs_ctx_init;
ring->add_request = gen6_add_request;
ring->flush = gen8_render_ring_flush;
ring->irq_get = gen8_ring_get_irq;
@@ -2426,7 +2503,7 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->dispatch_execbuffer = i830_dispatch_execbuffer;
else
ring->dispatch_execbuffer = i915_dispatch_execbuffer;
- ring->init = init_render_ring;
+ ring->init_hw = init_render_ring;
ring->cleanup = render_ring_cleanup;
/* Workaround batchbuffer to combat CS tlb bug. */
@@ -2448,7 +2525,17 @@ int intel_init_render_ring_buffer(struct drm_device *dev)
ring->scratch.gtt_offset = i915_gem_obj_ggtt_offset(obj);
}
- return intel_init_ring_buffer(dev, ring);
+ ret = intel_init_ring_buffer(dev, ring);
+ if (ret)
+ return ret;
+
+ if (INTEL_INFO(dev)->gen >= 5) {
+ ret = intel_init_pipe_control(ring);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
}
int intel_init_bsd_ring_buffer(struct drm_device *dev)
@@ -2519,7 +2606,7 @@ int intel_init_bsd_ring_buffer(struct drm_device *dev)
}
ring->dispatch_execbuffer = i965_dispatch_execbuffer;
}
- ring->init = init_ring_common;
+ ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring);
}
@@ -2558,7 +2645,7 @@ int intel_init_bsd2_ring_buffer(struct drm_device *dev)
ring->semaphore.signal = gen8_xcs_signal;
GEN8_RING_SEMAPHORE_INIT;
}
- ring->init = init_ring_common;
+ ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring);
}
@@ -2615,7 +2702,7 @@ int intel_init_blt_ring_buffer(struct drm_device *dev)
ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
}
}
- ring->init = init_ring_common;
+ ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring);
}
@@ -2666,7 +2753,7 @@ int intel_init_vebox_ring_buffer(struct drm_device *dev)
ring->semaphore.mbox.signal[VCS2] = GEN6_NOSYNC;
}
}
- ring->init = init_ring_common;
+ ring->init_hw = init_ring_common;
return intel_init_ring_buffer(dev, ring);
}
diff --git a/drivers/gpu/drm/i915/intel_ringbuffer.h b/drivers/gpu/drm/i915/intel_ringbuffer.h
index fe426cff598b..714f3fdd57d2 100644
--- a/drivers/gpu/drm/i915/intel_ringbuffer.h
+++ b/drivers/gpu/drm/i915/intel_ringbuffer.h
@@ -99,13 +99,6 @@ struct intel_ringbuffer {
struct intel_engine_cs *ring;
- /*
- * FIXME: This backpointer is an artifact of the history of how the
- * execlist patches came into being. It will get removed once the basic
- * code has landed.
- */
- struct intel_context *FIXME_lrc_ctx;
-
u32 head;
u32 tail;
int space;
@@ -123,6 +116,8 @@ struct intel_ringbuffer {
u32 last_retired_head;
};
+struct intel_context;
+
struct intel_engine_cs {
const char *name;
enum intel_ring_id {
@@ -142,11 +137,11 @@ struct intel_engine_cs {
unsigned irq_refcount; /* protected by dev_priv->irq_lock */
u32 irq_enable_mask; /* bitmask to enable ring interrupt */
- u32 trace_irq_seqno;
+ struct drm_i915_gem_request *trace_irq_req;
bool __must_check (*irq_get)(struct intel_engine_cs *ring);
void (*irq_put)(struct intel_engine_cs *ring);
- int (*init)(struct intel_engine_cs *ring);
+ int (*init_hw)(struct intel_engine_cs *ring);
int (*init_context)(struct intel_engine_cs *ring,
struct intel_context *ctx);
@@ -239,11 +234,14 @@ struct intel_engine_cs {
struct list_head execlist_retired_req_list;
u8 next_context_status_buffer;
u32 irq_keep_mask; /* bitmask for interrupts that should not be masked */
- int (*emit_request)(struct intel_ringbuffer *ringbuf);
+ int (*emit_request)(struct intel_ringbuffer *ringbuf,
+ struct drm_i915_gem_request *request);
int (*emit_flush)(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
u32 invalidate_domains,
u32 flush_domains);
int (*emit_bb_start)(struct intel_ringbuffer *ringbuf,
+ struct intel_context *ctx,
u64 offset, unsigned flags);
/**
@@ -251,7 +249,7 @@ struct intel_engine_cs {
* ringbuffer.
*
* Includes buffers having the contents of their GPU caches
- * flushed, not necessarily primitives. last_rendering_seqno
+ * flushed, not necessarily primitives. last_read_req
* represents when the rendering involved will be completed.
*
* A reference is held on the buffer while on this list.
@@ -267,8 +265,7 @@ struct intel_engine_cs {
/**
* Do we have some not yet emitted requests outstanding?
*/
- struct drm_i915_gem_request *preallocated_lazy_request;
- u32 outstanding_lazy_seqno;
+ struct drm_i915_gem_request *outstanding_lazy_request;
bool gpu_caches_dirty;
bool fbc_dirty;
@@ -408,6 +405,7 @@ static inline void intel_ring_advance(struct intel_engine_cs *ring)
ringbuf->tail &= ringbuf->size - 1;
}
int __intel_ring_space(int head, int tail, int size);
+void intel_ring_update_space(struct intel_ringbuffer *ringbuf);
int intel_ring_space(struct intel_ringbuffer *ringbuf);
bool intel_ring_stopped(struct intel_engine_cs *ring);
void __intel_ring_advance(struct intel_engine_cs *ring);
@@ -436,16 +434,11 @@ static inline u32 intel_ring_get_tail(struct intel_ringbuffer *ringbuf)
return ringbuf->tail;
}
-static inline u32 intel_ring_get_seqno(struct intel_engine_cs *ring)
-{
- BUG_ON(ring->outstanding_lazy_seqno == 0);
- return ring->outstanding_lazy_seqno;
-}
-
-static inline void i915_trace_irq_get(struct intel_engine_cs *ring, u32 seqno)
+static inline struct drm_i915_gem_request *
+intel_ring_get_request(struct intel_engine_cs *ring)
{
- if (ring->trace_irq_seqno == 0 && ring->irq_get(ring))
- ring->trace_irq_seqno = seqno;
+ BUG_ON(ring->outstanding_lazy_request == NULL);
+ return ring->outstanding_lazy_request;
}
#endif /* _INTEL_RINGBUFFER_H_ */
diff --git a/drivers/gpu/drm/i915/intel_runtime_pm.c b/drivers/gpu/drm/i915/intel_runtime_pm.c
index ac6da7102fbb..49695d7d51e3 100644
--- a/drivers/gpu/drm/i915/intel_runtime_pm.c
+++ b/drivers/gpu/drm/i915/intel_runtime_pm.c
@@ -31,7 +31,6 @@
#include "i915_drv.h"
#include "intel_drv.h"
-#include <drm/i915_powerwell.h>
/**
* DOC: runtime pm
@@ -50,8 +49,6 @@
* present for a given platform.
*/
-static struct i915_power_domains *hsw_pwr;
-
#define for_each_power_well(i, power_well, domain_mask, power_domains) \
for (i = 0; \
i < (power_domains)->power_well_count && \
@@ -118,7 +115,7 @@ bool __intel_display_power_is_enabled(struct drm_i915_private *dev_priv,
}
/**
- * intel_display_power_is_enabled - unlocked check for a power domain
+ * intel_display_power_is_enabled - check for a power domain
* @dev_priv: i915 device instance
* @domain: power domain to check
*
@@ -706,6 +703,10 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
BIT(POWER_DOMAIN_PORT_CRT) | \
BIT(POWER_DOMAIN_PLLS) | \
+ BIT(POWER_DOMAIN_AUX_A) | \
+ BIT(POWER_DOMAIN_AUX_B) | \
+ BIT(POWER_DOMAIN_AUX_C) | \
+ BIT(POWER_DOMAIN_AUX_D) | \
BIT(POWER_DOMAIN_INIT))
#define HSW_DISPLAY_POWER_DOMAINS ( \
(POWER_DOMAIN_MASK & ~HSW_ALWAYS_ON_POWER_DOMAINS) | \
@@ -727,24 +728,30 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
BIT(POWER_DOMAIN_PORT_CRT) | \
+ BIT(POWER_DOMAIN_AUX_B) | \
+ BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_B_LANES_01_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_B_2_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_B_LANES_23_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_B) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_C_LANES_01_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define VLV_DPIO_TX_C_LANES_23_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define CHV_PIPE_A_POWER_DOMAINS ( \
@@ -764,20 +771,25 @@ void intel_display_power_put(struct drm_i915_private *dev_priv,
BIT(POWER_DOMAIN_PORT_DDI_B_4_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_C_2_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_C_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_B) | \
+ BIT(POWER_DOMAIN_AUX_C) | \
BIT(POWER_DOMAIN_INIT))
#define CHV_DPIO_CMN_D_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_D) | \
BIT(POWER_DOMAIN_INIT))
#define CHV_DPIO_TX_D_LANES_01_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_D_2_LANES) | \
BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_D) | \
BIT(POWER_DOMAIN_INIT))
#define CHV_DPIO_TX_D_LANES_23_POWER_DOMAINS ( \
BIT(POWER_DOMAIN_PORT_DDI_D_4_LANES) | \
+ BIT(POWER_DOMAIN_AUX_D) | \
BIT(POWER_DOMAIN_INIT))
static const struct i915_power_well_ops i9xx_always_on_power_well_ops = {
@@ -1071,10 +1083,8 @@ int intel_power_domains_init(struct drm_i915_private *dev_priv)
*/
if (IS_HASWELL(dev_priv->dev)) {
set_power_wells(power_domains, hsw_power_wells);
- hsw_pwr = power_domains;
} else if (IS_BROADWELL(dev_priv->dev)) {
set_power_wells(power_domains, bdw_power_wells);
- hsw_pwr = power_domains;
} else if (IS_CHERRYVIEW(dev_priv->dev)) {
set_power_wells(power_domains, chv_power_wells);
} else if (IS_VALLEYVIEW(dev_priv->dev)) {
@@ -1118,8 +1128,6 @@ void intel_power_domains_fini(struct drm_i915_private *dev_priv)
* the power well is not enabled, so just enable it in case
* we're going to unload/reload. */
intel_display_set_init_power(dev_priv, true);
-
- hsw_pwr = NULL;
}
static void intel_power_domains_resume(struct drm_i915_private *dev_priv)
@@ -1328,52 +1336,3 @@ void intel_runtime_pm_enable(struct drm_i915_private *dev_priv)
pm_runtime_put_autosuspend(device);
}
-/* Display audio driver power well request */
-int i915_request_power_well(void)
-{
- struct drm_i915_private *dev_priv;
-
- if (!hsw_pwr)
- return -ENODEV;
-
- dev_priv = container_of(hsw_pwr, struct drm_i915_private,
- power_domains);
- intel_display_power_get(dev_priv, POWER_DOMAIN_AUDIO);
- return 0;
-}
-EXPORT_SYMBOL_GPL(i915_request_power_well);
-
-/* Display audio driver power well release */
-int i915_release_power_well(void)
-{
- struct drm_i915_private *dev_priv;
-
- if (!hsw_pwr)
- return -ENODEV;
-
- dev_priv = container_of(hsw_pwr, struct drm_i915_private,
- power_domains);
- intel_display_power_put(dev_priv, POWER_DOMAIN_AUDIO);
- return 0;
-}
-EXPORT_SYMBOL_GPL(i915_release_power_well);
-
-/*
- * Private interface for the audio driver to get CDCLK in kHz.
- *
- * Caller must request power well using i915_request_power_well() prior to
- * making the call.
- */
-int i915_get_cdclk_freq(void)
-{
- struct drm_i915_private *dev_priv;
-
- if (!hsw_pwr)
- return -ENODEV;
-
- dev_priv = container_of(hsw_pwr, struct drm_i915_private,
- power_domains);
-
- return intel_ddi_get_cdclk_freq(dev_priv);
-}
-EXPORT_SYMBOL_GPL(i915_get_cdclk_freq);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 6d7a277458b5..64ad2b40179f 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -30,6 +30,7 @@
#include <linux/delay.h>
#include <linux/export.h>
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include "intel_drv.h"
@@ -1007,7 +1008,7 @@ static bool intel_sdvo_set_avi_infoframe(struct intel_sdvo *intel_sdvo,
}
if (intel_sdvo->rgb_quant_range_selectable) {
- if (intel_crtc->config.limited_color_range)
+ if (intel_crtc->config->limited_color_range)
frame.avi.quantization_range =
HDMI_QUANTIZATION_RANGE_LIMITED;
else
@@ -1085,7 +1086,7 @@ intel_sdvo_get_preferred_input_mode(struct intel_sdvo *intel_sdvo,
return true;
}
-static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config)
+static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_state *pipe_config)
{
unsigned dotclock = pipe_config->port_clock;
struct dpll *clock = &pipe_config->dpll;
@@ -1112,11 +1113,11 @@ static void i9xx_adjust_sdvo_tv_clock(struct intel_crtc_config *pipe_config)
}
static bool intel_sdvo_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
- struct drm_display_mode *adjusted_mode = &pipe_config->adjusted_mode;
- struct drm_display_mode *mode = &pipe_config->requested_mode;
+ struct drm_display_mode *adjusted_mode = &pipe_config->base.adjusted_mode;
+ struct drm_display_mode *mode = &pipe_config->base.mode;
DRM_DEBUG_KMS("forcing bpc to 8 for SDVO\n");
pipe_config->pipe_bpp = 8*3;
@@ -1181,8 +1182,8 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
struct drm_i915_private *dev_priv = dev->dev_private;
struct intel_crtc *crtc = to_intel_crtc(intel_encoder->base.crtc);
struct drm_display_mode *adjusted_mode =
- &crtc->config.adjusted_mode;
- struct drm_display_mode *mode = &crtc->config.requested_mode;
+ &crtc->config->base.adjusted_mode;
+ struct drm_display_mode *mode = &crtc->config->base.mode;
struct intel_sdvo *intel_sdvo = to_sdvo(intel_encoder);
u32 sdvox;
struct intel_sdvo_in_out_map in_out;
@@ -1224,7 +1225,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
if (!intel_sdvo_set_target_input(intel_sdvo))
return;
- if (crtc->config.has_hdmi_sink) {
+ if (crtc->config->has_hdmi_sink) {
intel_sdvo_set_encode(intel_sdvo, SDVO_ENCODE_HDMI);
intel_sdvo_set_colorimetry(intel_sdvo,
SDVO_COLORIMETRY_RGB256);
@@ -1244,7 +1245,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
DRM_INFO("Setting input timings on %s failed\n",
SDVO_NAME(intel_sdvo));
- switch (crtc->config.pixel_multiplier) {
+ switch (crtc->config->pixel_multiplier) {
default:
WARN(1, "unknown pixel mutlipler specified\n");
case 1: rate = SDVO_CLOCK_RATE_MULT_1X; break;
@@ -1259,7 +1260,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
/* The real mode polarity is set by the SDVO commands, using
* struct intel_sdvo_dtd. */
sdvox = SDVO_VSYNC_ACTIVE_HIGH | SDVO_HSYNC_ACTIVE_HIGH;
- if (!HAS_PCH_SPLIT(dev) && crtc->config.limited_color_range)
+ if (!HAS_PCH_SPLIT(dev) && crtc->config->limited_color_range)
sdvox |= HDMI_COLOR_RANGE_16_235;
if (INTEL_INFO(dev)->gen < 5)
sdvox |= SDVO_BORDER_ENABLE;
@@ -1289,7 +1290,7 @@ static void intel_sdvo_pre_enable(struct intel_encoder *intel_encoder)
} else if (IS_I945G(dev) || IS_I945GM(dev) || IS_G33(dev)) {
/* done in crtc_mode_set as it lives inside the dpll register */
} else {
- sdvox |= (crtc->config.pixel_multiplier - 1)
+ sdvox |= (crtc->config->pixel_multiplier - 1)
<< SDVO_PORT_MULTIPLY_SHIFT;
}
@@ -1338,7 +1339,7 @@ static bool intel_sdvo_get_hw_state(struct intel_encoder *encoder,
}
static void intel_sdvo_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct drm_device *dev = encoder->base.dev;
struct drm_i915_private *dev_priv = dev->dev_private;
@@ -1370,7 +1371,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
flags |= DRM_MODE_FLAG_NVSYNC;
}
- pipe_config->adjusted_mode.flags |= flags;
+ pipe_config->base.adjusted_mode.flags |= flags;
/*
* pixel multiplier readout is tricky: Only on i915g/gm it is stored in
@@ -1392,7 +1393,7 @@ static void intel_sdvo_get_config(struct intel_encoder *encoder,
if (HAS_PCH_SPLIT(dev))
ironlake_check_encoder_dotclock(pipe_config, dotclock);
- pipe_config->adjusted_mode.crtc_clock = dotclock;
+ pipe_config->base.adjusted_mode.crtc_clock = dotclock;
/* Cross check the port pixel multiplier with the sdvo encoder state. */
if (intel_sdvo_get_value(intel_sdvo, SDVO_CMD_GET_CLOCK_RATE_MULT,
@@ -1617,6 +1618,9 @@ static uint16_t intel_sdvo_get_hotplug_support(struct intel_sdvo *intel_sdvo)
struct drm_device *dev = intel_sdvo->base.base.dev;
uint16_t hotplug;
+ if (!I915_HAS_HOTPLUG(dev))
+ return 0;
+
/* HW Erratum: SDVO Hotplug is broken on all i945G chips, there's noise
* on the line. */
if (IS_I945G(dev) || IS_I945GM(dev))
@@ -2187,7 +2191,9 @@ static const struct drm_connector_funcs intel_sdvo_connector_funcs = {
.detect = intel_sdvo_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.set_property = intel_sdvo_set_property,
+ .atomic_get_property = intel_connector_atomic_get_property,
.destroy = intel_sdvo_destroy,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs intel_sdvo_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_sideband.c b/drivers/gpu/drm/i915/intel_sideband.c
index 01d841ea3140..693ce8281970 100644
--- a/drivers/gpu/drm/i915/intel_sideband.c
+++ b/drivers/gpu/drm/i915/intel_sideband.c
@@ -75,26 +75,26 @@ static int vlv_sideband_rw(struct drm_i915_private *dev_priv, u32 devfn,
return 0;
}
-u32 vlv_punit_read(struct drm_i915_private *dev_priv, u8 addr)
+u32 vlv_punit_read(struct drm_i915_private *dev_priv, u32 addr)
{
u32 val = 0;
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
mutex_lock(&dev_priv->dpio_lock);
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
SB_CRRDDA_NP, addr, &val);
mutex_unlock(&dev_priv->dpio_lock);
return val;
}
-void vlv_punit_write(struct drm_i915_private *dev_priv, u8 addr, u32 val)
+void vlv_punit_write(struct drm_i915_private *dev_priv, u32 addr, u32 val)
{
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
mutex_lock(&dev_priv->dpio_lock);
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_PUNIT,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_PUNIT,
SB_CRWRDA_NP, addr, &val);
mutex_unlock(&dev_priv->dpio_lock);
}
@@ -103,7 +103,7 @@ u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val = 0;
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
SB_CRRDDA_NP, reg, &val);
return val;
@@ -111,7 +111,7 @@ u32 vlv_bunit_read(struct drm_i915_private *dev_priv, u32 reg)
void vlv_bunit_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
{
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_BUNIT,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_BUNIT,
SB_CRWRDA_NP, reg, &val);
}
@@ -122,7 +122,7 @@ u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr)
WARN_ON(!mutex_is_locked(&dev_priv->rps.hw_lock));
mutex_lock(&dev_priv->dpio_lock);
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_NC,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_NC,
SB_CRRDDA_NP, addr, &val);
mutex_unlock(&dev_priv->dpio_lock);
@@ -132,56 +132,56 @@ u32 vlv_nc_read(struct drm_i915_private *dev_priv, u8 addr)
u32 vlv_gpio_nc_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val = 0;
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPIO_NC,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPIO_NC,
SB_CRRDDA_NP, reg, &val);
return val;
}
void vlv_gpio_nc_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
{
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPIO_NC,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPIO_NC,
SB_CRWRDA_NP, reg, &val);
}
u32 vlv_cck_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val = 0;
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCK,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
SB_CRRDDA_NP, reg, &val);
return val;
}
void vlv_cck_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
{
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCK,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCK,
SB_CRWRDA_NP, reg, &val);
}
u32 vlv_ccu_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val = 0;
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCU,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
SB_CRRDDA_NP, reg, &val);
return val;
}
void vlv_ccu_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
{
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_CCU,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_CCU,
SB_CRWRDA_NP, reg, &val);
}
u32 vlv_gps_core_read(struct drm_i915_private *dev_priv, u32 reg)
{
u32 val = 0;
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPS_CORE,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPS_CORE,
SB_CRRDDA_NP, reg, &val);
return val;
}
void vlv_gps_core_write(struct drm_i915_private *dev_priv, u32 reg, u32 val)
{
- vlv_sideband_rw(dev_priv, PCI_DEVFN(2, 0), IOSF_PORT_GPS_CORE,
+ vlv_sideband_rw(dev_priv, PCI_DEVFN(0, 0), IOSF_PORT_GPS_CORE,
SB_CRWRDA_NP, reg, &val);
}
diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index 7d9c340f7693..0a52c44ad03d 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -33,6 +33,7 @@
#include <drm/drm_crtc.h>
#include <drm/drm_fourcc.h>
#include <drm/drm_rect.h>
+#include <drm/drm_plane_helper.h>
#include "intel_drv.h"
#include <drm/i915_drm.h>
#include "i915_drv.h"
@@ -79,7 +80,7 @@ static int usecs_to_scanlines(const struct drm_display_mode *mode, int usecs)
bool intel_pipe_update_start(struct intel_crtc *crtc, uint32_t *start_vbl_count)
{
struct drm_device *dev = crtc->base.dev;
- const struct drm_display_mode *mode = &crtc->config.adjusted_mode;
+ const struct drm_display_mode *mode = &crtc->config->base.adjusted_mode;
enum pipe pipe = crtc->pipe;
long timeout = msecs_to_jiffies_timeout(1);
int scanline, min, max, vblank_start;
@@ -255,7 +256,7 @@ skl_update_plane(struct drm_plane *drm_plane, struct drm_crtc *crtc,
default:
BUG();
}
- if (intel_plane->rotation == BIT(DRM_ROTATE_180))
+ if (drm_plane->state->rotation == BIT(DRM_ROTATE_180))
plane_ctl |= PLANE_CTL_ROTATE_180;
plane_ctl |= PLANE_CTL_ENABLE;
@@ -412,8 +413,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
u32 sprctl;
unsigned long sprsurf_offset, linear_offset;
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
- u32 start_vbl_count;
- bool atomic_update;
sprctl = I915_READ(SPCNTR(pipe, plane));
@@ -494,7 +493,7 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
fb->pitches[0]);
linear_offset -= sprsurf_offset;
- if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+ if (dplane->state->rotation == BIT(DRM_ROTATE_180)) {
sprctl |= SP_ROTATE_180;
x += src_w;
@@ -502,8 +501,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
}
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
intel_update_primary_plane(intel_crtc);
if (IS_CHERRYVIEW(dev) && pipe == PIPE_B)
@@ -525,9 +522,6 @@ vlv_update_plane(struct drm_plane *dplane, struct drm_crtc *crtc,
sprsurf_offset);
intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
}
static void
@@ -539,10 +533,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_plane->pipe;
int plane = intel_plane->plane;
- u32 start_vbl_count;
- bool atomic_update;
-
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
intel_update_primary_plane(intel_crtc);
@@ -553,9 +543,6 @@ vlv_disable_plane(struct drm_plane *dplane, struct drm_crtc *crtc)
intel_flush_primary_plane(dev_priv, intel_crtc->plane);
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
-
intel_update_sprite_watermarks(dplane, crtc, 0, 0, 0, false, false);
}
@@ -626,8 +613,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
u32 sprctl, sprscale = 0;
unsigned long sprsurf_offset, linear_offset;
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
- u32 start_vbl_count;
- bool atomic_update;
sprctl = I915_READ(SPRCTL(pipe));
@@ -699,7 +684,7 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
pixel_size, fb->pitches[0]);
linear_offset -= sprsurf_offset;
- if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+ if (plane->state->rotation == BIT(DRM_ROTATE_180)) {
sprctl |= SPRITE_ROTATE_180;
/* HSW and BDW does this automagically in hardware */
@@ -711,8 +696,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
}
}
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
intel_update_primary_plane(intel_crtc);
I915_WRITE(SPRSTRIDE(pipe), fb->pitches[0]);
@@ -735,9 +718,6 @@ ivb_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
i915_gem_obj_ggtt_offset(obj) + sprsurf_offset);
intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
}
static void
@@ -748,10 +728,6 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_plane->pipe;
- u32 start_vbl_count;
- bool atomic_update;
-
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
intel_update_primary_plane(intel_crtc);
@@ -764,16 +740,12 @@ ivb_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
intel_flush_primary_plane(dev_priv, intel_crtc->plane);
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
-
/*
* Avoid underruns when disabling the sprite.
* FIXME remove once watermark updates are done properly.
*/
- intel_wait_for_vblank(dev, pipe);
-
- intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false);
+ intel_crtc->atomic.wait_vblank = true;
+ intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
}
static int
@@ -846,8 +818,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
unsigned long dvssurf_offset, linear_offset;
u32 dvscntr, dvsscale;
int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
- u32 start_vbl_count;
- bool atomic_update;
dvscntr = I915_READ(DVSCNTR(pipe));
@@ -914,7 +884,7 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
pixel_size, fb->pitches[0]);
linear_offset -= dvssurf_offset;
- if (intel_plane->rotation == BIT(DRM_ROTATE_180)) {
+ if (plane->state->rotation == BIT(DRM_ROTATE_180)) {
dvscntr |= DVS_ROTATE_180;
x += src_w;
@@ -922,8 +892,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
linear_offset += src_h * fb->pitches[0] + src_w * pixel_size;
}
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
-
intel_update_primary_plane(intel_crtc);
I915_WRITE(DVSSTRIDE(pipe), fb->pitches[0]);
@@ -941,9 +909,6 @@ ilk_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
i915_gem_obj_ggtt_offset(obj) + dvssurf_offset);
intel_flush_primary_plane(dev_priv, intel_crtc->plane);
-
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
}
static void
@@ -954,10 +919,6 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
struct intel_plane *intel_plane = to_intel_plane(plane);
struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
int pipe = intel_plane->pipe;
- u32 start_vbl_count;
- bool atomic_update;
-
- atomic_update = intel_pipe_update_start(intel_crtc, &start_vbl_count);
intel_update_primary_plane(intel_crtc);
@@ -969,19 +930,25 @@ ilk_disable_plane(struct drm_plane *plane, struct drm_crtc *crtc)
intel_flush_primary_plane(dev_priv, intel_crtc->plane);
- if (atomic_update)
- intel_pipe_update_end(intel_crtc, start_vbl_count);
-
/*
* Avoid underruns when disabling the sprite.
* FIXME remove once watermark updates are done properly.
*/
- intel_wait_for_vblank(dev, pipe);
-
- intel_update_sprite_watermarks(plane, crtc, 0, 0, 0, false, false);
+ intel_crtc->atomic.wait_vblank = true;
+ intel_crtc->atomic.update_sprite_watermarks |= (1 << drm_plane_index(plane));
}
-static void
+/**
+ * intel_post_enable_primary - Perform operations after enabling primary plane
+ * @crtc: the CRTC whose primary plane was just enabled
+ *
+ * Performs potentially sleeping operations that must be done after the primary
+ * plane is enabled, such as updating FBC and IPS. Note that this may be
+ * called due to an explicit primary plane update, or due to an implicit
+ * re-enable that is caused when a sprite plane is updated to no longer
+ * completely hide the primary plane.
+ */
+void
intel_post_enable_primary(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -1004,11 +971,21 @@ intel_post_enable_primary(struct drm_crtc *crtc)
hsw_enable_ips(intel_crtc);
mutex_lock(&dev->struct_mutex);
- intel_update_fbc(dev);
+ intel_fbc_update(dev);
mutex_unlock(&dev->struct_mutex);
}
-static void
+/**
+ * intel_pre_disable_primary - Perform operations before disabling primary plane
+ * @crtc: the CRTC whose primary plane is to be disabled
+ *
+ * Performs potentially sleeping operations that must be done before the
+ * primary plane is enabled, such as updating FBC and IPS. Note that this may
+ * be called due to an explicit primary plane update, or due to an implicit
+ * disable that is caused when a sprite plane completely hides the primary
+ * plane.
+ */
+void
intel_pre_disable_primary(struct drm_crtc *crtc)
{
struct drm_device *dev = crtc->dev;
@@ -1017,7 +994,7 @@ intel_pre_disable_primary(struct drm_crtc *crtc)
mutex_lock(&dev->struct_mutex);
if (dev_priv->fbc.plane == intel_crtc->plane)
- intel_disable_fbc(dev);
+ intel_fbc_disable(dev);
mutex_unlock(&dev->struct_mutex);
/*
@@ -1096,20 +1073,26 @@ static int
intel_check_sprite_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct intel_crtc *intel_crtc = to_intel_crtc(state->crtc);
+ struct intel_crtc *intel_crtc = to_intel_crtc(state->base.crtc);
struct intel_plane *intel_plane = to_intel_plane(plane);
- struct drm_framebuffer *fb = state->fb;
+ struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h;
uint32_t src_x, src_y, src_w, src_h;
struct drm_rect *src = &state->src;
struct drm_rect *dst = &state->dst;
- struct drm_rect *orig_src = &state->orig_src;
const struct drm_rect *clip = &state->clip;
int hscale, vscale;
int max_scale, min_scale;
- int pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
+ int pixel_size;
+
+ intel_crtc = intel_crtc ? intel_crtc : to_intel_crtc(plane->crtc);
+
+ if (!fb) {
+ state->visible = false;
+ goto finish;
+ }
/* Don't modify another pipe's plane */
if (intel_plane->pipe != intel_crtc->pipe) {
@@ -1142,7 +1125,7 @@ intel_check_sprite_plane(struct drm_plane *plane,
min_scale = intel_plane->can_scale ? 1 : (1 << 16);
drm_rect_rotate(src, fb->width << 16, fb->height << 16,
- intel_plane->rotation);
+ state->base.rotation);
hscale = drm_rect_calc_hscale_relaxed(src, dst, min_scale, max_scale);
BUG_ON(hscale < 0);
@@ -1183,13 +1166,13 @@ intel_check_sprite_plane(struct drm_plane *plane,
drm_rect_height(dst) * vscale - drm_rect_height(src));
drm_rect_rotate_inv(src, fb->width << 16, fb->height << 16,
- intel_plane->rotation);
+ state->base.rotation);
/* sanity check to make sure the src viewport wasn't enlarged */
- WARN_ON(src->x1 < (int) orig_src->x1 ||
- src->y1 < (int) orig_src->y1 ||
- src->x2 > (int) orig_src->x2 ||
- src->y2 > (int) orig_src->y2);
+ WARN_ON(src->x1 < (int) state->base.src_x ||
+ src->y1 < (int) state->base.src_y ||
+ src->x2 > (int) state->base.src_x + state->base.src_w ||
+ src->y2 > (int) state->base.src_y + state->base.src_h);
/*
* Hardware doesn't handle subpixel coordinates.
@@ -1232,6 +1215,7 @@ intel_check_sprite_plane(struct drm_plane *plane,
if (src_w < 3 || src_h < 3)
state->visible = false;
+ pixel_size = drm_format_plane_cpp(fb->pixel_format, 0);
width_bytes = ((src_x * pixel_size) & 63) +
src_w * pixel_size;
@@ -1254,39 +1238,27 @@ intel_check_sprite_plane(struct drm_plane *plane,
dst->y1 = crtc_y;
dst->y2 = crtc_y + crtc_h;
- return 0;
-}
+finish:
+ /*
+ * If the sprite is completely covering the primary plane,
+ * we can disable the primary and save power.
+ */
+ state->hides_primary = fb != NULL && drm_rect_equals(dst, clip) &&
+ !colorkey_enabled(intel_plane);
+ WARN_ON(state->hides_primary && !state->visible && intel_crtc->active);
-static int
-intel_prepare_sprite_plane(struct drm_plane *plane,
- struct intel_plane_state *state)
-{
- struct drm_device *dev = plane->dev;
- struct drm_crtc *crtc = state->crtc;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- struct intel_plane *intel_plane = to_intel_plane(plane);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_framebuffer *fb = state->fb;
- struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct drm_i915_gem_object *old_obj = intel_plane->obj;
- int ret;
+ if (intel_crtc->active) {
+ if (intel_crtc->primary_enabled == state->hides_primary)
+ intel_crtc->atomic.wait_for_flips = true;
- if (old_obj != obj) {
- mutex_lock(&dev->struct_mutex);
+ if (intel_crtc->primary_enabled && state->hides_primary)
+ intel_crtc->atomic.pre_disable_primary = true;
- /* Note that this will apply the VT-d workaround for scanouts,
- * which is more restrictive than required for sprites. (The
- * primary plane requires 256KiB alignment with 64 PTE padding,
- * the sprite planes only require 128KiB alignment and 32 PTE
- * padding.
- */
- ret = intel_pin_and_fence_fb_obj(plane, fb, NULL);
- if (ret == 0)
- i915_gem_track_fb(old_obj, obj,
- INTEL_FRONTBUFFER_SPRITE(pipe));
- mutex_unlock(&dev->struct_mutex);
- if (ret)
- return ret;
+ intel_crtc->atomic.fb_bits |=
+ INTEL_FRONTBUFFER_SPRITE(intel_crtc->pipe);
+
+ if (!intel_crtc->primary_enabled && !state->hides_primary)
+ intel_crtc->atomic.post_enable_primary = true;
}
return 0;
@@ -1296,48 +1268,23 @@ static void
intel_commit_sprite_plane(struct drm_plane *plane,
struct intel_plane_state *state)
{
- struct drm_device *dev = plane->dev;
- struct drm_crtc *crtc = state->crtc;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
+ struct drm_crtc *crtc = state->base.crtc;
+ struct intel_crtc *intel_crtc;
struct intel_plane *intel_plane = to_intel_plane(plane);
- enum pipe pipe = intel_crtc->pipe;
- struct drm_framebuffer *fb = state->fb;
+ struct drm_framebuffer *fb = state->base.fb;
struct drm_i915_gem_object *obj = intel_fb_obj(fb);
- struct drm_i915_gem_object *old_obj = intel_plane->obj;
int crtc_x, crtc_y;
unsigned int crtc_w, crtc_h;
uint32_t src_x, src_y, src_w, src_h;
- struct drm_rect *dst = &state->dst;
- const struct drm_rect *clip = &state->clip;
- bool primary_enabled;
- /*
- * If the sprite is completely covering the primary plane,
- * we can disable the primary and save power.
- */
- primary_enabled = !drm_rect_equals(dst, clip) || colorkey_enabled(intel_plane);
- WARN_ON(!primary_enabled && !state->visible && intel_crtc->active);
-
- intel_plane->crtc_x = state->orig_dst.x1;
- intel_plane->crtc_y = state->orig_dst.y1;
- intel_plane->crtc_w = drm_rect_width(&state->orig_dst);
- intel_plane->crtc_h = drm_rect_height(&state->orig_dst);
- intel_plane->src_x = state->orig_src.x1;
- intel_plane->src_y = state->orig_src.y1;
- intel_plane->src_w = drm_rect_width(&state->orig_src);
- intel_plane->src_h = drm_rect_height(&state->orig_src);
+ crtc = crtc ? crtc : plane->crtc;
+ intel_crtc = to_intel_crtc(crtc);
+
+ plane->fb = state->base.fb;
intel_plane->obj = obj;
if (intel_crtc->active) {
- bool primary_was_enabled = intel_crtc->primary_enabled;
-
- intel_crtc->primary_enabled = primary_enabled;
-
- if (primary_was_enabled != primary_enabled)
- intel_crtc_wait_for_pending_flips(crtc);
-
- if (primary_was_enabled && !primary_enabled)
- intel_pre_disable_primary(crtc);
+ intel_crtc->primary_enabled = !state->hides_primary;
if (state->visible) {
crtc_x = state->dst.x1;
@@ -1354,129 +1301,9 @@ intel_commit_sprite_plane(struct drm_plane *plane,
} else {
intel_plane->disable_plane(plane, crtc);
}
-
-
- intel_frontbuffer_flip(dev, INTEL_FRONTBUFFER_SPRITE(pipe));
-
- if (!primary_was_enabled && primary_enabled)
- intel_post_enable_primary(crtc);
- }
-
- /* Unpin old obj after new one is active to avoid ugliness */
- if (old_obj && old_obj != obj) {
-
- /*
- * It's fairly common to simply update the position of
- * an existing object. In that case, we don't need to
- * wait for vblank to avoid ugliness, we only need to
- * do the pin & ref bookkeeping.
- */
- if (intel_crtc->active)
- intel_wait_for_vblank(dev, intel_crtc->pipe);
-
- mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(old_obj);
- mutex_unlock(&dev->struct_mutex);
}
}
-static int
-intel_update_plane(struct drm_plane *plane, struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x, int crtc_y,
- unsigned int crtc_w, unsigned int crtc_h,
- uint32_t src_x, uint32_t src_y,
- uint32_t src_w, uint32_t src_h)
-{
- struct intel_plane_state state;
- struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
- int ret;
-
- state.crtc = crtc;
- state.fb = fb;
-
- /* sample coordinates in 16.16 fixed point */
- state.src.x1 = src_x;
- state.src.x2 = src_x + src_w;
- state.src.y1 = src_y;
- state.src.y2 = src_y + src_h;
-
- /* integer pixels */
- state.dst.x1 = crtc_x;
- state.dst.x2 = crtc_x + crtc_w;
- state.dst.y1 = crtc_y;
- state.dst.y2 = crtc_y + crtc_h;
-
- state.clip.x1 = 0;
- state.clip.y1 = 0;
- state.clip.x2 = intel_crtc->active ? intel_crtc->config.pipe_src_w : 0;
- state.clip.y2 = intel_crtc->active ? intel_crtc->config.pipe_src_h : 0;
- state.orig_src = state.src;
- state.orig_dst = state.dst;
-
- ret = intel_check_sprite_plane(plane, &state);
- if (ret)
- return ret;
-
- ret = intel_prepare_sprite_plane(plane, &state);
- if (ret)
- return ret;
-
- intel_commit_sprite_plane(plane, &state);
- return 0;
-}
-
-static int
-intel_disable_plane(struct drm_plane *plane)
-{
- struct drm_device *dev = plane->dev;
- struct intel_plane *intel_plane = to_intel_plane(plane);
- struct intel_crtc *intel_crtc;
- enum pipe pipe;
-
- if (!plane->fb)
- return 0;
-
- if (WARN_ON(!plane->crtc))
- return -EINVAL;
-
- intel_crtc = to_intel_crtc(plane->crtc);
- pipe = intel_crtc->pipe;
-
- if (intel_crtc->active) {
- bool primary_was_enabled = intel_crtc->primary_enabled;
-
- intel_crtc->primary_enabled = true;
-
- intel_plane->disable_plane(plane, plane->crtc);
-
- if (!primary_was_enabled && intel_crtc->primary_enabled)
- intel_post_enable_primary(plane->crtc);
- }
-
- if (intel_plane->obj) {
- if (intel_crtc->active)
- intel_wait_for_vblank(dev, intel_plane->pipe);
-
- mutex_lock(&dev->struct_mutex);
- intel_unpin_fb_obj(intel_plane->obj);
- i915_gem_track_fb(intel_plane->obj, NULL,
- INTEL_FRONTBUFFER_SPRITE(pipe));
- mutex_unlock(&dev->struct_mutex);
-
- intel_plane->obj = NULL;
- }
-
- return 0;
-}
-
-static void intel_destroy_plane(struct drm_plane *plane)
-{
- struct intel_plane *intel_plane = to_intel_plane(plane);
- intel_disable_plane(plane);
- drm_plane_cleanup(plane);
- kfree(intel_plane);
-}
-
int intel_sprite_set_colorkey(struct drm_device *dev, void *data,
struct drm_file *file_priv)
{
@@ -1535,62 +1362,18 @@ out_unlock:
return ret;
}
-int intel_plane_set_property(struct drm_plane *plane,
- struct drm_property *prop,
- uint64_t val)
-{
- struct drm_device *dev = plane->dev;
- struct intel_plane *intel_plane = to_intel_plane(plane);
- uint64_t old_val;
- int ret = -ENOENT;
-
- if (prop == dev->mode_config.rotation_property) {
- /* exactly one rotation angle please */
- if (hweight32(val & 0xf) != 1)
- return -EINVAL;
-
- if (intel_plane->rotation == val)
- return 0;
-
- old_val = intel_plane->rotation;
- intel_plane->rotation = val;
- ret = intel_plane_restore(plane);
- if (ret)
- intel_plane->rotation = old_val;
- }
-
- return ret;
-}
-
int intel_plane_restore(struct drm_plane *plane)
{
- struct intel_plane *intel_plane = to_intel_plane(plane);
-
if (!plane->crtc || !plane->fb)
return 0;
return plane->funcs->update_plane(plane, plane->crtc, plane->fb,
- intel_plane->crtc_x, intel_plane->crtc_y,
- intel_plane->crtc_w, intel_plane->crtc_h,
- intel_plane->src_x, intel_plane->src_y,
- intel_plane->src_w, intel_plane->src_h);
-}
-
-void intel_plane_disable(struct drm_plane *plane)
-{
- if (!plane->crtc || !plane->fb)
- return;
-
- intel_disable_plane(plane);
+ plane->state->crtc_x, plane->state->crtc_y,
+ plane->state->crtc_w, plane->state->crtc_h,
+ plane->state->src_x, plane->state->src_y,
+ plane->state->src_w, plane->state->src_h);
}
-static const struct drm_plane_funcs intel_plane_funcs = {
- .update_plane = intel_update_plane,
- .disable_plane = intel_disable_plane,
- .destroy = intel_destroy_plane,
- .set_property = intel_plane_set_property,
-};
-
static uint32_t ilk_plane_formats[] = {
DRM_FORMAT_XRGB8888,
DRM_FORMAT_YUYV,
@@ -1638,6 +1421,7 @@ int
intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
{
struct intel_plane *intel_plane;
+ struct intel_plane_state *state;
unsigned long possible_crtcs;
const uint32_t *plane_formats;
int num_plane_formats;
@@ -1650,6 +1434,13 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
if (!intel_plane)
return -ENOMEM;
+ state = intel_create_plane_state(&intel_plane->base);
+ if (!state) {
+ kfree(intel_plane);
+ return -ENOMEM;
+ }
+ intel_plane->base.state = &state->base;
+
switch (INTEL_INFO(dev)->gen) {
case 5:
case 6:
@@ -1719,7 +1510,8 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
intel_plane->pipe = pipe;
intel_plane->plane = plane;
- intel_plane->rotation = BIT(DRM_ROTATE_0);
+ intel_plane->check_plane = intel_check_sprite_plane;
+ intel_plane->commit_plane = intel_commit_sprite_plane;
possible_crtcs = (1 << pipe);
ret = drm_universal_plane_init(dev, &intel_plane->base, possible_crtcs,
&intel_plane_funcs,
@@ -1739,7 +1531,9 @@ intel_plane_init(struct drm_device *dev, enum pipe pipe, int plane)
if (dev->mode_config.rotation_property)
drm_object_attach_property(&intel_plane->base.base,
dev->mode_config.rotation_property,
- intel_plane->rotation);
+ state->base.rotation);
+
+ drm_plane_helper_add(&intel_plane->base, &intel_plane_helper_funcs);
out:
return ret;
diff --git a/drivers/gpu/drm/i915/intel_tv.c b/drivers/gpu/drm/i915/intel_tv.c
index 6f5f59b880f5..892d23c8479d 100644
--- a/drivers/gpu/drm/i915/intel_tv.c
+++ b/drivers/gpu/drm/i915/intel_tv.c
@@ -31,6 +31,7 @@
*/
#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_crtc.h>
#include <drm/drm_edid.h>
#include "intel_drv.h"
@@ -908,14 +909,14 @@ intel_tv_mode_valid(struct drm_connector *connector,
static void
intel_tv_get_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
- pipe_config->adjusted_mode.crtc_clock = pipe_config->port_clock;
+ pipe_config->base.adjusted_mode.crtc_clock = pipe_config->port_clock;
}
static bool
intel_tv_compute_config(struct intel_encoder *encoder,
- struct intel_crtc_config *pipe_config)
+ struct intel_crtc_state *pipe_config)
{
struct intel_tv *intel_tv = enc_to_tv(encoder);
const struct tv_mode *tv_mode = intel_tv_mode_find(intel_tv);
@@ -923,12 +924,12 @@ intel_tv_compute_config(struct intel_encoder *encoder,
if (!tv_mode)
return false;
- pipe_config->adjusted_mode.crtc_clock = tv_mode->clock;
+ pipe_config->base.adjusted_mode.crtc_clock = tv_mode->clock;
DRM_DEBUG_KMS("forcing bpc to 8 for TV\n");
pipe_config->pipe_bpp = 8*3;
/* TV has it's own notion of sync and other mode flags, so clear them. */
- pipe_config->adjusted_mode.flags = 0;
+ pipe_config->base.adjusted_mode.flags = 0;
/*
* FIXME: We don't check whether the input mode is actually what we want
@@ -1512,7 +1513,9 @@ static const struct drm_connector_funcs intel_tv_connector_funcs = {
.detect = intel_tv_detect,
.destroy = intel_tv_destroy,
.set_property = intel_tv_set_property,
+ .atomic_get_property = intel_connector_atomic_get_property,
.fill_modes = drm_helper_probe_single_connector_modes,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
};
static const struct drm_connector_helper_funcs intel_tv_connector_helper_funcs = {
diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
index 46de8d75b4bf..c47a3baa53d5 100644
--- a/drivers/gpu/drm/i915/intel_uncore.c
+++ b/drivers/gpu/drm/i915/intel_uncore.c
@@ -24,6 +24,8 @@
#include "i915_drv.h"
#include "intel_drv.h"
+#include <linux/pm_runtime.h>
+
#define FORCEWAKE_ACK_TIMEOUT_MS 2
#define __raw_i915_read8(dev_priv__, reg__) readb((dev_priv__)->regs + (reg__))
@@ -40,6 +42,26 @@
#define __raw_posting_read(dev_priv__, reg__) (void)__raw_i915_read32(dev_priv__, reg__)
+static const char * const forcewake_domain_names[] = {
+ "render",
+ "blitter",
+ "media",
+};
+
+const char *
+intel_uncore_forcewake_domain_to_str(const enum forcewake_domain_id id)
+{
+ BUILD_BUG_ON((sizeof(forcewake_domain_names)/sizeof(const char *)) !=
+ FW_DOMAIN_ID_COUNT);
+
+ if (id >= 0 && id < FW_DOMAIN_ID_COUNT)
+ return forcewake_domain_names[id];
+
+ WARN_ON(id);
+
+ return "unknown";
+}
+
static void
assert_device_not_suspended(struct drm_i915_private *dev_priv)
{
@@ -47,73 +69,128 @@ assert_device_not_suspended(struct drm_i915_private *dev_priv)
"Device suspended\n");
}
-static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv)
+static inline void
+fw_domain_reset(const struct intel_uncore_forcewake_domain *d)
{
- /* w/a for a sporadic read returning 0 by waiting for the GT
- * thread to wake up.
- */
- if (wait_for_atomic_us((__raw_i915_read32(dev_priv, GEN6_GT_THREAD_STATUS_REG) &
- GEN6_GT_THREAD_STATUS_CORE_MASK) == 0, 500))
- DRM_ERROR("GT thread status wait timed out\n");
+ WARN_ON(d->reg_set == 0);
+ __raw_i915_write32(d->i915, d->reg_set, d->val_reset);
}
-static void __gen6_gt_force_wake_reset(struct drm_i915_private *dev_priv)
+static inline void
+fw_domain_arm_timer(struct intel_uncore_forcewake_domain *d)
{
- __raw_i915_write32(dev_priv, FORCEWAKE, 0);
- /* something from same cacheline, but !FORCEWAKE */
- __raw_posting_read(dev_priv, ECOBUS);
+ mod_timer_pinned(&d->timer, jiffies + 1);
}
-static void __gen6_gt_force_wake_get(struct drm_i915_private *dev_priv,
- int fw_engine)
+static inline void
+fw_domain_wait_ack_clear(const struct intel_uncore_forcewake_domain *d)
{
- if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1) == 0,
+ if (wait_for_atomic((__raw_i915_read32(d->i915, d->reg_ack) &
+ FORCEWAKE_KERNEL) == 0,
FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+ DRM_ERROR("%s: timed out waiting for forcewake ack to clear.\n",
+ intel_uncore_forcewake_domain_to_str(d->id));
+}
- __raw_i915_write32(dev_priv, FORCEWAKE, 1);
- /* something from same cacheline, but !FORCEWAKE */
- __raw_posting_read(dev_priv, ECOBUS);
+static inline void
+fw_domain_get(const struct intel_uncore_forcewake_domain *d)
+{
+ __raw_i915_write32(d->i915, d->reg_set, d->val_set);
+}
- if (wait_for_atomic((__raw_i915_read32(dev_priv, FORCEWAKE_ACK) & 1),
+static inline void
+fw_domain_wait_ack(const struct intel_uncore_forcewake_domain *d)
+{
+ if (wait_for_atomic((__raw_i915_read32(d->i915, d->reg_ack) &
+ FORCEWAKE_KERNEL),
FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+ DRM_ERROR("%s: timed out waiting for forcewake ack request.\n",
+ intel_uncore_forcewake_domain_to_str(d->id));
+}
- /* WaRsForcewakeWaitTC0:snb */
- __gen6_gt_wait_for_thread_c0(dev_priv);
+static inline void
+fw_domain_put(const struct intel_uncore_forcewake_domain *d)
+{
+ __raw_i915_write32(d->i915, d->reg_set, d->val_clear);
}
-static void __gen7_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
+static inline void
+fw_domain_posting_read(const struct intel_uncore_forcewake_domain *d)
{
- __raw_i915_write32(dev_priv, FORCEWAKE_MT, _MASKED_BIT_DISABLE(0xffff));
- /* something from same cacheline, but !FORCEWAKE_MT */
- __raw_posting_read(dev_priv, ECOBUS);
+ /* something from same cacheline, but not from the set register */
+ if (d->reg_post)
+ __raw_posting_read(d->i915, d->reg_post);
}
-static void __gen7_gt_force_wake_mt_get(struct drm_i915_private *dev_priv,
- int fw_engine)
+static void
+fw_domains_get(struct drm_i915_private *dev_priv, enum forcewake_domains fw_domains)
{
- u32 forcewake_ack;
+ struct intel_uncore_forcewake_domain *d;
+ enum forcewake_domain_id id;
- if (IS_HASWELL(dev_priv->dev) || IS_BROADWELL(dev_priv->dev))
- forcewake_ack = FORCEWAKE_ACK_HSW;
- else
- forcewake_ack = FORCEWAKE_MT_ACK;
+ for_each_fw_domain_mask(d, fw_domains, dev_priv, id) {
+ fw_domain_wait_ack_clear(d);
+ fw_domain_get(d);
+ fw_domain_wait_ack(d);
+ }
+}
- if (wait_for_atomic((__raw_i915_read32(dev_priv, forcewake_ack) & FORCEWAKE_KERNEL) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake old ack to clear.\n");
+static void
+fw_domains_put(struct drm_i915_private *dev_priv, enum forcewake_domains fw_domains)
+{
+ struct intel_uncore_forcewake_domain *d;
+ enum forcewake_domain_id id;
- __raw_i915_write32(dev_priv, FORCEWAKE_MT,
- _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
- /* something from same cacheline, but !FORCEWAKE_MT */
- __raw_posting_read(dev_priv, ECOBUS);
+ for_each_fw_domain_mask(d, fw_domains, dev_priv, id) {
+ fw_domain_put(d);
+ fw_domain_posting_read(d);
+ }
+}
- if (wait_for_atomic((__raw_i915_read32(dev_priv, forcewake_ack) & FORCEWAKE_KERNEL),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out waiting for forcewake to ack request.\n");
+static void
+fw_domains_posting_read(struct drm_i915_private *dev_priv)
+{
+ struct intel_uncore_forcewake_domain *d;
+ enum forcewake_domain_id id;
- /* WaRsForcewakeWaitTC0:ivb,hsw */
+ /* No need to do for all, just do for first found */
+ for_each_fw_domain(d, dev_priv, id) {
+ fw_domain_posting_read(d);
+ break;
+ }
+}
+
+static void
+fw_domains_reset(struct drm_i915_private *dev_priv, enum forcewake_domains fw_domains)
+{
+ struct intel_uncore_forcewake_domain *d;
+ enum forcewake_domain_id id;
+
+ if (dev_priv->uncore.fw_domains == 0)
+ return;
+
+ for_each_fw_domain_mask(d, fw_domains, dev_priv, id)
+ fw_domain_reset(d);
+
+ fw_domains_posting_read(dev_priv);
+}
+
+static void __gen6_gt_wait_for_thread_c0(struct drm_i915_private *dev_priv)
+{
+ /* w/a for a sporadic read returning 0 by waiting for the GT
+ * thread to wake up.
+ */
+ if (wait_for_atomic_us((__raw_i915_read32(dev_priv, GEN6_GT_THREAD_STATUS_REG) &
+ GEN6_GT_THREAD_STATUS_CORE_MASK) == 0, 500))
+ DRM_ERROR("GT thread status wait timed out\n");
+}
+
+static void fw_domains_get_with_thread_status(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
+{
+ fw_domains_get(dev_priv, fw_domains);
+
+ /* WaRsForcewakeWaitTC0:snb,ivb,hsw,bdw,vlv */
__gen6_gt_wait_for_thread_c0(dev_priv);
}
@@ -126,27 +203,13 @@ static void gen6_gt_check_fifodbg(struct drm_i915_private *dev_priv)
__raw_i915_write32(dev_priv, GTFIFODBG, gtfifodbg);
}
-static void __gen6_gt_force_wake_put(struct drm_i915_private *dev_priv,
- int fw_engine)
+static void fw_domains_put_with_fifo(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
{
- __raw_i915_write32(dev_priv, FORCEWAKE, 0);
- /* something from same cacheline, but !FORCEWAKE */
- __raw_posting_read(dev_priv, ECOBUS);
+ fw_domains_put(dev_priv, fw_domains);
gen6_gt_check_fifodbg(dev_priv);
}
-static void __gen7_gt_force_wake_mt_put(struct drm_i915_private *dev_priv,
- int fw_engine)
-{
- __raw_i915_write32(dev_priv, FORCEWAKE_MT,
- _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
- /* something from same cacheline, but !FORCEWAKE_MT */
- __raw_posting_read(dev_priv, ECOBUS);
-
- if (IS_GEN7(dev_priv->dev))
- gen6_gt_check_fifodbg(dev_priv);
-}
-
static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
{
int ret = 0;
@@ -174,332 +237,78 @@ static int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
return ret;
}
-static void vlv_force_wake_reset(struct drm_i915_private *dev_priv)
-{
- __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
- _MASKED_BIT_DISABLE(0xffff));
- __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
- _MASKED_BIT_DISABLE(0xffff));
- /* something from same cacheline, but !FORCEWAKE_VLV */
- __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
-}
-
-static void __vlv_force_wake_get(struct drm_i915_private *dev_priv,
- int fw_engine)
-{
- /* Check for Render Engine */
- if (FORCEWAKE_RENDER & fw_engine) {
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_VLV) &
- FORCEWAKE_KERNEL) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: Render forcewake old ack to clear.\n");
-
- __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
- _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_VLV) &
- FORCEWAKE_KERNEL),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: waiting for Render to ack.\n");
- }
-
- /* Check for Media Engine */
- if (FORCEWAKE_MEDIA & fw_engine) {
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_MEDIA_VLV) &
- FORCEWAKE_KERNEL) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: Media forcewake old ack to clear.\n");
-
- __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
- _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_MEDIA_VLV) &
- FORCEWAKE_KERNEL),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: waiting for media to ack.\n");
- }
-}
-
-static void __vlv_force_wake_put(struct drm_i915_private *dev_priv,
- int fw_engine)
-{
-
- /* Check for Render Engine */
- if (FORCEWAKE_RENDER & fw_engine)
- __raw_i915_write32(dev_priv, FORCEWAKE_VLV,
- _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
-
- /* Check for Media Engine */
- if (FORCEWAKE_MEDIA & fw_engine)
- __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_VLV,
- _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
- /* something from same cacheline, but !FORCEWAKE_VLV */
- __raw_posting_read(dev_priv, FORCEWAKE_ACK_VLV);
- if (!IS_CHERRYVIEW(dev_priv->dev))
- gen6_gt_check_fifodbg(dev_priv);
-}
-
-static void vlv_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
+static void intel_uncore_fw_release_timer(unsigned long arg)
{
+ struct intel_uncore_forcewake_domain *domain = (void *)arg;
unsigned long irqflags;
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- if (fw_engine & FORCEWAKE_RENDER &&
- dev_priv->uncore.fw_rendercount++ != 0)
- fw_engine &= ~FORCEWAKE_RENDER;
- if (fw_engine & FORCEWAKE_MEDIA &&
- dev_priv->uncore.fw_mediacount++ != 0)
- fw_engine &= ~FORCEWAKE_MEDIA;
-
- if (fw_engine)
- dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_engine);
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void vlv_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
-{
- unsigned long irqflags;
-
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- if (fw_engine & FORCEWAKE_RENDER) {
- WARN_ON(!dev_priv->uncore.fw_rendercount);
- if (--dev_priv->uncore.fw_rendercount != 0)
- fw_engine &= ~FORCEWAKE_RENDER;
- }
-
- if (fw_engine & FORCEWAKE_MEDIA) {
- WARN_ON(!dev_priv->uncore.fw_mediacount);
- if (--dev_priv->uncore.fw_mediacount != 0)
- fw_engine &= ~FORCEWAKE_MEDIA;
- }
-
- if (fw_engine)
- dev_priv->uncore.funcs.force_wake_put(dev_priv, fw_engine);
-
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void __gen9_gt_force_wake_mt_reset(struct drm_i915_private *dev_priv)
-{
- __raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9,
- _MASKED_BIT_DISABLE(0xffff));
-
- __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9,
- _MASKED_BIT_DISABLE(0xffff));
-
- __raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9,
- _MASKED_BIT_DISABLE(0xffff));
-}
-
-static void
-__gen9_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
-{
- /* Check for Render Engine */
- if (FORCEWAKE_RENDER & fw_engine) {
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_RENDER_GEN9) &
- FORCEWAKE_KERNEL) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: Render forcewake old ack to clear.\n");
-
- __raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9,
- _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_RENDER_GEN9) &
- FORCEWAKE_KERNEL),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: waiting for Render to ack.\n");
- }
+ assert_device_not_suspended(domain->i915);
- /* Check for Media Engine */
- if (FORCEWAKE_MEDIA & fw_engine) {
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_MEDIA_GEN9) &
- FORCEWAKE_KERNEL) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: Media forcewake old ack to clear.\n");
-
- __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9,
- _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_MEDIA_GEN9) &
- FORCEWAKE_KERNEL),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: waiting for Media to ack.\n");
- }
+ spin_lock_irqsave(&domain->i915->uncore.lock, irqflags);
+ if (WARN_ON(domain->wake_count == 0))
+ domain->wake_count++;
- /* Check for Blitter Engine */
- if (FORCEWAKE_BLITTER & fw_engine) {
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_BLITTER_GEN9) &
- FORCEWAKE_KERNEL) == 0,
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: Blitter forcewake old ack to clear.\n");
-
- __raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9,
- _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL));
-
- if (wait_for_atomic((__raw_i915_read32(dev_priv,
- FORCEWAKE_ACK_BLITTER_GEN9) &
- FORCEWAKE_KERNEL),
- FORCEWAKE_ACK_TIMEOUT_MS))
- DRM_ERROR("Timed out: waiting for Blitter to ack.\n");
- }
-}
+ if (--domain->wake_count == 0)
+ domain->i915->uncore.funcs.force_wake_put(domain->i915,
+ 1 << domain->id);
-static void
-__gen9_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
-{
- /* Check for Render Engine */
- if (FORCEWAKE_RENDER & fw_engine)
- __raw_i915_write32(dev_priv, FORCEWAKE_RENDER_GEN9,
- _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
- /* Check for Media Engine */
- if (FORCEWAKE_MEDIA & fw_engine)
- __raw_i915_write32(dev_priv, FORCEWAKE_MEDIA_GEN9,
- _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
-
- /* Check for Blitter Engine */
- if (FORCEWAKE_BLITTER & fw_engine)
- __raw_i915_write32(dev_priv, FORCEWAKE_BLITTER_GEN9,
- _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL));
+ spin_unlock_irqrestore(&domain->i915->uncore.lock, irqflags);
}
-static void
-gen9_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
+void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
{
+ struct drm_i915_private *dev_priv = dev->dev_private;
unsigned long irqflags;
+ struct intel_uncore_forcewake_domain *domain;
+ int retry_count = 100;
+ enum forcewake_domain_id id;
+ enum forcewake_domains fw = 0, active_domains;
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
-
- if (FORCEWAKE_RENDER & fw_engine) {
- if (dev_priv->uncore.fw_rendercount++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_RENDER);
- }
-
- if (FORCEWAKE_MEDIA & fw_engine) {
- if (dev_priv->uncore.fw_mediacount++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_MEDIA);
- }
+ /* Hold uncore.lock across reset to prevent any register access
+ * with forcewake not set correctly. Wait until all pending
+ * timers are run before holding.
+ */
+ while (1) {
+ active_domains = 0;
- if (FORCEWAKE_BLITTER & fw_engine) {
- if (dev_priv->uncore.fw_blittercount++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv,
- FORCEWAKE_BLITTER);
- }
+ for_each_fw_domain(domain, dev_priv, id) {
+ if (del_timer_sync(&domain->timer) == 0)
+ continue;
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
+ intel_uncore_fw_release_timer((unsigned long)domain);
+ }
-static void
-gen9_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
-{
- unsigned long irqflags;
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ for_each_fw_domain(domain, dev_priv, id) {
+ if (timer_pending(&domain->timer))
+ active_domains |= (1 << id);
+ }
- if (FORCEWAKE_RENDER & fw_engine) {
- WARN_ON(dev_priv->uncore.fw_rendercount == 0);
- if (--dev_priv->uncore.fw_rendercount == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_RENDER);
- }
+ if (active_domains == 0)
+ break;
- if (FORCEWAKE_MEDIA & fw_engine) {
- WARN_ON(dev_priv->uncore.fw_mediacount == 0);
- if (--dev_priv->uncore.fw_mediacount == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_MEDIA);
- }
+ if (--retry_count == 0) {
+ DRM_ERROR("Timed out waiting for forcewake timers to finish\n");
+ break;
+ }
- if (FORCEWAKE_BLITTER & fw_engine) {
- WARN_ON(dev_priv->uncore.fw_blittercount == 0);
- if (--dev_priv->uncore.fw_blittercount == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv,
- FORCEWAKE_BLITTER);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
+ cond_resched();
}
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-}
-
-static void gen6_force_wake_timer(unsigned long arg)
-{
- struct drm_i915_private *dev_priv = (void *)arg;
- unsigned long irqflags;
-
- assert_device_not_suspended(dev_priv);
-
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- WARN_ON(!dev_priv->uncore.forcewake_count);
-
- if (--dev_priv->uncore.forcewake_count == 0)
- dev_priv->uncore.funcs.force_wake_put(dev_priv, FORCEWAKE_ALL);
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-
- intel_runtime_pm_put(dev_priv);
-}
-
-void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
-{
- struct drm_i915_private *dev_priv = dev->dev_private;
- unsigned long irqflags;
-
- if (del_timer_sync(&dev_priv->uncore.force_wake_timer))
- gen6_force_wake_timer((unsigned long)dev_priv);
-
- /* Hold uncore.lock across reset to prevent any register access
- * with forcewake not set correctly
- */
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ WARN_ON(active_domains);
- if (IS_VALLEYVIEW(dev))
- vlv_force_wake_reset(dev_priv);
- else if (IS_GEN6(dev) || IS_GEN7(dev))
- __gen6_gt_force_wake_reset(dev_priv);
+ for_each_fw_domain(domain, dev_priv, id)
+ if (domain->wake_count)
+ fw |= 1 << id;
- if (IS_IVYBRIDGE(dev) || IS_HASWELL(dev) || IS_BROADWELL(dev))
- __gen7_gt_force_wake_mt_reset(dev_priv);
+ if (fw)
+ dev_priv->uncore.funcs.force_wake_put(dev_priv, fw);
- if (IS_GEN9(dev))
- __gen9_gt_force_wake_mt_reset(dev_priv);
+ fw_domains_reset(dev_priv, FORCEWAKE_ALL);
if (restore) { /* If reset with a user forcewake, try to restore */
- unsigned fw = 0;
-
- if (IS_VALLEYVIEW(dev)) {
- if (dev_priv->uncore.fw_rendercount)
- fw |= FORCEWAKE_RENDER;
-
- if (dev_priv->uncore.fw_mediacount)
- fw |= FORCEWAKE_MEDIA;
- } else if (IS_GEN9(dev)) {
- if (dev_priv->uncore.fw_rendercount)
- fw |= FORCEWAKE_RENDER;
-
- if (dev_priv->uncore.fw_mediacount)
- fw |= FORCEWAKE_MEDIA;
-
- if (dev_priv->uncore.fw_blittercount)
- fw |= FORCEWAKE_BLITTER;
- } else {
- if (dev_priv->uncore.forcewake_count)
- fw = FORCEWAKE_ALL;
- }
-
if (fw)
dev_priv->uncore.funcs.force_wake_get(dev_priv, fw);
@@ -509,17 +318,16 @@ void intel_uncore_forcewake_reset(struct drm_device *dev, bool restore)
GT_FIFO_FREE_ENTRIES_MASK;
}
+ if (!restore)
+ assert_forcewakes_inactive(dev_priv);
+
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
-static void __intel_uncore_early_sanitize(struct drm_device *dev,
- bool restore_forcewake)
+static void intel_uncore_ellc_detect(struct drm_device *dev)
{
struct drm_i915_private *dev_priv = dev->dev_private;
- if (HAS_FPGA_DBG_UNCLAIMED(dev))
- __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
-
if ((IS_HASWELL(dev) || IS_BROADWELL(dev)) &&
(__raw_i915_read32(dev_priv, HSW_EDRAM_PRESENT) == 1)) {
/* The docs do not explain exactly how the calculation can be
@@ -530,6 +338,15 @@ static void __intel_uncore_early_sanitize(struct drm_device *dev,
dev_priv->ellc_size = 128;
DRM_INFO("Found %zuMB of eLLC\n", dev_priv->ellc_size);
}
+}
+
+static void __intel_uncore_early_sanitize(struct drm_device *dev,
+ bool restore_forcewake)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (HAS_FPGA_DBG_UNCLAIMED(dev))
+ __raw_i915_write32(dev_priv, FPGA_DBG, FPGA_DBG_RM_NOCLAIM);
/* clear out old GT FIFO errors */
if (IS_GEN6(dev) || IS_GEN7(dev))
@@ -551,81 +368,92 @@ void intel_uncore_sanitize(struct drm_device *dev)
intel_disable_gt_powersave(dev);
}
-/*
- * Generally this is called implicitly by the register read function. However,
- * if some sequence requires the GT to not power down then this function should
- * be called at the beginning of the sequence followed by a call to
- * gen6_gt_force_wake_put() at the end of the sequence.
+/**
+ * intel_uncore_forcewake_get - grab forcewake domain references
+ * @dev_priv: i915 device instance
+ * @fw_domains: forcewake domains to get reference on
+ *
+ * This function can be used get GT's forcewake domain references.
+ * Normal register access will handle the forcewake domains automatically.
+ * However if some sequence requires the GT to not power down a particular
+ * forcewake domains this function should be called at the beginning of the
+ * sequence. And subsequently the reference should be dropped by symmetric
+ * call to intel_unforce_forcewake_put(). Usually caller wants all the domains
+ * to be kept awake so the @fw_domains would be then FORCEWAKE_ALL.
*/
-void gen6_gt_force_wake_get(struct drm_i915_private *dev_priv, int fw_engine)
+void intel_uncore_forcewake_get(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
{
unsigned long irqflags;
+ struct intel_uncore_forcewake_domain *domain;
+ enum forcewake_domain_id id;
if (!dev_priv->uncore.funcs.force_wake_get)
return;
- intel_runtime_pm_get(dev_priv);
+ WARN_ON(dev_priv->pm.suspended);
- /* Redirect to Gen9 specific routine */
- if (IS_GEN9(dev_priv->dev))
- return gen9_force_wake_get(dev_priv, fw_engine);
-
- /* Redirect to VLV specific routine */
- if (IS_VALLEYVIEW(dev_priv->dev))
- return vlv_force_wake_get(dev_priv, fw_engine);
+ fw_domains &= dev_priv->uncore.fw_domains;
spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- if (dev_priv->uncore.forcewake_count++ == 0)
- dev_priv->uncore.funcs.force_wake_get(dev_priv, FORCEWAKE_ALL);
+
+ for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+ if (domain->wake_count++)
+ fw_domains &= ~(1 << id);
+ }
+
+ if (fw_domains)
+ dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
+
spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
-/*
- * see gen6_gt_force_wake_get()
+/**
+ * intel_uncore_forcewake_put - release a forcewake domain reference
+ * @dev_priv: i915 device instance
+ * @fw_domains: forcewake domains to put references
+ *
+ * This function drops the device-level forcewakes for specified
+ * domains obtained by intel_uncore_forcewake_get().
*/
-void gen6_gt_force_wake_put(struct drm_i915_private *dev_priv, int fw_engine)
+void intel_uncore_forcewake_put(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
{
unsigned long irqflags;
- bool delayed = false;
+ struct intel_uncore_forcewake_domain *domain;
+ enum forcewake_domain_id id;
if (!dev_priv->uncore.funcs.force_wake_put)
return;
- /* Redirect to Gen9 specific routine */
- if (IS_GEN9(dev_priv->dev)) {
- gen9_force_wake_put(dev_priv, fw_engine);
- goto out;
- }
+ fw_domains &= dev_priv->uncore.fw_domains;
- /* Redirect to VLV specific routine */
- if (IS_VALLEYVIEW(dev_priv->dev)) {
- vlv_force_wake_put(dev_priv, fw_engine);
- goto out;
- }
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
+ for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+ if (WARN_ON(domain->wake_count == 0))
+ continue;
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags);
- WARN_ON(!dev_priv->uncore.forcewake_count);
+ if (--domain->wake_count)
+ continue;
- if (--dev_priv->uncore.forcewake_count == 0) {
- dev_priv->uncore.forcewake_count++;
- delayed = true;
- mod_timer_pinned(&dev_priv->uncore.force_wake_timer,
- jiffies + 1);
+ domain->wake_count++;
+ fw_domain_arm_timer(domain);
}
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
-out:
- if (!delayed)
- intel_runtime_pm_put(dev_priv);
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags);
}
-void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
+void assert_forcewakes_inactive(struct drm_i915_private *dev_priv)
{
+ struct intel_uncore_forcewake_domain *domain;
+ enum forcewake_domain_id id;
+
if (!dev_priv->uncore.funcs.force_wake_get)
return;
- WARN_ON(dev_priv->uncore.forcewake_count > 0);
+ for_each_fw_domain(domain, dev_priv, id)
+ WARN_ON(domain->wake_count);
}
/* We give fast paths for the really cool registers */
@@ -647,9 +475,9 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
#define FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg) \
(REG_RANGE((reg), 0x2000, 0x4000) || \
- REG_RANGE((reg), 0x5000, 0x8000) || \
+ REG_RANGE((reg), 0x5200, 0x8000) || \
REG_RANGE((reg), 0x8300, 0x8500) || \
- REG_RANGE((reg), 0xB000, 0xC000) || \
+ REG_RANGE((reg), 0xB000, 0xB480) || \
REG_RANGE((reg), 0xE000, 0xE800))
#define FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg) \
@@ -658,17 +486,14 @@ void assert_force_wake_inactive(struct drm_i915_private *dev_priv)
REG_RANGE((reg), 0x12000, 0x14000) || \
REG_RANGE((reg), 0x1A000, 0x1C000) || \
REG_RANGE((reg), 0x1E800, 0x1EA00) || \
- REG_RANGE((reg), 0x30000, 0x40000))
+ REG_RANGE((reg), 0x30000, 0x38000))
#define FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg) \
(REG_RANGE((reg), 0x4000, 0x5000) || \
REG_RANGE((reg), 0x8000, 0x8300) || \
REG_RANGE((reg), 0x8500, 0x8600) || \
REG_RANGE((reg), 0x9000, 0xB000) || \
- REG_RANGE((reg), 0xC000, 0xC800) || \
- REG_RANGE((reg), 0xF000, 0x10000) || \
- REG_RANGE((reg), 0x14000, 0x14400) || \
- REG_RANGE((reg), 0x22000, 0x24000))
+ REG_RANGE((reg), 0xF000, 0x10000))
#define FORCEWAKE_GEN9_UNCORE_RANGE_OFFSET(reg) \
REG_RANGE((reg), 0xB00, 0x2000)
@@ -740,96 +565,118 @@ hsw_unclaimed_reg_detect(struct drm_i915_private *dev_priv)
}
}
-#define REG_READ_HEADER(x) \
- unsigned long irqflags; \
+#define GEN2_READ_HEADER(x) \
u##x val = 0; \
- assert_device_not_suspended(dev_priv); \
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+ assert_device_not_suspended(dev_priv);
-#define REG_READ_FOOTER \
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+#define GEN2_READ_FOOTER \
trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
return val
-#define __gen4_read(x) \
+#define __gen2_read(x) \
static u##x \
-gen4_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- REG_READ_HEADER(x); \
+gen2_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
+ GEN2_READ_HEADER(x); \
val = __raw_i915_read##x(dev_priv, reg); \
- REG_READ_FOOTER; \
+ GEN2_READ_FOOTER; \
}
#define __gen5_read(x) \
static u##x \
gen5_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- REG_READ_HEADER(x); \
+ GEN2_READ_HEADER(x); \
ilk_dummy_write(dev_priv); \
val = __raw_i915_read##x(dev_priv, reg); \
- REG_READ_FOOTER; \
+ GEN2_READ_FOOTER; \
+}
+
+__gen5_read(8)
+__gen5_read(16)
+__gen5_read(32)
+__gen5_read(64)
+__gen2_read(8)
+__gen2_read(16)
+__gen2_read(32)
+__gen2_read(64)
+
+#undef __gen5_read
+#undef __gen2_read
+
+#undef GEN2_READ_FOOTER
+#undef GEN2_READ_HEADER
+
+#define GEN6_READ_HEADER(x) \
+ unsigned long irqflags; \
+ u##x val = 0; \
+ assert_device_not_suspended(dev_priv); \
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define GEN6_READ_FOOTER \
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags); \
+ trace_i915_reg_rw(false, reg, val, sizeof(val), trace); \
+ return val
+
+static inline void __force_wake_get(struct drm_i915_private *dev_priv,
+ enum forcewake_domains fw_domains)
+{
+ struct intel_uncore_forcewake_domain *domain;
+ enum forcewake_domain_id id;
+
+ if (WARN_ON(!fw_domains))
+ return;
+
+ /* Ideally GCC would be constant-fold and eliminate this loop */
+ for_each_fw_domain_mask(domain, fw_domains, dev_priv, id) {
+ if (domain->wake_count) {
+ fw_domains &= ~(1 << id);
+ continue;
+ }
+
+ domain->wake_count++;
+ fw_domain_arm_timer(domain);
+ }
+
+ if (fw_domains)
+ dev_priv->uncore.funcs.force_wake_get(dev_priv, fw_domains);
}
#define __gen6_read(x) \
static u##x \
gen6_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- REG_READ_HEADER(x); \
+ GEN6_READ_HEADER(x); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, true); \
- if (dev_priv->uncore.forcewake_count == 0 && \
- NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, \
- FORCEWAKE_ALL); \
- val = __raw_i915_read##x(dev_priv, reg); \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, \
- FORCEWAKE_ALL); \
- } else { \
- val = __raw_i915_read##x(dev_priv, reg); \
- } \
+ if (NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+ val = __raw_i915_read##x(dev_priv, reg); \
hsw_unclaimed_reg_debug(dev_priv, reg, true, false); \
- REG_READ_FOOTER; \
+ GEN6_READ_FOOTER; \
}
#define __vlv_read(x) \
static u##x \
vlv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- unsigned fwengine = 0; \
- REG_READ_HEADER(x); \
- if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine = FORCEWAKE_RENDER; \
- } else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine = FORCEWAKE_MEDIA; \
- } \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
+ GEN6_READ_HEADER(x); \
+ if (FORCEWAKE_VLV_RENDER_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+ else if (FORCEWAKE_VLV_MEDIA_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
val = __raw_i915_read##x(dev_priv, reg); \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
- REG_READ_FOOTER; \
+ GEN6_READ_FOOTER; \
}
#define __chv_read(x) \
static u##x \
chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- unsigned fwengine = 0; \
- REG_READ_HEADER(x); \
- if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine = FORCEWAKE_RENDER; \
- } else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine = FORCEWAKE_MEDIA; \
- } else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine |= FORCEWAKE_RENDER; \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine |= FORCEWAKE_MEDIA; \
- } \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
+ GEN6_READ_HEADER(x); \
+ if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+ else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
+ else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, \
+ FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
val = __raw_i915_read##x(dev_priv, reg); \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
- REG_READ_FOOTER; \
+ GEN6_READ_FOOTER; \
}
#define SKL_NEEDS_FORCE_WAKE(dev_priv, reg) \
@@ -838,33 +685,22 @@ chv_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
#define __gen9_read(x) \
static u##x \
gen9_read##x(struct drm_i915_private *dev_priv, off_t reg, bool trace) { \
- REG_READ_HEADER(x); \
- if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
- val = __raw_i915_read##x(dev_priv, reg); \
- } else { \
- unsigned fwengine = 0; \
- if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine = FORCEWAKE_RENDER; \
- } else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine = FORCEWAKE_MEDIA; \
- } else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine |= FORCEWAKE_RENDER; \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine |= FORCEWAKE_MEDIA; \
- } else { \
- if (dev_priv->uncore.fw_blittercount == 0) \
- fwengine = FORCEWAKE_BLITTER; \
- } \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
- val = __raw_i915_read##x(dev_priv, reg); \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
- } \
- REG_READ_FOOTER; \
+ enum forcewake_domains fw_engine; \
+ GEN6_READ_HEADER(x); \
+ if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg))) \
+ fw_engine = 0; \
+ else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+ fw_engine = FORCEWAKE_RENDER; \
+ else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+ fw_engine = FORCEWAKE_MEDIA; \
+ else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+ fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+ else \
+ fw_engine = FORCEWAKE_BLITTER; \
+ if (fw_engine) \
+ __force_wake_get(dev_priv, fw_engine); \
+ val = __raw_i915_read##x(dev_priv, reg); \
+ GEN6_READ_FOOTER; \
}
__gen9_read(8)
@@ -883,55 +719,66 @@ __gen6_read(8)
__gen6_read(16)
__gen6_read(32)
__gen6_read(64)
-__gen5_read(8)
-__gen5_read(16)
-__gen5_read(32)
-__gen5_read(64)
-__gen4_read(8)
-__gen4_read(16)
-__gen4_read(32)
-__gen4_read(64)
#undef __gen9_read
#undef __chv_read
#undef __vlv_read
#undef __gen6_read
-#undef __gen5_read
-#undef __gen4_read
-#undef REG_READ_FOOTER
-#undef REG_READ_HEADER
+#undef GEN6_READ_FOOTER
+#undef GEN6_READ_HEADER
-#define REG_WRITE_HEADER \
- unsigned long irqflags; \
+#define GEN2_WRITE_HEADER \
trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
assert_device_not_suspended(dev_priv); \
- spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
-#define REG_WRITE_FOOTER \
- spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+#define GEN2_WRITE_FOOTER
-#define __gen4_write(x) \
+#define __gen2_write(x) \
static void \
-gen4_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
- REG_WRITE_HEADER; \
+gen2_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
+ GEN2_WRITE_HEADER; \
__raw_i915_write##x(dev_priv, reg, val); \
- REG_WRITE_FOOTER; \
+ GEN2_WRITE_FOOTER; \
}
#define __gen5_write(x) \
static void \
gen5_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
- REG_WRITE_HEADER; \
+ GEN2_WRITE_HEADER; \
ilk_dummy_write(dev_priv); \
__raw_i915_write##x(dev_priv, reg, val); \
- REG_WRITE_FOOTER; \
+ GEN2_WRITE_FOOTER; \
}
+__gen5_write(8)
+__gen5_write(16)
+__gen5_write(32)
+__gen5_write(64)
+__gen2_write(8)
+__gen2_write(16)
+__gen2_write(32)
+__gen2_write(64)
+
+#undef __gen5_write
+#undef __gen2_write
+
+#undef GEN2_WRITE_FOOTER
+#undef GEN2_WRITE_HEADER
+
+#define GEN6_WRITE_HEADER \
+ unsigned long irqflags; \
+ trace_i915_reg_rw(true, reg, val, sizeof(val), trace); \
+ assert_device_not_suspended(dev_priv); \
+ spin_lock_irqsave(&dev_priv->uncore.lock, irqflags)
+
+#define GEN6_WRITE_FOOTER \
+ spin_unlock_irqrestore(&dev_priv->uncore.lock, irqflags)
+
#define __gen6_write(x) \
static void \
gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
- REG_WRITE_HEADER; \
+ GEN6_WRITE_HEADER; \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
@@ -939,14 +786,14 @@ gen6_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace
if (unlikely(__fifo_ret)) { \
gen6_gt_check_fifodbg(dev_priv); \
} \
- REG_WRITE_FOOTER; \
+ GEN6_WRITE_FOOTER; \
}
#define __hsw_write(x) \
static void \
hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
u32 __fifo_ret = 0; \
- REG_WRITE_HEADER; \
+ GEN6_WRITE_HEADER; \
if (NEEDS_FORCE_WAKE((dev_priv), (reg))) { \
__fifo_ret = __gen6_gt_wait_for_fifo(dev_priv); \
} \
@@ -957,7 +804,7 @@ hsw_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace)
} \
hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
hsw_unclaimed_reg_detect(dev_priv); \
- REG_WRITE_FOOTER; \
+ GEN6_WRITE_FOOTER; \
}
static const u32 gen8_shadowed_regs[] = {
@@ -984,50 +831,31 @@ static bool is_gen8_shadowed(struct drm_i915_private *dev_priv, u32 reg)
#define __gen8_write(x) \
static void \
gen8_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
- REG_WRITE_HEADER; \
+ GEN6_WRITE_HEADER; \
hsw_unclaimed_reg_debug(dev_priv, reg, false, true); \
- if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) { \
- if (dev_priv->uncore.forcewake_count == 0) \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, \
- FORCEWAKE_ALL); \
- __raw_i915_write##x(dev_priv, reg, val); \
- if (dev_priv->uncore.forcewake_count == 0) \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, \
- FORCEWAKE_ALL); \
- } else { \
- __raw_i915_write##x(dev_priv, reg, val); \
- } \
+ if (reg < 0x40000 && !is_gen8_shadowed(dev_priv, reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+ __raw_i915_write##x(dev_priv, reg, val); \
hsw_unclaimed_reg_debug(dev_priv, reg, false, false); \
hsw_unclaimed_reg_detect(dev_priv); \
- REG_WRITE_FOOTER; \
+ GEN6_WRITE_FOOTER; \
}
#define __chv_write(x) \
static void \
chv_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, bool trace) { \
- unsigned fwengine = 0; \
bool shadowed = is_gen8_shadowed(dev_priv, reg); \
- REG_WRITE_HEADER; \
+ GEN6_WRITE_HEADER; \
if (!shadowed) { \
- if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine = FORCEWAKE_RENDER; \
- } else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine = FORCEWAKE_MEDIA; \
- } else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine |= FORCEWAKE_RENDER; \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine |= FORCEWAKE_MEDIA; \
- } \
+ if (FORCEWAKE_CHV_RENDER_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_RENDER); \
+ else if (FORCEWAKE_CHV_MEDIA_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_MEDIA); \
+ else if (FORCEWAKE_CHV_COMMON_RANGE_OFFSET(reg)) \
+ __force_wake_get(dev_priv, FORCEWAKE_RENDER | FORCEWAKE_MEDIA); \
} \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, fwengine); \
__raw_i915_write##x(dev_priv, reg, val); \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, fwengine); \
- REG_WRITE_FOOTER; \
+ GEN6_WRITE_FOOTER; \
}
static const u32 gen9_shadowed_regs[] = {
@@ -1057,36 +885,23 @@ static bool is_gen9_shadowed(struct drm_i915_private *dev_priv, u32 reg)
static void \
gen9_write##x(struct drm_i915_private *dev_priv, off_t reg, u##x val, \
bool trace) { \
- REG_WRITE_HEADER; \
- if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)) || \
- is_gen9_shadowed(dev_priv, reg)) { \
- __raw_i915_write##x(dev_priv, reg, val); \
- } else { \
- unsigned fwengine = 0; \
- if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine = FORCEWAKE_RENDER; \
- } else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine = FORCEWAKE_MEDIA; \
- } else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) { \
- if (dev_priv->uncore.fw_rendercount == 0) \
- fwengine |= FORCEWAKE_RENDER; \
- if (dev_priv->uncore.fw_mediacount == 0) \
- fwengine |= FORCEWAKE_MEDIA; \
- } else { \
- if (dev_priv->uncore.fw_blittercount == 0) \
- fwengine = FORCEWAKE_BLITTER; \
- } \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_get(dev_priv, \
- fwengine); \
- __raw_i915_write##x(dev_priv, reg, val); \
- if (fwengine) \
- dev_priv->uncore.funcs.force_wake_put(dev_priv, \
- fwengine); \
- } \
- REG_WRITE_FOOTER; \
+ enum forcewake_domains fw_engine; \
+ GEN6_WRITE_HEADER; \
+ if (!SKL_NEEDS_FORCE_WAKE((dev_priv), (reg)) || \
+ is_gen9_shadowed(dev_priv, reg)) \
+ fw_engine = 0; \
+ else if (FORCEWAKE_GEN9_RENDER_RANGE_OFFSET(reg)) \
+ fw_engine = FORCEWAKE_RENDER; \
+ else if (FORCEWAKE_GEN9_MEDIA_RANGE_OFFSET(reg)) \
+ fw_engine = FORCEWAKE_MEDIA; \
+ else if (FORCEWAKE_GEN9_COMMON_RANGE_OFFSET(reg)) \
+ fw_engine = FORCEWAKE_RENDER | FORCEWAKE_MEDIA; \
+ else \
+ fw_engine = FORCEWAKE_BLITTER; \
+ if (fw_engine) \
+ __force_wake_get(dev_priv, fw_engine); \
+ __raw_i915_write##x(dev_priv, reg, val); \
+ GEN6_WRITE_FOOTER; \
}
__gen9_write(8)
@@ -1109,24 +924,14 @@ __gen6_write(8)
__gen6_write(16)
__gen6_write(32)
__gen6_write(64)
-__gen5_write(8)
-__gen5_write(16)
-__gen5_write(32)
-__gen5_write(64)
-__gen4_write(8)
-__gen4_write(16)
-__gen4_write(32)
-__gen4_write(64)
#undef __gen9_write
#undef __chv_write
#undef __gen8_write
#undef __hsw_write
#undef __gen6_write
-#undef __gen5_write
-#undef __gen4_write
-#undef REG_WRITE_FOOTER
-#undef REG_WRITE_HEADER
+#undef GEN6_WRITE_FOOTER
+#undef GEN6_WRITE_HEADER
#define ASSIGN_WRITE_MMIO_VFUNCS(x) \
do { \
@@ -1144,24 +949,86 @@ do { \
dev_priv->uncore.funcs.mmio_readq = x##_read64; \
} while (0)
-void intel_uncore_init(struct drm_device *dev)
+
+static void fw_domain_init(struct drm_i915_private *dev_priv,
+ enum forcewake_domain_id domain_id,
+ u32 reg_set, u32 reg_ack)
{
- struct drm_i915_private *dev_priv = dev->dev_private;
+ struct intel_uncore_forcewake_domain *d;
- setup_timer(&dev_priv->uncore.force_wake_timer,
- gen6_force_wake_timer, (unsigned long)dev_priv);
+ if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
+ return;
- __intel_uncore_early_sanitize(dev, false);
+ d = &dev_priv->uncore.fw_domain[domain_id];
+
+ WARN_ON(d->wake_count);
+
+ d->wake_count = 0;
+ d->reg_set = reg_set;
+ d->reg_ack = reg_ack;
+
+ if (IS_GEN6(dev_priv)) {
+ d->val_reset = 0;
+ d->val_set = FORCEWAKE_KERNEL;
+ d->val_clear = 0;
+ } else {
+ d->val_reset = _MASKED_BIT_DISABLE(0xffff);
+ d->val_set = _MASKED_BIT_ENABLE(FORCEWAKE_KERNEL);
+ d->val_clear = _MASKED_BIT_DISABLE(FORCEWAKE_KERNEL);
+ }
+
+ if (IS_VALLEYVIEW(dev_priv))
+ d->reg_post = FORCEWAKE_ACK_VLV;
+ else if (IS_GEN6(dev_priv) || IS_GEN7(dev_priv) || IS_GEN8(dev_priv))
+ d->reg_post = ECOBUS;
+ else
+ d->reg_post = 0;
+
+ d->i915 = dev_priv;
+ d->id = domain_id;
+
+ setup_timer(&d->timer, intel_uncore_fw_release_timer, (unsigned long)d);
+
+ dev_priv->uncore.fw_domains |= (1 << domain_id);
+
+ fw_domain_reset(d);
+}
+
+static void intel_uncore_fw_domains_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ if (INTEL_INFO(dev_priv->dev)->gen <= 5)
+ return;
if (IS_GEN9(dev)) {
- dev_priv->uncore.funcs.force_wake_get = __gen9_force_wake_get;
- dev_priv->uncore.funcs.force_wake_put = __gen9_force_wake_put;
+ dev_priv->uncore.funcs.force_wake_get = fw_domains_get;
+ dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE_RENDER_GEN9,
+ FORCEWAKE_ACK_RENDER_GEN9);
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_BLITTER,
+ FORCEWAKE_BLITTER_GEN9,
+ FORCEWAKE_ACK_BLITTER_GEN9);
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA,
+ FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
} else if (IS_VALLEYVIEW(dev)) {
- dev_priv->uncore.funcs.force_wake_get = __vlv_force_wake_get;
- dev_priv->uncore.funcs.force_wake_put = __vlv_force_wake_put;
+ dev_priv->uncore.funcs.force_wake_get = fw_domains_get;
+ if (!IS_CHERRYVIEW(dev))
+ dev_priv->uncore.funcs.force_wake_put =
+ fw_domains_put_with_fifo;
+ else
+ dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_MEDIA,
+ FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
} else if (IS_HASWELL(dev) || IS_BROADWELL(dev)) {
- dev_priv->uncore.funcs.force_wake_get = __gen7_gt_force_wake_mt_get;
- dev_priv->uncore.funcs.force_wake_put = __gen7_gt_force_wake_mt_put;
+ dev_priv->uncore.funcs.force_wake_get =
+ fw_domains_get_with_thread_status;
+ dev_priv->uncore.funcs.force_wake_put = fw_domains_put;
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
} else if (IS_IVYBRIDGE(dev)) {
u32 ecobus;
@@ -1174,35 +1041,54 @@ void intel_uncore_init(struct drm_device *dev)
* (correctly) interpreted by the test below as MT
* forcewake being disabled.
*/
+ dev_priv->uncore.funcs.force_wake_get =
+ fw_domains_get_with_thread_status;
+ dev_priv->uncore.funcs.force_wake_put =
+ fw_domains_put_with_fifo;
+
+ /* We need to init first for ECOBUS access and then
+ * determine later if we want to reinit, in case of MT access is
+ * not working
+ */
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE_MT, FORCEWAKE_MT_ACK);
+
mutex_lock(&dev->struct_mutex);
- __gen7_gt_force_wake_mt_get(dev_priv, FORCEWAKE_ALL);
+ fw_domains_get_with_thread_status(dev_priv, FORCEWAKE_ALL);
ecobus = __raw_i915_read32(dev_priv, ECOBUS);
- __gen7_gt_force_wake_mt_put(dev_priv, FORCEWAKE_ALL);
+ fw_domains_put_with_fifo(dev_priv, FORCEWAKE_ALL);
mutex_unlock(&dev->struct_mutex);
- if (ecobus & FORCEWAKE_MT_ENABLE) {
- dev_priv->uncore.funcs.force_wake_get =
- __gen7_gt_force_wake_mt_get;
- dev_priv->uncore.funcs.force_wake_put =
- __gen7_gt_force_wake_mt_put;
- } else {
+ if (!(ecobus & FORCEWAKE_MT_ENABLE)) {
DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
DRM_INFO("when using vblank-synced partial screen updates.\n");
- dev_priv->uncore.funcs.force_wake_get =
- __gen6_gt_force_wake_get;
- dev_priv->uncore.funcs.force_wake_put =
- __gen6_gt_force_wake_put;
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE, FORCEWAKE_ACK);
}
} else if (IS_GEN6(dev)) {
dev_priv->uncore.funcs.force_wake_get =
- __gen6_gt_force_wake_get;
+ fw_domains_get_with_thread_status;
dev_priv->uncore.funcs.force_wake_put =
- __gen6_gt_force_wake_put;
+ fw_domains_put_with_fifo;
+ fw_domain_init(dev_priv, FW_DOMAIN_ID_RENDER,
+ FORCEWAKE, FORCEWAKE_ACK);
}
+ /* All future platforms are expected to require complex power gating */
+ WARN_ON(dev_priv->uncore.fw_domains == 0);
+}
+
+void intel_uncore_init(struct drm_device *dev)
+{
+ struct drm_i915_private *dev_priv = dev->dev_private;
+
+ intel_uncore_ellc_detect(dev);
+ intel_uncore_fw_domains_init(dev);
+ __intel_uncore_early_sanitize(dev, false);
+
switch (INTEL_INFO(dev)->gen) {
default:
- WARN_ON(1);
+ MISSING_CASE(INTEL_INFO(dev)->gen);
return;
case 9:
ASSIGN_WRITE_MMIO_VFUNCS(gen9);
@@ -1239,8 +1125,8 @@ void intel_uncore_init(struct drm_device *dev)
case 4:
case 3:
case 2:
- ASSIGN_WRITE_MMIO_VFUNCS(gen4);
- ASSIGN_READ_MMIO_VFUNCS(gen4);
+ ASSIGN_WRITE_MMIO_VFUNCS(gen2);
+ ASSIGN_READ_MMIO_VFUNCS(gen2);
break;
}
@@ -1300,7 +1186,7 @@ int i915_reg_read_ioctl(struct drm_device *dev,
reg->val = I915_READ8(reg->offset);
break;
default:
- WARN_ON(1);
+ MISSING_CASE(entry->size);
ret = -EINVAL;
goto out;
}
diff --git a/drivers/gpu/drm/imx/Kconfig b/drivers/gpu/drm/imx/Kconfig
index ab31848e92cf..33cdddf26684 100644
--- a/drivers/gpu/drm/imx/Kconfig
+++ b/drivers/gpu/drm/imx/Kconfig
@@ -5,7 +5,7 @@ config DRM_IMX
select VIDEOMODE_HELPERS
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
- depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM)
+ depends on DRM && (ARCH_MXC || ARCH_MULTIPLATFORM) && HAVE_DMA_ATTRS
depends on IMX_IPUV3_CORE
help
enable i.MX graphics support
@@ -49,6 +49,7 @@ config DRM_IMX_IPUV3
config DRM_IMX_HDMI
tristate "Freescale i.MX DRM HDMI"
+ select DRM_DW_HDMI
depends on DRM_IMX
help
Choose this if you want to use HDMI on i.MX6.
diff --git a/drivers/gpu/drm/imx/Makefile b/drivers/gpu/drm/imx/Makefile
index 582c438d8cbd..f3ecd8903d97 100644
--- a/drivers/gpu/drm/imx/Makefile
+++ b/drivers/gpu/drm/imx/Makefile
@@ -9,4 +9,4 @@ obj-$(CONFIG_DRM_IMX_LDB) += imx-ldb.o
imx-ipuv3-crtc-objs := ipuv3-crtc.o ipuv3-plane.o
obj-$(CONFIG_DRM_IMX_IPUV3) += imx-ipuv3-crtc.o
-obj-$(CONFIG_DRM_IMX_HDMI) += imx-hdmi.o
+obj-$(CONFIG_DRM_IMX_HDMI) += dw_hdmi-imx.o
diff --git a/drivers/gpu/drm/imx/dw_hdmi-imx.c b/drivers/gpu/drm/imx/dw_hdmi-imx.c
new file mode 100644
index 000000000000..121d30ca2d44
--- /dev/null
+++ b/drivers/gpu/drm/imx/dw_hdmi-imx.c
@@ -0,0 +1,258 @@
+/* Copyright (C) 2011-2013 Freescale Semiconductor, Inc.
+ *
+ * derived from imx-hdmi.c(renamed to bridge/dw_hdmi.c now)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/component.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
+#include <drm/bridge/dw_hdmi.h>
+#include <video/imx-ipu-v3.h>
+#include <linux/regmap.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+
+#include "imx-drm.h"
+
+struct imx_hdmi {
+ struct device *dev;
+ struct drm_encoder encoder;
+ struct regmap *regmap;
+};
+
+static const struct dw_hdmi_mpll_config imx_mpll_cfg[] = {
+ {
+ 45250000, {
+ { 0x01e0, 0x0000 },
+ { 0x21e1, 0x0000 },
+ { 0x41e2, 0x0000 }
+ },
+ }, {
+ 92500000, {
+ { 0x0140, 0x0005 },
+ { 0x2141, 0x0005 },
+ { 0x4142, 0x0005 },
+ },
+ }, {
+ 148500000, {
+ { 0x00a0, 0x000a },
+ { 0x20a1, 0x000a },
+ { 0x40a2, 0x000a },
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+static const struct dw_hdmi_curr_ctrl imx_cur_ctr[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ {
+ 54000000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 58400000, { 0x091c, 0x06dc, 0x06dc },
+ }, {
+ 72000000, { 0x06dc, 0x06dc, 0x091c },
+ }, {
+ 74250000, { 0x06dc, 0x0b5c, 0x091c },
+ }, {
+ 118800000, { 0x091c, 0x091c, 0x06dc },
+ }, {
+ 216000000, { 0x06dc, 0x0b5c, 0x091c },
+ }
+};
+
+static const struct dw_hdmi_sym_term imx_sym_term[] = {
+ /*pixelclk symbol term*/
+ { 148500000, 0x800d, 0x0005 },
+ { ~0UL, 0x0000, 0x0000 }
+};
+
+static int dw_hdmi_imx_parse_dt(struct imx_hdmi *hdmi)
+{
+ struct device_node *np = hdmi->dev->of_node;
+
+ hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
+ if (IS_ERR(hdmi->regmap)) {
+ dev_err(hdmi->dev, "Unable to get gpr\n");
+ return PTR_ERR(hdmi->regmap);
+ }
+
+ return 0;
+}
+
+static void dw_hdmi_imx_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool dw_hdmi_imx_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_imx_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+}
+
+static void dw_hdmi_imx_encoder_commit(struct drm_encoder *encoder)
+{
+ struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
+ int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
+
+ regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
+ IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
+ mux << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
+}
+
+static void dw_hdmi_imx_encoder_prepare(struct drm_encoder *encoder)
+{
+ imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
+}
+
+static struct drm_encoder_helper_funcs dw_hdmi_imx_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_imx_encoder_mode_fixup,
+ .mode_set = dw_hdmi_imx_encoder_mode_set,
+ .prepare = dw_hdmi_imx_encoder_prepare,
+ .commit = dw_hdmi_imx_encoder_commit,
+ .disable = dw_hdmi_imx_encoder_disable,
+};
+
+static struct drm_encoder_funcs dw_hdmi_imx_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static struct dw_hdmi_plat_data imx6q_hdmi_drv_data = {
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .sym_term = imx_sym_term,
+ .dev_type = IMX6Q_HDMI,
+};
+
+static struct dw_hdmi_plat_data imx6dl_hdmi_drv_data = {
+ .mpll_cfg = imx_mpll_cfg,
+ .cur_ctr = imx_cur_ctr,
+ .sym_term = imx_sym_term,
+ .dev_type = IMX6DL_HDMI,
+};
+
+static const struct of_device_id dw_hdmi_imx_dt_ids[] = {
+ { .compatible = "fsl,imx6q-hdmi",
+ .data = &imx6q_hdmi_drv_data
+ }, {
+ .compatible = "fsl,imx6dl-hdmi",
+ .data = &imx6dl_hdmi_drv_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_hdmi_imx_dt_ids);
+
+static int dw_hdmi_imx_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct dw_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+ struct drm_device *drm = data;
+ struct drm_encoder *encoder;
+ struct imx_hdmi *hdmi;
+ struct resource *iores;
+ int irq;
+ int ret;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ match = of_match_node(dw_hdmi_imx_dt_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores)
+ return -ENXIO;
+
+ platform_set_drvdata(pdev, hdmi);
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (encoder->possible_crtcs == 0)
+ return -EPROBE_DEFER;
+
+ ret = dw_hdmi_imx_parse_dt(hdmi);
+ if (ret < 0)
+ return ret;
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_imx_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_imx_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+}
+
+static void dw_hdmi_imx_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ return dw_hdmi_unbind(dev, master, data);
+}
+
+static const struct component_ops dw_hdmi_imx_ops = {
+ .bind = dw_hdmi_imx_bind,
+ .unbind = dw_hdmi_imx_unbind,
+};
+
+static int dw_hdmi_imx_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &dw_hdmi_imx_ops);
+}
+
+static int dw_hdmi_imx_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dw_hdmi_imx_ops);
+
+ return 0;
+}
+
+static struct platform_driver dw_hdmi_imx_platform_driver = {
+ .probe = dw_hdmi_imx_probe,
+ .remove = dw_hdmi_imx_remove,
+ .driver = {
+ .name = "dwhdmi-imx",
+ .of_match_table = dw_hdmi_imx_dt_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_imx_platform_driver);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("IMX6 Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-imx");
diff --git a/drivers/gpu/drm/imx/imx-drm-core.c b/drivers/gpu/drm/imx/imx-drm-core.c
index b250130debc8..a002f53aab0e 100644
--- a/drivers/gpu/drm/imx/imx-drm-core.c
+++ b/drivers/gpu/drm/imx/imx-drm-core.c
@@ -25,6 +25,7 @@
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_plane_helper.h>
+#include <drm/drm_of.h>
#include "imx-drm.h"
@@ -46,7 +47,6 @@ struct imx_drm_crtc {
struct drm_crtc *crtc;
int pipe;
struct imx_drm_crtc_helper_funcs imx_drm_helper_funcs;
- struct device_node *port;
};
static int legacyfb_depth = 16;
@@ -116,8 +116,7 @@ int imx_drm_panel_format_pins(struct drm_encoder *encoder,
helper = &imx_crtc->imx_drm_helper_funcs;
if (helper->set_interface_pix_fmt)
return helper->set_interface_pix_fmt(encoder->crtc,
- encoder->encoder_type, interface_pix_fmt,
- hsync_pin, vsync_pin);
+ interface_pix_fmt, hsync_pin, vsync_pin);
return 0;
}
EXPORT_SYMBOL_GPL(imx_drm_panel_format_pins);
@@ -365,9 +364,10 @@ int imx_drm_add_crtc(struct drm_device *drm, struct drm_crtc *crtc,
imx_drm_crtc->imx_drm_helper_funcs = *imx_drm_helper_funcs;
imx_drm_crtc->pipe = imxdrm->pipes++;
- imx_drm_crtc->port = port;
imx_drm_crtc->crtc = crtc;
+ crtc->port = port;
+
imxdrm->crtc[imx_drm_crtc->pipe] = imx_drm_crtc;
*new_crtc = imx_drm_crtc;
@@ -408,33 +408,28 @@ int imx_drm_remove_crtc(struct imx_drm_crtc *imx_drm_crtc)
}
EXPORT_SYMBOL_GPL(imx_drm_remove_crtc);
-/*
- * Find the DRM CRTC possible mask for the connected endpoint.
- *
- * The encoder possible masks are defined by their position in the
- * mode_config crtc_list. This means that CRTCs must not be added
- * or removed once the DRM device has been fully initialised.
- */
-static uint32_t imx_drm_find_crtc_mask(struct imx_drm_device *imxdrm,
- struct device_node *endpoint)
+int imx_drm_encoder_parse_of(struct drm_device *drm,
+ struct drm_encoder *encoder, struct device_node *np)
{
- struct device_node *port;
- unsigned i;
+ uint32_t crtc_mask = drm_of_find_possible_crtcs(drm, np);
- port = of_graph_get_remote_port(endpoint);
- if (!port)
- return 0;
- of_node_put(port);
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (crtc_mask == 0)
+ return -EPROBE_DEFER;
- for (i = 0; i < MAX_CRTC; i++) {
- struct imx_drm_crtc *imx_drm_crtc = imxdrm->crtc[i];
+ encoder->possible_crtcs = crtc_mask;
- if (imx_drm_crtc && imx_drm_crtc->port == port)
- return drm_crtc_mask(imx_drm_crtc->crtc);
- }
+ /* FIXME: this is the mask of outputs which can clone this output. */
+ encoder->possible_clones = ~0;
return 0;
}
+EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
static struct device_node *imx_drm_of_get_next_endpoint(
const struct device_node *parent, struct device_node *prev)
@@ -445,48 +440,6 @@ static struct device_node *imx_drm_of_get_next_endpoint(
return node;
}
-int imx_drm_encoder_parse_of(struct drm_device *drm,
- struct drm_encoder *encoder, struct device_node *np)
-{
- struct imx_drm_device *imxdrm = drm->dev_private;
- struct device_node *ep = NULL;
- uint32_t crtc_mask = 0;
- int i;
-
- for (i = 0; ; i++) {
- u32 mask;
-
- ep = imx_drm_of_get_next_endpoint(np, ep);
- if (!ep)
- break;
-
- mask = imx_drm_find_crtc_mask(imxdrm, ep);
-
- /*
- * If we failed to find the CRTC(s) which this encoder is
- * supposed to be connected to, it's because the CRTC has
- * not been registered yet. Defer probing, and hope that
- * the required CRTC is added later.
- */
- if (mask == 0)
- return -EPROBE_DEFER;
-
- crtc_mask |= mask;
- }
-
- of_node_put(ep);
- if (i == 0)
- return -ENOENT;
-
- encoder->possible_crtcs = crtc_mask;
-
- /* FIXME: this is the mask of outputs which can clone this output. */
- encoder->possible_clones = ~0;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(imx_drm_encoder_parse_of);
-
/*
* @node: device tree node containing encoder input ports
* @encoder: drm_encoder
@@ -510,7 +463,7 @@ int imx_drm_encoder_get_mux_id(struct device_node *node,
port = of_graph_get_remote_port(ep);
of_node_put(port);
- if (port == imx_crtc->port) {
+ if (port == imx_crtc->crtc->port) {
ret = of_graph_parse_endpoint(ep, &endpoint);
return ret ? ret : endpoint.port;
}
diff --git a/drivers/gpu/drm/imx/imx-drm.h b/drivers/gpu/drm/imx/imx-drm.h
index 7453ae00c412..3c559ccd6af0 100644
--- a/drivers/gpu/drm/imx/imx-drm.h
+++ b/drivers/gpu/drm/imx/imx-drm.h
@@ -17,7 +17,7 @@ int imx_drm_crtc_id(struct imx_drm_crtc *crtc);
struct imx_drm_crtc_helper_funcs {
int (*enable_vblank)(struct drm_crtc *crtc);
void (*disable_vblank)(struct drm_crtc *crtc);
- int (*set_interface_pix_fmt)(struct drm_crtc *crtc, u32 encoder_type,
+ int (*set_interface_pix_fmt)(struct drm_crtc *crtc,
u32 pix_fmt, int hsync_pin, int vsync_pin);
const struct drm_crtc_helper_funcs *crtc_helper_funcs;
const struct drm_crtc_funcs *crtc_funcs;
diff --git a/drivers/gpu/drm/imx/imx-hdmi.c b/drivers/gpu/drm/imx/imx-hdmi.c
deleted file mode 100644
index ddc53e039530..000000000000
--- a/drivers/gpu/drm/imx/imx-hdmi.c
+++ /dev/null
@@ -1,1766 +0,0 @@
-/*
- * Copyright (C) 2011-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.
- *
- * SH-Mobile High-Definition Multimedia Interface (HDMI) driver
- * for SLISHDMI13T and SLIPHDMIT IP cores
- *
- * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
- */
-
-#include <linux/component.h>
-#include <linux/irq.h>
-#include <linux/delay.h>
-#include <linux/err.h>
-#include <linux/clk.h>
-#include <linux/hdmi.h>
-#include <linux/regmap.h>
-#include <linux/mfd/syscon.h>
-#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
-#include <linux/of_device.h>
-
-#include <drm/drmP.h>
-#include <drm/drm_crtc_helper.h>
-#include <drm/drm_edid.h>
-#include <drm/drm_encoder_slave.h>
-#include <video/imx-ipu-v3.h>
-
-#include "imx-hdmi.h"
-#include "imx-drm.h"
-
-#define HDMI_EDID_LEN 512
-
-#define RGB 0
-#define YCBCR444 1
-#define YCBCR422_16BITS 2
-#define YCBCR422_8BITS 3
-#define XVYCC444 4
-
-enum hdmi_datamap {
- RGB444_8B = 0x01,
- RGB444_10B = 0x03,
- RGB444_12B = 0x05,
- RGB444_16B = 0x07,
- YCbCr444_8B = 0x09,
- YCbCr444_10B = 0x0B,
- YCbCr444_12B = 0x0D,
- YCbCr444_16B = 0x0F,
- YCbCr422_8B = 0x16,
- YCbCr422_10B = 0x14,
- YCbCr422_12B = 0x12,
-};
-
-enum imx_hdmi_devtype {
- IMX6Q_HDMI,
- IMX6DL_HDMI,
-};
-
-static const u16 csc_coeff_default[3][4] = {
- { 0x2000, 0x0000, 0x0000, 0x0000 },
- { 0x0000, 0x2000, 0x0000, 0x0000 },
- { 0x0000, 0x0000, 0x2000, 0x0000 }
-};
-
-static const u16 csc_coeff_rgb_out_eitu601[3][4] = {
- { 0x2000, 0x6926, 0x74fd, 0x010e },
- { 0x2000, 0x2cdd, 0x0000, 0x7e9a },
- { 0x2000, 0x0000, 0x38b4, 0x7e3b }
-};
-
-static const u16 csc_coeff_rgb_out_eitu709[3][4] = {
- { 0x2000, 0x7106, 0x7a02, 0x00a7 },
- { 0x2000, 0x3264, 0x0000, 0x7e6d },
- { 0x2000, 0x0000, 0x3b61, 0x7e25 }
-};
-
-static const u16 csc_coeff_rgb_in_eitu601[3][4] = {
- { 0x2591, 0x1322, 0x074b, 0x0000 },
- { 0x6535, 0x2000, 0x7acc, 0x0200 },
- { 0x6acd, 0x7534, 0x2000, 0x0200 }
-};
-
-static const u16 csc_coeff_rgb_in_eitu709[3][4] = {
- { 0x2dc5, 0x0d9b, 0x049e, 0x0000 },
- { 0x62f0, 0x2000, 0x7d11, 0x0200 },
- { 0x6756, 0x78ab, 0x2000, 0x0200 }
-};
-
-struct hdmi_vmode {
- bool mdvi;
- bool mhsyncpolarity;
- bool mvsyncpolarity;
- bool minterlaced;
- bool mdataenablepolarity;
-
- unsigned int mpixelclock;
- unsigned int mpixelrepetitioninput;
- unsigned int mpixelrepetitionoutput;
-};
-
-struct hdmi_data_info {
- unsigned int enc_in_format;
- unsigned int enc_out_format;
- unsigned int enc_color_depth;
- unsigned int colorimetry;
- unsigned int pix_repet_factor;
- unsigned int hdcp_enable;
- struct hdmi_vmode video_mode;
-};
-
-struct imx_hdmi {
- struct drm_connector connector;
- struct drm_encoder encoder;
-
- enum imx_hdmi_devtype dev_type;
- struct device *dev;
- struct clk *isfr_clk;
- struct clk *iahb_clk;
-
- struct hdmi_data_info hdmi_data;
- int vic;
-
- u8 edid[HDMI_EDID_LEN];
- bool cable_plugin;
-
- bool phy_enabled;
- struct drm_display_mode previous_mode;
-
- struct regmap *regmap;
- struct i2c_adapter *ddc;
- void __iomem *regs;
-
- unsigned int sample_rate;
- int ratio;
-};
-
-static void imx_hdmi_set_ipu_di_mux(struct imx_hdmi *hdmi, int ipu_di)
-{
- regmap_update_bits(hdmi->regmap, IOMUXC_GPR3,
- IMX6Q_GPR3_HDMI_MUX_CTL_MASK,
- ipu_di << IMX6Q_GPR3_HDMI_MUX_CTL_SHIFT);
-}
-
-static inline void hdmi_writeb(struct imx_hdmi *hdmi, u8 val, int offset)
-{
- writeb(val, hdmi->regs + offset);
-}
-
-static inline u8 hdmi_readb(struct imx_hdmi *hdmi, int offset)
-{
- return readb(hdmi->regs + offset);
-}
-
-static void hdmi_modb(struct imx_hdmi *hdmi, u8 data, u8 mask, unsigned reg)
-{
- u8 val = hdmi_readb(hdmi, reg) & ~mask;
-
- val |= data & mask;
- hdmi_writeb(hdmi, val, reg);
-}
-
-static void hdmi_mask_writeb(struct imx_hdmi *hdmi, u8 data, unsigned int reg,
- u8 shift, u8 mask)
-{
- hdmi_modb(hdmi, data << shift, mask, reg);
-}
-
-static void hdmi_set_clock_regenerator_n(struct imx_hdmi *hdmi,
- unsigned int value)
-{
- hdmi_writeb(hdmi, value & 0xff, HDMI_AUD_N1);
- hdmi_writeb(hdmi, (value >> 8) & 0xff, HDMI_AUD_N2);
- hdmi_writeb(hdmi, (value >> 16) & 0x0f, HDMI_AUD_N3);
-
- /* nshift factor = 0 */
- hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_N_SHIFT_MASK, HDMI_AUD_CTS3);
-}
-
-static void hdmi_regenerate_cts(struct imx_hdmi *hdmi, unsigned int cts)
-{
- /* Must be set/cleared first */
- hdmi_modb(hdmi, 0, HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-
- hdmi_writeb(hdmi, cts & 0xff, HDMI_AUD_CTS1);
- hdmi_writeb(hdmi, (cts >> 8) & 0xff, HDMI_AUD_CTS2);
- hdmi_writeb(hdmi, ((cts >> 16) & HDMI_AUD_CTS3_AUDCTS19_16_MASK) |
- HDMI_AUD_CTS3_CTS_MANUAL, HDMI_AUD_CTS3);
-}
-
-static unsigned int hdmi_compute_n(unsigned int freq, unsigned long pixel_clk,
- unsigned int ratio)
-{
- unsigned int n = (128 * freq) / 1000;
-
- switch (freq) {
- case 32000:
- if (pixel_clk == 25170000)
- n = (ratio == 150) ? 9152 : 4576;
- else if (pixel_clk == 27020000)
- n = (ratio == 150) ? 8192 : 4096;
- else if (pixel_clk == 74170000 || pixel_clk == 148350000)
- n = 11648;
- else
- n = 4096;
- break;
-
- case 44100:
- if (pixel_clk == 25170000)
- n = 7007;
- else if (pixel_clk == 74170000)
- n = 17836;
- else if (pixel_clk == 148350000)
- n = (ratio == 150) ? 17836 : 8918;
- else
- n = 6272;
- break;
-
- case 48000:
- if (pixel_clk == 25170000)
- n = (ratio == 150) ? 9152 : 6864;
- else if (pixel_clk == 27020000)
- n = (ratio == 150) ? 8192 : 6144;
- else if (pixel_clk == 74170000)
- n = 11648;
- else if (pixel_clk == 148350000)
- n = (ratio == 150) ? 11648 : 5824;
- else
- n = 6144;
- break;
-
- case 88200:
- n = hdmi_compute_n(44100, pixel_clk, ratio) * 2;
- break;
-
- case 96000:
- n = hdmi_compute_n(48000, pixel_clk, ratio) * 2;
- break;
-
- case 176400:
- n = hdmi_compute_n(44100, pixel_clk, ratio) * 4;
- break;
-
- case 192000:
- n = hdmi_compute_n(48000, pixel_clk, ratio) * 4;
- break;
-
- default:
- break;
- }
-
- return n;
-}
-
-static unsigned int hdmi_compute_cts(unsigned int freq, unsigned long pixel_clk,
- unsigned int ratio)
-{
- unsigned int cts = 0;
-
- pr_debug("%s: freq: %d pixel_clk: %ld ratio: %d\n", __func__, freq,
- pixel_clk, ratio);
-
- switch (freq) {
- case 32000:
- if (pixel_clk == 297000000) {
- cts = 222750;
- break;
- }
- case 48000:
- case 96000:
- case 192000:
- switch (pixel_clk) {
- case 25200000:
- case 27000000:
- case 54000000:
- case 74250000:
- case 148500000:
- cts = pixel_clk / 1000;
- break;
- case 297000000:
- cts = 247500;
- break;
- /*
- * All other TMDS clocks are not supported by
- * DWC_hdmi_tx. The TMDS clocks divided or
- * multiplied by 1,001 coefficients are not
- * supported.
- */
- default:
- break;
- }
- break;
- case 44100:
- case 88200:
- case 176400:
- switch (pixel_clk) {
- case 25200000:
- cts = 28000;
- break;
- case 27000000:
- cts = 30000;
- break;
- case 54000000:
- cts = 60000;
- break;
- case 74250000:
- cts = 82500;
- break;
- case 148500000:
- cts = 165000;
- break;
- case 297000000:
- cts = 247500;
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
- if (ratio == 100)
- return cts;
- return (cts * ratio) / 100;
-}
-
-static void hdmi_set_clk_regenerator(struct imx_hdmi *hdmi,
- unsigned long pixel_clk)
-{
- unsigned int clk_n, clk_cts;
-
- clk_n = hdmi_compute_n(hdmi->sample_rate, pixel_clk,
- hdmi->ratio);
- clk_cts = hdmi_compute_cts(hdmi->sample_rate, pixel_clk,
- hdmi->ratio);
-
- if (!clk_cts) {
- dev_dbg(hdmi->dev, "%s: pixel clock not supported: %lu\n",
- __func__, pixel_clk);
- return;
- }
-
- dev_dbg(hdmi->dev, "%s: samplerate=%d ratio=%d pixelclk=%lu N=%d cts=%d\n",
- __func__, hdmi->sample_rate, hdmi->ratio,
- pixel_clk, clk_n, clk_cts);
-
- hdmi_set_clock_regenerator_n(hdmi, clk_n);
- hdmi_regenerate_cts(hdmi, clk_cts);
-}
-
-static void hdmi_init_clk_regenerator(struct imx_hdmi *hdmi)
-{
- hdmi_set_clk_regenerator(hdmi, 74250000);
-}
-
-static void hdmi_clk_regenerator_update_pixel_clock(struct imx_hdmi *hdmi)
-{
- hdmi_set_clk_regenerator(hdmi, hdmi->hdmi_data.video_mode.mpixelclock);
-}
-
-/*
- * this submodule is responsible for the video data synchronization.
- * for example, for RGB 4:4:4 input, the data map is defined as
- * pin{47~40} <==> R[7:0]
- * pin{31~24} <==> G[7:0]
- * pin{15~8} <==> B[7:0]
- */
-static void hdmi_video_sample(struct imx_hdmi *hdmi)
-{
- int color_format = 0;
- u8 val;
-
- if (hdmi->hdmi_data.enc_in_format == RGB) {
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_format = 0x01;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_format = 0x03;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_format = 0x05;
- else if (hdmi->hdmi_data.enc_color_depth == 16)
- color_format = 0x07;
- else
- return;
- } else if (hdmi->hdmi_data.enc_in_format == YCBCR444) {
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_format = 0x09;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_format = 0x0B;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_format = 0x0D;
- else if (hdmi->hdmi_data.enc_color_depth == 16)
- color_format = 0x0F;
- else
- return;
- } else if (hdmi->hdmi_data.enc_in_format == YCBCR422_8BITS) {
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_format = 0x16;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_format = 0x14;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_format = 0x12;
- else
- return;
- }
-
- val = HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE |
- ((color_format << HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET) &
- HDMI_TX_INVID0_VIDEO_MAPPING_MASK);
- hdmi_writeb(hdmi, val, HDMI_TX_INVID0);
-
- /* Enable TX stuffing: When DE is inactive, fix the output data to 0 */
- val = HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE |
- HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE |
- HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE;
- hdmi_writeb(hdmi, val, HDMI_TX_INSTUFFING);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA0);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_GYDATA1);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA0);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_RCRDATA1);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA0);
- hdmi_writeb(hdmi, 0x0, HDMI_TX_BCBDATA1);
-}
-
-static int is_color_space_conversion(struct imx_hdmi *hdmi)
-{
- return hdmi->hdmi_data.enc_in_format != hdmi->hdmi_data.enc_out_format;
-}
-
-static int is_color_space_decimation(struct imx_hdmi *hdmi)
-{
- if (hdmi->hdmi_data.enc_out_format != YCBCR422_8BITS)
- return 0;
- if (hdmi->hdmi_data.enc_in_format == RGB ||
- hdmi->hdmi_data.enc_in_format == YCBCR444)
- return 1;
- return 0;
-}
-
-static int is_color_space_interpolation(struct imx_hdmi *hdmi)
-{
- if (hdmi->hdmi_data.enc_in_format != YCBCR422_8BITS)
- return 0;
- if (hdmi->hdmi_data.enc_out_format == RGB ||
- hdmi->hdmi_data.enc_out_format == YCBCR444)
- return 1;
- return 0;
-}
-
-static void imx_hdmi_update_csc_coeffs(struct imx_hdmi *hdmi)
-{
- const u16 (*csc_coeff)[3][4] = &csc_coeff_default;
- unsigned i;
- u32 csc_scale = 1;
-
- if (is_color_space_conversion(hdmi)) {
- if (hdmi->hdmi_data.enc_out_format == RGB) {
- if (hdmi->hdmi_data.colorimetry ==
- HDMI_COLORIMETRY_ITU_601)
- csc_coeff = &csc_coeff_rgb_out_eitu601;
- else
- csc_coeff = &csc_coeff_rgb_out_eitu709;
- } else if (hdmi->hdmi_data.enc_in_format == RGB) {
- if (hdmi->hdmi_data.colorimetry ==
- HDMI_COLORIMETRY_ITU_601)
- csc_coeff = &csc_coeff_rgb_in_eitu601;
- else
- csc_coeff = &csc_coeff_rgb_in_eitu709;
- csc_scale = 0;
- }
- }
-
- /* The CSC registers are sequential, alternating MSB then LSB */
- for (i = 0; i < ARRAY_SIZE(csc_coeff_default[0]); i++) {
- u16 coeff_a = (*csc_coeff)[0][i];
- u16 coeff_b = (*csc_coeff)[1][i];
- u16 coeff_c = (*csc_coeff)[2][i];
-
- hdmi_writeb(hdmi, coeff_a & 0xff,
- HDMI_CSC_COEF_A1_LSB + i * 2);
- hdmi_writeb(hdmi, coeff_a >> 8, HDMI_CSC_COEF_A1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_b & 0xff, HDMI_CSC_COEF_B1_LSB + i * 2);
- hdmi_writeb(hdmi, coeff_b >> 8, HDMI_CSC_COEF_B1_MSB + i * 2);
- hdmi_writeb(hdmi, coeff_c & 0xff,
- HDMI_CSC_COEF_C1_LSB + i * 2);
- hdmi_writeb(hdmi, coeff_c >> 8, HDMI_CSC_COEF_C1_MSB + i * 2);
- }
-
- hdmi_modb(hdmi, csc_scale, HDMI_CSC_SCALE_CSCSCALE_MASK,
- HDMI_CSC_SCALE);
-}
-
-static void hdmi_video_csc(struct imx_hdmi *hdmi)
-{
- int color_depth = 0;
- int interpolation = HDMI_CSC_CFG_INTMODE_DISABLE;
- int decimation = 0;
-
- /* YCC422 interpolation to 444 mode */
- if (is_color_space_interpolation(hdmi))
- interpolation = HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1;
- else if (is_color_space_decimation(hdmi))
- decimation = HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3;
-
- if (hdmi->hdmi_data.enc_color_depth == 8)
- color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP;
- else if (hdmi->hdmi_data.enc_color_depth == 10)
- color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP;
- else if (hdmi->hdmi_data.enc_color_depth == 12)
- color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP;
- else if (hdmi->hdmi_data.enc_color_depth == 16)
- color_depth = HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP;
- else
- return;
-
- /* Configure the CSC registers */
- hdmi_writeb(hdmi, interpolation | decimation, HDMI_CSC_CFG);
- hdmi_modb(hdmi, color_depth, HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK,
- HDMI_CSC_SCALE);
-
- imx_hdmi_update_csc_coeffs(hdmi);
-}
-
-/*
- * HDMI video packetizer is used to packetize the data.
- * for example, if input is YCC422 mode or repeater is used,
- * data should be repacked this module can be bypassed.
- */
-static void hdmi_video_packetize(struct imx_hdmi *hdmi)
-{
- unsigned int color_depth = 0;
- unsigned int remap_size = HDMI_VP_REMAP_YCC422_16bit;
- unsigned int output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_PP;
- struct hdmi_data_info *hdmi_data = &hdmi->hdmi_data;
- u8 val, vp_conf;
-
- if (hdmi_data->enc_out_format == RGB
- || hdmi_data->enc_out_format == YCBCR444) {
- if (!hdmi_data->enc_color_depth)
- output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- else if (hdmi_data->enc_color_depth == 8) {
- color_depth = 4;
- output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS;
- } else if (hdmi_data->enc_color_depth == 10)
- color_depth = 5;
- else if (hdmi_data->enc_color_depth == 12)
- color_depth = 6;
- else if (hdmi_data->enc_color_depth == 16)
- color_depth = 7;
- else
- return;
- } else if (hdmi_data->enc_out_format == YCBCR422_8BITS) {
- if (!hdmi_data->enc_color_depth ||
- hdmi_data->enc_color_depth == 8)
- remap_size = HDMI_VP_REMAP_YCC422_16bit;
- else if (hdmi_data->enc_color_depth == 10)
- remap_size = HDMI_VP_REMAP_YCC422_20bit;
- else if (hdmi_data->enc_color_depth == 12)
- remap_size = HDMI_VP_REMAP_YCC422_24bit;
- else
- return;
- output_select = HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422;
- } else
- return;
-
- /* set the packetizer registers */
- val = ((color_depth << HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET) &
- HDMI_VP_PR_CD_COLOR_DEPTH_MASK) |
- ((hdmi_data->pix_repet_factor <<
- HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET) &
- HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK);
- hdmi_writeb(hdmi, val, HDMI_VP_PR_CD);
-
- hdmi_modb(hdmi, HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE,
- HDMI_VP_STUFF_PR_STUFFING_MASK, HDMI_VP_STUFF);
-
- /* Data from pixel repeater block */
- if (hdmi_data->pix_repet_factor > 1) {
- vp_conf = HDMI_VP_CONF_PR_EN_ENABLE |
- HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER;
- } else { /* data from packetizer block */
- vp_conf = HDMI_VP_CONF_PR_EN_DISABLE |
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER;
- }
-
- hdmi_modb(hdmi, vp_conf,
- HDMI_VP_CONF_PR_EN_MASK |
- HDMI_VP_CONF_BYPASS_SELECT_MASK, HDMI_VP_CONF);
-
- hdmi_modb(hdmi, 1 << HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET,
- HDMI_VP_STUFF_IDEFAULT_PHASE_MASK, HDMI_VP_STUFF);
-
- hdmi_writeb(hdmi, remap_size, HDMI_VP_REMAP);
-
- if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_PP) {
- vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_ENABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422) {
- vp_conf = HDMI_VP_CONF_BYPASS_EN_DISABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_ENABLE;
- } else if (output_select == HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS) {
- vp_conf = HDMI_VP_CONF_BYPASS_EN_ENABLE |
- HDMI_VP_CONF_PP_EN_DISABLE |
- HDMI_VP_CONF_YCC422_EN_DISABLE;
- } else {
- return;
- }
-
- hdmi_modb(hdmi, vp_conf,
- HDMI_VP_CONF_BYPASS_EN_MASK | HDMI_VP_CONF_PP_EN_ENMASK |
- HDMI_VP_CONF_YCC422_EN_MASK, HDMI_VP_CONF);
-
- hdmi_modb(hdmi, HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE |
- HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE,
- HDMI_VP_STUFF_PP_STUFFING_MASK |
- HDMI_VP_STUFF_YCC422_STUFFING_MASK, HDMI_VP_STUFF);
-
- hdmi_modb(hdmi, output_select, HDMI_VP_CONF_OUTPUT_SELECTOR_MASK,
- HDMI_VP_CONF);
-}
-
-static inline void hdmi_phy_test_clear(struct imx_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLR_OFFSET,
- HDMI_PHY_TST0_TSTCLR_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_enable(struct imx_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTEN_OFFSET,
- HDMI_PHY_TST0_TSTEN_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_clock(struct imx_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_modb(hdmi, bit << HDMI_PHY_TST0_TSTCLK_OFFSET,
- HDMI_PHY_TST0_TSTCLK_MASK, HDMI_PHY_TST0);
-}
-
-static inline void hdmi_phy_test_din(struct imx_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_writeb(hdmi, bit, HDMI_PHY_TST1);
-}
-
-static inline void hdmi_phy_test_dout(struct imx_hdmi *hdmi,
- unsigned char bit)
-{
- hdmi_writeb(hdmi, bit, HDMI_PHY_TST2);
-}
-
-static bool hdmi_phy_wait_i2c_done(struct imx_hdmi *hdmi, int msec)
-{
- while ((hdmi_readb(hdmi, HDMI_IH_I2CMPHY_STAT0) & 0x3) == 0) {
- if (msec-- == 0)
- return false;
- udelay(1000);
- }
- return true;
-}
-
-static void __hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
-{
- hdmi_writeb(hdmi, 0xFF, HDMI_IH_I2CMPHY_STAT0);
- hdmi_writeb(hdmi, addr, HDMI_PHY_I2CM_ADDRESS_ADDR);
- hdmi_writeb(hdmi, (unsigned char)(data >> 8),
- HDMI_PHY_I2CM_DATAO_1_ADDR);
- hdmi_writeb(hdmi, (unsigned char)(data >> 0),
- HDMI_PHY_I2CM_DATAO_0_ADDR);
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_OPERATION_ADDR_WRITE,
- HDMI_PHY_I2CM_OPERATION_ADDR);
- hdmi_phy_wait_i2c_done(hdmi, 1000);
-}
-
-static int hdmi_phy_i2c_write(struct imx_hdmi *hdmi, unsigned short data,
- unsigned char addr)
-{
- __hdmi_phy_i2c_write(hdmi, data, addr);
- return 0;
-}
-
-static void imx_hdmi_phy_enable_power(struct imx_hdmi *hdmi, u8 enable)
-{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_PDZ_OFFSET,
- HDMI_PHY_CONF0_PDZ_MASK);
-}
-
-static void imx_hdmi_phy_enable_tmds(struct imx_hdmi *hdmi, u8 enable)
-{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_ENTMDS_OFFSET,
- HDMI_PHY_CONF0_ENTMDS_MASK);
-}
-
-static void imx_hdmi_phy_gen2_pddq(struct imx_hdmi *hdmi, u8 enable)
-{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
- HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
-}
-
-static void imx_hdmi_phy_gen2_txpwron(struct imx_hdmi *hdmi, u8 enable)
-{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
- HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
-}
-
-static void imx_hdmi_phy_sel_data_en_pol(struct imx_hdmi *hdmi, u8 enable)
-{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_SELDATAENPOL_OFFSET,
- HDMI_PHY_CONF0_SELDATAENPOL_MASK);
-}
-
-static void imx_hdmi_phy_sel_interface_control(struct imx_hdmi *hdmi, u8 enable)
-{
- hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
- HDMI_PHY_CONF0_SELDIPIF_OFFSET,
- HDMI_PHY_CONF0_SELDIPIF_MASK);
-}
-
-enum {
- RES_8,
- RES_10,
- RES_12,
- RES_MAX,
-};
-
-struct mpll_config {
- unsigned long mpixelclock;
- struct {
- u16 cpce;
- u16 gmp;
- } res[RES_MAX];
-};
-
-static const struct mpll_config mpll_config[] = {
- {
- 45250000, {
- { 0x01e0, 0x0000 },
- { 0x21e1, 0x0000 },
- { 0x41e2, 0x0000 }
- },
- }, {
- 92500000, {
- { 0x0140, 0x0005 },
- { 0x2141, 0x0005 },
- { 0x4142, 0x0005 },
- },
- }, {
- 148500000, {
- { 0x00a0, 0x000a },
- { 0x20a1, 0x000a },
- { 0x40a2, 0x000a },
- },
- }, {
- ~0UL, {
- { 0x00a0, 0x000a },
- { 0x2001, 0x000f },
- { 0x4002, 0x000f },
- },
- }
-};
-
-struct curr_ctrl {
- unsigned long mpixelclock;
- u16 curr[RES_MAX];
-};
-
-static const struct curr_ctrl curr_ctrl[] = {
- /* pixelclk bpp8 bpp10 bpp12 */
- {
- 54000000, { 0x091c, 0x091c, 0x06dc },
- }, {
- 58400000, { 0x091c, 0x06dc, 0x06dc },
- }, {
- 72000000, { 0x06dc, 0x06dc, 0x091c },
- }, {
- 74250000, { 0x06dc, 0x0b5c, 0x091c },
- }, {
- 118800000, { 0x091c, 0x091c, 0x06dc },
- }, {
- 216000000, { 0x06dc, 0x0b5c, 0x091c },
- }
-};
-
-static int hdmi_phy_configure(struct imx_hdmi *hdmi, unsigned char prep,
- unsigned char res, int cscon)
-{
- unsigned res_idx, i;
- u8 val, msec;
-
- if (prep)
- return -EINVAL;
-
- switch (res) {
- case 0: /* color resolution 0 is 8 bit colour depth */
- case 8:
- res_idx = RES_8;
- break;
- case 10:
- res_idx = RES_10;
- break;
- case 12:
- res_idx = RES_12;
- break;
- default:
- return -EINVAL;
- }
-
- /* Enable csc path */
- if (cscon)
- val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH;
- else
- val = HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS;
-
- hdmi_writeb(hdmi, val, HDMI_MC_FLOWCTRL);
-
- /* gen2 tx power off */
- imx_hdmi_phy_gen2_txpwron(hdmi, 0);
-
- /* gen2 pddq */
- imx_hdmi_phy_gen2_pddq(hdmi, 1);
-
- /* PHY reset */
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_DEASSERT, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_ASSERT, HDMI_MC_PHYRSTZ);
-
- hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
-
- hdmi_phy_test_clear(hdmi, 1);
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
- hdmi_phy_test_clear(hdmi, 0);
-
- /* PLL/MPLL Cfg - always match on final entry */
- for (i = 0; i < ARRAY_SIZE(mpll_config) - 1; i++)
- if (hdmi->hdmi_data.video_mode.mpixelclock <=
- mpll_config[i].mpixelclock)
- break;
-
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].cpce, 0x06);
- hdmi_phy_i2c_write(hdmi, mpll_config[i].res[res_idx].gmp, 0x15);
-
- for (i = 0; i < ARRAY_SIZE(curr_ctrl); i++)
- if (hdmi->hdmi_data.video_mode.mpixelclock <=
- curr_ctrl[i].mpixelclock)
- break;
-
- if (i >= ARRAY_SIZE(curr_ctrl)) {
- dev_err(hdmi->dev,
- "Pixel clock %d - unsupported by HDMI\n",
- hdmi->hdmi_data.video_mode.mpixelclock);
- return -EINVAL;
- }
-
- /* CURRCTRL */
- hdmi_phy_i2c_write(hdmi, curr_ctrl[i].curr[res_idx], 0x10);
-
- hdmi_phy_i2c_write(hdmi, 0x0000, 0x13); /* PLLPHBYCTRL */
- hdmi_phy_i2c_write(hdmi, 0x0006, 0x17);
- /* RESISTANCE TERM 133Ohm Cfg */
- hdmi_phy_i2c_write(hdmi, 0x0005, 0x19); /* TXTERM */
- /* PREEMP Cgf 0.00 */
- hdmi_phy_i2c_write(hdmi, 0x800d, 0x09); /* CKSYMTXCTRL */
- /* TX/CK LVL 10 */
- hdmi_phy_i2c_write(hdmi, 0x01ad, 0x0E); /* VLEVCTRL */
- /* REMOVE CLK TERM */
- hdmi_phy_i2c_write(hdmi, 0x8000, 0x05); /* CKCALCTRL */
-
- imx_hdmi_phy_enable_power(hdmi, 1);
-
- /* toggle TMDS enable */
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 1);
-
- /* gen2 tx power on */
- imx_hdmi_phy_gen2_txpwron(hdmi, 1);
- imx_hdmi_phy_gen2_pddq(hdmi, 0);
-
- /*Wait for PHY PLL lock */
- msec = 5;
- do {
- val = hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_TX_PHY_LOCK;
- if (!val)
- break;
-
- if (msec == 0) {
- dev_err(hdmi->dev, "PHY PLL not locked\n");
- return -ETIMEDOUT;
- }
-
- udelay(1000);
- msec--;
- } while (1);
-
- return 0;
-}
-
-static int imx_hdmi_phy_init(struct imx_hdmi *hdmi)
-{
- int i, ret;
- bool cscon = false;
-
- /*check csc whether needed activated in HDMI mode */
- cscon = (is_color_space_conversion(hdmi) &&
- !hdmi->hdmi_data.video_mode.mdvi);
-
- /* HDMI Phy spec says to do the phy initialization sequence twice */
- for (i = 0; i < 2; i++) {
- imx_hdmi_phy_sel_data_en_pol(hdmi, 1);
- imx_hdmi_phy_sel_interface_control(hdmi, 0);
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
-
- /* Enable CSC */
- ret = hdmi_phy_configure(hdmi, 0, 8, cscon);
- if (ret)
- return ret;
- }
-
- hdmi->phy_enabled = true;
- return 0;
-}
-
-static void hdmi_tx_hdcp_config(struct imx_hdmi *hdmi)
-{
- u8 de;
-
- if (hdmi->hdmi_data.video_mode.mdataenablepolarity)
- de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH;
- else
- de = HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW;
-
- /* disable rx detect */
- hdmi_modb(hdmi, HDMI_A_HDCPCFG0_RXDETECT_DISABLE,
- HDMI_A_HDCPCFG0_RXDETECT_MASK, HDMI_A_HDCPCFG0);
-
- hdmi_modb(hdmi, de, HDMI_A_VIDPOLCFG_DATAENPOL_MASK, HDMI_A_VIDPOLCFG);
-
- hdmi_modb(hdmi, HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE,
- HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, HDMI_A_HDCPCFG1);
-}
-
-static void hdmi_config_AVI(struct imx_hdmi *hdmi)
-{
- u8 val, pix_fmt, under_scan;
- u8 act_ratio, coded_ratio, colorimetry, ext_colorimetry;
- bool aspect_16_9;
-
- aspect_16_9 = false; /* FIXME */
-
- /* AVI Data Byte 1 */
- if (hdmi->hdmi_data.enc_out_format == YCBCR444)
- pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR444;
- else if (hdmi->hdmi_data.enc_out_format == YCBCR422_8BITS)
- pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_YCBCR422;
- else
- pix_fmt = HDMI_FC_AVICONF0_PIX_FMT_RGB;
-
- under_scan = HDMI_FC_AVICONF0_SCAN_INFO_NODATA;
-
- /*
- * Active format identification data is present in the AVI InfoFrame.
- * Under scan info, no bar data
- */
- val = pix_fmt | under_scan |
- HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT |
- HDMI_FC_AVICONF0_BAR_DATA_NO_DATA;
-
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF0);
-
- /* AVI Data Byte 2 -Set the Aspect Ratio */
- if (aspect_16_9) {
- act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9;
- coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9;
- } else {
- act_ratio = HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3;
- coded_ratio = HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3;
- }
-
- /* Set up colorimetry */
- if (hdmi->hdmi_data.enc_out_format == XVYCC444) {
- colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO;
- if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
- ext_colorimetry =
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
- else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
- ext_colorimetry =
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709;
- } else if (hdmi->hdmi_data.enc_out_format != RGB) {
- if (hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_601)
- colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_SMPTE;
- else /*hdmi->hdmi_data.colorimetry == HDMI_COLORIMETRY_ITU_709*/
- colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_ITUR;
- ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
- } else { /* Carries no data */
- colorimetry = HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA;
- ext_colorimetry = HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601;
- }
-
- val = colorimetry | coded_ratio | act_ratio;
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF1);
-
- /* AVI Data Byte 3 */
- val = HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA | ext_colorimetry |
- HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT |
- HDMI_FC_AVICONF2_SCALING_NONE;
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF2);
-
- /* AVI Data Byte 4 */
- hdmi_writeb(hdmi, hdmi->vic, HDMI_FC_AVIVID);
-
- /* AVI Data Byte 5- set up input and output pixel repetition */
- val = (((hdmi->hdmi_data.video_mode.mpixelrepetitioninput + 1) <<
- HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET) &
- HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK) |
- ((hdmi->hdmi_data.video_mode.mpixelrepetitionoutput <<
- HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET) &
- HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK);
- hdmi_writeb(hdmi, val, HDMI_FC_PRCONF);
-
- /* IT Content and quantization range = don't care */
- val = HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS |
- HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED;
- hdmi_writeb(hdmi, val, HDMI_FC_AVICONF3);
-
- /* AVI Data Bytes 6-13 */
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIETB1);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISBB1);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVIELB1);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB0);
- hdmi_writeb(hdmi, 0, HDMI_FC_AVISRB1);
-}
-
-static void hdmi_av_composer(struct imx_hdmi *hdmi,
- const struct drm_display_mode *mode)
-{
- u8 inv_val;
- struct hdmi_vmode *vmode = &hdmi->hdmi_data.video_mode;
- int hblank, vblank, h_de_hs, v_de_vs, hsync_len, vsync_len;
-
- vmode->mhsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PHSYNC);
- vmode->mvsyncpolarity = !!(mode->flags & DRM_MODE_FLAG_PVSYNC);
- vmode->minterlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
- vmode->mpixelclock = mode->clock * 1000;
-
- dev_dbg(hdmi->dev, "final pixclk = %d\n", vmode->mpixelclock);
-
- /* Set up HDMI_FC_INVIDCONF */
- inv_val = (hdmi->hdmi_data.hdcp_enable ?
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE :
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE);
-
- inv_val |= (vmode->mvsyncpolarity ?
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH :
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW);
-
- inv_val |= (vmode->mhsyncpolarity ?
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH :
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW);
-
- inv_val |= (vmode->mdataenablepolarity ?
- HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH :
- HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW);
-
- if (hdmi->vic == 39)
- inv_val |= HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH;
- else
- inv_val |= (vmode->minterlaced ?
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH :
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW);
-
- inv_val |= (vmode->minterlaced ?
- HDMI_FC_INVIDCONF_IN_I_P_INTERLACED :
- HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE);
-
- inv_val |= (vmode->mdvi ?
- HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE :
- HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE);
-
- hdmi_writeb(hdmi, inv_val, HDMI_FC_INVIDCONF);
-
- /* Set up horizontal active pixel width */
- hdmi_writeb(hdmi, mode->hdisplay >> 8, HDMI_FC_INHACTV1);
- hdmi_writeb(hdmi, mode->hdisplay, HDMI_FC_INHACTV0);
-
- /* Set up vertical active lines */
- hdmi_writeb(hdmi, mode->vdisplay >> 8, HDMI_FC_INVACTV1);
- hdmi_writeb(hdmi, mode->vdisplay, HDMI_FC_INVACTV0);
-
- /* Set up horizontal blanking pixel region width */
- hblank = mode->htotal - mode->hdisplay;
- hdmi_writeb(hdmi, hblank >> 8, HDMI_FC_INHBLANK1);
- hdmi_writeb(hdmi, hblank, HDMI_FC_INHBLANK0);
-
- /* Set up vertical blanking pixel region width */
- vblank = mode->vtotal - mode->vdisplay;
- hdmi_writeb(hdmi, vblank, HDMI_FC_INVBLANK);
-
- /* Set up HSYNC active edge delay width (in pixel clks) */
- h_de_hs = mode->hsync_start - mode->hdisplay;
- hdmi_writeb(hdmi, h_de_hs >> 8, HDMI_FC_HSYNCINDELAY1);
- hdmi_writeb(hdmi, h_de_hs, HDMI_FC_HSYNCINDELAY0);
-
- /* Set up VSYNC active edge delay (in lines) */
- v_de_vs = mode->vsync_start - mode->vdisplay;
- hdmi_writeb(hdmi, v_de_vs, HDMI_FC_VSYNCINDELAY);
-
- /* Set up HSYNC active pulse width (in pixel clks) */
- hsync_len = mode->hsync_end - mode->hsync_start;
- hdmi_writeb(hdmi, hsync_len >> 8, HDMI_FC_HSYNCINWIDTH1);
- hdmi_writeb(hdmi, hsync_len, HDMI_FC_HSYNCINWIDTH0);
-
- /* Set up VSYNC active edge delay (in lines) */
- vsync_len = mode->vsync_end - mode->vsync_start;
- hdmi_writeb(hdmi, vsync_len, HDMI_FC_VSYNCINWIDTH);
-}
-
-static void imx_hdmi_phy_disable(struct imx_hdmi *hdmi)
-{
- if (!hdmi->phy_enabled)
- return;
-
- imx_hdmi_phy_enable_tmds(hdmi, 0);
- imx_hdmi_phy_enable_power(hdmi, 0);
-
- hdmi->phy_enabled = false;
-}
-
-/* HDMI Initialization Step B.4 */
-static void imx_hdmi_enable_video_path(struct imx_hdmi *hdmi)
-{
- u8 clkdis;
-
- /* control period minimum duration */
- hdmi_writeb(hdmi, 12, HDMI_FC_CTRLDUR);
- hdmi_writeb(hdmi, 32, HDMI_FC_EXCTRLDUR);
- hdmi_writeb(hdmi, 1, HDMI_FC_EXCTRLSPAC);
-
- /* Set to fill TMDS data channels */
- hdmi_writeb(hdmi, 0x0B, HDMI_FC_CH0PREAM);
- hdmi_writeb(hdmi, 0x16, HDMI_FC_CH1PREAM);
- hdmi_writeb(hdmi, 0x21, HDMI_FC_CH2PREAM);
-
- /* Enable pixel clock and tmds data path */
- clkdis = 0x7F;
- clkdis &= ~HDMI_MC_CLKDIS_PIXELCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-
- clkdis &= ~HDMI_MC_CLKDIS_TMDSCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
-
- /* Enable csc path */
- if (is_color_space_conversion(hdmi)) {
- clkdis &= ~HDMI_MC_CLKDIS_CSCCLK_DISABLE;
- hdmi_writeb(hdmi, clkdis, HDMI_MC_CLKDIS);
- }
-}
-
-static void hdmi_enable_audio_clk(struct imx_hdmi *hdmi)
-{
- hdmi_modb(hdmi, 0, HDMI_MC_CLKDIS_AUDCLK_DISABLE, HDMI_MC_CLKDIS);
-}
-
-/* Workaround to clear the overflow condition */
-static void imx_hdmi_clear_overflow(struct imx_hdmi *hdmi)
-{
- int count;
- u8 val;
-
- /* TMDS software reset */
- hdmi_writeb(hdmi, (u8)~HDMI_MC_SWRSTZ_TMDSSWRST_REQ, HDMI_MC_SWRSTZ);
-
- val = hdmi_readb(hdmi, HDMI_FC_INVIDCONF);
- if (hdmi->dev_type == IMX6DL_HDMI) {
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
- return;
- }
-
- for (count = 0; count < 4; count++)
- hdmi_writeb(hdmi, val, HDMI_FC_INVIDCONF);
-}
-
-static void hdmi_enable_overflow_interrupts(struct imx_hdmi *hdmi)
-{
- hdmi_writeb(hdmi, 0, HDMI_FC_MASK2);
- hdmi_writeb(hdmi, 0, HDMI_IH_MUTE_FC_STAT2);
-}
-
-static void hdmi_disable_overflow_interrupts(struct imx_hdmi *hdmi)
-{
- hdmi_writeb(hdmi, HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK,
- HDMI_IH_MUTE_FC_STAT2);
-}
-
-static int imx_hdmi_setup(struct imx_hdmi *hdmi, struct drm_display_mode *mode)
-{
- int ret;
-
- hdmi_disable_overflow_interrupts(hdmi);
-
- hdmi->vic = drm_match_cea_mode(mode);
-
- if (!hdmi->vic) {
- dev_dbg(hdmi->dev, "Non-CEA mode used in HDMI\n");
- hdmi->hdmi_data.video_mode.mdvi = true;
- } else {
- dev_dbg(hdmi->dev, "CEA mode used vic=%d\n", hdmi->vic);
- hdmi->hdmi_data.video_mode.mdvi = false;
- }
-
- if ((hdmi->vic == 6) || (hdmi->vic == 7) ||
- (hdmi->vic == 21) || (hdmi->vic == 22) ||
- (hdmi->vic == 2) || (hdmi->vic == 3) ||
- (hdmi->vic == 17) || (hdmi->vic == 18))
- hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_601;
- else
- hdmi->hdmi_data.colorimetry = HDMI_COLORIMETRY_ITU_709;
-
- if ((hdmi->vic == 10) || (hdmi->vic == 11) ||
- (hdmi->vic == 12) || (hdmi->vic == 13) ||
- (hdmi->vic == 14) || (hdmi->vic == 15) ||
- (hdmi->vic == 25) || (hdmi->vic == 26) ||
- (hdmi->vic == 27) || (hdmi->vic == 28) ||
- (hdmi->vic == 29) || (hdmi->vic == 30) ||
- (hdmi->vic == 35) || (hdmi->vic == 36) ||
- (hdmi->vic == 37) || (hdmi->vic == 38))
- hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 1;
- else
- hdmi->hdmi_data.video_mode.mpixelrepetitionoutput = 0;
-
- hdmi->hdmi_data.video_mode.mpixelrepetitioninput = 0;
-
- /* TODO: Get input format from IPU (via FB driver interface) */
- hdmi->hdmi_data.enc_in_format = RGB;
-
- hdmi->hdmi_data.enc_out_format = RGB;
-
- hdmi->hdmi_data.enc_color_depth = 8;
- hdmi->hdmi_data.pix_repet_factor = 0;
- hdmi->hdmi_data.hdcp_enable = 0;
- hdmi->hdmi_data.video_mode.mdataenablepolarity = true;
-
- /* HDMI Initialization Step B.1 */
- hdmi_av_composer(hdmi, mode);
-
- /* HDMI Initializateion Step B.2 */
- ret = imx_hdmi_phy_init(hdmi);
- if (ret)
- return ret;
-
- /* HDMI Initialization Step B.3 */
- imx_hdmi_enable_video_path(hdmi);
-
- /* not for DVI mode */
- if (hdmi->hdmi_data.video_mode.mdvi)
- dev_dbg(hdmi->dev, "%s DVI mode\n", __func__);
- else {
- dev_dbg(hdmi->dev, "%s CEA mode\n", __func__);
-
- /* HDMI Initialization Step E - Configure audio */
- hdmi_clk_regenerator_update_pixel_clock(hdmi);
- hdmi_enable_audio_clk(hdmi);
-
- /* HDMI Initialization Step F - Configure AVI InfoFrame */
- hdmi_config_AVI(hdmi);
- }
-
- hdmi_video_packetize(hdmi);
- hdmi_video_csc(hdmi);
- hdmi_video_sample(hdmi);
- hdmi_tx_hdcp_config(hdmi);
-
- imx_hdmi_clear_overflow(hdmi);
- if (hdmi->cable_plugin && !hdmi->hdmi_data.video_mode.mdvi)
- hdmi_enable_overflow_interrupts(hdmi);
-
- return 0;
-}
-
-/* Wait until we are registered to enable interrupts */
-static int imx_hdmi_fb_registered(struct imx_hdmi *hdmi)
-{
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_INT_ADDR_DONE_POL,
- HDMI_PHY_I2CM_INT_ADDR);
-
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL |
- HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL,
- HDMI_PHY_I2CM_CTLINT_ADDR);
-
- /* enable cable hot plug irq */
- hdmi_writeb(hdmi, (u8)~HDMI_PHY_HPD, HDMI_PHY_MASK0);
-
- /* Clear Hotplug interrupts */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
-
- return 0;
-}
-
-static void initialize_hdmi_ih_mutes(struct imx_hdmi *hdmi)
-{
- u8 ih_mute;
-
- /*
- * Boot up defaults are:
- * HDMI_IH_MUTE = 0x03 (disabled)
- * HDMI_IH_MUTE_* = 0x00 (enabled)
- *
- * Disable top level interrupt bits in HDMI block
- */
- ih_mute = hdmi_readb(hdmi, HDMI_IH_MUTE) |
- HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
- HDMI_IH_MUTE_MUTE_ALL_INTERRUPT;
-
- hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
-
- /* by default mask all interrupts */
- hdmi_writeb(hdmi, 0xff, HDMI_VP_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK0);
- hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK1);
- hdmi_writeb(hdmi, 0xff, HDMI_FC_MASK2);
- hdmi_writeb(hdmi, 0xff, HDMI_PHY_MASK0);
- hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_INT_ADDR);
- hdmi_writeb(hdmi, 0xff, HDMI_PHY_I2CM_CTLINT_ADDR);
- hdmi_writeb(hdmi, 0xff, HDMI_AUD_INT);
- hdmi_writeb(hdmi, 0xff, HDMI_AUD_SPDIFINT);
- hdmi_writeb(hdmi, 0xff, HDMI_AUD_HBR_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_GP_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_A_APIINTMSK);
- hdmi_writeb(hdmi, 0xff, HDMI_CEC_MASK);
- hdmi_writeb(hdmi, 0xff, HDMI_I2CM_INT);
- hdmi_writeb(hdmi, 0xff, HDMI_I2CM_CTLINT);
-
- /* Disable interrupts in the IH_MUTE_* registers */
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT1);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_FC_STAT2);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AS_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_PHY_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CM_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_CEC_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_VP_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_I2CMPHY_STAT0);
- hdmi_writeb(hdmi, 0xff, HDMI_IH_MUTE_AHBDMAAUD_STAT0);
-
- /* Enable top level interrupt bits in HDMI block */
- ih_mute &= ~(HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT |
- HDMI_IH_MUTE_MUTE_ALL_INTERRUPT);
- hdmi_writeb(hdmi, ih_mute, HDMI_IH_MUTE);
-}
-
-static void imx_hdmi_poweron(struct imx_hdmi *hdmi)
-{
- imx_hdmi_setup(hdmi, &hdmi->previous_mode);
-}
-
-static void imx_hdmi_poweroff(struct imx_hdmi *hdmi)
-{
- imx_hdmi_phy_disable(hdmi);
-}
-
-static enum drm_connector_status imx_hdmi_connector_detect(struct drm_connector
- *connector, bool force)
-{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- connector);
-
- return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
- connector_status_connected : connector_status_disconnected;
-}
-
-static int imx_hdmi_connector_get_modes(struct drm_connector *connector)
-{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- connector);
- struct edid *edid;
- int ret;
-
- if (!hdmi->ddc)
- return 0;
-
- edid = drm_get_edid(connector, hdmi->ddc);
- if (edid) {
- dev_dbg(hdmi->dev, "got edid: width[%d] x height[%d]\n",
- edid->width_cm, edid->height_cm);
-
- drm_mode_connector_update_edid_property(connector, edid);
- ret = drm_add_edid_modes(connector, edid);
- kfree(edid);
- } else {
- dev_dbg(hdmi->dev, "failed to get edid\n");
- }
-
- return 0;
-}
-
-static struct drm_encoder *imx_hdmi_connector_best_encoder(struct drm_connector
- *connector)
-{
- struct imx_hdmi *hdmi = container_of(connector, struct imx_hdmi,
- connector);
-
- return &hdmi->encoder;
-}
-
-static void imx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
- imx_hdmi_setup(hdmi, mode);
-
- /* Store the display mode for plugin/DKMS poweron events */
- memcpy(&hdmi->previous_mode, mode, sizeof(hdmi->previous_mode));
-}
-
-static bool imx_hdmi_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- return true;
-}
-
-static void imx_hdmi_encoder_disable(struct drm_encoder *encoder)
-{
-}
-
-static void imx_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
- if (mode)
- imx_hdmi_poweroff(hdmi);
- else
- imx_hdmi_poweron(hdmi);
-}
-
-static void imx_hdmi_encoder_prepare(struct drm_encoder *encoder)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
-
- imx_hdmi_poweroff(hdmi);
- imx_drm_panel_format(encoder, V4L2_PIX_FMT_RGB24);
-}
-
-static void imx_hdmi_encoder_commit(struct drm_encoder *encoder)
-{
- struct imx_hdmi *hdmi = container_of(encoder, struct imx_hdmi, encoder);
- int mux = imx_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
-
- imx_hdmi_set_ipu_di_mux(hdmi, mux);
-
- imx_hdmi_poweron(hdmi);
-}
-
-static struct drm_encoder_funcs imx_hdmi_encoder_funcs = {
- .destroy = imx_drm_encoder_destroy,
-};
-
-static struct drm_encoder_helper_funcs imx_hdmi_encoder_helper_funcs = {
- .dpms = imx_hdmi_encoder_dpms,
- .prepare = imx_hdmi_encoder_prepare,
- .commit = imx_hdmi_encoder_commit,
- .mode_set = imx_hdmi_encoder_mode_set,
- .mode_fixup = imx_hdmi_encoder_mode_fixup,
- .disable = imx_hdmi_encoder_disable,
-};
-
-static struct drm_connector_funcs imx_hdmi_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .detect = imx_hdmi_connector_detect,
- .destroy = imx_drm_connector_destroy,
-};
-
-static struct drm_connector_helper_funcs imx_hdmi_connector_helper_funcs = {
- .get_modes = imx_hdmi_connector_get_modes,
- .best_encoder = imx_hdmi_connector_best_encoder,
-};
-
-static irqreturn_t imx_hdmi_hardirq(int irq, void *dev_id)
-{
- struct imx_hdmi *hdmi = dev_id;
- u8 intr_stat;
-
- intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
- if (intr_stat)
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
- return intr_stat ? IRQ_WAKE_THREAD : IRQ_NONE;
-}
-
-static irqreturn_t imx_hdmi_irq(int irq, void *dev_id)
-{
- struct imx_hdmi *hdmi = dev_id;
- u8 intr_stat;
- u8 phy_int_pol;
-
- intr_stat = hdmi_readb(hdmi, HDMI_IH_PHY_STAT0);
-
- phy_int_pol = hdmi_readb(hdmi, HDMI_PHY_POL0);
-
- if (intr_stat & HDMI_IH_PHY_STAT0_HPD) {
- if (phy_int_pol & HDMI_PHY_HPD) {
- dev_dbg(hdmi->dev, "EVENT=plugin\n");
-
- hdmi_modb(hdmi, 0, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
- imx_hdmi_poweron(hdmi);
- } else {
- dev_dbg(hdmi->dev, "EVENT=plugout\n");
-
- hdmi_modb(hdmi, HDMI_PHY_HPD, HDMI_PHY_HPD,
- HDMI_PHY_POL0);
-
- imx_hdmi_poweroff(hdmi);
- }
- drm_helper_hpd_irq_event(hdmi->connector.dev);
- }
-
- hdmi_writeb(hdmi, intr_stat, HDMI_IH_PHY_STAT0);
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
- return IRQ_HANDLED;
-}
-
-static int imx_hdmi_register(struct drm_device *drm, struct imx_hdmi *hdmi)
-{
- int ret;
-
- ret = imx_drm_encoder_parse_of(drm, &hdmi->encoder,
- hdmi->dev->of_node);
- if (ret)
- return ret;
-
- hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
-
- drm_encoder_helper_add(&hdmi->encoder, &imx_hdmi_encoder_helper_funcs);
- drm_encoder_init(drm, &hdmi->encoder, &imx_hdmi_encoder_funcs,
- DRM_MODE_ENCODER_TMDS);
-
- drm_connector_helper_add(&hdmi->connector,
- &imx_hdmi_connector_helper_funcs);
- drm_connector_init(drm, &hdmi->connector, &imx_hdmi_connector_funcs,
- DRM_MODE_CONNECTOR_HDMIA);
-
- hdmi->connector.encoder = &hdmi->encoder;
-
- drm_mode_connector_attach_encoder(&hdmi->connector, &hdmi->encoder);
-
- return 0;
-}
-
-static struct platform_device_id imx_hdmi_devtype[] = {
- {
- .name = "imx6q-hdmi",
- .driver_data = IMX6Q_HDMI,
- }, {
- .name = "imx6dl-hdmi",
- .driver_data = IMX6DL_HDMI,
- }, { /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(platform, imx_hdmi_devtype);
-
-static const struct of_device_id imx_hdmi_dt_ids[] = {
-{ .compatible = "fsl,imx6q-hdmi", .data = &imx_hdmi_devtype[IMX6Q_HDMI], },
-{ .compatible = "fsl,imx6dl-hdmi", .data = &imx_hdmi_devtype[IMX6DL_HDMI], },
-{ /* sentinel */ }
-};
-MODULE_DEVICE_TABLE(of, imx_hdmi_dt_ids);
-
-static int imx_hdmi_bind(struct device *dev, struct device *master, void *data)
-{
- struct platform_device *pdev = to_platform_device(dev);
- const struct of_device_id *of_id =
- of_match_device(imx_hdmi_dt_ids, dev);
- struct drm_device *drm = data;
- struct device_node *np = dev->of_node;
- struct device_node *ddc_node;
- struct imx_hdmi *hdmi;
- struct resource *iores;
- int ret, irq;
-
- hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
- if (!hdmi)
- return -ENOMEM;
-
- hdmi->dev = dev;
- hdmi->sample_rate = 48000;
- hdmi->ratio = 100;
-
- if (of_id) {
- const struct platform_device_id *device_id = of_id->data;
-
- hdmi->dev_type = device_id->driver_data;
- }
-
- ddc_node = of_parse_phandle(np, "ddc-i2c-bus", 0);
- if (ddc_node) {
- hdmi->ddc = of_find_i2c_adapter_by_node(ddc_node);
- if (!hdmi->ddc)
- dev_dbg(hdmi->dev, "failed to read ddc node\n");
-
- of_node_put(ddc_node);
- } else {
- dev_dbg(hdmi->dev, "no ddc property found\n");
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
-
- ret = devm_request_threaded_irq(dev, irq, imx_hdmi_hardirq,
- imx_hdmi_irq, IRQF_SHARED,
- dev_name(dev), hdmi);
- if (ret)
- return ret;
-
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- hdmi->regs = devm_ioremap_resource(dev, iores);
- if (IS_ERR(hdmi->regs))
- return PTR_ERR(hdmi->regs);
-
- hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "gpr");
- if (IS_ERR(hdmi->regmap))
- return PTR_ERR(hdmi->regmap);
-
- hdmi->isfr_clk = devm_clk_get(hdmi->dev, "isfr");
- if (IS_ERR(hdmi->isfr_clk)) {
- ret = PTR_ERR(hdmi->isfr_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI isfr clk: %d\n", ret);
- return ret;
- }
-
- ret = clk_prepare_enable(hdmi->isfr_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI isfr clock: %d\n", ret);
- return ret;
- }
-
- hdmi->iahb_clk = devm_clk_get(hdmi->dev, "iahb");
- if (IS_ERR(hdmi->iahb_clk)) {
- ret = PTR_ERR(hdmi->iahb_clk);
- dev_err(hdmi->dev,
- "Unable to get HDMI iahb clk: %d\n", ret);
- goto err_isfr;
- }
-
- ret = clk_prepare_enable(hdmi->iahb_clk);
- if (ret) {
- dev_err(hdmi->dev,
- "Cannot enable HDMI iahb clock: %d\n", ret);
- goto err_isfr;
- }
-
- /* Product and revision IDs */
- dev_info(dev,
- "Detected HDMI controller 0x%x:0x%x:0x%x:0x%x\n",
- hdmi_readb(hdmi, HDMI_DESIGN_ID),
- hdmi_readb(hdmi, HDMI_REVISION_ID),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID0),
- hdmi_readb(hdmi, HDMI_PRODUCT_ID1));
-
- initialize_hdmi_ih_mutes(hdmi);
-
- /*
- * To prevent overflows in HDMI_IH_FC_STAT2, set the clk regenerator
- * N and cts values before enabling phy
- */
- hdmi_init_clk_regenerator(hdmi);
-
- /*
- * Configure registers related to HDMI interrupt
- * generation before registering IRQ.
- */
- hdmi_writeb(hdmi, HDMI_PHY_HPD, HDMI_PHY_POL0);
-
- /* Clear Hotplug interrupts */
- hdmi_writeb(hdmi, HDMI_IH_PHY_STAT0_HPD, HDMI_IH_PHY_STAT0);
-
- ret = imx_hdmi_fb_registered(hdmi);
- if (ret)
- goto err_iahb;
-
- ret = imx_hdmi_register(drm, hdmi);
- if (ret)
- goto err_iahb;
-
- /* Unmute interrupts */
- hdmi_writeb(hdmi, ~HDMI_IH_PHY_STAT0_HPD, HDMI_IH_MUTE_PHY_STAT0);
-
- dev_set_drvdata(dev, hdmi);
-
- return 0;
-
-err_iahb:
- clk_disable_unprepare(hdmi->iahb_clk);
-err_isfr:
- clk_disable_unprepare(hdmi->isfr_clk);
-
- return ret;
-}
-
-static void imx_hdmi_unbind(struct device *dev, struct device *master,
- void *data)
-{
- struct imx_hdmi *hdmi = dev_get_drvdata(dev);
-
- /* Disable all interrupts */
- hdmi_writeb(hdmi, ~0, HDMI_IH_MUTE_PHY_STAT0);
-
- hdmi->connector.funcs->destroy(&hdmi->connector);
- hdmi->encoder.funcs->destroy(&hdmi->encoder);
-
- clk_disable_unprepare(hdmi->iahb_clk);
- clk_disable_unprepare(hdmi->isfr_clk);
- i2c_put_adapter(hdmi->ddc);
-}
-
-static const struct component_ops hdmi_ops = {
- .bind = imx_hdmi_bind,
- .unbind = imx_hdmi_unbind,
-};
-
-static int imx_hdmi_platform_probe(struct platform_device *pdev)
-{
- return component_add(&pdev->dev, &hdmi_ops);
-}
-
-static int imx_hdmi_platform_remove(struct platform_device *pdev)
-{
- component_del(&pdev->dev, &hdmi_ops);
- return 0;
-}
-
-static struct platform_driver imx_hdmi_driver = {
- .probe = imx_hdmi_platform_probe,
- .remove = imx_hdmi_platform_remove,
- .driver = {
- .name = "imx-hdmi",
- .of_match_table = imx_hdmi_dt_ids,
- },
-};
-
-module_platform_driver(imx_hdmi_driver);
-
-MODULE_AUTHOR("Sascha Hauer <s.hauer@pengutronix.de>");
-MODULE_DESCRIPTION("i.MX6 HDMI transmitter driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:imx-hdmi");
diff --git a/drivers/gpu/drm/imx/imx-hdmi.h b/drivers/gpu/drm/imx/imx-hdmi.h
deleted file mode 100644
index 39b677689db6..000000000000
--- a/drivers/gpu/drm/imx/imx-hdmi.h
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright (C) 2011 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef __IMX_HDMI_H__
-#define __IMX_HDMI_H__
-
-/* Identification Registers */
-#define HDMI_DESIGN_ID 0x0000
-#define HDMI_REVISION_ID 0x0001
-#define HDMI_PRODUCT_ID0 0x0002
-#define HDMI_PRODUCT_ID1 0x0003
-#define HDMI_CONFIG0_ID 0x0004
-#define HDMI_CONFIG1_ID 0x0005
-#define HDMI_CONFIG2_ID 0x0006
-#define HDMI_CONFIG3_ID 0x0007
-
-/* Interrupt Registers */
-#define HDMI_IH_FC_STAT0 0x0100
-#define HDMI_IH_FC_STAT1 0x0101
-#define HDMI_IH_FC_STAT2 0x0102
-#define HDMI_IH_AS_STAT0 0x0103
-#define HDMI_IH_PHY_STAT0 0x0104
-#define HDMI_IH_I2CM_STAT0 0x0105
-#define HDMI_IH_CEC_STAT0 0x0106
-#define HDMI_IH_VP_STAT0 0x0107
-#define HDMI_IH_I2CMPHY_STAT0 0x0108
-#define HDMI_IH_AHBDMAAUD_STAT0 0x0109
-
-#define HDMI_IH_MUTE_FC_STAT0 0x0180
-#define HDMI_IH_MUTE_FC_STAT1 0x0181
-#define HDMI_IH_MUTE_FC_STAT2 0x0182
-#define HDMI_IH_MUTE_AS_STAT0 0x0183
-#define HDMI_IH_MUTE_PHY_STAT0 0x0184
-#define HDMI_IH_MUTE_I2CM_STAT0 0x0185
-#define HDMI_IH_MUTE_CEC_STAT0 0x0186
-#define HDMI_IH_MUTE_VP_STAT0 0x0187
-#define HDMI_IH_MUTE_I2CMPHY_STAT0 0x0188
-#define HDMI_IH_MUTE_AHBDMAAUD_STAT0 0x0189
-#define HDMI_IH_MUTE 0x01FF
-
-/* Video Sample Registers */
-#define HDMI_TX_INVID0 0x0200
-#define HDMI_TX_INSTUFFING 0x0201
-#define HDMI_TX_GYDATA0 0x0202
-#define HDMI_TX_GYDATA1 0x0203
-#define HDMI_TX_RCRDATA0 0x0204
-#define HDMI_TX_RCRDATA1 0x0205
-#define HDMI_TX_BCBDATA0 0x0206
-#define HDMI_TX_BCBDATA1 0x0207
-
-/* Video Packetizer Registers */
-#define HDMI_VP_STATUS 0x0800
-#define HDMI_VP_PR_CD 0x0801
-#define HDMI_VP_STUFF 0x0802
-#define HDMI_VP_REMAP 0x0803
-#define HDMI_VP_CONF 0x0804
-#define HDMI_VP_STAT 0x0805
-#define HDMI_VP_INT 0x0806
-#define HDMI_VP_MASK 0x0807
-#define HDMI_VP_POL 0x0808
-
-/* Frame Composer Registers */
-#define HDMI_FC_INVIDCONF 0x1000
-#define HDMI_FC_INHACTV0 0x1001
-#define HDMI_FC_INHACTV1 0x1002
-#define HDMI_FC_INHBLANK0 0x1003
-#define HDMI_FC_INHBLANK1 0x1004
-#define HDMI_FC_INVACTV0 0x1005
-#define HDMI_FC_INVACTV1 0x1006
-#define HDMI_FC_INVBLANK 0x1007
-#define HDMI_FC_HSYNCINDELAY0 0x1008
-#define HDMI_FC_HSYNCINDELAY1 0x1009
-#define HDMI_FC_HSYNCINWIDTH0 0x100A
-#define HDMI_FC_HSYNCINWIDTH1 0x100B
-#define HDMI_FC_VSYNCINDELAY 0x100C
-#define HDMI_FC_VSYNCINWIDTH 0x100D
-#define HDMI_FC_INFREQ0 0x100E
-#define HDMI_FC_INFREQ1 0x100F
-#define HDMI_FC_INFREQ2 0x1010
-#define HDMI_FC_CTRLDUR 0x1011
-#define HDMI_FC_EXCTRLDUR 0x1012
-#define HDMI_FC_EXCTRLSPAC 0x1013
-#define HDMI_FC_CH0PREAM 0x1014
-#define HDMI_FC_CH1PREAM 0x1015
-#define HDMI_FC_CH2PREAM 0x1016
-#define HDMI_FC_AVICONF3 0x1017
-#define HDMI_FC_GCP 0x1018
-#define HDMI_FC_AVICONF0 0x1019
-#define HDMI_FC_AVICONF1 0x101A
-#define HDMI_FC_AVICONF2 0x101B
-#define HDMI_FC_AVIVID 0x101C
-#define HDMI_FC_AVIETB0 0x101D
-#define HDMI_FC_AVIETB1 0x101E
-#define HDMI_FC_AVISBB0 0x101F
-#define HDMI_FC_AVISBB1 0x1020
-#define HDMI_FC_AVIELB0 0x1021
-#define HDMI_FC_AVIELB1 0x1022
-#define HDMI_FC_AVISRB0 0x1023
-#define HDMI_FC_AVISRB1 0x1024
-#define HDMI_FC_AUDICONF0 0x1025
-#define HDMI_FC_AUDICONF1 0x1026
-#define HDMI_FC_AUDICONF2 0x1027
-#define HDMI_FC_AUDICONF3 0x1028
-#define HDMI_FC_VSDIEEEID0 0x1029
-#define HDMI_FC_VSDSIZE 0x102A
-#define HDMI_FC_VSDIEEEID1 0x1030
-#define HDMI_FC_VSDIEEEID2 0x1031
-#define HDMI_FC_VSDPAYLOAD0 0x1032
-#define HDMI_FC_VSDPAYLOAD1 0x1033
-#define HDMI_FC_VSDPAYLOAD2 0x1034
-#define HDMI_FC_VSDPAYLOAD3 0x1035
-#define HDMI_FC_VSDPAYLOAD4 0x1036
-#define HDMI_FC_VSDPAYLOAD5 0x1037
-#define HDMI_FC_VSDPAYLOAD6 0x1038
-#define HDMI_FC_VSDPAYLOAD7 0x1039
-#define HDMI_FC_VSDPAYLOAD8 0x103A
-#define HDMI_FC_VSDPAYLOAD9 0x103B
-#define HDMI_FC_VSDPAYLOAD10 0x103C
-#define HDMI_FC_VSDPAYLOAD11 0x103D
-#define HDMI_FC_VSDPAYLOAD12 0x103E
-#define HDMI_FC_VSDPAYLOAD13 0x103F
-#define HDMI_FC_VSDPAYLOAD14 0x1040
-#define HDMI_FC_VSDPAYLOAD15 0x1041
-#define HDMI_FC_VSDPAYLOAD16 0x1042
-#define HDMI_FC_VSDPAYLOAD17 0x1043
-#define HDMI_FC_VSDPAYLOAD18 0x1044
-#define HDMI_FC_VSDPAYLOAD19 0x1045
-#define HDMI_FC_VSDPAYLOAD20 0x1046
-#define HDMI_FC_VSDPAYLOAD21 0x1047
-#define HDMI_FC_VSDPAYLOAD22 0x1048
-#define HDMI_FC_VSDPAYLOAD23 0x1049
-#define HDMI_FC_SPDVENDORNAME0 0x104A
-#define HDMI_FC_SPDVENDORNAME1 0x104B
-#define HDMI_FC_SPDVENDORNAME2 0x104C
-#define HDMI_FC_SPDVENDORNAME3 0x104D
-#define HDMI_FC_SPDVENDORNAME4 0x104E
-#define HDMI_FC_SPDVENDORNAME5 0x104F
-#define HDMI_FC_SPDVENDORNAME6 0x1050
-#define HDMI_FC_SPDVENDORNAME7 0x1051
-#define HDMI_FC_SDPPRODUCTNAME0 0x1052
-#define HDMI_FC_SDPPRODUCTNAME1 0x1053
-#define HDMI_FC_SDPPRODUCTNAME2 0x1054
-#define HDMI_FC_SDPPRODUCTNAME3 0x1055
-#define HDMI_FC_SDPPRODUCTNAME4 0x1056
-#define HDMI_FC_SDPPRODUCTNAME5 0x1057
-#define HDMI_FC_SDPPRODUCTNAME6 0x1058
-#define HDMI_FC_SDPPRODUCTNAME7 0x1059
-#define HDMI_FC_SDPPRODUCTNAME8 0x105A
-#define HDMI_FC_SDPPRODUCTNAME9 0x105B
-#define HDMI_FC_SDPPRODUCTNAME10 0x105C
-#define HDMI_FC_SDPPRODUCTNAME11 0x105D
-#define HDMI_FC_SDPPRODUCTNAME12 0x105E
-#define HDMI_FC_SDPPRODUCTNAME13 0x105F
-#define HDMI_FC_SDPPRODUCTNAME14 0x1060
-#define HDMI_FC_SPDPRODUCTNAME15 0x1061
-#define HDMI_FC_SPDDEVICEINF 0x1062
-#define HDMI_FC_AUDSCONF 0x1063
-#define HDMI_FC_AUDSSTAT 0x1064
-#define HDMI_FC_DATACH0FILL 0x1070
-#define HDMI_FC_DATACH1FILL 0x1071
-#define HDMI_FC_DATACH2FILL 0x1072
-#define HDMI_FC_CTRLQHIGH 0x1073
-#define HDMI_FC_CTRLQLOW 0x1074
-#define HDMI_FC_ACP0 0x1075
-#define HDMI_FC_ACP28 0x1076
-#define HDMI_FC_ACP27 0x1077
-#define HDMI_FC_ACP26 0x1078
-#define HDMI_FC_ACP25 0x1079
-#define HDMI_FC_ACP24 0x107A
-#define HDMI_FC_ACP23 0x107B
-#define HDMI_FC_ACP22 0x107C
-#define HDMI_FC_ACP21 0x107D
-#define HDMI_FC_ACP20 0x107E
-#define HDMI_FC_ACP19 0x107F
-#define HDMI_FC_ACP18 0x1080
-#define HDMI_FC_ACP17 0x1081
-#define HDMI_FC_ACP16 0x1082
-#define HDMI_FC_ACP15 0x1083
-#define HDMI_FC_ACP14 0x1084
-#define HDMI_FC_ACP13 0x1085
-#define HDMI_FC_ACP12 0x1086
-#define HDMI_FC_ACP11 0x1087
-#define HDMI_FC_ACP10 0x1088
-#define HDMI_FC_ACP9 0x1089
-#define HDMI_FC_ACP8 0x108A
-#define HDMI_FC_ACP7 0x108B
-#define HDMI_FC_ACP6 0x108C
-#define HDMI_FC_ACP5 0x108D
-#define HDMI_FC_ACP4 0x108E
-#define HDMI_FC_ACP3 0x108F
-#define HDMI_FC_ACP2 0x1090
-#define HDMI_FC_ACP1 0x1091
-#define HDMI_FC_ISCR1_0 0x1092
-#define HDMI_FC_ISCR1_16 0x1093
-#define HDMI_FC_ISCR1_15 0x1094
-#define HDMI_FC_ISCR1_14 0x1095
-#define HDMI_FC_ISCR1_13 0x1096
-#define HDMI_FC_ISCR1_12 0x1097
-#define HDMI_FC_ISCR1_11 0x1098
-#define HDMI_FC_ISCR1_10 0x1099
-#define HDMI_FC_ISCR1_9 0x109A
-#define HDMI_FC_ISCR1_8 0x109B
-#define HDMI_FC_ISCR1_7 0x109C
-#define HDMI_FC_ISCR1_6 0x109D
-#define HDMI_FC_ISCR1_5 0x109E
-#define HDMI_FC_ISCR1_4 0x109F
-#define HDMI_FC_ISCR1_3 0x10A0
-#define HDMI_FC_ISCR1_2 0x10A1
-#define HDMI_FC_ISCR1_1 0x10A2
-#define HDMI_FC_ISCR2_15 0x10A3
-#define HDMI_FC_ISCR2_14 0x10A4
-#define HDMI_FC_ISCR2_13 0x10A5
-#define HDMI_FC_ISCR2_12 0x10A6
-#define HDMI_FC_ISCR2_11 0x10A7
-#define HDMI_FC_ISCR2_10 0x10A8
-#define HDMI_FC_ISCR2_9 0x10A9
-#define HDMI_FC_ISCR2_8 0x10AA
-#define HDMI_FC_ISCR2_7 0x10AB
-#define HDMI_FC_ISCR2_6 0x10AC
-#define HDMI_FC_ISCR2_5 0x10AD
-#define HDMI_FC_ISCR2_4 0x10AE
-#define HDMI_FC_ISCR2_3 0x10AF
-#define HDMI_FC_ISCR2_2 0x10B0
-#define HDMI_FC_ISCR2_1 0x10B1
-#define HDMI_FC_ISCR2_0 0x10B2
-#define HDMI_FC_DATAUTO0 0x10B3
-#define HDMI_FC_DATAUTO1 0x10B4
-#define HDMI_FC_DATAUTO2 0x10B5
-#define HDMI_FC_DATMAN 0x10B6
-#define HDMI_FC_DATAUTO3 0x10B7
-#define HDMI_FC_RDRB0 0x10B8
-#define HDMI_FC_RDRB1 0x10B9
-#define HDMI_FC_RDRB2 0x10BA
-#define HDMI_FC_RDRB3 0x10BB
-#define HDMI_FC_RDRB4 0x10BC
-#define HDMI_FC_RDRB5 0x10BD
-#define HDMI_FC_RDRB6 0x10BE
-#define HDMI_FC_RDRB7 0x10BF
-#define HDMI_FC_STAT0 0x10D0
-#define HDMI_FC_INT0 0x10D1
-#define HDMI_FC_MASK0 0x10D2
-#define HDMI_FC_POL0 0x10D3
-#define HDMI_FC_STAT1 0x10D4
-#define HDMI_FC_INT1 0x10D5
-#define HDMI_FC_MASK1 0x10D6
-#define HDMI_FC_POL1 0x10D7
-#define HDMI_FC_STAT2 0x10D8
-#define HDMI_FC_INT2 0x10D9
-#define HDMI_FC_MASK2 0x10DA
-#define HDMI_FC_POL2 0x10DB
-#define HDMI_FC_PRCONF 0x10E0
-
-#define HDMI_FC_GMD_STAT 0x1100
-#define HDMI_FC_GMD_EN 0x1101
-#define HDMI_FC_GMD_UP 0x1102
-#define HDMI_FC_GMD_CONF 0x1103
-#define HDMI_FC_GMD_HB 0x1104
-#define HDMI_FC_GMD_PB0 0x1105
-#define HDMI_FC_GMD_PB1 0x1106
-#define HDMI_FC_GMD_PB2 0x1107
-#define HDMI_FC_GMD_PB3 0x1108
-#define HDMI_FC_GMD_PB4 0x1109
-#define HDMI_FC_GMD_PB5 0x110A
-#define HDMI_FC_GMD_PB6 0x110B
-#define HDMI_FC_GMD_PB7 0x110C
-#define HDMI_FC_GMD_PB8 0x110D
-#define HDMI_FC_GMD_PB9 0x110E
-#define HDMI_FC_GMD_PB10 0x110F
-#define HDMI_FC_GMD_PB11 0x1110
-#define HDMI_FC_GMD_PB12 0x1111
-#define HDMI_FC_GMD_PB13 0x1112
-#define HDMI_FC_GMD_PB14 0x1113
-#define HDMI_FC_GMD_PB15 0x1114
-#define HDMI_FC_GMD_PB16 0x1115
-#define HDMI_FC_GMD_PB17 0x1116
-#define HDMI_FC_GMD_PB18 0x1117
-#define HDMI_FC_GMD_PB19 0x1118
-#define HDMI_FC_GMD_PB20 0x1119
-#define HDMI_FC_GMD_PB21 0x111A
-#define HDMI_FC_GMD_PB22 0x111B
-#define HDMI_FC_GMD_PB23 0x111C
-#define HDMI_FC_GMD_PB24 0x111D
-#define HDMI_FC_GMD_PB25 0x111E
-#define HDMI_FC_GMD_PB26 0x111F
-#define HDMI_FC_GMD_PB27 0x1120
-
-#define HDMI_FC_DBGFORCE 0x1200
-#define HDMI_FC_DBGAUD0CH0 0x1201
-#define HDMI_FC_DBGAUD1CH0 0x1202
-#define HDMI_FC_DBGAUD2CH0 0x1203
-#define HDMI_FC_DBGAUD0CH1 0x1204
-#define HDMI_FC_DBGAUD1CH1 0x1205
-#define HDMI_FC_DBGAUD2CH1 0x1206
-#define HDMI_FC_DBGAUD0CH2 0x1207
-#define HDMI_FC_DBGAUD1CH2 0x1208
-#define HDMI_FC_DBGAUD2CH2 0x1209
-#define HDMI_FC_DBGAUD0CH3 0x120A
-#define HDMI_FC_DBGAUD1CH3 0x120B
-#define HDMI_FC_DBGAUD2CH3 0x120C
-#define HDMI_FC_DBGAUD0CH4 0x120D
-#define HDMI_FC_DBGAUD1CH4 0x120E
-#define HDMI_FC_DBGAUD2CH4 0x120F
-#define HDMI_FC_DBGAUD0CH5 0x1210
-#define HDMI_FC_DBGAUD1CH5 0x1211
-#define HDMI_FC_DBGAUD2CH5 0x1212
-#define HDMI_FC_DBGAUD0CH6 0x1213
-#define HDMI_FC_DBGAUD1CH6 0x1214
-#define HDMI_FC_DBGAUD2CH6 0x1215
-#define HDMI_FC_DBGAUD0CH7 0x1216
-#define HDMI_FC_DBGAUD1CH7 0x1217
-#define HDMI_FC_DBGAUD2CH7 0x1218
-#define HDMI_FC_DBGTMDS0 0x1219
-#define HDMI_FC_DBGTMDS1 0x121A
-#define HDMI_FC_DBGTMDS2 0x121B
-
-/* HDMI Source PHY Registers */
-#define HDMI_PHY_CONF0 0x3000
-#define HDMI_PHY_TST0 0x3001
-#define HDMI_PHY_TST1 0x3002
-#define HDMI_PHY_TST2 0x3003
-#define HDMI_PHY_STAT0 0x3004
-#define HDMI_PHY_INT0 0x3005
-#define HDMI_PHY_MASK0 0x3006
-#define HDMI_PHY_POL0 0x3007
-
-/* HDMI Master PHY Registers */
-#define HDMI_PHY_I2CM_SLAVE_ADDR 0x3020
-#define HDMI_PHY_I2CM_ADDRESS_ADDR 0x3021
-#define HDMI_PHY_I2CM_DATAO_1_ADDR 0x3022
-#define HDMI_PHY_I2CM_DATAO_0_ADDR 0x3023
-#define HDMI_PHY_I2CM_DATAI_1_ADDR 0x3024
-#define HDMI_PHY_I2CM_DATAI_0_ADDR 0x3025
-#define HDMI_PHY_I2CM_OPERATION_ADDR 0x3026
-#define HDMI_PHY_I2CM_INT_ADDR 0x3027
-#define HDMI_PHY_I2CM_CTLINT_ADDR 0x3028
-#define HDMI_PHY_I2CM_DIV_ADDR 0x3029
-#define HDMI_PHY_I2CM_SOFTRSTZ_ADDR 0x302a
-#define HDMI_PHY_I2CM_SS_SCL_HCNT_1_ADDR 0x302b
-#define HDMI_PHY_I2CM_SS_SCL_HCNT_0_ADDR 0x302c
-#define HDMI_PHY_I2CM_SS_SCL_LCNT_1_ADDR 0x302d
-#define HDMI_PHY_I2CM_SS_SCL_LCNT_0_ADDR 0x302e
-#define HDMI_PHY_I2CM_FS_SCL_HCNT_1_ADDR 0x302f
-#define HDMI_PHY_I2CM_FS_SCL_HCNT_0_ADDR 0x3030
-#define HDMI_PHY_I2CM_FS_SCL_LCNT_1_ADDR 0x3031
-#define HDMI_PHY_I2CM_FS_SCL_LCNT_0_ADDR 0x3032
-
-/* Audio Sampler Registers */
-#define HDMI_AUD_CONF0 0x3100
-#define HDMI_AUD_CONF1 0x3101
-#define HDMI_AUD_INT 0x3102
-#define HDMI_AUD_CONF2 0x3103
-#define HDMI_AUD_N1 0x3200
-#define HDMI_AUD_N2 0x3201
-#define HDMI_AUD_N3 0x3202
-#define HDMI_AUD_CTS1 0x3203
-#define HDMI_AUD_CTS2 0x3204
-#define HDMI_AUD_CTS3 0x3205
-#define HDMI_AUD_INPUTCLKFS 0x3206
-#define HDMI_AUD_SPDIFINT 0x3302
-#define HDMI_AUD_CONF0_HBR 0x3400
-#define HDMI_AUD_HBR_STATUS 0x3401
-#define HDMI_AUD_HBR_INT 0x3402
-#define HDMI_AUD_HBR_POL 0x3403
-#define HDMI_AUD_HBR_MASK 0x3404
-
-/*
- * Generic Parallel Audio Interface Registers
- * Not used as GPAUD interface is not enabled in hw
- */
-#define HDMI_GP_CONF0 0x3500
-#define HDMI_GP_CONF1 0x3501
-#define HDMI_GP_CONF2 0x3502
-#define HDMI_GP_STAT 0x3503
-#define HDMI_GP_INT 0x3504
-#define HDMI_GP_MASK 0x3505
-#define HDMI_GP_POL 0x3506
-
-/* Audio DMA Registers */
-#define HDMI_AHB_DMA_CONF0 0x3600
-#define HDMI_AHB_DMA_START 0x3601
-#define HDMI_AHB_DMA_STOP 0x3602
-#define HDMI_AHB_DMA_THRSLD 0x3603
-#define HDMI_AHB_DMA_STRADDR0 0x3604
-#define HDMI_AHB_DMA_STRADDR1 0x3605
-#define HDMI_AHB_DMA_STRADDR2 0x3606
-#define HDMI_AHB_DMA_STRADDR3 0x3607
-#define HDMI_AHB_DMA_STPADDR0 0x3608
-#define HDMI_AHB_DMA_STPADDR1 0x3609
-#define HDMI_AHB_DMA_STPADDR2 0x360a
-#define HDMI_AHB_DMA_STPADDR3 0x360b
-#define HDMI_AHB_DMA_BSTADDR0 0x360c
-#define HDMI_AHB_DMA_BSTADDR1 0x360d
-#define HDMI_AHB_DMA_BSTADDR2 0x360e
-#define HDMI_AHB_DMA_BSTADDR3 0x360f
-#define HDMI_AHB_DMA_MBLENGTH0 0x3610
-#define HDMI_AHB_DMA_MBLENGTH1 0x3611
-#define HDMI_AHB_DMA_STAT 0x3612
-#define HDMI_AHB_DMA_INT 0x3613
-#define HDMI_AHB_DMA_MASK 0x3614
-#define HDMI_AHB_DMA_POL 0x3615
-#define HDMI_AHB_DMA_CONF1 0x3616
-#define HDMI_AHB_DMA_BUFFSTAT 0x3617
-#define HDMI_AHB_DMA_BUFFINT 0x3618
-#define HDMI_AHB_DMA_BUFFMASK 0x3619
-#define HDMI_AHB_DMA_BUFFPOL 0x361a
-
-/* Main Controller Registers */
-#define HDMI_MC_SFRDIV 0x4000
-#define HDMI_MC_CLKDIS 0x4001
-#define HDMI_MC_SWRSTZ 0x4002
-#define HDMI_MC_OPCTRL 0x4003
-#define HDMI_MC_FLOWCTRL 0x4004
-#define HDMI_MC_PHYRSTZ 0x4005
-#define HDMI_MC_LOCKONCLOCK 0x4006
-#define HDMI_MC_HEACPHY_RST 0x4007
-
-/* Color Space Converter Registers */
-#define HDMI_CSC_CFG 0x4100
-#define HDMI_CSC_SCALE 0x4101
-#define HDMI_CSC_COEF_A1_MSB 0x4102
-#define HDMI_CSC_COEF_A1_LSB 0x4103
-#define HDMI_CSC_COEF_A2_MSB 0x4104
-#define HDMI_CSC_COEF_A2_LSB 0x4105
-#define HDMI_CSC_COEF_A3_MSB 0x4106
-#define HDMI_CSC_COEF_A3_LSB 0x4107
-#define HDMI_CSC_COEF_A4_MSB 0x4108
-#define HDMI_CSC_COEF_A4_LSB 0x4109
-#define HDMI_CSC_COEF_B1_MSB 0x410A
-#define HDMI_CSC_COEF_B1_LSB 0x410B
-#define HDMI_CSC_COEF_B2_MSB 0x410C
-#define HDMI_CSC_COEF_B2_LSB 0x410D
-#define HDMI_CSC_COEF_B3_MSB 0x410E
-#define HDMI_CSC_COEF_B3_LSB 0x410F
-#define HDMI_CSC_COEF_B4_MSB 0x4110
-#define HDMI_CSC_COEF_B4_LSB 0x4111
-#define HDMI_CSC_COEF_C1_MSB 0x4112
-#define HDMI_CSC_COEF_C1_LSB 0x4113
-#define HDMI_CSC_COEF_C2_MSB 0x4114
-#define HDMI_CSC_COEF_C2_LSB 0x4115
-#define HDMI_CSC_COEF_C3_MSB 0x4116
-#define HDMI_CSC_COEF_C3_LSB 0x4117
-#define HDMI_CSC_COEF_C4_MSB 0x4118
-#define HDMI_CSC_COEF_C4_LSB 0x4119
-
-/* HDCP Encryption Engine Registers */
-#define HDMI_A_HDCPCFG0 0x5000
-#define HDMI_A_HDCPCFG1 0x5001
-#define HDMI_A_HDCPOBS0 0x5002
-#define HDMI_A_HDCPOBS1 0x5003
-#define HDMI_A_HDCPOBS2 0x5004
-#define HDMI_A_HDCPOBS3 0x5005
-#define HDMI_A_APIINTCLR 0x5006
-#define HDMI_A_APIINTSTAT 0x5007
-#define HDMI_A_APIINTMSK 0x5008
-#define HDMI_A_VIDPOLCFG 0x5009
-#define HDMI_A_OESSWCFG 0x500A
-#define HDMI_A_TIMER1SETUP0 0x500B
-#define HDMI_A_TIMER1SETUP1 0x500C
-#define HDMI_A_TIMER2SETUP0 0x500D
-#define HDMI_A_TIMER2SETUP1 0x500E
-#define HDMI_A_100MSCFG 0x500F
-#define HDMI_A_2SCFG0 0x5010
-#define HDMI_A_2SCFG1 0x5011
-#define HDMI_A_5SCFG0 0x5012
-#define HDMI_A_5SCFG1 0x5013
-#define HDMI_A_SRMVERLSB 0x5014
-#define HDMI_A_SRMVERMSB 0x5015
-#define HDMI_A_SRMCTRL 0x5016
-#define HDMI_A_SFRSETUP 0x5017
-#define HDMI_A_I2CHSETUP 0x5018
-#define HDMI_A_INTSETUP 0x5019
-#define HDMI_A_PRESETUP 0x501A
-#define HDMI_A_SRM_BASE 0x5020
-
-/* CEC Engine Registers */
-#define HDMI_CEC_CTRL 0x7D00
-#define HDMI_CEC_STAT 0x7D01
-#define HDMI_CEC_MASK 0x7D02
-#define HDMI_CEC_POLARITY 0x7D03
-#define HDMI_CEC_INT 0x7D04
-#define HDMI_CEC_ADDR_L 0x7D05
-#define HDMI_CEC_ADDR_H 0x7D06
-#define HDMI_CEC_TX_CNT 0x7D07
-#define HDMI_CEC_RX_CNT 0x7D08
-#define HDMI_CEC_TX_DATA0 0x7D10
-#define HDMI_CEC_TX_DATA1 0x7D11
-#define HDMI_CEC_TX_DATA2 0x7D12
-#define HDMI_CEC_TX_DATA3 0x7D13
-#define HDMI_CEC_TX_DATA4 0x7D14
-#define HDMI_CEC_TX_DATA5 0x7D15
-#define HDMI_CEC_TX_DATA6 0x7D16
-#define HDMI_CEC_TX_DATA7 0x7D17
-#define HDMI_CEC_TX_DATA8 0x7D18
-#define HDMI_CEC_TX_DATA9 0x7D19
-#define HDMI_CEC_TX_DATA10 0x7D1a
-#define HDMI_CEC_TX_DATA11 0x7D1b
-#define HDMI_CEC_TX_DATA12 0x7D1c
-#define HDMI_CEC_TX_DATA13 0x7D1d
-#define HDMI_CEC_TX_DATA14 0x7D1e
-#define HDMI_CEC_TX_DATA15 0x7D1f
-#define HDMI_CEC_RX_DATA0 0x7D20
-#define HDMI_CEC_RX_DATA1 0x7D21
-#define HDMI_CEC_RX_DATA2 0x7D22
-#define HDMI_CEC_RX_DATA3 0x7D23
-#define HDMI_CEC_RX_DATA4 0x7D24
-#define HDMI_CEC_RX_DATA5 0x7D25
-#define HDMI_CEC_RX_DATA6 0x7D26
-#define HDMI_CEC_RX_DATA7 0x7D27
-#define HDMI_CEC_RX_DATA8 0x7D28
-#define HDMI_CEC_RX_DATA9 0x7D29
-#define HDMI_CEC_RX_DATA10 0x7D2a
-#define HDMI_CEC_RX_DATA11 0x7D2b
-#define HDMI_CEC_RX_DATA12 0x7D2c
-#define HDMI_CEC_RX_DATA13 0x7D2d
-#define HDMI_CEC_RX_DATA14 0x7D2e
-#define HDMI_CEC_RX_DATA15 0x7D2f
-#define HDMI_CEC_LOCK 0x7D30
-#define HDMI_CEC_WKUPCTRL 0x7D31
-
-/* I2C Master Registers (E-DDC) */
-#define HDMI_I2CM_SLAVE 0x7E00
-#define HDMI_I2CMESS 0x7E01
-#define HDMI_I2CM_DATAO 0x7E02
-#define HDMI_I2CM_DATAI 0x7E03
-#define HDMI_I2CM_OPERATION 0x7E04
-#define HDMI_I2CM_INT 0x7E05
-#define HDMI_I2CM_CTLINT 0x7E06
-#define HDMI_I2CM_DIV 0x7E07
-#define HDMI_I2CM_SEGADDR 0x7E08
-#define HDMI_I2CM_SOFTRSTZ 0x7E09
-#define HDMI_I2CM_SEGPTR 0x7E0A
-#define HDMI_I2CM_SS_SCL_HCNT_1_ADDR 0x7E0B
-#define HDMI_I2CM_SS_SCL_HCNT_0_ADDR 0x7E0C
-#define HDMI_I2CM_SS_SCL_LCNT_1_ADDR 0x7E0D
-#define HDMI_I2CM_SS_SCL_LCNT_0_ADDR 0x7E0E
-#define HDMI_I2CM_FS_SCL_HCNT_1_ADDR 0x7E0F
-#define HDMI_I2CM_FS_SCL_HCNT_0_ADDR 0x7E10
-#define HDMI_I2CM_FS_SCL_LCNT_1_ADDR 0x7E11
-#define HDMI_I2CM_FS_SCL_LCNT_0_ADDR 0x7E12
-
-enum {
-/* IH_FC_INT2 field values */
- HDMI_IH_FC_INT2_OVERFLOW_MASK = 0x03,
- HDMI_IH_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
- HDMI_IH_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_FC_STAT2 field values */
- HDMI_IH_FC_STAT2_OVERFLOW_MASK = 0x03,
- HDMI_IH_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
- HDMI_IH_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_PHY_STAT0 field values */
- HDMI_IH_PHY_STAT0_RX_SENSE3 = 0x20,
- HDMI_IH_PHY_STAT0_RX_SENSE2 = 0x10,
- HDMI_IH_PHY_STAT0_RX_SENSE1 = 0x8,
- HDMI_IH_PHY_STAT0_RX_SENSE0 = 0x4,
- HDMI_IH_PHY_STAT0_TX_PHY_LOCK = 0x2,
- HDMI_IH_PHY_STAT0_HPD = 0x1,
-
-/* IH_MUTE_I2CMPHY_STAT0 field values */
- HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYDONE = 0x2,
- HDMI_IH_MUTE_I2CMPHY_STAT0_I2CMPHYERROR = 0x1,
-
-/* IH_AHBDMAAUD_STAT0 field values */
- HDMI_IH_AHBDMAAUD_STAT0_ERROR = 0x20,
- HDMI_IH_AHBDMAAUD_STAT0_LOST = 0x10,
- HDMI_IH_AHBDMAAUD_STAT0_RETRY = 0x08,
- HDMI_IH_AHBDMAAUD_STAT0_DONE = 0x04,
- HDMI_IH_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
- HDMI_IH_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
-
-/* IH_MUTE_FC_STAT2 field values */
- HDMI_IH_MUTE_FC_STAT2_OVERFLOW_MASK = 0x03,
- HDMI_IH_MUTE_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
- HDMI_IH_MUTE_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* IH_MUTE_AHBDMAAUD_STAT0 field values */
- HDMI_IH_MUTE_AHBDMAAUD_STAT0_ERROR = 0x20,
- HDMI_IH_MUTE_AHBDMAAUD_STAT0_LOST = 0x10,
- HDMI_IH_MUTE_AHBDMAAUD_STAT0_RETRY = 0x08,
- HDMI_IH_MUTE_AHBDMAAUD_STAT0_DONE = 0x04,
- HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFFULL = 0x02,
- HDMI_IH_MUTE_AHBDMAAUD_STAT0_BUFFEMPTY = 0x01,
-
-/* IH_MUTE field values */
- HDMI_IH_MUTE_MUTE_WAKEUP_INTERRUPT = 0x2,
- HDMI_IH_MUTE_MUTE_ALL_INTERRUPT = 0x1,
-
-/* TX_INVID0 field values */
- HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_MASK = 0x80,
- HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_ENABLE = 0x80,
- HDMI_TX_INVID0_INTERNAL_DE_GENERATOR_DISABLE = 0x00,
- HDMI_TX_INVID0_VIDEO_MAPPING_MASK = 0x1F,
- HDMI_TX_INVID0_VIDEO_MAPPING_OFFSET = 0,
-
-/* TX_INSTUFFING field values */
- HDMI_TX_INSTUFFING_BDBDATA_STUFFING_MASK = 0x4,
- HDMI_TX_INSTUFFING_BDBDATA_STUFFING_ENABLE = 0x4,
- HDMI_TX_INSTUFFING_BDBDATA_STUFFING_DISABLE = 0x0,
- HDMI_TX_INSTUFFING_RCRDATA_STUFFING_MASK = 0x2,
- HDMI_TX_INSTUFFING_RCRDATA_STUFFING_ENABLE = 0x2,
- HDMI_TX_INSTUFFING_RCRDATA_STUFFING_DISABLE = 0x0,
- HDMI_TX_INSTUFFING_GYDATA_STUFFING_MASK = 0x1,
- HDMI_TX_INSTUFFING_GYDATA_STUFFING_ENABLE = 0x1,
- HDMI_TX_INSTUFFING_GYDATA_STUFFING_DISABLE = 0x0,
-
-/* VP_PR_CD field values */
- HDMI_VP_PR_CD_COLOR_DEPTH_MASK = 0xF0,
- HDMI_VP_PR_CD_COLOR_DEPTH_OFFSET = 4,
- HDMI_VP_PR_CD_DESIRED_PR_FACTOR_MASK = 0x0F,
- HDMI_VP_PR_CD_DESIRED_PR_FACTOR_OFFSET = 0,
-
-/* VP_STUFF field values */
- HDMI_VP_STUFF_IDEFAULT_PHASE_MASK = 0x20,
- HDMI_VP_STUFF_IDEFAULT_PHASE_OFFSET = 5,
- HDMI_VP_STUFF_IFIX_PP_TO_LAST_MASK = 0x10,
- HDMI_VP_STUFF_IFIX_PP_TO_LAST_OFFSET = 4,
- HDMI_VP_STUFF_ICX_GOTO_P0_ST_MASK = 0x8,
- HDMI_VP_STUFF_ICX_GOTO_P0_ST_OFFSET = 3,
- HDMI_VP_STUFF_YCC422_STUFFING_MASK = 0x4,
- HDMI_VP_STUFF_YCC422_STUFFING_STUFFING_MODE = 0x4,
- HDMI_VP_STUFF_YCC422_STUFFING_DIRECT_MODE = 0x0,
- HDMI_VP_STUFF_PP_STUFFING_MASK = 0x2,
- HDMI_VP_STUFF_PP_STUFFING_STUFFING_MODE = 0x2,
- HDMI_VP_STUFF_PP_STUFFING_DIRECT_MODE = 0x0,
- HDMI_VP_STUFF_PR_STUFFING_MASK = 0x1,
- HDMI_VP_STUFF_PR_STUFFING_STUFFING_MODE = 0x1,
- HDMI_VP_STUFF_PR_STUFFING_DIRECT_MODE = 0x0,
-
-/* VP_CONF field values */
- HDMI_VP_CONF_BYPASS_EN_MASK = 0x40,
- HDMI_VP_CONF_BYPASS_EN_ENABLE = 0x40,
- HDMI_VP_CONF_BYPASS_EN_DISABLE = 0x00,
- HDMI_VP_CONF_PP_EN_ENMASK = 0x20,
- HDMI_VP_CONF_PP_EN_ENABLE = 0x20,
- HDMI_VP_CONF_PP_EN_DISABLE = 0x00,
- HDMI_VP_CONF_PR_EN_MASK = 0x10,
- HDMI_VP_CONF_PR_EN_ENABLE = 0x10,
- HDMI_VP_CONF_PR_EN_DISABLE = 0x00,
- HDMI_VP_CONF_YCC422_EN_MASK = 0x8,
- HDMI_VP_CONF_YCC422_EN_ENABLE = 0x8,
- HDMI_VP_CONF_YCC422_EN_DISABLE = 0x0,
- HDMI_VP_CONF_BYPASS_SELECT_MASK = 0x4,
- HDMI_VP_CONF_BYPASS_SELECT_VID_PACKETIZER = 0x4,
- HDMI_VP_CONF_BYPASS_SELECT_PIX_REPEATER = 0x0,
- HDMI_VP_CONF_OUTPUT_SELECTOR_MASK = 0x3,
- HDMI_VP_CONF_OUTPUT_SELECTOR_BYPASS = 0x3,
- HDMI_VP_CONF_OUTPUT_SELECTOR_YCC422 = 0x1,
- HDMI_VP_CONF_OUTPUT_SELECTOR_PP = 0x0,
-
-/* VP_REMAP field values */
- HDMI_VP_REMAP_MASK = 0x3,
- HDMI_VP_REMAP_YCC422_24bit = 0x2,
- HDMI_VP_REMAP_YCC422_20bit = 0x1,
- HDMI_VP_REMAP_YCC422_16bit = 0x0,
-
-/* FC_INVIDCONF field values */
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_MASK = 0x80,
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_ACTIVE = 0x80,
- HDMI_FC_INVIDCONF_HDCP_KEEPOUT_INACTIVE = 0x00,
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_MASK = 0x40,
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_HIGH = 0x40,
- HDMI_FC_INVIDCONF_VSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_MASK = 0x20,
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_HIGH = 0x20,
- HDMI_FC_INVIDCONF_HSYNC_IN_POLARITY_ACTIVE_LOW = 0x00,
- HDMI_FC_INVIDCONF_DE_IN_POLARITY_MASK = 0x10,
- HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_HIGH = 0x10,
- HDMI_FC_INVIDCONF_DE_IN_POLARITY_ACTIVE_LOW = 0x00,
- HDMI_FC_INVIDCONF_DVI_MODEZ_MASK = 0x8,
- HDMI_FC_INVIDCONF_DVI_MODEZ_HDMI_MODE = 0x8,
- HDMI_FC_INVIDCONF_DVI_MODEZ_DVI_MODE = 0x0,
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_MASK = 0x2,
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_HIGH = 0x2,
- HDMI_FC_INVIDCONF_R_V_BLANK_IN_OSC_ACTIVE_LOW = 0x0,
- HDMI_FC_INVIDCONF_IN_I_P_MASK = 0x1,
- HDMI_FC_INVIDCONF_IN_I_P_INTERLACED = 0x1,
- HDMI_FC_INVIDCONF_IN_I_P_PROGRESSIVE = 0x0,
-
-/* FC_AUDICONF0 field values */
- HDMI_FC_AUDICONF0_CC_OFFSET = 4,
- HDMI_FC_AUDICONF0_CC_MASK = 0x70,
- HDMI_FC_AUDICONF0_CT_OFFSET = 0,
- HDMI_FC_AUDICONF0_CT_MASK = 0xF,
-
-/* FC_AUDICONF1 field values */
- HDMI_FC_AUDICONF1_SS_OFFSET = 3,
- HDMI_FC_AUDICONF1_SS_MASK = 0x18,
- HDMI_FC_AUDICONF1_SF_OFFSET = 0,
- HDMI_FC_AUDICONF1_SF_MASK = 0x7,
-
-/* FC_AUDICONF3 field values */
- HDMI_FC_AUDICONF3_LFEPBL_OFFSET = 5,
- HDMI_FC_AUDICONF3_LFEPBL_MASK = 0x60,
- HDMI_FC_AUDICONF3_DM_INH_OFFSET = 4,
- HDMI_FC_AUDICONF3_DM_INH_MASK = 0x10,
- HDMI_FC_AUDICONF3_LSV_OFFSET = 0,
- HDMI_FC_AUDICONF3_LSV_MASK = 0xF,
-
-/* FC_AUDSCHNLS0 field values */
- HDMI_FC_AUDSCHNLS0_CGMSA_OFFSET = 4,
- HDMI_FC_AUDSCHNLS0_CGMSA_MASK = 0x30,
- HDMI_FC_AUDSCHNLS0_COPYRIGHT_OFFSET = 0,
- HDMI_FC_AUDSCHNLS0_COPYRIGHT_MASK = 0x01,
-
-/* FC_AUDSCHNLS3-6 field values */
- HDMI_FC_AUDSCHNLS3_OIEC_CH0_OFFSET = 0,
- HDMI_FC_AUDSCHNLS3_OIEC_CH0_MASK = 0x0f,
- HDMI_FC_AUDSCHNLS3_OIEC_CH1_OFFSET = 4,
- HDMI_FC_AUDSCHNLS3_OIEC_CH1_MASK = 0xf0,
- HDMI_FC_AUDSCHNLS4_OIEC_CH2_OFFSET = 0,
- HDMI_FC_AUDSCHNLS4_OIEC_CH2_MASK = 0x0f,
- HDMI_FC_AUDSCHNLS4_OIEC_CH3_OFFSET = 4,
- HDMI_FC_AUDSCHNLS4_OIEC_CH3_MASK = 0xf0,
-
- HDMI_FC_AUDSCHNLS5_OIEC_CH0_OFFSET = 0,
- HDMI_FC_AUDSCHNLS5_OIEC_CH0_MASK = 0x0f,
- HDMI_FC_AUDSCHNLS5_OIEC_CH1_OFFSET = 4,
- HDMI_FC_AUDSCHNLS5_OIEC_CH1_MASK = 0xf0,
- HDMI_FC_AUDSCHNLS6_OIEC_CH2_OFFSET = 0,
- HDMI_FC_AUDSCHNLS6_OIEC_CH2_MASK = 0x0f,
- HDMI_FC_AUDSCHNLS6_OIEC_CH3_OFFSET = 4,
- HDMI_FC_AUDSCHNLS6_OIEC_CH3_MASK = 0xf0,
-
-/* HDMI_FC_AUDSCHNLS7 field values */
- HDMI_FC_AUDSCHNLS7_ACCURACY_OFFSET = 4,
- HDMI_FC_AUDSCHNLS7_ACCURACY_MASK = 0x30,
-
-/* HDMI_FC_AUDSCHNLS8 field values */
- HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_MASK = 0xf0,
- HDMI_FC_AUDSCHNLS8_ORIGSAMPFREQ_OFFSET = 4,
- HDMI_FC_AUDSCHNLS8_WORDLEGNTH_MASK = 0x0f,
- HDMI_FC_AUDSCHNLS8_WORDLEGNTH_OFFSET = 0,
-
-/* FC_AUDSCONF field values */
- HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_MASK = 0xF0,
- HDMI_FC_AUDSCONF_AUD_PACKET_SAMPFIT_OFFSET = 4,
- HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_MASK = 0x1,
- HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_OFFSET = 0,
- HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT1 = 0x1,
- HDMI_FC_AUDSCONF_AUD_PACKET_LAYOUT_LAYOUT0 = 0x0,
-
-/* FC_STAT2 field values */
- HDMI_FC_STAT2_OVERFLOW_MASK = 0x03,
- HDMI_FC_STAT2_LOW_PRIORITY_OVERFLOW = 0x02,
- HDMI_FC_STAT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_INT2 field values */
- HDMI_FC_INT2_OVERFLOW_MASK = 0x03,
- HDMI_FC_INT2_LOW_PRIORITY_OVERFLOW = 0x02,
- HDMI_FC_INT2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_MASK2 field values */
- HDMI_FC_MASK2_OVERFLOW_MASK = 0x03,
- HDMI_FC_MASK2_LOW_PRIORITY_OVERFLOW = 0x02,
- HDMI_FC_MASK2_HIGH_PRIORITY_OVERFLOW = 0x01,
-
-/* FC_PRCONF field values */
- HDMI_FC_PRCONF_INCOMING_PR_FACTOR_MASK = 0xF0,
- HDMI_FC_PRCONF_INCOMING_PR_FACTOR_OFFSET = 4,
- HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_MASK = 0x0F,
- HDMI_FC_PRCONF_OUTPUT_PR_FACTOR_OFFSET = 0,
-
-/* FC_AVICONF0-FC_AVICONF3 field values */
- HDMI_FC_AVICONF0_PIX_FMT_MASK = 0x03,
- HDMI_FC_AVICONF0_PIX_FMT_RGB = 0x00,
- HDMI_FC_AVICONF0_PIX_FMT_YCBCR422 = 0x01,
- HDMI_FC_AVICONF0_PIX_FMT_YCBCR444 = 0x02,
- HDMI_FC_AVICONF0_ACTIVE_FMT_MASK = 0x40,
- HDMI_FC_AVICONF0_ACTIVE_FMT_INFO_PRESENT = 0x40,
- HDMI_FC_AVICONF0_ACTIVE_FMT_NO_INFO = 0x00,
- HDMI_FC_AVICONF0_BAR_DATA_MASK = 0x0C,
- HDMI_FC_AVICONF0_BAR_DATA_NO_DATA = 0x00,
- HDMI_FC_AVICONF0_BAR_DATA_VERT_BAR = 0x04,
- HDMI_FC_AVICONF0_BAR_DATA_HORIZ_BAR = 0x08,
- HDMI_FC_AVICONF0_BAR_DATA_VERT_HORIZ_BAR = 0x0C,
- HDMI_FC_AVICONF0_SCAN_INFO_MASK = 0x30,
- HDMI_FC_AVICONF0_SCAN_INFO_OVERSCAN = 0x10,
- HDMI_FC_AVICONF0_SCAN_INFO_UNDERSCAN = 0x20,
- HDMI_FC_AVICONF0_SCAN_INFO_NODATA = 0x00,
-
- HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_MASK = 0x0F,
- HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_USE_CODED = 0x08,
- HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_4_3 = 0x09,
- HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_16_9 = 0x0A,
- HDMI_FC_AVICONF1_ACTIVE_ASPECT_RATIO_14_9 = 0x0B,
- HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_MASK = 0x30,
- HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_NO_DATA = 0x00,
- HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_4_3 = 0x10,
- HDMI_FC_AVICONF1_CODED_ASPECT_RATIO_16_9 = 0x20,
- HDMI_FC_AVICONF1_COLORIMETRY_MASK = 0xC0,
- HDMI_FC_AVICONF1_COLORIMETRY_NO_DATA = 0x00,
- HDMI_FC_AVICONF1_COLORIMETRY_SMPTE = 0x40,
- HDMI_FC_AVICONF1_COLORIMETRY_ITUR = 0x80,
- HDMI_FC_AVICONF1_COLORIMETRY_EXTENDED_INFO = 0xC0,
-
- HDMI_FC_AVICONF2_SCALING_MASK = 0x03,
- HDMI_FC_AVICONF2_SCALING_NONE = 0x00,
- HDMI_FC_AVICONF2_SCALING_HORIZ = 0x01,
- HDMI_FC_AVICONF2_SCALING_VERT = 0x02,
- HDMI_FC_AVICONF2_SCALING_HORIZ_VERT = 0x03,
- HDMI_FC_AVICONF2_RGB_QUANT_MASK = 0x0C,
- HDMI_FC_AVICONF2_RGB_QUANT_DEFAULT = 0x00,
- HDMI_FC_AVICONF2_RGB_QUANT_LIMITED_RANGE = 0x04,
- HDMI_FC_AVICONF2_RGB_QUANT_FULL_RANGE = 0x08,
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_MASK = 0x70,
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC601 = 0x00,
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_XVYCC709 = 0x10,
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_SYCC601 = 0x20,
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_YCC601 = 0x30,
- HDMI_FC_AVICONF2_EXT_COLORIMETRY_ADOBE_RGB = 0x40,
- HDMI_FC_AVICONF2_IT_CONTENT_MASK = 0x80,
- HDMI_FC_AVICONF2_IT_CONTENT_NO_DATA = 0x00,
- HDMI_FC_AVICONF2_IT_CONTENT_VALID = 0x80,
-
- HDMI_FC_AVICONF3_IT_CONTENT_TYPE_MASK = 0x03,
- HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GRAPHICS = 0x00,
- HDMI_FC_AVICONF3_IT_CONTENT_TYPE_PHOTO = 0x01,
- HDMI_FC_AVICONF3_IT_CONTENT_TYPE_CINEMA = 0x02,
- HDMI_FC_AVICONF3_IT_CONTENT_TYPE_GAME = 0x03,
- HDMI_FC_AVICONF3_QUANT_RANGE_MASK = 0x0C,
- HDMI_FC_AVICONF3_QUANT_RANGE_LIMITED = 0x00,
- HDMI_FC_AVICONF3_QUANT_RANGE_FULL = 0x04,
-
-/* FC_DBGFORCE field values */
- HDMI_FC_DBGFORCE_FORCEAUDIO = 0x10,
- HDMI_FC_DBGFORCE_FORCEVIDEO = 0x1,
-
-/* PHY_CONF0 field values */
- HDMI_PHY_CONF0_PDZ_MASK = 0x80,
- HDMI_PHY_CONF0_PDZ_OFFSET = 7,
- HDMI_PHY_CONF0_ENTMDS_MASK = 0x40,
- HDMI_PHY_CONF0_ENTMDS_OFFSET = 6,
- HDMI_PHY_CONF0_SPARECTRL = 0x20,
- HDMI_PHY_CONF0_GEN2_PDDQ_MASK = 0x10,
- HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET = 4,
- HDMI_PHY_CONF0_GEN2_TXPWRON_MASK = 0x8,
- HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET = 3,
- HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_MASK = 0x4,
- HDMI_PHY_CONF0_GEN2_ENHPDRXSENSE_OFFSET = 2,
- HDMI_PHY_CONF0_SELDATAENPOL_MASK = 0x2,
- HDMI_PHY_CONF0_SELDATAENPOL_OFFSET = 1,
- HDMI_PHY_CONF0_SELDIPIF_MASK = 0x1,
- HDMI_PHY_CONF0_SELDIPIF_OFFSET = 0,
-
-/* PHY_TST0 field values */
- HDMI_PHY_TST0_TSTCLR_MASK = 0x20,
- HDMI_PHY_TST0_TSTCLR_OFFSET = 5,
- HDMI_PHY_TST0_TSTEN_MASK = 0x10,
- HDMI_PHY_TST0_TSTEN_OFFSET = 4,
- HDMI_PHY_TST0_TSTCLK_MASK = 0x1,
- HDMI_PHY_TST0_TSTCLK_OFFSET = 0,
-
-/* PHY_STAT0 field values */
- HDMI_PHY_RX_SENSE3 = 0x80,
- HDMI_PHY_RX_SENSE2 = 0x40,
- HDMI_PHY_RX_SENSE1 = 0x20,
- HDMI_PHY_RX_SENSE0 = 0x10,
- HDMI_PHY_HPD = 0x02,
- HDMI_PHY_TX_PHY_LOCK = 0x01,
-
-/* PHY_I2CM_SLAVE_ADDR field values */
- HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2 = 0x69,
- HDMI_PHY_I2CM_SLAVE_ADDR_HEAC_PHY = 0x49,
-
-/* PHY_I2CM_OPERATION_ADDR field values */
- HDMI_PHY_I2CM_OPERATION_ADDR_WRITE = 0x10,
- HDMI_PHY_I2CM_OPERATION_ADDR_READ = 0x1,
-
-/* HDMI_PHY_I2CM_INT_ADDR */
- HDMI_PHY_I2CM_INT_ADDR_DONE_POL = 0x08,
- HDMI_PHY_I2CM_INT_ADDR_DONE_MASK = 0x04,
-
-/* HDMI_PHY_I2CM_CTLINT_ADDR */
- HDMI_PHY_I2CM_CTLINT_ADDR_NAC_POL = 0x80,
- HDMI_PHY_I2CM_CTLINT_ADDR_NAC_MASK = 0x40,
- HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_POL = 0x08,
- HDMI_PHY_I2CM_CTLINT_ADDR_ARBITRATION_MASK = 0x04,
-
-/* AUD_CTS3 field values */
- HDMI_AUD_CTS3_N_SHIFT_OFFSET = 5,
- HDMI_AUD_CTS3_N_SHIFT_MASK = 0xe0,
- HDMI_AUD_CTS3_N_SHIFT_1 = 0,
- HDMI_AUD_CTS3_N_SHIFT_16 = 0x20,
- HDMI_AUD_CTS3_N_SHIFT_32 = 0x40,
- HDMI_AUD_CTS3_N_SHIFT_64 = 0x60,
- HDMI_AUD_CTS3_N_SHIFT_128 = 0x80,
- HDMI_AUD_CTS3_N_SHIFT_256 = 0xa0,
- /* note that the CTS3 MANUAL bit has been removed
- from our part. Can't set it, will read as 0. */
- HDMI_AUD_CTS3_CTS_MANUAL = 0x10,
- HDMI_AUD_CTS3_AUDCTS19_16_MASK = 0x0f,
-
-/* AHB_DMA_CONF0 field values */
- HDMI_AHB_DMA_CONF0_SW_FIFO_RST_OFFSET = 7,
- HDMI_AHB_DMA_CONF0_SW_FIFO_RST_MASK = 0x80,
- HDMI_AHB_DMA_CONF0_HBR = 0x10,
- HDMI_AHB_DMA_CONF0_EN_HLOCK_OFFSET = 3,
- HDMI_AHB_DMA_CONF0_EN_HLOCK_MASK = 0x08,
- HDMI_AHB_DMA_CONF0_INCR_TYPE_OFFSET = 1,
- HDMI_AHB_DMA_CONF0_INCR_TYPE_MASK = 0x06,
- HDMI_AHB_DMA_CONF0_INCR4 = 0x0,
- HDMI_AHB_DMA_CONF0_INCR8 = 0x2,
- HDMI_AHB_DMA_CONF0_INCR16 = 0x4,
- HDMI_AHB_DMA_CONF0_BURST_MODE = 0x1,
-
-/* HDMI_AHB_DMA_START field values */
- HDMI_AHB_DMA_START_START_OFFSET = 0,
- HDMI_AHB_DMA_START_START_MASK = 0x01,
-
-/* HDMI_AHB_DMA_STOP field values */
- HDMI_AHB_DMA_STOP_STOP_OFFSET = 0,
- HDMI_AHB_DMA_STOP_STOP_MASK = 0x01,
-
-/* AHB_DMA_STAT, AHB_DMA_INT, AHB_DMA_MASK, AHB_DMA_POL field values */
- HDMI_AHB_DMA_DONE = 0x80,
- HDMI_AHB_DMA_RETRY_SPLIT = 0x40,
- HDMI_AHB_DMA_LOSTOWNERSHIP = 0x20,
- HDMI_AHB_DMA_ERROR = 0x10,
- HDMI_AHB_DMA_FIFO_THREMPTY = 0x04,
- HDMI_AHB_DMA_FIFO_FULL = 0x02,
- HDMI_AHB_DMA_FIFO_EMPTY = 0x01,
-
-/* AHB_DMA_BUFFSTAT, AHB_DMA_BUFFINT,AHB_DMA_BUFFMASK,AHB_DMA_BUFFPOL values */
- HDMI_AHB_DMA_BUFFSTAT_FULL = 0x02,
- HDMI_AHB_DMA_BUFFSTAT_EMPTY = 0x01,
-
-/* MC_CLKDIS field values */
- HDMI_MC_CLKDIS_HDCPCLK_DISABLE = 0x40,
- HDMI_MC_CLKDIS_CECCLK_DISABLE = 0x20,
- HDMI_MC_CLKDIS_CSCCLK_DISABLE = 0x10,
- HDMI_MC_CLKDIS_AUDCLK_DISABLE = 0x8,
- HDMI_MC_CLKDIS_PREPCLK_DISABLE = 0x4,
- HDMI_MC_CLKDIS_TMDSCLK_DISABLE = 0x2,
- HDMI_MC_CLKDIS_PIXELCLK_DISABLE = 0x1,
-
-/* MC_SWRSTZ field values */
- HDMI_MC_SWRSTZ_TMDSSWRST_REQ = 0x02,
-
-/* MC_FLOWCTRL field values */
- HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_MASK = 0x1,
- HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_IN_PATH = 0x1,
- HDMI_MC_FLOWCTRL_FEED_THROUGH_OFF_CSC_BYPASS = 0x0,
-
-/* MC_PHYRSTZ field values */
- HDMI_MC_PHYRSTZ_ASSERT = 0x0,
- HDMI_MC_PHYRSTZ_DEASSERT = 0x1,
-
-/* MC_HEACPHY_RST field values */
- HDMI_MC_HEACPHY_RST_ASSERT = 0x1,
- HDMI_MC_HEACPHY_RST_DEASSERT = 0x0,
-
-/* CSC_CFG field values */
- HDMI_CSC_CFG_INTMODE_MASK = 0x30,
- HDMI_CSC_CFG_INTMODE_OFFSET = 4,
- HDMI_CSC_CFG_INTMODE_DISABLE = 0x00,
- HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA1 = 0x10,
- HDMI_CSC_CFG_INTMODE_CHROMA_INT_FORMULA2 = 0x20,
- HDMI_CSC_CFG_DECMODE_MASK = 0x3,
- HDMI_CSC_CFG_DECMODE_OFFSET = 0,
- HDMI_CSC_CFG_DECMODE_DISABLE = 0x0,
- HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA1 = 0x1,
- HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA2 = 0x2,
- HDMI_CSC_CFG_DECMODE_CHROMA_INT_FORMULA3 = 0x3,
-
-/* CSC_SCALE field values */
- HDMI_CSC_SCALE_CSC_COLORDE_PTH_MASK = 0xF0,
- HDMI_CSC_SCALE_CSC_COLORDE_PTH_24BPP = 0x00,
- HDMI_CSC_SCALE_CSC_COLORDE_PTH_30BPP = 0x50,
- HDMI_CSC_SCALE_CSC_COLORDE_PTH_36BPP = 0x60,
- HDMI_CSC_SCALE_CSC_COLORDE_PTH_48BPP = 0x70,
- HDMI_CSC_SCALE_CSCSCALE_MASK = 0x03,
-
-/* A_HDCPCFG0 field values */
- HDMI_A_HDCPCFG0_ELVENA_MASK = 0x80,
- HDMI_A_HDCPCFG0_ELVENA_ENABLE = 0x80,
- HDMI_A_HDCPCFG0_ELVENA_DISABLE = 0x00,
- HDMI_A_HDCPCFG0_I2CFASTMODE_MASK = 0x40,
- HDMI_A_HDCPCFG0_I2CFASTMODE_ENABLE = 0x40,
- HDMI_A_HDCPCFG0_I2CFASTMODE_DISABLE = 0x00,
- HDMI_A_HDCPCFG0_BYPENCRYPTION_MASK = 0x20,
- HDMI_A_HDCPCFG0_BYPENCRYPTION_ENABLE = 0x20,
- HDMI_A_HDCPCFG0_BYPENCRYPTION_DISABLE = 0x00,
- HDMI_A_HDCPCFG0_SYNCRICHECK_MASK = 0x10,
- HDMI_A_HDCPCFG0_SYNCRICHECK_ENABLE = 0x10,
- HDMI_A_HDCPCFG0_SYNCRICHECK_DISABLE = 0x00,
- HDMI_A_HDCPCFG0_AVMUTE_MASK = 0x8,
- HDMI_A_HDCPCFG0_AVMUTE_ENABLE = 0x8,
- HDMI_A_HDCPCFG0_AVMUTE_DISABLE = 0x0,
- HDMI_A_HDCPCFG0_RXDETECT_MASK = 0x4,
- HDMI_A_HDCPCFG0_RXDETECT_ENABLE = 0x4,
- HDMI_A_HDCPCFG0_RXDETECT_DISABLE = 0x0,
- HDMI_A_HDCPCFG0_EN11FEATURE_MASK = 0x2,
- HDMI_A_HDCPCFG0_EN11FEATURE_ENABLE = 0x2,
- HDMI_A_HDCPCFG0_EN11FEATURE_DISABLE = 0x0,
- HDMI_A_HDCPCFG0_HDMIDVI_MASK = 0x1,
- HDMI_A_HDCPCFG0_HDMIDVI_HDMI = 0x1,
- HDMI_A_HDCPCFG0_HDMIDVI_DVI = 0x0,
-
-/* A_HDCPCFG1 field values */
- HDMI_A_HDCPCFG1_DISSHA1CHECK_MASK = 0x8,
- HDMI_A_HDCPCFG1_DISSHA1CHECK_DISABLE = 0x8,
- HDMI_A_HDCPCFG1_DISSHA1CHECK_ENABLE = 0x0,
- HDMI_A_HDCPCFG1_PH2UPSHFTENC_MASK = 0x4,
- HDMI_A_HDCPCFG1_PH2UPSHFTENC_ENABLE = 0x4,
- HDMI_A_HDCPCFG1_PH2UPSHFTENC_DISABLE = 0x0,
- HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_MASK = 0x2,
- HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_DISABLE = 0x2,
- HDMI_A_HDCPCFG1_ENCRYPTIONDISABLE_ENABLE = 0x0,
- HDMI_A_HDCPCFG1_SWRESET_MASK = 0x1,
- HDMI_A_HDCPCFG1_SWRESET_ASSERT = 0x0,
-
-/* A_VIDPOLCFG field values */
- HDMI_A_VIDPOLCFG_UNENCRYPTCONF_MASK = 0x60,
- HDMI_A_VIDPOLCFG_UNENCRYPTCONF_OFFSET = 5,
- HDMI_A_VIDPOLCFG_DATAENPOL_MASK = 0x10,
- HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_HIGH = 0x10,
- HDMI_A_VIDPOLCFG_DATAENPOL_ACTIVE_LOW = 0x0,
- HDMI_A_VIDPOLCFG_VSYNCPOL_MASK = 0x8,
- HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_HIGH = 0x8,
- HDMI_A_VIDPOLCFG_VSYNCPOL_ACTIVE_LOW = 0x0,
- HDMI_A_VIDPOLCFG_HSYNCPOL_MASK = 0x2,
- HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_HIGH = 0x2,
- HDMI_A_VIDPOLCFG_HSYNCPOL_ACTIVE_LOW = 0x0,
-};
-#endif /* __IMX_HDMI_H__ */
diff --git a/drivers/gpu/drm/imx/imx-ldb.c b/drivers/gpu/drm/imx/imx-ldb.c
index c60460043e24..1b86aac0b341 100644
--- a/drivers/gpu/drm/imx/imx-ldb.c
+++ b/drivers/gpu/drm/imx/imx-ldb.c
@@ -163,7 +163,7 @@ static void imx_ldb_encoder_prepare(struct drm_encoder *encoder)
{
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
- struct drm_display_mode *mode = &encoder->crtc->mode;
+ struct drm_display_mode *mode = &encoder->crtc->hwmode;
u32 pixel_fmt;
unsigned long serial_clk;
unsigned long di_clk = mode->clock * 1000;
@@ -241,8 +241,8 @@ static void imx_ldb_encoder_commit(struct drm_encoder *encoder)
}
static void imx_ldb_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
{
struct imx_ldb_channel *imx_ldb_ch = enc_to_imx_ldb_ch(encoder);
struct imx_ldb *ldb = imx_ldb_ch->ldb;
@@ -574,6 +574,8 @@ static void imx_ldb_unbind(struct device *dev, struct device *master,
channel->connector.funcs->destroy(&channel->connector);
channel->encoder.funcs->destroy(&channel->encoder);
+
+ kfree(channel->edid);
}
}
diff --git a/drivers/gpu/drm/imx/imx-tve.c b/drivers/gpu/drm/imx/imx-tve.c
index a729f4f7074c..4216e479a9be 100644
--- a/drivers/gpu/drm/imx/imx-tve.c
+++ b/drivers/gpu/drm/imx/imx-tve.c
@@ -191,10 +191,18 @@ static int tve_setup_vga(struct imx_tve *tve)
/* set gain to (1 + 10/128) to provide 0.7V peak-to-peak amplitude */
ret = regmap_update_bits(tve->regmap, TVE_TVDAC0_CONT_REG,
TVE_TVDAC_GAIN_MASK, 0x0a);
+ if (ret)
+ return ret;
+
ret = regmap_update_bits(tve->regmap, TVE_TVDAC1_CONT_REG,
TVE_TVDAC_GAIN_MASK, 0x0a);
+ if (ret)
+ return ret;
+
ret = regmap_update_bits(tve->regmap, TVE_TVDAC2_CONT_REG,
TVE_TVDAC_GAIN_MASK, 0x0a);
+ if (ret)
+ return ret;
/* set configuration register */
mask = TVE_DATA_SOURCE_MASK | TVE_INP_VIDEO_FORM;
@@ -204,16 +212,12 @@ static int tve_setup_vga(struct imx_tve *tve)
mask |= TVE_TV_OUT_MODE_MASK | TVE_SYNC_CH_0_EN;
val |= TVE_TV_OUT_RGB | TVE_SYNC_CH_0_EN;
ret = regmap_update_bits(tve->regmap, TVE_COM_CONF_REG, mask, val);
- if (ret < 0) {
- dev_err(tve->dev, "failed to set configuration: %d\n", ret);
+ if (ret)
return ret;
- }
/* set test mode (as documented) */
- ret = regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
+ return regmap_update_bits(tve->regmap, TVE_TST_MODE_REG,
TVE_TVDAC_TEST_MODE_MASK, 1);
-
- return 0;
}
static enum drm_connector_status imx_tve_connector_detect(
@@ -307,8 +311,8 @@ static void imx_tve_encoder_prepare(struct drm_encoder *encoder)
}
static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
{
struct imx_tve *tve = enc_to_tve(encoder);
unsigned long rounded_rate;
@@ -335,9 +339,11 @@ static void imx_tve_encoder_mode_set(struct drm_encoder *encoder,
}
if (tve->mode == TVE_MODE_VGA)
- tve_setup_vga(tve);
+ ret = tve_setup_vga(tve);
else
- tve_setup_tvout(tve);
+ ret = tve_setup_tvout(tve);
+ if (ret)
+ dev_err(tve->dev, "failed to set configuration: %d\n", ret);
}
static void imx_tve_encoder_commit(struct drm_encoder *encoder)
@@ -671,6 +677,8 @@ static int imx_tve_bind(struct device *dev, struct device *master, void *data)
/* disable cable detection for VGA mode */
ret = regmap_write(tve->regmap, TVE_CD_CONT_REG, 0);
+ if (ret)
+ return ret;
ret = imx_tve_register(drm, tve);
if (ret)
diff --git a/drivers/gpu/drm/imx/ipuv3-crtc.c b/drivers/gpu/drm/imx/ipuv3-crtc.c
index ebee59cb96d8..98551e356e12 100644
--- a/drivers/gpu/drm/imx/ipuv3-crtc.c
+++ b/drivers/gpu/drm/imx/ipuv3-crtc.c
@@ -46,7 +46,6 @@ struct ipu_crtc {
struct drm_framebuffer *newfb;
int irq;
u32 interface_pix_fmt;
- unsigned long di_clkflags;
int di_hsync_pin;
int di_vsync_pin;
};
@@ -141,47 +140,51 @@ static int ipu_crtc_mode_set(struct drm_crtc *crtc,
int x, int y,
struct drm_framebuffer *old_fb)
{
+ struct drm_device *dev = crtc->dev;
+ struct drm_encoder *encoder;
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
- int ret;
struct ipu_di_signal_cfg sig_cfg = {};
+ unsigned long encoder_types = 0;
u32 out_pixel_fmt;
+ int ret;
dev_dbg(ipu_crtc->dev, "%s: mode->hdisplay: %d\n", __func__,
mode->hdisplay);
dev_dbg(ipu_crtc->dev, "%s: mode->vdisplay: %d\n", __func__,
mode->vdisplay);
- out_pixel_fmt = ipu_crtc->interface_pix_fmt;
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head)
+ if (encoder->crtc == crtc)
+ encoder_types |= BIT(encoder->encoder_type);
- if (mode->flags & DRM_MODE_FLAG_INTERLACE)
- sig_cfg.interlaced = 1;
- if (mode->flags & DRM_MODE_FLAG_PHSYNC)
- sig_cfg.Hsync_pol = 1;
- if (mode->flags & DRM_MODE_FLAG_PVSYNC)
- sig_cfg.Vsync_pol = 1;
+ dev_dbg(ipu_crtc->dev, "%s: attached to encoder types 0x%lx\n",
+ __func__, encoder_types);
+
+ /*
+ * If we have DAC, TVDAC or LDB, then we need the IPU DI clock
+ * to be the same as the LDB DI clock.
+ */
+ if (encoder_types & (BIT(DRM_MODE_ENCODER_DAC) |
+ BIT(DRM_MODE_ENCODER_TVDAC) |
+ BIT(DRM_MODE_ENCODER_LVDS)))
+ sig_cfg.clkflags = IPU_DI_CLKMODE_SYNC | IPU_DI_CLKMODE_EXT;
+ else
+ sig_cfg.clkflags = 0;
+
+ out_pixel_fmt = ipu_crtc->interface_pix_fmt;
sig_cfg.enable_pol = 1;
sig_cfg.clk_pol = 0;
- sig_cfg.width = mode->hdisplay;
- sig_cfg.height = mode->vdisplay;
sig_cfg.pixel_fmt = out_pixel_fmt;
- sig_cfg.h_start_width = mode->htotal - mode->hsync_end;
- sig_cfg.h_sync_width = mode->hsync_end - mode->hsync_start;
- sig_cfg.h_end_width = mode->hsync_start - mode->hdisplay;
-
- sig_cfg.v_start_width = mode->vtotal - mode->vsync_end;
- sig_cfg.v_sync_width = mode->vsync_end - mode->vsync_start;
- sig_cfg.v_end_width = mode->vsync_start - mode->vdisplay;
- sig_cfg.pixelclock = mode->clock * 1000;
- sig_cfg.clkflags = ipu_crtc->di_clkflags;
-
sig_cfg.v_to_h_sync = 0;
-
sig_cfg.hsync_pin = ipu_crtc->di_hsync_pin;
sig_cfg.vsync_pin = ipu_crtc->di_vsync_pin;
- ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di, sig_cfg.interlaced,
- out_pixel_fmt, mode->hdisplay);
+ drm_display_mode_to_videomode(mode, &sig_cfg.mode);
+
+ ret = ipu_dc_init_sync(ipu_crtc->dc, ipu_crtc->di,
+ mode->flags & DRM_MODE_FLAG_INTERLACE,
+ out_pixel_fmt, mode->hdisplay);
if (ret) {
dev_err(ipu_crtc->dev,
"initializing display controller failed with %d\n",
@@ -237,6 +240,18 @@ static bool ipu_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
+ struct videomode vm;
+ int ret;
+
+ drm_display_mode_to_videomode(adjusted_mode, &vm);
+
+ ret = ipu_di_adjust_videomode(ipu_crtc->di, &vm);
+ if (ret)
+ return false;
+
+ drm_display_mode_from_videomode(&vm, adjusted_mode);
+
return true;
}
@@ -275,7 +290,7 @@ static void ipu_disable_vblank(struct drm_crtc *crtc)
ipu_crtc->newfb = NULL;
}
-static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
+static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc,
u32 pixfmt, int hsync_pin, int vsync_pin)
{
struct ipu_crtc *ipu_crtc = to_ipu_crtc(crtc);
@@ -284,19 +299,6 @@ static int ipu_set_interface_pix_fmt(struct drm_crtc *crtc, u32 encoder_type,
ipu_crtc->di_hsync_pin = hsync_pin;
ipu_crtc->di_vsync_pin = vsync_pin;
- switch (encoder_type) {
- case DRM_MODE_ENCODER_DAC:
- case DRM_MODE_ENCODER_TVDAC:
- case DRM_MODE_ENCODER_LVDS:
- ipu_crtc->di_clkflags = IPU_DI_CLKMODE_SYNC |
- IPU_DI_CLKMODE_EXT;
- break;
- case DRM_MODE_ENCODER_TMDS:
- case DRM_MODE_ENCODER_NONE:
- ipu_crtc->di_clkflags = 0;
- break;
- }
-
return 0;
}
diff --git a/drivers/gpu/drm/imx/parallel-display.c b/drivers/gpu/drm/imx/parallel-display.c
index 796c3c1c170a..5e83e007080f 100644
--- a/drivers/gpu/drm/imx/parallel-display.c
+++ b/drivers/gpu/drm/imx/parallel-display.c
@@ -130,8 +130,8 @@ static void imx_pd_encoder_commit(struct drm_encoder *encoder)
}
static void imx_pd_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
+ struct drm_display_mode *orig_mode,
+ struct drm_display_mode *mode)
{
}
@@ -257,6 +257,8 @@ static void imx_pd_unbind(struct device *dev, struct device *master,
imxpd->encoder.funcs->destroy(&imxpd->encoder);
imxpd->connector.funcs->destroy(&imxpd->connector);
+
+ kfree(imxpd->edid);
}
static const struct component_ops imx_pd_ops = {
@@ -272,6 +274,7 @@ static int imx_pd_probe(struct platform_device *pdev)
static int imx_pd_remove(struct platform_device *pdev)
{
component_del(&pdev->dev, &imx_pd_ops);
+
return 0;
}
diff --git a/drivers/gpu/drm/mgag200/mgag200_fb.c b/drivers/gpu/drm/mgag200/mgag200_fb.c
index 4415af3666ab..c36b8304042b 100644
--- a/drivers/gpu/drm/mgag200/mgag200_fb.c
+++ b/drivers/gpu/drm/mgag200/mgag200_fb.c
@@ -303,14 +303,22 @@ int mgag200_fbdev_init(struct mga_device *mdev)
if (ret)
return ret;
- drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
+ ret = drm_fb_helper_single_add_all_connectors(&mfbdev->helper);
+ if (ret)
+ goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(mdev->dev);
- drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
+ ret = drm_fb_helper_initial_config(&mfbdev->helper, bpp_sel);
+ if (ret)
+ goto fini;
return 0;
+
+fini:
+ drm_fb_helper_fini(&mfbdev->helper);
+ return ret;
}
void mgag200_fbdev_fini(struct mga_device *mdev)
diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig
index 5b2a1ff95d3d..bacbbb70f679 100644
--- a/drivers/gpu/drm/msm/Kconfig
+++ b/drivers/gpu/drm/msm/Kconfig
@@ -3,6 +3,7 @@ config DRM_MSM
tristate "MSM DRM"
depends on DRM
depends on ARCH_QCOM || (ARM && COMPILE_TEST)
+ depends on OF && COMMON_CLK
select REGULATOR
select DRM_KMS_HELPER
select DRM_PANEL
diff --git a/drivers/gpu/drm/msm/Makefile b/drivers/gpu/drm/msm/Makefile
index 143d988f8add..674a132fd76e 100644
--- a/drivers/gpu/drm/msm/Makefile
+++ b/drivers/gpu/drm/msm/Makefile
@@ -1,7 +1,4 @@
ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/msm
-ifeq (, $(findstring -W,$(EXTRA_CFLAGS)))
- ccflags-y += -Werror
-endif
msm-y := \
adreno/adreno_device.o \
@@ -16,6 +13,12 @@ msm-y := \
hdmi/hdmi_phy_8960.o \
hdmi/hdmi_phy_8x60.o \
hdmi/hdmi_phy_8x74.o \
+ edp/edp.o \
+ edp/edp_aux.o \
+ edp/edp_bridge.o \
+ edp/edp_connector.o \
+ edp/edp_ctrl.o \
+ edp/edp_phy.o \
mdp/mdp_format.o \
mdp/mdp_kms.o \
mdp/mdp4/mdp4_crtc.o \
diff --git a/drivers/gpu/drm/msm/adreno/a2xx.xml.h b/drivers/gpu/drm/msm/adreno/a2xx.xml.h
index 22882cc0a573..edc845fffdf4 100644
--- a/drivers/gpu/drm/msm/adreno/a2xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a2xx.xml.h
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/adreno/a3xx.xml.h b/drivers/gpu/drm/msm/adreno/a3xx.xml.h
index 109e9a263daf..e91a739452d7 100644
--- a/drivers/gpu/drm/msm/adreno/a3xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a3xx.xml.h
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@@ -58,111 +58,130 @@ enum a3xx_cache_opcode {
};
enum a3xx_vtx_fmt {
- VFMT_FLOAT_32 = 0,
- VFMT_FLOAT_32_32 = 1,
- VFMT_FLOAT_32_32_32 = 2,
- VFMT_FLOAT_32_32_32_32 = 3,
- VFMT_FLOAT_16 = 4,
- VFMT_FLOAT_16_16 = 5,
- VFMT_FLOAT_16_16_16 = 6,
- VFMT_FLOAT_16_16_16_16 = 7,
- VFMT_FIXED_32 = 8,
- VFMT_FIXED_32_32 = 9,
- VFMT_FIXED_32_32_32 = 10,
- VFMT_FIXED_32_32_32_32 = 11,
- VFMT_SHORT_16 = 16,
- VFMT_SHORT_16_16 = 17,
- VFMT_SHORT_16_16_16 = 18,
- VFMT_SHORT_16_16_16_16 = 19,
- VFMT_USHORT_16 = 20,
- VFMT_USHORT_16_16 = 21,
- VFMT_USHORT_16_16_16 = 22,
- VFMT_USHORT_16_16_16_16 = 23,
- VFMT_NORM_SHORT_16 = 24,
- VFMT_NORM_SHORT_16_16 = 25,
- VFMT_NORM_SHORT_16_16_16 = 26,
- VFMT_NORM_SHORT_16_16_16_16 = 27,
- VFMT_NORM_USHORT_16 = 28,
- VFMT_NORM_USHORT_16_16 = 29,
- VFMT_NORM_USHORT_16_16_16 = 30,
- VFMT_NORM_USHORT_16_16_16_16 = 31,
- VFMT_UINT_32 = 32,
- VFMT_UINT_32_32 = 33,
- VFMT_UINT_32_32_32 = 34,
- VFMT_UINT_32_32_32_32 = 35,
- VFMT_INT_32 = 36,
- VFMT_INT_32_32 = 37,
- VFMT_INT_32_32_32 = 38,
- VFMT_INT_32_32_32_32 = 39,
- VFMT_UBYTE_8 = 40,
- VFMT_UBYTE_8_8 = 41,
- VFMT_UBYTE_8_8_8 = 42,
- VFMT_UBYTE_8_8_8_8 = 43,
- VFMT_NORM_UBYTE_8 = 44,
- VFMT_NORM_UBYTE_8_8 = 45,
- VFMT_NORM_UBYTE_8_8_8 = 46,
- VFMT_NORM_UBYTE_8_8_8_8 = 47,
- VFMT_BYTE_8 = 48,
- VFMT_BYTE_8_8 = 49,
- VFMT_BYTE_8_8_8 = 50,
- VFMT_BYTE_8_8_8_8 = 51,
- VFMT_NORM_BYTE_8 = 52,
- VFMT_NORM_BYTE_8_8 = 53,
- VFMT_NORM_BYTE_8_8_8 = 54,
- VFMT_NORM_BYTE_8_8_8_8 = 55,
- VFMT_UINT_10_10_10_2 = 60,
- VFMT_NORM_UINT_10_10_10_2 = 61,
- VFMT_INT_10_10_10_2 = 62,
- VFMT_NORM_INT_10_10_10_2 = 63,
+ VFMT_32_FLOAT = 0,
+ VFMT_32_32_FLOAT = 1,
+ VFMT_32_32_32_FLOAT = 2,
+ VFMT_32_32_32_32_FLOAT = 3,
+ VFMT_16_FLOAT = 4,
+ VFMT_16_16_FLOAT = 5,
+ VFMT_16_16_16_FLOAT = 6,
+ VFMT_16_16_16_16_FLOAT = 7,
+ VFMT_32_FIXED = 8,
+ VFMT_32_32_FIXED = 9,
+ VFMT_32_32_32_FIXED = 10,
+ VFMT_32_32_32_32_FIXED = 11,
+ VFMT_16_SINT = 16,
+ VFMT_16_16_SINT = 17,
+ VFMT_16_16_16_SINT = 18,
+ VFMT_16_16_16_16_SINT = 19,
+ VFMT_16_UINT = 20,
+ VFMT_16_16_UINT = 21,
+ VFMT_16_16_16_UINT = 22,
+ VFMT_16_16_16_16_UINT = 23,
+ VFMT_16_SNORM = 24,
+ VFMT_16_16_SNORM = 25,
+ VFMT_16_16_16_SNORM = 26,
+ VFMT_16_16_16_16_SNORM = 27,
+ VFMT_16_UNORM = 28,
+ VFMT_16_16_UNORM = 29,
+ VFMT_16_16_16_UNORM = 30,
+ VFMT_16_16_16_16_UNORM = 31,
+ VFMT_32_UINT = 32,
+ VFMT_32_32_UINT = 33,
+ VFMT_32_32_32_UINT = 34,
+ VFMT_32_32_32_32_UINT = 35,
+ VFMT_32_SINT = 36,
+ VFMT_32_32_SINT = 37,
+ VFMT_32_32_32_SINT = 38,
+ VFMT_32_32_32_32_SINT = 39,
+ VFMT_8_UINT = 40,
+ VFMT_8_8_UINT = 41,
+ VFMT_8_8_8_UINT = 42,
+ VFMT_8_8_8_8_UINT = 43,
+ VFMT_8_UNORM = 44,
+ VFMT_8_8_UNORM = 45,
+ VFMT_8_8_8_UNORM = 46,
+ VFMT_8_8_8_8_UNORM = 47,
+ VFMT_8_SINT = 48,
+ VFMT_8_8_SINT = 49,
+ VFMT_8_8_8_SINT = 50,
+ VFMT_8_8_8_8_SINT = 51,
+ VFMT_8_SNORM = 52,
+ VFMT_8_8_SNORM = 53,
+ VFMT_8_8_8_SNORM = 54,
+ VFMT_8_8_8_8_SNORM = 55,
+ VFMT_10_10_10_2_UINT = 60,
+ VFMT_10_10_10_2_UNORM = 61,
+ VFMT_10_10_10_2_SINT = 62,
+ VFMT_10_10_10_2_SNORM = 63,
};
enum a3xx_tex_fmt {
- TFMT_NORM_USHORT_565 = 4,
- TFMT_NORM_USHORT_5551 = 6,
- TFMT_NORM_USHORT_4444 = 7,
- TFMT_NORM_USHORT_Z16 = 9,
- TFMT_NORM_UINT_X8Z24 = 10,
- TFMT_FLOAT_Z32 = 11,
- TFMT_NORM_UINT_NV12_UV_TILED = 17,
- TFMT_NORM_UINT_NV12_Y_TILED = 19,
- TFMT_NORM_UINT_NV12_UV = 21,
- TFMT_NORM_UINT_NV12_Y = 23,
- TFMT_NORM_UINT_I420_Y = 24,
- TFMT_NORM_UINT_I420_U = 26,
- TFMT_NORM_UINT_I420_V = 27,
- TFMT_NORM_UINT_2_10_10_10 = 41,
- TFMT_FLOAT_9_9_9_E5 = 42,
- TFMT_FLOAT_10_11_11 = 43,
- TFMT_NORM_UINT_A8 = 44,
- TFMT_NORM_UINT_L8_A8 = 47,
- TFMT_NORM_UINT_8 = 48,
- TFMT_NORM_UINT_8_8 = 49,
- TFMT_NORM_UINT_8_8_8 = 50,
- TFMT_NORM_UINT_8_8_8_8 = 51,
- TFMT_NORM_SINT_8_8 = 53,
- TFMT_NORM_SINT_8_8_8_8 = 55,
- TFMT_UINT_8_8 = 57,
- TFMT_UINT_8_8_8_8 = 59,
- TFMT_SINT_8_8 = 61,
- TFMT_SINT_8_8_8_8 = 63,
- TFMT_FLOAT_16 = 64,
- TFMT_FLOAT_16_16 = 65,
- TFMT_FLOAT_16_16_16_16 = 67,
- TFMT_UINT_16 = 68,
- TFMT_UINT_16_16 = 69,
- TFMT_UINT_16_16_16_16 = 71,
- TFMT_SINT_16 = 72,
- TFMT_SINT_16_16 = 73,
- TFMT_SINT_16_16_16_16 = 75,
- TFMT_FLOAT_32 = 84,
- TFMT_FLOAT_32_32 = 85,
- TFMT_FLOAT_32_32_32_32 = 87,
- TFMT_UINT_32 = 88,
- TFMT_UINT_32_32 = 89,
- TFMT_UINT_32_32_32_32 = 91,
- TFMT_SINT_32 = 92,
- TFMT_SINT_32_32 = 93,
- TFMT_SINT_32_32_32_32 = 95,
+ TFMT_5_6_5_UNORM = 4,
+ TFMT_5_5_5_1_UNORM = 5,
+ TFMT_4_4_4_4_UNORM = 7,
+ TFMT_Z16_UNORM = 9,
+ TFMT_X8Z24_UNORM = 10,
+ TFMT_Z32_FLOAT = 11,
+ TFMT_NV12_UV_TILED = 17,
+ TFMT_NV12_Y_TILED = 19,
+ TFMT_NV12_UV = 21,
+ TFMT_NV12_Y = 23,
+ TFMT_I420_Y = 24,
+ TFMT_I420_U = 26,
+ TFMT_I420_V = 27,
+ TFMT_DXT1 = 36,
+ TFMT_DXT3 = 37,
+ TFMT_DXT5 = 38,
+ TFMT_10_10_10_2_UNORM = 41,
+ TFMT_9_9_9_E5_FLOAT = 42,
+ TFMT_11_11_10_FLOAT = 43,
+ TFMT_A8_UNORM = 44,
+ TFMT_L8_A8_UNORM = 47,
+ TFMT_8_UNORM = 48,
+ TFMT_8_8_UNORM = 49,
+ TFMT_8_8_8_UNORM = 50,
+ TFMT_8_8_8_8_UNORM = 51,
+ TFMT_8_SNORM = 52,
+ TFMT_8_8_SNORM = 53,
+ TFMT_8_8_8_SNORM = 54,
+ TFMT_8_8_8_8_SNORM = 55,
+ TFMT_8_UINT = 56,
+ TFMT_8_8_UINT = 57,
+ TFMT_8_8_8_UINT = 58,
+ TFMT_8_8_8_8_UINT = 59,
+ TFMT_8_SINT = 60,
+ TFMT_8_8_SINT = 61,
+ TFMT_8_8_8_SINT = 62,
+ TFMT_8_8_8_8_SINT = 63,
+ TFMT_16_FLOAT = 64,
+ TFMT_16_16_FLOAT = 65,
+ TFMT_16_16_16_16_FLOAT = 67,
+ TFMT_16_UINT = 68,
+ TFMT_16_16_UINT = 69,
+ TFMT_16_16_16_16_UINT = 71,
+ TFMT_16_SINT = 72,
+ TFMT_16_16_SINT = 73,
+ TFMT_16_16_16_16_SINT = 75,
+ TFMT_16_UNORM = 76,
+ TFMT_16_16_UNORM = 77,
+ TFMT_16_16_16_16_UNORM = 79,
+ TFMT_16_SNORM = 80,
+ TFMT_16_16_SNORM = 81,
+ TFMT_16_16_16_16_SNORM = 83,
+ TFMT_32_FLOAT = 84,
+ TFMT_32_32_FLOAT = 85,
+ TFMT_32_32_32_32_FLOAT = 87,
+ TFMT_32_UINT = 88,
+ TFMT_32_32_UINT = 89,
+ TFMT_32_32_32_32_UINT = 91,
+ TFMT_32_SINT = 92,
+ TFMT_32_32_SINT = 93,
+ TFMT_32_32_32_32_SINT = 95,
+ TFMT_RGTC2_SNORM = 112,
+ TFMT_RGTC2_UNORM = 113,
+ TFMT_RGTC1_SNORM = 114,
+ TFMT_RGTC1_UNORM = 115,
};
enum a3xx_tex_fetchsize {
@@ -180,9 +199,11 @@ enum a3xx_color_fmt {
RB_R4G4B4A4_UNORM = 3,
RB_R8G8B8_UNORM = 4,
RB_R8G8B8A8_UNORM = 8,
+ RB_R8G8B8A8_SNORM = 9,
RB_R8G8B8A8_UINT = 10,
RB_R8G8B8A8_SINT = 11,
RB_R8G8_UNORM = 12,
+ RB_R8G8_SNORM = 13,
RB_R8_UINT = 14,
RB_R8_SINT = 15,
RB_R10G10B10A2_UNORM = 16,
@@ -258,6 +279,14 @@ enum a3xx_tex_clamp {
A3XX_TEX_MIRROR_CLAMP = 4,
};
+enum a3xx_tex_aniso {
+ A3XX_TEX_ANISO_1 = 0,
+ A3XX_TEX_ANISO_2 = 1,
+ A3XX_TEX_ANISO_4 = 2,
+ A3XX_TEX_ANISO_8 = 3,
+ A3XX_TEX_ANISO_16 = 4,
+};
+
enum a3xx_tex_swiz {
A3XX_TEX_X = 0,
A3XX_TEX_Y = 1,
@@ -1563,12 +1592,13 @@ static inline uint32_t A3XX_VFD_FETCH_INSTR_0_FETCHSIZE(uint32_t val)
{
return ((val) << A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_FETCHSIZE__MASK;
}
-#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK 0x0001ff80
+#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK 0x0000ff80
#define A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT 7
static inline uint32_t A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE(uint32_t val)
{
return ((val) << A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT) & A3XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK;
}
+#define A3XX_VFD_FETCH_INSTR_0_INSTANCED 0x00010000
#define A3XX_VFD_FETCH_INSTR_0_SWITCHNEXT 0x00020000
#define A3XX_VFD_FETCH_INSTR_0_INDEXCODE__MASK 0x00fc0000
#define A3XX_VFD_FETCH_INSTR_0_INDEXCODE__SHIFT 18
@@ -2509,6 +2539,12 @@ static inline uint32_t A3XX_TEX_SAMP_0_WRAP_R(enum a3xx_tex_clamp val)
{
return ((val) << A3XX_TEX_SAMP_0_WRAP_R__SHIFT) & A3XX_TEX_SAMP_0_WRAP_R__MASK;
}
+#define A3XX_TEX_SAMP_0_ANISO__MASK 0x00038000
+#define A3XX_TEX_SAMP_0_ANISO__SHIFT 15
+static inline uint32_t A3XX_TEX_SAMP_0_ANISO(enum a3xx_tex_aniso val)
+{
+ return ((val) << A3XX_TEX_SAMP_0_ANISO__SHIFT) & A3XX_TEX_SAMP_0_ANISO__MASK;
+}
#define A3XX_TEX_SAMP_0_COMPARE_FUNC__MASK 0x00700000
#define A3XX_TEX_SAMP_0_COMPARE_FUNC__SHIFT 20
static inline uint32_t A3XX_TEX_SAMP_0_COMPARE_FUNC(enum adreno_compare_func val)
diff --git a/drivers/gpu/drm/msm/adreno/a4xx.xml.h b/drivers/gpu/drm/msm/adreno/a4xx.xml.h
index 5a24c416d2dd..755723fd8ba5 100644
--- a/drivers/gpu/drm/msm/adreno/a4xx.xml.h
+++ b/drivers/gpu/drm/msm/adreno/a4xx.xml.h
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@@ -63,72 +63,82 @@ enum a4xx_rb_blend_opcode {
};
enum a4xx_vtx_fmt {
- VFMT4_FLOAT_32 = 1,
- VFMT4_FLOAT_32_32 = 2,
- VFMT4_FLOAT_32_32_32 = 3,
- VFMT4_FLOAT_32_32_32_32 = 4,
- VFMT4_FLOAT_16 = 5,
- VFMT4_FLOAT_16_16 = 6,
- VFMT4_FLOAT_16_16_16 = 7,
- VFMT4_FLOAT_16_16_16_16 = 8,
- VFMT4_FIXED_32 = 9,
- VFMT4_FIXED_32_32 = 10,
- VFMT4_FIXED_32_32_32 = 11,
- VFMT4_FIXED_32_32_32_32 = 12,
- VFMT4_SHORT_16 = 16,
- VFMT4_SHORT_16_16 = 17,
- VFMT4_SHORT_16_16_16 = 18,
- VFMT4_SHORT_16_16_16_16 = 19,
- VFMT4_USHORT_16 = 20,
- VFMT4_USHORT_16_16 = 21,
- VFMT4_USHORT_16_16_16 = 22,
- VFMT4_USHORT_16_16_16_16 = 23,
- VFMT4_NORM_SHORT_16 = 24,
- VFMT4_NORM_SHORT_16_16 = 25,
- VFMT4_NORM_SHORT_16_16_16 = 26,
- VFMT4_NORM_SHORT_16_16_16_16 = 27,
- VFMT4_NORM_USHORT_16 = 28,
- VFMT4_NORM_USHORT_16_16 = 29,
- VFMT4_NORM_USHORT_16_16_16 = 30,
- VFMT4_NORM_USHORT_16_16_16_16 = 31,
- VFMT4_UBYTE_8 = 40,
- VFMT4_UBYTE_8_8 = 41,
- VFMT4_UBYTE_8_8_8 = 42,
- VFMT4_UBYTE_8_8_8_8 = 43,
- VFMT4_NORM_UBYTE_8 = 44,
- VFMT4_NORM_UBYTE_8_8 = 45,
- VFMT4_NORM_UBYTE_8_8_8 = 46,
- VFMT4_NORM_UBYTE_8_8_8_8 = 47,
- VFMT4_BYTE_8 = 48,
- VFMT4_BYTE_8_8 = 49,
- VFMT4_BYTE_8_8_8 = 50,
- VFMT4_BYTE_8_8_8_8 = 51,
- VFMT4_NORM_BYTE_8 = 52,
- VFMT4_NORM_BYTE_8_8 = 53,
- VFMT4_NORM_BYTE_8_8_8 = 54,
- VFMT4_NORM_BYTE_8_8_8_8 = 55,
- VFMT4_UINT_10_10_10_2 = 60,
- VFMT4_NORM_UINT_10_10_10_2 = 61,
- VFMT4_INT_10_10_10_2 = 62,
- VFMT4_NORM_INT_10_10_10_2 = 63,
+ VFMT4_32_FLOAT = 1,
+ VFMT4_32_32_FLOAT = 2,
+ VFMT4_32_32_32_FLOAT = 3,
+ VFMT4_32_32_32_32_FLOAT = 4,
+ VFMT4_16_FLOAT = 5,
+ VFMT4_16_16_FLOAT = 6,
+ VFMT4_16_16_16_FLOAT = 7,
+ VFMT4_16_16_16_16_FLOAT = 8,
+ VFMT4_32_FIXED = 9,
+ VFMT4_32_32_FIXED = 10,
+ VFMT4_32_32_32_FIXED = 11,
+ VFMT4_32_32_32_32_FIXED = 12,
+ VFMT4_16_SINT = 16,
+ VFMT4_16_16_SINT = 17,
+ VFMT4_16_16_16_SINT = 18,
+ VFMT4_16_16_16_16_SINT = 19,
+ VFMT4_16_UINT = 20,
+ VFMT4_16_16_UINT = 21,
+ VFMT4_16_16_16_UINT = 22,
+ VFMT4_16_16_16_16_UINT = 23,
+ VFMT4_16_SNORM = 24,
+ VFMT4_16_16_SNORM = 25,
+ VFMT4_16_16_16_SNORM = 26,
+ VFMT4_16_16_16_16_SNORM = 27,
+ VFMT4_16_UNORM = 28,
+ VFMT4_16_16_UNORM = 29,
+ VFMT4_16_16_16_UNORM = 30,
+ VFMT4_16_16_16_16_UNORM = 31,
+ VFMT4_32_32_SINT = 37,
+ VFMT4_8_UINT = 40,
+ VFMT4_8_8_UINT = 41,
+ VFMT4_8_8_8_UINT = 42,
+ VFMT4_8_8_8_8_UINT = 43,
+ VFMT4_8_UNORM = 44,
+ VFMT4_8_8_UNORM = 45,
+ VFMT4_8_8_8_UNORM = 46,
+ VFMT4_8_8_8_8_UNORM = 47,
+ VFMT4_8_SINT = 48,
+ VFMT4_8_8_SINT = 49,
+ VFMT4_8_8_8_SINT = 50,
+ VFMT4_8_8_8_8_SINT = 51,
+ VFMT4_8_SNORM = 52,
+ VFMT4_8_8_SNORM = 53,
+ VFMT4_8_8_8_SNORM = 54,
+ VFMT4_8_8_8_8_SNORM = 55,
+ VFMT4_10_10_10_2_UINT = 60,
+ VFMT4_10_10_10_2_UNORM = 61,
+ VFMT4_10_10_10_2_SINT = 62,
+ VFMT4_10_10_10_2_SNORM = 63,
};
enum a4xx_tex_fmt {
- TFMT4_NORM_USHORT_565 = 11,
- TFMT4_NORM_USHORT_5551 = 10,
- TFMT4_NORM_USHORT_4444 = 8,
- TFMT4_NORM_UINT_X8Z24 = 71,
- TFMT4_NORM_UINT_2_10_10_10 = 33,
- TFMT4_NORM_UINT_A8 = 3,
- TFMT4_NORM_UINT_L8_A8 = 13,
- TFMT4_NORM_UINT_8 = 4,
- TFMT4_NORM_UINT_8_8_8_8 = 28,
- TFMT4_FLOAT_16 = 20,
- TFMT4_FLOAT_16_16 = 40,
- TFMT4_FLOAT_16_16_16_16 = 53,
- TFMT4_FLOAT_32 = 43,
- TFMT4_FLOAT_32_32 = 56,
- TFMT4_FLOAT_32_32_32_32 = 63,
+ TFMT4_5_6_5_UNORM = 11,
+ TFMT4_5_5_5_1_UNORM = 10,
+ TFMT4_4_4_4_4_UNORM = 8,
+ TFMT4_X8Z24_UNORM = 71,
+ TFMT4_10_10_10_2_UNORM = 33,
+ TFMT4_A8_UNORM = 3,
+ TFMT4_L8_A8_UNORM = 13,
+ TFMT4_8_UNORM = 4,
+ TFMT4_8_8_UNORM = 14,
+ TFMT4_8_8_8_8_UNORM = 28,
+ TFMT4_16_FLOAT = 20,
+ TFMT4_16_16_FLOAT = 40,
+ TFMT4_16_16_16_16_FLOAT = 53,
+ TFMT4_32_FLOAT = 43,
+ TFMT4_32_32_FLOAT = 56,
+ TFMT4_32_32_32_32_FLOAT = 63,
+};
+
+enum a4xx_tex_fetchsize {
+ TFETCH4_1_BYTE = 0,
+ TFETCH4_2_BYTE = 1,
+ TFETCH4_4_BYTE = 2,
+ TFETCH4_8_BYTE = 3,
+ TFETCH4_16_BYTE = 4,
};
enum a4xx_depth_format {
@@ -264,14 +274,19 @@ static inline uint32_t A4XX_RB_MSAA_CONTROL_SAMPLES(uint32_t val)
return ((val) << A4XX_RB_MSAA_CONTROL_SAMPLES__SHIFT) & A4XX_RB_MSAA_CONTROL_SAMPLES__MASK;
}
-#define REG_A4XX_RB_MSAA_CONTROL2 0x000020a3
-#define A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__MASK 0x00000380
-#define A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__SHIFT 7
-static inline uint32_t A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES(uint32_t val)
+#define REG_A4XX_RB_RENDER_CONTROL2 0x000020a3
+#define A4XX_RB_RENDER_CONTROL2_XCOORD 0x00000001
+#define A4XX_RB_RENDER_CONTROL2_YCOORD 0x00000002
+#define A4XX_RB_RENDER_CONTROL2_ZCOORD 0x00000004
+#define A4XX_RB_RENDER_CONTROL2_WCOORD 0x00000008
+#define A4XX_RB_RENDER_CONTROL2_FACENESS 0x00000020
+#define A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__MASK 0x00000380
+#define A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__SHIFT 7
+static inline uint32_t A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES(uint32_t val)
{
- return ((val) << A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__SHIFT) & A4XX_RB_MSAA_CONTROL2_MSAA_SAMPLES__MASK;
+ return ((val) << A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__SHIFT) & A4XX_RB_RENDER_CONTROL2_MSAA_SAMPLES__MASK;
}
-#define A4XX_RB_MSAA_CONTROL2_VARYING 0x00001000
+#define A4XX_RB_RENDER_CONTROL2_VARYING 0x00001000
static inline uint32_t REG_A4XX_RB_MRT(uint32_t i0) { return 0x000020a4 + 0x5*i0; }
@@ -362,7 +377,69 @@ static inline uint32_t A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR(enum adreno_r
return ((val) << A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__SHIFT) & A4XX_RB_MRT_BLEND_CONTROL_ALPHA_DEST_FACTOR__MASK;
}
+#define REG_A4XX_RB_BLEND_RED 0x000020f3
+#define A4XX_RB_BLEND_RED_UINT__MASK 0x00007fff
+#define A4XX_RB_BLEND_RED_UINT__SHIFT 0
+static inline uint32_t A4XX_RB_BLEND_RED_UINT(uint32_t val)
+{
+ return ((val) << A4XX_RB_BLEND_RED_UINT__SHIFT) & A4XX_RB_BLEND_RED_UINT__MASK;
+}
+#define A4XX_RB_BLEND_RED_FLOAT__MASK 0xffff0000
+#define A4XX_RB_BLEND_RED_FLOAT__SHIFT 16
+static inline uint32_t A4XX_RB_BLEND_RED_FLOAT(float val)
+{
+ return ((util_float_to_half(val)) << A4XX_RB_BLEND_RED_FLOAT__SHIFT) & A4XX_RB_BLEND_RED_FLOAT__MASK;
+}
+
+#define REG_A4XX_RB_BLEND_GREEN 0x000020f4
+#define A4XX_RB_BLEND_GREEN_UINT__MASK 0x00007fff
+#define A4XX_RB_BLEND_GREEN_UINT__SHIFT 0
+static inline uint32_t A4XX_RB_BLEND_GREEN_UINT(uint32_t val)
+{
+ return ((val) << A4XX_RB_BLEND_GREEN_UINT__SHIFT) & A4XX_RB_BLEND_GREEN_UINT__MASK;
+}
+#define A4XX_RB_BLEND_GREEN_FLOAT__MASK 0xffff0000
+#define A4XX_RB_BLEND_GREEN_FLOAT__SHIFT 16
+static inline uint32_t A4XX_RB_BLEND_GREEN_FLOAT(float val)
+{
+ return ((util_float_to_half(val)) << A4XX_RB_BLEND_GREEN_FLOAT__SHIFT) & A4XX_RB_BLEND_GREEN_FLOAT__MASK;
+}
+
+#define REG_A4XX_RB_BLEND_BLUE 0x000020f5
+#define A4XX_RB_BLEND_BLUE_UINT__MASK 0x00007fff
+#define A4XX_RB_BLEND_BLUE_UINT__SHIFT 0
+static inline uint32_t A4XX_RB_BLEND_BLUE_UINT(uint32_t val)
+{
+ return ((val) << A4XX_RB_BLEND_BLUE_UINT__SHIFT) & A4XX_RB_BLEND_BLUE_UINT__MASK;
+}
+#define A4XX_RB_BLEND_BLUE_FLOAT__MASK 0xffff0000
+#define A4XX_RB_BLEND_BLUE_FLOAT__SHIFT 16
+static inline uint32_t A4XX_RB_BLEND_BLUE_FLOAT(float val)
+{
+ return ((util_float_to_half(val)) << A4XX_RB_BLEND_BLUE_FLOAT__SHIFT) & A4XX_RB_BLEND_BLUE_FLOAT__MASK;
+}
+
+#define REG_A4XX_RB_BLEND_ALPHA 0x000020f6
+#define A4XX_RB_BLEND_ALPHA_UINT__MASK 0x00007fff
+#define A4XX_RB_BLEND_ALPHA_UINT__SHIFT 0
+static inline uint32_t A4XX_RB_BLEND_ALPHA_UINT(uint32_t val)
+{
+ return ((val) << A4XX_RB_BLEND_ALPHA_UINT__SHIFT) & A4XX_RB_BLEND_ALPHA_UINT__MASK;
+}
+#define A4XX_RB_BLEND_ALPHA_FLOAT__MASK 0xffff0000
+#define A4XX_RB_BLEND_ALPHA_FLOAT__SHIFT 16
+static inline uint32_t A4XX_RB_BLEND_ALPHA_FLOAT(float val)
+{
+ return ((util_float_to_half(val)) << A4XX_RB_BLEND_ALPHA_FLOAT__SHIFT) & A4XX_RB_BLEND_ALPHA_FLOAT__MASK;
+}
+
#define REG_A4XX_RB_ALPHA_CONTROL 0x000020f8
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK 0x000000ff
+#define A4XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT 0
+static inline uint32_t A4XX_RB_ALPHA_CONTROL_ALPHA_REF(uint32_t val)
+{
+ return ((val) << A4XX_RB_ALPHA_CONTROL_ALPHA_REF__SHIFT) & A4XX_RB_ALPHA_CONTROL_ALPHA_REF__MASK;
+}
#define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST 0x00000100
#define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__MASK 0x00000e00
#define A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC__SHIFT 9
@@ -372,7 +449,7 @@ static inline uint32_t A4XX_RB_ALPHA_CONTROL_ALPHA_TEST_FUNC(enum adreno_compare
}
#define REG_A4XX_RB_FS_OUTPUT 0x000020f9
-#define A4XX_RB_FS_OUTPUT_ENABLE_COLOR_PIPE 0x00000001
+#define A4XX_RB_FS_OUTPUT_ENABLE_BLEND 0x00000001
#define A4XX_RB_FS_OUTPUT_FAST_CLEAR 0x00000100
#define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__MASK 0xffff0000
#define A4XX_RB_FS_OUTPUT_SAMPLE_MASK__SHIFT 16
@@ -416,11 +493,11 @@ static inline uint32_t A4XX_RB_COPY_CONTROL_GMEM_BASE(uint32_t val)
}
#define REG_A4XX_RB_COPY_DEST_BASE 0x000020fd
-#define A4XX_RB_COPY_DEST_BASE_BASE__MASK 0xfffffff0
-#define A4XX_RB_COPY_DEST_BASE_BASE__SHIFT 4
+#define A4XX_RB_COPY_DEST_BASE_BASE__MASK 0xffffffe0
+#define A4XX_RB_COPY_DEST_BASE_BASE__SHIFT 5
static inline uint32_t A4XX_RB_COPY_DEST_BASE_BASE(uint32_t val)
{
- return ((val >> 4) << A4XX_RB_COPY_DEST_BASE_BASE__SHIFT) & A4XX_RB_COPY_DEST_BASE_BASE__MASK;
+ return ((val >> 5) << A4XX_RB_COPY_DEST_BASE_BASE__SHIFT) & A4XX_RB_COPY_DEST_BASE_BASE__MASK;
}
#define REG_A4XX_RB_COPY_DEST_PITCH 0x000020fe
@@ -508,7 +585,7 @@ static inline uint32_t A4XX_RB_DEPTH_INFO_DEPTH_BASE(uint32_t val)
#define A4XX_RB_DEPTH_PITCH__SHIFT 0
static inline uint32_t A4XX_RB_DEPTH_PITCH(uint32_t val)
{
- return ((val >> 4) << A4XX_RB_DEPTH_PITCH__SHIFT) & A4XX_RB_DEPTH_PITCH__MASK;
+ return ((val >> 5) << A4XX_RB_DEPTH_PITCH__SHIFT) & A4XX_RB_DEPTH_PITCH__MASK;
}
#define REG_A4XX_RB_DEPTH_PITCH2 0x00002105
@@ -516,7 +593,7 @@ static inline uint32_t A4XX_RB_DEPTH_PITCH(uint32_t val)
#define A4XX_RB_DEPTH_PITCH2__SHIFT 0
static inline uint32_t A4XX_RB_DEPTH_PITCH2(uint32_t val)
{
- return ((val >> 4) << A4XX_RB_DEPTH_PITCH2__SHIFT) & A4XX_RB_DEPTH_PITCH2__MASK;
+ return ((val >> 5) << A4XX_RB_DEPTH_PITCH2__SHIFT) & A4XX_RB_DEPTH_PITCH2__MASK;
}
#define REG_A4XX_RB_STENCIL_CONTROL 0x00002106
@@ -630,7 +707,11 @@ static inline uint32_t A4XX_RB_BIN_OFFSET_Y(uint32_t val)
return ((val) << A4XX_RB_BIN_OFFSET_Y__SHIFT) & A4XX_RB_BIN_OFFSET_Y__MASK;
}
-#define REG_A4XX_RB_VPORT_Z_CLAMP_MAX_15 0x0000213f
+static inline uint32_t REG_A4XX_RB_VPORT_Z_CLAMP(uint32_t i0) { return 0x00002120 + 0x2*i0; }
+
+static inline uint32_t REG_A4XX_RB_VPORT_Z_CLAMP_MIN(uint32_t i0) { return 0x00002120 + 0x2*i0; }
+
+static inline uint32_t REG_A4XX_RB_VPORT_Z_CLAMP_MAX(uint32_t i0) { return 0x00002121 + 0x2*i0; }
#define REG_A4XX_RBBM_HW_VERSION 0x00000000
@@ -1121,7 +1202,9 @@ static inline uint32_t A4XX_SP_FS_CTRL_REG1_CONSTLENGTH(uint32_t val)
{
return ((val) << A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__SHIFT) & A4XX_SP_FS_CTRL_REG1_CONSTLENGTH__MASK;
}
+#define A4XX_SP_FS_CTRL_REG1_FACENESS 0x00080000
#define A4XX_SP_FS_CTRL_REG1_VARYING 0x00100000
+#define A4XX_SP_FS_CTRL_REG1_FRAGCOORD 0x00200000
#define REG_A4XX_SP_FS_OBJ_OFFSET_REG 0x000022ea
#define A4XX_SP_FS_OBJ_OFFSET_REG_CONSTOBJECTOFFSET__MASK 0x01ff0000
@@ -1384,6 +1467,12 @@ static inline uint32_t A4XX_VFD_CONTROL_1_REGID4INST(uint32_t val)
#define REG_A4XX_VFD_CONTROL_2 0x00002202
#define REG_A4XX_VFD_CONTROL_3 0x00002203
+#define A4XX_VFD_CONTROL_3_REGID_VTXCNT__MASK 0x0000ff00
+#define A4XX_VFD_CONTROL_3_REGID_VTXCNT__SHIFT 8
+static inline uint32_t A4XX_VFD_CONTROL_3_REGID_VTXCNT(uint32_t val)
+{
+ return ((val) << A4XX_VFD_CONTROL_3_REGID_VTXCNT__SHIFT) & A4XX_VFD_CONTROL_3_REGID_VTXCNT__MASK;
+}
#define REG_A4XX_VFD_CONTROL_4 0x00002204
@@ -1405,12 +1494,7 @@ static inline uint32_t A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE(uint32_t val)
return ((val) << A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_BUFSTRIDE__MASK;
}
#define A4XX_VFD_FETCH_INSTR_0_SWITCHNEXT 0x00080000
-#define A4XX_VFD_FETCH_INSTR_0_STEPRATE__MASK 0xff000000
-#define A4XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT 24
-static inline uint32_t A4XX_VFD_FETCH_INSTR_0_STEPRATE(uint32_t val)
-{
- return ((val) << A4XX_VFD_FETCH_INSTR_0_STEPRATE__SHIFT) & A4XX_VFD_FETCH_INSTR_0_STEPRATE__MASK;
-}
+#define A4XX_VFD_FETCH_INSTR_0_INSTANCED 0x00100000
static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_1(uint32_t i0) { return 0x0000220b + 0x4*i0; }
@@ -1423,6 +1507,12 @@ static inline uint32_t A4XX_VFD_FETCH_INSTR_2_SIZE(uint32_t val)
}
static inline uint32_t REG_A4XX_VFD_FETCH_INSTR_3(uint32_t i0) { return 0x0000220d + 0x4*i0; }
+#define A4XX_VFD_FETCH_INSTR_3_STEPRATE__MASK 0x000001ff
+#define A4XX_VFD_FETCH_INSTR_3_STEPRATE__SHIFT 0
+static inline uint32_t A4XX_VFD_FETCH_INSTR_3_STEPRATE(uint32_t val)
+{
+ return ((val) << A4XX_VFD_FETCH_INSTR_3_STEPRATE__SHIFT) & A4XX_VFD_FETCH_INSTR_3_STEPRATE__MASK;
+}
static inline uint32_t REG_A4XX_VFD_DECODE(uint32_t i0) { return 0x0000228a + 0x1*i0; }
@@ -1446,6 +1536,7 @@ static inline uint32_t A4XX_VFD_DECODE_INSTR_REGID(uint32_t val)
{
return ((val) << A4XX_VFD_DECODE_INSTR_REGID__SHIFT) & A4XX_VFD_DECODE_INSTR_REGID__MASK;
}
+#define A4XX_VFD_DECODE_INSTR_INT 0x00100000
#define A4XX_VFD_DECODE_INSTR_SWAP__MASK 0x00c00000
#define A4XX_VFD_DECODE_INSTR_SWAP__SHIFT 22
static inline uint32_t A4XX_VFD_DECODE_INSTR_SWAP(enum a3xx_color_swap val)
@@ -1585,7 +1676,47 @@ static inline uint32_t A4XX_GRAS_SU_POLY_OFFSET_OFFSET(float val)
return ((fui(val)) << A4XX_GRAS_SU_POLY_OFFSET_OFFSET__SHIFT) & A4XX_GRAS_SU_POLY_OFFSET_OFFSET__MASK;
}
-#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_TL 0x0000209f
+#define REG_A4XX_GRAS_DEPTH_CONTROL 0x00002077
+#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK 0x00000003
+#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT 0
+static inline uint32_t A4XX_GRAS_DEPTH_CONTROL_FORMAT(enum a4xx_depth_format val)
+{
+ return ((val) << A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT) & A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK;
+}
+
+#define REG_A4XX_GRAS_SU_MODE_CONTROL 0x00002078
+#define A4XX_GRAS_SU_MODE_CONTROL_CULL_FRONT 0x00000001
+#define A4XX_GRAS_SU_MODE_CONTROL_CULL_BACK 0x00000002
+#define A4XX_GRAS_SU_MODE_CONTROL_FRONT_CW 0x00000004
+#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK 0x000007f8
+#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT 3
+static inline uint32_t A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
+{
+ return ((((int32_t)(val * 4.0))) << A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+}
+#define A4XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET 0x00000800
+#define A4XX_GRAS_SU_MODE_CONTROL_RENDERING_PASS 0x00100000
+
+#define REG_A4XX_GRAS_SC_CONTROL 0x0000207b
+#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK 0x0000000c
+#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT 2
+static inline uint32_t A4XX_GRAS_SC_CONTROL_RENDER_MODE(enum a3xx_render_mode val)
+{
+ return ((val) << A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK;
+}
+#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK 0x00000380
+#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT 7
+static inline uint32_t A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(uint32_t val)
+{
+ return ((val) << A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT) & A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK;
+}
+#define A4XX_GRAS_SC_CONTROL_MSAA_DISABLE 0x00000800
+#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK 0x0000f000
+#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT 12
+static inline uint32_t A4XX_GRAS_SC_CONTROL_RASTER_MODE(uint32_t val)
+{
+ return ((val) << A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK;
+}
#define REG_A4XX_GRAS_SC_SCREEN_SCISSOR_TL 0x0000207c
#define A4XX_GRAS_SC_SCREEN_SCISSOR_TL_WINDOW_OFFSET_DISABLE 0x80000000
@@ -1647,46 +1778,34 @@ static inline uint32_t A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y(uint32_t val)
return ((val) << A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__SHIFT) & A4XX_GRAS_SC_WINDOW_SCISSOR_TL_Y__MASK;
}
-#define REG_A4XX_GRAS_DEPTH_CONTROL 0x00002077
-#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK 0x00000003
-#define A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT 0
-static inline uint32_t A4XX_GRAS_DEPTH_CONTROL_FORMAT(enum a4xx_depth_format val)
+#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_BR 0x0000209e
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_WINDOW_OFFSET_DISABLE 0x80000000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__MASK 0x00007fff
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__SHIFT 0
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_BR_X(uint32_t val)
{
- return ((val) << A4XX_GRAS_DEPTH_CONTROL_FORMAT__SHIFT) & A4XX_GRAS_DEPTH_CONTROL_FORMAT__MASK;
+ return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_BR_X__MASK;
}
-
-#define REG_A4XX_GRAS_SU_MODE_CONTROL 0x00002078
-#define A4XX_GRAS_SU_MODE_CONTROL_CULL_FRONT 0x00000001
-#define A4XX_GRAS_SU_MODE_CONTROL_CULL_BACK 0x00000002
-#define A4XX_GRAS_SU_MODE_CONTROL_FRONT_CW 0x00000004
-#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK 0x000007f8
-#define A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT 3
-static inline uint32_t A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH(float val)
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__MASK 0x7fff0000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__SHIFT 16
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y(uint32_t val)
{
- return ((((int32_t)(val * 4.0))) << A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__SHIFT) & A4XX_GRAS_SU_MODE_CONTROL_LINEHALFWIDTH__MASK;
+ return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_BR_Y__MASK;
}
-#define A4XX_GRAS_SU_MODE_CONTROL_POLY_OFFSET 0x00000800
-#define A4XX_GRAS_SU_MODE_CONTROL_RENDERING_PASS 0x00100000
-#define REG_A4XX_GRAS_SC_CONTROL 0x0000207b
-#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK 0x0000000c
-#define A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT 2
-static inline uint32_t A4XX_GRAS_SC_CONTROL_RENDER_MODE(enum a3xx_render_mode val)
-{
- return ((val) << A4XX_GRAS_SC_CONTROL_RENDER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RENDER_MODE__MASK;
-}
-#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK 0x00000380
-#define A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT 7
-static inline uint32_t A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES(uint32_t val)
+#define REG_A4XX_GRAS_SC_EXTENT_WINDOW_TL 0x0000209f
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_WINDOW_OFFSET_DISABLE 0x80000000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__MASK 0x00007fff
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__SHIFT 0
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_TL_X(uint32_t val)
{
- return ((val) << A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__SHIFT) & A4XX_GRAS_SC_CONTROL_MSAA_SAMPLES__MASK;
+ return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_TL_X__MASK;
}
-#define A4XX_GRAS_SC_CONTROL_MSAA_DISABLE 0x00000800
-#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK 0x0000f000
-#define A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT 12
-static inline uint32_t A4XX_GRAS_SC_CONTROL_RASTER_MODE(uint32_t val)
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__MASK 0x7fff0000
+#define A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__SHIFT 16
+static inline uint32_t A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y(uint32_t val)
{
- return ((val) << A4XX_GRAS_SC_CONTROL_RASTER_MODE__SHIFT) & A4XX_GRAS_SC_CONTROL_RASTER_MODE__MASK;
+ return ((val) << A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__SHIFT) & A4XX_GRAS_SC_EXTENT_WINDOW_TL_Y__MASK;
}
#define REG_A4XX_UCHE_CACHE_MODE_CONTROL 0x00000e80
@@ -1742,6 +1861,12 @@ static inline uint32_t A4XX_HLSQ_CONTROL_1_REG_VSTHREADSIZE(enum a3xx_threadsize
}
#define A4XX_HLSQ_CONTROL_1_REG_VSSUPERTHREADENABLE 0x00000100
#define A4XX_HLSQ_CONTROL_1_REG_RESERVED1 0x00000200
+#define A4XX_HLSQ_CONTROL_1_REG_COORDREGID__MASK 0x00ff0000
+#define A4XX_HLSQ_CONTROL_1_REG_COORDREGID__SHIFT 16
+static inline uint32_t A4XX_HLSQ_CONTROL_1_REG_COORDREGID(uint32_t val)
+{
+ return ((val) << A4XX_HLSQ_CONTROL_1_REG_COORDREGID__SHIFT) & A4XX_HLSQ_CONTROL_1_REG_COORDREGID__MASK;
+}
#define A4XX_HLSQ_CONTROL_1_REG_ZWCOORD 0x02000000
#define REG_A4XX_HLSQ_CONTROL_2_REG 0x000023c2
@@ -1751,6 +1876,12 @@ static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD(uint32_t val)
{
return ((val) << A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_PRIMALLOCTHRESHOLD__MASK;
}
+#define A4XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK 0x000003fc
+#define A4XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT 2
+static inline uint32_t A4XX_HLSQ_CONTROL_2_REG_FACEREGID(uint32_t val)
+{
+ return ((val) << A4XX_HLSQ_CONTROL_2_REG_FACEREGID__SHIFT) & A4XX_HLSQ_CONTROL_2_REG_FACEREGID__MASK;
+}
#define REG_A4XX_HLSQ_CONTROL_3_REG 0x000023c3
#define A4XX_HLSQ_CONTROL_3_REG_REGID__MASK 0x000000ff
@@ -1965,15 +2096,13 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val)
#define REG_A4XX_UNKNOWN_20F2 0x000020f2
-#define REG_A4XX_UNKNOWN_20F3 0x000020f3
-
-#define REG_A4XX_UNKNOWN_20F4 0x000020f4
-
-#define REG_A4XX_UNKNOWN_20F5 0x000020f5
-
-#define REG_A4XX_UNKNOWN_20F6 0x000020f6
-
#define REG_A4XX_UNKNOWN_20F7 0x000020f7
+#define A4XX_UNKNOWN_20F7__MASK 0xffffffff
+#define A4XX_UNKNOWN_20F7__SHIFT 0
+static inline uint32_t A4XX_UNKNOWN_20F7(float val)
+{
+ return ((fui(val)) << A4XX_UNKNOWN_20F7__SHIFT) & A4XX_UNKNOWN_20F7__MASK;
+}
#define REG_A4XX_UNKNOWN_2152 0x00002152
@@ -2000,6 +2129,7 @@ static inline uint32_t A4XX_HLSQ_GS_CONTROL_REG_INSTRLENGTH(uint32_t val)
#define REG_A4XX_UNKNOWN_23A0 0x000023a0
#define REG_A4XX_TEX_SAMP_0 0x00000000
+#define A4XX_TEX_SAMP_0_MIPFILTER_LINEAR_NEAR 0x00000001
#define A4XX_TEX_SAMP_0_XY_MAG__MASK 0x00000006
#define A4XX_TEX_SAMP_0_XY_MAG__SHIFT 1
static inline uint32_t A4XX_TEX_SAMP_0_XY_MAG(enum a4xx_tex_filter val)
@@ -2038,17 +2168,19 @@ static inline uint32_t A4XX_TEX_SAMP_1_COMPARE_FUNC(enum adreno_compare_func val
{
return ((val) << A4XX_TEX_SAMP_1_COMPARE_FUNC__SHIFT) & A4XX_TEX_SAMP_1_COMPARE_FUNC__MASK;
}
+#define A4XX_TEX_SAMP_1_UNNORM_COORDS 0x00000020
+#define A4XX_TEX_SAMP_1_MIPFILTER_LINEAR_FAR 0x00000040
#define A4XX_TEX_SAMP_1_MAX_LOD__MASK 0x000fff00
#define A4XX_TEX_SAMP_1_MAX_LOD__SHIFT 8
static inline uint32_t A4XX_TEX_SAMP_1_MAX_LOD(float val)
{
- return ((((uint32_t)(val * 64.0))) << A4XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A4XX_TEX_SAMP_1_MAX_LOD__MASK;
+ return ((((uint32_t)(val * 256.0))) << A4XX_TEX_SAMP_1_MAX_LOD__SHIFT) & A4XX_TEX_SAMP_1_MAX_LOD__MASK;
}
#define A4XX_TEX_SAMP_1_MIN_LOD__MASK 0xfff00000
#define A4XX_TEX_SAMP_1_MIN_LOD__SHIFT 20
static inline uint32_t A4XX_TEX_SAMP_1_MIN_LOD(float val)
{
- return ((((uint32_t)(val * 64.0))) << A4XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A4XX_TEX_SAMP_1_MIN_LOD__MASK;
+ return ((((uint32_t)(val * 256.0))) << A4XX_TEX_SAMP_1_MIN_LOD__SHIFT) & A4XX_TEX_SAMP_1_MIN_LOD__MASK;
}
#define REG_A4XX_TEX_CONST_0 0x00000000
@@ -2077,6 +2209,12 @@ static inline uint32_t A4XX_TEX_CONST_0_SWIZ_W(enum a4xx_tex_swiz val)
{
return ((val) << A4XX_TEX_CONST_0_SWIZ_W__SHIFT) & A4XX_TEX_CONST_0_SWIZ_W__MASK;
}
+#define A4XX_TEX_CONST_0_MIPLVLS__MASK 0x000f0000
+#define A4XX_TEX_CONST_0_MIPLVLS__SHIFT 16
+static inline uint32_t A4XX_TEX_CONST_0_MIPLVLS(uint32_t val)
+{
+ return ((val) << A4XX_TEX_CONST_0_MIPLVLS__SHIFT) & A4XX_TEX_CONST_0_MIPLVLS__MASK;
+}
#define A4XX_TEX_CONST_0_FMT__MASK 0x1fc00000
#define A4XX_TEX_CONST_0_FMT__SHIFT 22
static inline uint32_t A4XX_TEX_CONST_0_FMT(enum a4xx_tex_fmt val)
@@ -2105,6 +2243,12 @@ static inline uint32_t A4XX_TEX_CONST_1_WIDTH(uint32_t val)
}
#define REG_A4XX_TEX_CONST_2 0x00000002
+#define A4XX_TEX_CONST_2_FETCHSIZE__MASK 0x0000000f
+#define A4XX_TEX_CONST_2_FETCHSIZE__SHIFT 0
+static inline uint32_t A4XX_TEX_CONST_2_FETCHSIZE(enum a4xx_tex_fetchsize val)
+{
+ return ((val) << A4XX_TEX_CONST_2_FETCHSIZE__SHIFT) & A4XX_TEX_CONST_2_FETCHSIZE__MASK;
+}
#define A4XX_TEX_CONST_2_PITCH__MASK 0x3ffffe00
#define A4XX_TEX_CONST_2_PITCH__SHIFT 9
static inline uint32_t A4XX_TEX_CONST_2_PITCH(uint32_t val)
@@ -2119,19 +2263,31 @@ static inline uint32_t A4XX_TEX_CONST_2_SWAP(enum a3xx_color_swap val)
}
#define REG_A4XX_TEX_CONST_3 0x00000003
-#define A4XX_TEX_CONST_3_LAYERSZ__MASK 0x0000000f
+#define A4XX_TEX_CONST_3_LAYERSZ__MASK 0x00003fff
#define A4XX_TEX_CONST_3_LAYERSZ__SHIFT 0
static inline uint32_t A4XX_TEX_CONST_3_LAYERSZ(uint32_t val)
{
return ((val >> 12) << A4XX_TEX_CONST_3_LAYERSZ__SHIFT) & A4XX_TEX_CONST_3_LAYERSZ__MASK;
}
+#define A4XX_TEX_CONST_3_DEPTH__MASK 0x7ffc0000
+#define A4XX_TEX_CONST_3_DEPTH__SHIFT 18
+static inline uint32_t A4XX_TEX_CONST_3_DEPTH(uint32_t val)
+{
+ return ((val) << A4XX_TEX_CONST_3_DEPTH__SHIFT) & A4XX_TEX_CONST_3_DEPTH__MASK;
+}
#define REG_A4XX_TEX_CONST_4 0x00000004
-#define A4XX_TEX_CONST_4_BASE__MASK 0xffffffff
-#define A4XX_TEX_CONST_4_BASE__SHIFT 0
+#define A4XX_TEX_CONST_4_LAYERSZ__MASK 0x0000000f
+#define A4XX_TEX_CONST_4_LAYERSZ__SHIFT 0
+static inline uint32_t A4XX_TEX_CONST_4_LAYERSZ(uint32_t val)
+{
+ return ((val >> 12) << A4XX_TEX_CONST_4_LAYERSZ__SHIFT) & A4XX_TEX_CONST_4_LAYERSZ__MASK;
+}
+#define A4XX_TEX_CONST_4_BASE__MASK 0xffffffe0
+#define A4XX_TEX_CONST_4_BASE__SHIFT 5
static inline uint32_t A4XX_TEX_CONST_4_BASE(uint32_t val)
{
- return ((val) << A4XX_TEX_CONST_4_BASE__SHIFT) & A4XX_TEX_CONST_4_BASE__MASK;
+ return ((val >> 5) << A4XX_TEX_CONST_4_BASE__SHIFT) & A4XX_TEX_CONST_4_BASE__MASK;
}
#define REG_A4XX_TEX_CONST_5 0x00000005
diff --git a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h
index a4b33af9338d..8531beb982e7 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_common.xml.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_common.xml.h
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
index 6a75cee94d81..6ffc4f6c8af1 100644
--- a/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
+++ b/drivers/gpu/drm/msm/adreno/adreno_pm4.xml.h
@@ -12,9 +12,9 @@ The rules-ng-ng source files this header was generated from are:
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/a2xx.xml ( 32901 bytes, from 2014-06-02 15:21:30)
- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_common.xml ( 10551 bytes, from 2014-11-13 22:44:30)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15053 bytes, from 2014-11-09 15:45:47)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 63169 bytes, from 2014-11-13 22:44:18)
-- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 49097 bytes, from 2014-11-14 15:38:00)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/adreno_pm4.xml ( 15085 bytes, from 2014-12-20 21:49:41)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a3xx.xml ( 64344 bytes, from 2014-12-12 20:22:26)
+- /home/robclark/src/freedreno/envytools/rnndb/adreno/a4xx.xml ( 51069 bytes, from 2014-12-21 15:51:54)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@@ -172,7 +172,9 @@ enum adreno_pm4_type3_packets {
CP_DRAW_INDIRECT = 40,
CP_DRAW_INDX_INDIRECT = 41,
CP_DRAW_AUTO = 36,
+ CP_UNKNOWN_19 = 25,
CP_UNKNOWN_1A = 26,
+ CP_UNKNOWN_4E = 78,
CP_WIDE_REG_WRITE = 116,
IN_IB_PREFETCH_END = 23,
IN_SUBBLK_PREFETCH = 31,
@@ -203,6 +205,12 @@ enum adreno_state_src {
SS_INDIRECT = 4,
};
+enum a4xx_index_size {
+ INDEX4_SIZE_8_BIT = 0,
+ INDEX4_SIZE_16_BIT = 1,
+ INDEX4_SIZE_32_BIT = 2,
+};
+
#define REG_CP_LOAD_STATE_0 0x00000000
#define CP_LOAD_STATE_0_DST_OFF__MASK 0x0000ffff
#define CP_LOAD_STATE_0_DST_OFF__SHIFT 0
@@ -374,29 +382,20 @@ static inline uint32_t CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT(enum pc_di_src_sel va
{
return ((val) << CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__SHIFT) & CP_DRAW_INDX_OFFSET_0_SOURCE_SELECT__MASK;
}
-#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK 0x00000700
-#define CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT 8
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_VIS_CULL(enum pc_di_vis_cull_mode val)
-{
- return ((val) << CP_DRAW_INDX_OFFSET_0_VIS_CULL__SHIFT) & CP_DRAW_INDX_OFFSET_0_VIS_CULL__MASK;
-}
-#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK 0x00000800
-#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT 11
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum pc_di_index_size val)
+#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK 0x00000c00
+#define CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT 10
+static inline uint32_t CP_DRAW_INDX_OFFSET_0_INDEX_SIZE(enum a4xx_index_size val)
{
return ((val) << CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__SHIFT) & CP_DRAW_INDX_OFFSET_0_INDEX_SIZE__MASK;
}
-#define CP_DRAW_INDX_OFFSET_0_NOT_EOP 0x00001000
-#define CP_DRAW_INDX_OFFSET_0_SMALL_INDEX 0x00002000
-#define CP_DRAW_INDX_OFFSET_0_PRE_DRAW_INITIATOR_ENABLE 0x00004000
-#define CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__MASK 0xffff0000
-#define CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__SHIFT 16
-static inline uint32_t CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES(uint32_t val)
-{
- return ((val) << CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_OFFSET_0_NUM_INSTANCES__MASK;
-}
#define REG_CP_DRAW_INDX_OFFSET_1 0x00000001
+#define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK 0xffffffff
+#define CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__SHIFT 0
+static inline uint32_t CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES(uint32_t val)
+{
+ return ((val) << CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__SHIFT) & CP_DRAW_INDX_OFFSET_1_NUM_INSTANCES__MASK;
+}
#define REG_CP_DRAW_INDX_OFFSET_2 0x00000002
#define CP_DRAW_INDX_OFFSET_2_NUM_INDICES__MASK 0xffffffff
diff --git a/drivers/gpu/drm/msm/dsi/dsi.xml.h b/drivers/gpu/drm/msm/dsi/dsi.xml.h
index 448438b759b4..abf1bba520bf 100644
--- a/drivers/gpu/drm/msm/dsi/dsi.xml.h
+++ b/drivers/gpu/drm/msm/dsi/dsi.xml.h
@@ -8,16 +8,17 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
Copyright (C) 2013 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
index c102a7f074ac..695f99d4bec2 100644
--- a/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
+++ b/drivers/gpu/drm/msm/dsi/mmss_cc.xml.h
@@ -8,16 +8,17 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/dsi/sfpb.xml.h b/drivers/gpu/drm/msm/dsi/sfpb.xml.h
index a900134bdf33..50ff9851d73d 100644
--- a/drivers/gpu/drm/msm/dsi/sfpb.xml.h
+++ b/drivers/gpu/drm/msm/dsi/sfpb.xml.h
@@ -8,16 +8,17 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
Copyright (C) 2013 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/edp/edp.c b/drivers/gpu/drm/msm/edp/edp.c
new file mode 100644
index 000000000000..0940e84b2821
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/of_irq.h>
+#include "edp.h"
+
+static irqreturn_t edp_irq(int irq, void *dev_id)
+{
+ struct msm_edp *edp = dev_id;
+
+ /* Process eDP irq */
+ return msm_edp_ctrl_irq(edp->ctrl);
+}
+
+static void edp_destroy(struct platform_device *pdev)
+{
+ struct msm_edp *edp = platform_get_drvdata(pdev);
+
+ if (!edp)
+ return;
+
+ if (edp->ctrl) {
+ msm_edp_ctrl_destroy(edp->ctrl);
+ edp->ctrl = NULL;
+ }
+
+ platform_set_drvdata(pdev, NULL);
+}
+
+/* construct eDP at bind/probe time, grab all the resources. */
+static struct msm_edp *edp_init(struct platform_device *pdev)
+{
+ struct msm_edp *edp = NULL;
+ int ret;
+
+ if (!pdev) {
+ pr_err("no eDP device\n");
+ ret = -ENXIO;
+ goto fail;
+ }
+
+ edp = devm_kzalloc(&pdev->dev, sizeof(*edp), GFP_KERNEL);
+ if (!edp) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ DBG("eDP probed=%p", edp);
+
+ edp->pdev = pdev;
+ platform_set_drvdata(pdev, edp);
+
+ ret = msm_edp_ctrl_init(edp);
+ if (ret)
+ goto fail;
+
+ return edp;
+
+fail:
+ if (edp)
+ edp_destroy(pdev);
+
+ return ERR_PTR(ret);
+}
+
+static int edp_bind(struct device *dev, struct device *master, void *data)
+{
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct msm_drm_private *priv = drm->dev_private;
+ struct msm_edp *edp;
+
+ DBG("");
+ edp = edp_init(to_platform_device(dev));
+ if (IS_ERR(edp))
+ return PTR_ERR(edp);
+ priv->edp = edp;
+
+ return 0;
+}
+
+static void edp_unbind(struct device *dev, struct device *master, void *data)
+{
+ struct drm_device *drm = dev_get_drvdata(master);
+ struct msm_drm_private *priv = drm->dev_private;
+
+ DBG("");
+ if (priv->edp) {
+ edp_destroy(to_platform_device(dev));
+ priv->edp = NULL;
+ }
+}
+
+static const struct component_ops edp_ops = {
+ .bind = edp_bind,
+ .unbind = edp_unbind,
+};
+
+static int edp_dev_probe(struct platform_device *pdev)
+{
+ DBG("");
+ return component_add(&pdev->dev, &edp_ops);
+}
+
+static int edp_dev_remove(struct platform_device *pdev)
+{
+ DBG("");
+ component_del(&pdev->dev, &edp_ops);
+ return 0;
+}
+
+static const struct of_device_id dt_match[] = {
+ { .compatible = "qcom,mdss-edp" },
+ {}
+};
+
+static struct platform_driver edp_driver = {
+ .probe = edp_dev_probe,
+ .remove = edp_dev_remove,
+ .driver = {
+ .name = "msm_edp",
+ .of_match_table = dt_match,
+ },
+};
+
+void __init msm_edp_register(void)
+{
+ DBG("");
+ platform_driver_register(&edp_driver);
+}
+
+void __exit msm_edp_unregister(void)
+{
+ DBG("");
+ platform_driver_unregister(&edp_driver);
+}
+
+/* Second part of initialization, the drm/kms level modeset_init */
+int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
+ struct drm_encoder *encoder)
+{
+ struct platform_device *pdev = edp->pdev;
+ struct msm_drm_private *priv = dev->dev_private;
+ int ret;
+
+ edp->encoder = encoder;
+ edp->dev = dev;
+
+ edp->bridge = msm_edp_bridge_init(edp);
+ if (IS_ERR(edp->bridge)) {
+ ret = PTR_ERR(edp->bridge);
+ dev_err(dev->dev, "failed to create eDP bridge: %d\n", ret);
+ edp->bridge = NULL;
+ goto fail;
+ }
+
+ edp->connector = msm_edp_connector_init(edp);
+ if (IS_ERR(edp->connector)) {
+ ret = PTR_ERR(edp->connector);
+ dev_err(dev->dev, "failed to create eDP connector: %d\n", ret);
+ edp->connector = NULL;
+ goto fail;
+ }
+
+ edp->irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ if (edp->irq < 0) {
+ ret = edp->irq;
+ dev_err(dev->dev, "failed to get IRQ: %d\n", ret);
+ goto fail;
+ }
+
+ ret = devm_request_irq(&pdev->dev, edp->irq,
+ edp_irq, IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
+ "edp_isr", edp);
+ if (ret < 0) {
+ dev_err(dev->dev, "failed to request IRQ%u: %d\n",
+ edp->irq, ret);
+ goto fail;
+ }
+
+ encoder->bridge = edp->bridge;
+
+ priv->bridges[priv->num_bridges++] = edp->bridge;
+ priv->connectors[priv->num_connectors++] = edp->connector;
+
+ return 0;
+
+fail:
+ /* bridge/connector are normally destroyed by drm */
+ if (edp->bridge) {
+ edp_bridge_destroy(edp->bridge);
+ edp->bridge = NULL;
+ }
+ if (edp->connector) {
+ edp->connector->funcs->destroy(edp->connector);
+ edp->connector = NULL;
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/msm/edp/edp.h b/drivers/gpu/drm/msm/edp/edp.h
new file mode 100644
index 000000000000..ba5bedde5241
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __EDP_CONNECTOR_H__
+#define __EDP_CONNECTOR_H__
+
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+
+#include "drm_crtc.h"
+#include "drm_dp_helper.h"
+#include "msm_drv.h"
+
+#define edp_read(offset) msm_readl((offset))
+#define edp_write(offset, data) msm_writel((data), (offset))
+
+struct edp_ctrl;
+struct edp_aux;
+struct edp_phy;
+
+struct msm_edp {
+ struct drm_device *dev;
+ struct platform_device *pdev;
+
+ struct drm_connector *connector;
+ struct drm_bridge *bridge;
+
+ /* the encoder we are hooked to (outside of eDP block) */
+ struct drm_encoder *encoder;
+
+ struct edp_ctrl *ctrl;
+
+ int irq;
+};
+
+/* eDP bridge */
+struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp);
+void edp_bridge_destroy(struct drm_bridge *bridge);
+
+/* eDP connector */
+struct drm_connector *msm_edp_connector_init(struct msm_edp *edp);
+
+/* AUX */
+void *msm_edp_aux_init(struct device *dev, void __iomem *regbase,
+ struct drm_dp_aux **drm_aux);
+void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux);
+irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr);
+void msm_edp_aux_ctrl(struct edp_aux *aux, int enable);
+
+/* Phy */
+bool msm_edp_phy_ready(struct edp_phy *phy);
+void msm_edp_phy_ctrl(struct edp_phy *phy, int enable);
+void msm_edp_phy_vm_pe_init(struct edp_phy *phy);
+void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1);
+void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane);
+void *msm_edp_phy_init(struct device *dev, void __iomem *regbase);
+
+/* Ctrl */
+irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl);
+void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on);
+int msm_edp_ctrl_init(struct msm_edp *edp);
+void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl);
+bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl);
+int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl,
+ struct drm_connector *connector, struct edid **edid);
+int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl,
+ const struct drm_display_mode *mode,
+ const struct drm_display_info *info);
+/* @pixel_rate is in kHz */
+bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl,
+ u32 pixel_rate, u32 *pm, u32 *pn);
+
+#endif /* __EDP_CONNECTOR_H__ */
diff --git a/drivers/gpu/drm/msm/edp/edp.xml.h b/drivers/gpu/drm/msm/edp/edp.xml.h
new file mode 100644
index 000000000000..a29f1df15143
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp.xml.h
@@ -0,0 +1,292 @@
+#ifndef EDP_XML
+#define EDP_XML
+
+/* Autogenerated file, DO NOT EDIT manually!
+
+This file was generated by the rules-ng-ng headergen tool in this git repository:
+http://github.com/freedreno/envytools/
+git clone https://github.com/freedreno/envytools.git
+
+The rules-ng-ng source files this header was generated from are:
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
+- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
+
+Copyright (C) 2013-2014 by the following authors:
+- Rob Clark <robdclark@gmail.com> (robclark)
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice (including the
+next paragraph) shall be included in all copies or substantial
+portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+enum edp_color_depth {
+ EDP_6BIT = 0,
+ EDP_8BIT = 1,
+ EDP_10BIT = 2,
+ EDP_12BIT = 3,
+ EDP_16BIT = 4,
+};
+
+enum edp_component_format {
+ EDP_RGB = 0,
+ EDP_YUV422 = 1,
+ EDP_YUV444 = 2,
+};
+
+#define REG_EDP_MAINLINK_CTRL 0x00000004
+#define EDP_MAINLINK_CTRL_ENABLE 0x00000001
+#define EDP_MAINLINK_CTRL_RESET 0x00000002
+
+#define REG_EDP_STATE_CTRL 0x00000008
+#define EDP_STATE_CTRL_TRAIN_PATTERN_1 0x00000001
+#define EDP_STATE_CTRL_TRAIN_PATTERN_2 0x00000002
+#define EDP_STATE_CTRL_TRAIN_PATTERN_3 0x00000004
+#define EDP_STATE_CTRL_SYMBOL_ERR_RATE_MEAS 0x00000008
+#define EDP_STATE_CTRL_PRBS7 0x00000010
+#define EDP_STATE_CTRL_CUSTOM_80_BIT_PATTERN 0x00000020
+#define EDP_STATE_CTRL_SEND_VIDEO 0x00000040
+#define EDP_STATE_CTRL_PUSH_IDLE 0x00000080
+
+#define REG_EDP_CONFIGURATION_CTRL 0x0000000c
+#define EDP_CONFIGURATION_CTRL_SYNC_CLK 0x00000001
+#define EDP_CONFIGURATION_CTRL_STATIC_MVID 0x00000002
+#define EDP_CONFIGURATION_CTRL_PROGRESSIVE 0x00000004
+#define EDP_CONFIGURATION_CTRL_LANES__MASK 0x00000030
+#define EDP_CONFIGURATION_CTRL_LANES__SHIFT 4
+static inline uint32_t EDP_CONFIGURATION_CTRL_LANES(uint32_t val)
+{
+ return ((val) << EDP_CONFIGURATION_CTRL_LANES__SHIFT) & EDP_CONFIGURATION_CTRL_LANES__MASK;
+}
+#define EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING 0x00000040
+#define EDP_CONFIGURATION_CTRL_COLOR__MASK 0x00000100
+#define EDP_CONFIGURATION_CTRL_COLOR__SHIFT 8
+static inline uint32_t EDP_CONFIGURATION_CTRL_COLOR(enum edp_color_depth val)
+{
+ return ((val) << EDP_CONFIGURATION_CTRL_COLOR__SHIFT) & EDP_CONFIGURATION_CTRL_COLOR__MASK;
+}
+
+#define REG_EDP_SOFTWARE_MVID 0x00000014
+
+#define REG_EDP_SOFTWARE_NVID 0x00000018
+
+#define REG_EDP_TOTAL_HOR_VER 0x0000001c
+#define EDP_TOTAL_HOR_VER_HORIZ__MASK 0x0000ffff
+#define EDP_TOTAL_HOR_VER_HORIZ__SHIFT 0
+static inline uint32_t EDP_TOTAL_HOR_VER_HORIZ(uint32_t val)
+{
+ return ((val) << EDP_TOTAL_HOR_VER_HORIZ__SHIFT) & EDP_TOTAL_HOR_VER_HORIZ__MASK;
+}
+#define EDP_TOTAL_HOR_VER_VERT__MASK 0xffff0000
+#define EDP_TOTAL_HOR_VER_VERT__SHIFT 16
+static inline uint32_t EDP_TOTAL_HOR_VER_VERT(uint32_t val)
+{
+ return ((val) << EDP_TOTAL_HOR_VER_VERT__SHIFT) & EDP_TOTAL_HOR_VER_VERT__MASK;
+}
+
+#define REG_EDP_START_HOR_VER_FROM_SYNC 0x00000020
+#define EDP_START_HOR_VER_FROM_SYNC_HORIZ__MASK 0x0000ffff
+#define EDP_START_HOR_VER_FROM_SYNC_HORIZ__SHIFT 0
+static inline uint32_t EDP_START_HOR_VER_FROM_SYNC_HORIZ(uint32_t val)
+{
+ return ((val) << EDP_START_HOR_VER_FROM_SYNC_HORIZ__SHIFT) & EDP_START_HOR_VER_FROM_SYNC_HORIZ__MASK;
+}
+#define EDP_START_HOR_VER_FROM_SYNC_VERT__MASK 0xffff0000
+#define EDP_START_HOR_VER_FROM_SYNC_VERT__SHIFT 16
+static inline uint32_t EDP_START_HOR_VER_FROM_SYNC_VERT(uint32_t val)
+{
+ return ((val) << EDP_START_HOR_VER_FROM_SYNC_VERT__SHIFT) & EDP_START_HOR_VER_FROM_SYNC_VERT__MASK;
+}
+
+#define REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY 0x00000024
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__MASK 0x00007fff
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__SHIFT 0
+static inline uint32_t EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ(uint32_t val)
+{
+ return ((val) << EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__SHIFT) & EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ__MASK;
+}
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC 0x00008000
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__MASK 0x7fff0000
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__SHIFT 16
+static inline uint32_t EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT(uint32_t val)
+{
+ return ((val) << EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__SHIFT) & EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT__MASK;
+}
+#define EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC 0x80000000
+
+#define REG_EDP_ACTIVE_HOR_VER 0x00000028
+#define EDP_ACTIVE_HOR_VER_HORIZ__MASK 0x0000ffff
+#define EDP_ACTIVE_HOR_VER_HORIZ__SHIFT 0
+static inline uint32_t EDP_ACTIVE_HOR_VER_HORIZ(uint32_t val)
+{
+ return ((val) << EDP_ACTIVE_HOR_VER_HORIZ__SHIFT) & EDP_ACTIVE_HOR_VER_HORIZ__MASK;
+}
+#define EDP_ACTIVE_HOR_VER_VERT__MASK 0xffff0000
+#define EDP_ACTIVE_HOR_VER_VERT__SHIFT 16
+static inline uint32_t EDP_ACTIVE_HOR_VER_VERT(uint32_t val)
+{
+ return ((val) << EDP_ACTIVE_HOR_VER_VERT__SHIFT) & EDP_ACTIVE_HOR_VER_VERT__MASK;
+}
+
+#define REG_EDP_MISC1_MISC0 0x0000002c
+#define EDP_MISC1_MISC0_MISC0__MASK 0x000000ff
+#define EDP_MISC1_MISC0_MISC0__SHIFT 0
+static inline uint32_t EDP_MISC1_MISC0_MISC0(uint32_t val)
+{
+ return ((val) << EDP_MISC1_MISC0_MISC0__SHIFT) & EDP_MISC1_MISC0_MISC0__MASK;
+}
+#define EDP_MISC1_MISC0_SYNC 0x00000001
+#define EDP_MISC1_MISC0_COMPONENT_FORMAT__MASK 0x00000006
+#define EDP_MISC1_MISC0_COMPONENT_FORMAT__SHIFT 1
+static inline uint32_t EDP_MISC1_MISC0_COMPONENT_FORMAT(enum edp_component_format val)
+{
+ return ((val) << EDP_MISC1_MISC0_COMPONENT_FORMAT__SHIFT) & EDP_MISC1_MISC0_COMPONENT_FORMAT__MASK;
+}
+#define EDP_MISC1_MISC0_CEA 0x00000008
+#define EDP_MISC1_MISC0_BT709_5 0x00000010
+#define EDP_MISC1_MISC0_COLOR__MASK 0x000000e0
+#define EDP_MISC1_MISC0_COLOR__SHIFT 5
+static inline uint32_t EDP_MISC1_MISC0_COLOR(enum edp_color_depth val)
+{
+ return ((val) << EDP_MISC1_MISC0_COLOR__SHIFT) & EDP_MISC1_MISC0_COLOR__MASK;
+}
+#define EDP_MISC1_MISC0_MISC1__MASK 0x0000ff00
+#define EDP_MISC1_MISC0_MISC1__SHIFT 8
+static inline uint32_t EDP_MISC1_MISC0_MISC1(uint32_t val)
+{
+ return ((val) << EDP_MISC1_MISC0_MISC1__SHIFT) & EDP_MISC1_MISC0_MISC1__MASK;
+}
+#define EDP_MISC1_MISC0_INTERLACED_ODD 0x00000100
+#define EDP_MISC1_MISC0_STEREO__MASK 0x00000600
+#define EDP_MISC1_MISC0_STEREO__SHIFT 9
+static inline uint32_t EDP_MISC1_MISC0_STEREO(uint32_t val)
+{
+ return ((val) << EDP_MISC1_MISC0_STEREO__SHIFT) & EDP_MISC1_MISC0_STEREO__MASK;
+}
+
+#define REG_EDP_PHY_CTRL 0x00000074
+#define EDP_PHY_CTRL_SW_RESET_PLL 0x00000001
+#define EDP_PHY_CTRL_SW_RESET 0x00000004
+
+#define REG_EDP_MAINLINK_READY 0x00000084
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY 0x00000008
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_2_READY 0x00000010
+#define EDP_MAINLINK_READY_TRAIN_PATTERN_3_READY 0x00000020
+
+#define REG_EDP_AUX_CTRL 0x00000300
+#define EDP_AUX_CTRL_ENABLE 0x00000001
+#define EDP_AUX_CTRL_RESET 0x00000002
+
+#define REG_EDP_INTERRUPT_REG_1 0x00000308
+#define EDP_INTERRUPT_REG_1_HPD 0x00000001
+#define EDP_INTERRUPT_REG_1_HPD_ACK 0x00000002
+#define EDP_INTERRUPT_REG_1_HPD_EN 0x00000004
+#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE 0x00000008
+#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE_ACK 0x00000010
+#define EDP_INTERRUPT_REG_1_AUX_I2C_DONE_EN 0x00000020
+#define EDP_INTERRUPT_REG_1_WRONG_ADDR 0x00000040
+#define EDP_INTERRUPT_REG_1_WRONG_ADDR_ACK 0x00000080
+#define EDP_INTERRUPT_REG_1_WRONG_ADDR_EN 0x00000100
+#define EDP_INTERRUPT_REG_1_TIMEOUT 0x00000200
+#define EDP_INTERRUPT_REG_1_TIMEOUT_ACK 0x00000400
+#define EDP_INTERRUPT_REG_1_TIMEOUT_EN 0x00000800
+#define EDP_INTERRUPT_REG_1_NACK_DEFER 0x00001000
+#define EDP_INTERRUPT_REG_1_NACK_DEFER_ACK 0x00002000
+#define EDP_INTERRUPT_REG_1_NACK_DEFER_EN 0x00004000
+#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT 0x00008000
+#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT_ACK 0x00010000
+#define EDP_INTERRUPT_REG_1_WRONG_DATA_CNT_EN 0x00020000
+#define EDP_INTERRUPT_REG_1_I2C_NACK 0x00040000
+#define EDP_INTERRUPT_REG_1_I2C_NACK_ACK 0x00080000
+#define EDP_INTERRUPT_REG_1_I2C_NACK_EN 0x00100000
+#define EDP_INTERRUPT_REG_1_I2C_DEFER 0x00200000
+#define EDP_INTERRUPT_REG_1_I2C_DEFER_ACK 0x00400000
+#define EDP_INTERRUPT_REG_1_I2C_DEFER_EN 0x00800000
+#define EDP_INTERRUPT_REG_1_PLL_UNLOCK 0x01000000
+#define EDP_INTERRUPT_REG_1_PLL_UNLOCK_ACK 0x02000000
+#define EDP_INTERRUPT_REG_1_PLL_UNLOCK_EN 0x04000000
+#define EDP_INTERRUPT_REG_1_AUX_ERROR 0x08000000
+#define EDP_INTERRUPT_REG_1_AUX_ERROR_ACK 0x10000000
+#define EDP_INTERRUPT_REG_1_AUX_ERROR_EN 0x20000000
+
+#define REG_EDP_INTERRUPT_REG_2 0x0000030c
+#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO 0x00000001
+#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO_ACK 0x00000002
+#define EDP_INTERRUPT_REG_2_READY_FOR_VIDEO_EN 0x00000004
+#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT 0x00000008
+#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT_ACK 0x00000010
+#define EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT_EN 0x00000020
+#define EDP_INTERRUPT_REG_2_FRAME_END 0x00000200
+#define EDP_INTERRUPT_REG_2_FRAME_END_ACK 0x00000080
+#define EDP_INTERRUPT_REG_2_FRAME_END_EN 0x00000100
+#define EDP_INTERRUPT_REG_2_CRC_UPDATED 0x00000200
+#define EDP_INTERRUPT_REG_2_CRC_UPDATED_ACK 0x00000400
+#define EDP_INTERRUPT_REG_2_CRC_UPDATED_EN 0x00000800
+
+#define REG_EDP_INTERRUPT_TRANS_NUM 0x00000310
+
+#define REG_EDP_AUX_DATA 0x00000314
+#define EDP_AUX_DATA_READ 0x00000001
+#define EDP_AUX_DATA_DATA__MASK 0x0000ff00
+#define EDP_AUX_DATA_DATA__SHIFT 8
+static inline uint32_t EDP_AUX_DATA_DATA(uint32_t val)
+{
+ return ((val) << EDP_AUX_DATA_DATA__SHIFT) & EDP_AUX_DATA_DATA__MASK;
+}
+#define EDP_AUX_DATA_INDEX__MASK 0x00ff0000
+#define EDP_AUX_DATA_INDEX__SHIFT 16
+static inline uint32_t EDP_AUX_DATA_INDEX(uint32_t val)
+{
+ return ((val) << EDP_AUX_DATA_INDEX__SHIFT) & EDP_AUX_DATA_INDEX__MASK;
+}
+#define EDP_AUX_DATA_INDEX_WRITE 0x80000000
+
+#define REG_EDP_AUX_TRANS_CTRL 0x00000318
+#define EDP_AUX_TRANS_CTRL_I2C 0x00000100
+#define EDP_AUX_TRANS_CTRL_GO 0x00000200
+
+#define REG_EDP_AUX_STATUS 0x00000324
+
+static inline uint32_t REG_EDP_PHY_LN(uint32_t i0) { return 0x00000400 + 0x40*i0; }
+
+static inline uint32_t REG_EDP_PHY_LN_PD_CTL(uint32_t i0) { return 0x00000404 + 0x40*i0; }
+
+#define REG_EDP_PHY_GLB_VM_CFG0 0x00000510
+
+#define REG_EDP_PHY_GLB_VM_CFG1 0x00000514
+
+#define REG_EDP_PHY_GLB_MISC9 0x00000518
+
+#define REG_EDP_PHY_GLB_CFG 0x00000528
+
+#define REG_EDP_PHY_GLB_PD_CTL 0x0000052c
+
+#define REG_EDP_PHY_GLB_PHY_STATUS 0x00000598
+
+
+#endif /* EDP_XML */
diff --git a/drivers/gpu/drm/msm/edp/edp_aux.c b/drivers/gpu/drm/msm/edp/edp_aux.c
new file mode 100644
index 000000000000..5f5a84f6074c
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_aux.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "edp.h"
+#include "edp.xml.h"
+
+#define AUX_CMD_FIFO_LEN 144
+#define AUX_CMD_NATIVE_MAX 16
+#define AUX_CMD_I2C_MAX 128
+
+#define EDP_INTR_AUX_I2C_ERR \
+ (EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
+ EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
+ EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER)
+#define EDP_INTR_TRANS_STATUS \
+ (EDP_INTERRUPT_REG_1_AUX_I2C_DONE | EDP_INTR_AUX_I2C_ERR)
+
+struct edp_aux {
+ void __iomem *base;
+ bool msg_err;
+
+ struct completion msg_comp;
+
+ /* To prevent the message transaction routine from reentry. */
+ struct mutex msg_mutex;
+
+ struct drm_dp_aux drm_aux;
+};
+#define to_edp_aux(x) container_of(x, struct edp_aux, drm_aux)
+
+static int edp_msg_fifo_tx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+ u32 data[4];
+ u32 reg, len;
+ bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+ bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+ u8 *msgdata = msg->buffer;
+ int i;
+
+ if (read)
+ len = 4;
+ else
+ len = msg->size + 4;
+
+ /*
+ * cmd fifo only has depth of 144 bytes
+ */
+ if (len > AUX_CMD_FIFO_LEN)
+ return -EINVAL;
+
+ /* Pack cmd and write to HW */
+ data[0] = (msg->address >> 16) & 0xf; /* addr[19:16] */
+ if (read)
+ data[0] |= BIT(4); /* R/W */
+
+ data[1] = (msg->address >> 8) & 0xff; /* addr[15:8] */
+ data[2] = msg->address & 0xff; /* addr[7:0] */
+ data[3] = (msg->size - 1) & 0xff; /* len[7:0] */
+
+ for (i = 0; i < len; i++) {
+ reg = (i < 4) ? data[i] : msgdata[i - 4];
+ reg = EDP_AUX_DATA_DATA(reg); /* index = 0, write */
+ if (i == 0)
+ reg |= EDP_AUX_DATA_INDEX_WRITE;
+ edp_write(aux->base + REG_EDP_AUX_DATA, reg);
+ }
+
+ reg = 0; /* Transaction number is always 1 */
+ if (!native) /* i2c */
+ reg |= EDP_AUX_TRANS_CTRL_I2C;
+
+ reg |= EDP_AUX_TRANS_CTRL_GO;
+ edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, reg);
+
+ return 0;
+}
+
+static int edp_msg_fifo_rx(struct edp_aux *aux, struct drm_dp_aux_msg *msg)
+{
+ u32 data;
+ u8 *dp;
+ int i;
+ u32 len = msg->size;
+
+ edp_write(aux->base + REG_EDP_AUX_DATA,
+ EDP_AUX_DATA_INDEX_WRITE | EDP_AUX_DATA_READ); /* index = 0 */
+
+ dp = msg->buffer;
+
+ /* discard first byte */
+ data = edp_read(aux->base + REG_EDP_AUX_DATA);
+ for (i = 0; i < len; i++) {
+ data = edp_read(aux->base + REG_EDP_AUX_DATA);
+ dp[i] = (u8)((data >> 8) & 0xff);
+ }
+
+ return 0;
+}
+
+/*
+ * This function does the real job to process an AUX transaction.
+ * It will call msm_edp_aux_ctrl() function to reset the AUX channel,
+ * if the waiting is timeout.
+ * The caller who triggers the transaction should avoid the
+ * msm_edp_aux_ctrl() running concurrently in other threads, i.e.
+ * start transaction only when AUX channel is fully enabled.
+ */
+ssize_t edp_aux_transfer(struct drm_dp_aux *drm_aux, struct drm_dp_aux_msg *msg)
+{
+ struct edp_aux *aux = to_edp_aux(drm_aux);
+ ssize_t ret;
+ bool native = msg->request & (DP_AUX_NATIVE_WRITE & DP_AUX_NATIVE_READ);
+ bool read = msg->request & (DP_AUX_I2C_READ & DP_AUX_NATIVE_READ);
+
+ /* Ignore address only message */
+ if ((msg->size == 0) || (msg->buffer == NULL)) {
+ msg->reply = native ?
+ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+ return msg->size;
+ }
+
+ /* msg sanity check */
+ if ((native && (msg->size > AUX_CMD_NATIVE_MAX)) ||
+ (msg->size > AUX_CMD_I2C_MAX)) {
+ pr_err("%s: invalid msg: size(%d), request(%x)\n",
+ __func__, msg->size, msg->request);
+ return -EINVAL;
+ }
+
+ mutex_lock(&aux->msg_mutex);
+
+ aux->msg_err = false;
+ reinit_completion(&aux->msg_comp);
+
+ ret = edp_msg_fifo_tx(aux, msg);
+ if (ret < 0)
+ goto unlock_exit;
+
+ DBG("wait_for_completion");
+ ret = wait_for_completion_timeout(&aux->msg_comp, 300);
+ if (ret <= 0) {
+ /*
+ * Clear GO and reset AUX channel
+ * to cancel the current transaction.
+ */
+ edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
+ msm_edp_aux_ctrl(aux, 1);
+ pr_err("%s: aux timeout, %d\n", __func__, ret);
+ goto unlock_exit;
+ }
+ DBG("completion");
+
+ if (!aux->msg_err) {
+ if (read) {
+ ret = edp_msg_fifo_rx(aux, msg);
+ if (ret < 0)
+ goto unlock_exit;
+ }
+
+ msg->reply = native ?
+ DP_AUX_NATIVE_REPLY_ACK : DP_AUX_I2C_REPLY_ACK;
+ } else {
+ /* Reply defer to retry */
+ msg->reply = native ?
+ DP_AUX_NATIVE_REPLY_DEFER : DP_AUX_I2C_REPLY_DEFER;
+ /*
+ * The sleep time in caller is not long enough to make sure
+ * our H/W completes transactions. Add more defer time here.
+ */
+ msleep(100);
+ }
+
+ /* Return requested size for success or retry */
+ ret = msg->size;
+
+unlock_exit:
+ mutex_unlock(&aux->msg_mutex);
+ return ret;
+}
+
+void *msm_edp_aux_init(struct device *dev, void __iomem *regbase,
+ struct drm_dp_aux **drm_aux)
+{
+ struct edp_aux *aux = NULL;
+ int ret;
+
+ DBG("");
+ aux = devm_kzalloc(dev, sizeof(*aux), GFP_KERNEL);
+ if (!aux)
+ return NULL;
+
+ aux->base = regbase;
+ mutex_init(&aux->msg_mutex);
+ init_completion(&aux->msg_comp);
+
+ aux->drm_aux.name = "msm_edp_aux";
+ aux->drm_aux.dev = dev;
+ aux->drm_aux.transfer = edp_aux_transfer;
+ ret = drm_dp_aux_register(&aux->drm_aux);
+ if (ret) {
+ pr_err("%s: failed to register drm aux: %d\n", __func__, ret);
+ mutex_destroy(&aux->msg_mutex);
+ }
+
+ if (drm_aux && aux)
+ *drm_aux = &aux->drm_aux;
+
+ return aux;
+}
+
+void msm_edp_aux_destroy(struct device *dev, struct edp_aux *aux)
+{
+ if (aux) {
+ drm_dp_aux_unregister(&aux->drm_aux);
+ mutex_destroy(&aux->msg_mutex);
+ }
+}
+
+irqreturn_t msm_edp_aux_irq(struct edp_aux *aux, u32 isr)
+{
+ if (isr & EDP_INTR_TRANS_STATUS) {
+ DBG("isr=%x", isr);
+ edp_write(aux->base + REG_EDP_AUX_TRANS_CTRL, 0);
+
+ if (isr & EDP_INTR_AUX_I2C_ERR)
+ aux->msg_err = true;
+ else
+ aux->msg_err = false;
+
+ complete(&aux->msg_comp);
+ }
+
+ return IRQ_HANDLED;
+}
+
+void msm_edp_aux_ctrl(struct edp_aux *aux, int enable)
+{
+ u32 data;
+
+ DBG("enable=%d", enable);
+ data = edp_read(aux->base + REG_EDP_AUX_CTRL);
+
+ if (enable) {
+ data |= EDP_AUX_CTRL_RESET;
+ edp_write(aux->base + REG_EDP_AUX_CTRL, data);
+ /* Make sure full reset */
+ wmb();
+ usleep_range(500, 1000);
+
+ data &= ~EDP_AUX_CTRL_RESET;
+ data |= EDP_AUX_CTRL_ENABLE;
+ edp_write(aux->base + REG_EDP_AUX_CTRL, data);
+ } else {
+ data &= ~EDP_AUX_CTRL_ENABLE;
+ edp_write(aux->base + REG_EDP_AUX_CTRL, data);
+ }
+}
+
diff --git a/drivers/gpu/drm/msm/edp/edp_bridge.c b/drivers/gpu/drm/msm/edp/edp_bridge.c
new file mode 100644
index 000000000000..2bc73f82f3f5
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_bridge.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "edp.h"
+
+struct edp_bridge {
+ struct drm_bridge base;
+ struct msm_edp *edp;
+};
+#define to_edp_bridge(x) container_of(x, struct edp_bridge, base)
+
+void edp_bridge_destroy(struct drm_bridge *bridge)
+{
+}
+
+static void edp_bridge_pre_enable(struct drm_bridge *bridge)
+{
+ struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
+ struct msm_edp *edp = edp_bridge->edp;
+
+ DBG("");
+ msm_edp_ctrl_power(edp->ctrl, true);
+}
+
+static void edp_bridge_enable(struct drm_bridge *bridge)
+{
+ DBG("");
+}
+
+static void edp_bridge_disable(struct drm_bridge *bridge)
+{
+ DBG("");
+}
+
+static void edp_bridge_post_disable(struct drm_bridge *bridge)
+{
+ struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
+ struct msm_edp *edp = edp_bridge->edp;
+
+ DBG("");
+ msm_edp_ctrl_power(edp->ctrl, false);
+}
+
+static void edp_bridge_mode_set(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct drm_device *dev = bridge->dev;
+ struct drm_connector *connector;
+ struct edp_bridge *edp_bridge = to_edp_bridge(bridge);
+ struct msm_edp *edp = edp_bridge->edp;
+
+ DBG("set mode: %d:\"%s\" %d %d %d %d %d %d %d %d %d %d 0x%x 0x%x",
+ mode->base.id, mode->name,
+ mode->vrefresh, mode->clock,
+ mode->hdisplay, mode->hsync_start,
+ mode->hsync_end, mode->htotal,
+ mode->vdisplay, mode->vsync_start,
+ mode->vsync_end, mode->vtotal,
+ mode->type, mode->flags);
+
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if ((connector->encoder != NULL) &&
+ (connector->encoder->bridge == bridge)) {
+ msm_edp_ctrl_timing_cfg(edp->ctrl,
+ adjusted_mode, &connector->display_info);
+ break;
+ }
+ }
+}
+
+static const struct drm_bridge_funcs edp_bridge_funcs = {
+ .pre_enable = edp_bridge_pre_enable,
+ .enable = edp_bridge_enable,
+ .disable = edp_bridge_disable,
+ .post_disable = edp_bridge_post_disable,
+ .mode_set = edp_bridge_mode_set,
+};
+
+/* initialize bridge */
+struct drm_bridge *msm_edp_bridge_init(struct msm_edp *edp)
+{
+ struct drm_bridge *bridge = NULL;
+ struct edp_bridge *edp_bridge;
+ int ret;
+
+ edp_bridge = devm_kzalloc(edp->dev->dev,
+ sizeof(*edp_bridge), GFP_KERNEL);
+ if (!edp_bridge) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ edp_bridge->edp = edp;
+
+ bridge = &edp_bridge->base;
+ bridge->funcs = &edp_bridge_funcs;
+
+ ret = drm_bridge_attach(edp->dev, bridge);
+ if (ret)
+ goto fail;
+
+ return bridge;
+
+fail:
+ if (bridge)
+ edp_bridge_destroy(bridge);
+
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/edp/edp_connector.c b/drivers/gpu/drm/msm/edp/edp_connector.c
new file mode 100644
index 000000000000..d8812e84da54
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_connector.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "drm/drm_edid.h"
+#include "msm_kms.h"
+#include "edp.h"
+
+struct edp_connector {
+ struct drm_connector base;
+ struct msm_edp *edp;
+};
+#define to_edp_connector(x) container_of(x, struct edp_connector, base)
+
+static enum drm_connector_status edp_connector_detect(
+ struct drm_connector *connector, bool force)
+{
+ struct edp_connector *edp_connector = to_edp_connector(connector);
+ struct msm_edp *edp = edp_connector->edp;
+
+ DBG("");
+ return msm_edp_ctrl_panel_connected(edp->ctrl) ?
+ connector_status_connected : connector_status_disconnected;
+}
+
+static void edp_connector_destroy(struct drm_connector *connector)
+{
+ struct edp_connector *edp_connector = to_edp_connector(connector);
+
+ DBG("");
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+
+ kfree(edp_connector);
+}
+
+static int edp_connector_get_modes(struct drm_connector *connector)
+{
+ struct edp_connector *edp_connector = to_edp_connector(connector);
+ struct msm_edp *edp = edp_connector->edp;
+
+ struct edid *drm_edid = NULL;
+ int ret = 0;
+
+ DBG("");
+ ret = msm_edp_ctrl_get_panel_info(edp->ctrl, connector, &drm_edid);
+ if (ret)
+ return ret;
+
+ drm_mode_connector_update_edid_property(connector, drm_edid);
+ if (drm_edid)
+ ret = drm_add_edid_modes(connector, drm_edid);
+
+ return ret;
+}
+
+static int edp_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct edp_connector *edp_connector = to_edp_connector(connector);
+ struct msm_edp *edp = edp_connector->edp;
+ struct msm_drm_private *priv = connector->dev->dev_private;
+ struct msm_kms *kms = priv->kms;
+ long actual, requested;
+
+ requested = 1000 * mode->clock;
+ actual = kms->funcs->round_pixclk(kms,
+ requested, edp_connector->edp->encoder);
+
+ DBG("requested=%ld, actual=%ld", requested, actual);
+ if (actual != requested)
+ return MODE_CLOCK_RANGE;
+
+ if (!msm_edp_ctrl_pixel_clock_valid(
+ edp->ctrl, mode->clock, NULL, NULL))
+ return MODE_CLOCK_RANGE;
+
+ /* Invalidate all modes if color format is not supported */
+ if (connector->display_info.bpc > 8)
+ return MODE_BAD;
+
+ return MODE_OK;
+}
+
+static struct drm_encoder *
+edp_connector_best_encoder(struct drm_connector *connector)
+{
+ struct edp_connector *edp_connector = to_edp_connector(connector);
+
+ DBG("");
+ return edp_connector->edp->encoder;
+}
+
+static const struct drm_connector_funcs edp_connector_funcs = {
+ .dpms = drm_atomic_helper_connector_dpms,
+ .detect = edp_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = edp_connector_destroy,
+ .reset = drm_atomic_helper_connector_reset,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static const struct drm_connector_helper_funcs edp_connector_helper_funcs = {
+ .get_modes = edp_connector_get_modes,
+ .mode_valid = edp_connector_mode_valid,
+ .best_encoder = edp_connector_best_encoder,
+};
+
+/* initialize connector */
+struct drm_connector *msm_edp_connector_init(struct msm_edp *edp)
+{
+ struct drm_connector *connector = NULL;
+ struct edp_connector *edp_connector;
+ int ret;
+
+ edp_connector = kzalloc(sizeof(*edp_connector), GFP_KERNEL);
+ if (!edp_connector) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ edp_connector->edp = edp;
+
+ connector = &edp_connector->base;
+
+ ret = drm_connector_init(edp->dev, connector, &edp_connector_funcs,
+ DRM_MODE_CONNECTOR_eDP);
+ if (ret)
+ goto fail;
+
+ drm_connector_helper_add(connector, &edp_connector_helper_funcs);
+
+ /* We don't support HPD, so only poll status until connected. */
+ connector->polled = DRM_CONNECTOR_POLL_CONNECT;
+
+ /* Display driver doesn't support interlace now. */
+ connector->interlace_allowed = false;
+ connector->doublescan_allowed = false;
+
+ ret = drm_connector_register(connector);
+ if (ret)
+ goto fail;
+
+ return connector;
+
+fail:
+ if (connector)
+ edp_connector_destroy(connector);
+
+ return ERR_PTR(ret);
+}
diff --git a/drivers/gpu/drm/msm/edp/edp_ctrl.c b/drivers/gpu/drm/msm/edp/edp_ctrl.c
new file mode 100644
index 000000000000..3e246210c46f
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_ctrl.c
@@ -0,0 +1,1373 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
+
+#include "drm_crtc.h"
+#include "drm_dp_helper.h"
+#include "drm_edid.h"
+#include "edp.h"
+#include "edp.xml.h"
+
+#define VDDA_MIN_UV 1800000 /* uV units */
+#define VDDA_MAX_UV 1800000 /* uV units */
+#define VDDA_UA_ON_LOAD 100000 /* uA units */
+#define VDDA_UA_OFF_LOAD 100 /* uA units */
+
+#define DPCD_LINK_VOLTAGE_MAX 4
+#define DPCD_LINK_PRE_EMPHASIS_MAX 4
+
+#define EDP_LINK_BW_MAX DP_LINK_BW_2_7
+
+/* Link training return value */
+#define EDP_TRAIN_FAIL -1
+#define EDP_TRAIN_SUCCESS 0
+#define EDP_TRAIN_RECONFIG 1
+
+#define EDP_CLK_MASK_AHB BIT(0)
+#define EDP_CLK_MASK_AUX BIT(1)
+#define EDP_CLK_MASK_LINK BIT(2)
+#define EDP_CLK_MASK_PIXEL BIT(3)
+#define EDP_CLK_MASK_MDP_CORE BIT(4)
+#define EDP_CLK_MASK_LINK_CHAN (EDP_CLK_MASK_LINK | EDP_CLK_MASK_PIXEL)
+#define EDP_CLK_MASK_AUX_CHAN \
+ (EDP_CLK_MASK_AHB | EDP_CLK_MASK_AUX | EDP_CLK_MASK_MDP_CORE)
+#define EDP_CLK_MASK_ALL (EDP_CLK_MASK_AUX_CHAN | EDP_CLK_MASK_LINK_CHAN)
+
+#define EDP_BACKLIGHT_MAX 255
+
+#define EDP_INTR_STATUS1 \
+ (EDP_INTERRUPT_REG_1_HPD | EDP_INTERRUPT_REG_1_AUX_I2C_DONE | \
+ EDP_INTERRUPT_REG_1_WRONG_ADDR | EDP_INTERRUPT_REG_1_TIMEOUT | \
+ EDP_INTERRUPT_REG_1_NACK_DEFER | EDP_INTERRUPT_REG_1_WRONG_DATA_CNT | \
+ EDP_INTERRUPT_REG_1_I2C_NACK | EDP_INTERRUPT_REG_1_I2C_DEFER | \
+ EDP_INTERRUPT_REG_1_PLL_UNLOCK | EDP_INTERRUPT_REG_1_AUX_ERROR)
+#define EDP_INTR_MASK1 (EDP_INTR_STATUS1 << 2)
+#define EDP_INTR_STATUS2 \
+ (EDP_INTERRUPT_REG_2_READY_FOR_VIDEO | \
+ EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT | \
+ EDP_INTERRUPT_REG_2_FRAME_END | EDP_INTERRUPT_REG_2_CRC_UPDATED)
+#define EDP_INTR_MASK2 (EDP_INTR_STATUS2 << 2)
+
+struct edp_ctrl {
+ struct platform_device *pdev;
+
+ void __iomem *base;
+
+ /* regulators */
+ struct regulator *vdda_vreg;
+ struct regulator *lvl_vreg;
+
+ /* clocks */
+ struct clk *aux_clk;
+ struct clk *pixel_clk;
+ struct clk *ahb_clk;
+ struct clk *link_clk;
+ struct clk *mdp_core_clk;
+
+ /* gpios */
+ struct gpio_desc *panel_en_gpio;
+ struct gpio_desc *panel_hpd_gpio;
+
+ /* completion and mutex */
+ struct completion idle_comp;
+ struct mutex dev_mutex; /* To protect device power status */
+
+ /* work queue */
+ struct work_struct on_work;
+ struct work_struct off_work;
+ struct workqueue_struct *workqueue;
+
+ /* Interrupt register lock */
+ spinlock_t irq_lock;
+
+ bool edp_connected;
+ bool power_on;
+
+ /* edid raw data */
+ struct edid *edid;
+
+ struct drm_dp_link dp_link;
+ struct drm_dp_aux *drm_aux;
+
+ /* dpcd raw data */
+ u8 dpcd[DP_RECEIVER_CAP_SIZE];
+
+ /* Link status */
+ u8 link_rate;
+ u8 lane_cnt;
+ u8 v_level;
+ u8 p_level;
+
+ /* Timing status */
+ u8 interlaced;
+ u32 pixel_rate; /* in kHz */
+ u32 color_depth;
+
+ struct edp_aux *aux;
+ struct edp_phy *phy;
+};
+
+struct edp_pixel_clk_div {
+ u32 rate; /* in kHz */
+ u32 m;
+ u32 n;
+};
+
+#define EDP_PIXEL_CLK_NUM 8
+static const struct edp_pixel_clk_div clk_divs[2][EDP_PIXEL_CLK_NUM] = {
+ { /* Link clock = 162MHz, source clock = 810MHz */
+ {119000, 31, 211}, /* WSXGA+ 1680x1050@60Hz CVT */
+ {130250, 32, 199}, /* UXGA 1600x1200@60Hz CVT */
+ {148500, 11, 60}, /* FHD 1920x1080@60Hz */
+ {154000, 50, 263}, /* WUXGA 1920x1200@60Hz CVT */
+ {209250, 31, 120}, /* QXGA 2048x1536@60Hz CVT */
+ {268500, 119, 359}, /* WQXGA 2560x1600@60Hz CVT */
+ {138530, 33, 193}, /* AUO B116HAN03.0 Panel */
+ {141400, 48, 275}, /* AUO B133HTN01.2 Panel */
+ },
+ { /* Link clock = 270MHz, source clock = 675MHz */
+ {119000, 52, 295}, /* WSXGA+ 1680x1050@60Hz CVT */
+ {130250, 11, 57}, /* UXGA 1600x1200@60Hz CVT */
+ {148500, 11, 50}, /* FHD 1920x1080@60Hz */
+ {154000, 47, 206}, /* WUXGA 1920x1200@60Hz CVT */
+ {209250, 31, 100}, /* QXGA 2048x1536@60Hz CVT */
+ {268500, 107, 269}, /* WQXGA 2560x1600@60Hz CVT */
+ {138530, 63, 307}, /* AUO B116HAN03.0 Panel */
+ {141400, 53, 253}, /* AUO B133HTN01.2 Panel */
+ },
+};
+
+static int edp_clk_init(struct edp_ctrl *ctrl)
+{
+ struct device *dev = &ctrl->pdev->dev;
+ int ret;
+
+ ctrl->aux_clk = devm_clk_get(dev, "core_clk");
+ if (IS_ERR(ctrl->aux_clk)) {
+ ret = PTR_ERR(ctrl->aux_clk);
+ pr_err("%s: Can't find aux_clk, %d\n", __func__, ret);
+ ctrl->aux_clk = NULL;
+ return ret;
+ }
+
+ ctrl->pixel_clk = devm_clk_get(dev, "pixel_clk");
+ if (IS_ERR(ctrl->pixel_clk)) {
+ ret = PTR_ERR(ctrl->pixel_clk);
+ pr_err("%s: Can't find pixel_clk, %d\n", __func__, ret);
+ ctrl->pixel_clk = NULL;
+ return ret;
+ }
+
+ ctrl->ahb_clk = devm_clk_get(dev, "iface_clk");
+ if (IS_ERR(ctrl->ahb_clk)) {
+ ret = PTR_ERR(ctrl->ahb_clk);
+ pr_err("%s: Can't find ahb_clk, %d\n", __func__, ret);
+ ctrl->ahb_clk = NULL;
+ return ret;
+ }
+
+ ctrl->link_clk = devm_clk_get(dev, "link_clk");
+ if (IS_ERR(ctrl->link_clk)) {
+ ret = PTR_ERR(ctrl->link_clk);
+ pr_err("%s: Can't find link_clk, %d\n", __func__, ret);
+ ctrl->link_clk = NULL;
+ return ret;
+ }
+
+ /* need mdp core clock to receive irq */
+ ctrl->mdp_core_clk = devm_clk_get(dev, "mdp_core_clk");
+ if (IS_ERR(ctrl->mdp_core_clk)) {
+ ret = PTR_ERR(ctrl->mdp_core_clk);
+ pr_err("%s: Can't find mdp_core_clk, %d\n", __func__, ret);
+ ctrl->mdp_core_clk = NULL;
+ return ret;
+ }
+
+ return 0;
+}
+
+static int edp_clk_enable(struct edp_ctrl *ctrl, u32 clk_mask)
+{
+ int ret;
+
+ DBG("mask=%x", clk_mask);
+ /* ahb_clk should be enabled first */
+ if (clk_mask & EDP_CLK_MASK_AHB) {
+ ret = clk_prepare_enable(ctrl->ahb_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable ahb clk\n", __func__);
+ goto f0;
+ }
+ }
+ if (clk_mask & EDP_CLK_MASK_AUX) {
+ ret = clk_set_rate(ctrl->aux_clk, 19200000);
+ if (ret) {
+ pr_err("%s: Failed to set rate aux clk\n", __func__);
+ goto f1;
+ }
+ ret = clk_prepare_enable(ctrl->aux_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable aux clk\n", __func__);
+ goto f1;
+ }
+ }
+ /* Need to set rate and enable link_clk prior to pixel_clk */
+ if (clk_mask & EDP_CLK_MASK_LINK) {
+ DBG("edp->link_clk, set_rate %ld",
+ (unsigned long)ctrl->link_rate * 27000000);
+ ret = clk_set_rate(ctrl->link_clk,
+ (unsigned long)ctrl->link_rate * 27000000);
+ if (ret) {
+ pr_err("%s: Failed to set rate to link clk\n",
+ __func__);
+ goto f2;
+ }
+
+ ret = clk_prepare_enable(ctrl->link_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable link clk\n", __func__);
+ goto f2;
+ }
+ }
+ if (clk_mask & EDP_CLK_MASK_PIXEL) {
+ DBG("edp->pixel_clk, set_rate %ld",
+ (unsigned long)ctrl->pixel_rate * 1000);
+ ret = clk_set_rate(ctrl->pixel_clk,
+ (unsigned long)ctrl->pixel_rate * 1000);
+ if (ret) {
+ pr_err("%s: Failed to set rate to pixel clk\n",
+ __func__);
+ goto f3;
+ }
+
+ ret = clk_prepare_enable(ctrl->pixel_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable pixel clk\n", __func__);
+ goto f3;
+ }
+ }
+ if (clk_mask & EDP_CLK_MASK_MDP_CORE) {
+ ret = clk_prepare_enable(ctrl->mdp_core_clk);
+ if (ret) {
+ pr_err("%s: Failed to enable mdp core clk\n", __func__);
+ goto f4;
+ }
+ }
+
+ return 0;
+
+f4:
+ if (clk_mask & EDP_CLK_MASK_PIXEL)
+ clk_disable_unprepare(ctrl->pixel_clk);
+f3:
+ if (clk_mask & EDP_CLK_MASK_LINK)
+ clk_disable_unprepare(ctrl->link_clk);
+f2:
+ if (clk_mask & EDP_CLK_MASK_AUX)
+ clk_disable_unprepare(ctrl->aux_clk);
+f1:
+ if (clk_mask & EDP_CLK_MASK_AHB)
+ clk_disable_unprepare(ctrl->ahb_clk);
+f0:
+ return ret;
+}
+
+static void edp_clk_disable(struct edp_ctrl *ctrl, u32 clk_mask)
+{
+ if (clk_mask & EDP_CLK_MASK_MDP_CORE)
+ clk_disable_unprepare(ctrl->mdp_core_clk);
+ if (clk_mask & EDP_CLK_MASK_PIXEL)
+ clk_disable_unprepare(ctrl->pixel_clk);
+ if (clk_mask & EDP_CLK_MASK_LINK)
+ clk_disable_unprepare(ctrl->link_clk);
+ if (clk_mask & EDP_CLK_MASK_AUX)
+ clk_disable_unprepare(ctrl->aux_clk);
+ if (clk_mask & EDP_CLK_MASK_AHB)
+ clk_disable_unprepare(ctrl->ahb_clk);
+}
+
+static int edp_regulator_init(struct edp_ctrl *ctrl)
+{
+ struct device *dev = &ctrl->pdev->dev;
+
+ DBG("");
+ ctrl->vdda_vreg = devm_regulator_get(dev, "vdda");
+ if (IS_ERR(ctrl->vdda_vreg)) {
+ pr_err("%s: Could not get vdda reg, ret = %ld\n", __func__,
+ PTR_ERR(ctrl->vdda_vreg));
+ ctrl->vdda_vreg = NULL;
+ return PTR_ERR(ctrl->vdda_vreg);
+ }
+ ctrl->lvl_vreg = devm_regulator_get(dev, "lvl-vdd");
+ if (IS_ERR(ctrl->lvl_vreg)) {
+ pr_err("Could not get lvl-vdd reg, %ld",
+ PTR_ERR(ctrl->lvl_vreg));
+ ctrl->lvl_vreg = NULL;
+ return PTR_ERR(ctrl->lvl_vreg);
+ }
+
+ return 0;
+}
+
+static int edp_regulator_enable(struct edp_ctrl *ctrl)
+{
+ int ret;
+
+ ret = regulator_set_voltage(ctrl->vdda_vreg, VDDA_MIN_UV, VDDA_MAX_UV);
+ if (ret) {
+ pr_err("%s:vdda_vreg set_voltage failed, %d\n", __func__, ret);
+ goto vdda_set_fail;
+ }
+
+ ret = regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_ON_LOAD);
+ if (ret < 0) {
+ pr_err("%s: vdda_vreg set regulator mode failed.\n", __func__);
+ goto vdda_set_fail;
+ }
+
+ ret = regulator_enable(ctrl->vdda_vreg);
+ if (ret) {
+ pr_err("%s: Failed to enable vdda_vreg regulator.\n", __func__);
+ goto vdda_enable_fail;
+ }
+
+ ret = regulator_enable(ctrl->lvl_vreg);
+ if (ret) {
+ pr_err("Failed to enable lvl-vdd reg regulator, %d", ret);
+ goto lvl_enable_fail;
+ }
+
+ DBG("exit");
+ return 0;
+
+lvl_enable_fail:
+ regulator_disable(ctrl->vdda_vreg);
+vdda_enable_fail:
+ regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD);
+vdda_set_fail:
+ return ret;
+}
+
+static void edp_regulator_disable(struct edp_ctrl *ctrl)
+{
+ regulator_disable(ctrl->lvl_vreg);
+ regulator_disable(ctrl->vdda_vreg);
+ regulator_set_optimum_mode(ctrl->vdda_vreg, VDDA_UA_OFF_LOAD);
+}
+
+static int edp_gpio_config(struct edp_ctrl *ctrl)
+{
+ struct device *dev = &ctrl->pdev->dev;
+ int ret;
+
+ ctrl->panel_hpd_gpio = devm_gpiod_get(dev, "panel-hpd");
+ if (IS_ERR(ctrl->panel_hpd_gpio)) {
+ ret = PTR_ERR(ctrl->panel_hpd_gpio);
+ ctrl->panel_hpd_gpio = NULL;
+ pr_err("%s: cannot get panel-hpd-gpios, %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = gpiod_direction_input(ctrl->panel_hpd_gpio);
+ if (ret) {
+ pr_err("%s: Set direction for hpd failed, %d\n", __func__, ret);
+ return ret;
+ }
+
+ ctrl->panel_en_gpio = devm_gpiod_get(dev, "panel-en");
+ if (IS_ERR(ctrl->panel_en_gpio)) {
+ ret = PTR_ERR(ctrl->panel_en_gpio);
+ ctrl->panel_en_gpio = NULL;
+ pr_err("%s: cannot get panel-en-gpios, %d\n", __func__, ret);
+ return ret;
+ }
+
+ ret = gpiod_direction_output(ctrl->panel_en_gpio, 0);
+ if (ret) {
+ pr_err("%s: Set direction for panel_en failed, %d\n",
+ __func__, ret);
+ return ret;
+ }
+
+ DBG("gpio on");
+
+ return 0;
+}
+
+static void edp_ctrl_irq_enable(struct edp_ctrl *ctrl, int enable)
+{
+ unsigned long flags;
+
+ DBG("%d", enable);
+ spin_lock_irqsave(&ctrl->irq_lock, flags);
+ if (enable) {
+ edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, EDP_INTR_MASK1);
+ edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, EDP_INTR_MASK2);
+ } else {
+ edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, 0x0);
+ edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, 0x0);
+ }
+ spin_unlock_irqrestore(&ctrl->irq_lock, flags);
+ DBG("exit");
+}
+
+static void edp_fill_link_cfg(struct edp_ctrl *ctrl)
+{
+ u32 prate;
+ u32 lrate;
+ u32 bpp;
+ u8 max_lane = ctrl->dp_link.num_lanes;
+ u8 lane;
+
+ prate = ctrl->pixel_rate;
+ bpp = ctrl->color_depth * 3;
+
+ /*
+ * By default, use the maximum link rate and minimum lane count,
+ * so that we can do rate down shift during link training.
+ */
+ ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate);
+
+ prate *= bpp;
+ prate /= 8; /* in kByte */
+
+ lrate = 270000; /* in kHz */
+ lrate *= ctrl->link_rate;
+ lrate /= 10; /* in kByte, 10 bits --> 8 bits */
+
+ for (lane = 1; lane <= max_lane; lane <<= 1) {
+ if (lrate >= prate)
+ break;
+ lrate <<= 1;
+ }
+
+ ctrl->lane_cnt = lane;
+ DBG("rate=%d lane=%d", ctrl->link_rate, ctrl->lane_cnt);
+}
+
+static void edp_config_ctrl(struct edp_ctrl *ctrl)
+{
+ u32 data;
+ enum edp_color_depth depth;
+
+ data = EDP_CONFIGURATION_CTRL_LANES(ctrl->lane_cnt - 1);
+
+ if (ctrl->dp_link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
+ data |= EDP_CONFIGURATION_CTRL_ENHANCED_FRAMING;
+
+ depth = EDP_6BIT;
+ if (ctrl->color_depth == 8)
+ depth = EDP_8BIT;
+
+ data |= EDP_CONFIGURATION_CTRL_COLOR(depth);
+
+ if (!ctrl->interlaced) /* progressive */
+ data |= EDP_CONFIGURATION_CTRL_PROGRESSIVE;
+
+ data |= (EDP_CONFIGURATION_CTRL_SYNC_CLK |
+ EDP_CONFIGURATION_CTRL_STATIC_MVID);
+
+ edp_write(ctrl->base + REG_EDP_CONFIGURATION_CTRL, data);
+}
+
+static void edp_state_ctrl(struct edp_ctrl *ctrl, u32 state)
+{
+ edp_write(ctrl->base + REG_EDP_STATE_CTRL, state);
+ /* Make sure H/W status is set */
+ wmb();
+}
+
+static int edp_lane_set_write(struct edp_ctrl *ctrl,
+ u8 voltage_level, u8 pre_emphasis_level)
+{
+ int i;
+ u8 buf[4];
+
+ if (voltage_level >= DPCD_LINK_VOLTAGE_MAX)
+ voltage_level |= 0x04;
+
+ if (pre_emphasis_level >= DPCD_LINK_PRE_EMPHASIS_MAX)
+ pre_emphasis_level |= 0x04;
+
+ pre_emphasis_level <<= 3;
+
+ for (i = 0; i < 4; i++)
+ buf[i] = voltage_level | pre_emphasis_level;
+
+ DBG("%s: p|v=0x%x", __func__, voltage_level | pre_emphasis_level);
+ if (drm_dp_dpcd_write(ctrl->drm_aux, 0x103, buf, 4) < 4) {
+ pr_err("%s: Set sw/pe to panel failed\n", __func__);
+ return -ENOLINK;
+ }
+
+ return 0;
+}
+
+static int edp_train_pattern_set_write(struct edp_ctrl *ctrl, u8 pattern)
+{
+ u8 p = pattern;
+
+ DBG("pattern=%x", p);
+ if (drm_dp_dpcd_write(ctrl->drm_aux,
+ DP_TRAINING_PATTERN_SET, &p, 1) < 1) {
+ pr_err("%s: Set training pattern to panel failed\n", __func__);
+ return -ENOLINK;
+ }
+
+ return 0;
+}
+
+static void edp_sink_train_set_adjust(struct edp_ctrl *ctrl,
+ const u8 *link_status)
+{
+ int i;
+ u8 max = 0;
+ u8 data;
+
+ /* use the max level across lanes */
+ for (i = 0; i < ctrl->lane_cnt; i++) {
+ data = drm_dp_get_adjust_request_voltage(link_status, i);
+ DBG("lane=%d req_voltage_swing=0x%x", i, data);
+ if (max < data)
+ max = data;
+ }
+
+ ctrl->v_level = max >> DP_TRAIN_VOLTAGE_SWING_SHIFT;
+
+ /* use the max level across lanes */
+ max = 0;
+ for (i = 0; i < ctrl->lane_cnt; i++) {
+ data = drm_dp_get_adjust_request_pre_emphasis(link_status, i);
+ DBG("lane=%d req_pre_emphasis=0x%x", i, data);
+ if (max < data)
+ max = data;
+ }
+
+ ctrl->p_level = max >> DP_TRAIN_PRE_EMPHASIS_SHIFT;
+ DBG("v_level=%d, p_level=%d", ctrl->v_level, ctrl->p_level);
+}
+
+static void edp_host_train_set(struct edp_ctrl *ctrl, u32 train)
+{
+ int cnt = 10;
+ u32 data;
+ u32 shift = train - 1;
+
+ DBG("train=%d", train);
+
+ edp_state_ctrl(ctrl, EDP_STATE_CTRL_TRAIN_PATTERN_1 << shift);
+ while (--cnt) {
+ data = edp_read(ctrl->base + REG_EDP_MAINLINK_READY);
+ if (data & (EDP_MAINLINK_READY_TRAIN_PATTERN_1_READY << shift))
+ break;
+ }
+
+ if (cnt == 0)
+ pr_err("%s: set link_train=%d failed\n", __func__, train);
+}
+
+static const u8 vm_pre_emphasis[4][4] = {
+ {0x03, 0x06, 0x09, 0x0C}, /* pe0, 0 db */
+ {0x03, 0x06, 0x09, 0xFF}, /* pe1, 3.5 db */
+ {0x03, 0x06, 0xFF, 0xFF}, /* pe2, 6.0 db */
+ {0x03, 0xFF, 0xFF, 0xFF} /* pe3, 9.5 db */
+};
+
+/* voltage swing, 0.2v and 1.0v are not support */
+static const u8 vm_voltage_swing[4][4] = {
+ {0x14, 0x18, 0x1A, 0x1E}, /* sw0, 0.4v */
+ {0x18, 0x1A, 0x1E, 0xFF}, /* sw1, 0.6 v */
+ {0x1A, 0x1E, 0xFF, 0xFF}, /* sw1, 0.8 v */
+ {0x1E, 0xFF, 0xFF, 0xFF} /* sw1, 1.2 v, optional */
+};
+
+static int edp_voltage_pre_emphasise_set(struct edp_ctrl *ctrl)
+{
+ u32 value0;
+ u32 value1;
+
+ DBG("v=%d p=%d", ctrl->v_level, ctrl->p_level);
+
+ value0 = vm_pre_emphasis[(int)(ctrl->v_level)][(int)(ctrl->p_level)];
+ value1 = vm_voltage_swing[(int)(ctrl->v_level)][(int)(ctrl->p_level)];
+
+ /* Configure host and panel only if both values are allowed */
+ if (value0 != 0xFF && value1 != 0xFF) {
+ msm_edp_phy_vm_pe_cfg(ctrl->phy, value0, value1);
+ return edp_lane_set_write(ctrl, ctrl->v_level, ctrl->p_level);
+ }
+
+ return -EINVAL;
+}
+
+static int edp_start_link_train_1(struct edp_ctrl *ctrl)
+{
+ u8 link_status[DP_LINK_STATUS_SIZE];
+ u8 old_v_level;
+ int tries;
+ int ret;
+ int rlen;
+
+ DBG("");
+
+ edp_host_train_set(ctrl, DP_TRAINING_PATTERN_1);
+ ret = edp_voltage_pre_emphasise_set(ctrl);
+ if (ret)
+ return ret;
+ ret = edp_train_pattern_set_write(ctrl,
+ DP_TRAINING_PATTERN_1 | DP_RECOVERED_CLOCK_OUT_EN);
+ if (ret)
+ return ret;
+
+ tries = 0;
+ old_v_level = ctrl->v_level;
+ while (1) {
+ drm_dp_link_train_clock_recovery_delay(ctrl->dpcd);
+
+ rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status);
+ if (rlen < DP_LINK_STATUS_SIZE) {
+ pr_err("%s: read link status failed\n", __func__);
+ return -ENOLINK;
+ }
+ if (drm_dp_clock_recovery_ok(link_status, ctrl->lane_cnt)) {
+ ret = 0;
+ break;
+ }
+
+ if (ctrl->v_level == DPCD_LINK_VOLTAGE_MAX) {
+ ret = -1;
+ break;
+ }
+
+ if (old_v_level == ctrl->v_level) {
+ tries++;
+ if (tries >= 5) {
+ ret = -1;
+ break;
+ }
+ } else {
+ tries = 0;
+ old_v_level = ctrl->v_level;
+ }
+
+ edp_sink_train_set_adjust(ctrl, link_status);
+ ret = edp_voltage_pre_emphasise_set(ctrl);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int edp_start_link_train_2(struct edp_ctrl *ctrl)
+{
+ u8 link_status[DP_LINK_STATUS_SIZE];
+ int tries = 0;
+ int ret;
+ int rlen;
+
+ DBG("");
+
+ edp_host_train_set(ctrl, DP_TRAINING_PATTERN_2);
+ ret = edp_voltage_pre_emphasise_set(ctrl);
+ if (ret)
+ return ret;
+
+ ret = edp_train_pattern_set_write(ctrl,
+ DP_TRAINING_PATTERN_2 | DP_RECOVERED_CLOCK_OUT_EN);
+ if (ret)
+ return ret;
+
+ while (1) {
+ drm_dp_link_train_channel_eq_delay(ctrl->dpcd);
+
+ rlen = drm_dp_dpcd_read_link_status(ctrl->drm_aux, link_status);
+ if (rlen < DP_LINK_STATUS_SIZE) {
+ pr_err("%s: read link status failed\n", __func__);
+ return -ENOLINK;
+ }
+ if (drm_dp_channel_eq_ok(link_status, ctrl->lane_cnt)) {
+ ret = 0;
+ break;
+ }
+
+ tries++;
+ if (tries > 10) {
+ ret = -1;
+ break;
+ }
+
+ edp_sink_train_set_adjust(ctrl, link_status);
+ ret = edp_voltage_pre_emphasise_set(ctrl);
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int edp_link_rate_down_shift(struct edp_ctrl *ctrl)
+{
+ u32 prate, lrate, bpp;
+ u8 rate, lane, max_lane;
+ int changed = 0;
+
+ rate = ctrl->link_rate;
+ lane = ctrl->lane_cnt;
+ max_lane = ctrl->dp_link.num_lanes;
+
+ bpp = ctrl->color_depth * 3;
+ prate = ctrl->pixel_rate;
+ prate *= bpp;
+ prate /= 8; /* in kByte */
+
+ if (rate > DP_LINK_BW_1_62 && rate <= EDP_LINK_BW_MAX) {
+ rate -= 4; /* reduce rate */
+ changed++;
+ }
+
+ if (changed) {
+ if (lane >= 1 && lane < max_lane)
+ lane <<= 1; /* increase lane */
+
+ lrate = 270000; /* in kHz */
+ lrate *= rate;
+ lrate /= 10; /* kByte, 10 bits --> 8 bits */
+ lrate *= lane;
+
+ DBG("new lrate=%u prate=%u(kHz) rate=%d lane=%d p=%u b=%d",
+ lrate, prate, rate, lane,
+ ctrl->pixel_rate,
+ bpp);
+
+ if (lrate > prate) {
+ ctrl->link_rate = rate;
+ ctrl->lane_cnt = lane;
+ DBG("new rate=%d %d", rate, lane);
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int edp_clear_training_pattern(struct edp_ctrl *ctrl)
+{
+ int ret;
+
+ ret = edp_train_pattern_set_write(ctrl, 0);
+
+ drm_dp_link_train_channel_eq_delay(ctrl->dpcd);
+
+ return ret;
+}
+
+static int edp_do_link_train(struct edp_ctrl *ctrl)
+{
+ int ret;
+ struct drm_dp_link dp_link;
+
+ DBG("");
+ /*
+ * Set the current link rate and lane cnt to panel. They may have been
+ * adjusted and the values are different from them in DPCD CAP
+ */
+ dp_link.num_lanes = ctrl->lane_cnt;
+ dp_link.rate = drm_dp_bw_code_to_link_rate(ctrl->link_rate);
+ dp_link.capabilities = ctrl->dp_link.capabilities;
+ if (drm_dp_link_configure(ctrl->drm_aux, &dp_link) < 0)
+ return EDP_TRAIN_FAIL;
+
+ ctrl->v_level = 0; /* start from default level */
+ ctrl->p_level = 0;
+
+ edp_state_ctrl(ctrl, 0);
+ if (edp_clear_training_pattern(ctrl))
+ return EDP_TRAIN_FAIL;
+
+ ret = edp_start_link_train_1(ctrl);
+ if (ret < 0) {
+ if (edp_link_rate_down_shift(ctrl) == 0) {
+ DBG("link reconfig");
+ ret = EDP_TRAIN_RECONFIG;
+ goto clear;
+ } else {
+ pr_err("%s: Training 1 failed", __func__);
+ ret = EDP_TRAIN_FAIL;
+ goto clear;
+ }
+ }
+ DBG("Training 1 completed successfully");
+
+ edp_state_ctrl(ctrl, 0);
+ if (edp_clear_training_pattern(ctrl))
+ return EDP_TRAIN_FAIL;
+
+ ret = edp_start_link_train_2(ctrl);
+ if (ret < 0) {
+ if (edp_link_rate_down_shift(ctrl) == 0) {
+ DBG("link reconfig");
+ ret = EDP_TRAIN_RECONFIG;
+ goto clear;
+ } else {
+ pr_err("%s: Training 2 failed", __func__);
+ ret = EDP_TRAIN_FAIL;
+ goto clear;
+ }
+ }
+ DBG("Training 2 completed successfully");
+
+ edp_state_ctrl(ctrl, EDP_STATE_CTRL_SEND_VIDEO);
+clear:
+ edp_clear_training_pattern(ctrl);
+
+ return ret;
+}
+
+static void edp_clock_synchrous(struct edp_ctrl *ctrl, int sync)
+{
+ u32 data;
+ enum edp_color_depth depth;
+
+ data = edp_read(ctrl->base + REG_EDP_MISC1_MISC0);
+
+ if (sync)
+ data |= EDP_MISC1_MISC0_SYNC;
+ else
+ data &= ~EDP_MISC1_MISC0_SYNC;
+
+ /* only legacy rgb mode supported */
+ depth = EDP_6BIT; /* Default */
+ if (ctrl->color_depth == 8)
+ depth = EDP_8BIT;
+ else if (ctrl->color_depth == 10)
+ depth = EDP_10BIT;
+ else if (ctrl->color_depth == 12)
+ depth = EDP_12BIT;
+ else if (ctrl->color_depth == 16)
+ depth = EDP_16BIT;
+
+ data |= EDP_MISC1_MISC0_COLOR(depth);
+
+ edp_write(ctrl->base + REG_EDP_MISC1_MISC0, data);
+}
+
+static int edp_sw_mvid_nvid(struct edp_ctrl *ctrl, u32 m, u32 n)
+{
+ u32 n_multi, m_multi = 5;
+
+ if (ctrl->link_rate == DP_LINK_BW_1_62) {
+ n_multi = 1;
+ } else if (ctrl->link_rate == DP_LINK_BW_2_7) {
+ n_multi = 2;
+ } else {
+ pr_err("%s: Invalid link rate, %d\n", __func__,
+ ctrl->link_rate);
+ return -EINVAL;
+ }
+
+ edp_write(ctrl->base + REG_EDP_SOFTWARE_MVID, m * m_multi);
+ edp_write(ctrl->base + REG_EDP_SOFTWARE_NVID, n * n_multi);
+
+ return 0;
+}
+
+static void edp_mainlink_ctrl(struct edp_ctrl *ctrl, int enable)
+{
+ u32 data = 0;
+
+ edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, EDP_MAINLINK_CTRL_RESET);
+ /* Make sure fully reset */
+ wmb();
+ usleep_range(500, 1000);
+
+ if (enable)
+ data |= EDP_MAINLINK_CTRL_ENABLE;
+
+ edp_write(ctrl->base + REG_EDP_MAINLINK_CTRL, data);
+}
+
+static void edp_ctrl_phy_aux_enable(struct edp_ctrl *ctrl, int enable)
+{
+ if (enable) {
+ edp_regulator_enable(ctrl);
+ edp_clk_enable(ctrl, EDP_CLK_MASK_AUX_CHAN);
+ msm_edp_phy_ctrl(ctrl->phy, 1);
+ msm_edp_aux_ctrl(ctrl->aux, 1);
+ gpiod_set_value(ctrl->panel_en_gpio, 1);
+ } else {
+ gpiod_set_value(ctrl->panel_en_gpio, 0);
+ msm_edp_aux_ctrl(ctrl->aux, 0);
+ msm_edp_phy_ctrl(ctrl->phy, 0);
+ edp_clk_disable(ctrl, EDP_CLK_MASK_AUX_CHAN);
+ edp_regulator_disable(ctrl);
+ }
+}
+
+static void edp_ctrl_link_enable(struct edp_ctrl *ctrl, int enable)
+{
+ u32 m, n;
+
+ if (enable) {
+ /* Enable link channel clocks */
+ edp_clk_enable(ctrl, EDP_CLK_MASK_LINK_CHAN);
+
+ msm_edp_phy_lane_power_ctrl(ctrl->phy, true, ctrl->lane_cnt);
+
+ msm_edp_phy_vm_pe_init(ctrl->phy);
+
+ /* Make sure phy is programed */
+ wmb();
+ msm_edp_phy_ready(ctrl->phy);
+
+ edp_config_ctrl(ctrl);
+ msm_edp_ctrl_pixel_clock_valid(ctrl, ctrl->pixel_rate, &m, &n);
+ edp_sw_mvid_nvid(ctrl, m, n);
+ edp_mainlink_ctrl(ctrl, 1);
+ } else {
+ edp_mainlink_ctrl(ctrl, 0);
+
+ msm_edp_phy_lane_power_ctrl(ctrl->phy, false, 0);
+ edp_clk_disable(ctrl, EDP_CLK_MASK_LINK_CHAN);
+ }
+}
+
+static int edp_ctrl_training(struct edp_ctrl *ctrl)
+{
+ int ret;
+
+ /* Do link training only when power is on */
+ if (!ctrl->power_on)
+ return -EINVAL;
+
+train_start:
+ ret = edp_do_link_train(ctrl);
+ if (ret == EDP_TRAIN_RECONFIG) {
+ /* Re-configure main link */
+ edp_ctrl_irq_enable(ctrl, 0);
+ edp_ctrl_link_enable(ctrl, 0);
+ msm_edp_phy_ctrl(ctrl->phy, 0);
+
+ /* Make sure link is fully disabled */
+ wmb();
+ usleep_range(500, 1000);
+
+ msm_edp_phy_ctrl(ctrl->phy, 1);
+ edp_ctrl_link_enable(ctrl, 1);
+ edp_ctrl_irq_enable(ctrl, 1);
+ goto train_start;
+ }
+
+ return ret;
+}
+
+static void edp_ctrl_on_worker(struct work_struct *work)
+{
+ struct edp_ctrl *ctrl = container_of(
+ work, struct edp_ctrl, on_work);
+ int ret;
+
+ mutex_lock(&ctrl->dev_mutex);
+
+ if (ctrl->power_on) {
+ DBG("already on");
+ goto unlock_ret;
+ }
+
+ edp_ctrl_phy_aux_enable(ctrl, 1);
+ edp_ctrl_link_enable(ctrl, 1);
+
+ edp_ctrl_irq_enable(ctrl, 1);
+ ret = drm_dp_link_power_up(ctrl->drm_aux, &ctrl->dp_link);
+ if (ret)
+ goto fail;
+
+ ctrl->power_on = true;
+
+ /* Start link training */
+ ret = edp_ctrl_training(ctrl);
+ if (ret != EDP_TRAIN_SUCCESS)
+ goto fail;
+
+ DBG("DONE");
+ goto unlock_ret;
+
+fail:
+ edp_ctrl_irq_enable(ctrl, 0);
+ edp_ctrl_link_enable(ctrl, 0);
+ edp_ctrl_phy_aux_enable(ctrl, 0);
+ ctrl->power_on = false;
+unlock_ret:
+ mutex_unlock(&ctrl->dev_mutex);
+}
+
+static void edp_ctrl_off_worker(struct work_struct *work)
+{
+ struct edp_ctrl *ctrl = container_of(
+ work, struct edp_ctrl, off_work);
+ int ret;
+
+ mutex_lock(&ctrl->dev_mutex);
+
+ if (!ctrl->power_on) {
+ DBG("already off");
+ goto unlock_ret;
+ }
+
+ reinit_completion(&ctrl->idle_comp);
+ edp_state_ctrl(ctrl, EDP_STATE_CTRL_PUSH_IDLE);
+
+ ret = wait_for_completion_timeout(&ctrl->idle_comp,
+ msecs_to_jiffies(500));
+ if (ret <= 0)
+ DBG("%s: idle pattern timedout, %d\n",
+ __func__, ret);
+
+ edp_state_ctrl(ctrl, 0);
+
+ drm_dp_link_power_down(ctrl->drm_aux, &ctrl->dp_link);
+
+ edp_ctrl_irq_enable(ctrl, 0);
+
+ edp_ctrl_link_enable(ctrl, 0);
+
+ edp_ctrl_phy_aux_enable(ctrl, 0);
+
+ ctrl->power_on = false;
+
+unlock_ret:
+ mutex_unlock(&ctrl->dev_mutex);
+}
+
+irqreturn_t msm_edp_ctrl_irq(struct edp_ctrl *ctrl)
+{
+ u32 isr1, isr2, mask1, mask2;
+ u32 ack;
+
+ DBG("");
+ spin_lock(&ctrl->irq_lock);
+ isr1 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_1);
+ isr2 = edp_read(ctrl->base + REG_EDP_INTERRUPT_REG_2);
+
+ mask1 = isr1 & EDP_INTR_MASK1;
+ mask2 = isr2 & EDP_INTR_MASK2;
+
+ isr1 &= ~mask1; /* remove masks bit */
+ isr2 &= ~mask2;
+
+ DBG("isr=%x mask=%x isr2=%x mask2=%x",
+ isr1, mask1, isr2, mask2);
+
+ ack = isr1 & EDP_INTR_STATUS1;
+ ack <<= 1; /* ack bits */
+ ack |= mask1;
+ edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_1, ack);
+
+ ack = isr2 & EDP_INTR_STATUS2;
+ ack <<= 1; /* ack bits */
+ ack |= mask2;
+ edp_write(ctrl->base + REG_EDP_INTERRUPT_REG_2, ack);
+ spin_unlock(&ctrl->irq_lock);
+
+ if (isr1 & EDP_INTERRUPT_REG_1_HPD)
+ DBG("edp_hpd");
+
+ if (isr2 & EDP_INTERRUPT_REG_2_READY_FOR_VIDEO)
+ DBG("edp_video_ready");
+
+ if (isr2 & EDP_INTERRUPT_REG_2_IDLE_PATTERNs_SENT) {
+ DBG("idle_patterns_sent");
+ complete(&ctrl->idle_comp);
+ }
+
+ msm_edp_aux_irq(ctrl->aux, isr1);
+
+ return IRQ_HANDLED;
+}
+
+void msm_edp_ctrl_power(struct edp_ctrl *ctrl, bool on)
+{
+ if (on)
+ queue_work(ctrl->workqueue, &ctrl->on_work);
+ else
+ queue_work(ctrl->workqueue, &ctrl->off_work);
+}
+
+int msm_edp_ctrl_init(struct msm_edp *edp)
+{
+ struct edp_ctrl *ctrl = NULL;
+ struct device *dev = &edp->pdev->dev;
+ int ret;
+
+ if (!edp) {
+ pr_err("%s: edp is NULL!\n", __func__);
+ return -EINVAL;
+ }
+
+ ctrl = devm_kzalloc(dev, sizeof(*ctrl), GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ edp->ctrl = ctrl;
+ ctrl->pdev = edp->pdev;
+
+ ctrl->base = msm_ioremap(ctrl->pdev, "edp", "eDP");
+ if (IS_ERR(ctrl->base))
+ return PTR_ERR(ctrl->base);
+
+ /* Get regulator, clock, gpio, pwm */
+ ret = edp_regulator_init(ctrl);
+ if (ret) {
+ pr_err("%s:regulator init fail\n", __func__);
+ return ret;
+ }
+ ret = edp_clk_init(ctrl);
+ if (ret) {
+ pr_err("%s:clk init fail\n", __func__);
+ return ret;
+ }
+ ret = edp_gpio_config(ctrl);
+ if (ret) {
+ pr_err("%s:failed to configure GPIOs: %d", __func__, ret);
+ return ret;
+ }
+
+ /* Init aux and phy */
+ ctrl->aux = msm_edp_aux_init(dev, ctrl->base, &ctrl->drm_aux);
+ if (!ctrl->aux || !ctrl->drm_aux) {
+ pr_err("%s:failed to init aux\n", __func__);
+ return ret;
+ }
+
+ ctrl->phy = msm_edp_phy_init(dev, ctrl->base);
+ if (!ctrl->phy) {
+ pr_err("%s:failed to init phy\n", __func__);
+ goto err_destory_aux;
+ }
+
+ spin_lock_init(&ctrl->irq_lock);
+ mutex_init(&ctrl->dev_mutex);
+ init_completion(&ctrl->idle_comp);
+
+ /* setup workqueue */
+ ctrl->workqueue = alloc_ordered_workqueue("edp_drm_work", 0);
+ INIT_WORK(&ctrl->on_work, edp_ctrl_on_worker);
+ INIT_WORK(&ctrl->off_work, edp_ctrl_off_worker);
+
+ return 0;
+
+err_destory_aux:
+ msm_edp_aux_destroy(dev, ctrl->aux);
+ ctrl->aux = NULL;
+ return ret;
+}
+
+void msm_edp_ctrl_destroy(struct edp_ctrl *ctrl)
+{
+ if (!ctrl)
+ return;
+
+ if (ctrl->workqueue) {
+ flush_workqueue(ctrl->workqueue);
+ destroy_workqueue(ctrl->workqueue);
+ ctrl->workqueue = NULL;
+ }
+
+ if (ctrl->aux) {
+ msm_edp_aux_destroy(&ctrl->pdev->dev, ctrl->aux);
+ ctrl->aux = NULL;
+ }
+
+ kfree(ctrl->edid);
+ ctrl->edid = NULL;
+
+ mutex_destroy(&ctrl->dev_mutex);
+}
+
+bool msm_edp_ctrl_panel_connected(struct edp_ctrl *ctrl)
+{
+ mutex_lock(&ctrl->dev_mutex);
+ DBG("connect status = %d", ctrl->edp_connected);
+ if (ctrl->edp_connected) {
+ mutex_unlock(&ctrl->dev_mutex);
+ return true;
+ }
+
+ if (!ctrl->power_on) {
+ edp_ctrl_phy_aux_enable(ctrl, 1);
+ edp_ctrl_irq_enable(ctrl, 1);
+ }
+
+ if (drm_dp_dpcd_read(ctrl->drm_aux, DP_DPCD_REV, ctrl->dpcd,
+ DP_RECEIVER_CAP_SIZE) < DP_RECEIVER_CAP_SIZE) {
+ pr_err("%s: AUX channel is NOT ready\n", __func__);
+ memset(ctrl->dpcd, 0, DP_RECEIVER_CAP_SIZE);
+ } else {
+ ctrl->edp_connected = true;
+ }
+
+ if (!ctrl->power_on) {
+ edp_ctrl_irq_enable(ctrl, 0);
+ edp_ctrl_phy_aux_enable(ctrl, 0);
+ }
+
+ DBG("exit: connect status=%d", ctrl->edp_connected);
+
+ mutex_unlock(&ctrl->dev_mutex);
+
+ return ctrl->edp_connected;
+}
+
+int msm_edp_ctrl_get_panel_info(struct edp_ctrl *ctrl,
+ struct drm_connector *connector, struct edid **edid)
+{
+ int ret = 0;
+
+ mutex_lock(&ctrl->dev_mutex);
+
+ if (ctrl->edid) {
+ if (edid) {
+ DBG("Just return edid buffer");
+ *edid = ctrl->edid;
+ }
+ goto unlock_ret;
+ }
+
+ if (!ctrl->power_on) {
+ edp_ctrl_phy_aux_enable(ctrl, 1);
+ edp_ctrl_irq_enable(ctrl, 1);
+ }
+
+ ret = drm_dp_link_probe(ctrl->drm_aux, &ctrl->dp_link);
+ if (ret) {
+ pr_err("%s: read dpcd cap failed, %d\n", __func__, ret);
+ goto disable_ret;
+ }
+
+ /* Initialize link rate as panel max link rate */
+ ctrl->link_rate = drm_dp_link_rate_to_bw_code(ctrl->dp_link.rate);
+
+ ctrl->edid = drm_get_edid(connector, &ctrl->drm_aux->ddc);
+ if (!ctrl->edid) {
+ pr_err("%s: edid read fail\n", __func__);
+ goto disable_ret;
+ }
+
+ if (edid)
+ *edid = ctrl->edid;
+
+disable_ret:
+ if (!ctrl->power_on) {
+ edp_ctrl_irq_enable(ctrl, 0);
+ edp_ctrl_phy_aux_enable(ctrl, 0);
+ }
+unlock_ret:
+ mutex_unlock(&ctrl->dev_mutex);
+ return ret;
+}
+
+int msm_edp_ctrl_timing_cfg(struct edp_ctrl *ctrl,
+ const struct drm_display_mode *mode,
+ const struct drm_display_info *info)
+{
+ u32 hstart_from_sync, vstart_from_sync;
+ u32 data;
+ int ret = 0;
+
+ mutex_lock(&ctrl->dev_mutex);
+ /*
+ * Need to keep color depth, pixel rate and
+ * interlaced information in ctrl context
+ */
+ ctrl->color_depth = info->bpc;
+ ctrl->pixel_rate = mode->clock;
+ ctrl->interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE);
+
+ /* Fill initial link config based on passed in timing */
+ edp_fill_link_cfg(ctrl);
+
+ if (edp_clk_enable(ctrl, EDP_CLK_MASK_AHB)) {
+ pr_err("%s, fail to prepare enable ahb clk\n", __func__);
+ ret = -EINVAL;
+ goto unlock_ret;
+ }
+ edp_clock_synchrous(ctrl, 1);
+
+ /* Configure eDP timing to HW */
+ edp_write(ctrl->base + REG_EDP_TOTAL_HOR_VER,
+ EDP_TOTAL_HOR_VER_HORIZ(mode->htotal) |
+ EDP_TOTAL_HOR_VER_VERT(mode->vtotal));
+
+ vstart_from_sync = mode->vtotal - mode->vsync_start;
+ hstart_from_sync = mode->htotal - mode->hsync_start;
+ edp_write(ctrl->base + REG_EDP_START_HOR_VER_FROM_SYNC,
+ EDP_START_HOR_VER_FROM_SYNC_HORIZ(hstart_from_sync) |
+ EDP_START_HOR_VER_FROM_SYNC_VERT(vstart_from_sync));
+
+ data = EDP_HSYNC_VSYNC_WIDTH_POLARITY_VERT(
+ mode->vsync_end - mode->vsync_start);
+ data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_HORIZ(
+ mode->hsync_end - mode->hsync_start);
+ if (mode->flags & DRM_MODE_FLAG_NVSYNC)
+ data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NVSYNC;
+ if (mode->flags & DRM_MODE_FLAG_NHSYNC)
+ data |= EDP_HSYNC_VSYNC_WIDTH_POLARITY_NHSYNC;
+ edp_write(ctrl->base + REG_EDP_HSYNC_VSYNC_WIDTH_POLARITY, data);
+
+ edp_write(ctrl->base + REG_EDP_ACTIVE_HOR_VER,
+ EDP_ACTIVE_HOR_VER_HORIZ(mode->hdisplay) |
+ EDP_ACTIVE_HOR_VER_VERT(mode->vdisplay));
+
+ edp_clk_disable(ctrl, EDP_CLK_MASK_AHB);
+
+unlock_ret:
+ mutex_unlock(&ctrl->dev_mutex);
+ return ret;
+}
+
+bool msm_edp_ctrl_pixel_clock_valid(struct edp_ctrl *ctrl,
+ u32 pixel_rate, u32 *pm, u32 *pn)
+{
+ const struct edp_pixel_clk_div *divs;
+ u32 err = 1; /* 1% error tolerance */
+ u32 clk_err;
+ int i;
+
+ if (ctrl->link_rate == DP_LINK_BW_1_62) {
+ divs = clk_divs[0];
+ } else if (ctrl->link_rate == DP_LINK_BW_2_7) {
+ divs = clk_divs[1];
+ } else {
+ pr_err("%s: Invalid link rate,%d\n", __func__, ctrl->link_rate);
+ return false;
+ }
+
+ for (i = 0; i < EDP_PIXEL_CLK_NUM; i++) {
+ clk_err = abs(divs[i].rate - pixel_rate);
+ if ((divs[i].rate * err / 100) >= clk_err) {
+ if (pm)
+ *pm = divs[i].m;
+ if (pn)
+ *pn = divs[i].n;
+ return true;
+ }
+ }
+
+ DBG("pixel clock %d(kHz) not supported", pixel_rate);
+
+ return false;
+}
+
diff --git a/drivers/gpu/drm/msm/edp/edp_phy.c b/drivers/gpu/drm/msm/edp/edp_phy.c
new file mode 100644
index 000000000000..36bb8933e9ee
--- /dev/null
+++ b/drivers/gpu/drm/msm/edp/edp_phy.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "edp.h"
+#include "edp.xml.h"
+
+#define EDP_MAX_LANE 4
+
+struct edp_phy {
+ void __iomem *base;
+};
+
+bool msm_edp_phy_ready(struct edp_phy *phy)
+{
+ u32 status;
+ int cnt = 100;
+
+ while (--cnt) {
+ status = edp_read(phy->base +
+ REG_EDP_PHY_GLB_PHY_STATUS);
+ if (status & 0x01)
+ break;
+ usleep_range(500, 1000);
+ }
+
+ if (cnt == 0) {
+ pr_err("%s: PHY NOT ready\n", __func__);
+ return false;
+ } else {
+ return true;
+ }
+}
+
+void msm_edp_phy_ctrl(struct edp_phy *phy, int enable)
+{
+ DBG("enable=%d", enable);
+ if (enable) {
+ /* Reset */
+ edp_write(phy->base + REG_EDP_PHY_CTRL,
+ EDP_PHY_CTRL_SW_RESET | EDP_PHY_CTRL_SW_RESET_PLL);
+ /* Make sure fully reset */
+ wmb();
+ usleep_range(500, 1000);
+ edp_write(phy->base + REG_EDP_PHY_CTRL, 0x000);
+ edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0x3f);
+ edp_write(phy->base + REG_EDP_PHY_GLB_CFG, 0x1);
+ } else {
+ edp_write(phy->base + REG_EDP_PHY_GLB_PD_CTL, 0xc0);
+ }
+}
+
+/* voltage mode and pre emphasis cfg */
+void msm_edp_phy_vm_pe_init(struct edp_phy *phy)
+{
+ edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, 0x3);
+ edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, 0x64);
+ edp_write(phy->base + REG_EDP_PHY_GLB_MISC9, 0x6c);
+}
+
+void msm_edp_phy_vm_pe_cfg(struct edp_phy *phy, u32 v0, u32 v1)
+{
+ edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG0, v0);
+ edp_write(phy->base + REG_EDP_PHY_GLB_VM_CFG1, v1);
+}
+
+void msm_edp_phy_lane_power_ctrl(struct edp_phy *phy, bool up, u32 max_lane)
+{
+ u32 i;
+ u32 data;
+
+ if (up)
+ data = 0; /* power up */
+ else
+ data = 0x7; /* power down */
+
+ for (i = 0; i < max_lane; i++)
+ edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data);
+
+ /* power down unused lane */
+ data = 0x7; /* power down */
+ for (i = max_lane; i < EDP_MAX_LANE; i++)
+ edp_write(phy->base + REG_EDP_PHY_LN_PD_CTL(i) , data);
+}
+
+void *msm_edp_phy_init(struct device *dev, void __iomem *regbase)
+{
+ struct edp_phy *phy = NULL;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return NULL;
+
+ phy->base = regbase;
+ return phy;
+}
+
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.c b/drivers/gpu/drm/msm/hdmi/hdmi.c
index 062c68725376..814536202efe 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -106,7 +107,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
goto fail;
}
- BUG_ON(config->hpd_reg_cnt > ARRAY_SIZE(hdmi->hpd_regs));
+ hdmi->hpd_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_regs[0]) *
+ config->hpd_reg_cnt, GFP_KERNEL);
+ if (!hdmi->hpd_regs) {
+ ret = -ENOMEM;
+ goto fail;
+ }
for (i = 0; i < config->hpd_reg_cnt; i++) {
struct regulator *reg;
@@ -122,7 +128,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
hdmi->hpd_regs[i] = reg;
}
- BUG_ON(config->pwr_reg_cnt > ARRAY_SIZE(hdmi->pwr_regs));
+ hdmi->pwr_regs = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_regs[0]) *
+ config->pwr_reg_cnt, GFP_KERNEL);
+ if (!hdmi->pwr_regs) {
+ ret = -ENOMEM;
+ goto fail;
+ }
for (i = 0; i < config->pwr_reg_cnt; i++) {
struct regulator *reg;
@@ -138,7 +149,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
hdmi->pwr_regs[i] = reg;
}
- BUG_ON(config->hpd_clk_cnt > ARRAY_SIZE(hdmi->hpd_clks));
+ hdmi->hpd_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->hpd_clks[0]) *
+ config->hpd_clk_cnt, GFP_KERNEL);
+ if (!hdmi->hpd_clks) {
+ ret = -ENOMEM;
+ goto fail;
+ }
for (i = 0; i < config->hpd_clk_cnt; i++) {
struct clk *clk;
@@ -153,7 +169,12 @@ static struct hdmi *hdmi_init(struct platform_device *pdev)
hdmi->hpd_clks[i] = clk;
}
- BUG_ON(config->pwr_clk_cnt > ARRAY_SIZE(hdmi->pwr_clks));
+ hdmi->pwr_clks = devm_kzalloc(&pdev->dev, sizeof(hdmi->pwr_clks[0]) *
+ config->pwr_clk_cnt, GFP_KERNEL);
+ if (!hdmi->pwr_clks) {
+ ret = -ENOMEM;
+ goto fail;
+ }
for (i = 0; i < config->pwr_clk_cnt; i++) {
struct clk *clk;
@@ -247,9 +268,9 @@ int hdmi_modeset_init(struct hdmi *hdmi,
return 0;
fail:
- /* bridge/connector are normally destroyed by drm: */
+ /* bridge is normally destroyed by drm: */
if (hdmi->bridge) {
- hdmi->bridge->funcs->destroy(hdmi->bridge);
+ hdmi_bridge_destroy(hdmi->bridge);
hdmi->bridge = NULL;
}
if (hdmi->connector) {
@@ -266,6 +287,57 @@ fail:
#include <linux/of_gpio.h>
+#define HDMI_CFG(item, entry) \
+ .item ## _names = item ##_names_ ## entry, \
+ .item ## _cnt = ARRAY_SIZE(item ## _names_ ## entry)
+
+static struct hdmi_platform_config hdmi_tx_8660_config = {
+ .phy_init = hdmi_phy_8x60_init,
+};
+
+static const char *hpd_reg_names_8960[] = {"core-vdda", "hdmi-mux"};
+static const char *hpd_clk_names_8960[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
+
+static struct hdmi_platform_config hdmi_tx_8960_config = {
+ .phy_init = hdmi_phy_8960_init,
+ HDMI_CFG(hpd_reg, 8960),
+ HDMI_CFG(hpd_clk, 8960),
+};
+
+static const char *pwr_reg_names_8x74[] = {"core-vdda", "core-vcc"};
+static const char *hpd_reg_names_8x74[] = {"hpd-gdsc", "hpd-5v"};
+static const char *pwr_clk_names_8x74[] = {"extp_clk", "alt_iface_clk"};
+static const char *hpd_clk_names_8x74[] = {"iface_clk", "core_clk", "mdp_core_clk"};
+static unsigned long hpd_clk_freq_8x74[] = {0, 19200000, 0};
+
+static struct hdmi_platform_config hdmi_tx_8074_config = {
+ .phy_init = hdmi_phy_8x74_init,
+ HDMI_CFG(pwr_reg, 8x74),
+ HDMI_CFG(hpd_reg, 8x74),
+ HDMI_CFG(pwr_clk, 8x74),
+ HDMI_CFG(hpd_clk, 8x74),
+ .hpd_freq = hpd_clk_freq_8x74,
+};
+
+static const char *hpd_reg_names_8084[] = {"hpd-gdsc", "hpd-5v", "hpd-5v-en"};
+
+static struct hdmi_platform_config hdmi_tx_8084_config = {
+ .phy_init = hdmi_phy_8x74_init,
+ HDMI_CFG(pwr_reg, 8x74),
+ HDMI_CFG(hpd_reg, 8084),
+ HDMI_CFG(pwr_clk, 8x74),
+ HDMI_CFG(hpd_clk, 8x74),
+ .hpd_freq = hpd_clk_freq_8x74,
+};
+
+static const struct of_device_id dt_match[] = {
+ { .compatible = "qcom,hdmi-tx-8084", .data = &hdmi_tx_8084_config },
+ { .compatible = "qcom,hdmi-tx-8074", .data = &hdmi_tx_8074_config },
+ { .compatible = "qcom,hdmi-tx-8960", .data = &hdmi_tx_8960_config },
+ { .compatible = "qcom,hdmi-tx-8660", .data = &hdmi_tx_8660_config },
+ {}
+};
+
#ifdef CONFIG_OF
static int get_gpio(struct device *dev, struct device_node *of_node, const char *name)
{
@@ -288,50 +360,31 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
{
struct drm_device *drm = dev_get_drvdata(master);
struct msm_drm_private *priv = drm->dev_private;
- static struct hdmi_platform_config config = {};
+ static struct hdmi_platform_config *hdmi_cfg;
struct hdmi *hdmi;
#ifdef CONFIG_OF
struct device_node *of_node = dev->of_node;
+ const struct of_device_id *match;
- if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8074")) {
- static const char *hpd_reg_names[] = {"hpd-gdsc", "hpd-5v"};
- static const char *pwr_reg_names[] = {"core-vdda", "core-vcc"};
- static const char *hpd_clk_names[] = {"iface_clk", "core_clk", "mdp_core_clk"};
- static unsigned long hpd_clk_freq[] = {0, 19200000, 0};
- static const char *pwr_clk_names[] = {"extp_clk", "alt_iface_clk"};
- config.phy_init = hdmi_phy_8x74_init;
- config.hpd_reg_names = hpd_reg_names;
- config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
- config.pwr_reg_names = pwr_reg_names;
- config.pwr_reg_cnt = ARRAY_SIZE(pwr_reg_names);
- config.hpd_clk_names = hpd_clk_names;
- config.hpd_freq = hpd_clk_freq;
- config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
- config.pwr_clk_names = pwr_clk_names;
- config.pwr_clk_cnt = ARRAY_SIZE(pwr_clk_names);
- } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8960")) {
- static const char *hpd_clk_names[] = {"core_clk", "master_iface_clk", "slave_iface_clk"};
- static const char *hpd_reg_names[] = {"core-vdda", "hdmi-mux"};
- config.phy_init = hdmi_phy_8960_init;
- config.hpd_reg_names = hpd_reg_names;
- config.hpd_reg_cnt = ARRAY_SIZE(hpd_reg_names);
- config.hpd_clk_names = hpd_clk_names;
- config.hpd_clk_cnt = ARRAY_SIZE(hpd_clk_names);
- } else if (of_device_is_compatible(of_node, "qcom,hdmi-tx-8660")) {
- config.phy_init = hdmi_phy_8x60_init;
+ match = of_match_node(dt_match, of_node);
+ if (match && match->data) {
+ hdmi_cfg = (struct hdmi_platform_config *)match->data;
+ DBG("hdmi phy: %s", match->compatible);
} else {
dev_err(dev, "unknown phy: %s\n", of_node->name);
+ return -ENXIO;
}
- config.mmio_name = "core_physical";
- config.ddc_clk_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
- config.ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
- config.hpd_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
- config.mux_en_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en");
- config.mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
- config.mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
+ hdmi_cfg->mmio_name = "core_physical";
+ hdmi_cfg->ddc_clk_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-clk");
+ hdmi_cfg->ddc_data_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-ddc-data");
+ hdmi_cfg->hpd_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-hpd");
+ hdmi_cfg->mux_en_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-en");
+ hdmi_cfg->mux_sel_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-sel");
+ hdmi_cfg->mux_lpm_gpio = get_gpio(dev, of_node, "qcom,hdmi-tx-mux-lpm");
#else
+ static struct hdmi_platform_config config = {};
static const char *hpd_clk_names[] = {
"core_clk", "master_iface_clk", "slave_iface_clk",
};
@@ -377,12 +430,15 @@ static int hdmi_bind(struct device *dev, struct device *master, void *data)
config.mux_en_gpio = -1;
config.mux_sel_gpio = -1;
}
+ hdmi_cfg = &config;
#endif
- dev->platform_data = &config;
+ dev->platform_data = hdmi_cfg;
+
hdmi = hdmi_init(to_platform_device(dev));
if (IS_ERR(hdmi))
return PTR_ERR(hdmi);
priv->hdmi = hdmi;
+
return 0;
}
@@ -413,13 +469,6 @@ static int hdmi_dev_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id dt_match[] = {
- { .compatible = "qcom,hdmi-tx-8074" },
- { .compatible = "qcom,hdmi-tx-8960" },
- { .compatible = "qcom,hdmi-tx-8660" },
- {}
-};
-
static struct platform_driver hdmi_driver = {
.probe = hdmi_dev_probe,
.remove = hdmi_dev_remove,
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.h b/drivers/gpu/drm/msm/hdmi/hdmi.h
index 43e654f751b7..68fdfb3622a5 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.h
@@ -52,10 +52,10 @@ struct hdmi {
void __iomem *mmio;
- struct regulator *hpd_regs[2];
- struct regulator *pwr_regs[2];
- struct clk *hpd_clks[3];
- struct clk *pwr_clks[2];
+ struct regulator **hpd_regs;
+ struct regulator **pwr_regs;
+ struct clk **hpd_clks;
+ struct clk **pwr_clks;
struct hdmi_phy *phy;
struct i2c_adapter *i2c;
@@ -146,6 +146,7 @@ void hdmi_audio_set_sample_rate(struct hdmi *hdmi, int rate);
*/
struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi);
+void hdmi_bridge_destroy(struct drm_bridge *bridge);
/*
* hdmi connector:
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
index 5b0844befbab..350988740e9f 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/hdmi.xml.h
@@ -8,18 +8,19 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
-Copyright (C) 2013-2014 by the following authors:
+Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining
@@ -45,12 +46,14 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
enum hdmi_hdcp_key_state {
- NO_KEYS = 0,
- NOT_CHECKED = 1,
- CHECKING = 2,
- KEYS_VALID = 3,
- AKSV_INVALID = 4,
- CHECKSUM_MISMATCH = 5,
+ HDCP_KEYS_STATE_NO_KEYS = 0,
+ HDCP_KEYS_STATE_NOT_CHECKED = 1,
+ HDCP_KEYS_STATE_CHECKING = 2,
+ HDCP_KEYS_STATE_VALID = 3,
+ HDCP_KEYS_STATE_AKSV_NOT_VALID = 4,
+ HDCP_KEYS_STATE_CHKSUM_MISMATCH = 5,
+ HDCP_KEYS_STATE_PROD_AKSV = 6,
+ HDCP_KEYS_STATE_RESERVED = 7,
};
enum hdmi_ddc_read_write {
@@ -199,11 +202,29 @@ static inline uint32_t HDMI_AUDIO_INFO1_LSV(uint32_t val)
#define HDMI_HDCP_CTRL_ENABLE 0x00000001
#define HDMI_HDCP_CTRL_ENCRYPTION_ENABLE 0x00000100
+#define REG_HDMI_HDCP_DEBUG_CTRL 0x00000114
+#define HDMI_HDCP_DEBUG_CTRL_RNG_CIPHER 0x00000004
+
#define REG_HDMI_HDCP_INT_CTRL 0x00000118
+#define HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_INT 0x00000001
+#define HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_ACK 0x00000002
+#define HDMI_HDCP_INT_CTRL_AUTH_SUCCESS_MASK 0x00000004
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_INT 0x00000010
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_ACK 0x00000020
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_MASK 0x00000040
+#define HDMI_HDCP_INT_CTRL_AUTH_FAIL_INFO_ACK 0x00000080
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_INT 0x00000100
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_ACK 0x00000200
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_REQ_MASK 0x00000400
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_INT 0x00001000
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_ACK 0x00002000
+#define HDMI_HDCP_INT_CTRL_AUTH_XFER_DONE_MASK 0x00004000
#define REG_HDMI_HDCP_LINK0_STATUS 0x0000011c
#define HDMI_HDCP_LINK0_STATUS_AN_0_READY 0x00000100
#define HDMI_HDCP_LINK0_STATUS_AN_1_READY 0x00000200
+#define HDMI_HDCP_LINK0_STATUS_RI_MATCHES 0x00001000
+#define HDMI_HDCP_LINK0_STATUS_V_MATCHES 0x00100000
#define HDMI_HDCP_LINK0_STATUS_KEY_STATE__MASK 0x70000000
#define HDMI_HDCP_LINK0_STATUS_KEY_STATE__SHIFT 28
static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state val)
@@ -211,9 +232,56 @@ static inline uint32_t HDMI_HDCP_LINK0_STATUS_KEY_STATE(enum hdmi_hdcp_key_state
return ((val) << HDMI_HDCP_LINK0_STATUS_KEY_STATE__SHIFT) & HDMI_HDCP_LINK0_STATUS_KEY_STATE__MASK;
}
+#define REG_HDMI_HDCP_DDC_CTRL_0 0x00000120
+#define HDMI_HDCP_DDC_CTRL_0_DISABLE 0x00000001
+
+#define REG_HDMI_HDCP_DDC_CTRL_1 0x00000124
+#define HDMI_HDCP_DDC_CTRL_1_FAILED_ACK 0x00000001
+
+#define REG_HDMI_HDCP_DDC_STATUS 0x00000128
+#define HDMI_HDCP_DDC_STATUS_XFER_REQ 0x00000010
+#define HDMI_HDCP_DDC_STATUS_XFER_DONE 0x00000400
+#define HDMI_HDCP_DDC_STATUS_ABORTED 0x00001000
+#define HDMI_HDCP_DDC_STATUS_TIMEOUT 0x00002000
+#define HDMI_HDCP_DDC_STATUS_NACK0 0x00004000
+#define HDMI_HDCP_DDC_STATUS_NACK1 0x00008000
+#define HDMI_HDCP_DDC_STATUS_FAILED 0x00010000
+
+#define REG_HDMI_HDCP_ENTROPY_CTRL0 0x0000012c
+
+#define REG_HDMI_HDCP_ENTROPY_CTRL1 0x0000025c
+
#define REG_HDMI_HDCP_RESET 0x00000130
#define HDMI_HDCP_RESET_LINK0_DEAUTHENTICATE 0x00000001
+#define REG_HDMI_HDCP_RCVPORT_DATA0 0x00000134
+
+#define REG_HDMI_HDCP_RCVPORT_DATA1 0x00000138
+
+#define REG_HDMI_HDCP_RCVPORT_DATA2_0 0x0000013c
+
+#define REG_HDMI_HDCP_RCVPORT_DATA2_1 0x00000140
+
+#define REG_HDMI_HDCP_RCVPORT_DATA3 0x00000144
+
+#define REG_HDMI_HDCP_RCVPORT_DATA4 0x00000148
+
+#define REG_HDMI_HDCP_RCVPORT_DATA5 0x0000014c
+
+#define REG_HDMI_HDCP_RCVPORT_DATA6 0x00000150
+
+#define REG_HDMI_HDCP_RCVPORT_DATA7 0x00000154
+
+#define REG_HDMI_HDCP_RCVPORT_DATA8 0x00000158
+
+#define REG_HDMI_HDCP_RCVPORT_DATA9 0x0000015c
+
+#define REG_HDMI_HDCP_RCVPORT_DATA10 0x00000160
+
+#define REG_HDMI_HDCP_RCVPORT_DATA11 0x00000164
+
+#define REG_HDMI_HDCP_RCVPORT_DATA12 0x00000168
+
#define REG_HDMI_VENSPEC_INFO0 0x0000016c
#define REG_HDMI_VENSPEC_INFO1 0x00000170
@@ -266,6 +334,7 @@ static inline uint32_t HDMI_DDC_CTRL_TRANSACTION_CNT(uint32_t val)
#define HDMI_DDC_SW_STATUS_NACK3 0x00008000
#define REG_HDMI_DDC_HW_STATUS 0x0000021c
+#define HDMI_DDC_HW_STATUS_DONE 0x00000008
#define REG_HDMI_DDC_SPEED 0x00000220
#define HDMI_DDC_SPEED_THRESHOLD__MASK 0x00000003
@@ -329,6 +398,15 @@ static inline uint32_t HDMI_DDC_DATA_INDEX(uint32_t val)
}
#define HDMI_DDC_DATA_INDEX_WRITE 0x80000000
+#define REG_HDMI_HDCP_SHA_CTRL 0x0000023c
+
+#define REG_HDMI_HDCP_SHA_STATUS 0x00000240
+#define HDMI_HDCP_SHA_STATUS_BLOCK_DONE 0x00000001
+#define HDMI_HDCP_SHA_STATUS_COMP_DONE 0x00000010
+
+#define REG_HDMI_HDCP_SHA_DATA 0x00000244
+#define HDMI_HDCP_SHA_DATA_DONE 0x00000001
+
#define REG_HDMI_HPD_INT_STATUS 0x00000250
#define HDMI_HPD_INT_STATUS_INT 0x00000001
#define HDMI_HPD_INT_STATUS_CABLE_DETECTED 0x00000002
@@ -359,6 +437,10 @@ static inline uint32_t HDMI_DDC_REF_REFTIMER(uint32_t val)
return ((val) << HDMI_DDC_REF_REFTIMER__SHIFT) & HDMI_DDC_REF_REFTIMER__MASK;
}
+#define REG_HDMI_HDCP_SW_UPPER_AKSV 0x00000284
+
+#define REG_HDMI_HDCP_SW_LOWER_AKSV 0x00000288
+
#define REG_HDMI_CEC_STATUS 0x00000298
#define REG_HDMI_CEC_INT 0x0000029c
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
index 6902ad6da710..a7a1d8267cf0 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_bridge.c
@@ -23,11 +23,8 @@ struct hdmi_bridge {
};
#define to_hdmi_bridge(x) container_of(x, struct hdmi_bridge, base)
-static void hdmi_bridge_destroy(struct drm_bridge *bridge)
+void hdmi_bridge_destroy(struct drm_bridge *bridge)
{
- struct hdmi_bridge *hdmi_bridge = to_hdmi_bridge(bridge);
- drm_bridge_cleanup(bridge);
- kfree(hdmi_bridge);
}
static void power_on(struct drm_bridge *bridge)
@@ -200,7 +197,6 @@ static const struct drm_bridge_funcs hdmi_bridge_funcs = {
.disable = hdmi_bridge_disable,
.post_disable = hdmi_bridge_post_disable,
.mode_set = hdmi_bridge_mode_set,
- .destroy = hdmi_bridge_destroy,
};
@@ -211,7 +207,8 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
struct hdmi_bridge *hdmi_bridge;
int ret;
- hdmi_bridge = kzalloc(sizeof(*hdmi_bridge), GFP_KERNEL);
+ hdmi_bridge = devm_kzalloc(hdmi->dev->dev,
+ sizeof(*hdmi_bridge), GFP_KERNEL);
if (!hdmi_bridge) {
ret = -ENOMEM;
goto fail;
@@ -220,8 +217,11 @@ struct drm_bridge *hdmi_bridge_init(struct hdmi *hdmi)
hdmi_bridge->hdmi = hdmi;
bridge = &hdmi_bridge->base;
+ bridge->funcs = &hdmi_bridge_funcs;
- drm_bridge_init(hdmi->dev, bridge, &hdmi_bridge_funcs);
+ ret = drm_bridge_attach(hdmi->dev, bridge);
+ if (ret)
+ goto fail;
return bridge;
diff --git a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
index b4e70e0e3cfa..b62cdb968614 100644
--- a/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
+++ b/drivers/gpu/drm/msm/hdmi/hdmi_connector.c
@@ -386,7 +386,7 @@ hdmi_connector_best_encoder(struct drm_connector *connector)
}
static const struct drm_connector_funcs hdmi_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
+ .dpms = drm_atomic_helper_connector_dpms,
.detect = hdmi_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = hdmi_connector_destroy,
@@ -426,7 +426,7 @@ struct drm_connector *hdmi_connector_init(struct hdmi *hdmi)
connector->polled = DRM_CONNECTOR_POLL_CONNECT |
DRM_CONNECTOR_POLL_DISCONNECT;
- connector->interlace_allowed = 1;
+ connector->interlace_allowed = 0;
connector->doublescan_allowed = 0;
drm_connector_register(connector);
diff --git a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
index 29bd796797de..43bb54a9afbf 100644
--- a/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
+++ b/drivers/gpu/drm/msm/hdmi/qfprom.xml.h
@@ -8,16 +8,17 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
Copyright (C) 2013 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
index a4a7f8c7122a..1d39174d91fb 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4.xml.h
@@ -8,16 +8,17 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
@@ -72,6 +73,18 @@ enum mdp4_cursor_format {
CURSOR_XRGB = 2,
};
+enum mdp4_frame_format {
+ FRAME_LINEAR = 0,
+ FRAME_TILE_ARGB_4X4 = 1,
+ FRAME_TILE_YCBCR_420 = 2,
+};
+
+enum mdp4_scale_unit {
+ SCALE_FIR = 0,
+ SCALE_MN_PHASE = 1,
+ SCALE_PIXEL_RPT = 2,
+};
+
enum mdp4_dma {
DMA_P = 0,
DMA_S = 1,
@@ -637,6 +650,8 @@ static inline uint32_t REG_MDP4_PIPE_SRCP1_BASE(enum mdp4_pipe i0) { return 0x00
static inline uint32_t REG_MDP4_PIPE_SRCP2_BASE(enum mdp4_pipe i0) { return 0x00020018 + 0x10000*i0; }
+static inline uint32_t REG_MDP4_PIPE_SRCP3_BASE(enum mdp4_pipe i0) { return 0x0002001c + 0x10000*i0; }
+
static inline uint32_t REG_MDP4_PIPE_SRC_STRIDE_A(enum mdp4_pipe i0) { return 0x00020040 + 0x10000*i0; }
#define MDP4_PIPE_SRC_STRIDE_A_P0__MASK 0x0000ffff
#define MDP4_PIPE_SRC_STRIDE_A_P0__SHIFT 0
@@ -720,7 +735,25 @@ static inline uint32_t MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
}
#define MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT 0x00020000
#define MDP4_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB 0x00040000
+#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK 0x00180000
+#define MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT 19
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(uint32_t val)
+{
+ return ((val) << MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__SHIFT) & MDP4_PIPE_SRC_FORMAT_FETCH_PLANES__MASK;
+}
#define MDP4_PIPE_SRC_FORMAT_SOLID_FILL 0x00400000
+#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK 0x0c000000
+#define MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT 26
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val)
+{
+ return ((val) << MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
+}
+#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK 0x60000000
+#define MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT 29
+static inline uint32_t MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT(enum mdp4_frame_format val)
+{
+ return ((val) << MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__SHIFT) & MDP4_PIPE_SRC_FORMAT_FRAME_FORMAT__MASK;
+}
static inline uint32_t REG_MDP4_PIPE_SRC_UNPACK(enum mdp4_pipe i0) { return 0x00020054 + 0x10000*i0; }
#define MDP4_PIPE_SRC_UNPACK_ELEM0__MASK 0x000000ff
@@ -751,6 +784,18 @@ static inline uint32_t MDP4_PIPE_SRC_UNPACK_ELEM3(uint32_t val)
static inline uint32_t REG_MDP4_PIPE_OP_MODE(enum mdp4_pipe i0) { return 0x00020058 + 0x10000*i0; }
#define MDP4_PIPE_OP_MODE_SCALEX_EN 0x00000001
#define MDP4_PIPE_OP_MODE_SCALEY_EN 0x00000002
+#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK 0x0000000c
+#define MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT 2
+static inline uint32_t MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(enum mdp4_scale_unit val)
+{
+ return ((val) << MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL__MASK;
+}
+#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK 0x00000030
+#define MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT 4
+static inline uint32_t MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(enum mdp4_scale_unit val)
+{
+ return ((val) << MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__SHIFT) & MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL__MASK;
+}
#define MDP4_PIPE_OP_MODE_SRC_YCBCR 0x00000200
#define MDP4_PIPE_OP_MODE_DST_YCBCR 0x00000400
#define MDP4_PIPE_OP_MODE_CSC_EN 0x00000800
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
index 3449213f1e76..73afa21822b4 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_crtc.c
@@ -140,26 +140,6 @@ static void mdp4_crtc_destroy(struct drm_crtc *crtc)
kfree(mdp4_crtc);
}
-static void mdp4_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
- struct mdp4_kms *mdp4_kms = get_kms(crtc);
- bool enabled = (mode == DRM_MODE_DPMS_ON);
-
- DBG("%s: mode=%d", mdp4_crtc->name, mode);
-
- if (enabled != mdp4_crtc->enabled) {
- if (enabled) {
- mdp4_enable(mdp4_kms);
- mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
- } else {
- mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
- mdp4_disable(mdp4_kms);
- }
- mdp4_crtc->enabled = enabled;
- }
-}
-
static bool mdp4_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -304,27 +284,38 @@ static void mdp4_crtc_mode_set_nofb(struct drm_crtc *crtc)
}
}
-static void mdp4_crtc_prepare(struct drm_crtc *crtc)
+static void mdp4_crtc_disable(struct drm_crtc *crtc)
{
struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+ struct mdp4_kms *mdp4_kms = get_kms(crtc);
+
DBG("%s", mdp4_crtc->name);
- /* make sure we hold a ref to mdp clks while setting up mode: */
- drm_crtc_vblank_get(crtc);
- mdp4_enable(get_kms(crtc));
- mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ if (WARN_ON(!mdp4_crtc->enabled))
+ return;
+
+ mdp_irq_unregister(&mdp4_kms->base, &mdp4_crtc->err);
+ mdp4_disable(mdp4_kms);
+
+ mdp4_crtc->enabled = false;
}
-static void mdp4_crtc_commit(struct drm_crtc *crtc)
+static void mdp4_crtc_enable(struct drm_crtc *crtc)
{
- mdp4_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+ struct mdp4_crtc *mdp4_crtc = to_mdp4_crtc(crtc);
+ struct mdp4_kms *mdp4_kms = get_kms(crtc);
+
+ DBG("%s", mdp4_crtc->name);
+
+ if (WARN_ON(mdp4_crtc->enabled))
+ return;
+
+ mdp4_enable(mdp4_kms);
+ mdp_irq_register(&mdp4_kms->base, &mdp4_crtc->err);
+
crtc_flush(crtc);
- /* drop the ref to mdp clk's that we got in prepare: */
- mdp4_disable(get_kms(crtc));
- drm_crtc_vblank_put(crtc);
-}
-static void mdp4_crtc_load_lut(struct drm_crtc *crtc)
-{
+ mdp4_crtc->enabled = true;
}
static int mdp4_crtc_atomic_check(struct drm_crtc *crtc,
@@ -508,14 +499,10 @@ static const struct drm_crtc_funcs mdp4_crtc_funcs = {
};
static const struct drm_crtc_helper_funcs mdp4_crtc_helper_funcs = {
- .dpms = mdp4_crtc_dpms,
.mode_fixup = mdp4_crtc_mode_fixup,
.mode_set_nofb = mdp4_crtc_mode_set_nofb,
- .mode_set = drm_helper_crtc_mode_set,
- .mode_set_base = drm_helper_crtc_mode_set_base,
- .prepare = mdp4_crtc_prepare,
- .commit = mdp4_crtc_commit,
- .load_lut = mdp4_crtc_load_lut,
+ .disable = mdp4_crtc_disable,
+ .enable = mdp4_crtc_enable,
.atomic_check = mdp4_crtc_atomic_check,
.atomic_begin = mdp4_crtc_atomic_begin,
.atomic_flush = mdp4_crtc_atomic_flush,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
index c3878420180b..7896323b2631 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_dtv_encoder.c
@@ -94,61 +94,6 @@ static const struct drm_encoder_funcs mdp4_dtv_encoder_funcs = {
.destroy = mdp4_dtv_encoder_destroy,
};
-static void mdp4_dtv_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct drm_device *dev = encoder->dev;
- struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
- struct mdp4_kms *mdp4_kms = get_kms(encoder);
- bool enabled = (mode == DRM_MODE_DPMS_ON);
-
- DBG("mode=%d", mode);
-
- if (enabled == mdp4_dtv_encoder->enabled)
- return;
-
- if (enabled) {
- unsigned long pc = mdp4_dtv_encoder->pixclock;
- int ret;
-
- bs_set(mdp4_dtv_encoder, 1);
-
- DBG("setting src_clk=%lu", pc);
-
- ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
- if (ret)
- dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret);
- clk_prepare_enable(mdp4_dtv_encoder->src_clk);
- ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
- if (ret)
- dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
- ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
- if (ret)
- dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
-
- mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1);
- } else {
- mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
-
- /*
- * Wait for a vsync so we know the ENABLE=0 latched before
- * the (connector) source of the vsync's gets disabled,
- * otherwise we end up in a funny state if we re-enable
- * before the disable latches, which results that some of
- * the settings changes for the new modeset (like new
- * scanout buffer) don't latch properly..
- */
- mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC);
-
- clk_disable_unprepare(mdp4_dtv_encoder->src_clk);
- clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
- clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
-
- bs_set(mdp4_dtv_encoder, 0);
- }
-
- mdp4_dtv_encoder->enabled = enabled;
-}
-
static bool mdp4_dtv_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -221,28 +166,78 @@ static void mdp4_dtv_encoder_mode_set(struct drm_encoder *encoder,
mdp4_write(mdp4_kms, REG_MDP4_DTV_ACTIVE_VEND, 0);
}
-static void mdp4_dtv_encoder_prepare(struct drm_encoder *encoder)
+static void mdp4_dtv_encoder_disable(struct drm_encoder *encoder)
{
- mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+ struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+
+ if (WARN_ON(!mdp4_dtv_encoder->enabled))
+ return;
+
+ mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 0);
+
+ /*
+ * Wait for a vsync so we know the ENABLE=0 latched before
+ * the (connector) source of the vsync's gets disabled,
+ * otherwise we end up in a funny state if we re-enable
+ * before the disable latches, which results that some of
+ * the settings changes for the new modeset (like new
+ * scanout buffer) don't latch properly..
+ */
+ mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_EXTERNAL_VSYNC);
+
+ clk_disable_unprepare(mdp4_dtv_encoder->src_clk);
+ clk_disable_unprepare(mdp4_dtv_encoder->hdmi_clk);
+ clk_disable_unprepare(mdp4_dtv_encoder->mdp_clk);
+
+ bs_set(mdp4_dtv_encoder, 0);
+
+ mdp4_dtv_encoder->enabled = false;
}
-static void mdp4_dtv_encoder_commit(struct drm_encoder *encoder)
+static void mdp4_dtv_encoder_enable(struct drm_encoder *encoder)
{
+ struct drm_device *dev = encoder->dev;
+ struct mdp4_dtv_encoder *mdp4_dtv_encoder = to_mdp4_dtv_encoder(encoder);
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+ unsigned long pc = mdp4_dtv_encoder->pixclock;
+ int ret;
+
+ if (WARN_ON(mdp4_dtv_encoder->enabled))
+ return;
+
mdp4_crtc_set_config(encoder->crtc,
MDP4_DMA_CONFIG_R_BPC(BPC8) |
MDP4_DMA_CONFIG_G_BPC(BPC8) |
MDP4_DMA_CONFIG_B_BPC(BPC8) |
MDP4_DMA_CONFIG_PACK(0x21));
mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 1);
- mdp4_dtv_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ bs_set(mdp4_dtv_encoder, 1);
+
+ DBG("setting src_clk=%lu", pc);
+
+ ret = clk_set_rate(mdp4_dtv_encoder->src_clk, pc);
+ if (ret)
+ dev_err(dev->dev, "failed to set src_clk to %lu: %d\n", pc, ret);
+ clk_prepare_enable(mdp4_dtv_encoder->src_clk);
+ ret = clk_prepare_enable(mdp4_dtv_encoder->hdmi_clk);
+ if (ret)
+ dev_err(dev->dev, "failed to enable hdmi_clk: %d\n", ret);
+ ret = clk_prepare_enable(mdp4_dtv_encoder->mdp_clk);
+ if (ret)
+ dev_err(dev->dev, "failed to enabled mdp_clk: %d\n", ret);
+
+ mdp4_write(mdp4_kms, REG_MDP4_DTV_ENABLE, 1);
+
+ mdp4_dtv_encoder->enabled = true;
}
static const struct drm_encoder_helper_funcs mdp4_dtv_encoder_helper_funcs = {
- .dpms = mdp4_dtv_encoder_dpms,
.mode_fixup = mdp4_dtv_encoder_mode_fixup,
.mode_set = mdp4_dtv_encoder_mode_set,
- .prepare = mdp4_dtv_encoder_prepare,
- .commit = mdp4_dtv_encoder_commit,
+ .enable = mdp4_dtv_encoder_enable,
+ .disable = mdp4_dtv_encoder_disable,
};
long mdp4_dtv_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
index a62109e4ae0d..d847b9436194 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.c
@@ -125,6 +125,38 @@ out:
return ret;
}
+static void mdp4_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+ struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+ int i, ncrtcs = state->dev->mode_config.num_crtc;
+
+ mdp4_enable(mdp4_kms);
+
+ /* see 119ecb7fd */
+ for (i = 0; i < ncrtcs; i++) {
+ struct drm_crtc *crtc = state->crtcs[i];
+ if (!crtc)
+ continue;
+ drm_crtc_vblank_get(crtc);
+ }
+}
+
+static void mdp4_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+ struct mdp4_kms *mdp4_kms = to_mdp4_kms(to_mdp_kms(kms));
+ int i, ncrtcs = state->dev->mode_config.num_crtc;
+
+ /* see 119ecb7fd */
+ for (i = 0; i < ncrtcs; i++) {
+ struct drm_crtc *crtc = state->crtcs[i];
+ if (!crtc)
+ continue;
+ drm_crtc_vblank_put(crtc);
+ }
+
+ mdp4_disable(mdp4_kms);
+}
+
static long mdp4_round_pixclk(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder)
{
@@ -161,6 +193,8 @@ static const struct mdp_kms_funcs kms_funcs = {
.irq = mdp4_irq,
.enable_vblank = mdp4_enable_vblank,
.disable_vblank = mdp4_disable_vblank,
+ .prepare_commit = mdp4_prepare_commit,
+ .complete_commit = mdp4_complete_commit,
.get_format = mdp_get_format,
.round_pixclk = mdp4_round_pixclk,
.preclose = mdp4_preclose,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
index cbd77bc626d5..0a5c58bde7a9 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_kms.h
@@ -175,14 +175,25 @@ irqreturn_t mdp4_irq(struct msm_kms *kms);
int mdp4_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
void mdp4_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
+static inline bool pipe_supports_yuv(enum mdp4_pipe pipe)
+{
+ switch (pipe) {
+ case VG1:
+ case VG2:
+ case VG3:
+ case VG4:
+ return true;
+ default:
+ return false;
+ }
+}
+
static inline
uint32_t mdp4_get_formats(enum mdp4_pipe pipe_id, uint32_t *pixel_formats,
uint32_t max_formats)
{
- /* TODO when we have YUV, we need to filter supported formats
- * based on pipe_id..
- */
- return mdp_get_formats(pixel_formats, max_formats);
+ return mdp_get_formats(pixel_formats, max_formats,
+ !pipe_supports_yuv(pipe_id));
}
void mdp4_plane_install_properties(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
index 41f6436754fc..60ec8222c9f6 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lcdc_encoder.c
@@ -259,77 +259,6 @@ static void setup_phy(struct drm_encoder *encoder)
mdp4_write(mdp4_kms, REG_MDP4_LVDS_PHY_CFG0, lvds_phy_cfg0);
}
-static void mdp4_lcdc_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct drm_device *dev = encoder->dev;
- struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
- to_mdp4_lcdc_encoder(encoder);
- struct mdp4_kms *mdp4_kms = get_kms(encoder);
- struct drm_panel *panel = mdp4_lcdc_encoder->panel;
- bool enabled = (mode == DRM_MODE_DPMS_ON);
- int i, ret;
-
- DBG("mode=%d", mode);
-
- if (enabled == mdp4_lcdc_encoder->enabled)
- return;
-
- if (enabled) {
- unsigned long pc = mdp4_lcdc_encoder->pixclock;
- int ret;
-
- bs_set(mdp4_lcdc_encoder, 1);
-
- for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
- ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
- if (ret)
- dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
- }
-
- DBG("setting lcdc_clk=%lu", pc);
- ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
- if (ret)
- dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
- ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
- if (ret)
- dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
-
- if (panel)
- drm_panel_enable(panel);
-
- setup_phy(encoder);
-
- mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
- } else {
- mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
-
- if (panel)
- drm_panel_disable(panel);
-
- /*
- * Wait for a vsync so we know the ENABLE=0 latched before
- * the (connector) source of the vsync's gets disabled,
- * otherwise we end up in a funny state if we re-enable
- * before the disable latches, which results that some of
- * the settings changes for the new modeset (like new
- * scanout buffer) don't latch properly..
- */
- mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
-
- clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
-
- for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
- ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
- if (ret)
- dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
- }
-
- bs_set(mdp4_lcdc_encoder, 0);
- }
-
- mdp4_lcdc_encoder->enabled = enabled;
-}
-
static bool mdp4_lcdc_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -403,13 +332,59 @@ static void mdp4_lcdc_encoder_mode_set(struct drm_encoder *encoder,
mdp4_write(mdp4_kms, REG_MDP4_LCDC_ACTIVE_VEND, 0);
}
-static void mdp4_lcdc_encoder_prepare(struct drm_encoder *encoder)
+static void mdp4_lcdc_encoder_disable(struct drm_encoder *encoder)
{
- mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+ struct drm_device *dev = encoder->dev;
+ struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+ to_mdp4_lcdc_encoder(encoder);
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+ struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+ int i, ret;
+
+ if (WARN_ON(!mdp4_lcdc_encoder->enabled))
+ return;
+
+ mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 0);
+
+ if (panel)
+ drm_panel_disable(panel);
+
+ /*
+ * Wait for a vsync so we know the ENABLE=0 latched before
+ * the (connector) source of the vsync's gets disabled,
+ * otherwise we end up in a funny state if we re-enable
+ * before the disable latches, which results that some of
+ * the settings changes for the new modeset (like new
+ * scanout buffer) don't latch properly..
+ */
+ mdp_irq_wait(&mdp4_kms->base, MDP4_IRQ_PRIMARY_VSYNC);
+
+ clk_disable_unprepare(mdp4_lcdc_encoder->lcdc_clk);
+
+ for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
+ ret = regulator_disable(mdp4_lcdc_encoder->regs[i]);
+ if (ret)
+ dev_err(dev->dev, "failed to disable regulator: %d\n", ret);
+ }
+
+ bs_set(mdp4_lcdc_encoder, 0);
+
+ mdp4_lcdc_encoder->enabled = false;
}
-static void mdp4_lcdc_encoder_commit(struct drm_encoder *encoder)
+static void mdp4_lcdc_encoder_enable(struct drm_encoder *encoder)
{
+ struct drm_device *dev = encoder->dev;
+ struct mdp4_lcdc_encoder *mdp4_lcdc_encoder =
+ to_mdp4_lcdc_encoder(encoder);
+ unsigned long pc = mdp4_lcdc_encoder->pixclock;
+ struct mdp4_kms *mdp4_kms = get_kms(encoder);
+ struct drm_panel *panel = mdp4_lcdc_encoder->panel;
+ int i, ret;
+
+ if (WARN_ON(mdp4_lcdc_encoder->enabled))
+ return;
+
/* TODO: hard-coded for 18bpp: */
mdp4_crtc_set_config(encoder->crtc,
MDP4_DMA_CONFIG_R_BPC(BPC6) |
@@ -420,15 +395,38 @@ static void mdp4_lcdc_encoder_commit(struct drm_encoder *encoder)
MDP4_DMA_CONFIG_DEFLKR_EN |
MDP4_DMA_CONFIG_DITHER_EN);
mdp4_crtc_set_intf(encoder->crtc, INTF_LCDC_DTV, 0);
- mdp4_lcdc_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ bs_set(mdp4_lcdc_encoder, 1);
+
+ for (i = 0; i < ARRAY_SIZE(mdp4_lcdc_encoder->regs); i++) {
+ ret = regulator_enable(mdp4_lcdc_encoder->regs[i]);
+ if (ret)
+ dev_err(dev->dev, "failed to enable regulator: %d\n", ret);
+ }
+
+ DBG("setting lcdc_clk=%lu", pc);
+ ret = clk_set_rate(mdp4_lcdc_encoder->lcdc_clk, pc);
+ if (ret)
+ dev_err(dev->dev, "failed to configure lcdc_clk: %d\n", ret);
+ ret = clk_prepare_enable(mdp4_lcdc_encoder->lcdc_clk);
+ if (ret)
+ dev_err(dev->dev, "failed to enable lcdc_clk: %d\n", ret);
+
+ if (panel)
+ drm_panel_enable(panel);
+
+ setup_phy(encoder);
+
+ mdp4_write(mdp4_kms, REG_MDP4_LCDC_ENABLE, 1);
+
+ mdp4_lcdc_encoder->enabled = true;
}
static const struct drm_encoder_helper_funcs mdp4_lcdc_encoder_helper_funcs = {
- .dpms = mdp4_lcdc_encoder_dpms,
.mode_fixup = mdp4_lcdc_encoder_mode_fixup,
.mode_set = mdp4_lcdc_encoder_mode_set,
- .prepare = mdp4_lcdc_encoder_prepare,
- .commit = mdp4_lcdc_encoder_commit,
+ .disable = mdp4_lcdc_encoder_disable,
+ .enable = mdp4_lcdc_encoder_enable,
};
long mdp4_lcdc_round_pixclk(struct drm_encoder *encoder, unsigned long rate)
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
index 4ddc28e1275b..921185133d38 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_lvds_connector.c
@@ -94,7 +94,7 @@ mdp4_lvds_connector_best_encoder(struct drm_connector *connector)
}
static const struct drm_connector_funcs mdp4_lvds_connector_funcs = {
- .dpms = drm_helper_connector_dpms,
+ .dpms = drm_atomic_helper_connector_dpms,
.detect = mdp4_lvds_connector_detect,
.fill_modes = drm_helper_probe_single_connector_modes,
.destroy = mdp4_lvds_connector_destroy,
diff --git a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
index 1e5ebe83647d..cde25009203a 100644
--- a/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp4/mdp4_plane.c
@@ -17,6 +17,8 @@
#include "mdp4_kms.h"
+#define DOWN_SCALE_MAX 8
+#define UP_SCALE_MAX 8
struct mdp4_plane {
struct drm_plane base;
@@ -136,10 +138,6 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane,
struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
struct mdp4_kms *mdp4_kms = get_kms(plane);
enum mdp4_pipe pipe = mdp4_plane->pipe;
- uint32_t iova = msm_framebuffer_iova(fb, mdp4_kms->id, 0);
-
- DBG("%s: set_scanout: %08x (%u)", mdp4_plane->name,
- iova, fb->pitches[0]);
mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_STRIDE_A(pipe),
MDP4_PIPE_SRC_STRIDE_A_P0(fb->pitches[0]) |
@@ -149,11 +147,45 @@ static void mdp4_plane_set_scanout(struct drm_plane *plane,
MDP4_PIPE_SRC_STRIDE_B_P2(fb->pitches[2]) |
MDP4_PIPE_SRC_STRIDE_B_P3(fb->pitches[3]));
- mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe), iova);
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP0_BASE(pipe),
+ msm_framebuffer_iova(fb, mdp4_kms->id, 0));
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP1_BASE(pipe),
+ msm_framebuffer_iova(fb, mdp4_kms->id, 1));
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP2_BASE(pipe),
+ msm_framebuffer_iova(fb, mdp4_kms->id, 2));
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRCP3_BASE(pipe),
+ msm_framebuffer_iova(fb, mdp4_kms->id, 3));
plane->fb = fb;
}
+static void mdp4_write_csc_config(struct mdp4_kms *mdp4_kms,
+ enum mdp4_pipe pipe, struct csc_cfg *csc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(csc->matrix); i++) {
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_MV(pipe, i),
+ csc->matrix[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(csc->post_bias) ; i++) {
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_BV(pipe, i),
+ csc->pre_bias[i]);
+
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_BV(pipe, i),
+ csc->post_bias[i]);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(csc->post_clamp) ; i++) {
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_PRE_LV(pipe, i),
+ csc->pre_clamp[i]);
+
+ mdp4_write(mdp4_kms, REG_MDP4_PIPE_CSC_POST_LV(pipe, i),
+ csc->post_clamp[i]);
+ }
+}
+
#define MDP4_VG_PHASE_STEP_DEFAULT 0x20000000
static int mdp4_plane_mode_set(struct drm_plane *plane,
@@ -163,6 +195,7 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
uint32_t src_x, uint32_t src_y,
uint32_t src_w, uint32_t src_h)
{
+ struct drm_device *dev = plane->dev;
struct mdp4_plane *mdp4_plane = to_mdp4_plane(plane);
struct mdp4_kms *mdp4_kms = get_kms(plane);
enum mdp4_pipe pipe = mdp4_plane->pipe;
@@ -186,14 +219,59 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
fb->base.id, src_x, src_y, src_w, src_h,
crtc->base.id, crtc_x, crtc_y, crtc_w, crtc_h);
+ format = to_mdp_format(msm_framebuffer_format(fb));
+
+ if (src_w > (crtc_w * DOWN_SCALE_MAX)) {
+ dev_err(dev->dev, "Width down scaling exceeds limits!\n");
+ return -ERANGE;
+ }
+
+ if (src_h > (crtc_h * DOWN_SCALE_MAX)) {
+ dev_err(dev->dev, "Height down scaling exceeds limits!\n");
+ return -ERANGE;
+ }
+
+ if (crtc_w > (src_w * UP_SCALE_MAX)) {
+ dev_err(dev->dev, "Width up scaling exceeds limits!\n");
+ return -ERANGE;
+ }
+
+ if (crtc_h > (src_h * UP_SCALE_MAX)) {
+ dev_err(dev->dev, "Height up scaling exceeds limits!\n");
+ return -ERANGE;
+ }
+
if (src_w != crtc_w) {
+ uint32_t sel_unit = SCALE_FIR;
op_mode |= MDP4_PIPE_OP_MODE_SCALEX_EN;
- /* TODO calc phasex_step */
+
+ if (MDP_FORMAT_IS_YUV(format)) {
+ if (crtc_w > src_w)
+ sel_unit = SCALE_PIXEL_RPT;
+ else if (crtc_w <= (src_w / 4))
+ sel_unit = SCALE_MN_PHASE;
+
+ op_mode |= MDP4_PIPE_OP_MODE_SCALEX_UNIT_SEL(sel_unit);
+ phasex_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT,
+ src_w, crtc_w);
+ }
}
if (src_h != crtc_h) {
+ uint32_t sel_unit = SCALE_FIR;
op_mode |= MDP4_PIPE_OP_MODE_SCALEY_EN;
- /* TODO calc phasey_step */
+
+ if (MDP_FORMAT_IS_YUV(format)) {
+
+ if (crtc_h > src_h)
+ sel_unit = SCALE_PIXEL_RPT;
+ else if (crtc_h <= (src_h / 4))
+ sel_unit = SCALE_MN_PHASE;
+
+ op_mode |= MDP4_PIPE_OP_MODE_SCALEY_UNIT_SEL(sel_unit);
+ phasey_step = mult_frac(MDP4_VG_PHASE_STEP_DEFAULT,
+ src_h, crtc_h);
+ }
}
mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_SIZE(pipe),
@@ -214,8 +292,6 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
mdp4_plane_set_scanout(plane, fb);
- format = to_mdp_format(msm_framebuffer_format(fb));
-
mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_FORMAT(pipe),
MDP4_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
MDP4_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
@@ -224,6 +300,8 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
COND(format->alpha_enable, MDP4_PIPE_SRC_FORMAT_ALPHA_ENABLE) |
MDP4_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
MDP4_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
+ MDP4_PIPE_SRC_FORMAT_FETCH_PLANES(format->fetch_type) |
+ MDP4_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample) |
COND(format->unpack_tight, MDP4_PIPE_SRC_FORMAT_UNPACK_TIGHT));
mdp4_write(mdp4_kms, REG_MDP4_PIPE_SRC_UNPACK(pipe),
@@ -232,6 +310,14 @@ static int mdp4_plane_mode_set(struct drm_plane *plane,
MDP4_PIPE_SRC_UNPACK_ELEM2(format->unpack[2]) |
MDP4_PIPE_SRC_UNPACK_ELEM3(format->unpack[3]));
+ if (MDP_FORMAT_IS_YUV(format)) {
+ struct csc_cfg *csc = mdp_get_default_csc_cfg(CSC_YUV2RGB);
+
+ op_mode |= MDP4_PIPE_OP_MODE_SRC_YCBCR;
+ op_mode |= MDP4_PIPE_OP_MODE_CSC_EN;
+ mdp4_write_csc_config(mdp4_kms, pipe, csc);
+ }
+
mdp4_write(mdp4_kms, REG_MDP4_PIPE_OP_MODE(pipe), op_mode);
mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEX_STEP(pipe), phasex_step);
mdp4_write(mdp4_kms, REG_MDP4_PIPE_PHASEY_STEP(pipe), phasey_step);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
index e87ef5512cb0..09b4a25eb553 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5.xml.h
@@ -8,18 +8,19 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20136 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1940 bytes, from 2014-10-31 16:51:39)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 23963 bytes, from 2014-10-31 16:51:46)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-07-17 15:33:30)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
-Copyright (C) 2013-2014 by the following authors:
+Copyright (C) 2013-2015 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining
@@ -88,13 +89,6 @@ enum mdp5_pack_3d {
PACK_3D_COL_INT = 3,
};
-enum mdp5_chroma_samp_type {
- CHROMA_RGB = 0,
- CHROMA_H2V1 = 1,
- CHROMA_H1V2 = 2,
- CHROMA_420 = 3,
-};
-
enum mdp5_scale_filter {
SCALE_FILTER_NEAREST = 0,
SCALE_FILTER_BIL = 1,
@@ -135,6 +129,17 @@ enum mdp5_client_id {
CID_MAX = 23,
};
+enum mdp5_cursor_format {
+ CURSOR_FMT_ARGB8888 = 0,
+ CURSOR_FMT_ARGB1555 = 2,
+ CURSOR_FMT_ARGB4444 = 4,
+};
+
+enum mdp5_cursor_alpha {
+ CURSOR_ALPHA_CONST = 0,
+ CURSOR_ALPHA_PER_PIXEL = 2,
+};
+
enum mdp5_igc_type {
IGC_VIG = 0,
IGC_RGB = 1,
@@ -142,6 +147,11 @@ enum mdp5_igc_type {
IGC_DSPP = 3,
};
+enum mdp5_data_format {
+ DATA_FORMAT_RGB = 0,
+ DATA_FORMAT_YUV = 1,
+};
+
#define MDP5_IRQ_INTF0_WB_ROT_COMP 0x00000001
#define MDP5_IRQ_INTF1_WB_ROT_COMP 0x00000002
#define MDP5_IRQ_INTF2_WB_ROT_COMP 0x00000004
@@ -463,12 +473,143 @@ static inline uint32_t __offset_PIPE(enum mdp5_pipe idx)
}
static inline uint32_t REG_MDP5_PIPE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); }
+static inline uint32_t REG_MDP5_PIPE_OP_MODE(enum mdp5_pipe i0) { return 0x00000200 + __offset_PIPE(i0); }
+#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK 0x00080000
+#define MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT 19
+static inline uint32_t MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(enum mdp5_data_format val)
+{
+ return ((val) << MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT__MASK;
+}
+#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK 0x00040000
+#define MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT 18
+static inline uint32_t MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(enum mdp5_data_format val)
+{
+ return ((val) << MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__SHIFT) & MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT__MASK;
+}
+#define MDP5_PIPE_OP_MODE_CSC_1_EN 0x00020000
+
static inline uint32_t REG_MDP5_PIPE_HIST_CTL_BASE(enum mdp5_pipe i0) { return 0x000002c4 + __offset_PIPE(i0); }
static inline uint32_t REG_MDP5_PIPE_HIST_LUT_BASE(enum mdp5_pipe i0) { return 0x000002f0 + __offset_PIPE(i0); }
static inline uint32_t REG_MDP5_PIPE_HIST_LUT_SWAP(enum mdp5_pipe i0) { return 0x00000300 + __offset_PIPE(i0); }
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(enum mdp5_pipe i0) { return 0x00000320 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK 0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK 0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT 16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(enum mdp5_pipe i0) { return 0x00000324 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK 0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK 0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT 16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(enum mdp5_pipe i0) { return 0x00000328 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK 0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK 0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT 16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(enum mdp5_pipe i0) { return 0x0000032c + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK 0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31__MASK;
+}
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK 0x1fff0000
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT 16
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(enum mdp5_pipe i0) { return 0x00000330 + __offset_PIPE(i0); }
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK 0x00001fff
+#define MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__SHIFT) & MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000334 + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK 0x000000ff
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH__MASK;
+}
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK 0x0000ff00
+#define MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT 8
+static inline uint32_t MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_CLAMP_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000340 + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK 0x000000ff
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH__MASK;
+}
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK 0x0000ff00
+#define MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT 8
+static inline uint32_t MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__SHIFT) & MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_PRE_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x0000034c + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK 0x000001ff
+#define MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE__MASK;
+}
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; }
+
+static inline uint32_t REG_MDP5_PIPE_CSC_1_POST_BIAS_REG(enum mdp5_pipe i0, uint32_t i1) { return 0x00000358 + __offset_PIPE(i0) + 0x4*i1; }
+#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK 0x000001ff
+#define MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT 0
+static inline uint32_t MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(uint32_t val)
+{
+ return ((val) << MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__SHIFT) & MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE__MASK;
+}
+
static inline uint32_t REG_MDP5_PIPE_SRC_SIZE(enum mdp5_pipe i0) { return 0x00000000 + __offset_PIPE(i0); }
#define MDP5_PIPE_SRC_SIZE_HEIGHT__MASK 0xffff0000
#define MDP5_PIPE_SRC_SIZE_HEIGHT__SHIFT 16
@@ -618,15 +759,15 @@ static inline uint32_t MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(uint32_t val)
}
#define MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT 0x00020000
#define MDP5_PIPE_SRC_FORMAT_UNPACK_ALIGN_MSB 0x00040000
-#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK 0x00780000
+#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK 0x00180000
#define MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT 19
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(uint32_t val)
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_NUM_PLANES(enum mdp_sspp_fetch_type val)
{
return ((val) << MDP5_PIPE_SRC_FORMAT_NUM_PLANES__SHIFT) & MDP5_PIPE_SRC_FORMAT_NUM_PLANES__MASK;
}
#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK 0x01800000
#define MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT 23
-static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp5_chroma_samp_type val)
+static inline uint32_t MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(enum mdp_chroma_samp_type val)
{
return ((val) << MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__SHIFT) & MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP__MASK;
}
@@ -753,6 +894,10 @@ static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_X(enum mdp5_pipe i0) { ret
static inline uint32_t REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x00000214 + __offset_PIPE(i0); }
+static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(enum mdp5_pipe i0) { return 0x00000218 + __offset_PIPE(i0); }
+
+static inline uint32_t REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(enum mdp5_pipe i0) { return 0x0000021c + __offset_PIPE(i0); }
+
static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_X(enum mdp5_pipe i0) { return 0x00000220 + __offset_PIPE(i0); }
static inline uint32_t REG_MDP5_PIPE_SCALE_INIT_PHASE_Y(enum mdp5_pipe i0) { return 0x00000224 + __offset_PIPE(i0); }
@@ -839,20 +984,88 @@ static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH0(uint32_t i0, uint32_t i
static inline uint32_t REG_MDP5_LM_BLEND_BG_TRANSP_HIGH1(uint32_t i0, uint32_t i1) { return 0x00000048 + __offset_LM(i0) + 0x30*i1; }
static inline uint32_t REG_MDP5_LM_CURSOR_IMG_SIZE(uint32_t i0) { return 0x000000e0 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK 0x0000ffff
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT 0
+static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_W(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_W__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_W__MASK;
+}
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK 0xffff0000
+#define MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT 16
+static inline uint32_t MDP5_LM_CURSOR_IMG_SIZE_SRC_H(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_IMG_SIZE_SRC_H__SHIFT) & MDP5_LM_CURSOR_IMG_SIZE_SRC_H__MASK;
+}
static inline uint32_t REG_MDP5_LM_CURSOR_SIZE(uint32_t i0) { return 0x000000e4 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_SIZE_ROI_W__MASK 0x0000ffff
+#define MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT 0
+static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_W(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_SIZE_ROI_W__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_W__MASK;
+}
+#define MDP5_LM_CURSOR_SIZE_ROI_H__MASK 0xffff0000
+#define MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT 16
+static inline uint32_t MDP5_LM_CURSOR_SIZE_ROI_H(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_SIZE_ROI_H__SHIFT) & MDP5_LM_CURSOR_SIZE_ROI_H__MASK;
+}
static inline uint32_t REG_MDP5_LM_CURSOR_XY(uint32_t i0) { return 0x000000e8 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_XY_SRC_X__MASK 0x0000ffff
+#define MDP5_LM_CURSOR_XY_SRC_X__SHIFT 0
+static inline uint32_t MDP5_LM_CURSOR_XY_SRC_X(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_XY_SRC_X__SHIFT) & MDP5_LM_CURSOR_XY_SRC_X__MASK;
+}
+#define MDP5_LM_CURSOR_XY_SRC_Y__MASK 0xffff0000
+#define MDP5_LM_CURSOR_XY_SRC_Y__SHIFT 16
+static inline uint32_t MDP5_LM_CURSOR_XY_SRC_Y(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_XY_SRC_Y__SHIFT) & MDP5_LM_CURSOR_XY_SRC_Y__MASK;
+}
static inline uint32_t REG_MDP5_LM_CURSOR_STRIDE(uint32_t i0) { return 0x000000dc + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_STRIDE_STRIDE__MASK 0x0000ffff
+#define MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT 0
+static inline uint32_t MDP5_LM_CURSOR_STRIDE_STRIDE(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_STRIDE_STRIDE__SHIFT) & MDP5_LM_CURSOR_STRIDE_STRIDE__MASK;
+}
static inline uint32_t REG_MDP5_LM_CURSOR_FORMAT(uint32_t i0) { return 0x000000ec + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_FORMAT_FORMAT__MASK 0x00000007
+#define MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT 0
+static inline uint32_t MDP5_LM_CURSOR_FORMAT_FORMAT(enum mdp5_cursor_format val)
+{
+ return ((val) << MDP5_LM_CURSOR_FORMAT_FORMAT__SHIFT) & MDP5_LM_CURSOR_FORMAT_FORMAT__MASK;
+}
static inline uint32_t REG_MDP5_LM_CURSOR_BASE_ADDR(uint32_t i0) { return 0x000000f0 + __offset_LM(i0); }
static inline uint32_t REG_MDP5_LM_CURSOR_START_XY(uint32_t i0) { return 0x000000f4 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_START_XY_X_START__MASK 0x0000ffff
+#define MDP5_LM_CURSOR_START_XY_X_START__SHIFT 0
+static inline uint32_t MDP5_LM_CURSOR_START_XY_X_START(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_START_XY_X_START__SHIFT) & MDP5_LM_CURSOR_START_XY_X_START__MASK;
+}
+#define MDP5_LM_CURSOR_START_XY_Y_START__MASK 0xffff0000
+#define MDP5_LM_CURSOR_START_XY_Y_START__SHIFT 16
+static inline uint32_t MDP5_LM_CURSOR_START_XY_Y_START(uint32_t val)
+{
+ return ((val) << MDP5_LM_CURSOR_START_XY_Y_START__SHIFT) & MDP5_LM_CURSOR_START_XY_Y_START__MASK;
+}
static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_CONFIG(uint32_t i0) { return 0x000000f8 + __offset_LM(i0); }
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN 0x00000001
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK 0x00000006
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT 1
+static inline uint32_t MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(enum mdp5_cursor_alpha val)
+{
+ return ((val) << MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__SHIFT) & MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL__MASK;
+}
+#define MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN 0x00000008
static inline uint32_t REG_MDP5_LM_CURSOR_BLEND_PARAM(uint32_t i0) { return 0x000000fc + __offset_LM(i0); }
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
index f021f960a8a2..46fac545dc2b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_crtc.c
@@ -24,6 +24,9 @@
#include "drm_crtc_helper.h"
#include "drm_flip_work.h"
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+
#define SSPP_MAX (SSPP_RGB3 + 1) /* TODO: Add SSPP_MAX in mdp5.xml.h */
struct mdp5_crtc {
@@ -47,8 +50,21 @@ struct mdp5_crtc {
#define PENDING_FLIP 0x2
atomic_t pending;
+ /* for unref'ing cursor bo's after scanout completes: */
+ struct drm_flip_work unref_cursor_work;
+
struct mdp_irq vblank;
struct mdp_irq err;
+
+ struct {
+ /* protect REG_MDP5_LM_CURSOR* registers and cursor scanout_bo*/
+ spinlock_t lock;
+
+ /* current cursor being scanned out: */
+ struct drm_gem_object *scanout_bo;
+ uint32_t width;
+ uint32_t height;
+ } cursor;
};
#define to_mdp5_crtc(x) container_of(x, struct mdp5_crtc, base)
@@ -129,37 +145,26 @@ static void complete_flip(struct drm_crtc *crtc, struct drm_file *file)
}
}
+static void unref_cursor_worker(struct drm_flip_work *work, void *val)
+{
+ struct mdp5_crtc *mdp5_crtc =
+ container_of(work, struct mdp5_crtc, unref_cursor_work);
+ struct mdp5_kms *mdp5_kms = get_kms(&mdp5_crtc->base);
+
+ msm_gem_put_iova(val, mdp5_kms->id);
+ drm_gem_object_unreference_unlocked(val);
+}
+
static void mdp5_crtc_destroy(struct drm_crtc *crtc)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
drm_crtc_cleanup(crtc);
+ drm_flip_work_cleanup(&mdp5_crtc->unref_cursor_work);
kfree(mdp5_crtc);
}
-static void mdp5_crtc_dpms(struct drm_crtc *crtc, int mode)
-{
- struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
- struct mdp5_kms *mdp5_kms = get_kms(crtc);
- bool enabled = (mode == DRM_MODE_DPMS_ON);
-
- DBG("%s: mode=%d", mdp5_crtc->name, mode);
-
- if (enabled != mdp5_crtc->enabled) {
- if (enabled) {
- mdp5_enable(mdp5_kms);
- mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
- } else {
- /* set STAGE_UNUSED for all layers */
- mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
- mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
- mdp5_disable(mdp5_kms);
- }
- mdp5_crtc->enabled = enabled;
- }
-}
-
static bool mdp5_crtc_mode_fixup(struct drm_crtc *crtc,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -256,27 +261,41 @@ static void mdp5_crtc_mode_set_nofb(struct drm_crtc *crtc)
spin_unlock_irqrestore(&mdp5_crtc->lm_lock, flags);
}
-static void mdp5_crtc_prepare(struct drm_crtc *crtc)
+static void mdp5_crtc_disable(struct drm_crtc *crtc)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+ struct mdp5_kms *mdp5_kms = get_kms(crtc);
+
DBG("%s", mdp5_crtc->name);
- /* make sure we hold a ref to mdp clks while setting up mode: */
- mdp5_enable(get_kms(crtc));
- mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_OFF);
+
+ if (WARN_ON(!mdp5_crtc->enabled))
+ return;
+
+ /* set STAGE_UNUSED for all layers */
+ mdp5_ctl_blend(mdp5_crtc->ctl, mdp5_crtc->lm, 0x00000000);
+
+ mdp_irq_unregister(&mdp5_kms->base, &mdp5_crtc->err);
+ mdp5_disable(mdp5_kms);
+
+ mdp5_crtc->enabled = false;
}
-static void mdp5_crtc_commit(struct drm_crtc *crtc)
+static void mdp5_crtc_enable(struct drm_crtc *crtc)
{
struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+ struct mdp5_kms *mdp5_kms = get_kms(crtc);
+
DBG("%s", mdp5_crtc->name);
- mdp5_crtc_dpms(crtc, DRM_MODE_DPMS_ON);
+
+ if (WARN_ON(mdp5_crtc->enabled))
+ return;
+
+ mdp5_enable(mdp5_kms);
+ mdp_irq_register(&mdp5_kms->base, &mdp5_crtc->err);
+
crtc_flush_all(crtc);
- /* drop the ref to mdp clk's that we got in prepare: */
- mdp5_disable(get_kms(crtc));
-}
-static void mdp5_crtc_load_lut(struct drm_crtc *crtc)
-{
+ mdp5_crtc->enabled = true;
}
struct plane_state {
@@ -384,6 +403,132 @@ static int mdp5_crtc_set_property(struct drm_crtc *crtc,
return -EINVAL;
}
+static int mdp5_crtc_cursor_set(struct drm_crtc *crtc,
+ struct drm_file *file, uint32_t handle,
+ uint32_t width, uint32_t height)
+{
+ struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+ struct drm_device *dev = crtc->dev;
+ struct mdp5_kms *mdp5_kms = get_kms(crtc);
+ struct drm_gem_object *cursor_bo, *old_bo;
+ uint32_t blendcfg, cursor_addr, stride;
+ int ret, bpp, lm;
+ unsigned int depth;
+ enum mdp5_cursor_alpha cur_alpha = CURSOR_ALPHA_PER_PIXEL;
+ uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+ unsigned long flags;
+
+ if ((width > CURSOR_WIDTH) || (height > CURSOR_HEIGHT)) {
+ dev_err(dev->dev, "bad cursor size: %dx%d\n", width, height);
+ return -EINVAL;
+ }
+
+ if (NULL == mdp5_crtc->ctl)
+ return -EINVAL;
+
+ if (!handle) {
+ DBG("Cursor off");
+ return mdp5_ctl_set_cursor(mdp5_crtc->ctl, false);
+ }
+
+ cursor_bo = drm_gem_object_lookup(dev, file, handle);
+ if (!cursor_bo)
+ return -ENOENT;
+
+ ret = msm_gem_get_iova(cursor_bo, mdp5_kms->id, &cursor_addr);
+ if (ret)
+ return -EINVAL;
+
+ lm = mdp5_crtc->lm;
+ drm_fb_get_bpp_depth(DRM_FORMAT_ARGB8888, &depth, &bpp);
+ stride = width * (bpp >> 3);
+
+ spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+ old_bo = mdp5_crtc->cursor.scanout_bo;
+
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_STRIDE(lm), stride);
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_FORMAT(lm),
+ MDP5_LM_CURSOR_FORMAT_FORMAT(CURSOR_FMT_ARGB8888));
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_IMG_SIZE(lm),
+ MDP5_LM_CURSOR_IMG_SIZE_SRC_H(height) |
+ MDP5_LM_CURSOR_IMG_SIZE_SRC_W(width));
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(lm),
+ MDP5_LM_CURSOR_SIZE_ROI_H(height) |
+ MDP5_LM_CURSOR_SIZE_ROI_W(width));
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BASE_ADDR(lm), cursor_addr);
+
+
+ blendcfg = MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_EN;
+ blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_TRANSP_EN;
+ blendcfg |= MDP5_LM_CURSOR_BLEND_CONFIG_BLEND_ALPHA_SEL(cur_alpha);
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_BLEND_CONFIG(lm), blendcfg);
+
+ mdp5_crtc->cursor.scanout_bo = cursor_bo;
+ mdp5_crtc->cursor.width = width;
+ mdp5_crtc->cursor.height = height;
+ spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+ ret = mdp5_ctl_set_cursor(mdp5_crtc->ctl, true);
+ if (ret)
+ goto end;
+
+ flush_mask |= mdp5_ctl_get_flush(mdp5_crtc->ctl);
+ crtc_flush(crtc, flush_mask);
+
+end:
+ if (old_bo) {
+ drm_flip_work_queue(&mdp5_crtc->unref_cursor_work, old_bo);
+ /* enable vblank to complete cursor work: */
+ request_pending(crtc, PENDING_CURSOR);
+ }
+ return ret;
+}
+
+static int mdp5_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
+{
+ struct mdp5_kms *mdp5_kms = get_kms(crtc);
+ struct mdp5_crtc *mdp5_crtc = to_mdp5_crtc(crtc);
+ uint32_t flush_mask = mdp_ctl_flush_mask_cursor(0);
+ uint32_t xres = crtc->mode.hdisplay;
+ uint32_t yres = crtc->mode.vdisplay;
+ uint32_t roi_w;
+ uint32_t roi_h;
+ unsigned long flags;
+
+ x = (x > 0) ? x : 0;
+ y = (y > 0) ? y : 0;
+
+ /*
+ * Cursor Region Of Interest (ROI) is a plane read from cursor
+ * buffer to render. The ROI region is determined by the visiblity of
+ * the cursor point. In the default Cursor image the cursor point will
+ * be at the top left of the cursor image, unless it is specified
+ * otherwise using hotspot feature.
+ *
+ * If the cursor point reaches the right (xres - x < cursor.width) or
+ * bottom (yres - y < cursor.height) boundary of the screen, then ROI
+ * width and ROI height need to be evaluated to crop the cursor image
+ * accordingly.
+ * (xres-x) will be new cursor width when x > (xres - cursor.width)
+ * (yres-y) will be new cursor height when y > (yres - cursor.height)
+ */
+ roi_w = min(mdp5_crtc->cursor.width, xres - x);
+ roi_h = min(mdp5_crtc->cursor.height, yres - y);
+
+ spin_lock_irqsave(&mdp5_crtc->cursor.lock, flags);
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_SIZE(mdp5_crtc->lm),
+ MDP5_LM_CURSOR_SIZE_ROI_H(roi_h) |
+ MDP5_LM_CURSOR_SIZE_ROI_W(roi_w));
+ mdp5_write(mdp5_kms, REG_MDP5_LM_CURSOR_START_XY(mdp5_crtc->lm),
+ MDP5_LM_CURSOR_START_XY_Y_START(y) |
+ MDP5_LM_CURSOR_START_XY_X_START(x));
+ spin_unlock_irqrestore(&mdp5_crtc->cursor.lock, flags);
+
+ crtc_flush(crtc, flush_mask);
+
+ return 0;
+}
+
static const struct drm_crtc_funcs mdp5_crtc_funcs = {
.set_config = drm_atomic_helper_set_config,
.destroy = mdp5_crtc_destroy,
@@ -392,17 +537,15 @@ static const struct drm_crtc_funcs mdp5_crtc_funcs = {
.reset = drm_atomic_helper_crtc_reset,
.atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
.atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
+ .cursor_set = mdp5_crtc_cursor_set,
+ .cursor_move = mdp5_crtc_cursor_move,
};
static const struct drm_crtc_helper_funcs mdp5_crtc_helper_funcs = {
- .dpms = mdp5_crtc_dpms,
.mode_fixup = mdp5_crtc_mode_fixup,
.mode_set_nofb = mdp5_crtc_mode_set_nofb,
- .mode_set = drm_helper_crtc_mode_set,
- .mode_set_base = drm_helper_crtc_mode_set_base,
- .prepare = mdp5_crtc_prepare,
- .commit = mdp5_crtc_commit,
- .load_lut = mdp5_crtc_load_lut,
+ .prepare = mdp5_crtc_disable,
+ .commit = mdp5_crtc_enable,
.atomic_check = mdp5_crtc_atomic_check,
.atomic_begin = mdp5_crtc_atomic_begin,
.atomic_flush = mdp5_crtc_atomic_flush,
@@ -412,6 +555,7 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
{
struct mdp5_crtc *mdp5_crtc = container_of(irq, struct mdp5_crtc, vblank);
struct drm_crtc *crtc = &mdp5_crtc->base;
+ struct msm_drm_private *priv = crtc->dev->dev_private;
unsigned pending;
mdp_irq_unregister(&get_kms(crtc)->base, &mdp5_crtc->vblank);
@@ -421,6 +565,9 @@ static void mdp5_crtc_vblank_irq(struct mdp_irq *irq, uint32_t irqstatus)
if (pending & PENDING_FLIP) {
complete_flip(crtc, NULL);
}
+
+ if (pending & PENDING_CURSOR)
+ drm_flip_work_commit(&mdp5_crtc->unref_cursor_work, priv->wq);
}
static void mdp5_crtc_err_irq(struct mdp_irq *irq, uint32_t irqstatus)
@@ -520,6 +667,7 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
mdp5_crtc->lm = GET_LM_ID(id);
spin_lock_init(&mdp5_crtc->lm_lock);
+ spin_lock_init(&mdp5_crtc->cursor.lock);
mdp5_crtc->vblank.irq = mdp5_crtc_vblank_irq;
mdp5_crtc->err.irq = mdp5_crtc_err_irq;
@@ -528,6 +676,10 @@ struct drm_crtc *mdp5_crtc_init(struct drm_device *dev,
pipe2name(mdp5_plane_pipe(plane)), id);
drm_crtc_init_with_planes(dev, crtc, plane, NULL, &mdp5_crtc_funcs);
+
+ drm_flip_work_init(&mdp5_crtc->unref_cursor_work,
+ "unref cursor", unref_cursor_worker);
+
drm_crtc_helper_add(crtc, &mdp5_crtc_helper_funcs);
plane->crtc = crtc;
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
index dea4505ac963..151129032d16 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.c
@@ -95,7 +95,7 @@ u32 ctl_read(struct mdp5_ctl *ctl, u32 reg)
}
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf)
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf)
{
unsigned long flags;
static const enum mdp5_intfnum intfnum[] = {
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
index 1018519b6af2..ad48788efeea 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_ctl.h
@@ -34,7 +34,7 @@ void mdp5_ctlm_destroy(struct mdp5_ctl_manager *ctlm);
*/
struct mdp5_ctl *mdp5_ctlm_request(struct mdp5_ctl_manager *ctlm, struct drm_crtc *crtc);
-int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, enum mdp5_intf intf);
+int mdp5_ctl_set_intf(struct mdp5_ctl *ctl, int intf);
int mdp5_ctl_set_cursor(struct mdp5_ctl *ctl, bool enable);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
index 0254bfdeb92f..d6a14bb99988 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_encoder.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -110,45 +111,6 @@ static const struct drm_encoder_funcs mdp5_encoder_funcs = {
.destroy = mdp5_encoder_destroy,
};
-static void mdp5_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
- struct mdp5_kms *mdp5_kms = get_kms(encoder);
- int intf = mdp5_encoder->intf;
- bool enabled = (mode == DRM_MODE_DPMS_ON);
- unsigned long flags;
-
- DBG("mode=%d", mode);
-
- if (enabled == mdp5_encoder->enabled)
- return;
-
- if (enabled) {
- bs_set(mdp5_encoder, 1);
- spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
- mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
- spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
- } else {
- spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
- mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
- spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
-
- /*
- * Wait for a vsync so we know the ENABLE=0 latched before
- * the (connector) source of the vsync's gets disabled,
- * otherwise we end up in a funny state if we re-enable
- * before the disable latches, which results that some of
- * the settings changes for the new modeset (like new
- * scanout buffer) don't latch properly..
- */
- mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
-
- bs_set(mdp5_encoder, 0);
- }
-
- mdp5_encoder->enabled = enabled;
-}
-
static bool mdp5_encoder_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
@@ -162,11 +124,13 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
struct mdp5_kms *mdp5_kms = get_kms(encoder);
+ struct drm_device *dev = encoder->dev;
+ struct drm_connector *connector;
int intf = mdp5_encoder->intf;
uint32_t dtv_hsync_skew, vsync_period, vsync_len, ctrl_pol;
uint32_t display_v_start, display_v_end;
uint32_t hsync_start_x, hsync_end_x;
- uint32_t format;
+ uint32_t format = 0x2100;
unsigned long flags;
mode = adjusted_mode;
@@ -188,7 +152,28 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
/* probably need to get DATA_EN polarity from panel.. */
dtv_hsync_skew = 0; /* get this from panel? */
- format = 0x213f; /* get this from panel? */
+
+ /* Get color format from panel, default is 8bpc */
+ list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ switch (connector->display_info.bpc) {
+ case 4:
+ format |= 0;
+ break;
+ case 5:
+ format |= 0x15;
+ break;
+ case 6:
+ format |= 0x2A;
+ break;
+ case 8:
+ default:
+ format |= 0x3F;
+ break;
+ }
+ break;
+ }
+ }
hsync_start_x = (mode->htotal - mode->hsync_start);
hsync_end_x = mode->htotal - (mode->hsync_start - mode->hdisplay) - 1;
@@ -198,6 +183,16 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
display_v_start = (mode->vtotal - mode->vsync_start) * mode->htotal + dtv_hsync_skew;
display_v_end = vsync_period - ((mode->vsync_start - mode->vdisplay) * mode->htotal) + dtv_hsync_skew - 1;
+ /*
+ * For edp only:
+ * DISPLAY_V_START = (VBP * HCYCLE) + HBP
+ * DISPLAY_V_END = (VBP + VACTIVE) * HCYCLE - 1 - HFP
+ */
+ if (mdp5_encoder->intf_id == INTF_eDP) {
+ display_v_start += mode->htotal - mode->hsync_start;
+ display_v_end -= mode->hsync_start - mode->hdisplay;
+ }
+
spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
mdp5_write(mdp5_kms, REG_MDP5_INTF_HSYNC_CTL(intf),
@@ -225,25 +220,61 @@ static void mdp5_encoder_mode_set(struct drm_encoder *encoder,
spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
}
-static void mdp5_encoder_prepare(struct drm_encoder *encoder)
+static void mdp5_encoder_disable(struct drm_encoder *encoder)
{
- mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
+ struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_kms *mdp5_kms = get_kms(encoder);
+ int intf = mdp5_encoder->intf;
+ unsigned long flags;
+
+ if (WARN_ON(!mdp5_encoder->enabled))
+ return;
+
+ spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+ mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 0);
+ spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+ /*
+ * Wait for a vsync so we know the ENABLE=0 latched before
+ * the (connector) source of the vsync's gets disabled,
+ * otherwise we end up in a funny state if we re-enable
+ * before the disable latches, which results that some of
+ * the settings changes for the new modeset (like new
+ * scanout buffer) don't latch properly..
+ */
+ mdp_irq_wait(&mdp5_kms->base, intf2vblank(intf));
+
+ bs_set(mdp5_encoder, 0);
+
+ mdp5_encoder->enabled = false;
}
-static void mdp5_encoder_commit(struct drm_encoder *encoder)
+static void mdp5_encoder_enable(struct drm_encoder *encoder)
{
struct mdp5_encoder *mdp5_encoder = to_mdp5_encoder(encoder);
+ struct mdp5_kms *mdp5_kms = get_kms(encoder);
+ int intf = mdp5_encoder->intf;
+ unsigned long flags;
+
+ if (WARN_ON(mdp5_encoder->enabled))
+ return;
+
mdp5_crtc_set_intf(encoder->crtc, mdp5_encoder->intf,
mdp5_encoder->intf_id);
- mdp5_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
+
+ bs_set(mdp5_encoder, 1);
+ spin_lock_irqsave(&mdp5_encoder->intf_lock, flags);
+ mdp5_write(mdp5_kms, REG_MDP5_INTF_TIMING_ENGINE_EN(intf), 1);
+ spin_unlock_irqrestore(&mdp5_encoder->intf_lock, flags);
+
+ mdp5_encoder->enabled = false;
}
static const struct drm_encoder_helper_funcs mdp5_encoder_helper_funcs = {
- .dpms = mdp5_encoder_dpms,
.mode_fixup = mdp5_encoder_mode_fixup,
.mode_set = mdp5_encoder_mode_set,
- .prepare = mdp5_encoder_prepare,
- .commit = mdp5_encoder_commit,
+ .prepare = mdp5_encoder_disable,
+ .commit = mdp5_encoder_enable,
};
/* initialize encoder */
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
index 9f01a4f21af2..92b61db5754c 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.c
@@ -68,6 +68,18 @@ static int mdp5_hw_init(struct msm_kms *kms)
return 0;
}
+static void mdp5_prepare_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+ struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+ mdp5_enable(mdp5_kms);
+}
+
+static void mdp5_complete_commit(struct msm_kms *kms, struct drm_atomic_state *state)
+{
+ struct mdp5_kms *mdp5_kms = to_mdp5_kms(to_mdp_kms(kms));
+ mdp5_disable(mdp5_kms);
+}
+
static long mdp5_round_pixclk(struct msm_kms *kms, unsigned long rate,
struct drm_encoder *encoder)
{
@@ -115,6 +127,8 @@ static const struct mdp_kms_funcs kms_funcs = {
.irq = mdp5_irq,
.enable_vblank = mdp5_enable_vblank,
.disable_vblank = mdp5_disable_vblank,
+ .prepare_commit = mdp5_prepare_commit,
+ .complete_commit = mdp5_complete_commit,
.get_format = mdp_get_format,
.round_pixclk = mdp5_round_pixclk,
.preclose = mdp5_preclose,
@@ -208,19 +222,18 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
}
}
- /* Construct encoder for HDMI: */
- encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
- if (IS_ERR(encoder)) {
- dev_err(dev->dev, "failed to construct encoder\n");
- ret = PTR_ERR(encoder);
- goto fail;
- }
+ if (priv->hdmi) {
+ /* Construct encoder for HDMI: */
+ encoder = mdp5_encoder_init(dev, 3, INTF_HDMI);
+ if (IS_ERR(encoder)) {
+ dev_err(dev->dev, "failed to construct encoder\n");
+ ret = PTR_ERR(encoder);
+ goto fail;
+ }
- encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
- priv->encoders[priv->num_encoders++] = encoder;
+ encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;;
+ priv->encoders[priv->num_encoders++] = encoder;
- /* Construct bridge/connector for HDMI: */
- if (priv->hdmi) {
ret = hdmi_modeset_init(priv->hdmi, dev, encoder);
if (ret) {
dev_err(dev->dev, "failed to initialize HDMI: %d\n", ret);
@@ -228,6 +241,27 @@ static int modeset_init(struct mdp5_kms *mdp5_kms)
}
}
+ if (priv->edp) {
+ /* Construct encoder for eDP: */
+ encoder = mdp5_encoder_init(dev, 0, INTF_eDP);
+ if (IS_ERR(encoder)) {
+ dev_err(dev->dev, "failed to construct eDP encoder\n");
+ ret = PTR_ERR(encoder);
+ goto fail;
+ }
+
+ encoder->possible_crtcs = (1 << priv->num_crtcs) - 1;
+ priv->encoders[priv->num_encoders++] = encoder;
+
+ /* Construct bridge/connector for eDP: */
+ ret = msm_edp_modeset_init(priv->edp, dev, encoder);
+ if (ret) {
+ dev_err(dev->dev, "failed to initialize eDP: %d\n",
+ ret);
+ goto fail;
+ }
+ }
+
return 0;
fail:
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
index dd69c77c0d64..49d011e8835b 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_kms.h
@@ -165,14 +165,25 @@ void mdp5_disable_vblank(struct msm_kms *kms, struct drm_crtc *crtc);
int mdp5_irq_domain_init(struct mdp5_kms *mdp5_kms);
void mdp5_irq_domain_fini(struct mdp5_kms *mdp5_kms);
+static inline bool pipe_supports_yuv(enum mdp5_pipe pipe)
+{
+ switch (pipe) {
+ case SSPP_VIG0:
+ case SSPP_VIG1:
+ case SSPP_VIG2:
+ case SSPP_VIG3:
+ return true;
+ default:
+ return false;
+ }
+}
+
static inline
uint32_t mdp5_get_formats(enum mdp5_pipe pipe, uint32_t *pixel_formats,
uint32_t max_formats)
{
- /* TODO when we have YUV, we need to filter supported formats
- * based on pipe id..
- */
- return mdp_get_formats(pixel_formats, max_formats);
+ return mdp_get_formats(pixel_formats, max_formats,
+ !pipe_supports_yuv(pipe));
}
void mdp5_plane_install_properties(struct drm_plane *plane,
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
index 26e5fdea6594..05cf9ab2a876 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_plane.c
@@ -18,8 +18,6 @@
#include "mdp5_kms.h"
-#define MAX_PLANE 4
-
struct mdp5_plane {
struct drm_plane base;
const char *name;
@@ -113,6 +111,7 @@ static void mdp5_plane_reset(struct drm_plane *plane)
} else {
mdp5_state->zpos = 1 + drm_plane_index(plane);
}
+ mdp5_state->base.plane = plane;
plane->state = &mdp5_state->base;
}
@@ -277,6 +276,155 @@ static void set_scanout_locked(struct drm_plane *plane,
plane->fb = fb;
}
+/* Note: mdp5_plane->pipe_lock must be locked */
+static void csc_disable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe)
+{
+ uint32_t value = mdp5_read(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe)) &
+ ~MDP5_PIPE_OP_MODE_CSC_1_EN;
+
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), value);
+}
+
+/* Note: mdp5_plane->pipe_lock must be locked */
+static void csc_enable(struct mdp5_kms *mdp5_kms, enum mdp5_pipe pipe,
+ struct csc_cfg *csc)
+{
+ uint32_t i, mode = 0; /* RGB, no CSC */
+ uint32_t *matrix;
+
+ if (unlikely(!csc))
+ return;
+
+ if ((csc->type == CSC_YUV2RGB) || (CSC_YUV2YUV == csc->type))
+ mode |= MDP5_PIPE_OP_MODE_CSC_SRC_DATA_FORMAT(DATA_FORMAT_YUV);
+ if ((csc->type == CSC_RGB2YUV) || (CSC_YUV2YUV == csc->type))
+ mode |= MDP5_PIPE_OP_MODE_CSC_DST_DATA_FORMAT(DATA_FORMAT_YUV);
+ mode |= MDP5_PIPE_OP_MODE_CSC_1_EN;
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_OP_MODE(pipe), mode);
+
+ matrix = csc->matrix;
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_0(pipe),
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_11(matrix[0]) |
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_0_COEFF_12(matrix[1]));
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_1(pipe),
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_13(matrix[2]) |
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_1_COEFF_21(matrix[3]));
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_2(pipe),
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_22(matrix[4]) |
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_2_COEFF_23(matrix[5]));
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_3(pipe),
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_31(matrix[6]) |
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_3_COEFF_32(matrix[7]));
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_MATRIX_COEFF_4(pipe),
+ MDP5_PIPE_CSC_1_MATRIX_COEFF_4_COEFF_33(matrix[8]));
+
+ for (i = 0; i < ARRAY_SIZE(csc->pre_bias); i++) {
+ uint32_t *pre_clamp = csc->pre_clamp;
+ uint32_t *post_clamp = csc->post_clamp;
+
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_CLAMP(pipe, i),
+ MDP5_PIPE_CSC_1_PRE_CLAMP_REG_HIGH(pre_clamp[2*i+1]) |
+ MDP5_PIPE_CSC_1_PRE_CLAMP_REG_LOW(pre_clamp[2*i]));
+
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_CLAMP(pipe, i),
+ MDP5_PIPE_CSC_1_POST_CLAMP_REG_HIGH(post_clamp[2*i+1]) |
+ MDP5_PIPE_CSC_1_POST_CLAMP_REG_LOW(post_clamp[2*i]));
+
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_PRE_BIAS(pipe, i),
+ MDP5_PIPE_CSC_1_PRE_BIAS_REG_VALUE(csc->pre_bias[i]));
+
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_CSC_1_POST_BIAS(pipe, i),
+ MDP5_PIPE_CSC_1_POST_BIAS_REG_VALUE(csc->post_bias[i]));
+ }
+}
+
+#define PHASE_STEP_SHIFT 21
+#define DOWN_SCALE_RATIO_MAX 32 /* 2^(26-21) */
+
+static int calc_phase_step(uint32_t src, uint32_t dst, uint32_t *out_phase)
+{
+ uint32_t unit;
+
+ if (src == 0 || dst == 0)
+ return -EINVAL;
+
+ /*
+ * PHASE_STEP_X/Y is coded on 26 bits (25:0),
+ * where 2^21 represents the unity "1" in fixed-point hardware design.
+ * This leaves 5 bits for the integer part (downscale case):
+ * -> maximum downscale ratio = 0b1_1111 = 31
+ */
+ if (src > (dst * DOWN_SCALE_RATIO_MAX))
+ return -EOVERFLOW;
+
+ unit = 1 << PHASE_STEP_SHIFT;
+ *out_phase = mult_frac(unit, src, dst);
+
+ return 0;
+}
+
+static int calc_scalex_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
+ uint32_t phasex_steps[2])
+{
+ uint32_t phasex_step;
+ unsigned int hsub;
+ int ret;
+
+ ret = calc_phase_step(src, dest, &phasex_step);
+ if (ret)
+ return ret;
+
+ hsub = drm_format_horz_chroma_subsampling(pixel_format);
+
+ phasex_steps[0] = phasex_step;
+ phasex_steps[1] = phasex_step / hsub;
+
+ return 0;
+}
+
+static int calc_scaley_steps(uint32_t pixel_format, uint32_t src, uint32_t dest,
+ uint32_t phasey_steps[2])
+{
+ uint32_t phasey_step;
+ unsigned int vsub;
+ int ret;
+
+ ret = calc_phase_step(src, dest, &phasey_step);
+ if (ret)
+ return ret;
+
+ vsub = drm_format_vert_chroma_subsampling(pixel_format);
+
+ phasey_steps[0] = phasey_step;
+ phasey_steps[1] = phasey_step / vsub;
+
+ return 0;
+}
+
+static uint32_t get_scalex_config(uint32_t src, uint32_t dest)
+{
+ uint32_t filter;
+
+ filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+
+ return MDP5_PIPE_SCALE_CONFIG_SCALEX_EN |
+ MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(filter) |
+ MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(filter) |
+ MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(filter);
+}
+
+static uint32_t get_scaley_config(uint32_t src, uint32_t dest)
+{
+ uint32_t filter;
+
+ filter = (src <= dest) ? SCALE_FILTER_BIL : SCALE_FILTER_PCMN;
+
+ return MDP5_PIPE_SCALE_CONFIG_SCALEY_EN |
+ MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(filter) |
+ MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(filter) |
+ MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(filter);
+}
+
static int mdp5_plane_mode_set(struct drm_plane *plane,
struct drm_crtc *crtc, struct drm_framebuffer *fb,
int crtc_x, int crtc_y,
@@ -286,11 +434,14 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
{
struct mdp5_plane *mdp5_plane = to_mdp5_plane(plane);
struct mdp5_kms *mdp5_kms = get_kms(plane);
+ struct device *dev = mdp5_kms->dev->dev;
enum mdp5_pipe pipe = mdp5_plane->pipe;
const struct mdp_format *format;
uint32_t nplanes, config = 0;
- uint32_t phasex_step = 0, phasey_step = 0;
+ /* below array -> index 0: comp 0/3 ; index 1: comp 1/2 */
+ uint32_t phasex_step[2] = {0,}, phasey_step[2] = {0,};
uint32_t hdecm = 0, vdecm = 0;
+ uint32_t pix_format;
unsigned long flags;
int ret;
@@ -300,6 +451,9 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
if (WARN_ON(nplanes > pipe2nclients(pipe)))
return -EINVAL;
+ format = to_mdp_format(msm_framebuffer_format(fb));
+ pix_format = format->base.pixel_format;
+
/* src values are in Q16 fixed point, convert to integer: */
src_x = src_x >> 16;
src_y = src_y >> 16;
@@ -324,14 +478,28 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
*/
mdp5_smp_configure(mdp5_kms->smp, pipe);
- if (src_w != crtc_w) {
- config |= MDP5_PIPE_SCALE_CONFIG_SCALEX_EN;
- /* TODO calc phasex_step, hdecm */
+ /* SCALE is used to both scale and up-sample chroma components */
+
+ if ((src_w != crtc_w) || MDP_FORMAT_IS_YUV(format)) {
+ /* TODO calc hdecm */
+ ret = calc_scalex_steps(pix_format, src_w, crtc_w, phasex_step);
+ if (ret) {
+ dev_err(dev, "X scaling (%d -> %d) failed: %d\n",
+ src_w, crtc_w, ret);
+ return ret;
+ }
+ config |= get_scalex_config(src_w, crtc_w);
}
- if (src_h != crtc_h) {
- config |= MDP5_PIPE_SCALE_CONFIG_SCALEY_EN;
- /* TODO calc phasey_step, vdecm */
+ if ((src_h != crtc_h) || MDP_FORMAT_IS_YUV(format)) {
+ /* TODO calc vdecm */
+ ret = calc_scaley_steps(pix_format, src_h, crtc_h, phasey_step);
+ if (ret) {
+ dev_err(dev, "Y scaling (%d -> %d) failed: %d\n",
+ src_h, crtc_h, ret);
+ return ret;
+ }
+ config |= get_scaley_config(src_h, crtc_h);
}
spin_lock_irqsave(&mdp5_plane->pipe_lock, flags);
@@ -356,8 +524,6 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
MDP5_PIPE_OUT_XY_X(crtc_x) |
MDP5_PIPE_OUT_XY_Y(crtc_y));
- format = to_mdp_format(msm_framebuffer_format(fb));
-
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_FORMAT(pipe),
MDP5_PIPE_SRC_FORMAT_A_BPC(format->bpc_a) |
MDP5_PIPE_SRC_FORMAT_R_BPC(format->bpc_r) |
@@ -367,8 +533,8 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
MDP5_PIPE_SRC_FORMAT_CPP(format->cpp - 1) |
MDP5_PIPE_SRC_FORMAT_UNPACK_COUNT(format->unpack_count - 1) |
COND(format->unpack_tight, MDP5_PIPE_SRC_FORMAT_UNPACK_TIGHT) |
- MDP5_PIPE_SRC_FORMAT_NUM_PLANES(nplanes - 1) |
- MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(CHROMA_RGB));
+ MDP5_PIPE_SRC_FORMAT_NUM_PLANES(format->fetch_type) |
+ MDP5_PIPE_SRC_FORMAT_CHROMA_SAMP(format->chroma_sample));
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_UNPACK(pipe),
MDP5_PIPE_SRC_UNPACK_ELEM0(format->unpack[0]) |
@@ -382,18 +548,24 @@ static int mdp5_plane_mode_set(struct drm_plane *plane,
/* not using secure mode: */
mdp5_write(mdp5_kms, REG_MDP5_PIPE_SRC_ADDR_SW_STATUS(pipe), 0);
- mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe), phasex_step);
- mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe), phasey_step);
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_X(pipe),
+ phasex_step[0]);
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_PHASE_STEP_Y(pipe),
+ phasey_step[0]);
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_X(pipe),
+ phasex_step[1]);
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CR_PHASE_STEP_Y(pipe),
+ phasey_step[1]);
mdp5_write(mdp5_kms, REG_MDP5_PIPE_DECIMATION(pipe),
MDP5_PIPE_DECIMATION_VERT(vdecm) |
MDP5_PIPE_DECIMATION_HORZ(hdecm));
- mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe),
- MDP5_PIPE_SCALE_CONFIG_SCALEX_MIN_FILTER(SCALE_FILTER_NEAREST) |
- MDP5_PIPE_SCALE_CONFIG_SCALEY_MIN_FILTER(SCALE_FILTER_NEAREST) |
- MDP5_PIPE_SCALE_CONFIG_SCALEX_CR_FILTER(SCALE_FILTER_NEAREST) |
- MDP5_PIPE_SCALE_CONFIG_SCALEY_CR_FILTER(SCALE_FILTER_NEAREST) |
- MDP5_PIPE_SCALE_CONFIG_SCALEX_MAX_FILTER(SCALE_FILTER_NEAREST) |
- MDP5_PIPE_SCALE_CONFIG_SCALEY_MAX_FILTER(SCALE_FILTER_NEAREST));
+ mdp5_write(mdp5_kms, REG_MDP5_PIPE_SCALE_CONFIG(pipe), config);
+
+ if (MDP_FORMAT_IS_YUV(format))
+ csc_enable(mdp5_kms, pipe,
+ mdp_get_default_csc_cfg(CSC_YUV2RGB));
+ else
+ csc_disable(mdp5_kms, pipe);
set_scanout_locked(plane, fb);
diff --git a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
index bf551885e019..1f795af89680 100644
--- a/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
+++ b/drivers/gpu/drm/msm/mdp/mdp5/mdp5_smp.c
@@ -119,9 +119,10 @@ static int smp_request_block(struct mdp5_smp *smp,
spin_lock_irqsave(&smp->state_lock, flags);
- nblks -= reserved;
- if (reserved)
+ if (reserved) {
+ nblks = max(0, nblks - reserved);
DBG("%d MMBs allocated (%d reserved)", nblks, reserved);
+ }
avail = cnt - bitmap_weight(smp->state, cnt);
if (nblks > avail) {
diff --git a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
index 64c1afd6030a..a1d35f162c7f 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
+++ b/drivers/gpu/drm/msm/mdp/mdp_common.xml.h
@@ -8,18 +8,19 @@ http://github.com/freedreno/envytools/
git clone https://github.com/freedreno/envytools.git
The rules-ng-ng source files this header was generated from are:
-- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 647 bytes, from 2013-11-30 14:45:35)
+- /home/robclark/src/freedreno/envytools/rnndb/msm.xml ( 676 bytes, from 2014-12-05 15:34:49)
- /home/robclark/src/freedreno/envytools/rnndb/freedreno_copyright.xml ( 1453 bytes, from 2013-03-31 16:51:27)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 17996 bytes, from 2013-12-01 19:10:31)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 1615 bytes, from 2013-11-30 15:00:52)
-- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 22517 bytes, from 2014-06-25 12:55:02)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp4.xml ( 20908 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp_common.xml ( 2357 bytes, from 2014-12-08 16:13:00)
+- /home/robclark/src/freedreno/envytools/rnndb/mdp/mdp5.xml ( 27208 bytes, from 2015-01-13 23:56:11)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/dsi.xml ( 11712 bytes, from 2013-08-17 17:13:43)
- /home/robclark/src/freedreno/envytools/rnndb/dsi/sfpb.xml ( 344 bytes, from 2013-08-11 19:26:32)
-- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1544 bytes, from 2013-08-16 19:17:05)
+- /home/robclark/src/freedreno/envytools/rnndb/dsi/mmss_cc.xml ( 1686 bytes, from 2014-10-31 16:48:57)
- /home/robclark/src/freedreno/envytools/rnndb/hdmi/qfprom.xml ( 600 bytes, from 2013-07-05 19:21:12)
-- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 23613 bytes, from 2014-06-25 12:53:44)
+- /home/robclark/src/freedreno/envytools/rnndb/hdmi/hdmi.xml ( 26848 bytes, from 2015-01-13 23:55:57)
+- /home/robclark/src/freedreno/envytools/rnndb/edp/edp.xml ( 8253 bytes, from 2014-12-08 16:13:00)
-Copyright (C) 2013 by the following authors:
+Copyright (C) 2013-2014 by the following authors:
- Rob Clark <robdclark@gmail.com> (robclark)
Permission is hereby granted, free of charge, to any person obtaining
@@ -44,6 +45,19 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+enum mdp_chroma_samp_type {
+ CHROMA_RGB = 0,
+ CHROMA_H2V1 = 1,
+ CHROMA_H1V2 = 2,
+ CHROMA_420 = 3,
+};
+
+enum mdp_sspp_fetch_type {
+ MDP_PLANE_INTERLEAVED = 0,
+ MDP_PLANE_PLANAR = 1,
+ MDP_PLANE_PSEUDO_PLANAR = 2,
+};
+
enum mdp_mixer_stage_id {
STAGE_UNUSED = 0,
STAGE_BASE = 1,
diff --git a/drivers/gpu/drm/msm/mdp/mdp_format.c b/drivers/gpu/drm/msm/mdp/mdp_format.c
index e0a6ffbe6ab4..f683433b6727 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_format.c
+++ b/drivers/gpu/drm/msm/mdp/mdp_format.c
@@ -1,4 +1,5 @@
/*
+ * Copyright (c) 2014 The Linux Foundation. All rights reserved.
* Copyright (C) 2013 Red Hat
* Author: Rob Clark <robdclark@gmail.com>
*
@@ -19,7 +20,58 @@
#include "msm_drv.h"
#include "mdp_kms.h"
-#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt) { \
+static struct csc_cfg csc_convert[CSC_MAX] = {
+ [CSC_RGB2RGB] = {
+ .type = CSC_RGB2RGB,
+ .matrix = {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200
+ },
+ .pre_bias = { 0x0, 0x0, 0x0 },
+ .post_bias = { 0x0, 0x0, 0x0 },
+ .pre_clamp = { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff },
+ .post_clamp = { 0x0, 0xff, 0x0, 0xff, 0x0, 0xff },
+ },
+ [CSC_YUV2RGB] = {
+ .type = CSC_YUV2RGB,
+ .matrix = {
+ 0x0254, 0x0000, 0x0331,
+ 0x0254, 0xff37, 0xfe60,
+ 0x0254, 0x0409, 0x0000
+ },
+ .pre_bias = { 0xfff0, 0xff80, 0xff80 },
+ .post_bias = { 0x00, 0x00, 0x00 },
+ .pre_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+ .post_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+ },
+ [CSC_RGB2YUV] = {
+ .type = CSC_RGB2YUV,
+ .matrix = {
+ 0x0083, 0x0102, 0x0032,
+ 0x1fb5, 0x1f6c, 0x00e1,
+ 0x00e1, 0x1f45, 0x1fdc
+ },
+ .pre_bias = { 0x00, 0x00, 0x00 },
+ .post_bias = { 0x10, 0x80, 0x80 },
+ .pre_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+ .post_clamp = { 0x10, 0xeb, 0x10, 0xf0, 0x10, 0xf0 },
+ },
+ [CSC_YUV2YUV] = {
+ .type = CSC_YUV2YUV,
+ .matrix = {
+ 0x0200, 0x0000, 0x0000,
+ 0x0000, 0x0200, 0x0000,
+ 0x0000, 0x0000, 0x0200
+ },
+ .pre_bias = { 0x00, 0x00, 0x00 },
+ .post_bias = { 0x00, 0x00, 0x00 },
+ .pre_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+ .post_clamp = { 0x00, 0xff, 0x00, 0xff, 0x00, 0xff },
+ },
+};
+
+#define FMT(name, a, r, g, b, e0, e1, e2, e3, alpha, tight, c, cnt, fp, cs) { \
.base = { .pixel_format = DRM_FORMAT_ ## name }, \
.bpc_a = BPC ## a ## A, \
.bpc_r = BPC ## r, \
@@ -30,21 +82,46 @@
.unpack_tight = tight, \
.cpp = c, \
.unpack_count = cnt, \
- }
+ .fetch_type = fp, \
+ .chroma_sample = cs \
+}
#define BPC0A 0
+/*
+ * Note: Keep RGB formats 1st, followed by YUV formats to avoid breaking
+ * mdp_get_rgb_formats()'s implementation.
+ */
static const struct mdp_format formats[] = {
- /* name a r g b e0 e1 e2 e3 alpha tight cpp cnt */
- FMT(ARGB8888, 8, 8, 8, 8, 1, 0, 2, 3, true, true, 4, 4),
- FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4),
- FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3),
- FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3),
- FMT(RGB565, 0, 5, 6, 5, 1, 0, 2, 0, false, true, 2, 3),
- FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3),
+ /* name a r g b e0 e1 e2 e3 alpha tight cpp cnt ... */
+ FMT(ARGB8888, 8, 8, 8, 8, 1, 0, 2, 3, true, true, 4, 4,
+ MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+ FMT(XRGB8888, 8, 8, 8, 8, 1, 0, 2, 3, false, true, 4, 4,
+ MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+ FMT(RGB888, 0, 8, 8, 8, 1, 0, 2, 0, false, true, 3, 3,
+ MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+ FMT(BGR888, 0, 8, 8, 8, 2, 0, 1, 0, false, true, 3, 3,
+ MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+ FMT(RGB565, 0, 5, 6, 5, 1, 0, 2, 0, false, true, 2, 3,
+ MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+ FMT(BGR565, 0, 5, 6, 5, 2, 0, 1, 0, false, true, 2, 3,
+ MDP_PLANE_INTERLEAVED, CHROMA_RGB),
+
+ /* --- RGB formats above / YUV formats below this line --- */
+
+ FMT(NV12, 0, 8, 8, 8, 1, 2, 0, 0, false, true, 2, 2,
+ MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
+ FMT(NV21, 0, 8, 8, 8, 2, 1, 0, 0, false, true, 2, 2,
+ MDP_PLANE_PSEUDO_PLANAR, CHROMA_420),
};
-uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats)
+/*
+ * Note:
+ * @rgb_only must be set to true, when requesting
+ * supported formats for RGB pipes.
+ */
+uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats,
+ bool rgb_only)
{
uint32_t i;
for (i = 0; i < ARRAY_SIZE(formats); i++) {
@@ -53,6 +130,9 @@ uint32_t mdp_get_formats(uint32_t *pixel_formats, uint32_t max_formats)
if (i == max_formats)
break;
+ if (rgb_only && MDP_FORMAT_IS_YUV(f))
+ break;
+
pixel_formats[i] = f->base.pixel_format;
}
@@ -69,3 +149,11 @@ const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format)
}
return NULL;
}
+
+struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type type)
+{
+ if (unlikely(WARN_ON(type >= CSC_MAX)))
+ return NULL;
+
+ return &csc_convert[type];
+}
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.c b/drivers/gpu/drm/msm/mdp/mdp_kms.c
index 2a731722d840..1988c243f437 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_kms.c
+++ b/drivers/gpu/drm/msm/mdp/mdp_kms.c
@@ -34,7 +34,7 @@ static void update_irq(struct mdp_kms *mdp_kms)
struct mdp_irq *irq;
uint32_t irqmask = mdp_kms->vblank_mask;
- BUG_ON(!spin_is_locked(&list_lock));
+ assert_spin_locked(&list_lock);
list_for_each_entry(irq, &mdp_kms->irq_list, node)
irqmask |= irq->irqmask;
diff --git a/drivers/gpu/drm/msm/mdp/mdp_kms.h b/drivers/gpu/drm/msm/mdp/mdp_kms.h
index b268ce95d394..5ae4039d68e4 100644
--- a/drivers/gpu/drm/msm/mdp/mdp_kms.h
+++ b/drivers/gpu/drm/msm/mdp/mdp_kms.h
@@ -88,10 +88,32 @@ struct mdp_format {
uint8_t unpack[4];
bool alpha_enable, unpack_tight;
uint8_t cpp, unpack_count;
+ enum mdp_sspp_fetch_type fetch_type;
+ enum mdp_chroma_samp_type chroma_sample;
};
#define to_mdp_format(x) container_of(x, struct mdp_format, base)
+#define MDP_FORMAT_IS_YUV(mdp_format) ((mdp_format)->chroma_sample > CHROMA_RGB)
-uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats);
+uint32_t mdp_get_formats(uint32_t *formats, uint32_t max_formats, bool rgb_only);
const struct msm_format *mdp_get_format(struct msm_kms *kms, uint32_t format);
+enum csc_type {
+ CSC_RGB2RGB = 0,
+ CSC_YUV2RGB,
+ CSC_RGB2YUV,
+ CSC_YUV2YUV,
+ CSC_MAX
+};
+
+struct csc_cfg {
+ enum csc_type type;
+ uint32_t matrix[9];
+ uint32_t pre_bias[3];
+ uint32_t post_bias[3];
+ uint32_t pre_clamp[6];
+ uint32_t post_clamp[6];
+};
+
+struct csc_cfg *mdp_get_default_csc_cfg(enum csc_type);
+
#endif /* __MDP_KMS_H__ */
diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c
index 191968256c58..871aa2108dc6 100644
--- a/drivers/gpu/drm/msm/msm_atomic.c
+++ b/drivers/gpu/drm/msm/msm_atomic.c
@@ -20,6 +20,7 @@
#include "msm_gem.h"
struct msm_commit {
+ struct drm_device *dev;
struct drm_atomic_state *state;
uint32_t fence;
struct msm_fence_cb fence_cb;
@@ -58,14 +59,16 @@ static void end_atomic(struct msm_drm_private *priv, uint32_t crtc_mask)
spin_unlock(&priv->pending_crtcs_event.lock);
}
-static struct msm_commit *new_commit(struct drm_atomic_state *state)
+static struct msm_commit *commit_init(struct drm_atomic_state *state)
{
struct msm_commit *c = kzalloc(sizeof(*c), GFP_KERNEL);
if (!c)
return NULL;
+ c->dev = state->dev;
c->state = state;
+
/* TODO we might need a way to indicate to run the cb on a
* different wq so wait_for_vblanks() doesn't block retiring
* bo's..
@@ -75,6 +78,12 @@ static struct msm_commit *new_commit(struct drm_atomic_state *state)
return c;
}
+static void commit_destroy(struct msm_commit *c)
+{
+ end_atomic(c->dev->dev_private, c->crtc_mask);
+ kfree(c);
+}
+
/* The (potentially) asynchronous part of the commit. At this point
* nothing can fail short of armageddon.
*/
@@ -82,6 +91,10 @@ static void complete_commit(struct msm_commit *c)
{
struct drm_atomic_state *state = c->state;
struct drm_device *dev = state->dev;
+ struct msm_drm_private *priv = dev->dev_private;
+ struct msm_kms *kms = priv->kms;
+
+ kms->funcs->prepare_commit(kms, state);
drm_atomic_helper_commit_pre_planes(dev, state);
@@ -106,11 +119,11 @@ static void complete_commit(struct msm_commit *c)
drm_atomic_helper_cleanup_planes(dev, state);
- drm_atomic_state_free(state);
+ kms->funcs->complete_commit(kms, state);
- end_atomic(dev->dev_private, c->crtc_mask);
+ drm_atomic_state_free(state);
- kfree(c);
+ commit_destroy(c);
}
static void fence_cb(struct msm_fence_cb *cb)
@@ -127,6 +140,26 @@ static void add_fb(struct msm_commit *c, struct drm_framebuffer *fb)
}
+int msm_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state)
+{
+ int ret;
+
+ /*
+ * msm ->atomic_check can update ->mode_changed for pixel format
+ * changes, hence must be run before we check the modeset changes.
+ */
+ ret = drm_atomic_helper_check_planes(dev, state);
+ if (ret)
+ return ret;
+
+ ret = drm_atomic_helper_check_modeset(dev, state);
+ if (ret)
+ return ret;
+
+ return ret;
+}
+
/**
* drm_atomic_helper_commit - commit validated state object
* @dev: DRM device
@@ -145,6 +178,7 @@ int msm_atomic_commit(struct drm_device *dev,
{
int nplanes = dev->mode_config.num_total_plane;
int ncrtcs = dev->mode_config.num_crtc;
+ struct timespec timeout;
struct msm_commit *c;
int i, ret;
@@ -152,7 +186,7 @@ int msm_atomic_commit(struct drm_device *dev,
if (ret)
return ret;
- c = new_commit(state);
+ c = commit_init(state);
if (!c)
return -ENOMEM;
@@ -217,10 +251,12 @@ int msm_atomic_commit(struct drm_device *dev,
return 0;
}
- ret = msm_wait_fence_interruptable(dev, c->fence, NULL);
+ jiffies_to_timespec(jiffies + msecs_to_jiffies(1000), &timeout);
+
+ ret = msm_wait_fence_interruptable(dev, c->fence, &timeout);
if (ret) {
WARN_ON(ret); // TODO unswap state back? or??
- kfree(c);
+ commit_destroy(c);
return ret;
}
diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c
index 9a61546a0b05..a4269119f9ea 100644
--- a/drivers/gpu/drm/msm/msm_drv.c
+++ b/drivers/gpu/drm/msm/msm_drv.c
@@ -29,7 +29,7 @@ static void msm_fb_output_poll_changed(struct drm_device *dev)
static const struct drm_mode_config_funcs mode_config_funcs = {
.fb_create = msm_framebuffer_create,
.output_poll_changed = msm_fb_output_poll_changed,
- .atomic_check = drm_atomic_helper_check,
+ .atomic_check = msm_atomic_check,
.atomic_commit = msm_atomic_commit,
};
@@ -54,6 +54,12 @@ module_param(reglog, bool, 0600);
#define reglog 0
#endif
+#ifdef CONFIG_DRM_MSM_FBDEV
+static bool fbdev = true;
+MODULE_PARM_DESC(fbdev, "Enable fbdev compat layer");
+module_param(fbdev, bool, 0600);
+#endif
+
static char *vram = "16m";
MODULE_PARM_DESC(vram, "Configure VRAM size (for devices without IOMMU/GPUMMU");
module_param(vram, charp, 0);
@@ -300,7 +306,8 @@ static int msm_load(struct drm_device *dev, unsigned long flags)
drm_mode_config_reset(dev);
#ifdef CONFIG_DRM_MSM_FBDEV
- priv->fbdev = msm_fbdev_init(dev);
+ if (fbdev)
+ priv->fbdev = msm_fbdev_init(dev);
#endif
ret = msm_debugfs_late_init(dev);
@@ -1023,6 +1030,7 @@ static struct platform_driver msm_platform_driver = {
static int __init msm_drm_register(void)
{
DBG("init");
+ msm_edp_register();
hdmi_register();
adreno_register();
return platform_driver_register(&msm_platform_driver);
@@ -1034,6 +1042,7 @@ static void __exit msm_drm_unregister(void)
platform_driver_unregister(&msm_platform_driver);
hdmi_unregister();
adreno_unregister();
+ msm_edp_unregister();
}
module_init(msm_drm_register);
diff --git a/drivers/gpu/drm/msm/msm_drv.h b/drivers/gpu/drm/msm/msm_drv.h
index b69ef2d5a26c..9e8d441b61c3 100644
--- a/drivers/gpu/drm/msm/msm_drv.h
+++ b/drivers/gpu/drm/msm/msm_drv.h
@@ -76,6 +76,12 @@ struct msm_drm_private {
*/
struct hdmi *hdmi;
+ /* eDP is for mdp5 only, but kms has not been created
+ * when edp_bind() and edp_init() are called. Here is the only
+ * place to keep the edp instance.
+ */
+ struct msm_edp *edp;
+
/* when we have more than one 'msm_gpu' these need to be an array: */
struct msm_gpu *gpu;
struct msm_file_private *lastctx;
@@ -148,6 +154,8 @@ void __msm_fence_worker(struct work_struct *work);
(_cb)->func = _func; \
} while (0)
+int msm_atomic_check(struct drm_device *dev,
+ struct drm_atomic_state *state);
int msm_atomic_commit(struct drm_device *dev,
struct drm_atomic_state *state, bool async);
@@ -222,6 +230,12 @@ int hdmi_modeset_init(struct hdmi *hdmi, struct drm_device *dev,
void __init hdmi_register(void);
void __exit hdmi_unregister(void);
+struct msm_edp;
+void __init msm_edp_register(void);
+void __exit msm_edp_unregister(void);
+int msm_edp_modeset_init(struct msm_edp *edp, struct drm_device *dev,
+ struct drm_encoder *encoder);
+
#ifdef CONFIG_DEBUG_FS
void msm_gem_describe(struct drm_gem_object *obj, struct seq_file *m);
void msm_gem_describe_objects(struct list_head *list, struct seq_file *m);
diff --git a/drivers/gpu/drm/msm/msm_fb.c b/drivers/gpu/drm/msm/msm_fb.c
index 84dec161d836..6b573e612f27 100644
--- a/drivers/gpu/drm/msm/msm_fb.c
+++ b/drivers/gpu/drm/msm/msm_fb.c
@@ -24,7 +24,7 @@
struct msm_framebuffer {
struct drm_framebuffer base;
const struct msm_format *format;
- struct drm_gem_object *planes[3];
+ struct drm_gem_object *planes[MAX_PLANE];
};
#define to_msm_framebuffer(x) container_of(x, struct msm_framebuffer, base)
@@ -122,7 +122,7 @@ uint32_t msm_framebuffer_iova(struct drm_framebuffer *fb, int id, int plane)
struct msm_framebuffer *msm_fb = to_msm_framebuffer(fb);
if (!msm_fb->planes[plane])
return 0;
- return msm_gem_iova(msm_fb->planes[plane], id);
+ return msm_gem_iova(msm_fb->planes[plane], id) + fb->offsets[plane];
}
struct drm_gem_object *msm_framebuffer_bo(struct drm_framebuffer *fb, int plane)
diff --git a/drivers/gpu/drm/msm/msm_fbdev.c b/drivers/gpu/drm/msm/msm_fbdev.c
index 1f3af13ccede..df60f65728ff 100644
--- a/drivers/gpu/drm/msm/msm_fbdev.c
+++ b/drivers/gpu/drm/msm/msm_fbdev.c
@@ -241,17 +241,20 @@ struct drm_fb_helper *msm_fbdev_init(struct drm_device *dev)
goto fail;
}
- drm_fb_helper_single_add_all_connectors(helper);
+ ret = drm_fb_helper_single_add_all_connectors(helper);
+ if (ret)
+ goto fini;
- /* disable all the possible outputs/crtcs before entering KMS mode */
- drm_helper_disable_unused_functions(dev);
-
- drm_fb_helper_initial_config(helper, 32);
+ ret = drm_fb_helper_initial_config(helper, 32);
+ if (ret)
+ goto fini;
priv->fbdev = helper;
return helper;
+fini:
+ drm_fb_helper_fini(helper);
fail:
kfree(fbdev);
return NULL;
diff --git a/drivers/gpu/drm/msm/msm_kms.h b/drivers/gpu/drm/msm/msm_kms.h
index 06437745bc2c..3a78cb48662b 100644
--- a/drivers/gpu/drm/msm/msm_kms.h
+++ b/drivers/gpu/drm/msm/msm_kms.h
@@ -23,6 +23,8 @@
#include "msm_drv.h"
+#define MAX_PLANE 4
+
/* As there are different display controller blocks depending on the
* snapdragon version, the kms support is split out and the appropriate
* implementation is loaded at runtime. The kms module is responsible
@@ -38,6 +40,9 @@ struct msm_kms_funcs {
irqreturn_t (*irq)(struct msm_kms *kms);
int (*enable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
void (*disable_vblank)(struct msm_kms *kms, struct drm_crtc *crtc);
+ /* modeset, bracketing atomic_commit(): */
+ void (*prepare_commit)(struct msm_kms *kms, struct drm_atomic_state *state);
+ void (*complete_commit)(struct msm_kms *kms, struct drm_atomic_state *state);
/* misc: */
const struct msm_format *(*get_format)(struct msm_kms *kms, uint32_t format);
long (*round_pixclk)(struct msm_kms *kms, unsigned long rate,
diff --git a/drivers/gpu/drm/nouveau/Kbuild b/drivers/gpu/drm/nouveau/Kbuild
new file mode 100644
index 000000000000..2b765663c1a3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/Kbuild
@@ -0,0 +1,66 @@
+ccflags-y := -Iinclude/drm
+ccflags-y += -I$(src)/include
+ccflags-y += -I$(src)/include/nvkm
+ccflags-y += -I$(src)/nvkm
+ccflags-y += -I$(src)
+
+# NVKM - HW resource manager
+#- code also used by various userspace tools/tests
+include $(src)/nvif/Kbuild
+nouveau-y := $(nvif-y)
+
+# NVIF - NVKM interface library (NVKM user interface also defined here)
+#- code also used by various userspace tools/tests
+include $(src)/nvkm/Kbuild
+nouveau-y += $(nvkm-y)
+
+# DRM - general
+ifdef CONFIG_X86
+nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
+endif
+nouveau-y += nouveau_agp.o
+nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
+nouveau-y += nouveau_drm.o
+nouveau-y += nouveau_hwmon.o
+nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
+nouveau-y += nouveau_nvif.o
+nouveau-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
+nouveau-y += nouveau_sysfs.o
+nouveau-y += nouveau_usif.o # userspace <-> nvif
+nouveau-y += nouveau_vga.o
+
+# DRM - memory management
+nouveau-y += nouveau_bo.o
+nouveau-y += nouveau_gem.o
+nouveau-y += nouveau_prime.o
+nouveau-y += nouveau_sgdma.o
+nouveau-y += nouveau_ttm.o
+
+# DRM - modesetting
+nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
+nouveau-y += nouveau_connector.o
+nouveau-y += nouveau_display.o
+nouveau-y += nv50_display.o
+nouveau-y += nouveau_dp.o
+nouveau-y += nouveau_fbcon.o
+nouveau-y += nv04_fbcon.o
+nouveau-y += nv50_fbcon.o
+nouveau-y += nvc0_fbcon.o
+
+# DRM - command submission
+nouveau-y += nouveau_abi16.o
+nouveau-y += nouveau_chan.o
+nouveau-y += nouveau_dma.o
+nouveau-y += nouveau_fence.o
+nouveau-y += nv04_fence.o
+nouveau-y += nv10_fence.o
+nouveau-y += nv17_fence.o
+nouveau-y += nv50_fence.o
+nouveau-y += nv84_fence.o
+nouveau-y += nvc0_fence.o
+
+# DRM - prehistoric modesetting (NV04-G7x)
+nouveau-y += nouveau_bios.o
+include $(src)/dispnv04/Kbuild
+
+obj-$(CONFIG_DRM_NOUVEAU) += nouveau.o
diff --git a/drivers/gpu/drm/nouveau/Kconfig b/drivers/gpu/drm/nouveau/Kconfig
index 40afc69a3778..5ab13e7939db 100644
--- a/drivers/gpu/drm/nouveau/Kconfig
+++ b/drivers/gpu/drm/nouveau/Kconfig
@@ -26,7 +26,7 @@ config DRM_NOUVEAU
Choose this option for open-source NVIDIA support.
config NOUVEAU_PLATFORM_DRIVER
- tristate "Nouveau (NVIDIA) SoC GPUs"
+ bool "Nouveau (NVIDIA) SoC GPUs"
depends on DRM_NOUVEAU && ARCH_TEGRA
default y
help
diff --git a/drivers/gpu/drm/nouveau/Makefile b/drivers/gpu/drm/nouveau/Makefile
deleted file mode 100644
index 6461e3565afe..000000000000
--- a/drivers/gpu/drm/nouveau/Makefile
+++ /dev/null
@@ -1,400 +0,0 @@
-#
-# Makefile for the drm device driver. This driver provides support for the
-# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-
-ccflags-y := -Iinclude/drm
-ccflags-y += -I$(src)/core/include
-ccflags-y += -I$(src)/core
-ccflags-y += -I$(src)
-
-nouveau-y := core/core/client.o
-nouveau-y += core/core/engctx.o
-nouveau-y += core/core/engine.o
-nouveau-y += core/core/enum.o
-nouveau-y += core/core/event.o
-nouveau-y += core/core/gpuobj.o
-nouveau-y += core/core/handle.o
-nouveau-y += core/core/ioctl.o
-nouveau-y += core/core/mm.o
-nouveau-y += core/core/namedb.o
-nouveau-y += core/core/notify.o
-nouveau-y += core/core/object.o
-nouveau-y += core/core/option.o
-nouveau-y += core/core/parent.o
-nouveau-y += core/core/printk.o
-nouveau-y += core/core/ramht.o
-nouveau-y += core/core/subdev.o
-
-nouveau-y += core/subdev/bar/base.o
-nouveau-y += core/subdev/bar/nv50.o
-nouveau-y += core/subdev/bar/nvc0.o
-nouveau-y += core/subdev/bar/gk20a.o
-nouveau-y += core/subdev/bios/base.o
-nouveau-y += core/subdev/bios/bit.o
-nouveau-y += core/subdev/bios/boost.o
-nouveau-y += core/subdev/bios/conn.o
-nouveau-y += core/subdev/bios/cstep.o
-nouveau-y += core/subdev/bios/dcb.o
-nouveau-y += core/subdev/bios/disp.o
-nouveau-y += core/subdev/bios/dp.o
-nouveau-y += core/subdev/bios/extdev.o
-nouveau-y += core/subdev/bios/fan.o
-nouveau-y += core/subdev/bios/gpio.o
-nouveau-y += core/subdev/bios/i2c.o
-nouveau-y += core/subdev/bios/image.o
-nouveau-y += core/subdev/bios/init.o
-nouveau-y += core/subdev/bios/mxm.o
-nouveau-y += core/subdev/bios/npde.o
-nouveau-y += core/subdev/bios/pcir.o
-nouveau-y += core/subdev/bios/perf.o
-nouveau-y += core/subdev/bios/pll.o
-nouveau-y += core/subdev/bios/pmu.o
-nouveau-y += core/subdev/bios/ramcfg.o
-nouveau-y += core/subdev/bios/rammap.o
-nouveau-y += core/subdev/bios/shadow.o
-nouveau-y += core/subdev/bios/shadowacpi.o
-nouveau-y += core/subdev/bios/shadowof.o
-nouveau-y += core/subdev/bios/shadowpci.o
-nouveau-y += core/subdev/bios/shadowramin.o
-nouveau-y += core/subdev/bios/shadowrom.o
-nouveau-y += core/subdev/bios/timing.o
-nouveau-y += core/subdev/bios/therm.o
-nouveau-y += core/subdev/bios/vmap.o
-nouveau-y += core/subdev/bios/volt.o
-nouveau-y += core/subdev/bios/xpio.o
-nouveau-y += core/subdev/bios/M0203.o
-nouveau-y += core/subdev/bios/M0205.o
-nouveau-y += core/subdev/bios/M0209.o
-nouveau-y += core/subdev/bios/P0260.o
-nouveau-y += core/subdev/bus/hwsq.o
-nouveau-y += core/subdev/bus/nv04.o
-nouveau-y += core/subdev/bus/nv31.o
-nouveau-y += core/subdev/bus/nv50.o
-nouveau-y += core/subdev/bus/nv94.o
-nouveau-y += core/subdev/bus/nvc0.o
-nouveau-y += core/subdev/clock/base.o
-nouveau-y += core/subdev/clock/nv04.o
-nouveau-y += core/subdev/clock/nv40.o
-nouveau-y += core/subdev/clock/nv50.o
-nouveau-y += core/subdev/clock/nv84.o
-nouveau-y += core/subdev/clock/nva3.o
-nouveau-y += core/subdev/clock/nvaa.o
-nouveau-y += core/subdev/clock/nvc0.o
-nouveau-y += core/subdev/clock/nve0.o
-nouveau-y += core/subdev/clock/gk20a.o
-nouveau-y += core/subdev/clock/pllnv04.o
-nouveau-y += core/subdev/clock/pllnva3.o
-nouveau-y += core/subdev/devinit/base.o
-nouveau-y += core/subdev/devinit/nv04.o
-nouveau-y += core/subdev/devinit/nv05.o
-nouveau-y += core/subdev/devinit/nv10.o
-nouveau-y += core/subdev/devinit/nv1a.o
-nouveau-y += core/subdev/devinit/nv20.o
-nouveau-y += core/subdev/devinit/nv50.o
-nouveau-y += core/subdev/devinit/nv84.o
-nouveau-y += core/subdev/devinit/nv98.o
-nouveau-y += core/subdev/devinit/nva3.o
-nouveau-y += core/subdev/devinit/nvaf.o
-nouveau-y += core/subdev/devinit/nvc0.o
-nouveau-y += core/subdev/devinit/gm107.o
-nouveau-y += core/subdev/devinit/gm204.o
-nouveau-y += core/subdev/fb/base.o
-nouveau-y += core/subdev/fb/nv04.o
-nouveau-y += core/subdev/fb/nv10.o
-nouveau-y += core/subdev/fb/nv1a.o
-nouveau-y += core/subdev/fb/nv20.o
-nouveau-y += core/subdev/fb/nv25.o
-nouveau-y += core/subdev/fb/nv30.o
-nouveau-y += core/subdev/fb/nv35.o
-nouveau-y += core/subdev/fb/nv36.o
-nouveau-y += core/subdev/fb/nv40.o
-nouveau-y += core/subdev/fb/nv41.o
-nouveau-y += core/subdev/fb/nv44.o
-nouveau-y += core/subdev/fb/nv46.o
-nouveau-y += core/subdev/fb/nv47.o
-nouveau-y += core/subdev/fb/nv49.o
-nouveau-y += core/subdev/fb/nv4e.o
-nouveau-y += core/subdev/fb/nv50.o
-nouveau-y += core/subdev/fb/nv84.o
-nouveau-y += core/subdev/fb/nva3.o
-nouveau-y += core/subdev/fb/nvaa.o
-nouveau-y += core/subdev/fb/nvaf.o
-nouveau-y += core/subdev/fb/nvc0.o
-nouveau-y += core/subdev/fb/nve0.o
-nouveau-y += core/subdev/fb/gk20a.o
-nouveau-y += core/subdev/fb/gm107.o
-nouveau-y += core/subdev/fb/ramnv04.o
-nouveau-y += core/subdev/fb/ramnv10.o
-nouveau-y += core/subdev/fb/ramnv1a.o
-nouveau-y += core/subdev/fb/ramnv20.o
-nouveau-y += core/subdev/fb/ramnv40.o
-nouveau-y += core/subdev/fb/ramnv41.o
-nouveau-y += core/subdev/fb/ramnv44.o
-nouveau-y += core/subdev/fb/ramnv49.o
-nouveau-y += core/subdev/fb/ramnv4e.o
-nouveau-y += core/subdev/fb/ramnv50.o
-nouveau-y += core/subdev/fb/ramnva3.o
-nouveau-y += core/subdev/fb/ramnvaa.o
-nouveau-y += core/subdev/fb/ramnvc0.o
-nouveau-y += core/subdev/fb/ramnve0.o
-nouveau-y += core/subdev/fb/ramgk20a.o
-nouveau-y += core/subdev/fb/ramgm107.o
-nouveau-y += core/subdev/fb/sddr2.o
-nouveau-y += core/subdev/fb/sddr3.o
-nouveau-y += core/subdev/fb/gddr3.o
-nouveau-y += core/subdev/fb/gddr5.o
-nouveau-y += core/subdev/fuse/base.o
-nouveau-y += core/subdev/fuse/g80.o
-nouveau-y += core/subdev/fuse/gf100.o
-nouveau-y += core/subdev/fuse/gm107.o
-nouveau-y += core/subdev/gpio/base.o
-nouveau-y += core/subdev/gpio/nv10.o
-nouveau-y += core/subdev/gpio/nv50.o
-nouveau-y += core/subdev/gpio/nv94.o
-nouveau-y += core/subdev/gpio/nvd0.o
-nouveau-y += core/subdev/gpio/nve0.o
-nouveau-y += core/subdev/i2c/base.o
-nouveau-y += core/subdev/i2c/anx9805.o
-nouveau-y += core/subdev/i2c/aux.o
-nouveau-y += core/subdev/i2c/bit.o
-nouveau-y += core/subdev/i2c/pad.o
-nouveau-y += core/subdev/i2c/padnv04.o
-nouveau-y += core/subdev/i2c/padnv94.o
-nouveau-y += core/subdev/i2c/padgm204.o
-nouveau-y += core/subdev/i2c/nv04.o
-nouveau-y += core/subdev/i2c/nv4e.o
-nouveau-y += core/subdev/i2c/nv50.o
-nouveau-y += core/subdev/i2c/nv94.o
-nouveau-y += core/subdev/i2c/nvd0.o
-nouveau-y += core/subdev/i2c/gf117.o
-nouveau-y += core/subdev/i2c/nve0.o
-nouveau-y += core/subdev/i2c/gm204.o
-nouveau-y += core/subdev/ibus/nvc0.o
-nouveau-y += core/subdev/ibus/nve0.o
-nouveau-y += core/subdev/ibus/gk20a.o
-nouveau-y += core/subdev/instmem/base.o
-nouveau-y += core/subdev/instmem/nv04.o
-nouveau-y += core/subdev/instmem/nv40.o
-nouveau-y += core/subdev/instmem/nv50.o
-nouveau-y += core/subdev/ltc/base.o
-nouveau-y += core/subdev/ltc/gf100.o
-nouveau-y += core/subdev/ltc/gk104.o
-nouveau-y += core/subdev/ltc/gm107.o
-nouveau-y += core/subdev/mc/base.o
-nouveau-y += core/subdev/mc/nv04.o
-nouveau-y += core/subdev/mc/nv40.o
-nouveau-y += core/subdev/mc/nv44.o
-nouveau-y += core/subdev/mc/nv4c.o
-nouveau-y += core/subdev/mc/nv50.o
-nouveau-y += core/subdev/mc/nv94.o
-nouveau-y += core/subdev/mc/nv98.o
-nouveau-y += core/subdev/mc/nvc0.o
-nouveau-y += core/subdev/mc/nvc3.o
-nouveau-y += core/subdev/mc/gk20a.o
-nouveau-y += core/subdev/mxm/base.o
-nouveau-y += core/subdev/mxm/mxms.o
-nouveau-y += core/subdev/mxm/nv50.o
-nouveau-y += core/subdev/pwr/base.o
-nouveau-y += core/subdev/pwr/memx.o
-nouveau-y += core/subdev/pwr/nva3.o
-nouveau-y += core/subdev/pwr/nvc0.o
-nouveau-y += core/subdev/pwr/nvd0.o
-nouveau-y += core/subdev/pwr/gk104.o
-nouveau-y += core/subdev/pwr/nv108.o
-nouveau-y += core/subdev/therm/base.o
-nouveau-y += core/subdev/therm/fan.o
-nouveau-y += core/subdev/therm/fannil.o
-nouveau-y += core/subdev/therm/fanpwm.o
-nouveau-y += core/subdev/therm/fantog.o
-nouveau-y += core/subdev/therm/ic.o
-nouveau-y += core/subdev/therm/temp.o
-nouveau-y += core/subdev/therm/nv40.o
-nouveau-y += core/subdev/therm/nv50.o
-nouveau-y += core/subdev/therm/nv84.o
-nouveau-y += core/subdev/therm/nva3.o
-nouveau-y += core/subdev/therm/nvd0.o
-nouveau-y += core/subdev/therm/gm107.o
-nouveau-y += core/subdev/timer/base.o
-nouveau-y += core/subdev/timer/nv04.o
-nouveau-y += core/subdev/timer/gk20a.o
-nouveau-y += core/subdev/vm/base.o
-nouveau-y += core/subdev/vm/nv04.o
-nouveau-y += core/subdev/vm/nv41.o
-nouveau-y += core/subdev/vm/nv44.o
-nouveau-y += core/subdev/vm/nv50.o
-nouveau-y += core/subdev/vm/nvc0.o
-nouveau-y += core/subdev/volt/base.o
-nouveau-y += core/subdev/volt/gpio.o
-nouveau-y += core/subdev/volt/nv40.o
-nouveau-y += core/subdev/volt/gk20a.o
-
-nouveau-y += core/engine/falcon.o
-nouveau-y += core/engine/xtensa.o
-nouveau-y += core/engine/dmaobj/base.o
-nouveau-y += core/engine/dmaobj/nv04.o
-nouveau-y += core/engine/dmaobj/nv50.o
-nouveau-y += core/engine/dmaobj/nvc0.o
-nouveau-y += core/engine/dmaobj/nvd0.o
-nouveau-y += core/engine/bsp/nv84.o
-nouveau-y += core/engine/bsp/nv98.o
-nouveau-y += core/engine/bsp/nvc0.o
-nouveau-y += core/engine/bsp/nve0.o
-nouveau-y += core/engine/copy/nva3.o
-nouveau-y += core/engine/copy/nvc0.o
-nouveau-y += core/engine/copy/nve0.o
-nouveau-y += core/engine/crypt/nv84.o
-nouveau-y += core/engine/crypt/nv98.o
-nouveau-y += core/engine/device/acpi.o
-nouveau-y += core/engine/device/base.o
-nouveau-y += core/engine/device/ctrl.o
-nouveau-y += core/engine/device/nv04.o
-nouveau-y += core/engine/device/nv10.o
-nouveau-y += core/engine/device/nv20.o
-nouveau-y += core/engine/device/nv30.o
-nouveau-y += core/engine/device/nv40.o
-nouveau-y += core/engine/device/nv50.o
-nouveau-y += core/engine/device/nvc0.o
-nouveau-y += core/engine/device/nve0.o
-nouveau-y += core/engine/device/gm100.o
-nouveau-y += core/engine/disp/base.o
-nouveau-y += core/engine/disp/conn.o
-nouveau-y += core/engine/disp/outp.o
-nouveau-y += core/engine/disp/outpdp.o
-nouveau-y += core/engine/disp/nv04.o
-nouveau-y += core/engine/disp/nv50.o
-nouveau-y += core/engine/disp/nv84.o
-nouveau-y += core/engine/disp/nv94.o
-nouveau-y += core/engine/disp/nva0.o
-nouveau-y += core/engine/disp/nva3.o
-nouveau-y += core/engine/disp/nvd0.o
-nouveau-y += core/engine/disp/nve0.o
-nouveau-y += core/engine/disp/nvf0.o
-nouveau-y += core/engine/disp/gm107.o
-nouveau-y += core/engine/disp/gm204.o
-nouveau-y += core/engine/disp/dacnv50.o
-nouveau-y += core/engine/disp/dport.o
-nouveau-y += core/engine/disp/hdanva3.o
-nouveau-y += core/engine/disp/hdanvd0.o
-nouveau-y += core/engine/disp/hdminv84.o
-nouveau-y += core/engine/disp/hdminva3.o
-nouveau-y += core/engine/disp/hdminvd0.o
-nouveau-y += core/engine/disp/hdminve0.o
-nouveau-y += core/engine/disp/piornv50.o
-nouveau-y += core/engine/disp/sornv50.o
-nouveau-y += core/engine/disp/sornv94.o
-nouveau-y += core/engine/disp/sornvd0.o
-nouveau-y += core/engine/disp/sorgm204.o
-nouveau-y += core/engine/disp/vga.o
-nouveau-y += core/engine/fifo/base.o
-nouveau-y += core/engine/fifo/nv04.o
-nouveau-y += core/engine/fifo/nv10.o
-nouveau-y += core/engine/fifo/nv17.o
-nouveau-y += core/engine/fifo/nv40.o
-nouveau-y += core/engine/fifo/nv50.o
-nouveau-y += core/engine/fifo/nv84.o
-nouveau-y += core/engine/fifo/nvc0.o
-nouveau-y += core/engine/fifo/nve0.o
-nouveau-y += core/engine/fifo/gk20a.o
-nouveau-y += core/engine/fifo/nv108.o
-nouveau-y += core/engine/graph/ctxnv40.o
-nouveau-y += core/engine/graph/ctxnv50.o
-nouveau-y += core/engine/graph/ctxnvc0.o
-nouveau-y += core/engine/graph/ctxnvc1.o
-nouveau-y += core/engine/graph/ctxnvc4.o
-nouveau-y += core/engine/graph/ctxnvc8.o
-nouveau-y += core/engine/graph/ctxnvd7.o
-nouveau-y += core/engine/graph/ctxnvd9.o
-nouveau-y += core/engine/graph/ctxnve4.o
-nouveau-y += core/engine/graph/ctxgk20a.o
-nouveau-y += core/engine/graph/ctxnvf0.o
-nouveau-y += core/engine/graph/ctxgk110b.o
-nouveau-y += core/engine/graph/ctxnv108.o
-nouveau-y += core/engine/graph/ctxgm107.o
-nouveau-y += core/engine/graph/nv04.o
-nouveau-y += core/engine/graph/nv10.o
-nouveau-y += core/engine/graph/nv20.o
-nouveau-y += core/engine/graph/nv25.o
-nouveau-y += core/engine/graph/nv2a.o
-nouveau-y += core/engine/graph/nv30.o
-nouveau-y += core/engine/graph/nv34.o
-nouveau-y += core/engine/graph/nv35.o
-nouveau-y += core/engine/graph/nv40.o
-nouveau-y += core/engine/graph/nv50.o
-nouveau-y += core/engine/graph/nvc0.o
-nouveau-y += core/engine/graph/nvc1.o
-nouveau-y += core/engine/graph/nvc4.o
-nouveau-y += core/engine/graph/nvc8.o
-nouveau-y += core/engine/graph/nvd7.o
-nouveau-y += core/engine/graph/nvd9.o
-nouveau-y += core/engine/graph/nve4.o
-nouveau-y += core/engine/graph/gk20a.o
-nouveau-y += core/engine/graph/nvf0.o
-nouveau-y += core/engine/graph/gk110b.o
-nouveau-y += core/engine/graph/nv108.o
-nouveau-y += core/engine/graph/gm107.o
-nouveau-y += core/engine/mpeg/nv31.o
-nouveau-y += core/engine/mpeg/nv40.o
-nouveau-y += core/engine/mpeg/nv44.o
-nouveau-y += core/engine/mpeg/nv50.o
-nouveau-y += core/engine/mpeg/nv84.o
-nouveau-y += core/engine/perfmon/base.o
-nouveau-y += core/engine/perfmon/daemon.o
-nouveau-y += core/engine/perfmon/nv40.o
-nouveau-y += core/engine/perfmon/nv50.o
-nouveau-y += core/engine/perfmon/nv84.o
-nouveau-y += core/engine/perfmon/nva3.o
-nouveau-y += core/engine/perfmon/nvc0.o
-nouveau-y += core/engine/perfmon/nve0.o
-nouveau-y += core/engine/perfmon/nvf0.o
-nouveau-y += core/engine/ppp/nv98.o
-nouveau-y += core/engine/ppp/nvc0.o
-nouveau-y += core/engine/software/nv04.o
-nouveau-y += core/engine/software/nv10.o
-nouveau-y += core/engine/software/nv50.o
-nouveau-y += core/engine/software/nvc0.o
-nouveau-y += core/engine/vp/nv84.o
-nouveau-y += core/engine/vp/nv98.o
-nouveau-y += core/engine/vp/nvc0.o
-nouveau-y += core/engine/vp/nve0.o
-
-# nvif
-nouveau-y += nvif/object.o
-nouveau-y += nvif/client.o
-nouveau-y += nvif/device.o
-nouveau-y += nvif/notify.o
-
-# drm/core
-nouveau-y += nouveau_drm.o nouveau_chan.o nouveau_dma.o nouveau_fence.o
-nouveau-y += nouveau_vga.o nouveau_agp.o
-nouveau-y += nouveau_ttm.o nouveau_sgdma.o nouveau_bo.o nouveau_gem.o
-nouveau-y += nouveau_prime.o nouveau_abi16.o
-nouveau-y += nouveau_nvif.o nouveau_usif.o
-nouveau-y += nv04_fence.o nv10_fence.o nv17_fence.o
-nouveau-y += nv50_fence.o nv84_fence.o nvc0_fence.o
-
-# drm/kms
-nouveau-y += nouveau_bios.o nouveau_fbcon.o nouveau_display.o
-nouveau-y += nouveau_connector.o nouveau_dp.o
-nouveau-y += nv04_fbcon.o nv50_fbcon.o nvc0_fbcon.o
-
-# drm/kms/nv04:nv50
-include $(src)/dispnv04/Makefile
-
-# drm/kms/nv50-
-nouveau-y += nv50_display.o
-
-# drm/pm
-nouveau-y += nouveau_hwmon.o nouveau_sysfs.o
-
-# other random bits
-nouveau-$(CONFIG_COMPAT) += nouveau_ioc32.o
-ifdef CONFIG_X86
-nouveau-$(CONFIG_ACPI) += nouveau_acpi.o
-endif
-nouveau-$(CONFIG_DRM_NOUVEAU_BACKLIGHT) += nouveau_backlight.o
-nouveau-$(CONFIG_DEBUG_FS) += nouveau_debugfs.o
-
-obj-$(CONFIG_DRM_NOUVEAU)+= nouveau.o
-
-# platform driver
-obj-$(CONFIG_NOUVEAU_PLATFORM_DRIVER) += nouveau_platform.o
diff --git a/drivers/gpu/drm/nouveau/core/core/client.c b/drivers/gpu/drm/nouveau/core/core/client.c
deleted file mode 100644
index e962433294c3..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/client.c
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/option.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <nvif/unpack.h>
-#include <nvif/event.h>
-
-#include <engine/device.h>
-
-struct nvkm_client_notify {
- struct nouveau_client *client;
- struct nvkm_notify n;
- u8 version;
- u8 size;
- union {
- struct nvif_notify_rep_v0 v0;
- } rep;
-};
-
-static int
-nvkm_client_notify(struct nvkm_notify *n)
-{
- struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
- struct nouveau_client *client = notify->client;
- return client->ntfy(&notify->rep, notify->size, n->data, n->size);
-}
-
-int
-nvkm_client_notify_put(struct nouveau_client *client, int index)
-{
- if (index < ARRAY_SIZE(client->notify)) {
- if (client->notify[index]) {
- nvkm_notify_put(&client->notify[index]->n);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int
-nvkm_client_notify_get(struct nouveau_client *client, int index)
-{
- if (index < ARRAY_SIZE(client->notify)) {
- if (client->notify[index]) {
- nvkm_notify_get(&client->notify[index]->n);
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int
-nvkm_client_notify_del(struct nouveau_client *client, int index)
-{
- if (index < ARRAY_SIZE(client->notify)) {
- if (client->notify[index]) {
- nvkm_notify_fini(&client->notify[index]->n);
- kfree(client->notify[index]);
- client->notify[index] = NULL;
- return 0;
- }
- }
- return -ENOENT;
-}
-
-int
-nvkm_client_notify_new(struct nouveau_object *object,
- struct nvkm_event *event, void *data, u32 size)
-{
- struct nouveau_client *client = nouveau_client(object);
- struct nvkm_client_notify *notify;
- union {
- struct nvif_notify_req_v0 v0;
- } *req = data;
- u8 index, reply;
- int ret;
-
- for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
- if (!client->notify[index])
- break;
- }
-
- if (index == ARRAY_SIZE(client->notify))
- return -ENOSPC;
-
- notify = kzalloc(sizeof(*notify), GFP_KERNEL);
- if (!notify)
- return -ENOMEM;
-
- nv_ioctl(client, "notify new size %d\n", size);
- if (nvif_unpack(req->v0, 0, 0, true)) {
- nv_ioctl(client, "notify new vers %d reply %d route %02x "
- "token %llx\n", req->v0.version,
- req->v0.reply, req->v0.route, req->v0.token);
- notify->version = req->v0.version;
- notify->size = sizeof(notify->rep.v0);
- notify->rep.v0.version = req->v0.version;
- notify->rep.v0.route = req->v0.route;
- notify->rep.v0.token = req->v0.token;
- reply = req->v0.reply;
- }
-
- if (ret == 0) {
- ret = nvkm_notify_init(object, event, nvkm_client_notify,
- false, data, size, reply, &notify->n);
- if (ret == 0) {
- client->notify[index] = notify;
- notify->client = client;
- return index;
- }
- }
-
- kfree(notify);
- return ret;
-}
-
-static int
-nouveau_client_devlist(struct nouveau_object *object, void *data, u32 size)
-{
- union {
- struct nv_client_devlist_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "client devlist size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "client devlist vers %d count %d\n",
- args->v0.version, args->v0.count);
- if (size == sizeof(args->v0.device[0]) * args->v0.count) {
- ret = nouveau_device_list(args->v0.device,
- args->v0.count);
- if (ret >= 0) {
- args->v0.count = ret;
- ret = 0;
- }
- } else {
- ret = -EINVAL;
- }
- }
-
- return ret;
-}
-
-static int
-nouveau_client_mthd(struct nouveau_object *object, u32 mthd,
- void *data, u32 size)
-{
- switch (mthd) {
- case NV_CLIENT_DEVLIST:
- return nouveau_client_devlist(object, data, size);
- default:
- break;
- }
- return -EINVAL;
-}
-
-static void
-nouveau_client_dtor(struct nouveau_object *object)
-{
- struct nouveau_client *client = (void *)object;
- int i;
- for (i = 0; i < ARRAY_SIZE(client->notify); i++)
- nvkm_client_notify_del(client, i);
- nouveau_object_ref(NULL, &client->device);
- nouveau_handle_destroy(client->root);
- nouveau_namedb_destroy(&client->base);
-}
-
-static struct nouveau_oclass
-nouveau_client_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .dtor = nouveau_client_dtor,
- .mthd = nouveau_client_mthd,
- },
-};
-
-int
-nouveau_client_create_(const char *name, u64 devname, const char *cfg,
- const char *dbg, int length, void **pobject)
-{
- struct nouveau_object *device;
- struct nouveau_client *client;
- int ret;
-
- device = (void *)nouveau_device_find(devname);
- if (!device)
- return -ENODEV;
-
- ret = nouveau_namedb_create_(NULL, NULL, &nouveau_client_oclass,
- NV_CLIENT_CLASS, NULL,
- (1ULL << NVDEV_ENGINE_DEVICE),
- length, pobject);
- client = *pobject;
- if (ret)
- return ret;
-
- ret = nouveau_handle_create(nv_object(client), ~0, ~0,
- nv_object(client), &client->root);
- if (ret)
- return ret;
-
- /* prevent init/fini being called, os in in charge of this */
- atomic_set(&nv_object(client)->usecount, 2);
-
- nouveau_object_ref(device, &client->device);
- snprintf(client->name, sizeof(client->name), "%s", name);
- client->debug = nouveau_dbgopt(dbg, "CLIENT");
- return 0;
-}
-
-int
-nouveau_client_init(struct nouveau_client *client)
-{
- int ret;
- nv_debug(client, "init running\n");
- ret = nouveau_handle_init(client->root);
- nv_debug(client, "init completed with %d\n", ret);
- return ret;
-}
-
-int
-nouveau_client_fini(struct nouveau_client *client, bool suspend)
-{
- const char *name[2] = { "fini", "suspend" };
- int ret, i;
- nv_debug(client, "%s running\n", name[suspend]);
- nv_debug(client, "%s notify\n", name[suspend]);
- for (i = 0; i < ARRAY_SIZE(client->notify); i++)
- nvkm_client_notify_put(client, i);
- nv_debug(client, "%s object\n", name[suspend]);
- ret = nouveau_handle_fini(client->root, suspend);
- nv_debug(client, "%s completed with %d\n", name[suspend], ret);
- return ret;
-}
-
-const char *
-nouveau_client_name(void *obj)
-{
- const char *client_name = "unknown";
- struct nouveau_client *client = nouveau_client(obj);
- if (client)
- client_name = client->name;
- return client_name;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/engctx.c b/drivers/gpu/drm/nouveau/core/core/engctx.c
deleted file mode 100644
index 84c71fad2b6c..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/engctx.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/client.h>
-#include <core/engctx.h>
-
-#include <subdev/vm.h>
-
-static inline int
-nouveau_engctx_exists(struct nouveau_object *parent,
- struct nouveau_engine *engine, void **pobject)
-{
- struct nouveau_engctx *engctx;
- struct nouveau_object *parctx;
-
- list_for_each_entry(engctx, &engine->contexts, head) {
- parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
- if (parctx == parent) {
- atomic_inc(&nv_object(engctx)->refcount);
- *pobject = engctx;
- return 1;
- }
- }
-
- return 0;
-}
-
-int
-nouveau_engctx_create_(struct nouveau_object *parent,
- struct nouveau_object *engobj,
- struct nouveau_oclass *oclass,
- struct nouveau_object *pargpu,
- u32 size, u32 align, u32 flags,
- int length, void **pobject)
-{
- struct nouveau_client *client = nouveau_client(parent);
- struct nouveau_engine *engine = nv_engine(engobj);
- struct nouveau_object *engctx;
- unsigned long save;
- int ret;
-
- /* check if this engine already has a context for the parent object,
- * and reference it instead of creating a new one
- */
- spin_lock_irqsave(&engine->lock, save);
- ret = nouveau_engctx_exists(parent, engine, pobject);
- spin_unlock_irqrestore(&engine->lock, save);
- if (ret)
- return ret;
-
- /* create the new context, supports creating both raw objects and
- * objects backed by instance memory
- */
- if (size) {
- ret = nouveau_gpuobj_create_(parent, engobj, oclass,
- NV_ENGCTX_CLASS,
- pargpu, size, align, flags,
- length, pobject);
- } else {
- ret = nouveau_object_create_(parent, engobj, oclass,
- NV_ENGCTX_CLASS, length, pobject);
- }
-
- engctx = *pobject;
- if (ret)
- return ret;
-
- /* must take the lock again and re-check a context doesn't already
- * exist (in case of a race) - the lock had to be dropped before as
- * it's not possible to allocate the object with it held.
- */
- spin_lock_irqsave(&engine->lock, save);
- ret = nouveau_engctx_exists(parent, engine, pobject);
- if (ret) {
- spin_unlock_irqrestore(&engine->lock, save);
- nouveau_object_ref(NULL, &engctx);
- return ret;
- }
-
- if (client->vm)
- atomic_inc(&client->vm->engref[nv_engidx(engobj)]);
- list_add(&nv_engctx(engctx)->head, &engine->contexts);
- nv_engctx(engctx)->addr = ~0ULL;
- spin_unlock_irqrestore(&engine->lock, save);
- return 0;
-}
-
-void
-nouveau_engctx_destroy(struct nouveau_engctx *engctx)
-{
- struct nouveau_object *engobj = nv_object(engctx)->engine;
- struct nouveau_engine *engine = nv_engine(engobj);
- struct nouveau_client *client = nouveau_client(engctx);
- unsigned long save;
-
- nouveau_gpuobj_unmap(&engctx->vma);
- spin_lock_irqsave(&engine->lock, save);
- list_del(&engctx->head);
- spin_unlock_irqrestore(&engine->lock, save);
-
- if (client->vm)
- atomic_dec(&client->vm->engref[nv_engidx(engobj)]);
-
- if (engctx->base.size)
- nouveau_gpuobj_destroy(&engctx->base);
- else
- nouveau_object_destroy(&engctx->base.base);
-}
-
-int
-nouveau_engctx_init(struct nouveau_engctx *engctx)
-{
- struct nouveau_object *object = nv_object(engctx);
- struct nouveau_subdev *subdev = nv_subdev(object->engine);
- struct nouveau_object *parent;
- struct nouveau_subdev *pardev;
- int ret;
-
- ret = nouveau_gpuobj_init(&engctx->base);
- if (ret)
- return ret;
-
- parent = nv_pclass(object->parent, NV_PARENT_CLASS);
- pardev = nv_subdev(parent->engine);
- if (nv_parent(parent)->context_attach) {
- mutex_lock(&pardev->mutex);
- ret = nv_parent(parent)->context_attach(parent, object);
- mutex_unlock(&pardev->mutex);
- }
-
- if (ret) {
- nv_error(parent, "failed to attach %s context, %d\n",
- subdev->name, ret);
- return ret;
- }
-
- nv_debug(parent, "attached %s context\n", subdev->name);
- return 0;
-}
-
-int
-nouveau_engctx_fini(struct nouveau_engctx *engctx, bool suspend)
-{
- struct nouveau_object *object = nv_object(engctx);
- struct nouveau_subdev *subdev = nv_subdev(object->engine);
- struct nouveau_object *parent;
- struct nouveau_subdev *pardev;
- int ret = 0;
-
- parent = nv_pclass(object->parent, NV_PARENT_CLASS);
- pardev = nv_subdev(parent->engine);
- if (nv_parent(parent)->context_detach) {
- mutex_lock(&pardev->mutex);
- ret = nv_parent(parent)->context_detach(parent, suspend, object);
- mutex_unlock(&pardev->mutex);
- }
-
- if (ret) {
- nv_error(parent, "failed to detach %s context, %d\n",
- subdev->name, ret);
- return ret;
- }
-
- nv_debug(parent, "detached %s context\n", subdev->name);
- return nouveau_gpuobj_fini(&engctx->base, suspend);
-}
-
-int
-_nouveau_engctx_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_engctx *engctx;
- int ret;
-
- ret = nouveau_engctx_create(parent, engine, oclass, NULL, 256, 256,
- NVOBJ_FLAG_ZERO_ALLOC, &engctx);
- *pobject = nv_object(engctx);
- return ret;
-}
-
-void
-_nouveau_engctx_dtor(struct nouveau_object *object)
-{
- nouveau_engctx_destroy(nv_engctx(object));
-}
-
-int
-_nouveau_engctx_init(struct nouveau_object *object)
-{
- return nouveau_engctx_init(nv_engctx(object));
-}
-
-
-int
-_nouveau_engctx_fini(struct nouveau_object *object, bool suspend)
-{
- return nouveau_engctx_fini(nv_engctx(object), suspend);
-}
-
-struct nouveau_object *
-nouveau_engctx_get(struct nouveau_engine *engine, u64 addr)
-{
- struct nouveau_engctx *engctx;
- unsigned long flags;
-
- spin_lock_irqsave(&engine->lock, flags);
- list_for_each_entry(engctx, &engine->contexts, head) {
- if (engctx->addr == addr) {
- engctx->save = flags;
- return nv_object(engctx);
- }
- }
- spin_unlock_irqrestore(&engine->lock, flags);
- return NULL;
-}
-
-void
-nouveau_engctx_put(struct nouveau_object *object)
-{
- if (object) {
- struct nouveau_engine *engine = nv_engine(object->engine);
- struct nouveau_engctx *engctx = nv_engctx(object);
- spin_unlock_irqrestore(&engine->lock, engctx->save);
- }
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/engine.c b/drivers/gpu/drm/nouveau/core/core/engine.c
deleted file mode 100644
index 1f6954ae9dd3..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/engine.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-#include <core/engine.h>
-#include <core/option.h>
-
-int
-nouveau_engine_create_(struct nouveau_object *parent,
- struct nouveau_object *engobj,
- struct nouveau_oclass *oclass, bool enable,
- const char *iname, const char *fname,
- int length, void **pobject)
-{
- struct nouveau_engine *engine;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
- iname, fname, length, pobject);
- engine = *pobject;
- if (ret)
- return ret;
-
- if (parent) {
- struct nouveau_device *device = nv_device(parent);
- int engidx = nv_engidx(nv_object(engine));
-
- if (device->disable_mask & (1ULL << engidx)) {
- if (!nouveau_boolopt(device->cfgopt, iname, false)) {
- nv_debug(engine, "engine disabled by hw/fw\n");
- return -ENODEV;
- }
-
- nv_warn(engine, "ignoring hw/fw engine disable\n");
- }
-
- if (!nouveau_boolopt(device->cfgopt, iname, enable)) {
- if (!enable)
- nv_warn(engine, "disabled, %s=1 to enable\n", iname);
- return -ENODEV;
- }
- }
-
- INIT_LIST_HEAD(&engine->contexts);
- spin_lock_init(&engine->lock);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/enum.c b/drivers/gpu/drm/nouveau/core/core/enum.c
deleted file mode 100644
index dd434790ccc4..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/enum.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2010 Nouveau Project
- *
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <core/os.h>
-#include <core/enum.h>
-
-const struct nouveau_enum *
-nouveau_enum_find(const struct nouveau_enum *en, u32 value)
-{
- while (en->name) {
- if (en->value == value)
- return en;
- en++;
- }
-
- return NULL;
-}
-
-const struct nouveau_enum *
-nouveau_enum_print(const struct nouveau_enum *en, u32 value)
-{
- en = nouveau_enum_find(en, value);
- if (en)
- pr_cont("%s", en->name);
- else
- pr_cont("(unknown enum 0x%08x)", value);
- return en;
-}
-
-void
-nouveau_bitfield_print(const struct nouveau_bitfield *bf, u32 value)
-{
- while (bf->name) {
- if (value & bf->mask) {
- pr_cont(" %s", bf->name);
- value &= ~bf->mask;
- }
-
- bf++;
- }
-
- if (value)
- pr_cont(" (unknown bits 0x%08x)", value);
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/event.c b/drivers/gpu/drm/nouveau/core/core/event.c
deleted file mode 100644
index 760947e380c9..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/event.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2013-2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <core/object.h>
-#include <core/event.h>
-
-void
-nvkm_event_put(struct nvkm_event *event, u32 types, int index)
-{
- assert_spin_locked(&event->refs_lock);
- while (types) {
- int type = __ffs(types); types &= ~(1 << type);
- if (--event->refs[index * event->types_nr + type] == 0) {
- if (event->func->fini)
- event->func->fini(event, 1 << type, index);
- }
- }
-}
-
-void
-nvkm_event_get(struct nvkm_event *event, u32 types, int index)
-{
- assert_spin_locked(&event->refs_lock);
- while (types) {
- int type = __ffs(types); types &= ~(1 << type);
- if (++event->refs[index * event->types_nr + type] == 1) {
- if (event->func->init)
- event->func->init(event, 1 << type, index);
- }
- }
-}
-
-void
-nvkm_event_send(struct nvkm_event *event, u32 types, int index,
- void *data, u32 size)
-{
- struct nvkm_notify *notify;
- unsigned long flags;
-
- if (!event->refs || WARN_ON(index >= event->index_nr))
- return;
-
- spin_lock_irqsave(&event->list_lock, flags);
- list_for_each_entry(notify, &event->list, head) {
- if (notify->index == index && (notify->types & types)) {
- if (event->func->send) {
- event->func->send(data, size, notify);
- continue;
- }
- nvkm_notify_send(notify, data, size);
- }
- }
- spin_unlock_irqrestore(&event->list_lock, flags);
-}
-
-void
-nvkm_event_fini(struct nvkm_event *event)
-{
- if (event->refs) {
- kfree(event->refs);
- event->refs = NULL;
- }
-}
-
-int
-nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
- struct nvkm_event *event)
-{
- event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
- GFP_KERNEL);
- if (!event->refs)
- return -ENOMEM;
-
- event->func = func;
- event->types_nr = types_nr;
- event->index_nr = index_nr;
- spin_lock_init(&event->refs_lock);
- spin_lock_init(&event->list_lock);
- INIT_LIST_HEAD(&event->list);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/gpuobj.c b/drivers/gpu/drm/nouveau/core/core/gpuobj.c
deleted file mode 100644
index daee87702502..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/gpuobj.c
+++ /dev/null
@@ -1,323 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/gpuobj.h>
-
-#include <subdev/instmem.h>
-#include <subdev/bar.h>
-#include <subdev/vm.h>
-
-void
-nouveau_gpuobj_destroy(struct nouveau_gpuobj *gpuobj)
-{
- int i;
-
- if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
- for (i = 0; i < gpuobj->size; i += 4)
- nv_wo32(gpuobj, i, 0x00000000);
- }
-
- if (gpuobj->node) {
- nouveau_mm_free(&nv_gpuobj(gpuobj->parent)->heap,
- &gpuobj->node);
- }
-
- if (gpuobj->heap.block_size)
- nouveau_mm_fini(&gpuobj->heap);
-
- nouveau_object_destroy(&gpuobj->base);
-}
-
-int
-nouveau_gpuobj_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pclass,
- struct nouveau_object *pargpu,
- u32 size, u32 align, u32 flags,
- int length, void **pobject)
-{
- struct nouveau_instmem *imem = nouveau_instmem(parent);
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nouveau_gpuobj *gpuobj;
- struct nouveau_mm *heap = NULL;
- int ret, i;
- u64 addr;
-
- *pobject = NULL;
-
- if (pargpu) {
- while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
- if (nv_gpuobj(pargpu)->heap.block_size)
- break;
- pargpu = pargpu->parent;
- }
-
- if (unlikely(pargpu == NULL)) {
- nv_error(parent, "no gpuobj heap\n");
- return -EINVAL;
- }
-
- addr = nv_gpuobj(pargpu)->addr;
- heap = &nv_gpuobj(pargpu)->heap;
- atomic_inc(&parent->refcount);
- } else {
- ret = imem->alloc(imem, parent, size, align, &parent);
- pargpu = parent;
- if (ret)
- return ret;
-
- addr = nv_memobj(pargpu)->addr;
- size = nv_memobj(pargpu)->size;
-
- if (bar && bar->alloc) {
- struct nouveau_instobj *iobj = (void *)parent;
- struct nouveau_mem **mem = (void *)(iobj + 1);
- struct nouveau_mem *node = *mem;
- if (!bar->alloc(bar, parent, node, &pargpu)) {
- nouveau_object_ref(NULL, &parent);
- parent = pargpu;
- }
- }
- }
-
- ret = nouveau_object_create_(parent, engine, oclass, pclass |
- NV_GPUOBJ_CLASS, length, pobject);
- nouveau_object_ref(NULL, &parent);
- gpuobj = *pobject;
- if (ret)
- return ret;
-
- gpuobj->parent = pargpu;
- gpuobj->flags = flags;
- gpuobj->addr = addr;
- gpuobj->size = size;
-
- if (heap) {
- ret = nouveau_mm_head(heap, 0, 1, size, size,
- max(align, (u32)1), &gpuobj->node);
- if (ret)
- return ret;
-
- gpuobj->addr += gpuobj->node->offset;
- }
-
- if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
- ret = nouveau_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
- if (ret)
- return ret;
- }
-
- if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
- for (i = 0; i < gpuobj->size; i += 4)
- nv_wo32(gpuobj, i, 0x00000000);
- }
-
- return ret;
-}
-
-struct nouveau_gpuobj_class {
- struct nouveau_object *pargpu;
- u64 size;
- u32 align;
- u32 flags;
-};
-
-static int
-_nouveau_gpuobj_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj_class *args = data;
- struct nouveau_gpuobj *object;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
- args->size, args->align, args->flags,
- &object);
- *pobject = nv_object(object);
- if (ret)
- return ret;
-
- return 0;
-}
-
-void
-_nouveau_gpuobj_dtor(struct nouveau_object *object)
-{
- nouveau_gpuobj_destroy(nv_gpuobj(object));
-}
-
-int
-_nouveau_gpuobj_init(struct nouveau_object *object)
-{
- return nouveau_gpuobj_init(nv_gpuobj(object));
-}
-
-int
-_nouveau_gpuobj_fini(struct nouveau_object *object, bool suspend)
-{
- return nouveau_gpuobj_fini(nv_gpuobj(object), suspend);
-}
-
-u32
-_nouveau_gpuobj_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
- struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
- if (gpuobj->node)
- addr += gpuobj->node->offset;
- return pfuncs->rd32(gpuobj->parent, addr);
-}
-
-void
-_nouveau_gpuobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_gpuobj *gpuobj = nv_gpuobj(object);
- struct nouveau_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
- if (gpuobj->node)
- addr += gpuobj->node->offset;
- pfuncs->wr32(gpuobj->parent, addr, data);
-}
-
-static struct nouveau_oclass
-_nouveau_gpuobj_oclass = {
- .handle = 0x00000000,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_gpuobj_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
- },
-};
-
-int
-nouveau_gpuobj_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
- u32 size, u32 align, u32 flags,
- struct nouveau_gpuobj **pgpuobj)
-{
- struct nouveau_object *engine = parent;
- struct nouveau_gpuobj_class args = {
- .pargpu = pargpu,
- .size = size,
- .align = align,
- .flags = flags,
- };
-
- if (!nv_iclass(engine, NV_SUBDEV_CLASS))
- engine = engine->engine;
- BUG_ON(engine == NULL);
-
- return nouveau_object_ctor(parent, engine, &_nouveau_gpuobj_oclass,
- &args, sizeof(args),
- (struct nouveau_object **)pgpuobj);
-}
-
-int
-nouveau_gpuobj_map(struct nouveau_gpuobj *gpuobj, u32 access,
- struct nouveau_vma *vma)
-{
- struct nouveau_bar *bar = nouveau_bar(gpuobj);
- int ret = -EINVAL;
-
- if (bar && bar->umap) {
- struct nouveau_instobj *iobj = (void *)
- nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
- struct nouveau_mem **mem = (void *)(iobj + 1);
- ret = bar->umap(bar, *mem, access, vma);
- }
-
- return ret;
-}
-
-int
-nouveau_gpuobj_map_vm(struct nouveau_gpuobj *gpuobj, struct nouveau_vm *vm,
- u32 access, struct nouveau_vma *vma)
-{
- struct nouveau_instobj *iobj = (void *)
- nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
- struct nouveau_mem **mem = (void *)(iobj + 1);
- int ret;
-
- ret = nouveau_vm_get(vm, gpuobj->size, 12, access, vma);
- if (ret)
- return ret;
-
- nouveau_vm_map(vma, *mem);
- return 0;
-}
-
-void
-nouveau_gpuobj_unmap(struct nouveau_vma *vma)
-{
- if (vma->node) {
- nouveau_vm_unmap(vma);
- nouveau_vm_put(vma);
- }
-}
-
-/* the below is basically only here to support sharing the paged dma object
- * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
- * anywhere else.
- */
-
-static void
-nouveau_gpudup_dtor(struct nouveau_object *object)
-{
- struct nouveau_gpuobj *gpuobj = (void *)object;
- nouveau_object_ref(NULL, &gpuobj->parent);
- nouveau_object_destroy(&gpuobj->base);
-}
-
-static struct nouveau_oclass
-nouveau_gpudup_oclass = {
- .handle = NV_GPUOBJ_CLASS,
- .ofuncs = &(struct nouveau_ofuncs) {
- .dtor = nouveau_gpudup_dtor,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- },
-};
-
-int
-nouveau_gpuobj_dup(struct nouveau_object *parent, struct nouveau_gpuobj *base,
- struct nouveau_gpuobj **pgpuobj)
-{
- struct nouveau_gpuobj *gpuobj;
- int ret;
-
- ret = nouveau_object_create(parent, parent->engine,
- &nouveau_gpudup_oclass, 0, &gpuobj);
- *pgpuobj = gpuobj;
- if (ret)
- return ret;
-
- nouveau_object_ref(nv_object(base), &gpuobj->parent);
- gpuobj->addr = base->addr;
- gpuobj->size = base->size;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/handle.c b/drivers/gpu/drm/nouveau/core/core/handle.c
deleted file mode 100644
index 13f816cb08bd..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/handle.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/handle.h>
-#include <core/client.h>
-
-#define hprintk(h,l,f,a...) do { \
- struct nouveau_client *c = nouveau_client((h)->object); \
- struct nouveau_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \
- nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \
-} while(0)
-
-int
-nouveau_handle_init(struct nouveau_handle *handle)
-{
- struct nouveau_handle *item;
- int ret;
-
- hprintk(handle, TRACE, "init running\n");
- ret = nouveau_object_inc(handle->object);
- if (ret)
- return ret;
-
- hprintk(handle, TRACE, "init children\n");
- list_for_each_entry(item, &handle->tree, head) {
- ret = nouveau_handle_init(item);
- if (ret)
- goto fail;
- }
-
- hprintk(handle, TRACE, "init completed\n");
- return 0;
-fail:
- hprintk(handle, ERROR, "init failed with %d\n", ret);
- list_for_each_entry_continue_reverse(item, &handle->tree, head) {
- nouveau_handle_fini(item, false);
- }
-
- nouveau_object_dec(handle->object, false);
- return ret;
-}
-
-int
-nouveau_handle_fini(struct nouveau_handle *handle, bool suspend)
-{
- static char *name[2] = { "fini", "suspend" };
- struct nouveau_handle *item;
- int ret;
-
- hprintk(handle, TRACE, "%s children\n", name[suspend]);
- list_for_each_entry(item, &handle->tree, head) {
- ret = nouveau_handle_fini(item, suspend);
- if (ret && suspend)
- goto fail;
- }
-
- hprintk(handle, TRACE, "%s running\n", name[suspend]);
- if (handle->object) {
- ret = nouveau_object_dec(handle->object, suspend);
- if (ret && suspend)
- goto fail;
- }
-
- hprintk(handle, TRACE, "%s completed\n", name[suspend]);
- return 0;
-fail:
- hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
- list_for_each_entry_continue_reverse(item, &handle->tree, head) {
- int rret = nouveau_handle_init(item);
- if (rret)
- hprintk(handle, FATAL, "failed to restart, %d\n", rret);
- }
-
- return ret;
-}
-
-int
-nouveau_handle_create(struct nouveau_object *parent, u32 _parent, u32 _handle,
- struct nouveau_object *object,
- struct nouveau_handle **phandle)
-{
- struct nouveau_object *namedb;
- struct nouveau_handle *handle;
- int ret;
-
- namedb = parent;
- while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
- namedb = namedb->parent;
-
- handle = kzalloc(sizeof(*handle), GFP_KERNEL);
- if (!handle)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&handle->head);
- INIT_LIST_HEAD(&handle->tree);
- handle->name = _handle;
- handle->priv = ~0;
-
- ret = nouveau_namedb_insert(nv_namedb(namedb), _handle, object, handle);
- if (ret) {
- kfree(handle);
- return ret;
- }
-
- if (nv_parent(parent)->object_attach) {
- ret = nv_parent(parent)->object_attach(parent, object, _handle);
- if (ret < 0) {
- nouveau_handle_destroy(handle);
- return ret;
- }
-
- handle->priv = ret;
- }
-
- if (object != namedb) {
- while (!nv_iclass(namedb, NV_CLIENT_CLASS))
- namedb = namedb->parent;
-
- handle->parent = nouveau_namedb_get(nv_namedb(namedb), _parent);
- if (handle->parent) {
- list_add(&handle->head, &handle->parent->tree);
- nouveau_namedb_put(handle->parent);
- }
- }
-
- hprintk(handle, TRACE, "created\n");
- *phandle = handle;
- return 0;
-}
-
-void
-nouveau_handle_destroy(struct nouveau_handle *handle)
-{
- struct nouveau_handle *item, *temp;
-
- hprintk(handle, TRACE, "destroy running\n");
- list_for_each_entry_safe(item, temp, &handle->tree, head) {
- nouveau_handle_destroy(item);
- }
- list_del(&handle->head);
-
- if (handle->priv != ~0) {
- struct nouveau_object *parent = handle->parent->object;
- nv_parent(parent)->object_detach(parent, handle->priv);
- }
-
- hprintk(handle, TRACE, "destroy completed\n");
- nouveau_namedb_remove(handle);
- kfree(handle);
-}
-
-struct nouveau_object *
-nouveau_handle_ref(struct nouveau_object *parent, u32 name)
-{
- struct nouveau_object *object = NULL;
- struct nouveau_handle *handle;
-
- while (!nv_iclass(parent, NV_NAMEDB_CLASS))
- parent = parent->parent;
-
- handle = nouveau_namedb_get(nv_namedb(parent), name);
- if (handle) {
- nouveau_object_ref(handle->object, &object);
- nouveau_namedb_put(handle);
- }
-
- return object;
-}
-
-struct nouveau_handle *
-nouveau_handle_get_class(struct nouveau_object *engctx, u16 oclass)
-{
- struct nouveau_namedb *namedb;
- if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
- return nouveau_namedb_get_class(namedb, oclass);
- return NULL;
-}
-
-struct nouveau_handle *
-nouveau_handle_get_vinst(struct nouveau_object *engctx, u64 vinst)
-{
- struct nouveau_namedb *namedb;
- if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
- return nouveau_namedb_get_vinst(namedb, vinst);
- return NULL;
-}
-
-struct nouveau_handle *
-nouveau_handle_get_cinst(struct nouveau_object *engctx, u32 cinst)
-{
- struct nouveau_namedb *namedb;
- if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
- return nouveau_namedb_get_cinst(namedb, cinst);
- return NULL;
-}
-
-void
-nouveau_handle_put(struct nouveau_handle *handle)
-{
- if (handle)
- nouveau_namedb_put(handle);
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/ioctl.c b/drivers/gpu/drm/nouveau/core/core/ioctl.c
deleted file mode 100644
index 692aa92dd850..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/ioctl.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <core/object.h>
-#include <core/parent.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-#include <core/client.h>
-#include <core/device.h>
-#include <core/ioctl.h>
-#include <core/event.h>
-
-#include <nvif/unpack.h>
-#include <nvif/ioctl.h>
-
-static int
-nvkm_ioctl_nop(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_nop none;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "nop size %d\n", size);
- if (nvif_unvers(args->none)) {
- nv_ioctl(object, "nop\n");
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_sclass(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_sclass_v0 v0;
- } *args = data;
- int ret;
-
- if (!nv_iclass(object, NV_PARENT_CLASS)) {
- nv_debug(object, "cannot have children (sclass)\n");
- return -ENODEV;
- }
-
- nv_ioctl(object, "sclass size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "sclass vers %d count %d\n",
- args->v0.version, args->v0.count);
- if (size == args->v0.count * sizeof(args->v0.oclass[0])) {
- ret = nouveau_parent_lclass(object, args->v0.oclass,
- args->v0.count);
- if (ret >= 0) {
- args->v0.count = ret;
- ret = 0;
- }
- } else {
- ret = -EINVAL;
- }
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_new(struct nouveau_handle *parent, void *data, u32 size)
-{
- union {
- struct nvif_ioctl_new_v0 v0;
- } *args = data;
- struct nouveau_client *client = nouveau_client(parent->object);
- struct nouveau_object *engctx = NULL;
- struct nouveau_object *object = NULL;
- struct nouveau_object *engine;
- struct nouveau_oclass *oclass;
- struct nouveau_handle *handle;
- u32 _handle, _oclass;
- int ret;
-
- nv_ioctl(client, "new size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- _handle = args->v0.handle;
- _oclass = args->v0.oclass;
- } else
- return ret;
-
- nv_ioctl(client, "new vers %d handle %08x class %08x "
- "route %02x token %llx\n",
- args->v0.version, _handle, _oclass,
- args->v0.route, args->v0.token);
-
- if (!nv_iclass(parent->object, NV_PARENT_CLASS)) {
- nv_debug(parent->object, "cannot have children (ctor)\n");
- ret = -ENODEV;
- goto fail_class;
- }
-
- /* check that parent supports the requested subclass */
- ret = nouveau_parent_sclass(parent->object, _oclass, &engine, &oclass);
- if (ret) {
- nv_debug(parent->object, "illegal class 0x%04x\n", _oclass);
- goto fail_class;
- }
-
- /* make sure engine init has been completed *before* any objects
- * it controls are created - the constructors may depend on
- * state calculated at init (ie. default context construction)
- */
- if (engine) {
- ret = nouveau_object_inc(engine);
- if (ret)
- goto fail_class;
- }
-
- /* if engine requires it, create a context object to insert
- * between the parent and its children (eg. PGRAPH context)
- */
- if (engine && nv_engine(engine)->cclass) {
- ret = nouveau_object_ctor(parent->object, engine,
- nv_engine(engine)->cclass,
- data, size, &engctx);
- if (ret)
- goto fail_engctx;
- } else {
- nouveau_object_ref(parent->object, &engctx);
- }
-
- /* finally, create new object and bind it to its handle */
- ret = nouveau_object_ctor(engctx, engine, oclass, data, size, &object);
- client->data = object;
- if (ret)
- goto fail_ctor;
-
- ret = nouveau_object_inc(object);
- if (ret)
- goto fail_init;
-
- ret = nouveau_handle_create(parent->object, parent->name,
- _handle, object, &handle);
- if (ret)
- goto fail_handle;
-
- ret = nouveau_handle_init(handle);
- handle->route = args->v0.route;
- handle->token = args->v0.token;
- if (ret)
- nouveau_handle_destroy(handle);
-
-fail_handle:
- nouveau_object_dec(object, false);
-fail_init:
- nouveau_object_ref(NULL, &object);
-fail_ctor:
- nouveau_object_ref(NULL, &engctx);
-fail_engctx:
- if (engine)
- nouveau_object_dec(engine, false);
-fail_class:
- return ret;
-}
-
-static int
-nvkm_ioctl_del(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_del none;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "delete size %d\n", size);
- if (nvif_unvers(args->none)) {
- nv_ioctl(object, "delete\n");
- nouveau_handle_fini(handle, false);
- nouveau_handle_destroy(handle);
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_mthd(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
- union {
- struct nvif_ioctl_mthd_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "mthd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "mthd vers %d mthd %02x\n",
- args->v0.version, args->v0.method);
- if (ret = -ENODEV, ofuncs->mthd)
- ret = ofuncs->mthd(object, args->v0.method, data, size);
- }
-
- return ret;
-}
-
-
-static int
-nvkm_ioctl_rd(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
- union {
- struct nvif_ioctl_rd_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "rd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "rd vers %d size %d addr %016llx\n",
- args->v0.version, args->v0.size, args->v0.addr);
- switch (args->v0.size) {
- case 1:
- if (ret = -ENODEV, ofuncs->rd08) {
- args->v0.data = nv_ro08(object, args->v0.addr);
- ret = 0;
- }
- break;
- case 2:
- if (ret = -ENODEV, ofuncs->rd16) {
- args->v0.data = nv_ro16(object, args->v0.addr);
- ret = 0;
- }
- break;
- case 4:
- if (ret = -ENODEV, ofuncs->rd32) {
- args->v0.data = nv_ro32(object, args->v0.addr);
- ret = 0;
- }
- break;
- default:
- ret = -EINVAL;
- break;
- }
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_wr(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
- union {
- struct nvif_ioctl_wr_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "wr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n",
- args->v0.version, args->v0.size, args->v0.addr,
- args->v0.data);
- switch (args->v0.size) {
- case 1:
- if (ret = -ENODEV, ofuncs->wr08) {
- nv_wo08(object, args->v0.addr, args->v0.data);
- ret = 0;
- }
- break;
- case 2:
- if (ret = -ENODEV, ofuncs->wr16) {
- nv_wo16(object, args->v0.addr, args->v0.data);
- ret = 0;
- }
- break;
- case 4:
- if (ret = -ENODEV, ofuncs->wr32) {
- nv_wo32(object, args->v0.addr, args->v0.data);
- ret = 0;
- }
- break;
- default:
- ret = -EINVAL;
- break;
- }
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_map(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
- union {
- struct nvif_ioctl_map_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "map size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "map vers %d\n", args->v0.version);
- if (ret = -ENODEV, ofuncs->map) {
- ret = ofuncs->map(object, &args->v0.handle,
- &args->v0.length);
- }
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_unmap(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_unmap none;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "unmap size %d\n", size);
- if (nvif_unvers(args->none)) {
- nv_ioctl(object, "unmap\n");
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_new(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_object *object = handle->object;
- struct nouveau_ofuncs *ofuncs = object->oclass->ofuncs;
- union {
- struct nvif_ioctl_ntfy_new_v0 v0;
- } *args = data;
- struct nvkm_event *event;
- int ret;
-
- nv_ioctl(object, "ntfy new size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "ntfy new vers %d event %02x\n",
- args->v0.version, args->v0.event);
- if (ret = -ENODEV, ofuncs->ntfy)
- ret = ofuncs->ntfy(object, args->v0.event, &event);
- if (ret == 0) {
- ret = nvkm_client_notify_new(object, event, data, size);
- if (ret >= 0) {
- args->v0.index = ret;
- ret = 0;
- }
- }
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_del(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_client *client = nouveau_client(handle->object);
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_ntfy_del_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "ntfy del size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "ntfy del vers %d index %d\n",
- args->v0.version, args->v0.index);
- ret = nvkm_client_notify_del(client, args->v0.index);
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_get(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_client *client = nouveau_client(handle->object);
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_ntfy_get_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "ntfy get size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "ntfy get vers %d index %d\n",
- args->v0.version, args->v0.index);
- ret = nvkm_client_notify_get(client, args->v0.index);
- }
-
- return ret;
-}
-
-static int
-nvkm_ioctl_ntfy_put(struct nouveau_handle *handle, void *data, u32 size)
-{
- struct nouveau_client *client = nouveau_client(handle->object);
- struct nouveau_object *object = handle->object;
- union {
- struct nvif_ioctl_ntfy_put_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "ntfy put size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "ntfy put vers %d index %d\n",
- args->v0.version, args->v0.index);
- ret = nvkm_client_notify_put(client, args->v0.index);
- }
-
- return ret;
-}
-
-static struct {
- int version;
- int (*func)(struct nouveau_handle *, void *, u32);
-}
-nvkm_ioctl_v0[] = {
- { 0x00, nvkm_ioctl_nop },
- { 0x00, nvkm_ioctl_sclass },
- { 0x00, nvkm_ioctl_new },
- { 0x00, nvkm_ioctl_del },
- { 0x00, nvkm_ioctl_mthd },
- { 0x00, nvkm_ioctl_rd },
- { 0x00, nvkm_ioctl_wr },
- { 0x00, nvkm_ioctl_map },
- { 0x00, nvkm_ioctl_unmap },
- { 0x00, nvkm_ioctl_ntfy_new },
- { 0x00, nvkm_ioctl_ntfy_del },
- { 0x00, nvkm_ioctl_ntfy_get },
- { 0x00, nvkm_ioctl_ntfy_put },
-};
-
-static int
-nvkm_ioctl_path(struct nouveau_handle *parent, u32 type, u32 nr,
- u32 *path, void *data, u32 size,
- u8 owner, u8 *route, u64 *token)
-{
- struct nouveau_handle *handle = parent;
- struct nouveau_namedb *namedb;
- struct nouveau_object *object;
- int ret;
-
- while ((object = parent->object), nr--) {
- nv_ioctl(object, "path 0x%08x\n", path[nr]);
- if (!nv_iclass(object, NV_PARENT_CLASS)) {
- nv_debug(object, "cannot have children (path)\n");
- return -EINVAL;
- }
-
- if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
- !(handle = nouveau_namedb_get(namedb, path[nr]))) {
- nv_debug(object, "handle 0x%08x not found\n", path[nr]);
- return -ENOENT;
- }
- nouveau_namedb_put(handle);
- parent = handle;
- }
-
- if (owner != NVIF_IOCTL_V0_OWNER_ANY &&
- owner != handle->route) {
- nv_ioctl(object, "object route != owner\n");
- return -EACCES;
- }
- *route = handle->route;
- *token = handle->token;
-
- if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
- if (nvkm_ioctl_v0[type].version == 0) {
- ret = nvkm_ioctl_v0[type].func(handle, data, size);
- }
- }
-
- return ret;
-}
-
-int
-nvkm_ioctl(struct nouveau_client *client, bool supervisor,
- void *data, u32 size, void **hack)
-{
- union {
- struct nvif_ioctl_v0 v0;
- } *args = data;
- int ret;
-
- client->super = supervisor;
- nv_ioctl(client, "size %d\n", size);
-
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",
- args->v0.version, args->v0.type, args->v0.path_nr,
- args->v0.owner);
- ret = nvkm_ioctl_path(client->root, args->v0.type,
- args->v0.path_nr, args->v0.path,
- data, size, args->v0.owner,
- &args->v0.route, &args->v0.token);
- }
-
- nv_ioctl(client, "return %d\n", ret);
- if (hack) {
- *hack = client->data;
- client->data = NULL;
- }
- client->super = false;
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/mm.c b/drivers/gpu/drm/nouveau/core/core/mm.c
deleted file mode 100644
index b4f5db66d5b5..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/mm.c
+++ /dev/null
@@ -1,303 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "core/os.h"
-#include "core/mm.h"
-
-#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
- list_entry((root)->nl_entry.dir, struct nouveau_mm_node, nl_entry)
-
-static void
-nouveau_mm_dump(struct nouveau_mm *mm, const char *header)
-{
- struct nouveau_mm_node *node;
-
- printk(KERN_ERR "nouveau: %s\n", header);
- printk(KERN_ERR "nouveau: node list:\n");
- list_for_each_entry(node, &mm->nodes, nl_entry) {
- printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
- node->offset, node->length, node->type);
- }
- printk(KERN_ERR "nouveau: free list:\n");
- list_for_each_entry(node, &mm->free, fl_entry) {
- printk(KERN_ERR "nouveau: \t%08x %08x %d\n",
- node->offset, node->length, node->type);
- }
-}
-
-void
-nouveau_mm_free(struct nouveau_mm *mm, struct nouveau_mm_node **pthis)
-{
- struct nouveau_mm_node *this = *pthis;
-
- if (this) {
- struct nouveau_mm_node *prev = node(this, prev);
- struct nouveau_mm_node *next = node(this, next);
-
- if (prev && prev->type == NVKM_MM_TYPE_NONE) {
- prev->length += this->length;
- list_del(&this->nl_entry);
- kfree(this); this = prev;
- }
-
- if (next && next->type == NVKM_MM_TYPE_NONE) {
- next->offset = this->offset;
- next->length += this->length;
- if (this->type == NVKM_MM_TYPE_NONE)
- list_del(&this->fl_entry);
- list_del(&this->nl_entry);
- kfree(this); this = NULL;
- }
-
- if (this && this->type != NVKM_MM_TYPE_NONE) {
- list_for_each_entry(prev, &mm->free, fl_entry) {
- if (this->offset < prev->offset)
- break;
- }
-
- list_add_tail(&this->fl_entry, &prev->fl_entry);
- this->type = NVKM_MM_TYPE_NONE;
- }
- }
-
- *pthis = NULL;
-}
-
-static struct nouveau_mm_node *
-region_head(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
-{
- struct nouveau_mm_node *b;
-
- if (a->length == size)
- return a;
-
- b = kmalloc(sizeof(*b), GFP_KERNEL);
- if (unlikely(b == NULL))
- return NULL;
-
- b->offset = a->offset;
- b->length = size;
- b->heap = a->heap;
- b->type = a->type;
- a->offset += size;
- a->length -= size;
- list_add_tail(&b->nl_entry, &a->nl_entry);
- if (b->type == NVKM_MM_TYPE_NONE)
- list_add_tail(&b->fl_entry, &a->fl_entry);
- return b;
-}
-
-int
-nouveau_mm_head(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
- u32 size_min, u32 align, struct nouveau_mm_node **pnode)
-{
- struct nouveau_mm_node *prev, *this, *next;
- u32 mask = align - 1;
- u32 splitoff;
- u32 s, e;
-
- BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
-
- list_for_each_entry(this, &mm->free, fl_entry) {
- if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
- if (this->heap != heap)
- continue;
- }
- e = this->offset + this->length;
- s = this->offset;
-
- prev = node(this, prev);
- if (prev && prev->type != type)
- s = roundup(s, mm->block_size);
-
- next = node(this, next);
- if (next && next->type != type)
- e = rounddown(e, mm->block_size);
-
- s = (s + mask) & ~mask;
- e &= ~mask;
- if (s > e || e - s < size_min)
- continue;
-
- splitoff = s - this->offset;
- if (splitoff && !region_head(mm, this, splitoff))
- return -ENOMEM;
-
- this = region_head(mm, this, min(size_max, e - s));
- if (!this)
- return -ENOMEM;
-
- this->type = type;
- list_del(&this->fl_entry);
- *pnode = this;
- return 0;
- }
-
- return -ENOSPC;
-}
-
-static struct nouveau_mm_node *
-region_tail(struct nouveau_mm *mm, struct nouveau_mm_node *a, u32 size)
-{
- struct nouveau_mm_node *b;
-
- if (a->length == size)
- return a;
-
- b = kmalloc(sizeof(*b), GFP_KERNEL);
- if (unlikely(b == NULL))
- return NULL;
-
- a->length -= size;
- b->offset = a->offset + a->length;
- b->length = size;
- b->heap = a->heap;
- b->type = a->type;
-
- list_add(&b->nl_entry, &a->nl_entry);
- if (b->type == NVKM_MM_TYPE_NONE)
- list_add(&b->fl_entry, &a->fl_entry);
- return b;
-}
-
-int
-nouveau_mm_tail(struct nouveau_mm *mm, u8 heap, u8 type, u32 size_max,
- u32 size_min, u32 align, struct nouveau_mm_node **pnode)
-{
- struct nouveau_mm_node *prev, *this, *next;
- u32 mask = align - 1;
-
- BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
-
- list_for_each_entry_reverse(this, &mm->free, fl_entry) {
- u32 e = this->offset + this->length;
- u32 s = this->offset;
- u32 c = 0, a;
- if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
- if (this->heap != heap)
- continue;
- }
-
- prev = node(this, prev);
- if (prev && prev->type != type)
- s = roundup(s, mm->block_size);
-
- next = node(this, next);
- if (next && next->type != type) {
- e = rounddown(e, mm->block_size);
- c = next->offset - e;
- }
-
- s = (s + mask) & ~mask;
- a = e - s;
- if (s > e || a < size_min)
- continue;
-
- a = min(a, size_max);
- s = (e - a) & ~mask;
- c += (e - s) - a;
-
- if (c && !region_tail(mm, this, c))
- return -ENOMEM;
-
- this = region_tail(mm, this, a);
- if (!this)
- return -ENOMEM;
-
- this->type = type;
- list_del(&this->fl_entry);
- *pnode = this;
- return 0;
- }
-
- return -ENOSPC;
-}
-
-int
-nouveau_mm_init(struct nouveau_mm *mm, u32 offset, u32 length, u32 block)
-{
- struct nouveau_mm_node *node, *prev;
- u32 next;
-
- if (nouveau_mm_initialised(mm)) {
- prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
- next = prev->offset + prev->length;
- if (next != offset) {
- BUG_ON(next > offset);
- if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
- return -ENOMEM;
- node->type = NVKM_MM_TYPE_HOLE;
- node->offset = next;
- node->length = offset - next;
- list_add_tail(&node->nl_entry, &mm->nodes);
- }
- BUG_ON(block != mm->block_size);
- } else {
- INIT_LIST_HEAD(&mm->nodes);
- INIT_LIST_HEAD(&mm->free);
- mm->block_size = block;
- mm->heap_nodes = 0;
- }
-
- node = kzalloc(sizeof(*node), GFP_KERNEL);
- if (!node)
- return -ENOMEM;
-
- if (length) {
- node->offset = roundup(offset, mm->block_size);
- node->length = rounddown(offset + length, mm->block_size);
- node->length -= node->offset;
- }
-
- list_add_tail(&node->nl_entry, &mm->nodes);
- list_add_tail(&node->fl_entry, &mm->free);
- node->heap = ++mm->heap_nodes;
- return 0;
-}
-
-int
-nouveau_mm_fini(struct nouveau_mm *mm)
-{
- struct nouveau_mm_node *node, *temp;
- int nodes = 0;
-
- if (!nouveau_mm_initialised(mm))
- return 0;
-
- list_for_each_entry(node, &mm->nodes, nl_entry) {
- if (node->type != NVKM_MM_TYPE_HOLE) {
- if (++nodes > mm->heap_nodes) {
- nouveau_mm_dump(mm, "mm not clean!");
- return -EBUSY;
- }
- }
- }
-
- list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
- list_del(&node->nl_entry);
- kfree(node);
- }
- mm->heap_nodes = 0;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/namedb.c b/drivers/gpu/drm/nouveau/core/core/namedb.c
deleted file mode 100644
index 0594a599f6fb..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/namedb.c
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/gpuobj.h>
-
-static struct nouveau_handle *
-nouveau_namedb_lookup(struct nouveau_namedb *namedb, u32 name)
-{
- struct nouveau_handle *handle;
-
- list_for_each_entry(handle, &namedb->list, node) {
- if (handle->name == name)
- return handle;
- }
-
- return NULL;
-}
-
-static struct nouveau_handle *
-nouveau_namedb_lookup_class(struct nouveau_namedb *namedb, u16 oclass)
-{
- struct nouveau_handle *handle;
-
- list_for_each_entry(handle, &namedb->list, node) {
- if (nv_mclass(handle->object) == oclass)
- return handle;
- }
-
- return NULL;
-}
-
-static struct nouveau_handle *
-nouveau_namedb_lookup_vinst(struct nouveau_namedb *namedb, u64 vinst)
-{
- struct nouveau_handle *handle;
-
- list_for_each_entry(handle, &namedb->list, node) {
- if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
- if (nv_gpuobj(handle->object)->addr == vinst)
- return handle;
- }
- }
-
- return NULL;
-}
-
-static struct nouveau_handle *
-nouveau_namedb_lookup_cinst(struct nouveau_namedb *namedb, u32 cinst)
-{
- struct nouveau_handle *handle;
-
- list_for_each_entry(handle, &namedb->list, node) {
- if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
- if (nv_gpuobj(handle->object)->node &&
- nv_gpuobj(handle->object)->node->offset == cinst)
- return handle;
- }
- }
-
- return NULL;
-}
-
-int
-nouveau_namedb_insert(struct nouveau_namedb *namedb, u32 name,
- struct nouveau_object *object,
- struct nouveau_handle *handle)
-{
- int ret = -EEXIST;
- write_lock_irq(&namedb->lock);
- if (!nouveau_namedb_lookup(namedb, name)) {
- nouveau_object_ref(object, &handle->object);
- handle->namedb = namedb;
- list_add(&handle->node, &namedb->list);
- ret = 0;
- }
- write_unlock_irq(&namedb->lock);
- return ret;
-}
-
-void
-nouveau_namedb_remove(struct nouveau_handle *handle)
-{
- struct nouveau_namedb *namedb = handle->namedb;
- struct nouveau_object *object = handle->object;
- write_lock_irq(&namedb->lock);
- list_del(&handle->node);
- write_unlock_irq(&namedb->lock);
- nouveau_object_ref(NULL, &object);
-}
-
-struct nouveau_handle *
-nouveau_namedb_get(struct nouveau_namedb *namedb, u32 name)
-{
- struct nouveau_handle *handle;
- read_lock(&namedb->lock);
- handle = nouveau_namedb_lookup(namedb, name);
- if (handle == NULL)
- read_unlock(&namedb->lock);
- return handle;
-}
-
-struct nouveau_handle *
-nouveau_namedb_get_class(struct nouveau_namedb *namedb, u16 oclass)
-{
- struct nouveau_handle *handle;
- read_lock(&namedb->lock);
- handle = nouveau_namedb_lookup_class(namedb, oclass);
- if (handle == NULL)
- read_unlock(&namedb->lock);
- return handle;
-}
-
-struct nouveau_handle *
-nouveau_namedb_get_vinst(struct nouveau_namedb *namedb, u64 vinst)
-{
- struct nouveau_handle *handle;
- read_lock(&namedb->lock);
- handle = nouveau_namedb_lookup_vinst(namedb, vinst);
- if (handle == NULL)
- read_unlock(&namedb->lock);
- return handle;
-}
-
-struct nouveau_handle *
-nouveau_namedb_get_cinst(struct nouveau_namedb *namedb, u32 cinst)
-{
- struct nouveau_handle *handle;
- read_lock(&namedb->lock);
- handle = nouveau_namedb_lookup_cinst(namedb, cinst);
- if (handle == NULL)
- read_unlock(&namedb->lock);
- return handle;
-}
-
-void
-nouveau_namedb_put(struct nouveau_handle *handle)
-{
- if (handle)
- read_unlock(&handle->namedb->lock);
-}
-
-int
-nouveau_namedb_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pclass,
- struct nouveau_oclass *sclass, u64 engcls,
- int length, void **pobject)
-{
- struct nouveau_namedb *namedb;
- int ret;
-
- ret = nouveau_parent_create_(parent, engine, oclass, pclass |
- NV_NAMEDB_CLASS, sclass, engcls,
- length, pobject);
- namedb = *pobject;
- if (ret)
- return ret;
-
- rwlock_init(&namedb->lock);
- INIT_LIST_HEAD(&namedb->list);
- return 0;
-}
-
-int
-_nouveau_namedb_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_namedb *object;
- int ret;
-
- ret = nouveau_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
- *pobject = nv_object(object);
- if (ret)
- return ret;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/notify.c b/drivers/gpu/drm/nouveau/core/core/notify.c
deleted file mode 100644
index 839a32577680..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/notify.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <core/client.h>
-#include <core/event.h>
-#include <core/notify.h>
-
-#include <nvif/unpack.h>
-#include <nvif/event.h>
-
-static inline void
-nvkm_notify_put_locked(struct nvkm_notify *notify)
-{
- if (notify->block++ == 0)
- nvkm_event_put(notify->event, notify->types, notify->index);
-}
-
-void
-nvkm_notify_put(struct nvkm_notify *notify)
-{
- struct nvkm_event *event = notify->event;
- unsigned long flags;
- if (likely(event) &&
- test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
- spin_lock_irqsave(&event->refs_lock, flags);
- nvkm_notify_put_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
- if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
- flush_work(&notify->work);
- }
-}
-
-static inline void
-nvkm_notify_get_locked(struct nvkm_notify *notify)
-{
- if (--notify->block == 0)
- nvkm_event_get(notify->event, notify->types, notify->index);
-}
-
-void
-nvkm_notify_get(struct nvkm_notify *notify)
-{
- struct nvkm_event *event = notify->event;
- unsigned long flags;
- if (likely(event) &&
- !test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
- spin_lock_irqsave(&event->refs_lock, flags);
- nvkm_notify_get_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
- }
-}
-
-static inline void
-nvkm_notify_func(struct nvkm_notify *notify)
-{
- struct nvkm_event *event = notify->event;
- int ret = notify->func(notify);
- unsigned long flags;
- if ((ret == NVKM_NOTIFY_KEEP) ||
- !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
- spin_lock_irqsave(&event->refs_lock, flags);
- nvkm_notify_get_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
- }
-}
-
-static void
-nvkm_notify_work(struct work_struct *work)
-{
- struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
- nvkm_notify_func(notify);
-}
-
-void
-nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
-{
- struct nvkm_event *event = notify->event;
- unsigned long flags;
-
- assert_spin_locked(&event->list_lock);
- BUG_ON(size != notify->size);
-
- spin_lock_irqsave(&event->refs_lock, flags);
- if (notify->block) {
- spin_unlock_irqrestore(&event->refs_lock, flags);
- return;
- }
- nvkm_notify_put_locked(notify);
- spin_unlock_irqrestore(&event->refs_lock, flags);
-
- if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
- memcpy((void *)notify->data, data, size);
- schedule_work(&notify->work);
- } else {
- notify->data = data;
- nvkm_notify_func(notify);
- notify->data = NULL;
- }
-}
-
-void
-nvkm_notify_fini(struct nvkm_notify *notify)
-{
- unsigned long flags;
- if (notify->event) {
- nvkm_notify_put(notify);
- spin_lock_irqsave(&notify->event->list_lock, flags);
- list_del(&notify->head);
- spin_unlock_irqrestore(&notify->event->list_lock, flags);
- kfree((void *)notify->data);
- notify->event = NULL;
- }
-}
-
-int
-nvkm_notify_init(struct nouveau_object *object, struct nvkm_event *event,
- int (*func)(struct nvkm_notify *), bool work,
- void *data, u32 size, u32 reply,
- struct nvkm_notify *notify)
-{
- unsigned long flags;
- int ret = -ENODEV;
- if ((notify->event = event), event->refs) {
- ret = event->func->ctor(object, data, size, notify);
- if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
- notify->flags = 0;
- notify->block = 1;
- notify->func = func;
- notify->data = NULL;
- if (ret = 0, work) {
- INIT_WORK(&notify->work, nvkm_notify_work);
- set_bit(NVKM_NOTIFY_WORK, &notify->flags);
- notify->data = kmalloc(reply, GFP_KERNEL);
- if (!notify->data)
- ret = -ENOMEM;
- }
- }
- if (ret == 0) {
- spin_lock_irqsave(&event->list_lock, flags);
- list_add_tail(&notify->head, &event->list);
- spin_unlock_irqrestore(&event->list_lock, flags);
- }
- }
- if (ret)
- notify->event = NULL;
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/object.c b/drivers/gpu/drm/nouveau/core/core/object.c
deleted file mode 100644
index b08630577c82..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/object.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/engine.h>
-
-#ifdef NOUVEAU_OBJECT_MAGIC
-static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
-static DEFINE_SPINLOCK(_objlist_lock);
-#endif
-
-int
-nouveau_object_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pclass,
- int size, void **pobject)
-{
- struct nouveau_object *object;
-
- object = *pobject = kzalloc(size, GFP_KERNEL);
- if (!object)
- return -ENOMEM;
-
- nouveau_object_ref(parent, &object->parent);
- nouveau_object_ref(engine, &object->engine);
- object->oclass = oclass;
- object->oclass->handle |= pclass;
- atomic_set(&object->refcount, 1);
- atomic_set(&object->usecount, 0);
-
-#ifdef NOUVEAU_OBJECT_MAGIC
- object->_magic = NOUVEAU_OBJECT_MAGIC;
- spin_lock(&_objlist_lock);
- list_add(&object->list, &_objlist);
- spin_unlock(&_objlist_lock);
-#endif
- return 0;
-}
-
-int
-_nouveau_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- if (size != 0)
- return -ENOSYS;
- return nouveau_object_create(parent, engine, oclass, 0, pobject);
-}
-
-void
-nouveau_object_destroy(struct nouveau_object *object)
-{
-#ifdef NOUVEAU_OBJECT_MAGIC
- spin_lock(&_objlist_lock);
- list_del(&object->list);
- spin_unlock(&_objlist_lock);
-#endif
- nouveau_object_ref(NULL, &object->engine);
- nouveau_object_ref(NULL, &object->parent);
- kfree(object);
-}
-
-int
-nouveau_object_init(struct nouveau_object *object)
-{
- return 0;
-}
-
-int
-nouveau_object_fini(struct nouveau_object *object, bool suspend)
-{
- return 0;
-}
-
-struct nouveau_ofuncs
-nouveau_object_ofuncs = {
- .ctor = _nouveau_object_ctor,
- .dtor = nouveau_object_destroy,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
-};
-
-int
-nouveau_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_ofuncs *ofuncs = oclass->ofuncs;
- struct nouveau_object *object = NULL;
- int ret;
-
- ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
- *pobject = object;
- if (ret < 0) {
- if (ret != -ENODEV) {
- nv_error(parent, "failed to create 0x%08x, %d\n",
- oclass->handle, ret);
- }
-
- if (object) {
- ofuncs->dtor(object);
- *pobject = NULL;
- }
-
- return ret;
- }
-
- if (ret == 0) {
- nv_trace(object, "created\n");
- atomic_set(&object->refcount, 1);
- }
-
- return 0;
-}
-
-static void
-nouveau_object_dtor(struct nouveau_object *object)
-{
- nv_trace(object, "destroying\n");
- nv_ofuncs(object)->dtor(object);
-}
-
-void
-nouveau_object_ref(struct nouveau_object *obj, struct nouveau_object **ref)
-{
- if (obj) {
- atomic_inc(&obj->refcount);
- nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
- }
-
- if (*ref) {
- int dead = atomic_dec_and_test(&(*ref)->refcount);
- nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
- if (dead)
- nouveau_object_dtor(*ref);
- }
-
- *ref = obj;
-}
-
-int
-nouveau_object_inc(struct nouveau_object *object)
-{
- int ref = atomic_add_return(1, &object->usecount);
- int ret;
-
- nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
- if (ref != 1)
- return 0;
-
- nv_trace(object, "initialising...\n");
- if (object->parent) {
- ret = nouveau_object_inc(object->parent);
- if (ret) {
- nv_error(object, "parent failed, %d\n", ret);
- goto fail_parent;
- }
- }
-
- if (object->engine) {
- mutex_lock(&nv_subdev(object->engine)->mutex);
- ret = nouveau_object_inc(object->engine);
- mutex_unlock(&nv_subdev(object->engine)->mutex);
- if (ret) {
- nv_error(object, "engine failed, %d\n", ret);
- goto fail_engine;
- }
- }
-
- ret = nv_ofuncs(object)->init(object);
- atomic_set(&object->usecount, 1);
- if (ret) {
- nv_error(object, "init failed, %d\n", ret);
- goto fail_self;
- }
-
- nv_trace(object, "initialised\n");
- return 0;
-
-fail_self:
- if (object->engine) {
- mutex_lock(&nv_subdev(object->engine)->mutex);
- nouveau_object_dec(object->engine, false);
- mutex_unlock(&nv_subdev(object->engine)->mutex);
- }
-fail_engine:
- if (object->parent)
- nouveau_object_dec(object->parent, false);
-fail_parent:
- atomic_dec(&object->usecount);
- return ret;
-}
-
-static int
-nouveau_object_decf(struct nouveau_object *object)
-{
- int ret;
-
- nv_trace(object, "stopping...\n");
-
- ret = nv_ofuncs(object)->fini(object, false);
- atomic_set(&object->usecount, 0);
- if (ret)
- nv_warn(object, "failed fini, %d\n", ret);
-
- if (object->engine) {
- mutex_lock(&nv_subdev(object->engine)->mutex);
- nouveau_object_dec(object->engine, false);
- mutex_unlock(&nv_subdev(object->engine)->mutex);
- }
-
- if (object->parent)
- nouveau_object_dec(object->parent, false);
-
- nv_trace(object, "stopped\n");
- return 0;
-}
-
-static int
-nouveau_object_decs(struct nouveau_object *object)
-{
- int ret, rret;
-
- nv_trace(object, "suspending...\n");
-
- ret = nv_ofuncs(object)->fini(object, true);
- atomic_set(&object->usecount, 0);
- if (ret) {
- nv_error(object, "failed suspend, %d\n", ret);
- return ret;
- }
-
- if (object->engine) {
- mutex_lock(&nv_subdev(object->engine)->mutex);
- ret = nouveau_object_dec(object->engine, true);
- mutex_unlock(&nv_subdev(object->engine)->mutex);
- if (ret) {
- nv_warn(object, "engine failed suspend, %d\n", ret);
- goto fail_engine;
- }
- }
-
- if (object->parent) {
- ret = nouveau_object_dec(object->parent, true);
- if (ret) {
- nv_warn(object, "parent failed suspend, %d\n", ret);
- goto fail_parent;
- }
- }
-
- nv_trace(object, "suspended\n");
- return 0;
-
-fail_parent:
- if (object->engine) {
- mutex_lock(&nv_subdev(object->engine)->mutex);
- rret = nouveau_object_inc(object->engine);
- mutex_unlock(&nv_subdev(object->engine)->mutex);
- if (rret)
- nv_fatal(object, "engine failed to reinit, %d\n", rret);
- }
-
-fail_engine:
- rret = nv_ofuncs(object)->init(object);
- if (rret)
- nv_fatal(object, "failed to reinit, %d\n", rret);
-
- return ret;
-}
-
-int
-nouveau_object_dec(struct nouveau_object *object, bool suspend)
-{
- int ref = atomic_add_return(-1, &object->usecount);
- int ret;
-
- nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
-
- if (ref == 0) {
- if (suspend)
- ret = nouveau_object_decs(object);
- else
- ret = nouveau_object_decf(object);
-
- if (ret) {
- atomic_inc(&object->usecount);
- return ret;
- }
- }
-
- return 0;
-}
-
-void
-nouveau_object_debug(void)
-{
-#ifdef NOUVEAU_OBJECT_MAGIC
- struct nouveau_object *object;
- if (!list_empty(&_objlist)) {
- nv_fatal(NULL, "*******************************************\n");
- nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
- nv_fatal(NULL, "*******************************************\n");
- list_for_each_entry(object, &_objlist, list) {
- nv_fatal(object, "%p/%p/%d/%d\n",
- object->parent, object->engine,
- atomic_read(&object->refcount),
- atomic_read(&object->usecount));
- }
- }
-#endif
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/option.c b/drivers/gpu/drm/nouveau/core/core/option.c
deleted file mode 100644
index 9f6fcc5f66c2..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/option.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-#include <core/debug.h>
-
-const char *
-nouveau_stropt(const char *optstr, const char *opt, int *arglen)
-{
- while (optstr && *optstr != '\0') {
- int len = strcspn(optstr, ",=");
- switch (optstr[len]) {
- case '=':
- if (!strncasecmpz(optstr, opt, len)) {
- optstr += len + 1;
- *arglen = strcspn(optstr, ",=");
- return *arglen ? optstr : NULL;
- }
- optstr++;
- break;
- case ',':
- optstr++;
- break;
- default:
- break;
- }
- optstr += len;
- }
-
- return NULL;
-}
-
-bool
-nouveau_boolopt(const char *optstr, const char *opt, bool value)
-{
- int arglen;
-
- optstr = nouveau_stropt(optstr, opt, &arglen);
- if (optstr) {
- if (!strncasecmpz(optstr, "0", arglen) ||
- !strncasecmpz(optstr, "no", arglen) ||
- !strncasecmpz(optstr, "off", arglen) ||
- !strncasecmpz(optstr, "false", arglen))
- value = false;
- else
- if (!strncasecmpz(optstr, "1", arglen) ||
- !strncasecmpz(optstr, "yes", arglen) ||
- !strncasecmpz(optstr, "on", arglen) ||
- !strncasecmpz(optstr, "true", arglen))
- value = true;
- }
-
- return value;
-}
-
-int
-nouveau_dbgopt(const char *optstr, const char *sub)
-{
- int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
-
- while (optstr) {
- int len = strcspn(optstr, ",=");
- switch (optstr[len]) {
- case '=':
- if (strncasecmpz(optstr, sub, len))
- mode = 0;
- optstr++;
- break;
- default:
- if (mode) {
- if (!strncasecmpz(optstr, "fatal", len))
- level = NV_DBG_FATAL;
- else if (!strncasecmpz(optstr, "error", len))
- level = NV_DBG_ERROR;
- else if (!strncasecmpz(optstr, "warn", len))
- level = NV_DBG_WARN;
- else if (!strncasecmpz(optstr, "info", len))
- level = NV_DBG_INFO_NORMAL;
- else if (!strncasecmpz(optstr, "debug", len))
- level = NV_DBG_DEBUG;
- else if (!strncasecmpz(optstr, "trace", len))
- level = NV_DBG_TRACE;
- else if (!strncasecmpz(optstr, "paranoia", len))
- level = NV_DBG_PARANOIA;
- else if (!strncasecmpz(optstr, "spam", len))
- level = NV_DBG_SPAM;
- }
-
- if (optstr[len] != '\0') {
- optstr++;
- mode = 1;
- break;
- }
-
- return level;
- }
- optstr += len;
- }
-
- return level;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/parent.c b/drivers/gpu/drm/nouveau/core/core/parent.c
deleted file mode 100644
index 30a2911878f8..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/parent.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/parent.h>
-#include <core/client.h>
-
-int
-nouveau_parent_sclass(struct nouveau_object *parent, u16 handle,
- struct nouveau_object **pengine,
- struct nouveau_oclass **poclass)
-{
- struct nouveau_sclass *sclass;
- struct nouveau_engine *engine;
- struct nouveau_oclass *oclass;
- u64 mask;
-
- sclass = nv_parent(parent)->sclass;
- while (sclass) {
- if ((sclass->oclass->handle & 0xffff) == handle) {
- *pengine = parent->engine;
- *poclass = sclass->oclass;
- return 0;
- }
-
- sclass = sclass->sclass;
- }
-
- mask = nv_parent(parent)->engine;
- while (mask) {
- int i = __ffs64(mask);
-
- if (nv_iclass(parent, NV_CLIENT_CLASS))
- engine = nv_engine(nv_client(parent)->device);
- else
- engine = nouveau_engine(parent, i);
-
- if (engine) {
- oclass = engine->sclass;
- while (oclass->ofuncs) {
- if ((oclass->handle & 0xffff) == handle) {
- *pengine = nv_object(engine);
- *poclass = oclass;
- return 0;
- }
- oclass++;
- }
- }
-
- mask &= ~(1ULL << i);
- }
-
- return -EINVAL;
-}
-
-int
-nouveau_parent_lclass(struct nouveau_object *parent, u32 *lclass, int size)
-{
- struct nouveau_sclass *sclass;
- struct nouveau_engine *engine;
- struct nouveau_oclass *oclass;
- int nr = -1, i;
- u64 mask;
-
- sclass = nv_parent(parent)->sclass;
- while (sclass) {
- if (++nr < size)
- lclass[nr] = sclass->oclass->handle & 0xffff;
- sclass = sclass->sclass;
- }
-
- mask = nv_parent(parent)->engine;
- while (i = __ffs64(mask), mask) {
- engine = nouveau_engine(parent, i);
- if (engine && (oclass = engine->sclass)) {
- while (oclass->ofuncs) {
- if (++nr < size)
- lclass[nr] = oclass->handle & 0xffff;
- oclass++;
- }
- }
-
- mask &= ~(1ULL << i);
- }
-
- return nr + 1;
-}
-
-int
-nouveau_parent_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pclass,
- struct nouveau_oclass *sclass, u64 engcls,
- int size, void **pobject)
-{
- struct nouveau_parent *object;
- struct nouveau_sclass *nclass;
- int ret;
-
- ret = nouveau_object_create_(parent, engine, oclass, pclass |
- NV_PARENT_CLASS, size, pobject);
- object = *pobject;
- if (ret)
- return ret;
-
- while (sclass && sclass->ofuncs) {
- nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
- if (!nclass)
- return -ENOMEM;
-
- nclass->sclass = object->sclass;
- object->sclass = nclass;
- nclass->engine = engine ? nv_engine(engine) : NULL;
- nclass->oclass = sclass;
- sclass++;
- }
-
- object->engine = engcls;
- return 0;
-}
-
-void
-nouveau_parent_destroy(struct nouveau_parent *parent)
-{
- struct nouveau_sclass *sclass;
-
- while ((sclass = parent->sclass)) {
- parent->sclass = sclass->sclass;
- kfree(sclass);
- }
-
- nouveau_object_destroy(&parent->base);
-}
-
-
-void
-_nouveau_parent_dtor(struct nouveau_object *object)
-{
- nouveau_parent_destroy(nv_parent(object));
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/printk.c b/drivers/gpu/drm/nouveau/core/core/printk.c
deleted file mode 100644
index 03e0060b13da..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/printk.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/subdev.h>
-#include <core/printk.h>
-
-int nv_info_debug_level = NV_DBG_INFO_NORMAL;
-
-void
-nv_printk_(struct nouveau_object *object, int level, const char *fmt, ...)
-{
- static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
- const char *pfx;
- char mfmt[256];
- va_list args;
-
- switch (level) {
- case NV_DBG_FATAL:
- pfx = KERN_CRIT;
- break;
- case NV_DBG_ERROR:
- pfx = KERN_ERR;
- break;
- case NV_DBG_WARN:
- pfx = KERN_WARNING;
- break;
- case NV_DBG_INFO_NORMAL:
- pfx = KERN_INFO;
- break;
- case NV_DBG_DEBUG:
- case NV_DBG_PARANOIA:
- case NV_DBG_TRACE:
- case NV_DBG_SPAM:
- default:
- pfx = KERN_DEBUG;
- break;
- }
-
- if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
- struct nouveau_object *device = object;
- struct nouveau_object *subdev = object;
- char obuf[64], *ofmt = "";
-
- if (object->engine) {
- snprintf(obuf, sizeof(obuf), "[0x%08x][%p]",
- nv_hclass(object), object);
- ofmt = obuf;
- subdev = object->engine;
- device = object->engine;
- }
-
- if (subdev->parent)
- device = subdev->parent;
-
- if (level > nv_subdev(subdev)->debug)
- return;
-
- snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
- name[level], nv_subdev(subdev)->name,
- nv_device(device)->name, ofmt, fmt);
- } else
- if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
- if (level > nv_client(object)->debug)
- return;
-
- snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx,
- name[level], nv_client(object)->name, fmt);
- } else {
- snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
- }
-
- va_start(args, fmt);
- vprintk(mfmt, args);
- va_end(args);
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/ramht.c b/drivers/gpu/drm/nouveau/core/core/ramht.c
deleted file mode 100644
index f3b9bddc3875..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/ramht.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <core/object.h>
-#include <core/ramht.h>
-
-#include <subdev/bar.h>
-
-static u32
-nouveau_ramht_hash(struct nouveau_ramht *ramht, int chid, u32 handle)
-{
- u32 hash = 0;
-
- while (handle) {
- hash ^= (handle & ((1 << ramht->bits) - 1));
- handle >>= ramht->bits;
- }
-
- hash ^= chid << (ramht->bits - 4);
- hash = hash << 3;
- return hash;
-}
-
-int
-nouveau_ramht_insert(struct nouveau_ramht *ramht, int chid,
- u32 handle, u32 context)
-{
- struct nouveau_bar *bar = nouveau_bar(ramht);
- u32 co, ho;
-
- co = ho = nouveau_ramht_hash(ramht, chid, handle);
- do {
- if (!nv_ro32(ramht, co + 4)) {
- nv_wo32(ramht, co + 0, handle);
- nv_wo32(ramht, co + 4, context);
- if (bar)
- bar->flush(bar);
- return co;
- }
-
- co += 8;
- if (co >= nv_gpuobj(ramht)->size)
- co = 0;
- } while (co != ho);
-
- return -ENOMEM;
-}
-
-void
-nouveau_ramht_remove(struct nouveau_ramht *ramht, int cookie)
-{
- struct nouveau_bar *bar = nouveau_bar(ramht);
- nv_wo32(ramht, cookie + 0, 0x00000000);
- nv_wo32(ramht, cookie + 4, 0x00000000);
- if (bar)
- bar->flush(bar);
-}
-
-static struct nouveau_oclass
-nouveau_ramht_oclass = {
- .handle = 0x0000abcd,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = NULL,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
- },
-};
-
-int
-nouveau_ramht_new(struct nouveau_object *parent, struct nouveau_object *pargpu,
- u32 size, u32 align, struct nouveau_ramht **pramht)
-{
- struct nouveau_ramht *ramht;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, parent->engine ?
- parent->engine : parent, /* <nv50 ramht */
- &nouveau_ramht_oclass, 0, pargpu, size,
- align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
- *pramht = ramht;
- if (ret)
- return ret;
-
- ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/core/subdev.c b/drivers/gpu/drm/nouveau/core/core/subdev.c
deleted file mode 100644
index 2ea5568b6cf5..000000000000
--- a/drivers/gpu/drm/nouveau/core/core/subdev.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/option.h>
-
-void
-nouveau_subdev_reset(struct nouveau_object *subdev)
-{
- nv_trace(subdev, "resetting...\n");
- nv_ofuncs(subdev)->fini(subdev, false);
- nv_debug(subdev, "reset\n");
-}
-
-int
-nouveau_subdev_init(struct nouveau_subdev *subdev)
-{
- int ret = nouveau_object_init(&subdev->base);
- if (ret)
- return ret;
-
- nouveau_subdev_reset(&subdev->base);
- return 0;
-}
-
-int
-_nouveau_subdev_init(struct nouveau_object *object)
-{
- return nouveau_subdev_init(nv_subdev(object));
-}
-
-int
-nouveau_subdev_fini(struct nouveau_subdev *subdev, bool suspend)
-{
- if (subdev->unit) {
- nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
- nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
- }
-
- return nouveau_object_fini(&subdev->base, suspend);
-}
-
-int
-_nouveau_subdev_fini(struct nouveau_object *object, bool suspend)
-{
- return nouveau_subdev_fini(nv_subdev(object), suspend);
-}
-
-void
-nouveau_subdev_destroy(struct nouveau_subdev *subdev)
-{
- int subidx = nv_hclass(subdev) & 0xff;
- nv_device(subdev)->subdev[subidx] = NULL;
- nouveau_object_destroy(&subdev->base);
-}
-
-void
-_nouveau_subdev_dtor(struct nouveau_object *object)
-{
- nouveau_subdev_destroy(nv_subdev(object));
-}
-
-int
-nouveau_subdev_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pclass,
- const char *subname, const char *sysname,
- int size, void **pobject)
-{
- struct nouveau_subdev *subdev;
- int ret;
-
- ret = nouveau_object_create_(parent, engine, oclass, pclass |
- NV_SUBDEV_CLASS, size, pobject);
- subdev = *pobject;
- if (ret)
- return ret;
-
- __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
- subdev->name = subname;
-
- if (parent) {
- struct nouveau_device *device = nv_device(parent);
- subdev->debug = nouveau_dbgopt(device->dbgopt, subname);
- subdev->mmio = nv_subdev(device)->mmio;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
deleted file mode 100644
index 1e8e75c0684a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv84.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs, Ilia Mirkin
- */
-
-#include <engine/xtensa.h>
-#include <engine/bsp.h>
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_bsp_sclass[] = {
- { 0x74b0, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * BSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_bsp_cclass = {
- .handle = NV_ENGCTX(BSP, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_xtensa_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
- },
-};
-
-/*******************************************************************************
- * BSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv84_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_xtensa *priv;
- int ret;
-
- ret = nouveau_xtensa_create(parent, engine, oclass, 0x103000, true,
- "PBSP", "bsp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x04008000;
- nv_engine(priv)->cclass = &nv84_bsp_cclass;
- nv_engine(priv)->sclass = nv84_bsp_sclass;
- priv->fifo_val = 0x1111;
- priv->unkd28 = 0x90044;
- return 0;
-}
-
-struct nouveau_oclass
-nv84_bsp_oclass = {
- .handle = NV_ENGINE(BSP, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_bsp_ctor,
- .dtor = _nouveau_xtensa_dtor,
- .init = _nouveau_xtensa_init,
- .fini = _nouveau_xtensa_fini,
- .rd32 = _nouveau_xtensa_rd32,
- .wr32 = _nouveau_xtensa_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
deleted file mode 100644
index 6b089e022fd2..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nv98.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
- */
-
-#include <engine/falcon.h>
-#include <engine/bsp.h>
-
-struct nv98_bsp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_bsp_sclass[] = {
- { 0x88b1, &nouveau_object_ofuncs },
- { 0x85b1, &nouveau_object_ofuncs },
- { 0x86b1, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_bsp_cclass = {
- .handle = NV_ENGCTX(BSP, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv98_bsp_init(struct nouveau_object *object)
-{
- struct nv98_bsp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x084010, 0x0000ffd2);
- nv_wr32(priv, 0x08401c, 0x0000fff2);
- return 0;
-}
-
-static int
-nv98_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv98_bsp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
- "PBSP", "bsp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x04008000;
- nv_engine(priv)->cclass = &nv98_bsp_cclass;
- nv_engine(priv)->sclass = nv98_bsp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nv98_bsp_oclass = {
- .handle = NV_ENGINE(BSP, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv98_bsp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nv98_bsp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
deleted file mode 100644
index ce860de43e61..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Maarten Lankhorst
- */
-
-#include <engine/falcon.h>
-#include <engine/bsp.h>
-
-struct nvc0_bsp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_bsp_sclass[] = {
- { 0x90b1, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_bsp_cclass = {
- .handle = NV_ENGCTX(BSP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_bsp_init(struct nouveau_object *object)
-{
- struct nvc0_bsp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x084010, 0x0000fff2);
- nv_wr32(priv, 0x08401c, 0x0000fff2);
- return 0;
-}
-
-static int
-nvc0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_bsp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
- "PBSP", "bsp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00008000;
- nv_subdev(priv)->intr = nouveau_falcon_intr;
- nv_engine(priv)->cclass = &nvc0_bsp_cclass;
- nv_engine(priv)->sclass = nvc0_bsp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_bsp_oclass = {
- .handle = NV_ENGINE(BSP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_bsp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_bsp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
deleted file mode 100644
index ba6aeca0285e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/bsp/nve0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/bsp.h>
-
-struct nve0_bsp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * BSP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_bsp_sclass[] = {
- { 0x95b1, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PBSP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_bsp_cclass = {
- .handle = NV_ENGCTX(BSP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PBSP engine/subdev functions
- ******************************************************************************/
-
-static int
-nve0_bsp_init(struct nouveau_object *object)
-{
- struct nve0_bsp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x084010, 0x0000fff2);
- nv_wr32(priv, 0x08401c, 0x0000fff2);
- return 0;
-}
-
-static int
-nve0_bsp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_bsp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x084000, true,
- "PBSP", "bsp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00008000;
- nv_subdev(priv)->intr = nouveau_falcon_intr;
- nv_engine(priv)->cclass = &nve0_bsp_cclass;
- nv_engine(priv)->sclass = nve0_bsp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_bsp_oclass = {
- .handle = NV_ENGINE(BSP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_bsp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nve0_bsp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc
deleted file mode 100644
index 219850d53286..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc
+++ /dev/null
@@ -1,872 +0,0 @@
-/* fuc microcode for copy engine on nva3- chipsets
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-/* To build for nva3:nvc0
- * m4 -DNVA3 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nva3_copy.fuc.h
- *
- * To build for nvc0-
- * m4 -DNVC0 nva3_copy.fuc | envyas -a -w -m fuc -V nva3 -o nvc0_copy.fuc.h
- */
-
-ifdef(`NVA3',
-.section #nva3_pcopy_data
-,
-.section #nvc0_pcopy_data
-)
-
-ctx_object: .b32 0
-ifdef(`NVA3',
-ctx_dma:
-ctx_dma_query: .b32 0
-ctx_dma_src: .b32 0
-ctx_dma_dst: .b32 0
-,)
-.equ #ctx_dma_count 3
-ctx_query_address_high: .b32 0
-ctx_query_address_low: .b32 0
-ctx_query_counter: .b32 0
-ctx_src_address_high: .b32 0
-ctx_src_address_low: .b32 0
-ctx_src_pitch: .b32 0
-ctx_src_tile_mode: .b32 0
-ctx_src_xsize: .b32 0
-ctx_src_ysize: .b32 0
-ctx_src_zsize: .b32 0
-ctx_src_zoff: .b32 0
-ctx_src_xoff: .b32 0
-ctx_src_yoff: .b32 0
-ctx_src_cpp: .b32 0
-ctx_dst_address_high: .b32 0
-ctx_dst_address_low: .b32 0
-ctx_dst_pitch: .b32 0
-ctx_dst_tile_mode: .b32 0
-ctx_dst_xsize: .b32 0
-ctx_dst_ysize: .b32 0
-ctx_dst_zsize: .b32 0
-ctx_dst_zoff: .b32 0
-ctx_dst_xoff: .b32 0
-ctx_dst_yoff: .b32 0
-ctx_dst_cpp: .b32 0
-ctx_format: .b32 0
-ctx_swz_const0: .b32 0
-ctx_swz_const1: .b32 0
-ctx_xcnt: .b32 0
-ctx_ycnt: .b32 0
-.align 256
-
-dispatch_table:
-// mthd 0x0000, NAME
-.b16 0x000 1
-.b32 #ctx_object ~0xffffffff
-// mthd 0x0100, NOP
-.b16 0x040 1
-.b32 0x00010000 + #cmd_nop ~0xffffffff
-// mthd 0x0140, PM_TRIGGER
-.b16 0x050 1
-.b32 0x00010000 + #cmd_pm_trigger ~0xffffffff
-ifdef(`NVA3', `
-// mthd 0x0180-0x018c, DMA_
-.b16 0x060 #ctx_dma_count
-dispatch_dma:
-.b32 0x00010000 + #cmd_dma ~0xffffffff
-.b32 0x00010000 + #cmd_dma ~0xffffffff
-.b32 0x00010000 + #cmd_dma ~0xffffffff
-',)
-// mthd 0x0200-0x0218, SRC_TILE
-.b16 0x80 7
-.b32 #ctx_src_tile_mode ~0x00000fff
-.b32 #ctx_src_xsize ~0x0007ffff
-.b32 #ctx_src_ysize ~0x00001fff
-.b32 #ctx_src_zsize ~0x000007ff
-.b32 #ctx_src_zoff ~0x00000fff
-.b32 #ctx_src_xoff ~0x0007ffff
-.b32 #ctx_src_yoff ~0x00001fff
-// mthd 0x0220-0x0238, DST_TILE
-.b16 0x88 7
-.b32 #ctx_dst_tile_mode ~0x00000fff
-.b32 #ctx_dst_xsize ~0x0007ffff
-.b32 #ctx_dst_ysize ~0x00001fff
-.b32 #ctx_dst_zsize ~0x000007ff
-.b32 #ctx_dst_zoff ~0x00000fff
-.b32 #ctx_dst_xoff ~0x0007ffff
-.b32 #ctx_dst_yoff ~0x00001fff
-// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
-.b16 0xc0 2
-.b32 0x00010000 + #cmd_exec ~0xffffffff
-.b32 0x00010000 + #cmd_wrcache_flush ~0xffffffff
-// mthd 0x030c-0x0340, various stuff
-.b16 0xc3 14
-.b32 #ctx_src_address_high ~0x000000ff
-.b32 #ctx_src_address_low ~0xffffffff
-.b32 #ctx_dst_address_high ~0x000000ff
-.b32 #ctx_dst_address_low ~0xffffffff
-.b32 #ctx_src_pitch ~0x0007ffff
-.b32 #ctx_dst_pitch ~0x0007ffff
-.b32 #ctx_xcnt ~0x0000ffff
-.b32 #ctx_ycnt ~0x00001fff
-.b32 #ctx_format ~0x0333ffff
-.b32 #ctx_swz_const0 ~0xffffffff
-.b32 #ctx_swz_const1 ~0xffffffff
-.b32 #ctx_query_address_high ~0x000000ff
-.b32 #ctx_query_address_low ~0xffffffff
-.b32 #ctx_query_counter ~0xffffffff
-.b16 0x800 0
-
-ifdef(`NVA3',
-.section #nva3_pcopy_code
-,
-.section #nvc0_pcopy_code
-)
-
-main:
- clear b32 $r0
- mov $sp $r0
-
- // setup i0 handler and route fifo and ctxswitch to it
- mov $r1 #ih
- mov $iv0 $r1
- mov $r1 0x400
- movw $r2 0xfff3
- sethi $r2 0
- iowr I[$r1 + 0x300] $r2
-
- // enable interrupts
- or $r2 0xc
- iowr I[$r1] $r2
- bset $flags ie0
-
- // enable fifo access and context switching
- mov $r1 0x1200
- mov $r2 3
- iowr I[$r1] $r2
-
- // sleep forever, waking for interrupts
- bset $flags $p0
- spin:
- sleep $p0
- bra #spin
-
-// i0 handler
-ih:
- iord $r1 I[$r0 + 0x200]
-
- and $r2 $r1 0x00000008
- bra e #ih_no_chsw
- call #chsw
- ih_no_chsw:
- and $r2 $r1 0x00000004
- bra e #ih_no_cmd
- call #dispatch
-
- ih_no_cmd:
- and $r1 $r1 0x0000000c
- iowr I[$r0 + 0x100] $r1
- iret
-
-// $p1 direction (0 = unload, 1 = load)
-// $r3 channel
-swctx:
- mov $r4 0x7700
- mov $xtargets $r4
-ifdef(`NVA3', `
- // target 7 hardcoded to ctx dma object
- mov $xdbase $r0
-', ` // NVC0
- // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
- mov $r4 0x2100
- iord $r4 I[$r4 + 0]
- and $r4 1
- shl b32 $r4 4
- add b32 $r4 0x30
-
- // channel is in vram
- mov $r15 0x61c
- shl b32 $r15 6
- mov $r5 0x114
- iowrs I[$r15] $r5
-
- // read 16-byte PCOPYn info, containing context pointer, from channel
- shl b32 $r5 $r3 4
- add b32 $r5 2
- mov $xdbase $r5
- mov $r5 $sp
- // get a chunk of stack space, aligned to 256 byte boundary
- sub b32 $r5 0x100
- mov $r6 0xff
- not b32 $r6
- and $r5 $r6
- sethi $r5 0x00020000
- xdld $r4 $r5
- xdwait
- sethi $r5 0
-
- // set context pointer, from within channel VM
- mov $r14 0
- iowrs I[$r15] $r14
- ld b32 $r4 D[$r5 + 0]
- shr b32 $r4 8
- ld b32 $r6 D[$r5 + 4]
- shl b32 $r6 24
- or $r4 $r6
- mov $xdbase $r4
-')
- // 256-byte context, at start of data segment
- mov b32 $r4 $r0
- sethi $r4 0x60000
-
- // swap!
- bra $p1 #swctx_load
- xdst $r0 $r4
- bra #swctx_done
- swctx_load:
- xdld $r0 $r4
- swctx_done:
- xdwait
- ret
-
-chsw:
- // read current channel
- mov $r2 0x1400
- iord $r3 I[$r2]
-
- // if it's active, unload it and return
- xbit $r15 $r3 0x1e
- bra e #chsw_no_unload
- bclr $flags $p1
- call #swctx
- bclr $r3 0x1e
- iowr I[$r2] $r3
- mov $r4 1
- iowr I[$r2 + 0x200] $r4
- ret
-
- // read next channel
- chsw_no_unload:
- iord $r3 I[$r2 + 0x100]
-
- // is there a channel waiting to be loaded?
- xbit $r13 $r3 0x1e
- bra e #chsw_finish_load
- bset $flags $p1
- call #swctx
-ifdef(`NVA3',
- // load dma objects back into TARGET regs
- mov $r5 #ctx_dma
- mov $r6 #ctx_dma_count
- chsw_load_ctx_dma:
- ld b32 $r7 D[$r5 + $r6 * 4]
- add b32 $r8 $r6 0x180
- shl b32 $r8 8
- iowr I[$r8] $r7
- sub b32 $r6 1
- bra nc #chsw_load_ctx_dma
-,)
-
- chsw_finish_load:
- mov $r3 2
- iowr I[$r2 + 0x200] $r3
- ret
-
-dispatch:
- // read incoming fifo command
- mov $r3 0x1900
- iord $r2 I[$r3 + 0x100]
- iord $r3 I[$r3 + 0x000]
- and $r4 $r2 0x7ff
- // $r2 will be used to store exception data
- shl b32 $r2 0x10
-
- // lookup method in the dispatch table, ILLEGAL_MTHD if not found
- mov $r5 #dispatch_table
- clear b32 $r6
- clear b32 $r7
- dispatch_loop:
- ld b16 $r6 D[$r5 + 0]
- ld b16 $r7 D[$r5 + 2]
- add b32 $r5 4
- cmpu b32 $r4 $r6
- bra c #dispatch_illegal_mthd
- add b32 $r7 $r6
- cmpu b32 $r4 $r7
- bra c #dispatch_valid_mthd
- sub b32 $r7 $r6
- shl b32 $r7 3
- add b32 $r5 $r7
- bra #dispatch_loop
-
- // ensure no bits set in reserved fields, INVALID_BITFIELD
- dispatch_valid_mthd:
- sub b32 $r4 $r6
- shl b32 $r4 3
- add b32 $r4 $r5
- ld b32 $r5 D[$r4 + 4]
- and $r5 $r3
- cmpu b32 $r5 0
- bra ne #dispatch_invalid_bitfield
-
- // depending on dispatch flags: execute method, or save data as state
- ld b16 $r5 D[$r4 + 0]
- ld b16 $r6 D[$r4 + 2]
- cmpu b32 $r6 0
- bra ne #dispatch_cmd
- st b32 D[$r5] $r3
- bra #dispatch_done
- dispatch_cmd:
- bclr $flags $p1
- call $r5
- bra $p1 #dispatch_error
- bra #dispatch_done
-
- dispatch_invalid_bitfield:
- or $r2 2
- dispatch_illegal_mthd:
- or $r2 1
-
- // store exception data in SCRATCH0/SCRATCH1, signal hostirq
- dispatch_error:
- mov $r4 0x1000
- iowr I[$r4 + 0x000] $r2
- iowr I[$r4 + 0x100] $r3
- mov $r2 0x40
- iowr I[$r0] $r2
- hostirq_wait:
- iord $r2 I[$r0 + 0x200]
- and $r2 0x40
- cmpu b32 $r2 0
- bra ne #hostirq_wait
-
- dispatch_done:
- mov $r2 0x1d00
- mov $r3 1
- iowr I[$r2] $r3
- ret
-
-// No-operation
-//
-// Inputs:
-// $r1: irqh state
-// $r2: hostirq state
-// $r3: data
-// $r4: dispatch table entry
-// Outputs:
-// $r1: irqh state
-// $p1: set on error
-// $r2: hostirq state
-// $r3: data
-cmd_nop:
- ret
-
-// PM_TRIGGER
-//
-// Inputs:
-// $r1: irqh state
-// $r2: hostirq state
-// $r3: data
-// $r4: dispatch table entry
-// Outputs:
-// $r1: irqh state
-// $p1: set on error
-// $r2: hostirq state
-// $r3: data
-cmd_pm_trigger:
- mov $r2 0x2200
- clear b32 $r3
- sethi $r3 0x20000
- iowr I[$r2] $r3
- ret
-
-ifdef(`NVA3',
-// SET_DMA_* method handler
-//
-// Inputs:
-// $r1: irqh state
-// $r2: hostirq state
-// $r3: data
-// $r4: dispatch table entry
-// Outputs:
-// $r1: irqh state
-// $p1: set on error
-// $r2: hostirq state
-// $r3: data
-cmd_dma:
- sub b32 $r4 #dispatch_dma
- shr b32 $r4 1
- bset $r3 0x1e
- st b32 D[$r4 + #ctx_dma] $r3
- add b32 $r4 0x600
- shl b32 $r4 6
- iowr I[$r4] $r3
- ret
-,)
-
-// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
-//
-cmd_exec_set_format:
- // zero out a chunk of the stack to store the swizzle into
- add $sp -0x10
- st b32 D[$sp + 0x00] $r0
- st b32 D[$sp + 0x04] $r0
- st b32 D[$sp + 0x08] $r0
- st b32 D[$sp + 0x0c] $r0
-
- // extract cpp, src_ncomp and dst_ncomp from FORMAT
- ld b32 $r4 D[$r0 + #ctx_format]
- extr $r5 $r4 16:17
- add b32 $r5 1
- extr $r6 $r4 20:21
- add b32 $r6 1
- extr $r7 $r4 24:25
- add b32 $r7 1
-
- // convert FORMAT swizzle mask to hw swizzle mask
- bclr $flags $p2
- clear b32 $r8
- clear b32 $r9
- ncomp_loop:
- and $r10 $r4 0xf
- shr b32 $r4 4
- clear b32 $r11
- bpc_loop:
- cmpu b8 $r10 4
- bra nc #cmp_c0
- mulu $r12 $r10 $r5
- add b32 $r12 $r11
- bset $flags $p2
- bra #bpc_next
- cmp_c0:
- bra ne #cmp_c1
- mov $r12 0x10
- add b32 $r12 $r11
- bra #bpc_next
- cmp_c1:
- cmpu b8 $r10 6
- bra nc #cmp_zero
- mov $r12 0x14
- add b32 $r12 $r11
- bra #bpc_next
- cmp_zero:
- mov $r12 0x80
- bpc_next:
- st b8 D[$sp + $r8] $r12
- add b32 $r8 1
- add b32 $r11 1
- cmpu b32 $r11 $r5
- bra c #bpc_loop
- add b32 $r9 1
- cmpu b32 $r9 $r7
- bra c #ncomp_loop
-
- // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
- mulu $r6 $r5
- st b32 D[$r0 + #ctx_src_cpp] $r6
- ld b32 $r8 D[$r0 + #ctx_xcnt]
- mulu $r6 $r8
- bra $p2 #dst_xcnt
- clear b32 $r6
-
- dst_xcnt:
- mulu $r7 $r5
- st b32 D[$r0 + #ctx_dst_cpp] $r7
- mulu $r7 $r8
-
- mov $r5 0x810
- shl b32 $r5 6
- iowr I[$r5 + 0x000] $r6
- iowr I[$r5 + 0x100] $r7
- add b32 $r5 0x800
- ld b32 $r6 D[$r0 + #ctx_dst_cpp]
- sub b32 $r6 1
- shl b32 $r6 8
- ld b32 $r7 D[$r0 + #ctx_src_cpp]
- sub b32 $r7 1
- or $r6 $r7
- iowr I[$r5 + 0x000] $r6
- add b32 $r5 0x100
- ld b32 $r6 D[$sp + 0x00]
- iowr I[$r5 + 0x000] $r6
- ld b32 $r6 D[$sp + 0x04]
- iowr I[$r5 + 0x100] $r6
- ld b32 $r6 D[$sp + 0x08]
- iowr I[$r5 + 0x200] $r6
- ld b32 $r6 D[$sp + 0x0c]
- iowr I[$r5 + 0x300] $r6
- add b32 $r5 0x400
- ld b32 $r6 D[$r0 + #ctx_swz_const0]
- iowr I[$r5 + 0x000] $r6
- ld b32 $r6 D[$r0 + #ctx_swz_const1]
- iowr I[$r5 + 0x100] $r6
- add $sp 0x10
- ret
-
-// Setup to handle a tiled surface
-//
-// Calculates a number of parameters the hardware requires in order
-// to correctly handle tiling.
-//
-// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
-// nTx = round_up(w * cpp, 1 << Tp) >> Tp
-// nTy = round_up(h, 1 << Th) >> Th
-// Txo = (x * cpp) & ((1 << Tp) - 1)
-// Tx = (x * cpp) >> Tp
-// Tyo = y & ((1 << Th) - 1)
-// Ty = y >> Th
-// Tzo = z & ((1 << Td) - 1)
-// Tz = z >> Td
-//
-// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
-// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
-//
-// Inputs:
-// $r4: hw command (0x104800)
-// $r5: ctx offset adjustment for src/dst selection
-// $p2: set if dst surface
-//
-cmd_exec_set_surface_tiled:
- // translate TILE_MODE into Tp, Th, Td shift values
- ld b32 $r7 D[$r5 + #ctx_src_tile_mode]
- extr $r9 $r7 8:11
- extr $r8 $r7 4:7
-ifdef(`NVA3',
- add b32 $r8 2
-,
- add b32 $r8 3
-)
- extr $r7 $r7 0:3
- cmp b32 $r7 0xe
- bra ne #xtile64
- mov $r7 4
- bra #xtileok
- xtile64:
- xbit $r7 $flags $p2
- add b32 $r7 17
- bset $r4 $r7
- mov $r7 6
- xtileok:
-
- // Op = (x * cpp) & ((1 << Tp) - 1)
- // Tx = (x * cpp) >> Tp
- ld b32 $r10 D[$r5 + #ctx_src_xoff]
- ld b32 $r11 D[$r5 + #ctx_src_cpp]
- mulu $r10 $r11
- mov $r11 1
- shl b32 $r11 $r7
- sub b32 $r11 1
- and $r12 $r10 $r11
- shr b32 $r10 $r7
-
- // Tyo = y & ((1 << Th) - 1)
- // Ty = y >> Th
- ld b32 $r13 D[$r5 + #ctx_src_yoff]
- mov $r14 1
- shl b32 $r14 $r8
- sub b32 $r14 1
- and $r11 $r13 $r14
- shr b32 $r13 $r8
-
- // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
- add b32 $r14 1
- shl b32 $r15 $r14 12
- sub b32 $r14 $r11
- or $r15 $r14
- xbit $r6 $flags $p2
- add b32 $r6 0x208
- shl b32 $r6 8
- iowr I[$r6 + 0x000] $r15
-
- // Op += Tyo << Tp
- shl b32 $r11 $r7
- add b32 $r12 $r11
-
- // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
- ld b32 $r15 D[$r5 + #ctx_src_xsize]
- ld b32 $r11 D[$r5 + #ctx_src_cpp]
- mulu $r15 $r11
- mov $r11 1
- shl b32 $r11 $r7
- sub b32 $r11 1
- add b32 $r15 $r11
- shr b32 $r15 $r7
- push $r15
-
- // nTy = (h + ((1 << Th) - 1)) >> Th
- ld b32 $r15 D[$r5 + #ctx_src_ysize]
- mov $r11 1
- shl b32 $r11 $r8
- sub b32 $r11 1
- add b32 $r15 $r11
- shr b32 $r15 $r8
- push $r15
-
- // Tys = Tp + Th
- // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
- add b32 $r7 $r8
- sub b32 $r8 2
- mov $r11 1
- shl b32 $r11 $r8
- shl b32 $r11 $r9
-
- // Tzo = z & ((1 << Td) - 1)
- // Tz = z >> Td
- // Op += Tzo << Tys
- // Ts = Tys + Td
- ld b32 $r8 D[$r5 + #ctx_src_zoff]
- mov $r14 1
- shl b32 $r14 $r9
- sub b32 $r14 1
- and $r15 $r8 $r14
- shl b32 $r15 $r7
- add b32 $r12 $r15
- add b32 $r7 $r9
- shr b32 $r8 $r9
-
- // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
- pop $r15
- pop $r9
- mulu $r13 $r9
- add b32 $r10 $r13
- mulu $r8 $r9
- mulu $r8 $r15
- add b32 $r10 $r8
- shl b32 $r10 $r7
-
- // PITCH = (nTx - 1) << Ts
- sub b32 $r9 1
- shl b32 $r9 $r7
- iowr I[$r6 + 0x200] $r9
-
- // SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff
- // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
- ld b32 $r7 D[$r5 + #ctx_src_address_low]
- ld b32 $r8 D[$r5 + #ctx_src_address_high]
- add b32 $r10 $r12
- add b32 $r7 $r10
- adc b32 $r8 0
- shl b32 $r8 16
- or $r8 $r11
- sub b32 $r6 0x600
- iowr I[$r6 + 0x000] $r7
- add b32 $r6 0x400
- iowr I[$r6 + 0x000] $r8
- ret
-
-// Setup to handle a linear surface
-//
-// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
-//
-cmd_exec_set_surface_linear:
- xbit $r6 $flags $p2
- add b32 $r6 0x202
- shl b32 $r6 8
- ld b32 $r7 D[$r5 + #ctx_src_address_low]
- iowr I[$r6 + 0x000] $r7
- add b32 $r6 0x400
- ld b32 $r7 D[$r5 + #ctx_src_address_high]
- shl b32 $r7 16
- iowr I[$r6 + 0x000] $r7
- add b32 $r6 0x400
- ld b32 $r7 D[$r5 + #ctx_src_pitch]
- iowr I[$r6 + 0x000] $r7
- ret
-
-// wait for regs to be available for use
-cmd_exec_wait:
- push $r0
- push $r1
- mov $r0 0x800
- shl b32 $r0 6
- loop:
- iord $r1 I[$r0]
- and $r1 1
- bra ne #loop
- pop $r1
- pop $r0
- ret
-
-cmd_exec_query:
- // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
- xbit $r4 $r3 13
- bra ne #query_counter
- call #cmd_exec_wait
- mov $r4 0x80c
- shl b32 $r4 6
- ld b32 $r5 D[$r0 + #ctx_query_address_low]
- add b32 $r5 4
- iowr I[$r4 + 0x000] $r5
- iowr I[$r4 + 0x100] $r0
- mov $r5 0xc
- iowr I[$r4 + 0x200] $r5
- add b32 $r4 0x400
- ld b32 $r5 D[$r0 + #ctx_query_address_high]
- shl b32 $r5 16
- iowr I[$r4 + 0x000] $r5
- add b32 $r4 0x500
- mov $r5 0x00000b00
- sethi $r5 0x00010000
- iowr I[$r4 + 0x000] $r5
- mov $r5 0x00004040
- shl b32 $r5 1
- sethi $r5 0x80800000
- iowr I[$r4 + 0x100] $r5
- mov $r5 0x00001110
- sethi $r5 0x13120000
- iowr I[$r4 + 0x200] $r5
- mov $r5 0x00001514
- sethi $r5 0x17160000
- iowr I[$r4 + 0x300] $r5
- mov $r5 0x00002601
- sethi $r5 0x00010000
- mov $r4 0x800
- shl b32 $r4 6
- iowr I[$r4 + 0x000] $r5
-
- // write COUNTER
- query_counter:
- call #cmd_exec_wait
- mov $r4 0x80c
- shl b32 $r4 6
- ld b32 $r5 D[$r0 + #ctx_query_address_low]
- iowr I[$r4 + 0x000] $r5
- iowr I[$r4 + 0x100] $r0
- mov $r5 0x4
- iowr I[$r4 + 0x200] $r5
- add b32 $r4 0x400
- ld b32 $r5 D[$r0 + #ctx_query_address_high]
- shl b32 $r5 16
- iowr I[$r4 + 0x000] $r5
- add b32 $r4 0x500
- mov $r5 0x00000300
- iowr I[$r4 + 0x000] $r5
- mov $r5 0x00001110
- sethi $r5 0x13120000
- iowr I[$r4 + 0x100] $r5
- ld b32 $r5 D[$r0 + #ctx_query_counter]
- add b32 $r4 0x500
- iowr I[$r4 + 0x000] $r5
- mov $r5 0x00002601
- sethi $r5 0x00010000
- mov $r4 0x800
- shl b32 $r4 6
- iowr I[$r4 + 0x000] $r5
- ret
-
-// Execute a copy operation
-//
-// Inputs:
-// $r1: irqh state
-// $r2: hostirq state
-// $r3: data
-// 000002000 QUERY_SHORT
-// 000001000 QUERY
-// 000000100 DST_LINEAR
-// 000000010 SRC_LINEAR
-// 000000001 FORMAT
-// $r4: dispatch table entry
-// Outputs:
-// $r1: irqh state
-// $p1: set on error
-// $r2: hostirq state
-// $r3: data
-cmd_exec:
- call #cmd_exec_wait
-
- // if format requested, call function to calculate it, otherwise
- // fill in cpp/xcnt for both surfaces as if (cpp == 1)
- xbit $r15 $r3 0
- bra e #cmd_exec_no_format
- call #cmd_exec_set_format
- mov $r4 0x200
- bra #cmd_exec_init_src_surface
- cmd_exec_no_format:
- mov $r6 0x810
- shl b32 $r6 6
- mov $r7 1
- st b32 D[$r0 + #ctx_src_cpp] $r7
- st b32 D[$r0 + #ctx_dst_cpp] $r7
- ld b32 $r7 D[$r0 + #ctx_xcnt]
- iowr I[$r6 + 0x000] $r7
- iowr I[$r6 + 0x100] $r7
- clear b32 $r4
-
- cmd_exec_init_src_surface:
- bclr $flags $p2
- clear b32 $r5
- xbit $r15 $r3 4
- bra e #src_tiled
- call #cmd_exec_set_surface_linear
- bra #cmd_exec_init_dst_surface
- src_tiled:
- call #cmd_exec_set_surface_tiled
- bset $r4 7
-
- cmd_exec_init_dst_surface:
- bset $flags $p2
- mov $r5 #ctx_dst_address_high - #ctx_src_address_high
- xbit $r15 $r3 8
- bra e #dst_tiled
- call #cmd_exec_set_surface_linear
- bra #cmd_exec_kick
- dst_tiled:
- call #cmd_exec_set_surface_tiled
- bset $r4 8
-
- cmd_exec_kick:
- mov $r5 0x800
- shl b32 $r5 6
- ld b32 $r6 D[$r0 + #ctx_ycnt]
- iowr I[$r5 + 0x100] $r6
- mov $r6 0x0041
- // SRC_TARGET = 1, DST_TARGET = 2
- sethi $r6 0x44000000
- or $r4 $r6
- iowr I[$r5] $r4
-
- // if requested, queue up a QUERY write after the copy has completed
- xbit $r15 $r3 12
- bra e #cmd_exec_done
- call #cmd_exec_query
-
- cmd_exec_done:
- ret
-
-// Flush write cache
-//
-// Inputs:
-// $r1: irqh state
-// $r2: hostirq state
-// $r3: data
-// $r4: dispatch table entry
-// Outputs:
-// $r1: irqh state
-// $p1: set on error
-// $r2: hostirq state
-// $r3: data
-cmd_wrcache_flush:
- mov $r2 0x2200
- clear b32 $r3
- sethi $r3 0x10000
- iowr I[$r2] $r3
- ret
-
-.align 0x100
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
deleted file mode 100644
index 241b27201206..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nva3.fuc.h
+++ /dev/null
@@ -1,620 +0,0 @@
-uint32_t nva3_pcopy_data[] = {
-/* 0x0000: ctx_object */
- 0x00000000,
-/* 0x0004: ctx_dma */
-/* 0x0004: ctx_dma_query */
- 0x00000000,
-/* 0x0008: ctx_dma_src */
- 0x00000000,
-/* 0x000c: ctx_dma_dst */
- 0x00000000,
-/* 0x0010: ctx_query_address_high */
- 0x00000000,
-/* 0x0014: ctx_query_address_low */
- 0x00000000,
-/* 0x0018: ctx_query_counter */
- 0x00000000,
-/* 0x001c: ctx_src_address_high */
- 0x00000000,
-/* 0x0020: ctx_src_address_low */
- 0x00000000,
-/* 0x0024: ctx_src_pitch */
- 0x00000000,
-/* 0x0028: ctx_src_tile_mode */
- 0x00000000,
-/* 0x002c: ctx_src_xsize */
- 0x00000000,
-/* 0x0030: ctx_src_ysize */
- 0x00000000,
-/* 0x0034: ctx_src_zsize */
- 0x00000000,
-/* 0x0038: ctx_src_zoff */
- 0x00000000,
-/* 0x003c: ctx_src_xoff */
- 0x00000000,
-/* 0x0040: ctx_src_yoff */
- 0x00000000,
-/* 0x0044: ctx_src_cpp */
- 0x00000000,
-/* 0x0048: ctx_dst_address_high */
- 0x00000000,
-/* 0x004c: ctx_dst_address_low */
- 0x00000000,
-/* 0x0050: ctx_dst_pitch */
- 0x00000000,
-/* 0x0054: ctx_dst_tile_mode */
- 0x00000000,
-/* 0x0058: ctx_dst_xsize */
- 0x00000000,
-/* 0x005c: ctx_dst_ysize */
- 0x00000000,
-/* 0x0060: ctx_dst_zsize */
- 0x00000000,
-/* 0x0064: ctx_dst_zoff */
- 0x00000000,
-/* 0x0068: ctx_dst_xoff */
- 0x00000000,
-/* 0x006c: ctx_dst_yoff */
- 0x00000000,
-/* 0x0070: ctx_dst_cpp */
- 0x00000000,
-/* 0x0074: ctx_format */
- 0x00000000,
-/* 0x0078: ctx_swz_const0 */
- 0x00000000,
-/* 0x007c: ctx_swz_const1 */
- 0x00000000,
-/* 0x0080: ctx_xcnt */
- 0x00000000,
-/* 0x0084: ctx_ycnt */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: dispatch_table */
- 0x00010000,
- 0x00000000,
- 0x00000000,
- 0x00010040,
- 0x00010160,
- 0x00000000,
- 0x00010050,
- 0x00010162,
- 0x00000000,
- 0x00030060,
-/* 0x0128: dispatch_dma */
- 0x00010170,
- 0x00000000,
- 0x00010170,
- 0x00000000,
- 0x00010170,
- 0x00000000,
- 0x00070080,
- 0x00000028,
- 0xfffff000,
- 0x0000002c,
- 0xfff80000,
- 0x00000030,
- 0xffffe000,
- 0x00000034,
- 0xfffff800,
- 0x00000038,
- 0xfffff000,
- 0x0000003c,
- 0xfff80000,
- 0x00000040,
- 0xffffe000,
- 0x00070088,
- 0x00000054,
- 0xfffff000,
- 0x00000058,
- 0xfff80000,
- 0x0000005c,
- 0xffffe000,
- 0x00000060,
- 0xfffff800,
- 0x00000064,
- 0xfffff000,
- 0x00000068,
- 0xfff80000,
- 0x0000006c,
- 0xffffe000,
- 0x000200c0,
- 0x00010492,
- 0x00000000,
- 0x0001051b,
- 0x00000000,
- 0x000e00c3,
- 0x0000001c,
- 0xffffff00,
- 0x00000020,
- 0x00000000,
- 0x00000048,
- 0xffffff00,
- 0x0000004c,
- 0x00000000,
- 0x00000024,
- 0xfff80000,
- 0x00000050,
- 0xfff80000,
- 0x00000080,
- 0xffff0000,
- 0x00000084,
- 0xffffe000,
- 0x00000074,
- 0xfccc0000,
- 0x00000078,
- 0x00000000,
- 0x0000007c,
- 0x00000000,
- 0x00000010,
- 0xffffff00,
- 0x00000014,
- 0x00000000,
- 0x00000018,
- 0x00000000,
- 0x00000800,
-};
-
-uint32_t nva3_pcopy_code[] = {
-/* 0x0000: main */
- 0x04fe04bd,
- 0x3517f000,
- 0xf10010fe,
- 0xf1040017,
- 0xf0fff327,
- 0x12d00023,
- 0x0c25f0c0,
- 0xf40012d0,
- 0x17f11031,
- 0x27f01200,
- 0x0012d003,
-/* 0x002f: spin */
- 0xf40031f4,
- 0x0ef40028,
-/* 0x0035: ih */
- 0x8001cffd,
- 0xf40812c4,
- 0x21f4060b,
-/* 0x0041: ih_no_chsw */
- 0x0412c472,
- 0xf4060bf4,
-/* 0x004a: ih_no_cmd */
- 0x11c4c321,
- 0x4001d00c,
-/* 0x0052: swctx */
- 0x47f101f8,
- 0x4bfe7700,
- 0x0007fe00,
- 0xf00204b9,
- 0x01f40643,
- 0x0604fa09,
-/* 0x006b: swctx_load */
- 0xfa060ef4,
-/* 0x006e: swctx_done */
- 0x03f80504,
-/* 0x0072: chsw */
- 0x27f100f8,
- 0x23cf1400,
- 0x1e3fc800,
- 0xf4170bf4,
- 0x21f40132,
- 0x1e3af052,
- 0xf00023d0,
- 0x24d00147,
-/* 0x0093: chsw_no_unload */
- 0xcf00f880,
- 0x3dc84023,
- 0x220bf41e,
- 0xf40131f4,
- 0x57f05221,
- 0x0367f004,
-/* 0x00a8: chsw_load_ctx_dma */
- 0xa07856bc,
- 0xb6018068,
- 0x87d00884,
- 0x0162b600,
-/* 0x00bb: chsw_finish_load */
- 0xf0f018f4,
- 0x23d00237,
-/* 0x00c3: dispatch */
- 0xf100f880,
- 0xcf190037,
- 0x33cf4032,
- 0xff24e400,
- 0x1024b607,
- 0x010057f1,
- 0x74bd64bd,
-/* 0x00dc: dispatch_loop */
- 0x58005658,
- 0x50b60157,
- 0x0446b804,
- 0xbb4d08f4,
- 0x47b80076,
- 0x0f08f404,
- 0xb60276bb,
- 0x57bb0374,
- 0xdf0ef400,
-/* 0x0100: dispatch_valid_mthd */
- 0xb60246bb,
- 0x45bb0344,
- 0x01459800,
- 0xb00453fd,
- 0x1bf40054,
- 0x00455820,
- 0xb0014658,
- 0x1bf40064,
- 0x00538009,
-/* 0x0127: dispatch_cmd */
- 0xf4300ef4,
- 0x55f90132,
- 0xf40c01f4,
-/* 0x0132: dispatch_invalid_bitfield */
- 0x25f0250e,
-/* 0x0135: dispatch_illegal_mthd */
- 0x0125f002,
-/* 0x0138: dispatch_error */
- 0x100047f1,
- 0xd00042d0,
- 0x27f04043,
- 0x0002d040,
-/* 0x0148: hostirq_wait */
- 0xf08002cf,
- 0x24b04024,
- 0xf71bf400,
-/* 0x0154: dispatch_done */
- 0x1d0027f1,
- 0xd00137f0,
- 0x00f80023,
-/* 0x0160: cmd_nop */
-/* 0x0162: cmd_pm_trigger */
- 0x27f100f8,
- 0x34bd2200,
- 0xd00233f0,
- 0x00f80023,
-/* 0x0170: cmd_dma */
- 0x012842b7,
- 0xf00145b6,
- 0x43801e39,
- 0x0040b701,
- 0x0644b606,
- 0xf80043d0,
-/* 0x0189: cmd_exec_set_format */
- 0xf030f400,
- 0xb00001b0,
- 0x01b00101,
- 0x0301b002,
- 0xc71d0498,
- 0x50b63045,
- 0x3446c701,
- 0xc70160b6,
- 0x70b63847,
- 0x0232f401,
- 0x94bd84bd,
-/* 0x01b4: ncomp_loop */
- 0xb60f4ac4,
- 0xb4bd0445,
-/* 0x01bc: bpc_loop */
- 0xf404a430,
- 0xa5ff0f18,
- 0x00cbbbc0,
- 0xf40231f4,
-/* 0x01ce: cmp_c0 */
- 0x1bf4220e,
- 0x10c7f00c,
- 0xf400cbbb,
-/* 0x01da: cmp_c1 */
- 0xa430160e,
- 0x0c18f406,
- 0xbb14c7f0,
- 0x0ef400cb,
-/* 0x01e9: cmp_zero */
- 0x80c7f107,
-/* 0x01ed: bpc_next */
- 0x01c83800,
- 0xb60180b6,
- 0xb5b801b0,
- 0xc308f404,
- 0xb80190b6,
- 0x08f40497,
- 0x0065fdb2,
- 0x98110680,
- 0x68fd2008,
- 0x0502f400,
-/* 0x0216: dst_xcnt */
- 0x75fd64bd,
- 0x1c078000,
- 0xf10078fd,
- 0xb6081057,
- 0x56d00654,
- 0x4057d000,
- 0x080050b7,
- 0xb61c0698,
- 0x64b60162,
- 0x11079808,
- 0xfd0172b6,
- 0x56d00567,
- 0x0050b700,
- 0x0060b401,
- 0xb40056d0,
- 0x56d00160,
- 0x0260b440,
- 0xb48056d0,
- 0x56d00360,
- 0x0050b7c0,
- 0x1e069804,
- 0x980056d0,
- 0x56d01f06,
- 0x1030f440,
-/* 0x0276: cmd_exec_set_surface_tiled */
- 0x579800f8,
- 0x6879c70a,
- 0xb66478c7,
- 0x77c70280,
- 0x0e76b060,
- 0xf0091bf4,
- 0x0ef40477,
-/* 0x0291: xtile64 */
- 0x027cf00f,
- 0xfd1170b6,
- 0x77f00947,
-/* 0x029d: xtileok */
- 0x0f5a9806,
- 0xfd115b98,
- 0xb7f000ab,
- 0x04b7bb01,
- 0xff01b2b6,
- 0xa7bbc4ab,
- 0x105d9805,
- 0xbb01e7f0,
- 0xe2b604e8,
- 0xb4deff01,
- 0xb605d8bb,
- 0xef9401e0,
- 0x02ebbb0c,
- 0xf005fefd,
- 0x60b7026c,
- 0x64b60208,
- 0x006fd008,
- 0xbb04b7bb,
- 0x5f9800cb,
- 0x115b980b,
- 0xf000fbfd,
- 0xb7bb01b7,
- 0x01b2b604,
- 0xbb00fbbb,
- 0xf0f905f7,
- 0xf00c5f98,
- 0xb8bb01b7,
- 0x01b2b604,
- 0xbb00fbbb,
- 0xf0f905f8,
- 0xb60078bb,
- 0xb7f00282,
- 0x04b8bb01,
- 0x9804b9bb,
- 0xe7f00e58,
- 0x04e9bb01,
- 0xff01e2b6,
- 0xf7bbf48e,
- 0x00cfbb04,
- 0xbb0079bb,
- 0xf0fc0589,
- 0xd9fd90fc,
- 0x00adbb00,
- 0xfd0089fd,
- 0xa8bb008f,
- 0x04a7bb00,
- 0xbb0192b6,
- 0x69d00497,
- 0x08579880,
- 0xbb075898,
- 0x7abb00ac,
- 0x0081b600,
- 0xfd1084b6,
- 0x62b7058b,
- 0x67d00600,
- 0x0060b700,
- 0x0068d004,
-/* 0x0382: cmd_exec_set_surface_linear */
- 0x6cf000f8,
- 0x0260b702,
- 0x0864b602,
- 0xd0085798,
- 0x60b70067,
- 0x57980400,
- 0x1074b607,
- 0xb70067d0,
- 0x98040060,
- 0x67d00957,
-/* 0x03ab: cmd_exec_wait */
- 0xf900f800,
- 0xf110f900,
- 0xb6080007,
-/* 0x03b6: loop */
- 0x01cf0604,
- 0x0114f000,
- 0xfcfa1bf4,
- 0xf800fc10,
-/* 0x03c5: cmd_exec_query */
- 0x0d34c800,
- 0xf5701bf4,
- 0xf103ab21,
- 0xb6080c47,
- 0x05980644,
- 0x0450b605,
- 0xd00045d0,
- 0x57f04040,
- 0x8045d00c,
- 0x040040b7,
- 0xb6040598,
- 0x45d01054,
- 0x0040b700,
- 0x0057f105,
- 0x0153f00b,
- 0xf10045d0,
- 0xb6404057,
- 0x53f10154,
- 0x45d08080,
- 0x1057f140,
- 0x1253f111,
- 0x8045d013,
- 0x151457f1,
- 0x171653f1,
- 0xf1c045d0,
- 0xf0260157,
- 0x47f10153,
- 0x44b60800,
- 0x0045d006,
-/* 0x0438: query_counter */
- 0x03ab21f5,
- 0x080c47f1,
- 0x980644b6,
- 0x45d00505,
- 0x4040d000,
- 0xd00457f0,
- 0x40b78045,
- 0x05980400,
- 0x1054b604,
- 0xb70045d0,
- 0xf1050040,
- 0xd0030057,
- 0x57f10045,
- 0x53f11110,
- 0x45d01312,
- 0x06059840,
- 0x050040b7,
- 0xf10045d0,
- 0xf0260157,
- 0x47f10153,
- 0x44b60800,
- 0x0045d006,
-/* 0x0492: cmd_exec */
- 0x21f500f8,
- 0x3fc803ab,
- 0x0e0bf400,
- 0x018921f5,
- 0x020047f1,
-/* 0x04a7: cmd_exec_no_format */
- 0xf11e0ef4,
- 0xb6081067,
- 0x77f00664,
- 0x11078001,
- 0x981c0780,
- 0x67d02007,
- 0x4067d000,
-/* 0x04c2: cmd_exec_init_src_surface */
- 0x32f444bd,
- 0xc854bd02,
- 0x0bf4043f,
- 0x8221f50a,
- 0x0a0ef403,
-/* 0x04d4: src_tiled */
- 0x027621f5,
-/* 0x04db: cmd_exec_init_dst_surface */
- 0xf40749f0,
- 0x57f00231,
- 0x083fc82c,
- 0xf50a0bf4,
- 0xf4038221,
-/* 0x04ee: dst_tiled */
- 0x21f50a0e,
- 0x49f00276,
-/* 0x04f5: cmd_exec_kick */
- 0x0057f108,
- 0x0654b608,
- 0xd0210698,
- 0x67f04056,
- 0x0063f141,
- 0x0546fd44,
- 0xc80054d0,
- 0x0bf40c3f,
- 0xc521f507,
-/* 0x0519: cmd_exec_done */
-/* 0x051b: cmd_wrcache_flush */
- 0xf100f803,
- 0xbd220027,
- 0x0133f034,
- 0xf80023d0,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
deleted file mode 100644
index 98cc4216a372..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/fuc/nvc0.fuc.h
+++ /dev/null
@@ -1,606 +0,0 @@
-uint32_t nvc0_pcopy_data[] = {
-/* 0x0000: ctx_object */
- 0x00000000,
-/* 0x0004: ctx_query_address_high */
- 0x00000000,
-/* 0x0008: ctx_query_address_low */
- 0x00000000,
-/* 0x000c: ctx_query_counter */
- 0x00000000,
-/* 0x0010: ctx_src_address_high */
- 0x00000000,
-/* 0x0014: ctx_src_address_low */
- 0x00000000,
-/* 0x0018: ctx_src_pitch */
- 0x00000000,
-/* 0x001c: ctx_src_tile_mode */
- 0x00000000,
-/* 0x0020: ctx_src_xsize */
- 0x00000000,
-/* 0x0024: ctx_src_ysize */
- 0x00000000,
-/* 0x0028: ctx_src_zsize */
- 0x00000000,
-/* 0x002c: ctx_src_zoff */
- 0x00000000,
-/* 0x0030: ctx_src_xoff */
- 0x00000000,
-/* 0x0034: ctx_src_yoff */
- 0x00000000,
-/* 0x0038: ctx_src_cpp */
- 0x00000000,
-/* 0x003c: ctx_dst_address_high */
- 0x00000000,
-/* 0x0040: ctx_dst_address_low */
- 0x00000000,
-/* 0x0044: ctx_dst_pitch */
- 0x00000000,
-/* 0x0048: ctx_dst_tile_mode */
- 0x00000000,
-/* 0x004c: ctx_dst_xsize */
- 0x00000000,
-/* 0x0050: ctx_dst_ysize */
- 0x00000000,
-/* 0x0054: ctx_dst_zsize */
- 0x00000000,
-/* 0x0058: ctx_dst_zoff */
- 0x00000000,
-/* 0x005c: ctx_dst_xoff */
- 0x00000000,
-/* 0x0060: ctx_dst_yoff */
- 0x00000000,
-/* 0x0064: ctx_dst_cpp */
- 0x00000000,
-/* 0x0068: ctx_format */
- 0x00000000,
-/* 0x006c: ctx_swz_const0 */
- 0x00000000,
-/* 0x0070: ctx_swz_const1 */
- 0x00000000,
-/* 0x0074: ctx_xcnt */
- 0x00000000,
-/* 0x0078: ctx_ycnt */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: dispatch_table */
- 0x00010000,
- 0x00000000,
- 0x00000000,
- 0x00010040,
- 0x0001019f,
- 0x00000000,
- 0x00010050,
- 0x000101a1,
- 0x00000000,
- 0x00070080,
- 0x0000001c,
- 0xfffff000,
- 0x00000020,
- 0xfff80000,
- 0x00000024,
- 0xffffe000,
- 0x00000028,
- 0xfffff800,
- 0x0000002c,
- 0xfffff000,
- 0x00000030,
- 0xfff80000,
- 0x00000034,
- 0xffffe000,
- 0x00070088,
- 0x00000048,
- 0xfffff000,
- 0x0000004c,
- 0xfff80000,
- 0x00000050,
- 0xffffe000,
- 0x00000054,
- 0xfffff800,
- 0x00000058,
- 0xfffff000,
- 0x0000005c,
- 0xfff80000,
- 0x00000060,
- 0xffffe000,
- 0x000200c0,
- 0x000104b8,
- 0x00000000,
- 0x00010541,
- 0x00000000,
- 0x000e00c3,
- 0x00000010,
- 0xffffff00,
- 0x00000014,
- 0x00000000,
- 0x0000003c,
- 0xffffff00,
- 0x00000040,
- 0x00000000,
- 0x00000018,
- 0xfff80000,
- 0x00000044,
- 0xfff80000,
- 0x00000074,
- 0xffff0000,
- 0x00000078,
- 0xffffe000,
- 0x00000068,
- 0xfccc0000,
- 0x0000006c,
- 0x00000000,
- 0x00000070,
- 0x00000000,
- 0x00000004,
- 0xffffff00,
- 0x00000008,
- 0x00000000,
- 0x0000000c,
- 0x00000000,
- 0x00000800,
-};
-
-uint32_t nvc0_pcopy_code[] = {
-/* 0x0000: main */
- 0x04fe04bd,
- 0x3517f000,
- 0xf10010fe,
- 0xf1040017,
- 0xf0fff327,
- 0x12d00023,
- 0x0c25f0c0,
- 0xf40012d0,
- 0x17f11031,
- 0x27f01200,
- 0x0012d003,
-/* 0x002f: spin */
- 0xf40031f4,
- 0x0ef40028,
-/* 0x0035: ih */
- 0x8001cffd,
- 0xf40812c4,
- 0x21f4060b,
-/* 0x0041: ih_no_chsw */
- 0x0412c4ca,
- 0xf5070bf4,
-/* 0x004b: ih_no_cmd */
- 0xc4010221,
- 0x01d00c11,
-/* 0x0053: swctx */
- 0xf101f840,
- 0xfe770047,
- 0x47f1004b,
- 0x44cf2100,
- 0x0144f000,
- 0xb60444b6,
- 0xf7f13040,
- 0xf4b6061c,
- 0x1457f106,
- 0x00f5d101,
- 0xb6043594,
- 0x57fe0250,
- 0x0145fe00,
- 0x010052b7,
- 0x00ff67f1,
- 0x56fd60bd,
- 0x0253f004,
- 0xf80545fa,
- 0x0053f003,
- 0xd100e7f0,
- 0x549800fe,
- 0x0845b600,
- 0xb6015698,
- 0x46fd1864,
- 0x0047fe05,
- 0xf00204b9,
- 0x01f40643,
- 0x0604fa09,
-/* 0x00c3: swctx_load */
- 0xfa060ef4,
-/* 0x00c6: swctx_done */
- 0x03f80504,
-/* 0x00ca: chsw */
- 0x27f100f8,
- 0x23cf1400,
- 0x1e3fc800,
- 0xf4170bf4,
- 0x21f40132,
- 0x1e3af053,
- 0xf00023d0,
- 0x24d00147,
-/* 0x00eb: chsw_no_unload */
- 0xcf00f880,
- 0x3dc84023,
- 0x090bf41e,
- 0xf40131f4,
-/* 0x00fa: chsw_finish_load */
- 0x37f05321,
- 0x8023d002,
-/* 0x0102: dispatch */
- 0x37f100f8,
- 0x32cf1900,
- 0x0033cf40,
- 0x07ff24e4,
- 0xf11024b6,
- 0xbd010057,
-/* 0x011b: dispatch_loop */
- 0x5874bd64,
- 0x57580056,
- 0x0450b601,
- 0xf40446b8,
- 0x76bb4d08,
- 0x0447b800,
- 0xbb0f08f4,
- 0x74b60276,
- 0x0057bb03,
-/* 0x013f: dispatch_valid_mthd */
- 0xbbdf0ef4,
- 0x44b60246,
- 0x0045bb03,
- 0xfd014598,
- 0x54b00453,
- 0x201bf400,
- 0x58004558,
- 0x64b00146,
- 0x091bf400,
- 0xf4005380,
-/* 0x0166: dispatch_cmd */
- 0x32f4300e,
- 0xf455f901,
- 0x0ef40c01,
-/* 0x0171: dispatch_invalid_bitfield */
- 0x0225f025,
-/* 0x0174: dispatch_illegal_mthd */
-/* 0x0177: dispatch_error */
- 0xf10125f0,
- 0xd0100047,
- 0x43d00042,
- 0x4027f040,
-/* 0x0187: hostirq_wait */
- 0xcf0002d0,
- 0x24f08002,
- 0x0024b040,
-/* 0x0193: dispatch_done */
- 0xf1f71bf4,
- 0xf01d0027,
- 0x23d00137,
-/* 0x019f: cmd_nop */
- 0xf800f800,
-/* 0x01a1: cmd_pm_trigger */
- 0x0027f100,
- 0xf034bd22,
- 0x23d00233,
-/* 0x01af: cmd_exec_set_format */
- 0xf400f800,
- 0x01b0f030,
- 0x0101b000,
- 0xb00201b0,
- 0x04980301,
- 0x3045c71a,
- 0xc70150b6,
- 0x60b63446,
- 0x3847c701,
- 0xf40170b6,
- 0x84bd0232,
-/* 0x01da: ncomp_loop */
- 0x4ac494bd,
- 0x0445b60f,
-/* 0x01e2: bpc_loop */
- 0xa430b4bd,
- 0x0f18f404,
- 0xbbc0a5ff,
- 0x31f400cb,
- 0x220ef402,
-/* 0x01f4: cmp_c0 */
- 0xf00c1bf4,
- 0xcbbb10c7,
- 0x160ef400,
-/* 0x0200: cmp_c1 */
- 0xf406a430,
- 0xc7f00c18,
- 0x00cbbb14,
-/* 0x020f: cmp_zero */
- 0xf1070ef4,
-/* 0x0213: bpc_next */
- 0x380080c7,
- 0x80b601c8,
- 0x01b0b601,
- 0xf404b5b8,
- 0x90b6c308,
- 0x0497b801,
- 0xfdb208f4,
- 0x06800065,
- 0x1d08980e,
- 0xf40068fd,
- 0x64bd0502,
-/* 0x023c: dst_xcnt */
- 0x800075fd,
- 0x78fd1907,
- 0x1057f100,
- 0x0654b608,
- 0xd00056d0,
- 0x50b74057,
- 0x06980800,
- 0x0162b619,
- 0x980864b6,
- 0x72b60e07,
- 0x0567fd01,
- 0xb70056d0,
- 0xb4010050,
- 0x56d00060,
- 0x0160b400,
- 0xb44056d0,
- 0x56d00260,
- 0x0360b480,
- 0xb7c056d0,
- 0x98040050,
- 0x56d01b06,
- 0x1c069800,
- 0xf44056d0,
- 0x00f81030,
-/* 0x029c: cmd_exec_set_surface_tiled */
- 0xc7075798,
- 0x78c76879,
- 0x0380b664,
- 0xb06077c7,
- 0x1bf40e76,
- 0x0477f009,
-/* 0x02b7: xtile64 */
- 0xf00f0ef4,
- 0x70b6027c,
- 0x0947fd11,
-/* 0x02c3: xtileok */
- 0x980677f0,
- 0x5b980c5a,
- 0x00abfd0e,
- 0xbb01b7f0,
- 0xb2b604b7,
- 0xc4abff01,
- 0x9805a7bb,
- 0xe7f00d5d,
- 0x04e8bb01,
- 0xff01e2b6,
- 0xd8bbb4de,
- 0x01e0b605,
- 0xbb0cef94,
- 0xfefd02eb,
- 0x026cf005,
- 0x020860b7,
- 0xd00864b6,
- 0xb7bb006f,
- 0x00cbbb04,
- 0x98085f98,
- 0xfbfd0e5b,
- 0x01b7f000,
- 0xb604b7bb,
- 0xfbbb01b2,
- 0x05f7bb00,
- 0x5f98f0f9,
- 0x01b7f009,
- 0xb604b8bb,
- 0xfbbb01b2,
- 0x05f8bb00,
- 0x78bbf0f9,
- 0x0282b600,
- 0xbb01b7f0,
- 0xb9bb04b8,
- 0x0b589804,
- 0xbb01e7f0,
- 0xe2b604e9,
- 0xf48eff01,
- 0xbb04f7bb,
- 0x79bb00cf,
- 0x0589bb00,
- 0x90fcf0fc,
- 0xbb00d9fd,
- 0x89fd00ad,
- 0x008ffd00,
- 0xbb00a8bb,
- 0x92b604a7,
- 0x0497bb01,
- 0x988069d0,
- 0x58980557,
- 0x00acbb04,
- 0xb6007abb,
- 0x84b60081,
- 0x058bfd10,
- 0x060062b7,
- 0xb70067d0,
- 0xd0040060,
- 0x00f80068,
-/* 0x03a8: cmd_exec_set_surface_linear */
- 0xb7026cf0,
- 0xb6020260,
- 0x57980864,
- 0x0067d005,
- 0x040060b7,
- 0xb6045798,
- 0x67d01074,
- 0x0060b700,
- 0x06579804,
- 0xf80067d0,
-/* 0x03d1: cmd_exec_wait */
- 0xf900f900,
- 0x0007f110,
- 0x0604b608,
-/* 0x03dc: loop */
- 0xf00001cf,
- 0x1bf40114,
- 0xfc10fcfa,
-/* 0x03eb: cmd_exec_query */
- 0xc800f800,
- 0x1bf40d34,
- 0xd121f570,
- 0x0c47f103,
- 0x0644b608,
- 0xb6020598,
- 0x45d00450,
- 0x4040d000,
- 0xd00c57f0,
- 0x40b78045,
- 0x05980400,
- 0x1054b601,
- 0xb70045d0,
- 0xf1050040,
- 0xf00b0057,
- 0x45d00153,
- 0x4057f100,
- 0x0154b640,
- 0x808053f1,
- 0xf14045d0,
- 0xf1111057,
- 0xd0131253,
- 0x57f18045,
- 0x53f11514,
- 0x45d01716,
- 0x0157f1c0,
- 0x0153f026,
- 0x080047f1,
- 0xd00644b6,
-/* 0x045e: query_counter */
- 0x21f50045,
- 0x47f103d1,
- 0x44b6080c,
- 0x02059806,
- 0xd00045d0,
- 0x57f04040,
- 0x8045d004,
- 0x040040b7,
- 0xb6010598,
- 0x45d01054,
- 0x0040b700,
- 0x0057f105,
- 0x0045d003,
- 0x111057f1,
- 0x131253f1,
- 0x984045d0,
- 0x40b70305,
- 0x45d00500,
- 0x0157f100,
- 0x0153f026,
- 0x080047f1,
- 0xd00644b6,
- 0x00f80045,
-/* 0x04b8: cmd_exec */
- 0x03d121f5,
- 0xf4003fc8,
- 0x21f50e0b,
- 0x47f101af,
- 0x0ef40200,
-/* 0x04cd: cmd_exec_no_format */
- 0x1067f11e,
- 0x0664b608,
- 0x800177f0,
- 0x07800e07,
- 0x1d079819,
- 0xd00067d0,
- 0x44bd4067,
-/* 0x04e8: cmd_exec_init_src_surface */
- 0xbd0232f4,
- 0x043fc854,
- 0xf50a0bf4,
- 0xf403a821,
-/* 0x04fa: src_tiled */
- 0x21f50a0e,
- 0x49f0029c,
-/* 0x0501: cmd_exec_init_dst_surface */
- 0x0231f407,
- 0xc82c57f0,
- 0x0bf4083f,
- 0xa821f50a,
- 0x0a0ef403,
-/* 0x0514: dst_tiled */
- 0x029c21f5,
-/* 0x051b: cmd_exec_kick */
- 0xf10849f0,
- 0xb6080057,
- 0x06980654,
- 0x4056d01e,
- 0xf14167f0,
- 0xfd440063,
- 0x54d00546,
- 0x0c3fc800,
- 0xf5070bf4,
-/* 0x053f: cmd_exec_done */
- 0xf803eb21,
-/* 0x0541: cmd_wrcache_flush */
- 0x0027f100,
- 0xf034bd22,
- 0x23d00133,
- 0x0000f800,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c b/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
deleted file mode 100644
index abb410ef09ea..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nva3.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/fifo.h>
-#include <engine/copy.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include <core/client.h>
-#include <core/enum.h>
-
-
-#include "fuc/nva3.fuc.h"
-
-struct nva3_copy_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * Copy object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva3_copy_sclass[] = {
- { 0x85b5, &nouveau_object_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PCOPY context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva3_copy_cclass = {
- .handle = NV_ENGCTX(COPY0, 0xa3),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
-
- },
-};
-
-/*******************************************************************************
- * PCOPY engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_enum nva3_copy_isr_error_name[] = {
- { 0x0001, "ILLEGAL_MTHD" },
- { 0x0002, "INVALID_ENUM" },
- { 0x0003, "INVALID_BITFIELD" },
- {}
-};
-
-void
-nva3_copy_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_falcon *falcon = (void *)subdev;
- struct nouveau_object *engctx;
- u32 dispatch = nv_ro32(falcon, 0x01c);
- u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
- u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff;
- u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff;
- u32 addr = nv_ro32(falcon, 0x040) >> 16;
- u32 mthd = (addr & 0x07ff) << 2;
- u32 subc = (addr & 0x3800) >> 11;
- u32 data = nv_ro32(falcon, 0x044);
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & 0x00000040) {
- nv_error(falcon, "DISPATCH_ERROR [");
- nouveau_enum_print(nva3_copy_isr_error_name, ssta);
- pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
- chid, inst << 12, nouveau_client_name(engctx), subc,
- mthd, data);
- nv_wo32(falcon, 0x004, 0x00000040);
- stat &= ~0x00000040;
- }
-
- if (stat) {
- nv_error(falcon, "unhandled intr 0x%08x\n", stat);
- nv_wo32(falcon, 0x004, stat);
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static int
-nva3_copy_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- bool enable = (nv_device(parent)->chipset != 0xaf);
- struct nva3_copy_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, enable,
- "PCE0", "copy0", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00802000;
- nv_subdev(priv)->intr = nva3_copy_intr;
- nv_engine(priv)->cclass = &nva3_copy_cclass;
- nv_engine(priv)->sclass = nva3_copy_sclass;
- nv_falcon(priv)->code.data = nva3_pcopy_code;
- nv_falcon(priv)->code.size = sizeof(nva3_pcopy_code);
- nv_falcon(priv)->data.data = nva3_pcopy_data;
- nv_falcon(priv)->data.size = sizeof(nva3_pcopy_data);
- return 0;
-}
-
-struct nouveau_oclass
-nva3_copy_oclass = {
- .handle = NV_ENGINE(COPY0, 0xa3),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_copy_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = _nouveau_falcon_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
deleted file mode 100644
index 9261694d0d35..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nvc0.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/fifo.h>
-#include <engine/copy.h>
-
-#include <core/enum.h>
-#include <core/enum.h>
-
-#include "fuc/nvc0.fuc.h"
-
-struct nvc0_copy_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * Copy object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_copy0_sclass[] = {
- { 0x90b5, &nouveau_object_ofuncs },
- {},
-};
-
-static struct nouveau_oclass
-nvc0_copy1_sclass[] = {
- { 0x90b8, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PCOPY context
- ******************************************************************************/
-
-static struct nouveau_ofuncs
-nvc0_copy_context_ofuncs = {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
-};
-
-static struct nouveau_oclass
-nvc0_copy0_cclass = {
- .handle = NV_ENGCTX(COPY0, 0xc0),
- .ofuncs = &nvc0_copy_context_ofuncs,
-};
-
-static struct nouveau_oclass
-nvc0_copy1_cclass = {
- .handle = NV_ENGCTX(COPY1, 0xc0),
- .ofuncs = &nvc0_copy_context_ofuncs,
-};
-
-/*******************************************************************************
- * PCOPY engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_copy_init(struct nouveau_object *object)
-{
- struct nvc0_copy_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wo32(priv, 0x084, nv_engidx(object) - NVDEV_ENGINE_COPY0);
- return 0;
-}
-
-static int
-nvc0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_copy_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x104000, true,
- "PCE0", "copy0", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000040;
- nv_subdev(priv)->intr = nva3_copy_intr;
- nv_engine(priv)->cclass = &nvc0_copy0_cclass;
- nv_engine(priv)->sclass = nvc0_copy0_sclass;
- nv_falcon(priv)->code.data = nvc0_pcopy_code;
- nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
- nv_falcon(priv)->data.data = nvc0_pcopy_data;
- nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
- return 0;
-}
-
-static int
-nvc0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_copy_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x105000, true,
- "PCE1", "copy1", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000080;
- nv_subdev(priv)->intr = nva3_copy_intr;
- nv_engine(priv)->cclass = &nvc0_copy1_cclass;
- nv_engine(priv)->sclass = nvc0_copy1_sclass;
- nv_falcon(priv)->code.data = nvc0_pcopy_code;
- nv_falcon(priv)->code.size = sizeof(nvc0_pcopy_code);
- nv_falcon(priv)->data.data = nvc0_pcopy_data;
- nv_falcon(priv)->data.size = sizeof(nvc0_pcopy_data);
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_copy0_oclass = {
- .handle = NV_ENGINE(COPY0, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_copy0_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_copy_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
-
-struct nouveau_oclass
-nvc0_copy1_oclass = {
- .handle = NV_ENGINE(COPY1, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_copy1_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_copy_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c b/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
deleted file mode 100644
index c7194b354605..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/copy/nve0.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-
-#include <engine/copy.h>
-
-struct nve0_copy_priv {
- struct nouveau_engine base;
-};
-
-/*******************************************************************************
- * Copy object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_copy_sclass[] = {
- { 0xa0b5, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PCOPY context
- ******************************************************************************/
-
-static struct nouveau_ofuncs
-nve0_copy_context_ofuncs = {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
-};
-
-static struct nouveau_oclass
-nve0_copy_cclass = {
- .handle = NV_ENGCTX(COPY0, 0xc0),
- .ofuncs = &nve0_copy_context_ofuncs,
-};
-
-/*******************************************************************************
- * PCOPY engine/subdev functions
- ******************************************************************************/
-
-static void
-nve0_copy_intr(struct nouveau_subdev *subdev)
-{
- const int ce = nv_subidx(nv_object(subdev)) - NVDEV_ENGINE_COPY0;
- struct nve0_copy_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
-
- if (stat) {
- nv_warn(priv, "unhandled intr 0x%08x\n", stat);
- nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
- }
-}
-
-static int
-nve0_copy0_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_copy_priv *priv;
- int ret;
-
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCE0", "copy0", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000040;
- nv_subdev(priv)->intr = nve0_copy_intr;
- nv_engine(priv)->cclass = &nve0_copy_cclass;
- nv_engine(priv)->sclass = nve0_copy_sclass;
- return 0;
-}
-
-static int
-nve0_copy1_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_copy_priv *priv;
- int ret;
-
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCE1", "copy1", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000080;
- nv_subdev(priv)->intr = nve0_copy_intr;
- nv_engine(priv)->cclass = &nve0_copy_cclass;
- nv_engine(priv)->sclass = nve0_copy_sclass;
- return 0;
-}
-
-static int
-nve0_copy2_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_copy_priv *priv;
- int ret;
-
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCE2", "copy2", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00200000;
- nv_subdev(priv)->intr = nve0_copy_intr;
- nv_engine(priv)->cclass = &nve0_copy_cclass;
- nv_engine(priv)->sclass = nve0_copy_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_copy0_oclass = {
- .handle = NV_ENGINE(COPY0, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_copy0_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
- },
-};
-
-struct nouveau_oclass
-nve0_copy1_oclass = {
- .handle = NV_ENGINE(COPY1, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_copy1_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
- },
-};
-
-struct nouveau_oclass
-nve0_copy2_oclass = {
- .handle = NV_ENGINE(COPY2, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_copy2_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = _nouveau_engine_init,
- .fini = _nouveau_engine_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc
deleted file mode 100644
index 629da02dc352..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * fuc microcode for nv98 pcrypt engine
- * Copyright (C) 2010 Marcin Kościelnicki
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-.section #nv98_pcrypt_data
-
-ctx_dma:
-ctx_dma_query: .b32 0
-ctx_dma_src: .b32 0
-ctx_dma_dst: .b32 0
-.equ #dma_count 3
-ctx_query_address_high: .b32 0
-ctx_query_address_low: .b32 0
-ctx_query_counter: .b32 0
-ctx_cond_address_high: .b32 0
-ctx_cond_address_low: .b32 0
-ctx_cond_off: .b32 0
-ctx_src_address_high: .b32 0
-ctx_src_address_low: .b32 0
-ctx_dst_address_high: .b32 0
-ctx_dst_address_low: .b32 0
-ctx_mode: .b32 0
-.align 16
-ctx_key: .skip 16
-ctx_iv: .skip 16
-
-.align 0x80
-swap:
-.skip 32
-
-.align 8
-common_cmd_dtable:
-.b32 #ctx_query_address_high + 0x20000 ~0xff
-.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
-.b32 #ctx_query_counter + 0x20000 ~0xffffffff
-.b32 #cmd_query_get + 0x00000 ~1
-.b32 #ctx_cond_address_high + 0x20000 ~0xff
-.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
-.b32 #cmd_cond_mode + 0x00000 ~7
-.b32 #cmd_wrcache_flush + 0x00000 ~0
-.equ #common_cmd_max 0x88
-
-
-.align 8
-engine_cmd_dtable:
-.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
-.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
-.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
-.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
-.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
-.b32 #ctx_src_address_high + 0x20000 ~0xff
-.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
-.b32 #ctx_dst_address_high + 0x20000 ~0xff
-.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
-.b32 #crypt_cmd_mode + 0x00000 ~0xf
-.b32 #crypt_cmd_length + 0x10000 ~0x0ffffff0
-.equ #engine_cmd_max 0xce
-
-.align 4
-crypt_dtable:
-.b16 #crypt_copy_prep #crypt_do_inout
-.b16 #crypt_store_prep #crypt_do_out
-.b16 #crypt_ecb_e_prep #crypt_do_inout
-.b16 #crypt_ecb_d_prep #crypt_do_inout
-.b16 #crypt_cbc_e_prep #crypt_do_inout
-.b16 #crypt_cbc_d_prep #crypt_do_inout
-.b16 #crypt_pcbc_e_prep #crypt_do_inout
-.b16 #crypt_pcbc_d_prep #crypt_do_inout
-.b16 #crypt_cfb_e_prep #crypt_do_inout
-.b16 #crypt_cfb_d_prep #crypt_do_inout
-.b16 #crypt_ofb_prep #crypt_do_inout
-.b16 #crypt_ctr_prep #crypt_do_inout
-.b16 #crypt_cbc_mac_prep #crypt_do_in
-.b16 #crypt_cmac_finish_complete_prep #crypt_do_in
-.b16 #crypt_cmac_finish_partial_prep #crypt_do_in
-
-.align 0x100
-
-.section #nv98_pcrypt_code
-
- // $r0 is always set to 0 in our code - this allows some space savings.
- clear b32 $r0
-
- // set up the interrupt handler
- mov $r1 #ih
- mov $iv0 $r1
-
- // init stack pointer
- mov $sp $r0
-
- // set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
- movw $r1 0xfff0
- sethi $r1 0
- mov $r2 0x400
- iowr I[$r2 + 0x300] $r1
-
- // enable the interrupts
- or $r1 0xc
- iowr I[$r2] $r1
-
- // enable fifo access and context switching
- mov $r1 3
- mov $r2 0x1200
- iowr I[$r2] $r1
-
- // enable i0 delivery
- bset $flags ie0
-
- // sleep forver, waking only for interrupts.
- bset $flags $p0
- spin:
- sleep $p0
- bra #spin
-
-// i0 handler
-ih:
- // see which interrupts we got
- iord $r1 I[$r0 + 0x200]
-
- and $r2 $r1 0x8
- cmpu b32 $r2 0
- bra e #noctx
-
- // context switch... prepare the regs for xfer
- mov $r2 0x7700
- mov $xtargets $r2
- mov $xdbase $r0
- // 128-byte context.
- mov $r2 0
- sethi $r2 0x50000
-
- // read current channel
- mov $r3 0x1400
- iord $r4 I[$r3]
- // if bit 30 set, it's active, so we have to unload it first.
- shl b32 $r5 $r4 1
- cmps b32 $r5 0
- bra nc #ctxload
-
- // unload the current channel - save the context
- xdst $r0 $r2
- xdwait
- // and clear bit 30, then write back
- bclr $r4 0x1e
- iowr I[$r3] $r4
- // tell PFIFO we unloaded
- mov $r4 1
- iowr I[$r3 + 0x200] $r4
-
- bra #noctx
-
- ctxload:
- // no channel loaded - perhaps we're requested to load one
- iord $r4 I[$r3 + 0x100]
- shl b32 $r15 $r4 1
- cmps b32 $r15 0
- // if bit 30 of next channel not set, probably PFIFO is just
- // killing a context. do a faux load, without the active bit.
- bra nc #dummyload
-
- // ok, do a real context load.
- xdld $r0 $r2
- xdwait
- mov $r5 #ctx_dma
- mov $r6 #dma_count - 1
- ctxload_dma_loop:
- ld b32 $r7 D[$r5 + $r6 * 4]
- add b32 $r8 $r6 0x180
- shl b32 $r8 8
- iowr I[$r8] $r7
- sub b32 $r6 1
- bra nc #ctxload_dma_loop
-
- dummyload:
- // tell PFIFO we're done
- mov $r5 2
- iowr I[$r3 + 0x200] $r5
-
- noctx:
- and $r2 $r1 0x4
- cmpu b32 $r2 0
- bra e #nocmd
-
- // incoming fifo command.
- mov $r3 0x1900
- iord $r2 I[$r3 + 0x100]
- iord $r3 I[$r3]
- // extract the method
- and $r4 $r2 0x7ff
- // shift the addr to proper position if we need to interrupt later
- shl b32 $r2 0x10
-
- // mthd 0 and 0x100 [NAME, NOP]: ignore
- and $r5 $r4 0x7bf
- cmpu b32 $r5 0
- bra e #cmddone
-
- mov $r5 #engine_cmd_dtable - 0xc0 * 8
- mov $r6 #engine_cmd_max
- cmpu b32 $r4 0xc0
- bra nc #dtable_cmd
- mov $r5 #common_cmd_dtable - 0x80 * 8
- mov $r6 #common_cmd_max
- cmpu b32 $r4 0x80
- bra nc #dtable_cmd
- cmpu b32 $r4 0x60
- bra nc #dma_cmd
- cmpu b32 $r4 0x50
- bra ne #illegal_mthd
-
- // mthd 0x140: PM_TRIGGER
- mov $r2 0x2200
- clear b32 $r3
- sethi $r3 0x20000
- iowr I[$r2] $r3
- bra #cmddone
-
- dma_cmd:
- // mthd 0x180...: DMA_*
- cmpu b32 $r4 0x60+#dma_count
- bra nc #illegal_mthd
- shl b32 $r5 $r4 2
- add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
- bset $r3 0x1e
- st b32 D[$r5] $r3
- add b32 $r4 0x180 - 0x60
- shl b32 $r4 8
- iowr I[$r4] $r3
- bra #cmddone
-
- dtable_cmd:
- cmpu b32 $r4 $r6
- bra nc #illegal_mthd
- shl b32 $r4 3
- add b32 $r4 $r5
- ld b32 $r5 D[$r4 + 4]
- and $r5 $r3
- cmpu b32 $r5 0
- bra ne #invalid_bitfield
- ld b16 $r5 D[$r4]
- ld b16 $r6 D[$r4 + 2]
- cmpu b32 $r6 2
- bra e #cmd_setctx
- ld b32 $r7 D[$r0 + #ctx_cond_off]
- and $r6 $r7
- cmpu b32 $r6 1
- bra e #cmddone
- call $r5
- bra $p1 #dispatch_error
- bra #cmddone
-
- cmd_setctx:
- st b32 D[$r5] $r3
- bra #cmddone
-
-
- invalid_bitfield:
- or $r2 1
- dispatch_error:
- illegal_mthd:
- mov $r4 0x1000
- iowr I[$r4] $r2
- iowr I[$r4 + 0x100] $r3
- mov $r4 0x40
- iowr I[$r0] $r4
-
- im_loop:
- iord $r4 I[$r0 + 0x200]
- and $r4 0x40
- cmpu b32 $r4 0
- bra ne #im_loop
-
- cmddone:
- // remove the command from FIFO
- mov $r3 0x1d00
- mov $r4 1
- iowr I[$r3] $r4
-
- nocmd:
- // ack the processed interrupts
- and $r1 $r1 0xc
- iowr I[$r0 + 0x100] $r1
-iret
-
-cmd_query_get:
- // if bit 0 of param set, trigger interrupt afterwards.
- setp $p1 $r3
- or $r2 3
-
- // read PTIMER, beware of races...
- mov $r4 0xb00
- ptimer_retry:
- iord $r6 I[$r4 + 0x100]
- iord $r5 I[$r4]
- iord $r7 I[$r4 + 0x100]
- cmpu b32 $r6 $r7
- bra ne #ptimer_retry
-
- // prepare the query structure
- ld b32 $r4 D[$r0 + #ctx_query_counter]
- st b32 D[$r0 + #swap + 0x0] $r4
- st b32 D[$r0 + #swap + 0x4] $r0
- st b32 D[$r0 + #swap + 0x8] $r5
- st b32 D[$r0 + #swap + 0xc] $r6
-
- // will use target 0, DMA_QUERY.
- mov $xtargets $r0
-
- ld b32 $r4 D[$r0 + #ctx_query_address_high]
- shl b32 $r4 0x18
- mov $xdbase $r4
-
- ld b32 $r4 D[$r0 + #ctx_query_address_low]
- mov $r5 #swap
- sethi $r5 0x20000
- xdst $r4 $r5
- xdwait
-
- ret
-
-cmd_cond_mode:
- // if >= 5, INVALID_ENUM
- bset $flags $p1
- or $r2 2
- cmpu b32 $r3 5
- bra nc #return
-
- // otherwise, no error.
- bclr $flags $p1
-
- // if < 2, no QUERY object is involved
- cmpu b32 $r3 2
- bra nc #cmd_cond_mode_queryful
-
- xor $r3 1
- st b32 D[$r0 + #ctx_cond_off] $r3
- return:
- ret
-
- cmd_cond_mode_queryful:
- // ok, will need to pull a QUERY object, prepare offsets
- ld b32 $r4 D[$r0 + #ctx_cond_address_high]
- ld b32 $r5 D[$r0 + #ctx_cond_address_low]
- and $r6 $r5 0xff
- shr b32 $r5 8
- shl b32 $r4 0x18
- or $r4 $r5
- mov $xdbase $r4
- mov $xtargets $r0
-
- // pull the first one
- mov $r5 #swap
- sethi $r5 0x20000
- xdld $r6 $r5
-
- // if == 2, only a single QUERY is involved...
- cmpu b32 $r3 2
- bra ne #cmd_cond_mode_double
-
- xdwait
- ld b32 $r4 D[$r0 + #swap + 4]
- cmpu b32 $r4 0
- xbit $r4 $flags z
- st b32 D[$r0 + #ctx_cond_off] $r4
- ret
-
- // ok, we'll need to pull second one too
- cmd_cond_mode_double:
- add b32 $r6 0x10
- add b32 $r5 0x10
- xdld $r6 $r5
- xdwait
-
- // compare COUNTERs
- ld b32 $r5 D[$r0 + #swap + 0x00]
- ld b32 $r6 D[$r0 + #swap + 0x10]
- cmpu b32 $r5 $r6
- xbit $r4 $flags z
-
- // compare RESen
- ld b32 $r5 D[$r0 + #swap + 0x04]
- ld b32 $r6 D[$r0 + #swap + 0x14]
- cmpu b32 $r5 $r6
- xbit $r5 $flags z
- and $r4 $r5
-
- // and negate or not, depending on mode
- cmpu b32 $r3 3
- xbit $r5 $flags z
- xor $r4 $r5
- st b32 D[$r0 + #ctx_cond_off] $r4
- ret
-
-cmd_wrcache_flush:
- bclr $flags $p1
- mov $r2 0x2200
- clear b32 $r3
- sethi $r3 0x10000
- iowr I[$r2] $r3
- ret
-
-crypt_cmd_mode:
- // if >= 0xf, INVALID_ENUM
- bset $flags $p1
- or $r2 2
- cmpu b32 $r3 0xf
- bra nc #crypt_cmd_mode_return
-
- bclr $flags $p1
- st b32 D[$r0 + #ctx_mode] $r3
-
- crypt_cmd_mode_return:
- ret
-
-crypt_cmd_length:
- // nop if length == 0
- cmpu b32 $r3 0
- bra e #crypt_cmd_mode_return
-
- // init key, IV
- cxset 3
- mov $r4 #ctx_key
- sethi $r4 0x70000
- xdst $r0 $r4
- mov $r4 #ctx_iv
- sethi $r4 0x60000
- xdst $r0 $r4
- xdwait
- ckeyreg $c7
-
- // prepare the targets
- mov $r4 0x2100
- mov $xtargets $r4
-
- // prepare src address
- ld b32 $r4 D[$r0 + #ctx_src_address_high]
- ld b32 $r5 D[$r0 + #ctx_src_address_low]
- shr b32 $r8 $r5 8
- shl b32 $r4 0x18
- or $r4 $r8
- and $r5 $r5 0xff
-
- // prepare dst address
- ld b32 $r6 D[$r0 + #ctx_dst_address_high]
- ld b32 $r7 D[$r0 + #ctx_dst_address_low]
- shr b32 $r8 $r7 8
- shl b32 $r6 0x18
- or $r6 $r8
- and $r7 $r7 0xff
-
- // find the proper prep & do functions
- ld b32 $r8 D[$r0 + #ctx_mode]
- shl b32 $r8 2
-
- // run prep
- ld b16 $r9 D[$r8 + #crypt_dtable]
- call $r9
-
- // do it
- ld b16 $r9 D[$r8 + #crypt_dtable + 2]
- call $r9
- cxset 1
- xdwait
- cxset 0x61
- xdwait
- xdwait
-
- // update src address
- shr b32 $r8 $r4 0x18
- shl b32 $r9 $r4 8
- add b32 $r9 $r5
- adc b32 $r8 0
- st b32 D[$r0 + #ctx_src_address_high] $r8
- st b32 D[$r0 + #ctx_src_address_low] $r9
-
- // update dst address
- shr b32 $r8 $r6 0x18
- shl b32 $r9 $r6 8
- add b32 $r9 $r7
- adc b32 $r8 0
- st b32 D[$r0 + #ctx_dst_address_high] $r8
- st b32 D[$r0 + #ctx_dst_address_low] $r9
-
- // pull updated IV
- cxset 2
- mov $r4 #ctx_iv
- sethi $r4 0x60000
- xdld $r0 $r4
- xdwait
-
- ret
-
-
-crypt_copy_prep:
- cs0begin 2
- cxsin $c0
- cxsout $c0
- ret
-
-crypt_store_prep:
- cs0begin 1
- cxsout $c6
- ret
-
-crypt_ecb_e_prep:
- cs0begin 3
- cxsin $c0
- cenc $c0 $c0
- cxsout $c0
- ret
-
-crypt_ecb_d_prep:
- ckexp $c7 $c7
- cs0begin 3
- cxsin $c0
- cdec $c0 $c0
- cxsout $c0
- ret
-
-crypt_cbc_e_prep:
- cs0begin 4
- cxsin $c0
- cxor $c6 $c0
- cenc $c6 $c6
- cxsout $c6
- ret
-
-crypt_cbc_d_prep:
- ckexp $c7 $c7
- cs0begin 5
- cmov $c2 $c6
- cxsin $c6
- cdec $c0 $c6
- cxor $c0 $c2
- cxsout $c0
- ret
-
-crypt_pcbc_e_prep:
- cs0begin 5
- cxsin $c0
- cxor $c6 $c0
- cenc $c6 $c6
- cxsout $c6
- cxor $c6 $c0
- ret
-
-crypt_pcbc_d_prep:
- ckexp $c7 $c7
- cs0begin 5
- cxsin $c0
- cdec $c1 $c0
- cxor $c6 $c1
- cxsout $c6
- cxor $c6 $c0
- ret
-
-crypt_cfb_e_prep:
- cs0begin 4
- cenc $c6 $c6
- cxsin $c0
- cxor $c6 $c0
- cxsout $c6
- ret
-
-crypt_cfb_d_prep:
- cs0begin 4
- cenc $c0 $c6
- cxsin $c6
- cxor $c0 $c6
- cxsout $c0
- ret
-
-crypt_ofb_prep:
- cs0begin 4
- cenc $c6 $c6
- cxsin $c0
- cxor $c0 $c6
- cxsout $c0
- ret
-
-crypt_ctr_prep:
- cs0begin 5
- cenc $c1 $c6
- cadd $c6 1
- cxsin $c0
- cxor $c0 $c1
- cxsout $c0
- ret
-
-crypt_cbc_mac_prep:
- cs0begin 3
- cxsin $c0
- cxor $c6 $c0
- cenc $c6 $c6
- ret
-
-crypt_cmac_finish_complete_prep:
- cs0begin 7
- cxsin $c0
- cxor $c6 $c0
- cxor $c0 $c0
- cenc $c0 $c0
- cprecmac $c0 $c0
- cxor $c6 $c0
- cenc $c6 $c6
- ret
-
-crypt_cmac_finish_partial_prep:
- cs0begin 8
- cxsin $c0
- cxor $c6 $c0
- cxor $c0 $c0
- cenc $c0 $c0
- cprecmac $c0 $c0
- cprecmac $c0 $c0
- cxor $c6 $c0
- cenc $c6 $c6
- ret
-
-// TODO
-crypt_do_in:
- add b32 $r3 $r5
- mov $xdbase $r4
- mov $r9 #swap
- sethi $r9 0x20000
- crypt_do_in_loop:
- xdld $r5 $r9
- xdwait
- cxset 0x22
- xdst $r0 $r9
- cs0exec 1
- xdwait
- add b32 $r5 0x10
- cmpu b32 $r5 $r3
- bra ne #crypt_do_in_loop
- cxset 1
- xdwait
- ret
-
-crypt_do_out:
- add b32 $r3 $r7
- mov $xdbase $r6
- mov $r9 #swap
- sethi $r9 0x20000
- crypt_do_out_loop:
- cs0exec 1
- cxset 0x61
- xdld $r7 $r9
- xdst $r7 $r9
- cxset 1
- xdwait
- add b32 $r7 0x10
- cmpu b32 $r7 $r3
- bra ne #crypt_do_out_loop
- ret
-
-crypt_do_inout:
- add b32 $r3 $r5
- mov $r9 #swap
- sethi $r9 0x20000
- crypt_do_inout_loop:
- mov $xdbase $r4
- xdld $r5 $r9
- xdwait
- cxset 0x21
- xdst $r0 $r9
- cs0exec 1
- cxset 0x61
- mov $xdbase $r6
- xdld $r7 $r9
- xdst $r7 $r9
- cxset 1
- xdwait
- add b32 $r5 0x10
- add b32 $r7 0x10
- cmpu b32 $r5 $r3
- bra ne #crypt_do_inout_loop
- ret
-
-.align 0x100
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h b/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
deleted file mode 100644
index 38676c74e6e0..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/fuc/nv98.fuc.h
+++ /dev/null
@@ -1,584 +0,0 @@
-uint32_t nv98_pcrypt_data[] = {
-/* 0x0000: ctx_dma */
-/* 0x0000: ctx_dma_query */
- 0x00000000,
-/* 0x0004: ctx_dma_src */
- 0x00000000,
-/* 0x0008: ctx_dma_dst */
- 0x00000000,
-/* 0x000c: ctx_query_address_high */
- 0x00000000,
-/* 0x0010: ctx_query_address_low */
- 0x00000000,
-/* 0x0014: ctx_query_counter */
- 0x00000000,
-/* 0x0018: ctx_cond_address_high */
- 0x00000000,
-/* 0x001c: ctx_cond_address_low */
- 0x00000000,
-/* 0x0020: ctx_cond_off */
- 0x00000000,
-/* 0x0024: ctx_src_address_high */
- 0x00000000,
-/* 0x0028: ctx_src_address_low */
- 0x00000000,
-/* 0x002c: ctx_dst_address_high */
- 0x00000000,
-/* 0x0030: ctx_dst_address_low */
- 0x00000000,
-/* 0x0034: ctx_mode */
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0040: ctx_key */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0050: ctx_iv */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0080: swap */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x00a0: common_cmd_dtable */
- 0x0002000c,
- 0xffffff00,
- 0x00020010,
- 0x0000000f,
- 0x00020014,
- 0x00000000,
- 0x00000192,
- 0xfffffffe,
- 0x00020018,
- 0xffffff00,
- 0x0002001c,
- 0x0000000f,
- 0x000001d7,
- 0xfffffff8,
- 0x00000260,
- 0xffffffff,
-/* 0x00e0: engine_cmd_dtable */
- 0x00020040,
- 0x00000000,
- 0x00020044,
- 0x00000000,
- 0x00020048,
- 0x00000000,
- 0x0002004c,
- 0x00000000,
- 0x00020050,
- 0x00000000,
- 0x00020054,
- 0x00000000,
- 0x00020058,
- 0x00000000,
- 0x0002005c,
- 0x00000000,
- 0x00020024,
- 0xffffff00,
- 0x00020028,
- 0x0000000f,
- 0x0002002c,
- 0xffffff00,
- 0x00020030,
- 0x0000000f,
- 0x00000271,
- 0xfffffff0,
- 0x00010285,
- 0xf000000f,
-/* 0x0150: crypt_dtable */
- 0x04db0321,
- 0x04b1032f,
- 0x04db0339,
- 0x04db034b,
- 0x04db0361,
- 0x04db0377,
- 0x04db0395,
- 0x04db03af,
- 0x04db03cd,
- 0x04db03e3,
- 0x04db03f9,
- 0x04db040f,
- 0x04830429,
- 0x0483043b,
- 0x0483045d,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nv98_pcrypt_code[] = {
- 0x17f004bd,
- 0x0010fe35,
- 0xf10004fe,
- 0xf0fff017,
- 0x27f10013,
- 0x21d00400,
- 0x0c15f0c0,
- 0xf00021d0,
- 0x27f10317,
- 0x21d01200,
- 0x1031f400,
-/* 0x002f: spin */
- 0xf40031f4,
- 0x0ef40028,
-/* 0x0035: ih */
- 0x8001cffd,
- 0xb00812c4,
- 0x0bf40024,
- 0x0027f167,
- 0x002bfe77,
- 0xf00007fe,
- 0x23f00027,
- 0x0037f105,
- 0x0034cf14,
- 0xb0014594,
- 0x18f40055,
- 0x0602fa17,
- 0x4af003f8,
- 0x0034d01e,
- 0xd00147f0,
- 0x0ef48034,
-/* 0x0075: ctxload */
- 0x4034cf33,
- 0xb0014f94,
- 0x18f400f5,
- 0x0502fa21,
- 0x57f003f8,
- 0x0267f000,
-/* 0x008c: ctxload_dma_loop */
- 0xa07856bc,
- 0xb6018068,
- 0x87d00884,
- 0x0162b600,
-/* 0x009f: dummyload */
- 0xf0f018f4,
- 0x35d00257,
-/* 0x00a5: noctx */
- 0x0412c480,
- 0xf50024b0,
- 0xf100df0b,
- 0xcf190037,
- 0x33cf4032,
- 0xff24e400,
- 0x1024b607,
- 0x07bf45e4,
- 0xf50054b0,
- 0xf100b90b,
- 0xf1fae057,
- 0xb000ce67,
- 0x18f4c044,
- 0xa057f14d,
- 0x8867f1fc,
- 0x8044b000,
- 0xb03f18f4,
- 0x18f46044,
- 0x5044b019,
- 0xf1741bf4,
- 0xbd220027,
- 0x0233f034,
- 0xf50023d0,
-/* 0x0103: dma_cmd */
- 0xb000810e,
- 0x18f46344,
- 0x0245945e,
- 0xfe8050b7,
- 0x801e39f0,
- 0x40b70053,
- 0x44b60120,
- 0x0043d008,
-/* 0x0123: dtable_cmd */
- 0xb8600ef4,
- 0x18f40446,
- 0x0344b63e,
- 0x980045bb,
- 0x53fd0145,
- 0x0054b004,
- 0x58291bf4,
- 0x46580045,
- 0x0264b001,
- 0x98170bf4,
- 0x67fd0807,
- 0x0164b004,
- 0xf9300bf4,
- 0x0f01f455,
-/* 0x015b: cmd_setctx */
- 0x80280ef4,
- 0x0ef40053,
-/* 0x0161: invalid_bitfield */
- 0x0125f022,
-/* 0x0164: dispatch_error */
-/* 0x0164: illegal_mthd */
- 0x100047f1,
- 0xd00042d0,
- 0x47f04043,
- 0x0004d040,
-/* 0x0174: im_loop */
- 0xf08004cf,
- 0x44b04044,
- 0xf71bf400,
-/* 0x0180: cmddone */
- 0x1d0037f1,
- 0xd00147f0,
-/* 0x018a: nocmd */
- 0x11c40034,
- 0x4001d00c,
-/* 0x0192: cmd_query_get */
- 0x38f201f8,
- 0x0325f001,
- 0x0b0047f1,
-/* 0x019c: ptimer_retry */
- 0xcf4046cf,
- 0x47cf0045,
- 0x0467b840,
- 0x98f41bf4,
- 0x04800504,
- 0x21008020,
- 0x80220580,
- 0x0bfe2306,
- 0x03049800,
- 0xfe1844b6,
- 0x04980047,
- 0x8057f104,
- 0x0253f000,
- 0xf80645fa,
-/* 0x01d7: cmd_cond_mode */
- 0xf400f803,
- 0x25f00131,
- 0x0534b002,
- 0xf41218f4,
- 0x34b00132,
- 0x0b18f402,
- 0x800136f0,
-/* 0x01f2: return */
- 0x00f80803,
-/* 0x01f4: cmd_cond_mode_queryful */
- 0x98060498,
- 0x56c40705,
- 0x0855b6ff,
- 0xfd1844b6,
- 0x47fe0545,
- 0x000bfe00,
- 0x008057f1,
- 0xfa0253f0,
- 0x34b00565,
- 0x131bf402,
- 0x049803f8,
- 0x0044b021,
- 0x800b4cf0,
- 0x00f80804,
-/* 0x022c: cmd_cond_mode_double */
- 0xb61060b6,
- 0x65fa1050,
- 0x9803f805,
- 0x06982005,
- 0x0456b824,
- 0x980b4cf0,
- 0x06982105,
- 0x0456b825,
- 0xfd0b5cf0,
- 0x34b00445,
- 0x0b5cf003,
- 0x800645fd,
- 0x00f80804,
-/* 0x0260: cmd_wrcache_flush */
- 0xf10132f4,
- 0xbd220027,
- 0x0133f034,
- 0xf80023d0,
-/* 0x0271: crypt_cmd_mode */
- 0x0131f400,
- 0xb00225f0,
- 0x18f40f34,
- 0x0132f409,
-/* 0x0283: crypt_cmd_mode_return */
- 0xf80d0380,
-/* 0x0285: crypt_cmd_length */
- 0x0034b000,
- 0xf4fb0bf4,
- 0x47f0033c,
- 0x0743f040,
- 0xf00604fa,
- 0x43f05047,
- 0x0604fa06,
- 0x3cf503f8,
- 0x47f1c407,
- 0x4bfe2100,
- 0x09049800,
- 0x950a0598,
- 0x44b60858,
- 0x0548fd18,
- 0x98ff55c4,
- 0x07980b06,
- 0x0878950c,
- 0xfd1864b6,
- 0x77c40568,
- 0x0d0898ff,
- 0x580284b6,
- 0x95f9a889,
- 0xf9a98958,
- 0x013cf495,
- 0x3cf403f8,
- 0xf803f861,
- 0x18489503,
- 0xbb084994,
- 0x81b60095,
- 0x09088000,
- 0x950a0980,
- 0x69941868,
- 0x0097bb08,
- 0x800081b6,
- 0x09800b08,
- 0x023cf40c,
- 0xf05047f0,
- 0x04fa0643,
- 0xf803f805,
-/* 0x0321: crypt_copy_prep */
- 0x203cf500,
- 0x003cf594,
- 0x003cf588,
-/* 0x032f: crypt_store_prep */
- 0xf500f88c,
- 0xf594103c,
- 0xf88c063c,
-/* 0x0339: crypt_ecb_e_prep */
- 0x303cf500,
- 0x003cf594,
- 0x003cf588,
- 0x003cf5d0,
-/* 0x034b: crypt_ecb_d_prep */
- 0xf500f88c,
- 0xf5c8773c,
- 0xf594303c,
- 0xf588003c,
- 0xf5d4003c,
- 0xf88c003c,
-/* 0x0361: crypt_cbc_e_prep */
- 0x403cf500,
- 0x003cf594,
- 0x063cf588,
- 0x663cf5ac,
- 0x063cf5d0,
-/* 0x0377: crypt_cbc_d_prep */
- 0xf500f88c,
- 0xf5c8773c,
- 0xf594503c,
- 0xf584623c,
- 0xf588063c,
- 0xf5d4603c,
- 0xf5ac203c,
- 0xf88c003c,
-/* 0x0395: crypt_pcbc_e_prep */
- 0x503cf500,
- 0x003cf594,
- 0x063cf588,
- 0x663cf5ac,
- 0x063cf5d0,
- 0x063cf58c,
-/* 0x03af: crypt_pcbc_d_prep */
- 0xf500f8ac,
- 0xf5c8773c,
- 0xf594503c,
- 0xf588003c,
- 0xf5d4013c,
- 0xf5ac163c,
- 0xf58c063c,
- 0xf8ac063c,
-/* 0x03cd: crypt_cfb_e_prep */
- 0x403cf500,
- 0x663cf594,
- 0x003cf5d0,
- 0x063cf588,
- 0x063cf5ac,
-/* 0x03e3: crypt_cfb_d_prep */
- 0xf500f88c,
- 0xf594403c,
- 0xf5d0603c,
- 0xf588063c,
- 0xf5ac603c,
- 0xf88c003c,
-/* 0x03f9: crypt_ofb_prep */
- 0x403cf500,
- 0x663cf594,
- 0x003cf5d0,
- 0x603cf588,
- 0x003cf5ac,
-/* 0x040f: crypt_ctr_prep */
- 0xf500f88c,
- 0xf594503c,
- 0xf5d0613c,
- 0xf5b0163c,
- 0xf588003c,
- 0xf5ac103c,
- 0xf88c003c,
-/* 0x0429: crypt_cbc_mac_prep */
- 0x303cf500,
- 0x003cf594,
- 0x063cf588,
- 0x663cf5ac,
-/* 0x043b: crypt_cmac_finish_complete_prep */
- 0xf500f8d0,
- 0xf594703c,
- 0xf588003c,
- 0xf5ac063c,
- 0xf5ac003c,
- 0xf5d0003c,
- 0xf5bc003c,
- 0xf5ac063c,
- 0xf8d0663c,
-/* 0x045d: crypt_cmac_finish_partial_prep */
- 0x803cf500,
- 0x003cf594,
- 0x063cf588,
- 0x003cf5ac,
- 0x003cf5ac,
- 0x003cf5d0,
- 0x003cf5bc,
- 0x063cf5bc,
- 0x663cf5ac,
-/* 0x0483: crypt_do_in */
- 0xbb00f8d0,
- 0x47fe0035,
- 0x8097f100,
- 0x0293f000,
-/* 0x0490: crypt_do_in_loop */
- 0xf80559fa,
- 0x223cf403,
- 0xf50609fa,
- 0xf898103c,
- 0x1050b603,
- 0xf40453b8,
- 0x3cf4e91b,
- 0xf803f801,
-/* 0x04b1: crypt_do_out */
- 0x0037bb00,
- 0xf10067fe,
- 0xf0008097,
-/* 0x04be: crypt_do_out_loop */
- 0x3cf50293,
- 0x3cf49810,
- 0x0579fa61,
- 0xf40679fa,
- 0x03f8013c,
- 0xb81070b6,
- 0x1bf40473,
-/* 0x04db: crypt_do_inout */
- 0xbb00f8e8,
- 0x97f10035,
- 0x93f00080,
-/* 0x04e5: crypt_do_inout_loop */
- 0x0047fe02,
- 0xf80559fa,
- 0x213cf403,
- 0xf50609fa,
- 0xf498103c,
- 0x67fe613c,
- 0x0579fa00,
- 0xf40679fa,
- 0x03f8013c,
- 0xb61050b6,
- 0x53b81070,
- 0xd41bf404,
- 0x000000f8,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
deleted file mode 100644
index ea5c42f31791..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv84.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-#include <core/gpuobj.h>
-
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-#include <engine/crypt.h>
-
-struct nv84_crypt_priv {
- struct nouveau_engine base;
-};
-
-/*******************************************************************************
- * Crypt object classes
- ******************************************************************************/
-
-static int
-nv84_crypt_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj *obj;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
- 16, 16, 0, &obj);
- *pobject = nv_object(obj);
- if (ret)
- return ret;
-
- nv_wo32(obj, 0x00, nv_mclass(obj));
- nv_wo32(obj, 0x04, 0x00000000);
- nv_wo32(obj, 0x08, 0x00000000);
- nv_wo32(obj, 0x0c, 0x00000000);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv84_crypt_ofuncs = {
- .ctor = nv84_crypt_object_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv84_crypt_sclass[] = {
- { 0x74c1, &nv84_crypt_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PCRYPT context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_crypt_cclass = {
- .handle = NV_ENGCTX(CRYPT, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
- },
-};
-
-/*******************************************************************************
- * PCRYPT engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_bitfield nv84_crypt_intr_mask[] = {
- { 0x00000001, "INVALID_STATE" },
- { 0x00000002, "ILLEGAL_MTHD" },
- { 0x00000004, "ILLEGAL_CLASS" },
- { 0x00000080, "QUERY" },
- { 0x00000100, "FAULT" },
- {}
-};
-
-static void
-nv84_crypt_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nv84_crypt_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, 0x102130);
- u32 mthd = nv_rd32(priv, 0x102190);
- u32 data = nv_rd32(priv, 0x102194);
- u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat) {
- nv_error(priv, "%s", "");
- nouveau_bitfield_print(nv84_crypt_intr_mask, stat);
- pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
- chid, (u64)inst << 12, nouveau_client_name(engctx),
- mthd, data);
- }
-
- nv_wr32(priv, 0x102130, stat);
- nv_wr32(priv, 0x10200c, 0x10);
-
- nouveau_engctx_put(engctx);
-}
-
-static int
-nv84_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv84_crypt_priv *priv;
- int ret;
-
- ret = nouveau_engine_create(parent, engine, oclass, true,
- "PCRYPT", "crypt", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00004000;
- nv_subdev(priv)->intr = nv84_crypt_intr;
- nv_engine(priv)->cclass = &nv84_crypt_cclass;
- nv_engine(priv)->sclass = nv84_crypt_sclass;
- return 0;
-}
-
-static int
-nv84_crypt_init(struct nouveau_object *object)
-{
- struct nv84_crypt_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_engine_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x102130, 0xffffffff);
- nv_wr32(priv, 0x102140, 0xffffffbf);
- nv_wr32(priv, 0x10200c, 0x00000010);
- return 0;
-}
-
-struct nouveau_oclass
-nv84_crypt_oclass = {
- .handle = NV_ENGINE(CRYPT, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_crypt_ctor,
- .dtor = _nouveau_engine_dtor,
- .init = nv84_crypt_init,
- .fini = _nouveau_engine_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c b/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
deleted file mode 100644
index 5571c09534cb..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/crypt/nv98.c
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/falcon.h>
-#include <engine/fifo.h>
-#include <engine/crypt.h>
-
-#include "fuc/nv98.fuc.h"
-
-struct nv98_crypt_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * Crypt object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_crypt_sclass[] = {
- { 0x88b4, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PCRYPT context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_crypt_cclass = {
- .handle = NV_ENGCTX(CRYPT, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PCRYPT engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_enum nv98_crypt_isr_error_name[] = {
- { 0x0000, "ILLEGAL_MTHD" },
- { 0x0001, "INVALID_BITFIELD" },
- { 0x0002, "INVALID_ENUM" },
- { 0x0003, "QUERY" },
- {}
-};
-
-static void
-nv98_crypt_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nv98_crypt_priv *priv = (void *)subdev;
- u32 disp = nv_rd32(priv, 0x08701c);
- u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
- u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
- u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
- u32 addr = nv_rd32(priv, 0x087040) >> 16;
- u32 mthd = (addr & 0x07ff) << 2;
- u32 subc = (addr & 0x3800) >> 11;
- u32 data = nv_rd32(priv, 0x087044);
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & 0x00000040) {
- nv_error(priv, "DISPATCH_ERROR [");
- nouveau_enum_print(nv98_crypt_isr_error_name, ssta);
- pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
- chid, (u64)inst << 12, nouveau_client_name(engctx),
- subc, mthd, data);
- nv_wr32(priv, 0x087004, 0x00000040);
- stat &= ~0x00000040;
- }
-
- if (stat) {
- nv_error(priv, "unhandled intr 0x%08x\n", stat);
- nv_wr32(priv, 0x087004, stat);
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static int
-nv98_crypt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv98_crypt_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x087000, true,
- "PCRYPT", "crypt", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00004000;
- nv_subdev(priv)->intr = nv98_crypt_intr;
- nv_engine(priv)->cclass = &nv98_crypt_cclass;
- nv_engine(priv)->sclass = nv98_crypt_sclass;
- nv_falcon(priv)->code.data = nv98_pcrypt_code;
- nv_falcon(priv)->code.size = sizeof(nv98_pcrypt_code);
- nv_falcon(priv)->data.data = nv98_pcrypt_data;
- nv_falcon(priv)->data.size = sizeof(nv98_pcrypt_data);
- return 0;
-}
-
-struct nouveau_oclass
-nv98_crypt_oclass = {
- .handle = NV_ENGINE(CRYPT, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv98_crypt_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = _nouveau_falcon_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/acpi.c b/drivers/gpu/drm/nouveau/core/engine/device/acpi.c
deleted file mode 100644
index 4dbf0ba89e5c..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/acpi.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "acpi.h"
-
-#ifdef CONFIG_ACPI
-static int
-nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
-{
- struct nouveau_device *device =
- container_of(nb, typeof(*device), acpi.nb);
- struct acpi_bus_event *info = data;
-
- if (!strcmp(info->device_class, "ac_adapter"))
- nvkm_event_send(&device->event, 1, 0, NULL, 0);
-
- return NOTIFY_DONE;
-}
-#endif
-
-int
-nvkm_acpi_fini(struct nouveau_device *device, bool suspend)
-{
-#ifdef CONFIG_ACPI
- unregister_acpi_notifier(&device->acpi.nb);
-#endif
- return 0;
-}
-
-int
-nvkm_acpi_init(struct nouveau_device *device)
-{
-#ifdef CONFIG_ACPI
- device->acpi.nb.notifier_call = nvkm_acpi_ntfy;
- register_acpi_notifier(&device->acpi.nb);
-#endif
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/acpi.h b/drivers/gpu/drm/nouveau/core/engine/device/acpi.h
deleted file mode 100644
index cc49f4f568cd..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/acpi.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NVKM_DEVICE_ACPI_H__
-#define __NVKM_DEVICE_ACPI_H__
-
-#include <engine/device.h>
-
-int nvkm_acpi_init(struct nouveau_device *);
-int nvkm_acpi_fini(struct nouveau_device *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/base.c b/drivers/gpu/drm/nouveau/core/engine/device/base.c
deleted file mode 100644
index 137e0b0faeae..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/base.c
+++ /dev/null
@@ -1,715 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/device.h>
-#include <core/client.h>
-#include <core/option.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-
-#include "priv.h"
-#include "acpi.h"
-
-static DEFINE_MUTEX(nv_devices_mutex);
-static LIST_HEAD(nv_devices);
-
-struct nouveau_device *
-nouveau_device_find(u64 name)
-{
- struct nouveau_device *device, *match = NULL;
- mutex_lock(&nv_devices_mutex);
- list_for_each_entry(device, &nv_devices, head) {
- if (device->handle == name) {
- match = device;
- break;
- }
- }
- mutex_unlock(&nv_devices_mutex);
- return match;
-}
-
-int
-nouveau_device_list(u64 *name, int size)
-{
- struct nouveau_device *device;
- int nr = 0;
- mutex_lock(&nv_devices_mutex);
- list_for_each_entry(device, &nv_devices, head) {
- if (nr++ < size)
- name[nr - 1] = device->handle;
- }
- mutex_unlock(&nv_devices_mutex);
- return nr;
-}
-
-/******************************************************************************
- * nouveau_devobj (0x0080): class implementation
- *****************************************************************************/
-
-struct nouveau_devobj {
- struct nouveau_parent base;
- struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
-};
-
-static int
-nouveau_devobj_info(struct nouveau_object *object, void *data, u32 size)
-{
- struct nouveau_device *device = nv_device(object);
- struct nouveau_fb *pfb = nouveau_fb(device);
- struct nouveau_instmem *imem = nouveau_instmem(device);
- union {
- struct nv_device_info_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "device info size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "device info vers %d\n", args->v0.version);
- } else
- return ret;
-
- switch (device->chipset) {
- case 0x01a:
- case 0x01f:
- case 0x04c:
- case 0x04e:
- case 0x063:
- case 0x067:
- case 0x068:
- case 0x0aa:
- case 0x0ac:
- case 0x0af:
- args->v0.platform = NV_DEVICE_INFO_V0_IGP;
- break;
- default:
- if (device->pdev) {
- if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
- args->v0.platform = NV_DEVICE_INFO_V0_AGP;
- else
- if (pci_is_pcie(device->pdev))
- args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
- else
- args->v0.platform = NV_DEVICE_INFO_V0_PCI;
- } else {
- args->v0.platform = NV_DEVICE_INFO_V0_SOC;
- }
- break;
- }
-
- switch (device->card_type) {
- case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
- case NV_10:
- case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
- case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
- case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
- case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
- case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
- case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
- case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
- case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
- default:
- args->v0.family = 0;
- break;
- }
-
- args->v0.chipset = device->chipset;
- args->v0.revision = device->chiprev;
- if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
- else args->v0.ram_size = args->v0.ram_user = 0;
- if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
- return 0;
-}
-
-static int
-nouveau_devobj_mthd(struct nouveau_object *object, u32 mthd,
- void *data, u32 size)
-{
- switch (mthd) {
- case NV_DEVICE_V0_INFO:
- return nouveau_devobj_info(object, data, size);
- default:
- break;
- }
- return -EINVAL;
-}
-
-static u8
-nouveau_devobj_rd08(struct nouveau_object *object, u64 addr)
-{
- return nv_rd08(object->engine, addr);
-}
-
-static u16
-nouveau_devobj_rd16(struct nouveau_object *object, u64 addr)
-{
- return nv_rd16(object->engine, addr);
-}
-
-static u32
-nouveau_devobj_rd32(struct nouveau_object *object, u64 addr)
-{
- return nv_rd32(object->engine, addr);
-}
-
-static void
-nouveau_devobj_wr08(struct nouveau_object *object, u64 addr, u8 data)
-{
- nv_wr08(object->engine, addr, data);
-}
-
-static void
-nouveau_devobj_wr16(struct nouveau_object *object, u64 addr, u16 data)
-{
- nv_wr16(object->engine, addr, data);
-}
-
-static void
-nouveau_devobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- nv_wr32(object->engine, addr, data);
-}
-
-static int
-nouveau_devobj_map(struct nouveau_object *object, u64 *addr, u32 *size)
-{
- struct nouveau_device *device = nv_device(object);
- *addr = nv_device_resource_start(device, 0);
- *size = nv_device_resource_len(device, 0);
- return 0;
-}
-
-static const u64 disable_map[] = {
- [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS,
- [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_CLOCK] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_VM] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_PWR] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_SUBDEV_FUSE] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_ENGINE_PERFMON] = NV_DEVICE_V0_DISABLE_CORE,
- [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO,
- [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO,
- [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GRAPH,
- [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG,
- [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME,
- [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP,
- [NVDEV_ENGINE_CRYPT] = NV_DEVICE_V0_DISABLE_CRYPT,
- [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP,
- [NVDEV_ENGINE_PPP] = NV_DEVICE_V0_DISABLE_PPP,
- [NVDEV_ENGINE_COPY0] = NV_DEVICE_V0_DISABLE_COPY0,
- [NVDEV_ENGINE_COPY1] = NV_DEVICE_V0_DISABLE_COPY1,
- [NVDEV_ENGINE_COPY2] = NV_DEVICE_V0_DISABLE_COPY1,
- [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC,
- [NVDEV_ENGINE_VENC] = NV_DEVICE_V0_DISABLE_VENC,
- [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP,
- [NVDEV_SUBDEV_NR] = 0,
-};
-
-static void
-nouveau_devobj_dtor(struct nouveau_object *object)
-{
- struct nouveau_devobj *devobj = (void *)object;
- int i;
-
- for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
- nouveau_object_ref(NULL, &devobj->subdev[i]);
-
- nouveau_parent_destroy(&devobj->base);
-}
-
-static struct nouveau_oclass
-nouveau_devobj_oclass_super = {
- .handle = NV_DEVICE,
- .ofuncs = &(struct nouveau_ofuncs) {
- .dtor = nouveau_devobj_dtor,
- .init = _nouveau_parent_init,
- .fini = _nouveau_parent_fini,
- .mthd = nouveau_devobj_mthd,
- .map = nouveau_devobj_map,
- .rd08 = nouveau_devobj_rd08,
- .rd16 = nouveau_devobj_rd16,
- .rd32 = nouveau_devobj_rd32,
- .wr08 = nouveau_devobj_wr08,
- .wr16 = nouveau_devobj_wr16,
- .wr32 = nouveau_devobj_wr32,
- }
-};
-
-static int
-nouveau_devobj_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv_device_v0 v0;
- } *args = data;
- struct nouveau_client *client = nv_client(parent);
- struct nouveau_device *device;
- struct nouveau_devobj *devobj;
- u32 boot0, strap;
- u64 disable, mmio_base, mmio_size;
- void __iomem *map;
- int ret, i, c;
-
- nv_ioctl(parent, "create device size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create device v%d device %016llx "
- "disable %016llx debug0 %016llx\n",
- args->v0.version, args->v0.device,
- args->v0.disable, args->v0.debug0);
- } else
- return ret;
-
- /* give priviledged clients register access */
- if (client->super)
- oclass = &nouveau_devobj_oclass_super;
-
- /* find the device subdev that matches what the client requested */
- device = nv_device(client->device);
- if (args->v0.device != ~0) {
- device = nouveau_device_find(args->v0.device);
- if (!device)
- return -ENODEV;
- }
-
- ret = nouveau_parent_create(parent, nv_object(device), oclass, 0,
- nouveau_control_oclass,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_FIFO) |
- (1ULL << NVDEV_ENGINE_DISP) |
- (1ULL << NVDEV_ENGINE_PERFMON), &devobj);
- *pobject = nv_object(devobj);
- if (ret)
- return ret;
-
- mmio_base = nv_device_resource_start(device, 0);
- mmio_size = nv_device_resource_len(device, 0);
-
- /* translate api disable mask into internal mapping */
- disable = args->v0.debug0;
- for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
- if (args->v0.disable & disable_map[i])
- disable |= (1ULL << i);
- }
-
- /* identify the chipset, and determine classes of subdev/engines */
- if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) &&
- !device->card_type) {
- map = ioremap(mmio_base, 0x102000);
- if (map == NULL)
- return -ENOMEM;
-
- /* switch mmio to cpu's native endianness */
-#ifndef __BIG_ENDIAN
- if (ioread32_native(map + 0x000004) != 0x00000000)
-#else
- if (ioread32_native(map + 0x000004) == 0x00000000)
-#endif
- iowrite32_native(0x01000001, map + 0x000004);
-
- /* read boot0 and strapping information */
- boot0 = ioread32_native(map + 0x000000);
- strap = ioread32_native(map + 0x101000);
- iounmap(map);
-
- /* determine chipset and derive architecture from it */
- if ((boot0 & 0x1f000000) > 0) {
- device->chipset = (boot0 & 0x1ff00000) >> 20;
- device->chiprev = (boot0 & 0x000000ff);
- switch (device->chipset & 0x1f0) {
- case 0x010: {
- if (0x461 & (1 << (device->chipset & 0xf)))
- device->card_type = NV_10;
- else
- device->card_type = NV_11;
- device->chiprev = 0x00;
- break;
- }
- case 0x020: device->card_type = NV_20; break;
- case 0x030: device->card_type = NV_30; break;
- case 0x040:
- case 0x060: device->card_type = NV_40; break;
- case 0x050:
- case 0x080:
- case 0x090:
- case 0x0a0: device->card_type = NV_50; break;
- case 0x0c0:
- case 0x0d0: device->card_type = NV_C0; break;
- case 0x0e0:
- case 0x0f0:
- case 0x100: device->card_type = NV_E0; break;
- case 0x110:
- case 0x120: device->card_type = GM100; break;
- default:
- break;
- }
- } else
- if ((boot0 & 0xff00fff0) == 0x20004000) {
- if (boot0 & 0x00f00000)
- device->chipset = 0x05;
- else
- device->chipset = 0x04;
- device->card_type = NV_04;
- }
-
- switch (device->card_type) {
- case NV_04: ret = nv04_identify(device); break;
- case NV_10:
- case NV_11: ret = nv10_identify(device); break;
- case NV_20: ret = nv20_identify(device); break;
- case NV_30: ret = nv30_identify(device); break;
- case NV_40: ret = nv40_identify(device); break;
- case NV_50: ret = nv50_identify(device); break;
- case NV_C0: ret = nvc0_identify(device); break;
- case NV_E0: ret = nve0_identify(device); break;
- case GM100: ret = gm100_identify(device); break;
- default:
- ret = -EINVAL;
- break;
- }
-
- if (ret) {
- nv_error(device, "unknown chipset, 0x%08x\n", boot0);
- return ret;
- }
-
- nv_info(device, "BOOT0 : 0x%08x\n", boot0);
- nv_info(device, "Chipset: %s (NV%02X)\n",
- device->cname, device->chipset);
- nv_info(device, "Family : NV%02X\n", device->card_type);
-
- /* determine frequency of timing crystal */
- if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
- (device->chipset >= 0x20 && device->chipset < 0x25))
- strap &= 0x00000040;
- else
- strap &= 0x00400040;
-
- switch (strap) {
- case 0x00000000: device->crystal = 13500; break;
- case 0x00000040: device->crystal = 14318; break;
- case 0x00400000: device->crystal = 27000; break;
- case 0x00400040: device->crystal = 25000; break;
- }
-
- nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
- } else
- if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) {
- device->cname = "NULL";
- device->oclass[NVDEV_SUBDEV_VBIOS] = &nouveau_bios_oclass;
- }
-
- if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
- !nv_subdev(device)->mmio) {
- nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size);
- if (!nv_subdev(device)->mmio) {
- nv_error(device, "unable to map device registers\n");
- return -ENOMEM;
- }
- }
-
- /* ensure requested subsystems are available for use */
- for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
- if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
- continue;
-
- if (device->subdev[i]) {
- nouveau_object_ref(device->subdev[i],
- &devobj->subdev[i]);
- continue;
- }
-
- ret = nouveau_object_ctor(nv_object(device), NULL,
- oclass, NULL, i,
- &devobj->subdev[i]);
- if (ret == -ENODEV)
- continue;
- if (ret)
- return ret;
-
- device->subdev[i] = devobj->subdev[i];
-
- /* note: can't init *any* subdevs until devinit has been run
- * due to not knowing exactly what the vbios init tables will
- * mess with. devinit also can't be run until all of its
- * dependencies have been created.
- *
- * this code delays init of any subdev until all of devinit's
- * dependencies have been created, and then initialises each
- * subdev in turn as they're created.
- */
- while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
- struct nouveau_object *subdev = devobj->subdev[c++];
- if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
- ret = nouveau_object_inc(subdev);
- if (ret)
- return ret;
- atomic_dec(&nv_object(device)->usecount);
- } else
- if (subdev) {
- nouveau_subdev_reset(subdev);
- }
- }
- }
-
- return 0;
-}
-
-static struct nouveau_ofuncs
-nouveau_devobj_ofuncs = {
- .ctor = nouveau_devobj_ctor,
- .dtor = nouveau_devobj_dtor,
- .init = _nouveau_parent_init,
- .fini = _nouveau_parent_fini,
- .mthd = nouveau_devobj_mthd,
-};
-
-/******************************************************************************
- * nouveau_device: engine functions
- *****************************************************************************/
-
-static struct nouveau_oclass
-nouveau_device_sclass[] = {
- { 0x0080, &nouveau_devobj_ofuncs },
- {}
-};
-
-static int
-nouveau_device_event_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- if (!WARN_ON(size != 0)) {
- notify->size = 0;
- notify->types = 1;
- notify->index = 0;
- return 0;
- }
- return -EINVAL;
-}
-
-static const struct nvkm_event_func
-nouveau_device_event_func = {
- .ctor = nouveau_device_event_ctor,
-};
-
-static int
-nouveau_device_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_device *device = (void *)object;
- struct nouveau_object *subdev;
- int ret, i;
-
- for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
- if ((subdev = device->subdev[i])) {
- if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
- ret = nouveau_object_dec(subdev, suspend);
- if (ret && suspend)
- goto fail;
- }
- }
- }
-
- ret = nvkm_acpi_fini(device, suspend);
-fail:
- for (; ret && i < NVDEV_SUBDEV_NR; i++) {
- if ((subdev = device->subdev[i])) {
- if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
- ret = nouveau_object_inc(subdev);
- if (ret) {
- /* XXX */
- }
- }
- }
- }
-
- return ret;
-}
-
-static int
-nouveau_device_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = (void *)object;
- struct nouveau_object *subdev;
- int ret, i = 0;
-
- ret = nvkm_acpi_init(device);
- if (ret)
- goto fail;
-
- for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
- if ((subdev = device->subdev[i])) {
- if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
- ret = nouveau_object_inc(subdev);
- if (ret)
- goto fail;
- } else {
- nouveau_subdev_reset(subdev);
- }
- }
- }
-
- ret = 0;
-fail:
- for (--i; ret && i >= 0; i--) {
- if ((subdev = device->subdev[i])) {
- if (!nv_iclass(subdev, NV_ENGINE_CLASS))
- nouveau_object_dec(subdev, false);
- }
- }
-
- if (ret)
- nvkm_acpi_fini(device, false);
- return ret;
-}
-
-static void
-nouveau_device_dtor(struct nouveau_object *object)
-{
- struct nouveau_device *device = (void *)object;
-
- nvkm_event_fini(&device->event);
-
- mutex_lock(&nv_devices_mutex);
- list_del(&device->head);
- mutex_unlock(&nv_devices_mutex);
-
- if (nv_subdev(device)->mmio)
- iounmap(nv_subdev(device)->mmio);
-
- nouveau_engine_destroy(&device->base);
-}
-
-resource_size_t
-nv_device_resource_start(struct nouveau_device *device, unsigned int bar)
-{
- if (nv_device_is_pci(device)) {
- return pci_resource_start(device->pdev, bar);
- } else {
- struct resource *res;
- res = platform_get_resource(device->platformdev,
- IORESOURCE_MEM, bar);
- if (!res)
- return 0;
- return res->start;
- }
-}
-
-resource_size_t
-nv_device_resource_len(struct nouveau_device *device, unsigned int bar)
-{
- if (nv_device_is_pci(device)) {
- return pci_resource_len(device->pdev, bar);
- } else {
- struct resource *res;
- res = platform_get_resource(device->platformdev,
- IORESOURCE_MEM, bar);
- if (!res)
- return 0;
- return resource_size(res);
- }
-}
-
-int
-nv_device_get_irq(struct nouveau_device *device, bool stall)
-{
- if (nv_device_is_pci(device)) {
- return device->pdev->irq;
- } else {
- return platform_get_irq_byname(device->platformdev,
- stall ? "stall" : "nonstall");
- }
-}
-
-static struct nouveau_oclass
-nouveau_device_oclass = {
- .handle = NV_ENGINE(DEVICE, 0x00),
- .ofuncs = &(struct nouveau_ofuncs) {
- .dtor = nouveau_device_dtor,
- .init = nouveau_device_init,
- .fini = nouveau_device_fini,
- },
-};
-
-int
-nouveau_device_create_(void *dev, enum nv_bus_type type, u64 name,
- const char *sname, const char *cfg, const char *dbg,
- int length, void **pobject)
-{
- struct nouveau_device *device;
- int ret = -EEXIST;
-
- mutex_lock(&nv_devices_mutex);
- list_for_each_entry(device, &nv_devices, head) {
- if (device->handle == name)
- goto done;
- }
-
- ret = nouveau_engine_create_(NULL, NULL, &nouveau_device_oclass, true,
- "DEVICE", "device", length, pobject);
- device = *pobject;
- if (ret)
- goto done;
-
- switch (type) {
- case NOUVEAU_BUS_PCI:
- device->pdev = dev;
- break;
- case NOUVEAU_BUS_PLATFORM:
- device->platformdev = dev;
- break;
- }
- device->handle = name;
- device->cfgopt = cfg;
- device->dbgopt = dbg;
- device->name = sname;
-
- nv_subdev(device)->debug = nouveau_dbgopt(device->dbgopt, "DEVICE");
- nv_engine(device)->sclass = nouveau_device_sclass;
- list_add(&device->head, &nv_devices);
-
- ret = nvkm_event_init(&nouveau_device_event_func, 1, 1,
- &device->event);
-done:
- mutex_unlock(&nv_devices_mutex);
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
deleted file mode 100644
index e34101a3490e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/ctrl.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <core/client.h>
-#include <core/object.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/ioctl.h>
-
-#include <subdev/clock.h>
-
-#include "priv.h"
-
-static int
-nouveau_control_mthd_pstate_info(struct nouveau_object *object,
- void *data, u32 size)
-{
- union {
- struct nvif_control_pstate_info_v0 v0;
- } *args = data;
- struct nouveau_clock *clk = nouveau_clock(object);
- int ret;
-
- nv_ioctl(object, "control pstate info size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "control pstate info vers %d\n",
- args->v0.version);
- } else
- return ret;
-
- if (clk) {
- args->v0.count = clk->state_nr;
- args->v0.ustate_ac = clk->ustate_ac;
- args->v0.ustate_dc = clk->ustate_dc;
- args->v0.pwrsrc = clk->pwrsrc;
- args->v0.pstate = clk->pstate;
- } else {
- args->v0.count = 0;
- args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
- args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
- args->v0.pwrsrc = -ENOSYS;
- args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
- }
-
- return 0;
-}
-
-static int
-nouveau_control_mthd_pstate_attr(struct nouveau_object *object,
- void *data, u32 size)
-{
- union {
- struct nvif_control_pstate_attr_v0 v0;
- } *args = data;
- struct nouveau_clock *clk = nouveau_clock(object);
- struct nouveau_clocks *domain;
- struct nouveau_pstate *pstate;
- struct nouveau_cstate *cstate;
- int i = 0, j = -1;
- u32 lo, hi;
- int ret;
-
- nv_ioctl(object, "control pstate attr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "control pstate attr vers %d state %d "
- "index %d\n",
- args->v0.version, args->v0.state, args->v0.index);
- if (!clk)
- return -ENODEV;
- if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT)
- return -EINVAL;
- if (args->v0.state >= clk->state_nr)
- return -EINVAL;
- } else
- return ret;
- domain = clk->domains;
-
- while (domain->name != nv_clk_src_max) {
- if (domain->mname && ++j == args->v0.index)
- break;
- domain++;
- }
-
- if (domain->name == nv_clk_src_max)
- return -EINVAL;
-
- if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) {
- list_for_each_entry(pstate, &clk->states, head) {
- if (i++ == args->v0.state)
- break;
- }
-
- lo = pstate->base.domain[domain->name];
- hi = lo;
- list_for_each_entry(cstate, &pstate->list, head) {
- lo = min(lo, cstate->domain[domain->name]);
- hi = max(hi, cstate->domain[domain->name]);
- }
-
- args->v0.state = pstate->pstate;
- } else {
- lo = max(clk->read(clk, domain->name), 0);
- hi = lo;
- }
-
- snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname);
- snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz");
- args->v0.min = lo / domain->mdiv;
- args->v0.max = hi / domain->mdiv;
-
- args->v0.index = 0;
- while ((++domain)->name != nv_clk_src_max) {
- if (domain->mname) {
- args->v0.index = ++j;
- break;
- }
- }
-
- return 0;
-}
-
-static int
-nouveau_control_mthd_pstate_user(struct nouveau_object *object,
- void *data, u32 size)
-{
- union {
- struct nvif_control_pstate_user_v0 v0;
- } *args = data;
- struct nouveau_clock *clk = nouveau_clock(object);
- int ret;
-
- nv_ioctl(object, "control pstate user size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "control pstate user vers %d ustate %d "
- "pwrsrc %d\n", args->v0.version,
- args->v0.ustate, args->v0.pwrsrc);
- if (!clk)
- return -ENODEV;
- } else
- return ret;
-
- if (args->v0.pwrsrc >= 0) {
- ret |= nouveau_clock_ustate(clk, args->v0.ustate, args->v0.pwrsrc);
- } else {
- ret |= nouveau_clock_ustate(clk, args->v0.ustate, 0);
- ret |= nouveau_clock_ustate(clk, args->v0.ustate, 1);
- }
-
- return ret;
-}
-
-static int
-nouveau_control_mthd(struct nouveau_object *object, u32 mthd,
- void *data, u32 size)
-{
- switch (mthd) {
- case NVIF_CONTROL_PSTATE_INFO:
- return nouveau_control_mthd_pstate_info(object, data, size);
- case NVIF_CONTROL_PSTATE_ATTR:
- return nouveau_control_mthd_pstate_attr(object, data, size);
- case NVIF_CONTROL_PSTATE_USER:
- return nouveau_control_mthd_pstate_user(object, data, size);
- default:
- break;
- }
- return -EINVAL;
-}
-
-static struct nouveau_ofuncs
-nouveau_control_ofuncs = {
- .ctor = _nouveau_object_ctor,
- .dtor = nouveau_object_destroy,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- .mthd = nouveau_control_mthd,
-};
-
-struct nouveau_oclass
-nouveau_control_oclass[] = {
- { .handle = NVIF_IOCTL_NEW_V0_CONTROL,
- .ofuncs = &nouveau_control_ofuncs
- },
- {}
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c b/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
deleted file mode 100644
index 4e74a3376de8..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/gm100.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/ltc.h>
-#include <subdev/ibus.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-#include <engine/copy.h>
-#include <engine/bsp.h>
-#include <engine/vp.h>
-#include <engine/ppp.h>
-#include <engine/perfmon.h>
-
-int
-gm100_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x117:
- device->cname = "GM107";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
-
-#if 0
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
-#endif
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
-#if 0
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
-#endif
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
-#if 0
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
-#endif
- break;
- case 0x124:
- device->cname = "GM204";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass;
-#if 0
- /* looks to be some non-trivial changes */
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- /* priv ring says no to 0x10eb14 writes */
- device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
-#endif
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
-#if 0
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
-#endif
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
-#if 0
- device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = gm107_graph_oclass;
-#endif
- device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass;
-#if 0
- device->oclass[NVDEV_ENGINE_COPY0 ] = &gm204_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &gm204_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &gm204_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
-#endif
- break;
- default:
- nv_fatal(device, "unknown Maxwell chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c b/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
deleted file mode 100644
index 573b55f5c2f9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv04.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-
-int
-nv04_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x04:
- device->cname = "NV04";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv04_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x05:
- device->cname = "NV05";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv04_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv04_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- default:
- nv_fatal(device, "unknown RIVA chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c b/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
deleted file mode 100644
index 183a85a6204e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv10.c
+++ /dev/null
@@ -1,204 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-
-int
-nv10_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x10:
- device->cname = "NV10";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x15:
- device->cname = "NV15";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x16:
- device->cname = "NV16";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x1a:
- device->cname = "nForce";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x11:
- device->cname = "NV11";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x17:
- device->cname = "NV17";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x1f:
- device->cname = "nForce2";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x18:
- device->cname = "NV18";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv10_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- default:
- nv_fatal(device, "unknown Celsius chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c b/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
deleted file mode 100644
index aa564c68a920..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv20.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-
-int
-nv20_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x20:
- device->cname = "NV20";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv20_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x25:
- device->cname = "NV25";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x28:
- device->cname = "NV28";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv25_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x2a:
- device->cname = "NV2A";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv2a_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- default:
- nv_fatal(device, "unknown Kelvin chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c b/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
deleted file mode 100644
index 11bd31da82ab..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv30.c
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/mpeg.h>
-#include <engine/disp.h>
-
-int
-nv30_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x30:
- device->cname = "NV30";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x35:
- device->cname = "NV35";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x31:
- device->cname = "NV31";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv30_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x36:
- device->cname = "NV36";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv35_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- case 0x34:
- device->cname = "NV34";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv04_clock_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv34_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- break;
- default:
- nv_fatal(device, "unknown Rankine chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c b/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
deleted file mode 100644
index e96c223cb797..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv40.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/vm.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/mpeg.h>
-#include <engine/disp.h>
-#include <engine/perfmon.h>
-
-int
-nv40_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x40:
- device->cname = "NV40";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x41:
- device->cname = "NV41";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x42:
- device->cname = "NV42";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x43:
- device->cname = "NV43";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x45:
- device->cname = "NV45";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv04_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x47:
- device->cname = "G70";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x49:
- device->cname = "G71";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x4b:
- device->cname = "G73";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv41_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x44:
- device->cname = "NV44";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x46:
- device->cname = "G72";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x4a:
- device->cname = "NV44A";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x4c:
- device->cname = "C61";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x4e:
- device->cname = "C51";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x63:
- device->cname = "C73";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x67:
- device->cname = "C67";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- case 0x68:
- device->cname = "C68";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nv40_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv44_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv10_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv40_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv40_perfmon_oclass;
- break;
- default:
- nv_fatal(device, "unknown Curie chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c b/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
deleted file mode 100644
index 96f568d1321b..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nv50.c
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/mpeg.h>
-#include <engine/vp.h>
-#include <engine/crypt.h>
-#include <engine/bsp.h>
-#include <engine/ppp.h>
-#include <engine/copy.h>
-#include <engine/disp.h>
-#include <engine/perfmon.h>
-
-int
-nv50_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0x50:
- device->cname = "G80";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv50_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv50_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv50_perfmon_oclass;
- break;
- case 0x84:
- device->cname = "G84";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0x86:
- device->cname = "G86";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0x92:
- device->cname = "G92";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv84_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0x94:
- device->cname = "G94";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv94_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0x96:
- device->cname = "G96";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv94_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0x98:
- device->cname = "G98";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0xa0:
- device->cname = "G200";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nv84_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv84_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nv84_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv84_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv84_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv84_bsp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva0_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0xaa:
- device->cname = "MCP77/MCP78";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvaa_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0xac:
- device->cname = "MCP79/MCP7A";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = nvaa_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nv84_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nv98_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvaa_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_CRYPT ] = &nv98_crypt_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nv94_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nv84_perfmon_oclass;
- break;
- case 0xa3:
- device->cname = "GT215";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nva3_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_MPEG ] = &nv84_mpeg_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass;
- break;
- case 0xa5:
- device->cname = "GT216";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nva3_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass;
- break;
- case 0xa8:
- device->cname = "GT218";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nva3_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nva3_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass;
- break;
- case 0xaf:
- device->cname = "MCP89";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &g80_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nva3_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvaf_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nv98_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nv94_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvaf_fb_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nv50_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nva3_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv84_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nv50_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = &nv50_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nv98_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nv98_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nv98_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nva3_copy_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = nva3_perfmon_oclass;
- break;
- default:
- nv_fatal(device, "unknown Tesla chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
deleted file mode 100644
index 72a40f95d048..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nvc0.c
+++ /dev/null
@@ -1,357 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/ltc.h>
-#include <subdev/ibus.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/vp.h>
-#include <engine/bsp.h>
-#include <engine/ppp.h>
-#include <engine/copy.h>
-#include <engine/disp.h>
-#include <engine/perfmon.h>
-
-int
-nvc0_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0xc0:
- device->cname = "GF100";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc0_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xc4:
- device->cname = "GF104";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xc3:
- device->cname = "GF106";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xce:
- device->cname = "GF114";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xcf:
- device->cname = "GF116";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc4_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xc1:
- device->cname = "GF108";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc1_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xc8:
- device->cname = "GF110";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nv94_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nv94_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nva3_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc0_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvc0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvc0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvc8_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nvc0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nva3_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xd9:
- device->cname = "GF119";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvd9_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- case 0xd7:
- device->cname = "GF117";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nvd0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nvc0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nvc0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nvc0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nvc0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvd7_graph_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nvc0_vp_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nvc0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nvc0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nvd0_disp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvc0_perfmon_oclass;
- break;
- default:
- nv_fatal(device, "unknown Fermi chipset\n");
- return -EINVAL;
- }
-
- return 0;
- }
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c b/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
deleted file mode 100644
index 732922690653..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/nve0.c
+++ /dev/null
@@ -1,324 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bus.h>
-#include <subdev/gpio.h>
-#include <subdev/i2c.h>
-#include <subdev/fuse.h>
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/mxm.h>
-#include <subdev/devinit.h>
-#include <subdev/mc.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/ltc.h>
-#include <subdev/ibus.h>
-#include <subdev/instmem.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/pwr.h>
-#include <subdev/volt.h>
-
-#include <engine/device.h>
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-#include <engine/software.h>
-#include <engine/graph.h>
-#include <engine/disp.h>
-#include <engine/copy.h>
-#include <engine/bsp.h>
-#include <engine/vp.h>
-#include <engine/ppp.h>
-#include <engine/perfmon.h>
-
-int
-nve0_identify(struct nouveau_device *device)
-{
- switch (device->chipset) {
- case 0xe4:
- device->cname = "GK104";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = gk104_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
- break;
- case 0xe7:
- device->cname = "GK107";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
- break;
- case 0xe6:
- device->cname = "GK106";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = gk104_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nve4_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nve0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
- break;
- case 0xea:
- device->cname = "GK20A";
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &gk20a_clock_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = gk20a_graph_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nve0_perfmon_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass;
- break;
- case 0xf0:
- device->cname = "GK110";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nvf0_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass;
- break;
- case 0xf1:
- device->cname = "GK110B";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nvd0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = nvc3_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nvd0_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nve0_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = gk110b_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- device->oclass[NVDEV_ENGINE_PERFMON] = &nvf0_perfmon_oclass;
- break;
- case 0x106:
- device->cname = "GK208B";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nv108_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- break;
- case 0x108:
- device->cname = "GK208";
- device->oclass[NVDEV_SUBDEV_VBIOS ] = &nouveau_bios_oclass;
- device->oclass[NVDEV_SUBDEV_GPIO ] = nve0_gpio_oclass;
- device->oclass[NVDEV_SUBDEV_I2C ] = nve0_i2c_oclass;
- device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
- device->oclass[NVDEV_SUBDEV_CLOCK ] = &nve0_clock_oclass;
- device->oclass[NVDEV_SUBDEV_THERM ] = &nvd0_therm_oclass;
- device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
- device->oclass[NVDEV_SUBDEV_DEVINIT] = nvc0_devinit_oclass;
- device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
- device->oclass[NVDEV_SUBDEV_BUS ] = nvc0_bus_oclass;
- device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
- device->oclass[NVDEV_SUBDEV_FB ] = nve0_fb_oclass;
- device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
- device->oclass[NVDEV_SUBDEV_IBUS ] = &nve0_ibus_oclass;
- device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
- device->oclass[NVDEV_SUBDEV_VM ] = &nvc0_vmmgr_oclass;
- device->oclass[NVDEV_SUBDEV_BAR ] = &nvc0_bar_oclass;
- device->oclass[NVDEV_SUBDEV_PWR ] = nv108_pwr_oclass;
- device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
- device->oclass[NVDEV_ENGINE_DMAOBJ ] = nvd0_dmaeng_oclass;
- device->oclass[NVDEV_ENGINE_FIFO ] = nv108_fifo_oclass;
- device->oclass[NVDEV_ENGINE_SW ] = nvc0_software_oclass;
- device->oclass[NVDEV_ENGINE_GR ] = nv108_graph_oclass;
- device->oclass[NVDEV_ENGINE_DISP ] = nvf0_disp_oclass;
- device->oclass[NVDEV_ENGINE_COPY0 ] = &nve0_copy0_oclass;
- device->oclass[NVDEV_ENGINE_COPY1 ] = &nve0_copy1_oclass;
- device->oclass[NVDEV_ENGINE_COPY2 ] = &nve0_copy2_oclass;
- device->oclass[NVDEV_ENGINE_BSP ] = &nve0_bsp_oclass;
- device->oclass[NVDEV_ENGINE_VP ] = &nve0_vp_oclass;
- device->oclass[NVDEV_ENGINE_PPP ] = &nvc0_ppp_oclass;
- break;
- default:
- nv_fatal(device, "unknown Kepler chipset\n");
- return -EINVAL;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/device/priv.h b/drivers/gpu/drm/nouveau/core/engine/device/priv.h
deleted file mode 100644
index 035fd5b9cfc3..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/device/priv.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NVKM_DEVICE_PRIV_H__
-#define __NVKM_DEVICE_PRIV_H__
-
-#include <engine/device.h>
-
-extern struct nouveau_oclass nouveau_control_oclass[];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/base.c b/drivers/gpu/drm/nouveau/core/engine/disp/base.c
deleted file mode 100644
index 64b84667f3a5..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/base.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/event.h>
-
-#include "priv.h"
-#include "outp.h"
-#include "conn.h"
-
-int
-nouveau_disp_vblank_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nouveau_disp *disp =
- container_of(notify->event, typeof(*disp), vblank);
- union {
- struct nvif_notify_head_req_v0 v0;
- } *req = data;
- int ret;
-
- if (nvif_unpack(req->v0, 0, 0, false)) {
- notify->size = sizeof(struct nvif_notify_head_rep_v0);
- if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
- notify->types = 1;
- notify->index = req->v0.head;
- return 0;
- }
- }
-
- return ret;
-}
-
-void
-nouveau_disp_vblank(struct nouveau_disp *disp, int head)
-{
- struct nvif_notify_head_rep_v0 rep = {};
- nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
-}
-
-static int
-nouveau_disp_hpd_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nouveau_disp *disp =
- container_of(notify->event, typeof(*disp), hpd);
- union {
- struct nvif_notify_conn_req_v0 v0;
- } *req = data;
- struct nvkm_output *outp;
- int ret;
-
- if (nvif_unpack(req->v0, 0, 0, false)) {
- notify->size = sizeof(struct nvif_notify_conn_rep_v0);
- list_for_each_entry(outp, &disp->outp, head) {
- if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
- if (ret = -ENODEV, outp->conn->hpd.event) {
- notify->types = req->v0.mask;
- notify->index = req->v0.conn;
- ret = 0;
- }
- break;
- }
- }
- }
-
- return ret;
-}
-
-static const struct nvkm_event_func
-nouveau_disp_hpd_func = {
- .ctor = nouveau_disp_hpd_ctor
-};
-
-int
-nouveau_disp_ntfy(struct nouveau_object *object, u32 type,
- struct nvkm_event **event)
-{
- struct nouveau_disp *disp = (void *)object->engine;
- switch (type) {
- case NV04_DISP_NTFY_VBLANK:
- *event = &disp->vblank;
- return 0;
- case NV04_DISP_NTFY_CONN:
- *event = &disp->hpd;
- return 0;
- default:
- break;
- }
- return -EINVAL;
-}
-
-int
-_nouveau_disp_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_disp *disp = (void *)object;
- struct nvkm_output *outp;
- int ret;
-
- list_for_each_entry(outp, &disp->outp, head) {
- ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
- if (ret && suspend)
- goto fail_outp;
- }
-
- return nouveau_engine_fini(&disp->base, suspend);
-
-fail_outp:
- list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
- nv_ofuncs(outp)->init(nv_object(outp));
- }
-
- return ret;
-}
-
-int
-_nouveau_disp_init(struct nouveau_object *object)
-{
- struct nouveau_disp *disp = (void *)object;
- struct nvkm_output *outp;
- int ret;
-
- ret = nouveau_engine_init(&disp->base);
- if (ret)
- return ret;
-
- list_for_each_entry(outp, &disp->outp, head) {
- ret = nv_ofuncs(outp)->init(nv_object(outp));
- if (ret)
- goto fail_outp;
- }
-
- return ret;
-
-fail_outp:
- list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
- nv_ofuncs(outp)->fini(nv_object(outp), false);
- }
-
- return ret;
-}
-
-void
-_nouveau_disp_dtor(struct nouveau_object *object)
-{
- struct nouveau_disp *disp = (void *)object;
- struct nvkm_output *outp, *outt;
-
- nvkm_event_fini(&disp->vblank);
- nvkm_event_fini(&disp->hpd);
-
- if (disp->outp.next) {
- list_for_each_entry_safe(outp, outt, &disp->outp, head) {
- nouveau_object_ref(NULL, (struct nouveau_object **)&outp);
- }
- }
-
- nouveau_engine_destroy(&disp->base);
-}
-
-int
-nouveau_disp_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int heads,
- const char *intname, const char *extname,
- int length, void **pobject)
-{
- struct nouveau_disp_impl *impl = (void *)oclass;
- struct nouveau_bios *bios = nouveau_bios(parent);
- struct nouveau_disp *disp;
- struct nouveau_oclass **sclass;
- struct nouveau_object *object;
- struct dcb_output dcbE;
- u8 hpd = 0, ver, hdr;
- u32 data;
- int ret, i;
-
- ret = nouveau_engine_create_(parent, engine, oclass, true,
- intname, extname, length, pobject);
- disp = *pobject;
- if (ret)
- return ret;
-
- INIT_LIST_HEAD(&disp->outp);
-
- /* create output objects for each display path in the vbios */
- i = -1;
- while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
- if (dcbE.type == DCB_OUTPUT_UNUSED)
- continue;
- if (dcbE.type == DCB_OUTPUT_EOL)
- break;
- data = dcbE.location << 4 | dcbE.type;
-
- oclass = nvkm_output_oclass;
- sclass = impl->outp;
- while (sclass && sclass[0]) {
- if (sclass[0]->handle == data) {
- oclass = sclass[0];
- break;
- }
- sclass++;
- }
-
- nouveau_object_ctor(*pobject, *pobject, oclass,
- &dcbE, i, &object);
- hpd = max(hpd, (u8)(dcbE.connector + 1));
- }
-
- ret = nvkm_event_init(&nouveau_disp_hpd_func, 3, hpd, &disp->hpd);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
- if (ret)
- return ret;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c b/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
deleted file mode 100644
index 1496b567dd4a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/conn.c
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <nvif/event.h>
-
-#include <subdev/gpio.h>
-
-#include "conn.h"
-#include "outp.h"
-
-static int
-nvkm_connector_hpd(struct nvkm_notify *notify)
-{
- struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
- struct nouveau_disp *disp = nouveau_disp(conn);
- struct nouveau_gpio *gpio = nouveau_gpio(conn);
- const struct nvkm_gpio_ntfy_rep *line = notify->data;
- struct nvif_notify_conn_rep_v0 rep;
- int index = conn->index;
-
- DBG("HPD: %d\n", line->mask);
-
- if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
- rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
- else
- rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
- rep.version = 0;
-
- nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
- return NVKM_NOTIFY_KEEP;
-}
-
-int
-_nvkm_connector_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvkm_connector *conn = (void *)object;
- nvkm_notify_put(&conn->hpd);
- return nouveau_object_fini(&conn->base, suspend);
-}
-
-int
-_nvkm_connector_init(struct nouveau_object *object)
-{
- struct nvkm_connector *conn = (void *)object;
- int ret = nouveau_object_init(&conn->base);
- if (ret == 0)
- nvkm_notify_get(&conn->hpd);
- return ret;
-}
-
-void
-_nvkm_connector_dtor(struct nouveau_object *object)
-{
- struct nvkm_connector *conn = (void *)object;
- nvkm_notify_fini(&conn->hpd);
- nouveau_object_destroy(&conn->base);
-}
-
-int
-nvkm_connector_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- struct nvbios_connE *info, int index,
- int length, void **pobject)
-{
- static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
- struct nouveau_gpio *gpio = nouveau_gpio(parent);
- struct nouveau_disp *disp = (void *)engine;
- struct nvkm_connector *conn;
- struct nvkm_output *outp;
- struct dcb_gpio_func func;
- int ret;
-
- list_for_each_entry(outp, &disp->outp, head) {
- if (outp->conn && outp->conn->index == index) {
- atomic_inc(&nv_object(outp->conn)->refcount);
- *pobject = outp->conn;
- return 1;
- }
- }
-
- ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
- conn = *pobject;
- if (ret)
- return ret;
-
- conn->info = *info;
- conn->index = index;
-
- DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
- info->type, info->location, info->hpd, info->dp,
- info->di, info->sr, info->lcdid);
-
- if ((info->hpd = ffs(info->hpd))) {
- if (--info->hpd >= ARRAY_SIZE(hpd)) {
- ERR("hpd %02x unknown\n", info->hpd);
- return 0;
- }
- info->hpd = hpd[info->hpd];
-
- ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
- if (ret) {
- ERR("func %02x lookup failed, %d\n", info->hpd, ret);
- return 0;
- }
-
- ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
- true, &(struct nvkm_gpio_ntfy_req) {
- .mask = NVKM_GPIO_TOGGLED,
- .line = func.line,
- },
- sizeof(struct nvkm_gpio_ntfy_req),
- sizeof(struct nvkm_gpio_ntfy_rep),
- &conn->hpd);
- if (ret) {
- ERR("func %02x failed, %d\n", info->hpd, ret);
- } else {
- DBG("func %02x (HPD)\n", info->hpd);
- }
- }
-
- return 0;
-}
-
-int
-_nvkm_connector_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *info, u32 index,
- struct nouveau_object **pobject)
-{
- struct nvkm_connector *conn;
- int ret;
-
- ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
- *pobject = nv_object(conn);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-nvkm_connector_oclass = &(struct nvkm_connector_impl) {
- .base = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_connector_ctor,
- .dtor = _nvkm_connector_dtor,
- .init = _nvkm_connector_init,
- .fini = _nvkm_connector_fini,
- },
- },
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h b/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
deleted file mode 100644
index 55e5f5c82c14..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/conn.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NVKM_DISP_CONN_H__
-#define __NVKM_DISP_CONN_H__
-
-#include "priv.h"
-
-struct nvkm_connector {
- struct nouveau_object base;
- struct list_head head;
-
- struct nvbios_connE info;
- int index;
-
- struct nvkm_notify hpd;
-};
-
-#define nvkm_connector_create(p,e,c,b,i,d) \
- nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_connector_destroy(d) ({ \
- struct nvkm_connector *disp = (d); \
- _nvkm_connector_dtor(nv_object(disp)); \
-})
-#define nvkm_connector_init(d) ({ \
- struct nvkm_connector *disp = (d); \
- _nvkm_connector_init(nv_object(disp)); \
-})
-#define nvkm_connector_fini(d,s) ({ \
- struct nvkm_connector *disp = (d); \
- _nvkm_connector_fini(nv_object(disp), (s)); \
-})
-
-int nvkm_connector_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, struct nvbios_connE *,
- int, int, void **);
-
-int _nvkm_connector_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void _nvkm_connector_dtor(struct nouveau_object *);
-int _nvkm_connector_init(struct nouveau_object *);
-int _nvkm_connector_fini(struct nouveau_object *, bool);
-
-struct nvkm_connector_impl {
- struct nouveau_oclass base;
-};
-
-#ifndef MSG
-#define MSG(l,f,a...) do { \
- struct nvkm_connector *_conn = (void *)conn; \
- nv_##l(nv_object(conn)->engine, "%02x:%02x%02x: "f, _conn->index, \
- _conn->info.location, _conn->info.type, ##a); \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
deleted file mode 100644
index b36addff06a9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dacnv50.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nv50_dac_power(NV50_DISP_MTHD_V1)
-{
- const u32 doff = outp->or * 0x800;
- union {
- struct nv50_disp_dac_pwr_v0 v0;
- } *args = data;
- u32 stat;
- int ret;
-
- nv_ioctl(object, "disp dac pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
- "vsync %d hsync %d\n",
- args->v0.version, args->v0.state, args->v0.data,
- args->v0.vsync, args->v0.hsync);
- stat = 0x00000040 * !args->v0.state;
- stat |= 0x00000010 * !args->v0.data;
- stat |= 0x00000004 * !args->v0.vsync;
- stat |= 0x00000001 * !args->v0.hsync;
- } else
- return ret;
-
- nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
- nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
- nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
- return 0;
-}
-
-int
-nv50_dac_sense(NV50_DISP_MTHD_V1)
-{
- union {
- struct nv50_disp_dac_load_v0 v0;
- } *args = data;
- const u32 doff = outp->or * 0x800;
- u32 loadval;
- int ret;
-
- nv_ioctl(object, "disp dac load size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp dac load vers %d data %08x\n",
- args->v0.version, args->v0.data);
- if (args->v0.data & 0xfff00000)
- return -EINVAL;
- loadval = args->v0.data;
- } else
- return ret;
-
- nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
- nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-
- nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
- mdelay(9);
- udelay(500);
- loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
-
- nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
- nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
-
- nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval);
- if (!(loadval & 0x80000000))
- return -ETIMEDOUT;
-
- args->v0.load = (loadval & 0x38000000) >> 27;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c b/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
deleted file mode 100644
index 16db08dfba6e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.c
+++ /dev/null
@@ -1,402 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/i2c.h>
-
-#include "nv50.h"
-
-#include <nvif/class.h>
-
-#include "dport.h"
-#include "outpdp.h"
-
-/******************************************************************************
- * link training
- *****************************************************************************/
-struct dp_state {
- struct nvkm_output_dp *outp;
- int link_nr;
- u32 link_bw;
- u8 stat[6];
- u8 conf[4];
- bool pc2;
- u8 pc2stat;
- u8 pc2conf[2];
-};
-
-static int
-dp_set_link_config(struct dp_state *dp)
-{
- struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
- struct nvkm_output_dp *outp = dp->outp;
- struct nouveau_disp *disp = nouveau_disp(outp);
- struct nouveau_bios *bios = nouveau_bios(disp);
- struct nvbios_init init = {
- .subdev = nv_subdev(disp),
- .bios = bios,
- .offset = 0x0000,
- .outp = &outp->base.info,
- .crtc = -1,
- .execute = 1,
- };
- u32 lnkcmp;
- u8 sink[2];
- int ret;
-
- DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
-
- /* set desired link configuration on the source */
- if ((lnkcmp = dp->outp->info.lnkcmp)) {
- if (outp->version < 0x30) {
- while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
- lnkcmp += 4;
- init.offset = nv_ro16(bios, lnkcmp + 2);
- } else {
- while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
- lnkcmp += 3;
- init.offset = nv_ro16(bios, lnkcmp + 1);
- }
-
- nvbios_exec(&init);
- }
-
- ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
- outp->dpcd[DPCD_RC02] &
- DPCD_RC02_ENHANCED_FRAME_CAP);
- if (ret) {
- if (ret < 0)
- ERR("lnk_ctl failed with %d\n", ret);
- return ret;
- }
-
- impl->lnk_pwr(outp, dp->link_nr);
-
- /* set desired link configuration on the sink */
- sink[0] = dp->link_bw / 27000;
- sink[1] = dp->link_nr;
- if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
- sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
-
- return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
-}
-
-static void
-dp_set_training_pattern(struct dp_state *dp, u8 pattern)
-{
- struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
- struct nvkm_output_dp *outp = dp->outp;
- u8 sink_tp;
-
- DBG("training pattern %d\n", pattern);
- impl->pattern(outp, pattern);
-
- nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
- sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
- sink_tp |= pattern;
- nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
-}
-
-static int
-dp_link_train_commit(struct dp_state *dp, bool pc)
-{
- struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
- struct nvkm_output_dp *outp = dp->outp;
- int ret, i;
-
- for (i = 0; i < dp->link_nr; i++) {
- u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
- u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
- u8 lpre = (lane & 0x0c) >> 2;
- u8 lvsw = (lane & 0x03) >> 0;
- u8 hivs = 3 - lpre;
- u8 hipe = 3;
- u8 hipc = 3;
-
- if (lpc2 >= hipc)
- lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
- if (lpre >= hipe) {
- lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
- lvsw = hivs = 3 - (lpre & 3);
- } else
- if (lvsw >= hivs) {
- lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
- }
-
- dp->conf[i] = (lpre << 3) | lvsw;
- dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
-
- DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
- impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
- }
-
- ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4);
- if (ret)
- return ret;
-
- if (pc) {
- ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int
-dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
-{
- struct nvkm_output_dp *outp = dp->outp;
- int ret;
-
- if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
- mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
- else
- udelay(delay);
-
- ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
- if (ret)
- return ret;
-
- if (pc) {
- ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1);
- if (ret)
- dp->pc2stat = 0x00;
- DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
- } else {
- DBG("status %6ph\n", dp->stat);
- }
-
- return 0;
-}
-
-static int
-dp_link_train_cr(struct dp_state *dp)
-{
- bool cr_done = false, abort = false;
- int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
- int tries = 0, i;
-
- dp_set_training_pattern(dp, 1);
-
- do {
- if (dp_link_train_commit(dp, false) ||
- dp_link_train_update(dp, false, 100))
- break;
-
- cr_done = true;
- for (i = 0; i < dp->link_nr; i++) {
- u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
- if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
- cr_done = false;
- if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
- abort = true;
- break;
- }
- }
-
- if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
- voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
- tries = 0;
- }
- } while (!cr_done && !abort && ++tries < 5);
-
- return cr_done ? 0 : -1;
-}
-
-static int
-dp_link_train_eq(struct dp_state *dp)
-{
- struct nvkm_output_dp *outp = dp->outp;
- bool eq_done = false, cr_done = true;
- int tries = 0, i;
-
- if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
- dp_set_training_pattern(dp, 3);
- else
- dp_set_training_pattern(dp, 2);
-
- do {
- if ((tries &&
- dp_link_train_commit(dp, dp->pc2)) ||
- dp_link_train_update(dp, dp->pc2, 400))
- break;
-
- eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
- for (i = 0; i < dp->link_nr && eq_done; i++) {
- u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
- if (!(lane & DPCD_LS02_LANE0_CR_DONE))
- cr_done = false;
- if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
- !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
- eq_done = false;
- }
- } while (!eq_done && cr_done && ++tries <= 5);
-
- return eq_done ? 0 : -1;
-}
-
-static void
-dp_link_train_init(struct dp_state *dp, bool spread)
-{
- struct nvkm_output_dp *outp = dp->outp;
- struct nouveau_disp *disp = nouveau_disp(outp);
- struct nouveau_bios *bios = nouveau_bios(disp);
- struct nvbios_init init = {
- .subdev = nv_subdev(disp),
- .bios = bios,
- .outp = &outp->base.info,
- .crtc = -1,
- .execute = 1,
- };
-
- /* set desired spread */
- if (spread)
- init.offset = outp->info.script[2];
- else
- init.offset = outp->info.script[3];
- nvbios_exec(&init);
-
- /* pre-train script */
- init.offset = outp->info.script[0];
- nvbios_exec(&init);
-}
-
-static void
-dp_link_train_fini(struct dp_state *dp)
-{
- struct nvkm_output_dp *outp = dp->outp;
- struct nouveau_disp *disp = nouveau_disp(outp);
- struct nouveau_bios *bios = nouveau_bios(disp);
- struct nvbios_init init = {
- .subdev = nv_subdev(disp),
- .bios = bios,
- .outp = &outp->base.info,
- .crtc = -1,
- .execute = 1,
- };
-
- /* post-train script */
- init.offset = outp->info.script[1],
- nvbios_exec(&init);
-}
-
-static const struct dp_rates {
- u32 rate;
- u8 bw;
- u8 nr;
-} nouveau_dp_rates[] = {
- { 2160000, 0x14, 4 },
- { 1080000, 0x0a, 4 },
- { 1080000, 0x14, 2 },
- { 648000, 0x06, 4 },
- { 540000, 0x0a, 2 },
- { 540000, 0x14, 1 },
- { 324000, 0x06, 2 },
- { 270000, 0x0a, 1 },
- { 162000, 0x06, 1 },
- {}
-};
-
-void
-nouveau_dp_train(struct work_struct *w)
-{
- struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const struct dp_rates *cfg = nouveau_dp_rates;
- struct dp_state _dp = {
- .outp = outp,
- }, *dp = &_dp;
- u32 datarate = 0;
- int ret;
-
- if (!outp->base.info.location && priv->sor.magic)
- priv->sor.magic(&outp->base);
-
- /* bring capabilities within encoder limits */
- if (nv_mclass(priv) < GF110_DISP)
- outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
- if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
- outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
- outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
- }
- if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
- outp->dpcd[1] = outp->base.info.dpconf.link_bw;
- dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
-
- /* restrict link config to the lowest required rate, if requested */
- if (datarate) {
- datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
- while (cfg[1].rate >= datarate)
- cfg++;
- }
- cfg--;
-
- /* disable link interrupt handling during link training */
- nvkm_notify_put(&outp->irq);
-
- /* enable down-spreading and execute pre-train script from vbios */
- dp_link_train_init(dp, outp->dpcd[3] & 0x01);
-
- while (ret = -EIO, (++cfg)->rate) {
- /* select next configuration supported by encoder and sink */
- while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
- cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
- cfg++;
- dp->link_bw = cfg->bw * 27000;
- dp->link_nr = cfg->nr;
-
- /* program selected link configuration */
- ret = dp_set_link_config(dp);
- if (ret == 0) {
- /* attempt to train the link at this configuration */
- memset(dp->stat, 0x00, sizeof(dp->stat));
- if (!dp_link_train_cr(dp) &&
- !dp_link_train_eq(dp))
- break;
- } else
- if (ret) {
- /* dp_set_link_config() handled training, or
- * we failed to communicate with the sink.
- */
- break;
- }
- }
-
- /* finish link training and execute post-train script from vbios */
- dp_set_training_pattern(dp, 0);
- if (ret < 0)
- ERR("link training failed\n");
-
- dp_link_train_fini(dp);
-
- /* signal completion and enable link interrupt handling */
- DBG("training complete\n");
- atomic_set(&outp->lt.done, 1);
- wake_up(&outp->lt.wait);
- nvkm_notify_get(&outp->irq);
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h b/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
deleted file mode 100644
index 5628d2d5ec71..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/dport.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef __NVKM_DISP_DPORT_H__
-#define __NVKM_DISP_DPORT_H__
-
-/* DPCD Receiver Capabilities */
-#define DPCD_RC00_DPCD_REV 0x00000
-#define DPCD_RC01_MAX_LINK_RATE 0x00001
-#define DPCD_RC02 0x00002
-#define DPCD_RC02_ENHANCED_FRAME_CAP 0x80
-#define DPCD_RC02_TPS3_SUPPORTED 0x40
-#define DPCD_RC02_MAX_LANE_COUNT 0x1f
-#define DPCD_RC03 0x00003
-#define DPCD_RC03_MAX_DOWNSPREAD 0x01
-#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e
-
-/* DPCD Link Configuration */
-#define DPCD_LC00_LINK_BW_SET 0x00100
-#define DPCD_LC01 0x00101
-#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
-#define DPCD_LC01_LANE_COUNT_SET 0x1f
-#define DPCD_LC02 0x00102
-#define DPCD_LC02_TRAINING_PATTERN_SET 0x03
-#define DPCD_LC03(l) ((l) + 0x00103)
-#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20
-#define DPCD_LC03_PRE_EMPHASIS_SET 0x18
-#define DPCD_LC03_MAX_SWING_REACHED 0x04
-#define DPCD_LC03_VOLTAGE_SWING_SET 0x03
-#define DPCD_LC0F 0x0010f
-#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED 0x40
-#define DPCD_LC0F_LANE1_POST_CURSOR2_SET 0x30
-#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED 0x04
-#define DPCD_LC0F_LANE0_POST_CURSOR2_SET 0x03
-#define DPCD_LC10 0x00110
-#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED 0x40
-#define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30
-#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04
-#define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03
-
-/* DPCD Link/Sink Status */
-#define DPCD_LS02 0x00202
-#define DPCD_LS02_LANE1_SYMBOL_LOCKED 0x40
-#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE 0x20
-#define DPCD_LS02_LANE1_CR_DONE 0x10
-#define DPCD_LS02_LANE0_SYMBOL_LOCKED 0x04
-#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE 0x02
-#define DPCD_LS02_LANE0_CR_DONE 0x01
-#define DPCD_LS03 0x00203
-#define DPCD_LS03_LANE3_SYMBOL_LOCKED 0x40
-#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE 0x20
-#define DPCD_LS03_LANE3_CR_DONE 0x10
-#define DPCD_LS03_LANE2_SYMBOL_LOCKED 0x04
-#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE 0x02
-#define DPCD_LS03_LANE2_CR_DONE 0x01
-#define DPCD_LS04 0x00204
-#define DPCD_LS04_LINK_STATUS_UPDATED 0x80
-#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED 0x40
-#define DPCD_LS04_INTERLANE_ALIGN_DONE 0x01
-#define DPCD_LS06 0x00206
-#define DPCD_LS06_LANE1_PRE_EMPHASIS 0xc0
-#define DPCD_LS06_LANE1_VOLTAGE_SWING 0x30
-#define DPCD_LS06_LANE0_PRE_EMPHASIS 0x0c
-#define DPCD_LS06_LANE0_VOLTAGE_SWING 0x03
-#define DPCD_LS07 0x00207
-#define DPCD_LS07_LANE3_PRE_EMPHASIS 0xc0
-#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30
-#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c
-#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03
-#define DPCD_LS0C 0x0020c
-#define DPCD_LS0C_LANE3_POST_CURSOR2 0xc0
-#define DPCD_LS0C_LANE2_POST_CURSOR2 0x30
-#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c
-#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03
-
-void nouveau_dp_train(struct work_struct *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
deleted file mode 100644
index e2ad0543fb31..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm107.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-gm107_disp_sclass[] = {
- { GM107_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
- { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
- { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
- { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
- { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-gm107_disp_main_oclass[] = {
- { GM107_DISP, &nvd0_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-gm107_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int heads = nv_rd32(parent, 0x022448);
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, heads,
- "PDISP", "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = gm107_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nvd0_disp_intr;
- INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
- priv->sclass = gm107_disp_sclass;
- priv->head.nr = heads;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nve0_hdmi_ctrl;
- return 0;
-}
-
-struct nouveau_oclass *
-gm107_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x07),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm107_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nvd0_disp_vblank_func,
- .base.outp = nvd0_disp_outp_sclass,
- .mthd.core = &nve0_disp_core_mthd_chan,
- .mthd.base = &nvd0_disp_base_mthd_chan,
- .mthd.ovly = &nve0_disp_ovly_mthd_chan,
- .mthd.prev = -0x020000,
- .head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c
deleted file mode 100644
index 672ded79b2a9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/gm204.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-gm204_disp_sclass[] = {
- { GM204_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
- { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
- { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
- { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
- { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-gm204_disp_main_oclass[] = {
- { GM204_DISP, &nvd0_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-gm204_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int heads = nv_rd32(parent, 0x022448);
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, heads,
- "PDISP", "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = gm204_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nvd0_disp_intr;
- INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
- priv->sclass = gm204_disp_sclass;
- priv->head.nr = heads;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nvd0_hdmi_ctrl;
- priv->sor.magic = gm204_sor_magic;
- return 0;
-}
-
-struct nouveau_oclass *
-gm204_disp_outp_sclass[] = {
- &gm204_sor_dp_impl.base.base,
- NULL
-};
-
-struct nouveau_oclass *
-gm204_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x07),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm204_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nvd0_disp_vblank_func,
- .base.outp = gm204_disp_outp_sclass,
- .mthd.core = &nve0_disp_core_mthd_chan,
- .mthd.base = &nvd0_disp_base_mthd_chan,
- .mthd.ovly = &nve0_disp_ovly_mthd_chan,
- .mthd.prev = -0x020000,
- .head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
deleted file mode 100644
index fe9ef5894dd4..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanva3.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nva3_hda_eld(NV50_DISP_MTHD_V1)
-{
- union {
- struct nv50_disp_sor_hda_eld_v0 v0;
- } *args = data;
- const u32 soff = outp->or * 0x800;
- int ret, i;
-
- nv_ioctl(object, "disp sor hda eld size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
- if (size > 0x60)
- return -E2BIG;
- } else
- return ret;
-
- if (size && args->v0.data[0]) {
- if (outp->info.type == DCB_OUTPUT_DP) {
- nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
- nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
- }
- for (i = 0; i < size; i++)
- nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
- for (; i < 0x60; i++)
- nv_wr32(priv, 0x61c440 + soff, (i << 8));
- nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
- } else {
- if (outp->info.type == DCB_OUTPUT_DP) {
- nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
- nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
- }
- nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
deleted file mode 100644
index 1d4e8432d857..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdanvd0.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nvd0_hda_eld(NV50_DISP_MTHD_V1)
-{
- union {
- struct nv50_disp_sor_hda_eld_v0 v0;
- } *args = data;
- const u32 soff = outp->or * 0x030;
- const u32 hoff = head * 0x800;
- int ret, i;
-
- nv_ioctl(object, "disp sor hda eld size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
- if (size > 0x60)
- return -E2BIG;
- } else
- return ret;
-
- if (size && args->v0.data[0]) {
- if (outp->info.type == DCB_OUTPUT_DP) {
- nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
- nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
- }
- nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
- for (i = 0; i < size; i++)
- nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
- for (; i < 0x60; i++)
- nv_wr32(priv, 0x10ec00 + soff, (i << 8));
- nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
- } else {
- if (outp->info.type == DCB_OUTPUT_DP) {
- nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
- nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
- }
- nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
deleted file mode 100644
index fa276dede9cd..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminv84.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nv84_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
- const u32 hoff = (head * 0x800);
- union {
- struct nv50_disp_sor_hdmi_pwr_v0 v0;
- } *args = data;
- u32 ctrl;
- int ret;
-
- nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
- "max_ac_packet %d rekey %d\n",
- args->v0.version, args->v0.state,
- args->v0.max_ac_packet, args->v0.rekey);
- if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
- return -EINVAL;
- ctrl = 0x40000000 * !!args->v0.state;
- ctrl |= args->v0.max_ac_packet << 16;
- ctrl |= args->v0.rekey;
- ctrl |= 0x1f000000; /* ??? */
- } else
- return ret;
-
- if (!(ctrl & 0x40000000)) {
- nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
- nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x616528 + hoff, 0x000d0282);
- nv_wr32(priv, 0x61652c + hoff, 0x0000006f);
- nv_wr32(priv, 0x616530 + hoff, 0x00000000);
- nv_wr32(priv, 0x616534 + hoff, 0x00000000);
- nv_wr32(priv, 0x616538 + hoff, 0x00000000);
- nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001);
-
- /* Audio InfoFrame */
- nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x616508 + hoff, 0x000a0184);
- nv_wr32(priv, 0x61650c + hoff, 0x00000071);
- nv_wr32(priv, 0x616510 + hoff, 0x00000000);
- nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
-
- nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
- nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
- nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
-
- /* ??? */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
- nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
deleted file mode 100644
index 57eeed1d1942..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminva3.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nva3_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
- const u32 soff = outp->or * 0x800;
- union {
- struct nv50_disp_sor_hdmi_pwr_v0 v0;
- } *args = data;
- u32 ctrl;
- int ret;
-
- nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
- "max_ac_packet %d rekey %d\n",
- args->v0.version, args->v0.state,
- args->v0.max_ac_packet, args->v0.rekey);
- if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
- return -EINVAL;
- ctrl = 0x40000000 * !!args->v0.state;
- ctrl |= args->v0.max_ac_packet << 16;
- ctrl |= args->v0.rekey;
- ctrl |= 0x1f000000; /* ??? */
- } else
- return ret;
-
- if (!(ctrl & 0x40000000)) {
- nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
- nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x61c528 + soff, 0x000d0282);
- nv_wr32(priv, 0x61c52c + soff, 0x0000006f);
- nv_wr32(priv, 0x61c530 + soff, 0x00000000);
- nv_wr32(priv, 0x61c534 + soff, 0x00000000);
- nv_wr32(priv, 0x61c538 + soff, 0x00000000);
- nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001);
-
- /* Audio InfoFrame */
- nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x61c508 + soff, 0x000a0184);
- nv_wr32(priv, 0x61c50c + soff, 0x00000071);
- nv_wr32(priv, 0x61c510 + soff, 0x00000000);
- nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
-
- nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
- nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
- nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
-
- /* ??? */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
- nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
- nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
deleted file mode 100644
index bac4fc4570f0..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminvd0.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
- const u32 hoff = (head * 0x800);
- union {
- struct nv50_disp_sor_hdmi_pwr_v0 v0;
- } *args = data;
- u32 ctrl;
- int ret;
-
- nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
- "max_ac_packet %d rekey %d\n",
- args->v0.version, args->v0.state,
- args->v0.max_ac_packet, args->v0.rekey);
- if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
- return -EINVAL;
- ctrl = 0x40000000 * !!args->v0.state;
- ctrl |= args->v0.max_ac_packet << 16;
- ctrl |= args->v0.rekey;
- } else
- return ret;
-
- if (!(ctrl & 0x40000000)) {
- nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
- nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x61671c + hoff, 0x000d0282);
- nv_wr32(priv, 0x616720 + hoff, 0x0000006f);
- nv_wr32(priv, 0x616724 + hoff, 0x00000000);
- nv_wr32(priv, 0x616728 + hoff, 0x00000000);
- nv_wr32(priv, 0x61672c + hoff, 0x00000000);
- nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001);
-
- /* ??? InfoFrame? */
- nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x6167ac + hoff, 0x00000010);
- nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001);
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
deleted file mode 100644
index 528d14ec2f7f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/hdminve0.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-int
-nve0_hdmi_ctrl(NV50_DISP_MTHD_V1)
-{
- const u32 hoff = (head * 0x800);
- const u32 hdmi = (head * 0x400);
- union {
- struct nv50_disp_sor_hdmi_pwr_v0 v0;
- } *args = data;
- u32 ctrl;
- int ret;
-
- nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
- "max_ac_packet %d rekey %d\n",
- args->v0.version, args->v0.state,
- args->v0.max_ac_packet, args->v0.rekey);
- if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
- return -EINVAL;
- ctrl = 0x40000000 * !!args->v0.state;
- ctrl |= args->v0.max_ac_packet << 16;
- ctrl |= args->v0.rekey;
- } else
- return ret;
-
- if (!(ctrl & 0x40000000)) {
- nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
- nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
- nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
- return 0;
- }
-
- /* AVI InfoFrame */
- nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
- nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
- nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
- nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
- nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
- nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
-
- /* ??? InfoFrame? */
- nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
- nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
- nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
-
- /* ??? */
- nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
-
- /* HDMI_CTRL */
- nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
deleted file mode 100644
index 366f315fc9a5..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv04.c
+++ /dev/null
@@ -1,205 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-#include <core/client.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-struct nv04_disp_priv {
- struct nouveau_disp base;
-};
-
-static int
-nv04_disp_scanoutpos(struct nouveau_object *object, struct nv04_disp_priv *priv,
- void *data, u32 size, int head)
-{
- const u32 hoff = head * 0x2000;
- union {
- struct nv04_disp_scanoutpos_v0 v0;
- } *args = data;
- u32 line;
- int ret;
-
- nv_ioctl(object, "disp scanoutpos size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
- args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
- args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
- args->v0.vblanke = args->v0.vtotal - 1;
-
- args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
- args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
- args->v0.hblanke = args->v0.htotal - 1;
-
- /*
- * If output is vga instead of digital then vtotal/htotal is
- * invalid so we have to give up and trigger the timestamping
- * fallback in the drm core.
- */
- if (!args->v0.vtotal || !args->v0.htotal)
- return -ENOTSUPP;
-
- args->v0.time[0] = ktime_to_ns(ktime_get());
- line = nv_rd32(priv, 0x600868 + hoff);
- args->v0.time[1] = ktime_to_ns(ktime_get());
- args->v0.hline = (line & 0xffff0000) >> 16;
- args->v0.vline = (line & 0x0000ffff);
- } else
- return ret;
-
- return 0;
-}
-
-static int
-nv04_disp_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
-{
- union {
- struct nv04_disp_mthd_v0 v0;
- } *args = data;
- struct nv04_disp_priv *priv = (void *)object->engine;
- int head, ret;
-
- nv_ioctl(object, "disp mthd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
- args->v0.version, args->v0.method, args->v0.head);
- mthd = args->v0.method;
- head = args->v0.head;
- } else
- return ret;
-
- if (head < 0 || head >= 2)
- return -ENXIO;
-
- switch (mthd) {
- case NV04_DISP_SCANOUTPOS:
- return nv04_disp_scanoutpos(object, priv, data, size, head);
- default:
- break;
- }
-
- return -EINVAL;
-}
-
-static struct nouveau_ofuncs
-nv04_disp_ofuncs = {
- .ctor = _nouveau_object_ctor,
- .dtor = nouveau_object_destroy,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- .mthd = nv04_disp_mthd,
- .ntfy = nouveau_disp_ntfy,
-};
-
-static struct nouveau_oclass
-nv04_disp_sclass[] = {
- { NV04_DISP, &nv04_disp_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
-{
- struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
- nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
-}
-
-static void
-nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
-{
- struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
- nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
-}
-
-static const struct nvkm_event_func
-nv04_disp_vblank_func = {
- .ctor = nouveau_disp_vblank_ctor,
- .init = nv04_disp_vblank_init,
- .fini = nv04_disp_vblank_fini,
-};
-
-static void
-nv04_disp_intr(struct nouveau_subdev *subdev)
-{
- struct nv04_disp_priv *priv = (void *)subdev;
- u32 crtc0 = nv_rd32(priv, 0x600100);
- u32 crtc1 = nv_rd32(priv, 0x602100);
- u32 pvideo;
-
- if (crtc0 & 0x00000001) {
- nouveau_disp_vblank(&priv->base, 0);
- nv_wr32(priv, 0x600100, 0x00000001);
- }
-
- if (crtc1 & 0x00000001) {
- nouveau_disp_vblank(&priv->base, 1);
- nv_wr32(priv, 0x602100, 0x00000001);
- }
-
- if (nv_device(priv)->chipset >= 0x10 &&
- nv_device(priv)->chipset <= 0x40) {
- pvideo = nv_rd32(priv, 0x8100);
- if (pvideo & ~0x11)
- nv_info(priv, "PVIDEO intr: %08x\n", pvideo);
- nv_wr32(priv, 0x8100, pvideo);
- }
-}
-
-static int
-nv04_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, 2, "DISPLAY",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nv04_disp_sclass;
- nv_subdev(priv)->intr = nv04_disp_intr;
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_disp_oclass = &(struct nouveau_disp_impl) {
- .base.handle = NV_ENGINE(DISP, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .vblank = &nv04_disp_vblank_func,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
deleted file mode 100644
index 44a8290aaea5..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.c
+++ /dev/null
@@ -1,2017 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/parent.h>
-#include <core/handle.h>
-#include <core/enum.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/event.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/disp.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/pll.h>
-#include <subdev/devinit.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_chan_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int head,
- int length, void **pobject)
-{
- const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
- struct nv50_disp_base *base = (void *)parent;
- struct nv50_disp_chan *chan;
- int chid = impl->chid + head;
- int ret;
-
- if (base->chan & (1 << chid))
- return -EBUSY;
- base->chan |= (1 << chid);
-
- ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
- (1ULL << NVDEV_ENGINE_DMAOBJ),
- length, pobject);
- chan = *pobject;
- if (ret)
- return ret;
- chan->chid = chid;
-
- nv_parent(chan)->object_attach = impl->attach;
- nv_parent(chan)->object_detach = impl->detach;
- return 0;
-}
-
-static void
-nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
-{
- struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
- base->chan &= ~(1 << chan->chid);
- nouveau_namedb_destroy(&chan->base);
-}
-
-static void
-nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
-{
- struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
- nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
- nv_wr32(priv, 0x610020, 0x00000001 << index);
-}
-
-static void
-nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
-{
- struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
- nv_wr32(priv, 0x610020, 0x00000001 << index);
- nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
-}
-
-void
-nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
-{
- struct nvif_notify_uevent_rep {
- } rep;
-
- nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
-}
-
-int
-nv50_disp_chan_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nv50_disp_dmac *dmac = (void *)object;
- union {
- struct nvif_notify_uevent_req none;
- } *args = data;
- int ret;
-
- if (nvif_unvers(args->none)) {
- notify->size = sizeof(struct nvif_notify_uevent_rep);
- notify->types = 1;
- notify->index = dmac->base.chid;
- return 0;
- }
-
- return ret;
-}
-
-const struct nvkm_event_func
-nv50_disp_chan_uevent = {
- .ctor = nv50_disp_chan_uevent_ctor,
- .init = nv50_disp_chan_uevent_init,
- .fini = nv50_disp_chan_uevent_fini,
-};
-
-int
-nv50_disp_chan_ntfy(struct nouveau_object *object, u32 type,
- struct nvkm_event **pevent)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- switch (type) {
- case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
- *pevent = &priv->uevent;
- return 0;
- default:
- break;
- }
- return -EINVAL;
-}
-
-int
-nv50_disp_chan_map(struct nouveau_object *object, u64 *addr, u32 *size)
-{
- struct nv50_disp_chan *chan = (void *)object;
- *addr = nv_device_resource_start(nv_device(object), 0) +
- 0x640000 + (chan->chid * 0x1000);
- *size = 0x001000;
- return 0;
-}
-
-u32
-nv50_disp_chan_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_chan *chan = (void *)object;
- return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
-}
-
-void
-nv50_disp_chan_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_chan *chan = (void *)object;
- nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
-}
-
-/*******************************************************************************
- * EVO DMA channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_dmac_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 name)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- struct nv50_disp_chan *chan = (void *)parent;
- u32 addr = nv_gpuobj(object)->node->offset;
- u32 chid = chan->chid;
- u32 data = (chid << 28) | (addr << 10) | chid;
- return nouveau_ramht_insert(base->ramht, chid, name, data);
-}
-
-static void
-nv50_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- nouveau_ramht_remove(base->ramht, cookie);
-}
-
-static int
-nv50_disp_dmac_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 pushbuf, int head,
- int length, void **pobject)
-{
- struct nv50_disp_dmac *dmac;
- int ret;
-
- ret = nv50_disp_chan_create_(parent, engine, oclass, head,
- length, pobject);
- dmac = *pobject;
- if (ret)
- return ret;
-
- dmac->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
- if (!dmac->pushdma)
- return -ENOENT;
-
- switch (nv_mclass(dmac->pushdma)) {
- case 0x0002:
- case 0x003d:
- if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
- return -EINVAL;
-
- switch (dmac->pushdma->target) {
- case NV_MEM_TARGET_VRAM:
- dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
- break;
- case NV_MEM_TARGET_PCI_NOSNOOP:
- dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-void
-nv50_disp_dmac_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_dmac *dmac = (void *)object;
- nouveau_object_ref(NULL, (struct nouveau_object **)&dmac->pushdma);
- nv50_disp_chan_destroy(&dmac->base);
-}
-
-static int
-nv50_disp_dmac_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&dmac->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
- nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
- nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
- nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
- nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
- nv_error(dmac, "init timeout, 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nv50_disp_dmac_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
-
- /* deactivate channel */
- nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
- nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
- nv_error(dmac, "fini timeout, 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting and completion notifications */
- nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
-
- return nv50_disp_chan_fini(&dmac->base, suspend);
-}
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-static void
-nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
- const struct nv50_disp_mthd_list *list, int inst)
-{
- struct nouveau_object *disp = nv_object(priv);
- int i;
-
- for (i = 0; list->data[i].mthd; i++) {
- if (list->data[i].addr) {
- u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
- u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
- u32 mthd = list->data[i].mthd + (list->mthd * inst);
- const char *name = list->data[i].name;
- char mods[16];
-
- if (prev != next)
- snprintf(mods, sizeof(mods), "-> 0x%08x", next);
- else
- snprintf(mods, sizeof(mods), "%13c", ' ');
-
- nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
- mthd, prev, mods, name ? " // " : "",
- name ? name : "");
- }
- }
-}
-
-void
-nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
- const struct nv50_disp_mthd_chan *chan)
-{
- struct nouveau_object *disp = nv_object(priv);
- const struct nv50_disp_impl *impl = (void *)disp->oclass;
- const struct nv50_disp_mthd_list *list;
- int i, j;
-
- if (debug > nv_subdev(priv)->debug)
- return;
-
- for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
- u32 base = head * chan->addr;
- for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
- const char *cname = chan->name;
- const char *sname = "";
- char cname_[16], sname_[16];
-
- if (chan->addr) {
- snprintf(cname_, sizeof(cname_), "%s %d",
- chan->name, head);
- cname = cname_;
- }
-
- if (chan->data[i].nr > 1) {
- snprintf(sname_, sizeof(sname_), " - %s %d",
- chan->data[i].name, j);
- sname = sname_;
- }
-
- nv_printk_(disp, debug, "%s%s:\n", cname, sname);
- nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
- list, j);
- }
- }
-}
-
-const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x000000 },
- { 0x0084, 0x610bb8 },
- { 0x0088, 0x610b9c },
- { 0x008c, 0x000000 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_dac = {
- .mthd = 0x0080,
- .addr = 0x000008,
- .data = {
- { 0x0400, 0x610b58 },
- { 0x0404, 0x610bdc },
- { 0x0420, 0x610828 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_sor = {
- .mthd = 0x0040,
- .addr = 0x000008,
- .data = {
- { 0x0600, 0x610b70 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_pior = {
- .mthd = 0x0040,
- .addr = 0x000008,
- .data = {
- { 0x0700, 0x610b80 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_list
-nv50_disp_core_mthd_head = {
- .mthd = 0x0400,
- .addr = 0x000540,
- .data = {
- { 0x0800, 0x610ad8 },
- { 0x0804, 0x610ad0 },
- { 0x0808, 0x610a48 },
- { 0x080c, 0x610a78 },
- { 0x0810, 0x610ac0 },
- { 0x0814, 0x610af8 },
- { 0x0818, 0x610b00 },
- { 0x081c, 0x610ae8 },
- { 0x0820, 0x610af0 },
- { 0x0824, 0x610b08 },
- { 0x0828, 0x610b10 },
- { 0x082c, 0x610a68 },
- { 0x0830, 0x610a60 },
- { 0x0834, 0x000000 },
- { 0x0838, 0x610a40 },
- { 0x0840, 0x610a24 },
- { 0x0844, 0x610a2c },
- { 0x0848, 0x610aa8 },
- { 0x084c, 0x610ab0 },
- { 0x0860, 0x610a84 },
- { 0x0864, 0x610a90 },
- { 0x0868, 0x610b18 },
- { 0x086c, 0x610b20 },
- { 0x0870, 0x610ac8 },
- { 0x0874, 0x610a38 },
- { 0x0880, 0x610a58 },
- { 0x0884, 0x610a9c },
- { 0x08a0, 0x610a70 },
- { 0x08a4, 0x610a50 },
- { 0x08a8, 0x610ae0 },
- { 0x08c0, 0x610b28 },
- { 0x08c4, 0x610b30 },
- { 0x08c8, 0x610b40 },
- { 0x08d4, 0x610b38 },
- { 0x08d8, 0x610b48 },
- { 0x08dc, 0x610b50 },
- { 0x0900, 0x610a18 },
- { 0x0904, 0x610ab8 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_chan
-nv50_disp_core_mthd_chan = {
- .name = "Core",
- .addr = 0x000000,
- .data = {
- { "Global", 1, &nv50_disp_core_mthd_base },
- { "DAC", 3, &nv50_disp_core_mthd_dac },
- { "SOR", 2, &nv50_disp_core_mthd_sor },
- { "PIOR", 3, &nv50_disp_core_mthd_pior },
- { "HEAD", 2, &nv50_disp_core_mthd_head },
- {}
- }
-};
-
-int
-nv50_disp_core_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_disp_core_channel_dma_v0 v0;
- } *args = data;
- struct nv50_disp_dmac *mast;
- int ret;
-
- nv_ioctl(parent, "create disp core channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create disp core channel dma vers %d "
- "pushbuf %08x\n",
- args->v0.version, args->v0.pushbuf);
- } else
- return ret;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
- 0, sizeof(*mast), (void **)&mast);
- *pobject = nv_object(mast);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int
-nv50_disp_core_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
- int ret;
-
- ret = nv50_disp_chan_init(&mast->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x610028, 0x00010000, 0x00010000);
-
- /* attempt to unstick channel from some unknown state */
- if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
- nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
- if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
- nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610204, mast->push);
- nv_wr32(priv, 0x610208, 0x00010000);
- nv_wr32(priv, 0x61020c, 0x00000000);
- nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000, 0x00000000);
- nv_wr32(priv, 0x610200, 0x01000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
- nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nv50_disp_core_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
-
- /* deactivate channel */
- nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
- nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
- nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting and completion notifications */
- nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
-
- return nv50_disp_chan_fini(&mast->base, suspend);
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_core_ofuncs = {
- .base.ctor = nv50_disp_core_ctor,
- .base.dtor = nv50_disp_dmac_dtor,
- .base.init = nv50_disp_core_init,
- .base.fini = nv50_disp_core_fini,
- .base.map = nv50_disp_chan_map,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 0,
- .attach = nv50_disp_dmac_object_attach,
- .detach = nv50_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nv50_disp_base_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x000000 },
- { 0x0084, 0x0008c4 },
- { 0x0088, 0x0008d0 },
- { 0x008c, 0x0008dc },
- { 0x0090, 0x0008e4 },
- { 0x0094, 0x610884 },
- { 0x00a0, 0x6108a0 },
- { 0x00a4, 0x610878 },
- { 0x00c0, 0x61086c },
- { 0x00e0, 0x610858 },
- { 0x00e4, 0x610860 },
- { 0x00e8, 0x6108ac },
- { 0x00ec, 0x6108b4 },
- { 0x0100, 0x610894 },
- { 0x0110, 0x6108bc },
- { 0x0114, 0x61088c },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nv50_disp_base_mthd_image = {
- .mthd = 0x0400,
- .addr = 0x000000,
- .data = {
- { 0x0800, 0x6108f0 },
- { 0x0804, 0x6108fc },
- { 0x0808, 0x61090c },
- { 0x080c, 0x610914 },
- { 0x0810, 0x610904 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_chan
-nv50_disp_base_mthd_chan = {
- .name = "Base",
- .addr = 0x000540,
- .data = {
- { "Global", 1, &nv50_disp_base_mthd_base },
- { "Image", 2, &nv50_disp_base_mthd_image },
- {}
- }
-};
-
-int
-nv50_disp_base_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_disp_base_channel_dma_v0 v0;
- } *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_dmac *dmac;
- int ret;
-
- nv_ioctl(parent, "create disp base channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create disp base channel dma vers %d "
- "pushbuf %08x head %d\n",
- args->v0.version, args->v0.pushbuf, args->v0.head);
- if (args->v0.head > priv->head.nr)
- return -EINVAL;
- } else
- return ret;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
- args->v0.head, sizeof(*dmac),
- (void **)&dmac);
- *pobject = nv_object(dmac);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_base_ofuncs = {
- .base.ctor = nv50_disp_base_ctor,
- .base.dtor = nv50_disp_dmac_dtor,
- .base.init = nv50_disp_dmac_init,
- .base.fini = nv50_disp_dmac_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 1,
- .attach = nv50_disp_dmac_object_attach,
- .detach = nv50_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nv50_disp_ovly_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x000000 },
- { 0x0084, 0x0009a0 },
- { 0x0088, 0x0009c0 },
- { 0x008c, 0x0009c8 },
- { 0x0090, 0x6109b4 },
- { 0x0094, 0x610970 },
- { 0x00a0, 0x610998 },
- { 0x00a4, 0x610964 },
- { 0x00c0, 0x610958 },
- { 0x00e0, 0x6109a8 },
- { 0x00e4, 0x6109d0 },
- { 0x00e8, 0x6109d8 },
- { 0x0100, 0x61094c },
- { 0x0104, 0x610984 },
- { 0x0108, 0x61098c },
- { 0x0800, 0x6109f8 },
- { 0x0808, 0x610a08 },
- { 0x080c, 0x610a10 },
- { 0x0810, 0x610a00 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_chan
-nv50_disp_ovly_mthd_chan = {
- .name = "Overlay",
- .addr = 0x000540,
- .data = {
- { "Global", 1, &nv50_disp_ovly_mthd_base },
- {}
- }
-};
-
-int
-nv50_disp_ovly_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_disp_overlay_channel_dma_v0 v0;
- } *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_dmac *dmac;
- int ret;
-
- nv_ioctl(parent, "create disp overlay channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create disp overlay channel dma vers %d "
- "pushbuf %08x head %d\n",
- args->v0.version, args->v0.pushbuf, args->v0.head);
- if (args->v0.head > priv->head.nr)
- return -EINVAL;
- } else
- return ret;
-
- ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
- args->v0.head, sizeof(*dmac),
- (void **)&dmac);
- *pobject = nv_object(dmac);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_ovly_ofuncs = {
- .base.ctor = nv50_disp_ovly_ctor,
- .base.dtor = nv50_disp_dmac_dtor,
- .base.init = nv50_disp_dmac_init,
- .base.fini = nv50_disp_dmac_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 3,
- .attach = nv50_disp_dmac_object_attach,
- .detach = nv50_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO PIO channel base class
- ******************************************************************************/
-
-static int
-nv50_disp_pioc_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int head,
- int length, void **pobject)
-{
- return nv50_disp_chan_create_(parent, engine, oclass, head,
- length, pobject);
-}
-
-void
-nv50_disp_pioc_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_pioc *pioc = (void *)object;
- nv50_disp_chan_destroy(&pioc->base);
-}
-
-static int
-nv50_disp_pioc_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&pioc->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
- nv_error(pioc, "timeout0: 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
- nv_error(pioc, "timeout1: 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nv50_disp_pioc_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
-
- nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
- nv_error(pioc, "timeout: 0x%08x\n",
- nv_rd32(priv, 0x610200 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- return nv50_disp_chan_fini(&pioc->base, suspend);
-}
-
-/*******************************************************************************
- * EVO immediate overlay channel objects
- ******************************************************************************/
-
-int
-nv50_disp_oimm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_disp_overlay_v0 v0;
- } *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_pioc *pioc;
- int ret;
-
- nv_ioctl(parent, "create disp overlay size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create disp overlay vers %d head %d\n",
- args->v0.version, args->v0.head);
- if (args->v0.head > priv->head.nr)
- return -EINVAL;
- } else
- return ret;
-
- ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
- sizeof(*pioc), (void **)&pioc);
- *pobject = nv_object(pioc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_oimm_ofuncs = {
- .base.ctor = nv50_disp_oimm_ctor,
- .base.dtor = nv50_disp_pioc_dtor,
- .base.init = nv50_disp_pioc_init,
- .base.fini = nv50_disp_pioc_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 5,
-};
-
-/*******************************************************************************
- * EVO cursor channel objects
- ******************************************************************************/
-
-int
-nv50_disp_curs_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_disp_cursor_v0 v0;
- } *args = data;
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_pioc *pioc;
- int ret;
-
- nv_ioctl(parent, "create disp cursor size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create disp cursor vers %d head %d\n",
- args->v0.version, args->v0.head);
- if (args->v0.head > priv->head.nr)
- return -EINVAL;
- } else
- return ret;
-
- ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
- sizeof(*pioc), (void **)&pioc);
- *pobject = nv_object(pioc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nv50_disp_chan_impl
-nv50_disp_curs_ofuncs = {
- .base.ctor = nv50_disp_curs_ctor,
- .base.dtor = nv50_disp_pioc_dtor,
- .base.init = nv50_disp_pioc_init,
- .base.fini = nv50_disp_pioc_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 7,
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-int
-nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
-{
- const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
- const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
- const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
- union {
- struct nv04_disp_scanoutpos_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "disp scanoutpos size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
- args->v0.vblanke = (blanke & 0xffff0000) >> 16;
- args->v0.hblanke = (blanke & 0x0000ffff);
- args->v0.vblanks = (blanks & 0xffff0000) >> 16;
- args->v0.hblanks = (blanks & 0x0000ffff);
- args->v0.vtotal = ( total & 0xffff0000) >> 16;
- args->v0.htotal = ( total & 0x0000ffff);
- args->v0.time[0] = ktime_to_ns(ktime_get());
- args->v0.vline = /* vline read locks hline */
- nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
- args->v0.time[1] = ktime_to_ns(ktime_get());
- args->v0.hline =
- nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
- } else
- return ret;
-
- return 0;
-}
-
-int
-nv50_disp_main_mthd(struct nouveau_object *object, u32 mthd,
- void *data, u32 size)
-{
- const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
- union {
- struct nv50_disp_mthd_v0 v0;
- struct nv50_disp_mthd_v1 v1;
- } *args = data;
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nvkm_output *outp = NULL;
- struct nvkm_output *temp;
- u16 type, mask = 0;
- int head, ret;
-
- if (mthd != NV50_DISP_MTHD)
- return -EINVAL;
-
- nv_ioctl(object, "disp mthd size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
- args->v0.version, args->v0.method, args->v0.head);
- mthd = args->v0.method;
- head = args->v0.head;
- } else
- if (nvif_unpack(args->v1, 1, 1, true)) {
- nv_ioctl(object, "disp mthd vers %d mthd %02x "
- "type %04x mask %04x\n",
- args->v1.version, args->v1.method,
- args->v1.hasht, args->v1.hashm);
- mthd = args->v1.method;
- type = args->v1.hasht;
- mask = args->v1.hashm;
- head = ffs((mask >> 8) & 0x0f) - 1;
- } else
- return ret;
-
- if (head < 0 || head >= priv->head.nr)
- return -ENXIO;
-
- if (mask) {
- list_for_each_entry(temp, &priv->base.outp, head) {
- if ((temp->info.hasht == type) &&
- (temp->info.hashm & mask) == mask) {
- outp = temp;
- break;
- }
- }
- if (outp == NULL)
- return -ENXIO;
- }
-
- switch (mthd) {
- case NV50_DISP_SCANOUTPOS:
- return impl->head.scanoutpos(object, priv, data, size, head);
- default:
- break;
- }
-
- switch (mthd * !!outp) {
- case NV50_DISP_MTHD_V1_DAC_PWR:
- return priv->dac.power(object, priv, data, size, head, outp);
- case NV50_DISP_MTHD_V1_DAC_LOAD:
- return priv->dac.sense(object, priv, data, size, head, outp);
- case NV50_DISP_MTHD_V1_SOR_PWR:
- return priv->sor.power(object, priv, data, size, head, outp);
- case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
- if (!priv->sor.hda_eld)
- return -ENODEV;
- return priv->sor.hda_eld(object, priv, data, size, head, outp);
- case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
- if (!priv->sor.hdmi)
- return -ENODEV;
- return priv->sor.hdmi(object, priv, data, size, head, outp);
- case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
- union {
- struct nv50_disp_sor_lvds_script_v0 v0;
- } *args = data;
- nv_ioctl(object, "disp sor lvds script size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor lvds script "
- "vers %d name %04x\n",
- args->v0.version, args->v0.script);
- priv->sor.lvdsconf = args->v0.script;
- return 0;
- } else
- return ret;
- }
- break;
- case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
- struct nvkm_output_dp *outpdp = (void *)outp;
- union {
- struct nv50_disp_sor_dp_pwr_v0 v0;
- } *args = data;
- nv_ioctl(object, "disp sor dp pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
- args->v0.version, args->v0.state);
- if (args->v0.state == 0) {
- nvkm_notify_put(&outpdp->irq);
- ((struct nvkm_output_dp_impl *)nv_oclass(outp))
- ->lnk_pwr(outpdp, 0);
- atomic_set(&outpdp->lt.done, 0);
- return 0;
- } else
- if (args->v0.state != 0) {
- nvkm_output_dp_train(&outpdp->base, 0, true);
- return 0;
- }
- } else
- return ret;
- }
- break;
- case NV50_DISP_MTHD_V1_PIOR_PWR:
- if (!priv->pior.power)
- return -ENODEV;
- return priv->pior.power(object, priv, data, size, head, outp);
- default:
- break;
- }
-
- return -EINVAL;
-}
-
-int
-nv50_disp_main_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv = (void *)engine;
- struct nv50_disp_base *base;
- int ret;
-
- ret = nouveau_parent_create(parent, engine, oclass, 0,
- priv->sclass, 0, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- return nouveau_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
- &base->ramht);
-}
-
-void
-nv50_disp_main_dtor(struct nouveau_object *object)
-{
- struct nv50_disp_base *base = (void *)object;
- nouveau_ramht_ref(NULL, &base->ramht);
- nouveau_parent_destroy(&base->base);
-}
-
-static int
-nv50_disp_main_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
- int ret, i;
- u32 tmp;
-
- ret = nouveau_parent_init(&base->base);
- if (ret)
- return ret;
-
- /* The below segments of code copying values from one register to
- * another appear to inform EVO of the display capabilities or
- * something similar. NFI what the 0x614004 caps are for..
- */
- tmp = nv_rd32(priv, 0x614004);
- nv_wr32(priv, 0x610184, tmp);
-
- /* ... CRTC caps */
- for (i = 0; i < priv->head.nr; i++) {
- tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
- nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
- tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
- nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
- tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
- nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
- tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
- nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
- }
-
- /* ... DAC caps */
- for (i = 0; i < priv->dac.nr; i++) {
- tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
- nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
- }
-
- /* ... SOR caps */
- for (i = 0; i < priv->sor.nr; i++) {
- tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
- nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
- }
-
- /* ... PIOR caps */
- for (i = 0; i < priv->pior.nr; i++) {
- tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
- nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
- }
-
- /* steal display away from vbios, or something like that */
- if (nv_rd32(priv, 0x610024) & 0x00000100) {
- nv_wr32(priv, 0x610024, 0x00000100);
- nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
- nv_error(priv, "timeout acquiring display\n");
- return -EBUSY;
- }
- }
-
- /* point at display engine memory area (hash table, objects) */
- nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
-
- /* enable supervisor interrupts, disable everything else */
- nv_wr32(priv, 0x61002c, 0x00000370);
- nv_wr32(priv, 0x610028, 0x00000000);
- return 0;
-}
-
-static int
-nv50_disp_main_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
-
- /* disable all interrupts */
- nv_wr32(priv, 0x610024, 0x00000000);
- nv_wr32(priv, 0x610020, 0x00000000);
-
- return nouveau_parent_fini(&base->base, suspend);
-}
-
-struct nouveau_ofuncs
-nv50_disp_main_ofuncs = {
- .ctor = nv50_disp_main_ctor,
- .dtor = nv50_disp_main_dtor,
- .init = nv50_disp_main_init,
- .fini = nv50_disp_main_fini,
- .mthd = nv50_disp_main_mthd,
- .ntfy = nouveau_disp_ntfy,
-};
-
-static struct nouveau_oclass
-nv50_disp_main_oclass[] = {
- { NV50_DISP, &nv50_disp_main_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nv50_disp_sclass[] = {
- { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
- { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
- { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
- { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
- { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
- {}
-};
-
-/*******************************************************************************
- * Display context, tracks instmem allocation and prevents more than one
- * client using the display hardware at any time.
- ******************************************************************************/
-
-static int
-nv50_disp_data_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv = (void *)engine;
- struct nouveau_engctx *ectx;
- int ret = -EBUSY;
-
- /* no context needed for channel objects... */
- if (nv_mclass(parent) != NV_DEVICE) {
- atomic_inc(&parent->refcount);
- *pobject = parent;
- return 1;
- }
-
- /* allocate display hardware to client */
- mutex_lock(&nv_subdev(priv)->mutex);
- if (list_empty(&nv_engine(priv)->contexts)) {
- ret = nouveau_engctx_create(parent, engine, oclass, NULL,
- 0x10000, 0x10000,
- NVOBJ_FLAG_HEAP, &ectx);
- *pobject = nv_object(ectx);
- }
- mutex_unlock(&nv_subdev(priv)->mutex);
- return ret;
-}
-
-struct nouveau_oclass
-nv50_disp_cclass = {
- .handle = NV_ENGCTX(DISP, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_disp_data_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
- },
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
-{
- struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
- nv_mask(disp, 0x61002c, (4 << head), 0);
-}
-
-static void
-nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
-{
- struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
- nv_mask(disp, 0x61002c, (4 << head), (4 << head));
-}
-
-const struct nvkm_event_func
-nv50_disp_vblank_func = {
- .ctor = nouveau_disp_vblank_ctor,
- .init = nv50_disp_vblank_init,
- .fini = nv50_disp_vblank_fini,
-};
-
-static const struct nouveau_enum
-nv50_disp_intr_error_type[] = {
- { 3, "ILLEGAL_MTHD" },
- { 4, "INVALID_VALUE" },
- { 5, "INVALID_STATE" },
- { 7, "INVALID_HANDLE" },
- {}
-};
-
-static const struct nouveau_enum
-nv50_disp_intr_error_code[] = {
- { 0x00, "" },
- {}
-};
-
-static void
-nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
-{
- struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
- u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
- u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
- u32 code = (addr & 0x00ff0000) >> 16;
- u32 type = (addr & 0x00007000) >> 12;
- u32 mthd = (addr & 0x00000ffc);
- const struct nouveau_enum *ec, *et;
- char ecunk[6], etunk[6];
-
- et = nouveau_enum_find(nv50_disp_intr_error_type, type);
- if (!et)
- snprintf(etunk, sizeof(etunk), "UNK%02X", type);
-
- ec = nouveau_enum_find(nv50_disp_intr_error_code, code);
- if (!ec)
- snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
-
- nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
- et ? et->name : etunk, ec ? ec->name : ecunk,
- chid, mthd, data);
-
- if (chid == 0) {
- switch (mthd) {
- case 0x0080:
- nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
- impl->mthd.core);
- break;
- default:
- break;
- }
- } else
- if (chid <= 2) {
- switch (mthd) {
- case 0x0080:
- nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
- impl->mthd.base);
- break;
- default:
- break;
- }
- } else
- if (chid <= 4) {
- switch (mthd) {
- case 0x0080:
- nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
- impl->mthd.ovly);
- break;
- default:
- break;
- }
- }
-
- nv_wr32(priv, 0x610020, 0x00010000 << chid);
- nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
-}
-
-static struct nvkm_output *
-exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
- u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvkm_output *outp;
- u16 mask, type;
-
- if (or < 4) {
- type = DCB_OUTPUT_ANALOG;
- mask = 0;
- } else
- if (or < 8) {
- switch (ctrl & 0x00000f00) {
- case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
- case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
- case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
- case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
- case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
- case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
- default:
- nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
- return NULL;
- }
- or -= 4;
- } else {
- or = or - 8;
- type = 0x0010;
- mask = 0;
- switch (ctrl & 0x00000f00) {
- case 0x00000000: type |= priv->pior.type[or]; break;
- default:
- nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
- return NULL;
- }
- }
-
- mask = 0x00c0 & (mask << 6);
- mask |= 0x0001 << or;
- mask |= 0x0100 << head;
-
- list_for_each_entry(outp, &priv->base.outp, head) {
- if ((outp->info.hasht & 0xff) == type &&
- (outp->info.hashm & mask) == mask) {
- *data = nvbios_outp_match(bios, outp->info.hasht,
- outp->info.hashm,
- ver, hdr, cnt, len, info);
- if (!*data)
- return NULL;
- return outp;
- }
- }
-
- return NULL;
-}
-
-static struct nvkm_output *
-exec_script(struct nv50_disp_priv *priv, int head, int id)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvkm_output *outp;
- struct nvbios_outp info;
- u8 ver, hdr, cnt, len;
- u32 data, ctrl = 0;
- u32 reg;
- int i;
-
- /* DAC */
- for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
- ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
-
- /* SOR */
- if (!(ctrl & (1 << head))) {
- if (nv_device(priv)->chipset < 0x90 ||
- nv_device(priv)->chipset == 0x92 ||
- nv_device(priv)->chipset == 0xa0) {
- reg = 0x610b74;
- } else {
- reg = 0x610798;
- }
- for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
- ctrl = nv_rd32(priv, reg + (i * 8));
- i += 4;
- }
-
- /* PIOR */
- if (!(ctrl & (1 << head))) {
- for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
- ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
- i += 8;
- }
-
- if (!(ctrl & (1 << head)))
- return NULL;
- i--;
-
- outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
- if (outp) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[id],
- .outp = &outp->info,
- .crtc = head,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
-
- return outp;
-}
-
-static struct nvkm_output *
-exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvkm_output *outp;
- struct nvbios_outp info1;
- struct nvbios_ocfg info2;
- u8 ver, hdr, cnt, len;
- u32 data, ctrl = 0;
- u32 reg;
- int i;
-
- /* DAC */
- for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
- ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
-
- /* SOR */
- if (!(ctrl & (1 << head))) {
- if (nv_device(priv)->chipset < 0x90 ||
- nv_device(priv)->chipset == 0x92 ||
- nv_device(priv)->chipset == 0xa0) {
- reg = 0x610b70;
- } else {
- reg = 0x610794;
- }
- for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
- ctrl = nv_rd32(priv, reg + (i * 8));
- i += 4;
- }
-
- /* PIOR */
- if (!(ctrl & (1 << head))) {
- for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
- ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
- i += 8;
- }
-
- if (!(ctrl & (1 << head)))
- return NULL;
- i--;
-
- outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
- if (!outp)
- return NULL;
-
- if (outp->info.location == 0) {
- switch (outp->info.type) {
- case DCB_OUTPUT_TMDS:
- *conf = (ctrl & 0x00000f00) >> 8;
- if (pclk >= 165000)
- *conf |= 0x0100;
- break;
- case DCB_OUTPUT_LVDS:
- *conf = priv->sor.lvdsconf;
- break;
- case DCB_OUTPUT_DP:
- *conf = (ctrl & 0x00000f00) >> 8;
- break;
- case DCB_OUTPUT_ANALOG:
- default:
- *conf = 0x00ff;
- break;
- }
- } else {
- *conf = (ctrl & 0x00000f00) >> 8;
- pclk = pclk / 2;
- }
-
- data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
- if (data && id < 0xff) {
- data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
- if (data) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = data,
- .outp = &outp->info,
- .crtc = head,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
- }
-
- return outp;
-}
-
-static void
-nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
-{
- exec_script(priv, head, 1);
-}
-
-static void
-nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
-{
- struct nvkm_output *outp = exec_script(priv, head, 2);
-
- /* the binary driver does this outside of the supervisor handling
- * (after the third supervisor from a detach). we (currently?)
- * allow both detach/attach to happen in the same set of
- * supervisor interrupts, so it would make sense to execute this
- * (full power down?) script after all the detach phases of the
- * supervisor handling. like with training if needed from the
- * second supervisor, nvidia doesn't do this, so who knows if it's
- * entirely safe, but it does appear to work..
- *
- * without this script being run, on some configurations i've
- * seen, switching from DP to TMDS on a DP connector may result
- * in a blank screen (SOR_PWR off/on can restore it)
- */
- if (outp && outp->info.type == DCB_OUTPUT_DP) {
- struct nvkm_output_dp *outpdp = (void *)outp;
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = nouveau_bios(priv),
- .outp = &outp->info,
- .crtc = head,
- .offset = outpdp->info.script[4],
- .execute = 1,
- };
-
- nvbios_exec(&init);
- atomic_set(&outpdp->lt.done, 0);
- }
-}
-
-static void
-nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
-{
- struct nouveau_devinit *devinit = nouveau_devinit(priv);
- u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
- if (pclk)
- devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
-}
-
-static void
-nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
- struct dcb_output *outp, u32 pclk)
-{
- const int link = !(outp->sorconf.link & 1);
- const int or = ffs(outp->or) - 1;
- const u32 soff = ( or * 0x800);
- const u32 loff = (link * 0x080) + soff;
- const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
- const u32 symbol = 100000;
- const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
- const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
- const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
- u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
- u32 clksor = nv_rd32(priv, 0x614300 + soff);
- int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
- int TU, VTUi, VTUf, VTUa;
- u64 link_data_rate, link_ratio, unk;
- u32 best_diff = 64 * symbol;
- u32 link_nr, link_bw, bits;
- u64 value;
-
- link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
- link_nr = hweight32(dpctrl & 0x000f0000);
-
- /* symbols/hblank - algorithm taken from comments in tegra driver */
- value = vblanke + vactive - vblanks - 7;
- value = value * link_bw;
- do_div(value, pclk);
- value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
- nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
-
- /* symbols/vblank - algorithm taken from comments in tegra driver */
- value = vblanks - vblanke - 25;
- value = value * link_bw;
- do_div(value, pclk);
- value = value - ((36 / link_nr) + 3) - 1;
- nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
-
- /* watermark / activesym */
- if ((ctrl & 0xf0000) == 0x60000) bits = 30;
- else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
- else bits = 18;
-
- link_data_rate = (pclk * bits / 8) / link_nr;
-
- /* calculate ratio of packed data rate to link symbol rate */
- link_ratio = link_data_rate * symbol;
- do_div(link_ratio, link_bw);
-
- for (TU = 64; TU >= 32; TU--) {
- /* calculate average number of valid symbols in each TU */
- u32 tu_valid = link_ratio * TU;
- u32 calc, diff;
-
- /* find a hw representation for the fraction.. */
- VTUi = tu_valid / symbol;
- calc = VTUi * symbol;
- diff = tu_valid - calc;
- if (diff) {
- if (diff >= (symbol / 2)) {
- VTUf = symbol / (symbol - diff);
- if (symbol - (VTUf * diff))
- VTUf++;
-
- if (VTUf <= 15) {
- VTUa = 1;
- calc += symbol - (symbol / VTUf);
- } else {
- VTUa = 0;
- VTUf = 1;
- calc += symbol;
- }
- } else {
- VTUa = 0;
- VTUf = min((int)(symbol / diff), 15);
- calc += symbol / VTUf;
- }
-
- diff = calc - tu_valid;
- } else {
- /* no remainder, but the hw doesn't like the fractional
- * part to be zero. decrement the integer part and
- * have the fraction add a whole symbol back
- */
- VTUa = 0;
- VTUf = 1;
- VTUi--;
- }
-
- if (diff < best_diff) {
- best_diff = diff;
- bestTU = TU;
- bestVTUa = VTUa;
- bestVTUf = VTUf;
- bestVTUi = VTUi;
- if (diff == 0)
- break;
- }
- }
-
- if (!bestTU) {
- nv_error(priv, "unable to find suitable dp config\n");
- return;
- }
-
- /* XXX close to vbios numbers, but not right */
- unk = (symbol - link_ratio) * bestTU;
- unk *= link_ratio;
- do_div(unk, symbol);
- do_div(unk, symbol);
- unk += 6;
-
- nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
- nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
- bestVTUf << 16 |
- bestVTUi << 8 | unk);
-}
-
-static void
-nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
-{
- struct nvkm_output *outp;
- u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
- u32 hval, hreg = 0x614200 + (head * 0x800);
- u32 oval, oreg;
- u32 mask, conf;
-
- outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
- if (!outp)
- return;
-
- /* we allow both encoder attach and detach operations to occur
- * within a single supervisor (ie. modeset) sequence. the
- * encoder detach scripts quite often switch off power to the
- * lanes, which requires the link to be re-trained.
- *
- * this is not generally an issue as the sink "must" (heh)
- * signal an irq when it's lost sync so the driver can
- * re-train.
- *
- * however, on some boards, if one does not configure at least
- * the gpu side of the link *before* attaching, then various
- * things can go horribly wrong (PDISP disappearing from mmio,
- * third supervisor never happens, etc).
- *
- * the solution is simply to retrain here, if necessary. last
- * i checked, the binary driver userspace does not appear to
- * trigger this situation (it forces an UPDATE between steps).
- */
- if (outp->info.type == DCB_OUTPUT_DP) {
- u32 soff = (ffs(outp->info.or) - 1) * 0x08;
- u32 ctrl, datarate;
-
- if (outp->info.location == 0) {
- ctrl = nv_rd32(priv, 0x610794 + soff);
- soff = 1;
- } else {
- ctrl = nv_rd32(priv, 0x610b80 + soff);
- soff = 2;
- }
-
- switch ((ctrl & 0x000f0000) >> 16) {
- case 6: datarate = pclk * 30; break;
- case 5: datarate = pclk * 24; break;
- case 2:
- default:
- datarate = pclk * 18;
- break;
- }
-
- if (nvkm_output_dp_train(outp, datarate / soff, true))
- ERR("link not trained before attach\n");
- }
-
- exec_clkcmp(priv, head, 0, pclk, &conf);
-
- if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
- oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
- oval = 0x00000000;
- hval = 0x00000000;
- mask = 0xffffffff;
- } else
- if (!outp->info.location) {
- if (outp->info.type == DCB_OUTPUT_DP)
- nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
- oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
- oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
- hval = 0x00000000;
- mask = 0x00000707;
- } else {
- oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
- oval = 0x00000001;
- hval = 0x00000001;
- mask = 0x00000707;
- }
-
- nv_mask(priv, hreg, 0x0000000f, hval);
- nv_mask(priv, oreg, mask, oval);
-}
-
-/* If programming a TMDS output on a SOR that can also be configured for
- * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
- *
- * It looks like the VBIOS TMDS scripts make an attempt at this, however,
- * the VBIOS scripts on at least one board I have only switch it off on
- * link 0, causing a blank display if the output has previously been
- * programmed for DisplayPort.
- */
-static void
-nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv, struct dcb_output *outp)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- const int link = !(outp->sorconf.link & 1);
- const int or = ffs(outp->or) - 1;
- const u32 loff = (or * 0x800) + (link * 0x80);
- const u16 mask = (outp->sorconf.link << 6) | outp->or;
- struct dcb_output match;
- u8 ver, hdr;
-
- if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
- nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
-}
-
-static void
-nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
-{
- struct nvkm_output *outp;
- u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
- u32 conf;
-
- outp = exec_clkcmp(priv, head, 1, pclk, &conf);
- if (!outp)
- return;
-
- if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
- nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
-}
-
-void
-nv50_disp_intr_supervisor(struct work_struct *work)
-{
- struct nv50_disp_priv *priv =
- container_of(work, struct nv50_disp_priv, supervisor);
- struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
- u32 super = nv_rd32(priv, 0x610030);
- int head;
-
- nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
-
- if (priv->super & 0x00000010) {
- nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
- for (head = 0; head < priv->head.nr; head++) {
- if (!(super & (0x00000020 << head)))
- continue;
- if (!(super & (0x00000080 << head)))
- continue;
- nv50_disp_intr_unk10_0(priv, head);
- }
- } else
- if (priv->super & 0x00000020) {
- for (head = 0; head < priv->head.nr; head++) {
- if (!(super & (0x00000080 << head)))
- continue;
- nv50_disp_intr_unk20_0(priv, head);
- }
- for (head = 0; head < priv->head.nr; head++) {
- if (!(super & (0x00000200 << head)))
- continue;
- nv50_disp_intr_unk20_1(priv, head);
- }
- for (head = 0; head < priv->head.nr; head++) {
- if (!(super & (0x00000080 << head)))
- continue;
- nv50_disp_intr_unk20_2(priv, head);
- }
- } else
- if (priv->super & 0x00000040) {
- for (head = 0; head < priv->head.nr; head++) {
- if (!(super & (0x00000080 << head)))
- continue;
- nv50_disp_intr_unk40_0(priv, head);
- }
- }
-
- nv_wr32(priv, 0x610030, 0x80000000);
-}
-
-void
-nv50_disp_intr(struct nouveau_subdev *subdev)
-{
- struct nv50_disp_priv *priv = (void *)subdev;
- u32 intr0 = nv_rd32(priv, 0x610020);
- u32 intr1 = nv_rd32(priv, 0x610024);
-
- while (intr0 & 0x001f0000) {
- u32 chid = __ffs(intr0 & 0x001f0000) - 16;
- nv50_disp_intr_error(priv, chid);
- intr0 &= ~(0x00010000 << chid);
- }
-
- while (intr0 & 0x0000001f) {
- u32 chid = __ffs(intr0 & 0x0000001f);
- nv50_disp_chan_uevent_send(priv, chid);
- intr0 &= ~(0x00000001 << chid);
- }
-
- if (intr1 & 0x00000004) {
- nouveau_disp_vblank(&priv->base, 0);
- nv_wr32(priv, 0x610024, 0x00000004);
- intr1 &= ~0x00000004;
- }
-
- if (intr1 & 0x00000008) {
- nouveau_disp_vblank(&priv->base, 1);
- nv_wr32(priv, 0x610024, 0x00000008);
- intr1 &= ~0x00000008;
- }
-
- if (intr1 & 0x00000070) {
- priv->super = (intr1 & 0x00000070);
- schedule_work(&priv->supervisor);
- nv_wr32(priv, 0x610024, priv->super);
- intr1 &= ~0x00000070;
- }
-}
-
-static int
-nv50_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nv50_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
- priv->sclass = nv50_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 2;
- priv->pior.nr = 3;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->pior.power = nv50_pior_power;
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_disp_outp_sclass[] = {
- &nv50_pior_dp_impl.base.base,
- NULL
-};
-
-struct nouveau_oclass *
-nv50_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x50),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nv50_disp_vblank_func,
- .base.outp = nv50_disp_outp_sclass,
- .mthd.core = &nv50_disp_core_mthd_chan,
- .mthd.base = &nv50_disp_base_mthd_chan,
- .mthd.ovly = &nv50_disp_ovly_mthd_chan,
- .mthd.prev = 0x000004,
- .head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
deleted file mode 100644
index 7f08078ee925..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv50.h
+++ /dev/null
@@ -1,252 +0,0 @@
-#ifndef __NV50_DISP_H__
-#define __NV50_DISP_H__
-
-#include <core/parent.h>
-#include <core/namedb.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-#include <core/event.h>
-
-#include <engine/dmaobj.h>
-
-#include "dport.h"
-#include "priv.h"
-#include "outp.h"
-#include "outpdp.h"
-
-#define NV50_DISP_MTHD_ struct nouveau_object *object, \
- struct nv50_disp_priv *priv, void *data, u32 size
-#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
-#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
-
-struct nv50_disp_priv {
- struct nouveau_disp base;
- struct nouveau_oclass *sclass;
-
- struct work_struct supervisor;
- u32 super;
-
- struct nvkm_event uevent;
-
- struct {
- int nr;
- } head;
- struct {
- int nr;
- int (*power)(NV50_DISP_MTHD_V1);
- int (*sense)(NV50_DISP_MTHD_V1);
- } dac;
- struct {
- int nr;
- int (*power)(NV50_DISP_MTHD_V1);
- int (*hda_eld)(NV50_DISP_MTHD_V1);
- int (*hdmi)(NV50_DISP_MTHD_V1);
- u32 lvdsconf;
- void (*magic)(struct nvkm_output *);
- } sor;
- struct {
- int nr;
- int (*power)(NV50_DISP_MTHD_V1);
- u8 type[3];
- } pior;
-};
-
-struct nv50_disp_impl {
- struct nouveau_disp_impl base;
- struct {
- const struct nv50_disp_mthd_chan *core;
- const struct nv50_disp_mthd_chan *base;
- const struct nv50_disp_mthd_chan *ovly;
- int prev;
- } mthd;
- struct {
- int (*scanoutpos)(NV50_DISP_MTHD_V0);
- } head;
-};
-
-int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
-int nv50_disp_main_mthd(struct nouveau_object *, u32, void *, u32);
-
-int nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
-
-int nv50_dac_power(NV50_DISP_MTHD_V1);
-int nv50_dac_sense(NV50_DISP_MTHD_V1);
-
-int nva3_hda_eld(NV50_DISP_MTHD_V1);
-int nvd0_hda_eld(NV50_DISP_MTHD_V1);
-
-int nv84_hdmi_ctrl(NV50_DISP_MTHD_V1);
-int nva3_hdmi_ctrl(NV50_DISP_MTHD_V1);
-int nvd0_hdmi_ctrl(NV50_DISP_MTHD_V1);
-int nve0_hdmi_ctrl(NV50_DISP_MTHD_V1);
-
-int nv50_sor_power(NV50_DISP_MTHD_V1);
-
-int nv94_sor_dp_train_init(struct nv50_disp_priv *, int, int, int, u16, u16,
- u32, struct dcb_output *);
-int nv94_sor_dp_train_fini(struct nv50_disp_priv *, int, int, int, u16, u16,
- u32, struct dcb_output *);
-int nv94_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
- struct dcb_output *);
-int nv94_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-int nv94_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-
-int nvd0_sor_dp_train(struct nv50_disp_priv *, int, int, u16, u16, u32,
- struct dcb_output *);
-int nvd0_sor_dp_lnkctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-int nvd0_sor_dp_drvctl(struct nv50_disp_priv *, int, int, int, u16, u16, u32,
- struct dcb_output *);
-
-int nv50_pior_power(NV50_DISP_MTHD_V1);
-
-struct nv50_disp_base {
- struct nouveau_parent base;
- struct nouveau_ramht *ramht;
- u32 chan;
-};
-
-struct nv50_disp_chan_impl {
- struct nouveau_ofuncs base;
- int chid;
- int (*attach)(struct nouveau_object *, struct nouveau_object *, u32);
- void (*detach)(struct nouveau_object *, int);
-};
-
-struct nv50_disp_chan {
- struct nouveau_namedb base;
- int chid;
-};
-
-int nv50_disp_chan_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
-int nv50_disp_chan_map(struct nouveau_object *, u64 *, u32 *);
-u32 nv50_disp_chan_rd32(struct nouveau_object *, u64);
-void nv50_disp_chan_wr32(struct nouveau_object *, u64, u32);
-extern const struct nvkm_event_func nv50_disp_chan_uevent;
-int nv50_disp_chan_uevent_ctor(struct nouveau_object *, void *, u32,
- struct nvkm_notify *);
-void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
-
-extern const struct nvkm_event_func nvd0_disp_chan_uevent;
-
-#define nv50_disp_chan_init(a) \
- nouveau_namedb_init(&(a)->base)
-#define nv50_disp_chan_fini(a,b) \
- nouveau_namedb_fini(&(a)->base, (b))
-
-struct nv50_disp_dmac {
- struct nv50_disp_chan base;
- struct nouveau_dmaobj *pushdma;
- u32 push;
-};
-
-void nv50_disp_dmac_dtor(struct nouveau_object *);
-
-struct nv50_disp_pioc {
- struct nv50_disp_chan base;
-};
-
-void nv50_disp_pioc_dtor(struct nouveau_object *);
-
-struct nv50_disp_mthd_list {
- u32 mthd;
- u32 addr;
- struct {
- u32 mthd;
- u32 addr;
- const char *name;
- } data[];
-};
-
-struct nv50_disp_mthd_chan {
- const char *name;
- u32 addr;
- struct {
- const char *name;
- int nr;
- const struct nv50_disp_mthd_list *mthd;
- } data[];
-};
-
-extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs;
-int nv50_disp_core_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
-extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
-extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
-extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs;
-int nv50_disp_base_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
-extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
-int nv50_disp_ovly_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
-extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs;
-int nv50_disp_oimm_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
-int nv50_disp_curs_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-extern struct nouveau_ofuncs nv50_disp_main_ofuncs;
-int nv50_disp_main_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv50_disp_main_dtor(struct nouveau_object *);
-extern struct nouveau_omthds nv50_disp_main_omthds[];
-extern struct nouveau_oclass nv50_disp_cclass;
-void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
- const struct nv50_disp_mthd_chan *);
-void nv50_disp_intr_supervisor(struct work_struct *);
-void nv50_disp_intr(struct nouveau_subdev *);
-extern const struct nvkm_event_func nv50_disp_vblank_func;
-
-extern const struct nv50_disp_mthd_chan nv84_disp_core_mthd_chan;
-extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_dac;
-extern const struct nv50_disp_mthd_list nv84_disp_core_mthd_head;
-extern const struct nv50_disp_mthd_chan nv84_disp_base_mthd_chan;
-extern const struct nv50_disp_mthd_chan nv84_disp_ovly_mthd_chan;
-
-extern const struct nv50_disp_mthd_chan nv94_disp_core_mthd_chan;
-
-extern struct nv50_disp_chan_impl nvd0_disp_core_ofuncs;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_base;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_dac;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_sor;
-extern const struct nv50_disp_mthd_list nvd0_disp_core_mthd_pior;
-extern struct nv50_disp_chan_impl nvd0_disp_base_ofuncs;
-extern struct nv50_disp_chan_impl nvd0_disp_ovly_ofuncs;
-extern const struct nv50_disp_mthd_chan nvd0_disp_base_mthd_chan;
-extern struct nv50_disp_chan_impl nvd0_disp_oimm_ofuncs;
-extern struct nv50_disp_chan_impl nvd0_disp_curs_ofuncs;
-extern struct nouveau_ofuncs nvd0_disp_main_ofuncs;
-extern struct nouveau_oclass nvd0_disp_cclass;
-void nvd0_disp_intr_supervisor(struct work_struct *);
-void nvd0_disp_intr(struct nouveau_subdev *);
-extern const struct nvkm_event_func nvd0_disp_vblank_func;
-
-extern const struct nv50_disp_mthd_chan nve0_disp_core_mthd_chan;
-extern const struct nv50_disp_mthd_chan nve0_disp_ovly_mthd_chan;
-
-extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
-extern struct nouveau_oclass *nv50_disp_outp_sclass[];
-
-extern struct nvkm_output_dp_impl nv94_sor_dp_impl;
-int nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
-extern struct nouveau_oclass *nv94_disp_outp_sclass[];
-
-extern struct nvkm_output_dp_impl nvd0_sor_dp_impl;
-int nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
-extern struct nouveau_oclass *nvd0_disp_outp_sclass[];
-
-void gm204_sor_magic(struct nvkm_output *outp);
-extern struct nvkm_output_dp_impl gm204_sor_dp_impl;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
deleted file mode 100644
index 13eff5e4ee51..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv84.c
+++ /dev/null
@@ -1,276 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nv84_disp_core_mthd_dac = {
- .mthd = 0x0080,
- .addr = 0x000008,
- .data = {
- { 0x0400, 0x610b58 },
- { 0x0404, 0x610bdc },
- { 0x0420, 0x610bc4 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nv84_disp_core_mthd_head = {
- .mthd = 0x0400,
- .addr = 0x000540,
- .data = {
- { 0x0800, 0x610ad8 },
- { 0x0804, 0x610ad0 },
- { 0x0808, 0x610a48 },
- { 0x080c, 0x610a78 },
- { 0x0810, 0x610ac0 },
- { 0x0814, 0x610af8 },
- { 0x0818, 0x610b00 },
- { 0x081c, 0x610ae8 },
- { 0x0820, 0x610af0 },
- { 0x0824, 0x610b08 },
- { 0x0828, 0x610b10 },
- { 0x082c, 0x610a68 },
- { 0x0830, 0x610a60 },
- { 0x0834, 0x000000 },
- { 0x0838, 0x610a40 },
- { 0x0840, 0x610a24 },
- { 0x0844, 0x610a2c },
- { 0x0848, 0x610aa8 },
- { 0x084c, 0x610ab0 },
- { 0x085c, 0x610c5c },
- { 0x0860, 0x610a84 },
- { 0x0864, 0x610a90 },
- { 0x0868, 0x610b18 },
- { 0x086c, 0x610b20 },
- { 0x0870, 0x610ac8 },
- { 0x0874, 0x610a38 },
- { 0x0878, 0x610c50 },
- { 0x0880, 0x610a58 },
- { 0x0884, 0x610a9c },
- { 0x089c, 0x610c68 },
- { 0x08a0, 0x610a70 },
- { 0x08a4, 0x610a50 },
- { 0x08a8, 0x610ae0 },
- { 0x08c0, 0x610b28 },
- { 0x08c4, 0x610b30 },
- { 0x08c8, 0x610b40 },
- { 0x08d4, 0x610b38 },
- { 0x08d8, 0x610b48 },
- { 0x08dc, 0x610b50 },
- { 0x0900, 0x610a18 },
- { 0x0904, 0x610ab8 },
- { 0x0910, 0x610c70 },
- { 0x0914, 0x610c78 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nv84_disp_core_mthd_chan = {
- .name = "Core",
- .addr = 0x000000,
- .data = {
- { "Global", 1, &nv50_disp_core_mthd_base },
- { "DAC", 3, &nv84_disp_core_mthd_dac },
- { "SOR", 2, &nv50_disp_core_mthd_sor },
- { "PIOR", 3, &nv50_disp_core_mthd_pior },
- { "HEAD", 2, &nv84_disp_core_mthd_head },
- {}
- }
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nv84_disp_base_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x000000 },
- { 0x0084, 0x0008c4 },
- { 0x0088, 0x0008d0 },
- { 0x008c, 0x0008dc },
- { 0x0090, 0x0008e4 },
- { 0x0094, 0x610884 },
- { 0x00a0, 0x6108a0 },
- { 0x00a4, 0x610878 },
- { 0x00c0, 0x61086c },
- { 0x00c4, 0x610800 },
- { 0x00c8, 0x61080c },
- { 0x00cc, 0x610818 },
- { 0x00e0, 0x610858 },
- { 0x00e4, 0x610860 },
- { 0x00e8, 0x6108ac },
- { 0x00ec, 0x6108b4 },
- { 0x00fc, 0x610824 },
- { 0x0100, 0x610894 },
- { 0x0104, 0x61082c },
- { 0x0110, 0x6108bc },
- { 0x0114, 0x61088c },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nv84_disp_base_mthd_chan = {
- .name = "Base",
- .addr = 0x000540,
- .data = {
- { "Global", 1, &nv84_disp_base_mthd_base },
- { "Image", 2, &nv50_disp_base_mthd_image },
- {}
- }
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nv84_disp_ovly_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x000000 },
- { 0x0084, 0x6109a0 },
- { 0x0088, 0x6109c0 },
- { 0x008c, 0x6109c8 },
- { 0x0090, 0x6109b4 },
- { 0x0094, 0x610970 },
- { 0x00a0, 0x610998 },
- { 0x00a4, 0x610964 },
- { 0x00c0, 0x610958 },
- { 0x00e0, 0x6109a8 },
- { 0x00e4, 0x6109d0 },
- { 0x00e8, 0x6109d8 },
- { 0x0100, 0x61094c },
- { 0x0104, 0x610984 },
- { 0x0108, 0x61098c },
- { 0x0800, 0x6109f8 },
- { 0x0808, 0x610a08 },
- { 0x080c, 0x610a10 },
- { 0x0810, 0x610a00 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nv84_disp_ovly_mthd_chan = {
- .name = "Overlay",
- .addr = 0x000540,
- .data = {
- { "Global", 1, &nv84_disp_ovly_mthd_base },
- {}
- }
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_disp_sclass[] = {
- { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
- { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
- { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
- { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
- { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-nv84_disp_main_oclass[] = {
- { G82_DISP, &nv50_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nv84_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nv84_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
- priv->sclass = nv84_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 2;
- priv->pior.nr = 3;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hdmi = nv84_hdmi_ctrl;
- priv->pior.power = nv50_pior_power;
- return 0;
-}
-
-struct nouveau_oclass *
-nv84_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x82),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nv50_disp_vblank_func,
- .base.outp = nv50_disp_outp_sclass,
- .mthd.core = &nv84_disp_core_mthd_chan,
- .mthd.base = &nv84_disp_base_mthd_chan,
- .mthd.ovly = &nv84_disp_ovly_mthd_chan,
- .mthd.prev = 0x000004,
- .head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
deleted file mode 100644
index 2bb7ac5cd0e6..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nv94.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nv94_disp_core_mthd_sor = {
- .mthd = 0x0040,
- .addr = 0x000008,
- .data = {
- { 0x0600, 0x610794 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nv94_disp_core_mthd_chan = {
- .name = "Core",
- .addr = 0x000000,
- .data = {
- { "Global", 1, &nv50_disp_core_mthd_base },
- { "DAC", 3, &nv84_disp_core_mthd_dac },
- { "SOR", 4, &nv94_disp_core_mthd_sor },
- { "PIOR", 3, &nv50_disp_core_mthd_pior },
- { "HEAD", 2, &nv84_disp_core_mthd_head },
- {}
- }
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv94_disp_sclass[] = {
- { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
- { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
- { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
- { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
- { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-nv94_disp_main_oclass[] = {
- { GT206_DISP, &nv50_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nv94_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nv94_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
- priv->sclass = nv94_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->pior.nr = 3;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hdmi = nv84_hdmi_ctrl;
- priv->pior.power = nv50_pior_power;
- return 0;
-}
-
-struct nouveau_oclass *
-nv94_disp_outp_sclass[] = {
- &nv50_pior_dp_impl.base.base,
- &nv94_sor_dp_impl.base.base,
- NULL
-};
-
-struct nouveau_oclass *
-nv94_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x88),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv94_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nv50_disp_vblank_func,
- .base.outp = nv94_disp_outp_sclass,
- .mthd.core = &nv94_disp_core_mthd_chan,
- .mthd.base = &nv84_disp_base_mthd_chan,
- .mthd.ovly = &nv84_disp_ovly_mthd_chan,
- .mthd.prev = 0x000004,
- .head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
deleted file mode 100644
index b32456c9494f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva0.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nva0_disp_ovly_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x000000 },
- { 0x0084, 0x6109a0 },
- { 0x0088, 0x6109c0 },
- { 0x008c, 0x6109c8 },
- { 0x0090, 0x6109b4 },
- { 0x0094, 0x610970 },
- { 0x00a0, 0x610998 },
- { 0x00a4, 0x610964 },
- { 0x00b0, 0x610c98 },
- { 0x00b4, 0x610ca4 },
- { 0x00b8, 0x610cac },
- { 0x00c0, 0x610958 },
- { 0x00e0, 0x6109a8 },
- { 0x00e4, 0x6109d0 },
- { 0x00e8, 0x6109d8 },
- { 0x0100, 0x61094c },
- { 0x0104, 0x610984 },
- { 0x0108, 0x61098c },
- { 0x0800, 0x6109f8 },
- { 0x0808, 0x610a08 },
- { 0x080c, 0x610a10 },
- { 0x0810, 0x610a00 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_chan
-nva0_disp_ovly_mthd_chan = {
- .name = "Overlay",
- .addr = 0x000540,
- .data = {
- { "Global", 1, &nva0_disp_ovly_mthd_base },
- {}
- }
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva0_disp_sclass[] = {
- { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
- { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
- { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
- { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
- { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-nva0_disp_main_oclass[] = {
- { GT200_DISP, &nv50_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nva0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nva0_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
- priv->sclass = nva0_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 2;
- priv->pior.nr = 3;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hdmi = nv84_hdmi_ctrl;
- priv->pior.power = nv50_pior_power;
- return 0;
-}
-
-struct nouveau_oclass *
-nva0_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x83),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva0_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nv50_disp_vblank_func,
- .base.outp = nv50_disp_outp_sclass,
- .mthd.core = &nv84_disp_core_mthd_chan,
- .mthd.base = &nv84_disp_base_mthd_chan,
- .mthd.ovly = &nva0_disp_ovly_mthd_chan,
- .mthd.prev = 0x000004,
- .head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c b/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
deleted file mode 100644
index 951d79f9b781..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nva3.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nva3_disp_sclass[] = {
- { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
- { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
- { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
- { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
- { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-nva3_disp_main_oclass[] = {
- { GT214_DISP, &nv50_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nva3_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, 2, "PDISP",
- "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nva3_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nv50_disp_intr;
- INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
- priv->sclass = nva3_disp_sclass;
- priv->head.nr = 2;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->pior.nr = 3;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nva3_hda_eld;
- priv->sor.hdmi = nva3_hdmi_ctrl;
- priv->pior.power = nv50_pior_power;
- return 0;
-}
-
-struct nouveau_oclass *
-nva3_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x85),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nv50_disp_vblank_func,
- .base.outp = nv94_disp_outp_sclass,
- .mthd.core = &nv94_disp_core_mthd_chan,
- .mthd.base = &nv84_disp_base_mthd_chan,
- .mthd.ovly = &nv84_disp_ovly_mthd_chan,
- .mthd.prev = 0x000004,
- .head.scanoutpos = nv50_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
deleted file mode 100644
index 181a2d57e356..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvd0.c
+++ /dev/null
@@ -1,1313 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <core/parent.h>
-#include <core/handle.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <engine/disp.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/disp.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/pll.h>
-#include <subdev/devinit.h>
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO channel base class
- ******************************************************************************/
-
-static void
-nvd0_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
-{
- struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
- nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
- nv_wr32(priv, 0x61008c, 0x00000001 << index);
-}
-
-static void
-nvd0_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
-{
- struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
- nv_wr32(priv, 0x61008c, 0x00000001 << index);
- nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
-}
-
-const struct nvkm_event_func
-nvd0_disp_chan_uevent = {
- .ctor = nv50_disp_chan_uevent_ctor,
- .init = nvd0_disp_chan_uevent_init,
- .fini = nvd0_disp_chan_uevent_fini,
-};
-
-/*******************************************************************************
- * EVO DMA channel base class
- ******************************************************************************/
-
-static int
-nvd0_disp_dmac_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 name)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- struct nv50_disp_chan *chan = (void *)parent;
- u32 addr = nv_gpuobj(object)->node->offset;
- u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
- return nouveau_ramht_insert(base->ramht, chan->chid, name, data);
-}
-
-static void
-nvd0_disp_dmac_object_detach(struct nouveau_object *parent, int cookie)
-{
- struct nv50_disp_base *base = (void *)parent->parent;
- nouveau_ramht_remove(base->ramht, cookie);
-}
-
-static int
-nvd0_disp_dmac_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&dmac->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push);
- nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000);
- nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001);
- nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
- nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) {
- nv_error(dmac, "init: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nvd0_disp_dmac_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *dmac = (void *)object;
- int chid = dmac->base.chid;
-
- /* deactivate channel */
- nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
- nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) {
- nv_error(dmac, "fini: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting and completion notification */
- nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
-
- return nv50_disp_chan_fini(&dmac->base, suspend);
-}
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x660080 },
- { 0x0084, 0x660084 },
- { 0x0088, 0x660088 },
- { 0x008c, 0x000000 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_dac = {
- .mthd = 0x0020,
- .addr = 0x000020,
- .data = {
- { 0x0180, 0x660180 },
- { 0x0184, 0x660184 },
- { 0x0188, 0x660188 },
- { 0x0190, 0x660190 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_sor = {
- .mthd = 0x0020,
- .addr = 0x000020,
- .data = {
- { 0x0200, 0x660200 },
- { 0x0204, 0x660204 },
- { 0x0208, 0x660208 },
- { 0x0210, 0x660210 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_pior = {
- .mthd = 0x0020,
- .addr = 0x000020,
- .data = {
- { 0x0300, 0x660300 },
- { 0x0304, 0x660304 },
- { 0x0308, 0x660308 },
- { 0x0310, 0x660310 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_core_mthd_head = {
- .mthd = 0x0300,
- .addr = 0x000300,
- .data = {
- { 0x0400, 0x660400 },
- { 0x0404, 0x660404 },
- { 0x0408, 0x660408 },
- { 0x040c, 0x66040c },
- { 0x0410, 0x660410 },
- { 0x0414, 0x660414 },
- { 0x0418, 0x660418 },
- { 0x041c, 0x66041c },
- { 0x0420, 0x660420 },
- { 0x0424, 0x660424 },
- { 0x0428, 0x660428 },
- { 0x042c, 0x66042c },
- { 0x0430, 0x660430 },
- { 0x0434, 0x660434 },
- { 0x0438, 0x660438 },
- { 0x0440, 0x660440 },
- { 0x0444, 0x660444 },
- { 0x0448, 0x660448 },
- { 0x044c, 0x66044c },
- { 0x0450, 0x660450 },
- { 0x0454, 0x660454 },
- { 0x0458, 0x660458 },
- { 0x045c, 0x66045c },
- { 0x0460, 0x660460 },
- { 0x0468, 0x660468 },
- { 0x046c, 0x66046c },
- { 0x0470, 0x660470 },
- { 0x0474, 0x660474 },
- { 0x0480, 0x660480 },
- { 0x0484, 0x660484 },
- { 0x048c, 0x66048c },
- { 0x0490, 0x660490 },
- { 0x0494, 0x660494 },
- { 0x0498, 0x660498 },
- { 0x04b0, 0x6604b0 },
- { 0x04b8, 0x6604b8 },
- { 0x04bc, 0x6604bc },
- { 0x04c0, 0x6604c0 },
- { 0x04c4, 0x6604c4 },
- { 0x04c8, 0x6604c8 },
- { 0x04d0, 0x6604d0 },
- { 0x04d4, 0x6604d4 },
- { 0x04e0, 0x6604e0 },
- { 0x04e4, 0x6604e4 },
- { 0x04e8, 0x6604e8 },
- { 0x04ec, 0x6604ec },
- { 0x04f0, 0x6604f0 },
- { 0x04f4, 0x6604f4 },
- { 0x04f8, 0x6604f8 },
- { 0x04fc, 0x6604fc },
- { 0x0500, 0x660500 },
- { 0x0504, 0x660504 },
- { 0x0508, 0x660508 },
- { 0x050c, 0x66050c },
- { 0x0510, 0x660510 },
- { 0x0514, 0x660514 },
- { 0x0518, 0x660518 },
- { 0x051c, 0x66051c },
- { 0x052c, 0x66052c },
- { 0x0530, 0x660530 },
- { 0x054c, 0x66054c },
- { 0x0550, 0x660550 },
- { 0x0554, 0x660554 },
- { 0x0558, 0x660558 },
- { 0x055c, 0x66055c },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_chan
-nvd0_disp_core_mthd_chan = {
- .name = "Core",
- .addr = 0x000000,
- .data = {
- { "Global", 1, &nvd0_disp_core_mthd_base },
- { "DAC", 3, &nvd0_disp_core_mthd_dac },
- { "SOR", 8, &nvd0_disp_core_mthd_sor },
- { "PIOR", 4, &nvd0_disp_core_mthd_pior },
- { "HEAD", 4, &nvd0_disp_core_mthd_head },
- {}
- }
-};
-
-static int
-nvd0_disp_core_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
- int ret;
-
- ret = nv50_disp_chan_init(&mast->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
-
- /* initialise channel for dma command submission */
- nv_wr32(priv, 0x610494, mast->push);
- nv_wr32(priv, 0x610498, 0x00010000);
- nv_wr32(priv, 0x61049c, 0x00000001);
- nv_mask(priv, 0x610490, 0x00000010, 0x00000010);
- nv_wr32(priv, 0x640000, 0x00000000);
- nv_wr32(priv, 0x610490, 0x01000013);
-
- /* wait for it to go inactive */
- if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) {
- nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nvd0_disp_core_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_dmac *mast = (void *)object;
-
- /* deactivate channel */
- nv_mask(priv, 0x610490, 0x00000010, 0x00000000);
- nv_mask(priv, 0x610490, 0x00000003, 0x00000000);
- if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) {
- nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting and completion notification */
- nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
- nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
-
- return nv50_disp_chan_fini(&mast->base, suspend);
-}
-
-struct nv50_disp_chan_impl
-nvd0_disp_core_ofuncs = {
- .base.ctor = nv50_disp_core_ctor,
- .base.dtor = nv50_disp_dmac_dtor,
- .base.init = nvd0_disp_core_init,
- .base.fini = nvd0_disp_core_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 0,
- .attach = nvd0_disp_dmac_object_attach,
- .detach = nvd0_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO sync channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_base_mthd_base = {
- .mthd = 0x0000,
- .addr = 0x000000,
- .data = {
- { 0x0080, 0x661080 },
- { 0x0084, 0x661084 },
- { 0x0088, 0x661088 },
- { 0x008c, 0x66108c },
- { 0x0090, 0x661090 },
- { 0x0094, 0x661094 },
- { 0x00a0, 0x6610a0 },
- { 0x00a4, 0x6610a4 },
- { 0x00c0, 0x6610c0 },
- { 0x00c4, 0x6610c4 },
- { 0x00c8, 0x6610c8 },
- { 0x00cc, 0x6610cc },
- { 0x00e0, 0x6610e0 },
- { 0x00e4, 0x6610e4 },
- { 0x00e8, 0x6610e8 },
- { 0x00ec, 0x6610ec },
- { 0x00fc, 0x6610fc },
- { 0x0100, 0x661100 },
- { 0x0104, 0x661104 },
- { 0x0108, 0x661108 },
- { 0x010c, 0x66110c },
- { 0x0110, 0x661110 },
- { 0x0114, 0x661114 },
- { 0x0118, 0x661118 },
- { 0x011c, 0x66111c },
- { 0x0130, 0x661130 },
- { 0x0134, 0x661134 },
- { 0x0138, 0x661138 },
- { 0x013c, 0x66113c },
- { 0x0140, 0x661140 },
- { 0x0144, 0x661144 },
- { 0x0148, 0x661148 },
- { 0x014c, 0x66114c },
- { 0x0150, 0x661150 },
- { 0x0154, 0x661154 },
- { 0x0158, 0x661158 },
- { 0x015c, 0x66115c },
- { 0x0160, 0x661160 },
- { 0x0164, 0x661164 },
- { 0x0168, 0x661168 },
- { 0x016c, 0x66116c },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_base_mthd_image = {
- .mthd = 0x0400,
- .addr = 0x000400,
- .data = {
- { 0x0400, 0x661400 },
- { 0x0404, 0x661404 },
- { 0x0408, 0x661408 },
- { 0x040c, 0x66140c },
- { 0x0410, 0x661410 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nvd0_disp_base_mthd_chan = {
- .name = "Base",
- .addr = 0x001000,
- .data = {
- { "Global", 1, &nvd0_disp_base_mthd_base },
- { "Image", 2, &nvd0_disp_base_mthd_image },
- {}
- }
-};
-
-struct nv50_disp_chan_impl
-nvd0_disp_base_ofuncs = {
- .base.ctor = nv50_disp_base_ctor,
- .base.dtor = nv50_disp_dmac_dtor,
- .base.init = nvd0_disp_dmac_init,
- .base.fini = nvd0_disp_dmac_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 1,
- .attach = nvd0_disp_dmac_object_attach,
- .detach = nvd0_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nvd0_disp_ovly_mthd_base = {
- .mthd = 0x0000,
- .data = {
- { 0x0080, 0x665080 },
- { 0x0084, 0x665084 },
- { 0x0088, 0x665088 },
- { 0x008c, 0x66508c },
- { 0x0090, 0x665090 },
- { 0x0094, 0x665094 },
- { 0x00a0, 0x6650a0 },
- { 0x00a4, 0x6650a4 },
- { 0x00b0, 0x6650b0 },
- { 0x00b4, 0x6650b4 },
- { 0x00b8, 0x6650b8 },
- { 0x00c0, 0x6650c0 },
- { 0x00e0, 0x6650e0 },
- { 0x00e4, 0x6650e4 },
- { 0x00e8, 0x6650e8 },
- { 0x0100, 0x665100 },
- { 0x0104, 0x665104 },
- { 0x0108, 0x665108 },
- { 0x010c, 0x66510c },
- { 0x0110, 0x665110 },
- { 0x0118, 0x665118 },
- { 0x011c, 0x66511c },
- { 0x0120, 0x665120 },
- { 0x0124, 0x665124 },
- { 0x0130, 0x665130 },
- { 0x0134, 0x665134 },
- { 0x0138, 0x665138 },
- { 0x013c, 0x66513c },
- { 0x0140, 0x665140 },
- { 0x0144, 0x665144 },
- { 0x0148, 0x665148 },
- { 0x014c, 0x66514c },
- { 0x0150, 0x665150 },
- { 0x0154, 0x665154 },
- { 0x0158, 0x665158 },
- { 0x015c, 0x66515c },
- { 0x0160, 0x665160 },
- { 0x0164, 0x665164 },
- { 0x0168, 0x665168 },
- { 0x016c, 0x66516c },
- { 0x0400, 0x665400 },
- { 0x0408, 0x665408 },
- { 0x040c, 0x66540c },
- { 0x0410, 0x665410 },
- {}
- }
-};
-
-static const struct nv50_disp_mthd_chan
-nvd0_disp_ovly_mthd_chan = {
- .name = "Overlay",
- .addr = 0x001000,
- .data = {
- { "Global", 1, &nvd0_disp_ovly_mthd_base },
- {}
- }
-};
-
-struct nv50_disp_chan_impl
-nvd0_disp_ovly_ofuncs = {
- .base.ctor = nv50_disp_ovly_ctor,
- .base.dtor = nv50_disp_dmac_dtor,
- .base.init = nvd0_disp_dmac_init,
- .base.fini = nvd0_disp_dmac_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 5,
- .attach = nvd0_disp_dmac_object_attach,
- .detach = nvd0_disp_dmac_object_detach,
-};
-
-/*******************************************************************************
- * EVO PIO channel base class
- ******************************************************************************/
-
-static int
-nvd0_disp_pioc_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
- int ret;
-
- ret = nv50_disp_chan_init(&pioc->base);
- if (ret)
- return ret;
-
- /* enable error reporting */
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
-
- /* activate channel */
- nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001);
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) {
- nv_error(pioc, "init: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- return -EBUSY;
- }
-
- return 0;
-}
-
-static int
-nvd0_disp_pioc_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_pioc *pioc = (void *)object;
- int chid = pioc->base.chid;
-
- nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) {
- nv_error(pioc, "timeout: 0x%08x\n",
- nv_rd32(priv, 0x610490 + (chid * 0x10)));
- if (suspend)
- return -EBUSY;
- }
-
- /* disable error reporting and completion notification */
- nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
- nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
-
- return nv50_disp_chan_fini(&pioc->base, suspend);
-}
-
-/*******************************************************************************
- * EVO immediate overlay channel objects
- ******************************************************************************/
-
-struct nv50_disp_chan_impl
-nvd0_disp_oimm_ofuncs = {
- .base.ctor = nv50_disp_oimm_ctor,
- .base.dtor = nv50_disp_pioc_dtor,
- .base.init = nvd0_disp_pioc_init,
- .base.fini = nvd0_disp_pioc_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 9,
-};
-
-/*******************************************************************************
- * EVO cursor channel objects
- ******************************************************************************/
-
-struct nv50_disp_chan_impl
-nvd0_disp_curs_ofuncs = {
- .base.ctor = nv50_disp_curs_ctor,
- .base.dtor = nv50_disp_pioc_dtor,
- .base.init = nvd0_disp_pioc_init,
- .base.fini = nvd0_disp_pioc_fini,
- .base.ntfy = nv50_disp_chan_ntfy,
- .base.map = nv50_disp_chan_map,
- .base.rd32 = nv50_disp_chan_rd32,
- .base.wr32 = nv50_disp_chan_wr32,
- .chid = 13,
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-int
-nvd0_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
-{
- const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300));
- const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
- const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
- union {
- struct nv04_disp_scanoutpos_v0 v0;
- } *args = data;
- int ret;
-
- nv_ioctl(object, "disp scanoutpos size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
- args->v0.vblanke = (blanke & 0xffff0000) >> 16;
- args->v0.hblanke = (blanke & 0x0000ffff);
- args->v0.vblanks = (blanks & 0xffff0000) >> 16;
- args->v0.hblanks = (blanks & 0x0000ffff);
- args->v0.vtotal = ( total & 0xffff0000) >> 16;
- args->v0.htotal = ( total & 0x0000ffff);
- args->v0.time[0] = ktime_to_ns(ktime_get());
- args->v0.vline = /* vline read locks hline */
- nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
- args->v0.time[1] = ktime_to_ns(ktime_get());
- args->v0.hline =
- nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
- } else
- return ret;
-
- return 0;
-}
-
-static int
-nvd0_disp_main_init(struct nouveau_object *object)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
- int ret, i;
- u32 tmp;
-
- ret = nouveau_parent_init(&base->base);
- if (ret)
- return ret;
-
- /* The below segments of code copying values from one register to
- * another appear to inform EVO of the display capabilities or
- * something similar.
- */
-
- /* ... CRTC caps */
- for (i = 0; i < priv->head.nr; i++) {
- tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
- nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp);
- tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
- nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp);
- tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
- nv_wr32(priv, 0x6101bc + (i * 0x800), tmp);
- }
-
- /* ... DAC caps */
- for (i = 0; i < priv->dac.nr; i++) {
- tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
- nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp);
- }
-
- /* ... SOR caps */
- for (i = 0; i < priv->sor.nr; i++) {
- tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
- nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp);
- }
-
- /* steal display away from vbios, or something like that */
- if (nv_rd32(priv, 0x6100ac) & 0x00000100) {
- nv_wr32(priv, 0x6100ac, 0x00000100);
- nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
- if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
- nv_error(priv, "timeout acquiring display\n");
- return -EBUSY;
- }
- }
-
- /* point at display engine memory area (hash table, objects) */
- nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
-
- /* enable supervisor interrupts, disable everything else */
- nv_wr32(priv, 0x610090, 0x00000000);
- nv_wr32(priv, 0x6100a0, 0x00000000);
- nv_wr32(priv, 0x6100b0, 0x00000307);
-
- /* disable underflow reporting, preventing an intermittent issue
- * on some nve4 boards where the production vbios left this
- * setting enabled by default.
- *
- * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
- */
- for (i = 0; i < priv->head.nr; i++)
- nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010);
-
- return 0;
-}
-
-static int
-nvd0_disp_main_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_disp_priv *priv = (void *)object->engine;
- struct nv50_disp_base *base = (void *)object;
-
- /* disable all interrupts */
- nv_wr32(priv, 0x6100b0, 0x00000000);
-
- return nouveau_parent_fini(&base->base, suspend);
-}
-
-struct nouveau_ofuncs
-nvd0_disp_main_ofuncs = {
- .ctor = nv50_disp_main_ctor,
- .dtor = nv50_disp_main_dtor,
- .init = nvd0_disp_main_init,
- .fini = nvd0_disp_main_fini,
- .mthd = nv50_disp_main_mthd,
- .ntfy = nouveau_disp_ntfy,
-};
-
-static struct nouveau_oclass
-nvd0_disp_main_oclass[] = {
- { GF110_DISP, &nvd0_disp_main_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nvd0_disp_sclass[] = {
- { GF110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
- { GF110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
- { GF110_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
- { GF110_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
- { GF110_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static void
-nvd0_disp_vblank_init(struct nvkm_event *event, int type, int head)
-{
- struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
- nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
-}
-
-static void
-nvd0_disp_vblank_fini(struct nvkm_event *event, int type, int head)
-{
- struct nouveau_disp *disp = container_of(event, typeof(*disp), vblank);
- nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
-}
-
-const struct nvkm_event_func
-nvd0_disp_vblank_func = {
- .ctor = nouveau_disp_vblank_ctor,
- .init = nvd0_disp_vblank_init,
- .fini = nvd0_disp_vblank_fini,
-};
-
-static struct nvkm_output *
-exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
- u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvkm_output *outp;
- u16 mask, type;
-
- if (or < 4) {
- type = DCB_OUTPUT_ANALOG;
- mask = 0;
- } else {
- or -= 4;
- switch (ctrl & 0x00000f00) {
- case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
- case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
- case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
- case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
- case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
- case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
- default:
- nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
- return 0x0000;
- }
- }
-
- mask = 0x00c0 & (mask << 6);
- mask |= 0x0001 << or;
- mask |= 0x0100 << head;
-
- list_for_each_entry(outp, &priv->base.outp, head) {
- if ((outp->info.hasht & 0xff) == type &&
- (outp->info.hashm & mask) == mask) {
- *data = nvbios_outp_match(bios, outp->info.hasht,
- outp->info.hashm,
- ver, hdr, cnt, len, info);
- if (!*data)
- return NULL;
- return outp;
- }
- }
-
- return NULL;
-}
-
-static struct nvkm_output *
-exec_script(struct nv50_disp_priv *priv, int head, int id)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvkm_output *outp;
- struct nvbios_outp info;
- u8 ver, hdr, cnt, len;
- u32 data, ctrl = 0;
- int or;
-
- for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
- ctrl = nv_rd32(priv, 0x640180 + (or * 0x20));
- if (ctrl & (1 << head))
- break;
- }
-
- if (or == 8)
- return NULL;
-
- outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
- if (outp) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[id],
- .outp = &outp->info,
- .crtc = head,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
-
- return outp;
-}
-
-static struct nvkm_output *
-exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvkm_output *outp;
- struct nvbios_outp info1;
- struct nvbios_ocfg info2;
- u8 ver, hdr, cnt, len;
- u32 data, ctrl = 0;
- int or;
-
- for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
- ctrl = nv_rd32(priv, 0x660180 + (or * 0x20));
- if (ctrl & (1 << head))
- break;
- }
-
- if (or == 8)
- return NULL;
-
- outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
- if (!outp)
- return NULL;
-
- switch (outp->info.type) {
- case DCB_OUTPUT_TMDS:
- *conf = (ctrl & 0x00000f00) >> 8;
- if (pclk >= 165000)
- *conf |= 0x0100;
- break;
- case DCB_OUTPUT_LVDS:
- *conf = priv->sor.lvdsconf;
- break;
- case DCB_OUTPUT_DP:
- *conf = (ctrl & 0x00000f00) >> 8;
- break;
- case DCB_OUTPUT_ANALOG:
- default:
- *conf = 0x00ff;
- break;
- }
-
- data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
- if (data && id < 0xff) {
- data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
- if (data) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = data,
- .outp = &outp->info,
- .crtc = head,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
- }
-
- return outp;
-}
-
-static void
-nvd0_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
-{
- exec_script(priv, head, 1);
-}
-
-static void
-nvd0_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
-{
- struct nvkm_output *outp = exec_script(priv, head, 2);
-
- /* see note in nv50_disp_intr_unk20_0() */
- if (outp && outp->info.type == DCB_OUTPUT_DP) {
- struct nvkm_output_dp *outpdp = (void *)outp;
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = nouveau_bios(priv),
- .outp = &outp->info,
- .crtc = head,
- .offset = outpdp->info.script[4],
- .execute = 1,
- };
-
- nvbios_exec(&init);
- atomic_set(&outpdp->lt.done, 0);
- }
-}
-
-static void
-nvd0_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
-{
- struct nouveau_devinit *devinit = nouveau_devinit(priv);
- u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
- if (pclk)
- devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
- nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
-}
-
-static void
-nvd0_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
- struct dcb_output *outp)
-{
- const int or = ffs(outp->or) - 1;
- const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
- const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
- const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
- const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
- const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
- const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
- const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
- const u32 hoff = (head * 0x800);
- const u32 soff = ( or * 0x800);
- const u32 loff = (link * 0x080) + soff;
- const u32 symbol = 100000;
- const u32 TU = 64;
- u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
- u32 clksor = nv_rd32(priv, 0x612300 + soff);
- u32 datarate, link_nr, link_bw, bits;
- u64 ratio, value;
-
- link_nr = hweight32(dpctrl & 0x000f0000);
- link_bw = (clksor & 0x007c0000) >> 18;
- link_bw *= 27000;
-
- /* symbols/hblank - algorithm taken from comments in tegra driver */
- value = vblanke + vactive - vblanks - 7;
- value = value * link_bw;
- do_div(value, pclk);
- value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
- nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
-
- /* symbols/vblank - algorithm taken from comments in tegra driver */
- value = vblanks - vblanke - 25;
- value = value * link_bw;
- do_div(value, pclk);
- value = value - ((36 / link_nr) + 3) - 1;
- nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
-
- /* watermark */
- if ((conf & 0x3c0) == 0x180) bits = 30;
- else if ((conf & 0x3c0) == 0x140) bits = 24;
- else bits = 18;
- datarate = (pclk * bits) / 8;
-
- ratio = datarate;
- ratio *= symbol;
- do_div(ratio, link_nr * link_bw);
-
- value = (symbol - ratio) * TU;
- value *= ratio;
- do_div(value, symbol);
- do_div(value, symbol);
-
- value += 5;
- value |= 0x08000000;
-
- nv_wr32(priv, 0x616610 + hoff, value);
-}
-
-static void
-nvd0_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
-{
- struct nvkm_output *outp;
- u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
- u32 conf, addr, data;
-
- outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
- if (!outp)
- return;
-
- /* see note in nv50_disp_intr_unk20_2() */
- if (outp->info.type == DCB_OUTPUT_DP) {
- u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
- switch ((sync & 0x000003c0) >> 6) {
- case 6: pclk = pclk * 30; break;
- case 5: pclk = pclk * 24; break;
- case 2:
- default:
- pclk = pclk * 18;
- break;
- }
-
- if (nvkm_output_dp_train(outp, pclk, true))
- ERR("link not trained before attach\n");
- } else {
- if (priv->sor.magic)
- priv->sor.magic(outp);
- }
-
- exec_clkcmp(priv, head, 0, pclk, &conf);
-
- if (outp->info.type == DCB_OUTPUT_ANALOG) {
- addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
- data = 0x00000000;
- } else {
- addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
- data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
- switch (outp->info.type) {
- case DCB_OUTPUT_TMDS:
- nv_mask(priv, addr, 0x007c0000, 0x00280000);
- break;
- case DCB_OUTPUT_DP:
- nvd0_disp_intr_unk2_2_tu(priv, head, &outp->info);
- break;
- default:
- break;
- }
- }
-
- nv_mask(priv, addr, 0x00000707, data);
-}
-
-static void
-nvd0_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
-{
- u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
- u32 conf;
-
- exec_clkcmp(priv, head, 1, pclk, &conf);
-}
-
-void
-nvd0_disp_intr_supervisor(struct work_struct *work)
-{
- struct nv50_disp_priv *priv =
- container_of(work, struct nv50_disp_priv, supervisor);
- struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
- u32 mask[4];
- int head;
-
- nv_debug(priv, "supervisor %d\n", ffs(priv->super));
- for (head = 0; head < priv->head.nr; head++) {
- mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800));
- nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]);
- }
-
- if (priv->super & 0x00000001) {
- nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
- for (head = 0; head < priv->head.nr; head++) {
- if (!(mask[head] & 0x00001000))
- continue;
- nv_debug(priv, "supervisor 1.0 - head %d\n", head);
- nvd0_disp_intr_unk1_0(priv, head);
- }
- } else
- if (priv->super & 0x00000002) {
- for (head = 0; head < priv->head.nr; head++) {
- if (!(mask[head] & 0x00001000))
- continue;
- nv_debug(priv, "supervisor 2.0 - head %d\n", head);
- nvd0_disp_intr_unk2_0(priv, head);
- }
- for (head = 0; head < priv->head.nr; head++) {
- if (!(mask[head] & 0x00010000))
- continue;
- nv_debug(priv, "supervisor 2.1 - head %d\n", head);
- nvd0_disp_intr_unk2_1(priv, head);
- }
- for (head = 0; head < priv->head.nr; head++) {
- if (!(mask[head] & 0x00001000))
- continue;
- nv_debug(priv, "supervisor 2.2 - head %d\n", head);
- nvd0_disp_intr_unk2_2(priv, head);
- }
- } else
- if (priv->super & 0x00000004) {
- for (head = 0; head < priv->head.nr; head++) {
- if (!(mask[head] & 0x00001000))
- continue;
- nv_debug(priv, "supervisor 3.0 - head %d\n", head);
- nvd0_disp_intr_unk4_0(priv, head);
- }
- }
-
- for (head = 0; head < priv->head.nr; head++)
- nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000);
- nv_wr32(priv, 0x6101d0, 0x80000000);
-}
-
-static void
-nvd0_disp_intr_error(struct nv50_disp_priv *priv, int chid)
-{
- const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
- u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
- u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
- u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
-
- nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
- "0x%08x 0x%08x\n",
- chid, (mthd & 0x0000ffc), data, mthd, unkn);
-
- if (chid == 0) {
- switch (mthd & 0xffc) {
- case 0x0080:
- nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
- impl->mthd.core);
- break;
- default:
- break;
- }
- } else
- if (chid <= 4) {
- switch (mthd & 0xffc) {
- case 0x0080:
- nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
- impl->mthd.base);
- break;
- default:
- break;
- }
- } else
- if (chid <= 8) {
- switch (mthd & 0xffc) {
- case 0x0080:
- nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
- impl->mthd.ovly);
- break;
- default:
- break;
- }
- }
-
- nv_wr32(priv, 0x61009c, (1 << chid));
- nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
-}
-
-void
-nvd0_disp_intr(struct nouveau_subdev *subdev)
-{
- struct nv50_disp_priv *priv = (void *)subdev;
- u32 intr = nv_rd32(priv, 0x610088);
- int i;
-
- if (intr & 0x00000001) {
- u32 stat = nv_rd32(priv, 0x61008c);
- while (stat) {
- int chid = __ffs(stat); stat &= ~(1 << chid);
- nv50_disp_chan_uevent_send(priv, chid);
- nv_wr32(priv, 0x61008c, 1 << chid);
- }
- intr &= ~0x00000001;
- }
-
- if (intr & 0x00000002) {
- u32 stat = nv_rd32(priv, 0x61009c);
- int chid = ffs(stat) - 1;
- if (chid >= 0)
- nvd0_disp_intr_error(priv, chid);
- intr &= ~0x00000002;
- }
-
- if (intr & 0x00100000) {
- u32 stat = nv_rd32(priv, 0x6100ac);
- if (stat & 0x00000007) {
- priv->super = (stat & 0x00000007);
- schedule_work(&priv->supervisor);
- nv_wr32(priv, 0x6100ac, priv->super);
- stat &= ~0x00000007;
- }
-
- if (stat) {
- nv_info(priv, "unknown intr24 0x%08x\n", stat);
- nv_wr32(priv, 0x6100ac, stat);
- }
-
- intr &= ~0x00100000;
- }
-
- for (i = 0; i < priv->head.nr; i++) {
- u32 mask = 0x01000000 << i;
- if (mask & intr) {
- u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
- if (stat & 0x00000001)
- nouveau_disp_vblank(&priv->base, i);
- nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
- nv_rd32(priv, 0x6100c0 + (i * 0x800));
- }
- }
-}
-
-static int
-nvd0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int heads = nv_rd32(parent, 0x022448);
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, heads,
- "PDISP", "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nvd0_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nvd0_disp_intr;
- INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
- priv->sclass = nvd0_disp_sclass;
- priv->head.nr = heads;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nvd0_hdmi_ctrl;
- return 0;
-}
-
-struct nouveau_oclass *
-nvd0_disp_outp_sclass[] = {
- &nvd0_sor_dp_impl.base.base,
- NULL
-};
-
-struct nouveau_oclass *
-nvd0_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x90),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvd0_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nvd0_disp_vblank_func,
- .base.outp = nvd0_disp_outp_sclass,
- .mthd.core = &nvd0_disp_core_mthd_chan,
- .mthd.base = &nvd0_disp_base_mthd_chan,
- .mthd.ovly = &nvd0_disp_ovly_mthd_chan,
- .mthd.prev = -0x020000,
- .head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
deleted file mode 100644
index 55debec7e68f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nve0.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * EVO master channel object
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nve0_disp_core_mthd_head = {
- .mthd = 0x0300,
- .addr = 0x000300,
- .data = {
- { 0x0400, 0x660400 },
- { 0x0404, 0x660404 },
- { 0x0408, 0x660408 },
- { 0x040c, 0x66040c },
- { 0x0410, 0x660410 },
- { 0x0414, 0x660414 },
- { 0x0418, 0x660418 },
- { 0x041c, 0x66041c },
- { 0x0420, 0x660420 },
- { 0x0424, 0x660424 },
- { 0x0428, 0x660428 },
- { 0x042c, 0x66042c },
- { 0x0430, 0x660430 },
- { 0x0434, 0x660434 },
- { 0x0438, 0x660438 },
- { 0x0440, 0x660440 },
- { 0x0444, 0x660444 },
- { 0x0448, 0x660448 },
- { 0x044c, 0x66044c },
- { 0x0450, 0x660450 },
- { 0x0454, 0x660454 },
- { 0x0458, 0x660458 },
- { 0x045c, 0x66045c },
- { 0x0460, 0x660460 },
- { 0x0468, 0x660468 },
- { 0x046c, 0x66046c },
- { 0x0470, 0x660470 },
- { 0x0474, 0x660474 },
- { 0x047c, 0x66047c },
- { 0x0480, 0x660480 },
- { 0x0484, 0x660484 },
- { 0x0488, 0x660488 },
- { 0x048c, 0x66048c },
- { 0x0490, 0x660490 },
- { 0x0494, 0x660494 },
- { 0x0498, 0x660498 },
- { 0x04a0, 0x6604a0 },
- { 0x04b0, 0x6604b0 },
- { 0x04b8, 0x6604b8 },
- { 0x04bc, 0x6604bc },
- { 0x04c0, 0x6604c0 },
- { 0x04c4, 0x6604c4 },
- { 0x04c8, 0x6604c8 },
- { 0x04d0, 0x6604d0 },
- { 0x04d4, 0x6604d4 },
- { 0x04e0, 0x6604e0 },
- { 0x04e4, 0x6604e4 },
- { 0x04e8, 0x6604e8 },
- { 0x04ec, 0x6604ec },
- { 0x04f0, 0x6604f0 },
- { 0x04f4, 0x6604f4 },
- { 0x04f8, 0x6604f8 },
- { 0x04fc, 0x6604fc },
- { 0x0500, 0x660500 },
- { 0x0504, 0x660504 },
- { 0x0508, 0x660508 },
- { 0x050c, 0x66050c },
- { 0x0510, 0x660510 },
- { 0x0514, 0x660514 },
- { 0x0518, 0x660518 },
- { 0x051c, 0x66051c },
- { 0x0520, 0x660520 },
- { 0x0524, 0x660524 },
- { 0x052c, 0x66052c },
- { 0x0530, 0x660530 },
- { 0x054c, 0x66054c },
- { 0x0550, 0x660550 },
- { 0x0554, 0x660554 },
- { 0x0558, 0x660558 },
- { 0x055c, 0x66055c },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nve0_disp_core_mthd_chan = {
- .name = "Core",
- .addr = 0x000000,
- .data = {
- { "Global", 1, &nvd0_disp_core_mthd_base },
- { "DAC", 3, &nvd0_disp_core_mthd_dac },
- { "SOR", 8, &nvd0_disp_core_mthd_sor },
- { "PIOR", 4, &nvd0_disp_core_mthd_pior },
- { "HEAD", 4, &nve0_disp_core_mthd_head },
- {}
- }
-};
-
-/*******************************************************************************
- * EVO overlay channel objects
- ******************************************************************************/
-
-static const struct nv50_disp_mthd_list
-nve0_disp_ovly_mthd_base = {
- .mthd = 0x0000,
- .data = {
- { 0x0080, 0x665080 },
- { 0x0084, 0x665084 },
- { 0x0088, 0x665088 },
- { 0x008c, 0x66508c },
- { 0x0090, 0x665090 },
- { 0x0094, 0x665094 },
- { 0x00a0, 0x6650a0 },
- { 0x00a4, 0x6650a4 },
- { 0x00b0, 0x6650b0 },
- { 0x00b4, 0x6650b4 },
- { 0x00b8, 0x6650b8 },
- { 0x00c0, 0x6650c0 },
- { 0x00c4, 0x6650c4 },
- { 0x00e0, 0x6650e0 },
- { 0x00e4, 0x6650e4 },
- { 0x00e8, 0x6650e8 },
- { 0x0100, 0x665100 },
- { 0x0104, 0x665104 },
- { 0x0108, 0x665108 },
- { 0x010c, 0x66510c },
- { 0x0110, 0x665110 },
- { 0x0118, 0x665118 },
- { 0x011c, 0x66511c },
- { 0x0120, 0x665120 },
- { 0x0124, 0x665124 },
- { 0x0130, 0x665130 },
- { 0x0134, 0x665134 },
- { 0x0138, 0x665138 },
- { 0x013c, 0x66513c },
- { 0x0140, 0x665140 },
- { 0x0144, 0x665144 },
- { 0x0148, 0x665148 },
- { 0x014c, 0x66514c },
- { 0x0150, 0x665150 },
- { 0x0154, 0x665154 },
- { 0x0158, 0x665158 },
- { 0x015c, 0x66515c },
- { 0x0160, 0x665160 },
- { 0x0164, 0x665164 },
- { 0x0168, 0x665168 },
- { 0x016c, 0x66516c },
- { 0x0400, 0x665400 },
- { 0x0404, 0x665404 },
- { 0x0408, 0x665408 },
- { 0x040c, 0x66540c },
- { 0x0410, 0x665410 },
- {}
- }
-};
-
-const struct nv50_disp_mthd_chan
-nve0_disp_ovly_mthd_chan = {
- .name = "Overlay",
- .addr = 0x001000,
- .data = {
- { "Global", 1, &nve0_disp_ovly_mthd_base },
- {}
- }
-};
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_disp_sclass[] = {
- { GK104_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
- { GK104_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
- { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
- { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
- { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-nve0_disp_main_oclass[] = {
- { GK104_DISP, &nvd0_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nve0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int heads = nv_rd32(parent, 0x022448);
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, heads,
- "PDISP", "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nve0_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nvd0_disp_intr;
- INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
- priv->sclass = nve0_disp_sclass;
- priv->head.nr = heads;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nve0_hdmi_ctrl;
- return 0;
-}
-
-struct nouveau_oclass *
-nve0_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x91),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nvd0_disp_vblank_func,
- .base.outp = nvd0_disp_outp_sclass,
- .mthd.core = &nve0_disp_core_mthd_chan,
- .mthd.base = &nvd0_disp_base_mthd_chan,
- .mthd.ovly = &nve0_disp_ovly_mthd_chan,
- .mthd.prev = -0x020000,
- .head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
deleted file mode 100644
index 3e7e2d28744c..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/nvf0.c
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include <nvif/class.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * Base display object
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvf0_disp_sclass[] = {
- { GK110_DISP_CORE_CHANNEL_DMA, &nvd0_disp_core_ofuncs.base },
- { GK110_DISP_BASE_CHANNEL_DMA, &nvd0_disp_base_ofuncs.base },
- { GK104_DISP_OVERLAY_CONTROL_DMA, &nvd0_disp_ovly_ofuncs.base },
- { GK104_DISP_OVERLAY, &nvd0_disp_oimm_ofuncs.base },
- { GK104_DISP_CURSOR, &nvd0_disp_curs_ofuncs.base },
- {}
-};
-
-static struct nouveau_oclass
-nvf0_disp_main_oclass[] = {
- { GK110_DISP, &nvd0_disp_main_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * Display engine implementation
- ******************************************************************************/
-
-static int
-nvf0_disp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_disp_priv *priv;
- int heads = nv_rd32(parent, 0x022448);
- int ret;
-
- ret = nouveau_disp_create(parent, engine, oclass, heads,
- "PDISP", "display", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nvd0_disp_chan_uevent, 1, 17, &priv->uevent);
- if (ret)
- return ret;
-
- nv_engine(priv)->sclass = nvf0_disp_main_oclass;
- nv_engine(priv)->cclass = &nv50_disp_cclass;
- nv_subdev(priv)->intr = nvd0_disp_intr;
- INIT_WORK(&priv->supervisor, nvd0_disp_intr_supervisor);
- priv->sclass = nvf0_disp_sclass;
- priv->head.nr = heads;
- priv->dac.nr = 3;
- priv->sor.nr = 4;
- priv->dac.power = nv50_dac_power;
- priv->dac.sense = nv50_dac_sense;
- priv->sor.power = nv50_sor_power;
- priv->sor.hda_eld = nvd0_hda_eld;
- priv->sor.hdmi = nve0_hdmi_ctrl;
- return 0;
-}
-
-struct nouveau_oclass *
-nvf0_disp_oclass = &(struct nv50_disp_impl) {
- .base.base.handle = NV_ENGINE(DISP, 0x92),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvf0_disp_ctor,
- .dtor = _nouveau_disp_dtor,
- .init = _nouveau_disp_init,
- .fini = _nouveau_disp_fini,
- },
- .base.vblank = &nvd0_disp_vblank_func,
- .base.outp = nvd0_disp_outp_sclass,
- .mthd.core = &nve0_disp_core_mthd_chan,
- .mthd.base = &nvd0_disp_base_mthd_chan,
- .mthd.ovly = &nve0_disp_ovly_mthd_chan,
- .mthd.prev = -0x020000,
- .head.scanoutpos = nvd0_disp_main_scanoutpos,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
deleted file mode 100644
index bbd9b6fdc90f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outp.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/i2c.h>
-#include <subdev/bios.h>
-#include <subdev/bios/conn.h>
-
-#include "outp.h"
-
-int
-_nvkm_output_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvkm_output *outp = (void *)object;
- nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
- return nouveau_object_fini(&outp->base, suspend);
-}
-
-int
-_nvkm_output_init(struct nouveau_object *object)
-{
- struct nvkm_output *outp = (void *)object;
- int ret = nouveau_object_init(&outp->base);
- if (ret == 0)
- nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
- return 0;
-}
-
-void
-_nvkm_output_dtor(struct nouveau_object *object)
-{
- struct nvkm_output *outp = (void *)object;
- list_del(&outp->head);
- nouveau_object_ref(NULL, (void *)&outp->conn);
- nouveau_object_destroy(&outp->base);
-}
-
-int
-nvkm_output_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- struct dcb_output *dcbE, int index,
- int length, void **pobject)
-{
- struct nouveau_bios *bios = nouveau_bios(engine);
- struct nouveau_i2c *i2c = nouveau_i2c(parent);
- struct nouveau_disp *disp = (void *)engine;
- struct nvbios_connE connE;
- struct nvkm_output *outp;
- u8 ver, hdr;
- u32 data;
- int ret;
-
- ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
- outp = *pobject;
- if (ret)
- return ret;
-
- outp->info = *dcbE;
- outp->index = index;
- outp->or = ffs(outp->info.or) - 1;
-
- DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
- dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
- dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
- dcbE->bus, dcbE->heads);
-
- if (outp->info.type != DCB_OUTPUT_DP)
- outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index));
- else
- outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index));
- outp->edid = outp->port;
-
- data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
- if (!data) {
- DBG("vbios connector data not found\n");
- memset(&connE, 0x00, sizeof(connE));
- connE.type = DCB_CONNECTOR_NONE;
- }
-
- ret = nouveau_object_ctor(parent, engine, nvkm_connector_oclass,
- &connE, outp->info.connector,
- (struct nouveau_object **)&outp->conn);
- if (ret < 0) {
- ERR("error %d creating connector, disabling\n", ret);
- return ret;
- }
-
- list_add_tail(&outp->head, &disp->outp);
- return 0;
-}
-
-int
-_nvkm_output_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *dcbE, u32 index,
- struct nouveau_object **pobject)
-{
- struct nvkm_output *outp;
- int ret;
-
- ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
- *pobject = nv_object(outp);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-nvkm_output_oclass = &(struct nvkm_output_impl) {
- .base = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_output_ctor,
- .dtor = _nvkm_output_dtor,
- .init = _nvkm_output_init,
- .fini = _nvkm_output_fini,
- },
- },
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
deleted file mode 100644
index 187f435ad0e2..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outp.h
+++ /dev/null
@@ -1,60 +0,0 @@
-#ifndef __NVKM_DISP_OUTP_H__
-#define __NVKM_DISP_OUTP_H__
-
-#include "priv.h"
-
-struct nvkm_output {
- struct nouveau_object base;
- struct list_head head;
-
- struct dcb_output info;
- int index;
- int or;
-
- struct nouveau_i2c_port *port;
- struct nouveau_i2c_port *edid;
-
- struct nvkm_connector *conn;
-};
-
-#define nvkm_output_create(p,e,c,b,i,d) \
- nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_output_destroy(d) ({ \
- struct nvkm_output *_outp = (d); \
- _nvkm_output_dtor(nv_object(_outp)); \
-})
-#define nvkm_output_init(d) ({ \
- struct nvkm_output *_outp = (d); \
- _nvkm_output_init(nv_object(_outp)); \
-})
-#define nvkm_output_fini(d,s) ({ \
- struct nvkm_output *_outp = (d); \
- _nvkm_output_fini(nv_object(_outp), (s)); \
-})
-
-int nvkm_output_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, struct dcb_output *,
- int, int, void **);
-
-int _nvkm_output_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void _nvkm_output_dtor(struct nouveau_object *);
-int _nvkm_output_init(struct nouveau_object *);
-int _nvkm_output_fini(struct nouveau_object *, bool);
-
-struct nvkm_output_impl {
- struct nouveau_oclass base;
-};
-
-#ifndef MSG
-#define MSG(l,f,a...) do { \
- struct nvkm_output *_outp = (void *)outp; \
- nv_##l(nv_object(outp)->engine, "%02x:%04x:%04x: "f, _outp->index, \
- _outp->info.hasht, _outp->info.hashm, ##a); \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
deleted file mode 100644
index 667a9070e006..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <nvif/event.h>
-
-#include <subdev/i2c.h>
-
-#include "outpdp.h"
-#include "conn.h"
-#include "dport.h"
-
-int
-nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
-{
- struct nvkm_output_dp *outp = (void *)base;
- bool retrain = true;
- u8 link[2], stat[3];
- u32 linkrate;
- int ret, i;
-
- /* check that the link is trained at a high enough rate */
- ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2);
- if (ret) {
- DBG("failed to read link config, assuming no sink\n");
- goto done;
- }
-
- linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
- linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */
- datarate = (datarate + 9) / 10; /* -> decakilobits */
- if (linkrate < datarate) {
- DBG("link not trained at sufficient rate\n");
- goto done;
- }
-
- /* check that link is still trained */
- ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3);
- if (ret) {
- DBG("failed to read link status, assuming no sink\n");
- goto done;
- }
-
- if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
- for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
- u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
- if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
- !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
- !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
- DBG("lane %d not equalised\n", lane);
- goto done;
- }
- }
- retrain = false;
- } else {
- DBG("no inter-lane alignment\n");
- }
-
-done:
- if (retrain || !atomic_read(&outp->lt.done)) {
- /* no sink, but still need to configure source */
- if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
- outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
- outp->base.info.dpconf.link_bw;
- outp->dpcd[DPCD_RC02] =
- outp->base.info.dpconf.link_nr;
- }
- atomic_set(&outp->lt.done, 0);
- schedule_work(&outp->lt.work);
- } else {
- nvkm_notify_get(&outp->irq);
- }
-
- if (wait) {
- if (!wait_event_timeout(outp->lt.wait,
- atomic_read(&outp->lt.done),
- msecs_to_jiffies(2000)))
- ret = -ETIMEDOUT;
- }
-
- return ret;
-}
-
-static void
-nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
-{
- struct nouveau_i2c_port *port = outp->base.edid;
- if (present) {
- if (!outp->present) {
- nouveau_i2c(port)->acquire_pad(port, 0);
- DBG("aux power -> always\n");
- outp->present = true;
- }
- nvkm_output_dp_train(&outp->base, 0, true);
- } else {
- if (outp->present) {
- nouveau_i2c(port)->release_pad(port);
- DBG("aux power -> demand\n");
- outp->present = false;
- }
- atomic_set(&outp->lt.done, 0);
- }
-}
-
-static void
-nvkm_output_dp_detect(struct nvkm_output_dp *outp)
-{
- struct nouveau_i2c_port *port = outp->base.edid;
- int ret = nouveau_i2c(port)->acquire_pad(port, 0);
- if (ret == 0) {
- ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
- outp->dpcd, sizeof(outp->dpcd));
- nvkm_output_dp_enable(outp, ret == 0);
- nouveau_i2c(port)->release_pad(port);
- }
-}
-
-static int
-nvkm_output_dp_hpd(struct nvkm_notify *notify)
-{
- struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
- struct nvkm_output_dp *outp;
- struct nouveau_disp *disp = nouveau_disp(conn);
- const struct nvkm_i2c_ntfy_rep *line = notify->data;
- struct nvif_notify_conn_rep_v0 rep = {};
-
- list_for_each_entry(outp, &disp->outp, base.head) {
- if (outp->base.conn == conn &&
- outp->info.type == DCB_OUTPUT_DP) {
- DBG("HPD: %d\n", line->mask);
- nvkm_output_dp_detect(outp);
-
- if (line->mask & NVKM_I2C_UNPLUG)
- rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
- if (line->mask & NVKM_I2C_PLUG)
- rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
-
- nvkm_event_send(&disp->hpd, rep.mask, conn->index,
- &rep, sizeof(rep));
- return NVKM_NOTIFY_KEEP;
- }
- }
-
- WARN_ON(1);
- return NVKM_NOTIFY_DROP;
-}
-
-static int
-nvkm_output_dp_irq(struct nvkm_notify *notify)
-{
- struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
- struct nouveau_disp *disp = nouveau_disp(outp);
- const struct nvkm_i2c_ntfy_rep *line = notify->data;
- struct nvif_notify_conn_rep_v0 rep = {
- .mask = NVIF_NOTIFY_CONN_V0_IRQ,
- };
- int index = outp->base.info.connector;
-
- DBG("IRQ: %d\n", line->mask);
- nvkm_output_dp_train(&outp->base, 0, true);
-
- nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
- return NVKM_NOTIFY_DROP;
-}
-
-int
-_nvkm_output_dp_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvkm_output_dp *outp = (void *)object;
- nvkm_notify_put(&outp->irq);
- nvkm_output_dp_enable(outp, false);
- return nvkm_output_fini(&outp->base, suspend);
-}
-
-int
-_nvkm_output_dp_init(struct nouveau_object *object)
-{
- struct nvkm_output_dp *outp = (void *)object;
- nvkm_output_dp_detect(outp);
- return nvkm_output_init(&outp->base);
-}
-
-void
-_nvkm_output_dp_dtor(struct nouveau_object *object)
-{
- struct nvkm_output_dp *outp = (void *)object;
- nvkm_notify_fini(&outp->irq);
- nvkm_output_destroy(&outp->base);
-}
-
-int
-nvkm_output_dp_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- struct dcb_output *info, int index,
- int length, void **pobject)
-{
- struct nouveau_bios *bios = nouveau_bios(parent);
- struct nouveau_i2c *i2c = nouveau_i2c(parent);
- struct nvkm_output_dp *outp;
- u8 hdr, cnt, len;
- u32 data;
- int ret;
-
- ret = nvkm_output_create_(parent, engine, oclass, info, index,
- length, pobject);
- outp = *pobject;
- if (ret)
- return ret;
-
- nvkm_notify_fini(&outp->base.conn->hpd);
-
- /* access to the aux channel is not optional... */
- if (!outp->base.edid) {
- ERR("aux channel not found\n");
- return -ENODEV;
- }
-
- /* nor is the bios data for this output... */
- data = nvbios_dpout_match(bios, outp->base.info.hasht,
- outp->base.info.hashm, &outp->version,
- &hdr, &cnt, &len, &outp->info);
- if (!data) {
- ERR("no bios dp data\n");
- return -ENODEV;
- }
-
- DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
-
- /* link training */
- INIT_WORK(&outp->lt.work, nouveau_dp_train);
- init_waitqueue_head(&outp->lt.wait);
- atomic_set(&outp->lt.done, 0);
-
- /* link maintenance */
- ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
- &(struct nvkm_i2c_ntfy_req) {
- .mask = NVKM_I2C_IRQ,
- .port = outp->base.edid->index,
- },
- sizeof(struct nvkm_i2c_ntfy_req),
- sizeof(struct nvkm_i2c_ntfy_rep),
- &outp->irq);
- if (ret) {
- ERR("error monitoring aux irq event: %d\n", ret);
- return ret;
- }
-
- /* hotplug detect, replaces gpio-based mechanism with aux events */
- ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
- &(struct nvkm_i2c_ntfy_req) {
- .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
- .port = outp->base.edid->index,
- },
- sizeof(struct nvkm_i2c_ntfy_req),
- sizeof(struct nvkm_i2c_ntfy_rep),
- &outp->base.conn->hpd);
- if (ret) {
- ERR("error monitoring aux hpd events: %d\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-int
-_nvkm_output_dp_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *info, u32 index,
- struct nouveau_object **pobject)
-{
- struct nvkm_output_dp *outp;
- int ret;
-
- ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
- *pobject = nv_object(outp);
- if (ret)
- return ret;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
deleted file mode 100644
index 1fac367cc867..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/outpdp.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NVKM_DISP_OUTP_DP_H__
-#define __NVKM_DISP_OUTP_DP_H__
-
-#include <subdev/bios.h>
-#include <subdev/bios/dp.h>
-
-#include "outp.h"
-
-struct nvkm_output_dp {
- struct nvkm_output base;
-
- struct nvbios_dpout info;
- u8 version;
-
- struct nvkm_notify irq;
- bool present;
- u8 dpcd[16];
-
- struct {
- struct work_struct work;
- wait_queue_head_t wait;
- atomic_t done;
- } lt;
-};
-
-#define nvkm_output_dp_create(p,e,c,b,i,d) \
- nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
-#define nvkm_output_dp_destroy(d) ({ \
- struct nvkm_output_dp *_outp = (d); \
- _nvkm_output_dp_dtor(nv_object(_outp)); \
-})
-#define nvkm_output_dp_init(d) ({ \
- struct nvkm_output_dp *_outp = (d); \
- _nvkm_output_dp_init(nv_object(_outp)); \
-})
-#define nvkm_output_dp_fini(d,s) ({ \
- struct nvkm_output_dp *_outp = (d); \
- _nvkm_output_dp_fini(nv_object(_outp), (s)); \
-})
-
-int nvkm_output_dp_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, struct dcb_output *,
- int, int, void **);
-
-int _nvkm_output_dp_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void _nvkm_output_dp_dtor(struct nouveau_object *);
-int _nvkm_output_dp_init(struct nouveau_object *);
-int _nvkm_output_dp_fini(struct nouveau_object *, bool);
-
-struct nvkm_output_dp_impl {
- struct nvkm_output_impl base;
- int (*pattern)(struct nvkm_output_dp *, int);
- int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
- int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
- int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
-};
-
-int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
deleted file mode 100644
index d00f89a468a7..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/piornv50.c
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/timer.h>
-#include <subdev/i2c.h>
-
-#include "nv50.h"
-
-/******************************************************************************
- * TMDS
- *****************************************************************************/
-
-static int
-nv50_pior_tmds_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *info, u32 index,
- struct nouveau_object **pobject)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(parent);
- struct nvkm_output *outp;
- int ret;
-
- ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
- *pobject = nv_object(outp);
- if (ret)
- return ret;
-
- outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
- return 0;
-}
-
-struct nvkm_output_impl
-nv50_pior_tmds_impl = {
- .base.handle = DCB_OUTPUT_TMDS | 0x0100,
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_pior_tmds_ctor,
- .dtor = _nvkm_output_dtor,
- .init = _nvkm_output_init,
- .fini = _nvkm_output_fini,
- },
-};
-
-/******************************************************************************
- * DisplayPort
- *****************************************************************************/
-
-static int
-nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
- struct nouveau_i2c_port *port = outp->base.edid;
- if (port && port->func->pattern)
- return port->func->pattern(port, pattern);
- return port ? 0 : -ENODEV;
-}
-
-static int
-nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
-{
- return 0;
-}
-
-static int
-nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
- struct nouveau_i2c_port *port = outp->base.edid;
- if (port && port->func->lnk_ctl)
- return port->func->lnk_ctl(port, nr, bw, ef);
- return port ? 0 : -ENODEV;
-}
-
-static int
-nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
- struct nouveau_i2c_port *port = outp->base.edid;
- if (port && port->func->drv_ctl)
- return port->func->drv_ctl(port, ln, vs, pe);
- return port ? 0 : -ENODEV;
-}
-
-static int
-nv50_pior_dp_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *info, u32 index,
- struct nouveau_object **pobject)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(parent);
- struct nvkm_output_dp *outp;
- int ret;
-
- ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
- *pobject = nv_object(outp);
- if (ret)
- return ret;
-
- outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
- outp->base.info.extdev));
- return 0;
-}
-
-struct nvkm_output_dp_impl
-nv50_pior_dp_impl = {
- .base.base.handle = DCB_OUTPUT_DP | 0x0010,
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_pior_dp_ctor,
- .dtor = _nvkm_output_dp_dtor,
- .init = _nvkm_output_dp_init,
- .fini = _nvkm_output_dp_fini,
- },
- .pattern = nv50_pior_dp_pattern,
- .lnk_pwr = nv50_pior_dp_lnk_pwr,
- .lnk_ctl = nv50_pior_dp_lnk_ctl,
- .drv_ctl = nv50_pior_dp_drv_ctl,
-};
-
-/******************************************************************************
- * General PIOR handling
- *****************************************************************************/
-
-int
-nv50_pior_power(NV50_DISP_MTHD_V1)
-{
- const u32 soff = outp->or * 0x800;
- union {
- struct nv50_disp_pior_pwr_v0 v0;
- } *args = data;
- u32 ctrl, type;
- int ret;
-
- nv_ioctl(object, "disp pior pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
- args->v0.version, args->v0.state, args->v0.type);
- if (args->v0.type > 0x0f)
- return -EINVAL;
- ctrl = !!args->v0.state;
- type = args->v0.type;
- } else
- return ret;
-
- nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
- nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
- nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
- priv->pior.type[outp->or] = type;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h b/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
deleted file mode 100644
index 6a0511d54ce6..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/priv.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVKM_DISP_PRIV_H__
-#define __NVKM_DISP_PRIV_H__
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/conn.h>
-
-#include <engine/disp.h>
-
-struct nouveau_disp_impl {
- struct nouveau_oclass base;
- struct nouveau_oclass **outp;
- struct nouveau_oclass **conn;
- const struct nvkm_event_func *vblank;
-};
-
-#define nouveau_disp_create(p,e,c,h,i,x,d) \
- nouveau_disp_create_((p), (e), (c), (h), (i), (x), \
- sizeof(**d), (void **)d)
-#define nouveau_disp_destroy(d) ({ \
- struct nouveau_disp *disp = (d); \
- _nouveau_disp_dtor(nv_object(disp)); \
-})
-#define nouveau_disp_init(d) ({ \
- struct nouveau_disp *disp = (d); \
- _nouveau_disp_init(nv_object(disp)); \
-})
-#define nouveau_disp_fini(d,s) ({ \
- struct nouveau_disp *disp = (d); \
- _nouveau_disp_fini(nv_object(disp), (s)); \
-})
-
-int nouveau_disp_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int heads,
- const char *, const char *, int, void **);
-void _nouveau_disp_dtor(struct nouveau_object *);
-int _nouveau_disp_init(struct nouveau_object *);
-int _nouveau_disp_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass *nvkm_output_oclass;
-extern struct nouveau_oclass *nvkm_connector_oclass;
-
-int nouveau_disp_vblank_ctor(struct nouveau_object *, void *data, u32 size,
- struct nvkm_notify *);
-void nouveau_disp_vblank(struct nouveau_disp *, int head);
-int nouveau_disp_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c
deleted file mode 100644
index 0b4fad39e9a6..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sorgm204.c
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-static inline u32
-gm204_sor_soff(struct nvkm_output_dp *outp)
-{
- return (ffs(outp->base.info.or) - 1) * 0x800;
-}
-
-static inline u32
-gm204_sor_loff(struct nvkm_output_dp *outp)
-{
- return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
-}
-
-void
-gm204_sor_magic(struct nvkm_output *outp)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 soff = outp->or * 0x100;
- const u32 data = outp->or + 1;
- if (outp->info.sorconf.link & 1)
- nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
- if (outp->info.sorconf.link & 2)
- nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
-}
-
-static inline u32
-gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
- return lane * 0x08;
-}
-
-static int
-gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 soff = gm204_sor_soff(outp);
- const u32 data = 0x01010101 * pattern;
- if (outp->base.info.sorconf.link & 1)
- nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data);
- else
- nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data);
- return 0;
-}
-
-static int
-gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 soff = gm204_sor_soff(outp);
- const u32 loff = gm204_sor_loff(outp);
- u32 mask = 0, i;
-
- for (i = 0; i < nr; i++)
- mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3);
-
- nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
- nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
- nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
- return 0;
-}
-
-static int
-gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 shift = gm204_sor_dp_lane_map(priv, ln);
- const u32 loff = gm204_sor_loff(outp);
- u32 addr, data[4];
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout info;
- struct nvbios_dpcfg ocfg;
-
- addr = nvbios_dpout_match(bios, outp->base.info.hasht,
- outp->base.info.hashm,
- &ver, &hdr, &cnt, &len, &info);
- if (!addr)
- return -ENODEV;
-
- addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
- &ver, &hdr, &cnt, &len, &ocfg);
- if (!addr)
- return -EINVAL;
-
- data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
- data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
- data[2] = nv_rd32(priv, 0x61c130 + loff);
- if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
- data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
- nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
- nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
- nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
- data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
- nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
- return 0;
-}
-
-struct nvkm_output_dp_impl
-gm204_sor_dp_impl = {
- .base.base.handle = DCB_OUTPUT_DP,
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_output_dp_ctor,
- .dtor = _nvkm_output_dp_dtor,
- .init = _nvkm_output_dp_init,
- .fini = _nvkm_output_dp_fini,
- },
- .pattern = gm204_sor_dp_pattern,
- .lnk_pwr = gm204_sor_dp_lnk_pwr,
- .lnk_ctl = nvd0_sor_dp_lnk_ctl,
- .drv_ctl = gm204_sor_dp_drv_ctl,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
deleted file mode 100644
index ddf1760c4400..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv50.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-int
-nv50_sor_power(NV50_DISP_MTHD_V1)
-{
- union {
- struct nv50_disp_sor_pwr_v0 v0;
- } *args = data;
- const u32 soff = outp->or * 0x800;
- u32 stat;
- int ret;
-
- nv_ioctl(object, "disp sor pwr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "disp sor pwr vers %d state %d\n",
- args->v0.version, args->v0.state);
- stat = !!args->v0.state;
- } else
- return ret;
-
- nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
- nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
- nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
- nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
deleted file mode 100644
index 39f85d627336..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornv94.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-#include "outpdp.h"
-
-static inline u32
-nv94_sor_soff(struct nvkm_output_dp *outp)
-{
- return (ffs(outp->base.info.or) - 1) * 0x800;
-}
-
-static inline u32
-nv94_sor_loff(struct nvkm_output_dp *outp)
-{
- return nv94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
-}
-
-static inline u32
-nv94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
- static const u8 nvaf[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
- static const u8 nv94[] = { 16, 8, 0, 24 };
- if (nv_device(priv)->chipset == 0xaf)
- return nvaf[lane];
- return nv94[lane];
-}
-
-static int
-nv94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 loff = nv94_sor_loff(outp);
- nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
- return 0;
-}
-
-int
-nv94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 soff = nv94_sor_soff(outp);
- const u32 loff = nv94_sor_loff(outp);
- u32 mask = 0, i;
-
- for (i = 0; i < nr; i++)
- mask |= 1 << (nv94_sor_dp_lane_map(priv, i) >> 3);
-
- nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
- nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
- nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
- return 0;
-}
-
-static int
-nv94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 soff = nv94_sor_soff(outp);
- const u32 loff = nv94_sor_loff(outp);
- u32 dpctrl = 0x00000000;
- u32 clksor = 0x00000000;
-
- dpctrl |= ((1 << nr) - 1) << 16;
- if (ef)
- dpctrl |= 0x00004000;
- if (bw > 0x06)
- clksor |= 0x00040000;
-
- nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
- nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
- return 0;
-}
-
-static int
-nv94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 shift = nv94_sor_dp_lane_map(priv, ln);
- const u32 loff = nv94_sor_loff(outp);
- u32 addr, data[3];
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout info;
- struct nvbios_dpcfg ocfg;
-
- addr = nvbios_dpout_match(bios, outp->base.info.hasht,
- outp->base.info.hashm,
- &ver, &hdr, &cnt, &len, &info);
- if (!addr)
- return -ENODEV;
-
- addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
- &ver, &hdr, &cnt, &len, &ocfg);
- if (!addr)
- return -EINVAL;
-
- data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
- data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
- data[2] = nv_rd32(priv, 0x61c130 + loff);
- if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
- data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
- nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
- nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
- nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
- return 0;
-}
-
-struct nvkm_output_dp_impl
-nv94_sor_dp_impl = {
- .base.base.handle = DCB_OUTPUT_DP,
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_output_dp_ctor,
- .dtor = _nvkm_output_dp_dtor,
- .init = _nvkm_output_dp_init,
- .fini = _nvkm_output_dp_fini,
- },
- .pattern = nv94_sor_dp_pattern,
- .lnk_pwr = nv94_sor_dp_lnk_pwr,
- .lnk_ctl = nv94_sor_dp_lnk_ctl,
- .drv_ctl = nv94_sor_dp_drv_ctl,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c b/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
deleted file mode 100644
index fdab2939070c..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/sornvd0.c
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/init.h>
-#include <subdev/timer.h>
-
-#include "nv50.h"
-
-static inline u32
-nvd0_sor_soff(struct nvkm_output_dp *outp)
-{
- return (ffs(outp->base.info.or) - 1) * 0x800;
-}
-
-static inline u32
-nvd0_sor_loff(struct nvkm_output_dp *outp)
-{
- return nvd0_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
-}
-
-static inline u32
-nvd0_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
-{
- static const u8 nvd0[] = { 16, 8, 0, 24 };
- return nvd0[lane];
-}
-
-static int
-nvd0_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 loff = nvd0_sor_loff(outp);
- nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
- return 0;
-}
-
-int
-nvd0_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- const u32 soff = nvd0_sor_soff(outp);
- const u32 loff = nvd0_sor_loff(outp);
- u32 dpctrl = 0x00000000;
- u32 clksor = 0x00000000;
-
- clksor |= bw << 18;
- dpctrl |= ((1 << nr) - 1) << 16;
- if (ef)
- dpctrl |= 0x00004000;
-
- nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
- nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
- return 0;
-}
-
-static int
-nvd0_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
-{
- struct nv50_disp_priv *priv = (void *)nouveau_disp(outp);
- struct nouveau_bios *bios = nouveau_bios(priv);
- const u32 shift = nvd0_sor_dp_lane_map(priv, ln);
- const u32 loff = nvd0_sor_loff(outp);
- u32 addr, data[4];
- u8 ver, hdr, cnt, len;
- struct nvbios_dpout info;
- struct nvbios_dpcfg ocfg;
-
- addr = nvbios_dpout_match(bios, outp->base.info.hasht,
- outp->base.info.hashm,
- &ver, &hdr, &cnt, &len, &info);
- if (!addr)
- return -ENODEV;
-
- addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
- &ver, &hdr, &cnt, &len, &ocfg);
- if (!addr)
- return -EINVAL;
-
- data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
- data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
- data[2] = nv_rd32(priv, 0x61c130 + loff);
- if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
- data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
- nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
- nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
- nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
- data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
- nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
- return 0;
-}
-
-struct nvkm_output_dp_impl
-nvd0_sor_dp_impl = {
- .base.base.handle = DCB_OUTPUT_DP,
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_output_dp_ctor,
- .dtor = _nvkm_output_dp_dtor,
- .init = _nvkm_output_dp_init,
- .fini = _nvkm_output_dp_fini,
- },
- .pattern = nvd0_sor_dp_pattern,
- .lnk_pwr = nv94_sor_dp_lnk_pwr,
- .lnk_ctl = nvd0_sor_dp_lnk_ctl,
- .drv_ctl = nvd0_sor_dp_drv_ctl,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c b/drivers/gpu/drm/nouveau/core/engine/disp/vga.c
deleted file mode 100644
index 8836c3cb99c3..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/disp/vga.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <subdev/vga.h>
-
-u8
-nv_rdport(void *obj, int head, u16 port)
-{
- struct nouveau_device *device = nv_device(obj);
-
- if (device->card_type >= NV_50)
- return nv_rd08(obj, 0x601000 + port);
-
- if (port == 0x03c0 || port == 0x03c1 || /* AR */
- port == 0x03c2 || port == 0x03da || /* INP0 */
- port == 0x03d4 || port == 0x03d5) /* CR */
- return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
-
- if (port == 0x03c2 || port == 0x03cc || /* MISC */
- port == 0x03c4 || port == 0x03c5 || /* SR */
- port == 0x03ce || port == 0x03cf) { /* GR */
- if (device->card_type < NV_40)
- head = 0; /* CR44 selects head */
- return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
- }
-
- nv_error(obj, "unknown vga port 0x%04x\n", port);
- return 0x00;
-}
-
-void
-nv_wrport(void *obj, int head, u16 port, u8 data)
-{
- struct nouveau_device *device = nv_device(obj);
-
- if (device->card_type >= NV_50)
- nv_wr08(obj, 0x601000 + port, data);
- else
- if (port == 0x03c0 || port == 0x03c1 || /* AR */
- port == 0x03c2 || port == 0x03da || /* INP0 */
- port == 0x03d4 || port == 0x03d5) /* CR */
- nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
- else
- if (port == 0x03c2 || port == 0x03cc || /* MISC */
- port == 0x03c4 || port == 0x03c5 || /* SR */
- port == 0x03ce || port == 0x03cf) { /* GR */
- if (device->card_type < NV_40)
- head = 0; /* CR44 selects head */
- nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
- } else
- nv_error(obj, "unknown vga port 0x%04x\n", port);
-}
-
-u8
-nv_rdvgas(void *obj, int head, u8 index)
-{
- nv_wrport(obj, head, 0x03c4, index);
- return nv_rdport(obj, head, 0x03c5);
-}
-
-void
-nv_wrvgas(void *obj, int head, u8 index, u8 value)
-{
- nv_wrport(obj, head, 0x03c4, index);
- nv_wrport(obj, head, 0x03c5, value);
-}
-
-u8
-nv_rdvgag(void *obj, int head, u8 index)
-{
- nv_wrport(obj, head, 0x03ce, index);
- return nv_rdport(obj, head, 0x03cf);
-}
-
-void
-nv_wrvgag(void *obj, int head, u8 index, u8 value)
-{
- nv_wrport(obj, head, 0x03ce, index);
- nv_wrport(obj, head, 0x03cf, value);
-}
-
-u8
-nv_rdvgac(void *obj, int head, u8 index)
-{
- nv_wrport(obj, head, 0x03d4, index);
- return nv_rdport(obj, head, 0x03d5);
-}
-
-void
-nv_wrvgac(void *obj, int head, u8 index, u8 value)
-{
- nv_wrport(obj, head, 0x03d4, index);
- nv_wrport(obj, head, 0x03d5, value);
-}
-
-u8
-nv_rdvgai(void *obj, int head, u16 port, u8 index)
-{
- if (port == 0x03c4) return nv_rdvgas(obj, head, index);
- if (port == 0x03ce) return nv_rdvgag(obj, head, index);
- if (port == 0x03d4) return nv_rdvgac(obj, head, index);
- nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
- return 0x00;
-}
-
-void
-nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
-{
- if (port == 0x03c4) nv_wrvgas(obj, head, index, value);
- else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
- else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
- else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
-}
-
-bool
-nv_lockvgac(void *obj, bool lock)
-{
- struct nouveau_device *dev = nv_device(obj);
-
- bool locked = !nv_rdvgac(obj, 0, 0x1f);
- u8 data = lock ? 0x99 : 0x57;
- if (dev->card_type < NV_50)
- nv_wrvgac(obj, 0, 0x1f, data);
- else
- nv_wrvgac(obj, 0, 0x3f, data);
- if (dev->chipset == 0x11) {
- if (!(nv_rd32(obj, 0x001084) & 0x10000000))
- nv_wrvgac(obj, 1, 0x1f, data);
- }
- return locked;
-}
-
-/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
- * it affects only the 8 bit vga io regs, which we access using mmio at
- * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
- * in general, the set value of cr44 does not matter: reg access works as
- * expected and values can be set for the appropriate head by using a 0x2000
- * offset as required
- * however:
- * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
- * cr44 must be set to 0 or 3 for accessing values on the correct head
- * through the common 0xc03c* addresses
- * b) in tied mode (4) head B is programmed to the values set on head A, and
- * access using the head B addresses can have strange results, ergo we leave
- * tied mode in init once we know to what cr44 should be restored on exit
- *
- * the owner parameter is slightly abused:
- * 0 and 1 are treated as head values and so the set value is (owner * 3)
- * other values are treated as literal values to set
- */
-u8
-nv_rdvgaowner(void *obj)
-{
- if (nv_device(obj)->card_type < NV_50) {
- if (nv_device(obj)->chipset == 0x11) {
- u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
- if (tied == 0) {
- u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
- u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
- u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
- u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
- if (slA && !tvA) return 0x00;
- if (slB && !tvB) return 0x03;
- if (slA) return 0x00;
- if (slB) return 0x03;
- return 0x00;
- }
- return 0x04;
- }
-
- return nv_rdvgac(obj, 0, 0x44);
- }
-
- nv_error(obj, "rdvgaowner after nv4x\n");
- return 0x00;
-}
-
-void
-nv_wrvgaowner(void *obj, u8 select)
-{
- if (nv_device(obj)->card_type < NV_50) {
- u8 owner = (select == 1) ? 3 : select;
- if (nv_device(obj)->chipset == 0x11) {
- /* workaround hw lockup bug */
- nv_rdvgac(obj, 0, 0x1f);
- nv_rdvgac(obj, 1, 0x1f);
- }
-
- nv_wrvgac(obj, 0, 0x44, owner);
-
- if (nv_device(obj)->chipset == 0x11) {
- nv_wrvgac(obj, 0, 0x2e, owner);
- nv_wrvgac(obj, 0, 0x2e, owner);
- }
- } else
- nv_error(obj, "wrvgaowner after nv4x\n");
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
deleted file mode 100644
index e1500f77a56a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/base.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-
-#include "priv.h"
-
-static int
-nvkm_dmaobj_bind(struct nouveau_dmaobj *dmaobj, struct nouveau_object *parent,
- struct nouveau_gpuobj **pgpuobj)
-{
- const struct nvkm_dmaeng_impl *impl = (void *)
- nv_oclass(nv_object(dmaobj)->engine);
- int ret = 0;
-
- if (nv_object(dmaobj) == parent) { /* ctor bind */
- if (nv_mclass(parent->parent) == NV_DEVICE) {
- /* delayed, or no, binding */
- return 0;
- }
- ret = impl->bind(dmaobj, parent, pgpuobj);
- if (ret == 0)
- nouveau_object_ref(NULL, &parent);
- return ret;
- }
-
- return impl->bind(dmaobj, parent, pgpuobj);
-}
-
-int
-nvkm_dmaobj_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void **pdata, u32 *psize,
- int length, void **pobject)
-{
- union {
- struct nv_dma_v0 v0;
- } *args = *pdata;
- struct nouveau_instmem *instmem = nouveau_instmem(parent);
- struct nouveau_client *client = nouveau_client(parent);
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_dmaobj *dmaobj;
- void *data = *pdata;
- u32 size = *psize;
- int ret;
-
- ret = nouveau_object_create_(parent, engine, oclass, 0, length, pobject);
- dmaobj = *pobject;
- if (ret)
- return ret;
-
- nv_ioctl(parent, "create dma size %d\n", *psize);
- if (nvif_unpack(args->v0, 0, 0, true)) {
- nv_ioctl(parent, "create dma vers %d target %d access %d "
- "start %016llx limit %016llx\n",
- args->v0.version, args->v0.target, args->v0.access,
- args->v0.start, args->v0.limit);
- dmaobj->target = args->v0.target;
- dmaobj->access = args->v0.access;
- dmaobj->start = args->v0.start;
- dmaobj->limit = args->v0.limit;
- } else
- return ret;
-
- *pdata = data;
- *psize = size;
-
- if (dmaobj->start > dmaobj->limit)
- return -EINVAL;
-
- switch (dmaobj->target) {
- case NV_DMA_V0_TARGET_VM:
- dmaobj->target = NV_MEM_TARGET_VM;
- break;
- case NV_DMA_V0_TARGET_VRAM:
- if (!client->super) {
- if (dmaobj->limit >= pfb->ram->size - instmem->reserved)
- return -EACCES;
- if (device->card_type >= NV_50)
- return -EACCES;
- }
- dmaobj->target = NV_MEM_TARGET_VRAM;
- break;
- case NV_DMA_V0_TARGET_PCI:
- if (!client->super)
- return -EACCES;
- dmaobj->target = NV_MEM_TARGET_PCI;
- break;
- case NV_DMA_V0_TARGET_PCI_US:
- case NV_DMA_V0_TARGET_AGP:
- if (!client->super)
- return -EACCES;
- dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP;
- break;
- default:
- return -EINVAL;
- }
-
- switch (dmaobj->access) {
- case NV_DMA_V0_ACCESS_VM:
- dmaobj->access = NV_MEM_ACCESS_VM;
- break;
- case NV_DMA_V0_ACCESS_RD:
- dmaobj->access = NV_MEM_ACCESS_RO;
- break;
- case NV_DMA_V0_ACCESS_WR:
- dmaobj->access = NV_MEM_ACCESS_WO;
- break;
- case NV_DMA_V0_ACCESS_RDWR:
- dmaobj->access = NV_MEM_ACCESS_RW;
- break;
- default:
- return -EINVAL;
- }
-
- return ret;
-}
-
-int
-_nvkm_dmaeng_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- const struct nvkm_dmaeng_impl *impl = (void *)oclass;
- struct nouveau_dmaeng *dmaeng;
- int ret;
-
- ret = nouveau_engine_create(parent, engine, oclass, true, "DMAOBJ",
- "dmaobj", &dmaeng);
- *pobject = nv_object(dmaeng);
- if (ret)
- return ret;
-
- nv_engine(dmaeng)->sclass = impl->sclass;
- dmaeng->bind = nvkm_dmaobj_bind;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
deleted file mode 100644
index 20c9dbfe3b2e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv04.c
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm/nv04.h>
-
-#include "priv.h"
-
-struct nv04_dmaobj_priv {
- struct nouveau_dmaobj base;
- bool clone;
- u32 flags0;
- u32 flags2;
-};
-
-static int
-nv04_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
- struct nouveau_object *parent,
- struct nouveau_gpuobj **pgpuobj)
-{
- struct nv04_dmaobj_priv *priv = (void *)dmaobj;
- struct nouveau_gpuobj *gpuobj;
- u64 offset = priv->base.start & 0xfffff000;
- u64 adjust = priv->base.start & 0x00000fff;
- u32 length = priv->base.limit - priv->base.start;
- int ret;
-
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case NV03_CHANNEL_DMA:
- case NV10_CHANNEL_DMA:
- case NV17_CHANNEL_DMA:
- case NV40_CHANNEL_DMA:
- break;
- default:
- return -EINVAL;
- }
- }
-
- if (priv->clone) {
- struct nv04_vmmgr_priv *vmm = nv04_vmmgr(dmaobj);
- struct nouveau_gpuobj *pgt = vmm->vm->pgt[0].obj[0];
- if (!dmaobj->start)
- return nouveau_gpuobj_dup(parent, pgt, pgpuobj);
- offset = nv_ro32(pgt, 8 + (offset >> 10));
- offset &= 0xfffff000;
- }
-
- ret = nouveau_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
- *pgpuobj = gpuobj;
- if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20));
- nv_wo32(*pgpuobj, 0x04, length);
- nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset);
- nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset);
- }
-
- return ret;
-}
-
-static int
-nv04_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_dmaeng *dmaeng = (void *)engine;
- struct nv04_vmmgr_priv *vmm = nv04_vmmgr(engine);
- struct nv04_dmaobj_priv *priv;
- int ret;
-
- ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
- *pobject = nv_object(priv);
- if (ret || (ret = -ENOSYS, size))
- return ret;
-
- if (priv->base.target == NV_MEM_TARGET_VM) {
- if (nv_object(vmm)->oclass == &nv04_vmmgr_oclass)
- priv->clone = true;
- priv->base.target = NV_MEM_TARGET_PCI;
- priv->base.access = NV_MEM_ACCESS_RW;
- }
-
- priv->flags0 = nv_mclass(priv);
- switch (priv->base.target) {
- case NV_MEM_TARGET_VRAM:
- priv->flags0 |= 0x00003000;
- break;
- case NV_MEM_TARGET_PCI:
- priv->flags0 |= 0x00023000;
- break;
- case NV_MEM_TARGET_PCI_NOSNOOP:
- priv->flags0 |= 0x00033000;
- break;
- default:
- return -EINVAL;
- }
-
- switch (priv->base.access) {
- case NV_MEM_ACCESS_RO:
- priv->flags0 |= 0x00004000;
- break;
- case NV_MEM_ACCESS_WO:
- priv->flags0 |= 0x00008000;
- case NV_MEM_ACCESS_RW:
- priv->flags2 |= 0x00000002;
- break;
- default:
- return -EINVAL;
- }
-
- return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nv04_dmaobj_ofuncs = {
- .ctor = nv04_dmaobj_ctor,
- .dtor = _nvkm_dmaobj_dtor,
- .init = _nvkm_dmaobj_init,
- .fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nv04_dmaeng_sclass[] = {
- { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs },
- { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs },
- { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs },
- {}
-};
-
-struct nouveau_oclass *
-nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
- .base.handle = NV_ENGINE(DMAOBJ, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_dmaeng_ctor,
- .dtor = _nvkm_dmaeng_dtor,
- .init = _nvkm_dmaeng_init,
- .fini = _nvkm_dmaeng_fini,
- },
- .sclass = nv04_dmaeng_sclass,
- .bind = nv04_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
deleted file mode 100644
index a740ddba2ee2..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nv50.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/gpuobj.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-
-#include "priv.h"
-
-struct nv50_dmaobj_priv {
- struct nouveau_dmaobj base;
- u32 flags0;
- u32 flags5;
-};
-
-static int
-nv50_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
- struct nouveau_object *parent,
- struct nouveau_gpuobj **pgpuobj)
-{
- struct nv50_dmaobj_priv *priv = (void *)dmaobj;
- int ret;
-
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case NV40_CHANNEL_DMA:
- case NV50_CHANNEL_GPFIFO:
- case G82_CHANNEL_GPFIFO:
- case NV50_DISP_CORE_CHANNEL_DMA:
- case G82_DISP_CORE_CHANNEL_DMA:
- case GT206_DISP_CORE_CHANNEL_DMA:
- case GT200_DISP_CORE_CHANNEL_DMA:
- case GT214_DISP_CORE_CHANNEL_DMA:
- case NV50_DISP_BASE_CHANNEL_DMA:
- case G82_DISP_BASE_CHANNEL_DMA:
- case GT200_DISP_BASE_CHANNEL_DMA:
- case GT214_DISP_BASE_CHANNEL_DMA:
- case NV50_DISP_OVERLAY_CHANNEL_DMA:
- case G82_DISP_OVERLAY_CHANNEL_DMA:
- case GT200_DISP_OVERLAY_CHANNEL_DMA:
- case GT214_DISP_OVERLAY_CHANNEL_DMA:
- break;
- default:
- return -EINVAL;
- }
- }
-
- ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
- if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
- nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
- nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
- nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
- upper_32_bits(priv->base.start));
- nv_wo32(*pgpuobj, 0x10, 0x00000000);
- nv_wo32(*pgpuobj, 0x14, priv->flags5);
- }
-
- return ret;
-}
-
-static int
-nv50_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_dmaeng *dmaeng = (void *)engine;
- union {
- struct nv50_dma_v0 v0;
- } *args;
- struct nv50_dmaobj_priv *priv;
- u32 user, part, comp, kind;
- int ret;
-
- ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
- args = data;
-
- nv_ioctl(parent, "create nv50 dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d "
- "comp %d kind %02x\n", args->v0.version,
- args->v0.priv, args->v0.part, args->v0.comp,
- args->v0.kind);
- user = args->v0.priv;
- part = args->v0.part;
- comp = args->v0.comp;
- kind = args->v0.kind;
- } else
- if (size == 0) {
- if (priv->base.target != NV_MEM_TARGET_VM) {
- user = NV50_DMA_V0_PRIV_US;
- part = NV50_DMA_V0_PART_256;
- comp = NV50_DMA_V0_COMP_NONE;
- kind = NV50_DMA_V0_KIND_PITCH;
- } else {
- user = NV50_DMA_V0_PRIV_VM;
- part = NV50_DMA_V0_PART_VM;
- comp = NV50_DMA_V0_COMP_VM;
- kind = NV50_DMA_V0_KIND_VM;
- }
- } else
- return ret;
-
- if (user > 2 || part > 2 || comp > 3 || kind > 0x7f)
- return -EINVAL;
- priv->flags0 = (comp << 29) | (kind << 22) | (user << 20);
- priv->flags5 = (part << 16);
-
- switch (priv->base.target) {
- case NV_MEM_TARGET_VM:
- priv->flags0 |= 0x00000000;
- break;
- case NV_MEM_TARGET_VRAM:
- priv->flags0 |= 0x00010000;
- break;
- case NV_MEM_TARGET_PCI:
- priv->flags0 |= 0x00020000;
- break;
- case NV_MEM_TARGET_PCI_NOSNOOP:
- priv->flags0 |= 0x00030000;
- break;
- default:
- return -EINVAL;
- }
-
- switch (priv->base.access) {
- case NV_MEM_ACCESS_VM:
- break;
- case NV_MEM_ACCESS_RO:
- priv->flags0 |= 0x00040000;
- break;
- case NV_MEM_ACCESS_WO:
- case NV_MEM_ACCESS_RW:
- priv->flags0 |= 0x00080000;
- break;
- default:
- return -EINVAL;
- }
-
- return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nv50_dmaobj_ofuncs = {
- .ctor = nv50_dmaobj_ctor,
- .dtor = _nvkm_dmaobj_dtor,
- .init = _nvkm_dmaobj_init,
- .fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nv50_dmaeng_sclass[] = {
- { NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs },
- { NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs },
- { NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs },
- {}
-};
-
-struct nouveau_oclass *
-nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
- .base.handle = NV_ENGINE(DMAOBJ, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_dmaeng_ctor,
- .dtor = _nvkm_dmaeng_dtor,
- .init = _nvkm_dmaeng_init,
- .fini = _nvkm_dmaeng_fini,
- },
- .sclass = nv50_dmaeng_sclass,
- .bind = nv50_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
deleted file mode 100644
index 88ec33b20048..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvc0.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/device.h>
-#include <core/gpuobj.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-
-#include "priv.h"
-
-struct nvc0_dmaobj_priv {
- struct nouveau_dmaobj base;
- u32 flags0;
- u32 flags5;
-};
-
-static int
-nvc0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
- struct nouveau_object *parent,
- struct nouveau_gpuobj **pgpuobj)
-{
- struct nvc0_dmaobj_priv *priv = (void *)dmaobj;
- int ret;
-
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case GT214_DISP_CORE_CHANNEL_DMA:
- case GT214_DISP_BASE_CHANNEL_DMA:
- case GT214_DISP_OVERLAY_CHANNEL_DMA:
- break;
- default:
- return -EINVAL;
- }
- } else
- return 0;
-
- ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
- if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
- nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
- nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
- nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
- upper_32_bits(priv->base.start));
- nv_wo32(*pgpuobj, 0x10, 0x00000000);
- nv_wo32(*pgpuobj, 0x14, priv->flags5);
- }
-
- return ret;
-}
-
-static int
-nvc0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_dmaeng *dmaeng = (void *)engine;
- union {
- struct gf100_dma_v0 v0;
- } *args;
- struct nvc0_dmaobj_priv *priv;
- u32 kind, user, unkn;
- int ret;
-
- ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
- args = data;
-
- nv_ioctl(parent, "create gf100 dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n",
- args->v0.version, args->v0.priv, args->v0.kind);
- kind = args->v0.kind;
- user = args->v0.priv;
- unkn = 0;
- } else
- if (size == 0) {
- if (priv->base.target != NV_MEM_TARGET_VM) {
- kind = GF100_DMA_V0_KIND_PITCH;
- user = GF100_DMA_V0_PRIV_US;
- unkn = 2;
- } else {
- kind = GF100_DMA_V0_KIND_VM;
- user = GF100_DMA_V0_PRIV_VM;
- unkn = 0;
- }
- } else
- return ret;
-
- if (user > 2)
- return -EINVAL;
- priv->flags0 |= (kind << 22) | (user << 20);
- priv->flags5 |= (unkn << 16);
-
- switch (priv->base.target) {
- case NV_MEM_TARGET_VM:
- priv->flags0 |= 0x00000000;
- break;
- case NV_MEM_TARGET_VRAM:
- priv->flags0 |= 0x00010000;
- break;
- case NV_MEM_TARGET_PCI:
- priv->flags0 |= 0x00020000;
- break;
- case NV_MEM_TARGET_PCI_NOSNOOP:
- priv->flags0 |= 0x00030000;
- break;
- default:
- return -EINVAL;
- }
-
- switch (priv->base.access) {
- case NV_MEM_ACCESS_VM:
- break;
- case NV_MEM_ACCESS_RO:
- priv->flags0 |= 0x00040000;
- break;
- case NV_MEM_ACCESS_WO:
- case NV_MEM_ACCESS_RW:
- priv->flags0 |= 0x00080000;
- break;
- }
-
- return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nvc0_dmaobj_ofuncs = {
- .ctor = nvc0_dmaobj_ctor,
- .dtor = _nvkm_dmaobj_dtor,
- .init = _nvkm_dmaobj_init,
- .fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nvc0_dmaeng_sclass[] = {
- { NV_DMA_FROM_MEMORY, &nvc0_dmaobj_ofuncs },
- { NV_DMA_TO_MEMORY, &nvc0_dmaobj_ofuncs },
- { NV_DMA_IN_MEMORY, &nvc0_dmaobj_ofuncs },
- {}
-};
-
-struct nouveau_oclass *
-nvc0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
- .base.handle = NV_ENGINE(DMAOBJ, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_dmaeng_ctor,
- .dtor = _nvkm_dmaeng_dtor,
- .init = _nvkm_dmaeng_init,
- .fini = _nvkm_dmaeng_fini,
- },
- .sclass = nvc0_dmaeng_sclass,
- .bind = nvc0_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c b/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
deleted file mode 100644
index 19f5f6522962..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/nvd0.c
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/device.h>
-#include <core/gpuobj.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-
-#include "priv.h"
-
-struct nvd0_dmaobj_priv {
- struct nouveau_dmaobj base;
- u32 flags0;
-};
-
-static int
-nvd0_dmaobj_bind(struct nouveau_dmaobj *dmaobj,
- struct nouveau_object *parent,
- struct nouveau_gpuobj **pgpuobj)
-{
- struct nvd0_dmaobj_priv *priv = (void *)dmaobj;
- int ret;
-
- if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
- switch (nv_mclass(parent->parent)) {
- case GF110_DISP_CORE_CHANNEL_DMA:
- case GK104_DISP_CORE_CHANNEL_DMA:
- case GK110_DISP_CORE_CHANNEL_DMA:
- case GM107_DISP_CORE_CHANNEL_DMA:
- case GM204_DISP_CORE_CHANNEL_DMA:
- case GF110_DISP_BASE_CHANNEL_DMA:
- case GK104_DISP_BASE_CHANNEL_DMA:
- case GK110_DISP_BASE_CHANNEL_DMA:
- case GF110_DISP_OVERLAY_CONTROL_DMA:
- case GK104_DISP_OVERLAY_CONTROL_DMA:
- break;
- default:
- return -EINVAL;
- }
- } else
- return 0;
-
- ret = nouveau_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
- if (ret == 0) {
- nv_wo32(*pgpuobj, 0x00, priv->flags0);
- nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8);
- nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8);
- nv_wo32(*pgpuobj, 0x0c, 0x00000000);
- nv_wo32(*pgpuobj, 0x10, 0x00000000);
- nv_wo32(*pgpuobj, 0x14, 0x00000000);
- }
-
- return ret;
-}
-
-static int
-nvd0_dmaobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_dmaeng *dmaeng = (void *)engine;
- union {
- struct gf110_dma_v0 v0;
- } *args;
- struct nvd0_dmaobj_priv *priv;
- u32 kind, page;
- int ret;
-
- ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
- args = data;
-
- nv_ioctl(parent, "create gf110 dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n",
- args->v0.version, args->v0.page, args->v0.kind);
- kind = args->v0.kind;
- page = args->v0.page;
- } else
- if (size == 0) {
- if (priv->base.target != NV_MEM_TARGET_VM) {
- kind = GF110_DMA_V0_KIND_PITCH;
- page = GF110_DMA_V0_PAGE_SP;
- } else {
- kind = GF110_DMA_V0_KIND_VM;
- page = GF110_DMA_V0_PAGE_LP;
- }
- } else
- return ret;
-
- if (page > 1)
- return -EINVAL;
- priv->flags0 = (kind << 20) | (page << 6);
-
- switch (priv->base.target) {
- case NV_MEM_TARGET_VRAM:
- priv->flags0 |= 0x00000009;
- break;
- case NV_MEM_TARGET_VM:
- case NV_MEM_TARGET_PCI:
- case NV_MEM_TARGET_PCI_NOSNOOP:
- /* XXX: don't currently know how to construct a real one
- * of these. we only use them to represent pushbufs
- * on these chipsets, and the classes that use them
- * deal with the target themselves.
- */
- break;
- default:
- return -EINVAL;
- }
-
- return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
-}
-
-static struct nouveau_ofuncs
-nvd0_dmaobj_ofuncs = {
- .ctor = nvd0_dmaobj_ctor,
- .dtor = _nvkm_dmaobj_dtor,
- .init = _nvkm_dmaobj_init,
- .fini = _nvkm_dmaobj_fini,
-};
-
-static struct nouveau_oclass
-nvd0_dmaeng_sclass[] = {
- { NV_DMA_FROM_MEMORY, &nvd0_dmaobj_ofuncs },
- { NV_DMA_TO_MEMORY, &nvd0_dmaobj_ofuncs },
- { NV_DMA_IN_MEMORY, &nvd0_dmaobj_ofuncs },
- {}
-};
-
-struct nouveau_oclass *
-nvd0_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
- .base.handle = NV_ENGINE(DMAOBJ, 0xd0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_dmaeng_ctor,
- .dtor = _nvkm_dmaeng_dtor,
- .init = _nvkm_dmaeng_init,
- .fini = _nvkm_dmaeng_fini,
- },
- .sclass = nvd0_dmaeng_sclass,
- .bind = nvd0_dmaobj_bind,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h
deleted file mode 100644
index 36f743866937..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/dmaobj/priv.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NVKM_DMAOBJ_PRIV_H__
-#define __NVKM_DMAOBJ_PRIV_H__
-
-#include <engine/dmaobj.h>
-
-#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \
- nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d)
-
-int nvkm_dmaobj_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void **, u32 *,
- int, void **);
-#define _nvkm_dmaobj_dtor nouveau_object_destroy
-#define _nvkm_dmaobj_init nouveau_object_init
-#define _nvkm_dmaobj_fini nouveau_object_fini
-
-int _nvkm_dmaeng_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-#define _nvkm_dmaeng_dtor _nouveau_engine_dtor
-#define _nvkm_dmaeng_init _nouveau_engine_init
-#define _nvkm_dmaeng_fini _nouveau_engine_fini
-
-struct nvkm_dmaeng_impl {
- struct nouveau_oclass base;
- struct nouveau_oclass *sclass;
- int (*bind)(struct nouveau_dmaobj *, struct nouveau_object *,
- struct nouveau_gpuobj **);
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/falcon.c b/drivers/gpu/drm/nouveau/core/engine/falcon.c
deleted file mode 100644
index 2914646c8709..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/falcon.c
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <engine/falcon.h>
-#include <subdev/timer.h>
-
-void
-nouveau_falcon_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_falcon *falcon = (void *)subdev;
- u32 dispatch = nv_ro32(falcon, 0x01c);
- u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
-
- if (intr & 0x00000010) {
- nv_debug(falcon, "ucode halted\n");
- nv_wo32(falcon, 0x004, 0x00000010);
- intr &= ~0x00000010;
- }
-
- if (intr) {
- nv_error(falcon, "unhandled intr 0x%08x\n", intr);
- nv_wo32(falcon, 0x004, intr);
- }
-}
-
-u32
-_nouveau_falcon_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_falcon *falcon = (void *)object;
- return nv_rd32(falcon, falcon->addr + addr);
-}
-
-void
-_nouveau_falcon_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_falcon *falcon = (void *)object;
- nv_wr32(falcon, falcon->addr + addr, data);
-}
-
-static void *
-vmemdup(const void *src, size_t len)
-{
- void *p = vmalloc(len);
-
- if (p)
- memcpy(p, src, len);
- return p;
-}
-
-int
-_nouveau_falcon_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nouveau_falcon *falcon = (void *)object;
- const struct firmware *fw;
- char name[32] = "internal";
- int ret, i;
- u32 caps;
-
- /* enable engine, and determine its capabilities */
- ret = nouveau_engine_init(&falcon->base);
- if (ret)
- return ret;
-
- if (device->chipset < 0xa3 ||
- device->chipset == 0xaa || device->chipset == 0xac) {
- falcon->version = 0;
- falcon->secret = (falcon->addr == 0x087000) ? 1 : 0;
- } else {
- caps = nv_ro32(falcon, 0x12c);
- falcon->version = (caps & 0x0000000f);
- falcon->secret = (caps & 0x00000030) >> 4;
- }
-
- caps = nv_ro32(falcon, 0x108);
- falcon->code.limit = (caps & 0x000001ff) << 8;
- falcon->data.limit = (caps & 0x0003fe00) >> 1;
-
- nv_debug(falcon, "falcon version: %d\n", falcon->version);
- nv_debug(falcon, "secret level: %d\n", falcon->secret);
- nv_debug(falcon, "code limit: %d\n", falcon->code.limit);
- nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
-
- /* wait for 'uc halted' to be signalled before continuing */
- if (falcon->secret && falcon->version < 4) {
- if (!falcon->version)
- nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
- else
- nv_wait(falcon, 0x180, 0x80000000, 0);
- nv_wo32(falcon, 0x004, 0x00000010);
- }
-
- /* disable all interrupts */
- nv_wo32(falcon, 0x014, 0xffffffff);
-
- /* no default ucode provided by the engine implementation, try and
- * locate a "self-bootstrapping" firmware image for the engine
- */
- if (!falcon->code.data) {
- snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
- device->chipset, falcon->addr >> 12);
-
- ret = request_firmware(&fw, name, nv_device_base(device));
- if (ret == 0) {
- falcon->code.data = vmemdup(fw->data, fw->size);
- falcon->code.size = fw->size;
- falcon->data.data = NULL;
- falcon->data.size = 0;
- release_firmware(fw);
- }
-
- falcon->external = true;
- }
-
- /* next step is to try and load "static code/data segment" firmware
- * images for the engine
- */
- if (!falcon->code.data) {
- snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
- device->chipset, falcon->addr >> 12);
-
- ret = request_firmware(&fw, name, nv_device_base(device));
- if (ret) {
- nv_error(falcon, "unable to load firmware data\n");
- return ret;
- }
-
- falcon->data.data = vmemdup(fw->data, fw->size);
- falcon->data.size = fw->size;
- release_firmware(fw);
- if (!falcon->data.data)
- return -ENOMEM;
-
- snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
- device->chipset, falcon->addr >> 12);
-
- ret = request_firmware(&fw, name, nv_device_base(device));
- if (ret) {
- nv_error(falcon, "unable to load firmware code\n");
- return ret;
- }
-
- falcon->code.data = vmemdup(fw->data, fw->size);
- falcon->code.size = fw->size;
- release_firmware(fw);
- if (!falcon->code.data)
- return -ENOMEM;
- }
-
- nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ?
- "static code/data segments" : "self-bootstrapping");
-
- /* ensure any "self-bootstrapping" firmware image is in vram */
- if (!falcon->data.data && !falcon->core) {
- ret = nouveau_gpuobj_new(object->parent, NULL,
- falcon->code.size, 256, 0,
- &falcon->core);
- if (ret) {
- nv_error(falcon, "core allocation failed, %d\n", ret);
- return ret;
- }
-
- for (i = 0; i < falcon->code.size; i += 4)
- nv_wo32(falcon->core, i, falcon->code.data[i / 4]);
- }
-
- /* upload firmware bootloader (or the full code segments) */
- if (falcon->core) {
- if (device->card_type < NV_C0)
- nv_wo32(falcon, 0x618, 0x04000000);
- else
- nv_wo32(falcon, 0x618, 0x00000114);
- nv_wo32(falcon, 0x11c, 0);
- nv_wo32(falcon, 0x110, falcon->core->addr >> 8);
- nv_wo32(falcon, 0x114, 0);
- nv_wo32(falcon, 0x118, 0x00006610);
- } else {
- if (falcon->code.size > falcon->code.limit ||
- falcon->data.size > falcon->data.limit) {
- nv_error(falcon, "ucode exceeds falcon limit(s)\n");
- return -EINVAL;
- }
-
- if (falcon->version < 3) {
- nv_wo32(falcon, 0xff8, 0x00100000);
- for (i = 0; i < falcon->code.size / 4; i++)
- nv_wo32(falcon, 0xff4, falcon->code.data[i]);
- } else {
- nv_wo32(falcon, 0x180, 0x01000000);
- for (i = 0; i < falcon->code.size / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wo32(falcon, 0x188, i >> 6);
- nv_wo32(falcon, 0x184, falcon->code.data[i]);
- }
- }
- }
-
- /* upload data segment (if necessary), zeroing the remainder */
- if (falcon->version < 3) {
- nv_wo32(falcon, 0xff8, 0x00000000);
- for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
- nv_wo32(falcon, 0xff4, falcon->data.data[i]);
- for (; i < falcon->data.limit; i += 4)
- nv_wo32(falcon, 0xff4, 0x00000000);
- } else {
- nv_wo32(falcon, 0x1c0, 0x01000000);
- for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
- nv_wo32(falcon, 0x1c4, falcon->data.data[i]);
- for (; i < falcon->data.limit / 4; i++)
- nv_wo32(falcon, 0x1c4, 0x00000000);
- }
-
- /* start it running */
- nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
- nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */
- nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */
- nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */
- return 0;
-}
-
-int
-_nouveau_falcon_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_falcon *falcon = (void *)object;
-
- if (!suspend) {
- nouveau_gpuobj_ref(NULL, &falcon->core);
- if (falcon->external) {
- vfree(falcon->data.data);
- vfree(falcon->code.data);
- falcon->code.data = NULL;
- }
- }
-
- nv_mo32(falcon, 0x048, 0x00000003, 0x00000000);
- nv_wo32(falcon, 0x014, 0xffffffff);
-
- return nouveau_engine_fini(&falcon->base, suspend);
-}
-
-int
-nouveau_falcon_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 addr, bool enable,
- const char *iname, const char *fname,
- int length, void **pobject)
-{
- struct nouveau_falcon *falcon;
- int ret;
-
- ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
- fname, length, pobject);
- falcon = *pobject;
- if (ret)
- return ret;
-
- falcon->addr = addr;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c b/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
deleted file mode 100644
index ac8375cf4eef..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/base.c
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/object.h>
-#include <core/handle.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/event.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-static int
-nouveau_fifo_event_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- if (size == 0) {
- notify->size = 0;
- notify->types = 1;
- notify->index = 0;
- return 0;
- }
- return -ENOSYS;
-}
-
-static const struct nvkm_event_func
-nouveau_fifo_event_func = {
- .ctor = nouveau_fifo_event_ctor,
-};
-
-int
-nouveau_fifo_channel_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int bar, u32 addr, u32 size, u32 pushbuf,
- u64 engmask, int len, void **ptr)
-{
- struct nouveau_device *device = nv_device(engine);
- struct nouveau_fifo *priv = (void *)engine;
- struct nouveau_fifo_chan *chan;
- struct nouveau_dmaeng *dmaeng;
- unsigned long flags;
- int ret;
-
- /* create base object class */
- ret = nouveau_namedb_create_(parent, engine, oclass, 0, NULL,
- engmask, len, ptr);
- chan = *ptr;
- if (ret)
- return ret;
-
- /* validate dma object representing push buffer */
- chan->pushdma = (void *)nouveau_handle_ref(parent, pushbuf);
- if (!chan->pushdma)
- return -ENOENT;
-
- dmaeng = (void *)chan->pushdma->base.engine;
- switch (chan->pushdma->base.oclass->handle) {
- case NV_DMA_FROM_MEMORY:
- case NV_DMA_IN_MEMORY:
- break;
- default:
- return -EINVAL;
- }
-
- ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
- if (ret)
- return ret;
-
- /* find a free fifo channel */
- spin_lock_irqsave(&priv->lock, flags);
- for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
- if (!priv->channel[chan->chid]) {
- priv->channel[chan->chid] = nv_object(chan);
- break;
- }
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (chan->chid == priv->max) {
- nv_error(priv, "no free channels\n");
- return -ENOSPC;
- }
-
- chan->addr = nv_device_resource_start(device, bar) +
- addr + size * chan->chid;
- chan->size = size;
- nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
- return 0;
-}
-
-void
-nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *chan)
-{
- struct nouveau_fifo *priv = (void *)nv_object(chan)->engine;
- unsigned long flags;
-
- if (chan->user)
- iounmap(chan->user);
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->channel[chan->chid] = NULL;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- nouveau_gpuobj_ref(NULL, &chan->pushgpu);
- nouveau_object_ref(NULL, (struct nouveau_object **)&chan->pushdma);
- nouveau_namedb_destroy(&chan->base);
-}
-
-void
-_nouveau_fifo_channel_dtor(struct nouveau_object *object)
-{
- struct nouveau_fifo_chan *chan = (void *)object;
- nouveau_fifo_channel_destroy(chan);
-}
-
-int
-_nouveau_fifo_channel_map(struct nouveau_object *object, u64 *addr, u32 *size)
-{
- struct nouveau_fifo_chan *chan = (void *)object;
- *addr = chan->addr;
- *size = chan->size;
- return 0;
-}
-
-u32
-_nouveau_fifo_channel_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_fifo_chan *chan = (void *)object;
- if (unlikely(!chan->user)) {
- chan->user = ioremap(chan->addr, chan->size);
- if (WARN_ON_ONCE(chan->user == NULL))
- return 0;
- }
- return ioread32_native(chan->user + addr);
-}
-
-void
-_nouveau_fifo_channel_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_fifo_chan *chan = (void *)object;
- if (unlikely(!chan->user)) {
- chan->user = ioremap(chan->addr, chan->size);
- if (WARN_ON_ONCE(chan->user == NULL))
- return;
- }
- iowrite32_native(data, chan->user + addr);
-}
-
-int
-nouveau_fifo_uevent_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- union {
- struct nvif_notify_uevent_req none;
- } *req = data;
- int ret;
-
- if (nvif_unvers(req->none)) {
- notify->size = sizeof(struct nvif_notify_uevent_rep);
- notify->types = 1;
- notify->index = 0;
- }
-
- return ret;
-}
-
-void
-nouveau_fifo_uevent(struct nouveau_fifo *fifo)
-{
- struct nvif_notify_uevent_rep rep = {
- };
- nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
-}
-
-int
-_nouveau_fifo_channel_ntfy(struct nouveau_object *object, u32 type,
- struct nvkm_event **event)
-{
- struct nouveau_fifo *fifo = (void *)object->engine;
- switch (type) {
- case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
- if (nv_mclass(object) >= G82_CHANNEL_DMA) {
- *event = &fifo->uevent;
- return 0;
- }
- break;
- default:
- break;
- }
- return -EINVAL;
-}
-
-static int
-nouveau_fifo_chid(struct nouveau_fifo *priv, struct nouveau_object *object)
-{
- int engidx = nv_hclass(priv) & 0xff;
-
- while (object && object->parent) {
- if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
- (nv_hclass(object->parent) & 0xff) == engidx)
- return nouveau_fifo_chan(object)->chid;
- object = object->parent;
- }
-
- return -1;
-}
-
-const char *
-nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid)
-{
- struct nouveau_fifo_chan *chan = NULL;
- unsigned long flags;
-
- spin_lock_irqsave(&fifo->lock, flags);
- if (chid >= fifo->min && chid <= fifo->max)
- chan = (void *)fifo->channel[chid];
- spin_unlock_irqrestore(&fifo->lock, flags);
-
- return nouveau_client_name(chan);
-}
-
-void
-nouveau_fifo_destroy(struct nouveau_fifo *priv)
-{
- kfree(priv->channel);
- nvkm_event_fini(&priv->uevent);
- nvkm_event_fini(&priv->cevent);
- nouveau_engine_destroy(&priv->base);
-}
-
-int
-nouveau_fifo_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int min, int max, int length, void **pobject)
-{
- struct nouveau_fifo *priv;
- int ret;
-
- ret = nouveau_engine_create_(parent, engine, oclass, true, "PFIFO",
- "fifo", length, pobject);
- priv = *pobject;
- if (ret)
- return ret;
-
- priv->min = min;
- priv->max = max;
- priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
- if (!priv->channel)
- return -ENOMEM;
-
- ret = nvkm_event_init(&nouveau_fifo_event_func, 1, 1, &priv->cevent);
- if (ret)
- return ret;
-
- priv->chid = nouveau_fifo_chid;
- spin_lock_init(&priv->lock);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c
deleted file mode 100644
index 327456eae963..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/gk20a.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "nve0.h"
-
-struct nouveau_oclass *
-gk20a_fifo_oclass = &(struct nve0_fifo_impl) {
- .base.handle = NV_ENGINE(FIFO, 0xea),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_fifo_ctor,
- .dtor = nve0_fifo_dtor,
- .init = nve0_fifo_init,
- .fini = nve0_fifo_fini,
- },
- .channels = 128,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
deleted file mode 100644
index 1931057f9962..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.c
+++ /dev/null
@@ -1,656 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/ramht.h>
-#include <core/event.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv04_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
- {}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-int
-nv04_fifo_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 handle)
-{
- struct nv04_fifo_priv *priv = (void *)parent->engine;
- struct nv04_fifo_chan *chan = (void *)parent;
- u32 context, chid = chan->base.chid;
- int ret;
-
- if (nv_iclass(object, NV_GPUOBJ_CLASS))
- context = nv_gpuobj(object)->addr >> 4;
- else
- context = 0x00000004; /* just non-zero */
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_DMAOBJ:
- case NVDEV_ENGINE_SW:
- context |= 0x00000000;
- break;
- case NVDEV_ENGINE_GR:
- context |= 0x00010000;
- break;
- case NVDEV_ENGINE_MPEG:
- context |= 0x00020000;
- break;
- default:
- return -EINVAL;
- }
-
- context |= 0x80000000; /* valid */
- context |= chid << 24;
-
- mutex_lock(&nv_subdev(priv)->mutex);
- ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
- mutex_unlock(&nv_subdev(priv)->mutex);
- return ret;
-}
-
-void
-nv04_fifo_object_detach(struct nouveau_object *parent, int cookie)
-{
- struct nv04_fifo_priv *priv = (void *)parent->engine;
- mutex_lock(&nv_subdev(priv)->mutex);
- nouveau_ramht_remove(priv->ramht, cookie);
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-int
-nv04_fifo_context_attach(struct nouveau_object *parent,
- struct nouveau_object *object)
-{
- nv_engctx(object)->addr = nouveau_fifo_chan(parent)->chid;
- return 0;
-}
-
-static int
-nv04_fifo_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo_priv *priv = (void *)engine;
- struct nv04_fifo_chan *chan;
- int ret;
-
- nv_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
- "offset %016llx\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
- 0x10000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->object_attach = nv04_fifo_object_attach;
- nv_parent(chan)->object_detach = nv04_fifo_object_detach;
- nv_parent(chan)->context_attach = nv04_fifo_context_attach;
- chan->ramfc = chan->base.chid * 32;
-
- nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
- nv_wo32(priv->ramfc, chan->ramfc + 0x10,
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- return 0;
-}
-
-void
-nv04_fifo_chan_dtor(struct nouveau_object *object)
-{
- struct nv04_fifo_priv *priv = (void *)object->engine;
- struct nv04_fifo_chan *chan = (void *)object;
- struct ramfc_desc *c = priv->ramfc_desc;
-
- do {
- nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
- } while ((++c)->bits);
-
- nouveau_fifo_channel_destroy(&chan->base);
-}
-
-int
-nv04_fifo_chan_init(struct nouveau_object *object)
-{
- struct nv04_fifo_priv *priv = (void *)object->engine;
- struct nv04_fifo_chan *chan = (void *)object;
- u32 mask = 1 << chan->base.chid;
- unsigned long flags;
- int ret;
-
- ret = nouveau_fifo_channel_init(&chan->base);
- if (ret)
- return ret;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
- spin_unlock_irqrestore(&priv->base.lock, flags);
- return 0;
-}
-
-int
-nv04_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv04_fifo_priv *priv = (void *)object->engine;
- struct nv04_fifo_chan *chan = (void *)object;
- struct nouveau_gpuobj *fctx = priv->ramfc;
- struct ramfc_desc *c;
- unsigned long flags;
- u32 data = chan->ramfc;
- u32 chid;
-
- /* prevent fifo context switches */
- spin_lock_irqsave(&priv->base.lock, flags);
- nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
- /* if this channel is active, replace it with a null context */
- chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
- if (chid == chan->base.chid) {
- nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
- nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
-
- c = priv->ramfc_desc;
- do {
- u32 rm = ((1ULL << c->bits) - 1) << c->regs;
- u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
- u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs;
- u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
- nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
- } while ((++c)->bits);
-
- c = priv->ramfc_desc;
- do {
- nv_wr32(priv, c->regp, 0x00000000);
- } while ((++c)->bits);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
- }
-
- /* restore normal operation, after disabling dma mode */
- nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
- nv_wr32(priv, NV03_PFIFO_CACHES, 1);
- spin_unlock_irqrestore(&priv->base.lock, flags);
-
- return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nv04_fifo_ofuncs = {
- .ctor = nv04_fifo_chan_ctor,
- .dtor = nv04_fifo_chan_dtor,
- .init = nv04_fifo_chan_init,
- .fini = nv04_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv04_fifo_sclass[] = {
- { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-int
-nv04_fifo_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_fifo_base *base;
- int ret;
-
- ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
- 0x1000, NVOBJ_FLAG_HEAP, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static struct nouveau_oclass
-nv04_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fifo_context_ctor,
- .dtor = _nouveau_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-void
-nv04_fifo_pause(struct nouveau_fifo *pfifo, unsigned long *pflags)
-__acquires(priv->base.lock)
-{
- struct nv04_fifo_priv *priv = (void *)pfifo;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- *pflags = flags;
-
- nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
- nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
-
- /* in some cases the puller may be left in an inconsistent state
- * if you try to stop it while it's busy translating handles.
- * sometimes you get a CACHE_ERROR, sometimes it just fails
- * silently; sending incorrect instance offsets to PGRAPH after
- * it's started up again.
- *
- * to avoid this, we invalidate the most recently calculated
- * instance.
- */
- if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
- NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
- nv_warn(priv, "timeout idling puller\n");
-
- if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
- NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
- nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
-
- nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
-}
-
-void
-nv04_fifo_start(struct nouveau_fifo *pfifo, unsigned long *pflags)
-__releases(priv->base.lock)
-{
- struct nv04_fifo_priv *priv = (void *)pfifo;
- unsigned long flags = *pflags;
-
- nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
- nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
-
- spin_unlock_irqrestore(&priv->base.lock, flags);
-}
-
-static const char *
-nv_dma_state_err(u32 state)
-{
- static const char * const desc[] = {
- "NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
- "INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
- };
- return desc[(state >> 29) & 0x7];
-}
-
-static bool
-nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
-{
- struct nv04_fifo_chan *chan = NULL;
- struct nouveau_handle *bind;
- const int subc = (addr >> 13) & 0x7;
- const int mthd = addr & 0x1ffc;
- bool handled = false;
- unsigned long flags;
- u32 engine;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- if (likely(chid >= priv->base.min && chid <= priv->base.max))
- chan = (void *)priv->base.channel[chid];
- if (unlikely(!chan))
- goto out;
-
- switch (mthd) {
- case 0x0000:
- bind = nouveau_namedb_get(nv_namedb(chan), data);
- if (unlikely(!bind))
- break;
-
- if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
- engine = 0x0000000f << (subc * 4);
- chan->subc[subc] = data;
- handled = true;
-
- nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
- }
-
- nouveau_namedb_put(bind);
- break;
- default:
- engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
- if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
- break;
-
- bind = nouveau_namedb_get(nv_namedb(chan), chan->subc[subc]);
- if (likely(bind)) {
- if (!nv_call(bind->object, mthd, data))
- handled = true;
- nouveau_namedb_put(bind);
- }
- break;
- }
-
-out:
- spin_unlock_irqrestore(&priv->base.lock, flags);
- return handled;
-}
-
-static void
-nv04_fifo_cache_error(struct nouveau_device *device,
- struct nv04_fifo_priv *priv, u32 chid, u32 get)
-{
- u32 mthd, data;
- int ptr;
-
- /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my
- * G80 chips, but CACHE1 isn't big enough for this much data.. Tests
- * show that it wraps around to the start at GET=0x800.. No clue as to
- * why..
- */
- ptr = (get & 0x7ff) >> 2;
-
- if (device->card_type < NV_40) {
- mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr));
- data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr));
- } else {
- mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr));
- data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr));
- }
-
- if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
- const char *client_name =
- nouveau_client_name_for_fifo_chid(&priv->base, chid);
- nv_error(priv,
- "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
- chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc,
- data);
- }
-
- nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
- nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
- nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
- nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
- nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
- nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
-
- nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
- nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
-}
-
-static void
-nv04_fifo_dma_pusher(struct nouveau_device *device, struct nv04_fifo_priv *priv,
- u32 chid)
-{
- const char *client_name;
- u32 dma_get = nv_rd32(priv, 0x003244);
- u32 dma_put = nv_rd32(priv, 0x003240);
- u32 push = nv_rd32(priv, 0x003220);
- u32 state = nv_rd32(priv, 0x003228);
-
- client_name = nouveau_client_name_for_fifo_chid(&priv->base, chid);
-
- if (device->card_type == NV_50) {
- u32 ho_get = nv_rd32(priv, 0x003328);
- u32 ho_put = nv_rd32(priv, 0x003320);
- u32 ib_get = nv_rd32(priv, 0x003334);
- u32 ib_put = nv_rd32(priv, 0x003330);
-
- nv_error(priv,
- "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
- chid, client_name, ho_get, dma_get, ho_put, dma_put,
- ib_get, ib_put, state, nv_dma_state_err(state), push);
-
- /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
- nv_wr32(priv, 0x003364, 0x00000000);
- if (dma_get != dma_put || ho_get != ho_put) {
- nv_wr32(priv, 0x003244, dma_put);
- nv_wr32(priv, 0x003328, ho_put);
- } else
- if (ib_get != ib_put)
- nv_wr32(priv, 0x003334, ib_put);
- } else {
- nv_error(priv,
- "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
- chid, client_name, dma_get, dma_put, state,
- nv_dma_state_err(state), push);
-
- if (dma_get != dma_put)
- nv_wr32(priv, 0x003244, dma_put);
- }
-
- nv_wr32(priv, 0x003228, 0x00000000);
- nv_wr32(priv, 0x003220, 0x00000001);
- nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
-}
-
-void
-nv04_fifo_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_device *device = nv_device(subdev);
- struct nv04_fifo_priv *priv = (void *)subdev;
- uint32_t status, reassign;
- int cnt = 0;
-
- reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
- while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
- uint32_t chid, get;
-
- nv_wr32(priv, NV03_PFIFO_CACHES, 0);
-
- chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
- get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
-
- if (status & NV_PFIFO_INTR_CACHE_ERROR) {
- nv04_fifo_cache_error(device, priv, chid, get);
- status &= ~NV_PFIFO_INTR_CACHE_ERROR;
- }
-
- if (status & NV_PFIFO_INTR_DMA_PUSHER) {
- nv04_fifo_dma_pusher(device, priv, chid);
- status &= ~NV_PFIFO_INTR_DMA_PUSHER;
- }
-
- if (status & NV_PFIFO_INTR_SEMAPHORE) {
- uint32_t sem;
-
- status &= ~NV_PFIFO_INTR_SEMAPHORE;
- nv_wr32(priv, NV03_PFIFO_INTR_0,
- NV_PFIFO_INTR_SEMAPHORE);
-
- sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
- nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
- }
-
- if (device->card_type == NV_50) {
- if (status & 0x00000010) {
- status &= ~0x00000010;
- nv_wr32(priv, 0x002100, 0x00000010);
- }
-
- if (status & 0x40000000) {
- nv_wr32(priv, 0x002100, 0x40000000);
- nouveau_fifo_uevent(&priv->base);
- status &= ~0x40000000;
- }
- }
-
- if (status) {
- nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
- status, chid);
- nv_wr32(priv, NV03_PFIFO_INTR_0, status);
- status = 0;
- }
-
- nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
- }
-
- if (status) {
- nv_error(priv, "still angry after %d spins, halt\n", cnt);
- nv_wr32(priv, 0x002140, 0);
- nv_wr32(priv, 0x000140, 0);
- }
-
- nv_wr32(priv, 0x000100, 0x00000100);
-}
-
-static int
-nv04_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_instmem_priv *imem = nv04_instmem(parent);
- struct nv04_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 0, 15, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nouveau_ramht_ref(imem->ramht, &priv->ramht);
- nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
- nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nv04_fifo_intr;
- nv_engine(priv)->cclass = &nv04_fifo_cclass;
- nv_engine(priv)->sclass = nv04_fifo_sclass;
- priv->base.pause = nv04_fifo_pause;
- priv->base.start = nv04_fifo_start;
- priv->ramfc_desc = nv04_ramfc;
- return 0;
-}
-
-void
-nv04_fifo_dtor(struct nouveau_object *object)
-{
- struct nv04_fifo_priv *priv = (void *)object;
- nouveau_gpuobj_ref(NULL, &priv->ramfc);
- nouveau_gpuobj_ref(NULL, &priv->ramro);
- nouveau_ramht_ref(NULL, &priv->ramht);
- nouveau_fifo_destroy(&priv->base);
-}
-
-int
-nv04_fifo_init(struct nouveau_object *object)
-{
- struct nv04_fifo_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fifo_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
- nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
-
- nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((priv->ramht->bits - 9) << 16) |
- (priv->ramht->base.addr >> 8));
- nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
- nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-
- nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
- nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
- nv_wr32(priv, NV03_PFIFO_CACHES, 1);
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fifo_ctor,
- .dtor = nv04_fifo_dtor,
- .init = nv04_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
deleted file mode 100644
index 496a4b4fdfaf..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv04.h
+++ /dev/null
@@ -1,178 +0,0 @@
-#ifndef __NV04_FIFO_H__
-#define __NV04_FIFO_H__
-
-#include <engine/fifo.h>
-
-#define NV04_PFIFO_DELAY_0 0x00002040
-#define NV04_PFIFO_DMA_TIMESLICE 0x00002044
-#define NV04_PFIFO_NEXT_CHANNEL 0x00002050
-#define NV03_PFIFO_INTR_0 0x00002100
-#define NV03_PFIFO_INTR_EN_0 0x00002140
-# define NV_PFIFO_INTR_CACHE_ERROR (1<<0)
-# define NV_PFIFO_INTR_RUNOUT (1<<4)
-# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8)
-# define NV_PFIFO_INTR_DMA_PUSHER (1<<12)
-# define NV_PFIFO_INTR_DMA_PT (1<<16)
-# define NV_PFIFO_INTR_SEMAPHORE (1<<20)
-# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24)
-#define NV03_PFIFO_RAMHT 0x00002210
-#define NV03_PFIFO_RAMFC 0x00002214
-#define NV03_PFIFO_RAMRO 0x00002218
-#define NV40_PFIFO_RAMFC 0x00002220
-#define NV03_PFIFO_CACHES 0x00002500
-#define NV04_PFIFO_MODE 0x00002504
-#define NV04_PFIFO_DMA 0x00002508
-#define NV04_PFIFO_SIZE 0x0000250c
-#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4)
-#define NV50_PFIFO_CTX_TABLE__SIZE 128
-#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31)
-#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30)
-#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF
-#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF
-#define NV03_PFIFO_CACHE0_PUSH0 0x00003000
-#define NV03_PFIFO_CACHE0_PULL0 0x00003040
-#define NV04_PFIFO_CACHE0_PULL0 0x00003050
-#define NV04_PFIFO_CACHE0_PULL1 0x00003054
-#define NV03_PFIFO_CACHE1_PUSH0 0x00003200
-#define NV03_PFIFO_CACHE1_PUSH1 0x00003204
-#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8)
-#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16)
-#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f
-#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f
-#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f
-#define NV03_PFIFO_CACHE1_PUT 0x00003210
-#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220
-#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0
-# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000
-# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000
-# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000
-# define NV_PFIFO_CACHE1_ENDIAN 0x80000000
-# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF
-# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000
-#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228
-#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c
-#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230
-#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240
-#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244
-#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248
-#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C
-#define NV03_PFIFO_CACHE1_PULL0 0x00003240
-#define NV04_PFIFO_CACHE1_PULL0 0x00003250
-# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010
-# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000
-#define NV03_PFIFO_CACHE1_PULL1 0x00003250
-#define NV04_PFIFO_CACHE1_PULL1 0x00003254
-#define NV04_PFIFO_CACHE1_HASH 0x00003258
-#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260
-#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264
-#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268
-#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C
-#define NV03_PFIFO_CACHE1_GET 0x00003270
-#define NV04_PFIFO_CACHE1_ENGINE 0x00003280
-#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
-#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0
-#define NV40_PFIFO_UNK32E4 0x000032E4
-#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8))
-#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8))
-#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8))
-#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8))
-
-struct ramfc_desc {
- unsigned bits:6;
- unsigned ctxs:5;
- unsigned ctxp:8;
- unsigned regs:5;
- unsigned regp;
-};
-
-struct nv04_fifo_priv {
- struct nouveau_fifo base;
- struct ramfc_desc *ramfc_desc;
- struct nouveau_ramht *ramht;
- struct nouveau_gpuobj *ramro;
- struct nouveau_gpuobj *ramfc;
-};
-
-struct nv04_fifo_base {
- struct nouveau_fifo_base base;
-};
-
-struct nv04_fifo_chan {
- struct nouveau_fifo_chan base;
- u32 subc[8];
- u32 ramfc;
-};
-
-int nv04_fifo_object_attach(struct nouveau_object *,
- struct nouveau_object *, u32);
-void nv04_fifo_object_detach(struct nouveau_object *, int);
-
-void nv04_fifo_chan_dtor(struct nouveau_object *);
-int nv04_fifo_chan_init(struct nouveau_object *);
-int nv04_fifo_chan_fini(struct nouveau_object *, bool suspend);
-
-int nv04_fifo_context_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-void nv04_fifo_dtor(struct nouveau_object *);
-int nv04_fifo_init(struct nouveau_object *);
-void nv04_fifo_pause(struct nouveau_fifo *, unsigned long *);
-void nv04_fifo_start(struct nouveau_fifo *, unsigned long *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
deleted file mode 100644
index 2a32add51c81..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv10.c
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv10_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
- { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
- {}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv10_fifo_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo_priv *priv = (void *)engine;
- struct nv04_fifo_chan *chan;
- int ret;
-
- nv_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
- "offset %016llx\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
- 0x10000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->object_attach = nv04_fifo_object_attach;
- nv_parent(chan)->object_detach = nv04_fifo_object_detach;
- nv_parent(chan)->context_attach = nv04_fifo_context_attach;
- chan->ramfc = chan->base.chid * 32;
-
- nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
- nv_wo32(priv->ramfc, chan->ramfc + 0x14,
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv10_fifo_ofuncs = {
- .ctor = nv10_fifo_chan_ctor,
- .dtor = nv04_fifo_chan_dtor,
- .init = nv04_fifo_chan_init,
- .fini = nv04_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv10_fifo_sclass[] = {
- { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv10_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0x10),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fifo_context_ctor,
- .dtor = _nouveau_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv10_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_instmem_priv *imem = nv04_instmem(parent);
- struct nv04_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nouveau_ramht_ref(imem->ramht, &priv->ramht);
- nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
- nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nv04_fifo_intr;
- nv_engine(priv)->cclass = &nv10_fifo_cclass;
- nv_engine(priv)->sclass = nv10_fifo_sclass;
- priv->base.pause = nv04_fifo_pause;
- priv->base.start = nv04_fifo_start;
- priv->ramfc_desc = nv10_ramfc;
- return 0;
-}
-
-struct nouveau_oclass *
-nv10_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0x10),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv10_fifo_ctor,
- .dtor = nv04_fifo_dtor,
- .init = nv04_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c
deleted file mode 100644
index 09362a51ba57..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv108.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nve0.h"
-
-struct nouveau_oclass *
-nv108_fifo_oclass = &(struct nve0_fifo_impl) {
- .base.handle = NV_ENGINE(FIFO, 0x08),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_fifo_ctor,
- .dtor = nve0_fifo_dtor,
- .init = nve0_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
- .channels = 1024,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
deleted file mode 100644
index 12d76c8adb23..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv17.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv17_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
- { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
- { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
- { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
- { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
- { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
- { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
- {}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv17_fifo_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo_priv *priv = (void *)engine;
- struct nv04_fifo_chan *chan;
- int ret;
-
- nv_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
- "offset %016llx\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
- 0x10000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */
- &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->object_attach = nv04_fifo_object_attach;
- nv_parent(chan)->object_detach = nv04_fifo_object_detach;
- nv_parent(chan)->context_attach = nv04_fifo_context_attach;
- chan->ramfc = chan->base.chid * 64;
-
- nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
- nv_wo32(priv->ramfc, chan->ramfc + 0x14,
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv17_fifo_ofuncs = {
- .ctor = nv17_fifo_chan_ctor,
- .dtor = nv04_fifo_chan_dtor,
- .init = nv04_fifo_chan_init,
- .fini = nv04_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv17_fifo_sclass[] = {
- { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv17_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0x17),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fifo_context_ctor,
- .dtor = _nouveau_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv17_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_instmem_priv *imem = nv04_instmem(parent);
- struct nv04_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nouveau_ramht_ref(imem->ramht, &priv->ramht);
- nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
- nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nv04_fifo_intr;
- nv_engine(priv)->cclass = &nv17_fifo_cclass;
- nv_engine(priv)->sclass = nv17_fifo_sclass;
- priv->base.pause = nv04_fifo_pause;
- priv->base.start = nv04_fifo_start;
- priv->ramfc_desc = nv17_ramfc;
- return 0;
-}
-
-static int
-nv17_fifo_init(struct nouveau_object *object)
-{
- struct nv04_fifo_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fifo_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
- nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
-
- nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((priv->ramht->bits - 9) << 16) |
- (priv->ramht->base.addr >> 8));
- nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
- nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-
- nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
- nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
- nv_wr32(priv, NV03_PFIFO_CACHES, 1);
- return 0;
-}
-
-struct nouveau_oclass *
-nv17_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0x17),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv17_fifo_ctor,
- .dtor = nv04_fifo_dtor,
- .init = nv17_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
deleted file mode 100644
index 9f49c3a24dc6..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv40.c
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-
-#include <subdev/instmem.h>
-#include <subdev/instmem/nv04.h>
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-
-#include "nv04.h"
-
-static struct ramfc_desc
-nv40_ramfc[] = {
- { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
- { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
- { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
- { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
- { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
- { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
- { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
- { 2, 28, 0x18, 28, 0x002058 },
- { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
- { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
- { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
- { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
- { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
- { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
- { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
- { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
- { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
- { 32, 0, 0x40, 0, 0x0032e4 },
- { 32, 0, 0x44, 0, 0x0032e8 },
- { 32, 0, 0x4c, 0, 0x002088 },
- { 32, 0, 0x50, 0, 0x003300 },
- { 32, 0, 0x54, 0, 0x00330c },
- {}
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv40_fifo_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 handle)
-{
- struct nv04_fifo_priv *priv = (void *)parent->engine;
- struct nv04_fifo_chan *chan = (void *)parent;
- u32 context, chid = chan->base.chid;
- int ret;
-
- if (nv_iclass(object, NV_GPUOBJ_CLASS))
- context = nv_gpuobj(object)->addr >> 4;
- else
- context = 0x00000004; /* just non-zero */
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_DMAOBJ:
- case NVDEV_ENGINE_SW:
- context |= 0x00000000;
- break;
- case NVDEV_ENGINE_GR:
- context |= 0x00100000;
- break;
- case NVDEV_ENGINE_MPEG:
- context |= 0x00200000;
- break;
- default:
- return -EINVAL;
- }
-
- context |= chid << 23;
-
- mutex_lock(&nv_subdev(priv)->mutex);
- ret = nouveau_ramht_insert(priv->ramht, chid, handle, context);
- mutex_unlock(&nv_subdev(priv)->mutex);
- return ret;
-}
-
-static int
-nv40_fifo_context_attach(struct nouveau_object *parent,
- struct nouveau_object *engctx)
-{
- struct nv04_fifo_priv *priv = (void *)parent->engine;
- struct nv04_fifo_chan *chan = (void *)parent;
- unsigned long flags;
- u32 reg, ctx;
-
- switch (nv_engidx(engctx->engine)) {
- case NVDEV_ENGINE_SW:
- return 0;
- case NVDEV_ENGINE_GR:
- reg = 0x32e0;
- ctx = 0x38;
- break;
- case NVDEV_ENGINE_MPEG:
- reg = 0x330c;
- ctx = 0x54;
- break;
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&priv->base.lock, flags);
- nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4;
- nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
-
- if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
- nv_wr32(priv, reg, nv_engctx(engctx)->addr);
- nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr);
-
- nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&priv->base.lock, flags);
- return 0;
-}
-
-static int
-nv40_fifo_context_detach(struct nouveau_object *parent, bool suspend,
- struct nouveau_object *engctx)
-{
- struct nv04_fifo_priv *priv = (void *)parent->engine;
- struct nv04_fifo_chan *chan = (void *)parent;
- unsigned long flags;
- u32 reg, ctx;
-
- switch (nv_engidx(engctx->engine)) {
- case NVDEV_ENGINE_SW:
- return 0;
- case NVDEV_ENGINE_GR:
- reg = 0x32e0;
- ctx = 0x38;
- break;
- case NVDEV_ENGINE_MPEG:
- reg = 0x330c;
- ctx = 0x54;
- break;
- default:
- return -EINVAL;
- }
-
- spin_lock_irqsave(&priv->base.lock, flags);
- nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
-
- if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
- nv_wr32(priv, reg, 0x00000000);
- nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
-
- nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&priv->base.lock, flags);
- return 0;
-}
-
-static int
-nv40_fifo_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nv04_fifo_priv *priv = (void *)engine;
- struct nv04_fifo_chan *chan;
- int ret;
-
- nv_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
- "offset %016llx\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
- 0x1000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->context_attach = nv40_fifo_context_attach;
- nv_parent(chan)->context_detach = nv40_fifo_context_detach;
- nv_parent(chan)->object_attach = nv40_fifo_object_attach;
- nv_parent(chan)->object_detach = nv04_fifo_object_detach;
- chan->ramfc = chan->base.chid * 128;
-
- nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
- nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
- nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
- NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
- NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
-#ifdef __BIG_ENDIAN
- NV_PFIFO_CACHE1_BIG_ENDIAN |
-#endif
- NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
- nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv40_fifo_ofuncs = {
- .ctor = nv40_fifo_chan_ctor,
- .dtor = nv04_fifo_chan_dtor,
- .init = nv04_fifo_chan_init,
- .fini = nv04_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv40_fifo_sclass[] = {
- { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv40_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fifo_context_ctor,
- .dtor = _nouveau_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv40_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_instmem_priv *imem = nv04_instmem(parent);
- struct nv04_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 0, 31, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nouveau_ramht_ref(imem->ramht, &priv->ramht);
- nouveau_gpuobj_ref(imem->ramro, &priv->ramro);
- nouveau_gpuobj_ref(imem->ramfc, &priv->ramfc);
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nv04_fifo_intr;
- nv_engine(priv)->cclass = &nv40_fifo_cclass;
- nv_engine(priv)->sclass = nv40_fifo_sclass;
- priv->base.pause = nv04_fifo_pause;
- priv->base.start = nv04_fifo_start;
- priv->ramfc_desc = nv40_ramfc;
- return 0;
-}
-
-static int
-nv40_fifo_init(struct nouveau_object *object)
-{
- struct nv04_fifo_priv *priv = (void *)object;
- struct nouveau_fb *pfb = nouveau_fb(object);
- int ret;
-
- ret = nouveau_fifo_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x002040, 0x000000ff);
- nv_wr32(priv, 0x002044, 0x2101ffff);
- nv_wr32(priv, 0x002058, 0x00000001);
-
- nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
- ((priv->ramht->bits - 9) << 16) |
- (priv->ramht->base.addr >> 8));
- nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
-
- switch (nv_device(priv)->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- nv_wr32(priv, 0x002230, 0x00000001);
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x45:
- case 0x48:
- nv_wr32(priv, 0x002220, 0x00030002);
- break;
- default:
- nv_wr32(priv, 0x002230, 0x00000000);
- nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
- priv->ramfc->addr) >> 16) |
- 0x00030000);
- break;
- }
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
-
- nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
- nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
-
- nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
- nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
- nv_wr32(priv, NV03_PFIFO_CACHES, 1);
- return 0;
-}
-
-struct nouveau_oclass *
-nv40_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_fifo_ctor,
- .dtor = nv04_fifo_dtor,
- .init = nv40_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
deleted file mode 100644
index 5d1e86bc244c..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.c
+++ /dev/null
@@ -1,541 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-#include "nv04.h"
-#include "nv50.h"
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static void
-nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
-{
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nouveau_gpuobj *cur;
- int i, p;
-
- cur = priv->playlist[priv->cur_playlist];
- priv->cur_playlist = !priv->cur_playlist;
-
- for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
- if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
- nv_wo32(cur, p++ * 4, i);
- }
-
- bar->flush(bar);
-
- nv_wr32(priv, 0x0032f4, cur->addr >> 12);
- nv_wr32(priv, 0x0032ec, p);
- nv_wr32(priv, 0x002500, 0x00000101);
-}
-
-void
-nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
-{
- mutex_lock(&nv_subdev(priv)->mutex);
- nv50_fifo_playlist_update_locked(priv);
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nv50_fifo_context_attach(struct nouveau_object *parent,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_base *base = (void *)parent->parent;
- struct nouveau_gpuobj *ectx = (void *)object;
- u64 limit = ectx->addr + ectx->size - 1;
- u64 start = ectx->addr;
- u32 addr;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR : addr = 0x0000; break;
- case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
- default:
- return -EINVAL;
- }
-
- nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
- nv_wo32(base->eng, addr + 0x00, 0x00190000);
- nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
- nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
- nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
- upper_32_bits(start));
- nv_wo32(base->eng, addr + 0x10, 0x00000000);
- nv_wo32(base->eng, addr + 0x14, 0x00000000);
- bar->flush(bar);
- return 0;
-}
-
-static int
-nv50_fifo_context_detach(struct nouveau_object *parent, bool suspend,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_priv *priv = (void *)parent->engine;
- struct nv50_fifo_base *base = (void *)parent->parent;
- struct nv50_fifo_chan *chan = (void *)parent;
- u32 addr, me;
- int ret = 0;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR : addr = 0x0000; break;
- case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
- default:
- return -EINVAL;
- }
-
- /* HW bug workaround:
- *
- * PFIFO will hang forever if the connected engines don't report
- * that they've processed the context switch request.
- *
- * In order for the kickoff to work, we need to ensure all the
- * connected engines are in a state where they can answer.
- *
- * Newer chipsets don't seem to suffer from this issue, and well,
- * there's also a "ignore these engines" bitmask reg we can use
- * if we hit the issue there..
- */
- me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
-
- /* do the kickoff... */
- nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
- if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
- nv_error(priv, "channel %d [%s] unload timeout\n",
- chan->base.chid, nouveau_client_name(chan));
- if (suspend)
- ret = -EBUSY;
- }
- nv_wr32(priv, 0x00b860, me);
-
- if (ret == 0) {
- nv_wo32(base->eng, addr + 0x00, 0x00000000);
- nv_wo32(base->eng, addr + 0x04, 0x00000000);
- nv_wo32(base->eng, addr + 0x08, 0x00000000);
- nv_wo32(base->eng, addr + 0x0c, 0x00000000);
- nv_wo32(base->eng, addr + 0x10, 0x00000000);
- nv_wo32(base->eng, addr + 0x14, 0x00000000);
- bar->flush(bar);
- }
-
- return ret;
-}
-
-static int
-nv50_fifo_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 handle)
-{
- struct nv50_fifo_chan *chan = (void *)parent;
- u32 context;
-
- if (nv_iclass(object, NV_GPUOBJ_CLASS))
- context = nv_gpuobj(object)->node->offset >> 4;
- else
- context = 0x00000004; /* just non-zero */
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_DMAOBJ:
- case NVDEV_ENGINE_SW : context |= 0x00000000; break;
- case NVDEV_ENGINE_GR : context |= 0x00100000; break;
- case NVDEV_ENGINE_MPEG : context |= 0x00200000; break;
- default:
- return -EINVAL;
- }
-
- return nouveau_ramht_insert(chan->ramht, 0, handle, context);
-}
-
-void
-nv50_fifo_object_detach(struct nouveau_object *parent, int cookie)
-{
- struct nv50_fifo_chan *chan = (void *)parent;
- nouveau_ramht_remove(chan->ramht, cookie);
-}
-
-static int
-nv50_fifo_chan_ctor_dma(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_base *base = (void *)parent;
- struct nv50_fifo_chan *chan;
- int ret;
-
- nv_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
- "offset %016llx\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
- 0x2000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->context_attach = nv50_fifo_context_attach;
- nv_parent(chan)->context_detach = nv50_fifo_context_detach;
- nv_parent(chan)->object_attach = nv50_fifo_object_attach;
- nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
- ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
- &chan->ramht);
- if (ret)
- return ret;
-
- nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x3c, 0x003f6078);
- nv_wo32(base->ramfc, 0x44, 0x01003fff);
- nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
- nv_wo32(base->ramfc, 0x4c, 0xffffffff);
- nv_wo32(base->ramfc, 0x60, 0x7fffffff);
- nv_wo32(base->ramfc, 0x78, 0x00000000);
- nv_wo32(base->ramfc, 0x7c, 0x30000001);
- nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->base.node->offset >> 4));
- bar->flush(bar);
- return 0;
-}
-
-static int
-nv50_fifo_chan_ctor_ind(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_channel_gpfifo_v0 v0;
- } *args = data;
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_base *base = (void *)parent;
- struct nv50_fifo_chan *chan;
- u64 ioffset, ilength;
- int ret;
-
- nv_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
- "ioffset %016llx ilength %08x\n",
- args->v0.version, args->v0.pushbuf, args->v0.ioffset,
- args->v0.ilength);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
- 0x2000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->context_attach = nv50_fifo_context_attach;
- nv_parent(chan)->context_detach = nv50_fifo_context_detach;
- nv_parent(chan)->object_attach = nv50_fifo_object_attach;
- nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
- ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
- &chan->ramht);
- if (ret)
- return ret;
-
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- nv_wo32(base->ramfc, 0x3c, 0x403f6078);
- nv_wo32(base->ramfc, 0x44, 0x01003fff);
- nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
- nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
- nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
- nv_wo32(base->ramfc, 0x60, 0x7fffffff);
- nv_wo32(base->ramfc, 0x78, 0x00000000);
- nv_wo32(base->ramfc, 0x7c, 0x30000001);
- nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->base.node->offset >> 4));
- bar->flush(bar);
- return 0;
-}
-
-void
-nv50_fifo_chan_dtor(struct nouveau_object *object)
-{
- struct nv50_fifo_chan *chan = (void *)object;
- nouveau_ramht_ref(NULL, &chan->ramht);
- nouveau_fifo_channel_destroy(&chan->base);
-}
-
-static int
-nv50_fifo_chan_init(struct nouveau_object *object)
-{
- struct nv50_fifo_priv *priv = (void *)object->engine;
- struct nv50_fifo_base *base = (void *)object->parent;
- struct nv50_fifo_chan *chan = (void *)object;
- struct nouveau_gpuobj *ramfc = base->ramfc;
- u32 chid = chan->base.chid;
- int ret;
-
- ret = nouveau_fifo_channel_init(&chan->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
- nv50_fifo_playlist_update(priv);
- return 0;
-}
-
-int
-nv50_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_fifo_priv *priv = (void *)object->engine;
- struct nv50_fifo_chan *chan = (void *)object;
- u32 chid = chan->base.chid;
-
- /* remove channel from playlist, fifo will unload context */
- nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
- nv50_fifo_playlist_update(priv);
- nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
-
- return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nv50_fifo_ofuncs_dma = {
- .ctor = nv50_fifo_chan_ctor_dma,
- .dtor = nv50_fifo_chan_dtor,
- .init = nv50_fifo_chan_init,
- .fini = nv50_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_ofuncs
-nv50_fifo_ofuncs_ind = {
- .ctor = nv50_fifo_chan_ctor_ind,
- .dtor = nv50_fifo_chan_dtor,
- .init = nv50_fifo_chan_init,
- .fini = nv50_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv50_fifo_sclass[] = {
- { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma },
- { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static int
-nv50_fifo_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_fifo_base *base;
- int ret;
-
- ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
- 0x1000, NVOBJ_FLAG_HEAP, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0,
- NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0,
- &base->pgd);
- if (ret)
- return ret;
-
- ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-void
-nv50_fifo_context_dtor(struct nouveau_object *object)
-{
- struct nv50_fifo_base *base = (void *)object;
- nouveau_vm_ref(NULL, &base->vm, base->pgd);
- nouveau_gpuobj_ref(NULL, &base->pgd);
- nouveau_gpuobj_ref(NULL, &base->eng);
- nouveau_gpuobj_ref(NULL, &base->ramfc);
- nouveau_gpuobj_ref(NULL, &base->cache);
- nouveau_fifo_context_destroy(&base->base);
-}
-
-static struct nouveau_oclass
-nv50_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fifo_context_ctor,
- .dtor = nv50_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static int
-nv50_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
- &priv->playlist[0]);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
- &priv->playlist[1]);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nv04_fifo_intr;
- nv_engine(priv)->cclass = &nv50_fifo_cclass;
- nv_engine(priv)->sclass = nv50_fifo_sclass;
- priv->base.pause = nv04_fifo_pause;
- priv->base.start = nv04_fifo_start;
- return 0;
-}
-
-void
-nv50_fifo_dtor(struct nouveau_object *object)
-{
- struct nv50_fifo_priv *priv = (void *)object;
-
- nouveau_gpuobj_ref(NULL, &priv->playlist[1]);
- nouveau_gpuobj_ref(NULL, &priv->playlist[0]);
-
- nouveau_fifo_destroy(&priv->base);
-}
-
-int
-nv50_fifo_init(struct nouveau_object *object)
-{
- struct nv50_fifo_priv *priv = (void *)object;
- int ret, i;
-
- ret = nouveau_fifo_init(&priv->base);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
- nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
- nv_wr32(priv, 0x00250c, 0x6f3cfc34);
- nv_wr32(priv, 0x002044, 0x01003fff);
-
- nv_wr32(priv, 0x002100, 0xffffffff);
- nv_wr32(priv, 0x002140, 0xbfffffff);
-
- for (i = 0; i < 128; i++)
- nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
- nv50_fifo_playlist_update_locked(priv);
-
- nv_wr32(priv, 0x003200, 0x00000001);
- nv_wr32(priv, 0x003250, 0x00000001);
- nv_wr32(priv, 0x002500, 0x00000001);
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fifo_ctor,
- .dtor = nv50_fifo_dtor,
- .init = nv50_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
deleted file mode 100644
index 3a9ceb315c20..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv50.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __NV50_FIFO_H__
-#define __NV50_FIFO_H__
-
-struct nv50_fifo_priv {
- struct nouveau_fifo base;
- struct nouveau_gpuobj *playlist[2];
- int cur_playlist;
-};
-
-struct nv50_fifo_base {
- struct nouveau_fifo_base base;
- struct nouveau_gpuobj *ramfc;
- struct nouveau_gpuobj *cache;
- struct nouveau_gpuobj *eng;
- struct nouveau_gpuobj *pgd;
- struct nouveau_vm *vm;
-};
-
-struct nv50_fifo_chan {
- struct nouveau_fifo_chan base;
- u32 subc[8];
- struct nouveau_ramht *ramht;
-};
-
-void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
-
-void nv50_fifo_object_detach(struct nouveau_object *, int);
-void nv50_fifo_chan_dtor(struct nouveau_object *);
-int nv50_fifo_chan_fini(struct nouveau_object *, bool);
-
-void nv50_fifo_context_dtor(struct nouveau_object *);
-
-void nv50_fifo_dtor(struct nouveau_object *);
-int nv50_fifo_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
deleted file mode 100644
index 1f42996b354a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nv84.c
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/client.h>
-#include <core/engctx.h>
-#include <core/ramht.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-#include "nv04.h"
-#include "nv50.h"
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static int
-nv84_fifo_context_attach(struct nouveau_object *parent,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_base *base = (void *)parent->parent;
- struct nouveau_gpuobj *ectx = (void *)object;
- u64 limit = ectx->addr + ectx->size - 1;
- u64 start = ectx->addr;
- u32 addr;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR : addr = 0x0020; break;
- case NVDEV_ENGINE_VP : addr = 0x0040; break;
- case NVDEV_ENGINE_PPP :
- case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
- case NVDEV_ENGINE_BSP : addr = 0x0080; break;
- case NVDEV_ENGINE_CRYPT: addr = 0x00a0; break;
- case NVDEV_ENGINE_COPY0: addr = 0x00c0; break;
- default:
- return -EINVAL;
- }
-
- nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
- nv_wo32(base->eng, addr + 0x00, 0x00190000);
- nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
- nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
- nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
- upper_32_bits(start));
- nv_wo32(base->eng, addr + 0x10, 0x00000000);
- nv_wo32(base->eng, addr + 0x14, 0x00000000);
- bar->flush(bar);
- return 0;
-}
-
-static int
-nv84_fifo_context_detach(struct nouveau_object *parent, bool suspend,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_priv *priv = (void *)parent->engine;
- struct nv50_fifo_base *base = (void *)parent->parent;
- struct nv50_fifo_chan *chan = (void *)parent;
- u32 addr, save, engn;
- bool done;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break;
- case NVDEV_ENGINE_VP : engn = 3; addr = 0x0040; break;
- case NVDEV_ENGINE_PPP :
- case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
- case NVDEV_ENGINE_BSP : engn = 5; addr = 0x0080; break;
- case NVDEV_ENGINE_CRYPT: engn = 4; addr = 0x00a0; break;
- case NVDEV_ENGINE_COPY0: engn = 2; addr = 0x00c0; break;
- default:
- return -EINVAL;
- }
-
- save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
- nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
- done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
- nv_wr32(priv, 0x002520, save);
- if (!done) {
- nv_error(priv, "channel %d [%s] unload timeout\n",
- chan->base.chid, nouveau_client_name(chan));
- if (suspend)
- return -EBUSY;
- }
-
- nv_wo32(base->eng, addr + 0x00, 0x00000000);
- nv_wo32(base->eng, addr + 0x04, 0x00000000);
- nv_wo32(base->eng, addr + 0x08, 0x00000000);
- nv_wo32(base->eng, addr + 0x0c, 0x00000000);
- nv_wo32(base->eng, addr + 0x10, 0x00000000);
- nv_wo32(base->eng, addr + 0x14, 0x00000000);
- bar->flush(bar);
- return 0;
-}
-
-static int
-nv84_fifo_object_attach(struct nouveau_object *parent,
- struct nouveau_object *object, u32 handle)
-{
- struct nv50_fifo_chan *chan = (void *)parent;
- u32 context;
-
- if (nv_iclass(object, NV_GPUOBJ_CLASS))
- context = nv_gpuobj(object)->node->offset >> 4;
- else
- context = 0x00000004; /* just non-zero */
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_DMAOBJ:
- case NVDEV_ENGINE_SW : context |= 0x00000000; break;
- case NVDEV_ENGINE_GR : context |= 0x00100000; break;
- case NVDEV_ENGINE_MPEG :
- case NVDEV_ENGINE_PPP : context |= 0x00200000; break;
- case NVDEV_ENGINE_ME :
- case NVDEV_ENGINE_COPY0 : context |= 0x00300000; break;
- case NVDEV_ENGINE_VP : context |= 0x00400000; break;
- case NVDEV_ENGINE_CRYPT :
- case NVDEV_ENGINE_VIC : context |= 0x00500000; break;
- case NVDEV_ENGINE_BSP : context |= 0x00600000; break;
- default:
- return -EINVAL;
- }
-
- return nouveau_ramht_insert(chan->ramht, 0, handle, context);
-}
-
-static int
-nv84_fifo_chan_ctor_dma(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv03_channel_dma_v0 v0;
- } *args = data;
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_base *base = (void *)parent;
- struct nv50_fifo_chan *chan;
- int ret;
-
- nv_ioctl(parent, "create channel dma size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
- "offset %016llx\n", args->v0.version,
- args->v0.pushbuf, args->v0.offset);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
- 0x2000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG) |
- (1ULL << NVDEV_ENGINE_ME) |
- (1ULL << NVDEV_ENGINE_VP) |
- (1ULL << NVDEV_ENGINE_CRYPT) |
- (1ULL << NVDEV_ENGINE_BSP) |
- (1ULL << NVDEV_ENGINE_PPP) |
- (1ULL << NVDEV_ENGINE_COPY0) |
- (1ULL << NVDEV_ENGINE_VIC), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
- &chan->ramht);
- if (ret)
- return ret;
-
- nv_parent(chan)->context_attach = nv84_fifo_context_attach;
- nv_parent(chan)->context_detach = nv84_fifo_context_detach;
- nv_parent(chan)->object_attach = nv84_fifo_object_attach;
- nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
- nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
- nv_wo32(base->ramfc, 0x3c, 0x003f6078);
- nv_wo32(base->ramfc, 0x44, 0x01003fff);
- nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
- nv_wo32(base->ramfc, 0x4c, 0xffffffff);
- nv_wo32(base->ramfc, 0x60, 0x7fffffff);
- nv_wo32(base->ramfc, 0x78, 0x00000000);
- nv_wo32(base->ramfc, 0x7c, 0x30000001);
- nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->base.node->offset >> 4));
- nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
- nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
- bar->flush(bar);
- return 0;
-}
-
-static int
-nv84_fifo_chan_ctor_ind(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_channel_gpfifo_v0 v0;
- } *args = data;
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_fifo_base *base = (void *)parent;
- struct nv50_fifo_chan *chan;
- u64 ioffset, ilength;
- int ret;
-
- nv_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
- "ioffset %016llx ilength %08x\n",
- args->v0.version, args->v0.pushbuf, args->v0.ioffset,
- args->v0.ilength);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
- 0x2000, args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_DMAOBJ) |
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_MPEG) |
- (1ULL << NVDEV_ENGINE_ME) |
- (1ULL << NVDEV_ENGINE_VP) |
- (1ULL << NVDEV_ENGINE_CRYPT) |
- (1ULL << NVDEV_ENGINE_BSP) |
- (1ULL << NVDEV_ENGINE_PPP) |
- (1ULL << NVDEV_ENGINE_COPY0) |
- (1ULL << NVDEV_ENGINE_VIC), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- ret = nouveau_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
- &chan->ramht);
- if (ret)
- return ret;
-
- nv_parent(chan)->context_attach = nv84_fifo_context_attach;
- nv_parent(chan)->context_detach = nv84_fifo_context_detach;
- nv_parent(chan)->object_attach = nv84_fifo_object_attach;
- nv_parent(chan)->object_detach = nv50_fifo_object_detach;
-
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- nv_wo32(base->ramfc, 0x3c, 0x403f6078);
- nv_wo32(base->ramfc, 0x44, 0x01003fff);
- nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
- nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
- nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
- nv_wo32(base->ramfc, 0x60, 0x7fffffff);
- nv_wo32(base->ramfc, 0x78, 0x00000000);
- nv_wo32(base->ramfc, 0x7c, 0x30000001);
- nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
- (4 << 24) /* SEARCH_FULL */ |
- (chan->ramht->base.node->offset >> 4));
- nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
- nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
- bar->flush(bar);
- return 0;
-}
-
-static int
-nv84_fifo_chan_init(struct nouveau_object *object)
-{
- struct nv50_fifo_priv *priv = (void *)object->engine;
- struct nv50_fifo_base *base = (void *)object->parent;
- struct nv50_fifo_chan *chan = (void *)object;
- struct nouveau_gpuobj *ramfc = base->ramfc;
- u32 chid = chan->base.chid;
- int ret;
-
- ret = nouveau_fifo_channel_init(&chan->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
- nv50_fifo_playlist_update(priv);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv84_fifo_ofuncs_dma = {
- .ctor = nv84_fifo_chan_ctor_dma,
- .dtor = nv50_fifo_chan_dtor,
- .init = nv84_fifo_chan_init,
- .fini = nv50_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_ofuncs
-nv84_fifo_ofuncs_ind = {
- .ctor = nv84_fifo_chan_ctor_ind,
- .dtor = nv50_fifo_chan_dtor,
- .init = nv84_fifo_chan_init,
- .fini = nv50_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nv84_fifo_sclass[] = {
- { G82_CHANNEL_DMA, &nv84_fifo_ofuncs_dma },
- { G82_CHANNEL_GPFIFO, &nv84_fifo_ofuncs_ind },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - basically just the instmem reserved for the channel
- ******************************************************************************/
-
-static int
-nv84_fifo_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_fifo_base *base;
- int ret;
-
- ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
- 0x1000, NVOBJ_FLAG_HEAP, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0,
- NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0,
- 0, &base->pgd);
- if (ret)
- return ret;
-
- ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x1000,
- 0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), nv_object(base), 0x0100,
- 0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static struct nouveau_oclass
-nv84_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_fifo_context_ctor,
- .dtor = nv50_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static void
-nv84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
-}
-
-static void
-nv84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
-}
-
-static const struct nvkm_event_func
-nv84_fifo_uevent_func = {
- .ctor = nouveau_fifo_uevent_ctor,
- .init = nv84_fifo_uevent_init,
- .fini = nv84_fifo_uevent_fini,
-};
-
-static int
-nv84_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 1, 127, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
- &priv->playlist[0]);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
- &priv->playlist[1]);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nv84_fifo_uevent_func, 1, 1, &priv->base.uevent);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nv04_fifo_intr;
- nv_engine(priv)->cclass = &nv84_fifo_cclass;
- nv_engine(priv)->sclass = nv84_fifo_sclass;
- priv->base.pause = nv04_fifo_pause;
- priv->base.start = nv04_fifo_start;
- return 0;
-}
-
-struct nouveau_oclass *
-nv84_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_fifo_ctor,
- .dtor = nv50_fifo_dtor,
- .init = nv50_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
deleted file mode 100644
index 074d434c3077..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nvc0.c
+++ /dev/null
@@ -1,975 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-#include <core/gpuobj.h>
-#include <core/engctx.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include <engine/dmaobj.h>
-#include <engine/fifo.h>
-
-struct nvc0_fifo_priv {
- struct nouveau_fifo base;
-
- struct work_struct fault;
- u64 mask;
-
- struct {
- struct nouveau_gpuobj *mem[2];
- int active;
- wait_queue_head_t wait;
- } runlist;
-
- struct {
- struct nouveau_gpuobj *mem;
- struct nouveau_vma bar;
- } user;
- int spoon_nr;
-};
-
-struct nvc0_fifo_base {
- struct nouveau_fifo_base base;
- struct nouveau_gpuobj *pgd;
- struct nouveau_vm *vm;
-};
-
-struct nvc0_fifo_chan {
- struct nouveau_fifo_chan base;
- enum {
- STOPPED,
- RUNNING,
- KILLED
- } state;
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static void
-nvc0_fifo_runlist_update(struct nvc0_fifo_priv *priv)
-{
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nouveau_gpuobj *cur;
- int i, p;
-
- mutex_lock(&nv_subdev(priv)->mutex);
- cur = priv->runlist.mem[priv->runlist.active];
- priv->runlist.active = !priv->runlist.active;
-
- for (i = 0, p = 0; i < 128; i++) {
- struct nvc0_fifo_chan *chan = (void *)priv->base.channel[i];
- if (chan && chan->state == RUNNING) {
- nv_wo32(cur, p + 0, i);
- nv_wo32(cur, p + 4, 0x00000004);
- p += 8;
- }
- }
- bar->flush(bar);
-
- nv_wr32(priv, 0x002270, cur->addr >> 12);
- nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
-
- if (wait_event_timeout(priv->runlist.wait,
- !(nv_rd32(priv, 0x00227c) & 0x00100000),
- msecs_to_jiffies(2000)) == 0)
- nv_error(priv, "runlist update timeout\n");
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nvc0_fifo_context_attach(struct nouveau_object *parent,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nvc0_fifo_base *base = (void *)parent->parent;
- struct nouveau_engctx *ectx = (void *)object;
- u32 addr;
- int ret;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR : addr = 0x0210; break;
- case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
- case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
- default:
- return -EINVAL;
- }
-
- if (!ectx->vma.node) {
- ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
- NV_MEM_ACCESS_RW, &ectx->vma);
- if (ret)
- return ret;
-
- nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
- }
-
- nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
- nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
- bar->flush(bar);
- return 0;
-}
-
-static int
-nvc0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nvc0_fifo_priv *priv = (void *)parent->engine;
- struct nvc0_fifo_base *base = (void *)parent->parent;
- struct nvc0_fifo_chan *chan = (void *)parent;
- u32 addr;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_GR : addr = 0x0210; break;
- case NVDEV_ENGINE_COPY0: addr = 0x0230; break;
- case NVDEV_ENGINE_COPY1: addr = 0x0240; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
- default:
- return -EINVAL;
- }
-
- nv_wr32(priv, 0x002634, chan->base.chid);
- if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
- nv_error(priv, "channel %d [%s] kick timeout\n",
- chan->base.chid, nouveau_client_name(chan));
- if (suspend)
- return -EBUSY;
- }
-
- nv_wo32(base, addr + 0x00, 0x00000000);
- nv_wo32(base, addr + 0x04, 0x00000000);
- bar->flush(bar);
- return 0;
-}
-
-static int
-nvc0_fifo_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nv50_channel_gpfifo_v0 v0;
- } *args = data;
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nvc0_fifo_priv *priv = (void *)engine;
- struct nvc0_fifo_base *base = (void *)parent;
- struct nvc0_fifo_chan *chan;
- u64 usermem, ioffset, ilength;
- int ret, i;
-
- nv_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
- "ioffset %016llx ilength %08x\n",
- args->v0.version, args->v0.pushbuf, args->v0.ioffset,
- args->v0.ilength);
- } else
- return ret;
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
- priv->user.bar.offset, 0x1000,
- args->v0.pushbuf,
- (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_GR) |
- (1ULL << NVDEV_ENGINE_COPY0) |
- (1ULL << NVDEV_ENGINE_COPY1) |
- (1ULL << NVDEV_ENGINE_BSP) |
- (1ULL << NVDEV_ENGINE_VP) |
- (1ULL << NVDEV_ENGINE_PPP), &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->context_attach = nvc0_fifo_context_attach;
- nv_parent(chan)->context_detach = nvc0_fifo_context_detach;
-
- usermem = chan->base.chid * 0x1000;
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- for (i = 0; i < 0x1000; i += 4)
- nv_wo32(priv->user.mem, usermem + i, 0x00000000);
-
- nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
- nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
- nv_wo32(base, 0x10, 0x0000face);
- nv_wo32(base, 0x30, 0xfffff902);
- nv_wo32(base, 0x48, lower_32_bits(ioffset));
- nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
- nv_wo32(base, 0x54, 0x00000002);
- nv_wo32(base, 0x84, 0x20400000);
- nv_wo32(base, 0x94, 0x30000001);
- nv_wo32(base, 0x9c, 0x00000100);
- nv_wo32(base, 0xa4, 0x1f1f1f1f);
- nv_wo32(base, 0xa8, 0x1f1f1f1f);
- nv_wo32(base, 0xac, 0x0000001f);
- nv_wo32(base, 0xb8, 0xf8000000);
- nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
- nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
- bar->flush(bar);
- return 0;
-}
-
-static int
-nvc0_fifo_chan_init(struct nouveau_object *object)
-{
- struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
- struct nvc0_fifo_priv *priv = (void *)object->engine;
- struct nvc0_fifo_chan *chan = (void *)object;
- u32 chid = chan->base.chid;
- int ret;
-
- ret = nouveau_fifo_channel_init(&chan->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
-
- if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
- nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
- nvc0_fifo_runlist_update(priv);
- }
-
- return 0;
-}
-
-static void nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv);
-
-static int
-nvc0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvc0_fifo_priv *priv = (void *)object->engine;
- struct nvc0_fifo_chan *chan = (void *)object;
- u32 chid = chan->base.chid;
-
- if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
- nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
- nvc0_fifo_runlist_update(priv);
- }
-
- nvc0_fifo_intr_engine(priv);
-
- nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
- return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nvc0_fifo_ofuncs = {
- .ctor = nvc0_fifo_chan_ctor,
- .dtor = _nouveau_fifo_channel_dtor,
- .init = nvc0_fifo_chan_init,
- .fini = nvc0_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nvc0_fifo_sclass[] = {
- { FERMI_CHANNEL_GPFIFO, &nvc0_fifo_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - instmem heap and vm setup
- ******************************************************************************/
-
-static int
-nvc0_fifo_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_fifo_base *base;
- int ret;
-
- ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC |
- NVOBJ_FLAG_HEAP, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
- &base->pgd);
- if (ret)
- return ret;
-
- nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
- nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
- nv_wo32(base, 0x0208, 0xffffffff);
- nv_wo32(base, 0x020c, 0x000000ff);
-
- ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void
-nvc0_fifo_context_dtor(struct nouveau_object *object)
-{
- struct nvc0_fifo_base *base = (void *)object;
- nouveau_vm_ref(NULL, &base->vm, base->pgd);
- nouveau_gpuobj_ref(NULL, &base->pgd);
- nouveau_fifo_context_destroy(&base->base);
-}
-
-static struct nouveau_oclass
-nvc0_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_fifo_context_ctor,
- .dtor = nvc0_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static inline int
-nvc0_fifo_engidx(struct nvc0_fifo_priv *priv, u32 engn)
-{
- switch (engn) {
- case NVDEV_ENGINE_GR : engn = 0; break;
- case NVDEV_ENGINE_BSP : engn = 1; break;
- case NVDEV_ENGINE_PPP : engn = 2; break;
- case NVDEV_ENGINE_VP : engn = 3; break;
- case NVDEV_ENGINE_COPY0: engn = 4; break;
- case NVDEV_ENGINE_COPY1: engn = 5; break;
- default:
- return -1;
- }
-
- return engn;
-}
-
-static inline struct nouveau_engine *
-nvc0_fifo_engine(struct nvc0_fifo_priv *priv, u32 engn)
-{
- switch (engn) {
- case 0: engn = NVDEV_ENGINE_GR; break;
- case 1: engn = NVDEV_ENGINE_BSP; break;
- case 2: engn = NVDEV_ENGINE_PPP; break;
- case 3: engn = NVDEV_ENGINE_VP; break;
- case 4: engn = NVDEV_ENGINE_COPY0; break;
- case 5: engn = NVDEV_ENGINE_COPY1; break;
- default:
- return NULL;
- }
-
- return nouveau_engine(priv, engn);
-}
-
-static void
-nvc0_fifo_recover_work(struct work_struct *work)
-{
- struct nvc0_fifo_priv *priv = container_of(work, typeof(*priv), fault);
- struct nouveau_object *engine;
- unsigned long flags;
- u32 engn, engm = 0;
- u64 mask, todo;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- mask = priv->mask;
- priv->mask = 0ULL;
- spin_unlock_irqrestore(&priv->base.lock, flags);
-
- for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
- engm |= 1 << nvc0_fifo_engidx(priv, engn);
- nv_mask(priv, 0x002630, engm, engm);
-
- for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
- if ((engine = (void *)nouveau_engine(priv, engn))) {
- nv_ofuncs(engine)->fini(engine, false);
- WARN_ON(nv_ofuncs(engine)->init(engine));
- }
- }
-
- nvc0_fifo_runlist_update(priv);
- nv_wr32(priv, 0x00262c, engm);
- nv_mask(priv, 0x002630, engm, 0x00000000);
-}
-
-static void
-nvc0_fifo_recover(struct nvc0_fifo_priv *priv, struct nouveau_engine *engine,
- struct nvc0_fifo_chan *chan)
-{
- struct nouveau_object *engobj = nv_object(engine);
- u32 chid = chan->base.chid;
- unsigned long flags;
-
- nv_error(priv, "%s engine fault on channel %d, recovering...\n",
- nv_subdev(engine)->name, chid);
-
- nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
- chan->state = KILLED;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- priv->mask |= 1ULL << nv_engidx(engobj);
- spin_unlock_irqrestore(&priv->base.lock, flags);
- schedule_work(&priv->fault);
-}
-
-static int
-nvc0_fifo_swmthd(struct nvc0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
-{
- struct nvc0_fifo_chan *chan = NULL;
- struct nouveau_handle *bind;
- unsigned long flags;
- int ret = -EINVAL;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- if (likely(chid >= priv->base.min && chid <= priv->base.max))
- chan = (void *)priv->base.channel[chid];
- if (unlikely(!chan))
- goto out;
-
- bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
- if (likely(bind)) {
- if (!mthd || !nv_call(bind->object, mthd, data))
- ret = 0;
- nouveau_namedb_put(bind);
- }
-
-out:
- spin_unlock_irqrestore(&priv->base.lock, flags);
- return ret;
-}
-
-static const struct nouveau_enum
-nvc0_fifo_sched_reason[] = {
- { 0x0a, "CTXSW_TIMEOUT" },
- {}
-};
-
-static void
-nvc0_fifo_intr_sched_ctxsw(struct nvc0_fifo_priv *priv)
-{
- struct nouveau_engine *engine;
- struct nvc0_fifo_chan *chan;
- u32 engn;
-
- for (engn = 0; engn < 6; engn++) {
- u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
- u32 busy = (stat & 0x80000000);
- u32 save = (stat & 0x00100000); /* maybe? */
- u32 unk0 = (stat & 0x00040000);
- u32 unk1 = (stat & 0x00001000);
- u32 chid = (stat & 0x0000007f);
- (void)save;
-
- if (busy && unk0 && unk1) {
- if (!(chan = (void *)priv->base.channel[chid]))
- continue;
- if (!(engine = nvc0_fifo_engine(priv, engn)))
- continue;
- nvc0_fifo_recover(priv, engine, chan);
- }
- }
-}
-
-static void
-nvc0_fifo_intr_sched(struct nvc0_fifo_priv *priv)
-{
- u32 intr = nv_rd32(priv, 0x00254c);
- u32 code = intr & 0x000000ff;
- const struct nouveau_enum *en;
- char enunk[6] = "";
-
- en = nouveau_enum_find(nvc0_fifo_sched_reason, code);
- if (!en)
- snprintf(enunk, sizeof(enunk), "UNK%02x", code);
-
- nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
-
- switch (code) {
- case 0x0a:
- nvc0_fifo_intr_sched_ctxsw(priv);
- break;
- default:
- break;
- }
-}
-
-static const struct nouveau_enum
-nvc0_fifo_fault_engine[] = {
- { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
- { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB },
- { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
- { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
- { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
- { 0x10, "PBSP", NULL, NVDEV_ENGINE_BSP },
- { 0x11, "PPPP", NULL, NVDEV_ENGINE_PPP },
- { 0x13, "PCOUNTER" },
- { 0x14, "PVP", NULL, NVDEV_ENGINE_VP },
- { 0x15, "PCOPY0", NULL, NVDEV_ENGINE_COPY0 },
- { 0x16, "PCOPY1", NULL, NVDEV_ENGINE_COPY1 },
- { 0x17, "PDAEMON" },
- {}
-};
-
-static const struct nouveau_enum
-nvc0_fifo_fault_reason[] = {
- { 0x00, "PT_NOT_PRESENT" },
- { 0x01, "PT_TOO_SHORT" },
- { 0x02, "PAGE_NOT_PRESENT" },
- { 0x03, "VM_LIMIT_EXCEEDED" },
- { 0x04, "NO_CHANNEL" },
- { 0x05, "PAGE_SYSTEM_ONLY" },
- { 0x06, "PAGE_READ_ONLY" },
- { 0x0a, "COMPRESSED_SYSRAM" },
- { 0x0c, "INVALID_STORAGE_TYPE" },
- {}
-};
-
-static const struct nouveau_enum
-nvc0_fifo_fault_hubclient[] = {
- { 0x01, "PCOPY0" },
- { 0x02, "PCOPY1" },
- { 0x04, "DISPATCH" },
- { 0x05, "CTXCTL" },
- { 0x06, "PFIFO" },
- { 0x07, "BAR_READ" },
- { 0x08, "BAR_WRITE" },
- { 0x0b, "PVP" },
- { 0x0c, "PPPP" },
- { 0x0d, "PBSP" },
- { 0x11, "PCOUNTER" },
- { 0x12, "PDAEMON" },
- { 0x14, "CCACHE" },
- { 0x15, "CCACHE_POST" },
- {}
-};
-
-static const struct nouveau_enum
-nvc0_fifo_fault_gpcclient[] = {
- { 0x01, "TEX" },
- { 0x0c, "ESETUP" },
- { 0x0e, "CTXCTL" },
- { 0x0f, "PROP" },
- {}
-};
-
-static void
-nvc0_fifo_intr_fault(struct nvc0_fifo_priv *priv, int unit)
-{
- u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
- u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
- u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
- u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
- u32 gpc = (stat & 0x1f000000) >> 24;
- u32 client = (stat & 0x00001f00) >> 8;
- u32 write = (stat & 0x00000080);
- u32 hub = (stat & 0x00000040);
- u32 reason = (stat & 0x0000000f);
- struct nouveau_object *engctx = NULL, *object;
- struct nouveau_engine *engine = NULL;
- const struct nouveau_enum *er, *eu, *ec;
- char erunk[6] = "";
- char euunk[6] = "";
- char ecunk[6] = "";
- char gpcid[3] = "";
-
- er = nouveau_enum_find(nvc0_fifo_fault_reason, reason);
- if (!er)
- snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
-
- eu = nouveau_enum_find(nvc0_fifo_fault_engine, unit);
- if (eu) {
- switch (eu->data2) {
- case NVDEV_SUBDEV_BAR:
- nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
- break;
- case NVDEV_SUBDEV_INSTMEM:
- nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
- break;
- case NVDEV_ENGINE_IFB:
- nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
- break;
- default:
- engine = nouveau_engine(priv, eu->data2);
- if (engine)
- engctx = nouveau_engctx_get(engine, inst);
- break;
- }
- } else {
- snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
- }
-
- if (hub) {
- ec = nouveau_enum_find(nvc0_fifo_fault_hubclient, client);
- } else {
- ec = nouveau_enum_find(nvc0_fifo_fault_gpcclient, client);
- snprintf(gpcid, sizeof(gpcid), "%d", gpc);
- }
-
- if (!ec)
- snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
-
- nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
- "channel 0x%010llx [%s]\n", write ? "write" : "read",
- (u64)vahi << 32 | valo, er ? er->name : erunk,
- eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
- ec ? ec->name : ecunk, (u64)inst << 12,
- nouveau_client_name(engctx));
-
- object = engctx;
- while (object) {
- switch (nv_mclass(object)) {
- case FERMI_CHANNEL_GPFIFO:
- nvc0_fifo_recover(priv, engine, (void *)object);
- break;
- }
- object = object->parent;
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static const struct nouveau_bitfield
-nvc0_fifo_pbdma_intr[] = {
-/* { 0x00008000, "" } seen with null ib push */
- { 0x00200000, "ILLEGAL_MTHD" },
- { 0x00800000, "EMPTY_SUBC" },
- {}
-};
-
-static void
-nvc0_fifo_intr_pbdma(struct nvc0_fifo_priv *priv, int unit)
-{
- u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
- u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
- u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
- u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00003ffc);
- u32 show = stat;
-
- if (stat & 0x00800000) {
- if (!nvc0_fifo_swmthd(priv, chid, mthd, data))
- show &= ~0x00800000;
- }
-
- if (show) {
- nv_error(priv, "PBDMA%d:", unit);
- nouveau_bitfield_print(nvc0_fifo_pbdma_intr, show);
- pr_cont("\n");
- nv_error(priv,
- "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
- unit, chid,
- nouveau_client_name_for_fifo_chid(&priv->base, chid),
- subc, mthd, data);
- }
-
- nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
- nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
-}
-
-static void
-nvc0_fifo_intr_runlist(struct nvc0_fifo_priv *priv)
-{
- u32 intr = nv_rd32(priv, 0x002a00);
-
- if (intr & 0x10000000) {
- wake_up(&priv->runlist.wait);
- nv_wr32(priv, 0x002a00, 0x10000000);
- intr &= ~0x10000000;
- }
-
- if (intr) {
- nv_error(priv, "RUNLIST 0x%08x\n", intr);
- nv_wr32(priv, 0x002a00, intr);
- }
-}
-
-static void
-nvc0_fifo_intr_engine_unit(struct nvc0_fifo_priv *priv, int engn)
-{
- u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04));
- u32 inte = nv_rd32(priv, 0x002628);
- u32 unkn;
-
- nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
-
- for (unkn = 0; unkn < 8; unkn++) {
- u32 ints = (intr >> (unkn * 0x04)) & inte;
- if (ints & 0x1) {
- nouveau_fifo_uevent(&priv->base);
- ints &= ~1;
- }
- if (ints) {
- nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
- nv_mask(priv, 0x002628, ints, 0);
- }
- }
-}
-
-static void
-nvc0_fifo_intr_engine(struct nvc0_fifo_priv *priv)
-{
- u32 mask = nv_rd32(priv, 0x0025a4);
- while (mask) {
- u32 unit = __ffs(mask);
- nvc0_fifo_intr_engine_unit(priv, unit);
- mask &= ~(1 << unit);
- }
-}
-
-static void
-nvc0_fifo_intr(struct nouveau_subdev *subdev)
-{
- struct nvc0_fifo_priv *priv = (void *)subdev;
- u32 mask = nv_rd32(priv, 0x002140);
- u32 stat = nv_rd32(priv, 0x002100) & mask;
-
- if (stat & 0x00000001) {
- u32 intr = nv_rd32(priv, 0x00252c);
- nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
- nv_wr32(priv, 0x002100, 0x00000001);
- stat &= ~0x00000001;
- }
-
- if (stat & 0x00000100) {
- nvc0_fifo_intr_sched(priv);
- nv_wr32(priv, 0x002100, 0x00000100);
- stat &= ~0x00000100;
- }
-
- if (stat & 0x00010000) {
- u32 intr = nv_rd32(priv, 0x00256c);
- nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
- nv_wr32(priv, 0x002100, 0x00010000);
- stat &= ~0x00010000;
- }
-
- if (stat & 0x01000000) {
- u32 intr = nv_rd32(priv, 0x00258c);
- nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
- nv_wr32(priv, 0x002100, 0x01000000);
- stat &= ~0x01000000;
- }
-
- if (stat & 0x10000000) {
- u32 mask = nv_rd32(priv, 0x00259c);
- while (mask) {
- u32 unit = __ffs(mask);
- nvc0_fifo_intr_fault(priv, unit);
- nv_wr32(priv, 0x00259c, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x10000000;
- }
-
- if (stat & 0x20000000) {
- u32 mask = nv_rd32(priv, 0x0025a0);
- while (mask) {
- u32 unit = __ffs(mask);
- nvc0_fifo_intr_pbdma(priv, unit);
- nv_wr32(priv, 0x0025a0, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x20000000;
- }
-
- if (stat & 0x40000000) {
- nvc0_fifo_intr_runlist(priv);
- stat &= ~0x40000000;
- }
-
- if (stat & 0x80000000) {
- nvc0_fifo_intr_engine(priv);
- stat &= ~0x80000000;
- }
-
- if (stat) {
- nv_error(priv, "INTR 0x%08x\n", stat);
- nv_mask(priv, 0x002140, stat, 0x00000000);
- nv_wr32(priv, 0x002100, stat);
- }
-}
-
-static void
-nvc0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
-}
-
-static void
-nvc0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
-}
-
-static const struct nvkm_event_func
-nvc0_fifo_uevent_func = {
- .ctor = nouveau_fifo_uevent_ctor,
- .init = nvc0_fifo_uevent_init,
- .fini = nvc0_fifo_uevent_fini,
-};
-
-static int
-nvc0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_fifo_priv *priv;
- int ret;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 0, 127, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- INIT_WORK(&priv->fault, nvc0_fifo_recover_work);
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
- &priv->runlist.mem[0]);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
- &priv->runlist.mem[1]);
- if (ret)
- return ret;
-
- init_waitqueue_head(&priv->runlist.wait);
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0,
- &priv->user.mem);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
- &priv->user.bar);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nvc0_fifo_uevent_func, 1, 1, &priv->base.uevent);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nvc0_fifo_intr;
- nv_engine(priv)->cclass = &nvc0_fifo_cclass;
- nv_engine(priv)->sclass = nvc0_fifo_sclass;
- return 0;
-}
-
-static void
-nvc0_fifo_dtor(struct nouveau_object *object)
-{
- struct nvc0_fifo_priv *priv = (void *)object;
-
- nouveau_gpuobj_unmap(&priv->user.bar);
- nouveau_gpuobj_ref(NULL, &priv->user.mem);
- nouveau_gpuobj_ref(NULL, &priv->runlist.mem[0]);
- nouveau_gpuobj_ref(NULL, &priv->runlist.mem[1]);
-
- nouveau_fifo_destroy(&priv->base);
-}
-
-static int
-nvc0_fifo_init(struct nouveau_object *object)
-{
- struct nvc0_fifo_priv *priv = (void *)object;
- int ret, i;
-
- ret = nouveau_fifo_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x000204, 0xffffffff);
- nv_wr32(priv, 0x002204, 0xffffffff);
-
- priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
- nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
-
- /* assign engines to PBDMAs */
- if (priv->spoon_nr >= 3) {
- nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
- nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
- nv_wr32(priv, 0x002210, ~(1 << 1)); /* PPP */
- nv_wr32(priv, 0x002214, ~(1 << 1)); /* PBSP */
- nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
- nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
- }
-
- /* PBDMA[n] */
- for (i = 0; i < priv->spoon_nr; i++) {
- nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
- nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
- nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
- }
-
- nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
- nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
-
- nv_wr32(priv, 0x002100, 0xffffffff);
- nv_wr32(priv, 0x002140, 0x7fffffff);
- nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
- return 0;
-}
-
-struct nouveau_oclass *
-nvc0_fifo_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(FIFO, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_fifo_ctor,
- .dtor = nvc0_fifo_dtor,
- .init = nvc0_fifo_init,
- .fini = _nouveau_fifo_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
deleted file mode 100644
index 6a8db7c80bd1..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.c
+++ /dev/null
@@ -1,1147 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-#include <core/gpuobj.h>
-#include <core/engctx.h>
-#include <core/event.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/bar.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include <engine/dmaobj.h>
-
-#include "nve0.h"
-
-#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
-static const struct {
- u64 subdev;
- u64 mask;
-} fifo_engine[] = {
- _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) |
- (1ULL << NVDEV_ENGINE_COPY2)),
- _(NVDEV_ENGINE_VP , 0),
- _(NVDEV_ENGINE_PPP , 0),
- _(NVDEV_ENGINE_BSP , 0),
- _(NVDEV_ENGINE_COPY0 , 0),
- _(NVDEV_ENGINE_COPY1 , 0),
- _(NVDEV_ENGINE_VENC , 0),
-};
-#undef _
-#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
-
-struct nve0_fifo_engn {
- struct nouveau_gpuobj *runlist[2];
- int cur_runlist;
- wait_queue_head_t wait;
-};
-
-struct nve0_fifo_priv {
- struct nouveau_fifo base;
-
- struct work_struct fault;
- u64 mask;
-
- struct nve0_fifo_engn engine[FIFO_ENGINE_NR];
- struct {
- struct nouveau_gpuobj *mem;
- struct nouveau_vma bar;
- } user;
- int spoon_nr;
-};
-
-struct nve0_fifo_base {
- struct nouveau_fifo_base base;
- struct nouveau_gpuobj *pgd;
- struct nouveau_vm *vm;
-};
-
-struct nve0_fifo_chan {
- struct nouveau_fifo_chan base;
- u32 engine;
- enum {
- STOPPED,
- RUNNING,
- KILLED
- } state;
-};
-
-/*******************************************************************************
- * FIFO channel objects
- ******************************************************************************/
-
-static void
-nve0_fifo_runlist_update(struct nve0_fifo_priv *priv, u32 engine)
-{
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nve0_fifo_engn *engn = &priv->engine[engine];
- struct nouveau_gpuobj *cur;
- int i, p;
-
- mutex_lock(&nv_subdev(priv)->mutex);
- cur = engn->runlist[engn->cur_runlist];
- engn->cur_runlist = !engn->cur_runlist;
-
- for (i = 0, p = 0; i < priv->base.max; i++) {
- struct nve0_fifo_chan *chan = (void *)priv->base.channel[i];
- if (chan && chan->state == RUNNING && chan->engine == engine) {
- nv_wo32(cur, p + 0, i);
- nv_wo32(cur, p + 4, 0x00000000);
- p += 8;
- }
- }
- bar->flush(bar);
-
- nv_wr32(priv, 0x002270, cur->addr >> 12);
- nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
-
- if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 +
- (engine * 0x08)) & 0x00100000),
- msecs_to_jiffies(2000)) == 0)
- nv_error(priv, "runlist %d update timeout\n", engine);
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nve0_fifo_context_attach(struct nouveau_object *parent,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nve0_fifo_base *base = (void *)parent->parent;
- struct nouveau_engctx *ectx = (void *)object;
- u32 addr;
- int ret;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW :
- return 0;
- case NVDEV_ENGINE_COPY0:
- case NVDEV_ENGINE_COPY1:
- case NVDEV_ENGINE_COPY2:
- nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
- return 0;
- case NVDEV_ENGINE_GR : addr = 0x0210; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
- default:
- return -EINVAL;
- }
-
- if (!ectx->vma.node) {
- ret = nouveau_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
- NV_MEM_ACCESS_RW, &ectx->vma);
- if (ret)
- return ret;
-
- nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
- }
-
- nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
- nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
- bar->flush(bar);
- return 0;
-}
-
-static int
-nve0_fifo_context_detach(struct nouveau_object *parent, bool suspend,
- struct nouveau_object *object)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nve0_fifo_priv *priv = (void *)parent->engine;
- struct nve0_fifo_base *base = (void *)parent->parent;
- struct nve0_fifo_chan *chan = (void *)parent;
- u32 addr;
-
- switch (nv_engidx(object->engine)) {
- case NVDEV_ENGINE_SW : return 0;
- case NVDEV_ENGINE_COPY0:
- case NVDEV_ENGINE_COPY1:
- case NVDEV_ENGINE_COPY2: addr = 0x0000; break;
- case NVDEV_ENGINE_GR : addr = 0x0210; break;
- case NVDEV_ENGINE_BSP : addr = 0x0270; break;
- case NVDEV_ENGINE_VP : addr = 0x0250; break;
- case NVDEV_ENGINE_PPP : addr = 0x0260; break;
- default:
- return -EINVAL;
- }
-
- nv_wr32(priv, 0x002634, chan->base.chid);
- if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
- nv_error(priv, "channel %d [%s] kick timeout\n",
- chan->base.chid, nouveau_client_name(chan));
- if (suspend)
- return -EBUSY;
- }
-
- if (addr) {
- nv_wo32(base, addr + 0x00, 0x00000000);
- nv_wo32(base, addr + 0x04, 0x00000000);
- bar->flush(bar);
- }
-
- return 0;
-}
-
-static int
-nve0_fifo_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct kepler_channel_gpfifo_a_v0 v0;
- } *args = data;
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nve0_fifo_priv *priv = (void *)engine;
- struct nve0_fifo_base *base = (void *)parent;
- struct nve0_fifo_chan *chan;
- u64 usermem, ioffset, ilength;
- int ret, i;
-
- nv_ioctl(parent, "create channel gpfifo size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
- "ioffset %016llx ilength %08x engine %08x\n",
- args->v0.version, args->v0.pushbuf, args->v0.ioffset,
- args->v0.ilength, args->v0.engine);
- } else
- return ret;
-
- for (i = 0; i < FIFO_ENGINE_NR; i++) {
- if (args->v0.engine & (1 << i)) {
- if (nouveau_engine(parent, fifo_engine[i].subdev)) {
- args->v0.engine = (1 << i);
- break;
- }
- }
- }
-
- if (i == FIFO_ENGINE_NR) {
- nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine);
- return -ENODEV;
- }
-
- ret = nouveau_fifo_channel_create(parent, engine, oclass, 1,
- priv->user.bar.offset, 0x200,
- args->v0.pushbuf,
- fifo_engine[i].mask, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- args->v0.chid = chan->base.chid;
-
- nv_parent(chan)->context_attach = nve0_fifo_context_attach;
- nv_parent(chan)->context_detach = nve0_fifo_context_detach;
- chan->engine = i;
-
- usermem = chan->base.chid * 0x200;
- ioffset = args->v0.ioffset;
- ilength = order_base_2(args->v0.ilength / 8);
-
- for (i = 0; i < 0x200; i += 4)
- nv_wo32(priv->user.mem, usermem + i, 0x00000000);
-
- nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
- nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
- nv_wo32(base, 0x10, 0x0000face);
- nv_wo32(base, 0x30, 0xfffff902);
- nv_wo32(base, 0x48, lower_32_bits(ioffset));
- nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
- nv_wo32(base, 0x84, 0x20400000);
- nv_wo32(base, 0x94, 0x30000001);
- nv_wo32(base, 0x9c, 0x00000100);
- nv_wo32(base, 0xac, 0x0000001f);
- nv_wo32(base, 0xe8, chan->base.chid);
- nv_wo32(base, 0xb8, 0xf8000000);
- nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
- nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
- bar->flush(bar);
- return 0;
-}
-
-static int
-nve0_fifo_chan_init(struct nouveau_object *object)
-{
- struct nouveau_gpuobj *base = nv_gpuobj(object->parent);
- struct nve0_fifo_priv *priv = (void *)object->engine;
- struct nve0_fifo_chan *chan = (void *)object;
- u32 chid = chan->base.chid;
- int ret;
-
- ret = nouveau_fifo_channel_init(&chan->base);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
- nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
-
- if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
- nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
- nve0_fifo_runlist_update(priv, chan->engine);
- nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
- }
-
- return 0;
-}
-
-static int
-nve0_fifo_chan_fini(struct nouveau_object *object, bool suspend)
-{
- struct nve0_fifo_priv *priv = (void *)object->engine;
- struct nve0_fifo_chan *chan = (void *)object;
- u32 chid = chan->base.chid;
-
- if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
- nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
- nve0_fifo_runlist_update(priv, chan->engine);
- }
-
- nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
- return nouveau_fifo_channel_fini(&chan->base, suspend);
-}
-
-static struct nouveau_ofuncs
-nve0_fifo_ofuncs = {
- .ctor = nve0_fifo_chan_ctor,
- .dtor = _nouveau_fifo_channel_dtor,
- .init = nve0_fifo_chan_init,
- .fini = nve0_fifo_chan_fini,
- .map = _nouveau_fifo_channel_map,
- .rd32 = _nouveau_fifo_channel_rd32,
- .wr32 = _nouveau_fifo_channel_wr32,
- .ntfy = _nouveau_fifo_channel_ntfy
-};
-
-static struct nouveau_oclass
-nve0_fifo_sclass[] = {
- { KEPLER_CHANNEL_GPFIFO_A, &nve0_fifo_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * FIFO context - instmem heap and vm setup
- ******************************************************************************/
-
-static int
-nve0_fifo_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_fifo_base *base;
- int ret;
-
- ret = nouveau_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
- *pobject = nv_object(base);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
- &base->pgd);
- if (ret)
- return ret;
-
- nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
- nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
- nv_wo32(base, 0x0208, 0xffffffff);
- nv_wo32(base, 0x020c, 0x000000ff);
-
- ret = nouveau_vm_ref(nouveau_client(parent)->vm, &base->vm, base->pgd);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static void
-nve0_fifo_context_dtor(struct nouveau_object *object)
-{
- struct nve0_fifo_base *base = (void *)object;
- nouveau_vm_ref(NULL, &base->vm, base->pgd);
- nouveau_gpuobj_ref(NULL, &base->pgd);
- nouveau_fifo_context_destroy(&base->base);
-}
-
-static struct nouveau_oclass
-nve0_fifo_cclass = {
- .handle = NV_ENGCTX(FIFO, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_fifo_context_ctor,
- .dtor = nve0_fifo_context_dtor,
- .init = _nouveau_fifo_context_init,
- .fini = _nouveau_fifo_context_fini,
- .rd32 = _nouveau_fifo_context_rd32,
- .wr32 = _nouveau_fifo_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PFIFO engine
- ******************************************************************************/
-
-static inline int
-nve0_fifo_engidx(struct nve0_fifo_priv *priv, u32 engn)
-{
- switch (engn) {
- case NVDEV_ENGINE_GR :
- case NVDEV_ENGINE_COPY2: engn = 0; break;
- case NVDEV_ENGINE_BSP : engn = 1; break;
- case NVDEV_ENGINE_PPP : engn = 2; break;
- case NVDEV_ENGINE_VP : engn = 3; break;
- case NVDEV_ENGINE_COPY0: engn = 4; break;
- case NVDEV_ENGINE_COPY1: engn = 5; break;
- case NVDEV_ENGINE_VENC : engn = 6; break;
- default:
- return -1;
- }
-
- return engn;
-}
-
-static inline struct nouveau_engine *
-nve0_fifo_engine(struct nve0_fifo_priv *priv, u32 engn)
-{
- if (engn >= ARRAY_SIZE(fifo_engine))
- return NULL;
- return nouveau_engine(priv, fifo_engine[engn].subdev);
-}
-
-static void
-nve0_fifo_recover_work(struct work_struct *work)
-{
- struct nve0_fifo_priv *priv = container_of(work, typeof(*priv), fault);
- struct nouveau_object *engine;
- unsigned long flags;
- u32 engn, engm = 0;
- u64 mask, todo;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- mask = priv->mask;
- priv->mask = 0ULL;
- spin_unlock_irqrestore(&priv->base.lock, flags);
-
- for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
- engm |= 1 << nve0_fifo_engidx(priv, engn);
- nv_mask(priv, 0x002630, engm, engm);
-
- for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
- if ((engine = (void *)nouveau_engine(priv, engn))) {
- nv_ofuncs(engine)->fini(engine, false);
- WARN_ON(nv_ofuncs(engine)->init(engine));
- }
- nve0_fifo_runlist_update(priv, nve0_fifo_engidx(priv, engn));
- }
-
- nv_wr32(priv, 0x00262c, engm);
- nv_mask(priv, 0x002630, engm, 0x00000000);
-}
-
-static void
-nve0_fifo_recover(struct nve0_fifo_priv *priv, struct nouveau_engine *engine,
- struct nve0_fifo_chan *chan)
-{
- struct nouveau_object *engobj = nv_object(engine);
- u32 chid = chan->base.chid;
- unsigned long flags;
-
- nv_error(priv, "%s engine fault on channel %d, recovering...\n",
- nv_subdev(engine)->name, chid);
-
- nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
- chan->state = KILLED;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- priv->mask |= 1ULL << nv_engidx(engobj);
- spin_unlock_irqrestore(&priv->base.lock, flags);
- schedule_work(&priv->fault);
-}
-
-static int
-nve0_fifo_swmthd(struct nve0_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
-{
- struct nve0_fifo_chan *chan = NULL;
- struct nouveau_handle *bind;
- unsigned long flags;
- int ret = -EINVAL;
-
- spin_lock_irqsave(&priv->base.lock, flags);
- if (likely(chid >= priv->base.min && chid <= priv->base.max))
- chan = (void *)priv->base.channel[chid];
- if (unlikely(!chan))
- goto out;
-
- bind = nouveau_namedb_get_class(nv_namedb(chan), 0x906e);
- if (likely(bind)) {
- if (!mthd || !nv_call(bind->object, mthd, data))
- ret = 0;
- nouveau_namedb_put(bind);
- }
-
-out:
- spin_unlock_irqrestore(&priv->base.lock, flags);
- return ret;
-}
-
-static const struct nouveau_enum
-nve0_fifo_bind_reason[] = {
- { 0x01, "BIND_NOT_UNBOUND" },
- { 0x02, "SNOOP_WITHOUT_BAR1" },
- { 0x03, "UNBIND_WHILE_RUNNING" },
- { 0x05, "INVALID_RUNLIST" },
- { 0x06, "INVALID_CTX_TGT" },
- { 0x0b, "UNBIND_WHILE_PARKED" },
- {}
-};
-
-static void
-nve0_fifo_intr_bind(struct nve0_fifo_priv *priv)
-{
- u32 intr = nv_rd32(priv, 0x00252c);
- u32 code = intr & 0x000000ff;
- const struct nouveau_enum *en;
- char enunk[6] = "";
-
- en = nouveau_enum_find(nve0_fifo_bind_reason, code);
- if (!en)
- snprintf(enunk, sizeof(enunk), "UNK%02x", code);
-
- nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk);
-}
-
-static const struct nouveau_enum
-nve0_fifo_sched_reason[] = {
- { 0x0a, "CTXSW_TIMEOUT" },
- {}
-};
-
-static void
-nve0_fifo_intr_sched_ctxsw(struct nve0_fifo_priv *priv)
-{
- struct nouveau_engine *engine;
- struct nve0_fifo_chan *chan;
- u32 engn;
-
- for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
- u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
- u32 busy = (stat & 0x80000000);
- u32 next = (stat & 0x07ff0000) >> 16;
- u32 chsw = (stat & 0x00008000);
- u32 save = (stat & 0x00004000);
- u32 load = (stat & 0x00002000);
- u32 prev = (stat & 0x000007ff);
- u32 chid = load ? next : prev;
- (void)save;
-
- if (busy && chsw) {
- if (!(chan = (void *)priv->base.channel[chid]))
- continue;
- if (!(engine = nve0_fifo_engine(priv, engn)))
- continue;
- nve0_fifo_recover(priv, engine, chan);
- }
- }
-}
-
-static void
-nve0_fifo_intr_sched(struct nve0_fifo_priv *priv)
-{
- u32 intr = nv_rd32(priv, 0x00254c);
- u32 code = intr & 0x000000ff;
- const struct nouveau_enum *en;
- char enunk[6] = "";
-
- en = nouveau_enum_find(nve0_fifo_sched_reason, code);
- if (!en)
- snprintf(enunk, sizeof(enunk), "UNK%02x", code);
-
- nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
-
- switch (code) {
- case 0x0a:
- nve0_fifo_intr_sched_ctxsw(priv);
- break;
- default:
- break;
- }
-}
-
-static void
-nve0_fifo_intr_chsw(struct nve0_fifo_priv *priv)
-{
- u32 stat = nv_rd32(priv, 0x00256c);
- nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
- nv_wr32(priv, 0x00256c, stat);
-}
-
-static void
-nve0_fifo_intr_dropped_fault(struct nve0_fifo_priv *priv)
-{
- u32 stat = nv_rd32(priv, 0x00259c);
- nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
-}
-
-static const struct nouveau_enum
-nve0_fifo_fault_engine[] = {
- { 0x00, "GR", NULL, NVDEV_ENGINE_GR },
- { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
- { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
- { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
- { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
- { 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
- { 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
- { 0x10, "MSVLD", NULL, NVDEV_ENGINE_BSP },
- { 0x11, "MSPPP", NULL, NVDEV_ENGINE_PPP },
- { 0x13, "PERF" },
- { 0x14, "MSPDEC", NULL, NVDEV_ENGINE_VP },
- { 0x15, "CE0", NULL, NVDEV_ENGINE_COPY0 },
- { 0x16, "CE1", NULL, NVDEV_ENGINE_COPY1 },
- { 0x17, "PMU" },
- { 0x19, "MSENC", NULL, NVDEV_ENGINE_VENC },
- { 0x1b, "CE2", NULL, NVDEV_ENGINE_COPY2 },
- {}
-};
-
-static const struct nouveau_enum
-nve0_fifo_fault_reason[] = {
- { 0x00, "PDE" },
- { 0x01, "PDE_SIZE" },
- { 0x02, "PTE" },
- { 0x03, "VA_LIMIT_VIOLATION" },
- { 0x04, "UNBOUND_INST_BLOCK" },
- { 0x05, "PRIV_VIOLATION" },
- { 0x06, "RO_VIOLATION" },
- { 0x07, "WO_VIOLATION" },
- { 0x08, "PITCH_MASK_VIOLATION" },
- { 0x09, "WORK_CREATION" },
- { 0x0a, "UNSUPPORTED_APERTURE" },
- { 0x0b, "COMPRESSION_FAILURE" },
- { 0x0c, "UNSUPPORTED_KIND" },
- { 0x0d, "REGION_VIOLATION" },
- { 0x0e, "BOTH_PTES_VALID" },
- { 0x0f, "INFO_TYPE_POISONED" },
- {}
-};
-
-static const struct nouveau_enum
-nve0_fifo_fault_hubclient[] = {
- { 0x00, "VIP" },
- { 0x01, "CE0" },
- { 0x02, "CE1" },
- { 0x03, "DNISO" },
- { 0x04, "FE" },
- { 0x05, "FECS" },
- { 0x06, "HOST" },
- { 0x07, "HOST_CPU" },
- { 0x08, "HOST_CPU_NB" },
- { 0x09, "ISO" },
- { 0x0a, "MMU" },
- { 0x0b, "MSPDEC" },
- { 0x0c, "MSPPP" },
- { 0x0d, "MSVLD" },
- { 0x0e, "NISO" },
- { 0x0f, "P2P" },
- { 0x10, "PD" },
- { 0x11, "PERF" },
- { 0x12, "PMU" },
- { 0x13, "RASTERTWOD" },
- { 0x14, "SCC" },
- { 0x15, "SCC_NB" },
- { 0x16, "SEC" },
- { 0x17, "SSYNC" },
- { 0x18, "GR_COPY" },
- { 0x19, "CE2" },
- { 0x1a, "XV" },
- { 0x1b, "MMU_NB" },
- { 0x1c, "MSENC" },
- { 0x1d, "DFALCON" },
- { 0x1e, "SKED" },
- { 0x1f, "AFALCON" },
- {}
-};
-
-static const struct nouveau_enum
-nve0_fifo_fault_gpcclient[] = {
- { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
- { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
- { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
- { 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" },
- { 0x0c, "RAST" },
- { 0x0d, "GCC" },
- { 0x0e, "GPCCS" },
- { 0x0f, "PROP_0" },
- { 0x10, "PROP_1" },
- { 0x11, "PROP_2" },
- { 0x12, "PROP_3" },
- { 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" },
- { 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" },
- { 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" },
- { 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" },
- { 0x1f, "GPM" },
- { 0x20, "LTP_UTLB_0" },
- { 0x21, "LTP_UTLB_1" },
- { 0x22, "LTP_UTLB_2" },
- { 0x23, "LTP_UTLB_3" },
- { 0x24, "GPC_RGG_UTLB" },
- {}
-};
-
-static void
-nve0_fifo_intr_fault(struct nve0_fifo_priv *priv, int unit)
-{
- u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
- u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
- u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
- u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
- u32 gpc = (stat & 0x1f000000) >> 24;
- u32 client = (stat & 0x00001f00) >> 8;
- u32 write = (stat & 0x00000080);
- u32 hub = (stat & 0x00000040);
- u32 reason = (stat & 0x0000000f);
- struct nouveau_object *engctx = NULL, *object;
- struct nouveau_engine *engine = NULL;
- const struct nouveau_enum *er, *eu, *ec;
- char erunk[6] = "";
- char euunk[6] = "";
- char ecunk[6] = "";
- char gpcid[3] = "";
-
- er = nouveau_enum_find(nve0_fifo_fault_reason, reason);
- if (!er)
- snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
-
- eu = nouveau_enum_find(nve0_fifo_fault_engine, unit);
- if (eu) {
- switch (eu->data2) {
- case NVDEV_SUBDEV_BAR:
- nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
- break;
- case NVDEV_SUBDEV_INSTMEM:
- nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
- break;
- case NVDEV_ENGINE_IFB:
- nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
- break;
- default:
- engine = nouveau_engine(priv, eu->data2);
- if (engine)
- engctx = nouveau_engctx_get(engine, inst);
- break;
- }
- } else {
- snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
- }
-
- if (hub) {
- ec = nouveau_enum_find(nve0_fifo_fault_hubclient, client);
- } else {
- ec = nouveau_enum_find(nve0_fifo_fault_gpcclient, client);
- snprintf(gpcid, sizeof(gpcid), "%d", gpc);
- }
-
- if (!ec)
- snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
-
- nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
- "channel 0x%010llx [%s]\n", write ? "write" : "read",
- (u64)vahi << 32 | valo, er ? er->name : erunk,
- eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
- ec ? ec->name : ecunk, (u64)inst << 12,
- nouveau_client_name(engctx));
-
- object = engctx;
- while (object) {
- switch (nv_mclass(object)) {
- case KEPLER_CHANNEL_GPFIFO_A:
- nve0_fifo_recover(priv, engine, (void *)object);
- break;
- }
- object = object->parent;
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static const struct nouveau_bitfield nve0_fifo_pbdma_intr_0[] = {
- { 0x00000001, "MEMREQ" },
- { 0x00000002, "MEMACK_TIMEOUT" },
- { 0x00000004, "MEMACK_EXTRA" },
- { 0x00000008, "MEMDAT_TIMEOUT" },
- { 0x00000010, "MEMDAT_EXTRA" },
- { 0x00000020, "MEMFLUSH" },
- { 0x00000040, "MEMOP" },
- { 0x00000080, "LBCONNECT" },
- { 0x00000100, "LBREQ" },
- { 0x00000200, "LBACK_TIMEOUT" },
- { 0x00000400, "LBACK_EXTRA" },
- { 0x00000800, "LBDAT_TIMEOUT" },
- { 0x00001000, "LBDAT_EXTRA" },
- { 0x00002000, "GPFIFO" },
- { 0x00004000, "GPPTR" },
- { 0x00008000, "GPENTRY" },
- { 0x00010000, "GPCRC" },
- { 0x00020000, "PBPTR" },
- { 0x00040000, "PBENTRY" },
- { 0x00080000, "PBCRC" },
- { 0x00100000, "XBARCONNECT" },
- { 0x00200000, "METHOD" },
- { 0x00400000, "METHODCRC" },
- { 0x00800000, "DEVICE" },
- { 0x02000000, "SEMAPHORE" },
- { 0x04000000, "ACQUIRE" },
- { 0x08000000, "PRI" },
- { 0x20000000, "NO_CTXSW_SEG" },
- { 0x40000000, "PBSEG" },
- { 0x80000000, "SIGNATURE" },
- {}
-};
-
-static void
-nve0_fifo_intr_pbdma_0(struct nve0_fifo_priv *priv, int unit)
-{
- u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000));
- u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask;
- u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
- u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
- u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00003ffc);
- u32 show = stat;
-
- if (stat & 0x00800000) {
- if (!nve0_fifo_swmthd(priv, chid, mthd, data))
- show &= ~0x00800000;
- nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
- }
-
- if (show) {
- nv_error(priv, "PBDMA%d:", unit);
- nouveau_bitfield_print(nve0_fifo_pbdma_intr_0, show);
- pr_cont("\n");
- nv_error(priv,
- "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
- unit, chid,
- nouveau_client_name_for_fifo_chid(&priv->base, chid),
- subc, mthd, data);
- }
-
- nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
-}
-
-static const struct nouveau_bitfield nve0_fifo_pbdma_intr_1[] = {
- { 0x00000001, "HCE_RE_ILLEGAL_OP" },
- { 0x00000002, "HCE_RE_ALIGNB" },
- { 0x00000004, "HCE_PRIV" },
- { 0x00000008, "HCE_ILLEGAL_MTHD" },
- { 0x00000010, "HCE_ILLEGAL_CLASS" },
- {}
-};
-
-static void
-nve0_fifo_intr_pbdma_1(struct nve0_fifo_priv *priv, int unit)
-{
- u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000));
- u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask;
- u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
-
- if (stat) {
- nv_error(priv, "PBDMA%d:", unit);
- nouveau_bitfield_print(nve0_fifo_pbdma_intr_1, stat);
- pr_cont("\n");
- nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
- nv_rd32(priv, 0x040150 + (unit * 0x2000)),
- nv_rd32(priv, 0x040154 + (unit * 0x2000)));
- }
-
- nv_wr32(priv, 0x040148 + (unit * 0x2000), stat);
-}
-
-static void
-nve0_fifo_intr_runlist(struct nve0_fifo_priv *priv)
-{
- u32 mask = nv_rd32(priv, 0x002a00);
- while (mask) {
- u32 engn = __ffs(mask);
- wake_up(&priv->engine[engn].wait);
- nv_wr32(priv, 0x002a00, 1 << engn);
- mask &= ~(1 << engn);
- }
-}
-
-static void
-nve0_fifo_intr_engine(struct nve0_fifo_priv *priv)
-{
- nouveau_fifo_uevent(&priv->base);
-}
-
-static void
-nve0_fifo_intr(struct nouveau_subdev *subdev)
-{
- struct nve0_fifo_priv *priv = (void *)subdev;
- u32 mask = nv_rd32(priv, 0x002140);
- u32 stat = nv_rd32(priv, 0x002100) & mask;
-
- if (stat & 0x00000001) {
- nve0_fifo_intr_bind(priv);
- nv_wr32(priv, 0x002100, 0x00000001);
- stat &= ~0x00000001;
- }
-
- if (stat & 0x00000010) {
- nv_error(priv, "PIO_ERROR\n");
- nv_wr32(priv, 0x002100, 0x00000010);
- stat &= ~0x00000010;
- }
-
- if (stat & 0x00000100) {
- nve0_fifo_intr_sched(priv);
- nv_wr32(priv, 0x002100, 0x00000100);
- stat &= ~0x00000100;
- }
-
- if (stat & 0x00010000) {
- nve0_fifo_intr_chsw(priv);
- nv_wr32(priv, 0x002100, 0x00010000);
- stat &= ~0x00010000;
- }
-
- if (stat & 0x00800000) {
- nv_error(priv, "FB_FLUSH_TIMEOUT\n");
- nv_wr32(priv, 0x002100, 0x00800000);
- stat &= ~0x00800000;
- }
-
- if (stat & 0x01000000) {
- nv_error(priv, "LB_ERROR\n");
- nv_wr32(priv, 0x002100, 0x01000000);
- stat &= ~0x01000000;
- }
-
- if (stat & 0x08000000) {
- nve0_fifo_intr_dropped_fault(priv);
- nv_wr32(priv, 0x002100, 0x08000000);
- stat &= ~0x08000000;
- }
-
- if (stat & 0x10000000) {
- u32 mask = nv_rd32(priv, 0x00259c);
- while (mask) {
- u32 unit = __ffs(mask);
- nve0_fifo_intr_fault(priv, unit);
- nv_wr32(priv, 0x00259c, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x10000000;
- }
-
- if (stat & 0x20000000) {
- u32 mask = nv_rd32(priv, 0x0025a0);
- while (mask) {
- u32 unit = __ffs(mask);
- nve0_fifo_intr_pbdma_0(priv, unit);
- nve0_fifo_intr_pbdma_1(priv, unit);
- nv_wr32(priv, 0x0025a0, (1 << unit));
- mask &= ~(1 << unit);
- }
- stat &= ~0x20000000;
- }
-
- if (stat & 0x40000000) {
- nve0_fifo_intr_runlist(priv);
- stat &= ~0x40000000;
- }
-
- if (stat & 0x80000000) {
- nv_wr32(priv, 0x002100, 0x80000000);
- nve0_fifo_intr_engine(priv);
- stat &= ~0x80000000;
- }
-
- if (stat) {
- nv_error(priv, "INTR 0x%08x\n", stat);
- nv_mask(priv, 0x002140, stat, 0x00000000);
- nv_wr32(priv, 0x002100, stat);
- }
-}
-
-static void
-nve0_fifo_uevent_init(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
-}
-
-static void
-nve0_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_fifo *fifo = container_of(event, typeof(*fifo), uevent);
- nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
-}
-
-static const struct nvkm_event_func
-nve0_fifo_uevent_func = {
- .ctor = nouveau_fifo_uevent_ctor,
- .init = nve0_fifo_uevent_init,
- .fini = nve0_fifo_uevent_fini,
-};
-
-int
-nve0_fifo_fini(struct nouveau_object *object, bool suspend)
-{
- struct nve0_fifo_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fifo_fini(&priv->base, suspend);
- if (ret)
- return ret;
-
- /* allow mmu fault interrupts, even when we're not using fifo */
- nv_mask(priv, 0x002140, 0x10000000, 0x10000000);
- return 0;
-}
-
-int
-nve0_fifo_init(struct nouveau_object *object)
-{
- struct nve0_fifo_priv *priv = (void *)object;
- int ret, i;
-
- ret = nouveau_fifo_init(&priv->base);
- if (ret)
- return ret;
-
- /* enable all available PBDMA units */
- nv_wr32(priv, 0x000204, 0xffffffff);
- priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
- nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
-
- /* PBDMA[n] */
- for (i = 0; i < priv->spoon_nr; i++) {
- nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
- nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
- nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
- }
-
- /* PBDMA[n].HCE */
- for (i = 0; i < priv->spoon_nr; i++) {
- nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
- nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
- }
-
- nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
-
- nv_wr32(priv, 0x002100, 0xffffffff);
- nv_wr32(priv, 0x002140, 0x7fffffff);
- return 0;
-}
-
-void
-nve0_fifo_dtor(struct nouveau_object *object)
-{
- struct nve0_fifo_priv *priv = (void *)object;
- int i;
-
- nouveau_gpuobj_unmap(&priv->user.bar);
- nouveau_gpuobj_ref(NULL, &priv->user.mem);
-
- for (i = 0; i < FIFO_ENGINE_NR; i++) {
- nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[1]);
- nouveau_gpuobj_ref(NULL, &priv->engine[i].runlist[0]);
- }
-
- nouveau_fifo_destroy(&priv->base);
-}
-
-int
-nve0_fifo_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_fifo_impl *impl = (void *)oclass;
- struct nve0_fifo_priv *priv;
- int ret, i;
-
- ret = nouveau_fifo_create(parent, engine, oclass, 0,
- impl->channels - 1, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- INIT_WORK(&priv->fault, nve0_fifo_recover_work);
-
- for (i = 0; i < FIFO_ENGINE_NR; i++) {
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
- 0, &priv->engine[i].runlist[0]);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
- 0, &priv->engine[i].runlist[1]);
- if (ret)
- return ret;
-
- init_waitqueue_head(&priv->engine[i].wait);
- }
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
- &priv->user.bar);
- if (ret)
- return ret;
-
- ret = nvkm_event_init(&nve0_fifo_uevent_func, 1, 1, &priv->base.uevent);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000100;
- nv_subdev(priv)->intr = nve0_fifo_intr;
- nv_engine(priv)->cclass = &nve0_fifo_cclass;
- nv_engine(priv)->sclass = nve0_fifo_sclass;
- return 0;
-}
-
-struct nouveau_oclass *
-nve0_fifo_oclass = &(struct nve0_fifo_impl) {
- .base.handle = NV_ENGINE(FIFO, 0xe0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_fifo_ctor,
- .dtor = nve0_fifo_dtor,
- .init = nve0_fifo_init,
- .fini = nve0_fifo_fini,
- },
- .channels = 4096,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h b/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h
deleted file mode 100644
index e96b32bb1bbc..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/fifo/nve0.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __NVKM_FIFO_NVE0_H__
-#define __NVKM_FIFO_NVE0_H__
-
-#include <engine/fifo.h>
-
-int nve0_fifo_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nve0_fifo_dtor(struct nouveau_object *);
-int nve0_fifo_init(struct nouveau_object *);
-int nve0_fifo_fini(struct nouveau_object *, bool);
-
-struct nve0_fifo_impl {
- struct nouveau_oclass base;
- u32 channels;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
deleted file mode 100644
index e1947013d3bc..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctx.h
+++ /dev/null
@@ -1,129 +0,0 @@
-#ifndef __NOUVEAU_GRCTX_H__
-#define __NOUVEAU_GRCTX_H__
-
-struct nouveau_grctx {
- struct nouveau_device *device;
-
- enum {
- NOUVEAU_GRCTX_PROG,
- NOUVEAU_GRCTX_VALS
- } mode;
- void *data;
-
- u32 ctxprog_max;
- u32 ctxprog_len;
- u32 ctxprog_reg;
- int ctxprog_label[32];
- u32 ctxvals_pos;
- u32 ctxvals_base;
-};
-
-static inline void
-cp_out(struct nouveau_grctx *ctx, u32 inst)
-{
- u32 *ctxprog = ctx->data;
-
- if (ctx->mode != NOUVEAU_GRCTX_PROG)
- return;
-
- BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max);
- ctxprog[ctx->ctxprog_len++] = inst;
-}
-
-static inline void
-cp_lsr(struct nouveau_grctx *ctx, u32 val)
-{
- cp_out(ctx, CP_LOAD_SR | val);
-}
-
-static inline void
-cp_ctx(struct nouveau_grctx *ctx, u32 reg, u32 length)
-{
- ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
-
- ctx->ctxvals_base = ctx->ctxvals_pos;
- ctx->ctxvals_pos = ctx->ctxvals_base + length;
-
- if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) {
- cp_lsr(ctx, length);
- length = 0;
- }
-
- cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg);
-}
-
-static inline void
-cp_name(struct nouveau_grctx *ctx, int name)
-{
- u32 *ctxprog = ctx->data;
- int i;
-
- if (ctx->mode != NOUVEAU_GRCTX_PROG)
- return;
-
- ctx->ctxprog_label[name] = ctx->ctxprog_len;
- for (i = 0; i < ctx->ctxprog_len; i++) {
- if ((ctxprog[i] & 0xfff00000) != 0xff400000)
- continue;
- if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT))
- continue;
- ctxprog[i] = (ctxprog[i] & 0x00ff00ff) |
- (ctx->ctxprog_len << CP_BRA_IP_SHIFT);
- }
-}
-
-static inline void
-_cp_bra(struct nouveau_grctx *ctx, u32 mod, int flag, int state, int name)
-{
- int ip = 0;
-
- if (mod != 2) {
- ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT;
- if (ip == 0)
- ip = 0xff000000 | (name << CP_BRA_IP_SHIFT);
- }
-
- cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
- (state ? 0 : CP_BRA_IF_CLEAR));
-}
-#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
-#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
-
-static inline void
-_cp_wait(struct nouveau_grctx *ctx, int flag, int state)
-{
- cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
-}
-#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
-
-static inline void
-_cp_set(struct nouveau_grctx *ctx, int flag, int state)
-{
- cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
-}
-#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
-
-static inline void
-cp_pos(struct nouveau_grctx *ctx, int offset)
-{
- ctx->ctxvals_pos = offset;
- ctx->ctxvals_base = ctx->ctxvals_pos;
-
- cp_lsr(ctx, ctx->ctxvals_pos);
- cp_out(ctx, CP_SET_CONTEXT_POINTER);
-}
-
-static inline void
-gr_def(struct nouveau_grctx *ctx, u32 reg, u32 val)
-{
- if (ctx->mode != NOUVEAU_GRCTX_VALS)
- return;
-
- reg = (reg - 0x00400000) / 4;
- reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
-
- nv_wo32(ctx->data, reg * 4, val);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c
deleted file mode 100644
index 3adb7fe91772..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk110b.c
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gk110b_grctx_init_sm_0[] = {
- { 0x419e04, 1, 0x04, 0x00000000 },
- { 0x419e08, 1, 0x04, 0x0000001d },
- { 0x419e0c, 1, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00001c02 },
- { 0x419e44, 1, 0x04, 0x0013eff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000007f },
- { 0x419e50, 2, 0x04, 0x00000000 },
- { 0x419e58, 1, 0x04, 0x00000001 },
- { 0x419e5c, 3, 0x04, 0x00000000 },
- { 0x419e68, 1, 0x04, 0x00000002 },
- { 0x419e6c, 12, 0x04, 0x00000000 },
- { 0x419eac, 1, 0x04, 0x00001f8f },
- { 0x419eb0, 1, 0x04, 0x0db00d2f },
- { 0x419eb8, 1, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x0001304f },
- { 0x419f30, 4, 0x04, 0x00000000 },
- { 0x419f40, 1, 0x04, 0x00000018 },
- { 0x419f44, 3, 0x04, 0x00000000 },
- { 0x419f58, 1, 0x04, 0x00000000 },
- { 0x419f70, 1, 0x04, 0x00006300 },
- { 0x419f78, 1, 0x04, 0x000000eb },
- { 0x419f7c, 1, 0x04, 0x00000404 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gk110b_grctx_pack_tpc[] = {
- { nvd7_grctx_init_pe_0 },
- { nvf0_grctx_init_tex_0 },
- { nvf0_grctx_init_mpc_0 },
- { nvf0_grctx_init_l1c_0 },
- { gk110b_grctx_init_sm_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-gk110b_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xf1),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nve4_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = nvf0_grctx_pack_hub,
- .gpc = nvf0_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = gk110b_grctx_pack_tpc,
- .ppc = nvf0_grctx_pack_ppc,
- .icmd = nvf0_grctx_pack_icmd,
- .mthd = nvf0_grctx_pack_mthd,
- .bundle = nve4_grctx_generate_bundle,
- .bundle_size = 0x3000,
- .bundle_min_gpm_fifo_depth = 0x180,
- .bundle_token_limit = 0x600,
- .pagepool = nve4_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvd7_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x7ff,
- .alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c
deleted file mode 100644
index 36fc9831cc93..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgk20a.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "ctxnvc0.h"
-
-static const struct nvc0_graph_pack
-gk20a_grctx_pack_mthd[] = {
- { nve4_grctx_init_a097_0, 0xa297 },
- { nvc0_grctx_init_902d_0, 0x902d },
- {}
-};
-
-struct nouveau_oclass *
-gk20a_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xea),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nve4_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = nve4_grctx_pack_hub,
- .gpc = nve4_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nve4_grctx_pack_tpc,
- .ppc = nve4_grctx_pack_ppc,
- .icmd = nve4_grctx_pack_icmd,
- .mthd = gk20a_grctx_pack_mthd,
- .bundle = nve4_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .bundle_min_gpm_fifo_depth = 0x62,
- .bundle_token_limit = 0x100,
- .pagepool = nve4_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvd7_grctx_generate_attrib,
- .attrib_nr_max = 0x240,
- .attrib_nr = 0x240,
- .alpha_nr_max = 0x648 + (0x648 / 2),
- .alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c
deleted file mode 100644
index 62e918b9fa81..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxgm107.c
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gm107_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x0000b1, 2, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000a8, 1, 0x01, 0x0000ffff },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002f2, 2, 0x01, 0x00000001 },
- { 0x0002f5, 1, 0x01, 0x00000001 },
- { 0x0002f7, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x0000de, 1, 0x01, 0x00000001 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000383, 1, 0x01, 0x00000011 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x0005d0, 1, 0x01, 0x20181008 },
- { 0x0005d1, 1, 0x01, 0x40383028 },
- { 0x0005d2, 1, 0x01, 0x60585048 },
- { 0x0005d3, 1, 0x01, 0x80787068 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000550, 32, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x000595, 1, 0x01, 0x00400040 },
- { 0x000596, 1, 0x01, 0x00000492 },
- { 0x000597, 1, 0x01, 0x08080203 },
- { 0x0005ad, 1, 0x01, 0x00000008 },
- { 0x000598, 1, 0x01, 0x00020001 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000662, 1, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x000a0d, 1, 0x01, 0x00000006 },
- { 0x00097d, 1, 0x01, 0x0000000c },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000687, 1, 0x01, 0x003fffff },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00400008 },
- { 0x000841, 1, 0x01, 0x08000080 },
- { 0x000842, 1, 0x01, 0x00400008 },
- { 0x000843, 1, 0x01, 0x08000080 },
- { 0x000818, 8, 0x01, 0x00000000 },
- { 0x000848, 16, 0x01, 0x00000000 },
- { 0x000738, 1, 0x01, 0x00000000 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000008 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000818, 8, 0x01, 0x00000000 },
- { 0x000848, 16, 0x01, 0x00000000 },
- { 0x000738, 1, 0x01, 0x00000000 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_icmd[] = {
- { gm107_grctx_init_icmd_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_b097_0[] = {
- { 0x000800, 8, 0x40, 0x00000000 },
- { 0x000804, 8, 0x40, 0x00000000 },
- { 0x000808, 8, 0x40, 0x00000400 },
- { 0x00080c, 8, 0x40, 0x00000300 },
- { 0x000810, 1, 0x04, 0x000000cf },
- { 0x000850, 7, 0x40, 0x00000000 },
- { 0x000814, 8, 0x40, 0x00000040 },
- { 0x000818, 8, 0x40, 0x00000001 },
- { 0x00081c, 8, 0x40, 0x00000000 },
- { 0x000820, 8, 0x40, 0x00000000 },
- { 0x001c00, 16, 0x10, 0x00000000 },
- { 0x001c04, 16, 0x10, 0x00000000 },
- { 0x001c08, 16, 0x10, 0x00000000 },
- { 0x001c0c, 16, 0x10, 0x00000000 },
- { 0x001d00, 16, 0x10, 0x00000000 },
- { 0x001d04, 16, 0x10, 0x00000000 },
- { 0x001d08, 16, 0x10, 0x00000000 },
- { 0x001d0c, 16, 0x10, 0x00000000 },
- { 0x001f00, 16, 0x08, 0x00000000 },
- { 0x001f04, 16, 0x08, 0x00000000 },
- { 0x001f80, 16, 0x08, 0x00000000 },
- { 0x001f84, 16, 0x08, 0x00000000 },
- { 0x002000, 1, 0x04, 0x00000000 },
- { 0x002040, 1, 0x04, 0x00000011 },
- { 0x002080, 1, 0x04, 0x00000020 },
- { 0x0020c0, 1, 0x04, 0x00000030 },
- { 0x002100, 1, 0x04, 0x00000040 },
- { 0x002140, 1, 0x04, 0x00000051 },
- { 0x00200c, 6, 0x40, 0x00000001 },
- { 0x002010, 1, 0x04, 0x00000000 },
- { 0x002050, 1, 0x04, 0x00000000 },
- { 0x002090, 1, 0x04, 0x00000001 },
- { 0x0020d0, 1, 0x04, 0x00000002 },
- { 0x002110, 1, 0x04, 0x00000003 },
- { 0x002150, 1, 0x04, 0x00000004 },
- { 0x000380, 4, 0x20, 0x00000000 },
- { 0x000384, 4, 0x20, 0x00000000 },
- { 0x000388, 4, 0x20, 0x00000000 },
- { 0x00038c, 4, 0x20, 0x00000000 },
- { 0x000700, 4, 0x10, 0x00000000 },
- { 0x000704, 4, 0x10, 0x00000000 },
- { 0x000708, 4, 0x10, 0x00000000 },
- { 0x002800, 128, 0x04, 0x00000000 },
- { 0x000a00, 16, 0x20, 0x00000000 },
- { 0x000a04, 16, 0x20, 0x00000000 },
- { 0x000a08, 16, 0x20, 0x00000000 },
- { 0x000a0c, 16, 0x20, 0x00000000 },
- { 0x000a10, 16, 0x20, 0x00000000 },
- { 0x000a14, 16, 0x20, 0x00000000 },
- { 0x000c00, 16, 0x10, 0x00000000 },
- { 0x000c04, 16, 0x10, 0x00000000 },
- { 0x000c08, 16, 0x10, 0x00000000 },
- { 0x000c0c, 16, 0x10, 0x3f800000 },
- { 0x000d00, 8, 0x08, 0xffff0000 },
- { 0x000d04, 8, 0x08, 0xffff0000 },
- { 0x000e00, 16, 0x10, 0x00000000 },
- { 0x000e04, 16, 0x10, 0xffff0000 },
- { 0x000e08, 16, 0x10, 0xffff0000 },
- { 0x000d40, 4, 0x08, 0x00000000 },
- { 0x000d44, 4, 0x08, 0x00000000 },
- { 0x001e00, 8, 0x20, 0x00000001 },
- { 0x001e04, 8, 0x20, 0x00000001 },
- { 0x001e08, 8, 0x20, 0x00000002 },
- { 0x001e0c, 8, 0x20, 0x00000001 },
- { 0x001e10, 8, 0x20, 0x00000001 },
- { 0x001e14, 8, 0x20, 0x00000002 },
- { 0x001e18, 8, 0x20, 0x00000001 },
- { 0x001480, 8, 0x10, 0x00000000 },
- { 0x001484, 8, 0x10, 0x00000000 },
- { 0x001488, 8, 0x10, 0x00000000 },
- { 0x003400, 128, 0x04, 0x00000000 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x001514, 1, 0x04, 0x00000000 },
- { 0x000d68, 1, 0x04, 0x0000ffff },
- { 0x00121c, 1, 0x04, 0x0fac6881 },
- { 0x000fac, 1, 0x04, 0x00000001 },
- { 0x001538, 1, 0x04, 0x00000001 },
- { 0x000fe0, 2, 0x04, 0x00000000 },
- { 0x000fe8, 1, 0x04, 0x00000014 },
- { 0x000fec, 1, 0x04, 0x00000040 },
- { 0x000ff0, 1, 0x04, 0x00000000 },
- { 0x00179c, 1, 0x04, 0x00000000 },
- { 0x001228, 1, 0x04, 0x00000400 },
- { 0x00122c, 1, 0x04, 0x00000300 },
- { 0x001230, 1, 0x04, 0x00010001 },
- { 0x0007f8, 1, 0x04, 0x00000000 },
- { 0x0015b4, 1, 0x04, 0x00000001 },
- { 0x0015cc, 1, 0x04, 0x00000000 },
- { 0x001534, 1, 0x04, 0x00000000 },
- { 0x000754, 1, 0x04, 0x00000001 },
- { 0x000fb0, 1, 0x04, 0x00000000 },
- { 0x0015d0, 1, 0x04, 0x00000000 },
- { 0x00153c, 1, 0x04, 0x00000000 },
- { 0x0016b4, 1, 0x04, 0x00000003 },
- { 0x000fbc, 4, 0x04, 0x0000ffff },
- { 0x000df8, 2, 0x04, 0x00000000 },
- { 0x001948, 1, 0x04, 0x00000000 },
- { 0x001970, 1, 0x04, 0x00000001 },
- { 0x00161c, 1, 0x04, 0x000009f0 },
- { 0x000dcc, 1, 0x04, 0x00000010 },
- { 0x0015e4, 1, 0x04, 0x00000000 },
- { 0x001160, 32, 0x04, 0x25e00040 },
- { 0x001880, 32, 0x04, 0x00000000 },
- { 0x000f84, 2, 0x04, 0x00000000 },
- { 0x0017c8, 2, 0x04, 0x00000000 },
- { 0x0017d0, 1, 0x04, 0x000000ff },
- { 0x0017d4, 1, 0x04, 0xffffffff },
- { 0x0017d8, 1, 0x04, 0x00000002 },
- { 0x0017dc, 1, 0x04, 0x00000000 },
- { 0x0015f4, 2, 0x04, 0x00000000 },
- { 0x001434, 2, 0x04, 0x00000000 },
- { 0x000d74, 1, 0x04, 0x00000000 },
- { 0x0013a4, 1, 0x04, 0x00000000 },
- { 0x001318, 1, 0x04, 0x00000001 },
- { 0x001080, 2, 0x04, 0x00000000 },
- { 0x001088, 2, 0x04, 0x00000001 },
- { 0x001090, 1, 0x04, 0x00000000 },
- { 0x001094, 1, 0x04, 0x00000001 },
- { 0x001098, 1, 0x04, 0x00000000 },
- { 0x00109c, 1, 0x04, 0x00000001 },
- { 0x0010a0, 2, 0x04, 0x00000000 },
- { 0x001644, 1, 0x04, 0x00000000 },
- { 0x000748, 1, 0x04, 0x00000000 },
- { 0x000de8, 1, 0x04, 0x00000000 },
- { 0x001648, 1, 0x04, 0x00000000 },
- { 0x0012a4, 1, 0x04, 0x00000000 },
- { 0x001120, 4, 0x04, 0x00000000 },
- { 0x001118, 1, 0x04, 0x00000000 },
- { 0x00164c, 1, 0x04, 0x00000000 },
- { 0x001658, 1, 0x04, 0x00000000 },
- { 0x001910, 1, 0x04, 0x00000290 },
- { 0x001518, 1, 0x04, 0x00000000 },
- { 0x00165c, 1, 0x04, 0x00000001 },
- { 0x001520, 1, 0x04, 0x00000000 },
- { 0x001604, 1, 0x04, 0x00000000 },
- { 0x001570, 1, 0x04, 0x00000000 },
- { 0x0013b0, 2, 0x04, 0x3f800000 },
- { 0x00020c, 1, 0x04, 0x00000000 },
- { 0x001670, 1, 0x04, 0x30201000 },
- { 0x001674, 1, 0x04, 0x70605040 },
- { 0x001678, 1, 0x04, 0xb8a89888 },
- { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
- { 0x00166c, 1, 0x04, 0x00000000 },
- { 0x001680, 1, 0x04, 0x00ffff00 },
- { 0x0012d0, 1, 0x04, 0x00000003 },
- { 0x0012d4, 1, 0x04, 0x00000002 },
- { 0x001684, 2, 0x04, 0x00000000 },
- { 0x000dac, 2, 0x04, 0x00001b02 },
- { 0x000db4, 1, 0x04, 0x00000000 },
- { 0x00168c, 1, 0x04, 0x00000000 },
- { 0x0015bc, 1, 0x04, 0x00000000 },
- { 0x00156c, 1, 0x04, 0x00000000 },
- { 0x00187c, 1, 0x04, 0x00000000 },
- { 0x001110, 1, 0x04, 0x00000001 },
- { 0x000dc0, 3, 0x04, 0x00000000 },
- { 0x000f40, 5, 0x04, 0x00000000 },
- { 0x001234, 1, 0x04, 0x00000000 },
- { 0x001690, 1, 0x04, 0x00000000 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x001000, 1, 0x04, 0x00000010 },
- { 0x0010fc, 1, 0x04, 0x00000000 },
- { 0x001290, 1, 0x04, 0x00000000 },
- { 0x000218, 1, 0x04, 0x00000010 },
- { 0x0012d8, 1, 0x04, 0x00000000 },
- { 0x0012dc, 1, 0x04, 0x00000010 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x00155c, 2, 0x04, 0x00000000 },
- { 0x001564, 1, 0x04, 0x00000fff },
- { 0x001574, 2, 0x04, 0x00000000 },
- { 0x00157c, 1, 0x04, 0x000fffff },
- { 0x001354, 1, 0x04, 0x00000000 },
- { 0x001610, 1, 0x04, 0x00000012 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x00260c, 1, 0x04, 0x00000000 },
- { 0x0007ac, 1, 0x04, 0x00000000 },
- { 0x00162c, 1, 0x04, 0x00000003 },
- { 0x000210, 1, 0x04, 0x00000000 },
- { 0x000320, 1, 0x04, 0x00000000 },
- { 0x000324, 6, 0x04, 0x3f800000 },
- { 0x000750, 1, 0x04, 0x00000000 },
- { 0x000760, 1, 0x04, 0x39291909 },
- { 0x000764, 1, 0x04, 0x79695949 },
- { 0x000768, 1, 0x04, 0xb9a99989 },
- { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
- { 0x000770, 1, 0x04, 0x30201000 },
- { 0x000774, 1, 0x04, 0x70605040 },
- { 0x000778, 1, 0x04, 0x00009080 },
- { 0x000780, 1, 0x04, 0x39291909 },
- { 0x000784, 1, 0x04, 0x79695949 },
- { 0x000788, 1, 0x04, 0xb9a99989 },
- { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
- { 0x0007d0, 1, 0x04, 0x30201000 },
- { 0x0007d4, 1, 0x04, 0x70605040 },
- { 0x0007d8, 1, 0x04, 0x00009080 },
- { 0x00037c, 1, 0x04, 0x00000001 },
- { 0x000740, 2, 0x04, 0x00000000 },
- { 0x002600, 1, 0x04, 0x00000000 },
- { 0x001918, 1, 0x04, 0x00000000 },
- { 0x00191c, 1, 0x04, 0x00000900 },
- { 0x001920, 1, 0x04, 0x00000405 },
- { 0x001308, 1, 0x04, 0x00000001 },
- { 0x001924, 1, 0x04, 0x00000000 },
- { 0x0013ac, 1, 0x04, 0x00000000 },
- { 0x00192c, 1, 0x04, 0x00000001 },
- { 0x00193c, 1, 0x04, 0x00002c1c },
- { 0x000d7c, 1, 0x04, 0x00000000 },
- { 0x000f8c, 1, 0x04, 0x00000000 },
- { 0x0002c0, 1, 0x04, 0x00000001 },
- { 0x001510, 1, 0x04, 0x00000000 },
- { 0x001940, 1, 0x04, 0x00000000 },
- { 0x000ff4, 2, 0x04, 0x00000000 },
- { 0x00194c, 2, 0x04, 0x00000000 },
- { 0x001968, 1, 0x04, 0x00000000 },
- { 0x001590, 1, 0x04, 0x0000003f },
- { 0x0007e8, 4, 0x04, 0x00000000 },
- { 0x00196c, 1, 0x04, 0x00000011 },
- { 0x0002e4, 1, 0x04, 0x0000b001 },
- { 0x00036c, 2, 0x04, 0x00000000 },
- { 0x00197c, 1, 0x04, 0x00000000 },
- { 0x000fcc, 2, 0x04, 0x00000000 },
- { 0x0002d8, 1, 0x04, 0x00000040 },
- { 0x001980, 1, 0x04, 0x00000080 },
- { 0x001504, 1, 0x04, 0x00000080 },
- { 0x001984, 1, 0x04, 0x00000000 },
- { 0x000f60, 1, 0x04, 0x00000000 },
- { 0x000f64, 1, 0x04, 0x00400040 },
- { 0x000f68, 1, 0x04, 0x00002212 },
- { 0x000f6c, 1, 0x04, 0x08080203 },
- { 0x001108, 1, 0x04, 0x00000008 },
- { 0x000f70, 1, 0x04, 0x00080001 },
- { 0x000ffc, 1, 0x04, 0x00000000 },
- { 0x000300, 1, 0x04, 0x00000001 },
- { 0x0013a8, 1, 0x04, 0x00000000 },
- { 0x0012ec, 1, 0x04, 0x00000000 },
- { 0x001310, 1, 0x04, 0x00000000 },
- { 0x001314, 1, 0x04, 0x00000001 },
- { 0x001380, 1, 0x04, 0x00000000 },
- { 0x001384, 4, 0x04, 0x00000001 },
- { 0x001394, 1, 0x04, 0x00000000 },
- { 0x00139c, 1, 0x04, 0x00000000 },
- { 0x001398, 1, 0x04, 0x00000000 },
- { 0x001594, 1, 0x04, 0x00000000 },
- { 0x001598, 4, 0x04, 0x00000001 },
- { 0x000f54, 3, 0x04, 0x00000000 },
- { 0x0019bc, 1, 0x04, 0x00000000 },
- { 0x000f9c, 2, 0x04, 0x00000000 },
- { 0x0012cc, 1, 0x04, 0x00000000 },
- { 0x0012e8, 1, 0x04, 0x00000000 },
- { 0x00130c, 1, 0x04, 0x00000001 },
- { 0x001360, 8, 0x04, 0x00000000 },
- { 0x00133c, 2, 0x04, 0x00000001 },
- { 0x001344, 1, 0x04, 0x00000002 },
- { 0x001348, 2, 0x04, 0x00000001 },
- { 0x001350, 1, 0x04, 0x00000002 },
- { 0x001358, 1, 0x04, 0x00000001 },
- { 0x0012e4, 1, 0x04, 0x00000000 },
- { 0x00131c, 4, 0x04, 0x00000000 },
- { 0x0019c0, 1, 0x04, 0x00000000 },
- { 0x001140, 1, 0x04, 0x00000000 },
- { 0x000dd0, 1, 0x04, 0x00000000 },
- { 0x000dd4, 1, 0x04, 0x00000001 },
- { 0x0002f4, 1, 0x04, 0x00000000 },
- { 0x0019c4, 1, 0x04, 0x00000000 },
- { 0x0019c8, 1, 0x04, 0x00001500 },
- { 0x00135c, 1, 0x04, 0x00000000 },
- { 0x000f90, 1, 0x04, 0x00000000 },
- { 0x0019e0, 8, 0x04, 0x00000001 },
- { 0x0019cc, 1, 0x04, 0x00000001 },
- { 0x0015b8, 1, 0x04, 0x00000000 },
- { 0x001a00, 1, 0x04, 0x00001111 },
- { 0x001a04, 7, 0x04, 0x00000000 },
- { 0x000d6c, 2, 0x04, 0xffff0000 },
- { 0x0010f8, 1, 0x04, 0x00001010 },
- { 0x000d80, 5, 0x04, 0x00000000 },
- { 0x000da0, 1, 0x04, 0x00000000 },
- { 0x0007a4, 2, 0x04, 0x00000000 },
- { 0x001508, 1, 0x04, 0x80000000 },
- { 0x00150c, 1, 0x04, 0x40000000 },
- { 0x001668, 1, 0x04, 0x00000000 },
- { 0x000318, 2, 0x04, 0x00000008 },
- { 0x000d9c, 1, 0x04, 0x00000001 },
- { 0x000f14, 1, 0x04, 0x00000000 },
- { 0x000374, 1, 0x04, 0x00000000 },
- { 0x000378, 1, 0x04, 0x0000000c },
- { 0x0007dc, 1, 0x04, 0x00000000 },
- { 0x00074c, 1, 0x04, 0x00000055 },
- { 0x001420, 1, 0x04, 0x00000003 },
- { 0x001008, 1, 0x04, 0x00000008 },
- { 0x00100c, 1, 0x04, 0x00000040 },
- { 0x001010, 1, 0x04, 0x0000012c },
- { 0x000d60, 1, 0x04, 0x00000040 },
- { 0x001018, 1, 0x04, 0x00000020 },
- { 0x00101c, 1, 0x04, 0x00000001 },
- { 0x001020, 1, 0x04, 0x00000020 },
- { 0x001024, 1, 0x04, 0x00000001 },
- { 0x001444, 3, 0x04, 0x00000000 },
- { 0x000360, 1, 0x04, 0x20164010 },
- { 0x000364, 1, 0x04, 0x00000020 },
- { 0x000368, 1, 0x04, 0x00000000 },
- { 0x000da8, 1, 0x04, 0x00000030 },
- { 0x000de4, 1, 0x04, 0x00000000 },
- { 0x000204, 1, 0x04, 0x00000006 },
- { 0x0002d0, 1, 0x04, 0x003fffff },
- { 0x001220, 1, 0x04, 0x00000005 },
- { 0x000fdc, 1, 0x04, 0x00000000 },
- { 0x000f98, 1, 0x04, 0x00400008 },
- { 0x001284, 1, 0x04, 0x08000080 },
- { 0x001450, 1, 0x04, 0x00400008 },
- { 0x001454, 1, 0x04, 0x08000080 },
- { 0x000214, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_mthd[] = {
- { gm107_grctx_init_b097_0, 0xb097 },
- { nvc0_grctx_init_902d_0, 0x902d },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_fe_0[] = {
- { 0x404004, 8, 0x04, 0x00000000 },
- { 0x404024, 1, 0x04, 0x0000e000 },
- { 0x404028, 8, 0x04, 0x00000000 },
- { 0x4040a8, 8, 0x04, 0x00000000 },
- { 0x4040c8, 1, 0x04, 0xf800008f },
- { 0x4040d0, 6, 0x04, 0x00000000 },
- { 0x4040f8, 1, 0x04, 0x00000000 },
- { 0x404100, 10, 0x04, 0x00000000 },
- { 0x404130, 2, 0x04, 0x00000000 },
- { 0x404150, 1, 0x04, 0x0000002e },
- { 0x404154, 1, 0x04, 0x00000400 },
- { 0x404158, 1, 0x04, 0x00000200 },
- { 0x404164, 1, 0x04, 0x00000045 },
- { 0x40417c, 2, 0x04, 0x00000000 },
- { 0x404194, 1, 0x04, 0x01000700 },
- { 0x4041a0, 4, 0x04, 0x00000000 },
- { 0x404200, 4, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x0f8001bf },
- { 0x405830, 1, 0x04, 0x0aa01000 },
- { 0x405834, 1, 0x04, 0x08000000 },
- { 0x405838, 1, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- { 0x405a1c, 1, 0x04, 0x000000ff },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x07410001 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b0, 3, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x80400280 },
- { 0x4064c4, 1, 0x04, 0x0400ffff },
- { 0x4064c8, 1, 0x04, 0x018001ff },
- { 0x4064cc, 9, 0x04, 0x00000000 },
- { 0x4064fc, 1, 0x04, 0x0000022a },
- { 0x406500, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x32802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x1003e005 },
- { 0x408840, 1, 0x04, 0x0000000b },
- { 0x408900, 1, 0x04, 0xb080b801 },
- { 0x408904, 1, 0x04, 0x63038001 },
- { 0x408908, 1, 0x04, 0x02c8102f },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { gm107_grctx_init_fe_0 },
- { nvf0_grctx_init_pri_0 },
- { nve4_grctx_init_memfmt_0 },
- { gm107_grctx_init_ds_0 },
- { nvf0_grctx_init_cwd_0 },
- { gm107_grctx_init_pd_0 },
- { nv108_grctx_init_rstr2d_0 },
- { nve4_grctx_init_scc_0 },
- { gm107_grctx_init_be_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_gpc_unk_0[] = {
- { 0x418380, 1, 0x04, 0x00000056 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_gpc_unk_1[] = {
- { 0x418600, 1, 0x04, 0x0000007f },
- { 0x418684, 1, 0x04, 0x0000001f },
- { 0x418700, 1, 0x04, 0x00000002 },
- { 0x418704, 1, 0x04, 0x00000080 },
- { 0x418708, 1, 0x04, 0x40000000 },
- { 0x41870c, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x7006863a },
- { 0x418810, 1, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00000044 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100058 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_gpc_unk_2[] = {
- { 0x418d24, 1, 0x04, 0x00000000 },
- { 0x418e00, 1, 0x04, 0x90000000 },
- { 0x418e24, 1, 0x04, 0x00000000 },
- { 0x418e28, 1, 0x04, 0x00000030 },
- { 0x418e30, 1, 0x04, 0x00000000 },
- { 0x418e34, 1, 0x04, 0x00010000 },
- { 0x418e38, 1, 0x04, 0x00000000 },
- { 0x418e40, 22, 0x04, 0x00000000 },
- { 0x418ea0, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_gpc[] = {
- { gm107_grctx_init_gpc_unk_0 },
- { nv108_grctx_init_prop_0 },
- { gm107_grctx_init_gpc_unk_1 },
- { gm107_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nv108_grctx_init_crstr_0 },
- { nve4_grctx_init_gpm_0 },
- { gm107_grctx_init_gpc_unk_2 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000300f0 },
- { 0x419a04, 1, 0x04, 0x00000005 },
- { 0x419a08, 1, 0x04, 0x00000421 },
- { 0x419a0c, 1, 0x04, 0x00120000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00002200 },
- { 0x419a1c, 1, 0x04, 0x0000c000 },
- { 0x419a20, 1, 0x04, 0x20008a00 },
- { 0x419a30, 1, 0x04, 0x00000001 },
- { 0x419a3c, 1, 0x04, 0x00000002 },
- { 0x419ac4, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_mpc_0[] = {
- { 0x419c00, 1, 0x04, 0x0000001a },
- { 0x419c04, 1, 0x04, 0x80000006 },
- { 0x419c08, 1, 0x04, 0x00000002 },
- { 0x419c20, 1, 0x04, 0x00000000 },
- { 0x419c24, 1, 0x04, 0x00084210 },
- { 0x419c28, 1, 0x04, 0x3efbefbe },
- { 0x419c2c, 1, 0x04, 0x00000000 },
- { 0x419c34, 1, 0x04, 0x01ff1ff3 },
- { 0x419c3c, 1, 0x04, 0x00001919 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_l1c_0[] = {
- { 0x419c84, 1, 0x04, 0x00000020 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_sm_0[] = {
- { 0x419e04, 3, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00001c02 },
- { 0x419e44, 1, 0x04, 0x00d3eff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000007f },
- { 0x419e50, 1, 0x04, 0x00000000 },
- { 0x419e60, 4, 0x04, 0x00000000 },
- { 0x419e74, 10, 0x04, 0x00000000 },
- { 0x419eac, 1, 0x04, 0x0001cf8b },
- { 0x419eb0, 1, 0x04, 0x00030300 },
- { 0x419eb8, 1, 0x04, 0x00000000 },
- { 0x419ef0, 24, 0x04, 0x00000000 },
- { 0x419f68, 2, 0x04, 0x00000000 },
- { 0x419f70, 1, 0x04, 0x00000020 },
- { 0x419f78, 1, 0x04, 0x000003eb },
- { 0x419f7c, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_tpc[] = {
- { nvd7_grctx_init_pe_0 },
- { gm107_grctx_init_tex_0 },
- { gm107_grctx_init_mpc_0 },
- { gm107_grctx_init_l1c_0 },
- { gm107_grctx_init_sm_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_cbm_0[] = {
- { 0x41bec0, 1, 0x04, 0x00000000 },
- { 0x41bec4, 1, 0x04, 0x01050000 },
- { 0x41bee4, 1, 0x04, 0x00000000 },
- { 0x41bef0, 1, 0x04, 0x000003ff },
- { 0x41bef4, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_grctx_init_wwdx_0[] = {
- { 0x41bf00, 1, 0x04, 0x0a418820 },
- { 0x41bf04, 1, 0x04, 0x062080e6 },
- { 0x41bf08, 1, 0x04, 0x020398a4 },
- { 0x41bf0c, 1, 0x04, 0x0e629062 },
- { 0x41bf10, 1, 0x04, 0x0a418820 },
- { 0x41bf14, 1, 0x04, 0x000000e6 },
- { 0x41bfd0, 1, 0x04, 0x00900103 },
- { 0x41bfe0, 1, 0x04, 0x80000000 },
- { 0x41bfe4, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_grctx_pack_ppc[] = {
- { nve4_grctx_init_pes_0 },
- { gm107_grctx_init_cbm_0 },
- { gm107_grctx_init_wwdx_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-static void
-gm107_grctx_generate_bundle(struct nvc0_grctx *info)
-{
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
- const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
- impl->bundle_size / 0x20);
- const u32 token_limit = impl->bundle_token_limit;
- const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
- const int s = 8;
- const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
- mmio_refn(info, 0x408004, 0x00000000, s, b);
- mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
- mmio_refn(info, 0x418e24, 0x00000000, s, b);
- mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
- mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
-}
-
-static void
-gm107_grctx_generate_pagepool(struct nvc0_grctx *info)
-{
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
- const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
- const int s = 8;
- const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x80000000);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
- mmio_wr32(info, 0x4064cc, 0x80000000);
- mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */
-}
-
-static void
-gm107_grctx_generate_attrib(struct nvc0_grctx *info)
-{
- struct nvc0_graph_priv *priv = info->priv;
- const struct nvc0_grctx_oclass *impl = (void *)nvc0_grctx_impl(priv);
- const u32 alpha = impl->alpha_nr;
- const u32 attrib = impl->attrib_nr;
- const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
- const u32 access = NV_MEM_ACCESS_RW;
- const int s = 12;
- const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
- const int max_batches = 0xffff;
- u32 bo = 0;
- u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
- int gpc, ppc, n = 0;
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_refn(info, 0x419c2c, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (attrib << 16) | alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) {
- const u32 as = alpha * priv->ppc_tpc_nr[gpc][ppc];
- const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc];
- const u32 u = 0x418ea0 + (n * 0x04);
- const u32 o = PPC_UNIT(gpc, ppc, 0);
- mmio_wr32(info, o + 0xc0, bs);
- mmio_wr32(info, o + 0xf4, bo);
- bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, o + 0xe4, as);
- mmio_wr32(info, o + 0xf8, ao);
- ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, u, (0x715 /*XXX*/ << 16) | bs);
- }
- }
-}
-
-static void
-gm107_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
-{
- int gpc, tpc, id;
-
- for (tpc = 0, id = 0; tpc < 4; tpc++) {
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- if (tpc < priv->tpc_nr[gpc]) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
- id++;
- }
-
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
- }
- }
-}
-
-static void
-gm107_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
- struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
- int i;
-
- nvc0_graph_mmio(priv, oclass->hub);
- nvc0_graph_mmio(priv, oclass->gpc);
- nvc0_graph_mmio(priv, oclass->zcull);
- nvc0_graph_mmio(priv, oclass->tpc);
- nvc0_graph_mmio(priv, oclass->ppc);
-
- nv_wr32(priv, 0x404154, 0x00000000);
-
- oclass->bundle(info);
- oclass->pagepool(info);
- oclass->attrib(info);
- oclass->unkn(priv);
-
- gm107_grctx_generate_tpcid(priv);
- nvc0_grctx_generate_r406028(priv);
- nve4_grctx_generate_r418bb8(priv);
- nvc0_grctx_generate_r406800(priv);
-
- nv_wr32(priv, 0x4064d0, 0x00000001);
- for (i = 1; i < 8; i++)
- nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
- nv_wr32(priv, 0x406500, 0x00000001);
-
- nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
-
- if (priv->gpc_nr == 1) {
- nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
- nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
- } else {
- nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
- nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
- }
-
- nvc0_graph_icmd(priv, oclass->icmd);
- nv_wr32(priv, 0x404154, 0x00000400);
- nvc0_graph_mthd(priv, oclass->mthd);
-
- nv_mask(priv, 0x419e00, 0x00808080, 0x00808080);
- nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000);
- nv_mask(priv, 0x419f80, 0x80000000, 0x80000000);
- nv_mask(priv, 0x419f88, 0x80000000, 0x80000000);
-}
-
-struct nouveau_oclass *
-gm107_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0x08),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = gm107_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = gm107_grctx_pack_hub,
- .gpc = gm107_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = gm107_grctx_pack_tpc,
- .ppc = gm107_grctx_pack_ppc,
- .icmd = gm107_grctx_pack_icmd,
- .mthd = gm107_grctx_pack_mthd,
- .bundle = gm107_grctx_generate_bundle,
- .bundle_size = 0x3000,
- .bundle_min_gpm_fifo_depth = 0x180,
- .bundle_token_limit = 0x2c0,
- .pagepool = gm107_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = gm107_grctx_generate_attrib,
- .attrib_nr_max = 0xff0,
- .attrib_nr = 0xaa0,
- .alpha_nr_max = 0x1800,
- .alpha_nr = 0x1000,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c
deleted file mode 100644
index ce252adbef81..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv108.c
+++ /dev/null
@@ -1,565 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nv108_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x0002f2, 2, 0x01, 0x00000001 },
- { 0x0002f5, 1, 0x01, 0x00000001 },
- { 0x0002f7, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000383, 1, 0x01, 0x00000011 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000662, 1, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x00080b, 1, 0x01, 0x00000002 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x000a0d, 1, 0x01, 0x00000006 },
- { 0x00097d, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x003fffff },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00400008 },
- { 0x000841, 1, 0x01, 0x08000080 },
- { 0x000842, 1, 0x01, 0x00400008 },
- { 0x000843, 1, 0x01, 0x08000080 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x00c500, 1, 0x01, 0x00000003 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000008 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x00c500, 1, 0x01, 0x00000003 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_icmd[] = {
- { nv108_grctx_init_icmd_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_fe_0[] = {
- { 0x404004, 8, 0x04, 0x00000000 },
- { 0x404024, 1, 0x04, 0x0000e000 },
- { 0x404028, 8, 0x04, 0x00000000 },
- { 0x4040a8, 8, 0x04, 0x00000000 },
- { 0x4040c8, 1, 0x04, 0xf800008f },
- { 0x4040d0, 6, 0x04, 0x00000000 },
- { 0x4040e8, 1, 0x04, 0x00001000 },
- { 0x4040f8, 1, 0x04, 0x00000000 },
- { 0x404100, 10, 0x04, 0x00000000 },
- { 0x404130, 2, 0x04, 0x00000000 },
- { 0x404138, 1, 0x04, 0x20000040 },
- { 0x404150, 1, 0x04, 0x0000002e },
- { 0x404154, 1, 0x04, 0x00000400 },
- { 0x404158, 1, 0x04, 0x00000200 },
- { 0x404164, 1, 0x04, 0x00000055 },
- { 0x40417c, 2, 0x04, 0x00000000 },
- { 0x404194, 1, 0x04, 0x01000700 },
- { 0x4041a0, 4, 0x04, 0x00000000 },
- { 0x404200, 1, 0x04, 0x0000a197 },
- { 0x404204, 1, 0x04, 0x0000a1c0 },
- { 0x404208, 1, 0x04, 0x0000a140 },
- { 0x40420c, 1, 0x04, 0x0000902d },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x0f8000bf },
- { 0x405830, 1, 0x04, 0x02180648 },
- { 0x405834, 1, 0x04, 0x08000000 },
- { 0x405838, 1, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- { 0x405a1c, 1, 0x04, 0x000000ff },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x034103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b0, 3, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x802000f0 },
- { 0x4064c4, 1, 0x04, 0x0192ffff },
- { 0x4064c8, 1, 0x04, 0x00c20200 },
- { 0x4064cc, 9, 0x04, 0x00000000 },
- { 0x4064fc, 1, 0x04, 0x0000022a },
- {}
-};
-
-const struct nvc0_graph_init
-nv108_grctx_init_rstr2d_0[] = {
- { 0x407804, 1, 0x04, 0x00000063 },
- { 0x40780c, 1, 0x04, 0x0a418820 },
- { 0x407810, 1, 0x04, 0x062080e6 },
- { 0x407814, 1, 0x04, 0x020398a4 },
- { 0x407818, 1, 0x04, 0x0e629062 },
- { 0x40781c, 1, 0x04, 0x0a418820 },
- { 0x407820, 1, 0x04, 0x000000e6 },
- { 0x4078bc, 1, 0x04, 0x00000103 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x32802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x1003e005 },
- { 0x408840, 1, 0x04, 0x0000000b },
- { 0x408900, 1, 0x04, 0xb080b801 },
- { 0x408904, 1, 0x04, 0x62000001 },
- { 0x408908, 1, 0x04, 0x02c8102f },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nv108_grctx_init_fe_0 },
- { nvf0_grctx_init_pri_0 },
- { nve4_grctx_init_memfmt_0 },
- { nv108_grctx_init_ds_0 },
- { nvf0_grctx_init_cwd_0 },
- { nv108_grctx_init_pd_0 },
- { nv108_grctx_init_rstr2d_0 },
- { nve4_grctx_init_scc_0 },
- { nv108_grctx_init_be_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nv108_grctx_init_prop_0[] = {
- { 0x418400, 1, 0x04, 0x38005e00 },
- { 0x418404, 1, 0x04, 0x71e0ffff },
- { 0x41840c, 1, 0x04, 0x00001008 },
- { 0x418410, 1, 0x04, 0x0fff0fff },
- { 0x418414, 1, 0x04, 0x02200fff },
- { 0x418450, 6, 0x04, 0x00000000 },
- { 0x418468, 1, 0x04, 0x00000001 },
- { 0x41846c, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_gpc_unk_1[] = {
- { 0x418600, 1, 0x04, 0x0000007f },
- { 0x418684, 1, 0x04, 0x0000001f },
- { 0x418700, 1, 0x04, 0x00000002 },
- { 0x418704, 2, 0x04, 0x00000080 },
- { 0x41870c, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x7006863a },
- { 0x418808, 1, 0x04, 0x00000000 },
- { 0x41880c, 1, 0x04, 0x00000030 },
- { 0x418810, 1, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00000044 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100058 },
- {}
-};
-
-const struct nvc0_graph_init
-nv108_grctx_init_crstr_0[] = {
- { 0x418b00, 1, 0x04, 0x0000001e },
- { 0x418b08, 1, 0x04, 0x0a418820 },
- { 0x418b0c, 1, 0x04, 0x062080e6 },
- { 0x418b10, 1, 0x04, 0x020398a4 },
- { 0x418b14, 1, 0x04, 0x0e629062 },
- { 0x418b18, 1, 0x04, 0x0a418820 },
- { 0x418b1c, 1, 0x04, 0x000000e6 },
- { 0x418bb8, 1, 0x04, 0x00000103 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_gpm_0[] = {
- { 0x418c08, 1, 0x04, 0x00000001 },
- { 0x418c10, 8, 0x04, 0x00000000 },
- { 0x418c40, 1, 0x04, 0xffffffff },
- { 0x418c6c, 1, 0x04, 0x00000001 },
- { 0x418c80, 1, 0x04, 0x2020000c },
- { 0x418c8c, 1, 0x04, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nv108_grctx_init_prop_0 },
- { nv108_grctx_init_gpc_unk_1 },
- { nv108_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nv108_grctx_init_crstr_0 },
- { nv108_grctx_init_gpm_0 },
- { nvf0_grctx_init_gpc_unk_2 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000100f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000421 },
- { 0x419a0c, 1, 0x04, 0x00120000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- { 0x419a1c, 1, 0x04, 0x0000c000 },
- { 0x419a20, 1, 0x04, 0x00000800 },
- { 0x419a30, 1, 0x04, 0x00000001 },
- { 0x419ac4, 1, 0x04, 0x0037f440 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_sm_0[] = {
- { 0x419e04, 1, 0x04, 0x00000000 },
- { 0x419e08, 1, 0x04, 0x0000001d },
- { 0x419e0c, 1, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00001c02 },
- { 0x419e44, 1, 0x04, 0x0013eff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000007f },
- { 0x419e50, 2, 0x04, 0x00000000 },
- { 0x419e58, 1, 0x04, 0x00000001 },
- { 0x419e5c, 3, 0x04, 0x00000000 },
- { 0x419e68, 1, 0x04, 0x00000002 },
- { 0x419e6c, 12, 0x04, 0x00000000 },
- { 0x419eac, 1, 0x04, 0x00001f8f },
- { 0x419eb0, 1, 0x04, 0x0db00d2f },
- { 0x419eb8, 1, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x0001304f },
- { 0x419f30, 4, 0x04, 0x00000000 },
- { 0x419f40, 1, 0x04, 0x00000018 },
- { 0x419f44, 3, 0x04, 0x00000000 },
- { 0x419f58, 1, 0x04, 0x00000020 },
- { 0x419f70, 1, 0x04, 0x00000000 },
- { 0x419f78, 1, 0x04, 0x000001eb },
- { 0x419f7c, 1, 0x04, 0x00000404 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_tpc[] = {
- { nvd7_grctx_init_pe_0 },
- { nv108_grctx_init_tex_0 },
- { nvf0_grctx_init_mpc_0 },
- { nvf0_grctx_init_l1c_0 },
- { nv108_grctx_init_sm_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_grctx_init_cbm_0[] = {
- { 0x41bec0, 1, 0x04, 0x10000000 },
- { 0x41bec4, 1, 0x04, 0x00037f7f },
- { 0x41bee4, 1, 0x04, 0x00000000 },
- { 0x41bef0, 1, 0x04, 0x000003ff },
- {}
-};
-
-static const struct nvc0_graph_pack
-nv108_grctx_pack_ppc[] = {
- { nve4_grctx_init_pes_0 },
- { nv108_grctx_init_cbm_0 },
- { nvd7_grctx_init_wwdx_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nv108_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0x08),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nve4_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = nv108_grctx_pack_hub,
- .gpc = nv108_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nv108_grctx_pack_tpc,
- .ppc = nv108_grctx_pack_ppc,
- .icmd = nv108_grctx_pack_icmd,
- .mthd = nvf0_grctx_pack_mthd,
- .bundle = nve4_grctx_generate_bundle,
- .bundle_size = 0x3000,
- .bundle_min_gpm_fifo_depth = 0xc2,
- .bundle_token_limit = 0x200,
- .pagepool = nve4_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvd7_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x7ff,
- .alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
deleted file mode 100644
index 7bbb1e1b7a8d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv40.c
+++ /dev/null
@@ -1,695 +0,0 @@
-/*
- * Copyright 2009 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-/* NVIDIA context programs handle a number of other conditions which are
- * not implemented in our versions. It's not clear why NVIDIA context
- * programs have this code, nor whether it's strictly necessary for
- * correct operation. We'll implement additional handling if/when we
- * discover it's necessary.
- *
- * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state"
- * flag is set, this gets saved into the context.
- * - On context save, the context program for all cards load nsource
- * into a flag register and check for ILLEGAL_MTHD. If it's set,
- * opcode 0x60000d is called before resuming normal operation.
- * - Some context programs check more conditions than the above. NV44
- * checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001))
- * and calls 0x60000d before resuming normal operation.
- * - At the very beginning of NVIDIA's context programs, flag 9 is checked
- * and if true 0x800001 is called with count=0, pos=0, the flag is cleared
- * and then the ctxprog is aborted. It looks like a complicated NOP,
- * its purpose is unknown.
- * - In the section of code that loads the per-vs state, NVIDIA check
- * flag 10. If it's set, they only transfer the small 0x300 byte block
- * of state + the state for a single vs as opposed to the state for
- * all vs units. It doesn't seem likely that it'll occur in normal
- * operation, especially seeing as it appears NVIDIA may have screwed
- * up the ctxprogs for some cards and have an invalid instruction
- * rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction.
- * - There's a number of places where context offset 0 (where we place
- * the PRAMIN offset of the context) is loaded into either 0x408000,
- * 0x408004 or 0x408008. Not sure what's up there either.
- * - The ctxprogs for some cards save 0x400a00 again during the cleanup
- * path for auto-loadctx.
- */
-
-#define CP_FLAG_CLEAR 0
-#define CP_FLAG_SET 1
-#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0)
-#define CP_FLAG_SWAP_DIRECTION_LOAD 0
-#define CP_FLAG_SWAP_DIRECTION_SAVE 1
-#define CP_FLAG_USER_SAVE ((0 * 32) + 5)
-#define CP_FLAG_USER_SAVE_NOT_PENDING 0
-#define CP_FLAG_USER_SAVE_PENDING 1
-#define CP_FLAG_USER_LOAD ((0 * 32) + 6)
-#define CP_FLAG_USER_LOAD_NOT_PENDING 0
-#define CP_FLAG_USER_LOAD_PENDING 1
-#define CP_FLAG_STATUS ((3 * 32) + 0)
-#define CP_FLAG_STATUS_IDLE 0
-#define CP_FLAG_STATUS_BUSY 1
-#define CP_FLAG_AUTO_SAVE ((3 * 32) + 4)
-#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
-#define CP_FLAG_AUTO_SAVE_PENDING 1
-#define CP_FLAG_AUTO_LOAD ((3 * 32) + 5)
-#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
-#define CP_FLAG_AUTO_LOAD_PENDING 1
-#define CP_FLAG_UNK54 ((3 * 32) + 6)
-#define CP_FLAG_UNK54_CLEAR 0
-#define CP_FLAG_UNK54_SET 1
-#define CP_FLAG_ALWAYS ((3 * 32) + 8)
-#define CP_FLAG_ALWAYS_FALSE 0
-#define CP_FLAG_ALWAYS_TRUE 1
-#define CP_FLAG_UNK57 ((3 * 32) + 9)
-#define CP_FLAG_UNK57_CLEAR 0
-#define CP_FLAG_UNK57_SET 1
-
-#define CP_CTX 0x00100000
-#define CP_CTX_COUNT 0x000fc000
-#define CP_CTX_COUNT_SHIFT 14
-#define CP_CTX_REG 0x00003fff
-#define CP_LOAD_SR 0x00200000
-#define CP_LOAD_SR_VALUE 0x000fffff
-#define CP_BRA 0x00400000
-#define CP_BRA_IP 0x0000ff00
-#define CP_BRA_IP_SHIFT 8
-#define CP_BRA_IF_CLEAR 0x00000080
-#define CP_BRA_FLAG 0x0000007f
-#define CP_WAIT 0x00500000
-#define CP_WAIT_SET 0x00000080
-#define CP_WAIT_FLAG 0x0000007f
-#define CP_SET 0x00700000
-#define CP_SET_1 0x00000080
-#define CP_SET_FLAG 0x0000007f
-#define CP_NEXT_TO_SWAP 0x00600007
-#define CP_NEXT_TO_CURRENT 0x00600009
-#define CP_SET_CONTEXT_POINTER 0x0060000a
-#define CP_END 0x0060000e
-#define CP_LOAD_MAGIC_UNK01 0x00800001 /* unknown */
-#define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */
-#define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */
-
-#include "nv40.h"
-#include "ctx.h"
-
-/* TODO:
- * - get vs count from 0x1540
- */
-
-static int
-nv40_graph_vs_count(struct nouveau_device *device)
-{
-
- switch (device->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- return 8;
- case 0x40:
- return 6;
- case 0x41:
- case 0x42:
- return 5;
- case 0x43:
- case 0x44:
- case 0x46:
- case 0x4a:
- return 3;
- case 0x4c:
- case 0x4e:
- case 0x67:
- default:
- return 1;
- }
-}
-
-
-enum cp_label {
- cp_check_load = 1,
- cp_setup_auto_load,
- cp_setup_load,
- cp_setup_save,
- cp_swap_state,
- cp_swap_state3d_3_is_save,
- cp_prepare_exit,
- cp_exit,
-};
-
-static void
-nv40_graph_construct_general(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
-
- cp_ctx(ctx, 0x4000a4, 1);
- gr_def(ctx, 0x4000a4, 0x00000008);
- cp_ctx(ctx, 0x400144, 58);
- gr_def(ctx, 0x400144, 0x00000001);
- cp_ctx(ctx, 0x400314, 1);
- gr_def(ctx, 0x400314, 0x00000000);
- cp_ctx(ctx, 0x400400, 10);
- cp_ctx(ctx, 0x400480, 10);
- cp_ctx(ctx, 0x400500, 19);
- gr_def(ctx, 0x400514, 0x00040000);
- gr_def(ctx, 0x400524, 0x55555555);
- gr_def(ctx, 0x400528, 0x55555555);
- gr_def(ctx, 0x40052c, 0x55555555);
- gr_def(ctx, 0x400530, 0x55555555);
- cp_ctx(ctx, 0x400560, 6);
- gr_def(ctx, 0x400568, 0x0000ffff);
- gr_def(ctx, 0x40056c, 0x0000ffff);
- cp_ctx(ctx, 0x40057c, 5);
- cp_ctx(ctx, 0x400710, 3);
- gr_def(ctx, 0x400710, 0x20010001);
- gr_def(ctx, 0x400714, 0x0f73ef00);
- cp_ctx(ctx, 0x400724, 1);
- gr_def(ctx, 0x400724, 0x02008821);
- cp_ctx(ctx, 0x400770, 3);
- if (device->chipset == 0x40) {
- cp_ctx(ctx, 0x400814, 4);
- cp_ctx(ctx, 0x400828, 5);
- cp_ctx(ctx, 0x400840, 5);
- gr_def(ctx, 0x400850, 0x00000040);
- cp_ctx(ctx, 0x400858, 4);
- gr_def(ctx, 0x400858, 0x00000040);
- gr_def(ctx, 0x40085c, 0x00000040);
- gr_def(ctx, 0x400864, 0x80000000);
- cp_ctx(ctx, 0x40086c, 9);
- gr_def(ctx, 0x40086c, 0x80000000);
- gr_def(ctx, 0x400870, 0x80000000);
- gr_def(ctx, 0x400874, 0x80000000);
- gr_def(ctx, 0x400878, 0x80000000);
- gr_def(ctx, 0x400888, 0x00000040);
- gr_def(ctx, 0x40088c, 0x80000000);
- cp_ctx(ctx, 0x4009c0, 8);
- gr_def(ctx, 0x4009cc, 0x80000000);
- gr_def(ctx, 0x4009dc, 0x80000000);
- } else {
- cp_ctx(ctx, 0x400840, 20);
- if (nv44_graph_class(ctx->device)) {
- for (i = 0; i < 8; i++)
- gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
- }
- gr_def(ctx, 0x400880, 0x00000040);
- gr_def(ctx, 0x400884, 0x00000040);
- gr_def(ctx, 0x400888, 0x00000040);
- cp_ctx(ctx, 0x400894, 11);
- gr_def(ctx, 0x400894, 0x00000040);
- if (!nv44_graph_class(ctx->device)) {
- for (i = 0; i < 8; i++)
- gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
- }
- cp_ctx(ctx, 0x4008e0, 2);
- cp_ctx(ctx, 0x4008f8, 2);
- if (device->chipset == 0x4c ||
- (device->chipset & 0xf0) == 0x60)
- cp_ctx(ctx, 0x4009f8, 1);
- }
- cp_ctx(ctx, 0x400a00, 73);
- gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
- cp_ctx(ctx, 0x401000, 4);
- cp_ctx(ctx, 0x405004, 1);
- switch (device->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- cp_ctx(ctx, 0x403448, 1);
- gr_def(ctx, 0x403448, 0x00001010);
- break;
- default:
- cp_ctx(ctx, 0x403440, 1);
- switch (device->chipset) {
- case 0x40:
- gr_def(ctx, 0x403440, 0x00000010);
- break;
- case 0x44:
- case 0x46:
- case 0x4a:
- gr_def(ctx, 0x403440, 0x00003010);
- break;
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x4c:
- case 0x4e:
- case 0x67:
- default:
- gr_def(ctx, 0x403440, 0x00001010);
- break;
- }
- break;
- }
-}
-
-static void
-nv40_graph_construct_state3d(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
-
- if (device->chipset == 0x40) {
- cp_ctx(ctx, 0x401880, 51);
- gr_def(ctx, 0x401940, 0x00000100);
- } else
- if (device->chipset == 0x46 || device->chipset == 0x47 ||
- device->chipset == 0x49 || device->chipset == 0x4b) {
- cp_ctx(ctx, 0x401880, 32);
- for (i = 0; i < 16; i++)
- gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
- if (device->chipset == 0x46)
- cp_ctx(ctx, 0x401900, 16);
- cp_ctx(ctx, 0x401940, 3);
- }
- cp_ctx(ctx, 0x40194c, 18);
- gr_def(ctx, 0x401954, 0x00000111);
- gr_def(ctx, 0x401958, 0x00080060);
- gr_def(ctx, 0x401974, 0x00000080);
- gr_def(ctx, 0x401978, 0xffff0000);
- gr_def(ctx, 0x40197c, 0x00000001);
- gr_def(ctx, 0x401990, 0x46400000);
- if (device->chipset == 0x40) {
- cp_ctx(ctx, 0x4019a0, 2);
- cp_ctx(ctx, 0x4019ac, 5);
- } else {
- cp_ctx(ctx, 0x4019a0, 1);
- cp_ctx(ctx, 0x4019b4, 3);
- }
- gr_def(ctx, 0x4019bc, 0xffff0000);
- switch (device->chipset) {
- case 0x46:
- case 0x47:
- case 0x49:
- case 0x4b:
- cp_ctx(ctx, 0x4019c0, 18);
- for (i = 0; i < 16; i++)
- gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888);
- break;
- }
- cp_ctx(ctx, 0x401a08, 8);
- gr_def(ctx, 0x401a10, 0x0fff0000);
- gr_def(ctx, 0x401a14, 0x0fff0000);
- gr_def(ctx, 0x401a1c, 0x00011100);
- cp_ctx(ctx, 0x401a2c, 4);
- cp_ctx(ctx, 0x401a44, 26);
- for (i = 0; i < 16; i++)
- gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
- gr_def(ctx, 0x401a8c, 0x4b7fffff);
- if (device->chipset == 0x40) {
- cp_ctx(ctx, 0x401ab8, 3);
- } else {
- cp_ctx(ctx, 0x401ab8, 1);
- cp_ctx(ctx, 0x401ac0, 1);
- }
- cp_ctx(ctx, 0x401ad0, 8);
- gr_def(ctx, 0x401ad0, 0x30201000);
- gr_def(ctx, 0x401ad4, 0x70605040);
- gr_def(ctx, 0x401ad8, 0xb8a89888);
- gr_def(ctx, 0x401adc, 0xf8e8d8c8);
- cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
- gr_def(ctx, 0x401b10, 0x40100000);
- cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
- gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
- 0x00000004 : 0x00000000);
- cp_ctx(ctx, 0x401b30, 25);
- gr_def(ctx, 0x401b34, 0x0000ffff);
- gr_def(ctx, 0x401b68, 0x435185d6);
- gr_def(ctx, 0x401b6c, 0x2155b699);
- gr_def(ctx, 0x401b70, 0xfedcba98);
- gr_def(ctx, 0x401b74, 0x00000098);
- gr_def(ctx, 0x401b84, 0xffffffff);
- gr_def(ctx, 0x401b88, 0x00ff7000);
- gr_def(ctx, 0x401b8c, 0x0000ffff);
- if (device->chipset != 0x44 && device->chipset != 0x4a &&
- device->chipset != 0x4e)
- cp_ctx(ctx, 0x401b94, 1);
- cp_ctx(ctx, 0x401b98, 8);
- gr_def(ctx, 0x401b9c, 0x00ff0000);
- cp_ctx(ctx, 0x401bc0, 9);
- gr_def(ctx, 0x401be0, 0x00ffff00);
- cp_ctx(ctx, 0x401c00, 192);
- for (i = 0; i < 16; i++) { /* fragment texture units */
- gr_def(ctx, 0x401c40 + (i * 4), 0x00018488);
- gr_def(ctx, 0x401c80 + (i * 4), 0x00028202);
- gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4);
- gr_def(ctx, 0x401d40 + (i * 4), 0x01012000);
- gr_def(ctx, 0x401d80 + (i * 4), 0x00080008);
- gr_def(ctx, 0x401e00 + (i * 4), 0x00100008);
- }
- for (i = 0; i < 4; i++) { /* vertex texture units */
- gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80);
- gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202);
- gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008);
- gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008);
- }
- cp_ctx(ctx, 0x400f5c, 3);
- gr_def(ctx, 0x400f5c, 0x00000002);
- cp_ctx(ctx, 0x400f84, 1);
-}
-
-static void
-nv40_graph_construct_state3d_2(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
-
- cp_ctx(ctx, 0x402000, 1);
- cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
- switch (device->chipset) {
- case 0x40:
- gr_def(ctx, 0x402404, 0x00000001);
- break;
- case 0x4c:
- case 0x4e:
- case 0x67:
- gr_def(ctx, 0x402404, 0x00000020);
- break;
- case 0x46:
- case 0x49:
- case 0x4b:
- gr_def(ctx, 0x402404, 0x00000421);
- break;
- default:
- gr_def(ctx, 0x402404, 0x00000021);
- }
- if (device->chipset != 0x40)
- gr_def(ctx, 0x402408, 0x030c30c3);
- switch (device->chipset) {
- case 0x44:
- case 0x46:
- case 0x4a:
- case 0x4c:
- case 0x4e:
- case 0x67:
- cp_ctx(ctx, 0x402440, 1);
- gr_def(ctx, 0x402440, 0x00011001);
- break;
- default:
- break;
- }
- cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
- gr_def(ctx, 0x402488, 0x3e020200);
- gr_def(ctx, 0x40248c, 0x00ffffff);
- switch (device->chipset) {
- case 0x40:
- gr_def(ctx, 0x402490, 0x60103f00);
- break;
- case 0x47:
- gr_def(ctx, 0x402490, 0x40103f00);
- break;
- case 0x41:
- case 0x42:
- case 0x49:
- case 0x4b:
- gr_def(ctx, 0x402490, 0x20103f00);
- break;
- default:
- gr_def(ctx, 0x402490, 0x0c103f00);
- break;
- }
- gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
- 0x00020000 : 0x00040000);
- cp_ctx(ctx, 0x402500, 31);
- gr_def(ctx, 0x402530, 0x00008100);
- if (device->chipset == 0x40)
- cp_ctx(ctx, 0x40257c, 6);
- cp_ctx(ctx, 0x402594, 16);
- cp_ctx(ctx, 0x402800, 17);
- gr_def(ctx, 0x402800, 0x00000001);
- switch (device->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- cp_ctx(ctx, 0x402864, 1);
- gr_def(ctx, 0x402864, 0x00001001);
- cp_ctx(ctx, 0x402870, 3);
- gr_def(ctx, 0x402878, 0x00000003);
- if (device->chipset != 0x47) { /* belong at end!! */
- cp_ctx(ctx, 0x402900, 1);
- cp_ctx(ctx, 0x402940, 1);
- cp_ctx(ctx, 0x402980, 1);
- cp_ctx(ctx, 0x4029c0, 1);
- cp_ctx(ctx, 0x402a00, 1);
- cp_ctx(ctx, 0x402a40, 1);
- cp_ctx(ctx, 0x402a80, 1);
- cp_ctx(ctx, 0x402ac0, 1);
- }
- break;
- case 0x40:
- cp_ctx(ctx, 0x402844, 1);
- gr_def(ctx, 0x402844, 0x00000001);
- cp_ctx(ctx, 0x402850, 1);
- break;
- default:
- cp_ctx(ctx, 0x402844, 1);
- gr_def(ctx, 0x402844, 0x00001001);
- cp_ctx(ctx, 0x402850, 2);
- gr_def(ctx, 0x402854, 0x00000003);
- break;
- }
-
- cp_ctx(ctx, 0x402c00, 4);
- gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
- 0x80800001 : 0x00888001);
- switch (device->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- cp_ctx(ctx, 0x402c20, 40);
- for (i = 0; i < 32; i++)
- gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff);
- cp_ctx(ctx, 0x4030b8, 13);
- gr_def(ctx, 0x4030dc, 0x00000005);
- gr_def(ctx, 0x4030e8, 0x0000ffff);
- break;
- default:
- cp_ctx(ctx, 0x402c10, 4);
- if (device->chipset == 0x40)
- cp_ctx(ctx, 0x402c20, 36);
- else
- if (device->chipset <= 0x42)
- cp_ctx(ctx, 0x402c20, 24);
- else
- if (device->chipset <= 0x4a)
- cp_ctx(ctx, 0x402c20, 16);
- else
- cp_ctx(ctx, 0x402c20, 8);
- cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
- gr_def(ctx, 0x402cd4, 0x00000005);
- if (device->chipset != 0x40)
- gr_def(ctx, 0x402ce0, 0x0000ffff);
- break;
- }
-
- cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
- cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
- cp_ctx(ctx, 0x403420, nv40_graph_vs_count(ctx->device));
- for (i = 0; i < nv40_graph_vs_count(ctx->device); i++)
- gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
-
- if (device->chipset != 0x40) {
- cp_ctx(ctx, 0x403600, 1);
- gr_def(ctx, 0x403600, 0x00000001);
- }
- cp_ctx(ctx, 0x403800, 1);
-
- cp_ctx(ctx, 0x403c18, 1);
- gr_def(ctx, 0x403c18, 0x00000001);
- switch (device->chipset) {
- case 0x46:
- case 0x47:
- case 0x49:
- case 0x4b:
- cp_ctx(ctx, 0x405018, 1);
- gr_def(ctx, 0x405018, 0x08e00001);
- cp_ctx(ctx, 0x405c24, 1);
- gr_def(ctx, 0x405c24, 0x000e3000);
- break;
- }
- if (device->chipset != 0x4e)
- cp_ctx(ctx, 0x405800, 11);
- cp_ctx(ctx, 0x407000, 1);
-}
-
-static void
-nv40_graph_construct_state3d_3(struct nouveau_grctx *ctx)
-{
- int len = nv44_graph_class(ctx->device) ? 0x0084 : 0x0684;
-
- cp_out (ctx, 0x300000);
- cp_lsr (ctx, len - 4);
- cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
- cp_lsr (ctx, len);
- cp_name(ctx, cp_swap_state3d_3_is_save);
- cp_out (ctx, 0x800001);
-
- ctx->ctxvals_pos += len;
-}
-
-static void
-nv40_graph_construct_shader(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- struct nouveau_gpuobj *obj = ctx->data;
- int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
- int offset, i;
-
- vs_nr = nv40_graph_vs_count(ctx->device);
- vs_nr_b0 = 363;
- vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
- if (device->chipset == 0x40) {
- b0_offset = 0x2200/4; /* 33a0 */
- b1_offset = 0x55a0/4; /* 1500 */
- vs_len = 0x6aa0/4;
- } else
- if (device->chipset == 0x41 || device->chipset == 0x42) {
- b0_offset = 0x2200/4; /* 2200 */
- b1_offset = 0x4400/4; /* 0b00 */
- vs_len = 0x4f00/4;
- } else {
- b0_offset = 0x1d40/4; /* 2200 */
- b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
- vs_len = nv44_graph_class(device) ? 0x4980/4 : 0x4a40/4;
- }
-
- cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
- cp_out(ctx, nv44_graph_class(device) ? 0x800029 : 0x800041);
-
- offset = ctx->ctxvals_pos;
- ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
-
- if (ctx->mode != NOUVEAU_GRCTX_VALS)
- return;
-
- offset += 0x0280/4;
- for (i = 0; i < 16; i++, offset += 2)
- nv_wo32(obj, offset * 4, 0x3f800000);
-
- for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
- for (i = 0; i < vs_nr_b0 * 6; i += 6)
- nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
- for (i = 0; i < vs_nr_b1 * 4; i += 4)
- nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
- }
-}
-
-static void
-nv40_grctx_generate(struct nouveau_grctx *ctx)
-{
- /* decide whether we're loading/unloading the context */
- cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
- cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
-
- cp_name(ctx, cp_check_load);
- cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
- cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
- cp_bra (ctx, ALWAYS, TRUE, cp_exit);
-
- /* setup for context load */
- cp_name(ctx, cp_setup_auto_load);
- cp_wait(ctx, STATUS, IDLE);
- cp_out (ctx, CP_NEXT_TO_SWAP);
- cp_name(ctx, cp_setup_load);
- cp_wait(ctx, STATUS, IDLE);
- cp_set (ctx, SWAP_DIRECTION, LOAD);
- cp_out (ctx, 0x00910880); /* ?? */
- cp_out (ctx, 0x00901ffe); /* ?? */
- cp_out (ctx, 0x01940000); /* ?? */
- cp_lsr (ctx, 0x20);
- cp_out (ctx, 0x0060000b); /* ?? */
- cp_wait(ctx, UNK57, CLEAR);
- cp_out (ctx, 0x0060000c); /* ?? */
- cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
-
- /* setup for context save */
- cp_name(ctx, cp_setup_save);
- cp_set (ctx, SWAP_DIRECTION, SAVE);
-
- /* general PGRAPH state */
- cp_name(ctx, cp_swap_state);
- cp_pos (ctx, 0x00020/4);
- nv40_graph_construct_general(ctx);
- cp_wait(ctx, STATUS, IDLE);
-
- /* 3D state, block 1 */
- cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
- nv40_graph_construct_state3d(ctx);
- cp_wait(ctx, STATUS, IDLE);
-
- /* 3D state, block 2 */
- nv40_graph_construct_state3d_2(ctx);
-
- /* Some other block of "random" state */
- nv40_graph_construct_state3d_3(ctx);
-
- /* Per-vertex shader state */
- cp_pos (ctx, ctx->ctxvals_pos);
- nv40_graph_construct_shader(ctx);
-
- /* pre-exit state updates */
- cp_name(ctx, cp_prepare_exit);
- cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
- cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
- cp_out (ctx, CP_NEXT_TO_CURRENT);
-
- cp_name(ctx, cp_exit);
- cp_set (ctx, USER_SAVE, NOT_PENDING);
- cp_set (ctx, USER_LOAD, NOT_PENDING);
- cp_out (ctx, CP_END);
-}
-
-void
-nv40_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
-{
- nv40_grctx_generate(&(struct nouveau_grctx) {
- .device = device,
- .mode = NOUVEAU_GRCTX_VALS,
- .data = mem,
- });
-}
-
-int
-nv40_grctx_init(struct nouveau_device *device, u32 *size)
-{
- u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i;
- struct nouveau_grctx ctx = {
- .device = device,
- .mode = NOUVEAU_GRCTX_PROG,
- .data = ctxprog,
- .ctxprog_max = 256,
- };
-
- if (!ctxprog)
- return -ENOMEM;
-
- nv40_grctx_generate(&ctx);
-
- nv_wr32(device, 0x400324, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(device, 0x400328, ctxprog[i]);
- *size = ctx.ctxvals_pos * 4;
-
- kfree(ctxprog);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
deleted file mode 100644
index 1d0e33fb5f61..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnv50.c
+++ /dev/null
@@ -1,3347 +0,0 @@
-/*
- * Copyright 2009 Marcin Kościelnicki
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <core/gpuobj.h>
-
-#define CP_FLAG_CLEAR 0
-#define CP_FLAG_SET 1
-#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0)
-#define CP_FLAG_SWAP_DIRECTION_LOAD 0
-#define CP_FLAG_SWAP_DIRECTION_SAVE 1
-#define CP_FLAG_UNK01 ((0 * 32) + 1)
-#define CP_FLAG_UNK01_CLEAR 0
-#define CP_FLAG_UNK01_SET 1
-#define CP_FLAG_UNK03 ((0 * 32) + 3)
-#define CP_FLAG_UNK03_CLEAR 0
-#define CP_FLAG_UNK03_SET 1
-#define CP_FLAG_USER_SAVE ((0 * 32) + 5)
-#define CP_FLAG_USER_SAVE_NOT_PENDING 0
-#define CP_FLAG_USER_SAVE_PENDING 1
-#define CP_FLAG_USER_LOAD ((0 * 32) + 6)
-#define CP_FLAG_USER_LOAD_NOT_PENDING 0
-#define CP_FLAG_USER_LOAD_PENDING 1
-#define CP_FLAG_UNK0B ((0 * 32) + 0xb)
-#define CP_FLAG_UNK0B_CLEAR 0
-#define CP_FLAG_UNK0B_SET 1
-#define CP_FLAG_XFER_SWITCH ((0 * 32) + 0xe)
-#define CP_FLAG_XFER_SWITCH_DISABLE 0
-#define CP_FLAG_XFER_SWITCH_ENABLE 1
-#define CP_FLAG_STATE ((0 * 32) + 0x1c)
-#define CP_FLAG_STATE_STOPPED 0
-#define CP_FLAG_STATE_RUNNING 1
-#define CP_FLAG_UNK1D ((0 * 32) + 0x1d)
-#define CP_FLAG_UNK1D_CLEAR 0
-#define CP_FLAG_UNK1D_SET 1
-#define CP_FLAG_UNK20 ((1 * 32) + 0)
-#define CP_FLAG_UNK20_CLEAR 0
-#define CP_FLAG_UNK20_SET 1
-#define CP_FLAG_STATUS ((2 * 32) + 0)
-#define CP_FLAG_STATUS_BUSY 0
-#define CP_FLAG_STATUS_IDLE 1
-#define CP_FLAG_AUTO_SAVE ((2 * 32) + 4)
-#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
-#define CP_FLAG_AUTO_SAVE_PENDING 1
-#define CP_FLAG_AUTO_LOAD ((2 * 32) + 5)
-#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
-#define CP_FLAG_AUTO_LOAD_PENDING 1
-#define CP_FLAG_NEWCTX ((2 * 32) + 10)
-#define CP_FLAG_NEWCTX_BUSY 0
-#define CP_FLAG_NEWCTX_DONE 1
-#define CP_FLAG_XFER ((2 * 32) + 11)
-#define CP_FLAG_XFER_IDLE 0
-#define CP_FLAG_XFER_BUSY 1
-#define CP_FLAG_ALWAYS ((2 * 32) + 13)
-#define CP_FLAG_ALWAYS_FALSE 0
-#define CP_FLAG_ALWAYS_TRUE 1
-#define CP_FLAG_INTR ((2 * 32) + 15)
-#define CP_FLAG_INTR_NOT_PENDING 0
-#define CP_FLAG_INTR_PENDING 1
-
-#define CP_CTX 0x00100000
-#define CP_CTX_COUNT 0x000f0000
-#define CP_CTX_COUNT_SHIFT 16
-#define CP_CTX_REG 0x00003fff
-#define CP_LOAD_SR 0x00200000
-#define CP_LOAD_SR_VALUE 0x000fffff
-#define CP_BRA 0x00400000
-#define CP_BRA_IP 0x0001ff00
-#define CP_BRA_IP_SHIFT 8
-#define CP_BRA_IF_CLEAR 0x00000080
-#define CP_BRA_FLAG 0x0000007f
-#define CP_WAIT 0x00500000
-#define CP_WAIT_SET 0x00000080
-#define CP_WAIT_FLAG 0x0000007f
-#define CP_SET 0x00700000
-#define CP_SET_1 0x00000080
-#define CP_SET_FLAG 0x0000007f
-#define CP_NEWCTX 0x00600004
-#define CP_NEXT_TO_SWAP 0x00600005
-#define CP_SET_CONTEXT_POINTER 0x00600006
-#define CP_SET_XFER_POINTER 0x00600007
-#define CP_ENABLE 0x00600009
-#define CP_END 0x0060000c
-#define CP_NEXT_TO_CURRENT 0x0060000d
-#define CP_DISABLE1 0x0090ffff
-#define CP_DISABLE2 0x0091ffff
-#define CP_XFER_1 0x008000ff
-#define CP_XFER_2 0x008800ff
-#define CP_SEEK_1 0x00c000ff
-#define CP_SEEK_2 0x00c800ff
-
-#include "nv50.h"
-#include "ctx.h"
-
-#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
-#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
-
-#include <subdev/fb.h>
-
-/*
- * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
- * the GPU itself that does context-switching, but it needs a special
- * microcode to do it. And it's the driver's task to supply this microcode,
- * further known as ctxprog, as well as the initial context values, known
- * as ctxvals.
- *
- * Without ctxprog, you cannot switch contexts. Not even in software, since
- * the majority of context [xfer strands] isn't accessible directly. You're
- * stuck with a single channel, and you also suffer all the problems resulting
- * from missing ctxvals, since you cannot load them.
- *
- * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to
- * run 2d operations, but trying to utilise 3d or CUDA will just lock you up,
- * since you don't have... some sort of needed setup.
- *
- * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since
- * it's too much hassle to handle no-ctxprog as a special case.
- */
-
-/*
- * How ctxprogs work.
- *
- * The ctxprog is written in its own kind of microcode, with very small and
- * crappy set of available commands. You upload it to a small [512 insns]
- * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to
- * switch channel. or when the driver explicitely requests it. Stuff visible
- * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands,
- * the per-channel context save area in VRAM [known as ctxvals or grctx],
- * 4 flags registers, a scratch register, two grctx pointers, plus many
- * random poorly-understood details.
- *
- * When ctxprog runs, it's supposed to check what operations are asked of it,
- * save old context if requested, optionally reset PGRAPH and switch to the
- * new channel, and load the new context. Context consists of three major
- * parts: subset of MMIO registers and two "xfer areas".
- */
-
-/* TODO:
- * - document unimplemented bits compared to nvidia
- * - NVAx: make a TP subroutine, use it.
- * - use 0x4008fc instead of 0x1540?
- */
-
-enum cp_label {
- cp_check_load = 1,
- cp_setup_auto_load,
- cp_setup_load,
- cp_setup_save,
- cp_swap_state,
- cp_prepare_exit,
- cp_exit,
-};
-
-static void nv50_graph_construct_mmio(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_xfer1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_xfer2(struct nouveau_grctx *ctx);
-
-/* Main function: construct the ctxprog skeleton, call the other functions. */
-
-static int
-nv50_grctx_generate(struct nouveau_grctx *ctx)
-{
- cp_set (ctx, STATE, RUNNING);
- cp_set (ctx, XFER_SWITCH, ENABLE);
- /* decide whether we're loading/unloading the context */
- cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
- cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
-
- cp_name(ctx, cp_check_load);
- cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
- cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
- cp_bra (ctx, ALWAYS, TRUE, cp_prepare_exit);
-
- /* setup for context load */
- cp_name(ctx, cp_setup_auto_load);
- cp_out (ctx, CP_DISABLE1);
- cp_out (ctx, CP_DISABLE2);
- cp_out (ctx, CP_ENABLE);
- cp_out (ctx, CP_NEXT_TO_SWAP);
- cp_set (ctx, UNK01, SET);
- cp_name(ctx, cp_setup_load);
- cp_out (ctx, CP_NEWCTX);
- cp_wait(ctx, NEWCTX, BUSY);
- cp_set (ctx, UNK1D, CLEAR);
- cp_set (ctx, SWAP_DIRECTION, LOAD);
- cp_bra (ctx, UNK0B, SET, cp_prepare_exit);
- cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
-
- /* setup for context save */
- cp_name(ctx, cp_setup_save);
- cp_set (ctx, UNK1D, SET);
- cp_wait(ctx, STATUS, BUSY);
- cp_wait(ctx, INTR, PENDING);
- cp_bra (ctx, STATUS, BUSY, cp_setup_save);
- cp_set (ctx, UNK01, SET);
- cp_set (ctx, SWAP_DIRECTION, SAVE);
-
- /* general PGRAPH state */
- cp_name(ctx, cp_swap_state);
- cp_set (ctx, UNK03, SET);
- cp_pos (ctx, 0x00004/4);
- cp_ctx (ctx, 0x400828, 1); /* needed. otherwise, flickering happens. */
- cp_pos (ctx, 0x00100/4);
- nv50_graph_construct_mmio(ctx);
- nv50_graph_construct_xfer1(ctx);
- nv50_graph_construct_xfer2(ctx);
-
- cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
-
- cp_set (ctx, UNK20, SET);
- cp_set (ctx, SWAP_DIRECTION, SAVE); /* no idea why this is needed, but fixes at least one lockup. */
- cp_lsr (ctx, ctx->ctxvals_base);
- cp_out (ctx, CP_SET_XFER_POINTER);
- cp_lsr (ctx, 4);
- cp_out (ctx, CP_SEEK_1);
- cp_out (ctx, CP_XFER_1);
- cp_wait(ctx, XFER, BUSY);
-
- /* pre-exit state updates */
- cp_name(ctx, cp_prepare_exit);
- cp_set (ctx, UNK01, CLEAR);
- cp_set (ctx, UNK03, CLEAR);
- cp_set (ctx, UNK1D, CLEAR);
-
- cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
- cp_out (ctx, CP_NEXT_TO_CURRENT);
-
- cp_name(ctx, cp_exit);
- cp_set (ctx, USER_SAVE, NOT_PENDING);
- cp_set (ctx, USER_LOAD, NOT_PENDING);
- cp_set (ctx, XFER_SWITCH, DISABLE);
- cp_set (ctx, STATE, STOPPED);
- cp_out (ctx, CP_END);
- ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */
-
- return 0;
-}
-
-void
-nv50_grctx_fill(struct nouveau_device *device, struct nouveau_gpuobj *mem)
-{
- nv50_grctx_generate(&(struct nouveau_grctx) {
- .device = device,
- .mode = NOUVEAU_GRCTX_VALS,
- .data = mem,
- });
-}
-
-int
-nv50_grctx_init(struct nouveau_device *device, u32 *size)
-{
- u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i;
- struct nouveau_grctx ctx = {
- .device = device,
- .mode = NOUVEAU_GRCTX_PROG,
- .data = ctxprog,
- .ctxprog_max = 512,
- };
-
- if (!ctxprog)
- return -ENOMEM;
- nv50_grctx_generate(&ctx);
-
- nv_wr32(device, 0x400324, 0);
- for (i = 0; i < ctx.ctxprog_len; i++)
- nv_wr32(device, 0x400328, ctxprog[i]);
- *size = ctx.ctxvals_pos * 4;
- kfree(ctxprog);
- return 0;
-}
-
-/*
- * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
- * registers to save/restore and the default values for them.
- */
-
-static void
-nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx);
-
-static void
-nv50_graph_construct_mmio(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i, j;
- int offset, base;
- u32 units = nv_rd32 (ctx->device, 0x1540);
-
- /* 0800: DISPATCH */
- cp_ctx(ctx, 0x400808, 7);
- gr_def(ctx, 0x400814, 0x00000030);
- cp_ctx(ctx, 0x400834, 0x32);
- if (device->chipset == 0x50) {
- gr_def(ctx, 0x400834, 0xff400040);
- gr_def(ctx, 0x400838, 0xfff00080);
- gr_def(ctx, 0x40083c, 0xfff70090);
- gr_def(ctx, 0x400840, 0xffe806a8);
- }
- gr_def(ctx, 0x400844, 0x00000002);
- if (IS_NVA3F(device->chipset))
- gr_def(ctx, 0x400894, 0x00001000);
- gr_def(ctx, 0x4008e8, 0x00000003);
- gr_def(ctx, 0x4008ec, 0x00001000);
- if (device->chipset == 0x50)
- cp_ctx(ctx, 0x400908, 0xb);
- else if (device->chipset < 0xa0)
- cp_ctx(ctx, 0x400908, 0xc);
- else
- cp_ctx(ctx, 0x400908, 0xe);
-
- if (device->chipset >= 0xa0)
- cp_ctx(ctx, 0x400b00, 0x1);
- if (IS_NVA3F(device->chipset)) {
- cp_ctx(ctx, 0x400b10, 0x1);
- gr_def(ctx, 0x400b10, 0x0001629d);
- cp_ctx(ctx, 0x400b20, 0x1);
- gr_def(ctx, 0x400b20, 0x0001629d);
- }
-
- nv50_graph_construct_mmio_ddata(ctx);
-
- /* 0C00: VFETCH */
- cp_ctx(ctx, 0x400c08, 0x2);
- gr_def(ctx, 0x400c08, 0x0000fe0c);
-
- /* 1000 */
- if (device->chipset < 0xa0) {
- cp_ctx(ctx, 0x401008, 0x4);
- gr_def(ctx, 0x401014, 0x00001000);
- } else if (!IS_NVA3F(device->chipset)) {
- cp_ctx(ctx, 0x401008, 0x5);
- gr_def(ctx, 0x401018, 0x00001000);
- } else {
- cp_ctx(ctx, 0x401008, 0x5);
- gr_def(ctx, 0x401018, 0x00004000);
- }
-
- /* 1400 */
- cp_ctx(ctx, 0x401400, 0x8);
- cp_ctx(ctx, 0x401424, 0x3);
- if (device->chipset == 0x50)
- gr_def(ctx, 0x40142c, 0x0001fd87);
- else
- gr_def(ctx, 0x40142c, 0x00000187);
- cp_ctx(ctx, 0x401540, 0x5);
- gr_def(ctx, 0x401550, 0x00001018);
-
- /* 1800: STREAMOUT */
- cp_ctx(ctx, 0x401814, 0x1);
- gr_def(ctx, 0x401814, 0x000000ff);
- if (device->chipset == 0x50) {
- cp_ctx(ctx, 0x40181c, 0xe);
- gr_def(ctx, 0x401850, 0x00000004);
- } else if (device->chipset < 0xa0) {
- cp_ctx(ctx, 0x40181c, 0xf);
- gr_def(ctx, 0x401854, 0x00000004);
- } else {
- cp_ctx(ctx, 0x40181c, 0x13);
- gr_def(ctx, 0x401864, 0x00000004);
- }
-
- /* 1C00 */
- cp_ctx(ctx, 0x401c00, 0x1);
- switch (device->chipset) {
- case 0x50:
- gr_def(ctx, 0x401c00, 0x0001005f);
- break;
- case 0x84:
- case 0x86:
- case 0x94:
- gr_def(ctx, 0x401c00, 0x044d00df);
- break;
- case 0x92:
- case 0x96:
- case 0x98:
- case 0xa0:
- case 0xaa:
- case 0xac:
- gr_def(ctx, 0x401c00, 0x042500df);
- break;
- case 0xa3:
- case 0xa5:
- case 0xa8:
- case 0xaf:
- gr_def(ctx, 0x401c00, 0x142500df);
- break;
- }
-
- /* 2000 */
-
- /* 2400 */
- cp_ctx(ctx, 0x402400, 0x1);
- if (device->chipset == 0x50)
- cp_ctx(ctx, 0x402408, 0x1);
- else
- cp_ctx(ctx, 0x402408, 0x2);
- gr_def(ctx, 0x402408, 0x00000600);
-
- /* 2800: CSCHED */
- cp_ctx(ctx, 0x402800, 0x1);
- if (device->chipset == 0x50)
- gr_def(ctx, 0x402800, 0x00000006);
-
- /* 2C00: ZCULL */
- cp_ctx(ctx, 0x402c08, 0x6);
- if (device->chipset != 0x50)
- gr_def(ctx, 0x402c14, 0x01000000);
- gr_def(ctx, 0x402c18, 0x000000ff);
- if (device->chipset == 0x50)
- cp_ctx(ctx, 0x402ca0, 0x1);
- else
- cp_ctx(ctx, 0x402ca0, 0x2);
- if (device->chipset < 0xa0)
- gr_def(ctx, 0x402ca0, 0x00000400);
- else if (!IS_NVA3F(device->chipset))
- gr_def(ctx, 0x402ca0, 0x00000800);
- else
- gr_def(ctx, 0x402ca0, 0x00000400);
- cp_ctx(ctx, 0x402cac, 0x4);
-
- /* 3000: ENG2D */
- cp_ctx(ctx, 0x403004, 0x1);
- gr_def(ctx, 0x403004, 0x00000001);
-
- /* 3400 */
- if (device->chipset >= 0xa0) {
- cp_ctx(ctx, 0x403404, 0x1);
- gr_def(ctx, 0x403404, 0x00000001);
- }
-
- /* 5000: CCACHE */
- cp_ctx(ctx, 0x405000, 0x1);
- switch (device->chipset) {
- case 0x50:
- gr_def(ctx, 0x405000, 0x00300080);
- break;
- case 0x84:
- case 0xa0:
- case 0xa3:
- case 0xa5:
- case 0xa8:
- case 0xaa:
- case 0xac:
- case 0xaf:
- gr_def(ctx, 0x405000, 0x000e0080);
- break;
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0x98:
- gr_def(ctx, 0x405000, 0x00000080);
- break;
- }
- cp_ctx(ctx, 0x405014, 0x1);
- gr_def(ctx, 0x405014, 0x00000004);
- cp_ctx(ctx, 0x40501c, 0x1);
- cp_ctx(ctx, 0x405024, 0x1);
- cp_ctx(ctx, 0x40502c, 0x1);
-
- /* 6000? */
- if (device->chipset == 0x50)
- cp_ctx(ctx, 0x4063e0, 0x1);
-
- /* 6800: M2MF */
- if (device->chipset < 0x90) {
- cp_ctx(ctx, 0x406814, 0x2b);
- gr_def(ctx, 0x406818, 0x00000f80);
- gr_def(ctx, 0x406860, 0x007f0080);
- gr_def(ctx, 0x40689c, 0x007f0080);
- } else {
- cp_ctx(ctx, 0x406814, 0x4);
- if (device->chipset == 0x98)
- gr_def(ctx, 0x406818, 0x00000f80);
- else
- gr_def(ctx, 0x406818, 0x00001f80);
- if (IS_NVA3F(device->chipset))
- gr_def(ctx, 0x40681c, 0x00000030);
- cp_ctx(ctx, 0x406830, 0x3);
- }
-
- /* 7000: per-ROP group state */
- for (i = 0; i < 8; i++) {
- if (units & (1<<(i+16))) {
- cp_ctx(ctx, 0x407000 + (i<<8), 3);
- if (device->chipset == 0x50)
- gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
- else if (device->chipset != 0xa5)
- gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
- else
- gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
- gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
-
- if (device->chipset == 0x50) {
- cp_ctx(ctx, 0x407010 + (i<<8), 1);
- } else if (device->chipset < 0xa0) {
- cp_ctx(ctx, 0x407010 + (i<<8), 2);
- gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
- gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
- } else {
- cp_ctx(ctx, 0x407010 + (i<<8), 3);
- gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
- if (device->chipset != 0xa5)
- gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
- else
- gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
- }
-
- cp_ctx(ctx, 0x407080 + (i<<8), 4);
- if (device->chipset != 0xa5)
- gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
- else
- gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
- if (device->chipset == 0x50)
- gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
- else
- gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
- gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
-
- if (device->chipset < 0xa0)
- cp_ctx(ctx, 0x407094 + (i<<8), 1);
- else if (!IS_NVA3F(device->chipset))
- cp_ctx(ctx, 0x407094 + (i<<8), 3);
- else {
- cp_ctx(ctx, 0x407094 + (i<<8), 4);
- gr_def(ctx, 0x4070a0 + (i<<8), 1);
- }
- }
- }
-
- cp_ctx(ctx, 0x407c00, 0x3);
- if (device->chipset < 0x90)
- gr_def(ctx, 0x407c00, 0x00010040);
- else if (device->chipset < 0xa0)
- gr_def(ctx, 0x407c00, 0x00390040);
- else
- gr_def(ctx, 0x407c00, 0x003d0040);
- gr_def(ctx, 0x407c08, 0x00000022);
- if (device->chipset >= 0xa0) {
- cp_ctx(ctx, 0x407c10, 0x3);
- cp_ctx(ctx, 0x407c20, 0x1);
- cp_ctx(ctx, 0x407c2c, 0x1);
- }
-
- if (device->chipset < 0xa0) {
- cp_ctx(ctx, 0x407d00, 0x9);
- } else {
- cp_ctx(ctx, 0x407d00, 0x15);
- }
- if (device->chipset == 0x98)
- gr_def(ctx, 0x407d08, 0x00380040);
- else {
- if (device->chipset < 0x90)
- gr_def(ctx, 0x407d08, 0x00010040);
- else if (device->chipset < 0xa0)
- gr_def(ctx, 0x407d08, 0x00390040);
- else {
- if (nouveau_fb(device)->ram->type != NV_MEM_TYPE_GDDR5)
- gr_def(ctx, 0x407d08, 0x003d0040);
- else
- gr_def(ctx, 0x407d08, 0x003c0040);
- }
- gr_def(ctx, 0x407d0c, 0x00000022);
- }
-
- /* 8000+: per-TP state */
- for (i = 0; i < 10; i++) {
- if (units & (1<<i)) {
- if (device->chipset < 0xa0)
- base = 0x408000 + (i<<12);
- else
- base = 0x408000 + (i<<11);
- if (device->chipset < 0xa0)
- offset = base + 0xc00;
- else
- offset = base + 0x80;
- cp_ctx(ctx, offset + 0x00, 1);
- gr_def(ctx, offset + 0x00, 0x0000ff0a);
- cp_ctx(ctx, offset + 0x08, 1);
-
- /* per-MP state */
- for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) {
- if (!(units & (1 << (j+24)))) continue;
- if (device->chipset < 0xa0)
- offset = base + 0x200 + (j<<7);
- else
- offset = base + 0x100 + (j<<7);
- cp_ctx(ctx, offset, 0x20);
- gr_def(ctx, offset + 0x00, 0x01800000);
- gr_def(ctx, offset + 0x04, 0x00160000);
- gr_def(ctx, offset + 0x08, 0x01800000);
- gr_def(ctx, offset + 0x18, 0x0003ffff);
- switch (device->chipset) {
- case 0x50:
- gr_def(ctx, offset + 0x1c, 0x00080000);
- break;
- case 0x84:
- gr_def(ctx, offset + 0x1c, 0x00880000);
- break;
- case 0x86:
- gr_def(ctx, offset + 0x1c, 0x018c0000);
- break;
- case 0x92:
- case 0x96:
- case 0x98:
- gr_def(ctx, offset + 0x1c, 0x118c0000);
- break;
- case 0x94:
- gr_def(ctx, offset + 0x1c, 0x10880000);
- break;
- case 0xa0:
- case 0xa5:
- gr_def(ctx, offset + 0x1c, 0x310c0000);
- break;
- case 0xa3:
- case 0xa8:
- case 0xaa:
- case 0xac:
- case 0xaf:
- gr_def(ctx, offset + 0x1c, 0x300c0000);
- break;
- }
- gr_def(ctx, offset + 0x40, 0x00010401);
- if (device->chipset == 0x50)
- gr_def(ctx, offset + 0x48, 0x00000040);
- else
- gr_def(ctx, offset + 0x48, 0x00000078);
- gr_def(ctx, offset + 0x50, 0x000000bf);
- gr_def(ctx, offset + 0x58, 0x00001210);
- if (device->chipset == 0x50)
- gr_def(ctx, offset + 0x5c, 0x00000080);
- else
- gr_def(ctx, offset + 0x5c, 0x08000080);
- if (device->chipset >= 0xa0)
- gr_def(ctx, offset + 0x68, 0x0000003e);
- }
-
- if (device->chipset < 0xa0)
- cp_ctx(ctx, base + 0x300, 0x4);
- else
- cp_ctx(ctx, base + 0x300, 0x5);
- if (device->chipset == 0x50)
- gr_def(ctx, base + 0x304, 0x00007070);
- else if (device->chipset < 0xa0)
- gr_def(ctx, base + 0x304, 0x00027070);
- else if (!IS_NVA3F(device->chipset))
- gr_def(ctx, base + 0x304, 0x01127070);
- else
- gr_def(ctx, base + 0x304, 0x05127070);
-
- if (device->chipset < 0xa0)
- cp_ctx(ctx, base + 0x318, 1);
- else
- cp_ctx(ctx, base + 0x320, 1);
- if (device->chipset == 0x50)
- gr_def(ctx, base + 0x318, 0x0003ffff);
- else if (device->chipset < 0xa0)
- gr_def(ctx, base + 0x318, 0x03ffffff);
- else
- gr_def(ctx, base + 0x320, 0x07ffffff);
-
- if (device->chipset < 0xa0)
- cp_ctx(ctx, base + 0x324, 5);
- else
- cp_ctx(ctx, base + 0x328, 4);
-
- if (device->chipset < 0xa0) {
- cp_ctx(ctx, base + 0x340, 9);
- offset = base + 0x340;
- } else if (!IS_NVA3F(device->chipset)) {
- cp_ctx(ctx, base + 0x33c, 0xb);
- offset = base + 0x344;
- } else {
- cp_ctx(ctx, base + 0x33c, 0xd);
- offset = base + 0x344;
- }
- gr_def(ctx, offset + 0x0, 0x00120407);
- gr_def(ctx, offset + 0x4, 0x05091507);
- if (device->chipset == 0x84)
- gr_def(ctx, offset + 0x8, 0x05100202);
- else
- gr_def(ctx, offset + 0x8, 0x05010202);
- gr_def(ctx, offset + 0xc, 0x00030201);
- if (device->chipset == 0xa3)
- cp_ctx(ctx, base + 0x36c, 1);
-
- cp_ctx(ctx, base + 0x400, 2);
- gr_def(ctx, base + 0x404, 0x00000040);
- cp_ctx(ctx, base + 0x40c, 2);
- gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
- gr_def(ctx, base + 0x410, 0x00141210);
-
- if (device->chipset < 0xa0)
- offset = base + 0x800;
- else
- offset = base + 0x500;
- cp_ctx(ctx, offset, 6);
- gr_def(ctx, offset + 0x0, 0x000001f0);
- gr_def(ctx, offset + 0x4, 0x00000001);
- gr_def(ctx, offset + 0x8, 0x00000003);
- if (device->chipset == 0x50 || IS_NVAAF(device->chipset))
- gr_def(ctx, offset + 0xc, 0x00008000);
- gr_def(ctx, offset + 0x14, 0x00039e00);
- cp_ctx(ctx, offset + 0x1c, 2);
- if (device->chipset == 0x50)
- gr_def(ctx, offset + 0x1c, 0x00000040);
- else
- gr_def(ctx, offset + 0x1c, 0x00000100);
- gr_def(ctx, offset + 0x20, 0x00003800);
-
- if (device->chipset >= 0xa0) {
- cp_ctx(ctx, base + 0x54c, 2);
- if (!IS_NVA3F(device->chipset))
- gr_def(ctx, base + 0x54c, 0x003fe006);
- else
- gr_def(ctx, base + 0x54c, 0x003fe007);
- gr_def(ctx, base + 0x550, 0x003fe000);
- }
-
- if (device->chipset < 0xa0)
- offset = base + 0xa00;
- else
- offset = base + 0x680;
- cp_ctx(ctx, offset, 1);
- gr_def(ctx, offset, 0x00404040);
-
- if (device->chipset < 0xa0)
- offset = base + 0xe00;
- else
- offset = base + 0x700;
- cp_ctx(ctx, offset, 2);
- if (device->chipset < 0xa0)
- gr_def(ctx, offset, 0x0077f005);
- else if (device->chipset == 0xa5)
- gr_def(ctx, offset, 0x6cf7f007);
- else if (device->chipset == 0xa8)
- gr_def(ctx, offset, 0x6cfff007);
- else if (device->chipset == 0xac)
- gr_def(ctx, offset, 0x0cfff007);
- else
- gr_def(ctx, offset, 0x0cf7f007);
- if (device->chipset == 0x50)
- gr_def(ctx, offset + 0x4, 0x00007fff);
- else if (device->chipset < 0xa0)
- gr_def(ctx, offset + 0x4, 0x003f7fff);
- else
- gr_def(ctx, offset + 0x4, 0x02bf7fff);
- cp_ctx(ctx, offset + 0x2c, 1);
- if (device->chipset == 0x50) {
- cp_ctx(ctx, offset + 0x50, 9);
- gr_def(ctx, offset + 0x54, 0x000003ff);
- gr_def(ctx, offset + 0x58, 0x00000003);
- gr_def(ctx, offset + 0x5c, 0x00000003);
- gr_def(ctx, offset + 0x60, 0x000001ff);
- gr_def(ctx, offset + 0x64, 0x0000001f);
- gr_def(ctx, offset + 0x68, 0x0000000f);
- gr_def(ctx, offset + 0x6c, 0x0000000f);
- } else if (device->chipset < 0xa0) {
- cp_ctx(ctx, offset + 0x50, 1);
- cp_ctx(ctx, offset + 0x70, 1);
- } else {
- cp_ctx(ctx, offset + 0x50, 1);
- cp_ctx(ctx, offset + 0x60, 5);
- }
- }
- }
-}
-
-static void
-dd_emit(struct nouveau_grctx *ctx, int num, u32 val) {
- int i;
- if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
- for (i = 0; i < num; i++)
- nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
- ctx->ctxvals_pos += num;
-}
-
-static void
-nv50_graph_construct_mmio_ddata(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int base, num;
- base = ctx->ctxvals_pos;
-
- /* tesla state */
- dd_emit(ctx, 1, 0); /* 00000001 UNK0F90 */
- dd_emit(ctx, 1, 0); /* 00000001 UNK135C */
-
- /* SRC_TIC state */
- dd_emit(ctx, 1, 0); /* 00000007 SRC_TILE_MODE_Z */
- dd_emit(ctx, 1, 2); /* 00000007 SRC_TILE_MODE_Y */
- dd_emit(ctx, 1, 1); /* 00000001 SRC_LINEAR #1 */
- dd_emit(ctx, 1, 0); /* 000000ff SRC_ADDRESS_HIGH */
- dd_emit(ctx, 1, 0); /* 00000001 SRC_SRGB */
- if (device->chipset >= 0x94)
- dd_emit(ctx, 1, 0); /* 00000003 eng2d UNK0258 */
- dd_emit(ctx, 1, 1); /* 00000fff SRC_DEPTH */
- dd_emit(ctx, 1, 0x100); /* 0000ffff SRC_HEIGHT */
-
- /* turing state */
- dd_emit(ctx, 1, 0); /* 0000000f TEXTURES_LOG2 */
- dd_emit(ctx, 1, 0); /* 0000000f SAMPLERS_LOG2 */
- dd_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */
- dd_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */
- dd_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */
- dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */
- dd_emit(ctx, 1, 1); /* 0000ffff BLOCK_ALLOC_THREADS */
- dd_emit(ctx, 1, 1); /* 00000001 LANES32 */
- dd_emit(ctx, 1, 0); /* 000000ff UNK370 */
- dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_UNK */
- dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_COUNT */
- dd_emit(ctx, 1, 1); /* 000000ff UNK384 bits 8-15 */
- dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
- dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
- dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */
- dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_X */
- dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_XMY */
- dd_emit(ctx, 1, 0); /* 00000001 BLOCKDIM_XMY_OVERFLOW */
- dd_emit(ctx, 1, 1); /* 0003ffff BLOCKDIM_XMYMZ */
- dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_Y */
- dd_emit(ctx, 1, 1); /* 0000007f BLOCKDIM_Z */
- dd_emit(ctx, 1, 4); /* 000000ff CP_REG_ALLOC_TEMP */
- dd_emit(ctx, 1, 1); /* 00000001 BLOCKDIM_DIRTY */
- if (IS_NVA3F(device->chipset))
- dd_emit(ctx, 1, 0); /* 00000003 UNK03E8 */
- dd_emit(ctx, 1, 1); /* 0000007f BLOCK_ALLOC_HALFWARPS */
- dd_emit(ctx, 1, 1); /* 00000007 LOCAL_WARPS_NO_CLAMP */
- dd_emit(ctx, 1, 7); /* 00000007 LOCAL_WARPS_LOG_ALLOC */
- dd_emit(ctx, 1, 1); /* 00000007 STACK_WARPS_NO_CLAMP */
- dd_emit(ctx, 1, 7); /* 00000007 STACK_WARPS_LOG_ALLOC */
- dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
- dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
- dd_emit(ctx, 1, 1); /* 000007ff BLOCK_ALLOC_THREADS */
-
- /* compat 2d state */
- if (device->chipset == 0x50) {
- dd_emit(ctx, 4, 0); /* 0000ffff clip X, Y, W, H */
-
- dd_emit(ctx, 1, 1); /* ffffffff chroma COLOR_FORMAT */
-
- dd_emit(ctx, 1, 1); /* ffffffff pattern COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff pattern SHAPE */
- dd_emit(ctx, 1, 1); /* ffffffff pattern PATTERN_SELECT */
-
- dd_emit(ctx, 1, 0xa); /* ffffffff surf2d SRC_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff surf2d DMA_SRC */
- dd_emit(ctx, 1, 0); /* 000000ff surf2d SRC_ADDRESS_HIGH */
- dd_emit(ctx, 1, 0); /* ffffffff surf2d SRC_ADDRESS_LOW */
- dd_emit(ctx, 1, 0x40); /* 0000ffff surf2d SRC_PITCH */
- dd_emit(ctx, 1, 0); /* 0000000f surf2d SRC_TILE_MODE_Z */
- dd_emit(ctx, 1, 2); /* 0000000f surf2d SRC_TILE_MODE_Y */
- dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_HEIGHT */
- dd_emit(ctx, 1, 1); /* 00000001 surf2d SRC_LINEAR */
- dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_WIDTH */
-
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_X */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_Y */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_X */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_Y */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_X */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_Y */
- dd_emit(ctx, 1, 1); /* ffffffff gdirect COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff gdirect OPERATION */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_X */
- dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_Y */
-
- dd_emit(ctx, 1, 0); /* 0000ffff blit SRC_Y */
- dd_emit(ctx, 1, 0); /* ffffffff blit OPERATION */
-
- dd_emit(ctx, 1, 0); /* ffffffff ifc OPERATION */
-
- dd_emit(ctx, 1, 0); /* ffffffff iifc INDEX_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff iifc LUT_OFFSET */
- dd_emit(ctx, 1, 4); /* ffffffff iifc COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff iifc OPERATION */
- }
-
- /* m2mf state */
- dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_COUNT */
- dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_LENGTH_IN */
- dd_emit(ctx, 2, 0); /* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
- dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_OUT */
- dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_OUT */
- dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_OUT_Z */
- dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_OUT */
- dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
- dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_OUT */
- dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_IN */
- dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_IN */
- dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_IN_Z */
- dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_IN */
- dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_IN_X, Y */
- dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_IN */
-
- /* more compat 2d state */
- if (device->chipset == 0x50) {
- dd_emit(ctx, 1, 1); /* ffffffff line COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff line OPERATION */
-
- dd_emit(ctx, 1, 1); /* ffffffff triangle COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff triangle OPERATION */
-
- dd_emit(ctx, 1, 0); /* 0000000f sifm TILE_MODE_Z */
- dd_emit(ctx, 1, 2); /* 0000000f sifm TILE_MODE_Y */
- dd_emit(ctx, 1, 0); /* 000000ff sifm FORMAT_FILTER */
- dd_emit(ctx, 1, 1); /* 000000ff sifm FORMAT_ORIGIN */
- dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_PITCH */
- dd_emit(ctx, 1, 1); /* 00000001 sifm SRC_LINEAR */
- dd_emit(ctx, 1, 0); /* 000000ff sifm SRC_OFFSET_HIGH */
- dd_emit(ctx, 1, 0); /* ffffffff sifm SRC_OFFSET */
- dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_HEIGHT */
- dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_WIDTH */
- dd_emit(ctx, 1, 3); /* ffffffff sifm COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff sifm OPERATION */
-
- dd_emit(ctx, 1, 0); /* ffffffff sifc OPERATION */
- }
-
- /* tesla state */
- dd_emit(ctx, 1, 0); /* 0000000f GP_TEXTURES_LOG2 */
- dd_emit(ctx, 1, 0); /* 0000000f GP_SAMPLERS_LOG2 */
- dd_emit(ctx, 1, 0); /* 000000ff */
- dd_emit(ctx, 1, 0); /* ffffffff */
- dd_emit(ctx, 1, 4); /* 000000ff UNK12B0_0 */
- dd_emit(ctx, 1, 0x70); /* 000000ff UNK12B0_1 */
- dd_emit(ctx, 1, 0x80); /* 000000ff UNK12B0_3 */
- dd_emit(ctx, 1, 0); /* 000000ff UNK12B0_2 */
- dd_emit(ctx, 1, 0); /* 0000000f FP_TEXTURES_LOG2 */
- dd_emit(ctx, 1, 0); /* 0000000f FP_SAMPLERS_LOG2 */
- if (IS_NVA3F(device->chipset)) {
- dd_emit(ctx, 1, 0); /* ffffffff */
- dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
- } else {
- dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
- }
- dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */
- if (device->chipset != 0x50)
- dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */
- dd_emit(ctx, 1, 8); /* 000000ff SEMANTIC_COLOR.COLR_NR */
- dd_emit(ctx, 1, 0x14); /* 000000ff SEMANTIC_COLOR.FFC0_ID */
- if (device->chipset == 0x50) {
- dd_emit(ctx, 1, 0); /* 000000ff SEMANTIC_LAYER */
- dd_emit(ctx, 1, 0); /* 00000001 */
- } else {
- dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_PTSZ.ENABLE */
- dd_emit(ctx, 1, 0x29); /* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
- dd_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM */
- dd_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
- dd_emit(ctx, 1, 8); /* 0000000f SMENATIC_CLIP.CLIP_HIGH */
- dd_emit(ctx, 1, 4); /* 000000ff SEMANTIC_CLIP.CLIP_LO */
- dd_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */
- dd_emit(ctx, 1, 0); /* 00000001 UNK1900 */
- }
- dd_emit(ctx, 1, 0); /* 00000007 RT_CONTROL_MAP0 */
- dd_emit(ctx, 1, 1); /* 00000007 RT_CONTROL_MAP1 */
- dd_emit(ctx, 1, 2); /* 00000007 RT_CONTROL_MAP2 */
- dd_emit(ctx, 1, 3); /* 00000007 RT_CONTROL_MAP3 */
- dd_emit(ctx, 1, 4); /* 00000007 RT_CONTROL_MAP4 */
- dd_emit(ctx, 1, 5); /* 00000007 RT_CONTROL_MAP5 */
- dd_emit(ctx, 1, 6); /* 00000007 RT_CONTROL_MAP6 */
- dd_emit(ctx, 1, 7); /* 00000007 RT_CONTROL_MAP7 */
- dd_emit(ctx, 1, 1); /* 0000000f RT_CONTROL_COUNT */
- dd_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_UNK */
- dd_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */
- dd_emit(ctx, 1, 0xcf); /* 000000ff RT_FORMAT */
- dd_emit(ctx, 7, 0); /* 000000ff RT_FORMAT */
- if (device->chipset != 0x50)
- dd_emit(ctx, 3, 0); /* 1, 1, 1 */
- else
- dd_emit(ctx, 2, 0); /* 1, 1 */
- dd_emit(ctx, 1, 0); /* ffffffff GP_ENABLE */
- dd_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
- dd_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
- dd_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- if (IS_NVA3F(device->chipset)) {
- dd_emit(ctx, 1, 3); /* 00000003 */
- dd_emit(ctx, 1, 0); /* 00000001 UNK1418. Alone. */
- }
- if (device->chipset != 0x50)
- dd_emit(ctx, 1, 3); /* 00000003 UNK15AC */
- dd_emit(ctx, 1, 1); /* ffffffff RASTERIZE_ENABLE */
- dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.EXPORTS_Z */
- if (device->chipset != 0x50)
- dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
- dd_emit(ctx, 1, 0x12); /* 000000ff FP_INTERPOLANT_CTRL.COUNT */
- dd_emit(ctx, 1, 0x10); /* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
- dd_emit(ctx, 1, 0xc); /* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
- dd_emit(ctx, 1, 1); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
- dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
- dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
- dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
- dd_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */
- dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */
- dd_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
- if (device->chipset >= 0xa0)
- dd_emit(ctx, 1, 0); /* ffffffff */
- dd_emit(ctx, 1, 0); /* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
- dd_emit(ctx, 1, 0); /* ffffffff STRMOUT_ENABLE */
- dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
- dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
- dd_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE*/
- if (device->chipset != 0x50)
- dd_emit(ctx, 8, 0); /* 00000001 */
- if (device->chipset >= 0xa0) {
- dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.COMP */
- dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.SIZE */
- dd_emit(ctx, 1, 2); /* 00000007 VTX_ATTR_DEFINE.TYPE */
- dd_emit(ctx, 1, 0); /* 000000ff VTX_ATTR_DEFINE.ATTR */
- }
- dd_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- dd_emit(ctx, 1, 0x14); /* 0000001f ZETA_FORMAT */
- dd_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- dd_emit(ctx, 1, 0); /* 0000000f VP_TEXTURES_LOG2 */
- dd_emit(ctx, 1, 0); /* 0000000f VP_SAMPLERS_LOG2 */
- if (IS_NVA3F(device->chipset))
- dd_emit(ctx, 1, 0); /* 00000001 */
- dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_BACK */
- if (device->chipset >= 0xa0)
- dd_emit(ctx, 1, 0); /* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
- dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */
- if (device->chipset >= 0xa0)
- dd_emit(ctx, 1, 0); /* 00000003 */
- dd_emit(ctx, 1, 0); /* 00000001 CULL_FACE_ENABLE */
- dd_emit(ctx, 1, 1); /* 00000003 CULL_FACE */
- dd_emit(ctx, 1, 0); /* 00000001 FRONT_FACE */
- dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_FRONT */
- dd_emit(ctx, 1, 0x1000); /* 00007fff UNK141C */
- if (device->chipset != 0x50) {
- dd_emit(ctx, 1, 0xe00); /* 7fff */
- dd_emit(ctx, 1, 0x1000); /* 7fff */
- dd_emit(ctx, 1, 0x1e00); /* 7fff */
- }
- dd_emit(ctx, 1, 0); /* 00000001 BEGIN_END_ACTIVE */
- dd_emit(ctx, 1, 1); /* 00000001 POLYGON_MODE_??? */
- dd_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
- dd_emit(ctx, 1, 1); /* 000000ff FP_REG_ALLOC_TEMP... without /4? */
- dd_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
- dd_emit(ctx, 1, 1); /* 00000001 */
- dd_emit(ctx, 1, 0); /* 00000001 */
- dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
- dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
- dd_emit(ctx, 1, 0x200); /* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
- if (IS_NVA3F(device->chipset))
- dd_emit(ctx, 1, 0x200);
- dd_emit(ctx, 1, 0); /* 00000001 */
- if (device->chipset < 0xa0) {
- dd_emit(ctx, 1, 1); /* 00000001 */
- dd_emit(ctx, 1, 0x70); /* 000000ff */
- dd_emit(ctx, 1, 0x80); /* 000000ff */
- dd_emit(ctx, 1, 0); /* 000000ff */
- dd_emit(ctx, 1, 0); /* 00000001 */
- dd_emit(ctx, 1, 1); /* 00000001 */
- dd_emit(ctx, 1, 0x70); /* 000000ff */
- dd_emit(ctx, 1, 0x80); /* 000000ff */
- dd_emit(ctx, 1, 0); /* 000000ff */
- } else {
- dd_emit(ctx, 1, 1); /* 00000001 */
- dd_emit(ctx, 1, 0xf0); /* 000000ff */
- dd_emit(ctx, 1, 0xff); /* 000000ff */
- dd_emit(ctx, 1, 0); /* 000000ff */
- dd_emit(ctx, 1, 0); /* 00000001 */
- dd_emit(ctx, 1, 1); /* 00000001 */
- dd_emit(ctx, 1, 0xf0); /* 000000ff */
- dd_emit(ctx, 1, 0xff); /* 000000ff */
- dd_emit(ctx, 1, 0); /* 000000ff */
- dd_emit(ctx, 1, 9); /* 0000003f UNK114C.COMP,SIZE */
- }
-
- /* eng2d state */
- dd_emit(ctx, 1, 0); /* 00000001 eng2d COLOR_KEY_ENABLE */
- dd_emit(ctx, 1, 0); /* 00000007 eng2d COLOR_KEY_FORMAT */
- dd_emit(ctx, 1, 1); /* ffffffff eng2d DST_DEPTH */
- dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DST_FORMAT */
- dd_emit(ctx, 1, 0); /* ffffffff eng2d DST_LAYER */
- dd_emit(ctx, 1, 1); /* 00000001 eng2d DST_LINEAR */
- dd_emit(ctx, 1, 0); /* 00000007 eng2d PATTERN_COLOR_FORMAT */
- dd_emit(ctx, 1, 0); /* 00000007 eng2d OPERATION */
- dd_emit(ctx, 1, 0); /* 00000003 eng2d PATTERN_SELECT */
- dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SIFC_FORMAT */
- dd_emit(ctx, 1, 0); /* 00000001 eng2d SIFC_BITMAP_ENABLE */
- dd_emit(ctx, 1, 2); /* 00000003 eng2d SIFC_BITMAP_UNK808 */
- dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DU_DX_FRACT */
- dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DU_DX_INT */
- dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DV_DY_FRACT */
- dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DV_DY_INT */
- dd_emit(ctx, 1, 0); /* 00000001 eng2d BLIT_CONTROL_FILTER */
- dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DRAW_COLOR_FORMAT */
- dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SRC_FORMAT */
- dd_emit(ctx, 1, 1); /* 00000001 eng2d SRC_LINEAR #2 */
-
- num = ctx->ctxvals_pos - base;
- ctx->ctxvals_pos = base;
- if (IS_NVA3F(device->chipset))
- cp_ctx(ctx, 0x404800, num);
- else
- cp_ctx(ctx, 0x405400, num);
-}
-
-/*
- * xfer areas. These are a pain.
- *
- * There are 2 xfer areas: the first one is big and contains all sorts of
- * stuff, the second is small and contains some per-TP context.
- *
- * Each area is split into 8 "strands". The areas, when saved to grctx,
- * are made of 8-word blocks. Each block contains a single word from
- * each strand. The strands are independent of each other, their
- * addresses are unrelated to each other, and data in them is closely
- * packed together. The strand layout varies a bit between cards: here
- * and there, a single word is thrown out in the middle and the whole
- * strand is offset by a bit from corresponding one on another chipset.
- * For this reason, addresses of stuff in strands are almost useless.
- * Knowing sequence of stuff and size of gaps between them is much more
- * useful, and that's how we build the strands in our generator.
- *
- * NVA0 takes this mess to a whole new level by cutting the old strands
- * into a few dozen pieces [known as genes], rearranging them randomly,
- * and putting them back together to make new strands. Hopefully these
- * genes correspond more or less directly to the same PGRAPH subunits
- * as in 400040 register.
- *
- * The most common value in default context is 0, and when the genes
- * are separated by 0's, gene bounduaries are quite speculative...
- * some of them can be clearly deduced, others can be guessed, and yet
- * others won't be resolved without figuring out the real meaning of
- * given ctxval. For the same reason, ending point of each strand
- * is unknown. Except for strand 0, which is the longest strand and
- * its end corresponds to end of the whole xfer.
- *
- * An unsolved mystery is the seek instruction: it takes an argument
- * in bits 8-18, and that argument is clearly the place in strands to
- * seek to... but the offsets don't seem to correspond to offsets as
- * seen in grctx. Perhaps there's another, real, not randomly-changing
- * addressing in strands, and the xfer insn just happens to skip over
- * the unused bits? NV10-NV30 PIPE comes to mind...
- *
- * As far as I know, there's no way to access the xfer areas directly
- * without the help of ctxprog.
- */
-
-static void
-xf_emit(struct nouveau_grctx *ctx, int num, u32 val) {
- int i;
- if (val && ctx->mode == NOUVEAU_GRCTX_VALS)
- for (i = 0; i < num; i++)
- nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
- ctx->ctxvals_pos += num << 3;
-}
-
-/* Gene declarations... */
-
-static void nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx);
-static void nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx);
-
-static void
-nv50_graph_construct_xfer1(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
- int offset;
- int size = 0;
- u32 units = nv_rd32 (ctx->device, 0x1540);
-
- offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
- ctx->ctxvals_base = offset;
-
- if (device->chipset < 0xa0) {
- /* Strand 0 */
- ctx->ctxvals_pos = offset;
- nv50_graph_construct_gene_dispatch(ctx);
- nv50_graph_construct_gene_m2mf(ctx);
- nv50_graph_construct_gene_unk24xx(ctx);
- nv50_graph_construct_gene_clipid(ctx);
- nv50_graph_construct_gene_zcull(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 1 */
- ctx->ctxvals_pos = offset + 0x1;
- nv50_graph_construct_gene_vfetch(ctx);
- nv50_graph_construct_gene_eng2d(ctx);
- nv50_graph_construct_gene_csched(ctx);
- nv50_graph_construct_gene_ropm1(ctx);
- nv50_graph_construct_gene_ropm2(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 2 */
- ctx->ctxvals_pos = offset + 0x2;
- nv50_graph_construct_gene_ccache(ctx);
- nv50_graph_construct_gene_unk1cxx(ctx);
- nv50_graph_construct_gene_strmout(ctx);
- nv50_graph_construct_gene_unk14xx(ctx);
- nv50_graph_construct_gene_unk10xx(ctx);
- nv50_graph_construct_gene_unk34xx(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 3: per-ROP group state */
- ctx->ctxvals_pos = offset + 3;
- for (i = 0; i < 6; i++)
- if (units & (1 << (i + 16)))
- nv50_graph_construct_gene_ropc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strands 4-7: per-TP state */
- for (i = 0; i < 4; i++) {
- ctx->ctxvals_pos = offset + 4 + i;
- if (units & (1 << (2 * i)))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << (2 * i + 1)))
- nv50_graph_construct_xfer_tp(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
- }
- } else {
- /* Strand 0 */
- ctx->ctxvals_pos = offset;
- nv50_graph_construct_gene_dispatch(ctx);
- nv50_graph_construct_gene_m2mf(ctx);
- nv50_graph_construct_gene_unk34xx(ctx);
- nv50_graph_construct_gene_csched(ctx);
- nv50_graph_construct_gene_unk1cxx(ctx);
- nv50_graph_construct_gene_strmout(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 1 */
- ctx->ctxvals_pos = offset + 1;
- nv50_graph_construct_gene_unk10xx(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 2 */
- ctx->ctxvals_pos = offset + 2;
- if (device->chipset == 0xa0)
- nv50_graph_construct_gene_unk14xx(ctx);
- nv50_graph_construct_gene_unk24xx(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 3 */
- ctx->ctxvals_pos = offset + 3;
- nv50_graph_construct_gene_vfetch(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 4 */
- ctx->ctxvals_pos = offset + 4;
- nv50_graph_construct_gene_ccache(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 5 */
- ctx->ctxvals_pos = offset + 5;
- nv50_graph_construct_gene_ropm2(ctx);
- nv50_graph_construct_gene_ropm1(ctx);
- /* per-ROP context */
- for (i = 0; i < 8; i++)
- if (units & (1<<(i+16)))
- nv50_graph_construct_gene_ropc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 6 */
- ctx->ctxvals_pos = offset + 6;
- nv50_graph_construct_gene_zcull(ctx);
- nv50_graph_construct_gene_clipid(ctx);
- nv50_graph_construct_gene_eng2d(ctx);
- if (units & (1 << 0))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 1))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 2))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 3))
- nv50_graph_construct_xfer_tp(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 7 */
- ctx->ctxvals_pos = offset + 7;
- if (device->chipset == 0xa0) {
- if (units & (1 << 4))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 5))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 6))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 7))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 8))
- nv50_graph_construct_xfer_tp(ctx);
- if (units & (1 << 9))
- nv50_graph_construct_xfer_tp(ctx);
- } else {
- nv50_graph_construct_gene_unk14xx(ctx);
- }
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
- }
-
- ctx->ctxvals_pos = offset + size * 8;
- ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
- cp_lsr (ctx, offset);
- cp_out (ctx, CP_SET_XFER_POINTER);
- cp_lsr (ctx, size);
- cp_out (ctx, CP_SEEK_1);
- cp_out (ctx, CP_XFER_1);
- cp_wait(ctx, XFER, BUSY);
-}
-
-/*
- * non-trivial demagiced parts of ctx init go here
- */
-
-static void
-nv50_graph_construct_gene_dispatch(struct nouveau_grctx *ctx)
-{
- /* start of strand 0 */
- struct nouveau_device *device = ctx->device;
- /* SEEK */
- if (device->chipset == 0x50)
- xf_emit(ctx, 5, 0);
- else if (!IS_NVA3F(device->chipset))
- xf_emit(ctx, 6, 0);
- else
- xf_emit(ctx, 4, 0);
- /* SEEK */
- /* the PGRAPH's internal FIFO */
- if (device->chipset == 0x50)
- xf_emit(ctx, 8*3, 0);
- else
- xf_emit(ctx, 0x100*3, 0);
- /* and another bonus slot?!? */
- xf_emit(ctx, 3, 0);
- /* and YET ANOTHER bonus slot? */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 3, 0);
- /* SEEK */
- /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
- xf_emit(ctx, 9, 0);
- /* SEEK */
- xf_emit(ctx, 9, 0);
- /* SEEK */
- xf_emit(ctx, 9, 0);
- /* SEEK */
- xf_emit(ctx, 9, 0);
- /* SEEK */
- if (device->chipset < 0x90)
- xf_emit(ctx, 4, 0);
- /* SEEK */
- xf_emit(ctx, 2, 0);
- /* SEEK */
- xf_emit(ctx, 6*2, 0);
- xf_emit(ctx, 2, 0);
- /* SEEK */
- xf_emit(ctx, 2, 0);
- /* SEEK */
- xf_emit(ctx, 6*2, 0);
- xf_emit(ctx, 2, 0);
- /* SEEK */
- if (device->chipset == 0x50)
- xf_emit(ctx, 0x1c, 0);
- else if (device->chipset < 0xa0)
- xf_emit(ctx, 0x1e, 0);
- else
- xf_emit(ctx, 0x22, 0);
- /* SEEK */
- xf_emit(ctx, 0x15, 0);
-}
-
-static void
-nv50_graph_construct_gene_m2mf(struct nouveau_grctx *ctx)
-{
- /* Strand 0, right after dispatch */
- struct nouveau_device *device = ctx->device;
- int smallm2mf = 0;
- if (device->chipset < 0x92 || device->chipset == 0x98)
- smallm2mf = 1;
- /* SEEK */
- xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */
- xf_emit (ctx, 1, 0); /* DMA_BUFFER_IN instance >> 4 */
- xf_emit (ctx, 1, 0); /* DMA_BUFFER_OUT instance >> 4 */
- xf_emit (ctx, 1, 0); /* OFFSET_IN */
- xf_emit (ctx, 1, 0); /* OFFSET_OUT */
- xf_emit (ctx, 1, 0); /* PITCH_IN */
- xf_emit (ctx, 1, 0); /* PITCH_OUT */
- xf_emit (ctx, 1, 0); /* LINE_LENGTH */
- xf_emit (ctx, 1, 0); /* LINE_COUNT */
- xf_emit (ctx, 1, 0x21); /* FORMAT: bits 0-4 INPUT_INC, bits 5-9 OUTPUT_INC */
- xf_emit (ctx, 1, 1); /* LINEAR_IN */
- xf_emit (ctx, 1, 0x2); /* TILING_MODE_IN: bits 0-2 y tiling, bits 3-5 z tiling */
- xf_emit (ctx, 1, 0x100); /* TILING_PITCH_IN */
- xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_IN */
- xf_emit (ctx, 1, 1); /* TILING_DEPTH_IN */
- xf_emit (ctx, 1, 0); /* TILING_POSITION_IN_Z */
- xf_emit (ctx, 1, 0); /* TILING_POSITION_IN */
- xf_emit (ctx, 1, 1); /* LINEAR_OUT */
- xf_emit (ctx, 1, 0x2); /* TILING_MODE_OUT: bits 0-2 y tiling, bits 3-5 z tiling */
- xf_emit (ctx, 1, 0x100); /* TILING_PITCH_OUT */
- xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_OUT */
- xf_emit (ctx, 1, 1); /* TILING_DEPTH_OUT */
- xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT_Z */
- xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT */
- xf_emit (ctx, 1, 0); /* OFFSET_IN_HIGH */
- xf_emit (ctx, 1, 0); /* OFFSET_OUT_HIGH */
- /* SEEK */
- if (smallm2mf)
- xf_emit(ctx, 0x40, 0); /* 20 * ffffffff, 3ffff */
- else
- xf_emit(ctx, 0x100, 0); /* 80 * ffffffff, 3ffff */
- xf_emit(ctx, 4, 0); /* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
- /* SEEK */
- if (smallm2mf)
- xf_emit(ctx, 0x400, 0); /* ffffffff */
- else
- xf_emit(ctx, 0x800, 0); /* ffffffff */
- xf_emit(ctx, 4, 0); /* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
- /* SEEK */
- xf_emit(ctx, 0x40, 0); /* 20 * bits ffffffff, 3ffff */
- xf_emit(ctx, 0x6, 0); /* 1f, 0, 1f, 0, 1f, 0 */
-}
-
-static void
-nv50_graph_construct_gene_ccache(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- xf_emit(ctx, 2, 0); /* RO */
- xf_emit(ctx, 0x800, 0); /* ffffffff */
- switch (device->chipset) {
- case 0x50:
- case 0x92:
- case 0xa0:
- xf_emit(ctx, 0x2b, 0);
- break;
- case 0x84:
- xf_emit(ctx, 0x29, 0);
- break;
- case 0x94:
- case 0x96:
- case 0xa3:
- xf_emit(ctx, 0x27, 0);
- break;
- case 0x86:
- case 0x98:
- case 0xa5:
- case 0xa8:
- case 0xaa:
- case 0xac:
- case 0xaf:
- xf_emit(ctx, 0x25, 0);
- break;
- }
- /* CB bindings, 0x80 of them. first word is address >> 8, second is
- * size >> 4 | valid << 24 */
- xf_emit(ctx, 0x100, 0); /* ffffffff CB_DEF */
- xf_emit(ctx, 1, 0); /* 0000007f CB_ADDR_BUFFER */
- xf_emit(ctx, 1, 0); /* 0 */
- xf_emit(ctx, 0x30, 0); /* ff SET_PROGRAM_CB */
- xf_emit(ctx, 1, 0); /* 3f last SET_PROGRAM_CB */
- xf_emit(ctx, 4, 0); /* RO */
- xf_emit(ctx, 0x100, 0); /* ffffffff */
- xf_emit(ctx, 8, 0); /* 1f, 0, 0, ... */
- xf_emit(ctx, 8, 0); /* ffffffff */
- xf_emit(ctx, 4, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 3 */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_CODE_CB */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_TIC */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_TSC */
- xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */
- xf_emit(ctx, 1, 0); /* 000000ff TIC_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff TIC_ADDRESS_LOW */
- xf_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
- xf_emit(ctx, 1, 0); /* 000000ff TSC_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff TSC_ADDRESS_LOW */
- xf_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
- xf_emit(ctx, 1, 0); /* 000000ff VP_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff VP_ADDRESS_LOW */
- xf_emit(ctx, 1, 0); /* 00ffffff VP_START_ID */
- xf_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0); /* 000000ff GP_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff GP_ADDRESS_LOW */
- xf_emit(ctx, 1, 0); /* 00ffffff GP_START_ID */
- xf_emit(ctx, 1, 0); /* 000000ff FP_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */
- xf_emit(ctx, 1, 0); /* 00ffffff FP_START_ID */
-}
-
-static void
-nv50_graph_construct_gene_unk10xx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
- /* end of area 2 on pre-NVA0, area 1 on NVAx */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
- xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
- if (device->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff);
- else
- xf_emit(ctx, 1, 0x7ff); /* 000007ff */
- xf_emit(ctx, 1, 0); /* 111/113 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- for (i = 0; i < 8; i++) {
- switch (device->chipset) {
- case 0x50:
- case 0x86:
- case 0x98:
- case 0xaa:
- case 0xac:
- xf_emit(ctx, 0xa0, 0); /* ffffffff */
- break;
- case 0x84:
- case 0x92:
- case 0x94:
- case 0x96:
- xf_emit(ctx, 0x120, 0);
- break;
- case 0xa5:
- case 0xa8:
- xf_emit(ctx, 0x100, 0); /* ffffffff */
- break;
- case 0xa0:
- case 0xa3:
- case 0xaf:
- xf_emit(ctx, 0x400, 0); /* ffffffff */
- break;
- }
- xf_emit(ctx, 4, 0); /* 3f, 0, 0, 0 */
- xf_emit(ctx, 4, 0); /* ffffffff */
- }
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
- xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_TEMP */
- xf_emit(ctx, 1, 1); /* 00000001 RASTERIZE_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
-}
-
-static void
-nv50_graph_construct_gene_unk34xx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- /* end of area 2 on pre-NVA0, area 1 on NVAx */
- xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */
- xf_emit(ctx, 1, 0); /* 00000003 VIEWPORT_CLIP_MODE */
- xf_emit(ctx, 0x10, 0x04000000); /* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
- xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */
- xf_emit(ctx, 0x20, 0); /* ffffffff POLYGON_STIPPLE */
- xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */
- xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */
- xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0x1fe21); /* 0001ffff tesla UNK0FAC */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 0x0fac6881);
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 1);
- xf_emit(ctx, 3, 0);
- }
-}
-
-static void
-nv50_graph_construct_gene_unk14xx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
- if (device->chipset != 0x50) {
- xf_emit(ctx, 5, 0); /* ffffffff */
- xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 2, 4); /* 7f, ff */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- }
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* 000000ff VP_CLIP_DISTANCE_ENABLE */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 0); /* 3ff */
- xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1940 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */
- xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */
- xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 0x7f); /* 000000ff tesla UNK0FFC */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 1); /* 00000001 SHADE_MODEL */
- xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0F8C */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0); /* 0000000f */
- if (device->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
- else
- xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
- xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
- xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
- xf_emit(ctx, 3, 0); /* f, 0, 0 */
- xf_emit(ctx, 3, 0); /* ffffffff last VIEWPORT_SCALE? */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
- xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_TRANSLATE */
- xf_emit(ctx, 3, 0); /* f, 0, 0 */
- xf_emit(ctx, 3, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 2, 0x88); /* 000001ff tesla UNK19D8 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
- xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
- xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
- xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
- xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0); /* 0000000f */
- xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
- xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
- if (device->chipset != 0x50) {
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- }
- xf_emit(ctx, 0x20, 0); /* 10xbits ffffffff, 3fffff. SCISSOR_* */
- xf_emit(ctx, 1, 0); /* f */
- xf_emit(ctx, 1, 0); /* 0? */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 003fffff */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
- xf_emit(ctx, 1, 0); /* 0000000f */
-}
-
-static void
-nv50_graph_construct_gene_zcull(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- /* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
- /* SEEK */
- xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */
- xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
- xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */
- xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
- xf_emit(ctx, 1, 0); /* 0000ffff */
- xf_emit(ctx, 1, 0); /* 00000001 UNK0FB0 */
- xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
- xf_emit(ctx, 1, 0); /* 00000007 */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1108 */
- xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */
- /* SEEK */
- xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
- xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
- xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
- xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
- xf_emit(ctx, 1, 0x10); /* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */
- xf_emit(ctx, 1, 3); /* 00000003 FP_CTRL_UNK196C */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1968 */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 0); /* 0fffffff tesla UNK1104 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK151C */
-}
-
-static void
-nv50_graph_construct_gene_clipid(struct nouveau_grctx *ctx)
-{
- /* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 00000007 UNK0FB4 */
- /* SEEK */
- xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_HORIZ */
- xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_VERT */
- xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
- xf_emit(ctx, 2, 0x04000000); /* 07ffffff UNK1508 */
- xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */
- xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_WIDTH */
- xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ID */
- xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff CLIPID_ADDRESS_LOW */
- xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_HEIGHT */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_CLIPID */
-}
-
-static void
-nv50_graph_construct_gene_unk24xx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
- /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
- /* SEEK */
- xf_emit(ctx, 0x33, 0);
- /* SEEK */
- xf_emit(ctx, 2, 0);
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- /* SEEK */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 4, 0); /* RO */
- xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
- xf_emit(ctx, 1, 0); /* 1ff */
- xf_emit(ctx, 8, 0); /* 0? */
- xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
-
- xf_emit(ctx, 4, 0); /* RO */
- xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
- xf_emit(ctx, 1, 0); /* 1ff */
- xf_emit(ctx, 8, 0); /* 0? */
- xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
- } else {
- xf_emit(ctx, 0xc, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
- xf_emit(ctx, 1, 0); /* 1ff */
- xf_emit(ctx, 8, 0); /* 0? */
-
- /* SEEK */
- xf_emit(ctx, 0xc, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
- xf_emit(ctx, 1, 0); /* 1ff */
- xf_emit(ctx, 8, 0); /* 0? */
- }
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
- xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
- xf_emit(ctx, 1, 1); /* 00000001 */
- /* SEEK */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 2, 4); /* 000000ff */
- xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM_ID */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f */
- xf_emit(ctx, 1, 1); /* 00000001 */
- for (i = 0; i < 10; i++) {
- /* SEEK */
- xf_emit(ctx, 0x40, 0); /* ffffffff */
- xf_emit(ctx, 0x10, 0); /* 3, 0, 0.... */
- xf_emit(ctx, 0x10, 0); /* ffffffff */
- }
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_CTRL */
- xf_emit(ctx, 1, 1); /* 00000001 */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */
- xf_emit(ctx, 0x10, 0); /* 00ffffff POINT_COORD_REPLACE_MAP */
- xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 0); /* 000003ff */
-}
-
-static void
-nv50_graph_construct_gene_vfetch(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int acnt = 0x10, rep, i;
- /* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
- if (IS_NVA3F(device->chipset))
- acnt = 0x20;
- /* SEEK */
- if (device->chipset >= 0xa0) {
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK13A4 */
- xf_emit(ctx, 1, 1); /* 00000fff tesla UNK1318 */
- }
- xf_emit(ctx, 1, 0); /* ffffffff VERTEX_BUFFER_FIRST */
- xf_emit(ctx, 1, 0); /* 00000001 PRIMITIVE_RESTART_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 UNK0DE8 */
- xf_emit(ctx, 1, 0); /* ffffffff PRIMITIVE_RESTART_INDEX */
- xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATR_MASK_UNK0DD0 */
- xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
- xf_emit(ctx, 1, 0x20); /* 0000ffff tesla UNK129C */
- xf_emit(ctx, 1, 0); /* 000000ff turing UNK370??? */
- xf_emit(ctx, 1, 0); /* 0000ffff turing USER_PARAM_COUNT */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- /* SEEK */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0xb, 0); /* RO */
- else if (device->chipset >= 0xa0)
- xf_emit(ctx, 0x9, 0); /* RO */
- else
- xf_emit(ctx, 0x8, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 00000001 EDGE_FLAG */
- xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
- /* SEEK */
- xf_emit(ctx, 0xc, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 7f/ff */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
- xf_emit(ctx, 1, 4); /* 000001ff UNK1A28 */
- xf_emit(ctx, 1, 8); /* 000001ff UNK0DF0 */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- if (device->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */
- else
- xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */
- if (device->chipset == 0xa8)
- xf_emit(ctx, 1, 0x1e00); /* 7fff */
- /* SEEK */
- xf_emit(ctx, 0xc, 0); /* RO or close */
- /* SEEK */
- xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
- if (device->chipset > 0x50 && device->chipset < 0xa0)
- xf_emit(ctx, 2, 0); /* ffffffff */
- else
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0FD8 */
- /* SEEK */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 0x10, 0); /* 0? */
- xf_emit(ctx, 2, 0); /* weird... */
- xf_emit(ctx, 2, 0); /* RO */
- } else {
- xf_emit(ctx, 8, 0); /* 0? */
- xf_emit(ctx, 1, 0); /* weird... */
- xf_emit(ctx, 2, 0); /* RO */
- }
- /* SEEK */
- xf_emit(ctx, 1, 0); /* ffffffff VB_ELEMENT_BASE */
- xf_emit(ctx, 1, 0); /* ffffffff UNK1438 */
- xf_emit(ctx, acnt, 0); /* 1 tesla UNK1000 */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1118? */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */
- xf_emit(ctx, 1, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */
- xf_emit(ctx, 1, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* RO */
- xf_emit(ctx, 2, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK111C? */
- xf_emit(ctx, 1, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 000000ff UNK15F4_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff UNK15F4_ADDRESS_LOW */
- xf_emit(ctx, 1, 0); /* 000000ff UNK0F84_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff UNK0F84_ADDRESS_LOW */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
- xf_emit(ctx, 3, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* 00000fff VERTEX_ARRAY_STRIDE */
- xf_emit(ctx, 3, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_LOW */
- xf_emit(ctx, 3, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_ARRAY_HIGH */
- xf_emit(ctx, 3, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_LIMIT_LOW */
- xf_emit(ctx, 3, 0); /* f/1f */
- /* SEEK */
- xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_LIMIT_HIGH */
- xf_emit(ctx, 3, 0); /* f/1f */
- /* SEEK */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, acnt, 0); /* f */
- xf_emit(ctx, 3, 0); /* f/1f */
- }
- /* SEEK */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 2, 0); /* RO */
- else
- xf_emit(ctx, 5, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* ffff DMA_VTXBUF */
- /* SEEK */
- if (device->chipset < 0xa0) {
- xf_emit(ctx, 0x41, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 0x11, 0); /* RO */
- } else if (!IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x50, 0); /* RO */
- else
- xf_emit(ctx, 0x58, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, 1, 1); /* 1 UNK0DEC */
- /* SEEK */
- xf_emit(ctx, acnt*4, 0); /* ffffffff VTX_ATTR */
- xf_emit(ctx, 4, 0); /* f/1f, 0, 0, 0 */
- /* SEEK */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x1d, 0); /* RO */
- else
- xf_emit(ctx, 0x16, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
- /* SEEK */
- if (device->chipset < 0xa0)
- xf_emit(ctx, 8, 0); /* RO */
- else if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0xc, 0); /* RO */
- else
- xf_emit(ctx, 7, 0); /* RO */
- /* SEEK */
- xf_emit(ctx, 0xa, 0); /* RO */
- if (device->chipset == 0xa0)
- rep = 0xc;
- else
- rep = 4;
- for (i = 0; i < rep; i++) {
- /* SEEK */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x20, 0); /* ffffffff */
- xf_emit(ctx, 0x200, 0); /* ffffffff */
- xf_emit(ctx, 4, 0); /* 7f/ff, 0, 0, 0 */
- xf_emit(ctx, 4, 0); /* ffffffff */
- }
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 113/111 */
- xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
- xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATTR_MASK_UNK0DD0 */
- xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- /* SEEK */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 7, 0); /* weird... */
- else
- xf_emit(ctx, 5, 0); /* weird... */
-}
-
-static void
-nv50_graph_construct_gene_eng2d(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- /* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
- /* SEEK */
- xf_emit(ctx, 2, 0); /* 0001ffff CLIP_X, CLIP_Y */
- xf_emit(ctx, 2, 0); /* 0000ffff CLIP_W, CLIP_H */
- xf_emit(ctx, 1, 0); /* 00000001 CLIP_ENABLE */
- if (device->chipset < 0xa0) {
- /* this is useless on everything but the original NV50,
- * guess they forgot to nuke it. Or just didn't bother. */
- xf_emit(ctx, 2, 0); /* 0000ffff IFC_CLIP_X, Y */
- xf_emit(ctx, 2, 1); /* 0000ffff IFC_CLIP_W, H */
- xf_emit(ctx, 1, 0); /* 00000001 IFC_CLIP_ENABLE */
- }
- xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
- xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */
- xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */
- xf_emit(ctx, 1, 0x11); /* 3f[NV50]/7f[NV84+] DST_FORMAT */
- xf_emit(ctx, 1, 0); /* 0001ffff DRAW_POINT_X */
- xf_emit(ctx, 1, 8); /* 0000000f DRAW_UNK58C */
- xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_X_FRACT */
- xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_X_INT */
- xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_Y_FRACT */
- xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_Y_INT */
- xf_emit(ctx, 1, 0); /* 000fffff SIFC_DX_DU_FRACT */
- xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DX_DU_INT */
- xf_emit(ctx, 1, 0); /* 000fffff SIFC_DY_DV_FRACT */
- xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DY_DV_INT */
- xf_emit(ctx, 1, 1); /* 0000ffff SIFC_WIDTH */
- xf_emit(ctx, 1, 1); /* 0000ffff SIFC_HEIGHT */
- xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */
- xf_emit(ctx, 1, 2); /* 00000003 SIFC_BITMAP_UNK808 */
- xf_emit(ctx, 1, 0); /* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
- xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_LSB_FIRST */
- xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_X */
- xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_Y */
- xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */
- xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */
- xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */
- xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */
- xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_W */
- xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_H */
- xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_X_FRACT */
- xf_emit(ctx, 1, 0); /* 0001ffff BLIT_SRC_X_INT */
- xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_Y_FRACT */
- xf_emit(ctx, 1, 0); /* 00000001 UNK888 */
- xf_emit(ctx, 1, 4); /* 0000003f UNK884 */
- xf_emit(ctx, 1, 0); /* 00000007 UNK880 */
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK0FB8 */
- xf_emit(ctx, 1, 0x15); /* 000000ff tesla UNK128C */
- xf_emit(ctx, 2, 0); /* 00000007, ffff0ff3 */
- xf_emit(ctx, 1, 0); /* 00000001 UNK260 */
- xf_emit(ctx, 1, 0x4444480); /* 1fffffff UNK870 */
- /* SEEK */
- xf_emit(ctx, 0x10, 0);
- /* SEEK */
- xf_emit(ctx, 0x27, 0);
-}
-
-static void
-nv50_graph_construct_gene_csched(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- /* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
- /* SEEK */
- xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
- xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 0); /* 000003ff */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* ffffffff turing UNK364 */
- xf_emit(ctx, 1, 0); /* 0000000f turing UNK36C */
- xf_emit(ctx, 1, 0); /* 0000ffff USER_PARAM_COUNT */
- xf_emit(ctx, 1, 0x100); /* 00ffffff turing UNK384 */
- xf_emit(ctx, 1, 0); /* 0000000f turing UNK2A0 */
- xf_emit(ctx, 1, 0); /* 0000ffff GRIDID */
- xf_emit(ctx, 1, 0x10001); /* ffffffff GRIDDIM_XY */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */
- xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */
- xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */
- xf_emit(ctx, 1, 1); /* 00000001 LANES32 */
- xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
- xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
- /* SEEK */
- xf_emit(ctx, 0x40, 0); /* ffffffff USER_PARAM */
- switch (device->chipset) {
- case 0x50:
- case 0x92:
- xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
- xf_emit(ctx, 0x80, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 0x10*2, 0); /* ffffffff, 1f */
- break;
- case 0x84:
- xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
- xf_emit(ctx, 0x60, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
- break;
- case 0x94:
- case 0x96:
- xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
- xf_emit(ctx, 0x40, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 8*2, 0); /* ffffffff, 1f */
- break;
- case 0x86:
- case 0x98:
- xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */
- xf_emit(ctx, 0x10, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */
- break;
- case 0xa0:
- xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
- xf_emit(ctx, 0xf0, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 0x1e*2, 0); /* ffffffff, 1f */
- break;
- case 0xa3:
- xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
- xf_emit(ctx, 0x60, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
- break;
- case 0xa5:
- case 0xaf:
- xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
- xf_emit(ctx, 0x30, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 6*2, 0); /* ffffffff, 1f */
- break;
- case 0xaa:
- xf_emit(ctx, 0x12, 0);
- break;
- case 0xa8:
- case 0xac:
- xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */
- xf_emit(ctx, 0x10, 0); /* fff */
- xf_emit(ctx, 2, 0); /* ff, fff */
- xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */
- break;
- }
- xf_emit(ctx, 1, 0); /* 0000000f */
- xf_emit(ctx, 1, 0); /* 00000000 */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 0000001f */
- xf_emit(ctx, 4, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 4, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 000000ff */
-}
-
-static void
-nv50_graph_construct_gene_unk1cxx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
- xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */
- xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */
- xf_emit(ctx, 3, 0); /* 00000001 POLYGON_OFFSET_*_ENABLE */
- xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */
- xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
- xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_UNITS */
- xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_FACTOR */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */
- xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */
- xf_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_LINEAR */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 3); /* 00000003 UNK16B4 */
- else if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 1); /* 00000001 UNK16B4 */
- xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */
- xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
- xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
- xf_emit(ctx, 1, 5); /* 0000000f UNK1408 */
- xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */
- xf_emit(ctx, 1, 0); /* ffffffff POINT_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 00000007 tesla UNK0FB4 */
- if (device->chipset != 0x50) {
- xf_emit(ctx, 1, 0); /* 3ff */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK1110 */
- }
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */
- xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
- xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
- xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 0x20, 0); /* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK187C */
- xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
- xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 5); /* 0000000f tesla UNK1220 */
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1A20 */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
- xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
- if (device->chipset < 0xa0)
- xf_emit(ctx, 0x1c, 0); /* RO */
- else if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x9, 0);
- xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
- xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
- if (device->chipset != 0x50) {
- xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
- xf_emit(ctx, 1, 0); /* 3ff */
- }
- /* XXX: the following block could belong either to unk1cxx, or
- * to STRMOUT. Rather hard to tell. */
- if (device->chipset < 0xa0)
- xf_emit(ctx, 0x25, 0);
- else
- xf_emit(ctx, 0x3b, 0);
-}
-
-static void
-nv50_graph_construct_gene_strmout(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */
- xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */
- xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */
- if (device->chipset >= 0xa0) {
- xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */
- xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */
- }
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- if (device->chipset == 0x50)
- xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
- else
- xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- /* SEEK */
- xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */
- xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */
- xf_emit(ctx, 4, 0); /* 000000ff STRMOUT_ADDRESS_HIGH */
- xf_emit(ctx, 4, 0); /* ffffffff STRMOUT_ADDRESS_LOW */
- xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */
- if (device->chipset >= 0xa0) {
- xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */
- xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */
- }
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_STRMOUT */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
- xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
- xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
- xf_emit(ctx, 2, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- /* SEEK */
- xf_emit(ctx, 0x20, 0); /* ffffffff STRMOUT_MAP */
- xf_emit(ctx, 1, 0); /* 0000000f */
- xf_emit(ctx, 1, 0); /* 00000000? */
- xf_emit(ctx, 2, 0); /* ffffffff */
-}
-
-static void
-nv50_graph_construct_gene_ropm1(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */
- xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
-}
-
-static void
-nv50_graph_construct_gene_ropm2(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 2, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
- xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
- xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
- xf_emit(ctx, 1, 0); /* 7 */
- /* SEEK */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
- xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
- xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
- xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */
- xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */
- xf_emit(ctx, 1, 0); /* 00000001 eng2d UNK260 */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 0); /* 00000007 */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
-}
-
-static void
-nv50_graph_construct_gene_ropc(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int magic2;
- if (device->chipset == 0x50) {
- magic2 = 0x00003e60;
- } else if (!IS_NVA3F(device->chipset)) {
- magic2 = 0x001ffe67;
- } else {
- magic2 = 0x00087e67;
- }
- xf_emit(ctx, 1, 0); /* f/7 MUTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset))
- xf_emit(ctx, 1, 0x15); /* 000000ff */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
- xf_emit(ctx, 1, 0x10); /* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) {
- xf_emit(ctx, 3, 0); /* ff, ffffffff, ffffffff */
- xf_emit(ctx, 1, 4); /* 7 */
- xf_emit(ctx, 1, 0x400); /* fffffff */
- xf_emit(ctx, 1, 0x300); /* ffff */
- xf_emit(ctx, 1, 0x1001); /* 1fff */
- if (device->chipset != 0xa0) {
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 0); /* 0000000f UNK15C8 */
- else
- xf_emit(ctx, 1, 0x15); /* ff */
- }
- }
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
- xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
- xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
- xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */
- xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 2, 0); /* ffff0ff3, ffff */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
- if (device->chipset >= 0xa0) {
- xf_emit(ctx, 2, 0);
- xf_emit(ctx, 1, 0x1001);
- xf_emit(ctx, 0xb, 0);
- } else {
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- }
- xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 1, 0x11); /* 3f/7f */
- xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
- if (device->chipset != 0x50) {
- xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */
- xf_emit(ctx, 1, 0); /* 000000ff */
- }
- xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
- xf_emit(ctx, 2, 1); /* 00000007 BLEND_EQUATION_RGB, ALPHA */
- xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK12E4 */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
- xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */
- xf_emit(ctx, 2, 0); /* 00000001 */
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* 0000000f */
- xf_emit(ctx, 1, 0); /* 00000003 */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 2, 0); /* 00000001 */
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- } else if (device->chipset >= 0xa0) {
- xf_emit(ctx, 2, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* 00000003 */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 2, 0); /* 00000001 */
- } else {
- xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1430 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- }
- xf_emit(ctx, 4, 0); /* ffffffff CLEAR_COLOR */
- xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR A R G B */
- xf_emit(ctx, 1, 0); /* 00000fff eng2d UNK2B0 */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 2, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
- xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */
- xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 0); /* 00000001 UNK12E4? NVA3+ only? */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK15C4 */
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */
- }
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
- xf_emit(ctx, 1, 0); /* 00000007 PATTERN_COLOR_FORMAT */
- xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 PATTERN_MONO_FORMAT */
- xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_BITMAP */
- xf_emit(ctx, 1, 0); /* 00000003 PATTERN_SELECT */
- xf_emit(ctx, 1, 0); /* 000000ff ROP */
- xf_emit(ctx, 1, 0); /* ffffffff BETA1 */
- xf_emit(ctx, 1, 0); /* ffffffff BETA4 */
- xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
- xf_emit(ctx, 0x50, 0); /* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
-}
-
-static void
-nv50_graph_construct_xfer_unk84xx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int magic3;
- switch (device->chipset) {
- case 0x50:
- magic3 = 0x1000;
- break;
- case 0x86:
- case 0x98:
- case 0xa8:
- case 0xaa:
- case 0xac:
- case 0xaf:
- magic3 = 0x1e00;
- break;
- default:
- magic3 = 0;
- }
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0); /* 111/113[NVA0+] */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x1f, 0); /* ffffffff */
- else if (device->chipset >= 0xa0)
- xf_emit(ctx, 0x0f, 0); /* ffffffff */
- else
- xf_emit(ctx, 0x10, 0); /* fffffff VP_RESULT_MAP_1 up */
- xf_emit(ctx, 2, 0); /* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 0x03020100); /* ffffffff */
- else
- xf_emit(ctx, 1, 0x00608080); /* fffffff VP_RESULT_MAP_0 */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 2, 0); /* 111/113, 7f/ff */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
- if (magic3)
- xf_emit(ctx, 1, magic3); /* 00007fff tesla UNK141C */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0); /* 111/113 */
- xf_emit(ctx, 0x1f, 0); /* ffffffff GP_RESULT_MAP_1 up */
- xf_emit(ctx, 1, 0); /* 0000001f */
- xf_emit(ctx, 1, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0x03020100); /* ffffffff GP_RESULT_MAP_0 */
- xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
- if (magic3)
- xf_emit(ctx, 1, magic3); /* 7fff tesla UNK141C */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0); /* 111/113 */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
- xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK13A0 */
- xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- xf_emit(ctx, 1, 0); /* 111/113 */
- if (device->chipset == 0x94 || device->chipset == 0x96)
- xf_emit(ctx, 0x1020, 0); /* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
- else if (device->chipset < 0xa0)
- xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
- else if (!IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x210, 0); /* ffffffff */
- else
- xf_emit(ctx, 0x410, 0); /* ffffffff */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
- xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
- xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
-}
-
-static void
-nv50_graph_construct_xfer_tprop(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int magic1, magic2;
- if (device->chipset == 0x50) {
- magic1 = 0x3ff;
- magic2 = 0x00003e60;
- } else if (!IS_NVA3F(device->chipset)) {
- magic1 = 0x7ff;
- magic2 = 0x001ffe67;
- } else {
- magic1 = 0x7ff;
- magic2 = 0x00087e67;
- }
- xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* ffffffff ALPHA_TEST_REF */
- xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000000f UNK16A0 */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR */
- xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */
- xf_emit(ctx, 1, 0); /* 00000001 UNK0FDC */
- xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
- xf_emit(ctx, 1, 0); /* ff[NV50]/3ff[NV84+] */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
- xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
- xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
- xf_emit(ctx, 1, 0); /* 7 */
- xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff COLOR_KEY */
- xf_emit(ctx, 1, 0); /* 00000001 COLOR_KEY_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 COLOR_KEY_FORMAT */
- xf_emit(ctx, 2, 0); /* ffffffff SIFC_BITMAP_COLOR */
- xf_emit(ctx, 1, 1); /* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */
- xf_emit(ctx, 1, 0); /* 00000003 */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1298 */
- } else if (device->chipset >= 0xa0) {
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK16B4 */
- xf_emit(ctx, 1, 0); /* 00000003 */
- } else {
- xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
- }
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
- xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_RGB */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_RGB */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_ALPHA */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_ALPHA */
- xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
- }
- xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
- xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
- xf_emit(ctx, 1, 0); /* 7 */
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
- xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
- xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */
- xf_emit(ctx, 1, 0xcf); /* 000000ff DRAW_COLOR_FORMAT */
- xf_emit(ctx, 1, 0xcf); /* 000000ff SRC_FORMAT */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- xf_emit(ctx, 1, 0); /* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 8, 1); /* 00000001 UNK19E0 */
- xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- if (device->chipset == 0x50)
- xf_emit(ctx, 1, 0); /* ff */
- else
- xf_emit(ctx, 3, 0); /* 1, 7, 3ff */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
- xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */
- xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */
- xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */
- xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, magic1); /* 3ff/7ff tesla UNK0D68 */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 8, 0); /* 0000ffff DMA_COLOR */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_GLOBAL */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_LOCAL */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_STACK */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_DST */
- xf_emit(ctx, 1, 0); /* 7 */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 8, 0); /* 000000ff RT_ADDRESS_HIGH */
- xf_emit(ctx, 8, 0); /* ffffffff RT_LAYER_STRIDE */
- xf_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */
- xf_emit(ctx, 8, 8); /* 0000007f RT_TILE_MODE */
- xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 8, 0x400); /* 0fffffff RT_HORIZ */
- xf_emit(ctx, 8, 0x300); /* 0000ffff RT_VERT */
- xf_emit(ctx, 1, 1); /* 00001fff RT_ARRAY_MODE */
- xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 1, 0x20); /* 00000fff DST_TILE_MODE */
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */
- xf_emit(ctx, 1, 0); /* 000007ff DST_LAYER */
- xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
- xf_emit(ctx, 1, 0); /* ffffffff DST_ADDRESS_LOW */
- xf_emit(ctx, 1, 0); /* 000000ff DST_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0x40); /* 0007ffff DST_PITCH */
- xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */
- xf_emit(ctx, 1, 0); /* 0000ffff */
- xf_emit(ctx, 1, 3); /* 00000003 tesla UNK15AC */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
- xf_emit(ctx, 1, 0); /* 00000007 */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_ZETA */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 2, 0); /* ffff, ff/3ff */
- xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* ffffffff ZETA_LAYER_STRIDE */
- xf_emit(ctx, 1, 0); /* 000000ff ZETA_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff ZETA_ADDRESS_LOW */
- xf_emit(ctx, 1, 4); /* 00000007 ZETA_TILE_MODE */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- xf_emit(ctx, 1, 0x400); /* 0fffffff ZETA_HORIZ */
- xf_emit(ctx, 1, 0x300); /* 0000ffff ZETA_VERT */
- xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 0); /* 00000001 */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
- xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
- xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
- xf_emit(ctx, 1, 0); /* 7 */
- xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- }
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 0x0fac6881); /* fffffff */
- xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
- xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
- xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* 0000000f tesla UNK15C8 */
- }
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
- if (device->chipset >= 0xa0) {
- xf_emit(ctx, 3, 0); /* 7/f, 1, ffff0ff3 */
- xf_emit(ctx, 1, 0xfac6881); /* fffffff */
- xf_emit(ctx, 4, 0); /* 1, 1, 1, 3ff */
- xf_emit(ctx, 1, 4); /* 7 */
- xf_emit(ctx, 1, 0); /* 1 */
- xf_emit(ctx, 2, 1); /* 1 */
- xf_emit(ctx, 2, 0); /* 7, f */
- xf_emit(ctx, 1, 1); /* 1 */
- xf_emit(ctx, 1, 0); /* 7/f */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 0x9, 0); /* 1 */
- else
- xf_emit(ctx, 0x8, 0); /* 1 */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 8, 1); /* 1 */
- xf_emit(ctx, 1, 0x11); /* 7f */
- xf_emit(ctx, 7, 0); /* 7f */
- xf_emit(ctx, 1, 0xfac6881); /* fffffff */
- xf_emit(ctx, 1, 0xf); /* f */
- xf_emit(ctx, 7, 0); /* f */
- xf_emit(ctx, 1, 0x11); /* 7f */
- xf_emit(ctx, 1, 1); /* 1 */
- xf_emit(ctx, 5, 0); /* 1, 7, 3ff, 3, 7 */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- }
- }
-}
-
-static void
-nv50_graph_construct_xfer_tex(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- xf_emit(ctx, 2, 0); /* 1 LINKED_TSC. yes, 2. */
- if (device->chipset != 0x50)
- xf_emit(ctx, 1, 0); /* 3 */
- xf_emit(ctx, 1, 1); /* 1ffff BLIT_DU_DX_INT */
- xf_emit(ctx, 1, 0); /* fffff BLIT_DU_DX_FRACT */
- xf_emit(ctx, 1, 1); /* 1ffff BLIT_DV_DY_INT */
- xf_emit(ctx, 1, 0); /* fffff BLIT_DV_DY_FRACT */
- if (device->chipset == 0x50)
- xf_emit(ctx, 1, 0); /* 3 BLIT_CONTROL */
- else
- xf_emit(ctx, 2, 0); /* 3ff, 1 */
- xf_emit(ctx, 1, 0x2a712488); /* ffffffff SRC_TIC_0 */
- xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_1 */
- xf_emit(ctx, 1, 0x4085c000); /* ffffffff SRC_TIC_2 */
- xf_emit(ctx, 1, 0x40); /* ffffffff SRC_TIC_3 */
- xf_emit(ctx, 1, 0x100); /* ffffffff SRC_TIC_4 */
- xf_emit(ctx, 1, 0x10100); /* ffffffff SRC_TIC_5 */
- xf_emit(ctx, 1, 0x02800000); /* ffffffff SRC_TIC_6 */
- xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_7 */
- if (device->chipset == 0x50) {
- xf_emit(ctx, 1, 0); /* 00000001 turing UNK358 */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */
- xf_emit(ctx, 1, 0); /* 00000003 turing UNK37C tesla UNK1690 */
- xf_emit(ctx, 1, 0); /* 00000003 BLIT_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000001 turing UNK32C tesla UNK0F94 */
- } else if (!IS_NVAAF(device->chipset)) {
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */
- xf_emit(ctx, 1, 0); /* 00000003 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- xf_emit(ctx, 1, 0); /* 00000003 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1664 / turing UNK03E8 */
- xf_emit(ctx, 1, 0); /* 00000003 */
- xf_emit(ctx, 1, 0); /* 000003ff */
- } else {
- xf_emit(ctx, 0x6, 0);
- }
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_TEXTURE */
- xf_emit(ctx, 1, 0); /* 0000ffff DMA_SRC */
-}
-
-static void
-nv50_graph_construct_xfer_unk8cxx(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 2, 0); /* 7, ffff0ff3 */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */
- xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */
- xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */
- xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK0F98 */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
- xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
- xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */
- xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
- xf_emit(ctx, 1, 0); /* ffff0ff3 */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */
- xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */
- xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
- xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */
- xf_emit(ctx, 1, 0x30201000); /* ffffffff tesla UNK1670 */
- xf_emit(ctx, 1, 0x70605040); /* ffffffff tesla UNK1670 */
- xf_emit(ctx, 1, 0xb8a89888); /* ffffffff tesla UNK1670 */
- xf_emit(ctx, 1, 0xf8e8d8c8); /* ffffffff tesla UNK1670 */
- xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
- xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
-}
-
-static void
-nv50_graph_construct_xfer_tp(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- if (device->chipset < 0xa0) {
- nv50_graph_construct_xfer_unk84xx(ctx);
- nv50_graph_construct_xfer_tprop(ctx);
- nv50_graph_construct_xfer_tex(ctx);
- nv50_graph_construct_xfer_unk8cxx(ctx);
- } else {
- nv50_graph_construct_xfer_tex(ctx);
- nv50_graph_construct_xfer_tprop(ctx);
- nv50_graph_construct_xfer_unk8cxx(ctx);
- nv50_graph_construct_xfer_unk84xx(ctx);
- }
-}
-
-static void
-nv50_graph_construct_xfer_mpc(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i, mpcnt = 2;
- switch (device->chipset) {
- case 0x98:
- case 0xaa:
- mpcnt = 1;
- break;
- case 0x50:
- case 0x84:
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0xa8:
- case 0xac:
- mpcnt = 2;
- break;
- case 0xa0:
- case 0xa3:
- case 0xa5:
- case 0xaf:
- mpcnt = 3;
- break;
- }
- for (i = 0; i < mpcnt; i++) {
- xf_emit(ctx, 1, 0); /* ff */
- xf_emit(ctx, 1, 0x80); /* ffffffff tesla UNK1404 */
- xf_emit(ctx, 1, 0x80007004); /* ffffffff tesla UNK12B0 */
- xf_emit(ctx, 1, 0x04000400); /* ffffffff */
- if (device->chipset >= 0xa0)
- xf_emit(ctx, 1, 0xc0); /* 00007fff tesla UNK152C */
- xf_emit(ctx, 1, 0x1000); /* 0000ffff tesla UNK0D60 */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
- if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) {
- xf_emit(ctx, 1, 0xe00); /* 7fff */
- xf_emit(ctx, 1, 0x1e00); /* 7fff */
- }
- xf_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP */
- xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- if (device->chipset == 0x50)
- xf_emit(ctx, 2, 0x1000); /* 7fff tesla UNK141C */
- xf_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP */
- xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
- xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
- xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
- if (IS_NVAAF(device->chipset))
- xf_emit(ctx, 0xb, 0); /* RO */
- else if (device->chipset >= 0xa0)
- xf_emit(ctx, 0xc, 0); /* RO */
- else
- xf_emit(ctx, 0xa, 0); /* RO */
- }
- xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- if (device->chipset >= 0xa0) {
- xf_emit(ctx, 1, 0x1fe21); /* 0003ffff tesla UNK0FAC */
- }
- xf_emit(ctx, 3, 0); /* 7fff, 0, 0 */
- xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
- xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
- xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
- xf_emit(ctx, 1, 1); /* 00000001 LANES32 */
- xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */
- xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */
- xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */
- xf_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */
- xf_emit(ctx, 1, 0x1fe21); /* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
- xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
- xf_emit(ctx, 1, 0); /* ff/3ff */
- xf_emit(ctx, 1, 0); /* 1 LINKED_TSC */
- xf_emit(ctx, 1, 0); /* ff FP_ADDRESS_HIGH */
- xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */
- xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
- xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
- xf_emit(ctx, 1, 0); /* 000000ff FRAG_COLOR_CLAMP_EN */
- xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
- xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */
- xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */
- xf_emit(ctx, 1, 0); /* 00000007 */
- xf_emit(ctx, 1, 0xfac6881); /* 0fffffff RT_CONTROL */
- xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
- if (IS_NVA3F(device->chipset))
- xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */
- xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
- xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
- xf_emit(ctx, 1, 4); /* ffffffff tesla UNK1400 */
- xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
- xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
- xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
- xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
- if (IS_NVA3F(device->chipset)) {
- xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
- xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
- xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
- xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
- xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */
- xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
- }
- xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */
- xf_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */
- /* XXX: demagic this part some day */
- if (device->chipset == 0x50)
- xf_emit(ctx, 0x3a0, 0);
- else if (device->chipset < 0x94)
- xf_emit(ctx, 0x3a2, 0);
- else if (device->chipset == 0x98 || device->chipset == 0xaa)
- xf_emit(ctx, 0x39f, 0);
- else
- xf_emit(ctx, 0x3a3, 0);
- xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
- xf_emit(ctx, 1, 0); /* 7 OPERATION */
- xf_emit(ctx, 1, 1); /* 1 DST_LINEAR */
- xf_emit(ctx, 0x2d, 0);
-}
-
-static void
-nv50_graph_construct_xfer2(struct nouveau_grctx *ctx)
-{
- struct nouveau_device *device = ctx->device;
- int i;
- u32 offset;
- u32 units = nv_rd32 (ctx->device, 0x1540);
- int size = 0;
-
- offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
-
- if (device->chipset < 0xa0) {
- for (i = 0; i < 8; i++) {
- ctx->ctxvals_pos = offset + i;
- /* that little bugger belongs to csched. No idea
- * what it's doing here. */
- if (i == 0)
- xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
- if (units & (1 << i))
- nv50_graph_construct_xfer_mpc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
- }
- } else {
- /* Strand 0: TPs 0, 1 */
- ctx->ctxvals_pos = offset;
- /* that little bugger belongs to csched. No idea
- * what it's doing here. */
- xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
- if (units & (1 << 0))
- nv50_graph_construct_xfer_mpc(ctx);
- if (units & (1 << 1))
- nv50_graph_construct_xfer_mpc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 1: TPs 2, 3 */
- ctx->ctxvals_pos = offset + 1;
- if (units & (1 << 2))
- nv50_graph_construct_xfer_mpc(ctx);
- if (units & (1 << 3))
- nv50_graph_construct_xfer_mpc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 2: TPs 4, 5, 6 */
- ctx->ctxvals_pos = offset + 2;
- if (units & (1 << 4))
- nv50_graph_construct_xfer_mpc(ctx);
- if (units & (1 << 5))
- nv50_graph_construct_xfer_mpc(ctx);
- if (units & (1 << 6))
- nv50_graph_construct_xfer_mpc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
-
- /* Strand 3: TPs 7, 8, 9 */
- ctx->ctxvals_pos = offset + 3;
- if (units & (1 << 7))
- nv50_graph_construct_xfer_mpc(ctx);
- if (units & (1 << 8))
- nv50_graph_construct_xfer_mpc(ctx);
- if (units & (1 << 9))
- nv50_graph_construct_xfer_mpc(ctx);
- if ((ctx->ctxvals_pos-offset)/8 > size)
- size = (ctx->ctxvals_pos-offset)/8;
- }
- ctx->ctxvals_pos = offset + size * 8;
- ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
- cp_lsr (ctx, offset);
- cp_out (ctx, CP_SET_XFER_POINTER);
- cp_lsr (ctx, size);
- cp_out (ctx, CP_SEEK_2);
- cp_out (ctx, CP_XFER_2);
- cp_wait(ctx, XFER, BUSY);
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
deleted file mode 100644
index b8e5fe60a1eb..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.c
+++ /dev/null
@@ -1,1386 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000b2, 40, 0x01, 0x00000000 },
- { 0x000210, 8, 0x01, 0x00000040 },
- { 0x000218, 8, 0x01, 0x0000c080 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00001fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x003fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x0005e0, 5, 0x01, 0x00000022 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x00000c48 },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00300008 },
- { 0x000841, 1, 0x01, 0x04000080 },
- { 0x000842, 1, 0x01, 0x00300008 },
- { 0x000843, 1, 0x01, 0x04000080 },
- { 0x000818, 8, 0x01, 0x00000000 },
- { 0x000848, 16, 0x01, 0x00000000 },
- { 0x000738, 1, 0x01, 0x00000000 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x000944, 1, 0x01, 0x00000022 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000014 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_icmd[] = {
- { nvc0_grctx_init_icmd_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_9097_0[] = {
- { 0x000800, 8, 0x40, 0x00000000 },
- { 0x000804, 8, 0x40, 0x00000000 },
- { 0x000808, 8, 0x40, 0x00000400 },
- { 0x00080c, 8, 0x40, 0x00000300 },
- { 0x000810, 1, 0x04, 0x000000cf },
- { 0x000850, 7, 0x40, 0x00000000 },
- { 0x000814, 8, 0x40, 0x00000040 },
- { 0x000818, 8, 0x40, 0x00000001 },
- { 0x00081c, 8, 0x40, 0x00000000 },
- { 0x000820, 8, 0x40, 0x00000000 },
- { 0x002700, 8, 0x20, 0x00000000 },
- { 0x002704, 8, 0x20, 0x00000000 },
- { 0x002708, 8, 0x20, 0x00000000 },
- { 0x00270c, 8, 0x20, 0x00000000 },
- { 0x002710, 8, 0x20, 0x00014000 },
- { 0x002714, 8, 0x20, 0x00000040 },
- { 0x001c00, 16, 0x10, 0x00000000 },
- { 0x001c04, 16, 0x10, 0x00000000 },
- { 0x001c08, 16, 0x10, 0x00000000 },
- { 0x001c0c, 16, 0x10, 0x00000000 },
- { 0x001d00, 16, 0x10, 0x00000000 },
- { 0x001d04, 16, 0x10, 0x00000000 },
- { 0x001d08, 16, 0x10, 0x00000000 },
- { 0x001d0c, 16, 0x10, 0x00000000 },
- { 0x001f00, 16, 0x08, 0x00000000 },
- { 0x001f04, 16, 0x08, 0x00000000 },
- { 0x001f80, 16, 0x08, 0x00000000 },
- { 0x001f84, 16, 0x08, 0x00000000 },
- { 0x002200, 5, 0x10, 0x00000022 },
- { 0x002000, 1, 0x04, 0x00000000 },
- { 0x002040, 1, 0x04, 0x00000011 },
- { 0x002080, 1, 0x04, 0x00000020 },
- { 0x0020c0, 1, 0x04, 0x00000030 },
- { 0x002100, 1, 0x04, 0x00000040 },
- { 0x002140, 1, 0x04, 0x00000051 },
- { 0x00200c, 6, 0x40, 0x00000001 },
- { 0x002010, 1, 0x04, 0x00000000 },
- { 0x002050, 1, 0x04, 0x00000000 },
- { 0x002090, 1, 0x04, 0x00000001 },
- { 0x0020d0, 1, 0x04, 0x00000002 },
- { 0x002110, 1, 0x04, 0x00000003 },
- { 0x002150, 1, 0x04, 0x00000004 },
- { 0x000380, 4, 0x20, 0x00000000 },
- { 0x000384, 4, 0x20, 0x00000000 },
- { 0x000388, 4, 0x20, 0x00000000 },
- { 0x00038c, 4, 0x20, 0x00000000 },
- { 0x000700, 4, 0x10, 0x00000000 },
- { 0x000704, 4, 0x10, 0x00000000 },
- { 0x000708, 4, 0x10, 0x00000000 },
- { 0x002800, 128, 0x04, 0x00000000 },
- { 0x000a00, 16, 0x20, 0x00000000 },
- { 0x000a04, 16, 0x20, 0x00000000 },
- { 0x000a08, 16, 0x20, 0x00000000 },
- { 0x000a0c, 16, 0x20, 0x00000000 },
- { 0x000a10, 16, 0x20, 0x00000000 },
- { 0x000a14, 16, 0x20, 0x00000000 },
- { 0x000c00, 16, 0x10, 0x00000000 },
- { 0x000c04, 16, 0x10, 0x00000000 },
- { 0x000c08, 16, 0x10, 0x00000000 },
- { 0x000c0c, 16, 0x10, 0x3f800000 },
- { 0x000d00, 8, 0x08, 0xffff0000 },
- { 0x000d04, 8, 0x08, 0xffff0000 },
- { 0x000e00, 16, 0x10, 0x00000000 },
- { 0x000e04, 16, 0x10, 0xffff0000 },
- { 0x000e08, 16, 0x10, 0xffff0000 },
- { 0x000d40, 4, 0x08, 0x00000000 },
- { 0x000d44, 4, 0x08, 0x00000000 },
- { 0x001e00, 8, 0x20, 0x00000001 },
- { 0x001e04, 8, 0x20, 0x00000001 },
- { 0x001e08, 8, 0x20, 0x00000002 },
- { 0x001e0c, 8, 0x20, 0x00000001 },
- { 0x001e10, 8, 0x20, 0x00000001 },
- { 0x001e14, 8, 0x20, 0x00000002 },
- { 0x001e18, 8, 0x20, 0x00000001 },
- { 0x003400, 128, 0x04, 0x00000000 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x001514, 1, 0x04, 0x00000000 },
- { 0x000d68, 1, 0x04, 0x0000ffff },
- { 0x00121c, 1, 0x04, 0x0fac6881 },
- { 0x000fac, 1, 0x04, 0x00000001 },
- { 0x001538, 1, 0x04, 0x00000001 },
- { 0x000fe0, 2, 0x04, 0x00000000 },
- { 0x000fe8, 1, 0x04, 0x00000014 },
- { 0x000fec, 1, 0x04, 0x00000040 },
- { 0x000ff0, 1, 0x04, 0x00000000 },
- { 0x00179c, 1, 0x04, 0x00000000 },
- { 0x001228, 1, 0x04, 0x00000400 },
- { 0x00122c, 1, 0x04, 0x00000300 },
- { 0x001230, 1, 0x04, 0x00010001 },
- { 0x0007f8, 1, 0x04, 0x00000000 },
- { 0x0015b4, 1, 0x04, 0x00000001 },
- { 0x0015cc, 1, 0x04, 0x00000000 },
- { 0x001534, 1, 0x04, 0x00000000 },
- { 0x000fb0, 1, 0x04, 0x00000000 },
- { 0x0015d0, 1, 0x04, 0x00000000 },
- { 0x00153c, 1, 0x04, 0x00000000 },
- { 0x0016b4, 1, 0x04, 0x00000003 },
- { 0x000fbc, 4, 0x04, 0x0000ffff },
- { 0x000df8, 2, 0x04, 0x00000000 },
- { 0x001948, 1, 0x04, 0x00000000 },
- { 0x001970, 1, 0x04, 0x00000001 },
- { 0x00161c, 1, 0x04, 0x000009f0 },
- { 0x000dcc, 1, 0x04, 0x00000010 },
- { 0x00163c, 1, 0x04, 0x00000000 },
- { 0x0015e4, 1, 0x04, 0x00000000 },
- { 0x001160, 32, 0x04, 0x25e00040 },
- { 0x001880, 32, 0x04, 0x00000000 },
- { 0x000f84, 2, 0x04, 0x00000000 },
- { 0x0017c8, 2, 0x04, 0x00000000 },
- { 0x0017d0, 1, 0x04, 0x000000ff },
- { 0x0017d4, 1, 0x04, 0xffffffff },
- { 0x0017d8, 1, 0x04, 0x00000002 },
- { 0x0017dc, 1, 0x04, 0x00000000 },
- { 0x0015f4, 2, 0x04, 0x00000000 },
- { 0x001434, 2, 0x04, 0x00000000 },
- { 0x000d74, 1, 0x04, 0x00000000 },
- { 0x000dec, 1, 0x04, 0x00000001 },
- { 0x0013a4, 1, 0x04, 0x00000000 },
- { 0x001318, 1, 0x04, 0x00000001 },
- { 0x001644, 1, 0x04, 0x00000000 },
- { 0x000748, 1, 0x04, 0x00000000 },
- { 0x000de8, 1, 0x04, 0x00000000 },
- { 0x001648, 1, 0x04, 0x00000000 },
- { 0x0012a4, 1, 0x04, 0x00000000 },
- { 0x001120, 4, 0x04, 0x00000000 },
- { 0x001118, 1, 0x04, 0x00000000 },
- { 0x00164c, 1, 0x04, 0x00000000 },
- { 0x001658, 1, 0x04, 0x00000000 },
- { 0x001910, 1, 0x04, 0x00000290 },
- { 0x001518, 1, 0x04, 0x00000000 },
- { 0x00165c, 1, 0x04, 0x00000001 },
- { 0x001520, 1, 0x04, 0x00000000 },
- { 0x001604, 1, 0x04, 0x00000000 },
- { 0x001570, 1, 0x04, 0x00000000 },
- { 0x0013b0, 2, 0x04, 0x3f800000 },
- { 0x00020c, 1, 0x04, 0x00000000 },
- { 0x001670, 1, 0x04, 0x30201000 },
- { 0x001674, 1, 0x04, 0x70605040 },
- { 0x001678, 1, 0x04, 0xb8a89888 },
- { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
- { 0x00166c, 1, 0x04, 0x00000000 },
- { 0x001680, 1, 0x04, 0x00ffff00 },
- { 0x0012d0, 1, 0x04, 0x00000003 },
- { 0x0012d4, 1, 0x04, 0x00000002 },
- { 0x001684, 2, 0x04, 0x00000000 },
- { 0x000dac, 2, 0x04, 0x00001b02 },
- { 0x000db4, 1, 0x04, 0x00000000 },
- { 0x00168c, 1, 0x04, 0x00000000 },
- { 0x0015bc, 1, 0x04, 0x00000000 },
- { 0x00156c, 1, 0x04, 0x00000000 },
- { 0x00187c, 1, 0x04, 0x00000000 },
- { 0x001110, 1, 0x04, 0x00000001 },
- { 0x000dc0, 3, 0x04, 0x00000000 },
- { 0x001234, 1, 0x04, 0x00000000 },
- { 0x001690, 1, 0x04, 0x00000000 },
- { 0x0012ac, 1, 0x04, 0x00000001 },
- { 0x0002c4, 1, 0x04, 0x00000000 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x001000, 1, 0x04, 0x00000010 },
- { 0x0010fc, 1, 0x04, 0x00000000 },
- { 0x001290, 1, 0x04, 0x00000000 },
- { 0x000218, 1, 0x04, 0x00000010 },
- { 0x0012d8, 1, 0x04, 0x00000000 },
- { 0x0012dc, 1, 0x04, 0x00000010 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x00155c, 2, 0x04, 0x00000000 },
- { 0x001564, 1, 0x04, 0x00001fff },
- { 0x001574, 2, 0x04, 0x00000000 },
- { 0x00157c, 1, 0x04, 0x003fffff },
- { 0x001354, 1, 0x04, 0x00000000 },
- { 0x001664, 1, 0x04, 0x00000000 },
- { 0x001610, 1, 0x04, 0x00000012 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x00162c, 1, 0x04, 0x00000003 },
- { 0x000210, 1, 0x04, 0x00000000 },
- { 0x000320, 1, 0x04, 0x00000000 },
- { 0x000324, 6, 0x04, 0x3f800000 },
- { 0x000750, 1, 0x04, 0x00000000 },
- { 0x000760, 1, 0x04, 0x39291909 },
- { 0x000764, 1, 0x04, 0x79695949 },
- { 0x000768, 1, 0x04, 0xb9a99989 },
- { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
- { 0x000770, 1, 0x04, 0x30201000 },
- { 0x000774, 1, 0x04, 0x70605040 },
- { 0x000778, 1, 0x04, 0x00009080 },
- { 0x000780, 1, 0x04, 0x39291909 },
- { 0x000784, 1, 0x04, 0x79695949 },
- { 0x000788, 1, 0x04, 0xb9a99989 },
- { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
- { 0x0007d0, 1, 0x04, 0x30201000 },
- { 0x0007d4, 1, 0x04, 0x70605040 },
- { 0x0007d8, 1, 0x04, 0x00009080 },
- { 0x00037c, 1, 0x04, 0x00000001 },
- { 0x000740, 2, 0x04, 0x00000000 },
- { 0x002600, 1, 0x04, 0x00000000 },
- { 0x001918, 1, 0x04, 0x00000000 },
- { 0x00191c, 1, 0x04, 0x00000900 },
- { 0x001920, 1, 0x04, 0x00000405 },
- { 0x001308, 1, 0x04, 0x00000001 },
- { 0x001924, 1, 0x04, 0x00000000 },
- { 0x0013ac, 1, 0x04, 0x00000000 },
- { 0x00192c, 1, 0x04, 0x00000001 },
- { 0x00193c, 1, 0x04, 0x00002c1c },
- { 0x000d7c, 1, 0x04, 0x00000000 },
- { 0x000f8c, 1, 0x04, 0x00000000 },
- { 0x0002c0, 1, 0x04, 0x00000001 },
- { 0x001510, 1, 0x04, 0x00000000 },
- { 0x001940, 1, 0x04, 0x00000000 },
- { 0x000ff4, 2, 0x04, 0x00000000 },
- { 0x00194c, 2, 0x04, 0x00000000 },
- { 0x001968, 1, 0x04, 0x00000000 },
- { 0x001590, 1, 0x04, 0x0000003f },
- { 0x0007e8, 4, 0x04, 0x00000000 },
- { 0x00196c, 1, 0x04, 0x00000011 },
- { 0x00197c, 1, 0x04, 0x00000000 },
- { 0x000fcc, 2, 0x04, 0x00000000 },
- { 0x0002d8, 1, 0x04, 0x00000040 },
- { 0x001980, 1, 0x04, 0x00000080 },
- { 0x001504, 1, 0x04, 0x00000080 },
- { 0x001984, 1, 0x04, 0x00000000 },
- { 0x000300, 1, 0x04, 0x00000001 },
- { 0x0013a8, 1, 0x04, 0x00000000 },
- { 0x0012ec, 1, 0x04, 0x00000000 },
- { 0x001310, 1, 0x04, 0x00000000 },
- { 0x001314, 1, 0x04, 0x00000001 },
- { 0x001380, 1, 0x04, 0x00000000 },
- { 0x001384, 4, 0x04, 0x00000001 },
- { 0x001394, 1, 0x04, 0x00000000 },
- { 0x00139c, 1, 0x04, 0x00000000 },
- { 0x001398, 1, 0x04, 0x00000000 },
- { 0x001594, 1, 0x04, 0x00000000 },
- { 0x001598, 4, 0x04, 0x00000001 },
- { 0x000f54, 3, 0x04, 0x00000000 },
- { 0x0019bc, 1, 0x04, 0x00000000 },
- { 0x000f9c, 2, 0x04, 0x00000000 },
- { 0x0012cc, 1, 0x04, 0x00000000 },
- { 0x0012e8, 1, 0x04, 0x00000000 },
- { 0x00130c, 1, 0x04, 0x00000001 },
- { 0x001360, 8, 0x04, 0x00000000 },
- { 0x00133c, 2, 0x04, 0x00000001 },
- { 0x001344, 1, 0x04, 0x00000002 },
- { 0x001348, 2, 0x04, 0x00000001 },
- { 0x001350, 1, 0x04, 0x00000002 },
- { 0x001358, 1, 0x04, 0x00000001 },
- { 0x0012e4, 1, 0x04, 0x00000000 },
- { 0x00131c, 4, 0x04, 0x00000000 },
- { 0x0019c0, 1, 0x04, 0x00000000 },
- { 0x001140, 1, 0x04, 0x00000000 },
- { 0x0019c4, 1, 0x04, 0x00000000 },
- { 0x0019c8, 1, 0x04, 0x00001500 },
- { 0x00135c, 1, 0x04, 0x00000000 },
- { 0x000f90, 1, 0x04, 0x00000000 },
- { 0x0019e0, 8, 0x04, 0x00000001 },
- { 0x0019cc, 1, 0x04, 0x00000001 },
- { 0x0015b8, 1, 0x04, 0x00000000 },
- { 0x001a00, 1, 0x04, 0x00001111 },
- { 0x001a04, 7, 0x04, 0x00000000 },
- { 0x000d6c, 2, 0x04, 0xffff0000 },
- { 0x0010f8, 1, 0x04, 0x00001010 },
- { 0x000d80, 5, 0x04, 0x00000000 },
- { 0x000da0, 1, 0x04, 0x00000000 },
- { 0x001508, 1, 0x04, 0x80000000 },
- { 0x00150c, 1, 0x04, 0x40000000 },
- { 0x001668, 1, 0x04, 0x00000000 },
- { 0x000318, 2, 0x04, 0x00000008 },
- { 0x000d9c, 1, 0x04, 0x00000001 },
- { 0x0007dc, 1, 0x04, 0x00000000 },
- { 0x00074c, 1, 0x04, 0x00000055 },
- { 0x001420, 1, 0x04, 0x00000003 },
- { 0x0017bc, 2, 0x04, 0x00000000 },
- { 0x0017c4, 1, 0x04, 0x00000001 },
- { 0x001008, 1, 0x04, 0x00000008 },
- { 0x00100c, 1, 0x04, 0x00000040 },
- { 0x001010, 1, 0x04, 0x0000012c },
- { 0x000d60, 1, 0x04, 0x00000040 },
- { 0x00075c, 1, 0x04, 0x00000003 },
- { 0x001018, 1, 0x04, 0x00000020 },
- { 0x00101c, 1, 0x04, 0x00000001 },
- { 0x001020, 1, 0x04, 0x00000020 },
- { 0x001024, 1, 0x04, 0x00000001 },
- { 0x001444, 3, 0x04, 0x00000000 },
- { 0x000360, 1, 0x04, 0x20164010 },
- { 0x000364, 1, 0x04, 0x00000020 },
- { 0x000368, 1, 0x04, 0x00000000 },
- { 0x000de4, 1, 0x04, 0x00000000 },
- { 0x000204, 1, 0x04, 0x00000006 },
- { 0x000208, 1, 0x04, 0x00000000 },
- { 0x0002cc, 1, 0x04, 0x003fffff },
- { 0x0002d0, 1, 0x04, 0x00000c48 },
- { 0x001220, 1, 0x04, 0x00000005 },
- { 0x000fdc, 1, 0x04, 0x00000000 },
- { 0x000f98, 1, 0x04, 0x00300008 },
- { 0x001284, 1, 0x04, 0x04000080 },
- { 0x001450, 1, 0x04, 0x00300008 },
- { 0x001454, 1, 0x04, 0x04000080 },
- { 0x000214, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_902d_0[] = {
- { 0x000200, 1, 0x04, 0x000000cf },
- { 0x000204, 1, 0x04, 0x00000001 },
- { 0x000208, 1, 0x04, 0x00000020 },
- { 0x00020c, 1, 0x04, 0x00000001 },
- { 0x000210, 1, 0x04, 0x00000000 },
- { 0x000214, 1, 0x04, 0x00000080 },
- { 0x000218, 2, 0x04, 0x00000100 },
- { 0x000220, 2, 0x04, 0x00000000 },
- { 0x000230, 1, 0x04, 0x000000cf },
- { 0x000234, 1, 0x04, 0x00000001 },
- { 0x000238, 1, 0x04, 0x00000020 },
- { 0x00023c, 1, 0x04, 0x00000001 },
- { 0x000244, 1, 0x04, 0x00000080 },
- { 0x000248, 2, 0x04, 0x00000100 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_9039_0[] = {
- { 0x00030c, 3, 0x04, 0x00000000 },
- { 0x000320, 1, 0x04, 0x00000000 },
- { 0x000238, 2, 0x04, 0x00000000 },
- { 0x000318, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_90c0_0[] = {
- { 0x00270c, 8, 0x20, 0x00000000 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x000758, 1, 0x04, 0x00000100 },
- { 0x0002c4, 1, 0x04, 0x00000000 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x000204, 3, 0x04, 0x00000000 },
- { 0x000214, 1, 0x04, 0x00000000 },
- { 0x00024c, 1, 0x04, 0x00000000 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x001664, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_mthd[] = {
- { nvc0_grctx_init_9097_0, 0x9097 },
- { nvc0_grctx_init_902d_0, 0x902d },
- { nvc0_grctx_init_9039_0, 0x9039 },
- { nvc0_grctx_init_90c0_0, 0x90c0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_main_0[] = {
- { 0x400204, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_fe_0[] = {
- { 0x404004, 11, 0x04, 0x00000000 },
- { 0x404044, 1, 0x04, 0x00000000 },
- { 0x404094, 13, 0x04, 0x00000000 },
- { 0x4040c8, 1, 0x04, 0xf0000087 },
- { 0x4040d0, 6, 0x04, 0x00000000 },
- { 0x4040e8, 1, 0x04, 0x00001000 },
- { 0x4040f8, 1, 0x04, 0x00000000 },
- { 0x404130, 2, 0x04, 0x00000000 },
- { 0x404138, 1, 0x04, 0x20000040 },
- { 0x404150, 1, 0x04, 0x0000002e },
- { 0x404154, 1, 0x04, 0x00000400 },
- { 0x404158, 1, 0x04, 0x00000200 },
- { 0x404164, 1, 0x04, 0x00000055 },
- { 0x404168, 1, 0x04, 0x00000000 },
- { 0x404174, 3, 0x04, 0x00000000 },
- { 0x404200, 8, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_pri_0[] = {
- { 0x404404, 14, 0x04, 0x00000000 },
- { 0x404460, 2, 0x04, 0x00000000 },
- { 0x404468, 1, 0x04, 0x00ffffff },
- { 0x40446c, 1, 0x04, 0x00000000 },
- { 0x404480, 1, 0x04, 0x00000001 },
- { 0x404498, 1, 0x04, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_memfmt_0[] = {
- { 0x404604, 1, 0x04, 0x00000015 },
- { 0x404608, 1, 0x04, 0x00000000 },
- { 0x40460c, 1, 0x04, 0x00002e00 },
- { 0x404610, 1, 0x04, 0x00000100 },
- { 0x404618, 8, 0x04, 0x00000000 },
- { 0x404638, 1, 0x04, 0x00000004 },
- { 0x40463c, 8, 0x04, 0x00000000 },
- { 0x40465c, 1, 0x04, 0x007f0100 },
- { 0x404660, 7, 0x04, 0x00000000 },
- { 0x40467c, 1, 0x04, 0x00000002 },
- { 0x404680, 8, 0x04, 0x00000000 },
- { 0x4046a0, 1, 0x04, 0x007f0080 },
- { 0x4046a4, 18, 0x04, 0x00000000 },
- { 0x4046f0, 2, 0x04, 0x00000000 },
- { 0x404700, 13, 0x04, 0x00000000 },
- { 0x404734, 1, 0x04, 0x00000100 },
- { 0x404738, 8, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x078000bf },
- { 0x405830, 1, 0x04, 0x02180000 },
- { 0x405834, 2, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x000103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b4, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_rstr2d_0[] = {
- { 0x407804, 1, 0x04, 0x00000023 },
- { 0x40780c, 1, 0x04, 0x0a418820 },
- { 0x407810, 1, 0x04, 0x062080e6 },
- { 0x407814, 1, 0x04, 0x020398a4 },
- { 0x407818, 1, 0x04, 0x0e629062 },
- { 0x40781c, 1, 0x04, 0x0a418820 },
- { 0x407820, 1, 0x04, 0x000000e6 },
- { 0x4078bc, 1, 0x04, 0x00000103 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_scc_0[] = {
- { 0x408000, 2, 0x04, 0x00000000 },
- { 0x408008, 1, 0x04, 0x00000018 },
- { 0x40800c, 2, 0x04, 0x00000000 },
- { 0x408014, 1, 0x04, 0x00000069 },
- { 0x408018, 1, 0x04, 0xe100e100 },
- { 0x408064, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x02802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x0003e00d },
- { 0x408900, 1, 0x04, 0x3080b801 },
- { 0x408904, 1, 0x04, 0x02000001 },
- { 0x408908, 1, 0x04, 0x00c80929 },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nvc0_grctx_init_fe_0 },
- { nvc0_grctx_init_pri_0 },
- { nvc0_grctx_init_memfmt_0 },
- { nvc0_grctx_init_ds_0 },
- { nvc0_grctx_init_pd_0 },
- { nvc0_grctx_init_rstr2d_0 },
- { nvc0_grctx_init_scc_0 },
- { nvc0_grctx_init_be_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gpc_unk_0[] = {
- { 0x418380, 1, 0x04, 0x00000016 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_prop_0[] = {
- { 0x418400, 1, 0x04, 0x38004e00 },
- { 0x418404, 1, 0x04, 0x71e0ffff },
- { 0x418408, 1, 0x04, 0x00000000 },
- { 0x41840c, 1, 0x04, 0x00001008 },
- { 0x418410, 1, 0x04, 0x0fff0fff },
- { 0x418414, 1, 0x04, 0x00200fff },
- { 0x418450, 6, 0x04, 0x00000000 },
- { 0x418468, 1, 0x04, 0x00000001 },
- { 0x41846c, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gpc_unk_1[] = {
- { 0x418600, 1, 0x04, 0x0000001f },
- { 0x418684, 1, 0x04, 0x0000000f },
- { 0x418700, 1, 0x04, 0x00000002 },
- { 0x418704, 1, 0x04, 0x00000080 },
- { 0x418708, 1, 0x04, 0x00000000 },
- { 0x41870c, 1, 0x04, 0x07c80000 },
- { 0x418710, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x0006860a },
- { 0x418808, 3, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00008442 },
- { 0x418830, 1, 0x04, 0x00000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x00100000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_zcull_0[] = {
- { 0x41891c, 1, 0x04, 0x00ff00ff },
- { 0x418924, 1, 0x04, 0x00000000 },
- { 0x418928, 1, 0x04, 0x00ffff00 },
- { 0x41892c, 1, 0x04, 0x0000ff00 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_crstr_0[] = {
- { 0x418b00, 1, 0x04, 0x00000000 },
- { 0x418b08, 1, 0x04, 0x0a418820 },
- { 0x418b0c, 1, 0x04, 0x062080e6 },
- { 0x418b10, 1, 0x04, 0x020398a4 },
- { 0x418b14, 1, 0x04, 0x0e629062 },
- { 0x418b18, 1, 0x04, 0x0a418820 },
- { 0x418b1c, 1, 0x04, 0x000000e6 },
- { 0x418bb8, 1, 0x04, 0x00000103 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gpm_0[] = {
- { 0x418c08, 1, 0x04, 0x00000001 },
- { 0x418c10, 8, 0x04, 0x00000000 },
- { 0x418c80, 1, 0x04, 0x20200004 },
- { 0x418c8c, 1, 0x04, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_gcc_0[] = {
- { 0x419000, 1, 0x04, 0x00000780 },
- { 0x419004, 2, 0x04, 0x00000000 },
- { 0x419014, 1, 0x04, 0x00000004 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvc0_grctx_init_prop_0 },
- { nvc0_grctx_init_gpc_unk_1 },
- { nvc0_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvc0_grctx_init_crstr_0 },
- { nvc0_grctx_init_gpm_0 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_zcullr_0[] = {
- { 0x418a00, 3, 0x04, 0x00000000 },
- { 0x418a0c, 1, 0x04, 0x00010000 },
- { 0x418a10, 3, 0x04, 0x00000000 },
- { 0x418a20, 3, 0x04, 0x00000000 },
- { 0x418a2c, 1, 0x04, 0x00010000 },
- { 0x418a30, 3, 0x04, 0x00000000 },
- { 0x418a40, 3, 0x04, 0x00000000 },
- { 0x418a4c, 1, 0x04, 0x00010000 },
- { 0x418a50, 3, 0x04, 0x00000000 },
- { 0x418a60, 3, 0x04, 0x00000000 },
- { 0x418a6c, 1, 0x04, 0x00010000 },
- { 0x418a70, 3, 0x04, 0x00000000 },
- { 0x418a80, 3, 0x04, 0x00000000 },
- { 0x418a8c, 1, 0x04, 0x00010000 },
- { 0x418a90, 3, 0x04, 0x00000000 },
- { 0x418aa0, 3, 0x04, 0x00000000 },
- { 0x418aac, 1, 0x04, 0x00010000 },
- { 0x418ab0, 3, 0x04, 0x00000000 },
- { 0x418ac0, 3, 0x04, 0x00000000 },
- { 0x418acc, 1, 0x04, 0x00010000 },
- { 0x418ad0, 3, 0x04, 0x00000000 },
- { 0x418ae0, 3, 0x04, 0x00000000 },
- { 0x418aec, 1, 0x04, 0x00010000 },
- { 0x418af0, 3, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_zcull[] = {
- { nvc0_grctx_init_zcullr_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_pe_0[] = {
- { 0x419818, 1, 0x04, 0x00000000 },
- { 0x41983c, 1, 0x04, 0x00038bc7 },
- { 0x419848, 1, 0x04, 0x00000000 },
- { 0x419864, 1, 0x04, 0x0000012a },
- { 0x419888, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000001f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000023 },
- { 0x419a0c, 1, 0x04, 0x00020000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_wwdx_0[] = {
- { 0x419b00, 1, 0x04, 0x0a418820 },
- { 0x419b04, 1, 0x04, 0x062080e6 },
- { 0x419b08, 1, 0x04, 0x020398a4 },
- { 0x419b0c, 1, 0x04, 0x0e629062 },
- { 0x419b10, 1, 0x04, 0x0a418820 },
- { 0x419b14, 1, 0x04, 0x000000e6 },
- { 0x419bd0, 1, 0x04, 0x00900103 },
- { 0x419be0, 1, 0x04, 0x00000001 },
- { 0x419be4, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_mpc_0[] = {
- { 0x419c00, 1, 0x04, 0x00000002 },
- { 0x419c04, 1, 0x04, 0x00000006 },
- { 0x419c08, 1, 0x04, 0x00000002 },
- { 0x419c20, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_l1c_0[] = {
- { 0x419cb0, 1, 0x04, 0x00060048 },
- { 0x419ce8, 1, 0x04, 0x00000000 },
- { 0x419cf4, 1, 0x04, 0x00000183 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_grctx_init_tpccs_0[] = {
- { 0x419d20, 1, 0x04, 0x02180000 },
- { 0x419d24, 1, 0x04, 0x00001fff },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_grctx_init_sm_0[] = {
- { 0x419e04, 3, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00000002 },
- { 0x419e44, 1, 0x04, 0x001beff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000000f },
- { 0x419e50, 17, 0x04, 0x00000000 },
- { 0x419e98, 1, 0x04, 0x00000000 },
- { 0x419f50, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvc0_grctx_pack_tpc[] = {
- { nvc0_grctx_init_pe_0 },
- { nvc0_grctx_init_tex_0 },
- { nvc0_grctx_init_wwdx_0 },
- { nvc0_grctx_init_mpc_0 },
- { nvc0_grctx_init_l1c_0 },
- { nvc0_grctx_init_tpccs_0 },
- { nvc0_grctx_init_sm_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-int
-nvc0_grctx_mmio_data(struct nvc0_grctx *info, u32 size, u32 align, u32 access)
-{
- if (info->data) {
- info->buffer[info->buffer_nr] = round_up(info->addr, align);
- info->addr = info->buffer[info->buffer_nr] + size;
- info->data->size = size;
- info->data->align = align;
- info->data->access = access;
- info->data++;
- return info->buffer_nr++;
- }
- return -1;
-}
-
-void
-nvc0_grctx_mmio_item(struct nvc0_grctx *info, u32 addr, u32 data,
- int shift, int buffer)
-{
- if (info->data) {
- if (shift >= 0) {
- info->mmio->addr = addr;
- info->mmio->data = data;
- info->mmio->shift = shift;
- info->mmio->buffer = buffer;
- if (buffer >= 0)
- data |= info->buffer[buffer] >> shift;
- info->mmio++;
- } else
- return;
- } else {
- if (buffer >= 0)
- return;
- }
-
- nv_wr32(info->priv, addr, data);
-}
-
-void
-nvc0_grctx_generate_bundle(struct nvc0_grctx *info)
-{
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
- const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
- const int s = 8;
- const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
- mmio_refn(info, 0x408004, 0x00000000, s, b);
- mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
- mmio_refn(info, 0x418808, 0x00000000, s, b);
- mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
-}
-
-void
-nvc0_grctx_generate_pagepool(struct nvc0_grctx *info)
-{
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
- const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
- const int s = 8;
- const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x80000000);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
-}
-
-void
-nvc0_grctx_generate_attrib(struct nvc0_grctx *info)
-{
- struct nvc0_graph_priv *priv = info->priv;
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv);
- const u32 attrib = impl->attrib_nr;
- const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
- const u32 access = NV_MEM_ACCESS_RW;
- const int s = 12;
- const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
- int gpc, tpc;
- u32 bo = 0;
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (attrib << 16));
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- const u32 o = TPC_UNIT(gpc, tpc, 0x0520);
- mmio_skip(info, o, (attrib << 16) | ++bo);
- mmio_wr32(info, o, (attrib << 16) | --bo);
- bo += impl->attrib_nr_max;
- }
- }
-}
-
-void
-nvc0_grctx_generate_unkn(struct nvc0_graph_priv *priv)
-{
-}
-
-void
-nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *priv)
-{
- int gpc, tpc, id;
-
- for (tpc = 0, id = 0; tpc < 4; tpc++) {
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- if (tpc < priv->tpc_nr[gpc]) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
- id++;
- }
-
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
- }
- }
-}
-
-void
-nvc0_grctx_generate_r406028(struct nvc0_graph_priv *priv)
-{
- u32 tmp[GPC_MAX / 8] = {}, i = 0;
- for (i = 0; i < priv->gpc_nr; i++)
- tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4);
- for (i = 0; i < 4; i++) {
- nv_wr32(priv, 0x406028 + (i * 4), tmp[i]);
- nv_wr32(priv, 0x405870 + (i * 4), tmp[i]);
- }
-}
-
-void
-nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *priv)
-{
- u8 tpcnr[GPC_MAX], data[TPC_MAX];
- int gpc, tpc, i;
-
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- memset(data, 0x1f, sizeof(data));
-
- gpc = -1;
- for (tpc = 0; tpc < priv->tpc_total; tpc++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpcnr[gpc]--;
- data[tpc] = gpc;
- }
-
- for (i = 0; i < 4; i++)
- nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
-}
-
-void
-nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
-{
- u32 data[6] = {}, data2[2] = {};
- u8 tpcnr[GPC_MAX];
- u8 shift, ntpcv;
- int gpc, tpc, i;
-
- /* calculate first set of magics */
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
- gpc = -1;
- for (tpc = 0; tpc < priv->tpc_total; tpc++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpcnr[gpc]--;
-
- data[tpc / 6] |= gpc << ((tpc % 6) * 5);
- }
-
- for (; tpc < 32; tpc++)
- data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
- /* and the second... */
- shift = 0;
- ntpcv = priv->tpc_total;
- while (!(ntpcv & (1 << 4))) {
- ntpcv <<= 1;
- shift++;
- }
-
- data2[0] = (ntpcv << 16);
- data2[0] |= (shift << 21);
- data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
- for (i = 1; i < 7; i++)
- data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
- /* GPC_BROADCAST */
- nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
- /* GPC_BROADCAST.TP_BROADCAST */
- nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr | data2[0]);
- nv_wr32(priv, 0x419be4, data2[1]);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
-
- /* UNK78xx */
- nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-}
-
-void
-nvc0_grctx_generate_r406800(struct nvc0_graph_priv *priv)
-{
- u64 tpc_mask = 0, tpc_set = 0;
- u8 tpcnr[GPC_MAX];
- int gpc, tpc;
- int i, a, b;
-
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (gpc = 0; gpc < priv->gpc_nr; gpc++)
- tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
-
- for (i = 0, gpc = -1, b = -1; i < 32; i++) {
- a = (i * (priv->tpc_total - 1)) / 32;
- if (a != b) {
- b = a;
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- tpc_set |= 1ULL << ((gpc * 8) + tpc);
- }
-
- nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
- nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask));
- if (priv->gpc_nr > 4) {
- nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set));
- nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask));
- }
- }
-}
-
-void
-nvc0_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
- struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
-
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-
- nvc0_graph_mmio(priv, oclass->hub);
- nvc0_graph_mmio(priv, oclass->gpc);
- nvc0_graph_mmio(priv, oclass->zcull);
- nvc0_graph_mmio(priv, oclass->tpc);
- nvc0_graph_mmio(priv, oclass->ppc);
-
- nv_wr32(priv, 0x404154, 0x00000000);
-
- oclass->bundle(info);
- oclass->pagepool(info);
- oclass->attrib(info);
- oclass->unkn(priv);
-
- nvc0_grctx_generate_tpcid(priv);
- nvc0_grctx_generate_r406028(priv);
- nvc0_grctx_generate_r4060a8(priv);
- nvc0_grctx_generate_r418bb8(priv);
- nvc0_grctx_generate_r406800(priv);
-
- nvc0_graph_icmd(priv, oclass->icmd);
- nv_wr32(priv, 0x404154, 0x00000400);
- nvc0_graph_mthd(priv, oclass->mthd);
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-}
-
-int
-nvc0_grctx_generate(struct nvc0_graph_priv *priv)
-{
- struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nouveau_gpuobj *chan;
- struct nvc0_grctx info;
- int ret, i;
-
- /* allocate memory to for a "channel", which we'll use to generate
- * the default context values
- */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size,
- 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- if (ret) {
- nv_error(priv, "failed to allocate channel memory, %d\n", ret);
- return ret;
- }
-
- /* PGD pointer */
- nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000));
- nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000));
- nv_wo32(chan, 0x0208, 0xffffffff);
- nv_wo32(chan, 0x020c, 0x000000ff);
-
- /* PGT[0] pointer */
- nv_wo32(chan, 0x1000, 0x00000000);
- nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
-
- /* identity-map the whole "channel" into its own vm */
- for (i = 0; i < chan->size / 4096; i++) {
- u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
- nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
- nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
- }
-
- /* context pointer (virt) */
- nv_wo32(chan, 0x0210, 0x00080004);
- nv_wo32(chan, 0x0214, 0x00000000);
-
- bar->flush(bar);
-
- nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
- nv_wr32(priv, 0x100cbc, 0x80000001);
- nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
-
- /* setup default state for mmio list construction */
- info.priv = priv;
- info.data = priv->mmio_data;
- info.mmio = priv->mmio_list;
- info.addr = 0x2000 + (i * 8);
- info.buffer_nr = 0;
-
- /* make channel current */
- if (priv->firmware) {
- nv_wr32(priv, 0x409840, 0x00000030);
- nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
- nv_wr32(priv, 0x409504, 0x00000003);
- if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
- nv_error(priv, "load_ctx timeout\n");
-
- nv_wo32(chan, 0x8001c, 1);
- nv_wo32(chan, 0x80020, 0);
- nv_wo32(chan, 0x80028, 0);
- nv_wo32(chan, 0x8002c, 0);
- bar->flush(bar);
- } else {
- nv_wr32(priv, 0x409840, 0x80000000);
- nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
- nv_wr32(priv, 0x409504, 0x00000001);
- if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000))
- nv_error(priv, "HUB_SET_CHAN timeout\n");
- }
-
- oclass->main(priv, &info);
-
- /* trigger a context unload by unsetting the "next channel valid" bit
- * and faking a context switch interrupt
- */
- nv_mask(priv, 0x409b04, 0x80000000, 0x00000000);
- nv_wr32(priv, 0x409000, 0x00000100);
- if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
- nv_error(priv, "grctx template channel unload timeout\n");
- ret = -EBUSY;
- goto done;
- }
-
- priv->data = kmalloc(priv->size, GFP_KERNEL);
- if (priv->data) {
- for (i = 0; i < priv->size; i += 4)
- priv->data[i / 4] = nv_ro32(chan, 0x80000 + i);
- ret = 0;
- } else {
- ret = -ENOMEM;
- }
-
-done:
- nouveau_gpuobj_ref(NULL, &chan);
- return ret;
-}
-
-struct nouveau_oclass *
-nvc0_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nvc0_grctx_generate_main,
- .unkn = nvc0_grctx_generate_unkn,
- .hub = nvc0_grctx_pack_hub,
- .gpc = nvc0_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvc0_grctx_pack_tpc,
- .icmd = nvc0_grctx_pack_icmd,
- .mthd = nvc0_grctx_pack_mthd,
- .bundle = nvc0_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .pagepool = nvc0_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvc0_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h
deleted file mode 100644
index c776cd715e33..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc0.h
+++ /dev/null
@@ -1,202 +0,0 @@
-#ifndef __NVKM_GRCTX_NVC0_H__
-#define __NVKM_GRCTX_NVC0_H__
-
-#include "nvc0.h"
-
-struct nvc0_grctx {
- struct nvc0_graph_priv *priv;
- struct nvc0_graph_data *data;
- struct nvc0_graph_mmio *mmio;
- int buffer_nr;
- u64 buffer[4];
- u64 addr;
-};
-
-int nvc0_grctx_mmio_data(struct nvc0_grctx *, u32 size, u32 align, u32 access);
-void nvc0_grctx_mmio_item(struct nvc0_grctx *, u32 addr, u32 data, int s, int);
-
-#define mmio_vram(a,b,c,d) nvc0_grctx_mmio_data((a), (b), (c), (d))
-#define mmio_refn(a,b,c,d,e) nvc0_grctx_mmio_item((a), (b), (c), (d), (e))
-#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1)
-#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1)
-
-struct nvc0_grctx_oclass {
- struct nouveau_oclass base;
- /* main context generation function */
- void (*main)(struct nvc0_graph_priv *, struct nvc0_grctx *);
- /* context-specific modify-on-first-load list generation function */
- void (*unkn)(struct nvc0_graph_priv *);
- /* mmio context data */
- const struct nvc0_graph_pack *hub;
- const struct nvc0_graph_pack *gpc;
- const struct nvc0_graph_pack *zcull;
- const struct nvc0_graph_pack *tpc;
- const struct nvc0_graph_pack *ppc;
- /* indirect context data, generated with icmds/mthds */
- const struct nvc0_graph_pack *icmd;
- const struct nvc0_graph_pack *mthd;
- /* bundle circular buffer */
- void (*bundle)(struct nvc0_grctx *);
- u32 bundle_size;
- u32 bundle_min_gpm_fifo_depth;
- u32 bundle_token_limit;
- /* pagepool */
- void (*pagepool)(struct nvc0_grctx *);
- u32 pagepool_size;
- /* attribute(/alpha) circular buffer */
- void (*attrib)(struct nvc0_grctx *);
- u32 attrib_nr_max;
- u32 attrib_nr;
- u32 alpha_nr_max;
- u32 alpha_nr;
-};
-
-static inline const struct nvc0_grctx_oclass *
-nvc0_grctx_impl(struct nvc0_graph_priv *priv)
-{
- return (void *)nv_engine(priv)->cclass;
-}
-
-extern struct nouveau_oclass *nvc0_grctx_oclass;
-int nvc0_grctx_generate(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nvc0_grctx_generate_bundle(struct nvc0_grctx *);
-void nvc0_grctx_generate_pagepool(struct nvc0_grctx *);
-void nvc0_grctx_generate_attrib(struct nvc0_grctx *);
-void nvc0_grctx_generate_unkn(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_tpcid(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r406028(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r4060a8(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r418bb8(struct nvc0_graph_priv *);
-void nvc0_grctx_generate_r406800(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvc1_grctx_oclass;
-void nvc1_grctx_generate_attrib(struct nvc0_grctx *);
-void nvc1_grctx_generate_unkn(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvc4_grctx_oclass;
-extern struct nouveau_oclass *nvc8_grctx_oclass;
-
-extern struct nouveau_oclass *nvd7_grctx_oclass;
-void nvd7_grctx_generate_attrib(struct nvc0_grctx *);
-
-extern struct nouveau_oclass *nvd9_grctx_oclass;
-
-extern struct nouveau_oclass *nve4_grctx_oclass;
-extern struct nouveau_oclass *gk20a_grctx_oclass;
-void nve4_grctx_generate_main(struct nvc0_graph_priv *, struct nvc0_grctx *);
-void nve4_grctx_generate_bundle(struct nvc0_grctx *);
-void nve4_grctx_generate_pagepool(struct nvc0_grctx *);
-void nve4_grctx_generate_unkn(struct nvc0_graph_priv *);
-void nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *);
-
-extern struct nouveau_oclass *nvf0_grctx_oclass;
-extern struct nouveau_oclass *gk110b_grctx_oclass;
-extern struct nouveau_oclass *nv108_grctx_oclass;
-extern struct nouveau_oclass *gm107_grctx_oclass;
-
-/* context init value lists */
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_icmd[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_mthd[];
-extern const struct nvc0_graph_init nvc0_grctx_init_902d_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_9039_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_90c0_0[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_hub[];
-extern const struct nvc0_graph_init nvc0_grctx_init_main_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_fe_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_pri_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_memfmt_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_rstr2d_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_scc_0[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_gpc[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_prop_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvc0_grctx_init_zcull_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_crstr_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gpm_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_gcc_0[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_zcull[];
-
-extern const struct nvc0_graph_pack nvc0_grctx_pack_tpc[];
-extern const struct nvc0_graph_init nvc0_grctx_init_pe_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_wwdx_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_mpc_0[];
-extern const struct nvc0_graph_init nvc0_grctx_init_tpccs_0[];
-
-extern const struct nvc0_graph_init nvc4_grctx_init_tex_0[];
-extern const struct nvc0_graph_init nvc4_grctx_init_l1c_0[];
-extern const struct nvc0_graph_init nvc4_grctx_init_sm_0[];
-
-extern const struct nvc0_graph_init nvc1_grctx_init_9097_0[];
-
-extern const struct nvc0_graph_init nvc1_grctx_init_gpm_0[];
-
-extern const struct nvc0_graph_init nvc1_grctx_init_pe_0[];
-extern const struct nvc0_graph_init nvc1_grctx_init_wwdx_0[];
-extern const struct nvc0_graph_init nvc1_grctx_init_tpccs_0[];
-
-extern const struct nvc0_graph_init nvc8_grctx_init_9197_0[];
-extern const struct nvc0_graph_init nvc8_grctx_init_9297_0[];
-
-extern const struct nvc0_graph_pack nvd9_grctx_pack_icmd[];
-
-extern const struct nvc0_graph_pack nvd9_grctx_pack_mthd[];
-
-extern const struct nvc0_graph_init nvd9_grctx_init_fe_0[];
-extern const struct nvc0_graph_init nvd9_grctx_init_be_0[];
-
-extern const struct nvc0_graph_init nvd9_grctx_init_prop_0[];
-extern const struct nvc0_graph_init nvd9_grctx_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvd9_grctx_init_crstr_0[];
-
-extern const struct nvc0_graph_init nvd9_grctx_init_sm_0[];
-
-extern const struct nvc0_graph_init nvd7_grctx_init_pe_0[];
-
-extern const struct nvc0_graph_init nvd7_grctx_init_wwdx_0[];
-
-extern const struct nvc0_graph_init nve4_grctx_init_memfmt_0[];
-extern const struct nvc0_graph_init nve4_grctx_init_ds_0[];
-extern const struct nvc0_graph_init nve4_grctx_init_scc_0[];
-
-extern const struct nvc0_graph_init nve4_grctx_init_gpm_0[];
-
-extern const struct nvc0_graph_init nve4_grctx_init_pes_0[];
-
-extern const struct nvc0_graph_pack nve4_grctx_pack_hub[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_gpc[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_tpc[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_ppc[];
-extern const struct nvc0_graph_pack nve4_grctx_pack_icmd[];
-extern const struct nvc0_graph_init nve4_grctx_init_a097_0[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_icmd[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_mthd[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_hub[];
-extern const struct nvc0_graph_init nvf0_grctx_init_pri_0[];
-extern const struct nvc0_graph_init nvf0_grctx_init_cwd_0[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_gpc[];
-extern const struct nvc0_graph_init nvf0_grctx_init_gpc_unk_2[];
-
-extern const struct nvc0_graph_init nvf0_grctx_init_tex_0[];
-extern const struct nvc0_graph_init nvf0_grctx_init_mpc_0[];
-extern const struct nvc0_graph_init nvf0_grctx_init_l1c_0[];
-
-extern const struct nvc0_graph_pack nvf0_grctx_pack_ppc[];
-
-extern const struct nvc0_graph_init nv108_grctx_init_rstr2d_0[];
-
-extern const struct nvc0_graph_init nv108_grctx_init_prop_0[];
-extern const struct nvc0_graph_init nv108_grctx_init_crstr_0[];
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
deleted file mode 100644
index c6ba8fed18f1..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc1.c
+++ /dev/null
@@ -1,805 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000b2, 40, 0x01, 0x00000000 },
- { 0x000210, 8, 0x01, 0x00000040 },
- { 0x000218, 8, 0x01, 0x0000c080 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00001fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x003fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x0005e0, 5, 0x01, 0x00000022 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x00000c48 },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00300008 },
- { 0x000841, 1, 0x01, 0x04000080 },
- { 0x000842, 1, 0x01, 0x00300008 },
- { 0x000843, 1, 0x01, 0x04000080 },
- { 0x000818, 8, 0x01, 0x00000000 },
- { 0x000848, 16, 0x01, 0x00000000 },
- { 0x000738, 1, 0x01, 0x00000000 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x000944, 1, 0x01, 0x00000022 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000014 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_icmd[] = {
- { nvc1_grctx_init_icmd_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_9097_0[] = {
- { 0x000800, 8, 0x40, 0x00000000 },
- { 0x000804, 8, 0x40, 0x00000000 },
- { 0x000808, 8, 0x40, 0x00000400 },
- { 0x00080c, 8, 0x40, 0x00000300 },
- { 0x000810, 1, 0x04, 0x000000cf },
- { 0x000850, 7, 0x40, 0x00000000 },
- { 0x000814, 8, 0x40, 0x00000040 },
- { 0x000818, 8, 0x40, 0x00000001 },
- { 0x00081c, 8, 0x40, 0x00000000 },
- { 0x000820, 8, 0x40, 0x00000000 },
- { 0x002700, 8, 0x20, 0x00000000 },
- { 0x002704, 8, 0x20, 0x00000000 },
- { 0x002708, 8, 0x20, 0x00000000 },
- { 0x00270c, 8, 0x20, 0x00000000 },
- { 0x002710, 8, 0x20, 0x00014000 },
- { 0x002714, 8, 0x20, 0x00000040 },
- { 0x001c00, 16, 0x10, 0x00000000 },
- { 0x001c04, 16, 0x10, 0x00000000 },
- { 0x001c08, 16, 0x10, 0x00000000 },
- { 0x001c0c, 16, 0x10, 0x00000000 },
- { 0x001d00, 16, 0x10, 0x00000000 },
- { 0x001d04, 16, 0x10, 0x00000000 },
- { 0x001d08, 16, 0x10, 0x00000000 },
- { 0x001d0c, 16, 0x10, 0x00000000 },
- { 0x001f00, 16, 0x08, 0x00000000 },
- { 0x001f04, 16, 0x08, 0x00000000 },
- { 0x001f80, 16, 0x08, 0x00000000 },
- { 0x001f84, 16, 0x08, 0x00000000 },
- { 0x002200, 5, 0x10, 0x00000022 },
- { 0x002000, 1, 0x04, 0x00000000 },
- { 0x002040, 1, 0x04, 0x00000011 },
- { 0x002080, 1, 0x04, 0x00000020 },
- { 0x0020c0, 1, 0x04, 0x00000030 },
- { 0x002100, 1, 0x04, 0x00000040 },
- { 0x002140, 1, 0x04, 0x00000051 },
- { 0x00200c, 6, 0x40, 0x00000001 },
- { 0x002010, 1, 0x04, 0x00000000 },
- { 0x002050, 1, 0x04, 0x00000000 },
- { 0x002090, 1, 0x04, 0x00000001 },
- { 0x0020d0, 1, 0x04, 0x00000002 },
- { 0x002110, 1, 0x04, 0x00000003 },
- { 0x002150, 1, 0x04, 0x00000004 },
- { 0x000380, 4, 0x20, 0x00000000 },
- { 0x000384, 4, 0x20, 0x00000000 },
- { 0x000388, 4, 0x20, 0x00000000 },
- { 0x00038c, 4, 0x20, 0x00000000 },
- { 0x000700, 4, 0x10, 0x00000000 },
- { 0x000704, 4, 0x10, 0x00000000 },
- { 0x000708, 4, 0x10, 0x00000000 },
- { 0x002800, 128, 0x04, 0x00000000 },
- { 0x000a00, 16, 0x20, 0x00000000 },
- { 0x000a04, 16, 0x20, 0x00000000 },
- { 0x000a08, 16, 0x20, 0x00000000 },
- { 0x000a0c, 16, 0x20, 0x00000000 },
- { 0x000a10, 16, 0x20, 0x00000000 },
- { 0x000a14, 16, 0x20, 0x00000000 },
- { 0x000c00, 16, 0x10, 0x00000000 },
- { 0x000c04, 16, 0x10, 0x00000000 },
- { 0x000c08, 16, 0x10, 0x00000000 },
- { 0x000c0c, 16, 0x10, 0x3f800000 },
- { 0x000d00, 8, 0x08, 0xffff0000 },
- { 0x000d04, 8, 0x08, 0xffff0000 },
- { 0x000e00, 16, 0x10, 0x00000000 },
- { 0x000e04, 16, 0x10, 0xffff0000 },
- { 0x000e08, 16, 0x10, 0xffff0000 },
- { 0x000d40, 4, 0x08, 0x00000000 },
- { 0x000d44, 4, 0x08, 0x00000000 },
- { 0x001e00, 8, 0x20, 0x00000001 },
- { 0x001e04, 8, 0x20, 0x00000001 },
- { 0x001e08, 8, 0x20, 0x00000002 },
- { 0x001e0c, 8, 0x20, 0x00000001 },
- { 0x001e10, 8, 0x20, 0x00000001 },
- { 0x001e14, 8, 0x20, 0x00000002 },
- { 0x001e18, 8, 0x20, 0x00000001 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x001514, 1, 0x04, 0x00000000 },
- { 0x000d68, 1, 0x04, 0x0000ffff },
- { 0x00121c, 1, 0x04, 0x0fac6881 },
- { 0x000fac, 1, 0x04, 0x00000001 },
- { 0x001538, 1, 0x04, 0x00000001 },
- { 0x000fe0, 2, 0x04, 0x00000000 },
- { 0x000fe8, 1, 0x04, 0x00000014 },
- { 0x000fec, 1, 0x04, 0x00000040 },
- { 0x000ff0, 1, 0x04, 0x00000000 },
- { 0x00179c, 1, 0x04, 0x00000000 },
- { 0x001228, 1, 0x04, 0x00000400 },
- { 0x00122c, 1, 0x04, 0x00000300 },
- { 0x001230, 1, 0x04, 0x00010001 },
- { 0x0007f8, 1, 0x04, 0x00000000 },
- { 0x0015b4, 1, 0x04, 0x00000001 },
- { 0x0015cc, 1, 0x04, 0x00000000 },
- { 0x001534, 1, 0x04, 0x00000000 },
- { 0x000fb0, 1, 0x04, 0x00000000 },
- { 0x0015d0, 1, 0x04, 0x00000000 },
- { 0x00153c, 1, 0x04, 0x00000000 },
- { 0x0016b4, 1, 0x04, 0x00000003 },
- { 0x000fbc, 4, 0x04, 0x0000ffff },
- { 0x000df8, 2, 0x04, 0x00000000 },
- { 0x001948, 1, 0x04, 0x00000000 },
- { 0x001970, 1, 0x04, 0x00000001 },
- { 0x00161c, 1, 0x04, 0x000009f0 },
- { 0x000dcc, 1, 0x04, 0x00000010 },
- { 0x00163c, 1, 0x04, 0x00000000 },
- { 0x0015e4, 1, 0x04, 0x00000000 },
- { 0x001160, 32, 0x04, 0x25e00040 },
- { 0x001880, 32, 0x04, 0x00000000 },
- { 0x000f84, 2, 0x04, 0x00000000 },
- { 0x0017c8, 2, 0x04, 0x00000000 },
- { 0x0017d0, 1, 0x04, 0x000000ff },
- { 0x0017d4, 1, 0x04, 0xffffffff },
- { 0x0017d8, 1, 0x04, 0x00000002 },
- { 0x0017dc, 1, 0x04, 0x00000000 },
- { 0x0015f4, 2, 0x04, 0x00000000 },
- { 0x001434, 2, 0x04, 0x00000000 },
- { 0x000d74, 1, 0x04, 0x00000000 },
- { 0x000dec, 1, 0x04, 0x00000001 },
- { 0x0013a4, 1, 0x04, 0x00000000 },
- { 0x001318, 1, 0x04, 0x00000001 },
- { 0x001644, 1, 0x04, 0x00000000 },
- { 0x000748, 1, 0x04, 0x00000000 },
- { 0x000de8, 1, 0x04, 0x00000000 },
- { 0x001648, 1, 0x04, 0x00000000 },
- { 0x0012a4, 1, 0x04, 0x00000000 },
- { 0x001120, 4, 0x04, 0x00000000 },
- { 0x001118, 1, 0x04, 0x00000000 },
- { 0x00164c, 1, 0x04, 0x00000000 },
- { 0x001658, 1, 0x04, 0x00000000 },
- { 0x001910, 1, 0x04, 0x00000290 },
- { 0x001518, 1, 0x04, 0x00000000 },
- { 0x00165c, 1, 0x04, 0x00000001 },
- { 0x001520, 1, 0x04, 0x00000000 },
- { 0x001604, 1, 0x04, 0x00000000 },
- { 0x001570, 1, 0x04, 0x00000000 },
- { 0x0013b0, 2, 0x04, 0x3f800000 },
- { 0x00020c, 1, 0x04, 0x00000000 },
- { 0x001670, 1, 0x04, 0x30201000 },
- { 0x001674, 1, 0x04, 0x70605040 },
- { 0x001678, 1, 0x04, 0xb8a89888 },
- { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
- { 0x00166c, 1, 0x04, 0x00000000 },
- { 0x001680, 1, 0x04, 0x00ffff00 },
- { 0x0012d0, 1, 0x04, 0x00000003 },
- { 0x0012d4, 1, 0x04, 0x00000002 },
- { 0x001684, 2, 0x04, 0x00000000 },
- { 0x000dac, 2, 0x04, 0x00001b02 },
- { 0x000db4, 1, 0x04, 0x00000000 },
- { 0x00168c, 1, 0x04, 0x00000000 },
- { 0x0015bc, 1, 0x04, 0x00000000 },
- { 0x00156c, 1, 0x04, 0x00000000 },
- { 0x00187c, 1, 0x04, 0x00000000 },
- { 0x001110, 1, 0x04, 0x00000001 },
- { 0x000dc0, 3, 0x04, 0x00000000 },
- { 0x001234, 1, 0x04, 0x00000000 },
- { 0x001690, 1, 0x04, 0x00000000 },
- { 0x0012ac, 1, 0x04, 0x00000001 },
- { 0x0002c4, 1, 0x04, 0x00000000 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x001000, 1, 0x04, 0x00000010 },
- { 0x0010fc, 1, 0x04, 0x00000000 },
- { 0x001290, 1, 0x04, 0x00000000 },
- { 0x000218, 1, 0x04, 0x00000010 },
- { 0x0012d8, 1, 0x04, 0x00000000 },
- { 0x0012dc, 1, 0x04, 0x00000010 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x00155c, 2, 0x04, 0x00000000 },
- { 0x001564, 1, 0x04, 0x00001fff },
- { 0x001574, 2, 0x04, 0x00000000 },
- { 0x00157c, 1, 0x04, 0x003fffff },
- { 0x001354, 1, 0x04, 0x00000000 },
- { 0x001664, 1, 0x04, 0x00000000 },
- { 0x001610, 1, 0x04, 0x00000012 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x00162c, 1, 0x04, 0x00000003 },
- { 0x000210, 1, 0x04, 0x00000000 },
- { 0x000320, 1, 0x04, 0x00000000 },
- { 0x000324, 6, 0x04, 0x3f800000 },
- { 0x000750, 1, 0x04, 0x00000000 },
- { 0x000760, 1, 0x04, 0x39291909 },
- { 0x000764, 1, 0x04, 0x79695949 },
- { 0x000768, 1, 0x04, 0xb9a99989 },
- { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
- { 0x000770, 1, 0x04, 0x30201000 },
- { 0x000774, 1, 0x04, 0x70605040 },
- { 0x000778, 1, 0x04, 0x00009080 },
- { 0x000780, 1, 0x04, 0x39291909 },
- { 0x000784, 1, 0x04, 0x79695949 },
- { 0x000788, 1, 0x04, 0xb9a99989 },
- { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
- { 0x0007d0, 1, 0x04, 0x30201000 },
- { 0x0007d4, 1, 0x04, 0x70605040 },
- { 0x0007d8, 1, 0x04, 0x00009080 },
- { 0x00037c, 1, 0x04, 0x00000001 },
- { 0x000740, 2, 0x04, 0x00000000 },
- { 0x002600, 1, 0x04, 0x00000000 },
- { 0x001918, 1, 0x04, 0x00000000 },
- { 0x00191c, 1, 0x04, 0x00000900 },
- { 0x001920, 1, 0x04, 0x00000405 },
- { 0x001308, 1, 0x04, 0x00000001 },
- { 0x001924, 1, 0x04, 0x00000000 },
- { 0x0013ac, 1, 0x04, 0x00000000 },
- { 0x00192c, 1, 0x04, 0x00000001 },
- { 0x00193c, 1, 0x04, 0x00002c1c },
- { 0x000d7c, 1, 0x04, 0x00000000 },
- { 0x000f8c, 1, 0x04, 0x00000000 },
- { 0x0002c0, 1, 0x04, 0x00000001 },
- { 0x001510, 1, 0x04, 0x00000000 },
- { 0x001940, 1, 0x04, 0x00000000 },
- { 0x000ff4, 2, 0x04, 0x00000000 },
- { 0x00194c, 2, 0x04, 0x00000000 },
- { 0x001968, 1, 0x04, 0x00000000 },
- { 0x001590, 1, 0x04, 0x0000003f },
- { 0x0007e8, 4, 0x04, 0x00000000 },
- { 0x00196c, 1, 0x04, 0x00000011 },
- { 0x00197c, 1, 0x04, 0x00000000 },
- { 0x000fcc, 2, 0x04, 0x00000000 },
- { 0x0002d8, 1, 0x04, 0x00000040 },
- { 0x001980, 1, 0x04, 0x00000080 },
- { 0x001504, 1, 0x04, 0x00000080 },
- { 0x001984, 1, 0x04, 0x00000000 },
- { 0x000300, 1, 0x04, 0x00000001 },
- { 0x0013a8, 1, 0x04, 0x00000000 },
- { 0x0012ec, 1, 0x04, 0x00000000 },
- { 0x001310, 1, 0x04, 0x00000000 },
- { 0x001314, 1, 0x04, 0x00000001 },
- { 0x001380, 1, 0x04, 0x00000000 },
- { 0x001384, 4, 0x04, 0x00000001 },
- { 0x001394, 1, 0x04, 0x00000000 },
- { 0x00139c, 1, 0x04, 0x00000000 },
- { 0x001398, 1, 0x04, 0x00000000 },
- { 0x001594, 1, 0x04, 0x00000000 },
- { 0x001598, 4, 0x04, 0x00000001 },
- { 0x000f54, 3, 0x04, 0x00000000 },
- { 0x0019bc, 1, 0x04, 0x00000000 },
- { 0x000f9c, 2, 0x04, 0x00000000 },
- { 0x0012cc, 1, 0x04, 0x00000000 },
- { 0x0012e8, 1, 0x04, 0x00000000 },
- { 0x00130c, 1, 0x04, 0x00000001 },
- { 0x001360, 8, 0x04, 0x00000000 },
- { 0x00133c, 2, 0x04, 0x00000001 },
- { 0x001344, 1, 0x04, 0x00000002 },
- { 0x001348, 2, 0x04, 0x00000001 },
- { 0x001350, 1, 0x04, 0x00000002 },
- { 0x001358, 1, 0x04, 0x00000001 },
- { 0x0012e4, 1, 0x04, 0x00000000 },
- { 0x00131c, 4, 0x04, 0x00000000 },
- { 0x0019c0, 1, 0x04, 0x00000000 },
- { 0x001140, 1, 0x04, 0x00000000 },
- { 0x0019c4, 1, 0x04, 0x00000000 },
- { 0x0019c8, 1, 0x04, 0x00001500 },
- { 0x00135c, 1, 0x04, 0x00000000 },
- { 0x000f90, 1, 0x04, 0x00000000 },
- { 0x0019e0, 8, 0x04, 0x00000001 },
- { 0x0019cc, 1, 0x04, 0x00000001 },
- { 0x0015b8, 1, 0x04, 0x00000000 },
- { 0x001a00, 1, 0x04, 0x00001111 },
- { 0x001a04, 7, 0x04, 0x00000000 },
- { 0x000d6c, 2, 0x04, 0xffff0000 },
- { 0x0010f8, 1, 0x04, 0x00001010 },
- { 0x000d80, 5, 0x04, 0x00000000 },
- { 0x000da0, 1, 0x04, 0x00000000 },
- { 0x001508, 1, 0x04, 0x80000000 },
- { 0x00150c, 1, 0x04, 0x40000000 },
- { 0x001668, 1, 0x04, 0x00000000 },
- { 0x000318, 2, 0x04, 0x00000008 },
- { 0x000d9c, 1, 0x04, 0x00000001 },
- { 0x0007dc, 1, 0x04, 0x00000000 },
- { 0x00074c, 1, 0x04, 0x00000055 },
- { 0x001420, 1, 0x04, 0x00000003 },
- { 0x0017bc, 2, 0x04, 0x00000000 },
- { 0x0017c4, 1, 0x04, 0x00000001 },
- { 0x001008, 1, 0x04, 0x00000008 },
- { 0x00100c, 1, 0x04, 0x00000040 },
- { 0x001010, 1, 0x04, 0x0000012c },
- { 0x000d60, 1, 0x04, 0x00000040 },
- { 0x00075c, 1, 0x04, 0x00000003 },
- { 0x001018, 1, 0x04, 0x00000020 },
- { 0x00101c, 1, 0x04, 0x00000001 },
- { 0x001020, 1, 0x04, 0x00000020 },
- { 0x001024, 1, 0x04, 0x00000001 },
- { 0x001444, 3, 0x04, 0x00000000 },
- { 0x000360, 1, 0x04, 0x20164010 },
- { 0x000364, 1, 0x04, 0x00000020 },
- { 0x000368, 1, 0x04, 0x00000000 },
- { 0x000de4, 1, 0x04, 0x00000000 },
- { 0x000204, 1, 0x04, 0x00000006 },
- { 0x000208, 1, 0x04, 0x00000000 },
- { 0x0002cc, 1, 0x04, 0x003fffff },
- { 0x0002d0, 1, 0x04, 0x00000c48 },
- { 0x001220, 1, 0x04, 0x00000005 },
- { 0x000fdc, 1, 0x04, 0x00000000 },
- { 0x000f98, 1, 0x04, 0x00300008 },
- { 0x001284, 1, 0x04, 0x04000080 },
- { 0x001450, 1, 0x04, 0x00300008 },
- { 0x001454, 1, 0x04, 0x04000080 },
- { 0x000214, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_9197_0[] = {
- { 0x003400, 128, 0x04, 0x00000000 },
- { 0x0002e4, 1, 0x04, 0x0000b001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_mthd[] = {
- { nvc1_grctx_init_9097_0, 0x9097 },
- { nvc1_grctx_init_9197_0, 0x9197 },
- { nvc0_grctx_init_902d_0, 0x902d },
- { nvc0_grctx_init_9039_0, 0x9039 },
- { nvc0_grctx_init_90c0_0, 0x90c0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x0f8000bf },
- { 0x405830, 1, 0x04, 0x02180218 },
- { 0x405834, 2, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x000103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b4, 2, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x80140078 },
- { 0x4064c4, 1, 0x04, 0x0086ffff },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x02802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x1003e005 },
- { 0x408900, 1, 0x04, 0x3080b801 },
- { 0x408904, 1, 0x04, 0x62000001 },
- { 0x408908, 1, 0x04, 0x00c80929 },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nvc0_grctx_init_fe_0 },
- { nvc0_grctx_init_pri_0 },
- { nvc0_grctx_init_memfmt_0 },
- { nvc1_grctx_init_ds_0 },
- { nvc1_grctx_init_pd_0 },
- { nvc0_grctx_init_rstr2d_0 },
- { nvc0_grctx_init_scc_0 },
- { nvc1_grctx_init_be_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x0006860a },
- { 0x418808, 3, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00008442 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x00100018 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_gpm_0[] = {
- { 0x418c08, 1, 0x04, 0x00000001 },
- { 0x418c10, 8, 0x04, 0x00000000 },
- { 0x418c6c, 1, 0x04, 0x00000001 },
- { 0x418c80, 1, 0x04, 0x20200004 },
- { 0x418c8c, 1, 0x04, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvc0_grctx_init_prop_0 },
- { nvc0_grctx_init_gpc_unk_1 },
- { nvc1_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvc0_grctx_init_crstr_0 },
- { nvc1_grctx_init_gpm_0 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_pe_0[] = {
- { 0x419818, 1, 0x04, 0x00000000 },
- { 0x41983c, 1, 0x04, 0x00038bc7 },
- { 0x419848, 1, 0x04, 0x00000000 },
- { 0x419864, 1, 0x04, 0x00000129 },
- { 0x419888, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_wwdx_0[] = {
- { 0x419b00, 1, 0x04, 0x0a418820 },
- { 0x419b04, 1, 0x04, 0x062080e6 },
- { 0x419b08, 1, 0x04, 0x020398a4 },
- { 0x419b0c, 1, 0x04, 0x0e629062 },
- { 0x419b10, 1, 0x04, 0x0a418820 },
- { 0x419b14, 1, 0x04, 0x000000e6 },
- { 0x419bd0, 1, 0x04, 0x00900103 },
- { 0x419be0, 1, 0x04, 0x00400001 },
- { 0x419be4, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc1_grctx_init_tpccs_0[] = {
- { 0x419d20, 1, 0x04, 0x12180000 },
- { 0x419d24, 1, 0x04, 0x00001fff },
- { 0x419d44, 1, 0x04, 0x02180218 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc1_grctx_pack_tpc[] = {
- { nvc1_grctx_init_pe_0 },
- { nvc4_grctx_init_tex_0 },
- { nvc1_grctx_init_wwdx_0 },
- { nvc0_grctx_init_mpc_0 },
- { nvc4_grctx_init_l1c_0 },
- { nvc1_grctx_init_tpccs_0 },
- { nvc4_grctx_init_sm_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-void
-nvc1_grctx_generate_attrib(struct nvc0_grctx *info)
-{
- struct nvc0_graph_priv *priv = info->priv;
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv);
- const u32 alpha = impl->alpha_nr;
- const u32 beta = impl->attrib_nr;
- const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
- const u32 access = NV_MEM_ACCESS_RW;
- const int s = 12;
- const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
- const int timeslice_mode = 1;
- const int max_batches = 0xffff;
- u32 bo = 0;
- u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
- int gpc, tpc;
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (beta << 16) | alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- const u32 a = alpha;
- const u32 b = beta;
- const u32 t = timeslice_mode;
- const u32 o = TPC_UNIT(gpc, tpc, 0x500);
- mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo);
- mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo);
- bo += impl->attrib_nr_max;
- mmio_wr32(info, o + 0x44, (a << 16) | ao);
- ao += impl->alpha_nr_max;
- }
- }
-}
-
-void
-nvc1_grctx_generate_unkn(struct nvc0_graph_priv *priv)
-{
- nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
- nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
- nv_mask(priv, 0x419814, 0x00000004, 0x00000004);
- nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
- nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
- nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
-}
-
-struct nouveau_oclass *
-nvc1_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xc1),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nvc0_grctx_generate_main,
- .unkn = nvc1_grctx_generate_unkn,
- .hub = nvc1_grctx_pack_hub,
- .gpc = nvc1_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvc1_grctx_pack_tpc,
- .icmd = nvc1_grctx_pack_icmd,
- .mthd = nvc1_grctx_pack_mthd,
- .bundle = nvc0_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .pagepool = nvc0_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvc1_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x324,
- .alpha_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c
deleted file mode 100644
index 41705c60cc47..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc4.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc4_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000001f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000023 },
- { 0x419a0c, 1, 0x04, 0x00020000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- { 0x419a1c, 1, 0x04, 0x00000000 },
- { 0x419a20, 1, 0x04, 0x00000800 },
- { 0x419ac4, 1, 0x04, 0x0007f440 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc4_grctx_init_l1c_0[] = {
- { 0x419cb0, 1, 0x04, 0x00020048 },
- { 0x419ce8, 1, 0x04, 0x00000000 },
- { 0x419cf4, 1, 0x04, 0x00000183 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc4_grctx_init_sm_0[] = {
- { 0x419e04, 3, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00000002 },
- { 0x419e44, 1, 0x04, 0x001beff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000000f },
- { 0x419e50, 17, 0x04, 0x00000000 },
- { 0x419e98, 1, 0x04, 0x00000000 },
- { 0x419ee0, 1, 0x04, 0x00011110 },
- { 0x419f30, 11, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc4_grctx_pack_tpc[] = {
- { nvc0_grctx_init_pe_0 },
- { nvc4_grctx_init_tex_0 },
- { nvc0_grctx_init_wwdx_0 },
- { nvc0_grctx_init_mpc_0 },
- { nvc4_grctx_init_l1c_0 },
- { nvc0_grctx_init_tpccs_0 },
- { nvc4_grctx_init_sm_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc4_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xc3),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nvc0_grctx_generate_main,
- .unkn = nvc0_grctx_generate_unkn,
- .hub = nvc0_grctx_pack_hub,
- .gpc = nvc0_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvc4_grctx_pack_tpc,
- .icmd = nvc0_grctx_pack_icmd,
- .mthd = nvc0_grctx_pack_mthd,
- .bundle = nvc0_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .pagepool = nvc0_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvc0_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
deleted file mode 100644
index 8f804cd8f9c7..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvc8.c
+++ /dev/null
@@ -1,360 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc8_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000b2, 40, 0x01, 0x00000000 },
- { 0x000210, 8, 0x01, 0x00000040 },
- { 0x000218, 8, 0x01, 0x0000c080 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00001fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x003fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x0005e0, 5, 0x01, 0x00000022 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x00097d, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x00000c48 },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00300008 },
- { 0x000841, 1, 0x01, 0x04000080 },
- { 0x000842, 1, 0x01, 0x00300008 },
- { 0x000843, 1, 0x01, 0x04000080 },
- { 0x000818, 8, 0x01, 0x00000000 },
- { 0x000848, 16, 0x01, 0x00000000 },
- { 0x000738, 1, 0x01, 0x00000000 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x000944, 1, 0x01, 0x00000022 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000014 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc8_grctx_pack_icmd[] = {
- { nvc8_grctx_init_icmd_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc8_grctx_init_9197_0[] = {
- { 0x0002e4, 1, 0x04, 0x0000b001 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc8_grctx_init_9297_0[] = {
- { 0x003400, 128, 0x04, 0x00000000 },
- { 0x00036c, 2, 0x04, 0x00000000 },
- { 0x0007a4, 2, 0x04, 0x00000000 },
- { 0x000374, 1, 0x04, 0x00000000 },
- { 0x000378, 1, 0x04, 0x00000020 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc8_grctx_pack_mthd[] = {
- { nvc1_grctx_init_9097_0, 0x9097 },
- { nvc8_grctx_init_9197_0, 0x9197 },
- { nvc8_grctx_init_9297_0, 0x9297 },
- { nvc0_grctx_init_902d_0, 0x902d },
- { nvc0_grctx_init_9039_0, 0x9039 },
- { nvc0_grctx_init_90c0_0, 0x90c0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc8_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x0006860a },
- { 0x418808, 3, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00008442 },
- { 0x418830, 1, 0x04, 0x00000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc8_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvc0_grctx_init_prop_0 },
- { nvc0_grctx_init_gpc_unk_1 },
- { nvc8_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvc0_grctx_init_crstr_0 },
- { nvc0_grctx_init_gpm_0 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc8_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xc8),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nvc0_grctx_generate_main,
- .unkn = nvc0_grctx_generate_unkn,
- .hub = nvc0_grctx_pack_hub,
- .gpc = nvc8_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvc0_grctx_pack_tpc,
- .icmd = nvc8_grctx_pack_icmd,
- .mthd = nvc8_grctx_pack_mthd,
- .bundle = nvc0_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .pagepool = nvc0_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvc0_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
deleted file mode 100644
index fcf534fd9e65..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd7.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x0f8000bf },
- { 0x405830, 1, 0x04, 0x02180324 },
- { 0x405834, 1, 0x04, 0x08000000 },
- { 0x405838, 1, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x000103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b4, 3, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x801a0078 },
- { 0x4064c4, 1, 0x04, 0x00c9ffff },
- { 0x4064d0, 8, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nvd9_grctx_init_fe_0 },
- { nvc0_grctx_init_pri_0 },
- { nvc0_grctx_init_memfmt_0 },
- { nvd7_grctx_init_ds_0 },
- { nvd7_grctx_init_pd_0 },
- { nvc0_grctx_init_rstr2d_0 },
- { nvc0_grctx_init_scc_0 },
- { nvd9_grctx_init_be_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x7006860a },
- { 0x418808, 3, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00008442 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100018 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvd9_grctx_init_prop_0 },
- { nvd9_grctx_init_gpc_unk_1 },
- { nvd7_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvd9_grctx_init_crstr_0 },
- { nvc1_grctx_init_gpm_0 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd7_grctx_init_pe_0[] = {
- { 0x419848, 1, 0x04, 0x00000000 },
- { 0x419864, 1, 0x04, 0x00000129 },
- { 0x419888, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000001f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000023 },
- { 0x419a0c, 1, 0x04, 0x00020000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- { 0x419a1c, 1, 0x04, 0x00008000 },
- { 0x419a20, 1, 0x04, 0x00000800 },
- { 0x419ac4, 1, 0x04, 0x0017f440 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_mpc_0[] = {
- { 0x419c00, 1, 0x04, 0x0000000a },
- { 0x419c04, 1, 0x04, 0x00000006 },
- { 0x419c08, 1, 0x04, 0x00000002 },
- { 0x419c20, 1, 0x04, 0x00000000 },
- { 0x419c24, 1, 0x04, 0x00084210 },
- { 0x419c28, 1, 0x04, 0x3efbefbe },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_tpc[] = {
- { nvd7_grctx_init_pe_0 },
- { nvd7_grctx_init_tex_0 },
- { nvd7_grctx_init_mpc_0 },
- { nvc4_grctx_init_l1c_0 },
- { nvd9_grctx_init_sm_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_pes_0[] = {
- { 0x41be24, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd7_grctx_init_cbm_0[] = {
- { 0x41bec0, 1, 0x04, 0x12180000 },
- { 0x41bec4, 1, 0x04, 0x00003fff },
- { 0x41bee4, 1, 0x04, 0x03240218 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd7_grctx_init_wwdx_0[] = {
- { 0x41bf00, 1, 0x04, 0x0a418820 },
- { 0x41bf04, 1, 0x04, 0x062080e6 },
- { 0x41bf08, 1, 0x04, 0x020398a4 },
- { 0x41bf0c, 1, 0x04, 0x0e629062 },
- { 0x41bf10, 1, 0x04, 0x0a418820 },
- { 0x41bf14, 1, 0x04, 0x000000e6 },
- { 0x41bfd0, 1, 0x04, 0x00900103 },
- { 0x41bfe0, 1, 0x04, 0x00400001 },
- { 0x41bfe4, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd7_grctx_pack_ppc[] = {
- { nvd7_grctx_init_pes_0 },
- { nvd7_grctx_init_cbm_0 },
- { nvd7_grctx_init_wwdx_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-void
-nvd7_grctx_generate_attrib(struct nvc0_grctx *info)
-{
- struct nvc0_graph_priv *priv = info->priv;
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(priv);
- const u32 alpha = impl->alpha_nr;
- const u32 beta = impl->attrib_nr;
- const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
- const u32 access = NV_MEM_ACCESS_RW;
- const int s = 12;
- const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
- const int timeslice_mode = 1;
- const int max_batches = 0xffff;
- u32 bo = 0;
- u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
- int gpc, ppc;
-
- mmio_refn(info, 0x418810, 0x80000000, s, b);
- mmio_refn(info, 0x419848, 0x10000000, s, b);
- mmio_wr32(info, 0x405830, (beta << 16) | alpha);
- mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) {
- const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc];
- const u32 b = beta * priv->ppc_tpc_nr[gpc][ppc];
- const u32 t = timeslice_mode;
- const u32 o = PPC_UNIT(gpc, ppc, 0);
- mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo);
- mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo);
- bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
- mmio_wr32(info, o + 0xe4, (a << 16) | ao);
- ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
- }
- }
-}
-
-void
-nvd7_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
- struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
- int i;
-
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-
- nvc0_graph_mmio(priv, oclass->hub);
- nvc0_graph_mmio(priv, oclass->gpc);
- nvc0_graph_mmio(priv, oclass->zcull);
- nvc0_graph_mmio(priv, oclass->tpc);
- nvc0_graph_mmio(priv, oclass->ppc);
-
- nv_wr32(priv, 0x404154, 0x00000000);
-
- oclass->bundle(info);
- oclass->pagepool(info);
- oclass->attrib(info);
- oclass->unkn(priv);
-
- nvc0_grctx_generate_tpcid(priv);
- nvc0_grctx_generate_r406028(priv);
- nvc0_grctx_generate_r4060a8(priv);
- nve4_grctx_generate_r418bb8(priv);
- nvc0_grctx_generate_r406800(priv);
-
- for (i = 0; i < 8; i++)
- nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-
- nvc0_graph_icmd(priv, oclass->icmd);
- nv_wr32(priv, 0x404154, 0x00000400);
- nvc0_graph_mthd(priv, oclass->mthd);
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-}
-
-struct nouveau_oclass *
-nvd7_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xd7),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nvd7_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = nvd7_grctx_pack_hub,
- .gpc = nvd7_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvd7_grctx_pack_tpc,
- .ppc = nvd7_grctx_pack_ppc,
- .icmd = nvd9_grctx_pack_icmd,
- .mthd = nvd9_grctx_pack_mthd,
- .bundle = nvc0_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .pagepool = nvc0_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvd7_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x7ff,
- .alpha_nr = 0x324,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
deleted file mode 100644
index b9a301b6fd9f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvd9.c
+++ /dev/null
@@ -1,530 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000b2, 40, 0x01, 0x00000000 },
- { 0x000210, 8, 0x01, 0x00000040 },
- { 0x000400, 24, 0x01, 0x00000040 },
- { 0x000218, 8, 0x01, 0x0000c080 },
- { 0x000440, 24, 0x01, 0x0000c080 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00001fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x003fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x0005e0, 5, 0x01, 0x00000022 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x00097d, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x00000c48 },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00300008 },
- { 0x000841, 1, 0x01, 0x04000080 },
- { 0x000842, 1, 0x01, 0x00300008 },
- { 0x000843, 1, 0x01, 0x04000080 },
- { 0x000818, 8, 0x01, 0x00000000 },
- { 0x000848, 16, 0x01, 0x00000000 },
- { 0x000738, 1, 0x01, 0x00000000 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x000944, 1, 0x01, 0x00000022 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000014 },
- { 0x000351, 1, 0x01, 0x00000100 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095d, 1, 0x01, 0x00000001 },
- { 0x00082b, 1, 0x01, 0x00000004 },
- { 0x000942, 1, 0x01, 0x00010001 },
- { 0x000943, 1, 0x01, 0x00000001 },
- { 0x0007c5, 1, 0x01, 0x00010001 },
- { 0x000834, 1, 0x01, 0x00000001 },
- { 0x0007c7, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x00080c, 1, 0x01, 0x00000002 },
- { 0x00080d, 2, 0x01, 0x00000100 },
- { 0x00080f, 1, 0x01, 0x00000001 },
- { 0x000823, 1, 0x01, 0x00000002 },
- { 0x000824, 2, 0x01, 0x00000100 },
- { 0x000826, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvd9_grctx_pack_icmd[] = {
- { nvd9_grctx_init_icmd_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_90c0_0[] = {
- { 0x002700, 8, 0x20, 0x00000000 },
- { 0x002704, 8, 0x20, 0x00000000 },
- { 0x002708, 8, 0x20, 0x00000000 },
- { 0x00270c, 8, 0x20, 0x00000000 },
- { 0x002710, 8, 0x20, 0x00014000 },
- { 0x002714, 8, 0x20, 0x00000040 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x000758, 1, 0x04, 0x00000100 },
- { 0x0002c4, 1, 0x04, 0x00000000 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x000204, 3, 0x04, 0x00000000 },
- { 0x000214, 1, 0x04, 0x00000000 },
- { 0x00024c, 1, 0x04, 0x00000000 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x001664, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvd9_grctx_pack_mthd[] = {
- { nvc1_grctx_init_9097_0, 0x9097 },
- { nvc8_grctx_init_9197_0, 0x9197 },
- { nvc8_grctx_init_9297_0, 0x9297 },
- { nvc0_grctx_init_902d_0, 0x902d },
- { nvc0_grctx_init_9039_0, 0x9039 },
- { nvd9_grctx_init_90c0_0, 0x90c0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_fe_0[] = {
- { 0x404004, 10, 0x04, 0x00000000 },
- { 0x404044, 1, 0x04, 0x00000000 },
- { 0x404094, 13, 0x04, 0x00000000 },
- { 0x4040c8, 1, 0x04, 0xf0000087 },
- { 0x4040d0, 6, 0x04, 0x00000000 },
- { 0x4040e8, 1, 0x04, 0x00001000 },
- { 0x4040f8, 1, 0x04, 0x00000000 },
- { 0x404130, 2, 0x04, 0x00000000 },
- { 0x404138, 1, 0x04, 0x20000040 },
- { 0x404150, 1, 0x04, 0x0000002e },
- { 0x404154, 1, 0x04, 0x00000400 },
- { 0x404158, 1, 0x04, 0x00000200 },
- { 0x404164, 1, 0x04, 0x00000055 },
- { 0x404168, 1, 0x04, 0x00000000 },
- { 0x404178, 2, 0x04, 0x00000000 },
- { 0x404200, 8, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x0f8000bf },
- { 0x405830, 1, 0x04, 0x02180218 },
- { 0x405834, 1, 0x04, 0x08000000 },
- { 0x405838, 1, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x000103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b4, 3, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x80140078 },
- { 0x4064c4, 1, 0x04, 0x0086ffff },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x02802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x1043e005 },
- { 0x408900, 1, 0x04, 0x3080b801 },
- { 0x408904, 1, 0x04, 0x62000001 },
- { 0x408908, 1, 0x04, 0x00c8102f },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd9_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nvd9_grctx_init_fe_0 },
- { nvc0_grctx_init_pri_0 },
- { nvc0_grctx_init_memfmt_0 },
- { nvd9_grctx_init_ds_0 },
- { nvd9_grctx_init_pd_0 },
- { nvc0_grctx_init_rstr2d_0 },
- { nvc0_grctx_init_scc_0 },
- { nvd9_grctx_init_be_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_prop_0[] = {
- { 0x418400, 1, 0x04, 0x38004e00 },
- { 0x418404, 1, 0x04, 0x71e0ffff },
- { 0x41840c, 1, 0x04, 0x00001008 },
- { 0x418410, 1, 0x04, 0x0fff0fff },
- { 0x418414, 1, 0x04, 0x02200fff },
- { 0x418450, 6, 0x04, 0x00000000 },
- { 0x418468, 1, 0x04, 0x00000001 },
- { 0x41846c, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_gpc_unk_1[] = {
- { 0x418600, 1, 0x04, 0x0000001f },
- { 0x418684, 1, 0x04, 0x0000000f },
- { 0x418700, 1, 0x04, 0x00000002 },
- { 0x418704, 1, 0x04, 0x00000080 },
- { 0x418708, 3, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x7006860a },
- { 0x418808, 3, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00008442 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100008 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_crstr_0[] = {
- { 0x418b00, 1, 0x04, 0x00000006 },
- { 0x418b08, 1, 0x04, 0x0a418820 },
- { 0x418b0c, 1, 0x04, 0x062080e6 },
- { 0x418b10, 1, 0x04, 0x020398a4 },
- { 0x418b14, 1, 0x04, 0x0e629062 },
- { 0x418b18, 1, 0x04, 0x0a418820 },
- { 0x418b1c, 1, 0x04, 0x000000e6 },
- { 0x418bb8, 1, 0x04, 0x00000103 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd9_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvd9_grctx_init_prop_0 },
- { nvd9_grctx_init_gpc_unk_1 },
- { nvd9_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvd9_grctx_init_crstr_0 },
- { nvc1_grctx_init_gpm_0 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000001f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000023 },
- { 0x419a0c, 1, 0x04, 0x00020000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- { 0x419a1c, 1, 0x04, 0x00000000 },
- { 0x419a20, 1, 0x04, 0x00000800 },
- { 0x419ac4, 1, 0x04, 0x0017f440 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_grctx_init_mpc_0[] = {
- { 0x419c00, 1, 0x04, 0x0000000a },
- { 0x419c04, 1, 0x04, 0x00000006 },
- { 0x419c08, 1, 0x04, 0x00000002 },
- { 0x419c20, 1, 0x04, 0x00000000 },
- { 0x419c24, 1, 0x04, 0x00084210 },
- { 0x419c28, 1, 0x04, 0x3cf3cf3c },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_grctx_init_sm_0[] = {
- { 0x419e04, 3, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00000002 },
- { 0x419e44, 1, 0x04, 0x001beff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000000f },
- { 0x419e50, 17, 0x04, 0x00000000 },
- { 0x419e98, 1, 0x04, 0x00000000 },
- { 0x419ee0, 1, 0x04, 0x00010110 },
- { 0x419f30, 11, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd9_grctx_pack_tpc[] = {
- { nvc1_grctx_init_pe_0 },
- { nvd9_grctx_init_tex_0 },
- { nvc1_grctx_init_wwdx_0 },
- { nvd9_grctx_init_mpc_0 },
- { nvc4_grctx_init_l1c_0 },
- { nvc1_grctx_init_tpccs_0 },
- { nvd9_grctx_init_sm_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvd9_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xd9),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nvc0_grctx_generate_main,
- .unkn = nvc1_grctx_generate_unkn,
- .hub = nvd9_grctx_pack_hub,
- .gpc = nvd9_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvd9_grctx_pack_tpc,
- .icmd = nvd9_grctx_pack_icmd,
- .mthd = nvd9_grctx_pack_mthd,
- .bundle = nvc0_grctx_generate_bundle,
- .bundle_size = 0x1800,
- .pagepool = nvc0_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvc1_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x324,
- .alpha_nr = 0x218,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
deleted file mode 100644
index ccac2ee1a1cb..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnve4.c
+++ /dev/null
@@ -1,1020 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nve4_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000383, 1, 0x01, 0x00000011 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x00097d, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x003fffff },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00400008 },
- { 0x000841, 1, 0x01, 0x08000080 },
- { 0x000842, 1, 0x01, 0x00400008 },
- { 0x000843, 1, 0x01, 0x08000080 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x00c500, 1, 0x01, 0x00000003 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000008 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x00c500, 1, 0x01, 0x00000003 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_icmd[] = {
- { nve4_grctx_init_icmd_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_a097_0[] = {
- { 0x000800, 8, 0x40, 0x00000000 },
- { 0x000804, 8, 0x40, 0x00000000 },
- { 0x000808, 8, 0x40, 0x00000400 },
- { 0x00080c, 8, 0x40, 0x00000300 },
- { 0x000810, 1, 0x04, 0x000000cf },
- { 0x000850, 7, 0x40, 0x00000000 },
- { 0x000814, 8, 0x40, 0x00000040 },
- { 0x000818, 8, 0x40, 0x00000001 },
- { 0x00081c, 8, 0x40, 0x00000000 },
- { 0x000820, 8, 0x40, 0x00000000 },
- { 0x001c00, 16, 0x10, 0x00000000 },
- { 0x001c04, 16, 0x10, 0x00000000 },
- { 0x001c08, 16, 0x10, 0x00000000 },
- { 0x001c0c, 16, 0x10, 0x00000000 },
- { 0x001d00, 16, 0x10, 0x00000000 },
- { 0x001d04, 16, 0x10, 0x00000000 },
- { 0x001d08, 16, 0x10, 0x00000000 },
- { 0x001d0c, 16, 0x10, 0x00000000 },
- { 0x001f00, 16, 0x08, 0x00000000 },
- { 0x001f04, 16, 0x08, 0x00000000 },
- { 0x001f80, 16, 0x08, 0x00000000 },
- { 0x001f84, 16, 0x08, 0x00000000 },
- { 0x002000, 1, 0x04, 0x00000000 },
- { 0x002040, 1, 0x04, 0x00000011 },
- { 0x002080, 1, 0x04, 0x00000020 },
- { 0x0020c0, 1, 0x04, 0x00000030 },
- { 0x002100, 1, 0x04, 0x00000040 },
- { 0x002140, 1, 0x04, 0x00000051 },
- { 0x00200c, 6, 0x40, 0x00000001 },
- { 0x002010, 1, 0x04, 0x00000000 },
- { 0x002050, 1, 0x04, 0x00000000 },
- { 0x002090, 1, 0x04, 0x00000001 },
- { 0x0020d0, 1, 0x04, 0x00000002 },
- { 0x002110, 1, 0x04, 0x00000003 },
- { 0x002150, 1, 0x04, 0x00000004 },
- { 0x000380, 4, 0x20, 0x00000000 },
- { 0x000384, 4, 0x20, 0x00000000 },
- { 0x000388, 4, 0x20, 0x00000000 },
- { 0x00038c, 4, 0x20, 0x00000000 },
- { 0x000700, 4, 0x10, 0x00000000 },
- { 0x000704, 4, 0x10, 0x00000000 },
- { 0x000708, 4, 0x10, 0x00000000 },
- { 0x002800, 128, 0x04, 0x00000000 },
- { 0x000a00, 16, 0x20, 0x00000000 },
- { 0x000a04, 16, 0x20, 0x00000000 },
- { 0x000a08, 16, 0x20, 0x00000000 },
- { 0x000a0c, 16, 0x20, 0x00000000 },
- { 0x000a10, 16, 0x20, 0x00000000 },
- { 0x000a14, 16, 0x20, 0x00000000 },
- { 0x000c00, 16, 0x10, 0x00000000 },
- { 0x000c04, 16, 0x10, 0x00000000 },
- { 0x000c08, 16, 0x10, 0x00000000 },
- { 0x000c0c, 16, 0x10, 0x3f800000 },
- { 0x000d00, 8, 0x08, 0xffff0000 },
- { 0x000d04, 8, 0x08, 0xffff0000 },
- { 0x000e00, 16, 0x10, 0x00000000 },
- { 0x000e04, 16, 0x10, 0xffff0000 },
- { 0x000e08, 16, 0x10, 0xffff0000 },
- { 0x000d40, 4, 0x08, 0x00000000 },
- { 0x000d44, 4, 0x08, 0x00000000 },
- { 0x001e00, 8, 0x20, 0x00000001 },
- { 0x001e04, 8, 0x20, 0x00000001 },
- { 0x001e08, 8, 0x20, 0x00000002 },
- { 0x001e0c, 8, 0x20, 0x00000001 },
- { 0x001e10, 8, 0x20, 0x00000001 },
- { 0x001e14, 8, 0x20, 0x00000002 },
- { 0x001e18, 8, 0x20, 0x00000001 },
- { 0x003400, 128, 0x04, 0x00000000 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x001514, 1, 0x04, 0x00000000 },
- { 0x000d68, 1, 0x04, 0x0000ffff },
- { 0x00121c, 1, 0x04, 0x0fac6881 },
- { 0x000fac, 1, 0x04, 0x00000001 },
- { 0x001538, 1, 0x04, 0x00000001 },
- { 0x000fe0, 2, 0x04, 0x00000000 },
- { 0x000fe8, 1, 0x04, 0x00000014 },
- { 0x000fec, 1, 0x04, 0x00000040 },
- { 0x000ff0, 1, 0x04, 0x00000000 },
- { 0x00179c, 1, 0x04, 0x00000000 },
- { 0x001228, 1, 0x04, 0x00000400 },
- { 0x00122c, 1, 0x04, 0x00000300 },
- { 0x001230, 1, 0x04, 0x00010001 },
- { 0x0007f8, 1, 0x04, 0x00000000 },
- { 0x0015b4, 1, 0x04, 0x00000001 },
- { 0x0015cc, 1, 0x04, 0x00000000 },
- { 0x001534, 1, 0x04, 0x00000000 },
- { 0x000fb0, 1, 0x04, 0x00000000 },
- { 0x0015d0, 1, 0x04, 0x00000000 },
- { 0x00153c, 1, 0x04, 0x00000000 },
- { 0x0016b4, 1, 0x04, 0x00000003 },
- { 0x000fbc, 4, 0x04, 0x0000ffff },
- { 0x000df8, 2, 0x04, 0x00000000 },
- { 0x001948, 1, 0x04, 0x00000000 },
- { 0x001970, 1, 0x04, 0x00000001 },
- { 0x00161c, 1, 0x04, 0x000009f0 },
- { 0x000dcc, 1, 0x04, 0x00000010 },
- { 0x00163c, 1, 0x04, 0x00000000 },
- { 0x0015e4, 1, 0x04, 0x00000000 },
- { 0x001160, 32, 0x04, 0x25e00040 },
- { 0x001880, 32, 0x04, 0x00000000 },
- { 0x000f84, 2, 0x04, 0x00000000 },
- { 0x0017c8, 2, 0x04, 0x00000000 },
- { 0x0017d0, 1, 0x04, 0x000000ff },
- { 0x0017d4, 1, 0x04, 0xffffffff },
- { 0x0017d8, 1, 0x04, 0x00000002 },
- { 0x0017dc, 1, 0x04, 0x00000000 },
- { 0x0015f4, 2, 0x04, 0x00000000 },
- { 0x001434, 2, 0x04, 0x00000000 },
- { 0x000d74, 1, 0x04, 0x00000000 },
- { 0x000dec, 1, 0x04, 0x00000001 },
- { 0x0013a4, 1, 0x04, 0x00000000 },
- { 0x001318, 1, 0x04, 0x00000001 },
- { 0x001644, 1, 0x04, 0x00000000 },
- { 0x000748, 1, 0x04, 0x00000000 },
- { 0x000de8, 1, 0x04, 0x00000000 },
- { 0x001648, 1, 0x04, 0x00000000 },
- { 0x0012a4, 1, 0x04, 0x00000000 },
- { 0x001120, 4, 0x04, 0x00000000 },
- { 0x001118, 1, 0x04, 0x00000000 },
- { 0x00164c, 1, 0x04, 0x00000000 },
- { 0x001658, 1, 0x04, 0x00000000 },
- { 0x001910, 1, 0x04, 0x00000290 },
- { 0x001518, 1, 0x04, 0x00000000 },
- { 0x00165c, 1, 0x04, 0x00000001 },
- { 0x001520, 1, 0x04, 0x00000000 },
- { 0x001604, 1, 0x04, 0x00000000 },
- { 0x001570, 1, 0x04, 0x00000000 },
- { 0x0013b0, 2, 0x04, 0x3f800000 },
- { 0x00020c, 1, 0x04, 0x00000000 },
- { 0x001670, 1, 0x04, 0x30201000 },
- { 0x001674, 1, 0x04, 0x70605040 },
- { 0x001678, 1, 0x04, 0xb8a89888 },
- { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
- { 0x00166c, 1, 0x04, 0x00000000 },
- { 0x001680, 1, 0x04, 0x00ffff00 },
- { 0x0012d0, 1, 0x04, 0x00000003 },
- { 0x0012d4, 1, 0x04, 0x00000002 },
- { 0x001684, 2, 0x04, 0x00000000 },
- { 0x000dac, 2, 0x04, 0x00001b02 },
- { 0x000db4, 1, 0x04, 0x00000000 },
- { 0x00168c, 1, 0x04, 0x00000000 },
- { 0x0015bc, 1, 0x04, 0x00000000 },
- { 0x00156c, 1, 0x04, 0x00000000 },
- { 0x00187c, 1, 0x04, 0x00000000 },
- { 0x001110, 1, 0x04, 0x00000001 },
- { 0x000dc0, 3, 0x04, 0x00000000 },
- { 0x001234, 1, 0x04, 0x00000000 },
- { 0x001690, 1, 0x04, 0x00000000 },
- { 0x0012ac, 1, 0x04, 0x00000001 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x001000, 1, 0x04, 0x00000010 },
- { 0x0010fc, 1, 0x04, 0x00000000 },
- { 0x001290, 1, 0x04, 0x00000000 },
- { 0x000218, 1, 0x04, 0x00000010 },
- { 0x0012d8, 1, 0x04, 0x00000000 },
- { 0x0012dc, 1, 0x04, 0x00000010 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x00155c, 2, 0x04, 0x00000000 },
- { 0x001564, 1, 0x04, 0x00000fff },
- { 0x001574, 2, 0x04, 0x00000000 },
- { 0x00157c, 1, 0x04, 0x000fffff },
- { 0x001354, 1, 0x04, 0x00000000 },
- { 0x001610, 1, 0x04, 0x00000012 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x00260c, 1, 0x04, 0x00000000 },
- { 0x0007ac, 1, 0x04, 0x00000000 },
- { 0x00162c, 1, 0x04, 0x00000003 },
- { 0x000210, 1, 0x04, 0x00000000 },
- { 0x000320, 1, 0x04, 0x00000000 },
- { 0x000324, 6, 0x04, 0x3f800000 },
- { 0x000750, 1, 0x04, 0x00000000 },
- { 0x000760, 1, 0x04, 0x39291909 },
- { 0x000764, 1, 0x04, 0x79695949 },
- { 0x000768, 1, 0x04, 0xb9a99989 },
- { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
- { 0x000770, 1, 0x04, 0x30201000 },
- { 0x000774, 1, 0x04, 0x70605040 },
- { 0x000778, 1, 0x04, 0x00009080 },
- { 0x000780, 1, 0x04, 0x39291909 },
- { 0x000784, 1, 0x04, 0x79695949 },
- { 0x000788, 1, 0x04, 0xb9a99989 },
- { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
- { 0x0007d0, 1, 0x04, 0x30201000 },
- { 0x0007d4, 1, 0x04, 0x70605040 },
- { 0x0007d8, 1, 0x04, 0x00009080 },
- { 0x00037c, 1, 0x04, 0x00000001 },
- { 0x000740, 2, 0x04, 0x00000000 },
- { 0x002600, 1, 0x04, 0x00000000 },
- { 0x001918, 1, 0x04, 0x00000000 },
- { 0x00191c, 1, 0x04, 0x00000900 },
- { 0x001920, 1, 0x04, 0x00000405 },
- { 0x001308, 1, 0x04, 0x00000001 },
- { 0x001924, 1, 0x04, 0x00000000 },
- { 0x0013ac, 1, 0x04, 0x00000000 },
- { 0x00192c, 1, 0x04, 0x00000001 },
- { 0x00193c, 1, 0x04, 0x00002c1c },
- { 0x000d7c, 1, 0x04, 0x00000000 },
- { 0x000f8c, 1, 0x04, 0x00000000 },
- { 0x0002c0, 1, 0x04, 0x00000001 },
- { 0x001510, 1, 0x04, 0x00000000 },
- { 0x001940, 1, 0x04, 0x00000000 },
- { 0x000ff4, 2, 0x04, 0x00000000 },
- { 0x00194c, 2, 0x04, 0x00000000 },
- { 0x001968, 1, 0x04, 0x00000000 },
- { 0x001590, 1, 0x04, 0x0000003f },
- { 0x0007e8, 4, 0x04, 0x00000000 },
- { 0x00196c, 1, 0x04, 0x00000011 },
- { 0x0002e4, 1, 0x04, 0x0000b001 },
- { 0x00036c, 2, 0x04, 0x00000000 },
- { 0x00197c, 1, 0x04, 0x00000000 },
- { 0x000fcc, 2, 0x04, 0x00000000 },
- { 0x0002d8, 1, 0x04, 0x00000040 },
- { 0x001980, 1, 0x04, 0x00000080 },
- { 0x001504, 1, 0x04, 0x00000080 },
- { 0x001984, 1, 0x04, 0x00000000 },
- { 0x000300, 1, 0x04, 0x00000001 },
- { 0x0013a8, 1, 0x04, 0x00000000 },
- { 0x0012ec, 1, 0x04, 0x00000000 },
- { 0x001310, 1, 0x04, 0x00000000 },
- { 0x001314, 1, 0x04, 0x00000001 },
- { 0x001380, 1, 0x04, 0x00000000 },
- { 0x001384, 4, 0x04, 0x00000001 },
- { 0x001394, 1, 0x04, 0x00000000 },
- { 0x00139c, 1, 0x04, 0x00000000 },
- { 0x001398, 1, 0x04, 0x00000000 },
- { 0x001594, 1, 0x04, 0x00000000 },
- { 0x001598, 4, 0x04, 0x00000001 },
- { 0x000f54, 3, 0x04, 0x00000000 },
- { 0x0019bc, 1, 0x04, 0x00000000 },
- { 0x000f9c, 2, 0x04, 0x00000000 },
- { 0x0012cc, 1, 0x04, 0x00000000 },
- { 0x0012e8, 1, 0x04, 0x00000000 },
- { 0x00130c, 1, 0x04, 0x00000001 },
- { 0x001360, 8, 0x04, 0x00000000 },
- { 0x00133c, 2, 0x04, 0x00000001 },
- { 0x001344, 1, 0x04, 0x00000002 },
- { 0x001348, 2, 0x04, 0x00000001 },
- { 0x001350, 1, 0x04, 0x00000002 },
- { 0x001358, 1, 0x04, 0x00000001 },
- { 0x0012e4, 1, 0x04, 0x00000000 },
- { 0x00131c, 4, 0x04, 0x00000000 },
- { 0x0019c0, 1, 0x04, 0x00000000 },
- { 0x001140, 1, 0x04, 0x00000000 },
- { 0x0019c4, 1, 0x04, 0x00000000 },
- { 0x0019c8, 1, 0x04, 0x00001500 },
- { 0x00135c, 1, 0x04, 0x00000000 },
- { 0x000f90, 1, 0x04, 0x00000000 },
- { 0x0019e0, 8, 0x04, 0x00000001 },
- { 0x0019cc, 1, 0x04, 0x00000001 },
- { 0x0015b8, 1, 0x04, 0x00000000 },
- { 0x001a00, 1, 0x04, 0x00001111 },
- { 0x001a04, 7, 0x04, 0x00000000 },
- { 0x000d6c, 2, 0x04, 0xffff0000 },
- { 0x0010f8, 1, 0x04, 0x00001010 },
- { 0x000d80, 5, 0x04, 0x00000000 },
- { 0x000da0, 1, 0x04, 0x00000000 },
- { 0x0007a4, 2, 0x04, 0x00000000 },
- { 0x001508, 1, 0x04, 0x80000000 },
- { 0x00150c, 1, 0x04, 0x40000000 },
- { 0x001668, 1, 0x04, 0x00000000 },
- { 0x000318, 2, 0x04, 0x00000008 },
- { 0x000d9c, 1, 0x04, 0x00000001 },
- { 0x000374, 1, 0x04, 0x00000000 },
- { 0x000378, 1, 0x04, 0x00000020 },
- { 0x0007dc, 1, 0x04, 0x00000000 },
- { 0x00074c, 1, 0x04, 0x00000055 },
- { 0x001420, 1, 0x04, 0x00000003 },
- { 0x0017bc, 2, 0x04, 0x00000000 },
- { 0x0017c4, 1, 0x04, 0x00000001 },
- { 0x001008, 1, 0x04, 0x00000008 },
- { 0x00100c, 1, 0x04, 0x00000040 },
- { 0x001010, 1, 0x04, 0x0000012c },
- { 0x000d60, 1, 0x04, 0x00000040 },
- { 0x00075c, 1, 0x04, 0x00000003 },
- { 0x001018, 1, 0x04, 0x00000020 },
- { 0x00101c, 1, 0x04, 0x00000001 },
- { 0x001020, 1, 0x04, 0x00000020 },
- { 0x001024, 1, 0x04, 0x00000001 },
- { 0x001444, 3, 0x04, 0x00000000 },
- { 0x000360, 1, 0x04, 0x20164010 },
- { 0x000364, 1, 0x04, 0x00000020 },
- { 0x000368, 1, 0x04, 0x00000000 },
- { 0x000de4, 1, 0x04, 0x00000000 },
- { 0x000204, 1, 0x04, 0x00000006 },
- { 0x000208, 1, 0x04, 0x00000000 },
- { 0x0002cc, 2, 0x04, 0x003fffff },
- { 0x001220, 1, 0x04, 0x00000005 },
- { 0x000fdc, 1, 0x04, 0x00000000 },
- { 0x000f98, 1, 0x04, 0x00400008 },
- { 0x001284, 1, 0x04, 0x08000080 },
- { 0x001450, 1, 0x04, 0x00400008 },
- { 0x001454, 1, 0x04, 0x08000080 },
- { 0x000214, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nve4_grctx_pack_mthd[] = {
- { nve4_grctx_init_a097_0, 0xa097 },
- { nvc0_grctx_init_902d_0, 0x902d },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_fe_0[] = {
- { 0x404010, 5, 0x04, 0x00000000 },
- { 0x404024, 1, 0x04, 0x0000e000 },
- { 0x404028, 1, 0x04, 0x00000000 },
- { 0x4040a8, 8, 0x04, 0x00000000 },
- { 0x4040c8, 1, 0x04, 0xf800008f },
- { 0x4040d0, 6, 0x04, 0x00000000 },
- { 0x4040e8, 1, 0x04, 0x00001000 },
- { 0x4040f8, 1, 0x04, 0x00000000 },
- { 0x404130, 2, 0x04, 0x00000000 },
- { 0x404138, 1, 0x04, 0x20000040 },
- { 0x404150, 1, 0x04, 0x0000002e },
- { 0x404154, 1, 0x04, 0x00000400 },
- { 0x404158, 1, 0x04, 0x00000200 },
- { 0x404164, 1, 0x04, 0x00000055 },
- { 0x4041a0, 4, 0x04, 0x00000000 },
- { 0x404200, 4, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_memfmt_0[] = {
- { 0x404604, 1, 0x04, 0x00000014 },
- { 0x404608, 1, 0x04, 0x00000000 },
- { 0x40460c, 1, 0x04, 0x00003fff },
- { 0x404610, 1, 0x04, 0x00000100 },
- { 0x404618, 4, 0x04, 0x00000000 },
- { 0x40462c, 2, 0x04, 0x00000000 },
- { 0x404640, 1, 0x04, 0x00000000 },
- { 0x404654, 1, 0x04, 0x00000000 },
- { 0x404660, 1, 0x04, 0x00000000 },
- { 0x404678, 1, 0x04, 0x00000000 },
- { 0x40467c, 1, 0x04, 0x00000002 },
- { 0x404680, 8, 0x04, 0x00000000 },
- { 0x4046a0, 1, 0x04, 0x007f0080 },
- { 0x4046a4, 8, 0x04, 0x00000000 },
- { 0x4046c8, 3, 0x04, 0x00000000 },
- { 0x404700, 3, 0x04, 0x00000000 },
- { 0x404718, 7, 0x04, 0x00000000 },
- { 0x404734, 1, 0x04, 0x00000100 },
- { 0x404738, 2, 0x04, 0x00000000 },
- { 0x404744, 2, 0x04, 0x00000000 },
- { 0x404754, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_ds_0[] = {
- { 0x405800, 1, 0x04, 0x0f8000bf },
- { 0x405830, 1, 0x04, 0x02180648 },
- { 0x405834, 1, 0x04, 0x08000000 },
- { 0x405838, 1, 0x04, 0x00000000 },
- { 0x405854, 1, 0x04, 0x00000000 },
- { 0x405870, 4, 0x04, 0x00000001 },
- { 0x405a00, 2, 0x04, 0x00000000 },
- { 0x405a18, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_cwd_0[] = {
- { 0x405b00, 1, 0x04, 0x00000000 },
- { 0x405b10, 1, 0x04, 0x00001000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x004103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b4, 2, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x801a00f0 },
- { 0x4064c4, 1, 0x04, 0x0192ffff },
- { 0x4064c8, 1, 0x04, 0x01800600 },
- { 0x4064cc, 9, 0x04, 0x00000000 },
- { 0x4064fc, 1, 0x04, 0x0000022a },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_sked_0[] = {
- { 0x407040, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_scc_0[] = {
- { 0x408000, 2, 0x04, 0x00000000 },
- { 0x408008, 1, 0x04, 0x00000030 },
- { 0x40800c, 2, 0x04, 0x00000000 },
- { 0x408014, 1, 0x04, 0x00000069 },
- { 0x408018, 1, 0x04, 0xe100e100 },
- { 0x408064, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x02802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x1043e005 },
- { 0x408840, 1, 0x04, 0x0000000b },
- { 0x408900, 1, 0x04, 0x3080b801 },
- { 0x408904, 1, 0x04, 0x62000001 },
- { 0x408908, 1, 0x04, 0x00c8102f },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nve4_grctx_init_fe_0 },
- { nvc0_grctx_init_pri_0 },
- { nve4_grctx_init_memfmt_0 },
- { nve4_grctx_init_ds_0 },
- { nve4_grctx_init_cwd_0 },
- { nve4_grctx_init_pd_0 },
- { nve4_grctx_init_sked_0 },
- { nvc0_grctx_init_rstr2d_0 },
- { nve4_grctx_init_scc_0 },
- { nve4_grctx_init_be_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x7006860a },
- { 0x418808, 3, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00000044 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100018 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_gpm_0[] = {
- { 0x418c08, 1, 0x04, 0x00000001 },
- { 0x418c10, 8, 0x04, 0x00000000 },
- { 0x418c40, 1, 0x04, 0xffffffff },
- { 0x418c6c, 1, 0x04, 0x00000001 },
- { 0x418c80, 1, 0x04, 0x20200004 },
- { 0x418c8c, 1, 0x04, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvd9_grctx_init_prop_0 },
- { nvd9_grctx_init_gpc_unk_1 },
- { nve4_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvd9_grctx_init_crstr_0 },
- { nve4_grctx_init_gpm_0 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000000f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000021 },
- { 0x419a0c, 1, 0x04, 0x00020000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- { 0x419a1c, 1, 0x04, 0x0000c000 },
- { 0x419a20, 1, 0x04, 0x00000800 },
- { 0x419a30, 1, 0x04, 0x00000001 },
- { 0x419ac4, 1, 0x04, 0x0037f440 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_mpc_0[] = {
- { 0x419c00, 1, 0x04, 0x0000000a },
- { 0x419c04, 1, 0x04, 0x80000006 },
- { 0x419c08, 1, 0x04, 0x00000002 },
- { 0x419c20, 1, 0x04, 0x00000000 },
- { 0x419c24, 1, 0x04, 0x00084210 },
- { 0x419c28, 1, 0x04, 0x3efbefbe },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_l1c_0[] = {
- { 0x419ce8, 1, 0x04, 0x00000000 },
- { 0x419cf4, 1, 0x04, 0x00003203 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_sm_0[] = {
- { 0x419e04, 3, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00000402 },
- { 0x419e44, 1, 0x04, 0x0013eff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000007f },
- { 0x419e50, 19, 0x04, 0x00000000 },
- { 0x419eac, 1, 0x04, 0x00001f8f },
- { 0x419eb0, 1, 0x04, 0x00000d3f },
- { 0x419ec8, 1, 0x04, 0x0001304f },
- { 0x419f30, 8, 0x04, 0x00000000 },
- { 0x419f58, 1, 0x04, 0x00000000 },
- { 0x419f70, 1, 0x04, 0x00000000 },
- { 0x419f78, 1, 0x04, 0x0000000b },
- { 0x419f7c, 1, 0x04, 0x0000027c },
- {}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_tpc[] = {
- { nvd7_grctx_init_pe_0 },
- { nve4_grctx_init_tex_0 },
- { nve4_grctx_init_mpc_0 },
- { nve4_grctx_init_l1c_0 },
- { nve4_grctx_init_sm_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_grctx_init_pes_0[] = {
- { 0x41be24, 1, 0x04, 0x00000006 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_grctx_init_cbm_0[] = {
- { 0x41bec0, 1, 0x04, 0x12180000 },
- { 0x41bec4, 1, 0x04, 0x00037f7f },
- { 0x41bee4, 1, 0x04, 0x06480430 },
- {}
-};
-
-const struct nvc0_graph_pack
-nve4_grctx_pack_ppc[] = {
- { nve4_grctx_init_pes_0 },
- { nve4_grctx_init_cbm_0 },
- { nvd7_grctx_init_wwdx_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-void
-nve4_grctx_generate_bundle(struct nvc0_grctx *info)
-{
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
- const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
- impl->bundle_size / 0x20);
- const u32 token_limit = impl->bundle_token_limit;
- const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
- const int s = 8;
- const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
- mmio_refn(info, 0x408004, 0x00000000, s, b);
- mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
- mmio_refn(info, 0x418808, 0x00000000, s, b);
- mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
- mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
-}
-
-void
-nve4_grctx_generate_pagepool(struct nvc0_grctx *info)
-{
- const struct nvc0_grctx_oclass *impl = nvc0_grctx_impl(info->priv);
- const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
- const int s = 8;
- const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
- mmio_refn(info, 0x40800c, 0x00000000, s, b);
- mmio_wr32(info, 0x408010, 0x80000000);
- mmio_refn(info, 0x419004, 0x00000000, s, b);
- mmio_wr32(info, 0x419008, 0x00000000);
- mmio_wr32(info, 0x4064cc, 0x80000000);
-}
-
-void
-nve4_grctx_generate_unkn(struct nvc0_graph_priv *priv)
-{
- nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
- nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
- nv_mask(priv, 0x41be08, 0x00000004, 0x00000004);
- nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
- nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
- nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
-}
-
-void
-nve4_grctx_generate_r418bb8(struct nvc0_graph_priv *priv)
-{
- u32 data[6] = {}, data2[2] = {};
- u8 tpcnr[GPC_MAX];
- u8 shift, ntpcv;
- int gpc, tpc, i;
-
- /* calculate first set of magics */
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
-
- gpc = -1;
- for (tpc = 0; tpc < priv->tpc_total; tpc++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpcnr[gpc]--;
-
- data[tpc / 6] |= gpc << ((tpc % 6) * 5);
- }
-
- for (; tpc < 32; tpc++)
- data[tpc / 6] |= 7 << ((tpc % 6) * 5);
-
- /* and the second... */
- shift = 0;
- ntpcv = priv->tpc_total;
- while (!(ntpcv & (1 << 4))) {
- ntpcv <<= 1;
- shift++;
- }
-
- data2[0] = (ntpcv << 16);
- data2[0] |= (shift << 21);
- data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
- for (i = 1; i < 7; i++)
- data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
-
- /* GPC_BROADCAST */
- nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
-
- /* GPC_BROADCAST.TP_BROADCAST */
- nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr | data2[0]);
- nv_wr32(priv, 0x41bfe4, data2[1]);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
-
- /* UNK78xx */
- nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
- priv->magic_not_rop_nr);
- for (i = 0; i < 6; i++)
- nv_wr32(priv, 0x40780c + (i * 4), data[i]);
-}
-
-void
-nve4_grctx_generate_main(struct nvc0_graph_priv *priv, struct nvc0_grctx *info)
-{
- struct nvc0_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
- int i;
-
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
-
- nvc0_graph_mmio(priv, oclass->hub);
- nvc0_graph_mmio(priv, oclass->gpc);
- nvc0_graph_mmio(priv, oclass->zcull);
- nvc0_graph_mmio(priv, oclass->tpc);
- nvc0_graph_mmio(priv, oclass->ppc);
-
- nv_wr32(priv, 0x404154, 0x00000000);
-
- oclass->bundle(info);
- oclass->pagepool(info);
- oclass->attrib(info);
- oclass->unkn(priv);
-
- nvc0_grctx_generate_tpcid(priv);
- nvc0_grctx_generate_r406028(priv);
- nve4_grctx_generate_r418bb8(priv);
- nvc0_grctx_generate_r406800(priv);
-
- for (i = 0; i < 8; i++)
- nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
-
- nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
- if (priv->gpc_nr == 1) {
- nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
- nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
- } else {
- nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
- nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
- }
- nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
-
- nvc0_graph_icmd(priv, oclass->icmd);
- nv_wr32(priv, 0x404154, 0x00000400);
- nvc0_graph_mthd(priv, oclass->mthd);
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-
- nv_mask(priv, 0x418800, 0x00200000, 0x00200000);
- nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
-}
-
-struct nouveau_oclass *
-nve4_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xe4),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nve4_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = nve4_grctx_pack_hub,
- .gpc = nve4_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nve4_grctx_pack_tpc,
- .ppc = nve4_grctx_pack_ppc,
- .icmd = nve4_grctx_pack_icmd,
- .mthd = nve4_grctx_pack_mthd,
- .bundle = nve4_grctx_generate_bundle,
- .bundle_size = 0x3000,
- .bundle_min_gpm_fifo_depth = 0x180,
- .bundle_token_limit = 0x600,
- .pagepool = nve4_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvd7_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x7ff,
- .alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
deleted file mode 100644
index e9b0dcf95a49..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/ctxnvf0.c
+++ /dev/null
@@ -1,843 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH context register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_icmd_0[] = {
- { 0x001000, 1, 0x01, 0x00000004 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x0000a9, 1, 0x01, 0x0000ffff },
- { 0x000038, 1, 0x01, 0x0fac6881 },
- { 0x00003d, 1, 0x01, 0x00000001 },
- { 0x0000e8, 8, 0x01, 0x00000400 },
- { 0x000078, 8, 0x01, 0x00000300 },
- { 0x000050, 1, 0x01, 0x00000011 },
- { 0x000058, 8, 0x01, 0x00000008 },
- { 0x000208, 8, 0x01, 0x00000001 },
- { 0x000081, 1, 0x01, 0x00000001 },
- { 0x000085, 1, 0x01, 0x00000004 },
- { 0x000088, 1, 0x01, 0x00000400 },
- { 0x000090, 1, 0x01, 0x00000300 },
- { 0x000098, 1, 0x01, 0x00001001 },
- { 0x0000e3, 1, 0x01, 0x00000001 },
- { 0x0000da, 1, 0x01, 0x00000001 },
- { 0x0000f8, 1, 0x01, 0x00000003 },
- { 0x0000fa, 1, 0x01, 0x00000001 },
- { 0x00009f, 4, 0x01, 0x0000ffff },
- { 0x0000b1, 1, 0x01, 0x00000001 },
- { 0x0000ad, 1, 0x01, 0x0000013e },
- { 0x0000e1, 1, 0x01, 0x00000010 },
- { 0x000290, 16, 0x01, 0x00000000 },
- { 0x0003b0, 16, 0x01, 0x00000000 },
- { 0x0002a0, 16, 0x01, 0x00000000 },
- { 0x000420, 16, 0x01, 0x00000000 },
- { 0x0002b0, 16, 0x01, 0x00000000 },
- { 0x000430, 16, 0x01, 0x00000000 },
- { 0x0002c0, 16, 0x01, 0x00000000 },
- { 0x0004d0, 16, 0x01, 0x00000000 },
- { 0x000720, 16, 0x01, 0x00000000 },
- { 0x0008c0, 16, 0x01, 0x00000000 },
- { 0x000890, 16, 0x01, 0x00000000 },
- { 0x0008e0, 16, 0x01, 0x00000000 },
- { 0x0008a0, 16, 0x01, 0x00000000 },
- { 0x0008f0, 16, 0x01, 0x00000000 },
- { 0x00094c, 1, 0x01, 0x000000ff },
- { 0x00094d, 1, 0x01, 0xffffffff },
- { 0x00094e, 1, 0x01, 0x00000002 },
- { 0x0002ec, 1, 0x01, 0x00000001 },
- { 0x0002f2, 2, 0x01, 0x00000001 },
- { 0x0002f5, 1, 0x01, 0x00000001 },
- { 0x0002f7, 1, 0x01, 0x00000001 },
- { 0x000303, 1, 0x01, 0x00000001 },
- { 0x0002e6, 1, 0x01, 0x00000001 },
- { 0x000466, 1, 0x01, 0x00000052 },
- { 0x000301, 1, 0x01, 0x3f800000 },
- { 0x000304, 1, 0x01, 0x30201000 },
- { 0x000305, 1, 0x01, 0x70605040 },
- { 0x000306, 1, 0x01, 0xb8a89888 },
- { 0x000307, 1, 0x01, 0xf8e8d8c8 },
- { 0x00030a, 1, 0x01, 0x00ffff00 },
- { 0x00030b, 1, 0x01, 0x0000001a },
- { 0x00030c, 1, 0x01, 0x00000001 },
- { 0x000318, 1, 0x01, 0x00000001 },
- { 0x000340, 1, 0x01, 0x00000000 },
- { 0x000375, 1, 0x01, 0x00000001 },
- { 0x00037d, 1, 0x01, 0x00000006 },
- { 0x0003a0, 1, 0x01, 0x00000002 },
- { 0x0003aa, 1, 0x01, 0x00000001 },
- { 0x0003a9, 1, 0x01, 0x00000001 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000383, 1, 0x01, 0x00000011 },
- { 0x000360, 1, 0x01, 0x00000040 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x00037a, 1, 0x01, 0x00000012 },
- { 0x000619, 1, 0x01, 0x00000003 },
- { 0x000811, 1, 0x01, 0x00000003 },
- { 0x000812, 1, 0x01, 0x00000004 },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000815, 1, 0x01, 0x0000000b },
- { 0x000800, 6, 0x01, 0x00000001 },
- { 0x000632, 1, 0x01, 0x00000001 },
- { 0x000633, 1, 0x01, 0x00000002 },
- { 0x000634, 1, 0x01, 0x00000003 },
- { 0x000635, 1, 0x01, 0x00000004 },
- { 0x000654, 1, 0x01, 0x3f800000 },
- { 0x000657, 1, 0x01, 0x3f800000 },
- { 0x000655, 2, 0x01, 0x3f800000 },
- { 0x0006cd, 1, 0x01, 0x3f800000 },
- { 0x0007f5, 1, 0x01, 0x3f800000 },
- { 0x0007dc, 1, 0x01, 0x39291909 },
- { 0x0007dd, 1, 0x01, 0x79695949 },
- { 0x0007de, 1, 0x01, 0xb9a99989 },
- { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007e8, 1, 0x01, 0x00003210 },
- { 0x0007e9, 1, 0x01, 0x00007654 },
- { 0x0007ea, 1, 0x01, 0x00000098 },
- { 0x0007ec, 1, 0x01, 0x39291909 },
- { 0x0007ed, 1, 0x01, 0x79695949 },
- { 0x0007ee, 1, 0x01, 0xb9a99989 },
- { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
- { 0x0007f0, 1, 0x01, 0x00003210 },
- { 0x0007f1, 1, 0x01, 0x00007654 },
- { 0x0007f2, 1, 0x01, 0x00000098 },
- { 0x0005a5, 1, 0x01, 0x00000001 },
- { 0x000980, 128, 0x01, 0x00000000 },
- { 0x000468, 1, 0x01, 0x00000004 },
- { 0x00046c, 1, 0x01, 0x00000001 },
- { 0x000470, 96, 0x01, 0x00000000 },
- { 0x000510, 16, 0x01, 0x3f800000 },
- { 0x000520, 1, 0x01, 0x000002b6 },
- { 0x000529, 1, 0x01, 0x00000001 },
- { 0x000530, 16, 0x01, 0xffff0000 },
- { 0x000585, 1, 0x01, 0x0000003f },
- { 0x000576, 1, 0x01, 0x00000003 },
- { 0x00057b, 1, 0x01, 0x00000059 },
- { 0x000586, 1, 0x01, 0x00000040 },
- { 0x000582, 2, 0x01, 0x00000080 },
- { 0x0005c2, 1, 0x01, 0x00000001 },
- { 0x000638, 2, 0x01, 0x00000001 },
- { 0x00063a, 1, 0x01, 0x00000002 },
- { 0x00063b, 2, 0x01, 0x00000001 },
- { 0x00063d, 1, 0x01, 0x00000002 },
- { 0x00063e, 1, 0x01, 0x00000001 },
- { 0x0008b8, 8, 0x01, 0x00000001 },
- { 0x000900, 8, 0x01, 0x00000001 },
- { 0x000908, 8, 0x01, 0x00000002 },
- { 0x000910, 16, 0x01, 0x00000001 },
- { 0x000920, 8, 0x01, 0x00000002 },
- { 0x000928, 8, 0x01, 0x00000001 },
- { 0x000662, 1, 0x01, 0x00000001 },
- { 0x000648, 9, 0x01, 0x00000001 },
- { 0x000658, 1, 0x01, 0x0000000f },
- { 0x0007ff, 1, 0x01, 0x0000000a },
- { 0x00066a, 1, 0x01, 0x40000000 },
- { 0x00066b, 1, 0x01, 0x10000000 },
- { 0x00066c, 2, 0x01, 0xffff0000 },
- { 0x0007af, 2, 0x01, 0x00000008 },
- { 0x0007f6, 1, 0x01, 0x00000001 },
- { 0x00080b, 1, 0x01, 0x00000002 },
- { 0x0006b2, 1, 0x01, 0x00000055 },
- { 0x0007ad, 1, 0x01, 0x00000003 },
- { 0x000937, 1, 0x01, 0x00000001 },
- { 0x000971, 1, 0x01, 0x00000008 },
- { 0x000972, 1, 0x01, 0x00000040 },
- { 0x000973, 1, 0x01, 0x0000012c },
- { 0x00097c, 1, 0x01, 0x00000040 },
- { 0x000979, 1, 0x01, 0x00000003 },
- { 0x000975, 1, 0x01, 0x00000020 },
- { 0x000976, 1, 0x01, 0x00000001 },
- { 0x000977, 1, 0x01, 0x00000020 },
- { 0x000978, 1, 0x01, 0x00000001 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x00095e, 1, 0x01, 0x20164010 },
- { 0x00095f, 1, 0x01, 0x00000020 },
- { 0x000a0d, 1, 0x01, 0x00000006 },
- { 0x00097d, 1, 0x01, 0x00000020 },
- { 0x000683, 1, 0x01, 0x00000006 },
- { 0x000685, 1, 0x01, 0x003fffff },
- { 0x000687, 1, 0x01, 0x003fffff },
- { 0x0006a0, 1, 0x01, 0x00000005 },
- { 0x000840, 1, 0x01, 0x00400008 },
- { 0x000841, 1, 0x01, 0x08000080 },
- { 0x000842, 1, 0x01, 0x00400008 },
- { 0x000843, 1, 0x01, 0x08000080 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ab, 1, 0x01, 0x00000002 },
- { 0x0006ac, 1, 0x01, 0x00000080 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x0006bb, 1, 0x01, 0x000000cf },
- { 0x0006ce, 1, 0x01, 0x2a712488 },
- { 0x000739, 1, 0x01, 0x4085c000 },
- { 0x00073a, 1, 0x01, 0x00000080 },
- { 0x000786, 1, 0x01, 0x80000100 },
- { 0x00073c, 1, 0x01, 0x00010100 },
- { 0x00073d, 1, 0x01, 0x02800000 },
- { 0x000787, 1, 0x01, 0x000000cf },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x000836, 1, 0x01, 0x00000001 },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c1b0, 8, 0x01, 0x0000000f },
- { 0x00c1b8, 1, 0x01, 0x0fac6881 },
- { 0x00c1b9, 1, 0x01, 0x00fac688 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x00c500, 1, 0x01, 0x00000003 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000002 },
- { 0x0006aa, 1, 0x01, 0x00000001 },
- { 0x0006ad, 2, 0x01, 0x00000100 },
- { 0x0006b1, 1, 0x01, 0x00000011 },
- { 0x00078c, 1, 0x01, 0x00000008 },
- { 0x000792, 1, 0x01, 0x00000001 },
- { 0x000794, 3, 0x01, 0x00000001 },
- { 0x000797, 1, 0x01, 0x000000cf },
- { 0x00079a, 1, 0x01, 0x00000002 },
- { 0x000833, 1, 0x01, 0x04444480 },
- { 0x0007a1, 1, 0x01, 0x00000001 },
- { 0x0007a3, 3, 0x01, 0x00000001 },
- { 0x000831, 1, 0x01, 0x00000004 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000008 },
- { 0x000039, 3, 0x01, 0x00000000 },
- { 0x000380, 1, 0x01, 0x00000001 },
- { 0x000366, 2, 0x01, 0x00000000 },
- { 0x000368, 1, 0x01, 0x00000fff },
- { 0x000370, 2, 0x01, 0x00000000 },
- { 0x000372, 1, 0x01, 0x000fffff },
- { 0x000813, 1, 0x01, 0x00000006 },
- { 0x000814, 1, 0x01, 0x00000008 },
- { 0x000957, 1, 0x01, 0x00000003 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x000a04, 1, 0x01, 0x000000ff },
- { 0x000a0b, 1, 0x01, 0x00000040 },
- { 0x00097f, 1, 0x01, 0x00000100 },
- { 0x000a02, 1, 0x01, 0x00000001 },
- { 0x000809, 1, 0x01, 0x00000007 },
- { 0x00c221, 1, 0x01, 0x00000040 },
- { 0x00c401, 1, 0x01, 0x00000001 },
- { 0x00c402, 1, 0x01, 0x00010001 },
- { 0x00c403, 2, 0x01, 0x00000001 },
- { 0x00c40e, 1, 0x01, 0x00000020 },
- { 0x00c500, 1, 0x01, 0x00000003 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- { 0x001000, 1, 0x01, 0x00000001 },
- { 0x000b07, 1, 0x01, 0x00000002 },
- { 0x000b08, 2, 0x01, 0x00000100 },
- { 0x000b0a, 1, 0x01, 0x00000001 },
- { 0x01e100, 1, 0x01, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_icmd[] = {
- { nvf0_grctx_init_icmd_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_a197_0[] = {
- { 0x000800, 8, 0x40, 0x00000000 },
- { 0x000804, 8, 0x40, 0x00000000 },
- { 0x000808, 8, 0x40, 0x00000400 },
- { 0x00080c, 8, 0x40, 0x00000300 },
- { 0x000810, 1, 0x04, 0x000000cf },
- { 0x000850, 7, 0x40, 0x00000000 },
- { 0x000814, 8, 0x40, 0x00000040 },
- { 0x000818, 8, 0x40, 0x00000001 },
- { 0x00081c, 8, 0x40, 0x00000000 },
- { 0x000820, 8, 0x40, 0x00000000 },
- { 0x001c00, 16, 0x10, 0x00000000 },
- { 0x001c04, 16, 0x10, 0x00000000 },
- { 0x001c08, 16, 0x10, 0x00000000 },
- { 0x001c0c, 16, 0x10, 0x00000000 },
- { 0x001d00, 16, 0x10, 0x00000000 },
- { 0x001d04, 16, 0x10, 0x00000000 },
- { 0x001d08, 16, 0x10, 0x00000000 },
- { 0x001d0c, 16, 0x10, 0x00000000 },
- { 0x001f00, 16, 0x08, 0x00000000 },
- { 0x001f04, 16, 0x08, 0x00000000 },
- { 0x001f80, 16, 0x08, 0x00000000 },
- { 0x001f84, 16, 0x08, 0x00000000 },
- { 0x002000, 1, 0x04, 0x00000000 },
- { 0x002040, 1, 0x04, 0x00000011 },
- { 0x002080, 1, 0x04, 0x00000020 },
- { 0x0020c0, 1, 0x04, 0x00000030 },
- { 0x002100, 1, 0x04, 0x00000040 },
- { 0x002140, 1, 0x04, 0x00000051 },
- { 0x00200c, 6, 0x40, 0x00000001 },
- { 0x002010, 1, 0x04, 0x00000000 },
- { 0x002050, 1, 0x04, 0x00000000 },
- { 0x002090, 1, 0x04, 0x00000001 },
- { 0x0020d0, 1, 0x04, 0x00000002 },
- { 0x002110, 1, 0x04, 0x00000003 },
- { 0x002150, 1, 0x04, 0x00000004 },
- { 0x000380, 4, 0x20, 0x00000000 },
- { 0x000384, 4, 0x20, 0x00000000 },
- { 0x000388, 4, 0x20, 0x00000000 },
- { 0x00038c, 4, 0x20, 0x00000000 },
- { 0x000700, 4, 0x10, 0x00000000 },
- { 0x000704, 4, 0x10, 0x00000000 },
- { 0x000708, 4, 0x10, 0x00000000 },
- { 0x002800, 128, 0x04, 0x00000000 },
- { 0x000a00, 16, 0x20, 0x00000000 },
- { 0x000a04, 16, 0x20, 0x00000000 },
- { 0x000a08, 16, 0x20, 0x00000000 },
- { 0x000a0c, 16, 0x20, 0x00000000 },
- { 0x000a10, 16, 0x20, 0x00000000 },
- { 0x000a14, 16, 0x20, 0x00000000 },
- { 0x000c00, 16, 0x10, 0x00000000 },
- { 0x000c04, 16, 0x10, 0x00000000 },
- { 0x000c08, 16, 0x10, 0x00000000 },
- { 0x000c0c, 16, 0x10, 0x3f800000 },
- { 0x000d00, 8, 0x08, 0xffff0000 },
- { 0x000d04, 8, 0x08, 0xffff0000 },
- { 0x000e00, 16, 0x10, 0x00000000 },
- { 0x000e04, 16, 0x10, 0xffff0000 },
- { 0x000e08, 16, 0x10, 0xffff0000 },
- { 0x000d40, 4, 0x08, 0x00000000 },
- { 0x000d44, 4, 0x08, 0x00000000 },
- { 0x001e00, 8, 0x20, 0x00000001 },
- { 0x001e04, 8, 0x20, 0x00000001 },
- { 0x001e08, 8, 0x20, 0x00000002 },
- { 0x001e0c, 8, 0x20, 0x00000001 },
- { 0x001e10, 8, 0x20, 0x00000001 },
- { 0x001e14, 8, 0x20, 0x00000002 },
- { 0x001e18, 8, 0x20, 0x00000001 },
- { 0x003400, 128, 0x04, 0x00000000 },
- { 0x00030c, 1, 0x04, 0x00000001 },
- { 0x001944, 1, 0x04, 0x00000000 },
- { 0x001514, 1, 0x04, 0x00000000 },
- { 0x000d68, 1, 0x04, 0x0000ffff },
- { 0x00121c, 1, 0x04, 0x0fac6881 },
- { 0x000fac, 1, 0x04, 0x00000001 },
- { 0x001538, 1, 0x04, 0x00000001 },
- { 0x000fe0, 2, 0x04, 0x00000000 },
- { 0x000fe8, 1, 0x04, 0x00000014 },
- { 0x000fec, 1, 0x04, 0x00000040 },
- { 0x000ff0, 1, 0x04, 0x00000000 },
- { 0x00179c, 1, 0x04, 0x00000000 },
- { 0x001228, 1, 0x04, 0x00000400 },
- { 0x00122c, 1, 0x04, 0x00000300 },
- { 0x001230, 1, 0x04, 0x00010001 },
- { 0x0007f8, 1, 0x04, 0x00000000 },
- { 0x0015b4, 1, 0x04, 0x00000001 },
- { 0x0015cc, 1, 0x04, 0x00000000 },
- { 0x001534, 1, 0x04, 0x00000000 },
- { 0x000fb0, 1, 0x04, 0x00000000 },
- { 0x0015d0, 1, 0x04, 0x00000000 },
- { 0x00153c, 1, 0x04, 0x00000000 },
- { 0x0016b4, 1, 0x04, 0x00000003 },
- { 0x000fbc, 4, 0x04, 0x0000ffff },
- { 0x000df8, 2, 0x04, 0x00000000 },
- { 0x001948, 1, 0x04, 0x00000000 },
- { 0x001970, 1, 0x04, 0x00000001 },
- { 0x00161c, 1, 0x04, 0x000009f0 },
- { 0x000dcc, 1, 0x04, 0x00000010 },
- { 0x00163c, 1, 0x04, 0x00000000 },
- { 0x0015e4, 1, 0x04, 0x00000000 },
- { 0x001160, 32, 0x04, 0x25e00040 },
- { 0x001880, 32, 0x04, 0x00000000 },
- { 0x000f84, 2, 0x04, 0x00000000 },
- { 0x0017c8, 2, 0x04, 0x00000000 },
- { 0x0017d0, 1, 0x04, 0x000000ff },
- { 0x0017d4, 1, 0x04, 0xffffffff },
- { 0x0017d8, 1, 0x04, 0x00000002 },
- { 0x0017dc, 1, 0x04, 0x00000000 },
- { 0x0015f4, 2, 0x04, 0x00000000 },
- { 0x001434, 2, 0x04, 0x00000000 },
- { 0x000d74, 1, 0x04, 0x00000000 },
- { 0x000dec, 1, 0x04, 0x00000001 },
- { 0x0013a4, 1, 0x04, 0x00000000 },
- { 0x001318, 1, 0x04, 0x00000001 },
- { 0x001644, 1, 0x04, 0x00000000 },
- { 0x000748, 1, 0x04, 0x00000000 },
- { 0x000de8, 1, 0x04, 0x00000000 },
- { 0x001648, 1, 0x04, 0x00000000 },
- { 0x0012a4, 1, 0x04, 0x00000000 },
- { 0x001120, 4, 0x04, 0x00000000 },
- { 0x001118, 1, 0x04, 0x00000000 },
- { 0x00164c, 1, 0x04, 0x00000000 },
- { 0x001658, 1, 0x04, 0x00000000 },
- { 0x001910, 1, 0x04, 0x00000290 },
- { 0x001518, 1, 0x04, 0x00000000 },
- { 0x00165c, 1, 0x04, 0x00000001 },
- { 0x001520, 1, 0x04, 0x00000000 },
- { 0x001604, 1, 0x04, 0x00000000 },
- { 0x001570, 1, 0x04, 0x00000000 },
- { 0x0013b0, 2, 0x04, 0x3f800000 },
- { 0x00020c, 1, 0x04, 0x00000000 },
- { 0x001670, 1, 0x04, 0x30201000 },
- { 0x001674, 1, 0x04, 0x70605040 },
- { 0x001678, 1, 0x04, 0xb8a89888 },
- { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
- { 0x00166c, 1, 0x04, 0x00000000 },
- { 0x001680, 1, 0x04, 0x00ffff00 },
- { 0x0012d0, 1, 0x04, 0x00000003 },
- { 0x0012d4, 1, 0x04, 0x00000002 },
- { 0x001684, 2, 0x04, 0x00000000 },
- { 0x000dac, 2, 0x04, 0x00001b02 },
- { 0x000db4, 1, 0x04, 0x00000000 },
- { 0x00168c, 1, 0x04, 0x00000000 },
- { 0x0015bc, 1, 0x04, 0x00000000 },
- { 0x00156c, 1, 0x04, 0x00000000 },
- { 0x00187c, 1, 0x04, 0x00000000 },
- { 0x001110, 1, 0x04, 0x00000001 },
- { 0x000dc0, 3, 0x04, 0x00000000 },
- { 0x001234, 1, 0x04, 0x00000000 },
- { 0x001690, 1, 0x04, 0x00000000 },
- { 0x0012ac, 1, 0x04, 0x00000001 },
- { 0x0002c4, 1, 0x04, 0x00000000 },
- { 0x000790, 5, 0x04, 0x00000000 },
- { 0x00077c, 1, 0x04, 0x00000000 },
- { 0x001000, 1, 0x04, 0x00000010 },
- { 0x0010fc, 1, 0x04, 0x00000000 },
- { 0x001290, 1, 0x04, 0x00000000 },
- { 0x000218, 1, 0x04, 0x00000010 },
- { 0x0012d8, 1, 0x04, 0x00000000 },
- { 0x0012dc, 1, 0x04, 0x00000010 },
- { 0x000d94, 1, 0x04, 0x00000001 },
- { 0x00155c, 2, 0x04, 0x00000000 },
- { 0x001564, 1, 0x04, 0x00000fff },
- { 0x001574, 2, 0x04, 0x00000000 },
- { 0x00157c, 1, 0x04, 0x000fffff },
- { 0x001354, 1, 0x04, 0x00000000 },
- { 0x001610, 1, 0x04, 0x00000012 },
- { 0x001608, 2, 0x04, 0x00000000 },
- { 0x00260c, 1, 0x04, 0x00000000 },
- { 0x0007ac, 1, 0x04, 0x00000000 },
- { 0x00162c, 1, 0x04, 0x00000003 },
- { 0x000210, 1, 0x04, 0x00000000 },
- { 0x000320, 1, 0x04, 0x00000000 },
- { 0x000324, 6, 0x04, 0x3f800000 },
- { 0x000750, 1, 0x04, 0x00000000 },
- { 0x000760, 1, 0x04, 0x39291909 },
- { 0x000764, 1, 0x04, 0x79695949 },
- { 0x000768, 1, 0x04, 0xb9a99989 },
- { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
- { 0x000770, 1, 0x04, 0x30201000 },
- { 0x000774, 1, 0x04, 0x70605040 },
- { 0x000778, 1, 0x04, 0x00009080 },
- { 0x000780, 1, 0x04, 0x39291909 },
- { 0x000784, 1, 0x04, 0x79695949 },
- { 0x000788, 1, 0x04, 0xb9a99989 },
- { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
- { 0x0007d0, 1, 0x04, 0x30201000 },
- { 0x0007d4, 1, 0x04, 0x70605040 },
- { 0x0007d8, 1, 0x04, 0x00009080 },
- { 0x00037c, 1, 0x04, 0x00000001 },
- { 0x000740, 2, 0x04, 0x00000000 },
- { 0x002600, 1, 0x04, 0x00000000 },
- { 0x001918, 1, 0x04, 0x00000000 },
- { 0x00191c, 1, 0x04, 0x00000900 },
- { 0x001920, 1, 0x04, 0x00000405 },
- { 0x001308, 1, 0x04, 0x00000001 },
- { 0x001924, 1, 0x04, 0x00000000 },
- { 0x0013ac, 1, 0x04, 0x00000000 },
- { 0x00192c, 1, 0x04, 0x00000001 },
- { 0x00193c, 1, 0x04, 0x00002c1c },
- { 0x000d7c, 1, 0x04, 0x00000000 },
- { 0x000f8c, 1, 0x04, 0x00000000 },
- { 0x0002c0, 1, 0x04, 0x00000001 },
- { 0x001510, 1, 0x04, 0x00000000 },
- { 0x001940, 1, 0x04, 0x00000000 },
- { 0x000ff4, 2, 0x04, 0x00000000 },
- { 0x00194c, 2, 0x04, 0x00000000 },
- { 0x001968, 1, 0x04, 0x00000000 },
- { 0x001590, 1, 0x04, 0x0000003f },
- { 0x0007e8, 4, 0x04, 0x00000000 },
- { 0x00196c, 1, 0x04, 0x00000011 },
- { 0x0002e4, 1, 0x04, 0x0000b001 },
- { 0x00036c, 2, 0x04, 0x00000000 },
- { 0x00197c, 1, 0x04, 0x00000000 },
- { 0x000fcc, 2, 0x04, 0x00000000 },
- { 0x0002d8, 1, 0x04, 0x00000040 },
- { 0x001980, 1, 0x04, 0x00000080 },
- { 0x001504, 1, 0x04, 0x00000080 },
- { 0x001984, 1, 0x04, 0x00000000 },
- { 0x000300, 1, 0x04, 0x00000001 },
- { 0x0013a8, 1, 0x04, 0x00000000 },
- { 0x0012ec, 1, 0x04, 0x00000000 },
- { 0x001310, 1, 0x04, 0x00000000 },
- { 0x001314, 1, 0x04, 0x00000001 },
- { 0x001380, 1, 0x04, 0x00000000 },
- { 0x001384, 4, 0x04, 0x00000001 },
- { 0x001394, 1, 0x04, 0x00000000 },
- { 0x00139c, 1, 0x04, 0x00000000 },
- { 0x001398, 1, 0x04, 0x00000000 },
- { 0x001594, 1, 0x04, 0x00000000 },
- { 0x001598, 4, 0x04, 0x00000001 },
- { 0x000f54, 3, 0x04, 0x00000000 },
- { 0x0019bc, 1, 0x04, 0x00000000 },
- { 0x000f9c, 2, 0x04, 0x00000000 },
- { 0x0012cc, 1, 0x04, 0x00000000 },
- { 0x0012e8, 1, 0x04, 0x00000000 },
- { 0x00130c, 1, 0x04, 0x00000001 },
- { 0x001360, 8, 0x04, 0x00000000 },
- { 0x00133c, 2, 0x04, 0x00000001 },
- { 0x001344, 1, 0x04, 0x00000002 },
- { 0x001348, 2, 0x04, 0x00000001 },
- { 0x001350, 1, 0x04, 0x00000002 },
- { 0x001358, 1, 0x04, 0x00000001 },
- { 0x0012e4, 1, 0x04, 0x00000000 },
- { 0x00131c, 4, 0x04, 0x00000000 },
- { 0x0019c0, 1, 0x04, 0x00000000 },
- { 0x001140, 1, 0x04, 0x00000000 },
- { 0x0019c4, 1, 0x04, 0x00000000 },
- { 0x0019c8, 1, 0x04, 0x00001500 },
- { 0x00135c, 1, 0x04, 0x00000000 },
- { 0x000f90, 1, 0x04, 0x00000000 },
- { 0x0019e0, 8, 0x04, 0x00000001 },
- { 0x0019cc, 1, 0x04, 0x00000001 },
- { 0x0015b8, 1, 0x04, 0x00000000 },
- { 0x001a00, 1, 0x04, 0x00001111 },
- { 0x001a04, 7, 0x04, 0x00000000 },
- { 0x000d6c, 2, 0x04, 0xffff0000 },
- { 0x0010f8, 1, 0x04, 0x00001010 },
- { 0x000d80, 5, 0x04, 0x00000000 },
- { 0x000da0, 1, 0x04, 0x00000000 },
- { 0x0007a4, 2, 0x04, 0x00000000 },
- { 0x001508, 1, 0x04, 0x80000000 },
- { 0x00150c, 1, 0x04, 0x40000000 },
- { 0x001668, 1, 0x04, 0x00000000 },
- { 0x000318, 2, 0x04, 0x00000008 },
- { 0x000d9c, 1, 0x04, 0x00000001 },
- { 0x000ddc, 1, 0x04, 0x00000002 },
- { 0x000374, 1, 0x04, 0x00000000 },
- { 0x000378, 1, 0x04, 0x00000020 },
- { 0x0007dc, 1, 0x04, 0x00000000 },
- { 0x00074c, 1, 0x04, 0x00000055 },
- { 0x001420, 1, 0x04, 0x00000003 },
- { 0x0017bc, 2, 0x04, 0x00000000 },
- { 0x0017c4, 1, 0x04, 0x00000001 },
- { 0x001008, 1, 0x04, 0x00000008 },
- { 0x00100c, 1, 0x04, 0x00000040 },
- { 0x001010, 1, 0x04, 0x0000012c },
- { 0x000d60, 1, 0x04, 0x00000040 },
- { 0x00075c, 1, 0x04, 0x00000003 },
- { 0x001018, 1, 0x04, 0x00000020 },
- { 0x00101c, 1, 0x04, 0x00000001 },
- { 0x001020, 1, 0x04, 0x00000020 },
- { 0x001024, 1, 0x04, 0x00000001 },
- { 0x001444, 3, 0x04, 0x00000000 },
- { 0x000360, 1, 0x04, 0x20164010 },
- { 0x000364, 1, 0x04, 0x00000020 },
- { 0x000368, 1, 0x04, 0x00000000 },
- { 0x000de4, 1, 0x04, 0x00000000 },
- { 0x000204, 1, 0x04, 0x00000006 },
- { 0x000208, 1, 0x04, 0x00000000 },
- { 0x0002cc, 2, 0x04, 0x003fffff },
- { 0x001220, 1, 0x04, 0x00000005 },
- { 0x000fdc, 1, 0x04, 0x00000000 },
- { 0x000f98, 1, 0x04, 0x00400008 },
- { 0x001284, 1, 0x04, 0x08000080 },
- { 0x001450, 1, 0x04, 0x00400008 },
- { 0x001454, 1, 0x04, 0x08000080 },
- { 0x000214, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_mthd[] = {
- { nvf0_grctx_init_a197_0, 0xa197 },
- { nvc0_grctx_init_902d_0, 0x902d },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_fe_0[] = {
- { 0x404004, 8, 0x04, 0x00000000 },
- { 0x404024, 1, 0x04, 0x0000e000 },
- { 0x404028, 8, 0x04, 0x00000000 },
- { 0x4040a8, 8, 0x04, 0x00000000 },
- { 0x4040c8, 1, 0x04, 0xf800008f },
- { 0x4040d0, 6, 0x04, 0x00000000 },
- { 0x4040e8, 1, 0x04, 0x00001000 },
- { 0x4040f8, 1, 0x04, 0x00000000 },
- { 0x404100, 10, 0x04, 0x00000000 },
- { 0x404130, 2, 0x04, 0x00000000 },
- { 0x404138, 1, 0x04, 0x20000040 },
- { 0x404150, 1, 0x04, 0x0000002e },
- { 0x404154, 1, 0x04, 0x00000400 },
- { 0x404158, 1, 0x04, 0x00000200 },
- { 0x404164, 1, 0x04, 0x00000055 },
- { 0x40417c, 2, 0x04, 0x00000000 },
- { 0x4041a0, 4, 0x04, 0x00000000 },
- { 0x404200, 1, 0x04, 0x0000a197 },
- { 0x404204, 1, 0x04, 0x0000a1c0 },
- { 0x404208, 1, 0x04, 0x0000a140 },
- { 0x40420c, 1, 0x04, 0x0000902d },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_pri_0[] = {
- { 0x404404, 12, 0x04, 0x00000000 },
- { 0x404438, 1, 0x04, 0x00000000 },
- { 0x404460, 2, 0x04, 0x00000000 },
- { 0x404468, 1, 0x04, 0x00ffffff },
- { 0x40446c, 1, 0x04, 0x00000000 },
- { 0x404480, 1, 0x04, 0x00000001 },
- { 0x404498, 1, 0x04, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_cwd_0[] = {
- { 0x405b00, 1, 0x04, 0x00000000 },
- { 0x405b10, 1, 0x04, 0x00001000 },
- { 0x405b20, 1, 0x04, 0x04000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_pd_0[] = {
- { 0x406020, 1, 0x04, 0x034103c1 },
- { 0x406028, 4, 0x04, 0x00000001 },
- { 0x4064a8, 1, 0x04, 0x00000000 },
- { 0x4064ac, 1, 0x04, 0x00003fff },
- { 0x4064b0, 3, 0x04, 0x00000000 },
- { 0x4064c0, 1, 0x04, 0x802000f0 },
- { 0x4064c4, 1, 0x04, 0x0192ffff },
- { 0x4064c8, 1, 0x04, 0x018007c0 },
- { 0x4064cc, 9, 0x04, 0x00000000 },
- { 0x4064fc, 1, 0x04, 0x0000022a },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_be_0[] = {
- { 0x408800, 1, 0x04, 0x12802a3c },
- { 0x408804, 1, 0x04, 0x00000040 },
- { 0x408808, 1, 0x04, 0x1003e005 },
- { 0x408840, 1, 0x04, 0x0000000b },
- { 0x408900, 1, 0x04, 0x3080b801 },
- { 0x408904, 1, 0x04, 0x62000001 },
- { 0x408908, 1, 0x04, 0x00c8102f },
- { 0x408980, 1, 0x04, 0x0000011d },
- {}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_hub[] = {
- { nvc0_grctx_init_main_0 },
- { nvf0_grctx_init_fe_0 },
- { nvf0_grctx_init_pri_0 },
- { nve4_grctx_init_memfmt_0 },
- { nve4_grctx_init_ds_0 },
- { nvf0_grctx_init_cwd_0 },
- { nvf0_grctx_init_pd_0 },
- { nvc0_grctx_init_rstr2d_0 },
- { nve4_grctx_init_scc_0 },
- { nvf0_grctx_init_be_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_setup_0[] = {
- { 0x418800, 1, 0x04, 0x7006860a },
- { 0x418808, 1, 0x04, 0x00000000 },
- { 0x41880c, 1, 0x04, 0x00000030 },
- { 0x418810, 1, 0x04, 0x00000000 },
- { 0x418828, 1, 0x04, 0x00000044 },
- { 0x418830, 1, 0x04, 0x10000001 },
- { 0x4188d8, 1, 0x04, 0x00000008 },
- { 0x4188e0, 1, 0x04, 0x01000000 },
- { 0x4188e8, 5, 0x04, 0x00000000 },
- { 0x4188fc, 1, 0x04, 0x20100018 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_gpc_unk_2[] = {
- { 0x418d24, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_gpc[] = {
- { nvc0_grctx_init_gpc_unk_0 },
- { nvd9_grctx_init_prop_0 },
- { nvd9_grctx_init_gpc_unk_1 },
- { nvf0_grctx_init_setup_0 },
- { nvc0_grctx_init_zcull_0 },
- { nvd9_grctx_init_crstr_0 },
- { nve4_grctx_init_gpm_0 },
- { nvf0_grctx_init_gpc_unk_2 },
- { nvc0_grctx_init_gcc_0 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_tex_0[] = {
- { 0x419a00, 1, 0x04, 0x000000f0 },
- { 0x419a04, 1, 0x04, 0x00000001 },
- { 0x419a08, 1, 0x04, 0x00000021 },
- { 0x419a0c, 1, 0x04, 0x00020000 },
- { 0x419a10, 1, 0x04, 0x00000000 },
- { 0x419a14, 1, 0x04, 0x00000200 },
- { 0x419a1c, 1, 0x04, 0x0000c000 },
- { 0x419a20, 1, 0x04, 0x00020800 },
- { 0x419a30, 1, 0x04, 0x00000001 },
- { 0x419ac4, 1, 0x04, 0x0037f440 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_mpc_0[] = {
- { 0x419c00, 1, 0x04, 0x0000001a },
- { 0x419c04, 1, 0x04, 0x80000006 },
- { 0x419c08, 1, 0x04, 0x00000002 },
- { 0x419c20, 1, 0x04, 0x00000000 },
- { 0x419c24, 1, 0x04, 0x00084210 },
- { 0x419c28, 1, 0x04, 0x3efbefbe },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_grctx_init_l1c_0[] = {
- { 0x419ce8, 1, 0x04, 0x00000000 },
- { 0x419cf4, 1, 0x04, 0x00000203 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_sm_0[] = {
- { 0x419e04, 1, 0x04, 0x00000000 },
- { 0x419e08, 1, 0x04, 0x0000001d },
- { 0x419e0c, 1, 0x04, 0x00000000 },
- { 0x419e10, 1, 0x04, 0x00001c02 },
- { 0x419e44, 1, 0x04, 0x0013eff2 },
- { 0x419e48, 1, 0x04, 0x00000000 },
- { 0x419e4c, 1, 0x04, 0x0000007f },
- { 0x419e50, 2, 0x04, 0x00000000 },
- { 0x419e58, 1, 0x04, 0x00000001 },
- { 0x419e5c, 3, 0x04, 0x00000000 },
- { 0x419e68, 1, 0x04, 0x00000002 },
- { 0x419e6c, 12, 0x04, 0x00000000 },
- { 0x419eac, 1, 0x04, 0x00001f8f },
- { 0x419eb0, 1, 0x04, 0x0db00d2f },
- { 0x419eb8, 1, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x0001304f },
- { 0x419f30, 4, 0x04, 0x00000000 },
- { 0x419f40, 1, 0x04, 0x00000018 },
- { 0x419f44, 3, 0x04, 0x00000000 },
- { 0x419f58, 1, 0x04, 0x00000000 },
- { 0x419f70, 1, 0x04, 0x00007300 },
- { 0x419f78, 1, 0x04, 0x000000eb },
- { 0x419f7c, 1, 0x04, 0x00000404 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvf0_grctx_pack_tpc[] = {
- { nvd7_grctx_init_pe_0 },
- { nvf0_grctx_init_tex_0 },
- { nvf0_grctx_init_mpc_0 },
- { nvf0_grctx_init_l1c_0 },
- { nvf0_grctx_init_sm_0 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_grctx_init_cbm_0[] = {
- { 0x41bec0, 1, 0x04, 0x10000000 },
- { 0x41bec4, 1, 0x04, 0x00037f7f },
- { 0x41bee4, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_pack
-nvf0_grctx_pack_ppc[] = {
- { nve4_grctx_init_pes_0 },
- { nvf0_grctx_init_cbm_0 },
- { nvd7_grctx_init_wwdx_0 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context implementation
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvf0_grctx_oclass = &(struct nvc0_grctx_oclass) {
- .base.handle = NV_ENGCTX(GR, 0xf0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_context_ctor,
- .dtor = nvc0_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
- .main = nve4_grctx_generate_main,
- .unkn = nve4_grctx_generate_unkn,
- .hub = nvf0_grctx_pack_hub,
- .gpc = nvf0_grctx_pack_gpc,
- .zcull = nvc0_grctx_pack_zcull,
- .tpc = nvf0_grctx_pack_tpc,
- .ppc = nvf0_grctx_pack_ppc,
- .icmd = nvf0_grctx_pack_icmd,
- .mthd = nvf0_grctx_pack_mthd,
- .bundle = nve4_grctx_generate_bundle,
- .bundle_size = 0x3000,
- .bundle_min_gpm_fifo_depth = 0x180,
- .bundle_token_limit = 0x7c0,
- .pagepool = nve4_grctx_generate_pagepool,
- .pagepool_size = 0x8000,
- .attrib = nvd7_grctx_generate_attrib,
- .attrib_nr_max = 0x324,
- .attrib_nr = 0x218,
- .alpha_nr_max = 0x7ff,
- .alpha_nr = 0x648,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
deleted file mode 100644
index e37d8106ae1a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/com.fuc
+++ /dev/null
@@ -1,335 +0,0 @@
-/* fuc microcode util functions for nvc0 PGRAPH
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifdef INCLUDE_CODE
-// queue_put - add request to queue
-//
-// In : $r13 queue pointer
-// $r14 command
-// $r15 data
-//
-queue_put:
- // make sure we have space..
- ld b32 $r8 D[$r13 + 0x0] // GET
- ld b32 $r9 D[$r13 + 0x4] // PUT
- xor $r8 8
- cmpu b32 $r8 $r9
- bra ne #queue_put_next
- mov $r15 E_CMD_OVERFLOW
- call(error)
- ret
-
- // store cmd/data on queue
- queue_put_next:
- and $r8 $r9 7
- shl b32 $r8 3
- add b32 $r8 $r13
- add b32 $r8 8
- st b32 D[$r8 + 0x0] $r14
- st b32 D[$r8 + 0x4] $r15
-
- // update PUT
- add b32 $r9 1
- and $r9 0xf
- st b32 D[$r13 + 0x4] $r9
- ret
-
-// queue_get - fetch request from queue
-//
-// In : $r13 queue pointer
-//
-// Out: $p1 clear on success (data available)
-// $r14 command
-// $r15 data
-//
-queue_get:
- bset $flags $p1
- ld b32 $r8 D[$r13 + 0x0] // GET
- ld b32 $r9 D[$r13 + 0x4] // PUT
- cmpu b32 $r8 $r9
- bra e #queue_get_done
- // fetch first cmd/data pair
- and $r9 $r8 7
- shl b32 $r9 3
- add b32 $r9 $r13
- add b32 $r9 8
- ld b32 $r14 D[$r9 + 0x0]
- ld b32 $r15 D[$r9 + 0x4]
-
- // update GET
- add b32 $r8 1
- and $r8 0xf
- st b32 D[$r13 + 0x0] $r8
- bclr $flags $p1
-queue_get_done:
- ret
-
-// nv_rd32 - read 32-bit value from nv register
-//
-// In : $r14 register
-// Out: $r15 value
-//
-nv_rd32:
- mov b32 $r12 $r14
- bset $r12 31 // MMIO_CTRL_PENDING
- nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
- nv_rd32_wait:
- nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
- xbit $r12 $r12 31
- bra ne #nv_rd32_wait
- mov $r10 6 // DONE_MMIO_RD
- call(wait_doneo)
- nv_iord($r15, NV_PGRAPH_FECS_MMIO_RDVAL, 0)
- ret
-
-// nv_wr32 - write 32-bit value to nv register
-//
-// In : $r14 register
-// $r15 value
-//
-nv_wr32:
- nv_iowr(NV_PGRAPH_FECS_MMIO_WRVAL, 0, $r15)
- mov b32 $r12 $r14
- bset $r12 31 // MMIO_CTRL_PENDING
- bset $r12 30 // MMIO_CTRL_WRITE
- nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
- nv_wr32_wait:
- nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
- xbit $r12 $r12 31
- bra ne #nv_wr32_wait
- ret
-
-// wait_donez - wait on FUC_DONE bit to become clear
-//
-// In : $r10 bit to wait on
-//
-wait_donez:
- trace_set(T_WAIT);
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
- wait_donez_ne:
- nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
- xbit $r8 $r8 $r10
- bra ne #wait_donez_ne
- trace_clr(T_WAIT)
- ret
-
-// wait_doneo - wait on FUC_DONE bit to become set
-//
-// In : $r10 bit to wait on
-//
-wait_doneo:
- trace_set(T_WAIT);
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
- wait_doneo_e:
- nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
- xbit $r8 $r8 $r10
- bra e #wait_doneo_e
- trace_clr(T_WAIT)
- ret
-
-// mmctx_size - determine size of a mmio list transfer
-//
-// In : $r14 mmio list head
-// $r15 mmio list tail
-// Out: $r15 transfer size (in bytes)
-//
-mmctx_size:
- clear b32 $r9
- nv_mmctx_size_loop:
- ld b32 $r8 D[$r14]
- shr b32 $r8 26
- add b32 $r8 1
- shl b32 $r8 2
- add b32 $r9 $r8
- add b32 $r14 4
- cmpu b32 $r14 $r15
- bra ne #nv_mmctx_size_loop
- mov b32 $r15 $r9
- ret
-
-// mmctx_xfer - execute a list of mmio transfers
-//
-// In : $r10 flags
-// bit 0: direction (0 = save, 1 = load)
-// bit 1: set if first transfer
-// bit 2: set if last transfer
-// $r11 base
-// $r12 mmio list head
-// $r13 mmio list tail
-// $r14 multi_stride
-// $r15 multi_mask
-//
-mmctx_xfer:
- trace_set(T_MMCTX)
- clear b32 $r9
- or $r11 $r11
- bra e #mmctx_base_disabled
- nv_iowr(NV_PGRAPH_FECS_MMCTX_BASE, 0, $r11)
- bset $r9 0 // BASE_EN
- mmctx_base_disabled:
- or $r14 $r14
- bra e #mmctx_multi_disabled
- nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE, 0, $r14)
- nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_MASK, 0, $r15)
- bset $r9 1 // MULTI_EN
- mmctx_multi_disabled:
-
- xbit $r11 $r10 0
- shl b32 $r11 16 // DIR
- bset $r11 12 // QLIMIT = 0x10
- xbit $r14 $r10 1
- shl b32 $r14 17
- or $r11 $r14 // START_TRIGGER
- nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
-
- // loop over the mmio list, and send requests to the hw
- mmctx_exec_loop:
- // wait for space in mmctx queue
- mmctx_wait_free:
- nv_iord($r14, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
- and $r14 0x1f
- bra e #mmctx_wait_free
-
- // queue up an entry
- ld b32 $r14 D[$r12]
- or $r14 $r9
- nv_iowr(NV_PGRAPH_FECS_MMCTX_QUEUE, 0, $r14)
- add b32 $r12 4
- cmpu b32 $r12 $r13
- bra ne #mmctx_exec_loop
-
- xbit $r11 $r10 2
- bra ne #mmctx_stop
- // wait for queue to empty
- mmctx_fini_wait:
- nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
- and $r11 0x1f
- cmpu b32 $r11 0x10
- bra ne #mmctx_fini_wait
- mov $r10 5 // DONE_MMCTX
- call(wait_donez)
- bra #mmctx_done
- mmctx_stop:
- xbit $r11 $r10 0
- shl b32 $r11 16 // DIR
- bset $r11 12 // QLIMIT = 0x10
- bset $r11 18 // STOP_TRIGGER
- nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
- mmctx_stop_wait:
- // wait for STOP_TRIGGER to clear
- nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
- xbit $r11 $r11 18
- bra ne #mmctx_stop_wait
- mmctx_done:
- trace_clr(T_MMCTX)
- ret
-
-// Wait for DONE_STRAND
-//
-strand_wait:
- push $r10
- mov $r10 2
- call(wait_donez)
- pop $r10
- ret
-
-// unknown - call before issuing strand commands
-//
-strand_pre:
- mov $r9 NV_PGRAPH_FECS_STRAND_CMD_ENABLE
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
- call(strand_wait)
- ret
-
-// unknown - call after issuing strand commands
-//
-strand_post:
- mov $r9 NV_PGRAPH_FECS_STRAND_CMD_DISABLE
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
- call(strand_wait)
- ret
-
-// Selects strand set?!
-//
-// In: $r14 id
-//
-strand_set:
- mov $r12 0xf
- nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r12)
- mov $r12 NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
- nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r14)
- mov $r12 NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
- call(strand_wait)
- ret
-
-// Initialise strand context data
-//
-// In : $r15 context base
-// Out: $r15 context size (in bytes)
-//
-// Strandset(?) 3 hardcoded currently
-//
-strand_ctx_init:
- trace_set(T_STRINIT)
- call(strand_pre)
- mov $r14 3
- call(strand_set)
-
- clear b32 $r12
- nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r12)
- mov $r12 NV_PGRAPH_FECS_STRAND_CMD_SEEK
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
- call(strand_wait)
- sub b32 $r12 $r0 1
- nv_iowr(NV_PGRAPH_FECS_STRAND_DATA, 0x3f, $r12)
- mov $r12 NV_PGRAPH_FECS_STRAND_CMD_GET_INFO
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
- call(strand_wait)
- call(strand_post)
-
- // read the size of each strand, poke the context offset of
- // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
- // about it later then.
- nv_mkio($r8, NV_PGRAPH_FECS_STRAND_SAVE_SWBASE, 0x00)
- nv_iord($r9, NV_PGRAPH_FECS_STRANDS_CNT, 0x00)
- shr b32 $r14 $r15 8
- ctx_init_strand_loop:
- iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE
- iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE
- iord $r10 I[$r8 + 0x200] // STRAND_SIZE
- shr b32 $r10 6
- add b32 $r10 1
- add b32 $r14 $r10
- add b32 $r8 4
- sub b32 $r9 1
- bra ne #ctx_init_strand_loop
-
- shl b32 $r14 8
- sub b32 $r15 $r14 $r15
- trace_clr(T_STRINIT)
- ret
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
deleted file mode 100644
index 7445f12b1d9e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpc.fuc
+++ /dev/null
@@ -1,378 +0,0 @@
-/* fuc microcode for nvc0 PGRAPH/GPC
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-/* TODO
- * - bracket certain functions with scratch writes, useful for debugging
- * - watchdog timer around ctx operations
- */
-
-#ifdef INCLUDE_DATA
-gpc_mmio_list_head: .b32 #mmio_list_base
-gpc_mmio_list_tail:
-tpc_mmio_list_head: .b32 #mmio_list_base
-tpc_mmio_list_tail:
-unk_mmio_list_head: .b32 #mmio_list_base
-unk_mmio_list_tail: .b32 #mmio_list_base
-
-gpc_id: .b32 0
-
-tpc_count: .b32 0
-tpc_mask: .b32 0
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
-unk_count: .b32 0
-unk_mask: .b32 0
-#endif
-
-cmd_queue: queue_init
-
-mmio_list_base:
-#endif
-
-#ifdef INCLUDE_CODE
-// reports an exception to the host
-//
-// In: $r15 error code (see os.h)
-//
-error:
- push $r14
- nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)
- mov $r15 1
- nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)
- pop $r14
- ret
-
-// GPC fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Input:
-// CC_SCRATCH[1]: context base
-//
-// Output:
-// CC_SCRATCH[0]:
-// 31:31: set to signal completion
-// CC_SCRATCH[1]:
-// 31:0: GPC context size
-//
-init:
- clear b32 $r0
-
- // setup stack
- nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)
- extr $r1 $r1 9:17
- shl b32 $r1 8
- mov $sp $r1
-
- // enable fifo access
- mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)
-
- // setup i0 handler, and route all interrupts to it
- mov $r1 #ih
- mov $iv0 $r1
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)
-
- // enable fifo interrupt
- mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)
-
- // enable interrupts
- bset $flags ie0
-
- // figure out which GPC we are, and how many TPCs we have
- nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
- mov $r3 1
- and $r2 0x1f
- shl b32 $r3 $r2
- sub b32 $r3 1
- st b32 D[$r0 + #tpc_count] $r2
- st b32 D[$r0 + #tpc_mask] $r3
- nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
- st b32 D[$r0 + #gpc_id] $r2
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
- // figure out which, and how many, UNKs are actually present
- imm32($r14, 0x500c30)
- clear b32 $r2
- clear b32 $r3
- clear b32 $r4
- init_unk_loop:
- call(nv_rd32)
- cmp b32 $r15 0
- bra z #init_unk_next
- mov $r15 1
- shl b32 $r15 $r2
- or $r4 $r15
- add b32 $r3 1
- init_unk_next:
- add b32 $r2 1
- add b32 $r14 4
- cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
- bra ne #init_unk_loop
- init_unk_done:
- st b32 D[$r0 + #unk_count] $r3
- st b32 D[$r0 + #unk_mask] $r4
-#endif
-
- // initialise context base, and size tracking
- nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
- clear b32 $r3 // track GPC context size here
-
- // set mmctx base addresses now so we don't have to do it later,
- // they don't currently ever change
- shr b32 $r5 $r2 8
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)
-
- // calculate GPC mmio context size
- ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
- ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
- call(mmctx_size)
- add b32 $r2 $r15
- add b32 $r3 $r15
-
- // calculate per-TPC mmio context size
- ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
- ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
- call(mmctx_size)
- ld b32 $r14 D[$r0 + #tpc_count]
- mulu $r14 $r15
- add b32 $r2 $r14
- add b32 $r3 $r14
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
- // calculate per-UNK mmio context size
- ld b32 $r14 D[$r0 + #unk_mmio_list_head]
- ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
- call(mmctx_size)
- ld b32 $r14 D[$r0 + #unk_count]
- mulu $r14 $r15
- add b32 $r2 $r14
- add b32 $r3 $r14
-#endif
-
- // round up base/size to 256 byte boundary (for strand SWBASE)
- shr b32 $r3 2
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!
- shr b32 $r2 8
- shr b32 $r3 6
- add b32 $r2 1
- add b32 $r3 1
- shl b32 $r2 8
- shl b32 $r3 8
-
- // calculate size of strand context data
- mov b32 $r15 $r2
- call(strand_ctx_init)
- add b32 $r3 $r15
-
- // save context size, and tell HUB we're done
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
- clear b32 $r2
- bset $r2 31
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
- bset $flags $p0
- sleep $p0
- mov $r13 #cmd_queue
- call(queue_get)
- bra $p1 #main
-
- // 0x0000-0x0003 are all context transfers
- cmpu b32 $r14 0x04
- bra nc #main_not_ctx_xfer
- // fetch $flags and mask off $p1/$p2
- mov $r1 $flags
- mov $r2 0x0006
- not b32 $r2
- and $r1 $r2
- // set $p1/$p2 according to transfer type
- shl b32 $r14 1
- or $r1 $r14
- mov $flags $r1
- // transfer context data
- call(ctx_xfer)
- bra #main
-
- main_not_ctx_xfer:
- shl b32 $r15 $r14 16
- or $r15 E_BAD_COMMAND
- call(error)
- bra #main
-
-// interrupt handler
-ih:
- push $r8
- mov $r8 $flags
- push $r8
- push $r9
- push $r10
- push $r11
- push $r13
- push $r14
- push $r15
- clear b32 $r0
-
- // incoming fifo command?
- nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)
- and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO
- bra e #ih_no_fifo
- // queue incoming fifo command for later processing
- mov $r13 #cmd_queue
- nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)
- nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)
- call(queue_put)
- mov $r14 1
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)
-
- // ack, and wake up main()
- ih_no_fifo:
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)
-
- pop $r15
- pop $r14
- pop $r13
- pop $r11
- pop $r10
- pop $r9
- pop $r8
- mov $flags $r8
- pop $r8
- bclr $flags $p0
- iret
-
-// Set this GPC's bit in HUB_BAR, used to signal completion of various
-// activities to the HUB fuc
-//
-hub_barrier_done:
- mov $r15 1
- ld b32 $r14 D[$r0 + #gpc_id]
- shl b32 $r15 $r14
- nv_wr32(0x409418, $r15) // 0x409418 - HUB_BAR_SET
- ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off? Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
- mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
- mov $r14 8
- ctx_redswitch_delay:
- sub b32 $r14 1
- bra ne #ctx_redswitch_delay
- or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11
- or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
- ret
-
-// Transfer GPC context data between GPU and storage area
-//
-// In: $r15 context base address
-// $p1 clear on save, set on load
-// $p2 set if opposite direction done/will be done, so:
-// on save it means: "a load will follow this save"
-// on load it means: "a save preceeded this load"
-//
-ctx_xfer:
- // set context base address
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
- bra not $p1 #ctx_xfer_not_load
- call(ctx_redswitch)
- ctx_xfer_not_load:
-
- // strands
- call(strand_pre)
- clear b32 $r2
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)
- xbit $r2 $flags $p1 // SAVE/LOAD
- add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
- nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
-
- // mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 2 // first
- imm32($r11,0x500000)
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
- ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
- ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
- mov $r14 0 // not multi
- call(mmctx_xfer)
-
- // per-TPC mmio context
- xbit $r10 $flags $p1 // direction
-#if !NV_PGRAPH_GPCX_UNK__SIZE
- or $r10 4 // last
-#endif
- imm32($r11, 0x504000)
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
- ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
- ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
- ld b32 $r15 D[$r0 + #tpc_mask]
- mov $r14 0x800 // stride = 0x800
- call(mmctx_xfer)
-
-#if NV_PGRAPH_GPCX_UNK__SIZE > 0
- // per-UNK mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 4 // last
- imm32($r11, 0x503000)
- ld b32 $r12 D[$r0 + #gpc_id]
- shl b32 $r12 15
- add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_UNK0
- ld b32 $r12 D[$r0 + #unk_mmio_list_head]
- ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
- ld b32 $r15 D[$r0 + #unk_mask]
- mov $r14 0x200 // stride = 0x200
- call(mmctx_xfer)
-#endif
-
- // wait for strands to finish
- call(strand_wait)
-
- // if load, or a save without a load following, do some
- // unknown stuff that's done after finishing a block of
- // strand commands
- bra $p1 #ctx_xfer_post
- bra not $p2 #ctx_xfer_done
- ctx_xfer_post:
- call(strand_post)
-
- // mark completion in HUB's barrier
- ctx_xfer_done:
- call(hub_barrier_done)
- ret
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5
deleted file mode 100644
index bd30262d635b..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
-
-#define CHIPSET GK208
-#include "macros.fuc"
-
-.section #nv108_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nv108_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h
deleted file mode 100644
index 31922707794f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnv108.fuc5.h
+++ /dev/null
@@ -1,473 +0,0 @@
-uint32_t nv108_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
- 0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
- 0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
- 0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
- 0x0000006c,
-/* 0x0010: gpc_id */
- 0x00000000,
-/* 0x0014: tpc_count */
- 0x00000000,
-/* 0x0018: tpc_mask */
- 0x00000000,
-/* 0x001c: unk_count */
- 0x00000000,
-/* 0x0020: unk_mask */
- 0x00000000,
-/* 0x0024: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nv108_grgpc_code[] = {
- 0x03140ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0xf489a408,
- 0x020f0b1b,
- 0x0002f87e,
-/* 0x001a: queue_put_next */
- 0x98c400f8,
- 0x0384b607,
- 0xb6008dbb,
- 0x8eb50880,
- 0x018fb500,
- 0xf00190b6,
- 0xd9b50f94,
-/* 0x0037: queue_get */
- 0xf400f801,
- 0xd8980131,
- 0x01d99800,
- 0x0bf489a4,
- 0x0789c421,
- 0xbb0394b6,
- 0x90b6009d,
- 0x009e9808,
- 0xb6019f98,
- 0x84f00180,
- 0x00d8b50f,
-/* 0x0063: queue_get_done */
- 0xf80132f4,
-/* 0x0065: nv_rd32 */
- 0xf0ecb200,
- 0x00801fc9,
- 0x0cf601ca,
-/* 0x0073: nv_rd32_wait */
- 0x8c04bd00,
- 0xcf01ca00,
- 0xccc800cc,
- 0xf61bf41f,
- 0xec7e060a,
- 0x008f0000,
- 0xffcf01cb,
-/* 0x008f: nv_wr32 */
- 0x8000f800,
- 0xf601cc00,
- 0x04bd000f,
- 0xc9f0ecb2,
- 0x1ec9f01f,
- 0x01ca0080,
- 0xbd000cf6,
-/* 0x00a9: nv_wr32_wait */
- 0xca008c04,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f61b,
-/* 0x00b8: wait_donez */
- 0x99f094bd,
- 0x37008000,
- 0x0009f602,
- 0x008004bd,
- 0x0af60206,
-/* 0x00cf: wait_donez_ne */
- 0x8804bd00,
- 0xcf010000,
- 0x8aff0088,
- 0xf61bf488,
- 0x99f094bd,
- 0x17008000,
- 0x0009f602,
- 0x00f804bd,
-/* 0x00ec: wait_doneo */
- 0x99f094bd,
- 0x37008000,
- 0x0009f602,
- 0x008004bd,
- 0x0af60206,
-/* 0x0103: wait_doneo_e */
- 0x8804bd00,
- 0xcf010000,
- 0x8aff0088,
- 0xf60bf488,
- 0x99f094bd,
- 0x17008000,
- 0x0009f602,
- 0x00f804bd,
-/* 0x0120: mmctx_size */
-/* 0x0122: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0x1bf4efa4,
- 0xf89fb2ec,
-/* 0x013d: mmctx_xfer */
- 0xf094bd00,
- 0x00800199,
- 0x09f60237,
- 0xbd04bd00,
- 0x05bbfd94,
- 0x800f0bf4,
- 0xf601c400,
- 0x04bd000b,
-/* 0x015f: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0xc6008018,
- 0x000ef601,
- 0x008004bd,
- 0x0ff601c7,
- 0xf004bd00,
-/* 0x017a: mmctx_multi_disabled */
- 0xabc80199,
- 0x10b4b600,
- 0xc80cb9f0,
- 0xe4b601ae,
- 0x05befd11,
- 0x01c50080,
- 0xbd000bf6,
-/* 0x0195: mmctx_exec_loop */
-/* 0x0195: mmctx_wait_free */
- 0xc5008e04,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f60b,
- 0x05e9fd00,
- 0x01c80080,
- 0xbd000ef6,
- 0x04c0b604,
- 0x1bf4cda4,
- 0x02abc8df,
-/* 0x01bf: mmctx_fini_wait */
- 0x8b1c1bf4,
- 0xcf01c500,
- 0xb4f000bb,
- 0x10b4b01f,
- 0x0af31bf4,
- 0x00b87e05,
- 0x250ef400,
-/* 0x01d8: mmctx_stop */
- 0xb600abc8,
- 0xb9f010b4,
- 0x12b9f00c,
- 0x01c50080,
- 0xbd000bf6,
-/* 0x01ed: mmctx_stop_wait */
- 0xc5008b04,
- 0x00bbcf01,
- 0xf412bbc8,
-/* 0x01fa: mmctx_done */
- 0x94bdf61b,
- 0x800199f0,
- 0xf6021700,
- 0x04bd0009,
-/* 0x020a: strand_wait */
- 0xa0f900f8,
- 0xb87e020a,
- 0xa0fc0000,
-/* 0x0216: strand_pre */
- 0x0c0900f8,
- 0x024afc80,
- 0xbd0009f6,
- 0x020a7e04,
-/* 0x0227: strand_post */
- 0x0900f800,
- 0x4afc800d,
- 0x0009f602,
- 0x0a7e04bd,
- 0x00f80002,
-/* 0x0238: strand_set */
- 0xfc800f0c,
- 0x0cf6024f,
- 0x0c04bd00,
- 0x4afc800b,
- 0x000cf602,
- 0xfc8004bd,
- 0x0ef6024f,
- 0x0c04bd00,
- 0x4afc800a,
- 0x000cf602,
- 0x0a7e04bd,
- 0x00f80002,
-/* 0x0268: strand_ctx_init */
- 0x99f094bd,
- 0x37008003,
- 0x0009f602,
- 0x167e04bd,
- 0x030e0002,
- 0x0002387e,
- 0xfc80c4bd,
- 0x0cf60247,
- 0x0c04bd00,
- 0x4afc8001,
- 0x000cf602,
- 0x0a7e04bd,
- 0x0c920002,
- 0x46fc8001,
- 0x000cf602,
- 0x020c04bd,
- 0x024afc80,
- 0xbd000cf6,
- 0x020a7e04,
- 0x02277e00,
- 0x42008800,
- 0x20008902,
- 0x0099cf02,
-/* 0x02c7: ctx_init_strand_loop */
- 0xf608fe95,
- 0x8ef6008e,
- 0x808acf40,
- 0xb606a5b6,
- 0xeabb01a0,
- 0x0480b600,
- 0xf40192b6,
- 0xe4b6e81b,
- 0xf2efbc08,
- 0x99f094bd,
- 0x17008003,
- 0x0009f602,
- 0x00f804bd,
-/* 0x02f8: error */
- 0xffb2e0f9,
- 0x4098148e,
- 0x00008f7e,
- 0xffb2010f,
- 0x409c1c8e,
- 0x00008f7e,
- 0x00f8e0fc,
-/* 0x0314: init */
- 0x004104bd,
- 0x0011cf42,
- 0x010911e7,
- 0xfe0814b6,
- 0x02020014,
- 0xf6120040,
- 0x04bd0002,
- 0xfe047241,
- 0x00400010,
- 0x0000f607,
- 0x040204bd,
- 0xf6040040,
- 0x04bd0002,
- 0x821031f4,
- 0xcf018200,
- 0x01030022,
- 0xbb1f24f0,
- 0x32b60432,
- 0x0502b501,
- 0x820603b5,
- 0xcf018600,
- 0x02b50022,
- 0x0c308e04,
- 0xbd24bd50,
-/* 0x0377: init_unk_loop */
- 0x7e44bd34,
- 0xb0000065,
- 0x0bf400f6,
- 0xbb010f0e,
- 0x4ffd04f2,
- 0x0130b605,
-/* 0x038c: init_unk_next */
- 0xb60120b6,
- 0x26b004e0,
- 0xe21bf401,
-/* 0x0398: init_unk_done */
- 0xb50703b5,
- 0x00820804,
- 0x22cf0201,
- 0x9534bd00,
- 0x00800825,
- 0x05f601c0,
- 0x8004bd00,
- 0xf601c100,
- 0x04bd0005,
- 0x98000e98,
- 0x207e010f,
- 0x2fbb0001,
- 0x003fbb00,
- 0x98010e98,
- 0x207e020f,
- 0x0e980001,
- 0x00effd05,
- 0xbb002ebb,
- 0x0e98003e,
- 0x030f9802,
- 0x0001207e,
- 0xfd070e98,
- 0x2ebb00ef,
- 0x003ebb00,
- 0x800235b6,
- 0xf601d300,
- 0x04bd0003,
- 0xb60825b6,
- 0x20b60635,
- 0x0130b601,
- 0xb60824b6,
- 0x2fb20834,
- 0x0002687e,
- 0x80003fbb,
- 0xf6020100,
- 0x04bd0003,
- 0x29f024bd,
- 0x3000801f,
- 0x0002f602,
-/* 0x0436: main */
- 0x31f404bd,
- 0x0028f400,
- 0x377e240d,
- 0x01f40000,
- 0x04e4b0f4,
- 0xfe1d18f4,
- 0x06020181,
- 0x12fd20bd,
- 0x01e4b604,
- 0xfe051efd,
- 0x097e0018,
- 0x0ef40005,
-/* 0x0465: main_not_ctx_xfer */
- 0x10ef94d4,
- 0x7e01f5f0,
- 0xf40002f8,
-/* 0x0472: ih */
- 0x80f9c70e,
- 0xf90188fe,
- 0xf990f980,
- 0xf9b0f9a0,
- 0xf9e0f9d0,
- 0x4a04bdf0,
- 0xaacf0200,
- 0x04abc400,
- 0x0d1f0bf4,
- 0x1a004e24,
- 0x4f00eecf,
- 0xffcf1900,
- 0x00047e00,
- 0x40010e00,
- 0x0ef61d00,
-/* 0x04af: ih_no_fifo */
- 0x4004bd00,
- 0x0af60100,
- 0xfc04bd00,
- 0xfce0fcf0,
- 0xfcb0fcd0,
- 0xfc90fca0,
- 0x0088fe80,
- 0x32f480fc,
-/* 0x04cf: hub_barrier_done */
- 0x0f01f800,
- 0x040e9801,
- 0xb204febb,
- 0x94188eff,
- 0x008f7e40,
-/* 0x04e3: ctx_redswitch */
- 0x0f00f800,
- 0x85008020,
- 0x000ff601,
- 0x080e04bd,
-/* 0x04f0: ctx_redswitch_delay */
- 0xf401e2b6,
- 0xf5f1fd1b,
- 0xf5f10800,
- 0x00800200,
- 0x0ff60185,
- 0xf804bd00,
-/* 0x0509: ctx_xfer */
- 0x81008000,
- 0x000ff602,
- 0x11f404bd,
- 0x04e37e07,
-/* 0x0519: ctx_xfer_not_load */
- 0x02167e00,
- 0x8024bd00,
- 0xf60247fc,
- 0x04bd0002,
- 0xb6012cf0,
- 0xfc800320,
- 0x02f6024a,
- 0xf004bd00,
- 0xa5f001ac,
- 0x00008b02,
- 0x040c9850,
- 0xbb0fc4b6,
- 0x0c9800bc,
- 0x010d9800,
- 0x3d7e000e,
- 0xacf00001,
- 0x40008b01,
- 0x040c9850,
- 0xbb0fc4b6,
- 0x0c9800bc,
- 0x020d9801,
- 0x4e060f98,
- 0x3d7e0800,
- 0xacf00001,
- 0x04a5f001,
- 0x5030008b,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x020c9800,
- 0x98030d98,
- 0x004e080f,
- 0x013d7e02,
- 0x020a7e00,
- 0x0601f400,
-/* 0x05a3: ctx_xfer_post */
- 0x7e0712f4,
-/* 0x05a7: ctx_xfer_done */
- 0x7e000227,
- 0xf80004cf,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
deleted file mode 100644
index 5ae06a2d64c9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000000
-
-#define CHIPSET GF100
-#include "macros.fuc"
-
-.section #nvc0_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nvc0_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
deleted file mode 100644
index 325cc7b7b2fb..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvc0.fuc.h
+++ /dev/null
@@ -1,530 +0,0 @@
-uint32_t nvc0_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
- 0x00000064,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
- 0x00000064,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
- 0x00000064,
-/* 0x000c: unk_mmio_list_tail */
- 0x00000064,
-/* 0x0010: gpc_id */
- 0x00000000,
-/* 0x0014: tpc_count */
- 0x00000000,
-/* 0x0018: tpc_mask */
- 0x00000000,
-/* 0x001c: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nvc0_grgpc_code[] = {
- 0x03a10ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0xe0f900f8,
- 0xf102ffb9,
- 0xf09814e7,
- 0x21f440e3,
- 0x01f7f09d,
- 0xf102ffb9,
- 0xf09c1ce7,
- 0x21f440e3,
- 0xf8e0fc9d,
-/* 0x03a1: init */
- 0xf104bd00,
- 0xf0420017,
- 0x11cf0013,
- 0x0911e700,
- 0x0814b601,
- 0xf00014fe,
- 0x07f10227,
- 0x03f01200,
- 0x0002d000,
- 0x17f104bd,
- 0x10fe04e6,
- 0x0007f100,
- 0x0003f007,
- 0xbd0000d0,
- 0x0427f004,
- 0x040007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0xf11031f4,
- 0xf0820027,
- 0x22cf0123,
- 0x0137f000,
- 0xbb1f24f0,
- 0x32b60432,
- 0x05028001,
- 0xf1060380,
- 0xf0860027,
- 0x22cf0123,
- 0x04028000,
- 0x010027f1,
- 0xcf0223f0,
- 0x34bd0022,
- 0xf1082595,
- 0xf0c00007,
- 0x05d00103,
- 0xf104bd00,
- 0xf0c10007,
- 0x05d00103,
- 0x9804bd00,
- 0x0f98000e,
- 0x5021f501,
- 0x002fbb01,
- 0x98003fbb,
- 0x0f98010e,
- 0x5021f502,
- 0x050e9801,
- 0xbb00effd,
- 0x3ebb002e,
- 0x0235b600,
- 0xd30007f1,
- 0xd00103f0,
- 0x04bd0003,
- 0xb60825b6,
- 0x20b60635,
- 0x0130b601,
- 0xb60824b6,
- 0x2fb90834,
- 0xd321f502,
- 0x003fbb02,
- 0x010007f1,
- 0xd00203f0,
- 0x04bd0003,
- 0x29f024bd,
- 0x0007f11f,
- 0x0203f008,
- 0xbd0002d0,
-/* 0x04a9: main */
- 0x0031f404,
- 0xf00028f4,
- 0x21f41cd7,
- 0xf401f439,
- 0xf404e4b0,
- 0x81fe1e18,
- 0x0627f001,
- 0x12fd20bd,
- 0x01e4b604,
- 0xfe051efd,
- 0x21f50018,
- 0x0ef4059e,
-/* 0x04d9: main_not_ctx_xfer */
- 0x10ef94d3,
- 0xf501f5f0,
- 0xf4037e21,
-/* 0x04e6: ih */
- 0x80f9c60e,
- 0xf90188fe,
- 0xf990f980,
- 0xf9b0f9a0,
- 0xf9e0f9d0,
- 0xf104bdf0,
- 0xf00200a7,
- 0xaacf00a3,
- 0x04abc400,
- 0xf02c0bf4,
- 0xe7f11cd7,
- 0xe3f01a00,
- 0x00eecf00,
- 0x1900f7f1,
- 0xcf00f3f0,
- 0x21f400ff,
- 0x01e7f004,
- 0x1d0007f1,
- 0xd00003f0,
- 0x04bd000e,
-/* 0x0534: ih_no_fifo */
- 0x010007f1,
- 0xd00003f0,
- 0x04bd000a,
- 0xe0fcf0fc,
- 0xb0fcd0fc,
- 0x90fca0fc,
- 0x88fe80fc,
- 0xf480fc00,
- 0x01f80032,
-/* 0x0558: hub_barrier_done */
- 0x9801f7f0,
- 0xfebb040e,
- 0x02ffb904,
- 0x9418e7f1,
- 0xf440e3f0,
- 0x00f89d21,
-/* 0x0570: ctx_redswitch */
- 0xf120f7f0,
- 0xf0850007,
- 0x0fd00103,
- 0xf004bd00,
-/* 0x0582: ctx_redswitch_delay */
- 0xe2b608e7,
- 0xfd1bf401,
- 0x0800f5f1,
- 0x0200f5f1,
- 0x850007f1,
- 0xd00103f0,
- 0x04bd000f,
-/* 0x059e: ctx_xfer */
- 0x07f100f8,
- 0x03f08100,
- 0x000fd002,
- 0x11f404bd,
- 0x7021f507,
-/* 0x05b1: ctx_xfer_not_load */
- 0x6a21f505,
- 0xf124bd02,
- 0xf047fc07,
- 0x02d00203,
- 0xf004bd00,
- 0x20b6012c,
- 0xfc07f103,
- 0x0203f04a,
- 0xbd0002d0,
- 0x01acf004,
- 0xf102a5f0,
- 0xf00000b7,
- 0x0c9850b3,
- 0x0fc4b604,
- 0x9800bcbb,
- 0x0d98000c,
- 0x00e7f001,
- 0x016f21f5,
- 0xf001acf0,
- 0xb7f104a5,
- 0xb3f04000,
- 0x040c9850,
- 0xbb0fc4b6,
- 0x0c9800bc,
- 0x020d9801,
- 0xf1060f98,
- 0xf50800e7,
- 0xf5016f21,
- 0xf4025e21,
- 0x12f40601,
-/* 0x0629: ctx_xfer_post */
- 0x7f21f507,
-/* 0x062d: ctx_xfer_done */
- 0x5821f502,
- 0x0000f805,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
deleted file mode 100644
index c2f754edbd7d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
-
-#define CHIPSET GF117
-#include "macros.fuc"
-
-.section #nvd7_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nvd7_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
deleted file mode 100644
index d1504a4059c6..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvd7.fuc.h
+++ /dev/null
@@ -1,537 +0,0 @@
-uint32_t nvd7_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
- 0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
- 0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
- 0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
- 0x0000006c,
-/* 0x0010: gpc_id */
- 0x00000000,
-/* 0x0014: tpc_count */
- 0x00000000,
-/* 0x0018: tpc_mask */
- 0x00000000,
-/* 0x001c: unk_count */
- 0x00000000,
-/* 0x0020: unk_mask */
- 0x00000000,
-/* 0x0024: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nvd7_grgpc_code[] = {
- 0x03a10ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0xe0f900f8,
- 0xf102ffb9,
- 0xf09814e7,
- 0x21f440e3,
- 0x01f7f09d,
- 0xf102ffb9,
- 0xf09c1ce7,
- 0x21f440e3,
- 0xf8e0fc9d,
-/* 0x03a1: init */
- 0xf104bd00,
- 0xf0420017,
- 0x11cf0013,
- 0x0911e700,
- 0x0814b601,
- 0xf00014fe,
- 0x07f10227,
- 0x03f01200,
- 0x0002d000,
- 0x17f104bd,
- 0x10fe0530,
- 0x0007f100,
- 0x0003f007,
- 0xbd0000d0,
- 0x0427f004,
- 0x040007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0xf11031f4,
- 0xf0820027,
- 0x22cf0123,
- 0x0137f000,
- 0xbb1f24f0,
- 0x32b60432,
- 0x05028001,
- 0xf1060380,
- 0xf0860027,
- 0x22cf0123,
- 0x04028000,
- 0x0c30e7f1,
- 0xbd50e3f0,
- 0xbd34bd24,
-/* 0x0421: init_unk_loop */
- 0x6821f444,
- 0xf400f6b0,
- 0xf7f00f0b,
- 0x04f2bb01,
- 0xb6054ffd,
-/* 0x0436: init_unk_next */
- 0x20b60130,
- 0x04e0b601,
- 0xf40126b0,
-/* 0x0442: init_unk_done */
- 0x0380e21b,
- 0x08048007,
- 0x010027f1,
- 0xcf0223f0,
- 0x34bd0022,
- 0xf1082595,
- 0xf0c00007,
- 0x05d00103,
- 0xf104bd00,
- 0xf0c10007,
- 0x05d00103,
- 0x9804bd00,
- 0x0f98000e,
- 0x5021f501,
- 0x002fbb01,
- 0x98003fbb,
- 0x0f98010e,
- 0x5021f502,
- 0x050e9801,
- 0xbb00effd,
- 0x3ebb002e,
- 0x020e9800,
- 0xf5030f98,
- 0x98015021,
- 0xeffd070e,
- 0x002ebb00,
- 0xb6003ebb,
- 0x07f10235,
- 0x03f0d300,
- 0x0003d001,
- 0x25b604bd,
- 0x0635b608,
- 0xb60120b6,
- 0x24b60130,
- 0x0834b608,
- 0xf5022fb9,
- 0xbb02d321,
- 0x07f1003f,
- 0x03f00100,
- 0x0003d002,
- 0x24bd04bd,
- 0xf11f29f0,
- 0xf0080007,
- 0x02d00203,
-/* 0x04f3: main */
- 0xf404bd00,
- 0x28f40031,
- 0x24d7f000,
- 0xf43921f4,
- 0xe4b0f401,
- 0x1e18f404,
- 0xf00181fe,
- 0x20bd0627,
- 0xb60412fd,
- 0x1efd01e4,
- 0x0018fe05,
- 0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
- 0x94d30ef4,
- 0xf5f010ef,
- 0x7e21f501,
- 0xc60ef403,
-/* 0x0530: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x24d7f02c,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xf00421f4,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x057e: ih_no_fifo */
- 0x07f104bd,
- 0x03f00100,
- 0x000ad000,
- 0xf0fc04bd,
- 0xd0fce0fc,
- 0xa0fcb0fc,
- 0x80fc90fc,
- 0xfc0088fe,
- 0x0032f480,
-/* 0x05a2: hub_barrier_done */
- 0xf7f001f8,
- 0x040e9801,
- 0xb904febb,
- 0xe7f102ff,
- 0xe3f09418,
- 0x9d21f440,
-/* 0x05ba: ctx_redswitch */
- 0xf7f000f8,
- 0x0007f120,
- 0x0103f085,
- 0xbd000fd0,
- 0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
- 0xf401e2b6,
- 0xf5f1fd1b,
- 0xf5f10800,
- 0x07f10200,
- 0x03f08500,
- 0x000fd001,
- 0x00f804bd,
-/* 0x05e8: ctx_xfer */
- 0x810007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
- 0xf505ba21,
- 0xbd026a21,
- 0xfc07f124,
- 0x0203f047,
- 0xbd0002d0,
- 0x012cf004,
- 0xf10320b6,
- 0xf04afc07,
- 0x02d00203,
- 0xf004bd00,
- 0xa5f001ac,
- 0x00b7f102,
- 0x50b3f000,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x000c9800,
- 0xf0010d98,
- 0x21f500e7,
- 0xacf0016f,
- 0x00b7f101,
- 0x50b3f040,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x010c9800,
- 0x98020d98,
- 0xe7f1060f,
- 0x21f50800,
- 0xacf0016f,
- 0x04a5f001,
- 0x3000b7f1,
- 0x9850b3f0,
- 0xc4b6040c,
- 0x00bcbb0f,
- 0x98020c98,
- 0x0f98030d,
- 0x00e7f108,
- 0x6f21f502,
- 0x5e21f501,
- 0x0601f402,
-/* 0x0697: ctx_xfer_post */
- 0xf50712f4,
-/* 0x069b: ctx_xfer_done */
- 0xf5027f21,
- 0xf805a221,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
deleted file mode 100644
index 6b906cd2a31f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
-
-#define CHIPSET GK100
-#include "macros.fuc"
-
-.section #nve0_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nve0_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
deleted file mode 100644
index 855b220378f9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnve0.fuc.h
+++ /dev/null
@@ -1,537 +0,0 @@
-uint32_t nve0_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
- 0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
- 0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
- 0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
- 0x0000006c,
-/* 0x0010: gpc_id */
- 0x00000000,
-/* 0x0014: tpc_count */
- 0x00000000,
-/* 0x0018: tpc_mask */
- 0x00000000,
-/* 0x001c: unk_count */
- 0x00000000,
-/* 0x0020: unk_mask */
- 0x00000000,
-/* 0x0024: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nve0_grgpc_code[] = {
- 0x03a10ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0xe0f900f8,
- 0xf102ffb9,
- 0xf09814e7,
- 0x21f440e3,
- 0x01f7f09d,
- 0xf102ffb9,
- 0xf09c1ce7,
- 0x21f440e3,
- 0xf8e0fc9d,
-/* 0x03a1: init */
- 0xf104bd00,
- 0xf0420017,
- 0x11cf0013,
- 0x0911e700,
- 0x0814b601,
- 0xf00014fe,
- 0x07f10227,
- 0x03f01200,
- 0x0002d000,
- 0x17f104bd,
- 0x10fe0530,
- 0x0007f100,
- 0x0003f007,
- 0xbd0000d0,
- 0x0427f004,
- 0x040007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0xf11031f4,
- 0xf0820027,
- 0x22cf0123,
- 0x0137f000,
- 0xbb1f24f0,
- 0x32b60432,
- 0x05028001,
- 0xf1060380,
- 0xf0860027,
- 0x22cf0123,
- 0x04028000,
- 0x0c30e7f1,
- 0xbd50e3f0,
- 0xbd34bd24,
-/* 0x0421: init_unk_loop */
- 0x6821f444,
- 0xf400f6b0,
- 0xf7f00f0b,
- 0x04f2bb01,
- 0xb6054ffd,
-/* 0x0436: init_unk_next */
- 0x20b60130,
- 0x04e0b601,
- 0xf40126b0,
-/* 0x0442: init_unk_done */
- 0x0380e21b,
- 0x08048007,
- 0x010027f1,
- 0xcf0223f0,
- 0x34bd0022,
- 0xf1082595,
- 0xf0c00007,
- 0x05d00103,
- 0xf104bd00,
- 0xf0c10007,
- 0x05d00103,
- 0x9804bd00,
- 0x0f98000e,
- 0x5021f501,
- 0x002fbb01,
- 0x98003fbb,
- 0x0f98010e,
- 0x5021f502,
- 0x050e9801,
- 0xbb00effd,
- 0x3ebb002e,
- 0x020e9800,
- 0xf5030f98,
- 0x98015021,
- 0xeffd070e,
- 0x002ebb00,
- 0xb6003ebb,
- 0x07f10235,
- 0x03f0d300,
- 0x0003d001,
- 0x25b604bd,
- 0x0635b608,
- 0xb60120b6,
- 0x24b60130,
- 0x0834b608,
- 0xf5022fb9,
- 0xbb02d321,
- 0x07f1003f,
- 0x03f00100,
- 0x0003d002,
- 0x24bd04bd,
- 0xf11f29f0,
- 0xf0080007,
- 0x02d00203,
-/* 0x04f3: main */
- 0xf404bd00,
- 0x28f40031,
- 0x24d7f000,
- 0xf43921f4,
- 0xe4b0f401,
- 0x1e18f404,
- 0xf00181fe,
- 0x20bd0627,
- 0xb60412fd,
- 0x1efd01e4,
- 0x0018fe05,
- 0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
- 0x94d30ef4,
- 0xf5f010ef,
- 0x7e21f501,
- 0xc60ef403,
-/* 0x0530: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x24d7f02c,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xf00421f4,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x057e: ih_no_fifo */
- 0x07f104bd,
- 0x03f00100,
- 0x000ad000,
- 0xf0fc04bd,
- 0xd0fce0fc,
- 0xa0fcb0fc,
- 0x80fc90fc,
- 0xfc0088fe,
- 0x0032f480,
-/* 0x05a2: hub_barrier_done */
- 0xf7f001f8,
- 0x040e9801,
- 0xb904febb,
- 0xe7f102ff,
- 0xe3f09418,
- 0x9d21f440,
-/* 0x05ba: ctx_redswitch */
- 0xf7f000f8,
- 0x0007f120,
- 0x0103f085,
- 0xbd000fd0,
- 0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
- 0xf401e2b6,
- 0xf5f1fd1b,
- 0xf5f10800,
- 0x07f10200,
- 0x03f08500,
- 0x000fd001,
- 0x00f804bd,
-/* 0x05e8: ctx_xfer */
- 0x810007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
- 0xf505ba21,
- 0xbd026a21,
- 0xfc07f124,
- 0x0203f047,
- 0xbd0002d0,
- 0x012cf004,
- 0xf10320b6,
- 0xf04afc07,
- 0x02d00203,
- 0xf004bd00,
- 0xa5f001ac,
- 0x00b7f102,
- 0x50b3f000,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x000c9800,
- 0xf0010d98,
- 0x21f500e7,
- 0xacf0016f,
- 0x00b7f101,
- 0x50b3f040,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x010c9800,
- 0x98020d98,
- 0xe7f1060f,
- 0x21f50800,
- 0xacf0016f,
- 0x04a5f001,
- 0x3000b7f1,
- 0x9850b3f0,
- 0xc4b6040c,
- 0x00bcbb0f,
- 0x98020c98,
- 0x0f98030d,
- 0x00e7f108,
- 0x6f21f502,
- 0x5e21f501,
- 0x0601f402,
-/* 0x0697: ctx_xfer_post */
- 0xf50712f4,
-/* 0x069b: ctx_xfer_done */
- 0xf5027f21,
- 0xf805a221,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
deleted file mode 100644
index 90bbe525b626..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000002
-
-#define CHIPSET GK110
-#include "macros.fuc"
-
-.section #nvf0_grgpc_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "gpc.fuc"
-#undef INCLUDE_DATA
-
-.section #nvf0_grgpc_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "gpc.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
deleted file mode 100644
index 1b803197d28b..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcnvf0.fuc.h
+++ /dev/null
@@ -1,537 +0,0 @@
-uint32_t nvf0_grgpc_data[] = {
-/* 0x0000: gpc_mmio_list_head */
- 0x0000006c,
-/* 0x0004: gpc_mmio_list_tail */
-/* 0x0004: tpc_mmio_list_head */
- 0x0000006c,
-/* 0x0008: tpc_mmio_list_tail */
-/* 0x0008: unk_mmio_list_head */
- 0x0000006c,
-/* 0x000c: unk_mmio_list_tail */
- 0x0000006c,
-/* 0x0010: gpc_id */
- 0x00000000,
-/* 0x0014: tpc_count */
- 0x00000000,
-/* 0x0018: tpc_mask */
- 0x00000000,
-/* 0x001c: unk_count */
- 0x00000000,
-/* 0x0020: unk_mask */
- 0x00000000,
-/* 0x0024: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nvf0_grgpc_code[] = {
- 0x03a10ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f037,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f037,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x370007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x370007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0xe0f900f8,
- 0xf102ffb9,
- 0xf09814e7,
- 0x21f440e3,
- 0x01f7f09d,
- 0xf102ffb9,
- 0xf09c1ce7,
- 0x21f440e3,
- 0xf8e0fc9d,
-/* 0x03a1: init */
- 0xf104bd00,
- 0xf0420017,
- 0x11cf0013,
- 0x0911e700,
- 0x0814b601,
- 0xf00014fe,
- 0x07f10227,
- 0x03f01200,
- 0x0002d000,
- 0x17f104bd,
- 0x10fe0530,
- 0x0007f100,
- 0x0003f007,
- 0xbd0000d0,
- 0x0427f004,
- 0x040007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0xf11031f4,
- 0xf0820027,
- 0x22cf0123,
- 0x0137f000,
- 0xbb1f24f0,
- 0x32b60432,
- 0x05028001,
- 0xf1060380,
- 0xf0860027,
- 0x22cf0123,
- 0x04028000,
- 0x0c30e7f1,
- 0xbd50e3f0,
- 0xbd34bd24,
-/* 0x0421: init_unk_loop */
- 0x6821f444,
- 0xf400f6b0,
- 0xf7f00f0b,
- 0x04f2bb01,
- 0xb6054ffd,
-/* 0x0436: init_unk_next */
- 0x20b60130,
- 0x04e0b601,
- 0xf40226b0,
-/* 0x0442: init_unk_done */
- 0x0380e21b,
- 0x08048007,
- 0x010027f1,
- 0xcf0223f0,
- 0x34bd0022,
- 0xf1082595,
- 0xf0c00007,
- 0x05d00103,
- 0xf104bd00,
- 0xf0c10007,
- 0x05d00103,
- 0x9804bd00,
- 0x0f98000e,
- 0x5021f501,
- 0x002fbb01,
- 0x98003fbb,
- 0x0f98010e,
- 0x5021f502,
- 0x050e9801,
- 0xbb00effd,
- 0x3ebb002e,
- 0x020e9800,
- 0xf5030f98,
- 0x98015021,
- 0xeffd070e,
- 0x002ebb00,
- 0xb6003ebb,
- 0x07f10235,
- 0x03f0d300,
- 0x0003d001,
- 0x25b604bd,
- 0x0635b608,
- 0xb60120b6,
- 0x24b60130,
- 0x0834b608,
- 0xf5022fb9,
- 0xbb02d321,
- 0x07f1003f,
- 0x03f00100,
- 0x0003d002,
- 0x24bd04bd,
- 0xf11f29f0,
- 0xf0300007,
- 0x02d00203,
-/* 0x04f3: main */
- 0xf404bd00,
- 0x28f40031,
- 0x24d7f000,
- 0xf43921f4,
- 0xe4b0f401,
- 0x1e18f404,
- 0xf00181fe,
- 0x20bd0627,
- 0xb60412fd,
- 0x1efd01e4,
- 0x0018fe05,
- 0x05e821f5,
-/* 0x0523: main_not_ctx_xfer */
- 0x94d30ef4,
- 0xf5f010ef,
- 0x7e21f501,
- 0xc60ef403,
-/* 0x0530: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x24d7f02c,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xf00421f4,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x057e: ih_no_fifo */
- 0x07f104bd,
- 0x03f00100,
- 0x000ad000,
- 0xf0fc04bd,
- 0xd0fce0fc,
- 0xa0fcb0fc,
- 0x80fc90fc,
- 0xfc0088fe,
- 0x0032f480,
-/* 0x05a2: hub_barrier_done */
- 0xf7f001f8,
- 0x040e9801,
- 0xb904febb,
- 0xe7f102ff,
- 0xe3f09418,
- 0x9d21f440,
-/* 0x05ba: ctx_redswitch */
- 0xf7f000f8,
- 0x0007f120,
- 0x0103f085,
- 0xbd000fd0,
- 0x08e7f004,
-/* 0x05cc: ctx_redswitch_delay */
- 0xf401e2b6,
- 0xf5f1fd1b,
- 0xf5f10800,
- 0x07f10200,
- 0x03f08500,
- 0x000fd001,
- 0x00f804bd,
-/* 0x05e8: ctx_xfer */
- 0x810007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0xf50711f4,
-/* 0x05fb: ctx_xfer_not_load */
- 0xf505ba21,
- 0xbd026a21,
- 0xfc07f124,
- 0x0203f047,
- 0xbd0002d0,
- 0x012cf004,
- 0xf10320b6,
- 0xf04afc07,
- 0x02d00203,
- 0xf004bd00,
- 0xa5f001ac,
- 0x00b7f102,
- 0x50b3f000,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x000c9800,
- 0xf0010d98,
- 0x21f500e7,
- 0xacf0016f,
- 0x00b7f101,
- 0x50b3f040,
- 0xb6040c98,
- 0xbcbb0fc4,
- 0x010c9800,
- 0x98020d98,
- 0xe7f1060f,
- 0x21f50800,
- 0xacf0016f,
- 0x04a5f001,
- 0x3000b7f1,
- 0x9850b3f0,
- 0xc4b6040c,
- 0x00bcbb0f,
- 0x98020c98,
- 0x0f98030d,
- 0x00e7f108,
- 0x6f21f502,
- 0x5e21f501,
- 0x0601f402,
-/* 0x0697: ctx_xfer_post */
- 0xf50712f4,
-/* 0x069b: ctx_xfer_done */
- 0xf5027f21,
- 0xf805a221,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
deleted file mode 100644
index b4ad18bf5a26..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hub.fuc
+++ /dev/null
@@ -1,696 +0,0 @@
-/* fuc microcode for nvc0 PGRAPH/HUB
- *
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifdef INCLUDE_DATA
-hub_mmio_list_head: .b32 #hub_mmio_list_base
-hub_mmio_list_tail: .b32 #hub_mmio_list_next
-
-gpc_count: .b32 0
-rop_count: .b32 0
-cmd_queue: queue_init
-
-ctx_current: .b32 0
-
-.align 256
-chan_data:
-chan_mmio_count: .b32 0
-chan_mmio_address: .b32 0
-
-.align 256
-xfer_data: .skip 256
-
-hub_mmio_list_base:
-.b32 0x0417e91c // 0x17e91c, 2
-hub_mmio_list_next:
-#endif
-
-#ifdef INCLUDE_CODE
-// reports an exception to the host
-//
-// In: $r15 error code (see os.h)
-//
-error:
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15)
- mov $r15 1
- nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r15)
- ret
-
-// HUB fuc initialisation, executed by triggering ucode start, will
-// fall through to main loop after completion.
-//
-// Output:
-// CC_SCRATCH[0]:
-// 31:31: set to signal completion
-// CC_SCRATCH[1]:
-// 31:0: total PGRAPH context size
-//
-init:
- clear b32 $r0
- mov $xdbase $r0
-
- // setup stack
- nv_iord($r1, NV_PGRAPH_FECS_CAPS, 0)
- extr $r1 $r1 9:17
- shl b32 $r1 8
- mov $sp $r1
-
- // enable fifo access
- mov $r2 NV_PGRAPH_FECS_ACCESS_FIFO
- nv_iowr(NV_PGRAPH_FECS_ACCESS, 0, $r2)
-
- // setup i0 handler, and route all interrupts to it
- mov $r1 #ih
- mov $iv0 $r1
-
- clear b32 $r2
- nv_iowr(NV_PGRAPH_FECS_INTR_ROUTE, 0, $r2)
-
- // route HUB_CHSW_PULSE to fuc interrupt 8
- mov $r2 0x2003 // { HUB_CHSW_PULSE, ZERO } -> intr 8
- nv_iowr(NV_PGRAPH_FECS_IROUTE, 0, $r2)
-
- // not sure what these are, route them because NVIDIA does, and
- // the IRQ handler will signal the host if we ever get one.. we
- // may find out if/why we need to handle these if so..
- //
- mov $r2 0x2004 // { 0x04, ZERO } -> intr 9
- nv_iowr(NV_PGRAPH_FECS_IROUTE, 1, $r2)
- mov $r2 0x200b // { HUB_FIRMWARE_MTHD, ZERO } -> intr 10
- nv_iowr(NV_PGRAPH_FECS_IROUTE, 2, $r2)
- mov $r2 0x200c // { 0x0c, ZERO } -> intr 15
- nv_iowr(NV_PGRAPH_FECS_IROUTE, 7, $r2)
-
- // enable all INTR_UP interrupts
- sub b32 $r3 $r0 1
- nv_iowr(NV_PGRAPH_FECS_INTR_UP_EN, 0, $r3)
-
- // enable fifo, ctxsw, 9, fwmthd, 15 interrupts
- imm32($r2, 0x8704)
- nv_iowr(NV_PGRAPH_FECS_INTR_EN_SET, 0, $r2)
-
- // fifo level triggered, rest edge
- mov $r2 NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL
- nv_iowr(NV_PGRAPH_FECS_INTR_MODE, 0, $r2)
-
- // enable interrupts
- bset $flags ie0
-
- // fetch enabled GPC/ROP counts
- nv_rd32($r14, 0x409604)
- extr $r1 $r15 16:20
- st b32 D[$r0 + #rop_count] $r1
- and $r15 0x1f
- st b32 D[$r0 + #gpc_count] $r15
-
- // set BAR_REQMASK to GPC mask
- mov $r1 1
- shl b32 $r1 $r15
- sub b32 $r1 1
- nv_iowr(NV_PGRAPH_FECS_BAR_MASK0, 0, $r1)
- nv_iowr(NV_PGRAPH_FECS_BAR_MASK1, 0, $r1)
-
- // context size calculation, reserve first 256 bytes for use by fuc
- mov $r1 256
-
- //
- mov $r15 2
- call(ctx_4170s)
- call(ctx_4170w)
- mov $r15 0x10
- call(ctx_86c)
-
- // calculate size of mmio context data
- ld b32 $r14 D[$r0 + #hub_mmio_list_head]
- ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
- call(mmctx_size)
-
- // set mmctx base addresses now so we don't have to do it later,
- // they don't (currently) ever change
- shr b32 $r4 $r1 8
- nv_iowr(NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE, 0, $r4)
- nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE, 0, $r4)
- add b32 $r3 0x1300
- add b32 $r1 $r15
- shr b32 $r15 2
- nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_COUNT, 0, $r15) // wtf??
-
- // strands, base offset needs to be aligned to 256 bytes
- shr b32 $r1 8
- add b32 $r1 1
- shl b32 $r1 8
- mov b32 $r15 $r1
- call(strand_ctx_init)
- add b32 $r1 $r15
-
- // initialise each GPC in sequence by passing in the offset of its
- // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
- // has previously been uploaded by the host) running.
- //
- // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
- // when it has completed, and return the size of its context data
- // in GPCn_CC_SCRATCH[1]
- //
- ld b32 $r3 D[$r0 + #gpc_count]
- imm32($r4, 0x502000)
- init_gpc:
- // setup, and start GPC ucode running
- add b32 $r14 $r4 0x804
- mov b32 $r15 $r1
- call(nv_wr32) // CC_SCRATCH[1] = ctx offset
- add b32 $r14 $r4 0x10c
- clear b32 $r15
- call(nv_wr32)
- add b32 $r14 $r4 0x104
- call(nv_wr32) // ENTRY
- add b32 $r14 $r4 0x100
- mov $r15 2 // CTRL_START_TRIGGER
- call(nv_wr32) // CTRL
-
- // wait for it to complete, and adjust context size
- add b32 $r14 $r4 0x800
- init_gpc_wait:
- call(nv_rd32)
- xbit $r15 $r15 31
- bra e #init_gpc_wait
- add b32 $r14 $r4 0x804
- call(nv_rd32)
- add b32 $r1 $r15
-
- // next!
- add b32 $r4 0x8000
- sub b32 $r3 1
- bra ne #init_gpc
-
- //
- mov $r15 0
- call(ctx_86c)
- mov $r15 0
- call(ctx_4170s)
-
- // save context size, and tell host we're ready
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
- clear b32 $r1
- bset $r1 31
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r1)
-
-// Main program loop, very simple, sleeps until woken up by the interrupt
-// handler, pulls a command from the queue and executes its handler
-//
-main:
- // sleep until we have something to do
- bset $flags $p0
- sleep $p0
- mov $r13 #cmd_queue
- call(queue_get)
- bra $p1 #main
-
- // context switch, requested by GPU?
- cmpu b32 $r14 0x4001
- bra ne #main_not_ctx_switch
- trace_set(T_AUTO)
- nv_iord($r1, NV_PGRAPH_FECS_CHAN_ADDR, 0)
- nv_iord($r2, NV_PGRAPH_FECS_CHAN_NEXT, 0)
-
- xbit $r3 $r1 31
- bra e #chsw_no_prev
- xbit $r3 $r2 31
- bra e #chsw_prev_no_next
- push $r2
- mov b32 $r2 $r1
- trace_set(T_SAVE)
- bclr $flags $p1
- bset $flags $p2
- call(ctx_xfer)
- trace_clr(T_SAVE);
- pop $r2
- trace_set(T_LOAD);
- bset $flags $p1
- call(ctx_xfer)
- trace_clr(T_LOAD);
- bra #chsw_done
- chsw_prev_no_next:
- push $r2
- mov b32 $r2 $r1
- bclr $flags $p1
- bclr $flags $p2
- call(ctx_xfer)
- pop $r2
- nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
- bra #chsw_done
- chsw_no_prev:
- xbit $r3 $r2 31
- bra e #chsw_done
- bset $flags $p1
- bclr $flags $p2
- call(ctx_xfer)
-
- // ack the context switch request
- chsw_done:
- mov $r2 NV_PGRAPH_FECS_CHSW_ACK
- nv_iowr(NV_PGRAPH_FECS_CHSW, 0, $r2)
- trace_clr(T_AUTO)
- bra #main
-
- // request to set current channel? (*not* a context switch)
- main_not_ctx_switch:
- cmpu b32 $r14 0x0001
- bra ne #main_not_ctx_chan
- mov b32 $r2 $r15
- call(ctx_chan)
- bra #main_done
-
- // request to store current channel context?
- main_not_ctx_chan:
- cmpu b32 $r14 0x0002
- bra ne #main_not_ctx_save
- trace_set(T_SAVE)
- bclr $flags $p1
- bclr $flags $p2
- call(ctx_xfer)
- trace_clr(T_SAVE)
- bra #main_done
-
- main_not_ctx_save:
- shl b32 $r15 $r14 16
- or $r15 E_BAD_COMMAND
- call(error)
- bra #main
-
- main_done:
- clear b32 $r2
- bset $r2 31
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r2)
- bra #main
-
-// interrupt handler
-ih:
- push $r8
- mov $r8 $flags
- push $r8
- push $r9
- push $r10
- push $r11
- push $r13
- push $r14
- push $r15
- clear b32 $r0
-
- // incoming fifo command?
- nv_iord($r10, NV_PGRAPH_FECS_INTR, 0)
- and $r11 $r10 NV_PGRAPH_FECS_INTR_FIFO
- bra e #ih_no_fifo
- // queue incoming fifo command for later processing
- mov $r13 #cmd_queue
- nv_iord($r14, NV_PGRAPH_FECS_FIFO_CMD, 0)
- nv_iord($r15, NV_PGRAPH_FECS_FIFO_DATA, 0)
- call(queue_put)
- add b32 $r11 0x400
- mov $r14 1
- nv_iowr(NV_PGRAPH_FECS_FIFO_ACK, 0, $r14)
-
- // context switch request?
- ih_no_fifo:
- and $r11 $r10 NV_PGRAPH_FECS_INTR_CHSW
- bra e #ih_no_ctxsw
- // enqueue a context switch for later processing
- mov $r13 #cmd_queue
- mov $r14 0x4001
- call(queue_put)
-
- // firmware method?
- ih_no_ctxsw:
- and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD
- bra e #ih_no_fwmthd
- // none we handle; report to host and ack
- nv_rd32($r15, NV_PGRAPH_TRAPPED_DATA_LO)
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(4), 0, $r15)
- nv_rd32($r15, NV_PGRAPH_TRAPPED_ADDR)
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(3), 0, $r15)
- extr $r14 $r15 16:18
- shl b32 $r14 $r14 2
- imm32($r15, NV_PGRAPH_FE_OBJECT_TABLE(0))
- add b32 $r14 $r15
- call(nv_rd32)
- nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(2), 0, $r15)
- mov $r15 E_BAD_FWMTHD
- call(error)
- mov $r11 0x100
- nv_wr32(0x400144, $r11)
-
- // anything we didn't handle, bring it to the host's attention
- ih_no_fwmthd:
- mov $r11 0x504 // FIFO | CHSW | FWMTHD
- not b32 $r11
- and $r11 $r10 $r11
- bra e #ih_no_other
- nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r11)
-
- // ack, and wake up main()
- ih_no_other:
- nv_iowr(NV_PGRAPH_FECS_INTR_ACK, 0, $r10)
-
- pop $r15
- pop $r14
- pop $r13
- pop $r11
- pop $r10
- pop $r9
- pop $r8
- mov $flags $r8
- pop $r8
- bclr $flags $p0
- iret
-
-#if CHIPSET < GK100
-// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
-ctx_4160s:
- mov $r15 1
- nv_wr32(0x404160, $r15)
- ctx_4160s_wait:
- nv_rd32($r15, 0x404160)
- xbit $r15 $r15 4
- bra e #ctx_4160s_wait
- ret
-
-// Without clearing again at end of xfer, some things cause PGRAPH
-// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
-// still function with it set however...
-ctx_4160c:
- clear b32 $r15
- nv_wr32(0x404160, $r15)
- ret
-#endif
-
-// Again, not real sure
-//
-// In: $r15 value to set 0x404170 to
-//
-ctx_4170s:
- or $r15 0x10
- nv_wr32(0x404170, $r15)
- ret
-
-// Waits for a ctx_4170s() call to complete
-//
-ctx_4170w:
- nv_rd32($r15, 0x404170)
- and $r15 0x10
- bra ne #ctx_4170w
- ret
-
-// Disables various things, waits a bit, and re-enables them..
-//
-// Not sure how exactly this helps, perhaps "ENABLE" is not such a
-// good description for the bits we turn off? Anyways, without this,
-// funny things happen.
-//
-ctx_redswitch:
- mov $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC
- or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP
- or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC
- or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN
- nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
- mov $r15 8
- ctx_redswitch_delay:
- sub b32 $r15 1
- bra ne #ctx_redswitch_delay
- or $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP
- or $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN
- nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
- ret
-
-// Not a clue what this is for, except that unless the value is 0x10, the
-// strand context is saved (and presumably restored) incorrectly..
-//
-// In: $r15 value to set to (0x00/0x10 are used)
-//
-ctx_86c:
- nv_iowr(NV_PGRAPH_FECS_UNK86C, 0, $r15)
- nv_wr32(0x408a14, $r15)
- nv_wr32(NV_PGRAPH_GPCX_GPCCS_UNK86C, $r15)
- ret
-
-// In: $r15 NV_PGRAPH_FECS_MEM_CMD_*
-ctx_mem:
- nv_iowr(NV_PGRAPH_FECS_MEM_CMD, 0, $r15)
- ctx_mem_wait:
- nv_iord($r15, NV_PGRAPH_FECS_MEM_CMD, 0)
- or $r15 $r15
- bra ne #ctx_mem_wait
- ret
-
-// ctx_load - load's a channel's ctxctl data, and selects its vm
-//
-// In: $r2 channel address
-//
-ctx_load:
- trace_set(T_CHAN)
-
- // switch to channel, somewhat magic in parts..
- mov $r10 12 // DONE_UNK12
- call(wait_donez)
- clear b32 $r15
- nv_iowr(0x409a24, 0, $r15)
- nv_iowr(NV_PGRAPH_FECS_CHAN_NEXT, 0, $r2)
- nv_iowr(NV_PGRAPH_FECS_MEM_CHAN, 0, $r2)
- mov $r15 NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN
- call(ctx_mem)
- nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
-
- // load channel header, fetch PGRAPH context pointer
- mov $xtargets $r0
- bclr $r2 31
- shl b32 $r2 4
- add b32 $r2 2
-
- trace_set(T_LCHAN)
- nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r2)
- imm32($r2, NV_PGRAPH_FECS_MEM_TARGET_UNK31)
- or $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM
- nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
- mov $r1 0x10 // chan + 0x0210
- mov $r2 #xfer_data
- sethi $r2 0x00020000 // 16 bytes
- xdld $r1 $r2
- xdwait
- trace_clr(T_LCHAN)
-
- // update current context
- ld b32 $r1 D[$r0 + #xfer_data + 4]
- shl b32 $r1 24
- ld b32 $r2 D[$r0 + #xfer_data + 0]
- shr b32 $r2 8
- or $r1 $r2
- st b32 D[$r0 + #ctx_current] $r1
-
- // set transfer base to start of context, and fetch context header
- trace_set(T_LCTXH)
- nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r1)
- mov $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VM
- nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
- mov $r1 #chan_data
- sethi $r1 0x00060000 // 256 bytes
- xdld $r0 $r1
- xdwait
- trace_clr(T_LCTXH)
-
- trace_clr(T_CHAN)
- ret
-
-// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
-// the active channel for ctxctl, but not actually transfer
-// any context data. intended for use only during initial
-// context construction.
-//
-// In: $r2 channel address
-//
-ctx_chan:
-#if CHIPSET < GK100
- call(ctx_4160s)
-#endif
- call(ctx_load)
- mov $r10 12 // DONE_UNK12
- call(wait_donez)
- mov $r15 5 // MEM_CMD 5 ???
- call(ctx_mem)
-#if CHIPSET < GK100
- call(ctx_4160c)
-#endif
- ret
-
-// Execute per-context state overrides list
-//
-// Only executed on the first load of a channel. Might want to look into
-// removing this and having the host directly modify the channel's context
-// to change this state... The nouveau DRM already builds this list as
-// it's definitely needed for NVIDIA's, so we may as well use it for now
-//
-// Input: $r1 mmio list length
-//
-ctx_mmio_exec:
- // set transfer base to be the mmio list
- ld b32 $r3 D[$r0 + #chan_mmio_address]
- nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
-
- clear b32 $r3
- ctx_mmio_loop:
- // fetch next 256 bytes of mmio list if necessary
- and $r4 $r3 0xff
- bra ne #ctx_mmio_pull
- mov $r5 #xfer_data
- sethi $r5 0x00060000 // 256 bytes
- xdld $r3 $r5
- xdwait
-
- // execute a single list entry
- ctx_mmio_pull:
- ld b32 $r14 D[$r4 + #xfer_data + 0x00]
- ld b32 $r15 D[$r4 + #xfer_data + 0x04]
- call(nv_wr32)
-
- // next!
- add b32 $r3 8
- sub b32 $r1 1
- bra ne #ctx_mmio_loop
-
- // set transfer base back to the current context
- ctx_mmio_done:
- ld b32 $r3 D[$r0 + #ctx_current]
- nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
-
- // disable the mmio list now, we don't need/want to execute it again
- st b32 D[$r0 + #chan_mmio_count] $r0
- mov $r1 #chan_data
- sethi $r1 0x00060000 // 256 bytes
- xdst $r0 $r1
- xdwait
- ret
-
-// Transfer HUB context data between GPU and storage area
-//
-// In: $r2 channel address
-// $p1 clear on save, set on load
-// $p2 set if opposite direction done/will be done, so:
-// on save it means: "a load will follow this save"
-// on load it means: "a save preceeded this load"
-//
-ctx_xfer:
- // according to mwk, some kind of wait for idle
- mov $r14 4
- nv_iowr(0x409c08, 0, $r14)
- ctx_xfer_idle:
- nv_iord($r14, 0x409c00, 0)
- and $r14 0x2000
- bra ne #ctx_xfer_idle
-
- bra not $p1 #ctx_xfer_pre
- bra $p2 #ctx_xfer_pre_load
- ctx_xfer_pre:
- mov $r15 0x10
- call(ctx_86c)
-#if CHIPSET < GK100
- call(ctx_4160s)
-#endif
- bra not $p1 #ctx_xfer_exec
-
- ctx_xfer_pre_load:
- mov $r15 2
- call(ctx_4170s)
- call(ctx_4170w)
- call(ctx_redswitch)
- clear b32 $r15
- call(ctx_4170s)
- call(ctx_load)
-
- // fetch context pointer, and initiate xfer on all GPCs
- ctx_xfer_exec:
- ld b32 $r1 D[$r0 + #ctx_current]
-
- clear b32 $r2
- nv_iowr(NV_PGRAPH_FECS_BAR, 0, $r2)
-
- nv_wr32(0x41a500, $r1) // GPC_BCAST_WRCMD_DATA = ctx pointer
- xbit $r15 $flags $p1
- xbit $r2 $flags $p2
- shl b32 $r2 1
- or $r15 $r2
- nv_wr32(0x41a504, $r15) // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
-
- // strands
- call(strand_pre)
- clear b32 $r2
- nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r2)
- xbit $r2 $flags $p1 // SAVE/LOAD
- add b32 $r2 NV_PGRAPH_FECS_STRAND_CMD_SAVE
- nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r2)
-
- // mmio context
- xbit $r10 $flags $p1 // direction
- or $r10 6 // first, last
- mov $r11 0 // base = 0
- ld b32 $r12 D[$r0 + #hub_mmio_list_head]
- ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
- mov $r14 0 // not multi
- call(mmctx_xfer)
-
- // wait for GPCs to all complete
- mov $r10 8 // DONE_BAR
- call(wait_doneo)
-
- // wait for strand xfer to complete
- call(strand_wait)
-
- // post-op
- bra $p1 #ctx_xfer_post
- mov $r10 12 // DONE_UNK12
- call(wait_donez)
- mov $r15 5 // MEM_CMD 5 ???
- call(ctx_mem)
-
- bra $p2 #ctx_xfer_done
- ctx_xfer_post:
- mov $r15 2
- call(ctx_4170s)
- clear b32 $r15
- call(ctx_86c)
- call(strand_post)
- call(ctx_4170w)
- clear b32 $r15
- call(ctx_4170s)
-
- bra not $p1 #ctx_xfer_no_post_mmio
- ld b32 $r1 D[$r0 + #chan_mmio_count]
- or $r1 $r1
- bra e #ctx_xfer_no_post_mmio
- call(ctx_mmio_exec)
-
- ctx_xfer_no_post_mmio:
-#if CHIPSET < GK100
- call(ctx_4160c)
-#endif
-
- ctx_xfer_done:
- ret
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5 b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5
deleted file mode 100644
index 7c5d25630fa8..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GK208
-#include "macros.fuc"
-
-.section #nv108_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nv108_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h
deleted file mode 100644
index e49b5a877ae4..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnv108.fuc5.h
+++ /dev/null
@@ -1,916 +0,0 @@
-uint32_t nv108_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
- 0x00000300,
-/* 0x0004: hub_mmio_list_tail */
- 0x00000304,
-/* 0x0008: gpc_count */
- 0x00000000,
-/* 0x000c: rop_count */
- 0x00000000,
-/* 0x0010: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: ctx_current */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
- 0x00000000,
-/* 0x0104: chan_mmio_address */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0200: xfer_data */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0300: hub_mmio_list_base */
- 0x0417e91c,
-};
-
-uint32_t nv108_grhub_code[] = {
- 0x030e0ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0xf489a408,
- 0x020f0b1b,
- 0x0002f87e,
-/* 0x001a: queue_put_next */
- 0x98c400f8,
- 0x0384b607,
- 0xb6008dbb,
- 0x8eb50880,
- 0x018fb500,
- 0xf00190b6,
- 0xd9b50f94,
-/* 0x0037: queue_get */
- 0xf400f801,
- 0xd8980131,
- 0x01d99800,
- 0x0bf489a4,
- 0x0789c421,
- 0xbb0394b6,
- 0x90b6009d,
- 0x009e9808,
- 0xb6019f98,
- 0x84f00180,
- 0x00d8b50f,
-/* 0x0063: queue_get_done */
- 0xf80132f4,
-/* 0x0065: nv_rd32 */
- 0xf0ecb200,
- 0x00801fc9,
- 0x0cf601ca,
-/* 0x0073: nv_rd32_wait */
- 0x8c04bd00,
- 0xcf01ca00,
- 0xccc800cc,
- 0xf61bf41f,
- 0xec7e060a,
- 0x008f0000,
- 0xffcf01cb,
-/* 0x008f: nv_wr32 */
- 0x8000f800,
- 0xf601cc00,
- 0x04bd000f,
- 0xc9f0ecb2,
- 0x1ec9f01f,
- 0x01ca0080,
- 0xbd000cf6,
-/* 0x00a9: nv_wr32_wait */
- 0xca008c04,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f61b,
-/* 0x00b8: wait_donez */
- 0x99f094bd,
- 0x37008000,
- 0x0009f602,
- 0x008004bd,
- 0x0af60206,
-/* 0x00cf: wait_donez_ne */
- 0x8804bd00,
- 0xcf010000,
- 0x8aff0088,
- 0xf61bf488,
- 0x99f094bd,
- 0x17008000,
- 0x0009f602,
- 0x00f804bd,
-/* 0x00ec: wait_doneo */
- 0x99f094bd,
- 0x37008000,
- 0x0009f602,
- 0x008004bd,
- 0x0af60206,
-/* 0x0103: wait_doneo_e */
- 0x8804bd00,
- 0xcf010000,
- 0x8aff0088,
- 0xf60bf488,
- 0x99f094bd,
- 0x17008000,
- 0x0009f602,
- 0x00f804bd,
-/* 0x0120: mmctx_size */
-/* 0x0122: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0x1bf4efa4,
- 0xf89fb2ec,
-/* 0x013d: mmctx_xfer */
- 0xf094bd00,
- 0x00800199,
- 0x09f60237,
- 0xbd04bd00,
- 0x05bbfd94,
- 0x800f0bf4,
- 0xf601c400,
- 0x04bd000b,
-/* 0x015f: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0xc6008018,
- 0x000ef601,
- 0x008004bd,
- 0x0ff601c7,
- 0xf004bd00,
-/* 0x017a: mmctx_multi_disabled */
- 0xabc80199,
- 0x10b4b600,
- 0xc80cb9f0,
- 0xe4b601ae,
- 0x05befd11,
- 0x01c50080,
- 0xbd000bf6,
-/* 0x0195: mmctx_exec_loop */
-/* 0x0195: mmctx_wait_free */
- 0xc5008e04,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f60b,
- 0x05e9fd00,
- 0x01c80080,
- 0xbd000ef6,
- 0x04c0b604,
- 0x1bf4cda4,
- 0x02abc8df,
-/* 0x01bf: mmctx_fini_wait */
- 0x8b1c1bf4,
- 0xcf01c500,
- 0xb4f000bb,
- 0x10b4b01f,
- 0x0af31bf4,
- 0x00b87e05,
- 0x250ef400,
-/* 0x01d8: mmctx_stop */
- 0xb600abc8,
- 0xb9f010b4,
- 0x12b9f00c,
- 0x01c50080,
- 0xbd000bf6,
-/* 0x01ed: mmctx_stop_wait */
- 0xc5008b04,
- 0x00bbcf01,
- 0xf412bbc8,
-/* 0x01fa: mmctx_done */
- 0x94bdf61b,
- 0x800199f0,
- 0xf6021700,
- 0x04bd0009,
-/* 0x020a: strand_wait */
- 0xa0f900f8,
- 0xb87e020a,
- 0xa0fc0000,
-/* 0x0216: strand_pre */
- 0x0c0900f8,
- 0x024afc80,
- 0xbd0009f6,
- 0x020a7e04,
-/* 0x0227: strand_post */
- 0x0900f800,
- 0x4afc800d,
- 0x0009f602,
- 0x0a7e04bd,
- 0x00f80002,
-/* 0x0238: strand_set */
- 0xfc800f0c,
- 0x0cf6024f,
- 0x0c04bd00,
- 0x4afc800b,
- 0x000cf602,
- 0xfc8004bd,
- 0x0ef6024f,
- 0x0c04bd00,
- 0x4afc800a,
- 0x000cf602,
- 0x0a7e04bd,
- 0x00f80002,
-/* 0x0268: strand_ctx_init */
- 0x99f094bd,
- 0x37008003,
- 0x0009f602,
- 0x167e04bd,
- 0x030e0002,
- 0x0002387e,
- 0xfc80c4bd,
- 0x0cf60247,
- 0x0c04bd00,
- 0x4afc8001,
- 0x000cf602,
- 0x0a7e04bd,
- 0x0c920002,
- 0x46fc8001,
- 0x000cf602,
- 0x020c04bd,
- 0x024afc80,
- 0xbd000cf6,
- 0x020a7e04,
- 0x02277e00,
- 0x42008800,
- 0x20008902,
- 0x0099cf02,
-/* 0x02c7: ctx_init_strand_loop */
- 0xf608fe95,
- 0x8ef6008e,
- 0x808acf40,
- 0xb606a5b6,
- 0xeabb01a0,
- 0x0480b600,
- 0xf40192b6,
- 0xe4b6e81b,
- 0xf2efbc08,
- 0x99f094bd,
- 0x17008003,
- 0x0009f602,
- 0x00f804bd,
-/* 0x02f8: error */
- 0x02050080,
- 0xbd000ff6,
- 0x80010f04,
- 0xf6030700,
- 0x04bd000f,
-/* 0x030e: init */
- 0x04bd00f8,
- 0x410007fe,
- 0x11cf4200,
- 0x0911e700,
- 0x0814b601,
- 0x020014fe,
- 0x12004002,
- 0xbd0002f6,
- 0x05c94104,
- 0xbd0010fe,
- 0x07004024,
- 0xbd0002f6,
- 0x20034204,
- 0x01010080,
- 0xbd0002f6,
- 0x20044204,
- 0x01010480,
- 0xbd0002f6,
- 0x200b4204,
- 0x01010880,
- 0xbd0002f6,
- 0x200c4204,
- 0x01011c80,
- 0xbd0002f6,
- 0x01039204,
- 0x03090080,
- 0xbd0003f6,
- 0x87044204,
- 0xf6040040,
- 0x04bd0002,
- 0x00400402,
- 0x0002f603,
- 0x31f404bd,
- 0x96048e10,
- 0x00657e40,
- 0xc7feb200,
- 0x01b590f1,
- 0x1ff4f003,
- 0x01020fb5,
- 0x041fbb01,
- 0x800112b6,
- 0xf6010300,
- 0x04bd0001,
- 0x01040080,
- 0xbd0001f6,
- 0x01004104,
- 0xa87e020f,
- 0xb77e0006,
- 0x100f0006,
- 0x0006f97e,
- 0x98000e98,
- 0x207e010f,
- 0x14950001,
- 0xc0008008,
- 0x0004f601,
- 0x008004bd,
- 0x04f601c1,
- 0xb704bd00,
- 0xbb130030,
- 0xf5b6001f,
- 0xd3008002,
- 0x000ff601,
- 0x15b604bd,
- 0x0110b608,
- 0xb20814b6,
- 0x02687e1f,
- 0x001fbb00,
- 0x84020398,
-/* 0x041f: init_gpc */
- 0xb8502000,
- 0x0008044e,
- 0x8f7e1fb2,
- 0x4eb80000,
- 0xbd00010c,
- 0x008f7ef4,
- 0x044eb800,
- 0x8f7e0001,
- 0x4eb80000,
- 0x0f000100,
- 0x008f7e02,
- 0x004eb800,
-/* 0x044e: init_gpc_wait */
- 0x657e0008,
- 0xffc80000,
- 0xf90bf41f,
- 0x08044eb8,
- 0x00657e00,
- 0x001fbb00,
- 0x800040b7,
- 0xf40132b6,
- 0x000fb41b,
- 0x0006f97e,
- 0xa87e000f,
- 0x00800006,
- 0x01f60201,
- 0xbd04bd00,
- 0x1f19f014,
- 0x02300080,
- 0xbd0001f6,
-/* 0x0491: main */
- 0x0031f404,
- 0x0d0028f4,
- 0x00377e10,
- 0xf401f400,
- 0x4001e4b1,
- 0x00c71bf5,
- 0x99f094bd,
- 0x37008004,
- 0x0009f602,
- 0x008104bd,
- 0x11cf02c0,
- 0xc1008200,
- 0x0022cf02,
- 0xf41f13c8,
- 0x23c8770b,
- 0x550bf41f,
- 0x12b220f9,
- 0x99f094bd,
- 0x37008007,
- 0x0009f602,
- 0x32f404bd,
- 0x0231f401,
- 0x00087c7e,
- 0x99f094bd,
- 0x17008007,
- 0x0009f602,
- 0x20fc04bd,
- 0x99f094bd,
- 0x37008006,
- 0x0009f602,
- 0x31f404bd,
- 0x087c7e01,
- 0xf094bd00,
- 0x00800699,
- 0x09f60217,
- 0xf404bd00,
-/* 0x0522: chsw_prev_no_next */
- 0x20f92f0e,
- 0x32f412b2,
- 0x0232f401,
- 0x00087c7e,
- 0x008020fc,
- 0x02f602c0,
- 0xf404bd00,
-/* 0x053e: chsw_no_prev */
- 0x23c8130e,
- 0x0d0bf41f,
- 0xf40131f4,
- 0x7c7e0232,
-/* 0x054e: chsw_done */
- 0x01020008,
- 0x02c30080,
- 0xbd0002f6,
- 0xf094bd04,
- 0x00800499,
- 0x09f60217,
- 0xf504bd00,
-/* 0x056b: main_not_ctx_switch */
- 0xb0ff2a0e,
- 0x1bf401e4,
- 0x7ef2b20c,
- 0xf400081c,
-/* 0x057a: main_not_ctx_chan */
- 0xe4b0400e,
- 0x2c1bf402,
- 0x99f094bd,
- 0x37008007,
- 0x0009f602,
- 0x32f404bd,
- 0x0232f401,
- 0x00087c7e,
- 0x99f094bd,
- 0x17008007,
- 0x0009f602,
- 0x0ef404bd,
-/* 0x05a9: main_not_ctx_save */
- 0x10ef9411,
- 0x7e01f5f0,
- 0xf50002f8,
-/* 0x05b7: main_done */
- 0xbdfede0e,
- 0x1f29f024,
- 0x02300080,
- 0xbd0002f6,
- 0xcc0ef504,
-/* 0x05c9: ih */
- 0xfe80f9fe,
- 0x80f90188,
- 0xa0f990f9,
- 0xd0f9b0f9,
- 0xf0f9e0f9,
- 0x004a04bd,
- 0x00aacf02,
- 0xf404abc4,
- 0x100d230b,
- 0xcf1a004e,
- 0x004f00ee,
- 0x00ffcf19,
- 0x0000047e,
- 0x0400b0b7,
- 0x0040010e,
- 0x000ef61d,
-/* 0x060a: ih_no_fifo */
- 0xabe404bd,
- 0x0bf40100,
- 0x4e100d0c,
- 0x047e4001,
-/* 0x061a: ih_no_ctxsw */
- 0xabe40000,
- 0x0bf40400,
- 0x07088e56,
- 0x00657e40,
- 0x80ffb200,
- 0xf6020400,
- 0x04bd000f,
- 0x4007048e,
- 0x0000657e,
- 0x0080ffb2,
- 0x0ff60203,
- 0xc704bd00,
- 0xee9450fe,
- 0x07008f02,
- 0x00efbb40,
- 0x0000657e,
- 0x02020080,
- 0xbd000ff6,
- 0x7e030f04,
- 0x4b0002f8,
- 0xbfb20100,
- 0x4001448e,
- 0x00008f7e,
-/* 0x0674: ih_no_fwmthd */
- 0xbd05044b,
- 0xb4abffb0,
- 0x800c0bf4,
- 0xf6030700,
- 0x04bd000b,
-/* 0x0688: ih_no_other */
- 0xf6010040,
- 0x04bd000a,
- 0xe0fcf0fc,
- 0xb0fcd0fc,
- 0x90fca0fc,
- 0x88fe80fc,
- 0xf480fc00,
- 0x01f80032,
-/* 0x06a8: ctx_4170s */
- 0xb210f5f0,
- 0x41708eff,
- 0x008f7e40,
-/* 0x06b7: ctx_4170w */
- 0x8e00f800,
- 0x7e404170,
- 0xb2000065,
- 0x10f4f0ff,
- 0xf8f31bf4,
-/* 0x06c9: ctx_redswitch */
- 0x02004e00,
- 0xf040e5f0,
- 0xe5f020e5,
- 0x85008010,
- 0x000ef601,
- 0x080f04bd,
-/* 0x06e0: ctx_redswitch_delay */
- 0xf401f2b6,
- 0xe5f1fd1b,
- 0xe5f10400,
- 0x00800100,
- 0x0ef60185,
- 0xf804bd00,
-/* 0x06f9: ctx_86c */
- 0x23008000,
- 0x000ff602,
- 0xffb204bd,
- 0x408a148e,
- 0x00008f7e,
- 0x8c8effb2,
- 0x8f7e41a8,
- 0x00f80000,
-/* 0x0718: ctx_mem */
- 0x02840080,
- 0xbd000ff6,
-/* 0x0721: ctx_mem_wait */
- 0x84008f04,
- 0x00ffcf02,
- 0xf405fffd,
- 0x00f8f61b,
-/* 0x0730: ctx_load */
- 0x99f094bd,
- 0x37008005,
- 0x0009f602,
- 0x0c0a04bd,
- 0x0000b87e,
- 0x0080f4bd,
- 0x0ff60289,
- 0x8004bd00,
- 0xf602c100,
- 0x04bd0002,
- 0x02830080,
- 0xbd0002f6,
- 0x7e070f04,
- 0x80000718,
- 0xf602c000,
- 0x04bd0002,
- 0xf0000bfe,
- 0x24b61f2a,
- 0x0220b604,
- 0x99f094bd,
- 0x37008008,
- 0x0009f602,
- 0x008004bd,
- 0x02f60281,
- 0xd204bd00,
- 0x80000000,
- 0x800225f0,
- 0xf6028800,
- 0x04bd0002,
- 0x00421001,
- 0x0223f002,
- 0xf80512fa,
- 0xf094bd03,
- 0x00800899,
- 0x09f60217,
- 0x9804bd00,
- 0x14b68101,
- 0x80029818,
- 0xfd0825b6,
- 0x01b50512,
- 0xf094bd16,
- 0x00800999,
- 0x09f60237,
- 0x8004bd00,
- 0xf6028100,
- 0x04bd0001,
- 0x00800102,
- 0x02f60288,
- 0x4104bd00,
- 0x13f00100,
- 0x0501fa06,
- 0x94bd03f8,
- 0x800999f0,
- 0xf6021700,
- 0x04bd0009,
- 0x99f094bd,
- 0x17008005,
- 0x0009f602,
- 0x00f804bd,
-/* 0x081c: ctx_chan */
- 0x0007307e,
- 0xb87e0c0a,
- 0x050f0000,
- 0x0007187e,
-/* 0x082e: ctx_mmio_exec */
- 0x039800f8,
- 0x81008041,
- 0x0003f602,
- 0x34bd04bd,
-/* 0x083c: ctx_mmio_loop */
- 0xf4ff34c4,
- 0x00450e1b,
- 0x0653f002,
- 0xf80535fa,
-/* 0x084d: ctx_mmio_pull */
- 0x804e9803,
- 0x7e814f98,
- 0xb600008f,
- 0x12b60830,
- 0xdf1bf401,
-/* 0x0860: ctx_mmio_done */
- 0x80160398,
- 0xf6028100,
- 0x04bd0003,
- 0x414000b5,
- 0x13f00100,
- 0x0601fa06,
- 0x00f803f8,
-/* 0x087c: ctx_xfer */
- 0x0080040e,
- 0x0ef60302,
-/* 0x0887: ctx_xfer_idle */
- 0x8e04bd00,
- 0xcf030000,
- 0xe4f100ee,
- 0x1bf42000,
- 0x0611f4f5,
-/* 0x089b: ctx_xfer_pre */
- 0x0f0c02f4,
- 0x06f97e10,
- 0x1b11f400,
-/* 0x08a4: ctx_xfer_pre_load */
- 0xa87e020f,
- 0xb77e0006,
- 0xc97e0006,
- 0xf4bd0006,
- 0x0006a87e,
- 0x0007307e,
-/* 0x08bc: ctx_xfer_exec */
- 0xbd160198,
- 0x05008024,
- 0x0002f601,
- 0x1fb204bd,
- 0x41a5008e,
- 0x00008f7e,
- 0xf001fcf0,
- 0x24b6022c,
- 0x05f2fd01,
- 0x048effb2,
- 0x8f7e41a5,
- 0x167e0000,
- 0x24bd0002,
- 0x0247fc80,
- 0xbd0002f6,
- 0x012cf004,
- 0x800320b6,
- 0xf6024afc,
- 0x04bd0002,
- 0xf001acf0,
- 0x000b06a5,
- 0x98000c98,
- 0x000e010d,
- 0x00013d7e,
- 0xec7e080a,
- 0x0a7e0000,
- 0x01f40002,
- 0x7e0c0a12,
- 0x0f0000b8,
- 0x07187e05,
- 0x2d02f400,
-/* 0x0938: ctx_xfer_post */
- 0xa87e020f,
- 0xf4bd0006,
- 0x0006f97e,
- 0x0002277e,
- 0x0006b77e,
- 0xa87ef4bd,
- 0x11f40006,
- 0x40019810,
- 0xf40511fd,
- 0x2e7e070b,
-/* 0x0962: ctx_xfer_no_post_mmio */
-/* 0x0962: ctx_xfer_done */
- 0x00f80008,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
deleted file mode 100644
index 3ff52badf932..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GF100
-#include "macros.fuc"
-
-.section #nvc0_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nvc0_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
deleted file mode 100644
index 92dfe6a4ac87..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvc0.fuc.h
+++ /dev/null
@@ -1,1047 +0,0 @@
-uint32_t nvc0_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
- 0x00000300,
-/* 0x0004: hub_mmio_list_tail */
- 0x00000304,
-/* 0x0008: gpc_count */
- 0x00000000,
-/* 0x000c: rop_count */
- 0x00000000,
-/* 0x0010: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: ctx_current */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
- 0x00000000,
-/* 0x0104: chan_mmio_address */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0200: xfer_data */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0300: hub_mmio_list_base */
- 0x0417e91c,
-};
-
-uint32_t nvc0_grhub_code[] = {
- 0x039b0ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0x07f100f8,
- 0x03f00500,
- 0x000fd002,
- 0xf7f004bd,
- 0x0007f101,
- 0x0303f007,
- 0xbd000fd0,
-/* 0x039b: init */
- 0xbd00f804,
- 0x0007fe04,
- 0x420017f1,
- 0xcf0013f0,
- 0x11e70011,
- 0x14b60109,
- 0x0014fe08,
- 0xf10227f0,
- 0xf0120007,
- 0x02d00003,
- 0xf104bd00,
- 0xfe06c817,
- 0x24bd0010,
- 0x070007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0x200327f1,
- 0x010007f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200427f1,
- 0x010407f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200b27f1,
- 0x010807f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200c27f1,
- 0x011c07f1,
- 0xd00103f0,
- 0x04bd0002,
- 0xf1010392,
- 0xf0090007,
- 0x03d00303,
- 0xf104bd00,
- 0xf0870427,
- 0x07f10023,
- 0x03f00400,
- 0x0002d000,
- 0x27f004bd,
- 0x0007f104,
- 0x0003f003,
- 0xbd0002d0,
- 0x1031f404,
- 0x9604e7f1,
- 0xf440e3f0,
- 0xfeb96821,
- 0x90f1c702,
- 0xf0030180,
- 0x0f801ff4,
- 0x0117f002,
- 0xb6041fbb,
- 0x07f10112,
- 0x03f00300,
- 0x0001d001,
- 0x07f104bd,
- 0x03f00400,
- 0x0001d001,
- 0x17f104bd,
- 0xf7f00100,
- 0x0d21f502,
- 0x1f21f508,
- 0x10f7f008,
- 0x086c21f5,
- 0x98000e98,
- 0x21f5010f,
- 0x14950150,
- 0x0007f108,
- 0x0103f0c0,
- 0xbd0004d0,
- 0x0007f104,
- 0x0103f0c1,
- 0xbd0004d0,
- 0x0030b704,
- 0x001fbb13,
- 0xf102f5b6,
- 0xf0d30007,
- 0x0fd00103,
- 0xb604bd00,
- 0x10b60815,
- 0x0814b601,
- 0xf5021fb9,
- 0xbb02d321,
- 0x0398001f,
- 0x0047f102,
- 0x5043f020,
-/* 0x04f4: init_gpc */
- 0x08044ea0,
- 0xf4021fb9,
- 0x4ea09d21,
- 0xf4bd010c,
- 0xa09d21f4,
- 0xf401044e,
- 0x4ea09d21,
- 0xf7f00100,
- 0x9d21f402,
- 0x08004ea0,
-/* 0x051c: init_gpc_wait */
- 0xc86821f4,
- 0x0bf41fff,
- 0x044ea0fa,
- 0x6821f408,
- 0xb7001fbb,
- 0xb6800040,
- 0x1bf40132,
- 0x00f7f0be,
- 0x086c21f5,
- 0xf500f7f0,
- 0xf1080d21,
- 0xf0010007,
- 0x01d00203,
- 0xbd04bd00,
- 0x1f19f014,
- 0x080007f1,
- 0xd00203f0,
- 0x04bd0001,
-/* 0x0564: main */
- 0xf40031f4,
- 0xd7f00028,
- 0x3921f410,
- 0xb1f401f4,
- 0xf54001e4,
- 0xbd00e91b,
- 0x0499f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xc00017f1,
- 0xcf0213f0,
- 0x27f10011,
- 0x23f0c100,
- 0x0022cf02,
- 0xf51f13c8,
- 0xc800890b,
- 0x0bf41f23,
- 0xb920f962,
- 0x94bd0212,
- 0xf10799f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf404bd00,
- 0x31f40132,
- 0x4021f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x20fc04bd,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0131f404,
- 0x0a4021f5,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f017,
- 0xbd0009d0,
- 0x330ef404,
-/* 0x060c: chsw_prev_no_next */
- 0x12b920f9,
- 0x0132f402,
- 0xf50232f4,
- 0xfc0a4021,
- 0x0007f120,
- 0x0203f0c0,
- 0xbd0002d0,
- 0x130ef404,
-/* 0x062c: chsw_no_prev */
- 0xf41f23c8,
- 0x31f40d0b,
- 0x0232f401,
- 0x0a4021f5,
-/* 0x063c: chsw_done */
- 0xf10127f0,
- 0xf0c30007,
- 0x02d00203,
- 0xbd04bd00,
- 0x0499f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
- 0xf401e4b0,
- 0xf2b90d1b,
- 0xd021f502,
- 0x460ef409,
-/* 0x0670: main_not_ctx_chan */
- 0xf402e4b0,
- 0x94bd321b,
- 0xf10799f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf404bd00,
- 0x32f40132,
- 0x4021f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
- 0x10ef9411,
- 0xf501f5f0,
- 0xf5037e21,
-/* 0x06b3: main_done */
- 0xbdfeb50e,
- 0x1f29f024,
- 0x080007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xfea00ef5,
-/* 0x06c8: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x10d7f030,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xb70421f4,
- 0xf00400b0,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x071a: ih_no_fifo */
- 0xabe404bd,
- 0x0bf40100,
- 0x10d7f00d,
- 0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
- 0xe40421f4,
- 0xf40400ab,
- 0xe7f16c0b,
- 0xe3f00708,
- 0x6821f440,
- 0xf102ffb9,
- 0xf0040007,
- 0x0fd00203,
- 0xf104bd00,
- 0xf00704e7,
- 0x21f440e3,
- 0x02ffb968,
- 0x030007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0x9450fec7,
- 0xf7f102ee,
- 0xf3f00700,
- 0x00efbb40,
- 0xf16821f4,
- 0xf0020007,
- 0x0fd00203,
- 0xf004bd00,
- 0x21f503f7,
- 0xb7f1037e,
- 0xbfb90100,
- 0x44e7f102,
- 0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
- 0xf19d21f4,
- 0xbd0504b7,
- 0xb4abffb0,
- 0xf10f0bf4,
- 0xf0070007,
- 0x0bd00303,
-/* 0x07b3: ih_no_other */
- 0xf104bd00,
- 0xf0010007,
- 0x0ad00003,
- 0xfc04bd00,
- 0xfce0fcf0,
- 0xfcb0fcd0,
- 0xfc90fca0,
- 0x0088fe80,
- 0x32f480fc,
-/* 0x07d7: ctx_4160s */
- 0xf001f800,
- 0xffb901f7,
- 0x60e7f102,
- 0x40e3f041,
-/* 0x07e7: ctx_4160s_wait */
- 0xf19d21f4,
- 0xf04160e7,
- 0x21f440e3,
- 0x02ffb968,
- 0xf404ffc8,
- 0x00f8f00b,
-/* 0x07fc: ctx_4160c */
- 0xffb9f4bd,
- 0x60e7f102,
- 0x40e3f041,
- 0xf89d21f4,
-/* 0x080d: ctx_4170s */
- 0x10f5f000,
- 0xf102ffb9,
- 0xf04170e7,
- 0x21f440e3,
-/* 0x081f: ctx_4170w */
- 0xf100f89d,
- 0xf04170e7,
- 0x21f440e3,
- 0x02ffb968,
- 0xf410f4f0,
- 0x00f8f01b,
-/* 0x0834: ctx_redswitch */
- 0x0200e7f1,
- 0xf040e5f0,
- 0xe5f020e5,
- 0x0007f110,
- 0x0103f085,
- 0xbd000ed0,
- 0x08f7f004,
-/* 0x0850: ctx_redswitch_delay */
- 0xf401f2b6,
- 0xe5f1fd1b,
- 0xe5f10400,
- 0x07f10100,
- 0x03f08500,
- 0x000ed001,
- 0x00f804bd,
-/* 0x086c: ctx_86c */
- 0x1b0007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0xf102ffb9,
- 0xf08a14e7,
- 0x21f440e3,
- 0x02ffb99d,
- 0xa86ce7f1,
- 0xf441e3f0,
- 0x00f89d21,
-/* 0x0894: ctx_mem */
- 0x840007f1,
- 0xd00203f0,
- 0x04bd000f,
-/* 0x08a0: ctx_mem_wait */
- 0x8400f7f1,
- 0xcf02f3f0,
- 0xfffd00ff,
- 0xf31bf405,
-/* 0x08b2: ctx_load */
- 0x94bd00f8,
- 0xf10599f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf004bd00,
- 0x21f40ca7,
- 0xf1f4bdd0,
- 0xf0890007,
- 0x0fd00203,
- 0xf104bd00,
- 0xf0c10007,
- 0x02d00203,
- 0xf104bd00,
- 0xf0830007,
- 0x02d00203,
- 0xf004bd00,
- 0x21f507f7,
- 0x07f10894,
- 0x03f0c000,
- 0x0002d002,
- 0x0bfe04bd,
- 0x1f2af000,
- 0xb60424b6,
- 0x94bd0220,
- 0xf10899f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf104bd00,
- 0xf0810007,
- 0x02d00203,
- 0xf104bd00,
- 0xf1000027,
- 0xf0800023,
- 0x07f10225,
- 0x03f08800,
- 0x0002d002,
- 0x17f004bd,
- 0x0027f110,
- 0x0223f002,
- 0xf80512fa,
- 0xf094bd03,
- 0x07f10899,
- 0x03f01700,
- 0x0009d002,
- 0x019804bd,
- 0x1814b681,
- 0xb6800298,
- 0x12fd0825,
- 0x16018005,
- 0x99f094bd,
- 0x0007f109,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f081,
- 0xbd0001d0,
- 0x0127f004,
- 0x880007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0x010017f1,
- 0xfa0613f0,
- 0x03f80501,
- 0x99f094bd,
- 0x0007f109,
- 0x0203f017,
- 0xbd0009d0,
- 0xf094bd04,
- 0x07f10599,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x09d0: ctx_chan */
- 0x07d721f5,
- 0x08b221f5,
- 0xf40ca7f0,
- 0xf7f0d021,
- 0x9421f505,
- 0xfc21f508,
-/* 0x09eb: ctx_mmio_exec */
- 0x9800f807,
- 0x07f14103,
- 0x03f08100,
- 0x0003d002,
- 0x34bd04bd,
-/* 0x09fc: ctx_mmio_loop */
- 0xf4ff34c4,
- 0x57f10f1b,
- 0x53f00200,
- 0x0535fa06,
-/* 0x0a0e: ctx_mmio_pull */
- 0x4e9803f8,
- 0x814f9880,
- 0xb69d21f4,
- 0x12b60830,
- 0xdf1bf401,
-/* 0x0a20: ctx_mmio_done */
- 0xf1160398,
- 0xf0810007,
- 0x03d00203,
- 0x8004bd00,
- 0x17f14000,
- 0x13f00100,
- 0x0601fa06,
- 0x00f803f8,
-/* 0x0a40: ctx_xfer */
- 0xf104e7f0,
- 0xf0020007,
- 0x0ed00303,
-/* 0x0a4f: ctx_xfer_idle */
- 0xf104bd00,
- 0xf00000e7,
- 0xeecf03e3,
- 0x00e4f100,
- 0xf21bf420,
- 0xf40611f4,
-/* 0x0a66: ctx_xfer_pre */
- 0xf7f01102,
- 0x6c21f510,
- 0xd721f508,
- 0x1c11f407,
-/* 0x0a74: ctx_xfer_pre_load */
- 0xf502f7f0,
- 0xf5080d21,
- 0xf5081f21,
- 0xbd083421,
- 0x0d21f5f4,
- 0xb221f508,
-/* 0x0a8d: ctx_xfer_exec */
- 0x16019808,
- 0x07f124bd,
- 0x03f00500,
- 0x0002d001,
- 0x1fb904bd,
- 0x00e7f102,
- 0x41e3f0a5,
- 0xf09d21f4,
- 0x2cf001fc,
- 0x0124b602,
- 0xb905f2fd,
- 0xe7f102ff,
- 0xe3f0a504,
- 0x9d21f441,
- 0x026a21f5,
- 0x07f124bd,
- 0x03f047fc,
- 0x0002d002,
- 0x2cf004bd,
- 0x0320b601,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xf001acf0,
- 0xb7f006a5,
- 0x000c9800,
- 0xf0010d98,
- 0x21f500e7,
- 0xa7f0016f,
- 0x1021f508,
- 0x5e21f501,
- 0x1301f402,
- 0xf40ca7f0,
- 0xf7f0d021,
- 0x9421f505,
- 0x3202f408,
-/* 0x0b1c: ctx_xfer_post */
- 0xf502f7f0,
- 0xbd080d21,
- 0x6c21f5f4,
- 0x7f21f508,
- 0x1f21f502,
- 0xf5f4bd08,
- 0xf4080d21,
- 0x01981011,
- 0x0511fd40,
- 0xf5070bf4,
-/* 0x0b47: ctx_xfer_no_post_mmio */
- 0xf509eb21,
-/* 0x0b4b: ctx_xfer_done */
- 0xf807fc21,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
deleted file mode 100644
index afbe03ac9077..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GF117
-#include "macros.fuc"
-
-.section #nvd7_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nvd7_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
deleted file mode 100644
index 62b0c7601d8b..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvd7.fuc.h
+++ /dev/null
@@ -1,1047 +0,0 @@
-uint32_t nvd7_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
- 0x00000300,
-/* 0x0004: hub_mmio_list_tail */
- 0x00000304,
-/* 0x0008: gpc_count */
- 0x00000000,
-/* 0x000c: rop_count */
- 0x00000000,
-/* 0x0010: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: ctx_current */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
- 0x00000000,
-/* 0x0104: chan_mmio_address */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0200: xfer_data */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0300: hub_mmio_list_base */
- 0x0417e91c,
-};
-
-uint32_t nvd7_grhub_code[] = {
- 0x039b0ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0x07f100f8,
- 0x03f00500,
- 0x000fd002,
- 0xf7f004bd,
- 0x0007f101,
- 0x0303f007,
- 0xbd000fd0,
-/* 0x039b: init */
- 0xbd00f804,
- 0x0007fe04,
- 0x420017f1,
- 0xcf0013f0,
- 0x11e70011,
- 0x14b60109,
- 0x0014fe08,
- 0xf10227f0,
- 0xf0120007,
- 0x02d00003,
- 0xf104bd00,
- 0xfe06c817,
- 0x24bd0010,
- 0x070007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0x200327f1,
- 0x010007f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200427f1,
- 0x010407f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200b27f1,
- 0x010807f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200c27f1,
- 0x011c07f1,
- 0xd00103f0,
- 0x04bd0002,
- 0xf1010392,
- 0xf0090007,
- 0x03d00303,
- 0xf104bd00,
- 0xf0870427,
- 0x07f10023,
- 0x03f00400,
- 0x0002d000,
- 0x27f004bd,
- 0x0007f104,
- 0x0003f003,
- 0xbd0002d0,
- 0x1031f404,
- 0x9604e7f1,
- 0xf440e3f0,
- 0xfeb96821,
- 0x90f1c702,
- 0xf0030180,
- 0x0f801ff4,
- 0x0117f002,
- 0xb6041fbb,
- 0x07f10112,
- 0x03f00300,
- 0x0001d001,
- 0x07f104bd,
- 0x03f00400,
- 0x0001d001,
- 0x17f104bd,
- 0xf7f00100,
- 0x0d21f502,
- 0x1f21f508,
- 0x10f7f008,
- 0x086c21f5,
- 0x98000e98,
- 0x21f5010f,
- 0x14950150,
- 0x0007f108,
- 0x0103f0c0,
- 0xbd0004d0,
- 0x0007f104,
- 0x0103f0c1,
- 0xbd0004d0,
- 0x0030b704,
- 0x001fbb13,
- 0xf102f5b6,
- 0xf0d30007,
- 0x0fd00103,
- 0xb604bd00,
- 0x10b60815,
- 0x0814b601,
- 0xf5021fb9,
- 0xbb02d321,
- 0x0398001f,
- 0x0047f102,
- 0x5043f020,
-/* 0x04f4: init_gpc */
- 0x08044ea0,
- 0xf4021fb9,
- 0x4ea09d21,
- 0xf4bd010c,
- 0xa09d21f4,
- 0xf401044e,
- 0x4ea09d21,
- 0xf7f00100,
- 0x9d21f402,
- 0x08004ea0,
-/* 0x051c: init_gpc_wait */
- 0xc86821f4,
- 0x0bf41fff,
- 0x044ea0fa,
- 0x6821f408,
- 0xb7001fbb,
- 0xb6800040,
- 0x1bf40132,
- 0x00f7f0be,
- 0x086c21f5,
- 0xf500f7f0,
- 0xf1080d21,
- 0xf0010007,
- 0x01d00203,
- 0xbd04bd00,
- 0x1f19f014,
- 0x080007f1,
- 0xd00203f0,
- 0x04bd0001,
-/* 0x0564: main */
- 0xf40031f4,
- 0xd7f00028,
- 0x3921f410,
- 0xb1f401f4,
- 0xf54001e4,
- 0xbd00e91b,
- 0x0499f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xc00017f1,
- 0xcf0213f0,
- 0x27f10011,
- 0x23f0c100,
- 0x0022cf02,
- 0xf51f13c8,
- 0xc800890b,
- 0x0bf41f23,
- 0xb920f962,
- 0x94bd0212,
- 0xf10799f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf404bd00,
- 0x31f40132,
- 0x4021f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x20fc04bd,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0131f404,
- 0x0a4021f5,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f017,
- 0xbd0009d0,
- 0x330ef404,
-/* 0x060c: chsw_prev_no_next */
- 0x12b920f9,
- 0x0132f402,
- 0xf50232f4,
- 0xfc0a4021,
- 0x0007f120,
- 0x0203f0c0,
- 0xbd0002d0,
- 0x130ef404,
-/* 0x062c: chsw_no_prev */
- 0xf41f23c8,
- 0x31f40d0b,
- 0x0232f401,
- 0x0a4021f5,
-/* 0x063c: chsw_done */
- 0xf10127f0,
- 0xf0c30007,
- 0x02d00203,
- 0xbd04bd00,
- 0x0499f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
- 0xf401e4b0,
- 0xf2b90d1b,
- 0xd021f502,
- 0x460ef409,
-/* 0x0670: main_not_ctx_chan */
- 0xf402e4b0,
- 0x94bd321b,
- 0xf10799f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf404bd00,
- 0x32f40132,
- 0x4021f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
- 0x10ef9411,
- 0xf501f5f0,
- 0xf5037e21,
-/* 0x06b3: main_done */
- 0xbdfeb50e,
- 0x1f29f024,
- 0x080007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xfea00ef5,
-/* 0x06c8: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x10d7f030,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xb70421f4,
- 0xf00400b0,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x071a: ih_no_fifo */
- 0xabe404bd,
- 0x0bf40100,
- 0x10d7f00d,
- 0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
- 0xe40421f4,
- 0xf40400ab,
- 0xe7f16c0b,
- 0xe3f00708,
- 0x6821f440,
- 0xf102ffb9,
- 0xf0040007,
- 0x0fd00203,
- 0xf104bd00,
- 0xf00704e7,
- 0x21f440e3,
- 0x02ffb968,
- 0x030007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0x9450fec7,
- 0xf7f102ee,
- 0xf3f00700,
- 0x00efbb40,
- 0xf16821f4,
- 0xf0020007,
- 0x0fd00203,
- 0xf004bd00,
- 0x21f503f7,
- 0xb7f1037e,
- 0xbfb90100,
- 0x44e7f102,
- 0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
- 0xf19d21f4,
- 0xbd0504b7,
- 0xb4abffb0,
- 0xf10f0bf4,
- 0xf0070007,
- 0x0bd00303,
-/* 0x07b3: ih_no_other */
- 0xf104bd00,
- 0xf0010007,
- 0x0ad00003,
- 0xfc04bd00,
- 0xfce0fcf0,
- 0xfcb0fcd0,
- 0xfc90fca0,
- 0x0088fe80,
- 0x32f480fc,
-/* 0x07d7: ctx_4160s */
- 0xf001f800,
- 0xffb901f7,
- 0x60e7f102,
- 0x40e3f041,
-/* 0x07e7: ctx_4160s_wait */
- 0xf19d21f4,
- 0xf04160e7,
- 0x21f440e3,
- 0x02ffb968,
- 0xf404ffc8,
- 0x00f8f00b,
-/* 0x07fc: ctx_4160c */
- 0xffb9f4bd,
- 0x60e7f102,
- 0x40e3f041,
- 0xf89d21f4,
-/* 0x080d: ctx_4170s */
- 0x10f5f000,
- 0xf102ffb9,
- 0xf04170e7,
- 0x21f440e3,
-/* 0x081f: ctx_4170w */
- 0xf100f89d,
- 0xf04170e7,
- 0x21f440e3,
- 0x02ffb968,
- 0xf410f4f0,
- 0x00f8f01b,
-/* 0x0834: ctx_redswitch */
- 0x0200e7f1,
- 0xf040e5f0,
- 0xe5f020e5,
- 0x0007f110,
- 0x0103f085,
- 0xbd000ed0,
- 0x08f7f004,
-/* 0x0850: ctx_redswitch_delay */
- 0xf401f2b6,
- 0xe5f1fd1b,
- 0xe5f10400,
- 0x07f10100,
- 0x03f08500,
- 0x000ed001,
- 0x00f804bd,
-/* 0x086c: ctx_86c */
- 0x1b0007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0xf102ffb9,
- 0xf08a14e7,
- 0x21f440e3,
- 0x02ffb99d,
- 0xa86ce7f1,
- 0xf441e3f0,
- 0x00f89d21,
-/* 0x0894: ctx_mem */
- 0x840007f1,
- 0xd00203f0,
- 0x04bd000f,
-/* 0x08a0: ctx_mem_wait */
- 0x8400f7f1,
- 0xcf02f3f0,
- 0xfffd00ff,
- 0xf31bf405,
-/* 0x08b2: ctx_load */
- 0x94bd00f8,
- 0xf10599f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf004bd00,
- 0x21f40ca7,
- 0xf1f4bdd0,
- 0xf0890007,
- 0x0fd00203,
- 0xf104bd00,
- 0xf0c10007,
- 0x02d00203,
- 0xf104bd00,
- 0xf0830007,
- 0x02d00203,
- 0xf004bd00,
- 0x21f507f7,
- 0x07f10894,
- 0x03f0c000,
- 0x0002d002,
- 0x0bfe04bd,
- 0x1f2af000,
- 0xb60424b6,
- 0x94bd0220,
- 0xf10899f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf104bd00,
- 0xf0810007,
- 0x02d00203,
- 0xf104bd00,
- 0xf1000027,
- 0xf0800023,
- 0x07f10225,
- 0x03f08800,
- 0x0002d002,
- 0x17f004bd,
- 0x0027f110,
- 0x0223f002,
- 0xf80512fa,
- 0xf094bd03,
- 0x07f10899,
- 0x03f01700,
- 0x0009d002,
- 0x019804bd,
- 0x1814b681,
- 0xb6800298,
- 0x12fd0825,
- 0x16018005,
- 0x99f094bd,
- 0x0007f109,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f081,
- 0xbd0001d0,
- 0x0127f004,
- 0x880007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0x010017f1,
- 0xfa0613f0,
- 0x03f80501,
- 0x99f094bd,
- 0x0007f109,
- 0x0203f017,
- 0xbd0009d0,
- 0xf094bd04,
- 0x07f10599,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x09d0: ctx_chan */
- 0x07d721f5,
- 0x08b221f5,
- 0xf40ca7f0,
- 0xf7f0d021,
- 0x9421f505,
- 0xfc21f508,
-/* 0x09eb: ctx_mmio_exec */
- 0x9800f807,
- 0x07f14103,
- 0x03f08100,
- 0x0003d002,
- 0x34bd04bd,
-/* 0x09fc: ctx_mmio_loop */
- 0xf4ff34c4,
- 0x57f10f1b,
- 0x53f00200,
- 0x0535fa06,
-/* 0x0a0e: ctx_mmio_pull */
- 0x4e9803f8,
- 0x814f9880,
- 0xb69d21f4,
- 0x12b60830,
- 0xdf1bf401,
-/* 0x0a20: ctx_mmio_done */
- 0xf1160398,
- 0xf0810007,
- 0x03d00203,
- 0x8004bd00,
- 0x17f14000,
- 0x13f00100,
- 0x0601fa06,
- 0x00f803f8,
-/* 0x0a40: ctx_xfer */
- 0xf104e7f0,
- 0xf0020007,
- 0x0ed00303,
-/* 0x0a4f: ctx_xfer_idle */
- 0xf104bd00,
- 0xf00000e7,
- 0xeecf03e3,
- 0x00e4f100,
- 0xf21bf420,
- 0xf40611f4,
-/* 0x0a66: ctx_xfer_pre */
- 0xf7f01102,
- 0x6c21f510,
- 0xd721f508,
- 0x1c11f407,
-/* 0x0a74: ctx_xfer_pre_load */
- 0xf502f7f0,
- 0xf5080d21,
- 0xf5081f21,
- 0xbd083421,
- 0x0d21f5f4,
- 0xb221f508,
-/* 0x0a8d: ctx_xfer_exec */
- 0x16019808,
- 0x07f124bd,
- 0x03f00500,
- 0x0002d001,
- 0x1fb904bd,
- 0x00e7f102,
- 0x41e3f0a5,
- 0xf09d21f4,
- 0x2cf001fc,
- 0x0124b602,
- 0xb905f2fd,
- 0xe7f102ff,
- 0xe3f0a504,
- 0x9d21f441,
- 0x026a21f5,
- 0x07f124bd,
- 0x03f047fc,
- 0x0002d002,
- 0x2cf004bd,
- 0x0320b601,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xf001acf0,
- 0xb7f006a5,
- 0x000c9800,
- 0xf0010d98,
- 0x21f500e7,
- 0xa7f0016f,
- 0x1021f508,
- 0x5e21f501,
- 0x1301f402,
- 0xf40ca7f0,
- 0xf7f0d021,
- 0x9421f505,
- 0x3202f408,
-/* 0x0b1c: ctx_xfer_post */
- 0xf502f7f0,
- 0xbd080d21,
- 0x6c21f5f4,
- 0x7f21f508,
- 0x1f21f502,
- 0xf5f4bd08,
- 0xf4080d21,
- 0x01981011,
- 0x0511fd40,
- 0xf5070bf4,
-/* 0x0b47: ctx_xfer_no_post_mmio */
- 0xf509eb21,
-/* 0x0b4b: ctx_xfer_done */
- 0xf807fc21,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
deleted file mode 100644
index d4840f1879fd..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GK100
-#include "macros.fuc"
-
-.section #nve0_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nve0_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
deleted file mode 100644
index 51c3797d8537..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnve0.fuc.h
+++ /dev/null
@@ -1,1044 +0,0 @@
-uint32_t nve0_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
- 0x00000300,
-/* 0x0004: hub_mmio_list_tail */
- 0x00000304,
-/* 0x0008: gpc_count */
- 0x00000000,
-/* 0x000c: rop_count */
- 0x00000000,
-/* 0x0010: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: ctx_current */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
- 0x00000000,
-/* 0x0104: chan_mmio_address */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0200: xfer_data */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0300: hub_mmio_list_base */
- 0x0417e91c,
-};
-
-uint32_t nve0_grhub_code[] = {
- 0x039b0ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0x07f100f8,
- 0x03f00500,
- 0x000fd002,
- 0xf7f004bd,
- 0x0007f101,
- 0x0303f007,
- 0xbd000fd0,
-/* 0x039b: init */
- 0xbd00f804,
- 0x0007fe04,
- 0x420017f1,
- 0xcf0013f0,
- 0x11e70011,
- 0x14b60109,
- 0x0014fe08,
- 0xf10227f0,
- 0xf0120007,
- 0x02d00003,
- 0xf104bd00,
- 0xfe06c817,
- 0x24bd0010,
- 0x070007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0x200327f1,
- 0x010007f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200427f1,
- 0x010407f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200b27f1,
- 0x010807f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200c27f1,
- 0x011c07f1,
- 0xd00103f0,
- 0x04bd0002,
- 0xf1010392,
- 0xf0090007,
- 0x03d00303,
- 0xf104bd00,
- 0xf0870427,
- 0x07f10023,
- 0x03f00400,
- 0x0002d000,
- 0x27f004bd,
- 0x0007f104,
- 0x0003f003,
- 0xbd0002d0,
- 0x1031f404,
- 0x9604e7f1,
- 0xf440e3f0,
- 0xfeb96821,
- 0x90f1c702,
- 0xf0030180,
- 0x0f801ff4,
- 0x0117f002,
- 0xb6041fbb,
- 0x07f10112,
- 0x03f00300,
- 0x0001d001,
- 0x07f104bd,
- 0x03f00400,
- 0x0001d001,
- 0x17f104bd,
- 0xf7f00100,
- 0xd721f502,
- 0xe921f507,
- 0x10f7f007,
- 0x083621f5,
- 0x98000e98,
- 0x21f5010f,
- 0x14950150,
- 0x0007f108,
- 0x0103f0c0,
- 0xbd0004d0,
- 0x0007f104,
- 0x0103f0c1,
- 0xbd0004d0,
- 0x0030b704,
- 0x001fbb13,
- 0xf102f5b6,
- 0xf0d30007,
- 0x0fd00103,
- 0xb604bd00,
- 0x10b60815,
- 0x0814b601,
- 0xf5021fb9,
- 0xbb02d321,
- 0x0398001f,
- 0x0047f102,
- 0x5043f020,
-/* 0x04f4: init_gpc */
- 0x08044ea0,
- 0xf4021fb9,
- 0x4ea09d21,
- 0xf4bd010c,
- 0xa09d21f4,
- 0xf401044e,
- 0x4ea09d21,
- 0xf7f00100,
- 0x9d21f402,
- 0x08004ea0,
-/* 0x051c: init_gpc_wait */
- 0xc86821f4,
- 0x0bf41fff,
- 0x044ea0fa,
- 0x6821f408,
- 0xb7001fbb,
- 0xb6800040,
- 0x1bf40132,
- 0x00f7f0be,
- 0x083621f5,
- 0xf500f7f0,
- 0xf107d721,
- 0xf0010007,
- 0x01d00203,
- 0xbd04bd00,
- 0x1f19f014,
- 0x080007f1,
- 0xd00203f0,
- 0x04bd0001,
-/* 0x0564: main */
- 0xf40031f4,
- 0xd7f00028,
- 0x3921f410,
- 0xb1f401f4,
- 0xf54001e4,
- 0xbd00e91b,
- 0x0499f094,
- 0x0f0007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xc00017f1,
- 0xcf0213f0,
- 0x27f10011,
- 0x23f0c100,
- 0x0022cf02,
- 0xf51f13c8,
- 0xc800890b,
- 0x0bf41f23,
- 0xb920f962,
- 0x94bd0212,
- 0xf10799f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf404bd00,
- 0x31f40132,
- 0x0221f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x20fc04bd,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0131f404,
- 0x0a0221f5,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f017,
- 0xbd0009d0,
- 0x330ef404,
-/* 0x060c: chsw_prev_no_next */
- 0x12b920f9,
- 0x0132f402,
- 0xf50232f4,
- 0xfc0a0221,
- 0x0007f120,
- 0x0203f0c0,
- 0xbd0002d0,
- 0x130ef404,
-/* 0x062c: chsw_no_prev */
- 0xf41f23c8,
- 0x31f40d0b,
- 0x0232f401,
- 0x0a0221f5,
-/* 0x063c: chsw_done */
- 0xf10127f0,
- 0xf0c30007,
- 0x02d00203,
- 0xbd04bd00,
- 0x0499f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
- 0xf401e4b0,
- 0xf2b90d1b,
- 0x9a21f502,
- 0x460ef409,
-/* 0x0670: main_not_ctx_chan */
- 0xf402e4b0,
- 0x94bd321b,
- 0xf10799f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf404bd00,
- 0x32f40132,
- 0x0221f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
- 0x10ef9411,
- 0xf501f5f0,
- 0xf5037e21,
-/* 0x06b3: main_done */
- 0xbdfeb50e,
- 0x1f29f024,
- 0x080007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xfea00ef5,
-/* 0x06c8: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x10d7f030,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xb70421f4,
- 0xf00400b0,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x071a: ih_no_fifo */
- 0xabe404bd,
- 0x0bf40100,
- 0x10d7f00d,
- 0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
- 0xe40421f4,
- 0xf40400ab,
- 0xe7f16c0b,
- 0xe3f00708,
- 0x6821f440,
- 0xf102ffb9,
- 0xf0040007,
- 0x0fd00203,
- 0xf104bd00,
- 0xf00704e7,
- 0x21f440e3,
- 0x02ffb968,
- 0x030007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0x9450fec7,
- 0xf7f102ee,
- 0xf3f00700,
- 0x00efbb40,
- 0xf16821f4,
- 0xf0020007,
- 0x0fd00203,
- 0xf004bd00,
- 0x21f503f7,
- 0xb7f1037e,
- 0xbfb90100,
- 0x44e7f102,
- 0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
- 0xf19d21f4,
- 0xbd0504b7,
- 0xb4abffb0,
- 0xf10f0bf4,
- 0xf0070007,
- 0x0bd00303,
-/* 0x07b3: ih_no_other */
- 0xf104bd00,
- 0xf0010007,
- 0x0ad00003,
- 0xfc04bd00,
- 0xfce0fcf0,
- 0xfcb0fcd0,
- 0xfc90fca0,
- 0x0088fe80,
- 0x32f480fc,
-/* 0x07d7: ctx_4170s */
- 0xf001f800,
- 0xffb910f5,
- 0x70e7f102,
- 0x40e3f041,
- 0xf89d21f4,
-/* 0x07e9: ctx_4170w */
- 0x70e7f100,
- 0x40e3f041,
- 0xb96821f4,
- 0xf4f002ff,
- 0xf01bf410,
-/* 0x07fe: ctx_redswitch */
- 0xe7f100f8,
- 0xe5f00200,
- 0x20e5f040,
- 0xf110e5f0,
- 0xf0850007,
- 0x0ed00103,
- 0xf004bd00,
-/* 0x081a: ctx_redswitch_delay */
- 0xf2b608f7,
- 0xfd1bf401,
- 0x0400e5f1,
- 0x0100e5f1,
- 0x850007f1,
- 0xd00103f0,
- 0x04bd000e,
-/* 0x0836: ctx_86c */
- 0x07f100f8,
- 0x03f01b00,
- 0x000fd002,
- 0xffb904bd,
- 0x14e7f102,
- 0x40e3f08a,
- 0xb99d21f4,
- 0xe7f102ff,
- 0xe3f0a86c,
- 0x9d21f441,
-/* 0x085e: ctx_mem */
- 0x07f100f8,
- 0x03f08400,
- 0x000fd002,
-/* 0x086a: ctx_mem_wait */
- 0xf7f104bd,
- 0xf3f08400,
- 0x00ffcf02,
- 0xf405fffd,
- 0x00f8f31b,
-/* 0x087c: ctx_load */
- 0x99f094bd,
- 0x0007f105,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0ca7f004,
- 0xbdd021f4,
- 0x0007f1f4,
- 0x0203f089,
- 0xbd000fd0,
- 0x0007f104,
- 0x0203f0c1,
- 0xbd0002d0,
- 0x0007f104,
- 0x0203f083,
- 0xbd0002d0,
- 0x07f7f004,
- 0x085e21f5,
- 0xc00007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xf0000bfe,
- 0x24b61f2a,
- 0x0220b604,
- 0x99f094bd,
- 0x0007f108,
- 0x0203f00f,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f081,
- 0xbd0002d0,
- 0x0027f104,
- 0x0023f100,
- 0x0225f080,
- 0x880007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xf11017f0,
- 0xf0020027,
- 0x12fa0223,
- 0xbd03f805,
- 0x0899f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xb6810198,
- 0x02981814,
- 0x0825b680,
- 0x800512fd,
- 0x94bd1601,
- 0xf10999f0,
- 0xf00f0007,
- 0x09d00203,
- 0xf104bd00,
- 0xf0810007,
- 0x01d00203,
- 0xf004bd00,
- 0x07f10127,
- 0x03f08800,
- 0x0002d002,
- 0x17f104bd,
- 0x13f00100,
- 0x0501fa06,
- 0x94bd03f8,
- 0xf10999f0,
- 0xf0170007,
- 0x09d00203,
- 0xbd04bd00,
- 0x0599f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x099a: ctx_chan */
- 0x21f500f8,
- 0xa7f0087c,
- 0xd021f40c,
- 0xf505f7f0,
- 0xf8085e21,
-/* 0x09ad: ctx_mmio_exec */
- 0x41039800,
- 0x810007f1,
- 0xd00203f0,
- 0x04bd0003,
-/* 0x09be: ctx_mmio_loop */
- 0x34c434bd,
- 0x0f1bf4ff,
- 0x020057f1,
- 0xfa0653f0,
- 0x03f80535,
-/* 0x09d0: ctx_mmio_pull */
- 0x98804e98,
- 0x21f4814f,
- 0x0830b69d,
- 0xf40112b6,
-/* 0x09e2: ctx_mmio_done */
- 0x0398df1b,
- 0x0007f116,
- 0x0203f081,
- 0xbd0003d0,
- 0x40008004,
- 0x010017f1,
- 0xfa0613f0,
- 0x03f80601,
-/* 0x0a02: ctx_xfer */
- 0xe7f000f8,
- 0x0007f104,
- 0x0303f002,
- 0xbd000ed0,
-/* 0x0a11: ctx_xfer_idle */
- 0x00e7f104,
- 0x03e3f000,
- 0xf100eecf,
- 0xf42000e4,
- 0x11f4f21b,
- 0x0d02f406,
-/* 0x0a28: ctx_xfer_pre */
- 0xf510f7f0,
- 0xf4083621,
-/* 0x0a32: ctx_xfer_pre_load */
- 0xf7f01c11,
- 0xd721f502,
- 0xe921f507,
- 0xfe21f507,
- 0xf5f4bd07,
- 0xf507d721,
-/* 0x0a4b: ctx_xfer_exec */
- 0x98087c21,
- 0x24bd1601,
- 0x050007f1,
- 0xd00103f0,
- 0x04bd0002,
- 0xf1021fb9,
- 0xf0a500e7,
- 0x21f441e3,
- 0x01fcf09d,
- 0xb6022cf0,
- 0xf2fd0124,
- 0x02ffb905,
- 0xa504e7f1,
- 0xf441e3f0,
- 0x21f59d21,
- 0x24bd026a,
- 0x47fc07f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xb6012cf0,
- 0x07f10320,
- 0x03f04afc,
- 0x0002d002,
- 0xacf004bd,
- 0x06a5f001,
- 0x9800b7f0,
- 0x0d98000c,
- 0x00e7f001,
- 0x016f21f5,
- 0xf508a7f0,
- 0xf5011021,
- 0xf4025e21,
- 0xa7f01301,
- 0xd021f40c,
- 0xf505f7f0,
- 0xf4085e21,
-/* 0x0ada: ctx_xfer_post */
- 0xf7f02e02,
- 0xd721f502,
- 0xf5f4bd07,
- 0xf5083621,
- 0xf5027f21,
- 0xbd07e921,
- 0xd721f5f4,
- 0x1011f407,
- 0xfd400198,
- 0x0bf40511,
- 0xad21f507,
-/* 0x0b05: ctx_xfer_no_post_mmio */
-/* 0x0b05: ctx_xfer_done */
- 0x0000f809,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
deleted file mode 100644
index ec42ed29b50d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#define CHIPSET GK110
-#include "macros.fuc"
-
-.section #nvf0_grhub_data
-#define INCLUDE_DATA
-#include "com.fuc"
-#include "hub.fuc"
-#undef INCLUDE_DATA
-
-.section #nvf0_grhub_code
-#define INCLUDE_CODE
-bra #init
-#include "com.fuc"
-#include "hub.fuc"
-.align 256
-#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h b/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
deleted file mode 100644
index a0af4b703a8e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubnvf0.fuc.h
+++ /dev/null
@@ -1,1044 +0,0 @@
-uint32_t nvf0_grhub_data[] = {
-/* 0x0000: hub_mmio_list_head */
- 0x00000300,
-/* 0x0004: hub_mmio_list_tail */
- 0x00000304,
-/* 0x0008: gpc_count */
- 0x00000000,
-/* 0x000c: rop_count */
- 0x00000000,
-/* 0x0010: cmd_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: ctx_current */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0100: chan_data */
-/* 0x0100: chan_mmio_count */
- 0x00000000,
-/* 0x0104: chan_mmio_address */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0200: xfer_data */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0300: hub_mmio_list_base */
- 0x0417e91c,
-};
-
-uint32_t nvf0_grhub_code[] = {
- 0x039b0ef5,
-/* 0x0004: queue_put */
- 0x9800d898,
- 0x86f001d9,
- 0x0489b808,
- 0xf00c1bf4,
- 0x21f502f7,
- 0x00f8037e,
-/* 0x001c: queue_put_next */
- 0xb60798c4,
- 0x8dbb0384,
- 0x0880b600,
- 0x80008e80,
- 0x90b6018f,
- 0x0f94f001,
- 0xf801d980,
-/* 0x0039: queue_get */
- 0x0131f400,
- 0x9800d898,
- 0x89b801d9,
- 0x210bf404,
- 0xb60789c4,
- 0x9dbb0394,
- 0x0890b600,
- 0x98009e98,
- 0x80b6019f,
- 0x0f84f001,
- 0xf400d880,
-/* 0x0066: queue_get_done */
- 0x00f80132,
-/* 0x0068: nv_rd32 */
- 0xf002ecb9,
- 0x07f11fc9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x007a: nv_rd32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0xa7f0f31b,
- 0x1021f506,
- 0x00f7f101,
- 0x01f3f0cb,
- 0xf800ffcf,
-/* 0x009d: nv_wr32 */
- 0x0007f100,
- 0x0103f0cc,
- 0xbd000fd0,
- 0x02ecb904,
- 0xf01fc9f0,
- 0x07f11ec9,
- 0x03f0ca00,
- 0x000cd001,
-/* 0x00be: nv_wr32_wait */
- 0xc7f104bd,
- 0xc3f0ca00,
- 0x00cccf01,
- 0xf41fccc8,
- 0x00f8f31b,
-/* 0x00d0: wait_donez */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f037,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x00ed: wait_donez_ne */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x1bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0110: wait_doneo */
- 0x99f094bd,
- 0x0007f100,
- 0x0203f037,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f006,
- 0xbd000ad0,
-/* 0x012d: wait_doneo_e */
- 0x0087f104,
- 0x0183f000,
- 0xff0088cf,
- 0x0bf4888a,
- 0xf094bdf3,
- 0x07f10099,
- 0x03f01700,
- 0x0009d002,
- 0x00f804bd,
-/* 0x0150: mmctx_size */
-/* 0x0152: nv_mmctx_size_loop */
- 0xe89894bd,
- 0x1a85b600,
- 0xb60180b6,
- 0x98bb0284,
- 0x04e0b600,
- 0xf404efb8,
- 0x9fb9eb1b,
-/* 0x016f: mmctx_xfer */
- 0xbd00f802,
- 0x0199f094,
- 0x370007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xbbfd94bd,
- 0x120bf405,
- 0xc40007f1,
- 0xd00103f0,
- 0x04bd000b,
-/* 0x0197: mmctx_base_disabled */
- 0xfd0099f0,
- 0x0bf405ee,
- 0x0007f11e,
- 0x0103f0c6,
- 0xbd000ed0,
- 0x0007f104,
- 0x0103f0c7,
- 0xbd000fd0,
- 0x0199f004,
-/* 0x01b8: mmctx_multi_disabled */
- 0xb600abc8,
- 0xb9f010b4,
- 0x01aec80c,
- 0xfd11e4b6,
- 0x07f105be,
- 0x03f0c500,
- 0x000bd001,
-/* 0x01d6: mmctx_exec_loop */
-/* 0x01d6: mmctx_wait_free */
- 0xe7f104bd,
- 0xe3f0c500,
- 0x00eecf01,
- 0xf41fe4f0,
- 0xce98f30b,
- 0x05e9fd00,
- 0xc80007f1,
- 0xd00103f0,
- 0x04bd000e,
- 0xb804c0b6,
- 0x1bf404cd,
- 0x02abc8d8,
-/* 0x0207: mmctx_fini_wait */
- 0xf11f1bf4,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x1fb4f000,
- 0xf410b4b0,
- 0xa7f0f01b,
- 0xd021f405,
-/* 0x0223: mmctx_stop */
- 0xc82b0ef4,
- 0xb4b600ab,
- 0x0cb9f010,
- 0xf112b9f0,
- 0xf0c50007,
- 0x0bd00103,
-/* 0x023b: mmctx_stop_wait */
- 0xf104bd00,
- 0xf0c500b7,
- 0xbbcf01b3,
- 0x12bbc800,
-/* 0x024b: mmctx_done */
- 0xbdf31bf4,
- 0x0199f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x025e: strand_wait */
- 0xa0f900f8,
- 0xf402a7f0,
- 0xa0fcd021,
-/* 0x026a: strand_pre */
- 0x97f000f8,
- 0xfc07f10c,
- 0x0203f04a,
- 0xbd0009d0,
- 0x5e21f504,
-/* 0x027f: strand_post */
- 0xf000f802,
- 0x07f10d97,
- 0x03f04afc,
- 0x0009d002,
- 0x21f504bd,
- 0x00f8025e,
-/* 0x0294: strand_set */
- 0xf10fc7f0,
- 0xf04ffc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f10bc7,
- 0x03f04afc,
- 0x000cd002,
- 0x07f104bd,
- 0x03f04ffc,
- 0x000ed002,
- 0xc7f004bd,
- 0xfc07f10a,
- 0x0203f04a,
- 0xbd000cd0,
- 0x5e21f504,
-/* 0x02d3: strand_ctx_init */
- 0xbd00f802,
- 0x0399f094,
- 0x370007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0x026a21f5,
- 0xf503e7f0,
- 0xbd029421,
- 0xfc07f1c4,
- 0x0203f047,
- 0xbd000cd0,
- 0x01c7f004,
- 0x4afc07f1,
- 0xd00203f0,
- 0x04bd000c,
- 0x025e21f5,
- 0xf1010c92,
- 0xf046fc07,
- 0x0cd00203,
- 0xf004bd00,
- 0x07f102c7,
- 0x03f04afc,
- 0x000cd002,
- 0x21f504bd,
- 0x21f5025e,
- 0x87f1027f,
- 0x83f04200,
- 0x0097f102,
- 0x0293f020,
- 0x950099cf,
-/* 0x034a: ctx_init_strand_loop */
- 0x8ed008fe,
- 0x408ed000,
- 0xb6808acf,
- 0xa0b606a5,
- 0x00eabb01,
- 0xb60480b6,
- 0x1bf40192,
- 0x08e4b6e8,
- 0xbdf2efbc,
- 0x0399f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x037e: error */
- 0x07f100f8,
- 0x03f00500,
- 0x000fd002,
- 0xf7f004bd,
- 0x0007f101,
- 0x0303f007,
- 0xbd000fd0,
-/* 0x039b: init */
- 0xbd00f804,
- 0x0007fe04,
- 0x420017f1,
- 0xcf0013f0,
- 0x11e70011,
- 0x14b60109,
- 0x0014fe08,
- 0xf10227f0,
- 0xf0120007,
- 0x02d00003,
- 0xf104bd00,
- 0xfe06c817,
- 0x24bd0010,
- 0x070007f1,
- 0xd00003f0,
- 0x04bd0002,
- 0x200327f1,
- 0x010007f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200427f1,
- 0x010407f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200b27f1,
- 0x010807f1,
- 0xd00103f0,
- 0x04bd0002,
- 0x200c27f1,
- 0x011c07f1,
- 0xd00103f0,
- 0x04bd0002,
- 0xf1010392,
- 0xf0090007,
- 0x03d00303,
- 0xf104bd00,
- 0xf0870427,
- 0x07f10023,
- 0x03f00400,
- 0x0002d000,
- 0x27f004bd,
- 0x0007f104,
- 0x0003f003,
- 0xbd0002d0,
- 0x1031f404,
- 0x9604e7f1,
- 0xf440e3f0,
- 0xfeb96821,
- 0x90f1c702,
- 0xf0030180,
- 0x0f801ff4,
- 0x0117f002,
- 0xb6041fbb,
- 0x07f10112,
- 0x03f00300,
- 0x0001d001,
- 0x07f104bd,
- 0x03f00400,
- 0x0001d001,
- 0x17f104bd,
- 0xf7f00100,
- 0xd721f502,
- 0xe921f507,
- 0x10f7f007,
- 0x083621f5,
- 0x98000e98,
- 0x21f5010f,
- 0x14950150,
- 0x0007f108,
- 0x0103f0c0,
- 0xbd0004d0,
- 0x0007f104,
- 0x0103f0c1,
- 0xbd0004d0,
- 0x0030b704,
- 0x001fbb13,
- 0xf102f5b6,
- 0xf0d30007,
- 0x0fd00103,
- 0xb604bd00,
- 0x10b60815,
- 0x0814b601,
- 0xf5021fb9,
- 0xbb02d321,
- 0x0398001f,
- 0x0047f102,
- 0x5043f020,
-/* 0x04f4: init_gpc */
- 0x08044ea0,
- 0xf4021fb9,
- 0x4ea09d21,
- 0xf4bd010c,
- 0xa09d21f4,
- 0xf401044e,
- 0x4ea09d21,
- 0xf7f00100,
- 0x9d21f402,
- 0x08004ea0,
-/* 0x051c: init_gpc_wait */
- 0xc86821f4,
- 0x0bf41fff,
- 0x044ea0fa,
- 0x6821f408,
- 0xb7001fbb,
- 0xb6800040,
- 0x1bf40132,
- 0x00f7f0be,
- 0x083621f5,
- 0xf500f7f0,
- 0xf107d721,
- 0xf0010007,
- 0x01d00203,
- 0xbd04bd00,
- 0x1f19f014,
- 0x300007f1,
- 0xd00203f0,
- 0x04bd0001,
-/* 0x0564: main */
- 0xf40031f4,
- 0xd7f00028,
- 0x3921f410,
- 0xb1f401f4,
- 0xf54001e4,
- 0xbd00e91b,
- 0x0499f094,
- 0x370007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xc00017f1,
- 0xcf0213f0,
- 0x27f10011,
- 0x23f0c100,
- 0x0022cf02,
- 0xf51f13c8,
- 0xc800890b,
- 0x0bf41f23,
- 0xb920f962,
- 0x94bd0212,
- 0xf10799f0,
- 0xf0370007,
- 0x09d00203,
- 0xf404bd00,
- 0x31f40132,
- 0x0221f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x20fc04bd,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f037,
- 0xbd0009d0,
- 0x0131f404,
- 0x0a0221f5,
- 0x99f094bd,
- 0x0007f106,
- 0x0203f017,
- 0xbd0009d0,
- 0x330ef404,
-/* 0x060c: chsw_prev_no_next */
- 0x12b920f9,
- 0x0132f402,
- 0xf50232f4,
- 0xfc0a0221,
- 0x0007f120,
- 0x0203f0c0,
- 0xbd0002d0,
- 0x130ef404,
-/* 0x062c: chsw_no_prev */
- 0xf41f23c8,
- 0x31f40d0b,
- 0x0232f401,
- 0x0a0221f5,
-/* 0x063c: chsw_done */
- 0xf10127f0,
- 0xf0c30007,
- 0x02d00203,
- 0xbd04bd00,
- 0x0499f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xff080ef5,
-/* 0x0660: main_not_ctx_switch */
- 0xf401e4b0,
- 0xf2b90d1b,
- 0x9a21f502,
- 0x460ef409,
-/* 0x0670: main_not_ctx_chan */
- 0xf402e4b0,
- 0x94bd321b,
- 0xf10799f0,
- 0xf0370007,
- 0x09d00203,
- 0xf404bd00,
- 0x32f40132,
- 0x0221f502,
- 0xf094bd0a,
- 0x07f10799,
- 0x03f01700,
- 0x0009d002,
- 0x0ef404bd,
-/* 0x06a5: main_not_ctx_save */
- 0x10ef9411,
- 0xf501f5f0,
- 0xf5037e21,
-/* 0x06b3: main_done */
- 0xbdfeb50e,
- 0x1f29f024,
- 0x300007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xfea00ef5,
-/* 0x06c8: ih */
- 0x88fe80f9,
- 0xf980f901,
- 0xf9a0f990,
- 0xf9d0f9b0,
- 0xbdf0f9e0,
- 0x00a7f104,
- 0x00a3f002,
- 0xc400aacf,
- 0x0bf404ab,
- 0x10d7f030,
- 0x1a00e7f1,
- 0xcf00e3f0,
- 0xf7f100ee,
- 0xf3f01900,
- 0x00ffcf00,
- 0xb70421f4,
- 0xf00400b0,
- 0x07f101e7,
- 0x03f01d00,
- 0x000ed000,
-/* 0x071a: ih_no_fifo */
- 0xabe404bd,
- 0x0bf40100,
- 0x10d7f00d,
- 0x4001e7f1,
-/* 0x072b: ih_no_ctxsw */
- 0xe40421f4,
- 0xf40400ab,
- 0xe7f16c0b,
- 0xe3f00708,
- 0x6821f440,
- 0xf102ffb9,
- 0xf0040007,
- 0x0fd00203,
- 0xf104bd00,
- 0xf00704e7,
- 0x21f440e3,
- 0x02ffb968,
- 0x030007f1,
- 0xd00203f0,
- 0x04bd000f,
- 0x9450fec7,
- 0xf7f102ee,
- 0xf3f00700,
- 0x00efbb40,
- 0xf16821f4,
- 0xf0020007,
- 0x0fd00203,
- 0xf004bd00,
- 0x21f503f7,
- 0xb7f1037e,
- 0xbfb90100,
- 0x44e7f102,
- 0x40e3f001,
-/* 0x079b: ih_no_fwmthd */
- 0xf19d21f4,
- 0xbd0504b7,
- 0xb4abffb0,
- 0xf10f0bf4,
- 0xf0070007,
- 0x0bd00303,
-/* 0x07b3: ih_no_other */
- 0xf104bd00,
- 0xf0010007,
- 0x0ad00003,
- 0xfc04bd00,
- 0xfce0fcf0,
- 0xfcb0fcd0,
- 0xfc90fca0,
- 0x0088fe80,
- 0x32f480fc,
-/* 0x07d7: ctx_4170s */
- 0xf001f800,
- 0xffb910f5,
- 0x70e7f102,
- 0x40e3f041,
- 0xf89d21f4,
-/* 0x07e9: ctx_4170w */
- 0x70e7f100,
- 0x40e3f041,
- 0xb96821f4,
- 0xf4f002ff,
- 0xf01bf410,
-/* 0x07fe: ctx_redswitch */
- 0xe7f100f8,
- 0xe5f00200,
- 0x20e5f040,
- 0xf110e5f0,
- 0xf0850007,
- 0x0ed00103,
- 0xf004bd00,
-/* 0x081a: ctx_redswitch_delay */
- 0xf2b608f7,
- 0xfd1bf401,
- 0x0400e5f1,
- 0x0100e5f1,
- 0x850007f1,
- 0xd00103f0,
- 0x04bd000e,
-/* 0x0836: ctx_86c */
- 0x07f100f8,
- 0x03f02300,
- 0x000fd002,
- 0xffb904bd,
- 0x14e7f102,
- 0x40e3f08a,
- 0xb99d21f4,
- 0xe7f102ff,
- 0xe3f0a88c,
- 0x9d21f441,
-/* 0x085e: ctx_mem */
- 0x07f100f8,
- 0x03f08400,
- 0x000fd002,
-/* 0x086a: ctx_mem_wait */
- 0xf7f104bd,
- 0xf3f08400,
- 0x00ffcf02,
- 0xf405fffd,
- 0x00f8f31b,
-/* 0x087c: ctx_load */
- 0x99f094bd,
- 0x0007f105,
- 0x0203f037,
- 0xbd0009d0,
- 0x0ca7f004,
- 0xbdd021f4,
- 0x0007f1f4,
- 0x0203f089,
- 0xbd000fd0,
- 0x0007f104,
- 0x0203f0c1,
- 0xbd0002d0,
- 0x0007f104,
- 0x0203f083,
- 0xbd0002d0,
- 0x07f7f004,
- 0x085e21f5,
- 0xc00007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xf0000bfe,
- 0x24b61f2a,
- 0x0220b604,
- 0x99f094bd,
- 0x0007f108,
- 0x0203f037,
- 0xbd0009d0,
- 0x0007f104,
- 0x0203f081,
- 0xbd0002d0,
- 0x0027f104,
- 0x0023f100,
- 0x0225f080,
- 0x880007f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xf11017f0,
- 0xf0020027,
- 0x12fa0223,
- 0xbd03f805,
- 0x0899f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
- 0xb6810198,
- 0x02981814,
- 0x0825b680,
- 0x800512fd,
- 0x94bd1601,
- 0xf10999f0,
- 0xf0370007,
- 0x09d00203,
- 0xf104bd00,
- 0xf0810007,
- 0x01d00203,
- 0xf004bd00,
- 0x07f10127,
- 0x03f08800,
- 0x0002d002,
- 0x17f104bd,
- 0x13f00100,
- 0x0501fa06,
- 0x94bd03f8,
- 0xf10999f0,
- 0xf0170007,
- 0x09d00203,
- 0xbd04bd00,
- 0x0599f094,
- 0x170007f1,
- 0xd00203f0,
- 0x04bd0009,
-/* 0x099a: ctx_chan */
- 0x21f500f8,
- 0xa7f0087c,
- 0xd021f40c,
- 0xf505f7f0,
- 0xf8085e21,
-/* 0x09ad: ctx_mmio_exec */
- 0x41039800,
- 0x810007f1,
- 0xd00203f0,
- 0x04bd0003,
-/* 0x09be: ctx_mmio_loop */
- 0x34c434bd,
- 0x0f1bf4ff,
- 0x020057f1,
- 0xfa0653f0,
- 0x03f80535,
-/* 0x09d0: ctx_mmio_pull */
- 0x98804e98,
- 0x21f4814f,
- 0x0830b69d,
- 0xf40112b6,
-/* 0x09e2: ctx_mmio_done */
- 0x0398df1b,
- 0x0007f116,
- 0x0203f081,
- 0xbd0003d0,
- 0x40008004,
- 0x010017f1,
- 0xfa0613f0,
- 0x03f80601,
-/* 0x0a02: ctx_xfer */
- 0xe7f000f8,
- 0x0007f104,
- 0x0303f002,
- 0xbd000ed0,
-/* 0x0a11: ctx_xfer_idle */
- 0x00e7f104,
- 0x03e3f000,
- 0xf100eecf,
- 0xf42000e4,
- 0x11f4f21b,
- 0x0d02f406,
-/* 0x0a28: ctx_xfer_pre */
- 0xf510f7f0,
- 0xf4083621,
-/* 0x0a32: ctx_xfer_pre_load */
- 0xf7f01c11,
- 0xd721f502,
- 0xe921f507,
- 0xfe21f507,
- 0xf5f4bd07,
- 0xf507d721,
-/* 0x0a4b: ctx_xfer_exec */
- 0x98087c21,
- 0x24bd1601,
- 0x050007f1,
- 0xd00103f0,
- 0x04bd0002,
- 0xf1021fb9,
- 0xf0a500e7,
- 0x21f441e3,
- 0x01fcf09d,
- 0xb6022cf0,
- 0xf2fd0124,
- 0x02ffb905,
- 0xa504e7f1,
- 0xf441e3f0,
- 0x21f59d21,
- 0x24bd026a,
- 0x47fc07f1,
- 0xd00203f0,
- 0x04bd0002,
- 0xb6012cf0,
- 0x07f10320,
- 0x03f04afc,
- 0x0002d002,
- 0xacf004bd,
- 0x06a5f001,
- 0x9800b7f0,
- 0x0d98000c,
- 0x00e7f001,
- 0x016f21f5,
- 0xf508a7f0,
- 0xf5011021,
- 0xf4025e21,
- 0xa7f01301,
- 0xd021f40c,
- 0xf505f7f0,
- 0xf4085e21,
-/* 0x0ada: ctx_xfer_post */
- 0xf7f02e02,
- 0xd721f502,
- 0xf5f4bd07,
- 0xf5083621,
- 0xf5027f21,
- 0xbd07e921,
- 0xd721f5f4,
- 0x1011f407,
- 0xfd400198,
- 0x0bf40511,
- 0xad21f507,
-/* 0x0b05: ctx_xfer_no_post_mmio */
-/* 0x0b05: ctx_xfer_done */
- 0x0000f809,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c
deleted file mode 100644
index d07b19dc168d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/gk110b.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gk110b_graph_init_l1c_0[] = {
- { 0x419c98, 1, 0x04, 0x00000000 },
- { 0x419ca8, 1, 0x04, 0x00000000 },
- { 0x419cb0, 1, 0x04, 0x09000000 },
- { 0x419cb4, 1, 0x04, 0x00000000 },
- { 0x419cb8, 1, 0x04, 0x00b08bea },
- { 0x419c84, 1, 0x04, 0x00010384 },
- { 0x419cbc, 1, 0x04, 0x281b3646 },
- { 0x419cc0, 2, 0x04, 0x00000000 },
- { 0x419c80, 1, 0x04, 0x00020230 },
- { 0x419ccc, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gk110b_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000080 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ee4, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x00000000 },
- { 0x419eb4, 1, 0x04, 0x00000000 },
- { 0x419ebc, 2, 0x04, 0x00000000 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419ed0, 1, 0x04, 0x00002616 },
- { 0x419f74, 1, 0x04, 0x00015555 },
- { 0x419f80, 4, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gk110b_graph_pack_mmio[] = {
- { nve4_graph_init_main_0 },
- { nvf0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvd9_graph_init_pd_0 },
- { nvf0_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvf0_graph_init_sked_0 },
- { nvf0_graph_init_cwd_0 },
- { nvd9_graph_init_prop_0 },
- { nvc1_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvd9_graph_init_gpm_0 },
- { nvf0_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nve4_graph_init_tpccs_0 },
- { nvf0_graph_init_tex_0 },
- { nve4_graph_init_pe_0 },
- { gk110b_graph_init_l1c_0 },
- { nvc0_graph_init_mpc_0 },
- { gk110b_graph_init_sm_0 },
- { nvd7_graph_init_pes_0 },
- { nvd7_graph_init_wwdx_0 },
- { nvd7_graph_init_cbm_0 },
- { nve4_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-gk110b_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xf1),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nve4_graph_init,
- .fini = nvf0_graph_fini,
- },
- .cclass = &gk110b_grctx_oclass,
- .sclass = nvf0_graph_sclass,
- .mmio = gk110b_graph_pack_mmio,
- .fecs.ucode = &nvf0_graph_fecs_ucode,
- .gpccs.ucode = &nvf0_graph_gpccs_ucode,
- .ppc_nr = 2,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c b/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c
deleted file mode 100644
index 7d0abe9f3fe7..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/gk20a.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "nvc0.h"
-#include "ctxnvc0.h"
-
-static struct nouveau_oclass
-gk20a_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0xa040, &nouveau_object_ofuncs },
- { KEPLER_C, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { KEPLER_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-struct nouveau_oclass *
-gk20a_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xea),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nve4_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &gk20a_grctx_oclass,
- .sclass = gk20a_graph_sclass,
- .mmio = nve4_graph_pack_mmio,
- .ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c b/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c
deleted file mode 100644
index 4bdbdab2fd9a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/gm107.c
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/P0260.h>
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-gm107_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0xa140, &nouveau_object_ofuncs },
- { MAXWELL_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { MAXWELL_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-gm107_graph_init_main_0[] = {
- { 0x400080, 1, 0x04, 0x003003c2 },
- { 0x400088, 1, 0x04, 0x0001bfe7 },
- { 0x40008c, 1, 0x04, 0x00060000 },
- { 0x400090, 1, 0x04, 0x00000030 },
- { 0x40013c, 1, 0x04, 0x003901f3 },
- { 0x400140, 1, 0x04, 0x00000100 },
- { 0x400144, 1, 0x04, 0x00000000 },
- { 0x400148, 1, 0x04, 0x00000110 },
- { 0x400138, 1, 0x04, 0x00000000 },
- { 0x400130, 2, 0x04, 0x00000000 },
- { 0x400124, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405900, 1, 0x04, 0x00000000 },
- { 0x405908, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_scc_0[] = {
- { 0x40803c, 1, 0x04, 0x00000010 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_sked_0[] = {
- { 0x407010, 1, 0x04, 0x00000000 },
- { 0x407040, 1, 0x04, 0x40440424 },
- { 0x407048, 1, 0x04, 0x0000000a },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_prop_0[] = {
- { 0x418408, 1, 0x04, 0x00000000 },
- { 0x4184a0, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_setup_1[] = {
- { 0x4188c8, 2, 0x04, 0x00000000 },
- { 0x4188d0, 1, 0x04, 0x00010000 },
- { 0x4188d4, 1, 0x04, 0x00010201 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_zcull_0[] = {
- { 0x418910, 1, 0x04, 0x00010001 },
- { 0x418914, 1, 0x04, 0x00000301 },
- { 0x418918, 1, 0x04, 0x00800000 },
- { 0x418930, 2, 0x04, 0x00000000 },
- { 0x418980, 1, 0x04, 0x77777770 },
- { 0x418984, 3, 0x04, 0x77777777 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_gpc_unk_1[] = {
- { 0x418d00, 1, 0x04, 0x00000000 },
- { 0x418f00, 1, 0x04, 0x00000400 },
- { 0x418f08, 1, 0x04, 0x00000000 },
- { 0x418e08, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_tpccs_0[] = {
- { 0x419dc4, 1, 0x04, 0x00000000 },
- { 0x419dc8, 1, 0x04, 0x00000501 },
- { 0x419dd0, 1, 0x04, 0x00000000 },
- { 0x419dd4, 1, 0x04, 0x00000100 },
- { 0x419dd8, 1, 0x04, 0x00000001 },
- { 0x419ddc, 1, 0x04, 0x00000002 },
- { 0x419de0, 1, 0x04, 0x00000001 },
- { 0x419d0c, 1, 0x04, 0x00000000 },
- { 0x419d10, 1, 0x04, 0x00000014 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_tex_0[] = {
- { 0x419ab0, 1, 0x04, 0x00000000 },
- { 0x419ab8, 1, 0x04, 0x000000e7 },
- { 0x419abc, 1, 0x04, 0x00000000 },
- { 0x419acc, 1, 0x04, 0x000000ff },
- { 0x419ac0, 1, 0x04, 0x00000000 },
- { 0x419aa8, 2, 0x04, 0x00000000 },
- { 0x419ad0, 2, 0x04, 0x00000000 },
- { 0x419ae0, 2, 0x04, 0x00000000 },
- { 0x419af0, 4, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_pe_0[] = {
- { 0x419900, 1, 0x04, 0x000000ff },
- { 0x41980c, 1, 0x04, 0x00000010 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x419838, 1, 0x04, 0x000000ff },
- { 0x419850, 1, 0x04, 0x00000004 },
- { 0x419854, 2, 0x04, 0x00000000 },
- { 0x419894, 3, 0x04, 0x00100401 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_l1c_0[] = {
- { 0x419c98, 1, 0x04, 0x00000000 },
- { 0x419cc0, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_sm_0[] = {
- { 0x419e30, 1, 0x04, 0x000000ff },
- { 0x419e00, 1, 0x04, 0x00000000 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ee4, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x01000000 },
- { 0x419ee8, 1, 0x04, 0x00000091 },
- { 0x419eb4, 1, 0x04, 0x00000000 },
- { 0x419ebc, 2, 0x04, 0x00000000 },
- { 0x419edc, 1, 0x04, 0x000c1810 },
- { 0x419ed8, 1, 0x04, 0x00000000 },
- { 0x419ee0, 1, 0x04, 0x00000000 },
- { 0x419f74, 1, 0x04, 0x00005155 },
- { 0x419f80, 4, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_l1c_1[] = {
- { 0x419ccc, 2, 0x04, 0x00000000 },
- { 0x419c80, 1, 0x04, 0x3f006022 },
- { 0x419c88, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_pes_0[] = {
- { 0x41be50, 1, 0x04, 0x000000ff },
- { 0x41be04, 1, 0x04, 0x00000000 },
- { 0x41be08, 1, 0x04, 0x00000004 },
- { 0x41be0c, 1, 0x04, 0x00000008 },
- { 0x41be10, 1, 0x04, 0x0e3b8bc7 },
- { 0x41be14, 2, 0x04, 0x00000000 },
- { 0x41be3c, 5, 0x04, 0x00100401 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_wwdx_0[] = {
- { 0x41bfd4, 1, 0x04, 0x00800000 },
- { 0x41bfdc, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_cbm_0[] = {
- { 0x41becc, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_be_0[] = {
- { 0x408890, 1, 0x04, 0x000000ff },
- { 0x40880c, 1, 0x04, 0x00000000 },
- { 0x408850, 1, 0x04, 0x00000004 },
- { 0x408878, 1, 0x04, 0x00c81603 },
- { 0x40887c, 1, 0x04, 0x80543432 },
- { 0x408880, 1, 0x04, 0x0010581e },
- { 0x408884, 1, 0x04, 0x00001205 },
- { 0x408974, 1, 0x04, 0x000000ff },
- { 0x408910, 9, 0x04, 0x00000000 },
- { 0x408950, 1, 0x04, 0x00000000 },
- { 0x408954, 1, 0x04, 0x0000ffff },
- { 0x408958, 1, 0x04, 0x00000034 },
- { 0x40895c, 1, 0x04, 0x8531a003 },
- { 0x408960, 1, 0x04, 0x0561985a },
- { 0x408964, 1, 0x04, 0x04e15c4f },
- { 0x408968, 1, 0x04, 0x02808833 },
- { 0x40896c, 1, 0x04, 0x01f02438 },
- { 0x408970, 1, 0x04, 0x00012c00 },
- { 0x408984, 1, 0x04, 0x00000000 },
- { 0x408988, 1, 0x04, 0x08040201 },
- { 0x40898c, 1, 0x04, 0x80402010 },
- {}
-};
-
-static const struct nvc0_graph_init
-gm107_graph_init_sm_1[] = {
- { 0x419e5c, 1, 0x04, 0x00000000 },
- { 0x419e58, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-gm107_graph_pack_mmio[] = {
- { gm107_graph_init_main_0 },
- { nvf0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvc0_graph_init_pd_0 },
- { gm107_graph_init_ds_0 },
- { gm107_graph_init_scc_0 },
- { gm107_graph_init_sked_0 },
- { nvf0_graph_init_cwd_0 },
- { gm107_graph_init_prop_0 },
- { nv108_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { gm107_graph_init_setup_1 },
- { gm107_graph_init_zcull_0 },
- { nvc0_graph_init_gpm_0 },
- { gm107_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { gm107_graph_init_tpccs_0 },
- { gm107_graph_init_tex_0 },
- { gm107_graph_init_pe_0 },
- { gm107_graph_init_l1c_0 },
- { nvc0_graph_init_mpc_0 },
- { gm107_graph_init_sm_0 },
- { gm107_graph_init_l1c_1 },
- { gm107_graph_init_pes_0 },
- { gm107_graph_init_wwdx_0 },
- { gm107_graph_init_cbm_0 },
- { gm107_graph_init_be_0 },
- { gm107_graph_init_sm_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-gm107_graph_init_bios(struct nvc0_graph_priv *priv)
-{
- static const struct {
- u32 ctrl;
- u32 data;
- } regs[] = {
- { 0x419ed8, 0x419ee0 },
- { 0x419ad0, 0x419ad4 },
- { 0x419ae0, 0x419ae4 },
- { 0x419af0, 0x419af4 },
- { 0x419af8, 0x419afc },
- };
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_P0260E infoE;
- struct nvbios_P0260X infoX;
- int E = -1, X;
- u8 ver, hdr;
-
- while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) {
- if (X = -1, E < ARRAY_SIZE(regs)) {
- nv_wr32(priv, regs[E].ctrl, infoE.data);
- while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX))
- nv_wr32(priv, regs[E].data, infoX.data);
- }
- }
-}
-
-int
-gm107_graph_init(struct nouveau_object *object)
-{
- struct nvc0_graph_oclass *oclass = (void *)object->oclass;
- struct nvc0_graph_priv *priv = (void *)object;
- const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
- u32 data[TPC_MAX / 8] = {};
- u8 tpcnr[GPC_MAX];
- int gpc, tpc, ppc, rop;
- int ret, i;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
- nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-
- nvc0_graph_mmio(priv, oclass->mmio);
-
- gm107_graph_init_bios(priv);
-
- nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
-
- memset(data, 0x00, sizeof(data));
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- data[i / 8] |= tpc << ((i % 8) * 4);
- }
-
- nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
- nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
- nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
- nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
- priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
- priv->tpc_total);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
- }
-
- nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
- nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-
- nv_wr32(priv, 0x400500, 0x00010001);
-
- nv_wr32(priv, 0x400100, 0xffffffff);
- nv_wr32(priv, 0x40013c, 0xffffffff);
- nv_wr32(priv, 0x400124, 0x00000002);
- nv_wr32(priv, 0x409c24, 0x000e0000);
-
- nv_wr32(priv, 0x404000, 0xc0000000);
- nv_wr32(priv, 0x404600, 0xc0000000);
- nv_wr32(priv, 0x408030, 0xc0000000);
- nv_wr32(priv, 0x404490, 0xc0000000);
- nv_wr32(priv, 0x406018, 0xc0000000);
- nv_wr32(priv, 0x407020, 0x40000000);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x405844, 0x00ffffff);
- nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++)
- nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005);
- }
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
- }
-
- for (rop = 0; rop < priv->rop_nr; rop++) {
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
- nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
- }
-
- nv_wr32(priv, 0x400108, 0xffffffff);
- nv_wr32(priv, 0x400138, 0xffffffff);
- nv_wr32(priv, 0x400118, 0xffffffff);
- nv_wr32(priv, 0x400130, 0xffffffff);
- nv_wr32(priv, 0x40011c, 0xffffffff);
- nv_wr32(priv, 0x400134, 0xffffffff);
-
- nv_wr32(priv, 0x400054, 0x2c350f63);
-
- nvc0_graph_zbc_init(priv);
-
- return nvc0_graph_init_ctxctl(priv);
-}
-
-#include "fuc/hubgm107.fuc5.h"
-
-static struct nvc0_graph_ucode
-gm107_graph_fecs_ucode = {
- .code.data = gm107_grhub_code,
- .code.size = sizeof(gm107_grhub_code),
- .data.data = gm107_grhub_data,
- .data.size = sizeof(gm107_grhub_data),
-};
-
-#include "fuc/gpcgm107.fuc5.h"
-
-static struct nvc0_graph_ucode
-gm107_graph_gpccs_ucode = {
- .code.data = gm107_grgpc_code,
- .code.size = sizeof(gm107_grgpc_code),
- .data.data = gm107_grgpc_data,
- .data.size = sizeof(gm107_grgpc_data),
-};
-
-struct nouveau_oclass *
-gm107_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0x07),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = gm107_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &gm107_grctx_oclass,
- .sclass = gm107_graph_sclass,
- .mmio = gm107_graph_pack_mmio,
- .fecs.ucode = 0 ? &gm107_graph_fecs_ucode : NULL,
- .gpccs.ucode = &gm107_graph_gpccs_ucode,
- .ppc_nr = 2,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
deleted file mode 100644
index f70e2f67a4dd..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv04.c
+++ /dev/null
@@ -1,1388 +0,0 @@
-/*
- * Copyright 2007 Stephane Marchesin
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/handle.h>
-#include <core/namedb.h>
-
-#include <subdev/fb.h>
-#include <subdev/instmem.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "regs.h"
-
-static u32
-nv04_graph_ctx_regs[] = {
- 0x0040053c,
- 0x00400544,
- 0x00400540,
- 0x00400548,
- NV04_PGRAPH_CTX_SWITCH1,
- NV04_PGRAPH_CTX_SWITCH2,
- NV04_PGRAPH_CTX_SWITCH3,
- NV04_PGRAPH_CTX_SWITCH4,
- NV04_PGRAPH_CTX_CACHE1,
- NV04_PGRAPH_CTX_CACHE2,
- NV04_PGRAPH_CTX_CACHE3,
- NV04_PGRAPH_CTX_CACHE4,
- 0x00400184,
- 0x004001a4,
- 0x004001c4,
- 0x004001e4,
- 0x00400188,
- 0x004001a8,
- 0x004001c8,
- 0x004001e8,
- 0x0040018c,
- 0x004001ac,
- 0x004001cc,
- 0x004001ec,
- 0x00400190,
- 0x004001b0,
- 0x004001d0,
- 0x004001f0,
- 0x00400194,
- 0x004001b4,
- 0x004001d4,
- 0x004001f4,
- 0x00400198,
- 0x004001b8,
- 0x004001d8,
- 0x004001f8,
- 0x0040019c,
- 0x004001bc,
- 0x004001dc,
- 0x004001fc,
- 0x00400174,
- NV04_PGRAPH_DMA_START_0,
- NV04_PGRAPH_DMA_START_1,
- NV04_PGRAPH_DMA_LENGTH,
- NV04_PGRAPH_DMA_MISC,
- NV04_PGRAPH_DMA_PITCH,
- NV04_PGRAPH_BOFFSET0,
- NV04_PGRAPH_BBASE0,
- NV04_PGRAPH_BLIMIT0,
- NV04_PGRAPH_BOFFSET1,
- NV04_PGRAPH_BBASE1,
- NV04_PGRAPH_BLIMIT1,
- NV04_PGRAPH_BOFFSET2,
- NV04_PGRAPH_BBASE2,
- NV04_PGRAPH_BLIMIT2,
- NV04_PGRAPH_BOFFSET3,
- NV04_PGRAPH_BBASE3,
- NV04_PGRAPH_BLIMIT3,
- NV04_PGRAPH_BOFFSET4,
- NV04_PGRAPH_BBASE4,
- NV04_PGRAPH_BLIMIT4,
- NV04_PGRAPH_BOFFSET5,
- NV04_PGRAPH_BBASE5,
- NV04_PGRAPH_BLIMIT5,
- NV04_PGRAPH_BPITCH0,
- NV04_PGRAPH_BPITCH1,
- NV04_PGRAPH_BPITCH2,
- NV04_PGRAPH_BPITCH3,
- NV04_PGRAPH_BPITCH4,
- NV04_PGRAPH_SURFACE,
- NV04_PGRAPH_STATE,
- NV04_PGRAPH_BSWIZZLE2,
- NV04_PGRAPH_BSWIZZLE5,
- NV04_PGRAPH_BPIXEL,
- NV04_PGRAPH_NOTIFY,
- NV04_PGRAPH_PATT_COLOR0,
- NV04_PGRAPH_PATT_COLOR1,
- NV04_PGRAPH_PATT_COLORRAM+0x00,
- NV04_PGRAPH_PATT_COLORRAM+0x04,
- NV04_PGRAPH_PATT_COLORRAM+0x08,
- NV04_PGRAPH_PATT_COLORRAM+0x0c,
- NV04_PGRAPH_PATT_COLORRAM+0x10,
- NV04_PGRAPH_PATT_COLORRAM+0x14,
- NV04_PGRAPH_PATT_COLORRAM+0x18,
- NV04_PGRAPH_PATT_COLORRAM+0x1c,
- NV04_PGRAPH_PATT_COLORRAM+0x20,
- NV04_PGRAPH_PATT_COLORRAM+0x24,
- NV04_PGRAPH_PATT_COLORRAM+0x28,
- NV04_PGRAPH_PATT_COLORRAM+0x2c,
- NV04_PGRAPH_PATT_COLORRAM+0x30,
- NV04_PGRAPH_PATT_COLORRAM+0x34,
- NV04_PGRAPH_PATT_COLORRAM+0x38,
- NV04_PGRAPH_PATT_COLORRAM+0x3c,
- NV04_PGRAPH_PATT_COLORRAM+0x40,
- NV04_PGRAPH_PATT_COLORRAM+0x44,
- NV04_PGRAPH_PATT_COLORRAM+0x48,
- NV04_PGRAPH_PATT_COLORRAM+0x4c,
- NV04_PGRAPH_PATT_COLORRAM+0x50,
- NV04_PGRAPH_PATT_COLORRAM+0x54,
- NV04_PGRAPH_PATT_COLORRAM+0x58,
- NV04_PGRAPH_PATT_COLORRAM+0x5c,
- NV04_PGRAPH_PATT_COLORRAM+0x60,
- NV04_PGRAPH_PATT_COLORRAM+0x64,
- NV04_PGRAPH_PATT_COLORRAM+0x68,
- NV04_PGRAPH_PATT_COLORRAM+0x6c,
- NV04_PGRAPH_PATT_COLORRAM+0x70,
- NV04_PGRAPH_PATT_COLORRAM+0x74,
- NV04_PGRAPH_PATT_COLORRAM+0x78,
- NV04_PGRAPH_PATT_COLORRAM+0x7c,
- NV04_PGRAPH_PATT_COLORRAM+0x80,
- NV04_PGRAPH_PATT_COLORRAM+0x84,
- NV04_PGRAPH_PATT_COLORRAM+0x88,
- NV04_PGRAPH_PATT_COLORRAM+0x8c,
- NV04_PGRAPH_PATT_COLORRAM+0x90,
- NV04_PGRAPH_PATT_COLORRAM+0x94,
- NV04_PGRAPH_PATT_COLORRAM+0x98,
- NV04_PGRAPH_PATT_COLORRAM+0x9c,
- NV04_PGRAPH_PATT_COLORRAM+0xa0,
- NV04_PGRAPH_PATT_COLORRAM+0xa4,
- NV04_PGRAPH_PATT_COLORRAM+0xa8,
- NV04_PGRAPH_PATT_COLORRAM+0xac,
- NV04_PGRAPH_PATT_COLORRAM+0xb0,
- NV04_PGRAPH_PATT_COLORRAM+0xb4,
- NV04_PGRAPH_PATT_COLORRAM+0xb8,
- NV04_PGRAPH_PATT_COLORRAM+0xbc,
- NV04_PGRAPH_PATT_COLORRAM+0xc0,
- NV04_PGRAPH_PATT_COLORRAM+0xc4,
- NV04_PGRAPH_PATT_COLORRAM+0xc8,
- NV04_PGRAPH_PATT_COLORRAM+0xcc,
- NV04_PGRAPH_PATT_COLORRAM+0xd0,
- NV04_PGRAPH_PATT_COLORRAM+0xd4,
- NV04_PGRAPH_PATT_COLORRAM+0xd8,
- NV04_PGRAPH_PATT_COLORRAM+0xdc,
- NV04_PGRAPH_PATT_COLORRAM+0xe0,
- NV04_PGRAPH_PATT_COLORRAM+0xe4,
- NV04_PGRAPH_PATT_COLORRAM+0xe8,
- NV04_PGRAPH_PATT_COLORRAM+0xec,
- NV04_PGRAPH_PATT_COLORRAM+0xf0,
- NV04_PGRAPH_PATT_COLORRAM+0xf4,
- NV04_PGRAPH_PATT_COLORRAM+0xf8,
- NV04_PGRAPH_PATT_COLORRAM+0xfc,
- NV04_PGRAPH_PATTERN,
- 0x0040080c,
- NV04_PGRAPH_PATTERN_SHAPE,
- 0x00400600,
- NV04_PGRAPH_ROP3,
- NV04_PGRAPH_CHROMA,
- NV04_PGRAPH_BETA_AND,
- NV04_PGRAPH_BETA_PREMULT,
- NV04_PGRAPH_CONTROL0,
- NV04_PGRAPH_CONTROL1,
- NV04_PGRAPH_CONTROL2,
- NV04_PGRAPH_BLEND,
- NV04_PGRAPH_STORED_FMT,
- NV04_PGRAPH_SOURCE_COLOR,
- 0x00400560,
- 0x00400568,
- 0x00400564,
- 0x0040056c,
- 0x00400400,
- 0x00400480,
- 0x00400404,
- 0x00400484,
- 0x00400408,
- 0x00400488,
- 0x0040040c,
- 0x0040048c,
- 0x00400410,
- 0x00400490,
- 0x00400414,
- 0x00400494,
- 0x00400418,
- 0x00400498,
- 0x0040041c,
- 0x0040049c,
- 0x00400420,
- 0x004004a0,
- 0x00400424,
- 0x004004a4,
- 0x00400428,
- 0x004004a8,
- 0x0040042c,
- 0x004004ac,
- 0x00400430,
- 0x004004b0,
- 0x00400434,
- 0x004004b4,
- 0x00400438,
- 0x004004b8,
- 0x0040043c,
- 0x004004bc,
- 0x00400440,
- 0x004004c0,
- 0x00400444,
- 0x004004c4,
- 0x00400448,
- 0x004004c8,
- 0x0040044c,
- 0x004004cc,
- 0x00400450,
- 0x004004d0,
- 0x00400454,
- 0x004004d4,
- 0x00400458,
- 0x004004d8,
- 0x0040045c,
- 0x004004dc,
- 0x00400460,
- 0x004004e0,
- 0x00400464,
- 0x004004e4,
- 0x00400468,
- 0x004004e8,
- 0x0040046c,
- 0x004004ec,
- 0x00400470,
- 0x004004f0,
- 0x00400474,
- 0x004004f4,
- 0x00400478,
- 0x004004f8,
- 0x0040047c,
- 0x004004fc,
- 0x00400534,
- 0x00400538,
- 0x00400514,
- 0x00400518,
- 0x0040051c,
- 0x00400520,
- 0x00400524,
- 0x00400528,
- 0x0040052c,
- 0x00400530,
- 0x00400d00,
- 0x00400d40,
- 0x00400d80,
- 0x00400d04,
- 0x00400d44,
- 0x00400d84,
- 0x00400d08,
- 0x00400d48,
- 0x00400d88,
- 0x00400d0c,
- 0x00400d4c,
- 0x00400d8c,
- 0x00400d10,
- 0x00400d50,
- 0x00400d90,
- 0x00400d14,
- 0x00400d54,
- 0x00400d94,
- 0x00400d18,
- 0x00400d58,
- 0x00400d98,
- 0x00400d1c,
- 0x00400d5c,
- 0x00400d9c,
- 0x00400d20,
- 0x00400d60,
- 0x00400da0,
- 0x00400d24,
- 0x00400d64,
- 0x00400da4,
- 0x00400d28,
- 0x00400d68,
- 0x00400da8,
- 0x00400d2c,
- 0x00400d6c,
- 0x00400dac,
- 0x00400d30,
- 0x00400d70,
- 0x00400db0,
- 0x00400d34,
- 0x00400d74,
- 0x00400db4,
- 0x00400d38,
- 0x00400d78,
- 0x00400db8,
- 0x00400d3c,
- 0x00400d7c,
- 0x00400dbc,
- 0x00400590,
- 0x00400594,
- 0x00400598,
- 0x0040059c,
- 0x004005a8,
- 0x004005ac,
- 0x004005b0,
- 0x004005b4,
- 0x004005c0,
- 0x004005c4,
- 0x004005c8,
- 0x004005cc,
- 0x004005d0,
- 0x004005d4,
- 0x004005d8,
- 0x004005dc,
- 0x004005e0,
- NV04_PGRAPH_PASSTHRU_0,
- NV04_PGRAPH_PASSTHRU_1,
- NV04_PGRAPH_PASSTHRU_2,
- NV04_PGRAPH_DVD_COLORFMT,
- NV04_PGRAPH_SCALED_FORMAT,
- NV04_PGRAPH_MISC24_0,
- NV04_PGRAPH_MISC24_1,
- NV04_PGRAPH_MISC24_2,
- 0x00400500,
- 0x00400504,
- NV04_PGRAPH_VALID1,
- NV04_PGRAPH_VALID2,
- NV04_PGRAPH_DEBUG_3
-};
-
-struct nv04_graph_priv {
- struct nouveau_graph base;
- struct nv04_graph_chan *chan[16];
- spinlock_t lock;
-};
-
-struct nv04_graph_chan {
- struct nouveau_object base;
- int chid;
- u32 nv04[ARRAY_SIZE(nv04_graph_ctx_regs)];
-};
-
-
-static inline struct nv04_graph_priv *
-nv04_graph_priv(struct nv04_graph_chan *chan)
-{
- return (void *)nv_object(chan)->engine;
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-/*
- * Software methods, why they are needed, and how they all work:
- *
- * NV04 and NV05 keep most of the state in PGRAPH context itself, but some
- * 2d engine settings are kept inside the grobjs themselves. The grobjs are
- * 3 words long on both. grobj format on NV04 is:
- *
- * word 0:
- * - bits 0-7: class
- * - bit 12: color key active
- * - bit 13: clip rect active
- * - bit 14: if set, destination surface is swizzled and taken from buffer 5
- * [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
- * from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
- * NV03_CONTEXT_SURFACE_DST].
- * - bits 15-17: 2d operation [aka patch config]
- * - bit 24: patch valid [enables rendering using this object]
- * - bit 25: surf3d valid [for tex_tri and multitex_tri only]
- * word 1:
- * - bits 0-1: mono format
- * - bits 8-13: color format
- * - bits 16-31: DMA_NOTIFY instance
- * word 2:
- * - bits 0-15: DMA_A instance
- * - bits 16-31: DMA_B instance
- *
- * On NV05 it's:
- *
- * word 0:
- * - bits 0-7: class
- * - bit 12: color key active
- * - bit 13: clip rect active
- * - bit 14: if set, destination surface is swizzled and taken from buffer 5
- * [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
- * from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
- * NV03_CONTEXT_SURFACE_DST].
- * - bits 15-17: 2d operation [aka patch config]
- * - bits 20-22: dither mode
- * - bit 24: patch valid [enables rendering using this object]
- * - bit 25: surface_dst/surface_color/surf2d/surf3d valid
- * - bit 26: surface_src/surface_zeta valid
- * - bit 27: pattern valid
- * - bit 28: rop valid
- * - bit 29: beta1 valid
- * - bit 30: beta4 valid
- * word 1:
- * - bits 0-1: mono format
- * - bits 8-13: color format
- * - bits 16-31: DMA_NOTIFY instance
- * word 2:
- * - bits 0-15: DMA_A instance
- * - bits 16-31: DMA_B instance
- *
- * NV05 will set/unset the relevant valid bits when you poke the relevant
- * object-binding methods with object of the proper type, or with the NULL
- * type. It'll only allow rendering using the grobj if all needed objects
- * are bound. The needed set of objects depends on selected operation: for
- * example rop object is needed by ROP_AND, but not by SRCCOPY_AND.
- *
- * NV04 doesn't have these methods implemented at all, and doesn't have the
- * relevant bits in grobj. Instead, it'll allow rendering whenever bit 24
- * is set. So we have to emulate them in software, internally keeping the
- * same bits as NV05 does. Since grobjs are aligned to 16 bytes on nv04,
- * but the last word isn't actually used for anything, we abuse it for this
- * purpose.
- *
- * Actually, NV05 can optionally check bit 24 too, but we disable this since
- * there's no use for it.
- *
- * For unknown reasons, NV04 implements surf3d binding in hardware as an
- * exception. Also for unknown reasons, NV04 doesn't implement the clipping
- * methods on the surf3d object, so we have to emulate them too.
- */
-
-static void
-nv04_graph_set_ctx1(struct nouveau_object *object, u32 mask, u32 value)
-{
- struct nv04_graph_priv *priv = (void *)object->engine;
- int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
- u32 tmp;
-
- tmp = nv_ro32(object, 0x00);
- tmp &= ~mask;
- tmp |= value;
- nv_wo32(object, 0x00, tmp);
-
- nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
- nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
-}
-
-static void
-nv04_graph_set_ctx_val(struct nouveau_object *object, u32 mask, u32 value)
-{
- int class, op, valid = 1;
- u32 tmp, ctx1;
-
- ctx1 = nv_ro32(object, 0x00);
- class = ctx1 & 0xff;
- op = (ctx1 >> 15) & 7;
-
- tmp = nv_ro32(object, 0x0c);
- tmp &= ~mask;
- tmp |= value;
- nv_wo32(object, 0x0c, tmp);
-
- /* check for valid surf2d/surf_dst/surf_color */
- if (!(tmp & 0x02000000))
- valid = 0;
- /* check for valid surf_src/surf_zeta */
- if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000))
- valid = 0;
-
- switch (op) {
- /* SRCCOPY_AND, SRCCOPY: no extra objects required */
- case 0:
- case 3:
- break;
- /* ROP_AND: requires pattern and rop */
- case 1:
- if (!(tmp & 0x18000000))
- valid = 0;
- break;
- /* BLEND_AND: requires beta1 */
- case 2:
- if (!(tmp & 0x20000000))
- valid = 0;
- break;
- /* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */
- case 4:
- case 5:
- if (!(tmp & 0x40000000))
- valid = 0;
- break;
- }
-
- nv04_graph_set_ctx1(object, 0x01000000, valid << 24);
-}
-
-static int
-nv04_graph_mthd_set_operation(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- u32 class = nv_ro32(object, 0) & 0xff;
- u32 data = *(u32 *)args;
- if (data > 5)
- return 1;
- /* Old versions of the objects only accept first three operations. */
- if (data > 2 && class < 0x40)
- return 1;
- nv04_graph_set_ctx1(object, 0x00038000, data << 15);
- /* changing operation changes set of objects needed for validation */
- nv04_graph_set_ctx_val(object, 0, 0);
- return 0;
-}
-
-static int
-nv04_graph_mthd_surf3d_clip_h(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv04_graph_priv *priv = (void *)object->engine;
- u32 data = *(u32 *)args;
- u32 min = data & 0xffff, max;
- u32 w = data >> 16;
- if (min & 0x8000)
- /* too large */
- return 1;
- if (w & 0x8000)
- /* yes, it accepts negative for some reason. */
- w |= 0xffff0000;
- max = min + w;
- max &= 0x3ffff;
- nv_wr32(priv, 0x40053c, min);
- nv_wr32(priv, 0x400544, max);
- return 0;
-}
-
-static int
-nv04_graph_mthd_surf3d_clip_v(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv04_graph_priv *priv = (void *)object->engine;
- u32 data = *(u32 *)args;
- u32 min = data & 0xffff, max;
- u32 w = data >> 16;
- if (min & 0x8000)
- /* too large */
- return 1;
- if (w & 0x8000)
- /* yes, it accepts negative for some reason. */
- w |= 0xffff0000;
- max = min + w;
- max &= 0x3ffff;
- nv_wr32(priv, 0x400540, min);
- nv_wr32(priv, 0x400548, max);
- return 0;
-}
-
-static u16
-nv04_graph_mthd_bind_class(struct nouveau_object *object, u32 *args, u32 size)
-{
- struct nouveau_instmem *imem = nouveau_instmem(object);
- u32 inst = *(u32 *)args << 4;
- return nv_ro32(imem, inst);
-}
-
-static int
-nv04_graph_mthd_bind_surf2d(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx1(object, 0x00004000, 0);
- nv04_graph_set_ctx_val(object, 0x02000000, 0);
- return 0;
- case 0x42:
- nv04_graph_set_ctx1(object, 0x00004000, 0);
- nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf2d_swzsurf(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx1(object, 0x00004000, 0);
- nv04_graph_set_ctx_val(object, 0x02000000, 0);
- return 0;
- case 0x42:
- nv04_graph_set_ctx1(object, 0x00004000, 0);
- nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
- return 0;
- case 0x52:
- nv04_graph_set_ctx1(object, 0x00004000, 0x00004000);
- nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv01_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x08000000, 0);
- return 0;
- case 0x18:
- nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_patt(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x08000000, 0);
- return 0;
- case 0x44:
- nv04_graph_set_ctx_val(object, 0x08000000, 0x08000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_rop(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x10000000, 0);
- return 0;
- case 0x43:
- nv04_graph_set_ctx_val(object, 0x10000000, 0x10000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_beta1(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x20000000, 0);
- return 0;
- case 0x12:
- nv04_graph_set_ctx_val(object, 0x20000000, 0x20000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_beta4(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x40000000, 0);
- return 0;
- case 0x72:
- nv04_graph_set_ctx_val(object, 0x40000000, 0x40000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_dst(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x02000000, 0);
- return 0;
- case 0x58:
- nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_src(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x04000000, 0);
- return 0;
- case 0x59:
- nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_color(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x02000000, 0);
- return 0;
- case 0x5a:
- nv04_graph_set_ctx_val(object, 0x02000000, 0x02000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv04_graph_mthd_bind_surf_zeta(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx_val(object, 0x04000000, 0);
- return 0;
- case 0x5b:
- nv04_graph_set_ctx_val(object, 0x04000000, 0x04000000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv01_graph_mthd_bind_clip(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx1(object, 0x2000, 0);
- return 0;
- case 0x19:
- nv04_graph_set_ctx1(object, 0x2000, 0x2000);
- return 0;
- }
- return 1;
-}
-
-static int
-nv01_graph_mthd_bind_chroma(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- switch (nv04_graph_mthd_bind_class(object, args, size)) {
- case 0x30:
- nv04_graph_set_ctx1(object, 0x1000, 0);
- return 0;
- /* Yes, for some reason even the old versions of objects
- * accept 0x57 and not 0x17. Consistency be damned.
- */
- case 0x57:
- nv04_graph_set_ctx1(object, 0x1000, 0x1000);
- return 0;
- }
- return 1;
-}
-
-static struct nouveau_omthds
-nv03_graph_gdi_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_patt },
- { 0x0188, 0x0188, nv04_graph_mthd_bind_rop },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_beta1 },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_gdi_omthds[] = {
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv01_graph_blit_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv01_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf_dst },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_surf_src },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_blit_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_beta4 },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_iifc_omthds[] = {
- { 0x0188, 0x0188, nv01_graph_mthd_bind_chroma },
- { 0x018c, 0x018c, nv01_graph_mthd_bind_clip },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_patt },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_rop },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_beta1 },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_beta4 },
- { 0x01a0, 0x01a0, nv04_graph_mthd_bind_surf2d_swzsurf },
- { 0x03e4, 0x03e4, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv01_graph_ifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv01_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_ifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_patt },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_rop },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta1 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_beta4 },
- { 0x019c, 0x019c, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv03_graph_sifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_sifc_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_chroma },
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv03_graph_sifm_omthds[] = {
- { 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x0304, 0x0304, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_sifm_omthds[] = {
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x0304, 0x0304, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_surf3d_omthds[] = {
- { 0x02f8, 0x02f8, nv04_graph_mthd_surf3d_clip_h },
- { 0x02fc, 0x02fc, nv04_graph_mthd_surf3d_clip_v },
- {}
-};
-
-static struct nouveau_omthds
-nv03_graph_ttri_omthds[] = {
- { 0x0188, 0x0188, nv01_graph_mthd_bind_clip },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_surf_color },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_surf_zeta },
- {}
-};
-
-static struct nouveau_omthds
-nv01_graph_prim_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_clip },
- { 0x0188, 0x0188, nv01_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_surf_dst },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static struct nouveau_omthds
-nv04_graph_prim_omthds[] = {
- { 0x0184, 0x0184, nv01_graph_mthd_bind_clip },
- { 0x0188, 0x0188, nv04_graph_mthd_bind_patt },
- { 0x018c, 0x018c, nv04_graph_mthd_bind_rop },
- { 0x0190, 0x0190, nv04_graph_mthd_bind_beta1 },
- { 0x0194, 0x0194, nv04_graph_mthd_bind_beta4 },
- { 0x0198, 0x0198, nv04_graph_mthd_bind_surf2d },
- { 0x02fc, 0x02fc, nv04_graph_mthd_set_operation },
- {}
-};
-
-static int
-nv04_graph_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj *obj;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
- 16, 16, 0, &obj);
- *pobject = nv_object(obj);
- if (ret)
- return ret;
-
- nv_wo32(obj, 0x00, nv_mclass(obj));
-#ifdef __BIG_ENDIAN
- nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
-#endif
- nv_wo32(obj, 0x04, 0x00000000);
- nv_wo32(obj, 0x08, 0x00000000);
- nv_wo32(obj, 0x0c, 0x00000000);
- return 0;
-}
-
-struct nouveau_ofuncs
-nv04_graph_ofuncs = {
- .ctor = nv04_graph_object_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv04_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
- { 0x0017, &nv04_graph_ofuncs }, /* chroma */
- { 0x0018, &nv04_graph_ofuncs }, /* pattern (nv01) */
- { 0x0019, &nv04_graph_ofuncs }, /* clip */
- { 0x001c, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* line */
- { 0x001d, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* tri */
- { 0x001e, &nv04_graph_ofuncs, nv01_graph_prim_omthds }, /* rect */
- { 0x001f, &nv04_graph_ofuncs, nv01_graph_blit_omthds },
- { 0x0021, &nv04_graph_ofuncs, nv01_graph_ifc_omthds },
- { 0x0030, &nv04_graph_ofuncs }, /* null */
- { 0x0036, &nv04_graph_ofuncs, nv03_graph_sifc_omthds },
- { 0x0037, &nv04_graph_ofuncs, nv03_graph_sifm_omthds },
- { 0x0038, &nv04_graph_ofuncs }, /* dvd subpicture */
- { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
- { 0x0042, &nv04_graph_ofuncs }, /* surf2d */
- { 0x0043, &nv04_graph_ofuncs }, /* rop */
- { 0x0044, &nv04_graph_ofuncs }, /* pattern */
- { 0x0048, &nv04_graph_ofuncs, nv03_graph_ttri_omthds },
- { 0x004a, &nv04_graph_ofuncs, nv04_graph_gdi_omthds },
- { 0x004b, &nv04_graph_ofuncs, nv03_graph_gdi_omthds },
- { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
- { 0x0053, &nv04_graph_ofuncs, nv04_graph_surf3d_omthds },
- { 0x0054, &nv04_graph_ofuncs }, /* ttri */
- { 0x0055, &nv04_graph_ofuncs }, /* mtri */
- { 0x0057, &nv04_graph_ofuncs }, /* chroma */
- { 0x0058, &nv04_graph_ofuncs }, /* surf_dst */
- { 0x0059, &nv04_graph_ofuncs }, /* surf_src */
- { 0x005a, &nv04_graph_ofuncs }, /* surf_color */
- { 0x005b, &nv04_graph_ofuncs }, /* surf_zeta */
- { 0x005c, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* line */
- { 0x005d, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* tri */
- { 0x005e, &nv04_graph_ofuncs, nv04_graph_prim_omthds }, /* rect */
- { 0x005f, &nv04_graph_ofuncs, nv04_graph_blit_omthds },
- { 0x0060, &nv04_graph_ofuncs, nv04_graph_iifc_omthds },
- { 0x0061, &nv04_graph_ofuncs, nv04_graph_ifc_omthds },
- { 0x0064, &nv04_graph_ofuncs }, /* iifc (nv05) */
- { 0x0065, &nv04_graph_ofuncs }, /* ifc (nv05) */
- { 0x0066, &nv04_graph_ofuncs }, /* sifc (nv05) */
- { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
- { 0x0076, &nv04_graph_ofuncs, nv04_graph_sifc_omthds },
- { 0x0077, &nv04_graph_ofuncs, nv04_graph_sifm_omthds },
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static struct nv04_graph_chan *
-nv04_graph_channel(struct nv04_graph_priv *priv)
-{
- struct nv04_graph_chan *chan = NULL;
- if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
- int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
- if (chid < ARRAY_SIZE(priv->chan))
- chan = priv->chan[chid];
- }
- return chan;
-}
-
-static int
-nv04_graph_load_context(struct nv04_graph_chan *chan, int chid)
-{
- struct nv04_graph_priv *priv = nv04_graph_priv(chan);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
- nv_wr32(priv, nv04_graph_ctx_regs[i], chan->nv04[i]);
-
- nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
- nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
- nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
- return 0;
-}
-
-static int
-nv04_graph_unload_context(struct nv04_graph_chan *chan)
-{
- struct nv04_graph_priv *priv = nv04_graph_priv(chan);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++)
- chan->nv04[i] = nv_rd32(priv, nv04_graph_ctx_regs[i]);
-
- nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
- nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
- return 0;
-}
-
-static void
-nv04_graph_context_switch(struct nv04_graph_priv *priv)
-{
- struct nv04_graph_chan *prev = NULL;
- struct nv04_graph_chan *next = NULL;
- unsigned long flags;
- int chid;
-
- spin_lock_irqsave(&priv->lock, flags);
- nv04_graph_idle(priv);
-
- /* If previous context is valid, we need to save it */
- prev = nv04_graph_channel(priv);
- if (prev)
- nv04_graph_unload_context(prev);
-
- /* load context for next channel */
- chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
- next = priv->chan[chid];
- if (next)
- nv04_graph_load_context(next, chid);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static u32 *ctx_reg(struct nv04_graph_chan *chan, u32 reg)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nv04_graph_ctx_regs); i++) {
- if (nv04_graph_ctx_regs[i] == reg)
- return &chan->nv04[i];
- }
-
- return NULL;
-}
-
-static int
-nv04_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fifo_chan *fifo = (void *)parent;
- struct nv04_graph_priv *priv = (void *)engine;
- struct nv04_graph_chan *chan;
- unsigned long flags;
- int ret;
-
- ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->chan[fifo->chid]) {
- *pobject = nv_object(priv->chan[fifo->chid]);
- atomic_inc(&(*pobject)->refcount);
- spin_unlock_irqrestore(&priv->lock, flags);
- nouveau_object_destroy(&chan->base);
- return 1;
- }
-
- *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
-
- priv->chan[fifo->chid] = chan;
- chan->chid = fifo->chid;
- spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
-}
-
-static void
-nv04_graph_context_dtor(struct nouveau_object *object)
-{
- struct nv04_graph_priv *priv = (void *)object->engine;
- struct nv04_graph_chan *chan = (void *)object;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->chan[chan->chid] = NULL;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- nouveau_object_destroy(&chan->base);
-}
-
-static int
-nv04_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv04_graph_priv *priv = (void *)object->engine;
- struct nv04_graph_chan *chan = (void *)object;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
- if (nv04_graph_channel(priv) == chan)
- nv04_graph_unload_context(chan);
- nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return nouveau_object_fini(&chan->base, suspend);
-}
-
-static struct nouveau_oclass
-nv04_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_graph_context_ctor,
- .dtor = nv04_graph_context_dtor,
- .init = nouveau_object_init,
- .fini = nv04_graph_context_fini,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-bool
-nv04_graph_idle(void *obj)
-{
- struct nouveau_graph *graph = nouveau_graph(obj);
- u32 mask = 0xffffffff;
-
- if (nv_device(obj)->card_type == NV_40)
- mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
-
- if (!nv_wait(graph, NV04_PGRAPH_STATUS, mask, 0)) {
- nv_error(graph, "idle timed out with status 0x%08x\n",
- nv_rd32(graph, NV04_PGRAPH_STATUS));
- return false;
- }
-
- return true;
-}
-
-static const struct nouveau_bitfield
-nv04_graph_intr_name[] = {
- { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
- {}
-};
-
-static const struct nouveau_bitfield
-nv04_graph_nstatus[] = {
- { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
- { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
- { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
- { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
- {}
-};
-
-const struct nouveau_bitfield
-nv04_graph_nsource[] = {
- { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
- { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
- { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
- { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
- { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
- { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
- { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
- { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
- { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
- { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
- { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
- { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
- { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
- {}
-};
-
-static void
-nv04_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nv04_graph_priv *priv = (void *)subdev;
- struct nv04_graph_chan *chan = NULL;
- struct nouveau_namedb *namedb = NULL;
- struct nouveau_handle *handle = NULL;
- u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
- u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
- u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
- u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
- u32 chid = (addr & 0x0f000000) >> 24;
- u32 subc = (addr & 0x0000e000) >> 13;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
- u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
- u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
- u32 show = stat;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- chan = priv->chan[chid];
- if (chan)
- namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (stat & NV_PGRAPH_INTR_NOTIFY) {
- if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
- handle = nouveau_namedb_get_vinst(namedb, inst);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~NV_PGRAPH_INTR_NOTIFY;
- }
- }
-
- if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
- nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
- stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- nv04_graph_context_switch(priv);
- }
-
- nv_wr32(priv, NV03_PGRAPH_INTR, stat);
- nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
- if (show) {
- nv_error(priv, "%s", "");
- nouveau_bitfield_print(nv04_graph_intr_name, show);
- pr_cont(" nsource:");
- nouveau_bitfield_print(nv04_graph_nsource, nsource);
- pr_cont(" nstatus:");
- nouveau_bitfield_print(nv04_graph_nstatus, nstatus);
- pr_cont("\n");
- nv_error(priv,
- "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, nouveau_client_name(chan), subc, class, mthd,
- data);
- }
-
- nouveau_namedb_put(handle);
-}
-
-static int
-nv04_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv04_graph_intr;
- nv_engine(priv)->cclass = &nv04_graph_cclass;
- nv_engine(priv)->sclass = nv04_graph_sclass;
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-static int
-nv04_graph_init(struct nouveau_object *object)
-{
- struct nouveau_engine *engine = nv_engine(object);
- struct nv04_graph_priv *priv = (void *)engine;
- int ret;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- /* Enable PGRAPH interrupts */
- nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
- nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
- nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
- nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
- /*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
- /*1231C000 blob, 001 haiku*/
- /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
- nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
- /*0x72111100 blob , 01 haiku*/
- /*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
- nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
- /*haiku same*/
-
- /*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
- nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
- /*haiku and blob 10d4*/
-
- nv_wr32(priv, NV04_PGRAPH_STATE , 0xFFFFFFFF);
- nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL , 0x10000100);
- nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
-
- /* These don't belong here, they're part of a per-channel context */
- nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
- nv_wr32(priv, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF);
- return 0;
-}
-
-struct nouveau_oclass
-nv04_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_graph_ctor,
- .dtor = _nouveau_graph_dtor,
- .init = nv04_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
deleted file mode 100644
index 2b12b09683c8..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv10.c
+++ /dev/null
@@ -1,1319 +0,0 @@
-/*
- * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/handle.h>
-
-#include <subdev/fb.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "regs.h"
-
-struct pipe_state {
- u32 pipe_0x0000[0x040/4];
- u32 pipe_0x0040[0x010/4];
- u32 pipe_0x0200[0x0c0/4];
- u32 pipe_0x4400[0x080/4];
- u32 pipe_0x6400[0x3b0/4];
- u32 pipe_0x6800[0x2f0/4];
- u32 pipe_0x6c00[0x030/4];
- u32 pipe_0x7000[0x130/4];
- u32 pipe_0x7400[0x0c0/4];
- u32 pipe_0x7800[0x0c0/4];
-};
-
-static int nv10_graph_ctx_regs[] = {
- NV10_PGRAPH_CTX_SWITCH(0),
- NV10_PGRAPH_CTX_SWITCH(1),
- NV10_PGRAPH_CTX_SWITCH(2),
- NV10_PGRAPH_CTX_SWITCH(3),
- NV10_PGRAPH_CTX_SWITCH(4),
- NV10_PGRAPH_CTX_CACHE(0, 0),
- NV10_PGRAPH_CTX_CACHE(0, 1),
- NV10_PGRAPH_CTX_CACHE(0, 2),
- NV10_PGRAPH_CTX_CACHE(0, 3),
- NV10_PGRAPH_CTX_CACHE(0, 4),
- NV10_PGRAPH_CTX_CACHE(1, 0),
- NV10_PGRAPH_CTX_CACHE(1, 1),
- NV10_PGRAPH_CTX_CACHE(1, 2),
- NV10_PGRAPH_CTX_CACHE(1, 3),
- NV10_PGRAPH_CTX_CACHE(1, 4),
- NV10_PGRAPH_CTX_CACHE(2, 0),
- NV10_PGRAPH_CTX_CACHE(2, 1),
- NV10_PGRAPH_CTX_CACHE(2, 2),
- NV10_PGRAPH_CTX_CACHE(2, 3),
- NV10_PGRAPH_CTX_CACHE(2, 4),
- NV10_PGRAPH_CTX_CACHE(3, 0),
- NV10_PGRAPH_CTX_CACHE(3, 1),
- NV10_PGRAPH_CTX_CACHE(3, 2),
- NV10_PGRAPH_CTX_CACHE(3, 3),
- NV10_PGRAPH_CTX_CACHE(3, 4),
- NV10_PGRAPH_CTX_CACHE(4, 0),
- NV10_PGRAPH_CTX_CACHE(4, 1),
- NV10_PGRAPH_CTX_CACHE(4, 2),
- NV10_PGRAPH_CTX_CACHE(4, 3),
- NV10_PGRAPH_CTX_CACHE(4, 4),
- NV10_PGRAPH_CTX_CACHE(5, 0),
- NV10_PGRAPH_CTX_CACHE(5, 1),
- NV10_PGRAPH_CTX_CACHE(5, 2),
- NV10_PGRAPH_CTX_CACHE(5, 3),
- NV10_PGRAPH_CTX_CACHE(5, 4),
- NV10_PGRAPH_CTX_CACHE(6, 0),
- NV10_PGRAPH_CTX_CACHE(6, 1),
- NV10_PGRAPH_CTX_CACHE(6, 2),
- NV10_PGRAPH_CTX_CACHE(6, 3),
- NV10_PGRAPH_CTX_CACHE(6, 4),
- NV10_PGRAPH_CTX_CACHE(7, 0),
- NV10_PGRAPH_CTX_CACHE(7, 1),
- NV10_PGRAPH_CTX_CACHE(7, 2),
- NV10_PGRAPH_CTX_CACHE(7, 3),
- NV10_PGRAPH_CTX_CACHE(7, 4),
- NV10_PGRAPH_CTX_USER,
- NV04_PGRAPH_DMA_START_0,
- NV04_PGRAPH_DMA_START_1,
- NV04_PGRAPH_DMA_LENGTH,
- NV04_PGRAPH_DMA_MISC,
- NV10_PGRAPH_DMA_PITCH,
- NV04_PGRAPH_BOFFSET0,
- NV04_PGRAPH_BBASE0,
- NV04_PGRAPH_BLIMIT0,
- NV04_PGRAPH_BOFFSET1,
- NV04_PGRAPH_BBASE1,
- NV04_PGRAPH_BLIMIT1,
- NV04_PGRAPH_BOFFSET2,
- NV04_PGRAPH_BBASE2,
- NV04_PGRAPH_BLIMIT2,
- NV04_PGRAPH_BOFFSET3,
- NV04_PGRAPH_BBASE3,
- NV04_PGRAPH_BLIMIT3,
- NV04_PGRAPH_BOFFSET4,
- NV04_PGRAPH_BBASE4,
- NV04_PGRAPH_BLIMIT4,
- NV04_PGRAPH_BOFFSET5,
- NV04_PGRAPH_BBASE5,
- NV04_PGRAPH_BLIMIT5,
- NV04_PGRAPH_BPITCH0,
- NV04_PGRAPH_BPITCH1,
- NV04_PGRAPH_BPITCH2,
- NV04_PGRAPH_BPITCH3,
- NV04_PGRAPH_BPITCH4,
- NV10_PGRAPH_SURFACE,
- NV10_PGRAPH_STATE,
- NV04_PGRAPH_BSWIZZLE2,
- NV04_PGRAPH_BSWIZZLE5,
- NV04_PGRAPH_BPIXEL,
- NV10_PGRAPH_NOTIFY,
- NV04_PGRAPH_PATT_COLOR0,
- NV04_PGRAPH_PATT_COLOR1,
- NV04_PGRAPH_PATT_COLORRAM, /* 64 values from 0x400900 to 0x4009fc */
- 0x00400904,
- 0x00400908,
- 0x0040090c,
- 0x00400910,
- 0x00400914,
- 0x00400918,
- 0x0040091c,
- 0x00400920,
- 0x00400924,
- 0x00400928,
- 0x0040092c,
- 0x00400930,
- 0x00400934,
- 0x00400938,
- 0x0040093c,
- 0x00400940,
- 0x00400944,
- 0x00400948,
- 0x0040094c,
- 0x00400950,
- 0x00400954,
- 0x00400958,
- 0x0040095c,
- 0x00400960,
- 0x00400964,
- 0x00400968,
- 0x0040096c,
- 0x00400970,
- 0x00400974,
- 0x00400978,
- 0x0040097c,
- 0x00400980,
- 0x00400984,
- 0x00400988,
- 0x0040098c,
- 0x00400990,
- 0x00400994,
- 0x00400998,
- 0x0040099c,
- 0x004009a0,
- 0x004009a4,
- 0x004009a8,
- 0x004009ac,
- 0x004009b0,
- 0x004009b4,
- 0x004009b8,
- 0x004009bc,
- 0x004009c0,
- 0x004009c4,
- 0x004009c8,
- 0x004009cc,
- 0x004009d0,
- 0x004009d4,
- 0x004009d8,
- 0x004009dc,
- 0x004009e0,
- 0x004009e4,
- 0x004009e8,
- 0x004009ec,
- 0x004009f0,
- 0x004009f4,
- 0x004009f8,
- 0x004009fc,
- NV04_PGRAPH_PATTERN, /* 2 values from 0x400808 to 0x40080c */
- 0x0040080c,
- NV04_PGRAPH_PATTERN_SHAPE,
- NV03_PGRAPH_MONO_COLOR0,
- NV04_PGRAPH_ROP3,
- NV04_PGRAPH_CHROMA,
- NV04_PGRAPH_BETA_AND,
- NV04_PGRAPH_BETA_PREMULT,
- 0x00400e70,
- 0x00400e74,
- 0x00400e78,
- 0x00400e7c,
- 0x00400e80,
- 0x00400e84,
- 0x00400e88,
- 0x00400e8c,
- 0x00400ea0,
- 0x00400ea4,
- 0x00400ea8,
- 0x00400e90,
- 0x00400e94,
- 0x00400e98,
- 0x00400e9c,
- NV10_PGRAPH_WINDOWCLIP_HORIZONTAL, /* 8 values from 0x400f00-0x400f1c */
- NV10_PGRAPH_WINDOWCLIP_VERTICAL, /* 8 values from 0x400f20-0x400f3c */
- 0x00400f04,
- 0x00400f24,
- 0x00400f08,
- 0x00400f28,
- 0x00400f0c,
- 0x00400f2c,
- 0x00400f10,
- 0x00400f30,
- 0x00400f14,
- 0x00400f34,
- 0x00400f18,
- 0x00400f38,
- 0x00400f1c,
- 0x00400f3c,
- NV10_PGRAPH_XFMODE0,
- NV10_PGRAPH_XFMODE1,
- NV10_PGRAPH_GLOBALSTATE0,
- NV10_PGRAPH_GLOBALSTATE1,
- NV04_PGRAPH_STORED_FMT,
- NV04_PGRAPH_SOURCE_COLOR,
- NV03_PGRAPH_ABS_X_RAM, /* 32 values from 0x400400 to 0x40047c */
- NV03_PGRAPH_ABS_Y_RAM, /* 32 values from 0x400480 to 0x4004fc */
- 0x00400404,
- 0x00400484,
- 0x00400408,
- 0x00400488,
- 0x0040040c,
- 0x0040048c,
- 0x00400410,
- 0x00400490,
- 0x00400414,
- 0x00400494,
- 0x00400418,
- 0x00400498,
- 0x0040041c,
- 0x0040049c,
- 0x00400420,
- 0x004004a0,
- 0x00400424,
- 0x004004a4,
- 0x00400428,
- 0x004004a8,
- 0x0040042c,
- 0x004004ac,
- 0x00400430,
- 0x004004b0,
- 0x00400434,
- 0x004004b4,
- 0x00400438,
- 0x004004b8,
- 0x0040043c,
- 0x004004bc,
- 0x00400440,
- 0x004004c0,
- 0x00400444,
- 0x004004c4,
- 0x00400448,
- 0x004004c8,
- 0x0040044c,
- 0x004004cc,
- 0x00400450,
- 0x004004d0,
- 0x00400454,
- 0x004004d4,
- 0x00400458,
- 0x004004d8,
- 0x0040045c,
- 0x004004dc,
- 0x00400460,
- 0x004004e0,
- 0x00400464,
- 0x004004e4,
- 0x00400468,
- 0x004004e8,
- 0x0040046c,
- 0x004004ec,
- 0x00400470,
- 0x004004f0,
- 0x00400474,
- 0x004004f4,
- 0x00400478,
- 0x004004f8,
- 0x0040047c,
- 0x004004fc,
- NV03_PGRAPH_ABS_UCLIP_XMIN,
- NV03_PGRAPH_ABS_UCLIP_XMAX,
- NV03_PGRAPH_ABS_UCLIP_YMIN,
- NV03_PGRAPH_ABS_UCLIP_YMAX,
- 0x00400550,
- 0x00400558,
- 0x00400554,
- 0x0040055c,
- NV03_PGRAPH_ABS_UCLIPA_XMIN,
- NV03_PGRAPH_ABS_UCLIPA_XMAX,
- NV03_PGRAPH_ABS_UCLIPA_YMIN,
- NV03_PGRAPH_ABS_UCLIPA_YMAX,
- NV03_PGRAPH_ABS_ICLIP_XMAX,
- NV03_PGRAPH_ABS_ICLIP_YMAX,
- NV03_PGRAPH_XY_LOGIC_MISC0,
- NV03_PGRAPH_XY_LOGIC_MISC1,
- NV03_PGRAPH_XY_LOGIC_MISC2,
- NV03_PGRAPH_XY_LOGIC_MISC3,
- NV03_PGRAPH_CLIPX_0,
- NV03_PGRAPH_CLIPX_1,
- NV03_PGRAPH_CLIPY_0,
- NV03_PGRAPH_CLIPY_1,
- NV10_PGRAPH_COMBINER0_IN_ALPHA,
- NV10_PGRAPH_COMBINER1_IN_ALPHA,
- NV10_PGRAPH_COMBINER0_IN_RGB,
- NV10_PGRAPH_COMBINER1_IN_RGB,
- NV10_PGRAPH_COMBINER_COLOR0,
- NV10_PGRAPH_COMBINER_COLOR1,
- NV10_PGRAPH_COMBINER0_OUT_ALPHA,
- NV10_PGRAPH_COMBINER1_OUT_ALPHA,
- NV10_PGRAPH_COMBINER0_OUT_RGB,
- NV10_PGRAPH_COMBINER1_OUT_RGB,
- NV10_PGRAPH_COMBINER_FINAL0,
- NV10_PGRAPH_COMBINER_FINAL1,
- 0x00400e00,
- 0x00400e04,
- 0x00400e08,
- 0x00400e0c,
- 0x00400e10,
- 0x00400e14,
- 0x00400e18,
- 0x00400e1c,
- 0x00400e20,
- 0x00400e24,
- 0x00400e28,
- 0x00400e2c,
- 0x00400e30,
- 0x00400e34,
- 0x00400e38,
- 0x00400e3c,
- NV04_PGRAPH_PASSTHRU_0,
- NV04_PGRAPH_PASSTHRU_1,
- NV04_PGRAPH_PASSTHRU_2,
- NV10_PGRAPH_DIMX_TEXTURE,
- NV10_PGRAPH_WDIMX_TEXTURE,
- NV10_PGRAPH_DVD_COLORFMT,
- NV10_PGRAPH_SCALED_FORMAT,
- NV04_PGRAPH_MISC24_0,
- NV04_PGRAPH_MISC24_1,
- NV04_PGRAPH_MISC24_2,
- NV03_PGRAPH_X_MISC,
- NV03_PGRAPH_Y_MISC,
- NV04_PGRAPH_VALID1,
- NV04_PGRAPH_VALID2,
-};
-
-static int nv17_graph_ctx_regs[] = {
- NV10_PGRAPH_DEBUG_4,
- 0x004006b0,
- 0x00400eac,
- 0x00400eb0,
- 0x00400eb4,
- 0x00400eb8,
- 0x00400ebc,
- 0x00400ec0,
- 0x00400ec4,
- 0x00400ec8,
- 0x00400ecc,
- 0x00400ed0,
- 0x00400ed4,
- 0x00400ed8,
- 0x00400edc,
- 0x00400ee0,
- 0x00400a00,
- 0x00400a04,
-};
-
-struct nv10_graph_priv {
- struct nouveau_graph base;
- struct nv10_graph_chan *chan[32];
- spinlock_t lock;
-};
-
-struct nv10_graph_chan {
- struct nouveau_object base;
- int chid;
- int nv10[ARRAY_SIZE(nv10_graph_ctx_regs)];
- int nv17[ARRAY_SIZE(nv17_graph_ctx_regs)];
- struct pipe_state pipe_state;
- u32 lma_window[4];
-};
-
-
-static inline struct nv10_graph_priv *
-nv10_graph_priv(struct nv10_graph_chan *chan)
-{
- return (void *)nv_object(chan)->engine;
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-#define PIPE_SAVE(priv, state, addr) \
- do { \
- int __i; \
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \
- for (__i = 0; __i < ARRAY_SIZE(state); __i++) \
- state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
- } while (0)
-
-#define PIPE_RESTORE(priv, state, addr) \
- do { \
- int __i; \
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \
- for (__i = 0; __i < ARRAY_SIZE(state); __i++) \
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
- } while (0)
-
-static struct nouveau_oclass
-nv10_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs }, /* clip */
- { 0x0030, &nv04_graph_ofuncs }, /* null */
- { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs }, /* rop */
- { 0x0044, &nv04_graph_ofuncs }, /* pattern */
- { 0x004a, &nv04_graph_ofuncs }, /* gdi */
- { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
- { 0x005f, &nv04_graph_ofuncs }, /* blit */
- { 0x0062, &nv04_graph_ofuncs }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs }, /* ifc */
- { 0x009f, &nv04_graph_ofuncs }, /* blit */
- { 0x0093, &nv04_graph_ofuncs }, /* surf3d */
- { 0x0094, &nv04_graph_ofuncs }, /* ttri */
- { 0x0095, &nv04_graph_ofuncs }, /* mtri */
- { 0x0056, &nv04_graph_ofuncs }, /* celcius */
- {},
-};
-
-static struct nouveau_oclass
-nv15_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs }, /* clip */
- { 0x0030, &nv04_graph_ofuncs }, /* null */
- { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs }, /* rop */
- { 0x0044, &nv04_graph_ofuncs }, /* pattern */
- { 0x004a, &nv04_graph_ofuncs }, /* gdi */
- { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
- { 0x005f, &nv04_graph_ofuncs }, /* blit */
- { 0x0062, &nv04_graph_ofuncs }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs }, /* ifc */
- { 0x009f, &nv04_graph_ofuncs }, /* blit */
- { 0x0093, &nv04_graph_ofuncs }, /* surf3d */
- { 0x0094, &nv04_graph_ofuncs }, /* ttri */
- { 0x0095, &nv04_graph_ofuncs }, /* mtri */
- { 0x0096, &nv04_graph_ofuncs }, /* celcius */
- {},
-};
-
-static int
-nv17_graph_mthd_lma_window(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv10_graph_chan *chan = (void *)object->parent;
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- struct pipe_state *pipe = &chan->pipe_state;
- u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
- u32 xfmode0, xfmode1;
- u32 data = *(u32 *)args;
- int i;
-
- chan->lma_window[(mthd - 0x1638) / 4] = data;
-
- if (mthd != 0x1644)
- return 0;
-
- nv04_graph_idle(priv);
-
- PIPE_SAVE(priv, pipe_0x0040, 0x0040);
- PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
-
- PIPE_RESTORE(priv, chan->lma_window, 0x6790);
-
- nv04_graph_idle(priv);
-
- xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
- xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
-
- PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
- PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
- PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
- PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
-
- nv04_graph_idle(priv);
-
- nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
- nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
- for (i = 0; i < 3; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
- for (i = 0; i < 3; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
- PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
-
- nv04_graph_idle(priv);
-
- PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
-
- nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
- nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
-
- PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
- PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
- PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
- PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
- nv04_graph_idle(priv);
-
- return 0;
-}
-
-static int
-nv17_graph_mthd_lma_enable(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv10_graph_chan *chan = (void *)object->parent;
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
-
- nv04_graph_idle(priv);
-
- nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
- nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
- return 0;
-}
-
-static struct nouveau_omthds
-nv17_celcius_omthds[] = {
- { 0x1638, 0x1638, nv17_graph_mthd_lma_window },
- { 0x163c, 0x163c, nv17_graph_mthd_lma_window },
- { 0x1640, 0x1640, nv17_graph_mthd_lma_window },
- { 0x1644, 0x1644, nv17_graph_mthd_lma_window },
- { 0x1658, 0x1658, nv17_graph_mthd_lma_enable },
- {}
-};
-
-static struct nouveau_oclass
-nv17_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs }, /* clip */
- { 0x0030, &nv04_graph_ofuncs }, /* null */
- { 0x0039, &nv04_graph_ofuncs }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs }, /* rop */
- { 0x0044, &nv04_graph_ofuncs }, /* pattern */
- { 0x004a, &nv04_graph_ofuncs }, /* gdi */
- { 0x0052, &nv04_graph_ofuncs }, /* swzsurf */
- { 0x005f, &nv04_graph_ofuncs }, /* blit */
- { 0x0062, &nv04_graph_ofuncs }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs }, /* ifc */
- { 0x009f, &nv04_graph_ofuncs }, /* blit */
- { 0x0093, &nv04_graph_ofuncs }, /* surf3d */
- { 0x0094, &nv04_graph_ofuncs }, /* ttri */
- { 0x0095, &nv04_graph_ofuncs }, /* mtri */
- { 0x0099, &nv04_graph_ofuncs, nv17_celcius_omthds },
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static struct nv10_graph_chan *
-nv10_graph_channel(struct nv10_graph_priv *priv)
-{
- struct nv10_graph_chan *chan = NULL;
- if (nv_rd32(priv, 0x400144) & 0x00010000) {
- int chid = nv_rd32(priv, 0x400148) >> 24;
- if (chid < ARRAY_SIZE(priv->chan))
- chan = priv->chan[chid];
- }
- return chan;
-}
-
-static void
-nv10_graph_save_pipe(struct nv10_graph_chan *chan)
-{
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- struct pipe_state *pipe = &chan->pipe_state;
-
- PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
- PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
- PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
- PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
- PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
- PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
- PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
- PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
- PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
- PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
-}
-
-static void
-nv10_graph_load_pipe(struct nv10_graph_chan *chan)
-{
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- struct pipe_state *pipe = &chan->pipe_state;
- u32 xfmode0, xfmode1;
- int i;
-
- nv04_graph_idle(priv);
- /* XXX check haiku comments */
- xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
- xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
- nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
- nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
- for (i = 0; i < 4; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
- for (i = 0; i < 3; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
- for (i = 0; i < 3; i++)
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
-
- nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
- nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
-
-
- PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
- nv04_graph_idle(priv);
-
- /* restore XFMODE */
- nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
- nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
- PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
- PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
- PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
- PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
- PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
- PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
- PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
- PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
- PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
- nv04_graph_idle(priv);
-}
-
-static void
-nv10_graph_create_pipe(struct nv10_graph_chan *chan)
-{
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- struct pipe_state *pipe_state = &chan->pipe_state;
- u32 *pipe_state_addr;
- int i;
-#define PIPE_INIT(addr) \
- do { \
- pipe_state_addr = pipe_state->pipe_##addr; \
- } while (0)
-#define PIPE_INIT_END(addr) \
- do { \
- u32 *__end_addr = pipe_state->pipe_##addr + \
- ARRAY_SIZE(pipe_state->pipe_##addr); \
- if (pipe_state_addr != __end_addr) \
- nv_error(priv, "incomplete pipe init for 0x%x : %p/%p\n", \
- addr, pipe_state_addr, __end_addr); \
- } while (0)
-#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
-
- PIPE_INIT(0x0200);
- for (i = 0; i < 48; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x0200);
-
- PIPE_INIT(0x6400);
- for (i = 0; i < 211; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- NV_WRITE_PIPE_INIT(0x40000000);
- NV_WRITE_PIPE_INIT(0x40000000);
- NV_WRITE_PIPE_INIT(0x40000000);
- NV_WRITE_PIPE_INIT(0x40000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x3f000000);
- NV_WRITE_PIPE_INIT(0x3f000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- PIPE_INIT_END(0x6400);
-
- PIPE_INIT(0x6800);
- for (i = 0; i < 162; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x3f800000);
- for (i = 0; i < 25; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x6800);
-
- PIPE_INIT(0x6c00);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0xbf800000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x6c00);
-
- PIPE_INIT(0x7000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x00000000);
- NV_WRITE_PIPE_INIT(0x7149f2ca);
- for (i = 0; i < 35; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x7000);
-
- PIPE_INIT(0x7400);
- for (i = 0; i < 48; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x7400);
-
- PIPE_INIT(0x7800);
- for (i = 0; i < 48; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x7800);
-
- PIPE_INIT(0x4400);
- for (i = 0; i < 32; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x4400);
-
- PIPE_INIT(0x0000);
- for (i = 0; i < 16; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x0000);
-
- PIPE_INIT(0x0040);
- for (i = 0; i < 4; i++)
- NV_WRITE_PIPE_INIT(0x00000000);
- PIPE_INIT_END(0x0040);
-
-#undef PIPE_INIT
-#undef PIPE_INIT_END
-#undef NV_WRITE_PIPE_INIT
-}
-
-static int
-nv10_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++) {
- if (nv10_graph_ctx_regs[i] == reg)
- return i;
- }
- nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
- return -1;
-}
-
-static int
-nv17_graph_ctx_regs_find_offset(struct nv10_graph_priv *priv, int reg)
-{
- int i;
- for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++) {
- if (nv17_graph_ctx_regs[i] == reg)
- return i;
- }
- nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
- return -1;
-}
-
-static void
-nv10_graph_load_dma_vtxbuf(struct nv10_graph_chan *chan, int chid, u32 inst)
-{
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
- u32 ctx_user, ctx_switch[5];
- int i, subchan = -1;
-
- /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
- * that cannot be restored via MMIO. Do it through the FIFO
- * instead.
- */
-
- /* Look for a celsius object */
- for (i = 0; i < 8; i++) {
- int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
-
- if (class == 0x56 || class == 0x96 || class == 0x99) {
- subchan = i;
- break;
- }
- }
-
- if (subchan < 0 || !inst)
- return;
-
- /* Save the current ctx object */
- ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
- for (i = 0; i < 5; i++)
- ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
-
- /* Save the FIFO state */
- st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
- st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
- st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
- fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
-
- for (i = 0; i < ARRAY_SIZE(fifo); i++)
- fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
-
- /* Switch to the celsius subchannel */
- for (i = 0; i < 5; i++)
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
- nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
- nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
-
- /* Inject NV10TCL_DMA_VTXBUF */
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
- 0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
- nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
- nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
- nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
-
- /* Restore the FIFO state */
- for (i = 0; i < ARRAY_SIZE(fifo); i++)
- nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
-
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
-
- /* Restore the current ctx object */
- for (i = 0; i < 5; i++)
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
- nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
-}
-
-static int
-nv10_graph_load_context(struct nv10_graph_chan *chan, int chid)
-{
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- u32 inst;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
- nv_wr32(priv, nv10_graph_ctx_regs[i], chan->nv10[i]);
-
- if (nv_device(priv)->card_type >= NV_11 &&
- nv_device(priv)->chipset >= 0x17) {
- for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
- nv_wr32(priv, nv17_graph_ctx_regs[i], chan->nv17[i]);
- }
-
- nv10_graph_load_pipe(chan);
-
- inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
- nv10_graph_load_dma_vtxbuf(chan, chid, inst);
-
- nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
- nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
- nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
- return 0;
-}
-
-static int
-nv10_graph_unload_context(struct nv10_graph_chan *chan)
-{
- struct nv10_graph_priv *priv = nv10_graph_priv(chan);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(nv10_graph_ctx_regs); i++)
- chan->nv10[i] = nv_rd32(priv, nv10_graph_ctx_regs[i]);
-
- if (nv_device(priv)->card_type >= NV_11 &&
- nv_device(priv)->chipset >= 0x17) {
- for (i = 0; i < ARRAY_SIZE(nv17_graph_ctx_regs); i++)
- chan->nv17[i] = nv_rd32(priv, nv17_graph_ctx_regs[i]);
- }
-
- nv10_graph_save_pipe(chan);
-
- nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
- nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
- return 0;
-}
-
-static void
-nv10_graph_context_switch(struct nv10_graph_priv *priv)
-{
- struct nv10_graph_chan *prev = NULL;
- struct nv10_graph_chan *next = NULL;
- unsigned long flags;
- int chid;
-
- spin_lock_irqsave(&priv->lock, flags);
- nv04_graph_idle(priv);
-
- /* If previous context is valid, we need to save it */
- prev = nv10_graph_channel(priv);
- if (prev)
- nv10_graph_unload_context(prev);
-
- /* load context for next channel */
- chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
- next = priv->chan[chid];
- if (next)
- nv10_graph_load_context(next, chid);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-#define NV_WRITE_CTX(reg, val) do { \
- int offset = nv10_graph_ctx_regs_find_offset(priv, reg); \
- if (offset > 0) \
- chan->nv10[offset] = val; \
- } while (0)
-
-#define NV17_WRITE_CTX(reg, val) do { \
- int offset = nv17_graph_ctx_regs_find_offset(priv, reg); \
- if (offset > 0) \
- chan->nv17[offset] = val; \
- } while (0)
-
-static int
-nv10_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fifo_chan *fifo = (void *)parent;
- struct nv10_graph_priv *priv = (void *)engine;
- struct nv10_graph_chan *chan;
- unsigned long flags;
- int ret;
-
- ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (priv->chan[fifo->chid]) {
- *pobject = nv_object(priv->chan[fifo->chid]);
- atomic_inc(&(*pobject)->refcount);
- spin_unlock_irqrestore(&priv->lock, flags);
- nouveau_object_destroy(&chan->base);
- return 1;
- }
-
- NV_WRITE_CTX(0x00400e88, 0x08000000);
- NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
- NV_WRITE_CTX(NV03_PGRAPH_XY_LOGIC_MISC0, 0x0001ffff);
- NV_WRITE_CTX(0x00400e10, 0x00001000);
- NV_WRITE_CTX(0x00400e14, 0x00001000);
- NV_WRITE_CTX(0x00400e30, 0x00080008);
- NV_WRITE_CTX(0x00400e34, 0x00080008);
- if (nv_device(priv)->card_type >= NV_11 &&
- nv_device(priv)->chipset >= 0x17) {
- /* is it really needed ??? */
- NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
- nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
- NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
- NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
- NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
- NV17_WRITE_CTX(0x00400ec0, 0x00000080);
- NV17_WRITE_CTX(0x00400ed0, 0x00000080);
- }
- NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
-
- nv10_graph_create_pipe(chan);
-
- priv->chan[fifo->chid] = chan;
- chan->chid = fifo->chid;
- spin_unlock_irqrestore(&priv->lock, flags);
- return 0;
-}
-
-static void
-nv10_graph_context_dtor(struct nouveau_object *object)
-{
- struct nv10_graph_priv *priv = (void *)object->engine;
- struct nv10_graph_chan *chan = (void *)object;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- priv->chan[chan->chid] = NULL;
- spin_unlock_irqrestore(&priv->lock, flags);
-
- nouveau_object_destroy(&chan->base);
-}
-
-static int
-nv10_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv10_graph_priv *priv = (void *)object->engine;
- struct nv10_graph_chan *chan = (void *)object;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
- if (nv10_graph_channel(priv) == chan)
- nv10_graph_unload_context(chan);
- nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- return nouveau_object_fini(&chan->base, suspend);
-}
-
-static struct nouveau_oclass
-nv10_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x10),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv10_graph_context_ctor,
- .dtor = nv10_graph_context_dtor,
- .init = nouveau_object_init,
- .fini = nv10_graph_context_fini,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-nv10_graph_tile_prog(struct nouveau_engine *engine, int i)
-{
- struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
- struct nouveau_fifo *pfifo = nouveau_fifo(engine);
- struct nv10_graph_priv *priv = (void *)engine;
- unsigned long flags;
-
- pfifo->pause(pfifo, &flags);
- nv04_graph_idle(priv);
-
- nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
- nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
- nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
-
- pfifo->start(pfifo, &flags);
-}
-
-const struct nouveau_bitfield nv10_graph_intr_name[] = {
- { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
- { NV_PGRAPH_INTR_ERROR, "ERROR" },
- {}
-};
-
-const struct nouveau_bitfield nv10_graph_nstatus[] = {
- { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
- { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
- { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
- { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
- {}
-};
-
-static void
-nv10_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nv10_graph_priv *priv = (void *)subdev;
- struct nv10_graph_chan *chan = NULL;
- struct nouveau_namedb *namedb = NULL;
- struct nouveau_handle *handle = NULL;
- u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
- u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
- u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
- u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
- u32 chid = (addr & 0x01f00000) >> 20;
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
- u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
- u32 show = stat;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->lock, flags);
- chan = priv->chan[chid];
- if (chan)
- namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (stat & NV_PGRAPH_INTR_ERROR) {
- if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
- handle = nouveau_namedb_get_class(namedb, class);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~NV_PGRAPH_INTR_ERROR;
- }
- }
-
- if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
- nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
- stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
- nv10_graph_context_switch(priv);
- }
-
- nv_wr32(priv, NV03_PGRAPH_INTR, stat);
- nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
- if (show) {
- nv_error(priv, "%s", "");
- nouveau_bitfield_print(nv10_graph_intr_name, show);
- pr_cont(" nsource:");
- nouveau_bitfield_print(nv04_graph_nsource, nsource);
- pr_cont(" nstatus:");
- nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
- pr_cont("\n");
- nv_error(priv,
- "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, nouveau_client_name(chan), subc, class, mthd,
- data);
- }
-
- nouveau_namedb_put(handle);
-}
-
-static int
-nv10_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv10_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv10_graph_intr;
- nv_engine(priv)->cclass = &nv10_graph_cclass;
-
- if (nv_device(priv)->chipset <= 0x10)
- nv_engine(priv)->sclass = nv10_graph_sclass;
- else
- if (nv_device(priv)->chipset < 0x17 ||
- nv_device(priv)->card_type < NV_11)
- nv_engine(priv)->sclass = nv15_graph_sclass;
- else
- nv_engine(priv)->sclass = nv17_graph_sclass;
-
- nv_engine(priv)->tile_prog = nv10_graph_tile_prog;
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-static void
-nv10_graph_dtor(struct nouveau_object *object)
-{
- struct nv10_graph_priv *priv = (void *)object;
- nouveau_graph_destroy(&priv->base);
-}
-
-static int
-nv10_graph_init(struct nouveau_object *object)
-{
- struct nouveau_engine *engine = nv_engine(object);
- struct nouveau_fb *pfb = nouveau_fb(object);
- struct nv10_graph_priv *priv = (void *)engine;
- int ret, i;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
- nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
- /* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
- nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
-
- if (nv_device(priv)->card_type >= NV_11 &&
- nv_device(priv)->chipset >= 0x17) {
- nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
- nv_wr32(priv, 0x400a10, 0x03ff3fb6);
- nv_wr32(priv, 0x400838, 0x002f8684);
- nv_wr32(priv, 0x40083c, 0x00115f3f);
- nv_wr32(priv, 0x4006b0, 0x40000020);
- } else {
- nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
- }
-
- /* Turn all the tiling regions off. */
- for (i = 0; i < pfb->tile.regions; i++)
- engine->tile_prog(engine, i);
-
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
- nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
-
- nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
- nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
- nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
- return 0;
-}
-
-static int
-nv10_graph_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv10_graph_priv *priv = (void *)object;
- return nouveau_graph_fini(&priv->base, suspend);
-}
-
-struct nouveau_oclass
-nv10_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x10),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv10_graph_ctor,
- .dtor = nv10_graph_dtor,
- .init = nv10_graph_init,
- .fini = nv10_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c
deleted file mode 100644
index 2b0e8f48c029..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv108.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv108_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0xa140, &nouveau_object_ofuncs },
- { KEPLER_B, &nvc0_fermi_ofuncs },
- { 0xa1c0, &nouveau_object_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nv108_graph_init_main_0[] = {
- { 0x400080, 1, 0x04, 0x003083c2 },
- { 0x400088, 1, 0x04, 0x0001bfe7 },
- { 0x40008c, 1, 0x04, 0x00000000 },
- { 0x400090, 1, 0x04, 0x00000030 },
- { 0x40013c, 1, 0x04, 0x003901f7 },
- { 0x400140, 1, 0x04, 0x00000100 },
- { 0x400144, 1, 0x04, 0x00000000 },
- { 0x400148, 1, 0x04, 0x00000110 },
- { 0x400138, 1, 0x04, 0x00000000 },
- { 0x400130, 2, 0x04, 0x00000000 },
- { 0x400124, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405900, 1, 0x04, 0x00000000 },
- { 0x405908, 1, 0x04, 0x00000000 },
- { 0x405928, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nv108_graph_init_gpc_unk_0[] = {
- { 0x418604, 1, 0x04, 0x00000000 },
- { 0x418680, 1, 0x04, 0x00000000 },
- { 0x418714, 1, 0x04, 0x00000000 },
- { 0x418384, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_setup_1[] = {
- { 0x4188c8, 2, 0x04, 0x00000000 },
- { 0x4188d0, 1, 0x04, 0x00010000 },
- { 0x4188d4, 1, 0x04, 0x00000201 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_tex_0[] = {
- { 0x419ab0, 1, 0x04, 0x00000000 },
- { 0x419ac8, 1, 0x04, 0x00000000 },
- { 0x419ab8, 1, 0x04, 0x000000e7 },
- { 0x419abc, 2, 0x04, 0x00000000 },
- { 0x419ab4, 1, 0x04, 0x00000000 },
- { 0x419aa8, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nv108_graph_init_l1c_0[] = {
- { 0x419c98, 1, 0x04, 0x00000000 },
- { 0x419ca8, 1, 0x04, 0x00000000 },
- { 0x419cb0, 1, 0x04, 0x01000000 },
- { 0x419cb4, 1, 0x04, 0x00000000 },
- { 0x419cb8, 1, 0x04, 0x00b08bea },
- { 0x419c84, 1, 0x04, 0x00010384 },
- { 0x419cbc, 1, 0x04, 0x281b3646 },
- { 0x419cc0, 2, 0x04, 0x00000000 },
- { 0x419c80, 1, 0x04, 0x00000230 },
- { 0x419ccc, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nv108_graph_pack_mmio[] = {
- { nv108_graph_init_main_0 },
- { nvf0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvd9_graph_init_pd_0 },
- { nv108_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvf0_graph_init_sked_0 },
- { nvf0_graph_init_cwd_0 },
- { nvd9_graph_init_prop_0 },
- { nv108_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nv108_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvd9_graph_init_gpm_0 },
- { nvf0_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nve4_graph_init_tpccs_0 },
- { nv108_graph_init_tex_0 },
- { nve4_graph_init_pe_0 },
- { nv108_graph_init_l1c_0 },
- { nvc0_graph_init_mpc_0 },
- { nvf0_graph_init_sm_0 },
- { nvd7_graph_init_pes_0 },
- { nvd7_graph_init_wwdx_0 },
- { nvd7_graph_init_cbm_0 },
- { nve4_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv108_graph_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvc0_graph_priv *priv = (void *)object;
- static const struct {
- u32 addr;
- u32 data;
- } magic[] = {
- { 0x020520, 0xfffffffc },
- { 0x020524, 0xfffffffe },
- { 0x020524, 0xfffffffc },
- { 0x020524, 0xfffffff8 },
- { 0x020524, 0xffffffe0 },
- { 0x020530, 0xfffffffe },
- { 0x02052c, 0xfffffffa },
- { 0x02052c, 0xfffffff0 },
- { 0x02052c, 0xffffffc0 },
- { 0x02052c, 0xffffff00 },
- { 0x02052c, 0xfffffc00 },
- { 0x02052c, 0xfffcfc00 },
- { 0x02052c, 0xfff0fc00 },
- { 0x02052c, 0xff80fc00 },
- { 0x020528, 0xfffffffe },
- { 0x020528, 0xfffffffc },
- };
- int i;
-
- nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
- nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
- for (i = 0; i < ARRAY_SIZE(magic); i++) {
- nv_wr32(priv, magic[i].addr, magic[i].data);
- nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
- }
-
- return nouveau_graph_fini(&priv->base, suspend);
-}
-
-#include "fuc/hubnv108.fuc5.h"
-
-static struct nvc0_graph_ucode
-nv108_graph_fecs_ucode = {
- .code.data = nv108_grhub_code,
- .code.size = sizeof(nv108_grhub_code),
- .data.data = nv108_grhub_data,
- .data.size = sizeof(nv108_grhub_data),
-};
-
-#include "fuc/gpcnv108.fuc5.h"
-
-static struct nvc0_graph_ucode
-nv108_graph_gpccs_ucode = {
- .code.data = nv108_grgpc_code,
- .code.size = sizeof(nv108_grgpc_code),
- .data.data = nv108_grgpc_data,
- .data.size = sizeof(nv108_grgpc_data),
-};
-
-struct nouveau_oclass *
-nv108_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0x08),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nve4_graph_init,
- .fini = nv108_graph_fini,
- },
- .cclass = &nv108_grctx_oclass,
- .sclass = nv108_graph_sclass,
- .mmio = nv108_graph_pack_mmio,
- .fecs.ucode = &nv108_graph_fecs_ucode,
- .gpccs.ucode = &nv108_graph_gpccs_ucode,
- .ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
deleted file mode 100644
index ceb9c746d94e..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.c
+++ /dev/null
@@ -1,383 +0,0 @@
-#include <core/client.h>
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/handle.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-#include <engine/fifo.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv20_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
- { 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
- { 0x0097, &nv04_graph_ofuncs, NULL }, /* kelvin */
- { 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
- { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv20_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_chan *chan;
- int ret, i;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
- 0x37f0, 16, NVOBJ_FLAG_ZERO_ALLOC,
- &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- chan->chid = nouveau_fifo_chan(parent)->chid;
-
- nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
- nv_wo32(chan, 0x033c, 0xffff0000);
- nv_wo32(chan, 0x03a0, 0x0fff0000);
- nv_wo32(chan, 0x03a4, 0x0fff0000);
- nv_wo32(chan, 0x047c, 0x00000101);
- nv_wo32(chan, 0x0490, 0x00000111);
- nv_wo32(chan, 0x04a8, 0x44400000);
- for (i = 0x04d4; i <= 0x04e0; i += 4)
- nv_wo32(chan, i, 0x00030303);
- for (i = 0x04f4; i <= 0x0500; i += 4)
- nv_wo32(chan, i, 0x00080000);
- for (i = 0x050c; i <= 0x0518; i += 4)
- nv_wo32(chan, i, 0x01012000);
- for (i = 0x051c; i <= 0x0528; i += 4)
- nv_wo32(chan, i, 0x000105b8);
- for (i = 0x052c; i <= 0x0538; i += 4)
- nv_wo32(chan, i, 0x00080008);
- for (i = 0x055c; i <= 0x0598; i += 4)
- nv_wo32(chan, i, 0x07ff0000);
- nv_wo32(chan, 0x05a4, 0x4b7fffff);
- nv_wo32(chan, 0x05fc, 0x00000001);
- nv_wo32(chan, 0x0604, 0x00004000);
- nv_wo32(chan, 0x0610, 0x00000001);
- nv_wo32(chan, 0x0618, 0x00040000);
- nv_wo32(chan, 0x061c, 0x00010000);
- for (i = 0x1c1c; i <= 0x248c; i += 16) {
- nv_wo32(chan, (i + 0), 0x10700ff9);
- nv_wo32(chan, (i + 4), 0x0436086c);
- nv_wo32(chan, (i + 8), 0x000c001b);
- }
- nv_wo32(chan, 0x281c, 0x3f800000);
- nv_wo32(chan, 0x2830, 0x3f800000);
- nv_wo32(chan, 0x285c, 0x40000000);
- nv_wo32(chan, 0x2860, 0x3f800000);
- nv_wo32(chan, 0x2864, 0x3f000000);
- nv_wo32(chan, 0x286c, 0x40000000);
- nv_wo32(chan, 0x2870, 0x3f800000);
- nv_wo32(chan, 0x2878, 0xbf800000);
- nv_wo32(chan, 0x2880, 0xbf800000);
- nv_wo32(chan, 0x34a4, 0x000fe000);
- nv_wo32(chan, 0x3530, 0x000003f8);
- nv_wo32(chan, 0x3540, 0x002fe000);
- for (i = 0x355c; i <= 0x3578; i += 4)
- nv_wo32(chan, i, 0x001c527c);
- return 0;
-}
-
-int
-nv20_graph_context_init(struct nouveau_object *object)
-{
- struct nv20_graph_priv *priv = (void *)object->engine;
- struct nv20_graph_chan *chan = (void *)object;
- int ret;
-
- ret = nouveau_graph_context_init(&chan->base);
- if (ret)
- return ret;
-
- nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
- return 0;
-}
-
-int
-nv20_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv20_graph_priv *priv = (void *)object->engine;
- struct nv20_graph_chan *chan = (void *)object;
- int chid = -1;
-
- nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
- if (nv_rd32(priv, 0x400144) & 0x00010000)
- chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
- if (chan->chid == chid) {
- nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
- nv_wr32(priv, 0x400788, 0x00000002);
- nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
- nv_wr32(priv, 0x400144, 0x10000000);
- nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
- }
- nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
-
- nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
- return nouveau_graph_context_fini(&chan->base, suspend);
-}
-
-static struct nouveau_oclass
-nv20_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x20),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv20_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = nv20_graph_context_init,
- .fini = nv20_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-void
-nv20_graph_tile_prog(struct nouveau_engine *engine, int i)
-{
- struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
- struct nouveau_fifo *pfifo = nouveau_fifo(engine);
- struct nv20_graph_priv *priv = (void *)engine;
- unsigned long flags;
-
- pfifo->pause(pfifo, &flags);
- nv04_graph_idle(priv);
-
- nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
- nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
- nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
-
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
-
- if (nv_device(engine)->chipset != 0x34) {
- nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
- }
-
- pfifo->start(pfifo, &flags);
-}
-
-void
-nv20_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nouveau_handle *handle;
- struct nv20_graph_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
- u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
- u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
- u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
- u32 chid = (addr & 0x01f00000) >> 20;
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
- u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
- u32 show = stat;
-
- engctx = nouveau_engctx_get(engine, chid);
- if (stat & NV_PGRAPH_INTR_ERROR) {
- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
- handle = nouveau_handle_get_class(engctx, class);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~NV_PGRAPH_INTR_ERROR;
- nouveau_handle_put(handle);
- }
- }
-
- nv_wr32(priv, NV03_PGRAPH_INTR, stat);
- nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
- if (show) {
- nv_error(priv, "%s", "");
- nouveau_bitfield_print(nv10_graph_intr_name, show);
- pr_cont(" nsource:");
- nouveau_bitfield_print(nv04_graph_nsource, nsource);
- pr_cont(" nstatus:");
- nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
- pr_cont("\n");
- nv_error(priv,
- "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, nouveau_client_name(engctx), subc, class, mthd,
- data);
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static int
-nv20_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv20_graph_intr;
- nv_engine(priv)->cclass = &nv20_graph_cclass;
- nv_engine(priv)->sclass = nv20_graph_sclass;
- nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
- return 0;
-}
-
-void
-nv20_graph_dtor(struct nouveau_object *object)
-{
- struct nv20_graph_priv *priv = (void *)object;
- nouveau_gpuobj_ref(NULL, &priv->ctxtab);
- nouveau_graph_destroy(&priv->base);
-}
-
-int
-nv20_graph_init(struct nouveau_object *object)
-{
- struct nouveau_engine *engine = nv_engine(object);
- struct nv20_graph_priv *priv = (void *)engine;
- struct nouveau_fb *pfb = nouveau_fb(object);
- u32 tmp, vramsz;
- int ret, i;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
-
- if (nv_device(priv)->chipset == 0x20) {
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
- for (i = 0; i < 15; i++)
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
- nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
- } else {
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
- for (i = 0; i < 32; i++)
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
- nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
- }
-
- nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
- nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
- nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
- nv_wr32(priv, 0x40009C , 0x00000040);
-
- if (nv_device(priv)->chipset >= 0x25) {
- nv_wr32(priv, 0x400890, 0x00a8cfff);
- nv_wr32(priv, 0x400610, 0x304B1FB6);
- nv_wr32(priv, 0x400B80, 0x1cbd3883);
- nv_wr32(priv, 0x400B84, 0x44000000);
- nv_wr32(priv, 0x400098, 0x40000080);
- nv_wr32(priv, 0x400B88, 0x000000ff);
-
- } else {
- nv_wr32(priv, 0x400880, 0x0008c7df);
- nv_wr32(priv, 0x400094, 0x00000005);
- nv_wr32(priv, 0x400B80, 0x45eae20e);
- nv_wr32(priv, 0x400B84, 0x24000000);
- nv_wr32(priv, 0x400098, 0x00000040);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
- }
-
- /* Turn all the tiling regions off. */
- for (i = 0; i < pfb->tile.regions; i++)
- engine->tile_prog(engine, i);
-
- nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
-
- nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
- nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
-
- tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
- nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
- tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
- nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
-
- /* begin RAM config */
- vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
- nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
- nv_wr32(priv, 0x400820, 0);
- nv_wr32(priv, 0x400824, 0);
- nv_wr32(priv, 0x400864, vramsz - 1);
- nv_wr32(priv, 0x400868, vramsz - 1);
-
- /* interesting.. the below overwrites some of the tile setup above.. */
- nv_wr32(priv, 0x400B20, 0x00000000);
- nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
-
- nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
- nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
- nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
- nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
- return 0;
-}
-
-struct nouveau_oclass
-nv20_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x20),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv20_graph_ctor,
- .dtor = nv20_graph_dtor,
- .init = nv20_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
deleted file mode 100644
index 2bea7313e03f..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv20.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NV20_GRAPH_H__
-#define __NV20_GRAPH_H__
-
-#include <core/enum.h>
-
-#include <engine/graph.h>
-#include <engine/fifo.h>
-
-struct nv20_graph_priv {
- struct nouveau_graph base;
- struct nouveau_gpuobj *ctxtab;
-};
-
-struct nv20_graph_chan {
- struct nouveau_graph_chan base;
- int chid;
-};
-
-extern struct nouveau_oclass nv25_graph_sclass[];
-int nv20_graph_context_init(struct nouveau_object *);
-int nv20_graph_context_fini(struct nouveau_object *, bool);
-
-void nv20_graph_tile_prog(struct nouveau_engine *, int);
-void nv20_graph_intr(struct nouveau_subdev *);
-
-void nv20_graph_dtor(struct nouveau_object *);
-int nv20_graph_init(struct nouveau_object *);
-
-int nv30_graph_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
deleted file mode 100644
index f8a6fdd7d5e8..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv25.c
+++ /dev/null
@@ -1,166 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-struct nouveau_oclass
-nv25_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
- { 0x0096, &nv04_graph_ofuncs, NULL }, /* celcius */
- { 0x009e, &nv04_graph_ofuncs, NULL }, /* swzsurf */
- { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
- { 0x0597, &nv04_graph_ofuncs, NULL }, /* kelvin */
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv25_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_chan *chan;
- int ret, i;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x3724,
- 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- chan->chid = nouveau_fifo_chan(parent)->chid;
-
- nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
- nv_wo32(chan, 0x035c, 0xffff0000);
- nv_wo32(chan, 0x03c0, 0x0fff0000);
- nv_wo32(chan, 0x03c4, 0x0fff0000);
- nv_wo32(chan, 0x049c, 0x00000101);
- nv_wo32(chan, 0x04b0, 0x00000111);
- nv_wo32(chan, 0x04c8, 0x00000080);
- nv_wo32(chan, 0x04cc, 0xffff0000);
- nv_wo32(chan, 0x04d0, 0x00000001);
- nv_wo32(chan, 0x04e4, 0x44400000);
- nv_wo32(chan, 0x04fc, 0x4b800000);
- for (i = 0x0510; i <= 0x051c; i += 4)
- nv_wo32(chan, i, 0x00030303);
- for (i = 0x0530; i <= 0x053c; i += 4)
- nv_wo32(chan, i, 0x00080000);
- for (i = 0x0548; i <= 0x0554; i += 4)
- nv_wo32(chan, i, 0x01012000);
- for (i = 0x0558; i <= 0x0564; i += 4)
- nv_wo32(chan, i, 0x000105b8);
- for (i = 0x0568; i <= 0x0574; i += 4)
- nv_wo32(chan, i, 0x00080008);
- for (i = 0x0598; i <= 0x05d4; i += 4)
- nv_wo32(chan, i, 0x07ff0000);
- nv_wo32(chan, 0x05e0, 0x4b7fffff);
- nv_wo32(chan, 0x0620, 0x00000080);
- nv_wo32(chan, 0x0624, 0x30201000);
- nv_wo32(chan, 0x0628, 0x70605040);
- nv_wo32(chan, 0x062c, 0xb0a09080);
- nv_wo32(chan, 0x0630, 0xf0e0d0c0);
- nv_wo32(chan, 0x0664, 0x00000001);
- nv_wo32(chan, 0x066c, 0x00004000);
- nv_wo32(chan, 0x0678, 0x00000001);
- nv_wo32(chan, 0x0680, 0x00040000);
- nv_wo32(chan, 0x0684, 0x00010000);
- for (i = 0x1b04; i <= 0x2374; i += 16) {
- nv_wo32(chan, (i + 0), 0x10700ff9);
- nv_wo32(chan, (i + 4), 0x0436086c);
- nv_wo32(chan, (i + 8), 0x000c001b);
- }
- nv_wo32(chan, 0x2704, 0x3f800000);
- nv_wo32(chan, 0x2718, 0x3f800000);
- nv_wo32(chan, 0x2744, 0x40000000);
- nv_wo32(chan, 0x2748, 0x3f800000);
- nv_wo32(chan, 0x274c, 0x3f000000);
- nv_wo32(chan, 0x2754, 0x40000000);
- nv_wo32(chan, 0x2758, 0x3f800000);
- nv_wo32(chan, 0x2760, 0xbf800000);
- nv_wo32(chan, 0x2768, 0xbf800000);
- nv_wo32(chan, 0x308c, 0x000fe000);
- nv_wo32(chan, 0x3108, 0x000003f8);
- nv_wo32(chan, 0x3468, 0x002fe000);
- for (i = 0x3484; i <= 0x34a0; i += 4)
- nv_wo32(chan, i, 0x001c527c);
- return 0;
-}
-
-static struct nouveau_oclass
-nv25_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x25),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv25_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = nv20_graph_context_init,
- .fini = nv20_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv25_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv20_graph_intr;
- nv_engine(priv)->cclass = &nv25_graph_cclass;
- nv_engine(priv)->sclass = nv25_graph_sclass;
- nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv25_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x25),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv25_graph_ctor,
- .dtor = nv20_graph_dtor,
- .init = nv20_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
deleted file mode 100644
index 5de9caa2ef67..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv2a.c
+++ /dev/null
@@ -1,133 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv2a_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_chan *chan;
- int ret, i;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x36b0,
- 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- chan->chid = nouveau_fifo_chan(parent)->chid;
-
- nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
- nv_wo32(chan, 0x033c, 0xffff0000);
- nv_wo32(chan, 0x03a0, 0x0fff0000);
- nv_wo32(chan, 0x03a4, 0x0fff0000);
- nv_wo32(chan, 0x047c, 0x00000101);
- nv_wo32(chan, 0x0490, 0x00000111);
- nv_wo32(chan, 0x04a8, 0x44400000);
- for (i = 0x04d4; i <= 0x04e0; i += 4)
- nv_wo32(chan, i, 0x00030303);
- for (i = 0x04f4; i <= 0x0500; i += 4)
- nv_wo32(chan, i, 0x00080000);
- for (i = 0x050c; i <= 0x0518; i += 4)
- nv_wo32(chan, i, 0x01012000);
- for (i = 0x051c; i <= 0x0528; i += 4)
- nv_wo32(chan, i, 0x000105b8);
- for (i = 0x052c; i <= 0x0538; i += 4)
- nv_wo32(chan, i, 0x00080008);
- for (i = 0x055c; i <= 0x0598; i += 4)
- nv_wo32(chan, i, 0x07ff0000);
- nv_wo32(chan, 0x05a4, 0x4b7fffff);
- nv_wo32(chan, 0x05fc, 0x00000001);
- nv_wo32(chan, 0x0604, 0x00004000);
- nv_wo32(chan, 0x0610, 0x00000001);
- nv_wo32(chan, 0x0618, 0x00040000);
- nv_wo32(chan, 0x061c, 0x00010000);
- for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
- nv_wo32(chan, (i + 0), 0x10700ff9);
- nv_wo32(chan, (i + 4), 0x0436086c);
- nv_wo32(chan, (i + 8), 0x000c001b);
- }
- nv_wo32(chan, 0x269c, 0x3f800000);
- nv_wo32(chan, 0x26b0, 0x3f800000);
- nv_wo32(chan, 0x26dc, 0x40000000);
- nv_wo32(chan, 0x26e0, 0x3f800000);
- nv_wo32(chan, 0x26e4, 0x3f000000);
- nv_wo32(chan, 0x26ec, 0x40000000);
- nv_wo32(chan, 0x26f0, 0x3f800000);
- nv_wo32(chan, 0x26f8, 0xbf800000);
- nv_wo32(chan, 0x2700, 0xbf800000);
- nv_wo32(chan, 0x3024, 0x000fe000);
- nv_wo32(chan, 0x30a0, 0x000003f8);
- nv_wo32(chan, 0x33fc, 0x002fe000);
- for (i = 0x341c; i <= 0x3438; i += 4)
- nv_wo32(chan, i, 0x001c527c);
- return 0;
-}
-
-static struct nouveau_oclass
-nv2a_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x2a),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv2a_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = nv20_graph_context_init,
- .fini = nv20_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv2a_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv20_graph_intr;
- nv_engine(priv)->cclass = &nv2a_graph_cclass;
- nv_engine(priv)->sclass = nv25_graph_sclass;
- nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv2a_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x2a),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv2a_graph_ctor,
- .dtor = nv20_graph_dtor,
- .init = nv20_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
deleted file mode 100644
index 2f9dbc709389..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv30.c
+++ /dev/null
@@ -1,237 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv30_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
- { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
- { 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
- { 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
- { 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
- { 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
- { 0x0397, &nv04_graph_ofuncs, NULL }, /* rankine */
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv30_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_chan *chan;
- int ret, i;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x5f48,
- 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- chan->chid = nouveau_fifo_chan(parent)->chid;
-
- nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
- nv_wo32(chan, 0x0410, 0x00000101);
- nv_wo32(chan, 0x0424, 0x00000111);
- nv_wo32(chan, 0x0428, 0x00000060);
- nv_wo32(chan, 0x0444, 0x00000080);
- nv_wo32(chan, 0x0448, 0xffff0000);
- nv_wo32(chan, 0x044c, 0x00000001);
- nv_wo32(chan, 0x0460, 0x44400000);
- nv_wo32(chan, 0x048c, 0xffff0000);
- for (i = 0x04e0; i < 0x04e8; i += 4)
- nv_wo32(chan, i, 0x0fff0000);
- nv_wo32(chan, 0x04ec, 0x00011100);
- for (i = 0x0508; i < 0x0548; i += 4)
- nv_wo32(chan, i, 0x07ff0000);
- nv_wo32(chan, 0x0550, 0x4b7fffff);
- nv_wo32(chan, 0x058c, 0x00000080);
- nv_wo32(chan, 0x0590, 0x30201000);
- nv_wo32(chan, 0x0594, 0x70605040);
- nv_wo32(chan, 0x0598, 0xb8a89888);
- nv_wo32(chan, 0x059c, 0xf8e8d8c8);
- nv_wo32(chan, 0x05b0, 0xb0000000);
- for (i = 0x0600; i < 0x0640; i += 4)
- nv_wo32(chan, i, 0x00010588);
- for (i = 0x0640; i < 0x0680; i += 4)
- nv_wo32(chan, i, 0x00030303);
- for (i = 0x06c0; i < 0x0700; i += 4)
- nv_wo32(chan, i, 0x0008aae4);
- for (i = 0x0700; i < 0x0740; i += 4)
- nv_wo32(chan, i, 0x01012000);
- for (i = 0x0740; i < 0x0780; i += 4)
- nv_wo32(chan, i, 0x00080008);
- nv_wo32(chan, 0x085c, 0x00040000);
- nv_wo32(chan, 0x0860, 0x00010000);
- for (i = 0x0864; i < 0x0874; i += 4)
- nv_wo32(chan, i, 0x00040004);
- for (i = 0x1f18; i <= 0x3088 ; i += 16) {
- nv_wo32(chan, i + 0, 0x10700ff9);
- nv_wo32(chan, i + 1, 0x0436086c);
- nv_wo32(chan, i + 2, 0x000c001b);
- }
- for (i = 0x30b8; i < 0x30c8; i += 4)
- nv_wo32(chan, i, 0x0000ffff);
- nv_wo32(chan, 0x344c, 0x3f800000);
- nv_wo32(chan, 0x3808, 0x3f800000);
- nv_wo32(chan, 0x381c, 0x3f800000);
- nv_wo32(chan, 0x3848, 0x40000000);
- nv_wo32(chan, 0x384c, 0x3f800000);
- nv_wo32(chan, 0x3850, 0x3f000000);
- nv_wo32(chan, 0x3858, 0x40000000);
- nv_wo32(chan, 0x385c, 0x3f800000);
- nv_wo32(chan, 0x3864, 0xbf800000);
- nv_wo32(chan, 0x386c, 0xbf800000);
- return 0;
-}
-
-static struct nouveau_oclass
-nv30_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x30),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv30_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = nv20_graph_context_init,
- .fini = nv20_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv30_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv20_graph_intr;
- nv_engine(priv)->cclass = &nv30_graph_cclass;
- nv_engine(priv)->sclass = nv30_graph_sclass;
- nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
- return 0;
-}
-
-int
-nv30_graph_init(struct nouveau_object *object)
-{
- struct nouveau_engine *engine = nv_engine(object);
- struct nv20_graph_priv *priv = (void *)engine;
- struct nouveau_fb *pfb = nouveau_fb(object);
- int ret, i;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
-
- nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
- nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
- nv_wr32(priv, 0x400890, 0x01b463ff);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
- nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
- nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
- nv_wr32(priv, 0x400B80, 0x1003d888);
- nv_wr32(priv, 0x400B84, 0x0c000000);
- nv_wr32(priv, 0x400098, 0x00000000);
- nv_wr32(priv, 0x40009C, 0x0005ad00);
- nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
- nv_wr32(priv, 0x4000a0, 0x00000000);
- nv_wr32(priv, 0x4000a4, 0x00000008);
- nv_wr32(priv, 0x4008a8, 0xb784a400);
- nv_wr32(priv, 0x400ba0, 0x002f8685);
- nv_wr32(priv, 0x400ba4, 0x00231f3f);
- nv_wr32(priv, 0x4008a4, 0x40000020);
-
- if (nv_device(priv)->chipset == 0x34) {
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
- nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
- nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
- }
-
- nv_wr32(priv, 0x4000c0, 0x00000016);
-
- /* Turn all the tiling regions off. */
- for (i = 0; i < pfb->tile.regions; i++)
- engine->tile_prog(engine, i);
-
- nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
- nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
- nv_wr32(priv, 0x0040075c , 0x00000001);
-
- /* begin RAM config */
- /* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
- nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
- if (nv_device(priv)->chipset != 0x34) {
- nv_wr32(priv, 0x400750, 0x00EA0000);
- nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x400750, 0x00EA0004);
- nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
- }
- return 0;
-}
-
-struct nouveau_oclass
-nv30_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x30),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv30_graph_ctor,
- .dtor = nv20_graph_dtor,
- .init = nv30_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
deleted file mode 100644
index 34dd26c70b64..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv34.c
+++ /dev/null
@@ -1,167 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include <engine/graph.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv34_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
- { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
- { 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
- { 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
- { 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
- { 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
- { 0x0697, &nv04_graph_ofuncs, NULL }, /* rankine */
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv34_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_chan *chan;
- int ret, i;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x46dc,
- 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- chan->chid = nouveau_fifo_chan(parent)->chid;
-
- nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
- nv_wo32(chan, 0x040c, 0x01000101);
- nv_wo32(chan, 0x0420, 0x00000111);
- nv_wo32(chan, 0x0424, 0x00000060);
- nv_wo32(chan, 0x0440, 0x00000080);
- nv_wo32(chan, 0x0444, 0xffff0000);
- nv_wo32(chan, 0x0448, 0x00000001);
- nv_wo32(chan, 0x045c, 0x44400000);
- nv_wo32(chan, 0x0480, 0xffff0000);
- for (i = 0x04d4; i < 0x04dc; i += 4)
- nv_wo32(chan, i, 0x0fff0000);
- nv_wo32(chan, 0x04e0, 0x00011100);
- for (i = 0x04fc; i < 0x053c; i += 4)
- nv_wo32(chan, i, 0x07ff0000);
- nv_wo32(chan, 0x0544, 0x4b7fffff);
- nv_wo32(chan, 0x057c, 0x00000080);
- nv_wo32(chan, 0x0580, 0x30201000);
- nv_wo32(chan, 0x0584, 0x70605040);
- nv_wo32(chan, 0x0588, 0xb8a89888);
- nv_wo32(chan, 0x058c, 0xf8e8d8c8);
- nv_wo32(chan, 0x05a0, 0xb0000000);
- for (i = 0x05f0; i < 0x0630; i += 4)
- nv_wo32(chan, i, 0x00010588);
- for (i = 0x0630; i < 0x0670; i += 4)
- nv_wo32(chan, i, 0x00030303);
- for (i = 0x06b0; i < 0x06f0; i += 4)
- nv_wo32(chan, i, 0x0008aae4);
- for (i = 0x06f0; i < 0x0730; i += 4)
- nv_wo32(chan, i, 0x01012000);
- for (i = 0x0730; i < 0x0770; i += 4)
- nv_wo32(chan, i, 0x00080008);
- nv_wo32(chan, 0x0850, 0x00040000);
- nv_wo32(chan, 0x0854, 0x00010000);
- for (i = 0x0858; i < 0x0868; i += 4)
- nv_wo32(chan, i, 0x00040004);
- for (i = 0x15ac; i <= 0x271c ; i += 16) {
- nv_wo32(chan, i + 0, 0x10700ff9);
- nv_wo32(chan, i + 1, 0x0436086c);
- nv_wo32(chan, i + 2, 0x000c001b);
- }
- for (i = 0x274c; i < 0x275c; i += 4)
- nv_wo32(chan, i, 0x0000ffff);
- nv_wo32(chan, 0x2ae0, 0x3f800000);
- nv_wo32(chan, 0x2e9c, 0x3f800000);
- nv_wo32(chan, 0x2eb0, 0x3f800000);
- nv_wo32(chan, 0x2edc, 0x40000000);
- nv_wo32(chan, 0x2ee0, 0x3f800000);
- nv_wo32(chan, 0x2ee4, 0x3f000000);
- nv_wo32(chan, 0x2eec, 0x40000000);
- nv_wo32(chan, 0x2ef0, 0x3f800000);
- nv_wo32(chan, 0x2ef8, 0xbf800000);
- nv_wo32(chan, 0x2f00, 0xbf800000);
- return 0;
-}
-
-static struct nouveau_oclass
-nv34_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x34),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv34_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = nv20_graph_context_init,
- .fini = nv20_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv34_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv20_graph_intr;
- nv_engine(priv)->cclass = &nv34_graph_cclass;
- nv_engine(priv)->sclass = nv34_graph_sclass;
- nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv34_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x34),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv34_graph_ctor,
- .dtor = nv20_graph_dtor,
- .init = nv30_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
deleted file mode 100644
index 2fb5756d9f66..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv35.c
+++ /dev/null
@@ -1,165 +0,0 @@
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-
-#include "nv20.h"
-#include "regs.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv35_graph_sclass[] = {
- { 0x0012, &nv04_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv04_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv04_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv04_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv04_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv04_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv04_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv04_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv04_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv04_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv04_graph_ofuncs, NULL }, /* ifc */
- { 0x009f, &nv04_graph_ofuncs, NULL }, /* imageblit */
- { 0x0362, &nv04_graph_ofuncs, NULL }, /* surf2d (nv30) */
- { 0x0389, &nv04_graph_ofuncs, NULL }, /* sifm (nv30) */
- { 0x038a, &nv04_graph_ofuncs, NULL }, /* ifc (nv30) */
- { 0x039e, &nv04_graph_ofuncs, NULL }, /* swzsurf (nv30) */
- { 0x0497, &nv04_graph_ofuncs, NULL }, /* rankine */
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv35_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_chan *chan;
- int ret, i;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL, 0x577c,
- 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- chan->chid = nouveau_fifo_chan(parent)->chid;
-
- nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
- nv_wo32(chan, 0x040c, 0x00000101);
- nv_wo32(chan, 0x0420, 0x00000111);
- nv_wo32(chan, 0x0424, 0x00000060);
- nv_wo32(chan, 0x0440, 0x00000080);
- nv_wo32(chan, 0x0444, 0xffff0000);
- nv_wo32(chan, 0x0448, 0x00000001);
- nv_wo32(chan, 0x045c, 0x44400000);
- nv_wo32(chan, 0x0488, 0xffff0000);
- for (i = 0x04dc; i < 0x04e4; i += 4)
- nv_wo32(chan, i, 0x0fff0000);
- nv_wo32(chan, 0x04e8, 0x00011100);
- for (i = 0x0504; i < 0x0544; i += 4)
- nv_wo32(chan, i, 0x07ff0000);
- nv_wo32(chan, 0x054c, 0x4b7fffff);
- nv_wo32(chan, 0x0588, 0x00000080);
- nv_wo32(chan, 0x058c, 0x30201000);
- nv_wo32(chan, 0x0590, 0x70605040);
- nv_wo32(chan, 0x0594, 0xb8a89888);
- nv_wo32(chan, 0x0598, 0xf8e8d8c8);
- nv_wo32(chan, 0x05ac, 0xb0000000);
- for (i = 0x0604; i < 0x0644; i += 4)
- nv_wo32(chan, i, 0x00010588);
- for (i = 0x0644; i < 0x0684; i += 4)
- nv_wo32(chan, i, 0x00030303);
- for (i = 0x06c4; i < 0x0704; i += 4)
- nv_wo32(chan, i, 0x0008aae4);
- for (i = 0x0704; i < 0x0744; i += 4)
- nv_wo32(chan, i, 0x01012000);
- for (i = 0x0744; i < 0x0784; i += 4)
- nv_wo32(chan, i, 0x00080008);
- nv_wo32(chan, 0x0860, 0x00040000);
- nv_wo32(chan, 0x0864, 0x00010000);
- for (i = 0x0868; i < 0x0878; i += 4)
- nv_wo32(chan, i, 0x00040004);
- for (i = 0x1f1c; i <= 0x308c ; i += 16) {
- nv_wo32(chan, i + 0, 0x10700ff9);
- nv_wo32(chan, i + 4, 0x0436086c);
- nv_wo32(chan, i + 8, 0x000c001b);
- }
- for (i = 0x30bc; i < 0x30cc; i += 4)
- nv_wo32(chan, i, 0x0000ffff);
- nv_wo32(chan, 0x3450, 0x3f800000);
- nv_wo32(chan, 0x380c, 0x3f800000);
- nv_wo32(chan, 0x3820, 0x3f800000);
- nv_wo32(chan, 0x384c, 0x40000000);
- nv_wo32(chan, 0x3850, 0x3f800000);
- nv_wo32(chan, 0x3854, 0x3f000000);
- nv_wo32(chan, 0x385c, 0x40000000);
- nv_wo32(chan, 0x3860, 0x3f800000);
- nv_wo32(chan, 0x3868, 0xbf800000);
- nv_wo32(chan, 0x3870, 0xbf800000);
- return 0;
-}
-
-static struct nouveau_oclass
-nv35_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x35),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv35_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = nv20_graph_context_init,
- .fini = nv20_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static int
-nv35_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv20_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv20_graph_intr;
- nv_engine(priv)->cclass = &nv35_graph_cclass;
- nv_engine(priv)->sclass = nv35_graph_sclass;
- nv_engine(priv)->tile_prog = nv20_graph_tile_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv35_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x35),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv35_graph_ctor,
- .dtor = nv20_graph_dtor,
- .init = nv30_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
deleted file mode 100644
index 4f401174868d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.c
+++ /dev/null
@@ -1,536 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/handle.h>
-#include <core/engctx.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include <engine/graph.h>
-#include <engine/fifo.h>
-
-#include "nv40.h"
-#include "regs.h"
-
-struct nv40_graph_priv {
- struct nouveau_graph base;
- u32 size;
-};
-
-struct nv40_graph_chan {
- struct nouveau_graph_chan base;
-};
-
-static u64
-nv40_graph_units(struct nouveau_graph *graph)
-{
- struct nv40_graph_priv *priv = (void *)graph;
-
- return nv_rd32(priv, 0x1540);
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static int
-nv40_graph_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj *obj;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
- 20, 16, 0, &obj);
- *pobject = nv_object(obj);
- if (ret)
- return ret;
-
- nv_wo32(obj, 0x00, nv_mclass(obj));
- nv_wo32(obj, 0x04, 0x00000000);
- nv_wo32(obj, 0x08, 0x00000000);
-#ifdef __BIG_ENDIAN
- nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
-#endif
- nv_wo32(obj, 0x0c, 0x00000000);
- nv_wo32(obj, 0x10, 0x00000000);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv40_graph_ofuncs = {
- .ctor = nv40_graph_object_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv40_graph_sclass[] = {
- { 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
- { 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
- { 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
- { 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
- { 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
- { 0x4097, &nv40_graph_ofuncs, NULL }, /* curie */
- {},
-};
-
-static struct nouveau_oclass
-nv44_graph_sclass[] = {
- { 0x0012, &nv40_graph_ofuncs, NULL }, /* beta1 */
- { 0x0019, &nv40_graph_ofuncs, NULL }, /* clip */
- { 0x0030, &nv40_graph_ofuncs, NULL }, /* null */
- { 0x0039, &nv40_graph_ofuncs, NULL }, /* m2mf */
- { 0x0043, &nv40_graph_ofuncs, NULL }, /* rop */
- { 0x0044, &nv40_graph_ofuncs, NULL }, /* patt */
- { 0x004a, &nv40_graph_ofuncs, NULL }, /* gdi */
- { 0x0062, &nv40_graph_ofuncs, NULL }, /* surf2d */
- { 0x0072, &nv40_graph_ofuncs, NULL }, /* beta4 */
- { 0x0089, &nv40_graph_ofuncs, NULL }, /* sifm */
- { 0x008a, &nv40_graph_ofuncs, NULL }, /* ifc */
- { 0x009f, &nv40_graph_ofuncs, NULL }, /* imageblit */
- { 0x3062, &nv40_graph_ofuncs, NULL }, /* surf2d (nv40) */
- { 0x3089, &nv40_graph_ofuncs, NULL }, /* sifm (nv40) */
- { 0x309e, &nv40_graph_ofuncs, NULL }, /* swzsurf (nv40) */
- { 0x4497, &nv40_graph_ofuncs, NULL }, /* curie */
- {},
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv40_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv40_graph_priv *priv = (void *)engine;
- struct nv40_graph_chan *chan;
- int ret;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
- priv->size, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
- nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
- return 0;
-}
-
-static int
-nv40_graph_context_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv40_graph_priv *priv = (void *)object->engine;
- struct nv40_graph_chan *chan = (void *)object;
- u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
- int ret = 0;
-
- nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
-
- if (nv_rd32(priv, 0x40032c) == inst) {
- if (suspend) {
- nv_wr32(priv, 0x400720, 0x00000000);
- nv_wr32(priv, 0x400784, inst);
- nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
- nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
- if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
- u32 insn = nv_rd32(priv, 0x400308);
- nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
- ret = -EBUSY;
- }
- }
-
- nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
- }
-
- if (nv_rd32(priv, 0x400330) == inst)
- nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
-
- nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
- return ret;
-}
-
-static struct nouveau_oclass
-nv40_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = nv40_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static void
-nv40_graph_tile_prog(struct nouveau_engine *engine, int i)
-{
- struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
- struct nouveau_fifo *pfifo = nouveau_fifo(engine);
- struct nv40_graph_priv *priv = (void *)engine;
- unsigned long flags;
-
- pfifo->pause(pfifo, &flags);
- nv04_graph_idle(priv);
-
- switch (nv_device(priv)->chipset) {
- case 0x40:
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x45:
- case 0x4e:
- nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
- nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
- nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
- nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
- nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
- nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
- switch (nv_device(priv)->chipset) {
- case 0x40:
- case 0x45:
- nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
- nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp);
- break;
- case 0x41:
- case 0x42:
- case 0x43:
- nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp);
- nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp);
- break;
- default:
- break;
- }
- break;
- case 0x44:
- case 0x4a:
- nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
- nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
- nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
- break;
- case 0x46:
- case 0x4c:
- case 0x47:
- case 0x49:
- case 0x4b:
- case 0x63:
- case 0x67:
- case 0x68:
- nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
- nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
- nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
- nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
- nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
- nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
- switch (nv_device(priv)->chipset) {
- case 0x47:
- case 0x49:
- case 0x4b:
- nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
- nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
- break;
- default:
- break;
- }
- break;
- default:
- break;
- }
-
- pfifo->start(pfifo, &flags);
-}
-
-static void
-nv40_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nouveau_handle *handle = NULL;
- struct nv40_graph_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
- u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
- u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
- u32 inst = nv_rd32(priv, 0x40032c) & 0x000fffff;
- u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
- u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
- u32 show = stat;
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & NV_PGRAPH_INTR_ERROR) {
- if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
- handle = nouveau_handle_get_class(engctx, class);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~NV_PGRAPH_INTR_ERROR;
- nouveau_handle_put(handle);
- }
-
- if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
- nv_mask(priv, 0x402000, 0, 0);
- }
- }
-
- nv_wr32(priv, NV03_PGRAPH_INTR, stat);
- nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
-
- if (show) {
- nv_error(priv, "%s", "");
- nouveau_bitfield_print(nv10_graph_intr_name, show);
- pr_cont(" nsource:");
- nouveau_bitfield_print(nv04_graph_nsource, nsource);
- pr_cont(" nstatus:");
- nouveau_bitfield_print(nv10_graph_nstatus, nstatus);
- pr_cont("\n");
- nv_error(priv,
- "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst << 4, nouveau_client_name(engctx), subc,
- class, mthd, data);
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static int
-nv40_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv40_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00001000;
- nv_subdev(priv)->intr = nv40_graph_intr;
- nv_engine(priv)->cclass = &nv40_graph_cclass;
- if (nv44_graph_class(priv))
- nv_engine(priv)->sclass = nv44_graph_sclass;
- else
- nv_engine(priv)->sclass = nv40_graph_sclass;
- nv_engine(priv)->tile_prog = nv40_graph_tile_prog;
-
- priv->base.units = nv40_graph_units;
- return 0;
-}
-
-static int
-nv40_graph_init(struct nouveau_object *object)
-{
- struct nouveau_engine *engine = nv_engine(object);
- struct nouveau_fb *pfb = nouveau_fb(object);
- struct nv40_graph_priv *priv = (void *)engine;
- int ret, i, j;
- u32 vramsz;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- /* generate and upload context program */
- ret = nv40_grctx_init(nv_device(priv), &priv->size);
- if (ret)
- return ret;
-
- /* No context present currently */
- nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
-
- nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
- nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
-
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
- nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
- nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
- nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
-
- nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
- nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
-
- j = nv_rd32(priv, 0x1540) & 0xff;
- if (j) {
- for (i = 0; !(j & 1); j >>= 1, i++)
- ;
- nv_wr32(priv, 0x405000, i);
- }
-
- if (nv_device(priv)->chipset == 0x40) {
- nv_wr32(priv, 0x4009b0, 0x83280fff);
- nv_wr32(priv, 0x4009b4, 0x000000a0);
- } else {
- nv_wr32(priv, 0x400820, 0x83280eff);
- nv_wr32(priv, 0x400824, 0x000000a0);
- }
-
- switch (nv_device(priv)->chipset) {
- case 0x40:
- case 0x45:
- nv_wr32(priv, 0x4009b8, 0x0078e366);
- nv_wr32(priv, 0x4009bc, 0x0000014c);
- break;
- case 0x41:
- case 0x42: /* pciid also 0x00Cx */
- /* case 0x0120: XXX (pciid) */
- nv_wr32(priv, 0x400828, 0x007596ff);
- nv_wr32(priv, 0x40082c, 0x00000108);
- break;
- case 0x43:
- nv_wr32(priv, 0x400828, 0x0072cb77);
- nv_wr32(priv, 0x40082c, 0x00000108);
- break;
- case 0x44:
- case 0x46: /* G72 */
- case 0x4a:
- case 0x4c: /* G7x-based C51 */
- case 0x4e:
- nv_wr32(priv, 0x400860, 0);
- nv_wr32(priv, 0x400864, 0);
- break;
- case 0x47: /* G70 */
- case 0x49: /* G71 */
- case 0x4b: /* G73 */
- nv_wr32(priv, 0x400828, 0x07830610);
- nv_wr32(priv, 0x40082c, 0x0000016A);
- break;
- default:
- break;
- }
-
- nv_wr32(priv, 0x400b38, 0x2ffff800);
- nv_wr32(priv, 0x400b3c, 0x00006000);
-
- /* Tiling related stuff. */
- switch (nv_device(priv)->chipset) {
- case 0x44:
- case 0x4a:
- nv_wr32(priv, 0x400bc4, 0x1003d888);
- nv_wr32(priv, 0x400bbc, 0xb7a7b500);
- break;
- case 0x46:
- nv_wr32(priv, 0x400bc4, 0x0000e024);
- nv_wr32(priv, 0x400bbc, 0xb7a7b520);
- break;
- case 0x4c:
- case 0x4e:
- case 0x67:
- nv_wr32(priv, 0x400bc4, 0x1003d888);
- nv_wr32(priv, 0x400bbc, 0xb7a7b540);
- break;
- default:
- break;
- }
-
- /* Turn all the tiling regions off. */
- for (i = 0; i < pfb->tile.regions; i++)
- engine->tile_prog(engine, i);
-
- /* begin RAM config */
- vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
- switch (nv_device(priv)->chipset) {
- case 0x40:
- nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
- nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
- nv_wr32(priv, 0x400820, 0);
- nv_wr32(priv, 0x400824, 0);
- nv_wr32(priv, 0x400864, vramsz);
- nv_wr32(priv, 0x400868, vramsz);
- break;
- default:
- switch (nv_device(priv)->chipset) {
- case 0x41:
- case 0x42:
- case 0x43:
- case 0x45:
- case 0x4e:
- case 0x44:
- case 0x4a:
- nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
- break;
- default:
- nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
- break;
- }
- nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
- nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
- nv_wr32(priv, 0x400840, 0);
- nv_wr32(priv, 0x400844, 0);
- nv_wr32(priv, 0x4008A0, vramsz);
- nv_wr32(priv, 0x4008A4, vramsz);
- break;
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-nv40_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_graph_ctor,
- .dtor = _nouveau_graph_dtor,
- .init = nv40_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
deleted file mode 100644
index ad8209377529..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv40.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __NV40_GRAPH_H__
-#define __NV40_GRAPH_H__
-
-#include <core/device.h>
-#include <core/gpuobj.h>
-
-/* returns 1 if device is one of the nv4x using the 0x4497 object class,
- * helpful to determine a number of other hardware features
- */
-static inline int
-nv44_graph_class(void *priv)
-{
- struct nouveau_device *device = nv_device(priv);
-
- if ((device->chipset & 0xf0) == 0x60)
- return 1;
-
- return !(0x0baf & (1 << (device->chipset & 0x0f)));
-}
-
-int nv40_grctx_init(struct nouveau_device *, u32 *size);
-void nv40_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
deleted file mode 100644
index 38e0aa26f1cd..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.c
+++ /dev/null
@@ -1,1009 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "nv50.h"
-
-struct nv50_graph_priv {
- struct nouveau_graph base;
- spinlock_t lock;
- u32 size;
-};
-
-struct nv50_graph_chan {
- struct nouveau_graph_chan base;
-};
-
-static u64
-nv50_graph_units(struct nouveau_graph *graph)
-{
- struct nv50_graph_priv *priv = (void *)graph;
-
- return nv_rd32(priv, 0x1540);
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static int
-nv50_graph_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj *obj;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
- 16, 16, 0, &obj);
- *pobject = nv_object(obj);
- if (ret)
- return ret;
-
- nv_wo32(obj, 0x00, nv_mclass(obj));
- nv_wo32(obj, 0x04, 0x00000000);
- nv_wo32(obj, 0x08, 0x00000000);
- nv_wo32(obj, 0x0c, 0x00000000);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nv50_graph_ofuncs = {
- .ctor = nv50_graph_object_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv50_graph_sclass[] = {
- { 0x0030, &nv50_graph_ofuncs },
- { 0x502d, &nv50_graph_ofuncs },
- { 0x5039, &nv50_graph_ofuncs },
- { 0x5097, &nv50_graph_ofuncs },
- { 0x50c0, &nv50_graph_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nv84_graph_sclass[] = {
- { 0x0030, &nv50_graph_ofuncs },
- { 0x502d, &nv50_graph_ofuncs },
- { 0x5039, &nv50_graph_ofuncs },
- { 0x50c0, &nv50_graph_ofuncs },
- { 0x8297, &nv50_graph_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nva0_graph_sclass[] = {
- { 0x0030, &nv50_graph_ofuncs },
- { 0x502d, &nv50_graph_ofuncs },
- { 0x5039, &nv50_graph_ofuncs },
- { 0x50c0, &nv50_graph_ofuncs },
- { 0x8397, &nv50_graph_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nva3_graph_sclass[] = {
- { 0x0030, &nv50_graph_ofuncs },
- { 0x502d, &nv50_graph_ofuncs },
- { 0x5039, &nv50_graph_ofuncs },
- { 0x50c0, &nv50_graph_ofuncs },
- { 0x8597, &nv50_graph_ofuncs },
- { 0x85c0, &nv50_graph_ofuncs },
- {}
-};
-
-static struct nouveau_oclass
-nvaf_graph_sclass[] = {
- { 0x0030, &nv50_graph_ofuncs },
- { 0x502d, &nv50_graph_ofuncs },
- { 0x5039, &nv50_graph_ofuncs },
- { 0x50c0, &nv50_graph_ofuncs },
- { 0x85c0, &nv50_graph_ofuncs },
- { 0x8697, &nv50_graph_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-static int
-nv50_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_graph_priv *priv = (void *)engine;
- struct nv50_graph_chan *chan;
- int ret;
-
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
- priv->size, 0,
- NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan));
- return 0;
-}
-
-static struct nouveau_oclass
-nv50_graph_cclass = {
- .handle = NV_ENGCTX(GR, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_graph_context_ctor,
- .dtor = _nouveau_graph_context_dtor,
- .init = _nouveau_graph_context_init,
- .fini = _nouveau_graph_context_fini,
- .rd32 = _nouveau_graph_context_rd32,
- .wr32 = _nouveau_graph_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_bitfield nv50_pgraph_status[] = {
- { 0x00000001, "BUSY" }, /* set when any bit is set */
- { 0x00000002, "DISPATCH" },
- { 0x00000004, "UNK2" },
- { 0x00000008, "UNK3" },
- { 0x00000010, "UNK4" },
- { 0x00000020, "UNK5" },
- { 0x00000040, "M2MF" },
- { 0x00000080, "UNK7" },
- { 0x00000100, "CTXPROG" },
- { 0x00000200, "VFETCH" },
- { 0x00000400, "CCACHE_PREGEOM" },
- { 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
- { 0x00001000, "VCLIP" },
- { 0x00002000, "RATTR_APLANE" },
- { 0x00004000, "TRAST" },
- { 0x00008000, "CLIPID" },
- { 0x00010000, "ZCULL" },
- { 0x00020000, "ENG2D" },
- { 0x00040000, "RMASK" },
- { 0x00080000, "TPC_RAST" },
- { 0x00100000, "TPC_PROP" },
- { 0x00200000, "TPC_TEX" },
- { 0x00400000, "TPC_GEOM" },
- { 0x00800000, "TPC_MP" },
- { 0x01000000, "ROP" },
- {}
-};
-
-static const char *const nv50_pgraph_vstatus_0[] = {
- "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP",
- NULL
-};
-
-static const char *const nv50_pgraph_vstatus_1[] = {
- "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL
-};
-
-static const char *const nv50_pgraph_vstatus_2[] = {
- "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK",
- "ROP", NULL
-};
-
-static void nouveau_pgraph_vstatus_print(struct nv50_graph_priv *priv, int r,
- const char *const units[], u32 status)
-{
- int i;
-
- nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status);
-
- for (i = 0; units[i] && status; i++) {
- if ((status & 7) == 1)
- pr_cont(" %s", units[i]);
- status >>= 3;
- }
- if (status)
- pr_cont(" (invalid: 0x%x)", status);
- pr_cont("\n");
-}
-
-static int
-nv84_graph_tlb_flush(struct nouveau_engine *engine)
-{
- struct nouveau_timer *ptimer = nouveau_timer(engine);
- struct nv50_graph_priv *priv = (void *)engine;
- bool idle, timeout = false;
- unsigned long flags;
- u64 start;
- u32 tmp;
-
- spin_lock_irqsave(&priv->lock, flags);
- nv_mask(priv, 0x400500, 0x00000001, 0x00000000);
-
- start = ptimer->read(ptimer);
- do {
- idle = true;
-
- for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) {
- if ((tmp & 7) == 1)
- idle = false;
- }
-
- for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) {
- if ((tmp & 7) == 1)
- idle = false;
- }
-
- for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) {
- if ((tmp & 7) == 1)
- idle = false;
- }
- } while (!idle &&
- !(timeout = ptimer->read(ptimer) - start > 2000000000));
-
- if (timeout) {
- nv_error(priv, "PGRAPH TLB flush idle timeout fail\n");
-
- tmp = nv_rd32(priv, 0x400700);
- nv_error(priv, "PGRAPH_STATUS : 0x%08x", tmp);
- nouveau_bitfield_print(nv50_pgraph_status, tmp);
- pr_cont("\n");
-
- nouveau_pgraph_vstatus_print(priv, 0, nv50_pgraph_vstatus_0,
- nv_rd32(priv, 0x400380));
- nouveau_pgraph_vstatus_print(priv, 1, nv50_pgraph_vstatus_1,
- nv_rd32(priv, 0x400384));
- nouveau_pgraph_vstatus_print(priv, 2, nv50_pgraph_vstatus_2,
- nv_rd32(priv, 0x400388));
- }
-
-
- nv_wr32(priv, 0x100c80, 0x00000001);
- if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
- nv_error(priv, "vm flush timeout\n");
- nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
- spin_unlock_irqrestore(&priv->lock, flags);
- return timeout ? -EBUSY : 0;
-}
-
-static const struct nouveau_bitfield nv50_mp_exec_errors[] = {
- { 0x01, "STACK_UNDERFLOW" },
- { 0x02, "STACK_MISMATCH" },
- { 0x04, "QUADON_ACTIVE" },
- { 0x08, "TIMEOUT" },
- { 0x10, "INVALID_OPCODE" },
- { 0x20, "PM_OVERFLOW" },
- { 0x40, "BREAKPOINT" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_mpc_traps[] = {
- { 0x0000001, "LOCAL_LIMIT_READ" },
- { 0x0000010, "LOCAL_LIMIT_WRITE" },
- { 0x0000040, "STACK_LIMIT" },
- { 0x0000100, "GLOBAL_LIMIT_READ" },
- { 0x0001000, "GLOBAL_LIMIT_WRITE" },
- { 0x0010000, "MP0" },
- { 0x0020000, "MP1" },
- { 0x0040000, "GLOBAL_LIMIT_RED" },
- { 0x0400000, "GLOBAL_LIMIT_ATOM" },
- { 0x4000000, "MP2" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_tex_traps[] = {
- { 0x00000001, "" }, /* any bit set? */
- { 0x00000002, "FAULT" },
- { 0x00000004, "STORAGE_TYPE_MISMATCH" },
- { 0x00000008, "LINEAR_MISMATCH" },
- { 0x00000020, "WRONG_MEMTYPE" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_m2mf[] = {
- { 0x00000001, "NOTIFY" },
- { 0x00000002, "IN" },
- { 0x00000004, "OUT" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_vfetch[] = {
- { 0x00000001, "FAULT" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_strmout[] = {
- { 0x00000001, "FAULT" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_ccache[] = {
- { 0x00000001, "FAULT" },
- {}
-};
-
-/* There must be a *lot* of these. Will take some time to gather them up. */
-const struct nouveau_enum nv50_data_error_names[] = {
- { 0x00000003, "INVALID_OPERATION", NULL },
- { 0x00000004, "INVALID_VALUE", NULL },
- { 0x00000005, "INVALID_ENUM", NULL },
- { 0x00000008, "INVALID_OBJECT", NULL },
- { 0x00000009, "READ_ONLY_OBJECT", NULL },
- { 0x0000000a, "SUPERVISOR_OBJECT", NULL },
- { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL },
- { 0x0000000c, "INVALID_BITFIELD", NULL },
- { 0x0000000d, "BEGIN_END_ACTIVE", NULL },
- { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL },
- { 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL },
- { 0x00000010, "RT_DOUBLE_BIND", NULL },
- { 0x00000011, "RT_TYPES_MISMATCH", NULL },
- { 0x00000012, "RT_LINEAR_WITH_ZETA", NULL },
- { 0x00000015, "FP_TOO_FEW_REGS", NULL },
- { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL },
- { 0x00000017, "RT_LINEAR_WITH_MSAA", NULL },
- { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL },
- { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL },
- { 0x0000001a, "RT_INVALID_ALIGNMENT", NULL },
- { 0x0000001b, "SAMPLER_OVER_LIMIT", NULL },
- { 0x0000001c, "TEXTURE_OVER_LIMIT", NULL },
- { 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL },
- { 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
- { 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
- { 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
- { 0x00000024, "VP_ZERO_INPUTS", NULL },
- { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
- { 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
- { 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
- { 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL },
- { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL },
- { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL },
- { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL },
- { 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL },
- { 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL },
- { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL },
- { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL },
- { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL },
- { 0x00000046, "LAYER_ID_NEEDS_GP", NULL },
- { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL },
- { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL },
- {}
-};
-
-static const struct nouveau_bitfield nv50_graph_intr_name[] = {
- { 0x00000001, "NOTIFY" },
- { 0x00000002, "COMPUTE_QUERY" },
- { 0x00000010, "ILLEGAL_MTHD" },
- { 0x00000020, "ILLEGAL_CLASS" },
- { 0x00000040, "DOUBLE_NOTIFY" },
- { 0x00001000, "CONTEXT_SWITCH" },
- { 0x00010000, "BUFFER_NOTIFY" },
- { 0x00100000, "DATA_ERROR" },
- { 0x00200000, "TRAP" },
- { 0x01000000, "SINGLE_STEP" },
- {}
-};
-
-static const struct nouveau_bitfield nv50_graph_trap_prop[] = {
- { 0x00000004, "SURF_WIDTH_OVERRUN" },
- { 0x00000008, "SURF_HEIGHT_OVERRUN" },
- { 0x00000010, "DST2D_FAULT" },
- { 0x00000020, "ZETA_FAULT" },
- { 0x00000040, "RT_FAULT" },
- { 0x00000080, "CUDA_FAULT" },
- { 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" },
- { 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" },
- { 0x00000400, "RT_STORAGE_TYPE_MISMATCH" },
- { 0x00000800, "DST2D_LINEAR_MISMATCH" },
- { 0x00001000, "RT_LINEAR_MISMATCH" },
- {}
-};
-
-static void
-nv50_priv_prop_trap(struct nv50_graph_priv *priv,
- u32 ustatus_addr, u32 ustatus, u32 tp)
-{
- u32 e0c = nv_rd32(priv, ustatus_addr + 0x04);
- u32 e10 = nv_rd32(priv, ustatus_addr + 0x08);
- u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c);
- u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
- u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
- u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
- u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
-
- /* CUDA memory: l[], g[] or stack. */
- if (ustatus & 0x00000080) {
- if (e18 & 0x80000000) {
- /* g[] read fault? */
- nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n",
- tp, e14, e10 | ((e18 >> 24) & 0x1f));
- e18 &= ~0x1f000000;
- } else if (e18 & 0xc) {
- /* g[] write fault? */
- nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n",
- tp, e14, e10 | ((e18 >> 7) & 0x1f));
- e18 &= ~0x00000f80;
- } else {
- nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n",
- tp, e14, e10);
- }
- ustatus &= ~0x00000080;
- }
- if (ustatus) {
- nv_error(priv, "TRAP_PROP - TP %d -", tp);
- nouveau_bitfield_print(nv50_graph_trap_prop, ustatus);
- pr_cont(" - Address %02x%08x\n", e14, e10);
- }
- nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
- tp, e0c, e18, e1c, e20, e24);
-}
-
-static void
-nv50_priv_mp_trap(struct nv50_graph_priv *priv, int tpid, int display)
-{
- u32 units = nv_rd32(priv, 0x1540);
- u32 addr, mp10, status, pc, oplow, ophigh;
- int i;
- int mps = 0;
- for (i = 0; i < 4; i++) {
- if (!(units & 1 << (i+24)))
- continue;
- if (nv_device(priv)->chipset < 0xa0)
- addr = 0x408200 + (tpid << 12) + (i << 7);
- else
- addr = 0x408100 + (tpid << 11) + (i << 7);
- mp10 = nv_rd32(priv, addr + 0x10);
- status = nv_rd32(priv, addr + 0x14);
- if (!status)
- continue;
- if (display) {
- nv_rd32(priv, addr + 0x20);
- pc = nv_rd32(priv, addr + 0x24);
- oplow = nv_rd32(priv, addr + 0x70);
- ophigh = nv_rd32(priv, addr + 0x74);
- nv_error(priv, "TRAP_MP_EXEC - "
- "TP %d MP %d:", tpid, i);
- nouveau_bitfield_print(nv50_mp_exec_errors, status);
- pr_cont(" at %06x warp %d, opcode %08x %08x\n",
- pc&0xffffff, pc >> 24,
- oplow, ophigh);
- }
- nv_wr32(priv, addr + 0x10, mp10);
- nv_wr32(priv, addr + 0x14, 0);
- mps++;
- }
- if (!mps && display)
- nv_error(priv, "TRAP_MP_EXEC - TP %d: "
- "No MPs claiming errors?\n", tpid);
-}
-
-static void
-nv50_priv_tp_trap(struct nv50_graph_priv *priv, int type, u32 ustatus_old,
- u32 ustatus_new, int display, const char *name)
-{
- int tps = 0;
- u32 units = nv_rd32(priv, 0x1540);
- int i, r;
- u32 ustatus_addr, ustatus;
- for (i = 0; i < 16; i++) {
- if (!(units & (1 << i)))
- continue;
- if (nv_device(priv)->chipset < 0xa0)
- ustatus_addr = ustatus_old + (i << 12);
- else
- ustatus_addr = ustatus_new + (i << 11);
- ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff;
- if (!ustatus)
- continue;
- tps++;
- switch (type) {
- case 6: /* texture error... unknown for now */
- if (display) {
- nv_error(priv, "magic set %d:\n", i);
- for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
- nv_error(priv, "\t0x%08x: 0x%08x\n", r,
- nv_rd32(priv, r));
- if (ustatus) {
- nv_error(priv, "%s - TP%d:", name, i);
- nouveau_bitfield_print(nv50_tex_traps,
- ustatus);
- pr_cont("\n");
- ustatus = 0;
- }
- }
- break;
- case 7: /* MP error */
- if (ustatus & 0x04030000) {
- nv50_priv_mp_trap(priv, i, display);
- ustatus &= ~0x04030000;
- }
- if (ustatus && display) {
- nv_error(priv, "%s - TP%d:", name, i);
- nouveau_bitfield_print(nv50_mpc_traps, ustatus);
- pr_cont("\n");
- ustatus = 0;
- }
- break;
- case 8: /* PROP error */
- if (display)
- nv50_priv_prop_trap(
- priv, ustatus_addr, ustatus, i);
- ustatus = 0;
- break;
- }
- if (ustatus) {
- if (display)
- nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
- }
- nv_wr32(priv, ustatus_addr, 0xc0000000);
- }
-
- if (!tps && display)
- nv_warn(priv, "%s - No TPs claiming errors?\n", name);
-}
-
-static int
-nv50_graph_trap_handler(struct nv50_graph_priv *priv, u32 display,
- int chid, u64 inst, struct nouveau_object *engctx)
-{
- u32 status = nv_rd32(priv, 0x400108);
- u32 ustatus;
-
- if (!status && display) {
- nv_error(priv, "TRAP: no units reporting traps?\n");
- return 1;
- }
-
- /* DISPATCH: Relays commands to other units and handles NOTIFY,
- * COND, QUERY. If you get a trap from it, the command is still stuck
- * in DISPATCH and you need to do something about it. */
- if (status & 0x001) {
- ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff;
- if (!ustatus && display) {
- nv_error(priv, "TRAP_DISPATCH - no ustatus?\n");
- }
-
- nv_wr32(priv, 0x400500, 0x00000000);
-
- /* Known to be triggered by screwed up NOTIFY and COND... */
- if (ustatus & 0x00000001) {
- u32 addr = nv_rd32(priv, 0x400808);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00001ffc);
- u32 datal = nv_rd32(priv, 0x40080c);
- u32 datah = nv_rd32(priv, 0x400810);
- u32 class = nv_rd32(priv, 0x400814);
- u32 r848 = nv_rd32(priv, 0x400848);
-
- nv_error(priv, "TRAP DISPATCH_FAULT\n");
- if (display && (addr & 0x80000000)) {
- nv_error(priv,
- "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n",
- chid, inst,
- nouveau_client_name(engctx), subc,
- class, mthd, datah, datal, addr, r848);
- } else
- if (display) {
- nv_error(priv, "no stuck command?\n");
- }
-
- nv_wr32(priv, 0x400808, 0);
- nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3);
- nv_wr32(priv, 0x400848, 0);
- ustatus &= ~0x00000001;
- }
-
- if (ustatus & 0x00000002) {
- u32 addr = nv_rd32(priv, 0x40084c);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(priv, 0x40085c);
- u32 class = nv_rd32(priv, 0x400814);
-
- nv_error(priv, "TRAP DISPATCH_QUERY\n");
- if (display && (addr & 0x80000000)) {
- nv_error(priv,
- "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n",
- chid, inst,
- nouveau_client_name(engctx), subc,
- class, mthd, data, addr);
- } else
- if (display) {
- nv_error(priv, "no stuck command?\n");
- }
-
- nv_wr32(priv, 0x40084c, 0);
- ustatus &= ~0x00000002;
- }
-
- if (ustatus && display) {
- nv_error(priv, "TRAP_DISPATCH (unknown "
- "0x%08x)\n", ustatus);
- }
-
- nv_wr32(priv, 0x400804, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x001);
- status &= ~0x001;
- if (!status)
- return 0;
- }
-
- /* M2MF: Memory to memory copy engine. */
- if (status & 0x002) {
- u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff;
- if (display) {
- nv_error(priv, "TRAP_M2MF");
- nouveau_bitfield_print(nv50_graph_trap_m2mf, ustatus);
- pr_cont("\n");
- nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
- nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
- nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
-
- }
-
- /* No sane way found yet -- just reset the bugger. */
- nv_wr32(priv, 0x400040, 2);
- nv_wr32(priv, 0x400040, 0);
- nv_wr32(priv, 0x406800, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x002);
- status &= ~0x002;
- }
-
- /* VFETCH: Fetches data from vertex buffers. */
- if (status & 0x004) {
- u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff;
- if (display) {
- nv_error(priv, "TRAP_VFETCH");
- nouveau_bitfield_print(nv50_graph_trap_vfetch, ustatus);
- pr_cont("\n");
- nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
- nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
- nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
- }
-
- nv_wr32(priv, 0x400c04, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x004);
- status &= ~0x004;
- }
-
- /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
- if (status & 0x008) {
- ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff;
- if (display) {
- nv_error(priv, "TRAP_STRMOUT");
- nouveau_bitfield_print(nv50_graph_trap_strmout, ustatus);
- pr_cont("\n");
- nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
- nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
- nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
-
- }
-
- /* No sane way found yet -- just reset the bugger. */
- nv_wr32(priv, 0x400040, 0x80);
- nv_wr32(priv, 0x400040, 0);
- nv_wr32(priv, 0x401800, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x008);
- status &= ~0x008;
- }
-
- /* CCACHE: Handles code and c[] caches and fills them. */
- if (status & 0x010) {
- ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff;
- if (display) {
- nv_error(priv, "TRAP_CCACHE");
- nouveau_bitfield_print(nv50_graph_trap_ccache, ustatus);
- pr_cont("\n");
- nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
- " %08x %08x %08x\n",
- nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
- nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c),
- nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014),
- nv_rd32(priv, 0x40501c));
-
- }
-
- nv_wr32(priv, 0x405018, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x010);
- status &= ~0x010;
- }
-
- /* Unknown, not seen yet... 0x402000 is the only trap status reg
- * remaining, so try to handle it anyway. Perhaps related to that
- * unknown DMA slot on tesla? */
- if (status & 0x20) {
- ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff;
- if (display)
- nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus);
- nv_wr32(priv, 0x402000, 0xc0000000);
- /* no status modifiction on purpose */
- }
-
- /* TEXTURE: CUDA texturing units */
- if (status & 0x040) {
- nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display,
- "TRAP_TEXTURE");
- nv_wr32(priv, 0x400108, 0x040);
- status &= ~0x040;
- }
-
- /* MP: CUDA execution engines. */
- if (status & 0x080) {
- nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display,
- "TRAP_MP");
- nv_wr32(priv, 0x400108, 0x080);
- status &= ~0x080;
- }
-
- /* PROP: Handles TP-initiated uncached memory accesses:
- * l[], g[], stack, 2d surfaces, render targets. */
- if (status & 0x100) {
- nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
- "TRAP_PROP");
- nv_wr32(priv, 0x400108, 0x100);
- status &= ~0x100;
- }
-
- if (status) {
- if (display)
- nv_error(priv, "TRAP: unknown 0x%08x\n", status);
- nv_wr32(priv, 0x400108, status);
- }
-
- return 1;
-}
-
-static void
-nv50_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nouveau_handle *handle = NULL;
- struct nv50_graph_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, 0x400100);
- u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff;
- u32 addr = nv_rd32(priv, 0x400704);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00001ffc);
- u32 data = nv_rd32(priv, 0x400708);
- u32 class = nv_rd32(priv, 0x400814);
- u32 show = stat, show_bitfield = stat;
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & 0x00000010) {
- handle = nouveau_handle_get_class(engctx, class);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~0x00000010;
- nouveau_handle_put(handle);
- }
-
- if (show & 0x00100000) {
- u32 ecode = nv_rd32(priv, 0x400110);
- nv_error(priv, "DATA_ERROR ");
- nouveau_enum_print(nv50_data_error_names, ecode);
- pr_cont("\n");
- show_bitfield &= ~0x00100000;
- }
-
- if (stat & 0x00200000) {
- if (!nv50_graph_trap_handler(priv, show, chid, (u64)inst << 12,
- engctx))
- show &= ~0x00200000;
- show_bitfield &= ~0x00200000;
- }
-
- nv_wr32(priv, 0x400100, stat);
- nv_wr32(priv, 0x400500, 0x00010001);
-
- if (show) {
- show &= show_bitfield;
- if (show) {
- nv_error(priv, "%s", "");
- nouveau_bitfield_print(nv50_graph_intr_name, show);
- pr_cont("\n");
- }
- nv_error(priv,
- "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, (u64)inst << 12, nouveau_client_name(engctx),
- subc, class, mthd, data);
- }
-
- if (nv_rd32(priv, 0x400824) & (1 << 31))
- nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31));
-
- nouveau_engctx_put(engctx);
-}
-
-static int
-nv50_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_graph_priv *priv;
- int ret;
-
- ret = nouveau_graph_create(parent, engine, oclass, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00201000;
- nv_subdev(priv)->intr = nv50_graph_intr;
- nv_engine(priv)->cclass = &nv50_graph_cclass;
-
- priv->base.units = nv50_graph_units;
-
- switch (nv_device(priv)->chipset) {
- case 0x50:
- nv_engine(priv)->sclass = nv50_graph_sclass;
- break;
- case 0x84:
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0x98:
- nv_engine(priv)->sclass = nv84_graph_sclass;
- break;
- case 0xa0:
- case 0xaa:
- case 0xac:
- nv_engine(priv)->sclass = nva0_graph_sclass;
- break;
- case 0xa3:
- case 0xa5:
- case 0xa8:
- nv_engine(priv)->sclass = nva3_graph_sclass;
- break;
- case 0xaf:
- nv_engine(priv)->sclass = nvaf_graph_sclass;
- break;
-
- }
-
- /* unfortunate hw bug workaround... */
- if (nv_device(priv)->chipset != 0x50 &&
- nv_device(priv)->chipset != 0xac)
- nv_engine(priv)->tlb_flush = nv84_graph_tlb_flush;
-
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-static int
-nv50_graph_init(struct nouveau_object *object)
-{
- struct nv50_graph_priv *priv = (void *)object;
- int ret, units, i;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
- nv_wr32(priv, 0x40008c, 0x00000004);
-
- /* reset/enable traps and interrupts */
- nv_wr32(priv, 0x400804, 0xc0000000);
- nv_wr32(priv, 0x406800, 0xc0000000);
- nv_wr32(priv, 0x400c04, 0xc0000000);
- nv_wr32(priv, 0x401800, 0xc0000000);
- nv_wr32(priv, 0x405018, 0xc0000000);
- nv_wr32(priv, 0x402000, 0xc0000000);
-
- units = nv_rd32(priv, 0x001540);
- for (i = 0; i < 16; i++) {
- if (!(units & (1 << i)))
- continue;
-
- if (nv_device(priv)->chipset < 0xa0) {
- nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000);
- nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000);
- nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000);
- } else {
- nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000);
- nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000);
- nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000);
- }
- }
-
- nv_wr32(priv, 0x400108, 0xffffffff);
- nv_wr32(priv, 0x400138, 0xffffffff);
- nv_wr32(priv, 0x400100, 0xffffffff);
- nv_wr32(priv, 0x40013c, 0xffffffff);
- nv_wr32(priv, 0x400500, 0x00010001);
-
- /* upload context program, initialise ctxctl defaults */
- ret = nv50_grctx_init(nv_device(priv), &priv->size);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x400824, 0x00000000);
- nv_wr32(priv, 0x400828, 0x00000000);
- nv_wr32(priv, 0x40082c, 0x00000000);
- nv_wr32(priv, 0x400830, 0x00000000);
- nv_wr32(priv, 0x40032c, 0x00000000);
- nv_wr32(priv, 0x400330, 0x00000000);
-
- /* some unknown zcull magic */
- switch (nv_device(priv)->chipset & 0xf0) {
- case 0x50:
- case 0x80:
- case 0x90:
- nv_wr32(priv, 0x402ca8, 0x00000800);
- break;
- case 0xa0:
- default:
- if (nv_device(priv)->chipset == 0xa0 ||
- nv_device(priv)->chipset == 0xaa ||
- nv_device(priv)->chipset == 0xac) {
- nv_wr32(priv, 0x402ca8, 0x00000802);
- } else {
- nv_wr32(priv, 0x402cc0, 0x00000000);
- nv_wr32(priv, 0x402ca8, 0x00000002);
- }
-
- break;
- }
-
- /* zero out zcull regions */
- for (i = 0; i < 8; i++) {
- nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000);
- nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000);
- nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000);
- nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000);
- }
- return 0;
-}
-
-struct nouveau_oclass
-nv50_graph_oclass = {
- .handle = NV_ENGINE(GR, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_graph_ctor,
- .dtor = _nouveau_graph_dtor,
- .init = nv50_graph_init,
- .fini = _nouveau_graph_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h b/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
deleted file mode 100644
index 0505fb419bde..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nv50.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __NV50_GRAPH_H__
-#define __NV50_GRAPH_H__
-
-int nv50_grctx_init(struct nouveau_device *, u32 *size);
-void nv50_grctx_fill(struct nouveau_device *, struct nouveau_gpuobj *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
deleted file mode 100644
index 17251e4b9e86..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.c
+++ /dev/null
@@ -1,1667 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Zero Bandwidth Clear
- ******************************************************************************/
-
-static void
-nvc0_graph_zbc_clear_color(struct nvc0_graph_priv *priv, int zbc)
-{
- if (priv->zbc_color[zbc].format) {
- nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]);
- nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]);
- nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]);
- nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]);
- }
- nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format);
- nv_wr32(priv, 0x405820, zbc);
- nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */
-}
-
-static int
-nvc0_graph_zbc_color_get(struct nvc0_graph_priv *priv, int format,
- const u32 ds[4], const u32 l2[4])
-{
- struct nouveau_ltc *ltc = nouveau_ltc(priv);
- int zbc = -ENOSPC, i;
-
- for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
- if (priv->zbc_color[i].format) {
- if (priv->zbc_color[i].format != format)
- continue;
- if (memcmp(priv->zbc_color[i].ds, ds, sizeof(
- priv->zbc_color[i].ds)))
- continue;
- if (memcmp(priv->zbc_color[i].l2, l2, sizeof(
- priv->zbc_color[i].l2))) {
- WARN_ON(1);
- return -EINVAL;
- }
- return i;
- } else {
- zbc = (zbc < 0) ? i : zbc;
- }
- }
-
- if (zbc < 0)
- return zbc;
-
- memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds));
- memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2));
- priv->zbc_color[zbc].format = format;
- ltc->zbc_color_get(ltc, zbc, l2);
- nvc0_graph_zbc_clear_color(priv, zbc);
- return zbc;
-}
-
-static void
-nvc0_graph_zbc_clear_depth(struct nvc0_graph_priv *priv, int zbc)
-{
- if (priv->zbc_depth[zbc].format)
- nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds);
- nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format);
- nv_wr32(priv, 0x405820, zbc);
- nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */
-}
-
-static int
-nvc0_graph_zbc_depth_get(struct nvc0_graph_priv *priv, int format,
- const u32 ds, const u32 l2)
-{
- struct nouveau_ltc *ltc = nouveau_ltc(priv);
- int zbc = -ENOSPC, i;
-
- for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
- if (priv->zbc_depth[i].format) {
- if (priv->zbc_depth[i].format != format)
- continue;
- if (priv->zbc_depth[i].ds != ds)
- continue;
- if (priv->zbc_depth[i].l2 != l2) {
- WARN_ON(1);
- return -EINVAL;
- }
- return i;
- } else {
- zbc = (zbc < 0) ? i : zbc;
- }
- }
-
- if (zbc < 0)
- return zbc;
-
- priv->zbc_depth[zbc].format = format;
- priv->zbc_depth[zbc].ds = ds;
- priv->zbc_depth[zbc].l2 = l2;
- ltc->zbc_depth_get(ltc, zbc, l2);
- nvc0_graph_zbc_clear_depth(priv, zbc);
- return zbc;
-}
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static int
-nvc0_fermi_mthd_zbc_color(struct nouveau_object *object, void *data, u32 size)
-{
- struct nvc0_graph_priv *priv = (void *)object->engine;
- union {
- struct fermi_a_zbc_color_v0 v0;
- } *args = data;
- int ret;
-
- if (nvif_unpack(args->v0, 0, 0, false)) {
- switch (args->v0.format) {
- case FERMI_A_ZBC_COLOR_V0_FMT_ZERO:
- case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE:
- case FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32:
- case FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16:
- case FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16:
- case FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16:
- case FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16:
- case FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16:
- case FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8:
- case FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8:
- case FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10:
- case FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10:
- case FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8:
- case FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8:
- case FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8:
- case FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8:
- case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8:
- case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10:
- case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11:
- ret = nvc0_graph_zbc_color_get(priv, args->v0.format,
- args->v0.ds,
- args->v0.l2);
- if (ret >= 0) {
- args->v0.index = ret;
- return 0;
- }
- break;
- default:
- return -EINVAL;
- }
- }
-
- return ret;
-}
-
-static int
-nvc0_fermi_mthd_zbc_depth(struct nouveau_object *object, void *data, u32 size)
-{
- struct nvc0_graph_priv *priv = (void *)object->engine;
- union {
- struct fermi_a_zbc_depth_v0 v0;
- } *args = data;
- int ret;
-
- if (nvif_unpack(args->v0, 0, 0, false)) {
- switch (args->v0.format) {
- case FERMI_A_ZBC_DEPTH_V0_FMT_FP32:
- ret = nvc0_graph_zbc_depth_get(priv, args->v0.format,
- args->v0.ds,
- args->v0.l2);
- return (ret >= 0) ? 0 : -ENOSPC;
- default:
- return -EINVAL;
- }
- }
-
- return ret;
-}
-
-static int
-nvc0_fermi_mthd(struct nouveau_object *object, u32 mthd, void *data, u32 size)
-{
- switch (mthd) {
- case FERMI_A_ZBC_COLOR:
- return nvc0_fermi_mthd_zbc_color(object, data, size);
- case FERMI_A_ZBC_DEPTH:
- return nvc0_fermi_mthd_zbc_depth(object, data, size);
- default:
- break;
- }
- return -EINVAL;
-}
-
-struct nouveau_ofuncs
-nvc0_fermi_ofuncs = {
- .ctor = _nouveau_object_ctor,
- .dtor = nouveau_object_destroy,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- .mthd = nvc0_fermi_mthd,
-};
-
-static int
-nvc0_graph_set_shader_exceptions(struct nouveau_object *object, u32 mthd,
- void *pdata, u32 size)
-{
- struct nvc0_graph_priv *priv = (void *)nv_engine(object);
- if (size >= sizeof(u32)) {
- u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000;
- nv_wr32(priv, 0x419e44, data);
- nv_wr32(priv, 0x419e4c, data);
- return 0;
- }
- return -EINVAL;
-}
-
-struct nouveau_omthds
-nvc0_graph_9097_omthds[] = {
- { 0x1528, 0x1528, nvc0_graph_set_shader_exceptions },
- {}
-};
-
-struct nouveau_omthds
-nvc0_graph_90c0_omthds[] = {
- { 0x1528, 0x1528, nvc0_graph_set_shader_exceptions },
- {}
-};
-
-struct nouveau_oclass
-nvc0_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0x9039, &nouveau_object_ofuncs },
- { FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH context
- ******************************************************************************/
-
-int
-nvc0_graph_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *args, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_vm *vm = nouveau_client(parent)->vm;
- struct nvc0_graph_priv *priv = (void *)engine;
- struct nvc0_graph_data *data = priv->mmio_data;
- struct nvc0_graph_mmio *mmio = priv->mmio_list;
- struct nvc0_graph_chan *chan;
- int ret, i;
-
- /* allocate memory for context, and fill with default values */
- ret = nouveau_graph_context_create(parent, engine, oclass, NULL,
- priv->size, 0x100,
- NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- /* allocate memory for a "mmio list" buffer that's used by the HUB
- * fuc to modify some per-context register settings on first load
- * of the context.
- */
- ret = nouveau_gpuobj_new(nv_object(chan), NULL, 0x1000, 0x100, 0,
- &chan->mmio);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm,
- NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
- &chan->mmio_vma);
- if (ret)
- return ret;
-
- /* allocate buffers referenced by mmio list */
- for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) {
- ret = nouveau_gpuobj_new(nv_object(chan), NULL, data->size,
- data->align, 0, &chan->data[i].mem);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_map_vm(chan->data[i].mem, vm, data->access,
- &chan->data[i].vma);
- if (ret)
- return ret;
-
- data++;
- }
-
- /* finally, fill in the mmio list and point the context at it */
- for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) {
- u32 addr = mmio->addr;
- u32 data = mmio->data;
-
- if (mmio->buffer >= 0) {
- u64 info = chan->data[mmio->buffer].vma.offset;
- data |= info >> mmio->shift;
- }
-
- nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
- nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
- mmio++;
- }
-
- for (i = 0; i < priv->size; i += 4)
- nv_wo32(chan, i, priv->data[i / 4]);
-
- if (!priv->firmware) {
- nv_wo32(chan, 0x00, chan->mmio_nr / 2);
- nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8);
- } else {
- nv_wo32(chan, 0xf4, 0);
- nv_wo32(chan, 0xf8, 0);
- nv_wo32(chan, 0x10, chan->mmio_nr / 2);
- nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset));
- nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset));
- nv_wo32(chan, 0x1c, 1);
- nv_wo32(chan, 0x20, 0);
- nv_wo32(chan, 0x28, 0);
- nv_wo32(chan, 0x2c, 0);
- }
-
- return 0;
-}
-
-void
-nvc0_graph_context_dtor(struct nouveau_object *object)
-{
- struct nvc0_graph_chan *chan = (void *)object;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
- nouveau_gpuobj_unmap(&chan->data[i].vma);
- nouveau_gpuobj_ref(NULL, &chan->data[i].mem);
- }
-
- nouveau_gpuobj_unmap(&chan->mmio_vma);
- nouveau_gpuobj_ref(NULL, &chan->mmio);
-
- nouveau_graph_context_destroy(&chan->base);
-}
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc0_graph_init_main_0[] = {
- { 0x400080, 1, 0x04, 0x003083c2 },
- { 0x400088, 1, 0x04, 0x00006fe7 },
- { 0x40008c, 1, 0x04, 0x00000000 },
- { 0x400090, 1, 0x04, 0x00000030 },
- { 0x40013c, 1, 0x04, 0x013901f7 },
- { 0x400140, 1, 0x04, 0x00000100 },
- { 0x400144, 1, 0x04, 0x00000000 },
- { 0x400148, 1, 0x04, 0x00000110 },
- { 0x400138, 1, 0x04, 0x00000000 },
- { 0x400130, 2, 0x04, 0x00000000 },
- { 0x400124, 1, 0x04, 0x00000002 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_fe_0[] = {
- { 0x40415c, 1, 0x04, 0x00000000 },
- { 0x404170, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pri_0[] = {
- { 0x404488, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_rstr2d_0[] = {
- { 0x407808, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pd_0[] = {
- { 0x406024, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405908, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_scc_0[] = {
- { 0x40803c, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_prop_0[] = {
- { 0x4184a0, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gpc_unk_0[] = {
- { 0x418604, 1, 0x04, 0x00000000 },
- { 0x418680, 1, 0x04, 0x00000000 },
- { 0x418714, 1, 0x04, 0x80000000 },
- { 0x418384, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_setup_0[] = {
- { 0x418814, 3, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_crstr_0[] = {
- { 0x418b04, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_setup_1[] = {
- { 0x4188c8, 1, 0x04, 0x80000000 },
- { 0x4188cc, 1, 0x04, 0x00000000 },
- { 0x4188d0, 1, 0x04, 0x00010000 },
- { 0x4188d4, 1, 0x04, 0x00000001 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_zcull_0[] = {
- { 0x418910, 1, 0x04, 0x00010001 },
- { 0x418914, 1, 0x04, 0x00000301 },
- { 0x418918, 1, 0x04, 0x00800000 },
- { 0x418980, 1, 0x04, 0x77777770 },
- { 0x418984, 3, 0x04, 0x77777777 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gpm_0[] = {
- { 0x418c04, 1, 0x04, 0x00000000 },
- { 0x418c88, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gpc_unk_1[] = {
- { 0x418d00, 1, 0x04, 0x00000000 },
- { 0x418f08, 1, 0x04, 0x00000000 },
- { 0x418e00, 1, 0x04, 0x00000050 },
- { 0x418e08, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_gcc_0[] = {
- { 0x41900c, 1, 0x04, 0x00000000 },
- { 0x419018, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_tpccs_0[] = {
- { 0x419d08, 2, 0x04, 0x00000000 },
- { 0x419d10, 1, 0x04, 0x00000014 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_tex_0[] = {
- { 0x419ab0, 1, 0x04, 0x00000000 },
- { 0x419ab8, 1, 0x04, 0x000000e7 },
- { 0x419abc, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pe_0[] = {
- { 0x41980c, 3, 0x04, 0x00000000 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x41984c, 1, 0x04, 0x00005bc5 },
- { 0x419850, 4, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_l1c_0[] = {
- { 0x419c98, 1, 0x04, 0x00000000 },
- { 0x419ca8, 1, 0x04, 0x80000000 },
- { 0x419cb4, 1, 0x04, 0x00000000 },
- { 0x419cb8, 1, 0x04, 0x00008bf4 },
- { 0x419cbc, 1, 0x04, 0x28137606 },
- { 0x419cc0, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_wwdx_0[] = {
- { 0x419bd4, 1, 0x04, 0x00800000 },
- { 0x419bdc, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_tpccs_1[] = {
- { 0x419d2c, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_mpc_0[] = {
- { 0x419c0c, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc0_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000000 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x00001100 },
- { 0x419eac, 1, 0x04, 0x11100702 },
- { 0x419eb0, 1, 0x04, 0x00000003 },
- { 0x419eb4, 4, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x06060618 },
- { 0x419ed0, 1, 0x04, 0x0eff0e38 },
- { 0x419ed4, 1, 0x04, 0x011104f1 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419f2c, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_be_0[] = {
- { 0x40880c, 1, 0x04, 0x00000000 },
- { 0x408910, 9, 0x04, 0x00000000 },
- { 0x408950, 1, 0x04, 0x00000000 },
- { 0x408954, 1, 0x04, 0x0000ffff },
- { 0x408984, 1, 0x04, 0x00000000 },
- { 0x408988, 1, 0x04, 0x08040201 },
- { 0x40898c, 1, 0x04, 0x80402010 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_fe_1[] = {
- { 0x4040f0, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc0_graph_init_pe_1[] = {
- { 0x419880, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc0_graph_pack_mmio[] = {
- { nvc0_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvc0_graph_init_pd_0 },
- { nvc0_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvc0_graph_init_prop_0 },
- { nvc0_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc0_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvc0_graph_init_gpm_0 },
- { nvc0_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nvc0_graph_init_tpccs_0 },
- { nvc0_graph_init_tex_0 },
- { nvc0_graph_init_pe_0 },
- { nvc0_graph_init_l1c_0 },
- { nvc0_graph_init_wwdx_0 },
- { nvc0_graph_init_tpccs_1 },
- { nvc0_graph_init_mpc_0 },
- { nvc0_graph_init_sm_0 },
- { nvc0_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- { nvc0_graph_init_pe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-void
-nvc0_graph_zbc_init(struct nvc0_graph_priv *priv)
-{
- const u32 zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
- const u32 one[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
- 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
- const u32 f32_0[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
- 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
- const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
- 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
- struct nouveau_ltc *ltc = nouveau_ltc(priv);
- int index;
-
- if (!priv->zbc_color[0].format) {
- nvc0_graph_zbc_color_get(priv, 1, & zero[0], &zero[4]);
- nvc0_graph_zbc_color_get(priv, 2, & one[0], &one[4]);
- nvc0_graph_zbc_color_get(priv, 4, &f32_0[0], &f32_0[4]);
- nvc0_graph_zbc_color_get(priv, 4, &f32_1[0], &f32_1[4]);
- nvc0_graph_zbc_depth_get(priv, 1, 0x00000000, 0x00000000);
- nvc0_graph_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000);
- }
-
- for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
- nvc0_graph_zbc_clear_color(priv, index);
- for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
- nvc0_graph_zbc_clear_depth(priv, index);
-}
-
-void
-nvc0_graph_mmio(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
-{
- const struct nvc0_graph_pack *pack;
- const struct nvc0_graph_init *init;
-
- pack_for_each_init(init, pack, p) {
- u32 next = init->addr + init->count * init->pitch;
- u32 addr = init->addr;
- while (addr < next) {
- nv_wr32(priv, addr, init->data);
- addr += init->pitch;
- }
- }
-}
-
-void
-nvc0_graph_icmd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
-{
- const struct nvc0_graph_pack *pack;
- const struct nvc0_graph_init *init;
- u32 data = 0;
-
- nv_wr32(priv, 0x400208, 0x80000000);
-
- pack_for_each_init(init, pack, p) {
- u32 next = init->addr + init->count * init->pitch;
- u32 addr = init->addr;
-
- if ((pack == p && init == p->init) || data != init->data) {
- nv_wr32(priv, 0x400204, init->data);
- data = init->data;
- }
-
- while (addr < next) {
- nv_wr32(priv, 0x400200, addr);
- nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
- addr += init->pitch;
- }
- }
-
- nv_wr32(priv, 0x400208, 0x00000000);
-}
-
-void
-nvc0_graph_mthd(struct nvc0_graph_priv *priv, const struct nvc0_graph_pack *p)
-{
- const struct nvc0_graph_pack *pack;
- const struct nvc0_graph_init *init;
- u32 data = 0;
-
- pack_for_each_init(init, pack, p) {
- u32 ctrl = 0x80000000 | pack->type;
- u32 next = init->addr + init->count * init->pitch;
- u32 addr = init->addr;
-
- if ((pack == p && init == p->init) || data != init->data) {
- nv_wr32(priv, 0x40448c, init->data);
- data = init->data;
- }
-
- while (addr < next) {
- nv_wr32(priv, 0x404488, ctrl | (addr << 14));
- addr += init->pitch;
- }
- }
-}
-
-u64
-nvc0_graph_units(struct nouveau_graph *graph)
-{
- struct nvc0_graph_priv *priv = (void *)graph;
- u64 cfg;
-
- cfg = (u32)priv->gpc_nr;
- cfg |= (u32)priv->tpc_total << 8;
- cfg |= (u64)priv->rop_nr << 32;
-
- return cfg;
-}
-
-static const struct nouveau_enum nve0_sked_error[] = {
- { 7, "CONSTANT_BUFFER_SIZE" },
- { 9, "LOCAL_MEMORY_SIZE_POS" },
- { 10, "LOCAL_MEMORY_SIZE_NEG" },
- { 11, "WARP_CSTACK_SIZE" },
- { 12, "TOTAL_TEMP_SIZE" },
- { 13, "REGISTER_COUNT" },
- { 18, "TOTAL_THREADS" },
- { 20, "PROGRAM_OFFSET" },
- { 21, "SHARED_MEMORY_SIZE" },
- { 25, "SHARED_CONFIG_TOO_SMALL" },
- { 26, "TOTAL_REGISTER_COUNT" },
- {}
-};
-
-static const struct nouveau_enum nvc0_gpc_rop_error[] = {
- { 1, "RT_PITCH_OVERRUN" },
- { 4, "RT_WIDTH_OVERRUN" },
- { 5, "RT_HEIGHT_OVERRUN" },
- { 7, "ZETA_STORAGE_TYPE_MISMATCH" },
- { 8, "RT_STORAGE_TYPE_MISMATCH" },
- { 10, "RT_LINEAR_MISMATCH" },
- {}
-};
-
-static void
-nvc0_graph_trap_gpc_rop(struct nvc0_graph_priv *priv, int gpc)
-{
- u32 trap[4];
- int i;
-
- trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
- trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
- trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
- trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
-
- nv_error(priv, "GPC%d/PROP trap:", gpc);
- for (i = 0; i <= 29; ++i) {
- if (!(trap[0] & (1 << i)))
- continue;
- pr_cont(" ");
- nouveau_enum_print(nvc0_gpc_rop_error, i);
- }
- pr_cont("\n");
-
- nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n",
- trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f,
- trap[3] & 0xff);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
-}
-
-static const struct nouveau_enum nvc0_mp_warp_error[] = {
- { 0x00, "NO_ERROR" },
- { 0x01, "STACK_MISMATCH" },
- { 0x05, "MISALIGNED_PC" },
- { 0x08, "MISALIGNED_GPR" },
- { 0x09, "INVALID_OPCODE" },
- { 0x0d, "GPR_OUT_OF_BOUNDS" },
- { 0x0e, "MEM_OUT_OF_BOUNDS" },
- { 0x0f, "UNALIGNED_MEM_ACCESS" },
- { 0x11, "INVALID_PARAM" },
- {}
-};
-
-static const struct nouveau_bitfield nvc0_mp_global_error[] = {
- { 0x00000004, "MULTIPLE_WARP_ERRORS" },
- { 0x00000008, "OUT_OF_STACK_SPACE" },
- {}
-};
-
-static void
-nvc0_graph_trap_mp(struct nvc0_graph_priv *priv, int gpc, int tpc)
-{
- u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648));
- u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650));
-
- nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc);
- nouveau_bitfield_print(nvc0_mp_global_error, gerr);
- if (werr) {
- pr_cont(" ");
- nouveau_enum_print(nvc0_mp_warp_error, werr & 0xffff);
- }
- pr_cont("\n");
-
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr);
-}
-
-static void
-nvc0_graph_trap_tpc(struct nvc0_graph_priv *priv, int gpc, int tpc)
-{
- u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508));
-
- if (stat & 0x00000001) {
- u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224));
- nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000);
- stat &= ~0x00000001;
- }
-
- if (stat & 0x00000002) {
- nvc0_graph_trap_mp(priv, gpc, tpc);
- stat &= ~0x00000002;
- }
-
- if (stat & 0x00000004) {
- u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084));
- nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000);
- stat &= ~0x00000004;
- }
-
- if (stat & 0x00000008) {
- u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c));
- nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000);
- stat &= ~0x00000008;
- }
-
- if (stat) {
- nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat);
- }
-}
-
-static void
-nvc0_graph_trap_gpc(struct nvc0_graph_priv *priv, int gpc)
-{
- u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90));
- int tpc;
-
- if (stat & 0x00000001) {
- nvc0_graph_trap_gpc_rop(priv, gpc);
- stat &= ~0x00000001;
- }
-
- if (stat & 0x00000002) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
- nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- stat &= ~0x00000002;
- }
-
- if (stat & 0x00000004) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
- nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- stat &= ~0x00000004;
- }
-
- if (stat & 0x00000008) {
- u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
- nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- stat &= ~0x00000009;
- }
-
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- u32 mask = 0x00010000 << tpc;
- if (stat & mask) {
- nvc0_graph_trap_tpc(priv, gpc, tpc);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask);
- stat &= ~mask;
- }
- }
-
- if (stat) {
- nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat);
- }
-}
-
-static void
-nvc0_graph_trap_intr(struct nvc0_graph_priv *priv)
-{
- u32 trap = nv_rd32(priv, 0x400108);
- int rop, gpc, i;
-
- if (trap & 0x00000001) {
- u32 stat = nv_rd32(priv, 0x404000);
- nv_error(priv, "DISPATCH 0x%08x\n", stat);
- nv_wr32(priv, 0x404000, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000001);
- trap &= ~0x00000001;
- }
-
- if (trap & 0x00000002) {
- u32 stat = nv_rd32(priv, 0x404600);
- nv_error(priv, "M2MF 0x%08x\n", stat);
- nv_wr32(priv, 0x404600, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000002);
- trap &= ~0x00000002;
- }
-
- if (trap & 0x00000008) {
- u32 stat = nv_rd32(priv, 0x408030);
- nv_error(priv, "CCACHE 0x%08x\n", stat);
- nv_wr32(priv, 0x408030, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000008);
- trap &= ~0x00000008;
- }
-
- if (trap & 0x00000010) {
- u32 stat = nv_rd32(priv, 0x405840);
- nv_error(priv, "SHADER 0x%08x\n", stat);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000010);
- trap &= ~0x00000010;
- }
-
- if (trap & 0x00000040) {
- u32 stat = nv_rd32(priv, 0x40601c);
- nv_error(priv, "UNK6 0x%08x\n", stat);
- nv_wr32(priv, 0x40601c, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000040);
- trap &= ~0x00000040;
- }
-
- if (trap & 0x00000080) {
- u32 stat = nv_rd32(priv, 0x404490);
- nv_error(priv, "MACRO 0x%08x\n", stat);
- nv_wr32(priv, 0x404490, 0xc0000000);
- nv_wr32(priv, 0x400108, 0x00000080);
- trap &= ~0x00000080;
- }
-
- if (trap & 0x00000100) {
- u32 stat = nv_rd32(priv, 0x407020);
-
- nv_error(priv, "SKED:");
- for (i = 0; i <= 29; ++i) {
- if (!(stat & (1 << i)))
- continue;
- pr_cont(" ");
- nouveau_enum_print(nve0_sked_error, i);
- }
- pr_cont("\n");
-
- if (stat & 0x3fffffff)
- nv_wr32(priv, 0x407020, 0x40000000);
- nv_wr32(priv, 0x400108, 0x00000100);
- trap &= ~0x00000100;
- }
-
- if (trap & 0x01000000) {
- u32 stat = nv_rd32(priv, 0x400118);
- for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) {
- u32 mask = 0x00000001 << gpc;
- if (stat & mask) {
- nvc0_graph_trap_gpc(priv, gpc);
- nv_wr32(priv, 0x400118, mask);
- stat &= ~mask;
- }
- }
- nv_wr32(priv, 0x400108, 0x01000000);
- trap &= ~0x01000000;
- }
-
- if (trap & 0x02000000) {
- for (rop = 0; rop < priv->rop_nr; rop++) {
- u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
- u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
- nv_error(priv, "ROP%d 0x%08x 0x%08x\n",
- rop, statz, statc);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
- }
- nv_wr32(priv, 0x400108, 0x02000000);
- trap &= ~0x02000000;
- }
-
- if (trap) {
- nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap);
- nv_wr32(priv, 0x400108, trap);
- }
-}
-
-static void
-nvc0_graph_ctxctl_debug_unit(struct nvc0_graph_priv *priv, u32 base)
-{
- nv_error(priv, "%06x - done 0x%08x\n", base,
- nv_rd32(priv, base + 0x400));
- nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
- nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
- nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
- nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
- nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
- nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
-}
-
-void
-nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *priv)
-{
- u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
- u32 gpc;
-
- nvc0_graph_ctxctl_debug_unit(priv, 0x409000);
- for (gpc = 0; gpc < gpcnr; gpc++)
- nvc0_graph_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
-}
-
-static void
-nvc0_graph_ctxctl_isr(struct nvc0_graph_priv *priv)
-{
- u32 stat = nv_rd32(priv, 0x409c18);
-
- if (stat & 0x00000001) {
- u32 code = nv_rd32(priv, 0x409814);
- if (code == E_BAD_FWMTHD) {
- u32 class = nv_rd32(priv, 0x409808);
- u32 addr = nv_rd32(priv, 0x40980c);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 mthd = (addr & 0x00003ffc);
- u32 data = nv_rd32(priv, 0x409810);
-
- nv_error(priv, "FECS MTHD subc %d class 0x%04x "
- "mthd 0x%04x data 0x%08x\n",
- subc, class, mthd, data);
-
- nv_wr32(priv, 0x409c20, 0x00000001);
- stat &= ~0x00000001;
- } else {
- nv_error(priv, "FECS ucode error %d\n", code);
- }
- }
-
- if (stat & 0x00080000) {
- nv_error(priv, "FECS watchdog timeout\n");
- nvc0_graph_ctxctl_debug(priv);
- nv_wr32(priv, 0x409c20, 0x00080000);
- stat &= ~0x00080000;
- }
-
- if (stat) {
- nv_error(priv, "FECS 0x%08x\n", stat);
- nvc0_graph_ctxctl_debug(priv);
- nv_wr32(priv, 0x409c20, stat);
- }
-}
-
-static void
-nvc0_graph_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nouveau_handle *handle;
- struct nvc0_graph_priv *priv = (void *)subdev;
- u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff;
- u32 stat = nv_rd32(priv, 0x400100);
- u32 addr = nv_rd32(priv, 0x400704);
- u32 mthd = (addr & 0x00003ffc);
- u32 subc = (addr & 0x00070000) >> 16;
- u32 data = nv_rd32(priv, 0x400708);
- u32 code = nv_rd32(priv, 0x400110);
- u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & 0x00000010) {
- handle = nouveau_handle_get_class(engctx, class);
- if (!handle || nv_call(handle->object, mthd, data)) {
- nv_error(priv,
- "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst << 12, nouveau_client_name(engctx),
- subc, class, mthd, data);
- }
- nouveau_handle_put(handle);
- nv_wr32(priv, 0x400100, 0x00000010);
- stat &= ~0x00000010;
- }
-
- if (stat & 0x00000020) {
- nv_error(priv,
- "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst << 12, nouveau_client_name(engctx), subc,
- class, mthd, data);
- nv_wr32(priv, 0x400100, 0x00000020);
- stat &= ~0x00000020;
- }
-
- if (stat & 0x00100000) {
- nv_error(priv, "DATA_ERROR [");
- nouveau_enum_print(nv50_data_error_names, code);
- pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
- chid, inst << 12, nouveau_client_name(engctx), subc,
- class, mthd, data);
- nv_wr32(priv, 0x400100, 0x00100000);
- stat &= ~0x00100000;
- }
-
- if (stat & 0x00200000) {
- nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12,
- nouveau_client_name(engctx));
- nvc0_graph_trap_intr(priv);
- nv_wr32(priv, 0x400100, 0x00200000);
- stat &= ~0x00200000;
- }
-
- if (stat & 0x00080000) {
- nvc0_graph_ctxctl_isr(priv);
- nv_wr32(priv, 0x400100, 0x00080000);
- stat &= ~0x00080000;
- }
-
- if (stat) {
- nv_error(priv, "unknown stat 0x%08x\n", stat);
- nv_wr32(priv, 0x400100, stat);
- }
-
- nv_wr32(priv, 0x400500, 0x00010001);
- nouveau_engctx_put(engctx);
-}
-
-void
-nvc0_graph_init_fw(struct nvc0_graph_priv *priv, u32 fuc_base,
- struct nvc0_graph_fuc *code, struct nvc0_graph_fuc *data)
-{
- int i;
-
- nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
- for (i = 0; i < data->size / 4; i++)
- nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
-
- nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
- for (i = 0; i < code->size / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wr32(priv, fuc_base + 0x0188, i >> 6);
- nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
- }
-
- /* code must be padded to 0x40 words */
- for (; i & 0x3f; i++)
- nv_wr32(priv, fuc_base + 0x0184, 0);
-}
-
-static void
-nvc0_graph_init_csdata(struct nvc0_graph_priv *priv,
- const struct nvc0_graph_pack *pack,
- u32 falcon, u32 starstar, u32 base)
-{
- const struct nvc0_graph_pack *iter;
- const struct nvc0_graph_init *init;
- u32 addr = ~0, prev = ~0, xfer = 0;
- u32 star, temp;
-
- nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
- star = nv_rd32(priv, falcon + 0x01c4);
- temp = nv_rd32(priv, falcon + 0x01c4);
- if (temp > star)
- star = temp;
- nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
-
- pack_for_each_init(init, iter, pack) {
- u32 head = init->addr - base;
- u32 tail = head + init->count * init->pitch;
- while (head < tail) {
- if (head != prev + 4 || xfer >= 32) {
- if (xfer) {
- u32 data = ((--xfer << 26) | addr);
- nv_wr32(priv, falcon + 0x01c4, data);
- star += 4;
- }
- addr = head;
- xfer = 0;
- }
- prev = head;
- xfer = xfer + 1;
- head = head + init->pitch;
- }
- }
-
- nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr);
- nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
- nv_wr32(priv, falcon + 0x01c4, star + 4);
-}
-
-int
-nvc0_graph_init_ctxctl(struct nvc0_graph_priv *priv)
-{
- struct nvc0_graph_oclass *oclass = (void *)nv_object(priv)->oclass;
- struct nvc0_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
- int i;
-
- if (priv->firmware) {
- /* load fuc microcode */
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
- nvc0_graph_init_fw(priv, 0x409000, &priv->fuc409c,
- &priv->fuc409d);
- nvc0_graph_init_fw(priv, 0x41a000, &priv->fuc41ac,
- &priv->fuc41ad);
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-
- /* start both of them running */
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x41a10c, 0x00000000);
- nv_wr32(priv, 0x40910c, 0x00000000);
- nv_wr32(priv, 0x41a100, 0x00000002);
- nv_wr32(priv, 0x409100, 0x00000002);
- if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
- nv_warn(priv, "0x409800 wait failed\n");
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x7fffffff);
- nv_wr32(priv, 0x409504, 0x00000021);
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x00000000);
- nv_wr32(priv, 0x409504, 0x00000010);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x10 timeout\n");
- return -EBUSY;
- }
- priv->size = nv_rd32(priv, 0x409800);
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x00000000);
- nv_wr32(priv, 0x409504, 0x00000016);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x16 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409840, 0xffffffff);
- nv_wr32(priv, 0x409500, 0x00000000);
- nv_wr32(priv, 0x409504, 0x00000025);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x25 timeout\n");
- return -EBUSY;
- }
-
- if (nv_device(priv)->chipset >= 0xe0) {
- nv_wr32(priv, 0x409800, 0x00000000);
- nv_wr32(priv, 0x409500, 0x00000001);
- nv_wr32(priv, 0x409504, 0x00000030);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x30 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409810, 0xb00095c8);
- nv_wr32(priv, 0x409800, 0x00000000);
- nv_wr32(priv, 0x409500, 0x00000001);
- nv_wr32(priv, 0x409504, 0x00000031);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x31 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409810, 0x00080420);
- nv_wr32(priv, 0x409800, 0x00000000);
- nv_wr32(priv, 0x409500, 0x00000001);
- nv_wr32(priv, 0x409504, 0x00000032);
- if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
- nv_error(priv, "fuc09 req 0x32 timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x409614, 0x00000070);
- nv_wr32(priv, 0x409614, 0x00000770);
- nv_wr32(priv, 0x40802c, 0x00000001);
- }
-
- if (priv->data == NULL) {
- int ret = nvc0_grctx_generate(priv);
- if (ret) {
- nv_error(priv, "failed to construct context\n");
- return ret;
- }
- }
-
- return 0;
- } else
- if (!oclass->fecs.ucode) {
- return -ENOSYS;
- }
-
- /* load HUB microcode */
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 0);
- nv_wr32(priv, 0x4091c0, 0x01000000);
- for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
- nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]);
-
- nv_wr32(priv, 0x409180, 0x01000000);
- for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wr32(priv, 0x409188, i >> 6);
- nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
- }
-
- /* load GPC microcode */
- nv_wr32(priv, 0x41a1c0, 0x01000000);
- for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
- nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
-
- nv_wr32(priv, 0x41a180, 0x01000000);
- for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wr32(priv, 0x41a188, i >> 6);
- nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]);
- }
- nouveau_mc(priv)->unk260(nouveau_mc(priv), 1);
-
- /* load register lists */
- nvc0_graph_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000);
- nvc0_graph_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000);
- nvc0_graph_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800);
- nvc0_graph_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00);
-
- /* start HUB ucode running, it'll init the GPCs */
- nv_wr32(priv, 0x40910c, 0x00000000);
- nv_wr32(priv, 0x409100, 0x00000002);
- if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
- nv_error(priv, "HUB_INIT timed out\n");
- nvc0_graph_ctxctl_debug(priv);
- return -EBUSY;
- }
-
- priv->size = nv_rd32(priv, 0x409804);
- if (priv->data == NULL) {
- int ret = nvc0_grctx_generate(priv);
- if (ret) {
- nv_error(priv, "failed to construct context\n");
- return ret;
- }
- }
-
- return 0;
-}
-
-int
-nvc0_graph_init(struct nouveau_object *object)
-{
- struct nvc0_graph_oclass *oclass = (void *)object->oclass;
- struct nvc0_graph_priv *priv = (void *)object;
- const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
- u32 data[TPC_MAX / 8] = {};
- u8 tpcnr[GPC_MAX];
- int gpc, tpc, rop;
- int ret, i;
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
- nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-
- nvc0_graph_mmio(priv, oclass->mmio);
-
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- data[i / 8] |= tpc << ((i % 8) * 4);
- }
-
- nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
- nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
- nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
- nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
- priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
- priv->tpc_total);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
- }
-
- if (nv_device(priv)->chipset != 0xd7)
- nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
- else
- nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
-
- nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-
- nv_wr32(priv, 0x400500, 0x00010001);
-
- nv_wr32(priv, 0x400100, 0xffffffff);
- nv_wr32(priv, 0x40013c, 0xffffffff);
-
- nv_wr32(priv, 0x409c24, 0x000f0000);
- nv_wr32(priv, 0x404000, 0xc0000000);
- nv_wr32(priv, 0x404600, 0xc0000000);
- nv_wr32(priv, 0x408030, 0xc0000000);
- nv_wr32(priv, 0x40601c, 0xc0000000);
- nv_wr32(priv, 0x404490, 0xc0000000);
- nv_wr32(priv, 0x406018, 0xc0000000);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x405844, 0x00ffffff);
- nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
- nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
- }
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
- }
-
- for (rop = 0; rop < priv->rop_nr; rop++) {
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
- nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
- }
-
- nv_wr32(priv, 0x400108, 0xffffffff);
- nv_wr32(priv, 0x400138, 0xffffffff);
- nv_wr32(priv, 0x400118, 0xffffffff);
- nv_wr32(priv, 0x400130, 0xffffffff);
- nv_wr32(priv, 0x40011c, 0xffffffff);
- nv_wr32(priv, 0x400134, 0xffffffff);
-
- nv_wr32(priv, 0x400054, 0x34ce3464);
-
- nvc0_graph_zbc_init(priv);
-
- return nvc0_graph_init_ctxctl(priv);
-}
-
-static void
-nvc0_graph_dtor_fw(struct nvc0_graph_fuc *fuc)
-{
- kfree(fuc->data);
- fuc->data = NULL;
-}
-
-int
-nvc0_graph_ctor_fw(struct nvc0_graph_priv *priv, const char *fwname,
- struct nvc0_graph_fuc *fuc)
-{
- struct nouveau_device *device = nv_device(priv);
- const struct firmware *fw;
- char f[32];
- int ret;
-
- snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
- ret = request_firmware(&fw, f, nv_device_base(device));
- if (ret) {
- snprintf(f, sizeof(f), "nouveau/%s", fwname);
- ret = request_firmware(&fw, f, nv_device_base(device));
- if (ret) {
- nv_error(priv, "failed to load %s\n", fwname);
- return ret;
- }
- }
-
- fuc->size = fw->size;
- fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
- release_firmware(fw);
- return (fuc->data != NULL) ? 0 : -ENOMEM;
-}
-
-void
-nvc0_graph_dtor(struct nouveau_object *object)
-{
- struct nvc0_graph_priv *priv = (void *)object;
-
- kfree(priv->data);
-
- nvc0_graph_dtor_fw(&priv->fuc409c);
- nvc0_graph_dtor_fw(&priv->fuc409d);
- nvc0_graph_dtor_fw(&priv->fuc41ac);
- nvc0_graph_dtor_fw(&priv->fuc41ad);
-
- nouveau_gpuobj_ref(NULL, &priv->unk4188b8);
- nouveau_gpuobj_ref(NULL, &priv->unk4188b4);
-
- nouveau_graph_destroy(&priv->base);
-}
-
-int
-nvc0_graph_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *bclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_graph_oclass *oclass = (void *)bclass;
- struct nouveau_device *device = nv_device(parent);
- struct nvc0_graph_priv *priv;
- bool use_ext_fw, enable;
- int ret, i, j;
-
- use_ext_fw = nouveau_boolopt(device->cfgopt, "NvGrUseFW",
- oclass->fecs.ucode == NULL);
- enable = use_ext_fw || oclass->fecs.ucode != NULL;
-
- ret = nouveau_graph_create(parent, engine, bclass, enable, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x08001000;
- nv_subdev(priv)->intr = nvc0_graph_intr;
-
- priv->base.units = nvc0_graph_units;
-
- if (use_ext_fw) {
- nv_info(priv, "using external firmware\n");
- if (nvc0_graph_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
- nvc0_graph_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
- nvc0_graph_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
- nvc0_graph_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
- return -ENODEV;
- priv->firmware = true;
- }
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
- &priv->unk4188b4);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
- &priv->unk4188b8);
- if (ret)
- return ret;
-
- for (i = 0; i < 0x1000; i += 4) {
- nv_wo32(priv->unk4188b4, i, 0x00000010);
- nv_wo32(priv->unk4188b8, i, 0x00000010);
- }
-
- priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
- priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f;
- for (i = 0; i < priv->gpc_nr; i++) {
- priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
- priv->tpc_total += priv->tpc_nr[i];
- priv->ppc_nr[i] = oclass->ppc_nr;
- for (j = 0; j < priv->ppc_nr[i]; j++) {
- u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4)));
- priv->ppc_tpc_nr[i][j] = hweight8(mask);
- }
- }
-
- /*XXX: these need figuring out... though it might not even matter */
- switch (nv_device(priv)->chipset) {
- case 0xc0:
- if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
- priv->magic_not_rop_nr = 0x07;
- } else
- if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
- priv->magic_not_rop_nr = 0x05;
- } else
- if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
- priv->magic_not_rop_nr = 0x06;
- }
- break;
- case 0xc3: /* 450, 4/0/0/0, 2 */
- priv->magic_not_rop_nr = 0x03;
- break;
- case 0xc4: /* 460, 3/4/0/0, 4 */
- priv->magic_not_rop_nr = 0x01;
- break;
- case 0xc1: /* 2/0/0/0, 1 */
- priv->magic_not_rop_nr = 0x01;
- break;
- case 0xc8: /* 4/4/3/4, 5 */
- priv->magic_not_rop_nr = 0x06;
- break;
- case 0xce: /* 4/4/0/0, 4 */
- priv->magic_not_rop_nr = 0x03;
- break;
- case 0xcf: /* 4/0/0/0, 3 */
- priv->magic_not_rop_nr = 0x03;
- break;
- case 0xd7:
- case 0xd9: /* 1/0/0/0, 1 */
- priv->magic_not_rop_nr = 0x01;
- break;
- }
-
- nv_engine(priv)->cclass = *oclass->cclass;
- nv_engine(priv)->sclass = oclass->sclass;
- return 0;
-}
-
-#include "fuc/hubnvc0.fuc.h"
-
-struct nvc0_graph_ucode
-nvc0_graph_fecs_ucode = {
- .code.data = nvc0_grhub_code,
- .code.size = sizeof(nvc0_grhub_code),
- .data.data = nvc0_grhub_data,
- .data.size = sizeof(nvc0_grhub_data),
-};
-
-#include "fuc/gpcnvc0.fuc.h"
-
-struct nvc0_graph_ucode
-nvc0_graph_gpccs_ucode = {
- .code.data = nvc0_grgpc_code,
- .code.size = sizeof(nvc0_grgpc_code),
- .data.data = nvc0_grgpc_data,
- .data.size = sizeof(nvc0_grgpc_data),
-};
-
-struct nouveau_oclass *
-nvc0_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nvc0_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nvc0_grctx_oclass,
- .sclass = nvc0_graph_sclass,
- .mmio = nvc0_graph_pack_mmio,
- .fecs.ucode = &nvc0_graph_fecs_ucode,
- .gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
deleted file mode 100644
index 7ed9e89c3435..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc0.h
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifndef __NVC0_GRAPH_H__
-#define __NVC0_GRAPH_H__
-
-#include <core/client.h>
-#include <core/handle.h>
-#include <core/gpuobj.h>
-#include <core/option.h>
-
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/timer.h>
-#include <subdev/mc.h>
-#include <subdev/ltc.h>
-
-#include <engine/fifo.h>
-#include <engine/graph.h>
-
-#include "fuc/os.h"
-
-#define GPC_MAX 32
-#define TPC_MAX (GPC_MAX * 8)
-
-#define ROP_BCAST(r) (0x408800 + (r))
-#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r))
-#define GPC_BCAST(r) (0x418000 + (r))
-#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r))
-#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r))
-#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
-
-struct nvc0_graph_data {
- u32 size;
- u32 align;
- u32 access;
-};
-
-struct nvc0_graph_mmio {
- u32 addr;
- u32 data;
- u32 shift;
- int buffer;
-};
-
-struct nvc0_graph_fuc {
- u32 *data;
- u32 size;
-};
-
-struct nvc0_graph_zbc_color {
- u32 format;
- u32 ds[4];
- u32 l2[4];
-};
-
-struct nvc0_graph_zbc_depth {
- u32 format;
- u32 ds;
- u32 l2;
-};
-
-struct nvc0_graph_priv {
- struct nouveau_graph base;
-
- struct nvc0_graph_fuc fuc409c;
- struct nvc0_graph_fuc fuc409d;
- struct nvc0_graph_fuc fuc41ac;
- struct nvc0_graph_fuc fuc41ad;
- bool firmware;
-
- struct nvc0_graph_zbc_color zbc_color[NOUVEAU_LTC_MAX_ZBC_CNT];
- struct nvc0_graph_zbc_depth zbc_depth[NOUVEAU_LTC_MAX_ZBC_CNT];
-
- u8 rop_nr;
- u8 gpc_nr;
- u8 tpc_nr[GPC_MAX];
- u8 tpc_total;
- u8 ppc_nr[GPC_MAX];
- u8 ppc_tpc_nr[GPC_MAX][4];
-
- struct nouveau_gpuobj *unk4188b4;
- struct nouveau_gpuobj *unk4188b8;
-
- struct nvc0_graph_data mmio_data[4];
- struct nvc0_graph_mmio mmio_list[4096/8];
- u32 size;
- u32 *data;
-
- u8 magic_not_rop_nr;
-};
-
-struct nvc0_graph_chan {
- struct nouveau_graph_chan base;
-
- struct nouveau_gpuobj *mmio;
- struct nouveau_vma mmio_vma;
- int mmio_nr;
- struct {
- struct nouveau_gpuobj *mem;
- struct nouveau_vma vma;
- } data[4];
-};
-
-int nvc0_graph_context_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nvc0_graph_context_dtor(struct nouveau_object *);
-
-void nvc0_graph_ctxctl_debug(struct nvc0_graph_priv *);
-
-u64 nvc0_graph_units(struct nouveau_graph *);
-int nvc0_graph_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *data, u32 size,
- struct nouveau_object **);
-void nvc0_graph_dtor(struct nouveau_object *);
-int nvc0_graph_init(struct nouveau_object *);
-void nvc0_graph_zbc_init(struct nvc0_graph_priv *);
-
-int nve4_graph_fini(struct nouveau_object *, bool);
-int nve4_graph_init(struct nouveau_object *);
-
-int nvf0_graph_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_ofuncs nvc0_fermi_ofuncs;
-
-extern struct nouveau_oclass nvc0_graph_sclass[];
-extern struct nouveau_omthds nvc0_graph_9097_omthds[];
-extern struct nouveau_omthds nvc0_graph_90c0_omthds[];
-extern struct nouveau_oclass nvc8_graph_sclass[];
-extern struct nouveau_oclass nvf0_graph_sclass[];
-
-struct nvc0_graph_init {
- u32 addr;
- u8 count;
- u8 pitch;
- u32 data;
-};
-
-struct nvc0_graph_pack {
- const struct nvc0_graph_init *init;
- u32 type;
-};
-
-#define pack_for_each_init(init, pack, head) \
- for (pack = head; pack && pack->init; pack++) \
- for (init = pack->init; init && init->count; init++)
-
-struct nvc0_graph_ucode {
- struct nvc0_graph_fuc code;
- struct nvc0_graph_fuc data;
-};
-
-extern struct nvc0_graph_ucode nvc0_graph_fecs_ucode;
-extern struct nvc0_graph_ucode nvc0_graph_gpccs_ucode;
-
-extern struct nvc0_graph_ucode nvf0_graph_fecs_ucode;
-extern struct nvc0_graph_ucode nvf0_graph_gpccs_ucode;
-
-struct nvc0_graph_oclass {
- struct nouveau_oclass base;
- struct nouveau_oclass **cclass;
- struct nouveau_oclass *sclass;
- const struct nvc0_graph_pack *mmio;
- struct {
- struct nvc0_graph_ucode *ucode;
- } fecs;
- struct {
- struct nvc0_graph_ucode *ucode;
- } gpccs;
- int ppc_nr;
-};
-
-void nvc0_graph_mmio(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
-void nvc0_graph_icmd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
-void nvc0_graph_mthd(struct nvc0_graph_priv *, const struct nvc0_graph_pack *);
-int nvc0_graph_init_ctxctl(struct nvc0_graph_priv *);
-
-/* register init value lists */
-
-extern const struct nvc0_graph_init nvc0_graph_init_main_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_fe_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_pri_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_rstr2d_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_pd_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_scc_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_prop_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_setup_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_crstr_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_setup_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_zcull_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_gpm_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_gcc_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_tpccs_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_pe_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_l1c_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_wwdx_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_tpccs_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_mpc_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_be_0[];
-extern const struct nvc0_graph_init nvc0_graph_init_fe_1[];
-extern const struct nvc0_graph_init nvc0_graph_init_pe_1[];
-
-extern const struct nvc0_graph_init nvc4_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvc4_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvc4_graph_init_sm_0[];
-
-extern const struct nvc0_graph_init nvc1_graph_init_gpc_unk_0[];
-extern const struct nvc0_graph_init nvc1_graph_init_setup_1[];
-
-extern const struct nvc0_graph_init nvd9_graph_init_pd_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_prop_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_gpm_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvd9_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_sm_0[];
-extern const struct nvc0_graph_init nvd9_graph_init_fe_1[];
-
-extern const struct nvc0_graph_init nvd7_graph_init_pes_0[];
-extern const struct nvc0_graph_init nvd7_graph_init_wwdx_0[];
-extern const struct nvc0_graph_init nvd7_graph_init_cbm_0[];
-
-extern const struct nvc0_graph_init nve4_graph_init_main_0[];
-extern const struct nvc0_graph_init nve4_graph_init_tpccs_0[];
-extern const struct nvc0_graph_init nve4_graph_init_pe_0[];
-extern const struct nvc0_graph_init nve4_graph_init_be_0[];
-extern const struct nvc0_graph_pack nve4_graph_pack_mmio[];
-
-extern const struct nvc0_graph_init nvf0_graph_init_fe_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_ds_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_sked_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_cwd_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_gpc_unk_1[];
-extern const struct nvc0_graph_init nvf0_graph_init_tex_0[];
-extern const struct nvc0_graph_init nvf0_graph_init_sm_0[];
-
-extern const struct nvc0_graph_init nv108_graph_init_gpc_unk_0[];
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
deleted file mode 100644
index 93d58e5b82c2..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc1.c
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc1_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0x9039, &nouveau_object_ofuncs },
- { FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { FERMI_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc1_graph_init_gpc_unk_0[] = {
- { 0x418604, 1, 0x04, 0x00000000 },
- { 0x418680, 1, 0x04, 0x00000000 },
- { 0x418714, 1, 0x04, 0x00000000 },
- { 0x418384, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc1_graph_init_setup_1[] = {
- { 0x4188c8, 2, 0x04, 0x00000000 },
- { 0x4188d0, 1, 0x04, 0x00010000 },
- { 0x4188d4, 1, 0x04, 0x00000001 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_graph_init_gpc_unk_1[] = {
- { 0x418d00, 1, 0x04, 0x00000000 },
- { 0x418f08, 1, 0x04, 0x00000000 },
- { 0x418e00, 1, 0x04, 0x00000003 },
- { 0x418e08, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc1_graph_init_pe_0[] = {
- { 0x41980c, 1, 0x04, 0x00000010 },
- { 0x419810, 1, 0x04, 0x00000000 },
- { 0x419814, 1, 0x04, 0x00000004 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x41984c, 1, 0x04, 0x00005bc5 },
- { 0x419850, 4, 0x04, 0x00000000 },
- { 0x419880, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc1_graph_pack_mmio[] = {
- { nvc0_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvc0_graph_init_pd_0 },
- { nvc4_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvc0_graph_init_prop_0 },
- { nvc1_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvc0_graph_init_gpm_0 },
- { nvc1_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nvc0_graph_init_tpccs_0 },
- { nvc4_graph_init_tex_0 },
- { nvc1_graph_init_pe_0 },
- { nvc0_graph_init_l1c_0 },
- { nvc0_graph_init_wwdx_0 },
- { nvc0_graph_init_tpccs_1 },
- { nvc0_graph_init_mpc_0 },
- { nvc4_graph_init_sm_0 },
- { nvc0_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc1_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xc1),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nvc0_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nvc1_grctx_oclass,
- .sclass = nvc1_graph_sclass,
- .mmio = nvc1_graph_pack_mmio,
- .fecs.ucode = &nvc0_graph_fecs_ucode,
- .gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c
deleted file mode 100644
index e82e70c53132..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc4.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvc4_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405900, 1, 0x04, 0x00002834 },
- { 0x405908, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc4_graph_init_tex_0[] = {
- { 0x419ab0, 1, 0x04, 0x00000000 },
- { 0x419ac8, 1, 0x04, 0x00000000 },
- { 0x419ab8, 1, 0x04, 0x000000e7 },
- { 0x419abc, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvc4_graph_init_pe_0[] = {
- { 0x41980c, 3, 0x04, 0x00000000 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x41984c, 1, 0x04, 0x00005bc5 },
- { 0x419850, 4, 0x04, 0x00000000 },
- { 0x419880, 1, 0x04, 0x00000002 },
- {}
-};
-
-const struct nvc0_graph_init
-nvc4_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000000 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x00001100 },
- { 0x419eac, 1, 0x04, 0x11100702 },
- { 0x419eb0, 1, 0x04, 0x00000003 },
- { 0x419eb4, 4, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x0e063818 },
- { 0x419ecc, 1, 0x04, 0x0e060e06 },
- { 0x419ed0, 1, 0x04, 0x00003818 },
- { 0x419ed4, 1, 0x04, 0x011104f1 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419f2c, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc4_graph_pack_mmio[] = {
- { nvc0_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvc0_graph_init_pd_0 },
- { nvc4_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvc0_graph_init_prop_0 },
- { nvc0_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc0_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvc0_graph_init_gpm_0 },
- { nvc0_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nvc0_graph_init_tpccs_0 },
- { nvc4_graph_init_tex_0 },
- { nvc4_graph_init_pe_0 },
- { nvc0_graph_init_l1c_0 },
- { nvc0_graph_init_wwdx_0 },
- { nvc0_graph_init_tpccs_1 },
- { nvc0_graph_init_mpc_0 },
- { nvc4_graph_init_sm_0 },
- { nvc0_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc4_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xc3),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nvc0_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nvc4_grctx_oclass,
- .sclass = nvc0_graph_sclass,
- .mmio = nvc4_graph_pack_mmio,
- .fecs.ucode = &nvc0_graph_fecs_ucode,
- .gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
deleted file mode 100644
index 692e1eda0eb4..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvc8.c
+++ /dev/null
@@ -1,115 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-struct nouveau_oclass
-nvc8_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0x9039, &nouveau_object_ofuncs },
- { FERMI_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { FERMI_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { FERMI_C, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { FERMI_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvc8_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000000 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x00001100 },
- { 0x419eac, 1, 0x04, 0x11100f02 },
- { 0x419eb0, 1, 0x04, 0x00000003 },
- { 0x419eb4, 4, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x06060618 },
- { 0x419ed0, 1, 0x04, 0x0eff0e38 },
- { 0x419ed4, 1, 0x04, 0x011104f1 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419f2c, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvc8_graph_pack_mmio[] = {
- { nvc0_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvc0_graph_init_pd_0 },
- { nvc0_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvc0_graph_init_prop_0 },
- { nvc0_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvc0_graph_init_gpm_0 },
- { nvc0_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nvc0_graph_init_tpccs_0 },
- { nvc0_graph_init_tex_0 },
- { nvc0_graph_init_pe_0 },
- { nvc0_graph_init_l1c_0 },
- { nvc0_graph_init_wwdx_0 },
- { nvc0_graph_init_tpccs_1 },
- { nvc0_graph_init_mpc_0 },
- { nvc8_graph_init_sm_0 },
- { nvc0_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- { nvc0_graph_init_pe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc8_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xc8),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nvc0_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nvc8_grctx_oclass,
- .sclass = nvc8_graph_sclass,
- .mmio = nvc8_graph_pack_mmio,
- .fecs.ucode = &nvc0_graph_fecs_ucode,
- .gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
deleted file mode 100644
index 41e8445c7eea..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd7.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-static const struct nvc0_graph_init
-nvd7_graph_init_pe_0[] = {
- { 0x41980c, 1, 0x04, 0x00000010 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x41984c, 1, 0x04, 0x00005bc8 },
- { 0x419850, 3, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd7_graph_init_pes_0[] = {
- { 0x41be04, 1, 0x04, 0x00000000 },
- { 0x41be08, 1, 0x04, 0x00000004 },
- { 0x41be0c, 1, 0x04, 0x00000000 },
- { 0x41be10, 1, 0x04, 0x003b8bc7 },
- { 0x41be14, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd7_graph_init_wwdx_0[] = {
- { 0x41bfd4, 1, 0x04, 0x00800000 },
- { 0x41bfdc, 1, 0x04, 0x00000000 },
- { 0x41bff8, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd7_graph_init_cbm_0[] = {
- { 0x41becc, 1, 0x04, 0x00000000 },
- { 0x41bee8, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd7_graph_pack_mmio[] = {
- { nvc0_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvd9_graph_init_pd_0 },
- { nvd9_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvd9_graph_init_prop_0 },
- { nvc1_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvd9_graph_init_gpm_0 },
- { nvd9_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nvc0_graph_init_tpccs_0 },
- { nvd9_graph_init_tex_0 },
- { nvd7_graph_init_pe_0 },
- { nvc0_graph_init_l1c_0 },
- { nvc0_graph_init_mpc_0 },
- { nvd9_graph_init_sm_0 },
- { nvd7_graph_init_pes_0 },
- { nvd7_graph_init_wwdx_0 },
- { nvd7_graph_init_cbm_0 },
- { nvc0_graph_init_be_0 },
- { nvd9_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-#include "fuc/hubnvd7.fuc.h"
-
-struct nvc0_graph_ucode
-nvd7_graph_fecs_ucode = {
- .code.data = nvd7_grhub_code,
- .code.size = sizeof(nvd7_grhub_code),
- .data.data = nvd7_grhub_data,
- .data.size = sizeof(nvd7_grhub_data),
-};
-
-#include "fuc/gpcnvd7.fuc.h"
-
-struct nvc0_graph_ucode
-nvd7_graph_gpccs_ucode = {
- .code.data = nvd7_grgpc_code,
- .code.size = sizeof(nvd7_grgpc_code),
- .data.data = nvd7_grgpc_data,
- .data.size = sizeof(nvd7_grgpc_data),
-};
-
-struct nouveau_oclass *
-nvd7_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xd7),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nvc0_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nvd7_grctx_oclass,
- .sclass = nvc8_graph_sclass,
- .mmio = nvd7_graph_pack_mmio,
- .fecs.ucode = &nvd7_graph_fecs_ucode,
- .gpccs.ucode = &nvd7_graph_gpccs_ucode,
- .ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
deleted file mode 100644
index 00fdf202fb92..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvd9.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvd9_graph_init_pd_0[] = {
- { 0x406024, 1, 0x04, 0x00000000 },
- { 0x4064f0, 3, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405900, 1, 0x04, 0x00002834 },
- { 0x405908, 1, 0x04, 0x00000000 },
- { 0x405928, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_prop_0[] = {
- { 0x418408, 1, 0x04, 0x00000000 },
- { 0x4184a0, 3, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_gpm_0[] = {
- { 0x418c04, 1, 0x04, 0x00000000 },
- { 0x418c64, 2, 0x04, 0x00000000 },
- { 0x418c88, 1, 0x04, 0x00000000 },
- { 0x418cb4, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_gpc_unk_1[] = {
- { 0x418d00, 1, 0x04, 0x00000000 },
- { 0x418d28, 2, 0x04, 0x00000000 },
- { 0x418f00, 1, 0x04, 0x00000000 },
- { 0x418f08, 1, 0x04, 0x00000000 },
- { 0x418f20, 2, 0x04, 0x00000000 },
- { 0x418e00, 1, 0x04, 0x00000003 },
- { 0x418e08, 1, 0x04, 0x00000000 },
- { 0x418e1c, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_tex_0[] = {
- { 0x419ab0, 1, 0x04, 0x00000000 },
- { 0x419ac8, 1, 0x04, 0x00000000 },
- { 0x419ab8, 1, 0x04, 0x000000e7 },
- { 0x419abc, 2, 0x04, 0x00000000 },
- { 0x419ab4, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_graph_init_pe_0[] = {
- { 0x41980c, 1, 0x04, 0x00000010 },
- { 0x419810, 1, 0x04, 0x00000000 },
- { 0x419814, 1, 0x04, 0x00000004 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x41984c, 1, 0x04, 0x0000a918 },
- { 0x419850, 4, 0x04, 0x00000000 },
- { 0x419880, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_graph_init_wwdx_0[] = {
- { 0x419bd4, 1, 0x04, 0x00800000 },
- { 0x419bdc, 1, 0x04, 0x00000000 },
- { 0x419bf8, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvd9_graph_init_tpccs_1[] = {
- { 0x419d2c, 1, 0x04, 0x00000000 },
- { 0x419d48, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000000 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x02001100 },
- { 0x419eac, 1, 0x04, 0x11100702 },
- { 0x419eb0, 1, 0x04, 0x00000003 },
- { 0x419eb4, 4, 0x04, 0x00000000 },
- { 0x419ec8, 1, 0x04, 0x0e063818 },
- { 0x419ecc, 1, 0x04, 0x0e060e06 },
- { 0x419ed0, 1, 0x04, 0x00003818 },
- { 0x419ed4, 1, 0x04, 0x011104f1 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419f2c, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvd9_graph_init_fe_1[] = {
- { 0x40402c, 1, 0x04, 0x00000000 },
- { 0x4040f0, 1, 0x04, 0x00000000 },
- { 0x404174, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvd9_graph_pack_mmio[] = {
- { nvc0_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvd9_graph_init_pd_0 },
- { nvd9_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvd9_graph_init_prop_0 },
- { nvc1_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvd9_graph_init_gpm_0 },
- { nvd9_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nvc0_graph_init_tpccs_0 },
- { nvd9_graph_init_tex_0 },
- { nvd9_graph_init_pe_0 },
- { nvc0_graph_init_l1c_0 },
- { nvd9_graph_init_wwdx_0 },
- { nvd9_graph_init_tpccs_1 },
- { nvc0_graph_init_mpc_0 },
- { nvd9_graph_init_sm_0 },
- { nvc0_graph_init_be_0 },
- { nvd9_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvd9_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xd9),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nvc0_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nvd9_grctx_oclass,
- .sclass = nvc8_graph_sclass,
- .mmio = nvd9_graph_pack_mmio,
- .fecs.ucode = &nvc0_graph_fecs_ucode,
- .gpccs.ucode = &nvc0_graph_gpccs_ucode,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c b/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
deleted file mode 100644
index 0c71f5c67ae0..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nve4.c
+++ /dev/null
@@ -1,347 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/pwr.h>
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve4_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0xa040, &nouveau_object_ofuncs },
- { KEPLER_A, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { KEPLER_COMPUTE_A, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nve4_graph_init_main_0[] = {
- { 0x400080, 1, 0x04, 0x003083c2 },
- { 0x400088, 1, 0x04, 0x0001ffe7 },
- { 0x40008c, 1, 0x04, 0x00000000 },
- { 0x400090, 1, 0x04, 0x00000030 },
- { 0x40013c, 1, 0x04, 0x003901f7 },
- { 0x400140, 1, 0x04, 0x00000100 },
- { 0x400144, 1, 0x04, 0x00000000 },
- { 0x400148, 1, 0x04, 0x00000110 },
- { 0x400138, 1, 0x04, 0x00000000 },
- { 0x400130, 2, 0x04, 0x00000000 },
- { 0x400124, 1, 0x04, 0x00000002 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405900, 1, 0x04, 0x0000ff34 },
- { 0x405908, 1, 0x04, 0x00000000 },
- { 0x405928, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_sked_0[] = {
- { 0x407010, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_cwd_0[] = {
- { 0x405b50, 1, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_gpc_unk_1[] = {
- { 0x418d00, 1, 0x04, 0x00000000 },
- { 0x418d28, 2, 0x04, 0x00000000 },
- { 0x418f00, 1, 0x04, 0x00000000 },
- { 0x418f08, 1, 0x04, 0x00000000 },
- { 0x418f20, 2, 0x04, 0x00000000 },
- { 0x418e00, 1, 0x04, 0x00000060 },
- { 0x418e08, 1, 0x04, 0x00000000 },
- { 0x418e1c, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_graph_init_tpccs_0[] = {
- { 0x419d0c, 1, 0x04, 0x00000000 },
- { 0x419d10, 1, 0x04, 0x00000014 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_graph_init_pe_0[] = {
- { 0x41980c, 1, 0x04, 0x00000010 },
- { 0x419844, 1, 0x04, 0x00000000 },
- { 0x419850, 1, 0x04, 0x00000004 },
- { 0x419854, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_l1c_0[] = {
- { 0x419c98, 1, 0x04, 0x00000000 },
- { 0x419ca8, 1, 0x04, 0x00000000 },
- { 0x419cb0, 1, 0x04, 0x01000000 },
- { 0x419cb4, 1, 0x04, 0x00000000 },
- { 0x419cb8, 1, 0x04, 0x00b08bea },
- { 0x419c84, 1, 0x04, 0x00010384 },
- { 0x419cbc, 1, 0x04, 0x28137646 },
- { 0x419cc0, 2, 0x04, 0x00000000 },
- { 0x419c80, 1, 0x04, 0x00020232 },
- {}
-};
-
-static const struct nvc0_graph_init
-nve4_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000000 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ee4, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x00000000 },
- { 0x419eb4, 4, 0x04, 0x00000000 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419f74, 1, 0x04, 0x00000555 },
- {}
-};
-
-const struct nvc0_graph_init
-nve4_graph_init_be_0[] = {
- { 0x40880c, 1, 0x04, 0x00000000 },
- { 0x408850, 1, 0x04, 0x00000004 },
- { 0x408910, 9, 0x04, 0x00000000 },
- { 0x408950, 1, 0x04, 0x00000000 },
- { 0x408954, 1, 0x04, 0x0000ffff },
- { 0x408958, 1, 0x04, 0x00000034 },
- { 0x408984, 1, 0x04, 0x00000000 },
- { 0x408988, 1, 0x04, 0x08040201 },
- { 0x40898c, 1, 0x04, 0x80402010 },
- {}
-};
-
-const struct nvc0_graph_pack
-nve4_graph_pack_mmio[] = {
- { nve4_graph_init_main_0 },
- { nvc0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvd9_graph_init_pd_0 },
- { nve4_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nve4_graph_init_sked_0 },
- { nve4_graph_init_cwd_0 },
- { nvd9_graph_init_prop_0 },
- { nvc1_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvd9_graph_init_gpm_0 },
- { nve4_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nve4_graph_init_tpccs_0 },
- { nvd9_graph_init_tex_0 },
- { nve4_graph_init_pe_0 },
- { nve4_graph_init_l1c_0 },
- { nvc0_graph_init_mpc_0 },
- { nve4_graph_init_sm_0 },
- { nvd7_graph_init_pes_0 },
- { nvd7_graph_init_wwdx_0 },
- { nvd7_graph_init_cbm_0 },
- { nve4_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-int
-nve4_graph_init(struct nouveau_object *object)
-{
- struct nvc0_graph_oclass *oclass = (void *)object->oclass;
- struct nvc0_graph_priv *priv = (void *)object;
- struct nouveau_pwr *ppwr = nouveau_pwr(priv);
- const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
- u32 data[TPC_MAX / 8] = {};
- u8 tpcnr[GPC_MAX];
- int gpc, tpc, rop;
- int ret, i;
-
- if (ppwr)
- ppwr->pgob(ppwr, false);
-
- ret = nouveau_graph_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
- nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
- nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
-
- nvc0_graph_mmio(priv, oclass->mmio);
-
- nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
-
- memset(data, 0x00, sizeof(data));
- memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
- for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
- do {
- gpc = (gpc + 1) % priv->gpc_nr;
- } while (!tpcnr[gpc]);
- tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
-
- data[i / 8] |= tpc << ((i % 8) * 4);
- }
-
- nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
- nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
- nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
- nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
- priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
- priv->tpc_total);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
- }
-
- nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
- nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
-
- nv_wr32(priv, 0x400500, 0x00010001);
-
- nv_wr32(priv, 0x400100, 0xffffffff);
- nv_wr32(priv, 0x40013c, 0xffffffff);
-
- nv_wr32(priv, 0x409ffc, 0x00000000);
- nv_wr32(priv, 0x409c14, 0x00003e3e);
- nv_wr32(priv, 0x409c24, 0x000f0001);
- nv_wr32(priv, 0x404000, 0xc0000000);
- nv_wr32(priv, 0x404600, 0xc0000000);
- nv_wr32(priv, 0x408030, 0xc0000000);
- nv_wr32(priv, 0x404490, 0xc0000000);
- nv_wr32(priv, 0x406018, 0xc0000000);
- nv_wr32(priv, 0x407020, 0x40000000);
- nv_wr32(priv, 0x405840, 0xc0000000);
- nv_wr32(priv, 0x405844, 0x00ffffff);
- nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
- nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
-
- for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
- nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
- nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
- for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
- nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
- }
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
- nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
- }
-
- for (rop = 0; rop < priv->rop_nr; rop++) {
- nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
- nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
- nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
- }
-
- nv_wr32(priv, 0x400108, 0xffffffff);
- nv_wr32(priv, 0x400138, 0xffffffff);
- nv_wr32(priv, 0x400118, 0xffffffff);
- nv_wr32(priv, 0x400130, 0xffffffff);
- nv_wr32(priv, 0x40011c, 0xffffffff);
- nv_wr32(priv, 0x400134, 0xffffffff);
-
- nv_wr32(priv, 0x400054, 0x34ce3464);
-
- nvc0_graph_zbc_init(priv);
-
- return nvc0_graph_init_ctxctl(priv);
-}
-
-#include "fuc/hubnve0.fuc.h"
-
-static struct nvc0_graph_ucode
-nve4_graph_fecs_ucode = {
- .code.data = nve0_grhub_code,
- .code.size = sizeof(nve0_grhub_code),
- .data.data = nve0_grhub_data,
- .data.size = sizeof(nve0_grhub_data),
-};
-
-#include "fuc/gpcnve0.fuc.h"
-
-static struct nvc0_graph_ucode
-nve4_graph_gpccs_ucode = {
- .code.data = nve0_grgpc_code,
- .code.size = sizeof(nve0_grgpc_code),
- .data.data = nve0_grgpc_data,
- .data.size = sizeof(nve0_grgpc_data),
-};
-
-struct nouveau_oclass *
-nve4_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xe4),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nve4_graph_init,
- .fini = _nouveau_graph_fini,
- },
- .cclass = &nve4_grctx_oclass,
- .sclass = nve4_graph_sclass,
- .mmio = nve4_graph_pack_mmio,
- .fecs.ucode = &nve4_graph_fecs_ucode,
- .gpccs.ucode = &nve4_graph_gpccs_ucode,
- .ppc_nr = 1,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
deleted file mode 100644
index c306c0f2fc84..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/nvf0.c
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nvc0.h"
-#include "ctxnvc0.h"
-
-/*******************************************************************************
- * Graphics object classes
- ******************************************************************************/
-
-struct nouveau_oclass
-nvf0_graph_sclass[] = {
- { 0x902d, &nouveau_object_ofuncs },
- { 0xa140, &nouveau_object_ofuncs },
- { KEPLER_B, &nvc0_fermi_ofuncs, nvc0_graph_9097_omthds },
- { KEPLER_COMPUTE_B, &nouveau_object_ofuncs, nvc0_graph_90c0_omthds },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH register lists
- ******************************************************************************/
-
-const struct nvc0_graph_init
-nvf0_graph_init_fe_0[] = {
- { 0x40415c, 1, 0x04, 0x00000000 },
- { 0x404170, 1, 0x04, 0x00000000 },
- { 0x4041b4, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_ds_0[] = {
- { 0x405844, 1, 0x04, 0x00ffffff },
- { 0x405850, 1, 0x04, 0x00000000 },
- { 0x405900, 1, 0x04, 0x0000ff00 },
- { 0x405908, 1, 0x04, 0x00000000 },
- { 0x405928, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_sked_0[] = {
- { 0x407010, 1, 0x04, 0x00000000 },
- { 0x407040, 1, 0x04, 0x80440424 },
- { 0x407048, 1, 0x04, 0x0000000a },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_cwd_0[] = {
- { 0x405b44, 1, 0x04, 0x00000000 },
- { 0x405b50, 1, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_gpc_unk_1[] = {
- { 0x418d00, 1, 0x04, 0x00000000 },
- { 0x418d28, 2, 0x04, 0x00000000 },
- { 0x418f00, 1, 0x04, 0x00000400 },
- { 0x418f08, 1, 0x04, 0x00000000 },
- { 0x418f20, 2, 0x04, 0x00000000 },
- { 0x418e00, 1, 0x04, 0x00000000 },
- { 0x418e08, 1, 0x04, 0x00000000 },
- { 0x418e1c, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_tex_0[] = {
- { 0x419ab0, 1, 0x04, 0x00000000 },
- { 0x419ac8, 1, 0x04, 0x00000000 },
- { 0x419ab8, 1, 0x04, 0x000000e7 },
- { 0x419aec, 1, 0x04, 0x00000000 },
- { 0x419abc, 2, 0x04, 0x00000000 },
- { 0x419ab4, 1, 0x04, 0x00000000 },
- { 0x419aa8, 2, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_init
-nvf0_graph_init_l1c_0[] = {
- { 0x419c98, 1, 0x04, 0x00000000 },
- { 0x419ca8, 1, 0x04, 0x00000000 },
- { 0x419cb0, 1, 0x04, 0x01000000 },
- { 0x419cb4, 1, 0x04, 0x00000000 },
- { 0x419cb8, 1, 0x04, 0x00b08bea },
- { 0x419c84, 1, 0x04, 0x00010384 },
- { 0x419cbc, 1, 0x04, 0x281b3646 },
- { 0x419cc0, 2, 0x04, 0x00000000 },
- { 0x419c80, 1, 0x04, 0x00020230 },
- { 0x419ccc, 2, 0x04, 0x00000000 },
- {}
-};
-
-const struct nvc0_graph_init
-nvf0_graph_init_sm_0[] = {
- { 0x419e00, 1, 0x04, 0x00000080 },
- { 0x419ea0, 1, 0x04, 0x00000000 },
- { 0x419ee4, 1, 0x04, 0x00000000 },
- { 0x419ea4, 1, 0x04, 0x00000100 },
- { 0x419ea8, 1, 0x04, 0x00000000 },
- { 0x419eb4, 1, 0x04, 0x00000000 },
- { 0x419ebc, 2, 0x04, 0x00000000 },
- { 0x419edc, 1, 0x04, 0x00000000 },
- { 0x419f00, 1, 0x04, 0x00000000 },
- { 0x419ed0, 1, 0x04, 0x00003234 },
- { 0x419f74, 1, 0x04, 0x00015555 },
- { 0x419f80, 4, 0x04, 0x00000000 },
- {}
-};
-
-static const struct nvc0_graph_pack
-nvf0_graph_pack_mmio[] = {
- { nve4_graph_init_main_0 },
- { nvf0_graph_init_fe_0 },
- { nvc0_graph_init_pri_0 },
- { nvc0_graph_init_rstr2d_0 },
- { nvd9_graph_init_pd_0 },
- { nvf0_graph_init_ds_0 },
- { nvc0_graph_init_scc_0 },
- { nvf0_graph_init_sked_0 },
- { nvf0_graph_init_cwd_0 },
- { nvd9_graph_init_prop_0 },
- { nvc1_graph_init_gpc_unk_0 },
- { nvc0_graph_init_setup_0 },
- { nvc0_graph_init_crstr_0 },
- { nvc1_graph_init_setup_1 },
- { nvc0_graph_init_zcull_0 },
- { nvd9_graph_init_gpm_0 },
- { nvf0_graph_init_gpc_unk_1 },
- { nvc0_graph_init_gcc_0 },
- { nve4_graph_init_tpccs_0 },
- { nvf0_graph_init_tex_0 },
- { nve4_graph_init_pe_0 },
- { nvf0_graph_init_l1c_0 },
- { nvc0_graph_init_mpc_0 },
- { nvf0_graph_init_sm_0 },
- { nvd7_graph_init_pes_0 },
- { nvd7_graph_init_wwdx_0 },
- { nvd7_graph_init_cbm_0 },
- { nve4_graph_init_be_0 },
- { nvc0_graph_init_fe_1 },
- {}
-};
-
-/*******************************************************************************
- * PGRAPH engine/subdev functions
- ******************************************************************************/
-
-int
-nvf0_graph_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvc0_graph_priv *priv = (void *)object;
- static const struct {
- u32 addr;
- u32 data;
- } magic[] = {
- { 0x020520, 0xfffffffc },
- { 0x020524, 0xfffffffe },
- { 0x020524, 0xfffffffc },
- { 0x020524, 0xfffffff8 },
- { 0x020524, 0xffffffe0 },
- { 0x020530, 0xfffffffe },
- { 0x02052c, 0xfffffffa },
- { 0x02052c, 0xfffffff0 },
- { 0x02052c, 0xffffffc0 },
- { 0x02052c, 0xffffff00 },
- { 0x02052c, 0xfffffc00 },
- { 0x02052c, 0xfffcfc00 },
- { 0x02052c, 0xfff0fc00 },
- { 0x02052c, 0xff80fc00 },
- { 0x020528, 0xfffffffe },
- { 0x020528, 0xfffffffc },
- };
- int i;
-
- nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
- nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
- for (i = 0; i < ARRAY_SIZE(magic); i++) {
- nv_wr32(priv, magic[i].addr, magic[i].data);
- nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
- }
-
- return nouveau_graph_fini(&priv->base, suspend);
-}
-
-#include "fuc/hubnvf0.fuc.h"
-
-struct nvc0_graph_ucode
-nvf0_graph_fecs_ucode = {
- .code.data = nvf0_grhub_code,
- .code.size = sizeof(nvf0_grhub_code),
- .data.data = nvf0_grhub_data,
- .data.size = sizeof(nvf0_grhub_data),
-};
-
-#include "fuc/gpcnvf0.fuc.h"
-
-struct nvc0_graph_ucode
-nvf0_graph_gpccs_ucode = {
- .code.data = nvf0_grgpc_code,
- .code.size = sizeof(nvf0_grgpc_code),
- .data.data = nvf0_grgpc_data,
- .data.size = sizeof(nvf0_grgpc_data),
-};
-
-struct nouveau_oclass *
-nvf0_graph_oclass = &(struct nvc0_graph_oclass) {
- .base.handle = NV_ENGINE(GR, 0xf0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_graph_ctor,
- .dtor = nvc0_graph_dtor,
- .init = nve4_graph_init,
- .fini = nvf0_graph_fini,
- },
- .cclass = &nvf0_grctx_oclass,
- .sclass = nvf0_graph_sclass,
- .mmio = nvf0_graph_pack_mmio,
- .fecs.ucode = &nvf0_graph_fecs_ucode,
- .gpccs.ucode = &nvf0_graph_gpccs_ucode,
- .ppc_nr = 2,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/regs.h b/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
deleted file mode 100644
index fde8e24415e4..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/graph/regs.h
+++ /dev/null
@@ -1,274 +0,0 @@
-#ifndef __NOUVEAU_GRAPH_REGS_H__
-#define __NOUVEAU_GRAPH_REGS_H__
-
-#define NV04_PGRAPH_DEBUG_0 0x00400080
-#define NV04_PGRAPH_DEBUG_1 0x00400084
-#define NV04_PGRAPH_DEBUG_2 0x00400088
-#define NV04_PGRAPH_DEBUG_3 0x0040008c
-#define NV10_PGRAPH_DEBUG_4 0x00400090
-#define NV03_PGRAPH_INTR 0x00400100
-#define NV03_PGRAPH_NSTATUS 0x00400104
-# define NV04_PGRAPH_NSTATUS_STATE_IN_USE (1<<11)
-# define NV04_PGRAPH_NSTATUS_INVALID_STATE (1<<12)
-# define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<13)
-# define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<14)
-# define NV10_PGRAPH_NSTATUS_STATE_IN_USE (1<<23)
-# define NV10_PGRAPH_NSTATUS_INVALID_STATE (1<<24)
-# define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<25)
-# define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<26)
-#define NV03_PGRAPH_NSOURCE 0x00400108
-# define NV03_PGRAPH_NSOURCE_NOTIFICATION (1<<0)
-# define NV03_PGRAPH_NSOURCE_DATA_ERROR (1<<1)
-# define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR (1<<2)
-# define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION (1<<3)
-# define NV03_PGRAPH_NSOURCE_LIMIT_COLOR (1<<4)
-# define NV03_PGRAPH_NSOURCE_LIMIT_ZETA (1<<5)
-# define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD (1<<6)
-# define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION (1<<7)
-# define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION (1<<8)
-# define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION (1<<9)
-# define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION (1<<10)
-# define NV03_PGRAPH_NSOURCE_STATE_INVALID (1<<11)
-# define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY (1<<12)
-# define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE (1<<13)
-# define NV03_PGRAPH_NSOURCE_METHOD_CNT (1<<14)
-# define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION (1<<15)
-# define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION (1<<16)
-# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A (1<<17)
-# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B (1<<18)
-#define NV03_PGRAPH_INTR_EN 0x00400140
-#define NV40_PGRAPH_INTR_EN 0x0040013C
-# define NV_PGRAPH_INTR_NOTIFY (1<<0)
-# define NV_PGRAPH_INTR_MISSING_HW (1<<4)
-# define NV_PGRAPH_INTR_CONTEXT_SWITCH (1<<12)
-# define NV_PGRAPH_INTR_BUFFER_NOTIFY (1<<16)
-# define NV_PGRAPH_INTR_ERROR (1<<20)
-#define NV10_PGRAPH_CTX_CONTROL 0x00400144
-#define NV10_PGRAPH_CTX_USER 0x00400148
-#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i))
-#define NV04_PGRAPH_CTX_SWITCH1 0x00400160
-#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \
- + 0x4*(i) + 0x20*(j))
-#define NV04_PGRAPH_CTX_SWITCH2 0x00400164
-#define NV04_PGRAPH_CTX_SWITCH3 0x00400168
-#define NV04_PGRAPH_CTX_SWITCH4 0x0040016C
-#define NV04_PGRAPH_CTX_CONTROL 0x00400170
-#define NV04_PGRAPH_CTX_USER 0x00400174
-#define NV04_PGRAPH_CTX_CACHE1 0x00400180
-#define NV03_PGRAPH_CTX_CONTROL 0x00400190
-#define NV03_PGRAPH_CTX_USER 0x00400194
-#define NV04_PGRAPH_CTX_CACHE2 0x004001A0
-#define NV04_PGRAPH_CTX_CACHE3 0x004001C0
-#define NV04_PGRAPH_CTX_CACHE4 0x004001E0
-#define NV40_PGRAPH_CTXCTL_0304 0x00400304
-#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK 0xff000000
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT 24
-#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK 0x00ffffff
-#define NV40_PGRAPH_CTXCTL_0310 0x00400310
-#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE 0x00000020
-#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD 0x00000040
-#define NV40_PGRAPH_CTXCTL_030C 0x0040030c
-#define NV40_PGRAPH_CTXCTL_UCODE_INDEX 0x00400324
-#define NV40_PGRAPH_CTXCTL_UCODE_DATA 0x00400328
-#define NV40_PGRAPH_CTXCTL_CUR 0x0040032c
-#define NV40_PGRAPH_CTXCTL_CUR_LOADED 0x01000000
-#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE 0x000FFFFF
-#define NV40_PGRAPH_CTXCTL_NEXT 0x00400330
-#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE 0x000fffff
-#define NV50_PGRAPH_CTXCTL_CUR 0x0040032c
-#define NV50_PGRAPH_CTXCTL_CUR_LOADED 0x80000000
-#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE 0x00ffffff
-#define NV50_PGRAPH_CTXCTL_NEXT 0x00400330
-#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE 0x00ffffff
-#define NV03_PGRAPH_ABS_X_RAM 0x00400400
-#define NV03_PGRAPH_ABS_Y_RAM 0x00400480
-#define NV03_PGRAPH_X_MISC 0x00400500
-#define NV03_PGRAPH_Y_MISC 0x00400504
-#define NV04_PGRAPH_VALID1 0x00400508
-#define NV04_PGRAPH_SOURCE_COLOR 0x0040050C
-#define NV04_PGRAPH_MISC24_0 0x00400510
-#define NV03_PGRAPH_XY_LOGIC_MISC0 0x00400514
-#define NV03_PGRAPH_XY_LOGIC_MISC1 0x00400518
-#define NV03_PGRAPH_XY_LOGIC_MISC2 0x0040051C
-#define NV03_PGRAPH_XY_LOGIC_MISC3 0x00400520
-#define NV03_PGRAPH_CLIPX_0 0x00400524
-#define NV03_PGRAPH_CLIPX_1 0x00400528
-#define NV03_PGRAPH_CLIPY_0 0x0040052C
-#define NV03_PGRAPH_CLIPY_1 0x00400530
-#define NV03_PGRAPH_ABS_ICLIP_XMAX 0x00400534
-#define NV03_PGRAPH_ABS_ICLIP_YMAX 0x00400538
-#define NV03_PGRAPH_ABS_UCLIP_XMIN 0x0040053C
-#define NV03_PGRAPH_ABS_UCLIP_YMIN 0x00400540
-#define NV03_PGRAPH_ABS_UCLIP_XMAX 0x00400544
-#define NV03_PGRAPH_ABS_UCLIP_YMAX 0x00400548
-#define NV03_PGRAPH_ABS_UCLIPA_XMIN 0x00400560
-#define NV03_PGRAPH_ABS_UCLIPA_YMIN 0x00400564
-#define NV03_PGRAPH_ABS_UCLIPA_XMAX 0x00400568
-#define NV03_PGRAPH_ABS_UCLIPA_YMAX 0x0040056C
-#define NV04_PGRAPH_MISC24_1 0x00400570
-#define NV04_PGRAPH_MISC24_2 0x00400574
-#define NV04_PGRAPH_VALID2 0x00400578
-#define NV04_PGRAPH_PASSTHRU_0 0x0040057C
-#define NV04_PGRAPH_PASSTHRU_1 0x00400580
-#define NV04_PGRAPH_PASSTHRU_2 0x00400584
-#define NV10_PGRAPH_DIMX_TEXTURE 0x00400588
-#define NV10_PGRAPH_WDIMX_TEXTURE 0x0040058C
-#define NV04_PGRAPH_COMBINE_0_ALPHA 0x00400590
-#define NV04_PGRAPH_COMBINE_0_COLOR 0x00400594
-#define NV04_PGRAPH_COMBINE_1_ALPHA 0x00400598
-#define NV04_PGRAPH_COMBINE_1_COLOR 0x0040059C
-#define NV04_PGRAPH_FORMAT_0 0x004005A8
-#define NV04_PGRAPH_FORMAT_1 0x004005AC
-#define NV04_PGRAPH_FILTER_0 0x004005B0
-#define NV04_PGRAPH_FILTER_1 0x004005B4
-#define NV03_PGRAPH_MONO_COLOR0 0x00400600
-#define NV04_PGRAPH_ROP3 0x00400604
-#define NV04_PGRAPH_BETA_AND 0x00400608
-#define NV04_PGRAPH_BETA_PREMULT 0x0040060C
-#define NV04_PGRAPH_LIMIT_VIOL_PIX 0x00400610
-#define NV04_PGRAPH_FORMATS 0x00400618
-#define NV10_PGRAPH_DEBUG_2 0x00400620
-#define NV04_PGRAPH_BOFFSET0 0x00400640
-#define NV04_PGRAPH_BOFFSET1 0x00400644
-#define NV04_PGRAPH_BOFFSET2 0x00400648
-#define NV04_PGRAPH_BOFFSET3 0x0040064C
-#define NV04_PGRAPH_BOFFSET4 0x00400650
-#define NV04_PGRAPH_BOFFSET5 0x00400654
-#define NV04_PGRAPH_BBASE0 0x00400658
-#define NV04_PGRAPH_BBASE1 0x0040065C
-#define NV04_PGRAPH_BBASE2 0x00400660
-#define NV04_PGRAPH_BBASE3 0x00400664
-#define NV04_PGRAPH_BBASE4 0x00400668
-#define NV04_PGRAPH_BBASE5 0x0040066C
-#define NV04_PGRAPH_BPITCH0 0x00400670
-#define NV04_PGRAPH_BPITCH1 0x00400674
-#define NV04_PGRAPH_BPITCH2 0x00400678
-#define NV04_PGRAPH_BPITCH3 0x0040067C
-#define NV04_PGRAPH_BPITCH4 0x00400680
-#define NV04_PGRAPH_BLIMIT0 0x00400684
-#define NV04_PGRAPH_BLIMIT1 0x00400688
-#define NV04_PGRAPH_BLIMIT2 0x0040068C
-#define NV04_PGRAPH_BLIMIT3 0x00400690
-#define NV04_PGRAPH_BLIMIT4 0x00400694
-#define NV04_PGRAPH_BLIMIT5 0x00400698
-#define NV04_PGRAPH_BSWIZZLE2 0x0040069C
-#define NV04_PGRAPH_BSWIZZLE5 0x004006A0
-#define NV03_PGRAPH_STATUS 0x004006B0
-#define NV04_PGRAPH_STATUS 0x00400700
-# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000
-#define NV04_PGRAPH_TRAPPED_ADDR 0x00400704
-#define NV04_PGRAPH_TRAPPED_DATA 0x00400708
-#define NV04_PGRAPH_SURFACE 0x0040070C
-#define NV10_PGRAPH_TRAPPED_DATA_HIGH 0x0040070C
-#define NV04_PGRAPH_STATE 0x00400710
-#define NV10_PGRAPH_SURFACE 0x00400710
-#define NV04_PGRAPH_NOTIFY 0x00400714
-#define NV10_PGRAPH_STATE 0x00400714
-#define NV10_PGRAPH_NOTIFY 0x00400718
-
-#define NV04_PGRAPH_FIFO 0x00400720
-
-#define NV04_PGRAPH_BPIXEL 0x00400724
-#define NV10_PGRAPH_RDI_INDEX 0x00400750
-#define NV04_PGRAPH_FFINTFC_ST2 0x00400754
-#define NV10_PGRAPH_RDI_DATA 0x00400754
-#define NV04_PGRAPH_DMA_PITCH 0x00400760
-#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760
-#define NV04_PGRAPH_DVD_COLORFMT 0x00400764
-#define NV10_PGRAPH_FFINTFC_ST2 0x00400764
-#define NV04_PGRAPH_SCALED_FORMAT 0x00400768
-#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768
-#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c
-#define NV10_PGRAPH_DMA_PITCH 0x00400770
-#define NV10_PGRAPH_DVD_COLORFMT 0x00400774
-#define NV10_PGRAPH_SCALED_FORMAT 0x00400778
-#define NV20_PGRAPH_CHANNEL_CTX_TABLE 0x00400780
-#define NV20_PGRAPH_CHANNEL_CTX_POINTER 0x00400784
-#define NV20_PGRAPH_CHANNEL_CTX_XFER 0x00400788
-#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD 0x00000001
-#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE 0x00000002
-#define NV04_PGRAPH_PATT_COLOR0 0x00400800
-#define NV04_PGRAPH_PATT_COLOR1 0x00400804
-#define NV04_PGRAPH_PATTERN 0x00400808
-#define NV04_PGRAPH_PATTERN_SHAPE 0x00400810
-#define NV04_PGRAPH_CHROMA 0x00400814
-#define NV04_PGRAPH_CONTROL0 0x00400818
-#define NV04_PGRAPH_CONTROL1 0x0040081C
-#define NV04_PGRAPH_CONTROL2 0x00400820
-#define NV04_PGRAPH_BLEND 0x00400824
-#define NV04_PGRAPH_STORED_FMT 0x00400830
-#define NV04_PGRAPH_PATT_COLORRAM 0x00400900
-#define NV20_PGRAPH_TILE(i) (0x00400900 + (i*16))
-#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16))
-#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16))
-#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16))
-#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i))
-#define NV41_PGRAPH_ZCOMP0(i) (0x004009c0 + 4*(i))
-#define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16))
-#define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16))
-#define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16))
-#define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16))
-#define NV04_PGRAPH_U_RAM 0x00400D00
-#define NV47_PGRAPH_TILE(i) (0x00400D00 + (i*16))
-#define NV47_PGRAPH_TLIMIT(i) (0x00400D04 + (i*16))
-#define NV47_PGRAPH_TSIZE(i) (0x00400D08 + (i*16))
-#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16))
-#define NV04_PGRAPH_V_RAM 0x00400D40
-#define NV04_PGRAPH_W_RAM 0x00400D80
-#define NV47_PGRAPH_ZCOMP0(i) (0x00400e00 + 4*(i))
-#define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40
-#define NV10_PGRAPH_COMBINER1_IN_ALPHA 0x00400E44
-#define NV10_PGRAPH_COMBINER0_IN_RGB 0x00400E48
-#define NV10_PGRAPH_COMBINER1_IN_RGB 0x00400E4C
-#define NV10_PGRAPH_COMBINER_COLOR0 0x00400E50
-#define NV10_PGRAPH_COMBINER_COLOR1 0x00400E54
-#define NV10_PGRAPH_COMBINER0_OUT_ALPHA 0x00400E58
-#define NV10_PGRAPH_COMBINER1_OUT_ALPHA 0x00400E5C
-#define NV10_PGRAPH_COMBINER0_OUT_RGB 0x00400E60
-#define NV10_PGRAPH_COMBINER1_OUT_RGB 0x00400E64
-#define NV10_PGRAPH_COMBINER_FINAL0 0x00400E68
-#define NV10_PGRAPH_COMBINER_FINAL1 0x00400E6C
-#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL 0x00400F00
-#define NV10_PGRAPH_WINDOWCLIP_VERTICAL 0x00400F20
-#define NV10_PGRAPH_XFMODE0 0x00400F40
-#define NV10_PGRAPH_XFMODE1 0x00400F44
-#define NV10_PGRAPH_GLOBALSTATE0 0x00400F48
-#define NV10_PGRAPH_GLOBALSTATE1 0x00400F4C
-#define NV10_PGRAPH_PIPE_ADDRESS 0x00400F50
-#define NV10_PGRAPH_PIPE_DATA 0x00400F54
-#define NV04_PGRAPH_DMA_START_0 0x00401000
-#define NV04_PGRAPH_DMA_START_1 0x00401004
-#define NV04_PGRAPH_DMA_LENGTH 0x00401008
-#define NV04_PGRAPH_DMA_MISC 0x0040100C
-#define NV04_PGRAPH_DMA_DATA_0 0x00401020
-#define NV04_PGRAPH_DMA_DATA_1 0x00401024
-#define NV04_PGRAPH_DMA_RM 0x00401030
-#define NV04_PGRAPH_DMA_A_XLATE_INST 0x00401040
-#define NV04_PGRAPH_DMA_A_CONTROL 0x00401044
-#define NV04_PGRAPH_DMA_A_LIMIT 0x00401048
-#define NV04_PGRAPH_DMA_A_TLB_PTE 0x0040104C
-#define NV04_PGRAPH_DMA_A_TLB_TAG 0x00401050
-#define NV04_PGRAPH_DMA_A_ADJ_OFFSET 0x00401054
-#define NV04_PGRAPH_DMA_A_OFFSET 0x00401058
-#define NV04_PGRAPH_DMA_A_SIZE 0x0040105C
-#define NV04_PGRAPH_DMA_A_Y_SIZE 0x00401060
-#define NV04_PGRAPH_DMA_B_XLATE_INST 0x00401080
-#define NV04_PGRAPH_DMA_B_CONTROL 0x00401084
-#define NV04_PGRAPH_DMA_B_LIMIT 0x00401088
-#define NV04_PGRAPH_DMA_B_TLB_PTE 0x0040108C
-#define NV04_PGRAPH_DMA_B_TLB_TAG 0x00401090
-#define NV04_PGRAPH_DMA_B_ADJ_OFFSET 0x00401094
-#define NV04_PGRAPH_DMA_B_OFFSET 0x00401098
-#define NV04_PGRAPH_DMA_B_SIZE 0x0040109C
-#define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0
-#define NV47_PGRAPH_ZCOMP1(i) (0x004068c0 + 4*(i))
-#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16))
-#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16))
-#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16))
-#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16))
-#define NV40_PGRAPH_ZCOMP1(i) (0x00406980 + 4*(i))
-#define NV41_PGRAPH_ZCOMP1(i) (0x004069c0 + 4*(i))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
deleted file mode 100644
index d88c700b2f69..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.c
+++ /dev/null
@@ -1,309 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/handle.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-#include <subdev/instmem.h>
-
-#include <engine/fifo.h>
-#include <engine/mpeg.h>
-#include <engine/mpeg/nv31.h>
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static int
-nv31_mpeg_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj *obj;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
- 20, 16, 0, &obj);
- *pobject = nv_object(obj);
- if (ret)
- return ret;
-
- nv_wo32(obj, 0x00, nv_mclass(obj));
- nv_wo32(obj, 0x04, 0x00000000);
- nv_wo32(obj, 0x08, 0x00000000);
- nv_wo32(obj, 0x0c, 0x00000000);
- return 0;
-}
-
-static int
-nv31_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
-{
- struct nouveau_instmem *imem = nouveau_instmem(object);
- struct nv31_mpeg_priv *priv = (void *)object->engine;
- u32 inst = *(u32 *)arg << 4;
- u32 dma0 = nv_ro32(imem, inst + 0);
- u32 dma1 = nv_ro32(imem, inst + 4);
- u32 dma2 = nv_ro32(imem, inst + 8);
- u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
- u32 size = dma1 + 1;
-
- /* only allow linear DMA objects */
- if (!(dma0 & 0x00002000))
- return -EINVAL;
-
- if (mthd == 0x0190) {
- /* DMA_CMD */
- nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0);
- nv_wr32(priv, 0x00b334, base);
- nv_wr32(priv, 0x00b324, size);
- } else
- if (mthd == 0x01a0) {
- /* DMA_DATA */
- nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0);
- nv_wr32(priv, 0x00b360, base);
- nv_wr32(priv, 0x00b364, size);
- } else {
- /* DMA_IMAGE, VRAM only */
- if (dma0 & 0x00030000)
- return -EINVAL;
-
- nv_wr32(priv, 0x00b370, base);
- nv_wr32(priv, 0x00b374, size);
- }
-
- return 0;
-}
-
-struct nouveau_ofuncs
-nv31_mpeg_ofuncs = {
- .ctor = nv31_mpeg_object_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_omthds
-nv31_mpeg_omthds[] = {
- { 0x0190, 0x0190, nv31_mpeg_mthd_dma },
- { 0x01a0, 0x01a0, nv31_mpeg_mthd_dma },
- { 0x01b0, 0x01b0, nv31_mpeg_mthd_dma },
- {}
-};
-
-struct nouveau_oclass
-nv31_mpeg_sclass[] = {
- { 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds },
- {}
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-static int
-nv31_mpeg_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv31_mpeg_priv *priv = (void *)engine;
- struct nv31_mpeg_chan *chan;
- unsigned long flags;
- int ret;
-
- ret = nouveau_object_create(parent, engine, oclass, 0, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- spin_lock_irqsave(&nv_engine(priv)->lock, flags);
- if (priv->chan) {
- spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
- nouveau_object_destroy(&chan->base);
- *pobject = NULL;
- return -EBUSY;
- }
- priv->chan = chan;
- spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
- return 0;
-}
-
-static void
-nv31_mpeg_context_dtor(struct nouveau_object *object)
-{
- struct nv31_mpeg_priv *priv = (void *)object->engine;
- struct nv31_mpeg_chan *chan = (void *)object;
- unsigned long flags;
-
- spin_lock_irqsave(&nv_engine(priv)->lock, flags);
- priv->chan = NULL;
- spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
- nouveau_object_destroy(&chan->base);
-}
-
-struct nouveau_oclass
-nv31_mpeg_cclass = {
- .handle = NV_ENGCTX(MPEG, 0x31),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv31_mpeg_context_ctor,
- .dtor = nv31_mpeg_context_dtor,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- },
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-void
-nv31_mpeg_tile_prog(struct nouveau_engine *engine, int i)
-{
- struct nouveau_fb_tile *tile = &nouveau_fb(engine)->tile.region[i];
- struct nv31_mpeg_priv *priv = (void *)engine;
-
- nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch);
- nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit);
- nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr);
-}
-
-void
-nv31_mpeg_intr(struct nouveau_subdev *subdev)
-{
- struct nv31_mpeg_priv *priv = (void *)subdev;
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_handle *handle;
- struct nouveau_object *engctx;
- u32 stat = nv_rd32(priv, 0x00b100);
- u32 type = nv_rd32(priv, 0x00b230);
- u32 mthd = nv_rd32(priv, 0x00b234);
- u32 data = nv_rd32(priv, 0x00b238);
- u32 show = stat;
- unsigned long flags;
-
- spin_lock_irqsave(&nv_engine(priv)->lock, flags);
- engctx = nv_object(priv->chan);
-
- if (stat & 0x01000000) {
- /* happens on initial binding of the object */
- if (type == 0x00000020 && mthd == 0x0000) {
- nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
- show &= ~0x01000000;
- }
-
- if (type == 0x00000010 && engctx) {
- handle = nouveau_handle_get_class(engctx, 0x3174);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~0x01000000;
- nouveau_handle_put(handle);
- }
- }
-
- nv_wr32(priv, 0x00b100, stat);
- nv_wr32(priv, 0x00b230, 0x00000001);
-
- if (show) {
- nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
- pfifo->chid(pfifo, engctx),
- nouveau_client_name(engctx), stat, type, mthd, data);
- }
-
- spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
-}
-
-static int
-nv31_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv31_mpeg_priv *priv;
- int ret;
-
- ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000002;
- nv_subdev(priv)->intr = nv31_mpeg_intr;
- nv_engine(priv)->cclass = &nv31_mpeg_cclass;
- nv_engine(priv)->sclass = nv31_mpeg_sclass;
- nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
- return 0;
-}
-
-int
-nv31_mpeg_init(struct nouveau_object *object)
-{
- struct nouveau_engine *engine = nv_engine(object);
- struct nv31_mpeg_priv *priv = (void *)object;
- struct nouveau_fb *pfb = nouveau_fb(object);
- int ret, i;
-
- ret = nouveau_mpeg_init(&priv->base);
- if (ret)
- return ret;
-
- /* VPE init */
- nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
- nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
-
- for (i = 0; i < pfb->tile.regions; i++)
- engine->tile_prog(engine, i);
-
- /* PMPEG init */
- nv_wr32(priv, 0x00b32c, 0x00000000);
- nv_wr32(priv, 0x00b314, 0x00000100);
- nv_wr32(priv, 0x00b220, 0x00000031);
- nv_wr32(priv, 0x00b300, 0x02001ec1);
- nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
-
- nv_wr32(priv, 0x00b100, 0xffffffff);
- nv_wr32(priv, 0x00b140, 0xffffffff);
-
- if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
- nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
- return -EBUSY;
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-nv31_mpeg_oclass = {
- .handle = NV_ENGINE(MPEG, 0x31),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv31_mpeg_ctor,
- .dtor = _nouveau_mpeg_dtor,
- .init = nv31_mpeg_init,
- .fini = _nouveau_mpeg_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h
deleted file mode 100644
index d08629d0b6ad..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv31.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __NV31_MPEG_H__
-#define __NV31_MPEG_H__
-
-#include <engine/mpeg.h>
-
-struct nv31_mpeg_chan {
- struct nouveau_object base;
-};
-
-struct nv31_mpeg_priv {
- struct nouveau_mpeg base;
- struct nv31_mpeg_chan *chan;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
deleted file mode 100644
index bdb2f20ff7b1..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv40.c
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-#include <subdev/instmem.h>
-
-#include <engine/mpeg.h>
-#include <engine/mpeg/nv31.h>
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static int
-nv40_mpeg_mthd_dma(struct nouveau_object *object, u32 mthd, void *arg, u32 len)
-{
- struct nouveau_instmem *imem = nouveau_instmem(object);
- struct nv31_mpeg_priv *priv = (void *)object->engine;
- u32 inst = *(u32 *)arg << 4;
- u32 dma0 = nv_ro32(imem, inst + 0);
- u32 dma1 = nv_ro32(imem, inst + 4);
- u32 dma2 = nv_ro32(imem, inst + 8);
- u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
- u32 size = dma1 + 1;
-
- /* only allow linear DMA objects */
- if (!(dma0 & 0x00002000))
- return -EINVAL;
-
- if (mthd == 0x0190) {
- /* DMA_CMD */
- nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
- nv_wr32(priv, 0x00b334, base);
- nv_wr32(priv, 0x00b324, size);
- } else
- if (mthd == 0x01a0) {
- /* DMA_DATA */
- nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
- nv_wr32(priv, 0x00b360, base);
- nv_wr32(priv, 0x00b364, size);
- } else {
- /* DMA_IMAGE, VRAM only */
- if (dma0 & 0x00030000)
- return -EINVAL;
-
- nv_wr32(priv, 0x00b370, base);
- nv_wr32(priv, 0x00b374, size);
- }
-
- return 0;
-}
-
-static struct nouveau_omthds
-nv40_mpeg_omthds[] = {
- { 0x0190, 0x0190, nv40_mpeg_mthd_dma },
- { 0x01a0, 0x01a0, nv40_mpeg_mthd_dma },
- { 0x01b0, 0x01b0, nv40_mpeg_mthd_dma },
- {}
-};
-
-struct nouveau_oclass
-nv40_mpeg_sclass[] = {
- { 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds },
- {}
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-static void
-nv40_mpeg_intr(struct nouveau_subdev *subdev)
-{
- struct nv31_mpeg_priv *priv = (void *)subdev;
- u32 stat;
-
- if ((stat = nv_rd32(priv, 0x00b100)))
- nv31_mpeg_intr(subdev);
-
- if ((stat = nv_rd32(priv, 0x00b800))) {
- nv_error(priv, "PMSRCH 0x%08x\n", stat);
- nv_wr32(priv, 0x00b800, stat);
- }
-}
-
-static int
-nv40_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv31_mpeg_priv *priv;
- int ret;
-
- ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000002;
- nv_subdev(priv)->intr = nv40_mpeg_intr;
- nv_engine(priv)->cclass = &nv31_mpeg_cclass;
- nv_engine(priv)->sclass = nv40_mpeg_sclass;
- nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv40_mpeg_oclass = {
- .handle = NV_ENGINE(MPEG, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_mpeg_ctor,
- .dtor = _nouveau_mpeg_dtor,
- .init = nv31_mpeg_init,
- .fini = _nouveau_mpeg_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c
deleted file mode 100644
index 72c7f33fd29b..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv44.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/client.h>
-#include <core/engctx.h>
-#include <core/handle.h>
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-#include <subdev/instmem.h>
-
-#include <engine/fifo.h>
-#include <engine/mpeg.h>
-
-struct nv44_mpeg_priv {
- struct nouveau_mpeg base;
-};
-
-struct nv44_mpeg_chan {
- struct nouveau_mpeg_chan base;
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-static int
-nv44_mpeg_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv44_mpeg_chan *chan;
- int ret;
-
- ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL,
- 264 * 4, 16,
- NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
- return 0;
-}
-
-static int
-nv44_mpeg_context_fini(struct nouveau_object *object, bool suspend)
-{
-
- struct nv44_mpeg_priv *priv = (void *)object->engine;
- struct nv44_mpeg_chan *chan = (void *)object;
- u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
-
- nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
- if (nv_rd32(priv, 0x00b318) == inst)
- nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
- nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
- return 0;
-}
-
-static struct nouveau_oclass
-nv44_mpeg_cclass = {
- .handle = NV_ENGCTX(MPEG, 0x44),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv44_mpeg_context_ctor,
- .dtor = _nouveau_mpeg_context_dtor,
- .init = _nouveau_mpeg_context_init,
- .fini = nv44_mpeg_context_fini,
- .rd32 = _nouveau_mpeg_context_rd32,
- .wr32 = _nouveau_mpeg_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-static void
-nv44_mpeg_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(subdev);
- struct nouveau_engine *engine = nv_engine(subdev);
- struct nouveau_object *engctx;
- struct nouveau_handle *handle;
- struct nv44_mpeg_priv *priv = (void *)subdev;
- u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff;
- u32 stat = nv_rd32(priv, 0x00b100);
- u32 type = nv_rd32(priv, 0x00b230);
- u32 mthd = nv_rd32(priv, 0x00b234);
- u32 data = nv_rd32(priv, 0x00b238);
- u32 show = stat;
- int chid;
-
- engctx = nouveau_engctx_get(engine, inst);
- chid = pfifo->chid(pfifo, engctx);
-
- if (stat & 0x01000000) {
- /* happens on initial binding of the object */
- if (type == 0x00000020 && mthd == 0x0000) {
- nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
- show &= ~0x01000000;
- }
-
- if (type == 0x00000010) {
- handle = nouveau_handle_get_class(engctx, 0x3174);
- if (handle && !nv_call(handle->object, mthd, data))
- show &= ~0x01000000;
- nouveau_handle_put(handle);
- }
- }
-
- nv_wr32(priv, 0x00b100, stat);
- nv_wr32(priv, 0x00b230, 0x00000001);
-
- if (show) {
- nv_error(priv,
- "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
- chid, inst << 4, nouveau_client_name(engctx), stat,
- type, mthd, data);
- }
-
- nouveau_engctx_put(engctx);
-}
-
-static void
-nv44_mpeg_me_intr(struct nouveau_subdev *subdev)
-{
- struct nv44_mpeg_priv *priv = (void *)subdev;
- u32 stat;
-
- if ((stat = nv_rd32(priv, 0x00b100)))
- nv44_mpeg_intr(subdev);
-
- if ((stat = nv_rd32(priv, 0x00b800))) {
- nv_error(priv, "PMSRCH 0x%08x\n", stat);
- nv_wr32(priv, 0x00b800, stat);
- }
-}
-
-static int
-nv44_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv44_mpeg_priv *priv;
- int ret;
-
- ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000002;
- nv_subdev(priv)->intr = nv44_mpeg_me_intr;
- nv_engine(priv)->cclass = &nv44_mpeg_cclass;
- nv_engine(priv)->sclass = nv40_mpeg_sclass;
- nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv44_mpeg_oclass = {
- .handle = NV_ENGINE(MPEG, 0x44),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv44_mpeg_ctor,
- .dtor = _nouveau_mpeg_dtor,
- .init = nv31_mpeg_init,
- .fini = _nouveau_mpeg_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
deleted file mode 100644
index cae33f86b11a..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv50.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/timer.h>
-
-#include <engine/mpeg.h>
-
-struct nv50_mpeg_priv {
- struct nouveau_mpeg base;
-};
-
-struct nv50_mpeg_chan {
- struct nouveau_mpeg_chan base;
-};
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static int
-nv50_mpeg_object_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpuobj *obj;
- int ret;
-
- ret = nouveau_gpuobj_create(parent, engine, oclass, 0, parent,
- 16, 16, 0, &obj);
- *pobject = nv_object(obj);
- if (ret)
- return ret;
-
- nv_wo32(obj, 0x00, nv_mclass(obj));
- nv_wo32(obj, 0x04, 0x00000000);
- nv_wo32(obj, 0x08, 0x00000000);
- nv_wo32(obj, 0x0c, 0x00000000);
- return 0;
-}
-
-struct nouveau_ofuncs
-nv50_mpeg_ofuncs = {
- .ctor = nv50_mpeg_object_ctor,
- .dtor = _nouveau_gpuobj_dtor,
- .init = _nouveau_gpuobj_init,
- .fini = _nouveau_gpuobj_fini,
- .rd32 = _nouveau_gpuobj_rd32,
- .wr32 = _nouveau_gpuobj_wr32,
-};
-
-static struct nouveau_oclass
-nv50_mpeg_sclass[] = {
- { 0x3174, &nv50_mpeg_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-int
-nv50_mpeg_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_bar *bar = nouveau_bar(parent);
- struct nv50_mpeg_chan *chan;
- int ret;
-
- ret = nouveau_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4,
- 0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- nv_wo32(chan, 0x0070, 0x00801ec1);
- nv_wo32(chan, 0x007c, 0x0000037c);
- bar->flush(bar);
- return 0;
-}
-
-static struct nouveau_oclass
-nv50_mpeg_cclass = {
- .handle = NV_ENGCTX(MPEG, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_mpeg_context_ctor,
- .dtor = _nouveau_mpeg_context_dtor,
- .init = _nouveau_mpeg_context_init,
- .fini = _nouveau_mpeg_context_fini,
- .rd32 = _nouveau_mpeg_context_rd32,
- .wr32 = _nouveau_mpeg_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-void
-nv50_mpeg_intr(struct nouveau_subdev *subdev)
-{
- struct nv50_mpeg_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, 0x00b100);
- u32 type = nv_rd32(priv, 0x00b230);
- u32 mthd = nv_rd32(priv, 0x00b234);
- u32 data = nv_rd32(priv, 0x00b238);
- u32 show = stat;
-
- if (stat & 0x01000000) {
- /* happens on initial binding of the object */
- if (type == 0x00000020 && mthd == 0x0000) {
- nv_wr32(priv, 0x00b308, 0x00000100);
- show &= ~0x01000000;
- }
- }
-
- if (show) {
- nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
- stat, type, mthd, data);
- }
-
- nv_wr32(priv, 0x00b100, stat);
- nv_wr32(priv, 0x00b230, 0x00000001);
-}
-
-static void
-nv50_vpe_intr(struct nouveau_subdev *subdev)
-{
- struct nv50_mpeg_priv *priv = (void *)subdev;
-
- if (nv_rd32(priv, 0x00b100))
- nv50_mpeg_intr(subdev);
-
- if (nv_rd32(priv, 0x00b800)) {
- u32 stat = nv_rd32(priv, 0x00b800);
- nv_info(priv, "PMSRCH: 0x%08x\n", stat);
- nv_wr32(priv, 0xb800, stat);
- }
-}
-
-static int
-nv50_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_mpeg_priv *priv;
- int ret;
-
- ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00400002;
- nv_subdev(priv)->intr = nv50_vpe_intr;
- nv_engine(priv)->cclass = &nv50_mpeg_cclass;
- nv_engine(priv)->sclass = nv50_mpeg_sclass;
- return 0;
-}
-
-int
-nv50_mpeg_init(struct nouveau_object *object)
-{
- struct nv50_mpeg_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_mpeg_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x00b32c, 0x00000000);
- nv_wr32(priv, 0x00b314, 0x00000100);
- nv_wr32(priv, 0x00b0e0, 0x0000001a);
-
- nv_wr32(priv, 0x00b220, 0x00000044);
- nv_wr32(priv, 0x00b300, 0x00801ec1);
- nv_wr32(priv, 0x00b390, 0x00000000);
- nv_wr32(priv, 0x00b394, 0x00000000);
- nv_wr32(priv, 0x00b398, 0x00000000);
- nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
-
- nv_wr32(priv, 0x00b100, 0xffffffff);
- nv_wr32(priv, 0x00b140, 0xffffffff);
-
- if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
- nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
- return -EBUSY;
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-nv50_mpeg_oclass = {
- .handle = NV_ENGINE(MPEG, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_mpeg_ctor,
- .dtor = _nouveau_mpeg_dtor,
- .init = nv50_mpeg_init,
- .fini = _nouveau_mpeg_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c b/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
deleted file mode 100644
index e9cc8b116a24..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/mpeg/nv84.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/timer.h>
-
-#include <engine/mpeg.h>
-
-struct nv84_mpeg_priv {
- struct nouveau_mpeg base;
-};
-
-struct nv84_mpeg_chan {
- struct nouveau_mpeg_chan base;
-};
-
-/*******************************************************************************
- * MPEG object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_mpeg_sclass[] = {
- { 0x8274, &nv50_mpeg_ofuncs },
- {}
-};
-
-/*******************************************************************************
- * PMPEG context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_mpeg_cclass = {
- .handle = NV_ENGCTX(MPEG, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_mpeg_context_ctor,
- .dtor = _nouveau_mpeg_context_dtor,
- .init = _nouveau_mpeg_context_init,
- .fini = _nouveau_mpeg_context_fini,
- .rd32 = _nouveau_mpeg_context_rd32,
- .wr32 = _nouveau_mpeg_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PMPEG engine/subdev functions
- ******************************************************************************/
-
-static int
-nv84_mpeg_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv84_mpeg_priv *priv;
- int ret;
-
- ret = nouveau_mpeg_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000002;
- nv_subdev(priv)->intr = nv50_mpeg_intr;
- nv_engine(priv)->cclass = &nv84_mpeg_cclass;
- nv_engine(priv)->sclass = nv84_mpeg_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nv84_mpeg_oclass = {
- .handle = NV_ENGINE(MPEG, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_mpeg_ctor,
- .dtor = _nouveau_mpeg_dtor,
- .init = nv50_mpeg_init,
- .fini = _nouveau_mpeg_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
deleted file mode 100644
index 63013812f7c9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/base.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/option.h>
-#include <nvif/unpack.h>
-#include <nvif/class.h>
-#include <nvif/ioctl.h>
-
-#include <subdev/clock.h>
-
-#include "priv.h"
-
-#define QUAD_MASK 0x0f
-#define QUAD_FREE 0x01
-
-static struct nouveau_perfsig *
-nouveau_perfsig_find_(struct nouveau_perfdom *dom, const char *name, u32 size)
-{
- char path[64];
- int i;
-
- if (name[0] != '/') {
- for (i = 0; i < dom->signal_nr; i++) {
- if ( dom->signal[i].name &&
- !strncmp(name, dom->signal[i].name, size))
- return &dom->signal[i];
- }
- } else {
- for (i = 0; i < dom->signal_nr; i++) {
- snprintf(path, sizeof(path), "/%s/%02x", dom->name, i);
- if (!strncmp(name, path, size))
- return &dom->signal[i];
- }
- }
-
- return NULL;
-}
-
-struct nouveau_perfsig *
-nouveau_perfsig_find(struct nouveau_perfmon *ppm, const char *name, u32 size,
- struct nouveau_perfdom **pdom)
-{
- struct nouveau_perfdom *dom = *pdom;
- struct nouveau_perfsig *sig;
-
- if (dom == NULL) {
- list_for_each_entry(dom, &ppm->domains, head) {
- sig = nouveau_perfsig_find_(dom, name, size);
- if (sig) {
- *pdom = dom;
- return sig;
- }
- }
-
- return NULL;
- }
-
- return nouveau_perfsig_find_(dom, name, size);
-}
-
-struct nouveau_perfctr *
-nouveau_perfsig_wrap(struct nouveau_perfmon *ppm, const char *name,
- struct nouveau_perfdom **pdom)
-{
- struct nouveau_perfsig *sig;
- struct nouveau_perfctr *ctr;
-
- sig = nouveau_perfsig_find(ppm, name, strlen(name), pdom);
- if (!sig)
- return NULL;
-
- ctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
- if (ctr) {
- ctr->signal[0] = sig;
- ctr->logic_op = 0xaaaa;
- }
-
- return ctr;
-}
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-static int
-nouveau_perfctr_query(struct nouveau_object *object, void *data, u32 size)
-{
- union {
- struct nvif_perfctr_query_v0 v0;
- } *args = data;
- struct nouveau_device *device = nv_device(object);
- struct nouveau_perfmon *ppm = (void *)object->engine;
- struct nouveau_perfdom *dom = NULL, *chk;
- const bool all = nouveau_boolopt(device->cfgopt, "NvPmShowAll", false);
- const bool raw = nouveau_boolopt(device->cfgopt, "NvPmUnnamed", all);
- const char *name;
- int tmp = 0, di, si;
- int ret;
-
- nv_ioctl(object, "perfctr query size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "perfctr query vers %d iter %08x\n",
- args->v0.version, args->v0.iter);
- di = (args->v0.iter & 0xff000000) >> 24;
- si = (args->v0.iter & 0x00ffffff) - 1;
- } else
- return ret;
-
- list_for_each_entry(chk, &ppm->domains, head) {
- if (tmp++ == di) {
- dom = chk;
- break;
- }
- }
-
- if (dom == NULL || si >= (int)dom->signal_nr)
- return -EINVAL;
-
- if (si >= 0) {
- if (raw || !(name = dom->signal[si].name)) {
- snprintf(args->v0.name, sizeof(args->v0.name),
- "/%s/%02x", dom->name, si);
- } else {
- strncpy(args->v0.name, name, sizeof(args->v0.name));
- }
- }
-
- do {
- while (++si < dom->signal_nr) {
- if (all || dom->signal[si].name) {
- args->v0.iter = (di << 24) | ++si;
- return 0;
- }
- }
- si = -1;
- di = di + 1;
- dom = list_entry(dom->head.next, typeof(*dom), head);
- } while (&dom->head != &ppm->domains);
-
- args->v0.iter = 0xffffffff;
- return 0;
-}
-
-static int
-nouveau_perfctr_sample(struct nouveau_object *object, void *data, u32 size)
-{
- union {
- struct nvif_perfctr_sample none;
- } *args = data;
- struct nouveau_perfmon *ppm = (void *)object->engine;
- struct nouveau_perfctr *ctr, *tmp;
- struct nouveau_perfdom *dom;
- int ret;
-
- nv_ioctl(object, "perfctr sample size %d\n", size);
- if (nvif_unvers(args->none)) {
- nv_ioctl(object, "perfctr sample\n");
- } else
- return ret;
- ppm->sequence++;
-
- list_for_each_entry(dom, &ppm->domains, head) {
- /* sample previous batch of counters */
- if (dom->quad != QUAD_MASK) {
- dom->func->next(ppm, dom);
- tmp = NULL;
- while (!list_empty(&dom->list)) {
- ctr = list_first_entry(&dom->list,
- typeof(*ctr), head);
- if (ctr->slot < 0) break;
- if ( tmp && tmp == ctr) break;
- if (!tmp) tmp = ctr;
- dom->func->read(ppm, dom, ctr);
- ctr->slot = -1;
- list_move_tail(&ctr->head, &dom->list);
- }
- }
-
- dom->quad = QUAD_MASK;
-
- /* setup next batch of counters for sampling */
- list_for_each_entry(ctr, &dom->list, head) {
- ctr->slot = ffs(dom->quad) - 1;
- if (ctr->slot < 0)
- break;
- dom->quad &= ~(QUAD_FREE << ctr->slot);
- dom->func->init(ppm, dom, ctr);
- }
-
- if (dom->quad != QUAD_MASK)
- dom->func->next(ppm, dom);
- }
-
- return 0;
-}
-
-static int
-nouveau_perfctr_read(struct nouveau_object *object, void *data, u32 size)
-{
- union {
- struct nvif_perfctr_read_v0 v0;
- } *args = data;
- struct nouveau_perfctr *ctr = (void *)object;
- int ret;
-
- nv_ioctl(object, "perfctr read size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
- } else
- return ret;
-
- if (!ctr->clk)
- return -EAGAIN;
-
- args->v0.clk = ctr->clk;
- args->v0.ctr = ctr->ctr;
- return 0;
-}
-
-static int
-nouveau_perfctr_mthd(struct nouveau_object *object, u32 mthd,
- void *data, u32 size)
-{
- switch (mthd) {
- case NVIF_PERFCTR_V0_QUERY:
- return nouveau_perfctr_query(object, data, size);
- case NVIF_PERFCTR_V0_SAMPLE:
- return nouveau_perfctr_sample(object, data, size);
- case NVIF_PERFCTR_V0_READ:
- return nouveau_perfctr_read(object, data, size);
- default:
- break;
- }
- return -EINVAL;
-}
-
-static void
-nouveau_perfctr_dtor(struct nouveau_object *object)
-{
- struct nouveau_perfctr *ctr = (void *)object;
- if (ctr->head.next)
- list_del(&ctr->head);
- nouveau_object_destroy(&ctr->base);
-}
-
-static int
-nouveau_perfctr_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- union {
- struct nvif_perfctr_v0 v0;
- } *args = data;
- struct nouveau_perfmon *ppm = (void *)engine;
- struct nouveau_perfdom *dom = NULL;
- struct nouveau_perfsig *sig[4] = {};
- struct nouveau_perfctr *ctr;
- int ret, i;
-
- nv_ioctl(parent, "create perfctr size %d\n", size);
- if (nvif_unpack(args->v0, 0, 0, false)) {
- nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
- args->v0.version, args->v0.logic_op);
- } else
- return ret;
-
- for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) {
- sig[i] = nouveau_perfsig_find(ppm, args->v0.name[i],
- strnlen(args->v0.name[i],
- sizeof(args->v0.name[i])),
- &dom);
- if (!sig[i])
- return -EINVAL;
- }
-
- ret = nouveau_object_create(parent, engine, oclass, 0, &ctr);
- *pobject = nv_object(ctr);
- if (ret)
- return ret;
-
- ctr->slot = -1;
- ctr->logic_op = args->v0.logic_op;
- ctr->signal[0] = sig[0];
- ctr->signal[1] = sig[1];
- ctr->signal[2] = sig[2];
- ctr->signal[3] = sig[3];
- if (dom)
- list_add_tail(&ctr->head, &dom->list);
- return 0;
-}
-
-static struct nouveau_ofuncs
-nouveau_perfctr_ofuncs = {
- .ctor = nouveau_perfctr_ctor,
- .dtor = nouveau_perfctr_dtor,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- .mthd = nouveau_perfctr_mthd,
-};
-
-struct nouveau_oclass
-nouveau_perfmon_sclass[] = {
- { .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
- .ofuncs = &nouveau_perfctr_ofuncs,
- },
- {},
-};
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-static void
-nouveau_perfctx_dtor(struct nouveau_object *object)
-{
- struct nouveau_perfmon *ppm = (void *)object->engine;
- mutex_lock(&nv_subdev(ppm)->mutex);
- nouveau_engctx_destroy(&ppm->context->base);
- ppm->context = NULL;
- mutex_unlock(&nv_subdev(ppm)->mutex);
-}
-
-static int
-nouveau_perfctx_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_perfmon *ppm = (void *)engine;
- struct nouveau_perfctx *ctx;
- int ret;
-
- ret = nouveau_engctx_create(parent, engine, oclass, NULL,
- 0, 0, 0, &ctx);
- *pobject = nv_object(ctx);
- if (ret)
- return ret;
-
- mutex_lock(&nv_subdev(ppm)->mutex);
- if (ppm->context == NULL)
- ppm->context = ctx;
- mutex_unlock(&nv_subdev(ppm)->mutex);
-
- if (ctx != ppm->context)
- return -EBUSY;
-
- return 0;
-}
-
-struct nouveau_oclass
-nouveau_perfmon_cclass = {
- .handle = NV_ENGCTX(PERFMON, 0x00),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nouveau_perfctx_ctor,
- .dtor = nouveau_perfctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- },
-};
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-int
-nouveau_perfdom_new(struct nouveau_perfmon *ppm, const char *name, u32 mask,
- u32 base, u32 size_unit, u32 size_domain,
- const struct nouveau_specdom *spec)
-{
- const struct nouveau_specdom *sdom;
- const struct nouveau_specsig *ssig;
- struct nouveau_perfdom *dom;
- int i;
-
- for (i = 0; i == 0 || mask; i++) {
- u32 addr = base + (i * size_unit);
- if (i && !(mask & (1 << i)))
- continue;
-
- sdom = spec;
- while (sdom->signal_nr) {
- dom = kzalloc(sizeof(*dom) + sdom->signal_nr *
- sizeof(*dom->signal), GFP_KERNEL);
- if (!dom)
- return -ENOMEM;
-
- if (mask) {
- snprintf(dom->name, sizeof(dom->name),
- "%s/%02x/%02x", name, i,
- (int)(sdom - spec));
- } else {
- snprintf(dom->name, sizeof(dom->name),
- "%s/%02x", name, (int)(sdom - spec));
- }
-
- list_add_tail(&dom->head, &ppm->domains);
- INIT_LIST_HEAD(&dom->list);
- dom->func = sdom->func;
- dom->addr = addr;
- dom->quad = QUAD_MASK;
- dom->signal_nr = sdom->signal_nr;
-
- ssig = (sdom++)->signal;
- while (ssig->name) {
- dom->signal[ssig->signal].name = ssig->name;
- ssig++;
- }
-
- addr += size_domain;
- }
-
- mask &= ~(1 << i);
- }
-
- return 0;
-}
-
-int
-_nouveau_perfmon_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_perfmon *ppm = (void *)object;
- return nouveau_engine_fini(&ppm->base, suspend);
-}
-
-int
-_nouveau_perfmon_init(struct nouveau_object *object)
-{
- struct nouveau_perfmon *ppm = (void *)object;
- return nouveau_engine_init(&ppm->base);
-}
-
-void
-_nouveau_perfmon_dtor(struct nouveau_object *object)
-{
- struct nouveau_perfmon *ppm = (void *)object;
- struct nouveau_perfdom *dom, *tmp;
-
- list_for_each_entry_safe(dom, tmp, &ppm->domains, head) {
- list_del(&dom->head);
- kfree(dom);
- }
-
- nouveau_engine_destroy(&ppm->base);
-}
-
-int
-nouveau_perfmon_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int length, void **pobject)
-{
- struct nouveau_perfmon *ppm;
- int ret;
-
- ret = nouveau_engine_create_(parent, engine, oclass, true, "PPM",
- "perfmon", length, pobject);
- ppm = *pobject;
- if (ret)
- return ret;
-
- INIT_LIST_HEAD(&ppm->domains);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c
deleted file mode 100644
index 50696cc7b7d7..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/daemon.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static void
-pwr_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
- struct nouveau_perfctr *ctr)
-{
- u32 mask = 0x00000000;
- u32 ctrl = 0x00000001;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++)
- mask |= 1 << (ctr->signal[i] - dom->signal);
-
- nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask);
- nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl);
- nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003);
-}
-
-static void
-pwr_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
- struct nouveau_perfctr *ctr)
-{
- ctr->ctr = ppm->pwr[ctr->slot];
- ctr->clk = ppm->pwr[ppm->last];
-}
-
-static void
-pwr_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
-{
- int i;
-
- for (i = 0; i <= ppm->last; i++) {
- ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10));
- nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000);
- }
-}
-
-static const struct nouveau_funcdom
-pwr_perfctr_func = {
- .init = pwr_perfctr_init,
- .read = pwr_perfctr_read,
- .next = pwr_perfctr_next,
-};
-
-const struct nouveau_specdom
-nva3_perfmon_pwr[] = {
- { 0x20, (const struct nouveau_specsig[]) {
- { 0x00, "pwr_gr_idle" },
- { 0x04, "pwr_bsp_idle" },
- { 0x05, "pwr_vp_idle" },
- { 0x06, "pwr_ppp_idle" },
- { 0x13, "pwr_ce0_idle" },
- {}
- }, &pwr_perfctr_func },
- {}
-};
-
-const struct nouveau_specdom
-nvc0_perfmon_pwr[] = {
- { 0x20, (const struct nouveau_specsig[]) {
- { 0x00, "pwr_gr_idle" },
- { 0x04, "pwr_bsp_idle" },
- { 0x05, "pwr_vp_idle" },
- { 0x06, "pwr_ppp_idle" },
- { 0x13, "pwr_ce0_idle" },
- { 0x14, "pwr_ce1_idle" },
- {}
- }, &pwr_perfctr_func },
- {}
-};
-
-const struct nouveau_specdom
-nve0_perfmon_pwr[] = {
- { 0x20, (const struct nouveau_specsig[]) {
- { 0x00, "pwr_gr_idle" },
- { 0x04, "pwr_bsp_idle" },
- { 0x05, "pwr_vp_idle" },
- { 0x06, "pwr_ppp_idle" },
- { 0x13, "pwr_ce0_idle" },
- { 0x14, "pwr_ce1_idle" },
- { 0x15, "pwr_ce2_idle" },
- {}
- }, &pwr_perfctr_func },
- {}
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c
deleted file mode 100644
index b2a10785adb1..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static void
-nv40_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
- struct nouveau_perfctr *ctr)
-{
- struct nv40_perfmon_priv *priv = (void *)ppm;
- struct nv40_perfmon_cntr *cntr = (void *)ctr;
- u32 log = ctr->logic_op;
- u32 src = 0x00000000;
- int i;
-
- for (i = 0; i < 4 && ctr->signal[i]; i++)
- src |= (ctr->signal[i] - dom->signal) << (i * 8);
-
- nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
- nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
- nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
-}
-
-static void
-nv40_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
- struct nouveau_perfctr *ctr)
-{
- struct nv40_perfmon_priv *priv = (void *)ppm;
- struct nv40_perfmon_cntr *cntr = (void *)ctr;
-
- switch (cntr->base.slot) {
- case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break;
- case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break;
- case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
- case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
- }
- cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
-}
-
-static void
-nv40_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
-{
- struct nv40_perfmon_priv *priv = (void *)ppm;
- if (priv->sequence != ppm->sequence) {
- nv_wr32(priv, 0x400084, 0x00000020);
- priv->sequence = ppm->sequence;
- }
-}
-
-const struct nouveau_funcdom
-nv40_perfctr_func = {
- .init = nv40_perfctr_init,
- .read = nv40_perfctr_read,
- .next = nv40_perfctr_next,
-};
-
-static const struct nouveau_specdom
-nv40_perfmon[] = {
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- {}
-};
-
-int
-nv40_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv40_perfmon_oclass *mclass = (void *)oclass;
- struct nv40_perfmon_priv *priv;
- int ret;
-
- ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
- nv_engine(priv)->sclass = nouveau_perfmon_sclass;
- return 0;
-}
-
-struct nouveau_oclass *
-nv40_perfmon_oclass = &(struct nv40_perfmon_oclass) {
- .base.handle = NV_ENGINE(PERFMON, 0x40),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = _nouveau_perfmon_fini,
- },
- .doms = nv40_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h
deleted file mode 100644
index 1b5792d1df14..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv40.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __NVKM_PM_NV40_H__
-#define __NVKM_PM_NV40_H__
-
-#include "priv.h"
-
-struct nv40_perfmon_oclass {
- struct nouveau_oclass base;
- const struct nouveau_specdom *doms;
-};
-
-struct nv40_perfmon_priv {
- struct nouveau_perfmon base;
- u32 sequence;
-};
-
-int nv40_perfmon_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *data, u32 size,
- struct nouveau_object **pobject);
-
-struct nv40_perfmon_cntr {
- struct nouveau_perfctr base;
-};
-
-extern const struct nouveau_funcdom nv40_perfctr_func;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c
deleted file mode 100644
index 94217691fe67..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv50.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nv50_perfmon[] = {
- { 0x040, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x100, (const struct nouveau_specsig[]) {
- { 0xc8, "gr_idle" },
- {}
- }, &nv40_perfctr_func },
- { 0x100, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x020, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x040, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- {}
-};
-
-struct nouveau_oclass *
-nv50_perfmon_oclass = &(struct nv40_perfmon_oclass) {
- .base.handle = NV_ENGINE(PERFMON, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = _nouveau_perfmon_fini,
- },
- .doms = nv50_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c
deleted file mode 100644
index 9232c7fc6253..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nv84.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nv84_perfmon[] = {
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- {}
-};
-
-struct nouveau_oclass *
-nv84_perfmon_oclass = &(struct nv40_perfmon_oclass) {
- .base.handle = NV_ENGINE(PERFMON, 0x84),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = _nouveau_perfmon_fini,
- },
- .doms = nv84_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c
deleted file mode 100644
index 6197ebdeb648..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nva3.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nva3_perfmon[] = {
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- { 0x20, (const struct nouveau_specsig[]) {
- {}
- }, &nv40_perfctr_func },
- {}
-};
-
-static int
-nva3_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **object)
-{
- int ret = nv40_perfmon_ctor(parent, engine, oclass, data, size, object);
- if (ret == 0) {
- struct nv40_perfmon_priv *priv = (void *)*object;
- ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
- nva3_perfmon_pwr);
- if (ret)
- return ret;
-
- priv->base.last = 3;
- }
- return ret;
-}
-
-struct nouveau_oclass *
-nva3_perfmon_oclass = &(struct nv40_perfmon_oclass) {
- .base.handle = NV_ENGINE(PERFMON, 0xa3),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = _nouveau_perfmon_fini,
- },
- .doms = nva3_perfmon,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c
deleted file mode 100644
index 74b241042502..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nvc0_perfmon_hub[] = {
- {}
-};
-
-static const struct nouveau_specdom
-nvc0_perfmon_gpc[] = {
- {}
-};
-
-static const struct nouveau_specdom
-nvc0_perfmon_part[] = {
- {}
-};
-
-static void
-nvc0_perfctr_init(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
- struct nouveau_perfctr *ctr)
-{
- struct nvc0_perfmon_priv *priv = (void *)ppm;
- struct nvc0_perfmon_cntr *cntr = (void *)ctr;
- u32 log = ctr->logic_op;
- u32 src = 0x00000000;
- int i;
-
- for (i = 0; i < 4 && ctr->signal[i]; i++)
- src |= (ctr->signal[i] - dom->signal) << (i * 8);
-
- nv_wr32(priv, dom->addr + 0x09c, 0x00040002);
- nv_wr32(priv, dom->addr + 0x100, 0x00000000);
- nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src);
- nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log);
-}
-
-static void
-nvc0_perfctr_read(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom,
- struct nouveau_perfctr *ctr)
-{
- struct nvc0_perfmon_priv *priv = (void *)ppm;
- struct nvc0_perfmon_cntr *cntr = (void *)ctr;
-
- switch (cntr->base.slot) {
- case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break;
- case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break;
- case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break;
- case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break;
- }
- cntr->base.clk = nv_rd32(priv, dom->addr + 0x070);
-}
-
-static void
-nvc0_perfctr_next(struct nouveau_perfmon *ppm, struct nouveau_perfdom *dom)
-{
- struct nvc0_perfmon_priv *priv = (void *)ppm;
- nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27);
- nv_wr32(priv, dom->addr + 0x0ec, 0x00000011);
-}
-
-const struct nouveau_funcdom
-nvc0_perfctr_func = {
- .init = nvc0_perfctr_init,
- .read = nvc0_perfctr_read,
- .next = nvc0_perfctr_next,
-};
-
-int
-nvc0_perfmon_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvc0_perfmon_priv *priv = (void *)object;
- nv_mask(priv, 0x000200, 0x10000000, 0x00000000);
- nv_mask(priv, 0x000200, 0x10000000, 0x10000000);
- return nouveau_perfmon_fini(&priv->base, suspend);
-}
-
-static int
-nvc0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_perfmon_priv *priv;
- u32 mask;
- int ret;
-
- ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
- nvc0_perfmon_pwr);
- if (ret)
- return ret;
-
- /* HUB */
- ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
- nvc0_perfmon_hub);
- if (ret)
- return ret;
-
- /* GPC */
- mask = (1 << nv_rd32(priv, 0x022430)) - 1;
- mask &= ~nv_rd32(priv, 0x022504);
- mask &= ~nv_rd32(priv, 0x022584);
-
- ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000,
- 0x1000, 0x200, nvc0_perfmon_gpc);
- if (ret)
- return ret;
-
- /* PART */
- mask = (1 << nv_rd32(priv, 0x022438)) - 1;
- mask &= ~nv_rd32(priv, 0x022548);
- mask &= ~nv_rd32(priv, 0x0225c8);
-
- ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000,
- 0x1000, 0x200, nvc0_perfmon_part);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
- nv_engine(priv)->sclass = nouveau_perfmon_sclass;
- priv->base.last = 7;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_perfmon_oclass = {
- .handle = NV_ENGINE(PERFMON, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = nvc0_perfmon_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h
deleted file mode 100644
index f66bca484263..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvc0.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __NVKM_PM_NVC0_H__
-#define __NVKM_PM_NVC0_H__
-
-#include "priv.h"
-
-struct nvc0_perfmon_priv {
- struct nouveau_perfmon base;
-};
-
-struct nvc0_perfmon_cntr {
- struct nouveau_perfctr base;
-};
-
-extern const struct nouveau_funcdom nvc0_perfctr_func;
-int nvc0_perfmon_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c
deleted file mode 100644
index 71d718c12075..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nve0.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static const struct nouveau_specdom
-nve0_perfmon_hub[] = {
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "hub00_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x40, (const struct nouveau_specsig[]) {
- { 0x27, "hub01_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "hub02_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "hub03_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x40, (const struct nouveau_specsig[]) {
- { 0x03, "host_mmio_rd" },
- { 0x27, "hub04_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "hub05_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0xc0, (const struct nouveau_specsig[]) {
- { 0x74, "host_fb_rd3x" },
- { 0x75, "host_fb_rd3x_2" },
- { 0xa7, "hub06_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "hub07_user_0" },
- {}
- }, &nvc0_perfctr_func },
- {}
-};
-
-static const struct nouveau_specdom
-nve0_perfmon_gpc[] = {
- { 0xe0, (const struct nouveau_specsig[]) {
- { 0xc7, "gpc00_user_0" },
- {}
- }, &nvc0_perfctr_func },
- {}
-};
-
-static const struct nouveau_specdom
-nve0_perfmon_part[] = {
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "part00_user_0" },
- {}
- }, &nvc0_perfctr_func },
- { 0x60, (const struct nouveau_specsig[]) {
- { 0x47, "part01_user_0" },
- {}
- }, &nvc0_perfctr_func },
- {}
-};
-
-static int
-nve0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_perfmon_priv *priv;
- u32 mask;
- int ret;
-
- ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- /* PDAEMON */
- ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
- nve0_perfmon_pwr);
- if (ret)
- return ret;
-
- /* HUB */
- ret = nouveau_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
- nve0_perfmon_hub);
- if (ret)
- return ret;
-
- /* GPC */
- mask = (1 << nv_rd32(priv, 0x022430)) - 1;
- mask &= ~nv_rd32(priv, 0x022504);
- mask &= ~nv_rd32(priv, 0x022584);
-
- ret = nouveau_perfdom_new(&priv->base, "gpc", mask, 0x180000,
- 0x1000, 0x200, nve0_perfmon_gpc);
- if (ret)
- return ret;
-
- /* PART */
- mask = (1 << nv_rd32(priv, 0x022438)) - 1;
- mask &= ~nv_rd32(priv, 0x022548);
- mask &= ~nv_rd32(priv, 0x0225c8);
-
- ret = nouveau_perfdom_new(&priv->base, "part", mask, 0x1a0000,
- 0x1000, 0x200, nve0_perfmon_part);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
- nv_engine(priv)->sclass = nouveau_perfmon_sclass;
- priv->base.last = 7;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_perfmon_oclass = {
- .handle = NV_ENGINE(PERFMON, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = nvc0_perfmon_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c b/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c
deleted file mode 100644
index 47256f78a895..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/nvf0.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-/*******************************************************************************
- * Perfmon object classes
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM context
- ******************************************************************************/
-
-/*******************************************************************************
- * PPM engine/subdev functions
- ******************************************************************************/
-
-static int
-nvf0_perfmon_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_perfmon_priv *priv;
- int ret;
-
- ret = nouveau_perfmon_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
- nve0_perfmon_pwr);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = &nouveau_perfmon_cclass;
- nv_engine(priv)->sclass = nouveau_perfmon_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvf0_perfmon_oclass = {
- .handle = NV_ENGINE(PERFMON, 0xf0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvf0_perfmon_ctor,
- .dtor = _nouveau_perfmon_dtor,
- .init = _nouveau_perfmon_init,
- .fini = nvc0_perfmon_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h b/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h
deleted file mode 100644
index 0ac8714fe0ba..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/perfmon/priv.h
+++ /dev/null
@@ -1,91 +0,0 @@
-#ifndef __NVKM_PERFMON_PRIV_H__
-#define __NVKM_PERFMON_PRIV_H__
-
-#include <engine/perfmon.h>
-
-struct nouveau_perfctr {
- struct nouveau_object base;
- struct list_head head;
- struct nouveau_perfsig *signal[4];
- int slot;
- u32 logic_op;
- u32 clk;
- u32 ctr;
-};
-
-extern struct nouveau_oclass nouveau_perfmon_sclass[];
-
-struct nouveau_perfctx {
- struct nouveau_engctx base;
-};
-
-extern struct nouveau_oclass nouveau_perfmon_cclass;
-
-struct nouveau_specsig {
- u8 signal;
- const char *name;
-};
-
-struct nouveau_perfsig {
- const char *name;
-};
-
-struct nouveau_perfdom;
-struct nouveau_perfctr *
-nouveau_perfsig_wrap(struct nouveau_perfmon *, const char *,
- struct nouveau_perfdom **);
-
-struct nouveau_specdom {
- u16 signal_nr;
- const struct nouveau_specsig *signal;
- const struct nouveau_funcdom *func;
-};
-
-extern const struct nouveau_specdom nva3_perfmon_pwr[];
-extern const struct nouveau_specdom nvc0_perfmon_pwr[];
-extern const struct nouveau_specdom nve0_perfmon_pwr[];
-
-struct nouveau_perfdom {
- struct list_head head;
- struct list_head list;
- const struct nouveau_funcdom *func;
- char name[32];
- u32 addr;
- u8 quad;
- u32 signal_nr;
- struct nouveau_perfsig signal[];
-};
-
-struct nouveau_funcdom {
- void (*init)(struct nouveau_perfmon *, struct nouveau_perfdom *,
- struct nouveau_perfctr *);
- void (*read)(struct nouveau_perfmon *, struct nouveau_perfdom *,
- struct nouveau_perfctr *);
- void (*next)(struct nouveau_perfmon *, struct nouveau_perfdom *);
-};
-
-int nouveau_perfdom_new(struct nouveau_perfmon *, const char *, u32,
- u32, u32, u32, const struct nouveau_specdom *);
-
-#define nouveau_perfmon_create(p,e,o,d) \
- nouveau_perfmon_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_perfmon_dtor(p) ({ \
- struct nouveau_perfmon *c = (p); \
- _nouveau_perfmon_dtor(nv_object(c)); \
-})
-#define nouveau_perfmon_init(p) ({ \
- struct nouveau_perfmon *c = (p); \
- _nouveau_perfmon_init(nv_object(c)); \
-})
-#define nouveau_perfmon_fini(p,s) ({ \
- struct nouveau_perfmon *c = (p); \
- _nouveau_perfmon_fini(nv_object(c), (s)); \
-})
-
-int nouveau_perfmon_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_perfmon_dtor(struct nouveau_object *);
-int _nouveau_perfmon_init(struct nouveau_object *);
-int _nouveau_perfmon_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
deleted file mode 100644
index 13bf31c40aa1..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nv98.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
- */
-
-#include <engine/falcon.h>
-#include <engine/ppp.h>
-
-struct nv98_ppp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * PPP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_ppp_sclass[] = {
- { 0x88b3, &nouveau_object_ofuncs },
- { 0x85b3, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PPPP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_ppp_cclass = {
- .handle = NV_ENGCTX(PPP, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PPPP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv98_ppp_init(struct nouveau_object *object)
-{
- struct nv98_ppp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x086010, 0x0000ffd2);
- nv_wr32(priv, 0x08601c, 0x0000fff2);
- return 0;
-}
-
-static int
-nv98_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv98_ppp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
- "PPPP", "ppp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00400002;
- nv_engine(priv)->cclass = &nv98_ppp_cclass;
- nv_engine(priv)->sclass = nv98_ppp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nv98_ppp_oclass = {
- .handle = NV_ENGINE(PPP, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv98_ppp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nv98_ppp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
deleted file mode 100644
index 73719aaa62d6..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/ppp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Maarten Lankhorst
- */
-
-#include <engine/falcon.h>
-#include <engine/ppp.h>
-
-struct nvc0_ppp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * PPP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_ppp_sclass[] = {
- { 0x90b3, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PPPP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_ppp_cclass = {
- .handle = NV_ENGCTX(PPP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PPPP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_ppp_init(struct nouveau_object *object)
-{
- struct nvc0_ppp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x086010, 0x0000fff2);
- nv_wr32(priv, 0x08601c, 0x0000fff2);
- return 0;
-}
-
-static int
-nvc0_ppp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_ppp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x086000, true,
- "PPPP", "ppp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00000002;
- nv_subdev(priv)->intr = nouveau_falcon_intr;
- nv_engine(priv)->cclass = &nvc0_ppp_cclass;
- nv_engine(priv)->sclass = nvc0_ppp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_ppp_oclass = {
- .handle = NV_ENGINE(PPP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_ppp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_ppp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c b/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
deleted file mode 100644
index 64df15c7f051..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv04.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <engine/software.h>
-#include <engine/fifo.h>
-
-struct nv04_software_priv {
- struct nouveau_software base;
-};
-
-struct nv04_software_chan {
- struct nouveau_software_chan base;
-};
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nv04_software_set_ref(struct nouveau_object *object, u32 mthd,
- void *data, u32 size)
-{
- struct nouveau_object *channel = (void *)nv_engctx(object->parent);
- struct nouveau_fifo_chan *fifo = (void *)channel->parent;
- atomic_set(&fifo->refcnt, *(u32*)data);
- return 0;
-}
-
-static int
-nv04_software_flip(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv04_software_chan *chan = (void *)nv_engctx(object->parent);
- if (chan->base.flip)
- return chan->base.flip(chan->base.flip_data);
- return -EINVAL;
-}
-
-static struct nouveau_omthds
-nv04_software_omthds[] = {
- { 0x0150, 0x0150, nv04_software_set_ref },
- { 0x0500, 0x0500, nv04_software_flip },
- {}
-};
-
-static struct nouveau_oclass
-nv04_software_sclass[] = {
- { 0x006e, &nouveau_object_ofuncs, nv04_software_omthds },
- {}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nv04_software_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_software_chan *chan;
- int ret;
-
- ret = nouveau_software_context_create(parent, engine, oclass, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static struct nouveau_oclass
-nv04_software_cclass = {
- .handle = NV_ENGCTX(SW, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_software_context_ctor,
- .dtor = _nouveau_software_context_dtor,
- .init = _nouveau_software_context_init,
- .fini = _nouveau_software_context_fini,
- },
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-void
-nv04_software_intr(struct nouveau_subdev *subdev)
-{
- nv_mask(subdev, 0x000100, 0x80000000, 0x00000000);
-}
-
-static int
-nv04_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_software_priv *priv;
- int ret;
-
- ret = nouveau_software_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = &nv04_software_cclass;
- nv_engine(priv)->sclass = nv04_software_sclass;
- nv_subdev(priv)->intr = nv04_software_intr;
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_software_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(SW, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_software_ctor,
- .dtor = _nouveau_software_dtor,
- .init = _nouveau_software_init,
- .fini = _nouveau_software_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c b/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
deleted file mode 100644
index f54a2253deca..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv10.c
+++ /dev/null
@@ -1,128 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-
-#include <engine/software.h>
-
-struct nv10_software_priv {
- struct nouveau_software base;
-};
-
-struct nv10_software_chan {
- struct nouveau_software_chan base;
-};
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nv10_software_flip(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv10_software_chan *chan = (void *)nv_engctx(object->parent);
- if (chan->base.flip)
- return chan->base.flip(chan->base.flip_data);
- return -EINVAL;
-}
-
-static struct nouveau_omthds
-nv10_software_omthds[] = {
- { 0x0500, 0x0500, nv10_software_flip },
- {}
-};
-
-static struct nouveau_oclass
-nv10_software_sclass[] = {
- { 0x016e, &nouveau_object_ofuncs, nv10_software_omthds },
- {}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nv10_software_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv10_software_chan *chan;
- int ret;
-
- ret = nouveau_software_context_create(parent, engine, oclass, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- return 0;
-}
-
-static struct nouveau_oclass
-nv10_software_cclass = {
- .handle = NV_ENGCTX(SW, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv10_software_context_ctor,
- .dtor = _nouveau_software_context_dtor,
- .init = _nouveau_software_context_init,
- .fini = _nouveau_software_context_fini,
- },
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-static int
-nv10_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv10_software_priv *priv;
- int ret;
-
- ret = nouveau_software_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = &nv10_software_cclass;
- nv_engine(priv)->sclass = nv10_software_sclass;
- nv_subdev(priv)->intr = nv04_software_intr;
- return 0;
-}
-
-struct nouveau_oclass *
-nv10_software_oclass = &(struct nouveau_oclass) {
- .handle = NV_ENGINE(SW, 0x10),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv10_software_ctor,
- .dtor = _nouveau_software_dtor,
- .init = _nouveau_software_init,
- .fini = _nouveau_software_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c b/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
deleted file mode 100644
index a0fec205f9db..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.c
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/namedb.h>
-#include <core/handle.h>
-#include <core/gpuobj.h>
-#include <core/event.h>
-#include <nvif/event.h>
-
-#include <subdev/bar.h>
-
-#include <engine/disp.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nv50_software_mthd_dma_vblsem(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- struct nouveau_fifo_chan *fifo = (void *)nv_object(chan)->parent;
- struct nouveau_handle *handle;
- int ret = -EINVAL;
-
- handle = nouveau_namedb_get(nv_namedb(fifo), *(u32 *)args);
- if (!handle)
- return -ENOENT;
-
- if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
- struct nouveau_gpuobj *gpuobj = nv_gpuobj(handle->object);
- chan->vblank.ctxdma = gpuobj->node->offset >> 4;
- ret = 0;
- }
- nouveau_namedb_put(handle);
- return ret;
-}
-
-static int
-nv50_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- chan->vblank.offset = *(u32 *)args;
- return 0;
-}
-
-int
-nv50_software_mthd_vblsem_value(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- chan->vblank.value = *(u32 *)args;
- return 0;
-}
-
-int
-nv50_software_mthd_vblsem_release(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- u32 head = *(u32 *)args;
- if (head >= nouveau_disp(chan)->vblank.index_nr)
- return -EINVAL;
-
- nvkm_notify_get(&chan->vblank.notify[head]);
- return 0;
-}
-
-int
-nv50_software_mthd_flip(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- if (chan->base.flip)
- return chan->base.flip(chan->base.flip_data);
- return -EINVAL;
-}
-
-static struct nouveau_omthds
-nv50_software_omthds[] = {
- { 0x018c, 0x018c, nv50_software_mthd_dma_vblsem },
- { 0x0400, 0x0400, nv50_software_mthd_vblsem_offset },
- { 0x0404, 0x0404, nv50_software_mthd_vblsem_value },
- { 0x0408, 0x0408, nv50_software_mthd_vblsem_release },
- { 0x0500, 0x0500, nv50_software_mthd_flip },
- {}
-};
-
-static struct nouveau_oclass
-nv50_software_sclass[] = {
- { 0x506e, &nouveau_object_ofuncs, nv50_software_omthds },
- {}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nv50_software_vblsem_release(struct nvkm_notify *notify)
-{
- struct nv50_software_chan *chan =
- container_of(notify, typeof(*chan), vblank.notify[notify->index]);
- struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
- struct nouveau_bar *bar = nouveau_bar(priv);
-
- nv_wr32(priv, 0x001704, chan->vblank.channel);
- nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
- bar->flush(bar);
-
- if (nv_device(priv)->chipset == 0x50) {
- nv_wr32(priv, 0x001570, chan->vblank.offset);
- nv_wr32(priv, 0x001574, chan->vblank.value);
- } else {
- nv_wr32(priv, 0x060010, chan->vblank.offset);
- nv_wr32(priv, 0x060014, chan->vblank.value);
- }
-
- return NVKM_NOTIFY_DROP;
-}
-
-void
-nv50_software_context_dtor(struct nouveau_object *object)
-{
- struct nv50_software_chan *chan = (void *)object;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
- nvkm_notify_fini(&chan->vblank.notify[i]);
-
- nouveau_software_context_destroy(&chan->base);
-}
-
-int
-nv50_software_context_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_disp *pdisp = nouveau_disp(parent);
- struct nv50_software_cclass *pclass = (void *)oclass;
- struct nv50_software_chan *chan;
- int ret, i;
-
- ret = nouveau_software_context_create(parent, engine, oclass, &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
- ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank,
- false,
- &(struct nvif_notify_head_req_v0) {
- .head = i,
- },
- sizeof(struct nvif_notify_head_req_v0),
- sizeof(struct nvif_notify_head_rep_v0),
- &chan->vblank.notify[i]);
- if (ret)
- return ret;
- }
-
- chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
- return 0;
-}
-
-static struct nv50_software_cclass
-nv50_software_cclass = {
- .base.handle = NV_ENGCTX(SW, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_software_context_ctor,
- .dtor = nv50_software_context_dtor,
- .init = _nouveau_software_context_init,
- .fini = _nouveau_software_context_fini,
- },
- .vblank = nv50_software_vblsem_release,
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-int
-nv50_software_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_software_oclass *pclass = (void *)oclass;
- struct nv50_software_priv *priv;
- int ret;
-
- ret = nouveau_software_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_engine(priv)->cclass = pclass->cclass;
- nv_engine(priv)->sclass = pclass->sclass;
- nv_subdev(priv)->intr = nv04_software_intr;
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_software_oclass = &(struct nv50_software_oclass) {
- .base.handle = NV_ENGINE(SW, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_software_ctor,
- .dtor = _nouveau_software_dtor,
- .init = _nouveau_software_init,
- .fini = _nouveau_software_fini,
- },
- .cclass = &nv50_software_cclass.base,
- .sclass = nv50_software_sclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h b/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
deleted file mode 100644
index 41542e725b4b..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nv50.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __NVKM_SW_NV50_H__
-#define __NVKM_SW_NV50_H__
-
-#include <engine/software.h>
-
-struct nv50_software_oclass {
- struct nouveau_oclass base;
- struct nouveau_oclass *cclass;
- struct nouveau_oclass *sclass;
-};
-
-struct nv50_software_priv {
- struct nouveau_software base;
-};
-
-int nv50_software_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-struct nv50_software_cclass {
- struct nouveau_oclass base;
- int (*vblank)(struct nvkm_notify *);
-};
-
-struct nv50_software_chan {
- struct nouveau_software_chan base;
- struct {
- struct nvkm_notify notify[4];
- u32 channel;
- u32 ctxdma;
- u64 offset;
- u32 value;
- } vblank;
-};
-
-int nv50_software_context_ctor(struct nouveau_object *,
- struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv50_software_context_dtor(struct nouveau_object *);
-
-int nv50_software_mthd_vblsem_value(struct nouveau_object *, u32, void *, u32);
-int nv50_software_mthd_vblsem_release(struct nouveau_object *, u32, void *, u32);
-int nv50_software_mthd_flip(struct nouveau_object *, u32, void *, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
deleted file mode 100644
index 6af370d3a06d..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/software/nvc0.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/os.h>
-#include <core/engctx.h>
-#include <core/event.h>
-
-#include <subdev/bar.h>
-
-#include <engine/software.h>
-#include <engine/disp.h>
-
-#include "nv50.h"
-
-/*******************************************************************************
- * software object classes
- ******************************************************************************/
-
-static int
-nvc0_software_mthd_vblsem_offset(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- u64 data = *(u32 *)args;
- if (mthd == 0x0400) {
- chan->vblank.offset &= 0x00ffffffffULL;
- chan->vblank.offset |= data << 32;
- } else {
- chan->vblank.offset &= 0xff00000000ULL;
- chan->vblank.offset |= data;
- }
- return 0;
-}
-
-static int
-nvc0_software_mthd_mp_control(struct nouveau_object *object, u32 mthd,
- void *args, u32 size)
-{
- struct nv50_software_chan *chan = (void *)nv_engctx(object->parent);
- struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
- u32 data = *(u32 *)args;
-
- switch (mthd) {
- case 0x600:
- nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */
- break;
- case 0x644:
- if (data & ~0x1ffffe)
- return -EINVAL;
- nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */
- break;
- case 0x6ac:
- nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static struct nouveau_omthds
-nvc0_software_omthds[] = {
- { 0x0400, 0x0400, nvc0_software_mthd_vblsem_offset },
- { 0x0404, 0x0404, nvc0_software_mthd_vblsem_offset },
- { 0x0408, 0x0408, nv50_software_mthd_vblsem_value },
- { 0x040c, 0x040c, nv50_software_mthd_vblsem_release },
- { 0x0500, 0x0500, nv50_software_mthd_flip },
- { 0x0600, 0x0600, nvc0_software_mthd_mp_control },
- { 0x0644, 0x0644, nvc0_software_mthd_mp_control },
- { 0x06ac, 0x06ac, nvc0_software_mthd_mp_control },
- {}
-};
-
-static struct nouveau_oclass
-nvc0_software_sclass[] = {
- { 0x906e, &nouveau_object_ofuncs, nvc0_software_omthds },
- {}
-};
-
-/*******************************************************************************
- * software context
- ******************************************************************************/
-
-static int
-nvc0_software_vblsem_release(struct nvkm_notify *notify)
-{
- struct nv50_software_chan *chan =
- container_of(notify, typeof(*chan), vblank.notify[notify->index]);
- struct nv50_software_priv *priv = (void *)nv_object(chan)->engine;
- struct nouveau_bar *bar = nouveau_bar(priv);
-
- nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
- bar->flush(bar);
- nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
- nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
- nv_wr32(priv, 0x060014, chan->vblank.value);
-
- return NVKM_NOTIFY_DROP;
-}
-
-static struct nv50_software_cclass
-nvc0_software_cclass = {
- .base.handle = NV_ENGCTX(SW, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_software_context_ctor,
- .dtor = nv50_software_context_dtor,
- .init = _nouveau_software_context_init,
- .fini = _nouveau_software_context_fini,
- },
- .vblank = nvc0_software_vblsem_release,
-};
-
-/*******************************************************************************
- * software engine/subdev functions
- ******************************************************************************/
-
-struct nouveau_oclass *
-nvc0_software_oclass = &(struct nv50_software_oclass) {
- .base.handle = NV_ENGINE(SW, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_software_ctor,
- .dtor = _nouveau_software_dtor,
- .init = _nouveau_software_init,
- .fini = _nouveau_software_fini,
- },
- .cclass = &nvc0_software_cclass.base,
- .sclass = nvc0_software_sclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
deleted file mode 100644
index fd6272b8cdb2..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv84.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs, Ilia Mirkin
- */
-
-#include <engine/xtensa.h>
-#include <engine/vp.h>
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_vp_sclass[] = {
- { 0x7476, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv84_vp_cclass = {
- .handle = NV_ENGCTX(VP, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_xtensa_engctx_ctor,
- .dtor = _nouveau_engctx_dtor,
- .init = _nouveau_engctx_init,
- .fini = _nouveau_engctx_fini,
- .rd32 = _nouveau_engctx_rd32,
- .wr32 = _nouveau_engctx_wr32,
- },
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv84_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_xtensa *priv;
- int ret;
-
- ret = nouveau_xtensa_create(parent, engine, oclass, 0xf000, true,
- "PVP", "vp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x01020000;
- nv_engine(priv)->cclass = &nv84_vp_cclass;
- nv_engine(priv)->sclass = nv84_vp_sclass;
- priv->fifo_val = 0x111;
- priv->unkd28 = 0x9c544;
- return 0;
-}
-
-struct nouveau_oclass
-nv84_vp_oclass = {
- .handle = NV_ENGINE(VP, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_vp_ctor,
- .dtor = _nouveau_xtensa_dtor,
- .init = _nouveau_xtensa_init,
- .fini = _nouveau_xtensa_fini,
- .rd32 = _nouveau_xtensa_rd32,
- .wr32 = _nouveau_xtensa_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c b/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
deleted file mode 100644
index fc9ae0ff1ef5..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nv98.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
- */
-
-#include <engine/falcon.h>
-#include <engine/vp.h>
-
-struct nv98_vp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_vp_sclass[] = {
- { 0x88b2, &nouveau_object_ofuncs },
- { 0x85b2, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nv98_vp_cclass = {
- .handle = NV_ENGCTX(VP, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nv98_vp_init(struct nouveau_object *object)
-{
- struct nv98_vp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x085010, 0x0000ffd2);
- nv_wr32(priv, 0x08501c, 0x0000fff2);
- return 0;
-}
-
-static int
-nv98_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv98_vp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
- "PVP", "vp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x01020000;
- nv_engine(priv)->cclass = &nv98_vp_cclass;
- nv_engine(priv)->sclass = nv98_vp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nv98_vp_oclass = {
- .handle = NV_ENGINE(VP, 0x98),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv98_vp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nv98_vp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
deleted file mode 100644
index ac1f62aace72..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nvc0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Maarten Lankhorst
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Maarten Lankhorst
- */
-
-#include <engine/falcon.h>
-#include <engine/vp.h>
-
-struct nvc0_vp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_vp_sclass[] = {
- { 0x90b2, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nvc0_vp_cclass = {
- .handle = NV_ENGCTX(VP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nvc0_vp_init(struct nouveau_object *object)
-{
- struct nvc0_vp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x085010, 0x0000fff2);
- nv_wr32(priv, 0x08501c, 0x0000fff2);
- return 0;
-}
-
-static int
-nvc0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_vp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
- "PVP", "vp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00020000;
- nv_subdev(priv)->intr = nouveau_falcon_intr;
- nv_engine(priv)->cclass = &nvc0_vp_cclass;
- nv_engine(priv)->sclass = nvc0_vp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_vp_oclass = {
- .handle = NV_ENGINE(VP, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_vp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nvc0_vp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c b/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
deleted file mode 100644
index d4c3108479c9..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/vp/nve0.c
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/falcon.h>
-#include <engine/vp.h>
-
-struct nve0_vp_priv {
- struct nouveau_falcon base;
-};
-
-/*******************************************************************************
- * VP object classes
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_vp_sclass[] = {
- { 0x95b2, &nouveau_object_ofuncs },
- {},
-};
-
-/*******************************************************************************
- * PVP context
- ******************************************************************************/
-
-static struct nouveau_oclass
-nve0_vp_cclass = {
- .handle = NV_ENGCTX(VP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_falcon_context_ctor,
- .dtor = _nouveau_falcon_context_dtor,
- .init = _nouveau_falcon_context_init,
- .fini = _nouveau_falcon_context_fini,
- .rd32 = _nouveau_falcon_context_rd32,
- .wr32 = _nouveau_falcon_context_wr32,
- },
-};
-
-/*******************************************************************************
- * PVP engine/subdev functions
- ******************************************************************************/
-
-static int
-nve0_vp_init(struct nouveau_object *object)
-{
- struct nve0_vp_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_falcon_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x085010, 0x0000fff2);
- nv_wr32(priv, 0x08501c, 0x0000fff2);
- return 0;
-}
-
-static int
-nve0_vp_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_vp_priv *priv;
- int ret;
-
- ret = nouveau_falcon_create(parent, engine, oclass, 0x085000, true,
- "PVP", "vp", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->unit = 0x00020000;
- nv_subdev(priv)->intr = nouveau_falcon_intr;
- nv_engine(priv)->cclass = &nve0_vp_cclass;
- nv_engine(priv)->sclass = nve0_vp_sclass;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_vp_oclass = {
- .handle = NV_ENGINE(VP, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_vp_ctor,
- .dtor = _nouveau_falcon_dtor,
- .init = nve0_vp_init,
- .fini = _nouveau_falcon_fini,
- .rd32 = _nouveau_falcon_rd32,
- .wr32 = _nouveau_falcon_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/engine/xtensa.c b/drivers/gpu/drm/nouveau/core/engine/xtensa.c
deleted file mode 100644
index 92384759d2f5..000000000000
--- a/drivers/gpu/drm/nouveau/core/engine/xtensa.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright 2013 Ilia Mirkin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- */
-
-#include <engine/xtensa.h>
-
-u32
-_nouveau_xtensa_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_xtensa *xtensa = (void *)object;
- return nv_rd32(xtensa, xtensa->addr + addr);
-}
-
-void
-_nouveau_xtensa_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_xtensa *xtensa = (void *)object;
- nv_wr32(xtensa, xtensa->addr + addr, data);
-}
-
-int
-_nouveau_xtensa_engctx_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_engctx *engctx;
- int ret;
-
- ret = nouveau_engctx_create(parent, engine, oclass, NULL,
- 0x10000, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &engctx);
- *pobject = nv_object(engctx);
- return ret;
-}
-
-void
-_nouveau_xtensa_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_xtensa *xtensa = (void *)subdev;
- u32 unk104 = nv_ro32(xtensa, 0xd04);
- u32 intr = nv_ro32(xtensa, 0xc20);
- u32 chan = nv_ro32(xtensa, 0xc28);
- u32 unk10c = nv_ro32(xtensa, 0xd0c);
-
- if (intr & 0x10)
- nv_warn(xtensa, "Watchdog interrupt, engine hung.\n");
- nv_wo32(xtensa, 0xc20, intr);
- intr = nv_ro32(xtensa, 0xc20);
- if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
- nv_debug(xtensa, "Enabling FIFO_CTRL\n");
- nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
- }
-}
-
-int
-nouveau_xtensa_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 addr, bool enable,
- const char *iname, const char *fname,
- int length, void **pobject)
-{
- struct nouveau_xtensa *xtensa;
- int ret;
-
- ret = nouveau_engine_create_(parent, engine, oclass, enable, iname,
- fname, length, pobject);
- xtensa = *pobject;
- if (ret)
- return ret;
-
- nv_subdev(xtensa)->intr = _nouveau_xtensa_intr;
-
- xtensa->addr = addr;
-
- return 0;
-}
-
-int
-_nouveau_xtensa_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nouveau_xtensa *xtensa = (void *)object;
- const struct firmware *fw;
- char name[32];
- int i, ret;
- u32 tmp;
-
- ret = nouveau_engine_init(&xtensa->base);
- if (ret)
- return ret;
-
- if (!xtensa->gpu_fw) {
- snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
- xtensa->addr >> 12);
-
- ret = request_firmware(&fw, name, nv_device_base(device));
- if (ret) {
- nv_warn(xtensa, "unable to load firmware %s\n", name);
- return ret;
- }
-
- if (fw->size > 0x40000) {
- nv_warn(xtensa, "firmware %s too large\n", name);
- release_firmware(fw);
- return -EINVAL;
- }
-
- ret = nouveau_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
- &xtensa->gpu_fw);
- if (ret) {
- release_firmware(fw);
- return ret;
- }
-
- nv_debug(xtensa, "Loading firmware to address: 0x%llx\n",
- xtensa->gpu_fw->addr);
-
- for (i = 0; i < fw->size / 4; i++)
- nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
- release_firmware(fw);
- }
-
- nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
- nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */
-
- nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
- nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
- nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
-
- nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
- nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
- nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */
-
- tmp = nv_rd32(xtensa, 0x0);
- nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */
-
- nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */
-
- nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
- nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
-
- return 0;
-}
-
-int
-_nouveau_xtensa_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_xtensa *xtensa = (void *)object;
-
- nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
- nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */
-
- if (!suspend)
- nouveau_gpuobj_ref(NULL, &xtensa->gpu_fw);
-
- return nouveau_engine_fini(&xtensa->base, suspend);
-}
diff --git a/drivers/gpu/drm/nouveau/core/include/core/client.h b/drivers/gpu/drm/nouveau/core/include/core/client.h
deleted file mode 100644
index b0ce9f6680b5..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/client.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __NOUVEAU_CLIENT_H__
-#define __NOUVEAU_CLIENT_H__
-
-#include <core/namedb.h>
-
-struct nouveau_client {
- struct nouveau_namedb base;
- struct nouveau_handle *root;
- struct nouveau_object *device;
- char name[32];
- u32 debug;
- struct nouveau_vm *vm;
- bool super;
- void *data;
-
- int (*ntfy)(const void *, u32, const void *, u32);
- struct nvkm_client_notify *notify[16];
-};
-
-static inline struct nouveau_client *
-nv_client(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS)))
- nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-static inline struct nouveau_client *
-nouveau_client(void *obj)
-{
- struct nouveau_object *client = nv_object(obj);
- while (client && !(nv_iclass(client, NV_CLIENT_CLASS)))
- client = client->parent;
- return (void *)client;
-}
-
-#define nouveau_client_create(n,c,oc,od,d) \
- nouveau_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d)
-
-int nouveau_client_create_(const char *name, u64 device, const char *cfg,
- const char *dbg, int, void **);
-#define nouveau_client_destroy(p) \
- nouveau_namedb_destroy(&(p)->base)
-
-int nouveau_client_init(struct nouveau_client *);
-int nouveau_client_fini(struct nouveau_client *, bool suspend);
-const char *nouveau_client_name(void *obj);
-
-int nvkm_client_notify_new(struct nouveau_object *, struct nvkm_event *,
- void *data, u32 size);
-int nvkm_client_notify_del(struct nouveau_client *, int index);
-int nvkm_client_notify_get(struct nouveau_client *, int index);
-int nvkm_client_notify_put(struct nouveau_client *, int index);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/debug.h b/drivers/gpu/drm/nouveau/core/include/core/debug.h
deleted file mode 100644
index 8092e2e90323..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/debug.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __NOUVEAU_DEBUG_H__
-#define __NOUVEAU_DEBUG_H__
-
-extern int nv_info_debug_level;
-
-#define NV_DBG_FATAL 0
-#define NV_DBG_ERROR 1
-#define NV_DBG_WARN 2
-#define NV_DBG_INFO nv_info_debug_level
-#define NV_DBG_DEBUG 4
-#define NV_DBG_TRACE 5
-#define NV_DBG_PARANOIA 6
-#define NV_DBG_SPAM 7
-
-#define NV_DBG_INFO_NORMAL 3
-#define NV_DBG_INFO_SILENT NV_DBG_DEBUG
-
-#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/device.h b/drivers/gpu/drm/nouveau/core/include/core/device.h
deleted file mode 100644
index 2ec2e50d3676..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/device.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef __NOUVEAU_DEVICE_H__
-#define __NOUVEAU_DEVICE_H__
-
-#include <core/object.h>
-#include <core/subdev.h>
-#include <core/engine.h>
-#include <core/event.h>
-
-enum nv_subdev_type {
- NVDEV_ENGINE_DEVICE,
- NVDEV_SUBDEV_VBIOS,
-
- /* All subdevs from DEVINIT to DEVINIT_LAST will be created before
- * *any* of them are initialised. This subdev category is used
- * for any subdevs that the VBIOS init table parsing may call out
- * to during POST.
- */
- NVDEV_SUBDEV_DEVINIT,
- NVDEV_SUBDEV_IBUS,
- NVDEV_SUBDEV_GPIO,
- NVDEV_SUBDEV_I2C,
- NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
-
- /* This grouping of subdevs are initialised right after they've
- * been created, and are allowed to assume any subdevs in the
- * list above them exist and have been initialised.
- */
- NVDEV_SUBDEV_FUSE,
- NVDEV_SUBDEV_MXM,
- NVDEV_SUBDEV_MC,
- NVDEV_SUBDEV_BUS,
- NVDEV_SUBDEV_TIMER,
- NVDEV_SUBDEV_FB,
- NVDEV_SUBDEV_LTC,
- NVDEV_SUBDEV_INSTMEM,
- NVDEV_SUBDEV_VM,
- NVDEV_SUBDEV_BAR,
- NVDEV_SUBDEV_PWR,
- NVDEV_SUBDEV_VOLT,
- NVDEV_SUBDEV_THERM,
- NVDEV_SUBDEV_CLOCK,
-
- NVDEV_ENGINE_FIRST,
- NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
- NVDEV_ENGINE_IFB,
- NVDEV_ENGINE_FIFO,
- NVDEV_ENGINE_SW,
- NVDEV_ENGINE_GR,
- NVDEV_ENGINE_MPEG,
- NVDEV_ENGINE_ME,
- NVDEV_ENGINE_VP,
- NVDEV_ENGINE_CRYPT,
- NVDEV_ENGINE_BSP,
- NVDEV_ENGINE_PPP,
- NVDEV_ENGINE_COPY0,
- NVDEV_ENGINE_COPY1,
- NVDEV_ENGINE_COPY2,
- NVDEV_ENGINE_VIC,
- NVDEV_ENGINE_VENC,
- NVDEV_ENGINE_DISP,
- NVDEV_ENGINE_PERFMON,
-
- NVDEV_SUBDEV_NR,
-};
-
-struct nouveau_device {
- struct nouveau_engine base;
- struct list_head head;
-
- struct pci_dev *pdev;
- struct platform_device *platformdev;
- u64 handle;
-
- struct nvkm_event event;
-
- const char *cfgopt;
- const char *dbgopt;
- const char *name;
- const char *cname;
- u64 disable_mask;
-
- enum {
- NV_04 = 0x04,
- NV_10 = 0x10,
- NV_11 = 0x11,
- NV_20 = 0x20,
- NV_30 = 0x30,
- NV_40 = 0x40,
- NV_50 = 0x50,
- NV_C0 = 0xc0,
- NV_E0 = 0xe0,
- GM100 = 0x110,
- } card_type;
- u32 chipset;
- u8 chiprev;
- u32 crystal;
-
- struct nouveau_oclass *oclass[NVDEV_SUBDEV_NR];
- struct nouveau_object *subdev[NVDEV_SUBDEV_NR];
-
- struct {
- struct notifier_block nb;
- } acpi;
-};
-
-int nouveau_device_list(u64 *name, int size);
-
-static inline struct nouveau_device *
-nv_device(void *obj)
-{
- struct nouveau_object *object = nv_object(obj);
- struct nouveau_object *device = object;
-
- if (device->engine)
- device = device->engine;
- if (device->parent)
- device = device->parent;
-
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(device, NV_SUBDEV_CLASS) ||
- (nv_hclass(device) & 0xff) != NVDEV_ENGINE_DEVICE)) {
- nv_assert("BAD CAST -> NvDevice, 0x%08x 0x%08x",
- nv_hclass(object), nv_hclass(device));
- }
-#endif
-
- return (void *)device;
-}
-
-static inline struct nouveau_subdev *
-nouveau_subdev(void *obj, int sub)
-{
- if (nv_device(obj)->subdev[sub])
- return nv_subdev(nv_device(obj)->subdev[sub]);
- return NULL;
-}
-
-static inline struct nouveau_engine *
-nouveau_engine(void *obj, int sub)
-{
- struct nouveau_subdev *subdev = nouveau_subdev(obj, sub);
- if (subdev && nv_iclass(subdev, NV_ENGINE_CLASS))
- return nv_engine(subdev);
- return NULL;
-}
-
-static inline bool
-nv_device_match(struct nouveau_object *object, u16 dev, u16 ven, u16 sub)
-{
- struct nouveau_device *device = nv_device(object);
- return device->pdev->device == dev &&
- device->pdev->subsystem_vendor == ven &&
- device->pdev->subsystem_device == sub;
-}
-
-static inline bool
-nv_device_is_pci(struct nouveau_device *device)
-{
- return device->pdev != NULL;
-}
-
-static inline bool
-nv_device_is_cpu_coherent(struct nouveau_device *device)
-{
- return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device));
-}
-
-static inline struct device *
-nv_device_base(struct nouveau_device *device)
-{
- return nv_device_is_pci(device) ? &device->pdev->dev :
- &device->platformdev->dev;
-}
-
-resource_size_t
-nv_device_resource_start(struct nouveau_device *device, unsigned int bar);
-
-resource_size_t
-nv_device_resource_len(struct nouveau_device *device, unsigned int bar);
-
-int
-nv_device_get_irq(struct nouveau_device *device, bool stall);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/engctx.h b/drivers/gpu/drm/nouveau/core/include/core/engctx.h
deleted file mode 100644
index 2fd48b564c7d..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/engctx.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef __NOUVEAU_ENGCTX_H__
-#define __NOUVEAU_ENGCTX_H__
-
-#include <core/object.h>
-#include <core/gpuobj.h>
-
-#include <subdev/vm.h>
-
-#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng))
-#define NV_ENGCTX(name,var) NV_ENGCTX_(NVDEV_ENGINE_##name, (var))
-
-struct nouveau_engctx {
- struct nouveau_gpuobj base;
- struct nouveau_vma vma;
- struct list_head head;
- unsigned long save;
- u64 addr;
-};
-
-static inline struct nouveau_engctx *
-nv_engctx(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS)))
- nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-#define nouveau_engctx_create(p,e,c,g,s,a,f,d) \
- nouveau_engctx_create_((p), (e), (c), (g), (s), (a), (f), \
- sizeof(**d), (void **)d)
-
-int nouveau_engctx_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, struct nouveau_object *,
- u32 size, u32 align, u32 flags,
- int length, void **data);
-void nouveau_engctx_destroy(struct nouveau_engctx *);
-int nouveau_engctx_init(struct nouveau_engctx *);
-int nouveau_engctx_fini(struct nouveau_engctx *, bool suspend);
-
-int _nouveau_engctx_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void _nouveau_engctx_dtor(struct nouveau_object *);
-int _nouveau_engctx_init(struct nouveau_object *);
-int _nouveau_engctx_fini(struct nouveau_object *, bool suspend);
-#define _nouveau_engctx_rd32 _nouveau_gpuobj_rd32
-#define _nouveau_engctx_wr32 _nouveau_gpuobj_wr32
-
-struct nouveau_object *nouveau_engctx_get(struct nouveau_engine *, u64 addr);
-void nouveau_engctx_put(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/engine.h b/drivers/gpu/drm/nouveau/core/include/core/engine.h
deleted file mode 100644
index 666d06de77ec..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/engine.h
+++ /dev/null
@@ -1,57 +0,0 @@
-#ifndef __NOUVEAU_ENGINE_H__
-#define __NOUVEAU_ENGINE_H__
-
-#include <core/object.h>
-#include <core/subdev.h>
-
-#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng))
-#define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var))
-
-struct nouveau_engine {
- struct nouveau_subdev base;
- struct nouveau_oclass *cclass;
- struct nouveau_oclass *sclass;
-
- struct list_head contexts;
- spinlock_t lock;
-
- void (*tile_prog)(struct nouveau_engine *, int region);
- int (*tlb_flush)(struct nouveau_engine *);
-};
-
-static inline struct nouveau_engine *
-nv_engine(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS)))
- nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-static inline int
-nv_engidx(struct nouveau_object *object)
-{
- return nv_subidx(object);
-}
-
-#define nouveau_engine_create(p,e,c,d,i,f,r) \
- nouveau_engine_create_((p), (e), (c), (d), (i), (f), \
- sizeof(**r),(void **)r)
-
-#define nouveau_engine_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_engine_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_engine_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_engine_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, bool, const char *,
- const char *, int, void **);
-
-#define _nouveau_engine_dtor _nouveau_subdev_dtor
-#define _nouveau_engine_init _nouveau_subdev_init
-#define _nouveau_engine_fini _nouveau_subdev_fini
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/enum.h b/drivers/gpu/drm/nouveau/core/include/core/enum.h
deleted file mode 100644
index 4fc62bb8c1f0..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/enum.h
+++ /dev/null
@@ -1,24 +0,0 @@
-#ifndef __NOUVEAU_ENUM_H__
-#define __NOUVEAU_ENUM_H__
-
-struct nouveau_enum {
- u32 value;
- const char *name;
- const void *data;
- u32 data2;
-};
-
-const struct nouveau_enum *
-nouveau_enum_find(const struct nouveau_enum *, u32 value);
-
-const struct nouveau_enum *
-nouveau_enum_print(const struct nouveau_enum *en, u32 value);
-
-struct nouveau_bitfield {
- u32 mask;
- const char *name;
-};
-
-void nouveau_bitfield_print(const struct nouveau_bitfield *, u32 value);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/event.h b/drivers/gpu/drm/nouveau/core/include/core/event.h
deleted file mode 100644
index 92876528972f..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/event.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NVKM_EVENT_H__
-#define __NVKM_EVENT_H__
-
-#include <core/notify.h>
-
-struct nvkm_event_func {
- int (*ctor)(struct nouveau_object *, void *data, u32 size,
- struct nvkm_notify *);
- void (*send)(void *data, u32 size, struct nvkm_notify *);
- void (*init)(struct nvkm_event *, int type, int index);
- void (*fini)(struct nvkm_event *, int type, int index);
-};
-
-struct nvkm_event {
- const struct nvkm_event_func *func;
-
- int types_nr;
- int index_nr;
-
- spinlock_t refs_lock;
- spinlock_t list_lock;
- struct list_head list;
- int *refs;
-};
-
-int nvkm_event_init(const struct nvkm_event_func *func,
- int types_nr, int index_nr,
- struct nvkm_event *);
-void nvkm_event_fini(struct nvkm_event *);
-void nvkm_event_get(struct nvkm_event *, u32 types, int index);
-void nvkm_event_put(struct nvkm_event *, u32 types, int index);
-void nvkm_event_send(struct nvkm_event *, u32 types, int index,
- void *data, u32 size);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h b/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
deleted file mode 100644
index b3b9ce4e9d38..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/gpuobj.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __NOUVEAU_GPUOBJ_H__
-#define __NOUVEAU_GPUOBJ_H__
-
-#include <core/object.h>
-#include <core/device.h>
-#include <core/parent.h>
-#include <core/mm.h>
-
-struct nouveau_vma;
-struct nouveau_vm;
-
-#define NVOBJ_FLAG_ZERO_ALLOC 0x00000001
-#define NVOBJ_FLAG_ZERO_FREE 0x00000002
-#define NVOBJ_FLAG_HEAP 0x00000004
-
-struct nouveau_gpuobj {
- struct nouveau_object base;
- struct nouveau_object *parent;
- struct nouveau_mm_node *node;
- struct nouveau_mm heap;
-
- u32 flags;
- u64 addr;
- u32 size;
-};
-
-static inline struct nouveau_gpuobj *
-nv_gpuobj(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS)))
- nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-#define nouveau_gpuobj_create(p,e,c,v,g,s,a,f,d) \
- nouveau_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f), \
- sizeof(**d), (void **)d)
-#define nouveau_gpuobj_init(p) nouveau_object_init(&(p)->base)
-#define nouveau_gpuobj_fini(p,s) nouveau_object_fini(&(p)->base, (s))
-int nouveau_gpuobj_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32 pclass,
- struct nouveau_object *, u32 size, u32 align,
- u32 flags, int length, void **);
-void nouveau_gpuobj_destroy(struct nouveau_gpuobj *);
-
-int nouveau_gpuobj_new(struct nouveau_object *, struct nouveau_object *,
- u32 size, u32 align, u32 flags,
- struct nouveau_gpuobj **);
-int nouveau_gpuobj_dup(struct nouveau_object *, struct nouveau_gpuobj *,
- struct nouveau_gpuobj **);
-
-int nouveau_gpuobj_map(struct nouveau_gpuobj *, u32 acc, struct nouveau_vma *);
-int nouveau_gpuobj_map_vm(struct nouveau_gpuobj *, struct nouveau_vm *,
- u32 access, struct nouveau_vma *);
-void nouveau_gpuobj_unmap(struct nouveau_vma *);
-
-static inline void
-nouveau_gpuobj_ref(struct nouveau_gpuobj *obj, struct nouveau_gpuobj **ref)
-{
- nouveau_object_ref(&obj->base, (struct nouveau_object **)ref);
-}
-
-void _nouveau_gpuobj_dtor(struct nouveau_object *);
-int _nouveau_gpuobj_init(struct nouveau_object *);
-int _nouveau_gpuobj_fini(struct nouveau_object *, bool);
-u32 _nouveau_gpuobj_rd32(struct nouveau_object *, u64);
-void _nouveau_gpuobj_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/handle.h b/drivers/gpu/drm/nouveau/core/include/core/handle.h
deleted file mode 100644
index d22a59138a9b..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/handle.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __NOUVEAU_HANDLE_H__
-#define __NOUVEAU_HANDLE_H__
-
-struct nouveau_handle {
- struct nouveau_namedb *namedb;
- struct list_head node;
-
- struct list_head head;
- struct list_head tree;
- u32 name;
- u32 priv;
-
- u8 route;
- u64 token;
-
- struct nouveau_handle *parent;
- struct nouveau_object *object;
-};
-
-int nouveau_handle_create(struct nouveau_object *, u32 parent, u32 handle,
- struct nouveau_object *, struct nouveau_handle **);
-void nouveau_handle_destroy(struct nouveau_handle *);
-int nouveau_handle_init(struct nouveau_handle *);
-int nouveau_handle_fini(struct nouveau_handle *, bool suspend);
-
-struct nouveau_object *
-nouveau_handle_ref(struct nouveau_object *, u32 name);
-
-struct nouveau_handle *nouveau_handle_get_class(struct nouveau_object *, u16);
-struct nouveau_handle *nouveau_handle_get_vinst(struct nouveau_object *, u64);
-struct nouveau_handle *nouveau_handle_get_cinst(struct nouveau_object *, u32);
-void nouveau_handle_put(struct nouveau_handle *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/ioctl.h b/drivers/gpu/drm/nouveau/core/include/core/ioctl.h
deleted file mode 100644
index ac7935c2474e..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/ioctl.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __NVKM_IOCTL_H__
-#define __NVKM_IOCTL_H__
-
-int nvkm_ioctl(struct nouveau_client *, bool, void *, u32, void **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/mm.h b/drivers/gpu/drm/nouveau/core/include/core/mm.h
deleted file mode 100644
index bfe6931544fe..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/mm.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __NOUVEAU_MM_H__
-#define __NOUVEAU_MM_H__
-
-struct nouveau_mm_node {
- struct list_head nl_entry;
- struct list_head fl_entry;
- struct list_head rl_entry;
-
-#define NVKM_MM_HEAP_ANY 0x00
- u8 heap;
-#define NVKM_MM_TYPE_NONE 0x00
-#define NVKM_MM_TYPE_HOLE 0xff
- u8 type;
- u32 offset;
- u32 length;
-};
-
-struct nouveau_mm {
- struct list_head nodes;
- struct list_head free;
-
- u32 block_size;
- int heap_nodes;
-};
-
-static inline bool
-nouveau_mm_initialised(struct nouveau_mm *mm)
-{
- return mm->block_size != 0;
-}
-
-int nouveau_mm_init(struct nouveau_mm *, u32 offset, u32 length, u32 block);
-int nouveau_mm_fini(struct nouveau_mm *);
-int nouveau_mm_head(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
- u32 size_min, u32 align, struct nouveau_mm_node **);
-int nouveau_mm_tail(struct nouveau_mm *, u8 heap, u8 type, u32 size_max,
- u32 size_min, u32 align, struct nouveau_mm_node **);
-void nouveau_mm_free(struct nouveau_mm *, struct nouveau_mm_node **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/namedb.h b/drivers/gpu/drm/nouveau/core/include/core/namedb.h
deleted file mode 100644
index f5b5fd8e1fc9..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/namedb.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NOUVEAU_NAMEDB_H__
-#define __NOUVEAU_NAMEDB_H__
-
-#include <core/parent.h>
-
-struct nouveau_handle;
-
-struct nouveau_namedb {
- struct nouveau_parent base;
- rwlock_t lock;
- struct list_head list;
-};
-
-static inline struct nouveau_namedb *
-nv_namedb(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS)))
- nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-#define nouveau_namedb_create(p,e,c,v,s,m,d) \
- nouveau_namedb_create_((p), (e), (c), (v), (s), (m), \
- sizeof(**d), (void **)d)
-#define nouveau_namedb_init(p) \
- nouveau_parent_init(&(p)->base)
-#define nouveau_namedb_fini(p,s) \
- nouveau_parent_fini(&(p)->base, (s))
-#define nouveau_namedb_destroy(p) \
- nouveau_parent_destroy(&(p)->base)
-
-int nouveau_namedb_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32 pclass,
- struct nouveau_oclass *, u64 engcls,
- int size, void **);
-
-int _nouveau_namedb_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-#define _nouveau_namedb_dtor _nouveau_parent_dtor
-#define _nouveau_namedb_init _nouveau_parent_init
-#define _nouveau_namedb_fini _nouveau_parent_fini
-
-int nouveau_namedb_insert(struct nouveau_namedb *, u32 name,
- struct nouveau_object *, struct nouveau_handle *);
-void nouveau_namedb_remove(struct nouveau_handle *);
-
-struct nouveau_handle *nouveau_namedb_get(struct nouveau_namedb *, u32);
-struct nouveau_handle *nouveau_namedb_get_class(struct nouveau_namedb *, u16);
-struct nouveau_handle *nouveau_namedb_get_vinst(struct nouveau_namedb *, u64);
-struct nouveau_handle *nouveau_namedb_get_cinst(struct nouveau_namedb *, u32);
-void nouveau_namedb_put(struct nouveau_handle *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/notify.h b/drivers/gpu/drm/nouveau/core/include/core/notify.h
deleted file mode 100644
index a7c3c5f578cc..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/notify.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NVKM_NOTIFY_H__
-#define __NVKM_NOTIFY_H__
-
-struct nvkm_notify {
- struct nvkm_event *event;
- struct list_head head;
-#define NVKM_NOTIFY_USER 0
-#define NVKM_NOTIFY_WORK 1
- unsigned long flags;
- int block;
-#define NVKM_NOTIFY_DROP 0
-#define NVKM_NOTIFY_KEEP 1
- int (*func)(struct nvkm_notify *);
-
- /* set by nvkm_event ctor */
- u32 types;
- int index;
- u32 size;
-
- struct work_struct work;
- /* this is const for a *very* good reason - the data might be on the
- * stack from an irq handler. if you're not core/notify.c then you
- * should probably think twice before casting it away...
- */
- const void *data;
-};
-
-int nvkm_notify_init(struct nouveau_object *, struct nvkm_event *,
- int (*func)(struct nvkm_notify *), bool work,
- void *data, u32 size, u32 reply,
- struct nvkm_notify *);
-void nvkm_notify_fini(struct nvkm_notify *);
-void nvkm_notify_get(struct nvkm_notify *);
-void nvkm_notify_put(struct nvkm_notify *);
-void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/object.h b/drivers/gpu/drm/nouveau/core/include/core/object.h
deleted file mode 100644
index 2e2afa502c99..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/object.h
+++ /dev/null
@@ -1,206 +0,0 @@
-#ifndef __NOUVEAU_OBJECT_H__
-#define __NOUVEAU_OBJECT_H__
-
-#include <core/os.h>
-#include <core/printk.h>
-
-#define NV_PARENT_CLASS 0x80000000
-#define NV_NAMEDB_CLASS 0x40000000
-#define NV_CLIENT_CLASS 0x20000000
-#define NV_SUBDEV_CLASS 0x10000000
-#define NV_ENGINE_CLASS 0x08000000
-#define NV_MEMOBJ_CLASS 0x04000000
-#define NV_GPUOBJ_CLASS 0x02000000
-#define NV_ENGCTX_CLASS 0x01000000
-#define NV_OBJECT_CLASS 0x0000ffff
-
-struct nouveau_object {
- struct nouveau_oclass *oclass;
- struct nouveau_object *parent;
- struct nouveau_object *engine;
- atomic_t refcount;
- atomic_t usecount;
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
-#define NOUVEAU_OBJECT_MAGIC 0x75ef0bad
- struct list_head list;
- u32 _magic;
-#endif
-};
-
-static inline struct nouveau_object *
-nv_object(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (likely(obj)) {
- struct nouveau_object *object = obj;
- if (unlikely(object->_magic != NOUVEAU_OBJECT_MAGIC))
- nv_assert("BAD CAST -> NvObject, invalid magic");
- }
-#endif
- return obj;
-}
-
-#define nouveau_object_create(p,e,c,s,d) \
- nouveau_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d)
-int nouveau_object_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32, int size, void **);
-void nouveau_object_destroy(struct nouveau_object *);
-int nouveau_object_init(struct nouveau_object *);
-int nouveau_object_fini(struct nouveau_object *, bool suspend);
-
-int _nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-extern struct nouveau_ofuncs nouveau_object_ofuncs;
-
-/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
- * ".data". */
-struct nouveau_oclass {
- u32 handle;
- struct nouveau_ofuncs * const ofuncs;
- struct nouveau_omthds * const omthds;
- struct lock_class_key lock_class_key;
-};
-
-#define nv_oclass(o) nv_object(o)->oclass
-#define nv_hclass(o) nv_oclass(o)->handle
-#define nv_iclass(o,i) (nv_hclass(o) & (i))
-#define nv_mclass(o) nv_iclass(o, NV_OBJECT_CLASS)
-
-static inline struct nouveau_object *
-nv_pclass(struct nouveau_object *parent, u32 oclass)
-{
- while (parent && !nv_iclass(parent, oclass))
- parent = parent->parent;
- return parent;
-}
-
-struct nouveau_omthds {
- u32 start;
- u32 limit;
- int (*call)(struct nouveau_object *, u32, void *, u32);
-};
-
-struct nvkm_event;
-struct nouveau_ofuncs {
- int (*ctor)(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *data, u32 size,
- struct nouveau_object **);
- void (*dtor)(struct nouveau_object *);
- int (*init)(struct nouveau_object *);
- int (*fini)(struct nouveau_object *, bool suspend);
- int (*mthd)(struct nouveau_object *, u32, void *, u32);
- int (*ntfy)(struct nouveau_object *, u32, struct nvkm_event **);
- int (* map)(struct nouveau_object *, u64 *, u32 *);
- u8 (*rd08)(struct nouveau_object *, u64 offset);
- u16 (*rd16)(struct nouveau_object *, u64 offset);
- u32 (*rd32)(struct nouveau_object *, u64 offset);
- void (*wr08)(struct nouveau_object *, u64 offset, u8 data);
- void (*wr16)(struct nouveau_object *, u64 offset, u16 data);
- void (*wr32)(struct nouveau_object *, u64 offset, u32 data);
-};
-
-static inline struct nouveau_ofuncs *
-nv_ofuncs(void *obj)
-{
- return nv_oclass(obj)->ofuncs;
-}
-
-int nouveau_object_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nouveau_object_ref(struct nouveau_object *, struct nouveau_object **);
-int nouveau_object_inc(struct nouveau_object *);
-int nouveau_object_dec(struct nouveau_object *, bool suspend);
-
-void nouveau_object_debug(void);
-
-static inline int
-nv_exec(void *obj, u32 mthd, void *data, u32 size)
-{
- struct nouveau_omthds *method = nv_oclass(obj)->omthds;
-
- while (method && method->call) {
- if (mthd >= method->start && mthd <= method->limit)
- return method->call(obj, mthd, data, size);
- method++;
- }
-
- return -EINVAL;
-}
-
-static inline int
-nv_call(void *obj, u32 mthd, u32 data)
-{
- return nv_exec(obj, mthd, &data, sizeof(data));
-}
-
-static inline u8
-nv_ro08(void *obj, u64 addr)
-{
- u8 data = nv_ofuncs(obj)->rd08(obj, addr);
- nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data);
- return data;
-}
-
-static inline u16
-nv_ro16(void *obj, u64 addr)
-{
- u16 data = nv_ofuncs(obj)->rd16(obj, addr);
- nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data);
- return data;
-}
-
-static inline u32
-nv_ro32(void *obj, u64 addr)
-{
- u32 data = nv_ofuncs(obj)->rd32(obj, addr);
- nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data);
- return data;
-}
-
-static inline void
-nv_wo08(void *obj, u64 addr, u8 data)
-{
- nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data);
- nv_ofuncs(obj)->wr08(obj, addr, data);
-}
-
-static inline void
-nv_wo16(void *obj, u64 addr, u16 data)
-{
- nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data);
- nv_ofuncs(obj)->wr16(obj, addr, data);
-}
-
-static inline void
-nv_wo32(void *obj, u64 addr, u32 data)
-{
- nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data);
- nv_ofuncs(obj)->wr32(obj, addr, data);
-}
-
-static inline u32
-nv_mo32(void *obj, u64 addr, u32 mask, u32 data)
-{
- u32 temp = nv_ro32(obj, addr);
- nv_wo32(obj, addr, (temp & ~mask) | data);
- return temp;
-}
-
-static inline int
-nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
-{
- unsigned char c1, c2;
-
- while (len--) {
- c1 = nv_ro08(obj, addr++);
- c2 = *(str++);
- if (c1 != c2)
- return c1 - c2;
- }
- return 0;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/option.h b/drivers/gpu/drm/nouveau/core/include/core/option.h
deleted file mode 100644
index ed055847887e..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/option.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __NOUVEAU_OPTION_H__
-#define __NOUVEAU_OPTION_H__
-
-#include <core/os.h>
-
-const char *nouveau_stropt(const char *optstr, const char *opt, int *len);
-bool nouveau_boolopt(const char *optstr, const char *opt, bool value);
-
-int nouveau_dbgopt(const char *optstr, const char *sub);
-
-/* compares unterminated string 'str' with zero-terminated string 'cmp' */
-static inline int
-strncasecmpz(const char *str, const char *cmp, size_t len)
-{
- if (strlen(cmp) != len)
- return len;
- return strncasecmp(str, cmp, len);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/parent.h b/drivers/gpu/drm/nouveau/core/include/core/parent.h
deleted file mode 100644
index 12da418ec70a..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/parent.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NOUVEAU_PARENT_H__
-#define __NOUVEAU_PARENT_H__
-
-#include <core/device.h>
-#include <core/object.h>
-
-struct nouveau_sclass {
- struct nouveau_sclass *sclass;
- struct nouveau_engine *engine;
- struct nouveau_oclass *oclass;
-};
-
-struct nouveau_parent {
- struct nouveau_object base;
-
- struct nouveau_sclass *sclass;
- u64 engine;
-
- int (*context_attach)(struct nouveau_object *,
- struct nouveau_object *);
- int (*context_detach)(struct nouveau_object *, bool suspend,
- struct nouveau_object *);
-
- int (*object_attach)(struct nouveau_object *parent,
- struct nouveau_object *object, u32 name);
- void (*object_detach)(struct nouveau_object *parent, int cookie);
-};
-
-static inline struct nouveau_parent *
-nv_parent(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS))))
- nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-#define nouveau_parent_create(p,e,c,v,s,m,d) \
- nouveau_parent_create_((p), (e), (c), (v), (s), (m), \
- sizeof(**d), (void **)d)
-#define nouveau_parent_init(p) \
- nouveau_object_init(&(p)->base)
-#define nouveau_parent_fini(p,s) \
- nouveau_object_fini(&(p)->base, (s))
-
-int nouveau_parent_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32 pclass,
- struct nouveau_oclass *, u64 engcls,
- int size, void **);
-void nouveau_parent_destroy(struct nouveau_parent *);
-
-void _nouveau_parent_dtor(struct nouveau_object *);
-#define _nouveau_parent_init nouveau_object_init
-#define _nouveau_parent_fini nouveau_object_fini
-
-int nouveau_parent_sclass(struct nouveau_object *, u16 handle,
- struct nouveau_object **pengine,
- struct nouveau_oclass **poclass);
-int nouveau_parent_lclass(struct nouveau_object *, u32 *, int);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/printk.h b/drivers/gpu/drm/nouveau/core/include/core/printk.h
deleted file mode 100644
index 451b6ed20b7e..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/printk.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NOUVEAU_PRINTK_H__
-#define __NOUVEAU_PRINTK_H__
-
-#include <core/os.h>
-#include <core/debug.h>
-
-struct nouveau_object;
-
-void __printf(3, 4)
-nv_printk_(struct nouveau_object *, int, const char *, ...);
-
-#define nv_printk(o,l,f,a...) do { \
- if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \
- nv_printk_(nv_object(o), NV_DBG_##l, f, ##a); \
-} while(0)
-
-#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a)
-#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a)
-#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a)
-#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a)
-#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a)
-#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
-#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
-#define nv_ioctl(o,f,a...) nv_trace(nouveau_client(o), "ioctl: "f, ##a)
-
-#define nv_assert(f,a...) do { \
- if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \
- nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a); \
- BUG_ON(1); \
-} while(0)
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/ramht.h b/drivers/gpu/drm/nouveau/core/include/core/ramht.h
deleted file mode 100644
index 47e4cacbca37..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/ramht.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NOUVEAU_RAMHT_H__
-#define __NOUVEAU_RAMHT_H__
-
-#include <core/gpuobj.h>
-
-struct nouveau_ramht {
- struct nouveau_gpuobj base;
- int bits;
-};
-
-int nouveau_ramht_insert(struct nouveau_ramht *, int chid,
- u32 handle, u32 context);
-void nouveau_ramht_remove(struct nouveau_ramht *, int cookie);
-int nouveau_ramht_new(struct nouveau_object *, struct nouveau_object *,
- u32 size, u32 align, struct nouveau_ramht **);
-
-static inline void
-nouveau_ramht_ref(struct nouveau_ramht *obj, struct nouveau_ramht **ref)
-{
- nouveau_gpuobj_ref(&obj->base, (struct nouveau_gpuobj **)ref);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/core/subdev.h b/drivers/gpu/drm/nouveau/core/include/core/subdev.h
deleted file mode 100644
index e9632e931616..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/core/subdev.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#ifndef __NOUVEAU_SUBDEV_H__
-#define __NOUVEAU_SUBDEV_H__
-
-#include <core/object.h>
-
-#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub))
-#define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var))
-
-struct nouveau_subdev {
- struct nouveau_object base;
- struct mutex mutex;
- const char *name;
- void __iomem *mmio;
- u32 debug;
- u32 unit;
-
- void (*intr)(struct nouveau_subdev *);
-};
-
-static inline struct nouveau_subdev *
-nv_subdev(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS)))
- nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-static inline int
-nv_subidx(struct nouveau_object *object)
-{
- return nv_hclass(nv_subdev(object)) & 0xff;
-}
-
-#define nouveau_subdev_create(p,e,o,v,s,f,d) \
- nouveau_subdev_create_((p), (e), (o), (v), (s), (f), \
- sizeof(**d),(void **)d)
-
-int nouveau_subdev_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32 pclass,
- const char *sname, const char *fname,
- int size, void **);
-void nouveau_subdev_destroy(struct nouveau_subdev *);
-int nouveau_subdev_init(struct nouveau_subdev *);
-int nouveau_subdev_fini(struct nouveau_subdev *, bool suspend);
-void nouveau_subdev_reset(struct nouveau_object *);
-
-void _nouveau_subdev_dtor(struct nouveau_object *);
-int _nouveau_subdev_init(struct nouveau_object *);
-int _nouveau_subdev_fini(struct nouveau_object *, bool suspend);
-
-#define s_printk(s,l,f,a...) do { \
- if ((s)->debug >= OS_DBG_##l) { \
- nv_printk((s)->base.parent, (s)->name, l, f, ##a); \
- } \
-} while(0)
-
-static inline u8
-nv_rd08(void *obj, u32 addr)
-{
- struct nouveau_subdev *subdev = nv_subdev(obj);
- u8 data = ioread8(subdev->mmio + addr);
- nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data);
- return data;
-}
-
-static inline u16
-nv_rd16(void *obj, u32 addr)
-{
- struct nouveau_subdev *subdev = nv_subdev(obj);
- u16 data = ioread16_native(subdev->mmio + addr);
- nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data);
- return data;
-}
-
-static inline u32
-nv_rd32(void *obj, u32 addr)
-{
- struct nouveau_subdev *subdev = nv_subdev(obj);
- u32 data = ioread32_native(subdev->mmio + addr);
- nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data);
- return data;
-}
-
-static inline void
-nv_wr08(void *obj, u32 addr, u8 data)
-{
- struct nouveau_subdev *subdev = nv_subdev(obj);
- nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data);
- iowrite8(data, subdev->mmio + addr);
-}
-
-static inline void
-nv_wr16(void *obj, u32 addr, u16 data)
-{
- struct nouveau_subdev *subdev = nv_subdev(obj);
- nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data);
- iowrite16_native(data, subdev->mmio + addr);
-}
-
-static inline void
-nv_wr32(void *obj, u32 addr, u32 data)
-{
- struct nouveau_subdev *subdev = nv_subdev(obj);
- nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data);
- iowrite32_native(data, subdev->mmio + addr);
-}
-
-static inline u32
-nv_mask(void *obj, u32 addr, u32 mask, u32 data)
-{
- u32 temp = nv_rd32(obj, addr);
- nv_wr32(obj, addr, (temp & ~mask) | data);
- return temp;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h b/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
deleted file mode 100644
index 67662e2c4547..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/bsp.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NOUVEAU_BSP_H__
-#define __NOUVEAU_BSP_H__
-
-extern struct nouveau_oclass nv84_bsp_oclass;
-extern struct nouveau_oclass nv98_bsp_oclass;
-extern struct nouveau_oclass nvc0_bsp_oclass;
-extern struct nouveau_oclass nve0_bsp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/copy.h b/drivers/gpu/drm/nouveau/core/include/engine/copy.h
deleted file mode 100644
index 316a28ae5f5c..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/copy.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NOUVEAU_COPY_H__
-#define __NOUVEAU_COPY_H__
-
-void nva3_copy_intr(struct nouveau_subdev *);
-
-extern struct nouveau_oclass nva3_copy_oclass;
-extern struct nouveau_oclass nvc0_copy0_oclass;
-extern struct nouveau_oclass nvc0_copy1_oclass;
-extern struct nouveau_oclass nve0_copy0_oclass;
-extern struct nouveau_oclass nve0_copy1_oclass;
-extern struct nouveau_oclass nve0_copy2_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/crypt.h b/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
deleted file mode 100644
index db975618e937..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/crypt.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __NOUVEAU_CRYPT_H__
-#define __NOUVEAU_CRYPT_H__
-
-extern struct nouveau_oclass nv84_crypt_oclass;
-extern struct nouveau_oclass nv98_crypt_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/device.h b/drivers/gpu/drm/nouveau/core/include/engine/device.h
deleted file mode 100644
index 672d3c8f4145..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/device.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __NOUVEAU_SUBDEV_DEVICE_H__
-#define __NOUVEAU_SUBDEV_DEVICE_H__
-
-#include <core/device.h>
-
-struct platform_device;
-
-enum nv_bus_type {
- NOUVEAU_BUS_PCI,
- NOUVEAU_BUS_PLATFORM,
-};
-
-#define nouveau_device_create(p,t,n,s,c,d,u) \
- nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d), \
- sizeof(**u), (void **)u)
-
-int nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
- const char *sname, const char *cfg, const char *dbg,
- int, void **);
-
-int nv04_identify(struct nouveau_device *);
-int nv10_identify(struct nouveau_device *);
-int nv20_identify(struct nouveau_device *);
-int nv30_identify(struct nouveau_device *);
-int nv40_identify(struct nouveau_device *);
-int nv50_identify(struct nouveau_device *);
-int nvc0_identify(struct nouveau_device *);
-int nve0_identify(struct nouveau_device *);
-int gm100_identify(struct nouveau_device *);
-
-struct nouveau_device *nouveau_device_find(u64 name);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/disp.h b/drivers/gpu/drm/nouveau/core/include/engine/disp.h
deleted file mode 100644
index fc307f1317ff..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/disp.h
+++ /dev/null
@@ -1,36 +0,0 @@
-#ifndef __NOUVEAU_DISP_H__
-#define __NOUVEAU_DISP_H__
-
-#include <core/object.h>
-#include <core/engine.h>
-#include <core/device.h>
-#include <core/event.h>
-
-struct nouveau_disp {
- struct nouveau_engine base;
-
- struct list_head outp;
-
- struct nvkm_event hpd;
- struct nvkm_event vblank;
-};
-
-static inline struct nouveau_disp *
-nouveau_disp(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_DISP];
-}
-
-extern struct nouveau_oclass *nv04_disp_oclass;
-extern struct nouveau_oclass *nv50_disp_oclass;
-extern struct nouveau_oclass *nv84_disp_oclass;
-extern struct nouveau_oclass *nva0_disp_oclass;
-extern struct nouveau_oclass *nv94_disp_oclass;
-extern struct nouveau_oclass *nva3_disp_oclass;
-extern struct nouveau_oclass *nvd0_disp_oclass;
-extern struct nouveau_oclass *nve0_disp_oclass;
-extern struct nouveau_oclass *nvf0_disp_oclass;
-extern struct nouveau_oclass *gm107_disp_oclass;
-extern struct nouveau_oclass *gm204_disp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h b/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
deleted file mode 100644
index 1b283a7b78e6..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/dmaobj.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NOUVEAU_DMAOBJ_H__
-#define __NOUVEAU_DMAOBJ_H__
-
-#include <core/object.h>
-#include <core/engine.h>
-
-struct nouveau_gpuobj;
-
-struct nouveau_dmaobj {
- struct nouveau_object base;
- u32 target;
- u32 access;
- u64 start;
- u64 limit;
-};
-
-struct nouveau_dmaeng {
- struct nouveau_engine base;
-
- /* creates a "physical" dma object from a struct nouveau_dmaobj */
- int (*bind)(struct nouveau_dmaobj *dmaobj,
- struct nouveau_object *parent,
- struct nouveau_gpuobj **);
-};
-
-extern struct nouveau_oclass *nv04_dmaeng_oclass;
-extern struct nouveau_oclass *nv50_dmaeng_oclass;
-extern struct nouveau_oclass *nvc0_dmaeng_oclass;
-extern struct nouveau_oclass *nvd0_dmaeng_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h b/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
deleted file mode 100644
index 181aa7da524d..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/falcon.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __NOUVEAU_FALCON_H__
-#define __NOUVEAU_FALCON_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/gpuobj.h>
-
-struct nouveau_falcon_chan {
- struct nouveau_engctx base;
-};
-
-#define nouveau_falcon_context_create(p,e,c,g,s,a,f,d) \
- nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_falcon_context_destroy(d) \
- nouveau_engctx_destroy(&(d)->base)
-#define nouveau_falcon_context_init(d) \
- nouveau_engctx_init(&(d)->base)
-#define nouveau_falcon_context_fini(d,s) \
- nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_falcon_context_ctor _nouveau_engctx_ctor
-#define _nouveau_falcon_context_dtor _nouveau_engctx_dtor
-#define _nouveau_falcon_context_init _nouveau_engctx_init
-#define _nouveau_falcon_context_fini _nouveau_engctx_fini
-#define _nouveau_falcon_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_falcon_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_falcon_data {
- bool external;
-};
-
-struct nouveau_falcon {
- struct nouveau_engine base;
-
- u32 addr;
- u8 version;
- u8 secret;
-
- struct nouveau_gpuobj *core;
- bool external;
-
- struct {
- u32 limit;
- u32 *data;
- u32 size;
- } code;
-
- struct {
- u32 limit;
- u32 *data;
- u32 size;
- } data;
-};
-
-#define nv_falcon(priv) (&(priv)->base)
-
-#define nouveau_falcon_create(p,e,c,b,d,i,f,r) \
- nouveau_falcon_create_((p), (e), (c), (b), (d), (i), (f), \
- sizeof(**r),(void **)r)
-#define nouveau_falcon_destroy(p) \
- nouveau_engine_destroy(&(p)->base)
-#define nouveau_falcon_init(p) ({ \
- struct nouveau_falcon *falcon = (p); \
- _nouveau_falcon_init(nv_object(falcon)); \
-})
-#define nouveau_falcon_fini(p,s) ({ \
- struct nouveau_falcon *falcon = (p); \
- _nouveau_falcon_fini(nv_object(falcon), (s)); \
-})
-
-int nouveau_falcon_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32, bool, const char *,
- const char *, int, void **);
-
-void nouveau_falcon_intr(struct nouveau_subdev *subdev);
-
-#define _nouveau_falcon_dtor _nouveau_engine_dtor
-int _nouveau_falcon_init(struct nouveau_object *);
-int _nouveau_falcon_fini(struct nouveau_object *, bool);
-u32 _nouveau_falcon_rd32(struct nouveau_object *, u64);
-void _nouveau_falcon_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h b/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
deleted file mode 100644
index 2007453f6fce..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/fifo.h
+++ /dev/null
@@ -1,126 +0,0 @@
-#ifndef __NOUVEAU_FIFO_H__
-#define __NOUVEAU_FIFO_H__
-
-#include <core/namedb.h>
-#include <core/gpuobj.h>
-#include <core/engine.h>
-#include <core/event.h>
-
-struct nouveau_fifo_chan {
- struct nouveau_namedb base;
- struct nouveau_dmaobj *pushdma;
- struct nouveau_gpuobj *pushgpu;
- void __iomem *user;
- u64 addr;
- u32 size;
- u16 chid;
- atomic_t refcnt; /* NV04_NVSW_SET_REF */
-};
-
-static inline struct nouveau_fifo_chan *
-nouveau_fifo_chan(void *obj)
-{
- return (void *)nv_namedb(obj);
-}
-
-#define nouveau_fifo_channel_create(p,e,c,b,a,s,n,m,d) \
- nouveau_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \
- (m), sizeof(**d), (void **)d)
-#define nouveau_fifo_channel_init(p) \
- nouveau_namedb_init(&(p)->base)
-#define nouveau_fifo_channel_fini(p,s) \
- nouveau_namedb_fini(&(p)->base, (s))
-
-int nouveau_fifo_channel_create_(struct nouveau_object *,
- struct nouveau_object *,
- struct nouveau_oclass *,
- int bar, u32 addr, u32 size, u32 push,
- u64 engmask, int len, void **);
-void nouveau_fifo_channel_destroy(struct nouveau_fifo_chan *);
-
-#define _nouveau_fifo_channel_init _nouveau_namedb_init
-#define _nouveau_fifo_channel_fini _nouveau_namedb_fini
-
-void _nouveau_fifo_channel_dtor(struct nouveau_object *);
-int _nouveau_fifo_channel_map(struct nouveau_object *, u64 *, u32 *);
-u32 _nouveau_fifo_channel_rd32(struct nouveau_object *, u64);
-void _nouveau_fifo_channel_wr32(struct nouveau_object *, u64, u32);
-int _nouveau_fifo_channel_ntfy(struct nouveau_object *, u32, struct nvkm_event **);
-
-struct nouveau_fifo_base {
- struct nouveau_gpuobj base;
-};
-
-#define nouveau_fifo_context_create(p,e,c,g,s,a,f,d) \
- nouveau_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d))
-#define nouveau_fifo_context_destroy(p) \
- nouveau_gpuobj_destroy(&(p)->base)
-#define nouveau_fifo_context_init(p) \
- nouveau_gpuobj_init(&(p)->base)
-#define nouveau_fifo_context_fini(p,s) \
- nouveau_gpuobj_fini(&(p)->base, (s))
-
-#define _nouveau_fifo_context_dtor _nouveau_gpuobj_dtor
-#define _nouveau_fifo_context_init _nouveau_gpuobj_init
-#define _nouveau_fifo_context_fini _nouveau_gpuobj_fini
-#define _nouveau_fifo_context_rd32 _nouveau_gpuobj_rd32
-#define _nouveau_fifo_context_wr32 _nouveau_gpuobj_wr32
-
-struct nouveau_fifo {
- struct nouveau_engine base;
-
- struct nvkm_event cevent; /* channel creation event */
- struct nvkm_event uevent; /* async user trigger */
-
- struct nouveau_object **channel;
- spinlock_t lock;
- u16 min;
- u16 max;
-
- int (*chid)(struct nouveau_fifo *, struct nouveau_object *);
- void (*pause)(struct nouveau_fifo *, unsigned long *);
- void (*start)(struct nouveau_fifo *, unsigned long *);
-};
-
-static inline struct nouveau_fifo *
-nouveau_fifo(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_FIFO];
-}
-
-#define nouveau_fifo_create(o,e,c,fc,lc,d) \
- nouveau_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d)
-#define nouveau_fifo_init(p) \
- nouveau_engine_init(&(p)->base)
-#define nouveau_fifo_fini(p,s) \
- nouveau_engine_fini(&(p)->base, (s))
-
-int nouveau_fifo_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int min, int max,
- int size, void **);
-void nouveau_fifo_destroy(struct nouveau_fifo *);
-const char *
-nouveau_client_name_for_fifo_chid(struct nouveau_fifo *fifo, u32 chid);
-
-#define _nouveau_fifo_init _nouveau_engine_init
-#define _nouveau_fifo_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass *nv04_fifo_oclass;
-extern struct nouveau_oclass *nv10_fifo_oclass;
-extern struct nouveau_oclass *nv17_fifo_oclass;
-extern struct nouveau_oclass *nv40_fifo_oclass;
-extern struct nouveau_oclass *nv50_fifo_oclass;
-extern struct nouveau_oclass *nv84_fifo_oclass;
-extern struct nouveau_oclass *nvc0_fifo_oclass;
-extern struct nouveau_oclass *nve0_fifo_oclass;
-extern struct nouveau_oclass *gk20a_fifo_oclass;
-extern struct nouveau_oclass *nv108_fifo_oclass;
-
-int nouveau_fifo_uevent_ctor(struct nouveau_object *, void *, u32,
- struct nvkm_notify *);
-void nouveau_fifo_uevent(struct nouveau_fifo *);
-
-void nv04_fifo_intr(struct nouveau_subdev *);
-int nv04_fifo_context_attach(struct nouveau_object *, struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/graph.h b/drivers/gpu/drm/nouveau/core/include/engine/graph.h
deleted file mode 100644
index d5055570d01b..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/graph.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef __NOUVEAU_GRAPH_H__
-#define __NOUVEAU_GRAPH_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/enum.h>
-
-struct nouveau_graph_chan {
- struct nouveau_engctx base;
-};
-
-#define nouveau_graph_context_create(p,e,c,g,s,a,f,d) \
- nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_graph_context_destroy(d) \
- nouveau_engctx_destroy(&(d)->base)
-#define nouveau_graph_context_init(d) \
- nouveau_engctx_init(&(d)->base)
-#define nouveau_graph_context_fini(d,s) \
- nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_graph_context_dtor _nouveau_engctx_dtor
-#define _nouveau_graph_context_init _nouveau_engctx_init
-#define _nouveau_graph_context_fini _nouveau_engctx_fini
-#define _nouveau_graph_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_graph_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_graph {
- struct nouveau_engine base;
-
- /* Returns chipset-specific counts of units packed into an u64.
- */
- u64 (*units)(struct nouveau_graph *);
-};
-
-static inline struct nouveau_graph *
-nouveau_graph(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_GR];
-}
-
-#define nouveau_graph_create(p,e,c,y,d) \
- nouveau_engine_create((p), (e), (c), (y), "PGRAPH", "graphics", (d))
-#define nouveau_graph_destroy(d) \
- nouveau_engine_destroy(&(d)->base)
-#define nouveau_graph_init(d) \
- nouveau_engine_init(&(d)->base)
-#define nouveau_graph_fini(d,s) \
- nouveau_engine_fini(&(d)->base, (s))
-
-#define _nouveau_graph_dtor _nouveau_engine_dtor
-#define _nouveau_graph_init _nouveau_engine_init
-#define _nouveau_graph_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass nv04_graph_oclass;
-extern struct nouveau_oclass nv10_graph_oclass;
-extern struct nouveau_oclass nv20_graph_oclass;
-extern struct nouveau_oclass nv25_graph_oclass;
-extern struct nouveau_oclass nv2a_graph_oclass;
-extern struct nouveau_oclass nv30_graph_oclass;
-extern struct nouveau_oclass nv34_graph_oclass;
-extern struct nouveau_oclass nv35_graph_oclass;
-extern struct nouveau_oclass nv40_graph_oclass;
-extern struct nouveau_oclass nv50_graph_oclass;
-extern struct nouveau_oclass *nvc0_graph_oclass;
-extern struct nouveau_oclass *nvc1_graph_oclass;
-extern struct nouveau_oclass *nvc4_graph_oclass;
-extern struct nouveau_oclass *nvc8_graph_oclass;
-extern struct nouveau_oclass *nvd7_graph_oclass;
-extern struct nouveau_oclass *nvd9_graph_oclass;
-extern struct nouveau_oclass *nve4_graph_oclass;
-extern struct nouveau_oclass *gk20a_graph_oclass;
-extern struct nouveau_oclass *nvf0_graph_oclass;
-extern struct nouveau_oclass *gk110b_graph_oclass;
-extern struct nouveau_oclass *nv108_graph_oclass;
-extern struct nouveau_oclass *gm107_graph_oclass;
-
-extern const struct nouveau_bitfield nv04_graph_nsource[];
-extern struct nouveau_ofuncs nv04_graph_ofuncs;
-bool nv04_graph_idle(void *obj);
-
-extern const struct nouveau_bitfield nv10_graph_intr_name[];
-extern const struct nouveau_bitfield nv10_graph_nstatus[];
-
-extern const struct nouveau_enum nv50_data_error_names[];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h b/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
deleted file mode 100644
index 9b0d938199f6..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/mpeg.h
+++ /dev/null
@@ -1,63 +0,0 @@
-#ifndef __NOUVEAU_MPEG_H__
-#define __NOUVEAU_MPEG_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-
-struct nouveau_mpeg_chan {
- struct nouveau_engctx base;
-};
-
-#define nouveau_mpeg_context_create(p,e,c,g,s,a,f,d) \
- nouveau_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
-#define nouveau_mpeg_context_destroy(d) \
- nouveau_engctx_destroy(&(d)->base)
-#define nouveau_mpeg_context_init(d) \
- nouveau_engctx_init(&(d)->base)
-#define nouveau_mpeg_context_fini(d,s) \
- nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_mpeg_context_dtor _nouveau_engctx_dtor
-#define _nouveau_mpeg_context_init _nouveau_engctx_init
-#define _nouveau_mpeg_context_fini _nouveau_engctx_fini
-#define _nouveau_mpeg_context_rd32 _nouveau_engctx_rd32
-#define _nouveau_mpeg_context_wr32 _nouveau_engctx_wr32
-
-struct nouveau_mpeg {
- struct nouveau_engine base;
-};
-
-#define nouveau_mpeg_create(p,e,c,d) \
- nouveau_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d))
-#define nouveau_mpeg_destroy(d) \
- nouveau_engine_destroy(&(d)->base)
-#define nouveau_mpeg_init(d) \
- nouveau_engine_init(&(d)->base)
-#define nouveau_mpeg_fini(d,s) \
- nouveau_engine_fini(&(d)->base, (s))
-
-#define _nouveau_mpeg_dtor _nouveau_engine_dtor
-#define _nouveau_mpeg_init _nouveau_engine_init
-#define _nouveau_mpeg_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass nv31_mpeg_oclass;
-extern struct nouveau_oclass nv40_mpeg_oclass;
-extern struct nouveau_oclass nv44_mpeg_oclass;
-extern struct nouveau_oclass nv50_mpeg_oclass;
-extern struct nouveau_oclass nv84_mpeg_oclass;
-extern struct nouveau_ofuncs nv31_mpeg_ofuncs;
-extern struct nouveau_oclass nv31_mpeg_cclass;
-extern struct nouveau_oclass nv31_mpeg_sclass[];
-extern struct nouveau_oclass nv40_mpeg_sclass[];
-void nv31_mpeg_intr(struct nouveau_subdev *);
-void nv31_mpeg_tile_prog(struct nouveau_engine *, int);
-int nv31_mpeg_init(struct nouveau_object *);
-
-extern struct nouveau_ofuncs nv50_mpeg_ofuncs;
-int nv50_mpeg_context_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv50_mpeg_intr(struct nouveau_subdev *);
-int nv50_mpeg_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h b/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h
deleted file mode 100644
index 88cc812baaa3..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/perfmon.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __NVKM_PERFMON_H__
-#define __NVKM_PERFMON_H__
-
-#include <core/device.h>
-#include <core/engine.h>
-#include <core/engctx.h>
-
-struct nouveau_perfdom;
-struct nouveau_perfctr;
-struct nouveau_perfmon {
- struct nouveau_engine base;
-
- struct nouveau_perfctx *context;
- void *profile_data;
-
- struct list_head domains;
- u32 sequence;
-
- /*XXX: temp for daemon backend */
- u32 pwr[8];
- u32 last;
-};
-
-static inline struct nouveau_perfmon *
-nouveau_perfmon(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_ENGINE_PERFMON];
-}
-
-extern struct nouveau_oclass *nv40_perfmon_oclass;
-extern struct nouveau_oclass *nv50_perfmon_oclass;
-extern struct nouveau_oclass *nv84_perfmon_oclass;
-extern struct nouveau_oclass *nva3_perfmon_oclass;
-extern struct nouveau_oclass nvc0_perfmon_oclass;
-extern struct nouveau_oclass nve0_perfmon_oclass;
-extern struct nouveau_oclass nvf0_perfmon_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/ppp.h b/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
deleted file mode 100644
index 0a66781e8cf1..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/ppp.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __NOUVEAU_PPP_H__
-#define __NOUVEAU_PPP_H__
-
-extern struct nouveau_oclass nv98_ppp_oclass;
-extern struct nouveau_oclass nvc0_ppp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/software.h b/drivers/gpu/drm/nouveau/core/include/engine/software.h
deleted file mode 100644
index 23a462b50d03..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/software.h
+++ /dev/null
@@ -1,51 +0,0 @@
-#ifndef __NOUVEAU_SOFTWARE_H__
-#define __NOUVEAU_SOFTWARE_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-
-struct nouveau_software_chan {
- struct nouveau_engctx base;
-
- int (*flip)(void *);
- void *flip_data;
-};
-
-#define nouveau_software_context_create(p,e,c,d) \
- nouveau_engctx_create((p), (e), (c), (p), 0, 0, 0, (d))
-#define nouveau_software_context_destroy(d) \
- nouveau_engctx_destroy(&(d)->base)
-#define nouveau_software_context_init(d) \
- nouveau_engctx_init(&(d)->base)
-#define nouveau_software_context_fini(d,s) \
- nouveau_engctx_fini(&(d)->base, (s))
-
-#define _nouveau_software_context_dtor _nouveau_engctx_dtor
-#define _nouveau_software_context_init _nouveau_engctx_init
-#define _nouveau_software_context_fini _nouveau_engctx_fini
-
-struct nouveau_software {
- struct nouveau_engine base;
-};
-
-#define nouveau_software_create(p,e,c,d) \
- nouveau_engine_create((p), (e), (c), true, "SW", "software", (d))
-#define nouveau_software_destroy(d) \
- nouveau_engine_destroy(&(d)->base)
-#define nouveau_software_init(d) \
- nouveau_engine_init(&(d)->base)
-#define nouveau_software_fini(d,s) \
- nouveau_engine_fini(&(d)->base, (s))
-
-#define _nouveau_software_dtor _nouveau_engine_dtor
-#define _nouveau_software_init _nouveau_engine_init
-#define _nouveau_software_fini _nouveau_engine_fini
-
-extern struct nouveau_oclass *nv04_software_oclass;
-extern struct nouveau_oclass *nv10_software_oclass;
-extern struct nouveau_oclass *nv50_software_oclass;
-extern struct nouveau_oclass *nvc0_software_oclass;
-
-void nv04_software_intr(struct nouveau_subdev *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/vp.h b/drivers/gpu/drm/nouveau/core/include/engine/vp.h
deleted file mode 100644
index 39baebec7fbb..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/vp.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NOUVEAU_VP_H__
-#define __NOUVEAU_VP_H__
-
-extern struct nouveau_oclass nv84_vp_oclass;
-extern struct nouveau_oclass nv98_vp_oclass;
-extern struct nouveau_oclass nvc0_vp_oclass;
-extern struct nouveau_oclass nve0_vp_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h b/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
deleted file mode 100644
index 306100f31f02..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/engine/xtensa.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __NOUVEAU_XTENSA_H__
-#define __NOUVEAU_XTENSA_H__
-
-#include <core/engine.h>
-#include <core/engctx.h>
-#include <core/gpuobj.h>
-
-struct nouveau_xtensa {
- struct nouveau_engine base;
-
- u32 addr;
- struct nouveau_gpuobj *gpu_fw;
- u32 fifo_val;
- u32 unkd28;
-};
-
-#define nouveau_xtensa_create(p,e,c,b,d,i,f,r) \
- nouveau_xtensa_create_((p), (e), (c), (b), (d), (i), (f), \
- sizeof(**r),(void **)r)
-
-int _nouveau_xtensa_engctx_ctor(struct nouveau_object *,
- struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-void _nouveau_xtensa_intr(struct nouveau_subdev *);
-int nouveau_xtensa_create_(struct nouveau_object *,
- struct nouveau_object *,
- struct nouveau_oclass *, u32, bool,
- const char *, const char *,
- int, void **);
-#define _nouveau_xtensa_dtor _nouveau_engine_dtor
-int _nouveau_xtensa_init(struct nouveau_object *);
-int _nouveau_xtensa_fini(struct nouveau_object *, bool);
-u32 _nouveau_xtensa_rd32(struct nouveau_object *, u64);
-void _nouveau_xtensa_wr32(struct nouveau_object *, u64, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/class.h b/drivers/gpu/drm/nouveau/core/include/nvif/class.h
deleted file mode 120000
index f1ac4859edd4..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/class.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/class.h \ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/event.h b/drivers/gpu/drm/nouveau/core/include/nvif/event.h
deleted file mode 120000
index 1b798538a725..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/event.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/event.h \ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h b/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h
deleted file mode 120000
index 8569c86907c5..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/ioctl.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/ioctl.h \ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h b/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h
deleted file mode 120000
index 69d99292bca4..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/nvif/unpack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../../nvif/unpack.h \ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h b/drivers/gpu/drm/nouveau/core/include/subdev/bar.h
deleted file mode 100644
index 257ddf6d36d4..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bar.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NOUVEAU_BAR_H__
-#define __NOUVEAU_BAR_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_mem;
-struct nouveau_vma;
-
-struct nouveau_bar {
- struct nouveau_subdev base;
-
- int (*alloc)(struct nouveau_bar *, struct nouveau_object *,
- struct nouveau_mem *, struct nouveau_object **);
-
- int (*kmap)(struct nouveau_bar *, struct nouveau_mem *,
- u32 flags, struct nouveau_vma *);
- int (*umap)(struct nouveau_bar *, struct nouveau_mem *,
- u32 flags, struct nouveau_vma *);
- void (*unmap)(struct nouveau_bar *, struct nouveau_vma *);
- void (*flush)(struct nouveau_bar *);
-
- /* whether the BAR supports to be ioremapped WC or should be uncached */
- bool iomap_uncached;
-};
-
-static inline struct nouveau_bar *
-nouveau_bar(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BAR];
-}
-
-extern struct nouveau_oclass nv50_bar_oclass;
-extern struct nouveau_oclass nvc0_bar_oclass;
-extern struct nouveau_oclass gk20a_bar_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios.h
deleted file mode 100644
index 5bd1ca8cd20d..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_BIOS_H__
-#define __NOUVEAU_BIOS_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_bios {
- struct nouveau_subdev base;
- u32 size;
- u8 *data;
-
- u32 bmp_offset;
- u32 bit_offset;
-
- struct {
- u8 major;
- u8 chip;
- u8 minor;
- u8 micro;
- u8 patch;
- } version;
-};
-
-static inline struct nouveau_bios *
-nouveau_bios(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VBIOS];
-}
-
-u8 nvbios_checksum(const u8 *data, int size);
-u16 nvbios_findstr(const u8 *data, int size, const char *str, int len);
-
-extern struct nouveau_oclass nouveau_bios_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h
deleted file mode 100644
index 1f84d3612dd8..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0203.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NVBIOS_M0203_H__
-#define __NVBIOS_M0203_H__
-
-struct nvbios_M0203T {
-#define M0203T_TYPE_RAMCFG 0x00
- u8 type;
- u16 pointer;
-};
-
-u32 nvbios_M0203Te(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_M0203Tp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_M0203T *);
-
-struct nvbios_M0203E {
-#define M0203E_TYPE_DDR2 0x0
-#define M0203E_TYPE_DDR3 0x1
-#define M0203E_TYPE_GDDR3 0x2
-#define M0203E_TYPE_GDDR5 0x3
-#define M0203E_TYPE_SKIP 0xf
- u8 type;
- u8 strap;
- u8 group;
-};
-
-u32 nvbios_M0203Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_M0203Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
- struct nvbios_M0203E *);
-u32 nvbios_M0203Em(struct nouveau_bios *, u8 ramcfg, u8 *ver, u8 *hdr,
- struct nvbios_M0203E *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
deleted file mode 100644
index e171120cec81..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0205.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NVBIOS_M0205_H__
-#define __NVBIOS_M0205_H__
-
-struct nvbios_M0205T {
- u16 freq;
-};
-
-u32 nvbios_M0205Te(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-u32 nvbios_M0205Tp(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
- struct nvbios_M0205T *);
-
-struct nvbios_M0205E {
- u8 type;
-};
-
-u32 nvbios_M0205Ee(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_M0205Ep(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_M0205E *);
-
-struct nvbios_M0205S {
- u8 data;
-};
-
-u32 nvbios_M0205Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_M0205Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
- struct nvbios_M0205S *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
deleted file mode 100644
index 67dc50d837bc..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/M0209.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NVBIOS_M0209_H__
-#define __NVBIOS_M0209_H__
-
-u32 nvbios_M0209Te(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-
-struct nvbios_M0209E {
- u8 v00_40;
- u8 bits;
- u8 modulo;
- u8 v02_40;
- u8 v02_07;
- u8 v03;
-};
-
-u32 nvbios_M0209Ee(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_M0209Ep(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_M0209E *);
-
-struct nvbios_M0209S {
- u32 data[0x200];
-};
-
-u32 nvbios_M0209Se(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_M0209Sp(struct nouveau_bios *, int ent, int idx, u8 *ver, u8 *hdr,
- struct nvbios_M0209S *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h
deleted file mode 100644
index bba01ab1e049..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/P0260.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVBIOS_P0260_H__
-#define __NVBIOS_P0260_H__
-
-u32 nvbios_P0260Te(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
-
-struct nvbios_P0260E {
- u32 data;
-};
-
-u32 nvbios_P0260Ee(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_P0260Ep(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
- struct nvbios_P0260E *);
-
-struct nvbios_P0260X {
- u32 data;
-};
-
-u32 nvbios_P0260Xe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_P0260Xp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
- struct nvbios_P0260X *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h
deleted file mode 100644
index 73f060b07981..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bit.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NVBIOS_BIT_H__
-#define __NVBIOS_BIT_H__
-
-struct bit_entry {
- u8 id;
- u8 version;
- u16 length;
- u16 offset;
-};
-
-int bit_entry(struct nouveau_bios *, u8 id, struct bit_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h
deleted file mode 100644
index 10e4dbca649a..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/bmp.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __NVBIOS_BMP_H__
-#define __NVBIOS_BMP_H__
-
-static inline u16
-bmp_version(struct nouveau_bios *bios)
-{
- if (bios->bmp_offset) {
- return nv_ro08(bios, bios->bmp_offset + 5) << 8 |
- nv_ro08(bios, bios->bmp_offset + 6);
- }
-
- return 0x0000;
-}
-
-static inline u16
-bmp_mem_init_table(struct nouveau_bios *bios)
-{
- if (bmp_version(bios) >= 0x0300)
- return nv_ro16(bios, bios->bmp_offset + 24);
- return 0x0000;
-}
-
-static inline u16
-bmp_sdr_seq_table(struct nouveau_bios *bios)
-{
- if (bmp_version(bios) >= 0x0300)
- return nv_ro16(bios, bios->bmp_offset + 26);
- return 0x0000;
-}
-
-static inline u16
-bmp_ddr_seq_table(struct nouveau_bios *bios)
-{
- if (bmp_version(bios) >= 0x0300)
- return nv_ro16(bios, bios->bmp_offset + 28);
- return 0x0000;
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h
deleted file mode 100644
index 662b20726851..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/boost.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __NVBIOS_BOOST_H__
-#define __NVBIOS_BOOST_H__
-
-u16 nvbios_boostTe(struct nouveau_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *);
-
-struct nvbios_boostE {
- u8 pstate;
- u32 min;
- u32 max;
-};
-
-u16 nvbios_boostEe(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *);
-u16 nvbios_boostEp(struct nouveau_bios *, int idx, u8 *, u8 *, u8 *, u8 *,
- struct nvbios_boostE *);
-u16 nvbios_boostEm(struct nouveau_bios *, u8, u8 *, u8 *, u8 *, u8 *,
- struct nvbios_boostE *);
-
-struct nvbios_boostS {
- u8 domain;
- u8 percent;
- u32 min;
- u32 max;
-};
-
-u16 nvbios_boostSe(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8);
-u16 nvbios_boostSp(struct nouveau_bios *, int, u16, u8 *, u8 *, u8, u8,
- struct nvbios_boostS *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
deleted file mode 100644
index f3930c27cb7a..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/conn.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __NVBIOS_CONN_H__
-#define __NVBIOS_CONN_H__
-
-enum dcb_connector_type {
- DCB_CONNECTOR_VGA = 0x00,
- DCB_CONNECTOR_TV_0 = 0x10,
- DCB_CONNECTOR_TV_1 = 0x11,
- DCB_CONNECTOR_TV_3 = 0x13,
- DCB_CONNECTOR_DVI_I = 0x30,
- DCB_CONNECTOR_DVI_D = 0x31,
- DCB_CONNECTOR_DMS59_0 = 0x38,
- DCB_CONNECTOR_DMS59_1 = 0x39,
- DCB_CONNECTOR_LVDS = 0x40,
- DCB_CONNECTOR_LVDS_SPWG = 0x41,
- DCB_CONNECTOR_DP = 0x46,
- DCB_CONNECTOR_eDP = 0x47,
- DCB_CONNECTOR_HDMI_0 = 0x60,
- DCB_CONNECTOR_HDMI_1 = 0x61,
- DCB_CONNECTOR_HDMI_C = 0x63,
- DCB_CONNECTOR_DMS59_DP0 = 0x64,
- DCB_CONNECTOR_DMS59_DP1 = 0x65,
- DCB_CONNECTOR_NONE = 0xff
-};
-
-struct nvbios_connT {
-};
-
-u32 nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_connT *info);
-
-struct nvbios_connE {
- u8 type;
- u8 location;
- u8 hpd;
- u8 dp;
- u8 di;
- u8 sr;
- u8 lcdid;
-};
-
-u32 nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr);
-u32 nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *hdr,
- struct nvbios_connE *info);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h
deleted file mode 100644
index a80a43809883..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/cstep.h
+++ /dev/null
@@ -1,28 +0,0 @@
-#ifndef __NVBIOS_CSTEP_H__
-#define __NVBIOS_CSTEP_H__
-
-u16 nvbios_cstepTe(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
-
-struct nvbios_cstepE {
- u8 pstate;
- u8 index;
-};
-
-u16 nvbios_cstepEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u16 nvbios_cstepEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
- struct nvbios_cstepE *);
-u16 nvbios_cstepEm(struct nouveau_bios *, u8 pstate, u8 *ver, u8 *hdr,
- struct nvbios_cstepE *);
-
-struct nvbios_cstepX {
- u32 freq;
- u8 unkn[2];
- u8 voltage;
-};
-
-u16 nvbios_cstepXe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u16 nvbios_cstepXp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
- struct nvbios_cstepX *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
deleted file mode 100644
index 123270e9813a..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dcb.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef __NVBIOS_DCB_H__
-#define __NVBIOS_DCB_H__
-
-struct nouveau_bios;
-
-enum dcb_output_type {
- DCB_OUTPUT_ANALOG = 0x0,
- DCB_OUTPUT_TV = 0x1,
- DCB_OUTPUT_TMDS = 0x2,
- DCB_OUTPUT_LVDS = 0x3,
- DCB_OUTPUT_DP = 0x6,
- DCB_OUTPUT_EOL = 0xe,
- DCB_OUTPUT_UNUSED = 0xf,
- DCB_OUTPUT_ANY = -1,
-};
-
-struct dcb_output {
- int index; /* may not be raw dcb index if merging has happened */
- u16 hasht;
- u16 hashm;
- enum dcb_output_type type;
- uint8_t i2c_index;
- uint8_t heads;
- uint8_t connector;
- uint8_t bus;
- uint8_t location;
- uint8_t or;
- uint8_t link;
- bool duallink_possible;
- uint8_t extdev;
- union {
- struct sor_conf {
- int link;
- } sorconf;
- struct {
- int maxfreq;
- } crtconf;
- struct {
- struct sor_conf sor;
- bool use_straps_for_mode;
- bool use_acpi_for_edid;
- bool use_power_scripts;
- } lvdsconf;
- struct {
- bool has_component_output;
- } tvconf;
- struct {
- struct sor_conf sor;
- int link_nr;
- int link_bw;
- } dpconf;
- struct {
- struct sor_conf sor;
- int slave_addr;
- } tmdsconf;
- };
- bool i2c_upper_default;
-};
-
-u16 dcb_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
-u16 dcb_outp(struct nouveau_bios *, u8 idx, u8 *ver, u8 *len);
-u16 dcb_outp_parse(struct nouveau_bios *, u8 idx, u8 *, u8 *,
- struct dcb_output *);
-u16 dcb_outp_match(struct nouveau_bios *, u16 type, u16 mask, u8 *, u8 *,
- struct dcb_output *);
-int dcb_outp_foreach(struct nouveau_bios *, void *data, int (*exec)
- (struct nouveau_bios *, void *, int index, u16 entry));
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h
deleted file mode 100644
index c35937e2f6a4..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/disp.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVBIOS_DISP_H__
-#define __NVBIOS_DISP_H__
-
-u16 nvbios_disp_table(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub);
-
-struct nvbios_disp {
- u16 data;
-};
-
-u16 nvbios_disp_entry(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr__, u8 *sub);
-u16 nvbios_disp_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr__, u8 *sub,
- struct nvbios_disp *);
-
-struct nvbios_outp {
- u16 type;
- u16 mask;
- u16 script[3];
-};
-
-u16 nvbios_outp_entry(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_outp_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *);
-u16 nvbios_outp_match(struct nouveau_bios *, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *);
-
-
-struct nvbios_ocfg {
- u16 match;
- u16 clkcmp[2];
-};
-
-u16 nvbios_ocfg_entry(struct nouveau_bios *, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_ocfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *);
-u16 nvbios_ocfg_match(struct nouveau_bios *, u16 outp, u16 type,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *);
-u16 nvbios_oclk_match(struct nouveau_bios *, u16 cmp, u32 khz);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
deleted file mode 100644
index 728206e21777..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/dp.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NVBIOS_DP_H__
-#define __NVBIOS_DP_H__
-
-struct nvbios_dpout {
- u16 type;
- u16 mask;
- u8 flags;
- u32 script[5];
- u32 lnkcmp;
-};
-
-u16 nvbios_dpout_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *);
-u16 nvbios_dpout_match(struct nouveau_bios *, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *);
-
-struct nvbios_dpcfg {
- u8 pc;
- u8 dc;
- u8 pe;
- u8 tx_pu;
-};
-
-u16
-nvbios_dpcfg_parse(struct nouveau_bios *, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *);
-u16
-nvbios_dpcfg_match(struct nouveau_bios *, u16 outp, u8 pc, u8 vs, u8 pe,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h
deleted file mode 100644
index 949fee3af8fb..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/extdev.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NVBIOS_EXTDEV_H__
-#define __NVBIOS_EXTDEV_H__
-
-struct nouveau_bios;
-
-enum nvbios_extdev_type {
- NVBIOS_EXTDEV_LM89 = 0x02,
- NVBIOS_EXTDEV_VT1103M = 0x40,
- NVBIOS_EXTDEV_PX3540 = 0x41,
- NVBIOS_EXTDEV_VT1105M = 0x42, /* or close enough... */
- NVBIOS_EXTDEV_ADT7473 = 0x70, /* can also be a LM64 */
- NVBIOS_EXTDEV_HDCP_EEPROM = 0x90,
- NVBIOS_EXTDEV_NONE = 0xff,
-};
-
-struct nvbios_extdev_func {
- u8 type;
- u8 addr;
- u8 bus;
-};
-
-int
-nvbios_extdev_parse(struct nouveau_bios *, int, struct nvbios_extdev_func *);
-
-int
-nvbios_extdev_find(struct nouveau_bios *, enum nvbios_extdev_type,
- struct nvbios_extdev_func *);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
deleted file mode 100644
index 119d0874e041..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/fan.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __NVBIOS_FAN_H__
-#define __NVBIOS_FAN_H__
-
-#include <subdev/bios/therm.h>
-
-u16 nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
deleted file mode 100644
index c7b2e586be0b..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/gpio.h
+++ /dev/null
@@ -1,48 +0,0 @@
-#ifndef __NVBIOS_GPIO_H__
-#define __NVBIOS_GPIO_H__
-
-enum dcb_gpio_func_name {
- DCB_GPIO_PANEL_POWER = 0x01,
- DCB_GPIO_TVDAC0 = 0x0c,
- DCB_GPIO_TVDAC1 = 0x2d,
- DCB_GPIO_FAN = 0x09,
- DCB_GPIO_FAN_SENSE = 0x3d,
- DCB_GPIO_UNUSED = 0xff,
- DCB_GPIO_VID0 = 0x04,
- DCB_GPIO_VID1 = 0x05,
- DCB_GPIO_VID2 = 0x06,
- DCB_GPIO_VID3 = 0x1a,
- DCB_GPIO_VID4 = 0x73,
- DCB_GPIO_VID5 = 0x74,
- DCB_GPIO_VID6 = 0x75,
- DCB_GPIO_VID7 = 0x76,
-};
-
-#define DCB_GPIO_LOG_DIR 0x02
-#define DCB_GPIO_LOG_DIR_OUT 0x00
-#define DCB_GPIO_LOG_DIR_IN 0x02
-#define DCB_GPIO_LOG_VAL 0x01
-#define DCB_GPIO_LOG_VAL_LO 0x00
-#define DCB_GPIO_LOG_VAL_HI 0x01
-
-struct dcb_gpio_func {
- u8 func;
- u8 line;
- u8 log[2];
-
- /* so far, "param" seems to only have an influence on PWM-related
- * GPIOs such as FAN_CONTROL and PANEL_BACKLIGHT_LEVEL.
- * if param equals 1, hardware PWM is available
- * if param equals 0, the host should toggle the GPIO itself
- */
- u8 param;
-};
-
-u16 dcb_gpio_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 dcb_gpio_entry(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len);
-u16 dcb_gpio_parse(struct nouveau_bios *, int idx, int ent, u8 *ver, u8 *len,
- struct dcb_gpio_func *);
-u16 dcb_gpio_match(struct nouveau_bios *, int idx, u8 func, u8 line,
- u8 *ver, u8 *len, struct dcb_gpio_func *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
deleted file mode 100644
index c9bb112895af..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/i2c.h
+++ /dev/null
@@ -1,29 +0,0 @@
-#ifndef __NVBIOS_I2C_H__
-#define __NVBIOS_I2C_H__
-
-struct nouveau_bios;
-
-enum dcb_i2c_type {
- /* matches bios type field prior to ccb 4.1 */
- DCB_I2C_NV04_BIT = 0x00,
- DCB_I2C_NV4E_BIT = 0x04,
- DCB_I2C_NVIO_BIT = 0x05,
- DCB_I2C_NVIO_AUX = 0x06,
- /* made up - mostly */
- DCB_I2C_PMGR = 0x80,
- DCB_I2C_UNUSED = 0xff
-};
-
-struct dcb_i2c_entry {
- enum dcb_i2c_type type;
- u8 drive;
- u8 sense;
- u8 share;
- u8 auxch;
-};
-
-u16 dcb_i2c_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 dcb_i2c_entry(struct nouveau_bios *, u8 index, u8 *ver, u8 *len);
-int dcb_i2c_parse(struct nouveau_bios *, u8 index, struct dcb_i2c_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h
deleted file mode 100644
index 3348b4580843..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/image.h
+++ /dev/null
@@ -1,13 +0,0 @@
-#ifndef __NVBIOS_IMAGE_H__
-#define __NVBIOS_IMAGE_H__
-
-struct nvbios_image {
- u32 base;
- u32 size;
- u8 type;
- bool last;
-};
-
-bool nvbios_image(struct nouveau_bios *, int, struct nvbios_image *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h
deleted file mode 100644
index ca2f6bf37f46..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/init.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __NVBIOS_INIT_H__
-#define __NVBIOS_INIT_H__
-
-struct nvbios_init {
- struct nouveau_subdev *subdev;
- struct nouveau_bios *bios;
- u16 offset;
- struct dcb_output *outp;
- int crtc;
-
- /* internal state used during parsing */
- u8 execute;
- u32 nested;
- u16 repeat;
- u16 repend;
- u32 ramcfg;
-};
-
-int nvbios_exec(struct nvbios_init *);
-int nvbios_init(struct nouveau_subdev *, bool execute);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
deleted file mode 100644
index 5572e60414e8..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/mxm.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NVBIOS_MXM_H__
-#define __NVBIOS_MXM_H__
-
-u16 mxm_table(struct nouveau_bios *, u8 *ver, u8 *hdr);
-
-u8 mxm_sor_map(struct nouveau_bios *, u8 conn);
-u8 mxm_ddc_map(struct nouveau_bios *, u8 port);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h
deleted file mode 100644
index b18413d951e5..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/npde.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef __NVBIOS_NPDE_H__
-#define __NVBIOS_NPDE_H__
-
-struct nvbios_npdeT {
- u32 image_size;
- bool last;
-};
-
-u32 nvbios_npdeTe(struct nouveau_bios *, u32);
-u32 nvbios_npdeTp(struct nouveau_bios *, u32, struct nvbios_npdeT *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h
deleted file mode 100644
index 3d634a06dca1..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pcir.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __NVBIOS_PCIR_H__
-#define __NVBIOS_PCIR_H__
-
-struct nvbios_pcirT {
- u16 vendor_id;
- u16 device_id;
- u8 class_code[3];
- u32 image_size;
- u16 image_rev;
- u8 image_type;
- bool last;
-};
-
-u32 nvbios_pcirTe(struct nouveau_bios *, u32, u8 *ver, u16 *hdr);
-u32 nvbios_pcirTp(struct nouveau_bios *, u32, u8 *ver, u16 *hdr,
- struct nvbios_pcirT *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h
deleted file mode 100644
index 16ff06ec2a88..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/perf.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __NVBIOS_PERF_H__
-#define __NVBIOS_PERF_H__
-
-struct nouveau_bios;
-
-u16 nvbios_perf_table(struct nouveau_bios *, u8 *ver, u8 *hdr,
- u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-
-struct nvbios_perfE {
- u8 pstate;
- u8 fanspeed;
- u8 voltage;
- u32 core;
- u32 shader;
- u32 memory;
- u32 vdec;
- u32 disp;
- u32 script;
-};
-
-u16 nvbios_perf_entry(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_perfEp(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *);
-
-struct nvbios_perfS {
- union {
- struct {
- u32 freq;
- } v40;
- };
-};
-
-u32 nvbios_perfSe(struct nouveau_bios *, u32 data, int idx,
- u8 *ver, u8 *hdr, u8 cnt, u8 len);
-u32 nvbios_perfSp(struct nouveau_bios *, u32 data, int idx,
- u8 *ver, u8 *hdr, u8 cnt, u8 len, struct nvbios_perfS *);
-
-struct nvbios_perf_fan {
- u32 pwm_divisor;
-};
-
-int
-nvbios_perf_fan_parse(struct nouveau_bios *, struct nvbios_perf_fan *);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h
deleted file mode 100644
index b2f3d4d0aa49..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pll.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#ifndef __NVBIOS_PLL_H__
-#define __NVBIOS_PLL_H__
-
-/*XXX: kill me */
-struct nouveau_pll_vals {
- union {
- struct {
-#ifdef __BIG_ENDIAN
- uint8_t N1, M1, N2, M2;
-#else
- uint8_t M1, N1, M2, N2;
-#endif
- };
- struct {
- uint16_t NM1, NM2;
- } __attribute__((packed));
- };
- int log2P;
-
- int refclk;
-};
-
-struct nouveau_bios;
-
-/* these match types in pll limits table version 0x40,
- * nouveau uses them on all chipsets internally where a
- * specific pll needs to be referenced, but the exact
- * register isn't known.
- */
-enum nvbios_pll_type {
- PLL_CORE = 0x01,
- PLL_SHADER = 0x02,
- PLL_UNK03 = 0x03,
- PLL_MEMORY = 0x04,
- PLL_VDEC = 0x05,
- PLL_UNK40 = 0x40,
- PLL_UNK41 = 0x41,
- PLL_UNK42 = 0x42,
- PLL_VPLL0 = 0x80,
- PLL_VPLL1 = 0x81,
- PLL_VPLL2 = 0x82,
- PLL_VPLL3 = 0x83,
- PLL_MAX = 0xff
-};
-
-struct nvbios_pll {
- enum nvbios_pll_type type;
- u32 reg;
- u32 refclk;
-
- u8 min_p;
- u8 max_p;
- u8 bias_p;
-
- /*
- * for most pre nv50 cards setting a log2P of 7 (the common max_log2p
- * value) is no different to 6 (at least for vplls) so allowing the MNP
- * calc to use 7 causes the generated clock to be out by a factor of 2.
- * however, max_log2p cannot be fixed-up during parsing as the
- * unmodified max_log2p value is still needed for setting mplls, hence
- * an additional max_usable_log2p member
- */
- u8 max_p_usable;
-
- struct {
- u32 min_freq;
- u32 max_freq;
- u32 min_inputfreq;
- u32 max_inputfreq;
- u8 min_m;
- u8 max_m;
- u8 min_n;
- u8 max_n;
- } vco1, vco2;
-};
-
-int nvbios_pll_parse(struct nouveau_bios *, u32 type, struct nvbios_pll *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h
deleted file mode 100644
index 9de593deaea8..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/pmu.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NVBIOS_PMU_H__
-#define __NVBIOS_PMU_H__
-
-struct nvbios_pmuT {
-};
-
-u32 nvbios_pmuTe(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_pmuTp(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_pmuT *);
-
-struct nvbios_pmuE {
- u8 type;
- u32 data;
-};
-
-u32 nvbios_pmuEe(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr);
-u32 nvbios_pmuEp(struct nouveau_bios *, int idx, u8 *ver, u8 *hdr,
- struct nvbios_pmuE *);
-
-struct nvbios_pmuR {
- u32 boot_addr_pmu;
- u32 boot_addr;
- u32 boot_size;
- u32 code_addr_pmu;
- u32 code_addr;
- u32 code_size;
- u32 init_addr_pmu;
-
- u32 data_addr_pmu;
- u32 data_addr;
- u32 data_size;
- u32 args_addr_pmu;
-};
-
-bool nvbios_pmuRm(struct nouveau_bios *, u8 type, struct nvbios_pmuR *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
deleted file mode 100644
index 4a0e0ceb41ba..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/ramcfg.h
+++ /dev/null
@@ -1,145 +0,0 @@
-#ifndef __NVBIOS_RAMCFG_H__
-#define __NVBIOS_RAMCFG_H__
-
-struct nouveau_bios;
-
-struct nvbios_ramcfg {
- unsigned rammap_ver;
- unsigned rammap_hdr;
- unsigned rammap_min;
- unsigned rammap_max;
- union {
- struct {
- unsigned rammap_10_04_02:1;
- unsigned rammap_10_04_08:1;
- };
- struct {
- unsigned rammap_11_08_01:1;
- unsigned rammap_11_08_0c:2;
- unsigned rammap_11_08_10:1;
- unsigned rammap_11_09_01ff:9;
- unsigned rammap_11_0a_03fe:9;
- unsigned rammap_11_0a_0400:1;
- unsigned rammap_11_0a_0800:1;
- unsigned rammap_11_0b_01f0:5;
- unsigned rammap_11_0b_0200:1;
- unsigned rammap_11_0b_0400:1;
- unsigned rammap_11_0b_0800:1;
- unsigned rammap_11_0d:8;
- unsigned rammap_11_0e:8;
- unsigned rammap_11_0f:8;
- unsigned rammap_11_11_0c:2;
- };
- };
-
- unsigned ramcfg_ver;
- unsigned ramcfg_hdr;
- unsigned ramcfg_timing;
- union {
- struct {
- unsigned ramcfg_10_02_01:1;
- unsigned ramcfg_10_02_02:1;
- unsigned ramcfg_10_02_04:1;
- unsigned ramcfg_10_02_08:1;
- unsigned ramcfg_10_02_10:1;
- unsigned ramcfg_10_02_20:1;
- unsigned ramcfg_10_DLLoff:1;
- unsigned ramcfg_10_03_0f:4;
- unsigned ramcfg_10_04_01:1;
- unsigned ramcfg_10_05:8;
- unsigned ramcfg_10_06:8;
- unsigned ramcfg_10_07:8;
- unsigned ramcfg_10_08:8;
- unsigned ramcfg_10_09_0f:4;
- unsigned ramcfg_10_09_f0:4;
- };
- struct {
- unsigned ramcfg_11_01_01:1;
- unsigned ramcfg_11_01_02:1;
- unsigned ramcfg_11_01_04:1;
- unsigned ramcfg_11_01_08:1;
- unsigned ramcfg_11_01_10:1;
- unsigned ramcfg_11_01_20:1;
- unsigned ramcfg_11_01_40:1;
- unsigned ramcfg_11_01_80:1;
- unsigned ramcfg_11_02_03:2;
- unsigned ramcfg_11_02_04:1;
- unsigned ramcfg_11_02_08:1;
- unsigned ramcfg_11_02_10:1;
- unsigned ramcfg_11_02_40:1;
- unsigned ramcfg_11_02_80:1;
- unsigned ramcfg_11_03_0f:4;
- unsigned ramcfg_11_03_30:2;
- unsigned ramcfg_11_03_c0:2;
- unsigned ramcfg_11_03_f0:4;
- unsigned ramcfg_11_04:8;
- unsigned ramcfg_11_06:8;
- unsigned ramcfg_11_07_02:1;
- unsigned ramcfg_11_07_04:1;
- unsigned ramcfg_11_07_08:1;
- unsigned ramcfg_11_07_10:1;
- unsigned ramcfg_11_07_40:1;
- unsigned ramcfg_11_07_80:1;
- unsigned ramcfg_11_08_01:1;
- unsigned ramcfg_11_08_02:1;
- unsigned ramcfg_11_08_04:1;
- unsigned ramcfg_11_08_08:1;
- unsigned ramcfg_11_08_10:1;
- unsigned ramcfg_11_08_20:1;
- unsigned ramcfg_11_09:8;
- };
- };
-
- unsigned timing_ver;
- unsigned timing_hdr;
- unsigned timing[11];
- union {
- struct {
- unsigned timing_10_WR:8;
- unsigned timing_10_WTR:8;
- unsigned timing_10_CL:8;
- unsigned timing_10_RC:8;
- /*empty: 4 */
- unsigned timing_10_RFC:8; /* Byte 5 */
- /*empty: 6 */
- unsigned timing_10_RAS:8; /* Byte 7 */
- /*empty: 8 */
- unsigned timing_10_RP:8; /* Byte 9 */
- unsigned timing_10_RCDRD:8;
- unsigned timing_10_RCDWR:8;
- unsigned timing_10_RRD:8;
- unsigned timing_10_13:8;
- unsigned timing_10_ODT:3;
- /* empty: 15 */
- unsigned timing_10_16:8;
- /* empty: 17 */
- unsigned timing_10_18:8;
- unsigned timing_10_CWL:8;
- unsigned timing_10_20:8;
- unsigned timing_10_21:8;
- /* empty: 22, 23 */
- unsigned timing_10_24:8;
- };
- struct {
- unsigned timing_20_2e_03:2;
- unsigned timing_20_2e_30:2;
- unsigned timing_20_2e_c0:2;
- unsigned timing_20_2f_03:2;
- unsigned timing_20_2c_003f:6;
- unsigned timing_20_2c_1fc0:7;
- unsigned timing_20_30_f8:5;
- unsigned timing_20_30_07:3;
- unsigned timing_20_31_0007:3;
- unsigned timing_20_31_0078:4;
- unsigned timing_20_31_0780:4;
- unsigned timing_20_31_0800:1;
- unsigned timing_20_31_7000:3;
- unsigned timing_20_31_8000:1;
- };
- };
-};
-
-u8 nvbios_ramcfg_count(struct nouveau_bios *);
-u8 nvbios_ramcfg_index(struct nouveau_subdev *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
deleted file mode 100644
index 47e021d3e20d..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/rammap.h
+++ /dev/null
@@ -1,26 +0,0 @@
-#ifndef __NVBIOS_RAMMAP_H__
-#define __NVBIOS_RAMMAP_H__
-
-struct nvbios_ramcfg;
-
-u32 nvbios_rammapTe(struct nouveau_bios *, u8 *ver, u8 *hdr,
- u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-
-u32 nvbios_rammapEe(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u32 nvbios_rammapEp(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ramcfg *);
-u32 nvbios_rammapEm(struct nouveau_bios *, u16 mhz,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ramcfg *);
-
-u32 nvbios_rammapSe(struct nouveau_bios *, u32 data,
- u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
- u8 *ver, u8 *hdr);
-u32 nvbios_rammapSp(struct nouveau_bios *, u32 data,
- u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
- u8 *ver, u8 *hdr,
- struct nvbios_ramcfg *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
deleted file mode 100644
index 295d093f3b30..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/therm.h
+++ /dev/null
@@ -1,77 +0,0 @@
-#ifndef __NVBIOS_THERM_H__
-#define __NVBIOS_THERM_H__
-
-struct nouveau_bios;
-
-struct nvbios_therm_threshold {
- u8 temp;
- u8 hysteresis;
-};
-
-struct nvbios_therm_sensor {
- /* diode */
- s16 slope_mult;
- s16 slope_div;
- s16 offset_num;
- s16 offset_den;
- s8 offset_constant;
-
- /* thresholds */
- struct nvbios_therm_threshold thrs_fan_boost;
- struct nvbios_therm_threshold thrs_down_clock;
- struct nvbios_therm_threshold thrs_critical;
- struct nvbios_therm_threshold thrs_shutdown;
-};
-
-enum nvbios_therm_fan_type {
- NVBIOS_THERM_FAN_UNK = 0,
- NVBIOS_THERM_FAN_TOGGLE = 1,
- NVBIOS_THERM_FAN_PWM = 2,
-};
-
-/* no vbios have more than 6 */
-#define NOUVEAU_TEMP_FAN_TRIP_MAX 10
-struct nouveau_therm_trip_point {
- int fan_duty;
- int temp;
- int hysteresis;
-};
-
-enum nvbios_therm_fan_mode {
- NVBIOS_THERM_FAN_TRIP = 0,
- NVBIOS_THERM_FAN_LINEAR = 1,
- NVBIOS_THERM_FAN_OTHER = 2,
-};
-
-struct nvbios_therm_fan {
- enum nvbios_therm_fan_type type;
-
- u32 pwm_freq;
-
- u8 min_duty;
- u8 max_duty;
-
- u16 bump_period;
- u16 slow_down_period;
-
- enum nvbios_therm_fan_mode fan_mode;
- struct nouveau_therm_trip_point trip[NOUVEAU_TEMP_FAN_TRIP_MAX];
- u8 nr_fan_trip;
- u8 linear_min_temp;
- u8 linear_max_temp;
-};
-
-enum nvbios_therm_domain {
- NVBIOS_THERM_DOMAIN_CORE,
- NVBIOS_THERM_DOMAIN_AMBIENT,
-};
-
-int
-nvbios_therm_sensor_parse(struct nouveau_bios *, enum nvbios_therm_domain,
- struct nvbios_therm_sensor *);
-
-int
-nvbios_therm_fan_parse(struct nouveau_bios *, struct nvbios_therm_fan *);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h
deleted file mode 100644
index 76d914b67ab5..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/timing.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#ifndef __NVBIOS_TIMING_H__
-#define __NVBIOS_TIMING_H__
-
-struct nvbios_ramcfg;
-
-u16 nvbios_timingTe(struct nouveau_bios *,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
-u16 nvbios_timingEe(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_timingEp(struct nouveau_bios *, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ramcfg *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h
deleted file mode 100644
index ad5a8f20e113..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/vmap.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __NVBIOS_VMAP_H__
-#define __NVBIOS_VMAP_H__
-
-struct nouveau_bios;
-
-struct nvbios_vmap {
-};
-
-u16 nvbios_vmap_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_vmap_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_vmap *);
-
-struct nvbios_vmap_entry {
- u8 unk0;
- u8 link;
- u32 min;
- u32 max;
- s32 arg[6];
-};
-
-u16 nvbios_vmap_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len);
-u16 nvbios_vmap_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len,
- struct nvbios_vmap_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h
deleted file mode 100644
index 6a11dcd59770..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/volt.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __NVBIOS_VOLT_H__
-#define __NVBIOS_VOLT_H__
-
-struct nouveau_bios;
-
-struct nvbios_volt {
- u8 vidmask;
- u32 min;
- u32 max;
- u32 base;
- s16 step;
-};
-
-u16 nvbios_volt_table(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 nvbios_volt_parse(struct nouveau_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_volt *);
-
-struct nvbios_volt_entry {
- u32 voltage;
- u8 vid;
-};
-
-u16 nvbios_volt_entry(struct nouveau_bios *, int idx, u8 *ver, u8 *len);
-u16 nvbios_volt_entry_parse(struct nouveau_bios *, int idx, u8 *ver, u8 *len,
- struct nvbios_volt_entry *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h
deleted file mode 100644
index 360baab52e4c..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bios/xpio.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __NVBIOS_XPIO_H__
-#define __NVBIOS_XPIO_H__
-
-#define NVBIOS_XPIO_FLAG_AUX 0x10
-#define NVBIOS_XPIO_FLAG_AUX0 0x00
-#define NVBIOS_XPIO_FLAG_AUX1 0x10
-
-struct nvbios_xpio {
- u8 type;
- u8 addr;
- u8 flags;
-};
-
-u16 dcb_xpio_table(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
-u16 dcb_xpio_parse(struct nouveau_bios *, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h b/drivers/gpu/drm/nouveau/core/include/subdev/bus.h
deleted file mode 100644
index 697f7ce70aab..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/bus.h
+++ /dev/null
@@ -1,53 +0,0 @@
-#ifndef __NOUVEAU_BUS_H__
-#define __NOUVEAU_BUS_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_bus_intr {
- u32 stat;
- u32 unit;
-};
-
-struct nouveau_bus {
- struct nouveau_subdev base;
- int (*hwsq_exec)(struct nouveau_bus *, u32 *, u32);
- u32 hwsq_size;
-};
-
-static inline struct nouveau_bus *
-nouveau_bus(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_BUS];
-}
-
-#define nouveau_bus_create(p, e, o, d) \
- nouveau_subdev_create_((p), (e), (o), 0, "PBUS", "master", \
- sizeof(**d), (void **)d)
-#define nouveau_bus_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_bus_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_bus_fini(p, s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-#define _nouveau_bus_dtor _nouveau_subdev_dtor
-#define _nouveau_bus_init _nouveau_subdev_init
-#define _nouveau_bus_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass *nv04_bus_oclass;
-extern struct nouveau_oclass *nv31_bus_oclass;
-extern struct nouveau_oclass *nv50_bus_oclass;
-extern struct nouveau_oclass *nv94_bus_oclass;
-extern struct nouveau_oclass *nvc0_bus_oclass;
-
-/* interface to sequencer */
-struct nouveau_hwsq;
-int nouveau_hwsq_init(struct nouveau_bus *, struct nouveau_hwsq **);
-int nouveau_hwsq_fini(struct nouveau_hwsq **, bool exec);
-void nouveau_hwsq_wr32(struct nouveau_hwsq *, u32 addr, u32 data);
-void nouveau_hwsq_setf(struct nouveau_hwsq *, u8 flag, int data);
-void nouveau_hwsq_wait(struct nouveau_hwsq *, u8 flag, u8 data);
-void nouveau_hwsq_nsec(struct nouveau_hwsq *, u32 nsec);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h b/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
deleted file mode 100644
index 36ed035d4d42..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/clock.h
+++ /dev/null
@@ -1,166 +0,0 @@
-#ifndef __NOUVEAU_CLOCK_H__
-#define __NOUVEAU_CLOCK_H__
-
-#include <core/device.h>
-#include <core/subdev.h>
-
-struct nouveau_pll_vals;
-struct nvbios_pll;
-
-enum nv_clk_src {
- nv_clk_src_crystal,
- nv_clk_src_href,
-
- nv_clk_src_hclk,
- nv_clk_src_hclkm3,
- nv_clk_src_hclkm3d2,
- nv_clk_src_hclkm2d3, /* NVAA */
- nv_clk_src_hclkm4, /* NVAA */
- nv_clk_src_cclk, /* NVAA */
-
- nv_clk_src_host,
-
- nv_clk_src_sppll0,
- nv_clk_src_sppll1,
-
- nv_clk_src_mpllsrcref,
- nv_clk_src_mpllsrc,
- nv_clk_src_mpll,
- nv_clk_src_mdiv,
-
- nv_clk_src_core,
- nv_clk_src_core_intm,
- nv_clk_src_shader,
-
- nv_clk_src_mem,
-
- nv_clk_src_gpc,
- nv_clk_src_rop,
- nv_clk_src_hubk01,
- nv_clk_src_hubk06,
- nv_clk_src_hubk07,
- nv_clk_src_copy,
- nv_clk_src_daemon,
- nv_clk_src_disp,
- nv_clk_src_vdec,
-
- nv_clk_src_dom6,
-
- nv_clk_src_max,
-};
-
-struct nouveau_cstate {
- struct list_head head;
- u8 voltage;
- u32 domain[nv_clk_src_max];
-};
-
-struct nouveau_pstate {
- struct list_head head;
- struct list_head list; /* c-states */
- struct nouveau_cstate base;
- u8 pstate;
- u8 fanspeed;
-};
-
-struct nouveau_clock {
- struct nouveau_subdev base;
-
- struct nouveau_clocks *domains;
- struct nouveau_pstate bstate;
-
- struct list_head states;
- int state_nr;
-
- struct work_struct work;
- wait_queue_head_t wait;
- atomic_t waiting;
-
- struct nvkm_notify pwrsrc_ntfy;
- int pwrsrc;
- int pstate; /* current */
- int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
- int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
- int astate; /* perfmon adjustment (base) */
- int tstate; /* thermal adjustment (max-) */
- int dstate; /* display adjustment (min+) */
-
- bool allow_reclock;
-
- int (*read)(struct nouveau_clock *, enum nv_clk_src);
- int (*calc)(struct nouveau_clock *, struct nouveau_cstate *);
- int (*prog)(struct nouveau_clock *);
- void (*tidy)(struct nouveau_clock *);
-
- /*XXX: die, these are here *only* to support the completely
- * bat-shit insane what-was-nouveau_hw.c code
- */
- int (*pll_calc)(struct nouveau_clock *, struct nvbios_pll *,
- int clk, struct nouveau_pll_vals *pv);
- int (*pll_prog)(struct nouveau_clock *, u32 reg1,
- struct nouveau_pll_vals *pv);
-};
-
-static inline struct nouveau_clock *
-nouveau_clock(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_CLOCK];
-}
-
-struct nouveau_clocks {
- enum nv_clk_src name;
- u8 bios; /* 0xff for none */
-#define NVKM_CLK_DOM_FLAG_CORE 0x01
- u8 flags;
- const char *mname;
- int mdiv;
-};
-
-#define nouveau_clock_create(p,e,o,i,r,s,n,d) \
- nouveau_clock_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \
- (void **)d)
-#define nouveau_clock_destroy(p) ({ \
- struct nouveau_clock *clk = (p); \
- _nouveau_clock_dtor(nv_object(clk)); \
-})
-#define nouveau_clock_init(p) ({ \
- struct nouveau_clock *clk = (p); \
- _nouveau_clock_init(nv_object(clk)); \
-})
-#define nouveau_clock_fini(p,s) ({ \
- struct nouveau_clock *clk = (p); \
- _nouveau_clock_fini(nv_object(clk), (s)); \
-})
-
-int nouveau_clock_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *,
- struct nouveau_clocks *, struct nouveau_pstate *,
- int, bool, int, void **);
-void _nouveau_clock_dtor(struct nouveau_object *);
-int _nouveau_clock_init(struct nouveau_object *);
-int _nouveau_clock_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass nv04_clock_oclass;
-extern struct nouveau_oclass nv40_clock_oclass;
-extern struct nouveau_oclass *nv50_clock_oclass;
-extern struct nouveau_oclass *nv84_clock_oclass;
-extern struct nouveau_oclass *nvaa_clock_oclass;
-extern struct nouveau_oclass nva3_clock_oclass;
-extern struct nouveau_oclass nvc0_clock_oclass;
-extern struct nouveau_oclass nve0_clock_oclass;
-extern struct nouveau_oclass gk20a_clock_oclass;
-
-int nv04_clock_pll_set(struct nouveau_clock *, u32 type, u32 freq);
-int nv04_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
- int clk, struct nouveau_pll_vals *);
-int nv04_clock_pll_prog(struct nouveau_clock *, u32 reg1,
- struct nouveau_pll_vals *);
-int nva3_clock_pll_calc(struct nouveau_clock *, struct nvbios_pll *,
- int clk, struct nouveau_pll_vals *);
-
-int nouveau_clock_ustate(struct nouveau_clock *, int req, int pwr);
-int nouveau_clock_astate(struct nouveau_clock *, int req, int rel);
-int nouveau_clock_dstate(struct nouveau_clock *, int req, int rel);
-int nouveau_clock_tstate(struct nouveau_clock *, int req, int rel);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h b/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
deleted file mode 100644
index e007a9d44683..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/devinit.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_DEVINIT_H__
-#define __NOUVEAU_DEVINIT_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_devinit {
- struct nouveau_subdev base;
- bool post;
- void (*meminit)(struct nouveau_devinit *);
- int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
- u32 (*mmio)(struct nouveau_devinit *, u32 addr);
-};
-
-static inline struct nouveau_devinit *
-nouveau_devinit(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_DEVINIT];
-}
-
-extern struct nouveau_oclass *nv04_devinit_oclass;
-extern struct nouveau_oclass *nv05_devinit_oclass;
-extern struct nouveau_oclass *nv10_devinit_oclass;
-extern struct nouveau_oclass *nv1a_devinit_oclass;
-extern struct nouveau_oclass *nv20_devinit_oclass;
-extern struct nouveau_oclass *nv50_devinit_oclass;
-extern struct nouveau_oclass *nv84_devinit_oclass;
-extern struct nouveau_oclass *nv98_devinit_oclass;
-extern struct nouveau_oclass *nva3_devinit_oclass;
-extern struct nouveau_oclass *nvaf_devinit_oclass;
-extern struct nouveau_oclass *nvc0_devinit_oclass;
-extern struct nouveau_oclass *gm107_devinit_oclass;
-extern struct nouveau_oclass *gm204_devinit_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
deleted file mode 100644
index 8d0032f15205..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb.h
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef __NOUVEAU_FB_H__
-#define __NOUVEAU_FB_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/mm.h>
-
-#include <subdev/vm.h>
-
-/* memory type/access flags, do not match hardware values */
-#define NV_MEM_ACCESS_RO 1
-#define NV_MEM_ACCESS_WO 2
-#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
-#define NV_MEM_ACCESS_SYS 4
-#define NV_MEM_ACCESS_VM 8
-#define NV_MEM_ACCESS_NOSNOOP 16
-
-#define NV_MEM_TARGET_VRAM 0
-#define NV_MEM_TARGET_PCI 1
-#define NV_MEM_TARGET_PCI_NOSNOOP 2
-#define NV_MEM_TARGET_VM 3
-#define NV_MEM_TARGET_GART 4
-
-#define NV_MEM_TYPE_VM 0x7f
-#define NV_MEM_COMP_VM 0x03
-
-struct nouveau_mem {
- struct drm_device *dev;
-
- struct nouveau_vma bar_vma;
- struct nouveau_vma vma[2];
- u8 page_shift;
-
- struct nouveau_mm_node *tag;
- struct list_head regions;
- dma_addr_t *pages;
- u32 memtype;
- u64 offset;
- u64 size;
- struct sg_table *sg;
-};
-
-struct nouveau_fb_tile {
- struct nouveau_mm_node *tag;
- u32 addr;
- u32 limit;
- u32 pitch;
- u32 zcomp;
-};
-
-struct nouveau_fb {
- struct nouveau_subdev base;
-
- bool (*memtype_valid)(struct nouveau_fb *, u32 memtype);
-
- struct nouveau_ram *ram;
-
- struct nouveau_mm vram;
- struct nouveau_mm tags;
-
- struct {
- struct nouveau_fb_tile region[16];
- int regions;
- void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
- void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *);
- void (*fini)(struct nouveau_fb *, int i,
- struct nouveau_fb_tile *);
- void (*prog)(struct nouveau_fb *, int i,
- struct nouveau_fb_tile *);
- } tile;
-};
-
-static inline struct nouveau_fb *
-nouveau_fb(void *obj)
-{
- /* fbram uses this before device subdev pointer is valid */
- if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
- nv_subidx(obj) == NVDEV_SUBDEV_FB)
- return obj;
-
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FB];
-}
-
-extern struct nouveau_oclass *nv04_fb_oclass;
-extern struct nouveau_oclass *nv10_fb_oclass;
-extern struct nouveau_oclass *nv1a_fb_oclass;
-extern struct nouveau_oclass *nv20_fb_oclass;
-extern struct nouveau_oclass *nv25_fb_oclass;
-extern struct nouveau_oclass *nv30_fb_oclass;
-extern struct nouveau_oclass *nv35_fb_oclass;
-extern struct nouveau_oclass *nv36_fb_oclass;
-extern struct nouveau_oclass *nv40_fb_oclass;
-extern struct nouveau_oclass *nv41_fb_oclass;
-extern struct nouveau_oclass *nv44_fb_oclass;
-extern struct nouveau_oclass *nv46_fb_oclass;
-extern struct nouveau_oclass *nv47_fb_oclass;
-extern struct nouveau_oclass *nv49_fb_oclass;
-extern struct nouveau_oclass *nv4e_fb_oclass;
-extern struct nouveau_oclass *nv50_fb_oclass;
-extern struct nouveau_oclass *nv84_fb_oclass;
-extern struct nouveau_oclass *nva3_fb_oclass;
-extern struct nouveau_oclass *nvaa_fb_oclass;
-extern struct nouveau_oclass *nvaf_fb_oclass;
-extern struct nouveau_oclass *nvc0_fb_oclass;
-extern struct nouveau_oclass *nve0_fb_oclass;
-extern struct nouveau_oclass *gk20a_fb_oclass;
-extern struct nouveau_oclass *gm107_fb_oclass;
-
-#include <subdev/bios/ramcfg.h>
-
-struct nouveau_ram_data {
- struct list_head head;
- struct nvbios_ramcfg bios;
- u32 freq;
-};
-
-struct nouveau_ram {
- struct nouveau_object base;
- enum {
- NV_MEM_TYPE_UNKNOWN = 0,
- NV_MEM_TYPE_STOLEN,
- NV_MEM_TYPE_SGRAM,
- NV_MEM_TYPE_SDRAM,
- NV_MEM_TYPE_DDR1,
- NV_MEM_TYPE_DDR2,
- NV_MEM_TYPE_DDR3,
- NV_MEM_TYPE_GDDR2,
- NV_MEM_TYPE_GDDR3,
- NV_MEM_TYPE_GDDR4,
- NV_MEM_TYPE_GDDR5
- } type;
- u64 stolen;
- u64 size;
- u32 tags;
-
- int ranks;
- int parts;
- int part_mask;
-
- int (*get)(struct nouveau_fb *, u64 size, u32 align,
- u32 size_nc, u32 type, struct nouveau_mem **);
- void (*put)(struct nouveau_fb *, struct nouveau_mem **);
-
- int (*calc)(struct nouveau_fb *, u32 freq);
- int (*prog)(struct nouveau_fb *);
- void (*tidy)(struct nouveau_fb *);
- u32 freq;
- u32 mr[16];
- u32 mr1_nuts;
-
- struct nouveau_ram_data *next;
- struct nouveau_ram_data former;
- struct nouveau_ram_data xition;
- struct nouveau_ram_data target;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h b/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
deleted file mode 100644
index 0f7fc0c52ab2..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fb/regsnv04.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef __NOUVEAU_FB_REGS_04_H__
-#define __NOUVEAU_FB_REGS_04_H__
-
-#define NV04_PFB_BOOT_0 0x00100000
-# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
-# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
-# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
-# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
-# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
-# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
-# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
-# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h b/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
deleted file mode 100644
index 2b1ddb2a9a7d..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/fuse.h
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef __NOUVEAU_FUSE_H__
-#define __NOUVEAU_FUSE_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_fuse {
- struct nouveau_subdev base;
-};
-
-static inline struct nouveau_fuse *
-nouveau_fuse(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_FUSE];
-}
-
-#define nouveau_fuse_create(p, e, o, d) \
- nouveau_fuse_create_((p), (e), (o), sizeof(**d), (void **)d)
-
-int nouveau_fuse_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_fuse_dtor(struct nouveau_object *);
-int _nouveau_fuse_init(struct nouveau_object *);
-#define _nouveau_fuse_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass g80_fuse_oclass;
-extern struct nouveau_oclass gf100_fuse_oclass;
-extern struct nouveau_oclass gm107_fuse_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h b/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
deleted file mode 100644
index f855140dbcb7..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/gpio.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __NOUVEAU_GPIO_H__
-#define __NOUVEAU_GPIO_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/event.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/gpio.h>
-
-struct nvkm_gpio_ntfy_req {
-#define NVKM_GPIO_HI 0x01
-#define NVKM_GPIO_LO 0x02
-#define NVKM_GPIO_TOGGLED 0x03
- u8 mask;
- u8 line;
-};
-
-struct nvkm_gpio_ntfy_rep {
- u8 mask;
-};
-
-struct nouveau_gpio {
- struct nouveau_subdev base;
-
- struct nvkm_event event;
-
- void (*reset)(struct nouveau_gpio *, u8 func);
- int (*find)(struct nouveau_gpio *, int idx, u8 tag, u8 line,
- struct dcb_gpio_func *);
- int (*set)(struct nouveau_gpio *, int idx, u8 tag, u8 line, int state);
- int (*get)(struct nouveau_gpio *, int idx, u8 tag, u8 line);
-};
-
-static inline struct nouveau_gpio *
-nouveau_gpio(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_GPIO];
-}
-
-extern struct nouveau_oclass *nv10_gpio_oclass;
-extern struct nouveau_oclass *nv50_gpio_oclass;
-extern struct nouveau_oclass *nv94_gpio_oclass;
-extern struct nouveau_oclass *nvd0_gpio_oclass;
-extern struct nouveau_oclass *nve0_gpio_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h b/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
deleted file mode 100644
index d94ccacb40bf..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/i2c.h
+++ /dev/null
@@ -1,136 +0,0 @@
-#ifndef __NOUVEAU_I2C_H__
-#define __NOUVEAU_I2C_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/i2c.h>
-
-#define NV_I2C_PORT(n) (0x00 + (n))
-#define NV_I2C_AUX(n) (0x10 + (n))
-#define NV_I2C_EXT(n) (0x20 + (n))
-#define NV_I2C_DEFAULT(n) (0x80 + (n))
-
-#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
-#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
-#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
-
-struct nvkm_i2c_ntfy_req {
-#define NVKM_I2C_PLUG 0x01
-#define NVKM_I2C_UNPLUG 0x02
-#define NVKM_I2C_IRQ 0x04
-#define NVKM_I2C_DONE 0x08
-#define NVKM_I2C_ANY 0x0f
- u8 mask;
- u8 port;
-};
-
-struct nvkm_i2c_ntfy_rep {
- u8 mask;
-};
-
-struct nouveau_i2c_port {
- struct nouveau_object base;
- struct i2c_adapter adapter;
- struct mutex mutex;
-
- struct list_head head;
- u8 index;
- int aux;
-
- const struct nouveau_i2c_func *func;
-};
-
-struct nouveau_i2c_func {
- void (*drive_scl)(struct nouveau_i2c_port *, int);
- void (*drive_sda)(struct nouveau_i2c_port *, int);
- int (*sense_scl)(struct nouveau_i2c_port *);
- int (*sense_sda)(struct nouveau_i2c_port *);
-
- int (*aux)(struct nouveau_i2c_port *, bool, u8, u32, u8 *, u8);
- int (*pattern)(struct nouveau_i2c_port *, int pattern);
- int (*lnk_ctl)(struct nouveau_i2c_port *, int nr, int bw, bool enh);
- int (*drv_ctl)(struct nouveau_i2c_port *, int lane, int sw, int pe);
-};
-
-struct nouveau_i2c_board_info {
- struct i2c_board_info dev;
- u8 udelay; /* set to 0 to use the standard delay */
-};
-
-struct nouveau_i2c {
- struct nouveau_subdev base;
- struct nvkm_event event;
-
- struct nouveau_i2c_port *(*find)(struct nouveau_i2c *, u8 index);
- struct nouveau_i2c_port *(*find_type)(struct nouveau_i2c *, u16 type);
- int (*acquire_pad)(struct nouveau_i2c_port *, unsigned long timeout);
- void (*release_pad)(struct nouveau_i2c_port *);
- int (*acquire)(struct nouveau_i2c_port *, unsigned long timeout);
- void (*release)(struct nouveau_i2c_port *);
- int (*identify)(struct nouveau_i2c *, int index,
- const char *what, struct nouveau_i2c_board_info *,
- bool (*match)(struct nouveau_i2c_port *,
- struct i2c_board_info *, void *), void *);
-
- wait_queue_head_t wait;
- struct list_head ports;
-};
-
-static inline struct nouveau_i2c *
-nouveau_i2c(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_I2C];
-}
-
-extern struct nouveau_oclass *nv04_i2c_oclass;
-extern struct nouveau_oclass *nv4e_i2c_oclass;
-extern struct nouveau_oclass *nv50_i2c_oclass;
-extern struct nouveau_oclass *nv94_i2c_oclass;
-extern struct nouveau_oclass *nvd0_i2c_oclass;
-extern struct nouveau_oclass *gf117_i2c_oclass;
-extern struct nouveau_oclass *nve0_i2c_oclass;
-extern struct nouveau_oclass *gm204_i2c_oclass;
-
-static inline int
-nv_rdi2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg)
-{
- u8 val;
- struct i2c_msg msgs[] = {
- { .addr = addr, .flags = 0, .len = 1, .buf = &reg },
- { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
- };
-
- int ret = i2c_transfer(&port->adapter, msgs, 2);
- if (ret != 2)
- return -EIO;
-
- return val;
-}
-
-static inline int
-nv_wri2cr(struct nouveau_i2c_port *port, u8 addr, u8 reg, u8 val)
-{
- u8 buf[2] = { reg, val };
- struct i2c_msg msgs[] = {
- { .addr = addr, .flags = 0, .len = 2, .buf = buf },
- };
-
- int ret = i2c_transfer(&port->adapter, msgs, 1);
- if (ret != 1)
- return -EIO;
-
- return 0;
-}
-
-static inline bool
-nv_probe_i2c(struct nouveau_i2c_port *port, u8 addr)
-{
- return nv_rdi2cr(port, addr, 0) >= 0;
-}
-
-int nv_rdaux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
-int nv_wraux(struct nouveau_i2c_port *, u32 addr, u8 *data, u8 size);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h b/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h
deleted file mode 100644
index 31df634c0fdc..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/ibus.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_IBUS_H__
-#define __NOUVEAU_IBUS_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_ibus {
- struct nouveau_subdev base;
-};
-
-static inline struct nouveau_ibus *
-nouveau_ibus(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_IBUS];
-}
-
-#define nouveau_ibus_create(p,e,o,d) \
- nouveau_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus", \
- sizeof(**d), (void **)d)
-#define nouveau_ibus_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_ibus_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_ibus_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-#define _nouveau_ibus_dtor _nouveau_subdev_dtor
-#define _nouveau_ibus_init _nouveau_subdev_init
-#define _nouveau_ibus_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nvc0_ibus_oclass;
-extern struct nouveau_oclass nve0_ibus_oclass;
-extern struct nouveau_oclass gk20a_ibus_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h b/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
deleted file mode 100644
index c1df26f3230c..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/instmem.h
+++ /dev/null
@@ -1,52 +0,0 @@
-#ifndef __NOUVEAU_INSTMEM_H__
-#define __NOUVEAU_INSTMEM_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/mm.h>
-
-struct nouveau_instobj {
- struct nouveau_object base;
- struct list_head head;
- u32 *suspend;
- u64 addr;
- u32 size;
-};
-
-static inline struct nouveau_instobj *
-nv_memobj(void *obj)
-{
-#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
- if (unlikely(!nv_iclass(obj, NV_MEMOBJ_CLASS)))
- nv_assert("BAD CAST -> NvMemObj, %08x", nv_hclass(obj));
-#endif
- return obj;
-}
-
-struct nouveau_instmem {
- struct nouveau_subdev base;
- struct list_head list;
-
- u32 reserved;
- int (*alloc)(struct nouveau_instmem *, struct nouveau_object *,
- u32 size, u32 align, struct nouveau_object **);
-};
-
-static inline struct nouveau_instmem *
-nouveau_instmem(void *obj)
-{
- /* nv04/nv40 impls need to create objects in their constructor,
- * which is before the subdev pointer is valid
- */
- if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
- nv_subidx(obj) == NVDEV_SUBDEV_INSTMEM)
- return obj;
-
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_INSTMEM];
-}
-
-extern struct nouveau_oclass *nv04_instmem_oclass;
-extern struct nouveau_oclass *nv40_instmem_oclass;
-extern struct nouveau_oclass *nv50_instmem_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h b/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h
deleted file mode 100644
index b909a7363f6b..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/ltc.h
+++ /dev/null
@@ -1,35 +0,0 @@
-#ifndef __NOUVEAU_LTC_H__
-#define __NOUVEAU_LTC_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-#define NOUVEAU_LTC_MAX_ZBC_CNT 16
-
-struct nouveau_mm_node;
-
-struct nouveau_ltc {
- struct nouveau_subdev base;
-
- int (*tags_alloc)(struct nouveau_ltc *, u32 count,
- struct nouveau_mm_node **);
- void (*tags_free)(struct nouveau_ltc *, struct nouveau_mm_node **);
- void (*tags_clear)(struct nouveau_ltc *, u32 first, u32 count);
-
- int zbc_min;
- int zbc_max;
- int (*zbc_color_get)(struct nouveau_ltc *, int index, const u32[4]);
- int (*zbc_depth_get)(struct nouveau_ltc *, int index, const u32);
-};
-
-static inline struct nouveau_ltc *
-nouveau_ltc(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_LTC];
-}
-
-extern struct nouveau_oclass *gf100_ltc_oclass;
-extern struct nouveau_oclass *gk104_ltc_oclass;
-extern struct nouveau_oclass *gm107_ltc_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h b/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
deleted file mode 100644
index 568e4dfc5e9e..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mc.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NOUVEAU_MC_H__
-#define __NOUVEAU_MC_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_mc {
- struct nouveau_subdev base;
- bool use_msi;
- unsigned int irq;
- void (*unk260)(struct nouveau_mc *, u32);
-};
-
-static inline struct nouveau_mc *
-nouveau_mc(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MC];
-}
-
-extern struct nouveau_oclass *nv04_mc_oclass;
-extern struct nouveau_oclass *nv40_mc_oclass;
-extern struct nouveau_oclass *nv44_mc_oclass;
-extern struct nouveau_oclass *nv4c_mc_oclass;
-extern struct nouveau_oclass *nv50_mc_oclass;
-extern struct nouveau_oclass *nv94_mc_oclass;
-extern struct nouveau_oclass *nv98_mc_oclass;
-extern struct nouveau_oclass *nvc0_mc_oclass;
-extern struct nouveau_oclass *nvc3_mc_oclass;
-extern struct nouveau_oclass *gk20a_mc_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h b/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
deleted file mode 100644
index b93b152cb566..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/mxm.h
+++ /dev/null
@@ -1,37 +0,0 @@
-#ifndef __NOUVEAU_MXM_H__
-#define __NOUVEAU_MXM_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-#define MXM_SANITISE_DCB 0x00000001
-
-struct nouveau_mxm {
- struct nouveau_subdev base;
- u32 action;
- u8 *mxms;
-};
-
-static inline struct nouveau_mxm *
-nouveau_mxm(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_MXM];
-}
-
-#define nouveau_mxm_create(p,e,o,d) \
- nouveau_mxm_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_mxm_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_mxm_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-int nouveau_mxm_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void nouveau_mxm_destroy(struct nouveau_mxm *);
-
-#define _nouveau_mxm_dtor _nouveau_subdev_dtor
-#define _nouveau_mxm_init _nouveau_subdev_init
-#define _nouveau_mxm_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nv50_mxm_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h b/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
deleted file mode 100644
index f2427bf5aeed..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/pwr.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NOUVEAU_PWR_H__
-#define __NOUVEAU_PWR_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_pwr {
- struct nouveau_subdev base;
-
- struct {
- u32 base;
- u32 size;
- } send;
-
- struct {
- u32 base;
- u32 size;
-
- struct work_struct work;
- wait_queue_head_t wait;
- u32 process;
- u32 message;
- u32 data[2];
- } recv;
-
- int (*message)(struct nouveau_pwr *, u32[2], u32, u32, u32, u32);
- void (*pgob)(struct nouveau_pwr *, bool);
-};
-
-static inline struct nouveau_pwr *
-nouveau_pwr(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_PWR];
-}
-
-extern struct nouveau_oclass *nva3_pwr_oclass;
-extern struct nouveau_oclass *nvc0_pwr_oclass;
-extern struct nouveau_oclass *nvd0_pwr_oclass;
-extern struct nouveau_oclass *gk104_pwr_oclass;
-extern struct nouveau_oclass *nv108_pwr_oclass;
-
-/* interface to MEMX process running on PPWR */
-struct nouveau_memx;
-int nouveau_memx_init(struct nouveau_pwr *, struct nouveau_memx **);
-int nouveau_memx_fini(struct nouveau_memx **, bool exec);
-void nouveau_memx_wr32(struct nouveau_memx *, u32 addr, u32 data);
-void nouveau_memx_wait(struct nouveau_memx *,
- u32 addr, u32 mask, u32 data, u32 nsec);
-void nouveau_memx_nsec(struct nouveau_memx *, u32 nsec);
-void nouveau_memx_wait_vblank(struct nouveau_memx *);
-void nouveau_memx_train(struct nouveau_memx *);
-int nouveau_memx_train_result(struct nouveau_pwr *, u32 *, int);
-void nouveau_memx_block(struct nouveau_memx *);
-void nouveau_memx_unblock(struct nouveau_memx *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h b/drivers/gpu/drm/nouveau/core/include/subdev/therm.h
deleted file mode 100644
index a437597dcafc..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/therm.h
+++ /dev/null
@@ -1,83 +0,0 @@
-#ifndef __NOUVEAU_THERM_H__
-#define __NOUVEAU_THERM_H__
-
-#include <core/device.h>
-#include <core/subdev.h>
-
-enum nouveau_therm_fan_mode {
- NOUVEAU_THERM_CTRL_NONE = 0,
- NOUVEAU_THERM_CTRL_MANUAL = 1,
- NOUVEAU_THERM_CTRL_AUTO = 2,
-};
-
-enum nouveau_therm_attr_type {
- NOUVEAU_THERM_ATTR_FAN_MIN_DUTY = 0,
- NOUVEAU_THERM_ATTR_FAN_MAX_DUTY = 1,
- NOUVEAU_THERM_ATTR_FAN_MODE = 2,
-
- NOUVEAU_THERM_ATTR_THRS_FAN_BOOST = 10,
- NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST = 11,
- NOUVEAU_THERM_ATTR_THRS_DOWN_CLK = 12,
- NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST = 13,
- NOUVEAU_THERM_ATTR_THRS_CRITICAL = 14,
- NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST = 15,
- NOUVEAU_THERM_ATTR_THRS_SHUTDOWN = 16,
- NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST = 17,
-};
-
-struct nouveau_therm {
- struct nouveau_subdev base;
-
- int (*pwm_ctrl)(struct nouveau_therm *, int line, bool);
- int (*pwm_get)(struct nouveau_therm *, int line, u32 *, u32 *);
- int (*pwm_set)(struct nouveau_therm *, int line, u32, u32);
- int (*pwm_clock)(struct nouveau_therm *, int line);
-
- int (*fan_get)(struct nouveau_therm *);
- int (*fan_set)(struct nouveau_therm *, int);
- int (*fan_sense)(struct nouveau_therm *);
-
- int (*temp_get)(struct nouveau_therm *);
-
- int (*attr_get)(struct nouveau_therm *, enum nouveau_therm_attr_type);
- int (*attr_set)(struct nouveau_therm *,
- enum nouveau_therm_attr_type, int);
-};
-
-static inline struct nouveau_therm *
-nouveau_therm(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_THERM];
-}
-
-#define nouveau_therm_create(p,e,o,d) \
- nouveau_therm_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_therm_destroy(p) ({ \
- struct nouveau_therm *therm = (p); \
- _nouveau_therm_dtor(nv_object(therm)); \
-})
-#define nouveau_therm_init(p) ({ \
- struct nouveau_therm *therm = (p); \
- _nouveau_therm_init(nv_object(therm)); \
-})
-#define nouveau_therm_fini(p,s) ({ \
- struct nouveau_therm *therm = (p); \
- _nouveau_therm_init(nv_object(therm), (s)); \
-})
-
-int nouveau_therm_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_therm_dtor(struct nouveau_object *);
-int _nouveau_therm_init(struct nouveau_object *);
-int _nouveau_therm_fini(struct nouveau_object *, bool);
-
-int nouveau_therm_cstate(struct nouveau_therm *, int, int);
-
-extern struct nouveau_oclass nv40_therm_oclass;
-extern struct nouveau_oclass nv50_therm_oclass;
-extern struct nouveau_oclass nv84_therm_oclass;
-extern struct nouveau_oclass nva3_therm_oclass;
-extern struct nouveau_oclass nvd0_therm_oclass;
-extern struct nouveau_oclass gm107_therm_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h b/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
deleted file mode 100644
index db9be803a874..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/timer.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef __NOUVEAU_TIMER_H__
-#define __NOUVEAU_TIMER_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_alarm {
- struct list_head head;
- u64 timestamp;
- void (*func)(struct nouveau_alarm *);
-};
-
-static inline void
-nouveau_alarm_init(struct nouveau_alarm *alarm,
- void (*func)(struct nouveau_alarm *))
-{
- INIT_LIST_HEAD(&alarm->head);
- alarm->func = func;
-}
-
-bool nouveau_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
-bool nouveau_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
-bool nouveau_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
-void nouveau_timer_alarm(void *, u32 nsec, struct nouveau_alarm *);
-void nouveau_timer_alarm_cancel(void *, struct nouveau_alarm *);
-
-#define NV_WAIT_DEFAULT 2000000000ULL
-#define nv_wait(o,a,m,v) \
- nouveau_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v))
-#define nv_wait_ne(o,a,m,v) \
- nouveau_timer_wait_ne((o), NV_WAIT_DEFAULT, (a), (m), (v))
-#define nv_wait_cb(o,c,d) \
- nouveau_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d))
-
-struct nouveau_timer {
- struct nouveau_subdev base;
- u64 (*read)(struct nouveau_timer *);
- void (*alarm)(struct nouveau_timer *, u64 time, struct nouveau_alarm *);
- void (*alarm_cancel)(struct nouveau_timer *, struct nouveau_alarm *);
-};
-
-static inline struct nouveau_timer *
-nouveau_timer(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_TIMER];
-}
-
-#define nouveau_timer_create(p,e,o,d) \
- nouveau_subdev_create_((p), (e), (o), 0, "PTIMER", "timer", \
- sizeof(**d), (void **)d)
-#define nouveau_timer_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_timer_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_timer_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_timer_create_(struct nouveau_object *, struct nouveau_engine *,
- struct nouveau_oclass *, int size, void **);
-
-extern struct nouveau_oclass nv04_timer_oclass;
-extern struct nouveau_oclass gk20a_timer_oclass;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h b/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
deleted file mode 100644
index c9509039f94b..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vm.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#ifndef __NOUVEAU_VM_H__
-#define __NOUVEAU_VM_H__
-
-#include <core/object.h>
-#include <core/subdev.h>
-#include <core/device.h>
-#include <core/mm.h>
-
-struct nouveau_vm_pgt {
- struct nouveau_gpuobj *obj[2];
- u32 refcount[2];
-};
-
-struct nouveau_vm_pgd {
- struct list_head head;
- struct nouveau_gpuobj *obj;
-};
-
-struct nouveau_gpuobj;
-struct nouveau_mem;
-
-struct nouveau_vma {
- struct list_head head;
- int refcount;
- struct nouveau_vm *vm;
- struct nouveau_mm_node *node;
- u64 offset;
- u32 access;
-};
-
-struct nouveau_vm {
- struct nouveau_vmmgr *vmm;
- struct nouveau_mm mm;
- struct kref refcount;
-
- struct list_head pgd_list;
- atomic_t engref[NVDEV_SUBDEV_NR];
-
- struct nouveau_vm_pgt *pgt;
- u32 fpde;
- u32 lpde;
-};
-
-struct nouveau_vmmgr {
- struct nouveau_subdev base;
-
- u64 limit;
- u8 dma_bits;
- u32 pgt_bits;
- u8 spg_shift;
- u8 lpg_shift;
-
- int (*create)(struct nouveau_vmmgr *, u64 offset, u64 length,
- u64 mm_offset, struct nouveau_vm **);
-
- void (*map_pgt)(struct nouveau_gpuobj *pgd, u32 pde,
- struct nouveau_gpuobj *pgt[2]);
- void (*map)(struct nouveau_vma *, struct nouveau_gpuobj *,
- struct nouveau_mem *, u32 pte, u32 cnt,
- u64 phys, u64 delta);
- void (*map_sg)(struct nouveau_vma *, struct nouveau_gpuobj *,
- struct nouveau_mem *, u32 pte, u32 cnt, dma_addr_t *);
- void (*unmap)(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt);
- void (*flush)(struct nouveau_vm *);
-};
-
-static inline struct nouveau_vmmgr *
-nouveau_vmmgr(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VM];
-}
-
-#define nouveau_vmmgr_create(p,e,o,i,f,d) \
- nouveau_subdev_create((p), (e), (o), 0, (i), (f), (d))
-#define nouveau_vmmgr_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_vmmgr_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_vmmgr_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-#define _nouveau_vmmgr_dtor _nouveau_subdev_dtor
-#define _nouveau_vmmgr_init _nouveau_subdev_init
-#define _nouveau_vmmgr_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nv04_vmmgr_oclass;
-extern struct nouveau_oclass nv41_vmmgr_oclass;
-extern struct nouveau_oclass nv44_vmmgr_oclass;
-extern struct nouveau_oclass nv50_vmmgr_oclass;
-extern struct nouveau_oclass nvc0_vmmgr_oclass;
-
-int nv04_vm_create(struct nouveau_vmmgr *, u64, u64, u64,
- struct nouveau_vm **);
-void nv04_vmmgr_dtor(struct nouveau_object *);
-
-/* nouveau_vm.c */
-int nouveau_vm_create(struct nouveau_vmmgr *, u64 offset, u64 length,
- u64 mm_offset, u32 block, struct nouveau_vm **);
-int nouveau_vm_new(struct nouveau_device *, u64 offset, u64 length,
- u64 mm_offset, struct nouveau_vm **);
-int nouveau_vm_ref(struct nouveau_vm *, struct nouveau_vm **,
- struct nouveau_gpuobj *pgd);
-int nouveau_vm_get(struct nouveau_vm *, u64 size, u32 page_shift,
- u32 access, struct nouveau_vma *);
-void nouveau_vm_put(struct nouveau_vma *);
-void nouveau_vm_map(struct nouveau_vma *, struct nouveau_mem *);
-void nouveau_vm_map_at(struct nouveau_vma *, u64 offset, struct nouveau_mem *);
-void nouveau_vm_unmap(struct nouveau_vma *);
-void nouveau_vm_unmap_at(struct nouveau_vma *, u64 offset, u64 length);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h b/drivers/gpu/drm/nouveau/core/include/subdev/volt.h
deleted file mode 100644
index 67db5e58880d..000000000000
--- a/drivers/gpu/drm/nouveau/core/include/subdev/volt.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __NOUVEAU_VOLT_H__
-#define __NOUVEAU_VOLT_H__
-
-#include <core/subdev.h>
-#include <core/device.h>
-
-struct nouveau_voltage {
- u32 uv;
- u8 id;
-};
-
-struct nouveau_volt {
- struct nouveau_subdev base;
-
- int (*vid_get)(struct nouveau_volt *);
- int (*get)(struct nouveau_volt *);
- int (*vid_set)(struct nouveau_volt *, u8 vid);
- int (*set)(struct nouveau_volt *, u32 uv);
- int (*set_id)(struct nouveau_volt *, u8 id, int condition);
-
- u8 vid_mask;
- u8 vid_nr;
- struct {
- u32 uv;
- u8 vid;
- } vid[256];
-};
-
-static inline struct nouveau_volt *
-nouveau_volt(void *obj)
-{
- return (void *)nv_device(obj)->subdev[NVDEV_SUBDEV_VOLT];
-}
-
-#define nouveau_volt_create(p, e, o, d) \
- nouveau_volt_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_volt_destroy(p) ({ \
- struct nouveau_volt *v = (p); \
- _nouveau_volt_dtor(nv_object(v)); \
-})
-#define nouveau_volt_init(p) ({ \
- struct nouveau_volt *v = (p); \
- _nouveau_volt_init(nv_object(v)); \
-})
-#define nouveau_volt_fini(p,s) \
- nouveau_subdev_fini((p), (s))
-
-int nouveau_volt_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_volt_dtor(struct nouveau_object *);
-int _nouveau_volt_init(struct nouveau_object *);
-#define _nouveau_volt_fini _nouveau_subdev_fini
-
-extern struct nouveau_oclass nv40_volt_oclass;
-extern struct nouveau_oclass gk20a_volt_oclass;
-
-int nouveau_voltgpio_init(struct nouveau_volt *);
-int nouveau_voltgpio_get(struct nouveau_volt *);
-int nouveau_voltgpio_set(struct nouveau_volt *, u8);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c b/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
deleted file mode 100644
index b1adc69efd88..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/base.c
+++ /dev/null
@@ -1,149 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include "priv.h"
-
-struct nouveau_barobj {
- struct nouveau_object base;
- struct nouveau_vma vma;
- void __iomem *iomem;
-};
-
-static int
-nouveau_barobj_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_bar *bar = (void *)engine;
- struct nouveau_mem *mem = data;
- struct nouveau_barobj *barobj;
- int ret;
-
- ret = nouveau_object_create(parent, engine, oclass, 0, &barobj);
- *pobject = nv_object(barobj);
- if (ret)
- return ret;
-
- ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma);
- if (ret)
- return ret;
-
- barobj->iomem = ioremap(nv_device_resource_start(device, 3) +
- (u32)barobj->vma.offset, mem->size << 12);
- if (!barobj->iomem) {
- nv_warn(bar, "PRAMIN ioremap failed\n");
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static void
-nouveau_barobj_dtor(struct nouveau_object *object)
-{
- struct nouveau_bar *bar = (void *)object->engine;
- struct nouveau_barobj *barobj = (void *)object;
- if (barobj->vma.node) {
- if (barobj->iomem)
- iounmap(barobj->iomem);
- bar->unmap(bar, &barobj->vma);
- }
- nouveau_object_destroy(&barobj->base);
-}
-
-static u32
-nouveau_barobj_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_barobj *barobj = (void *)object;
- return ioread32_native(barobj->iomem + addr);
-}
-
-static void
-nouveau_barobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_barobj *barobj = (void *)object;
- iowrite32_native(data, barobj->iomem + addr);
-}
-
-static struct nouveau_oclass
-nouveau_barobj_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nouveau_barobj_ctor,
- .dtor = nouveau_barobj_dtor,
- .init = nouveau_object_init,
- .fini = nouveau_object_fini,
- .rd32 = nouveau_barobj_rd32,
- .wr32 = nouveau_barobj_wr32,
- },
-};
-
-int
-nouveau_bar_alloc(struct nouveau_bar *bar, struct nouveau_object *parent,
- struct nouveau_mem *mem, struct nouveau_object **pobject)
-{
- struct nouveau_object *engine = nv_object(bar);
- struct nouveau_object *gpuobj;
- int ret = nouveau_object_ctor(parent, engine, &nouveau_barobj_oclass,
- mem, 0, &gpuobj);
- if (ret == 0)
- *pobject = gpuobj;
- return ret;
-}
-
-int
-nouveau_bar_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- struct nouveau_bar *bar;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "BARCTL",
- "bar", length, pobject);
- bar = *pobject;
- if (ret)
- return ret;
-
- return 0;
-}
-
-void
-nouveau_bar_destroy(struct nouveau_bar *bar)
-{
- nouveau_subdev_destroy(&bar->base);
-}
-
-void
-_nouveau_bar_dtor(struct nouveau_object *object)
-{
- struct nouveau_bar *bar = (void *)object;
- nouveau_bar_destroy(bar);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c
deleted file mode 100644
index bf877af9d3bd..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/gk20a.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 <subdev/bar.h>
-
-#include "priv.h"
-
-int
-gk20a_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_bar *bar;
- int ret;
-
- ret = nvc0_bar_ctor(parent, engine, oclass, data, size, pobject);
- if (ret)
- return ret;
-
- bar = (struct nouveau_bar *)*pobject;
- bar->iomap_uncached = true;
-
- return 0;
-}
-
-struct nouveau_oclass
-gk20a_bar_oclass = {
- .handle = NV_SUBDEV(BAR, 0xea),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gk20a_bar_ctor,
- .dtor = nvc0_bar_dtor,
- .init = nvc0_bar_init,
- .fini = _nouveau_bar_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
deleted file mode 100644
index f748ba49dfc8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nv50.c
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include "priv.h"
-
-struct nv50_bar_priv {
- struct nouveau_bar base;
- spinlock_t lock;
- struct nouveau_gpuobj *mem;
- struct nouveau_gpuobj *pad;
- struct nouveau_gpuobj *pgd;
- struct nouveau_vm *bar1_vm;
- struct nouveau_gpuobj *bar1;
- struct nouveau_vm *bar3_vm;
- struct nouveau_gpuobj *bar3;
-};
-
-static int
-nv50_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem,
- u32 flags, struct nouveau_vma *vma)
-{
- struct nv50_bar_priv *priv = (void *)bar;
- int ret;
-
- ret = nouveau_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma);
- if (ret)
- return ret;
-
- nouveau_vm_map(vma, mem);
- return 0;
-}
-
-static int
-nv50_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem,
- u32 flags, struct nouveau_vma *vma)
-{
- struct nv50_bar_priv *priv = (void *)bar;
- int ret;
-
- ret = nouveau_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma);
- if (ret)
- return ret;
-
- nouveau_vm_map(vma, mem);
- return 0;
-}
-
-static void
-nv50_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
-{
- nouveau_vm_unmap(vma);
- nouveau_vm_put(vma);
-}
-
-static void
-nv50_bar_flush(struct nouveau_bar *bar)
-{
- struct nv50_bar_priv *priv = (void *)bar;
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- nv_wr32(priv, 0x00330c, 0x00000001);
- if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000))
- nv_warn(priv, "flush timeout\n");
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-void
-nv84_bar_flush(struct nouveau_bar *bar)
-{
- struct nv50_bar_priv *priv = (void *)bar;
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- nv_wr32(bar, 0x070000, 0x00000001);
- if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000))
- nv_warn(priv, "flush timeout\n");
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static int
-nv50_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_object *heap;
- struct nouveau_vm *vm;
- struct nv50_bar_priv *priv;
- u64 start, limit;
- int ret;
-
- ret = nouveau_bar_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
- NVOBJ_FLAG_HEAP, &priv->mem);
- heap = nv_object(priv->mem);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), heap,
- (device->chipset == 0x50) ? 0x1400 : 0x0200,
- 0, 0, &priv->pad);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), heap, 0x4000, 0,
- 0, &priv->pgd);
- if (ret)
- return ret;
-
- /* BAR3 */
- start = 0x0100000000ULL;
- limit = start + nv_device_resource_len(device, 3);
-
- ret = nouveau_vm_new(device, start, limit, start, &vm);
- if (ret)
- return ret;
-
- atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
-
- ret = nouveau_gpuobj_new(nv_object(priv), heap,
- ((limit-- - start) >> 12) * 8, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]);
- vm->pgt[0].refcount[0] = 1;
- if (ret)
- return ret;
-
- ret = nouveau_vm_ref(vm, &priv->bar3_vm, priv->pgd);
- nouveau_vm_ref(NULL, &vm, NULL);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3);
- if (ret)
- return ret;
-
- nv_wo32(priv->bar3, 0x00, 0x7fc00000);
- nv_wo32(priv->bar3, 0x04, lower_32_bits(limit));
- nv_wo32(priv->bar3, 0x08, lower_32_bits(start));
- nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 |
- upper_32_bits(start));
- nv_wo32(priv->bar3, 0x10, 0x00000000);
- nv_wo32(priv->bar3, 0x14, 0x00000000);
-
- /* BAR1 */
- start = 0x0000000000ULL;
- limit = start + nv_device_resource_len(device, 1);
-
- ret = nouveau_vm_new(device, start, limit--, start, &vm);
- if (ret)
- return ret;
-
- atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
-
- ret = nouveau_vm_ref(vm, &priv->bar1_vm, priv->pgd);
- nouveau_vm_ref(NULL, &vm, NULL);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1);
- if (ret)
- return ret;
-
- nv_wo32(priv->bar1, 0x00, 0x7fc00000);
- nv_wo32(priv->bar1, 0x04, lower_32_bits(limit));
- nv_wo32(priv->bar1, 0x08, lower_32_bits(start));
- nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 |
- upper_32_bits(start));
- nv_wo32(priv->bar1, 0x10, 0x00000000);
- nv_wo32(priv->bar1, 0x14, 0x00000000);
-
- priv->base.alloc = nouveau_bar_alloc;
- priv->base.kmap = nv50_bar_kmap;
- priv->base.umap = nv50_bar_umap;
- priv->base.unmap = nv50_bar_unmap;
- if (device->chipset == 0x50)
- priv->base.flush = nv50_bar_flush;
- else
- priv->base.flush = nv84_bar_flush;
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-static void
-nv50_bar_dtor(struct nouveau_object *object)
-{
- struct nv50_bar_priv *priv = (void *)object;
- nouveau_gpuobj_ref(NULL, &priv->bar1);
- nouveau_vm_ref(NULL, &priv->bar1_vm, priv->pgd);
- nouveau_gpuobj_ref(NULL, &priv->bar3);
- if (priv->bar3_vm) {
- nouveau_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]);
- nouveau_vm_ref(NULL, &priv->bar3_vm, priv->pgd);
- }
- nouveau_gpuobj_ref(NULL, &priv->pgd);
- nouveau_gpuobj_ref(NULL, &priv->pad);
- nouveau_gpuobj_ref(NULL, &priv->mem);
- nouveau_bar_destroy(&priv->base);
-}
-
-static int
-nv50_bar_init(struct nouveau_object *object)
-{
- struct nv50_bar_priv *priv = (void *)object;
- int ret, i;
-
- ret = nouveau_bar_init(&priv->base);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
- nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
- nv_wr32(priv, 0x100c80, 0x00060001);
- if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) {
- nv_error(priv, "vm flush timeout\n");
- return -EBUSY;
- }
-
- nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12);
- nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
- nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4);
- nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4);
- for (i = 0; i < 8; i++)
- nv_wr32(priv, 0x001900 + (i * 4), 0x00000000);
- return 0;
-}
-
-static int
-nv50_bar_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_bar_priv *priv = (void *)object;
- return nouveau_bar_fini(&priv->base, suspend);
-}
-
-struct nouveau_oclass
-nv50_bar_oclass = {
- .handle = NV_SUBDEV(BAR, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_bar_ctor,
- .dtor = nv50_bar_dtor,
- .init = nv50_bar_init,
- .fini = nv50_bar_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
deleted file mode 100644
index 05a278bab247..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/nvc0.c
+++ /dev/null
@@ -1,220 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-#include "priv.h"
-
-struct nvc0_bar_priv_vm {
- struct nouveau_gpuobj *mem;
- struct nouveau_gpuobj *pgd;
- struct nouveau_vm *vm;
-};
-
-struct nvc0_bar_priv {
- struct nouveau_bar base;
- spinlock_t lock;
- struct nvc0_bar_priv_vm bar[2];
-};
-
-static int
-nvc0_bar_kmap(struct nouveau_bar *bar, struct nouveau_mem *mem,
- u32 flags, struct nouveau_vma *vma)
-{
- struct nvc0_bar_priv *priv = (void *)bar;
- int ret;
-
- ret = nouveau_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma);
- if (ret)
- return ret;
-
- nouveau_vm_map(vma, mem);
- return 0;
-}
-
-static int
-nvc0_bar_umap(struct nouveau_bar *bar, struct nouveau_mem *mem,
- u32 flags, struct nouveau_vma *vma)
-{
- struct nvc0_bar_priv *priv = (void *)bar;
- int ret;
-
- ret = nouveau_vm_get(priv->bar[1].vm, mem->size << 12,
- mem->page_shift, flags, vma);
- if (ret)
- return ret;
-
- nouveau_vm_map(vma, mem);
- return 0;
-}
-
-static void
-nvc0_bar_unmap(struct nouveau_bar *bar, struct nouveau_vma *vma)
-{
- nouveau_vm_unmap(vma);
- nouveau_vm_put(vma);
-}
-
-static int
-nvc0_bar_init_vm(struct nvc0_bar_priv *priv, struct nvc0_bar_priv_vm *bar_vm,
- int bar_nr)
-{
- struct nouveau_device *device = nv_device(&priv->base);
- struct nouveau_vm *vm;
- resource_size_t bar_len;
- int ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
- &bar_vm->mem);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0,
- &bar_vm->pgd);
- if (ret)
- return ret;
-
- bar_len = nv_device_resource_len(device, bar_nr);
-
- ret = nouveau_vm_new(device, 0, bar_len, 0, &vm);
- if (ret)
- return ret;
-
- atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
-
- /*
- * Bootstrap page table lookup.
- */
- if (bar_nr == 3) {
- ret = nouveau_gpuobj_new(nv_object(priv), NULL,
- (bar_len >> 12) * 8, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC,
- &vm->pgt[0].obj[0]);
- vm->pgt[0].refcount[0] = 1;
- if (ret)
- return ret;
- }
-
- ret = nouveau_vm_ref(vm, &bar_vm->vm, bar_vm->pgd);
- nouveau_vm_ref(NULL, &vm, NULL);
- if (ret)
- return ret;
-
- nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr));
- nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr));
- nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1));
- nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1));
-
- return 0;
-}
-
-int
-nvc0_bar_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nvc0_bar_priv *priv;
- bool has_bar3 = nv_device_resource_len(device, 3) != 0;
- int ret;
-
- ret = nouveau_bar_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- /* BAR3 */
- if (has_bar3) {
- ret = nvc0_bar_init_vm(priv, &priv->bar[0], 3);
- if (ret)
- return ret;
- priv->base.alloc = nouveau_bar_alloc;
- priv->base.kmap = nvc0_bar_kmap;
- }
-
- /* BAR1 */
- ret = nvc0_bar_init_vm(priv, &priv->bar[1], 1);
- if (ret)
- return ret;
-
- priv->base.umap = nvc0_bar_umap;
- priv->base.unmap = nvc0_bar_unmap;
- priv->base.flush = nv84_bar_flush;
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-void
-nvc0_bar_dtor(struct nouveau_object *object)
-{
- struct nvc0_bar_priv *priv = (void *)object;
-
- nouveau_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd);
- nouveau_gpuobj_ref(NULL, &priv->bar[1].pgd);
- nouveau_gpuobj_ref(NULL, &priv->bar[1].mem);
-
- if (priv->bar[0].vm) {
- nouveau_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]);
- nouveau_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd);
- }
- nouveau_gpuobj_ref(NULL, &priv->bar[0].pgd);
- nouveau_gpuobj_ref(NULL, &priv->bar[0].mem);
-
- nouveau_bar_destroy(&priv->base);
-}
-
-int
-nvc0_bar_init(struct nouveau_object *object)
-{
- struct nvc0_bar_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_bar_init(&priv->base);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
- nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
-
- nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12);
- if (priv->bar[0].mem)
- nv_wr32(priv, 0x001714,
- 0xc0000000 | priv->bar[0].mem->addr >> 12);
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_bar_oclass = {
- .handle = NV_SUBDEV(BAR, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_bar_ctor,
- .dtor = nvc0_bar_dtor,
- .init = nvc0_bar_init,
- .fini = _nouveau_bar_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h
deleted file mode 100644
index 3ee8b1476d00..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bar/priv.h
+++ /dev/null
@@ -1,32 +0,0 @@
-#ifndef __NVKM_BAR_PRIV_H__
-#define __NVKM_BAR_PRIV_H__
-
-#include <subdev/bar.h>
-
-#define nouveau_bar_create(p,e,o,d) \
- nouveau_bar_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_bar_init(p) \
- nouveau_subdev_init(&(p)->base)
-#define nouveau_bar_fini(p,s) \
- nouveau_subdev_fini(&(p)->base, (s))
-
-int nouveau_bar_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void nouveau_bar_destroy(struct nouveau_bar *);
-
-void _nouveau_bar_dtor(struct nouveau_object *);
-#define _nouveau_bar_init _nouveau_subdev_init
-#define _nouveau_bar_fini _nouveau_subdev_fini
-
-int nouveau_bar_alloc(struct nouveau_bar *, struct nouveau_object *,
- struct nouveau_mem *, struct nouveau_object **);
-
-void nv84_bar_flush(struct nouveau_bar *);
-
-int nvc0_bar_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nvc0_bar_dtor(struct nouveau_object *);
-int nvc0_bar_init(struct nouveau_object *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c
deleted file mode 100644
index 28906b16d4e5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/M0203.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/M0203.h>
-
-u32
-nvbios_M0203Te(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry bit_M;
- u32 data = 0x00000000;
-
- if (!bit_entry(bios, 'M', &bit_M)) {
- if (bit_M.version == 2 && bit_M.length > 0x04)
- data = nv_ro16(bios, bit_M.offset + 0x03);
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *cnt = nv_ro08(bios, data + 0x03);
- return data;
- default:
- break;
- }
- }
- }
-
- return 0x00000000;
-}
-
-u32
-nvbios_M0203Tp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_M0203T *info)
-{
- u32 data = nvbios_M0203Te(bios, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->type = nv_ro08(bios, data + 0x04);
- info->pointer = nv_ro16(bios, data + 0x05);
- break;
- default:
- break;
- }
- return data;
-}
-
-u32
-nvbios_M0203Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
- u8 cnt, len;
- u32 data = nvbios_M0203Te(bios, ver, hdr, &cnt, &len);
- if (data && idx < cnt) {
- data = data + *hdr + idx * len;
- *hdr = len;
- return data;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0203Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
- struct nvbios_M0203E *info)
-{
- u32 data = nvbios_M0203Ee(bios, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->type = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0;
- info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4;
- info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0;
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0203Em(struct nouveau_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr,
- struct nvbios_M0203E *info)
-{
- struct nvbios_M0203T M0203T;
- u8 cnt, len, idx = 0xff;
- u32 data;
-
- if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) {
- nv_warn(bios, "M0203T not found\n");
- return 0x00000000;
- }
-
- while ((data = nvbios_M0203Ep(bios, ++idx, ver, hdr, info))) {
- switch (M0203T.type) {
- case M0203T_TYPE_RAMCFG:
- if (info->strap != ramcfg)
- continue;
- return data;
- default:
- nv_warn(bios, "M0203T type %02x\n", M0203T.type);
- return 0x00000000;
- }
- }
-
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
deleted file mode 100644
index ac9617c5fc2a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/M0205.c
+++ /dev/null
@@ -1,136 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/M0205.h>
-
-u32
-nvbios_M0205Te(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
- struct bit_entry bit_M;
- u32 data = 0x00000000;
-
- if (!bit_entry(bios, 'M', &bit_M)) {
- if (bit_M.version == 2 && bit_M.length > 0x08)
- data = nv_ro32(bios, bit_M.offset + 0x05);
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *ssz = nv_ro08(bios, data + 0x03);
- *snr = nv_ro08(bios, data + 0x04);
- *cnt = nv_ro08(bios, data + 0x05);
- return data;
- default:
- break;
- }
- }
- }
-
- return 0x00000000;
-}
-
-u32
-nvbios_M0205Tp(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
- struct nvbios_M0205T *info)
-{
- u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->freq = nv_ro16(bios, data + 0x06);
- break;
- default:
- break;
- }
- return data;
-}
-
-u32
-nvbios_M0205Ee(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u8 snr, ssz;
- u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz);
- if (data && idx < *cnt) {
- data = data + *hdr + idx * (*len + (snr * ssz));
- *hdr = *len;
- *cnt = snr;
- *len = ssz;
- return data;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0205Ep(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_M0205E *info)
-{
- u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->type = nv_ro08(bios, data + 0x00) & 0x0f;
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0205Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
-{
-
- u8 cnt, len;
- u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len);
- if (data && idx < cnt) {
- data = data + *hdr + idx * len;
- *hdr = len;
- return data;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0205Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
- struct nvbios_M0205S *info)
-{
- u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->data = nv_ro08(bios, data + 0x00);
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
deleted file mode 100644
index b142a510e89f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/M0209.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/M0209.h>
-
-u32
-nvbios_M0209Te(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
- struct bit_entry bit_M;
- u32 data = 0x00000000;
-
- if (!bit_entry(bios, 'M', &bit_M)) {
- if (bit_M.version == 2 && bit_M.length > 0x0c)
- data = nv_ro32(bios, bit_M.offset + 0x09);
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *ssz = nv_ro08(bios, data + 0x03);
- *snr = 1;
- *cnt = nv_ro08(bios, data + 0x04);
- return data;
- default:
- break;
- }
- }
- }
-
- return 0x00000000;
-}
-
-u32
-nvbios_M0209Ee(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u8 snr, ssz;
- u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz);
- if (data && idx < *cnt) {
- data = data + *hdr + idx * (*len + (snr * ssz));
- *hdr = *len;
- *cnt = snr;
- *len = ssz;
- return data;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0209Ep(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_M0209E *info)
-{
- u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6;
- info->bits = nv_ro08(bios, data + 0x00) & 0x3f;
- info->modulo = nv_ro08(bios, data + 0x01);
- info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
- info->v02_07 = nv_ro08(bios, data + 0x02) & 0x07;
- info->v03 = nv_ro08(bios, data + 0x03);
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0209Se(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
-{
-
- u8 cnt, len;
- u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len);
- if (data && idx < cnt) {
- data = data + *hdr + idx * len;
- *hdr = len;
- return data;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_M0209Sp(struct nouveau_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
- struct nvbios_M0209S *info)
-{
- struct nvbios_M0209E M0209E;
- u8 cnt, len;
- u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E);
- if (data) {
- u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- for (i = 0; i < ARRAY_SIZE(info->data); i++) {
- u32 bits = (i % M0209E.modulo) * M0209E.bits;
- u32 mask = (1ULL << M0209E.bits) - 1;
- u16 off = bits / 8;
- u8 mod = bits % 8;
- info->data[i] = nv_ro32(bios, data + off);
- info->data[i] = info->data[i] >> mod;
- info->data[i] = info->data[i] & mask;
- }
- return data;
- default:
- break;
- }
- }
- return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c
deleted file mode 100644
index 199f4e5f7488..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/P0260.c
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/P0260.h>
-
-u32
-nvbios_P0260Te(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
-{
- struct bit_entry bit_P;
- u32 data = 0x00000000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2 && bit_P.length > 0x63)
- data = nv_ro32(bios, bit_P.offset + 0x60);
- if (data) {
- *ver = nv_ro08(bios, data + 0);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, data + 1);
- *cnt = nv_ro08(bios, data + 2);
- *len = 4;
- *xnr = nv_ro08(bios, data + 3);
- *xsz = 4;
- return data;
- default:
- break;
- }
- }
- }
-
- return 0x00000000;
-}
-
-u32
-nvbios_P0260Ee(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt, xnr, xsz;
- u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz);
- if (data && idx < cnt)
- return data + hdr + (idx * *len);
- return 0x00000000;
-}
-
-u32
-nvbios_P0260Ep(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
- struct nvbios_P0260E *info)
-{
- u32 data = nvbios_P0260Ee(bios, idx, ver, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->data = nv_ro32(bios, data);
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_P0260Xe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *xsz)
-{
- u8 hdr, cnt, len, xnr;
- u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz);
- if (data && idx < xnr)
- return data + hdr + (cnt * len) + (idx * *xsz);
- return 0x00000000;
-}
-
-u32
-nvbios_P0260Xp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
- struct nvbios_P0260X *info)
-{
- u32 data = nvbios_P0260Xe(bios, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x10:
- info->data = nv_ro32(bios, data);
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c b/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
deleted file mode 100644
index 7df3a273553d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/base.c
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/object.h>
-#include <core/device.h>
-#include <core/subdev.h>
-#include <core/option.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/bios/bit.h>
-
-#include "priv.h"
-
-u8
-nvbios_checksum(const u8 *data, int size)
-{
- u8 sum = 0;
- while (size--)
- sum += *data++;
- return sum;
-}
-
-u16
-nvbios_findstr(const u8 *data, int size, const char *str, int len)
-{
- int i, j;
-
- for (i = 0; i <= (size - len); i++) {
- for (j = 0; j < len; j++)
- if ((char)data[i + j] != str[j])
- break;
- if (j == len)
- return i;
- }
-
- return 0;
-}
-
-int
-nvbios_extend(struct nouveau_bios *bios, u32 length)
-{
- if (bios->size < length) {
- u8 *prev = bios->data;
- if (!(bios->data = kmalloc(length, GFP_KERNEL))) {
- bios->data = prev;
- return -ENOMEM;
- }
- memcpy(bios->data, prev, bios->size);
- bios->size = length;
- kfree(prev);
- return 1;
- }
- return 0;
-}
-
-static u8
-nouveau_bios_rd08(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_bios *bios = (void *)object;
- return bios->data[addr];
-}
-
-static u16
-nouveau_bios_rd16(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_bios *bios = (void *)object;
- return get_unaligned_le16(&bios->data[addr]);
-}
-
-static u32
-nouveau_bios_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_bios *bios = (void *)object;
- return get_unaligned_le32(&bios->data[addr]);
-}
-
-static void
-nouveau_bios_wr08(struct nouveau_object *object, u64 addr, u8 data)
-{
- struct nouveau_bios *bios = (void *)object;
- bios->data[addr] = data;
-}
-
-static void
-nouveau_bios_wr16(struct nouveau_object *object, u64 addr, u16 data)
-{
- struct nouveau_bios *bios = (void *)object;
- put_unaligned_le16(data, &bios->data[addr]);
-}
-
-static void
-nouveau_bios_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nouveau_bios *bios = (void *)object;
- put_unaligned_le32(data, &bios->data[addr]);
-}
-
-static int
-nouveau_bios_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_bios *bios;
- struct bit_entry bit_i;
- int ret;
-
- ret = nouveau_subdev_create(parent, engine, oclass, 0,
- "VBIOS", "bios", &bios);
- *pobject = nv_object(bios);
- if (ret)
- return ret;
-
- ret = nvbios_shadow(bios);
- if (ret)
- return ret;
-
- /* detect type of vbios we're dealing with */
- bios->bmp_offset = nvbios_findstr(bios->data, bios->size,
- "\xff\x7f""NV\0", 5);
- if (bios->bmp_offset) {
- nv_info(bios, "BMP version %x.%x\n",
- bmp_version(bios) >> 8,
- bmp_version(bios) & 0xff);
- }
-
- bios->bit_offset = nvbios_findstr(bios->data, bios->size,
- "\xff\xb8""BIT", 5);
- if (bios->bit_offset)
- nv_info(bios, "BIT signature found\n");
-
- /* determine the vbios version number */
- if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) {
- bios->version.major = nv_ro08(bios, bit_i.offset + 3);
- bios->version.chip = nv_ro08(bios, bit_i.offset + 2);
- bios->version.minor = nv_ro08(bios, bit_i.offset + 1);
- bios->version.micro = nv_ro08(bios, bit_i.offset + 0);
- bios->version.patch = nv_ro08(bios, bit_i.offset + 4);
- } else
- if (bmp_version(bios)) {
- bios->version.major = nv_ro08(bios, bios->bmp_offset + 13);
- bios->version.chip = nv_ro08(bios, bios->bmp_offset + 12);
- bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11);
- bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10);
- }
-
- nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n",
- bios->version.major, bios->version.chip,
- bios->version.minor, bios->version.micro, bios->version.patch);
-
- return 0;
-}
-
-static void
-nouveau_bios_dtor(struct nouveau_object *object)
-{
- struct nouveau_bios *bios = (void *)object;
- kfree(bios->data);
- nouveau_subdev_destroy(&bios->base);
-}
-
-static int
-nouveau_bios_init(struct nouveau_object *object)
-{
- struct nouveau_bios *bios = (void *)object;
- return nouveau_subdev_init(&bios->base);
-}
-
-static int
-nouveau_bios_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_bios *bios = (void *)object;
- return nouveau_subdev_fini(&bios->base, suspend);
-}
-
-struct nouveau_oclass
-nouveau_bios_oclass = {
- .handle = NV_SUBDEV(VBIOS, 0x00),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nouveau_bios_ctor,
- .dtor = nouveau_bios_dtor,
- .init = nouveau_bios_init,
- .fini = nouveau_bios_fini,
- .rd08 = nouveau_bios_rd08,
- .rd16 = nouveau_bios_rd16,
- .rd32 = nouveau_bios_rd32,
- .wr08 = nouveau_bios_wr08,
- .wr16 = nouveau_bios_wr16,
- .wr32 = nouveau_bios_wr32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c b/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c
deleted file mode 100644
index 1d03a3f2b2d2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/bit.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "core/object.h"
-
-#include "subdev/bios.h"
-#include "subdev/bios/bit.h"
-
-int
-bit_entry(struct nouveau_bios *bios, u8 id, struct bit_entry *bit)
-{
- if (likely(bios->bit_offset)) {
- u8 entries = nv_ro08(bios, bios->bit_offset + 10);
- u32 entry = bios->bit_offset + 12;
- while (entries--) {
- if (nv_ro08(bios, entry + 0) == id) {
- bit->id = nv_ro08(bios, entry + 0);
- bit->version = nv_ro08(bios, entry + 1);
- bit->length = nv_ro16(bios, entry + 2);
- bit->offset = nv_ro16(bios, entry + 4);
- return 0;
- }
-
- entry += nv_ro08(bios, bios->bit_offset + 9);
- }
-
- return -ENOENT;
- }
-
- return -EINVAL;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c
deleted file mode 100644
index c1835e591c44..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/boost.c
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/boost.h>
-
-u16
-nvbios_boostTe(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
- struct bit_entry bit_P;
- u16 boost = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2)
- boost = nv_ro16(bios, bit_P.offset + 0x30);
-
- if (boost) {
- *ver = nv_ro08(bios, boost + 0);
- switch (*ver) {
- case 0x11:
- *hdr = nv_ro08(bios, boost + 1);
- *cnt = nv_ro08(bios, boost + 5);
- *len = nv_ro08(bios, boost + 2);
- *snr = nv_ro08(bios, boost + 4);
- *ssz = nv_ro08(bios, boost + 3);
- return boost;
- default:
- break;
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_boostEe(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u8 snr, ssz;
- u16 data = nvbios_boostTe(bios, ver, hdr, cnt, len, &snr, &ssz);
- if (data && idx < *cnt) {
- data = data + *hdr + (idx * (*len + (snr * ssz)));
- *hdr = *len;
- *cnt = snr;
- *len = ssz;
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_boostEp(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
-{
- u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
- info->min = nv_ro16(bios, data + 0x02) * 1000;
- info->max = nv_ro16(bios, data + 0x04) * 1000;
- }
- return data;
-}
-
-u16
-nvbios_boostEm(struct nouveau_bios *bios, u8 pstate,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
-{
- u32 data, idx = 0;
- while ((data = nvbios_boostEp(bios, idx++, ver, hdr, cnt, len, info))) {
- if (info->pstate == pstate)
- break;
- }
- return data;
-}
-
-u16
-nvbios_boostSe(struct nouveau_bios *bios, int idx,
- u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len)
-{
- if (data && idx < cnt) {
- data = data + *hdr + (idx * len);
- *hdr = len;
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_boostSp(struct nouveau_bios *bios, int idx,
- u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len,
- struct nvbios_boostS *info)
-{
- data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- info->domain = nv_ro08(bios, data + 0x00);
- info->percent = nv_ro08(bios, data + 0x01);
- info->min = nv_ro16(bios, data + 0x02) * 1000;
- info->max = nv_ro16(bios, data + 0x04) * 1000;
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
deleted file mode 100644
index 2ede3bcd96a1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/conn.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/conn.h>
-
-u32
-nvbios_connTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u32 dcb = dcb_table(bios, ver, hdr, cnt, len);
- if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
- u32 data = nv_ro16(bios, dcb + 0x14);
- if (data) {
- *ver = nv_ro08(bios, data + 0);
- *hdr = nv_ro08(bios, data + 1);
- *cnt = nv_ro08(bios, data + 2);
- *len = nv_ro08(bios, data + 3);
- return data;
- }
- }
- return 0x00000000;
-}
-
-u32
-nvbios_connTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_connT *info)
-{
- u32 data = nvbios_connTe(bios, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x30:
- case 0x40:
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
-
-u32
-nvbios_connEe(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len);
- if (data && idx < cnt)
- return data + hdr + (idx * *len);
- return 0x00000000;
-}
-
-u32
-nvbios_connEp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
- struct nvbios_connE *info)
-{
- u32 data = nvbios_connEe(bios, idx, ver, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x30:
- case 0x40:
- info->type = nv_ro08(bios, data + 0x00);
- info->location = nv_ro08(bios, data + 0x01) & 0x0f;
- info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4;
- info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6;
- if (*len < 4)
- return data;
- info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2;
- info->dp |= nv_ro08(bios, data + 0x02) & 0x0c;
- info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4;
- info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4;
- info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3;
- info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4;
- return data;
- default:
- break;
- }
- return 0x00000000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c
deleted file mode 100644
index d3b15327fbfd..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/cstep.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/cstep.h>
-
-u16
-nvbios_cstepTe(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
-{
- struct bit_entry bit_P;
- u16 cstep = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2)
- cstep = nv_ro16(bios, bit_P.offset + 0x34);
-
- if (cstep) {
- *ver = nv_ro08(bios, cstep + 0);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, cstep + 1);
- *cnt = nv_ro08(bios, cstep + 3);
- *len = nv_ro08(bios, cstep + 2);
- *xnr = nv_ro08(bios, cstep + 5);
- *xsz = nv_ro08(bios, cstep + 4);
- return cstep;
- default:
- break;
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_cstepEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
- u8 cnt, len, xnr, xsz;
- u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
- if (data && idx < cnt) {
- data = data + *hdr + (idx * len);
- *hdr = len;
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_cstepEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
- struct nvbios_cstepE *info)
-{
- u16 data = nvbios_cstepEe(bios, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
- info->index = nv_ro08(bios, data + 0x03);
- }
- return data;
-}
-
-u16
-nvbios_cstepEm(struct nouveau_bios *bios, u8 pstate, u8 *ver, u8 *hdr,
- struct nvbios_cstepE *info)
-{
- u32 data, idx = 0;
- while ((data = nvbios_cstepEp(bios, idx++, ver, hdr, info))) {
- if (info->pstate == pstate)
- break;
- }
- return data;
-}
-
-u16
-nvbios_cstepXe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
- u8 cnt, len, xnr, xsz;
- u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
- if (data && idx < xnr) {
- data = data + *hdr + (cnt * len) + (idx * xsz);
- *hdr = xsz;
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_cstepXp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
- struct nvbios_cstepX *info)
-{
- u16 data = nvbios_cstepXe(bios, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- info->freq = nv_ro16(bios, data + 0x00) * 1000;
- info->unkn[0] = nv_ro08(bios, data + 0x02);
- info->unkn[1] = nv_ro08(bios, data + 0x03);
- info->voltage = nv_ro08(bios, data + 0x04);
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
deleted file mode 100644
index 96099aff8b41..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dcb.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "core/device.h"
-
-#include "subdev/bios.h"
-#include "subdev/bios/dcb.h"
-
-u16
-dcb_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct nouveau_device *device = nv_device(bios);
- u16 dcb = 0x0000;
-
- if (device->card_type > NV_04)
- dcb = nv_ro16(bios, 0x36);
- if (!dcb) {
- nv_warn(bios, "DCB table not found\n");
- return dcb;
- }
-
- *ver = nv_ro08(bios, dcb);
-
- if (*ver >= 0x42) {
- nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);
- return 0x0000;
- } else
- if (*ver >= 0x30) {
- if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) {
- *hdr = nv_ro08(bios, dcb + 1);
- *cnt = nv_ro08(bios, dcb + 2);
- *len = nv_ro08(bios, dcb + 3);
- return dcb;
- }
- } else
- if (*ver >= 0x20) {
- if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) {
- u16 i2c = nv_ro16(bios, dcb + 2);
- *hdr = 8;
- *cnt = (i2c - dcb) / 8;
- *len = 8;
- return dcb;
- }
- } else
- if (*ver >= 0x15) {
- if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) {
- u16 i2c = nv_ro16(bios, dcb + 2);
- *hdr = 4;
- *cnt = (i2c - dcb) / 10;
- *len = 10;
- return dcb;
- }
- } else {
- /*
- * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but
- * always has the same single (crt) entry, even when tv-out
- * present, so the conclusion is this version cannot really
- * be used.
- *
- * v1.2 tables (some NV6/10, and NV15+) normally have the
- * same 5 entries, which are not specific to the card and so
- * no use.
- *
- * v1.2 does have an I2C table that read_dcb_i2c_table can
- * handle, but cards exist (nv11 in #14821) with a bad i2c
- * table pointer, so use the indices parsed in
- * parse_bmp_structure.
- *
- * v1.1 (NV5+, maybe some NV4) is entirely unhelpful
- */
- nv_warn(bios, "DCB contains no useful data\n");
- return 0x0000;
- }
-
- nv_warn(bios, "DCB header validation failed\n");
- return 0x0000;
-}
-
-u16
-dcb_outp(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len);
- if (dcb && idx < cnt)
- return dcb + hdr + (idx * *len);
- return 0x0000;
-}
-
-static inline u16
-dcb_outp_hasht(struct dcb_output *outp)
-{
- return (outp->extdev << 8) | (outp->location << 4) | outp->type;
-}
-
-static inline u16
-dcb_outp_hashm(struct dcb_output *outp)
-{
- return (outp->heads << 8) | (outp->link << 6) | outp->or;
-}
-
-u16
-dcb_outp_parse(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len,
- struct dcb_output *outp)
-{
- u16 dcb = dcb_outp(bios, idx, ver, len);
- memset(outp, 0x00, sizeof(*outp));
- if (dcb) {
- if (*ver >= 0x20) {
- u32 conn = nv_ro32(bios, dcb + 0x00);
- outp->or = (conn & 0x0f000000) >> 24;
- outp->location = (conn & 0x00300000) >> 20;
- outp->bus = (conn & 0x000f0000) >> 16;
- outp->connector = (conn & 0x0000f000) >> 12;
- outp->heads = (conn & 0x00000f00) >> 8;
- outp->i2c_index = (conn & 0x000000f0) >> 4;
- outp->type = (conn & 0x0000000f);
- outp->link = 0;
- } else {
- dcb = 0x0000;
- }
-
- if (*ver >= 0x40) {
- u32 conf = nv_ro32(bios, dcb + 0x04);
- switch (outp->type) {
- case DCB_OUTPUT_DP:
- switch (conf & 0x00e00000) {
- case 0x00000000:
- outp->dpconf.link_bw = 0x06;
- break;
- case 0x00200000:
- outp->dpconf.link_bw = 0x0a;
- break;
- case 0x00400000:
- default:
- outp->dpconf.link_bw = 0x14;
- break;
- }
-
- outp->dpconf.link_nr = (conf & 0x0f000000) >> 24;
- if (*ver < 0x41) {
- switch (outp->dpconf.link_nr) {
- case 0x0f:
- outp->dpconf.link_nr = 4;
- break;
- case 0x03:
- outp->dpconf.link_nr = 2;
- break;
- case 0x01:
- default:
- outp->dpconf.link_nr = 1;
- break;
- }
- }
-
- /* fall-through... */
- case DCB_OUTPUT_TMDS:
- case DCB_OUTPUT_LVDS:
- outp->link = (conf & 0x00000030) >> 4;
- outp->sorconf.link = outp->link; /*XXX*/
- outp->extdev = 0x00;
- if (outp->location != 0)
- outp->extdev = (conf & 0x0000ff00) >> 8;
- break;
- default:
- break;
- }
- }
-
- outp->hasht = dcb_outp_hasht(outp);
- outp->hashm = dcb_outp_hashm(outp);
- }
- return dcb;
-}
-
-u16
-dcb_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
- u8 *ver, u8 *len, struct dcb_output *outp)
-{
- u16 dcb, idx = 0;
- while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
- if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) {
- if ((dcb_outp_hashm(outp) & mask) == mask)
- break;
- }
- }
- return dcb;
-}
-
-int
-dcb_outp_foreach(struct nouveau_bios *bios, void *data,
- int (*exec)(struct nouveau_bios *, void *, int, u16))
-{
- int ret, idx = -1;
- u8 ver, len;
- u16 outp;
-
- while ((outp = dcb_outp(bios, ++idx, &ver, &len))) {
- if (nv_ro32(bios, outp) == 0x00000000)
- break; /* seen on an NV11 with DCB v1.5 */
- if (nv_ro32(bios, outp) == 0xffffffff)
- break; /* seen on an NV17 with DCB v2.0 */
-
- if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED)
- continue;
- if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL)
- break;
-
- ret = exec(bios, data, idx, outp);
- if (ret)
- return ret;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
deleted file mode 100644
index 51f355599694..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/disp.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/disp.h>
-
-u16
-nvbios_disp_table(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub)
-{
- struct bit_entry U;
-
- if (!bit_entry(bios, 'U', &U)) {
- if (U.version == 1) {
- u16 data = nv_ro16(bios, U.offset);
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x20:
- case 0x21:
- case 0x22:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *cnt = nv_ro08(bios, data + 0x03);
- *sub = nv_ro08(bios, data + 0x04);
- return data;
- default:
- break;
- }
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_disp_entry(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *len, u8 *sub)
-{
- u8 hdr, cnt;
- u16 data = nvbios_disp_table(bios, ver, &hdr, &cnt, len, sub);
- if (data && idx < cnt)
- return data + hdr + (idx * *len);
- *ver = 0x00;
- return 0x0000;
-}
-
-u16
-nvbios_disp_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *len, u8 *sub,
- struct nvbios_disp *info)
-{
- u16 data = nvbios_disp_entry(bios, idx, ver, len, sub);
- if (data && *len >= 2) {
- info->data = nv_ro16(bios, data + 0);
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_outp_entry(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct nvbios_disp info;
- u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info);
- if (data) {
- *cnt = nv_ro08(bios, info.data + 0x05);
- *len = 0x06;
- data = info.data;
- }
- return data;
-}
-
-u16
-nvbios_outp_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len);
- if (data && *hdr >= 0x0a) {
- info->type = nv_ro16(bios, data + 0x00);
- info->mask = nv_ro32(bios, data + 0x02);
- if (*ver <= 0x20) /* match any link */
- info->mask |= 0x00c0;
- info->script[0] = nv_ro16(bios, data + 0x06);
- info->script[1] = nv_ro16(bios, data + 0x08);
- info->script[2] = 0x0000;
- if (*hdr >= 0x0c)
- info->script[2] = nv_ro16(bios, data + 0x0a);
- return data;
- }
- return 0x0000;
-}
-
-u16
-nvbios_outp_match(struct nouveau_bios *bios, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_outp *info)
-{
- u16 data, idx = 0;
- while ((data = nvbios_outp_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
- if (data && info->type == type) {
- if ((info->mask & mask) == mask)
- break;
- }
- }
- return data;
-}
-
-u16
-nvbios_ocfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- if (idx < *cnt)
- return outp + *hdr + (idx * *len);
- return 0x0000;
-}
-
-u16
-nvbios_ocfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *info)
-{
- u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len);
- if (data) {
- info->match = nv_ro16(bios, data + 0x00);
- info->clkcmp[0] = nv_ro16(bios, data + 0x02);
- info->clkcmp[1] = nv_ro16(bios, data + 0x04);
- }
- return data;
-}
-
-u16
-nvbios_ocfg_match(struct nouveau_bios *bios, u16 outp, u16 type,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ocfg *info)
-{
- u16 data, idx = 0;
- while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) {
- if (info->match == type)
- break;
- }
- return data;
-}
-
-u16
-nvbios_oclk_match(struct nouveau_bios *bios, u16 cmp, u32 khz)
-{
- while (cmp) {
- if (khz / 10 >= nv_ro16(bios, cmp + 0x00))
- return nv_ro16(bios, cmp + 0x02);
- cmp += 0x04;
- }
- return 0x0000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
deleted file mode 100644
index cef53f81f12b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/dp.c
+++ /dev/null
@@ -1,217 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-
-#include "subdev/bios.h"
-#include "subdev/bios/bit.h"
-#include "subdev/bios/dp.h"
-
-static u16
-nvbios_dp_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry d;
-
- if (!bit_entry(bios, 'd', &d)) {
- if (d.version == 1 && d.length >= 2) {
- u16 data = nv_ro16(bios, d.offset);
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- switch (*ver) {
- case 0x21:
- case 0x30:
- case 0x40:
- case 0x41:
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *cnt = nv_ro08(bios, data + 0x03);
- return data;
- default:
- break;
- }
- }
- }
- }
-
- return 0x0000;
-}
-
-static u16
-nvbios_dpout_entry(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
- if (data && idx < *cnt) {
- u16 outp = nv_ro16(bios, data + *hdr + idx * *len);
- switch (*ver * !!outp) {
- case 0x21:
- case 0x30:
- *hdr = nv_ro08(bios, data + 0x04);
- *len = nv_ro08(bios, data + 0x05);
- *cnt = nv_ro08(bios, outp + 0x04);
- break;
- case 0x40:
- case 0x41:
- *hdr = nv_ro08(bios, data + 0x04);
- *cnt = 0;
- *len = 0;
- break;
- default:
- break;
- }
- return outp;
- }
- *ver = 0x00;
- return 0x0000;
-}
-
-u16
-nvbios_dpout_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *info)
-{
- u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- if (data && *ver) {
- info->type = nv_ro16(bios, data + 0x00);
- info->mask = nv_ro16(bios, data + 0x02);
- switch (*ver) {
- case 0x21:
- case 0x30:
- info->flags = nv_ro08(bios, data + 0x05);
- info->script[0] = nv_ro16(bios, data + 0x06);
- info->script[1] = nv_ro16(bios, data + 0x08);
- info->lnkcmp = nv_ro16(bios, data + 0x0a);
- if (*len >= 0x0f) {
- info->script[2] = nv_ro16(bios, data + 0x0c);
- info->script[3] = nv_ro16(bios, data + 0x0e);
- }
- if (*len >= 0x11)
- info->script[4] = nv_ro16(bios, data + 0x10);
- break;
- case 0x40:
- case 0x41:
- info->flags = nv_ro08(bios, data + 0x04);
- info->script[0] = nv_ro16(bios, data + 0x05);
- info->script[1] = nv_ro16(bios, data + 0x07);
- info->lnkcmp = nv_ro16(bios, data + 0x09);
- info->script[2] = nv_ro16(bios, data + 0x0b);
- info->script[3] = nv_ro16(bios, data + 0x0d);
- info->script[4] = nv_ro16(bios, data + 0x0f);
- break;
- default:
- data = 0x0000;
- break;
- }
- }
- return data;
-}
-
-u16
-nvbios_dpout_match(struct nouveau_bios *bios, u16 type, u16 mask,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpout *info)
-{
- u16 data, idx = 0;
- while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
- if (data && info->type == type) {
- if ((info->mask & mask) == mask)
- break;
- }
- }
- return data;
-}
-
-static u16
-nvbios_dpcfg_entry(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- if (*ver >= 0x40) {
- outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
- *hdr = *hdr + (*len * * cnt);
- *len = nv_ro08(bios, outp + 0x06);
- *cnt = nv_ro08(bios, outp + 0x07);
- }
-
- if (idx < *cnt)
- return outp + *hdr + (idx * *len);
-
- return 0x0000;
-}
-
-u16
-nvbios_dpcfg_parse(struct nouveau_bios *bios, u16 outp, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *info)
-{
- u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- switch (*ver) {
- case 0x21:
- info->dc = nv_ro08(bios, data + 0x02);
- info->pe = nv_ro08(bios, data + 0x03);
- info->tx_pu = nv_ro08(bios, data + 0x04);
- break;
- case 0x30:
- case 0x40:
- case 0x41:
- info->pc = nv_ro08(bios, data + 0x00);
- info->dc = nv_ro08(bios, data + 0x01);
- info->pe = nv_ro08(bios, data + 0x02);
- info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f;
- break;
- default:
- data = 0x0000;
- break;
- }
- }
- return data;
-}
-
-u16
-nvbios_dpcfg_match(struct nouveau_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_dpcfg *info)
-{
- u8 idx = 0xff;
- u16 data;
-
- if (*ver >= 0x30) {
- /*XXX: there's a second set of these on at least 4.1, that
- * i've witnessed nvidia using instead of the first
- * on gm204. figure out what/why
- */
- const u8 vsoff[] = { 0, 4, 7, 9 };
- idx = (pc * 10) + vsoff[vs] + pe;
- } else {
- while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
- ver, hdr, cnt, len))) {
- if (nv_ro08(bios, data + 0x00) == vs &&
- nv_ro08(bios, data + 0x01) == pe)
- break;
- }
- }
-
- return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
deleted file mode 100644
index 49285d4f7ca5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/extdev.c
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/extdev.h>
-
-static u16
-extdev_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
-{
- u8 dcb_ver, dcb_hdr, dcb_cnt, dcb_len;
- u16 dcb, extdev = 0;
-
- dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len);
- if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40))
- return 0x0000;
-
- extdev = nv_ro16(bios, dcb + 18);
- if (!extdev)
- return 0x0000;
-
- *ver = nv_ro08(bios, extdev + 0);
- *hdr = nv_ro08(bios, extdev + 1);
- *cnt = nv_ro08(bios, extdev + 2);
- *len = nv_ro08(bios, extdev + 3);
-
- return extdev + *hdr;
-}
-
-static u16
-nvbios_extdev_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt);
- if (extdev && idx < cnt)
- return extdev + idx * *len;
- return 0x0000;
-}
-
-static void
-extdev_parse_entry(struct nouveau_bios *bios, u16 offset,
- struct nvbios_extdev_func *entry)
-{
- entry->type = nv_ro08(bios, offset + 0);
- entry->addr = nv_ro08(bios, offset + 1);
- entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1;
-}
-
-int
-nvbios_extdev_parse(struct nouveau_bios *bios, int idx,
- struct nvbios_extdev_func *func)
-{
- u8 ver, len;
- u16 entry;
-
- if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len)))
- return -EINVAL;
-
- extdev_parse_entry(bios, entry, func);
-
- return 0;
-}
-
-int
-nvbios_extdev_find(struct nouveau_bios *bios, enum nvbios_extdev_type type,
- struct nvbios_extdev_func *func)
-{
- u8 ver, len, i;
- u16 entry;
-
- i = 0;
- while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
- extdev_parse_entry(bios, entry, func);
- if (func->type == type)
- return 0;
- }
-
- return -EINVAL;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
deleted file mode 100644
index e419892240f5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/fan.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/fan.h>
-
-u16
-nvbios_fan_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry bit_P;
- u16 fan = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2 && bit_P.length >= 0x5a)
- fan = nv_ro16(bios, bit_P.offset + 0x58);
-
- if (fan) {
- *ver = nv_ro08(bios, fan + 0);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, fan + 1);
- *len = nv_ro08(bios, fan + 2);
- *cnt = nv_ro08(bios, fan + 3);
- return fan;
- default:
- break;
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_fan_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
- u8 *cnt, u8 *len)
-{
- u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len);
- if (data && idx < *cnt)
- return data + *hdr + (idx * (*len));
- return 0x0000;
-}
-
-u16
-nvbios_fan_parse(struct nouveau_bios *bios, struct nvbios_therm_fan *fan)
-{
- u8 ver, hdr, cnt, len;
-
- u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len);
- if (data) {
- u8 type = nv_ro08(bios, data + 0x00);
- switch (type) {
- case 0:
- fan->type = NVBIOS_THERM_FAN_TOGGLE;
- break;
- case 1:
- case 2:
- /* TODO: Understand the difference between the two! */
- fan->type = NVBIOS_THERM_FAN_PWM;
- break;
- default:
- fan->type = NVBIOS_THERM_FAN_UNK;
- }
-
- fan->min_duty = nv_ro08(bios, data + 0x02);
- fan->max_duty = nv_ro08(bios, data + 0x03);
-
- fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff;
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
deleted file mode 100644
index 172a4f999990..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/gpio.c
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/xpio.h>
-
-u16
-dcb_gpio_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u16 data = 0x0000;
- u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
- if (dcb) {
- if (*ver >= 0x30 && *hdr >= 0x0c)
- data = nv_ro16(bios, dcb + 0x0a);
- else
- if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
- data = nv_ro16(bios, dcb - 0x0f);
-
- if (data) {
- *ver = nv_ro08(bios, data + 0x00);
- if (*ver < 0x30) {
- *hdr = 3;
- *cnt = nv_ro08(bios, data + 0x02);
- *len = nv_ro08(bios, data + 0x01);
- } else
- if (*ver <= 0x41) {
- *hdr = nv_ro08(bios, data + 0x01);
- *cnt = nv_ro08(bios, data + 0x02);
- *len = nv_ro08(bios, data + 0x03);
- } else {
- data = 0x0000;
- }
- }
- }
- return data;
-}
-
-u16
-dcb_gpio_entry(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len)
-{
- u8 hdr, cnt, xver; /* use gpio version for xpio entry parsing */
- u16 gpio;
-
- if (!idx--)
- gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len);
- else
- gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len);
-
- if (gpio && ent < cnt)
- return gpio + hdr + (ent * *len);
- return 0x0000;
-}
-
-u16
-dcb_gpio_parse(struct nouveau_bios *bios, int idx, int ent, u8 *ver, u8 *len,
- struct dcb_gpio_func *gpio)
-{
- u16 data = dcb_gpio_entry(bios, idx, ent, ver, len);
- if (data) {
- if (*ver < 0x40) {
- u16 info = nv_ro16(bios, data);
- *gpio = (struct dcb_gpio_func) {
- .line = (info & 0x001f) >> 0,
- .func = (info & 0x07e0) >> 5,
- .log[0] = (info & 0x1800) >> 11,
- .log[1] = (info & 0x6000) >> 13,
- .param = !!(info & 0x8000),
- };
- } else
- if (*ver < 0x41) {
- u32 info = nv_ro32(bios, data);
- *gpio = (struct dcb_gpio_func) {
- .line = (info & 0x0000001f) >> 0,
- .func = (info & 0x0000ff00) >> 8,
- .log[0] = (info & 0x18000000) >> 27,
- .log[1] = (info & 0x60000000) >> 29,
- .param = !!(info & 0x80000000),
- };
- } else {
- u32 info = nv_ro32(bios, data + 0);
- u8 info1 = nv_ro32(bios, data + 4);
- *gpio = (struct dcb_gpio_func) {
- .line = (info & 0x0000003f) >> 0,
- .func = (info & 0x0000ff00) >> 8,
- .log[0] = (info1 & 0x30) >> 4,
- .log[1] = (info1 & 0xc0) >> 6,
- .param = !!(info & 0x80000000),
- };
- }
- }
-
- return data;
-}
-
-u16
-dcb_gpio_match(struct nouveau_bios *bios, int idx, u8 func, u8 line,
- u8 *ver, u8 *len, struct dcb_gpio_func *gpio)
-{
- u8 hdr, cnt, i = 0;
- u16 data;
-
- while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) {
- if ((line == 0xff || line == gpio->line) &&
- (func == 0xff || func == gpio->func))
- return data;
- }
-
- /* DCB 2.2, fixed TVDAC GPIO data */
- if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) {
- if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) {
- u8 conf = nv_ro08(bios, data - 5);
- u8 addr = nv_ro08(bios, data - 4);
- if (conf & 0x01) {
- *gpio = (struct dcb_gpio_func) {
- .func = DCB_GPIO_TVDAC0,
- .line = addr >> 4,
- .log[0] = !!(conf & 0x02),
- .log[1] = !(conf & 0x02),
- };
- *ver = 0x00;
- return data;
- }
- }
- }
-
- return 0x0000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
deleted file mode 100644
index 282320ba9264..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/i2c.c
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-
-#include "subdev/bios.h"
-#include "subdev/bios/dcb.h"
-#include "subdev/bios/i2c.h"
-
-u16
-dcb_i2c_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u16 i2c = 0x0000;
- u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
- if (dcb) {
- if (*ver >= 0x15)
- i2c = nv_ro16(bios, dcb + 2);
- if (*ver >= 0x30)
- i2c = nv_ro16(bios, dcb + 4);
- }
-
- if (i2c && *ver >= 0x42) {
- nv_warn(bios, "ccb %02x not supported\n", *ver);
- return 0x0000;
- }
-
- if (i2c && *ver >= 0x30) {
- *ver = nv_ro08(bios, i2c + 0);
- *hdr = nv_ro08(bios, i2c + 1);
- *cnt = nv_ro08(bios, i2c + 2);
- *len = nv_ro08(bios, i2c + 3);
- } else {
- *ver = *ver; /* use DCB version */
- *hdr = 0;
- *cnt = 16;
- *len = 4;
- }
-
- return i2c;
-}
-
-u16
-dcb_i2c_entry(struct nouveau_bios *bios, u8 idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u16 i2c = dcb_i2c_table(bios, ver, &hdr, &cnt, len);
- if (i2c && idx < cnt)
- return i2c + hdr + (idx * *len);
- return 0x0000;
-}
-
-int
-dcb_i2c_parse(struct nouveau_bios *bios, u8 idx, struct dcb_i2c_entry *info)
-{
- u8 ver, len;
- u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
- if (ent) {
- if (ver >= 0x41) {
- if (!(nv_ro32(bios, ent) & 0x80000000))
- info->type = DCB_I2C_UNUSED;
- else
- info->type = DCB_I2C_PMGR;
- } else
- if (ver >= 0x30) {
- info->type = nv_ro08(bios, ent + 0x03);
- } else {
- info->type = nv_ro08(bios, ent + 0x03) & 0x07;
- if (info->type == 0x07)
- info->type = DCB_I2C_UNUSED;
- }
-
- info->drive = DCB_I2C_UNUSED;
- info->sense = DCB_I2C_UNUSED;
- info->share = DCB_I2C_UNUSED;
- info->auxch = DCB_I2C_UNUSED;
-
- switch (info->type) {
- case DCB_I2C_NV04_BIT:
- info->drive = nv_ro08(bios, ent + 0);
- info->sense = nv_ro08(bios, ent + 1);
- return 0;
- case DCB_I2C_NV4E_BIT:
- info->drive = nv_ro08(bios, ent + 1);
- return 0;
- case DCB_I2C_NVIO_BIT:
- info->drive = nv_ro08(bios, ent + 0) & 0x0f;
- if (nv_ro08(bios, ent + 1) & 0x01)
- info->share = nv_ro08(bios, ent + 1) >> 1;
- return 0;
- case DCB_I2C_NVIO_AUX:
- info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
- if (nv_ro08(bios, ent + 1) & 0x01)
- info->share = info->auxch;
- return 0;
- case DCB_I2C_PMGR:
- info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0;
- if (info->drive == 0x1f)
- info->drive = DCB_I2C_UNUSED;
- info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5;
- if (info->auxch == 0x1f)
- info->auxch = DCB_I2C_UNUSED;
- info->share = info->auxch;
- return 0;
- case DCB_I2C_UNUSED:
- return 0;
- default:
- nv_warn(bios, "unknown i2c type %d\n", info->type);
- info->type = DCB_I2C_UNUSED;
- return 0;
- }
- }
-
- if (bios->bmp_offset && idx < 2) {
- /* BMP (from v4.0 has i2c info in the structure, it's in a
- * fixed location on earlier VBIOS
- */
- if (nv_ro08(bios, bios->bmp_offset + 5) < 4)
- ent = 0x0048;
- else
- ent = 0x0036 + bios->bmp_offset;
-
- if (idx == 0) {
- info->drive = nv_ro08(bios, ent + 4);
- if (!info->drive) info->drive = 0x3f;
- info->sense = nv_ro08(bios, ent + 5);
- if (!info->sense) info->sense = 0x3e;
- } else
- if (idx == 1) {
- info->drive = nv_ro08(bios, ent + 6);
- if (!info->drive) info->drive = 0x37;
- info->sense = nv_ro08(bios, ent + 7);
- if (!info->sense) info->sense = 0x36;
- }
-
- info->type = DCB_I2C_NV04_BIT;
- info->share = DCB_I2C_UNUSED;
- return 0;
- }
-
- return -ENOENT;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/image.c b/drivers/gpu/drm/nouveau/core/subdev/bios/image.c
deleted file mode 100644
index 373f9a564ac9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/image.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/image.h>
-#include <subdev/bios/pcir.h>
-#include <subdev/bios/npde.h>
-
-static bool
-nvbios_imagen(struct nouveau_bios *bios, struct nvbios_image *image)
-{
- struct nvbios_pcirT pcir;
- struct nvbios_npdeT npde;
- u8 ver;
- u16 hdr;
- u32 data;
-
- switch ((data = nv_ro16(bios, image->base + 0x00))) {
- case 0xaa55:
- case 0xbb77:
- case 0x4e56: /* NV */
- break;
- default:
- nv_debug(bios, "%08x: ROM signature (%04x) unknown\n",
- image->base, data);
- return false;
- }
-
- if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
- return false;
- image->size = pcir.image_size;
- image->type = pcir.image_type;
- image->last = pcir.last;
-
- if (image->type != 0x70) {
- if (!(data = nvbios_npdeTp(bios, image->base, &npde)))
- return true;
- image->size = npde.image_size;
- image->last = npde.last;
- } else {
- image->last = true;
- }
-
- return true;
-}
-
-bool
-nvbios_image(struct nouveau_bios *bios, int idx, struct nvbios_image *image)
-{
- memset(image, 0x00, sizeof(*image));
- do {
- image->base += image->size;
- if (image->last || !nvbios_imagen(bios, image))
- return false;
- } while(idx--);
- return true;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c b/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
deleted file mode 100644
index c6579ef32cd1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/init.c
+++ /dev/null
@@ -1,2227 +0,0 @@
-#include <core/engine.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/conn.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/dp.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/devinit.h>
-#include <subdev/i2c.h>
-#include <subdev/vga.h>
-#include <subdev/gpio.h>
-
-#define bioslog(lvl, fmt, args...) do { \
- nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset, \
- init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args); \
-} while(0)
-#define cont(fmt, args...) do { \
- if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE) \
- printk(fmt, ##args); \
-} while(0)
-#define trace(fmt, args...) bioslog(TRACE, fmt, ##args)
-#define warn(fmt, args...) bioslog(WARN, fmt, ##args)
-#define error(fmt, args...) bioslog(ERROR, fmt, ##args)
-
-/******************************************************************************
- * init parser control flow helpers
- *****************************************************************************/
-
-static inline bool
-init_exec(struct nvbios_init *init)
-{
- return (init->execute == 1) || ((init->execute & 5) == 5);
-}
-
-static inline void
-init_exec_set(struct nvbios_init *init, bool exec)
-{
- if (exec) init->execute &= 0xfd;
- else init->execute |= 0x02;
-}
-
-static inline void
-init_exec_inv(struct nvbios_init *init)
-{
- init->execute ^= 0x02;
-}
-
-static inline void
-init_exec_force(struct nvbios_init *init, bool exec)
-{
- if (exec) init->execute |= 0x04;
- else init->execute &= 0xfb;
-}
-
-/******************************************************************************
- * init parser wrappers for normal register/i2c/whatever accessors
- *****************************************************************************/
-
-static inline int
-init_or(struct nvbios_init *init)
-{
- if (init_exec(init)) {
- if (init->outp)
- return ffs(init->outp->or) - 1;
- error("script needs OR!!\n");
- }
- return 0;
-}
-
-static inline int
-init_link(struct nvbios_init *init)
-{
- if (init_exec(init)) {
- if (init->outp)
- return !(init->outp->sorconf.link & 1);
- error("script needs OR link\n");
- }
- return 0;
-}
-
-static inline int
-init_crtc(struct nvbios_init *init)
-{
- if (init_exec(init)) {
- if (init->crtc >= 0)
- return init->crtc;
- error("script needs crtc\n");
- }
- return 0;
-}
-
-static u8
-init_conn(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- struct nvbios_connE connE;
- u8 ver, hdr;
- u32 conn;
-
- if (init_exec(init)) {
- if (init->outp) {
- conn = init->outp->connector;
- conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
- if (conn)
- return connE.type;
- }
-
- error("script needs connector type\n");
- }
-
- return 0xff;
-}
-
-static inline u32
-init_nvreg(struct nvbios_init *init, u32 reg)
-{
- struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
-
- /* C51 (at least) sometimes has the lower bits set which the VBIOS
- * interprets to mean that access needs to go through certain IO
- * ports instead. The NVIDIA binary driver has been seen to access
- * these through the NV register address, so lets assume we can
- * do the same
- */
- reg &= ~0x00000003;
-
- /* GF8+ display scripts need register addresses mangled a bit to
- * select a specific CRTC/OR
- */
- if (nv_device(init->bios)->card_type >= NV_50) {
- if (reg & 0x80000000) {
- reg += init_crtc(init) * 0x800;
- reg &= ~0x80000000;
- }
-
- if (reg & 0x40000000) {
- reg += init_or(init) * 0x800;
- reg &= ~0x40000000;
- if (reg & 0x20000000) {
- reg += init_link(init) * 0x80;
- reg &= ~0x20000000;
- }
- }
- }
-
- if (reg & ~0x00fffffc)
- warn("unknown bits in register 0x%08x\n", reg);
-
- if (devinit->mmio)
- reg = devinit->mmio(devinit, reg);
- return reg;
-}
-
-static u32
-init_rd32(struct nvbios_init *init, u32 reg)
-{
- reg = init_nvreg(init, reg);
- if (reg != ~0 && init_exec(init))
- return nv_rd32(init->subdev, reg);
- return 0x00000000;
-}
-
-static void
-init_wr32(struct nvbios_init *init, u32 reg, u32 val)
-{
- reg = init_nvreg(init, reg);
- if (reg != ~0 && init_exec(init))
- nv_wr32(init->subdev, reg, val);
-}
-
-static u32
-init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
-{
- reg = init_nvreg(init, reg);
- if (reg != ~0 && init_exec(init)) {
- u32 tmp = nv_rd32(init->subdev, reg);
- nv_wr32(init->subdev, reg, (tmp & ~mask) | val);
- return tmp;
- }
- return 0x00000000;
-}
-
-static u8
-init_rdport(struct nvbios_init *init, u16 port)
-{
- if (init_exec(init))
- return nv_rdport(init->subdev, init->crtc, port);
- return 0x00;
-}
-
-static void
-init_wrport(struct nvbios_init *init, u16 port, u8 value)
-{
- if (init_exec(init))
- nv_wrport(init->subdev, init->crtc, port, value);
-}
-
-static u8
-init_rdvgai(struct nvbios_init *init, u16 port, u8 index)
-{
- struct nouveau_subdev *subdev = init->subdev;
- if (init_exec(init)) {
- int head = init->crtc < 0 ? 0 : init->crtc;
- return nv_rdvgai(subdev, head, port, index);
- }
- return 0x00;
-}
-
-static void
-init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
-{
- /* force head 0 for updates to cr44, it only exists on first head */
- if (nv_device(init->subdev)->card_type < NV_50) {
- if (port == 0x03d4 && index == 0x44)
- init->crtc = 0;
- }
-
- if (init_exec(init)) {
- int head = init->crtc < 0 ? 0 : init->crtc;
- nv_wrvgai(init->subdev, head, port, index, value);
- }
-
- /* select head 1 if cr44 write selected it */
- if (nv_device(init->subdev)->card_type < NV_50) {
- if (port == 0x03d4 && index == 0x44 && value == 3)
- init->crtc = 1;
- }
-}
-
-static struct nouveau_i2c_port *
-init_i2c(struct nvbios_init *init, int index)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(init->bios);
-
- if (index == 0xff) {
- index = NV_I2C_DEFAULT(0);
- if (init->outp && init->outp->i2c_upper_default)
- index = NV_I2C_DEFAULT(1);
- } else
- if (index < 0) {
- if (!init->outp) {
- if (init_exec(init))
- error("script needs output for i2c\n");
- return NULL;
- }
-
- if (index == -2 && init->outp->location) {
- index = NV_I2C_TYPE_EXTAUX(init->outp->extdev);
- return i2c->find_type(i2c, index);
- }
-
- index = init->outp->i2c_index;
- if (init->outp->type == DCB_OUTPUT_DP)
- index += NV_I2C_AUX(0);
- }
-
- return i2c->find(i2c, index);
-}
-
-static int
-init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg)
-{
- struct nouveau_i2c_port *port = init_i2c(init, index);
- if (port && init_exec(init))
- return nv_rdi2cr(port, addr, reg);
- return -ENODEV;
-}
-
-static int
-init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
-{
- struct nouveau_i2c_port *port = init_i2c(init, index);
- if (port && init_exec(init))
- return nv_wri2cr(port, addr, reg, val);
- return -ENODEV;
-}
-
-static u8
-init_rdauxr(struct nvbios_init *init, u32 addr)
-{
- struct nouveau_i2c_port *port = init_i2c(init, -2);
- u8 data;
-
- if (port && init_exec(init)) {
- int ret = nv_rdaux(port, addr, &data, 1);
- if (ret == 0)
- return data;
- trace("auxch read failed with %d\n", ret);
- }
-
- return 0x00;
-}
-
-static int
-init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
-{
- struct nouveau_i2c_port *port = init_i2c(init, -2);
- if (port && init_exec(init)) {
- int ret = nv_wraux(port, addr, &data, 1);
- if (ret)
- trace("auxch write failed with %d\n", ret);
- return ret;
- }
- return -ENODEV;
-}
-
-static void
-init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
-{
- struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
- if (devinit->pll_set && init_exec(init)) {
- int ret = devinit->pll_set(devinit, id, freq);
- if (ret)
- warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
- }
-}
-
-/******************************************************************************
- * parsing of bios structures that are required to execute init tables
- *****************************************************************************/
-
-static u16
-init_table(struct nouveau_bios *bios, u16 *len)
-{
- struct bit_entry bit_I;
-
- if (!bit_entry(bios, 'I', &bit_I)) {
- *len = bit_I.length;
- return bit_I.offset;
- }
-
- if (bmp_version(bios) >= 0x0510) {
- *len = 14;
- return bios->bmp_offset + 75;
- }
-
- return 0x0000;
-}
-
-static u16
-init_table_(struct nvbios_init *init, u16 offset, const char *name)
-{
- struct nouveau_bios *bios = init->bios;
- u16 len, data = init_table(bios, &len);
- if (data) {
- if (len >= offset + 2) {
- data = nv_ro16(bios, data + offset);
- if (data)
- return data;
-
- warn("%s pointer invalid\n", name);
- return 0x0000;
- }
-
- warn("init data too short for %s pointer", name);
- return 0x0000;
- }
-
- warn("init data not found\n");
- return 0x0000;
-}
-
-#define init_script_table(b) init_table_((b), 0x00, "script table")
-#define init_macro_index_table(b) init_table_((b), 0x02, "macro index table")
-#define init_macro_table(b) init_table_((b), 0x04, "macro table")
-#define init_condition_table(b) init_table_((b), 0x06, "condition table")
-#define init_io_condition_table(b) init_table_((b), 0x08, "io condition table")
-#define init_io_flag_condition_table(b) init_table_((b), 0x0a, "io flag conditon table")
-#define init_function_table(b) init_table_((b), 0x0c, "function table")
-#define init_xlat_table(b) init_table_((b), 0x10, "xlat table");
-
-static u16
-init_script(struct nouveau_bios *bios, int index)
-{
- struct nvbios_init init = { .bios = bios };
- u16 bmp_ver = bmp_version(bios), data;
-
- if (bmp_ver && bmp_ver < 0x0510) {
- if (index > 1 || bmp_ver < 0x0100)
- return 0x0000;
-
- data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18);
- return nv_ro16(bios, data + (index * 2));
- }
-
- data = init_script_table(&init);
- if (data)
- return nv_ro16(bios, data + (index * 2));
-
- return 0x0000;
-}
-
-static u16
-init_unknown_script(struct nouveau_bios *bios)
-{
- u16 len, data = init_table(bios, &len);
- if (data && len >= 16)
- return nv_ro16(bios, data + 14);
- return 0x0000;
-}
-
-static u8
-init_ram_restrict_group_count(struct nvbios_init *init)
-{
- return nvbios_ramcfg_count(init->bios);
-}
-
-static u8
-init_ram_restrict(struct nvbios_init *init)
-{
- /* This appears to be the behaviour of the VBIOS parser, and *is*
- * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
- * avoid fucking up the memory controller (somehow) by reading it
- * on every INIT_RAM_RESTRICT_ZM_GROUP opcode.
- *
- * Preserving the non-caching behaviour on earlier chipsets just
- * in case *not* re-reading the strap causes similar breakage.
- */
- if (!init->ramcfg || init->bios->version.major < 0x70)
- init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
- return (init->ramcfg & 0x7fffffff);
-}
-
-static u8
-init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
-{
- struct nouveau_bios *bios = init->bios;
- u16 table = init_xlat_table(init);
- if (table) {
- u16 data = nv_ro16(bios, table + (index * 2));
- if (data)
- return nv_ro08(bios, data + offset);
- warn("xlat table pointer %d invalid\n", index);
- }
- return 0x00;
-}
-
-/******************************************************************************
- * utility functions used by various init opcode handlers
- *****************************************************************************/
-
-static bool
-init_condition_met(struct nvbios_init *init, u8 cond)
-{
- struct nouveau_bios *bios = init->bios;
- u16 table = init_condition_table(init);
- if (table) {
- u32 reg = nv_ro32(bios, table + (cond * 12) + 0);
- u32 msk = nv_ro32(bios, table + (cond * 12) + 4);
- u32 val = nv_ro32(bios, table + (cond * 12) + 8);
- trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n",
- cond, reg, msk, val);
- return (init_rd32(init, reg) & msk) == val;
- }
- return false;
-}
-
-static bool
-init_io_condition_met(struct nvbios_init *init, u8 cond)
-{
- struct nouveau_bios *bios = init->bios;
- u16 table = init_io_condition_table(init);
- if (table) {
- u16 port = nv_ro16(bios, table + (cond * 5) + 0);
- u8 index = nv_ro08(bios, table + (cond * 5) + 2);
- u8 mask = nv_ro08(bios, table + (cond * 5) + 3);
- u8 value = nv_ro08(bios, table + (cond * 5) + 4);
- trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n",
- cond, port, index, mask, value);
- return (init_rdvgai(init, port, index) & mask) == value;
- }
- return false;
-}
-
-static bool
-init_io_flag_condition_met(struct nvbios_init *init, u8 cond)
-{
- struct nouveau_bios *bios = init->bios;
- u16 table = init_io_flag_condition_table(init);
- if (table) {
- u16 port = nv_ro16(bios, table + (cond * 9) + 0);
- u8 index = nv_ro08(bios, table + (cond * 9) + 2);
- u8 mask = nv_ro08(bios, table + (cond * 9) + 3);
- u8 shift = nv_ro08(bios, table + (cond * 9) + 4);
- u16 data = nv_ro16(bios, table + (cond * 9) + 5);
- u8 dmask = nv_ro08(bios, table + (cond * 9) + 7);
- u8 value = nv_ro08(bios, table + (cond * 9) + 8);
- u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift;
- return (nv_ro08(bios, data + ioval) & dmask) == value;
- }
- return false;
-}
-
-static inline u32
-init_shift(u32 data, u8 shift)
-{
- if (shift < 0x80)
- return data >> shift;
- return data << (0x100 - shift);
-}
-
-static u32
-init_tmds_reg(struct nvbios_init *init, u8 tmds)
-{
- /* For mlv < 0x80, it is an index into a table of TMDS base addresses.
- * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
- * CR58 for CR57 = 0 to index a table of offsets to the basic
- * 0x6808b0 address.
- * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
- * CR58 for CR57 = 0 to index a table of offsets to the basic
- * 0x6808b0 address, and then flip the offset by 8.
- */
-
- const int pramdac_offset[13] = {
- 0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
- const u32 pramdac_table[4] = {
- 0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
-
- if (tmds >= 0x80) {
- if (init->outp) {
- u32 dacoffset = pramdac_offset[init->outp->or];
- if (tmds == 0x81)
- dacoffset ^= 8;
- return 0x6808b0 + dacoffset;
- }
-
- if (init_exec(init))
- error("tmds opcodes need dcb\n");
- } else {
- if (tmds < ARRAY_SIZE(pramdac_table))
- return pramdac_table[tmds];
-
- error("tmds selector 0x%02x unknown\n", tmds);
- }
-
- return 0;
-}
-
-/******************************************************************************
- * init opcode handlers
- *****************************************************************************/
-
-/**
- * init_reserved - stub for various unknown/unused single-byte opcodes
- *
- */
-static void
-init_reserved(struct nvbios_init *init)
-{
- u8 opcode = nv_ro08(init->bios, init->offset);
- u8 length, i;
-
- switch (opcode) {
- case 0xaa:
- length = 4;
- break;
- default:
- length = 1;
- break;
- }
-
- trace("RESERVED 0x%02x\t", opcode);
- for (i = 1; i < length; i++)
- cont(" 0x%02x", nv_ro08(init->bios, init->offset + i));
- cont("\n");
- init->offset += length;
-}
-
-/**
- * INIT_DONE - opcode 0x71
- *
- */
-static void
-init_done(struct nvbios_init *init)
-{
- trace("DONE\n");
- init->offset = 0x0000;
-}
-
-/**
- * INIT_IO_RESTRICT_PROG - opcode 0x32
- *
- */
-static void
-init_io_restrict_prog(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 port = nv_ro16(bios, init->offset + 1);
- u8 index = nv_ro08(bios, init->offset + 3);
- u8 mask = nv_ro08(bios, init->offset + 4);
- u8 shift = nv_ro08(bios, init->offset + 5);
- u8 count = nv_ro08(bios, init->offset + 6);
- u32 reg = nv_ro32(bios, init->offset + 7);
- u8 conf, i;
-
- trace("IO_RESTRICT_PROG\tR[0x%06x] = "
- "((0x%04x[0x%02x] & 0x%02x) >> %d) [{\n",
- reg, port, index, mask, shift);
- init->offset += 11;
-
- conf = (init_rdvgai(init, port, index) & mask) >> shift;
- for (i = 0; i < count; i++) {
- u32 data = nv_ro32(bios, init->offset);
-
- if (i == conf) {
- trace("\t0x%08x *\n", data);
- init_wr32(init, reg, data);
- } else {
- trace("\t0x%08x\n", data);
- }
-
- init->offset += 4;
- }
- trace("}]\n");
-}
-
-/**
- * INIT_REPEAT - opcode 0x33
- *
- */
-static void
-init_repeat(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 count = nv_ro08(bios, init->offset + 1);
- u16 repeat = init->repeat;
-
- trace("REPEAT\t0x%02x\n", count);
- init->offset += 2;
-
- init->repeat = init->offset;
- init->repend = init->offset;
- while (count--) {
- init->offset = init->repeat;
- nvbios_exec(init);
- if (count)
- trace("REPEAT\t0x%02x\n", count);
- }
- init->offset = init->repend;
- init->repeat = repeat;
-}
-
-/**
- * INIT_IO_RESTRICT_PLL - opcode 0x34
- *
- */
-static void
-init_io_restrict_pll(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 port = nv_ro16(bios, init->offset + 1);
- u8 index = nv_ro08(bios, init->offset + 3);
- u8 mask = nv_ro08(bios, init->offset + 4);
- u8 shift = nv_ro08(bios, init->offset + 5);
- s8 iofc = nv_ro08(bios, init->offset + 6);
- u8 count = nv_ro08(bios, init->offset + 7);
- u32 reg = nv_ro32(bios, init->offset + 8);
- u8 conf, i;
-
- trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= "
- "((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) IOFCOND 0x%02x [{\n",
- reg, port, index, mask, shift, iofc);
- init->offset += 12;
-
- conf = (init_rdvgai(init, port, index) & mask) >> shift;
- for (i = 0; i < count; i++) {
- u32 freq = nv_ro16(bios, init->offset) * 10;
-
- if (i == conf) {
- trace("\t%dkHz *\n", freq);
- if (iofc > 0 && init_io_flag_condition_met(init, iofc))
- freq *= 2;
- init_prog_pll(init, reg, freq);
- } else {
- trace("\t%dkHz\n", freq);
- }
-
- init->offset += 2;
- }
- trace("}]\n");
-}
-
-/**
- * INIT_END_REPEAT - opcode 0x36
- *
- */
-static void
-init_end_repeat(struct nvbios_init *init)
-{
- trace("END_REPEAT\n");
- init->offset += 1;
-
- if (init->repeat) {
- init->repend = init->offset;
- init->offset = 0;
- }
-}
-
-/**
- * INIT_COPY - opcode 0x37
- *
- */
-static void
-init_copy(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u8 shift = nv_ro08(bios, init->offset + 5);
- u8 smask = nv_ro08(bios, init->offset + 6);
- u16 port = nv_ro16(bios, init->offset + 7);
- u8 index = nv_ro08(bios, init->offset + 9);
- u8 mask = nv_ro08(bios, init->offset + 10);
- u8 data;
-
- trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= "
- "((R[0x%06x] %s 0x%02x) & 0x%02x)\n",
- port, index, mask, reg, (shift & 0x80) ? "<<" : ">>",
- (shift & 0x80) ? (0x100 - shift) : shift, smask);
- init->offset += 11;
-
- data = init_rdvgai(init, port, index) & mask;
- data |= init_shift(init_rd32(init, reg), shift) & smask;
- init_wrvgai(init, port, index, data);
-}
-
-/**
- * INIT_NOT - opcode 0x38
- *
- */
-static void
-init_not(struct nvbios_init *init)
-{
- trace("NOT\n");
- init->offset += 1;
- init_exec_inv(init);
-}
-
-/**
- * INIT_IO_FLAG_CONDITION - opcode 0x39
- *
- */
-static void
-init_io_flag_condition(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 cond = nv_ro08(bios, init->offset + 1);
-
- trace("IO_FLAG_CONDITION\t0x%02x\n", cond);
- init->offset += 2;
-
- if (!init_io_flag_condition_met(init, cond))
- init_exec_set(init, false);
-}
-
-/**
- * INIT_DP_CONDITION - opcode 0x3a
- *
- */
-static void
-init_dp_condition(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- struct nvbios_dpout info;
- u8 cond = nv_ro08(bios, init->offset + 1);
- u8 unkn = nv_ro08(bios, init->offset + 2);
- u8 ver, hdr, cnt, len;
- u16 data;
-
- trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn);
- init->offset += 3;
-
- switch (cond) {
- case 0:
- if (init_conn(init) != DCB_CONNECTOR_eDP)
- init_exec_set(init, false);
- break;
- case 1:
- case 2:
- if ( init->outp &&
- (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
- (init->outp->or << 0) |
- (init->outp->sorconf.link << 6),
- &ver, &hdr, &cnt, &len, &info)))
- {
- if (!(info.flags & cond))
- init_exec_set(init, false);
- break;
- }
-
- if (init_exec(init))
- warn("script needs dp output table data\n");
- break;
- case 5:
- if (!(init_rdauxr(init, 0x0d) & 1))
- init_exec_set(init, false);
- break;
- default:
- warn("unknown dp condition 0x%02x\n", cond);
- break;
- }
-}
-
-/**
- * INIT_IO_MASK_OR - opcode 0x3b
- *
- */
-static void
-init_io_mask_or(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 or = init_or(init);
- u8 data;
-
- trace("IO_MASK_OR\t0x03d4[0x%02x] &= ~(1 << 0x%02x)\n", index, or);
- init->offset += 2;
-
- data = init_rdvgai(init, 0x03d4, index);
- init_wrvgai(init, 0x03d4, index, data &= ~(1 << or));
-}
-
-/**
- * INIT_IO_OR - opcode 0x3c
- *
- */
-static void
-init_io_or(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 or = init_or(init);
- u8 data;
-
- trace("IO_OR\t0x03d4[0x%02x] |= (1 << 0x%02x)\n", index, or);
- init->offset += 2;
-
- data = init_rdvgai(init, 0x03d4, index);
- init_wrvgai(init, 0x03d4, index, data | (1 << or));
-}
-
-/**
- * INIT_ANDN_REG - opcode 0x47
- *
- */
-static void
-init_andn_reg(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u32 mask = nv_ro32(bios, init->offset + 5);
-
- trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
- init->offset += 9;
-
- init_mask(init, reg, mask, 0);
-}
-
-/**
- * INIT_OR_REG - opcode 0x48
- *
- */
-static void
-init_or_reg(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u32 mask = nv_ro32(bios, init->offset + 5);
-
- trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
- init->offset += 9;
-
- init_mask(init, reg, 0, mask);
-}
-
-/**
- * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
- *
- */
-static void
-init_idx_addr_latched(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 creg = nv_ro32(bios, init->offset + 1);
- u32 dreg = nv_ro32(bios, init->offset + 5);
- u32 mask = nv_ro32(bios, init->offset + 9);
- u32 data = nv_ro32(bios, init->offset + 13);
- u8 count = nv_ro08(bios, init->offset + 17);
-
- trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg);
- trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data);
- init->offset += 18;
-
- while (count--) {
- u8 iaddr = nv_ro08(bios, init->offset + 0);
- u8 idata = nv_ro08(bios, init->offset + 1);
-
- trace("\t[0x%02x] = 0x%02x\n", iaddr, idata);
- init->offset += 2;
-
- init_wr32(init, dreg, idata);
- init_mask(init, creg, ~mask, data | iaddr);
- }
-}
-
-/**
- * INIT_IO_RESTRICT_PLL2 - opcode 0x4a
- *
- */
-static void
-init_io_restrict_pll2(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 port = nv_ro16(bios, init->offset + 1);
- u8 index = nv_ro08(bios, init->offset + 3);
- u8 mask = nv_ro08(bios, init->offset + 4);
- u8 shift = nv_ro08(bios, init->offset + 5);
- u8 count = nv_ro08(bios, init->offset + 6);
- u32 reg = nv_ro32(bios, init->offset + 7);
- u8 conf, i;
-
- trace("IO_RESTRICT_PLL2\t"
- "R[0x%06x] =PLL= ((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) [{\n",
- reg, port, index, mask, shift);
- init->offset += 11;
-
- conf = (init_rdvgai(init, port, index) & mask) >> shift;
- for (i = 0; i < count; i++) {
- u32 freq = nv_ro32(bios, init->offset);
- if (i == conf) {
- trace("\t%dkHz *\n", freq);
- init_prog_pll(init, reg, freq);
- } else {
- trace("\t%dkHz\n", freq);
- }
- init->offset += 4;
- }
- trace("}]\n");
-}
-
-/**
- * INIT_PLL2 - opcode 0x4b
- *
- */
-static void
-init_pll2(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u32 freq = nv_ro32(bios, init->offset + 5);
-
- trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
- init->offset += 9;
-
- init_prog_pll(init, reg, freq);
-}
-
-/**
- * INIT_I2C_BYTE - opcode 0x4c
- *
- */
-static void
-init_i2c_byte(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
- u8 count = nv_ro08(bios, init->offset + 3);
-
- trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
- init->offset += 4;
-
- while (count--) {
- u8 reg = nv_ro08(bios, init->offset + 0);
- u8 mask = nv_ro08(bios, init->offset + 1);
- u8 data = nv_ro08(bios, init->offset + 2);
- int val;
-
- trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data);
- init->offset += 3;
-
- val = init_rdi2cr(init, index, addr, reg);
- if (val < 0)
- continue;
- init_wri2cr(init, index, addr, reg, (val & mask) | data);
- }
-}
-
-/**
- * INIT_ZM_I2C_BYTE - opcode 0x4d
- *
- */
-static void
-init_zm_i2c_byte(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
- u8 count = nv_ro08(bios, init->offset + 3);
-
- trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
- init->offset += 4;
-
- while (count--) {
- u8 reg = nv_ro08(bios, init->offset + 0);
- u8 data = nv_ro08(bios, init->offset + 1);
-
- trace("\t[0x%02x] = 0x%02x\n", reg, data);
- init->offset += 2;
-
- init_wri2cr(init, index, addr, reg, data);
- }
-
-}
-
-/**
- * INIT_ZM_I2C - opcode 0x4e
- *
- */
-static void
-init_zm_i2c(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
- u8 count = nv_ro08(bios, init->offset + 3);
- u8 data[256], i;
-
- trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr);
- init->offset += 4;
-
- for (i = 0; i < count; i++) {
- data[i] = nv_ro08(bios, init->offset);
- trace("\t0x%02x\n", data[i]);
- init->offset++;
- }
-
- if (init_exec(init)) {
- struct nouveau_i2c_port *port = init_i2c(init, index);
- struct i2c_msg msg = {
- .addr = addr, .flags = 0, .len = count, .buf = data,
- };
- int ret;
-
- if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1)
- warn("i2c wr failed, %d\n", ret);
- }
-}
-
-/**
- * INIT_TMDS - opcode 0x4f
- *
- */
-static void
-init_tmds(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 tmds = nv_ro08(bios, init->offset + 1);
- u8 addr = nv_ro08(bios, init->offset + 2);
- u8 mask = nv_ro08(bios, init->offset + 3);
- u8 data = nv_ro08(bios, init->offset + 4);
- u32 reg = init_tmds_reg(init, tmds);
-
- trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n",
- tmds, addr, mask, data);
- init->offset += 5;
-
- if (reg == 0)
- return;
-
- init_wr32(init, reg + 0, addr | 0x00010000);
- init_wr32(init, reg + 4, data | (init_rd32(init, reg + 4) & mask));
- init_wr32(init, reg + 0, addr);
-}
-
-/**
- * INIT_ZM_TMDS_GROUP - opcode 0x50
- *
- */
-static void
-init_zm_tmds_group(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 tmds = nv_ro08(bios, init->offset + 1);
- u8 count = nv_ro08(bios, init->offset + 2);
- u32 reg = init_tmds_reg(init, tmds);
-
- trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds);
- init->offset += 3;
-
- while (count--) {
- u8 addr = nv_ro08(bios, init->offset + 0);
- u8 data = nv_ro08(bios, init->offset + 1);
-
- trace("\t[0x%02x] = 0x%02x\n", addr, data);
- init->offset += 2;
-
- init_wr32(init, reg + 4, data);
- init_wr32(init, reg + 0, addr);
- }
-}
-
-/**
- * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51
- *
- */
-static void
-init_cr_idx_adr_latch(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 addr0 = nv_ro08(bios, init->offset + 1);
- u8 addr1 = nv_ro08(bios, init->offset + 2);
- u8 base = nv_ro08(bios, init->offset + 3);
- u8 count = nv_ro08(bios, init->offset + 4);
- u8 save0;
-
- trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1);
- init->offset += 5;
-
- save0 = init_rdvgai(init, 0x03d4, addr0);
- while (count--) {
- u8 data = nv_ro08(bios, init->offset);
-
- trace("\t\t[0x%02x] = 0x%02x\n", base, data);
- init->offset += 1;
-
- init_wrvgai(init, 0x03d4, addr0, base++);
- init_wrvgai(init, 0x03d4, addr1, data);
- }
- init_wrvgai(init, 0x03d4, addr0, save0);
-}
-
-/**
- * INIT_CR - opcode 0x52
- *
- */
-static void
-init_cr(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 addr = nv_ro08(bios, init->offset + 1);
- u8 mask = nv_ro08(bios, init->offset + 2);
- u8 data = nv_ro08(bios, init->offset + 3);
- u8 val;
-
- trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
- init->offset += 4;
-
- val = init_rdvgai(init, 0x03d4, addr) & mask;
- init_wrvgai(init, 0x03d4, addr, val | data);
-}
-
-/**
- * INIT_ZM_CR - opcode 0x53
- *
- */
-static void
-init_zm_cr(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 addr = nv_ro08(bios, init->offset + 1);
- u8 data = nv_ro08(bios, init->offset + 2);
-
- trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr, data);
- init->offset += 3;
-
- init_wrvgai(init, 0x03d4, addr, data);
-}
-
-/**
- * INIT_ZM_CR_GROUP - opcode 0x54
- *
- */
-static void
-init_zm_cr_group(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 count = nv_ro08(bios, init->offset + 1);
-
- trace("ZM_CR_GROUP\n");
- init->offset += 2;
-
- while (count--) {
- u8 addr = nv_ro08(bios, init->offset + 0);
- u8 data = nv_ro08(bios, init->offset + 1);
-
- trace("\t\tC[0x%02x] = 0x%02x\n", addr, data);
- init->offset += 2;
-
- init_wrvgai(init, 0x03d4, addr, data);
- }
-}
-
-/**
- * INIT_CONDITION_TIME - opcode 0x56
- *
- */
-static void
-init_condition_time(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 cond = nv_ro08(bios, init->offset + 1);
- u8 retry = nv_ro08(bios, init->offset + 2);
- u8 wait = min((u16)retry * 50, 100);
-
- trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry);
- init->offset += 3;
-
- if (!init_exec(init))
- return;
-
- while (wait--) {
- if (init_condition_met(init, cond))
- return;
- mdelay(20);
- }
-
- init_exec_set(init, false);
-}
-
-/**
- * INIT_LTIME - opcode 0x57
- *
- */
-static void
-init_ltime(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 msec = nv_ro16(bios, init->offset + 1);
-
- trace("LTIME\t0x%04x\n", msec);
- init->offset += 3;
-
- if (init_exec(init))
- mdelay(msec);
-}
-
-/**
- * INIT_ZM_REG_SEQUENCE - opcode 0x58
- *
- */
-static void
-init_zm_reg_sequence(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 base = nv_ro32(bios, init->offset + 1);
- u8 count = nv_ro08(bios, init->offset + 5);
-
- trace("ZM_REG_SEQUENCE\t0x%02x\n", count);
- init->offset += 6;
-
- while (count--) {
- u32 data = nv_ro32(bios, init->offset);
-
- trace("\t\tR[0x%06x] = 0x%08x\n", base, data);
- init->offset += 4;
-
- init_wr32(init, base, data);
- base += 4;
- }
-}
-
-/**
- * INIT_SUB_DIRECT - opcode 0x5b
- *
- */
-static void
-init_sub_direct(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 addr = nv_ro16(bios, init->offset + 1);
- u16 save;
-
- trace("SUB_DIRECT\t0x%04x\n", addr);
-
- if (init_exec(init)) {
- save = init->offset;
- init->offset = addr;
- if (nvbios_exec(init)) {
- error("error parsing sub-table\n");
- return;
- }
- init->offset = save;
- }
-
- init->offset += 3;
-}
-
-/**
- * INIT_JUMP - opcode 0x5c
- *
- */
-static void
-init_jump(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 offset = nv_ro16(bios, init->offset + 1);
-
- trace("JUMP\t0x%04x\n", offset);
-
- if (init_exec(init))
- init->offset = offset;
- else
- init->offset += 3;
-}
-
-/**
- * INIT_I2C_IF - opcode 0x5e
- *
- */
-static void
-init_i2c_if(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 addr = nv_ro08(bios, init->offset + 2);
- u8 reg = nv_ro08(bios, init->offset + 3);
- u8 mask = nv_ro08(bios, init->offset + 4);
- u8 data = nv_ro08(bios, init->offset + 5);
- u8 value;
-
- trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n",
- index, addr, reg, mask, data);
- init->offset += 6;
- init_exec_force(init, true);
-
- value = init_rdi2cr(init, index, addr, reg);
- if ((value & mask) != data)
- init_exec_set(init, false);
-
- init_exec_force(init, false);
-}
-
-/**
- * INIT_COPY_NV_REG - opcode 0x5f
- *
- */
-static void
-init_copy_nv_reg(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 sreg = nv_ro32(bios, init->offset + 1);
- u8 shift = nv_ro08(bios, init->offset + 5);
- u32 smask = nv_ro32(bios, init->offset + 6);
- u32 sxor = nv_ro32(bios, init->offset + 10);
- u32 dreg = nv_ro32(bios, init->offset + 14);
- u32 dmask = nv_ro32(bios, init->offset + 18);
- u32 data;
-
- trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= "
- "((R[0x%06x] %s 0x%02x) & 0x%08x ^ 0x%08x)\n",
- dreg, dmask, sreg, (shift & 0x80) ? "<<" : ">>",
- (shift & 0x80) ? (0x100 - shift) : shift, smask, sxor);
- init->offset += 22;
-
- data = init_shift(init_rd32(init, sreg), shift);
- init_mask(init, dreg, ~dmask, (data & smask) ^ sxor);
-}
-
-/**
- * INIT_ZM_INDEX_IO - opcode 0x62
- *
- */
-static void
-init_zm_index_io(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 port = nv_ro16(bios, init->offset + 1);
- u8 index = nv_ro08(bios, init->offset + 3);
- u8 data = nv_ro08(bios, init->offset + 4);
-
- trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data);
- init->offset += 5;
-
- init_wrvgai(init, port, index, data);
-}
-
-/**
- * INIT_COMPUTE_MEM - opcode 0x63
- *
- */
-static void
-init_compute_mem(struct nvbios_init *init)
-{
- struct nouveau_devinit *devinit = nouveau_devinit(init->bios);
-
- trace("COMPUTE_MEM\n");
- init->offset += 1;
-
- init_exec_force(init, true);
- if (init_exec(init) && devinit->meminit)
- devinit->meminit(devinit);
- init_exec_force(init, false);
-}
-
-/**
- * INIT_RESET - opcode 0x65
- *
- */
-static void
-init_reset(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u32 data1 = nv_ro32(bios, init->offset + 5);
- u32 data2 = nv_ro32(bios, init->offset + 9);
- u32 savepci19;
-
- trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2);
- init->offset += 13;
- init_exec_force(init, true);
-
- savepci19 = init_mask(init, 0x00184c, 0x00000f00, 0x00000000);
- init_wr32(init, reg, data1);
- udelay(10);
- init_wr32(init, reg, data2);
- init_wr32(init, 0x00184c, savepci19);
- init_mask(init, 0x001850, 0x00000001, 0x00000000);
-
- init_exec_force(init, false);
-}
-
-/**
- * INIT_CONFIGURE_MEM - opcode 0x66
- *
- */
-static u16
-init_configure_mem_clk(struct nvbios_init *init)
-{
- u16 mdata = bmp_mem_init_table(init->bios);
- if (mdata)
- mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66;
- return mdata;
-}
-
-static void
-init_configure_mem(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 mdata, sdata;
- u32 addr, data;
-
- trace("CONFIGURE_MEM\n");
- init->offset += 1;
-
- if (bios->version.major > 2) {
- init_done(init);
- return;
- }
- init_exec_force(init, true);
-
- mdata = init_configure_mem_clk(init);
- sdata = bmp_sdr_seq_table(bios);
- if (nv_ro08(bios, mdata) & 0x01)
- sdata = bmp_ddr_seq_table(bios);
- mdata += 6; /* skip to data */
-
- data = init_rdvgai(init, 0x03c4, 0x01);
- init_wrvgai(init, 0x03c4, 0x01, data | 0x20);
-
- for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) {
- switch (addr) {
- case 0x10021c: /* CKE_NORMAL */
- case 0x1002d0: /* CMD_REFRESH */
- case 0x1002d4: /* CMD_PRECHARGE */
- data = 0x00000001;
- break;
- default:
- data = nv_ro32(bios, mdata);
- mdata += 4;
- if (data == 0xffffffff)
- continue;
- break;
- }
-
- init_wr32(init, addr, data);
- }
-
- init_exec_force(init, false);
-}
-
-/**
- * INIT_CONFIGURE_CLK - opcode 0x67
- *
- */
-static void
-init_configure_clk(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 mdata, clock;
-
- trace("CONFIGURE_CLK\n");
- init->offset += 1;
-
- if (bios->version.major > 2) {
- init_done(init);
- return;
- }
- init_exec_force(init, true);
-
- mdata = init_configure_mem_clk(init);
-
- /* NVPLL */
- clock = nv_ro16(bios, mdata + 4) * 10;
- init_prog_pll(init, 0x680500, clock);
-
- /* MPLL */
- clock = nv_ro16(bios, mdata + 2) * 10;
- if (nv_ro08(bios, mdata) & 0x01)
- clock *= 2;
- init_prog_pll(init, 0x680504, clock);
-
- init_exec_force(init, false);
-}
-
-/**
- * INIT_CONFIGURE_PREINIT - opcode 0x68
- *
- */
-static void
-init_configure_preinit(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 strap;
-
- trace("CONFIGURE_PREINIT\n");
- init->offset += 1;
-
- if (bios->version.major > 2) {
- init_done(init);
- return;
- }
- init_exec_force(init, true);
-
- strap = init_rd32(init, 0x101000);
- strap = ((strap << 2) & 0xf0) | ((strap & 0x40) >> 6);
- init_wrvgai(init, 0x03d4, 0x3c, strap);
-
- init_exec_force(init, false);
-}
-
-/**
- * INIT_IO - opcode 0x69
- *
- */
-static void
-init_io(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 port = nv_ro16(bios, init->offset + 1);
- u8 mask = nv_ro16(bios, init->offset + 3);
- u8 data = nv_ro16(bios, init->offset + 4);
- u8 value;
-
- trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data);
- init->offset += 5;
-
- /* ummm.. yes.. should really figure out wtf this is and why it's
- * needed some day.. it's almost certainly wrong, but, it also
- * somehow makes things work...
- */
- if (nv_device(init->bios)->card_type >= NV_50 &&
- port == 0x03c3 && data == 0x01) {
- init_mask(init, 0x614100, 0xf0800000, 0x00800000);
- init_mask(init, 0x00e18c, 0x00020000, 0x00020000);
- init_mask(init, 0x614900, 0xf0800000, 0x00800000);
- init_mask(init, 0x000200, 0x40000000, 0x00000000);
- mdelay(10);
- init_mask(init, 0x00e18c, 0x00020000, 0x00000000);
- init_mask(init, 0x000200, 0x40000000, 0x40000000);
- init_wr32(init, 0x614100, 0x00800018);
- init_wr32(init, 0x614900, 0x00800018);
- mdelay(10);
- init_wr32(init, 0x614100, 0x10000018);
- init_wr32(init, 0x614900, 0x10000018);
- }
-
- value = init_rdport(init, port) & mask;
- init_wrport(init, port, data | value);
-}
-
-/**
- * INIT_SUB - opcode 0x6b
- *
- */
-static void
-init_sub(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u16 addr, save;
-
- trace("SUB\t0x%02x\n", index);
-
- addr = init_script(bios, index);
- if (addr && init_exec(init)) {
- save = init->offset;
- init->offset = addr;
- if (nvbios_exec(init)) {
- error("error parsing sub-table\n");
- return;
- }
- init->offset = save;
- }
-
- init->offset += 2;
-}
-
-/**
- * INIT_RAM_CONDITION - opcode 0x6d
- *
- */
-static void
-init_ram_condition(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 mask = nv_ro08(bios, init->offset + 1);
- u8 value = nv_ro08(bios, init->offset + 2);
-
- trace("RAM_CONDITION\t"
- "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value);
- init->offset += 3;
-
- if ((init_rd32(init, 0x100000) & mask) != value)
- init_exec_set(init, false);
-}
-
-/**
- * INIT_NV_REG - opcode 0x6e
- *
- */
-static void
-init_nv_reg(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u32 mask = nv_ro32(bios, init->offset + 5);
- u32 data = nv_ro32(bios, init->offset + 9);
-
- trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data);
- init->offset += 13;
-
- init_mask(init, reg, ~mask, data);
-}
-
-/**
- * INIT_MACRO - opcode 0x6f
- *
- */
-static void
-init_macro(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 macro = nv_ro08(bios, init->offset + 1);
- u16 table;
-
- trace("MACRO\t0x%02x\n", macro);
-
- table = init_macro_table(init);
- if (table) {
- u32 addr = nv_ro32(bios, table + (macro * 8) + 0);
- u32 data = nv_ro32(bios, table + (macro * 8) + 4);
- trace("\t\tR[0x%06x] = 0x%08x\n", addr, data);
- init_wr32(init, addr, data);
- }
-
- init->offset += 2;
-}
-
-/**
- * INIT_RESUME - opcode 0x72
- *
- */
-static void
-init_resume(struct nvbios_init *init)
-{
- trace("RESUME\n");
- init->offset += 1;
- init_exec_set(init, true);
-}
-
-/**
- * INIT_TIME - opcode 0x74
- *
- */
-static void
-init_time(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 usec = nv_ro16(bios, init->offset + 1);
-
- trace("TIME\t0x%04x\n", usec);
- init->offset += 3;
-
- if (init_exec(init)) {
- if (usec < 1000)
- udelay(usec);
- else
- mdelay((usec + 900) / 1000);
- }
-}
-
-/**
- * INIT_CONDITION - opcode 0x75
- *
- */
-static void
-init_condition(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 cond = nv_ro08(bios, init->offset + 1);
-
- trace("CONDITION\t0x%02x\n", cond);
- init->offset += 2;
-
- if (!init_condition_met(init, cond))
- init_exec_set(init, false);
-}
-
-/**
- * INIT_IO_CONDITION - opcode 0x76
- *
- */
-static void
-init_io_condition(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 cond = nv_ro08(bios, init->offset + 1);
-
- trace("IO_CONDITION\t0x%02x\n", cond);
- init->offset += 2;
-
- if (!init_io_condition_met(init, cond))
- init_exec_set(init, false);
-}
-
-/**
- * INIT_INDEX_IO - opcode 0x78
- *
- */
-static void
-init_index_io(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u16 port = nv_ro16(bios, init->offset + 1);
- u8 index = nv_ro16(bios, init->offset + 3);
- u8 mask = nv_ro08(bios, init->offset + 4);
- u8 data = nv_ro08(bios, init->offset + 5);
- u8 value;
-
- trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n",
- port, index, mask, data);
- init->offset += 6;
-
- value = init_rdvgai(init, port, index) & mask;
- init_wrvgai(init, port, index, data | value);
-}
-
-/**
- * INIT_PLL - opcode 0x79
- *
- */
-static void
-init_pll(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 reg = nv_ro32(bios, init->offset + 1);
- u32 freq = nv_ro16(bios, init->offset + 5) * 10;
-
- trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
- init->offset += 7;
-
- init_prog_pll(init, reg, freq);
-}
-
-/**
- * INIT_ZM_REG - opcode 0x7a
- *
- */
-static void
-init_zm_reg(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 addr = nv_ro32(bios, init->offset + 1);
- u32 data = nv_ro32(bios, init->offset + 5);
-
- trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data);
- init->offset += 9;
-
- if (addr == 0x000200)
- data |= 0x00000001;
-
- init_wr32(init, addr, data);
-}
-
-/**
- * INIT_RAM_RESTRICT_PLL - opcde 0x87
- *
- */
-static void
-init_ram_restrict_pll(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 type = nv_ro08(bios, init->offset + 1);
- u8 count = init_ram_restrict_group_count(init);
- u8 strap = init_ram_restrict(init);
- u8 cconf;
-
- trace("RAM_RESTRICT_PLL\t0x%02x\n", type);
- init->offset += 2;
-
- for (cconf = 0; cconf < count; cconf++) {
- u32 freq = nv_ro32(bios, init->offset);
-
- if (cconf == strap) {
- trace("%dkHz *\n", freq);
- init_prog_pll(init, type, freq);
- } else {
- trace("%dkHz\n", freq);
- }
-
- init->offset += 4;
- }
-}
-
-/**
- * INIT_GPIO - opcode 0x8e
- *
- */
-static void
-init_gpio(struct nvbios_init *init)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(init->bios);
-
- trace("GPIO\n");
- init->offset += 1;
-
- if (init_exec(init) && gpio && gpio->reset)
- gpio->reset(gpio, DCB_GPIO_UNUSED);
-}
-
-/**
- * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f
- *
- */
-static void
-init_ram_restrict_zm_reg_group(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 addr = nv_ro32(bios, init->offset + 1);
- u8 incr = nv_ro08(bios, init->offset + 5);
- u8 num = nv_ro08(bios, init->offset + 6);
- u8 count = init_ram_restrict_group_count(init);
- u8 index = init_ram_restrict(init);
- u8 i, j;
-
- trace("RAM_RESTRICT_ZM_REG_GROUP\t"
- "R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num);
- init->offset += 7;
-
- for (i = 0; i < num; i++) {
- trace("\tR[0x%06x] = {\n", addr);
- for (j = 0; j < count; j++) {
- u32 data = nv_ro32(bios, init->offset);
-
- if (j == index) {
- trace("\t\t0x%08x *\n", data);
- init_wr32(init, addr, data);
- } else {
- trace("\t\t0x%08x\n", data);
- }
-
- init->offset += 4;
- }
- trace("\t}\n");
- addr += incr;
- }
-}
-
-/**
- * INIT_COPY_ZM_REG - opcode 0x90
- *
- */
-static void
-init_copy_zm_reg(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 sreg = nv_ro32(bios, init->offset + 1);
- u32 dreg = nv_ro32(bios, init->offset + 5);
-
- trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg);
- init->offset += 9;
-
- init_wr32(init, dreg, init_rd32(init, sreg));
-}
-
-/**
- * INIT_ZM_REG_GROUP - opcode 0x91
- *
- */
-static void
-init_zm_reg_group(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 addr = nv_ro32(bios, init->offset + 1);
- u8 count = nv_ro08(bios, init->offset + 5);
-
- trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr);
- init->offset += 6;
-
- while (count--) {
- u32 data = nv_ro32(bios, init->offset);
- trace("\t0x%08x\n", data);
- init_wr32(init, addr, data);
- init->offset += 4;
- }
-}
-
-/**
- * INIT_XLAT - opcode 0x96
- *
- */
-static void
-init_xlat(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 saddr = nv_ro32(bios, init->offset + 1);
- u8 sshift = nv_ro08(bios, init->offset + 5);
- u8 smask = nv_ro08(bios, init->offset + 6);
- u8 index = nv_ro08(bios, init->offset + 7);
- u32 daddr = nv_ro32(bios, init->offset + 8);
- u32 dmask = nv_ro32(bios, init->offset + 12);
- u8 shift = nv_ro08(bios, init->offset + 16);
- u32 data;
-
- trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= "
- "(X%02x((R[0x%06x] %s 0x%02x) & 0x%02x) << 0x%02x)\n",
- daddr, dmask, index, saddr, (sshift & 0x80) ? "<<" : ">>",
- (sshift & 0x80) ? (0x100 - sshift) : sshift, smask, shift);
- init->offset += 17;
-
- data = init_shift(init_rd32(init, saddr), sshift) & smask;
- data = init_xlat_(init, index, data) << shift;
- init_mask(init, daddr, ~dmask, data);
-}
-
-/**
- * INIT_ZM_MASK_ADD - opcode 0x97
- *
- */
-static void
-init_zm_mask_add(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 addr = nv_ro32(bios, init->offset + 1);
- u32 mask = nv_ro32(bios, init->offset + 5);
- u32 add = nv_ro32(bios, init->offset + 9);
- u32 data;
-
- trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add);
- init->offset += 13;
-
- data = init_rd32(init, addr);
- data = (data & mask) | ((data + add) & ~mask);
- init_wr32(init, addr, data);
-}
-
-/**
- * INIT_AUXCH - opcode 0x98
- *
- */
-static void
-init_auxch(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 addr = nv_ro32(bios, init->offset + 1);
- u8 count = nv_ro08(bios, init->offset + 5);
-
- trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
- init->offset += 6;
-
- while (count--) {
- u8 mask = nv_ro08(bios, init->offset + 0);
- u8 data = nv_ro08(bios, init->offset + 1);
- trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
- mask = init_rdauxr(init, addr) & mask;
- init_wrauxr(init, addr, mask | data);
- init->offset += 2;
- }
-}
-
-/**
- * INIT_AUXCH - opcode 0x99
- *
- */
-static void
-init_zm_auxch(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u32 addr = nv_ro32(bios, init->offset + 1);
- u8 count = nv_ro08(bios, init->offset + 5);
-
- trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
- init->offset += 6;
-
- while (count--) {
- u8 data = nv_ro08(bios, init->offset + 0);
- trace("\tAUX[0x%08x] = 0x%02x\n", addr, data);
- init_wrauxr(init, addr, data);
- init->offset += 1;
- }
-}
-
-/**
- * INIT_I2C_LONG_IF - opcode 0x9a
- *
- */
-static void
-init_i2c_long_if(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- u8 index = nv_ro08(bios, init->offset + 1);
- u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
- u8 reglo = nv_ro08(bios, init->offset + 3);
- u8 reghi = nv_ro08(bios, init->offset + 4);
- u8 mask = nv_ro08(bios, init->offset + 5);
- u8 data = nv_ro08(bios, init->offset + 6);
- struct nouveau_i2c_port *port;
-
- trace("I2C_LONG_IF\t"
- "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n",
- index, addr, reglo, reghi, mask, data);
- init->offset += 7;
-
- port = init_i2c(init, index);
- if (port) {
- u8 i[2] = { reghi, reglo };
- u8 o[1] = {};
- struct i2c_msg msg[] = {
- { .addr = addr, .flags = 0, .len = 2, .buf = i },
- { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = o }
- };
- int ret;
-
- ret = i2c_transfer(&port->adapter, msg, 2);
- if (ret == 2 && ((o[0] & mask) == data))
- return;
- }
-
- init_exec_set(init, false);
-}
-
-/**
- * INIT_GPIO_NE - opcode 0xa9
- *
- */
-static void
-init_gpio_ne(struct nvbios_init *init)
-{
- struct nouveau_bios *bios = init->bios;
- struct nouveau_gpio *gpio = nouveau_gpio(bios);
- struct dcb_gpio_func func;
- u8 count = nv_ro08(bios, init->offset + 1);
- u8 idx = 0, ver, len;
- u16 data, i;
-
- trace("GPIO_NE\t");
- init->offset += 2;
-
- for (i = init->offset; i < init->offset + count; i++)
- cont("0x%02x ", nv_ro08(bios, i));
- cont("\n");
-
- while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) {
- if (func.func != DCB_GPIO_UNUSED) {
- for (i = init->offset; i < init->offset + count; i++) {
- if (func.func == nv_ro08(bios, i))
- break;
- }
-
- trace("\tFUNC[0x%02x]", func.func);
- if (i == (init->offset + count)) {
- cont(" *");
- if (init_exec(init) && gpio && gpio->reset)
- gpio->reset(gpio, func.func);
- }
- cont("\n");
- }
- }
-
- init->offset += count;
-}
-
-static struct nvbios_init_opcode {
- void (*exec)(struct nvbios_init *);
-} init_opcode[] = {
- [0x32] = { init_io_restrict_prog },
- [0x33] = { init_repeat },
- [0x34] = { init_io_restrict_pll },
- [0x36] = { init_end_repeat },
- [0x37] = { init_copy },
- [0x38] = { init_not },
- [0x39] = { init_io_flag_condition },
- [0x3a] = { init_dp_condition },
- [0x3b] = { init_io_mask_or },
- [0x3c] = { init_io_or },
- [0x47] = { init_andn_reg },
- [0x48] = { init_or_reg },
- [0x49] = { init_idx_addr_latched },
- [0x4a] = { init_io_restrict_pll2 },
- [0x4b] = { init_pll2 },
- [0x4c] = { init_i2c_byte },
- [0x4d] = { init_zm_i2c_byte },
- [0x4e] = { init_zm_i2c },
- [0x4f] = { init_tmds },
- [0x50] = { init_zm_tmds_group },
- [0x51] = { init_cr_idx_adr_latch },
- [0x52] = { init_cr },
- [0x53] = { init_zm_cr },
- [0x54] = { init_zm_cr_group },
- [0x56] = { init_condition_time },
- [0x57] = { init_ltime },
- [0x58] = { init_zm_reg_sequence },
- [0x5b] = { init_sub_direct },
- [0x5c] = { init_jump },
- [0x5e] = { init_i2c_if },
- [0x5f] = { init_copy_nv_reg },
- [0x62] = { init_zm_index_io },
- [0x63] = { init_compute_mem },
- [0x65] = { init_reset },
- [0x66] = { init_configure_mem },
- [0x67] = { init_configure_clk },
- [0x68] = { init_configure_preinit },
- [0x69] = { init_io },
- [0x6b] = { init_sub },
- [0x6d] = { init_ram_condition },
- [0x6e] = { init_nv_reg },
- [0x6f] = { init_macro },
- [0x71] = { init_done },
- [0x72] = { init_resume },
- [0x74] = { init_time },
- [0x75] = { init_condition },
- [0x76] = { init_io_condition },
- [0x78] = { init_index_io },
- [0x79] = { init_pll },
- [0x7a] = { init_zm_reg },
- [0x87] = { init_ram_restrict_pll },
- [0x8c] = { init_reserved },
- [0x8d] = { init_reserved },
- [0x8e] = { init_gpio },
- [0x8f] = { init_ram_restrict_zm_reg_group },
- [0x90] = { init_copy_zm_reg },
- [0x91] = { init_zm_reg_group },
- [0x92] = { init_reserved },
- [0x96] = { init_xlat },
- [0x97] = { init_zm_mask_add },
- [0x98] = { init_auxch },
- [0x99] = { init_zm_auxch },
- [0x9a] = { init_i2c_long_if },
- [0xa9] = { init_gpio_ne },
- [0xaa] = { init_reserved },
-};
-
-#define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0]))
-
-int
-nvbios_exec(struct nvbios_init *init)
-{
- init->nested++;
- while (init->offset) {
- u8 opcode = nv_ro08(init->bios, init->offset);
- if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) {
- error("unknown opcode 0x%02x\n", opcode);
- return -EINVAL;
- }
-
- init_opcode[opcode].exec(init);
- }
- init->nested--;
- return 0;
-}
-
-int
-nvbios_init(struct nouveau_subdev *subdev, bool execute)
-{
- struct nouveau_bios *bios = nouveau_bios(subdev);
- int ret = 0;
- int i = -1;
- u16 data;
-
- if (execute)
- nv_info(bios, "running init tables\n");
- while (!ret && (data = (init_script(bios, ++i)))) {
- struct nvbios_init init = {
- .subdev = subdev,
- .bios = bios,
- .offset = data,
- .outp = NULL,
- .crtc = -1,
- .execute = execute ? 1 : 0,
- };
-
- ret = nvbios_exec(&init);
- }
-
- /* the vbios parser will run this right after the normal init
- * tables, whereas the binary driver appears to run it later.
- */
- if (!ret && (data = init_unknown_script(bios))) {
- struct nvbios_init init = {
- .subdev = subdev,
- .bios = bios,
- .offset = data,
- .outp = NULL,
- .crtc = -1,
- .execute = execute ? 1 : 0,
- };
-
- ret = nvbios_exec(&init);
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
deleted file mode 100644
index 2610b11a99b3..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/mxm.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/mxm.h>
-
-u16
-mxm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr)
-{
- struct bit_entry x;
-
- if (bit_entry(bios, 'x', &x)) {
- nv_debug(bios, "BIT 'x' table not present\n");
- return 0x0000;
- }
-
- *ver = x.version;
- *hdr = x.length;
- if (*ver != 1 || *hdr < 3) {
- nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr);
- return 0x0000;
- }
-
- return x.offset;
-}
-
-/* These map MXM v2.x digital connection values to the appropriate SOR/link,
- * hopefully they're correct for all boards within the same chipset...
- *
- * MXM v3.x VBIOS are nicer and provide pointers to these tables.
- */
-static u8 nv84_sor_map[16] = {
- 0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static u8 nv92_sor_map[16] = {
- 0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
- 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static u8 nv94_sor_map[16] = {
- 0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31,
- 0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-static u8 nv98_sor_map[16] = {
- 0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31,
- 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
-};
-
-u8
-mxm_sor_map(struct nouveau_bios *bios, u8 conn)
-{
- u8 ver, hdr;
- u16 mxm = mxm_table(bios, &ver, &hdr);
- if (mxm && hdr >= 6) {
- u16 map = nv_ro16(bios, mxm + 4);
- if (map) {
- ver = nv_ro08(bios, map);
- if (ver == 0x10) {
- if (conn < nv_ro08(bios, map + 3)) {
- map += nv_ro08(bios, map + 1);
- map += conn;
- return nv_ro08(bios, map);
- }
-
- return 0x00;
- }
-
- nv_warn(bios, "unknown sor map v%02x\n", ver);
- }
- }
-
- if (bios->version.chip == 0x84 || bios->version.chip == 0x86)
- return nv84_sor_map[conn];
- if (bios->version.chip == 0x92)
- return nv92_sor_map[conn];
- if (bios->version.chip == 0x94 || bios->version.chip == 0x96)
- return nv94_sor_map[conn];
- if (bios->version.chip == 0x98)
- return nv98_sor_map[conn];
-
- nv_warn(bios, "missing sor map\n");
- return 0x00;
-}
-
-u8
-mxm_ddc_map(struct nouveau_bios *bios, u8 port)
-{
- u8 ver, hdr;
- u16 mxm = mxm_table(bios, &ver, &hdr);
- if (mxm && hdr >= 8) {
- u16 map = nv_ro16(bios, mxm + 6);
- if (map) {
- ver = nv_ro08(bios, map);
- if (ver == 0x10) {
- if (port < nv_ro08(bios, map + 3)) {
- map += nv_ro08(bios, map + 1);
- map += port;
- return nv_ro08(bios, map);
- }
-
- return 0x00;
- }
-
- nv_warn(bios, "unknown ddc map v%02x\n", ver);
- }
- }
-
- /* v2.x: directly write port as dcb i2cidx */
- return (port << 4) | port;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c
deleted file mode 100644
index d694716a166c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/npde.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/npde.h>
-#include <subdev/bios/pcir.h>
-
-u32
-nvbios_npdeTe(struct nouveau_bios *bios, u32 base)
-{
- struct nvbios_pcirT pcir;
- u8 ver; u16 hdr;
- u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir);
- if (data = (data + hdr + 0x0f) & ~0x0f, data) {
- switch (nv_ro32(bios, data + 0x00)) {
- case 0x4544504e: /* NPDE */
- break;
- default:
- nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n",
- data, nv_ro32(bios, data + 0x00));
- data = 0;
- break;
- }
- }
- return data;
-}
-
-u32
-nvbios_npdeTp(struct nouveau_bios *bios, u32 base, struct nvbios_npdeT *info)
-{
- u32 data = nvbios_npdeTe(bios, base);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- info->image_size = nv_ro16(bios, data + 0x08) * 512;
- info->last = nv_ro08(bios, data + 0x0a) & 0x80;
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c
deleted file mode 100644
index 91dae26bc50f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/pcir.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pcir.h>
-
-u32
-nvbios_pcirTe(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr)
-{
- u32 data = nv_ro16(bios, base + 0x18);
- if (data) {
- data += base;
- switch (nv_ro32(bios, data + 0x00)) {
- case 0x52494350: /* PCIR */
- case 0x53494752: /* RGIS */
- case 0x5344504e: /* NPDS */
- *hdr = nv_ro16(bios, data + 0x0a);
- *ver = nv_ro08(bios, data + 0x0c);
- break;
- default:
- nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n",
- data, nv_ro32(bios, data + 0x00));
- data = 0;
- break;
- }
- }
- return data;
-}
-
-u32
-nvbios_pcirTp(struct nouveau_bios *bios, u32 base, u8 *ver, u16 *hdr,
- struct nvbios_pcirT *info)
-{
- u32 data = nvbios_pcirTe(bios, base, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- if (data) {
- info->vendor_id = nv_ro16(bios, data + 0x04);
- info->device_id = nv_ro16(bios, data + 0x06);
- info->class_code[0] = nv_ro08(bios, data + 0x0d);
- info->class_code[1] = nv_ro08(bios, data + 0x0e);
- info->class_code[2] = nv_ro08(bios, data + 0x0f);
- info->image_size = nv_ro16(bios, data + 0x10) * 512;
- info->image_rev = nv_ro16(bios, data + 0x12);
- info->image_type = nv_ro08(bios, data + 0x14);
- info->last = nv_ro08(bios, data + 0x15) & 0x80;
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c
deleted file mode 100644
index 675e221680aa..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/perf.c
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/perf.h>
-
-u16
-nvbios_perf_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
- u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
- struct bit_entry bit_P;
- u16 perf = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version <= 2) {
- perf = nv_ro16(bios, bit_P.offset + 0);
- if (perf) {
- *ver = nv_ro08(bios, perf + 0);
- *hdr = nv_ro08(bios, perf + 1);
- if (*ver >= 0x40 && *ver < 0x41) {
- *cnt = nv_ro08(bios, perf + 5);
- *len = nv_ro08(bios, perf + 2);
- *snr = nv_ro08(bios, perf + 4);
- *ssz = nv_ro08(bios, perf + 3);
- return perf;
- } else
- if (*ver >= 0x20 && *ver < 0x40) {
- *cnt = nv_ro08(bios, perf + 2);
- *len = nv_ro08(bios, perf + 3);
- *snr = nv_ro08(bios, perf + 4);
- *ssz = nv_ro08(bios, perf + 5);
- return perf;
- }
- }
- }
- }
-
- if (bios->bmp_offset) {
- if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) {
- perf = nv_ro16(bios, bios->bmp_offset + 0x94);
- if (perf) {
- *hdr = nv_ro08(bios, perf + 0);
- *ver = nv_ro08(bios, perf + 1);
- *cnt = nv_ro08(bios, perf + 2);
- *len = nv_ro08(bios, perf + 3);
- *snr = 0;
- *ssz = 0;
- return perf;
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_perf_entry(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u8 snr, ssz;
- u16 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
- if (perf && idx < *cnt) {
- perf = perf + *hdr + (idx * (*len + (snr * ssz)));
- *hdr = *len;
- *cnt = snr;
- *len = ssz;
- return perf;
- }
- return 0x0000;
-}
-
-u16
-nvbios_perfEp(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_perfE *info)
-{
- u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- info->pstate = nv_ro08(bios, perf + 0x00);
- switch (!!perf * *ver) {
- case 0x12:
- case 0x13:
- case 0x14:
- info->core = nv_ro32(bios, perf + 0x01) * 10;
- info->memory = nv_ro32(bios, perf + 0x05) * 20;
- info->fanspeed = nv_ro08(bios, perf + 0x37);
- if (*hdr > 0x38)
- info->voltage = nv_ro08(bios, perf + 0x38);
- break;
- case 0x21:
- case 0x23:
- case 0x24:
- info->fanspeed = nv_ro08(bios, perf + 0x04);
- info->voltage = nv_ro08(bios, perf + 0x05);
- info->shader = nv_ro16(bios, perf + 0x06) * 1000;
- info->core = info->shader + (signed char)
- nv_ro08(bios, perf + 0x08) * 1000;
- switch (nv_device(bios)->chipset) {
- case 0x49:
- case 0x4b:
- info->memory = nv_ro16(bios, perf + 0x0b) * 1000;
- break;
- default:
- info->memory = nv_ro16(bios, perf + 0x0b) * 2000;
- break;
- }
- break;
- case 0x25:
- info->fanspeed = nv_ro08(bios, perf + 0x04);
- info->voltage = nv_ro08(bios, perf + 0x05);
- info->core = nv_ro16(bios, perf + 0x06) * 1000;
- info->shader = nv_ro16(bios, perf + 0x0a) * 1000;
- info->memory = nv_ro16(bios, perf + 0x0c) * 1000;
- break;
- case 0x30:
- info->script = nv_ro16(bios, perf + 0x02);
- case 0x35:
- info->fanspeed = nv_ro08(bios, perf + 0x06);
- info->voltage = nv_ro08(bios, perf + 0x07);
- info->core = nv_ro16(bios, perf + 0x08) * 1000;
- info->shader = nv_ro16(bios, perf + 0x0a) * 1000;
- info->memory = nv_ro16(bios, perf + 0x0c) * 1000;
- info->vdec = nv_ro16(bios, perf + 0x10) * 1000;
- info->disp = nv_ro16(bios, perf + 0x14) * 1000;
- break;
- case 0x40:
- info->voltage = nv_ro08(bios, perf + 0x02);
- break;
- default:
- return 0x0000;
- }
- return perf;
-}
-
-u32
-nvbios_perfSe(struct nouveau_bios *bios, u32 perfE, int idx,
- u8 *ver, u8 *hdr, u8 cnt, u8 len)
-{
- u32 data = 0x00000000;
- if (idx < cnt) {
- data = perfE + *hdr + (idx * len);
- *hdr = len;
- }
- return data;
-}
-
-u32
-nvbios_perfSp(struct nouveau_bios *bios, u32 perfE, int idx,
- u8 *ver, u8 *hdr, u8 cnt, u8 len,
- struct nvbios_perfS *info)
-{
- u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- case 0x40:
- info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000;
- break;
- default:
- break;
- }
- return data;
-}
-
-int
-nvbios_perf_fan_parse(struct nouveau_bios *bios,
- struct nvbios_perf_fan *fan)
-{
- u8 ver, hdr, cnt, len, snr, ssz;
- u16 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
- if (!perf)
- return -ENODEV;
-
- if (ver >= 0x20 && ver < 0x40 && hdr > 6)
- fan->pwm_divisor = nv_ro16(bios, perf + 6);
- else
- fan->pwm_divisor = 0;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c
deleted file mode 100644
index 1f76de597d4b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/pll.c
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright 2005-2006 Erik Waling
- * Copyright 2006 Stephane Marchesin
- * Copyright 2007-2009 Stuart Bennett
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION 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 <subdev/vga.h>
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/bios/pll.h>
-
-struct pll_mapping {
- u8 type;
- u32 reg;
-};
-
-static struct pll_mapping
-nv04_pll_mapping[] = {
- { PLL_CORE , 0x680500 },
- { PLL_MEMORY, 0x680504 },
- { PLL_VPLL0 , 0x680508 },
- { PLL_VPLL1 , 0x680520 },
- {}
-};
-
-static struct pll_mapping
-nv40_pll_mapping[] = {
- { PLL_CORE , 0x004000 },
- { PLL_MEMORY, 0x004020 },
- { PLL_VPLL0 , 0x680508 },
- { PLL_VPLL1 , 0x680520 },
- {}
-};
-
-static struct pll_mapping
-nv50_pll_mapping[] = {
- { PLL_CORE , 0x004028 },
- { PLL_SHADER, 0x004020 },
- { PLL_UNK03 , 0x004000 },
- { PLL_MEMORY, 0x004008 },
- { PLL_UNK40 , 0x00e810 },
- { PLL_UNK41 , 0x00e818 },
- { PLL_UNK42 , 0x00e824 },
- { PLL_VPLL0 , 0x614100 },
- { PLL_VPLL1 , 0x614900 },
- {}
-};
-
-static struct pll_mapping
-nv84_pll_mapping[] = {
- { PLL_CORE , 0x004028 },
- { PLL_SHADER, 0x004020 },
- { PLL_MEMORY, 0x004008 },
- { PLL_VDEC , 0x004030 },
- { PLL_UNK41 , 0x00e818 },
- { PLL_VPLL0 , 0x614100 },
- { PLL_VPLL1 , 0x614900 },
- {}
-};
-
-static u16
-pll_limits_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry bit_C;
-
- if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) {
- u16 data = nv_ro16(bios, bit_C.offset + 8);
- if (data) {
- *ver = nv_ro08(bios, data + 0);
- *hdr = nv_ro08(bios, data + 1);
- *len = nv_ro08(bios, data + 2);
- *cnt = nv_ro08(bios, data + 3);
- return data;
- }
- }
-
- if (bmp_version(bios) >= 0x0524) {
- u16 data = nv_ro16(bios, bios->bmp_offset + 142);
- if (data) {
- *ver = nv_ro08(bios, data + 0);
- *hdr = 1;
- *cnt = 1;
- *len = 0x18;
- return data;
- }
- }
-
- *ver = 0x00;
- return 0x0000;
-}
-
-static struct pll_mapping *
-pll_map(struct nouveau_bios *bios)
-{
- switch (nv_device(bios)->card_type) {
- case NV_04:
- case NV_10:
- case NV_11:
- case NV_20:
- case NV_30:
- return nv04_pll_mapping;
- break;
- case NV_40:
- return nv40_pll_mapping;
- case NV_50:
- if (nv_device(bios)->chipset == 0x50)
- return nv50_pll_mapping;
- else
- if (nv_device(bios)->chipset < 0xa3 ||
- nv_device(bios)->chipset == 0xaa ||
- nv_device(bios)->chipset == 0xac)
- return nv84_pll_mapping;
- default:
- return NULL;
- }
-}
-
-static u16
-pll_map_reg(struct nouveau_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len)
-{
- struct pll_mapping *map;
- u8 hdr, cnt;
- u16 data;
-
- data = pll_limits_table(bios, ver, &hdr, &cnt, len);
- if (data && *ver >= 0x30) {
- data += hdr;
- while (cnt--) {
- if (nv_ro32(bios, data + 3) == reg) {
- *type = nv_ro08(bios, data + 0);
- return data;
- }
- data += *len;
- }
- return 0x0000;
- }
-
- map = pll_map(bios);
- while (map->reg) {
- if (map->reg == reg && *ver >= 0x20) {
- u16 addr = (data += hdr);
- *type = map->type;
- while (cnt--) {
- if (nv_ro32(bios, data) == map->reg)
- return data;
- data += *len;
- }
- return addr;
- } else
- if (map->reg == reg) {
- *type = map->type;
- return data + 1;
- }
- map++;
- }
-
- return 0x0000;
-}
-
-static u16
-pll_map_type(struct nouveau_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len)
-{
- struct pll_mapping *map;
- u8 hdr, cnt;
- u16 data;
-
- data = pll_limits_table(bios, ver, &hdr, &cnt, len);
- if (data && *ver >= 0x30) {
- data += hdr;
- while (cnt--) {
- if (nv_ro08(bios, data + 0) == type) {
- *reg = nv_ro32(bios, data + 3);
- return data;
- }
- data += *len;
- }
- return 0x0000;
- }
-
- map = pll_map(bios);
- while (map->reg) {
- if (map->type == type && *ver >= 0x20) {
- u16 addr = (data += hdr);
- *reg = map->reg;
- while (cnt--) {
- if (nv_ro32(bios, data) == map->reg)
- return data;
- data += *len;
- }
- return addr;
- } else
- if (map->type == type) {
- *reg = map->reg;
- return data + 1;
- }
- map++;
- }
-
- return 0x0000;
-}
-
-int
-nvbios_pll_parse(struct nouveau_bios *bios, u32 type, struct nvbios_pll *info)
-{
- u8 ver, len;
- u32 reg = type;
- u16 data;
-
- if (type > PLL_MAX) {
- reg = type;
- data = pll_map_reg(bios, reg, &type, &ver, &len);
- } else {
- data = pll_map_type(bios, type, &reg, &ver, &len);
- }
-
- if (ver && !data)
- return -ENOENT;
-
- memset(info, 0, sizeof(*info));
- info->type = type;
- info->reg = reg;
-
- switch (ver) {
- case 0x00:
- break;
- case 0x10:
- case 0x11:
- info->vco1.min_freq = nv_ro32(bios, data + 0);
- info->vco1.max_freq = nv_ro32(bios, data + 4);
- info->vco2.min_freq = nv_ro32(bios, data + 8);
- info->vco2.max_freq = nv_ro32(bios, data + 12);
- info->vco1.min_inputfreq = nv_ro32(bios, data + 16);
- info->vco2.min_inputfreq = nv_ro32(bios, data + 20);
- info->vco1.max_inputfreq = INT_MAX;
- info->vco2.max_inputfreq = INT_MAX;
-
- info->max_p = 0x7;
- info->max_p_usable = 0x6;
-
- /* these values taken from nv30/31/36 */
- switch (bios->version.chip) {
- case 0x36:
- info->vco1.min_n = 0x5;
- break;
- default:
- info->vco1.min_n = 0x1;
- break;
- }
- info->vco1.max_n = 0xff;
- info->vco1.min_m = 0x1;
- info->vco1.max_m = 0xd;
-
- /*
- * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this
- * table version (apart from nv35)), N2 is compared to
- * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and
- * save a comparison
- */
- info->vco2.min_n = 0x4;
- switch (bios->version.chip) {
- case 0x30:
- case 0x35:
- info->vco2.max_n = 0x1f;
- break;
- default:
- info->vco2.max_n = 0x28;
- break;
- }
- info->vco2.min_m = 0x1;
- info->vco2.max_m = 0x4;
- break;
- case 0x20:
- case 0x21:
- info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000;
- info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000;
- info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000;
- info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000;
- info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000;
- info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000;
- info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000;
- info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000;
- info->vco1.min_n = nv_ro08(bios, data + 20);
- info->vco1.max_n = nv_ro08(bios, data + 21);
- info->vco1.min_m = nv_ro08(bios, data + 22);
- info->vco1.max_m = nv_ro08(bios, data + 23);
- info->vco2.min_n = nv_ro08(bios, data + 24);
- info->vco2.max_n = nv_ro08(bios, data + 25);
- info->vco2.min_m = nv_ro08(bios, data + 26);
- info->vco2.max_m = nv_ro08(bios, data + 27);
-
- info->max_p = nv_ro08(bios, data + 29);
- info->max_p_usable = info->max_p;
- if (bios->version.chip < 0x60)
- info->max_p_usable = 0x6;
- info->bias_p = nv_ro08(bios, data + 30);
-
- if (len > 0x22)
- info->refclk = nv_ro32(bios, data + 31);
- break;
- case 0x30:
- data = nv_ro16(bios, data + 1);
-
- info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
- info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
- info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000;
- info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000;
- info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000;
- info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000;
- info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000;
- info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000;
- info->vco1.min_n = nv_ro08(bios, data + 16);
- info->vco1.max_n = nv_ro08(bios, data + 17);
- info->vco1.min_m = nv_ro08(bios, data + 18);
- info->vco1.max_m = nv_ro08(bios, data + 19);
- info->vco2.min_n = nv_ro08(bios, data + 20);
- info->vco2.max_n = nv_ro08(bios, data + 21);
- info->vco2.min_m = nv_ro08(bios, data + 22);
- info->vco2.max_m = nv_ro08(bios, data + 23);
- info->max_p_usable = info->max_p = nv_ro08(bios, data + 25);
- info->bias_p = nv_ro08(bios, data + 27);
- info->refclk = nv_ro32(bios, data + 28);
- break;
- case 0x40:
- info->refclk = nv_ro16(bios, data + 9) * 1000;
- data = nv_ro16(bios, data + 1);
-
- info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
- info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
- info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000;
- info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000;
- info->vco1.min_m = nv_ro08(bios, data + 8);
- info->vco1.max_m = nv_ro08(bios, data + 9);
- info->vco1.min_n = nv_ro08(bios, data + 10);
- info->vco1.max_n = nv_ro08(bios, data + 11);
- info->min_p = nv_ro08(bios, data + 12);
- info->max_p = nv_ro08(bios, data + 13);
- break;
- default:
- nv_error(bios, "unknown pll limits version 0x%02x\n", ver);
- return -EINVAL;
- }
-
- if (!info->refclk) {
- info->refclk = nv_device(bios)->crystal;
- if (bios->version.chip == 0x51) {
- u32 sel_clk = nv_rd32(bios, 0x680524);
- if ((info->reg == 0x680508 && sel_clk & 0x20) ||
- (info->reg == 0x680520 && sel_clk & 0x80)) {
- if (nv_rdvgac(bios, 0, 0x27) < 0xa3)
- info->refclk = 200000;
- else
- info->refclk = 25000;
- }
- }
- }
-
- /*
- * By now any valid limit table ought to have set a max frequency for
- * vco1, so if it's zero it's either a pre limit table bios, or one
- * with an empty limit table (seen on nv18)
- */
- if (!info->vco1.max_freq) {
- info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67);
- info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71);
- if (bmp_version(bios) < 0x0506) {
- info->vco1.max_freq = 256000;
- info->vco1.min_freq = 128000;
- }
-
- info->vco1.min_inputfreq = 0;
- info->vco1.max_inputfreq = INT_MAX;
- info->vco1.min_n = 0x1;
- info->vco1.max_n = 0xff;
- info->vco1.min_m = 0x1;
-
- if (nv_device(bios)->crystal == 13500) {
- /* nv05 does this, nv11 doesn't, nv10 unknown */
- if (bios->version.chip < 0x11)
- info->vco1.min_m = 0x7;
- info->vco1.max_m = 0xd;
- } else {
- if (bios->version.chip < 0x11)
- info->vco1.min_m = 0x8;
- info->vco1.max_m = 0xe;
- }
-
- if (bios->version.chip < 0x17 ||
- bios->version.chip == 0x1a ||
- bios->version.chip == 0x20)
- info->max_p = 4;
- else
- info->max_p = 5;
- info->max_p_usable = info->max_p;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c
deleted file mode 100644
index 66c56ba07d1b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/pmu.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/image.h>
-#include <subdev/bios/pmu.h>
-
-static u32
-weirdo_pointer(struct nouveau_bios *bios, u32 data)
-{
- struct nvbios_image image;
- int idx = 0;
- if (nvbios_image(bios, idx++, &image)) {
- data -= image.size;
- while (nvbios_image(bios, idx++, &image)) {
- if (image.type == 0xe0)
- return image.base + data;
- }
- }
- return 0;
-}
-
-u32
-nvbios_pmuTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry bit_p;
- u32 data = 0;
-
- if (!bit_entry(bios, 'p', &bit_p)) {
- if (bit_p.version == 2 && bit_p.length >= 4)
- data = nv_ro32(bios, bit_p.offset + 0x00);
- if ((data = weirdo_pointer(bios, data))) {
- *ver = nv_ro08(bios, data + 0x00); /* maybe? */
- *hdr = nv_ro08(bios, data + 0x01);
- *len = nv_ro08(bios, data + 0x02);
- *cnt = nv_ro08(bios, data + 0x03);
- }
- }
-
- return data;
-}
-
-u32
-nvbios_pmuTp(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_pmuT *info)
-{
- u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- default:
- break;
- }
- return data;
-}
-
-u32
-nvbios_pmuEe(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr)
-{
- u8 cnt, len;
- u32 data = nvbios_pmuTe(bios, ver, hdr, &cnt, &len);
- if (data && idx < cnt) {
- data = data + *hdr + (idx * len);
- *hdr = len;
- return data;
- }
- return 0;
-}
-
-u32
-nvbios_pmuEp(struct nouveau_bios *bios, int idx, u8 *ver, u8 *hdr,
- struct nvbios_pmuE *info)
-{
- u32 data = nvbios_pmuEe(bios, idx, ver, hdr);
- memset(info, 0x00, sizeof(*info));
- switch (!!data * *ver) {
- default:
- info->type = nv_ro08(bios, data + 0x00);
- info->data = nv_ro32(bios, data + 0x02);
- break;
- }
- return data;
-}
-
-bool
-nvbios_pmuRm(struct nouveau_bios *bios, u8 type, struct nvbios_pmuR *info)
-{
- struct nvbios_pmuE pmuE;
- u8 ver, hdr, idx = 0;
- u32 data;
- memset(info, 0x00, sizeof(*info));
- while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) {
- if ( pmuE.type == type &&
- (data = weirdo_pointer(bios, pmuE.data))) {
- info->init_addr_pmu = nv_ro32(bios, data + 0x08);
- info->args_addr_pmu = nv_ro32(bios, data + 0x0c);
- info->boot_addr = data + 0x30;
- info->boot_addr_pmu = nv_ro32(bios, data + 0x10) +
- nv_ro32(bios, data + 0x18);
- info->boot_size = nv_ro32(bios, data + 0x1c) -
- nv_ro32(bios, data + 0x18);
- info->code_addr = info->boot_addr + info->boot_size;
- info->code_addr_pmu = info->boot_addr_pmu +
- info->boot_size;
- info->code_size = nv_ro32(bios, data + 0x20);
- info->data_addr = data + 0x30 +
- nv_ro32(bios, data + 0x24);
- info->data_addr_pmu = nv_ro32(bios, data + 0x28);
- info->data_size = nv_ro32(bios, data + 0x2c);
- return true;
- }
- }
- return false;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h
deleted file mode 100644
index 187d225bd1e9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/priv.h
+++ /dev/null
@@ -1,25 +0,0 @@
-#ifndef __NVKM_BIOS_PRIV_H__
-#define __NVKM_BIOS_PRIV_H__
-
-#include <subdev/bios.h>
-
-struct nvbios_source {
- const char *name;
- void *(*init)(struct nouveau_bios *, const char *);
- void (*fini)(void *);
- u32 (*read)(void *, u32 offset, u32 length, struct nouveau_bios *);
- bool rw;
-};
-
-int nvbios_extend(struct nouveau_bios *, u32 length);
-int nvbios_shadow(struct nouveau_bios *);
-
-extern const struct nvbios_source nvbios_rom;
-extern const struct nvbios_source nvbios_ramin;
-extern const struct nvbios_source nvbios_acpi_fast;
-extern const struct nvbios_source nvbios_acpi_slow;
-extern const struct nvbios_source nvbios_pcirom;
-extern const struct nvbios_source nvbios_platform;
-extern const struct nvbios_source nvbios_of;
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
deleted file mode 100644
index 1623c8dfe797..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/ramcfg.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/M0203.h>
-
-static u8
-nvbios_ramcfg_strap(struct nouveau_subdev *subdev)
-{
- return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2;
-}
-
-u8
-nvbios_ramcfg_count(struct nouveau_bios *bios)
-{
- struct bit_entry bit_M;
-
- if (!bit_entry(bios, 'M', &bit_M)) {
- if (bit_M.version == 1 && bit_M.length >= 5)
- return nv_ro08(bios, bit_M.offset + 2);
- if (bit_M.version == 2 && bit_M.length >= 3)
- return nv_ro08(bios, bit_M.offset + 0);
- }
-
- return 0x00;
-}
-
-u8
-nvbios_ramcfg_index(struct nouveau_subdev *subdev)
-{
- struct nouveau_bios *bios = nouveau_bios(subdev);
- u8 strap = nvbios_ramcfg_strap(subdev);
- u32 xlat = 0x00000000;
- struct bit_entry bit_M;
- struct nvbios_M0203E M0203E;
- u8 ver, hdr;
-
- if (!bit_entry(bios, 'M', &bit_M)) {
- if (bit_M.version == 1 && bit_M.length >= 5)
- xlat = nv_ro16(bios, bit_M.offset + 3);
- if (bit_M.version == 2 && bit_M.length >= 3) {
- /*XXX: is M ever shorter than this?
- * if not - what is xlat used for now?
- * also - sigh..
- */
- if (bit_M.length >= 7 &&
- nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E))
- return M0203E.group;
- xlat = nv_ro16(bios, bit_M.offset + 1);
- }
- }
-
- if (xlat)
- strap = nv_ro08(bios, xlat + strap);
- return strap;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
deleted file mode 100644
index c5685228c322..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/rammap.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/rammap.h>
-
-u32
-nvbios_rammapTe(struct nouveau_bios *bios, u8 *ver, u8 *hdr,
- u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
- struct bit_entry bit_P;
- u16 rammap = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2)
- rammap = nv_ro16(bios, bit_P.offset + 4);
-
- if (rammap) {
- *ver = nv_ro08(bios, rammap + 0);
- switch (*ver) {
- case 0x10:
- case 0x11:
- *hdr = nv_ro08(bios, rammap + 1);
- *cnt = nv_ro08(bios, rammap + 5);
- *len = nv_ro08(bios, rammap + 2);
- *snr = nv_ro08(bios, rammap + 4);
- *ssz = nv_ro08(bios, rammap + 3);
- return rammap;
- default:
- break;
- }
- }
- }
-
- return 0x0000;
-}
-
-u32
-nvbios_rammapEe(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u8 snr, ssz;
- u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz);
- if (rammap && idx < *cnt) {
- rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
- *hdr = *len;
- *cnt = snr;
- *len = ssz;
- return rammap;
- }
- return 0x0000;
-}
-
-u32
-nvbios_rammapEp(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ramcfg *p)
-{
- u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
- memset(p, 0x00, sizeof(*p));
- p->rammap_ver = *ver;
- p->rammap_hdr = *hdr;
- switch (!!data * *ver) {
- case 0x10:
- p->rammap_min = nv_ro16(bios, data + 0x00);
- p->rammap_max = nv_ro16(bios, data + 0x02);
- p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1;
- p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3;
- break;
- case 0x11:
- p->rammap_min = nv_ro16(bios, data + 0x00);
- p->rammap_max = nv_ro16(bios, data + 0x02);
- p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
- p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2;
- p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
- temp = nv_ro32(bios, data + 0x09);
- p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
- p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
- p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
- p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
- p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
- p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
- p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
- p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
- p->rammap_11_0d = nv_ro08(bios, data + 0x0d);
- p->rammap_11_0e = nv_ro08(bios, data + 0x0e);
- p->rammap_11_0f = nv_ro08(bios, data + 0x0f);
- p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
- break;
- default:
- data = 0;
- break;
- }
- return data;
-}
-
-u32
-nvbios_rammapEm(struct nouveau_bios *bios, u16 mhz,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ramcfg *info)
-{
- int idx = 0;
- u32 data;
- while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
- if (mhz >= info->rammap_min && mhz <= info->rammap_max)
- break;
- }
- return data;
-}
-
-u32
-nvbios_rammapSe(struct nouveau_bios *bios, u32 data,
- u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
- u8 *ver, u8 *hdr)
-{
- if (idx < ecnt) {
- data = data + ehdr + (idx * elen);
- *ver = ever;
- *hdr = elen;
- return data;
- }
- return 0;
-}
-
-u32
-nvbios_rammapSp(struct nouveau_bios *bios, u32 data,
- u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
- u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
-{
- data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
- p->ramcfg_ver = *ver;
- p->ramcfg_hdr = *hdr;
- switch (!!data * *ver) {
- case 0x10:
- p->ramcfg_timing = nv_ro08(bios, data + 0x01);
- p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0;
- p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1;
- p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
- p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
- p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
- p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
- p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
- p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
- p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0;
- p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
- p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
- p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
- p->ramcfg_10_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0;
- p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0;
- p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4;
- break;
- case 0x11:
- p->ramcfg_timing = nv_ro08(bios, data + 0x00);
- p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0;
- p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1;
- p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2;
- p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3;
- p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4;
- p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5;
- p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6;
- p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7;
- p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0;
- p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
- p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
- p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
- p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
- p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7;
- p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
- p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4;
- p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6;
- p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4;
- p->ramcfg_11_04 = (nv_ro08(bios, data + 0x04) & 0xff) >> 0;
- p->ramcfg_11_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
- p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1;
- p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2;
- p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3;
- p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4;
- p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6;
- p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7;
- p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
- p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1;
- p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2;
- p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3;
- p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
- p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5;
- p->ramcfg_11_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0;
- break;
- default:
- data = 0;
- break;
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c
deleted file mode 100644
index bb9e0018d936..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadow.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "priv.h"
-#include <core/option.h>
-#include <subdev/bios/image.h>
-
-struct shadow {
- struct nouveau_oclass base;
- u32 skip;
- const struct nvbios_source *func;
- void *data;
- u32 size;
- int score;
-};
-
-static bool
-shadow_fetch(struct nouveau_bios *bios, u32 upto)
-{
- struct shadow *mthd = (void *)nv_object(bios)->oclass;
- const u32 limit = (upto + 3) & ~3;
- const u32 start = bios->size;
- void *data = mthd->data;
- if (nvbios_extend(bios, limit) > 0) {
- u32 read = mthd->func->read(data, start, limit - start, bios);
- bios->size = start + read;
- }
- return bios->size >= limit;
-}
-
-static u8
-shadow_rd08(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_bios *bios = (void *)object;
- if (shadow_fetch(bios, addr + 1))
- return bios->data[addr];
- return 0x00;
-}
-
-static u16
-shadow_rd16(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_bios *bios = (void *)object;
- if (shadow_fetch(bios, addr + 2))
- return get_unaligned_le16(&bios->data[addr]);
- return 0x0000;
-}
-
-static u32
-shadow_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nouveau_bios *bios = (void *)object;
- if (shadow_fetch(bios, addr + 4))
- return get_unaligned_le32(&bios->data[addr]);
- return 0x00000000;
-}
-
-static struct nouveau_oclass
-shadow_class = {
- .handle = NV_SUBDEV(VBIOS, 0x00),
- .ofuncs = &(struct nouveau_ofuncs) {
- .rd08 = shadow_rd08,
- .rd16 = shadow_rd16,
- .rd32 = shadow_rd32,
- },
-};
-
-static int
-shadow_image(struct nouveau_bios *bios, int idx, struct shadow *mthd)
-{
- struct nvbios_image image;
- int score = 1;
-
- if (!nvbios_image(bios, idx, &image)) {
- nv_debug(bios, "image %d invalid\n", idx);
- return 0;
- }
- nv_debug(bios, "%08x: type %02x, %d bytes\n",
- image.base, image.type, image.size);
-
- if (!shadow_fetch(bios, image.size)) {
- nv_debug(bios, "%08x: fetch failed\n", image.base);
- return 0;
- }
-
- switch (image.type) {
- case 0x00:
- if (nvbios_checksum(&bios->data[image.base], image.size)) {
- nv_debug(bios, "%08x: checksum failed\n", image.base);
- if (mthd->func->rw)
- score += 1;
- score += 1;
- } else {
- score += 3;
- }
- break;
- default:
- score += 3;
- break;
- }
-
- if (!image.last)
- score += shadow_image(bios, idx + 1, mthd);
- return score;
-}
-
-static int
-shadow_score(struct nouveau_bios *bios, struct shadow *mthd)
-{
- struct nouveau_oclass *oclass = nv_object(bios)->oclass;
- int score;
- nv_object(bios)->oclass = &mthd->base;
- score = shadow_image(bios, 0, mthd);
- nv_object(bios)->oclass = oclass;
- return score;
-
-}
-
-static int
-shadow_method(struct nouveau_bios *bios, struct shadow *mthd, const char *name)
-{
- const struct nvbios_source *func = mthd->func;
- if (func->name) {
- nv_debug(bios, "trying %s...\n", name ? name : func->name);
- if (func->init) {
- mthd->data = func->init(bios, name);
- if (IS_ERR(mthd->data)) {
- mthd->data = NULL;
- return 0;
- }
- }
- mthd->score = shadow_score(bios, mthd);
- if (func->fini)
- func->fini(mthd->data);
- nv_debug(bios, "scored %d\n", mthd->score);
- mthd->data = bios->data;
- mthd->size = bios->size;
- bios->data = NULL;
- bios->size = 0;
- }
- return mthd->score;
-}
-
-static u32
-shadow_fw_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- const struct firmware *fw = data;
- if (offset + length <= fw->size) {
- memcpy(bios->data + offset, fw->data + offset, length);
- return length;
- }
- return 0;
-}
-
-static void *
-shadow_fw_init(struct nouveau_bios *bios, const char *name)
-{
- struct device *dev = &nv_device(bios)->pdev->dev;
- const struct firmware *fw;
- int ret = request_firmware(&fw, name, dev);
- if (ret)
- return ERR_PTR(-ENOENT);
- return (void *)fw;
-}
-
-static const struct nvbios_source
-shadow_fw = {
- .name = "firmware",
- .init = shadow_fw_init,
- .fini = (void(*)(void *))release_firmware,
- .read = shadow_fw_read,
- .rw = false,
-};
-
-int
-nvbios_shadow(struct nouveau_bios *bios)
-{
- struct shadow mthds[] = {
- { shadow_class, 0, &nvbios_of },
- { shadow_class, 0, &nvbios_ramin },
- { shadow_class, 0, &nvbios_rom },
- { shadow_class, 0, &nvbios_acpi_fast },
- { shadow_class, 4, &nvbios_acpi_slow },
- { shadow_class, 1, &nvbios_pcirom },
- { shadow_class, 1, &nvbios_platform },
- { shadow_class }
- }, *mthd = mthds, *best = NULL;
- const char *optarg;
- char *source;
- int optlen;
-
- /* handle user-specified bios source */
- optarg = nouveau_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
- source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
- if (source) {
- /* try to match one of the built-in methods */
- for (mthd = mthds; mthd->func; mthd++) {
- if (mthd->func->name &&
- !strcasecmp(source, mthd->func->name)) {
- best = mthd;
- if (shadow_method(bios, mthd, NULL))
- break;
- }
- }
-
- /* otherwise, attempt to load as firmware */
- if (!best && (best = mthd)) {
- mthd->func = &shadow_fw;
- shadow_method(bios, mthd, source);
- mthd->func = NULL;
- }
-
- if (!best->score) {
- nv_error(bios, "%s invalid\n", source);
- kfree(source);
- source = NULL;
- }
- }
-
- /* scan all potential bios sources, looking for best image */
- if (!best || !best->score) {
- for (mthd = mthds, best = mthd; mthd->func; mthd++) {
- if (!mthd->skip || best->score < mthd->skip) {
- if (shadow_method(bios, mthd, NULL)) {
- if (mthd->score > best->score)
- best = mthd;
- }
- }
- }
- }
-
- /* cleanup the ones we didn't use */
- for (mthd = mthds; mthd->func; mthd++) {
- if (mthd != best)
- kfree(mthd->data);
- }
-
- if (!best->score) {
- nv_fatal(bios, "unable to locate usable image\n");
- return -EINVAL;
- }
-
- nv_info(bios, "using image from %s\n", best->func ?
- best->func->name : source);
- bios->data = best->data;
- bios->size = best->size;
- kfree(source);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c
deleted file mode 100644
index bc130c12ec06..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowacpi.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "priv.h"
-
-#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
-int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
-bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
-#else
-static inline bool
-nouveau_acpi_rom_supported(struct pci_dev *pdev)
-{
- return false;
-}
-
-static inline int
-nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
-{
- return -EINVAL;
-}
-#endif
-
-/* This version of the shadow function disobeys the ACPI spec and tries
- * to fetch in units of more than 4KiB at a time. This is a LOT faster
- * on some systems, such as Lenovo W530.
- */
-static u32
-acpi_read_fast(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- u32 limit = (offset + length + 0xfff) & ~0xfff;
- u32 start = offset & ~0x00000fff;
- u32 fetch = limit - start;
-
- if (nvbios_extend(bios, limit) > 0) {
- int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
- if (ret == fetch)
- return fetch;
- }
-
- return 0;
-}
-
-/* Other systems, such as the one in fdo#55948, will report a success
- * but only return 4KiB of data. The common bios fetching logic will
- * detect an invalid image, and fall back to this version of the read
- * function.
- */
-static u32
-acpi_read_slow(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- u32 limit = (offset + length + 0xfff) & ~0xfff;
- u32 start = offset & ~0xfff;
- u32 fetch = 0;
-
- if (nvbios_extend(bios, limit) > 0) {
- while (start + fetch < limit) {
- int ret = nouveau_acpi_get_bios_chunk(bios->data,
- start + fetch,
- 0x1000);
- if (ret != 0x1000)
- break;
- fetch += 0x1000;
- }
- }
-
- return fetch;
-}
-
-static void *
-acpi_init(struct nouveau_bios *bios, const char *name)
-{
- if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev))
- return ERR_PTR(-ENODEV);
- return NULL;
-}
-
-const struct nvbios_source
-nvbios_acpi_fast = {
- .name = "ACPI",
- .init = acpi_init,
- .read = acpi_read_fast,
- .rw = false,
-};
-
-const struct nvbios_source
-nvbios_acpi_slow = {
- .name = "ACPI",
- .init = acpi_init,
- .read = acpi_read_slow,
- .rw = false,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c
deleted file mode 100644
index 3abe487a6025..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowof.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "priv.h"
-
-#if defined(__powerpc__)
-struct priv {
- const void __iomem *data;
- int size;
-};
-
-static u32
-of_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- struct priv *priv = data;
- if (offset + length <= priv->size) {
- memcpy_fromio(bios->data + offset, priv->data + offset, length);
- return length;
- }
- return 0;
-}
-
-static void *
-of_init(struct nouveau_bios *bios, const char *name)
-{
- struct pci_dev *pdev = nv_device(bios)->pdev;
- struct device_node *dn;
- struct priv *priv;
- if (!(dn = pci_device_to_OF_node(pdev)))
- return ERR_PTR(-ENODEV);
- if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
- return ERR_PTR(-ENOMEM);
- if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
- return priv;
- kfree(priv);
- return ERR_PTR(-EINVAL);
-}
-
-const struct nvbios_source
-nvbios_of = {
- .name = "OpenFirmware",
- .init = of_init,
- .fini = (void(*)(void *))kfree,
- .read = of_read,
- .rw = false,
-};
-#else
-const struct nvbios_source
-nvbios_of = {
-};
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c
deleted file mode 100644
index 1d0389c0abef..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowpci.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "priv.h"
-
-struct priv {
- struct pci_dev *pdev;
- void __iomem *rom;
- size_t size;
-};
-
-static u32
-pcirom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- struct priv *priv = data;
- if (offset + length <= priv->size) {
- memcpy_fromio(bios->data + offset, priv->rom + offset, length);
- return length;
- }
- return 0;
-}
-
-static void
-pcirom_fini(void *data)
-{
- struct priv *priv = data;
- pci_unmap_rom(priv->pdev, priv->rom);
- pci_disable_rom(priv->pdev);
- kfree(priv);
-}
-
-static void *
-pcirom_init(struct nouveau_bios *bios, const char *name)
-{
- struct pci_dev *pdev = nv_device(bios)->pdev;
- struct priv *priv = NULL;
- int ret;
-
- if (!(ret = pci_enable_rom(pdev))) {
- if (ret = -ENOMEM,
- (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
- if (ret = -EFAULT,
- (priv->rom = pci_map_rom(pdev, &priv->size))) {
- priv->pdev = pdev;
- return priv;
- }
- kfree(priv);
- }
- pci_disable_rom(pdev);
- }
-
- return ERR_PTR(ret);
-}
-
-const struct nvbios_source
-nvbios_pcirom = {
- .name = "PCIROM",
- .init = pcirom_init,
- .fini = pcirom_fini,
- .read = pcirom_read,
- .rw = true,
-};
-
-static void *
-platform_init(struct nouveau_bios *bios, const char *name)
-{
- struct pci_dev *pdev = nv_device(bios)->pdev;
- struct priv *priv;
- int ret = -ENOMEM;
-
- if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
- if (ret = -ENODEV,
- (priv->rom = pci_platform_rom(pdev, &priv->size)))
- return priv;
- kfree(priv);
- }
-
- return ERR_PTR(ret);
-}
-
-const struct nvbios_source
-nvbios_platform = {
- .name = "PLATFORM",
- .init = platform_init,
- .fini = (void(*)(void *))kfree,
- .read = pcirom_read,
- .rw = true,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c
deleted file mode 100644
index a7a890fad1e5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowramin.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "priv.h"
-
-struct priv {
- struct nouveau_bios *bios;
- u32 bar0;
-};
-
-static u32
-pramin_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- u32 i;
- if (offset + length <= 0x00100000) {
- for (i = offset; i < offset + length; i += 4)
- *(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i);
- return length;
- }
- return 0;
-}
-
-static void
-pramin_fini(void *data)
-{
- struct priv *priv = data;
- if (priv) {
- nv_wr32(priv->bios, 0x001700, priv->bar0);
- kfree(priv);
- }
-}
-
-static void *
-pramin_init(struct nouveau_bios *bios, const char *name)
-{
- struct priv *priv = NULL;
- u64 addr = 0;
-
- /* PRAMIN always potentially available prior to nv50 */
- if (nv_device(bios)->card_type < NV_50)
- return NULL;
-
- /* we can't get the bios image pointer without PDISP */
- if (nv_device(bios)->card_type >= GM100)
- addr = nv_rd32(bios, 0x021c04);
- else
- if (nv_device(bios)->card_type >= NV_C0)
- addr = nv_rd32(bios, 0x022500);
- if (addr & 0x00000001) {
- nv_debug(bios, "... display disabled\n");
- return ERR_PTR(-ENODEV);
- }
-
- /* check that the window is enabled and in vram, particularly
- * important as we don't want to be touching vram on an
- * uninitialised board
- */
- addr = nv_rd32(bios, 0x619f04);
- if (!(addr & 0x00000008)) {
- nv_debug(bios, "... not enabled\n");
- return ERR_PTR(-ENODEV);
- }
- if ( (addr & 0x00000003) != 1) {
- nv_debug(bios, "... not in vram\n");
- return ERR_PTR(-ENODEV);
- }
-
- /* some alternate method inherited from xf86-video-nv... */
- addr = (addr & 0xffffff00) << 8;
- if (!addr) {
- addr = (u64)nv_rd32(bios, 0x001700) << 16;
- addr += 0xf0000;
- }
-
- /* modify bar0 PRAMIN window to cover the bios image */
- if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
- nv_error(bios, "... out of memory\n");
- return ERR_PTR(-ENOMEM);
- }
-
- priv->bios = bios;
- priv->bar0 = nv_rd32(bios, 0x001700);
- nv_wr32(bios, 0x001700, addr >> 16);
- return priv;
-}
-
-const struct nvbios_source
-nvbios_ramin = {
- .name = "PRAMIN",
- .init = pramin_init,
- .fini = pramin_fini,
- .read = pramin_read,
- .rw = true,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c
deleted file mode 100644
index b7992bc3ffa5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/shadowrom.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "priv.h"
-
-static u32
-prom_read(void *data, u32 offset, u32 length, struct nouveau_bios *bios)
-{
- u32 i;
- if (offset + length <= 0x00100000) {
- for (i = offset; i < offset + length; i += 4)
- *(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i);
- return length;
- }
- return 0;
-}
-
-static void
-prom_fini(void *data)
-{
- struct nouveau_bios *bios = data;
- if (nv_device(bios)->card_type < NV_50)
- nv_mask(bios, 0x001850, 0x00000001, 0x00000001);
- else
- nv_mask(bios, 0x088050, 0x00000001, 0x00000001);
-}
-
-static void *
-prom_init(struct nouveau_bios *bios, const char *name)
-{
- if (nv_device(bios)->card_type < NV_50) {
- if (nv_device(bios)->card_type == NV_40 &&
- nv_device(bios)->chipset >= 0x4c)
- return ERR_PTR(-ENODEV);
- nv_mask(bios, 0x001850, 0x00000001, 0x00000000);
- } else {
- nv_mask(bios, 0x088050, 0x00000001, 0x00000000);
- }
- return bios;
-}
-
-const struct nvbios_source
-nvbios_rom = {
- .name = "PROM",
- .init = prom_init,
- .fini = prom_fini,
- .read = prom_read,
- .rw = false,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
deleted file mode 100644
index d15854094078..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/therm.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/therm.h>
-
-static u16
-therm_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
-{
- struct bit_entry bit_P;
- u16 therm = 0;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 1)
- therm = nv_ro16(bios, bit_P.offset + 12);
- else if (bit_P.version == 2)
- therm = nv_ro16(bios, bit_P.offset + 16);
- else
- nv_error(bios,
- "unknown offset for thermal in BIT P %d\n",
- bit_P.version);
- }
-
- /* exit now if we haven't found the thermal table */
- if (!therm)
- return 0x0000;
-
- *ver = nv_ro08(bios, therm + 0);
- *hdr = nv_ro08(bios, therm + 1);
- *len = nv_ro08(bios, therm + 2);
- *cnt = nv_ro08(bios, therm + 3);
-
- return therm + nv_ro08(bios, therm + 1);
-}
-
-static u16
-nvbios_therm_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u16 therm = therm_table(bios, ver, &hdr, len, &cnt);
- if (therm && idx < cnt)
- return therm + idx * *len;
- return 0x0000;
-}
-
-int
-nvbios_therm_sensor_parse(struct nouveau_bios *bios,
- enum nvbios_therm_domain domain,
- struct nvbios_therm_sensor *sensor)
-{
- s8 thrs_section, sensor_section, offset;
- u8 ver, len, i;
- u16 entry;
-
- /* we only support the core domain for now */
- if (domain != NVBIOS_THERM_DOMAIN_CORE)
- return -EINVAL;
-
- /* Read the entries from the table */
- thrs_section = 0;
- sensor_section = -1;
- i = 0;
- while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
- s16 value = nv_ro16(bios, entry + 1);
-
- switch (nv_ro08(bios, entry + 0)) {
- case 0x0:
- thrs_section = value;
- if (value > 0)
- return 0; /* we do not try to support ambient */
- break;
- case 0x01:
- sensor_section++;
- if (sensor_section == 0) {
- offset = ((s8) nv_ro08(bios, entry + 2)) / 2;
- sensor->offset_constant = offset;
- }
- break;
-
- case 0x04:
- if (thrs_section == 0) {
- sensor->thrs_critical.temp = (value & 0xff0) >> 4;
- sensor->thrs_critical.hysteresis = value & 0xf;
- }
- break;
-
- case 0x07:
- if (thrs_section == 0) {
- sensor->thrs_down_clock.temp = (value & 0xff0) >> 4;
- sensor->thrs_down_clock.hysteresis = value & 0xf;
- }
- break;
-
- case 0x08:
- if (thrs_section == 0) {
- sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4;
- sensor->thrs_fan_boost.hysteresis = value & 0xf;
- }
- break;
-
- case 0x10:
- if (sensor_section == 0)
- sensor->offset_num = value;
- break;
-
- case 0x11:
- if (sensor_section == 0)
- sensor->offset_den = value;
- break;
-
- case 0x12:
- if (sensor_section == 0)
- sensor->slope_mult = value;
- break;
-
- case 0x13:
- if (sensor_section == 0)
- sensor->slope_div = value;
- break;
- case 0x32:
- if (thrs_section == 0) {
- sensor->thrs_shutdown.temp = (value & 0xff0) >> 4;
- sensor->thrs_shutdown.hysteresis = value & 0xf;
- }
- break;
- }
- }
-
- return 0;
-}
-
-int
-nvbios_therm_fan_parse(struct nouveau_bios *bios,
- struct nvbios_therm_fan *fan)
-{
- struct nouveau_therm_trip_point *cur_trip = NULL;
- u8 ver, len, i;
- u16 entry;
-
- uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0,
- 75, 0, 85, 0, 100, 0, 100, 0 };
-
- i = 0;
- fan->nr_fan_trip = 0;
- fan->fan_mode = NVBIOS_THERM_FAN_OTHER;
- while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
- s16 value = nv_ro16(bios, entry + 1);
-
- switch (nv_ro08(bios, entry + 0)) {
- case 0x22:
- fan->min_duty = value & 0xff;
- fan->max_duty = (value & 0xff00) >> 8;
- break;
- case 0x24:
- fan->nr_fan_trip++;
- if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP)
- fan->fan_mode = NVBIOS_THERM_FAN_TRIP;
- cur_trip = &fan->trip[fan->nr_fan_trip - 1];
- cur_trip->hysteresis = value & 0xf;
- cur_trip->temp = (value & 0xff0) >> 4;
- cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12];
- break;
- case 0x25:
- cur_trip = &fan->trip[fan->nr_fan_trip - 1];
- cur_trip->fan_duty = value;
- break;
- case 0x26:
- if (!fan->pwm_freq)
- fan->pwm_freq = value;
- break;
- case 0x3b:
- fan->bump_period = value;
- break;
- case 0x3c:
- fan->slow_down_period = value;
- break;
- case 0x46:
- if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR)
- fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
- fan->linear_min_temp = nv_ro08(bios, entry + 1);
- fan->linear_max_temp = nv_ro08(bios, entry + 2);
- break;
- }
- }
-
- /* starting from fermi, fan management is always linear */
- if (nv_device(bios)->card_type >= NV_C0 &&
- fan->fan_mode == NVBIOS_THERM_FAN_OTHER) {
- fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
deleted file mode 100644
index 8521eca1ed9c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/timing.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/ramcfg.h>
-#include <subdev/bios/timing.h>
-
-u16
-nvbios_timingTe(struct nouveau_bios *bios,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
-{
- struct bit_entry bit_P;
- u16 timing = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 1)
- timing = nv_ro16(bios, bit_P.offset + 4);
- else
- if (bit_P.version == 2)
- timing = nv_ro16(bios, bit_P.offset + 8);
-
- if (timing) {
- *ver = nv_ro08(bios, timing + 0);
- switch (*ver) {
- case 0x10:
- *hdr = nv_ro08(bios, timing + 1);
- *cnt = nv_ro08(bios, timing + 2);
- *len = nv_ro08(bios, timing + 3);
- *snr = 0;
- *ssz = 0;
- return timing;
- case 0x20:
- *hdr = nv_ro08(bios, timing + 1);
- *cnt = nv_ro08(bios, timing + 5);
- *len = nv_ro08(bios, timing + 2);
- *snr = nv_ro08(bios, timing + 4);
- *ssz = nv_ro08(bios, timing + 3);
- return timing;
- default:
- break;
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_timingEe(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u8 snr, ssz;
- u16 timing = nvbios_timingTe(bios, ver, hdr, cnt, len, &snr, &ssz);
- if (timing && idx < *cnt) {
- timing += *hdr + idx * (*len + (snr * ssz));
- *hdr = *len;
- *cnt = snr;
- *len = ssz;
- return timing;
- }
- return 0x0000;
-}
-
-u16
-nvbios_timingEp(struct nouveau_bios *bios, int idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_ramcfg *p)
-{
- u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
- p->timing_ver = *ver;
- p->timing_hdr = *hdr;
- switch (!!data * *ver) {
- case 0x10:
- p->timing_10_WR = nv_ro08(bios, data + 0x00);
- p->timing_10_WTR = nv_ro08(bios, data + 0x01);
- p->timing_10_CL = nv_ro08(bios, data + 0x02);
- p->timing_10_RC = nv_ro08(bios, data + 0x03);
- p->timing_10_RFC = nv_ro08(bios, data + 0x05);
- p->timing_10_RAS = nv_ro08(bios, data + 0x07);
- p->timing_10_RP = nv_ro08(bios, data + 0x09);
- p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a);
- p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b);
- p->timing_10_RRD = nv_ro08(bios, data + 0x0c);
- p->timing_10_13 = nv_ro08(bios, data + 0x0d);
- p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07;
-
- p->timing_10_24 = 0xff;
- p->timing_10_21 = 0;
- p->timing_10_20 = 0;
- p->timing_10_CWL = 0;
- p->timing_10_18 = 0;
- p->timing_10_16 = 0;
-
- switch (min_t(u8, *hdr, 25)) {
- case 25:
- p->timing_10_24 = nv_ro08(bios, data + 0x18);
- case 24:
- case 23:
- case 22:
- p->timing_10_21 = nv_ro08(bios, data + 0x15);
- case 21:
- p->timing_10_20 = nv_ro08(bios, data + 0x14);
- case 20:
- p->timing_10_CWL = nv_ro08(bios, data + 0x13);
- case 19:
- p->timing_10_18 = nv_ro08(bios, data + 0x12);
- case 18:
- case 17:
- p->timing_10_16 = nv_ro08(bios, data + 0x10);
- }
-
- break;
- case 0x20:
- p->timing[0] = nv_ro32(bios, data + 0x00);
- p->timing[1] = nv_ro32(bios, data + 0x04);
- p->timing[2] = nv_ro32(bios, data + 0x08);
- p->timing[3] = nv_ro32(bios, data + 0x0c);
- p->timing[4] = nv_ro32(bios, data + 0x10);
- p->timing[5] = nv_ro32(bios, data + 0x14);
- p->timing[6] = nv_ro32(bios, data + 0x18);
- p->timing[7] = nv_ro32(bios, data + 0x1c);
- p->timing[8] = nv_ro32(bios, data + 0x20);
- p->timing[9] = nv_ro32(bios, data + 0x24);
- p->timing[10] = nv_ro32(bios, data + 0x28);
- p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0;
- p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4;
- p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6;
- p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0;
- temp = nv_ro16(bios, data + 0x2c);
- p->timing_20_2c_003f = (temp & 0x003f) >> 0;
- p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6;
- p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0;
- p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3;
- temp = nv_ro16(bios, data + 0x31);
- p->timing_20_31_0007 = (temp & 0x0007) >> 0;
- p->timing_20_31_0078 = (temp & 0x0078) >> 3;
- p->timing_20_31_0780 = (temp & 0x0780) >> 7;
- p->timing_20_31_0800 = (temp & 0x0800) >> 11;
- p->timing_20_31_7000 = (temp & 0x7000) >> 12;
- p->timing_20_31_8000 = (temp & 0x8000) >> 15;
- break;
- default:
- data = 0;
- break;
- }
- return data;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c
deleted file mode 100644
index f343a1b060e8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/vmap.c
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/vmap.h>
-
-u16
-nvbios_vmap_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry bit_P;
- u16 vmap = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2) {
- vmap = nv_ro16(bios, bit_P.offset + 0x20);
- if (vmap) {
- *ver = nv_ro08(bios, vmap + 0);
- switch (*ver) {
- case 0x10:
- case 0x20:
- *hdr = nv_ro08(bios, vmap + 1);
- *cnt = nv_ro08(bios, vmap + 3);
- *len = nv_ro08(bios, vmap + 2);
- return vmap;
- default:
- break;
- }
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_vmap_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_vmap *info)
-{
- u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!vmap * *ver) {
- case 0x10:
- case 0x20:
- break;
- }
- return vmap;
-}
-
-u16
-nvbios_vmap_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u16 vmap = nvbios_vmap_table(bios, ver, &hdr, &cnt, len);
- if (vmap && idx < cnt) {
- vmap = vmap + hdr + (idx * *len);
- return vmap;
- }
- return 0x0000;
-}
-
-u16
-nvbios_vmap_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
- struct nvbios_vmap_entry *info)
-{
- u16 vmap = nvbios_vmap_entry(bios, idx, ver, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!vmap * *ver) {
- case 0x10:
- info->link = 0xff;
- info->min = nv_ro32(bios, vmap + 0x00);
- info->max = nv_ro32(bios, vmap + 0x04);
- info->arg[0] = nv_ro32(bios, vmap + 0x08);
- info->arg[1] = nv_ro32(bios, vmap + 0x0c);
- info->arg[2] = nv_ro32(bios, vmap + 0x10);
- break;
- case 0x20:
- info->unk0 = nv_ro08(bios, vmap + 0x00);
- info->link = nv_ro08(bios, vmap + 0x01);
- info->min = nv_ro32(bios, vmap + 0x02);
- info->max = nv_ro32(bios, vmap + 0x06);
- info->arg[0] = nv_ro32(bios, vmap + 0x0a);
- info->arg[1] = nv_ro32(bios, vmap + 0x0e);
- info->arg[2] = nv_ro32(bios, vmap + 0x12);
- info->arg[3] = nv_ro32(bios, vmap + 0x16);
- info->arg[4] = nv_ro32(bios, vmap + 0x1a);
- info->arg[5] = nv_ro32(bios, vmap + 0x1e);
- break;
- }
- return vmap;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c
deleted file mode 100644
index bb590de4ecb2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/volt.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/volt.h>
-
-u16
-nvbios_volt_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- struct bit_entry bit_P;
- u16 volt = 0x0000;
-
- if (!bit_entry(bios, 'P', &bit_P)) {
- if (bit_P.version == 2)
- volt = nv_ro16(bios, bit_P.offset + 0x0c);
- else
- if (bit_P.version == 1)
- volt = nv_ro16(bios, bit_P.offset + 0x10);
-
- if (volt) {
- *ver = nv_ro08(bios, volt + 0);
- switch (*ver) {
- case 0x12:
- *hdr = 5;
- *cnt = nv_ro08(bios, volt + 2);
- *len = nv_ro08(bios, volt + 1);
- return volt;
- case 0x20:
- *hdr = nv_ro08(bios, volt + 1);
- *cnt = nv_ro08(bios, volt + 2);
- *len = nv_ro08(bios, volt + 3);
- return volt;
- case 0x30:
- case 0x40:
- case 0x50:
- *hdr = nv_ro08(bios, volt + 1);
- *cnt = nv_ro08(bios, volt + 3);
- *len = nv_ro08(bios, volt + 2);
- return volt;
- }
- }
- }
-
- return 0x0000;
-}
-
-u16
-nvbios_volt_parse(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_volt *info)
-{
- u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!volt * *ver) {
- case 0x12:
- info->vidmask = nv_ro08(bios, volt + 0x04);
- break;
- case 0x20:
- info->vidmask = nv_ro08(bios, volt + 0x05);
- break;
- case 0x30:
- info->vidmask = nv_ro08(bios, volt + 0x04);
- break;
- case 0x40:
- info->base = nv_ro32(bios, volt + 0x04);
- info->step = nv_ro16(bios, volt + 0x08);
- info->vidmask = nv_ro08(bios, volt + 0x0b);
- /*XXX*/
- info->min = 0;
- info->max = info->base;
- break;
- case 0x50:
- info->vidmask = nv_ro08(bios, volt + 0x06);
- info->min = nv_ro32(bios, volt + 0x0a);
- info->max = nv_ro32(bios, volt + 0x0e);
- info->base = nv_ro32(bios, volt + 0x12) & 0x00ffffff;
- info->step = nv_ro16(bios, volt + 0x16);
- break;
- }
- return volt;
-}
-
-u16
-nvbios_volt_entry(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len)
-{
- u8 hdr, cnt;
- u16 volt = nvbios_volt_table(bios, ver, &hdr, &cnt, len);
- if (volt && idx < cnt) {
- volt = volt + hdr + (idx * *len);
- return volt;
- }
- return 0x0000;
-}
-
-u16
-nvbios_volt_entry_parse(struct nouveau_bios *bios, int idx, u8 *ver, u8 *len,
- struct nvbios_volt_entry *info)
-{
- u16 volt = nvbios_volt_entry(bios, idx, ver, len);
- memset(info, 0x00, sizeof(*info));
- switch (!!volt * *ver) {
- case 0x12:
- case 0x20:
- info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
- info->vid = nv_ro08(bios, volt + 0x01);
- break;
- case 0x30:
- info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
- info->vid = nv_ro08(bios, volt + 0x01) >> 2;
- break;
- case 0x40:
- case 0x50:
- break;
- }
- return volt;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c b/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c
deleted file mode 100644
index e9b8e5d30a7a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bios/xpio.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/xpio.h>
-
-static u16
-dcb_xpiod_table(struct nouveau_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len);
- if (data && *ver >= 0x40 && *hdr >= 0x06) {
- u16 xpio = nv_ro16(bios, data + 0x04);
- if (xpio) {
- *ver = nv_ro08(bios, data + 0x00);
- *hdr = nv_ro08(bios, data + 0x01);
- *cnt = nv_ro08(bios, data + 0x02);
- *len = nv_ro08(bios, data + 0x03);
- return xpio;
- }
- }
- return 0x0000;
-}
-
-u16
-dcb_xpio_table(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
-{
- u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len);
- if (data && idx < *cnt) {
- u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len));
- if (xpio) {
- *ver = nv_ro08(bios, data + 0x00);
- *hdr = nv_ro08(bios, data + 0x01);
- *cnt = nv_ro08(bios, data + 0x02);
- *len = nv_ro08(bios, data + 0x03);
- return xpio;
- }
- }
- return 0x0000;
-}
-
-u16
-dcb_xpio_parse(struct nouveau_bios *bios, u8 idx,
- u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
- struct nvbios_xpio *info)
-{
- u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len);
- if (data && *len >= 6) {
- info->type = nv_ro08(bios, data + 0x04);
- info->addr = nv_ro08(bios, data + 0x05);
- info->flags = nv_ro08(bios, data + 0x06);
- }
- return 0x0000;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c
deleted file mode 100644
index f757470e2284..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.c
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/timer.h>
-#include <subdev/bus.h>
-
-struct nouveau_hwsq {
- struct nouveau_bus *pbus;
- u32 addr;
- u32 data;
- struct {
- u8 data[512];
- u8 size;
- } c;
-};
-
-static void
-hwsq_cmd(struct nouveau_hwsq *hwsq, int size, u8 data[])
-{
- memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0]));
- hwsq->c.size += size;
-}
-
-int
-nouveau_hwsq_init(struct nouveau_bus *pbus, struct nouveau_hwsq **phwsq)
-{
- struct nouveau_hwsq *hwsq;
-
- hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL);
- if (hwsq) {
- hwsq->pbus = pbus;
- hwsq->addr = ~0;
- hwsq->data = ~0;
- memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data));
- hwsq->c.size = 0;
- }
-
- return hwsq ? 0 : -ENOMEM;
-}
-
-int
-nouveau_hwsq_fini(struct nouveau_hwsq **phwsq, bool exec)
-{
- struct nouveau_hwsq *hwsq = *phwsq;
- int ret = 0, i;
- if (hwsq) {
- struct nouveau_bus *pbus = hwsq->pbus;
- hwsq->c.size = (hwsq->c.size + 4) / 4;
- if (hwsq->c.size <= pbus->hwsq_size) {
- if (exec)
- ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data,
- hwsq->c.size);
- if (ret)
- nv_error(pbus, "hwsq exec failed: %d\n", ret);
- } else {
- nv_error(pbus, "hwsq ucode too large\n");
- ret = -ENOSPC;
- }
-
- for (i = 0; ret && i < hwsq->c.size; i++)
- nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]);
-
- *phwsq = NULL;
- kfree(hwsq);
- }
- return ret;
-}
-
-void
-nouveau_hwsq_wr32(struct nouveau_hwsq *hwsq, u32 addr, u32 data)
-{
- nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data);
-
- if (hwsq->data != data) {
- if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) {
- hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8,
- data >> 16, data >> 24 });
- } else {
- hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 });
- }
- }
-
- if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) {
- hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8,
- addr >> 16, addr >> 24 });
- } else {
- hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 });
- }
-
- hwsq->addr = addr;
- hwsq->data = data;
-}
-
-void
-nouveau_hwsq_setf(struct nouveau_hwsq *hwsq, u8 flag, int data)
-{
- nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data);
- flag += 0x80;
- if (data >= 0)
- flag += 0x20;
- if (data >= 1)
- flag += 0x20;
- hwsq_cmd(hwsq, 1, (u8[]){ flag });
-}
-
-void
-nouveau_hwsq_wait(struct nouveau_hwsq *hwsq, u8 flag, u8 data)
-{
- nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data);
- hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data });
-}
-
-void
-nouveau_hwsq_nsec(struct nouveau_hwsq *hwsq, u32 nsec)
-{
- u8 shift = 0, usec = nsec / 1000;
- while (usec & ~3) {
- usec >>= 2;
- shift++;
- }
-
- nv_debug(hwsq->pbus, " DELAY = %d ns\n", nsec);
- hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec });
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h
deleted file mode 100644
index 12176f9c1bc6..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/hwsq.h
+++ /dev/null
@@ -1,113 +0,0 @@
-#ifndef __NVKM_BUS_HWSQ_H__
-#define __NVKM_BUS_HWSQ_H__
-
-#include <subdev/bus.h>
-
-struct hwsq {
- struct nouveau_subdev *subdev;
- struct nouveau_hwsq *hwsq;
- int sequence;
-};
-
-struct hwsq_reg {
- int sequence;
- bool force;
- u32 addr[2];
- u32 data;
-};
-
-static inline struct hwsq_reg
-hwsq_reg2(u32 addr1, u32 addr2)
-{
- return (struct hwsq_reg) {
- .sequence = 0,
- .force = 0,
- .addr = { addr1, addr2 },
- .data = 0xdeadbeef,
- };
-}
-
-static inline struct hwsq_reg
-hwsq_reg(u32 addr)
-{
- return hwsq_reg2(addr, addr);
-}
-
-static inline int
-hwsq_init(struct hwsq *ram, struct nouveau_subdev *subdev)
-{
- struct nouveau_bus *pbus = nouveau_bus(subdev);
- int ret;
-
- ret = nouveau_hwsq_init(pbus, &ram->hwsq);
- if (ret)
- return ret;
-
- ram->sequence++;
- ram->subdev = subdev;
- return 0;
-}
-
-static inline int
-hwsq_exec(struct hwsq *ram, bool exec)
-{
- int ret = 0;
- if (ram->subdev) {
- ret = nouveau_hwsq_fini(&ram->hwsq, exec);
- ram->subdev = NULL;
- }
- return ret;
-}
-
-static inline u32
-hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg)
-{
- if (reg->sequence != ram->sequence)
- reg->data = nv_rd32(ram->subdev, reg->addr[0]);
- return reg->data;
-}
-
-static inline void
-hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data)
-{
- reg->sequence = ram->sequence;
- reg->data = data;
- if (reg->addr[0] != reg->addr[1])
- nouveau_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data);
- nouveau_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data);
-}
-
-static inline void
-hwsq_nuke(struct hwsq *ram, struct hwsq_reg *reg)
-{
- reg->force = true;
-}
-
-static inline u32
-hwsq_mask(struct hwsq *ram, struct hwsq_reg *reg, u32 mask, u32 data)
-{
- u32 temp = hwsq_rd32(ram, reg);
- if (temp != ((temp & ~mask) | data) || reg->force)
- hwsq_wr32(ram, reg, (temp & ~mask) | data);
- return temp;
-}
-
-static inline void
-hwsq_setf(struct hwsq *ram, u8 flag, int data)
-{
- nouveau_hwsq_setf(ram->hwsq, flag, data);
-}
-
-static inline void
-hwsq_wait(struct hwsq *ram, u8 flag, u8 data)
-{
- nouveau_hwsq_wait(ram->hwsq, flag, data);
-}
-
-static inline void
-hwsq_nsec(struct hwsq *ram, u32 nsec)
-{
- nouveau_hwsq_nsec(ram->hwsq, nsec);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
deleted file mode 100644
index 23921b5351db..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- * Ben Skeggs
- */
-
-#include "nv04.h"
-
-static void
-nv04_bus_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_bus *pbus = nouveau_bus(subdev);
- u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-
- if (stat & 0x00000001) {
- nv_error(pbus, "BUS ERROR\n");
- stat &= ~0x00000001;
- nv_wr32(pbus, 0x001100, 0x00000001);
- }
-
- if (stat & 0x00000110) {
- subdev = nouveau_subdev(subdev, NVDEV_SUBDEV_GPIO);
- if (subdev && subdev->intr)
- subdev->intr(subdev);
- stat &= ~0x00000110;
- nv_wr32(pbus, 0x001100, 0x00000110);
- }
-
- if (stat) {
- nv_error(pbus, "unknown intr 0x%08x\n", stat);
- nv_mask(pbus, 0x001140, stat, 0x00000000);
- }
-}
-
-static int
-nv04_bus_init(struct nouveau_object *object)
-{
- struct nv04_bus_priv *priv = (void *)object;
-
- nv_wr32(priv, 0x001100, 0xffffffff);
- nv_wr32(priv, 0x001140, 0x00000111);
-
- return nouveau_bus_init(&priv->base);
-}
-
-int
-nv04_bus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_bus_impl *impl = (void *)oclass;
- struct nv04_bus_priv *priv;
- int ret;
-
- ret = nouveau_bus_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->intr = impl->intr;
- priv->base.hwsq_exec = impl->hwsq_exec;
- priv->base.hwsq_size = impl->hwsq_size;
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_bus_oclass = &(struct nv04_bus_impl) {
- .base.handle = NV_SUBDEV(BUS, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_bus_ctor,
- .dtor = _nouveau_bus_dtor,
- .init = nv04_bus_init,
- .fini = _nouveau_bus_fini,
- },
- .intr = nv04_bus_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h
deleted file mode 100644
index 4d7602450a20..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv04.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVKM_BUS_NV04_H__
-#define __NVKM_BUS_NV04_H__
-
-#include <subdev/bus.h>
-
-struct nv04_bus_priv {
- struct nouveau_bus base;
-};
-
-int nv04_bus_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-int nv50_bus_init(struct nouveau_object *);
-void nv50_bus_intr(struct nouveau_subdev *);
-
-struct nv04_bus_impl {
- struct nouveau_oclass base;
- void (*intr)(struct nouveau_subdev *);
- int (*hwsq_exec)(struct nouveau_bus *, u32 *, u32);
- u32 hwsq_size;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
deleted file mode 100644
index 94da46f61627..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv31.c
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- * Ben Skeggs
- */
-
-#include "nv04.h"
-
-static void
-nv31_bus_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_bus *pbus = nouveau_bus(subdev);
- u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
- u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144);
-
- if (gpio) {
- subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_GPIO);
- if (subdev && subdev->intr)
- subdev->intr(subdev);
- }
-
- if (stat & 0x00000008) { /* NV41- */
- u32 addr = nv_rd32(pbus, 0x009084);
- u32 data = nv_rd32(pbus, 0x009088);
-
- nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
- (addr & 0x00000002) ? "write" : "read", data,
- (addr & 0x00fffffc));
-
- stat &= ~0x00000008;
- nv_wr32(pbus, 0x001100, 0x00000008);
- }
-
- if (stat & 0x00070000) {
- subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM);
- if (subdev && subdev->intr)
- subdev->intr(subdev);
- stat &= ~0x00070000;
- nv_wr32(pbus, 0x001100, 0x00070000);
- }
-
- if (stat) {
- nv_error(pbus, "unknown intr 0x%08x\n", stat);
- nv_mask(pbus, 0x001140, stat, 0x00000000);
- }
-}
-
-static int
-nv31_bus_init(struct nouveau_object *object)
-{
- struct nv04_bus_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_bus_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x001100, 0xffffffff);
- nv_wr32(priv, 0x001140, 0x00070008);
- return 0;
-}
-
-struct nouveau_oclass *
-nv31_bus_oclass = &(struct nv04_bus_impl) {
- .base.handle = NV_SUBDEV(BUS, 0x31),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_bus_ctor,
- .dtor = _nouveau_bus_dtor,
- .init = nv31_bus_init,
- .fini = _nouveau_bus_fini,
- },
- .intr = nv31_bus_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
deleted file mode 100644
index 11918f7e2aca..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv50.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- * Ben Skeggs
- */
-
-#include <subdev/timer.h>
-
-#include "nv04.h"
-
-static int
-nv50_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size)
-{
- struct nv50_bus_priv *priv = (void *)pbus;
- int i;
-
- nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
- nv_wr32(pbus, 0x001304, 0x00000000);
- for (i = 0; i < size; i++)
- nv_wr32(priv, 0x001400 + (i * 4), data[i]);
- nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
- nv_wr32(pbus, 0x00130c, 0x00000003);
-
- return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
-}
-
-void
-nv50_bus_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_bus *pbus = nouveau_bus(subdev);
- u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-
- if (stat & 0x00000008) {
- u32 addr = nv_rd32(pbus, 0x009084);
- u32 data = nv_rd32(pbus, 0x009088);
-
- nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
- (addr & 0x00000002) ? "write" : "read", data,
- (addr & 0x00fffffc));
-
- stat &= ~0x00000008;
- nv_wr32(pbus, 0x001100, 0x00000008);
- }
-
- if (stat & 0x00010000) {
- subdev = nouveau_subdev(pbus, NVDEV_SUBDEV_THERM);
- if (subdev && subdev->intr)
- subdev->intr(subdev);
- stat &= ~0x00010000;
- nv_wr32(pbus, 0x001100, 0x00010000);
- }
-
- if (stat) {
- nv_error(pbus, "unknown intr 0x%08x\n", stat);
- nv_mask(pbus, 0x001140, stat, 0);
- }
-}
-
-int
-nv50_bus_init(struct nouveau_object *object)
-{
- struct nv04_bus_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_bus_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x001100, 0xffffffff);
- nv_wr32(priv, 0x001140, 0x00010008);
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_bus_oclass = &(struct nv04_bus_impl) {
- .base.handle = NV_SUBDEV(BUS, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_bus_ctor,
- .dtor = _nouveau_bus_dtor,
- .init = nv50_bus_init,
- .fini = _nouveau_bus_fini,
- },
- .intr = nv50_bus_intr,
- .hwsq_exec = nv50_bus_hwsq_exec,
- .hwsq_size = 64,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c
deleted file mode 100644
index d3659055fa4b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nv94.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- * Ben Skeggs
- */
-
-#include <subdev/timer.h>
-
-#include "nv04.h"
-
-static int
-nv94_bus_hwsq_exec(struct nouveau_bus *pbus, u32 *data, u32 size)
-{
- struct nv50_bus_priv *priv = (void *)pbus;
- int i;
-
- nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
- nv_wr32(pbus, 0x001304, 0x00000000);
- nv_wr32(pbus, 0x001318, 0x00000000);
- for (i = 0; i < size; i++)
- nv_wr32(priv, 0x080000 + (i * 4), data[i]);
- nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
- nv_wr32(pbus, 0x00130c, 0x00000001);
-
- return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
-}
-
-struct nouveau_oclass *
-nv94_bus_oclass = &(struct nv04_bus_impl) {
- .base.handle = NV_SUBDEV(BUS, 0x94),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_bus_ctor,
- .dtor = _nouveau_bus_dtor,
- .init = nv50_bus_init,
- .fini = _nouveau_bus_fini,
- },
- .intr = nv50_bus_intr,
- .hwsq_exec = nv94_bus_hwsq_exec,
- .hwsq_size = 128,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
deleted file mode 100644
index 73839d7151a7..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/bus/nvc0.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2012 Nouveau Community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres <martin.peres@labri.fr>
- * Ben Skeggs
- */
-
-#include "nv04.h"
-
-static void
-nvc0_bus_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_bus *pbus = nouveau_bus(subdev);
- u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
-
- if (stat & 0x0000000e) {
- u32 addr = nv_rd32(pbus, 0x009084);
- u32 data = nv_rd32(pbus, 0x009088);
-
- nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n",
- (addr & 0x00000002) ? "write" : "read", data,
- (addr & 0x00fffffc),
- (stat & 0x00000002) ? "!ENGINE " : "",
- (stat & 0x00000004) ? "IBUS " : "",
- (stat & 0x00000008) ? "TIMEOUT " : "");
-
- nv_wr32(pbus, 0x009084, 0x00000000);
- nv_wr32(pbus, 0x001100, (stat & 0x0000000e));
- stat &= ~0x0000000e;
- }
-
- if (stat) {
- nv_error(pbus, "unknown intr 0x%08x\n", stat);
- nv_mask(pbus, 0x001140, stat, 0x00000000);
- }
-}
-
-static int
-nvc0_bus_init(struct nouveau_object *object)
-{
- struct nv04_bus_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_bus_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x001100, 0xffffffff);
- nv_wr32(priv, 0x001140, 0x0000000e);
- return 0;
-}
-
-struct nouveau_oclass *
-nvc0_bus_oclass = &(struct nv04_bus_impl) {
- .base.handle = NV_SUBDEV(BUS, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_bus_ctor,
- .dtor = _nouveau_bus_dtor,
- .init = nvc0_bus_init,
- .fini = _nouveau_bus_fini,
- },
- .intr = nvc0_bus_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c b/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
deleted file mode 100644
index e51b72d47129..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/base.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-
-#include <subdev/clock.h>
-#include <subdev/therm.h>
-#include <subdev/volt.h>
-#include <subdev/fb.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/boost.h>
-#include <subdev/bios/cstep.h>
-#include <subdev/bios/perf.h>
-
-/******************************************************************************
- * misc
- *****************************************************************************/
-static u32
-nouveau_clock_adjust(struct nouveau_clock *clk, bool adjust,
- u8 pstate, u8 domain, u32 input)
-{
- struct nouveau_bios *bios = nouveau_bios(clk);
- struct nvbios_boostE boostE;
- u8 ver, hdr, cnt, len;
- u16 data;
-
- data = nvbios_boostEm(bios, pstate, &ver, &hdr, &cnt, &len, &boostE);
- if (data) {
- struct nvbios_boostS boostS;
- u8 idx = 0, sver, shdr;
- u16 subd;
-
- input = max(boostE.min, input);
- input = min(boostE.max, input);
- do {
- sver = ver;
- shdr = hdr;
- subd = nvbios_boostSp(bios, idx++, data, &sver, &shdr,
- cnt, len, &boostS);
- if (subd && boostS.domain == domain) {
- if (adjust)
- input = input * boostS.percent / 100;
- input = max(boostS.min, input);
- input = min(boostS.max, input);
- break;
- }
- } while (subd);
- }
-
- return input;
-}
-
-/******************************************************************************
- * C-States
- *****************************************************************************/
-static int
-nouveau_cstate_prog(struct nouveau_clock *clk,
- struct nouveau_pstate *pstate, int cstatei)
-{
- struct nouveau_therm *ptherm = nouveau_therm(clk);
- struct nouveau_volt *volt = nouveau_volt(clk);
- struct nouveau_cstate *cstate;
- int ret;
-
- if (!list_empty(&pstate->list)) {
- cstate = list_entry(pstate->list.prev, typeof(*cstate), head);
- } else {
- cstate = &pstate->base;
- }
-
- if (ptherm) {
- ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, +1);
- if (ret && ret != -ENODEV) {
- nv_error(clk, "failed to raise fan speed: %d\n", ret);
- return ret;
- }
- }
-
- if (volt) {
- ret = volt->set_id(volt, cstate->voltage, +1);
- if (ret && ret != -ENODEV) {
- nv_error(clk, "failed to raise voltage: %d\n", ret);
- return ret;
- }
- }
-
- ret = clk->calc(clk, cstate);
- if (ret == 0) {
- ret = clk->prog(clk);
- clk->tidy(clk);
- }
-
- if (volt) {
- ret = volt->set_id(volt, cstate->voltage, -1);
- if (ret && ret != -ENODEV)
- nv_error(clk, "failed to lower voltage: %d\n", ret);
- }
-
- if (ptherm) {
- ret = nouveau_therm_cstate(ptherm, pstate->fanspeed, -1);
- if (ret && ret != -ENODEV)
- nv_error(clk, "failed to lower fan speed: %d\n", ret);
- }
-
- return 0;
-}
-
-static void
-nouveau_cstate_del(struct nouveau_cstate *cstate)
-{
- list_del(&cstate->head);
- kfree(cstate);
-}
-
-static int
-nouveau_cstate_new(struct nouveau_clock *clk, int idx,
- struct nouveau_pstate *pstate)
-{
- struct nouveau_bios *bios = nouveau_bios(clk);
- struct nouveau_clocks *domain = clk->domains;
- struct nouveau_cstate *cstate = NULL;
- struct nvbios_cstepX cstepX;
- u8 ver, hdr;
- u16 data;
-
- data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX);
- if (!data)
- return -ENOENT;
-
- cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
- if (!cstate)
- return -ENOMEM;
-
- *cstate = pstate->base;
- cstate->voltage = cstepX.voltage;
-
- while (domain && domain->name != nv_clk_src_max) {
- if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
- u32 freq = nouveau_clock_adjust(clk, true,
- pstate->pstate,
- domain->bios,
- cstepX.freq);
- cstate->domain[domain->name] = freq;
- }
- domain++;
- }
-
- list_add(&cstate->head, &pstate->list);
- return 0;
-}
-
-/******************************************************************************
- * P-States
- *****************************************************************************/
-static int
-nouveau_pstate_prog(struct nouveau_clock *clk, int pstatei)
-{
- struct nouveau_fb *pfb = nouveau_fb(clk);
- struct nouveau_pstate *pstate;
- int ret, idx = 0;
-
- list_for_each_entry(pstate, &clk->states, head) {
- if (idx++ == pstatei)
- break;
- }
-
- nv_debug(clk, "setting performance state %d\n", pstatei);
- clk->pstate = pstatei;
-
- if (pfb->ram->calc) {
- int khz = pstate->base.domain[nv_clk_src_mem];
- do {
- ret = pfb->ram->calc(pfb, khz);
- if (ret == 0)
- ret = pfb->ram->prog(pfb);
- } while (ret > 0);
- pfb->ram->tidy(pfb);
- }
-
- return nouveau_cstate_prog(clk, pstate, 0);
-}
-
-static void
-nouveau_pstate_work(struct work_struct *work)
-{
- struct nouveau_clock *clk = container_of(work, typeof(*clk), work);
- int pstate;
-
- if (!atomic_xchg(&clk->waiting, 0))
- return;
- clk->pwrsrc = power_supply_is_system_supplied();
-
- nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
- clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
- clk->astate, clk->tstate, clk->dstate);
-
- pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
- if (clk->state_nr && pstate != -1) {
- pstate = (pstate < 0) ? clk->astate : pstate;
- pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
- pstate = max(pstate, clk->dstate);
- } else {
- pstate = clk->pstate = -1;
- }
-
- nv_trace(clk, "-> %d\n", pstate);
- if (pstate != clk->pstate) {
- int ret = nouveau_pstate_prog(clk, pstate);
- if (ret) {
- nv_error(clk, "error setting pstate %d: %d\n",
- pstate, ret);
- }
- }
-
- wake_up_all(&clk->wait);
- nvkm_notify_get(&clk->pwrsrc_ntfy);
-}
-
-static int
-nouveau_pstate_calc(struct nouveau_clock *clk, bool wait)
-{
- atomic_set(&clk->waiting, 1);
- schedule_work(&clk->work);
- if (wait)
- wait_event(clk->wait, !atomic_read(&clk->waiting));
- return 0;
-}
-
-static void
-nouveau_pstate_info(struct nouveau_clock *clk, struct nouveau_pstate *pstate)
-{
- struct nouveau_clocks *clock = clk->domains - 1;
- struct nouveau_cstate *cstate;
- char info[3][32] = { "", "", "" };
- char name[4] = "--";
- int i = -1;
-
- if (pstate->pstate != 0xff)
- snprintf(name, sizeof(name), "%02x", pstate->pstate);
-
- while ((++clock)->name != nv_clk_src_max) {
- u32 lo = pstate->base.domain[clock->name];
- u32 hi = lo;
- if (hi == 0)
- continue;
-
- nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo);
- list_for_each_entry(cstate, &pstate->list, head) {
- u32 freq = cstate->domain[clock->name];
- lo = min(lo, freq);
- hi = max(hi, freq);
- nv_debug(clk, "%10d KHz\n", freq);
- }
-
- if (clock->mname && ++i < ARRAY_SIZE(info)) {
- lo /= clock->mdiv;
- hi /= clock->mdiv;
- if (lo == hi) {
- snprintf(info[i], sizeof(info[i]), "%s %d MHz",
- clock->mname, lo);
- } else {
- snprintf(info[i], sizeof(info[i]),
- "%s %d-%d MHz", clock->mname, lo, hi);
- }
- }
- }
-
- nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]);
-}
-
-static void
-nouveau_pstate_del(struct nouveau_pstate *pstate)
-{
- struct nouveau_cstate *cstate, *temp;
-
- list_for_each_entry_safe(cstate, temp, &pstate->list, head) {
- nouveau_cstate_del(cstate);
- }
-
- list_del(&pstate->head);
- kfree(pstate);
-}
-
-static int
-nouveau_pstate_new(struct nouveau_clock *clk, int idx)
-{
- struct nouveau_bios *bios = nouveau_bios(clk);
- struct nouveau_clocks *domain = clk->domains - 1;
- struct nouveau_pstate *pstate;
- struct nouveau_cstate *cstate;
- struct nvbios_cstepE cstepE;
- struct nvbios_perfE perfE;
- u8 ver, hdr, cnt, len;
- u16 data;
-
- data = nvbios_perfEp(bios, idx, &ver, &hdr, &cnt, &len, &perfE);
- if (!data)
- return -EINVAL;
- if (perfE.pstate == 0xff)
- return 0;
-
- pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
- cstate = &pstate->base;
- if (!pstate)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&pstate->list);
-
- pstate->pstate = perfE.pstate;
- pstate->fanspeed = perfE.fanspeed;
- cstate->voltage = perfE.voltage;
- cstate->domain[nv_clk_src_core] = perfE.core;
- cstate->domain[nv_clk_src_shader] = perfE.shader;
- cstate->domain[nv_clk_src_mem] = perfE.memory;
- cstate->domain[nv_clk_src_vdec] = perfE.vdec;
- cstate->domain[nv_clk_src_dom6] = perfE.disp;
-
- while (ver >= 0x40 && (++domain)->name != nv_clk_src_max) {
- struct nvbios_perfS perfS;
- u8 sver = ver, shdr = hdr;
- u32 perfSe = nvbios_perfSp(bios, data, domain->bios,
- &sver, &shdr, cnt, len, &perfS);
- if (perfSe == 0 || sver != 0x40)
- continue;
-
- if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
- perfS.v40.freq = nouveau_clock_adjust(clk, false,
- pstate->pstate,
- domain->bios,
- perfS.v40.freq);
- }
-
- cstate->domain[domain->name] = perfS.v40.freq;
- }
-
- data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE);
- if (data) {
- int idx = cstepE.index;
- do {
- nouveau_cstate_new(clk, idx, pstate);
- } while(idx--);
- }
-
- nouveau_pstate_info(clk, pstate);
- list_add_tail(&pstate->head, &clk->states);
- clk->state_nr++;
- return 0;
-}
-
-/******************************************************************************
- * Adjustment triggers
- *****************************************************************************/
-static int
-nouveau_clock_ustate_update(struct nouveau_clock *clk, int req)
-{
- struct nouveau_pstate *pstate;
- int i = 0;
-
- if (!clk->allow_reclock)
- return -ENOSYS;
-
- if (req != -1 && req != -2) {
- list_for_each_entry(pstate, &clk->states, head) {
- if (pstate->pstate == req)
- break;
- i++;
- }
-
- if (pstate->pstate != req)
- return -EINVAL;
- req = i;
- }
-
- return req + 2;
-}
-
-static int
-nouveau_clock_nstate(struct nouveau_clock *clk, const char *mode, int arglen)
-{
- int ret = 1;
-
- if (strncasecmpz(mode, "disabled", arglen)) {
- char save = mode[arglen];
- long v;
-
- ((char *)mode)[arglen] = '\0';
- if (!kstrtol(mode, 0, &v)) {
- ret = nouveau_clock_ustate_update(clk, v);
- if (ret < 0)
- ret = 1;
- }
- ((char *)mode)[arglen] = save;
- }
-
- return ret - 2;
-}
-
-int
-nouveau_clock_ustate(struct nouveau_clock *clk, int req, int pwr)
-{
- int ret = nouveau_clock_ustate_update(clk, req);
- if (ret >= 0) {
- if (ret -= 2, pwr) clk->ustate_ac = ret;
- else clk->ustate_dc = ret;
- return nouveau_pstate_calc(clk, true);
- }
- return ret;
-}
-
-int
-nouveau_clock_astate(struct nouveau_clock *clk, int req, int rel)
-{
- if (!rel) clk->astate = req;
- if ( rel) clk->astate += rel;
- clk->astate = min(clk->astate, clk->state_nr - 1);
- clk->astate = max(clk->astate, 0);
- return nouveau_pstate_calc(clk, true);
-}
-
-int
-nouveau_clock_tstate(struct nouveau_clock *clk, int req, int rel)
-{
- if (!rel) clk->tstate = req;
- if ( rel) clk->tstate += rel;
- clk->tstate = min(clk->tstate, 0);
- clk->tstate = max(clk->tstate, -(clk->state_nr - 1));
- return nouveau_pstate_calc(clk, true);
-}
-
-int
-nouveau_clock_dstate(struct nouveau_clock *clk, int req, int rel)
-{
- if (!rel) clk->dstate = req;
- if ( rel) clk->dstate += rel;
- clk->dstate = min(clk->dstate, clk->state_nr - 1);
- clk->dstate = max(clk->dstate, 0);
- return nouveau_pstate_calc(clk, true);
-}
-
-static int
-nouveau_clock_pwrsrc(struct nvkm_notify *notify)
-{
- struct nouveau_clock *clk =
- container_of(notify, typeof(*clk), pwrsrc_ntfy);
- nouveau_pstate_calc(clk, false);
- return NVKM_NOTIFY_DROP;
-}
-
-/******************************************************************************
- * subdev base class implementation
- *****************************************************************************/
-
-int
-_nouveau_clock_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_clock *clk = (void *)object;
- nvkm_notify_put(&clk->pwrsrc_ntfy);
- return nouveau_subdev_fini(&clk->base, suspend);
-}
-
-int
-_nouveau_clock_init(struct nouveau_object *object)
-{
- struct nouveau_clock *clk = (void *)object;
- struct nouveau_clocks *clock = clk->domains;
- int ret;
-
- ret = nouveau_subdev_init(&clk->base);
- if (ret)
- return ret;
-
- memset(&clk->bstate, 0x00, sizeof(clk->bstate));
- INIT_LIST_HEAD(&clk->bstate.list);
- clk->bstate.pstate = 0xff;
-
- while (clock->name != nv_clk_src_max) {
- ret = clk->read(clk, clock->name);
- if (ret < 0) {
- nv_error(clk, "%02x freq unknown\n", clock->name);
- return ret;
- }
- clk->bstate.base.domain[clock->name] = ret;
- clock++;
- }
-
- nouveau_pstate_info(clk, &clk->bstate);
-
- clk->astate = clk->state_nr - 1;
- clk->tstate = 0;
- clk->dstate = 0;
- clk->pstate = -1;
- nouveau_pstate_calc(clk, true);
- return 0;
-}
-
-void
-_nouveau_clock_dtor(struct nouveau_object *object)
-{
- struct nouveau_clock *clk = (void *)object;
- struct nouveau_pstate *pstate, *temp;
-
- nvkm_notify_fini(&clk->pwrsrc_ntfy);
-
- list_for_each_entry_safe(pstate, temp, &clk->states, head) {
- nouveau_pstate_del(pstate);
- }
-
- nouveau_subdev_destroy(&clk->base);
-}
-
-int
-nouveau_clock_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- struct nouveau_clocks *clocks,
- struct nouveau_pstate *pstates, int nb_pstates,
- bool allow_reclock,
- int length, void **object)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_clock *clk;
- int ret, idx, arglen;
- const char *mode;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "CLK",
- "clock", length, object);
- clk = *object;
- if (ret)
- return ret;
-
- INIT_LIST_HEAD(&clk->states);
- clk->domains = clocks;
- clk->ustate_ac = -1;
- clk->ustate_dc = -1;
-
- INIT_WORK(&clk->work, nouveau_pstate_work);
- init_waitqueue_head(&clk->wait);
- atomic_set(&clk->waiting, 0);
-
- /* If no pstates are provided, try and fetch them from the BIOS */
- if (!pstates) {
- idx = 0;
- do {
- ret = nouveau_pstate_new(clk, idx++);
- } while (ret == 0);
- } else {
- for (idx = 0; idx < nb_pstates; idx++)
- list_add_tail(&pstates[idx].head, &clk->states);
- clk->state_nr = nb_pstates;
- }
-
- clk->allow_reclock = allow_reclock;
-
- ret = nvkm_notify_init(NULL, &device->event, nouveau_clock_pwrsrc, true,
- NULL, 0, 0, &clk->pwrsrc_ntfy);
- if (ret)
- return ret;
-
- mode = nouveau_stropt(device->cfgopt, "NvClkMode", &arglen);
- if (mode) {
- clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
- clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
- }
-
- mode = nouveau_stropt(device->cfgopt, "NvClkModeAC", &arglen);
- if (mode)
- clk->ustate_ac = nouveau_clock_nstate(clk, mode, arglen);
-
- mode = nouveau_stropt(device->cfgopt, "NvClkModeDC", &arglen);
- if (mode)
- clk->ustate_dc = nouveau_clock_nstate(clk, mode, arglen);
-
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c
deleted file mode 100644
index fb4fad374bdd..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/gk20a.c
+++ /dev/null
@@ -1,680 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
- *
- * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c
- *
- */
-
-#define MHZ (1000 * 1000)
-
-#define MASK(w) ((1 << w) - 1)
-
-#define SYS_GPCPLL_CFG_BASE 0x00137000
-#define GPC_BCASE_GPCPLL_CFG_BASE 0x00132800
-
-#define GPCPLL_CFG (SYS_GPCPLL_CFG_BASE + 0)
-#define GPCPLL_CFG_ENABLE BIT(0)
-#define GPCPLL_CFG_IDDQ BIT(1)
-#define GPCPLL_CFG_LOCK_DET_OFF BIT(4)
-#define GPCPLL_CFG_LOCK BIT(17)
-
-#define GPCPLL_COEFF (SYS_GPCPLL_CFG_BASE + 4)
-#define GPCPLL_COEFF_M_SHIFT 0
-#define GPCPLL_COEFF_M_WIDTH 8
-#define GPCPLL_COEFF_N_SHIFT 8
-#define GPCPLL_COEFF_N_WIDTH 8
-#define GPCPLL_COEFF_P_SHIFT 16
-#define GPCPLL_COEFF_P_WIDTH 6
-
-#define GPCPLL_CFG2 (SYS_GPCPLL_CFG_BASE + 0xc)
-#define GPCPLL_CFG2_SETUP2_SHIFT 16
-#define GPCPLL_CFG2_PLL_STEPA_SHIFT 24
-
-#define GPCPLL_CFG3 (SYS_GPCPLL_CFG_BASE + 0x18)
-#define GPCPLL_CFG3_PLL_STEPB_SHIFT 16
-
-#define GPCPLL_NDIV_SLOWDOWN (SYS_GPCPLL_CFG_BASE + 0x1c)
-#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT 0
-#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT 8
-#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT 16
-#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT 22
-#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT 31
-
-#define SEL_VCO (SYS_GPCPLL_CFG_BASE + 0x100)
-#define SEL_VCO_GPC2CLK_OUT_SHIFT 0
-
-#define GPC2CLK_OUT (SYS_GPCPLL_CFG_BASE + 0x250)
-#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH 1
-#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT 31
-#define GPC2CLK_OUT_SDIV14_INDIV4_MODE 1
-#define GPC2CLK_OUT_VCODIV_WIDTH 6
-#define GPC2CLK_OUT_VCODIV_SHIFT 8
-#define GPC2CLK_OUT_VCODIV1 0
-#define GPC2CLK_OUT_VCODIV_MASK (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \
- GPC2CLK_OUT_VCODIV_SHIFT)
-#define GPC2CLK_OUT_BYPDIV_WIDTH 6
-#define GPC2CLK_OUT_BYPDIV_SHIFT 0
-#define GPC2CLK_OUT_BYPDIV31 0x3c
-#define GPC2CLK_OUT_INIT_MASK ((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \
- GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\
- | (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\
- | (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT))
-#define GPC2CLK_OUT_INIT_VAL ((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \
- GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \
- | (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \
- | (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT))
-
-#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG (GPC_BCASE_GPCPLL_CFG_BASE + 0xa0)
-#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT 24
-#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \
- (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT)
-
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-
-#ifdef __KERNEL__
-#include <nouveau_platform.h>
-#endif
-
-static const u8 pl_to_div[] = {
-/* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */
-/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32,
-};
-
-/* All frequencies in Mhz */
-struct gk20a_clk_pllg_params {
- u32 min_vco, max_vco;
- u32 min_u, max_u;
- u32 min_m, max_m;
- u32 min_n, max_n;
- u32 min_pl, max_pl;
-};
-
-static const struct gk20a_clk_pllg_params gk20a_pllg_params = {
- .min_vco = 1000, .max_vco = 2064,
- .min_u = 12, .max_u = 38,
- .min_m = 1, .max_m = 255,
- .min_n = 8, .max_n = 255,
- .min_pl = 1, .max_pl = 32,
-};
-
-struct gk20a_clock_priv {
- struct nouveau_clock base;
- const struct gk20a_clk_pllg_params *params;
- u32 m, n, pl;
- u32 parent_rate;
-};
-#define to_gk20a_clock(base) container_of(base, struct gk20a_clock_priv, base)
-
-static void
-gk20a_pllg_read_mnp(struct gk20a_clock_priv *priv)
-{
- u32 val;
-
- val = nv_rd32(priv, GPCPLL_COEFF);
- priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
- priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH);
- priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
-}
-
-static u32
-gk20a_pllg_calc_rate(struct gk20a_clock_priv *priv)
-{
- u32 rate;
- u32 divider;
-
- rate = priv->parent_rate * priv->n;
- divider = priv->m * pl_to_div[priv->pl];
- do_div(rate, divider);
-
- return rate / 2;
-}
-
-static int
-gk20a_pllg_calc_mnp(struct gk20a_clock_priv *priv, unsigned long rate)
-{
- u32 target_clk_f, ref_clk_f, target_freq;
- u32 min_vco_f, max_vco_f;
- u32 low_pl, high_pl, best_pl;
- u32 target_vco_f, vco_f;
- u32 best_m, best_n;
- u32 u_f;
- u32 m, n, n2;
- u32 delta, lwv, best_delta = ~0;
- u32 pl;
-
- target_clk_f = rate * 2 / MHZ;
- ref_clk_f = priv->parent_rate / MHZ;
-
- max_vco_f = priv->params->max_vco;
- min_vco_f = priv->params->min_vco;
- best_m = priv->params->max_m;
- best_n = priv->params->min_n;
- best_pl = priv->params->min_pl;
-
- target_vco_f = target_clk_f + target_clk_f / 50;
- if (max_vco_f < target_vco_f)
- max_vco_f = target_vco_f;
-
- /* min_pl <= high_pl <= max_pl */
- high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f;
- high_pl = min(high_pl, priv->params->max_pl);
- high_pl = max(high_pl, priv->params->min_pl);
-
- /* min_pl <= low_pl <= max_pl */
- low_pl = min_vco_f / target_vco_f;
- low_pl = min(low_pl, priv->params->max_pl);
- low_pl = max(low_pl, priv->params->min_pl);
-
- /* Find Indices of high_pl and low_pl */
- for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
- if (pl_to_div[pl] >= low_pl) {
- low_pl = pl;
- break;
- }
- }
- for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
- if (pl_to_div[pl] >= high_pl) {
- high_pl = pl;
- break;
- }
- }
-
- nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl,
- pl_to_div[low_pl], high_pl, pl_to_div[high_pl]);
-
- /* Select lowest possible VCO */
- for (pl = low_pl; pl <= high_pl; pl++) {
- target_vco_f = target_clk_f * pl_to_div[pl];
- for (m = priv->params->min_m; m <= priv->params->max_m; m++) {
- u_f = ref_clk_f / m;
-
- if (u_f < priv->params->min_u)
- break;
- if (u_f > priv->params->max_u)
- continue;
-
- n = (target_vco_f * m) / ref_clk_f;
- n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f;
-
- if (n > priv->params->max_n)
- break;
-
- for (; n <= n2; n++) {
- if (n < priv->params->min_n)
- continue;
- if (n > priv->params->max_n)
- break;
-
- vco_f = ref_clk_f * n / m;
-
- if (vco_f >= min_vco_f && vco_f <= max_vco_f) {
- lwv = (vco_f + (pl_to_div[pl] / 2))
- / pl_to_div[pl];
- delta = abs(lwv - target_clk_f);
-
- if (delta < best_delta) {
- best_delta = delta;
- best_m = m;
- best_n = n;
- best_pl = pl;
-
- if (best_delta == 0)
- goto found_match;
- }
- }
- }
- }
- }
-
-found_match:
- WARN_ON(best_delta == ~0);
-
- if (best_delta != 0)
- nv_debug(priv, "no best match for target @ %dMHz on gpc_pll",
- target_clk_f);
-
- priv->m = best_m;
- priv->n = best_n;
- priv->pl = best_pl;
-
- target_freq = gk20a_pllg_calc_rate(priv) / MHZ;
-
- nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n",
- target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]);
-
- return 0;
-}
-
-static int
-gk20a_pllg_slide(struct gk20a_clock_priv *priv, u32 n)
-{
- u32 val;
- int ramp_timeout;
-
- /* get old coefficients */
- val = nv_rd32(priv, GPCPLL_COEFF);
- /* do nothing if NDIV is the same */
- if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH)))
- return 0;
-
- /* setup */
- nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT,
- 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT);
- nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT,
- 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT);
-
- /* pll slowdown mode */
- nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
- BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT),
- BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT));
-
- /* new ndiv ready for ramp */
- val = nv_rd32(priv, GPCPLL_COEFF);
- val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT);
- val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT;
- udelay(1);
- nv_wr32(priv, GPCPLL_COEFF, val);
-
- /* dynamic ramp to new ndiv */
- val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
- val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT;
- udelay(1);
- nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val);
-
- for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) {
- udelay(1);
- val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG);
- if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK)
- break;
- }
-
- /* exit slowdown mode */
- nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
- BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) |
- BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0);
- nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
-
- if (ramp_timeout <= 0) {
- nv_error(priv, "gpcpll dynamic ramp timeout\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-static void
-_gk20a_pllg_enable(struct gk20a_clock_priv *priv)
-{
- nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE);
- nv_rd32(priv, GPCPLL_CFG);
-}
-
-static void
-_gk20a_pllg_disable(struct gk20a_clock_priv *priv)
-{
- nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0);
- nv_rd32(priv, GPCPLL_CFG);
-}
-
-static int
-_gk20a_pllg_program_mnp(struct gk20a_clock_priv *priv, bool allow_slide)
-{
- u32 val, cfg;
- u32 m_old, pl_old, n_lo;
-
- /* get old coefficients */
- val = nv_rd32(priv, GPCPLL_COEFF);
- m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
- pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
-
- /* do NDIV slide if there is no change in M and PL */
- cfg = nv_rd32(priv, GPCPLL_CFG);
- if (allow_slide && priv->m == m_old && priv->pl == pl_old &&
- (cfg & GPCPLL_CFG_ENABLE)) {
- return gk20a_pllg_slide(priv, priv->n);
- }
-
- /* slide down to NDIV_LO */
- n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco,
- priv->parent_rate / MHZ);
- if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) {
- int ret = gk20a_pllg_slide(priv, n_lo);
-
- if (ret)
- return ret;
- }
-
- /* split FO-to-bypass jump in halfs by setting out divider 1:2 */
- nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK,
- 0x2 << GPC2CLK_OUT_VCODIV_SHIFT);
-
- /* put PLL in bypass before programming it */
- val = nv_rd32(priv, SEL_VCO);
- val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
- udelay(2);
- nv_wr32(priv, SEL_VCO, val);
-
- /* get out from IDDQ */
- val = nv_rd32(priv, GPCPLL_CFG);
- if (val & GPCPLL_CFG_IDDQ) {
- val &= ~GPCPLL_CFG_IDDQ;
- nv_wr32(priv, GPCPLL_CFG, val);
- nv_rd32(priv, GPCPLL_CFG);
- udelay(2);
- }
-
- _gk20a_pllg_disable(priv);
-
- nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n,
- priv->pl);
-
- n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco,
- priv->parent_rate / MHZ);
- val = priv->m << GPCPLL_COEFF_M_SHIFT;
- val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT;
- val |= priv->pl << GPCPLL_COEFF_P_SHIFT;
- nv_wr32(priv, GPCPLL_COEFF, val);
-
- _gk20a_pllg_enable(priv);
-
- val = nv_rd32(priv, GPCPLL_CFG);
- if (val & GPCPLL_CFG_LOCK_DET_OFF) {
- val &= ~GPCPLL_CFG_LOCK_DET_OFF;
- nv_wr32(priv, GPCPLL_CFG, val);
- }
-
- if (!nouveau_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK,
- GPCPLL_CFG_LOCK)) {
- nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__);
- return -ETIMEDOUT;
- }
-
- /* switch to VCO mode */
- nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
-
- /* restore out divider 1:1 */
- val = nv_rd32(priv, GPC2CLK_OUT);
- val &= ~GPC2CLK_OUT_VCODIV_MASK;
- udelay(2);
- nv_wr32(priv, GPC2CLK_OUT, val);
-
- /* slide up to new NDIV */
- return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0;
-}
-
-static int
-gk20a_pllg_program_mnp(struct gk20a_clock_priv *priv)
-{
- int err;
-
- err = _gk20a_pllg_program_mnp(priv, true);
- if (err)
- err = _gk20a_pllg_program_mnp(priv, false);
-
- return err;
-}
-
-static void
-gk20a_pllg_disable(struct gk20a_clock_priv *priv)
-{
- u32 val;
-
- /* slide to VCO min */
- val = nv_rd32(priv, GPCPLL_CFG);
- if (val & GPCPLL_CFG_ENABLE) {
- u32 coeff, m, n_lo;
-
- coeff = nv_rd32(priv, GPCPLL_COEFF);
- m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
- n_lo = DIV_ROUND_UP(m * priv->params->min_vco,
- priv->parent_rate / MHZ);
- gk20a_pllg_slide(priv, n_lo);
- }
-
- /* put PLL in bypass before disabling it */
- nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0);
-
- _gk20a_pllg_disable(priv);
-}
-
-#define GK20A_CLK_GPC_MDIV 1000
-
-static struct nouveau_clocks
-gk20a_domains[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV },
- { nv_clk_src_max }
-};
-
-static struct nouveau_pstate
-gk20a_pstates[] = {
- {
- .base = {
- .domain[nv_clk_src_gpc] = 72000,
- .voltage = 0,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 108000,
- .voltage = 1,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 180000,
- .voltage = 2,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 252000,
- .voltage = 3,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 324000,
- .voltage = 4,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 396000,
- .voltage = 5,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 468000,
- .voltage = 6,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 540000,
- .voltage = 7,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 612000,
- .voltage = 8,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 648000,
- .voltage = 9,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 684000,
- .voltage = 10,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 708000,
- .voltage = 11,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 756000,
- .voltage = 12,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 804000,
- .voltage = 13,
- },
- },
- {
- .base = {
- .domain[nv_clk_src_gpc] = 852000,
- .voltage = 14,
- },
- },
-};
-
-static int
-gk20a_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct gk20a_clock_priv *priv = (void *)clk;
-
- switch (src) {
- case nv_clk_src_crystal:
- return nv_device(clk)->crystal;
- case nv_clk_src_gpc:
- gk20a_pllg_read_mnp(priv);
- return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV;
- default:
- nv_error(clk, "invalid clock source %d\n", src);
- return -EINVAL;
- }
-}
-
-static int
-gk20a_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct gk20a_clock_priv *priv = (void *)clk;
-
- return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] *
- GK20A_CLK_GPC_MDIV);
-}
-
-static int
-gk20a_clock_prog(struct nouveau_clock *clk)
-{
- struct gk20a_clock_priv *priv = (void *)clk;
-
- return gk20a_pllg_program_mnp(priv);
-}
-
-static void
-gk20a_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static int
-gk20a_clock_fini(struct nouveau_object *object, bool suspend)
-{
- struct gk20a_clock_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_clock_fini(&priv->base, false);
-
- gk20a_pllg_disable(priv);
-
- return ret;
-}
-
-static int
-gk20a_clock_init(struct nouveau_object *object)
-{
- struct gk20a_clock_priv *priv = (void *)object;
- int ret;
-
- nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL);
-
- ret = nouveau_clock_init(&priv->base);
- if (ret)
- return ret;
-
- ret = gk20a_clock_prog(&priv->base);
- if (ret) {
- nv_error(priv, "cannot initialize clock\n");
- return ret;
- }
-
- return 0;
-}
-
-static int
-gk20a_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gk20a_clock_priv *priv;
- struct nouveau_platform_device *plat;
- int ret;
- int i;
-
- /* Finish initializing the pstates */
- for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) {
- INIT_LIST_HEAD(&gk20a_pstates[i].list);
- gk20a_pstates[i].pstate = i + 1;
- }
-
- ret = nouveau_clock_create(parent, engine, oclass, gk20a_domains,
- gk20a_pstates, ARRAY_SIZE(gk20a_pstates), true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->params = &gk20a_pllg_params;
-
- plat = nv_device_to_platform(nv_device(parent));
- priv->parent_rate = clk_get_rate(plat->gpu->clk);
- nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ);
-
- priv->base.read = gk20a_clock_read;
- priv->base.calc = gk20a_clock_calc;
- priv->base.prog = gk20a_clock_prog;
- priv->base.tidy = gk20a_clock_tidy;
-
- return 0;
-}
-
-struct nouveau_oclass
-gk20a_clock_oclass = {
- .handle = NV_SUBDEV(CLOCK, 0xea),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gk20a_clock_ctor,
- .dtor = _nouveau_subdev_dtor,
- .init = gk20a_clock_init,
- .fini = gk20a_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
deleted file mode 100644
index 4c48232686be..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv04.c
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
-#include <subdev/devinit/nv04.h>
-
-#include "pll.h"
-
-struct nv04_clock_priv {
- struct nouveau_clock base;
-};
-
-int
-nv04_clock_pll_calc(struct nouveau_clock *clock, struct nvbios_pll *info,
- int clk, struct nouveau_pll_vals *pv)
-{
- int N1, M1, N2, M2, P;
- int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P);
- if (ret) {
- pv->refclk = info->refclk;
- pv->N1 = N1;
- pv->M1 = M1;
- pv->N2 = N2;
- pv->M2 = M2;
- pv->log2P = P;
- }
- return ret;
-}
-
-int
-nv04_clock_pll_prog(struct nouveau_clock *clk, u32 reg1,
- struct nouveau_pll_vals *pv)
-{
- struct nouveau_devinit *devinit = nouveau_devinit(clk);
- int cv = nouveau_bios(clk)->version.chip;
-
- if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
- cv >= 0x40) {
- if (reg1 > 0x405c)
- setPLL_double_highregs(devinit, reg1, pv);
- else
- setPLL_double_lowregs(devinit, reg1, pv);
- } else
- setPLL_single(devinit, reg1, pv);
-
- return 0;
-}
-
-static struct nouveau_clocks
-nv04_domain[] = {
- { nv_clk_src_max }
-};
-
-static int
-nv04_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, nv04_domain, NULL, 0,
- false, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.pll_calc = nv04_clock_pll_calc;
- priv->base.pll_prog = nv04_clock_pll_prog;
- return 0;
-}
-
-struct nouveau_oclass
-nv04_clock_oclass = {
- .handle = NV_SUBDEV(CLOCK, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
deleted file mode 100644
index 08368fe97029..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv40.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-struct nv40_clock_priv {
- struct nouveau_clock base;
- u32 ctrl;
- u32 npll_ctrl;
- u32 npll_coef;
- u32 spll;
-};
-
-static struct nouveau_clocks
-nv40_domain[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_href , 0xff },
- { nv_clk_src_core , 0xff, 0, "core", 1000 },
- { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
- { nv_clk_src_mem , 0xff, 0, "memory", 1000 },
- { nv_clk_src_max }
-};
-
-static u32
-read_pll_1(struct nv40_clock_priv *priv, u32 reg)
-{
- u32 ctrl = nv_rd32(priv, reg + 0x00);
- int P = (ctrl & 0x00070000) >> 16;
- int N = (ctrl & 0x0000ff00) >> 8;
- int M = (ctrl & 0x000000ff) >> 0;
- u32 ref = 27000, clk = 0;
-
- if (ctrl & 0x80000000)
- clk = ref * N / M;
-
- return clk >> P;
-}
-
-static u32
-read_pll_2(struct nv40_clock_priv *priv, u32 reg)
-{
- u32 ctrl = nv_rd32(priv, reg + 0x00);
- u32 coef = nv_rd32(priv, reg + 0x04);
- int N2 = (coef & 0xff000000) >> 24;
- int M2 = (coef & 0x00ff0000) >> 16;
- int N1 = (coef & 0x0000ff00) >> 8;
- int M1 = (coef & 0x000000ff) >> 0;
- int P = (ctrl & 0x00070000) >> 16;
- u32 ref = 27000, clk = 0;
-
- if ((ctrl & 0x80000000) && M1) {
- clk = ref * N1 / M1;
- if ((ctrl & 0x40000100) == 0x40000000) {
- if (M2)
- clk = clk * N2 / M2;
- else
- clk = 0;
- }
- }
-
- return clk >> P;
-}
-
-static u32
-read_clk(struct nv40_clock_priv *priv, u32 src)
-{
- switch (src) {
- case 3:
- return read_pll_2(priv, 0x004000);
- case 2:
- return read_pll_1(priv, 0x004008);
- default:
- break;
- }
-
- return 0;
-}
-
-static int
-nv40_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct nv40_clock_priv *priv = (void *)clk;
- u32 mast = nv_rd32(priv, 0x00c040);
-
- switch (src) {
- case nv_clk_src_crystal:
- return nv_device(priv)->crystal;
- case nv_clk_src_href:
- return 100000; /*XXX: PCIE/AGP differ*/
- case nv_clk_src_core:
- return read_clk(priv, (mast & 0x00000003) >> 0);
- case nv_clk_src_shader:
- return read_clk(priv, (mast & 0x00000030) >> 4);
- case nv_clk_src_mem:
- return read_pll_2(priv, 0x4020);
- default:
- break;
- }
-
- nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
- return -EINVAL;
-}
-
-static int
-nv40_clock_calc_pll(struct nv40_clock_priv *priv, u32 reg, u32 clk,
- int *N1, int *M1, int *N2, int *M2, int *log2P)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll pll;
- int ret;
-
- ret = nvbios_pll_parse(bios, reg, &pll);
- if (ret)
- return ret;
-
- if (clk < pll.vco1.max_freq)
- pll.vco2.max_freq = 0;
-
- ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P);
- if (ret == 0)
- return -ERANGE;
- return ret;
-}
-
-static int
-nv40_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct nv40_clock_priv *priv = (void *)clk;
- int gclk = cstate->domain[nv_clk_src_core];
- int sclk = cstate->domain[nv_clk_src_shader];
- int N1, M1, N2, M2, log2P;
- int ret;
-
- /* core/geometric clock */
- ret = nv40_clock_calc_pll(priv, 0x004000, gclk,
- &N1, &M1, &N2, &M2, &log2P);
- if (ret < 0)
- return ret;
-
- if (N2 == M2) {
- priv->npll_ctrl = 0x80000100 | (log2P << 16);
- priv->npll_coef = (N1 << 8) | M1;
- } else {
- priv->npll_ctrl = 0xc0000000 | (log2P << 16);
- priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
- }
-
- /* use the second pll for shader/rop clock, if it differs from core */
- if (sclk && sclk != gclk) {
- ret = nv40_clock_calc_pll(priv, 0x004008, sclk,
- &N1, &M1, NULL, NULL, &log2P);
- if (ret < 0)
- return ret;
-
- priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
- priv->ctrl = 0x00000223;
- } else {
- priv->spll = 0x00000000;
- priv->ctrl = 0x00000333;
- }
-
- return 0;
-}
-
-static int
-nv40_clock_prog(struct nouveau_clock *clk)
-{
- struct nv40_clock_priv *priv = (void *)clk;
- nv_mask(priv, 0x00c040, 0x00000333, 0x00000000);
- nv_wr32(priv, 0x004004, priv->npll_coef);
- nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl);
- nv_mask(priv, 0x004008, 0xc007ffff, priv->spll);
- mdelay(5);
- nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl);
- return 0;
-}
-
-static void
-nv40_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static int
-nv40_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv40_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, nv40_domain, NULL, 0,
- true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.pll_calc = nv04_clock_pll_calc;
- priv->base.pll_prog = nv04_clock_pll_prog;
- priv->base.read = nv40_clock_read;
- priv->base.calc = nv40_clock_calc;
- priv->base.prog = nv40_clock_prog;
- priv->base.tidy = nv40_clock_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nv40_clock_oclass = {
- .handle = NV_SUBDEV(CLOCK, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
deleted file mode 100644
index 5070ebc260f8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.c
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "nv50.h"
-#include "pll.h"
-#include "seq.h"
-
-static u32
-read_div(struct nv50_clock_priv *priv)
-{
- switch (nv_device(priv)->chipset) {
- case 0x50: /* it exists, but only has bit 31, not the dividers.. */
- case 0x84:
- case 0x86:
- case 0x98:
- case 0xa0:
- return nv_rd32(priv, 0x004700);
- case 0x92:
- case 0x94:
- case 0x96:
- return nv_rd32(priv, 0x004800);
- default:
- return 0x00000000;
- }
-}
-
-static u32
-read_pll_src(struct nv50_clock_priv *priv, u32 base)
-{
- struct nouveau_clock *clk = &priv->base;
- u32 coef, ref = clk->read(clk, nv_clk_src_crystal);
- u32 rsel = nv_rd32(priv, 0x00e18c);
- int P, N, M, id;
-
- switch (nv_device(priv)->chipset) {
- case 0x50:
- case 0xa0:
- switch (base) {
- case 0x4020:
- case 0x4028: id = !!(rsel & 0x00000004); break;
- case 0x4008: id = !!(rsel & 0x00000008); break;
- case 0x4030: id = 0; break;
- default:
- nv_error(priv, "ref: bad pll 0x%06x\n", base);
- return 0;
- }
-
- coef = nv_rd32(priv, 0x00e81c + (id * 0x0c));
- ref *= (coef & 0x01000000) ? 2 : 4;
- P = (coef & 0x00070000) >> 16;
- N = ((coef & 0x0000ff00) >> 8) + 1;
- M = ((coef & 0x000000ff) >> 0) + 1;
- break;
- case 0x84:
- case 0x86:
- case 0x92:
- coef = nv_rd32(priv, 0x00e81c);
- P = (coef & 0x00070000) >> 16;
- N = (coef & 0x0000ff00) >> 8;
- M = (coef & 0x000000ff) >> 0;
- break;
- case 0x94:
- case 0x96:
- case 0x98:
- rsel = nv_rd32(priv, 0x00c050);
- switch (base) {
- case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
- case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
- case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
- case 0x4030: rsel = 3; break;
- default:
- nv_error(priv, "ref: bad pll 0x%06x\n", base);
- return 0;
- }
-
- switch (rsel) {
- case 0: id = 1; break;
- case 1: return clk->read(clk, nv_clk_src_crystal);
- case 2: return clk->read(clk, nv_clk_src_href);
- case 3: id = 0; break;
- }
-
- coef = nv_rd32(priv, 0x00e81c + (id * 0x28));
- P = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7;
- P += (coef & 0x00070000) >> 16;
- N = (coef & 0x0000ff00) >> 8;
- M = (coef & 0x000000ff) >> 0;
- break;
- default:
- BUG_ON(1);
- }
-
- if (M)
- return (ref * N / M) >> P;
- return 0;
-}
-
-static u32
-read_pll_ref(struct nv50_clock_priv *priv, u32 base)
-{
- struct nouveau_clock *clk = &priv->base;
- u32 src, mast = nv_rd32(priv, 0x00c040);
-
- switch (base) {
- case 0x004028:
- src = !!(mast & 0x00200000);
- break;
- case 0x004020:
- src = !!(mast & 0x00400000);
- break;
- case 0x004008:
- src = !!(mast & 0x00010000);
- break;
- case 0x004030:
- src = !!(mast & 0x02000000);
- break;
- case 0x00e810:
- return clk->read(clk, nv_clk_src_crystal);
- default:
- nv_error(priv, "bad pll 0x%06x\n", base);
- return 0;
- }
-
- if (src)
- return clk->read(clk, nv_clk_src_href);
- return read_pll_src(priv, base);
-}
-
-static u32
-read_pll(struct nv50_clock_priv *priv, u32 base)
-{
- struct nouveau_clock *clk = &priv->base;
- u32 mast = nv_rd32(priv, 0x00c040);
- u32 ctrl = nv_rd32(priv, base + 0);
- u32 coef = nv_rd32(priv, base + 4);
- u32 ref = read_pll_ref(priv, base);
- u32 freq = 0;
- int N1, N2, M1, M2;
-
- if (base == 0x004028 && (mast & 0x00100000)) {
- /* wtf, appears to only disable post-divider on nva0 */
- if (nv_device(priv)->chipset != 0xa0)
- return clk->read(clk, nv_clk_src_dom6);
- }
-
- N2 = (coef & 0xff000000) >> 24;
- M2 = (coef & 0x00ff0000) >> 16;
- N1 = (coef & 0x0000ff00) >> 8;
- M1 = (coef & 0x000000ff);
- if ((ctrl & 0x80000000) && M1) {
- freq = ref * N1 / M1;
- if ((ctrl & 0x40000100) == 0x40000000) {
- if (M2)
- freq = freq * N2 / M2;
- else
- freq = 0;
- }
- }
-
- return freq;
-}
-
-static int
-nv50_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct nv50_clock_priv *priv = (void *)clk;
- u32 mast = nv_rd32(priv, 0x00c040);
- u32 P = 0;
-
- switch (src) {
- case nv_clk_src_crystal:
- return nv_device(priv)->crystal;
- case nv_clk_src_href:
- return 100000; /* PCIE reference clock */
- case nv_clk_src_hclk:
- return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000);
- case nv_clk_src_hclkm3:
- return clk->read(clk, nv_clk_src_hclk) * 3;
- case nv_clk_src_hclkm3d2:
- return clk->read(clk, nv_clk_src_hclk) * 3 / 2;
- case nv_clk_src_host:
- switch (mast & 0x30000000) {
- case 0x00000000: return clk->read(clk, nv_clk_src_href);
- case 0x10000000: break;
- case 0x20000000: /* !0x50 */
- case 0x30000000: return clk->read(clk, nv_clk_src_hclk);
- }
- break;
- case nv_clk_src_core:
- if (!(mast & 0x00100000))
- P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16;
- switch (mast & 0x00000003) {
- case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
- case 0x00000001: return clk->read(clk, nv_clk_src_dom6);
- case 0x00000002: return read_pll(priv, 0x004020) >> P;
- case 0x00000003: return read_pll(priv, 0x004028) >> P;
- }
- break;
- case nv_clk_src_shader:
- P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16;
- switch (mast & 0x00000030) {
- case 0x00000000:
- if (mast & 0x00000080)
- return clk->read(clk, nv_clk_src_host) >> P;
- return clk->read(clk, nv_clk_src_crystal) >> P;
- case 0x00000010: break;
- case 0x00000020: return read_pll(priv, 0x004028) >> P;
- case 0x00000030: return read_pll(priv, 0x004020) >> P;
- }
- break;
- case nv_clk_src_mem:
- P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16;
- if (nv_rd32(priv, 0x004008) & 0x00000200) {
- switch (mast & 0x0000c000) {
- case 0x00000000:
- return clk->read(clk, nv_clk_src_crystal) >> P;
- case 0x00008000:
- case 0x0000c000:
- return clk->read(clk, nv_clk_src_href) >> P;
- }
- } else {
- return read_pll(priv, 0x004008) >> P;
- }
- break;
- case nv_clk_src_vdec:
- P = (read_div(priv) & 0x00000700) >> 8;
- switch (nv_device(priv)->chipset) {
- case 0x84:
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0xa0:
- switch (mast & 0x00000c00) {
- case 0x00000000:
- if (nv_device(priv)->chipset == 0xa0) /* wtf?? */
- return clk->read(clk, nv_clk_src_core) >> P;
- return clk->read(clk, nv_clk_src_crystal) >> P;
- case 0x00000400:
- return 0;
- case 0x00000800:
- if (mast & 0x01000000)
- return read_pll(priv, 0x004028) >> P;
- return read_pll(priv, 0x004030) >> P;
- case 0x00000c00:
- return clk->read(clk, nv_clk_src_core) >> P;
- }
- break;
- case 0x98:
- switch (mast & 0x00000c00) {
- case 0x00000000:
- return clk->read(clk, nv_clk_src_core) >> P;
- case 0x00000400:
- return 0;
- case 0x00000800:
- return clk->read(clk, nv_clk_src_hclkm3d2) >> P;
- case 0x00000c00:
- return clk->read(clk, nv_clk_src_mem) >> P;
- }
- break;
- }
- break;
- case nv_clk_src_dom6:
- switch (nv_device(priv)->chipset) {
- case 0x50:
- case 0xa0:
- return read_pll(priv, 0x00e810) >> 2;
- case 0x84:
- case 0x86:
- case 0x92:
- case 0x94:
- case 0x96:
- case 0x98:
- P = (read_div(priv) & 0x00000007) >> 0;
- switch (mast & 0x0c000000) {
- case 0x00000000: return clk->read(clk, nv_clk_src_href);
- case 0x04000000: break;
- case 0x08000000: return clk->read(clk, nv_clk_src_hclk);
- case 0x0c000000:
- return clk->read(clk, nv_clk_src_hclkm3) >> P;
- }
- break;
- default:
- break;
- }
- default:
- break;
- }
-
- nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
- return -EINVAL;
-}
-
-static u32
-calc_pll(struct nv50_clock_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll pll;
- int ret;
-
- ret = nvbios_pll_parse(bios, reg, &pll);
- if (ret)
- return 0;
-
- pll.vco2.max_freq = 0;
- pll.refclk = read_pll_ref(priv, reg);
- if (!pll.refclk)
- return 0;
-
- return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P);
-}
-
-static inline u32
-calc_div(u32 src, u32 target, int *div)
-{
- u32 clk0 = src, clk1 = src;
- for (*div = 0; *div <= 7; (*div)++) {
- if (clk0 <= target) {
- clk1 = clk0 << (*div ? 1 : 0);
- break;
- }
- clk0 >>= 1;
- }
-
- if (target - clk0 <= clk1 - target)
- return clk0;
- (*div)--;
- return clk1;
-}
-
-static inline u32
-clk_same(u32 a, u32 b)
-{
- return ((a / 1000) == (b / 1000));
-}
-
-static int
-nv50_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct nv50_clock_priv *priv = (void *)clk;
- struct nv50_clock_hwsq *hwsq = &priv->hwsq;
- const int shader = cstate->domain[nv_clk_src_shader];
- const int core = cstate->domain[nv_clk_src_core];
- const int vdec = cstate->domain[nv_clk_src_vdec];
- const int dom6 = cstate->domain[nv_clk_src_dom6];
- u32 mastm = 0, mastv = 0;
- u32 divsm = 0, divsv = 0;
- int N, M, P1, P2;
- int freq, out;
-
- /* prepare a hwsq script from which we'll perform the reclock */
- out = clk_init(hwsq, nv_subdev(clk));
- if (out)
- return out;
-
- clk_wr32(hwsq, fifo, 0x00000001); /* block fifo */
- clk_nsec(hwsq, 8000);
- clk_setf(hwsq, 0x10, 0x00); /* disable fb */
- clk_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
-
- /* vdec: avoid modifying xpll until we know exactly how the other
- * clock domains work, i suspect at least some of them can also be
- * tied to xpll...
- */
- if (vdec) {
- /* see how close we can get using nvclk as a source */
- freq = calc_div(core, vdec, &P1);
-
- /* see how close we can get using xpll/hclk as a source */
- if (nv_device(priv)->chipset != 0x98)
- out = read_pll(priv, 0x004030);
- else
- out = clk->read(clk, nv_clk_src_hclkm3d2);
- out = calc_div(out, vdec, &P2);
-
- /* select whichever gets us closest */
- if (abs(vdec - freq) <= abs(vdec - out)) {
- if (nv_device(priv)->chipset != 0x98)
- mastv |= 0x00000c00;
- divsv |= P1 << 8;
- } else {
- mastv |= 0x00000800;
- divsv |= P2 << 8;
- }
-
- mastm |= 0x00000c00;
- divsm |= 0x00000700;
- }
-
- /* dom6: nfi what this is, but we're limited to various combinations
- * of the host clock frequency
- */
- if (dom6) {
- if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) {
- mastv |= 0x00000000;
- } else
- if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) {
- mastv |= 0x08000000;
- } else {
- freq = clk->read(clk, nv_clk_src_hclk) * 3;
- freq = calc_div(freq, dom6, &P1);
-
- mastv |= 0x0c000000;
- divsv |= P1;
- }
-
- mastm |= 0x0c000000;
- divsm |= 0x00000007;
- }
-
- /* vdec/dom6: switch to "safe" clocks temporarily, update dividers
- * and then switch to target clocks
- */
- clk_mask(hwsq, mast, mastm, 0x00000000);
- clk_mask(hwsq, divs, divsm, divsv);
- clk_mask(hwsq, mast, mastm, mastv);
-
- /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6,
- * sclk to hclk) before reprogramming
- */
- if (nv_device(priv)->chipset < 0x92)
- clk_mask(hwsq, mast, 0x001000b0, 0x00100080);
- else
- clk_mask(hwsq, mast, 0x000000b3, 0x00000081);
-
- /* core: for the moment at least, always use nvpll */
- freq = calc_pll(priv, 0x4028, core, &N, &M, &P1);
- if (freq == 0)
- return -ERANGE;
-
- clk_mask(hwsq, nvpll[0], 0xc03f0100,
- 0x80000000 | (P1 << 19) | (P1 << 16));
- clk_mask(hwsq, nvpll[1], 0x0000ffff, (N << 8) | M);
-
- /* shader: tie to nvclk if possible, otherwise use spll. have to be
- * very careful that the shader clock is at least twice the core, or
- * some chipsets will be very unhappy. i expect most or all of these
- * cases will be handled by tying to nvclk, but it's possible there's
- * corners
- */
- if (P1-- && shader == (core << 1)) {
- clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16));
- clk_mask(hwsq, mast, 0x00100033, 0x00000023);
- } else {
- freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
- if (freq == 0)
- return -ERANGE;
-
- clk_mask(hwsq, spll[0], 0xc03f0100,
- 0x80000000 | (P1 << 19) | (P1 << 16));
- clk_mask(hwsq, spll[1], 0x0000ffff, (N << 8) | M);
- clk_mask(hwsq, mast, 0x00100033, 0x00000033);
- }
-
- /* restore normal operation */
- clk_setf(hwsq, 0x10, 0x01); /* enable fb */
- clk_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
- clk_wr32(hwsq, fifo, 0x00000000); /* un-block fifo */
- return 0;
-}
-
-static int
-nv50_clock_prog(struct nouveau_clock *clk)
-{
- struct nv50_clock_priv *priv = (void *)clk;
- return clk_exec(&priv->hwsq, true);
-}
-
-static void
-nv50_clock_tidy(struct nouveau_clock *clk)
-{
- struct nv50_clock_priv *priv = (void *)clk;
- clk_exec(&priv->hwsq, false);
-}
-
-int
-nv50_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_clock_oclass *pclass = (void *)oclass;
- struct nv50_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, pclass->domains,
- NULL, 0, false, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->hwsq.r_fifo = hwsq_reg(0x002504);
- priv->hwsq.r_spll[0] = hwsq_reg(0x004020);
- priv->hwsq.r_spll[1] = hwsq_reg(0x004024);
- priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028);
- priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c);
- switch (nv_device(priv)->chipset) {
- case 0x92:
- case 0x94:
- case 0x96:
- priv->hwsq.r_divs = hwsq_reg(0x004800);
- break;
- default:
- priv->hwsq.r_divs = hwsq_reg(0x004700);
- break;
- }
- priv->hwsq.r_mast = hwsq_reg(0x00c040);
-
- priv->base.read = nv50_clock_read;
- priv->base.calc = nv50_clock_calc;
- priv->base.prog = nv50_clock_prog;
- priv->base.tidy = nv50_clock_tidy;
- return 0;
-}
-
-static struct nouveau_clocks
-nv50_domains[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_href , 0xff },
- { nv_clk_src_core , 0xff, 0, "core", 1000 },
- { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
- { nv_clk_src_mem , 0xff, 0, "memory", 1000 },
- { nv_clk_src_max }
-};
-
-struct nouveau_oclass *
-nv50_clock_oclass = &(struct nv50_clock_oclass) {
- .base.handle = NV_SUBDEV(CLOCK, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
- .domains = nv50_domains,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h
deleted file mode 100644
index f10917d789e8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv50.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NVKM_CLK_NV50_H__
-#define __NVKM_CLK_NV50_H__
-
-#include <subdev/bus.h>
-#include <subdev/bus/hwsq.h>
-#include <subdev/clock.h>
-
-struct nv50_clock_hwsq {
- struct hwsq base;
- struct hwsq_reg r_fifo;
- struct hwsq_reg r_spll[2];
- struct hwsq_reg r_nvpll[2];
- struct hwsq_reg r_divs;
- struct hwsq_reg r_mast;
-};
-
-struct nv50_clock_priv {
- struct nouveau_clock base;
- struct nv50_clock_hwsq hwsq;
-};
-
-int nv50_clock_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-struct nv50_clock_oclass {
- struct nouveau_oclass base;
- struct nouveau_clocks *domains;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c
deleted file mode 100644
index b0b7c1437f10..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nv84.c
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "nv50.h"
-
-static struct nouveau_clocks
-nv84_domains[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_href , 0xff },
- { nv_clk_src_core , 0xff, 0, "core", 1000 },
- { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
- { nv_clk_src_mem , 0xff, 0, "memory", 1000 },
- { nv_clk_src_vdec , 0xff },
- { nv_clk_src_max }
-};
-
-struct nouveau_oclass *
-nv84_clock_oclass = &(struct nv50_clock_oclass) {
- .base.handle = NV_SUBDEV(CLOCK, 0x84),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
- .domains = nv84_domains,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
deleted file mode 100644
index 07ad01247675..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Roy Spliet
- */
-
-#include <engine/fifo.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/timer.h>
-
-#include "pll.h"
-
-#include "nva3.h"
-
-struct nva3_clock_priv {
- struct nouveau_clock base;
- struct nva3_clock_info eng[nv_clk_src_max];
-};
-
-static u32 read_clk(struct nva3_clock_priv *, int, bool);
-static u32 read_pll(struct nva3_clock_priv *, int, u32);
-
-static u32
-read_vco(struct nva3_clock_priv *priv, int clk)
-{
- u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
-
- switch (sctl & 0x00000030) {
- case 0x00000000:
- return nv_device(priv)->crystal;
- case 0x00000020:
- return read_pll(priv, 0x41, 0x00e820);
- case 0x00000030:
- return read_pll(priv, 0x42, 0x00e8a0);
- default:
- return 0;
- }
-}
-
-static u32
-read_clk(struct nva3_clock_priv *priv, int clk, bool ignore_en)
-{
- u32 sctl, sdiv, sclk;
-
- /* refclk for the 0xe8xx plls is a fixed frequency */
- if (clk >= 0x40) {
- if (nv_device(priv)->chipset == 0xaf) {
- /* no joke.. seriously.. sigh.. */
- return nv_rd32(priv, 0x00471c) * 1000;
- }
-
- return nv_device(priv)->crystal;
- }
-
- sctl = nv_rd32(priv, 0x4120 + (clk * 4));
- if (!ignore_en && !(sctl & 0x00000100))
- return 0;
-
- /* out_alt */
- if (sctl & 0x00000400)
- return 108000;
-
- /* vco_out */
- switch (sctl & 0x00003000) {
- case 0x00000000:
- if (!(sctl & 0x00000200))
- return nv_device(priv)->crystal;
- return 0;
- case 0x00002000:
- if (sctl & 0x00000040)
- return 108000;
- return 100000;
- case 0x00003000:
- /* vco_enable */
- if (!(sctl & 0x00000001))
- return 0;
-
- sclk = read_vco(priv, clk);
- sdiv = ((sctl & 0x003f0000) >> 16) + 2;
- return (sclk * 2) / sdiv;
- default:
- return 0;
- }
-}
-
-static u32
-read_pll(struct nva3_clock_priv *priv, int clk, u32 pll)
-{
- u32 ctrl = nv_rd32(priv, pll + 0);
- u32 sclk = 0, P = 1, N = 1, M = 1;
-
- if (!(ctrl & 0x00000008)) {
- if (ctrl & 0x00000001) {
- u32 coef = nv_rd32(priv, pll + 4);
- M = (coef & 0x000000ff) >> 0;
- N = (coef & 0x0000ff00) >> 8;
- P = (coef & 0x003f0000) >> 16;
-
- /* no post-divider on these..
- * XXX: it looks more like two post-"dividers" that
- * cross each other out in the default RPLL config */
- if ((pll & 0x00ff00) == 0x00e800)
- P = 1;
-
- sclk = read_clk(priv, 0x00 + clk, false);
- }
- } else {
- sclk = read_clk(priv, 0x10 + clk, false);
- }
-
- if (M * P)
- return sclk * N / (M * P);
- return 0;
-}
-
-static int
-nva3_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct nva3_clock_priv *priv = (void *)clk;
- u32 hsrc;
-
- switch (src) {
- case nv_clk_src_crystal:
- return nv_device(priv)->crystal;
- case nv_clk_src_core:
- case nv_clk_src_core_intm:
- return read_pll(priv, 0x00, 0x4200);
- case nv_clk_src_shader:
- return read_pll(priv, 0x01, 0x4220);
- case nv_clk_src_mem:
- return read_pll(priv, 0x02, 0x4000);
- case nv_clk_src_disp:
- return read_clk(priv, 0x20, false);
- case nv_clk_src_vdec:
- return read_clk(priv, 0x21, false);
- case nv_clk_src_daemon:
- return read_clk(priv, 0x25, false);
- case nv_clk_src_host:
- hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
- switch (hsrc) {
- case 0:
- return read_clk(priv, 0x1d, false);
- case 2:
- case 3:
- return 277000;
- default:
- nv_error(clk, "unknown HOST clock source %d\n", hsrc);
- return -EINVAL;
- }
- default:
- nv_error(clk, "invalid clock source %d\n", src);
- return -EINVAL;
- }
-
- return 0;
-}
-
-int
-nva3_clk_info(struct nouveau_clock *clock, int clk, u32 khz,
- struct nva3_clock_info *info)
-{
- struct nva3_clock_priv *priv = (void *)clock;
- u32 oclk, sclk, sdiv, diff;
-
- info->clk = 0;
-
- switch (khz) {
- case 27000:
- info->clk = 0x00000100;
- return khz;
- case 100000:
- info->clk = 0x00002100;
- return khz;
- case 108000:
- info->clk = 0x00002140;
- return khz;
- default:
- sclk = read_vco(priv, clk);
- sdiv = min((sclk * 2) / khz, (u32)65);
- oclk = (sclk * 2) / sdiv;
- diff = ((khz + 3000) - oclk);
-
- /* When imprecise, play it safe and aim for a clock lower than
- * desired rather than higher */
- if (diff < 0) {
- sdiv++;
- oclk = (sclk * 2) / sdiv;
- }
-
- /* divider can go as low as 2, limited here because NVIDIA
- * and the VBIOS on my NVA8 seem to prefer using the PLL
- * for 810MHz - is there a good reason?
- * XXX: PLLs with refclk 810MHz? */
- if (sdiv > 4) {
- info->clk = (((sdiv - 2) << 16) | 0x00003100);
- return oclk;
- }
-
- break;
- }
-
- return -ERANGE;
-}
-
-int
-nva3_pll_info(struct nouveau_clock *clock, int clk, u32 pll, u32 khz,
- struct nva3_clock_info *info)
-{
- struct nouveau_bios *bios = nouveau_bios(clock);
- struct nva3_clock_priv *priv = (void *)clock;
- struct nvbios_pll limits;
- int P, N, M, diff;
- int ret;
-
- info->pll = 0;
-
- /* If we can get a within [-2, 3) MHz of a divider, we'll disable the
- * PLL and use the divider instead. */
- ret = nva3_clk_info(clock, clk, khz, info);
- diff = khz - ret;
- if (!pll || (diff >= -2000 && diff < 3000)) {
- goto out;
- }
-
- /* Try with PLL */
- ret = nvbios_pll_parse(bios, pll, &limits);
- if (ret)
- return ret;
-
- ret = nva3_clk_info(clock, clk - 0x10, limits.refclk, info);
- if (ret != limits.refclk)
- return -EINVAL;
-
- ret = nva3_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
- if (ret >= 0) {
- info->pll = (P << 16) | (N << 8) | M;
- }
-
-out:
- info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
-
- return ret ? ret : -ERANGE;
-}
-
-static int
-calc_clk(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate,
- int clk, u32 pll, int idx)
-{
- int ret = nva3_pll_info(&priv->base, clk, pll, cstate->domain[idx],
- &priv->eng[idx]);
- if (ret >= 0)
- return 0;
- return ret;
-}
-
-static int
-calc_host(struct nva3_clock_priv *priv, struct nouveau_cstate *cstate)
-{
- int ret = 0;
- u32 kHz = cstate->domain[nv_clk_src_host];
- struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
-
- if (kHz == 277000) {
- info->clk = 0;
- info->host_out = NVA3_HOST_277;
- return 0;
- }
-
- info->host_out = NVA3_HOST_CLK;
-
- ret = nva3_clk_info(&priv->base, 0x1d, kHz, info);
- if (ret >= 0)
- return 0;
- return ret;
-}
-
-int
-nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(clk);
-
- /* halt and idle execution engines */
- nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
- nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
- /* Wait until the interrupt handler is finished */
- if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
- return -EBUSY;
-
- if (pfifo)
- pfifo->pause(pfifo, flags);
-
- if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
- return -EIO;
- if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
- return -EIO;
-
- return 0;
-}
-
-void
-nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags)
-{
- struct nouveau_fifo *pfifo = nouveau_fifo(clk);
-
- if (pfifo && flags)
- pfifo->start(pfifo, flags);
-
- nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
- nv_mask(clk, 0x020060, 0x00070000, 0x00040000);
-}
-
-static void
-disable_clk_src(struct nva3_clock_priv *priv, u32 src)
-{
- nv_mask(priv, src, 0x00000100, 0x00000000);
- nv_mask(priv, src, 0x00000001, 0x00000000);
-}
-
-static void
-prog_pll(struct nva3_clock_priv *priv, int clk, u32 pll, int idx)
-{
- struct nva3_clock_info *info = &priv->eng[idx];
- const u32 src0 = 0x004120 + (clk * 4);
- const u32 src1 = 0x004160 + (clk * 4);
- const u32 ctrl = pll + 0;
- const u32 coef = pll + 4;
- u32 bypass;
-
- if (info->pll) {
- /* Always start from a non-PLL clock */
- bypass = nv_rd32(priv, ctrl) & 0x00000008;
- if (!bypass) {
- nv_mask(priv, src1, 0x00000101, 0x00000101);
- nv_mask(priv, ctrl, 0x00000008, 0x00000008);
- udelay(20);
- }
-
- nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk);
- nv_wr32(priv, coef, info->pll);
- nv_mask(priv, ctrl, 0x00000015, 0x00000015);
- nv_mask(priv, ctrl, 0x00000010, 0x00000000);
- if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) {
- nv_mask(priv, ctrl, 0x00000010, 0x00000010);
- nv_mask(priv, src0, 0x00000101, 0x00000000);
- return;
- }
- nv_mask(priv, ctrl, 0x00000010, 0x00000010);
- nv_mask(priv, ctrl, 0x00000008, 0x00000000);
- disable_clk_src(priv, src1);
- } else {
- nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
- nv_mask(priv, ctrl, 0x00000018, 0x00000018);
- udelay(20);
- nv_mask(priv, ctrl, 0x00000001, 0x00000000);
- disable_clk_src(priv, src0);
- }
-}
-
-static void
-prog_clk(struct nva3_clock_priv *priv, int clk, int idx)
-{
- struct nva3_clock_info *info = &priv->eng[idx];
- nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
-}
-
-static void
-prog_host(struct nva3_clock_priv *priv)
-{
- struct nva3_clock_info *info = &priv->eng[nv_clk_src_host];
- u32 hsrc = (nv_rd32(priv, 0xc040));
-
- switch (info->host_out) {
- case NVA3_HOST_277:
- if ((hsrc & 0x30000000) == 0) {
- nv_wr32(priv, 0xc040, hsrc | 0x20000000);
- disable_clk_src(priv, 0x4194);
- }
- break;
- case NVA3_HOST_CLK:
- prog_clk(priv, 0x1d, nv_clk_src_host);
- if ((hsrc & 0x30000000) >= 0x20000000) {
- nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
- }
- break;
- default:
- break;
- }
-
- /* This seems to be a clock gating factor on idle, always set to 64 */
- nv_wr32(priv, 0xc044, 0x3e);
-}
-
-static void
-prog_core(struct nva3_clock_priv *priv, int idx)
-{
- struct nva3_clock_info *info = &priv->eng[idx];
- u32 fb_delay = nv_rd32(priv, 0x10002c);
-
- if (fb_delay < info->fb_delay)
- nv_wr32(priv, 0x10002c, info->fb_delay);
-
- prog_pll(priv, 0x00, 0x004200, idx);
-
- if (fb_delay > info->fb_delay)
- nv_wr32(priv, 0x10002c, info->fb_delay);
-}
-
-static int
-nva3_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct nva3_clock_priv *priv = (void *)clk;
- struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
- int ret;
-
- if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
- (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
- (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
- (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
- (ret = calc_host(priv, cstate)))
- return ret;
-
- /* XXX: Should be reading the highest bit in the VBIOS clock to decide
- * whether to use a PLL or not... but using a PLL defeats the purpose */
- if (core->pll) {
- ret = nva3_clk_info(clk, 0x10,
- cstate->domain[nv_clk_src_core_intm],
- &priv->eng[nv_clk_src_core_intm]);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-static int
-nva3_clock_prog(struct nouveau_clock *clk)
-{
- struct nva3_clock_priv *priv = (void *)clk;
- struct nva3_clock_info *core = &priv->eng[nv_clk_src_core];
- int ret = 0;
- unsigned long flags;
- unsigned long *f = &flags;
-
- ret = nva3_clock_pre(clk, f);
- if (ret)
- goto out;
-
- if (core->pll)
- prog_core(priv, nv_clk_src_core_intm);
-
- prog_core(priv, nv_clk_src_core);
- prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
- prog_clk(priv, 0x20, nv_clk_src_disp);
- prog_clk(priv, 0x21, nv_clk_src_vdec);
- prog_host(priv);
-
-out:
- if (ret == -EBUSY)
- f = NULL;
-
- nva3_clock_post(clk, f);
-
- return ret;
-}
-
-static void
-nva3_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static struct nouveau_clocks
-nva3_domain[] = {
- { nv_clk_src_crystal , 0xff },
- { nv_clk_src_core , 0x00, 0, "core", 1000 },
- { nv_clk_src_shader , 0x01, 0, "shader", 1000 },
- { nv_clk_src_mem , 0x02, 0, "memory", 1000 },
- { nv_clk_src_vdec , 0x03 },
- { nv_clk_src_disp , 0x04 },
- { nv_clk_src_host , 0x05 },
- { nv_clk_src_core_intm, 0x06 },
- { nv_clk_src_max }
-};
-
-static int
-nva3_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nva3_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, nva3_domain, NULL, 0,
- true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.read = nva3_clock_read;
- priv->base.calc = nva3_clock_calc;
- priv->base.prog = nva3_clock_prog;
- priv->base.tidy = nva3_clock_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nva3_clock_oclass = {
- .handle = NV_SUBDEV(CLOCK, 0xa3),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h b/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h
deleted file mode 100644
index a45a1038b12f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nva3.h
+++ /dev/null
@@ -1,20 +0,0 @@
-#ifndef __NVKM_CLK_NVA3_H__
-#define __NVKM_CLK_NVA3_H__
-
-#include <subdev/clock.h>
-
-struct nva3_clock_info {
- u32 clk;
- u32 pll;
- enum {
- NVA3_HOST_277,
- NVA3_HOST_CLK,
- } host_out;
- u32 fb_delay;
-};
-
-int nva3_pll_info(struct nouveau_clock *, int, u32, u32,
- struct nva3_clock_info *);
-int nva3_clock_pre(struct nouveau_clock *clk, unsigned long *flags);
-void nva3_clock_post(struct nouveau_clock *clk, unsigned long *flags);
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c
deleted file mode 100644
index 54aeab8005a0..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvaa.c
+++ /dev/null
@@ -1,435 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/fifo.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/timer.h>
-#include <subdev/clock.h>
-
-#include "nva3.h"
-#include "pll.h"
-
-struct nvaa_clock_priv {
- struct nouveau_clock base;
- enum nv_clk_src csrc, ssrc, vsrc;
- u32 cctrl, sctrl;
- u32 ccoef, scoef;
- u32 cpost, spost;
- u32 vdiv;
-};
-
-static u32
-read_div(struct nouveau_clock *clk)
-{
- return nv_rd32(clk, 0x004600);
-}
-
-static u32
-read_pll(struct nouveau_clock *clk, u32 base)
-{
- u32 ctrl = nv_rd32(clk, base + 0);
- u32 coef = nv_rd32(clk, base + 4);
- u32 ref = clk->read(clk, nv_clk_src_href);
- u32 post_div = 0;
- u32 clock = 0;
- int N1, M1;
-
- switch (base){
- case 0x4020:
- post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16);
- break;
- case 0x4028:
- post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16;
- break;
- default:
- break;
- }
-
- N1 = (coef & 0x0000ff00) >> 8;
- M1 = (coef & 0x000000ff);
- if ((ctrl & 0x80000000) && M1) {
- clock = ref * N1 / M1;
- clock = clock / post_div;
- }
-
- return clock;
-}
-
-static int
-nvaa_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct nvaa_clock_priv *priv = (void *)clk;
- u32 mast = nv_rd32(clk, 0x00c054);
- u32 P = 0;
-
- switch (src) {
- case nv_clk_src_crystal:
- return nv_device(priv)->crystal;
- case nv_clk_src_href:
- return 100000; /* PCIE reference clock */
- case nv_clk_src_hclkm4:
- return clk->read(clk, nv_clk_src_href) * 4;
- case nv_clk_src_hclkm2d3:
- return clk->read(clk, nv_clk_src_href) * 2 / 3;
- case nv_clk_src_host:
- switch (mast & 0x000c0000) {
- case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3);
- case 0x00040000: break;
- case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4);
- case 0x000c0000: return clk->read(clk, nv_clk_src_cclk);
- }
- break;
- case nv_clk_src_core:
- P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16;
-
- switch (mast & 0x00000003) {
- case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
- case 0x00000001: return 0;
- case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P;
- case 0x00000003: return read_pll(clk, 0x004028) >> P;
- }
- break;
- case nv_clk_src_cclk:
- if ((mast & 0x03000000) != 0x03000000)
- return clk->read(clk, nv_clk_src_core);
-
- if ((mast & 0x00000200) == 0x00000000)
- return clk->read(clk, nv_clk_src_core);
-
- switch (mast & 0x00000c00) {
- case 0x00000000: return clk->read(clk, nv_clk_src_href);
- case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4);
- case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3);
- default: return 0;
- }
- case nv_clk_src_shader:
- P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16;
- switch (mast & 0x00000030) {
- case 0x00000000:
- if (mast & 0x00000040)
- return clk->read(clk, nv_clk_src_href) >> P;
- return clk->read(clk, nv_clk_src_crystal) >> P;
- case 0x00000010: break;
- case 0x00000020: return read_pll(clk, 0x004028) >> P;
- case 0x00000030: return read_pll(clk, 0x004020) >> P;
- }
- break;
- case nv_clk_src_mem:
- return 0;
- break;
- case nv_clk_src_vdec:
- P = (read_div(clk) & 0x00000700) >> 8;
-
- switch (mast & 0x00400000) {
- case 0x00400000:
- return clk->read(clk, nv_clk_src_core) >> P;
- break;
- default:
- return 500000 >> P;
- break;
- }
- break;
- default:
- break;
- }
-
- nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
- return 0;
-}
-
-static u32
-calc_pll(struct nvaa_clock_priv *priv, u32 reg,
- u32 clock, int *N, int *M, int *P)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll pll;
- struct nouveau_clock *clk = &priv->base;
- int ret;
-
- ret = nvbios_pll_parse(bios, reg, &pll);
- if (ret)
- return 0;
-
- pll.vco2.max_freq = 0;
- pll.refclk = clk->read(clk, nv_clk_src_href);
- if (!pll.refclk)
- return 0;
-
- return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P);
-}
-
-static inline u32
-calc_P(u32 src, u32 target, int *div)
-{
- u32 clk0 = src, clk1 = src;
- for (*div = 0; *div <= 7; (*div)++) {
- if (clk0 <= target) {
- clk1 = clk0 << (*div ? 1 : 0);
- break;
- }
- clk0 >>= 1;
- }
-
- if (target - clk0 <= clk1 - target)
- return clk0;
- (*div)--;
- return clk1;
-}
-
-static int
-nvaa_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct nvaa_clock_priv *priv = (void *)clk;
- const int shader = cstate->domain[nv_clk_src_shader];
- const int core = cstate->domain[nv_clk_src_core];
- const int vdec = cstate->domain[nv_clk_src_vdec];
- u32 out = 0, clock = 0;
- int N, M, P1, P2 = 0;
- int divs = 0;
-
- /* cclk: find suitable source, disable PLL if we can */
- if (core < clk->read(clk, nv_clk_src_hclkm4))
- out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs);
-
- /* Calculate clock * 2, so shader clock can use it too */
- clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1);
-
- if (abs(core - out) <=
- abs(core - (clock >> 1))) {
- priv->csrc = nv_clk_src_hclkm4;
- priv->cctrl = divs << 16;
- } else {
- /* NVCTRL is actually used _after_ NVPOST, and after what we
- * call NVPLL. To make matters worse, NVPOST is an integer
- * divider instead of a right-shift number. */
- if(P1 > 2) {
- P2 = P1 - 2;
- P1 = 2;
- }
-
- priv->csrc = nv_clk_src_core;
- priv->ccoef = (N << 8) | M;
-
- priv->cctrl = (P2 + 1) << 16;
- priv->cpost = (1 << P1) << 16;
- }
-
- /* sclk: nvpll + divisor, href or spll */
- out = 0;
- if (shader == clk->read(clk, nv_clk_src_href)) {
- priv->ssrc = nv_clk_src_href;
- } else {
- clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
- if (priv->csrc == nv_clk_src_core) {
- out = calc_P((core << 1), shader, &divs);
- }
-
- if (abs(shader - out) <=
- abs(shader - clock) &&
- (divs + P2) <= 7) {
- priv->ssrc = nv_clk_src_core;
- priv->sctrl = (divs + P2) << 16;
- } else {
- priv->ssrc = nv_clk_src_shader;
- priv->scoef = (N << 8) | M;
- priv->sctrl = P1 << 16;
- }
- }
-
- /* vclk */
- out = calc_P(core, vdec, &divs);
- clock = calc_P(500000, vdec, &P1);
- if(abs(vdec - out) <=
- abs(vdec - clock)) {
- priv->vsrc = nv_clk_src_cclk;
- priv->vdiv = divs << 16;
- } else {
- priv->vsrc = nv_clk_src_vdec;
- priv->vdiv = P1 << 16;
- }
-
- /* Print strategy! */
- nv_debug(priv, "nvpll: %08x %08x %08x\n",
- priv->ccoef, priv->cpost, priv->cctrl);
- nv_debug(priv, " spll: %08x %08x %08x\n",
- priv->scoef, priv->spost, priv->sctrl);
- nv_debug(priv, " vdiv: %08x\n", priv->vdiv);
- if (priv->csrc == nv_clk_src_hclkm4)
- nv_debug(priv, "core: hrefm4\n");
- else
- nv_debug(priv, "core: nvpll\n");
-
- if (priv->ssrc == nv_clk_src_hclkm4)
- nv_debug(priv, "shader: hrefm4\n");
- else if (priv->ssrc == nv_clk_src_core)
- nv_debug(priv, "shader: nvpll\n");
- else
- nv_debug(priv, "shader: spll\n");
-
- if (priv->vsrc == nv_clk_src_hclkm4)
- nv_debug(priv, "vdec: 500MHz\n");
- else
- nv_debug(priv, "vdec: core\n");
-
- return 0;
-}
-
-static int
-nvaa_clock_prog(struct nouveau_clock *clk)
-{
- struct nvaa_clock_priv *priv = (void *)clk;
- u32 pllmask = 0, mast;
- unsigned long flags;
- unsigned long *f = &flags;
- int ret = 0;
-
- ret = nva3_clock_pre(clk, f);
- if (ret)
- goto out;
-
- /* First switch to safe clocks: href */
- mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
- mast &= ~0x00400e73;
- mast |= 0x03000000;
-
- switch (priv->csrc) {
- case nv_clk_src_hclkm4:
- nv_mask(clk, 0x4028, 0x00070000, priv->cctrl);
- mast |= 0x00000002;
- break;
- case nv_clk_src_core:
- nv_wr32(clk, 0x402c, priv->ccoef);
- nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl);
- nv_wr32(clk, 0x4040, priv->cpost);
- pllmask |= (0x3 << 8);
- mast |= 0x00000003;
- break;
- default:
- nv_warn(priv,"Reclocking failed: unknown core clock\n");
- goto resume;
- }
-
- switch (priv->ssrc) {
- case nv_clk_src_href:
- nv_mask(clk, 0x4020, 0x00070000, 0x00000000);
- /* mast |= 0x00000000; */
- break;
- case nv_clk_src_core:
- nv_mask(clk, 0x4020, 0x00070000, priv->sctrl);
- mast |= 0x00000020;
- break;
- case nv_clk_src_shader:
- nv_wr32(clk, 0x4024, priv->scoef);
- nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl);
- nv_wr32(clk, 0x4070, priv->spost);
- pllmask |= (0x3 << 12);
- mast |= 0x00000030;
- break;
- default:
- nv_warn(priv,"Reclocking failed: unknown sclk clock\n");
- goto resume;
- }
-
- if (!nv_wait(clk, 0x004080, pllmask, pllmask)) {
- nv_warn(priv,"Reclocking failed: unstable PLLs\n");
- goto resume;
- }
-
- switch (priv->vsrc) {
- case nv_clk_src_cclk:
- mast |= 0x00400000;
- default:
- nv_wr32(clk, 0x4600, priv->vdiv);
- }
-
- nv_wr32(clk, 0xc054, mast);
-
-resume:
- /* Disable some PLLs and dividers when unused */
- if (priv->csrc != nv_clk_src_core) {
- nv_wr32(clk, 0x4040, 0x00000000);
- nv_mask(clk, 0x4028, 0x80000000, 0x00000000);
- }
-
- if (priv->ssrc != nv_clk_src_shader) {
- nv_wr32(clk, 0x4070, 0x00000000);
- nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
- }
-
-out:
- if (ret == -EBUSY)
- f = NULL;
-
- nva3_clock_post(clk, f);
-
- return ret;
-}
-
-static void
-nvaa_clock_tidy(struct nouveau_clock *clk)
-{
-}
-
-static struct nouveau_clocks
-nvaa_domains[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_href , 0xff },
- { nv_clk_src_core , 0xff, 0, "core", 1000 },
- { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
- { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 },
- { nv_clk_src_max }
-};
-
-static int
-nvaa_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvaa_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, nvaa_domains, NULL,
- 0, true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.read = nvaa_clock_read;
- priv->base.calc = nvaa_clock_calc;
- priv->base.prog = nvaa_clock_prog;
- priv->base.tidy = nvaa_clock_tidy;
- return 0;
-}
-
-struct nouveau_oclass *
-nvaa_clock_oclass = &(struct nouveau_oclass) {
- .handle = NV_SUBDEV(CLOCK, 0xaa),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvaa_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
deleted file mode 100644
index 1234abaab2db..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nvc0.c
+++ /dev/null
@@ -1,462 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/timer.h>
-
-#include "pll.h"
-
-struct nvc0_clock_info {
- u32 freq;
- u32 ssel;
- u32 mdiv;
- u32 dsrc;
- u32 ddiv;
- u32 coef;
-};
-
-struct nvc0_clock_priv {
- struct nouveau_clock base;
- struct nvc0_clock_info eng[16];
-};
-
-static u32 read_div(struct nvc0_clock_priv *, int, u32, u32);
-
-static u32
-read_vco(struct nvc0_clock_priv *priv, u32 dsrc)
-{
- struct nouveau_clock *clk = &priv->base;
- u32 ssrc = nv_rd32(priv, dsrc);
- if (!(ssrc & 0x00000100))
- return clk->read(clk, nv_clk_src_sppll0);
- return clk->read(clk, nv_clk_src_sppll1);
-}
-
-static u32
-read_pll(struct nvc0_clock_priv *priv, u32 pll)
-{
- struct nouveau_clock *clk = &priv->base;
- u32 ctrl = nv_rd32(priv, pll + 0x00);
- u32 coef = nv_rd32(priv, pll + 0x04);
- u32 P = (coef & 0x003f0000) >> 16;
- u32 N = (coef & 0x0000ff00) >> 8;
- u32 M = (coef & 0x000000ff) >> 0;
- u32 sclk;
-
- if (!(ctrl & 0x00000001))
- return 0;
-
- switch (pll) {
- case 0x00e800:
- case 0x00e820:
- sclk = nv_device(priv)->crystal;
- P = 1;
- break;
- case 0x132000:
- sclk = clk->read(clk, nv_clk_src_mpllsrc);
- break;
- case 0x132020:
- sclk = clk->read(clk, nv_clk_src_mpllsrcref);
- break;
- case 0x137000:
- case 0x137020:
- case 0x137040:
- case 0x1370e0:
- sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
- break;
- default:
- return 0;
- }
-
- return sclk * N / M / P;
-}
-
-static u32
-read_div(struct nvc0_clock_priv *priv, int doff, u32 dsrc, u32 dctl)
-{
- u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
- u32 sctl = nv_rd32(priv, dctl + (doff * 4));
-
- switch (ssrc & 0x00000003) {
- case 0:
- if ((ssrc & 0x00030000) != 0x00030000)
- return nv_device(priv)->crystal;
- return 108000;
- case 2:
- return 100000;
- case 3:
- if (sctl & 0x80000000) {
- u32 sclk = read_vco(priv, dsrc + (doff * 4));
- u32 sdiv = (sctl & 0x0000003f) + 2;
- return (sclk * 2) / sdiv;
- }
-
- return read_vco(priv, dsrc + (doff * 4));
- default:
- return 0;
- }
-}
-
-static u32
-read_clk(struct nvc0_clock_priv *priv, int clk)
-{
- u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
- u32 ssel = nv_rd32(priv, 0x137100);
- u32 sclk, sdiv;
-
- if (ssel & (1 << clk)) {
- if (clk < 7)
- sclk = read_pll(priv, 0x137000 + (clk * 0x20));
- else
- sclk = read_pll(priv, 0x1370e0);
- sdiv = ((sctl & 0x00003f00) >> 8) + 2;
- } else {
- sclk = read_div(priv, clk, 0x137160, 0x1371d0);
- sdiv = ((sctl & 0x0000003f) >> 0) + 2;
- }
-
- if (sctl & 0x80000000)
- return (sclk * 2) / sdiv;
-
- return sclk;
-}
-
-static int
-nvc0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct nouveau_device *device = nv_device(clk);
- struct nvc0_clock_priv *priv = (void *)clk;
-
- switch (src) {
- case nv_clk_src_crystal:
- return device->crystal;
- case nv_clk_src_href:
- return 100000;
- case nv_clk_src_sppll0:
- return read_pll(priv, 0x00e800);
- case nv_clk_src_sppll1:
- return read_pll(priv, 0x00e820);
-
- case nv_clk_src_mpllsrcref:
- return read_div(priv, 0, 0x137320, 0x137330);
- case nv_clk_src_mpllsrc:
- return read_pll(priv, 0x132020);
- case nv_clk_src_mpll:
- return read_pll(priv, 0x132000);
- case nv_clk_src_mdiv:
- return read_div(priv, 0, 0x137300, 0x137310);
- case nv_clk_src_mem:
- if (nv_rd32(priv, 0x1373f0) & 0x00000002)
- return clk->read(clk, nv_clk_src_mpll);
- return clk->read(clk, nv_clk_src_mdiv);
-
- case nv_clk_src_gpc:
- return read_clk(priv, 0x00);
- case nv_clk_src_rop:
- return read_clk(priv, 0x01);
- case nv_clk_src_hubk07:
- return read_clk(priv, 0x02);
- case nv_clk_src_hubk06:
- return read_clk(priv, 0x07);
- case nv_clk_src_hubk01:
- return read_clk(priv, 0x08);
- case nv_clk_src_copy:
- return read_clk(priv, 0x09);
- case nv_clk_src_daemon:
- return read_clk(priv, 0x0c);
- case nv_clk_src_vdec:
- return read_clk(priv, 0x0e);
- default:
- nv_error(clk, "invalid clock source %d\n", src);
- return -EINVAL;
- }
-}
-
-static u32
-calc_div(struct nvc0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
-{
- u32 div = min((ref * 2) / freq, (u32)65);
- if (div < 2)
- div = 2;
-
- *ddiv = div - 2;
- return (ref * 2) / div;
-}
-
-static u32
-calc_src(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
-{
- u32 sclk;
-
- /* use one of the fixed frequencies if possible */
- *ddiv = 0x00000000;
- switch (freq) {
- case 27000:
- case 108000:
- *dsrc = 0x00000000;
- if (freq == 108000)
- *dsrc |= 0x00030000;
- return freq;
- case 100000:
- *dsrc = 0x00000002;
- return freq;
- default:
- *dsrc = 0x00000003;
- break;
- }
-
- /* otherwise, calculate the closest divider */
- sclk = read_vco(priv, 0x137160 + (clk * 4));
- if (clk < 7)
- sclk = calc_div(priv, clk, sclk, freq, ddiv);
- return sclk;
-}
-
-static u32
-calc_pll(struct nvc0_clock_priv *priv, int clk, u32 freq, u32 *coef)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll limits;
- int N, M, P, ret;
-
- ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
- if (ret)
- return 0;
-
- limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
- if (!limits.refclk)
- return 0;
-
- ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
- if (ret <= 0)
- return 0;
-
- *coef = (P << 16) | (N << 8) | M;
- return ret;
-}
-
-static int
-calc_clk(struct nvc0_clock_priv *priv,
- struct nouveau_cstate *cstate, int clk, int dom)
-{
- struct nvc0_clock_info *info = &priv->eng[clk];
- u32 freq = cstate->domain[dom];
- u32 src0, div0, div1D, div1P = 0;
- u32 clk0, clk1 = 0;
-
- /* invalid clock domain */
- if (!freq)
- return 0;
-
- /* first possible path, using only dividers */
- clk0 = calc_src(priv, clk, freq, &src0, &div0);
- clk0 = calc_div(priv, clk, clk0, freq, &div1D);
-
- /* see if we can get any closer using PLLs */
- if (clk0 != freq && (0x00004387 & (1 << clk))) {
- if (clk <= 7)
- clk1 = calc_pll(priv, clk, freq, &info->coef);
- else
- clk1 = cstate->domain[nv_clk_src_hubk06];
- clk1 = calc_div(priv, clk, clk1, freq, &div1P);
- }
-
- /* select the method which gets closest to target freq */
- if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
- info->dsrc = src0;
- if (div0) {
- info->ddiv |= 0x80000000;
- info->ddiv |= div0 << 8;
- info->ddiv |= div0;
- }
- if (div1D) {
- info->mdiv |= 0x80000000;
- info->mdiv |= div1D;
- }
- info->ssel = info->coef = 0;
- info->freq = clk0;
- } else {
- if (div1P) {
- info->mdiv |= 0x80000000;
- info->mdiv |= div1P << 8;
- }
- info->ssel = (1 << clk);
- info->freq = clk1;
- }
-
- return 0;
-}
-
-static int
-nvc0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct nvc0_clock_priv *priv = (void *)clk;
- int ret;
-
- if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
- (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
- (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
- (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
- (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
- (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) ||
- (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
- (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
- return ret;
-
- return 0;
-}
-
-static void
-nvc0_clock_prog_0(struct nvc0_clock_priv *priv, int clk)
-{
- struct nvc0_clock_info *info = &priv->eng[clk];
- if (clk < 7 && !info->ssel) {
- nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
- nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
- }
-}
-
-static void
-nvc0_clock_prog_1(struct nvc0_clock_priv *priv, int clk)
-{
- nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
- nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
-}
-
-static void
-nvc0_clock_prog_2(struct nvc0_clock_priv *priv, int clk)
-{
- struct nvc0_clock_info *info = &priv->eng[clk];
- const u32 addr = 0x137000 + (clk * 0x20);
- if (clk <= 7) {
- nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
- nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
- if (info->coef) {
- nv_wr32(priv, addr + 0x04, info->coef);
- nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
- nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
- nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
- }
- }
-}
-
-static void
-nvc0_clock_prog_3(struct nvc0_clock_priv *priv, int clk)
-{
- struct nvc0_clock_info *info = &priv->eng[clk];
- if (info->ssel) {
- nv_mask(priv, 0x137100, (1 << clk), info->ssel);
- nv_wait(priv, 0x137100, (1 << clk), info->ssel);
- }
-}
-
-static void
-nvc0_clock_prog_4(struct nvc0_clock_priv *priv, int clk)
-{
- struct nvc0_clock_info *info = &priv->eng[clk];
- nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
-}
-
-static int
-nvc0_clock_prog(struct nouveau_clock *clk)
-{
- struct nvc0_clock_priv *priv = (void *)clk;
- struct {
- void (*exec)(struct nvc0_clock_priv *, int);
- } stage[] = {
- { nvc0_clock_prog_0 }, /* div programming */
- { nvc0_clock_prog_1 }, /* select div mode */
- { nvc0_clock_prog_2 }, /* (maybe) program pll */
- { nvc0_clock_prog_3 }, /* (maybe) select pll mode */
- { nvc0_clock_prog_4 }, /* final divider */
- };
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(stage); i++) {
- for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
- if (!priv->eng[j].freq)
- continue;
- stage[i].exec(priv, j);
- }
- }
-
- return 0;
-}
-
-static void
-nvc0_clock_tidy(struct nouveau_clock *clk)
-{
- struct nvc0_clock_priv *priv = (void *)clk;
- memset(priv->eng, 0x00, sizeof(priv->eng));
-}
-
-static struct nouveau_clocks
-nvc0_domain[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_href , 0xff },
- { nv_clk_src_hubk06 , 0x00 },
- { nv_clk_src_hubk01 , 0x01 },
- { nv_clk_src_copy , 0x02 },
- { nv_clk_src_gpc , 0x03, 0, "core", 2000 },
- { nv_clk_src_rop , 0x04 },
- { nv_clk_src_mem , 0x05, 0, "memory", 1000 },
- { nv_clk_src_vdec , 0x06 },
- { nv_clk_src_daemon , 0x0a },
- { nv_clk_src_hubk07 , 0x0b },
- { nv_clk_src_max }
-};
-
-static int
-nvc0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, nvc0_domain, NULL, 0,
- false, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.read = nvc0_clock_read;
- priv->base.calc = nvc0_clock_calc;
- priv->base.prog = nvc0_clock_prog;
- priv->base.tidy = nvc0_clock_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_clock_oclass = {
- .handle = NV_SUBDEV(CLOCK, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c
deleted file mode 100644
index 7eccad57512e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/nve0.c
+++ /dev/null
@@ -1,500 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/timer.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-struct nve0_clock_info {
- u32 freq;
- u32 ssel;
- u32 mdiv;
- u32 dsrc;
- u32 ddiv;
- u32 coef;
-};
-
-struct nve0_clock_priv {
- struct nouveau_clock base;
- struct nve0_clock_info eng[16];
-};
-
-static u32 read_div(struct nve0_clock_priv *, int, u32, u32);
-static u32 read_pll(struct nve0_clock_priv *, u32);
-
-static u32
-read_vco(struct nve0_clock_priv *priv, u32 dsrc)
-{
- u32 ssrc = nv_rd32(priv, dsrc);
- if (!(ssrc & 0x00000100))
- return read_pll(priv, 0x00e800);
- return read_pll(priv, 0x00e820);
-}
-
-static u32
-read_pll(struct nve0_clock_priv *priv, u32 pll)
-{
- u32 ctrl = nv_rd32(priv, pll + 0x00);
- u32 coef = nv_rd32(priv, pll + 0x04);
- u32 P = (coef & 0x003f0000) >> 16;
- u32 N = (coef & 0x0000ff00) >> 8;
- u32 M = (coef & 0x000000ff) >> 0;
- u32 sclk;
- u16 fN = 0xf000;
-
- if (!(ctrl & 0x00000001))
- return 0;
-
- switch (pll) {
- case 0x00e800:
- case 0x00e820:
- sclk = nv_device(priv)->crystal;
- P = 1;
- break;
- case 0x132000:
- sclk = read_pll(priv, 0x132020);
- P = (coef & 0x10000000) ? 2 : 1;
- break;
- case 0x132020:
- sclk = read_div(priv, 0, 0x137320, 0x137330);
- fN = nv_rd32(priv, pll + 0x10) >> 16;
- break;
- case 0x137000:
- case 0x137020:
- case 0x137040:
- case 0x1370e0:
- sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
- break;
- default:
- return 0;
- }
-
- if (P == 0)
- P = 1;
-
- sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13);
- return sclk / (M * P);
-}
-
-static u32
-read_div(struct nve0_clock_priv *priv, int doff, u32 dsrc, u32 dctl)
-{
- u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
- u32 sctl = nv_rd32(priv, dctl + (doff * 4));
-
- switch (ssrc & 0x00000003) {
- case 0:
- if ((ssrc & 0x00030000) != 0x00030000)
- return nv_device(priv)->crystal;
- return 108000;
- case 2:
- return 100000;
- case 3:
- if (sctl & 0x80000000) {
- u32 sclk = read_vco(priv, dsrc + (doff * 4));
- u32 sdiv = (sctl & 0x0000003f) + 2;
- return (sclk * 2) / sdiv;
- }
-
- return read_vco(priv, dsrc + (doff * 4));
- default:
- return 0;
- }
-}
-
-static u32
-read_mem(struct nve0_clock_priv *priv)
-{
- switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) {
- case 1: return read_pll(priv, 0x132020);
- case 2: return read_pll(priv, 0x132000);
- default:
- return 0;
- }
-}
-
-static u32
-read_clk(struct nve0_clock_priv *priv, int clk)
-{
- u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
- u32 sclk, sdiv;
-
- if (clk < 7) {
- u32 ssel = nv_rd32(priv, 0x137100);
- if (ssel & (1 << clk)) {
- sclk = read_pll(priv, 0x137000 + (clk * 0x20));
- sdiv = 1;
- } else {
- sclk = read_div(priv, clk, 0x137160, 0x1371d0);
- sdiv = 0;
- }
- } else {
- u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04));
- if ((ssrc & 0x00000003) == 0x00000003) {
- sclk = read_div(priv, clk, 0x137160, 0x1371d0);
- if (ssrc & 0x00000100) {
- if (ssrc & 0x40000000)
- sclk = read_pll(priv, 0x1370e0);
- sdiv = 1;
- } else {
- sdiv = 0;
- }
- } else {
- sclk = read_div(priv, clk, 0x137160, 0x1371d0);
- sdiv = 0;
- }
- }
-
- if (sctl & 0x80000000) {
- if (sdiv)
- sdiv = ((sctl & 0x00003f00) >> 8) + 2;
- else
- sdiv = ((sctl & 0x0000003f) >> 0) + 2;
- return (sclk * 2) / sdiv;
- }
-
- return sclk;
-}
-
-static int
-nve0_clock_read(struct nouveau_clock *clk, enum nv_clk_src src)
-{
- struct nouveau_device *device = nv_device(clk);
- struct nve0_clock_priv *priv = (void *)clk;
-
- switch (src) {
- case nv_clk_src_crystal:
- return device->crystal;
- case nv_clk_src_href:
- return 100000;
- case nv_clk_src_mem:
- return read_mem(priv);
- case nv_clk_src_gpc:
- return read_clk(priv, 0x00);
- case nv_clk_src_rop:
- return read_clk(priv, 0x01);
- case nv_clk_src_hubk07:
- return read_clk(priv, 0x02);
- case nv_clk_src_hubk06:
- return read_clk(priv, 0x07);
- case nv_clk_src_hubk01:
- return read_clk(priv, 0x08);
- case nv_clk_src_daemon:
- return read_clk(priv, 0x0c);
- case nv_clk_src_vdec:
- return read_clk(priv, 0x0e);
- default:
- nv_error(clk, "invalid clock source %d\n", src);
- return -EINVAL;
- }
-}
-
-static u32
-calc_div(struct nve0_clock_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
-{
- u32 div = min((ref * 2) / freq, (u32)65);
- if (div < 2)
- div = 2;
-
- *ddiv = div - 2;
- return (ref * 2) / div;
-}
-
-static u32
-calc_src(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
-{
- u32 sclk;
-
- /* use one of the fixed frequencies if possible */
- *ddiv = 0x00000000;
- switch (freq) {
- case 27000:
- case 108000:
- *dsrc = 0x00000000;
- if (freq == 108000)
- *dsrc |= 0x00030000;
- return freq;
- case 100000:
- *dsrc = 0x00000002;
- return freq;
- default:
- *dsrc = 0x00000003;
- break;
- }
-
- /* otherwise, calculate the closest divider */
- sclk = read_vco(priv, 0x137160 + (clk * 4));
- if (clk < 7)
- sclk = calc_div(priv, clk, sclk, freq, ddiv);
- return sclk;
-}
-
-static u32
-calc_pll(struct nve0_clock_priv *priv, int clk, u32 freq, u32 *coef)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll limits;
- int N, M, P, ret;
-
- ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
- if (ret)
- return 0;
-
- limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
- if (!limits.refclk)
- return 0;
-
- ret = nva3_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
- if (ret <= 0)
- return 0;
-
- *coef = (P << 16) | (N << 8) | M;
- return ret;
-}
-
-static int
-calc_clk(struct nve0_clock_priv *priv,
- struct nouveau_cstate *cstate, int clk, int dom)
-{
- struct nve0_clock_info *info = &priv->eng[clk];
- u32 freq = cstate->domain[dom];
- u32 src0, div0, div1D, div1P = 0;
- u32 clk0, clk1 = 0;
-
- /* invalid clock domain */
- if (!freq)
- return 0;
-
- /* first possible path, using only dividers */
- clk0 = calc_src(priv, clk, freq, &src0, &div0);
- clk0 = calc_div(priv, clk, clk0, freq, &div1D);
-
- /* see if we can get any closer using PLLs */
- if (clk0 != freq && (0x0000ff87 & (1 << clk))) {
- if (clk <= 7)
- clk1 = calc_pll(priv, clk, freq, &info->coef);
- else
- clk1 = cstate->domain[nv_clk_src_hubk06];
- clk1 = calc_div(priv, clk, clk1, freq, &div1P);
- }
-
- /* select the method which gets closest to target freq */
- if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
- info->dsrc = src0;
- if (div0) {
- info->ddiv |= 0x80000000;
- info->ddiv |= div0;
- }
- if (div1D) {
- info->mdiv |= 0x80000000;
- info->mdiv |= div1D;
- }
- info->ssel = 0;
- info->freq = clk0;
- } else {
- if (div1P) {
- info->mdiv |= 0x80000000;
- info->mdiv |= div1P << 8;
- }
- info->ssel = (1 << clk);
- info->dsrc = 0x40000100;
- info->freq = clk1;
- }
-
- return 0;
-}
-
-static int
-nve0_clock_calc(struct nouveau_clock *clk, struct nouveau_cstate *cstate)
-{
- struct nve0_clock_priv *priv = (void *)clk;
- int ret;
-
- if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
- (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
- (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
- (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
- (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
- (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
- (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
- return ret;
-
- return 0;
-}
-
-static void
-nve0_clock_prog_0(struct nve0_clock_priv *priv, int clk)
-{
- struct nve0_clock_info *info = &priv->eng[clk];
- if (!info->ssel) {
- nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv);
- nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
- }
-}
-
-static void
-nve0_clock_prog_1_0(struct nve0_clock_priv *priv, int clk)
-{
- nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
- nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
-}
-
-static void
-nve0_clock_prog_1_1(struct nve0_clock_priv *priv, int clk)
-{
- nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000);
-}
-
-static void
-nve0_clock_prog_2(struct nve0_clock_priv *priv, int clk)
-{
- struct nve0_clock_info *info = &priv->eng[clk];
- const u32 addr = 0x137000 + (clk * 0x20);
- nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
- nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
- if (info->coef) {
- nv_wr32(priv, addr + 0x04, info->coef);
- nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
- nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
- nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
- }
-}
-
-static void
-nve0_clock_prog_3(struct nve0_clock_priv *priv, int clk)
-{
- struct nve0_clock_info *info = &priv->eng[clk];
- if (info->ssel)
- nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv);
- else
- nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv);
-}
-
-static void
-nve0_clock_prog_4_0(struct nve0_clock_priv *priv, int clk)
-{
- struct nve0_clock_info *info = &priv->eng[clk];
- if (info->ssel) {
- nv_mask(priv, 0x137100, (1 << clk), info->ssel);
- nv_wait(priv, 0x137100, (1 << clk), info->ssel);
- }
-}
-
-static void
-nve0_clock_prog_4_1(struct nve0_clock_priv *priv, int clk)
-{
- struct nve0_clock_info *info = &priv->eng[clk];
- if (info->ssel) {
- nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000);
- nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100);
- }
-}
-
-static int
-nve0_clock_prog(struct nouveau_clock *clk)
-{
- struct nve0_clock_priv *priv = (void *)clk;
- struct {
- u32 mask;
- void (*exec)(struct nve0_clock_priv *, int);
- } stage[] = {
- { 0x007f, nve0_clock_prog_0 }, /* div programming */
- { 0x007f, nve0_clock_prog_1_0 }, /* select div mode */
- { 0xff80, nve0_clock_prog_1_1 },
- { 0x00ff, nve0_clock_prog_2 }, /* (maybe) program pll */
- { 0xff80, nve0_clock_prog_3 }, /* final divider */
- { 0x007f, nve0_clock_prog_4_0 }, /* (maybe) select pll mode */
- { 0xff80, nve0_clock_prog_4_1 },
- };
- int i, j;
-
- for (i = 0; i < ARRAY_SIZE(stage); i++) {
- for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
- if (!(stage[i].mask & (1 << j)))
- continue;
- if (!priv->eng[j].freq)
- continue;
- stage[i].exec(priv, j);
- }
- }
-
- return 0;
-}
-
-static void
-nve0_clock_tidy(struct nouveau_clock *clk)
-{
- struct nve0_clock_priv *priv = (void *)clk;
- memset(priv->eng, 0x00, sizeof(priv->eng));
-}
-
-static struct nouveau_clocks
-nve0_domain[] = {
- { nv_clk_src_crystal, 0xff },
- { nv_clk_src_href , 0xff },
- { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
- { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
- { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE },
- { nv_clk_src_mem , 0x03, 0, "memory", 500 },
- { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
- { nv_clk_src_hubk01 , 0x05 },
- { nv_clk_src_vdec , 0x06 },
- { nv_clk_src_daemon , 0x07 },
- { nv_clk_src_max }
-};
-
-static int
-nve0_clock_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_clock_priv *priv;
- int ret;
-
- ret = nouveau_clock_create(parent, engine, oclass, nve0_domain, NULL, 0,
- true, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.read = nve0_clock_read;
- priv->base.calc = nve0_clock_calc;
- priv->base.prog = nve0_clock_prog;
- priv->base.tidy = nve0_clock_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_clock_oclass = {
- .handle = NV_SUBDEV(CLOCK, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_clock_ctor,
- .dtor = _nouveau_clock_dtor,
- .init = _nouveau_clock_init,
- .fini = _nouveau_clock_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h b/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
deleted file mode 100644
index 445b14c33a98..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pll.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NOUVEAU_PLL_H__
-#define __NOUVEAU_PLL_H__
-
-int nv04_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
- int *N1, int *M1, int *N2, int *M2, int *P);
-int nva3_pll_calc(struct nouveau_subdev *, struct nvbios_pll *, u32 freq,
- int *N, int *fN, int *M, int *P);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
deleted file mode 100644
index b47d543ab2e3..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnv04.c
+++ /dev/null
@@ -1,246 +0,0 @@
-/*
- * Copyright 1993-2003 NVIDIA, Corporation
- * Copyright 2007-2009 Stuart Bennett
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION 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 <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-static int
-getMNP_single(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
- int *pN, int *pM, int *pP)
-{
- /* Find M, N and P for a single stage PLL
- *
- * Note that some bioses (NV3x) have lookup tables of precomputed MNP
- * values, but we're too lazy to use those atm
- *
- * "clk" parameter in kHz
- * returns calculated clock
- */
- struct nouveau_bios *bios = nouveau_bios(subdev);
- int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
- int minM = info->vco1.min_m, maxM = info->vco1.max_m;
- int minN = info->vco1.min_n, maxN = info->vco1.max_n;
- int minU = info->vco1.min_inputfreq;
- int maxU = info->vco1.max_inputfreq;
- int minP = info->min_p;
- int maxP = info->max_p_usable;
- int crystal = info->refclk;
- int M, N, thisP, P;
- int clkP, calcclk;
- int delta, bestdelta = INT_MAX;
- int bestclk = 0;
-
- /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
- /* possibly correlated with introduction of 27MHz crystal */
- if (bios->version.major < 0x60) {
- int cv = bios->version.chip;
- if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
- if (clk > 250000)
- maxM = 6;
- if (clk > 340000)
- maxM = 2;
- } else if (cv < 0x40) {
- if (clk > 150000)
- maxM = 6;
- if (clk > 200000)
- maxM = 4;
- if (clk > 340000)
- maxM = 2;
- }
- }
-
- P = 1 << maxP;
- if ((clk * P) < minvco) {
- minvco = clk * maxP;
- maxvco = minvco * 2;
- }
-
- if (clk + clk/200 > maxvco) /* +0.5% */
- maxvco = clk + clk/200;
-
- /* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
- for (thisP = minP; thisP <= maxP; thisP++) {
- P = 1 << thisP;
- clkP = clk * P;
-
- if (clkP < minvco)
- continue;
- if (clkP > maxvco)
- return bestclk;
-
- for (M = minM; M <= maxM; M++) {
- if (crystal/M < minU)
- return bestclk;
- if (crystal/M > maxU)
- continue;
-
- /* add crystal/2 to round better */
- N = (clkP * M + crystal/2) / crystal;
-
- if (N < minN)
- continue;
- if (N > maxN)
- break;
-
- /* more rounding additions */
- calcclk = ((N * crystal + P/2) / P + M/2) / M;
- delta = abs(calcclk - clk);
- /* we do an exhaustive search rather than terminating
- * on an optimality condition...
- */
- if (delta < bestdelta) {
- bestdelta = delta;
- bestclk = calcclk;
- *pN = N;
- *pM = M;
- *pP = thisP;
- if (delta == 0) /* except this one */
- return bestclk;
- }
- }
- }
-
- return bestclk;
-}
-
-static int
-getMNP_double(struct nouveau_subdev *subdev, struct nvbios_pll *info, int clk,
- int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
-{
- /* Find M, N and P for a two stage PLL
- *
- * Note that some bioses (NV30+) have lookup tables of precomputed MNP
- * values, but we're too lazy to use those atm
- *
- * "clk" parameter in kHz
- * returns calculated clock
- */
- int chip_version = nouveau_bios(subdev)->version.chip;
- int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
- int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
- int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
- int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq;
- int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m;
- int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n;
- int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m;
- int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n;
- int maxlog2P = info->max_p_usable;
- int crystal = info->refclk;
- bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
- int M1, N1, M2, N2, log2P;
- int clkP, calcclk1, calcclk2, calcclkout;
- int delta, bestdelta = INT_MAX;
- int bestclk = 0;
-
- int vco2 = (maxvco2 - maxvco2/200) / 2;
- for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++)
- ;
- clkP = clk << log2P;
-
- if (maxvco2 < clk + clk/200) /* +0.5% */
- maxvco2 = clk + clk/200;
-
- for (M1 = minM1; M1 <= maxM1; M1++) {
- if (crystal/M1 < minU1)
- return bestclk;
- if (crystal/M1 > maxU1)
- continue;
-
- for (N1 = minN1; N1 <= maxN1; N1++) {
- calcclk1 = crystal * N1 / M1;
- if (calcclk1 < minvco1)
- continue;
- if (calcclk1 > maxvco1)
- break;
-
- for (M2 = minM2; M2 <= maxM2; M2++) {
- if (calcclk1/M2 < minU2)
- break;
- if (calcclk1/M2 > maxU2)
- continue;
-
- /* add calcclk1/2 to round better */
- N2 = (clkP * M2 + calcclk1/2) / calcclk1;
- if (N2 < minN2)
- continue;
- if (N2 > maxN2)
- break;
-
- if (!fixedgain2) {
- if (chip_version < 0x60)
- if (N2/M2 < 4 || N2/M2 > 10)
- continue;
-
- calcclk2 = calcclk1 * N2 / M2;
- if (calcclk2 < minvco2)
- break;
- if (calcclk2 > maxvco2)
- continue;
- } else
- calcclk2 = calcclk1;
-
- calcclkout = calcclk2 >> log2P;
- delta = abs(calcclkout - clk);
- /* we do an exhaustive search rather than terminating
- * on an optimality condition...
- */
- if (delta < bestdelta) {
- bestdelta = delta;
- bestclk = calcclkout;
- *pN1 = N1;
- *pM1 = M1;
- *pN2 = N2;
- *pM2 = M2;
- *pP = log2P;
- if (delta == 0) /* except this one */
- return bestclk;
- }
- }
- }
- }
-
- return bestclk;
-}
-
-int
-nv04_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info, u32 freq,
- int *N1, int *M1, int *N2, int *M2, int *P)
-{
- int ret;
-
- if (!info->vco2.max_freq || !N2) {
- ret = getMNP_single(subdev, info, freq, N1, M1, P);
- if (N2) {
- *N2 = 1;
- *M2 = 1;
- }
- } else {
- ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
- }
-
- if (!ret)
- nv_error(subdev, "unable to compute acceptable pll values\n");
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c b/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
deleted file mode 100644
index 8eca457c2814..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/pllnva3.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/clock.h>
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-
-#include "pll.h"
-
-int
-nva3_pll_calc(struct nouveau_subdev *subdev, struct nvbios_pll *info,
- u32 freq, int *pN, int *pfN, int *pM, int *P)
-{
- u32 best_err = ~0, err;
- int M, lM, hM, N, fN;
-
- *P = info->vco1.max_freq / freq;
- if (*P > info->max_p)
- *P = info->max_p;
- if (*P < info->min_p)
- *P = info->min_p;
-
- lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq;
- lM = max(lM, (int)info->vco1.min_m);
- hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq;
- hM = min(hM, (int)info->vco1.max_m);
- lM = min(lM, hM);
-
- for (M = lM; M <= hM; M++) {
- u32 tmp = freq * *P * M;
- N = tmp / info->refclk;
- fN = tmp % info->refclk;
-
- if (!pfN) {
- if (fN >= info->refclk / 2)
- N++;
- } else {
- if (fN < info->refclk / 2)
- N--;
- fN = tmp - (N * info->refclk);
- }
-
- if (N < info->vco1.min_n)
- continue;
- if (N > info->vco1.max_n)
- break;
-
- err = abs(freq - (info->refclk * N / M / *P));
- if (err < best_err) {
- best_err = err;
- *pN = N;
- *pM = M;
- }
-
- if (pfN) {
- *pfN = ((fN << 13) + info->refclk / 2) / info->refclk;
- *pfN = (*pfN - 4096) & 0xffff;
- return freq;
- }
- }
-
- if (unlikely(best_err == ~0)) {
- nv_error(subdev, "unable to find matching pll values\n");
- return -EINVAL;
- }
-
- return info->refclk * *pN / *pM / *P;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h b/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h
deleted file mode 100644
index fb33f06ebd59..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/clock/seq.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __NVKM_CLK_SEQ_H__
-#define __NVKM_CLK_SEQ_H__
-
-#include <subdev/bus.h>
-#include <subdev/bus/hwsq.h>
-
-#define clk_init(s,p) hwsq_init(&(s)->base, (p))
-#define clk_exec(s,e) hwsq_exec(&(s)->base, (e))
-#define clk_have(s,r) ((s)->r_##r.addr != 0x000000)
-#define clk_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r)
-#define clk_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
-#define clk_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define clk_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d))
-#define clk_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d))
-#define clk_nsec(s,n) hwsq_nsec(&(s)->base, (n))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
deleted file mode 100644
index 0e45cee82463..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/base.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-
-#include <subdev/vga.h>
-
-#include "priv.h"
-
-int
-_nouveau_devinit_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_devinit *devinit = (void *)object;
-
- /* force full reinit on resume */
- if (suspend)
- devinit->post = true;
-
- /* unlock the extended vga crtc regs */
- nv_lockvgac(devinit, false);
-
- return nouveau_subdev_fini(&devinit->base, suspend);
-}
-
-int
-_nouveau_devinit_init(struct nouveau_object *object)
-{
- struct nouveau_devinit_impl *impl = (void *)object->oclass;
- struct nouveau_devinit *devinit = (void *)object;
- int ret;
-
- ret = nouveau_subdev_init(&devinit->base);
- if (ret)
- return ret;
-
- ret = impl->post(&devinit->base, devinit->post);
- if (ret)
- return ret;
-
- if (impl->disable)
- nv_device(devinit)->disable_mask |= impl->disable(devinit);
- return 0;
-}
-
-void
-_nouveau_devinit_dtor(struct nouveau_object *object)
-{
- struct nouveau_devinit *devinit = (void *)object;
-
- /* lock crtc regs */
- nv_lockvgac(devinit, true);
-
- nouveau_subdev_destroy(&devinit->base);
-}
-
-int
-nouveau_devinit_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int size, void **pobject)
-{
- struct nouveau_devinit_impl *impl = (void *)oclass;
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_devinit *devinit;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "DEVINIT",
- "init", size, pobject);
- devinit = *pobject;
- if (ret)
- return ret;
-
- devinit->post = nouveau_boolopt(device->cfgopt, "NvForcePost", false);
- devinit->meminit = impl->meminit;
- devinit->pll_set = impl->pll_set;
- devinit->mmio = impl->mmio;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
deleted file mode 100644
index 6103484fea72..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/fbmem.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <core/device.h>
-
-#include <subdev/fb/regsnv04.h>
-
-#define NV04_PFB_DEBUG_0 0x00100080
-# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001
-# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010
-# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00
-# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000
-# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000
-# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000
-# define NV04_PFB_DEBUG_0_CASOE 0x00100000
-# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000
-# define NV04_PFB_DEBUG_0_REFINC 0x20000000
-# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000
-#define NV04_PFB_CFG0 0x00100200
-# define NV04_PFB_CFG0_SCRAMBLE 0x20000000
-#define NV04_PFB_CFG1 0x00100204
-#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i))
-
-#define NV10_PFB_REFCTRL 0x00100210
-# define NV10_PFB_REFCTRL_VALID_1 (1 << 31)
-
-static inline struct io_mapping *
-fbmem_init(struct nouveau_device *dev)
-{
- return io_mapping_create_wc(nv_device_resource_start(dev, 1),
- nv_device_resource_len(dev, 1));
-}
-
-static inline void
-fbmem_fini(struct io_mapping *fb)
-{
- io_mapping_free(fb);
-}
-
-static inline u32
-fbmem_peek(struct io_mapping *fb, u32 off)
-{
- u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
- u32 val = ioread32(p + (off & ~PAGE_MASK));
- io_mapping_unmap_atomic(p);
- return val;
-}
-
-static inline void
-fbmem_poke(struct io_mapping *fb, u32 off, u32 val)
-{
- u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
- iowrite32(val, p + (off & ~PAGE_MASK));
- wmb();
- io_mapping_unmap_atomic(p);
-}
-
-static inline bool
-fbmem_readback(struct io_mapping *fb, u32 off, u32 val)
-{
- fbmem_poke(fb, off, val);
- return val == fbmem_peek(fb, off);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c
deleted file mode 100644
index 4ba43d6a1ec8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm107.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-u64
-gm107_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r021c00 = nv_rd32(priv, 0x021c00);
- u32 r021c04 = nv_rd32(priv, 0x021c04);
- u64 disable = 0ULL;
-
- if (r021c00 & 0x00000001)
- disable |= (1ULL << NVDEV_ENGINE_COPY0);
- if (r021c00 & 0x00000004)
- disable |= (1ULL << NVDEV_ENGINE_COPY2);
- if (r021c04 & 0x00000001)
- disable |= (1ULL << NVDEV_ENGINE_DISP);
-
- return disable;
-}
-
-struct nouveau_oclass *
-gm107_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x07),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nvc0_devinit_pll_set,
- .disable = gm107_devinit_disable,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c
deleted file mode 100644
index e44a86662a2a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/gm204.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pmu.h>
-
-#include "nv50.h"
-
-static void
-pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- int i;
-
- nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu);
- for (i = 0; i < len; i += 4) {
- if ((i & 0xff) == 0)
- nv_wr32(priv, 0x10a188, (pmu + i) >> 8);
- nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i));
- }
-
- while (i & 0xff) {
- nv_wr32(priv, 0x10a184, 0x00000000);
- i += 4;
- }
-}
-
-static void
-pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- int i;
-
- nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu);
- for (i = 0; i < len; i += 4)
- nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i));
-}
-
-static u32
-pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi)
-{
- nv_wr32(priv, 0x10a1c0, argp);
- nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi);
- return nv_rd32(priv, 0x10a1c4);
-}
-
-static void
-pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr)
-{
- nv_wr32(priv, 0x10a104, init_addr);
- nv_wr32(priv, 0x10a10c, 0x00000000);
- nv_wr32(priv, 0x10a100, 0x00000002);
-}
-
-static int
-pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post,
- u32 *init_addr_pmu, u32 *args_addr_pmu)
-{
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pmuR pmu;
-
- if (!nvbios_pmuRm(bios, type, &pmu)) {
- nv_error(priv, "VBIOS PMU fuc %02x not found\n", type);
- return -EINVAL;
- }
-
- if (!post)
- return 0;
-
- pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
- pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
- pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
-
- if (init_addr_pmu) {
- *init_addr_pmu = pmu.init_addr_pmu;
- *args_addr_pmu = pmu.args_addr_pmu;
- return 0;
- }
-
- return pmu_exec(priv, pmu.init_addr_pmu), 0;
-}
-
-static int
-gm204_devinit_post(struct nouveau_subdev *subdev, bool post)
-{
- struct nv50_devinit_priv *priv = (void *)nouveau_devinit(subdev);
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct bit_entry bit_I;
- u32 init, args;
- int ret;
-
- if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 ||
- bit_I.length < 0x1c) {
- nv_error(priv, "VBIOS PMU init data not found\n");
- return -EINVAL;
- }
-
- /* reset PMU and load init table parser ucode */
- if (post) {
- nv_mask(priv, 0x000200, 0x00002000, 0x00000000);
- nv_mask(priv, 0x000200, 0x00002000, 0x00002000);
- nv_rd32(priv, 0x000200);
- while (nv_rd32(priv, 0x10a10c) & 0x00000006) {
- }
- }
-
- ret = pmu_load(priv, 0x04, post, &init, &args);
- if (ret)
- return ret;
-
- /* upload first chunk of init data */
- if (post) {
- u32 pmu = pmu_args(priv, args + 0x08, 0x08);
- u32 img = nv_ro16(bios, bit_I.offset + 0x14);
- u32 len = nv_ro16(bios, bit_I.offset + 0x16);
- pmu_data(priv, pmu, img, len);
- }
-
- /* upload second chunk of init data */
- if (post) {
- u32 pmu = pmu_args(priv, args + 0x08, 0x10);
- u32 img = nv_ro16(bios, bit_I.offset + 0x18);
- u32 len = nv_ro16(bios, bit_I.offset + 0x1a);
- pmu_data(priv, pmu, img, len);
- }
-
- /* execute init tables */
- if (post) {
- nv_wr32(priv, 0x10a040, 0x00005000);
- pmu_exec(priv, init);
- while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) {
- }
- }
-
- /* load and execute some other ucode image (bios therm?) */
- return pmu_load(priv, 0x01, post, NULL, NULL);
-}
-
-struct nouveau_oclass *
-gm204_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x07),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nvc0_devinit_pll_set,
- .disable = gm107_devinit_disable,
- .post = gm204_devinit_post,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
deleted file mode 100644
index 65651c50f6ea..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.c
+++ /dev/null
@@ -1,468 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <subdev/vga.h>
-
-#include "fbmem.h"
-#include "nv04.h"
-
-static void
-nv04_devinit_meminit(struct nouveau_devinit *devinit)
-{
- struct nv04_devinit_priv *priv = (void *)devinit;
- u32 patt = 0xdeadbeef;
- struct io_mapping *fb;
- int i;
-
- /* Map the framebuffer aperture */
- fb = fbmem_init(nv_device(priv));
- if (!fb) {
- nv_error(priv, "failed to map fb\n");
- return;
- }
-
- /* Sequencer and refresh off */
- nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
- nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF);
-
- nv_mask(priv, NV04_PFB_BOOT_0, ~0,
- NV04_PFB_BOOT_0_RAM_AMOUNT_16MB |
- NV04_PFB_BOOT_0_RAM_WIDTH_128 |
- NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT);
-
- for (i = 0; i < 4; i++)
- fbmem_poke(fb, 4 * i, patt);
-
- fbmem_poke(fb, 0x400000, patt + 1);
-
- if (fbmem_peek(fb, 0) == patt + 1) {
- nv_mask(priv, NV04_PFB_BOOT_0,
- NV04_PFB_BOOT_0_RAM_TYPE,
- NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT);
- nv_mask(priv, NV04_PFB_DEBUG_0,
- NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-
- for (i = 0; i < 4; i++)
- fbmem_poke(fb, 4 * i, patt);
-
- if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff))
- nv_mask(priv, NV04_PFB_BOOT_0,
- NV04_PFB_BOOT_0_RAM_WIDTH_128 |
- NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
- } else
- if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) {
- nv_mask(priv, NV04_PFB_BOOT_0,
- NV04_PFB_BOOT_0_RAM_WIDTH_128 |
- NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
- } else
- if (fbmem_peek(fb, 0) != patt) {
- if (fbmem_readback(fb, 0x800000, patt))
- nv_mask(priv, NV04_PFB_BOOT_0,
- NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
- else
- nv_mask(priv, NV04_PFB_BOOT_0,
- NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-
- nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
- NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT);
- } else
- if (!fbmem_readback(fb, 0x800000, patt)) {
- nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-
- }
-
- /* Refresh on, sequencer on */
- nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
- nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
- fbmem_fini(fb);
-}
-
-static int
-powerctrl_1_shift(int chip_version, int reg)
-{
- int shift = -4;
-
- if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
- return shift;
-
- switch (reg) {
- case 0x680520:
- shift += 4;
- case 0x680508:
- shift += 4;
- case 0x680504:
- shift += 4;
- case 0x680500:
- shift += 4;
- }
-
- /*
- * the shift for vpll regs is only used for nv3x chips with a single
- * stage pll
- */
- if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
- chip_version == 0x36 || chip_version >= 0x40))
- shift = -4;
-
- return shift;
-}
-
-void
-setPLL_single(struct nouveau_devinit *devinit, u32 reg,
- struct nouveau_pll_vals *pv)
-{
- int chip_version = nouveau_bios(devinit)->version.chip;
- uint32_t oldpll = nv_rd32(devinit, reg);
- int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
- uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
- uint32_t saved_powerctrl_1 = 0;
- int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
-
- if (oldpll == pll)
- return; /* already set */
-
- if (shift_powerctrl_1 >= 0) {
- saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
- nv_wr32(devinit, 0x001584,
- (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
- 1 << shift_powerctrl_1);
- }
-
- if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
- /* upclock -- write new post divider first */
- nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
- else
- /* downclock -- write new NM first */
- nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
-
- if ((chip_version < 0x17 || chip_version == 0x1a) &&
- chip_version != 0x11)
- /* wait a bit on older chips */
- msleep(64);
- nv_rd32(devinit, reg);
-
- /* then write the other half as well */
- nv_wr32(devinit, reg, pll);
-
- if (shift_powerctrl_1 >= 0)
- nv_wr32(devinit, 0x001584, saved_powerctrl_1);
-}
-
-static uint32_t
-new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
-{
- bool head_a = (reg1 == 0x680508);
-
- if (ss) /* single stage pll mode */
- ramdac580 |= head_a ? 0x00000100 : 0x10000000;
- else
- ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
-
- return ramdac580;
-}
-
-void
-setPLL_double_highregs(struct nouveau_devinit *devinit, u32 reg1,
- struct nouveau_pll_vals *pv)
-{
- int chip_version = nouveau_bios(devinit)->version.chip;
- bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
- uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
- uint32_t oldpll1 = nv_rd32(devinit, reg1);
- uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0;
- uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
- uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
- uint32_t oldramdac580 = 0, ramdac580 = 0;
- bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */
- uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
- int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
-
- /* model specific additions to generic pll1 and pll2 set up above */
- if (nv3035) {
- pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
- (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
- pll2 = 0;
- }
- if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
- oldramdac580 = nv_rd32(devinit, 0x680580);
- ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
- if (oldramdac580 != ramdac580)
- oldpll1 = ~0; /* force mismatch */
- if (single_stage)
- /* magic value used by nvidia in single stage mode */
- pll2 |= 0x011f;
- }
- if (chip_version > 0x70)
- /* magic bits set by the blob (but not the bios) on g71-73 */
- pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
-
- if (oldpll1 == pll1 && oldpll2 == pll2)
- return; /* already set */
-
- if (shift_powerctrl_1 >= 0) {
- saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
- nv_wr32(devinit, 0x001584,
- (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
- 1 << shift_powerctrl_1);
- }
-
- if (chip_version >= 0x40) {
- int shift_c040 = 14;
-
- switch (reg1) {
- case 0x680504:
- shift_c040 += 2;
- case 0x680500:
- shift_c040 += 2;
- case 0x680520:
- shift_c040 += 2;
- case 0x680508:
- shift_c040 += 2;
- }
-
- savedc040 = nv_rd32(devinit, 0xc040);
- if (shift_c040 != 14)
- nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
- }
-
- if (oldramdac580 != ramdac580)
- nv_wr32(devinit, 0x680580, ramdac580);
-
- if (!nv3035)
- nv_wr32(devinit, reg2, pll2);
- nv_wr32(devinit, reg1, pll1);
-
- if (shift_powerctrl_1 >= 0)
- nv_wr32(devinit, 0x001584, saved_powerctrl_1);
- if (chip_version >= 0x40)
- nv_wr32(devinit, 0xc040, savedc040);
-}
-
-void
-setPLL_double_lowregs(struct nouveau_devinit *devinit, u32 NMNMreg,
- struct nouveau_pll_vals *pv)
-{
- /* When setting PLLs, there is a merry game of disabling and enabling
- * various bits of hardware during the process. This function is a
- * synthesis of six nv4x traces, nearly each card doing a subtly
- * different thing. With luck all the necessary bits for each card are
- * combined herein. Without luck it deviates from each card's formula
- * so as to not work on any :)
- */
-
- uint32_t Preg = NMNMreg - 4;
- bool mpll = Preg == 0x4020;
- uint32_t oldPval = nv_rd32(devinit, Preg);
- uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
- uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
- 0xc << 28 | pv->log2P << 16;
- uint32_t saved4600 = 0;
- /* some cards have different maskc040s */
- uint32_t maskc040 = ~(3 << 14), savedc040;
- bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
-
- if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
- return;
-
- if (Preg == 0x4000)
- maskc040 = ~0x333;
- if (Preg == 0x4058)
- maskc040 = ~(0xc << 24);
-
- if (mpll) {
- struct nvbios_pll info;
- uint8_t Pval2;
-
- if (nvbios_pll_parse(nouveau_bios(devinit), Preg, &info))
- return;
-
- Pval2 = pv->log2P + info.bias_p;
- if (Pval2 > info.max_p)
- Pval2 = info.max_p;
- Pval |= 1 << 28 | Pval2 << 20;
-
- saved4600 = nv_rd32(devinit, 0x4600);
- nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
- }
- if (single_stage)
- Pval |= mpll ? 1 << 12 : 1 << 8;
-
- nv_wr32(devinit, Preg, oldPval | 1 << 28);
- nv_wr32(devinit, Preg, Pval & ~(4 << 28));
- if (mpll) {
- Pval |= 8 << 20;
- nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
- nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
- }
-
- savedc040 = nv_rd32(devinit, 0xc040);
- nv_wr32(devinit, 0xc040, savedc040 & maskc040);
-
- nv_wr32(devinit, NMNMreg, NMNM);
- if (NMNMreg == 0x4024)
- nv_wr32(devinit, 0x403c, NMNM);
-
- nv_wr32(devinit, Preg, Pval);
- if (mpll) {
- Pval &= ~(8 << 20);
- nv_wr32(devinit, 0x4020, Pval);
- nv_wr32(devinit, 0x4038, Pval);
- nv_wr32(devinit, 0x4600, saved4600);
- }
-
- nv_wr32(devinit, 0xc040, savedc040);
-
- if (mpll) {
- nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
- nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
- }
-}
-
-int
-nv04_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
- struct nouveau_bios *bios = nouveau_bios(devinit);
- struct nouveau_pll_vals pv;
- struct nvbios_pll info;
- int cv = bios->version.chip;
- int N1, M1, N2, M2, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
- if (ret)
- return ret;
-
- ret = nv04_pll_calc(nv_subdev(devinit), &info, freq,
- &N1, &M1, &N2, &M2, &P);
- if (!ret)
- return -EINVAL;
-
- pv.refclk = info.refclk;
- pv.N1 = N1;
- pv.M1 = M1;
- pv.N2 = N2;
- pv.M2 = M2;
- pv.log2P = P;
-
- if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
- cv >= 0x40) {
- if (type > 0x405c)
- setPLL_double_highregs(devinit, type, &pv);
- else
- setPLL_double_lowregs(devinit, type, &pv);
- } else
- setPLL_single(devinit, type, &pv);
-
- return 0;
-}
-
-int
-nv04_devinit_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv04_devinit_priv *priv = (void *)object;
- int ret;
-
- /* make i2c busses accessible */
- nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
-
- ret = nouveau_devinit_fini(&priv->base, suspend);
- if (ret)
- return ret;
-
- /* unslave crtcs */
- if (priv->owner < 0)
- priv->owner = nv_rdvgaowner(priv);
- nv_wrvgaowner(priv, 0);
-
- return 0;
-}
-
-int
-nv04_devinit_init(struct nouveau_object *object)
-{
- struct nv04_devinit_priv *priv = (void *)object;
-
- if (!priv->base.post) {
- u32 htotal = nv_rdvgac(priv, 0, 0x06);
- htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8;
- htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4;
- htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10;
- htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11;
- if (!htotal) {
- nv_info(priv, "adaptor not initialised\n");
- priv->base.post = true;
- }
- }
-
- return nouveau_devinit_init(&priv->base);
-}
-
-void
-nv04_devinit_dtor(struct nouveau_object *object)
-{
- struct nv04_devinit_priv *priv = (void *)object;
-
- /* restore vga owner saved at first init */
- nv_wrvgaowner(priv, priv->owner);
-
- nouveau_devinit_destroy(&priv->base);
-}
-
-int
-nv04_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_devinit_priv *priv;
- int ret;
-
- ret = nouveau_devinit_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->owner = -1;
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_devinit_ctor,
- .dtor = nv04_devinit_dtor,
- .init = nv04_devinit_init,
- .fini = nv04_devinit_fini,
- },
- .meminit = nv04_devinit_meminit,
- .pll_set = nv04_devinit_pll_set,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h
deleted file mode 100644
index 23470a57510c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv04.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVKM_DEVINIT_NV04_H__
-#define __NVKM_DEVINIT_NV04_H__
-
-#include "priv.h"
-
-struct nv04_devinit_priv {
- struct nouveau_devinit base;
- u8 owner;
-};
-
-int nv04_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv04_devinit_dtor(struct nouveau_object *);
-int nv04_devinit_init(struct nouveau_object *);
-int nv04_devinit_fini(struct nouveau_object *, bool);
-int nv04_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-void setPLL_single(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-void setPLL_double_highregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-void setPLL_double_lowregs(struct nouveau_devinit *, u32, struct nouveau_pll_vals *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
deleted file mode 100644
index a2007a3efc4d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv05.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bmp.h>
-#include <subdev/vga.h>
-
-#include "fbmem.h"
-#include "nv04.h"
-
-static void
-nv05_devinit_meminit(struct nouveau_devinit *devinit)
-{
- static const u8 default_config_tab[][2] = {
- { 0x24, 0x00 },
- { 0x28, 0x00 },
- { 0x24, 0x01 },
- { 0x1f, 0x00 },
- { 0x0f, 0x00 },
- { 0x17, 0x00 },
- { 0x06, 0x00 },
- { 0x00, 0x00 }
- };
- struct nv04_devinit_priv *priv = (void *)devinit;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct io_mapping *fb;
- u32 patt = 0xdeadbeef;
- u16 data;
- u8 strap, ramcfg[2];
- int i, v;
-
- /* Map the framebuffer aperture */
- fb = fbmem_init(nv_device(priv));
- if (!fb) {
- nv_error(priv, "failed to map fb\n");
- return;
- }
-
- strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2;
- if ((data = bmp_mem_init_table(bios))) {
- ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0);
- ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1);
- } else {
- ramcfg[0] = default_config_tab[strap][0];
- ramcfg[1] = default_config_tab[strap][1];
- }
-
- /* Sequencer off */
- nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
-
- if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE)
- goto out;
-
- nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
-
- /* If present load the hardcoded scrambling table */
- if (data) {
- for (i = 0, data += 0x10; i < 8; i++, data += 4) {
- u32 scramble = nv_ro32(bios, data);
- nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble);
- }
- }
-
- /* Set memory type/width/length defaults depending on the straps */
- nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]);
-
- if (ramcfg[1] & 0x80)
- nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE);
-
- nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20);
- nv_mask(priv, NV04_PFB_CFG1, 0, 1);
-
- /* Probe memory bus width */
- for (i = 0; i < 4; i++)
- fbmem_poke(fb, 4 * i, patt);
-
- if (fbmem_peek(fb, 0xc) != patt)
- nv_mask(priv, NV04_PFB_BOOT_0,
- NV04_PFB_BOOT_0_RAM_WIDTH_128, 0);
-
- /* Probe memory length */
- v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT;
-
- if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB &&
- (!fbmem_readback(fb, 0x1000000, ++patt) ||
- !fbmem_readback(fb, 0, ++patt)))
- nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_16MB);
-
- if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB &&
- !fbmem_readback(fb, 0x800000, ++patt))
- nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
-
- if (!fbmem_readback(fb, 0x400000, ++patt))
- nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
- NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
-
-out:
- /* Sequencer on */
- nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
- fbmem_fini(fb);
-}
-
-struct nouveau_oclass *
-nv05_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x05),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_devinit_ctor,
- .dtor = nv04_devinit_dtor,
- .init = nv04_devinit_init,
- .fini = nv04_devinit_fini,
- },
- .meminit = nv05_devinit_meminit,
- .pll_set = nv04_devinit_pll_set,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
deleted file mode 100644
index 178b46f79b50..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv10.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include <subdev/vga.h>
-
-#include "fbmem.h"
-#include "nv04.h"
-
-static void
-nv10_devinit_meminit(struct nouveau_devinit *devinit)
-{
- struct nv04_devinit_priv *priv = (void *)devinit;
- static const int mem_width[] = { 0x10, 0x00, 0x20 };
- int mem_width_count;
- uint32_t patt = 0xdeadbeef;
- struct io_mapping *fb;
- int i, j, k;
-
- if (nv_device(priv)->card_type >= NV_11 &&
- nv_device(priv)->chipset >= 0x17)
- mem_width_count = 3;
- else
- mem_width_count = 2;
-
- /* Map the framebuffer aperture */
- fb = fbmem_init(nv_device(priv));
- if (!fb) {
- nv_error(priv, "failed to map fb\n");
- return;
- }
-
- nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
-
- /* Probe memory bus width */
- for (i = 0; i < mem_width_count; i++) {
- nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]);
-
- for (j = 0; j < 4; j++) {
- for (k = 0; k < 4; k++)
- fbmem_poke(fb, 0x1c, 0);
-
- fbmem_poke(fb, 0x1c, patt);
- fbmem_poke(fb, 0x3c, 0);
-
- if (fbmem_peek(fb, 0x1c) == patt)
- goto mem_width_found;
- }
- }
-
-mem_width_found:
- patt <<= 1;
-
- /* Probe amount of installed memory */
- for (i = 0; i < 4; i++) {
- int off = nv_rd32(priv, 0x10020c) - 0x100000;
-
- fbmem_poke(fb, off, patt);
- fbmem_poke(fb, 0, 0);
-
- fbmem_peek(fb, 0);
- fbmem_peek(fb, 0);
- fbmem_peek(fb, 0);
- fbmem_peek(fb, 0);
-
- if (fbmem_peek(fb, off) == patt)
- goto amount_found;
- }
-
- /* IC missing - disable the upper half memory space. */
- nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0);
-
-amount_found:
- fbmem_fini(fb);
-}
-
-struct nouveau_oclass *
-nv10_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x10),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_devinit_ctor,
- .dtor = nv04_devinit_dtor,
- .init = nv04_devinit_init,
- .fini = nv04_devinit_fini,
- },
- .meminit = nv10_devinit_meminit,
- .pll_set = nv04_devinit_pll_set,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
deleted file mode 100644
index 995dd97af3e9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv1a.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv1a_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x1a),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_devinit_ctor,
- .dtor = nv04_devinit_dtor,
- .init = nv04_devinit_init,
- .fini = nv04_devinit_fini,
- },
- .pll_set = nv04_devinit_pll_set,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
deleted file mode 100644
index 915089fb46f7..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv20.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-#include "fbmem.h"
-
-static void
-nv20_devinit_meminit(struct nouveau_devinit *devinit)
-{
- struct nv04_devinit_priv *priv = (void *)devinit;
- struct nouveau_device *device = nv_device(priv);
- uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900);
- uint32_t amount, off;
- struct io_mapping *fb;
-
- /* Map the framebuffer aperture */
- fb = fbmem_init(nv_device(priv));
- if (!fb) {
- nv_error(priv, "failed to map fb\n");
- return;
- }
-
- nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
-
- /* Allow full addressing */
- nv_mask(priv, NV04_PFB_CFG0, 0, mask);
-
- amount = nv_rd32(priv, 0x10020c);
- for (off = amount; off > 0x2000000; off -= 0x2000000)
- fbmem_poke(fb, off - 4, off);
-
- amount = nv_rd32(priv, 0x10020c);
- if (amount != fbmem_peek(fb, amount - 4))
- /* IC missing - disable the upper half memory space. */
- nv_mask(priv, NV04_PFB_CFG0, mask, 0);
-
- fbmem_fini(fb);
-}
-
-struct nouveau_oclass *
-nv20_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x20),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_devinit_ctor,
- .dtor = nv04_devinit_dtor,
- .init = nv04_devinit_init,
- .fini = nv04_devinit_fini,
- },
- .meminit = nv20_devinit_meminit,
- .pll_set = nv04_devinit_pll_set,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
deleted file mode 100644
index 968334d1dca4..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.c
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/disp.h>
-#include <subdev/bios/init.h>
-#include <subdev/ibus.h>
-#include <subdev/vga.h>
-
-#include "nv50.h"
-
-int
-nv50_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll info;
- int N1, M1, N2, M2, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type, &info);
- if (ret) {
- nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
- return ret;
- }
-
- ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P);
- if (!ret) {
- nv_error(devinit, "failed pll calculation\n");
- return ret;
- }
-
- switch (info.type) {
- case PLL_VPLL0:
- case PLL_VPLL1:
- nv_wr32(priv, info.reg + 0, 0x10000611);
- nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
- nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) |
- (M2 << 16) | N2);
- break;
- case PLL_MEMORY:
- nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
- (info.bias_p << 19) |
- (P << 16));
- nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
- break;
- default:
- nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
- nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
- break;
- }
-
- return 0;
-}
-
-static u64
-nv50_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r001540 = nv_rd32(priv, 0x001540);
- u64 disable = 0ULL;
-
- if (!(r001540 & 0x40000000))
- disable |= (1ULL << NVDEV_ENGINE_MPEG);
-
- return disable;
-}
-
-int
-nv50_devinit_init(struct nouveau_object *object)
-{
- struct nouveau_bios *bios = nouveau_bios(object);
- struct nouveau_ibus *ibus = nouveau_ibus(object);
- struct nv50_devinit_priv *priv = (void *)object;
- struct nvbios_outp info;
- struct dcb_output outp;
- u8 ver = 0xff, hdr, cnt, len;
- int ret, i = 0;
-
- if (!priv->base.post) {
- if (!nv_rdvgac(priv, 0, 0x00) &&
- !nv_rdvgac(priv, 0, 0x1a)) {
- nv_info(priv, "adaptor not initialised\n");
- priv->base.post = true;
- }
- }
-
- /* some boards appear to require certain priv register timeouts
- * to be bumped before runing devinit scripts. not a clue why
- * the vbios engineers didn't make the scripts just work...
- */
- if (priv->base.post && ibus)
- nv_ofuncs(ibus)->init(nv_object(ibus));
-
- ret = nouveau_devinit_init(&priv->base);
- if (ret)
- return ret;
-
- /* if we ran the init tables, we have to execute the first script
- * pointer of each dcb entry's display encoder table in order
- * to properly initialise each encoder.
- */
- while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
- if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
- &ver, &hdr, &cnt, &len, &info)) {
- struct nvbios_init init = {
- .subdev = nv_subdev(priv),
- .bios = bios,
- .offset = info.script[0],
- .outp = &outp,
- .crtc = -1,
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
- i++;
- }
-
- return 0;
-}
-
-int
-nv50_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_devinit_priv *priv;
- int ret;
-
- ret = nouveau_devinit_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nv50_devinit_pll_set,
- .disable = nv50_devinit_disable,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
deleted file mode 100644
index f412bb7f780e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv50.h
+++ /dev/null
@@ -1,23 +0,0 @@
-#ifndef __NVKM_DEVINIT_NV50_H__
-#define __NVKM_DEVINIT_NV50_H__
-
-#include "priv.h"
-
-struct nv50_devinit_priv {
- struct nouveau_devinit base;
- u32 r001540;
-};
-
-int nv50_devinit_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-int nv50_devinit_init(struct nouveau_object *);
-int nv50_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-int nva3_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-int nvc0_devinit_pll_set(struct nouveau_devinit *, u32, u32);
-
-u64 gm107_devinit_disable(struct nouveau_devinit *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c
deleted file mode 100644
index a7c80ded77cd..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv84.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static u64
-nv84_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r001540 = nv_rd32(priv, 0x001540);
- u32 r00154c = nv_rd32(priv, 0x00154c);
- u64 disable = 0ULL;
-
- if (!(r001540 & 0x40000000)) {
- disable |= (1ULL << NVDEV_ENGINE_MPEG);
- disable |= (1ULL << NVDEV_ENGINE_VP);
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- disable |= (1ULL << NVDEV_ENGINE_CRYPT);
- }
-
- if (!(r00154c & 0x00000004))
- disable |= (1ULL << NVDEV_ENGINE_DISP);
- if (!(r00154c & 0x00000020))
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- if (!(r00154c & 0x00000040))
- disable |= (1ULL << NVDEV_ENGINE_CRYPT);
-
- return disable;
-}
-
-struct nouveau_oclass *
-nv84_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x84),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nv50_devinit_pll_set,
- .disable = nv84_devinit_disable,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c
deleted file mode 100644
index a773253a17f6..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nv98.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static u64
-nv98_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r001540 = nv_rd32(priv, 0x001540);
- u32 r00154c = nv_rd32(priv, 0x00154c);
- u64 disable = 0ULL;
-
- if (!(r001540 & 0x40000000)) {
- disable |= (1ULL << NVDEV_ENGINE_VP);
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- disable |= (1ULL << NVDEV_ENGINE_PPP);
- }
-
- if (!(r00154c & 0x00000004))
- disable |= (1ULL << NVDEV_ENGINE_DISP);
- if (!(r00154c & 0x00000020))
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- if (!(r00154c & 0x00000040))
- disable |= (1ULL << NVDEV_ENGINE_CRYPT);
-
- return disable;
-}
-
-struct nouveau_oclass *
-nv98_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0x98),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nv50_devinit_pll_set,
- .disable = nv98_devinit_disable,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
deleted file mode 100644
index b9cd9e53f760..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nva3.c
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-int
-nva3_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll info;
- int N, fN, M, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type, &info);
- if (ret)
- return ret;
-
- ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
- if (ret < 0)
- return ret;
-
- switch (info.type) {
- case PLL_VPLL0:
- case PLL_VPLL1:
- nv_wr32(priv, info.reg + 0, 0x50000610);
- nv_mask(priv, info.reg + 4, 0x003fffff,
- (P << 16) | (M << 8) | N);
- nv_wr32(priv, info.reg + 8, fN);
- break;
- default:
- nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static u64
-nva3_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r001540 = nv_rd32(priv, 0x001540);
- u32 r00154c = nv_rd32(priv, 0x00154c);
- u64 disable = 0ULL;
-
- if (!(r001540 & 0x40000000)) {
- disable |= (1ULL << NVDEV_ENGINE_VP);
- disable |= (1ULL << NVDEV_ENGINE_PPP);
- }
-
- if (!(r00154c & 0x00000004))
- disable |= (1ULL << NVDEV_ENGINE_DISP);
- if (!(r00154c & 0x00000020))
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- if (!(r00154c & 0x00000200))
- disable |= (1ULL << NVDEV_ENGINE_COPY0);
-
- return disable;
-}
-
-static u32
-nva3_devinit_mmio_part[] = {
- 0x100720, 0x1008bc, 4,
- 0x100a20, 0x100adc, 4,
- 0x100d80, 0x100ddc, 4,
- 0x110000, 0x110f9c, 4,
- 0x111000, 0x11103c, 8,
- 0x111080, 0x1110fc, 4,
- 0x111120, 0x1111fc, 4,
- 0x111300, 0x1114bc, 4,
- 0,
-};
-
-static u32
-nva3_devinit_mmio(struct nouveau_devinit *devinit, u32 addr)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 *mmio = nva3_devinit_mmio_part;
-
- /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP
- * instructions which touch registers that may not even exist on
- * some configurations (Quadro 400), which causes the register
- * interface to screw up for some amount of time after attempting to
- * write to one of these, and results in all sorts of things going
- * horribly wrong.
- *
- * the binary driver avoids touching these registers at all, however,
- * the video bios doesn't care and does what the scripts say. it's
- * presumed that the io-port access to priv registers isn't effected
- * by the screw-up bug mentioned above.
- *
- * really, a new opcode should've been invented to handle these
- * requirements, but whatever, it's too late for that now.
- */
- while (mmio[0]) {
- if (addr >= mmio[0] && addr <= mmio[1]) {
- u32 part = (addr / mmio[2]) & 7;
- if (!priv->r001540)
- priv->r001540 = nv_rd32(priv, 0x001540);
- if (part >= hweight8((priv->r001540 >> 16) & 0xff))
- return ~0;
- return addr;
- }
- mmio += 3;
- }
-
- return addr;
-}
-
-struct nouveau_oclass *
-nva3_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0xa3),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nva3_devinit_pll_set,
- .disable = nva3_devinit_disable,
- .mmio = nva3_devinit_mmio,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c
deleted file mode 100644
index 3729846a8e5c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvaf.c
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static u64
-nvaf_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r001540 = nv_rd32(priv, 0x001540);
- u32 r00154c = nv_rd32(priv, 0x00154c);
- u64 disable = 0;
-
- if (!(r001540 & 0x40000000)) {
- disable |= (1ULL << NVDEV_ENGINE_VP);
- disable |= (1ULL << NVDEV_ENGINE_PPP);
- }
-
- if (!(r00154c & 0x00000004))
- disable |= (1ULL << NVDEV_ENGINE_DISP);
- if (!(r00154c & 0x00000020))
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- if (!(r00154c & 0x00000040))
- disable |= (1ULL << NVDEV_ENGINE_VIC);
- if (!(r00154c & 0x00000200))
- disable |= (1ULL << NVDEV_ENGINE_COPY0);
-
- return disable;
-}
-
-struct nouveau_oclass *
-nvaf_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0xaf),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nva3_devinit_pll_set,
- .disable = nvaf_devinit_disable,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
deleted file mode 100644
index 80bd7f5eda3d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/nvc0.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-int
-nvc0_devinit_pll_set(struct nouveau_devinit *devinit, u32 type, u32 freq)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- struct nouveau_bios *bios = nouveau_bios(priv);
- struct nvbios_pll info;
- int N, fN, M, P;
- int ret;
-
- ret = nvbios_pll_parse(bios, type, &info);
- if (ret)
- return ret;
-
- ret = nva3_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
- if (ret < 0)
- return ret;
-
- switch (info.type) {
- case PLL_VPLL0:
- case PLL_VPLL1:
- case PLL_VPLL2:
- case PLL_VPLL3:
- nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
- nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
- nv_wr32(priv, info.reg + 0x10, fN << 16);
- break;
- default:
- nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
- ret = -EINVAL;
- break;
- }
-
- return ret;
-}
-
-static u64
-nvc0_devinit_disable(struct nouveau_devinit *devinit)
-{
- struct nv50_devinit_priv *priv = (void *)devinit;
- u32 r022500 = nv_rd32(priv, 0x022500);
- u64 disable = 0ULL;
-
- if (r022500 & 0x00000001)
- disable |= (1ULL << NVDEV_ENGINE_DISP);
-
- if (r022500 & 0x00000002) {
- disable |= (1ULL << NVDEV_ENGINE_VP);
- disable |= (1ULL << NVDEV_ENGINE_PPP);
- }
-
- if (r022500 & 0x00000004)
- disable |= (1ULL << NVDEV_ENGINE_BSP);
- if (r022500 & 0x00000008)
- disable |= (1ULL << NVDEV_ENGINE_VENC);
- if (r022500 & 0x00000100)
- disable |= (1ULL << NVDEV_ENGINE_COPY0);
- if (r022500 & 0x00000200)
- disable |= (1ULL << NVDEV_ENGINE_COPY1);
-
- return disable;
-}
-
-static int
-nvc0_devinit_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_devinit_priv *priv;
- int ret;
-
- ret = nouveau_devinit_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- if (nv_rd32(priv, 0x022500) & 0x00000001)
- priv->base.post = true;
- return 0;
-}
-
-struct nouveau_oclass *
-nvc0_devinit_oclass = &(struct nouveau_devinit_impl) {
- .base.handle = NV_SUBDEV(DEVINIT, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_devinit_ctor,
- .dtor = _nouveau_devinit_dtor,
- .init = nv50_devinit_init,
- .fini = _nouveau_devinit_fini,
- },
- .pll_set = nvc0_devinit_pll_set,
- .disable = nvc0_devinit_disable,
- .post = nvbios_init,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
deleted file mode 100644
index cbcd51852472..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/devinit/priv.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __NVKM_DEVINIT_PRIV_H__
-#define __NVKM_DEVINIT_PRIV_H__
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/init.h>
-#include <subdev/clock/pll.h>
-#include <subdev/devinit.h>
-
-struct nouveau_devinit_impl {
- struct nouveau_oclass base;
- void (*meminit)(struct nouveau_devinit *);
- int (*pll_set)(struct nouveau_devinit *, u32 type, u32 freq);
- u64 (*disable)(struct nouveau_devinit *);
- u32 (*mmio)(struct nouveau_devinit *, u32);
- int (*post)(struct nouveau_subdev *, bool);
-};
-
-#define nouveau_devinit_create(p,e,o,d) \
- nouveau_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_devinit_destroy(p) ({ \
- struct nouveau_devinit *d = (p); \
- _nouveau_devinit_dtor(nv_object(d)); \
-})
-#define nouveau_devinit_init(p) ({ \
- struct nouveau_devinit *d = (p); \
- _nouveau_devinit_init(nv_object(d)); \
-})
-#define nouveau_devinit_fini(p,s) ({ \
- struct nouveau_devinit *d = (p); \
- _nouveau_devinit_fini(nv_object(d), (s)); \
-})
-
-int nouveau_devinit_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_devinit_dtor(struct nouveau_object *);
-int _nouveau_devinit_init(struct nouveau_object *);
-int _nouveau_devinit_fini(struct nouveau_object *, bool suspend);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c b/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
deleted file mode 100644
index c866148c440f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/base.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/M0203.h>
-
-#include "priv.h"
-
-int
-nouveau_fb_bios_memtype(struct nouveau_bios *bios)
-{
- const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
- struct nvbios_M0203E M0203E;
- u8 ver, hdr;
-
- if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
- switch (M0203E.type) {
- case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2;
- case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3;
- case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3;
- case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5;
- default:
- nv_warn(bios, "M0203E type %02x\n", M0203E.type);
- return NV_MEM_TYPE_UNKNOWN;
- }
- }
-
- nv_warn(bios, "M0203E not matched!\n");
- return NV_MEM_TYPE_UNKNOWN;
-}
-
-int
-_nouveau_fb_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_fb *pfb = (void *)object;
- int ret;
-
- ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
- if (ret && suspend)
- return ret;
-
- return nouveau_subdev_fini(&pfb->base, suspend);
-}
-
-int
-_nouveau_fb_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- int ret, i;
-
- ret = nouveau_subdev_init(&pfb->base);
- if (ret)
- return ret;
-
- ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
- if (ret)
- return ret;
-
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
-
- return 0;
-}
-
-void
-_nouveau_fb_dtor(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object;
- int i;
-
- for (i = 0; i < pfb->tile.regions; i++)
- pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
- nouveau_mm_fini(&pfb->tags);
- nouveau_mm_fini(&pfb->vram);
-
- nouveau_object_ref(NULL, (struct nouveau_object **)&pfb->ram);
- nouveau_subdev_destroy(&pfb->base);
-}
-
-int
-nouveau_fb_create_(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- struct nouveau_fb_impl *impl = (void *)oclass;
- static const char *name[] = {
- [NV_MEM_TYPE_UNKNOWN] = "unknown",
- [NV_MEM_TYPE_STOLEN ] = "stolen system memory",
- [NV_MEM_TYPE_SGRAM ] = "SGRAM",
- [NV_MEM_TYPE_SDRAM ] = "SDRAM",
- [NV_MEM_TYPE_DDR1 ] = "DDR1",
- [NV_MEM_TYPE_DDR2 ] = "DDR2",
- [NV_MEM_TYPE_DDR3 ] = "DDR3",
- [NV_MEM_TYPE_GDDR2 ] = "GDDR2",
- [NV_MEM_TYPE_GDDR3 ] = "GDDR3",
- [NV_MEM_TYPE_GDDR4 ] = "GDDR4",
- [NV_MEM_TYPE_GDDR5 ] = "GDDR5",
- };
- struct nouveau_object *ram;
- struct nouveau_fb *pfb;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
- length, pobject);
- pfb = *pobject;
- if (ret)
- return ret;
-
- pfb->memtype_valid = impl->memtype;
-
- ret = nouveau_object_ctor(nv_object(pfb), nv_object(pfb),
- impl->ram, NULL, 0, &ram);
- if (ret) {
- nv_fatal(pfb, "error detecting memory configuration!!\n");
- return ret;
- }
-
- atomic_dec(&ram->parent->refcount);
- atomic_dec(&ram->engine->refcount);
- pfb->ram = (void *)ram;
-
- if (!nouveau_mm_initialised(&pfb->vram)) {
- ret = nouveau_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
- if (ret)
- return ret;
- }
-
- if (!nouveau_mm_initialised(&pfb->tags)) {
- ret = nouveau_mm_init(&pfb->tags, 0, pfb->ram->tags ?
- ++pfb->ram->tags : 0, 1);
- if (ret)
- return ret;
- }
-
- nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
- nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
- nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c
deleted file mode 100644
index d85a25d027ee..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr3.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- * Roy Spliet <rspliet@eclipso.eu>
- */
-
-#include <subdev/bios.h>
-#include "priv.h"
-
-struct ramxlat {
- int id;
- u8 enc;
-};
-
-static inline int
-ramxlat(const struct ramxlat *xlat, int id)
-{
- while (xlat->id >= 0) {
- if (xlat->id == id)
- return xlat->enc;
- xlat++;
- }
- return -EINVAL;
-}
-
-static const struct ramxlat
-ramgddr3_cl_lo[] = {
- { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 },
- /* the below are mentioned in some, but not all, gddr3 docs */
- { 12, 4 }, { 13, 5 }, { 14, 6 },
- /* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
- /* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
- * { 15, 11 }, */
- { -1 }
-};
-
-static const struct ramxlat
-ramgddr3_cl_hi[] = {
- { 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
- { 16, 0 }, { 17, 1 },
- { -1 }
-};
-
-static const struct ramxlat
-ramgddr3_wr_lo[] = {
- { 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
- { 11, 0 },
- /* the below are mentioned in some, but not all, gddr3 docs */
- { 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 },
- { -1 }
-};
-
-int
-nouveau_gddr3_calc(struct nouveau_ram *ram)
-{
- int CL, WR, CWL, DLL = 0, ODT = 0, hi;
-
- switch (ram->next->bios.timing_ver) {
- case 0x10:
- CWL = ram->next->bios.timing_10_CWL;
- CL = ram->next->bios.timing_10_CL;
- WR = ram->next->bios.timing_10_WR;
- DLL = !ram->next->bios.ramcfg_10_DLLoff;
- ODT = ram->next->bios.timing_10_ODT;
- break;
- case 0x20:
- CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
- CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
- WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
- /* XXX: Get these values from the VBIOS instead */
- DLL = !(ram->mr[1] & 0x1);
- ODT = (ram->mr[1] & 0x004) >> 2 |
- (ram->mr[1] & 0x040) >> 5 |
- (ram->mr[1] & 0x200) >> 7;
- break;
- default:
- return -ENOSYS;
- }
-
- hi = ram->mr[2] & 0x1;
- CL = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
- WR = ramxlat(ramgddr3_wr_lo, WR);
- if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
- return -EINVAL;
-
- ram->mr[0] &= ~0xf74;
- ram->mr[0] |= (CWL & 0x07) << 9;
- ram->mr[0] |= (CL & 0x07) << 4;
- ram->mr[0] |= (CL & 0x08) >> 1;
-
- ram->mr[1] &= ~0x3fc;
- ram->mr[1] |= (ODT & 0x03) << 2;
- ram->mr[1] |= (ODT & 0x03) << 8;
- ram->mr[1] |= (WR & 0x03) << 4;
- ram->mr[1] |= (WR & 0x04) << 5;
- ram->mr[1] |= !DLL << 6;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
deleted file mode 100644
index 7fbbe05d5c60..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gddr5.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include <subdev/bios.h>
-#include "priv.h"
-
-/* binary driver only executes this path if the condition (a) is true
- * for any configuration (combination of rammap+ramcfg+timing) that
- * can be reached on a given card. for now, we will execute the branch
- * unconditionally in the hope that a "false everywhere" in the bios
- * tables doesn't actually mean "don't touch this".
- */
-#define NOTE00(a) 1
-
-int
-nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts)
-{
- int pd, lf, xd, vh, vr, vo, l3;
- int WL, CL, WR, at[2], dt, ds;
- int rq = ram->freq < 1000000; /* XXX */
-
- switch (ram->next->bios.ramcfg_ver) {
- case 0x11:
- pd = ram->next->bios.ramcfg_11_01_80;
- lf = ram->next->bios.ramcfg_11_01_40;
- xd = !ram->next->bios.ramcfg_11_01_20;
- vh = ram->next->bios.ramcfg_11_02_10;
- vr = ram->next->bios.ramcfg_11_02_04;
- vo = ram->next->bios.ramcfg_11_06;
- l3 = !ram->next->bios.ramcfg_11_07_02;
- break;
- default:
- return -ENOSYS;
- }
-
- switch (ram->next->bios.timing_ver) {
- case 0x20:
- WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
- CL = (ram->next->bios.timing[1] & 0x0000001f);
- WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
- at[0] = ram->next->bios.timing_20_2e_c0;
- at[1] = ram->next->bios.timing_20_2e_30;
- dt = ram->next->bios.timing_20_2e_03;
- ds = ram->next->bios.timing_20_2f_03;
- break;
- default:
- return -ENOSYS;
- }
-
- if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35)
- return -EINVAL;
- CL -= 5;
- WR -= 4;
-
- ram->mr[0] &= ~0xf7f;
- ram->mr[0] |= (WR & 0x0f) << 8;
- ram->mr[0] |= (CL & 0x0f) << 3;
- ram->mr[0] |= (WL & 0x07) << 0;
-
- ram->mr[1] &= ~0x0bf;
- ram->mr[1] |= (xd & 0x01) << 7;
- ram->mr[1] |= (at[0] & 0x03) << 4;
- ram->mr[1] |= (dt & 0x03) << 2;
- ram->mr[1] |= (ds & 0x03) << 0;
-
- /* this seems wrong, alternate field used for the broadcast
- * on nuts vs non-nuts configs.. meh, it matches for now.
- */
- ram->mr1_nuts = ram->mr[1];
- if (nuts) {
- ram->mr[1] &= ~0x030;
- ram->mr[1] |= (at[1] & 0x03) << 4;
- }
-
- ram->mr[3] &= ~0x020;
- ram->mr[3] |= (rq & 0x01) << 5;
-
- ram->mr[5] &= ~0x004;
- ram->mr[5] |= (l3 << 2);
-
- if (!vo)
- vo = (ram->mr[6] & 0xff0) >> 4;
- if (ram->mr[6] & 0x001)
- pd = 1; /* binary driver does this.. bug? */
- ram->mr[6] &= ~0xff1;
- ram->mr[6] |= (vo & 0xff) << 4;
- ram->mr[6] |= (pd & 0x01) << 0;
-
- if (NOTE00(vr)) {
- ram->mr[7] &= ~0x300;
- ram->mr[7] |= (vr & 0x03) << 8;
- }
- ram->mr[7] &= ~0x088;
- ram->mr[7] |= (vh & 0x01) << 7;
- ram->mr[7] |= (lf & 0x01) << 3;
-
- ram->mr[8] &= ~0x003;
- ram->mr[8] |= (WR & 0x10) >> 3;
- ram->mr[8] |= (CL & 0x10) >> 4;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c
deleted file mode 100644
index fde42e4d1b56..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gk20a.c
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "nvc0.h"
-
-struct gk20a_fb_priv {
- struct nouveau_fb base;
-};
-
-static int
-gk20a_fb_init(struct nouveau_object *object)
-{
- struct gk20a_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
- return 0;
-}
-
-static int
-gk20a_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gk20a_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-gk20a_fb_oclass = &(struct nouveau_fb_impl) {
- .base.handle = NV_SUBDEV(FB, 0xea),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gk20a_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = gk20a_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .memtype = nvc0_fb_memtype_valid,
- .ram = &gk20a_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c
deleted file mode 100644
index c4840aedc2dc..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/gm107.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-struct nouveau_oclass *
-gm107_fb_oclass = &(struct nouveau_fb_impl) {
- .base.handle = NV_SUBDEV(FB, 0x07),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_fb_ctor,
- .dtor = nvc0_fb_dtor,
- .init = nvc0_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .memtype = nvc0_fb_memtype_valid,
- .ram = &gm107_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
deleted file mode 100644
index 8309fe33fe84..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.c
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-#define NV04_PFB_CFG0 0x00100200
-
-bool
-nv04_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
-{
- if (!(tile_flags & 0xff00))
- return true;
-
- return false;
-}
-
-static int
-nv04_fb_init(struct nouveau_object *object)
-{
- struct nv04_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
- * nvidia reading PFB_CFG_0, then writing back its original value.
- * (which was 0x701114 in this case)
- */
- nv_wr32(priv, NV04_PFB_CFG0, 0x1114);
- return 0;
-}
-
-int
-nv04_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_fb_impl *impl = (void *)oclass;
- struct nv04_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.tile.regions = impl->tile.regions;
- priv->base.tile.init = impl->tile.init;
- priv->base.tile.comp = impl->tile.comp;
- priv->base.tile.fini = impl->tile.fini;
- priv->base.tile.prog = impl->tile.prog;
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x04),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv04_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv04_ram_oclass,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h
deleted file mode 100644
index 06ce71f87a74..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv04.h
+++ /dev/null
@@ -1,55 +0,0 @@
-#ifndef __NVKM_FB_NV04_H__
-#define __NVKM_FB_NV04_H__
-
-#include "priv.h"
-
-struct nv04_fb_priv {
- struct nouveau_fb base;
-};
-
-int nv04_fb_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-struct nv04_fb_impl {
- struct nouveau_fb_impl base;
- struct {
- int regions;
- void (*init)(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
- void (*comp)(struct nouveau_fb *, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *);
- void (*fini)(struct nouveau_fb *, int i,
- struct nouveau_fb_tile *);
- void (*prog)(struct nouveau_fb *, int i,
- struct nouveau_fb_tile *);
- } tile;
-};
-
-void nv10_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv10_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv10_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv20_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-void nv20_fb_tile_fini(struct nouveau_fb *, int i, struct nouveau_fb_tile *);
-void nv20_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv30_fb_init(struct nouveau_object *);
-void nv30_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-void nv40_fb_tile_comp(struct nouveau_fb *, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *);
-
-int nv41_fb_init(struct nouveau_object *);
-void nv41_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-int nv44_fb_init(struct nouveau_object *);
-void nv44_fb_tile_prog(struct nouveau_fb *, int, struct nouveau_fb_tile *);
-
-void nv46_fb_tile_init(struct nouveau_fb *, int i, u32 addr, u32 size,
- u32 pitch, u32 flags, struct nouveau_fb_tile *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
deleted file mode 100644
index ffb7ec6d97aa..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv10.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-void
-nv10_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- tile->addr = 0x80000000 | addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
-}
-
-void
-nv10_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- tile->addr = 0;
- tile->limit = 0;
- tile->pitch = 0;
- tile->zcomp = 0;
-}
-
-void
-nv10_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
- nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
- nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100240 + (i * 0x10));
-}
-
-struct nouveau_oclass *
-nv10_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x10),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = _nouveau_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv10_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv10_fb_tile_init,
- .tile.fini = nv10_fb_tile_fini,
- .tile.prog = nv10_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
deleted file mode 100644
index 265d1253624a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv1a.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv1a_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x1a),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = _nouveau_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv1a_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv10_fb_tile_init,
- .tile.fini = nv10_fb_tile_fini,
- .tile.prog = nv10_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
deleted file mode 100644
index 2209ade63339..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv20.c
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-void
-nv20_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- tile->addr = 0x00000001 | addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
- if (flags & 4) {
- pfb->tile.comp(pfb, i, size, flags, tile);
- tile->addr |= 2;
- }
-}
-
-static void
-nv20_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
- if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
- else tile->zcomp = 0x04000000; /* Z24S8 */
- tile->zcomp |= tile->tag->offset;
- tile->zcomp |= 0x80000000; /* enable */
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x08000000;
-#endif
- }
-}
-
-void
-nv20_fb_tile_fini(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- tile->addr = 0;
- tile->limit = 0;
- tile->pitch = 0;
- tile->zcomp = 0;
- nouveau_mm_free(&pfb->tags, &tile->tag);
-}
-
-void
-nv20_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
- nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
- nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100240 + (i * 0x10));
- nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp);
-}
-
-struct nouveau_oclass *
-nv20_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x20),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = _nouveau_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv20_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv20_fb_tile_init,
- .tile.comp = nv20_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
deleted file mode 100644
index e2a66c355c50..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv25.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv25_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
- if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
- else tile->zcomp = 0x00200000; /* Z24S8 */
- tile->zcomp |= tile->tag->offset;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x01000000;
-#endif
- }
-}
-
-struct nouveau_oclass *
-nv25_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x25),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = _nouveau_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv20_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv20_fb_tile_init,
- .tile.comp = nv25_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
deleted file mode 100644
index cbec402ba5b9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv30.c
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-void
-nv30_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- /* for performance, select alternate bank offset for zeta */
- if (!(flags & 4)) {
- tile->addr = (0 << 4);
- } else {
- if (pfb->tile.comp) /* z compression */
- pfb->tile.comp(pfb, i, size, flags, tile);
- tile->addr = (1 << 4);
- }
-
- tile->addr |= 0x00000001; /* enable */
- tile->addr |= addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
-}
-
-static void
-nv30_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
- if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
- else tile->zcomp |= 0x02000000; /* Z24S8 */
- tile->zcomp |= ((tile->tag->offset ) >> 6);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 12;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x10000000;
-#endif
- }
-}
-
-static int
-calc_bias(struct nv04_fb_priv *priv, int k, int i, int j)
-{
- struct nouveau_device *device = nv_device(priv);
- int b = (device->chipset > 0x30 ?
- nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
- 0) & 0xf;
-
- return 2 * (b & 0x8 ? b - 0x10 : b);
-}
-
-static int
-calc_ref(struct nv04_fb_priv *priv, int l, int k, int i)
-{
- int j, x = 0;
-
- for (j = 0; j < 4; j++) {
- int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j);
-
- x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
- }
-
- return x;
-}
-
-int
-nv30_fb_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nv04_fb_priv *priv = (void *)object;
- int ret, i, j;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- /* Init the memory timing regs at 0x10037c/0x1003ac */
- if (device->chipset == 0x30 ||
- device->chipset == 0x31 ||
- device->chipset == 0x35) {
- /* Related to ROP count */
- int n = (device->chipset == 0x31 ? 2 : 4);
- int l = nv_rd32(priv, 0x1003d0);
-
- for (i = 0; i < n; i++) {
- for (j = 0; j < 3; j++)
- nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j,
- calc_ref(priv, l, 0, j));
-
- for (j = 0; j < 2; j++)
- nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j,
- calc_ref(priv, l, 1, j));
- }
- }
-
- return 0;
-}
-
-struct nouveau_oclass *
-nv30_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x30),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv30_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv20_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv30_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
deleted file mode 100644
index b2cf8c69fb2e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv35.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv35_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
- if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
- else tile->zcomp |= 0x08000000; /* Z24S8 */
- tile->zcomp |= ((tile->tag->offset ) >> 6);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 13;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x40000000;
-#endif
- }
-}
-
-struct nouveau_oclass *
-nv35_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x35),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv30_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv20_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv35_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
deleted file mode 100644
index b4cdae2a3b2f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv36.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv36_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x40);
- u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
- if (!nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
- if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
- else tile->zcomp |= 0x20000000; /* Z24S8 */
- tile->zcomp |= ((tile->tag->offset ) >> 6);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 14;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x80000000;
-#endif
- }
-}
-
-struct nouveau_oclass *
-nv36_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x36),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv30_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv20_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv36_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
deleted file mode 100644
index 52814258c212..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.c
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-void
-nv40_fb_tile_comp(struct nouveau_fb *pfb, int i, u32 size, u32 flags,
- struct nouveau_fb_tile *tile)
-{
- u32 tiles = DIV_ROUND_UP(size, 0x80);
- u32 tags = round_up(tiles / pfb->ram->parts, 0x100);
- if ( (flags & 2) &&
- !nouveau_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
- tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
- tile->zcomp |= ((tile->tag->offset ) >> 8);
- tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
-#ifdef __BIG_ENDIAN
- tile->zcomp |= 0x40000000;
-#endif
- }
-}
-
-static int
-nv40_fb_init(struct nouveau_object *object)
-{
- struct nv04_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
- return 0;
-}
-
-struct nouveau_oclass *
-nv40_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x40),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv40_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv40_ram_oclass,
- .tile.regions = 8,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv40_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv20_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h
deleted file mode 100644
index 581f808527f2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv40.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __NVKM_FB_NV40_H__
-#define __NVKM_FB_NV40_H__
-
-#include "priv.h"
-
-struct nv40_ram {
- struct nouveau_ram base;
- u32 ctrl;
- u32 coef;
-};
-
-
-int nv40_ram_calc(struct nouveau_fb *, u32);
-int nv40_ram_prog(struct nouveau_fb *);
-void nv40_ram_tidy(struct nouveau_fb *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
deleted file mode 100644
index b239a8615599..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv41.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-void
-nv41_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
- nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
- nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100600 + (i * 0x10));
- nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp);
-}
-
-int
-nv41_fb_init(struct nouveau_object *object)
-{
- struct nv04_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x100800, 0x00000001);
- return 0;
-}
-
-struct nouveau_oclass *
-nv41_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x41),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv41_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv41_ram_oclass,
- .tile.regions = 12,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv40_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv41_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
deleted file mode 100644
index d8478208a681..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv44.c
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-static void
-nv44_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- tile->addr = 0x00000001; /* mode = vram */
- tile->addr |= addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
-}
-
-void
-nv44_fb_tile_prog(struct nouveau_fb *pfb, int i, struct nouveau_fb_tile *tile)
-{
- nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
- nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
- nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
- nv_rd32(pfb, 0x100600 + (i * 0x10));
-}
-
-int
-nv44_fb_init(struct nouveau_object *object)
-{
- struct nv04_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x100850, 0x80000000);
- nv_wr32(priv, 0x100800, 0x00000001);
- return 0;
-}
-
-struct nouveau_oclass *
-nv44_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x44),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv44_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv44_ram_oclass,
- .tile.regions = 12,
- .tile.init = nv44_fb_tile_init,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv44_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
deleted file mode 100644
index a5b77514d35b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv46.c
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-void
-nv46_fb_tile_init(struct nouveau_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
- u32 flags, struct nouveau_fb_tile *tile)
-{
- /* for performance, select alternate bank offset for zeta */
- if (!(flags & 4)) tile->addr = (0 << 3);
- else tile->addr = (1 << 3);
-
- tile->addr |= 0x00000001; /* mode = vram */
- tile->addr |= addr;
- tile->limit = max(1u, addr + size) - 1;
- tile->pitch = pitch;
-}
-
-struct nouveau_oclass *
-nv46_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x46),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv44_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv44_ram_oclass,
- .tile.regions = 15,
- .tile.init = nv46_fb_tile_init,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv44_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
deleted file mode 100644
index 3bea142376bc..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv47.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv47_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x47),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv41_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv41_ram_oclass,
- .tile.regions = 15,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv40_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv41_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
deleted file mode 100644
index 666cbd5d47f5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv49.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv49_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x49),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv41_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv49_ram_oclass,
- .tile.regions = 15,
- .tile.init = nv30_fb_tile_init,
- .tile.comp = nv40_fb_tile_comp,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv41_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
deleted file mode 100644
index 42e64f364ec1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv4e.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2010 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv4e_fb_oclass = &(struct nv04_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x4e),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_fb_ctor,
- .dtor = _nouveau_fb_dtor,
- .init = nv44_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv04_fb_memtype_valid,
- .base.ram = &nv4e_ram_oclass,
- .tile.regions = 12,
- .tile.init = nv46_fb_tile_init,
- .tile.fini = nv20_fb_tile_fini,
- .tile.prog = nv44_fb_tile_prog,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
deleted file mode 100644
index 4150b0d10af8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.c
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/client.h>
-#include <core/enum.h>
-#include <core/engctx.h>
-#include <core/object.h>
-
-#include <subdev/bios.h>
-
-#include "nv50.h"
-
-int
-nv50_fb_memtype[0x80] = {
- 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
- 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
- 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
-};
-
-bool
-nv50_fb_memtype_valid(struct nouveau_fb *pfb, u32 memtype)
-{
- return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
-}
-
-static const struct nouveau_enum vm_dispatch_subclients[] = {
- { 0x00000000, "GRCTX", NULL },
- { 0x00000001, "NOTIFY", NULL },
- { 0x00000002, "QUERY", NULL },
- { 0x00000003, "COND", NULL },
- { 0x00000004, "M2M_IN", NULL },
- { 0x00000005, "M2M_OUT", NULL },
- { 0x00000006, "M2M_NOTIFY", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_ccache_subclients[] = {
- { 0x00000000, "CB", NULL },
- { 0x00000001, "TIC", NULL },
- { 0x00000002, "TSC", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_prop_subclients[] = {
- { 0x00000000, "RT0", NULL },
- { 0x00000001, "RT1", NULL },
- { 0x00000002, "RT2", NULL },
- { 0x00000003, "RT3", NULL },
- { 0x00000004, "RT4", NULL },
- { 0x00000005, "RT5", NULL },
- { 0x00000006, "RT6", NULL },
- { 0x00000007, "RT7", NULL },
- { 0x00000008, "ZETA", NULL },
- { 0x00000009, "LOCAL", NULL },
- { 0x0000000a, "GLOBAL", NULL },
- { 0x0000000b, "STACK", NULL },
- { 0x0000000c, "DST2D", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_pfifo_subclients[] = {
- { 0x00000000, "PUSHBUF", NULL },
- { 0x00000001, "SEMAPHORE", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_bar_subclients[] = {
- { 0x00000000, "FB", NULL },
- { 0x00000001, "IN", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_client[] = {
- { 0x00000000, "STRMOUT", NULL },
- { 0x00000003, "DISPATCH", vm_dispatch_subclients },
- { 0x00000004, "PFIFO_WRITE", NULL },
- { 0x00000005, "CCACHE", vm_ccache_subclients },
- { 0x00000006, "PPPP", NULL },
- { 0x00000007, "CLIPID", NULL },
- { 0x00000008, "PFIFO_READ", NULL },
- { 0x00000009, "VFETCH", NULL },
- { 0x0000000a, "TEXTURE", NULL },
- { 0x0000000b, "PROP", vm_prop_subclients },
- { 0x0000000c, "PVP", NULL },
- { 0x0000000d, "PBSP", NULL },
- { 0x0000000e, "PCRYPT", NULL },
- { 0x0000000f, "PCOUNTER", NULL },
- { 0x00000011, "PDAEMON", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_engine[] = {
- { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
- { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
- { 0x00000004, "PEEPHOLE", NULL },
- { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
- { 0x00000006, "BAR", vm_bar_subclients },
- { 0x00000008, "PPPP", NULL, NVDEV_ENGINE_PPP },
- { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
- { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
- { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CRYPT },
- { 0x0000000b, "PCOUNTER", NULL },
- { 0x0000000c, "SEMAPHORE_BG", NULL },
- { 0x0000000d, "PCOPY", NULL, NVDEV_ENGINE_COPY0 },
- { 0x0000000e, "PDAEMON", NULL },
- {}
-};
-
-static const struct nouveau_enum vm_fault[] = {
- { 0x00000000, "PT_NOT_PRESENT", NULL },
- { 0x00000001, "PT_TOO_SHORT", NULL },
- { 0x00000002, "PAGE_NOT_PRESENT", NULL },
- { 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
- { 0x00000004, "PAGE_READ_ONLY", NULL },
- { 0x00000006, "NULL_DMAOBJ", NULL },
- { 0x00000007, "WRONG_MEMTYPE", NULL },
- { 0x0000000b, "VRAM_LIMIT", NULL },
- { 0x0000000f, "DMAOBJ_LIMIT", NULL },
- {}
-};
-
-static void
-nv50_fb_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_device *device = nv_device(subdev);
- struct nouveau_engine *engine;
- struct nv50_fb_priv *priv = (void *)subdev;
- const struct nouveau_enum *en, *cl;
- struct nouveau_object *engctx = NULL;
- u32 trap[6], idx, chan;
- u8 st0, st1, st2, st3;
- int i;
-
- idx = nv_rd32(priv, 0x100c90);
- if (!(idx & 0x80000000))
- return;
- idx &= 0x00ffffff;
-
- for (i = 0; i < 6; i++) {
- nv_wr32(priv, 0x100c90, idx | i << 24);
- trap[i] = nv_rd32(priv, 0x100c94);
- }
- nv_wr32(priv, 0x100c90, idx | 0x80000000);
-
- /* decode status bits into something more useful */
- if (device->chipset < 0xa3 ||
- device->chipset == 0xaa || device->chipset == 0xac) {
- st0 = (trap[0] & 0x0000000f) >> 0;
- st1 = (trap[0] & 0x000000f0) >> 4;
- st2 = (trap[0] & 0x00000f00) >> 8;
- st3 = (trap[0] & 0x0000f000) >> 12;
- } else {
- st0 = (trap[0] & 0x000000ff) >> 0;
- st1 = (trap[0] & 0x0000ff00) >> 8;
- st2 = (trap[0] & 0x00ff0000) >> 16;
- st3 = (trap[0] & 0xff000000) >> 24;
- }
- chan = (trap[2] << 16) | trap[1];
-
- en = nouveau_enum_find(vm_engine, st0);
-
- if (en && en->data2) {
- const struct nouveau_enum *orig_en = en;
- while (en->name && en->value == st0 && en->data2) {
- engine = nouveau_engine(subdev, en->data2);
- if (engine) {
- engctx = nouveau_engctx_get(engine, chan);
- if (engctx)
- break;
- }
- en++;
- }
- if (!engctx)
- en = orig_en;
- }
-
- nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
- (trap[5] & 0x00000100) ? "read" : "write",
- trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
- nouveau_client_name(engctx));
-
- nouveau_engctx_put(engctx);
-
- if (en)
- pr_cont("%s/", en->name);
- else
- pr_cont("%02x/", st0);
-
- cl = nouveau_enum_find(vm_client, st2);
- if (cl)
- pr_cont("%s/", cl->name);
- else
- pr_cont("%02x/", st2);
-
- if (cl && cl->data) cl = nouveau_enum_find(cl->data, st3);
- else if (en && en->data) cl = nouveau_enum_find(en->data, st3);
- else cl = NULL;
- if (cl)
- pr_cont("%s", cl->name);
- else
- pr_cont("%02x", st3);
-
- pr_cont(" reason: ");
- en = nouveau_enum_find(vm_fault, st1);
- if (en)
- pr_cont("%s\n", en->name);
- else
- pr_cont("0x%08x\n", st1);
-}
-
-int
-nv50_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nv50_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (priv->r100c08_page) {
- priv->r100c08 = dma_map_page(nv_device_base(device),
- priv->r100c08_page, 0, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(nv_device_base(device), priv->r100c08))
- return -EFAULT;
- } else {
- nv_warn(priv, "failed 0x100c08 page alloc\n");
- }
-
- nv_subdev(priv)->intr = nv50_fb_intr;
- return 0;
-}
-
-void
-nv50_fb_dtor(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nv50_fb_priv *priv = (void *)object;
-
- if (priv->r100c08_page) {
- dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- __free_page(priv->r100c08_page);
- }
-
- nouveau_fb_destroy(&priv->base);
-}
-
-int
-nv50_fb_init(struct nouveau_object *object)
-{
- struct nv50_fb_impl *impl = (void *)object->oclass;
- struct nv50_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- /* Not a clue what this is exactly. Without pointing it at a
- * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
- * cause IOMMU "read from address 0" errors (rh#561267)
- */
- nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
-
- /* This is needed to get meaningful information from 100c90
- * on traps. No idea what these values mean exactly. */
- nv_wr32(priv, 0x100c90, impl->trap);
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_fb_oclass = &(struct nv50_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x50),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fb_ctor,
- .dtor = nv50_fb_dtor,
- .init = nv50_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv50_fb_memtype_valid,
- .base.ram = &nv50_ram_oclass,
- .trap = 0x000707ff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h
deleted file mode 100644
index c5e5a888c607..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv50.h
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef __NVKM_FB_NV50_H__
-#define __NVKM_FB_NV50_H__
-
-#include "priv.h"
-
-struct nv50_fb_priv {
- struct nouveau_fb base;
- struct page *r100c08_page;
- dma_addr_t r100c08;
-};
-
-int nv50_fb_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv50_fb_dtor(struct nouveau_object *);
-int nv50_fb_init(struct nouveau_object *);
-
-struct nv50_fb_impl {
- struct nouveau_fb_impl base;
- u32 trap;
-};
-
-#define nv50_ram_create(p,e,o,d) \
- nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
-int nv50_ram_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-int nv50_ram_get(struct nouveau_fb *, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **);
-void nv50_ram_put(struct nouveau_fb *, struct nouveau_mem **);
-void __nv50_ram_put(struct nouveau_fb *, struct nouveau_mem *);
-extern int nv50_fb_memtype[0x80];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c
deleted file mode 100644
index cf0e767d3833..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nv84.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nv84_fb_oclass = &(struct nv50_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0x84),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fb_ctor,
- .dtor = nv50_fb_dtor,
- .init = nv50_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv50_fb_memtype_valid,
- .base.ram = &nv50_ram_oclass,
- .trap = 0x001d07ff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c
deleted file mode 100644
index dab6e1c63d48..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nva3.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nva3_fb_oclass = &(struct nv50_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0xa3),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fb_ctor,
- .dtor = nv50_fb_dtor,
- .init = nv50_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv50_fb_memtype_valid,
- .base.ram = &nva3_ram_oclass,
- .trap = 0x000d0fff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c
deleted file mode 100644
index cba8e6818035..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaa.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nvaa_fb_oclass = &(struct nv50_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0xaa),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fb_ctor,
- .dtor = nv50_fb_dtor,
- .init = nv50_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv50_fb_memtype_valid,
- .base.ram = &nvaa_ram_oclass,
- .trap = 0x001d07ff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c
deleted file mode 100644
index 5423faa2c09b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvaf.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-nvaf_fb_oclass = &(struct nv50_fb_impl) {
- .base.base.handle = NV_SUBDEV(FB, 0xaf),
- .base.base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_fb_ctor,
- .dtor = nv50_fb_dtor,
- .init = nv50_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .base.memtype = nv50_fb_memtype_valid,
- .base.ram = &nvaa_ram_oclass,
- .trap = 0x089d1fff,
-}.base.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
deleted file mode 100644
index 32f28dc73ef2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-extern const u8 nvc0_pte_storage_type_map[256];
-
-bool
-nvc0_fb_memtype_valid(struct nouveau_fb *pfb, u32 tile_flags)
-{
- u8 memtype = (tile_flags & 0x0000ff00) >> 8;
- return likely((nvc0_pte_storage_type_map[memtype] != 0xff));
-}
-
-static void
-nvc0_fb_intr(struct nouveau_subdev *subdev)
-{
- struct nvc0_fb_priv *priv = (void *)subdev;
- u32 intr = nv_rd32(priv, 0x000100);
- if (intr & 0x08000000) {
- nv_debug(priv, "PFFB intr\n");
- intr &= ~0x08000000;
- }
- if (intr & 0x00002000) {
- nv_debug(priv, "PBFB intr\n");
- intr &= ~0x00002000;
- }
-}
-
-int
-nvc0_fb_init(struct nouveau_object *object)
-{
- struct nvc0_fb_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_fb_init(&priv->base);
- if (ret)
- return ret;
-
- if (priv->r100c10_page)
- nv_wr32(priv, 0x100c10, priv->r100c10 >> 8);
- nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
- return 0;
-}
-
-void
-nvc0_fb_dtor(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nvc0_fb_priv *priv = (void *)object;
-
- if (priv->r100c10_page) {
- dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- __free_page(priv->r100c10_page);
- }
-
- nouveau_fb_destroy(&priv->base);
-}
-
-int
-nvc0_fb_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nvc0_fb_priv *priv;
- int ret;
-
- ret = nouveau_fb_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (priv->r100c10_page) {
- priv->r100c10 = dma_map_page(nv_device_base(device),
- priv->r100c10_page, 0, PAGE_SIZE,
- DMA_BIDIRECTIONAL);
- if (dma_mapping_error(nv_device_base(device), priv->r100c10))
- return -EFAULT;
- }
-
- nv_subdev(priv)->intr = nvc0_fb_intr;
- return 0;
-}
-
-struct nouveau_oclass *
-nvc0_fb_oclass = &(struct nouveau_fb_impl) {
- .base.handle = NV_SUBDEV(FB, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_fb_ctor,
- .dtor = nvc0_fb_dtor,
- .init = nvc0_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .memtype = nvc0_fb_memtype_valid,
- .ram = &nvc0_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h b/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h
deleted file mode 100644
index 705a06d755ad..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nvc0.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __NVKM_RAM_NVC0_H__
-#define __NVKM_RAM_NVC0_H__
-
-#include "priv.h"
-#include "nv50.h"
-
-struct nvc0_fb_priv {
- struct nouveau_fb base;
- struct page *r100c10_page;
- dma_addr_t r100c10;
-};
-
-int nvc0_fb_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nvc0_fb_dtor(struct nouveau_object *);
-int nvc0_fb_init(struct nouveau_object *);
-bool nvc0_fb_memtype_valid(struct nouveau_fb *, u32);
-
-
-#define nvc0_ram_create(p,e,o,m,d) \
- nvc0_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
-int nvc0_ram_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u32, int, void **);
-int nvc0_ram_get(struct nouveau_fb *, u64, u32, u32, u32,
- struct nouveau_mem **);
-void nvc0_ram_put(struct nouveau_fb *, struct nouveau_mem **);
-
-int nve0_ram_init(struct nouveau_object*);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c
deleted file mode 100644
index 595db50cfef3..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/nve0.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-struct nouveau_oclass *
-nve0_fb_oclass = &(struct nouveau_fb_impl) {
- .base.handle = NV_SUBDEV(FB, 0xe0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_fb_ctor,
- .dtor = nvc0_fb_dtor,
- .init = nvc0_fb_init,
- .fini = _nouveau_fb_fini,
- },
- .memtype = nvc0_fb_memtype_valid,
- .ram = &nve0_ram_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
deleted file mode 100644
index 283863f7aa9b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/priv.h
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef __NVKM_FB_PRIV_H__
-#define __NVKM_FB_PRIV_H__
-
-#include <subdev/fb.h>
-
-#define nouveau_ram_create(p,e,o,d) \
- nouveau_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
-#define nouveau_ram_destroy(p) \
- nouveau_object_destroy(&(p)->base)
-#define nouveau_ram_init(p) \
- nouveau_object_init(&(p)->base)
-#define nouveau_ram_fini(p,s) \
- nouveau_object_fini(&(p)->base, (s))
-
-#define nouveau_ram_create_(p,e,o,s,d) \
- nouveau_object_create_((p), (e), (o), 0, (s), (void **)d)
-#define _nouveau_ram_dtor nouveau_object_destroy
-#define _nouveau_ram_init nouveau_object_init
-#define _nouveau_ram_fini nouveau_object_fini
-
-extern struct nouveau_oclass nv04_ram_oclass;
-extern struct nouveau_oclass nv10_ram_oclass;
-extern struct nouveau_oclass nv1a_ram_oclass;
-extern struct nouveau_oclass nv20_ram_oclass;
-extern struct nouveau_oclass nv40_ram_oclass;
-extern struct nouveau_oclass nv41_ram_oclass;
-extern struct nouveau_oclass nv44_ram_oclass;
-extern struct nouveau_oclass nv49_ram_oclass;
-extern struct nouveau_oclass nv4e_ram_oclass;
-extern struct nouveau_oclass nv50_ram_oclass;
-extern struct nouveau_oclass nva3_ram_oclass;
-extern struct nouveau_oclass nvaa_ram_oclass;
-extern struct nouveau_oclass nvc0_ram_oclass;
-extern struct nouveau_oclass nve0_ram_oclass;
-extern struct nouveau_oclass gk20a_ram_oclass;
-extern struct nouveau_oclass gm107_ram_oclass;
-
-int nouveau_sddr2_calc(struct nouveau_ram *ram);
-int nouveau_sddr3_calc(struct nouveau_ram *ram);
-int nouveau_gddr3_calc(struct nouveau_ram *ram);
-int nouveau_gddr5_calc(struct nouveau_ram *ram, bool nuts);
-
-#define nouveau_fb_create(p,e,c,d) \
- nouveau_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
-#define nouveau_fb_destroy(p) ({ \
- struct nouveau_fb *pfb = (p); \
- _nouveau_fb_dtor(nv_object(pfb)); \
-})
-#define nouveau_fb_init(p) ({ \
- struct nouveau_fb *pfb = (p); \
- _nouveau_fb_init(nv_object(pfb)); \
-})
-#define nouveau_fb_fini(p,s) ({ \
- struct nouveau_fb *pfb = (p); \
- _nouveau_fb_fini(nv_object(pfb), (s)); \
-})
-
-int nouveau_fb_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_fb_dtor(struct nouveau_object *);
-int _nouveau_fb_init(struct nouveau_object *);
-int _nouveau_fb_fini(struct nouveau_object *, bool);
-
-struct nouveau_fb_impl {
- struct nouveau_oclass base;
- struct nouveau_oclass *ram;
- bool (*memtype)(struct nouveau_fb *, u32);
-};
-
-bool nv04_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
-bool nv50_fb_memtype_valid(struct nouveau_fb *, u32 memtype);
-
-struct nouveau_bios;
-int nouveau_fb_bios_memtype(struct nouveau_bios *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
deleted file mode 100644
index 0ac7256443bb..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramfuc.h
+++ /dev/null
@@ -1,184 +0,0 @@
-#ifndef __NVKM_FBRAM_FUC_H__
-#define __NVKM_FBRAM_FUC_H__
-
-#include <subdev/pwr.h>
-
-struct ramfuc {
- struct nouveau_memx *memx;
- struct nouveau_fb *pfb;
- int sequence;
-};
-
-struct ramfuc_reg {
- int sequence;
- bool force;
- u32 addr;
- u32 stride; /* in bytes */
- u32 mask;
- u32 data;
-};
-
-static inline struct ramfuc_reg
-ramfuc_stride(u32 addr, u32 stride, u32 mask)
-{
- return (struct ramfuc_reg) {
- .sequence = 0,
- .addr = addr,
- .stride = stride,
- .mask = mask,
- .data = 0xdeadbeef,
- };
-}
-
-static inline struct ramfuc_reg
-ramfuc_reg2(u32 addr1, u32 addr2)
-{
- return (struct ramfuc_reg) {
- .sequence = 0,
- .addr = addr1,
- .stride = addr2 - addr1,
- .mask = 0x3,
- .data = 0xdeadbeef,
- };
-}
-
-static noinline struct ramfuc_reg
-ramfuc_reg(u32 addr)
-{
- return (struct ramfuc_reg) {
- .sequence = 0,
- .addr = addr,
- .stride = 0,
- .mask = 0x1,
- .data = 0xdeadbeef,
- };
-}
-
-static inline int
-ramfuc_init(struct ramfuc *ram, struct nouveau_fb *pfb)
-{
- struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
- int ret;
-
- ret = nouveau_memx_init(ppwr, &ram->memx);
- if (ret)
- return ret;
-
- ram->sequence++;
- ram->pfb = pfb;
- return 0;
-}
-
-static inline int
-ramfuc_exec(struct ramfuc *ram, bool exec)
-{
- int ret = 0;
- if (ram->pfb) {
- ret = nouveau_memx_fini(&ram->memx, exec);
- ram->pfb = NULL;
- }
- return ret;
-}
-
-static inline u32
-ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
-{
- if (reg->sequence != ram->sequence)
- reg->data = nv_rd32(ram->pfb, reg->addr);
- return reg->data;
-}
-
-static inline void
-ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
-{
- unsigned int mask, off = 0;
-
- reg->sequence = ram->sequence;
- reg->data = data;
-
- for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
- if (mask & 1) {
- nouveau_memx_wr32(ram->memx, reg->addr+off, reg->data);
- }
-
- off += reg->stride;
- }
-}
-
-static inline void
-ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg)
-{
- reg->force = true;
-}
-
-static inline u32
-ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data)
-{
- u32 temp = ramfuc_rd32(ram, reg);
- if (temp != ((temp & ~mask) | data) || reg->force) {
- ramfuc_wr32(ram, reg, (temp & ~mask) | data);
- reg->force = false;
- }
- return temp;
-}
-
-static inline void
-ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec)
-{
- nouveau_memx_wait(ram->memx, addr, mask, data, nsec);
-}
-
-static inline void
-ramfuc_nsec(struct ramfuc *ram, u32 nsec)
-{
- nouveau_memx_nsec(ram->memx, nsec);
-}
-
-static inline void
-ramfuc_wait_vblank(struct ramfuc *ram)
-{
- nouveau_memx_wait_vblank(ram->memx);
-}
-
-static inline void
-ramfuc_train(struct ramfuc *ram)
-{
- nouveau_memx_train(ram->memx);
-}
-
-static inline int
-ramfuc_train_result(struct nouveau_fb *pfb, u32 *result, u32 rsize)
-{
- struct nouveau_pwr *ppwr = nouveau_pwr(pfb);
-
- return nouveau_memx_train_result(ppwr, result, rsize);
-}
-
-static inline void
-ramfuc_block(struct ramfuc *ram)
-{
- nouveau_memx_block(ram->memx);
-}
-
-static inline void
-ramfuc_unblock(struct ramfuc *ram)
-{
- nouveau_memx_unblock(ram->memx);
-}
-
-#define ram_init(s,p) ramfuc_init(&(s)->base, (p))
-#define ram_exec(s,e) ramfuc_exec(&(s)->base, (e))
-#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
-#define ram_rd32(s,r) ramfuc_rd32(&(s)->base, &(s)->r_##r)
-#define ram_wr32(s,r,d) ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
-#define ram_nuke(s,r) ramfuc_nuke(&(s)->base, &(s)->r_##r)
-#define ram_mask(s,r,m,d) ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
-#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n))
-#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base)
-#define ram_train(s) ramfuc_train(&(s)->base)
-#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
-#define ram_block(s) ramfuc_block(&(s)->base)
-#define ram_unblock(s) ramfuc_unblock(&(s)->base)
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c
deleted file mode 100644
index 4d77d75e4673..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgk20a.c
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "priv.h"
-
-#include <subdev/fb.h>
-
-struct gk20a_mem {
- struct nouveau_mem base;
- void *cpuaddr;
- dma_addr_t handle;
-};
-#define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base)
-
-static void
-gk20a_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct device *dev = nv_device_base(nv_device(pfb));
- struct gk20a_mem *mem = to_gk20a_mem(*pmem);
-
- *pmem = NULL;
- if (unlikely(mem == NULL))
- return;
-
- if (likely(mem->cpuaddr))
- dma_free_coherent(dev, mem->base.size << PAGE_SHIFT,
- mem->cpuaddr, mem->handle);
-
- kfree(mem->base.pages);
- kfree(mem);
-}
-
-static int
-gk20a_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct device *dev = nv_device_base(nv_device(pfb));
- struct gk20a_mem *mem;
- u32 type = memtype & 0xff;
- u32 npages, order;
- int i;
-
- nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size,
- align, ncmin);
-
- npages = size >> PAGE_SHIFT;
- if (npages == 0)
- npages = 1;
-
- if (align == 0)
- align = PAGE_SIZE;
- align >>= PAGE_SHIFT;
-
- /* round alignment to the next power of 2, if needed */
- order = fls(align);
- if ((align & (align - 1)) == 0)
- order--;
- align = BIT(order);
-
- /* ensure returned address is correctly aligned */
- npages = max(align, npages);
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- mem->base.size = npages;
- mem->base.memtype = type;
-
- mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
- if (!mem->base.pages) {
- kfree(mem);
- return -ENOMEM;
- }
-
- *pmem = &mem->base;
-
- mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
- &mem->handle, GFP_KERNEL);
- if (!mem->cpuaddr) {
- nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
- gk20a_ram_put(pfb, pmem);
- return -ENOMEM;
- }
-
- align <<= PAGE_SHIFT;
-
- /* alignment check */
- if (unlikely(mem->handle & (align - 1)))
- nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
- &mem->handle, align);
-
- nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
- npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);
-
- for (i = 0; i < npages; i++)
- mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);
-
- mem->base.offset = (u64)mem->base.pages[0];
-
- return 0;
-}
-
-static int
-gk20a_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 datasize,
- struct nouveau_object **pobject)
-{
- struct nouveau_ram *ram;
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
- ram->type = NV_MEM_TYPE_STOLEN;
- ram->size = get_num_physpages() << PAGE_SHIFT;
-
- ram->get = gk20a_ram_get;
- ram->put = gk20a_ram_put;
-
- return 0;
-}
-
-struct nouveau_oclass
-gk20a_ram_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gk20a_ram_ctor,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c
deleted file mode 100644
index 4c6363595c79..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramgm107.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nvc0.h"
-
-struct gm107_ram {
- struct nouveau_ram base;
-};
-
-static int
-gm107_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gm107_ram *ram;
- int ret;
-
- ret = nvc0_ram_create(parent, engine, oclass, 0x021c14, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass
-gm107_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm107_ram_ctor,
- .dtor = _nouveau_ram_dtor,
- .init = nve0_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
deleted file mode 100644
index 1972268d1410..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv04.c
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb/regsnv04.h>
-
-#include "priv.h"
-
-static int
-nv04_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_ram *ram;
- u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- if (boot0 & 0x00000100) {
- ram->size = ((boot0 >> 12) & 0xf) * 2 + 2;
- ram->size *= 1024 * 1024;
- } else {
- switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
- case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
- ram->size = 32 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
- ram->size = 16 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
- ram->size = 8 * 1024 * 1024;
- break;
- case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
- ram->size = 4 * 1024 * 1024;
- break;
- }
- }
-
- if ((boot0 & 0x00000038) <= 0x10)
- ram->type = NV_MEM_TYPE_SGRAM;
- else
- ram->type = NV_MEM_TYPE_SDRAM;
- return 0;
-}
-
-struct nouveau_oclass
-nv04_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
deleted file mode 100644
index 8311f3774edf..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv10.c
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv10_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_ram *ram;
- u32 cfg0 = nv_rd32(pfb, 0x100200);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- if (cfg0 & 0x00000001)
- ram->type = NV_MEM_TYPE_DDR1;
- else
- ram->type = NV_MEM_TYPE_SDRAM;
-
- ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- return 0;
-}
-
-
-struct nouveau_oclass
-nv10_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv10_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
deleted file mode 100644
index d0caddfb9db0..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv1a.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv1a_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_ram *ram;
- struct pci_dev *bridge;
- u32 mem, mib;
- int ret;
-
- bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
- if (!bridge) {
- nv_fatal(pfb, "no bridge device\n");
- return -ENODEV;
- }
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- if (nv_device(pfb)->chipset == 0x1a) {
- pci_read_config_dword(bridge, 0x7c, &mem);
- mib = ((mem >> 6) & 31) + 1;
- } else {
- pci_read_config_dword(bridge, 0x84, &mem);
- mib = ((mem >> 4) & 127) + 1;
- }
-
- ram->type = NV_MEM_TYPE_STOLEN;
- ram->size = mib * 1024 * 1024;
- return 0;
-}
-
-struct nouveau_oclass
-nv1a_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv1a_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
deleted file mode 100644
index fdc11bba226d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv20.c
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv20_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_ram *ram;
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
- }
- ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
- ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- ram->tags = nv_rd32(pfb, 0x100320);
- return 0;
-}
-
-struct nouveau_oclass
-nv20_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv20_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
deleted file mode 100644
index 7648beb11199..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv40.c
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/init.h>
-#include <subdev/clock.h>
-#include <subdev/clock/pll.h>
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-
-#include "nv40.h"
-
-int
-nv40_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nv40_ram *ram = (void *)pfb->ram;
- struct nvbios_pll pll;
- int N1, M1, N2, M2;
- int log2P, ret;
-
- ret = nvbios_pll_parse(bios, 0x04, &pll);
- if (ret) {
- nv_error(pfb, "mclk pll data not found\n");
- return ret;
- }
-
- ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq,
- &N1, &M1, &N2, &M2, &log2P);
- if (ret < 0)
- return ret;
-
- ram->ctrl = 0x80000000 | (log2P << 16);
- ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
- if (N2 == M2) {
- ram->ctrl |= 0x00000100;
- ram->coef = (N1 << 8) | M1;
- } else {
- ram->ctrl |= 0x40000000;
- ram->coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
- }
-
- return 0;
-}
-
-int
-nv40_ram_prog(struct nouveau_fb *pfb)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nv40_ram *ram = (void *)pfb->ram;
- struct bit_entry M;
- u32 crtc_mask = 0;
- u8 sr1[2];
- int i;
-
- /* determine which CRTCs are active, fetch VGA_SR1 for each */
- for (i = 0; i < 2; i++) {
- u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000));
- u32 cnt = 0;
- do {
- if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) {
- nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
- sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000));
- if (!(sr1[i] & 0x20))
- crtc_mask |= (1 << i);
- break;
- }
- udelay(1);
- } while (cnt++ < 32);
- }
-
- /* wait for vblank start on active crtcs, disable memory access */
- for (i = 0; i < 2; i++) {
- if (!(crtc_mask & (1 << i)))
- continue;
- nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
- nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
- nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
- nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
- }
-
- /* prepare ram for reclocking */
- nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */
- nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
- nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
- nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
- nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */
-
- /* change the PLL of each memory partition */
- nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000);
- switch (nv_device(pfb)->chipset) {
- case 0x40:
- case 0x45:
- case 0x41:
- case 0x42:
- case 0x47:
- nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl);
- nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl);
- nv_wr32(pfb, 0x004048, ram->coef);
- nv_wr32(pfb, 0x004030, ram->coef);
- case 0x43:
- case 0x49:
- case 0x4b:
- nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl);
- nv_wr32(pfb, 0x00403c, ram->coef);
- default:
- nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl);
- nv_wr32(pfb, 0x004024, ram->coef);
- break;
- }
- udelay(100);
- nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000);
-
- /* re-enable normal operation of memory controller */
- nv_wr32(pfb, 0x1002dc, 0x00000000);
- nv_mask(pfb, 0x100210, 0x80000000, 0x80000000);
- udelay(100);
-
- /* execute memory reset script from vbios */
- if (!bit_entry(bios, 'M', &M)) {
- struct nvbios_init init = {
- .subdev = nv_subdev(pfb),
- .bios = bios,
- .offset = nv_ro16(bios, M.offset + 0x00),
- .execute = 1,
- };
-
- nvbios_exec(&init);
- }
-
- /* make sure we're in vblank (hopefully the same one as before), and
- * then re-enable crtc memory access
- */
- for (i = 0; i < 2; i++) {
- if (!(crtc_mask & (1 << i)))
- continue;
- nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
- nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
- nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]);
- }
-
- return 0;
-}
-
-void
-nv40_ram_tidy(struct nouveau_fb *pfb)
-{
-}
-
-static int
-nv40_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nv40_ram *ram;
- u32 pbus1218 = nv_rd32(pfb, 0x001218);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- switch (pbus1218 & 0x00000300) {
- case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break;
- case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break;
- }
-
- ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- ram->base.tags = nv_rd32(pfb, 0x100320);
- ram->base.calc = nv40_ram_calc;
- ram->base.prog = nv40_ram_prog;
- ram->base.tidy = nv40_ram_tidy;
- return 0;
-}
-
-
-struct nouveau_oclass
-nv40_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
deleted file mode 100644
index d64498a4d9ee..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv41.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-static int
-nv41_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nv40_ram *ram;
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- if (pfb474 & 0x00000004)
- ram->base.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- ram->base.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- ram->base.type = NV_MEM_TYPE_DDR1;
-
- ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- ram->base.tags = nv_rd32(pfb, 0x100320);
- ram->base.calc = nv40_ram_calc;
- ram->base.prog = nv40_ram_prog;
- ram->base.tidy = nv40_ram_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nv41_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv41_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
deleted file mode 100644
index 089acac810c5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv44.c
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-static int
-nv44_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nv40_ram *ram;
- u32 pfb474 = nv_rd32(pfb, 0x100474);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- if (pfb474 & 0x00000004)
- ram->base.type = NV_MEM_TYPE_GDDR3;
- if (pfb474 & 0x00000002)
- ram->base.type = NV_MEM_TYPE_DDR2;
- if (pfb474 & 0x00000001)
- ram->base.type = NV_MEM_TYPE_DDR1;
-
- ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- ram->base.calc = nv40_ram_calc;
- ram->base.prog = nv40_ram_prog;
- ram->base.tidy = nv40_ram_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nv44_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv44_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
deleted file mode 100644
index baa013afa57b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv49.c
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv40.h"
-
-static int
-nv49_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nv40_ram *ram;
- u32 pfb914 = nv_rd32(pfb, 0x100914);
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- switch (pfb914 & 0x00000003) {
- case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break;
- case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break;
- case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break;
- case 0x00000003: break;
- }
-
- ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
- ram->base.tags = nv_rd32(pfb, 0x100320);
- ram->base.calc = nv40_ram_calc;
- ram->base.prog = nv40_ram_prog;
- ram->base.tidy = nv40_ram_tidy;
- return 0;
-}
-
-struct nouveau_oclass
-nv49_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv49_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
deleted file mode 100644
index 63a6aab86028..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv4e.c
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nv4e_ram_create(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_ram *ram;
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
- ram->type = NV_MEM_TYPE_STOLEN;
- return 0;
-}
-
-struct nouveau_oclass
-nv4e_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv4e_ram_create,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
deleted file mode 100644
index 64a983c96625..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnv50.c
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/perf.h>
-#include <subdev/bios/timing.h>
-#include <subdev/clock/pll.h>
-#include <subdev/fb.h>
-
-#include <core/option.h>
-#include <core/mm.h>
-
-#include "ramseq.h"
-
-#include "nv50.h"
-
-struct nv50_ramseq {
- struct hwsq base;
- struct hwsq_reg r_0x002504;
- struct hwsq_reg r_0x004008;
- struct hwsq_reg r_0x00400c;
- struct hwsq_reg r_0x00c040;
- struct hwsq_reg r_0x100210;
- struct hwsq_reg r_0x1002d0;
- struct hwsq_reg r_0x1002d4;
- struct hwsq_reg r_0x1002dc;
- struct hwsq_reg r_0x100da0[8];
- struct hwsq_reg r_0x100e20;
- struct hwsq_reg r_0x100e24;
- struct hwsq_reg r_0x611200;
- struct hwsq_reg r_timing[9];
- struct hwsq_reg r_mr[4];
-};
-
-struct nv50_ram {
- struct nouveau_ram base;
- struct nv50_ramseq hwsq;
-};
-
-#define QFX5800NVA0 1
-
-static int
-nv50_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nv50_ram *ram = (void *)pfb->ram;
- struct nv50_ramseq *hwsq = &ram->hwsq;
- struct nvbios_perfE perfE;
- struct nvbios_pll mpll;
- struct {
- u32 data;
- u8 size;
- } ramcfg, timing;
- u8 ver, hdr, cnt, len, strap;
- int N1, M1, N2, M2, P;
- int ret, i;
-
- /* lookup closest matching performance table entry for frequency */
- i = 0;
- do {
- ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt,
- &ramcfg.size, &perfE);
- if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) ||
- (ramcfg.size < 2)) {
- nv_error(pfb, "invalid/missing perftab entry\n");
- return -EINVAL;
- }
- } while (perfE.memory < freq);
-
- /* locate specific data set for the attached memory */
- strap = nvbios_ramcfg_index(nv_subdev(pfb));
- if (strap >= cnt) {
- nv_error(pfb, "invalid ramcfg strap\n");
- return -EINVAL;
- }
-
- ramcfg.data += hdr + (strap * ramcfg.size);
-
- /* lookup memory timings, if bios says they're present */
- strap = nv_ro08(bios, ramcfg.data + 0x01);
- if (strap != 0xff) {
- timing.data = nvbios_timingEe(bios, strap, &ver, &hdr,
- &cnt, &len);
- if (!timing.data || ver != 0x10 || hdr < 0x12) {
- nv_error(pfb, "invalid/missing timing entry "
- "%02x %04x %02x %02x\n",
- strap, timing.data, ver, hdr);
- return -EINVAL;
- }
- } else {
- timing.data = 0;
- }
-
- ret = ram_init(hwsq, nv_subdev(pfb));
- if (ret)
- return ret;
-
- ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */
- ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */
- ram_wr32(hwsq, 0x611200, 0x00003300);
- ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
- ram_nsec(hwsq, 8000);
- ram_setf(hwsq, 0x10, 0x00); /* disable fb */
- ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
-
- ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */
- ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
- ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
- ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */
- ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */
-
- ret = nvbios_pll_parse(bios, 0x004008, &mpll);
- mpll.vco2.max_freq = 0;
- if (ret == 0) {
- ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq,
- &N1, &M1, &N2, &M2, &P);
- if (ret == 0)
- ret = -EINVAL;
- }
-
- if (ret < 0)
- return ret;
-
- ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000);
- ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200);
- ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1);
- ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) |
- (P << 22) | (P << 16));
-#if QFX5800NVA0
- for (i = 0; i < 8; i++)
- ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/
-#endif
- ram_nsec(hwsq, 96000); /*XXX*/
- ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000);
-
- ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */
- ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */
-
- ram_nsec(hwsq, 12000);
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- ram_nuke(hwsq, mr[0]); /* force update */
- ram_mask(hwsq, mr[0], 0x000, 0x000);
- break;
- case NV_MEM_TYPE_GDDR3:
- ram_mask(hwsq, mr[2], 0x000, 0x000);
- ram_nuke(hwsq, mr[0]); /* force update */
- ram_mask(hwsq, mr[0], 0x000, 0x000);
- break;
- default:
- break;
- }
-
- ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/
- ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/
-
- ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
-
-#if QFX5800NVA0
- ram_nuke(hwsq, 0x100e24);
- ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000);
- ram_nuke(hwsq, 0x100e20);
- ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000);
-#endif
-
- ram_mask(hwsq, mr[0], 0x100, 0x100);
- ram_mask(hwsq, mr[0], 0x100, 0x000);
-
- ram_setf(hwsq, 0x10, 0x01); /* enable fb */
- ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
- ram_wr32(hwsq, 0x611200, 0x00003330);
- ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */
- return 0;
-}
-
-static int
-nv50_ram_prog(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nv50_ram *ram = (void *)pfb->ram;
- struct nv50_ramseq *hwsq = &ram->hwsq;
-
- ram_exec(hwsq, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
- return 0;
-}
-
-static void
-nv50_ram_tidy(struct nouveau_fb *pfb)
-{
- struct nv50_ram *ram = (void *)pfb->ram;
- struct nv50_ramseq *hwsq = &ram->hwsq;
- ram_exec(hwsq, false);
-}
-
-void
-__nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem *mem)
-{
- struct nouveau_mm_node *this;
-
- while (!list_empty(&mem->regions)) {
- this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
-
- list_del(&this->rl_entry);
- nouveau_mm_free(&pfb->vram, &this);
- }
-
- nouveau_mm_free(&pfb->tags, &mem->tag);
-}
-
-void
-nv50_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct nouveau_mem *mem = *pmem;
-
- *pmem = NULL;
- if (unlikely(mem == NULL))
- return;
-
- mutex_lock(&pfb->base.mutex);
- __nv50_ram_put(pfb, mem);
- mutex_unlock(&pfb->base.mutex);
-
- kfree(mem);
-}
-
-int
-nv50_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct nouveau_mm *heap = &pfb->vram;
- struct nouveau_mm *tags = &pfb->tags;
- struct nouveau_mm_node *r;
- struct nouveau_mem *mem;
- int comp = (memtype & 0x300) >> 8;
- int type = (memtype & 0x07f);
- int back = (memtype & 0x800);
- int min, max, ret;
-
- max = (size >> 12);
- min = ncmin ? (ncmin >> 12) : max;
- align >>= 12;
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- mutex_lock(&pfb->base.mutex);
- if (comp) {
- if (align == 16) {
- int n = (max >> 4) * comp;
-
- ret = nouveau_mm_head(tags, 0, 1, n, n, 1, &mem->tag);
- if (ret)
- mem->tag = NULL;
- }
-
- if (unlikely(!mem->tag))
- comp = 0;
- }
-
- INIT_LIST_HEAD(&mem->regions);
- mem->memtype = (comp << 7) | type;
- mem->size = max;
-
- type = nv50_fb_memtype[type];
- do {
- if (back)
- ret = nouveau_mm_tail(heap, 0, type, max, min, align, &r);
- else
- ret = nouveau_mm_head(heap, 0, type, max, min, align, &r);
- if (ret) {
- mutex_unlock(&pfb->base.mutex);
- pfb->ram->put(pfb, &mem);
- return ret;
- }
-
- list_add_tail(&r->rl_entry, &mem->regions);
- max -= r->length;
- } while (max);
- mutex_unlock(&pfb->base.mutex);
-
- r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
- mem->offset = (u64)r->offset << 12;
- *pmem = mem;
- return 0;
-}
-
-static u32
-nv50_fb_vram_rblock(struct nouveau_fb *pfb, struct nouveau_ram *ram)
-{
- int colbits, rowbitsa, rowbitsb, banks;
- u64 rowsize, predicted;
- u32 r0, r4, rt, rblock_size;
-
- r0 = nv_rd32(pfb, 0x100200);
- r4 = nv_rd32(pfb, 0x100204);
- rt = nv_rd32(pfb, 0x100250);
- nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n", r0, r4, rt,
- nv_rd32(pfb, 0x001540));
-
- colbits = (r4 & 0x0000f000) >> 12;
- rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
- rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
- banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
-
- rowsize = ram->parts * banks * (1 << colbits) * 8;
- predicted = rowsize << rowbitsa;
- if (r0 & 0x00000004)
- predicted += rowsize << rowbitsb;
-
- if (predicted != ram->size) {
- nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
- (u32)(ram->size >> 20));
- }
-
- rblock_size = rowsize;
- if (rt & 1)
- rblock_size *= 3;
-
- nv_debug(pfb, "rblock %d bytes\n", rblock_size);
- return rblock_size;
-}
-
-int
-nv50_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- struct nouveau_bios *bios = nouveau_bios(parent);
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_ram *ram;
- int ret;
-
- ret = nouveau_ram_create_(parent, engine, oclass, length, pobject);
- ram = *pobject;
- if (ret)
- return ret;
-
- ram->size = nv_rd32(pfb, 0x10020c);
- ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
-
- ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16;
- ram->parts = hweight8(ram->part_mask);
-
- switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
- case 0: ram->type = NV_MEM_TYPE_DDR1; break;
- case 1:
- if (nouveau_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
- ram->type = NV_MEM_TYPE_DDR3;
- else
- ram->type = NV_MEM_TYPE_DDR2;
- break;
- case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
- case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
- case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
- default:
- break;
- }
-
- ret = nouveau_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
- (rsvd_head + rsvd_tail),
- nv50_fb_vram_rblock(pfb, ram) >> 12);
- if (ret)
- return ret;
-
- ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
- ram->tags = nv_rd32(pfb, 0x100320);
- ram->get = nv50_ram_get;
- ram->put = nv50_ram_put;
- return 0;
-}
-
-static int
-nv50_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 datasize,
- struct nouveau_object **pobject)
-{
- struct nv50_ram *ram;
- int ret, i;
-
- ret = nv50_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- case NV_MEM_TYPE_GDDR3:
- ram->base.calc = nv50_ram_calc;
- ram->base.prog = nv50_ram_prog;
- ram->base.tidy = nv50_ram_tidy;
- break;
- default:
- nv_warn(ram, "reclocking of this ram type unsupported\n");
- return 0;
- }
-
- ram->hwsq.r_0x002504 = hwsq_reg(0x002504);
- ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040);
- ram->hwsq.r_0x004008 = hwsq_reg(0x004008);
- ram->hwsq.r_0x00400c = hwsq_reg(0x00400c);
- ram->hwsq.r_0x100210 = hwsq_reg(0x100210);
- ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0);
- ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4);
- ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc);
- for (i = 0; i < 8; i++)
- ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04));
- ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20);
- ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24);
- ram->hwsq.r_0x611200 = hwsq_reg(0x611200);
-
- for (i = 0; i < 9; i++)
- ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04));
-
- if (ram->base.ranks > 1) {
- ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8);
- ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc);
- ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8);
- ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec);
- } else {
- ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0);
- ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4);
- ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0);
- ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4);
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-nv50_ram_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_ram_ctor,
- .dtor = _nouveau_ram_dtor,
- .init = _nouveau_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
deleted file mode 100644
index 3b38a538845d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnva3.c
+++ /dev/null
@@ -1,1024 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Roy Spliet <rspliet@eclipso.eu>
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/bit.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/rammap.h>
-#include <subdev/bios/M0205.h>
-#include <subdev/bios/timing.h>
-
-#include <subdev/clock/nva3.h>
-#include <subdev/clock/pll.h>
-
-#include <subdev/gpio.h>
-
-#include <subdev/timer.h>
-
-#include <engine/fifo.h>
-
-#include <core/option.h>
-
-#include "ramfuc.h"
-
-#include "nv50.h"
-
-/* XXX: Remove when memx gains GPIO support */
-extern int nv50_gpio_location(int line, u32 *reg, u32 *shift);
-
-struct nva3_ramfuc {
- struct ramfuc base;
- struct ramfuc_reg r_0x001610;
- struct ramfuc_reg r_0x001700;
- struct ramfuc_reg r_0x002504;
- struct ramfuc_reg r_0x004000;
- struct ramfuc_reg r_0x004004;
- struct ramfuc_reg r_0x004018;
- struct ramfuc_reg r_0x004128;
- struct ramfuc_reg r_0x004168;
- struct ramfuc_reg r_0x100080;
- struct ramfuc_reg r_0x100200;
- struct ramfuc_reg r_0x100210;
- struct ramfuc_reg r_0x100220[9];
- struct ramfuc_reg r_0x100264;
- struct ramfuc_reg r_0x1002d0;
- struct ramfuc_reg r_0x1002d4;
- struct ramfuc_reg r_0x1002dc;
- struct ramfuc_reg r_0x10053c;
- struct ramfuc_reg r_0x1005a0;
- struct ramfuc_reg r_0x1005a4;
- struct ramfuc_reg r_0x100700;
- struct ramfuc_reg r_0x100714;
- struct ramfuc_reg r_0x100718;
- struct ramfuc_reg r_0x10071c;
- struct ramfuc_reg r_0x100720;
- struct ramfuc_reg r_0x100760;
- struct ramfuc_reg r_0x1007a0;
- struct ramfuc_reg r_0x1007e0;
- struct ramfuc_reg r_0x100da0;
- struct ramfuc_reg r_0x10f804;
- struct ramfuc_reg r_0x1110e0;
- struct ramfuc_reg r_0x111100;
- struct ramfuc_reg r_0x111104;
- struct ramfuc_reg r_0x1111e0;
- struct ramfuc_reg r_0x111400;
- struct ramfuc_reg r_0x611200;
- struct ramfuc_reg r_mr[4];
- struct ramfuc_reg r_gpioFBVREF;
-};
-
-struct nva3_ltrain {
- enum {
- NVA3_TRAIN_UNKNOWN,
- NVA3_TRAIN_UNSUPPORTED,
- NVA3_TRAIN_ONCE,
- NVA3_TRAIN_EXEC,
- NVA3_TRAIN_DONE
- } state;
- u32 r_100720;
- u32 r_1111e0;
- u32 r_111400;
- struct nouveau_mem *mem;
-};
-
-struct nva3_ram {
- struct nouveau_ram base;
- struct nva3_ramfuc fuc;
- struct nva3_ltrain ltrain;
-};
-
-void
-nva3_link_train_calc(u32 *vals, struct nva3_ltrain *train)
-{
- int i, lo, hi;
- u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0;
-
- for (i = 0; i < 8; i++) {
- for (lo = 0; lo < 0x40; lo++) {
- if (!(vals[lo] & 0x80000000))
- continue;
- if (vals[lo] & (0x101 << i))
- break;
- }
-
- if (lo == 0x40)
- return;
-
- for (hi = lo + 1; hi < 0x40; hi++) {
- if (!(vals[lo] & 0x80000000))
- continue;
- if (!(vals[hi] & (0x101 << i))) {
- hi--;
- break;
- }
- }
-
- median[i] = ((hi - lo) >> 1) + lo;
- bins[(median[i] & 0xf0) >> 4]++;
- median[i] += 0x30;
- }
-
- /* Find the best value for 0x1111e0 */
- for (i = 0; i < 4; i++) {
- if (bins[i] > qty) {
- bin = i + 3;
- qty = bins[i];
- }
- }
-
- train->r_100720 = 0;
- for (i = 0; i < 8; i++) {
- median[i] = max(median[i], (u8) (bin << 4));
- median[i] = min(median[i], (u8) ((bin << 4) | 0xf));
-
- train->r_100720 |= ((median[i] & 0x0f) << (i << 2));
- }
-
- train->r_1111e0 = 0x02000000 | (bin * 0x101);
- train->r_111400 = 0x0;
-}
-
-/*
- * Link training for (at least) DDR3
- */
-int
-nva3_link_train(struct nouveau_fb *pfb)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nva3_ram *ram = (void *)pfb->ram;
- struct nouveau_clock *clk = nouveau_clock(pfb);
- struct nva3_ltrain *train = &ram->ltrain;
- struct nouveau_device *device = nv_device(pfb);
- struct nva3_ramfuc *fuc = &ram->fuc;
- u32 *result, r1700;
- int ret, i;
- struct nvbios_M0205T M0205T = { 0 };
- u8 ver, hdr, cnt, len, snr, ssz;
- unsigned int clk_current;
- unsigned long flags;
- unsigned long *f = &flags;
-
- if (nouveau_boolopt(device->cfgopt, "NvMemExec", true) != true)
- return -ENOSYS;
-
- /* XXX: Multiple partitions? */
- result = kmalloc(64 * sizeof(u32), GFP_KERNEL);
- if (!result)
- return -ENOMEM;
-
- train->state = NVA3_TRAIN_EXEC;
-
- /* Clock speeds for training and back */
- nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T);
- if (M0205T.freq == 0)
- return -ENOENT;
-
- clk_current = clk->read(clk, nv_clk_src_mem);
-
- ret = nva3_clock_pre(clk, f);
- if (ret)
- goto out;
-
- /* First: clock up/down */
- ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000);
- if (ret)
- goto out;
-
- /* Do this *after* calc, eliminates write in script */
- nv_wr32(pfb, 0x111400, 0x00000000);
- /* XXX: Magic writes that improve train reliability? */
- nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000);
- nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000);
- nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000);
- nv_wr32(pfb, 0x100c04, 0x00000400);
-
- /* Now the training script */
- r1700 = ram_rd32(fuc, 0x001700);
-
- ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
- ram_wr32(fuc, 0x611200, 0x3300);
- ram_wait_vblank(fuc);
- ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000);
- ram_mask(fuc, 0x001610, 0x00000083, 0x00000003);
- ram_mask(fuc, 0x100080, 0x00000020, 0x00000000);
- ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
- ram_wr32(fuc, 0x001700, 0x00000000);
-
- ram_train(fuc);
-
- /* Reset */
- ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000);
- ram_wr32(fuc, 0x10053c, 0x0);
- ram_wr32(fuc, 0x100720, train->r_100720);
- ram_wr32(fuc, 0x1111e0, train->r_1111e0);
- ram_wr32(fuc, 0x111400, train->r_111400);
- ram_nuke(fuc, 0x100080);
- ram_mask(fuc, 0x100080, 0x00000020, 0x00000020);
- ram_nsec(fuc, 1000);
-
- ram_wr32(fuc, 0x001700, r1700);
- ram_mask(fuc, 0x001610, 0x00000083, 0x00000080);
- ram_wr32(fuc, 0x611200, 0x3330);
- ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
-
- ram_exec(fuc, true);
-
- ram->base.calc(pfb, clk_current);
- ram_exec(fuc, true);
-
- /* Post-processing, avoids flicker */
- nv_mask(pfb, 0x616308, 0x10, 0x10);
- nv_mask(pfb, 0x616b08, 0x10, 0x10);
-
- nva3_clock_post(clk, f);
-
- ram_train_result(pfb, result, 64);
- for (i = 0; i < 64; i++)
- nv_debug(pfb, "Train: %08x", result[i]);
- nva3_link_train_calc(result, train);
-
- nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720,
- train->r_1111e0, train->r_111400);
-
- kfree(result);
-
- train->state = NVA3_TRAIN_DONE;
-
- return ret;
-
-out:
- if(ret == -EBUSY)
- f = NULL;
-
- train->state = NVA3_TRAIN_UNSUPPORTED;
-
- nva3_clock_post(clk, f);
- return ret;
-}
-
-int
-nva3_link_train_init(struct nouveau_fb *pfb)
-{
- static const u32 pattern[16] = {
- 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
- 0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
- 0x33333333, 0x55555555, 0x77777777, 0x66666666,
- 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
- };
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nva3_ram *ram = (void *)pfb->ram;
- struct nva3_ltrain *train = &ram->ltrain;
- struct nouveau_mem *mem;
- struct nvbios_M0205E M0205E;
- u8 ver, hdr, cnt, len;
- u32 r001700;
- int ret, i = 0;
-
- train->state = NVA3_TRAIN_UNSUPPORTED;
-
- /* We support type "5"
- * XXX: training pattern table appears to be unused for this routine */
- if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))
- return -ENOENT;
-
- if (M0205E.type != 5)
- return 0;
-
- train->state = NVA3_TRAIN_ONCE;
-
- ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem);
- if (ret)
- return ret;
-
- mem = ram->ltrain.mem;
-
- nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16));
- nv_wr32(pfb, 0x1005a8, 0x0000ffff);
- nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
-
- for (i = 0; i < 0x30; i++) {
- nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
- nv_wr32(pfb, 0x10f900, pattern[i % 16]);
- }
-
- for (i = 0; i < 0x30; i++) {
- nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
- nv_wr32(pfb, 0x10f920, pattern[i % 16]);
- }
-
- /* And upload the pattern */
- r001700 = nv_rd32(pfb, 0x1700);
- nv_wr32(pfb, 0x1700, mem->offset >> 16);
- for (i = 0; i < 16; i++)
- nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]);
- for (i = 0; i < 16; i++)
- nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]);
- nv_wr32(pfb, 0x1700, r001700);
-
- train->r_100720 = nv_rd32(pfb, 0x100720);
- train->r_1111e0 = nv_rd32(pfb, 0x1111e0);
- train->r_111400 = nv_rd32(pfb, 0x111400);
-
- return 0;
-}
-
-void
-nva3_link_train_fini(struct nouveau_fb *pfb)
-{
- struct nva3_ram *ram = (void *)pfb->ram;
-
- if (ram->ltrain.mem)
- pfb->ram->put(pfb, &ram->ltrain.mem);
-}
-
-/*
- * RAM reclocking
- */
-#define T(t) cfg->timing_10_##t
-static int
-nva3_ram_timing_calc(struct nouveau_fb *pfb, u32 *timing)
-{
- struct nva3_ram *ram = (void *)pfb->ram;
- struct nvbios_ramcfg *cfg = &ram->base.target.bios;
- int tUNK_base, tUNK_40_0, prevCL;
- u32 cur2, cur3, cur7, cur8;
-
- cur2 = nv_rd32(pfb, 0x100228);
- cur3 = nv_rd32(pfb, 0x10022c);
- cur7 = nv_rd32(pfb, 0x10023c);
- cur8 = nv_rd32(pfb, 0x100240);
-
-
- switch ((!T(CWL)) * ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- T(CWL) = T(CL) - 1;
- break;
- case NV_MEM_TYPE_GDDR3:
- T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
- break;
- }
-
- prevCL = (cur3 & 0x000000ff) + 1;
- tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
-
- timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
- timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
- max_t(u8,T(18), 1) << 16 |
- (T(WTR) + 1 + T(CWL)) << 8 |
- (5 + T(CL) - T(CWL));
- timing[2] = (T(CWL) - 1) << 24 |
- (T(RRD) << 16) |
- (T(RCDWR) << 8) |
- T(RCDRD);
- timing[3] = (cur3 & 0x00ff0000) |
- (0x30 + T(CL)) << 24 |
- (0xb + T(CL)) << 8 |
- (T(CL) - 1);
- timing[4] = T(20) << 24 |
- T(21) << 16 |
- T(13) << 8 |
- T(13);
- timing[5] = T(RFC) << 24 |
- max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
- max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
- T(RP);
- timing[6] = (0x5a + T(CL)) << 16 |
- max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
- (0x50 + T(CL) - T(CWL));
- timing[7] = (cur7 & 0xff000000) |
- ((tUNK_base + T(CL)) << 16) |
- 0x202;
- timing[8] = cur8 & 0xffffff00;
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- case NV_MEM_TYPE_GDDR3:
- tUNK_40_0 = prevCL - (cur8 & 0xff);
- if (tUNK_40_0 > 0)
- timing[8] |= T(CL);
- break;
- default:
- break;
- }
-
- nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n",
- timing[0], timing[1], timing[2], timing[3]);
- nv_debug(pfb, " 230: %08x %08x %08x %08x\n",
- timing[4], timing[5], timing[6], timing[7]);
- nv_debug(pfb, " 240: %08x\n", timing[8]);
- return 0;
-}
-#undef T
-
-static void
-nouveau_sddr2_dll_reset(struct nva3_ramfuc *fuc)
-{
- ram_mask(fuc, mr[0], 0x100, 0x100);
- ram_nsec(fuc, 1000);
- ram_mask(fuc, mr[0], 0x100, 0x000);
- ram_nsec(fuc, 1000);
-}
-
-static void
-nouveau_sddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
-{
- u32 mr1_old = ram_rd32(fuc, mr[1]);
-
- if (!(mr1_old & 0x1)) {
- ram_wr32(fuc, 0x1002d4, 0x00000001);
- ram_wr32(fuc, mr[1], mr[1]);
- ram_nsec(fuc, 1000);
- }
-}
-
-static void
-nouveau_gddr3_dll_disable(struct nva3_ramfuc *fuc, u32 *mr)
-{
- u32 mr1_old = ram_rd32(fuc, mr[1]);
-
- if (!(mr1_old & 0x40)) {
- ram_wr32(fuc, mr[1], mr[1]);
- ram_nsec(fuc, 1000);
- }
-}
-
-static void
-nva3_ram_lock_pll(struct nva3_ramfuc *fuc, struct nva3_clock_info *mclk)
-{
- ram_wr32(fuc, 0x004004, mclk->pll);
- ram_mask(fuc, 0x004000, 0x00000001, 0x00000001);
- ram_mask(fuc, 0x004000, 0x00000010, 0x00000000);
- ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
- ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
-}
-
-static void
-nva3_ram_fbvref(struct nva3_ramfuc *fuc, u32 val)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(fuc->base.pfb);
- struct dcb_gpio_func func;
- u32 reg, sh, gpio_val;
- int ret;
-
- if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) {
- ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
- if (ret)
- return;
-
- nv50_gpio_location(func.line, &reg, &sh);
- gpio_val = ram_rd32(fuc, gpioFBVREF);
- if (gpio_val & (8 << sh))
- val = !val;
-
- ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh));
- ram_nsec(fuc, 20000);
- }
-}
-
-static int
-nva3_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nva3_ram *ram = (void *)pfb->ram;
- struct nva3_ramfuc *fuc = &ram->fuc;
- struct nva3_ltrain *train = &ram->ltrain;
- struct nva3_clock_info mclk;
- struct nouveau_ram_data *next;
- u8 ver, hdr, cnt, len, strap;
- u32 data;
- u32 r004018, r100760, r100da0, r111100, ctrl;
- u32 unk714, unk718, unk71c;
- int ret, i;
- u32 timing[9];
- bool pll2pll;
-
- next = &ram->base.target;
- next->freq = freq;
- ram->base.next = next;
-
- if (ram->ltrain.state == NVA3_TRAIN_ONCE)
- nva3_link_train(pfb);
-
- /* lookup memory config data relevant to the target frequency */
- i = 0;
- data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len,
- &next->bios);
- if (!data || ver != 0x10 || hdr < 0x05) {
- nv_error(pfb, "invalid/missing rammap entry\n");
- return -EINVAL;
- }
-
- /* locate specific data set for the attached memory */
- strap = nvbios_ramcfg_index(nv_subdev(pfb));
- if (strap >= cnt) {
- nv_error(pfb, "invalid ramcfg strap\n");
- return -EINVAL;
- }
-
- data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
- &ver, &hdr, &next->bios);
- if (!data || ver != 0x10 || hdr < 0x09) {
- nv_error(pfb, "invalid/missing ramcfg entry\n");
- return -EINVAL;
- }
-
- /* lookup memory timings, if bios says they're present */
- if (next->bios.ramcfg_timing != 0xff) {
- data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
- &ver, &hdr, &cnt, &len,
- &next->bios);
- if (!data || ver != 0x10 || hdr < 0x17) {
- nv_error(pfb, "invalid/missing timing entry\n");
- return -EINVAL;
- }
- }
-
- ret = nva3_pll_info(nouveau_clock(pfb), 0x12, 0x4000, freq, &mclk);
- if (ret < 0) {
- nv_error(pfb, "failed mclk calculation\n");
- return ret;
- }
-
- nva3_ram_timing_calc(pfb, timing);
-
- ret = ram_init(fuc, pfb);
- if (ret)
- return ret;
-
- /* Determine ram-specific MR values */
- ram->base.mr[0] = ram_rd32(fuc, mr[0]);
- ram->base.mr[1] = ram_rd32(fuc, mr[1]);
- ram->base.mr[2] = ram_rd32(fuc, mr[2]);
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- ret = nouveau_sddr2_calc(&ram->base);
- break;
- case NV_MEM_TYPE_DDR3:
- ret = nouveau_sddr3_calc(&ram->base);
- break;
- case NV_MEM_TYPE_GDDR3:
- ret = nouveau_gddr3_calc(&ram->base);
- break;
- default:
- ret = -ENOSYS;
- break;
- }
-
- if (ret)
- return ret;
-
- /* XXX: where the fuck does 750MHz come from? */
- if (freq <= 750000) {
- r004018 = 0x10000000;
- r100760 = 0x22222222;
- r100da0 = 0x00000010;
- } else {
- r004018 = 0x00000000;
- r100760 = 0x00000000;
- r100da0 = 0x00000000;
- }
-
- if (!next->bios.ramcfg_10_DLLoff)
- r004018 |= 0x00004000;
-
- /* pll2pll requires to switch to a safe clock first */
- ctrl = ram_rd32(fuc, 0x004000);
- pll2pll = (!(ctrl & 0x00000008)) && mclk.pll;
-
- /* Pre, NVIDIA does this outside the script */
- if (next->bios.ramcfg_10_02_10) {
- ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
- } else {
- ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
- ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
- }
- /* Always disable this bit during reclock */
- ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
-
- /* If switching from non-pll to pll, lock before disabling FB */
- if (mclk.pll && !pll2pll) {
- ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101);
- nva3_ram_lock_pll(fuc, &mclk);
- }
-
- /* Start with disabling some CRTCs and PFIFO? */
- ram_wait_vblank(fuc);
- ram_wr32(fuc, 0x611200, 0x3300);
- ram_mask(fuc, 0x002504, 0x1, 0x1);
- ram_nsec(fuc, 10000);
- ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */
- ram_block(fuc);
- ram_nsec(fuc, 2000);
-
- if (!next->bios.ramcfg_10_02_10) {
- if (ram->base.type == NV_MEM_TYPE_GDDR3)
- ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
- else
- ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
- }
-
- /* If we're disabling the DLL, do it now */
- switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
- case NV_MEM_TYPE_DDR3:
- nouveau_sddr3_dll_disable(fuc, ram->base.mr);
- break;
- case NV_MEM_TYPE_GDDR3:
- nouveau_gddr3_dll_disable(fuc, ram->base.mr);
- break;
- }
-
- if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT)
- nva3_ram_fbvref(fuc, 0);
-
- /* Brace RAM for impact */
- ram_wr32(fuc, 0x1002d4, 0x00000001);
- ram_wr32(fuc, 0x1002d0, 0x00000001);
- ram_wr32(fuc, 0x1002d0, 0x00000001);
- ram_wr32(fuc, 0x100210, 0x00000000);
- ram_wr32(fuc, 0x1002dc, 0x00000001);
- ram_nsec(fuc, 2000);
-
- if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000)
- ram_mask(fuc, 0x100700, 0x00000006, 0x00000006);
-
- /* Fiddle with clocks */
- /* There's 4 scenario's
- * pll->pll: first switch to a 324MHz clock, set up new PLL, switch
- * clk->pll: Set up new PLL, switch
- * pll->clk: Set up clock, switch
- * clk->clk: Overwrite ctrl and other bits, switch */
-
- /* Switch to regular clock - 324MHz */
- if (pll2pll) {
- ram_mask(fuc, 0x004000, 0x00000004, 0x00000004);
- ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101);
- ram_mask(fuc, 0x004000, 0x00000008, 0x00000008);
- ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
- ram_wr32(fuc, 0x004018, 0x00001000);
- nva3_ram_lock_pll(fuc, &mclk);
- }
-
- if (mclk.pll) {
- ram_mask(fuc, 0x004000, 0x00000105, 0x00000105);
- ram_wr32(fuc, 0x004018, 0x00001000 | r004018);
- ram_wr32(fuc, 0x100da0, r100da0);
- } else {
- ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101);
- ram_mask(fuc, 0x004000, 0x00000108, 0x00000008);
- ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
- ram_wr32(fuc, 0x004018, 0x00009000 | r004018);
- ram_wr32(fuc, 0x100da0, r100da0);
- }
- ram_nsec(fuc, 20000);
-
- if (next->bios.rammap_10_04_08) {
- ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
- next->bios.ramcfg_10_05 << 8 |
- next->bios.ramcfg_10_05);
- ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
- next->bios.ramcfg_10_07);
- ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
- next->bios.ramcfg_10_03_0f << 16 |
- next->bios.ramcfg_10_09_0f |
- 0x80000000);
- ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
- } else {
- if (train->state == NVA3_TRAIN_DONE) {
- ram_wr32(fuc, 0x100080, 0x1020);
- ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400);
- ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0);
- ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720);
- }
- ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
- ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
- ram_mask(fuc, 0x100760, 0x22222222, r100760);
- ram_mask(fuc, 0x1007a0, 0x22222222, r100760);
- ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
- }
-
- if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) {
- ram_mask(fuc, 0x100700, 0x00000006, 0x00000000);
- }
-
- /* Final switch */
- if (mclk.pll) {
- ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
- ram_mask(fuc, 0x004000, 0x00000008, 0x00000000);
- }
-
- ram_wr32(fuc, 0x1002dc, 0x00000000);
- ram_wr32(fuc, 0x1002d4, 0x00000001);
- ram_wr32(fuc, 0x100210, 0x80000000);
- ram_nsec(fuc, 2000);
-
- /* Set RAM MR parameters and timings */
- for (i = 2; i >= 0; i--) {
- if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) {
- ram_wr32(fuc, mr[i], ram->base.mr[i]);
- ram_nsec(fuc, 1000);
- }
- }
-
- ram_wr32(fuc, 0x100220[3], timing[3]);
- ram_wr32(fuc, 0x100220[1], timing[1]);
- ram_wr32(fuc, 0x100220[6], timing[6]);
- ram_wr32(fuc, 0x100220[7], timing[7]);
- ram_wr32(fuc, 0x100220[2], timing[2]);
- ram_wr32(fuc, 0x100220[4], timing[4]);
- ram_wr32(fuc, 0x100220[5], timing[5]);
- ram_wr32(fuc, 0x100220[0], timing[0]);
- ram_wr32(fuc, 0x100220[8], timing[8]);
-
- /* Misc */
- ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
-
- /* XXX: A lot of "chipset"/"ram type" specific stuff...? */
- unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000130;
- unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
- unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
- r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000;
-
- if (next->bios.ramcfg_10_02_04) {
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR3:
- if (nv_device(pfb)->chipset != 0xa8)
- r111100 |= 0x00000004;
- /* no break */
- case NV_MEM_TYPE_DDR2:
- r111100 |= 0x08000000;
- break;
- default:
- break;
- }
- } else {
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- r111100 |= 0x1a800000;
- unk714 |= 0x00000010;
- break;
- case NV_MEM_TYPE_DDR3:
- if (nv_device(pfb)->chipset == 0xa8) {
- r111100 |= 0x08000000;
- } else {
- r111100 &= ~0x00000004;
- r111100 |= 0x12800000;
- }
- unk714 |= 0x00000010;
- break;
- case NV_MEM_TYPE_GDDR3:
- r111100 |= 0x30000000;
- unk714 |= 0x00000020;
- break;
- default:
- break;
- }
- }
-
- unk714 |= (next->bios.ramcfg_10_04_01) << 8;
-
- if (next->bios.ramcfg_10_02_20)
- unk714 |= 0xf0000000;
- if (next->bios.ramcfg_10_02_02)
- unk718 |= 0x00000100;
- if (next->bios.ramcfg_10_02_01)
- unk71c |= 0x00000100;
- if (next->bios.timing_10_24 != 0xff) {
- unk718 &= ~0xf0000000;
- unk718 |= next->bios.timing_10_24 << 28;
- }
- if (next->bios.ramcfg_10_02_10)
- r111100 &= ~0x04020000;
-
- ram_mask(fuc, 0x100714, 0xffffffff, unk714);
- ram_mask(fuc, 0x10071c, 0xffffffff, unk71c);
- ram_mask(fuc, 0x100718, 0xffffffff, unk718);
- ram_mask(fuc, 0x111100, 0xffffffff, r111100);
-
- if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT)
- nva3_ram_fbvref(fuc, 1);
-
- /* Reset DLL */
- if (!next->bios.ramcfg_10_DLLoff)
- nouveau_sddr2_dll_reset(fuc);
-
- if (ram->base.type == NV_MEM_TYPE_GDDR3) {
- ram_nsec(fuc, 31000);
- } else {
- ram_nsec(fuc, 14000);
- }
-
- if (ram->base.type == NV_MEM_TYPE_DDR3) {
- ram_wr32(fuc, 0x100264, 0x1);
- ram_nsec(fuc, 2000);
- }
-
- ram_nuke(fuc, 0x100700);
- ram_mask(fuc, 0x100700, 0x01000000, 0x01000000);
- ram_mask(fuc, 0x100700, 0x01000000, 0x00000000);
-
- /* Re-enable FB */
- ram_unblock(fuc);
- ram_wr32(fuc, 0x611200, 0x3330);
-
- /* Post fiddlings */
- if (next->bios.rammap_10_04_02)
- ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
- if (next->bios.ramcfg_10_02_10) {
- ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
- ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
- } else {
- ram_mask(fuc, 0x111104, 0x00000600, 0x00000600);
- }
-
- if (mclk.pll) {
- ram_mask(fuc, 0x004168, 0x00000001, 0x00000000);
- ram_mask(fuc, 0x004168, 0x00000100, 0x00000000);
- } else {
- ram_mask(fuc, 0x004000, 0x00000001, 0x00000000);
- ram_mask(fuc, 0x004128, 0x00000001, 0x00000000);
- ram_mask(fuc, 0x004128, 0x00000100, 0x00000000);
- }
-
- return 0;
-}
-
-static int
-nva3_ram_prog(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nva3_ram *ram = (void *)pfb->ram;
- struct nva3_ramfuc *fuc = &ram->fuc;
- bool exec = nouveau_boolopt(device->cfgopt, "NvMemExec", true);
-
- if (exec) {
- nv_mask(pfb, 0x001534, 0x2, 0x2);
-
- ram_exec(fuc, true);
-
- /* Post-processing, avoids flicker */
- nv_mask(pfb, 0x002504, 0x1, 0x0);
- nv_mask(pfb, 0x001534, 0x2, 0x0);
-
- nv_mask(pfb, 0x616308, 0x10, 0x10);
- nv_mask(pfb, 0x616b08, 0x10, 0x10);
- } else {
- ram_exec(fuc, false);
- }
- return 0;
-}
-
-static void
-nva3_ram_tidy(struct nouveau_fb *pfb)
-{
- struct nva3_ram *ram = (void *)pfb->ram;
- struct nva3_ramfuc *fuc = &ram->fuc;
- ram_exec(fuc, false);
-}
-
-static int
-nva3_ram_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object->parent;
- struct nva3_ram *ram = (void *)object;
- int ret;
-
- ret = nouveau_ram_init(&ram->base);
- if (ret)
- return ret;
-
- nva3_link_train_init(pfb);
-
- return 0;
-}
-
-static int
-nva3_ram_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_fb *pfb = (void *)object->parent;
-
- if (!suspend)
- nva3_link_train_fini(pfb);
-
- return 0;
-}
-
-static int
-nva3_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 datasize,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_gpio *gpio = nouveau_gpio(pfb);
- struct dcb_gpio_func func;
- struct nva3_ram *ram;
- int ret, i;
- u32 reg, shift;
-
- ret = nv50_ram_create(parent, engine, oclass, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR2:
- case NV_MEM_TYPE_DDR3:
- case NV_MEM_TYPE_GDDR3:
- ram->base.calc = nva3_ram_calc;
- ram->base.prog = nva3_ram_prog;
- ram->base.tidy = nva3_ram_tidy;
- break;
- default:
- nv_warn(ram, "reclocking of this ram type unsupported\n");
- return 0;
- }
-
- ram->fuc.r_0x001610 = ramfuc_reg(0x001610);
- ram->fuc.r_0x001700 = ramfuc_reg(0x001700);
- ram->fuc.r_0x002504 = ramfuc_reg(0x002504);
- ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
- ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
- ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
- ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
- ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
- ram->fuc.r_0x100080 = ramfuc_reg(0x100080);
- ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
- ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
- for (i = 0; i < 9; i++)
- ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
- ram->fuc.r_0x100264 = ramfuc_reg(0x100264);
- ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
- ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
- ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
- ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
- ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
- ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
- ram->fuc.r_0x100700 = ramfuc_reg(0x100700);
- ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
- ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
- ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
- ram->fuc.r_0x100720 = ramfuc_reg(0x100720);
- ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
- ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
- ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
- ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask);
- ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
- ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
- ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
- ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
- ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0);
- ram->fuc.r_0x111400 = ramfuc_reg(0x111400);
- ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
-
- if (ram->base.ranks > 1) {
- ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8);
- ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc);
- ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8);
- ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec);
- } else {
- ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0);
- ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4);
- ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0);
- ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
- }
-
- ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
- if (ret == 0) {
- nv50_gpio_location(func.line, &reg, &shift);
- ram->fuc.r_gpioFBVREF = ramfuc_reg(reg);
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-nva3_ram_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_ram_ctor,
- .dtor = _nouveau_ram_dtor,
- .init = nva3_ram_init,
- .fini = nva3_ram_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c
deleted file mode 100644
index 033a8e999497..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvaa.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nvaa_ram_priv {
- struct nouveau_ram base;
- u64 poller_base;
-};
-
-static int
-nvaa_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 datasize,
- struct nouveau_object **pobject)
-{
- u32 rsvd_head = ( 256 * 1024); /* vga memory */
- u32 rsvd_tail = (1024 * 1024); /* vbios etc */
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nvaa_ram_priv *priv;
- int ret;
-
- ret = nouveau_ram_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.type = NV_MEM_TYPE_STOLEN;
- priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
- priv->base.size = (u64)nv_rd32(pfb, 0x100e14) << 12;
-
- rsvd_tail += 0x1000;
- priv->poller_base = priv->base.size - rsvd_tail;
-
- ret = nouveau_mm_init(&pfb->vram, rsvd_head >> 12,
- (priv->base.size - (rsvd_head + rsvd_tail)) >> 12,
- 1);
- if (ret)
- return ret;
-
- priv->base.get = nv50_ram_get;
- priv->base.put = nv50_ram_put;
- return 0;
-}
-
-static int
-nvaa_ram_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = nouveau_fb(object);
- struct nvaa_ram_priv *priv = (void *)object;
- int ret;
- u64 dniso, hostnb, flush;
-
- ret = nouveau_ram_init(&priv->base);
- if (ret)
- return ret;
-
- dniso = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1;
- hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1;
- flush = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1;
-
- /* Enable NISO poller for various clients and set their associated
- * read address, only for MCP77/78 and MCP79/7A. (fd#25701)
- */
- nv_wr32(pfb, 0x100c18, dniso);
- nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001);
- nv_wr32(pfb, 0x100c1c, hostnb);
- nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002);
- nv_wr32(pfb, 0x100c24, flush);
- nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000);
-
- return 0;
-}
-
-struct nouveau_oclass
-nvaa_ram_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvaa_ram_ctor,
- .dtor = _nouveau_ram_dtor,
- .init = nvaa_ram_init,
- .fini = _nouveau_ram_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
deleted file mode 100644
index 735cb9580abe..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnvc0.c
+++ /dev/null
@@ -1,733 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/rammap.h>
-#include <subdev/bios/timing.h>
-#include <subdev/ltc.h>
-
-#include <subdev/clock.h>
-#include <subdev/clock/pll.h>
-
-#include <core/option.h>
-
-#include "ramfuc.h"
-
-#include "nvc0.h"
-
-struct nvc0_ramfuc {
- struct ramfuc base;
-
- struct ramfuc_reg r_0x10fe20;
- struct ramfuc_reg r_0x10fe24;
- struct ramfuc_reg r_0x137320;
- struct ramfuc_reg r_0x137330;
-
- struct ramfuc_reg r_0x132000;
- struct ramfuc_reg r_0x132004;
- struct ramfuc_reg r_0x132100;
-
- struct ramfuc_reg r_0x137390;
-
- struct ramfuc_reg r_0x10f290;
- struct ramfuc_reg r_0x10f294;
- struct ramfuc_reg r_0x10f298;
- struct ramfuc_reg r_0x10f29c;
- struct ramfuc_reg r_0x10f2a0;
-
- struct ramfuc_reg r_0x10f300;
- struct ramfuc_reg r_0x10f338;
- struct ramfuc_reg r_0x10f340;
- struct ramfuc_reg r_0x10f344;
- struct ramfuc_reg r_0x10f348;
-
- struct ramfuc_reg r_0x10f910;
- struct ramfuc_reg r_0x10f914;
-
- struct ramfuc_reg r_0x100b0c;
- struct ramfuc_reg r_0x10f050;
- struct ramfuc_reg r_0x10f090;
- struct ramfuc_reg r_0x10f200;
- struct ramfuc_reg r_0x10f210;
- struct ramfuc_reg r_0x10f310;
- struct ramfuc_reg r_0x10f314;
- struct ramfuc_reg r_0x10f610;
- struct ramfuc_reg r_0x10f614;
- struct ramfuc_reg r_0x10f800;
- struct ramfuc_reg r_0x10f808;
- struct ramfuc_reg r_0x10f824;
- struct ramfuc_reg r_0x10f830;
- struct ramfuc_reg r_0x10f988;
- struct ramfuc_reg r_0x10f98c;
- struct ramfuc_reg r_0x10f990;
- struct ramfuc_reg r_0x10f998;
- struct ramfuc_reg r_0x10f9b0;
- struct ramfuc_reg r_0x10f9b4;
- struct ramfuc_reg r_0x10fb04;
- struct ramfuc_reg r_0x10fb08;
- struct ramfuc_reg r_0x137300;
- struct ramfuc_reg r_0x137310;
- struct ramfuc_reg r_0x137360;
- struct ramfuc_reg r_0x1373ec;
- struct ramfuc_reg r_0x1373f0;
- struct ramfuc_reg r_0x1373f8;
-
- struct ramfuc_reg r_0x61c140;
- struct ramfuc_reg r_0x611200;
-
- struct ramfuc_reg r_0x13d8f4;
-};
-
-struct nvc0_ram {
- struct nouveau_ram base;
- struct nvc0_ramfuc fuc;
- struct nvbios_pll refpll;
- struct nvbios_pll mempll;
-};
-
-static void
-nvc0_ram_train(struct nvc0_ramfuc *fuc, u32 magic)
-{
- struct nvc0_ram *ram = container_of(fuc, typeof(*ram), fuc);
- struct nouveau_fb *pfb = nouveau_fb(ram);
- u32 part = nv_rd32(pfb, 0x022438), i;
- u32 mask = nv_rd32(pfb, 0x022554);
- u32 addr = 0x110974;
-
- ram_wr32(fuc, 0x10f910, magic);
- ram_wr32(fuc, 0x10f914, magic);
-
- for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) {
- if (mask & (1 << i))
- continue;
- ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
- }
-}
-
-static int
-nvc0_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
- struct nouveau_clock *clk = nouveau_clock(pfb);
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nvc0_ram *ram = (void *)pfb->ram;
- struct nvc0_ramfuc *fuc = &ram->fuc;
- struct nvbios_ramcfg cfg;
- u8 ver, cnt, len, strap;
- struct {
- u32 data;
- u8 size;
- } rammap, ramcfg, timing;
- int ref, div, out;
- int from, mode;
- int N1, M1, P;
- int ret;
-
- /* lookup memory config data relevant to the target frequency */
- rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
- &cnt, &ramcfg.size, &cfg);
- if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
- nv_error(pfb, "invalid/missing rammap entry\n");
- return -EINVAL;
- }
-
- /* locate specific data set for the attached memory */
- strap = nvbios_ramcfg_index(nv_subdev(pfb));
- if (strap >= cnt) {
- nv_error(pfb, "invalid ramcfg strap\n");
- return -EINVAL;
- }
-
- ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
- if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
- nv_error(pfb, "invalid/missing ramcfg entry\n");
- return -EINVAL;
- }
-
- /* lookup memory timings, if bios says they're present */
- strap = nv_ro08(bios, ramcfg.data + 0x01);
- if (strap != 0xff) {
- timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
- &cnt, &len);
- if (!timing.data || ver != 0x10 || timing.size < 0x19) {
- nv_error(pfb, "invalid/missing timing entry\n");
- return -EINVAL;
- }
- } else {
- timing.data = 0;
- }
-
- ret = ram_init(fuc, pfb);
- if (ret)
- return ret;
-
- /* determine current mclk configuration */
- from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */
-
- /* determine target mclk configuration */
- if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
- ref = clk->read(clk, nv_clk_src_sppll0);
- else
- ref = clk->read(clk, nv_clk_src_sppll1);
- div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
- out = (ref * 2) / (div + 2);
- mode = freq != out;
-
- ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);
-
- if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
- ram_nuke(fuc, 0x132000);
- ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
- ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
- }
-
- if (mode == 1) {
- ram_nuke(fuc, 0x10fe20);
- ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
- ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
- }
-
-// 0x00020034 // 0x0000000a
- ram_wr32(fuc, 0x132100, 0x00000001);
-
- if (mode == 1 && from == 0) {
- /* calculate refpll */
- ret = nva3_pll_calc(nv_subdev(pfb), &ram->refpll,
- ram->mempll.refclk, &N1, NULL, &M1, &P);
- if (ret <= 0) {
- nv_error(pfb, "unable to calc refpll\n");
- return ret ? ret : -ERANGE;
- }
-
- ram_wr32(fuc, 0x10fe20, 0x20010000);
- ram_wr32(fuc, 0x137320, 0x00000003);
- ram_wr32(fuc, 0x137330, 0x81200006);
- ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
- ram_wr32(fuc, 0x10fe20, 0x20010001);
- ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
-
- /* calculate mempll */
- ret = nva3_pll_calc(nv_subdev(pfb), &ram->mempll, freq,
- &N1, NULL, &M1, &P);
- if (ret <= 0) {
- nv_error(pfb, "unable to calc refpll\n");
- return ret ? ret : -ERANGE;
- }
-
- ram_wr32(fuc, 0x10fe20, 0x20010005);
- ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
- ram_wr32(fuc, 0x132000, 0x18010101);
- ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
- } else
- if (mode == 0) {
- ram_wr32(fuc, 0x137300, 0x00000003);
- }
-
- if (from == 0) {
- ram_nuke(fuc, 0x10fb04);
- ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
- ram_nuke(fuc, 0x10fb08);
- ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
- ram_wr32(fuc, 0x10f988, 0x2004ff00);
- ram_wr32(fuc, 0x10f98c, 0x003fc040);
- ram_wr32(fuc, 0x10f990, 0x20012001);
- ram_wr32(fuc, 0x10f998, 0x00011a00);
- ram_wr32(fuc, 0x13d8f4, 0x00000000);
- } else {
- ram_wr32(fuc, 0x10f988, 0x20010000);
- ram_wr32(fuc, 0x10f98c, 0x00000000);
- ram_wr32(fuc, 0x10f990, 0x20012001);
- ram_wr32(fuc, 0x10f998, 0x00010a00);
- }
-
- if (from == 0) {
-// 0x00020039 // 0x000000ba
- }
-
-// 0x0002003a // 0x00000002
- ram_wr32(fuc, 0x100b0c, 0x00080012);
-// 0x00030014 // 0x00000000 // 0x02b5f070
-// 0x00030014 // 0x00010000 // 0x02b5f070
- ram_wr32(fuc, 0x611200, 0x00003300);
-// 0x00020034 // 0x0000000a
-// 0x00030020 // 0x00000001 // 0x00000000
-
- ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
- ram_wr32(fuc, 0x10f210, 0x00000000);
- ram_nsec(fuc, 1000);
- if (mode == 0)
- nvc0_ram_train(fuc, 0x000c1001);
- ram_wr32(fuc, 0x10f310, 0x00000001);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f090, 0x00000061);
- ram_wr32(fuc, 0x10f090, 0xc000007f);
- ram_nsec(fuc, 1000);
-
- if (from == 0) {
- ram_wr32(fuc, 0x10f824, 0x00007fd4);
- } else {
- ram_wr32(fuc, 0x1373ec, 0x00020404);
- }
-
- if (mode == 0) {
- ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
- ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
- ram_wr32(fuc, 0x10f830, 0x41500010);
- ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
- ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
- ram_wr32(fuc, 0x10f050, 0xff000090);
- ram_wr32(fuc, 0x1373ec, 0x00020f0f);
- ram_wr32(fuc, 0x1373f0, 0x00000003);
- ram_wr32(fuc, 0x137310, 0x81201616);
- ram_wr32(fuc, 0x132100, 0x00000001);
-// 0x00020039 // 0x000000ba
- ram_wr32(fuc, 0x10f830, 0x00300017);
- ram_wr32(fuc, 0x1373f0, 0x00000001);
- ram_wr32(fuc, 0x10f824, 0x00007e77);
- ram_wr32(fuc, 0x132000, 0x18030001);
- ram_wr32(fuc, 0x10f090, 0x4000007e);
- ram_nsec(fuc, 2000);
- ram_wr32(fuc, 0x10f314, 0x00000001);
- ram_wr32(fuc, 0x10f210, 0x80000000);
- ram_wr32(fuc, 0x10f338, 0x00300220);
- ram_wr32(fuc, 0x10f300, 0x0000011d);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f290, 0x02060505);
- ram_wr32(fuc, 0x10f294, 0x34208288);
- ram_wr32(fuc, 0x10f298, 0x44050411);
- ram_wr32(fuc, 0x10f29c, 0x0000114c);
- ram_wr32(fuc, 0x10f2a0, 0x42e10069);
- ram_wr32(fuc, 0x10f614, 0x40044f77);
- ram_wr32(fuc, 0x10f610, 0x40044f77);
- ram_wr32(fuc, 0x10f344, 0x00600009);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f348, 0x00700008);
- ram_wr32(fuc, 0x61c140, 0x19240000);
- ram_wr32(fuc, 0x10f830, 0x00300017);
- nvc0_ram_train(fuc, 0x80021001);
- nvc0_ram_train(fuc, 0x80081001);
- ram_wr32(fuc, 0x10f340, 0x00500004);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f830, 0x01300017);
- ram_wr32(fuc, 0x10f830, 0x00300017);
-// 0x00030020 // 0x00000000 // 0x00000000
-// 0x00020034 // 0x0000000b
- ram_wr32(fuc, 0x100b0c, 0x00080028);
- ram_wr32(fuc, 0x611200, 0x00003330);
- } else {
- ram_wr32(fuc, 0x10f800, 0x00001800);
- ram_wr32(fuc, 0x13d8f4, 0x00000000);
- ram_wr32(fuc, 0x1373ec, 0x00020404);
- ram_wr32(fuc, 0x1373f0, 0x00000003);
- ram_wr32(fuc, 0x10f830, 0x40700010);
- ram_wr32(fuc, 0x10f830, 0x40500010);
- ram_wr32(fuc, 0x13d8f4, 0x00000000);
- ram_wr32(fuc, 0x1373f8, 0x00000000);
- ram_wr32(fuc, 0x132100, 0x00000101);
- ram_wr32(fuc, 0x137310, 0x89201616);
- ram_wr32(fuc, 0x10f050, 0xff000090);
- ram_wr32(fuc, 0x1373ec, 0x00030404);
- ram_wr32(fuc, 0x1373f0, 0x00000002);
- // 0x00020039 // 0x00000011
- ram_wr32(fuc, 0x132100, 0x00000001);
- ram_wr32(fuc, 0x1373f8, 0x00002000);
- ram_nsec(fuc, 2000);
- ram_wr32(fuc, 0x10f808, 0x7aaa0050);
- ram_wr32(fuc, 0x10f830, 0x00500010);
- ram_wr32(fuc, 0x10f200, 0x00ce1000);
- ram_wr32(fuc, 0x10f090, 0x4000007e);
- ram_nsec(fuc, 2000);
- ram_wr32(fuc, 0x10f314, 0x00000001);
- ram_wr32(fuc, 0x10f210, 0x80000000);
- ram_wr32(fuc, 0x10f338, 0x00300200);
- ram_wr32(fuc, 0x10f300, 0x0000084d);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f290, 0x0b343825);
- ram_wr32(fuc, 0x10f294, 0x3483028e);
- ram_wr32(fuc, 0x10f298, 0x440c0600);
- ram_wr32(fuc, 0x10f29c, 0x0000214c);
- ram_wr32(fuc, 0x10f2a0, 0x42e20069);
- ram_wr32(fuc, 0x10f200, 0x00ce0000);
- ram_wr32(fuc, 0x10f614, 0x60044e77);
- ram_wr32(fuc, 0x10f610, 0x60044e77);
- ram_wr32(fuc, 0x10f340, 0x00500000);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f344, 0x00600228);
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f348, 0x00700000);
- ram_wr32(fuc, 0x13d8f4, 0x00000000);
- ram_wr32(fuc, 0x61c140, 0x09a40000);
-
- nvc0_ram_train(fuc, 0x800e1008);
-
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f800, 0x00001804);
- // 0x00030020 // 0x00000000 // 0x00000000
- // 0x00020034 // 0x0000000b
- ram_wr32(fuc, 0x13d8f4, 0x00000000);
- ram_wr32(fuc, 0x100b0c, 0x00080028);
- ram_wr32(fuc, 0x611200, 0x00003330);
- ram_nsec(fuc, 100000);
- ram_wr32(fuc, 0x10f9b0, 0x05313f41);
- ram_wr32(fuc, 0x10f9b4, 0x00002f50);
-
- nvc0_ram_train(fuc, 0x010c1001);
- }
-
- ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
-// 0x00020016 // 0x00000000
-
- if (mode == 0)
- ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
- return 0;
-}
-
-static int
-nvc0_ram_prog(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nvc0_ram *ram = (void *)pfb->ram;
- struct nvc0_ramfuc *fuc = &ram->fuc;
- ram_exec(fuc, nouveau_boolopt(device->cfgopt, "NvMemExec", true));
- return 0;
-}
-
-static void
-nvc0_ram_tidy(struct nouveau_fb *pfb)
-{
- struct nvc0_ram *ram = (void *)pfb->ram;
- struct nvc0_ramfuc *fuc = &ram->fuc;
- ram_exec(fuc, false);
-}
-
-extern const u8 nvc0_pte_storage_type_map[256];
-
-void
-nvc0_ram_put(struct nouveau_fb *pfb, struct nouveau_mem **pmem)
-{
- struct nouveau_ltc *ltc = nouveau_ltc(pfb);
- struct nouveau_mem *mem = *pmem;
-
- *pmem = NULL;
- if (unlikely(mem == NULL))
- return;
-
- mutex_lock(&pfb->base.mutex);
- if (mem->tag)
- ltc->tags_free(ltc, &mem->tag);
- __nv50_ram_put(pfb, mem);
- mutex_unlock(&pfb->base.mutex);
-
- kfree(mem);
-}
-
-int
-nvc0_ram_get(struct nouveau_fb *pfb, u64 size, u32 align, u32 ncmin,
- u32 memtype, struct nouveau_mem **pmem)
-{
- struct nouveau_mm *mm = &pfb->vram;
- struct nouveau_mm_node *r;
- struct nouveau_mem *mem;
- int type = (memtype & 0x0ff);
- int back = (memtype & 0x800);
- const bool comp = nvc0_pte_storage_type_map[type] != type;
- int ret;
-
- size >>= 12;
- align >>= 12;
- ncmin >>= 12;
- if (!ncmin)
- ncmin = size;
-
- mem = kzalloc(sizeof(*mem), GFP_KERNEL);
- if (!mem)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&mem->regions);
- mem->size = size;
-
- mutex_lock(&pfb->base.mutex);
- if (comp) {
- struct nouveau_ltc *ltc = nouveau_ltc(pfb);
-
- /* compression only works with lpages */
- if (align == (1 << (17 - 12))) {
- int n = size >> 5;
- ltc->tags_alloc(ltc, n, &mem->tag);
- }
-
- if (unlikely(!mem->tag))
- type = nvc0_pte_storage_type_map[type];
- }
- mem->memtype = type;
-
- do {
- if (back)
- ret = nouveau_mm_tail(mm, 0, 1, size, ncmin, align, &r);
- else
- ret = nouveau_mm_head(mm, 0, 1, size, ncmin, align, &r);
- if (ret) {
- mutex_unlock(&pfb->base.mutex);
- pfb->ram->put(pfb, &mem);
- return ret;
- }
-
- list_add_tail(&r->rl_entry, &mem->regions);
- size -= r->length;
- } while (size);
- mutex_unlock(&pfb->base.mutex);
-
- r = list_first_entry(&mem->regions, struct nouveau_mm_node, rl_entry);
- mem->offset = (u64)r->offset << 12;
- *pmem = mem;
- return 0;
-}
-
-int
-nvc0_ram_create_(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u32 maskaddr, int size,
- void **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nouveau_ram *ram;
- const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
- const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
- u32 parts = nv_rd32(pfb, 0x022438);
- u32 pmask = nv_rd32(pfb, maskaddr);
- u32 bsize = nv_rd32(pfb, 0x10f20c);
- u32 offset, length;
- bool uniform = true;
- int ret, part;
-
- ret = nouveau_ram_create_(parent, engine, oclass, size, pobject);
- ram = *pobject;
- if (ret)
- return ret;
-
- nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
- nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
-
- ram->type = nouveau_fb_bios_memtype(bios);
- ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
-
- /* read amount of vram attached to each memory controller */
- for (part = 0; part < parts; part++) {
- if (!(pmask & (1 << part))) {
- u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
- if (psize != bsize) {
- if (psize < bsize)
- bsize = psize;
- uniform = false;
- }
-
- nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
- ram->size += (u64)psize << 20;
- }
- }
-
- /* if all controllers have the same amount attached, there's no holes */
- if (uniform) {
- offset = rsvd_head;
- length = (ram->size >> 12) - rsvd_head - rsvd_tail;
- ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
- } else {
- /* otherwise, address lowest common amount from 0GiB */
- ret = nouveau_mm_init(&pfb->vram, rsvd_head,
- (bsize << 8) * parts - rsvd_head, 1);
- if (ret)
- return ret;
-
- /* and the rest starting from (8GiB + common_size) */
- offset = (0x0200000000ULL >> 12) + (bsize << 8);
- length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
-
- ret = nouveau_mm_init(&pfb->vram, offset, length, 1);
- if (ret)
- nouveau_mm_fini(&pfb->vram);
- }
-
- if (ret)
- return ret;
-
- ram->get = nvc0_ram_get;
- ram->put = nvc0_ram_put;
- return 0;
-}
-
-static int
-nvc0_ram_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object->parent;
- struct nvc0_ram *ram = (void *)object;
- int ret, i;
-
- ret = nouveau_ram_init(&ram->base);
- if (ret)
- return ret;
-
- /* prepare for ddr link training, and load training patterns */
- switch (ram->base.type) {
- case NV_MEM_TYPE_GDDR5: {
- static const u8 train0[] = {
- 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc,
- 0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
- };
- static const u32 train1[] = {
- 0x00000000, 0xffffffff,
- 0x55555555, 0xaaaaaaaa,
- 0x33333333, 0xcccccccc,
- 0xf0f0f0f0, 0x0f0f0f0f,
- 0x00ff00ff, 0xff00ff00,
- 0x0000ffff, 0xffff0000,
- };
-
- for (i = 0; i < 0x30; i++) {
- nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
- nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
- nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
- nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
- nv_wr32(pfb, 0x10f918, train1[i % 12]);
- nv_wr32(pfb, 0x10f91c, train1[i % 12]);
- nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
- nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
- nv_wr32(pfb, 0x10f918, train1[i % 12]);
- nv_wr32(pfb, 0x10f91c, train1[i % 12]);
- }
- } break;
- default:
- break;
- }
-
- return 0;
-}
-
-static int
-nvc0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_bios *bios = nouveau_bios(parent);
- struct nvc0_ram *ram;
- int ret;
-
- ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll);
- if (ret) {
- nv_error(ram, "mclk refpll data not found\n");
- return ret;
- }
-
- ret = nvbios_pll_parse(bios, 0x04, &ram->mempll);
- if (ret) {
- nv_error(ram, "mclk pll data not found\n");
- return ret;
- }
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_GDDR5:
- ram->base.calc = nvc0_ram_calc;
- ram->base.prog = nvc0_ram_prog;
- ram->base.tidy = nvc0_ram_tidy;
- break;
- default:
- nv_warn(ram, "reclocking of this ram type unsupported\n");
- return 0;
- }
-
- ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20);
- ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24);
- ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
- ram->fuc.r_0x137330 = ramfuc_reg(0x137330);
-
- ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
- ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
- ram->fuc.r_0x132100 = ramfuc_reg(0x132100);
-
- ram->fuc.r_0x137390 = ramfuc_reg(0x137390);
-
- ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
- ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
- ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
- ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
- ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
-
- ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300);
- ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338);
- ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340);
- ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344);
- ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348);
-
- ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
- ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
-
- ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c);
- ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050);
- ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
- ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
- ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
- ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
- ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
- ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
- ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
- ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
- ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
- ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
- ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
- ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988);
- ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c);
- ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990);
- ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998);
- ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0);
- ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4);
- ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04);
- ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08);
- ram->fuc.r_0x137310 = ramfuc_reg(0x137300);
- ram->fuc.r_0x137310 = ramfuc_reg(0x137310);
- ram->fuc.r_0x137360 = ramfuc_reg(0x137360);
- ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
- ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
- ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8);
-
- ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140);
- ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
-
- ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_ram_ctor,
- .dtor = _nouveau_ram_dtor,
- .init = nvc0_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c b/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
deleted file mode 100644
index 6bae474abb44..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramnve0.c
+++ /dev/null
@@ -1,1646 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/gpio.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/pll.h>
-#include <subdev/bios/init.h>
-#include <subdev/bios/rammap.h>
-#include <subdev/bios/timing.h>
-#include <subdev/bios/M0205.h>
-#include <subdev/bios/M0209.h>
-
-#include <subdev/clock.h>
-#include <subdev/clock/pll.h>
-
-#include <subdev/timer.h>
-
-#include <core/option.h>
-
-#include "nvc0.h"
-
-#include "ramfuc.h"
-
-struct nve0_ramfuc {
- struct ramfuc base;
-
- struct nvbios_pll refpll;
- struct nvbios_pll mempll;
-
- struct ramfuc_reg r_gpioMV;
- u32 r_funcMV[2];
- struct ramfuc_reg r_gpio2E;
- u32 r_func2E[2];
- struct ramfuc_reg r_gpiotrig;
-
- struct ramfuc_reg r_0x132020;
- struct ramfuc_reg r_0x132028;
- struct ramfuc_reg r_0x132024;
- struct ramfuc_reg r_0x132030;
- struct ramfuc_reg r_0x132034;
- struct ramfuc_reg r_0x132000;
- struct ramfuc_reg r_0x132004;
- struct ramfuc_reg r_0x132040;
-
- struct ramfuc_reg r_0x10f248;
- struct ramfuc_reg r_0x10f290;
- struct ramfuc_reg r_0x10f294;
- struct ramfuc_reg r_0x10f298;
- struct ramfuc_reg r_0x10f29c;
- struct ramfuc_reg r_0x10f2a0;
- struct ramfuc_reg r_0x10f2a4;
- struct ramfuc_reg r_0x10f2a8;
- struct ramfuc_reg r_0x10f2ac;
- struct ramfuc_reg r_0x10f2cc;
- struct ramfuc_reg r_0x10f2e8;
- struct ramfuc_reg r_0x10f250;
- struct ramfuc_reg r_0x10f24c;
- struct ramfuc_reg r_0x10fec4;
- struct ramfuc_reg r_0x10fec8;
- struct ramfuc_reg r_0x10f604;
- struct ramfuc_reg r_0x10f614;
- struct ramfuc_reg r_0x10f610;
- struct ramfuc_reg r_0x100770;
- struct ramfuc_reg r_0x100778;
- struct ramfuc_reg r_0x10f224;
-
- struct ramfuc_reg r_0x10f870;
- struct ramfuc_reg r_0x10f698;
- struct ramfuc_reg r_0x10f694;
- struct ramfuc_reg r_0x10f6b8;
- struct ramfuc_reg r_0x10f808;
- struct ramfuc_reg r_0x10f670;
- struct ramfuc_reg r_0x10f60c;
- struct ramfuc_reg r_0x10f830;
- struct ramfuc_reg r_0x1373ec;
- struct ramfuc_reg r_0x10f800;
- struct ramfuc_reg r_0x10f82c;
-
- struct ramfuc_reg r_0x10f978;
- struct ramfuc_reg r_0x10f910;
- struct ramfuc_reg r_0x10f914;
-
- struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
-
- struct ramfuc_reg r_0x62c000;
-
- struct ramfuc_reg r_0x10f200;
-
- struct ramfuc_reg r_0x10f210;
- struct ramfuc_reg r_0x10f310;
- struct ramfuc_reg r_0x10f314;
- struct ramfuc_reg r_0x10f318;
- struct ramfuc_reg r_0x10f090;
- struct ramfuc_reg r_0x10f69c;
- struct ramfuc_reg r_0x10f824;
- struct ramfuc_reg r_0x1373f0;
- struct ramfuc_reg r_0x1373f4;
- struct ramfuc_reg r_0x137320;
- struct ramfuc_reg r_0x10f65c;
- struct ramfuc_reg r_0x10f6bc;
- struct ramfuc_reg r_0x100710;
- struct ramfuc_reg r_0x100750;
-};
-
-struct nve0_ram {
- struct nouveau_ram base;
- struct nve0_ramfuc fuc;
-
- struct list_head cfg;
- u32 parts;
- u32 pmask;
- u32 pnuts;
-
- struct nvbios_ramcfg diff;
- int from;
- int mode;
- int N1, fN1, M1, P1;
- int N2, M2, P2;
-};
-
-/*******************************************************************************
- * GDDR5
- ******************************************************************************/
-static void
-nve0_ram_train(struct nve0_ramfuc *fuc, u32 mask, u32 data)
-{
- struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
- u32 addr = 0x110974, i;
-
- ram_mask(fuc, 0x10f910, mask, data);
- ram_mask(fuc, 0x10f914, mask, data);
-
- for (i = 0; (data & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
- if (ram->pmask & (1 << i))
- continue;
- ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
- }
-}
-
-static void
-r1373f4_init(struct nve0_ramfuc *fuc)
-{
- struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
- const u32 mcoef = ((--ram->P2 << 28) | (ram->N2 << 8) | ram->M2);
- const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
- const u32 runk0 = ram->fN1 << 16;
- const u32 runk1 = ram->fN1;
-
- if (ram->from == 2) {
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
- } else {
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
- }
-
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
- ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
-
- /* (re)program refpll, if required */
- if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
- (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
- ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
- ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
- ram_wr32(fuc, 0x137320, 0x00000000);
- ram_mask(fuc, 0x132030, 0xffff0000, runk0);
- ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
- ram_wr32(fuc, 0x132024, rcoef);
- ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
- ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
- ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
- ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
- }
-
- /* (re)program mempll, if required */
- if (ram->mode == 2) {
- ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
- ram_mask(fuc, 0x132000, 0x80000000, 0x80000000);
- ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
- ram_mask(fuc, 0x132004, 0x103fffff, mcoef);
- ram_mask(fuc, 0x132000, 0x00000001, 0x00000001);
- ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
- } else {
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010100);
- }
-
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
-}
-
-static void
-r1373f4_fini(struct nve0_ramfuc *fuc)
-{
- struct nve0_ram *ram = container_of(fuc, typeof(*ram), fuc);
- struct nouveau_ram_data *next = ram->base.next;
- u8 v0 = next->bios.ramcfg_11_03_c0;
- u8 v1 = next->bios.ramcfg_11_03_30;
- u32 tmp;
-
- tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
- ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16));
- ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000);
- if (ram->mode == 2) {
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002);
- ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000);
- } else {
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001);
- ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000);
- }
- ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
-}
-
-static void
-nve0_ram_nuts(struct nve0_ram *ram, struct ramfuc_reg *reg,
- u32 _mask, u32 _data, u32 _copy)
-{
- struct nve0_fb_priv *priv = (void *)nouveau_fb(ram);
- struct ramfuc *fuc = &ram->fuc.base;
- u32 addr = 0x110000 + (reg->addr & 0xfff);
- u32 mask = _mask | _copy;
- u32 data = (_data & _mask) | (reg->data & _copy);
- u32 i;
-
- for (i = 0; i < 16; i++, addr += 0x1000) {
- if (ram->pnuts & (1 << i)) {
- u32 prev = nv_rd32(priv, addr);
- u32 next = (prev & ~mask) | data;
- nouveau_memx_wr32(fuc->memx, addr, next);
- }
- }
-}
-#define ram_nuts(s,r,m,d,c) \
- nve0_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
-
-static int
-nve0_ram_calc_gddr5(struct nouveau_fb *pfb, u32 freq)
-{
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nve0_ramfuc *fuc = &ram->fuc;
- struct nouveau_ram_data *next = ram->base.next;
- int vc = !next->bios.ramcfg_11_02_08;
- int mv = !next->bios.ramcfg_11_02_04;
- u32 mask, data;
-
- ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
- ram_block(fuc);
- ram_wr32(fuc, 0x62c000, 0x0f0f0000);
-
- /* MR1: turn termination on early, for some reason.. */
- if ((ram->base.mr[1] & 0x03c) != 0x030) {
- ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
- ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
- }
-
- if (vc == 1 && ram_have(fuc, gpio2E)) {
- u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
- if (temp != ram_rd32(fuc, gpio2E)) {
- ram_wr32(fuc, gpiotrig, 1);
- ram_nsec(fuc, 20000);
- }
- }
-
- ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
-
- nve0_ram_train(fuc, 0x01020000, 0x000c0000);
-
- ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
- ram_nsec(fuc, 1000);
-
- ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
- ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
- ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
- ram_wr32(fuc, 0x10f090, 0x00000061);
- ram_wr32(fuc, 0x10f090, 0xc000007f);
- ram_nsec(fuc, 1000);
-
- ram_wr32(fuc, 0x10f698, 0x00000000);
- ram_wr32(fuc, 0x10f69c, 0x00000000);
-
- /*XXX: there does appear to be some kind of condition here, simply
- * modifying these bits in the vbios from the default pl0
- * entries shows no change. however, the data does appear to
- * be correct and may be required for the transition back
- */
- mask = 0x800f07e0;
- data = 0x00030000;
- if (ram_rd32(fuc, 0x10f978) & 0x00800000)
- data |= 0x00040000;
-
- if (1) {
- data |= 0x800807e0;
- switch (next->bios.ramcfg_11_03_c0) {
- case 3: data &= ~0x00000040; break;
- case 2: data &= ~0x00000100; break;
- case 1: data &= ~0x80000000; break;
- case 0: data &= ~0x00000400; break;
- }
-
- switch (next->bios.ramcfg_11_03_30) {
- case 3: data &= ~0x00000020; break;
- case 2: data &= ~0x00000080; break;
- case 1: data &= ~0x00080000; break;
- case 0: data &= ~0x00000200; break;
- }
- }
-
- if (next->bios.ramcfg_11_02_80)
- mask |= 0x03000000;
- if (next->bios.ramcfg_11_02_40)
- mask |= 0x00002000;
- if (next->bios.ramcfg_11_07_10)
- mask |= 0x00004000;
- if (next->bios.ramcfg_11_07_08)
- mask |= 0x00000003;
- else {
- mask |= 0x34000000;
- if (ram_rd32(fuc, 0x10f978) & 0x00800000)
- mask |= 0x40000000;
- }
- ram_mask(fuc, 0x10f824, mask, data);
-
- ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
-
- if (ram->from == 2 && ram->mode != 2) {
- ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
- ram_mask(fuc, 0x10f200, 0x18008000, 0x00008000);
- ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004);
- ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010);
- ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
- r1373f4_init(fuc);
- ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001);
- r1373f4_fini(fuc);
- ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001);
- } else
- if (ram->from != 2 && ram->mode != 2) {
- r1373f4_init(fuc);
- r1373f4_fini(fuc);
- }
-
- if (ram_have(fuc, gpioMV)) {
- u32 temp = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
- if (temp != ram_rd32(fuc, gpioMV)) {
- ram_wr32(fuc, gpiotrig, 1);
- ram_nsec(fuc, 64000);
- }
- }
-
- if (next->bios.ramcfg_11_02_40 ||
- next->bios.ramcfg_11_07_10) {
- ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
- ram_nsec(fuc, 20000);
- }
-
- if (ram->from != 2 && ram->mode == 2) {
- if (0 /*XXX: Titan */)
- ram_mask(fuc, 0x10f200, 0x18000000, 0x18000000);
- ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
- ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002);
- ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010);
- r1373f4_init(fuc);
- r1373f4_fini(fuc);
- ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000);
- ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000);
- } else
- if (ram->from == 2 && ram->mode == 2) {
- ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
- r1373f4_init(fuc);
- r1373f4_fini(fuc);
- }
-
- if (ram->mode != 2) /*XXX*/ {
- if (next->bios.ramcfg_11_07_40)
- ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
- }
-
- ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
- ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
- ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
-
- if (!next->bios.ramcfg_11_07_08 && !next->bios.ramcfg_11_07_04) {
- ram_wr32(fuc, 0x10f698, 0x01010101 * next->bios.ramcfg_11_04);
- ram_wr32(fuc, 0x10f69c, 0x01010101 * next->bios.ramcfg_11_04);
- } else
- if (!next->bios.ramcfg_11_07_08) {
- ram_wr32(fuc, 0x10f698, 0x00000000);
- ram_wr32(fuc, 0x10f69c, 0x00000000);
- }
-
- if (ram->mode != 2) {
- u32 data = 0x01000100 * next->bios.ramcfg_11_04;
- ram_nuke(fuc, 0x10f694);
- ram_mask(fuc, 0x10f694, 0xff00ff00, data);
- }
-
- if (ram->mode == 2 && next->bios.ramcfg_11_08_10)
- data = 0x00000080;
- else
- data = 0x00000000;
- ram_mask(fuc, 0x10f60c, 0x00000080, data);
-
- mask = 0x00070000;
- data = 0x00000000;
- if (!next->bios.ramcfg_11_02_80)
- data |= 0x03000000;
- if (!next->bios.ramcfg_11_02_40)
- data |= 0x00002000;
- if (!next->bios.ramcfg_11_07_10)
- data |= 0x00004000;
- if (!next->bios.ramcfg_11_07_08)
- data |= 0x00000003;
- else
- data |= 0x74000000;
- ram_mask(fuc, 0x10f824, mask, data);
-
- if (next->bios.ramcfg_11_01_08)
- data = 0x00000000;
- else
- data = 0x00001000;
- ram_mask(fuc, 0x10f200, 0x00001000, data);
-
- if (ram_rd32(fuc, 0x10f670) & 0x80000000) {
- ram_nsec(fuc, 10000);
- ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000);
- }
-
- if (next->bios.ramcfg_11_08_01)
- data = 0x00100000;
- else
- data = 0x00000000;
- ram_mask(fuc, 0x10f82c, 0x00100000, data);
-
- data = 0x00000000;
- if (next->bios.ramcfg_11_08_08)
- data |= 0x00002000;
- if (next->bios.ramcfg_11_08_04)
- data |= 0x00001000;
- if (next->bios.ramcfg_11_08_02)
- data |= 0x00004000;
- ram_mask(fuc, 0x10f830, 0x00007000, data);
-
- /* PFB timing */
- ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
- ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
- ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
- ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
- ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
- ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
- ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
- ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
- ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
- ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
- ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
-
- data = mask = 0x00000000;
- if (ram->diff.ramcfg_11_08_20) {
- if (next->bios.ramcfg_11_08_20)
- data |= 0x01000000;
- mask |= 0x01000000;
- }
- ram_mask(fuc, 0x10f200, mask, data);
-
- data = mask = 0x00000000;
- if (ram->diff.ramcfg_11_02_03) {
- data |= next->bios.ramcfg_11_02_03 << 8;
- mask |= 0x00000300;
- }
- if (ram->diff.ramcfg_11_01_10) {
- if (next->bios.ramcfg_11_01_10)
- data |= 0x70000000;
- mask |= 0x70000000;
- }
- ram_mask(fuc, 0x10f604, mask, data);
-
- data = mask = 0x00000000;
- if (ram->diff.timing_20_30_07) {
- data |= next->bios.timing_20_30_07 << 28;
- mask |= 0x70000000;
- }
- if (ram->diff.ramcfg_11_01_01) {
- if (next->bios.ramcfg_11_01_01)
- data |= 0x00000100;
- mask |= 0x00000100;
- }
- ram_mask(fuc, 0x10f614, mask, data);
-
- data = mask = 0x00000000;
- if (ram->diff.timing_20_30_07) {
- data |= next->bios.timing_20_30_07 << 28;
- mask |= 0x70000000;
- }
- if (ram->diff.ramcfg_11_01_02) {
- if (next->bios.ramcfg_11_01_02)
- data |= 0x00000100;
- mask |= 0x00000100;
- }
- ram_mask(fuc, 0x10f610, mask, data);
-
- mask = 0x33f00000;
- data = 0x00000000;
- if (!next->bios.ramcfg_11_01_04)
- data |= 0x20200000;
- if (!next->bios.ramcfg_11_07_80)
- data |= 0x12800000;
- /*XXX: see note above about there probably being some condition
- * for the 10f824 stuff that uses ramcfg 3...
- */
- if (next->bios.ramcfg_11_03_f0) {
- if (next->bios.rammap_11_08_0c) {
- if (!next->bios.ramcfg_11_07_80)
- mask |= 0x00000020;
- else
- data |= 0x00000020;
- mask |= 0x00000004;
- }
- } else {
- mask |= 0x40000020;
- data |= 0x00000004;
- }
-
- ram_mask(fuc, 0x10f808, mask, data);
-
- ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
-
- data = mask = 0x00000000;
- if (ram->diff.ramcfg_11_02_03) {
- data |= next->bios.ramcfg_11_02_03;
- mask |= 0x00000003;
- }
- if (ram->diff.ramcfg_11_01_10) {
- if (next->bios.ramcfg_11_01_10)
- data |= 0x00000004;
- mask |= 0x00000004;
- }
-
- if ((ram_mask(fuc, 0x100770, mask, data) & mask & 4) != (data & 4)) {
- ram_mask(fuc, 0x100750, 0x00000008, 0x00000008);
- ram_wr32(fuc, 0x100710, 0x00000000);
- ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000);
- }
-
- data = next->bios.timing_20_30_07 << 8;
- if (next->bios.ramcfg_11_01_01)
- data |= 0x80000000;
- ram_mask(fuc, 0x100778, 0x00000700, data);
-
- ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
- data = (next->bios.timing[10] & 0x7f000000) >> 24;
- if (data < next->bios.timing_20_2c_1fc0)
- data = next->bios.timing_20_2c_1fc0;
- ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
- ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
-
- ram_mask(fuc, 0x10fec4, 0x041e0f07, next->bios.timing_20_31_0800 << 26 |
- next->bios.timing_20_31_0780 << 17 |
- next->bios.timing_20_31_0078 << 8 |
- next->bios.timing_20_31_0007);
- ram_mask(fuc, 0x10fec8, 0x00000027, next->bios.timing_20_31_8000 << 5 |
- next->bios.timing_20_31_7000);
-
- ram_wr32(fuc, 0x10f090, 0x4000007e);
- ram_nsec(fuc, 2000);
- ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
- ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
- ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
-
- if (next->bios.ramcfg_11_08_10 && (ram->mode == 2) /*XXX*/) {
- u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000);
- nve0_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/
- ram_nsec(fuc, 1000);
- ram_wr32(fuc, 0x10f294, temp);
- }
-
- ram_mask(fuc, mr[3], 0xfff, ram->base.mr[3]);
- ram_wr32(fuc, mr[0], ram->base.mr[0]);
- ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]);
- ram_nsec(fuc, 1000);
- ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]);
- ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5] & ~0x004); /* LP3 later */
- ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]);
- ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]);
-
- if (vc == 0 && ram_have(fuc, gpio2E)) {
- u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
- if (temp != ram_rd32(fuc, gpio2E)) {
- ram_wr32(fuc, gpiotrig, 1);
- ram_nsec(fuc, 20000);
- }
- }
-
- ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
- ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
- ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
- ram_nsec(fuc, 1000);
- ram_nuts(ram, 0x10f200, 0x18808800, 0x00000000, 0x18808800);
-
- data = ram_rd32(fuc, 0x10f978);
- data &= ~0x00046144;
- data |= 0x0000000b;
- if (!next->bios.ramcfg_11_07_08) {
- if (!next->bios.ramcfg_11_07_04)
- data |= 0x0000200c;
- else
- data |= 0x00000000;
- } else {
- data |= 0x00040044;
- }
- ram_wr32(fuc, 0x10f978, data);
-
- if (ram->mode == 1) {
- data = ram_rd32(fuc, 0x10f830) | 0x00000001;
- ram_wr32(fuc, 0x10f830, data);
- }
-
- if (!next->bios.ramcfg_11_07_08) {
- data = 0x88020000;
- if ( next->bios.ramcfg_11_07_04)
- data |= 0x10000000;
- if (!next->bios.rammap_11_08_10)
- data |= 0x00080000;
- } else {
- data = 0xa40e0000;
- }
- nve0_ram_train(fuc, 0xbc0f0000, data);
- if (1) /* XXX: not always? */
- ram_nsec(fuc, 1000);
-
- if (ram->mode == 2) { /*XXX*/
- ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004);
- }
-
- /* LP3 */
- if (ram_mask(fuc, mr[5], 0x004, ram->base.mr[5]) != ram->base.mr[5])
- ram_nsec(fuc, 1000);
-
- if (ram->mode != 2) {
- ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
- ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
- }
-
- if (next->bios.ramcfg_11_07_02)
- nve0_ram_train(fuc, 0x80020000, 0x01000000);
-
- ram_unblock(fuc);
- ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
-
- if (next->bios.rammap_11_08_01)
- data = 0x00000800;
- else
- data = 0x00000000;
- ram_mask(fuc, 0x10f200, 0x00000800, data);
- ram_nuts(ram, 0x10f200, 0x18808800, data, 0x18808800);
- return 0;
-}
-
-/*******************************************************************************
- * DDR3
- ******************************************************************************/
-
-static int
-nve0_ram_calc_sddr3(struct nouveau_fb *pfb, u32 freq)
-{
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nve0_ramfuc *fuc = &ram->fuc;
- const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
- const u32 runk0 = ram->fN1 << 16;
- const u32 runk1 = ram->fN1;
- struct nouveau_ram_data *next = ram->base.next;
- int vc = !next->bios.ramcfg_11_02_08;
- int mv = !next->bios.ramcfg_11_02_04;
- u32 mask, data;
-
- ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
- ram_block(fuc);
- ram_wr32(fuc, 0x62c000, 0x0f0f0000);
-
- if (vc == 1 && ram_have(fuc, gpio2E)) {
- u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
- if (temp != ram_rd32(fuc, gpio2E)) {
- ram_wr32(fuc, gpiotrig, 1);
- ram_nsec(fuc, 20000);
- }
- }
-
- ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
- if (next->bios.ramcfg_11_03_f0)
- ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
-
- ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
- ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
- ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
- ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
- ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
- ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
- ram_nsec(fuc, 1000);
-
- ram_wr32(fuc, 0x10f090, 0x00000060);
- ram_wr32(fuc, 0x10f090, 0xc000007e);
-
- /*XXX: there does appear to be some kind of condition here, simply
- * modifying these bits in the vbios from the default pl0
- * entries shows no change. however, the data does appear to
- * be correct and may be required for the transition back
- */
- mask = 0x00010000;
- data = 0x00010000;
-
- if (1) {
- mask |= 0x800807e0;
- data |= 0x800807e0;
- switch (next->bios.ramcfg_11_03_c0) {
- case 3: data &= ~0x00000040; break;
- case 2: data &= ~0x00000100; break;
- case 1: data &= ~0x80000000; break;
- case 0: data &= ~0x00000400; break;
- }
-
- switch (next->bios.ramcfg_11_03_30) {
- case 3: data &= ~0x00000020; break;
- case 2: data &= ~0x00000080; break;
- case 1: data &= ~0x00080000; break;
- case 0: data &= ~0x00000200; break;
- }
- }
-
- if (next->bios.ramcfg_11_02_80)
- mask |= 0x03000000;
- if (next->bios.ramcfg_11_02_40)
- mask |= 0x00002000;
- if (next->bios.ramcfg_11_07_10)
- mask |= 0x00004000;
- if (next->bios.ramcfg_11_07_08)
- mask |= 0x00000003;
- else
- mask |= 0x14000000;
- ram_mask(fuc, 0x10f824, mask, data);
-
- ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
-
- ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
- data = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
- data |= next->bios.ramcfg_11_03_30 << 16;
- ram_wr32(fuc, 0x1373ec, data);
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
- ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
-
- /* (re)program refpll, if required */
- if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
- (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
- ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
- ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
- ram_wr32(fuc, 0x137320, 0x00000000);
- ram_mask(fuc, 0x132030, 0xffff0000, runk0);
- ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
- ram_wr32(fuc, 0x132024, rcoef);
- ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
- ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
- ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
- ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
- }
-
- ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000010);
- ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001);
- ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
-
- if (ram_have(fuc, gpioMV)) {
- u32 temp = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
- if (temp != ram_rd32(fuc, gpioMV)) {
- ram_wr32(fuc, gpiotrig, 1);
- ram_nsec(fuc, 64000);
- }
- }
-
- if (next->bios.ramcfg_11_02_40 ||
- next->bios.ramcfg_11_07_10) {
- ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
- ram_nsec(fuc, 20000);
- }
-
- if (ram->mode != 2) /*XXX*/ {
- if (next->bios.ramcfg_11_07_40)
- ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
- }
-
- ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
- ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
- ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
-
- mask = 0x00010000;
- data = 0x00000000;
- if (!next->bios.ramcfg_11_02_80)
- data |= 0x03000000;
- if (!next->bios.ramcfg_11_02_40)
- data |= 0x00002000;
- if (!next->bios.ramcfg_11_07_10)
- data |= 0x00004000;
- if (!next->bios.ramcfg_11_07_08)
- data |= 0x00000003;
- else
- data |= 0x14000000;
- ram_mask(fuc, 0x10f824, mask, data);
- ram_nsec(fuc, 1000);
-
- if (next->bios.ramcfg_11_08_01)
- data = 0x00100000;
- else
- data = 0x00000000;
- ram_mask(fuc, 0x10f82c, 0x00100000, data);
-
- /* PFB timing */
- ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
- ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
- ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
- ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
- ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
- ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
- ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
- ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
- ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
- ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
- ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
-
- mask = 0x33f00000;
- data = 0x00000000;
- if (!next->bios.ramcfg_11_01_04)
- data |= 0x20200000;
- if (!next->bios.ramcfg_11_07_80)
- data |= 0x12800000;
- /*XXX: see note above about there probably being some condition
- * for the 10f824 stuff that uses ramcfg 3...
- */
- if (next->bios.ramcfg_11_03_f0) {
- if (next->bios.rammap_11_08_0c) {
- if (!next->bios.ramcfg_11_07_80)
- mask |= 0x00000020;
- else
- data |= 0x00000020;
- mask |= 0x08000004;
- }
- data |= 0x04000000;
- } else {
- mask |= 0x44000020;
- data |= 0x08000004;
- }
-
- ram_mask(fuc, 0x10f808, mask, data);
-
- ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
-
- ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
-
- data = (next->bios.timing[10] & 0x7f000000) >> 24;
- if (data < next->bios.timing_20_2c_1fc0)
- data = next->bios.timing_20_2c_1fc0;
- ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
-
- ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
-
- ram_wr32(fuc, 0x10f090, 0x4000007f);
- ram_nsec(fuc, 1000);
-
- ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
- ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
- ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
- ram_nsec(fuc, 1000);
-
- ram_nuke(fuc, mr[0]);
- ram_mask(fuc, mr[0], 0x100, 0x100);
- ram_mask(fuc, mr[0], 0x100, 0x000);
-
- ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]);
- ram_wr32(fuc, mr[0], ram->base.mr[0]);
- ram_nsec(fuc, 1000);
-
- ram_nuke(fuc, mr[0]);
- ram_mask(fuc, mr[0], 0x100, 0x100);
- ram_mask(fuc, mr[0], 0x100, 0x000);
-
- if (vc == 0 && ram_have(fuc, gpio2E)) {
- u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
- if (temp != ram_rd32(fuc, gpio2E)) {
- ram_wr32(fuc, gpiotrig, 1);
- ram_nsec(fuc, 20000);
- }
- }
-
- if (ram->mode != 2) {
- ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
- ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
- }
-
- ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
- ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
- ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
- ram_nsec(fuc, 1000);
-
- ram_unblock(fuc);
- ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
-
- if (next->bios.rammap_11_08_01)
- data = 0x00000800;
- else
- data = 0x00000000;
- ram_mask(fuc, 0x10f200, 0x00000800, data);
- return 0;
-}
-
-/*******************************************************************************
- * main hooks
- ******************************************************************************/
-
-static int
-nve0_ram_calc_data(struct nouveau_fb *pfb, u32 khz,
- struct nouveau_ram_data *data)
-{
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nouveau_ram_data *cfg;
- u32 mhz = khz / 1000;
-
- list_for_each_entry(cfg, &ram->cfg, head) {
- if (mhz >= cfg->bios.rammap_min &&
- mhz <= cfg->bios.rammap_max) {
- *data = *cfg;
- data->freq = khz;
- return 0;
- }
- }
-
- nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
- return -EINVAL;
-}
-
-static int
-nve0_ram_calc_xits(struct nouveau_fb *pfb, struct nouveau_ram_data *next)
-{
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nve0_ramfuc *fuc = &ram->fuc;
- int refclk, i;
- int ret;
-
- ret = ram_init(fuc, pfb);
- if (ret)
- return ret;
-
- ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
- ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
-
- /* XXX: this is *not* what nvidia do. on fermi nvidia generally
- * select, based on some unknown condition, one of the two possible
- * reference frequencies listed in the vbios table for mempll and
- * program refpll to that frequency.
- *
- * so far, i've seen very weird values being chosen by nvidia on
- * kepler boards, no idea how/why they're chosen.
- */
- refclk = next->freq;
- if (ram->mode == 2)
- refclk = fuc->mempll.refclk;
-
- /* calculate refpll coefficients */
- ret = nva3_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1,
- &ram->fN1, &ram->M1, &ram->P1);
- fuc->mempll.refclk = ret;
- if (ret <= 0) {
- nv_error(pfb, "unable to calc refpll\n");
- return -EINVAL;
- }
-
- /* calculate mempll coefficients, if we're using it */
- if (ram->mode == 2) {
- /* post-divider doesn't work... the reg takes the values but
- * appears to completely ignore it. there *is* a bit at
- * bit 28 that appears to divide the clock by 2 if set.
- */
- fuc->mempll.min_p = 1;
- fuc->mempll.max_p = 2;
-
- ret = nva3_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq,
- &ram->N2, NULL, &ram->M2, &ram->P2);
- if (ret <= 0) {
- nv_error(pfb, "unable to calc mempll\n");
- return -EINVAL;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) {
- if (ram_have(fuc, mr[i]))
- ram->base.mr[i] = ram_rd32(fuc, mr[i]);
- }
- ram->base.freq = next->freq;
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR3:
- ret = nouveau_sddr3_calc(&ram->base);
- if (ret == 0)
- ret = nve0_ram_calc_sddr3(pfb, next->freq);
- break;
- case NV_MEM_TYPE_GDDR5:
- ret = nouveau_gddr5_calc(&ram->base, ram->pnuts != 0);
- if (ret == 0)
- ret = nve0_ram_calc_gddr5(pfb, next->freq);
- break;
- default:
- ret = -ENOSYS;
- break;
- }
-
- return ret;
-}
-
-static int
-nve0_ram_calc(struct nouveau_fb *pfb, u32 freq)
-{
- struct nouveau_clock *clk = nouveau_clock(pfb);
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nouveau_ram_data *xits = &ram->base.xition;
- struct nouveau_ram_data *copy;
- int ret;
-
- if (ram->base.next == NULL) {
- ret = nve0_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem),
- &ram->base.former);
- if (ret)
- return ret;
-
- ret = nve0_ram_calc_data(pfb, freq, &ram->base.target);
- if (ret)
- return ret;
-
- if (ram->base.target.freq < ram->base.former.freq) {
- *xits = ram->base.target;
- copy = &ram->base.former;
- } else {
- *xits = ram->base.former;
- copy = &ram->base.target;
- }
-
- xits->bios.ramcfg_11_02_04 = copy->bios.ramcfg_11_02_04;
- xits->bios.ramcfg_11_02_03 = copy->bios.ramcfg_11_02_03;
- xits->bios.timing_20_30_07 = copy->bios.timing_20_30_07;
-
- ram->base.next = &ram->base.target;
- if (memcmp(xits, &ram->base.former, sizeof(xits->bios)))
- ram->base.next = &ram->base.xition;
- } else {
- BUG_ON(ram->base.next != &ram->base.xition);
- ram->base.next = &ram->base.target;
- }
-
- return nve0_ram_calc_xits(pfb, ram->base.next);
-}
-
-static void
-nve0_ram_prog_0(struct nouveau_fb *pfb, u32 freq)
-{
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nouveau_ram_data *cfg;
- u32 mhz = freq / 1000;
- u32 mask, data;
-
- list_for_each_entry(cfg, &ram->cfg, head) {
- if (mhz >= cfg->bios.rammap_min &&
- mhz <= cfg->bios.rammap_max)
- break;
- }
-
- if (&cfg->head == &ram->cfg)
- return;
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
- data |= cfg->bios.rammap_11_0a_03fe << 12;
- mask |= 0x001ff000;
- }
- if (ram->diff.rammap_11_09_01ff) {
- data |= cfg->bios.rammap_11_09_01ff;
- mask |= 0x000001ff;
- }
- nv_mask(pfb, 0x10f468, mask, data);
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
- data |= cfg->bios.rammap_11_0a_0400;
- mask |= 0x00000001;
- }
- nv_mask(pfb, 0x10f420, mask, data);
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
- data |= cfg->bios.rammap_11_0a_0800;
- mask |= 0x00000001;
- }
- nv_mask(pfb, 0x10f430, mask, data);
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
- data |= cfg->bios.rammap_11_0b_01f0;
- mask |= 0x0000001f;
- }
- nv_mask(pfb, 0x10f400, mask, data);
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
- data |= cfg->bios.rammap_11_0b_0200 << 9;
- mask |= 0x00000200;
- }
- nv_mask(pfb, 0x10f410, mask, data);
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
- data |= cfg->bios.rammap_11_0d << 16;
- mask |= 0x00ff0000;
- }
- if (ram->diff.rammap_11_0f) {
- data |= cfg->bios.rammap_11_0f << 8;
- mask |= 0x0000ff00;
- }
- nv_mask(pfb, 0x10f440, mask, data);
-
- if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
- data |= cfg->bios.rammap_11_0e << 8;
- mask |= 0x0000ff00;
- }
- if (ram->diff.rammap_11_0b_0800) {
- data |= cfg->bios.rammap_11_0b_0800 << 7;
- mask |= 0x00000080;
- }
- if (ram->diff.rammap_11_0b_0400) {
- data |= cfg->bios.rammap_11_0b_0400 << 5;
- mask |= 0x00000020;
- }
- nv_mask(pfb, 0x10f444, mask, data);
-}
-
-static int
-nve0_ram_prog(struct nouveau_fb *pfb)
-{
- struct nouveau_device *device = nv_device(pfb);
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nve0_ramfuc *fuc = &ram->fuc;
- struct nouveau_ram_data *next = ram->base.next;
-
- if (!nouveau_boolopt(device->cfgopt, "NvMemExec", true)) {
- ram_exec(fuc, false);
- return (ram->base.next == &ram->base.xition);
- }
-
- nve0_ram_prog_0(pfb, 1000);
- ram_exec(fuc, true);
- nve0_ram_prog_0(pfb, next->freq);
-
- return (ram->base.next == &ram->base.xition);
-}
-
-static void
-nve0_ram_tidy(struct nouveau_fb *pfb)
-{
- struct nve0_ram *ram = (void *)pfb->ram;
- struct nve0_ramfuc *fuc = &ram->fuc;
- ram->base.next = NULL;
- ram_exec(fuc, false);
-}
-
-struct nve0_ram_train {
- u16 mask;
- struct nvbios_M0209S remap;
- struct nvbios_M0209S type00;
- struct nvbios_M0209S type01;
- struct nvbios_M0209S type04;
- struct nvbios_M0209S type06;
- struct nvbios_M0209S type07;
- struct nvbios_M0209S type08;
- struct nvbios_M0209S type09;
-};
-
-static int
-nve0_ram_train_type(struct nouveau_fb *pfb, int i, u8 ramcfg,
- struct nve0_ram_train *train)
-{
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nvbios_M0205E M0205E;
- struct nvbios_M0205S M0205S;
- struct nvbios_M0209E M0209E;
- struct nvbios_M0209S *remap = &train->remap;
- struct nvbios_M0209S *value;
- u8 ver, hdr, cnt, len;
- u32 data;
-
- /* determine type of data for this index */
- if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)))
- return -ENOENT;
-
- switch (M0205E.type) {
- case 0x00: value = &train->type00; break;
- case 0x01: value = &train->type01; break;
- case 0x04: value = &train->type04; break;
- case 0x06: value = &train->type06; break;
- case 0x07: value = &train->type07; break;
- case 0x08: value = &train->type08; break;
- case 0x09: value = &train->type09; break;
- default:
- return 0;
- }
-
- /* training data index determined by ramcfg strap */
- if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S)))
- return -EINVAL;
- i = M0205S.data;
-
- /* training data format information */
- if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E)))
- return -EINVAL;
-
- /* ... and the raw data */
- if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value)))
- return -EINVAL;
-
- if (M0209E.v02_07 == 2) {
- /* of course! why wouldn't we have a pointer to another entry
- * in the same table, and use the first one as an array of
- * remap indices...
- */
- if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr,
- remap)))
- return -EINVAL;
-
- for (i = 0; i < ARRAY_SIZE(value->data); i++)
- value->data[i] = remap->data[value->data[i]];
- } else
- if (M0209E.v02_07 != 1)
- return -EINVAL;
-
- train->mask |= 1 << M0205E.type;
- return 0;
-}
-
-static int
-nve0_ram_train_init_0(struct nouveau_fb *pfb, struct nve0_ram_train *train)
-{
- int i, j;
-
- if ((train->mask & 0x03d3) != 0x03d3) {
- nv_warn(pfb, "missing link training data\n");
- return -EINVAL;
- }
-
- for (i = 0; i < 0x30; i++) {
- for (j = 0; j < 8; j += 4) {
- nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
- nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
- train->type08.data[i] << 4 |
- train->type06.data[i]);
- nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
- nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
- train->type09.data[i] << 4 |
- train->type07.data[i]);
- nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
- }
- }
-
- for (j = 0; j < 8; j += 4) {
- for (i = 0; i < 0x100; i++) {
- nv_wr32(pfb, 0x10f968 + j, i);
- nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
- }
- }
-
- return 0;
-}
-
-static int
-nve0_ram_train_init(struct nouveau_fb *pfb)
-{
- u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
- struct nve0_ram_train *train;
- int ret = -ENOMEM, i;
-
- if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
- for (i = 0; i < 0x100; i++) {
- ret = nve0_ram_train_type(pfb, i, ramcfg, train);
- if (ret && ret != -ENOENT)
- break;
- }
- }
-
- switch (pfb->ram->type) {
- case NV_MEM_TYPE_GDDR5:
- ret = nve0_ram_train_init_0(pfb, train);
- break;
- default:
- ret = 0;
- break;
- }
-
- kfree(train);
- return ret;
-}
-
-int
-nve0_ram_init(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = (void *)object->parent;
- struct nve0_ram *ram = (void *)object;
- struct nouveau_bios *bios = nouveau_bios(pfb);
- u8 ver, hdr, cnt, len, snr, ssz;
- u32 data, save;
- int ret, i;
-
- ret = nouveau_ram_init(&ram->base);
- if (ret)
- return ret;
-
- /* run a bunch of tables from rammap table. there's actually
- * individual pointers for each rammap entry too, but, nvidia
- * seem to just run the last two entries' scripts early on in
- * their init, and never again.. we'll just run 'em all once
- * for now.
- *
- * i strongly suspect that each script is for a separate mode
- * (likely selected by 0x10f65c's lower bits?), and the
- * binary driver skips the one that's already been setup by
- * the init tables.
- */
- data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
- if (!data || hdr < 0x15)
- return -EINVAL;
-
- cnt = nv_ro08(bios, data + 0x14); /* guess at count */
- data = nv_ro32(bios, data + 0x10); /* guess u32... */
- save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
- for (i = 0; i < cnt; i++, data += 4) {
- if (i != save >> 4) {
- nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
- nvbios_exec(&(struct nvbios_init) {
- .subdev = nv_subdev(pfb),
- .bios = bios,
- .offset = nv_ro32(bios, data),
- .execute = 1,
- });
- }
- }
- nv_mask(pfb, 0x10f65c, 0x000000f0, save);
- nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
- nv_wr32(pfb, 0x10ecc0, 0xffffffff);
- nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
-
- return nve0_ram_train_init(pfb);
-}
-
-static int
-nve0_ram_ctor_data(struct nve0_ram *ram, u8 ramcfg, int i)
-{
- struct nouveau_fb *pfb = (void *)nv_object(ram)->parent;
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nouveau_ram_data *cfg;
- struct nvbios_ramcfg *d = &ram->diff;
- struct nvbios_ramcfg *p, *n;
- u8 ver, hdr, cnt, len;
- u32 data;
- int ret;
-
- if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
- return -ENOMEM;
- p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
- n = &cfg->bios;
-
- /* memory config data for a range of target frequencies */
- data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
- if (ret = -ENOENT, !data)
- goto done;
- if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
- goto done;
-
- /* ... and a portion specific to the attached memory */
- data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
- &ver, &hdr, &cfg->bios);
- if (ret = -EINVAL, !data)
- goto done;
- if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
- goto done;
-
- /* lookup memory timings, if bios says they're present */
- if (cfg->bios.ramcfg_timing != 0xff) {
- data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
- &ver, &hdr, &cnt, &len,
- &cfg->bios);
- if (ret = -EINVAL, !data)
- goto done;
- if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
- goto done;
- }
-
- list_add_tail(&cfg->head, &ram->cfg);
- if (ret = 0, i == 0)
- goto done;
-
- d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
- d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
- d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
- d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
- d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
- d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
- d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
- d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
- d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
- d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
- d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
- d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
- d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
- d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;
- d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03;
- d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20;
- d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07;
-done:
- if (ret)
- kfree(cfg);
- return ret;
-}
-
-static void
-nve0_ram_dtor(struct nouveau_object *object)
-{
- struct nve0_ram *ram = (void *)object;
- struct nouveau_ram_data *cfg, *tmp;
-
- list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
- kfree(cfg);
- }
-
- nouveau_ram_destroy(&ram->base);
-}
-
-static int
-nve0_ram_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_bios *bios = nouveau_bios(pfb);
- struct nouveau_gpio *gpio = nouveau_gpio(pfb);
- struct dcb_gpio_func func;
- struct nve0_ram *ram;
- int ret, i;
- u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
- u32 tmp;
-
- ret = nvc0_ram_create(parent, engine, oclass, 0x022554, &ram);
- *pobject = nv_object(ram);
- if (ret)
- return ret;
-
- INIT_LIST_HEAD(&ram->cfg);
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_DDR3:
- case NV_MEM_TYPE_GDDR5:
- ram->base.calc = nve0_ram_calc;
- ram->base.prog = nve0_ram_prog;
- ram->base.tidy = nve0_ram_tidy;
- break;
- default:
- nv_warn(pfb, "reclocking of this RAM type is unsupported\n");
- break;
- }
-
- /* calculate a mask of differently configured memory partitions,
- * because, of course reclocking wasn't complicated enough
- * already without having to treat some of them differently to
- * the others....
- */
- ram->parts = nv_rd32(pfb, 0x022438);
- ram->pmask = nv_rd32(pfb, 0x022554);
- ram->pnuts = 0;
- for (i = 0, tmp = 0; i < ram->parts; i++) {
- if (!(ram->pmask & (1 << i))) {
- u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
- if (tmp && tmp != cfg1) {
- ram->pnuts |= (1 << i);
- continue;
- }
- tmp = cfg1;
- }
- }
-
- /* parse bios data for all rammap table entries up-front, and
- * build information on whether certain fields differ between
- * any of the entries.
- *
- * the binary driver appears to completely ignore some fields
- * when all entries contain the same value. at first, it was
- * hoped that these were mere optimisations and the bios init
- * tables had configured as per the values here, but there is
- * evidence now to suggest that this isn't the case and we do
- * need to treat this condition as a "don't touch" indicator.
- */
- for (i = 0; !ret; i++) {
- ret = nve0_ram_ctor_data(ram, ramcfg, i);
- if (ret && ret != -ENOENT) {
- nv_error(pfb, "failed to parse ramcfg data\n");
- return ret;
- }
- }
-
- /* parse bios data for both pll's */
- ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
- if (ret) {
- nv_error(pfb, "mclk refpll data not found\n");
- return ret;
- }
-
- ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll);
- if (ret) {
- nv_error(pfb, "mclk pll data not found\n");
- return ret;
- }
-
- /* lookup memory voltage gpios */
- ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
- if (ret == 0) {
- ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
- ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
- ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
- }
-
- ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
- if (ret == 0) {
- ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
- ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
- ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12;
- }
-
- ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604);
-
- ram->fuc.r_0x132020 = ramfuc_reg(0x132020);
- ram->fuc.r_0x132028 = ramfuc_reg(0x132028);
- ram->fuc.r_0x132024 = ramfuc_reg(0x132024);
- ram->fuc.r_0x132030 = ramfuc_reg(0x132030);
- ram->fuc.r_0x132034 = ramfuc_reg(0x132034);
- ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
- ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
- ram->fuc.r_0x132040 = ramfuc_reg(0x132040);
-
- ram->fuc.r_0x10f248 = ramfuc_reg(0x10f248);
- ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
- ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
- ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
- ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
- ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
- ram->fuc.r_0x10f2a4 = ramfuc_reg(0x10f2a4);
- ram->fuc.r_0x10f2a8 = ramfuc_reg(0x10f2a8);
- ram->fuc.r_0x10f2ac = ramfuc_reg(0x10f2ac);
- ram->fuc.r_0x10f2cc = ramfuc_reg(0x10f2cc);
- ram->fuc.r_0x10f2e8 = ramfuc_reg(0x10f2e8);
- ram->fuc.r_0x10f250 = ramfuc_reg(0x10f250);
- ram->fuc.r_0x10f24c = ramfuc_reg(0x10f24c);
- ram->fuc.r_0x10fec4 = ramfuc_reg(0x10fec4);
- ram->fuc.r_0x10fec8 = ramfuc_reg(0x10fec8);
- ram->fuc.r_0x10f604 = ramfuc_reg(0x10f604);
- ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
- ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
- ram->fuc.r_0x100770 = ramfuc_reg(0x100770);
- ram->fuc.r_0x100778 = ramfuc_reg(0x100778);
- ram->fuc.r_0x10f224 = ramfuc_reg(0x10f224);
-
- ram->fuc.r_0x10f870 = ramfuc_reg(0x10f870);
- ram->fuc.r_0x10f698 = ramfuc_reg(0x10f698);
- ram->fuc.r_0x10f694 = ramfuc_reg(0x10f694);
- ram->fuc.r_0x10f6b8 = ramfuc_reg(0x10f6b8);
- ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
- ram->fuc.r_0x10f670 = ramfuc_reg(0x10f670);
- ram->fuc.r_0x10f60c = ramfuc_reg(0x10f60c);
- ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
- ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
- ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
- ram->fuc.r_0x10f82c = ramfuc_reg(0x10f82c);
-
- ram->fuc.r_0x10f978 = ramfuc_reg(0x10f978);
- ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
- ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
-
- switch (ram->base.type) {
- case NV_MEM_TYPE_GDDR5:
- ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
- ram->fuc.r_mr[1] = ramfuc_reg(0x10f330);
- ram->fuc.r_mr[2] = ramfuc_reg(0x10f334);
- ram->fuc.r_mr[3] = ramfuc_reg(0x10f338);
- ram->fuc.r_mr[4] = ramfuc_reg(0x10f33c);
- ram->fuc.r_mr[5] = ramfuc_reg(0x10f340);
- ram->fuc.r_mr[6] = ramfuc_reg(0x10f344);
- ram->fuc.r_mr[7] = ramfuc_reg(0x10f348);
- ram->fuc.r_mr[8] = ramfuc_reg(0x10f354);
- ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c);
- break;
- case NV_MEM_TYPE_DDR3:
- ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
- ram->fuc.r_mr[2] = ramfuc_reg(0x10f320);
- break;
- default:
- break;
- }
-
- ram->fuc.r_0x62c000 = ramfuc_reg(0x62c000);
- ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
- ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
- ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
- ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
- ram->fuc.r_0x10f318 = ramfuc_reg(0x10f318);
- ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
- ram->fuc.r_0x10f69c = ramfuc_reg(0x10f69c);
- ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
- ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
- ram->fuc.r_0x1373f4 = ramfuc_reg(0x1373f4);
- ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
- ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c);
- ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc);
- ram->fuc.r_0x100710 = ramfuc_reg(0x100710);
- ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
- return 0;
-}
-
-struct nouveau_oclass
-nve0_ram_oclass = {
- .handle = 0,
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_ram_ctor,
- .dtor = nve0_ram_dtor,
- .init = nve0_ram_init,
- .fini = _nouveau_ram_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h b/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h
deleted file mode 100644
index 571077e39071..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/ramseq.h
+++ /dev/null
@@ -1,18 +0,0 @@
-#ifndef __NVKM_FBRAM_SEQ_H__
-#define __NVKM_FBRAM_SEQ_H__
-
-#include <subdev/bus.h>
-#include <subdev/bus/hwsq.h>
-
-#define ram_init(s,p) hwsq_init(&(s)->base, (p))
-#define ram_exec(s,e) hwsq_exec(&(s)->base, (e))
-#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
-#define ram_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r)
-#define ram_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
-#define ram_nuke(s,r) hwsq_nuke(&(s)->base, &(s)->r_##r)
-#define ram_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
-#define ram_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d))
-#define ram_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d))
-#define ram_nsec(s,n) hwsq_nsec(&(s)->base, (n))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
deleted file mode 100644
index 252575f3aa29..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr2.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2014 Roy Spliet
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Roy Spliet <rspliet@eclipso.eu>
- * Ben Skeggs
- */
-
-#include "priv.h"
-
-struct ramxlat {
- int id;
- u8 enc;
-};
-
-static inline int
-ramxlat(const struct ramxlat *xlat, int id)
-{
- while (xlat->id >= 0) {
- if (xlat->id == id)
- return xlat->enc;
- xlat++;
- }
- return -EINVAL;
-}
-
-static const struct ramxlat
-ramddr2_cl[] = {
- { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
- /* The following are available in some, but not all DDR2 docs */
- { 7, 7 },
- { -1 }
-};
-
-static const struct ramxlat
-ramddr2_wr[] = {
- { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
- /* The following are available in some, but not all DDR2 docs */
- { 7, 6 },
- { -1 }
-};
-
-int
-nouveau_sddr2_calc(struct nouveau_ram *ram)
-{
- int CL, WR, DLL = 0, ODT = 0;
-
- switch (ram->next->bios.timing_ver) {
- case 0x10:
- CL = ram->next->bios.timing_10_CL;
- WR = ram->next->bios.timing_10_WR;
- DLL = !ram->next->bios.ramcfg_10_DLLoff;
- ODT = ram->next->bios.timing_10_ODT & 3;
- break;
- case 0x20:
- CL = (ram->next->bios.timing[1] & 0x0000001f);
- WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
- break;
- default:
- return -ENOSYS;
- }
-
- CL = ramxlat(ramddr2_cl, CL);
- WR = ramxlat(ramddr2_wr, WR);
- if (CL < 0 || WR < 0)
- return -EINVAL;
-
- ram->mr[0] &= ~0xf70;
- ram->mr[0] |= (WR & 0x07) << 9;
- ram->mr[0] |= (CL & 0x07) << 4;
-
- ram->mr[1] &= ~0x045;
- ram->mr[1] |= (ODT & 0x1) << 2;
- ram->mr[1] |= (ODT & 0x2) << 5;
- ram->mr[1] |= !DLL;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
deleted file mode 100644
index a2dca4869e52..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fb/sddr3.c
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- * Roy Spliet <rspliet@eclipso.eu>
- */
-
-#include "priv.h"
-
-struct ramxlat {
- int id;
- u8 enc;
-};
-
-static inline int
-ramxlat(const struct ramxlat *xlat, int id)
-{
- while (xlat->id >= 0) {
- if (xlat->id == id)
- return xlat->enc;
- xlat++;
- }
- return -EINVAL;
-}
-
-static const struct ramxlat
-ramddr3_cl[] = {
- { 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
- { 11, 14 },
- /* the below are mentioned in some, but not all, ddr3 docs */
- { 12, 1 }, { 13, 3 }, { 14, 5 },
- { -1 }
-};
-
-static const struct ramxlat
-ramddr3_wr[] = {
- { 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
- /* the below are mentioned in some, but not all, ddr3 docs */
- { 14, 7 }, { 16, 0 },
- { -1 }
-};
-
-static const struct ramxlat
-ramddr3_cwl[] = {
- { 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
- /* the below are mentioned in some, but not all, ddr3 docs */
- { 9, 4 },
- { -1 }
-};
-
-int
-nouveau_sddr3_calc(struct nouveau_ram *ram)
-{
- int CWL, CL, WR, DLL = 0, ODT = 0;
-
- switch (ram->next->bios.timing_ver) {
- case 0x10:
- if (ram->next->bios.timing_hdr < 0x17) {
- /* XXX: NV50: Get CWL from the timing register */
- return -ENOSYS;
- }
- CWL = ram->next->bios.timing_10_CWL;
- CL = ram->next->bios.timing_10_CL;
- WR = ram->next->bios.timing_10_WR;
- DLL = !ram->next->bios.ramcfg_10_DLLoff;
- ODT = ram->next->bios.timing_10_ODT;
- break;
- case 0x20:
- CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
- CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
- WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
- /* XXX: Get these values from the VBIOS instead */
- DLL = !(ram->mr[1] & 0x1);
- ODT = (ram->mr[1] & 0x004) >> 2 |
- (ram->mr[1] & 0x040) >> 5 |
- (ram->mr[1] & 0x200) >> 7;
- break;
- default:
- return -ENOSYS;
- }
-
- CWL = ramxlat(ramddr3_cwl, CWL);
- CL = ramxlat(ramddr3_cl, CL);
- WR = ramxlat(ramddr3_wr, WR);
- if (CL < 0 || CWL < 0 || WR < 0)
- return -EINVAL;
-
- ram->mr[0] &= ~0xf74;
- ram->mr[0] |= (WR & 0x07) << 9;
- ram->mr[0] |= (CL & 0x0e) << 3;
- ram->mr[0] |= (CL & 0x01) << 2;
-
- ram->mr[1] &= ~0x245;
- ram->mr[1] |= (ODT & 0x1) << 2;
- ram->mr[1] |= (ODT & 0x2) << 5;
- ram->mr[1] |= (ODT & 0x4) << 7;
- ram->mr[1] |= !DLL;
-
- ram->mr[2] &= ~0x038;
- ram->mr[2] |= (CWL & 0x07) << 3;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
deleted file mode 100644
index 9e8e92127715..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/base.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/fuse.h>
-
-int
-_nouveau_fuse_init(struct nouveau_object *object)
-{
- struct nouveau_fuse *fuse = (void *)object;
- return nouveau_subdev_init(&fuse->base);
-}
-
-void
-_nouveau_fuse_dtor(struct nouveau_object *object)
-{
- struct nouveau_fuse *fuse = (void *)object;
- nouveau_subdev_destroy(&fuse->base);
-}
-
-int
-nouveau_fuse_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- struct nouveau_fuse *fuse;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "FUSE",
- "fuse", length, pobject);
- fuse = *pobject;
-
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
deleted file mode 100644
index a374ade485be..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/g80.c
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct g80_fuse_priv {
- struct nouveau_fuse base;
-
- spinlock_t fuse_enable_lock;
-};
-
-static u32
-g80_fuse_rd32(struct nouveau_object *object, u64 addr)
-{
- struct g80_fuse_priv *priv = (void *)object;
- unsigned long flags;
- u32 fuse_enable, val;
-
- spin_lock_irqsave(&priv->fuse_enable_lock, flags);
-
- /* racy if another part of nouveau start writing to this reg */
- fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800);
- val = nv_rd32(priv, 0x21000 + addr);
- nv_wr32(priv, 0x1084, fuse_enable);
-
- spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
-
- return val;
-}
-
-
-static int
-g80_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct g80_fuse_priv *priv;
- int ret;
-
- ret = nouveau_fuse_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- spin_lock_init(&priv->fuse_enable_lock);
-
- return 0;
-}
-
-struct nouveau_oclass
-g80_fuse_oclass = {
- .handle = NV_SUBDEV(FUSE, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = g80_fuse_ctor,
- .dtor = _nouveau_fuse_dtor,
- .init = _nouveau_fuse_init,
- .fini = _nouveau_fuse_fini,
- .rd32 = g80_fuse_rd32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
deleted file mode 100644
index 5ed03f54b3d4..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/gf100.c
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct gf100_fuse_priv {
- struct nouveau_fuse base;
-
- spinlock_t fuse_enable_lock;
-};
-
-static u32
-gf100_fuse_rd32(struct nouveau_object *object, u64 addr)
-{
- struct gf100_fuse_priv *priv = (void *)object;
- unsigned long flags;
- u32 fuse_enable, unk, val;
-
- spin_lock_irqsave(&priv->fuse_enable_lock, flags);
-
- /* racy if another part of nouveau start writing to these regs */
- fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800);
- unk = nv_mask(priv, 0x21000, 0x1, 0x1);
- val = nv_rd32(priv, 0x21100 + addr);
- nv_wr32(priv, 0x21000, unk);
- nv_wr32(priv, 0x22400, fuse_enable);
-
- spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
-
- return val;
-}
-
-
-static int
-gf100_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gf100_fuse_priv *priv;
- int ret;
-
- ret = nouveau_fuse_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- spin_lock_init(&priv->fuse_enable_lock);
-
- return 0;
-}
-
-struct nouveau_oclass
-gf100_fuse_oclass = {
- .handle = NV_SUBDEV(FUSE, 0xC0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gf100_fuse_ctor,
- .dtor = _nouveau_fuse_dtor,
- .init = _nouveau_fuse_init,
- .fini = _nouveau_fuse_fini,
- .rd32 = gf100_fuse_rd32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
deleted file mode 100644
index 4f1a636c6538..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/gm107.c
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct gm107_fuse_priv {
- struct nouveau_fuse base;
-};
-
-static u32
-gm107_fuse_rd32(struct nouveau_object *object, u64 addr)
-{
- struct gf100_fuse_priv *priv = (void *)object;
-
- return nv_rd32(priv, 0x21100 + addr);
-}
-
-
-static int
-gm107_fuse_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gm107_fuse_priv *priv;
- int ret;
-
- ret = nouveau_fuse_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass
-gm107_fuse_oclass = {
- .handle = NV_SUBDEV(FUSE, 0x117),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm107_fuse_ctor,
- .dtor = _nouveau_fuse_dtor,
- .init = _nouveau_fuse_init,
- .fini = _nouveau_fuse_fini,
- .rd32 = gm107_fuse_rd32,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
deleted file mode 100644
index d2085411a5cb..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/fuse/priv.h
+++ /dev/null
@@ -1,9 +0,0 @@
-#ifndef __NVKM_FUSE_PRIV_H__
-#define __NVKM_FUSE_PRIV_H__
-
-#include <subdev/fuse.h>
-
-int _nouveau_fuse_init(struct nouveau_object *object);
-void _nouveau_fuse_dtor(struct nouveau_object *object);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
deleted file mode 100644
index 7ad99b763f4c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/base.c
+++ /dev/null
@@ -1,255 +0,0 @@
-/*
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/bios.h>
-#include <subdev/bios/gpio.h>
-
-#include "priv.h"
-
-static int
-nouveau_gpio_drive(struct nouveau_gpio *gpio,
- int idx, int line, int dir, int out)
-{
- const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
- return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
-}
-
-static int
-nouveau_gpio_sense(struct nouveau_gpio *gpio, int idx, int line)
-{
- const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
- return impl->sense ? impl->sense(gpio, line) : -ENODEV;
-}
-
-static int
-nouveau_gpio_find(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line,
- struct dcb_gpio_func *func)
-{
- struct nouveau_bios *bios = nouveau_bios(gpio);
- u8 ver, len;
- u16 data;
-
- if (line == 0xff && tag == 0xff)
- return -EINVAL;
-
- data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
- if (data)
- return 0;
-
- /* Apple iMac G4 NV18 */
- if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) {
- if (tag == DCB_GPIO_TVDAC0) {
- *func = (struct dcb_gpio_func) {
- .func = DCB_GPIO_TVDAC0,
- .line = 4,
- .log[0] = 0,
- .log[1] = 1,
- };
- return 0;
- }
- }
-
- return -ENOENT;
-}
-
-static int
-nouveau_gpio_set(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line, int state)
-{
- struct dcb_gpio_func func;
- int ret;
-
- ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
- if (ret == 0) {
- int dir = !!(func.log[state] & 0x02);
- int out = !!(func.log[state] & 0x01);
- ret = nouveau_gpio_drive(gpio, idx, func.line, dir, out);
- }
-
- return ret;
-}
-
-static int
-nouveau_gpio_get(struct nouveau_gpio *gpio, int idx, u8 tag, u8 line)
-{
- struct dcb_gpio_func func;
- int ret;
-
- ret = nouveau_gpio_find(gpio, idx, tag, line, &func);
- if (ret == 0) {
- ret = nouveau_gpio_sense(gpio, idx, func.line);
- if (ret >= 0)
- ret = (ret == (func.log[1] & 1));
- }
-
- return ret;
-}
-
-static void
-nouveau_gpio_intr_fini(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
- const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
- impl->intr_mask(gpio, type, 1 << index, 0);
-}
-
-static void
-nouveau_gpio_intr_init(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_gpio *gpio = container_of(event, typeof(*gpio), event);
- const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
- impl->intr_mask(gpio, type, 1 << index, 1 << index);
-}
-
-static int
-nouveau_gpio_intr_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_gpio_ntfy_req *req = data;
- if (!WARN_ON(size != sizeof(*req))) {
- notify->size = sizeof(struct nvkm_gpio_ntfy_rep);
- notify->types = req->mask;
- notify->index = req->line;
- return 0;
- }
- return -EINVAL;
-}
-
-static void
-nouveau_gpio_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(subdev);
- const struct nouveau_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
- u32 hi, lo, i;
-
- impl->intr_stat(gpio, &hi, &lo);
-
- for (i = 0; (hi | lo) && i < impl->lines; i++) {
- struct nvkm_gpio_ntfy_rep rep = {
- .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
- (NVKM_GPIO_LO * !!(lo & (1 << i))),
- };
- nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
- }
-}
-
-static const struct nvkm_event_func
-nouveau_gpio_intr_func = {
- .ctor = nouveau_gpio_intr_ctor,
- .init = nouveau_gpio_intr_init,
- .fini = nouveau_gpio_intr_fini,
-};
-
-int
-_nouveau_gpio_fini(struct nouveau_object *object, bool suspend)
-{
- const struct nouveau_gpio_impl *impl = (void *)object->oclass;
- struct nouveau_gpio *gpio = nouveau_gpio(object);
- u32 mask = (1 << impl->lines) - 1;
-
- impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
- impl->intr_stat(gpio, &mask, &mask);
-
- return nouveau_subdev_fini(&gpio->base, suspend);
-}
-
-static struct dmi_system_id gpio_reset_ids[] = {
- {
- .ident = "Apple Macbook 10,1",
- .matches = {
- DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
- DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
- }
- },
- { }
-};
-
-int
-_nouveau_gpio_init(struct nouveau_object *object)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(object);
- int ret;
-
- ret = nouveau_subdev_init(&gpio->base);
- if (ret)
- return ret;
-
- if (gpio->reset && dmi_check_system(gpio_reset_ids))
- gpio->reset(gpio, DCB_GPIO_UNUSED);
-
- return ret;
-}
-
-void
-_nouveau_gpio_dtor(struct nouveau_object *object)
-{
- struct nouveau_gpio *gpio = (void *)object;
- nvkm_event_fini(&gpio->event);
- nouveau_subdev_destroy(&gpio->base);
-}
-
-int
-nouveau_gpio_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int length, void **pobject)
-{
- const struct nouveau_gpio_impl *impl = (void *)oclass;
- struct nouveau_gpio *gpio;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "GPIO", "gpio",
- length, pobject);
- gpio = *pobject;
- if (ret)
- return ret;
-
- gpio->find = nouveau_gpio_find;
- gpio->set = nouveau_gpio_set;
- gpio->get = nouveau_gpio_get;
- gpio->reset = impl->reset;
-
- ret = nvkm_event_init(&nouveau_gpio_intr_func, 2, impl->lines,
- &gpio->event);
- if (ret)
- return ret;
-
- nv_subdev(gpio)->intr = nouveau_gpio_intr;
- return 0;
-}
-
-int
-_nouveau_gpio_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_gpio *gpio;
- int ret;
-
- ret = nouveau_gpio_create(parent, engine, oclass, &gpio);
- *pobject = nv_object(gpio);
- if (ret)
- return ret;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
deleted file mode 100644
index 27ad23eaf185..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv10.c
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2009 Francisco Jerez.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-#include "priv.h"
-
-static int
-nv10_gpio_sense(struct nouveau_gpio *gpio, int line)
-{
- if (line < 2) {
- line = line * 16;
- line = nv_rd32(gpio, 0x600818) >> line;
- return !!(line & 0x0100);
- } else
- if (line < 10) {
- line = (line - 2) * 4;
- line = nv_rd32(gpio, 0x60081c) >> line;
- return !!(line & 0x04);
- } else
- if (line < 14) {
- line = (line - 10) * 4;
- line = nv_rd32(gpio, 0x600850) >> line;
- return !!(line & 0x04);
- }
-
- return -EINVAL;
-}
-
-static int
-nv10_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
-{
- u32 reg, mask, data;
-
- if (line < 2) {
- line = line * 16;
- reg = 0x600818;
- mask = 0x00000011;
- data = (dir << 4) | out;
- } else
- if (line < 10) {
- line = (line - 2) * 4;
- reg = 0x60081c;
- mask = 0x00000003;
- data = (dir << 1) | out;
- } else
- if (line < 14) {
- line = (line - 10) * 4;
- reg = 0x600850;
- mask = 0x00000003;
- data = (dir << 1) | out;
- } else {
- return -EINVAL;
- }
-
- nv_mask(gpio, reg, mask << line, data << line);
- return 0;
-}
-
-static void
-nv10_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
- u32 intr = nv_rd32(gpio, 0x001104);
- u32 stat = nv_rd32(gpio, 0x001144) & intr;
- *lo = (stat & 0xffff0000) >> 16;
- *hi = (stat & 0x0000ffff);
- nv_wr32(gpio, 0x001104, intr);
-}
-
-static void
-nv10_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
- u32 inte = nv_rd32(gpio, 0x001144);
- if (type & NVKM_GPIO_LO)
- inte = (inte & ~(mask << 16)) | (data << 16);
- if (type & NVKM_GPIO_HI)
- inte = (inte & ~mask) | data;
- nv_wr32(gpio, 0x001144, inte);
-}
-
-struct nouveau_oclass *
-nv10_gpio_oclass = &(struct nouveau_gpio_impl) {
- .base.handle = NV_SUBDEV(GPIO, 0x10),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_gpio_ctor,
- .dtor = _nouveau_gpio_dtor,
- .init = _nouveau_gpio_init,
- .fini = _nouveau_gpio_fini,
- },
- .lines = 16,
- .intr_stat = nv10_gpio_intr_stat,
- .intr_mask = nv10_gpio_intr_mask,
- .drive = nv10_gpio_drive,
- .sense = nv10_gpio_sense,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
deleted file mode 100644
index 2e30d5a62d6e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv50.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nv50_gpio_reset(struct nouveau_gpio *gpio, u8 match)
-{
- struct nouveau_bios *bios = nouveau_bios(gpio);
- u8 ver, len;
- u16 entry;
- int ent = -1;
-
- while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
- static const u32 regs[] = { 0xe100, 0xe28c };
- u32 data = nv_ro32(bios, entry);
- u8 line = (data & 0x0000001f);
- u8 func = (data & 0x0000ff00) >> 8;
- u8 defs = !!(data & 0x01000000);
- u8 unk0 = !!(data & 0x02000000);
- u8 unk1 = !!(data & 0x04000000);
- u32 val = (unk1 << 16) | unk0;
- u32 reg = regs[line >> 4];
- u32 lsh = line & 0x0f;
-
- if ( func == DCB_GPIO_UNUSED ||
- (match != DCB_GPIO_UNUSED && match != func))
- continue;
-
- gpio->set(gpio, 0, func, line, defs);
-
- nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh);
- }
-}
-
-int
-nv50_gpio_location(int line, u32 *reg, u32 *shift)
-{
- const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
-
- if (line >= 32)
- return -EINVAL;
-
- *reg = nv50_gpio_reg[line >> 3];
- *shift = (line & 7) << 2;
- return 0;
-}
-
-int
-nv50_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
-{
- u32 reg, shift;
-
- if (nv50_gpio_location(line, &reg, &shift))
- return -EINVAL;
-
- nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift);
- return 0;
-}
-
-int
-nv50_gpio_sense(struct nouveau_gpio *gpio, int line)
-{
- u32 reg, shift;
-
- if (nv50_gpio_location(line, &reg, &shift))
- return -EINVAL;
-
- return !!(nv_rd32(gpio, reg) & (4 << shift));
-}
-
-static void
-nv50_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
- u32 intr = nv_rd32(gpio, 0x00e054);
- u32 stat = nv_rd32(gpio, 0x00e050) & intr;
- *lo = (stat & 0xffff0000) >> 16;
- *hi = (stat & 0x0000ffff);
- nv_wr32(gpio, 0x00e054, intr);
-}
-
-static void
-nv50_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
- u32 inte = nv_rd32(gpio, 0x00e050);
- if (type & NVKM_GPIO_LO)
- inte = (inte & ~(mask << 16)) | (data << 16);
- if (type & NVKM_GPIO_HI)
- inte = (inte & ~mask) | data;
- nv_wr32(gpio, 0x00e050, inte);
-}
-
-struct nouveau_oclass *
-nv50_gpio_oclass = &(struct nouveau_gpio_impl) {
- .base.handle = NV_SUBDEV(GPIO, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_gpio_ctor,
- .dtor = _nouveau_gpio_dtor,
- .init = _nouveau_gpio_init,
- .fini = _nouveau_gpio_fini,
- },
- .lines = 16,
- .intr_stat = nv50_gpio_intr_stat,
- .intr_mask = nv50_gpio_intr_mask,
- .drive = nv50_gpio_drive,
- .sense = nv50_gpio_sense,
- .reset = nv50_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c
deleted file mode 100644
index cae404ccadac..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nv94.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nv94_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
- u32 intr0 = nv_rd32(gpio, 0x00e054);
- u32 intr1 = nv_rd32(gpio, 0x00e074);
- u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
- u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
- *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
- *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
- nv_wr32(gpio, 0x00e054, intr0);
- nv_wr32(gpio, 0x00e074, intr1);
-}
-
-void
-nv94_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
- u32 inte0 = nv_rd32(gpio, 0x00e050);
- u32 inte1 = nv_rd32(gpio, 0x00e070);
- if (type & NVKM_GPIO_LO)
- inte0 = (inte0 & ~(mask << 16)) | (data << 16);
- if (type & NVKM_GPIO_HI)
- inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
- mask >>= 16;
- data >>= 16;
- if (type & NVKM_GPIO_LO)
- inte1 = (inte1 & ~(mask << 16)) | (data << 16);
- if (type & NVKM_GPIO_HI)
- inte1 = (inte1 & ~mask) | data;
- nv_wr32(gpio, 0x00e050, inte0);
- nv_wr32(gpio, 0x00e070, inte1);
-}
-
-struct nouveau_oclass *
-nv94_gpio_oclass = &(struct nouveau_gpio_impl) {
- .base.handle = NV_SUBDEV(GPIO, 0x94),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_gpio_ctor,
- .dtor = _nouveau_gpio_dtor,
- .init = _nouveau_gpio_init,
- .fini = _nouveau_gpio_fini,
- },
- .lines = 32,
- .intr_stat = nv94_gpio_intr_stat,
- .intr_mask = nv94_gpio_intr_mask,
- .drive = nv50_gpio_drive,
- .sense = nv50_gpio_sense,
- .reset = nv50_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
deleted file mode 100644
index 480d6d2af770..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nvd0.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-void
-nvd0_gpio_reset(struct nouveau_gpio *gpio, u8 match)
-{
- struct nouveau_bios *bios = nouveau_bios(gpio);
- u8 ver, len;
- u16 entry;
- int ent = -1;
-
- while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
- u32 data = nv_ro32(bios, entry);
- u8 line = (data & 0x0000003f);
- u8 defs = !!(data & 0x00000080);
- u8 func = (data & 0x0000ff00) >> 8;
- u8 unk0 = (data & 0x00ff0000) >> 16;
- u8 unk1 = (data & 0x1f000000) >> 24;
-
- if ( func == DCB_GPIO_UNUSED ||
- (match != DCB_GPIO_UNUSED && match != func))
- continue;
-
- gpio->set(gpio, 0, func, line, defs);
-
- nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0);
- if (unk1--)
- nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line);
- }
-}
-
-int
-nvd0_gpio_drive(struct nouveau_gpio *gpio, int line, int dir, int out)
-{
- u32 data = ((dir ^ 1) << 13) | (out << 12);
- nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data);
- nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */
- return 0;
-}
-
-int
-nvd0_gpio_sense(struct nouveau_gpio *gpio, int line)
-{
- return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
-}
-
-struct nouveau_oclass *
-nvd0_gpio_oclass = &(struct nouveau_gpio_impl) {
- .base.handle = NV_SUBDEV(GPIO, 0xd0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_gpio_ctor,
- .dtor = _nouveau_gpio_dtor,
- .init = _nouveau_gpio_init,
- .fini = _nouveau_gpio_fini,
- },
- .lines = 32,
- .intr_stat = nv94_gpio_intr_stat,
- .intr_mask = nv94_gpio_intr_mask,
- .drive = nvd0_gpio_drive,
- .sense = nvd0_gpio_sense,
- .reset = nvd0_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
deleted file mode 100644
index e1145b48c76c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/nve0.c
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static void
-nve0_gpio_intr_stat(struct nouveau_gpio *gpio, u32 *hi, u32 *lo)
-{
- u32 intr0 = nv_rd32(gpio, 0x00dc00);
- u32 intr1 = nv_rd32(gpio, 0x00dc80);
- u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0;
- u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1;
- *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
- *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
- nv_wr32(gpio, 0x00dc00, intr0);
- nv_wr32(gpio, 0x00dc80, intr1);
-}
-
-void
-nve0_gpio_intr_mask(struct nouveau_gpio *gpio, u32 type, u32 mask, u32 data)
-{
- u32 inte0 = nv_rd32(gpio, 0x00dc08);
- u32 inte1 = nv_rd32(gpio, 0x00dc88);
- if (type & NVKM_GPIO_LO)
- inte0 = (inte0 & ~(mask << 16)) | (data << 16);
- if (type & NVKM_GPIO_HI)
- inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
- mask >>= 16;
- data >>= 16;
- if (type & NVKM_GPIO_LO)
- inte1 = (inte1 & ~(mask << 16)) | (data << 16);
- if (type & NVKM_GPIO_HI)
- inte1 = (inte1 & ~mask) | data;
- nv_wr32(gpio, 0x00dc08, inte0);
- nv_wr32(gpio, 0x00dc88, inte1);
-}
-
-struct nouveau_oclass *
-nve0_gpio_oclass = &(struct nouveau_gpio_impl) {
- .base.handle = NV_SUBDEV(GPIO, 0xe0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_gpio_ctor,
- .dtor = _nouveau_gpio_dtor,
- .init = _nouveau_gpio_init,
- .fini = _nouveau_gpio_fini,
- },
- .lines = 32,
- .intr_stat = nve0_gpio_intr_stat,
- .intr_mask = nve0_gpio_intr_mask,
- .drive = nvd0_gpio_drive,
- .sense = nvd0_gpio_sense,
- .reset = nvd0_gpio_reset,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
deleted file mode 100644
index bff98b86e2b5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/gpio/priv.h
+++ /dev/null
@@ -1,67 +0,0 @@
-#ifndef __NVKM_GPIO_H__
-#define __NVKM_GPIO_H__
-
-#include <subdev/gpio.h>
-
-#define nouveau_gpio_create(p,e,o,d) \
- nouveau_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_gpio_destroy(p) ({ \
- struct nouveau_gpio *gpio = (p); \
- _nouveau_gpio_dtor(nv_object(gpio)); \
-})
-#define nouveau_gpio_init(p) ({ \
- struct nouveau_gpio *gpio = (p); \
- _nouveau_gpio_init(nv_object(gpio)); \
-})
-#define nouveau_gpio_fini(p,s) ({ \
- struct nouveau_gpio *gpio = (p); \
- _nouveau_gpio_fini(nv_object(gpio), (s)); \
-})
-
-int nouveau_gpio_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-int _nouveau_gpio_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void _nouveau_gpio_dtor(struct nouveau_object *);
-int _nouveau_gpio_init(struct nouveau_object *);
-int _nouveau_gpio_fini(struct nouveau_object *, bool);
-
-struct nouveau_gpio_impl {
- struct nouveau_oclass base;
- int lines;
-
- /* read and ack pending interrupts, returning only data
- * for lines that have not been masked off, while still
- * performing the ack for anything that was pending.
- */
- void (*intr_stat)(struct nouveau_gpio *, u32 *, u32 *);
-
- /* mask on/off interrupts for hi/lo transitions on a
- * given set of gpio lines
- */
- void (*intr_mask)(struct nouveau_gpio *, u32, u32, u32);
-
- /* configure gpio direction and output value */
- int (*drive)(struct nouveau_gpio *, int line, int dir, int out);
-
- /* sense current state of given gpio line */
- int (*sense)(struct nouveau_gpio *, int line);
-
- /*XXX*/
- void (*reset)(struct nouveau_gpio *, u8);
-};
-
-void nv50_gpio_reset(struct nouveau_gpio *, u8);
-int nv50_gpio_drive(struct nouveau_gpio *, int, int, int);
-int nv50_gpio_sense(struct nouveau_gpio *, int);
-
-void nv94_gpio_intr_stat(struct nouveau_gpio *, u32 *, u32 *);
-void nv94_gpio_intr_mask(struct nouveau_gpio *, u32, u32, u32);
-
-void nvd0_gpio_reset(struct nouveau_gpio *, u8);
-int nvd0_gpio_drive(struct nouveau_gpio *, int, int, int);
-int nvd0_gpio_sense(struct nouveau_gpio *, int);
-
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
deleted file mode 100644
index 2c2731a6cf91..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/anx9805.c
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "port.h"
-
-struct anx9805_i2c_port {
- struct nouveau_i2c_port base;
- u32 addr;
- u32 ctrl;
-};
-
-static int
-anx9805_train(struct nouveau_i2c_port *port, int link_nr, int link_bw, bool enh)
-{
- struct anx9805_i2c_port *chan = (void *)port;
- struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
- u8 tmp, i;
-
- DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh);
-
- nv_wri2cr(mast, chan->addr, 0xa0, link_bw);
- nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
- nv_wri2cr(mast, chan->addr, 0xa2, 0x01);
- nv_wri2cr(mast, chan->addr, 0xa8, 0x01);
-
- i = 0;
- while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) {
- mdelay(5);
- if (i++ == 100) {
- nv_error(port, "link training timed out\n");
- return -ETIMEDOUT;
- }
- }
-
- if (tmp & 0x70) {
- nv_error(port, "link training failed: 0x%02x\n", tmp);
- return -EIO;
- }
-
- return 1;
-}
-
-static int
-anx9805_aux(struct nouveau_i2c_port *port, bool retry,
- u8 type, u32 addr, u8 *data, u8 size)
-{
- struct anx9805_i2c_port *chan = (void *)port;
- struct nouveau_i2c_port *mast = (void *)nv_object(chan)->parent;
- int i, ret = -ETIMEDOUT;
- u8 buf[16] = {};
- u8 tmp;
-
- DBG("%02x %05x %d\n", type, addr, size);
-
- tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04;
- nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04);
- nv_wri2cr(mast, chan->ctrl, 0x07, tmp);
- nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
-
- nv_wri2cr(mast, chan->addr, 0xe4, 0x80);
- if (!(type & 1)) {
- memcpy(buf, data, size);
- DBG("%16ph", buf);
- for (i = 0; i < size; i++)
- nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]);
- }
- nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type);
- nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0);
- nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8);
- nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16);
- nv_wri2cr(mast, chan->addr, 0xe9, 0x01);
-
- i = 0;
- while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) {
- mdelay(5);
- if (i++ == 32)
- goto done;
- }
-
- if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) {
- ret = -EIO;
- goto done;
- }
-
- if (type & 1) {
- for (i = 0; i < size; i++)
- buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i);
- DBG("%16ph", buf);
- memcpy(data, buf, size);
- }
-
- ret = 0;
-done:
- nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
- return ret;
-}
-
-static const struct nouveau_i2c_func
-anx9805_aux_func = {
- .aux = anx9805_aux,
- .lnk_ctl = anx9805_train,
-};
-
-static int
-anx9805_aux_chan_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct nouveau_i2c_port *mast = (void *)parent;
- struct anx9805_i2c_port *chan;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_aux_algo, &anx9805_aux_func,
- &chan);
- *pobject = nv_object(chan);
- if (ret)
- return ret;
-
- switch ((oclass->handle & 0xff00) >> 8) {
- case 0x0d:
- chan->addr = 0x38;
- chan->ctrl = 0x39;
- break;
- case 0x0e:
- chan->addr = 0x3c;
- chan->ctrl = 0x3b;
- break;
- default:
- BUG_ON(1);
- }
-
- if (mast->adapter.algo == &i2c_bit_algo) {
- struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
- algo->udelay = max(algo->udelay, 40);
- }
- return 0;
-}
-
-static struct nouveau_ofuncs
-anx9805_aux_ofuncs = {
- .ctor = anx9805_aux_chan_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
-};
-
-static int
-anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
- struct anx9805_i2c_port *port = adap->algo_data;
- struct nouveau_i2c_port *mast = (void *)nv_object(port)->parent;
- struct i2c_msg *msg = msgs;
- int ret = -ETIMEDOUT;
- int i, j, cnt = num;
- u8 seg = 0x00, off = 0x00, tmp;
-
- tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10;
- nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10);
- nv_wri2cr(mast, port->ctrl, 0x07, tmp);
- nv_wri2cr(mast, port->addr, 0x43, 0x05);
- mdelay(5);
-
- while (cnt--) {
- if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
- nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1);
- nv_wri2cr(mast, port->addr, 0x41, seg);
- nv_wri2cr(mast, port->addr, 0x42, off);
- nv_wri2cr(mast, port->addr, 0x44, msg->len);
- nv_wri2cr(mast, port->addr, 0x45, 0x00);
- nv_wri2cr(mast, port->addr, 0x43, 0x01);
- for (i = 0; i < msg->len; i++) {
- j = 0;
- while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) {
- mdelay(5);
- if (j++ == 32)
- goto done;
- }
- msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47);
- }
- } else
- if (!(msg->flags & I2C_M_RD)) {
- if (msg->addr == 0x50 && msg->len == 0x01) {
- off = msg->buf[0];
- } else
- if (msg->addr == 0x30 && msg->len == 0x01) {
- seg = msg->buf[0];
- } else
- goto done;
- } else {
- goto done;
- }
- msg++;
- }
-
- ret = num;
-done:
- nv_wri2cr(mast, port->addr, 0x43, 0x00);
- return ret;
-}
-
-static u32
-anx9805_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-static const struct i2c_algorithm
-anx9805_i2c_algo = {
- .master_xfer = anx9805_xfer,
- .functionality = anx9805_func
-};
-
-static const struct nouveau_i2c_func
-anx9805_i2c_func = {
-};
-
-static int
-anx9805_ddc_port_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct nouveau_i2c_port *mast = (void *)parent;
- struct anx9805_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &anx9805_i2c_algo, &anx9805_i2c_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- switch ((oclass->handle & 0xff00) >> 8) {
- case 0x0d:
- port->addr = 0x3d;
- port->ctrl = 0x39;
- break;
- case 0x0e:
- port->addr = 0x3f;
- port->ctrl = 0x3b;
- break;
- default:
- BUG_ON(1);
- }
-
- if (mast->adapter.algo == &i2c_bit_algo) {
- struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
- algo->udelay = max(algo->udelay, 40);
- }
- return 0;
-}
-
-static struct nouveau_ofuncs
-anx9805_ddc_ofuncs = {
- .ctor = anx9805_ddc_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
-};
-
-struct nouveau_oclass
-nouveau_anx9805_sclass[] = {
- { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs },
- { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs },
- { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs },
- { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs },
- {}
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
deleted file mode 100644
index 02eb42be2e9e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/aux.c
+++ /dev/null
@@ -1,114 +0,0 @@
-/*
- * Copyright 2009 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-int
-nv_rdaux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(port);
- if (port->func->aux) {
- int ret = i2c->acquire(port, 0);
- if (ret == 0) {
- ret = port->func->aux(port, true, 9, addr, data, size);
- i2c->release(port);
- }
- return ret;
- }
- return -ENODEV;
-}
-
-int
-nv_wraux(struct nouveau_i2c_port *port, u32 addr, u8 *data, u8 size)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(port);
- if (port->func->aux) {
- int ret = i2c->acquire(port, 0);
- if (ret == 0) {
- ret = port->func->aux(port, true, 8, addr, data, size);
- i2c->release(port);
- }
- return ret;
- }
- return -ENODEV;
-}
-
-static int
-aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
- struct nouveau_i2c_port *port = adap->algo_data;
- struct nouveau_i2c *i2c = nouveau_i2c(port);
- struct i2c_msg *msg = msgs;
- int ret, mcnt = num;
-
- if (!port->func->aux)
- return -ENODEV;
-
- ret = i2c->acquire(port, 0);
- if (ret)
- return ret;
-
- while (mcnt--) {
- u8 remaining = msg->len;
- u8 *ptr = msg->buf;
-
- while (remaining) {
- u8 cnt = (remaining > 16) ? 16 : remaining;
- u8 cmd;
-
- if (msg->flags & I2C_M_RD)
- cmd = 1;
- else
- cmd = 0;
-
- if (mcnt || remaining > 16)
- cmd |= 4; /* MOT */
-
- ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
- if (ret < 0) {
- i2c->release(port);
- return ret;
- }
-
- ptr += cnt;
- remaining -= cnt;
- }
-
- msg++;
- }
-
- i2c->release(port);
- return num;
-}
-
-static u32
-aux_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-const struct i2c_algorithm nouveau_i2c_aux_algo = {
- .master_xfer = aux_xfer,
- .functionality = aux_func
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
deleted file mode 100644
index 0dc605db7ec8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/base.c
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-#include <core/object.h>
-#include <core/event.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/i2c.h>
-#include <subdev/vga.h>
-
-#include "priv.h"
-#include "pad.h"
-
-/******************************************************************************
- * interface to linux i2c bit-banging algorithm
- *****************************************************************************/
-
-#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
-#define CSTMSEL true
-#else
-#define CSTMSEL false
-#endif
-
-static int
-nouveau_i2c_pre_xfer(struct i2c_adapter *adap)
-{
- struct i2c_algo_bit_data *bit = adap->algo_data;
- struct nouveau_i2c_port *port = bit->data;
- return nouveau_i2c(port)->acquire(port, bit->timeout);
-}
-
-static void
-nouveau_i2c_post_xfer(struct i2c_adapter *adap)
-{
- struct i2c_algo_bit_data *bit = adap->algo_data;
- struct nouveau_i2c_port *port = bit->data;
- return nouveau_i2c(port)->release(port);
-}
-
-static void
-nouveau_i2c_setscl(void *data, int state)
-{
- struct nouveau_i2c_port *port = data;
- port->func->drive_scl(port, state);
-}
-
-static void
-nouveau_i2c_setsda(void *data, int state)
-{
- struct nouveau_i2c_port *port = data;
- port->func->drive_sda(port, state);
-}
-
-static int
-nouveau_i2c_getscl(void *data)
-{
- struct nouveau_i2c_port *port = data;
- return port->func->sense_scl(port);
-}
-
-static int
-nouveau_i2c_getsda(void *data)
-{
- struct nouveau_i2c_port *port = data;
- return port->func->sense_sda(port);
-}
-
-/******************************************************************************
- * base i2c "port" class implementation
- *****************************************************************************/
-
-int
-_nouveau_i2c_port_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_i2c_port *port = (void *)object;
- struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
- nv_ofuncs(pad)->fini(nv_object(pad), suspend);
- return nouveau_object_fini(&port->base, suspend);
-}
-
-void
-_nouveau_i2c_port_dtor(struct nouveau_object *object)
-{
- struct nouveau_i2c_port *port = (void *)object;
- i2c_del_adapter(&port->adapter);
- nouveau_object_destroy(&port->base);
-}
-
-int
-nouveau_i2c_port_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, u8 index,
- const struct i2c_algorithm *algo,
- const struct nouveau_i2c_func *func,
- int size, void **pobject)
-{
- struct nouveau_device *device = nv_device(engine);
- struct nouveau_i2c *i2c = (void *)engine;
- struct nouveau_i2c_port *port;
- int ret;
-
- ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
- port = *pobject;
- if (ret)
- return ret;
-
- snprintf(port->adapter.name, sizeof(port->adapter.name),
- "nouveau-%s-%d", device->name, index);
- port->adapter.owner = THIS_MODULE;
- port->adapter.dev.parent = nv_device_base(device);
- port->index = index;
- port->aux = -1;
- port->func = func;
- mutex_init(&port->mutex);
-
- if ( algo == &nouveau_i2c_bit_algo &&
- !nouveau_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
- struct i2c_algo_bit_data *bit;
-
- bit = kzalloc(sizeof(*bit), GFP_KERNEL);
- if (!bit)
- return -ENOMEM;
-
- bit->udelay = 10;
- bit->timeout = usecs_to_jiffies(2200);
- bit->data = port;
- bit->pre_xfer = nouveau_i2c_pre_xfer;
- bit->post_xfer = nouveau_i2c_post_xfer;
- bit->setsda = nouveau_i2c_setsda;
- bit->setscl = nouveau_i2c_setscl;
- bit->getsda = nouveau_i2c_getsda;
- bit->getscl = nouveau_i2c_getscl;
-
- port->adapter.algo_data = bit;
- ret = i2c_bit_add_bus(&port->adapter);
- } else {
- port->adapter.algo_data = port;
- port->adapter.algo = algo;
- ret = i2c_add_adapter(&port->adapter);
- }
-
- if (ret == 0)
- list_add_tail(&port->head, &i2c->ports);
- return ret;
-}
-
-/******************************************************************************
- * base i2c subdev class implementation
- *****************************************************************************/
-
-static struct nouveau_i2c_port *
-nouveau_i2c_find(struct nouveau_i2c *i2c, u8 index)
-{
- struct nouveau_bios *bios = nouveau_bios(i2c);
- struct nouveau_i2c_port *port;
-
- if (index == NV_I2C_DEFAULT(0) ||
- index == NV_I2C_DEFAULT(1)) {
- u8 ver, hdr, cnt, len;
- u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
- if (i2c && ver >= 0x30) {
- u8 auxidx = nv_ro08(bios, i2c + 4);
- if (index == NV_I2C_DEFAULT(0))
- index = (auxidx & 0x0f) >> 0;
- else
- index = (auxidx & 0xf0) >> 4;
- } else {
- index = 2;
- }
- }
-
- list_for_each_entry(port, &i2c->ports, head) {
- if (port->index == index)
- return port;
- }
-
- return NULL;
-}
-
-static struct nouveau_i2c_port *
-nouveau_i2c_find_type(struct nouveau_i2c *i2c, u16 type)
-{
- struct nouveau_i2c_port *port;
-
- list_for_each_entry(port, &i2c->ports, head) {
- if (nv_hclass(port) == type)
- return port;
- }
-
- return NULL;
-}
-
-static void
-nouveau_i2c_release_pad(struct nouveau_i2c_port *port)
-{
- struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
- struct nouveau_i2c *i2c = nouveau_i2c(port);
-
- if (atomic_dec_and_test(&nv_object(pad)->usecount)) {
- nv_ofuncs(pad)->fini(nv_object(pad), false);
- wake_up_all(&i2c->wait);
- }
-}
-
-static int
-nouveau_i2c_try_acquire_pad(struct nouveau_i2c_port *port)
-{
- struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
-
- if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) {
- struct nouveau_object *owner = (void *)pad->port;
- do {
- if (owner == (void *)port)
- return 0;
- owner = owner->parent;
- } while(owner);
- nouveau_i2c_release_pad(port);
- return -EBUSY;
- }
-
- pad->next = port;
- nv_ofuncs(pad)->init(nv_object(pad));
- return 0;
-}
-
-static int
-nouveau_i2c_acquire_pad(struct nouveau_i2c_port *port, unsigned long timeout)
-{
- struct nouveau_i2c *i2c = nouveau_i2c(port);
-
- if (timeout) {
- if (wait_event_timeout(i2c->wait,
- nouveau_i2c_try_acquire_pad(port) == 0,
- timeout) == 0)
- return -EBUSY;
- } else {
- wait_event(i2c->wait, nouveau_i2c_try_acquire_pad(port) == 0);
- }
-
- return 0;
-}
-
-static void
-nouveau_i2c_release(struct nouveau_i2c_port *port)
-__releases(pad->mutex)
-{
- nouveau_i2c(port)->release_pad(port);
- mutex_unlock(&port->mutex);
-}
-
-static int
-nouveau_i2c_acquire(struct nouveau_i2c_port *port, unsigned long timeout)
-__acquires(pad->mutex)
-{
- int ret;
- mutex_lock(&port->mutex);
- if ((ret = nouveau_i2c(port)->acquire_pad(port, timeout)))
- mutex_unlock(&port->mutex);
- return ret;
-}
-
-static int
-nouveau_i2c_identify(struct nouveau_i2c *i2c, int index, const char *what,
- struct nouveau_i2c_board_info *info,
- bool (*match)(struct nouveau_i2c_port *,
- struct i2c_board_info *, void *), void *data)
-{
- struct nouveau_i2c_port *port = nouveau_i2c_find(i2c, index);
- int i;
-
- if (!port) {
- nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
- return -ENODEV;
- }
-
- nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
- for (i = 0; info[i].dev.addr; i++) {
- u8 orig_udelay = 0;
-
- if ((port->adapter.algo == &i2c_bit_algo) &&
- (info[i].udelay != 0)) {
- struct i2c_algo_bit_data *algo = port->adapter.algo_data;
- nv_debug(i2c, "using custom udelay %d instead of %d\n",
- info[i].udelay, algo->udelay);
- orig_udelay = algo->udelay;
- algo->udelay = info[i].udelay;
- }
-
- if (nv_probe_i2c(port, info[i].dev.addr) &&
- (!match || match(port, &info[i].dev, data))) {
- nv_info(i2c, "detected %s: %s\n", what,
- info[i].dev.type);
- return i;
- }
-
- if (orig_udelay) {
- struct i2c_algo_bit_data *algo = port->adapter.algo_data;
- algo->udelay = orig_udelay;
- }
- }
-
- nv_debug(i2c, "no devices found.\n");
- return -ENODEV;
-}
-
-static void
-nouveau_i2c_intr_fini(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
- struct nouveau_i2c_port *port = i2c->find(i2c, index);
- const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
- if (port && port->aux >= 0)
- impl->aux_mask(i2c, type, 1 << port->aux, 0);
-}
-
-static void
-nouveau_i2c_intr_init(struct nvkm_event *event, int type, int index)
-{
- struct nouveau_i2c *i2c = container_of(event, typeof(*i2c), event);
- struct nouveau_i2c_port *port = i2c->find(i2c, index);
- const struct nouveau_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
- if (port && port->aux >= 0)
- impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
-}
-
-static int
-nouveau_i2c_intr_ctor(struct nouveau_object *object, void *data, u32 size,
- struct nvkm_notify *notify)
-{
- struct nvkm_i2c_ntfy_req *req = data;
- if (!WARN_ON(size != sizeof(*req))) {
- notify->size = sizeof(struct nvkm_i2c_ntfy_rep);
- notify->types = req->mask;
- notify->index = req->port;
- return 0;
- }
- return -EINVAL;
-}
-
-static void
-nouveau_i2c_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_i2c_impl *impl = (void *)nv_oclass(subdev);
- struct nouveau_i2c *i2c = nouveau_i2c(subdev);
- struct nouveau_i2c_port *port;
- u32 hi, lo, rq, tx, e;
-
- if (impl->aux_stat) {
- impl->aux_stat(i2c, &hi, &lo, &rq, &tx);
- if (hi || lo || rq || tx) {
- list_for_each_entry(port, &i2c->ports, head) {
- if (e = 0, port->aux < 0)
- continue;
-
- if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG;
- if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
- if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
- if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
- if (e) {
- struct nvkm_i2c_ntfy_rep rep = {
- .mask = e,
- };
- nvkm_event_send(&i2c->event, rep.mask,
- port->index, &rep,
- sizeof(rep));
- }
- }
- }
- }
-}
-
-static const struct nvkm_event_func
-nouveau_i2c_intr_func = {
- .ctor = nouveau_i2c_intr_ctor,
- .init = nouveau_i2c_intr_init,
- .fini = nouveau_i2c_intr_fini,
-};
-
-int
-_nouveau_i2c_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_i2c_impl *impl = (void *)nv_oclass(object);
- struct nouveau_i2c *i2c = (void *)object;
- struct nouveau_i2c_port *port;
- u32 mask;
- int ret;
-
- list_for_each_entry(port, &i2c->ports, head) {
- ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
- if (ret && suspend)
- goto fail;
- }
-
- if ((mask = (1 << impl->aux) - 1), impl->aux_stat) {
- impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
- impl->aux_stat(i2c, &mask, &mask, &mask, &mask);
- }
-
- return nouveau_subdev_fini(&i2c->base, suspend);
-fail:
- list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
- nv_ofuncs(port)->init(nv_object(port));
- }
-
- return ret;
-}
-
-int
-_nouveau_i2c_init(struct nouveau_object *object)
-{
- struct nouveau_i2c *i2c = (void *)object;
- struct nouveau_i2c_port *port;
- int ret;
-
- ret = nouveau_subdev_init(&i2c->base);
- if (ret == 0) {
- list_for_each_entry(port, &i2c->ports, head) {
- ret = nv_ofuncs(port)->init(nv_object(port));
- if (ret)
- goto fail;
- }
- }
-
- return ret;
-fail:
- list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
- nv_ofuncs(port)->fini(nv_object(port), false);
- }
-
- return ret;
-}
-
-void
-_nouveau_i2c_dtor(struct nouveau_object *object)
-{
- struct nouveau_i2c *i2c = (void *)object;
- struct nouveau_i2c_port *port, *temp;
-
- nvkm_event_fini(&i2c->event);
-
- list_for_each_entry_safe(port, temp, &i2c->ports, head) {
- nouveau_object_ref(NULL, (struct nouveau_object **)&port);
- }
-
- nouveau_subdev_destroy(&i2c->base);
-}
-
-static struct nouveau_oclass *
-nouveau_i2c_extdev_sclass[] = {
- nouveau_anx9805_sclass,
-};
-
-static void
-nouveau_i2c_create_port(struct nouveau_i2c *i2c, int index, u8 type,
- struct dcb_i2c_entry *info)
-{
- const struct nouveau_i2c_impl *impl = (void *)nv_oclass(i2c);
- struct nouveau_oclass *oclass;
- struct nouveau_object *parent;
- struct nouveau_object *object;
- int ret, pad;
-
- if (info->share != DCB_I2C_UNUSED) {
- pad = info->share;
- oclass = impl->pad_s;
- } else {
- if (type != DCB_I2C_NVIO_AUX)
- pad = 0x100 + info->drive;
- else
- pad = 0x100 + info->auxch;
- oclass = impl->pad_x;
- }
-
- ret = nouveau_object_ctor(NULL, nv_object(i2c), oclass, NULL, pad,
- &parent);
- if (ret < 0)
- return;
-
- oclass = impl->sclass;
- do {
- ret = -EINVAL;
- if (oclass->handle == type) {
- ret = nouveau_object_ctor(parent, nv_object(i2c),
- oclass, info, index,
- &object);
- }
- } while (ret && (++oclass)->handle);
-
- nouveau_object_ref(NULL, &parent);
-}
-
-int
-nouveau_i2c_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int length, void **pobject)
-{
- struct nouveau_bios *bios = nouveau_bios(parent);
- struct nouveau_i2c *i2c;
- struct nouveau_object *object;
- struct dcb_i2c_entry info;
- int ret, i, j, index = -1;
- struct dcb_output outp;
- u8 ver, hdr;
- u32 data;
-
- ret = nouveau_subdev_create(parent, engine, oclass, 0,
- "I2C", "i2c", &i2c);
- *pobject = nv_object(i2c);
- if (ret)
- return ret;
-
- nv_subdev(i2c)->intr = nouveau_i2c_intr;
- i2c->find = nouveau_i2c_find;
- i2c->find_type = nouveau_i2c_find_type;
- i2c->acquire_pad = nouveau_i2c_acquire_pad;
- i2c->release_pad = nouveau_i2c_release_pad;
- i2c->acquire = nouveau_i2c_acquire;
- i2c->release = nouveau_i2c_release;
- i2c->identify = nouveau_i2c_identify;
- init_waitqueue_head(&i2c->wait);
- INIT_LIST_HEAD(&i2c->ports);
-
- while (!dcb_i2c_parse(bios, ++index, &info)) {
- switch (info.type) {
- case DCB_I2C_NV04_BIT:
- case DCB_I2C_NV4E_BIT:
- case DCB_I2C_NVIO_BIT:
- nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
- info.type, &info);
- break;
- case DCB_I2C_NVIO_AUX:
- nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
- info.type, &info);
- break;
- case DCB_I2C_PMGR:
- if (info.drive != DCB_I2C_UNUSED) {
- nouveau_i2c_create_port(i2c, NV_I2C_PORT(index),
- DCB_I2C_NVIO_BIT,
- &info);
- }
- if (info.auxch != DCB_I2C_UNUSED) {
- nouveau_i2c_create_port(i2c, NV_I2C_AUX(index),
- DCB_I2C_NVIO_AUX,
- &info);
- }
- break;
- case DCB_I2C_UNUSED:
- default:
- continue;
- }
- }
-
- /* in addition to the busses specified in the i2c table, there
- * may be ddc/aux channels hiding behind external tmds/dp/etc
- * transmitters.
- */
- index = NV_I2C_EXT(0);
- i = -1;
- while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
- if (!outp.location || !outp.extdev)
- continue;
-
- switch (outp.type) {
- case DCB_OUTPUT_TMDS:
- info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
- break;
- case DCB_OUTPUT_DP:
- info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
- break;
- default:
- continue;
- }
-
- ret = -ENODEV;
- j = -1;
- while (ret && ++j < ARRAY_SIZE(nouveau_i2c_extdev_sclass)) {
- parent = nv_object(i2c->find(i2c, outp.i2c_index));
- oclass = nouveau_i2c_extdev_sclass[j];
- do {
- if (oclass->handle != info.type)
- continue;
- ret = nouveau_object_ctor(parent, *pobject,
- oclass, NULL,
- index++, &object);
- } while (ret && (++oclass)->handle);
- }
- }
-
- ret = nvkm_event_init(&nouveau_i2c_intr_func, 4, index, &i2c->event);
- if (ret)
- return ret;
-
- return 0;
-}
-
-int
-_nouveau_i2c_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_i2c *i2c;
- int ret;
-
- ret = nouveau_i2c_create(parent, engine, oclass, &i2c);
- *pobject = nv_object(i2c);
- if (ret)
- return ret;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
deleted file mode 100644
index 813ffc96e864..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/bit.c
+++ /dev/null
@@ -1,234 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
-#define T_TIMEOUT 2200000
-#define T_RISEFALL 1000
-#define T_HOLD 5000
-
-static inline void
-i2c_drive_scl(struct nouveau_i2c_port *port, int state)
-{
- port->func->drive_scl(port, state);
-}
-
-static inline void
-i2c_drive_sda(struct nouveau_i2c_port *port, int state)
-{
- port->func->drive_sda(port, state);
-}
-
-static inline int
-i2c_sense_scl(struct nouveau_i2c_port *port)
-{
- return port->func->sense_scl(port);
-}
-
-static inline int
-i2c_sense_sda(struct nouveau_i2c_port *port)
-{
- return port->func->sense_sda(port);
-}
-
-static void
-i2c_delay(struct nouveau_i2c_port *port, u32 nsec)
-{
- udelay((nsec + 500) / 1000);
-}
-
-static bool
-i2c_raise_scl(struct nouveau_i2c_port *port)
-{
- u32 timeout = T_TIMEOUT / T_RISEFALL;
-
- i2c_drive_scl(port, 1);
- do {
- i2c_delay(port, T_RISEFALL);
- } while (!i2c_sense_scl(port) && --timeout);
-
- return timeout != 0;
-}
-
-static int
-i2c_start(struct nouveau_i2c_port *port)
-{
- int ret = 0;
-
- if (!i2c_sense_scl(port) ||
- !i2c_sense_sda(port)) {
- i2c_drive_scl(port, 0);
- i2c_drive_sda(port, 1);
- if (!i2c_raise_scl(port))
- ret = -EBUSY;
- }
-
- i2c_drive_sda(port, 0);
- i2c_delay(port, T_HOLD);
- i2c_drive_scl(port, 0);
- i2c_delay(port, T_HOLD);
- return ret;
-}
-
-static void
-i2c_stop(struct nouveau_i2c_port *port)
-{
- i2c_drive_scl(port, 0);
- i2c_drive_sda(port, 0);
- i2c_delay(port, T_RISEFALL);
-
- i2c_drive_scl(port, 1);
- i2c_delay(port, T_HOLD);
- i2c_drive_sda(port, 1);
- i2c_delay(port, T_HOLD);
-}
-
-static int
-i2c_bitw(struct nouveau_i2c_port *port, int sda)
-{
- i2c_drive_sda(port, sda);
- i2c_delay(port, T_RISEFALL);
-
- if (!i2c_raise_scl(port))
- return -ETIMEDOUT;
- i2c_delay(port, T_HOLD);
-
- i2c_drive_scl(port, 0);
- i2c_delay(port, T_HOLD);
- return 0;
-}
-
-static int
-i2c_bitr(struct nouveau_i2c_port *port)
-{
- int sda;
-
- i2c_drive_sda(port, 1);
- i2c_delay(port, T_RISEFALL);
-
- if (!i2c_raise_scl(port))
- return -ETIMEDOUT;
- i2c_delay(port, T_HOLD);
-
- sda = i2c_sense_sda(port);
-
- i2c_drive_scl(port, 0);
- i2c_delay(port, T_HOLD);
- return sda;
-}
-
-static int
-i2c_get_byte(struct nouveau_i2c_port *port, u8 *byte, bool last)
-{
- int i, bit;
-
- *byte = 0;
- for (i = 7; i >= 0; i--) {
- bit = i2c_bitr(port);
- if (bit < 0)
- return bit;
- *byte |= bit << i;
- }
-
- return i2c_bitw(port, last ? 1 : 0);
-}
-
-static int
-i2c_put_byte(struct nouveau_i2c_port *port, u8 byte)
-{
- int i, ret;
- for (i = 7; i >= 0; i--) {
- ret = i2c_bitw(port, !!(byte & (1 << i)));
- if (ret < 0)
- return ret;
- }
-
- ret = i2c_bitr(port);
- if (ret == 1) /* nack */
- ret = -EIO;
- return ret;
-}
-
-static int
-i2c_addr(struct nouveau_i2c_port *port, struct i2c_msg *msg)
-{
- u32 addr = msg->addr << 1;
- if (msg->flags & I2C_M_RD)
- addr |= 1;
- return i2c_put_byte(port, addr);
-}
-
-static int
-i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
- struct nouveau_i2c_port *port = adap->algo_data;
- struct i2c_msg *msg = msgs;
- int ret = 0, mcnt = num;
-
- ret = nouveau_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT));
- if (ret)
- return ret;
-
- while (!ret && mcnt--) {
- u8 remaining = msg->len;
- u8 *ptr = msg->buf;
-
- ret = i2c_start(port);
- if (ret == 0)
- ret = i2c_addr(port, msg);
-
- if (msg->flags & I2C_M_RD) {
- while (!ret && remaining--)
- ret = i2c_get_byte(port, ptr++, !remaining);
- } else {
- while (!ret && remaining--)
- ret = i2c_put_byte(port, *ptr++);
- }
-
- msg++;
- }
-
- i2c_stop(port);
- nouveau_i2c(port)->release(port);
- return (ret < 0) ? ret : num;
-}
-#else
-static int
-i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
-{
- return -ENODEV;
-}
-#endif
-
-static u32
-i2c_bit_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
-}
-
-const struct i2c_algorithm nouveau_i2c_bit_algo = {
- .master_xfer = i2c_bit_xfer,
- .functionality = i2c_bit_func
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c
deleted file mode 100644
index fa891c39866b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/gf117.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-struct nouveau_oclass *
-gf117_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0xd7),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nvd0_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
- .pad_s = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c
deleted file mode 100644
index 06a2b87ccbf1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/gm204.c
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
-#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
-
-static void
-auxch_fini(struct nouveau_i2c *aux, int ch)
-{
- nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000);
-}
-
-static int
-auxch_init(struct nouveau_i2c *aux, int ch)
-{
- const u32 unksel = 1; /* nfi which to use, or if it matters.. */
- const u32 ureq = unksel ? 0x00100000 : 0x00200000;
- const u32 urep = unksel ? 0x01000000 : 0x02000000;
- u32 ctrl, timeout;
-
- /* wait up to 1ms for any previous transaction to be done... */
- timeout = 1000;
- do {
- ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
- return -EBUSY;
- }
- } while (ctrl & 0x03010000);
-
- /* set some magic, and wait up to 1ms for it to appear */
- nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq);
- timeout = 1000;
- do {
- ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("magic wait 0x%08x\n", ctrl);
- auxch_fini(aux, ch);
- return -EBUSY;
- }
- } while ((ctrl & 0x03000000) != urep);
-
- return 0;
-}
-
-int
-gm204_aux(struct nouveau_i2c_port *base, bool retry,
- u8 type, u32 addr, u8 *data, u8 size)
-{
- struct nouveau_i2c *aux = nouveau_i2c(base);
- struct nv50_i2c_port *port = (void *)base;
- u32 ctrl, stat, timeout, retries;
- u32 xbuf[4] = {};
- int ch = port->addr;
- int ret, i;
-
- AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-
- ret = auxch_init(aux, ch);
- if (ret)
- goto out;
-
- stat = nv_rd32(aux, 0x00d958 + (ch * 0x50));
- if (!(stat & 0x10000000)) {
- AUX_DBG("sink not detected\n");
- ret = -ENXIO;
- goto out;
- }
-
- if (!(type & 1)) {
- memcpy(xbuf, data, size);
- for (i = 0; i < 16; i += 4) {
- AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
- nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]);
- }
- }
-
- ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
- ctrl &= ~0x0001f0ff;
- ctrl |= type << 12;
- ctrl |= size - 1;
- nv_wr32(aux, 0x00d950 + (ch * 0x50), addr);
-
- /* (maybe) retry transaction a number of times on failure... */
- for (retries = 0; !ret && retries < 32; retries++) {
- /* reset, and delay a while if this is a retry */
- nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl);
- nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl);
- if (retries)
- udelay(400);
-
- /* transaction request, wait up to 1ms for it to complete */
- nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl);
-
- timeout = 1000;
- do {
- ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("tx req timeout 0x%08x\n", ctrl);
- ret = -EIO;
- goto out;
- }
- } while (ctrl & 0x00010000);
- ret = 1;
-
- /* read status, and check if transaction completed ok */
- stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0);
- if ((stat & 0x000f0000) == 0x00080000 ||
- (stat & 0x000f0000) == 0x00020000)
- ret = retry ? 0 : 1;
- if ((stat & 0x00000100))
- ret = -ETIMEDOUT;
- if ((stat & 0x00000e00))
- ret = -EIO;
-
- AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
- }
-
- if (type & 1) {
- for (i = 0; i < 16; i += 4) {
- xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i);
- AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
- }
- memcpy(data, xbuf, size);
- }
-
-out:
- auxch_fini(aux, ch);
- return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
-}
-
-static const struct nouveau_i2c_func
-gm204_aux_func = {
- .aux = gm204_aux,
-};
-
-int
-gm204_aux_port_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv50_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_aux_algo, &gm204_aux_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- port->base.aux = info->auxch;
- port->addr = info->auxch;
- return 0;
-}
-
-struct nouveau_oclass
-gm204_i2c_sclass[] = {
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvd0_i2c_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = nv50_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm204_aux_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- {}
-};
-
-struct nouveau_oclass *
-gm204_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0x24),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = gm204_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
- .pad_s = &gm204_i2c_pad_oclass,
- .aux = 8,
- .aux_stat = nve0_aux_stat,
- .aux_mask = nve0_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
deleted file mode 100644
index b1725bdea967..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv04.c
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/vga.h>
-
-#include "priv.h"
-
-struct nv04_i2c_priv {
- struct nouveau_i2c base;
-};
-
-struct nv04_i2c_port {
- struct nouveau_i2c_port base;
- u8 drive;
- u8 sense;
-};
-
-static void
-nv04_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
-{
- struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv04_i2c_port *port = (void *)base;
- u8 val = nv_rdvgac(priv, 0, port->drive);
- if (state) val |= 0x20;
- else val &= 0xdf;
- nv_wrvgac(priv, 0, port->drive, val | 0x01);
-}
-
-static void
-nv04_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
-{
- struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv04_i2c_port *port = (void *)base;
- u8 val = nv_rdvgac(priv, 0, port->drive);
- if (state) val |= 0x10;
- else val &= 0xef;
- nv_wrvgac(priv, 0, port->drive, val | 0x01);
-}
-
-static int
-nv04_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
- struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv04_i2c_port *port = (void *)base;
- return !!(nv_rdvgac(priv, 0, port->sense) & 0x04);
-}
-
-static int
-nv04_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
- struct nv04_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv04_i2c_port *port = (void *)base;
- return !!(nv_rdvgac(priv, 0, port->sense) & 0x08);
-}
-
-static const struct nouveau_i2c_func
-nv04_i2c_func = {
- .drive_scl = nv04_i2c_drive_scl,
- .drive_sda = nv04_i2c_drive_sda,
- .sense_scl = nv04_i2c_sense_scl,
- .sense_sda = nv04_i2c_sense_sda,
-};
-
-static int
-nv04_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv04_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_bit_algo, &nv04_i2c_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- port->drive = info->drive;
- port->sense = info->sense;
- return 0;
-}
-
-static struct nouveau_oclass
-nv04_i2c_sclass[] = {
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_i2c_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- {}
-};
-
-struct nouveau_oclass *
-nv04_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nv04_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
deleted file mode 100644
index f16c87ce5ba1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv4e.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/vga.h>
-
-#include "priv.h"
-
-struct nv4e_i2c_priv {
- struct nouveau_i2c base;
-};
-
-struct nv4e_i2c_port {
- struct nouveau_i2c_port base;
- u32 addr;
-};
-
-static void
-nv4e_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
-{
- struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv4e_i2c_port *port = (void *)base;
- nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01);
-}
-
-static void
-nv4e_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
-{
- struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv4e_i2c_port *port = (void *)base;
- nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01);
-}
-
-static int
-nv4e_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
- struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv4e_i2c_port *port = (void *)base;
- return !!(nv_rd32(priv, port->addr) & 0x00040000);
-}
-
-static int
-nv4e_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
- struct nv4e_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv4e_i2c_port *port = (void *)base;
- return !!(nv_rd32(priv, port->addr) & 0x00080000);
-}
-
-static const struct nouveau_i2c_func
-nv4e_i2c_func = {
- .drive_scl = nv4e_i2c_drive_scl,
- .drive_sda = nv4e_i2c_drive_sda,
- .sense_scl = nv4e_i2c_sense_scl,
- .sense_sda = nv4e_i2c_sense_sda,
-};
-
-static int
-nv4e_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv4e_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_bit_algo, &nv4e_i2c_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- port->addr = 0x600800 + info->drive;
- return 0;
-}
-
-static struct nouveau_oclass
-nv4e_i2c_sclass[] = {
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv4e_i2c_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- {}
-};
-
-struct nouveau_oclass *
-nv4e_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0x4e),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nv4e_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
deleted file mode 100644
index 7b8756d4df08..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.c
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-void
-nv50_i2c_drive_scl(struct nouveau_i2c_port *base, int state)
-{
- struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv50_i2c_port *port = (void *)base;
- if (state) port->state |= 0x01;
- else port->state &= 0xfe;
- nv_wr32(priv, port->addr, port->state);
-}
-
-void
-nv50_i2c_drive_sda(struct nouveau_i2c_port *base, int state)
-{
- struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv50_i2c_port *port = (void *)base;
- if (state) port->state |= 0x02;
- else port->state &= 0xfd;
- nv_wr32(priv, port->addr, port->state);
-}
-
-int
-nv50_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
- struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv50_i2c_port *port = (void *)base;
- return !!(nv_rd32(priv, port->addr) & 0x00000001);
-}
-
-int
-nv50_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
- struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv50_i2c_port *port = (void *)base;
- return !!(nv_rd32(priv, port->addr) & 0x00000002);
-}
-
-static const struct nouveau_i2c_func
-nv50_i2c_func = {
- .drive_scl = nv50_i2c_drive_scl,
- .drive_sda = nv50_i2c_drive_sda,
- .sense_scl = nv50_i2c_sense_scl,
- .sense_sda = nv50_i2c_sense_sda,
-};
-
-const u32 nv50_i2c_addr[] = {
- 0x00e138, 0x00e150, 0x00e168, 0x00e180,
- 0x00e254, 0x00e274, 0x00e764, 0x00e780,
- 0x00e79c, 0x00e7b8
-};
-const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr);
-
-static int
-nv50_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv50_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_bit_algo, &nv50_i2c_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- if (info->drive >= nv50_i2c_addr_nr)
- return -EINVAL;
-
- port->state = 0x00000007;
- port->addr = nv50_i2c_addr[info->drive];
- return 0;
-}
-
-int
-nv50_i2c_port_init(struct nouveau_object *object)
-{
- struct nv50_i2c_priv *priv = (void *)object->engine;
- struct nv50_i2c_port *port = (void *)object;
- nv_wr32(priv, port->addr, port->state);
- return nouveau_i2c_port_init(&port->base);
-}
-
-static struct nouveau_oclass
-nv50_i2c_sclass[] = {
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_i2c_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = nv50_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- {}
-};
-
-struct nouveau_oclass *
-nv50_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nv50_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
deleted file mode 100644
index 9ef965692fb1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv50.h
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef __NV50_I2C_H__
-#define __NV50_I2C_H__
-
-#include "priv.h"
-
-struct nv50_i2c_priv {
- struct nouveau_i2c base;
-};
-
-struct nv50_i2c_port {
- struct nouveau_i2c_port base;
- u32 addr;
- u32 state;
-};
-
-extern const u32 nv50_i2c_addr[];
-extern const int nv50_i2c_addr_nr;
-int nv50_i2c_port_init(struct nouveau_object *);
-int nv50_i2c_sense_scl(struct nouveau_i2c_port *);
-int nv50_i2c_sense_sda(struct nouveau_i2c_port *);
-void nv50_i2c_drive_scl(struct nouveau_i2c_port *, int state);
-void nv50_i2c_drive_sda(struct nouveau_i2c_port *, int state);
-
-int nv94_aux_port_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv94_i2c_acquire(struct nouveau_i2c_port *);
-void nv94_i2c_release(struct nouveau_i2c_port *);
-
-int nvd0_i2c_port_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
deleted file mode 100644
index e383ee81f4d2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nv94.c
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-void
-nv94_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
-{
- u32 intr = nv_rd32(i2c, 0x00e06c);
- u32 stat = nv_rd32(i2c, 0x00e068) & intr, i;
- for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
- if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
- if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
- if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
- if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
- }
- nv_wr32(i2c, 0x00e06c, intr);
-}
-
-void
-nv94_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
-{
- u32 temp = nv_rd32(i2c, 0x00e068), i;
- for (i = 0; i < 8; i++) {
- if (mask & (1 << i)) {
- if (!(data & (1 << i))) {
- temp &= ~(type << (i * 4));
- continue;
- }
- temp |= type << (i * 4);
- }
- }
- nv_wr32(i2c, 0x00e068, temp);
-}
-
-#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
-#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
-
-static void
-auxch_fini(struct nouveau_i2c *aux, int ch)
-{
- nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
-}
-
-static int
-auxch_init(struct nouveau_i2c *aux, int ch)
-{
- const u32 unksel = 1; /* nfi which to use, or if it matters.. */
- const u32 ureq = unksel ? 0x00100000 : 0x00200000;
- const u32 urep = unksel ? 0x01000000 : 0x02000000;
- u32 ctrl, timeout;
-
- /* wait up to 1ms for any previous transaction to be done... */
- timeout = 1000;
- do {
- ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
- return -EBUSY;
- }
- } while (ctrl & 0x03010000);
-
- /* set some magic, and wait up to 1ms for it to appear */
- nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
- timeout = 1000;
- do {
- ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("magic wait 0x%08x\n", ctrl);
- auxch_fini(aux, ch);
- return -EBUSY;
- }
- } while ((ctrl & 0x03000000) != urep);
-
- return 0;
-}
-
-int
-nv94_aux(struct nouveau_i2c_port *base, bool retry,
- u8 type, u32 addr, u8 *data, u8 size)
-{
- struct nouveau_i2c *aux = nouveau_i2c(base);
- struct nv50_i2c_port *port = (void *)base;
- u32 ctrl, stat, timeout, retries;
- u32 xbuf[4] = {};
- int ch = port->addr;
- int ret, i;
-
- AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
-
- ret = auxch_init(aux, ch);
- if (ret)
- goto out;
-
- stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
- if (!(stat & 0x10000000)) {
- AUX_DBG("sink not detected\n");
- ret = -ENXIO;
- goto out;
- }
-
- if (!(type & 1)) {
- memcpy(xbuf, data, size);
- for (i = 0; i < 16; i += 4) {
- AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
- nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
- }
- }
-
- ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
- ctrl &= ~0x0001f0ff;
- ctrl |= type << 12;
- ctrl |= size - 1;
- nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
-
- /* (maybe) retry transaction a number of times on failure... */
- for (retries = 0; !ret && retries < 32; retries++) {
- /* reset, and delay a while if this is a retry */
- nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
- nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
- if (retries)
- udelay(400);
-
- /* transaction request, wait up to 1ms for it to complete */
- nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
-
- timeout = 1000;
- do {
- ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
- udelay(1);
- if (!timeout--) {
- AUX_ERR("tx req timeout 0x%08x\n", ctrl);
- ret = -EIO;
- goto out;
- }
- } while (ctrl & 0x00010000);
- ret = 1;
-
- /* read status, and check if transaction completed ok */
- stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
- if ((stat & 0x000f0000) == 0x00080000 ||
- (stat & 0x000f0000) == 0x00020000)
- ret = retry ? 0 : 1;
- if ((stat & 0x00000100))
- ret = -ETIMEDOUT;
- if ((stat & 0x00000e00))
- ret = -EIO;
-
- AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
- }
-
- if (type & 1) {
- for (i = 0; i < 16; i += 4) {
- xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
- AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
- }
- memcpy(data, xbuf, size);
- }
-
-out:
- auxch_fini(aux, ch);
- return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
-}
-
-static const struct nouveau_i2c_func
-nv94_i2c_func = {
- .drive_scl = nv50_i2c_drive_scl,
- .drive_sda = nv50_i2c_drive_sda,
- .sense_scl = nv50_i2c_sense_scl,
- .sense_sda = nv50_i2c_sense_sda,
-};
-
-static int
-nv94_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv50_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_bit_algo, &nv94_i2c_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- if (info->drive >= nv50_i2c_addr_nr)
- return -EINVAL;
-
- port->state = 7;
- port->addr = nv50_i2c_addr[info->drive];
- return 0;
-}
-
-static const struct nouveau_i2c_func
-nv94_aux_func = {
- .aux = nv94_aux,
-};
-
-int
-nv94_aux_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv50_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_aux_algo, &nv94_aux_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- port->base.aux = info->auxch;
- port->addr = info->auxch;
- return 0;
-}
-
-static struct nouveau_oclass
-nv94_i2c_sclass[] = {
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv94_i2c_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = nv50_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv94_aux_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- {}
-};
-
-struct nouveau_oclass *
-nv94_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0x94),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nv94_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
- .pad_s = &nv94_i2c_pad_oclass,
- .aux = 4,
- .aux_stat = nv94_aux_stat,
- .aux_mask = nv94_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
deleted file mode 100644
index fd99380502ec..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nvd0.c
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-static int
-nvd0_i2c_sense_scl(struct nouveau_i2c_port *base)
-{
- struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv50_i2c_port *port = (void *)base;
- return !!(nv_rd32(priv, port->addr) & 0x00000010);
-}
-
-static int
-nvd0_i2c_sense_sda(struct nouveau_i2c_port *base)
-{
- struct nv50_i2c_priv *priv = (void *)nv_object(base)->engine;
- struct nv50_i2c_port *port = (void *)base;
- return !!(nv_rd32(priv, port->addr) & 0x00000020);
-}
-
-static const struct nouveau_i2c_func
-nvd0_i2c_func = {
- .drive_scl = nv50_i2c_drive_scl,
- .drive_sda = nv50_i2c_drive_sda,
- .sense_scl = nvd0_i2c_sense_scl,
- .sense_sda = nvd0_i2c_sense_sda,
-};
-
-int
-nvd0_i2c_port_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct dcb_i2c_entry *info = data;
- struct nv50_i2c_port *port;
- int ret;
-
- ret = nouveau_i2c_port_create(parent, engine, oclass, index,
- &nouveau_i2c_bit_algo, &nvd0_i2c_func,
- &port);
- *pobject = nv_object(port);
- if (ret)
- return ret;
-
- port->state = 0x00000007;
- port->addr = 0x00d014 + (info->drive * 0x20);
- return 0;
-}
-
-struct nouveau_oclass
-nvd0_i2c_sclass[] = {
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvd0_i2c_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = nv50_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv94_aux_port_ctor,
- .dtor = _nouveau_i2c_port_dtor,
- .init = _nouveau_i2c_port_init,
- .fini = _nouveau_i2c_port_fini,
- },
- },
- {}
-};
-
-struct nouveau_oclass *
-nvd0_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0xd0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nvd0_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
- .pad_s = &nv94_i2c_pad_oclass,
- .aux = 4,
- .aux_stat = nv94_aux_stat,
- .aux_mask = nv94_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
deleted file mode 100644
index 25fe5c2d110e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/nve0.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv50.h"
-
-void
-nve0_aux_stat(struct nouveau_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
-{
- u32 intr = nv_rd32(i2c, 0x00dc60);
- u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i;
- for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
- if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
- if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
- if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
- if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
- }
- nv_wr32(i2c, 0x00dc60, intr);
-}
-
-void
-nve0_aux_mask(struct nouveau_i2c *i2c, u32 type, u32 mask, u32 data)
-{
- u32 temp = nv_rd32(i2c, 0x00dc68), i;
- for (i = 0; i < 8; i++) {
- if (mask & (1 << i)) {
- if (!(data & (1 << i))) {
- temp &= ~(type << (i * 4));
- continue;
- }
- temp |= type << (i * 4);
- }
- }
- nv_wr32(i2c, 0x00dc68, temp);
-}
-
-struct nouveau_oclass *
-nve0_i2c_oclass = &(struct nouveau_i2c_impl) {
- .base.handle = NV_SUBDEV(I2C, 0xe0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_i2c_ctor,
- .dtor = _nouveau_i2c_dtor,
- .init = _nouveau_i2c_init,
- .fini = _nouveau_i2c_fini,
- },
- .sclass = nvd0_i2c_sclass,
- .pad_x = &nv04_i2c_pad_oclass,
- .pad_s = &nv94_i2c_pad_oclass,
- .aux = 4,
- .aux_stat = nve0_aux_stat,
- .aux_mask = nve0_aux_mask,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c
deleted file mode 100644
index e9e412477c12..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-int
-_nvkm_i2c_pad_fini(struct nouveau_object *object, bool suspend)
-{
- struct nvkm_i2c_pad *pad = (void *)object;
- DBG("-> NULL\n");
- pad->port = NULL;
- return nouveau_object_fini(&pad->base, suspend);
-}
-
-int
-_nvkm_i2c_pad_init(struct nouveau_object *object)
-{
- struct nvkm_i2c_pad *pad = (void *)object;
- DBG("-> PORT:%02x\n", pad->next->index);
- pad->port = pad->next;
- return nouveau_object_init(&pad->base);
-}
-
-int
-nvkm_i2c_pad_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int index,
- int size, void **pobject)
-{
- struct nouveau_i2c *i2c = (void *)engine;
- struct nouveau_i2c_port *port;
- struct nvkm_i2c_pad *pad;
- int ret;
-
- list_for_each_entry(port, &i2c->ports, head) {
- pad = nvkm_i2c_pad(port);
- if (pad->index == index) {
- atomic_inc(&nv_object(pad)->refcount);
- *pobject = pad;
- return 1;
- }
- }
-
- ret = nouveau_object_create_(parent, engine, oclass, 0, size, pobject);
- pad = *pobject;
- if (ret)
- return ret;
-
- pad->index = index;
- return 0;
-}
-
-int
-_nvkm_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct nvkm_i2c_pad *pad;
- int ret;
- ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
- *pobject = nv_object(pad);
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h
deleted file mode 100644
index 452ac10c3004..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/pad.h
+++ /dev/null
@@ -1,58 +0,0 @@
-#ifndef __NVKM_I2C_PAD_H__
-#define __NVKM_I2C_PAD_H__
-
-#include "priv.h"
-
-struct nvkm_i2c_pad {
- struct nouveau_object base;
- int index;
- struct nouveau_i2c_port *port;
- struct nouveau_i2c_port *next;
-};
-
-static inline struct nvkm_i2c_pad *
-nvkm_i2c_pad(struct nouveau_i2c_port *port)
-{
- struct nouveau_object *pad = nv_object(port);
- while (pad->parent)
- pad = pad->parent;
- return (void *)pad;
-}
-
-#define nvkm_i2c_pad_create(p,e,o,i,d) \
- nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
-#define nvkm_i2c_pad_destroy(p) ({ \
- struct nvkm_i2c_pad *_p = (p); \
- _nvkm_i2c_pad_dtor(nv_object(_p)); \
-})
-#define nvkm_i2c_pad_init(p) ({ \
- struct nvkm_i2c_pad *_p = (p); \
- _nvkm_i2c_pad_init(nv_object(_p)); \
-})
-#define nvkm_i2c_pad_fini(p,s) ({ \
- struct nvkm_i2c_pad *_p = (p); \
- _nvkm_i2c_pad_fini(nv_object(_p), (s)); \
-})
-
-int nvkm_i2c_pad_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int index, int, void **);
-
-int _nvkm_i2c_pad_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-#define _nvkm_i2c_pad_dtor nouveau_object_destroy
-int _nvkm_i2c_pad_init(struct nouveau_object *);
-int _nvkm_i2c_pad_fini(struct nouveau_object *, bool);
-
-#ifndef MSG
-#define MSG(l,f,a...) do { \
- struct nvkm_i2c_pad *_pad = (void *)pad; \
- nv_##l(nv_object(_pad)->engine, "PAD:%c:%02x: "f, \
- _pad->index >= 0x100 ? 'X' : 'S', \
- _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c
deleted file mode 100644
index f0e6fbbaa8cd..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/padgm204.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-struct gm204_i2c_pad {
- struct nvkm_i2c_pad base;
- int addr;
-};
-
-static int
-gm204_i2c_pad_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_i2c *i2c = (void *)object->engine;
- struct gm204_i2c_pad *pad = (void *)object;
- nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001);
- return nvkm_i2c_pad_fini(&pad->base, suspend);
-}
-
-static int
-gm204_i2c_pad_init(struct nouveau_object *object)
-{
- struct nouveau_i2c *i2c = (void *)object->engine;
- struct gm204_i2c_pad *pad = (void *)object;
-
- switch (nv_oclass(pad->base.next)->handle) {
- case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
- nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002);
- break;
- case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
- default:
- nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001);
- break;
- }
-
- nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000);
- return nvkm_i2c_pad_init(&pad->base);
-}
-
-static int
-gm204_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct gm204_i2c_pad *pad;
- int ret;
-
- ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
- *pobject = nv_object(pad);
- if (ret)
- return ret;
-
- pad->addr = index * 0x50;;
- return 0;
-}
-
-struct nouveau_oclass
-gm204_i2c_pad_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm204_i2c_pad_ctor,
- .dtor = _nvkm_i2c_pad_dtor,
- .init = gm204_i2c_pad_init,
- .fini = gm204_i2c_pad_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c
deleted file mode 100644
index 2c4b61296dd1..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv04.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-struct nouveau_oclass
-nv04_i2c_pad_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nvkm_i2c_pad_ctor,
- .dtor = _nvkm_i2c_pad_dtor,
- .init = _nvkm_i2c_pad_init,
- .fini = _nvkm_i2c_pad_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c b/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c
deleted file mode 100644
index 0dc6753014f0..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/padnv94.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "pad.h"
-
-struct nv94_i2c_pad {
- struct nvkm_i2c_pad base;
- int addr;
-};
-
-static int
-nv94_i2c_pad_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_i2c *i2c = (void *)object->engine;
- struct nv94_i2c_pad *pad = (void *)object;
- nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001);
- return nvkm_i2c_pad_fini(&pad->base, suspend);
-}
-
-static int
-nv94_i2c_pad_init(struct nouveau_object *object)
-{
- struct nouveau_i2c *i2c = (void *)object->engine;
- struct nv94_i2c_pad *pad = (void *)object;
-
- switch (nv_oclass(pad->base.next)->handle) {
- case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
- nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002);
- break;
- case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
- default:
- nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001);
- break;
- }
-
- nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000);
- return nvkm_i2c_pad_init(&pad->base);
-}
-
-static int
-nv94_i2c_pad_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 index,
- struct nouveau_object **pobject)
-{
- struct nv94_i2c_pad *pad;
- int ret;
-
- ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
- *pobject = nv_object(pad);
- if (ret)
- return ret;
-
- pad->addr = index * 0x50;;
- return 0;
-}
-
-struct nouveau_oclass
-nv94_i2c_pad_oclass = {
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv94_i2c_pad_ctor,
- .dtor = _nvkm_i2c_pad_dtor,
- .init = nv94_i2c_pad_init,
- .fini = nv94_i2c_pad_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h
deleted file mode 100644
index a8ff6e077af5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/port.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef __NVKM_I2C_PORT_H__
-#define __NVKM_I2C_PORT_H__
-
-#include "priv.h"
-
-#ifndef MSG
-#define MSG(l,f,a...) do { \
- struct nouveau_i2c_port *_port = (void *)port; \
- nv_##l(nv_object(_port)->engine, "PORT:%02x: "f, _port->index, ##a); \
-} while(0)
-#define DBG(f,a...) MSG(debug, f, ##a)
-#define ERR(f,a...) MSG(error, f, ##a)
-#endif
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
deleted file mode 100644
index 4fe7ae3fde4e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/i2c/priv.h
+++ /dev/null
@@ -1,89 +0,0 @@
-#ifndef __NVKM_I2C_H__
-#define __NVKM_I2C_H__
-
-#include <subdev/i2c.h>
-
-extern struct nouveau_oclass nv04_i2c_pad_oclass;
-extern struct nouveau_oclass nv94_i2c_pad_oclass;
-extern struct nouveau_oclass gm204_i2c_pad_oclass;
-
-#define nouveau_i2c_port_create(p,e,o,i,a,f,d) \
- nouveau_i2c_port_create_((p), (e), (o), (i), (a), (f), \
- sizeof(**d), (void **)d)
-#define nouveau_i2c_port_destroy(p) ({ \
- struct nouveau_i2c_port *port = (p); \
- _nouveau_i2c_port_dtor(nv_object(i2c)); \
-})
-#define nouveau_i2c_port_init(p) \
- nouveau_object_init(&(p)->base)
-#define nouveau_i2c_port_fini(p,s) \
- nouveau_object_fini(&(p)->base, (s))
-
-int nouveau_i2c_port_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, u8,
- const struct i2c_algorithm *,
- const struct nouveau_i2c_func *,
- int, void **);
-void _nouveau_i2c_port_dtor(struct nouveau_object *);
-#define _nouveau_i2c_port_init nouveau_object_init
-int _nouveau_i2c_port_fini(struct nouveau_object *, bool);
-
-#define nouveau_i2c_create(p,e,o,d) \
- nouveau_i2c_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_i2c_destroy(p) ({ \
- struct nouveau_i2c *i2c = (p); \
- _nouveau_i2c_dtor(nv_object(i2c)); \
-})
-#define nouveau_i2c_init(p) ({ \
- struct nouveau_i2c *i2c = (p); \
- _nouveau_i2c_init(nv_object(i2c)); \
-})
-#define nouveau_i2c_fini(p,s) ({ \
- struct nouveau_i2c *i2c = (p); \
- _nouveau_i2c_fini(nv_object(i2c), (s)); \
-})
-
-int nouveau_i2c_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-int _nouveau_i2c_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void _nouveau_i2c_dtor(struct nouveau_object *);
-int _nouveau_i2c_init(struct nouveau_object *);
-int _nouveau_i2c_fini(struct nouveau_object *, bool);
-
-extern struct nouveau_oclass nouveau_anx9805_sclass[];
-extern struct nouveau_oclass nvd0_i2c_sclass[];
-
-extern const struct i2c_algorithm nouveau_i2c_bit_algo;
-extern const struct i2c_algorithm nouveau_i2c_aux_algo;
-
-struct nouveau_i2c_impl {
- struct nouveau_oclass base;
-
- /* supported i2c port classes */
- struct nouveau_oclass *sclass;
- struct nouveau_oclass *pad_x;
- struct nouveau_oclass *pad_s;
-
- /* number of native dp aux channels present */
- int aux;
-
- /* read and ack pending interrupts, returning only data
- * for ports that have not been masked off, while still
- * performing the ack for anything that was pending.
- */
- void (*aux_stat)(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
-
- /* mask on/off interrupt types for a given set of auxch
- */
- void (*aux_mask)(struct nouveau_i2c *, u32, u32, u32);
-};
-
-void nv94_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
-void nv94_aux_mask(struct nouveau_i2c *, u32, u32, u32);
-
-void nve0_aux_stat(struct nouveau_i2c *, u32 *, u32 *, u32 *, u32 *);
-void nve0_aux_mask(struct nouveau_i2c *, u32, u32, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c
deleted file mode 100644
index 245f0ebaa6af..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ibus/gk20a.c
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 <subdev/ibus.h>
-#include <subdev/timer.h>
-
-struct gk20a_ibus_priv {
- struct nouveau_ibus base;
-};
-
-static void
-gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv)
-{
- nv_mask(priv, 0x137250, 0x3f, 0);
-
- nv_mask(priv, 0x000200, 0x20, 0);
- usleep_range(20, 30);
- nv_mask(priv, 0x000200, 0x20, 0x20);
-
- nv_wr32(priv, 0x12004c, 0x4);
- nv_wr32(priv, 0x122204, 0x2);
- nv_rd32(priv, 0x122204);
-}
-
-static void
-gk20a_ibus_intr(struct nouveau_subdev *subdev)
-{
- struct gk20a_ibus_priv *priv = (void *)subdev;
- u32 status0 = nv_rd32(priv, 0x120058);
-
- if (status0 & 0x7) {
- nv_debug(priv, "resetting priv ring\n");
- gk20a_ibus_init_priv_ring(priv);
- }
-
- /* Acknowledge interrupt */
- nv_mask(priv, 0x12004c, 0x2, 0x2);
-
- if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00))
- nv_warn(priv, "timeout waiting for ringmaster ack\n");
-}
-
-static int
-gk20a_ibus_init(struct nouveau_object *object)
-{
- struct gk20a_ibus_priv *priv = (void *)object;
- int ret;
-
- ret = _nouveau_ibus_init(object);
- if (ret)
- return ret;
-
- gk20a_ibus_init_priv_ring(priv);
-
- return 0;
-}
-
-static int
-gk20a_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gk20a_ibus_priv *priv;
- int ret;
-
- ret = nouveau_ibus_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->intr = gk20a_ibus_intr;
- return 0;
-}
-
-struct nouveau_oclass
-gk20a_ibus_oclass = {
- .handle = NV_SUBDEV(IBUS, 0xea),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gk20a_ibus_ctor,
- .dtor = _nouveau_ibus_dtor,
- .init = gk20a_ibus_init,
- .fini = _nouveau_ibus_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c
deleted file mode 100644
index 4e977ff27e44..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ibus/nvc0.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/ibus.h>
-
-struct nvc0_ibus_priv {
- struct nouveau_ibus base;
-};
-
-static void
-nvc0_ibus_intr_hub(struct nvc0_ibus_priv *priv, int i)
-{
- u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400));
- u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400));
- u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400));
- nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
- nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000);
-}
-
-static void
-nvc0_ibus_intr_rop(struct nvc0_ibus_priv *priv, int i)
-{
- u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400));
- u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400));
- u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400));
- nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
- nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000);
-}
-
-static void
-nvc0_ibus_intr_gpc(struct nvc0_ibus_priv *priv, int i)
-{
- u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400));
- u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400));
- u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400));
- nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
- nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000);
-}
-
-static void
-nvc0_ibus_intr(struct nouveau_subdev *subdev)
-{
- struct nvc0_ibus_priv *priv = (void *)subdev;
- u32 intr0 = nv_rd32(priv, 0x121c58);
- u32 intr1 = nv_rd32(priv, 0x121c5c);
- u32 hubnr = nv_rd32(priv, 0x121c70);
- u32 ropnr = nv_rd32(priv, 0x121c74);
- u32 gpcnr = nv_rd32(priv, 0x121c78);
- u32 i;
-
- for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
- u32 stat = 0x00000100 << i;
- if (intr0 & stat) {
- nvc0_ibus_intr_hub(priv, i);
- intr0 &= ~stat;
- }
- }
-
- for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
- u32 stat = 0x00010000 << i;
- if (intr0 & stat) {
- nvc0_ibus_intr_rop(priv, i);
- intr0 &= ~stat;
- }
- }
-
- for (i = 0; intr1 && i < gpcnr; i++) {
- u32 stat = 0x00000001 << i;
- if (intr1 & stat) {
- nvc0_ibus_intr_gpc(priv, i);
- intr1 &= ~stat;
- }
- }
-}
-
-static int
-nvc0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_ibus_priv *priv;
- int ret;
-
- ret = nouveau_ibus_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->intr = nvc0_ibus_intr;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_ibus_oclass = {
- .handle = NV_SUBDEV(IBUS, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_ibus_ctor,
- .dtor = _nouveau_ibus_dtor,
- .init = _nouveau_ibus_init,
- .fini = _nouveau_ibus_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c b/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c
deleted file mode 100644
index ebef970a0645..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ibus/nve0.c
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/ibus.h>
-
-struct nve0_ibus_priv {
- struct nouveau_ibus base;
-};
-
-static void
-nve0_ibus_intr_hub(struct nve0_ibus_priv *priv, int i)
-{
- u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800));
- u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800));
- u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800));
- nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
- nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000);
-}
-
-static void
-nve0_ibus_intr_rop(struct nve0_ibus_priv *priv, int i)
-{
- u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800));
- u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800));
- u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800));
- nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
- nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000);
-}
-
-static void
-nve0_ibus_intr_gpc(struct nve0_ibus_priv *priv, int i)
-{
- u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800));
- u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800));
- u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800));
- nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
- nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000);
-}
-
-static void
-nve0_ibus_intr(struct nouveau_subdev *subdev)
-{
- struct nve0_ibus_priv *priv = (void *)subdev;
- u32 intr0 = nv_rd32(priv, 0x120058);
- u32 intr1 = nv_rd32(priv, 0x12005c);
- u32 hubnr = nv_rd32(priv, 0x120070);
- u32 ropnr = nv_rd32(priv, 0x120074);
- u32 gpcnr = nv_rd32(priv, 0x120078);
- u32 i;
-
- for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
- u32 stat = 0x00000100 << i;
- if (intr0 & stat) {
- nve0_ibus_intr_hub(priv, i);
- intr0 &= ~stat;
- }
- }
-
- for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
- u32 stat = 0x00010000 << i;
- if (intr0 & stat) {
- nve0_ibus_intr_rop(priv, i);
- intr0 &= ~stat;
- }
- }
-
- for (i = 0; intr1 && i < gpcnr; i++) {
- u32 stat = 0x00000001 << i;
- if (intr1 & stat) {
- nve0_ibus_intr_gpc(priv, i);
- intr1 &= ~stat;
- }
- }
-}
-
-static int
-nve0_ibus_init(struct nouveau_object *object)
-{
- struct nve0_ibus_priv *priv = (void *)object;
- int ret = nouveau_ibus_init(&priv->base);
- if (ret == 0) {
- nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000);
- nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200);
- nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800);
- nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100);
- nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff);
- nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200);
- nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880);
- }
- return ret;
-}
-
-static int
-nve0_ibus_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nve0_ibus_priv *priv;
- int ret;
-
- ret = nouveau_ibus_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->intr = nve0_ibus_intr;
- return 0;
-}
-
-struct nouveau_oclass
-nve0_ibus_oclass = {
- .handle = NV_SUBDEV(IBUS, 0xe0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nve0_ibus_ctor,
- .dtor = _nouveau_ibus_dtor,
- .init = nve0_ibus_init,
- .fini = _nouveau_ibus_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c
deleted file mode 100644
index 14706d9842ca..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/base.c
+++ /dev/null
@@ -1,157 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-/******************************************************************************
- * instmem object base implementation
- *****************************************************************************/
-
-void
-_nouveau_instobj_dtor(struct nouveau_object *object)
-{
- struct nouveau_instmem *imem = (void *)object->engine;
- struct nouveau_instobj *iobj = (void *)object;
-
- mutex_lock(&nv_subdev(imem)->mutex);
- list_del(&iobj->head);
- mutex_unlock(&nv_subdev(imem)->mutex);
-
- return nouveau_object_destroy(&iobj->base);
-}
-
-int
-nouveau_instobj_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int length, void **pobject)
-{
- struct nouveau_instmem *imem = (void *)engine;
- struct nouveau_instobj *iobj;
- int ret;
-
- ret = nouveau_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS,
- length, pobject);
- iobj = *pobject;
- if (ret)
- return ret;
-
- mutex_lock(&imem->base.mutex);
- list_add(&iobj->head, &imem->list);
- mutex_unlock(&imem->base.mutex);
- return 0;
-}
-
-/******************************************************************************
- * instmem subdev base implementation
- *****************************************************************************/
-
-static int
-nouveau_instmem_alloc(struct nouveau_instmem *imem,
- struct nouveau_object *parent, u32 size, u32 align,
- struct nouveau_object **pobject)
-{
- struct nouveau_object *engine = nv_object(imem);
- struct nouveau_instmem_impl *impl = (void *)engine->oclass;
- struct nouveau_instobj_args args = { .size = size, .align = align };
- return nouveau_object_ctor(parent, engine, impl->instobj, &args,
- sizeof(args), pobject);
-}
-
-int
-_nouveau_instmem_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_instmem *imem = (void *)object;
- struct nouveau_instobj *iobj;
- int i, ret = 0;
-
- if (suspend) {
- mutex_lock(&imem->base.mutex);
-
- list_for_each_entry(iobj, &imem->list, head) {
- iobj->suspend = vmalloc(iobj->size);
- if (!iobj->suspend) {
- ret = -ENOMEM;
- break;
- }
-
- for (i = 0; i < iobj->size; i += 4)
- iobj->suspend[i / 4] = nv_ro32(iobj, i);
- }
-
- mutex_unlock(&imem->base.mutex);
-
- if (ret)
- return ret;
- }
-
- return nouveau_subdev_fini(&imem->base, suspend);
-}
-
-int
-_nouveau_instmem_init(struct nouveau_object *object)
-{
- struct nouveau_instmem *imem = (void *)object;
- struct nouveau_instobj *iobj;
- int ret, i;
-
- ret = nouveau_subdev_init(&imem->base);
- if (ret)
- return ret;
-
- mutex_lock(&imem->base.mutex);
-
- list_for_each_entry(iobj, &imem->list, head) {
- if (iobj->suspend) {
- for (i = 0; i < iobj->size; i += 4)
- nv_wo32(iobj, i, iobj->suspend[i / 4]);
- vfree(iobj->suspend);
- iobj->suspend = NULL;
- }
- }
-
- mutex_unlock(&imem->base.mutex);
-
- return 0;
-}
-
-int
-nouveau_instmem_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int length, void **pobject)
-{
- struct nouveau_instmem *imem;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0,
- "INSTMEM", "instmem", length, pobject);
- imem = *pobject;
- if (ret)
- return ret;
-
- INIT_LIST_HEAD(&imem->list);
- imem->alloc = nouveau_instmem_alloc;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
deleted file mode 100644
index e8b1401c59c0..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.c
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-/******************************************************************************
- * instmem object implementation
- *****************************************************************************/
-
-static u32
-nv04_instobj_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nv04_instobj_priv *node = (void *)object;
- return nv_ro32(object->engine, node->mem->offset + addr);
-}
-
-static void
-nv04_instobj_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nv04_instobj_priv *node = (void *)object;
- nv_wo32(object->engine, node->mem->offset + addr, data);
-}
-
-static void
-nv04_instobj_dtor(struct nouveau_object *object)
-{
- struct nv04_instmem_priv *priv = (void *)object->engine;
- struct nv04_instobj_priv *node = (void *)object;
- nouveau_mm_free(&priv->heap, &node->mem);
- nouveau_instobj_destroy(&node->base);
-}
-
-static int
-nv04_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_instmem_priv *priv = (void *)engine;
- struct nv04_instobj_priv *node;
- struct nouveau_instobj_args *args = data;
- int ret;
-
- if (!args->align)
- args->align = 1;
-
- ret = nouveau_instobj_create(parent, engine, oclass, &node);
- *pobject = nv_object(node);
- if (ret)
- return ret;
-
- ret = nouveau_mm_head(&priv->heap, 0, 1, args->size, args->size,
- args->align, &node->mem);
- if (ret)
- return ret;
-
- node->base.addr = node->mem->offset;
- node->base.size = node->mem->length;
- return 0;
-}
-
-struct nouveau_instobj_impl
-nv04_instobj_oclass = {
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_instobj_ctor,
- .dtor = nv04_instobj_dtor,
- .init = _nouveau_instobj_init,
- .fini = _nouveau_instobj_fini,
- .rd32 = nv04_instobj_rd32,
- .wr32 = nv04_instobj_wr32,
- },
-};
-
-/******************************************************************************
- * instmem subdev implementation
- *****************************************************************************/
-
-static u32
-nv04_instmem_rd32(struct nouveau_object *object, u64 addr)
-{
- return nv_rd32(object, 0x700000 + addr);
-}
-
-static void
-nv04_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- return nv_wr32(object, 0x700000 + addr, data);
-}
-
-void
-nv04_instmem_dtor(struct nouveau_object *object)
-{
- struct nv04_instmem_priv *priv = (void *)object;
- nouveau_gpuobj_ref(NULL, &priv->ramfc);
- nouveau_gpuobj_ref(NULL, &priv->ramro);
- nouveau_ramht_ref(NULL, &priv->ramht);
- nouveau_gpuobj_ref(NULL, &priv->vbios);
- nouveau_mm_fini(&priv->heap);
- if (priv->iomem)
- iounmap(priv->iomem);
- nouveau_instmem_destroy(&priv->base);
-}
-
-static int
-nv04_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_instmem_priv *priv;
- int ret;
-
- ret = nouveau_instmem_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- /* PRAMIN aperture maps over the end of VRAM, reserve it */
- priv->base.reserved = 512 * 1024;
-
- ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
- if (ret)
- return ret;
-
- /* 0x00000-0x10000: reserve for probable vbios image */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
- &priv->vbios);
- if (ret)
- return ret;
-
- /* 0x10000-0x18000: reserve for RAMHT */
- ret = nouveau_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht);
- if (ret)
- return ret;
-
- /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x00800, 0,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
- if (ret)
- return ret;
-
- /* 0x18800-0x18a00: reserve for RAMRO */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0,
- &priv->ramro);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_instmem_oclass = &(struct nouveau_instmem_impl) {
- .base.handle = NV_SUBDEV(INSTMEM, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_instmem_ctor,
- .dtor = nv04_instmem_dtor,
- .init = _nouveau_instmem_init,
- .fini = _nouveau_instmem_fini,
- .rd32 = nv04_instmem_rd32,
- .wr32 = nv04_instmem_wr32,
- },
- .instobj = &nv04_instobj_oclass.base,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
deleted file mode 100644
index 095fbc6fc099..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv04.h
+++ /dev/null
@@ -1,40 +0,0 @@
-#ifndef __NV04_INSTMEM_H__
-#define __NV04_INSTMEM_H__
-
-#include <core/gpuobj.h>
-#include <core/ramht.h>
-#include <core/mm.h>
-
-#include "priv.h"
-
-extern struct nouveau_instobj_impl nv04_instobj_oclass;
-
-struct nv04_instmem_priv {
- struct nouveau_instmem base;
-
- void __iomem *iomem;
- struct nouveau_mm heap;
-
- struct nouveau_gpuobj *vbios;
- struct nouveau_ramht *ramht;
- struct nouveau_gpuobj *ramro;
- struct nouveau_gpuobj *ramfc;
-};
-
-static inline struct nv04_instmem_priv *
-nv04_instmem(void *obj)
-{
- return (void *)nouveau_instmem(obj);
-}
-
-struct nv04_instobj_priv {
- struct nouveau_instobj base;
- struct nouveau_mm_node *mem;
-};
-
-void nv04_instmem_dtor(struct nouveau_object *);
-
-int nv04_instmem_alloc(struct nouveau_instmem *, struct nouveau_object *,
- u32 size, u32 align, struct nouveau_object **pobject);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
deleted file mode 100644
index 8803809f9fc5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv40.c
+++ /dev/null
@@ -1,137 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <engine/graph/nv40.h>
-
-#include "nv04.h"
-
-/******************************************************************************
- * instmem subdev implementation
- *****************************************************************************/
-
-static u32
-nv40_instmem_rd32(struct nouveau_object *object, u64 addr)
-{
- struct nv04_instmem_priv *priv = (void *)object;
- return ioread32_native(priv->iomem + addr);
-}
-
-static void
-nv40_instmem_wr32(struct nouveau_object *object, u64 addr, u32 data)
-{
- struct nv04_instmem_priv *priv = (void *)object;
- iowrite32_native(data, priv->iomem + addr);
-}
-
-static int
-nv40_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nv04_instmem_priv *priv;
- int ret, bar, vs;
-
- ret = nouveau_instmem_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- /* map bar */
- if (nv_device_resource_len(device, 2))
- bar = 2;
- else
- bar = 3;
-
- priv->iomem = ioremap(nv_device_resource_start(device, bar),
- nv_device_resource_len(device, bar));
- if (!priv->iomem) {
- nv_error(priv, "unable to map PRAMIN BAR\n");
- return -EFAULT;
- }
-
- /* PRAMIN aperture maps over the end of vram, reserve enough space
- * to fit graphics contexts for every channel, the magics come
- * from engine/graph/nv40.c
- */
- vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8);
- if (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs;
- else if (device->chipset < 0x43) priv->base.reserved = 0x4f00 * vs;
- else if (nv44_graph_class(priv)) priv->base.reserved = 0x4980 * vs;
- else priv->base.reserved = 0x4a40 * vs;
- priv->base.reserved += 16 * 1024;
- priv->base.reserved *= 32; /* per-channel */
- priv->base.reserved += 512 * 1024; /* pci(e)gart table */
- priv->base.reserved += 512 * 1024; /* object storage */
-
- priv->base.reserved = round_up(priv->base.reserved, 4096);
-
- ret = nouveau_mm_init(&priv->heap, 0, priv->base.reserved, 1);
- if (ret)
- return ret;
-
- /* 0x00000-0x10000: reserve for probable vbios image */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
- &priv->vbios);
- if (ret)
- return ret;
-
- /* 0x10000-0x18000: reserve for RAMHT */
- ret = nouveau_ramht_new(nv_object(priv), NULL, 0x08000, 0,
- &priv->ramht);
- if (ret)
- return ret;
-
- /* 0x18000-0x18200: reserve for RAMRO
- * 0x18200-0x20000: padding
- */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x08000, 0, 0,
- &priv->ramro);
- if (ret)
- return ret;
-
- /* 0x20000-0x21000: reserve for RAMFC
- * 0x21000-0x40000: padding and some unknown crap
- */
- ret = nouveau_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
- NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-nv40_instmem_oclass = &(struct nouveau_instmem_impl) {
- .base.handle = NV_SUBDEV(INSTMEM, 0x40),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_instmem_ctor,
- .dtor = nv04_instmem_dtor,
- .init = _nouveau_instmem_init,
- .fini = _nouveau_instmem_fini,
- .rd32 = nv40_instmem_rd32,
- .wr32 = nv40_instmem_wr32,
- },
- .instobj = &nv04_instobj_oclass.base,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
deleted file mode 100644
index 7cb3b098a08d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/nv50.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb.h>
-#include <core/mm.h>
-
-#include "priv.h"
-
-struct nv50_instmem_priv {
- struct nouveau_instmem base;
- spinlock_t lock;
- u64 addr;
-};
-
-struct nv50_instobj_priv {
- struct nouveau_instobj base;
- struct nouveau_mem *mem;
-};
-
-/******************************************************************************
- * instmem object implementation
- *****************************************************************************/
-
-static u32
-nv50_instobj_rd32(struct nouveau_object *object, u64 offset)
-{
- struct nv50_instmem_priv *priv = (void *)object->engine;
- struct nv50_instobj_priv *node = (void *)object;
- unsigned long flags;
- u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
- u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
- u32 data;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (unlikely(priv->addr != base)) {
- nv_wr32(priv, 0x001700, base >> 16);
- priv->addr = base;
- }
- data = nv_rd32(priv, 0x700000 + addr);
- spin_unlock_irqrestore(&priv->lock, flags);
- return data;
-}
-
-static void
-nv50_instobj_wr32(struct nouveau_object *object, u64 offset, u32 data)
-{
- struct nv50_instmem_priv *priv = (void *)object->engine;
- struct nv50_instobj_priv *node = (void *)object;
- unsigned long flags;
- u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
- u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (unlikely(priv->addr != base)) {
- nv_wr32(priv, 0x001700, base >> 16);
- priv->addr = base;
- }
- nv_wr32(priv, 0x700000 + addr, data);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void
-nv50_instobj_dtor(struct nouveau_object *object)
-{
- struct nv50_instobj_priv *node = (void *)object;
- struct nouveau_fb *pfb = nouveau_fb(object);
- pfb->ram->put(pfb, &node->mem);
- nouveau_instobj_destroy(&node->base);
-}
-
-static int
-nv50_instobj_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nouveau_instobj_args *args = data;
- struct nv50_instobj_priv *node;
- int ret;
-
- args->size = max((args->size + 4095) & ~4095, (u32)4096);
- args->align = max((args->align + 4095) & ~4095, (u32)4096);
-
- ret = nouveau_instobj_create(parent, engine, oclass, &node);
- *pobject = nv_object(node);
- if (ret)
- return ret;
-
- ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem);
- if (ret)
- return ret;
-
- node->base.addr = node->mem->offset;
- node->base.size = node->mem->size << 12;
- node->mem->page_shift = 12;
- return 0;
-}
-
-static struct nouveau_instobj_impl
-nv50_instobj_oclass = {
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_instobj_ctor,
- .dtor = nv50_instobj_dtor,
- .init = _nouveau_instobj_init,
- .fini = _nouveau_instobj_fini,
- .rd32 = nv50_instobj_rd32,
- .wr32 = nv50_instobj_wr32,
- },
-};
-
-/******************************************************************************
- * instmem subdev implementation
- *****************************************************************************/
-
-static int
-nv50_instmem_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv50_instmem_priv *priv = (void *)object;
- priv->addr = ~0ULL;
- return nouveau_instmem_fini(&priv->base, suspend);
-}
-
-static int
-nv50_instmem_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_instmem_priv *priv;
- int ret;
-
- ret = nouveau_instmem_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-struct nouveau_oclass *
-nv50_instmem_oclass = &(struct nouveau_instmem_impl) {
- .base.handle = NV_SUBDEV(INSTMEM, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_instmem_ctor,
- .dtor = _nouveau_instmem_dtor,
- .init = _nouveau_instmem_init,
- .fini = nv50_instmem_fini,
- },
- .instobj = &nv50_instobj_oclass.base,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h
deleted file mode 100644
index 8d67dedc5bb2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/instmem/priv.h
+++ /dev/null
@@ -1,56 +0,0 @@
-#ifndef __NVKM_INSTMEM_PRIV_H__
-#define __NVKM_INSTMEM_PRIV_H__
-
-#include <subdev/instmem.h>
-
-struct nouveau_instobj_impl {
- struct nouveau_oclass base;
-};
-
-struct nouveau_instobj_args {
- u32 size;
- u32 align;
-};
-
-#define nouveau_instobj_create(p,e,o,d) \
- nouveau_instobj_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_instobj_destroy(p) ({ \
- struct nouveau_instobj *iobj = (p); \
- _nouveau_instobj_dtor(nv_object(iobj)); \
-})
-#define nouveau_instobj_init(p) \
- nouveau_object_init(&(p)->base)
-#define nouveau_instobj_fini(p,s) \
- nouveau_object_fini(&(p)->base, (s))
-
-int nouveau_instobj_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_instobj_dtor(struct nouveau_object *);
-#define _nouveau_instobj_init nouveau_object_init
-#define _nouveau_instobj_fini nouveau_object_fini
-
-struct nouveau_instmem_impl {
- struct nouveau_oclass base;
- struct nouveau_oclass *instobj;
-};
-
-#define nouveau_instmem_create(p,e,o,d) \
- nouveau_instmem_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_instmem_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_instmem_init(p) ({ \
- struct nouveau_instmem *imem = (p); \
- _nouveau_instmem_init(nv_object(imem)); \
-})
-#define nouveau_instmem_fini(p,s) ({ \
- struct nouveau_instmem *imem = (p); \
- _nouveau_instmem_fini(nv_object(imem), (s)); \
-})
-
-int nouveau_instmem_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-#define _nouveau_instmem_dtor _nouveau_subdev_dtor
-int _nouveau_instmem_init(struct nouveau_object *);
-int _nouveau_instmem_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c
deleted file mode 100644
index 7fa331516f84..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/base.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs <bskeggs@redhat.com>
- */
-
-#include "priv.h"
-
-static int
-nvkm_ltc_tags_alloc(struct nouveau_ltc *ltc, u32 n,
- struct nouveau_mm_node **pnode)
-{
- struct nvkm_ltc_priv *priv = (void *)ltc;
- int ret;
-
- ret = nouveau_mm_head(&priv->tags, 0, 1, n, n, 1, pnode);
- if (ret)
- *pnode = NULL;
-
- return ret;
-}
-
-static void
-nvkm_ltc_tags_free(struct nouveau_ltc *ltc, struct nouveau_mm_node **pnode)
-{
- struct nvkm_ltc_priv *priv = (void *)ltc;
- nouveau_mm_free(&priv->tags, pnode);
-}
-
-static void
-nvkm_ltc_tags_clear(struct nouveau_ltc *ltc, u32 first, u32 count)
-{
- const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
- struct nvkm_ltc_priv *priv = (void *)ltc;
- const u32 limit = first + count - 1;
-
- BUG_ON((first > limit) || (limit >= priv->num_tags));
-
- impl->cbc_clear(priv, first, limit);
- impl->cbc_wait(priv);
-}
-
-static int
-nvkm_ltc_zbc_color_get(struct nouveau_ltc *ltc, int index, const u32 color[4])
-{
- const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
- struct nvkm_ltc_priv *priv = (void *)ltc;
- memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index]));
- impl->zbc_clear_color(priv, index, color);
- return index;
-}
-
-static int
-nvkm_ltc_zbc_depth_get(struct nouveau_ltc *ltc, int index, const u32 depth)
-{
- const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
- struct nvkm_ltc_priv *priv = (void *)ltc;
- priv->zbc_depth[index] = depth;
- impl->zbc_clear_depth(priv, index, depth);
- return index;
-}
-
-int
-_nvkm_ltc_init(struct nouveau_object *object)
-{
- const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object);
- struct nvkm_ltc_priv *priv = (void *)object;
- int ret, i;
-
- ret = nouveau_subdev_init(&priv->base.base);
- if (ret)
- return ret;
-
- for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) {
- impl->zbc_clear_color(priv, i, priv->zbc_color[i]);
- impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]);
- }
-
- return 0;
-}
-
-int
-nvkm_ltc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- const struct nvkm_ltc_impl *impl = (void *)oclass;
- struct nvkm_ltc_priv *priv;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PLTCG",
- "l2c", length, pobject);
- priv = *pobject;
- if (ret)
- return ret;
-
- memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color));
- memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth));
-
- priv->base.base.intr = impl->intr;
- priv->base.tags_alloc = nvkm_ltc_tags_alloc;
- priv->base.tags_free = nvkm_ltc_tags_free;
- priv->base.tags_clear = nvkm_ltc_tags_clear;
- priv->base.zbc_min = 1; /* reserve 0 for disabled */
- priv->base.zbc_max = min(impl->zbc, NOUVEAU_LTC_MAX_ZBC_CNT) - 1;
- priv->base.zbc_color_get = nvkm_ltc_zbc_color_get;
- priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
deleted file mode 100644
index 2db0977284f8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/gf100.c
+++ /dev/null
@@ -1,236 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include "priv.h"
-
-void
-gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
-{
- nv_wr32(priv, 0x17e8cc, start);
- nv_wr32(priv, 0x17e8d0, limit);
- nv_wr32(priv, 0x17e8c8, 0x00000004);
-}
-
-void
-gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
-{
- int c, s;
- for (c = 0; c < priv->ltc_nr; c++) {
- for (s = 0; s < priv->lts_nr; s++)
- nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0);
- }
-}
-
-void
-gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
-{
- nv_mask(priv, 0x17ea44, 0x0000000f, i);
- nv_wr32(priv, 0x17ea48, color[0]);
- nv_wr32(priv, 0x17ea4c, color[1]);
- nv_wr32(priv, 0x17ea50, color[2]);
- nv_wr32(priv, 0x17ea54, color[3]);
-}
-
-void
-gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
-{
- nv_mask(priv, 0x17ea44, 0x0000000f, i);
- nv_wr32(priv, 0x17ea58, depth);
-}
-
-static const struct nouveau_bitfield
-gf100_ltc_lts_intr_name[] = {
- { 0x00000001, "IDLE_ERROR_IQ" },
- { 0x00000002, "IDLE_ERROR_CBC" },
- { 0x00000004, "IDLE_ERROR_TSTG" },
- { 0x00000008, "IDLE_ERROR_DSTG" },
- { 0x00000010, "EVICTED_CB" },
- { 0x00000020, "ILLEGAL_COMPSTAT" },
- { 0x00000040, "BLOCKLINEAR_CB" },
- { 0x00000100, "ECC_SEC_ERROR" },
- { 0x00000200, "ECC_DED_ERROR" },
- { 0x00000400, "DEBUG" },
- { 0x00000800, "ATOMIC_TO_Z" },
- { 0x00001000, "ILLEGAL_ATOMIC" },
- { 0x00002000, "BLKACTIVITY_ERR" },
- {}
-};
-
-static void
-gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
-{
- u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
- u32 intr = nv_rd32(priv, base + 0x020);
- u32 stat = intr & 0x0000ffff;
-
- if (stat) {
- nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
- nouveau_bitfield_print(gf100_ltc_lts_intr_name, stat);
- pr_cont("\n");
- }
-
- nv_wr32(priv, base + 0x020, intr);
-}
-
-void
-gf100_ltc_intr(struct nouveau_subdev *subdev)
-{
- struct nvkm_ltc_priv *priv = (void *)subdev;
- u32 mask;
-
- mask = nv_rd32(priv, 0x00017c);
- while (mask) {
- u32 lts, ltc = __ffs(mask);
- for (lts = 0; lts < priv->lts_nr; lts++)
- gf100_ltc_lts_intr(priv, ltc, lts);
- mask &= ~(1 << ltc);
- }
-}
-
-static int
-gf100_ltc_init(struct nouveau_object *object)
-{
- struct nvkm_ltc_priv *priv = (void *)object;
- u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
- int ret;
-
- ret = nvkm_ltc_init(priv);
- if (ret)
- return ret;
-
- nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
- nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
- nv_wr32(priv, 0x17e8d4, priv->tag_base);
- nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
- return 0;
-}
-
-void
-gf100_ltc_dtor(struct nouveau_object *object)
-{
- struct nouveau_fb *pfb = nouveau_fb(object);
- struct nvkm_ltc_priv *priv = (void *)object;
-
- nouveau_mm_fini(&priv->tags);
- nouveau_mm_free(&pfb->vram, &priv->tag_ram);
-
- nvkm_ltc_destroy(priv);
-}
-
-/* TODO: Figure out tag memory details and drop the over-cautious allocation.
- */
-int
-gf100_ltc_init_tag_ram(struct nouveau_fb *pfb, struct nvkm_ltc_priv *priv)
-{
- u32 tag_size, tag_margin, tag_align;
- int ret;
-
- /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
- priv->num_tags = (pfb->ram->size >> 17) / 4;
- if (priv->num_tags > (1 << 17))
- priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
- priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
-
- tag_align = priv->ltc_nr * 0x800;
- tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;
-
- /* 4 part 4 sub: 0x2000 bytes for 56 tags */
- /* 3 part 4 sub: 0x6000 bytes for 168 tags */
- /*
- * About 147 bytes per tag. Let's be safe and allocate x2, which makes
- * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
- *
- * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
- */
- tag_size = (priv->num_tags / 64) * 0x6000 + tag_margin;
- tag_size += tag_align;
- tag_size = (tag_size + 0xfff) >> 12; /* round up */
-
- ret = nouveau_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1,
- &priv->tag_ram);
- if (ret) {
- priv->num_tags = 0;
- } else {
- u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;
-
- tag_base += tag_align - 1;
- ret = do_div(tag_base, tag_align);
-
- priv->tag_base = tag_base;
- }
-
- ret = nouveau_mm_init(&priv->tags, 0, priv->num_tags, 1);
- return ret;
-}
-
-int
-gf100_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nvkm_ltc_priv *priv;
- u32 parts, mask;
- int ret, i;
-
- ret = nvkm_ltc_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- parts = nv_rd32(priv, 0x022438);
- mask = nv_rd32(priv, 0x022554);
- for (i = 0; i < parts; i++) {
- if (!(mask & (1 << i)))
- priv->ltc_nr++;
- }
- priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28;
-
- ret = gf100_ltc_init_tag_ram(pfb, priv);
- if (ret)
- return ret;
-
- nv_subdev(priv)->intr = gf100_ltc_intr;
- return 0;
-}
-
-struct nouveau_oclass *
-gf100_ltc_oclass = &(struct nvkm_ltc_impl) {
- .base.handle = NV_SUBDEV(LTC, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gf100_ltc_ctor,
- .dtor = gf100_ltc_dtor,
- .init = gf100_ltc_init,
- .fini = _nvkm_ltc_fini,
- },
- .intr = gf100_ltc_intr,
- .cbc_clear = gf100_ltc_cbc_clear,
- .cbc_wait = gf100_ltc_cbc_wait,
- .zbc = 16,
- .zbc_clear_color = gf100_ltc_zbc_clear_color,
- .zbc_clear_depth = gf100_ltc_zbc_clear_depth,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c
deleted file mode 100644
index b39b5d0eb8f9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/gk104.c
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-gk104_ltc_init(struct nouveau_object *object)
-{
- struct nvkm_ltc_priv *priv = (void *)object;
- u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
- int ret;
-
- ret = nvkm_ltc_init(priv);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
- nv_wr32(priv, 0x17e000, priv->ltc_nr);
- nv_wr32(priv, 0x17e8d4, priv->tag_base);
- nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
- return 0;
-}
-
-struct nouveau_oclass *
-gk104_ltc_oclass = &(struct nvkm_ltc_impl) {
- .base.handle = NV_SUBDEV(LTC, 0xe4),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gf100_ltc_ctor,
- .dtor = gf100_ltc_dtor,
- .init = gk104_ltc_init,
- .fini = _nvkm_ltc_fini,
- },
- .intr = gf100_ltc_intr,
- .cbc_clear = gf100_ltc_cbc_clear,
- .cbc_wait = gf100_ltc_cbc_wait,
- .zbc = 16,
- .zbc_clear_color = gf100_ltc_zbc_clear_color,
- .zbc_clear_depth = gf100_ltc_zbc_clear_depth,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c
deleted file mode 100644
index 89fc4238f50c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/gm107.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright 2014 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/fb.h>
-#include <subdev/timer.h>
-
-#include "priv.h"
-
-static void
-gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
-{
- nv_wr32(priv, 0x17e270, start);
- nv_wr32(priv, 0x17e274, limit);
- nv_wr32(priv, 0x17e26c, 0x00000004);
-}
-
-static void
-gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
-{
- int c, s;
- for (c = 0; c < priv->ltc_nr; c++) {
- for (s = 0; s < priv->lts_nr; s++)
- nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0);
- }
-}
-
-static void
-gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
-{
- nv_mask(priv, 0x17e338, 0x0000000f, i);
- nv_wr32(priv, 0x17e33c, color[0]);
- nv_wr32(priv, 0x17e340, color[1]);
- nv_wr32(priv, 0x17e344, color[2]);
- nv_wr32(priv, 0x17e348, color[3]);
-}
-
-static void
-gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
-{
- nv_mask(priv, 0x17e338, 0x0000000f, i);
- nv_wr32(priv, 0x17e34c, depth);
-}
-
-static void
-gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
-{
- u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400);
- u32 stat = nv_rd32(priv, base + 0x00c);
-
- if (stat) {
- nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
- nv_wr32(priv, base + 0x00c, stat);
- }
-}
-
-static void
-gm107_ltc_intr(struct nouveau_subdev *subdev)
-{
- struct nvkm_ltc_priv *priv = (void *)subdev;
- u32 mask;
-
- mask = nv_rd32(priv, 0x00017c);
- while (mask) {
- u32 lts, ltc = __ffs(mask);
- for (lts = 0; lts < priv->lts_nr; lts++)
- gm107_ltc_lts_isr(priv, ltc, lts);
- mask &= ~(1 << ltc);
- }
-}
-
-static int
-gm107_ltc_init(struct nouveau_object *object)
-{
- struct nvkm_ltc_priv *priv = (void *)object;
- u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
- int ret;
-
- ret = nvkm_ltc_init(priv);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x17e27c, priv->ltc_nr);
- nv_wr32(priv, 0x17e278, priv->tag_base);
- nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
- return 0;
-}
-
-static int
-gm107_ltc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_fb *pfb = nouveau_fb(parent);
- struct nvkm_ltc_priv *priv;
- u32 parts, mask;
- int ret, i;
-
- ret = nvkm_ltc_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- parts = nv_rd32(priv, 0x022438);
- mask = nv_rd32(priv, 0x021c14);
- for (i = 0; i < parts; i++) {
- if (!(mask & (1 << i)))
- priv->ltc_nr++;
- }
- priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28;
-
- ret = gf100_ltc_init_tag_ram(pfb, priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-gm107_ltc_oclass = &(struct nvkm_ltc_impl) {
- .base.handle = NV_SUBDEV(LTC, 0xff),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm107_ltc_ctor,
- .dtor = gf100_ltc_dtor,
- .init = gm107_ltc_init,
- .fini = _nvkm_ltc_fini,
- },
- .intr = gm107_ltc_intr,
- .cbc_clear = gm107_ltc_cbc_clear,
- .cbc_wait = gm107_ltc_cbc_wait,
- .zbc = 16,
- .zbc_clear_color = gm107_ltc_zbc_clear_color,
- .zbc_clear_depth = gm107_ltc_zbc_clear_depth,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h
deleted file mode 100644
index 41f179d93da6..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/ltc/priv.h
+++ /dev/null
@@ -1,71 +0,0 @@
-#ifndef __NVKM_LTC_PRIV_H__
-#define __NVKM_LTC_PRIV_H__
-
-#include <subdev/ltc.h>
-#include <subdev/fb.h>
-
-#include <core/enum.h>
-
-struct nvkm_ltc_priv {
- struct nouveau_ltc base;
- u32 ltc_nr;
- u32 lts_nr;
-
- u32 num_tags;
- u32 tag_base;
- struct nouveau_mm tags;
- struct nouveau_mm_node *tag_ram;
-
- u32 zbc_color[NOUVEAU_LTC_MAX_ZBC_CNT][4];
- u32 zbc_depth[NOUVEAU_LTC_MAX_ZBC_CNT];
-};
-
-#define nvkm_ltc_create(p,e,o,d) \
- nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nvkm_ltc_destroy(p) ({ \
- struct nvkm_ltc_priv *_priv = (p); \
- _nvkm_ltc_dtor(nv_object(_priv)); \
-})
-#define nvkm_ltc_init(p) ({ \
- struct nvkm_ltc_priv *_priv = (p); \
- _nvkm_ltc_init(nv_object(_priv)); \
-})
-#define nvkm_ltc_fini(p,s) ({ \
- struct nvkm_ltc_priv *_priv = (p); \
- _nvkm_ltc_fini(nv_object(_priv), (s)); \
-})
-
-int nvkm_ltc_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-
-#define _nvkm_ltc_dtor _nouveau_subdev_dtor
-int _nvkm_ltc_init(struct nouveau_object *);
-#define _nvkm_ltc_fini _nouveau_subdev_fini
-
-int gf100_ltc_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void gf100_ltc_dtor(struct nouveau_object *);
-int gf100_ltc_init_tag_ram(struct nouveau_fb *, struct nvkm_ltc_priv *);
-int gf100_ltc_tags_alloc(struct nouveau_ltc *, u32, struct nouveau_mm_node **);
-void gf100_ltc_tags_free(struct nouveau_ltc *, struct nouveau_mm_node **);
-
-struct nvkm_ltc_impl {
- struct nouveau_oclass base;
- void (*intr)(struct nouveau_subdev *);
-
- void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit);
- void (*cbc_wait)(struct nvkm_ltc_priv *);
-
- int zbc;
- void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]);
- void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32);
-};
-
-void gf100_ltc_intr(struct nouveau_subdev *);
-void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32);
-void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *);
-void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]);
-void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c b/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
deleted file mode 100644
index ca7cee3a314a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/base.c
+++ /dev/null
@@ -1,169 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include <core/option.h>
-
-static inline void
-nouveau_mc_unk260(struct nouveau_mc *pmc, u32 data)
-{
- const struct nouveau_mc_oclass *impl = (void *)nv_oclass(pmc);
- if (impl->unk260)
- impl->unk260(pmc, data);
-}
-
-static inline u32
-nouveau_mc_intr_mask(struct nouveau_mc *pmc)
-{
- u32 intr = nv_rd32(pmc, 0x000100);
- if (intr == 0xffffffff) /* likely fallen off the bus */
- intr = 0x00000000;
- return intr;
-}
-
-static irqreturn_t
-nouveau_mc_intr(int irq, void *arg)
-{
- struct nouveau_mc *pmc = arg;
- const struct nouveau_mc_oclass *oclass = (void *)nv_object(pmc)->oclass;
- const struct nouveau_mc_intr *map = oclass->intr;
- struct nouveau_subdev *unit;
- u32 intr;
-
- nv_wr32(pmc, 0x000140, 0x00000000);
- nv_rd32(pmc, 0x000140);
- intr = nouveau_mc_intr_mask(pmc);
- if (pmc->use_msi)
- oclass->msi_rearm(pmc);
-
- if (intr) {
- u32 stat = intr = nouveau_mc_intr_mask(pmc);
- while (map->stat) {
- if (intr & map->stat) {
- unit = nouveau_subdev(pmc, map->unit);
- if (unit && unit->intr)
- unit->intr(unit);
- stat &= ~map->stat;
- }
- map++;
- }
-
- if (stat)
- nv_error(pmc, "unknown intr 0x%08x\n", stat);
- }
-
- nv_wr32(pmc, 0x000140, 0x00000001);
- return intr ? IRQ_HANDLED : IRQ_NONE;
-}
-
-int
-_nouveau_mc_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_mc *pmc = (void *)object;
- nv_wr32(pmc, 0x000140, 0x00000000);
- return nouveau_subdev_fini(&pmc->base, suspend);
-}
-
-int
-_nouveau_mc_init(struct nouveau_object *object)
-{
- struct nouveau_mc *pmc = (void *)object;
- int ret = nouveau_subdev_init(&pmc->base);
- if (ret)
- return ret;
- nv_wr32(pmc, 0x000140, 0x00000001);
- return 0;
-}
-
-void
-_nouveau_mc_dtor(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nouveau_mc *pmc = (void *)object;
- free_irq(pmc->irq, pmc);
- if (pmc->use_msi)
- pci_disable_msi(device->pdev);
- nouveau_subdev_destroy(&pmc->base);
-}
-
-int
-nouveau_mc_create_(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *bclass, int length, void **pobject)
-{
- const struct nouveau_mc_oclass *oclass = (void *)bclass;
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_mc *pmc;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, bclass, 0, "PMC",
- "master", length, pobject);
- pmc = *pobject;
- if (ret)
- return ret;
-
- pmc->unk260 = nouveau_mc_unk260;
-
- if (nv_device_is_pci(device))
- switch (device->pdev->device & 0x0ff0) {
- case 0x00f0:
- case 0x02e0:
- /* BR02? NFI how these would be handled yet exactly */
- break;
- default:
- switch (device->chipset) {
- case 0xaa:
- /* reported broken, nv also disable it */
- break;
- default:
- pmc->use_msi = true;
- break;
- }
-
- pmc->use_msi = nouveau_boolopt(device->cfgopt, "NvMSI",
- pmc->use_msi);
-
- if (pmc->use_msi && oclass->msi_rearm) {
- pmc->use_msi = pci_enable_msi(device->pdev) == 0;
- if (pmc->use_msi) {
- nv_info(pmc, "MSI interrupts enabled\n");
- oclass->msi_rearm(pmc);
- }
- } else {
- pmc->use_msi = false;
- }
- }
-
- ret = nv_device_get_irq(device, true);
- if (ret < 0)
- return ret;
- pmc->irq = ret;
-
- ret = request_irq(pmc->irq, nouveau_mc_intr, IRQF_SHARED, "nouveau",
- pmc);
-
- if (ret < 0)
- return ret;
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c
deleted file mode 100644
index b8d6cb435d0a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/gk20a.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-gk20a_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0xea),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv50_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nvc0_mc_intr,
- .msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
deleted file mode 100644
index 2d787e4dfefa..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.c
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-const struct nouveau_mc_intr
-nv04_mc_intr[] = {
- { 0x00000001, NVDEV_ENGINE_MPEG }, /* NV17- MPEG/ME */
- { 0x00000100, NVDEV_ENGINE_FIFO },
- { 0x00001000, NVDEV_ENGINE_GR },
- { 0x00010000, NVDEV_ENGINE_DISP },
- { 0x00020000, NVDEV_ENGINE_VP }, /* NV40- */
- { 0x00100000, NVDEV_SUBDEV_TIMER },
- { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */
- { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */
- { 0x10000000, NVDEV_SUBDEV_BUS },
- { 0x80000000, NVDEV_ENGINE_SW },
- {}
-};
-
-int
-nv04_mc_init(struct nouveau_object *object)
-{
- struct nv04_mc_priv *priv = (void *)object;
-
- nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
- nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */
-
- return nouveau_mc_init(&priv->base);
-}
-
-int
-nv04_mc_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_mc_priv *priv;
- int ret;
-
- ret = nouveau_mc_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass *
-nv04_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x04),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv04_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv04_mc_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
deleted file mode 100644
index 4d9ea46c47c2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv04.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __NVKM_MC_NV04_H__
-#define __NVKM_MC_NV04_H__
-
-#include "priv.h"
-
-struct nv04_mc_priv {
- struct nouveau_mc base;
-};
-
-int nv04_mc_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-
-extern const struct nouveau_mc_intr nv04_mc_intr[];
-int nv04_mc_init(struct nouveau_object *);
-void nv40_mc_msi_rearm(struct nouveau_mc *);
-int nv44_mc_init(struct nouveau_object *object);
-int nv50_mc_init(struct nouveau_object *);
-extern const struct nouveau_mc_intr nv50_mc_intr[];
-extern const struct nouveau_mc_intr nvc0_mc_intr[];
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c
deleted file mode 100644
index 5b1faecfed2d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv40.c
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-void
-nv40_mc_msi_rearm(struct nouveau_mc *pmc)
-{
- struct nv04_mc_priv *priv = (void *)pmc;
- nv_wr08(priv, 0x088068, 0xff);
-}
-
-struct nouveau_oclass *
-nv40_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x40),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv04_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv04_mc_intr,
- .msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
deleted file mode 100644
index cc4d0d2d886e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv44.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-int
-nv44_mc_init(struct nouveau_object *object)
-{
- struct nv04_mc_priv *priv = (void *)object;
- u32 tmp = nv_rd32(priv, 0x10020c);
-
- nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
-
- nv_wr32(priv, 0x001700, tmp);
- nv_wr32(priv, 0x001704, 0);
- nv_wr32(priv, 0x001708, 0);
- nv_wr32(priv, 0x00170c, tmp);
-
- return nouveau_mc_init(&priv->base);
-}
-
-struct nouveau_oclass *
-nv44_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x44),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv44_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv04_mc_intr,
- .msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
deleted file mode 100644
index 165401c4045c..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv4c.c
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2014 Ilia Mirkin
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ilia Mirkin
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv4c_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x4c),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv44_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv04_mc_intr,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
deleted file mode 100644
index 9ca93e2718f7..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv50.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-const struct nouveau_mc_intr
-nv50_mc_intr[] = {
- { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */
- { 0x00000001, NVDEV_ENGINE_MPEG },
- { 0x00000100, NVDEV_ENGINE_FIFO },
- { 0x00001000, NVDEV_ENGINE_GR },
- { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84- */
- { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */
- { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */
- { 0x00100000, NVDEV_SUBDEV_TIMER },
- { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
- { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
- { 0x10000000, NVDEV_SUBDEV_BUS },
- { 0x80000000, NVDEV_ENGINE_SW },
- { 0x0002d101, NVDEV_SUBDEV_FB },
- {},
-};
-
-static void
-nv50_mc_msi_rearm(struct nouveau_mc *pmc)
-{
- struct nouveau_device *device = nv_device(pmc);
- pci_write_config_byte(device->pdev, 0x68, 0xff);
-}
-
-int
-nv50_mc_init(struct nouveau_object *object)
-{
- struct nv04_mc_priv *priv = (void *)object;
- nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */
- return nouveau_mc_init(&priv->base);
-}
-
-struct nouveau_oclass *
-nv50_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x50),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv50_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv50_mc_intr,
- .msi_rearm = nv50_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c
deleted file mode 100644
index 5f4541105e73..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv94.c
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nv94_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x94),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv50_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv50_mc_intr,
- .msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
deleted file mode 100644
index 3c76d9038f38..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nv98.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-static const struct nouveau_mc_intr
-nv98_mc_intr[] = {
- { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */
- { 0x00000001, NVDEV_ENGINE_PPP },
- { 0x00000100, NVDEV_ENGINE_FIFO },
- { 0x00001000, NVDEV_ENGINE_GR },
- { 0x00004000, NVDEV_ENGINE_CRYPT }, /* NV84:NVA3 */
- { 0x00008000, NVDEV_ENGINE_BSP },
- { 0x00020000, NVDEV_ENGINE_VP },
- { 0x00040000, NVDEV_SUBDEV_PWR }, /* NVA3:NVC0 */
- { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */
- { 0x00100000, NVDEV_SUBDEV_TIMER },
- { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
- { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
- { 0x00400000, NVDEV_ENGINE_COPY0 }, /* NVA3- */
- { 0x10000000, NVDEV_SUBDEV_BUS },
- { 0x80000000, NVDEV_ENGINE_SW },
- { 0x0042d101, NVDEV_SUBDEV_FB },
- {},
-};
-
-struct nouveau_oclass *
-nv98_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0x98),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv50_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nv98_mc_intr,
- .msi_rearm = nv40_mc_msi_rearm,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
deleted file mode 100644
index 15d41dc176ff..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc0.c
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-const struct nouveau_mc_intr
-nvc0_mc_intr[] = {
- { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */
- { 0x00000001, NVDEV_ENGINE_PPP },
- { 0x00000020, NVDEV_ENGINE_COPY0 },
- { 0x00000040, NVDEV_ENGINE_COPY1 },
- { 0x00000080, NVDEV_ENGINE_COPY2 },
- { 0x00000100, NVDEV_ENGINE_FIFO },
- { 0x00001000, NVDEV_ENGINE_GR },
- { 0x00002000, NVDEV_SUBDEV_FB },
- { 0x00008000, NVDEV_ENGINE_BSP },
- { 0x00040000, NVDEV_SUBDEV_THERM },
- { 0x00020000, NVDEV_ENGINE_VP },
- { 0x00100000, NVDEV_SUBDEV_TIMER },
- { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
- { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
- { 0x01000000, NVDEV_SUBDEV_PWR },
- { 0x02000000, NVDEV_SUBDEV_LTC },
- { 0x08000000, NVDEV_SUBDEV_FB },
- { 0x10000000, NVDEV_SUBDEV_BUS },
- { 0x40000000, NVDEV_SUBDEV_IBUS },
- { 0x80000000, NVDEV_ENGINE_SW },
- {},
-};
-
-static void
-nvc0_mc_msi_rearm(struct nouveau_mc *pmc)
-{
- struct nv04_mc_priv *priv = (void *)pmc;
- nv_wr32(priv, 0x088704, 0x00000000);
-}
-
-void
-nvc0_mc_unk260(struct nouveau_mc *pmc, u32 data)
-{
- nv_wr32(pmc, 0x000260, data);
-}
-
-struct nouveau_oclass *
-nvc0_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv50_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nvc0_mc_intr,
- .msi_rearm = nvc0_mc_msi_rearm,
- .unk260 = nvc0_mc_unk260,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c b/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c
deleted file mode 100644
index 68b5f61aadb5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/nvc3.c
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-struct nouveau_oclass *
-nvc3_mc_oclass = &(struct nouveau_mc_oclass) {
- .base.handle = NV_SUBDEV(MC, 0xc3),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_mc_ctor,
- .dtor = _nouveau_mc_dtor,
- .init = nv50_mc_init,
- .fini = _nouveau_mc_fini,
- },
- .intr = nvc0_mc_intr,
- .msi_rearm = nv40_mc_msi_rearm,
- .unk260 = nvc0_mc_unk260,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h
deleted file mode 100644
index 911e66392587..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mc/priv.h
+++ /dev/null
@@ -1,38 +0,0 @@
-#ifndef __NVKM_MC_PRIV_H__
-#define __NVKM_MC_PRIV_H__
-
-#include <subdev/mc.h>
-
-#define nouveau_mc_create(p,e,o,d) \
- nouveau_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_mc_destroy(p) ({ \
- struct nouveau_mc *pmc = (p); _nouveau_mc_dtor(nv_object(pmc)); \
-})
-#define nouveau_mc_init(p) ({ \
- struct nouveau_mc *pmc = (p); _nouveau_mc_init(nv_object(pmc)); \
-})
-#define nouveau_mc_fini(p,s) ({ \
- struct nouveau_mc *pmc = (p); _nouveau_mc_fini(nv_object(pmc), (s)); \
-})
-
-int nouveau_mc_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-void _nouveau_mc_dtor(struct nouveau_object *);
-int _nouveau_mc_init(struct nouveau_object *);
-int _nouveau_mc_fini(struct nouveau_object *, bool);
-
-struct nouveau_mc_intr {
- u32 stat;
- u32 unit;
-};
-
-struct nouveau_mc_oclass {
- struct nouveau_oclass base;
- const struct nouveau_mc_intr *intr;
- void (*msi_rearm)(struct nouveau_mc *);
- void (*unk260)(struct nouveau_mc *, u32);
-};
-
-void nvc0_mc_unk260(struct nouveau_mc *, u32);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
deleted file mode 100644
index 51fcf7960417..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/base.c
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/option.h>
-
-#include <subdev/i2c.h>
-#include <subdev/mxm.h>
-#include <subdev/bios.h>
-#include <subdev/bios/mxm.h>
-
-#include "mxms.h"
-
-static bool
-mxm_shadow_rom_fetch(struct nouveau_i2c_port *i2c, u8 addr,
- u8 offset, u8 size, u8 *data)
-{
- struct i2c_msg msgs[] = {
- { .addr = addr, .flags = 0, .len = 1, .buf = &offset },
- { .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, },
- };
-
- return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
-}
-
-static bool
-mxm_shadow_rom(struct nouveau_mxm *mxm, u8 version)
-{
- struct nouveau_bios *bios = nouveau_bios(mxm);
- struct nouveau_i2c *i2c = nouveau_i2c(mxm);
- struct nouveau_i2c_port *port = NULL;
- u8 i2cidx, mxms[6], addr, size;
-
- i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f;
- if (i2cidx < 0x0f)
- port = i2c->find(i2c, i2cidx);
- if (!port)
- return false;
-
- addr = 0x54;
- if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) {
- addr = 0x56;
- if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms))
- return false;
- }
-
- mxm->mxms = mxms;
- size = mxms_headerlen(mxm) + mxms_structlen(mxm);
- mxm->mxms = kmalloc(size, GFP_KERNEL);
-
- if (mxm->mxms &&
- mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms))
- return true;
-
- kfree(mxm->mxms);
- mxm->mxms = NULL;
- return false;
-}
-
-#if defined(CONFIG_ACPI)
-static bool
-mxm_shadow_dsm(struct nouveau_mxm *mxm, u8 version)
-{
- struct nouveau_device *device = nv_device(mxm);
- static char muid[] = {
- 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
- 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
- };
- u32 mxms_args[] = { 0x00000000 };
- union acpi_object argv4 = {
- .buffer.type = ACPI_TYPE_BUFFER,
- .buffer.length = sizeof(mxms_args),
- .buffer.pointer = (char *)mxms_args,
- };
- union acpi_object *obj;
- acpi_handle handle;
- int rev;
-
- handle = ACPI_HANDLE(nv_device_base(device));
- if (!handle)
- return false;
-
- /*
- * spec says this can be zero to mean "highest revision", but
- * of course there's at least one bios out there which fails
- * unless you pass in exactly the version it supports..
- */
- rev = (version & 0xf0) << 4 | (version & 0x0f);
- obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
- if (!obj) {
- nv_debug(mxm, "DSM MXMS failed\n");
- return false;
- }
-
- if (obj->type == ACPI_TYPE_BUFFER) {
- mxm->mxms = kmemdup(obj->buffer.pointer,
- obj->buffer.length, GFP_KERNEL);
- } else if (obj->type == ACPI_TYPE_INTEGER) {
- nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value);
- }
-
- ACPI_FREE(obj);
- return mxm->mxms != NULL;
-}
-#endif
-
-#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
-
-#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
-
-static u8
-wmi_wmmx_mxmi(struct nouveau_mxm *mxm, u8 version)
-{
- u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
- struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
- struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- acpi_status status;
-
- status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
- if (ACPI_FAILURE(status)) {
- nv_debug(mxm, "WMMX MXMI returned %d\n", status);
- return 0x00;
- }
-
- obj = retn.pointer;
- if (obj->type == ACPI_TYPE_INTEGER) {
- version = obj->integer.value;
- nv_debug(mxm, "WMMX MXMI version %d.%d\n",
- (version >> 4), version & 0x0f);
- } else {
- version = 0;
- nv_debug(mxm, "WMMX MXMI returned non-integer\n");
- }
-
- kfree(obj);
- return version;
-}
-
-static bool
-mxm_shadow_wmi(struct nouveau_mxm *mxm, u8 version)
-{
- u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 };
- struct acpi_buffer args = { sizeof(mxms_args), mxms_args };
- struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
- union acpi_object *obj;
- acpi_status status;
-
- if (!wmi_has_guid(WMI_WMMX_GUID)) {
- nv_debug(mxm, "WMMX GUID not found\n");
- return false;
- }
-
- mxms_args[1] = wmi_wmmx_mxmi(mxm, 0x00);
- if (!mxms_args[1])
- mxms_args[1] = wmi_wmmx_mxmi(mxm, version);
- if (!mxms_args[1])
- return false;
-
- status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
- if (ACPI_FAILURE(status)) {
- nv_debug(mxm, "WMMX MXMS returned %d\n", status);
- return false;
- }
-
- obj = retn.pointer;
- if (obj->type == ACPI_TYPE_BUFFER) {
- mxm->mxms = kmemdup(obj->buffer.pointer,
- obj->buffer.length, GFP_KERNEL);
- }
-
- kfree(obj);
- return mxm->mxms != NULL;
-}
-#endif
-
-static struct mxm_shadow_h {
- const char *name;
- bool (*exec)(struct nouveau_mxm *, u8 version);
-} _mxm_shadow[] = {
- { "ROM", mxm_shadow_rom },
-#if defined(CONFIG_ACPI)
- { "DSM", mxm_shadow_dsm },
-#endif
-#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
- { "WMI", mxm_shadow_wmi },
-#endif
- {}
-};
-
-static int
-mxm_shadow(struct nouveau_mxm *mxm, u8 version)
-{
- struct mxm_shadow_h *shadow = _mxm_shadow;
- do {
- nv_debug(mxm, "checking %s\n", shadow->name);
- if (shadow->exec(mxm, version)) {
- if (mxms_valid(mxm))
- return 0;
- kfree(mxm->mxms);
- mxm->mxms = NULL;
- }
- } while ((++shadow)->name);
- return -ENOENT;
-}
-
-int
-nouveau_mxm_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nouveau_bios *bios = nouveau_bios(device);
- struct nouveau_mxm *mxm;
- u8 ver, len;
- u16 data;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm",
- length, pobject);
- mxm = *pobject;
- if (ret)
- return ret;
-
- data = mxm_table(bios, &ver, &len);
- if (!data || !(ver = nv_ro08(bios, data))) {
- nv_debug(mxm, "no VBIOS data, nothing to do\n");
- return 0;
- }
-
- nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f);
-
- if (mxm_shadow(mxm, ver)) {
- nv_info(mxm, "failed to locate valid SIS\n");
-#if 0
- /* we should, perhaps, fall back to some kind of limited
- * mode here if the x86 vbios hasn't already done the
- * work for us (so we prevent loading with completely
- * whacked vbios tables).
- */
- return -EINVAL;
-#else
- return 0;
-#endif
- }
-
- nv_info(mxm, "MXMS Version %d.%d\n",
- mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff);
- mxms_foreach(mxm, 0, NULL, NULL);
-
- if (nouveau_boolopt(device->cfgopt, "NvMXMDCB", true))
- mxm->action |= MXM_SANITISE_DCB;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
deleted file mode 100644
index 4bde7f7f7b81..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.c
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/mxm.h>
-#include "mxms.h"
-
-#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
-#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
-
-static u8 *
-mxms_data(struct nouveau_mxm *mxm)
-{
- return mxm->mxms;
-
-}
-
-u16
-mxms_version(struct nouveau_mxm *mxm)
-{
- u8 *mxms = mxms_data(mxm);
- u16 version = (mxms[4] << 8) | mxms[5];
- switch (version ) {
- case 0x0200:
- case 0x0201:
- case 0x0300:
- return version;
- default:
- break;
- }
-
- nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]);
- return 0x0000;
-}
-
-u16
-mxms_headerlen(struct nouveau_mxm *mxm)
-{
- return 8;
-}
-
-u16
-mxms_structlen(struct nouveau_mxm *mxm)
-{
- return *(u16 *)&mxms_data(mxm)[6];
-}
-
-bool
-mxms_checksum(struct nouveau_mxm *mxm)
-{
- u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
- u8 *mxms = mxms_data(mxm), sum = 0;
- while (size--)
- sum += *mxms++;
- if (sum) {
- nv_debug(mxm, "checksum invalid\n");
- return false;
- }
- return true;
-}
-
-bool
-mxms_valid(struct nouveau_mxm *mxm)
-{
- u8 *mxms = mxms_data(mxm);
- if (*(u32 *)mxms != 0x5f4d584d) {
- nv_debug(mxm, "signature invalid\n");
- return false;
- }
-
- if (!mxms_version(mxm) || !mxms_checksum(mxm))
- return false;
-
- return true;
-}
-
-bool
-mxms_foreach(struct nouveau_mxm *mxm, u8 types,
- bool (*exec)(struct nouveau_mxm *, u8 *, void *), void *info)
-{
- u8 *mxms = mxms_data(mxm);
- u8 *desc = mxms + mxms_headerlen(mxm);
- u8 *fini = desc + mxms_structlen(mxm) - 1;
- while (desc < fini) {
- u8 type = desc[0] & 0x0f;
- u8 headerlen = 0;
- u8 recordlen = 0;
- u8 entries = 0;
-
- switch (type) {
- case 0: /* Output Device Structure */
- if (mxms_version(mxm) >= 0x0300)
- headerlen = 8;
- else
- headerlen = 6;
- break;
- case 1: /* System Cooling Capability Structure */
- case 2: /* Thermal Structure */
- case 3: /* Input Power Structure */
- headerlen = 4;
- break;
- case 4: /* GPIO Device Structure */
- headerlen = 4;
- recordlen = 2;
- entries = (ROM32(desc[0]) & 0x01f00000) >> 20;
- break;
- case 5: /* Vendor Specific Structure */
- headerlen = 8;
- break;
- case 6: /* Backlight Control Structure */
- if (mxms_version(mxm) >= 0x0300) {
- headerlen = 4;
- recordlen = 8;
- entries = (desc[1] & 0xf0) >> 4;
- } else {
- headerlen = 8;
- }
- break;
- case 7: /* Fan Control Structure */
- headerlen = 8;
- recordlen = 4;
- entries = desc[1] & 0x07;
- break;
- default:
- nv_debug(mxm, "unknown descriptor type %d\n", type);
- return false;
- }
-
- if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) {
- static const char * mxms_desc_name[] = {
- "ODS", "SCCS", "TS", "IPS",
- "GSD", "VSS", "BCS", "FCS",
- };
- u8 *dump = desc;
- int i, j;
-
- nv_debug(mxm, "%4s: ", mxms_desc_name[type]);
- for (j = headerlen - 1; j >= 0; j--)
- pr_cont("%02x", dump[j]);
- pr_cont("\n");
- dump += headerlen;
-
- for (i = 0; i < entries; i++, dump += recordlen) {
- nv_debug(mxm, " ");
- for (j = recordlen - 1; j >= 0; j--)
- pr_cont("%02x", dump[j]);
- pr_cont("\n");
- }
- }
-
- if (types & (1 << type)) {
- if (!exec(mxm, desc, info))
- return false;
- }
-
- desc += headerlen + (entries * recordlen);
- }
-
- return true;
-}
-
-void
-mxms_output_device(struct nouveau_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
-{
- u64 data = ROM32(pdata[0]);
- if (mxms_version(mxm) >= 0x0300)
- data |= (u64)ROM16(pdata[4]) << 32;
-
- desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
- desc->ddc_port = (data & 0x0000000000000f00ULL) >> 8;
- desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
- desc->dig_conn = (data & 0x0000000000780000ULL) >> 19;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h b/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
deleted file mode 100644
index 5e0be0c591ca..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/mxms.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef __NVMXM_MXMS_H__
-#define __NVMXM_MXMS_H__
-
-struct mxms_odev {
- u8 outp_type;
- u8 conn_type;
- u8 ddc_port;
- u8 dig_conn;
-};
-
-void mxms_output_device(struct nouveau_mxm *, u8 *, struct mxms_odev *);
-
-u16 mxms_version(struct nouveau_mxm *);
-u16 mxms_headerlen(struct nouveau_mxm *);
-u16 mxms_structlen(struct nouveau_mxm *);
-bool mxms_checksum(struct nouveau_mxm *);
-bool mxms_valid(struct nouveau_mxm *);
-
-bool mxms_foreach(struct nouveau_mxm *, u8,
- bool (*)(struct nouveau_mxm *, u8 *, void *), void *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
deleted file mode 100644
index fcaabe8456e3..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/mxm/nv50.c
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright 2011 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/mxm.h>
-#include <subdev/bios.h>
-#include <subdev/bios/conn.h>
-#include <subdev/bios/dcb.h>
-#include <subdev/bios/mxm.h>
-
-#include "mxms.h"
-
-struct nv50_mxm_priv {
- struct nouveau_mxm base;
-};
-
-struct context {
- u32 *outp;
- struct mxms_odev desc;
-};
-
-static bool
-mxm_match_tmds_partner(struct nouveau_mxm *mxm, u8 *data, void *info)
-{
- struct context *ctx = info;
- struct mxms_odev desc;
-
- mxms_output_device(mxm, data, &desc);
- if (desc.outp_type == 2 &&
- desc.dig_conn == ctx->desc.dig_conn)
- return false;
- return true;
-}
-
-static bool
-mxm_match_dcb(struct nouveau_mxm *mxm, u8 *data, void *info)
-{
- struct nouveau_bios *bios = nouveau_bios(mxm);
- struct context *ctx = info;
- u64 desc = *(u64 *)data;
-
- mxms_output_device(mxm, data, &ctx->desc);
-
- /* match dcb encoder type to mxm-ods device type */
- if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
- return true;
-
- /* digital output, have some extra stuff to match here, there's a
- * table in the vbios that provides a mapping from the mxm digital
- * connection enum values to SOR/link
- */
- if ((desc & 0x00000000000000f0) >= 0x20) {
- /* check against sor index */
- u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
- if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
- return true;
-
- /* check dcb entry has a compatible link field */
- link = (link & 0x30) >> 4;
- if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
- return true;
- }
-
- /* mark this descriptor accounted for by setting invalid device type,
- * except of course some manufactures don't follow specs properly and
- * we need to avoid killing off the TMDS function on DP connectors
- * if MXM-SIS is missing an entry for it.
- */
- data[0] &= ~0xf0;
- if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
- mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
- data[0] |= 0x20; /* modify descriptor to match TMDS now */
- } else {
- data[0] |= 0xf0;
- }
-
- return false;
-}
-
-static int
-mxm_dcb_sanitise_entry(struct nouveau_bios *bios, void *data, int idx, u16 pdcb)
-{
- struct nouveau_mxm *mxm = data;
- struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
- u8 type, i2cidx, link, ver, len;
- u8 *conn;
-
- /* look for an output device structure that matches this dcb entry.
- * if one isn't found, disable it.
- */
- if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
- nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n",
- idx, ctx.outp[0], ctx.outp[1]);
- ctx.outp[0] |= 0x0000000f;
- return 0;
- }
-
- /* modify the output's ddc/aux port, there's a pointer to a table
- * with the mapping from mxm ddc/aux port to dcb i2c_index in the
- * vbios mxm table
- */
- i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
- if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
- i2cidx = (i2cidx & 0x0f) << 4;
- else
- i2cidx = (i2cidx & 0xf0);
-
- if (i2cidx != 0xf0) {
- ctx.outp[0] &= ~0x000000f0;
- ctx.outp[0] |= i2cidx;
- }
-
- /* override dcb sorconf.link, based on what mxm data says */
- switch (ctx.desc.outp_type) {
- case 0x00: /* Analog CRT */
- case 0x01: /* Analog TV/HDTV */
- break;
- default:
- link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
- ctx.outp[1] &= ~0x00000030;
- ctx.outp[1] |= link;
- break;
- }
-
- /* we may need to fixup various other vbios tables based on what
- * the descriptor says the connector type should be.
- *
- * in a lot of cases, the vbios tables will claim DVI-I is possible,
- * and the mxm data says the connector is really HDMI. another
- * common example is DP->eDP.
- */
- conn = bios->data;
- conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
- type = conn[0];
- switch (ctx.desc.conn_type) {
- case 0x01: /* LVDS */
- ctx.outp[1] |= 0x00000004; /* use_power_scripts */
- /* XXX: modify default link width in LVDS table */
- break;
- case 0x02: /* HDMI */
- type = DCB_CONNECTOR_HDMI_1;
- break;
- case 0x03: /* DVI-D */
- type = DCB_CONNECTOR_DVI_D;
- break;
- case 0x0e: /* eDP, falls through to DPint */
- ctx.outp[1] |= 0x00010000;
- case 0x07: /* DP internal, wtf is this?? HP8670w */
- ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
- type = DCB_CONNECTOR_eDP;
- break;
- default:
- break;
- }
-
- if (mxms_version(mxm) >= 0x0300)
- conn[0] = type;
-
- return 0;
-}
-
-static bool
-mxm_show_unmatched(struct nouveau_mxm *mxm, u8 *data, void *info)
-{
- u64 desc = *(u64 *)data;
- if ((desc & 0xf0) != 0xf0)
- nv_info(mxm, "unmatched output device 0x%016llx\n", desc);
- return true;
-}
-
-static void
-mxm_dcb_sanitise(struct nouveau_mxm *mxm)
-{
- struct nouveau_bios *bios = nouveau_bios(mxm);
- u8 ver, hdr, cnt, len;
- u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
- if (dcb == 0x0000 || ver != 0x40) {
- nv_debug(mxm, "unsupported DCB version\n");
- return;
- }
-
- dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
- mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
-}
-
-static int
-nv50_mxm_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_mxm_priv *priv;
- int ret;
-
- ret = nouveau_mxm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- if (priv->base.action & MXM_SANITISE_DCB)
- mxm_dcb_sanitise(&priv->base);
- return 0;
-}
-
-struct nouveau_oclass
-nv50_mxm_oclass = {
- .handle = NV_SUBDEV(MXM, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_mxm_ctor,
- .dtor = _nouveau_mxm_dtor,
- .init = _nouveau_mxm_init,
- .fini = _nouveau_mxm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
deleted file mode 100644
index 0ab55f27ec45..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/base.c
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/timer.h>
-
-#include "priv.h"
-
-static void
-nouveau_pwr_pgob(struct nouveau_pwr *ppwr, bool enable)
-{
- const struct nvkm_pwr_impl *impl = (void *)nv_oclass(ppwr);
- if (impl->pgob)
- impl->pgob(ppwr, enable);
-}
-
-static int
-nouveau_pwr_send(struct nouveau_pwr *ppwr, u32 reply[2],
- u32 process, u32 message, u32 data0, u32 data1)
-{
- struct nouveau_subdev *subdev = nv_subdev(ppwr);
- u32 addr;
-
- /* wait for a free slot in the fifo */
- addr = nv_rd32(ppwr, 0x10a4a0);
- if (!nv_wait_ne(ppwr, 0x10a4b0, 0xffffffff, addr ^ 8))
- return -EBUSY;
-
- /* we currently only support a single process at a time waiting
- * on a synchronous reply, take the PPWR mutex and tell the
- * receive handler what we're waiting for
- */
- if (reply) {
- mutex_lock(&subdev->mutex);
- ppwr->recv.message = message;
- ppwr->recv.process = process;
- }
-
- /* acquire data segment access */
- do {
- nv_wr32(ppwr, 0x10a580, 0x00000001);
- } while (nv_rd32(ppwr, 0x10a580) != 0x00000001);
-
- /* write the packet */
- nv_wr32(ppwr, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
- ppwr->send.base));
- nv_wr32(ppwr, 0x10a1c4, process);
- nv_wr32(ppwr, 0x10a1c4, message);
- nv_wr32(ppwr, 0x10a1c4, data0);
- nv_wr32(ppwr, 0x10a1c4, data1);
- nv_wr32(ppwr, 0x10a4a0, (addr + 1) & 0x0f);
-
- /* release data segment access */
- nv_wr32(ppwr, 0x10a580, 0x00000000);
-
- /* wait for reply, if requested */
- if (reply) {
- wait_event(ppwr->recv.wait, (ppwr->recv.process == 0));
- reply[0] = ppwr->recv.data[0];
- reply[1] = ppwr->recv.data[1];
- mutex_unlock(&subdev->mutex);
- }
-
- return 0;
-}
-
-static void
-nouveau_pwr_recv(struct work_struct *work)
-{
- struct nouveau_pwr *ppwr =
- container_of(work, struct nouveau_pwr, recv.work);
- u32 process, message, data0, data1;
-
- /* nothing to do if GET == PUT */
- u32 addr = nv_rd32(ppwr, 0x10a4cc);
- if (addr == nv_rd32(ppwr, 0x10a4c8))
- return;
-
- /* acquire data segment access */
- do {
- nv_wr32(ppwr, 0x10a580, 0x00000002);
- } while (nv_rd32(ppwr, 0x10a580) != 0x00000002);
-
- /* read the packet */
- nv_wr32(ppwr, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
- ppwr->recv.base));
- process = nv_rd32(ppwr, 0x10a1c4);
- message = nv_rd32(ppwr, 0x10a1c4);
- data0 = nv_rd32(ppwr, 0x10a1c4);
- data1 = nv_rd32(ppwr, 0x10a1c4);
- nv_wr32(ppwr, 0x10a4cc, (addr + 1) & 0x0f);
-
- /* release data segment access */
- nv_wr32(ppwr, 0x10a580, 0x00000000);
-
- /* wake process if it's waiting on a synchronous reply */
- if (ppwr->recv.process) {
- if (process == ppwr->recv.process &&
- message == ppwr->recv.message) {
- ppwr->recv.data[0] = data0;
- ppwr->recv.data[1] = data1;
- ppwr->recv.process = 0;
- wake_up(&ppwr->recv.wait);
- return;
- }
- }
-
- /* right now there's no other expected responses from the engine,
- * so assume that any unexpected message is an error.
- */
- nv_warn(ppwr, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n",
- (char)((process & 0x000000ff) >> 0),
- (char)((process & 0x0000ff00) >> 8),
- (char)((process & 0x00ff0000) >> 16),
- (char)((process & 0xff000000) >> 24),
- process, message, data0, data1);
-}
-
-static void
-nouveau_pwr_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_pwr *ppwr = (void *)subdev;
- u32 disp = nv_rd32(ppwr, 0x10a01c);
- u32 intr = nv_rd32(ppwr, 0x10a008) & disp & ~(disp >> 16);
-
- if (intr & 0x00000020) {
- u32 stat = nv_rd32(ppwr, 0x10a16c);
- if (stat & 0x80000000) {
- nv_error(ppwr, "UAS fault at 0x%06x addr 0x%08x\n",
- stat & 0x00ffffff, nv_rd32(ppwr, 0x10a168));
- nv_wr32(ppwr, 0x10a16c, 0x00000000);
- intr &= ~0x00000020;
- }
- }
-
- if (intr & 0x00000040) {
- schedule_work(&ppwr->recv.work);
- nv_wr32(ppwr, 0x10a004, 0x00000040);
- intr &= ~0x00000040;
- }
-
- if (intr & 0x00000080) {
- nv_info(ppwr, "wr32 0x%06x 0x%08x\n", nv_rd32(ppwr, 0x10a7a0),
- nv_rd32(ppwr, 0x10a7a4));
- nv_wr32(ppwr, 0x10a004, 0x00000080);
- intr &= ~0x00000080;
- }
-
- if (intr) {
- nv_error(ppwr, "intr 0x%08x\n", intr);
- nv_wr32(ppwr, 0x10a004, intr);
- }
-}
-
-int
-_nouveau_pwr_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_pwr *ppwr = (void *)object;
-
- nv_wr32(ppwr, 0x10a014, 0x00000060);
- flush_work(&ppwr->recv.work);
-
- return nouveau_subdev_fini(&ppwr->base, suspend);
-}
-
-int
-_nouveau_pwr_init(struct nouveau_object *object)
-{
- const struct nvkm_pwr_impl *impl = (void *)object->oclass;
- struct nouveau_pwr *ppwr = (void *)object;
- int ret, i;
-
- ret = nouveau_subdev_init(&ppwr->base);
- if (ret)
- return ret;
-
- nv_subdev(ppwr)->intr = nouveau_pwr_intr;
- ppwr->message = nouveau_pwr_send;
- ppwr->pgob = nouveau_pwr_pgob;
-
- /* prevent previous ucode from running, wait for idle, reset */
- nv_wr32(ppwr, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */
- nv_wait(ppwr, 0x10a04c, 0xffffffff, 0x00000000);
- nv_mask(ppwr, 0x000200, 0x00002000, 0x00000000);
- nv_mask(ppwr, 0x000200, 0x00002000, 0x00002000);
- nv_rd32(ppwr, 0x000200);
- nv_wait(ppwr, 0x10a10c, 0x00000006, 0x00000000);
-
- /* upload data segment */
- nv_wr32(ppwr, 0x10a1c0, 0x01000000);
- for (i = 0; i < impl->data.size / 4; i++)
- nv_wr32(ppwr, 0x10a1c4, impl->data.data[i]);
-
- /* upload code segment */
- nv_wr32(ppwr, 0x10a180, 0x01000000);
- for (i = 0; i < impl->code.size / 4; i++) {
- if ((i & 0x3f) == 0)
- nv_wr32(ppwr, 0x10a188, i >> 6);
- nv_wr32(ppwr, 0x10a184, impl->code.data[i]);
- }
-
- /* start it running */
- nv_wr32(ppwr, 0x10a10c, 0x00000000);
- nv_wr32(ppwr, 0x10a104, 0x00000000);
- nv_wr32(ppwr, 0x10a100, 0x00000002);
-
- /* wait for valid host->pwr ring configuration */
- if (!nv_wait_ne(ppwr, 0x10a4d0, 0xffffffff, 0x00000000))
- return -EBUSY;
- ppwr->send.base = nv_rd32(ppwr, 0x10a4d0) & 0x0000ffff;
- ppwr->send.size = nv_rd32(ppwr, 0x10a4d0) >> 16;
-
- /* wait for valid pwr->host ring configuration */
- if (!nv_wait_ne(ppwr, 0x10a4dc, 0xffffffff, 0x00000000))
- return -EBUSY;
- ppwr->recv.base = nv_rd32(ppwr, 0x10a4dc) & 0x0000ffff;
- ppwr->recv.size = nv_rd32(ppwr, 0x10a4dc) >> 16;
-
- nv_wr32(ppwr, 0x10a010, 0x000000e0);
- return 0;
-}
-
-int
-nouveau_pwr_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- struct nouveau_pwr *ppwr;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PPWR",
- "pwr", length, pobject);
- ppwr = *pobject;
- if (ret)
- return ret;
-
- INIT_WORK(&ppwr->recv.work, nouveau_pwr_recv);
- init_waitqueue_head(&ppwr->recv.wait);
- return 0;
-}
-
-int
-_nouveau_pwr_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_pwr *ppwr;
- int ret = nouveau_pwr_create(parent, engine, oclass, &ppwr);
- *pobject = nv_object(ppwr);
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc
deleted file mode 100644
index b439519ec866..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GK208
-#define HW_TICKS_PER_US 324
-
-#define NVKM_FALCON_PC24
-#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nv108_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nv108_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
deleted file mode 100644
index 713e11e2953d..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nv108.fuc.h
+++ /dev/null
@@ -1,1731 +0,0 @@
-uint32_t nv108_pwr_data[] = {
-/* 0x0000: proc_kern */
- 0x52544e49,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: proc_list_head */
- 0x54534f48,
- 0x00000453,
- 0x00000404,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x584d454d,
- 0x0000062d,
- 0x0000061f,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x46524550,
- 0x00000631,
- 0x0000062f,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x5f433249,
- 0x00000a35,
- 0x000008dc,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x54534554,
- 0x00000a56,
- 0x00000a37,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x454c4449,
- 0x00000a61,
- 0x00000a5f,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
- 0x00000000,
-/* 0x026c: time_next */
- 0x00000000,
-/* 0x0270: fifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x02f0: rfifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0370: memx_func_head */
- 0x00000001,
- 0x00000000,
- 0x00000483,
-/* 0x037c: memx_func_next */
- 0x00000002,
- 0x00000000,
- 0x00000500,
- 0x00000003,
- 0x00000002,
- 0x00000580,
- 0x00040004,
- 0x00000000,
- 0x0000059d,
- 0x00010005,
- 0x00000000,
- 0x000005b7,
- 0x00010006,
- 0x00000000,
- 0x0000057b,
- 0x00000007,
- 0x00000000,
- 0x000005c3,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
- 0x00000000,
-/* 0x03c8: memx_ts_end */
- 0x00000000,
-/* 0x03cc: memx_data_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
- 0x00000400,
- 0x00000800,
- 0x00001000,
- 0x00002000,
- 0x00004000,
- 0x00008000,
- 0x00010000,
- 0x00020000,
- 0x00040000,
- 0x00080000,
-/* 0x0cf4: i2c_sda_map */
- 0x00100000,
- 0x00200000,
- 0x00400000,
- 0x00800000,
- 0x01000000,
- 0x02000000,
- 0x04000000,
- 0x08000000,
- 0x10000000,
- 0x20000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nv108_pwr_code[] = {
- 0x031c0ef5,
-/* 0x0004: rd32 */
- 0xf607a040,
- 0x04bd000e,
- 0xd3f0010d,
- 0x07ac4001,
- 0xbd000df6,
-/* 0x0019: rd32_wait */
- 0x07ac4d04,
- 0xf100ddcf,
- 0xf47000d4,
- 0xa44df61b,
- 0x00ddcf07,
-/* 0x002e: wr32 */
- 0xa04000f8,
- 0x000ef607,
- 0xa44004bd,
- 0x000df607,
- 0x020d04bd,
- 0xf0f0d5f0,
- 0xac4001d3,
- 0x000df607,
-/* 0x004e: wr32_wait */
- 0xac4d04bd,
- 0x00ddcf07,
- 0x7000d4f1,
- 0xf8f61bf4,
-/* 0x005d: nsec */
- 0xf990f900,
- 0xcf2c0880,
-/* 0x0066: nsec_loop */
- 0x2c090088,
- 0xbb0099cf,
- 0x9ea60298,
- 0xfcf61ef4,
- 0xf890fc80,
-/* 0x0079: wait */
- 0xf990f900,
- 0xcf2c0880,
-/* 0x0082: wait_loop */
- 0xeeb20088,
- 0x0000047e,
- 0xadfddab2,
- 0xf4aca604,
- 0x2c09100b,
- 0xbb0099cf,
- 0x9ba60298,
-/* 0x009f: wait_done */
- 0xfce61ef4,
- 0xf890fc80,
-/* 0x00a5: intr_watchdog */
- 0x03e99800,
- 0xf40096b0,
- 0x0a98280b,
- 0x029abb9a,
- 0x0d0e1cf4,
- 0x02617e01,
- 0xf494bd00,
-/* 0x00c2: intr_watchdog_next_time */
- 0x0a98140e,
- 0x00a6b09b,
- 0xa6080bf4,
- 0x061cf49a,
-/* 0x00d0: intr_watchdog_next_time_set */
-/* 0x00d3: intr_watchdog_next_proc */
- 0xb59b09b5,
- 0xe0b603e9,
- 0x68e6b158,
- 0xc81bf402,
-/* 0x00e2: intr */
- 0x00f900f8,
- 0x80f904bd,
- 0xa0f990f9,
- 0xc0f9b0f9,
- 0xe0f9d0f9,
- 0x000ff0f9,
- 0xf90188fe,
- 0x04504880,
- 0xb60088cf,
- 0x50400180,
- 0x0008f604,
- 0x080804bd,
- 0xc40088cf,
- 0x0bf40289,
- 0x9b00b51f,
- 0xa57e580e,
- 0x09980000,
- 0x0096b09b,
- 0x000d0bf4,
- 0x0009f634,
- 0x09b504bd,
-/* 0x0135: intr_skip_watchdog */
- 0x0089e49a,
- 0x360bf408,
- 0xcf068849,
- 0x9ac40099,
- 0x220bf402,
- 0xcf04c04c,
- 0xc0f900cc,
- 0xf14f484e,
- 0x0d5453e3,
- 0x02c27e00,
- 0x40c0fc00,
- 0x0cf604c0,
-/* 0x0167: intr_subintr_skip_fifo */
- 0x4004bd00,
- 0x09f60688,
-/* 0x016f: intr_skip_subintr */
- 0xc404bd00,
- 0x0bf42089,
- 0xbfa4f107,
-/* 0x0179: intr_skip_pause */
- 0x4089c4ff,
- 0xf1070bf4,
-/* 0x0183: intr_skip_user0 */
- 0x00ffbfa4,
- 0x0008f604,
- 0x80fc04bd,
- 0xfc0088fe,
- 0xfce0fcf0,
- 0xfcc0fcd0,
- 0xfca0fcb0,
- 0xfc80fc90,
- 0x0032f400,
-/* 0x01a6: ticks_from_ns */
- 0xc0f901f8,
- 0xd7f1b0f9,
- 0xd3f00144,
- 0x7721f500,
- 0xe8ccec03,
- 0x00b4b003,
- 0xec120bf4,
- 0xf103e8ee,
- 0xf00144d7,
- 0x21f500d3,
-/* 0x01ce: ticks_from_ns_quit */
- 0xceb20377,
- 0xc0fcb0fc,
-/* 0x01d6: ticks_from_us */
- 0xc0f900f8,
- 0xd7f1b0f9,
- 0xd3f00144,
- 0x7721f500,
- 0xb0ceb203,
- 0x0bf400b4,
-/* 0x01ef: ticks_from_us_quit */
- 0xfce4bd05,
- 0xf8c0fcb0,
-/* 0x01f5: ticks_to_us */
- 0x44d7f100,
- 0x00d3f001,
- 0xf8ecedff,
-/* 0x0201: timer */
- 0xf990f900,
- 0x1032f480,
- 0xb003f898,
- 0x1cf40086,
- 0x0084bd4a,
- 0x0008f638,
- 0x340804bd,
- 0x980088cf,
- 0x98bb9a09,
- 0x00e9bb02,
- 0x0803feb5,
- 0x0088cf08,
- 0xf40284f0,
- 0x34081c1b,
- 0xa60088cf,
- 0x080bf4e0,
- 0x1cf4e8a6,
-/* 0x0245: timer_reset */
- 0xf634000d,
- 0x04bd000e,
-/* 0x024f: timer_enable */
- 0x089a0eb5,
- 0xf6380001,
- 0x04bd0008,
-/* 0x0258: timer_done */
- 0xfc1031f4,
- 0xf890fc80,
-/* 0x0261: send_proc */
- 0xf980f900,
- 0x05e89890,
- 0xf004e998,
- 0x89a60486,
- 0xc42a0bf4,
- 0x88940398,
- 0x1880b604,
- 0x98008ebb,
- 0x8ab500fa,
- 0x018db500,
- 0xb5028cb5,
- 0x90b6038b,
- 0x0794f001,
- 0xf404e9b5,
-/* 0x029a: send_done */
- 0x90fc0231,
- 0x00f880fc,
-/* 0x02a0: find */
- 0x580880f9,
-/* 0x02a7: find_loop */
- 0x980131f4,
- 0xaea6008a,
- 0xb6100bf4,
- 0x86b15880,
- 0x1bf40268,
- 0x0132f4f1,
-/* 0x02bc: find_done */
- 0x80fc8eb2,
-/* 0x02c2: send */
- 0xa07e00f8,
- 0x01f40002,
-/* 0x02cb: recv */
- 0xf900f89b,
- 0x9880f990,
- 0xe99805e8,
- 0x0132f404,
- 0x0bf489a6,
- 0x0389c43c,
- 0xf00180b6,
- 0xe8b50784,
- 0x02ea9805,
- 0x8ffef0f9,
- 0xb2f0f901,
- 0x049994ef,
- 0xb600e9bb,
- 0xeb9818e0,
- 0x02ec9803,
- 0x9801ed98,
- 0xa5f900ee,
- 0xf8fef0fc,
- 0x0131f400,
-/* 0x0316: recv_done */
- 0x80fcf0fc,
- 0x00f890fc,
-/* 0x031c: init */
- 0xcf010841,
- 0x11e70011,
- 0x14b60109,
- 0x0014fe08,
- 0xf000e041,
- 0x1c000013,
- 0xbd0001f6,
- 0x00ff0104,
- 0x0001f614,
- 0x020104bd,
- 0x080015f1,
- 0x01f61000,
- 0x4104bd00,
- 0x13f000e2,
- 0x0010fe00,
- 0x011031f4,
- 0xf6380001,
- 0x04bd0001,
-/* 0x0366: init_proc */
- 0xf198580f,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x0377: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb2301dff,
- 0xff34f134,
- 0x1034b6ff,
- 0xbb1045b6,
- 0xb4bb00c3,
- 0x30e2ff01,
- 0x34f134b2,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0x12ff01b4,
- 0x00b3bb30,
- 0x30fc40fc,
- 0x10fc20fc,
-/* 0x03c6: host_send */
- 0xb04100f8,
- 0x0011cf04,
- 0xcf04a042,
- 0x12a60022,
- 0xc42e0bf4,
- 0xee94071e,
- 0x70e0b704,
- 0x03eb9802,
- 0x9802ec98,
- 0xee9801ed,
- 0x02c27e00,
- 0x0110b600,
- 0x400f1ec4,
- 0x0ef604b0,
- 0xf404bd00,
-/* 0x0402: host_send_done */
- 0x00f8c70e,
-/* 0x0404: host_recv */
- 0xf14e4941,
- 0xa6525413,
- 0xb90bf4e1,
-/* 0x0410: host_recv_wait */
- 0xcf04cc41,
- 0xc8420011,
- 0x0022cf04,
- 0xa60816f0,
- 0xef0bf412,
- 0xb60723c4,
- 0x30b70434,
- 0x3bb502f0,
- 0x023cb503,
- 0xb5013db5,
- 0x20b6003e,
- 0x0f24f001,
- 0xf604c840,
- 0x04bd0002,
- 0x00004002,
- 0xbd0002f6,
-/* 0x0453: host_init */
- 0x4100f804,
- 0x14b60080,
- 0x7015f110,
- 0x04d04002,
- 0xbd0001f6,
- 0x00804104,
- 0xf11014b6,
- 0x4002f015,
- 0x01f604dc,
- 0x0104bd00,
- 0x04c44001,
- 0xbd0001f6,
-/* 0x0483: memx_func_enter */
- 0xf100f804,
- 0xf1162067,
- 0xf1f55d77,
- 0xb2ffff73,
- 0x00047e6e,
- 0xfdd8b200,
- 0x60f90487,
- 0xd0fc80f9,
- 0x2e7ee0fc,
- 0x77f10000,
- 0x73f1fffe,
- 0x6eb2ffff,
- 0x0000047e,
- 0x87fdd8b2,
- 0xf960f904,
- 0xfcd0fc80,
- 0x002e7ee0,
- 0xf067f100,
- 0x7e6eb226,
- 0xb2000004,
- 0x0487fdd8,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0x00002e7e,
- 0xe0400406,
- 0x0006f607,
-/* 0x04ea: memx_func_enter_wait */
- 0xc04604bd,
- 0x0066cf07,
- 0xf40464f0,
- 0x2c06f70b,
- 0xb50066cf,
- 0x00f8f106,
-/* 0x0500: memx_func_leave */
- 0x66cf2c06,
- 0xf206b500,
- 0xe4400406,
- 0x0006f607,
-/* 0x0512: memx_func_leave_wait */
- 0xc04604bd,
- 0x0066cf07,
- 0xf40464f0,
- 0x67f1f71b,
- 0x77f126f0,
- 0x73f00001,
- 0x7e6eb200,
- 0xb2000004,
- 0x0587fdd8,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0x00002e7e,
- 0x162067f1,
- 0x047e6eb2,
- 0xd8b20000,
- 0xf90587fd,
- 0xfc80f960,
- 0x7ee0fcd0,
- 0xf100002e,
- 0xf00aa277,
- 0x6eb20073,
- 0x0000047e,
- 0x87fdd8b2,
- 0xf960f905,
- 0xfcd0fc80,
- 0x002e7ee0,
-/* 0x057b: memx_func_wait_vblank */
- 0xb600f800,
- 0x00f80410,
-/* 0x0580: memx_func_wr32 */
- 0x98001698,
- 0x10b60115,
- 0xf960f908,
- 0xfcd0fc50,
- 0x002e7ee0,
- 0x0242b600,
- 0xf8e81bf4,
-/* 0x059d: memx_func_wait */
- 0xcf2c0800,
- 0x1e980088,
- 0x011d9800,
- 0x98021c98,
- 0x10b6031b,
- 0x00797e10,
-/* 0x05b7: memx_func_delay */
- 0x9800f800,
- 0x10b6001e,
- 0x005d7e04,
-/* 0x05c3: memx_func_train */
- 0xf800f800,
-/* 0x05c5: memx_exec */
- 0xf9e0f900,
- 0xb2c1b2d0,
-/* 0x05cd: memx_exec_next */
- 0x001398b2,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12a655f9,
- 0x98e51ef4,
- 0x0c98f10b,
- 0x02cbbbf2,
- 0xcf07c44b,
- 0xd0fc00bb,
- 0xc27ee0fc,
- 0x00f80002,
-/* 0x0604: memx_info */
- 0xf401c670,
-/* 0x060a: memx_info_data */
- 0xcc4c0c0b,
- 0x08004b03,
-/* 0x0613: memx_info_train */
- 0x4c090ef4,
- 0x004b0bcc,
-/* 0x0619: memx_info_send */
- 0x02c27e01,
-/* 0x061f: memx_recv */
- 0xb000f800,
- 0x0bf401d6,
- 0x00d6b0a3,
- 0xf8dc0bf4,
-/* 0x062d: memx_init */
-/* 0x062f: perf_recv */
- 0xf800f800,
-/* 0x0631: perf_init */
-/* 0x0633: i2c_drive_scl */
- 0xb000f800,
- 0x0bf40036,
- 0x07e0400d,
- 0xbd0001f6,
-/* 0x0643: i2c_drive_scl_lo */
- 0x4000f804,
- 0x01f607e4,
- 0xf804bd00,
-/* 0x064d: i2c_drive_sda */
- 0x0036b000,
- 0x400d0bf4,
- 0x02f607e0,
- 0xf804bd00,
-/* 0x065d: i2c_drive_sda_lo */
- 0x07e44000,
- 0xbd0002f6,
-/* 0x0667: i2c_sense_scl */
- 0xf400f804,
- 0xc4430132,
- 0x0033cf07,
- 0xf40431fd,
- 0x31f4060b,
-/* 0x0679: i2c_sense_scl_done */
-/* 0x067b: i2c_sense_sda */
- 0xf400f801,
- 0xc4430132,
- 0x0033cf07,
- 0xf40432fd,
- 0x31f4060b,
-/* 0x068d: i2c_sense_sda_done */
-/* 0x068f: i2c_raise_scl */
- 0xf900f801,
- 0x08984440,
- 0x337e0103,
-/* 0x069a: i2c_raise_scl_wait */
- 0xe84e0006,
- 0x005d7e03,
- 0x06677e00,
- 0x0901f400,
- 0xf40142b6,
-/* 0x06ae: i2c_raise_scl_done */
- 0x40fcef1b,
-/* 0x06b2: i2c_start */
- 0x677e00f8,
- 0x11f40006,
- 0x067b7e0d,
- 0x0611f400,
-/* 0x06c3: i2c_start_rep */
- 0x032e0ef4,
- 0x06337e00,
- 0x7e010300,
- 0xbb00064d,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x00068f7e,
- 0xf40464b6,
-/* 0x06ee: i2c_start_send */
- 0x00031d11,
- 0x00064d7e,
- 0x7e13884e,
- 0x0300005d,
- 0x06337e00,
- 0x13884e00,
- 0x00005d7e,
-/* 0x0708: i2c_start_out */
-/* 0x070a: i2c_stop */
- 0x000300f8,
- 0x0006337e,
- 0x4d7e0003,
- 0xe84e0006,
- 0x005d7e03,
- 0x7e010300,
- 0x4e000633,
- 0x5d7e1388,
- 0x01030000,
- 0x00064d7e,
- 0x7e13884e,
- 0xf800005d,
-/* 0x0739: i2c_bitw */
- 0x064d7e00,
- 0x03e84e00,
- 0x00005d7e,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x068f7e50,
- 0x0464b600,
- 0x4e1711f4,
- 0x5d7e1388,
- 0x00030000,
- 0x0006337e,
- 0x7e13884e,
-/* 0x0777: i2c_bitw_out */
- 0xf800005d,
-/* 0x0779: i2c_bitr */
- 0x7e010300,
- 0x4e00064d,
- 0x5d7e03e8,
- 0x76bb0000,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0x7e50fc04,
- 0xb600068f,
- 0x11f40464,
- 0x067b7e1a,
- 0x7e000300,
- 0x4e000633,
- 0x5d7e1388,
- 0x3cf00000,
- 0x0131f401,
-/* 0x07bc: i2c_bitr_done */
-/* 0x07be: i2c_get_byte */
- 0x000500f8,
-/* 0x07c2: i2c_get_byte_next */
- 0x54b60804,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x797e50fc,
- 0x64b60007,
- 0x2a11f404,
- 0xb60553fd,
- 0x1bf40142,
- 0xbb0103d8,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x0007397e,
-/* 0x080b: i2c_get_byte_done */
- 0xf80464b6,
-/* 0x080d: i2c_put_byte */
-/* 0x080f: i2c_put_byte_next */
- 0xb6080400,
- 0x54ff0142,
- 0x0076bb38,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x397e50fc,
- 0x64b60007,
- 0x3411f404,
- 0xf40046b0,
- 0x76bbd81b,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0x7e50fc04,
- 0xb6000779,
- 0x11f40464,
- 0x0076bb0f,
- 0xf40136b0,
- 0x32f4061b,
-/* 0x0865: i2c_put_byte_done */
-/* 0x0867: i2c_addr */
- 0xbb00f801,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x0006b27e,
- 0xf40464b6,
- 0xc3e72911,
- 0x34b6012e,
- 0x0553fd01,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x080d7e50,
- 0x0464b600,
-/* 0x08ac: i2c_addr_done */
-/* 0x08ae: i2c_acquire_addr */
- 0xcec700f8,
- 0x05e4b6f8,
- 0xd014e0b7,
-/* 0x08ba: i2c_acquire */
- 0xae7e00f8,
- 0x047e0008,
- 0xd9f00000,
- 0x002e7e03,
-/* 0x08cb: i2c_release */
- 0x7e00f800,
- 0x7e0008ae,
- 0xf0000004,
- 0x2e7e03da,
- 0x00f80000,
-/* 0x08dc: i2c_recv */
- 0xc70132f4,
- 0x14b6f8c1,
- 0x2816b002,
- 0x01371ff5,
- 0x0cf413b8,
- 0x00329800,
- 0x0ccc13b8,
- 0x00319800,
- 0xf90231f4,
- 0xf9e0f9d0,
- 0x0067f1d0,
- 0x0063f100,
- 0x01679210,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x08ba7e50,
- 0x0464b600,
- 0xd6b0d0fc,
- 0xb01bf500,
- 0xbb000500,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x0008677e,
- 0xf50464b6,
- 0xc700cc11,
- 0x76bbe0c5,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0x7e50fc04,
- 0xb600080d,
- 0x11f50464,
- 0x010500a9,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x08677e50,
- 0x0464b600,
- 0x008711f5,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x07be7e50,
- 0x0464b600,
- 0xcb6711f4,
- 0x76bbe05b,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0x7e50fc04,
- 0xb600070a,
- 0x5bb20464,
- 0x0ef474bd,
-/* 0x09e1: i2c_recv_not_rd08 */
- 0x01d6b041,
- 0x053b1bf4,
- 0x08677e00,
- 0x3211f400,
- 0x7ee0c5c7,
- 0xf400080d,
- 0x00052811,
- 0x0008677e,
- 0xc71f11f4,
- 0x0d7ee0b5,
- 0x11f40008,
- 0x070a7e15,
- 0xc774bd00,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0a1f: i2c_recv_not_wr08 */
-/* 0x0a1f: i2c_recv_done */
- 0xc7030ef4,
- 0xcb7ef8ce,
- 0xe0fc0008,
- 0x12f4d0fc,
- 0x7e7cb209,
-/* 0x0a33: i2c_recv_exit */
- 0xf80002c2,
-/* 0x0a35: i2c_init */
-/* 0x0a37: test_recv */
- 0x4100f800,
- 0x11cf0458,
- 0x0110b600,
- 0xf6045840,
- 0x04bd0001,
- 0xd900e7f1,
- 0x134fe3f1,
- 0x0002017e,
-/* 0x0a56: test_init */
- 0x004e00f8,
- 0x02017e08,
-/* 0x0a5f: idle_recv */
- 0xf800f800,
-/* 0x0a61: idle */
- 0x0031f400,
- 0xcf045441,
- 0x10b60011,
- 0x04544001,
- 0xbd0001f6,
-/* 0x0a75: idle_loop */
- 0xf4580104,
-/* 0x0a7a: idle_proc */
-/* 0x0a7a: idle_proc_exec */
- 0x10f90232,
- 0xcb7e1eb2,
- 0x10fc0002,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0a8d: idle_proc_next */
- 0x5810b6f0,
- 0x1bf41fa6,
- 0xe002f4e8,
- 0xf40028f4,
- 0x0000c60e,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc
deleted file mode 100644
index daa06c1c655e..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GT215
-#define HW_TICKS_PER_US 203 // should be 202.5
-
-//#define NVKM_FALCON_PC24
-//#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nva3_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nva3_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
deleted file mode 100644
index d1f9b6cb66d7..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nva3.fuc.h
+++ /dev/null
@@ -1,1868 +0,0 @@
-uint32_t nva3_pwr_data[] = {
-/* 0x0000: proc_kern */
- 0x52544e49,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: proc_list_head */
- 0x54534f48,
- 0x00000512,
- 0x000004af,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x584d454d,
- 0x00000842,
- 0x00000834,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x46524550,
- 0x00000846,
- 0x00000844,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x5f433249,
- 0x00000c76,
- 0x00000b19,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x54534554,
- 0x00000c9f,
- 0x00000c78,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x454c4449,
- 0x00000cab,
- 0x00000ca9,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
- 0x00000000,
-/* 0x026c: time_next */
- 0x00000000,
-/* 0x0270: fifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x02f0: rfifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0370: memx_func_head */
- 0x00000001,
- 0x00000000,
- 0x00000551,
-/* 0x037c: memx_func_next */
- 0x00000002,
- 0x00000000,
- 0x000005a8,
- 0x00000003,
- 0x00000002,
- 0x0000063a,
- 0x00040004,
- 0x00000000,
- 0x00000656,
- 0x00010005,
- 0x00000000,
- 0x00000673,
- 0x00010006,
- 0x00000000,
- 0x000005f8,
- 0x00000007,
- 0x00000000,
- 0x0000067e,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
- 0x00000000,
-/* 0x03c8: memx_ts_end */
- 0x00000000,
-/* 0x03cc: memx_data_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
- 0x00001000,
- 0x00004000,
- 0x00010000,
- 0x00000100,
- 0x00040000,
- 0x00100000,
- 0x00400000,
- 0x01000000,
- 0x04000000,
- 0x10000000,
-/* 0x0cf4: i2c_sda_map */
- 0x00002000,
- 0x00008000,
- 0x00020000,
- 0x00000200,
- 0x00080000,
- 0x00200000,
- 0x00800000,
- 0x02000000,
- 0x08000000,
- 0x20000000,
-/* 0x0d1c: i2c_ctrl */
- 0x0000e138,
- 0x0000e150,
- 0x0000e168,
- 0x0000e180,
- 0x0000e254,
- 0x0000e274,
- 0x0000e764,
- 0x0000e780,
- 0x0000e79c,
- 0x0000e7b8,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nva3_pwr_code[] = {
- 0x039e0ef5,
-/* 0x0004: rd32 */
- 0x07a007f1,
- 0xd00604b6,
- 0x04bd000e,
- 0xf001d7f0,
- 0x07f101d3,
- 0x04b607ac,
- 0x000dd006,
-/* 0x0022: rd32_wait */
- 0xd7f104bd,
- 0xd4b607ac,
- 0x00ddcf06,
- 0x7000d4f1,
- 0xf1f21bf4,
- 0xb607a4d7,
- 0xddcf06d4,
-/* 0x003f: wr32 */
- 0xf100f800,
- 0xb607a007,
- 0x0ed00604,
- 0xf104bd00,
- 0xb607a407,
- 0x0dd00604,
- 0xf004bd00,
- 0xd5f002d7,
- 0x01d3f0f0,
- 0x07ac07f1,
- 0xd00604b6,
- 0x04bd000d,
-/* 0x006c: wr32_wait */
- 0x07acd7f1,
- 0xcf06d4b6,
- 0xd4f100dd,
- 0x1bf47000,
-/* 0x007f: nsec */
- 0xf900f8f2,
- 0xf080f990,
- 0x84b62c87,
- 0x0088cf06,
-/* 0x008c: nsec_loop */
- 0xb62c97f0,
- 0x99cf0694,
- 0x0298bb00,
- 0xf4069eb8,
- 0x80fcf11e,
- 0x00f890fc,
-/* 0x00a4: wait */
- 0x80f990f9,
- 0xb62c87f0,
- 0x88cf0684,
-/* 0x00b1: wait_loop */
- 0x02eeb900,
- 0xb90421f4,
- 0xadfd02da,
- 0x06acb804,
- 0xf0150bf4,
- 0x94b62c97,
- 0x0099cf06,
- 0xb80298bb,
- 0x1ef4069b,
-/* 0x00d5: wait_done */
- 0xfc80fcdf,
-/* 0x00db: intr_watchdog */
- 0x9800f890,
- 0x96b003e9,
- 0x2a0bf400,
- 0xbb9a0a98,
- 0x1cf4029a,
- 0x01d7f00f,
- 0x02dd21f5,
- 0x0ef494bd,
-/* 0x00f9: intr_watchdog_next_time */
- 0x9b0a9815,
- 0xf400a6b0,
- 0x9ab8090b,
- 0x061cf406,
-/* 0x0108: intr_watchdog_next_time_set */
-/* 0x010b: intr_watchdog_next_proc */
- 0x809b0980,
- 0xe0b603e9,
- 0x68e6b158,
- 0xc61bf402,
-/* 0x011a: intr */
- 0x00f900f8,
- 0x80f904bd,
- 0xa0f990f9,
- 0xc0f9b0f9,
- 0xe0f9d0f9,
- 0xf7f0f0f9,
- 0x0188fe00,
- 0x87f180f9,
- 0x84b605d0,
- 0x0088cf06,
- 0xf10180b6,
- 0xb605d007,
- 0x08d00604,
- 0xf004bd00,
- 0x84b60887,
- 0x0088cf06,
- 0xf40289c4,
- 0x0080230b,
- 0x58e7f09b,
- 0x98db21f4,
- 0x96b09b09,
- 0x110bf400,
- 0xb63407f0,
- 0x09d00604,
- 0x8004bd00,
-/* 0x017e: intr_skip_watchdog */
- 0x89e49a09,
- 0x0bf40800,
- 0x8897f148,
- 0x0694b606,
- 0xc40099cf,
- 0x0bf4029a,
- 0xc0c7f12c,
- 0x06c4b604,
- 0xf900cccf,
- 0x48e7f1c0,
- 0x53e3f14f,
- 0x00d7f054,
- 0x034221f5,
- 0x07f1c0fc,
- 0x04b604c0,
- 0x000cd006,
-/* 0x01be: intr_subintr_skip_fifo */
- 0x07f104bd,
- 0x04b60688,
- 0x0009d006,
-/* 0x01ca: intr_skip_subintr */
- 0x89c404bd,
- 0x070bf420,
- 0xffbfa4f1,
-/* 0x01d4: intr_skip_pause */
- 0xf44089c4,
- 0xa4f1070b,
-/* 0x01de: intr_skip_user0 */
- 0x07f0ffbf,
- 0x0604b604,
- 0xbd0008d0,
- 0xfe80fc04,
- 0xf0fc0088,
- 0xd0fce0fc,
- 0xb0fcc0fc,
- 0x90fca0fc,
- 0x00fc80fc,
- 0xf80032f4,
-/* 0x0205: ticks_from_ns */
- 0xf9c0f901,
- 0xcbd7f1b0,
- 0x00d3f000,
- 0x041321f5,
- 0x03e8ccec,
- 0xf400b4b0,
- 0xeeec120b,
- 0xd7f103e8,
- 0xd3f000cb,
- 0x1321f500,
-/* 0x022d: ticks_from_ns_quit */
- 0x02ceb904,
- 0xc0fcb0fc,
-/* 0x0236: ticks_from_us */
- 0xc0f900f8,
- 0xd7f1b0f9,
- 0xd3f000cb,
- 0x1321f500,
- 0x02ceb904,
- 0xf400b4b0,
- 0xe4bd050b,
-/* 0x0250: ticks_from_us_quit */
- 0xc0fcb0fc,
-/* 0x0256: ticks_to_us */
- 0xd7f100f8,
- 0xd3f000cb,
- 0xecedff00,
-/* 0x0262: timer */
- 0x90f900f8,
- 0x32f480f9,
- 0x03f89810,
- 0xf40086b0,
- 0x84bd651c,
- 0xb63807f0,
- 0x08d00604,
- 0xf004bd00,
- 0x84b63487,
- 0x0088cf06,
- 0xbb9a0998,
- 0xe9bb0298,
- 0x03fe8000,
- 0xb60887f0,
- 0x88cf0684,
- 0x0284f000,
- 0xf0261bf4,
- 0x84b63487,
- 0x0088cf06,
- 0xf406e0b8,
- 0xe8b8090b,
- 0x111cf406,
-/* 0x02b8: timer_reset */
- 0xb63407f0,
- 0x0ed00604,
- 0x8004bd00,
-/* 0x02c6: timer_enable */
- 0x87f09a0e,
- 0x3807f001,
- 0xd00604b6,
- 0x04bd0008,
-/* 0x02d4: timer_done */
- 0xfc1031f4,
- 0xf890fc80,
-/* 0x02dd: send_proc */
- 0xf980f900,
- 0x05e89890,
- 0xf004e998,
- 0x89b80486,
- 0x2a0bf406,
- 0x940398c4,
- 0x80b60488,
- 0x008ebb18,
- 0x8000fa98,
- 0x8d80008a,
- 0x028c8001,
- 0xb6038b80,
- 0x94f00190,
- 0x04e98007,
-/* 0x0317: send_done */
- 0xfc0231f4,
- 0xf880fc90,
-/* 0x031d: find */
- 0xf080f900,
- 0x31f45887,
-/* 0x0325: find_loop */
- 0x008a9801,
- 0xf406aeb8,
- 0x80b6100b,
- 0x6886b158,
- 0xf01bf402,
-/* 0x033b: find_done */
- 0xb90132f4,
- 0x80fc028e,
-/* 0x0342: send */
- 0x21f500f8,
- 0x01f4031d,
-/* 0x034b: recv */
- 0xf900f897,
- 0x9880f990,
- 0xe99805e8,
- 0x0132f404,
- 0xf40689b8,
- 0x89c43d0b,
- 0x0180b603,
- 0x800784f0,
- 0xea9805e8,
- 0xfef0f902,
- 0xf0f9018f,
- 0x9402efb9,
- 0xe9bb0499,
- 0x18e0b600,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0xf0fca5f9,
- 0xf400f8fe,
- 0xf0fc0131,
-/* 0x0398: recv_done */
- 0x90fc80fc,
-/* 0x039e: init */
- 0x17f100f8,
- 0x14b60108,
- 0x0011cf06,
- 0x010911e7,
- 0xfe0814b6,
- 0x17f10014,
- 0x13f000e0,
- 0x1c07f000,
- 0xd00604b6,
- 0x04bd0001,
- 0xf0ff17f0,
- 0x04b61407,
- 0x0001d006,
- 0x17f004bd,
- 0x0015f102,
- 0x1007f008,
- 0xd00604b6,
- 0x04bd0001,
- 0x011a17f1,
- 0xfe0013f0,
- 0x31f40010,
- 0x0117f010,
- 0xb63807f0,
- 0x01d00604,
- 0xf004bd00,
-/* 0x0402: init_proc */
- 0xf19858f7,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x0413: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb9301dff,
- 0x34f10234,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0xe2ff01b4,
- 0x0234b930,
- 0xffff34f1,
- 0xb61034b6,
- 0xc3bb1045,
- 0x01b4bb00,
- 0xbb3012ff,
- 0x40fc00b3,
- 0x20fc30fc,
- 0x00f810fc,
-/* 0x0464: host_send */
- 0x04b017f1,
- 0xcf0614b6,
- 0x27f10011,
- 0x24b604a0,
- 0x0022cf06,
- 0xf40612b8,
- 0x1ec4320b,
- 0x04ee9407,
- 0x0270e0b7,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0x034221f5,
- 0xc40110b6,
- 0x07f10f1e,
- 0x04b604b0,
- 0x000ed006,
- 0x0ef404bd,
-/* 0x04ad: host_send_done */
-/* 0x04af: host_recv */
- 0xf100f8ba,
- 0xf14e4917,
- 0xb8525413,
- 0x0bf406e1,
-/* 0x04bd: host_recv_wait */
- 0xcc17f1aa,
- 0x0614b604,
- 0xf10011cf,
- 0xb604c827,
- 0x22cf0624,
- 0x0816f000,
- 0xf40612b8,
- 0x23c4e60b,
- 0x0434b607,
- 0x02f030b7,
- 0x80033b80,
- 0x3d80023c,
- 0x003e8001,
- 0xf00120b6,
- 0x07f10f24,
- 0x04b604c8,
- 0x0002d006,
- 0x27f004bd,
- 0x0007f040,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x0512: host_init */
- 0x17f100f8,
- 0x14b60080,
- 0x7015f110,
- 0xd007f102,
- 0x0604b604,
- 0xbd0001d0,
- 0x8017f104,
- 0x1014b600,
- 0x02f015f1,
- 0x04dc07f1,
- 0xd00604b6,
- 0x04bd0001,
- 0xf10117f0,
- 0xb604c407,
- 0x01d00604,
- 0xf804bd00,
-/* 0x0551: memx_func_enter */
- 0x1087f100,
- 0x028eb916,
- 0xb90421f4,
- 0x67f102d7,
- 0x63f1fffc,
- 0x76fdffff,
- 0x0267f104,
- 0x0576fd00,
- 0x70f980f9,
- 0xe0fcd0fc,
- 0xf03f21f4,
- 0x07f10467,
- 0x04b607e0,
- 0x0006d006,
-/* 0x058a: memx_func_enter_wait */
- 0x67f104bd,
- 0x64b607c0,
- 0x0066cf06,
- 0xf40464f0,
- 0x67f0f30b,
- 0x0664b62c,
- 0x800066cf,
- 0x00f8f106,
-/* 0x05a8: memx_func_leave */
- 0xb62c67f0,
- 0x66cf0664,
- 0xf2068000,
- 0xf10467f0,
- 0xb607e407,
- 0x06d00604,
-/* 0x05c3: memx_func_leave_wait */
- 0xf104bd00,
- 0xb607c067,
- 0x66cf0664,
- 0x0464f000,
- 0xf1f31bf4,
- 0xb9161087,
- 0x21f4028e,
- 0x02d7b904,
- 0xffcc67f1,
- 0xffff63f1,
- 0xf90476fd,
- 0xfc70f980,
- 0xf4e0fcd0,
- 0x00f83f21,
-/* 0x05f8: memx_func_wait_vblank */
- 0xb0001698,
- 0x0bf40066,
- 0x0166b013,
- 0xf4060bf4,
-/* 0x060a: memx_func_wait_vblank_head1 */
- 0x77f12e0e,
- 0x0ef40020,
-/* 0x0611: memx_func_wait_vblank_head0 */
- 0x0877f107,
-/* 0x0615: memx_func_wait_vblank_0 */
- 0xc467f100,
- 0x0664b607,
- 0xfd0066cf,
- 0x1bf40467,
-/* 0x0625: memx_func_wait_vblank_1 */
- 0xc467f1f3,
- 0x0664b607,
- 0xfd0066cf,
- 0x0bf40467,
-/* 0x0635: memx_func_wait_vblank_fini */
- 0x0410b6f3,
-/* 0x063a: memx_func_wr32 */
- 0x169800f8,
- 0x01159800,
- 0xf90810b6,
- 0xfc50f960,
- 0xf4e0fcd0,
- 0x42b63f21,
- 0xe91bf402,
-/* 0x0656: memx_func_wait */
- 0x87f000f8,
- 0x0684b62c,
- 0x980088cf,
- 0x1d98001e,
- 0x021c9801,
- 0xb6031b98,
- 0x21f41010,
-/* 0x0673: memx_func_delay */
- 0x9800f8a4,
- 0x10b6001e,
- 0x7f21f404,
-/* 0x067e: memx_func_train */
- 0x57f100f8,
- 0x77f10003,
- 0x97f10000,
- 0x93f00000,
- 0x029eb970,
- 0xb90421f4,
- 0xe7f102d8,
- 0x21f42710,
-/* 0x069d: memx_func_train_loop_outer */
- 0x0158e07f,
- 0x0083f101,
- 0xe097f102,
- 0x1193f011,
- 0x80f990f9,
- 0xe0fcd0fc,
- 0xf93f21f4,
- 0x0067f150,
-/* 0x06bd: memx_func_train_loop_inner */
- 0x1187f100,
- 0x9068ff11,
- 0xfd109894,
- 0x97f10589,
- 0x93f00720,
- 0xf990f910,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x008097f1,
- 0xb91093f0,
- 0x21f4029e,
- 0x02d8b904,
- 0xf92088c5,
- 0xfc80f990,
- 0xf4e0fcd0,
- 0x97f13f21,
- 0x93f0053c,
- 0x0287f110,
- 0x0083f130,
- 0xf990f980,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x0560e7f1,
- 0xf110e3f0,
- 0xf10000d7,
- 0x908000d3,
- 0xb7f100dc,
- 0xb3f08480,
- 0xa421f41e,
- 0x000057f1,
- 0xffff97f1,
- 0x830093f1,
-/* 0x073c: memx_func_train_loop_4x */
- 0x0080a7f1,
- 0xb910a3f0,
- 0x21f402ae,
- 0x02d8b904,
- 0xffdfb7f1,
- 0xffffb3f1,
- 0xf9048bfd,
- 0xfc80f9a0,
- 0xf4e0fcd0,
- 0xa7f13f21,
- 0xa3f0053c,
- 0x0287f110,
- 0x0083f130,
- 0xf9a0f980,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x0560e7f1,
- 0xf110e3f0,
- 0xf10000d7,
- 0xb98000d3,
- 0xb7f102dc,
- 0xb3f02710,
- 0xa421f400,
- 0xf402eeb9,
- 0xddb90421,
- 0x949dff02,
- 0x700150b6,
- 0x1ef40456,
- 0xcc7aa092,
- 0x00a9800b,
- 0xb60160b6,
- 0x66700470,
- 0x001ef510,
- 0xb650fcff,
- 0x56700150,
- 0xd41ef507,
-/* 0x07cf: memx_exec */
- 0xf900f8fe,
- 0xb9d0f9e0,
- 0xb2b902c1,
-/* 0x07d9: memx_exec_next */
- 0x00139802,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12b855f9,
- 0xe41ef406,
- 0x98f10b98,
- 0xcbbbf20c,
- 0xc4b7f102,
- 0x06b4b607,
- 0xfc00bbcf,
- 0xf5e0fcd0,
- 0xf8034221,
-/* 0x0815: memx_info */
- 0x01c67000,
-/* 0x081b: memx_info_data */
- 0xf10e0bf4,
- 0xf103ccc7,
- 0xf40800b7,
-/* 0x0826: memx_info_train */
- 0xc7f10b0e,
- 0xb7f10bcc,
-/* 0x082e: memx_info_send */
- 0x21f50100,
- 0x00f80342,
-/* 0x0834: memx_recv */
- 0xf401d6b0,
- 0xd6b0980b,
- 0xd80bf400,
-/* 0x0842: memx_init */
- 0x00f800f8,
-/* 0x0844: perf_recv */
-/* 0x0846: perf_init */
- 0x00f800f8,
-/* 0x0848: i2c_drive_scl */
- 0xf40036b0,
- 0x07f1110b,
- 0x04b607e0,
- 0x0001d006,
- 0x00f804bd,
-/* 0x085c: i2c_drive_scl_lo */
- 0x07e407f1,
- 0xd00604b6,
- 0x04bd0001,
-/* 0x086a: i2c_drive_sda */
- 0x36b000f8,
- 0x110bf400,
- 0x07e007f1,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x087e: i2c_drive_sda_lo */
- 0x07f100f8,
- 0x04b607e4,
- 0x0002d006,
- 0x00f804bd,
-/* 0x088c: i2c_sense_scl */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0431fd00,
- 0xf4060bf4,
-/* 0x08a2: i2c_sense_scl_done */
- 0x00f80131,
-/* 0x08a4: i2c_sense_sda */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0432fd00,
- 0xf4060bf4,
-/* 0x08ba: i2c_sense_sda_done */
- 0x00f80131,
-/* 0x08bc: i2c_raise_scl */
- 0x47f140f9,
- 0x37f00898,
- 0x4821f501,
-/* 0x08c9: i2c_raise_scl_wait */
- 0xe8e7f108,
- 0x7f21f403,
- 0x088c21f5,
- 0xb60901f4,
- 0x1bf40142,
-/* 0x08dd: i2c_raise_scl_done */
- 0xf840fcef,
-/* 0x08e1: i2c_start */
- 0x8c21f500,
- 0x0d11f408,
- 0x08a421f5,
- 0xf40611f4,
-/* 0x08f2: i2c_start_rep */
- 0x37f0300e,
- 0x4821f500,
- 0x0137f008,
- 0x086a21f5,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0xbc21f550,
- 0x0464b608,
-/* 0x091f: i2c_start_send */
- 0xf01f11f4,
- 0x21f50037,
- 0xe7f1086a,
- 0x21f41388,
- 0x0037f07f,
- 0x084821f5,
- 0x1388e7f1,
-/* 0x093b: i2c_start_out */
- 0xf87f21f4,
-/* 0x093d: i2c_stop */
- 0x0037f000,
- 0x084821f5,
- 0xf50037f0,
- 0xf1086a21,
- 0xf403e8e7,
- 0x37f07f21,
- 0x4821f501,
- 0x88e7f108,
- 0x7f21f413,
- 0xf50137f0,
- 0xf1086a21,
- 0xf41388e7,
- 0x00f87f21,
-/* 0x0970: i2c_bitw */
- 0x086a21f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x08bc21f5,
- 0xf40464b6,
- 0xe7f11811,
- 0x21f41388,
- 0x0037f07f,
- 0x084821f5,
- 0x1388e7f1,
-/* 0x09af: i2c_bitw_out */
- 0xf87f21f4,
-/* 0x09b1: i2c_bitr */
- 0x0137f000,
- 0x086a21f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x08bc21f5,
- 0xf40464b6,
- 0x21f51b11,
- 0x37f008a4,
- 0x4821f500,
- 0x88e7f108,
- 0x7f21f413,
- 0xf4013cf0,
-/* 0x09f6: i2c_bitr_done */
- 0x00f80131,
-/* 0x09f8: i2c_get_byte */
- 0xf00057f0,
-/* 0x09fe: i2c_get_byte_next */
- 0x54b60847,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b609b1,
- 0x2b11f404,
- 0xb60553fd,
- 0x1bf40142,
- 0x0137f0d8,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x7021f550,
- 0x0464b609,
-/* 0x0a48: i2c_get_byte_done */
-/* 0x0a4a: i2c_put_byte */
- 0x47f000f8,
-/* 0x0a4d: i2c_put_byte_next */
- 0x0142b608,
- 0xbb3854ff,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x097021f5,
- 0xf40464b6,
- 0x46b03411,
- 0xd81bf400,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0xb121f550,
- 0x0464b609,
- 0xbb0f11f4,
- 0x36b00076,
- 0x061bf401,
-/* 0x0aa3: i2c_put_byte_done */
- 0xf80132f4,
-/* 0x0aa5: i2c_addr */
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b608e1,
- 0x2911f404,
- 0x012ec3e7,
- 0xfd0134b6,
- 0x76bb0553,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb60a4a21,
-/* 0x0aea: i2c_addr_done */
- 0x00f80464,
-/* 0x0aec: i2c_acquire_addr */
- 0xb6f8cec7,
- 0xe0b702e4,
- 0xee980d1c,
-/* 0x0afb: i2c_acquire */
- 0xf500f800,
- 0xf40aec21,
- 0xd9f00421,
- 0x3f21f403,
-/* 0x0b0a: i2c_release */
- 0x21f500f8,
- 0x21f40aec,
- 0x03daf004,
- 0xf83f21f4,
-/* 0x0b19: i2c_recv */
- 0x0132f400,
- 0xb6f8c1c7,
- 0x16b00214,
- 0x3a1ff528,
- 0xf413a001,
- 0x0032980c,
- 0x0ccc13a0,
- 0xf4003198,
- 0xd0f90231,
- 0xd0f9e0f9,
- 0x000067f1,
- 0x100063f1,
- 0xbb016792,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x0afb21f5,
- 0xfc0464b6,
- 0x00d6b0d0,
- 0x00b31bf5,
- 0xbb0057f0,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x0aa521f5,
- 0xf50464b6,
- 0xc700d011,
- 0x76bbe0c5,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb60a4a21,
- 0x11f50464,
- 0x57f000ad,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b60aa5,
- 0x8a11f504,
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b609f8,
- 0x6a11f404,
- 0xbbe05bcb,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x093d21f5,
- 0xb90464b6,
- 0x74bd025b,
-/* 0x0c1f: i2c_recv_not_rd08 */
- 0xb0430ef4,
- 0x1bf401d6,
- 0x0057f03d,
- 0x0aa521f5,
- 0xc73311f4,
- 0x21f5e0c5,
- 0x11f40a4a,
- 0x0057f029,
- 0x0aa521f5,
- 0xc71f11f4,
- 0x21f5e0b5,
- 0x11f40a4a,
- 0x3d21f515,
- 0xc774bd09,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0c5f: i2c_recv_not_wr08 */
-/* 0x0c5f: i2c_recv_done */
- 0xc7030ef4,
- 0x21f5f8ce,
- 0xe0fc0b0a,
- 0x12f4d0fc,
- 0x027cb90a,
- 0x034221f5,
-/* 0x0c74: i2c_recv_exit */
-/* 0x0c76: i2c_init */
- 0x00f800f8,
-/* 0x0c78: test_recv */
- 0x05d817f1,
- 0xcf0614b6,
- 0x10b60011,
- 0xd807f101,
- 0x0604b605,
- 0xbd0001d0,
- 0x00e7f104,
- 0x4fe3f1d9,
- 0x6221f513,
-/* 0x0c9f: test_init */
- 0xf100f802,
- 0xf50800e7,
- 0xf8026221,
-/* 0x0ca9: idle_recv */
-/* 0x0cab: idle */
- 0xf400f800,
- 0x17f10031,
- 0x14b605d4,
- 0x0011cf06,
- 0xf10110b6,
- 0xb605d407,
- 0x01d00604,
-/* 0x0cc7: idle_loop */
- 0xf004bd00,
- 0x32f45817,
-/* 0x0ccd: idle_proc */
-/* 0x0ccd: idle_proc_exec */
- 0xb910f902,
- 0x21f5021e,
- 0x10fc034b,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0ce1: idle_proc_next */
- 0x5810b6ef,
- 0xf4061fb8,
- 0x02f4e61b,
- 0x0028f4dd,
- 0x00bb0ef4,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc
deleted file mode 100644
index 21bf8cc7618f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GF100
-#define HW_TICKS_PER_US 203 // should be 202.5
-
-//#define NVKM_FALCON_PC24
-//#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nvc0_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nvc0_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
deleted file mode 100644
index 90221d973f84..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvc0.fuc.h
+++ /dev/null
@@ -1,1865 +0,0 @@
-uint32_t nvc0_pwr_data[] = {
-/* 0x0000: proc_kern */
- 0x52544e49,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: proc_list_head */
- 0x54534f48,
- 0x00000512,
- 0x000004af,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x584d454d,
- 0x0000075e,
- 0x00000750,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x46524550,
- 0x00000762,
- 0x00000760,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x5f433249,
- 0x00000b92,
- 0x00000a35,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x54534554,
- 0x00000bbb,
- 0x00000b94,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x454c4449,
- 0x00000bc7,
- 0x00000bc5,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
- 0x00000000,
-/* 0x026c: time_next */
- 0x00000000,
-/* 0x0270: fifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x02f0: rfifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0370: memx_func_head */
- 0x00000001,
- 0x00000000,
- 0x00000551,
-/* 0x037c: memx_func_next */
- 0x00000002,
- 0x00000000,
- 0x000005db,
- 0x00000003,
- 0x00000002,
- 0x000006a5,
- 0x00040004,
- 0x00000000,
- 0x000006c1,
- 0x00010005,
- 0x00000000,
- 0x000006de,
- 0x00010006,
- 0x00000000,
- 0x00000663,
- 0x00000007,
- 0x00000000,
- 0x000006e9,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
- 0x00000000,
-/* 0x03c8: memx_ts_end */
- 0x00000000,
-/* 0x03cc: memx_data_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
- 0x00001000,
- 0x00004000,
- 0x00010000,
- 0x00000100,
- 0x00040000,
- 0x00100000,
- 0x00400000,
- 0x01000000,
- 0x04000000,
- 0x10000000,
-/* 0x0cf4: i2c_sda_map */
- 0x00002000,
- 0x00008000,
- 0x00020000,
- 0x00000200,
- 0x00080000,
- 0x00200000,
- 0x00800000,
- 0x02000000,
- 0x08000000,
- 0x20000000,
-/* 0x0d1c: i2c_ctrl */
- 0x0000e138,
- 0x0000e150,
- 0x0000e168,
- 0x0000e180,
- 0x0000e254,
- 0x0000e274,
- 0x0000e764,
- 0x0000e780,
- 0x0000e79c,
- 0x0000e7b8,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nvc0_pwr_code[] = {
- 0x039e0ef5,
-/* 0x0004: rd32 */
- 0x07a007f1,
- 0xd00604b6,
- 0x04bd000e,
- 0xf001d7f0,
- 0x07f101d3,
- 0x04b607ac,
- 0x000dd006,
-/* 0x0022: rd32_wait */
- 0xd7f104bd,
- 0xd4b607ac,
- 0x00ddcf06,
- 0x7000d4f1,
- 0xf1f21bf4,
- 0xb607a4d7,
- 0xddcf06d4,
-/* 0x003f: wr32 */
- 0xf100f800,
- 0xb607a007,
- 0x0ed00604,
- 0xf104bd00,
- 0xb607a407,
- 0x0dd00604,
- 0xf004bd00,
- 0xd5f002d7,
- 0x01d3f0f0,
- 0x07ac07f1,
- 0xd00604b6,
- 0x04bd000d,
-/* 0x006c: wr32_wait */
- 0x07acd7f1,
- 0xcf06d4b6,
- 0xd4f100dd,
- 0x1bf47000,
-/* 0x007f: nsec */
- 0xf900f8f2,
- 0xf080f990,
- 0x84b62c87,
- 0x0088cf06,
-/* 0x008c: nsec_loop */
- 0xb62c97f0,
- 0x99cf0694,
- 0x0298bb00,
- 0xf4069eb8,
- 0x80fcf11e,
- 0x00f890fc,
-/* 0x00a4: wait */
- 0x80f990f9,
- 0xb62c87f0,
- 0x88cf0684,
-/* 0x00b1: wait_loop */
- 0x02eeb900,
- 0xb90421f4,
- 0xadfd02da,
- 0x06acb804,
- 0xf0150bf4,
- 0x94b62c97,
- 0x0099cf06,
- 0xb80298bb,
- 0x1ef4069b,
-/* 0x00d5: wait_done */
- 0xfc80fcdf,
-/* 0x00db: intr_watchdog */
- 0x9800f890,
- 0x96b003e9,
- 0x2a0bf400,
- 0xbb9a0a98,
- 0x1cf4029a,
- 0x01d7f00f,
- 0x02dd21f5,
- 0x0ef494bd,
-/* 0x00f9: intr_watchdog_next_time */
- 0x9b0a9815,
- 0xf400a6b0,
- 0x9ab8090b,
- 0x061cf406,
-/* 0x0108: intr_watchdog_next_time_set */
-/* 0x010b: intr_watchdog_next_proc */
- 0x809b0980,
- 0xe0b603e9,
- 0x68e6b158,
- 0xc61bf402,
-/* 0x011a: intr */
- 0x00f900f8,
- 0x80f904bd,
- 0xa0f990f9,
- 0xc0f9b0f9,
- 0xe0f9d0f9,
- 0xf7f0f0f9,
- 0x0188fe00,
- 0x87f180f9,
- 0x84b605d0,
- 0x0088cf06,
- 0xf10180b6,
- 0xb605d007,
- 0x08d00604,
- 0xf004bd00,
- 0x84b60887,
- 0x0088cf06,
- 0xf40289c4,
- 0x0080230b,
- 0x58e7f09b,
- 0x98db21f4,
- 0x96b09b09,
- 0x110bf400,
- 0xb63407f0,
- 0x09d00604,
- 0x8004bd00,
-/* 0x017e: intr_skip_watchdog */
- 0x89e49a09,
- 0x0bf40800,
- 0x8897f148,
- 0x0694b606,
- 0xc40099cf,
- 0x0bf4029a,
- 0xc0c7f12c,
- 0x06c4b604,
- 0xf900cccf,
- 0x48e7f1c0,
- 0x53e3f14f,
- 0x00d7f054,
- 0x034221f5,
- 0x07f1c0fc,
- 0x04b604c0,
- 0x000cd006,
-/* 0x01be: intr_subintr_skip_fifo */
- 0x07f104bd,
- 0x04b60688,
- 0x0009d006,
-/* 0x01ca: intr_skip_subintr */
- 0x89c404bd,
- 0x070bf420,
- 0xffbfa4f1,
-/* 0x01d4: intr_skip_pause */
- 0xf44089c4,
- 0xa4f1070b,
-/* 0x01de: intr_skip_user0 */
- 0x07f0ffbf,
- 0x0604b604,
- 0xbd0008d0,
- 0xfe80fc04,
- 0xf0fc0088,
- 0xd0fce0fc,
- 0xb0fcc0fc,
- 0x90fca0fc,
- 0x00fc80fc,
- 0xf80032f4,
-/* 0x0205: ticks_from_ns */
- 0xf9c0f901,
- 0xcbd7f1b0,
- 0x00d3f000,
- 0x041321f5,
- 0x03e8ccec,
- 0xf400b4b0,
- 0xeeec120b,
- 0xd7f103e8,
- 0xd3f000cb,
- 0x1321f500,
-/* 0x022d: ticks_from_ns_quit */
- 0x02ceb904,
- 0xc0fcb0fc,
-/* 0x0236: ticks_from_us */
- 0xc0f900f8,
- 0xd7f1b0f9,
- 0xd3f000cb,
- 0x1321f500,
- 0x02ceb904,
- 0xf400b4b0,
- 0xe4bd050b,
-/* 0x0250: ticks_from_us_quit */
- 0xc0fcb0fc,
-/* 0x0256: ticks_to_us */
- 0xd7f100f8,
- 0xd3f000cb,
- 0xecedff00,
-/* 0x0262: timer */
- 0x90f900f8,
- 0x32f480f9,
- 0x03f89810,
- 0xf40086b0,
- 0x84bd651c,
- 0xb63807f0,
- 0x08d00604,
- 0xf004bd00,
- 0x84b63487,
- 0x0088cf06,
- 0xbb9a0998,
- 0xe9bb0298,
- 0x03fe8000,
- 0xb60887f0,
- 0x88cf0684,
- 0x0284f000,
- 0xf0261bf4,
- 0x84b63487,
- 0x0088cf06,
- 0xf406e0b8,
- 0xe8b8090b,
- 0x111cf406,
-/* 0x02b8: timer_reset */
- 0xb63407f0,
- 0x0ed00604,
- 0x8004bd00,
-/* 0x02c6: timer_enable */
- 0x87f09a0e,
- 0x3807f001,
- 0xd00604b6,
- 0x04bd0008,
-/* 0x02d4: timer_done */
- 0xfc1031f4,
- 0xf890fc80,
-/* 0x02dd: send_proc */
- 0xf980f900,
- 0x05e89890,
- 0xf004e998,
- 0x89b80486,
- 0x2a0bf406,
- 0x940398c4,
- 0x80b60488,
- 0x008ebb18,
- 0x8000fa98,
- 0x8d80008a,
- 0x028c8001,
- 0xb6038b80,
- 0x94f00190,
- 0x04e98007,
-/* 0x0317: send_done */
- 0xfc0231f4,
- 0xf880fc90,
-/* 0x031d: find */
- 0xf080f900,
- 0x31f45887,
-/* 0x0325: find_loop */
- 0x008a9801,
- 0xf406aeb8,
- 0x80b6100b,
- 0x6886b158,
- 0xf01bf402,
-/* 0x033b: find_done */
- 0xb90132f4,
- 0x80fc028e,
-/* 0x0342: send */
- 0x21f500f8,
- 0x01f4031d,
-/* 0x034b: recv */
- 0xf900f897,
- 0x9880f990,
- 0xe99805e8,
- 0x0132f404,
- 0xf40689b8,
- 0x89c43d0b,
- 0x0180b603,
- 0x800784f0,
- 0xea9805e8,
- 0xfef0f902,
- 0xf0f9018f,
- 0x9402efb9,
- 0xe9bb0499,
- 0x18e0b600,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0xf0fca5f9,
- 0xf400f8fe,
- 0xf0fc0131,
-/* 0x0398: recv_done */
- 0x90fc80fc,
-/* 0x039e: init */
- 0x17f100f8,
- 0x14b60108,
- 0x0011cf06,
- 0x010911e7,
- 0xfe0814b6,
- 0x17f10014,
- 0x13f000e0,
- 0x1c07f000,
- 0xd00604b6,
- 0x04bd0001,
- 0xf0ff17f0,
- 0x04b61407,
- 0x0001d006,
- 0x17f004bd,
- 0x0015f102,
- 0x1007f008,
- 0xd00604b6,
- 0x04bd0001,
- 0x011a17f1,
- 0xfe0013f0,
- 0x31f40010,
- 0x0117f010,
- 0xb63807f0,
- 0x01d00604,
- 0xf004bd00,
-/* 0x0402: init_proc */
- 0xf19858f7,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x0413: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb9301dff,
- 0x34f10234,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0xe2ff01b4,
- 0x0234b930,
- 0xffff34f1,
- 0xb61034b6,
- 0xc3bb1045,
- 0x01b4bb00,
- 0xbb3012ff,
- 0x40fc00b3,
- 0x20fc30fc,
- 0x00f810fc,
-/* 0x0464: host_send */
- 0x04b017f1,
- 0xcf0614b6,
- 0x27f10011,
- 0x24b604a0,
- 0x0022cf06,
- 0xf40612b8,
- 0x1ec4320b,
- 0x04ee9407,
- 0x0270e0b7,
- 0x9803eb98,
- 0xed9802ec,
- 0x00ee9801,
- 0x034221f5,
- 0xc40110b6,
- 0x07f10f1e,
- 0x04b604b0,
- 0x000ed006,
- 0x0ef404bd,
-/* 0x04ad: host_send_done */
-/* 0x04af: host_recv */
- 0xf100f8ba,
- 0xf14e4917,
- 0xb8525413,
- 0x0bf406e1,
-/* 0x04bd: host_recv_wait */
- 0xcc17f1aa,
- 0x0614b604,
- 0xf10011cf,
- 0xb604c827,
- 0x22cf0624,
- 0x0816f000,
- 0xf40612b8,
- 0x23c4e60b,
- 0x0434b607,
- 0x02f030b7,
- 0x80033b80,
- 0x3d80023c,
- 0x003e8001,
- 0xf00120b6,
- 0x07f10f24,
- 0x04b604c8,
- 0x0002d006,
- 0x27f004bd,
- 0x0007f040,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x0512: host_init */
- 0x17f100f8,
- 0x14b60080,
- 0x7015f110,
- 0xd007f102,
- 0x0604b604,
- 0xbd0001d0,
- 0x8017f104,
- 0x1014b600,
- 0x02f015f1,
- 0x04dc07f1,
- 0xd00604b6,
- 0x04bd0001,
- 0xf10117f0,
- 0xb604c407,
- 0x01d00604,
- 0xf804bd00,
-/* 0x0551: memx_func_enter */
- 0x2067f100,
- 0x5d77f116,
- 0xff73f1f5,
- 0x026eb9ff,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f904,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0xfffe77f1,
- 0xffff73f1,
- 0xf4026eb9,
- 0xd8b90421,
- 0x0487fd02,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0xf13f21f4,
- 0xb926f067,
- 0x21f4026e,
- 0x02d8b904,
- 0xf90487fd,
- 0xfc80f960,
- 0xf4e0fcd0,
- 0x67f03f21,
- 0xe007f104,
- 0x0604b607,
- 0xbd0006d0,
-/* 0x05bd: memx_func_enter_wait */
- 0xc067f104,
- 0x0664b607,
- 0xf00066cf,
- 0x0bf40464,
- 0x2c67f0f3,
- 0xcf0664b6,
- 0x06800066,
-/* 0x05db: memx_func_leave */
- 0xf000f8f1,
- 0x64b62c67,
- 0x0066cf06,
- 0xf0f20680,
- 0x07f10467,
- 0x04b607e4,
- 0x0006d006,
-/* 0x05f6: memx_func_leave_wait */
- 0x67f104bd,
- 0x64b607c0,
- 0x0066cf06,
- 0xf40464f0,
- 0x67f1f31b,
- 0x77f126f0,
- 0x73f00001,
- 0x026eb900,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f905,
- 0xfcd0fc80,
- 0x3f21f4e0,
- 0x162067f1,
- 0xf4026eb9,
- 0xd8b90421,
- 0x0587fd02,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0xf13f21f4,
- 0xf00aa277,
- 0x6eb90073,
- 0x0421f402,
- 0xfd02d8b9,
- 0x60f90587,
- 0xd0fc80f9,
- 0x21f4e0fc,
-/* 0x0663: memx_func_wait_vblank */
- 0x9800f83f,
- 0x66b00016,
- 0x130bf400,
- 0xf40166b0,
- 0x0ef4060b,
-/* 0x0675: memx_func_wait_vblank_head1 */
- 0x2077f12e,
- 0x070ef400,
-/* 0x067c: memx_func_wait_vblank_head0 */
- 0x000877f1,
-/* 0x0680: memx_func_wait_vblank_0 */
- 0x07c467f1,
- 0xcf0664b6,
- 0x67fd0066,
- 0xf31bf404,
-/* 0x0690: memx_func_wait_vblank_1 */
- 0x07c467f1,
- 0xcf0664b6,
- 0x67fd0066,
- 0xf30bf404,
-/* 0x06a0: memx_func_wait_vblank_fini */
- 0xf80410b6,
-/* 0x06a5: memx_func_wr32 */
- 0x00169800,
- 0xb6011598,
- 0x60f90810,
- 0xd0fc50f9,
- 0x21f4e0fc,
- 0x0242b63f,
- 0xf8e91bf4,
-/* 0x06c1: memx_func_wait */
- 0x2c87f000,
- 0xcf0684b6,
- 0x1e980088,
- 0x011d9800,
- 0x98021c98,
- 0x10b6031b,
- 0xa421f410,
-/* 0x06de: memx_func_delay */
- 0x1e9800f8,
- 0x0410b600,
- 0xf87f21f4,
-/* 0x06e9: memx_func_train */
-/* 0x06eb: memx_exec */
- 0xf900f800,
- 0xb9d0f9e0,
- 0xb2b902c1,
-/* 0x06f5: memx_exec_next */
- 0x00139802,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12b855f9,
- 0xe41ef406,
- 0x98f10b98,
- 0xcbbbf20c,
- 0xc4b7f102,
- 0x06b4b607,
- 0xfc00bbcf,
- 0xf5e0fcd0,
- 0xf8034221,
-/* 0x0731: memx_info */
- 0x01c67000,
-/* 0x0737: memx_info_data */
- 0xf10e0bf4,
- 0xf103ccc7,
- 0xf40800b7,
-/* 0x0742: memx_info_train */
- 0xc7f10b0e,
- 0xb7f10bcc,
-/* 0x074a: memx_info_send */
- 0x21f50100,
- 0x00f80342,
-/* 0x0750: memx_recv */
- 0xf401d6b0,
- 0xd6b0980b,
- 0xd80bf400,
-/* 0x075e: memx_init */
- 0x00f800f8,
-/* 0x0760: perf_recv */
-/* 0x0762: perf_init */
- 0x00f800f8,
-/* 0x0764: i2c_drive_scl */
- 0xf40036b0,
- 0x07f1110b,
- 0x04b607e0,
- 0x0001d006,
- 0x00f804bd,
-/* 0x0778: i2c_drive_scl_lo */
- 0x07e407f1,
- 0xd00604b6,
- 0x04bd0001,
-/* 0x0786: i2c_drive_sda */
- 0x36b000f8,
- 0x110bf400,
- 0x07e007f1,
- 0xd00604b6,
- 0x04bd0002,
-/* 0x079a: i2c_drive_sda_lo */
- 0x07f100f8,
- 0x04b607e4,
- 0x0002d006,
- 0x00f804bd,
-/* 0x07a8: i2c_sense_scl */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0431fd00,
- 0xf4060bf4,
-/* 0x07be: i2c_sense_scl_done */
- 0x00f80131,
-/* 0x07c0: i2c_sense_sda */
- 0xf10132f4,
- 0xb607c437,
- 0x33cf0634,
- 0x0432fd00,
- 0xf4060bf4,
-/* 0x07d6: i2c_sense_sda_done */
- 0x00f80131,
-/* 0x07d8: i2c_raise_scl */
- 0x47f140f9,
- 0x37f00898,
- 0x6421f501,
-/* 0x07e5: i2c_raise_scl_wait */
- 0xe8e7f107,
- 0x7f21f403,
- 0x07a821f5,
- 0xb60901f4,
- 0x1bf40142,
-/* 0x07f9: i2c_raise_scl_done */
- 0xf840fcef,
-/* 0x07fd: i2c_start */
- 0xa821f500,
- 0x0d11f407,
- 0x07c021f5,
- 0xf40611f4,
-/* 0x080e: i2c_start_rep */
- 0x37f0300e,
- 0x6421f500,
- 0x0137f007,
- 0x078621f5,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0xd821f550,
- 0x0464b607,
-/* 0x083b: i2c_start_send */
- 0xf01f11f4,
- 0x21f50037,
- 0xe7f10786,
- 0x21f41388,
- 0x0037f07f,
- 0x076421f5,
- 0x1388e7f1,
-/* 0x0857: i2c_start_out */
- 0xf87f21f4,
-/* 0x0859: i2c_stop */
- 0x0037f000,
- 0x076421f5,
- 0xf50037f0,
- 0xf1078621,
- 0xf403e8e7,
- 0x37f07f21,
- 0x6421f501,
- 0x88e7f107,
- 0x7f21f413,
- 0xf50137f0,
- 0xf1078621,
- 0xf41388e7,
- 0x00f87f21,
-/* 0x088c: i2c_bitw */
- 0x078621f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07d821f5,
- 0xf40464b6,
- 0xe7f11811,
- 0x21f41388,
- 0x0037f07f,
- 0x076421f5,
- 0x1388e7f1,
-/* 0x08cb: i2c_bitw_out */
- 0xf87f21f4,
-/* 0x08cd: i2c_bitr */
- 0x0137f000,
- 0x078621f5,
- 0x03e8e7f1,
- 0xbb7f21f4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07d821f5,
- 0xf40464b6,
- 0x21f51b11,
- 0x37f007c0,
- 0x6421f500,
- 0x88e7f107,
- 0x7f21f413,
- 0xf4013cf0,
-/* 0x0912: i2c_bitr_done */
- 0x00f80131,
-/* 0x0914: i2c_get_byte */
- 0xf00057f0,
-/* 0x091a: i2c_get_byte_next */
- 0x54b60847,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b608cd,
- 0x2b11f404,
- 0xb60553fd,
- 0x1bf40142,
- 0x0137f0d8,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x8c21f550,
- 0x0464b608,
-/* 0x0964: i2c_get_byte_done */
-/* 0x0966: i2c_put_byte */
- 0x47f000f8,
-/* 0x0969: i2c_put_byte_next */
- 0x0142b608,
- 0xbb3854ff,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x088c21f5,
- 0xf40464b6,
- 0x46b03411,
- 0xd81bf400,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0xcd21f550,
- 0x0464b608,
- 0xbb0f11f4,
- 0x36b00076,
- 0x061bf401,
-/* 0x09bf: i2c_put_byte_done */
- 0xf80132f4,
-/* 0x09c1: i2c_addr */
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b607fd,
- 0x2911f404,
- 0x012ec3e7,
- 0xfd0134b6,
- 0x76bb0553,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb6096621,
-/* 0x0a06: i2c_addr_done */
- 0x00f80464,
-/* 0x0a08: i2c_acquire_addr */
- 0xb6f8cec7,
- 0xe0b702e4,
- 0xee980d1c,
-/* 0x0a17: i2c_acquire */
- 0xf500f800,
- 0xf40a0821,
- 0xd9f00421,
- 0x3f21f403,
-/* 0x0a26: i2c_release */
- 0x21f500f8,
- 0x21f40a08,
- 0x03daf004,
- 0xf83f21f4,
-/* 0x0a35: i2c_recv */
- 0x0132f400,
- 0xb6f8c1c7,
- 0x16b00214,
- 0x3a1ff528,
- 0xf413a001,
- 0x0032980c,
- 0x0ccc13a0,
- 0xf4003198,
- 0xd0f90231,
- 0xd0f9e0f9,
- 0x000067f1,
- 0x100063f1,
- 0xbb016792,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x0a1721f5,
- 0xfc0464b6,
- 0x00d6b0d0,
- 0x00b31bf5,
- 0xbb0057f0,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x09c121f5,
- 0xf50464b6,
- 0xc700d011,
- 0x76bbe0c5,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb6096621,
- 0x11f50464,
- 0x57f000ad,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b609c1,
- 0x8a11f504,
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b60914,
- 0x6a11f404,
- 0xbbe05bcb,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x085921f5,
- 0xb90464b6,
- 0x74bd025b,
-/* 0x0b3b: i2c_recv_not_rd08 */
- 0xb0430ef4,
- 0x1bf401d6,
- 0x0057f03d,
- 0x09c121f5,
- 0xc73311f4,
- 0x21f5e0c5,
- 0x11f40966,
- 0x0057f029,
- 0x09c121f5,
- 0xc71f11f4,
- 0x21f5e0b5,
- 0x11f40966,
- 0x5921f515,
- 0xc774bd08,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0b7b: i2c_recv_not_wr08 */
-/* 0x0b7b: i2c_recv_done */
- 0xc7030ef4,
- 0x21f5f8ce,
- 0xe0fc0a26,
- 0x12f4d0fc,
- 0x027cb90a,
- 0x034221f5,
-/* 0x0b90: i2c_recv_exit */
-/* 0x0b92: i2c_init */
- 0x00f800f8,
-/* 0x0b94: test_recv */
- 0x05d817f1,
- 0xcf0614b6,
- 0x10b60011,
- 0xd807f101,
- 0x0604b605,
- 0xbd0001d0,
- 0x00e7f104,
- 0x4fe3f1d9,
- 0x6221f513,
-/* 0x0bbb: test_init */
- 0xf100f802,
- 0xf50800e7,
- 0xf8026221,
-/* 0x0bc5: idle_recv */
-/* 0x0bc7: idle */
- 0xf400f800,
- 0x17f10031,
- 0x14b605d4,
- 0x0011cf06,
- 0xf10110b6,
- 0xb605d407,
- 0x01d00604,
-/* 0x0be3: idle_loop */
- 0xf004bd00,
- 0x32f45817,
-/* 0x0be9: idle_proc */
-/* 0x0be9: idle_proc_exec */
- 0xb910f902,
- 0x21f5021e,
- 0x10fc034b,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0bfd: idle_proc_next */
- 0x5810b6ef,
- 0xf4061fb8,
- 0x02f4e61b,
- 0x0028f4dd,
- 0x00bb0ef4,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc
deleted file mode 100644
index b85443261569..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#define NVKM_PPWR_CHIPSET GF119
-#define HW_TICKS_PER_US 324
-
-//#define NVKM_FALCON_PC24
-#define NVKM_FALCON_UNSHIFTED_IO
-//#define NVKM_FALCON_MMIO_UAS
-//#define NVKM_FALCON_MMIO_TRAP
-
-#include "macros.fuc"
-
-.section #nvd0_pwr_data
-#define INCLUDE_PROC
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_PROC
-
-#define INCLUDE_DATA
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_DATA
-.align 256
-
-.section #nvd0_pwr_code
-#define INCLUDE_CODE
-#include "kernel.fuc"
-#include "arith.fuc"
-#include "host.fuc"
-#include "memx.fuc"
-#include "perf.fuc"
-#include "i2c_.fuc"
-#include "test.fuc"
-#include "idle.fuc"
-#undef INCLUDE_CODE
-.align 256
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
deleted file mode 100644
index 7e16aab44d85..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/nvd0.fuc.h
+++ /dev/null
@@ -1,1795 +0,0 @@
-uint32_t nvd0_pwr_data[] = {
-/* 0x0000: proc_kern */
- 0x52544e49,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0058: proc_list_head */
- 0x54534f48,
- 0x0000049d,
- 0x00000446,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x584d454d,
- 0x0000068b,
- 0x0000067d,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x46524550,
- 0x0000068f,
- 0x0000068d,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x5f433249,
- 0x00000aaa,
- 0x0000094d,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x54534554,
- 0x00000acd,
- 0x00000aac,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x454c4449,
- 0x00000ad9,
- 0x00000ad7,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0268: proc_list_tail */
-/* 0x0268: time_prev */
- 0x00000000,
-/* 0x026c: time_next */
- 0x00000000,
-/* 0x0270: fifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x02f0: rfifo_queue */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0370: memx_func_head */
- 0x00000001,
- 0x00000000,
- 0x000004d3,
-/* 0x037c: memx_func_next */
- 0x00000002,
- 0x00000000,
- 0x00000554,
- 0x00000003,
- 0x00000002,
- 0x000005d8,
- 0x00040004,
- 0x00000000,
- 0x000005f4,
- 0x00010005,
- 0x00000000,
- 0x0000060e,
- 0x00010006,
- 0x00000000,
- 0x000005d3,
- 0x00000007,
- 0x00000000,
- 0x00000619,
-/* 0x03c4: memx_func_tail */
-/* 0x03c4: memx_ts_start */
- 0x00000000,
-/* 0x03c8: memx_ts_end */
- 0x00000000,
-/* 0x03cc: memx_data_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0bcc: memx_data_tail */
-/* 0x0bcc: memx_train_head */
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-/* 0x0ccc: memx_train_tail */
-/* 0x0ccc: i2c_scl_map */
- 0x00000400,
- 0x00000800,
- 0x00001000,
- 0x00002000,
- 0x00004000,
- 0x00008000,
- 0x00010000,
- 0x00020000,
- 0x00040000,
- 0x00080000,
-/* 0x0cf4: i2c_sda_map */
- 0x00100000,
- 0x00200000,
- 0x00400000,
- 0x00800000,
- 0x01000000,
- 0x02000000,
- 0x04000000,
- 0x08000000,
- 0x10000000,
- 0x20000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
-
-uint32_t nvd0_pwr_code[] = {
- 0x034d0ef5,
-/* 0x0004: rd32 */
- 0x07a007f1,
- 0xbd000ed0,
- 0x01d7f004,
- 0xf101d3f0,
- 0xd007ac07,
- 0x04bd000d,
-/* 0x001c: rd32_wait */
- 0x07acd7f1,
- 0xf100ddcf,
- 0xf47000d4,
- 0xd7f1f51b,
- 0xddcf07a4,
-/* 0x0033: wr32 */
- 0xf100f800,
- 0xd007a007,
- 0x04bd000e,
- 0x07a407f1,
- 0xbd000dd0,
- 0x02d7f004,
- 0xf0f0d5f0,
- 0x07f101d3,
- 0x0dd007ac,
-/* 0x0057: wr32_wait */
- 0xf104bd00,
- 0xcf07acd7,
- 0xd4f100dd,
- 0x1bf47000,
-/* 0x0067: nsec */
- 0xf900f8f5,
- 0xf080f990,
- 0x88cf2c87,
-/* 0x0071: nsec_loop */
- 0x2c97f000,
- 0xbb0099cf,
- 0x9eb80298,
- 0xf41ef406,
- 0x90fc80fc,
-/* 0x0086: wait */
- 0x90f900f8,
- 0x87f080f9,
- 0x0088cf2c,
-/* 0x0090: wait_loop */
- 0xf402eeb9,
- 0xdab90421,
- 0x04adfd02,
- 0xf406acb8,
- 0x97f0120b,
- 0x0099cf2c,
- 0xb80298bb,
- 0x1ef4069b,
-/* 0x00b1: wait_done */
- 0xfc80fce2,
-/* 0x00b7: intr_watchdog */
- 0x9800f890,
- 0x96b003e9,
- 0x2a0bf400,
- 0xbb9a0a98,
- 0x1cf4029a,
- 0x01d7f00f,
- 0x028c21f5,
- 0x0ef494bd,
-/* 0x00d5: intr_watchdog_next_time */
- 0x9b0a9815,
- 0xf400a6b0,
- 0x9ab8090b,
- 0x061cf406,
-/* 0x00e4: intr_watchdog_next_time_set */
-/* 0x00e7: intr_watchdog_next_proc */
- 0x809b0980,
- 0xe0b603e9,
- 0x68e6b158,
- 0xc61bf402,
-/* 0x00f6: intr */
- 0x00f900f8,
- 0x80f904bd,
- 0xa0f990f9,
- 0xc0f9b0f9,
- 0xe0f9d0f9,
- 0xf7f0f0f9,
- 0x0188fe00,
- 0x87f180f9,
- 0x88cf05d0,
- 0x0180b600,
- 0x05d007f1,
- 0xbd0008d0,
- 0x0887f004,
- 0xc40088cf,
- 0x0bf40289,
- 0x9b008020,
- 0xf458e7f0,
- 0x0998b721,
- 0x0096b09b,
- 0xf00e0bf4,
- 0x09d03407,
- 0x8004bd00,
-/* 0x014e: intr_skip_watchdog */
- 0x89e49a09,
- 0x0bf40800,
- 0x8897f13c,
- 0x0099cf06,
- 0xf4029ac4,
- 0xc7f1260b,
- 0xcccf04c0,
- 0xf1c0f900,
- 0xf14f48e7,
- 0xf05453e3,
- 0x21f500d7,
- 0xc0fc02f1,
- 0x04c007f1,
- 0xbd000cd0,
-/* 0x0185: intr_subintr_skip_fifo */
- 0x8807f104,
- 0x0009d006,
-/* 0x018e: intr_skip_subintr */
- 0x89c404bd,
- 0x070bf420,
- 0xffbfa4f1,
-/* 0x0198: intr_skip_pause */
- 0xf44089c4,
- 0xa4f1070b,
-/* 0x01a2: intr_skip_user0 */
- 0x07f0ffbf,
- 0x0008d004,
- 0x80fc04bd,
- 0xfc0088fe,
- 0xfce0fcf0,
- 0xfcc0fcd0,
- 0xfca0fcb0,
- 0xfc80fc90,
- 0x0032f400,
-/* 0x01c6: ticks_from_ns */
- 0xc0f901f8,
- 0xd7f1b0f9,
- 0xd3f00144,
- 0xb321f500,
- 0xe8ccec03,
- 0x00b4b003,
- 0xec120bf4,
- 0xf103e8ee,
- 0xf00144d7,
- 0x21f500d3,
-/* 0x01ee: ticks_from_ns_quit */
- 0xceb903b3,
- 0xfcb0fc02,
-/* 0x01f7: ticks_from_us */
- 0xf900f8c0,
- 0xf1b0f9c0,
- 0xf00144d7,
- 0x21f500d3,
- 0xceb903b3,
- 0x00b4b002,
- 0xbd050bf4,
-/* 0x0211: ticks_from_us_quit */
- 0xfcb0fce4,
-/* 0x0217: ticks_to_us */
- 0xf100f8c0,
- 0xf00144d7,
- 0xedff00d3,
-/* 0x0223: timer */
- 0xf900f8ec,
- 0xf480f990,
- 0xf8981032,
- 0x0086b003,
- 0xbd531cf4,
- 0x3807f084,
- 0xbd0008d0,
- 0x3487f004,
- 0x980088cf,
- 0x98bb9a09,
- 0x00e9bb02,
- 0xf003fe80,
- 0x88cf0887,
- 0x0284f000,
- 0xf0201bf4,
- 0x88cf3487,
- 0x06e0b800,
- 0xb8090bf4,
- 0x1cf406e8,
-/* 0x026d: timer_reset */
- 0x3407f00e,
- 0xbd000ed0,
- 0x9a0e8004,
-/* 0x0278: timer_enable */
- 0xf00187f0,
- 0x08d03807,
-/* 0x0283: timer_done */
- 0xf404bd00,
- 0x80fc1031,
- 0x00f890fc,
-/* 0x028c: send_proc */
- 0x90f980f9,
- 0x9805e898,
- 0x86f004e9,
- 0x0689b804,
- 0xc42a0bf4,
- 0x88940398,
- 0x1880b604,
- 0x98008ebb,
- 0x8a8000fa,
- 0x018d8000,
- 0x80028c80,
- 0x90b6038b,
- 0x0794f001,
- 0xf404e980,
-/* 0x02c6: send_done */
- 0x90fc0231,
- 0x00f880fc,
-/* 0x02cc: find */
- 0x87f080f9,
- 0x0131f458,
-/* 0x02d4: find_loop */
- 0xb8008a98,
- 0x0bf406ae,
- 0x5880b610,
- 0x026886b1,
- 0xf4f01bf4,
-/* 0x02ea: find_done */
- 0x8eb90132,
- 0xf880fc02,
-/* 0x02f1: send */
- 0xcc21f500,
- 0x9701f402,
-/* 0x02fa: recv */
- 0x90f900f8,
- 0xe89880f9,
- 0x04e99805,
- 0xb80132f4,
- 0x0bf40689,
- 0x0389c43d,
- 0xf00180b6,
- 0xe8800784,
- 0x02ea9805,
- 0x8ffef0f9,
- 0xb9f0f901,
- 0x999402ef,
- 0x00e9bb04,
- 0x9818e0b6,
- 0xec9803eb,
- 0x01ed9802,
- 0xf900ee98,
- 0xfef0fca5,
- 0x31f400f8,
-/* 0x0347: recv_done */
- 0xfcf0fc01,
- 0xf890fc80,
-/* 0x034d: init */
- 0x0817f100,
- 0x0011cf01,
- 0x010911e7,
- 0xfe0814b6,
- 0x17f10014,
- 0x13f000e0,
- 0x1c07f000,
- 0xbd0001d0,
- 0xff17f004,
- 0xd01407f0,
- 0x04bd0001,
- 0xf10217f0,
- 0xf0080015,
- 0x01d01007,
- 0xf104bd00,
- 0xf000f617,
- 0x10fe0013,
- 0x1031f400,
- 0xf00117f0,
- 0x01d03807,
- 0xf004bd00,
-/* 0x03a2: init_proc */
- 0xf19858f7,
- 0x0016b001,
- 0xf9fa0bf4,
- 0x58f0b615,
-/* 0x03b3: mulu32_32_64 */
- 0xf9f20ef4,
- 0xf920f910,
- 0x9540f930,
- 0xd29510e1,
- 0xbdc4bd10,
- 0xc0edffb4,
- 0xb9301dff,
- 0x34f10234,
- 0x34b6ffff,
- 0x1045b610,
- 0xbb00c3bb,
- 0xe2ff01b4,
- 0x0234b930,
- 0xffff34f1,
- 0xb61034b6,
- 0xc3bb1045,
- 0x01b4bb00,
- 0xbb3012ff,
- 0x40fc00b3,
- 0x20fc30fc,
- 0x00f810fc,
-/* 0x0404: host_send */
- 0x04b017f1,
- 0xf10011cf,
- 0xcf04a027,
- 0x12b80022,
- 0x2f0bf406,
- 0x94071ec4,
- 0xe0b704ee,
- 0xeb980270,
- 0x02ec9803,
- 0x9801ed98,
- 0x21f500ee,
- 0x10b602f1,
- 0x0f1ec401,
- 0x04b007f1,
- 0xbd000ed0,
- 0xc30ef404,
-/* 0x0444: host_send_done */
-/* 0x0446: host_recv */
- 0x17f100f8,
- 0x13f14e49,
- 0xe1b85254,
- 0xb30bf406,
-/* 0x0454: host_recv_wait */
- 0x04cc17f1,
- 0xf10011cf,
- 0xcf04c827,
- 0x16f00022,
- 0x0612b808,
- 0xc4ec0bf4,
- 0x34b60723,
- 0xf030b704,
- 0x033b8002,
- 0x80023c80,
- 0x3e80013d,
- 0x0120b600,
- 0xf10f24f0,
- 0xd004c807,
- 0x04bd0002,
- 0xf04027f0,
- 0x02d00007,
- 0xf804bd00,
-/* 0x049d: host_init */
- 0x8017f100,
- 0x1014b600,
- 0x027015f1,
- 0x04d007f1,
- 0xbd0001d0,
- 0x8017f104,
- 0x1014b600,
- 0x02f015f1,
- 0x04dc07f1,
- 0xbd0001d0,
- 0x0117f004,
- 0x04c407f1,
- 0xbd0001d0,
-/* 0x04d3: memx_func_enter */
- 0xf100f804,
- 0xf1162067,
- 0xf1f55d77,
- 0xb9ffff73,
- 0x21f4026e,
- 0x02d8b904,
- 0xf90487fd,
- 0xfc80f960,
- 0xf4e0fcd0,
- 0x77f13321,
- 0x73f1fffe,
- 0x6eb9ffff,
- 0x0421f402,
- 0xfd02d8b9,
- 0x60f90487,
- 0xd0fc80f9,
- 0x21f4e0fc,
- 0xf067f133,
- 0x026eb926,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f904,
- 0xfcd0fc80,
- 0x3321f4e0,
- 0xf10467f0,
- 0xd007e007,
- 0x04bd0006,
-/* 0x053c: memx_func_enter_wait */
- 0x07c067f1,
- 0xf00066cf,
- 0x0bf40464,
- 0x2c67f0f6,
- 0x800066cf,
- 0x00f8f106,
-/* 0x0554: memx_func_leave */
- 0xcf2c67f0,
- 0x06800066,
- 0x0467f0f2,
- 0x07e407f1,
- 0xbd0006d0,
-/* 0x0569: memx_func_leave_wait */
- 0xc067f104,
- 0x0066cf07,
- 0xf40464f0,
- 0x67f1f61b,
- 0x77f126f0,
- 0x73f00001,
- 0x026eb900,
- 0xb90421f4,
- 0x87fd02d8,
- 0xf960f905,
- 0xfcd0fc80,
- 0x3321f4e0,
- 0x162067f1,
- 0xf4026eb9,
- 0xd8b90421,
- 0x0587fd02,
- 0x80f960f9,
- 0xe0fcd0fc,
- 0xf13321f4,
- 0xf00aa277,
- 0x6eb90073,
- 0x0421f402,
- 0xfd02d8b9,
- 0x60f90587,
- 0xd0fc80f9,
- 0x21f4e0fc,
-/* 0x05d3: memx_func_wait_vblank */
- 0xb600f833,
- 0x00f80410,
-/* 0x05d8: memx_func_wr32 */
- 0x98001698,
- 0x10b60115,
- 0xf960f908,
- 0xfcd0fc50,
- 0x3321f4e0,
- 0xf40242b6,
- 0x00f8e91b,
-/* 0x05f4: memx_func_wait */
- 0xcf2c87f0,
- 0x1e980088,
- 0x011d9800,
- 0x98021c98,
- 0x10b6031b,
- 0x8621f410,
-/* 0x060e: memx_func_delay */
- 0x1e9800f8,
- 0x0410b600,
- 0xf86721f4,
-/* 0x0619: memx_func_train */
-/* 0x061b: memx_exec */
- 0xf900f800,
- 0xb9d0f9e0,
- 0xb2b902c1,
-/* 0x0625: memx_exec_next */
- 0x00139802,
- 0xe70410b6,
- 0xe701f034,
- 0xb601e033,
- 0x30f00132,
- 0xde35980c,
- 0x12b855f9,
- 0xe41ef406,
- 0x98f10b98,
- 0xcbbbf20c,
- 0xc4b7f102,
- 0x00bbcf07,
- 0xe0fcd0fc,
- 0x02f121f5,
-/* 0x065e: memx_info */
- 0xc67000f8,
- 0x0e0bf401,
-/* 0x0664: memx_info_data */
- 0x03ccc7f1,
- 0x0800b7f1,
-/* 0x066f: memx_info_train */
- 0xf10b0ef4,
- 0xf10bccc7,
-/* 0x0677: memx_info_send */
- 0xf50100b7,
- 0xf802f121,
-/* 0x067d: memx_recv */
- 0x01d6b000,
- 0xb09b0bf4,
- 0x0bf400d6,
-/* 0x068b: memx_init */
- 0xf800f8d8,
-/* 0x068d: perf_recv */
-/* 0x068f: perf_init */
- 0xf800f800,
-/* 0x0691: i2c_drive_scl */
- 0x0036b000,
- 0xf10e0bf4,
- 0xd007e007,
- 0x04bd0001,
-/* 0x06a2: i2c_drive_scl_lo */
- 0x07f100f8,
- 0x01d007e4,
- 0xf804bd00,
-/* 0x06ad: i2c_drive_sda */
- 0x0036b000,
- 0xf10e0bf4,
- 0xd007e007,
- 0x04bd0002,
-/* 0x06be: i2c_drive_sda_lo */
- 0x07f100f8,
- 0x02d007e4,
- 0xf804bd00,
-/* 0x06c9: i2c_sense_scl */
- 0x0132f400,
- 0x07c437f1,
- 0xfd0033cf,
- 0x0bf40431,
- 0x0131f406,
-/* 0x06dc: i2c_sense_scl_done */
-/* 0x06de: i2c_sense_sda */
- 0x32f400f8,
- 0xc437f101,
- 0x0033cf07,
- 0xf40432fd,
- 0x31f4060b,
-/* 0x06f1: i2c_sense_sda_done */
-/* 0x06f3: i2c_raise_scl */
- 0xf900f801,
- 0x9847f140,
- 0x0137f008,
- 0x069121f5,
-/* 0x0700: i2c_raise_scl_wait */
- 0x03e8e7f1,
- 0xf56721f4,
- 0xf406c921,
- 0x42b60901,
- 0xef1bf401,
-/* 0x0714: i2c_raise_scl_done */
- 0x00f840fc,
-/* 0x0718: i2c_start */
- 0x06c921f5,
- 0xf50d11f4,
- 0xf406de21,
- 0x0ef40611,
-/* 0x0729: i2c_start_rep */
- 0x0037f030,
- 0x069121f5,
- 0xf50137f0,
- 0xbb06ad21,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x06f321f5,
- 0xf40464b6,
-/* 0x0756: i2c_start_send */
- 0x37f01f11,
- 0xad21f500,
- 0x88e7f106,
- 0x6721f413,
- 0xf50037f0,
- 0xf1069121,
- 0xf41388e7,
-/* 0x0772: i2c_start_out */
- 0x00f86721,
-/* 0x0774: i2c_stop */
- 0xf50037f0,
- 0xf0069121,
- 0x21f50037,
- 0xe7f106ad,
- 0x21f403e8,
- 0x0137f067,
- 0x069121f5,
- 0x1388e7f1,
- 0xf06721f4,
- 0x21f50137,
- 0xe7f106ad,
- 0x21f41388,
-/* 0x07a7: i2c_bitw */
- 0xf500f867,
- 0xf106ad21,
- 0xf403e8e7,
- 0x76bb6721,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb606f321,
- 0x11f40464,
- 0x88e7f118,
- 0x6721f413,
- 0xf50037f0,
- 0xf1069121,
- 0xf41388e7,
-/* 0x07e6: i2c_bitw_out */
- 0x00f86721,
-/* 0x07e8: i2c_bitr */
- 0xf50137f0,
- 0xf106ad21,
- 0xf403e8e7,
- 0x76bb6721,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb606f321,
- 0x11f40464,
- 0xde21f51b,
- 0x0037f006,
- 0x069121f5,
- 0x1388e7f1,
- 0xf06721f4,
- 0x31f4013c,
-/* 0x082d: i2c_bitr_done */
-/* 0x082f: i2c_get_byte */
- 0xf000f801,
- 0x47f00057,
-/* 0x0835: i2c_get_byte_next */
- 0x0154b608,
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0xe821f550,
- 0x0464b607,
- 0xfd2b11f4,
- 0x42b60553,
- 0xd81bf401,
- 0xbb0137f0,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07a721f5,
-/* 0x087f: i2c_get_byte_done */
- 0xf80464b6,
-/* 0x0881: i2c_put_byte */
- 0x0847f000,
-/* 0x0884: i2c_put_byte_next */
- 0xff0142b6,
- 0x76bb3854,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb607a721,
- 0x11f40464,
- 0x0046b034,
- 0xbbd81bf4,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x07e821f5,
- 0xf40464b6,
- 0x76bb0f11,
- 0x0136b000,
- 0xf4061bf4,
-/* 0x08da: i2c_put_byte_done */
- 0x00f80132,
-/* 0x08dc: i2c_addr */
- 0xb60076bb,
- 0x50f90465,
- 0xbb046594,
- 0x50bd0256,
- 0xfc0475fd,
- 0x1821f550,
- 0x0464b607,
- 0xe72911f4,
- 0xb6012ec3,
- 0x53fd0134,
- 0x0076bb05,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b60881,
-/* 0x0921: i2c_addr_done */
-/* 0x0923: i2c_acquire_addr */
- 0xc700f804,
- 0xe4b6f8ce,
- 0x14e0b705,
-/* 0x092f: i2c_acquire */
- 0xf500f8d0,
- 0xf4092321,
- 0xd9f00421,
- 0x3321f403,
-/* 0x093e: i2c_release */
- 0x21f500f8,
- 0x21f40923,
- 0x03daf004,
- 0xf83321f4,
-/* 0x094d: i2c_recv */
- 0x0132f400,
- 0xb6f8c1c7,
- 0x16b00214,
- 0x3a1ff528,
- 0xf413a001,
- 0x0032980c,
- 0x0ccc13a0,
- 0xf4003198,
- 0xd0f90231,
- 0xd0f9e0f9,
- 0x000067f1,
- 0x100063f1,
- 0xbb016792,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x092f21f5,
- 0xfc0464b6,
- 0x00d6b0d0,
- 0x00b31bf5,
- 0xbb0057f0,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x08dc21f5,
- 0xf50464b6,
- 0xc700d011,
- 0x76bbe0c5,
- 0x0465b600,
- 0x659450f9,
- 0x0256bb04,
- 0x75fd50bd,
- 0xf550fc04,
- 0xb6088121,
- 0x11f50464,
- 0x57f000ad,
- 0x0076bb01,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b608dc,
- 0x8a11f504,
- 0x0076bb00,
- 0xf90465b6,
- 0x04659450,
- 0xbd0256bb,
- 0x0475fd50,
- 0x21f550fc,
- 0x64b6082f,
- 0x6a11f404,
- 0xbbe05bcb,
- 0x65b60076,
- 0x9450f904,
- 0x56bb0465,
- 0xfd50bd02,
- 0x50fc0475,
- 0x077421f5,
- 0xb90464b6,
- 0x74bd025b,
-/* 0x0a53: i2c_recv_not_rd08 */
- 0xb0430ef4,
- 0x1bf401d6,
- 0x0057f03d,
- 0x08dc21f5,
- 0xc73311f4,
- 0x21f5e0c5,
- 0x11f40881,
- 0x0057f029,
- 0x08dc21f5,
- 0xc71f11f4,
- 0x21f5e0b5,
- 0x11f40881,
- 0x7421f515,
- 0xc774bd07,
- 0x1bf408c5,
- 0x0232f409,
-/* 0x0a93: i2c_recv_not_wr08 */
-/* 0x0a93: i2c_recv_done */
- 0xc7030ef4,
- 0x21f5f8ce,
- 0xe0fc093e,
- 0x12f4d0fc,
- 0x027cb90a,
- 0x02f121f5,
-/* 0x0aa8: i2c_recv_exit */
-/* 0x0aaa: i2c_init */
- 0x00f800f8,
-/* 0x0aac: test_recv */
- 0x05d817f1,
- 0xb60011cf,
- 0x07f10110,
- 0x01d005d8,
- 0xf104bd00,
- 0xf1d900e7,
- 0xf5134fe3,
- 0xf8022321,
-/* 0x0acd: test_init */
- 0x00e7f100,
- 0x2321f508,
-/* 0x0ad7: idle_recv */
- 0xf800f802,
-/* 0x0ad9: idle */
- 0x0031f400,
- 0x05d417f1,
- 0xb60011cf,
- 0x07f10110,
- 0x01d005d4,
-/* 0x0aef: idle_loop */
- 0xf004bd00,
- 0x32f45817,
-/* 0x0af5: idle_proc */
-/* 0x0af5: idle_proc_exec */
- 0xb910f902,
- 0x21f5021e,
- 0x10fc02fa,
- 0xf40911f4,
- 0x0ef40231,
-/* 0x0b09: idle_proc_next */
- 0x5810b6ef,
- 0xf4061fb8,
- 0x02f4e61b,
- 0x0028f4dd,
- 0x00c10ef4,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
- 0x00000000,
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c
deleted file mode 100644
index d76612999b9f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/gk104.c
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-#define nvd0_pwr_code gk104_pwr_code
-#define nvd0_pwr_data gk104_pwr_data
-#include "fuc/nvd0.fuc.h"
-
-static void
-gk104_pwr_pgob(struct nouveau_pwr *ppwr, bool enable)
-{
- nv_mask(ppwr, 0x000200, 0x00001000, 0x00000000);
- nv_rd32(ppwr, 0x000200);
- nv_mask(ppwr, 0x000200, 0x08000000, 0x08000000);
- msleep(50);
-
- nv_mask(ppwr, 0x10a78c, 0x00000002, 0x00000002);
- nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000001);
- nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000000);
-
- nv_mask(ppwr, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000);
- msleep(50);
-
- nv_mask(ppwr, 0x10a78c, 0x00000002, 0x00000000);
- nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000001);
- nv_mask(ppwr, 0x10a78c, 0x00000001, 0x00000000);
-
- nv_mask(ppwr, 0x000200, 0x08000000, 0x00000000);
- nv_mask(ppwr, 0x000200, 0x00001000, 0x00001000);
- nv_rd32(ppwr, 0x000200);
-}
-
-struct nouveau_oclass *
-gk104_pwr_oclass = &(struct nvkm_pwr_impl) {
- .base.handle = NV_SUBDEV(PWR, 0xe4),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_pwr_ctor,
- .dtor = _nouveau_pwr_dtor,
- .init = _nouveau_pwr_init,
- .fini = _nouveau_pwr_fini,
- },
- .code.data = gk104_pwr_code,
- .code.size = sizeof(gk104_pwr_code),
- .data.data = gk104_pwr_data,
- .data.size = sizeof(gk104_pwr_data),
- .pgob = gk104_pwr_pgob,
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
deleted file mode 100644
index 7a9299d7159f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/memx.c
+++ /dev/null
@@ -1,201 +0,0 @@
-#ifndef __NVKM_PWR_MEMX_H__
-#define __NVKM_PWR_MEMX_H__
-
-#include "priv.h"
-
-struct nouveau_memx {
- struct nouveau_pwr *ppwr;
- u32 base;
- u32 size;
- struct {
- u32 mthd;
- u32 size;
- u32 data[64];
- } c;
-};
-
-static void
-memx_out(struct nouveau_memx *memx)
-{
- struct nouveau_pwr *ppwr = memx->ppwr;
- int i;
-
- if (memx->c.mthd) {
- nv_wr32(ppwr, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd);
- for (i = 0; i < memx->c.size; i++)
- nv_wr32(ppwr, 0x10a1c4, memx->c.data[i]);
- memx->c.mthd = 0;
- memx->c.size = 0;
- }
-}
-
-static void
-memx_cmd(struct nouveau_memx *memx, u32 mthd, u32 size, u32 data[])
-{
- if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) ||
- (memx->c.mthd && memx->c.mthd != mthd))
- memx_out(memx);
- memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0]));
- memx->c.size += size;
- memx->c.mthd = mthd;
-}
-
-int
-nouveau_memx_init(struct nouveau_pwr *ppwr, struct nouveau_memx **pmemx)
-{
- struct nouveau_memx *memx;
- u32 reply[2];
- int ret;
-
- ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
- MEMX_INFO_DATA, 0);
- if (ret)
- return ret;
-
- memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL);
- if (!memx)
- return -ENOMEM;
- memx->ppwr = ppwr;
- memx->base = reply[0];
- memx->size = reply[1];
-
- /* acquire data segment access */
- do {
- nv_wr32(ppwr, 0x10a580, 0x00000003);
- } while (nv_rd32(ppwr, 0x10a580) != 0x00000003);
- nv_wr32(ppwr, 0x10a1c0, 0x01000000 | memx->base);
-
- return 0;
-}
-
-int
-nouveau_memx_fini(struct nouveau_memx **pmemx, bool exec)
-{
- struct nouveau_memx *memx = *pmemx;
- struct nouveau_pwr *ppwr = memx->ppwr;
- u32 finish, reply[2];
-
- /* flush the cache... */
- memx_out(memx);
-
- /* release data segment access */
- finish = nv_rd32(ppwr, 0x10a1c0) & 0x00ffffff;
- nv_wr32(ppwr, 0x10a580, 0x00000000);
-
- /* call MEMX process to execute the script, and wait for reply */
- if (exec) {
- ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_EXEC,
- memx->base, finish);
- }
-
- nv_debug(memx->ppwr, "Exec took %uns, PPWR_IN %08x\n",
- reply[0], reply[1]);
- kfree(memx);
- return 0;
-}
-
-void
-nouveau_memx_wr32(struct nouveau_memx *memx, u32 addr, u32 data)
-{
- nv_debug(memx->ppwr, "R[%06x] = 0x%08x\n", addr, data);
- memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data });
-}
-
-void
-nouveau_memx_wait(struct nouveau_memx *memx,
- u32 addr, u32 mask, u32 data, u32 nsec)
-{
- nv_debug(memx->ppwr, "R[%06x] & 0x%08x == 0x%08x, %d us\n",
- addr, mask, data, nsec);
- memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec });
- memx_out(memx); /* fuc can't handle multiple */
-}
-
-void
-nouveau_memx_nsec(struct nouveau_memx *memx, u32 nsec)
-{
- nv_debug(memx->ppwr, " DELAY = %d ns\n", nsec);
- memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec });
- memx_out(memx); /* fuc can't handle multiple */
-}
-
-void
-nouveau_memx_wait_vblank(struct nouveau_memx *memx)
-{
- struct nouveau_pwr *ppwr = memx->ppwr;
- u32 heads, x, y, px = 0;
- int i, head_sync;
-
- if (nv_device(ppwr)->chipset < 0xd0) {
- heads = nv_rd32(ppwr, 0x610050);
- for (i = 0; i < 2; i++) {
- /* Heuristic: sync to head with biggest resolution */
- if (heads & (2 << (i << 3))) {
- x = nv_rd32(ppwr, 0x610b40 + (0x540 * i));
- y = (x & 0xffff0000) >> 16;
- x &= 0x0000ffff;
- if ((x * y) > px) {
- px = (x * y);
- head_sync = i;
- }
- }
- }
- }
-
- if (px == 0) {
- nv_debug(memx->ppwr, "WAIT VBLANK !NO ACTIVE HEAD\n");
- return;
- }
-
- nv_debug(memx->ppwr, "WAIT VBLANK HEAD%d\n", head_sync);
- memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync });
- memx_out(memx); /* fuc can't handle multiple */
-}
-
-void
-nouveau_memx_train(struct nouveau_memx *memx)
-{
- nv_debug(memx->ppwr, " MEM TRAIN\n");
- memx_cmd(memx, MEMX_TRAIN, 0, NULL);
-}
-
-int
-nouveau_memx_train_result(struct nouveau_pwr *ppwr, u32 *res, int rsize)
-{
- u32 reply[2], base, size, i;
- int ret;
-
- ret = ppwr->message(ppwr, reply, PROC_MEMX, MEMX_MSG_INFO,
- MEMX_INFO_TRAIN, 0);
- if (ret)
- return ret;
-
- base = reply[0];
- size = reply[1] >> 2;
- if (size > rsize)
- return -ENOMEM;
-
- /* read the packet */
- nv_wr32(ppwr, 0x10a1c0, 0x02000000 | base);
-
- for (i = 0; i < size; i++)
- res[i] = nv_rd32(ppwr, 0x10a1c4);
-
- return 0;
-}
-
-void
-nouveau_memx_block(struct nouveau_memx *memx)
-{
- nv_debug(memx->ppwr, " HOST BLOCKED\n");
- memx_cmd(memx, MEMX_ENTER, 0, NULL);
-}
-
-void
-nouveau_memx_unblock(struct nouveau_memx *memx)
-{
- nv_debug(memx->ppwr, " HOST UNBLOCKED\n");
- memx_cmd(memx, MEMX_LEAVE, 0, NULL);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c
deleted file mode 100644
index 04ff7c3c34e9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nv108.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nv108.fuc.h"
-
-struct nouveau_oclass *
-nv108_pwr_oclass = &(struct nvkm_pwr_impl) {
- .base.handle = NV_SUBDEV(PWR, 0x00),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_pwr_ctor,
- .dtor = _nouveau_pwr_dtor,
- .init = _nouveau_pwr_init,
- .fini = _nouveau_pwr_fini,
- },
- .code.data = nv108_pwr_code,
- .code.size = sizeof(nv108_pwr_code),
- .data.data = nv108_pwr_data,
- .data.size = sizeof(nv108_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c
deleted file mode 100644
index 998d53076b8b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nva3.c
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nva3.fuc.h"
-
-static int
-nva3_pwr_init(struct nouveau_object *object)
-{
- struct nouveau_pwr *ppwr = (void *)object;
- nv_mask(ppwr, 0x022210, 0x00000001, 0x00000000);
- nv_mask(ppwr, 0x022210, 0x00000001, 0x00000001);
- return nouveau_pwr_init(ppwr);
-}
-
-struct nouveau_oclass *
-nva3_pwr_oclass = &(struct nvkm_pwr_impl) {
- .base.handle = NV_SUBDEV(PWR, 0xa3),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_pwr_ctor,
- .dtor = _nouveau_pwr_dtor,
- .init = nva3_pwr_init,
- .fini = _nouveau_pwr_fini,
- },
- .code.data = nva3_pwr_code,
- .code.size = sizeof(nva3_pwr_code),
- .data.data = nva3_pwr_data,
- .data.size = sizeof(nva3_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c
deleted file mode 100644
index 9a773e66efa4..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvc0.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nvc0.fuc.h"
-
-struct nouveau_oclass *
-nvc0_pwr_oclass = &(struct nvkm_pwr_impl) {
- .base.handle = NV_SUBDEV(PWR, 0xc0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_pwr_ctor,
- .dtor = _nouveau_pwr_dtor,
- .init = _nouveau_pwr_init,
- .fini = _nouveau_pwr_fini,
- },
- .code.data = nvc0_pwr_code,
- .code.size = sizeof(nvc0_pwr_code),
- .data.data = nvc0_pwr_data,
- .data.size = sizeof(nvc0_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c
deleted file mode 100644
index 2b29be5d08ac..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/nvd0.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-#include "fuc/nvd0.fuc.h"
-
-struct nouveau_oclass *
-nvd0_pwr_oclass = &(struct nvkm_pwr_impl) {
- .base.handle = NV_SUBDEV(PWR, 0xd0),
- .base.ofuncs = &(struct nouveau_ofuncs) {
- .ctor = _nouveau_pwr_ctor,
- .dtor = _nouveau_pwr_dtor,
- .init = _nouveau_pwr_init,
- .fini = _nouveau_pwr_fini,
- },
- .code.data = nvd0_pwr_code,
- .code.size = sizeof(nvd0_pwr_code),
- .data.data = nvd0_pwr_data,
- .data.size = sizeof(nvd0_pwr_data),
-}.base;
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h b/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h
deleted file mode 100644
index 3814a341db32..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/priv.h
+++ /dev/null
@@ -1,44 +0,0 @@
-#ifndef __NVKM_PWR_PRIV_H__
-#define __NVKM_PWR_PRIV_H__
-
-#include <subdev/pwr.h>
-#include <subdev/pwr/fuc/os.h>
-
-#define nouveau_pwr_create(p, e, o, d) \
- nouveau_pwr_create_((p), (e), (o), sizeof(**d), (void **)d)
-#define nouveau_pwr_destroy(p) \
- nouveau_subdev_destroy(&(p)->base)
-#define nouveau_pwr_init(p) ({ \
- struct nouveau_pwr *_ppwr = (p); \
- _nouveau_pwr_init(nv_object(_ppwr)); \
-})
-#define nouveau_pwr_fini(p,s) ({ \
- struct nouveau_pwr *_ppwr = (p); \
- _nouveau_pwr_fini(nv_object(_ppwr), (s)); \
-})
-
-int nouveau_pwr_create_(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, int, void **);
-
-int _nouveau_pwr_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-#define _nouveau_pwr_dtor _nouveau_subdev_dtor
-int _nouveau_pwr_init(struct nouveau_object *);
-int _nouveau_pwr_fini(struct nouveau_object *, bool);
-
-struct nvkm_pwr_impl {
- struct nouveau_oclass base;
- struct {
- u32 *data;
- u32 size;
- } code;
- struct {
- u32 *data;
- u32 size;
- } data;
-
- void (*pgob)(struct nouveau_pwr *, bool);
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c b/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
deleted file mode 100644
index 9ad01da6eacb..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/base.c
+++ /dev/null
@@ -1,374 +0,0 @@
-/*
- * Copyright 2012 The Nouveau community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-
-#include "priv.h"
-
-static int
-nouveau_therm_update_trip(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_therm_trip_point *trip = priv->fan->bios.trip,
- *cur_trip = NULL,
- *last_trip = priv->last_trip;
- u8 temp = therm->temp_get(therm);
- u16 duty, i;
-
- /* look for the trip point corresponding to the current temperature */
- cur_trip = NULL;
- for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) {
- if (temp >= trip[i].temp)
- cur_trip = &trip[i];
- }
-
- /* account for the hysteresis cycle */
- if (last_trip && temp <= (last_trip->temp) &&
- temp > (last_trip->temp - last_trip->hysteresis))
- cur_trip = last_trip;
-
- if (cur_trip) {
- duty = cur_trip->fan_duty;
- priv->last_trip = cur_trip;
- } else {
- duty = 0;
- priv->last_trip = NULL;
- }
-
- return duty;
-}
-
-static int
-nouveau_therm_update_linear(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- u8 linear_min_temp = priv->fan->bios.linear_min_temp;
- u8 linear_max_temp = priv->fan->bios.linear_max_temp;
- u8 temp = therm->temp_get(therm);
- u16 duty;
-
- /* handle the non-linear part first */
- if (temp < linear_min_temp)
- return priv->fan->bios.min_duty;
- else if (temp > linear_max_temp)
- return priv->fan->bios.max_duty;
-
- /* we are in the linear zone */
- duty = (temp - linear_min_temp);
- duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty);
- duty /= (linear_max_temp - linear_min_temp);
- duty += priv->fan->bios.min_duty;
-
- return duty;
-}
-
-static void
-nouveau_therm_update(struct nouveau_therm *therm, int mode)
-{
- struct nouveau_timer *ptimer = nouveau_timer(therm);
- struct nouveau_therm_priv *priv = (void *)therm;
- unsigned long flags;
- bool immd = true;
- bool poll = true;
- int duty = -1;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (mode < 0)
- mode = priv->mode;
- priv->mode = mode;
-
- switch (mode) {
- case NOUVEAU_THERM_CTRL_MANUAL:
- ptimer->alarm_cancel(ptimer, &priv->alarm);
- duty = nouveau_therm_fan_get(therm);
- if (duty < 0)
- duty = 100;
- poll = false;
- break;
- case NOUVEAU_THERM_CTRL_AUTO:
- switch(priv->fan->bios.fan_mode) {
- case NVBIOS_THERM_FAN_TRIP:
- duty = nouveau_therm_update_trip(therm);
- break;
- case NVBIOS_THERM_FAN_LINEAR:
- duty = nouveau_therm_update_linear(therm);
- break;
- case NVBIOS_THERM_FAN_OTHER:
- if (priv->cstate)
- duty = priv->cstate;
- poll = false;
- break;
- }
- immd = false;
- break;
- case NOUVEAU_THERM_CTRL_NONE:
- default:
- ptimer->alarm_cancel(ptimer, &priv->alarm);
- poll = false;
- }
-
- if (list_empty(&priv->alarm.head) && poll)
- ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
- spin_unlock_irqrestore(&priv->lock, flags);
-
- if (duty >= 0) {
- nv_debug(therm, "FAN target request: %d%%\n", duty);
- nouveau_therm_fan_set(therm, immd, duty);
- }
-}
-
-int
-nouveau_therm_cstate(struct nouveau_therm *ptherm, int fan, int dir)
-{
- struct nouveau_therm_priv *priv = (void *)ptherm;
- if (!dir || (dir < 0 && fan < priv->cstate) ||
- (dir > 0 && fan > priv->cstate)) {
- nv_debug(ptherm, "default fan speed -> %d%%\n", fan);
- priv->cstate = fan;
- nouveau_therm_update(ptherm, -1);
- }
- return 0;
-}
-
-static void
-nouveau_therm_alarm(struct nouveau_alarm *alarm)
-{
- struct nouveau_therm_priv *priv =
- container_of(alarm, struct nouveau_therm_priv, alarm);
- nouveau_therm_update(&priv->base, -1);
-}
-
-int
-nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_device *device = nv_device(therm);
- static const char *name[] = {
- "disabled",
- "manual",
- "automatic"
- };
-
- /* The default PPWR ucode on fermi interferes with fan management */
- if ((mode >= ARRAY_SIZE(name)) ||
- (mode != NOUVEAU_THERM_CTRL_NONE && device->card_type >= NV_C0 &&
- !nouveau_subdev(device, NVDEV_SUBDEV_PWR)))
- return -EINVAL;
-
- /* do not allow automatic fan management if the thermal sensor is
- * not available */
- if (mode == NOUVEAU_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
- return -EINVAL;
-
- if (priv->mode == mode)
- return 0;
-
- nv_info(therm, "fan management: %s\n", name[mode]);
- nouveau_therm_update(therm, mode);
- return 0;
-}
-
-int
-nouveau_therm_attr_get(struct nouveau_therm *therm,
- enum nouveau_therm_attr_type type)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
-
- switch (type) {
- case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
- return priv->fan->bios.min_duty;
- case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
- return priv->fan->bios.max_duty;
- case NOUVEAU_THERM_ATTR_FAN_MODE:
- return priv->mode;
- case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
- return priv->bios_sensor.thrs_fan_boost.temp;
- case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
- return priv->bios_sensor.thrs_fan_boost.hysteresis;
- case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
- return priv->bios_sensor.thrs_down_clock.temp;
- case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
- return priv->bios_sensor.thrs_down_clock.hysteresis;
- case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
- return priv->bios_sensor.thrs_critical.temp;
- case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
- return priv->bios_sensor.thrs_critical.hysteresis;
- case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
- return priv->bios_sensor.thrs_shutdown.temp;
- case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
- return priv->bios_sensor.thrs_shutdown.hysteresis;
- }
-
- return -EINVAL;
-}
-
-int
-nouveau_therm_attr_set(struct nouveau_therm *therm,
- enum nouveau_therm_attr_type type, int value)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
-
- switch (type) {
- case NOUVEAU_THERM_ATTR_FAN_MIN_DUTY:
- if (value < 0)
- value = 0;
- if (value > priv->fan->bios.max_duty)
- value = priv->fan->bios.max_duty;
- priv->fan->bios.min_duty = value;
- return 0;
- case NOUVEAU_THERM_ATTR_FAN_MAX_DUTY:
- if (value < 0)
- value = 0;
- if (value < priv->fan->bios.min_duty)
- value = priv->fan->bios.min_duty;
- priv->fan->bios.max_duty = value;
- return 0;
- case NOUVEAU_THERM_ATTR_FAN_MODE:
- return nouveau_therm_fan_mode(therm, value);
- case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST:
- priv->bios_sensor.thrs_fan_boost.temp = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST:
- priv->bios_sensor.thrs_fan_boost.hysteresis = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK:
- priv->bios_sensor.thrs_down_clock.temp = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST:
- priv->bios_sensor.thrs_down_clock.hysteresis = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_CRITICAL:
- priv->bios_sensor.thrs_critical.temp = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST:
- priv->bios_sensor.thrs_critical.hysteresis = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN:
- priv->bios_sensor.thrs_shutdown.temp = value;
- priv->sensor.program_alarms(therm);
- return 0;
- case NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST:
- priv->bios_sensor.thrs_shutdown.hysteresis = value;
- priv->sensor.program_alarms(therm);
- return 0;
- }
-
- return -EINVAL;
-}
-
-int
-_nouveau_therm_init(struct nouveau_object *object)
-{
- struct nouveau_therm *therm = (void *)object;
- struct nouveau_therm_priv *priv = (void *)therm;
- int ret;
-
- ret = nouveau_subdev_init(&therm->base);
- if (ret)
- return ret;
-
- if (priv->suspend >= 0) {
- /* restore the pwm value only when on manual or auto mode */
- if (priv->suspend > 0)
- nouveau_therm_fan_set(therm, true, priv->fan->percent);
-
- nouveau_therm_fan_mode(therm, priv->suspend);
- }
- nouveau_therm_sensor_init(therm);
- nouveau_therm_fan_init(therm);
- return 0;
-}
-
-int
-_nouveau_therm_fini(struct nouveau_object *object, bool suspend)
-{
- struct nouveau_therm *therm = (void *)object;
- struct nouveau_therm_priv *priv = (void *)therm;
-
- nouveau_therm_fan_fini(therm, suspend);
- nouveau_therm_sensor_fini(therm, suspend);
- if (suspend) {
- priv->suspend = priv->mode;
- priv->mode = NOUVEAU_THERM_CTRL_NONE;
- }
-
- return nouveau_subdev_fini(&therm->base, suspend);
-}
-
-int
-nouveau_therm_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass,
- int length, void **pobject)
-{
- struct nouveau_therm_priv *priv;
- int ret;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "PTHERM",
- "therm", length, pobject);
- priv = *pobject;
- if (ret)
- return ret;
-
- nouveau_alarm_init(&priv->alarm, nouveau_therm_alarm);
- spin_lock_init(&priv->lock);
- spin_lock_init(&priv->sensor.alarm_program_lock);
-
- priv->base.fan_get = nouveau_therm_fan_user_get;
- priv->base.fan_set = nouveau_therm_fan_user_set;
- priv->base.fan_sense = nouveau_therm_fan_sense;
- priv->base.attr_get = nouveau_therm_attr_get;
- priv->base.attr_set = nouveau_therm_attr_set;
- priv->mode = priv->suspend = -1; /* undefined */
- return 0;
-}
-
-int
-nouveau_therm_preinit(struct nouveau_therm *therm)
-{
- nouveau_therm_sensor_ctor(therm);
- nouveau_therm_ic_ctor(therm);
- nouveau_therm_fan_ctor(therm);
-
- nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
- nouveau_therm_sensor_preinit(therm);
- return 0;
-}
-
-void
-_nouveau_therm_dtor(struct nouveau_object *object)
-{
- struct nouveau_therm_priv *priv = (void *)object;
- kfree(priv->fan);
- nouveau_subdev_destroy(&priv->base.base);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
deleted file mode 100644
index 3656d605168f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fan.c
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Martin Peres
- */
-
-#include "priv.h"
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/gpio.h>
-#include <subdev/timer.h>
-
-#include <subdev/bios/fan.h>
-
-static int
-nouveau_fan_update(struct nouveau_fan *fan, bool immediate, int target)
-{
- struct nouveau_therm *therm = fan->parent;
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_timer *ptimer = nouveau_timer(priv);
- unsigned long flags;
- int ret = 0;
- int duty;
-
- /* update target fan speed, restricting to allowed range */
- spin_lock_irqsave(&fan->lock, flags);
- if (target < 0)
- target = fan->percent;
- target = max_t(u8, target, fan->bios.min_duty);
- target = min_t(u8, target, fan->bios.max_duty);
- if (fan->percent != target) {
- nv_debug(therm, "FAN target: %d\n", target);
- fan->percent = target;
- }
-
- /* check that we're not already at the target duty cycle */
- duty = fan->get(therm);
- if (duty == target) {
- spin_unlock_irqrestore(&fan->lock, flags);
- return 0;
- }
-
- /* smooth out the fanspeed increase/decrease */
- if (!immediate && duty >= 0) {
- /* the constant "3" is a rough approximation taken from
- * nvidia's behaviour.
- * it is meant to bump the fan speed more incrementally
- */
- if (duty < target)
- duty = min(duty + 3, target);
- else if (duty > target)
- duty = max(duty - 3, target);
- } else {
- duty = target;
- }
-
- nv_debug(therm, "FAN update: %d\n", duty);
- ret = fan->set(therm, duty);
- if (ret) {
- spin_unlock_irqrestore(&fan->lock, flags);
- return ret;
- }
-
- /* fan speed updated, drop the fan lock before grabbing the
- * alarm-scheduling lock and risking a deadlock
- */
- spin_unlock_irqrestore(&fan->lock, flags);
-
- /* schedule next fan update, if not at target speed already */
- if (list_empty(&fan->alarm.head) && target != duty) {
- u16 bump_period = fan->bios.bump_period;
- u16 slow_down_period = fan->bios.slow_down_period;
- u64 delay;
-
- if (duty > target)
- delay = slow_down_period;
- else if (duty == target)
- delay = min(bump_period, slow_down_period) ;
- else
- delay = bump_period;
-
- ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm);
- }
-
- return ret;
-}
-
-static void
-nouveau_fan_alarm(struct nouveau_alarm *alarm)
-{
- struct nouveau_fan *fan = container_of(alarm, struct nouveau_fan, alarm);
- nouveau_fan_update(fan, false, -1);
-}
-
-int
-nouveau_therm_fan_get(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- return priv->fan->get(therm);
-}
-
-int
-nouveau_therm_fan_set(struct nouveau_therm *therm, bool immediate, int percent)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- return nouveau_fan_update(priv->fan, immediate, percent);
-}
-
-int
-nouveau_therm_fan_sense(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_timer *ptimer = nouveau_timer(therm);
- struct nouveau_gpio *gpio = nouveau_gpio(therm);
- u32 cycles, cur, prev;
- u64 start, end, tach;
-
- if (priv->fan->tach.func == DCB_GPIO_UNUSED)
- return -ENODEV;
-
- /* Time a complete rotation and extrapolate to RPM:
- * When the fan spins, it changes the value of GPIO FAN_SENSE.
- * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation.
- */
- start = ptimer->read(ptimer);
- prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
- cycles = 0;
- do {
- usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
-
- cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
- if (prev != cur) {
- if (!start)
- start = ptimer->read(ptimer);
- cycles++;
- prev = cur;
- }
- } while (cycles < 5 && ptimer->read(ptimer) - start < 250000000);
- end = ptimer->read(ptimer);
-
- if (cycles == 5) {
- tach = (u64)60000000000ULL;
- do_div(tach, (end - start));
- return tach;
- } else
- return 0;
-}
-
-int
-nouveau_therm_fan_user_get(struct nouveau_therm *therm)
-{
- return nouveau_therm_fan_get(therm);
-}
-
-int
-nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
-
- if (priv->mode != NOUVEAU_THERM_CTRL_MANUAL)
- return -EINVAL;
-
- return nouveau_therm_fan_set(therm, true, percent);
-}
-
-static void
-nouveau_therm_fan_set_defaults(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
-
- priv->fan->bios.pwm_freq = 0;
- priv->fan->bios.min_duty = 0;
- priv->fan->bios.max_duty = 100;
- priv->fan->bios.bump_period = 500;
- priv->fan->bios.slow_down_period = 2000;
- priv->fan->bios.linear_min_temp = 40;
- priv->fan->bios.linear_max_temp = 85;
-}
-
-static void
-nouveau_therm_fan_safety_checks(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
-
- if (priv->fan->bios.min_duty > 100)
- priv->fan->bios.min_duty = 100;
- if (priv->fan->bios.max_duty > 100)
- priv->fan->bios.max_duty = 100;
-
- if (priv->fan->bios.min_duty > priv->fan->bios.max_duty)
- priv->fan->bios.min_duty = priv->fan->bios.max_duty;
-}
-
-int
-nouveau_therm_fan_init(struct nouveau_therm *therm)
-{
- return 0;
-}
-
-int
-nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_timer *ptimer = nouveau_timer(therm);
-
- if (suspend)
- ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
- return 0;
-}
-
-int
-nouveau_therm_fan_ctor(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_gpio *gpio = nouveau_gpio(therm);
- struct nouveau_bios *bios = nouveau_bios(therm);
- struct dcb_gpio_func func;
- int ret;
-
- /* attempt to locate a drivable fan, and determine control method */
- ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
- if (ret == 0) {
- /* FIXME: is this really the place to perform such checks ? */
- if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
- nv_debug(therm, "GPIO_FAN is in input mode\n");
- ret = -EINVAL;
- } else {
- ret = nouveau_fanpwm_create(therm, &func);
- if (ret != 0)
- ret = nouveau_fantog_create(therm, &func);
- }
- }
-
- /* no controllable fan found, create a dummy fan module */
- if (ret != 0) {
- ret = nouveau_fannil_create(therm);
- if (ret)
- return ret;
- }
-
- nv_info(therm, "FAN control: %s\n", priv->fan->type);
-
- /* read the current speed, it is useful when resuming */
- priv->fan->percent = nouveau_therm_fan_get(therm);
-
- /* attempt to detect a tachometer connection */
- ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
- if (ret)
- priv->fan->tach.func = DCB_GPIO_UNUSED;
-
- /* initialise fan bump/slow update handling */
- priv->fan->parent = therm;
- nouveau_alarm_init(&priv->fan->alarm, nouveau_fan_alarm);
- spin_lock_init(&priv->fan->lock);
-
- /* other random init... */
- nouveau_therm_fan_set_defaults(therm);
- nvbios_perf_fan_parse(bios, &priv->fan->perf);
- if (!nvbios_fan_parse(bios, &priv->fan->bios)) {
- nv_debug(therm, "parsing the fan table failed\n");
- if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
- nv_error(therm, "parsing both fan tables failed\n");
- }
- nouveau_therm_fan_safety_checks(therm);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c
deleted file mode 100644
index b78c182e1d51..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fannil.c
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-static int
-nouveau_fannil_get(struct nouveau_therm *therm)
-{
- return -ENODEV;
-}
-
-static int
-nouveau_fannil_set(struct nouveau_therm *therm, int percent)
-{
- return -ENODEV;
-}
-
-int
-nouveau_fannil_create(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_fan *priv;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- tpriv->fan = priv;
- if (!priv)
- return -ENOMEM;
-
- priv->type = "none / external";
- priv->get = nouveau_fannil_get;
- priv->set = nouveau_fannil_set;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c
deleted file mode 100644
index c629d7f2a6a4..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fanpwm.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Martin Peres
- */
-
-#include <core/option.h>
-#include <subdev/gpio.h>
-#include <subdev/bios.h>
-#include <subdev/bios/fan.h>
-
-#include "priv.h"
-
-struct nouveau_fanpwm_priv {
- struct nouveau_fan base;
- struct dcb_gpio_func func;
-};
-
-static int
-nouveau_fanpwm_get(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_fanpwm_priv *priv = (void *)tpriv->fan;
- struct nouveau_gpio *gpio = nouveau_gpio(therm);
- int card_type = nv_device(therm)->card_type;
- u32 divs, duty;
- int ret;
-
- ret = therm->pwm_get(therm, priv->func.line, &divs, &duty);
- if (ret == 0 && divs) {
- divs = max(divs, duty);
- if (card_type <= NV_40 || (priv->func.log[0] & 1))
- duty = divs - duty;
- return (duty * 100) / divs;
- }
-
- return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100;
-}
-
-static int
-nouveau_fanpwm_set(struct nouveau_therm *therm, int percent)
-{
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_fanpwm_priv *priv = (void *)tpriv->fan;
- int card_type = nv_device(therm)->card_type;
- u32 divs, duty;
- int ret;
-
- divs = priv->base.perf.pwm_divisor;
- if (priv->base.bios.pwm_freq) {
- divs = 1;
- if (therm->pwm_clock)
- divs = therm->pwm_clock(therm, priv->func.line);
- divs /= priv->base.bios.pwm_freq;
- }
-
- duty = ((divs * percent) + 99) / 100;
- if (card_type <= NV_40 || (priv->func.log[0] & 1))
- duty = divs - duty;
-
- ret = therm->pwm_set(therm, priv->func.line, divs, duty);
- if (ret == 0)
- ret = therm->pwm_ctrl(therm, priv->func.line, true);
- return ret;
-}
-
-int
-nouveau_fanpwm_create(struct nouveau_therm *therm, struct dcb_gpio_func *func)
-{
- struct nouveau_device *device = nv_device(therm);
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_bios *bios = nouveau_bios(therm);
- struct nouveau_fanpwm_priv *priv;
- struct nvbios_therm_fan fan;
- u32 divs, duty;
-
- nvbios_fan_parse(bios, &fan);
-
- if (!nouveau_boolopt(device->cfgopt, "NvFanPWM", func->param) ||
- !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE ||
- therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV)
- return -ENODEV;
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- tpriv->fan = &priv->base;
- if (!priv)
- return -ENOMEM;
-
- priv->base.type = "PWM";
- priv->base.get = nouveau_fanpwm_get;
- priv->base.set = nouveau_fanpwm_set;
- priv->func = *func;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c
deleted file mode 100644
index f69dab11f720..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/fantog.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright 2012 The Nouveau community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/gpio.h>
-#include <subdev/timer.h>
-
-struct nouveau_fantog_priv {
- struct nouveau_fan base;
- struct nouveau_alarm alarm;
- spinlock_t lock;
- u32 period_us;
- u32 percent;
- struct dcb_gpio_func func;
-};
-
-static void
-nouveau_fantog_update(struct nouveau_fantog_priv *priv, int percent)
-{
- struct nouveau_therm_priv *tpriv = (void *)priv->base.parent;
- struct nouveau_timer *ptimer = nouveau_timer(tpriv);
- struct nouveau_gpio *gpio = nouveau_gpio(tpriv);
- unsigned long flags;
- int duty;
-
- spin_lock_irqsave(&priv->lock, flags);
- if (percent < 0)
- percent = priv->percent;
- priv->percent = percent;
-
- duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff);
- gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
-
- if (list_empty(&priv->alarm.head) && percent != (duty * 100)) {
- u64 next_change = (percent * priv->period_us) / 100;
- if (!duty)
- next_change = priv->period_us - next_change;
- ptimer->alarm(ptimer, next_change * 1000, &priv->alarm);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void
-nouveau_fantog_alarm(struct nouveau_alarm *alarm)
-{
- struct nouveau_fantog_priv *priv =
- container_of(alarm, struct nouveau_fantog_priv, alarm);
- nouveau_fantog_update(priv, -1);
-}
-
-static int
-nouveau_fantog_get(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_fantog_priv *priv = (void *)tpriv->fan;
- return priv->percent;
-}
-
-static int
-nouveau_fantog_set(struct nouveau_therm *therm, int percent)
-{
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_fantog_priv *priv = (void *)tpriv->fan;
- if (therm->pwm_ctrl)
- therm->pwm_ctrl(therm, priv->func.line, false);
- nouveau_fantog_update(priv, percent);
- return 0;
-}
-
-int
-nouveau_fantog_create(struct nouveau_therm *therm, struct dcb_gpio_func *func)
-{
- struct nouveau_therm_priv *tpriv = (void *)therm;
- struct nouveau_fantog_priv *priv;
- int ret;
-
- if (therm->pwm_ctrl) {
- ret = therm->pwm_ctrl(therm, func->line, false);
- if (ret)
- return ret;
- }
-
- priv = kzalloc(sizeof(*priv), GFP_KERNEL);
- tpriv->fan = &priv->base;
- if (!priv)
- return -ENOMEM;
-
- priv->base.type = "toggle";
- priv->base.get = nouveau_fantog_get;
- priv->base.set = nouveau_fantog_set;
- nouveau_alarm_init(&priv->alarm, nouveau_fantog_alarm);
- priv->period_us = 100000; /* 10Hz */
- priv->percent = 100;
- priv->func = *func;
- spin_lock_init(&priv->lock);
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c
deleted file mode 100644
index 668cf3322285..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/gm107.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2014 Martin Peres
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-struct gm107_therm_priv {
- struct nouveau_therm_priv base;
-};
-
-static int
-gm107_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
- /* nothing to do, it seems hardwired */
- return 0;
-}
-
-static int
-gm107_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
- *divs = nv_rd32(therm, 0x10eb20) & 0x1fff;
- *duty = nv_rd32(therm, 0x10eb24) & 0x1fff;
- return 0;
-}
-
-static int
-gm107_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
- nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */
- nv_wr32(therm, 0x10eb14, duty | 0x80000000);
- return 0;
-}
-
-static int
-gm107_fan_pwm_clock(struct nouveau_therm *therm, int line)
-{
- return nv_device(therm)->crystal * 1000;
-}
-
-static int
-gm107_therm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gm107_therm_priv *priv;
- int ret;
-
- ret = nouveau_therm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl;
- priv->base.base.pwm_get = gm107_fan_pwm_get;
- priv->base.base.pwm_set = gm107_fan_pwm_set;
- priv->base.base.pwm_clock = gm107_fan_pwm_clock;
- priv->base.base.temp_get = nv84_temp_get;
- priv->base.base.fan_sense = nva3_therm_fan_sense;
- priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
- return nouveau_therm_preinit(&priv->base.base);
-}
-
-struct nouveau_oclass
-gm107_therm_oclass = {
- .handle = NV_SUBDEV(THERM, 0x117),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gm107_therm_ctor,
- .dtor = _nouveau_therm_dtor,
- .init = nvd0_therm_init,
- .fini = nv84_therm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
deleted file mode 100644
index ca9ad9fd47be..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/ic.c
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright 2012 Nouveau community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-#include <subdev/i2c.h>
-#include <subdev/bios/extdev.h>
-
-static bool
-probe_monitoring_device(struct nouveau_i2c_port *i2c,
- struct i2c_board_info *info, void *data)
-{
- struct nouveau_therm_priv *priv = data;
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
- struct i2c_client *client;
-
- request_module("%s%s", I2C_MODULE_PREFIX, info->type);
-
- client = i2c_new_device(&i2c->adapter, info);
- if (!client)
- return false;
-
- if (!client->dev.driver ||
- to_i2c_driver(client->dev.driver)->detect(client, info)) {
- i2c_unregister_device(client);
- return false;
- }
-
- nv_info(priv,
- "Found an %s at address 0x%x (controlled by lm_sensors, "
- "temp offset %+i C)\n",
- info->type, info->addr, sensor->offset_constant);
- priv->ic = client;
-
- return true;
-}
-
-static struct nouveau_i2c_board_info
-nv_board_infos[] = {
- { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
- { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 },
- { { I2C_BOARD_INFO("adt7473", 0x2e) }, 40 },
- { { I2C_BOARD_INFO("adt7473", 0x2d) }, 40 },
- { { I2C_BOARD_INFO("adt7473", 0x2c) }, 40 },
- { { I2C_BOARD_INFO("f75375", 0x2e) }, 0 },
- { { I2C_BOARD_INFO("lm99", 0x4c) }, 0 },
- { { I2C_BOARD_INFO("lm90", 0x4c) }, 0 },
- { { I2C_BOARD_INFO("lm90", 0x4d) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x18) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x19) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x1a) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x29) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x2a) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x2b) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x4c) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x4d) }, 0 },
- { { I2C_BOARD_INFO("adm1021", 0x4e) }, 0 },
- { { I2C_BOARD_INFO("lm63", 0x18) }, 0 },
- { { I2C_BOARD_INFO("lm63", 0x4e) }, 0 },
- { }
-};
-
-void
-nouveau_therm_ic_ctor(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_bios *bios = nouveau_bios(therm);
- struct nouveau_i2c *i2c = nouveau_i2c(therm);
- struct nvbios_extdev_func extdev_entry;
-
- if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
- struct nouveau_i2c_board_info board[] = {
- { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
- { }
- };
-
- i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
- board, probe_monitoring_device, therm);
- if (priv->ic)
- return;
- }
-
- if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
- struct nouveau_i2c_board_info board[] = {
- { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
- { }
- };
-
- i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
- board, probe_monitoring_device, therm);
- if (priv->ic)
- return;
- }
-
- /* The vbios doesn't provide the address of an exisiting monitoring
- device. Let's try our static list.
- */
- i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
- nv_board_infos, probe_monitoring_device, therm);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c
deleted file mode 100644
index 002e51b3af93..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv40.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Martin Peres
- */
-
-#include "priv.h"
-
-struct nv40_therm_priv {
- struct nouveau_therm_priv base;
-};
-
-enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
-
-static enum nv40_sensor_style
-nv40_sensor_style(struct nouveau_therm *therm)
-{
- struct nouveau_device *device = nv_device(therm);
-
- switch (device->chipset) {
- case 0x43:
- case 0x44:
- case 0x4a:
- case 0x47:
- return OLD_STYLE;
-
- case 0x46:
- case 0x49:
- case 0x4b:
- case 0x4e:
- case 0x4c:
- case 0x67:
- case 0x68:
- case 0x63:
- return NEW_STYLE;
- default:
- return INVALID_STYLE;
- }
-}
-
-static int
-nv40_sensor_setup(struct nouveau_therm *therm)
-{
- enum nv40_sensor_style style = nv40_sensor_style(therm);
-
- /* enable ADC readout and disable the ALARM threshold */
- if (style == NEW_STYLE) {
- nv_mask(therm, 0x15b8, 0x80000000, 0);
- nv_wr32(therm, 0x15b0, 0x80003fff);
- mdelay(20); /* wait for the temperature to stabilize */
- return nv_rd32(therm, 0x15b4) & 0x3fff;
- } else if (style == OLD_STYLE) {
- nv_wr32(therm, 0x15b0, 0xff);
- mdelay(20); /* wait for the temperature to stabilize */
- return nv_rd32(therm, 0x15b4) & 0xff;
- } else
- return -ENODEV;
-}
-
-static int
-nv40_temp_get(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
- enum nv40_sensor_style style = nv40_sensor_style(therm);
- int core_temp;
-
- if (style == NEW_STYLE) {
- nv_wr32(therm, 0x15b0, 0x80003fff);
- core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
- } else if (style == OLD_STYLE) {
- nv_wr32(therm, 0x15b0, 0xff);
- core_temp = nv_rd32(therm, 0x15b4) & 0xff;
- } else
- return -ENODEV;
-
- /* if the slope or the offset is unset, do no use the sensor */
- if (!sensor->slope_div || !sensor->slope_mult ||
- !sensor->offset_num || !sensor->offset_den)
- return -ENODEV;
-
- core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
- core_temp = core_temp + sensor->offset_num / sensor->offset_den;
- core_temp = core_temp + sensor->offset_constant - 8;
-
- /* reserve negative temperatures for errors */
- if (core_temp < 0)
- core_temp = 0;
-
- return core_temp;
-}
-
-static int
-nv40_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
- u32 mask = enable ? 0x80000000 : 0x0000000;
- if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask);
- else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask);
- else {
- nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
- return -ENODEV;
- }
- return 0;
-}
-
-static int
-nv40_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
- if (line == 2) {
- u32 reg = nv_rd32(therm, 0x0010f0);
- if (reg & 0x80000000) {
- *duty = (reg & 0x7fff0000) >> 16;
- *divs = (reg & 0x00007fff);
- return 0;
- }
- } else
- if (line == 9) {
- u32 reg = nv_rd32(therm, 0x0015f4);
- if (reg & 0x80000000) {
- *divs = nv_rd32(therm, 0x0015f8);
- *duty = (reg & 0x7fffffff);
- return 0;
- }
- } else {
- nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
- return -ENODEV;
- }
-
- return -EINVAL;
-}
-
-static int
-nv40_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
- if (line == 2) {
- nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
- } else
- if (line == 9) {
- nv_wr32(therm, 0x0015f8, divs);
- nv_mask(therm, 0x0015f4, 0x7fffffff, duty);
- } else {
- nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
- return -ENODEV;
- }
-
- return 0;
-}
-
-void
-nv40_therm_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_therm *therm = nouveau_therm(subdev);
- uint32_t stat = nv_rd32(therm, 0x1100);
-
- /* traitement */
-
- /* ack all IRQs */
- nv_wr32(therm, 0x1100, 0x70000);
-
- nv_error(therm, "THERM received an IRQ: stat = %x\n", stat);
-}
-
-static int
-nv40_therm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv40_therm_priv *priv;
- int ret;
-
- ret = nouveau_therm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl;
- priv->base.base.pwm_get = nv40_fan_pwm_get;
- priv->base.base.pwm_set = nv40_fan_pwm_set;
- priv->base.base.temp_get = nv40_temp_get;
- priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
- nv_subdev(priv)->intr = nv40_therm_intr;
- return nouveau_therm_preinit(&priv->base.base);
-}
-
-static int
-nv40_therm_init(struct nouveau_object *object)
-{
- struct nouveau_therm *therm = (void *)object;
-
- nv40_sensor_setup(therm);
-
- return _nouveau_therm_init(object);
-}
-
-struct nouveau_oclass
-nv40_therm_oclass = {
- .handle = NV_SUBDEV(THERM, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_therm_ctor,
- .dtor = _nouveau_therm_dtor,
- .init = nv40_therm_init,
- .fini = _nouveau_therm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
deleted file mode 100644
index 321db927d638..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv50.c
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Martin Peres
- */
-
-#include "priv.h"
-
-struct nv50_therm_priv {
- struct nouveau_therm_priv base;
-};
-
-static int
-pwm_info(struct nouveau_therm *therm, int *line, int *ctrl, int *indx)
-{
- if (*line == 0x04) {
- *ctrl = 0x00e100;
- *line = 4;
- *indx = 0;
- } else
- if (*line == 0x09) {
- *ctrl = 0x00e100;
- *line = 9;
- *indx = 1;
- } else
- if (*line == 0x10) {
- *ctrl = 0x00e28c;
- *line = 0;
- *indx = 0;
- } else {
- nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
- return -ENODEV;
- }
-
- return 0;
-}
-
-int
-nv50_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
- u32 data = enable ? 0x00000001 : 0x00000000;
- int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
- if (ret == 0)
- nv_mask(therm, ctrl, 0x00010001 << line, data << line);
- return ret;
-}
-
-int
-nv50_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
- int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
- if (ret)
- return ret;
-
- if (nv_rd32(therm, ctrl) & (1 << line)) {
- *divs = nv_rd32(therm, 0x00e114 + (id * 8));
- *duty = nv_rd32(therm, 0x00e118 + (id * 8));
- return 0;
- }
-
- return -EINVAL;
-}
-
-int
-nv50_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
- int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
- if (ret)
- return ret;
-
- nv_wr32(therm, 0x00e114 + (id * 8), divs);
- nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
- return 0;
-}
-
-int
-nv50_fan_pwm_clock(struct nouveau_therm *therm, int line)
-{
- int chipset = nv_device(therm)->chipset;
- int crystal = nv_device(therm)->crystal;
- int pwm_clock;
-
- /* determine the PWM source clock */
- if (chipset > 0x50 && chipset < 0x94) {
- u8 pwm_div = nv_rd32(therm, 0x410c);
- if (nv_rd32(therm, 0xc040) & 0x800000) {
- /* Use the HOST clock (100 MHz)
- * Where does this constant(2.4) comes from? */
- pwm_clock = (100000000 >> pwm_div) * 10 / 24;
- } else {
- /* Where does this constant(20) comes from? */
- pwm_clock = (crystal * 1000) >> pwm_div;
- pwm_clock /= 20;
- }
- } else {
- pwm_clock = (crystal * 1000) / 20;
- }
-
- return pwm_clock;
-}
-
-static void
-nv50_sensor_setup(struct nouveau_therm *therm)
-{
- nv_mask(therm, 0x20010, 0x40000000, 0x0);
- mdelay(20); /* wait for the temperature to stabilize */
-}
-
-static int
-nv50_temp_get(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
- int core_temp;
-
- core_temp = nv_rd32(therm, 0x20014) & 0x3fff;
-
- /* if the slope or the offset is unset, do no use the sensor */
- if (!sensor->slope_div || !sensor->slope_mult ||
- !sensor->offset_num || !sensor->offset_den)
- return -ENODEV;
-
- core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
- core_temp = core_temp + sensor->offset_num / sensor->offset_den;
- core_temp = core_temp + sensor->offset_constant - 8;
-
- /* reserve negative temperatures for errors */
- if (core_temp < 0)
- core_temp = 0;
-
- return core_temp;
-}
-
-static int
-nv50_therm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_therm_priv *priv;
- int ret;
-
- ret = nouveau_therm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
- priv->base.base.pwm_get = nv50_fan_pwm_get;
- priv->base.base.pwm_set = nv50_fan_pwm_set;
- priv->base.base.pwm_clock = nv50_fan_pwm_clock;
- priv->base.base.temp_get = nv50_temp_get;
- priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
- nv_subdev(priv)->intr = nv40_therm_intr;
-
- return nouveau_therm_preinit(&priv->base.base);
-}
-
-static int
-nv50_therm_init(struct nouveau_object *object)
-{
- struct nouveau_therm *therm = (void *)object;
-
- nv50_sensor_setup(therm);
-
- return _nouveau_therm_init(object);
-}
-
-struct nouveau_oclass
-nv50_therm_oclass = {
- .handle = NV_SUBDEV(THERM, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_therm_ctor,
- .dtor = _nouveau_therm_dtor,
- .init = nv50_therm_init,
- .fini = _nouveau_therm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c
deleted file mode 100644
index 14e2e09bfc24..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nv84.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- * Martin Peres
- */
-
-#include "priv.h"
-#include <subdev/fuse.h>
-
-struct nv84_therm_priv {
- struct nouveau_therm_priv base;
-};
-
-int
-nv84_temp_get(struct nouveau_therm *therm)
-{
- struct nouveau_fuse *fuse = nouveau_fuse(therm);
-
- if (nv_ro32(fuse, 0x1a8) == 1)
- return nv_rd32(therm, 0x20400);
- else
- return -ENODEV;
-}
-
-void
-nv84_sensor_setup(struct nouveau_therm *therm)
-{
- struct nouveau_fuse *fuse = nouveau_fuse(therm);
-
- /* enable temperature reading for cards with insane defaults */
- if (nv_ro32(fuse, 0x1a8) == 1) {
- nv_mask(therm, 0x20008, 0x80008000, 0x80000000);
- nv_mask(therm, 0x2000c, 0x80000003, 0x00000000);
- mdelay(20); /* wait for the temperature to stabilize */
- }
-}
-
-static void
-nv84_therm_program_alarms(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
-
- /* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */
- nv_wr32(therm, 0x20000, 0x000003ff);
-
- /* shutdown: The computer should be shutdown when reached */
- nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis);
- nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp);
-
- /* THRS_1 : fan boost*/
- nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp);
-
- /* THRS_2 : critical */
- nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp);
-
- /* THRS_4 : down clock */
- nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp);
- spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
-
- nv_debug(therm,
- "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
- sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
- sensor->thrs_down_clock.temp,
- sensor->thrs_down_clock.hysteresis,
- sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
- sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
-
-}
-
-/* must be called with alarm_program_lock taken ! */
-static void
-nv84_therm_threshold_hyst_emulation(struct nouveau_therm *therm,
- uint32_t thrs_reg, u8 status_bit,
- const struct nvbios_therm_threshold *thrs,
- enum nouveau_therm_thrs thrs_name)
-{
- enum nouveau_therm_thrs_direction direction;
- enum nouveau_therm_thrs_state prev_state, new_state;
- int temp, cur;
-
- prev_state = nouveau_therm_sensor_get_threshold_state(therm, thrs_name);
- temp = nv_rd32(therm, thrs_reg);
-
- /* program the next threshold */
- if (temp == thrs->temp) {
- nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis);
- new_state = NOUVEAU_THERM_THRS_HIGHER;
- } else {
- nv_wr32(therm, thrs_reg, thrs->temp);
- new_state = NOUVEAU_THERM_THRS_LOWER;
- }
-
- /* fix the state (in case someone reprogrammed the alarms) */
- cur = therm->temp_get(therm);
- if (new_state == NOUVEAU_THERM_THRS_LOWER && cur > thrs->temp)
- new_state = NOUVEAU_THERM_THRS_HIGHER;
- else if (new_state == NOUVEAU_THERM_THRS_HIGHER &&
- cur < thrs->temp - thrs->hysteresis)
- new_state = NOUVEAU_THERM_THRS_LOWER;
- nouveau_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
-
- /* find the direction */
- if (prev_state < new_state)
- direction = NOUVEAU_THERM_THRS_RISING;
- else if (prev_state > new_state)
- direction = NOUVEAU_THERM_THRS_FALLING;
- else
- return;
-
- /* advertise a change in direction */
- nouveau_therm_sensor_event(therm, thrs_name, direction);
-}
-
-static void
-nv84_therm_intr(struct nouveau_subdev *subdev)
-{
- struct nouveau_therm *therm = nouveau_therm(subdev);
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
- unsigned long flags;
- uint32_t intr;
-
- spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
-
- intr = nv_rd32(therm, 0x20100) & 0x3ff;
-
- /* THRS_4: downclock */
- if (intr & 0x002) {
- nv84_therm_threshold_hyst_emulation(therm, 0x20414, 24,
- &sensor->thrs_down_clock,
- NOUVEAU_THERM_THRS_DOWNCLOCK);
- intr &= ~0x002;
- }
-
- /* shutdown */
- if (intr & 0x004) {
- nv84_therm_threshold_hyst_emulation(therm, 0x20480, 20,
- &sensor->thrs_shutdown,
- NOUVEAU_THERM_THRS_SHUTDOWN);
- intr &= ~0x004;
- }
-
- /* THRS_1 : fan boost */
- if (intr & 0x008) {
- nv84_therm_threshold_hyst_emulation(therm, 0x204c4, 21,
- &sensor->thrs_fan_boost,
- NOUVEAU_THERM_THRS_FANBOOST);
- intr &= ~0x008;
- }
-
- /* THRS_2 : critical */
- if (intr & 0x010) {
- nv84_therm_threshold_hyst_emulation(therm, 0x204c0, 22,
- &sensor->thrs_critical,
- NOUVEAU_THERM_THRS_CRITICAL);
- intr &= ~0x010;
- }
-
- if (intr)
- nv_error(therm, "unhandled intr 0x%08x\n", intr);
-
- /* ACK everything */
- nv_wr32(therm, 0x20100, 0xffffffff);
- nv_wr32(therm, 0x1100, 0x10000); /* PBUS */
-
- spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
-}
-
-static int
-nv84_therm_init(struct nouveau_object *object)
-{
- struct nv84_therm_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_therm_init(&priv->base.base);
- if (ret)
- return ret;
-
- nv84_sensor_setup(&priv->base.base);
-
- return 0;
-}
-
-static int
-nv84_therm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv84_therm_priv *priv;
- int ret;
-
- ret = nouveau_therm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
- priv->base.base.pwm_get = nv50_fan_pwm_get;
- priv->base.base.pwm_set = nv50_fan_pwm_set;
- priv->base.base.pwm_clock = nv50_fan_pwm_clock;
- priv->base.base.temp_get = nv84_temp_get;
- priv->base.sensor.program_alarms = nv84_therm_program_alarms;
- nv_subdev(priv)->intr = nv84_therm_intr;
-
- /* init the thresholds */
- nouveau_therm_sensor_set_threshold_state(&priv->base.base,
- NOUVEAU_THERM_THRS_SHUTDOWN,
- NOUVEAU_THERM_THRS_LOWER);
- nouveau_therm_sensor_set_threshold_state(&priv->base.base,
- NOUVEAU_THERM_THRS_FANBOOST,
- NOUVEAU_THERM_THRS_LOWER);
- nouveau_therm_sensor_set_threshold_state(&priv->base.base,
- NOUVEAU_THERM_THRS_CRITICAL,
- NOUVEAU_THERM_THRS_LOWER);
- nouveau_therm_sensor_set_threshold_state(&priv->base.base,
- NOUVEAU_THERM_THRS_DOWNCLOCK,
- NOUVEAU_THERM_THRS_LOWER);
-
- return nouveau_therm_preinit(&priv->base.base);
-}
-
-int
-nv84_therm_fini(struct nouveau_object *object, bool suspend)
-{
- /* Disable PTherm IRQs */
- nv_wr32(object, 0x20000, 0x00000000);
-
- /* ACK all PTherm IRQs */
- nv_wr32(object, 0x20100, 0xffffffff);
- nv_wr32(object, 0x1100, 0x10000); /* PBUS */
-
- return _nouveau_therm_fini(object, suspend);
-}
-
-struct nouveau_oclass
-nv84_therm_oclass = {
- .handle = NV_SUBDEV(THERM, 0x84),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv84_therm_ctor,
- .dtor = _nouveau_therm_dtor,
- .init = nv84_therm_init,
- .fini = nv84_therm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c
deleted file mode 100644
index 7893357a7e9f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nva3.c
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/gpio.h>
-
-#include "priv.h"
-
-struct nva3_therm_priv {
- struct nouveau_therm_priv base;
-};
-
-int
-nva3_therm_fan_sense(struct nouveau_therm *therm)
-{
- u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff;
- u32 ctrl = nv_rd32(therm, 0x00e720);
- if (ctrl & 0x00000001)
- return tach * 60 / 2;
- return -ENODEV;
-}
-
-static int
-nva3_therm_init(struct nouveau_object *object)
-{
- struct nva3_therm_priv *priv = (void *)object;
- struct dcb_gpio_func *tach = &priv->base.fan->tach;
- int ret;
-
- ret = nouveau_therm_init(&priv->base.base);
- if (ret)
- return ret;
-
- nv84_sensor_setup(&priv->base.base);
-
- /* enable fan tach, count revolutions per-second */
- nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
- if (tach->func != DCB_GPIO_UNUSED) {
- nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
- nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16);
- nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
- }
- nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
-
- return 0;
-}
-
-static int
-nva3_therm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nva3_therm_priv *priv;
- int ret;
-
- ret = nouveau_therm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
- priv->base.base.pwm_get = nv50_fan_pwm_get;
- priv->base.base.pwm_set = nv50_fan_pwm_set;
- priv->base.base.pwm_clock = nv50_fan_pwm_clock;
- priv->base.base.temp_get = nv84_temp_get;
- priv->base.base.fan_sense = nva3_therm_fan_sense;
- priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
- return nouveau_therm_preinit(&priv->base.base);
-}
-
-struct nouveau_oclass
-nva3_therm_oclass = {
- .handle = NV_SUBDEV(THERM, 0xa3),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nva3_therm_ctor,
- .dtor = _nouveau_therm_dtor,
- .init = nva3_therm_init,
- .fini = nv84_therm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c b/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
deleted file mode 100644
index b70f7cc649b8..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/nvd0.c
+++ /dev/null
@@ -1,174 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "priv.h"
-
-struct nvd0_therm_priv {
- struct nouveau_therm_priv base;
-};
-
-static int
-pwm_info(struct nouveau_therm *therm, int line)
-{
- u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));
-
- switch (gpio & 0x000000c0) {
- case 0x00000000: /* normal mode, possibly pwm forced off by us */
- case 0x00000040: /* nvio special */
- switch (gpio & 0x0000001f) {
- case 0x00: return 2;
- case 0x19: return 1;
- case 0x1c: return 0;
- case 0x1e: return 2;
- default:
- break;
- }
- default:
- break;
- }
-
- nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio);
- return -ENODEV;
-}
-
-static int
-nvd0_fan_pwm_ctrl(struct nouveau_therm *therm, int line, bool enable)
-{
- u32 data = enable ? 0x00000040 : 0x00000000;
- int indx = pwm_info(therm, line);
- if (indx < 0)
- return indx;
- else if (indx < 2)
- nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
- /* nothing to do for indx == 2, it seems hardwired to PTHERM */
- return 0;
-}
-
-static int
-nvd0_fan_pwm_get(struct nouveau_therm *therm, int line, u32 *divs, u32 *duty)
-{
- int indx = pwm_info(therm, line);
- if (indx < 0)
- return indx;
- else if (indx < 2) {
- if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
- *divs = nv_rd32(therm, 0x00e114 + (indx * 8));
- *duty = nv_rd32(therm, 0x00e118 + (indx * 8));
- return 0;
- }
- } else if (indx == 2) {
- *divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
- *duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
- return 0;
- }
-
- return -EINVAL;
-}
-
-static int
-nvd0_fan_pwm_set(struct nouveau_therm *therm, int line, u32 divs, u32 duty)
-{
- int indx = pwm_info(therm, line);
- if (indx < 0)
- return indx;
- else if (indx < 2) {
- nv_wr32(therm, 0x00e114 + (indx * 8), divs);
- nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
- } else if (indx == 2) {
- nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
- nv_wr32(therm, 0x0200dc, duty | 0x40000000);
- }
- return 0;
-}
-
-static int
-nvd0_fan_pwm_clock(struct nouveau_therm *therm, int line)
-{
- int indx = pwm_info(therm, line);
- if (indx < 0)
- return 0;
- else if (indx < 2)
- return (nv_device(therm)->crystal * 1000) / 20;
- else
- return nv_device(therm)->crystal * 1000 / 10;
-}
-
-int
-nvd0_therm_init(struct nouveau_object *object)
-{
- struct nvd0_therm_priv *priv = (void *)object;
- int ret;
-
- ret = nouveau_therm_init(&priv->base.base);
- if (ret)
- return ret;
-
- /* enable fan tach, count revolutions per-second */
- nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
- if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) {
- nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line);
- nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
- nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
- }
- nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
-
- return 0;
-}
-
-static int
-nvd0_therm_ctor(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvd0_therm_priv *priv;
- int ret;
-
- ret = nouveau_therm_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- nv84_sensor_setup(&priv->base.base);
-
- priv->base.base.pwm_ctrl = nvd0_fan_pwm_ctrl;
- priv->base.base.pwm_get = nvd0_fan_pwm_get;
- priv->base.base.pwm_set = nvd0_fan_pwm_set;
- priv->base.base.pwm_clock = nvd0_fan_pwm_clock;
- priv->base.base.temp_get = nv84_temp_get;
- priv->base.base.fan_sense = nva3_therm_fan_sense;
- priv->base.sensor.program_alarms = nouveau_therm_program_alarms_polling;
- return nouveau_therm_preinit(&priv->base.base);
-}
-
-struct nouveau_oclass
-nvd0_therm_oclass = {
- .handle = NV_SUBDEV(THERM, 0xd0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvd0_therm_ctor,
- .dtor = _nouveau_therm_dtor,
- .init = nvd0_therm_init,
- .fini = nv84_therm_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
deleted file mode 100644
index 7dba8c281a0b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/priv.h
+++ /dev/null
@@ -1,159 +0,0 @@
-#ifndef __NVTHERM_PRIV_H__
-#define __NVTHERM_PRIV_H__
-
-/*
- * Copyright 2012 The Nouveau community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include <subdev/therm.h>
-
-#include <subdev/bios/extdev.h>
-#include <subdev/bios/gpio.h>
-#include <subdev/bios/perf.h>
-#include <subdev/bios/therm.h>
-#include <subdev/timer.h>
-
-struct nouveau_fan {
- struct nouveau_therm *parent;
- const char *type;
-
- struct nvbios_therm_fan bios;
- struct nvbios_perf_fan perf;
-
- struct nouveau_alarm alarm;
- spinlock_t lock;
- int percent;
-
- int (*get)(struct nouveau_therm *therm);
- int (*set)(struct nouveau_therm *therm, int percent);
-
- struct dcb_gpio_func tach;
-};
-
-enum nouveau_therm_thrs_direction {
- NOUVEAU_THERM_THRS_FALLING = 0,
- NOUVEAU_THERM_THRS_RISING = 1
-};
-
-enum nouveau_therm_thrs_state {
- NOUVEAU_THERM_THRS_LOWER = 0,
- NOUVEAU_THERM_THRS_HIGHER = 1
-};
-
-enum nouveau_therm_thrs {
- NOUVEAU_THERM_THRS_FANBOOST = 0,
- NOUVEAU_THERM_THRS_DOWNCLOCK = 1,
- NOUVEAU_THERM_THRS_CRITICAL = 2,
- NOUVEAU_THERM_THRS_SHUTDOWN = 3,
- NOUVEAU_THERM_THRS_NR
-};
-
-struct nouveau_therm_priv {
- struct nouveau_therm base;
-
- /* automatic thermal management */
- struct nouveau_alarm alarm;
- spinlock_t lock;
- struct nouveau_therm_trip_point *last_trip;
- int mode;
- int cstate;
- int suspend;
-
- /* bios */
- struct nvbios_therm_sensor bios_sensor;
-
- /* fan priv */
- struct nouveau_fan *fan;
-
- /* alarms priv */
- struct {
- spinlock_t alarm_program_lock;
- struct nouveau_alarm therm_poll_alarm;
- enum nouveau_therm_thrs_state alarm_state[NOUVEAU_THERM_THRS_NR];
- void (*program_alarms)(struct nouveau_therm *);
- } sensor;
-
- /* what should be done if the card overheats */
- struct {
- void (*downclock)(struct nouveau_therm *, bool active);
- void (*pause)(struct nouveau_therm *, bool active);
- } emergency;
-
- /* ic */
- struct i2c_client *ic;
-};
-
-int nouveau_therm_fan_mode(struct nouveau_therm *therm, int mode);
-int nouveau_therm_attr_get(struct nouveau_therm *therm,
- enum nouveau_therm_attr_type type);
-int nouveau_therm_attr_set(struct nouveau_therm *therm,
- enum nouveau_therm_attr_type type, int value);
-
-void nouveau_therm_ic_ctor(struct nouveau_therm *therm);
-
-int nouveau_therm_sensor_ctor(struct nouveau_therm *therm);
-
-int nouveau_therm_fan_ctor(struct nouveau_therm *therm);
-int nouveau_therm_fan_init(struct nouveau_therm *therm);
-int nouveau_therm_fan_fini(struct nouveau_therm *therm, bool suspend);
-int nouveau_therm_fan_get(struct nouveau_therm *therm);
-int nouveau_therm_fan_set(struct nouveau_therm *therm, bool now, int percent);
-int nouveau_therm_fan_user_get(struct nouveau_therm *therm);
-int nouveau_therm_fan_user_set(struct nouveau_therm *therm, int percent);
-
-int nouveau_therm_fan_sense(struct nouveau_therm *therm);
-
-int nouveau_therm_preinit(struct nouveau_therm *);
-
-int nouveau_therm_sensor_init(struct nouveau_therm *therm);
-int nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend);
-void nouveau_therm_sensor_preinit(struct nouveau_therm *);
-void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
- enum nouveau_therm_thrs thrs,
- enum nouveau_therm_thrs_state st);
-enum nouveau_therm_thrs_state
-nouveau_therm_sensor_get_threshold_state(struct nouveau_therm *therm,
- enum nouveau_therm_thrs thrs);
-void nouveau_therm_sensor_event(struct nouveau_therm *therm,
- enum nouveau_therm_thrs thrs,
- enum nouveau_therm_thrs_direction dir);
-void nouveau_therm_program_alarms_polling(struct nouveau_therm *therm);
-
-void nv40_therm_intr(struct nouveau_subdev *);
-int nv50_fan_pwm_ctrl(struct nouveau_therm *, int, bool);
-int nv50_fan_pwm_get(struct nouveau_therm *, int, u32 *, u32 *);
-int nv50_fan_pwm_set(struct nouveau_therm *, int, u32, u32);
-int nv50_fan_pwm_clock(struct nouveau_therm *, int);
-int nv84_temp_get(struct nouveau_therm *therm);
-void nv84_sensor_setup(struct nouveau_therm *therm);
-int nv84_therm_fini(struct nouveau_object *object, bool suspend);
-
-int nva3_therm_fan_sense(struct nouveau_therm *);
-
-int nvd0_therm_init(struct nouveau_object *object);
-
-int nouveau_fanpwm_create(struct nouveau_therm *, struct dcb_gpio_func *);
-int nouveau_fantog_create(struct nouveau_therm *, struct dcb_gpio_func *);
-int nouveau_fannil_create(struct nouveau_therm *);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
deleted file mode 100644
index 6212537b90c5..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/therm/temp.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2012 The Nouveau community
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Martin Peres
- */
-
-#include "priv.h"
-
-#include <core/object.h>
-#include <core/device.h>
-
-#include <subdev/bios.h>
-
-static void
-nouveau_therm_temp_set_defaults(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
-
- priv->bios_sensor.offset_constant = 0;
-
- priv->bios_sensor.thrs_fan_boost.temp = 90;
- priv->bios_sensor.thrs_fan_boost.hysteresis = 3;
-
- priv->bios_sensor.thrs_down_clock.temp = 95;
- priv->bios_sensor.thrs_down_clock.hysteresis = 3;
-
- priv->bios_sensor.thrs_critical.temp = 105;
- priv->bios_sensor.thrs_critical.hysteresis = 5;
-
- priv->bios_sensor.thrs_shutdown.temp = 135;
- priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */
-}
-
-
-static void
-nouveau_therm_temp_safety_checks(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nvbios_therm_sensor *s = &priv->bios_sensor;
-
- /* enforce a minimum hysteresis on thresholds */
- s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2);
- s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2);
- s->thrs_critical.hysteresis = max_t(u8, s->thrs_critical.hysteresis, 2);
- s->thrs_shutdown.hysteresis = max_t(u8, s->thrs_shutdown.hysteresis, 2);
-}
-
-/* must be called with alarm_program_lock taken ! */
-void nouveau_therm_sensor_set_threshold_state(struct nouveau_therm *therm,
- enum nouveau_therm_thrs thrs,
- enum nouveau_therm_thrs_state st)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- priv->sensor.alarm_state[thrs] = st;
-}
-
-/* must be called with alarm_program_lock taken ! */
-enum nouveau_therm_thrs_state
-nouveau_therm_sensor_get_threshold_state(struct nouveau_therm *therm,
- enum nouveau_therm_thrs thrs)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- return priv->sensor.alarm_state[thrs];
-}
-
-static void
-nv_poweroff_work(struct work_struct *work)
-{
- orderly_poweroff(true);
- kfree(work);
-}
-
-void nouveau_therm_sensor_event(struct nouveau_therm *therm,
- enum nouveau_therm_thrs thrs,
- enum nouveau_therm_thrs_direction dir)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- bool active;
- const char *thresolds[] = {
- "fanboost", "downclock", "critical", "shutdown"
- };
- int temperature = therm->temp_get(therm);
-
- if (thrs < 0 || thrs > 3)
- return;
-
- if (dir == NOUVEAU_THERM_THRS_FALLING)
- nv_info(therm, "temperature (%i C) went below the '%s' threshold\n",
- temperature, thresolds[thrs]);
- else
- nv_info(therm, "temperature (%i C) hit the '%s' threshold\n",
- temperature, thresolds[thrs]);
-
- active = (dir == NOUVEAU_THERM_THRS_RISING);
- switch (thrs) {
- case NOUVEAU_THERM_THRS_FANBOOST:
- if (active) {
- nouveau_therm_fan_set(therm, true, 100);
- nouveau_therm_fan_mode(therm, NOUVEAU_THERM_CTRL_AUTO);
- }
- break;
- case NOUVEAU_THERM_THRS_DOWNCLOCK:
- if (priv->emergency.downclock)
- priv->emergency.downclock(therm, active);
- break;
- case NOUVEAU_THERM_THRS_CRITICAL:
- if (priv->emergency.pause)
- priv->emergency.pause(therm, active);
- break;
- case NOUVEAU_THERM_THRS_SHUTDOWN:
- if (active) {
- struct work_struct *work;
-
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- if (work) {
- INIT_WORK(work, nv_poweroff_work);
- schedule_work(work);
- }
- }
- break;
- case NOUVEAU_THERM_THRS_NR:
- break;
- }
-
-}
-
-/* must be called with alarm_program_lock taken ! */
-static void
-nouveau_therm_threshold_hyst_polling(struct nouveau_therm *therm,
- const struct nvbios_therm_threshold *thrs,
- enum nouveau_therm_thrs thrs_name)
-{
- enum nouveau_therm_thrs_direction direction;
- enum nouveau_therm_thrs_state prev_state, new_state;
- int temp = therm->temp_get(therm);
-
- prev_state = nouveau_therm_sensor_get_threshold_state(therm, thrs_name);
-
- if (temp >= thrs->temp && prev_state == NOUVEAU_THERM_THRS_LOWER) {
- direction = NOUVEAU_THERM_THRS_RISING;
- new_state = NOUVEAU_THERM_THRS_HIGHER;
- } else if (temp <= thrs->temp - thrs->hysteresis &&
- prev_state == NOUVEAU_THERM_THRS_HIGHER) {
- direction = NOUVEAU_THERM_THRS_FALLING;
- new_state = NOUVEAU_THERM_THRS_LOWER;
- } else
- return; /* nothing to do */
-
- nouveau_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
- nouveau_therm_sensor_event(therm, thrs_name, direction);
-}
-
-static void
-alarm_timer_callback(struct nouveau_alarm *alarm)
-{
- struct nouveau_therm_priv *priv =
- container_of(alarm, struct nouveau_therm_priv, sensor.therm_poll_alarm);
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
- struct nouveau_timer *ptimer = nouveau_timer(priv);
- struct nouveau_therm *therm = &priv->base;
- unsigned long flags;
-
- spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
-
- nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
- NOUVEAU_THERM_THRS_FANBOOST);
-
- nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock,
- NOUVEAU_THERM_THRS_DOWNCLOCK);
-
- nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_critical,
- NOUVEAU_THERM_THRS_CRITICAL);
-
- nouveau_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown,
- NOUVEAU_THERM_THRS_SHUTDOWN);
-
- spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
-
- /* schedule the next poll in one second */
- if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head))
- ptimer->alarm(ptimer, 1000000000ULL, alarm);
-}
-
-void
-nouveau_therm_program_alarms_polling(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
-
- nv_debug(therm,
- "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
- sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
- sensor->thrs_down_clock.temp,
- sensor->thrs_down_clock.hysteresis,
- sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
- sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
-
- alarm_timer_callback(&priv->sensor.therm_poll_alarm);
-}
-
-int
-nouveau_therm_sensor_init(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- priv->sensor.program_alarms(therm);
- return 0;
-}
-
-int
-nouveau_therm_sensor_fini(struct nouveau_therm *therm, bool suspend)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_timer *ptimer = nouveau_timer(therm);
-
- if (suspend)
- ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
- return 0;
-}
-
-void
-nouveau_therm_sensor_preinit(struct nouveau_therm *therm)
-{
- const char *sensor_avail = "yes";
-
- if (therm->temp_get(therm) < 0)
- sensor_avail = "no";
-
- nv_info(therm, "internal sensor: %s\n", sensor_avail);
-}
-
-int
-nouveau_therm_sensor_ctor(struct nouveau_therm *therm)
-{
- struct nouveau_therm_priv *priv = (void *)therm;
- struct nouveau_bios *bios = nouveau_bios(therm);
-
- nouveau_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback);
-
- nouveau_therm_temp_set_defaults(therm);
- if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
- &priv->bios_sensor))
- nv_error(therm, "nvbios_therm_sensor_parse failed\n");
- nouveau_therm_temp_safety_checks(therm);
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c b/drivers/gpu/drm/nouveau/core/subdev/timer/base.c
deleted file mode 100644
index cf8a0e0f8ee3..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/base.c
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "subdev/timer.h"
-
-bool
-nouveau_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
-{
- struct nouveau_timer *ptimer = nouveau_timer(obj);
- u64 time0;
-
- time0 = ptimer->read(ptimer);
- do {
- if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
- if ((nv_rd32(obj, addr) & mask) == data)
- return true;
- } else {
- if ((nv_ro32(obj, addr) & mask) == data)
- return true;
- }
- } while (ptimer->read(ptimer) - time0 < nsec);
-
- return false;
-}
-
-bool
-nouveau_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
-{
- struct nouveau_timer *ptimer = nouveau_timer(obj);
- u64 time0;
-
- time0 = ptimer->read(ptimer);
- do {
- if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
- if ((nv_rd32(obj, addr) & mask) != data)
- return true;
- } else {
- if ((nv_ro32(obj, addr) & mask) != data)
- return true;
- }
- } while (ptimer->read(ptimer) - time0 < nsec);
-
- return false;
-}
-
-bool
-nouveau_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data)
-{
- struct nouveau_timer *ptimer = nouveau_timer(obj);
- u64 time0;
-
- time0 = ptimer->read(ptimer);
- do {
- if (func(data) == true)
- return true;
- } while (ptimer->read(ptimer) - time0 < nsec);
-
- return false;
-}
-
-void
-nouveau_timer_alarm(void *obj, u32 nsec, struct nouveau_alarm *alarm)
-{
- struct nouveau_timer *ptimer = nouveau_timer(obj);
- ptimer->alarm(ptimer, nsec, alarm);
-}
-
-void
-nouveau_timer_alarm_cancel(void *obj, struct nouveau_alarm *alarm)
-{
- struct nouveau_timer *ptimer = nouveau_timer(obj);
- ptimer->alarm_cancel(ptimer, alarm);
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c
deleted file mode 100644
index 37484db1f7fc..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/gk20a.c
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-static int
-gk20a_timer_init(struct nouveau_object *object)
-{
- struct nv04_timer_priv *priv = (void *)object;
- u32 hi = upper_32_bits(priv->suspend_time);
- u32 lo = lower_32_bits(priv->suspend_time);
- int ret;
-
- ret = nouveau_timer_init(&priv->base);
- if (ret)
- return ret;
-
- nv_debug(priv, "time low : 0x%08x\n", lo);
- nv_debug(priv, "time high : 0x%08x\n", hi);
-
- /* restore the time before suspend */
- nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
- nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
- return 0;
-}
-
-struct nouveau_oclass
-gk20a_timer_oclass = {
- .handle = NV_SUBDEV(TIMER, 0xff),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_timer_ctor,
- .dtor = nv04_timer_dtor,
- .init = gk20a_timer_init,
- .fini = nv04_timer_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
deleted file mode 100644
index 240ed0b983a9..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include "nv04.h"
-
-static u64
-nv04_timer_read(struct nouveau_timer *ptimer)
-{
- struct nv04_timer_priv *priv = (void *)ptimer;
- u32 hi, lo;
-
- do {
- hi = nv_rd32(priv, NV04_PTIMER_TIME_1);
- lo = nv_rd32(priv, NV04_PTIMER_TIME_0);
- } while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1));
-
- return ((u64)hi << 32 | lo);
-}
-
-static void
-nv04_timer_alarm_trigger(struct nouveau_timer *ptimer)
-{
- struct nv04_timer_priv *priv = (void *)ptimer;
- struct nouveau_alarm *alarm, *atemp;
- unsigned long flags;
- LIST_HEAD(exec);
-
- /* move any due alarms off the pending list */
- spin_lock_irqsave(&priv->lock, flags);
- list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) {
- if (alarm->timestamp <= ptimer->read(ptimer))
- list_move_tail(&alarm->head, &exec);
- }
-
- /* reschedule interrupt for next alarm time */
- if (!list_empty(&priv->alarms)) {
- alarm = list_first_entry(&priv->alarms, typeof(*alarm), head);
- nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp);
- nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001);
- } else {
- nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* execute any pending alarm handlers */
- list_for_each_entry_safe(alarm, atemp, &exec, head) {
- list_del_init(&alarm->head);
- alarm->func(alarm);
- }
-}
-
-static void
-nv04_timer_alarm(struct nouveau_timer *ptimer, u64 time,
- struct nouveau_alarm *alarm)
-{
- struct nv04_timer_priv *priv = (void *)ptimer;
- struct nouveau_alarm *list;
- unsigned long flags;
-
- alarm->timestamp = ptimer->read(ptimer) + time;
-
- /* append new alarm to list, in soonest-alarm-first order */
- spin_lock_irqsave(&priv->lock, flags);
- if (!time) {
- if (!list_empty(&alarm->head))
- list_del(&alarm->head);
- } else {
- list_for_each_entry(list, &priv->alarms, head) {
- if (list->timestamp > alarm->timestamp)
- break;
- }
- list_add_tail(&alarm->head, &list->head);
- }
- spin_unlock_irqrestore(&priv->lock, flags);
-
- /* process pending alarms */
- nv04_timer_alarm_trigger(ptimer);
-}
-
-static void
-nv04_timer_alarm_cancel(struct nouveau_timer *ptimer,
- struct nouveau_alarm *alarm)
-{
- struct nv04_timer_priv *priv = (void *)ptimer;
- unsigned long flags;
- spin_lock_irqsave(&priv->lock, flags);
- list_del_init(&alarm->head);
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-static void
-nv04_timer_intr(struct nouveau_subdev *subdev)
-{
- struct nv04_timer_priv *priv = (void *)subdev;
- u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0);
-
- if (stat & 0x00000001) {
- nv04_timer_alarm_trigger(&priv->base);
- nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001);
- stat &= ~0x00000001;
- }
-
- if (stat) {
- nv_error(priv, "unknown stat 0x%08x\n", stat);
- nv_wr32(priv, NV04_PTIMER_INTR_0, stat);
- }
-}
-
-int
-nv04_timer_fini(struct nouveau_object *object, bool suspend)
-{
- struct nv04_timer_priv *priv = (void *)object;
- if (suspend)
- priv->suspend_time = nv04_timer_read(&priv->base);
- nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
- return nouveau_timer_fini(&priv->base, suspend);
-}
-
-static int
-nv04_timer_init(struct nouveau_object *object)
-{
- struct nouveau_device *device = nv_device(object);
- struct nv04_timer_priv *priv = (void *)object;
- u32 m = 1, f, n, d, lo, hi;
- int ret;
-
- ret = nouveau_timer_init(&priv->base);
- if (ret)
- return ret;
-
- /* aim for 31.25MHz, which gives us nanosecond timestamps */
- d = 1000000 / 32;
-
- /* determine base clock for timer source */
-#if 0 /*XXX*/
- if (device->chipset < 0x40) {
- n = nouveau_hw_get_clock(device, PLL_CORE);
- } else
-#endif
- if (device->chipset <= 0x40) {
- /*XXX: figure this out */
- f = -1;
- n = 0;
- } else {
- f = device->crystal;
- n = f;
- while (n < (d * 2)) {
- n += (n / m);
- m++;
- }
-
- nv_wr32(priv, 0x009220, m - 1);
- }
-
- if (!n) {
- nv_warn(priv, "unknown input clock freq\n");
- if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) ||
- !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) {
- nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1);
- nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1);
- }
- return 0;
- }
-
- /* reduce ratio to acceptable values */
- while (((n % 5) == 0) && ((d % 5) == 0)) {
- n /= 5;
- d /= 5;
- }
-
- while (((n % 2) == 0) && ((d % 2) == 0)) {
- n /= 2;
- d /= 2;
- }
-
- while (n > 0xffff || d > 0xffff) {
- n >>= 1;
- d >>= 1;
- }
-
- /* restore the time before suspend */
- lo = priv->suspend_time;
- hi = (priv->suspend_time >> 32);
-
- nv_debug(priv, "input frequency : %dHz\n", f);
- nv_debug(priv, "input multiplier: %d\n", m);
- nv_debug(priv, "numerator : 0x%08x\n", n);
- nv_debug(priv, "denominator : 0x%08x\n", d);
- nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
- nv_debug(priv, "time low : 0x%08x\n", lo);
- nv_debug(priv, "time high : 0x%08x\n", hi);
-
- nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
- nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
- nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
- nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
- nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
- nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
-
- return 0;
-}
-
-void
-nv04_timer_dtor(struct nouveau_object *object)
-{
- struct nv04_timer_priv *priv = (void *)object;
- return nouveau_timer_destroy(&priv->base);
-}
-
-int
-nv04_timer_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_timer_priv *priv;
- int ret;
-
- ret = nouveau_timer_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.base.intr = nv04_timer_intr;
- priv->base.read = nv04_timer_read;
- priv->base.alarm = nv04_timer_alarm;
- priv->base.alarm_cancel = nv04_timer_alarm_cancel;
- priv->suspend_time = 0;
-
- INIT_LIST_HEAD(&priv->alarms);
- spin_lock_init(&priv->lock);
- return 0;
-}
-
-struct nouveau_oclass
-nv04_timer_oclass = {
- .handle = NV_SUBDEV(TIMER, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_timer_ctor,
- .dtor = nv04_timer_dtor,
- .init = nv04_timer_init,
- .fini = nv04_timer_fini,
- }
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h
deleted file mode 100644
index 4bc152697c37..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/nv04.h
+++ /dev/null
@@ -1,27 +0,0 @@
-#ifndef __NVKM_TIMER_NV04_H__
-#define __NVKM_TIMER_NV04_H__
-
-#include "priv.h"
-
-#define NV04_PTIMER_INTR_0 0x009100
-#define NV04_PTIMER_INTR_EN_0 0x009140
-#define NV04_PTIMER_NUMERATOR 0x009200
-#define NV04_PTIMER_DENOMINATOR 0x009210
-#define NV04_PTIMER_TIME_0 0x009400
-#define NV04_PTIMER_TIME_1 0x009410
-#define NV04_PTIMER_ALARM_0 0x009420
-
-struct nv04_timer_priv {
- struct nouveau_timer base;
- struct list_head alarms;
- spinlock_t lock;
- u64 suspend_time;
-};
-
-int nv04_timer_ctor(struct nouveau_object *, struct nouveau_object *,
- struct nouveau_oclass *, void *, u32,
- struct nouveau_object **);
-void nv04_timer_dtor(struct nouveau_object *);
-int nv04_timer_fini(struct nouveau_object *, bool);
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h
deleted file mode 100644
index 799dae3f2300..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/timer/priv.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __NVKM_TIMER_PRIV_H__
-#define __NVKM_TIMER_PRIV_H__
-
-#include <subdev/timer.h>
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c b/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
deleted file mode 100644
index f75a683bd47a..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/base.c
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <core/mm.h>
-
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-
-void
-nouveau_vm_map_at(struct nouveau_vma *vma, u64 delta, struct nouveau_mem *node)
-{
- struct nouveau_vm *vm = vma->vm;
- struct nouveau_vmmgr *vmm = vm->vmm;
- struct nouveau_mm_node *r;
- int big = vma->node->type != vmm->spg_shift;
- u32 offset = vma->node->offset + (delta >> 12);
- u32 bits = vma->node->type - 12;
- u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
- u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
- u32 max = 1 << (vmm->pgt_bits - bits);
- u32 end, len;
-
- delta = 0;
- list_for_each_entry(r, &node->regions, rl_entry) {
- u64 phys = (u64)r->offset << 12;
- u32 num = r->length >> bits;
-
- while (num) {
- struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-
- end = (pte + num);
- if (unlikely(end >= max))
- end = max;
- len = end - pte;
-
- vmm->map(vma, pgt, node, pte, len, phys, delta);
-
- num -= len;
- pte += len;
- if (unlikely(end >= max)) {
- phys += len << (bits + 12);
- pde++;
- pte = 0;
- }
-
- delta += (u64)len << vma->node->type;
- }
- }
-
- vmm->flush(vm);
-}
-
-static void
-nouveau_vm_map_sg_table(struct nouveau_vma *vma, u64 delta, u64 length,
- struct nouveau_mem *mem)
-{
- struct nouveau_vm *vm = vma->vm;
- struct nouveau_vmmgr *vmm = vm->vmm;
- int big = vma->node->type != vmm->spg_shift;
- u32 offset = vma->node->offset + (delta >> 12);
- u32 bits = vma->node->type - 12;
- u32 num = length >> vma->node->type;
- u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
- u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
- u32 max = 1 << (vmm->pgt_bits - bits);
- unsigned m, sglen;
- u32 end, len;
- int i;
- struct scatterlist *sg;
-
- for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) {
- struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
- sglen = sg_dma_len(sg) >> PAGE_SHIFT;
-
- end = pte + sglen;
- if (unlikely(end >= max))
- end = max;
- len = end - pte;
-
- for (m = 0; m < len; m++) {
- dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
-
- vmm->map_sg(vma, pgt, mem, pte, 1, &addr);
- num--;
- pte++;
-
- if (num == 0)
- goto finish;
- }
- if (unlikely(end >= max)) {
- pde++;
- pte = 0;
- }
- if (m < sglen) {
- for (; m < sglen; m++) {
- dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
-
- vmm->map_sg(vma, pgt, mem, pte, 1, &addr);
- num--;
- pte++;
- if (num == 0)
- goto finish;
- }
- }
-
- }
-finish:
- vmm->flush(vm);
-}
-
-static void
-nouveau_vm_map_sg(struct nouveau_vma *vma, u64 delta, u64 length,
- struct nouveau_mem *mem)
-{
- struct nouveau_vm *vm = vma->vm;
- struct nouveau_vmmgr *vmm = vm->vmm;
- dma_addr_t *list = mem->pages;
- int big = vma->node->type != vmm->spg_shift;
- u32 offset = vma->node->offset + (delta >> 12);
- u32 bits = vma->node->type - 12;
- u32 num = length >> vma->node->type;
- u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
- u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
- u32 max = 1 << (vmm->pgt_bits - bits);
- u32 end, len;
-
- while (num) {
- struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-
- end = (pte + num);
- if (unlikely(end >= max))
- end = max;
- len = end - pte;
-
- vmm->map_sg(vma, pgt, mem, pte, len, list);
-
- num -= len;
- pte += len;
- list += len;
- if (unlikely(end >= max)) {
- pde++;
- pte = 0;
- }
- }
-
- vmm->flush(vm);
-}
-
-void
-nouveau_vm_map(struct nouveau_vma *vma, struct nouveau_mem *node)
-{
- if (node->sg)
- nouveau_vm_map_sg_table(vma, 0, node->size << 12, node);
- else
- if (node->pages)
- nouveau_vm_map_sg(vma, 0, node->size << 12, node);
- else
- nouveau_vm_map_at(vma, 0, node);
-}
-
-void
-nouveau_vm_unmap_at(struct nouveau_vma *vma, u64 delta, u64 length)
-{
- struct nouveau_vm *vm = vma->vm;
- struct nouveau_vmmgr *vmm = vm->vmm;
- int big = vma->node->type != vmm->spg_shift;
- u32 offset = vma->node->offset + (delta >> 12);
- u32 bits = vma->node->type - 12;
- u32 num = length >> vma->node->type;
- u32 pde = (offset >> vmm->pgt_bits) - vm->fpde;
- u32 pte = (offset & ((1 << vmm->pgt_bits) - 1)) >> bits;
- u32 max = 1 << (vmm->pgt_bits - bits);
- u32 end, len;
-
- while (num) {
- struct nouveau_gpuobj *pgt = vm->pgt[pde].obj[big];
-
- end = (pte + num);
- if (unlikely(end >= max))
- end = max;
- len = end - pte;
-
- vmm->unmap(pgt, pte, len);
-
- num -= len;
- pte += len;
- if (unlikely(end >= max)) {
- pde++;
- pte = 0;
- }
- }
-
- vmm->flush(vm);
-}
-
-void
-nouveau_vm_unmap(struct nouveau_vma *vma)
-{
- nouveau_vm_unmap_at(vma, 0, (u64)vma->node->length << 12);
-}
-
-static void
-nouveau_vm_unmap_pgt(struct nouveau_vm *vm, int big, u32 fpde, u32 lpde)
-{
- struct nouveau_vmmgr *vmm = vm->vmm;
- struct nouveau_vm_pgd *vpgd;
- struct nouveau_vm_pgt *vpgt;
- struct nouveau_gpuobj *pgt;
- u32 pde;
-
- for (pde = fpde; pde <= lpde; pde++) {
- vpgt = &vm->pgt[pde - vm->fpde];
- if (--vpgt->refcount[big])
- continue;
-
- pgt = vpgt->obj[big];
- vpgt->obj[big] = NULL;
-
- list_for_each_entry(vpgd, &vm->pgd_list, head) {
- vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
- }
-
- mutex_unlock(&nv_subdev(vmm)->mutex);
- nouveau_gpuobj_ref(NULL, &pgt);
- mutex_lock(&nv_subdev(vmm)->mutex);
- }
-}
-
-static int
-nouveau_vm_map_pgt(struct nouveau_vm *vm, u32 pde, u32 type)
-{
- struct nouveau_vmmgr *vmm = vm->vmm;
- struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
- struct nouveau_vm_pgd *vpgd;
- struct nouveau_gpuobj *pgt;
- int big = (type != vmm->spg_shift);
- u32 pgt_size;
- int ret;
-
- pgt_size = (1 << (vmm->pgt_bits + 12)) >> type;
- pgt_size *= 8;
-
- mutex_unlock(&nv_subdev(vmm)->mutex);
- ret = nouveau_gpuobj_new(nv_object(vm->vmm), NULL, pgt_size, 0x1000,
- NVOBJ_FLAG_ZERO_ALLOC, &pgt);
- mutex_lock(&nv_subdev(vmm)->mutex);
- if (unlikely(ret))
- return ret;
-
- /* someone beat us to filling the PDE while we didn't have the lock */
- if (unlikely(vpgt->refcount[big]++)) {
- mutex_unlock(&nv_subdev(vmm)->mutex);
- nouveau_gpuobj_ref(NULL, &pgt);
- mutex_lock(&nv_subdev(vmm)->mutex);
- return 0;
- }
-
- vpgt->obj[big] = pgt;
- list_for_each_entry(vpgd, &vm->pgd_list, head) {
- vmm->map_pgt(vpgd->obj, pde, vpgt->obj);
- }
-
- return 0;
-}
-
-int
-nouveau_vm_get(struct nouveau_vm *vm, u64 size, u32 page_shift,
- u32 access, struct nouveau_vma *vma)
-{
- struct nouveau_vmmgr *vmm = vm->vmm;
- u32 align = (1 << page_shift) >> 12;
- u32 msize = size >> 12;
- u32 fpde, lpde, pde;
- int ret;
-
- mutex_lock(&nv_subdev(vmm)->mutex);
- ret = nouveau_mm_head(&vm->mm, 0, page_shift, msize, msize, align,
- &vma->node);
- if (unlikely(ret != 0)) {
- mutex_unlock(&nv_subdev(vmm)->mutex);
- return ret;
- }
-
- fpde = (vma->node->offset >> vmm->pgt_bits);
- lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
-
- for (pde = fpde; pde <= lpde; pde++) {
- struct nouveau_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
- int big = (vma->node->type != vmm->spg_shift);
-
- if (likely(vpgt->refcount[big])) {
- vpgt->refcount[big]++;
- continue;
- }
-
- ret = nouveau_vm_map_pgt(vm, pde, vma->node->type);
- if (ret) {
- if (pde != fpde)
- nouveau_vm_unmap_pgt(vm, big, fpde, pde - 1);
- nouveau_mm_free(&vm->mm, &vma->node);
- mutex_unlock(&nv_subdev(vmm)->mutex);
- return ret;
- }
- }
- mutex_unlock(&nv_subdev(vmm)->mutex);
-
- vma->vm = NULL;
- nouveau_vm_ref(vm, &vma->vm, NULL);
- vma->offset = (u64)vma->node->offset << 12;
- vma->access = access;
- return 0;
-}
-
-void
-nouveau_vm_put(struct nouveau_vma *vma)
-{
- struct nouveau_vm *vm = vma->vm;
- struct nouveau_vmmgr *vmm = vm->vmm;
- u32 fpde, lpde;
-
- if (unlikely(vma->node == NULL))
- return;
- fpde = (vma->node->offset >> vmm->pgt_bits);
- lpde = (vma->node->offset + vma->node->length - 1) >> vmm->pgt_bits;
-
- mutex_lock(&nv_subdev(vmm)->mutex);
- nouveau_vm_unmap_pgt(vm, vma->node->type != vmm->spg_shift, fpde, lpde);
- nouveau_mm_free(&vm->mm, &vma->node);
- mutex_unlock(&nv_subdev(vmm)->mutex);
-
- nouveau_vm_ref(NULL, &vma->vm, NULL);
-}
-
-int
-nouveau_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
- u64 mm_offset, u32 block, struct nouveau_vm **pvm)
-{
- struct nouveau_vm *vm;
- u64 mm_length = (offset + length) - mm_offset;
- int ret;
-
- vm = kzalloc(sizeof(*vm), GFP_KERNEL);
- if (!vm)
- return -ENOMEM;
-
- INIT_LIST_HEAD(&vm->pgd_list);
- vm->vmm = vmm;
- kref_init(&vm->refcount);
- vm->fpde = offset >> (vmm->pgt_bits + 12);
- vm->lpde = (offset + length - 1) >> (vmm->pgt_bits + 12);
-
- vm->pgt = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt));
- if (!vm->pgt) {
- kfree(vm);
- return -ENOMEM;
- }
-
- ret = nouveau_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
- block >> 12);
- if (ret) {
- vfree(vm->pgt);
- kfree(vm);
- return ret;
- }
-
- *pvm = vm;
-
- return 0;
-}
-
-int
-nouveau_vm_new(struct nouveau_device *device, u64 offset, u64 length,
- u64 mm_offset, struct nouveau_vm **pvm)
-{
- struct nouveau_vmmgr *vmm = nouveau_vmmgr(device);
- return vmm->create(vmm, offset, length, mm_offset, pvm);
-}
-
-static int
-nouveau_vm_link(struct nouveau_vm *vm, struct nouveau_gpuobj *pgd)
-{
- struct nouveau_vmmgr *vmm = vm->vmm;
- struct nouveau_vm_pgd *vpgd;
- int i;
-
- if (!pgd)
- return 0;
-
- vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL);
- if (!vpgd)
- return -ENOMEM;
-
- nouveau_gpuobj_ref(pgd, &vpgd->obj);
-
- mutex_lock(&nv_subdev(vmm)->mutex);
- for (i = vm->fpde; i <= vm->lpde; i++)
- vmm->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
- list_add(&vpgd->head, &vm->pgd_list);
- mutex_unlock(&nv_subdev(vmm)->mutex);
- return 0;
-}
-
-static void
-nouveau_vm_unlink(struct nouveau_vm *vm, struct nouveau_gpuobj *mpgd)
-{
- struct nouveau_vmmgr *vmm = vm->vmm;
- struct nouveau_vm_pgd *vpgd, *tmp;
- struct nouveau_gpuobj *pgd = NULL;
-
- if (!mpgd)
- return;
-
- mutex_lock(&nv_subdev(vmm)->mutex);
- list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
- if (vpgd->obj == mpgd) {
- pgd = vpgd->obj;
- list_del(&vpgd->head);
- kfree(vpgd);
- break;
- }
- }
- mutex_unlock(&nv_subdev(vmm)->mutex);
-
- nouveau_gpuobj_ref(NULL, &pgd);
-}
-
-static void
-nouveau_vm_del(struct kref *kref)
-{
- struct nouveau_vm *vm = container_of(kref, typeof(*vm), refcount);
- struct nouveau_vm_pgd *vpgd, *tmp;
-
- list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
- nouveau_vm_unlink(vm, vpgd->obj);
- }
-
- nouveau_mm_fini(&vm->mm);
- vfree(vm->pgt);
- kfree(vm);
-}
-
-int
-nouveau_vm_ref(struct nouveau_vm *ref, struct nouveau_vm **ptr,
- struct nouveau_gpuobj *pgd)
-{
- if (ref) {
- int ret = nouveau_vm_link(ref, pgd);
- if (ret)
- return ret;
-
- kref_get(&ref->refcount);
- }
-
- if (*ptr) {
- nouveau_vm_unlink(*ptr, pgd);
- kref_put(&(*ptr)->refcount, nouveau_vm_del);
- }
-
- *ptr = ref;
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
deleted file mode 100644
index ed45437167f2..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-
-#include "nv04.h"
-
-#define NV04_PDMA_SIZE (128 * 1024 * 1024)
-#define NV04_PDMA_PAGE ( 4 * 1024)
-
-/*******************************************************************************
- * VM map/unmap callbacks
- ******************************************************************************/
-
-static void
-nv04_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
- pte = 0x00008 + (pte * 4);
- while (cnt) {
- u32 page = PAGE_SIZE / NV04_PDMA_PAGE;
- u32 phys = (u32)*list++;
- while (cnt && page--) {
- nv_wo32(pgt, pte, phys | 3);
- phys += NV04_PDMA_PAGE;
- pte += 4;
- cnt -= 1;
- }
- }
-}
-
-static void
-nv04_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
- pte = 0x00008 + (pte * 4);
- while (cnt--) {
- nv_wo32(pgt, pte, 0x00000000);
- pte += 4;
- }
-}
-
-static void
-nv04_vm_flush(struct nouveau_vm *vm)
-{
-}
-
-/*******************************************************************************
- * VM object
- ******************************************************************************/
-
-int
-nv04_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length, u64 mmstart,
- struct nouveau_vm **pvm)
-{
- return -EINVAL;
-}
-
-/*******************************************************************************
- * VMMGR subdev
- ******************************************************************************/
-
-static int
-nv04_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv04_vmmgr_priv *priv;
- struct nouveau_gpuobj *dma;
- int ret;
-
- ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIGART",
- "pcigart", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.create = nv04_vm_create;
- priv->base.limit = NV04_PDMA_SIZE;
- priv->base.dma_bits = 32;
- priv->base.pgt_bits = 32 - 12;
- priv->base.spg_shift = 12;
- priv->base.lpg_shift = 12;
- priv->base.map_sg = nv04_vm_map_sg;
- priv->base.unmap = nv04_vm_unmap;
- priv->base.flush = nv04_vm_flush;
-
- ret = nouveau_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096,
- &priv->vm);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL,
- (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 +
- 8, 16, NVOBJ_FLAG_ZERO_ALLOC,
- &priv->vm->pgt[0].obj[0]);
- dma = priv->vm->pgt[0].obj[0];
- priv->vm->pgt[0].refcount[0] = 1;
- if (ret)
- return ret;
-
- nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */
- nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1);
- return 0;
-}
-
-void
-nv04_vmmgr_dtor(struct nouveau_object *object)
-{
- struct nv04_vmmgr_priv *priv = (void *)object;
- if (priv->vm) {
- nouveau_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]);
- nouveau_vm_ref(NULL, &priv->vm, NULL);
- }
- if (priv->nullp) {
- pci_free_consistent(nv_device(priv)->pdev, 16 * 1024,
- priv->nullp, priv->null);
- }
- nouveau_vmmgr_destroy(&priv->base);
-}
-
-struct nouveau_oclass
-nv04_vmmgr_oclass = {
- .handle = NV_SUBDEV(VM, 0x04),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv04_vmmgr_ctor,
- .dtor = nv04_vmmgr_dtor,
- .init = _nouveau_vmmgr_init,
- .fini = _nouveau_vmmgr_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h b/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
deleted file mode 100644
index ec42d4bc86a6..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv04.h
+++ /dev/null
@@ -1,19 +0,0 @@
-#ifndef __NV04_VMMGR_PRIV__
-#define __NV04_VMMGR_PRIV__
-
-#include <subdev/vm.h>
-
-struct nv04_vmmgr_priv {
- struct nouveau_vmmgr base;
- struct nouveau_vm *vm;
- dma_addr_t null;
- void *nullp;
-};
-
-static inline struct nv04_vmmgr_priv *
-nv04_vmmgr(void *obj)
-{
- return (void *)nouveau_vmmgr(obj);
-}
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
deleted file mode 100644
index 064c76262876..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv41.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <core/option.h>
-
-#include <subdev/timer.h>
-#include <subdev/vm.h>
-
-#include "nv04.h"
-
-#define NV41_GART_SIZE (512 * 1024 * 1024)
-#define NV41_GART_PAGE ( 4 * 1024)
-
-/*******************************************************************************
- * VM map/unmap callbacks
- ******************************************************************************/
-
-static void
-nv41_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
- pte = pte * 4;
- while (cnt) {
- u32 page = PAGE_SIZE / NV41_GART_PAGE;
- u64 phys = (u64)*list++;
- while (cnt && page--) {
- nv_wo32(pgt, pte, (phys >> 7) | 1);
- phys += NV41_GART_PAGE;
- pte += 4;
- cnt -= 1;
- }
- }
-}
-
-static void
-nv41_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
- pte = pte * 4;
- while (cnt--) {
- nv_wo32(pgt, pte, 0x00000000);
- pte += 4;
- }
-}
-
-static void
-nv41_vm_flush(struct nouveau_vm *vm)
-{
- struct nv04_vmmgr_priv *priv = (void *)vm->vmm;
-
- mutex_lock(&nv_subdev(priv)->mutex);
- nv_wr32(priv, 0x100810, 0x00000022);
- if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) {
- nv_warn(priv, "flush timeout, 0x%08x\n",
- nv_rd32(priv, 0x100810));
- }
- nv_wr32(priv, 0x100810, 0x00000000);
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-/*******************************************************************************
- * VMMGR subdev
- ******************************************************************************/
-
-static int
-nv41_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nv04_vmmgr_priv *priv;
- int ret;
-
- if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
- !nouveau_boolopt(device->cfgopt, "NvPCIE", true)) {
- return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass,
- data, size, pobject);
- }
-
- ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART",
- "pciegart", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.create = nv04_vm_create;
- priv->base.limit = NV41_GART_SIZE;
- priv->base.dma_bits = 39;
- priv->base.pgt_bits = 32 - 12;
- priv->base.spg_shift = 12;
- priv->base.lpg_shift = 12;
- priv->base.map_sg = nv41_vm_map_sg;
- priv->base.unmap = nv41_vm_unmap;
- priv->base.flush = nv41_vm_flush;
-
- ret = nouveau_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096,
- &priv->vm);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL,
- (NV41_GART_SIZE / NV41_GART_PAGE) * 4,
- 16, NVOBJ_FLAG_ZERO_ALLOC,
- &priv->vm->pgt[0].obj[0]);
- priv->vm->pgt[0].refcount[0] = 1;
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int
-nv41_vmmgr_init(struct nouveau_object *object)
-{
- struct nv04_vmmgr_priv *priv = (void *)object;
- struct nouveau_gpuobj *dma = priv->vm->pgt[0].obj[0];
- int ret;
-
- ret = nouveau_vmmgr_init(&priv->base);
- if (ret)
- return ret;
-
- nv_wr32(priv, 0x100800, dma->addr | 0x00000002);
- nv_mask(priv, 0x10008c, 0x00000100, 0x00000100);
- nv_wr32(priv, 0x100820, 0x00000000);
- return 0;
-}
-
-struct nouveau_oclass
-nv41_vmmgr_oclass = {
- .handle = NV_SUBDEV(VM, 0x41),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv41_vmmgr_ctor,
- .dtor = nv04_vmmgr_dtor,
- .init = nv41_vmmgr_init,
- .fini = _nouveau_vmmgr_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
deleted file mode 100644
index fae1f67d5948..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv44.c
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2012 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/gpuobj.h>
-#include <core/option.h>
-
-#include <subdev/timer.h>
-#include <subdev/vm.h>
-
-#include "nv04.h"
-
-#define NV44_GART_SIZE (512 * 1024 * 1024)
-#define NV44_GART_PAGE ( 4 * 1024)
-
-/*******************************************************************************
- * VM map/unmap callbacks
- ******************************************************************************/
-
-static void
-nv44_vm_fill(struct nouveau_gpuobj *pgt, dma_addr_t null,
- dma_addr_t *list, u32 pte, u32 cnt)
-{
- u32 base = (pte << 2) & ~0x0000000f;
- u32 tmp[4];
-
- tmp[0] = nv_ro32(pgt, base + 0x0);
- tmp[1] = nv_ro32(pgt, base + 0x4);
- tmp[2] = nv_ro32(pgt, base + 0x8);
- tmp[3] = nv_ro32(pgt, base + 0xc);
-
- while (cnt--) {
- u32 addr = list ? (*list++ >> 12) : (null >> 12);
- switch (pte++ & 0x3) {
- case 0:
- tmp[0] &= ~0x07ffffff;
- tmp[0] |= addr;
- break;
- case 1:
- tmp[0] &= ~0xf8000000;
- tmp[0] |= addr << 27;
- tmp[1] &= ~0x003fffff;
- tmp[1] |= addr >> 5;
- break;
- case 2:
- tmp[1] &= ~0xffc00000;
- tmp[1] |= addr << 22;
- tmp[2] &= ~0x0001ffff;
- tmp[2] |= addr >> 10;
- break;
- case 3:
- tmp[2] &= ~0xfffe0000;
- tmp[2] |= addr << 17;
- tmp[3] &= ~0x00000fff;
- tmp[3] |= addr >> 15;
- break;
- }
- }
-
- nv_wo32(pgt, base + 0x0, tmp[0]);
- nv_wo32(pgt, base + 0x4, tmp[1]);
- nv_wo32(pgt, base + 0x8, tmp[2]);
- nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000);
-}
-
-static void
-nv44_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
- struct nv04_vmmgr_priv *priv = (void *)vma->vm->vmm;
- u32 tmp[4];
- int i;
-
- if (pte & 3) {
- u32 max = 4 - (pte & 3);
- u32 part = (cnt > max) ? max : cnt;
- nv44_vm_fill(pgt, priv->null, list, pte, part);
- pte += part;
- list += part;
- cnt -= part;
- }
-
- while (cnt >= 4) {
- for (i = 0; i < 4; i++)
- tmp[i] = *list++ >> 12;
- nv_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27);
- nv_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22);
- nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17);
- nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000);
- cnt -= 4;
- }
-
- if (cnt)
- nv44_vm_fill(pgt, priv->null, list, pte, cnt);
-}
-
-static void
-nv44_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
- struct nv04_vmmgr_priv *priv = (void *)nouveau_vmmgr(pgt);
-
- if (pte & 3) {
- u32 max = 4 - (pte & 3);
- u32 part = (cnt > max) ? max : cnt;
- nv44_vm_fill(pgt, priv->null, NULL, pte, part);
- pte += part;
- cnt -= part;
- }
-
- while (cnt >= 4) {
- nv_wo32(pgt, pte++ * 4, 0x00000000);
- nv_wo32(pgt, pte++ * 4, 0x00000000);
- nv_wo32(pgt, pte++ * 4, 0x00000000);
- nv_wo32(pgt, pte++ * 4, 0x00000000);
- cnt -= 4;
- }
-
- if (cnt)
- nv44_vm_fill(pgt, priv->null, NULL, pte, cnt);
-}
-
-static void
-nv44_vm_flush(struct nouveau_vm *vm)
-{
- struct nv04_vmmgr_priv *priv = (void *)vm->vmm;
- nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE);
- nv_wr32(priv, 0x100808, 0x00000020);
- if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001))
- nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808));
- nv_wr32(priv, 0x100808, 0x00000000);
-}
-
-/*******************************************************************************
- * VMMGR subdev
- ******************************************************************************/
-
-static int
-nv44_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nouveau_device *device = nv_device(parent);
- struct nv04_vmmgr_priv *priv;
- int ret;
-
- if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
- !nouveau_boolopt(device->cfgopt, "NvPCIE", true)) {
- return nouveau_object_ctor(parent, engine, &nv04_vmmgr_oclass,
- data, size, pobject);
- }
-
- ret = nouveau_vmmgr_create(parent, engine, oclass, "PCIEGART",
- "pciegart", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.create = nv04_vm_create;
- priv->base.limit = NV44_GART_SIZE;
- priv->base.dma_bits = 39;
- priv->base.pgt_bits = 32 - 12;
- priv->base.spg_shift = 12;
- priv->base.lpg_shift = 12;
- priv->base.map_sg = nv44_vm_map_sg;
- priv->base.unmap = nv44_vm_unmap;
- priv->base.flush = nv44_vm_flush;
-
- priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null);
- if (!priv->nullp) {
- nv_error(priv, "unable to allocate dummy pages\n");
- return -ENOMEM;
- }
-
- ret = nouveau_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096,
- &priv->vm);
- if (ret)
- return ret;
-
- ret = nouveau_gpuobj_new(nv_object(priv), NULL,
- (NV44_GART_SIZE / NV44_GART_PAGE) * 4,
- 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC,
- &priv->vm->pgt[0].obj[0]);
- priv->vm->pgt[0].refcount[0] = 1;
- if (ret)
- return ret;
-
- return 0;
-}
-
-static int
-nv44_vmmgr_init(struct nouveau_object *object)
-{
- struct nv04_vmmgr_priv *priv = (void *)object;
- struct nouveau_gpuobj *gart = priv->vm->pgt[0].obj[0];
- u32 addr;
- int ret;
-
- ret = nouveau_vmmgr_init(&priv->base);
- if (ret)
- return ret;
-
- /* calculate vram address of this PRAMIN block, object must be
- * allocated on 512KiB alignment, and not exceed a total size
- * of 512KiB for this to work correctly
- */
- addr = nv_rd32(priv, 0x10020c);
- addr -= ((gart->addr >> 19) + 1) << 19;
-
- nv_wr32(priv, 0x100850, 0x80000000);
- nv_wr32(priv, 0x100818, priv->null);
- nv_wr32(priv, 0x100804, NV44_GART_SIZE);
- nv_wr32(priv, 0x100850, 0x00008000);
- nv_mask(priv, 0x10008c, 0x00000200, 0x00000200);
- nv_wr32(priv, 0x100820, 0x00000000);
- nv_wr32(priv, 0x10082c, 0x00000001);
- nv_wr32(priv, 0x100800, addr | 0x00000010);
- return 0;
-}
-
-struct nouveau_oclass
-nv44_vmmgr_oclass = {
- .handle = NV_SUBDEV(VM, 0x44),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv44_vmmgr_ctor,
- .dtor = nv04_vmmgr_dtor,
- .init = nv44_vmmgr_init,
- .fini = _nouveau_vmmgr_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
deleted file mode 100644
index a4aa81a2173b..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nv50.c
+++ /dev/null
@@ -1,240 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/bar.h>
-#include <subdev/vm.h>
-
-struct nv50_vmmgr_priv {
- struct nouveau_vmmgr base;
-};
-
-static void
-nv50_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 pde,
- struct nouveau_gpuobj *pgt[2])
-{
- u64 phys = 0xdeadcafe00000000ULL;
- u32 coverage = 0;
-
- if (pgt[0]) {
- phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */
- coverage = (pgt[0]->size >> 3) << 12;
- } else
- if (pgt[1]) {
- phys = 0x00000001 | pgt[1]->addr; /* present */
- coverage = (pgt[1]->size >> 3) << 16;
- }
-
- if (phys & 1) {
- if (coverage <= 32 * 1024 * 1024)
- phys |= 0x60;
- else if (coverage <= 64 * 1024 * 1024)
- phys |= 0x40;
- else if (coverage <= 128 * 1024 * 1024)
- phys |= 0x20;
- }
-
- nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys));
- nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys));
-}
-
-static inline u64
-vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
-{
- phys |= 1; /* present */
- phys |= (u64)memtype << 40;
- phys |= target << 4;
- if (vma->access & NV_MEM_ACCESS_SYS)
- phys |= (1 << 6);
- if (!(vma->access & NV_MEM_ACCESS_WO))
- phys |= (1 << 3);
- return phys;
-}
-
-static void
-nv50_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
-{
- u32 comp = (mem->memtype & 0x180) >> 7;
- u32 block, target;
- int i;
-
- /* IGPs don't have real VRAM, re-target to stolen system memory */
- target = 0;
- if (nouveau_fb(vma->vm->vmm)->ram->stolen) {
- phys += nouveau_fb(vma->vm->vmm)->ram->stolen;
- target = 3;
- }
-
- phys = vm_addr(vma, phys, mem->memtype, target);
- pte <<= 3;
- cnt <<= 3;
-
- while (cnt) {
- u32 offset_h = upper_32_bits(phys);
- u32 offset_l = lower_32_bits(phys);
-
- for (i = 7; i >= 0; i--) {
- block = 1 << (i + 3);
- if (cnt >= block && !(pte & (block - 1)))
- break;
- }
- offset_l |= (i << 7);
-
- phys += block << (vma->node->type - 3);
- cnt -= block;
- if (comp) {
- u32 tag = mem->tag->offset + ((delta >> 16) * comp);
- offset_h |= (tag << 17);
- delta += block << (vma->node->type - 3);
- }
-
- while (block) {
- nv_wo32(pgt, pte + 0, offset_l);
- nv_wo32(pgt, pte + 4, offset_h);
- pte += 8;
- block -= 8;
- }
- }
-}
-
-static void
-nv50_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
- u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2;
- pte <<= 3;
- while (cnt--) {
- u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target);
- nv_wo32(pgt, pte + 0, lower_32_bits(phys));
- nv_wo32(pgt, pte + 4, upper_32_bits(phys));
- pte += 8;
- }
-}
-
-static void
-nv50_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
- pte <<= 3;
- while (cnt--) {
- nv_wo32(pgt, pte + 0, 0x00000000);
- nv_wo32(pgt, pte + 4, 0x00000000);
- pte += 8;
- }
-}
-
-static void
-nv50_vm_flush(struct nouveau_vm *vm)
-{
- struct nv50_vmmgr_priv *priv = (void *)vm->vmm;
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nouveau_engine *engine;
- int i, vme;
-
- bar->flush(bar);
-
- mutex_lock(&nv_subdev(priv)->mutex);
- for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
- if (!atomic_read(&vm->engref[i]))
- continue;
-
- /* unfortunate hw bug workaround... */
- engine = nouveau_engine(priv, i);
- if (engine && engine->tlb_flush) {
- engine->tlb_flush(engine);
- continue;
- }
-
- switch (i) {
- case NVDEV_ENGINE_GR : vme = 0x00; break;
- case NVDEV_ENGINE_VP : vme = 0x01; break;
- case NVDEV_SUBDEV_BAR : vme = 0x06; break;
- case NVDEV_ENGINE_PPP :
- case NVDEV_ENGINE_MPEG : vme = 0x08; break;
- case NVDEV_ENGINE_BSP : vme = 0x09; break;
- case NVDEV_ENGINE_CRYPT: vme = 0x0a; break;
- case NVDEV_ENGINE_COPY0: vme = 0x0d; break;
- default:
- continue;
- }
-
- nv_wr32(priv, 0x100c80, (vme << 16) | 1);
- if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
- nv_error(priv, "vm flush timeout: engine %d\n", vme);
- }
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nv50_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
- u64 mm_offset, struct nouveau_vm **pvm)
-{
- u32 block = (1 << (vmm->pgt_bits + 12));
- if (block > length)
- block = length;
-
- return nouveau_vm_create(vmm, offset, length, mm_offset, block, pvm);
-}
-
-static int
-nv50_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv50_vmmgr_priv *priv;
- int ret;
-
- ret = nouveau_vmmgr_create(parent, engine, oclass, "VM", "vm", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.limit = 1ULL << 40;
- priv->base.dma_bits = 40;
- priv->base.pgt_bits = 29 - 12;
- priv->base.spg_shift = 12;
- priv->base.lpg_shift = 16;
- priv->base.create = nv50_vm_create;
- priv->base.map_pgt = nv50_vm_map_pgt;
- priv->base.map = nv50_vm_map;
- priv->base.map_sg = nv50_vm_map_sg;
- priv->base.unmap = nv50_vm_unmap;
- priv->base.flush = nv50_vm_flush;
- return 0;
-}
-
-struct nouveau_oclass
-nv50_vmmgr_oclass = {
- .handle = NV_SUBDEV(VM, 0x50),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv50_vmmgr_ctor,
- .dtor = _nouveau_vmmgr_dtor,
- .init = _nouveau_vmmgr_init,
- .fini = _nouveau_vmmgr_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c b/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
deleted file mode 100644
index 2d0988755530..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/vm/nvc0.c
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright 2010 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <core/device.h>
-#include <core/gpuobj.h>
-
-#include <subdev/timer.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/ltc.h>
-#include <subdev/bar.h>
-
-struct nvc0_vmmgr_priv {
- struct nouveau_vmmgr base;
-};
-
-
-/* Map from compressed to corresponding uncompressed storage type.
- * The value 0xff represents an invalid storage type.
- */
-const u8 nvc0_pte_storage_type_map[256] =
-{
- 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, /* 0x00 */
- 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, /* 0x10 */
- 0x11, 0x11, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x27, /* 0x20 */
- 0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
- 0xff, 0xff, 0x26, 0x27, 0x28, 0x29, 0x26, 0x27,
- 0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0x46, 0xff, /* 0x40 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0x46, 0x46, 0x46, 0x46, 0xff, 0xff, 0xff, /* 0x50 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
- 0xff, 0xff, 0xff, 0x7b, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x7b, /* 0x80 */
- 0x7b, 0x7b, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xa7, /* 0xa0 */
- 0xa8, 0xa9, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
- 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xc3, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
- 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xc3, 0xc3,
- 0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
- 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
- 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, /* 0xe0 */
- 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff,
- 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0 */
- 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xfe, 0xff
-};
-
-
-static void
-nvc0_vm_map_pgt(struct nouveau_gpuobj *pgd, u32 index,
- struct nouveau_gpuobj *pgt[2])
-{
- u32 pde[2] = { 0, 0 };
-
- if (pgt[0])
- pde[1] = 0x00000001 | (pgt[0]->addr >> 8);
- if (pgt[1])
- pde[0] = 0x00000001 | (pgt[1]->addr >> 8);
-
- nv_wo32(pgd, (index * 8) + 0, pde[0]);
- nv_wo32(pgd, (index * 8) + 4, pde[1]);
-}
-
-static inline u64
-nvc0_vm_addr(struct nouveau_vma *vma, u64 phys, u32 memtype, u32 target)
-{
- phys >>= 8;
-
- phys |= 0x00000001; /* present */
- if (vma->access & NV_MEM_ACCESS_SYS)
- phys |= 0x00000002;
-
- phys |= ((u64)target << 32);
- phys |= ((u64)memtype << 36);
-
- return phys;
-}
-
-static void
-nvc0_vm_map(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
-{
- u64 next = 1 << (vma->node->type - 8);
-
- phys = nvc0_vm_addr(vma, phys, mem->memtype, 0);
- pte <<= 3;
-
- if (mem->tag) {
- struct nouveau_ltc *ltc =
- nouveau_ltc(vma->vm->vmm->base.base.parent);
- u32 tag = mem->tag->offset + (delta >> 17);
- phys |= (u64)tag << (32 + 12);
- next |= (u64)1 << (32 + 12);
- ltc->tags_clear(ltc, tag, cnt);
- }
-
- while (cnt--) {
- nv_wo32(pgt, pte + 0, lower_32_bits(phys));
- nv_wo32(pgt, pte + 4, upper_32_bits(phys));
- phys += next;
- pte += 8;
- }
-}
-
-static void
-nvc0_vm_map_sg(struct nouveau_vma *vma, struct nouveau_gpuobj *pgt,
- struct nouveau_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
-{
- u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5;
- /* compressed storage types are invalid for system memory */
- u32 memtype = nvc0_pte_storage_type_map[mem->memtype & 0xff];
-
- pte <<= 3;
- while (cnt--) {
- u64 phys = nvc0_vm_addr(vma, *list++, memtype, target);
- nv_wo32(pgt, pte + 0, lower_32_bits(phys));
- nv_wo32(pgt, pte + 4, upper_32_bits(phys));
- pte += 8;
- }
-}
-
-static void
-nvc0_vm_unmap(struct nouveau_gpuobj *pgt, u32 pte, u32 cnt)
-{
- pte <<= 3;
- while (cnt--) {
- nv_wo32(pgt, pte + 0, 0x00000000);
- nv_wo32(pgt, pte + 4, 0x00000000);
- pte += 8;
- }
-}
-
-static void
-nvc0_vm_flush(struct nouveau_vm *vm)
-{
- struct nvc0_vmmgr_priv *priv = (void *)vm->vmm;
- struct nouveau_bar *bar = nouveau_bar(priv);
- struct nouveau_vm_pgd *vpgd;
- u32 type;
-
- bar->flush(bar);
-
- type = 0x00000001; /* PAGE_ALL */
- if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR]))
- type |= 0x00000004; /* HUB_ONLY */
-
- mutex_lock(&nv_subdev(priv)->mutex);
- list_for_each_entry(vpgd, &vm->pgd_list, head) {
- /* looks like maybe a "free flush slots" counter, the
- * faster you write to 0x100cbc to more it decreases
- */
- if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) {
- nv_error(priv, "vm timeout 0: 0x%08x %d\n",
- nv_rd32(priv, 0x100c80), type);
- }
-
- nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8);
- nv_wr32(priv, 0x100cbc, 0x80000000 | type);
-
- /* wait for flush to be queued? */
- if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) {
- nv_error(priv, "vm timeout 1: 0x%08x %d\n",
- nv_rd32(priv, 0x100c80), type);
- }
- }
- mutex_unlock(&nv_subdev(priv)->mutex);
-}
-
-static int
-nvc0_vm_create(struct nouveau_vmmgr *vmm, u64 offset, u64 length,
- u64 mm_offset, struct nouveau_vm **pvm)
-{
- return nouveau_vm_create(vmm, offset, length, mm_offset, 4096, pvm);
-}
-
-static int
-nvc0_vmmgr_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nvc0_vmmgr_priv *priv;
- int ret;
-
- ret = nouveau_vmmgr_create(parent, engine, oclass, "VM", "vm", &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- priv->base.limit = 1ULL << 40;
- priv->base.dma_bits = 40;
- priv->base.pgt_bits = 27 - 12;
- priv->base.spg_shift = 12;
- priv->base.lpg_shift = 17;
- priv->base.create = nvc0_vm_create;
- priv->base.map_pgt = nvc0_vm_map_pgt;
- priv->base.map = nvc0_vm_map;
- priv->base.map_sg = nvc0_vm_map_sg;
- priv->base.unmap = nvc0_vm_unmap;
- priv->base.flush = nvc0_vm_flush;
- return 0;
-}
-
-struct nouveau_oclass
-nvc0_vmmgr_oclass = {
- .handle = NV_SUBDEV(VM, 0xc0),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nvc0_vmmgr_ctor,
- .dtor = _nouveau_vmmgr_dtor,
- .init = _nouveau_vmmgr_init,
- .fini = _nouveau_vmmgr_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c b/drivers/gpu/drm/nouveau/core/subdev/volt/base.c
deleted file mode 100644
index 26ccd8df193f..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/base.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/volt.h>
-
-#include <subdev/bios.h>
-#include <subdev/bios/vmap.h>
-#include <subdev/bios/volt.h>
-
-static int
-nouveau_volt_get(struct nouveau_volt *volt)
-{
- if (volt->vid_get) {
- int ret = volt->vid_get(volt), i;
- if (ret >= 0) {
- for (i = 0; i < volt->vid_nr; i++) {
- if (volt->vid[i].vid == ret)
- return volt->vid[i].uv;
- }
- ret = -EINVAL;
- }
- return ret;
- }
- return -ENODEV;
-}
-
-static int
-nouveau_volt_set(struct nouveau_volt *volt, u32 uv)
-{
- if (volt->vid_set) {
- int i, ret = -EINVAL;
- for (i = 0; i < volt->vid_nr; i++) {
- if (volt->vid[i].uv == uv) {
- ret = volt->vid_set(volt, volt->vid[i].vid);
- nv_debug(volt, "set %duv: %d\n", uv, ret);
- break;
- }
- }
- return ret;
- }
- return -ENODEV;
-}
-
-static int
-nouveau_volt_map(struct nouveau_volt *volt, u8 id)
-{
- struct nouveau_bios *bios = nouveau_bios(volt);
- struct nvbios_vmap_entry info;
- u8 ver, len;
- u16 vmap;
-
- vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
- if (vmap) {
- if (info.link != 0xff) {
- int ret = nouveau_volt_map(volt, info.link);
- if (ret < 0)
- return ret;
- info.min += ret;
- }
- return info.min;
- }
-
- return id ? id * 10000 : -ENODEV;
-}
-
-static int
-nouveau_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
-{
- int ret = nouveau_volt_map(volt, id);
- if (ret >= 0) {
- int prev = nouveau_volt_get(volt);
- if (!condition || prev < 0 ||
- (condition < 0 && ret < prev) ||
- (condition > 0 && ret > prev)) {
- ret = nouveau_volt_set(volt, ret);
- } else {
- ret = 0;
- }
- }
- return ret;
-}
-
-static void nouveau_volt_parse_bios(struct nouveau_bios *bios,
- struct nouveau_volt *volt)
-{
- struct nvbios_volt_entry ivid;
- struct nvbios_volt info;
- u8 ver, hdr, cnt, len;
- u16 data;
- int i;
-
- data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
- if (data && info.vidmask && info.base && info.step) {
- for (i = 0; i < info.vidmask + 1; i++) {
- if (info.base >= info.min &&
- info.base <= info.max) {
- volt->vid[volt->vid_nr].uv = info.base;
- volt->vid[volt->vid_nr].vid = i;
- volt->vid_nr++;
- }
- info.base += info.step;
- }
- volt->vid_mask = info.vidmask;
- } else if (data && info.vidmask) {
- for (i = 0; i < cnt; i++) {
- data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
- &ivid);
- if (data) {
- volt->vid[volt->vid_nr].uv = ivid.voltage;
- volt->vid[volt->vid_nr].vid = ivid.vid;
- volt->vid_nr++;
- }
- }
- volt->vid_mask = info.vidmask;
- }
-}
-
-int
-_nouveau_volt_init(struct nouveau_object *object)
-{
- struct nouveau_volt *volt = (void *)object;
- int ret;
-
- ret = nouveau_subdev_init(&volt->base);
- if (ret)
- return ret;
-
- ret = volt->get(volt);
- if (ret < 0) {
- if (ret != -ENODEV)
- nv_debug(volt, "current voltage unknown\n");
- return 0;
- }
-
- nv_info(volt, "GPU voltage: %duv\n", ret);
- return 0;
-}
-
-void
-_nouveau_volt_dtor(struct nouveau_object *object)
-{
- struct nouveau_volt *volt = (void *)object;
- nouveau_subdev_destroy(&volt->base);
-}
-
-int
-nouveau_volt_create_(struct nouveau_object *parent,
- struct nouveau_object *engine,
- struct nouveau_oclass *oclass, int length, void **pobject)
-{
- struct nouveau_bios *bios = nouveau_bios(parent);
- struct nouveau_volt *volt;
- int ret, i;
-
- ret = nouveau_subdev_create_(parent, engine, oclass, 0, "VOLT",
- "voltage", length, pobject);
- volt = *pobject;
- if (ret)
- return ret;
-
- volt->get = nouveau_volt_get;
- volt->set = nouveau_volt_set;
- volt->set_id = nouveau_volt_set_id;
-
- /* Assuming the non-bios device should build the voltage table later */
- if (bios)
- nouveau_volt_parse_bios(bios, volt);
-
- if (volt->vid_nr) {
- for (i = 0; i < volt->vid_nr; i++) {
- nv_debug(volt, "VID %02x: %duv\n",
- volt->vid[i].vid, volt->vid[i].uv);
- }
-
- /*XXX: this is an assumption.. there probably exists boards
- * out there with i2c-connected voltage controllers too..
- */
- ret = nouveau_voltgpio_init(volt);
- if (ret == 0) {
- volt->vid_get = nouveau_voltgpio_get;
- volt->vid_set = nouveau_voltgpio_set;
- }
- }
-
- return ret;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c
deleted file mode 100644
index 717368ef31ac..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/gk20a.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
- */
-
-#ifdef __KERNEL__
-#include <nouveau_platform.h>
-#endif
-#include <subdev/volt.h>
-
-struct cvb_coef {
- int c0;
- int c1;
- int c2;
- int c3;
- int c4;
- int c5;
-};
-
-struct gk20a_volt_priv {
- struct nouveau_volt base;
- struct regulator *vdd;
-};
-
-const struct cvb_coef gk20a_cvb_coef[] = {
- /* MHz, c0, c1, c2, c3, c4, c5 */
- /* 72 */ { 1209886, -36468, 515, 417, -13123, 203},
- /* 108 */ { 1130804, -27659, 296, 298, -10834, 221},
- /* 180 */ { 1162871, -27110, 247, 238, -10681, 268},
- /* 252 */ { 1220458, -28654, 247, 179, -10376, 298},
- /* 324 */ { 1280953, -30204, 247, 119, -9766, 304},
- /* 396 */ { 1344547, -31777, 247, 119, -8545, 292},
- /* 468 */ { 1420168, -34227, 269, 60, -7172, 256},
- /* 540 */ { 1490757, -35955, 274, 60, -5188, 197},
- /* 612 */ { 1599112, -42583, 398, 0, -1831, 119},
- /* 648 */ { 1366986, -16459, -274, 0, -3204, 72},
- /* 684 */ { 1391884, -17078, -274, -60, -1526, 30},
- /* 708 */ { 1415522, -17497, -274, -60, -458, 0},
- /* 756 */ { 1464061, -18331, -274, -119, 1831, -72},
- /* 804 */ { 1524225, -20064, -254, -119, 4272, -155},
- /* 852 */ { 1608418, -21643, -269, 0, 763, -48},
-};
-
-/**
- * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
- */
-static inline int
-gk20a_volt_get_cvb_voltage(int speedo, int s_scale,
- const struct cvb_coef *coef)
-{
- int mv;
-
- mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale);
- mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0;
- return mv;
-}
-
-/**
- * cvb_t_mv =
- * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
- * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
- */
-static inline int
-gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale,
- const struct cvb_coef *coef)
-{
- int cvb_mv, mv;
-
- cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef);
-
- mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 +
- DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale);
- mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv;
- return mv;
-}
-
-static int
-gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo)
-{
- int mv;
-
- mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef);
- mv = DIV_ROUND_UP(mv, 1000);
-
- return mv * 1000;
-}
-
-static int
-gk20a_volt_vid_get(struct nouveau_volt *volt)
-{
- struct gk20a_volt_priv *priv = (void *)volt;
- int i, uv;
-
- uv = regulator_get_voltage(priv->vdd);
-
- for (i = 0; i < volt->vid_nr; i++)
- if (volt->vid[i].uv >= uv)
- return i;
-
- return -EINVAL;
-}
-
-static int
-gk20a_volt_vid_set(struct nouveau_volt *volt, u8 vid)
-{
- struct gk20a_volt_priv *priv = (void *)volt;
-
- nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv);
- return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000);
-}
-
-static int
-gk20a_volt_set_id(struct nouveau_volt *volt, u8 id, int condition)
-{
- struct gk20a_volt_priv *priv = (void *)volt;
- int prev_uv = regulator_get_voltage(priv->vdd);
- int target_uv = volt->vid[id].uv;
- int ret;
-
- nv_debug(volt, "prev=%d, target=%d, condition=%d\n",
- prev_uv, target_uv, condition);
- if (!condition ||
- (condition < 0 && target_uv < prev_uv) ||
- (condition > 0 && target_uv > prev_uv)) {
- ret = gk20a_volt_vid_set(volt, volt->vid[id].vid);
- } else {
- ret = 0;
- }
-
- return ret;
-}
-
-static int
-gk20a_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct gk20a_volt_priv *priv;
- struct nouveau_volt *volt;
- struct nouveau_platform_device *plat;
- int i, ret, uv;
-
- ret = nouveau_volt_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- volt = &priv->base;
-
- plat = nv_device_to_platform(nv_device(parent));
-
- uv = regulator_get_voltage(plat->gpu->vdd);
- nv_info(priv, "The default voltage is %duV\n", uv);
-
- priv->vdd = plat->gpu->vdd;
- priv->base.vid_get = gk20a_volt_vid_get;
- priv->base.vid_set = gk20a_volt_vid_set;
- priv->base.set_id = gk20a_volt_set_id;
-
- volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef);
- nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr);
- for (i = 0; i < volt->vid_nr; i++) {
- volt->vid[i].vid = i;
- volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i],
- plat->gpu_speedo);
- nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid,
- volt->vid[i].uv);
- }
-
- return 0;
-}
-
-struct nouveau_oclass
-gk20a_volt_oclass = {
- .handle = NV_SUBDEV(VOLT, 0xea),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = gk20a_volt_ctor,
- .dtor = _nouveau_volt_dtor,
- .init = _nouveau_volt_init,
- .fini = _nouveau_volt_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c
deleted file mode 100644
index 755fa91bcd09..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/gpio.c
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/volt.h>
-#include <subdev/gpio.h>
-#include <subdev/bios/gpio.h>
-
-static const u8 tags[] = {
- DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
- DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
-};
-
-int
-nouveau_voltgpio_get(struct nouveau_volt *volt)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(volt);
- u8 vid = 0;
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tags); i++) {
- if (volt->vid_mask & (1 << i)) {
- int ret = gpio->get(gpio, 0, tags[i], 0xff);
- if (ret < 0)
- return ret;
- vid |= ret << i;
- }
- }
-
- return vid;
-}
-
-int
-nouveau_voltgpio_set(struct nouveau_volt *volt, u8 vid)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(volt);
- int i;
-
- for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
- if (volt->vid_mask & (1 << i)) {
- int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
- if (ret < 0)
- return ret;
- }
- }
-
- return 0;
-}
-
-int
-nouveau_voltgpio_init(struct nouveau_volt *volt)
-{
- struct nouveau_gpio *gpio = nouveau_gpio(volt);
- struct dcb_gpio_func func;
- int i;
-
- /* check we have gpio function info for each vid bit. on some
- * boards (ie. nvs295) the vid mask has more bits than there
- * are valid gpio functions... from traces, nvidia appear to
- * just touch the existing ones, so let's mask off the invalid
- * bits and continue with life
- */
- for (i = 0; i < ARRAY_SIZE(tags); i++) {
- if (volt->vid_mask & (1 << i)) {
- int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
- if (ret) {
- if (ret != -ENOENT)
- return ret;
- nv_debug(volt, "VID bit %d has no GPIO\n", i);
- volt->vid_mask &= ~(1 << i);
- }
- }
- }
-
- return 0;
-}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c
deleted file mode 100644
index 87d5358376a6..000000000000
--- a/drivers/gpu/drm/nouveau/core/subdev/volt/nv40.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright 2013 Red Hat Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
- * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
- * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- * OTHER DEALINGS IN THE SOFTWARE.
- *
- * Authors: Ben Skeggs
- */
-
-#include <subdev/volt.h>
-
-struct nv40_volt_priv {
- struct nouveau_volt base;
-};
-
-static int
-nv40_volt_ctor(struct nouveau_object *parent, struct nouveau_object *engine,
- struct nouveau_oclass *oclass, void *data, u32 size,
- struct nouveau_object **pobject)
-{
- struct nv40_volt_priv *priv;
- int ret;
-
- ret = nouveau_volt_create(parent, engine, oclass, &priv);
- *pobject = nv_object(priv);
- if (ret)
- return ret;
-
- return 0;
-}
-
-struct nouveau_oclass
-nv40_volt_oclass = {
- .handle = NV_SUBDEV(VOLT, 0x40),
- .ofuncs = &(struct nouveau_ofuncs) {
- .ctor = nv40_volt_ctor,
- .dtor = _nouveau_volt_dtor,
- .init = _nouveau_volt_init,
- .fini = _nouveau_volt_fini,
- },
-};
diff --git a/drivers/gpu/drm/nouveau/dispnv04/Makefile b/drivers/gpu/drm/nouveau/dispnv04/Kbuild
index 424a489d0f03..424a489d0f03 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/Makefile
+++ b/drivers/gpu/drm/nouveau/dispnv04/Kbuild
diff --git a/drivers/gpu/drm/nouveau/dispnv04/crtc.c b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
index 38402ade6835..542bb266a0ab 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/crtc.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/crtc.c
@@ -41,7 +41,7 @@
#include "disp.h"
#include <subdev/bios/pll.h>
-#include <subdev/clock.h>
+#include <subdev/clk.h>
static int
nv04_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
@@ -112,12 +112,12 @@ static void nv_crtc_calc_state_ext(struct drm_crtc *crtc, struct drm_display_mod
{
struct drm_device *dev = crtc->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_bios *bios = nvkm_bios(&drm->device);
- struct nouveau_clock *clk = nvkm_clock(&drm->device);
+ struct nvkm_bios *bios = nvxx_bios(&drm->device);
+ struct nvkm_clk *clk = nvxx_clk(&drm->device);
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nv04_mode_state *state = &nv04_display(dev)->mode_reg;
struct nv04_crtc_reg *regp = &state->crtc_reg[nv_crtc->index];
- struct nouveau_pll_vals *pv = &regp->pllvals;
+ struct nvkm_pll_vals *pv = &regp->pllvals;
struct nvbios_pll pll_lim;
if (nvbios_pll_parse(bios, nv_crtc->index ? PLL_VPLL1 : PLL_VPLL0,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dac.c b/drivers/gpu/drm/nouveau/dispnv04/dac.c
index 2d8056cde996..d7b495a5f30c 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dac.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dac.c
@@ -66,7 +66,7 @@ int nv04_dac_output_offset(struct drm_encoder *encoder)
static int sample_load_twice(struct drm_device *dev, bool sense[2])
{
struct nvif_device *device = &nouveau_drm(dev)->device;
- struct nouveau_timer *ptimer = nvkm_timer(device);
+ struct nvkm_timer *ptimer = nvxx_timer(device);
int i;
for (i = 0; i < 2; i++) {
@@ -80,17 +80,17 @@ static int sample_load_twice(struct drm_device *dev, bool sense[2])
* use a 10ms timeout (guards against crtc being inactive, in
* which case blank state would never change)
*/
- if (!nouveau_timer_wait_eq(ptimer, 10000000,
- NV_PRMCIO_INP0__COLOR,
- 0x00000001, 0x00000000))
+ if (!nvkm_timer_wait_eq(ptimer, 10000000,
+ NV_PRMCIO_INP0__COLOR,
+ 0x00000001, 0x00000000))
return -EBUSY;
- if (!nouveau_timer_wait_eq(ptimer, 10000000,
- NV_PRMCIO_INP0__COLOR,
- 0x00000001, 0x00000001))
+ if (!nvkm_timer_wait_eq(ptimer, 10000000,
+ NV_PRMCIO_INP0__COLOR,
+ 0x00000001, 0x00000001))
return -EBUSY;
- if (!nouveau_timer_wait_eq(ptimer, 10000000,
- NV_PRMCIO_INP0__COLOR,
- 0x00000001, 0x00000000))
+ if (!nvkm_timer_wait_eq(ptimer, 10000000,
+ NV_PRMCIO_INP0__COLOR,
+ 0x00000001, 0x00000000))
return -EBUSY;
udelay(100);
@@ -232,7 +232,7 @@ uint32_t nv17_dac_sample_load(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &nouveau_drm(dev)->device;
- struct nouveau_gpio *gpio = nvkm_gpio(device);
+ struct nvkm_gpio *gpio = nvxx_gpio(device);
struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
uint32_t sample, testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t saved_powerctrl_2 = 0, saved_powerctrl_4 = 0, saved_routput,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/dfp.c b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
index 42a5435259f7..f6ca343fd34a 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/dfp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/dfp.c
@@ -623,9 +623,9 @@ static void nv04_tmds_slave_init(struct drm_encoder *encoder)
struct drm_device *dev = encoder->dev;
struct dcb_output *dcb = nouveau_encoder(encoder)->dcb;
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
- struct nouveau_i2c_port *port = i2c->find(i2c, 2);
- struct nouveau_i2c_board_info info[] = {
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
+ struct nvkm_i2c_port *port = i2c->find(i2c, 2);
+ struct nvkm_i2c_board_info info[] = {
{
{
.type = "sil164",
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.c b/drivers/gpu/drm/nouveau/dispnv04/disp.c
index 3d0afa1c6cff..f96237ef2a6b 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.c
@@ -32,28 +32,10 @@
#include "nouveau_connector.h"
int
-nv04_display_early_init(struct drm_device *dev)
-{
- /* ensure vblank interrupts are off, they can't be enabled until
- * drm_vblank has been initialised
- */
- NVWriteCRTC(dev, 0, NV_PCRTC_INTR_EN_0, 0);
- if (nv_two_heads(dev))
- NVWriteCRTC(dev, 1, NV_PCRTC_INTR_EN_0, 0);
-
- return 0;
-}
-
-void
-nv04_display_late_takedown(struct drm_device *dev)
-{
-}
-
-int
nv04_display_create(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
struct dcb_table *dcb = &drm->vbios.dcb;
struct drm_connector *connector, *ct;
struct drm_encoder *encoder;
diff --git a/drivers/gpu/drm/nouveau/dispnv04/disp.h b/drivers/gpu/drm/nouveau/dispnv04/disp.h
index 17b899d9aba3..c910c5d5c662 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/disp.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/disp.h
@@ -36,7 +36,7 @@ struct nv04_crtc_reg {
/* PRAMDAC regs */
uint32_t nv10_cursync;
- struct nouveau_pll_vals pllvals;
+ struct nvkm_pll_vals pllvals;
uint32_t ramdac_gen_ctrl;
uint32_t ramdac_630;
uint32_t ramdac_634;
@@ -90,8 +90,6 @@ nv04_display(struct drm_device *dev)
}
/* nv04_display.c */
-int nv04_display_early_init(struct drm_device *);
-void nv04_display_late_takedown(struct drm_device *);
int nv04_display_create(struct drm_device *);
void nv04_display_destroy(struct drm_device *);
int nv04_display_init(struct drm_device *);
@@ -172,7 +170,7 @@ nouveau_bios_run_init_table(struct drm_device *dev, u16 table,
struct dcb_output *outp, int crtc)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_bios *bios = nvkm_bios(&drm->device);
+ struct nvkm_bios *bios = nvxx_bios(&drm->device);
struct nvbios_init init = {
.subdev = nv_subdev(bios),
.bios = bios,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.c b/drivers/gpu/drm/nouveau/dispnv04/hw.c
index 3d4c19300768..42e07afc4c2b 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/hw.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/hw.c
@@ -130,7 +130,7 @@ NVBlankScreen(struct drm_device *dev, int head, bool blank)
static void
nouveau_hw_decode_pll(struct drm_device *dev, uint32_t reg1, uint32_t pll1,
- uint32_t pll2, struct nouveau_pll_vals *pllvals)
+ uint32_t pll2, struct nvkm_pll_vals *pllvals)
{
struct nouveau_drm *drm = nouveau_drm(dev);
@@ -162,11 +162,11 @@ nouveau_hw_decode_pll(struct drm_device *dev, uint32_t reg1, uint32_t pll1,
int
nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype,
- struct nouveau_pll_vals *pllvals)
+ struct nvkm_pll_vals *pllvals)
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->device;
- struct nouveau_bios *bios = nvkm_bios(device);
+ struct nvkm_bios *bios = nvxx_bios(device);
uint32_t reg1, pll1, pll2 = 0;
struct nvbios_pll pll_lim;
int ret;
@@ -202,7 +202,7 @@ nouveau_hw_get_pllvals(struct drm_device *dev, enum nvbios_pll_type plltype,
}
int
-nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pv)
+nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pv)
{
/* Avoid divide by zero if called at an inappropriate time */
if (!pv->M1 || !pv->M2)
@@ -214,7 +214,7 @@ nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pv)
int
nouveau_hw_get_clock(struct drm_device *dev, enum nvbios_pll_type plltype)
{
- struct nouveau_pll_vals pllvals;
+ struct nvkm_pll_vals pllvals;
int ret;
if (plltype == PLL_MEMORY &&
@@ -253,10 +253,10 @@ nouveau_hw_fix_bad_vpll(struct drm_device *dev, int head)
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->device;
- struct nouveau_clock *clk = nvkm_clock(device);
- struct nouveau_bios *bios = nvkm_bios(device);
+ struct nvkm_clk *clk = nvxx_clk(device);
+ struct nvkm_bios *bios = nvxx_bios(device);
struct nvbios_pll pll_lim;
- struct nouveau_pll_vals pv;
+ struct nvkm_pll_vals pv;
enum nvbios_pll_type pll = head ? PLL_VPLL1 : PLL_VPLL0;
if (nvbios_pll_parse(bios, pll, &pll_lim))
@@ -463,7 +463,7 @@ nv_load_state_ramdac(struct drm_device *dev, int head,
struct nv04_mode_state *state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_clock *clk = nvkm_clock(&drm->device);
+ struct nvkm_clk *clk = nvxx_clk(&drm->device);
struct nv04_crtc_reg *regp = &state->crtc_reg[head];
uint32_t pllreg = head ? NV_RAMDAC_VPLL2 : NV_PRAMDAC_VPLL_COEFF;
int i;
@@ -661,7 +661,7 @@ nv_load_state_ext(struct drm_device *dev, int head,
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->device;
- struct nouveau_timer *ptimer = nvkm_timer(device);
+ struct nvkm_timer *ptimer = nvxx_timer(device);
struct nv04_crtc_reg *regp = &state->crtc_reg[head];
uint32_t reg900;
int i;
@@ -741,8 +741,8 @@ nv_load_state_ext(struct drm_device *dev, int head,
if (drm->device.info.family < NV_DEVICE_INFO_V0_KELVIN) {
/* Not waiting for vertical retrace before modifying
CRE_53/CRE_54 causes lockups. */
- nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
- nouveau_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
+ nvkm_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x8);
+ nvkm_timer_wait_eq(ptimer, 650000000, NV_PRMCIO_INP0__COLOR, 0x8, 0x0);
}
wr_cio_state(dev, head, regp, NV_CIO_CRE_42);
diff --git a/drivers/gpu/drm/nouveau/dispnv04/hw.h b/drivers/gpu/drm/nouveau/dispnv04/hw.h
index 7f53c571f31f..6c796178bf0c 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/hw.h
+++ b/drivers/gpu/drm/nouveau/dispnv04/hw.h
@@ -42,8 +42,8 @@ uint8_t NVReadVgaGr(struct drm_device *, int head, uint8_t index);
void NVSetOwner(struct drm_device *, int owner);
void NVBlankScreen(struct drm_device *, int head, bool blank);
int nouveau_hw_get_pllvals(struct drm_device *, enum nvbios_pll_type plltype,
- struct nouveau_pll_vals *pllvals);
-int nouveau_hw_pllvals_to_clk(struct nouveau_pll_vals *pllvals);
+ struct nvkm_pll_vals *pllvals);
+int nouveau_hw_pllvals_to_clk(struct nvkm_pll_vals *pllvals);
int nouveau_hw_get_clock(struct drm_device *, enum nvbios_pll_type plltype);
void nouveau_hw_save_vga_fonts(struct drm_device *, bool save);
void nouveau_hw_save_state(struct drm_device *, int head,
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
index 8061d8d0ce79..d9664b37def1 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv04.c
@@ -35,7 +35,7 @@
#include <drm/i2c/ch7006.h>
-static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = {
+static struct nvkm_i2c_board_info nv04_tv_encoder_info[] = {
{
{
I2C_BOARD_INFO("ch7006", 0x75),
@@ -54,7 +54,7 @@ static struct nouveau_i2c_board_info nv04_tv_encoder_info[] = {
int nv04_tv_identify(struct drm_device *dev, int i2c_index)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
return i2c->identify(i2c, i2c_index, "TV encoder",
nv04_tv_encoder_info, NULL, NULL);
@@ -204,8 +204,8 @@ nv04_tv_create(struct drm_connector *connector, struct dcb_output *entry)
struct drm_encoder *encoder;
struct drm_device *dev = connector->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
- struct nouveau_i2c_port *port = i2c->find(i2c, entry->i2c_index);
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
+ struct nvkm_i2c_port *port = i2c->find(i2c, entry->i2c_index);
int type, ret;
/* Ensure that we can talk to this encoder */
diff --git a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
index 72d2ab04db47..731d74efc1e5 100644
--- a/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
+++ b/drivers/gpu/drm/nouveau/dispnv04/tvnv17.c
@@ -46,7 +46,7 @@ static uint32_t nv42_tv_sample_load(struct drm_encoder *encoder)
{
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_gpio *gpio = nvkm_gpio(&drm->device);
+ struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
uint32_t testval, regoffset = nv04_dac_output_offset(encoder);
uint32_t gpio0, gpio1, fp_htotal, fp_hsync_start, fp_hsync_end,
fp_control, test_ctrl, dacclk, ctv_14, ctv_1c, ctv_6c;
@@ -133,14 +133,14 @@ get_tv_detect_quirks(struct drm_device *dev, uint32_t *pin_mask)
struct nvif_device *device = &drm->device;
/* Zotac FX5200 */
- if (nv_device_match(nvkm_object(device), 0x0322, 0x19da, 0x1035) ||
- nv_device_match(nvkm_object(device), 0x0322, 0x19da, 0x2035)) {
+ if (nv_device_match(nvxx_object(device), 0x0322, 0x19da, 0x1035) ||
+ nv_device_match(nvxx_object(device), 0x0322, 0x19da, 0x2035)) {
*pin_mask = 0xc;
return false;
}
/* MSI nForce2 IGP */
- if (nv_device_match(nvkm_object(device), 0x01f0, 0x1462, 0x5710)) {
+ if (nv_device_match(nvxx_object(device), 0x01f0, 0x1462, 0x5710)) {
*pin_mask = 0xc;
return false;
}
@@ -370,7 +370,7 @@ static void nv17_tv_dpms(struct drm_encoder *encoder, int mode)
{
struct drm_device *dev = encoder->dev;
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_gpio *gpio = nvkm_gpio(&drm->device);
+ struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
struct nv17_tv_state *regs = &to_tv_enc(encoder)->state;
struct nv17_tv_norm_params *tv_norm = get_tv_norm(encoder);
diff --git a/drivers/gpu/drm/nouveau/include/nvif/class.h b/drivers/gpu/drm/nouveau/include/nvif/class.h
new file mode 100644
index 000000000000..5ad17fc36ae3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/class.h
@@ -0,0 +1,573 @@
+#ifndef __NVIF_CLASS_H__
+#define __NVIF_CLASS_H__
+
+/*******************************************************************************
+ * class identifiers
+ ******************************************************************************/
+
+/* the below match nvidia-assigned (either in hw, or sw) class numbers */
+#define NV_DEVICE 0x00000080
+
+#define NV_DMA_FROM_MEMORY 0x00000002
+#define NV_DMA_TO_MEMORY 0x00000003
+#define NV_DMA_IN_MEMORY 0x0000003d
+
+#define NV04_DISP 0x00000046
+
+#define NV03_CHANNEL_DMA 0x0000006b
+#define NV10_CHANNEL_DMA 0x0000006e
+#define NV17_CHANNEL_DMA 0x0000176e
+#define NV40_CHANNEL_DMA 0x0000406e
+#define NV50_CHANNEL_DMA 0x0000506e
+#define G82_CHANNEL_DMA 0x0000826e
+
+#define NV50_CHANNEL_GPFIFO 0x0000506f
+#define G82_CHANNEL_GPFIFO 0x0000826f
+#define FERMI_CHANNEL_GPFIFO 0x0000906f
+#define KEPLER_CHANNEL_GPFIFO_A 0x0000a06f
+
+#define NV50_DISP 0x00005070
+#define G82_DISP 0x00008270
+#define GT200_DISP 0x00008370
+#define GT214_DISP 0x00008570
+#define GT206_DISP 0x00008870
+#define GF110_DISP 0x00009070
+#define GK104_DISP 0x00009170
+#define GK110_DISP 0x00009270
+#define GM107_DISP 0x00009470
+#define GM204_DISP 0x00009570
+
+#define NV50_DISP_CURSOR 0x0000507a
+#define G82_DISP_CURSOR 0x0000827a
+#define GT214_DISP_CURSOR 0x0000857a
+#define GF110_DISP_CURSOR 0x0000907a
+#define GK104_DISP_CURSOR 0x0000917a
+
+#define NV50_DISP_OVERLAY 0x0000507b
+#define G82_DISP_OVERLAY 0x0000827b
+#define GT214_DISP_OVERLAY 0x0000857b
+#define GF110_DISP_OVERLAY 0x0000907b
+#define GK104_DISP_OVERLAY 0x0000917b
+
+#define NV50_DISP_BASE_CHANNEL_DMA 0x0000507c
+#define G82_DISP_BASE_CHANNEL_DMA 0x0000827c
+#define GT200_DISP_BASE_CHANNEL_DMA 0x0000837c
+#define GT214_DISP_BASE_CHANNEL_DMA 0x0000857c
+#define GF110_DISP_BASE_CHANNEL_DMA 0x0000907c
+#define GK104_DISP_BASE_CHANNEL_DMA 0x0000917c
+#define GK110_DISP_BASE_CHANNEL_DMA 0x0000927c
+
+#define NV50_DISP_CORE_CHANNEL_DMA 0x0000507d
+#define G82_DISP_CORE_CHANNEL_DMA 0x0000827d
+#define GT200_DISP_CORE_CHANNEL_DMA 0x0000837d
+#define GT214_DISP_CORE_CHANNEL_DMA 0x0000857d
+#define GT206_DISP_CORE_CHANNEL_DMA 0x0000887d
+#define GF110_DISP_CORE_CHANNEL_DMA 0x0000907d
+#define GK104_DISP_CORE_CHANNEL_DMA 0x0000917d
+#define GK110_DISP_CORE_CHANNEL_DMA 0x0000927d
+#define GM107_DISP_CORE_CHANNEL_DMA 0x0000947d
+#define GM204_DISP_CORE_CHANNEL_DMA 0x0000957d
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA 0x0000507e
+#define G82_DISP_OVERLAY_CHANNEL_DMA 0x0000827e
+#define GT200_DISP_OVERLAY_CHANNEL_DMA 0x0000837e
+#define GT214_DISP_OVERLAY_CHANNEL_DMA 0x0000857e
+#define GF110_DISP_OVERLAY_CONTROL_DMA 0x0000907e
+#define GK104_DISP_OVERLAY_CONTROL_DMA 0x0000917e
+
+#define FERMI_A 0x00009097
+#define FERMI_B 0x00009197
+#define FERMI_C 0x00009297
+
+#define KEPLER_A 0x0000a097
+#define KEPLER_B 0x0000a197
+#define KEPLER_C 0x0000a297
+
+#define MAXWELL_A 0x0000b097
+
+#define FERMI_COMPUTE_A 0x000090c0
+#define FERMI_COMPUTE_B 0x000091c0
+
+#define KEPLER_COMPUTE_A 0x0000a0c0
+#define KEPLER_COMPUTE_B 0x0000a1c0
+
+#define MAXWELL_COMPUTE_A 0x0000b0c0
+
+
+/*******************************************************************************
+ * client
+ ******************************************************************************/
+
+#define NV_CLIENT_DEVLIST 0x00
+
+struct nv_client_devlist_v0 {
+ __u8 version;
+ __u8 count;
+ __u8 pad02[6];
+ __u64 device[];
+};
+
+
+/*******************************************************************************
+ * device
+ ******************************************************************************/
+
+struct nv_device_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u64 device; /* device identifier, ~0 for client default */
+#define NV_DEVICE_V0_DISABLE_IDENTIFY 0x0000000000000001ULL
+#define NV_DEVICE_V0_DISABLE_MMIO 0x0000000000000002ULL
+#define NV_DEVICE_V0_DISABLE_VBIOS 0x0000000000000004ULL
+#define NV_DEVICE_V0_DISABLE_CORE 0x0000000000000008ULL
+#define NV_DEVICE_V0_DISABLE_DISP 0x0000000000010000ULL
+#define NV_DEVICE_V0_DISABLE_FIFO 0x0000000000020000ULL
+#define NV_DEVICE_V0_DISABLE_GR 0x0000000100000000ULL
+#define NV_DEVICE_V0_DISABLE_MPEG 0x0000000200000000ULL
+#define NV_DEVICE_V0_DISABLE_ME 0x0000000400000000ULL
+#define NV_DEVICE_V0_DISABLE_VP 0x0000000800000000ULL
+#define NV_DEVICE_V0_DISABLE_CIPHER 0x0000001000000000ULL
+#define NV_DEVICE_V0_DISABLE_BSP 0x0000002000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSPPP 0x0000004000000000ULL
+#define NV_DEVICE_V0_DISABLE_CE0 0x0000008000000000ULL
+#define NV_DEVICE_V0_DISABLE_CE1 0x0000010000000000ULL
+#define NV_DEVICE_V0_DISABLE_VIC 0x0000020000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSENC 0x0000040000000000ULL
+#define NV_DEVICE_V0_DISABLE_CE2 0x0000080000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSVLD 0x0000100000000000ULL
+#define NV_DEVICE_V0_DISABLE_SEC 0x0000200000000000ULL
+#define NV_DEVICE_V0_DISABLE_MSPDEC 0x0000400000000000ULL
+ __u64 disable; /* disable particular subsystems */
+ __u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */
+};
+
+#define NV_DEVICE_V0_INFO 0x00
+
+struct nv_device_info_v0 {
+ __u8 version;
+#define NV_DEVICE_INFO_V0_IGP 0x00
+#define NV_DEVICE_INFO_V0_PCI 0x01
+#define NV_DEVICE_INFO_V0_AGP 0x02
+#define NV_DEVICE_INFO_V0_PCIE 0x03
+#define NV_DEVICE_INFO_V0_SOC 0x04
+ __u8 platform;
+ __u16 chipset; /* from NV_PMC_BOOT_0 */
+ __u8 revision; /* from NV_PMC_BOOT_0 */
+#define NV_DEVICE_INFO_V0_TNT 0x01
+#define NV_DEVICE_INFO_V0_CELSIUS 0x02
+#define NV_DEVICE_INFO_V0_KELVIN 0x03
+#define NV_DEVICE_INFO_V0_RANKINE 0x04
+#define NV_DEVICE_INFO_V0_CURIE 0x05
+#define NV_DEVICE_INFO_V0_TESLA 0x06
+#define NV_DEVICE_INFO_V0_FERMI 0x07
+#define NV_DEVICE_INFO_V0_KEPLER 0x08
+#define NV_DEVICE_INFO_V0_MAXWELL 0x09
+ __u8 family;
+ __u8 pad06[2];
+ __u64 ram_size;
+ __u64 ram_user;
+};
+
+
+/*******************************************************************************
+ * context dma
+ ******************************************************************************/
+
+struct nv_dma_v0 {
+ __u8 version;
+#define NV_DMA_V0_TARGET_VM 0x00
+#define NV_DMA_V0_TARGET_VRAM 0x01
+#define NV_DMA_V0_TARGET_PCI 0x02
+#define NV_DMA_V0_TARGET_PCI_US 0x03
+#define NV_DMA_V0_TARGET_AGP 0x04
+ __u8 target;
+#define NV_DMA_V0_ACCESS_VM 0x00
+#define NV_DMA_V0_ACCESS_RD 0x01
+#define NV_DMA_V0_ACCESS_WR 0x02
+#define NV_DMA_V0_ACCESS_RDWR (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
+ __u8 access;
+ __u8 pad03[5];
+ __u64 start;
+ __u64 limit;
+ /* ... chipset-specific class data */
+};
+
+struct nv50_dma_v0 {
+ __u8 version;
+#define NV50_DMA_V0_PRIV_VM 0x00
+#define NV50_DMA_V0_PRIV_US 0x01
+#define NV50_DMA_V0_PRIV__S 0x02
+ __u8 priv;
+#define NV50_DMA_V0_PART_VM 0x00
+#define NV50_DMA_V0_PART_256 0x01
+#define NV50_DMA_V0_PART_1KB 0x02
+ __u8 part;
+#define NV50_DMA_V0_COMP_NONE 0x00
+#define NV50_DMA_V0_COMP_1 0x01
+#define NV50_DMA_V0_COMP_2 0x02
+#define NV50_DMA_V0_COMP_VM 0x03
+ __u8 comp;
+#define NV50_DMA_V0_KIND_PITCH 0x00
+#define NV50_DMA_V0_KIND_VM 0x7f
+ __u8 kind;
+ __u8 pad05[3];
+};
+
+struct gf100_dma_v0 {
+ __u8 version;
+#define GF100_DMA_V0_PRIV_VM 0x00
+#define GF100_DMA_V0_PRIV_US 0x01
+#define GF100_DMA_V0_PRIV__S 0x02
+ __u8 priv;
+#define GF100_DMA_V0_KIND_PITCH 0x00
+#define GF100_DMA_V0_KIND_VM 0xff
+ __u8 kind;
+ __u8 pad03[5];
+};
+
+struct gf110_dma_v0 {
+ __u8 version;
+#define GF110_DMA_V0_PAGE_LP 0x00
+#define GF110_DMA_V0_PAGE_SP 0x01
+ __u8 page;
+#define GF110_DMA_V0_KIND_PITCH 0x00
+#define GF110_DMA_V0_KIND_VM 0xff
+ __u8 kind;
+ __u8 pad03[5];
+};
+
+
+/*******************************************************************************
+ * perfmon
+ ******************************************************************************/
+
+struct nvif_perfctr_v0 {
+ __u8 version;
+ __u8 pad01[1];
+ __u16 logic_op;
+ __u8 pad04[4];
+ char name[4][64];
+};
+
+#define NVIF_PERFCTR_V0_QUERY 0x00
+#define NVIF_PERFCTR_V0_SAMPLE 0x01
+#define NVIF_PERFCTR_V0_READ 0x02
+
+struct nvif_perfctr_query_v0 {
+ __u8 version;
+ __u8 pad01[3];
+ __u32 iter;
+ char name[64];
+};
+
+struct nvif_perfctr_sample {
+};
+
+struct nvif_perfctr_read_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u32 ctr;
+ __u32 clk;
+};
+
+
+/*******************************************************************************
+ * device control
+ ******************************************************************************/
+
+#define NVIF_CONTROL_PSTATE_INFO 0x00
+#define NVIF_CONTROL_PSTATE_ATTR 0x01
+#define NVIF_CONTROL_PSTATE_USER 0x02
+
+struct nvif_control_pstate_info_v0 {
+ __u8 version;
+ __u8 count; /* out: number of power states */
+#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE (-1)
+#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON (-2)
+ __s8 ustate_ac; /* out: target pstate index */
+ __s8 ustate_dc; /* out: target pstate index */
+ __s8 pwrsrc; /* out: current power source */
+#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN (-1)
+#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON (-2)
+ __s8 pstate; /* out: current pstate index */
+ __u8 pad06[2];
+};
+
+struct nvif_control_pstate_attr_v0 {
+ __u8 version;
+#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT (-1)
+ __s8 state; /* in: index of pstate to query
+ * out: pstate identifier
+ */
+ __u8 index; /* in: index of attribute to query
+ * out: index of next attribute, or 0 if no more
+ */
+ __u8 pad03[5];
+ __u32 min;
+ __u32 max;
+ char name[32];
+ char unit[16];
+};
+
+struct nvif_control_pstate_user_v0 {
+ __u8 version;
+#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN (-1)
+#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON (-2)
+ __s8 ustate; /* in: pstate identifier */
+ __s8 pwrsrc; /* in: target power source */
+ __u8 pad03[5];
+};
+
+
+/*******************************************************************************
+ * DMA FIFO channels
+ ******************************************************************************/
+
+struct nv03_channel_dma_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad02[2];
+ __u32 pushbuf;
+ __u64 offset;
+};
+
+#define G82_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+
+/*******************************************************************************
+ * GPFIFO channels
+ ******************************************************************************/
+
+struct nv50_channel_gpfifo_v0 {
+ __u8 version;
+ __u8 chid;
+ __u8 pad01[6];
+ __u32 pushbuf;
+ __u32 ilength;
+ __u64 ioffset;
+};
+
+struct kepler_channel_gpfifo_a_v0 {
+ __u8 version;
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR 0x01
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPDEC 0x02
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSPPP 0x04
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_MSVLD 0x08
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0 0x10
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1 0x20
+#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40
+ __u8 engine;
+ __u16 chid;
+ __u8 pad04[4];
+ __u32 pushbuf;
+ __u32 ilength;
+ __u64 ioffset;
+};
+
+/*******************************************************************************
+ * legacy display
+ ******************************************************************************/
+
+#define NV04_DISP_NTFY_VBLANK 0x00
+#define NV04_DISP_NTFY_CONN 0x01
+
+struct nv04_disp_mthd_v0 {
+ __u8 version;
+#define NV04_DISP_SCANOUTPOS 0x00
+ __u8 method;
+ __u8 head;
+ __u8 pad03[5];
+};
+
+struct nv04_disp_scanoutpos_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __s64 time[2];
+ __u16 vblanks;
+ __u16 vblanke;
+ __u16 vtotal;
+ __u16 vline;
+ __u16 hblanks;
+ __u16 hblanke;
+ __u16 htotal;
+ __u16 hline;
+};
+
+/*******************************************************************************
+ * display
+ ******************************************************************************/
+
+#define NV50_DISP_MTHD 0x00
+
+struct nv50_disp_mthd_v0 {
+ __u8 version;
+#define NV50_DISP_SCANOUTPOS 0x00
+ __u8 method;
+ __u8 head;
+ __u8 pad03[5];
+};
+
+struct nv50_disp_mthd_v1 {
+ __u8 version;
+#define NV50_DISP_MTHD_V1_DAC_PWR 0x10
+#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
+#define NV50_DISP_MTHD_V1_SOR_PWR 0x20
+#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
+#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
+#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
+#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24
+#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
+ __u8 method;
+ __u16 hasht;
+ __u16 hashm;
+ __u8 pad06[2];
+};
+
+struct nv50_disp_dac_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 data;
+ __u8 vsync;
+ __u8 hsync;
+ __u8 pad05[3];
+};
+
+struct nv50_disp_dac_load_v0 {
+ __u8 version;
+ __u8 load;
+ __u8 pad02[2];
+ __u32 data;
+};
+
+struct nv50_disp_sor_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 pad02[6];
+};
+
+struct nv50_disp_sor_hda_eld_v0 {
+ __u8 version;
+ __u8 pad01[7];
+ __u8 data[];
+};
+
+struct nv50_disp_sor_hdmi_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 max_ac_packet;
+ __u8 rekey;
+ __u8 pad04[4];
+};
+
+struct nv50_disp_sor_lvds_script_v0 {
+ __u8 version;
+ __u8 pad01[1];
+ __u16 script;
+ __u8 pad04[4];
+};
+
+struct nv50_disp_sor_dp_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 pad02[6];
+};
+
+struct nv50_disp_pior_pwr_v0 {
+ __u8 version;
+ __u8 state;
+ __u8 type;
+ __u8 pad03[5];
+};
+
+/* core */
+struct nv50_disp_core_channel_dma_v0 {
+ __u8 version;
+ __u8 pad01[3];
+ __u32 pushbuf;
+};
+
+#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+
+/* cursor immediate */
+struct nv50_disp_cursor_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+};
+
+#define NV50_DISP_CURSOR_V0_NTFY_UEVENT 0x00
+
+/* base */
+struct nv50_disp_base_channel_dma_v0 {
+ __u8 version;
+ __u8 pad01[2];
+ __u8 head;
+ __u32 pushbuf;
+};
+
+#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+
+/* overlay */
+struct nv50_disp_overlay_channel_dma_v0 {
+ __u8 version;
+ __u8 pad01[2];
+ __u8 head;
+ __u32 pushbuf;
+};
+
+#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
+
+/* overlay immediate */
+struct nv50_disp_overlay_v0 {
+ __u8 version;
+ __u8 head;
+ __u8 pad02[6];
+};
+
+#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00
+
+/*******************************************************************************
+ * fermi
+ ******************************************************************************/
+
+#define FERMI_A_ZBC_COLOR 0x00
+#define FERMI_A_ZBC_DEPTH 0x01
+
+struct fermi_a_zbc_color_v0 {
+ __u8 version;
+#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO 0x01
+#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE 0x02
+#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32 0x04
+#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16 0x08
+#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16 0x0c
+#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16 0x10
+#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16 0x14
+#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16 0x16
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8 0x18
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8 0x1c
+#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10 0x20
+#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10 0x24
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8 0x28
+#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8 0x2c
+#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8 0x30
+#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8 0x34
+#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8 0x38
+#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10 0x3c
+#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11 0x40
+ __u8 format;
+ __u8 index;
+ __u8 pad03[5];
+ __u32 ds[4];
+ __u32 l2[4];
+};
+
+struct fermi_a_zbc_depth_v0 {
+ __u8 version;
+#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32 0x01
+ __u8 format;
+ __u8 index;
+ __u8 pad03[5];
+ __u32 ds;
+ __u32 l2;
+};
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/client.h b/drivers/gpu/drm/nouveau/include/nvif/client.h
new file mode 100644
index 000000000000..eca648ef0f7a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/client.h
@@ -0,0 +1,39 @@
+#ifndef __NVIF_CLIENT_H__
+#define __NVIF_CLIENT_H__
+
+#include <nvif/object.h>
+
+struct nvif_client {
+ struct nvif_object base;
+ struct nvif_object *object; /*XXX: hack for nvif_object() */
+ const struct nvif_driver *driver;
+ bool super;
+};
+
+static inline struct nvif_client *
+nvif_client(struct nvif_object *object)
+{
+ while (object && object->parent != object)
+ object = object->parent;
+ return (void *)object;
+}
+
+int nvif_client_init(void (*dtor)(struct nvif_client *), const char *,
+ const char *, u64, const char *, const char *,
+ struct nvif_client *);
+void nvif_client_fini(struct nvif_client *);
+int nvif_client_new(const char *, const char *, u64, const char *,
+ const char *, struct nvif_client **);
+void nvif_client_ref(struct nvif_client *, struct nvif_client **);
+int nvif_client_ioctl(struct nvif_client *, void *, u32);
+int nvif_client_suspend(struct nvif_client *);
+int nvif_client_resume(struct nvif_client *);
+
+/*XXX*/
+#include <core/client.h>
+#define nvxx_client(a) ({ \
+ struct nvif_client *_client = nvif_client(nvif_object(a)); \
+ nvkm_client(_client->base.priv); \
+})
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvif/device.h b/drivers/gpu/drm/nouveau/include/nvif/device.h
new file mode 100644
index 000000000000..88553a741ab7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/device.h
@@ -0,0 +1,61 @@
+#ifndef __NVIF_DEVICE_H__
+#define __NVIF_DEVICE_H__
+
+#include <nvif/object.h>
+#include <nvif/class.h>
+
+struct nvif_device {
+ struct nvif_object base;
+ struct nvif_object *object; /*XXX: hack for nvif_object() */
+ struct nv_device_info_v0 info;
+};
+
+static inline struct nvif_device *
+nvif_device(struct nvif_object *object)
+{
+ while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ )
+ object = object->parent;
+ return (void *)object;
+}
+
+int nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *),
+ u32 handle, u32 oclass, void *, u32,
+ struct nvif_device *);
+void nvif_device_fini(struct nvif_device *);
+int nvif_device_new(struct nvif_object *, u32 handle, u32 oclass,
+ void *, u32, struct nvif_device **);
+void nvif_device_ref(struct nvif_device *, struct nvif_device **);
+
+/*XXX*/
+#include <subdev/bios.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/gpio.h>
+#include <subdev/clk.h>
+#include <subdev/i2c.h>
+#include <subdev/timer.h>
+#include <subdev/therm.h>
+
+#define nvxx_device(a) nv_device(nvxx_object((a)))
+#define nvxx_bios(a) nvkm_bios(nvxx_device(a))
+#define nvxx_fb(a) nvkm_fb(nvxx_device(a))
+#define nvxx_mmu(a) nvkm_mmu(nvxx_device(a))
+#define nvxx_bar(a) nvkm_bar(nvxx_device(a))
+#define nvxx_gpio(a) nvkm_gpio(nvxx_device(a))
+#define nvxx_clk(a) nvkm_clk(nvxx_device(a))
+#define nvxx_i2c(a) nvkm_i2c(nvxx_device(a))
+#define nvxx_timer(a) nvkm_timer(nvxx_device(a))
+#define nvxx_wait(a,b,c,d) nv_wait(nvxx_timer(a), (b), (c), (d))
+#define nvxx_wait_cb(a,b,c) nv_wait_cb(nvxx_timer(a), (b), (c))
+#define nvxx_therm(a) nvkm_therm(nvxx_device(a))
+
+#include <core/device.h>
+#include <engine/fifo.h>
+#include <engine/gr.h>
+#include <engine/sw.h>
+
+#define nvxx_fifo(a) nvkm_fifo(nvxx_device(a))
+#define nvxx_fifo_chan(a) ((struct nvkm_fifo_chan *)nvxx_object(a))
+#define nvxx_gr(a) ((struct nvkm_gr *)nvkm_engine(nvxx_object(a), NVDEV_ENGINE_GR))
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/driver.h b/drivers/gpu/drm/nouveau/include/nvif/driver.h
index 8bd39e69229c..8bd39e69229c 100644
--- a/drivers/gpu/drm/nouveau/nvif/driver.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/driver.h
diff --git a/drivers/gpu/drm/nouveau/nvif/event.h b/drivers/gpu/drm/nouveau/include/nvif/event.h
index 21764499b4be..21764499b4be 100644
--- a/drivers/gpu/drm/nouveau/nvif/event.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/event.h
diff --git a/drivers/gpu/drm/nouveau/nvif/ioctl.h b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
index 4cd8e323b23d..4cd8e323b23d 100644
--- a/drivers/gpu/drm/nouveau/nvif/ioctl.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/ioctl.h
diff --git a/drivers/gpu/drm/nouveau/nvif/list.h b/drivers/gpu/drm/nouveau/include/nvif/list.h
index 8af5d144ecb0..8af5d144ecb0 100644
--- a/drivers/gpu/drm/nouveau/nvif/list.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/list.h
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.h b/drivers/gpu/drm/nouveau/include/nvif/notify.h
index 9ebfa3b45e76..9ebfa3b45e76 100644
--- a/drivers/gpu/drm/nouveau/nvif/notify.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/notify.h
diff --git a/drivers/gpu/drm/nouveau/include/nvif/object.h b/drivers/gpu/drm/nouveau/include/nvif/object.h
new file mode 100644
index 000000000000..04c874707b96
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvif/object.h
@@ -0,0 +1,75 @@
+#ifndef __NVIF_OBJECT_H__
+#define __NVIF_OBJECT_H__
+
+#include <nvif/os.h>
+
+struct nvif_object {
+ struct nvif_object *parent;
+ struct nvif_object *object; /*XXX: hack for nvif_object() */
+ struct kref refcount;
+ u32 handle;
+ u32 oclass;
+ void *data;
+ u32 size;
+ void *priv; /*XXX: hack */
+ void (*dtor)(struct nvif_object *);
+ struct {
+ void __iomem *ptr;
+ u32 size;
+ } map;
+};
+
+int nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *),
+ u32 handle, u32 oclass, void *, u32,
+ struct nvif_object *);
+void nvif_object_fini(struct nvif_object *);
+int nvif_object_new(struct nvif_object *, u32 handle, u32 oclass,
+ void *, u32, struct nvif_object **);
+void nvif_object_ref(struct nvif_object *, struct nvif_object **);
+int nvif_object_ioctl(struct nvif_object *, void *, u32, void **);
+int nvif_object_sclass(struct nvif_object *, u32 *, int);
+u32 nvif_object_rd(struct nvif_object *, int, u64);
+void nvif_object_wr(struct nvif_object *, int, u64, u32);
+int nvif_object_mthd(struct nvif_object *, u32, void *, u32);
+int nvif_object_map(struct nvif_object *);
+void nvif_object_unmap(struct nvif_object *);
+
+#define nvif_object(a) (a)->object
+
+#define ioread8_native ioread8
+#define iowrite8_native iowrite8
+#define nvif_rd(a,b,c) ({ \
+ struct nvif_object *_object = nvif_object(a); \
+ u32 _data; \
+ if (likely(_object->map.ptr)) \
+ _data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c)); \
+ else \
+ _data = nvif_object_rd(_object, (b) / 8, (c)); \
+ _data; \
+})
+#define nvif_wr(a,b,c,d) ({ \
+ struct nvif_object *_object = nvif_object(a); \
+ if (likely(_object->map.ptr)) \
+ iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c)); \
+ else \
+ nvif_object_wr(_object, (b) / 8, (c), (d)); \
+})
+#define nvif_rd08(a,b) ({ u8 _v = nvif_rd((a), 8, (b)); _v; })
+#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; })
+#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; })
+#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c))
+#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c))
+#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c))
+#define nvif_mask(a,b,c,d) ({ \
+ u32 _v = nvif_rd32(nvif_object(a), (b)); \
+ nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d)); \
+ _v; \
+})
+
+#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d))
+
+/*XXX*/
+#include <core/object.h>
+#define nvxx_object(a) ((struct nvkm_object *)nvif_object(a)->priv)
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/os.h b/drivers/gpu/drm/nouveau/include/nvif/os.h
index bdd05ee7ec72..bdd05ee7ec72 100644
--- a/drivers/gpu/drm/nouveau/core/os.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/os.h
diff --git a/drivers/gpu/drm/nouveau/nvif/unpack.h b/drivers/gpu/drm/nouveau/include/nvif/unpack.h
index 5933188b4a77..5933188b4a77 100644
--- a/drivers/gpu/drm/nouveau/nvif/unpack.h
+++ b/drivers/gpu/drm/nouveau/include/nvif/unpack.h
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/client.h b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
new file mode 100644
index 000000000000..a35b38244502
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/client.h
@@ -0,0 +1,55 @@
+#ifndef __NVKM_CLIENT_H__
+#define __NVKM_CLIENT_H__
+#include <core/namedb.h>
+
+struct nvkm_client {
+ struct nvkm_namedb namedb;
+ struct nvkm_handle *root;
+ struct nvkm_object *device;
+ char name[32];
+ u32 debug;
+ struct nvkm_vm *vm;
+ bool super;
+ void *data;
+
+ int (*ntfy)(const void *, u32, const void *, u32);
+ struct nvkm_client_notify *notify[16];
+};
+
+static inline struct nvkm_client *
+nv_client(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_CLIENT_CLASS)))
+ nv_assert("BAD CAST -> NvClient, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+static inline struct nvkm_client *
+nvkm_client(void *obj)
+{
+ struct nvkm_object *client = nv_object(obj);
+ while (client && !(nv_iclass(client, NV_CLIENT_CLASS)))
+ client = client->parent;
+ return (void *)client;
+}
+
+#define nvkm_client_create(n,c,oc,od,d) \
+ nvkm_client_create_((n), (c), (oc), (od), sizeof(**d), (void **)d)
+
+int nvkm_client_create_(const char *name, u64 device, const char *cfg,
+ const char *dbg, int, void **);
+#define nvkm_client_destroy(p) \
+ nvkm_namedb_destroy(&(p)->base)
+
+int nvkm_client_init(struct nvkm_client *);
+int nvkm_client_fini(struct nvkm_client *, bool suspend);
+const char *nvkm_client_name(void *obj);
+
+int nvkm_client_notify_new(struct nvkm_object *, struct nvkm_event *,
+ void *data, u32 size);
+int nvkm_client_notify_del(struct nvkm_client *, int index);
+int nvkm_client_notify_get(struct nvkm_client *, int index);
+int nvkm_client_notify_put(struct nvkm_client *, int index);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h b/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h
new file mode 100644
index 000000000000..d07cb860b56c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/debug.h
@@ -0,0 +1,18 @@
+#ifndef __NVKM_DEBUG_H__
+#define __NVKM_DEBUG_H__
+extern int nv_info_debug_level;
+
+#define NV_DBG_FATAL 0
+#define NV_DBG_ERROR 1
+#define NV_DBG_WARN 2
+#define NV_DBG_INFO nv_info_debug_level
+#define NV_DBG_DEBUG 4
+#define NV_DBG_TRACE 5
+#define NV_DBG_PARANOIA 6
+#define NV_DBG_SPAM 7
+
+#define NV_DBG_INFO_NORMAL 3
+#define NV_DBG_INFO_SILENT NV_DBG_DEBUG
+
+#define nv_debug_level(a) nv_info_debug_level = NV_DBG_INFO_##a
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/device.h b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
new file mode 100644
index 000000000000..333db33a162c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/device.h
@@ -0,0 +1,101 @@
+#ifndef __NVKM_DEVICE_H__
+#define __NVKM_DEVICE_H__
+#include <core/engine.h>
+#include <core/event.h>
+
+struct nvkm_device {
+ struct nvkm_engine engine;
+ struct list_head head;
+
+ struct pci_dev *pdev;
+ struct platform_device *platformdev;
+ u64 handle;
+
+ struct nvkm_event event;
+
+ const char *cfgopt;
+ const char *dbgopt;
+ const char *name;
+ const char *cname;
+ u64 disable_mask;
+
+ enum {
+ NV_04 = 0x04,
+ NV_10 = 0x10,
+ NV_11 = 0x11,
+ NV_20 = 0x20,
+ NV_30 = 0x30,
+ NV_40 = 0x40,
+ NV_50 = 0x50,
+ NV_C0 = 0xc0,
+ NV_E0 = 0xe0,
+ GM100 = 0x110,
+ } card_type;
+ u32 chipset;
+ u8 chiprev;
+ u32 crystal;
+
+ struct nvkm_oclass *oclass[NVDEV_SUBDEV_NR];
+ struct nvkm_object *subdev[NVDEV_SUBDEV_NR];
+
+ struct {
+ struct notifier_block nb;
+ } acpi;
+};
+
+struct nvkm_device *nvkm_device_find(u64 name);
+int nvkm_device_list(u64 *name, int size);
+
+struct nvkm_device *nv_device(void *obj);
+
+static inline bool
+nv_device_match(struct nvkm_object *object, u16 dev, u16 ven, u16 sub)
+{
+ struct nvkm_device *device = nv_device(object);
+ return device->pdev->device == dev &&
+ device->pdev->subsystem_vendor == ven &&
+ device->pdev->subsystem_device == sub;
+}
+
+static inline bool
+nv_device_is_pci(struct nvkm_device *device)
+{
+ return device->pdev != NULL;
+}
+
+static inline bool
+nv_device_is_cpu_coherent(struct nvkm_device *device)
+{
+ return (!IS_ENABLED(CONFIG_ARM) && nv_device_is_pci(device));
+}
+
+static inline struct device *
+nv_device_base(struct nvkm_device *device)
+{
+ return nv_device_is_pci(device) ? &device->pdev->dev :
+ &device->platformdev->dev;
+}
+
+resource_size_t
+nv_device_resource_start(struct nvkm_device *device, unsigned int bar);
+
+resource_size_t
+nv_device_resource_len(struct nvkm_device *device, unsigned int bar);
+
+int
+nv_device_get_irq(struct nvkm_device *device, bool stall);
+
+struct platform_device;
+
+enum nv_bus_type {
+ NVKM_BUS_PCI,
+ NVKM_BUS_PLATFORM,
+};
+
+#define nvkm_device_create(p,t,n,s,c,d,u) \
+ nvkm_device_create_((void *)(p), (t), (n), (s), (c), (d), \
+ sizeof(**u), (void **)u)
+int nvkm_device_create_(void *, enum nv_bus_type type, u64 name,
+ const char *sname, const char *cfg, const char *dbg,
+ int, void **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h
new file mode 100644
index 000000000000..60c5888b5df3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/devidx.h
@@ -0,0 +1,62 @@
+#ifndef __NVKM_DEVIDX_H__
+#define __NVKM_DEVIDX_H__
+enum nvkm_devidx {
+ NVDEV_ENGINE_DEVICE,
+ NVDEV_SUBDEV_VBIOS,
+
+ /* All subdevs from DEVINIT to DEVINIT_LAST will be created before
+ * *any* of them are initialised. This subdev category is used
+ * for any subdevs that the VBIOS init table parsing may call out
+ * to during POST.
+ */
+ NVDEV_SUBDEV_DEVINIT,
+ NVDEV_SUBDEV_IBUS,
+ NVDEV_SUBDEV_GPIO,
+ NVDEV_SUBDEV_I2C,
+ NVDEV_SUBDEV_DEVINIT_LAST = NVDEV_SUBDEV_I2C,
+
+ /* This grouping of subdevs are initialised right after they've
+ * been created, and are allowed to assume any subdevs in the
+ * list above them exist and have been initialised.
+ */
+ NVDEV_SUBDEV_FUSE,
+ NVDEV_SUBDEV_MXM,
+ NVDEV_SUBDEV_MC,
+ NVDEV_SUBDEV_BUS,
+ NVDEV_SUBDEV_TIMER,
+ NVDEV_SUBDEV_FB,
+ NVDEV_SUBDEV_LTC,
+ NVDEV_SUBDEV_INSTMEM,
+ NVDEV_SUBDEV_MMU,
+ NVDEV_SUBDEV_BAR,
+ NVDEV_SUBDEV_PMU,
+ NVDEV_SUBDEV_VOLT,
+ NVDEV_SUBDEV_THERM,
+ NVDEV_SUBDEV_CLK,
+
+ NVDEV_ENGINE_FIRST,
+ NVDEV_ENGINE_DMAOBJ = NVDEV_ENGINE_FIRST,
+ NVDEV_ENGINE_IFB,
+ NVDEV_ENGINE_FIFO,
+ NVDEV_ENGINE_SW,
+ NVDEV_ENGINE_GR,
+ NVDEV_ENGINE_MPEG,
+ NVDEV_ENGINE_ME,
+ NVDEV_ENGINE_VP,
+ NVDEV_ENGINE_CIPHER,
+ NVDEV_ENGINE_BSP,
+ NVDEV_ENGINE_MSPPP,
+ NVDEV_ENGINE_CE0,
+ NVDEV_ENGINE_CE1,
+ NVDEV_ENGINE_CE2,
+ NVDEV_ENGINE_VIC,
+ NVDEV_ENGINE_MSENC,
+ NVDEV_ENGINE_DISP,
+ NVDEV_ENGINE_PM,
+ NVDEV_ENGINE_MSVLD,
+ NVDEV_ENGINE_SEC,
+ NVDEV_ENGINE_MSPDEC,
+
+ NVDEV_SUBDEV_NR,
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h
new file mode 100644
index 000000000000..1bf2e8eb4268
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engctx.h
@@ -0,0 +1,51 @@
+#ifndef __NVKM_ENGCTX_H__
+#define __NVKM_ENGCTX_H__
+#include <core/gpuobj.h>
+
+#include <subdev/mmu.h>
+
+#define NV_ENGCTX_(eng,var) (NV_ENGCTX_CLASS | ((var) << 8) | (eng))
+#define NV_ENGCTX(name,var) NV_ENGCTX_(NVDEV_ENGINE_##name, (var))
+
+struct nvkm_engctx {
+ struct nvkm_gpuobj gpuobj;
+ struct nvkm_vma vma;
+ struct list_head head;
+ unsigned long save;
+ u64 addr;
+};
+
+static inline struct nvkm_engctx *
+nv_engctx(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_ENGCTX_CLASS)))
+ nv_assert("BAD CAST -> NvEngCtx, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nvkm_engctx_create(p,e,c,g,s,a,f,d) \
+ nvkm_engctx_create_((p), (e), (c), (g), (s), (a), (f), \
+ sizeof(**d), (void **)d)
+
+int nvkm_engctx_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, struct nvkm_object *,
+ u32 size, u32 align, u32 flags,
+ int length, void **data);
+void nvkm_engctx_destroy(struct nvkm_engctx *);
+int nvkm_engctx_init(struct nvkm_engctx *);
+int nvkm_engctx_fini(struct nvkm_engctx *, bool suspend);
+
+int _nvkm_engctx_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void _nvkm_engctx_dtor(struct nvkm_object *);
+int _nvkm_engctx_init(struct nvkm_object *);
+int _nvkm_engctx_fini(struct nvkm_object *, bool suspend);
+#define _nvkm_engctx_rd32 _nvkm_gpuobj_rd32
+#define _nvkm_engctx_wr32 _nvkm_gpuobj_wr32
+
+struct nvkm_object *nvkm_engctx_get(struct nvkm_engine *, u64 addr);
+void nvkm_engctx_put(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
new file mode 100644
index 000000000000..faf0fd2f0638
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/engine.h
@@ -0,0 +1,56 @@
+#ifndef __NVKM_ENGINE_H__
+#define __NVKM_ENGINE_H__
+#include <core/subdev.h>
+
+#define NV_ENGINE_(eng,var) (NV_ENGINE_CLASS | ((var) << 8) | (eng))
+#define NV_ENGINE(name,var) NV_ENGINE_(NVDEV_ENGINE_##name, (var))
+
+struct nvkm_engine {
+ struct nvkm_subdev subdev;
+ struct nvkm_oclass *cclass;
+ struct nvkm_oclass *sclass;
+
+ struct list_head contexts;
+ spinlock_t lock;
+
+ void (*tile_prog)(struct nvkm_engine *, int region);
+ int (*tlb_flush)(struct nvkm_engine *);
+};
+
+static inline struct nvkm_engine *
+nv_engine(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_ENGINE_CLASS)))
+ nv_assert("BAD CAST -> NvEngine, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+static inline int
+nv_engidx(struct nvkm_engine *engine)
+{
+ return nv_subidx(&engine->subdev);
+}
+
+struct nvkm_engine *nvkm_engine(void *obj, int idx);
+
+#define nvkm_engine_create(p,e,c,d,i,f,r) \
+ nvkm_engine_create_((p), (e), (c), (d), (i), (f), \
+ sizeof(**r),(void **)r)
+
+#define nvkm_engine_destroy(p) \
+ nvkm_subdev_destroy(&(p)->subdev)
+#define nvkm_engine_init(p) \
+ nvkm_subdev_init(&(p)->subdev)
+#define nvkm_engine_fini(p,s) \
+ nvkm_subdev_fini(&(p)->subdev, (s))
+
+int nvkm_engine_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, bool, const char *,
+ const char *, int, void **);
+
+#define _nvkm_engine_dtor _nvkm_subdev_dtor
+#define _nvkm_engine_init _nvkm_subdev_init
+#define _nvkm_engine_fini _nvkm_subdev_fini
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h
new file mode 100644
index 000000000000..e76f76f115e9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/enum.h
@@ -0,0 +1,21 @@
+#ifndef __NVKM_ENUM_H__
+#define __NVKM_ENUM_H__
+#include <core/os.h>
+
+struct nvkm_enum {
+ u32 value;
+ const char *name;
+ const void *data;
+ u32 data2;
+};
+
+const struct nvkm_enum *nvkm_enum_find(const struct nvkm_enum *, u32 value);
+const struct nvkm_enum *nvkm_enum_print(const struct nvkm_enum *, u32 value);
+
+struct nvkm_bitfield {
+ u32 mask;
+ const char *name;
+};
+
+void nvkm_bitfield_print(const struct nvkm_bitfield *, u32 value);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/event.h b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
new file mode 100644
index 000000000000..b98fe2de546a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/event.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_EVENT_H__
+#define __NVKM_EVENT_H__
+#include <core/os.h>
+struct nvkm_notify;
+struct nvkm_object;
+
+struct nvkm_event {
+ const struct nvkm_event_func *func;
+
+ int types_nr;
+ int index_nr;
+
+ spinlock_t refs_lock;
+ spinlock_t list_lock;
+ struct list_head list;
+ int *refs;
+};
+
+struct nvkm_event_func {
+ int (*ctor)(struct nvkm_object *, void *data, u32 size,
+ struct nvkm_notify *);
+ void (*send)(void *data, u32 size, struct nvkm_notify *);
+ void (*init)(struct nvkm_event *, int type, int index);
+ void (*fini)(struct nvkm_event *, int type, int index);
+};
+
+int nvkm_event_init(const struct nvkm_event_func *func, int types_nr,
+ int index_nr, struct nvkm_event *);
+void nvkm_event_fini(struct nvkm_event *);
+void nvkm_event_get(struct nvkm_event *, u32 types, int index);
+void nvkm_event_put(struct nvkm_event *, u32 types, int index);
+void nvkm_event_send(struct nvkm_event *, u32 types, int index,
+ void *data, u32 size);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h
new file mode 100644
index 000000000000..e0187e7abb6e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/gpuobj.h
@@ -0,0 +1,64 @@
+#ifndef __NVKM_GPUOBJ_H__
+#define __NVKM_GPUOBJ_H__
+#include <core/object.h>
+#include <core/mm.h>
+struct nvkm_vma;
+struct nvkm_vm;
+
+#define NVOBJ_FLAG_ZERO_ALLOC 0x00000001
+#define NVOBJ_FLAG_ZERO_FREE 0x00000002
+#define NVOBJ_FLAG_HEAP 0x00000004
+
+struct nvkm_gpuobj {
+ struct nvkm_object object;
+ struct nvkm_object *parent;
+ struct nvkm_mm_node *node;
+ struct nvkm_mm heap;
+
+ u32 flags;
+ u64 addr;
+ u32 size;
+};
+
+static inline struct nvkm_gpuobj *
+nv_gpuobj(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_GPUOBJ_CLASS)))
+ nv_assert("BAD CAST -> NvGpuObj, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nvkm_gpuobj_create(p,e,c,v,g,s,a,f,d) \
+ nvkm_gpuobj_create_((p), (e), (c), (v), (g), (s), (a), (f), \
+ sizeof(**d), (void **)d)
+#define nvkm_gpuobj_init(p) nvkm_object_init(&(p)->object)
+#define nvkm_gpuobj_fini(p,s) nvkm_object_fini(&(p)->object, (s))
+int nvkm_gpuobj_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32 pclass,
+ struct nvkm_object *, u32 size, u32 align,
+ u32 flags, int length, void **);
+void nvkm_gpuobj_destroy(struct nvkm_gpuobj *);
+
+int nvkm_gpuobj_new(struct nvkm_object *, struct nvkm_object *, u32 size,
+ u32 align, u32 flags, struct nvkm_gpuobj **);
+int nvkm_gpuobj_dup(struct nvkm_object *, struct nvkm_gpuobj *,
+ struct nvkm_gpuobj **);
+int nvkm_gpuobj_map(struct nvkm_gpuobj *, u32 acc, struct nvkm_vma *);
+int nvkm_gpuobj_map_vm(struct nvkm_gpuobj *, struct nvkm_vm *, u32 access,
+ struct nvkm_vma *);
+void nvkm_gpuobj_unmap(struct nvkm_vma *);
+
+static inline void
+nvkm_gpuobj_ref(struct nvkm_gpuobj *obj, struct nvkm_gpuobj **ref)
+{
+ nvkm_object_ref(&obj->object, (struct nvkm_object **)ref);
+}
+
+void _nvkm_gpuobj_dtor(struct nvkm_object *);
+int _nvkm_gpuobj_init(struct nvkm_object *);
+int _nvkm_gpuobj_fini(struct nvkm_object *, bool);
+u32 _nvkm_gpuobj_rd32(struct nvkm_object *, u64);
+void _nvkm_gpuobj_wr32(struct nvkm_object *, u64, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h
new file mode 100644
index 000000000000..67f384d0916c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/handle.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_HANDLE_H__
+#define __NVKM_HANDLE_H__
+#include <core/os.h>
+struct nvkm_object;
+
+struct nvkm_handle {
+ struct nvkm_namedb *namedb;
+ struct list_head node;
+
+ struct list_head head;
+ struct list_head tree;
+ u32 name;
+ u32 priv;
+
+ u8 route;
+ u64 token;
+
+ struct nvkm_handle *parent;
+ struct nvkm_object *object;
+};
+
+int nvkm_handle_create(struct nvkm_object *, u32 parent, u32 handle,
+ struct nvkm_object *, struct nvkm_handle **);
+void nvkm_handle_destroy(struct nvkm_handle *);
+int nvkm_handle_init(struct nvkm_handle *);
+int nvkm_handle_fini(struct nvkm_handle *, bool suspend);
+
+struct nvkm_object *nvkm_handle_ref(struct nvkm_object *, u32 name);
+
+struct nvkm_handle *nvkm_handle_get_class(struct nvkm_object *, u16);
+struct nvkm_handle *nvkm_handle_get_vinst(struct nvkm_object *, u64);
+struct nvkm_handle *nvkm_handle_get_cinst(struct nvkm_object *, u32);
+void nvkm_handle_put(struct nvkm_handle *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h b/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h
new file mode 100644
index 000000000000..88971eb37afa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/ioctl.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_IOCTL_H__
+#define __NVKM_IOCTL_H__
+#include <core/os.h>
+struct nvkm_client;
+
+int nvkm_ioctl(struct nvkm_client *, bool, void *, u32, void **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h b/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h
new file mode 100644
index 000000000000..096eb1a623ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/mm.h
@@ -0,0 +1,40 @@
+#ifndef __NVKM_MM_H__
+#define __NVKM_MM_H__
+#include <core/os.h>
+
+struct nvkm_mm_node {
+ struct list_head nl_entry;
+ struct list_head fl_entry;
+ struct list_head rl_entry;
+
+#define NVKM_MM_HEAP_ANY 0x00
+ u8 heap;
+#define NVKM_MM_TYPE_NONE 0x00
+#define NVKM_MM_TYPE_HOLE 0xff
+ u8 type;
+ u32 offset;
+ u32 length;
+};
+
+struct nvkm_mm {
+ struct list_head nodes;
+ struct list_head free;
+
+ u32 block_size;
+ int heap_nodes;
+};
+
+static inline bool
+nvkm_mm_initialised(struct nvkm_mm *mm)
+{
+ return mm->block_size != 0;
+}
+
+int nvkm_mm_init(struct nvkm_mm *, u32 offset, u32 length, u32 block);
+int nvkm_mm_fini(struct nvkm_mm *);
+int nvkm_mm_head(struct nvkm_mm *, u8 heap, u8 type, u32 size_max,
+ u32 size_min, u32 align, struct nvkm_mm_node **);
+int nvkm_mm_tail(struct nvkm_mm *, u8 heap, u8 type, u32 size_max,
+ u32 size_min, u32 align, struct nvkm_mm_node **);
+void nvkm_mm_free(struct nvkm_mm *, struct nvkm_mm_node **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h
new file mode 100644
index 000000000000..4cfe16fcde9b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/namedb.h
@@ -0,0 +1,53 @@
+#ifndef __NVKM_NAMEDB_H__
+#define __NVKM_NAMEDB_H__
+#include <core/parent.h>
+struct nvkm_handle;
+
+struct nvkm_namedb {
+ struct nvkm_parent parent;
+ rwlock_t lock;
+ struct list_head list;
+};
+
+static inline struct nvkm_namedb *
+nv_namedb(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_NAMEDB_CLASS)))
+ nv_assert("BAD CAST -> NvNameDB, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nvkm_namedb_create(p,e,c,v,s,m,d) \
+ nvkm_namedb_create_((p), (e), (c), (v), (s), (m), \
+ sizeof(**d), (void **)d)
+#define nvkm_namedb_init(p) \
+ nvkm_parent_init(&(p)->parent)
+#define nvkm_namedb_fini(p,s) \
+ nvkm_parent_fini(&(p)->parent, (s))
+#define nvkm_namedb_destroy(p) \
+ nvkm_parent_destroy(&(p)->parent)
+
+int nvkm_namedb_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32 pclass,
+ struct nvkm_oclass *, u64 engcls,
+ int size, void **);
+
+int _nvkm_namedb_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+#define _nvkm_namedb_dtor _nvkm_parent_dtor
+#define _nvkm_namedb_init _nvkm_parent_init
+#define _nvkm_namedb_fini _nvkm_parent_fini
+
+int nvkm_namedb_insert(struct nvkm_namedb *, u32 name, struct nvkm_object *,
+ struct nvkm_handle *);
+void nvkm_namedb_remove(struct nvkm_handle *);
+
+struct nvkm_handle *nvkm_namedb_get(struct nvkm_namedb *, u32);
+struct nvkm_handle *nvkm_namedb_get_class(struct nvkm_namedb *, u16);
+struct nvkm_handle *nvkm_namedb_get_vinst(struct nvkm_namedb *, u64);
+struct nvkm_handle *nvkm_namedb_get_cinst(struct nvkm_namedb *, u32);
+void nvkm_namedb_put(struct nvkm_handle *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h b/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
new file mode 100644
index 000000000000..753d08c1767b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/notify.h
@@ -0,0 +1,38 @@
+#ifndef __NVKM_NOTIFY_H__
+#define __NVKM_NOTIFY_H__
+#include <core/os.h>
+struct nvkm_object;
+
+struct nvkm_notify {
+ struct nvkm_event *event;
+ struct list_head head;
+#define NVKM_NOTIFY_USER 0
+#define NVKM_NOTIFY_WORK 1
+ unsigned long flags;
+ int block;
+#define NVKM_NOTIFY_DROP 0
+#define NVKM_NOTIFY_KEEP 1
+ int (*func)(struct nvkm_notify *);
+
+ /* set by nvkm_event ctor */
+ u32 types;
+ int index;
+ u32 size;
+
+ struct work_struct work;
+ /* this is const for a *very* good reason - the data might be on the
+ * stack from an irq handler. if you're not core/notify.c then you
+ * should probably think twice before casting it away...
+ */
+ const void *data;
+};
+
+int nvkm_notify_init(struct nvkm_object *, struct nvkm_event *,
+ int (*func)(struct nvkm_notify *), bool work,
+ void *data, u32 size, u32 reply,
+ struct nvkm_notify *);
+void nvkm_notify_fini(struct nvkm_notify *);
+void nvkm_notify_get(struct nvkm_notify *);
+void nvkm_notify_put(struct nvkm_notify *);
+void nvkm_notify_send(struct nvkm_notify *, void *data, u32 size);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/object.h b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
new file mode 100644
index 000000000000..6e3cd3908400
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/object.h
@@ -0,0 +1,203 @@
+#ifndef __NVKM_OBJECT_H__
+#define __NVKM_OBJECT_H__
+#include <core/os.h>
+#include <core/printk.h>
+
+#define NV_PARENT_CLASS 0x80000000
+#define NV_NAMEDB_CLASS 0x40000000
+#define NV_CLIENT_CLASS 0x20000000
+#define NV_SUBDEV_CLASS 0x10000000
+#define NV_ENGINE_CLASS 0x08000000
+#define NV_MEMOBJ_CLASS 0x04000000
+#define NV_GPUOBJ_CLASS 0x02000000
+#define NV_ENGCTX_CLASS 0x01000000
+#define NV_OBJECT_CLASS 0x0000ffff
+
+struct nvkm_object {
+ struct nvkm_oclass *oclass;
+ struct nvkm_object *parent;
+ struct nvkm_engine *engine;
+ atomic_t refcount;
+ atomic_t usecount;
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+#define NVKM_OBJECT_MAGIC 0x75ef0bad
+ struct list_head list;
+ u32 _magic;
+#endif
+};
+
+static inline struct nvkm_object *
+nv_object(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (likely(obj)) {
+ struct nvkm_object *object = obj;
+ if (unlikely(object->_magic != NVKM_OBJECT_MAGIC))
+ nv_assert("BAD CAST -> NvObject, invalid magic");
+ }
+#endif
+ return obj;
+}
+
+#define nvkm_object_create(p,e,c,s,d) \
+ nvkm_object_create_((p), (e), (c), (s), sizeof(**d), (void **)d)
+int nvkm_object_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32, int size, void **);
+void nvkm_object_destroy(struct nvkm_object *);
+int nvkm_object_init(struct nvkm_object *);
+int nvkm_object_fini(struct nvkm_object *, bool suspend);
+
+int _nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+extern struct nvkm_ofuncs nvkm_object_ofuncs;
+
+/* Don't allocate dynamically, because lockdep needs lock_class_keys to be in
+ * ".data". */
+struct nvkm_oclass {
+ u32 handle;
+ struct nvkm_ofuncs * const ofuncs;
+ struct nvkm_omthds * const omthds;
+ struct lock_class_key lock_class_key;
+};
+
+#define nv_oclass(o) nv_object(o)->oclass
+#define nv_hclass(o) nv_oclass(o)->handle
+#define nv_iclass(o,i) (nv_hclass(o) & (i))
+#define nv_mclass(o) nv_iclass(o, NV_OBJECT_CLASS)
+
+static inline struct nvkm_object *
+nv_pclass(struct nvkm_object *parent, u32 oclass)
+{
+ while (parent && !nv_iclass(parent, oclass))
+ parent = parent->parent;
+ return parent;
+}
+
+struct nvkm_omthds {
+ u32 start;
+ u32 limit;
+ int (*call)(struct nvkm_object *, u32, void *, u32);
+};
+
+struct nvkm_event;
+struct nvkm_ofuncs {
+ int (*ctor)(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *data, u32 size,
+ struct nvkm_object **);
+ void (*dtor)(struct nvkm_object *);
+ int (*init)(struct nvkm_object *);
+ int (*fini)(struct nvkm_object *, bool suspend);
+ int (*mthd)(struct nvkm_object *, u32, void *, u32);
+ int (*ntfy)(struct nvkm_object *, u32, struct nvkm_event **);
+ int (* map)(struct nvkm_object *, u64 *, u32 *);
+ u8 (*rd08)(struct nvkm_object *, u64 offset);
+ u16 (*rd16)(struct nvkm_object *, u64 offset);
+ u32 (*rd32)(struct nvkm_object *, u64 offset);
+ void (*wr08)(struct nvkm_object *, u64 offset, u8 data);
+ void (*wr16)(struct nvkm_object *, u64 offset, u16 data);
+ void (*wr32)(struct nvkm_object *, u64 offset, u32 data);
+};
+
+static inline struct nvkm_ofuncs *
+nv_ofuncs(void *obj)
+{
+ return nv_oclass(obj)->ofuncs;
+}
+
+int nvkm_object_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nvkm_object_ref(struct nvkm_object *, struct nvkm_object **);
+int nvkm_object_inc(struct nvkm_object *);
+int nvkm_object_dec(struct nvkm_object *, bool suspend);
+void nvkm_object_debug(void);
+
+static inline int
+nv_exec(void *obj, u32 mthd, void *data, u32 size)
+{
+ struct nvkm_omthds *method = nv_oclass(obj)->omthds;
+
+ while (method && method->call) {
+ if (mthd >= method->start && mthd <= method->limit)
+ return method->call(obj, mthd, data, size);
+ method++;
+ }
+
+ return -EINVAL;
+}
+
+static inline int
+nv_call(void *obj, u32 mthd, u32 data)
+{
+ return nv_exec(obj, mthd, &data, sizeof(data));
+}
+
+static inline u8
+nv_ro08(void *obj, u64 addr)
+{
+ u8 data = nv_ofuncs(obj)->rd08(obj, addr);
+ nv_spam(obj, "nv_ro08 0x%08llx 0x%02x\n", addr, data);
+ return data;
+}
+
+static inline u16
+nv_ro16(void *obj, u64 addr)
+{
+ u16 data = nv_ofuncs(obj)->rd16(obj, addr);
+ nv_spam(obj, "nv_ro16 0x%08llx 0x%04x\n", addr, data);
+ return data;
+}
+
+static inline u32
+nv_ro32(void *obj, u64 addr)
+{
+ u32 data = nv_ofuncs(obj)->rd32(obj, addr);
+ nv_spam(obj, "nv_ro32 0x%08llx 0x%08x\n", addr, data);
+ return data;
+}
+
+static inline void
+nv_wo08(void *obj, u64 addr, u8 data)
+{
+ nv_spam(obj, "nv_wo08 0x%08llx 0x%02x\n", addr, data);
+ nv_ofuncs(obj)->wr08(obj, addr, data);
+}
+
+static inline void
+nv_wo16(void *obj, u64 addr, u16 data)
+{
+ nv_spam(obj, "nv_wo16 0x%08llx 0x%04x\n", addr, data);
+ nv_ofuncs(obj)->wr16(obj, addr, data);
+}
+
+static inline void
+nv_wo32(void *obj, u64 addr, u32 data)
+{
+ nv_spam(obj, "nv_wo32 0x%08llx 0x%08x\n", addr, data);
+ nv_ofuncs(obj)->wr32(obj, addr, data);
+}
+
+static inline u32
+nv_mo32(void *obj, u64 addr, u32 mask, u32 data)
+{
+ u32 temp = nv_ro32(obj, addr);
+ nv_wo32(obj, addr, (temp & ~mask) | data);
+ return temp;
+}
+
+static inline int
+nv_memcmp(void *obj, u32 addr, const char *str, u32 len)
+{
+ unsigned char c1, c2;
+
+ while (len--) {
+ c1 = nv_ro08(obj, addr++);
+ c2 = *(str++);
+ if (c1 != c2)
+ return c1 - c2;
+ }
+ return 0;
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/option.h b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
new file mode 100644
index 000000000000..532bfa8e3f72
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/option.h
@@ -0,0 +1,17 @@
+#ifndef __NVKM_OPTION_H__
+#define __NVKM_OPTION_H__
+#include <core/os.h>
+
+const char *nvkm_stropt(const char *optstr, const char *opt, int *len);
+bool nvkm_boolopt(const char *optstr, const char *opt, bool value);
+int nvkm_dbgopt(const char *optstr, const char *sub);
+
+/* compares unterminated string 'str' with zero-terminated string 'cmp' */
+static inline int
+strncasecmpz(const char *str, const char *cmp, size_t len)
+{
+ if (strlen(cmp) != len)
+ return len;
+ return strncasecmp(str, cmp, len);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/os.h b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
new file mode 100644
index 000000000000..cd57e238ddd3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/os.h
@@ -0,0 +1,4 @@
+#ifndef __NVKM_OS_H__
+#define __NVKM_OS_H__
+#include <nvif/os.h>
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h
new file mode 100644
index 000000000000..837e4fe966a5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/parent.h
@@ -0,0 +1,58 @@
+#ifndef __NVKM_PARENT_H__
+#define __NVKM_PARENT_H__
+#include <core/object.h>
+
+struct nvkm_sclass {
+ struct nvkm_sclass *sclass;
+ struct nvkm_engine *engine;
+ struct nvkm_oclass *oclass;
+};
+
+struct nvkm_parent {
+ struct nvkm_object object;
+
+ struct nvkm_sclass *sclass;
+ u64 engine;
+
+ int (*context_attach)(struct nvkm_object *, struct nvkm_object *);
+ int (*context_detach)(struct nvkm_object *, bool suspend,
+ struct nvkm_object *);
+
+ int (*object_attach)(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 name);
+ void (*object_detach)(struct nvkm_object *parent, int cookie);
+};
+
+static inline struct nvkm_parent *
+nv_parent(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!(nv_iclass(obj, NV_PARENT_CLASS))))
+ nv_assert("BAD CAST -> NvParent, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+#define nvkm_parent_create(p,e,c,v,s,m,d) \
+ nvkm_parent_create_((p), (e), (c), (v), (s), (m), \
+ sizeof(**d), (void **)d)
+#define nvkm_parent_init(p) \
+ nvkm_object_init(&(p)->object)
+#define nvkm_parent_fini(p,s) \
+ nvkm_object_fini(&(p)->object, (s))
+
+int nvkm_parent_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32 pclass,
+ struct nvkm_oclass *, u64 engcls,
+ int size, void **);
+void nvkm_parent_destroy(struct nvkm_parent *);
+
+void _nvkm_parent_dtor(struct nvkm_object *);
+#define _nvkm_parent_init nvkm_object_init
+#define _nvkm_parent_fini nvkm_object_fini
+
+int nvkm_parent_sclass(struct nvkm_object *, u16 handle,
+ struct nvkm_object **pengine,
+ struct nvkm_oclass **poclass);
+int nvkm_parent_lclass(struct nvkm_object *, u32 *, int);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h b/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h
new file mode 100644
index 000000000000..83648177059f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/printk.h
@@ -0,0 +1,29 @@
+#ifndef __NVKM_PRINTK_H__
+#define __NVKM_PRINTK_H__
+#include <core/os.h>
+#include <core/debug.h>
+struct nvkm_object;
+
+void __printf(3, 4)
+nv_printk_(struct nvkm_object *, int, const char *, ...);
+
+#define nv_printk(o,l,f,a...) do { \
+ if (NV_DBG_##l <= CONFIG_NOUVEAU_DEBUG) \
+ nv_printk_(nv_object(o), NV_DBG_##l, f, ##a); \
+} while(0)
+
+#define nv_fatal(o,f,a...) nv_printk((o), FATAL, f, ##a)
+#define nv_error(o,f,a...) nv_printk((o), ERROR, f, ##a)
+#define nv_warn(o,f,a...) nv_printk((o), WARN, f, ##a)
+#define nv_info(o,f,a...) nv_printk((o), INFO, f, ##a)
+#define nv_debug(o,f,a...) nv_printk((o), DEBUG, f, ##a)
+#define nv_trace(o,f,a...) nv_printk((o), TRACE, f, ##a)
+#define nv_spam(o,f,a...) nv_printk((o), SPAM, f, ##a)
+#define nv_ioctl(o,f,a...) nv_trace(nvkm_client(o), "ioctl: "f, ##a)
+
+#define nv_assert(f,a...) do { \
+ if (NV_DBG_FATAL <= CONFIG_NOUVEAU_DEBUG) \
+ nv_printk_(NULL, NV_DBG_FATAL, f "\n", ##a); \
+ BUG_ON(1); \
+} while(0)
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h b/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h
new file mode 100644
index 000000000000..cc132eaa10cc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/ramht.h
@@ -0,0 +1,20 @@
+#ifndef __NVKM_RAMHT_H__
+#define __NVKM_RAMHT_H__
+#include <core/gpuobj.h>
+
+struct nvkm_ramht {
+ struct nvkm_gpuobj gpuobj;
+ int bits;
+};
+
+int nvkm_ramht_insert(struct nvkm_ramht *, int chid, u32 handle, u32 context);
+void nvkm_ramht_remove(struct nvkm_ramht *, int cookie);
+int nvkm_ramht_new(struct nvkm_object *, struct nvkm_object *, u32 size,
+ u32 align, struct nvkm_ramht **);
+
+static inline void
+nvkm_ramht_ref(struct nvkm_ramht *obj, struct nvkm_ramht **ref)
+{
+ nvkm_gpuobj_ref(&obj->gpuobj, (struct nvkm_gpuobj **)ref);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
new file mode 100644
index 000000000000..6fdc39116aac
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/core/subdev.h
@@ -0,0 +1,119 @@
+#ifndef __NVKM_SUBDEV_H__
+#define __NVKM_SUBDEV_H__
+#include <core/object.h>
+#include <core/devidx.h>
+
+#define NV_SUBDEV_(sub,var) (NV_SUBDEV_CLASS | ((var) << 8) | (sub))
+#define NV_SUBDEV(name,var) NV_SUBDEV_(NVDEV_SUBDEV_##name, (var))
+
+struct nvkm_subdev {
+ struct nvkm_object object;
+ struct mutex mutex;
+ const char *name;
+ void __iomem *mmio;
+ u32 debug;
+ u32 unit;
+
+ void (*intr)(struct nvkm_subdev *);
+};
+
+static inline struct nvkm_subdev *
+nv_subdev(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_SUBDEV_CLASS)))
+ nv_assert("BAD CAST -> NvSubDev, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+static inline int
+nv_subidx(struct nvkm_subdev *subdev)
+{
+ return nv_hclass(subdev) & 0xff;
+}
+
+struct nvkm_subdev *nvkm_subdev(void *obj, int idx);
+
+#define nvkm_subdev_create(p,e,o,v,s,f,d) \
+ nvkm_subdev_create_((p), (e), (o), (v), (s), (f), \
+ sizeof(**d),(void **)d)
+
+int nvkm_subdev_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32 pclass,
+ const char *sname, const char *fname,
+ int size, void **);
+void nvkm_subdev_destroy(struct nvkm_subdev *);
+int nvkm_subdev_init(struct nvkm_subdev *);
+int nvkm_subdev_fini(struct nvkm_subdev *, bool suspend);
+void nvkm_subdev_reset(struct nvkm_object *);
+
+void _nvkm_subdev_dtor(struct nvkm_object *);
+int _nvkm_subdev_init(struct nvkm_object *);
+int _nvkm_subdev_fini(struct nvkm_object *, bool suspend);
+
+#define s_printk(s,l,f,a...) do { \
+ if ((s)->debug >= OS_DBG_##l) { \
+ nv_printk((s)->base.parent, (s)->name, l, f, ##a); \
+ } \
+} while(0)
+
+static inline u8
+nv_rd08(void *obj, u32 addr)
+{
+ struct nvkm_subdev *subdev = nv_subdev(obj);
+ u8 data = ioread8(subdev->mmio + addr);
+ nv_spam(subdev, "nv_rd08 0x%06x 0x%02x\n", addr, data);
+ return data;
+}
+
+static inline u16
+nv_rd16(void *obj, u32 addr)
+{
+ struct nvkm_subdev *subdev = nv_subdev(obj);
+ u16 data = ioread16_native(subdev->mmio + addr);
+ nv_spam(subdev, "nv_rd16 0x%06x 0x%04x\n", addr, data);
+ return data;
+}
+
+static inline u32
+nv_rd32(void *obj, u32 addr)
+{
+ struct nvkm_subdev *subdev = nv_subdev(obj);
+ u32 data = ioread32_native(subdev->mmio + addr);
+ nv_spam(subdev, "nv_rd32 0x%06x 0x%08x\n", addr, data);
+ return data;
+}
+
+static inline void
+nv_wr08(void *obj, u32 addr, u8 data)
+{
+ struct nvkm_subdev *subdev = nv_subdev(obj);
+ nv_spam(subdev, "nv_wr08 0x%06x 0x%02x\n", addr, data);
+ iowrite8(data, subdev->mmio + addr);
+}
+
+static inline void
+nv_wr16(void *obj, u32 addr, u16 data)
+{
+ struct nvkm_subdev *subdev = nv_subdev(obj);
+ nv_spam(subdev, "nv_wr16 0x%06x 0x%04x\n", addr, data);
+ iowrite16_native(data, subdev->mmio + addr);
+}
+
+static inline void
+nv_wr32(void *obj, u32 addr, u32 data)
+{
+ struct nvkm_subdev *subdev = nv_subdev(obj);
+ nv_spam(subdev, "nv_wr32 0x%06x 0x%08x\n", addr, data);
+ iowrite32_native(data, subdev->mmio + addr);
+}
+
+static inline u32
+nv_mask(void *obj, u32 addr, u32 mask, u32 data)
+{
+ u32 temp = nv_rd32(obj, addr);
+ nv_wr32(obj, addr, (temp & ~mask) | data);
+ return temp;
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h
new file mode 100644
index 000000000000..e489beef2b92
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/bsp.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_BSP_H__
+#define __NVKM_BSP_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g84_bsp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
new file mode 100644
index 000000000000..7e29c52617ea
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/ce.h
@@ -0,0 +1,13 @@
+#ifndef __NVKM_CE_H__
+#define __NVKM_CE_H__
+#include <core/engine.h>
+
+void gt215_ce_intr(struct nvkm_subdev *);
+
+extern struct nvkm_oclass gt215_ce_oclass;
+extern struct nvkm_oclass gf100_ce0_oclass;
+extern struct nvkm_oclass gf100_ce1_oclass;
+extern struct nvkm_oclass gk104_ce0_oclass;
+extern struct nvkm_oclass gk104_ce1_oclass;
+extern struct nvkm_oclass gk104_ce2_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h
new file mode 100644
index 000000000000..57c29e91bad5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/cipher.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_CIPHER_H__
+#define __NVKM_CIPHER_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g84_cipher_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h
new file mode 100644
index 000000000000..5d4805e67e76
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/device.h
@@ -0,0 +1,30 @@
+#ifndef __NOUVEAU_SUBDEV_DEVICE_H__
+#define __NOUVEAU_SUBDEV_DEVICE_H__
+
+#include <core/device.h>
+
+struct platform_device;
+
+enum nv_bus_type {
+ NOUVEAU_BUS_PCI,
+ NOUVEAU_BUS_PLATFORM,
+};
+
+#define nouveau_device_create(p,t,n,s,c,d,u) \
+ nouveau_device_create_((void *)(p), (t), (n), (s), (c), (d), \
+ sizeof(**u), (void **)u)
+
+int nouveau_device_create_(void *, enum nv_bus_type type, u64 name,
+ const char *sname, const char *cfg, const char *dbg,
+ int, void **);
+
+int nv04_identify(struct nouveau_device *);
+int nv10_identify(struct nouveau_device *);
+int nv20_identify(struct nouveau_device *);
+int nv30_identify(struct nouveau_device *);
+int nv40_identify(struct nouveau_device *);
+int nv50_identify(struct nouveau_device *);
+int nvc0_identify(struct nouveau_device *);
+int nve0_identify(struct nouveau_device *);
+int gm100_identify(struct nouveau_device *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
new file mode 100644
index 000000000000..a5e1ed81312f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/disp.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_DISP_H__
+#define __NVKM_DISP_H__
+#include <core/engine.h>
+#include <core/event.h>
+
+struct nvkm_disp {
+ struct nvkm_engine base;
+
+ struct list_head outp;
+
+ struct nvkm_event hpd;
+ struct nvkm_event vblank;
+};
+
+static inline struct nvkm_disp *
+nvkm_disp(void *obj)
+{
+ return (void *)nvkm_engine(obj, NVDEV_ENGINE_DISP);
+}
+
+extern struct nvkm_oclass *nv04_disp_oclass;
+extern struct nvkm_oclass *nv50_disp_oclass;
+extern struct nvkm_oclass *g84_disp_oclass;
+extern struct nvkm_oclass *gt200_disp_oclass;
+extern struct nvkm_oclass *g94_disp_oclass;
+extern struct nvkm_oclass *gt215_disp_oclass;
+extern struct nvkm_oclass *gf110_disp_oclass;
+extern struct nvkm_oclass *gk104_disp_oclass;
+extern struct nvkm_oclass *gk110_disp_oclass;
+extern struct nvkm_oclass *gm107_disp_oclass;
+extern struct nvkm_oclass *gm204_disp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h
new file mode 100644
index 000000000000..c4fce8afcf83
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/dmaobj.h
@@ -0,0 +1,26 @@
+#ifndef __NVKM_DMAOBJ_H__
+#define __NVKM_DMAOBJ_H__
+#include <core/engine.h>
+struct nvkm_gpuobj;
+
+struct nvkm_dmaobj {
+ struct nvkm_object base;
+ u32 target;
+ u32 access;
+ u64 start;
+ u64 limit;
+};
+
+struct nvkm_dmaeng {
+ struct nvkm_engine base;
+
+ /* creates a "physical" dma object from a struct nvkm_dmaobj */
+ int (*bind)(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+ struct nvkm_gpuobj **);
+};
+
+extern struct nvkm_oclass *nv04_dmaeng_oclass;
+extern struct nvkm_oclass *nv50_dmaeng_oclass;
+extern struct nvkm_oclass *gf100_dmaeng_oclass;
+extern struct nvkm_oclass *gf110_dmaeng_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
new file mode 100644
index 000000000000..bd38cf9130fc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/falcon.h
@@ -0,0 +1,81 @@
+#ifndef __NVKM_FALCON_H__
+#define __NVKM_FALCON_H__
+#include <core/engctx.h>
+
+struct nvkm_falcon_chan {
+ struct nvkm_engctx base;
+};
+
+#define nvkm_falcon_context_create(p,e,c,g,s,a,f,d) \
+ nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nvkm_falcon_context_destroy(d) \
+ nvkm_engctx_destroy(&(d)->base)
+#define nvkm_falcon_context_init(d) \
+ nvkm_engctx_init(&(d)->base)
+#define nvkm_falcon_context_fini(d,s) \
+ nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_falcon_context_ctor _nvkm_engctx_ctor
+#define _nvkm_falcon_context_dtor _nvkm_engctx_dtor
+#define _nvkm_falcon_context_init _nvkm_engctx_init
+#define _nvkm_falcon_context_fini _nvkm_engctx_fini
+#define _nvkm_falcon_context_rd32 _nvkm_engctx_rd32
+#define _nvkm_falcon_context_wr32 _nvkm_engctx_wr32
+
+struct nvkm_falcon_data {
+ bool external;
+};
+
+#include <core/engine.h>
+
+struct nvkm_falcon {
+ struct nvkm_engine base;
+
+ u32 addr;
+ u8 version;
+ u8 secret;
+
+ struct nvkm_gpuobj *core;
+ bool external;
+
+ struct {
+ u32 limit;
+ u32 *data;
+ u32 size;
+ } code;
+
+ struct {
+ u32 limit;
+ u32 *data;
+ u32 size;
+ } data;
+};
+
+#define nv_falcon(priv) (&(priv)->base)
+
+#define nvkm_falcon_create(p,e,c,b,d,i,f,r) \
+ nvkm_falcon_create_((p), (e), (c), (b), (d), (i), (f), \
+ sizeof(**r),(void **)r)
+#define nvkm_falcon_destroy(p) \
+ nvkm_engine_destroy(&(p)->base)
+#define nvkm_falcon_init(p) ({ \
+ struct nvkm_falcon *falcon = (p); \
+ _nvkm_falcon_init(nv_object(falcon)); \
+})
+#define nvkm_falcon_fini(p,s) ({ \
+ struct nvkm_falcon *falcon = (p); \
+ _nvkm_falcon_fini(nv_object(falcon), (s)); \
+})
+
+int nvkm_falcon_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32, bool, const char *,
+ const char *, int, void **);
+
+void nvkm_falcon_intr(struct nvkm_subdev *subdev);
+
+#define _nvkm_falcon_dtor _nvkm_engine_dtor
+int _nvkm_falcon_init(struct nvkm_object *);
+int _nvkm_falcon_fini(struct nvkm_object *, bool);
+u32 _nvkm_falcon_rd32(struct nvkm_object *, u64);
+void _nvkm_falcon_wr32(struct nvkm_object *, u64, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
new file mode 100644
index 000000000000..05321ce7ab15
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/fifo.h
@@ -0,0 +1,126 @@
+#ifndef __NVKM_FIFO_H__
+#define __NVKM_FIFO_H__
+#include <core/namedb.h>
+
+struct nvkm_fifo_chan {
+ struct nvkm_namedb namedb;
+ struct nvkm_dmaobj *pushdma;
+ struct nvkm_gpuobj *pushgpu;
+ void __iomem *user;
+ u64 addr;
+ u32 size;
+ u16 chid;
+ atomic_t refcnt; /* NV04_NVSW_SET_REF */
+};
+
+static inline struct nvkm_fifo_chan *
+nvkm_fifo_chan(void *obj)
+{
+ return (void *)nv_namedb(obj);
+}
+
+#define nvkm_fifo_channel_create(p,e,c,b,a,s,n,m,d) \
+ nvkm_fifo_channel_create_((p), (e), (c), (b), (a), (s), (n), \
+ (m), sizeof(**d), (void **)d)
+#define nvkm_fifo_channel_init(p) \
+ nvkm_namedb_init(&(p)->namedb)
+#define nvkm_fifo_channel_fini(p,s) \
+ nvkm_namedb_fini(&(p)->namedb, (s))
+
+int nvkm_fifo_channel_create_(struct nvkm_object *,
+ struct nvkm_object *,
+ struct nvkm_oclass *,
+ int bar, u32 addr, u32 size, u32 push,
+ u64 engmask, int len, void **);
+void nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *);
+
+#define _nvkm_fifo_channel_init _nvkm_namedb_init
+#define _nvkm_fifo_channel_fini _nvkm_namedb_fini
+
+void _nvkm_fifo_channel_dtor(struct nvkm_object *);
+int _nvkm_fifo_channel_map(struct nvkm_object *, u64 *, u32 *);
+u32 _nvkm_fifo_channel_rd32(struct nvkm_object *, u64);
+void _nvkm_fifo_channel_wr32(struct nvkm_object *, u64, u32);
+int _nvkm_fifo_channel_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
+
+#include <core/gpuobj.h>
+
+struct nvkm_fifo_base {
+ struct nvkm_gpuobj gpuobj;
+};
+
+#define nvkm_fifo_context_create(p,e,c,g,s,a,f,d) \
+ nvkm_gpuobj_create((p), (e), (c), 0, (g), (s), (a), (f), (d))
+#define nvkm_fifo_context_destroy(p) \
+ nvkm_gpuobj_destroy(&(p)->gpuobj)
+#define nvkm_fifo_context_init(p) \
+ nvkm_gpuobj_init(&(p)->gpuobj)
+#define nvkm_fifo_context_fini(p,s) \
+ nvkm_gpuobj_fini(&(p)->gpuobj, (s))
+
+#define _nvkm_fifo_context_dtor _nvkm_gpuobj_dtor
+#define _nvkm_fifo_context_init _nvkm_gpuobj_init
+#define _nvkm_fifo_context_fini _nvkm_gpuobj_fini
+#define _nvkm_fifo_context_rd32 _nvkm_gpuobj_rd32
+#define _nvkm_fifo_context_wr32 _nvkm_gpuobj_wr32
+
+#include <core/engine.h>
+#include <core/event.h>
+
+struct nvkm_fifo {
+ struct nvkm_engine base;
+
+ struct nvkm_event cevent; /* channel creation event */
+ struct nvkm_event uevent; /* async user trigger */
+
+ struct nvkm_object **channel;
+ spinlock_t lock;
+ u16 min;
+ u16 max;
+
+ int (*chid)(struct nvkm_fifo *, struct nvkm_object *);
+ void (*pause)(struct nvkm_fifo *, unsigned long *);
+ void (*start)(struct nvkm_fifo *, unsigned long *);
+};
+
+static inline struct nvkm_fifo *
+nvkm_fifo(void *obj)
+{
+ return (void *)nvkm_engine(obj, NVDEV_ENGINE_FIFO);
+}
+
+#define nvkm_fifo_create(o,e,c,fc,lc,d) \
+ nvkm_fifo_create_((o), (e), (c), (fc), (lc), sizeof(**d), (void **)d)
+#define nvkm_fifo_init(p) \
+ nvkm_engine_init(&(p)->base)
+#define nvkm_fifo_fini(p,s) \
+ nvkm_engine_fini(&(p)->base, (s))
+
+int nvkm_fifo_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int min, int max,
+ int size, void **);
+void nvkm_fifo_destroy(struct nvkm_fifo *);
+const char *
+nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid);
+
+#define _nvkm_fifo_init _nvkm_engine_init
+#define _nvkm_fifo_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass *nv04_fifo_oclass;
+extern struct nvkm_oclass *nv10_fifo_oclass;
+extern struct nvkm_oclass *nv17_fifo_oclass;
+extern struct nvkm_oclass *nv40_fifo_oclass;
+extern struct nvkm_oclass *nv50_fifo_oclass;
+extern struct nvkm_oclass *g84_fifo_oclass;
+extern struct nvkm_oclass *gf100_fifo_oclass;
+extern struct nvkm_oclass *gk104_fifo_oclass;
+extern struct nvkm_oclass *gk20a_fifo_oclass;
+extern struct nvkm_oclass *gk208_fifo_oclass;
+
+int nvkm_fifo_uevent_ctor(struct nvkm_object *, void *, u32,
+ struct nvkm_notify *);
+void nvkm_fifo_uevent(struct nvkm_fifo *);
+
+void nv04_fifo_intr(struct nvkm_subdev *);
+int nv04_fifo_context_attach(struct nvkm_object *, struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
new file mode 100644
index 000000000000..93ef1f2bfac4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/gr.h
@@ -0,0 +1,86 @@
+#ifndef __NVKM_GR_H__
+#define __NVKM_GR_H__
+#include <core/engctx.h>
+
+struct nvkm_gr_chan {
+ struct nvkm_engctx base;
+};
+
+#define nvkm_gr_context_create(p,e,c,g,s,a,f,d) \
+ nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nvkm_gr_context_destroy(d) \
+ nvkm_engctx_destroy(&(d)->base)
+#define nvkm_gr_context_init(d) \
+ nvkm_engctx_init(&(d)->base)
+#define nvkm_gr_context_fini(d,s) \
+ nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_gr_context_dtor _nvkm_engctx_dtor
+#define _nvkm_gr_context_init _nvkm_engctx_init
+#define _nvkm_gr_context_fini _nvkm_engctx_fini
+#define _nvkm_gr_context_rd32 _nvkm_engctx_rd32
+#define _nvkm_gr_context_wr32 _nvkm_engctx_wr32
+
+#include <core/engine.h>
+
+struct nvkm_gr {
+ struct nvkm_engine base;
+
+ /* Returns chipset-specific counts of units packed into an u64.
+ */
+ u64 (*units)(struct nvkm_gr *);
+};
+
+static inline struct nvkm_gr *
+nvkm_gr(void *obj)
+{
+ return (void *)nvkm_engine(obj, NVDEV_ENGINE_GR);
+}
+
+#define nvkm_gr_create(p,e,c,y,d) \
+ nvkm_engine_create((p), (e), (c), (y), "PGR", "graphics", (d))
+#define nvkm_gr_destroy(d) \
+ nvkm_engine_destroy(&(d)->base)
+#define nvkm_gr_init(d) \
+ nvkm_engine_init(&(d)->base)
+#define nvkm_gr_fini(d,s) \
+ nvkm_engine_fini(&(d)->base, (s))
+
+#define _nvkm_gr_dtor _nvkm_engine_dtor
+#define _nvkm_gr_init _nvkm_engine_init
+#define _nvkm_gr_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass nv04_gr_oclass;
+extern struct nvkm_oclass nv10_gr_oclass;
+extern struct nvkm_oclass nv20_gr_oclass;
+extern struct nvkm_oclass nv25_gr_oclass;
+extern struct nvkm_oclass nv2a_gr_oclass;
+extern struct nvkm_oclass nv30_gr_oclass;
+extern struct nvkm_oclass nv34_gr_oclass;
+extern struct nvkm_oclass nv35_gr_oclass;
+extern struct nvkm_oclass nv40_gr_oclass;
+extern struct nvkm_oclass nv50_gr_oclass;
+extern struct nvkm_oclass *gf100_gr_oclass;
+extern struct nvkm_oclass *gf108_gr_oclass;
+extern struct nvkm_oclass *gf104_gr_oclass;
+extern struct nvkm_oclass *gf110_gr_oclass;
+extern struct nvkm_oclass *gf117_gr_oclass;
+extern struct nvkm_oclass *gf119_gr_oclass;
+extern struct nvkm_oclass *gk104_gr_oclass;
+extern struct nvkm_oclass *gk20a_gr_oclass;
+extern struct nvkm_oclass *gk110_gr_oclass;
+extern struct nvkm_oclass *gk110b_gr_oclass;
+extern struct nvkm_oclass *gk208_gr_oclass;
+extern struct nvkm_oclass *gm107_gr_oclass;
+
+#include <core/enum.h>
+
+extern const struct nvkm_bitfield nv04_gr_nsource[];
+extern struct nvkm_ofuncs nv04_gr_ofuncs;
+bool nv04_gr_idle(void *obj);
+
+extern const struct nvkm_bitfield nv10_gr_intr_name[];
+extern const struct nvkm_bitfield nv10_gr_nstatus[];
+
+extern const struct nvkm_enum nv50_data_error_names[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h
new file mode 100644
index 000000000000..4e500b398064
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mpeg.h
@@ -0,0 +1,62 @@
+#ifndef __NVKM_MPEG_H__
+#define __NVKM_MPEG_H__
+#include <core/engctx.h>
+
+struct nvkm_mpeg_chan {
+ struct nvkm_engctx base;
+};
+
+#define nvkm_mpeg_context_create(p,e,c,g,s,a,f,d) \
+ nvkm_engctx_create((p), (e), (c), (g), (s), (a), (f), (d))
+#define nvkm_mpeg_context_destroy(d) \
+ nvkm_engctx_destroy(&(d)->base)
+#define nvkm_mpeg_context_init(d) \
+ nvkm_engctx_init(&(d)->base)
+#define nvkm_mpeg_context_fini(d,s) \
+ nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_mpeg_context_dtor _nvkm_engctx_dtor
+#define _nvkm_mpeg_context_init _nvkm_engctx_init
+#define _nvkm_mpeg_context_fini _nvkm_engctx_fini
+#define _nvkm_mpeg_context_rd32 _nvkm_engctx_rd32
+#define _nvkm_mpeg_context_wr32 _nvkm_engctx_wr32
+
+#include <core/engine.h>
+
+struct nvkm_mpeg {
+ struct nvkm_engine base;
+};
+
+#define nvkm_mpeg_create(p,e,c,d) \
+ nvkm_engine_create((p), (e), (c), true, "PMPEG", "mpeg", (d))
+#define nvkm_mpeg_destroy(d) \
+ nvkm_engine_destroy(&(d)->base)
+#define nvkm_mpeg_init(d) \
+ nvkm_engine_init(&(d)->base)
+#define nvkm_mpeg_fini(d,s) \
+ nvkm_engine_fini(&(d)->base, (s))
+
+#define _nvkm_mpeg_dtor _nvkm_engine_dtor
+#define _nvkm_mpeg_init _nvkm_engine_init
+#define _nvkm_mpeg_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass nv31_mpeg_oclass;
+extern struct nvkm_oclass nv40_mpeg_oclass;
+extern struct nvkm_oclass nv44_mpeg_oclass;
+extern struct nvkm_oclass nv50_mpeg_oclass;
+extern struct nvkm_oclass g84_mpeg_oclass;
+extern struct nvkm_ofuncs nv31_mpeg_ofuncs;
+extern struct nvkm_oclass nv31_mpeg_cclass;
+extern struct nvkm_oclass nv31_mpeg_sclass[];
+extern struct nvkm_oclass nv40_mpeg_sclass[];
+void nv31_mpeg_intr(struct nvkm_subdev *);
+void nv31_mpeg_tile_prog(struct nvkm_engine *, int);
+int nv31_mpeg_init(struct nvkm_object *);
+
+extern struct nvkm_ofuncs nv50_mpeg_ofuncs;
+int nv50_mpeg_context_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nv50_mpeg_intr(struct nvkm_subdev *);
+int nv50_mpeg_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h
new file mode 100644
index 000000000000..54b7672eed9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/mspdec.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_MSPDEC_H__
+#define __NVKM_MSPDEC_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_mspdec_oclass;
+extern struct nvkm_oclass gf100_mspdec_oclass;
+extern struct nvkm_oclass gk104_mspdec_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h
new file mode 100644
index 000000000000..c6c69d0a8d01
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/msppp.h
@@ -0,0 +1,6 @@
+#ifndef __NVKM_MSPPP_H__
+#define __NVKM_MSPPP_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_msppp_oclass;
+extern struct nvkm_oclass gf100_msppp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h
new file mode 100644
index 000000000000..1f193b7bd6c5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/msvld.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_MSVLD_H__
+#define __NVKM_MSVLD_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_msvld_oclass;
+extern struct nvkm_oclass gf100_msvld_oclass;
+extern struct nvkm_oclass gk104_msvld_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h
new file mode 100644
index 000000000000..93181bbf0f63
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/pm.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_PM_H__
+#define __NVKM_PM_H__
+#include <core/engine.h>
+
+struct nvkm_perfdom;
+struct nvkm_perfctr;
+struct nvkm_pm {
+ struct nvkm_engine base;
+
+ struct nvkm_perfctx *context;
+ void *profile_data;
+
+ struct list_head domains;
+ u32 sequence;
+
+ /*XXX: temp for daemon backend */
+ u32 pwr[8];
+ u32 last;
+};
+
+static inline struct nvkm_pm *
+nvkm_pm(void *obj)
+{
+ return (void *)nvkm_engine(obj, NVDEV_ENGINE_PM);
+}
+
+extern struct nvkm_oclass *nv40_pm_oclass;
+extern struct nvkm_oclass *nv50_pm_oclass;
+extern struct nvkm_oclass *g84_pm_oclass;
+extern struct nvkm_oclass *gt215_pm_oclass;
+extern struct nvkm_oclass gf100_pm_oclass;
+extern struct nvkm_oclass gk104_pm_oclass;
+extern struct nvkm_oclass gk110_pm_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h
new file mode 100644
index 000000000000..44590a2a479d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sec.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_SEC_H__
+#define __NVKM_SEC_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g98_sec_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h
new file mode 100644
index 000000000000..a529013c92ab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/sw.h
@@ -0,0 +1,50 @@
+#ifndef __NVKM_SW_H__
+#define __NVKM_SW_H__
+#include <core/engctx.h>
+
+struct nvkm_sw_chan {
+ struct nvkm_engctx base;
+
+ int (*flip)(void *);
+ void *flip_data;
+};
+
+#define nvkm_sw_context_create(p,e,c,d) \
+ nvkm_engctx_create((p), (e), (c), (p), 0, 0, 0, (d))
+#define nvkm_sw_context_destroy(d) \
+ nvkm_engctx_destroy(&(d)->base)
+#define nvkm_sw_context_init(d) \
+ nvkm_engctx_init(&(d)->base)
+#define nvkm_sw_context_fini(d,s) \
+ nvkm_engctx_fini(&(d)->base, (s))
+
+#define _nvkm_sw_context_dtor _nvkm_engctx_dtor
+#define _nvkm_sw_context_init _nvkm_engctx_init
+#define _nvkm_sw_context_fini _nvkm_engctx_fini
+
+#include <core/engine.h>
+
+struct nvkm_sw {
+ struct nvkm_engine base;
+};
+
+#define nvkm_sw_create(p,e,c,d) \
+ nvkm_engine_create((p), (e), (c), true, "SW", "software", (d))
+#define nvkm_sw_destroy(d) \
+ nvkm_engine_destroy(&(d)->base)
+#define nvkm_sw_init(d) \
+ nvkm_engine_init(&(d)->base)
+#define nvkm_sw_fini(d,s) \
+ nvkm_engine_fini(&(d)->base, (s))
+
+#define _nvkm_sw_dtor _nvkm_engine_dtor
+#define _nvkm_sw_init _nvkm_engine_init
+#define _nvkm_sw_fini _nvkm_engine_fini
+
+extern struct nvkm_oclass *nv04_sw_oclass;
+extern struct nvkm_oclass *nv10_sw_oclass;
+extern struct nvkm_oclass *nv50_sw_oclass;
+extern struct nvkm_oclass *gf100_sw_oclass;
+
+void nv04_sw_intr(struct nvkm_subdev *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h
new file mode 100644
index 000000000000..7851f18c5add
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/vp.h
@@ -0,0 +1,5 @@
+#ifndef __NVKM_VP_H__
+#define __NVKM_VP_H__
+#include <core/engine.h>
+extern struct nvkm_oclass g84_vp_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h
new file mode 100644
index 000000000000..7a216cca2865
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/engine/xtensa.h
@@ -0,0 +1,35 @@
+#ifndef __NVKM_XTENSA_H__
+#define __NVKM_XTENSA_H__
+#include <core/engine.h>
+struct nvkm_gpuobj;
+
+struct nvkm_xtensa {
+ struct nvkm_engine base;
+
+ u32 addr;
+ struct nvkm_gpuobj *gpu_fw;
+ u32 fifo_val;
+ u32 unkd28;
+};
+
+#define nvkm_xtensa_create(p,e,c,b,d,i,f,r) \
+ nvkm_xtensa_create_((p), (e), (c), (b), (d), (i), (f), \
+ sizeof(**r),(void **)r)
+
+int _nvkm_xtensa_engctx_ctor(struct nvkm_object *,
+ struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+void _nvkm_xtensa_intr(struct nvkm_subdev *);
+int nvkm_xtensa_create_(struct nvkm_object *,
+ struct nvkm_object *,
+ struct nvkm_oclass *, u32, bool,
+ const char *, const char *,
+ int, void **);
+#define _nvkm_xtensa_dtor _nvkm_engine_dtor
+int _nvkm_xtensa_init(struct nvkm_object *);
+int _nvkm_xtensa_fini(struct nvkm_object *, bool);
+u32 _nvkm_xtensa_rd32(struct nvkm_object *, u64);
+void _nvkm_xtensa_wr32(struct nvkm_object *, u64, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
new file mode 100644
index 000000000000..c7a007b8bc10
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bar.h
@@ -0,0 +1,33 @@
+#ifndef __NVKM_BAR_H__
+#define __NVKM_BAR_H__
+#include <core/subdev.h>
+struct nvkm_mem;
+struct nvkm_vma;
+
+struct nvkm_bar {
+ struct nvkm_subdev base;
+
+ int (*alloc)(struct nvkm_bar *, struct nvkm_object *,
+ struct nvkm_mem *, struct nvkm_object **);
+
+ int (*kmap)(struct nvkm_bar *, struct nvkm_mem *, u32 flags,
+ struct nvkm_vma *);
+ int (*umap)(struct nvkm_bar *, struct nvkm_mem *, u32 flags,
+ struct nvkm_vma *);
+ void (*unmap)(struct nvkm_bar *, struct nvkm_vma *);
+ void (*flush)(struct nvkm_bar *);
+
+ /* whether the BAR supports to be ioremapped WC or should be uncached */
+ bool iomap_uncached;
+};
+
+static inline struct nvkm_bar *
+nvkm_bar(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_BAR);
+}
+
+extern struct nvkm_oclass nv50_bar_oclass;
+extern struct nvkm_oclass gf100_bar_oclass;
+extern struct nvkm_oclass gk20a_bar_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
new file mode 100644
index 000000000000..cef287e0bbf2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_BIOS_H__
+#define __NVKM_BIOS_H__
+#include <core/subdev.h>
+
+struct nvkm_bios {
+ struct nvkm_subdev base;
+ u32 size;
+ u8 *data;
+
+ u32 bmp_offset;
+ u32 bit_offset;
+
+ struct {
+ u8 major;
+ u8 chip;
+ u8 minor;
+ u8 micro;
+ u8 patch;
+ } version;
+};
+
+static inline struct nvkm_bios *
+nvkm_bios(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_VBIOS);
+}
+
+u8 nvbios_checksum(const u8 *data, int size);
+u16 nvbios_findstr(const u8 *data, int size, const char *str, int len);
+
+extern struct nvkm_oclass nvkm_bios_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h
new file mode 100644
index 000000000000..cf202c793a1d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0203.h
@@ -0,0 +1,29 @@
+#ifndef __NVBIOS_M0203_H__
+#define __NVBIOS_M0203_H__
+struct nvbios_M0203T {
+#define M0203T_TYPE_RAMCFG 0x00
+ u8 type;
+ u16 pointer;
+};
+
+u32 nvbios_M0203Te(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0203Tp(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_M0203T *);
+
+struct nvbios_M0203E {
+#define M0203E_TYPE_DDR2 0x0
+#define M0203E_TYPE_DDR3 0x1
+#define M0203E_TYPE_GDDR3 0x2
+#define M0203E_TYPE_GDDR5 0x3
+#define M0203E_TYPE_SKIP 0xf
+ u8 type;
+ u8 strap;
+ u8 group;
+};
+
+u32 nvbios_M0203Ee(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0203Ep(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_M0203E *);
+u32 nvbios_M0203Em(struct nvkm_bios *, u8 ramcfg, u8 *ver, u8 *hdr,
+ struct nvbios_M0203E *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h
new file mode 100644
index 000000000000..d34608ff241e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0205.h
@@ -0,0 +1,29 @@
+#ifndef __NVBIOS_M0205_H__
+#define __NVBIOS_M0205_H__
+struct nvbios_M0205T {
+ u16 freq;
+};
+
+u32 nvbios_M0205Te(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u32 nvbios_M0205Tp(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
+ struct nvbios_M0205T *);
+
+struct nvbios_M0205E {
+ u8 type;
+};
+
+u32 nvbios_M0205Ee(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0205Ep(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_M0205E *);
+
+struct nvbios_M0205S {
+ u8 data;
+};
+
+u32 nvbios_M0205Se(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0205Sp(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_M0205S *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h
new file mode 100644
index 000000000000..c7ff8d9526e7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/M0209.h
@@ -0,0 +1,27 @@
+#ifndef __NVBIOS_M0209_H__
+#define __NVBIOS_M0209_H__
+u32 nvbios_M0209Te(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+struct nvbios_M0209E {
+ u8 v00_40;
+ u8 bits;
+ u8 modulo;
+ u8 v02_40;
+ u8 v02_07;
+ u8 v03;
+};
+
+u32 nvbios_M0209Ee(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_M0209Ep(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_M0209E *);
+
+struct nvbios_M0209S {
+ u32 data[0x200];
+};
+
+u32 nvbios_M0209Se(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_M0209Sp(struct nvkm_bios *, int ent, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_M0209S *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h
new file mode 100644
index 000000000000..1c1c52eac97d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/P0260.h
@@ -0,0 +1,21 @@
+#ifndef __NVBIOS_P0260_H__
+#define __NVBIOS_P0260_H__
+u32 nvbios_P0260Te(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
+
+struct nvbios_P0260E {
+ u32 data;
+};
+
+u32 nvbios_P0260Ee(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_P0260Ep(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_P0260E *);
+
+struct nvbios_P0260X {
+ u32 data;
+};
+
+u32 nvbios_P0260Xe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_P0260Xp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_P0260X *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h
new file mode 100644
index 000000000000..6711732b7cb1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bit.h
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_BIT_H__
+#define __NVBIOS_BIT_H__
+struct bit_entry {
+ u8 id;
+ u8 version;
+ u16 length;
+ u16 offset;
+};
+
+int bit_entry(struct nvkm_bios *, u8 id, struct bit_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h
new file mode 100644
index 000000000000..4107aa546a21
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/bmp.h
@@ -0,0 +1,37 @@
+#ifndef __NVBIOS_BMP_H__
+#define __NVBIOS_BMP_H__
+static inline u16
+bmp_version(struct nvkm_bios *bios)
+{
+ if (bios->bmp_offset) {
+ return nv_ro08(bios, bios->bmp_offset + 5) << 8 |
+ nv_ro08(bios, bios->bmp_offset + 6);
+ }
+
+ return 0x0000;
+}
+
+static inline u16
+bmp_mem_init_table(struct nvkm_bios *bios)
+{
+ if (bmp_version(bios) >= 0x0300)
+ return nv_ro16(bios, bios->bmp_offset + 24);
+ return 0x0000;
+}
+
+static inline u16
+bmp_sdr_seq_table(struct nvkm_bios *bios)
+{
+ if (bmp_version(bios) >= 0x0300)
+ return nv_ro16(bios, bios->bmp_offset + 26);
+ return 0x0000;
+}
+
+static inline u16
+bmp_ddr_seq_table(struct nvkm_bios *bios)
+{
+ if (bmp_version(bios) >= 0x0300)
+ return nv_ro16(bios, bios->bmp_offset + 28);
+ return 0x0000;
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h
new file mode 100644
index 000000000000..934b0ae5521d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/boost.h
@@ -0,0 +1,27 @@
+#ifndef __NVBIOS_BOOST_H__
+#define __NVBIOS_BOOST_H__
+u16 nvbios_boostTe(struct nvkm_bios *, u8 *, u8 *, u8 *, u8 *, u8 *, u8 *);
+
+struct nvbios_boostE {
+ u8 pstate;
+ u32 min;
+ u32 max;
+};
+
+u16 nvbios_boostEe(struct nvkm_bios *, int idx, u8 *, u8 *, u8 *, u8 *);
+u16 nvbios_boostEp(struct nvkm_bios *, int idx, u8 *, u8 *, u8 *, u8 *,
+ struct nvbios_boostE *);
+u16 nvbios_boostEm(struct nvkm_bios *, u8, u8 *, u8 *, u8 *, u8 *,
+ struct nvbios_boostE *);
+
+struct nvbios_boostS {
+ u8 domain;
+ u8 percent;
+ u32 min;
+ u32 max;
+};
+
+u16 nvbios_boostSe(struct nvkm_bios *, int, u16, u8 *, u8 *, u8, u8);
+u16 nvbios_boostSp(struct nvkm_bios *, int, u16, u8 *, u8 *, u8, u8,
+ struct nvbios_boostS *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
new file mode 100644
index 000000000000..e8e77ee24776
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/conn.h
@@ -0,0 +1,44 @@
+#ifndef __NVBIOS_CONN_H__
+#define __NVBIOS_CONN_H__
+enum dcb_connector_type {
+ DCB_CONNECTOR_VGA = 0x00,
+ DCB_CONNECTOR_TV_0 = 0x10,
+ DCB_CONNECTOR_TV_1 = 0x11,
+ DCB_CONNECTOR_TV_3 = 0x13,
+ DCB_CONNECTOR_DVI_I = 0x30,
+ DCB_CONNECTOR_DVI_D = 0x31,
+ DCB_CONNECTOR_DMS59_0 = 0x38,
+ DCB_CONNECTOR_DMS59_1 = 0x39,
+ DCB_CONNECTOR_LVDS = 0x40,
+ DCB_CONNECTOR_LVDS_SPWG = 0x41,
+ DCB_CONNECTOR_DP = 0x46,
+ DCB_CONNECTOR_eDP = 0x47,
+ DCB_CONNECTOR_HDMI_0 = 0x60,
+ DCB_CONNECTOR_HDMI_1 = 0x61,
+ DCB_CONNECTOR_HDMI_C = 0x63,
+ DCB_CONNECTOR_DMS59_DP0 = 0x64,
+ DCB_CONNECTOR_DMS59_DP1 = 0x65,
+ DCB_CONNECTOR_NONE = 0xff
+};
+
+struct nvbios_connT {
+};
+
+u32 nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_connTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_connT *info);
+
+struct nvbios_connE {
+ u8 type;
+ u8 location;
+ u8 hpd;
+ u8 dp;
+ u8 di;
+ u8 sr;
+ u8 lcdid;
+};
+
+u32 nvbios_connEe(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *hdr);
+u32 nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *hdr,
+ struct nvbios_connE *info);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h
new file mode 100644
index 000000000000..2f0e0c8e83be
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/cstep.h
@@ -0,0 +1,26 @@
+#ifndef __NVBIOS_CSTEP_H__
+#define __NVBIOS_CSTEP_H__
+u16 nvbios_cstepTe(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz);
+
+struct nvbios_cstepE {
+ u8 pstate;
+ u8 index;
+};
+
+u16 nvbios_cstepEe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u16 nvbios_cstepEp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_cstepE *);
+u16 nvbios_cstepEm(struct nvkm_bios *, u8 pstate, u8 *ver, u8 *hdr,
+ struct nvbios_cstepE *);
+
+struct nvbios_cstepX {
+ u32 freq;
+ u8 unkn[2];
+ u8 voltage;
+};
+
+u16 nvbios_cstepXe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u16 nvbios_cstepXp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_cstepX *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h
new file mode 100644
index 000000000000..4892a65ddd48
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dcb.h
@@ -0,0 +1,65 @@
+#ifndef __NVBIOS_DCB_H__
+#define __NVBIOS_DCB_H__
+enum dcb_output_type {
+ DCB_OUTPUT_ANALOG = 0x0,
+ DCB_OUTPUT_TV = 0x1,
+ DCB_OUTPUT_TMDS = 0x2,
+ DCB_OUTPUT_LVDS = 0x3,
+ DCB_OUTPUT_DP = 0x6,
+ DCB_OUTPUT_EOL = 0xe,
+ DCB_OUTPUT_UNUSED = 0xf,
+ DCB_OUTPUT_ANY = -1,
+};
+
+struct dcb_output {
+ int index; /* may not be raw dcb index if merging has happened */
+ u16 hasht;
+ u16 hashm;
+ enum dcb_output_type type;
+ uint8_t i2c_index;
+ uint8_t heads;
+ uint8_t connector;
+ uint8_t bus;
+ uint8_t location;
+ uint8_t or;
+ uint8_t link;
+ bool duallink_possible;
+ uint8_t extdev;
+ union {
+ struct sor_conf {
+ int link;
+ } sorconf;
+ struct {
+ int maxfreq;
+ } crtconf;
+ struct {
+ struct sor_conf sor;
+ bool use_straps_for_mode;
+ bool use_acpi_for_edid;
+ bool use_power_scripts;
+ } lvdsconf;
+ struct {
+ bool has_component_output;
+ } tvconf;
+ struct {
+ struct sor_conf sor;
+ int link_nr;
+ int link_bw;
+ } dpconf;
+ struct {
+ struct sor_conf sor;
+ int slave_addr;
+ } tmdsconf;
+ };
+ bool i2c_upper_default;
+};
+
+u16 dcb_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *ent, u8 *len);
+u16 dcb_outp(struct nvkm_bios *, u8 idx, u8 *ver, u8 *len);
+u16 dcb_outp_parse(struct nvkm_bios *, u8 idx, u8 *, u8 *,
+ struct dcb_output *);
+u16 dcb_outp_match(struct nvkm_bios *, u16 type, u16 mask, u8 *, u8 *,
+ struct dcb_output *);
+int dcb_outp_foreach(struct nvkm_bios *, void *data, int (*exec)
+ (struct nvkm_bios *, void *, int index, u16 entry));
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h
new file mode 100644
index 000000000000..db10c11f0595
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/disp.h
@@ -0,0 +1,39 @@
+#ifndef __NVBIOS_DISP_H__
+#define __NVBIOS_DISP_H__
+u16 nvbios_disp_table(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub);
+
+struct nvbios_disp {
+ u16 data;
+};
+
+u16 nvbios_disp_entry(struct nvkm_bios *, u8 idx, u8 *ver, u8 *hdr, u8 *sub);
+u16 nvbios_disp_parse(struct nvkm_bios *, u8 idx, u8 *ver, u8 *hdr, u8 *sub,
+ struct nvbios_disp *);
+
+struct nvbios_outp {
+ u16 type;
+ u16 mask;
+ u16 script[3];
+};
+
+u16 nvbios_outp_entry(struct nvkm_bios *, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_outp_parse(struct nvkm_bios *, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *);
+u16 nvbios_outp_match(struct nvkm_bios *, u16 type, u16 mask,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *);
+
+struct nvbios_ocfg {
+ u16 match;
+ u16 clkcmp[2];
+};
+
+u16 nvbios_ocfg_entry(struct nvkm_bios *, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_ocfg_parse(struct nvkm_bios *, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *);
+u16 nvbios_ocfg_match(struct nvkm_bios *, u16 outp, u16 type,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *);
+u16 nvbios_oclk_match(struct nvkm_bios *, u16 cmp, u32 khz);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h
new file mode 100644
index 000000000000..b4d39df70d4e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/dp.h
@@ -0,0 +1,31 @@
+#ifndef __NVBIOS_DP_H__
+#define __NVBIOS_DP_H__
+struct nvbios_dpout {
+ u16 type;
+ u16 mask;
+ u8 flags;
+ u32 script[5];
+ u32 lnkcmp;
+};
+
+u16 nvbios_dpout_parse(struct nvkm_bios *, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_dpout *);
+u16 nvbios_dpout_match(struct nvkm_bios *, u16 type, u16 mask,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_dpout *);
+
+struct nvbios_dpcfg {
+ u8 pc;
+ u8 dc;
+ u8 pe;
+ u8 tx_pu;
+};
+
+u16
+nvbios_dpcfg_parse(struct nvkm_bios *, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *);
+u16
+nvbios_dpcfg_match(struct nvkm_bios *, u16 outp, u8 pc, u8 vs, u8 pe,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_dpcfg *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h
new file mode 100644
index 000000000000..6d3bedc633b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/extdev.h
@@ -0,0 +1,25 @@
+#ifndef __NVBIOS_EXTDEV_H__
+#define __NVBIOS_EXTDEV_H__
+enum nvbios_extdev_type {
+ NVBIOS_EXTDEV_LM89 = 0x02,
+ NVBIOS_EXTDEV_VT1103M = 0x40,
+ NVBIOS_EXTDEV_PX3540 = 0x41,
+ NVBIOS_EXTDEV_VT1105M = 0x42, /* or close enough... */
+ NVBIOS_EXTDEV_ADT7473 = 0x70, /* can also be a LM64 */
+ NVBIOS_EXTDEV_HDCP_EEPROM = 0x90,
+ NVBIOS_EXTDEV_NONE = 0xff,
+};
+
+struct nvbios_extdev_func {
+ u8 type;
+ u8 addr;
+ u8 bus;
+};
+
+int
+nvbios_extdev_parse(struct nvkm_bios *, int, struct nvbios_extdev_func *);
+
+int
+nvbios_extdev_find(struct nvkm_bios *, enum nvbios_extdev_type,
+ struct nvbios_extdev_func *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h
new file mode 100644
index 000000000000..693ea7d9ec43
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/fan.h
@@ -0,0 +1,6 @@
+#ifndef __NVBIOS_FAN_H__
+#define __NVBIOS_FAN_H__
+#include <subdev/bios/therm.h>
+
+u16 nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
new file mode 100644
index 000000000000..33be260ddd38
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/gpio.h
@@ -0,0 +1,46 @@
+#ifndef __NVBIOS_GPIO_H__
+#define __NVBIOS_GPIO_H__
+enum dcb_gpio_func_name {
+ DCB_GPIO_PANEL_POWER = 0x01,
+ DCB_GPIO_TVDAC0 = 0x0c,
+ DCB_GPIO_TVDAC1 = 0x2d,
+ DCB_GPIO_FAN = 0x09,
+ DCB_GPIO_FAN_SENSE = 0x3d,
+ DCB_GPIO_UNUSED = 0xff,
+ DCB_GPIO_VID0 = 0x04,
+ DCB_GPIO_VID1 = 0x05,
+ DCB_GPIO_VID2 = 0x06,
+ DCB_GPIO_VID3 = 0x1a,
+ DCB_GPIO_VID4 = 0x73,
+ DCB_GPIO_VID5 = 0x74,
+ DCB_GPIO_VID6 = 0x75,
+ DCB_GPIO_VID7 = 0x76,
+};
+
+#define DCB_GPIO_LOG_DIR 0x02
+#define DCB_GPIO_LOG_DIR_OUT 0x00
+#define DCB_GPIO_LOG_DIR_IN 0x02
+#define DCB_GPIO_LOG_VAL 0x01
+#define DCB_GPIO_LOG_VAL_LO 0x00
+#define DCB_GPIO_LOG_VAL_HI 0x01
+
+struct dcb_gpio_func {
+ u8 func;
+ u8 line;
+ u8 log[2];
+
+ /* so far, "param" seems to only have an influence on PWM-related
+ * GPIOs such as FAN_CONTROL and PANEL_BACKLIGHT_LEVEL.
+ * if param equals 1, hardware PWM is available
+ * if param equals 0, the host should toggle the GPIO itself
+ */
+ u8 param;
+};
+
+u16 dcb_gpio_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_gpio_entry(struct nvkm_bios *, int idx, int ent, u8 *ver, u8 *len);
+u16 dcb_gpio_parse(struct nvkm_bios *, int idx, int ent, u8 *ver, u8 *len,
+ struct dcb_gpio_func *);
+u16 dcb_gpio_match(struct nvkm_bios *, int idx, u8 func, u8 line,
+ u8 *ver, u8 *len, struct dcb_gpio_func *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h
new file mode 100644
index 000000000000..85c529ecf9b1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/i2c.h
@@ -0,0 +1,25 @@
+#ifndef __NVBIOS_I2C_H__
+#define __NVBIOS_I2C_H__
+enum dcb_i2c_type {
+ /* matches bios type field prior to ccb 4.1 */
+ DCB_I2C_NV04_BIT = 0x00,
+ DCB_I2C_NV4E_BIT = 0x04,
+ DCB_I2C_NVIO_BIT = 0x05,
+ DCB_I2C_NVIO_AUX = 0x06,
+ /* made up - mostly */
+ DCB_I2C_PMGR = 0x80,
+ DCB_I2C_UNUSED = 0xff
+};
+
+struct dcb_i2c_entry {
+ enum dcb_i2c_type type;
+ u8 drive;
+ u8 sense;
+ u8 share;
+ u8 auxch;
+};
+
+u16 dcb_i2c_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_i2c_entry(struct nvkm_bios *, u8 index, u8 *ver, u8 *len);
+int dcb_i2c_parse(struct nvkm_bios *, u8 index, struct dcb_i2c_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h
new file mode 100644
index 000000000000..e15d63b9a5eb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/image.h
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_IMAGE_H__
+#define __NVBIOS_IMAGE_H__
+struct nvbios_image {
+ u32 base;
+ u32 size;
+ u8 type;
+ bool last;
+};
+
+bool nvbios_image(struct nvkm_bios *, int, struct nvbios_image *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
new file mode 100644
index 000000000000..578a667eed3b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/init.h
@@ -0,0 +1,20 @@
+#ifndef __NVBIOS_INIT_H__
+#define __NVBIOS_INIT_H__
+struct nvbios_init {
+ struct nvkm_subdev *subdev;
+ struct nvkm_bios *bios;
+ u16 offset;
+ struct dcb_output *outp;
+ int crtc;
+
+ /* internal state used during parsing */
+ u8 execute;
+ u32 nested;
+ u16 repeat;
+ u16 repend;
+ u32 ramcfg;
+};
+
+int nvbios_exec(struct nvbios_init *);
+int nvbios_init(struct nvkm_subdev *, bool execute);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h
new file mode 100644
index 000000000000..4e31b64c5edf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/mxm.h
@@ -0,0 +1,6 @@
+#ifndef __NVBIOS_MXM_H__
+#define __NVBIOS_MXM_H__
+u16 mxm_table(struct nvkm_bios *, u8 *ver, u8 *hdr);
+u8 mxm_sor_map(struct nvkm_bios *, u8 conn);
+u8 mxm_ddc_map(struct nvkm_bios *, u8 port);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h
new file mode 100644
index 000000000000..64a59549b7ea
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/npde.h
@@ -0,0 +1,10 @@
+#ifndef __NVBIOS_NPDE_H__
+#define __NVBIOS_NPDE_H__
+struct nvbios_npdeT {
+ u32 image_size;
+ bool last;
+};
+
+u32 nvbios_npdeTe(struct nvkm_bios *, u32);
+u32 nvbios_npdeTp(struct nvkm_bios *, u32, struct nvbios_npdeT *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h
new file mode 100644
index 000000000000..e85931541f4f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pcir.h
@@ -0,0 +1,16 @@
+#ifndef __NVBIOS_PCIR_H__
+#define __NVBIOS_PCIR_H__
+struct nvbios_pcirT {
+ u16 vendor_id;
+ u16 device_id;
+ u8 class_code[3];
+ u32 image_size;
+ u16 image_rev;
+ u8 image_type;
+ bool last;
+};
+
+u32 nvbios_pcirTe(struct nvkm_bios *, u32, u8 *ver, u16 *hdr);
+u32 nvbios_pcirTp(struct nvkm_bios *, u32, u8 *ver, u16 *hdr,
+ struct nvbios_pcirT *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
new file mode 100644
index 000000000000..7cc2becabc69
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/perf.h
@@ -0,0 +1,41 @@
+#ifndef __NVBIOS_PERF_H__
+#define __NVBIOS_PERF_H__
+u16 nvbios_perf_table(struct nvkm_bios *, u8 *ver, u8 *hdr,
+ u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+struct nvbios_perfE {
+ u8 pstate;
+ u8 fanspeed;
+ u8 voltage;
+ u32 core;
+ u32 shader;
+ u32 memory;
+ u32 vdec;
+ u32 disp;
+ u32 script;
+};
+
+u16 nvbios_perf_entry(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_perfEp(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *);
+
+struct nvbios_perfS {
+ union {
+ struct {
+ u32 freq;
+ } v40;
+ };
+};
+
+u32 nvbios_perfSe(struct nvkm_bios *, u32 data, int idx,
+ u8 *ver, u8 *hdr, u8 cnt, u8 len);
+u32 nvbios_perfSp(struct nvkm_bios *, u32 data, int idx,
+ u8 *ver, u8 *hdr, u8 cnt, u8 len, struct nvbios_perfS *);
+
+struct nvbios_perf_fan {
+ u32 pwm_divisor;
+};
+
+int nvbios_perf_fan_parse(struct nvkm_bios *, struct nvbios_perf_fan *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h
new file mode 100644
index 000000000000..5a69978d1e3b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pll.h
@@ -0,0 +1,75 @@
+#ifndef __NVBIOS_PLL_H__
+#define __NVBIOS_PLL_H__
+/*XXX: kill me */
+struct nvkm_pll_vals {
+ union {
+ struct {
+#ifdef __BIG_ENDIAN
+ uint8_t N1, M1, N2, M2;
+#else
+ uint8_t M1, N1, M2, N2;
+#endif
+ };
+ struct {
+ uint16_t NM1, NM2;
+ } __attribute__((packed));
+ };
+ int log2P;
+
+ int refclk;
+};
+
+/* these match types in pll limits table version 0x40,
+ * nvkm uses them on all chipsets internally where a
+ * specific pll needs to be referenced, but the exact
+ * register isn't known.
+ */
+enum nvbios_pll_type {
+ PLL_CORE = 0x01,
+ PLL_SHADER = 0x02,
+ PLL_UNK03 = 0x03,
+ PLL_MEMORY = 0x04,
+ PLL_VDEC = 0x05,
+ PLL_UNK40 = 0x40,
+ PLL_UNK41 = 0x41,
+ PLL_UNK42 = 0x42,
+ PLL_VPLL0 = 0x80,
+ PLL_VPLL1 = 0x81,
+ PLL_VPLL2 = 0x82,
+ PLL_VPLL3 = 0x83,
+ PLL_MAX = 0xff
+};
+
+struct nvbios_pll {
+ enum nvbios_pll_type type;
+ u32 reg;
+ u32 refclk;
+
+ u8 min_p;
+ u8 max_p;
+ u8 bias_p;
+
+ /*
+ * for most pre nv50 cards setting a log2P of 7 (the common max_log2p
+ * value) is no different to 6 (at least for vplls) so allowing the MNP
+ * calc to use 7 causes the generated clock to be out by a factor of 2.
+ * however, max_log2p cannot be fixed-up during parsing as the
+ * unmodified max_log2p value is still needed for setting mplls, hence
+ * an additional max_usable_log2p member
+ */
+ u8 max_p_usable;
+
+ struct {
+ u32 min_freq;
+ u32 max_freq;
+ u32 min_inputfreq;
+ u32 max_inputfreq;
+ u8 min_m;
+ u8 max_m;
+ u8 min_n;
+ u8 max_n;
+ } vco1, vco2;
+};
+
+int nvbios_pll_parse(struct nvkm_bios *, u32 type, struct nvbios_pll *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h
new file mode 100644
index 000000000000..d606875c125a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/pmu.h
@@ -0,0 +1,35 @@
+#ifndef __NVBIOS_PMU_H__
+#define __NVBIOS_PMU_H__
+struct nvbios_pmuT {
+};
+
+u32 nvbios_pmuTe(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_pmuTp(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_pmuT *);
+
+struct nvbios_pmuE {
+ u8 type;
+ u32 data;
+};
+
+u32 nvbios_pmuEe(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr);
+u32 nvbios_pmuEp(struct nvkm_bios *, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_pmuE *);
+
+struct nvbios_pmuR {
+ u32 boot_addr_pmu;
+ u32 boot_addr;
+ u32 boot_size;
+ u32 code_addr_pmu;
+ u32 code_addr;
+ u32 code_size;
+ u32 init_addr_pmu;
+
+ u32 data_addr_pmu;
+ u32 data_addr;
+ u32 data_size;
+ u32 args_addr_pmu;
+};
+
+bool nvbios_pmuRm(struct nvkm_bios *, u8 type, struct nvbios_pmuR *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h
new file mode 100644
index 000000000000..420426793880
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/ramcfg.h
@@ -0,0 +1,141 @@
+#ifndef __NVBIOS_RAMCFG_H__
+#define __NVBIOS_RAMCFG_H__
+struct nvbios_ramcfg {
+ unsigned rammap_ver;
+ unsigned rammap_hdr;
+ unsigned rammap_min;
+ unsigned rammap_max;
+ union {
+ struct {
+ unsigned rammap_10_04_02:1;
+ unsigned rammap_10_04_08:1;
+ };
+ struct {
+ unsigned rammap_11_08_01:1;
+ unsigned rammap_11_08_0c:2;
+ unsigned rammap_11_08_10:1;
+ unsigned rammap_11_09_01ff:9;
+ unsigned rammap_11_0a_03fe:9;
+ unsigned rammap_11_0a_0400:1;
+ unsigned rammap_11_0a_0800:1;
+ unsigned rammap_11_0b_01f0:5;
+ unsigned rammap_11_0b_0200:1;
+ unsigned rammap_11_0b_0400:1;
+ unsigned rammap_11_0b_0800:1;
+ unsigned rammap_11_0d:8;
+ unsigned rammap_11_0e:8;
+ unsigned rammap_11_0f:8;
+ unsigned rammap_11_11_0c:2;
+ };
+ };
+
+ unsigned ramcfg_ver;
+ unsigned ramcfg_hdr;
+ unsigned ramcfg_timing;
+ union {
+ struct {
+ unsigned ramcfg_10_02_01:1;
+ unsigned ramcfg_10_02_02:1;
+ unsigned ramcfg_10_02_04:1;
+ unsigned ramcfg_10_02_08:1;
+ unsigned ramcfg_10_02_10:1;
+ unsigned ramcfg_10_02_20:1;
+ unsigned ramcfg_10_DLLoff:1;
+ unsigned ramcfg_10_03_0f:4;
+ unsigned ramcfg_10_04_01:1;
+ unsigned ramcfg_10_05:8;
+ unsigned ramcfg_10_06:8;
+ unsigned ramcfg_10_07:8;
+ unsigned ramcfg_10_08:8;
+ unsigned ramcfg_10_09_0f:4;
+ unsigned ramcfg_10_09_f0:4;
+ };
+ struct {
+ unsigned ramcfg_11_01_01:1;
+ unsigned ramcfg_11_01_02:1;
+ unsigned ramcfg_11_01_04:1;
+ unsigned ramcfg_11_01_08:1;
+ unsigned ramcfg_11_01_10:1;
+ unsigned ramcfg_11_01_20:1;
+ unsigned ramcfg_11_01_40:1;
+ unsigned ramcfg_11_01_80:1;
+ unsigned ramcfg_11_02_03:2;
+ unsigned ramcfg_11_02_04:1;
+ unsigned ramcfg_11_02_08:1;
+ unsigned ramcfg_11_02_10:1;
+ unsigned ramcfg_11_02_40:1;
+ unsigned ramcfg_11_02_80:1;
+ unsigned ramcfg_11_03_0f:4;
+ unsigned ramcfg_11_03_30:2;
+ unsigned ramcfg_11_03_c0:2;
+ unsigned ramcfg_11_03_f0:4;
+ unsigned ramcfg_11_04:8;
+ unsigned ramcfg_11_06:8;
+ unsigned ramcfg_11_07_02:1;
+ unsigned ramcfg_11_07_04:1;
+ unsigned ramcfg_11_07_08:1;
+ unsigned ramcfg_11_07_10:1;
+ unsigned ramcfg_11_07_40:1;
+ unsigned ramcfg_11_07_80:1;
+ unsigned ramcfg_11_08_01:1;
+ unsigned ramcfg_11_08_02:1;
+ unsigned ramcfg_11_08_04:1;
+ unsigned ramcfg_11_08_08:1;
+ unsigned ramcfg_11_08_10:1;
+ unsigned ramcfg_11_08_20:1;
+ unsigned ramcfg_11_09:8;
+ };
+ };
+
+ unsigned timing_ver;
+ unsigned timing_hdr;
+ unsigned timing[11];
+ union {
+ struct {
+ unsigned timing_10_WR:8;
+ unsigned timing_10_WTR:8;
+ unsigned timing_10_CL:8;
+ unsigned timing_10_RC:8;
+ /*empty: 4 */
+ unsigned timing_10_RFC:8; /* Byte 5 */
+ /*empty: 6 */
+ unsigned timing_10_RAS:8; /* Byte 7 */
+ /*empty: 8 */
+ unsigned timing_10_RP:8; /* Byte 9 */
+ unsigned timing_10_RCDRD:8;
+ unsigned timing_10_RCDWR:8;
+ unsigned timing_10_RRD:8;
+ unsigned timing_10_13:8;
+ unsigned timing_10_ODT:3;
+ /* empty: 15 */
+ unsigned timing_10_16:8;
+ /* empty: 17 */
+ unsigned timing_10_18:8;
+ unsigned timing_10_CWL:8;
+ unsigned timing_10_20:8;
+ unsigned timing_10_21:8;
+ /* empty: 22, 23 */
+ unsigned timing_10_24:8;
+ };
+ struct {
+ unsigned timing_20_2e_03:2;
+ unsigned timing_20_2e_30:2;
+ unsigned timing_20_2e_c0:2;
+ unsigned timing_20_2f_03:2;
+ unsigned timing_20_2c_003f:6;
+ unsigned timing_20_2c_1fc0:7;
+ unsigned timing_20_30_f8:5;
+ unsigned timing_20_30_07:3;
+ unsigned timing_20_31_0007:3;
+ unsigned timing_20_31_0078:4;
+ unsigned timing_20_31_0780:4;
+ unsigned timing_20_31_0800:1;
+ unsigned timing_20_31_7000:3;
+ unsigned timing_20_31_8000:1;
+ };
+ };
+};
+
+u8 nvbios_ramcfg_count(struct nvkm_bios *);
+u8 nvbios_ramcfg_index(struct nvkm_subdev *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h
new file mode 100644
index 000000000000..609a905ec780
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/rammap.h
@@ -0,0 +1,21 @@
+#ifndef __NVBIOS_RAMMAP_H__
+#define __NVBIOS_RAMMAP_H__
+#include <subdev/bios/ramcfg.h>
+
+u32 nvbios_rammapTe(struct nvkm_bios *, u8 *ver, u8 *hdr,
+ u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+
+u32 nvbios_rammapEe(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u32 nvbios_rammapEp(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *);
+u32 nvbios_rammapEm(struct nvkm_bios *, u16 mhz,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *);
+
+u32 nvbios_rammapSe(struct nvkm_bios *, u32 data,
+ u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+ u8 *ver, u8 *hdr);
+u32 nvbios_rammapSp(struct nvkm_bios *, u32 data,
+ u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+ u8 *ver, u8 *hdr, struct nvbios_ramcfg *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h
new file mode 100644
index 000000000000..dd3ba960e75d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/therm.h
@@ -0,0 +1,72 @@
+#ifndef __NVBIOS_THERM_H__
+#define __NVBIOS_THERM_H__
+struct nvbios_therm_threshold {
+ u8 temp;
+ u8 hysteresis;
+};
+
+struct nvbios_therm_sensor {
+ /* diode */
+ s16 slope_mult;
+ s16 slope_div;
+ s16 offset_num;
+ s16 offset_den;
+ s8 offset_constant;
+
+ /* thresholds */
+ struct nvbios_therm_threshold thrs_fan_boost;
+ struct nvbios_therm_threshold thrs_down_clock;
+ struct nvbios_therm_threshold thrs_critical;
+ struct nvbios_therm_threshold thrs_shutdown;
+};
+
+enum nvbios_therm_fan_type {
+ NVBIOS_THERM_FAN_UNK = 0,
+ NVBIOS_THERM_FAN_TOGGLE = 1,
+ NVBIOS_THERM_FAN_PWM = 2,
+};
+
+/* no vbios have more than 6 */
+#define NVKM_TEMP_FAN_TRIP_MAX 10
+struct nvbios_therm_trip_point {
+ int fan_duty;
+ int temp;
+ int hysteresis;
+};
+
+enum nvbios_therm_fan_mode {
+ NVBIOS_THERM_FAN_TRIP = 0,
+ NVBIOS_THERM_FAN_LINEAR = 1,
+ NVBIOS_THERM_FAN_OTHER = 2,
+};
+
+struct nvbios_therm_fan {
+ enum nvbios_therm_fan_type type;
+
+ u32 pwm_freq;
+
+ u8 min_duty;
+ u8 max_duty;
+
+ u16 bump_period;
+ u16 slow_down_period;
+
+ enum nvbios_therm_fan_mode fan_mode;
+ struct nvbios_therm_trip_point trip[NVKM_TEMP_FAN_TRIP_MAX];
+ u8 nr_fan_trip;
+ u8 linear_min_temp;
+ u8 linear_max_temp;
+};
+
+enum nvbios_therm_domain {
+ NVBIOS_THERM_DOMAIN_CORE,
+ NVBIOS_THERM_DOMAIN_AMBIENT,
+};
+
+int
+nvbios_therm_sensor_parse(struct nvkm_bios *, enum nvbios_therm_domain,
+ struct nvbios_therm_sensor *);
+
+int
+nvbios_therm_fan_parse(struct nvkm_bios *, struct nvbios_therm_fan *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h
new file mode 100644
index 000000000000..339a826aa176
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/timing.h
@@ -0,0 +1,11 @@
+#ifndef __NVBIOS_TIMING_H__
+#define __NVBIOS_TIMING_H__
+#include <subdev/bios/ramcfg.h>
+
+u16 nvbios_timingTe(struct nvkm_bios *,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz);
+u16 nvbios_timingEe(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_timingEp(struct nvkm_bios *, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
new file mode 100644
index 000000000000..6633c6db9281
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/vmap.h
@@ -0,0 +1,21 @@
+#ifndef __NVBIOS_VMAP_H__
+#define __NVBIOS_VMAP_H__
+struct nvbios_vmap {
+};
+
+u16 nvbios_vmap_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_vmap_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_vmap *);
+
+struct nvbios_vmap_entry {
+ u8 unk0;
+ u8 link;
+ u32 min;
+ u32 max;
+ s32 arg[6];
+};
+
+u16 nvbios_vmap_entry(struct nvkm_bios *, int idx, u8 *ver, u8 *len);
+u16 nvbios_vmap_entry_parse(struct nvkm_bios *, int idx, u8 *ver, u8 *len,
+ struct nvbios_vmap_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
new file mode 100644
index 000000000000..eb2de4b85bbd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/volt.h
@@ -0,0 +1,23 @@
+#ifndef __NVBIOS_VOLT_H__
+#define __NVBIOS_VOLT_H__
+struct nvbios_volt {
+ u8 vidmask;
+ u32 min;
+ u32 max;
+ u32 base;
+ s16 step;
+};
+
+u16 nvbios_volt_table(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 nvbios_volt_parse(struct nvkm_bios *, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_volt *);
+
+struct nvbios_volt_entry {
+ u32 voltage;
+ u8 vid;
+};
+
+u16 nvbios_volt_entry(struct nvkm_bios *, int idx, u8 *ver, u8 *len);
+u16 nvbios_volt_entry_parse(struct nvkm_bios *, int idx, u8 *ver, u8 *len,
+ struct nvbios_volt_entry *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h
new file mode 100644
index 000000000000..0c0fe234ff12
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bios/xpio.h
@@ -0,0 +1,18 @@
+#ifndef __NVBIOS_XPIO_H__
+#define __NVBIOS_XPIO_H__
+
+#define NVBIOS_XPIO_FLAG_AUX 0x10
+#define NVBIOS_XPIO_FLAG_AUX0 0x00
+#define NVBIOS_XPIO_FLAG_AUX1 0x10
+
+struct nvbios_xpio {
+ u8 type;
+ u8 addr;
+ u8 flags;
+};
+
+u16 dcb_xpio_table(struct nvkm_bios *, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len);
+u16 dcb_xpio_parse(struct nvkm_bios *, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h
new file mode 100644
index 000000000000..fba83c04849e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/bus.h
@@ -0,0 +1,50 @@
+#ifndef __NVKM_BUS_H__
+#define __NVKM_BUS_H__
+#include <core/subdev.h>
+
+struct nvkm_bus_intr {
+ u32 stat;
+ u32 unit;
+};
+
+struct nvkm_bus {
+ struct nvkm_subdev base;
+ int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32);
+ u32 hwsq_size;
+};
+
+static inline struct nvkm_bus *
+nvkm_bus(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_BUS);
+}
+
+#define nvkm_bus_create(p, e, o, d) \
+ nvkm_subdev_create_((p), (e), (o), 0, "PBUS", "master", \
+ sizeof(**d), (void **)d)
+#define nvkm_bus_destroy(p) \
+ nvkm_subdev_destroy(&(p)->base)
+#define nvkm_bus_init(p) \
+ nvkm_subdev_init(&(p)->base)
+#define nvkm_bus_fini(p, s) \
+ nvkm_subdev_fini(&(p)->base, (s))
+
+#define _nvkm_bus_dtor _nvkm_subdev_dtor
+#define _nvkm_bus_init _nvkm_subdev_init
+#define _nvkm_bus_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass *nv04_bus_oclass;
+extern struct nvkm_oclass *nv31_bus_oclass;
+extern struct nvkm_oclass *nv50_bus_oclass;
+extern struct nvkm_oclass *g94_bus_oclass;
+extern struct nvkm_oclass *gf100_bus_oclass;
+
+/* interface to sequencer */
+struct nvkm_hwsq;
+int nvkm_hwsq_init(struct nvkm_bus *, struct nvkm_hwsq **);
+int nvkm_hwsq_fini(struct nvkm_hwsq **, bool exec);
+void nvkm_hwsq_wr32(struct nvkm_hwsq *, u32 addr, u32 data);
+void nvkm_hwsq_setf(struct nvkm_hwsq *, u8 flag, int data);
+void nvkm_hwsq_wait(struct nvkm_hwsq *, u8 flag, u8 data);
+void nvkm_hwsq_nsec(struct nvkm_hwsq *, u32 nsec);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
new file mode 100644
index 000000000000..f5d303850d8c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/clk.h
@@ -0,0 +1,161 @@
+#ifndef __NVKM_CLK_H__
+#define __NVKM_CLK_H__
+#include <core/subdev.h>
+#include <core/notify.h>
+struct nvbios_pll;
+struct nvkm_pll_vals;
+
+enum nv_clk_src {
+ nv_clk_src_crystal,
+ nv_clk_src_href,
+
+ nv_clk_src_hclk,
+ nv_clk_src_hclkm3,
+ nv_clk_src_hclkm3d2,
+ nv_clk_src_hclkm2d3, /* NVAA */
+ nv_clk_src_hclkm4, /* NVAA */
+ nv_clk_src_cclk, /* NVAA */
+
+ nv_clk_src_host,
+
+ nv_clk_src_sppll0,
+ nv_clk_src_sppll1,
+
+ nv_clk_src_mpllsrcref,
+ nv_clk_src_mpllsrc,
+ nv_clk_src_mpll,
+ nv_clk_src_mdiv,
+
+ nv_clk_src_core,
+ nv_clk_src_core_intm,
+ nv_clk_src_shader,
+
+ nv_clk_src_mem,
+
+ nv_clk_src_gpc,
+ nv_clk_src_rop,
+ nv_clk_src_hubk01,
+ nv_clk_src_hubk06,
+ nv_clk_src_hubk07,
+ nv_clk_src_copy,
+ nv_clk_src_daemon,
+ nv_clk_src_disp,
+ nv_clk_src_vdec,
+
+ nv_clk_src_dom6,
+
+ nv_clk_src_max,
+};
+
+struct nvkm_cstate {
+ struct list_head head;
+ u8 voltage;
+ u32 domain[nv_clk_src_max];
+};
+
+struct nvkm_pstate {
+ struct list_head head;
+ struct list_head list; /* c-states */
+ struct nvkm_cstate base;
+ u8 pstate;
+ u8 fanspeed;
+};
+
+struct nvkm_domain {
+ enum nv_clk_src name;
+ u8 bios; /* 0xff for none */
+#define NVKM_CLK_DOM_FLAG_CORE 0x01
+ u8 flags;
+ const char *mname;
+ int mdiv;
+};
+
+struct nvkm_clk {
+ struct nvkm_subdev base;
+
+ struct nvkm_domain *domains;
+ struct nvkm_pstate bstate;
+
+ struct list_head states;
+ int state_nr;
+
+ struct work_struct work;
+ wait_queue_head_t wait;
+ atomic_t waiting;
+
+ struct nvkm_notify pwrsrc_ntfy;
+ int pwrsrc;
+ int pstate; /* current */
+ int ustate_ac; /* user-requested (-1 disabled, -2 perfmon) */
+ int ustate_dc; /* user-requested (-1 disabled, -2 perfmon) */
+ int astate; /* perfmon adjustment (base) */
+ int tstate; /* thermal adjustment (max-) */
+ int dstate; /* display adjustment (min+) */
+
+ bool allow_reclock;
+
+ int (*read)(struct nvkm_clk *, enum nv_clk_src);
+ int (*calc)(struct nvkm_clk *, struct nvkm_cstate *);
+ int (*prog)(struct nvkm_clk *);
+ void (*tidy)(struct nvkm_clk *);
+
+ /*XXX: die, these are here *only* to support the completely
+ * bat-shit insane what-was-nvkm_hw.c code
+ */
+ int (*pll_calc)(struct nvkm_clk *, struct nvbios_pll *, int clk,
+ struct nvkm_pll_vals *pv);
+ int (*pll_prog)(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *pv);
+};
+
+static inline struct nvkm_clk *
+nvkm_clk(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_CLK);
+}
+
+#define nvkm_clk_create(p,e,o,i,r,s,n,d) \
+ nvkm_clk_create_((p), (e), (o), (i), (r), (s), (n), sizeof(**d), \
+ (void **)d)
+#define nvkm_clk_destroy(p) ({ \
+ struct nvkm_clk *clk = (p); \
+ _nvkm_clk_dtor(nv_object(clk)); \
+})
+#define nvkm_clk_init(p) ({ \
+ struct nvkm_clk *clk = (p); \
+ _nvkm_clk_init(nv_object(clk)); \
+})
+#define nvkm_clk_fini(p,s) ({ \
+ struct nvkm_clk *clk = (p); \
+ _nvkm_clk_fini(nv_object(clk), (s)); \
+})
+
+int nvkm_clk_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *,
+ struct nvkm_domain *, struct nvkm_pstate *,
+ int, bool, int, void **);
+void _nvkm_clk_dtor(struct nvkm_object *);
+int _nvkm_clk_init(struct nvkm_object *);
+int _nvkm_clk_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_oclass nv04_clk_oclass;
+extern struct nvkm_oclass nv40_clk_oclass;
+extern struct nvkm_oclass *nv50_clk_oclass;
+extern struct nvkm_oclass *g84_clk_oclass;
+extern struct nvkm_oclass *mcp77_clk_oclass;
+extern struct nvkm_oclass gt215_clk_oclass;
+extern struct nvkm_oclass gf100_clk_oclass;
+extern struct nvkm_oclass gk104_clk_oclass;
+extern struct nvkm_oclass gk20a_clk_oclass;
+
+int nv04_clk_pll_set(struct nvkm_clk *, u32 type, u32 freq);
+int nv04_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *, int clk,
+ struct nvkm_pll_vals *);
+int nv04_clk_pll_prog(struct nvkm_clk *, u32 reg1, struct nvkm_pll_vals *);
+int gt215_clk_pll_calc(struct nvkm_clk *, struct nvbios_pll *,
+ int clk, struct nvkm_pll_vals *);
+
+int nvkm_clk_ustate(struct nvkm_clk *, int req, int pwr);
+int nvkm_clk_astate(struct nvkm_clk *, int req, int rel, bool wait);
+int nvkm_clk_dstate(struct nvkm_clk *, int req, int rel);
+int nvkm_clk_tstate(struct nvkm_clk *, int req, int rel);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
new file mode 100644
index 000000000000..d1bbe0d62b35
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/devinit.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_DEVINIT_H__
+#define __NVKM_DEVINIT_H__
+#include <core/subdev.h>
+
+struct nvkm_devinit {
+ struct nvkm_subdev base;
+ bool post;
+ void (*meminit)(struct nvkm_devinit *);
+ int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq);
+ u32 (*mmio)(struct nvkm_devinit *, u32 addr);
+};
+
+static inline struct nvkm_devinit *
+nvkm_devinit(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_DEVINIT);
+}
+
+extern struct nvkm_oclass *nv04_devinit_oclass;
+extern struct nvkm_oclass *nv05_devinit_oclass;
+extern struct nvkm_oclass *nv10_devinit_oclass;
+extern struct nvkm_oclass *nv1a_devinit_oclass;
+extern struct nvkm_oclass *nv20_devinit_oclass;
+extern struct nvkm_oclass *nv50_devinit_oclass;
+extern struct nvkm_oclass *g84_devinit_oclass;
+extern struct nvkm_oclass *g98_devinit_oclass;
+extern struct nvkm_oclass *gt215_devinit_oclass;
+extern struct nvkm_oclass *mcp89_devinit_oclass;
+extern struct nvkm_oclass *gf100_devinit_oclass;
+extern struct nvkm_oclass *gm107_devinit_oclass;
+extern struct nvkm_oclass *gm204_devinit_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
new file mode 100644
index 000000000000..16da56cf43b0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fb.h
@@ -0,0 +1,154 @@
+#ifndef __NVKM_FB_H__
+#define __NVKM_FB_H__
+#include <core/subdev.h>
+
+#include <subdev/mmu.h>
+
+/* memory type/access flags, do not match hardware values */
+#define NV_MEM_ACCESS_RO 1
+#define NV_MEM_ACCESS_WO 2
+#define NV_MEM_ACCESS_RW (NV_MEM_ACCESS_RO | NV_MEM_ACCESS_WO)
+#define NV_MEM_ACCESS_SYS 4
+#define NV_MEM_ACCESS_VM 8
+#define NV_MEM_ACCESS_NOSNOOP 16
+
+#define NV_MEM_TARGET_VRAM 0
+#define NV_MEM_TARGET_PCI 1
+#define NV_MEM_TARGET_PCI_NOSNOOP 2
+#define NV_MEM_TARGET_VM 3
+#define NV_MEM_TARGET_GART 4
+
+#define NV_MEM_TYPE_VM 0x7f
+#define NV_MEM_COMP_VM 0x03
+
+struct nvkm_mem {
+ struct drm_device *dev;
+
+ struct nvkm_vma bar_vma;
+ struct nvkm_vma vma[2];
+ u8 page_shift;
+
+ struct nvkm_mm_node *tag;
+ struct list_head regions;
+ dma_addr_t *pages;
+ u32 memtype;
+ u64 offset;
+ u64 size;
+ struct sg_table *sg;
+};
+
+struct nvkm_fb_tile {
+ struct nvkm_mm_node *tag;
+ u32 addr;
+ u32 limit;
+ u32 pitch;
+ u32 zcomp;
+};
+
+struct nvkm_fb {
+ struct nvkm_subdev base;
+
+ bool (*memtype_valid)(struct nvkm_fb *, u32 memtype);
+
+ struct nvkm_ram *ram;
+
+ struct nvkm_mm vram;
+ struct nvkm_mm tags;
+
+ struct {
+ struct nvkm_fb_tile region[16];
+ int regions;
+ void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nvkm_fb_tile *);
+ void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *);
+ void (*fini)(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+ void (*prog)(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+ } tile;
+};
+
+static inline struct nvkm_fb *
+nvkm_fb(void *obj)
+{
+ /* fbram uses this before device subdev pointer is valid */
+ if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
+ nv_subidx(obj) == NVDEV_SUBDEV_FB)
+ return obj;
+
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_FB);
+}
+
+extern struct nvkm_oclass *nv04_fb_oclass;
+extern struct nvkm_oclass *nv10_fb_oclass;
+extern struct nvkm_oclass *nv1a_fb_oclass;
+extern struct nvkm_oclass *nv20_fb_oclass;
+extern struct nvkm_oclass *nv25_fb_oclass;
+extern struct nvkm_oclass *nv30_fb_oclass;
+extern struct nvkm_oclass *nv35_fb_oclass;
+extern struct nvkm_oclass *nv36_fb_oclass;
+extern struct nvkm_oclass *nv40_fb_oclass;
+extern struct nvkm_oclass *nv41_fb_oclass;
+extern struct nvkm_oclass *nv44_fb_oclass;
+extern struct nvkm_oclass *nv46_fb_oclass;
+extern struct nvkm_oclass *nv47_fb_oclass;
+extern struct nvkm_oclass *nv49_fb_oclass;
+extern struct nvkm_oclass *nv4e_fb_oclass;
+extern struct nvkm_oclass *nv50_fb_oclass;
+extern struct nvkm_oclass *g84_fb_oclass;
+extern struct nvkm_oclass *gt215_fb_oclass;
+extern struct nvkm_oclass *mcp77_fb_oclass;
+extern struct nvkm_oclass *mcp89_fb_oclass;
+extern struct nvkm_oclass *gf100_fb_oclass;
+extern struct nvkm_oclass *gk104_fb_oclass;
+extern struct nvkm_oclass *gk20a_fb_oclass;
+extern struct nvkm_oclass *gm107_fb_oclass;
+
+#include <subdev/bios.h>
+#include <subdev/bios/ramcfg.h>
+
+struct nvkm_ram_data {
+ struct list_head head;
+ struct nvbios_ramcfg bios;
+ u32 freq;
+};
+
+struct nvkm_ram {
+ struct nvkm_object base;
+ enum {
+ NV_MEM_TYPE_UNKNOWN = 0,
+ NV_MEM_TYPE_STOLEN,
+ NV_MEM_TYPE_SGRAM,
+ NV_MEM_TYPE_SDRAM,
+ NV_MEM_TYPE_DDR1,
+ NV_MEM_TYPE_DDR2,
+ NV_MEM_TYPE_DDR3,
+ NV_MEM_TYPE_GDDR2,
+ NV_MEM_TYPE_GDDR3,
+ NV_MEM_TYPE_GDDR4,
+ NV_MEM_TYPE_GDDR5
+ } type;
+ u64 stolen;
+ u64 size;
+ u32 tags;
+
+ int ranks;
+ int parts;
+ int part_mask;
+
+ int (*get)(struct nvkm_fb *, u64 size, u32 align, u32 size_nc,
+ u32 type, struct nvkm_mem **);
+ void (*put)(struct nvkm_fb *, struct nvkm_mem **);
+
+ int (*calc)(struct nvkm_fb *, u32 freq);
+ int (*prog)(struct nvkm_fb *);
+ void (*tidy)(struct nvkm_fb *);
+ u32 freq;
+ u32 mr[16];
+ u32 mr1_nuts;
+
+ struct nvkm_ram_data *next;
+ struct nvkm_ram_data former;
+ struct nvkm_ram_data xition;
+ struct nvkm_ram_data target;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h
new file mode 100644
index 000000000000..a1384786adc9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/fuse.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_FUSE_H__
+#define __NVKM_FUSE_H__
+#include <core/subdev.h>
+#include <core/device.h>
+
+struct nvkm_fuse {
+ struct nvkm_subdev base;
+};
+
+static inline struct nvkm_fuse *
+nvkm_fuse(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_FUSE);
+}
+
+#define nvkm_fuse_create(p, e, o, d) \
+ nvkm_fuse_create_((p), (e), (o), sizeof(**d), (void **)d)
+
+int nvkm_fuse_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_fuse_dtor(struct nvkm_object *);
+int _nvkm_fuse_init(struct nvkm_object *);
+#define _nvkm_fuse_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv50_fuse_oclass;
+extern struct nvkm_oclass gf100_fuse_oclass;
+extern struct nvkm_oclass gm107_fuse_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
new file mode 100644
index 000000000000..ca5099a81b5a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/gpio.h
@@ -0,0 +1,44 @@
+#ifndef __NVKM_GPIO_H__
+#define __NVKM_GPIO_H__
+#include <core/subdev.h>
+#include <core/event.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/gpio.h>
+
+struct nvkm_gpio_ntfy_req {
+#define NVKM_GPIO_HI 0x01
+#define NVKM_GPIO_LO 0x02
+#define NVKM_GPIO_TOGGLED 0x03
+ u8 mask;
+ u8 line;
+};
+
+struct nvkm_gpio_ntfy_rep {
+ u8 mask;
+};
+
+struct nvkm_gpio {
+ struct nvkm_subdev base;
+
+ struct nvkm_event event;
+
+ void (*reset)(struct nvkm_gpio *, u8 func);
+ int (*find)(struct nvkm_gpio *, int idx, u8 tag, u8 line,
+ struct dcb_gpio_func *);
+ int (*set)(struct nvkm_gpio *, int idx, u8 tag, u8 line, int state);
+ int (*get)(struct nvkm_gpio *, int idx, u8 tag, u8 line);
+};
+
+static inline struct nvkm_gpio *
+nvkm_gpio(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_GPIO);
+}
+
+extern struct nvkm_oclass *nv10_gpio_oclass;
+extern struct nvkm_oclass *nv50_gpio_oclass;
+extern struct nvkm_oclass *g94_gpio_oclass;
+extern struct nvkm_oclass *gf110_gpio_oclass;
+extern struct nvkm_oclass *gk104_gpio_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
new file mode 100644
index 000000000000..a2e33730f05e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/i2c.h
@@ -0,0 +1,135 @@
+#ifndef __NVKM_I2C_H__
+#define __NVKM_I2C_H__
+#include <core/subdev.h>
+#include <core/event.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/i2c.h>
+
+#define NV_I2C_PORT(n) (0x00 + (n))
+#define NV_I2C_AUX(n) (0x10 + (n))
+#define NV_I2C_EXT(n) (0x20 + (n))
+#define NV_I2C_DEFAULT(n) (0x80 + (n))
+
+#define NV_I2C_TYPE_DCBI2C(n) (0x0000 | (n))
+#define NV_I2C_TYPE_EXTDDC(e) (0x0005 | (e) << 8)
+#define NV_I2C_TYPE_EXTAUX(e) (0x0006 | (e) << 8)
+
+struct nvkm_i2c_ntfy_req {
+#define NVKM_I2C_PLUG 0x01
+#define NVKM_I2C_UNPLUG 0x02
+#define NVKM_I2C_IRQ 0x04
+#define NVKM_I2C_DONE 0x08
+#define NVKM_I2C_ANY 0x0f
+ u8 mask;
+ u8 port;
+};
+
+struct nvkm_i2c_ntfy_rep {
+ u8 mask;
+};
+
+struct nvkm_i2c_port {
+ struct nvkm_object base;
+ struct i2c_adapter adapter;
+ struct mutex mutex;
+
+ struct list_head head;
+ u8 index;
+ int aux;
+
+ const struct nvkm_i2c_func *func;
+};
+
+struct nvkm_i2c_func {
+ void (*drive_scl)(struct nvkm_i2c_port *, int);
+ void (*drive_sda)(struct nvkm_i2c_port *, int);
+ int (*sense_scl)(struct nvkm_i2c_port *);
+ int (*sense_sda)(struct nvkm_i2c_port *);
+
+ int (*aux)(struct nvkm_i2c_port *, bool, u8, u32, u8 *, u8);
+ int (*pattern)(struct nvkm_i2c_port *, int pattern);
+ int (*lnk_ctl)(struct nvkm_i2c_port *, int nr, int bw, bool enh);
+ int (*drv_ctl)(struct nvkm_i2c_port *, int lane, int sw, int pe);
+};
+
+struct nvkm_i2c_board_info {
+ struct i2c_board_info dev;
+ u8 udelay; /* set to 0 to use the standard delay */
+};
+
+struct nvkm_i2c {
+ struct nvkm_subdev base;
+ struct nvkm_event event;
+
+ struct nvkm_i2c_port *(*find)(struct nvkm_i2c *, u8 index);
+ struct nvkm_i2c_port *(*find_type)(struct nvkm_i2c *, u16 type);
+ int (*acquire_pad)(struct nvkm_i2c_port *, unsigned long timeout);
+ void (*release_pad)(struct nvkm_i2c_port *);
+ int (*acquire)(struct nvkm_i2c_port *, unsigned long timeout);
+ void (*release)(struct nvkm_i2c_port *);
+ int (*identify)(struct nvkm_i2c *, int index,
+ const char *what, struct nvkm_i2c_board_info *,
+ bool (*match)(struct nvkm_i2c_port *,
+ struct i2c_board_info *, void *),
+ void *);
+
+ wait_queue_head_t wait;
+ struct list_head ports;
+};
+
+static inline struct nvkm_i2c *
+nvkm_i2c(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_I2C);
+}
+
+extern struct nvkm_oclass *nv04_i2c_oclass;
+extern struct nvkm_oclass *nv4e_i2c_oclass;
+extern struct nvkm_oclass *nv50_i2c_oclass;
+extern struct nvkm_oclass *g94_i2c_oclass;
+extern struct nvkm_oclass *gf110_i2c_oclass;
+extern struct nvkm_oclass *gf117_i2c_oclass;
+extern struct nvkm_oclass *gk104_i2c_oclass;
+extern struct nvkm_oclass *gm204_i2c_oclass;
+
+static inline int
+nv_rdi2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg)
+{
+ u8 val;
+ struct i2c_msg msgs[] = {
+ { .addr = addr, .flags = 0, .len = 1, .buf = &reg },
+ { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = &val },
+ };
+
+ int ret = i2c_transfer(&port->adapter, msgs, 2);
+ if (ret != 2)
+ return -EIO;
+
+ return val;
+}
+
+static inline int
+nv_wri2cr(struct nvkm_i2c_port *port, u8 addr, u8 reg, u8 val)
+{
+ u8 buf[2] = { reg, val };
+ struct i2c_msg msgs[] = {
+ { .addr = addr, .flags = 0, .len = 2, .buf = buf },
+ };
+
+ int ret = i2c_transfer(&port->adapter, msgs, 1);
+ if (ret != 1)
+ return -EIO;
+
+ return 0;
+}
+
+static inline bool
+nv_probe_i2c(struct nvkm_i2c_port *port, u8 addr)
+{
+ return nv_rdi2cr(port, addr, 0) >= 0;
+}
+
+int nv_rdaux(struct nvkm_i2c_port *, u32 addr, u8 *data, u8 size);
+int nv_wraux(struct nvkm_i2c_port *, u32 addr, u8 *data, u8 size);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
new file mode 100644
index 000000000000..2150d8af0040
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ibus.h
@@ -0,0 +1,32 @@
+#ifndef __NVKM_IBUS_H__
+#define __NVKM_IBUS_H__
+#include <core/subdev.h>
+
+struct nvkm_ibus {
+ struct nvkm_subdev base;
+};
+
+static inline struct nvkm_ibus *
+nvkm_ibus(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_IBUS);
+}
+
+#define nvkm_ibus_create(p,e,o,d) \
+ nvkm_subdev_create_((p), (e), (o), 0, "PIBUS", "ibus", \
+ sizeof(**d), (void **)d)
+#define nvkm_ibus_destroy(p) \
+ nvkm_subdev_destroy(&(p)->base)
+#define nvkm_ibus_init(p) \
+ nvkm_subdev_init(&(p)->base)
+#define nvkm_ibus_fini(p,s) \
+ nvkm_subdev_fini(&(p)->base, (s))
+
+#define _nvkm_ibus_dtor _nvkm_subdev_dtor
+#define _nvkm_ibus_init _nvkm_subdev_init
+#define _nvkm_ibus_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass gf100_ibus_oclass;
+extern struct nvkm_oclass gk104_ibus_oclass;
+extern struct nvkm_oclass gk20a_ibus_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
new file mode 100644
index 000000000000..d104c1aac807
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/instmem.h
@@ -0,0 +1,48 @@
+#ifndef __NVKM_INSTMEM_H__
+#define __NVKM_INSTMEM_H__
+#include <core/subdev.h>
+
+struct nvkm_instobj {
+ struct nvkm_object base;
+ struct list_head head;
+ u32 *suspend;
+ u64 addr;
+ u32 size;
+};
+
+static inline struct nvkm_instobj *
+nv_memobj(void *obj)
+{
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!nv_iclass(obj, NV_MEMOBJ_CLASS)))
+ nv_assert("BAD CAST -> NvMemObj, %08x", nv_hclass(obj));
+#endif
+ return obj;
+}
+
+struct nvkm_instmem {
+ struct nvkm_subdev base;
+ struct list_head list;
+
+ u32 reserved;
+ int (*alloc)(struct nvkm_instmem *, struct nvkm_object *,
+ u32 size, u32 align, struct nvkm_object **);
+};
+
+static inline struct nvkm_instmem *
+nvkm_instmem(void *obj)
+{
+ /* nv04/nv40 impls need to create objects in their constructor,
+ * which is before the subdev pointer is valid
+ */
+ if (nv_iclass(obj, NV_SUBDEV_CLASS) &&
+ nv_subidx(obj) == NVDEV_SUBDEV_INSTMEM)
+ return obj;
+
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_INSTMEM);
+}
+
+extern struct nvkm_oclass *nv04_instmem_oclass;
+extern struct nvkm_oclass *nv40_instmem_oclass;
+extern struct nvkm_oclass *nv50_instmem_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
new file mode 100644
index 000000000000..cd5d29fc0565
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/ltc.h
@@ -0,0 +1,31 @@
+#ifndef __NVKM_LTC_H__
+#define __NVKM_LTC_H__
+#include <core/subdev.h>
+struct nvkm_mm_node;
+
+#define NVKM_LTC_MAX_ZBC_CNT 16
+
+struct nvkm_ltc {
+ struct nvkm_subdev base;
+
+ int (*tags_alloc)(struct nvkm_ltc *, u32 count,
+ struct nvkm_mm_node **);
+ void (*tags_free)(struct nvkm_ltc *, struct nvkm_mm_node **);
+ void (*tags_clear)(struct nvkm_ltc *, u32 first, u32 count);
+
+ int zbc_min;
+ int zbc_max;
+ int (*zbc_color_get)(struct nvkm_ltc *, int index, const u32[4]);
+ int (*zbc_depth_get)(struct nvkm_ltc *, int index, const u32);
+};
+
+static inline struct nvkm_ltc *
+nvkm_ltc(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_LTC);
+}
+
+extern struct nvkm_oclass *gf100_ltc_oclass;
+extern struct nvkm_oclass *gk104_ltc_oclass;
+extern struct nvkm_oclass *gm107_ltc_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
new file mode 100644
index 000000000000..055bea7702a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mc.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_MC_H__
+#define __NVKM_MC_H__
+#include <core/subdev.h>
+
+struct nvkm_mc {
+ struct nvkm_subdev base;
+ bool use_msi;
+ unsigned int irq;
+ void (*unk260)(struct nvkm_mc *, u32);
+};
+
+static inline struct nvkm_mc *
+nvkm_mc(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MC);
+}
+
+extern struct nvkm_oclass *nv04_mc_oclass;
+extern struct nvkm_oclass *nv40_mc_oclass;
+extern struct nvkm_oclass *nv44_mc_oclass;
+extern struct nvkm_oclass *nv4c_mc_oclass;
+extern struct nvkm_oclass *nv50_mc_oclass;
+extern struct nvkm_oclass *g94_mc_oclass;
+extern struct nvkm_oclass *g98_mc_oclass;
+extern struct nvkm_oclass *gf100_mc_oclass;
+extern struct nvkm_oclass *gf106_mc_oclass;
+extern struct nvkm_oclass *gk20a_mc_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
new file mode 100644
index 000000000000..3a5368776c31
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mmu.h
@@ -0,0 +1,104 @@
+#ifndef __NVKM_MMU_H__
+#define __NVKM_MMU_H__
+#include <core/subdev.h>
+#include <core/mm.h>
+struct nvkm_device;
+struct nvkm_mem;
+
+struct nvkm_vm_pgt {
+ struct nvkm_gpuobj *obj[2];
+ u32 refcount[2];
+};
+
+struct nvkm_vm_pgd {
+ struct list_head head;
+ struct nvkm_gpuobj *obj;
+};
+
+struct nvkm_vma {
+ struct list_head head;
+ int refcount;
+ struct nvkm_vm *vm;
+ struct nvkm_mm_node *node;
+ u64 offset;
+ u32 access;
+};
+
+struct nvkm_vm {
+ struct nvkm_mmu *mmu;
+ struct nvkm_mm mm;
+ struct kref refcount;
+
+ struct list_head pgd_list;
+ atomic_t engref[NVDEV_SUBDEV_NR];
+
+ struct nvkm_vm_pgt *pgt;
+ u32 fpde;
+ u32 lpde;
+};
+
+struct nvkm_mmu {
+ struct nvkm_subdev base;
+
+ u64 limit;
+ u8 dma_bits;
+ u32 pgt_bits;
+ u8 spg_shift;
+ u8 lpg_shift;
+
+ int (*create)(struct nvkm_mmu *, u64 offset, u64 length,
+ u64 mm_offset, struct nvkm_vm **);
+
+ void (*map_pgt)(struct nvkm_gpuobj *pgd, u32 pde,
+ struct nvkm_gpuobj *pgt[2]);
+ void (*map)(struct nvkm_vma *, struct nvkm_gpuobj *,
+ struct nvkm_mem *, u32 pte, u32 cnt,
+ u64 phys, u64 delta);
+ void (*map_sg)(struct nvkm_vma *, struct nvkm_gpuobj *,
+ struct nvkm_mem *, u32 pte, u32 cnt, dma_addr_t *);
+ void (*unmap)(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt);
+ void (*flush)(struct nvkm_vm *);
+};
+
+static inline struct nvkm_mmu *
+nvkm_mmu(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MMU);
+}
+
+#define nvkm_mmu_create(p,e,o,i,f,d) \
+ nvkm_subdev_create((p), (e), (o), 0, (i), (f), (d))
+#define nvkm_mmu_destroy(p) \
+ nvkm_subdev_destroy(&(p)->base)
+#define nvkm_mmu_init(p) \
+ nvkm_subdev_init(&(p)->base)
+#define nvkm_mmu_fini(p,s) \
+ nvkm_subdev_fini(&(p)->base, (s))
+
+#define _nvkm_mmu_dtor _nvkm_subdev_dtor
+#define _nvkm_mmu_init _nvkm_subdev_init
+#define _nvkm_mmu_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv04_mmu_oclass;
+extern struct nvkm_oclass nv41_mmu_oclass;
+extern struct nvkm_oclass nv44_mmu_oclass;
+extern struct nvkm_oclass nv50_mmu_oclass;
+extern struct nvkm_oclass gf100_mmu_oclass;
+
+int nv04_vm_create(struct nvkm_mmu *, u64, u64, u64,
+ struct nvkm_vm **);
+void nv04_mmu_dtor(struct nvkm_object *);
+
+int nvkm_vm_create(struct nvkm_mmu *, u64 offset, u64 length, u64 mm_offset,
+ u32 block, struct nvkm_vm **);
+int nvkm_vm_new(struct nvkm_device *, u64 offset, u64 length, u64 mm_offset,
+ struct nvkm_vm **);
+int nvkm_vm_ref(struct nvkm_vm *, struct nvkm_vm **, struct nvkm_gpuobj *pgd);
+int nvkm_vm_get(struct nvkm_vm *, u64 size, u32 page_shift, u32 access,
+ struct nvkm_vma *);
+void nvkm_vm_put(struct nvkm_vma *);
+void nvkm_vm_map(struct nvkm_vma *, struct nvkm_mem *);
+void nvkm_vm_map_at(struct nvkm_vma *, u64 offset, struct nvkm_mem *);
+void nvkm_vm_unmap(struct nvkm_vma *);
+void nvkm_vm_unmap_at(struct nvkm_vma *, u64 offset, u64 length);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h
new file mode 100644
index 000000000000..fba613477b1a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/mxm.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_MXM_H__
+#define __NVKM_MXM_H__
+#include <core/subdev.h>
+
+#define MXM_SANITISE_DCB 0x00000001
+
+struct nvkm_mxm {
+ struct nvkm_subdev base;
+ u32 action;
+ u8 *mxms;
+};
+
+static inline struct nvkm_mxm *
+nvkm_mxm(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_MXM);
+}
+
+#define nvkm_mxm_create(p,e,o,d) \
+ nvkm_mxm_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_mxm_init(p) \
+ nvkm_subdev_init(&(p)->base)
+#define nvkm_mxm_fini(p,s) \
+ nvkm_subdev_fini(&(p)->base, (s))
+int nvkm_mxm_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void nvkm_mxm_destroy(struct nvkm_mxm *);
+
+#define _nvkm_mxm_dtor _nvkm_subdev_dtor
+#define _nvkm_mxm_init _nvkm_subdev_init
+#define _nvkm_mxm_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv50_mxm_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
new file mode 100644
index 000000000000..7b86acc634a0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/pmu.h
@@ -0,0 +1,53 @@
+#ifndef __NVKM_PMU_H__
+#define __NVKM_PMU_H__
+#include <core/subdev.h>
+
+struct nvkm_pmu {
+ struct nvkm_subdev base;
+
+ struct {
+ u32 base;
+ u32 size;
+ } send;
+
+ struct {
+ u32 base;
+ u32 size;
+
+ struct work_struct work;
+ wait_queue_head_t wait;
+ u32 process;
+ u32 message;
+ u32 data[2];
+ } recv;
+
+ int (*message)(struct nvkm_pmu *, u32[2], u32, u32, u32, u32);
+ void (*pgob)(struct nvkm_pmu *, bool);
+};
+
+static inline struct nvkm_pmu *
+nvkm_pmu(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_PMU);
+}
+
+extern struct nvkm_oclass *gt215_pmu_oclass;
+extern struct nvkm_oclass *gf100_pmu_oclass;
+extern struct nvkm_oclass *gf110_pmu_oclass;
+extern struct nvkm_oclass *gk104_pmu_oclass;
+extern struct nvkm_oclass *gk208_pmu_oclass;
+extern struct nvkm_oclass *gk20a_pmu_oclass;
+
+/* interface to MEMX process running on PMU */
+struct nvkm_memx;
+int nvkm_memx_init(struct nvkm_pmu *, struct nvkm_memx **);
+int nvkm_memx_fini(struct nvkm_memx **, bool exec);
+void nvkm_memx_wr32(struct nvkm_memx *, u32 addr, u32 data);
+void nvkm_memx_wait(struct nvkm_memx *, u32 addr, u32 mask, u32 data, u32 nsec);
+void nvkm_memx_nsec(struct nvkm_memx *, u32 nsec);
+void nvkm_memx_wait_vblank(struct nvkm_memx *);
+void nvkm_memx_train(struct nvkm_memx *);
+int nvkm_memx_train_result(struct nvkm_pmu *, u32 *, int);
+void nvkm_memx_block(struct nvkm_memx *);
+void nvkm_memx_unblock(struct nvkm_memx *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
new file mode 100644
index 000000000000..6662829b6db1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/therm.h
@@ -0,0 +1,79 @@
+#ifndef __NVKM_THERM_H__
+#define __NVKM_THERM_H__
+#include <core/subdev.h>
+
+enum nvkm_therm_fan_mode {
+ NVKM_THERM_CTRL_NONE = 0,
+ NVKM_THERM_CTRL_MANUAL = 1,
+ NVKM_THERM_CTRL_AUTO = 2,
+};
+
+enum nvkm_therm_attr_type {
+ NVKM_THERM_ATTR_FAN_MIN_DUTY = 0,
+ NVKM_THERM_ATTR_FAN_MAX_DUTY = 1,
+ NVKM_THERM_ATTR_FAN_MODE = 2,
+
+ NVKM_THERM_ATTR_THRS_FAN_BOOST = 10,
+ NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST = 11,
+ NVKM_THERM_ATTR_THRS_DOWN_CLK = 12,
+ NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST = 13,
+ NVKM_THERM_ATTR_THRS_CRITICAL = 14,
+ NVKM_THERM_ATTR_THRS_CRITICAL_HYST = 15,
+ NVKM_THERM_ATTR_THRS_SHUTDOWN = 16,
+ NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST = 17,
+};
+
+struct nvkm_therm {
+ struct nvkm_subdev base;
+
+ int (*pwm_ctrl)(struct nvkm_therm *, int line, bool);
+ int (*pwm_get)(struct nvkm_therm *, int line, u32 *, u32 *);
+ int (*pwm_set)(struct nvkm_therm *, int line, u32, u32);
+ int (*pwm_clock)(struct nvkm_therm *, int line);
+
+ int (*fan_get)(struct nvkm_therm *);
+ int (*fan_set)(struct nvkm_therm *, int);
+ int (*fan_sense)(struct nvkm_therm *);
+
+ int (*temp_get)(struct nvkm_therm *);
+
+ int (*attr_get)(struct nvkm_therm *, enum nvkm_therm_attr_type);
+ int (*attr_set)(struct nvkm_therm *, enum nvkm_therm_attr_type, int);
+};
+
+static inline struct nvkm_therm *
+nvkm_therm(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_THERM);
+}
+
+#define nvkm_therm_create(p,e,o,d) \
+ nvkm_therm_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_therm_destroy(p) ({ \
+ struct nvkm_therm *therm = (p); \
+ _nvkm_therm_dtor(nv_object(therm)); \
+})
+#define nvkm_therm_init(p) ({ \
+ struct nvkm_therm *therm = (p); \
+ _nvkm_therm_init(nv_object(therm)); \
+})
+#define nvkm_therm_fini(p,s) ({ \
+ struct nvkm_therm *therm = (p); \
+ _nvkm_therm_init(nv_object(therm), (s)); \
+})
+
+int nvkm_therm_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_therm_dtor(struct nvkm_object *);
+int _nvkm_therm_init(struct nvkm_object *);
+int _nvkm_therm_fini(struct nvkm_object *, bool);
+
+int nvkm_therm_cstate(struct nvkm_therm *, int, int);
+
+extern struct nvkm_oclass nv40_therm_oclass;
+extern struct nvkm_oclass nv50_therm_oclass;
+extern struct nvkm_oclass g84_therm_oclass;
+extern struct nvkm_oclass gt215_therm_oclass;
+extern struct nvkm_oclass gf110_therm_oclass;
+extern struct nvkm_oclass gm107_therm_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
new file mode 100644
index 000000000000..4ad55082ef7a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/timer.h
@@ -0,0 +1,61 @@
+#ifndef __NVKM_TIMER_H__
+#define __NVKM_TIMER_H__
+#include <core/subdev.h>
+
+struct nvkm_alarm {
+ struct list_head head;
+ u64 timestamp;
+ void (*func)(struct nvkm_alarm *);
+};
+
+static inline void
+nvkm_alarm_init(struct nvkm_alarm *alarm,
+ void (*func)(struct nvkm_alarm *))
+{
+ INIT_LIST_HEAD(&alarm->head);
+ alarm->func = func;
+}
+
+bool nvkm_timer_wait_eq(void *, u64 nsec, u32 addr, u32 mask, u32 data);
+bool nvkm_timer_wait_ne(void *, u64 nsec, u32 addr, u32 mask, u32 data);
+bool nvkm_timer_wait_cb(void *, u64 nsec, bool (*func)(void *), void *data);
+void nvkm_timer_alarm(void *, u32 nsec, struct nvkm_alarm *);
+void nvkm_timer_alarm_cancel(void *, struct nvkm_alarm *);
+
+#define NV_WAIT_DEFAULT 2000000000ULL
+#define nv_wait(o,a,m,v) \
+ nvkm_timer_wait_eq((o), NV_WAIT_DEFAULT, (a), (m), (v))
+#define nv_wait_ne(o,a,m,v) \
+ nvkm_timer_wait_ne((o), NV_WAIT_DEFAULT, (a), (m), (v))
+#define nv_wait_cb(o,c,d) \
+ nvkm_timer_wait_cb((o), NV_WAIT_DEFAULT, (c), (d))
+
+struct nvkm_timer {
+ struct nvkm_subdev base;
+ u64 (*read)(struct nvkm_timer *);
+ void (*alarm)(struct nvkm_timer *, u64 time, struct nvkm_alarm *);
+ void (*alarm_cancel)(struct nvkm_timer *, struct nvkm_alarm *);
+};
+
+static inline struct nvkm_timer *
+nvkm_timer(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_TIMER);
+}
+
+#define nvkm_timer_create(p,e,o,d) \
+ nvkm_subdev_create_((p), (e), (o), 0, "PTIMER", "timer", \
+ sizeof(**d), (void **)d)
+#define nvkm_timer_destroy(p) \
+ nvkm_subdev_destroy(&(p)->base)
+#define nvkm_timer_init(p) \
+ nvkm_subdev_init(&(p)->base)
+#define nvkm_timer_fini(p,s) \
+ nvkm_subdev_fini(&(p)->base, (s))
+
+int nvkm_timer_create_(struct nvkm_object *, struct nvkm_engine *,
+ struct nvkm_oclass *, int size, void **);
+
+extern struct nvkm_oclass nv04_timer_oclass;
+extern struct nvkm_oclass gk20a_timer_oclass;
+#endif
diff --git a/drivers/gpu/drm/nouveau/core/include/subdev/vga.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h
index fee09ad818e4..fee09ad818e4 100644
--- a/drivers/gpu/drm/nouveau/core/include/subdev/vga.h
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/vga.h
diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
new file mode 100644
index 000000000000..e3d7243fbb1d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/volt.h
@@ -0,0 +1,58 @@
+#ifndef __NVKM_VOLT_H__
+#define __NVKM_VOLT_H__
+#include <core/subdev.h>
+
+struct nvkm_voltage {
+ u32 uv;
+ u8 id;
+};
+
+struct nvkm_volt {
+ struct nvkm_subdev base;
+
+ int (*vid_get)(struct nvkm_volt *);
+ int (*get)(struct nvkm_volt *);
+ int (*vid_set)(struct nvkm_volt *, u8 vid);
+ int (*set)(struct nvkm_volt *, u32 uv);
+ int (*set_id)(struct nvkm_volt *, u8 id, int condition);
+
+ u8 vid_mask;
+ u8 vid_nr;
+ struct {
+ u32 uv;
+ u8 vid;
+ } vid[256];
+};
+
+static inline struct nvkm_volt *
+nvkm_volt(void *obj)
+{
+ return (void *)nvkm_subdev(obj, NVDEV_SUBDEV_VOLT);
+}
+
+#define nvkm_volt_create(p, e, o, d) \
+ nvkm_volt_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_volt_destroy(p) ({ \
+ struct nvkm_volt *v = (p); \
+ _nvkm_volt_dtor(nv_object(v)); \
+})
+#define nvkm_volt_init(p) ({ \
+ struct nvkm_volt *v = (p); \
+ _nvkm_volt_init(nv_object(v)); \
+})
+#define nvkm_volt_fini(p,s) \
+ nvkm_subdev_fini((p), (s))
+
+int nvkm_volt_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_volt_dtor(struct nvkm_object *);
+int _nvkm_volt_init(struct nvkm_object *);
+#define _nvkm_volt_fini _nvkm_subdev_fini
+
+extern struct nvkm_oclass nv40_volt_oclass;
+extern struct nvkm_oclass gk20a_volt_oclass;
+
+int nvkm_voltgpio_init(struct nvkm_volt *);
+int nvkm_voltgpio_get(struct nvkm_volt *);
+int nvkm_voltgpio_set(struct nvkm_volt *, u8);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.c b/drivers/gpu/drm/nouveau/nouveau_abi16.c
index d39a15000068..d8b0891a141c 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.c
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.c
@@ -100,7 +100,7 @@ static void
nouveau_abi16_ntfy_fini(struct nouveau_abi16_chan *chan,
struct nouveau_abi16_ntfy *ntfy)
{
- nouveau_mm_free(&chan->heap, &ntfy->node);
+ nvkm_mm_free(&chan->heap, &ntfy->node);
list_del(&ntfy->head);
kfree(ntfy);
}
@@ -128,7 +128,7 @@ nouveau_abi16_chan_fini(struct nouveau_abi16 *abi16,
}
if (chan->heap.block_size)
- nouveau_mm_fini(&chan->heap);
+ nvkm_mm_fini(&chan->heap);
/* destroy channel object, all children will be killed too */
if (chan->chan) {
@@ -164,8 +164,8 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct nouveau_drm *drm = nouveau_drm(dev);
struct nvif_device *device = &drm->device;
- struct nouveau_timer *ptimer = nvkm_timer(device);
- struct nouveau_graph *graph = nvkm_gr(device);
+ struct nvkm_timer *ptimer = nvxx_timer(device);
+ struct nvkm_gr *gr = nvxx_gr(device);
struct drm_nouveau_getparam *getparam = data;
switch (getparam->param) {
@@ -173,19 +173,19 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
getparam->value = device->info.chipset;
break;
case NOUVEAU_GETPARAM_PCI_VENDOR:
- if (nv_device_is_pci(nvkm_device(device)))
+ if (nv_device_is_pci(nvxx_device(device)))
getparam->value = dev->pdev->vendor;
else
getparam->value = 0;
break;
case NOUVEAU_GETPARAM_PCI_DEVICE:
- if (nv_device_is_pci(nvkm_device(device)))
+ if (nv_device_is_pci(nvxx_device(device)))
getparam->value = dev->pdev->device;
else
getparam->value = 0;
break;
case NOUVEAU_GETPARAM_BUS_TYPE:
- if (!nv_device_is_pci(nvkm_device(device)))
+ if (!nv_device_is_pci(nvxx_device(device)))
getparam->value = 3;
else
if (drm_pci_device_is_agp(dev))
@@ -215,7 +215,7 @@ nouveau_abi16_ioctl_getparam(ABI16_IOCTL_ARGS)
getparam->value = 1;
break;
case NOUVEAU_GETPARAM_GRAPH_UNITS:
- getparam->value = graph->units ? graph->units(graph) : 0;
+ getparam->value = gr->units ? gr->units(gr) : 0;
break;
default:
NV_PRINTK(debug, cli, "unknown parameter %lld\n", getparam->param);
@@ -324,7 +324,7 @@ nouveau_abi16_ioctl_channel_alloc(ABI16_IOCTL_ARGS)
if (ret)
goto done;
- ret = nouveau_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
+ ret = nvkm_mm_init(&chan->heap, 0, PAGE_SIZE, 1);
done:
if (ret)
nouveau_abi16_chan_fini(abi16, chan);
@@ -448,8 +448,8 @@ nouveau_abi16_ioctl_notifierobj_alloc(ABI16_IOCTL_ARGS)
list_add(&ntfy->head, &chan->notifiers);
ntfy->handle = info->handle;
- ret = nouveau_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
- &ntfy->node);
+ ret = nvkm_mm_head(&chan->heap, 0, 1, info->size, info->size, 1,
+ &ntfy->node);
if (ret)
goto done;
@@ -527,7 +527,7 @@ nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS)
/* cleanup extra state if this object was a notifier */
list_for_each_entry(ntfy, &chan->notifiers, head) {
if (ntfy->handle == fini->handle) {
- nouveau_mm_free(&chan->heap, &ntfy->node);
+ nvkm_mm_free(&chan->heap, &ntfy->node);
list_del(&ntfy->head);
break;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_abi16.h b/drivers/gpu/drm/nouveau/nouveau_abi16.h
index 39844e6bfbff..86eb1caf4957 100644
--- a/drivers/gpu/drm/nouveau/nouveau_abi16.h
+++ b/drivers/gpu/drm/nouveau/nouveau_abi16.h
@@ -14,7 +14,7 @@ int nouveau_abi16_ioctl_gpuobj_free(ABI16_IOCTL_ARGS);
struct nouveau_abi16_ntfy {
struct list_head head;
- struct nouveau_mm_node *node;
+ struct nvkm_mm_node *node;
u32 handle;
};
@@ -23,8 +23,8 @@ struct nouveau_abi16_chan {
struct nouveau_channel *chan;
struct list_head notifiers;
struct nouveau_bo *ntfy;
- struct nouveau_vma ntfy_vma;
- struct nouveau_mm heap;
+ struct nvkm_vma ntfy_vma;
+ struct nvkm_mm heap;
};
struct nouveau_abi16 {
diff --git a/drivers/gpu/drm/nouveau/nouveau_agp.c b/drivers/gpu/drm/nouveau/nouveau_agp.c
index 1f6f6ba6847a..0b5970955604 100644
--- a/drivers/gpu/drm/nouveau/nouveau_agp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_agp.c
@@ -45,8 +45,8 @@ get_agp_mode(struct nouveau_drm *drm, const struct drm_agp_info *info)
while (agpmode == -1 && quirk->hostbridge_vendor) {
if (info->id_vendor == quirk->hostbridge_vendor &&
info->id_device == quirk->hostbridge_device &&
- nvkm_device(device)->pdev->vendor == quirk->chip_vendor &&
- nvkm_device(device)->pdev->device == quirk->chip_device) {
+ nvxx_device(device)->pdev->vendor == quirk->chip_vendor &&
+ nvxx_device(device)->pdev->device == quirk->chip_device) {
agpmode = quirk->mode;
NV_INFO(drm, "Forcing agp mode to %dX. Use agpmode to override.\n",
agpmode);
diff --git a/drivers/gpu/drm/nouveau/nouveau_bios.c b/drivers/gpu/drm/nouveau/nouveau_bios.c
index 7df6acc8bb34..0190b69bbe25 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bios.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bios.c
@@ -2009,7 +2009,7 @@ uint8_t *nouveau_bios_embedded_edid(struct drm_device *dev)
static bool NVInitVBIOS(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_bios *bios = nvkm_bios(&drm->device);
+ struct nvkm_bios *bios = nvxx_bios(&drm->device);
struct nvbios *legacy = &drm->vbios;
memset(legacy, 0, sizeof(struct nvbios));
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.c b/drivers/gpu/drm/nouveau/nouveau_bo.c
index bba2960d3dfb..77326e344dad 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.c
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.c
@@ -48,9 +48,9 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
{
struct nouveau_drm *drm = nouveau_drm(dev);
int i = reg - drm->tile.reg;
- struct nouveau_fb *pfb = nvkm_fb(&drm->device);
- struct nouveau_fb_tile *tile = &pfb->tile.region[i];
- struct nouveau_engine *engine;
+ struct nvkm_fb *pfb = nvxx_fb(&drm->device);
+ struct nvkm_fb_tile *tile = &pfb->tile.region[i];
+ struct nvkm_engine *engine;
nouveau_fence_unref(&reg->fence);
@@ -62,9 +62,9 @@ nv10_bo_update_tile_region(struct drm_device *dev, struct nouveau_drm_tile *reg,
pfb->tile.prog(pfb, i, tile);
- if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_GR)))
+ if ((engine = nvkm_engine(pfb, NVDEV_ENGINE_GR)))
engine->tile_prog(engine, i);
- if ((engine = nouveau_engine(pfb, NVDEV_ENGINE_MPEG)))
+ if ((engine = nvkm_engine(pfb, NVDEV_ENGINE_MPEG)))
engine->tile_prog(engine, i);
}
@@ -105,7 +105,7 @@ nv10_bo_set_tiling(struct drm_device *dev, u32 addr,
u32 size, u32 pitch, u32 flags)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+ struct nvkm_fb *pfb = nvxx_fb(&drm->device);
struct nouveau_drm_tile *tile, *found = NULL;
int i;
@@ -193,7 +193,7 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
int max_size;
if (drm->client.vm)
- lpg_shift = drm->client.vm->vmm->lpg_shift;
+ lpg_shift = drm->client.vm->mmu->lpg_shift;
max_size = INT_MAX & ~((1 << lpg_shift) - 1);
if (size <= 0 || size > max_size) {
@@ -214,13 +214,13 @@ nouveau_bo_new(struct drm_device *dev, int size, int align,
nvbo->tile_flags = tile_flags;
nvbo->bo.bdev = &drm->ttm.bdev;
- if (!nv_device_is_cpu_coherent(nvkm_device(&drm->device)))
+ if (!nv_device_is_cpu_coherent(nvxx_device(&drm->device)))
nvbo->force_coherent = flags & TTM_PL_FLAG_UNCACHED;
nvbo->page_shift = 12;
if (drm->client.vm) {
if (!(flags & TTM_PL_FLAG_TT) && size > 256 * 1024)
- nvbo->page_shift = drm->client.vm->vmm->lpg_shift;
+ nvbo->page_shift = drm->client.vm->mmu->lpg_shift;
}
nouveau_bo_fixup_align(nvbo, flags, &align, &size);
@@ -325,7 +325,7 @@ nouveau_bo_pin(struct nouveau_bo *nvbo, uint32_t memtype, bool contig)
memtype == TTM_PL_FLAG_VRAM && contig) {
if (nvbo->tile_flags & NOUVEAU_GEM_TILE_NONCONTIG) {
if (bo->mem.mem_type == TTM_PL_VRAM) {
- struct nouveau_mem *mem = bo->mem.mm_node;
+ struct nvkm_mem *mem = bo->mem.mm_node;
if (!list_is_singular(&mem->regions))
evict = true;
}
@@ -459,7 +459,7 @@ void
nouveau_bo_sync_for_device(struct nouveau_bo *nvbo)
{
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
- struct nouveau_device *device = nvkm_device(&drm->device);
+ struct nvkm_device *device = nvxx_device(&drm->device);
struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
int i;
@@ -479,7 +479,7 @@ void
nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo)
{
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
- struct nouveau_device *device = nvkm_device(&drm->device);
+ struct nvkm_device *device = nvxx_device(&drm->device);
struct ttm_dma_tt *ttm_dma = (struct ttm_dma_tt *)nvbo->bo.ttm;
int i;
@@ -533,20 +533,6 @@ _nouveau_bo_mem_index(struct nouveau_bo *nvbo, unsigned index, void *mem, u8 sz)
}
#define nouveau_bo_mem_index(o, i, m) _nouveau_bo_mem_index(o, i, m, sizeof(*m))
-u16
-nouveau_bo_rd16(struct nouveau_bo *nvbo, unsigned index)
-{
- bool is_iomem;
- u16 *mem = ttm_kmap_obj_virtual(&nvbo->kmap, &is_iomem);
-
- mem = nouveau_bo_mem_index(nvbo, index, mem);
-
- if (is_iomem)
- return ioread16_native((void __force __iomem *)mem);
- else
- return *mem;
-}
-
void
nouveau_bo_wr16(struct nouveau_bo *nvbo, unsigned index, u16 val)
{
@@ -634,7 +620,7 @@ nouveau_bo_init_mem_type(struct ttm_bo_device *bdev, uint32_t type,
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
/* Some BARs do not support being ioremapped WC */
- if (nvkm_bar(&drm->device)->iomap_uncached) {
+ if (nvxx_bar(&drm->device)->iomap_uncached) {
man->available_caching = TTM_PL_FLAG_UNCACHED;
man->default_caching = TTM_PL_FLAG_UNCACHED;
}
@@ -709,7 +695,7 @@ static int
nve0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
int ret = RING_SPACE(chan, 10);
if (ret == 0) {
BEGIN_NVC0(chan, NvSubCopy, 0x0400, 8);
@@ -741,7 +727,7 @@ static int
nvc0_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
u64 src_offset = node->vma[0].offset;
u64 dst_offset = node->vma[1].offset;
u32 page_count = new_mem->num_pages;
@@ -779,7 +765,7 @@ static int
nvc0_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
u64 src_offset = node->vma[0].offset;
u64 dst_offset = node->vma[1].offset;
u32 page_count = new_mem->num_pages;
@@ -818,7 +804,7 @@ static int
nva3_bo_move_copy(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
u64 src_offset = node->vma[0].offset;
u64 dst_offset = node->vma[1].offset;
u32 page_count = new_mem->num_pages;
@@ -856,7 +842,7 @@ static int
nv98_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
int ret = RING_SPACE(chan, 7);
if (ret == 0) {
BEGIN_NV04(chan, NvSubCopy, 0x0320, 6);
@@ -874,7 +860,7 @@ static int
nv84_bo_move_exec(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
int ret = RING_SPACE(chan, 7);
if (ret == 0) {
BEGIN_NV04(chan, NvSubCopy, 0x0304, 6);
@@ -908,12 +894,12 @@ static int
nv50_bo_move_m2mf(struct nouveau_channel *chan, struct ttm_buffer_object *bo,
struct ttm_mem_reg *old_mem, struct ttm_mem_reg *new_mem)
{
- struct nouveau_mem *node = old_mem->mm_node;
+ struct nvkm_mem *node = old_mem->mm_node;
u64 length = (new_mem->num_pages << PAGE_SHIFT);
u64 src_offset = node->vma[0].offset;
u64 dst_offset = node->vma[1].offset;
int src_tiled = !!node->memtype;
- int dst_tiled = !!((struct nouveau_mem *)new_mem->mm_node)->memtype;
+ int dst_tiled = !!((struct nvkm_mem *)new_mem->mm_node)->memtype;
int ret;
while (length) {
@@ -1050,25 +1036,25 @@ static int
nouveau_bo_move_prep(struct nouveau_drm *drm, struct ttm_buffer_object *bo,
struct ttm_mem_reg *mem)
{
- struct nouveau_mem *old_node = bo->mem.mm_node;
- struct nouveau_mem *new_node = mem->mm_node;
+ struct nvkm_mem *old_node = bo->mem.mm_node;
+ struct nvkm_mem *new_node = mem->mm_node;
u64 size = (u64)mem->num_pages << PAGE_SHIFT;
int ret;
- ret = nouveau_vm_get(drm->client.vm, size, old_node->page_shift,
- NV_MEM_ACCESS_RW, &old_node->vma[0]);
+ ret = nvkm_vm_get(drm->client.vm, size, old_node->page_shift,
+ NV_MEM_ACCESS_RW, &old_node->vma[0]);
if (ret)
return ret;
- ret = nouveau_vm_get(drm->client.vm, size, new_node->page_shift,
- NV_MEM_ACCESS_RW, &old_node->vma[1]);
+ ret = nvkm_vm_get(drm->client.vm, size, new_node->page_shift,
+ NV_MEM_ACCESS_RW, &old_node->vma[1]);
if (ret) {
- nouveau_vm_put(&old_node->vma[0]);
+ nvkm_vm_put(&old_node->vma[0]);
return ret;
}
- nouveau_vm_map(&old_node->vma[0], old_node);
- nouveau_vm_map(&old_node->vma[1], new_node);
+ nvkm_vm_map(&old_node->vma[0], old_node);
+ nvkm_vm_map(&old_node->vma[1], new_node);
return 0;
}
@@ -1083,7 +1069,7 @@ nouveau_bo_move_m2mf(struct ttm_buffer_object *bo, int evict, bool intr,
int ret;
/* create temporary vmas for the transfer and attach them to the
- * old nouveau_mem node, these will get cleaned up after ttm has
+ * old nvkm_mem node, these will get cleaned up after ttm has
* destroyed the ttm_mem_reg
*/
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
@@ -1245,7 +1231,7 @@ static void
nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
{
struct nouveau_bo *nvbo = nouveau_bo(bo);
- struct nouveau_vma *vma;
+ struct nvkm_vma *vma;
/* ttm can now (stupidly) pass the driver bos it didn't create... */
if (bo->destroy != nouveau_bo_del_ttm)
@@ -1254,10 +1240,10 @@ nouveau_bo_move_ntfy(struct ttm_buffer_object *bo, struct ttm_mem_reg *new_mem)
list_for_each_entry(vma, &nvbo->vma_list, head) {
if (new_mem && new_mem->mem_type != TTM_PL_SYSTEM &&
(new_mem->mem_type == TTM_PL_VRAM ||
- nvbo->page_shift != vma->vm->vmm->lpg_shift)) {
- nouveau_vm_map(vma, new_mem->mm_node);
+ nvbo->page_shift != vma->vm->mmu->lpg_shift)) {
+ nvkm_vm_map(vma, new_mem->mm_node);
} else {
- nouveau_vm_unmap(vma);
+ nvkm_vm_unmap(vma);
}
}
}
@@ -1368,7 +1354,7 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
struct ttm_mem_type_manager *man = &bdev->man[mem->mem_type];
struct nouveau_drm *drm = nouveau_bdev(bdev);
- struct nouveau_mem *node = mem->mm_node;
+ struct nvkm_mem *node = mem->mm_node;
int ret;
mem->bus.addr = NULL;
@@ -1396,10 +1382,10 @@ nouveau_ttm_io_mem_reserve(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
/* fallthrough, tiled memory */
case TTM_PL_VRAM:
mem->bus.offset = mem->start << PAGE_SHIFT;
- mem->bus.base = nv_device_resource_start(nvkm_device(&drm->device), 1);
+ mem->bus.base = nv_device_resource_start(nvxx_device(&drm->device), 1);
mem->bus.is_iomem = true;
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
- struct nouveau_bar *bar = nvkm_bar(&drm->device);
+ struct nvkm_bar *bar = nvxx_bar(&drm->device);
ret = bar->umap(bar, node, NV_MEM_ACCESS_RW,
&node->bar_vma);
@@ -1419,8 +1405,8 @@ static void
nouveau_ttm_io_mem_free(struct ttm_bo_device *bdev, struct ttm_mem_reg *mem)
{
struct nouveau_drm *drm = nouveau_bdev(bdev);
- struct nouveau_bar *bar = nvkm_bar(&drm->device);
- struct nouveau_mem *node = mem->mm_node;
+ struct nvkm_bar *bar = nvxx_bar(&drm->device);
+ struct nvkm_mem *node = mem->mm_node;
if (!node->bar_vma.node)
return;
@@ -1434,7 +1420,7 @@ nouveau_ttm_fault_reserve_notify(struct ttm_buffer_object *bo)
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
struct nvif_device *device = &drm->device;
- u32 mappable = nv_device_resource_len(nvkm_device(device), 1) >> PAGE_SHIFT;
+ u32 mappable = nv_device_resource_len(nvxx_device(device), 1) >> PAGE_SHIFT;
int i, ret;
/* as long as the bo isn't in vram, and isn't tiled, we've got
@@ -1479,7 +1465,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
{
struct ttm_dma_tt *ttm_dma = (void *)ttm;
struct nouveau_drm *drm;
- struct nouveau_device *device;
+ struct nvkm_device *device;
struct drm_device *dev;
struct device *pdev;
unsigned i;
@@ -1498,7 +1484,7 @@ nouveau_ttm_tt_populate(struct ttm_tt *ttm)
}
drm = nouveau_bdev(ttm->bdev);
- device = nvkm_device(&drm->device);
+ device = nvxx_device(&drm->device);
dev = drm->dev;
pdev = nv_device_base(device);
@@ -1553,7 +1539,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
{
struct ttm_dma_tt *ttm_dma = (void *)ttm;
struct nouveau_drm *drm;
- struct nouveau_device *device;
+ struct nvkm_device *device;
struct drm_device *dev;
struct device *pdev;
unsigned i;
@@ -1563,7 +1549,7 @@ nouveau_ttm_tt_unpopulate(struct ttm_tt *ttm)
return;
drm = nouveau_bdev(ttm->bdev);
- device = nvkm_device(&drm->device);
+ device = nvxx_device(&drm->device);
dev = drm->dev;
pdev = nv_device_base(device);
@@ -1627,10 +1613,10 @@ struct ttm_bo_driver nouveau_bo_driver = {
.io_mem_free = &nouveau_ttm_io_mem_free,
};
-struct nouveau_vma *
-nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nouveau_vm *vm)
+struct nvkm_vma *
+nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nvkm_vm *vm)
{
- struct nouveau_vma *vma;
+ struct nvkm_vma *vma;
list_for_each_entry(vma, &nvbo->vma_list, head) {
if (vma->vm == vm)
return vma;
@@ -1640,21 +1626,21 @@ nouveau_bo_vma_find(struct nouveau_bo *nvbo, struct nouveau_vm *vm)
}
int
-nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
- struct nouveau_vma *vma)
+nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nvkm_vm *vm,
+ struct nvkm_vma *vma)
{
const u32 size = nvbo->bo.mem.num_pages << PAGE_SHIFT;
int ret;
- ret = nouveau_vm_get(vm, size, nvbo->page_shift,
+ ret = nvkm_vm_get(vm, size, nvbo->page_shift,
NV_MEM_ACCESS_RW, vma);
if (ret)
return ret;
if ( nvbo->bo.mem.mem_type != TTM_PL_SYSTEM &&
(nvbo->bo.mem.mem_type == TTM_PL_VRAM ||
- nvbo->page_shift != vma->vm->vmm->lpg_shift))
- nouveau_vm_map(vma, nvbo->bo.mem.mm_node);
+ nvbo->page_shift != vma->vm->mmu->lpg_shift))
+ nvkm_vm_map(vma, nvbo->bo.mem.mm_node);
list_add_tail(&vma->head, &nvbo->vma_list);
vma->refcount = 1;
@@ -1662,12 +1648,12 @@ nouveau_bo_vma_add(struct nouveau_bo *nvbo, struct nouveau_vm *vm,
}
void
-nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+nouveau_bo_vma_del(struct nouveau_bo *nvbo, struct nvkm_vma *vma)
{
if (vma->node) {
if (nvbo->bo.mem.mem_type != TTM_PL_SYSTEM)
- nouveau_vm_unmap(vma);
- nouveau_vm_put(vma);
+ nvkm_vm_unmap(vma);
+ nvkm_vm_put(vma);
list_del(&vma->head);
}
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_bo.h b/drivers/gpu/drm/nouveau/nouveau_bo.h
index 072222efeeb7..e42360983229 100644
--- a/drivers/gpu/drm/nouveau/nouveau_bo.h
+++ b/drivers/gpu/drm/nouveau/nouveau_bo.h
@@ -5,7 +5,7 @@
struct nouveau_channel;
struct nouveau_fence;
-struct nouveau_vma;
+struct nvkm_vma;
struct nouveau_bo {
struct ttm_buffer_object bo;
@@ -78,7 +78,6 @@ int nouveau_bo_unpin(struct nouveau_bo *);
int nouveau_bo_map(struct nouveau_bo *);
void nouveau_bo_unmap(struct nouveau_bo *);
void nouveau_bo_placement_set(struct nouveau_bo *, u32 type, u32 busy);
-u16 nouveau_bo_rd16(struct nouveau_bo *, unsigned index);
void nouveau_bo_wr16(struct nouveau_bo *, unsigned index, u16 val);
u32 nouveau_bo_rd32(struct nouveau_bo *, unsigned index);
void nouveau_bo_wr32(struct nouveau_bo *, unsigned index, u32 val);
@@ -88,12 +87,12 @@ int nouveau_bo_validate(struct nouveau_bo *, bool interruptible,
void nouveau_bo_sync_for_device(struct nouveau_bo *nvbo);
void nouveau_bo_sync_for_cpu(struct nouveau_bo *nvbo);
-struct nouveau_vma *
-nouveau_bo_vma_find(struct nouveau_bo *, struct nouveau_vm *);
+struct nvkm_vma *
+nouveau_bo_vma_find(struct nouveau_bo *, struct nvkm_vm *);
-int nouveau_bo_vma_add(struct nouveau_bo *, struct nouveau_vm *,
- struct nouveau_vma *);
-void nouveau_bo_vma_del(struct nouveau_bo *, struct nouveau_vma *);
+int nouveau_bo_vma_add(struct nouveau_bo *, struct nvkm_vm *,
+ struct nvkm_vma *);
+void nouveau_bo_vma_del(struct nouveau_bo *, struct nvkm_vma *);
/* TODO: submit equivalent to TTM generic API upstream? */
static inline void __iomem *
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.c b/drivers/gpu/drm/nouveau/nouveau_chan.c
index aff9099aae6c..e581f63cbf25 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.c
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.c
@@ -54,7 +54,7 @@ nouveau_channel_idle(struct nouveau_channel *chan)
if (ret)
NV_PRINTK(error, cli, "failed to idle channel 0x%08x [%s]\n",
- chan->object->handle, nvkm_client(&cli->base)->name);
+ chan->object->handle, nvxx_client(&cli->base)->name);
return ret;
}
@@ -88,7 +88,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
u32 handle, u32 size, struct nouveau_channel **pchan)
{
struct nouveau_cli *cli = (void *)nvif_client(&device->base);
- struct nouveau_vmmgr *vmm = nvkm_vmmgr(device);
+ struct nvkm_mmu *mmu = nvxx_mmu(device);
struct nv_dma_v0 args = {};
struct nouveau_channel *chan;
u32 target;
@@ -136,7 +136,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_VM;
args.start = 0;
- args.limit = cli->vm->vmm->limit - 1;
+ args.limit = cli->vm->mmu->limit - 1;
} else
if (chan->push.buffer->bo.mem.mem_type == TTM_PL_VRAM) {
if (device->info.family == NV_DEVICE_INFO_V0_TNT) {
@@ -146,7 +146,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
*/
args.target = NV_DMA_V0_TARGET_PCI;
args.access = NV_DMA_V0_ACCESS_RDWR;
- args.start = nv_device_resource_start(nvkm_device(device), 1);
+ args.start = nv_device_resource_start(nvxx_device(device), 1);
args.limit = args.start + device->info.ram_user - 1;
} else {
args.target = NV_DMA_V0_TARGET_VRAM;
@@ -165,7 +165,7 @@ nouveau_channel_prep(struct nouveau_drm *drm, struct nvif_device *device,
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_RDWR;
args.start = 0;
- args.limit = vmm->limit - 1;
+ args.limit = mmu->limit - 1;
}
}
@@ -281,8 +281,8 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
{
struct nvif_device *device = chan->device;
struct nouveau_cli *cli = (void *)nvif_client(&device->base);
- struct nouveau_vmmgr *vmm = nvkm_vmmgr(device);
- struct nouveau_software_chan *swch;
+ struct nvkm_mmu *mmu = nvxx_mmu(device);
+ struct nvkm_sw_chan *swch;
struct nv_dma_v0 args = {};
int ret, i;
@@ -294,7 +294,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_VM;
args.start = 0;
- args.limit = cli->vm->vmm->limit - 1;
+ args.limit = cli->vm->mmu->limit - 1;
} else {
args.target = NV_DMA_V0_TARGET_VRAM;
args.access = NV_DMA_V0_ACCESS_RDWR;
@@ -312,7 +312,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_VM;
args.start = 0;
- args.limit = cli->vm->vmm->limit - 1;
+ args.limit = cli->vm->mmu->limit - 1;
} else
if (chan->drm->agp.stat == ENABLED) {
args.target = NV_DMA_V0_TARGET_AGP;
@@ -324,7 +324,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
args.target = NV_DMA_V0_TARGET_VM;
args.access = NV_DMA_V0_ACCESS_RDWR;
args.start = 0;
- args.limit = vmm->limit - 1;
+ args.limit = mmu->limit - 1;
}
ret = nvif_object_init(chan->object, NULL, gart,
@@ -372,7 +372,7 @@ nouveau_channel_init(struct nouveau_channel *chan, u32 vram, u32 gart)
if (ret)
return ret;
- swch = (void *)nvkm_object(&chan->nvsw)->parent;
+ swch = (void *)nvxx_object(&chan->nvsw)->parent;
swch->flip = nouveau_flip_complete;
swch->flip_data = chan;
diff --git a/drivers/gpu/drm/nouveau/nouveau_chan.h b/drivers/gpu/drm/nouveau/nouveau_chan.h
index 8309c24ee698..8b3640f69e4f 100644
--- a/drivers/gpu/drm/nouveau/nouveau_chan.h
+++ b/drivers/gpu/drm/nouveau/nouveau_chan.h
@@ -16,7 +16,7 @@ struct nouveau_channel {
struct {
struct nouveau_bo *buffer;
- struct nouveau_vma vma;
+ struct nvkm_vma vma;
struct nvif_object ctxdma;
} push;
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.c b/drivers/gpu/drm/nouveau/nouveau_connector.c
index c8ac9482cf2e..db7095ae4ebb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.c
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.c
@@ -115,7 +115,7 @@ nouveau_connector_ddc_detect(struct drm_connector *connector)
struct drm_device *dev = connector->dev;
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_gpio *gpio = nvkm_gpio(&drm->device);
+ struct nvkm_gpio *gpio = nvxx_gpio(&drm->device);
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
int i, panel = -ENODEV;
@@ -241,7 +241,7 @@ nouveau_connector_detect(struct drm_connector *connector, bool force)
struct nouveau_connector *nv_connector = nouveau_connector(connector);
struct nouveau_encoder *nv_encoder = NULL;
struct nouveau_encoder *nv_partner;
- struct nouveau_i2c_port *i2c;
+ struct nvkm_i2c_port *i2c;
int type;
int ret;
enum drm_connector_status conn_status = connector_status_disconnected;
@@ -458,6 +458,28 @@ nouveau_connector_set_property(struct drm_connector *connector,
switch (value) {
case DRM_MODE_SCALE_NONE:
+ /* We allow 'None' for EDID modes, even on a fixed
+ * panel (some exist with support for lower refresh
+ * rates, which people might want to use for power
+ * saving purposes).
+ *
+ * Non-EDID modes will force the use of GPU scaling
+ * to the native mode regardless of this setting.
+ */
+ switch (nv_connector->type) {
+ case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
+ case DCB_CONNECTOR_eDP:
+ /* ... except prior to G80, where the code
+ * doesn't support such things.
+ */
+ if (disp->disp.oclass < NV50_DISP)
+ return -EINVAL;
+ break;
+ default:
+ break;
+ }
+ break;
case DRM_MODE_SCALE_FULLSCREEN:
case DRM_MODE_SCALE_CENTER:
case DRM_MODE_SCALE_ASPECT:
@@ -466,11 +488,6 @@ nouveau_connector_set_property(struct drm_connector *connector,
return -EINVAL;
}
- /* LVDS always needs gpu scaling */
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS &&
- value == DRM_MODE_SCALE_NONE)
- return -EINVAL;
-
/* Changing between GPU and panel scaling requires a full
* modeset
*/
@@ -655,15 +672,15 @@ nouveau_connector_scaler_modes_add(struct drm_connector *connector)
while (mode->hdisplay) {
if (mode->hdisplay <= native->hdisplay &&
- mode->vdisplay <= native->vdisplay) {
+ mode->vdisplay <= native->vdisplay &&
+ (mode->hdisplay != native->hdisplay ||
+ mode->vdisplay != native->vdisplay)) {
m = drm_cvt_mode(dev, mode->hdisplay, mode->vdisplay,
drm_mode_vrefresh(native), false,
false, false);
if (!m)
continue;
- m->type |= DRM_MODE_TYPE_DRIVER;
-
drm_mode_probed_add(connector, m);
modes++;
}
@@ -968,7 +985,7 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
struct nouveau_connector *nv_connector =
container_of(aux, typeof(*nv_connector), aux);
struct nouveau_encoder *nv_encoder;
- struct nouveau_i2c_port *port;
+ struct nvkm_i2c_port *port;
int ret;
nv_encoder = find_encoder(&nv_connector->base, DCB_OUTPUT_DP);
@@ -979,13 +996,13 @@ nouveau_connector_aux_xfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
if (msg->size == 0)
return msg->size;
- ret = nouveau_i2c(port)->acquire(port, 0);
+ ret = nvkm_i2c(port)->acquire(port, 0);
if (ret)
return ret;
ret = port->func->aux(port, false, msg->request, msg->address,
msg->buffer, msg->size);
- nouveau_i2c(port)->release(port);
+ nvkm_i2c(port)->release(port);
if (ret >= 0) {
msg->reply = ret;
return msg->size;
@@ -1180,36 +1197,61 @@ nouveau_connector_create(struct drm_device *dev, int index)
disp->color_vibrance_property,
150);
+ /* default scaling mode */
switch (nv_connector->type) {
- case DCB_CONNECTOR_VGA:
- if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
- drm_object_attach_property(&connector->base,
- dev->mode_config.scaling_mode_property,
- nv_connector->scaling_mode);
+ case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
+ case DCB_CONNECTOR_eDP:
+ /* see note in nouveau_connector_set_property() */
+ if (disp->disp.oclass < NV50_DISP) {
+ nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
+ break;
}
- /* fall-through */
+ nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
+ break;
+ default:
+ nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
+ break;
+ }
+
+ /* scaling mode property */
+ switch (nv_connector->type) {
case DCB_CONNECTOR_TV_0:
case DCB_CONNECTOR_TV_1:
case DCB_CONNECTOR_TV_3:
- nv_connector->scaling_mode = DRM_MODE_SCALE_NONE;
break;
+ case DCB_CONNECTOR_VGA:
+ if (disp->disp.oclass < NV50_DISP)
+ break; /* can only scale on DFPs */
+ /* fall-through */
default:
- nv_connector->scaling_mode = DRM_MODE_SCALE_FULLSCREEN;
+ drm_object_attach_property(&connector->base, dev->mode_config.
+ scaling_mode_property,
+ nv_connector->scaling_mode);
+ break;
+ }
- drm_object_attach_property(&connector->base,
- dev->mode_config.scaling_mode_property,
- nv_connector->scaling_mode);
+ /* dithering properties */
+ switch (nv_connector->type) {
+ case DCB_CONNECTOR_TV_0:
+ case DCB_CONNECTOR_TV_1:
+ case DCB_CONNECTOR_TV_3:
+ case DCB_CONNECTOR_VGA:
+ break;
+ default:
if (disp->dithering_mode) {
- nv_connector->dithering_mode = DITHERING_MODE_AUTO;
drm_object_attach_property(&connector->base,
- disp->dithering_mode,
- nv_connector->dithering_mode);
+ disp->dithering_mode,
+ nv_connector->
+ dithering_mode);
+ nv_connector->dithering_mode = DITHERING_MODE_AUTO;
}
if (disp->dithering_depth) {
- nv_connector->dithering_depth = DITHERING_DEPTH_AUTO;
drm_object_attach_property(&connector->base,
- disp->dithering_depth,
- nv_connector->dithering_depth);
+ disp->dithering_depth,
+ nv_connector->
+ dithering_depth);
+ nv_connector->dithering_depth = DITHERING_DEPTH_AUTO;
}
break;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_connector.h b/drivers/gpu/drm/nouveau/nouveau_connector.h
index 629a380c7085..7446ee66ea04 100644
--- a/drivers/gpu/drm/nouveau/nouveau_connector.h
+++ b/drivers/gpu/drm/nouveau/nouveau_connector.h
@@ -33,7 +33,7 @@
#include <drm/drm_dp_helper.h>
#include "nouveau_crtc.h"
-struct nouveau_i2c_port;
+struct nvkm_i2c_port;
enum nouveau_underscan_type {
UNDERSCAN_OFF,
@@ -72,6 +72,7 @@ struct nouveau_connector {
int dithering_mode;
int dithering_depth;
int scaling_mode;
+ bool scaling_full;
enum nouveau_underscan_type underscan;
u32 underscan_hborder;
u32 underscan_vborder;
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.c b/drivers/gpu/drm/nouveau/nouveau_display.c
index f8042433752b..860b0e2d4181 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.c
+++ b/drivers/gpu/drm/nouveau/nouveau_display.c
@@ -450,7 +450,7 @@ nouveau_display_create(struct drm_device *dev)
drm_mode_create_dvi_i_properties(dev);
dev->mode_config.funcs = &nouveau_mode_config_funcs;
- dev->mode_config.fb_base = nv_device_resource_start(nvkm_device(&drm->device), 1);
+ dev->mode_config.fb_base = nv_device_resource_start(nvxx_device(&drm->device), 1);
dev->mode_config.min_width = 0;
dev->mode_config.min_height = 0;
@@ -570,7 +570,8 @@ nouveau_display_suspend(struct drm_device *dev, bool runtime)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
if (nv_crtc->cursor.nvbo) {
- nouveau_bo_unmap(nv_crtc->cursor.nvbo);
+ if (nv_crtc->cursor.set_offset)
+ nouveau_bo_unmap(nv_crtc->cursor.nvbo);
nouveau_bo_unpin(nv_crtc->cursor.nvbo);
}
}
@@ -604,7 +605,7 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
continue;
ret = nouveau_bo_pin(nv_crtc->cursor.nvbo, TTM_PL_FLAG_VRAM, true);
- if (!ret)
+ if (!ret && nv_crtc->cursor.set_offset)
ret = nouveau_bo_map(nv_crtc->cursor.nvbo);
if (ret)
NV_ERROR(drm, "Could not pin/map cursor.\n");
@@ -637,7 +638,9 @@ nouveau_display_resume(struct drm_device *dev, bool runtime)
if (!nv_crtc->cursor.nvbo)
continue;
- nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
+
+ if (nv_crtc->cursor.set_offset)
+ nv_crtc->cursor.set_offset(nv_crtc, nv_crtc->cursor.nvbo->bo.offset);
nv_crtc->cursor.set_pos(nv_crtc, nv_crtc->cursor_saved_x,
nv_crtc->cursor_saved_y);
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_display.h b/drivers/gpu/drm/nouveau/nouveau_display.h
index be3d5947c6be..a6213e2425c5 100644
--- a/drivers/gpu/drm/nouveau/nouveau_display.h
+++ b/drivers/gpu/drm/nouveau/nouveau_display.h
@@ -1,14 +1,14 @@
#ifndef __NOUVEAU_DISPLAY_H__
#define __NOUVEAU_DISPLAY_H__
-#include <subdev/vm.h>
+#include <subdev/mmu.h>
#include "nouveau_drm.h"
struct nouveau_framebuffer {
struct drm_framebuffer base;
struct nouveau_bo *nvbo;
- struct nouveau_vma vma;
+ struct nvkm_vma vma;
u32 r_handle;
u32 r_format;
u32 r_pitch;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dma.c b/drivers/gpu/drm/nouveau/nouveau_dma.c
index 8508603cc8c3..6d9245aa81a6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dma.c
@@ -84,7 +84,7 @@ nv50_dma_push(struct nouveau_channel *chan, struct nouveau_bo *bo,
{
struct nouveau_cli *cli = (void *)nvif_client(&chan->device->base);
struct nouveau_bo *pb = chan->push.buffer;
- struct nouveau_vma *vma;
+ struct nvkm_vma *vma;
int ip = (chan->dma.ib_put * 2) + chan->dma.ib_base;
u64 offset;
diff --git a/drivers/gpu/drm/nouveau/nouveau_dp.c b/drivers/gpu/drm/nouveau/nouveau_dp.c
index c5137cccce7d..c3ef30b3a5ec 100644
--- a/drivers/gpu/drm/nouveau/nouveau_dp.c
+++ b/drivers/gpu/drm/nouveau/nouveau_dp.c
@@ -31,7 +31,7 @@
#include "nouveau_crtc.h"
static void
-nouveau_dp_probe_oui(struct drm_device *dev, struct nouveau_i2c_port *auxch,
+nouveau_dp_probe_oui(struct drm_device *dev, struct nvkm_i2c_port *auxch,
u8 *dpcd)
{
struct nouveau_drm *drm = nouveau_drm(dev);
@@ -55,7 +55,7 @@ nouveau_dp_detect(struct nouveau_encoder *nv_encoder)
{
struct drm_device *dev = nv_encoder->base.base.dev;
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_i2c_port *auxch;
+ struct nvkm_i2c_port *auxch;
u8 *dpcd = nv_encoder->dp.dpcd;
int ret;
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.c b/drivers/gpu/drm/nouveau/nouveau_drm.c
index 65910e3aed0c..8763deb5188b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.c
@@ -52,6 +52,7 @@
#include "nouveau_debugfs.h"
#include "nouveau_usif.h"
#include "nouveau_connector.h"
+#include "nouveau_platform.h"
MODULE_PARM_DESC(config, "option string to pass to driver core");
static char *nouveau_config;
@@ -123,7 +124,7 @@ nouveau_cli_create(u64 name, const char *sname,
static void
nouveau_cli_destroy(struct nouveau_cli *cli)
{
- nouveau_vm_ref(NULL, &nvkm_client(&cli->base)->vm, NULL);
+ nvkm_vm_ref(NULL, &nvxx_client(&cli->base)->vm, NULL);
nvif_client_fini(&cli->base);
usif_client_fini(cli);
}
@@ -133,7 +134,7 @@ nouveau_accel_fini(struct nouveau_drm *drm)
{
nouveau_channel_del(&drm->channel);
nvif_object_fini(&drm->ntfy);
- nouveau_gpuobj_ref(NULL, &drm->notify);
+ nvkm_gpuobj_ref(NULL, &drm->notify);
nvif_object_fini(&drm->nvsw);
nouveau_channel_del(&drm->cechan);
nvif_object_fini(&drm->ttm.copy);
@@ -230,7 +231,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
ret = nvif_object_init(drm->channel->object, NULL, NVDRM_NVSW,
nouveau_abi16_swclass(drm), NULL, 0, &drm->nvsw);
if (ret == 0) {
- struct nouveau_software_chan *swch;
+ struct nvkm_sw_chan *swch;
ret = RING_SPACE(drm->channel, 2);
if (ret == 0) {
if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
@@ -242,7 +243,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
OUT_RING (drm->channel, 0x001f0000);
}
}
- swch = (void *)nvkm_object(&drm->nvsw)->parent;
+ swch = (void *)nvxx_object(&drm->nvsw)->parent;
swch->flip = nouveau_flip_complete;
swch->flip_data = drm->channel;
}
@@ -254,8 +255,8 @@ nouveau_accel_init(struct nouveau_drm *drm)
}
if (device->info.family < NV_DEVICE_INFO_V0_FERMI) {
- ret = nouveau_gpuobj_new(nvkm_object(&drm->device), NULL, 32,
- 0, 0, &drm->notify);
+ ret = nvkm_gpuobj_new(nvxx_object(&drm->device), NULL, 32,
+ 0, 0, &drm->notify);
if (ret) {
NV_ERROR(drm, "failed to allocate notifier, %d\n", ret);
nouveau_accel_fini(drm);
@@ -284,7 +285,7 @@ nouveau_accel_init(struct nouveau_drm *drm)
static int nouveau_drm_probe(struct pci_dev *pdev,
const struct pci_device_id *pent)
{
- struct nouveau_device *device;
+ struct nvkm_device *device;
struct apertures_struct *aper;
bool boot = false;
int ret;
@@ -317,9 +318,9 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
remove_conflicting_framebuffers(aper, "nouveaufb", boot);
kfree(aper);
- ret = nouveau_device_create(pdev, NOUVEAU_BUS_PCI,
- nouveau_pci_name(pdev), pci_name(pdev),
- nouveau_config, nouveau_debug, &device);
+ ret = nvkm_device_create(pdev, NVKM_BUS_PCI,
+ nouveau_pci_name(pdev), pci_name(pdev),
+ nouveau_config, nouveau_debug, &device);
if (ret)
return ret;
@@ -327,7 +328,7 @@ static int nouveau_drm_probe(struct pci_dev *pdev,
ret = drm_get_pci_dev(pdev, pent, &driver_pci);
if (ret) {
- nouveau_object_ref(NULL, (struct nouveau_object **)&device);
+ nvkm_object_ref(NULL, (struct nvkm_object **)&device);
return ret;
}
@@ -378,8 +379,8 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
dev->dev_private = drm;
drm->dev = dev;
- nvkm_client(&drm->client.base)->debug =
- nouveau_dbgopt(nouveau_debug, "DRM");
+ nvxx_client(&drm->client.base)->debug =
+ nvkm_dbgopt(nouveau_debug, "DRM");
INIT_LIST_HEAD(&drm->clients);
spin_lock_init(&drm->tile.lock);
@@ -434,12 +435,12 @@ nouveau_drm_load(struct drm_device *dev, unsigned long flags)
nouveau_agp_init(drm);
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
- ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40),
- 0x1000, &drm->client.vm);
+ ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
+ 0x1000, &drm->client.vm);
if (ret)
goto fail_device;
- nvkm_client(&drm->client.base)->vm = drm->client.vm;
+ nvxx_client(&drm->client.base)->vm = drm->client.vm;
}
ret = nouveau_ttm_init(drm);
@@ -522,18 +523,17 @@ void
nouveau_drm_device_remove(struct drm_device *dev)
{
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_client *client;
- struct nouveau_object *device;
+ struct nvkm_client *client;
+ struct nvkm_object *device;
dev->irq_enabled = false;
- client = nvkm_client(&drm->client.base);
+ client = nvxx_client(&drm->client.base);
device = client->device;
drm_put_dev(dev);
- nouveau_object_ref(NULL, &device);
- nouveau_object_debug();
+ nvkm_object_ref(NULL, &device);
+ nvkm_object_debug();
}
-EXPORT_SYMBOL(nouveau_drm_device_remove);
static void
nouveau_drm_remove(struct pci_dev *pdev)
@@ -831,14 +831,14 @@ nouveau_drm_open(struct drm_device *dev, struct drm_file *fpriv)
cli->base.super = false;
if (drm->device.info.family >= NV_DEVICE_INFO_V0_TESLA) {
- ret = nouveau_vm_new(nvkm_device(&drm->device), 0, (1ULL << 40),
- 0x1000, &cli->vm);
+ ret = nvkm_vm_new(nvxx_device(&drm->device), 0, (1ULL << 40),
+ 0x1000, &cli->vm);
if (ret) {
nouveau_cli_destroy(cli);
goto out_suspend;
}
- nvkm_client(&cli->base)->vm = cli->vm;
+ nvxx_client(&cli->base)->vm = cli->vm;
}
fpriv->driver_priv = cli;
@@ -1056,10 +1056,10 @@ nouveau_platform_device_create_(struct platform_device *pdev, int size,
struct drm_device *drm;
int err;
- err = nouveau_device_create_(pdev, NOUVEAU_BUS_PLATFORM,
- nouveau_platform_name(pdev),
- dev_name(&pdev->dev), nouveau_config,
- nouveau_debug, size, pobject);
+ err = nvkm_device_create_(pdev, NVKM_BUS_PLATFORM,
+ nouveau_platform_name(pdev),
+ dev_name(&pdev->dev), nouveau_config,
+ nouveau_debug, size, pobject);
if (err)
return ERR_PTR(err);
@@ -1079,11 +1079,10 @@ nouveau_platform_device_create_(struct platform_device *pdev, int size,
return drm;
err_free:
- nouveau_object_ref(NULL, (struct nouveau_object **)pobject);
+ nvkm_object_ref(NULL, (struct nvkm_object **)pobject);
return ERR_PTR(err);
}
-EXPORT_SYMBOL(nouveau_platform_device_create_);
static int __init
nouveau_drm_init(void)
@@ -1105,6 +1104,10 @@ nouveau_drm_init(void)
if (!nouveau_modeset)
return 0;
+#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
+ platform_driver_register(&nouveau_platform_driver);
+#endif
+
nouveau_register_dsm_handler();
return drm_pci_init(&driver_pci, &nouveau_drm_pci_driver);
}
@@ -1117,6 +1120,10 @@ nouveau_drm_exit(void)
drm_pci_exit(&driver_pci, &nouveau_drm_pci_driver);
nouveau_unregister_dsm_handler();
+
+#ifdef CONFIG_NOUVEAU_PLATFORM_DRIVER
+ platform_driver_unregister(&nouveau_platform_driver);
+#endif
}
module_init(nouveau_drm_init);
diff --git a/drivers/gpu/drm/nouveau/nouveau_drm.h b/drivers/gpu/drm/nouveau/nouveau_drm.h
index 8ae36f265fb8..fc68f0973f9e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_drm.h
+++ b/drivers/gpu/drm/nouveau/nouveau_drm.h
@@ -80,7 +80,7 @@ enum nouveau_drm_handle {
struct nouveau_cli {
struct nvif_client base;
- struct nouveau_vm *vm; /*XXX*/
+ struct nvkm_vm *vm; /*XXX*/
struct list_head head;
struct mutex mutex;
void *abi16;
@@ -142,7 +142,7 @@ struct nouveau_drm {
/* context for accelerated drm-internal operations */
struct nouveau_channel *cechan;
struct nouveau_channel *channel;
- struct nouveau_gpuobj *notify;
+ struct nvkm_gpuobj *notify;
struct nouveau_fbdev *fbcon;
struct nvif_object nvsw;
struct nvif_object ntfy;
diff --git a/drivers/gpu/drm/nouveau/nouveau_encoder.h b/drivers/gpu/drm/nouveau/nouveau_encoder.h
index 5f0e37fc2849..c57a37e8e1eb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_encoder.h
+++ b/drivers/gpu/drm/nouveau/nouveau_encoder.h
@@ -34,14 +34,14 @@
#define NV_DPMS_CLEARED 0x80
-struct nouveau_i2c_port;
+struct nvkm_i2c_port;
struct nouveau_encoder {
struct drm_encoder_slave base;
struct dcb_output *dcb;
int or;
- struct nouveau_i2c_port *i2c;
+ struct nvkm_i2c_port *i2c;
/* different to drm_encoder.crtc, this reflects what's
* actually programmed on the hw, not the proposed crtc */
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.c b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
index 3ed12a8cfc91..79924e4b1b49 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.c
@@ -370,6 +370,7 @@ nouveau_fbcon_create(struct drm_fb_helper *helper,
ret = -ENOMEM;
goto out_unlock;
}
+ info->skip_vt_switch = 1;
ret = fb_alloc_cmap(&info->cmap, 256, 0);
if (ret) {
@@ -487,30 +488,17 @@ static const struct drm_fb_helper_funcs nouveau_fbcon_helper_funcs = {
.fb_probe = nouveau_fbcon_create,
};
-static void
-nouveau_fbcon_set_suspend_work(struct work_struct *work)
-{
- struct nouveau_fbdev *fbcon = container_of(work, typeof(*fbcon), work);
- console_lock();
- nouveau_fbcon_accel_restore(fbcon->dev);
- nouveau_fbcon_zfill(fbcon->dev, fbcon);
- fb_set_suspend(fbcon->helper.fbdev, FBINFO_STATE_RUNNING);
- console_unlock();
-}
-
void
nouveau_fbcon_set_suspend(struct drm_device *dev, int state)
{
struct nouveau_drm *drm = nouveau_drm(dev);
if (drm->fbcon) {
- if (state == FBINFO_STATE_RUNNING) {
- schedule_work(&drm->fbcon->work);
- return;
- }
- flush_work(&drm->fbcon->work);
console_lock();
+ if (state == FBINFO_STATE_RUNNING)
+ nouveau_fbcon_accel_restore(dev);
fb_set_suspend(drm->fbcon->helper.fbdev, state);
- nouveau_fbcon_accel_save_disable(dev);
+ if (state != FBINFO_STATE_RUNNING)
+ nouveau_fbcon_accel_save_disable(dev);
console_unlock();
}
}
@@ -531,7 +519,6 @@ nouveau_fbcon_init(struct drm_device *dev)
if (!fbcon)
return -ENOMEM;
- INIT_WORK(&fbcon->work, nouveau_fbcon_set_suspend_work);
fbcon->dev = dev;
drm->fbcon = fbcon;
@@ -539,12 +526,12 @@ nouveau_fbcon_init(struct drm_device *dev)
ret = drm_fb_helper_init(dev, &fbcon->helper,
dev->mode_config.num_crtc, 4);
- if (ret) {
- kfree(fbcon);
- return ret;
- }
+ if (ret)
+ goto free;
- drm_fb_helper_single_add_all_connectors(&fbcon->helper);
+ ret = drm_fb_helper_single_add_all_connectors(&fbcon->helper);
+ if (ret)
+ goto fini;
if (drm->device.info.ram_size <= 32 * 1024 * 1024)
preferred_bpp = 8;
@@ -557,8 +544,17 @@ nouveau_fbcon_init(struct drm_device *dev)
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
- drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
+ ret = drm_fb_helper_initial_config(&fbcon->helper, preferred_bpp);
+ if (ret)
+ goto fini;
+
return 0;
+
+fini:
+ drm_fb_helper_fini(&fbcon->helper);
+free:
+ kfree(fbcon);
+ return ret;
}
void
diff --git a/drivers/gpu/drm/nouveau/nouveau_fbcon.h b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
index 6208e70e4a1c..1e2e9e27a03b 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fbcon.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fbcon.h
@@ -36,7 +36,6 @@ struct nouveau_fbdev {
struct nouveau_framebuffer nouveau_fb;
struct list_head fbdev_list;
struct drm_device *dev;
- struct work_struct work;
unsigned int saved_flags;
struct nvif_object surf2d;
struct nvif_object clip;
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.c b/drivers/gpu/drm/nouveau/nouveau_fence.c
index f32a434724e3..c6d56bef5823 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.c
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.c
@@ -182,7 +182,7 @@ nouveau_fence_context_new(struct nouveau_channel *chan, struct nouveau_fence_cha
else if (chan == chan->drm->channel)
strcpy(fctx->name, "generic kernel channel");
else
- strcpy(fctx->name, nvkm_client(&cli->base)->name);
+ strcpy(fctx->name, nvxx_client(&cli->base)->name);
kref_init(&fctx->fence_ref);
if (!priv->uevent)
diff --git a/drivers/gpu/drm/nouveau/nouveau_fence.h b/drivers/gpu/drm/nouveau/nouveau_fence.h
index 96e461c6f68f..d9241d8247fb 100644
--- a/drivers/gpu/drm/nouveau/nouveau_fence.h
+++ b/drivers/gpu/drm/nouveau/nouveau_fence.h
@@ -89,9 +89,9 @@ int nouveau_flip_complete(void *chan);
struct nv84_fence_chan {
struct nouveau_fence_chan base;
- struct nouveau_vma vma;
- struct nouveau_vma vma_gart;
- struct nouveau_vma dispc_vma[4];
+ struct nvkm_vma vma;
+ struct nvkm_vma vma_gart;
+ struct nvkm_vma dispc_vma[4];
};
struct nv84_fence_priv {
diff --git a/drivers/gpu/drm/nouveau/nouveau_gem.c b/drivers/gpu/drm/nouveau/nouveau_gem.c
index bf0f9e21d714..7c077fced1d1 100644
--- a/drivers/gpu/drm/nouveau/nouveau_gem.c
+++ b/drivers/gpu/drm/nouveau/nouveau_gem.c
@@ -64,7 +64,7 @@ nouveau_gem_object_open(struct drm_gem_object *gem, struct drm_file *file_priv)
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
- struct nouveau_vma *vma;
+ struct nvkm_vma *vma;
struct device *dev = drm->dev->dev;
int ret;
@@ -105,14 +105,14 @@ out:
static void
nouveau_gem_object_delete(void *data)
{
- struct nouveau_vma *vma = data;
- nouveau_vm_unmap(vma);
- nouveau_vm_put(vma);
+ struct nvkm_vma *vma = data;
+ nvkm_vm_unmap(vma);
+ nvkm_vm_put(vma);
kfree(vma);
}
static void
-nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
+nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nvkm_vma *vma)
{
const bool mapped = nvbo->bo.mem.mem_type != TTM_PL_SYSTEM;
struct reservation_object *resv = nvbo->bo.resv;
@@ -135,8 +135,8 @@ nouveau_gem_object_unmap(struct nouveau_bo *nvbo, struct nouveau_vma *vma)
nouveau_fence_work(fence, nouveau_gem_object_delete, vma);
} else {
if (mapped)
- nouveau_vm_unmap(vma);
- nouveau_vm_put(vma);
+ nvkm_vm_unmap(vma);
+ nvkm_vm_put(vma);
kfree(vma);
}
}
@@ -148,7 +148,7 @@ nouveau_gem_object_close(struct drm_gem_object *gem, struct drm_file *file_priv)
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
struct nouveau_drm *drm = nouveau_bdev(nvbo->bo.bdev);
struct device *dev = drm->dev->dev;
- struct nouveau_vma *vma;
+ struct nvkm_vma *vma;
int ret;
if (!cli->vm)
@@ -222,7 +222,7 @@ nouveau_gem_info(struct drm_file *file_priv, struct drm_gem_object *gem,
{
struct nouveau_cli *cli = nouveau_cli(file_priv);
struct nouveau_bo *nvbo = nouveau_gem_object(gem);
- struct nouveau_vma *vma;
+ struct nvkm_vma *vma;
if (nvbo->bo.mem.mem_type == TTM_PL_TT)
rep->domain = NOUVEAU_GEM_DOMAIN_GART;
@@ -251,7 +251,7 @@ nouveau_gem_ioctl_new(struct drm_device *dev, void *data,
{
struct nouveau_drm *drm = nouveau_drm(dev);
struct nouveau_cli *cli = nouveau_cli(file_priv);
- struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+ struct nvkm_fb *pfb = nvxx_fb(&drm->device);
struct drm_nouveau_gem_new *req = data;
struct nouveau_bo *nvbo = NULL;
int ret = 0;
@@ -850,19 +850,6 @@ out_next:
return nouveau_abi16_put(abi16, ret);
}
-static inline uint32_t
-domain_to_ttm(struct nouveau_bo *nvbo, uint32_t domain)
-{
- uint32_t flags = 0;
-
- if (domain & NOUVEAU_GEM_DOMAIN_VRAM)
- flags |= TTM_PL_FLAG_VRAM;
- if (domain & NOUVEAU_GEM_DOMAIN_GART)
- flags |= TTM_PL_FLAG_TT;
-
- return flags;
-}
-
int
nouveau_gem_ioctl_cpu_prep(struct drm_device *dev, void *data,
struct drm_file *file_priv)
diff --git a/drivers/gpu/drm/nouveau/nouveau_hwmon.c b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
index afb36d66e78d..0dbe0060f86e 100644
--- a/drivers/gpu/drm/nouveau/nouveau_hwmon.c
+++ b/drivers/gpu/drm/nouveau/nouveau_hwmon.c
@@ -40,7 +40,7 @@ nouveau_hwmon_show_temp(struct device *d, struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
int temp = therm->temp_get(therm);
if (temp < 0)
@@ -66,10 +66,10 @@ nouveau_hwmon_temp1_auto_point1_temp(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST) * 1000);
}
static ssize_t
nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
@@ -78,13 +78,13 @@ nouveau_hwmon_set_temp1_auto_point1_temp(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST,
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST,
value / 1000);
return count;
@@ -99,10 +99,10 @@ nouveau_hwmon_temp1_auto_point1_temp_hyst(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST) * 1000);
}
static ssize_t
nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
@@ -111,13 +111,13 @@ nouveau_hwmon_set_temp1_auto_point1_temp_hyst(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_FAN_BOOST_HYST,
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST,
value / 1000);
return count;
@@ -131,10 +131,10 @@ nouveau_hwmon_max_temp(struct device *d, struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK) * 1000);
}
static ssize_t
nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
@@ -142,13 +142,13 @@ nouveau_hwmon_set_max_temp(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK, value / 1000);
return count;
}
@@ -162,10 +162,10 @@ nouveau_hwmon_max_temp_hyst(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST) * 1000);
}
static ssize_t
nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a,
@@ -173,13 +173,13 @@ nouveau_hwmon_set_max_temp_hyst(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_DOWN_CLK_HYST,
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST,
value / 1000);
return count;
@@ -194,10 +194,10 @@ nouveau_hwmon_critical_temp(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL) * 1000);
}
static ssize_t
nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
@@ -206,13 +206,13 @@ nouveau_hwmon_set_critical_temp(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL, value / 1000);
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL, value / 1000);
return count;
}
@@ -227,10 +227,10 @@ nouveau_hwmon_critical_temp_hyst(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST) * 1000);
}
static ssize_t
nouveau_hwmon_set_critical_temp_hyst(struct device *d,
@@ -240,13 +240,13 @@ nouveau_hwmon_set_critical_temp_hyst(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_CRITICAL_HYST,
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_CRITICAL_HYST,
value / 1000);
return count;
@@ -260,10 +260,10 @@ nouveau_hwmon_emergency_temp(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN) * 1000);
}
static ssize_t
nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a,
@@ -272,13 +272,13 @@ nouveau_hwmon_set_emergency_temp(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN, value / 1000);
return count;
}
@@ -293,10 +293,10 @@ nouveau_hwmon_emergency_temp_hyst(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n",
- therm->attr_get(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
+ therm->attr_get(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST) * 1000);
}
static ssize_t
nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
@@ -306,13 +306,13 @@ nouveau_hwmon_set_emergency_temp_hyst(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
if (kstrtol(buf, 10, &value) == -EINVAL)
return count;
- therm->attr_set(therm, NOUVEAU_THERM_ATTR_THRS_SHUTDOWN_HYST,
+ therm->attr_set(therm, NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST,
value / 1000);
return count;
@@ -346,7 +346,7 @@ nouveau_hwmon_show_fan1_input(struct device *d, struct device_attribute *attr,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
return snprintf(buf, PAGE_SIZE, "%d\n", therm->fan_sense(therm));
}
@@ -359,10 +359,10 @@ nouveau_hwmon_get_pwm1_enable(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
int ret;
- ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MODE);
+ ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MODE);
if (ret < 0)
return ret;
@@ -375,7 +375,7 @@ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
int ret;
@@ -383,7 +383,7 @@ nouveau_hwmon_set_pwm1_enable(struct device *d, struct device_attribute *a,
if (ret)
return ret;
- ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MODE, value);
+ ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MODE, value);
if (ret)
return ret;
else
@@ -398,7 +398,7 @@ nouveau_hwmon_get_pwm1(struct device *d, struct device_attribute *a, char *buf)
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
int ret;
ret = therm->fan_get(therm);
@@ -414,7 +414,7 @@ nouveau_hwmon_set_pwm1(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
int ret = -ENODEV;
long value;
@@ -438,10 +438,10 @@ nouveau_hwmon_get_pwm1_min(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
int ret;
- ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY);
+ ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY);
if (ret < 0)
return ret;
@@ -454,14 +454,14 @@ nouveau_hwmon_set_pwm1_min(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
int ret;
if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
- ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MIN_DUTY, value);
+ ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MIN_DUTY, value);
if (ret < 0)
return ret;
@@ -478,10 +478,10 @@ nouveau_hwmon_get_pwm1_max(struct device *d,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
int ret;
- ret = therm->attr_get(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY);
+ ret = therm->attr_get(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY);
if (ret < 0)
return ret;
@@ -494,14 +494,14 @@ nouveau_hwmon_set_pwm1_max(struct device *d, struct device_attribute *a,
{
struct drm_device *dev = dev_get_drvdata(d);
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
long value;
int ret;
if (kstrtol(buf, 10, &value) == -EINVAL)
return -EINVAL;
- ret = therm->attr_set(therm, NOUVEAU_THERM_ATTR_FAN_MAX_DUTY, value);
+ ret = therm->attr_set(therm, NVKM_THERM_ATTR_FAN_MAX_DUTY, value);
if (ret < 0)
return ret;
@@ -561,7 +561,7 @@ nouveau_hwmon_init(struct drm_device *dev)
{
#if defined(CONFIG_HWMON) || (defined(MODULE) && defined(CONFIG_HWMON_MODULE))
struct nouveau_drm *drm = nouveau_drm(dev);
- struct nouveau_therm *therm = nvkm_therm(&drm->device);
+ struct nvkm_therm *therm = nvxx_therm(&drm->device);
struct nouveau_hwmon *hwmon;
struct device *hwmon_dev;
int ret = 0;
diff --git a/drivers/gpu/drm/nouveau/nouveau_nvif.c b/drivers/gpu/drm/nouveau/nouveau_nvif.c
index 6544b84f0303..ca0ad9d1563d 100644
--- a/drivers/gpu/drm/nouveau/nouveau_nvif.c
+++ b/drivers/gpu/drm/nouveau/nouveau_nvif.c
@@ -60,22 +60,22 @@ nvkm_client_ioctl(void *priv, bool super, void *data, u32 size, void **hack)
static int
nvkm_client_resume(void *priv)
{
- return nouveau_client_init(priv);
+ return nvkm_client_init(priv);
}
static int
nvkm_client_suspend(void *priv)
{
- return nouveau_client_fini(priv, true);
+ return nvkm_client_fini(priv, true);
}
static void
-nvkm_client_fini(void *priv)
+nvkm_client_driver_fini(void *priv)
{
- struct nouveau_object *client = priv;
- nouveau_client_fini(nv_client(client), false);
+ struct nvkm_object *client = priv;
+ nvkm_client_fini(nv_client(client), false);
atomic_set(&client->refcount, 1);
- nouveau_object_ref(NULL, &client);
+ nvkm_object_ref(NULL, &client);
}
static int
@@ -107,13 +107,13 @@ nvkm_client_ntfy(const void *header, u32 length, const void *data, u32 size)
}
static int
-nvkm_client_init(const char *name, u64 device, const char *cfg,
- const char *dbg, void **ppriv)
+nvkm_client_driver_init(const char *name, u64 device, const char *cfg,
+ const char *dbg, void **ppriv)
{
- struct nouveau_client *client;
+ struct nvkm_client *client;
int ret;
- ret = nouveau_client_create(name, device, cfg, dbg, &client);
+ ret = nvkm_client_create(name, device, cfg, dbg, &client);
*ppriv = client;
if (ret)
return ret;
@@ -125,8 +125,8 @@ nvkm_client_init(const char *name, u64 device, const char *cfg,
const struct nvif_driver
nvif_driver_nvkm = {
.name = "nvkm",
- .init = nvkm_client_init,
- .fini = nvkm_client_fini,
+ .init = nvkm_client_driver_init,
+ .fini = nvkm_client_driver_fini,
.suspend = nvkm_client_suspend,
.resume = nvkm_client_resume,
.ioctl = nvkm_client_ioctl,
diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.c b/drivers/gpu/drm/nouveau/nouveau_platform.c
index b307bbedd4c4..dc5900bf54ff 100644
--- a/drivers/gpu/drm/nouveau/nouveau_platform.c
+++ b/drivers/gpu/drm/nouveau/nouveau_platform.c
@@ -152,7 +152,7 @@ static int nouveau_platform_remove(struct platform_device *pdev)
{
struct drm_device *drm_dev = platform_get_drvdata(pdev);
struct nouveau_drm *drm = nouveau_drm(drm_dev);
- struct nouveau_device *device = nvkm_device(&drm->device);
+ struct nvkm_device *device = nvxx_device(&drm->device);
struct nouveau_platform_gpu *gpu = nv_device_to_platform(device)->gpu;
nouveau_drm_device_remove(drm_dev);
@@ -177,9 +177,3 @@ struct platform_driver nouveau_platform_driver = {
.probe = nouveau_platform_probe,
.remove = nouveau_platform_remove,
};
-
-module_platform_driver(nouveau_platform_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL and additional rights");
diff --git a/drivers/gpu/drm/nouveau/nouveau_platform.h b/drivers/gpu/drm/nouveau/nouveau_platform.h
index 58c28b5653d5..268bb7213681 100644
--- a/drivers/gpu/drm/nouveau/nouveau_platform.h
+++ b/drivers/gpu/drm/nouveau/nouveau_platform.h
@@ -28,6 +28,7 @@
struct reset_control;
struct clk;
struct regulator;
+struct platform_driver;
struct nouveau_platform_gpu {
struct reset_control *rst;
@@ -38,7 +39,7 @@ struct nouveau_platform_gpu {
};
struct nouveau_platform_device {
- struct nouveau_device device;
+ struct nvkm_device device;
struct nouveau_platform_gpu *gpu;
@@ -48,4 +49,6 @@ struct nouveau_platform_device {
#define nv_device_to_platform(d) \
container_of(d, struct nouveau_platform_device, device)
+extern struct platform_driver nouveau_platform_driver;
+
#endif
diff --git a/drivers/gpu/drm/nouveau/nouveau_reg.h b/drivers/gpu/drm/nouveau/nouveau_reg.h
index 43a96b99e180..7226f1f60901 100644
--- a/drivers/gpu/drm/nouveau/nouveau_reg.h
+++ b/drivers/gpu/drm/nouveau/nouveau_reg.h
@@ -72,7 +72,7 @@
# define NV_RAMHT_CONTEXT_VALID (1<<31)
# define NV_RAMHT_CONTEXT_CHANNEL_SHIFT 24
# define NV_RAMHT_CONTEXT_ENGINE_SHIFT 16
-# define NV_RAMHT_CONTEXT_ENGINE_SOFTWARE 0
+# define NV_RAMHT_CONTEXT_ENGINE_SW 0
# define NV_RAMHT_CONTEXT_ENGINE_GRAPHICS 1
# define NV_RAMHT_CONTEXT_INSTANCE_SHIFT 0
# define NV40_RAMHT_CONTEXT_CHANNEL_SHIFT 23
diff --git a/drivers/gpu/drm/nouveau/nouveau_sgdma.c b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
index 01707e7deaf5..8c3053a177d6 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sgdma.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sgdma.c
@@ -9,8 +9,7 @@ struct nouveau_sgdma_be {
* nouve_bo.c works properly, otherwise have to move them here
*/
struct ttm_dma_tt ttm;
- struct drm_device *dev;
- struct nouveau_mem *node;
+ struct nvkm_mem *node;
};
static void
@@ -28,7 +27,7 @@ static int
nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
- struct nouveau_mem *node = mem->mm_node;
+ struct nvkm_mem *node = mem->mm_node;
if (ttm->sg) {
node->sg = ttm->sg;
@@ -39,7 +38,7 @@ nv04_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
}
node->size = (mem->num_pages << PAGE_SHIFT) >> 12;
- nouveau_vm_map(&node->vma[0], node);
+ nvkm_vm_map(&node->vma[0], node);
nvbe->node = node;
return 0;
}
@@ -48,7 +47,7 @@ static int
nv04_sgdma_unbind(struct ttm_tt *ttm)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
- nouveau_vm_unmap(&nvbe->node->vma[0]);
+ nvkm_vm_unmap(&nvbe->node->vma[0]);
return 0;
}
@@ -62,7 +61,7 @@ static int
nv50_sgdma_bind(struct ttm_tt *ttm, struct ttm_mem_reg *mem)
{
struct nouveau_sgdma_be *nvbe = (struct nouveau_sgdma_be *)ttm;
- struct nouveau_mem *node = mem->mm_node;
+ struct nvkm_mem *node = mem->mm_node;
/* noop: bound in move_notify() */
if (ttm->sg) {
@@ -101,13 +100,17 @@ nouveau_sgdma_create_ttm(struct ttm_bo_device *bdev,
if (!nvbe)
return NULL;
- nvbe->dev = drm->dev;
if (drm->device.info.family < NV_DEVICE_INFO_V0_TESLA)
nvbe->ttm.ttm.func = &nv04_sgdma_backend;
else
nvbe->ttm.ttm.func = &nv50_sgdma_backend;
if (ttm_dma_tt_init(&nvbe->ttm, bdev, size, page_flags, dummy_read_page))
+ /*
+ * A failing ttm_dma_tt_init() will call ttm_tt_destroy()
+ * and thus our nouveau_sgdma_destroy() hook, so we don't need
+ * to free nvbe here.
+ */
return NULL;
return &nvbe->ttm.ttm;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_sysfs.c b/drivers/gpu/drm/nouveau/nouveau_sysfs.c
index 8fbbf3093d86..1ec8f38ae69a 100644
--- a/drivers/gpu/drm/nouveau/nouveau_sysfs.c
+++ b/drivers/gpu/drm/nouveau/nouveau_sysfs.c
@@ -165,7 +165,7 @@ nouveau_sysfs_fini(struct drm_device *dev)
struct nvif_device *device = &drm->device;
if (sysfs && sysfs->ctrl.priv) {
- device_remove_file(nv_device_base(nvkm_device(device)), &dev_attr_pstate);
+ device_remove_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate);
nvif_object_fini(&sysfs->ctrl);
}
@@ -192,7 +192,7 @@ nouveau_sysfs_init(struct drm_device *dev)
NVIF_IOCTL_NEW_V0_CONTROL, NULL, 0,
&sysfs->ctrl);
if (ret == 0)
- device_create_file(nv_device_base(nvkm_device(device)), &dev_attr_pstate);
+ device_create_file(nv_device_base(nvxx_device(device)), &dev_attr_pstate);
return 0;
}
diff --git a/drivers/gpu/drm/nouveau/nouveau_ttm.c b/drivers/gpu/drm/nouveau/nouveau_ttm.c
index 3d1cfcb96b6b..273e50110ec3 100644
--- a/drivers/gpu/drm/nouveau/nouveau_ttm.c
+++ b/drivers/gpu/drm/nouveau/nouveau_ttm.c
@@ -33,7 +33,7 @@ static int
nouveau_vram_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
{
struct nouveau_drm *drm = nouveau_bdev(man->bdev);
- struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+ struct nvkm_fb *pfb = nvxx_fb(&drm->device);
man->priv = pfb;
return 0;
}
@@ -46,16 +46,16 @@ nouveau_vram_manager_fini(struct ttm_mem_type_manager *man)
}
static inline void
-nouveau_mem_node_cleanup(struct nouveau_mem *node)
+nvkm_mem_node_cleanup(struct nvkm_mem *node)
{
if (node->vma[0].node) {
- nouveau_vm_unmap(&node->vma[0]);
- nouveau_vm_put(&node->vma[0]);
+ nvkm_vm_unmap(&node->vma[0]);
+ nvkm_vm_put(&node->vma[0]);
}
if (node->vma[1].node) {
- nouveau_vm_unmap(&node->vma[1]);
- nouveau_vm_put(&node->vma[1]);
+ nvkm_vm_unmap(&node->vma[1]);
+ nvkm_vm_put(&node->vma[1]);
}
}
@@ -64,9 +64,9 @@ nouveau_vram_manager_del(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
struct nouveau_drm *drm = nouveau_bdev(man->bdev);
- struct nouveau_fb *pfb = nvkm_fb(&drm->device);
- nouveau_mem_node_cleanup(mem->mm_node);
- pfb->ram->put(pfb, (struct nouveau_mem **)&mem->mm_node);
+ struct nvkm_fb *pfb = nvxx_fb(&drm->device);
+ nvkm_mem_node_cleanup(mem->mm_node);
+ pfb->ram->put(pfb, (struct nvkm_mem **)&mem->mm_node);
}
static int
@@ -76,9 +76,9 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
struct nouveau_drm *drm = nouveau_bdev(man->bdev);
- struct nouveau_fb *pfb = nvkm_fb(&drm->device);
+ struct nvkm_fb *pfb = nvxx_fb(&drm->device);
struct nouveau_bo *nvbo = nouveau_bo(bo);
- struct nouveau_mem *node;
+ struct nvkm_mem *node;
u32 size_nc = 0;
int ret;
@@ -103,9 +103,9 @@ nouveau_vram_manager_new(struct ttm_mem_type_manager *man,
static void
nouveau_vram_manager_debug(struct ttm_mem_type_manager *man, const char *prefix)
{
- struct nouveau_fb *pfb = man->priv;
- struct nouveau_mm *mm = &pfb->vram;
- struct nouveau_mm_node *r;
+ struct nvkm_fb *pfb = man->priv;
+ struct nvkm_mm *mm = &pfb->vram;
+ struct nvkm_mm_node *r;
u32 total = 0, free = 0;
mutex_lock(&nv_subdev(pfb)->mutex);
@@ -150,7 +150,7 @@ static void
nouveau_gart_manager_del(struct ttm_mem_type_manager *man,
struct ttm_mem_reg *mem)
{
- nouveau_mem_node_cleanup(mem->mm_node);
+ nvkm_mem_node_cleanup(mem->mm_node);
kfree(mem->mm_node);
mem->mm_node = NULL;
}
@@ -163,7 +163,7 @@ nouveau_gart_manager_new(struct ttm_mem_type_manager *man,
{
struct nouveau_drm *drm = nouveau_bdev(bo->bdev);
struct nouveau_bo *nvbo = nouveau_bo(bo);
- struct nouveau_mem *node;
+ struct nvkm_mem *node;
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
@@ -203,15 +203,15 @@ const struct ttm_mem_type_manager_func nouveau_gart_manager = {
};
/*XXX*/
-#include <core/subdev/vm/nv04.h>
+#include <subdev/mmu/nv04.h>
static int
nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
{
struct nouveau_drm *drm = nouveau_bdev(man->bdev);
- struct nouveau_vmmgr *vmm = nvkm_vmmgr(&drm->device);
- struct nv04_vmmgr_priv *priv = (void *)vmm;
- struct nouveau_vm *vm = NULL;
- nouveau_vm_ref(priv->vm, &vm, NULL);
+ struct nvkm_mmu *mmu = nvxx_mmu(&drm->device);
+ struct nv04_mmu_priv *priv = (void *)mmu;
+ struct nvkm_vm *vm = NULL;
+ nvkm_vm_ref(priv->vm, &vm, NULL);
man->priv = vm;
return 0;
}
@@ -219,8 +219,8 @@ nv04_gart_manager_init(struct ttm_mem_type_manager *man, unsigned long psize)
static int
nv04_gart_manager_fini(struct ttm_mem_type_manager *man)
{
- struct nouveau_vm *vm = man->priv;
- nouveau_vm_ref(NULL, &vm, NULL);
+ struct nvkm_vm *vm = man->priv;
+ nvkm_vm_ref(NULL, &vm, NULL);
man->priv = NULL;
return 0;
}
@@ -228,9 +228,9 @@ nv04_gart_manager_fini(struct ttm_mem_type_manager *man)
static void
nv04_gart_manager_del(struct ttm_mem_type_manager *man, struct ttm_mem_reg *mem)
{
- struct nouveau_mem *node = mem->mm_node;
+ struct nvkm_mem *node = mem->mm_node;
if (node->vma[0].node)
- nouveau_vm_put(&node->vma[0]);
+ nvkm_vm_put(&node->vma[0]);
kfree(mem->mm_node);
mem->mm_node = NULL;
}
@@ -241,7 +241,7 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man,
const struct ttm_place *place,
struct ttm_mem_reg *mem)
{
- struct nouveau_mem *node;
+ struct nvkm_mem *node;
int ret;
node = kzalloc(sizeof(*node), GFP_KERNEL);
@@ -250,8 +250,8 @@ nv04_gart_manager_new(struct ttm_mem_type_manager *man,
node->page_shift = 12;
- ret = nouveau_vm_get(man->priv, mem->num_pages << 12, node->page_shift,
- NV_MEM_ACCESS_RW, &node->vma[0]);
+ ret = nvkm_vm_get(man->priv, mem->num_pages << 12, node->page_shift,
+ NV_MEM_ACCESS_RW, &node->vma[0]);
if (ret) {
kfree(node);
return ret;
@@ -354,8 +354,8 @@ nouveau_ttm_init(struct nouveau_drm *drm)
u32 bits;
int ret;
- bits = nvkm_vmmgr(&drm->device)->dma_bits;
- if (nv_device_is_pci(nvkm_device(&drm->device))) {
+ bits = nvxx_mmu(&drm->device)->dma_bits;
+ if (nv_device_is_pci(nvxx_device(&drm->device))) {
if (drm->agp.stat == ENABLED ||
!pci_dma_supported(dev->pdev, DMA_BIT_MASK(bits)))
bits = 32;
@@ -396,12 +396,12 @@ nouveau_ttm_init(struct nouveau_drm *drm)
return ret;
}
- drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(nvkm_device(&drm->device), 1),
- nv_device_resource_len(nvkm_device(&drm->device), 1));
+ drm->ttm.mtrr = arch_phys_wc_add(nv_device_resource_start(nvxx_device(&drm->device), 1),
+ nv_device_resource_len(nvxx_device(&drm->device), 1));
/* GART init */
if (drm->agp.stat != ENABLED) {
- drm->gem.gart_available = nvkm_vmmgr(&drm->device)->limit;
+ drm->gem.gart_available = nvxx_mmu(&drm->device)->limit;
} else {
drm->gem.gart_available = drm->agp.size;
}
diff --git a/drivers/gpu/drm/nouveau/nv04_fence.c b/drivers/gpu/drm/nouveau/nv04_fence.c
index f9859deb108a..c2e05e64cd6f 100644
--- a/drivers/gpu/drm/nouveau/nv04_fence.c
+++ b/drivers/gpu/drm/nouveau/nv04_fence.c
@@ -57,7 +57,7 @@ nv04_fence_sync(struct nouveau_fence *fence,
static u32
nv04_fence_read(struct nouveau_channel *chan)
{
- struct nouveau_fifo_chan *fifo = nvkm_fifo_chan(chan);;
+ struct nvkm_fifo_chan *fifo = nvxx_fifo_chan(chan);;
return atomic_read(&fifo->refcnt);
}
diff --git a/drivers/gpu/drm/nouveau/nv50_display.c b/drivers/gpu/drm/nouveau/nv50_display.c
index 490b90866baf..7da7958556a3 100644
--- a/drivers/gpu/drm/nouveau/nv50_display.c
+++ b/drivers/gpu/drm/nouveau/nv50_display.c
@@ -125,7 +125,6 @@ nv50_pioc_create(struct nvif_object *disp, const u32 *oclass, u8 head,
struct nv50_curs {
struct nv50_pioc base;
- struct nouveau_bo *image;
};
static int
@@ -201,7 +200,7 @@ nv50_dmac_destroy(struct nv50_dmac *dmac, struct nvif_object *disp)
nv50_chan_destroy(&dmac->base);
if (dmac->ptr) {
- struct pci_dev *pdev = nvkm_device(nvif_device(disp))->pdev;
+ struct pci_dev *pdev = nvxx_device(nvif_device(disp))->pdev;
pci_free_consistent(pdev, PAGE_SIZE, dmac->ptr, dmac->handle);
}
}
@@ -218,7 +217,7 @@ nv50_dmac_create(struct nvif_object *disp, const u32 *oclass, u8 head,
mutex_init(&dmac->lock);
- dmac->ptr = pci_alloc_consistent(nvkm_device(device)->pdev,
+ dmac->ptr = pci_alloc_consistent(nvxx_device(device)->pdev,
PAGE_SIZE, &dmac->handle);
if (!dmac->ptr)
return -ENOMEM;
@@ -421,9 +420,9 @@ evo_wait(void *evoc, int nr)
dmac->ptr[put] = 0x20000000;
nvif_wr32(&dmac->base.user, 0x0000, 0x00000000);
- if (!nvkm_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) {
+ if (!nvxx_wait(&dmac->base.user, 0x0004, ~0, 0x00000000)) {
mutex_unlock(&dmac->lock);
- nv_error(nvkm_object(&dmac->base.user), "channel stalled\n");
+ nv_error(nvxx_object(&dmac->base.user), "channel stalled\n");
return NULL;
}
@@ -481,7 +480,7 @@ evo_sync(struct drm_device *dev)
evo_data(push, 0x00000000);
evo_data(push, 0x00000000);
evo_kick(push, mast);
- if (nv_wait_cb(nvkm_device(device), evo_sync_wait, disp->sync))
+ if (nv_wait_cb(nvxx_device(device), evo_sync_wait, disp->sync))
return 0;
}
@@ -536,7 +535,7 @@ nv50_display_flip_stop(struct drm_crtc *crtc)
evo_kick(push, flip.chan);
}
- nv_wait_cb(nvkm_device(device), nv50_display_flip_wait, &flip);
+ nv_wait_cb(nvxx_device(device), nv50_display_flip_wait, &flip);
}
int
@@ -550,6 +549,10 @@ nv50_display_flip_next(struct drm_crtc *crtc, struct drm_framebuffer *fb,
u32 *push;
int ret;
+ if (crtc->primary->fb->width != fb->width ||
+ crtc->primary->fb->height != fb->height)
+ return -EINVAL;
+
swap_interval <<= 4;
if (swap_interval == 0)
swap_interval |= 0x100;
@@ -729,8 +732,11 @@ nv50_crtc_set_scale(struct nouveau_crtc *nv_crtc, bool update)
* effectively handles NONE/FULL scaling
*/
nv_connector = nouveau_crtc_connector_get(nv_crtc);
- if (nv_connector && nv_connector->native_mode)
+ if (nv_connector && nv_connector->native_mode) {
mode = nv_connector->scaling_mode;
+ if (nv_connector->scaling_full) /* non-EDID LVDS/eDP mode */
+ mode = DRM_MODE_SCALE_FULLSCREEN;
+ }
if (mode != DRM_MODE_SCALE_NONE)
omode = nv_connector->native_mode;
@@ -917,29 +923,29 @@ static void
nv50_crtc_cursor_show(struct nouveau_crtc *nv_crtc)
{
struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- struct nv50_curs *curs = nv50_curs(&nv_crtc->base);
u32 *push = evo_wait(mast, 16);
if (push) {
if (nv50_vers(mast) < G82_DISP_CORE_CHANNEL_DMA) {
evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
evo_data(push, 0x85000000);
- evo_data(push, curs->image->bo.offset >> 8);
+ evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
} else
if (nv50_vers(mast) < GF110_DISP_CORE_CHANNEL_DMA) {
evo_mthd(push, 0x0880 + (nv_crtc->index * 0x400), 2);
evo_data(push, 0x85000000);
- evo_data(push, curs->image->bo.offset >> 8);
+ evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
evo_mthd(push, 0x089c + (nv_crtc->index * 0x400), 1);
evo_data(push, mast->base.vram.handle);
} else {
evo_mthd(push, 0x0480 + (nv_crtc->index * 0x300), 2);
evo_data(push, 0x85000000);
- evo_data(push, curs->image->bo.offset >> 8);
+ evo_data(push, nv_crtc->cursor.nvbo->bo.offset >> 8);
evo_mthd(push, 0x048c + (nv_crtc->index * 0x300), 1);
evo_data(push, mast->base.vram.handle);
}
evo_kick(push, mast);
}
+ nv_crtc->cursor.visible = true;
}
static void
@@ -965,15 +971,15 @@ nv50_crtc_cursor_hide(struct nouveau_crtc *nv_crtc)
}
evo_kick(push, mast);
}
+ nv_crtc->cursor.visible = false;
}
static void
nv50_crtc_cursor_show_hide(struct nouveau_crtc *nv_crtc, bool show, bool update)
{
struct nv50_mast *mast = nv50_mast(nv_crtc->base.dev);
- struct nv50_curs *curs = nv50_curs(&nv_crtc->base);
- if (show && curs->image)
+ if (show && nv_crtc->cursor.nvbo)
nv50_crtc_cursor_show(nv_crtc);
else
nv50_crtc_cursor_hide(nv_crtc);
@@ -1273,7 +1279,6 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
uint32_t handle, uint32_t width, uint32_t height)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
- struct nv50_curs *curs = nv50_curs(crtc);
struct drm_device *dev = crtc->dev;
struct drm_gem_object *gem = NULL;
struct nouveau_bo *nvbo = NULL;
@@ -1292,9 +1297,9 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
}
if (ret == 0) {
- if (curs->image)
- nouveau_bo_unpin(curs->image);
- nouveau_bo_ref(nvbo, &curs->image);
+ if (nv_crtc->cursor.nvbo)
+ nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+ nouveau_bo_ref(nvbo, &nv_crtc->cursor.nvbo);
}
drm_gem_object_unreference_unlocked(gem);
@@ -1305,10 +1310,14 @@ nv50_crtc_cursor_set(struct drm_crtc *crtc, struct drm_file *file_priv,
static int
nv50_crtc_cursor_move(struct drm_crtc *crtc, int x, int y)
{
+ struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
struct nv50_curs *curs = nv50_curs(crtc);
struct nv50_chan *chan = nv50_chan(curs);
nvif_wr32(&chan->user, 0x0084, (y << 16) | (x & 0xffff));
nvif_wr32(&chan->user, 0x0080, 0x00000000);
+
+ nv_crtc->cursor_saved_x = x;
+ nv_crtc->cursor_saved_y = y;
return 0;
}
@@ -1330,6 +1339,14 @@ nv50_crtc_gamma_set(struct drm_crtc *crtc, u16 *r, u16 *g, u16 *b,
}
static void
+nv50_crtc_cursor_restore(struct nouveau_crtc *nv_crtc, int x, int y)
+{
+ nv50_crtc_cursor_move(&nv_crtc->base, x, y);
+
+ nv50_crtc_cursor_show_hide(nv_crtc, true, true);
+}
+
+static void
nv50_crtc_destroy(struct drm_crtc *crtc)
{
struct nouveau_crtc *nv_crtc = nouveau_crtc(crtc);
@@ -1354,9 +1371,9 @@ nv50_crtc_destroy(struct drm_crtc *crtc)
nouveau_bo_ref(NULL, &head->image);
/*XXX: ditto */
- if (head->curs.image)
- nouveau_bo_unpin(head->curs.image);
- nouveau_bo_ref(NULL, &head->curs.image);
+ if (nv_crtc->cursor.nvbo)
+ nouveau_bo_unpin(nv_crtc->cursor.nvbo);
+ nouveau_bo_ref(NULL, &nv_crtc->cursor.nvbo);
nouveau_bo_unmap(nv_crtc->lut.nvbo);
if (nv_crtc->lut.nvbo)
@@ -1406,6 +1423,7 @@ nv50_crtc_create(struct drm_device *dev, int index)
head->base.set_color_vibrance = nv50_crtc_set_color_vibrance;
head->base.color_vibrance = 50;
head->base.vibrant_hue = 0;
+ head->base.cursor.set_pos = nv50_crtc_cursor_restore;
for (i = 0; i < 256; i++) {
head->base.lut.r[i] = i << 8;
head->base.lut.g[i] = i << 8;
@@ -1433,8 +1451,6 @@ nv50_crtc_create(struct drm_device *dev, int index)
if (ret)
goto out;
- nv50_crtc_lut_load(crtc);
-
/* allocate cursor resources */
ret = nv50_curs_create(disp->disp, index, &head->curs);
if (ret)
@@ -1466,6 +1482,41 @@ out:
}
/******************************************************************************
+ * Encoder helpers
+ *****************************************************************************/
+static bool
+nv50_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
+ struct nouveau_connector *nv_connector;
+
+ nv_connector = nouveau_encoder_connector_get(nv_encoder);
+ if (nv_connector && nv_connector->native_mode) {
+ nv_connector->scaling_full = false;
+ if (nv_connector->scaling_mode == DRM_MODE_SCALE_NONE) {
+ switch (nv_connector->type) {
+ case DCB_CONNECTOR_LVDS:
+ case DCB_CONNECTOR_LVDS_SPWG:
+ case DCB_CONNECTOR_eDP:
+ /* force use of scaler for non-edid modes */
+ if (adjusted_mode->type & DRM_MODE_TYPE_DRIVER)
+ return true;
+ nv_connector->scaling_full = true;
+ break;
+ default:
+ return true;
+ }
+ }
+
+ drm_mode_copy(adjusted_mode, nv_connector->native_mode);
+ }
+
+ return true;
+}
+
+/******************************************************************************
* DAC
*****************************************************************************/
static void
@@ -1492,26 +1543,6 @@ nv50_dac_dpms(struct drm_encoder *encoder, int mode)
nvif_mthd(disp->disp, 0, &args, sizeof(args));
}
-static bool
-nv50_dac_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_connector *nv_connector;
-
- nv_connector = nouveau_encoder_connector_get(nv_encoder);
- if (nv_connector && nv_connector->native_mode) {
- if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
- int id = adjusted_mode->base.id;
- *adjusted_mode = *nv_connector->native_mode;
- adjusted_mode->base.id = id;
- }
- }
-
- return true;
-}
-
static void
nv50_dac_commit(struct drm_encoder *encoder)
{
@@ -1629,7 +1660,7 @@ nv50_dac_destroy(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs nv50_dac_hfunc = {
.dpms = nv50_dac_dpms,
- .mode_fixup = nv50_dac_mode_fixup,
+ .mode_fixup = nv50_encoder_mode_fixup,
.prepare = nv50_dac_disconnect,
.commit = nv50_dac_commit,
.mode_set = nv50_dac_mode_set,
@@ -1646,7 +1677,7 @@ static int
nv50_dac_create(struct drm_connector *connector, struct dcb_output *dcbe)
{
struct nouveau_drm *drm = nouveau_drm(connector->dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
int type = DRM_MODE_ENCODER_DAC;
@@ -1834,26 +1865,6 @@ nv50_sor_dpms(struct drm_encoder *encoder, int mode)
}
}
-static bool
-nv50_sor_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted_mode)
-{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_connector *nv_connector;
-
- nv_connector = nouveau_encoder_connector_get(nv_encoder);
- if (nv_connector && nv_connector->native_mode) {
- if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
- int id = adjusted_mode->base.id;
- *adjusted_mode = *nv_connector->native_mode;
- adjusted_mode->base.id = id;
- }
- }
-
- return true;
-}
-
static void
nv50_sor_ctrl(struct nouveau_encoder *nv_encoder, u32 mask, u32 data)
{
@@ -2035,7 +2046,7 @@ nv50_sor_destroy(struct drm_encoder *encoder)
static const struct drm_encoder_helper_funcs nv50_sor_hfunc = {
.dpms = nv50_sor_dpms,
- .mode_fixup = nv50_sor_mode_fixup,
+ .mode_fixup = nv50_encoder_mode_fixup,
.prepare = nv50_sor_disconnect,
.commit = nv50_sor_commit,
.mode_set = nv50_sor_mode_set,
@@ -2051,7 +2062,7 @@ static int
nv50_sor_create(struct drm_connector *connector, struct dcb_output *dcbe)
{
struct nouveau_drm *drm = nouveau_drm(connector->dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
int type;
@@ -2112,18 +2123,8 @@ nv50_pior_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
- struct nouveau_encoder *nv_encoder = nouveau_encoder(encoder);
- struct nouveau_connector *nv_connector;
-
- nv_connector = nouveau_encoder_connector_get(nv_encoder);
- if (nv_connector && nv_connector->native_mode) {
- if (nv_connector->scaling_mode != DRM_MODE_SCALE_NONE) {
- int id = adjusted_mode->base.id;
- *adjusted_mode = *nv_connector->native_mode;
- adjusted_mode->base.id = id;
- }
- }
-
+ if (!nv50_encoder_mode_fixup(encoder, mode, adjusted_mode))
+ return false;
adjusted_mode->clock *= 2;
return true;
}
@@ -2232,8 +2233,8 @@ static int
nv50_pior_create(struct drm_connector *connector, struct dcb_output *dcbe)
{
struct nouveau_drm *drm = nouveau_drm(connector->dev);
- struct nouveau_i2c *i2c = nvkm_i2c(&drm->device);
- struct nouveau_i2c_port *ddc = NULL;
+ struct nvkm_i2c *i2c = nvxx_i2c(&drm->device);
+ struct nvkm_i2c_port *ddc = NULL;
struct nouveau_encoder *nv_encoder;
struct drm_encoder *encoder;
int type;
@@ -2427,6 +2428,8 @@ nv50_display_init(struct drm_device *dev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
struct nv50_sync *sync = nv50_sync(crtc);
+
+ nv50_crtc_lut_load(crtc);
nouveau_bo_wr32(disp->sync, sync->addr / 4, sync->data);
}
diff --git a/drivers/gpu/drm/nouveau/nv84_fence.c b/drivers/gpu/drm/nouveau/nv84_fence.c
index cb5b88938d45..bf429cabbaa8 100644
--- a/drivers/gpu/drm/nouveau/nv84_fence.c
+++ b/drivers/gpu/drm/nouveau/nv84_fence.c
@@ -213,7 +213,7 @@ nv84_fence_destroy(struct nouveau_drm *drm)
int
nv84_fence_create(struct nouveau_drm *drm)
{
- struct nouveau_fifo *pfifo = nvkm_fifo(&drm->device);
+ struct nvkm_fifo *pfifo = nvxx_fifo(&drm->device);
struct nv84_fence_priv *priv;
int ret;
diff --git a/drivers/gpu/drm/nouveau/nvif/Kbuild b/drivers/gpu/drm/nouveau/nvif/Kbuild
new file mode 100644
index 000000000000..ff8ed3a04d06
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvif/Kbuild
@@ -0,0 +1,4 @@
+nvif-y := nvif/object.o
+nvif-y += nvif/client.o
+nvif-y += nvif/device.o
+nvif-y += nvif/notify.o
diff --git a/drivers/gpu/drm/nouveau/nvif/class.h b/drivers/gpu/drm/nouveau/nvif/class.h
deleted file mode 100644
index 4e308eacb27a..000000000000
--- a/drivers/gpu/drm/nouveau/nvif/class.h
+++ /dev/null
@@ -1,570 +0,0 @@
-#ifndef __NVIF_CLASS_H__
-#define __NVIF_CLASS_H__
-
-/*******************************************************************************
- * class identifiers
- ******************************************************************************/
-
-/* the below match nvidia-assigned (either in hw, or sw) class numbers */
-#define NV_DEVICE 0x00000080
-
-#define NV_DMA_FROM_MEMORY 0x00000002
-#define NV_DMA_TO_MEMORY 0x00000003
-#define NV_DMA_IN_MEMORY 0x0000003d
-
-#define NV04_DISP 0x00000046
-
-#define NV03_CHANNEL_DMA 0x0000006b
-#define NV10_CHANNEL_DMA 0x0000006e
-#define NV17_CHANNEL_DMA 0x0000176e
-#define NV40_CHANNEL_DMA 0x0000406e
-#define NV50_CHANNEL_DMA 0x0000506e
-#define G82_CHANNEL_DMA 0x0000826e
-
-#define NV50_CHANNEL_GPFIFO 0x0000506f
-#define G82_CHANNEL_GPFIFO 0x0000826f
-#define FERMI_CHANNEL_GPFIFO 0x0000906f
-#define KEPLER_CHANNEL_GPFIFO_A 0x0000a06f
-
-#define NV50_DISP 0x00005070
-#define G82_DISP 0x00008270
-#define GT200_DISP 0x00008370
-#define GT214_DISP 0x00008570
-#define GT206_DISP 0x00008870
-#define GF110_DISP 0x00009070
-#define GK104_DISP 0x00009170
-#define GK110_DISP 0x00009270
-#define GM107_DISP 0x00009470
-#define GM204_DISP 0x00009570
-
-#define NV50_DISP_CURSOR 0x0000507a
-#define G82_DISP_CURSOR 0x0000827a
-#define GT214_DISP_CURSOR 0x0000857a
-#define GF110_DISP_CURSOR 0x0000907a
-#define GK104_DISP_CURSOR 0x0000917a
-
-#define NV50_DISP_OVERLAY 0x0000507b
-#define G82_DISP_OVERLAY 0x0000827b
-#define GT214_DISP_OVERLAY 0x0000857b
-#define GF110_DISP_OVERLAY 0x0000907b
-#define GK104_DISP_OVERLAY 0x0000917b
-
-#define NV50_DISP_BASE_CHANNEL_DMA 0x0000507c
-#define G82_DISP_BASE_CHANNEL_DMA 0x0000827c
-#define GT200_DISP_BASE_CHANNEL_DMA 0x0000837c
-#define GT214_DISP_BASE_CHANNEL_DMA 0x0000857c
-#define GF110_DISP_BASE_CHANNEL_DMA 0x0000907c
-#define GK104_DISP_BASE_CHANNEL_DMA 0x0000917c
-#define GK110_DISP_BASE_CHANNEL_DMA 0x0000927c
-
-#define NV50_DISP_CORE_CHANNEL_DMA 0x0000507d
-#define G82_DISP_CORE_CHANNEL_DMA 0x0000827d
-#define GT200_DISP_CORE_CHANNEL_DMA 0x0000837d
-#define GT214_DISP_CORE_CHANNEL_DMA 0x0000857d
-#define GT206_DISP_CORE_CHANNEL_DMA 0x0000887d
-#define GF110_DISP_CORE_CHANNEL_DMA 0x0000907d
-#define GK104_DISP_CORE_CHANNEL_DMA 0x0000917d
-#define GK110_DISP_CORE_CHANNEL_DMA 0x0000927d
-#define GM107_DISP_CORE_CHANNEL_DMA 0x0000947d
-#define GM204_DISP_CORE_CHANNEL_DMA 0x0000957d
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA 0x0000507e
-#define G82_DISP_OVERLAY_CHANNEL_DMA 0x0000827e
-#define GT200_DISP_OVERLAY_CHANNEL_DMA 0x0000837e
-#define GT214_DISP_OVERLAY_CHANNEL_DMA 0x0000857e
-#define GF110_DISP_OVERLAY_CONTROL_DMA 0x0000907e
-#define GK104_DISP_OVERLAY_CONTROL_DMA 0x0000917e
-
-#define FERMI_A 0x00009097
-#define FERMI_B 0x00009197
-#define FERMI_C 0x00009297
-
-#define KEPLER_A 0x0000a097
-#define KEPLER_B 0x0000a197
-#define KEPLER_C 0x0000a297
-
-#define MAXWELL_A 0x0000b097
-
-#define FERMI_COMPUTE_A 0x000090c0
-#define FERMI_COMPUTE_B 0x000091c0
-
-#define KEPLER_COMPUTE_A 0x0000a0c0
-#define KEPLER_COMPUTE_B 0x0000a1c0
-
-#define MAXWELL_COMPUTE_A 0x0000b0c0
-
-
-/*******************************************************************************
- * client
- ******************************************************************************/
-
-#define NV_CLIENT_DEVLIST 0x00
-
-struct nv_client_devlist_v0 {
- __u8 version;
- __u8 count;
- __u8 pad02[6];
- __u64 device[];
-};
-
-
-/*******************************************************************************
- * device
- ******************************************************************************/
-
-struct nv_device_v0 {
- __u8 version;
- __u8 pad01[7];
- __u64 device; /* device identifier, ~0 for client default */
-#define NV_DEVICE_V0_DISABLE_IDENTIFY 0x0000000000000001ULL
-#define NV_DEVICE_V0_DISABLE_MMIO 0x0000000000000002ULL
-#define NV_DEVICE_V0_DISABLE_VBIOS 0x0000000000000004ULL
-#define NV_DEVICE_V0_DISABLE_CORE 0x0000000000000008ULL
-#define NV_DEVICE_V0_DISABLE_DISP 0x0000000000010000ULL
-#define NV_DEVICE_V0_DISABLE_FIFO 0x0000000000020000ULL
-#define NV_DEVICE_V0_DISABLE_GRAPH 0x0000000100000000ULL
-#define NV_DEVICE_V0_DISABLE_MPEG 0x0000000200000000ULL
-#define NV_DEVICE_V0_DISABLE_ME 0x0000000400000000ULL
-#define NV_DEVICE_V0_DISABLE_VP 0x0000000800000000ULL
-#define NV_DEVICE_V0_DISABLE_CRYPT 0x0000001000000000ULL
-#define NV_DEVICE_V0_DISABLE_BSP 0x0000002000000000ULL
-#define NV_DEVICE_V0_DISABLE_PPP 0x0000004000000000ULL
-#define NV_DEVICE_V0_DISABLE_COPY0 0x0000008000000000ULL
-#define NV_DEVICE_V0_DISABLE_COPY1 0x0000010000000000ULL
-#define NV_DEVICE_V0_DISABLE_VIC 0x0000020000000000ULL
-#define NV_DEVICE_V0_DISABLE_VENC 0x0000040000000000ULL
-#define NV_DEVICE_V0_DISABLE_COPY2 0x0000080000000000ULL
- __u64 disable; /* disable particular subsystems */
- __u64 debug0; /* as above, but *internal* ids, and *NOT* ABI */
-};
-
-#define NV_DEVICE_V0_INFO 0x00
-
-struct nv_device_info_v0 {
- __u8 version;
-#define NV_DEVICE_INFO_V0_IGP 0x00
-#define NV_DEVICE_INFO_V0_PCI 0x01
-#define NV_DEVICE_INFO_V0_AGP 0x02
-#define NV_DEVICE_INFO_V0_PCIE 0x03
-#define NV_DEVICE_INFO_V0_SOC 0x04
- __u8 platform;
- __u16 chipset; /* from NV_PMC_BOOT_0 */
- __u8 revision; /* from NV_PMC_BOOT_0 */
-#define NV_DEVICE_INFO_V0_TNT 0x01
-#define NV_DEVICE_INFO_V0_CELSIUS 0x02
-#define NV_DEVICE_INFO_V0_KELVIN 0x03
-#define NV_DEVICE_INFO_V0_RANKINE 0x04
-#define NV_DEVICE_INFO_V0_CURIE 0x05
-#define NV_DEVICE_INFO_V0_TESLA 0x06
-#define NV_DEVICE_INFO_V0_FERMI 0x07
-#define NV_DEVICE_INFO_V0_KEPLER 0x08
-#define NV_DEVICE_INFO_V0_MAXWELL 0x09
- __u8 family;
- __u8 pad06[2];
- __u64 ram_size;
- __u64 ram_user;
-};
-
-
-/*******************************************************************************
- * context dma
- ******************************************************************************/
-
-struct nv_dma_v0 {
- __u8 version;
-#define NV_DMA_V0_TARGET_VM 0x00
-#define NV_DMA_V0_TARGET_VRAM 0x01
-#define NV_DMA_V0_TARGET_PCI 0x02
-#define NV_DMA_V0_TARGET_PCI_US 0x03
-#define NV_DMA_V0_TARGET_AGP 0x04
- __u8 target;
-#define NV_DMA_V0_ACCESS_VM 0x00
-#define NV_DMA_V0_ACCESS_RD 0x01
-#define NV_DMA_V0_ACCESS_WR 0x02
-#define NV_DMA_V0_ACCESS_RDWR (NV_DMA_V0_ACCESS_RD | NV_DMA_V0_ACCESS_WR)
- __u8 access;
- __u8 pad03[5];
- __u64 start;
- __u64 limit;
- /* ... chipset-specific class data */
-};
-
-struct nv50_dma_v0 {
- __u8 version;
-#define NV50_DMA_V0_PRIV_VM 0x00
-#define NV50_DMA_V0_PRIV_US 0x01
-#define NV50_DMA_V0_PRIV__S 0x02
- __u8 priv;
-#define NV50_DMA_V0_PART_VM 0x00
-#define NV50_DMA_V0_PART_256 0x01
-#define NV50_DMA_V0_PART_1KB 0x02
- __u8 part;
-#define NV50_DMA_V0_COMP_NONE 0x00
-#define NV50_DMA_V0_COMP_1 0x01
-#define NV50_DMA_V0_COMP_2 0x02
-#define NV50_DMA_V0_COMP_VM 0x03
- __u8 comp;
-#define NV50_DMA_V0_KIND_PITCH 0x00
-#define NV50_DMA_V0_KIND_VM 0x7f
- __u8 kind;
- __u8 pad05[3];
-};
-
-struct gf100_dma_v0 {
- __u8 version;
-#define GF100_DMA_V0_PRIV_VM 0x00
-#define GF100_DMA_V0_PRIV_US 0x01
-#define GF100_DMA_V0_PRIV__S 0x02
- __u8 priv;
-#define GF100_DMA_V0_KIND_PITCH 0x00
-#define GF100_DMA_V0_KIND_VM 0xff
- __u8 kind;
- __u8 pad03[5];
-};
-
-struct gf110_dma_v0 {
- __u8 version;
-#define GF110_DMA_V0_PAGE_LP 0x00
-#define GF110_DMA_V0_PAGE_SP 0x01
- __u8 page;
-#define GF110_DMA_V0_KIND_PITCH 0x00
-#define GF110_DMA_V0_KIND_VM 0xff
- __u8 kind;
- __u8 pad03[5];
-};
-
-
-/*******************************************************************************
- * perfmon
- ******************************************************************************/
-
-struct nvif_perfctr_v0 {
- __u8 version;
- __u8 pad01[1];
- __u16 logic_op;
- __u8 pad04[4];
- char name[4][64];
-};
-
-#define NVIF_PERFCTR_V0_QUERY 0x00
-#define NVIF_PERFCTR_V0_SAMPLE 0x01
-#define NVIF_PERFCTR_V0_READ 0x02
-
-struct nvif_perfctr_query_v0 {
- __u8 version;
- __u8 pad01[3];
- __u32 iter;
- char name[64];
-};
-
-struct nvif_perfctr_sample {
-};
-
-struct nvif_perfctr_read_v0 {
- __u8 version;
- __u8 pad01[7];
- __u32 ctr;
- __u32 clk;
-};
-
-
-/*******************************************************************************
- * device control
- ******************************************************************************/
-
-#define NVIF_CONTROL_PSTATE_INFO 0x00
-#define NVIF_CONTROL_PSTATE_ATTR 0x01
-#define NVIF_CONTROL_PSTATE_USER 0x02
-
-struct nvif_control_pstate_info_v0 {
- __u8 version;
- __u8 count; /* out: number of power states */
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_USTATE_PERFMON (-2)
- __s8 ustate_ac; /* out: target pstate index */
- __s8 ustate_dc; /* out: target pstate index */
- __s8 pwrsrc; /* out: current power source */
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN (-1)
-#define NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_PERFMON (-2)
- __s8 pstate; /* out: current pstate index */
- __u8 pad06[2];
-};
-
-struct nvif_control_pstate_attr_v0 {
- __u8 version;
-#define NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT (-1)
- __s8 state; /* in: index of pstate to query
- * out: pstate identifier
- */
- __u8 index; /* in: index of attribute to query
- * out: index of next attribute, or 0 if no more
- */
- __u8 pad03[5];
- __u32 min;
- __u32 max;
- char name[32];
- char unit[16];
-};
-
-struct nvif_control_pstate_user_v0 {
- __u8 version;
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_UNKNOWN (-1)
-#define NVIF_CONTROL_PSTATE_USER_V0_STATE_PERFMON (-2)
- __s8 ustate; /* in: pstate identifier */
- __s8 pwrsrc; /* in: target power source */
- __u8 pad03[5];
-};
-
-
-/*******************************************************************************
- * DMA FIFO channels
- ******************************************************************************/
-
-struct nv03_channel_dma_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad02[2];
- __u32 pushbuf;
- __u64 offset;
-};
-
-#define G82_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/*******************************************************************************
- * GPFIFO channels
- ******************************************************************************/
-
-struct nv50_channel_gpfifo_v0 {
- __u8 version;
- __u8 chid;
- __u8 pad01[6];
- __u32 pushbuf;
- __u32 ilength;
- __u64 ioffset;
-};
-
-struct kepler_channel_gpfifo_a_v0 {
- __u8 version;
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_GR 0x01
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_VP 0x02
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_PPP 0x04
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_BSP 0x08
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE0 0x10
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_CE1 0x20
-#define KEPLER_CHANNEL_GPFIFO_A_V0_ENGINE_ENC 0x40
- __u8 engine;
- __u16 chid;
- __u8 pad04[4];
- __u32 pushbuf;
- __u32 ilength;
- __u64 ioffset;
-};
-
-/*******************************************************************************
- * legacy display
- ******************************************************************************/
-
-#define NV04_DISP_NTFY_VBLANK 0x00
-#define NV04_DISP_NTFY_CONN 0x01
-
-struct nv04_disp_mthd_v0 {
- __u8 version;
-#define NV04_DISP_SCANOUTPOS 0x00
- __u8 method;
- __u8 head;
- __u8 pad03[5];
-};
-
-struct nv04_disp_scanoutpos_v0 {
- __u8 version;
- __u8 pad01[7];
- __s64 time[2];
- __u16 vblanks;
- __u16 vblanke;
- __u16 vtotal;
- __u16 vline;
- __u16 hblanks;
- __u16 hblanke;
- __u16 htotal;
- __u16 hline;
-};
-
-/*******************************************************************************
- * display
- ******************************************************************************/
-
-#define NV50_DISP_MTHD 0x00
-
-struct nv50_disp_mthd_v0 {
- __u8 version;
-#define NV50_DISP_SCANOUTPOS 0x00
- __u8 method;
- __u8 head;
- __u8 pad03[5];
-};
-
-struct nv50_disp_mthd_v1 {
- __u8 version;
-#define NV50_DISP_MTHD_V1_DAC_PWR 0x10
-#define NV50_DISP_MTHD_V1_DAC_LOAD 0x11
-#define NV50_DISP_MTHD_V1_SOR_PWR 0x20
-#define NV50_DISP_MTHD_V1_SOR_HDA_ELD 0x21
-#define NV50_DISP_MTHD_V1_SOR_HDMI_PWR 0x22
-#define NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT 0x23
-#define NV50_DISP_MTHD_V1_SOR_DP_PWR 0x24
-#define NV50_DISP_MTHD_V1_PIOR_PWR 0x30
- __u8 method;
- __u16 hasht;
- __u16 hashm;
- __u8 pad06[2];
-};
-
-struct nv50_disp_dac_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 data;
- __u8 vsync;
- __u8 hsync;
- __u8 pad05[3];
-};
-
-struct nv50_disp_dac_load_v0 {
- __u8 version;
- __u8 load;
- __u8 pad02[2];
- __u32 data;
-};
-
-struct nv50_disp_sor_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 pad02[6];
-};
-
-struct nv50_disp_sor_hda_eld_v0 {
- __u8 version;
- __u8 pad01[7];
- __u8 data[];
-};
-
-struct nv50_disp_sor_hdmi_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 max_ac_packet;
- __u8 rekey;
- __u8 pad04[4];
-};
-
-struct nv50_disp_sor_lvds_script_v0 {
- __u8 version;
- __u8 pad01[1];
- __u16 script;
- __u8 pad04[4];
-};
-
-struct nv50_disp_sor_dp_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 pad02[6];
-};
-
-struct nv50_disp_pior_pwr_v0 {
- __u8 version;
- __u8 state;
- __u8 type;
- __u8 pad03[5];
-};
-
-/* core */
-struct nv50_disp_core_channel_dma_v0 {
- __u8 version;
- __u8 pad01[3];
- __u32 pushbuf;
-};
-
-#define NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/* cursor immediate */
-struct nv50_disp_cursor_v0 {
- __u8 version;
- __u8 head;
- __u8 pad02[6];
-};
-
-#define NV50_DISP_CURSOR_V0_NTFY_UEVENT 0x00
-
-/* base */
-struct nv50_disp_base_channel_dma_v0 {
- __u8 version;
- __u8 pad01[2];
- __u8 head;
- __u32 pushbuf;
-};
-
-#define NV50_DISP_BASE_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/* overlay */
-struct nv50_disp_overlay_channel_dma_v0 {
- __u8 version;
- __u8 pad01[2];
- __u8 head;
- __u32 pushbuf;
-};
-
-#define NV50_DISP_OVERLAY_CHANNEL_DMA_V0_NTFY_UEVENT 0x00
-
-/* overlay immediate */
-struct nv50_disp_overlay_v0 {
- __u8 version;
- __u8 head;
- __u8 pad02[6];
-};
-
-#define NV50_DISP_OVERLAY_V0_NTFY_UEVENT 0x00
-
-/*******************************************************************************
- * fermi
- ******************************************************************************/
-
-#define FERMI_A_ZBC_COLOR 0x00
-#define FERMI_A_ZBC_DEPTH 0x01
-
-struct fermi_a_zbc_color_v0 {
- __u8 version;
-#define FERMI_A_ZBC_COLOR_V0_FMT_ZERO 0x01
-#define FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE 0x02
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32 0x04
-#define FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16 0x08
-#define FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16 0x0c
-#define FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16 0x10
-#define FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16 0x14
-#define FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16 0x16
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8 0x18
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8 0x1c
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10 0x20
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10 0x24
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8 0x28
-#define FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8 0x2c
-#define FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8 0x30
-#define FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8 0x34
-#define FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8 0x38
-#define FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10 0x3c
-#define FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11 0x40
- __u8 format;
- __u8 index;
- __u8 pad03[5];
- __u32 ds[4];
- __u32 l2[4];
-};
-
-struct fermi_a_zbc_depth_v0 {
- __u8 version;
-#define FERMI_A_ZBC_DEPTH_V0_FMT_FP32 0x01
- __u8 format;
- __u8 index;
- __u8 pad03[5];
- __u32 ds;
- __u32 l2;
-};
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/client.c b/drivers/gpu/drm/nouveau/nvif/client.c
index 3f7ac5bc8e03..80b96844221e 100644
--- a/drivers/gpu/drm/nouveau/nvif/client.c
+++ b/drivers/gpu/drm/nouveau/nvif/client.c
@@ -22,9 +22,9 @@
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-#include "client.h"
-#include "driver.h"
-#include "ioctl.h"
+#include <nvif/client.h>
+#include <nvif/driver.h>
+#include <nvif/ioctl.h>
int
nvif_client_ioctl(struct nvif_client *client, void *data, u32 size)
diff --git a/drivers/gpu/drm/nouveau/nvif/client.h b/drivers/gpu/drm/nouveau/nvif/client.h
deleted file mode 100644
index 28352f0882ec..000000000000
--- a/drivers/gpu/drm/nouveau/nvif/client.h
+++ /dev/null
@@ -1,39 +0,0 @@
-#ifndef __NVIF_CLIENT_H__
-#define __NVIF_CLIENT_H__
-
-#include "object.h"
-
-struct nvif_client {
- struct nvif_object base;
- struct nvif_object *object; /*XXX: hack for nvif_object() */
- const struct nvif_driver *driver;
- bool super;
-};
-
-static inline struct nvif_client *
-nvif_client(struct nvif_object *object)
-{
- while (object && object->parent != object)
- object = object->parent;
- return (void *)object;
-}
-
-int nvif_client_init(void (*dtor)(struct nvif_client *), const char *,
- const char *, u64, const char *, const char *,
- struct nvif_client *);
-void nvif_client_fini(struct nvif_client *);
-int nvif_client_new(const char *, const char *, u64, const char *,
- const char *, struct nvif_client **);
-void nvif_client_ref(struct nvif_client *, struct nvif_client **);
-int nvif_client_ioctl(struct nvif_client *, void *, u32);
-int nvif_client_suspend(struct nvif_client *);
-int nvif_client_resume(struct nvif_client *);
-
-/*XXX*/
-#include <core/client.h>
-#define nvkm_client(a) ({ \
- struct nvif_client *_client = nvif_client(nvif_object(a)); \
- nouveau_client(_client->base.priv); \
-})
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/device.c b/drivers/gpu/drm/nouveau/nvif/device.c
index f477579725e3..6f72244c52cd 100644
--- a/drivers/gpu/drm/nouveau/nvif/device.c
+++ b/drivers/gpu/drm/nouveau/nvif/device.c
@@ -22,7 +22,7 @@
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-#include "device.h"
+#include <nvif/device.h>
void
nvif_device_fini(struct nvif_device *device)
diff --git a/drivers/gpu/drm/nouveau/nvif/device.h b/drivers/gpu/drm/nouveau/nvif/device.h
deleted file mode 100644
index 43180f9fe630..000000000000
--- a/drivers/gpu/drm/nouveau/nvif/device.h
+++ /dev/null
@@ -1,62 +0,0 @@
-#ifndef __NVIF_DEVICE_H__
-#define __NVIF_DEVICE_H__
-
-#include "object.h"
-#include "class.h"
-
-struct nvif_device {
- struct nvif_object base;
- struct nvif_object *object; /*XXX: hack for nvif_object() */
- struct nv_device_info_v0 info;
-};
-
-static inline struct nvif_device *
-nvif_device(struct nvif_object *object)
-{
- while (object && object->oclass != 0x0080 /*XXX: NV_DEVICE_CLASS*/ )
- object = object->parent;
- return (void *)object;
-}
-
-int nvif_device_init(struct nvif_object *, void (*dtor)(struct nvif_device *),
- u32 handle, u32 oclass, void *, u32,
- struct nvif_device *);
-void nvif_device_fini(struct nvif_device *);
-int nvif_device_new(struct nvif_object *, u32 handle, u32 oclass,
- void *, u32, struct nvif_device **);
-void nvif_device_ref(struct nvif_device *, struct nvif_device **);
-
-/*XXX*/
-#include <subdev/bios.h>
-#include <subdev/fb.h>
-#include <subdev/vm.h>
-#include <subdev/bar.h>
-#include <subdev/gpio.h>
-#include <subdev/clock.h>
-#include <subdev/i2c.h>
-#include <subdev/timer.h>
-#include <subdev/therm.h>
-
-#define nvkm_device(a) nv_device(nvkm_object((a)))
-#define nvkm_bios(a) nouveau_bios(nvkm_device(a))
-#define nvkm_fb(a) nouveau_fb(nvkm_device(a))
-#define nvkm_vmmgr(a) nouveau_vmmgr(nvkm_device(a))
-#define nvkm_bar(a) nouveau_bar(nvkm_device(a))
-#define nvkm_gpio(a) nouveau_gpio(nvkm_device(a))
-#define nvkm_clock(a) nouveau_clock(nvkm_device(a))
-#define nvkm_i2c(a) nouveau_i2c(nvkm_device(a))
-#define nvkm_timer(a) nouveau_timer(nvkm_device(a))
-#define nvkm_wait(a,b,c,d) nv_wait(nvkm_timer(a), (b), (c), (d))
-#define nvkm_wait_cb(a,b,c) nv_wait_cb(nvkm_timer(a), (b), (c))
-#define nvkm_therm(a) nouveau_therm(nvkm_device(a))
-
-#include <engine/device.h>
-#include <engine/fifo.h>
-#include <engine/graph.h>
-#include <engine/software.h>
-
-#define nvkm_fifo(a) nouveau_fifo(nvkm_device(a))
-#define nvkm_fifo_chan(a) ((struct nouveau_fifo_chan *)nvkm_object(a))
-#define nvkm_gr(a) ((struct nouveau_graph *)nouveau_engine(nvkm_object(a), NVDEV_ENGINE_GR))
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/notify.c b/drivers/gpu/drm/nouveau/nvif/notify.c
index 0898c3155292..8e34748709a0 100644
--- a/drivers/gpu/drm/nouveau/nvif/notify.c
+++ b/drivers/gpu/drm/nouveau/nvif/notify.c
@@ -92,7 +92,7 @@ nvif_notify_func(struct nvif_notify *notify, bool keep)
{
int ret = notify->func(notify);
if (ret == NVIF_NOTIFY_KEEP ||
- !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+ !test_and_clear_bit(NVIF_NOTIFY_USER, &notify->flags)) {
if (!keep)
atomic_dec(&notify->putcnt);
else
diff --git a/drivers/gpu/drm/nouveau/nvif/object.c b/drivers/gpu/drm/nouveau/nvif/object.c
index dd85b56f6aa5..3ab4e2f8cc12 100644
--- a/drivers/gpu/drm/nouveau/nvif/object.c
+++ b/drivers/gpu/drm/nouveau/nvif/object.c
@@ -22,10 +22,10 @@
* Authors: Ben Skeggs <bskeggs@redhat.com>
*/
-#include "object.h"
-#include "client.h"
-#include "driver.h"
-#include "ioctl.h"
+#include <nvif/object.h>
+#include <nvif/client.h>
+#include <nvif/driver.h>
+#include <nvif/ioctl.h>
int
nvif_object_ioctl(struct nvif_object *object, void *data, u32 size, void **hack)
diff --git a/drivers/gpu/drm/nouveau/nvif/object.h b/drivers/gpu/drm/nouveau/nvif/object.h
deleted file mode 100644
index fe519179b76c..000000000000
--- a/drivers/gpu/drm/nouveau/nvif/object.h
+++ /dev/null
@@ -1,75 +0,0 @@
-#ifndef __NVIF_OBJECT_H__
-#define __NVIF_OBJECT_H__
-
-#include <nvif/os.h>
-
-struct nvif_object {
- struct nvif_object *parent;
- struct nvif_object *object; /*XXX: hack for nvif_object() */
- struct kref refcount;
- u32 handle;
- u32 oclass;
- void *data;
- u32 size;
- void *priv; /*XXX: hack */
- void (*dtor)(struct nvif_object *);
- struct {
- void __iomem *ptr;
- u32 size;
- } map;
-};
-
-int nvif_object_init(struct nvif_object *, void (*dtor)(struct nvif_object *),
- u32 handle, u32 oclass, void *, u32,
- struct nvif_object *);
-void nvif_object_fini(struct nvif_object *);
-int nvif_object_new(struct nvif_object *, u32 handle, u32 oclass,
- void *, u32, struct nvif_object **);
-void nvif_object_ref(struct nvif_object *, struct nvif_object **);
-int nvif_object_ioctl(struct nvif_object *, void *, u32, void **);
-int nvif_object_sclass(struct nvif_object *, u32 *, int);
-u32 nvif_object_rd(struct nvif_object *, int, u64);
-void nvif_object_wr(struct nvif_object *, int, u64, u32);
-int nvif_object_mthd(struct nvif_object *, u32, void *, u32);
-int nvif_object_map(struct nvif_object *);
-void nvif_object_unmap(struct nvif_object *);
-
-#define nvif_object(a) (a)->object
-
-#define ioread8_native ioread8
-#define iowrite8_native iowrite8
-#define nvif_rd(a,b,c) ({ \
- struct nvif_object *_object = nvif_object(a); \
- u32 _data; \
- if (likely(_object->map.ptr)) \
- _data = ioread##b##_native((u8 __iomem *)_object->map.ptr + (c)); \
- else \
- _data = nvif_object_rd(_object, (b) / 8, (c)); \
- _data; \
-})
-#define nvif_wr(a,b,c,d) ({ \
- struct nvif_object *_object = nvif_object(a); \
- if (likely(_object->map.ptr)) \
- iowrite##b##_native((d), (u8 __iomem *)_object->map.ptr + (c)); \
- else \
- nvif_object_wr(_object, (b) / 8, (c), (d)); \
-})
-#define nvif_rd08(a,b) ({ u8 _v = nvif_rd((a), 8, (b)); _v; })
-#define nvif_rd16(a,b) ({ u16 _v = nvif_rd((a), 16, (b)); _v; })
-#define nvif_rd32(a,b) ({ u32 _v = nvif_rd((a), 32, (b)); _v; })
-#define nvif_wr08(a,b,c) nvif_wr((a), 8, (b), (u8)(c))
-#define nvif_wr16(a,b,c) nvif_wr((a), 16, (b), (u16)(c))
-#define nvif_wr32(a,b,c) nvif_wr((a), 32, (b), (u32)(c))
-#define nvif_mask(a,b,c,d) ({ \
- u32 _v = nvif_rd32(nvif_object(a), (b)); \
- nvif_wr32(nvif_object(a), (b), (_v & ~(c)) | (d)); \
- _v; \
-})
-
-#define nvif_mthd(a,b,c,d) nvif_object_mthd(nvif_object(a), (b), (c), (d))
-
-/*XXX*/
-#include <core/object.h>
-#define nvkm_object(a) ((struct nouveau_object *)nvif_object(a)->priv)
-
-#endif
diff --git a/drivers/gpu/drm/nouveau/nvif/os.h b/drivers/gpu/drm/nouveau/nvif/os.h
deleted file mode 120000
index bd744b2cf5cf..000000000000
--- a/drivers/gpu/drm/nouveau/nvif/os.h
+++ /dev/null
@@ -1 +0,0 @@
-../core/os.h \ No newline at end of file
diff --git a/drivers/gpu/drm/nouveau/nvkm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/Kbuild
new file mode 100644
index 000000000000..2832147b676c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/Kbuild
@@ -0,0 +1,3 @@
+include $(src)/nvkm/core/Kbuild
+include $(src)/nvkm/subdev/Kbuild
+include $(src)/nvkm/engine/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/Kbuild b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
new file mode 100644
index 000000000000..a2bdb2069113
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/Kbuild
@@ -0,0 +1,17 @@
+nvkm-y := nvkm/core/client.o
+nvkm-y += nvkm/core/engctx.o
+nvkm-y += nvkm/core/engine.o
+nvkm-y += nvkm/core/enum.o
+nvkm-y += nvkm/core/event.o
+nvkm-y += nvkm/core/gpuobj.o
+nvkm-y += nvkm/core/handle.o
+nvkm-y += nvkm/core/ioctl.o
+nvkm-y += nvkm/core/mm.o
+nvkm-y += nvkm/core/namedb.o
+nvkm-y += nvkm/core/notify.o
+nvkm-y += nvkm/core/object.o
+nvkm-y += nvkm/core/option.o
+nvkm-y += nvkm/core/parent.o
+nvkm-y += nvkm/core/printk.o
+nvkm-y += nvkm/core/ramht.o
+nvkm-y += nvkm/core/subdev.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/client.c b/drivers/gpu/drm/nouveau/nvkm/core/client.c
new file mode 100644
index 000000000000..878a82f8f295
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/client.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/notify.h>
+#include <core/option.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+struct nvkm_client_notify {
+ struct nvkm_client *client;
+ struct nvkm_notify n;
+ u8 version;
+ u8 size;
+ union {
+ struct nvif_notify_rep_v0 v0;
+ } rep;
+};
+
+static int
+nvkm_client_notify(struct nvkm_notify *n)
+{
+ struct nvkm_client_notify *notify = container_of(n, typeof(*notify), n);
+ struct nvkm_client *client = notify->client;
+ return client->ntfy(&notify->rep, notify->size, n->data, n->size);
+}
+
+int
+nvkm_client_notify_put(struct nvkm_client *client, int index)
+{
+ if (index < ARRAY_SIZE(client->notify)) {
+ if (client->notify[index]) {
+ nvkm_notify_put(&client->notify[index]->n);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int
+nvkm_client_notify_get(struct nvkm_client *client, int index)
+{
+ if (index < ARRAY_SIZE(client->notify)) {
+ if (client->notify[index]) {
+ nvkm_notify_get(&client->notify[index]->n);
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int
+nvkm_client_notify_del(struct nvkm_client *client, int index)
+{
+ if (index < ARRAY_SIZE(client->notify)) {
+ if (client->notify[index]) {
+ nvkm_notify_fini(&client->notify[index]->n);
+ kfree(client->notify[index]);
+ client->notify[index] = NULL;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+int
+nvkm_client_notify_new(struct nvkm_object *object,
+ struct nvkm_event *event, void *data, u32 size)
+{
+ struct nvkm_client *client = nvkm_client(object);
+ struct nvkm_client_notify *notify;
+ union {
+ struct nvif_notify_req_v0 v0;
+ } *req = data;
+ u8 index, reply;
+ int ret;
+
+ for (index = 0; index < ARRAY_SIZE(client->notify); index++) {
+ if (!client->notify[index])
+ break;
+ }
+
+ if (index == ARRAY_SIZE(client->notify))
+ return -ENOSPC;
+
+ notify = kzalloc(sizeof(*notify), GFP_KERNEL);
+ if (!notify)
+ return -ENOMEM;
+
+ nv_ioctl(client, "notify new size %d\n", size);
+ if (nvif_unpack(req->v0, 0, 0, true)) {
+ nv_ioctl(client, "notify new vers %d reply %d route %02x "
+ "token %llx\n", req->v0.version,
+ req->v0.reply, req->v0.route, req->v0.token);
+ notify->version = req->v0.version;
+ notify->size = sizeof(notify->rep.v0);
+ notify->rep.v0.version = req->v0.version;
+ notify->rep.v0.route = req->v0.route;
+ notify->rep.v0.token = req->v0.token;
+ reply = req->v0.reply;
+ }
+
+ if (ret == 0) {
+ ret = nvkm_notify_init(object, event, nvkm_client_notify,
+ false, data, size, reply, &notify->n);
+ if (ret == 0) {
+ client->notify[index] = notify;
+ notify->client = client;
+ return index;
+ }
+ }
+
+ kfree(notify);
+ return ret;
+}
+
+static int
+nvkm_client_mthd_devlist(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nv_client_devlist_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "client devlist size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "client devlist vers %d count %d\n",
+ args->v0.version, args->v0.count);
+ if (size == sizeof(args->v0.device[0]) * args->v0.count) {
+ ret = nvkm_device_list(args->v0.device, args->v0.count);
+ if (ret >= 0) {
+ args->v0.count = ret;
+ ret = 0;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_client_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ switch (mthd) {
+ case NV_CLIENT_DEVLIST:
+ return nvkm_client_mthd_devlist(object, data, size);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static void
+nvkm_client_dtor(struct nvkm_object *object)
+{
+ struct nvkm_client *client = (void *)object;
+ int i;
+ for (i = 0; i < ARRAY_SIZE(client->notify); i++)
+ nvkm_client_notify_del(client, i);
+ nvkm_object_ref(NULL, &client->device);
+ nvkm_handle_destroy(client->root);
+ nvkm_namedb_destroy(&client->namedb);
+}
+
+static struct nvkm_oclass
+nvkm_client_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .dtor = nvkm_client_dtor,
+ .mthd = nvkm_client_mthd,
+ },
+};
+
+int
+nvkm_client_create_(const char *name, u64 devname, const char *cfg,
+ const char *dbg, int length, void **pobject)
+{
+ struct nvkm_object *device;
+ struct nvkm_client *client;
+ int ret;
+
+ device = (void *)nvkm_device_find(devname);
+ if (!device)
+ return -ENODEV;
+
+ ret = nvkm_namedb_create_(NULL, NULL, &nvkm_client_oclass,
+ NV_CLIENT_CLASS, NULL,
+ (1ULL << NVDEV_ENGINE_DEVICE),
+ length, pobject);
+ client = *pobject;
+ if (ret)
+ return ret;
+
+ ret = nvkm_handle_create(nv_object(client), ~0, ~0, nv_object(client),
+ &client->root);
+ if (ret)
+ return ret;
+
+ /* prevent init/fini being called, os in in charge of this */
+ atomic_set(&nv_object(client)->usecount, 2);
+
+ nvkm_object_ref(device, &client->device);
+ snprintf(client->name, sizeof(client->name), "%s", name);
+ client->debug = nvkm_dbgopt(dbg, "CLIENT");
+ return 0;
+}
+
+int
+nvkm_client_init(struct nvkm_client *client)
+{
+ int ret;
+ nv_debug(client, "init running\n");
+ ret = nvkm_handle_init(client->root);
+ nv_debug(client, "init completed with %d\n", ret);
+ return ret;
+}
+
+int
+nvkm_client_fini(struct nvkm_client *client, bool suspend)
+{
+ const char *name[2] = { "fini", "suspend" };
+ int ret, i;
+ nv_debug(client, "%s running\n", name[suspend]);
+ nv_debug(client, "%s notify\n", name[suspend]);
+ for (i = 0; i < ARRAY_SIZE(client->notify); i++)
+ nvkm_client_notify_put(client, i);
+ nv_debug(client, "%s object\n", name[suspend]);
+ ret = nvkm_handle_fini(client->root, suspend);
+ nv_debug(client, "%s completed with %d\n", name[suspend], ret);
+ return ret;
+}
+
+const char *
+nvkm_client_name(void *obj)
+{
+ const char *client_name = "unknown";
+ struct nvkm_client *client = nvkm_client(obj);
+ if (client)
+ client_name = client->name;
+ return client_name;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engctx.c b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c
new file mode 100644
index 000000000000..fb2acbca75d9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/engctx.c
@@ -0,0 +1,239 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/engctx.h>
+#include <core/engine.h>
+#include <core/client.h>
+
+static inline int
+nvkm_engctx_exists(struct nvkm_object *parent,
+ struct nvkm_engine *engine, void **pobject)
+{
+ struct nvkm_engctx *engctx;
+ struct nvkm_object *parctx;
+
+ list_for_each_entry(engctx, &engine->contexts, head) {
+ parctx = nv_pclass(nv_object(engctx), NV_PARENT_CLASS);
+ if (parctx == parent) {
+ atomic_inc(&nv_object(engctx)->refcount);
+ *pobject = engctx;
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+int
+nvkm_engctx_create_(struct nvkm_object *parent, struct nvkm_object *engobj,
+ struct nvkm_oclass *oclass, struct nvkm_object *pargpu,
+ u32 size, u32 align, u32 flags, int length, void **pobject)
+{
+ struct nvkm_client *client = nvkm_client(parent);
+ struct nvkm_engine *engine = nv_engine(engobj);
+ struct nvkm_object *engctx;
+ unsigned long save;
+ int ret;
+
+ /* check if this engine already has a context for the parent object,
+ * and reference it instead of creating a new one
+ */
+ spin_lock_irqsave(&engine->lock, save);
+ ret = nvkm_engctx_exists(parent, engine, pobject);
+ spin_unlock_irqrestore(&engine->lock, save);
+ if (ret)
+ return ret;
+
+ /* create the new context, supports creating both raw objects and
+ * objects backed by instance memory
+ */
+ if (size) {
+ ret = nvkm_gpuobj_create_(parent, engobj, oclass,
+ NV_ENGCTX_CLASS, pargpu, size,
+ align, flags, length, pobject);
+ } else {
+ ret = nvkm_object_create_(parent, engobj, oclass,
+ NV_ENGCTX_CLASS, length, pobject);
+ }
+
+ engctx = *pobject;
+ if (ret)
+ return ret;
+
+ /* must take the lock again and re-check a context doesn't already
+ * exist (in case of a race) - the lock had to be dropped before as
+ * it's not possible to allocate the object with it held.
+ */
+ spin_lock_irqsave(&engine->lock, save);
+ ret = nvkm_engctx_exists(parent, engine, pobject);
+ if (ret) {
+ spin_unlock_irqrestore(&engine->lock, save);
+ nvkm_object_ref(NULL, &engctx);
+ return ret;
+ }
+
+ if (client->vm)
+ atomic_inc(&client->vm->engref[nv_engidx(engine)]);
+ list_add(&nv_engctx(engctx)->head, &engine->contexts);
+ nv_engctx(engctx)->addr = ~0ULL;
+ spin_unlock_irqrestore(&engine->lock, save);
+ return 0;
+}
+
+void
+nvkm_engctx_destroy(struct nvkm_engctx *engctx)
+{
+ struct nvkm_engine *engine = engctx->gpuobj.object.engine;
+ struct nvkm_client *client = nvkm_client(engctx);
+ unsigned long save;
+
+ nvkm_gpuobj_unmap(&engctx->vma);
+ spin_lock_irqsave(&engine->lock, save);
+ list_del(&engctx->head);
+ spin_unlock_irqrestore(&engine->lock, save);
+
+ if (client->vm)
+ atomic_dec(&client->vm->engref[nv_engidx(engine)]);
+
+ if (engctx->gpuobj.size)
+ nvkm_gpuobj_destroy(&engctx->gpuobj);
+ else
+ nvkm_object_destroy(&engctx->gpuobj.object);
+}
+
+int
+nvkm_engctx_init(struct nvkm_engctx *engctx)
+{
+ struct nvkm_object *object = nv_object(engctx);
+ struct nvkm_subdev *subdev = nv_subdev(object->engine);
+ struct nvkm_object *parent;
+ struct nvkm_subdev *pardev;
+ int ret;
+
+ ret = nvkm_gpuobj_init(&engctx->gpuobj);
+ if (ret)
+ return ret;
+
+ parent = nv_pclass(object->parent, NV_PARENT_CLASS);
+ pardev = nv_subdev(parent->engine);
+ if (nv_parent(parent)->context_attach) {
+ mutex_lock(&pardev->mutex);
+ ret = nv_parent(parent)->context_attach(parent, object);
+ mutex_unlock(&pardev->mutex);
+ }
+
+ if (ret) {
+ nv_error(parent, "failed to attach %s context, %d\n",
+ subdev->name, ret);
+ return ret;
+ }
+
+ nv_debug(parent, "attached %s context\n", subdev->name);
+ return 0;
+}
+
+int
+nvkm_engctx_fini(struct nvkm_engctx *engctx, bool suspend)
+{
+ struct nvkm_object *object = nv_object(engctx);
+ struct nvkm_subdev *subdev = nv_subdev(object->engine);
+ struct nvkm_object *parent;
+ struct nvkm_subdev *pardev;
+ int ret = 0;
+
+ parent = nv_pclass(object->parent, NV_PARENT_CLASS);
+ pardev = nv_subdev(parent->engine);
+ if (nv_parent(parent)->context_detach) {
+ mutex_lock(&pardev->mutex);
+ ret = nv_parent(parent)->context_detach(parent, suspend, object);
+ mutex_unlock(&pardev->mutex);
+ }
+
+ if (ret) {
+ nv_error(parent, "failed to detach %s context, %d\n",
+ subdev->name, ret);
+ return ret;
+ }
+
+ nv_debug(parent, "detached %s context\n", subdev->name);
+ return nvkm_gpuobj_fini(&engctx->gpuobj, suspend);
+}
+
+int
+_nvkm_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_engctx *engctx;
+ int ret;
+
+ ret = nvkm_engctx_create(parent, engine, oclass, NULL, 256, 256,
+ NVOBJ_FLAG_ZERO_ALLOC, &engctx);
+ *pobject = nv_object(engctx);
+ return ret;
+}
+
+void
+_nvkm_engctx_dtor(struct nvkm_object *object)
+{
+ nvkm_engctx_destroy(nv_engctx(object));
+}
+
+int
+_nvkm_engctx_init(struct nvkm_object *object)
+{
+ return nvkm_engctx_init(nv_engctx(object));
+}
+
+int
+_nvkm_engctx_fini(struct nvkm_object *object, bool suspend)
+{
+ return nvkm_engctx_fini(nv_engctx(object), suspend);
+}
+
+struct nvkm_object *
+nvkm_engctx_get(struct nvkm_engine *engine, u64 addr)
+{
+ struct nvkm_engctx *engctx;
+ unsigned long flags;
+
+ spin_lock_irqsave(&engine->lock, flags);
+ list_for_each_entry(engctx, &engine->contexts, head) {
+ if (engctx->addr == addr) {
+ engctx->save = flags;
+ return nv_object(engctx);
+ }
+ }
+ spin_unlock_irqrestore(&engine->lock, flags);
+ return NULL;
+}
+
+void
+nvkm_engctx_put(struct nvkm_object *object)
+{
+ if (object) {
+ struct nvkm_engine *engine = nv_engine(object->engine);
+ struct nvkm_engctx *engctx = nv_engctx(object);
+ spin_unlock_irqrestore(&engine->lock, engctx->save);
+ }
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/engine.c b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
new file mode 100644
index 000000000000..60820173c6aa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/engine.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/engine.h>
+#include <core/device.h>
+#include <core/option.h>
+
+struct nvkm_engine *
+nvkm_engine(void *obj, int idx)
+{
+ obj = nvkm_subdev(obj, idx);
+ if (obj && nv_iclass(obj, NV_ENGINE_CLASS))
+ return nv_engine(obj);
+ return NULL;
+}
+
+int
+nvkm_engine_create_(struct nvkm_object *parent, struct nvkm_object *engobj,
+ struct nvkm_oclass *oclass, bool enable,
+ const char *iname, const char *fname,
+ int length, void **pobject)
+{
+ struct nvkm_engine *engine;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engobj, oclass, NV_ENGINE_CLASS,
+ iname, fname, length, pobject);
+ engine = *pobject;
+ if (ret)
+ return ret;
+
+ if (parent) {
+ struct nvkm_device *device = nv_device(parent);
+ int engidx = nv_engidx(engine);
+
+ if (device->disable_mask & (1ULL << engidx)) {
+ if (!nvkm_boolopt(device->cfgopt, iname, false)) {
+ nv_debug(engine, "engine disabled by hw/fw\n");
+ return -ENODEV;
+ }
+
+ nv_warn(engine, "ignoring hw/fw engine disable\n");
+ }
+
+ if (!nvkm_boolopt(device->cfgopt, iname, enable)) {
+ if (!enable)
+ nv_warn(engine, "disabled, %s=1 to enable\n", iname);
+ return -ENODEV;
+ }
+ }
+
+ INIT_LIST_HEAD(&engine->contexts);
+ spin_lock_init(&engine->lock);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/enum.c b/drivers/gpu/drm/nouveau/nvkm/core/enum.c
new file mode 100644
index 000000000000..4f92bfc13d6b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/enum.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Nouveau Project
+ *
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <core/enum.h>
+
+const struct nvkm_enum *
+nvkm_enum_find(const struct nvkm_enum *en, u32 value)
+{
+ while (en->name) {
+ if (en->value == value)
+ return en;
+ en++;
+ }
+
+ return NULL;
+}
+
+const struct nvkm_enum *
+nvkm_enum_print(const struct nvkm_enum *en, u32 value)
+{
+ en = nvkm_enum_find(en, value);
+ if (en)
+ pr_cont("%s", en->name);
+ else
+ pr_cont("(unknown enum 0x%08x)", value);
+ return en;
+}
+
+void
+nvkm_bitfield_print(const struct nvkm_bitfield *bf, u32 value)
+{
+ while (bf->name) {
+ if (value & bf->mask) {
+ pr_cont(" %s", bf->name);
+ value &= ~bf->mask;
+ }
+
+ bf++;
+ }
+
+ if (value)
+ pr_cont(" (unknown bits 0x%08x)", value);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/event.c b/drivers/gpu/drm/nouveau/nvkm/core/event.c
new file mode 100644
index 000000000000..4e8d3fa042df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/event.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013-2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <core/event.h>
+#include <core/notify.h>
+
+void
+nvkm_event_put(struct nvkm_event *event, u32 types, int index)
+{
+ assert_spin_locked(&event->refs_lock);
+ while (types) {
+ int type = __ffs(types); types &= ~(1 << type);
+ if (--event->refs[index * event->types_nr + type] == 0) {
+ if (event->func->fini)
+ event->func->fini(event, 1 << type, index);
+ }
+ }
+}
+
+void
+nvkm_event_get(struct nvkm_event *event, u32 types, int index)
+{
+ assert_spin_locked(&event->refs_lock);
+ while (types) {
+ int type = __ffs(types); types &= ~(1 << type);
+ if (++event->refs[index * event->types_nr + type] == 1) {
+ if (event->func->init)
+ event->func->init(event, 1 << type, index);
+ }
+ }
+}
+
+void
+nvkm_event_send(struct nvkm_event *event, u32 types, int index,
+ void *data, u32 size)
+{
+ struct nvkm_notify *notify;
+ unsigned long flags;
+
+ if (!event->refs || WARN_ON(index >= event->index_nr))
+ return;
+
+ spin_lock_irqsave(&event->list_lock, flags);
+ list_for_each_entry(notify, &event->list, head) {
+ if (notify->index == index && (notify->types & types)) {
+ if (event->func->send) {
+ event->func->send(data, size, notify);
+ continue;
+ }
+ nvkm_notify_send(notify, data, size);
+ }
+ }
+ spin_unlock_irqrestore(&event->list_lock, flags);
+}
+
+void
+nvkm_event_fini(struct nvkm_event *event)
+{
+ if (event->refs) {
+ kfree(event->refs);
+ event->refs = NULL;
+ }
+}
+
+int
+nvkm_event_init(const struct nvkm_event_func *func, int types_nr, int index_nr,
+ struct nvkm_event *event)
+{
+ event->refs = kzalloc(sizeof(*event->refs) * index_nr * types_nr,
+ GFP_KERNEL);
+ if (!event->refs)
+ return -ENOMEM;
+
+ event->func = func;
+ event->types_nr = types_nr;
+ event->index_nr = index_nr;
+ spin_lock_init(&event->refs_lock);
+ spin_lock_init(&event->list_lock);
+ INIT_LIST_HEAD(&event->list);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c
new file mode 100644
index 000000000000..2eba801aae6f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/gpuobj.c
@@ -0,0 +1,316 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/gpuobj.h>
+#include <core/engine.h>
+
+#include <subdev/instmem.h>
+#include <subdev/bar.h>
+#include <subdev/mmu.h>
+
+void
+nvkm_gpuobj_destroy(struct nvkm_gpuobj *gpuobj)
+{
+ int i;
+
+ if (gpuobj->flags & NVOBJ_FLAG_ZERO_FREE) {
+ for (i = 0; i < gpuobj->size; i += 4)
+ nv_wo32(gpuobj, i, 0x00000000);
+ }
+
+ if (gpuobj->node)
+ nvkm_mm_free(&nv_gpuobj(gpuobj->parent)->heap, &gpuobj->node);
+
+ if (gpuobj->heap.block_size)
+ nvkm_mm_fini(&gpuobj->heap);
+
+ nvkm_object_destroy(&gpuobj->object);
+}
+
+int
+nvkm_gpuobj_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 pclass,
+ struct nvkm_object *pargpu, u32 size, u32 align, u32 flags,
+ int length, void **pobject)
+{
+ struct nvkm_instmem *imem = nvkm_instmem(parent);
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nvkm_gpuobj *gpuobj;
+ struct nvkm_mm *heap = NULL;
+ int ret, i;
+ u64 addr;
+
+ *pobject = NULL;
+
+ if (pargpu) {
+ while ((pargpu = nv_pclass(pargpu, NV_GPUOBJ_CLASS))) {
+ if (nv_gpuobj(pargpu)->heap.block_size)
+ break;
+ pargpu = pargpu->parent;
+ }
+
+ if (unlikely(pargpu == NULL)) {
+ nv_error(parent, "no gpuobj heap\n");
+ return -EINVAL;
+ }
+
+ addr = nv_gpuobj(pargpu)->addr;
+ heap = &nv_gpuobj(pargpu)->heap;
+ atomic_inc(&parent->refcount);
+ } else {
+ ret = imem->alloc(imem, parent, size, align, &parent);
+ pargpu = parent;
+ if (ret)
+ return ret;
+
+ addr = nv_memobj(pargpu)->addr;
+ size = nv_memobj(pargpu)->size;
+
+ if (bar && bar->alloc) {
+ struct nvkm_instobj *iobj = (void *)parent;
+ struct nvkm_mem **mem = (void *)(iobj + 1);
+ struct nvkm_mem *node = *mem;
+ if (!bar->alloc(bar, parent, node, &pargpu)) {
+ nvkm_object_ref(NULL, &parent);
+ parent = pargpu;
+ }
+ }
+ }
+
+ ret = nvkm_object_create_(parent, engine, oclass, pclass |
+ NV_GPUOBJ_CLASS, length, pobject);
+ nvkm_object_ref(NULL, &parent);
+ gpuobj = *pobject;
+ if (ret)
+ return ret;
+
+ gpuobj->parent = pargpu;
+ gpuobj->flags = flags;
+ gpuobj->addr = addr;
+ gpuobj->size = size;
+
+ if (heap) {
+ ret = nvkm_mm_head(heap, 0, 1, size, size, max(align, (u32)1),
+ &gpuobj->node);
+ if (ret)
+ return ret;
+
+ gpuobj->addr += gpuobj->node->offset;
+ }
+
+ if (gpuobj->flags & NVOBJ_FLAG_HEAP) {
+ ret = nvkm_mm_init(&gpuobj->heap, 0, gpuobj->size, 1);
+ if (ret)
+ return ret;
+ }
+
+ if (flags & NVOBJ_FLAG_ZERO_ALLOC) {
+ for (i = 0; i < gpuobj->size; i += 4)
+ nv_wo32(gpuobj, i, 0x00000000);
+ }
+
+ return ret;
+}
+
+struct nvkm_gpuobj_class {
+ struct nvkm_object *pargpu;
+ u64 size;
+ u32 align;
+ u32 flags;
+};
+
+static int
+_nvkm_gpuobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj_class *args = data;
+ struct nvkm_gpuobj *object;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, args->pargpu,
+ args->size, args->align, args->flags,
+ &object);
+ *pobject = nv_object(object);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void
+_nvkm_gpuobj_dtor(struct nvkm_object *object)
+{
+ nvkm_gpuobj_destroy(nv_gpuobj(object));
+}
+
+int
+_nvkm_gpuobj_init(struct nvkm_object *object)
+{
+ return nvkm_gpuobj_init(nv_gpuobj(object));
+}
+
+int
+_nvkm_gpuobj_fini(struct nvkm_object *object, bool suspend)
+{
+ return nvkm_gpuobj_fini(nv_gpuobj(object), suspend);
+}
+
+u32
+_nvkm_gpuobj_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_gpuobj *gpuobj = nv_gpuobj(object);
+ struct nvkm_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
+ if (gpuobj->node)
+ addr += gpuobj->node->offset;
+ return pfuncs->rd32(gpuobj->parent, addr);
+}
+
+void
+_nvkm_gpuobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nvkm_gpuobj *gpuobj = nv_gpuobj(object);
+ struct nvkm_ofuncs *pfuncs = nv_ofuncs(gpuobj->parent);
+ if (gpuobj->node)
+ addr += gpuobj->node->offset;
+ pfuncs->wr32(gpuobj->parent, addr, data);
+}
+
+static struct nvkm_oclass
+_nvkm_gpuobj_oclass = {
+ .handle = 0x00000000,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_gpuobj_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+ },
+};
+
+int
+nvkm_gpuobj_new(struct nvkm_object *parent, struct nvkm_object *pargpu,
+ u32 size, u32 align, u32 flags,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ struct nvkm_object *engine = parent;
+ struct nvkm_gpuobj_class args = {
+ .pargpu = pargpu,
+ .size = size,
+ .align = align,
+ .flags = flags,
+ };
+
+ if (!nv_iclass(engine, NV_SUBDEV_CLASS))
+ engine = &engine->engine->subdev.object;
+ BUG_ON(engine == NULL);
+
+ return nvkm_object_ctor(parent, engine, &_nvkm_gpuobj_oclass,
+ &args, sizeof(args),
+ (struct nvkm_object **)pgpuobj);
+}
+
+int
+nvkm_gpuobj_map(struct nvkm_gpuobj *gpuobj, u32 access, struct nvkm_vma *vma)
+{
+ struct nvkm_bar *bar = nvkm_bar(gpuobj);
+ int ret = -EINVAL;
+
+ if (bar && bar->umap) {
+ struct nvkm_instobj *iobj = (void *)
+ nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
+ struct nvkm_mem **mem = (void *)(iobj + 1);
+ ret = bar->umap(bar, *mem, access, vma);
+ }
+
+ return ret;
+}
+
+int
+nvkm_gpuobj_map_vm(struct nvkm_gpuobj *gpuobj, struct nvkm_vm *vm,
+ u32 access, struct nvkm_vma *vma)
+{
+ struct nvkm_instobj *iobj = (void *)
+ nv_pclass(nv_object(gpuobj), NV_MEMOBJ_CLASS);
+ struct nvkm_mem **mem = (void *)(iobj + 1);
+ int ret;
+
+ ret = nvkm_vm_get(vm, gpuobj->size, 12, access, vma);
+ if (ret)
+ return ret;
+
+ nvkm_vm_map(vma, *mem);
+ return 0;
+}
+
+void
+nvkm_gpuobj_unmap(struct nvkm_vma *vma)
+{
+ if (vma->node) {
+ nvkm_vm_unmap(vma);
+ nvkm_vm_put(vma);
+ }
+}
+
+/* the below is basically only here to support sharing the paged dma object
+ * for PCI(E)GART on <=nv4x chipsets, and should *not* be expected to work
+ * anywhere else.
+ */
+
+static void
+nvkm_gpudup_dtor(struct nvkm_object *object)
+{
+ struct nvkm_gpuobj *gpuobj = (void *)object;
+ nvkm_object_ref(NULL, &gpuobj->parent);
+ nvkm_object_destroy(&gpuobj->object);
+}
+
+static struct nvkm_oclass
+nvkm_gpudup_oclass = {
+ .handle = NV_GPUOBJ_CLASS,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .dtor = nvkm_gpudup_dtor,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ },
+};
+
+int
+nvkm_gpuobj_dup(struct nvkm_object *parent, struct nvkm_gpuobj *base,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ struct nvkm_gpuobj *gpuobj;
+ int ret;
+
+ ret = nvkm_object_create(parent, &parent->engine->subdev.object,
+ &nvkm_gpudup_oclass, 0, &gpuobj);
+ *pgpuobj = gpuobj;
+ if (ret)
+ return ret;
+
+ nvkm_object_ref(nv_object(base), &gpuobj->parent);
+ gpuobj->addr = base->addr;
+ gpuobj->size = base->size;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/handle.c b/drivers/gpu/drm/nouveau/nvkm/core/handle.c
new file mode 100644
index 000000000000..dc7ff10ebe7b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/handle.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/handle.h>
+#include <core/client.h>
+
+#define hprintk(h,l,f,a...) do { \
+ struct nvkm_client *c = nvkm_client((h)->object); \
+ struct nvkm_handle *p = (h)->parent; u32 n = p ? p->name : ~0; \
+ nv_printk((c), l, "0x%08x:0x%08x "f, n, (h)->name, ##a); \
+} while(0)
+
+int
+nvkm_handle_init(struct nvkm_handle *handle)
+{
+ struct nvkm_handle *item;
+ int ret;
+
+ hprintk(handle, TRACE, "init running\n");
+ ret = nvkm_object_inc(handle->object);
+ if (ret)
+ return ret;
+
+ hprintk(handle, TRACE, "init children\n");
+ list_for_each_entry(item, &handle->tree, head) {
+ ret = nvkm_handle_init(item);
+ if (ret)
+ goto fail;
+ }
+
+ hprintk(handle, TRACE, "init completed\n");
+ return 0;
+fail:
+ hprintk(handle, ERROR, "init failed with %d\n", ret);
+ list_for_each_entry_continue_reverse(item, &handle->tree, head) {
+ nvkm_handle_fini(item, false);
+ }
+
+ nvkm_object_dec(handle->object, false);
+ return ret;
+}
+
+int
+nvkm_handle_fini(struct nvkm_handle *handle, bool suspend)
+{
+ static char *name[2] = { "fini", "suspend" };
+ struct nvkm_handle *item;
+ int ret;
+
+ hprintk(handle, TRACE, "%s children\n", name[suspend]);
+ list_for_each_entry(item, &handle->tree, head) {
+ ret = nvkm_handle_fini(item, suspend);
+ if (ret && suspend)
+ goto fail;
+ }
+
+ hprintk(handle, TRACE, "%s running\n", name[suspend]);
+ if (handle->object) {
+ ret = nvkm_object_dec(handle->object, suspend);
+ if (ret && suspend)
+ goto fail;
+ }
+
+ hprintk(handle, TRACE, "%s completed\n", name[suspend]);
+ return 0;
+fail:
+ hprintk(handle, ERROR, "%s failed with %d\n", name[suspend], ret);
+ list_for_each_entry_continue_reverse(item, &handle->tree, head) {
+ int rret = nvkm_handle_init(item);
+ if (rret)
+ hprintk(handle, FATAL, "failed to restart, %d\n", rret);
+ }
+
+ return ret;
+}
+
+int
+nvkm_handle_create(struct nvkm_object *parent, u32 _parent, u32 _handle,
+ struct nvkm_object *object, struct nvkm_handle **phandle)
+{
+ struct nvkm_object *namedb;
+ struct nvkm_handle *handle;
+ int ret;
+
+ namedb = parent;
+ while (!nv_iclass(namedb, NV_NAMEDB_CLASS))
+ namedb = namedb->parent;
+
+ handle = kzalloc(sizeof(*handle), GFP_KERNEL);
+ if (!handle)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&handle->head);
+ INIT_LIST_HEAD(&handle->tree);
+ handle->name = _handle;
+ handle->priv = ~0;
+
+ ret = nvkm_namedb_insert(nv_namedb(namedb), _handle, object, handle);
+ if (ret) {
+ kfree(handle);
+ return ret;
+ }
+
+ if (nv_parent(parent)->object_attach) {
+ ret = nv_parent(parent)->object_attach(parent, object, _handle);
+ if (ret < 0) {
+ nvkm_handle_destroy(handle);
+ return ret;
+ }
+
+ handle->priv = ret;
+ }
+
+ if (object != namedb) {
+ while (!nv_iclass(namedb, NV_CLIENT_CLASS))
+ namedb = namedb->parent;
+
+ handle->parent = nvkm_namedb_get(nv_namedb(namedb), _parent);
+ if (handle->parent) {
+ list_add(&handle->head, &handle->parent->tree);
+ nvkm_namedb_put(handle->parent);
+ }
+ }
+
+ hprintk(handle, TRACE, "created\n");
+ *phandle = handle;
+ return 0;
+}
+
+void
+nvkm_handle_destroy(struct nvkm_handle *handle)
+{
+ struct nvkm_handle *item, *temp;
+
+ hprintk(handle, TRACE, "destroy running\n");
+ list_for_each_entry_safe(item, temp, &handle->tree, head) {
+ nvkm_handle_destroy(item);
+ }
+ list_del(&handle->head);
+
+ if (handle->priv != ~0) {
+ struct nvkm_object *parent = handle->parent->object;
+ nv_parent(parent)->object_detach(parent, handle->priv);
+ }
+
+ hprintk(handle, TRACE, "destroy completed\n");
+ nvkm_namedb_remove(handle);
+ kfree(handle);
+}
+
+struct nvkm_object *
+nvkm_handle_ref(struct nvkm_object *parent, u32 name)
+{
+ struct nvkm_object *object = NULL;
+ struct nvkm_handle *handle;
+
+ while (!nv_iclass(parent, NV_NAMEDB_CLASS))
+ parent = parent->parent;
+
+ handle = nvkm_namedb_get(nv_namedb(parent), name);
+ if (handle) {
+ nvkm_object_ref(handle->object, &object);
+ nvkm_namedb_put(handle);
+ }
+
+ return object;
+}
+
+struct nvkm_handle *
+nvkm_handle_get_class(struct nvkm_object *engctx, u16 oclass)
+{
+ struct nvkm_namedb *namedb;
+ if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
+ return nvkm_namedb_get_class(namedb, oclass);
+ return NULL;
+}
+
+struct nvkm_handle *
+nvkm_handle_get_vinst(struct nvkm_object *engctx, u64 vinst)
+{
+ struct nvkm_namedb *namedb;
+ if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
+ return nvkm_namedb_get_vinst(namedb, vinst);
+ return NULL;
+}
+
+struct nvkm_handle *
+nvkm_handle_get_cinst(struct nvkm_object *engctx, u32 cinst)
+{
+ struct nvkm_namedb *namedb;
+ if (engctx && (namedb = (void *)nv_pclass(engctx, NV_NAMEDB_CLASS)))
+ return nvkm_namedb_get_cinst(namedb, cinst);
+ return NULL;
+}
+
+void
+nvkm_handle_put(struct nvkm_handle *handle)
+{
+ if (handle)
+ nvkm_namedb_put(handle);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
new file mode 100644
index 000000000000..4459ff5f4cb8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/ioctl.c
@@ -0,0 +1,526 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <core/ioctl.h>
+#include <core/client.h>
+#include <core/engine.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+
+#include <nvif/unpack.h>
+#include <nvif/ioctl.h>
+
+static int
+nvkm_ioctl_nop(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_nop none;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "nop size %d\n", size);
+ if (nvif_unvers(args->none)) {
+ nv_ioctl(object, "nop\n");
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_sclass(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_sclass_v0 v0;
+ } *args = data;
+ int ret;
+
+ if (!nv_iclass(object, NV_PARENT_CLASS)) {
+ nv_debug(object, "cannot have children (sclass)\n");
+ return -ENODEV;
+ }
+
+ nv_ioctl(object, "sclass size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "sclass vers %d count %d\n",
+ args->v0.version, args->v0.count);
+ if (size == args->v0.count * sizeof(args->v0.oclass[0])) {
+ ret = nvkm_parent_lclass(object, args->v0.oclass,
+ args->v0.count);
+ if (ret >= 0) {
+ args->v0.count = ret;
+ ret = 0;
+ }
+ } else {
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_new(struct nvkm_handle *handle, void *data, u32 size)
+{
+ union {
+ struct nvif_ioctl_new_v0 v0;
+ } *args = data;
+ struct nvkm_client *client = nvkm_client(handle->object);
+ struct nvkm_object *engctx = NULL;
+ struct nvkm_object *object = NULL;
+ struct nvkm_parent *parent;
+ struct nvkm_object *engine;
+ struct nvkm_oclass *oclass;
+ u32 _handle, _oclass;
+ int ret;
+
+ nv_ioctl(client, "new size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ _handle = args->v0.handle;
+ _oclass = args->v0.oclass;
+ } else
+ return ret;
+
+ nv_ioctl(client, "new vers %d handle %08x class %08x "
+ "route %02x token %llx\n",
+ args->v0.version, _handle, _oclass,
+ args->v0.route, args->v0.token);
+
+ if (!nv_iclass(handle->object, NV_PARENT_CLASS)) {
+ nv_debug(handle->object, "cannot have children (ctor)\n");
+ ret = -ENODEV;
+ goto fail_class;
+ }
+
+ parent = nv_parent(handle->object);
+
+ /* check that parent supports the requested subclass */
+ ret = nvkm_parent_sclass(&parent->object, _oclass, &engine, &oclass);
+ if (ret) {
+ nv_debug(parent, "illegal class 0x%04x\n", _oclass);
+ goto fail_class;
+ }
+
+ /* make sure engine init has been completed *before* any objects
+ * it controls are created - the constructors may depend on
+ * state calculated at init (ie. default context construction)
+ */
+ if (engine) {
+ ret = nvkm_object_inc(engine);
+ if (ret)
+ goto fail_class;
+ }
+
+ /* if engine requires it, create a context object to insert
+ * between the parent and its children (eg. PGRAPH context)
+ */
+ if (engine && nv_engine(engine)->cclass) {
+ ret = nvkm_object_ctor(&parent->object, engine,
+ nv_engine(engine)->cclass,
+ data, size, &engctx);
+ if (ret)
+ goto fail_engctx;
+ } else {
+ nvkm_object_ref(&parent->object, &engctx);
+ }
+
+ /* finally, create new object and bind it to its handle */
+ ret = nvkm_object_ctor(engctx, engine, oclass, data, size, &object);
+ client->data = object;
+ if (ret)
+ goto fail_ctor;
+
+ ret = nvkm_object_inc(object);
+ if (ret)
+ goto fail_init;
+
+ ret = nvkm_handle_create(&parent->object, handle->name,
+ _handle, object, &handle);
+ if (ret)
+ goto fail_handle;
+
+ ret = nvkm_handle_init(handle);
+ handle->route = args->v0.route;
+ handle->token = args->v0.token;
+ if (ret)
+ nvkm_handle_destroy(handle);
+
+fail_handle:
+ nvkm_object_dec(object, false);
+fail_init:
+ nvkm_object_ref(NULL, &object);
+fail_ctor:
+ nvkm_object_ref(NULL, &engctx);
+fail_engctx:
+ if (engine)
+ nvkm_object_dec(engine, false);
+fail_class:
+ return ret;
+}
+
+static int
+nvkm_ioctl_del(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_del none;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "delete size %d\n", size);
+ if (nvif_unvers(args->none)) {
+ nv_ioctl(object, "delete\n");
+ nvkm_handle_fini(handle, false);
+ nvkm_handle_destroy(handle);
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_mthd(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+ union {
+ struct nvif_ioctl_mthd_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "mthd size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "mthd vers %d mthd %02x\n",
+ args->v0.version, args->v0.method);
+ if (ret = -ENODEV, ofuncs->mthd)
+ ret = ofuncs->mthd(object, args->v0.method, data, size);
+ }
+
+ return ret;
+}
+
+
+static int
+nvkm_ioctl_rd(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+ union {
+ struct nvif_ioctl_rd_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "rd size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "rd vers %d size %d addr %016llx\n",
+ args->v0.version, args->v0.size, args->v0.addr);
+ switch (args->v0.size) {
+ case 1:
+ if (ret = -ENODEV, ofuncs->rd08) {
+ args->v0.data = nv_ro08(object, args->v0.addr);
+ ret = 0;
+ }
+ break;
+ case 2:
+ if (ret = -ENODEV, ofuncs->rd16) {
+ args->v0.data = nv_ro16(object, args->v0.addr);
+ ret = 0;
+ }
+ break;
+ case 4:
+ if (ret = -ENODEV, ofuncs->rd32) {
+ args->v0.data = nv_ro32(object, args->v0.addr);
+ ret = 0;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_wr(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+ union {
+ struct nvif_ioctl_wr_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "wr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "wr vers %d size %d addr %016llx data %08x\n",
+ args->v0.version, args->v0.size, args->v0.addr,
+ args->v0.data);
+ switch (args->v0.size) {
+ case 1:
+ if (ret = -ENODEV, ofuncs->wr08) {
+ nv_wo08(object, args->v0.addr, args->v0.data);
+ ret = 0;
+ }
+ break;
+ case 2:
+ if (ret = -ENODEV, ofuncs->wr16) {
+ nv_wo16(object, args->v0.addr, args->v0.data);
+ ret = 0;
+ }
+ break;
+ case 4:
+ if (ret = -ENODEV, ofuncs->wr32) {
+ nv_wo32(object, args->v0.addr, args->v0.data);
+ ret = 0;
+ }
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_map(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+ union {
+ struct nvif_ioctl_map_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "map size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "map vers %d\n", args->v0.version);
+ if (ret = -ENODEV, ofuncs->map) {
+ ret = ofuncs->map(object, &args->v0.handle,
+ &args->v0.length);
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_unmap(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_unmap none;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "unmap size %d\n", size);
+ if (nvif_unvers(args->none)) {
+ nv_ioctl(object, "unmap\n");
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_new(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_object *object = handle->object;
+ struct nvkm_ofuncs *ofuncs = object->oclass->ofuncs;
+ union {
+ struct nvif_ioctl_ntfy_new_v0 v0;
+ } *args = data;
+ struct nvkm_event *event;
+ int ret;
+
+ nv_ioctl(object, "ntfy new size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "ntfy new vers %d event %02x\n",
+ args->v0.version, args->v0.event);
+ if (ret = -ENODEV, ofuncs->ntfy)
+ ret = ofuncs->ntfy(object, args->v0.event, &event);
+ if (ret == 0) {
+ ret = nvkm_client_notify_new(object, event, data, size);
+ if (ret >= 0) {
+ args->v0.index = ret;
+ ret = 0;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_del(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_client *client = nvkm_client(handle->object);
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_ntfy_del_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "ntfy del size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "ntfy del vers %d index %d\n",
+ args->v0.version, args->v0.index);
+ ret = nvkm_client_notify_del(client, args->v0.index);
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_get(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_client *client = nvkm_client(handle->object);
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_ntfy_get_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "ntfy get size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "ntfy get vers %d index %d\n",
+ args->v0.version, args->v0.index);
+ ret = nvkm_client_notify_get(client, args->v0.index);
+ }
+
+ return ret;
+}
+
+static int
+nvkm_ioctl_ntfy_put(struct nvkm_handle *handle, void *data, u32 size)
+{
+ struct nvkm_client *client = nvkm_client(handle->object);
+ struct nvkm_object *object = handle->object;
+ union {
+ struct nvif_ioctl_ntfy_put_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "ntfy put size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "ntfy put vers %d index %d\n",
+ args->v0.version, args->v0.index);
+ ret = nvkm_client_notify_put(client, args->v0.index);
+ }
+
+ return ret;
+}
+
+static struct {
+ int version;
+ int (*func)(struct nvkm_handle *, void *, u32);
+}
+nvkm_ioctl_v0[] = {
+ { 0x00, nvkm_ioctl_nop },
+ { 0x00, nvkm_ioctl_sclass },
+ { 0x00, nvkm_ioctl_new },
+ { 0x00, nvkm_ioctl_del },
+ { 0x00, nvkm_ioctl_mthd },
+ { 0x00, nvkm_ioctl_rd },
+ { 0x00, nvkm_ioctl_wr },
+ { 0x00, nvkm_ioctl_map },
+ { 0x00, nvkm_ioctl_unmap },
+ { 0x00, nvkm_ioctl_ntfy_new },
+ { 0x00, nvkm_ioctl_ntfy_del },
+ { 0x00, nvkm_ioctl_ntfy_get },
+ { 0x00, nvkm_ioctl_ntfy_put },
+};
+
+static int
+nvkm_ioctl_path(struct nvkm_handle *parent, u32 type, u32 nr, u32 *path,
+ void *data, u32 size, u8 owner, u8 *route, u64 *token)
+{
+ struct nvkm_handle *handle = parent;
+ struct nvkm_namedb *namedb;
+ struct nvkm_object *object;
+ int ret;
+
+ while ((object = parent->object), nr--) {
+ nv_ioctl(object, "path 0x%08x\n", path[nr]);
+ if (!nv_iclass(object, NV_PARENT_CLASS)) {
+ nv_debug(object, "cannot have children (path)\n");
+ return -EINVAL;
+ }
+
+ if (!(namedb = (void *)nv_pclass(object, NV_NAMEDB_CLASS)) ||
+ !(handle = nvkm_namedb_get(namedb, path[nr]))) {
+ nv_debug(object, "handle 0x%08x not found\n", path[nr]);
+ return -ENOENT;
+ }
+ nvkm_namedb_put(handle);
+ parent = handle;
+ }
+
+ if (owner != NVIF_IOCTL_V0_OWNER_ANY && owner != handle->route) {
+ nv_ioctl(object, "object route != owner\n");
+ return -EACCES;
+ }
+ *route = handle->route;
+ *token = handle->token;
+
+ if (ret = -EINVAL, type < ARRAY_SIZE(nvkm_ioctl_v0)) {
+ if (nvkm_ioctl_v0[type].version == 0)
+ ret = nvkm_ioctl_v0[type].func(handle, data, size);
+ }
+
+ return ret;
+}
+
+int
+nvkm_ioctl(struct nvkm_client *client, bool supervisor,
+ void *data, u32 size, void **hack)
+{
+ union {
+ struct nvif_ioctl_v0 v0;
+ } *args = data;
+ int ret;
+
+ client->super = supervisor;
+ nv_ioctl(client, "size %d\n", size);
+
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(client, "vers %d type %02x path %d owner %02x\n",
+ args->v0.version, args->v0.type, args->v0.path_nr,
+ args->v0.owner);
+ ret = nvkm_ioctl_path(client->root, args->v0.type,
+ args->v0.path_nr, args->v0.path,
+ data, size, args->v0.owner,
+ &args->v0.route, &args->v0.token);
+ }
+
+ nv_ioctl(client, "return %d\n", ret);
+ if (hack) {
+ *hack = client->data;
+ client->data = NULL;
+ }
+
+ client->super = false;
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/mm.c b/drivers/gpu/drm/nouveau/nvkm/core/mm.c
new file mode 100644
index 000000000000..7f458dfd5608
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/mm.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/mm.h>
+
+#define node(root, dir) ((root)->nl_entry.dir == &mm->nodes) ? NULL : \
+ list_entry((root)->nl_entry.dir, struct nvkm_mm_node, nl_entry)
+
+static void
+nvkm_mm_dump(struct nvkm_mm *mm, const char *header)
+{
+ struct nvkm_mm_node *node;
+
+ printk(KERN_ERR "nvkm: %s\n", header);
+ printk(KERN_ERR "nvkm: node list:\n");
+ list_for_each_entry(node, &mm->nodes, nl_entry) {
+ printk(KERN_ERR "nvkm: \t%08x %08x %d\n",
+ node->offset, node->length, node->type);
+ }
+ printk(KERN_ERR "nvkm: free list:\n");
+ list_for_each_entry(node, &mm->free, fl_entry) {
+ printk(KERN_ERR "nvkm: \t%08x %08x %d\n",
+ node->offset, node->length, node->type);
+ }
+}
+
+void
+nvkm_mm_free(struct nvkm_mm *mm, struct nvkm_mm_node **pthis)
+{
+ struct nvkm_mm_node *this = *pthis;
+
+ if (this) {
+ struct nvkm_mm_node *prev = node(this, prev);
+ struct nvkm_mm_node *next = node(this, next);
+
+ if (prev && prev->type == NVKM_MM_TYPE_NONE) {
+ prev->length += this->length;
+ list_del(&this->nl_entry);
+ kfree(this); this = prev;
+ }
+
+ if (next && next->type == NVKM_MM_TYPE_NONE) {
+ next->offset = this->offset;
+ next->length += this->length;
+ if (this->type == NVKM_MM_TYPE_NONE)
+ list_del(&this->fl_entry);
+ list_del(&this->nl_entry);
+ kfree(this); this = NULL;
+ }
+
+ if (this && this->type != NVKM_MM_TYPE_NONE) {
+ list_for_each_entry(prev, &mm->free, fl_entry) {
+ if (this->offset < prev->offset)
+ break;
+ }
+
+ list_add_tail(&this->fl_entry, &prev->fl_entry);
+ this->type = NVKM_MM_TYPE_NONE;
+ }
+ }
+
+ *pthis = NULL;
+}
+
+static struct nvkm_mm_node *
+region_head(struct nvkm_mm *mm, struct nvkm_mm_node *a, u32 size)
+{
+ struct nvkm_mm_node *b;
+
+ if (a->length == size)
+ return a;
+
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (unlikely(b == NULL))
+ return NULL;
+
+ b->offset = a->offset;
+ b->length = size;
+ b->heap = a->heap;
+ b->type = a->type;
+ a->offset += size;
+ a->length -= size;
+ list_add_tail(&b->nl_entry, &a->nl_entry);
+ if (b->type == NVKM_MM_TYPE_NONE)
+ list_add_tail(&b->fl_entry, &a->fl_entry);
+
+ return b;
+}
+
+int
+nvkm_mm_head(struct nvkm_mm *mm, u8 heap, u8 type, u32 size_max, u32 size_min,
+ u32 align, struct nvkm_mm_node **pnode)
+{
+ struct nvkm_mm_node *prev, *this, *next;
+ u32 mask = align - 1;
+ u32 splitoff;
+ u32 s, e;
+
+ BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
+
+ list_for_each_entry(this, &mm->free, fl_entry) {
+ if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
+ if (this->heap != heap)
+ continue;
+ }
+ e = this->offset + this->length;
+ s = this->offset;
+
+ prev = node(this, prev);
+ if (prev && prev->type != type)
+ s = roundup(s, mm->block_size);
+
+ next = node(this, next);
+ if (next && next->type != type)
+ e = rounddown(e, mm->block_size);
+
+ s = (s + mask) & ~mask;
+ e &= ~mask;
+ if (s > e || e - s < size_min)
+ continue;
+
+ splitoff = s - this->offset;
+ if (splitoff && !region_head(mm, this, splitoff))
+ return -ENOMEM;
+
+ this = region_head(mm, this, min(size_max, e - s));
+ if (!this)
+ return -ENOMEM;
+
+ this->type = type;
+ list_del(&this->fl_entry);
+ *pnode = this;
+ return 0;
+ }
+
+ return -ENOSPC;
+}
+
+static struct nvkm_mm_node *
+region_tail(struct nvkm_mm *mm, struct nvkm_mm_node *a, u32 size)
+{
+ struct nvkm_mm_node *b;
+
+ if (a->length == size)
+ return a;
+
+ b = kmalloc(sizeof(*b), GFP_KERNEL);
+ if (unlikely(b == NULL))
+ return NULL;
+
+ a->length -= size;
+ b->offset = a->offset + a->length;
+ b->length = size;
+ b->heap = a->heap;
+ b->type = a->type;
+
+ list_add(&b->nl_entry, &a->nl_entry);
+ if (b->type == NVKM_MM_TYPE_NONE)
+ list_add(&b->fl_entry, &a->fl_entry);
+
+ return b;
+}
+
+int
+nvkm_mm_tail(struct nvkm_mm *mm, u8 heap, u8 type, u32 size_max, u32 size_min,
+ u32 align, struct nvkm_mm_node **pnode)
+{
+ struct nvkm_mm_node *prev, *this, *next;
+ u32 mask = align - 1;
+
+ BUG_ON(type == NVKM_MM_TYPE_NONE || type == NVKM_MM_TYPE_HOLE);
+
+ list_for_each_entry_reverse(this, &mm->free, fl_entry) {
+ u32 e = this->offset + this->length;
+ u32 s = this->offset;
+ u32 c = 0, a;
+ if (unlikely(heap != NVKM_MM_HEAP_ANY)) {
+ if (this->heap != heap)
+ continue;
+ }
+
+ prev = node(this, prev);
+ if (prev && prev->type != type)
+ s = roundup(s, mm->block_size);
+
+ next = node(this, next);
+ if (next && next->type != type) {
+ e = rounddown(e, mm->block_size);
+ c = next->offset - e;
+ }
+
+ s = (s + mask) & ~mask;
+ a = e - s;
+ if (s > e || a < size_min)
+ continue;
+
+ a = min(a, size_max);
+ s = (e - a) & ~mask;
+ c += (e - s) - a;
+
+ if (c && !region_tail(mm, this, c))
+ return -ENOMEM;
+
+ this = region_tail(mm, this, a);
+ if (!this)
+ return -ENOMEM;
+
+ this->type = type;
+ list_del(&this->fl_entry);
+ *pnode = this;
+ return 0;
+ }
+
+ return -ENOSPC;
+}
+
+int
+nvkm_mm_init(struct nvkm_mm *mm, u32 offset, u32 length, u32 block)
+{
+ struct nvkm_mm_node *node, *prev;
+ u32 next;
+
+ if (nvkm_mm_initialised(mm)) {
+ prev = list_last_entry(&mm->nodes, typeof(*node), nl_entry);
+ next = prev->offset + prev->length;
+ if (next != offset) {
+ BUG_ON(next > offset);
+ if (!(node = kzalloc(sizeof(*node), GFP_KERNEL)))
+ return -ENOMEM;
+ node->type = NVKM_MM_TYPE_HOLE;
+ node->offset = next;
+ node->length = offset - next;
+ list_add_tail(&node->nl_entry, &mm->nodes);
+ }
+ BUG_ON(block != mm->block_size);
+ } else {
+ INIT_LIST_HEAD(&mm->nodes);
+ INIT_LIST_HEAD(&mm->free);
+ mm->block_size = block;
+ mm->heap_nodes = 0;
+ }
+
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
+ if (!node)
+ return -ENOMEM;
+
+ if (length) {
+ node->offset = roundup(offset, mm->block_size);
+ node->length = rounddown(offset + length, mm->block_size);
+ node->length -= node->offset;
+ }
+
+ list_add_tail(&node->nl_entry, &mm->nodes);
+ list_add_tail(&node->fl_entry, &mm->free);
+ node->heap = ++mm->heap_nodes;
+ return 0;
+}
+
+int
+nvkm_mm_fini(struct nvkm_mm *mm)
+{
+ struct nvkm_mm_node *node, *temp;
+ int nodes = 0;
+
+ if (!nvkm_mm_initialised(mm))
+ return 0;
+
+ list_for_each_entry(node, &mm->nodes, nl_entry) {
+ if (node->type != NVKM_MM_TYPE_HOLE) {
+ if (++nodes > mm->heap_nodes) {
+ nvkm_mm_dump(mm, "mm not clean!");
+ return -EBUSY;
+ }
+ }
+ }
+
+ list_for_each_entry_safe(node, temp, &mm->nodes, nl_entry) {
+ list_del(&node->nl_entry);
+ kfree(node);
+ }
+
+ mm->heap_nodes = 0;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/namedb.c b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c
new file mode 100644
index 000000000000..6400767c5dba
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/namedb.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/namedb.h>
+#include <core/gpuobj.h>
+#include <core/handle.h>
+
+static struct nvkm_handle *
+nvkm_namedb_lookup(struct nvkm_namedb *namedb, u32 name)
+{
+ struct nvkm_handle *handle;
+
+ list_for_each_entry(handle, &namedb->list, node) {
+ if (handle->name == name)
+ return handle;
+ }
+
+ return NULL;
+}
+
+static struct nvkm_handle *
+nvkm_namedb_lookup_class(struct nvkm_namedb *namedb, u16 oclass)
+{
+ struct nvkm_handle *handle;
+
+ list_for_each_entry(handle, &namedb->list, node) {
+ if (nv_mclass(handle->object) == oclass)
+ return handle;
+ }
+
+ return NULL;
+}
+
+static struct nvkm_handle *
+nvkm_namedb_lookup_vinst(struct nvkm_namedb *namedb, u64 vinst)
+{
+ struct nvkm_handle *handle;
+
+ list_for_each_entry(handle, &namedb->list, node) {
+ if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+ if (nv_gpuobj(handle->object)->addr == vinst)
+ return handle;
+ }
+ }
+
+ return NULL;
+}
+
+static struct nvkm_handle *
+nvkm_namedb_lookup_cinst(struct nvkm_namedb *namedb, u32 cinst)
+{
+ struct nvkm_handle *handle;
+
+ list_for_each_entry(handle, &namedb->list, node) {
+ if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+ if (nv_gpuobj(handle->object)->node &&
+ nv_gpuobj(handle->object)->node->offset == cinst)
+ return handle;
+ }
+ }
+
+ return NULL;
+}
+
+int
+nvkm_namedb_insert(struct nvkm_namedb *namedb, u32 name,
+ struct nvkm_object *object,
+ struct nvkm_handle *handle)
+{
+ int ret = -EEXIST;
+ write_lock_irq(&namedb->lock);
+ if (!nvkm_namedb_lookup(namedb, name)) {
+ nvkm_object_ref(object, &handle->object);
+ handle->namedb = namedb;
+ list_add(&handle->node, &namedb->list);
+ ret = 0;
+ }
+ write_unlock_irq(&namedb->lock);
+ return ret;
+}
+
+void
+nvkm_namedb_remove(struct nvkm_handle *handle)
+{
+ struct nvkm_namedb *namedb = handle->namedb;
+ struct nvkm_object *object = handle->object;
+ write_lock_irq(&namedb->lock);
+ list_del(&handle->node);
+ write_unlock_irq(&namedb->lock);
+ nvkm_object_ref(NULL, &object);
+}
+
+struct nvkm_handle *
+nvkm_namedb_get(struct nvkm_namedb *namedb, u32 name)
+{
+ struct nvkm_handle *handle;
+ read_lock(&namedb->lock);
+ handle = nvkm_namedb_lookup(namedb, name);
+ if (handle == NULL)
+ read_unlock(&namedb->lock);
+ return handle;
+}
+
+struct nvkm_handle *
+nvkm_namedb_get_class(struct nvkm_namedb *namedb, u16 oclass)
+{
+ struct nvkm_handle *handle;
+ read_lock(&namedb->lock);
+ handle = nvkm_namedb_lookup_class(namedb, oclass);
+ if (handle == NULL)
+ read_unlock(&namedb->lock);
+ return handle;
+}
+
+struct nvkm_handle *
+nvkm_namedb_get_vinst(struct nvkm_namedb *namedb, u64 vinst)
+{
+ struct nvkm_handle *handle;
+ read_lock(&namedb->lock);
+ handle = nvkm_namedb_lookup_vinst(namedb, vinst);
+ if (handle == NULL)
+ read_unlock(&namedb->lock);
+ return handle;
+}
+
+struct nvkm_handle *
+nvkm_namedb_get_cinst(struct nvkm_namedb *namedb, u32 cinst)
+{
+ struct nvkm_handle *handle;
+ read_lock(&namedb->lock);
+ handle = nvkm_namedb_lookup_cinst(namedb, cinst);
+ if (handle == NULL)
+ read_unlock(&namedb->lock);
+ return handle;
+}
+
+void
+nvkm_namedb_put(struct nvkm_handle *handle)
+{
+ if (handle)
+ read_unlock(&handle->namedb->lock);
+}
+
+int
+nvkm_namedb_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 pclass,
+ struct nvkm_oclass *sclass, u64 engcls,
+ int length, void **pobject)
+{
+ struct nvkm_namedb *namedb;
+ int ret;
+
+ ret = nvkm_parent_create_(parent, engine, oclass, pclass |
+ NV_NAMEDB_CLASS, sclass, engcls,
+ length, pobject);
+ namedb = *pobject;
+ if (ret)
+ return ret;
+
+ rwlock_init(&namedb->lock);
+ INIT_LIST_HEAD(&namedb->list);
+ return 0;
+}
+
+int
+_nvkm_namedb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_namedb *object;
+ int ret;
+
+ ret = nvkm_namedb_create(parent, engine, oclass, 0, NULL, 0, &object);
+ *pobject = nv_object(object);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/notify.c b/drivers/gpu/drm/nouveau/nvkm/core/notify.c
new file mode 100644
index 000000000000..023610d01458
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/notify.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <core/notify.h>
+#include <core/event.h>
+
+static inline void
+nvkm_notify_put_locked(struct nvkm_notify *notify)
+{
+ if (notify->block++ == 0)
+ nvkm_event_put(notify->event, notify->types, notify->index);
+}
+
+void
+nvkm_notify_put(struct nvkm_notify *notify)
+{
+ struct nvkm_event *event = notify->event;
+ unsigned long flags;
+ if (likely(event) &&
+ test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+ spin_lock_irqsave(&event->refs_lock, flags);
+ nvkm_notify_put_locked(notify);
+ spin_unlock_irqrestore(&event->refs_lock, flags);
+ if (test_bit(NVKM_NOTIFY_WORK, &notify->flags))
+ flush_work(&notify->work);
+ }
+}
+
+static inline void
+nvkm_notify_get_locked(struct nvkm_notify *notify)
+{
+ if (--notify->block == 0)
+ nvkm_event_get(notify->event, notify->types, notify->index);
+}
+
+void
+nvkm_notify_get(struct nvkm_notify *notify)
+{
+ struct nvkm_event *event = notify->event;
+ unsigned long flags;
+ if (likely(event) &&
+ !test_and_set_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+ spin_lock_irqsave(&event->refs_lock, flags);
+ nvkm_notify_get_locked(notify);
+ spin_unlock_irqrestore(&event->refs_lock, flags);
+ }
+}
+
+static inline void
+nvkm_notify_func(struct nvkm_notify *notify)
+{
+ struct nvkm_event *event = notify->event;
+ int ret = notify->func(notify);
+ unsigned long flags;
+ if ((ret == NVKM_NOTIFY_KEEP) ||
+ !test_and_clear_bit(NVKM_NOTIFY_USER, &notify->flags)) {
+ spin_lock_irqsave(&event->refs_lock, flags);
+ nvkm_notify_get_locked(notify);
+ spin_unlock_irqrestore(&event->refs_lock, flags);
+ }
+}
+
+static void
+nvkm_notify_work(struct work_struct *work)
+{
+ struct nvkm_notify *notify = container_of(work, typeof(*notify), work);
+ nvkm_notify_func(notify);
+}
+
+void
+nvkm_notify_send(struct nvkm_notify *notify, void *data, u32 size)
+{
+ struct nvkm_event *event = notify->event;
+ unsigned long flags;
+
+ assert_spin_locked(&event->list_lock);
+ BUG_ON(size != notify->size);
+
+ spin_lock_irqsave(&event->refs_lock, flags);
+ if (notify->block) {
+ spin_unlock_irqrestore(&event->refs_lock, flags);
+ return;
+ }
+ nvkm_notify_put_locked(notify);
+ spin_unlock_irqrestore(&event->refs_lock, flags);
+
+ if (test_bit(NVKM_NOTIFY_WORK, &notify->flags)) {
+ memcpy((void *)notify->data, data, size);
+ schedule_work(&notify->work);
+ } else {
+ notify->data = data;
+ nvkm_notify_func(notify);
+ notify->data = NULL;
+ }
+}
+
+void
+nvkm_notify_fini(struct nvkm_notify *notify)
+{
+ unsigned long flags;
+ if (notify->event) {
+ nvkm_notify_put(notify);
+ spin_lock_irqsave(&notify->event->list_lock, flags);
+ list_del(&notify->head);
+ spin_unlock_irqrestore(&notify->event->list_lock, flags);
+ kfree((void *)notify->data);
+ notify->event = NULL;
+ }
+}
+
+int
+nvkm_notify_init(struct nvkm_object *object, struct nvkm_event *event,
+ int (*func)(struct nvkm_notify *), bool work,
+ void *data, u32 size, u32 reply,
+ struct nvkm_notify *notify)
+{
+ unsigned long flags;
+ int ret = -ENODEV;
+ if ((notify->event = event), event->refs) {
+ ret = event->func->ctor(object, data, size, notify);
+ if (ret == 0 && (ret = -EINVAL, notify->size == reply)) {
+ notify->flags = 0;
+ notify->block = 1;
+ notify->func = func;
+ notify->data = NULL;
+ if (ret = 0, work) {
+ INIT_WORK(&notify->work, nvkm_notify_work);
+ set_bit(NVKM_NOTIFY_WORK, &notify->flags);
+ notify->data = kmalloc(reply, GFP_KERNEL);
+ if (!notify->data)
+ ret = -ENOMEM;
+ }
+ }
+ if (ret == 0) {
+ spin_lock_irqsave(&event->list_lock, flags);
+ list_add_tail(&notify->head, &event->list);
+ spin_unlock_irqrestore(&event->list_lock, flags);
+ }
+ }
+ if (ret)
+ notify->event = NULL;
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/object.c b/drivers/gpu/drm/nouveau/nvkm/core/object.c
new file mode 100644
index 000000000000..979f3627d395
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/object.c
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/object.h>
+#include <core/engine.h>
+
+#ifdef NVKM_OBJECT_MAGIC
+static struct list_head _objlist = LIST_HEAD_INIT(_objlist);
+static DEFINE_SPINLOCK(_objlist_lock);
+#endif
+
+int
+nvkm_object_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 pclass,
+ int size, void **pobject)
+{
+ struct nvkm_object *object;
+
+ object = *pobject = kzalloc(size, GFP_KERNEL);
+ if (!object)
+ return -ENOMEM;
+
+ nvkm_object_ref(parent, &object->parent);
+ nvkm_object_ref(engine, (struct nvkm_object **)&object->engine);
+ object->oclass = oclass;
+ object->oclass->handle |= pclass;
+ atomic_set(&object->refcount, 1);
+ atomic_set(&object->usecount, 0);
+
+#ifdef NVKM_OBJECT_MAGIC
+ object->_magic = NVKM_OBJECT_MAGIC;
+ spin_lock(&_objlist_lock);
+ list_add(&object->list, &_objlist);
+ spin_unlock(&_objlist_lock);
+#endif
+ return 0;
+}
+
+int
+_nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ if (size != 0)
+ return -ENOSYS;
+ return nvkm_object_create(parent, engine, oclass, 0, pobject);
+}
+
+void
+nvkm_object_destroy(struct nvkm_object *object)
+{
+#ifdef NVKM_OBJECT_MAGIC
+ spin_lock(&_objlist_lock);
+ list_del(&object->list);
+ spin_unlock(&_objlist_lock);
+#endif
+ nvkm_object_ref(NULL, (struct nvkm_object **)&object->engine);
+ nvkm_object_ref(NULL, &object->parent);
+ kfree(object);
+}
+
+int
+nvkm_object_init(struct nvkm_object *object)
+{
+ return 0;
+}
+
+int
+nvkm_object_fini(struct nvkm_object *object, bool suspend)
+{
+ return 0;
+}
+
+struct nvkm_ofuncs
+nvkm_object_ofuncs = {
+ .ctor = _nvkm_object_ctor,
+ .dtor = nvkm_object_destroy,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+};
+
+int
+nvkm_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_ofuncs *ofuncs = oclass->ofuncs;
+ struct nvkm_object *object = NULL;
+ int ret;
+
+ ret = ofuncs->ctor(parent, engine, oclass, data, size, &object);
+ *pobject = object;
+ if (ret < 0) {
+ if (ret != -ENODEV) {
+ nv_error(parent, "failed to create 0x%08x, %d\n",
+ oclass->handle, ret);
+ }
+
+ if (object) {
+ ofuncs->dtor(object);
+ *pobject = NULL;
+ }
+
+ return ret;
+ }
+
+ if (ret == 0) {
+ nv_trace(object, "created\n");
+ atomic_set(&object->refcount, 1);
+ }
+
+ return 0;
+}
+
+static void
+nvkm_object_dtor(struct nvkm_object *object)
+{
+ nv_trace(object, "destroying\n");
+ nv_ofuncs(object)->dtor(object);
+}
+
+void
+nvkm_object_ref(struct nvkm_object *obj, struct nvkm_object **ref)
+{
+ if (obj) {
+ atomic_inc(&obj->refcount);
+ nv_trace(obj, "inc() == %d\n", atomic_read(&obj->refcount));
+ }
+
+ if (*ref) {
+ int dead = atomic_dec_and_test(&(*ref)->refcount);
+ nv_trace(*ref, "dec() == %d\n", atomic_read(&(*ref)->refcount));
+ if (dead)
+ nvkm_object_dtor(*ref);
+ }
+
+ *ref = obj;
+}
+
+int
+nvkm_object_inc(struct nvkm_object *object)
+{
+ int ref = atomic_add_return(1, &object->usecount);
+ int ret;
+
+ nv_trace(object, "use(+1) == %d\n", atomic_read(&object->usecount));
+ if (ref != 1)
+ return 0;
+
+ nv_trace(object, "initialising...\n");
+ if (object->parent) {
+ ret = nvkm_object_inc(object->parent);
+ if (ret) {
+ nv_error(object, "parent failed, %d\n", ret);
+ goto fail_parent;
+ }
+ }
+
+ if (object->engine) {
+ mutex_lock(&nv_subdev(object->engine)->mutex);
+ ret = nvkm_object_inc(&object->engine->subdev.object);
+ mutex_unlock(&nv_subdev(object->engine)->mutex);
+ if (ret) {
+ nv_error(object, "engine failed, %d\n", ret);
+ goto fail_engine;
+ }
+ }
+
+ ret = nv_ofuncs(object)->init(object);
+ atomic_set(&object->usecount, 1);
+ if (ret) {
+ nv_error(object, "init failed, %d\n", ret);
+ goto fail_self;
+ }
+
+ nv_trace(object, "initialised\n");
+ return 0;
+
+fail_self:
+ if (object->engine) {
+ mutex_lock(&nv_subdev(object->engine)->mutex);
+ nvkm_object_dec(&object->engine->subdev.object, false);
+ mutex_unlock(&nv_subdev(object->engine)->mutex);
+ }
+fail_engine:
+ if (object->parent)
+ nvkm_object_dec(object->parent, false);
+fail_parent:
+ atomic_dec(&object->usecount);
+ return ret;
+}
+
+static int
+nvkm_object_decf(struct nvkm_object *object)
+{
+ int ret;
+
+ nv_trace(object, "stopping...\n");
+
+ ret = nv_ofuncs(object)->fini(object, false);
+ atomic_set(&object->usecount, 0);
+ if (ret)
+ nv_warn(object, "failed fini, %d\n", ret);
+
+ if (object->engine) {
+ mutex_lock(&nv_subdev(object->engine)->mutex);
+ nvkm_object_dec(&object->engine->subdev.object, false);
+ mutex_unlock(&nv_subdev(object->engine)->mutex);
+ }
+
+ if (object->parent)
+ nvkm_object_dec(object->parent, false);
+
+ nv_trace(object, "stopped\n");
+ return 0;
+}
+
+static int
+nvkm_object_decs(struct nvkm_object *object)
+{
+ int ret, rret;
+
+ nv_trace(object, "suspending...\n");
+
+ ret = nv_ofuncs(object)->fini(object, true);
+ atomic_set(&object->usecount, 0);
+ if (ret) {
+ nv_error(object, "failed suspend, %d\n", ret);
+ return ret;
+ }
+
+ if (object->engine) {
+ mutex_lock(&nv_subdev(object->engine)->mutex);
+ ret = nvkm_object_dec(&object->engine->subdev.object, true);
+ mutex_unlock(&nv_subdev(object->engine)->mutex);
+ if (ret) {
+ nv_warn(object, "engine failed suspend, %d\n", ret);
+ goto fail_engine;
+ }
+ }
+
+ if (object->parent) {
+ ret = nvkm_object_dec(object->parent, true);
+ if (ret) {
+ nv_warn(object, "parent failed suspend, %d\n", ret);
+ goto fail_parent;
+ }
+ }
+
+ nv_trace(object, "suspended\n");
+ return 0;
+
+fail_parent:
+ if (object->engine) {
+ mutex_lock(&nv_subdev(object->engine)->mutex);
+ rret = nvkm_object_inc(&object->engine->subdev.object);
+ mutex_unlock(&nv_subdev(object->engine)->mutex);
+ if (rret)
+ nv_fatal(object, "engine failed to reinit, %d\n", rret);
+ }
+
+fail_engine:
+ rret = nv_ofuncs(object)->init(object);
+ if (rret)
+ nv_fatal(object, "failed to reinit, %d\n", rret);
+
+ return ret;
+}
+
+int
+nvkm_object_dec(struct nvkm_object *object, bool suspend)
+{
+ int ref = atomic_add_return(-1, &object->usecount);
+ int ret;
+
+ nv_trace(object, "use(-1) == %d\n", atomic_read(&object->usecount));
+
+ if (ref == 0) {
+ if (suspend)
+ ret = nvkm_object_decs(object);
+ else
+ ret = nvkm_object_decf(object);
+
+ if (ret) {
+ atomic_inc(&object->usecount);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+void
+nvkm_object_debug(void)
+{
+#ifdef NVKM_OBJECT_MAGIC
+ struct nvkm_object *object;
+ if (!list_empty(&_objlist)) {
+ nv_fatal(NULL, "*******************************************\n");
+ nv_fatal(NULL, "* AIIIII! object(s) still exist!!!\n");
+ nv_fatal(NULL, "*******************************************\n");
+ list_for_each_entry(object, &_objlist, list) {
+ nv_fatal(object, "%p/%p/%d/%d\n",
+ object->parent, object->engine,
+ atomic_read(&object->refcount),
+ atomic_read(&object->usecount));
+ }
+ }
+#endif
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/option.c b/drivers/gpu/drm/nouveau/nvkm/core/option.c
new file mode 100644
index 000000000000..19d153f8c8fd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/option.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/option.h>
+#include <core/debug.h>
+
+const char *
+nvkm_stropt(const char *optstr, const char *opt, int *arglen)
+{
+ while (optstr && *optstr != '\0') {
+ int len = strcspn(optstr, ",=");
+ switch (optstr[len]) {
+ case '=':
+ if (!strncasecmpz(optstr, opt, len)) {
+ optstr += len + 1;
+ *arglen = strcspn(optstr, ",=");
+ return *arglen ? optstr : NULL;
+ }
+ optstr++;
+ break;
+ case ',':
+ optstr++;
+ break;
+ default:
+ break;
+ }
+ optstr += len;
+ }
+
+ return NULL;
+}
+
+bool
+nvkm_boolopt(const char *optstr, const char *opt, bool value)
+{
+ int arglen;
+
+ optstr = nvkm_stropt(optstr, opt, &arglen);
+ if (optstr) {
+ if (!strncasecmpz(optstr, "0", arglen) ||
+ !strncasecmpz(optstr, "no", arglen) ||
+ !strncasecmpz(optstr, "off", arglen) ||
+ !strncasecmpz(optstr, "false", arglen))
+ value = false;
+ else
+ if (!strncasecmpz(optstr, "1", arglen) ||
+ !strncasecmpz(optstr, "yes", arglen) ||
+ !strncasecmpz(optstr, "on", arglen) ||
+ !strncasecmpz(optstr, "true", arglen))
+ value = true;
+ }
+
+ return value;
+}
+
+int
+nvkm_dbgopt(const char *optstr, const char *sub)
+{
+ int mode = 1, level = CONFIG_NOUVEAU_DEBUG_DEFAULT;
+
+ while (optstr) {
+ int len = strcspn(optstr, ",=");
+ switch (optstr[len]) {
+ case '=':
+ if (strncasecmpz(optstr, sub, len))
+ mode = 0;
+ optstr++;
+ break;
+ default:
+ if (mode) {
+ if (!strncasecmpz(optstr, "fatal", len))
+ level = NV_DBG_FATAL;
+ else if (!strncasecmpz(optstr, "error", len))
+ level = NV_DBG_ERROR;
+ else if (!strncasecmpz(optstr, "warn", len))
+ level = NV_DBG_WARN;
+ else if (!strncasecmpz(optstr, "info", len))
+ level = NV_DBG_INFO_NORMAL;
+ else if (!strncasecmpz(optstr, "debug", len))
+ level = NV_DBG_DEBUG;
+ else if (!strncasecmpz(optstr, "trace", len))
+ level = NV_DBG_TRACE;
+ else if (!strncasecmpz(optstr, "paranoia", len))
+ level = NV_DBG_PARANOIA;
+ else if (!strncasecmpz(optstr, "spam", len))
+ level = NV_DBG_SPAM;
+ }
+
+ if (optstr[len] != '\0') {
+ optstr++;
+ mode = 1;
+ break;
+ }
+
+ return level;
+ }
+ optstr += len;
+ }
+
+ return level;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/parent.c b/drivers/gpu/drm/nouveau/nvkm/core/parent.c
new file mode 100644
index 000000000000..dd56cd1eeb38
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/parent.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/parent.h>
+#include <core/client.h>
+#include <core/engine.h>
+
+int
+nvkm_parent_sclass(struct nvkm_object *parent, u16 handle,
+ struct nvkm_object **pengine,
+ struct nvkm_oclass **poclass)
+{
+ struct nvkm_sclass *sclass;
+ struct nvkm_engine *engine;
+ struct nvkm_oclass *oclass;
+ u64 mask;
+
+ sclass = nv_parent(parent)->sclass;
+ while (sclass) {
+ if ((sclass->oclass->handle & 0xffff) == handle) {
+ *pengine = &parent->engine->subdev.object;
+ *poclass = sclass->oclass;
+ return 0;
+ }
+
+ sclass = sclass->sclass;
+ }
+
+ mask = nv_parent(parent)->engine;
+ while (mask) {
+ int i = __ffs64(mask);
+
+ if (nv_iclass(parent, NV_CLIENT_CLASS))
+ engine = nv_engine(nv_client(parent)->device);
+ else
+ engine = nvkm_engine(parent, i);
+
+ if (engine) {
+ oclass = engine->sclass;
+ while (oclass->ofuncs) {
+ if ((oclass->handle & 0xffff) == handle) {
+ *pengine = nv_object(engine);
+ *poclass = oclass;
+ return 0;
+ }
+ oclass++;
+ }
+ }
+
+ mask &= ~(1ULL << i);
+ }
+
+ return -EINVAL;
+}
+
+int
+nvkm_parent_lclass(struct nvkm_object *parent, u32 *lclass, int size)
+{
+ struct nvkm_sclass *sclass;
+ struct nvkm_engine *engine;
+ struct nvkm_oclass *oclass;
+ int nr = -1, i;
+ u64 mask;
+
+ sclass = nv_parent(parent)->sclass;
+ while (sclass) {
+ if (++nr < size)
+ lclass[nr] = sclass->oclass->handle & 0xffff;
+ sclass = sclass->sclass;
+ }
+
+ mask = nv_parent(parent)->engine;
+ while (i = __ffs64(mask), mask) {
+ engine = nvkm_engine(parent, i);
+ if (engine && (oclass = engine->sclass)) {
+ while (oclass->ofuncs) {
+ if (++nr < size)
+ lclass[nr] = oclass->handle & 0xffff;
+ oclass++;
+ }
+ }
+
+ mask &= ~(1ULL << i);
+ }
+
+ return nr + 1;
+}
+
+int
+nvkm_parent_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 pclass,
+ struct nvkm_oclass *sclass, u64 engcls,
+ int size, void **pobject)
+{
+ struct nvkm_parent *object;
+ struct nvkm_sclass *nclass;
+ int ret;
+
+ ret = nvkm_object_create_(parent, engine, oclass, pclass |
+ NV_PARENT_CLASS, size, pobject);
+ object = *pobject;
+ if (ret)
+ return ret;
+
+ while (sclass && sclass->ofuncs) {
+ nclass = kzalloc(sizeof(*nclass), GFP_KERNEL);
+ if (!nclass)
+ return -ENOMEM;
+
+ nclass->sclass = object->sclass;
+ object->sclass = nclass;
+ nclass->engine = engine ? nv_engine(engine) : NULL;
+ nclass->oclass = sclass;
+ sclass++;
+ }
+
+ object->engine = engcls;
+ return 0;
+}
+
+void
+nvkm_parent_destroy(struct nvkm_parent *parent)
+{
+ struct nvkm_sclass *sclass;
+
+ while ((sclass = parent->sclass)) {
+ parent->sclass = sclass->sclass;
+ kfree(sclass);
+ }
+
+ nvkm_object_destroy(&parent->object);
+}
+
+
+void
+_nvkm_parent_dtor(struct nvkm_object *object)
+{
+ nvkm_parent_destroy(nv_parent(object));
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/printk.c b/drivers/gpu/drm/nouveau/nvkm/core/printk.c
new file mode 100644
index 000000000000..4a220eb91660
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/printk.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/printk.h>
+#include <core/client.h>
+#include <core/device.h>
+
+int nv_info_debug_level = NV_DBG_INFO_NORMAL;
+
+void
+nv_printk_(struct nvkm_object *object, int level, const char *fmt, ...)
+{
+ static const char name[] = { '!', 'E', 'W', ' ', 'D', 'T', 'P', 'S' };
+ const char *pfx;
+ char mfmt[256];
+ va_list args;
+
+ switch (level) {
+ case NV_DBG_FATAL:
+ pfx = KERN_CRIT;
+ break;
+ case NV_DBG_ERROR:
+ pfx = KERN_ERR;
+ break;
+ case NV_DBG_WARN:
+ pfx = KERN_WARNING;
+ break;
+ case NV_DBG_INFO_NORMAL:
+ pfx = KERN_INFO;
+ break;
+ case NV_DBG_DEBUG:
+ case NV_DBG_PARANOIA:
+ case NV_DBG_TRACE:
+ case NV_DBG_SPAM:
+ default:
+ pfx = KERN_DEBUG;
+ break;
+ }
+
+ if (object && !nv_iclass(object, NV_CLIENT_CLASS)) {
+ struct nvkm_object *device;
+ struct nvkm_object *subdev;
+ char obuf[64], *ofmt = "";
+
+ if (object->engine == NULL) {
+ subdev = object;
+ while (subdev && !nv_iclass(subdev, NV_SUBDEV_CLASS))
+ subdev = subdev->parent;
+ } else {
+ subdev = &object->engine->subdev.object;
+ }
+
+ device = subdev;
+ if (device->parent)
+ device = device->parent;
+
+ if (object != subdev) {
+ snprintf(obuf, sizeof(obuf), "[0x%08x]",
+ nv_hclass(object));
+ ofmt = obuf;
+ }
+
+ if (level > nv_subdev(subdev)->debug)
+ return;
+
+ snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s][%s]%s %s", pfx,
+ name[level], nv_subdev(subdev)->name,
+ nv_device(device)->name, ofmt, fmt);
+ } else
+ if (object && nv_iclass(object, NV_CLIENT_CLASS)) {
+ if (level > nv_client(object)->debug)
+ return;
+
+ snprintf(mfmt, sizeof(mfmt), "%snouveau %c[%8s] %s", pfx,
+ name[level], nv_client(object)->name, fmt);
+ } else {
+ snprintf(mfmt, sizeof(mfmt), "%snouveau: %s", pfx, fmt);
+ }
+
+ va_start(args, fmt);
+ vprintk(mfmt, args);
+ va_end(args);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/ramht.c b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c
new file mode 100644
index 000000000000..ebd4d15479bd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/ramht.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <core/ramht.h>
+#include <core/engine.h>
+
+#include <subdev/bar.h>
+
+static u32
+nvkm_ramht_hash(struct nvkm_ramht *ramht, int chid, u32 handle)
+{
+ u32 hash = 0;
+
+ while (handle) {
+ hash ^= (handle & ((1 << ramht->bits) - 1));
+ handle >>= ramht->bits;
+ }
+
+ hash ^= chid << (ramht->bits - 4);
+ hash = hash << 3;
+ return hash;
+}
+
+int
+nvkm_ramht_insert(struct nvkm_ramht *ramht, int chid, u32 handle, u32 context)
+{
+ struct nvkm_bar *bar = nvkm_bar(ramht);
+ u32 co, ho;
+
+ co = ho = nvkm_ramht_hash(ramht, chid, handle);
+ do {
+ if (!nv_ro32(ramht, co + 4)) {
+ nv_wo32(ramht, co + 0, handle);
+ nv_wo32(ramht, co + 4, context);
+ if (bar)
+ bar->flush(bar);
+ return co;
+ }
+
+ co += 8;
+ if (co >= nv_gpuobj(ramht)->size)
+ co = 0;
+ } while (co != ho);
+
+ return -ENOMEM;
+}
+
+void
+nvkm_ramht_remove(struct nvkm_ramht *ramht, int cookie)
+{
+ struct nvkm_bar *bar = nvkm_bar(ramht);
+ nv_wo32(ramht, cookie + 0, 0x00000000);
+ nv_wo32(ramht, cookie + 4, 0x00000000);
+ if (bar)
+ bar->flush(bar);
+}
+
+static struct nvkm_oclass
+nvkm_ramht_oclass = {
+ .handle = 0x0000abcd,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = NULL,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+ },
+};
+
+int
+nvkm_ramht_new(struct nvkm_object *parent, struct nvkm_object *pargpu,
+ u32 size, u32 align, struct nvkm_ramht **pramht)
+{
+ struct nvkm_ramht *ramht;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, parent->engine ?
+ &parent->engine->subdev.object : parent, /* <nv50 ramht */
+ &nvkm_ramht_oclass, 0, pargpu, size,
+ align, NVOBJ_FLAG_ZERO_ALLOC, &ramht);
+ *pramht = ramht;
+ if (ret)
+ return ret;
+
+ ramht->bits = order_base_2(nv_gpuobj(ramht)->size >> 3);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/core/subdev.c b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
new file mode 100644
index 000000000000..c5fb3a793174
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/core/subdev.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <core/subdev.h>
+#include <core/device.h>
+#include <core/option.h>
+
+struct nvkm_subdev *
+nvkm_subdev(void *obj, int idx)
+{
+ struct nvkm_object *object = nv_object(obj);
+ while (object && !nv_iclass(object, NV_SUBDEV_CLASS))
+ object = object->parent;
+ if (object == NULL || nv_subidx(nv_subdev(object)) != idx)
+ object = nv_device(obj)->subdev[idx];
+ return object ? nv_subdev(object) : NULL;
+}
+
+void
+nvkm_subdev_reset(struct nvkm_object *subdev)
+{
+ nv_trace(subdev, "resetting...\n");
+ nv_ofuncs(subdev)->fini(subdev, false);
+ nv_debug(subdev, "reset\n");
+}
+
+int
+nvkm_subdev_init(struct nvkm_subdev *subdev)
+{
+ int ret = nvkm_object_init(&subdev->object);
+ if (ret)
+ return ret;
+
+ nvkm_subdev_reset(&subdev->object);
+ return 0;
+}
+
+int
+_nvkm_subdev_init(struct nvkm_object *object)
+{
+ return nvkm_subdev_init(nv_subdev(object));
+}
+
+int
+nvkm_subdev_fini(struct nvkm_subdev *subdev, bool suspend)
+{
+ if (subdev->unit) {
+ nv_mask(subdev, 0x000200, subdev->unit, 0x00000000);
+ nv_mask(subdev, 0x000200, subdev->unit, subdev->unit);
+ }
+
+ return nvkm_object_fini(&subdev->object, suspend);
+}
+
+int
+_nvkm_subdev_fini(struct nvkm_object *object, bool suspend)
+{
+ return nvkm_subdev_fini(nv_subdev(object), suspend);
+}
+
+void
+nvkm_subdev_destroy(struct nvkm_subdev *subdev)
+{
+ int subidx = nv_hclass(subdev) & 0xff;
+ nv_device(subdev)->subdev[subidx] = NULL;
+ nvkm_object_destroy(&subdev->object);
+}
+
+void
+_nvkm_subdev_dtor(struct nvkm_object *object)
+{
+ nvkm_subdev_destroy(nv_subdev(object));
+}
+
+int
+nvkm_subdev_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 pclass,
+ const char *subname, const char *sysname,
+ int size, void **pobject)
+{
+ struct nvkm_subdev *subdev;
+ int ret;
+
+ ret = nvkm_object_create_(parent, engine, oclass, pclass |
+ NV_SUBDEV_CLASS, size, pobject);
+ subdev = *pobject;
+ if (ret)
+ return ret;
+
+ __mutex_init(&subdev->mutex, subname, &oclass->lock_class_key);
+ subdev->name = subname;
+
+ if (parent) {
+ struct nvkm_device *device = nv_device(parent);
+ subdev->debug = nvkm_dbgopt(device->dbgopt, subname);
+ subdev->mmio = nv_subdev(device)->mmio;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
new file mode 100644
index 000000000000..6bd3d756f32c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/Kbuild
@@ -0,0 +1,19 @@
+nvkm-y += nvkm/engine/falcon.o
+nvkm-y += nvkm/engine/xtensa.o
+
+include $(src)/nvkm/engine/bsp/Kbuild
+include $(src)/nvkm/engine/ce/Kbuild
+include $(src)/nvkm/engine/cipher/Kbuild
+include $(src)/nvkm/engine/device/Kbuild
+include $(src)/nvkm/engine/disp/Kbuild
+include $(src)/nvkm/engine/dmaobj/Kbuild
+include $(src)/nvkm/engine/fifo/Kbuild
+include $(src)/nvkm/engine/gr/Kbuild
+include $(src)/nvkm/engine/mpeg/Kbuild
+include $(src)/nvkm/engine/mspdec/Kbuild
+include $(src)/nvkm/engine/msppp/Kbuild
+include $(src)/nvkm/engine/msvld/Kbuild
+include $(src)/nvkm/engine/pm/Kbuild
+include $(src)/nvkm/engine/sec/Kbuild
+include $(src)/nvkm/engine/sw/Kbuild
+include $(src)/nvkm/engine/vp/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild
new file mode 100644
index 000000000000..5ac9f9e1a283
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/bsp/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c
new file mode 100644
index 000000000000..a0b1fd80fa93
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/bsp/g84.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs, Ilia Mirkin
+ */
+#include <engine/bsp.h>
+#include <engine/xtensa.h>
+
+#include <core/engctx.h>
+
+/*******************************************************************************
+ * BSP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_bsp_sclass[] = {
+ { 0x74b0, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * BSP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_bsp_cclass = {
+ .handle = NV_ENGCTX(BSP, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_xtensa_engctx_ctor,
+ .dtor = _nvkm_engctx_dtor,
+ .init = _nvkm_engctx_init,
+ .fini = _nvkm_engctx_fini,
+ .rd32 = _nvkm_engctx_rd32,
+ .wr32 = _nvkm_engctx_wr32,
+ },
+};
+
+/*******************************************************************************
+ * BSP engine/subdev functions
+ ******************************************************************************/
+
+static int
+g84_bsp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_xtensa *priv;
+ int ret;
+
+ ret = nvkm_xtensa_create(parent, engine, oclass, 0x103000, true,
+ "PBSP", "bsp", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x04008000;
+ nv_engine(priv)->cclass = &g84_bsp_cclass;
+ nv_engine(priv)->sclass = g84_bsp_sclass;
+ priv->fifo_val = 0x1111;
+ priv->unkd28 = 0x90044;
+ return 0;
+}
+
+struct nvkm_oclass
+g84_bsp_oclass = {
+ .handle = NV_ENGINE(BSP, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_bsp_ctor,
+ .dtor = _nvkm_xtensa_dtor,
+ .init = _nvkm_xtensa_init,
+ .fini = _nvkm_xtensa_fini,
+ .rd32 = _nvkm_xtensa_rd32,
+ .wr32 = _nvkm_xtensa_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
new file mode 100644
index 000000000000..858797453e0b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/engine/ce/gt215.o
+nvkm-y += nvkm/engine/ce/gf100.o
+nvkm-y += nvkm/engine/ce/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc
new file mode 100644
index 000000000000..a558dfa4d76a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/com.fuc
@@ -0,0 +1,864 @@
+/* fuc microcode for copy engine on gt215- chipsets
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef GT215
+.section #gt215_pce_data
+#else
+.section #gf100_pce_data
+#endif
+
+ctx_object: .b32 0
+#ifdef GT215
+ctx_dma:
+ctx_dma_query: .b32 0
+ctx_dma_src: .b32 0
+ctx_dma_dst: .b32 0
+#endif
+.equ #ctx_dma_count 3
+ctx_query_address_high: .b32 0
+ctx_query_address_low: .b32 0
+ctx_query_counter: .b32 0
+ctx_src_address_high: .b32 0
+ctx_src_address_low: .b32 0
+ctx_src_pitch: .b32 0
+ctx_src_tile_mode: .b32 0
+ctx_src_xsize: .b32 0
+ctx_src_ysize: .b32 0
+ctx_src_zsize: .b32 0
+ctx_src_zoff: .b32 0
+ctx_src_xoff: .b32 0
+ctx_src_yoff: .b32 0
+ctx_src_cpp: .b32 0
+ctx_dst_address_high: .b32 0
+ctx_dst_address_low: .b32 0
+ctx_dst_pitch: .b32 0
+ctx_dst_tile_mode: .b32 0
+ctx_dst_xsize: .b32 0
+ctx_dst_ysize: .b32 0
+ctx_dst_zsize: .b32 0
+ctx_dst_zoff: .b32 0
+ctx_dst_xoff: .b32 0
+ctx_dst_yoff: .b32 0
+ctx_dst_cpp: .b32 0
+ctx_format: .b32 0
+ctx_swz_const0: .b32 0
+ctx_swz_const1: .b32 0
+ctx_xcnt: .b32 0
+ctx_ycnt: .b32 0
+.align 256
+
+dispatch_table:
+// mthd 0x0000, NAME
+.b16 0x000 1
+.b32 #ctx_object ~0xffffffff
+// mthd 0x0100, NOP
+.b16 0x040 1
+.b32 0x00010000 + #cmd_nop ~0xffffffff
+// mthd 0x0140, PM_TRIGGER
+.b16 0x050 1
+.b32 0x00010000 + #cmd_pm_trigger ~0xffffffff
+#ifdef GT215
+// mthd 0x0180-0x018c, DMA_
+.b16 0x060 #ctx_dma_count
+dispatch_dma:
+.b32 0x00010000 + #cmd_dma ~0xffffffff
+.b32 0x00010000 + #cmd_dma ~0xffffffff
+.b32 0x00010000 + #cmd_dma ~0xffffffff
+#endif
+// mthd 0x0200-0x0218, SRC_TILE
+.b16 0x80 7
+.b32 #ctx_src_tile_mode ~0x00000fff
+.b32 #ctx_src_xsize ~0x0007ffff
+.b32 #ctx_src_ysize ~0x00001fff
+.b32 #ctx_src_zsize ~0x000007ff
+.b32 #ctx_src_zoff ~0x00000fff
+.b32 #ctx_src_xoff ~0x0007ffff
+.b32 #ctx_src_yoff ~0x00001fff
+// mthd 0x0220-0x0238, DST_TILE
+.b16 0x88 7
+.b32 #ctx_dst_tile_mode ~0x00000fff
+.b32 #ctx_dst_xsize ~0x0007ffff
+.b32 #ctx_dst_ysize ~0x00001fff
+.b32 #ctx_dst_zsize ~0x000007ff
+.b32 #ctx_dst_zoff ~0x00000fff
+.b32 #ctx_dst_xoff ~0x0007ffff
+.b32 #ctx_dst_yoff ~0x00001fff
+// mthd 0x0300-0x0304, EXEC, WRCACHE_FLUSH
+.b16 0xc0 2
+.b32 0x00010000 + #cmd_exec ~0xffffffff
+.b32 0x00010000 + #cmd_wrcache_flush ~0xffffffff
+// mthd 0x030c-0x0340, various stuff
+.b16 0xc3 14
+.b32 #ctx_src_address_high ~0x000000ff
+.b32 #ctx_src_address_low ~0xffffffff
+.b32 #ctx_dst_address_high ~0x000000ff
+.b32 #ctx_dst_address_low ~0xffffffff
+.b32 #ctx_src_pitch ~0x0007ffff
+.b32 #ctx_dst_pitch ~0x0007ffff
+.b32 #ctx_xcnt ~0x0000ffff
+.b32 #ctx_ycnt ~0x00001fff
+.b32 #ctx_format ~0x0333ffff
+.b32 #ctx_swz_const0 ~0xffffffff
+.b32 #ctx_swz_const1 ~0xffffffff
+.b32 #ctx_query_address_high ~0x000000ff
+.b32 #ctx_query_address_low ~0xffffffff
+.b32 #ctx_query_counter ~0xffffffff
+.b16 0x800 0
+
+#ifdef GT215
+.section #gt215_pce_code
+#else
+.section #gf100_pce_code
+#endif
+
+main:
+ clear b32 $r0
+ mov $sp $r0
+
+ // setup i0 handler and route fifo and ctxswitch to it
+ mov $r1 #ih
+ mov $iv0 $r1
+ mov $r1 0x400
+ movw $r2 0xfff3
+ sethi $r2 0
+ iowr I[$r1 + 0x300] $r2
+
+ // enable interrupts
+ or $r2 0xc
+ iowr I[$r1] $r2
+ bset $flags ie0
+
+ // enable fifo access and context switching
+ mov $r1 0x1200
+ mov $r2 3
+ iowr I[$r1] $r2
+
+ // sleep forever, waking for interrupts
+ bset $flags $p0
+ spin:
+ sleep $p0
+ bra #spin
+
+// i0 handler
+ih:
+ iord $r1 I[$r0 + 0x200]
+
+ and $r2 $r1 0x00000008
+ bra e #ih_no_chsw
+ call #chsw
+ ih_no_chsw:
+ and $r2 $r1 0x00000004
+ bra e #ih_no_cmd
+ call #dispatch
+
+ ih_no_cmd:
+ and $r1 $r1 0x0000000c
+ iowr I[$r0 + 0x100] $r1
+ iret
+
+// $p1 direction (0 = unload, 1 = load)
+// $r3 channel
+swctx:
+ mov $r4 0x7700
+ mov $xtargets $r4
+#ifdef GT215
+ // target 7 hardcoded to ctx dma object
+ mov $xdbase $r0
+#else
+ // read SCRATCH3 to decide if we are PCOPY0 or PCOPY1
+ mov $r4 0x2100
+ iord $r4 I[$r4 + 0]
+ and $r4 1
+ shl b32 $r4 4
+ add b32 $r4 0x30
+
+ // channel is in vram
+ mov $r15 0x61c
+ shl b32 $r15 6
+ mov $r5 0x114
+ iowrs I[$r15] $r5
+
+ // read 16-byte PCOPYn info, containing context pointer, from channel
+ shl b32 $r5 $r3 4
+ add b32 $r5 2
+ mov $xdbase $r5
+ mov $r5 $sp
+ // get a chunk of stack space, aligned to 256 byte boundary
+ sub b32 $r5 0x100
+ mov $r6 0xff
+ not b32 $r6
+ and $r5 $r6
+ sethi $r5 0x00020000
+ xdld $r4 $r5
+ xdwait
+ sethi $r5 0
+
+ // set context pointer, from within channel VM
+ mov $r14 0
+ iowrs I[$r15] $r14
+ ld b32 $r4 D[$r5 + 0]
+ shr b32 $r4 8
+ ld b32 $r6 D[$r5 + 4]
+ shl b32 $r6 24
+ or $r4 $r6
+ mov $xdbase $r4
+#endif
+ // 256-byte context, at start of data segment
+ mov b32 $r4 $r0
+ sethi $r4 0x60000
+
+ // swap!
+ bra $p1 #swctx_load
+ xdst $r0 $r4
+ bra #swctx_done
+ swctx_load:
+ xdld $r0 $r4
+ swctx_done:
+ xdwait
+ ret
+
+chsw:
+ // read current channel
+ mov $r2 0x1400
+ iord $r3 I[$r2]
+
+ // if it's active, unload it and return
+ xbit $r15 $r3 0x1e
+ bra e #chsw_no_unload
+ bclr $flags $p1
+ call #swctx
+ bclr $r3 0x1e
+ iowr I[$r2] $r3
+ mov $r4 1
+ iowr I[$r2 + 0x200] $r4
+ ret
+
+ // read next channel
+ chsw_no_unload:
+ iord $r3 I[$r2 + 0x100]
+
+ // is there a channel waiting to be loaded?
+ xbit $r13 $r3 0x1e
+ bra e #chsw_finish_load
+ bset $flags $p1
+ call #swctx
+#ifdef GT215
+ // load dma objects back into TARGET regs
+ mov $r5 #ctx_dma
+ mov $r6 #ctx_dma_count
+ chsw_load_ctx_dma:
+ ld b32 $r7 D[$r5 + $r6 * 4]
+ add b32 $r8 $r6 0x180
+ shl b32 $r8 8
+ iowr I[$r8] $r7
+ sub b32 $r6 1
+ bra nc #chsw_load_ctx_dma
+#endif
+ chsw_finish_load:
+ mov $r3 2
+ iowr I[$r2 + 0x200] $r3
+ ret
+
+dispatch:
+ // read incoming fifo command
+ mov $r3 0x1900
+ iord $r2 I[$r3 + 0x100]
+ iord $r3 I[$r3 + 0x000]
+ and $r4 $r2 0x7ff
+ // $r2 will be used to store exception data
+ shl b32 $r2 0x10
+
+ // lookup method in the dispatch table, ILLEGAL_MTHD if not found
+ mov $r5 #dispatch_table
+ clear b32 $r6
+ clear b32 $r7
+ dispatch_loop:
+ ld b16 $r6 D[$r5 + 0]
+ ld b16 $r7 D[$r5 + 2]
+ add b32 $r5 4
+ cmpu b32 $r4 $r6
+ bra c #dispatch_illegal_mthd
+ add b32 $r7 $r6
+ cmpu b32 $r4 $r7
+ bra c #dispatch_valid_mthd
+ sub b32 $r7 $r6
+ shl b32 $r7 3
+ add b32 $r5 $r7
+ bra #dispatch_loop
+
+ // ensure no bits set in reserved fields, INVALID_BITFIELD
+ dispatch_valid_mthd:
+ sub b32 $r4 $r6
+ shl b32 $r4 3
+ add b32 $r4 $r5
+ ld b32 $r5 D[$r4 + 4]
+ and $r5 $r3
+ cmpu b32 $r5 0
+ bra ne #dispatch_invalid_bitfield
+
+ // depending on dispatch flags: execute method, or save data as state
+ ld b16 $r5 D[$r4 + 0]
+ ld b16 $r6 D[$r4 + 2]
+ cmpu b32 $r6 0
+ bra ne #dispatch_cmd
+ st b32 D[$r5] $r3
+ bra #dispatch_done
+ dispatch_cmd:
+ bclr $flags $p1
+ call $r5
+ bra $p1 #dispatch_error
+ bra #dispatch_done
+
+ dispatch_invalid_bitfield:
+ or $r2 2
+ dispatch_illegal_mthd:
+ or $r2 1
+
+ // store exception data in SCRATCH0/SCRATCH1, signal hostirq
+ dispatch_error:
+ mov $r4 0x1000
+ iowr I[$r4 + 0x000] $r2
+ iowr I[$r4 + 0x100] $r3
+ mov $r2 0x40
+ iowr I[$r0] $r2
+ hostirq_wait:
+ iord $r2 I[$r0 + 0x200]
+ and $r2 0x40
+ cmpu b32 $r2 0
+ bra ne #hostirq_wait
+
+ dispatch_done:
+ mov $r2 0x1d00
+ mov $r3 1
+ iowr I[$r2] $r3
+ ret
+
+// No-operation
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_nop:
+ ret
+
+// PM_TRIGGER
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_pm_trigger:
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x20000
+ iowr I[$r2] $r3
+ ret
+
+#ifdef GT215
+// SET_DMA_* method handler
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_dma:
+ sub b32 $r4 #dispatch_dma
+ shr b32 $r4 1
+ bset $r3 0x1e
+ st b32 D[$r4 + #ctx_dma] $r3
+ add b32 $r4 0x600
+ shl b32 $r4 6
+ iowr I[$r4] $r3
+ ret
+#endif
+
+// Calculates the hw swizzle mask and adjusts the surface's xcnt to match
+//
+cmd_exec_set_format:
+ // zero out a chunk of the stack to store the swizzle into
+ add $sp -0x10
+ st b32 D[$sp + 0x00] $r0
+ st b32 D[$sp + 0x04] $r0
+ st b32 D[$sp + 0x08] $r0
+ st b32 D[$sp + 0x0c] $r0
+
+ // extract cpp, src_ncomp and dst_ncomp from FORMAT
+ ld b32 $r4 D[$r0 + #ctx_format]
+ extr $r5 $r4 16:17
+ add b32 $r5 1
+ extr $r6 $r4 20:21
+ add b32 $r6 1
+ extr $r7 $r4 24:25
+ add b32 $r7 1
+
+ // convert FORMAT swizzle mask to hw swizzle mask
+ bclr $flags $p2
+ clear b32 $r8
+ clear b32 $r9
+ ncomp_loop:
+ and $r10 $r4 0xf
+ shr b32 $r4 4
+ clear b32 $r11
+ bpc_loop:
+ cmpu b8 $r10 4
+ bra nc #cmp_c0
+ mulu $r12 $r10 $r5
+ add b32 $r12 $r11
+ bset $flags $p2
+ bra #bpc_next
+ cmp_c0:
+ bra ne #cmp_c1
+ mov $r12 0x10
+ add b32 $r12 $r11
+ bra #bpc_next
+ cmp_c1:
+ cmpu b8 $r10 6
+ bra nc #cmp_zero
+ mov $r12 0x14
+ add b32 $r12 $r11
+ bra #bpc_next
+ cmp_zero:
+ mov $r12 0x80
+ bpc_next:
+ st b8 D[$sp + $r8] $r12
+ add b32 $r8 1
+ add b32 $r11 1
+ cmpu b32 $r11 $r5
+ bra c #bpc_loop
+ add b32 $r9 1
+ cmpu b32 $r9 $r7
+ bra c #ncomp_loop
+
+ // SRC_XCNT = (xcnt * src_cpp), or 0 if no src ref in swz (hw will hang)
+ mulu $r6 $r5
+ st b32 D[$r0 + #ctx_src_cpp] $r6
+ ld b32 $r8 D[$r0 + #ctx_xcnt]
+ mulu $r6 $r8
+ bra $p2 #dst_xcnt
+ clear b32 $r6
+
+ dst_xcnt:
+ mulu $r7 $r5
+ st b32 D[$r0 + #ctx_dst_cpp] $r7
+ mulu $r7 $r8
+
+ mov $r5 0x810
+ shl b32 $r5 6
+ iowr I[$r5 + 0x000] $r6
+ iowr I[$r5 + 0x100] $r7
+ add b32 $r5 0x800
+ ld b32 $r6 D[$r0 + #ctx_dst_cpp]
+ sub b32 $r6 1
+ shl b32 $r6 8
+ ld b32 $r7 D[$r0 + #ctx_src_cpp]
+ sub b32 $r7 1
+ or $r6 $r7
+ iowr I[$r5 + 0x000] $r6
+ add b32 $r5 0x100
+ ld b32 $r6 D[$sp + 0x00]
+ iowr I[$r5 + 0x000] $r6
+ ld b32 $r6 D[$sp + 0x04]
+ iowr I[$r5 + 0x100] $r6
+ ld b32 $r6 D[$sp + 0x08]
+ iowr I[$r5 + 0x200] $r6
+ ld b32 $r6 D[$sp + 0x0c]
+ iowr I[$r5 + 0x300] $r6
+ add b32 $r5 0x400
+ ld b32 $r6 D[$r0 + #ctx_swz_const0]
+ iowr I[$r5 + 0x000] $r6
+ ld b32 $r6 D[$r0 + #ctx_swz_const1]
+ iowr I[$r5 + 0x100] $r6
+ add $sp 0x10
+ ret
+
+// Setup to handle a tiled surface
+//
+// Calculates a number of parameters the hardware requires in order
+// to correctly handle tiling.
+//
+// Offset calculation is performed as follows (Tp/Th/Td from TILE_MODE):
+// nTx = round_up(w * cpp, 1 << Tp) >> Tp
+// nTy = round_up(h, 1 << Th) >> Th
+// Txo = (x * cpp) & ((1 << Tp) - 1)
+// Tx = (x * cpp) >> Tp
+// Tyo = y & ((1 << Th) - 1)
+// Ty = y >> Th
+// Tzo = z & ((1 << Td) - 1)
+// Tz = z >> Td
+//
+// off = (Tzo << Tp << Th) + (Tyo << Tp) + Txo
+// off += ((Tz * nTy * nTx)) + (Ty * nTx) + Tx) << Td << Th << Tp;
+//
+// Inputs:
+// $r4: hw command (0x104800)
+// $r5: ctx offset adjustment for src/dst selection
+// $p2: set if dst surface
+//
+cmd_exec_set_surface_tiled:
+ // translate TILE_MODE into Tp, Th, Td shift values
+ ld b32 $r7 D[$r5 + #ctx_src_tile_mode]
+ extr $r9 $r7 8:11
+ extr $r8 $r7 4:7
+#ifdef GT215
+ add b32 $r8 2
+#else
+ add b32 $r8 3
+#endif
+ extr $r7 $r7 0:3
+ cmp b32 $r7 0xe
+ bra ne #xtile64
+ mov $r7 4
+ bra #xtileok
+ xtile64:
+ xbit $r7 $flags $p2
+ add b32 $r7 17
+ bset $r4 $r7
+ mov $r7 6
+ xtileok:
+
+ // Op = (x * cpp) & ((1 << Tp) - 1)
+ // Tx = (x * cpp) >> Tp
+ ld b32 $r10 D[$r5 + #ctx_src_xoff]
+ ld b32 $r11 D[$r5 + #ctx_src_cpp]
+ mulu $r10 $r11
+ mov $r11 1
+ shl b32 $r11 $r7
+ sub b32 $r11 1
+ and $r12 $r10 $r11
+ shr b32 $r10 $r7
+
+ // Tyo = y & ((1 << Th) - 1)
+ // Ty = y >> Th
+ ld b32 $r13 D[$r5 + #ctx_src_yoff]
+ mov $r14 1
+ shl b32 $r14 $r8
+ sub b32 $r14 1
+ and $r11 $r13 $r14
+ shr b32 $r13 $r8
+
+ // YTILE = ((1 << Th) << 12) | ((1 << Th) - Tyo)
+ add b32 $r14 1
+ shl b32 $r15 $r14 12
+ sub b32 $r14 $r11
+ or $r15 $r14
+ xbit $r6 $flags $p2
+ add b32 $r6 0x208
+ shl b32 $r6 8
+ iowr I[$r6 + 0x000] $r15
+
+ // Op += Tyo << Tp
+ shl b32 $r11 $r7
+ add b32 $r12 $r11
+
+ // nTx = ((w * cpp) + ((1 << Tp) - 1) >> Tp)
+ ld b32 $r15 D[$r5 + #ctx_src_xsize]
+ ld b32 $r11 D[$r5 + #ctx_src_cpp]
+ mulu $r15 $r11
+ mov $r11 1
+ shl b32 $r11 $r7
+ sub b32 $r11 1
+ add b32 $r15 $r11
+ shr b32 $r15 $r7
+ push $r15
+
+ // nTy = (h + ((1 << Th) - 1)) >> Th
+ ld b32 $r15 D[$r5 + #ctx_src_ysize]
+ mov $r11 1
+ shl b32 $r11 $r8
+ sub b32 $r11 1
+ add b32 $r15 $r11
+ shr b32 $r15 $r8
+ push $r15
+
+ // Tys = Tp + Th
+ // CFG_YZ_TILE_SIZE = ((1 << Th) >> 2) << Td
+ add b32 $r7 $r8
+ sub b32 $r8 2
+ mov $r11 1
+ shl b32 $r11 $r8
+ shl b32 $r11 $r9
+
+ // Tzo = z & ((1 << Td) - 1)
+ // Tz = z >> Td
+ // Op += Tzo << Tys
+ // Ts = Tys + Td
+ ld b32 $r8 D[$r5 + #ctx_src_zoff]
+ mov $r14 1
+ shl b32 $r14 $r9
+ sub b32 $r14 1
+ and $r15 $r8 $r14
+ shl b32 $r15 $r7
+ add b32 $r12 $r15
+ add b32 $r7 $r9
+ shr b32 $r8 $r9
+
+ // Ot = ((Tz * nTy * nTx) + (Ty * nTx) + Tx) << Ts
+ pop $r15
+ pop $r9
+ mulu $r13 $r9
+ add b32 $r10 $r13
+ mulu $r8 $r9
+ mulu $r8 $r15
+ add b32 $r10 $r8
+ shl b32 $r10 $r7
+
+ // PITCH = (nTx - 1) << Ts
+ sub b32 $r9 1
+ shl b32 $r9 $r7
+ iowr I[$r6 + 0x200] $r9
+
+ // SRC_ADDRESS_LOW = (Ot + Op) & 0xffffffff
+ // CFG_ADDRESS_HIGH |= ((Ot + Op) >> 32) << 16
+ ld b32 $r7 D[$r5 + #ctx_src_address_low]
+ ld b32 $r8 D[$r5 + #ctx_src_address_high]
+ add b32 $r10 $r12
+ add b32 $r7 $r10
+ adc b32 $r8 0
+ shl b32 $r8 16
+ or $r8 $r11
+ sub b32 $r6 0x600
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ iowr I[$r6 + 0x000] $r8
+ ret
+
+// Setup to handle a linear surface
+//
+// Nothing to see here.. Sets ADDRESS and PITCH, pretty non-exciting
+//
+cmd_exec_set_surface_linear:
+ xbit $r6 $flags $p2
+ add b32 $r6 0x202
+ shl b32 $r6 8
+ ld b32 $r7 D[$r5 + #ctx_src_address_low]
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ ld b32 $r7 D[$r5 + #ctx_src_address_high]
+ shl b32 $r7 16
+ iowr I[$r6 + 0x000] $r7
+ add b32 $r6 0x400
+ ld b32 $r7 D[$r5 + #ctx_src_pitch]
+ iowr I[$r6 + 0x000] $r7
+ ret
+
+// wait for regs to be available for use
+cmd_exec_wait:
+ push $r0
+ push $r1
+ mov $r0 0x800
+ shl b32 $r0 6
+ loop:
+ iord $r1 I[$r0]
+ and $r1 1
+ bra ne #loop
+ pop $r1
+ pop $r0
+ ret
+
+cmd_exec_query:
+ // if QUERY_SHORT not set, write out { -, 0, TIME_LO, TIME_HI }
+ xbit $r4 $r3 13
+ bra ne #query_counter
+ call #cmd_exec_wait
+ mov $r4 0x80c
+ shl b32 $r4 6
+ ld b32 $r5 D[$r0 + #ctx_query_address_low]
+ add b32 $r5 4
+ iowr I[$r4 + 0x000] $r5
+ iowr I[$r4 + 0x100] $r0
+ mov $r5 0xc
+ iowr I[$r4 + 0x200] $r5
+ add b32 $r4 0x400
+ ld b32 $r5 D[$r0 + #ctx_query_address_high]
+ shl b32 $r5 16
+ iowr I[$r4 + 0x000] $r5
+ add b32 $r4 0x500
+ mov $r5 0x00000b00
+ sethi $r5 0x00010000
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00004040
+ shl b32 $r5 1
+ sethi $r5 0x80800000
+ iowr I[$r4 + 0x100] $r5
+ mov $r5 0x00001110
+ sethi $r5 0x13120000
+ iowr I[$r4 + 0x200] $r5
+ mov $r5 0x00001514
+ sethi $r5 0x17160000
+ iowr I[$r4 + 0x300] $r5
+ mov $r5 0x00002601
+ sethi $r5 0x00010000
+ mov $r4 0x800
+ shl b32 $r4 6
+ iowr I[$r4 + 0x000] $r5
+
+ // write COUNTER
+ query_counter:
+ call #cmd_exec_wait
+ mov $r4 0x80c
+ shl b32 $r4 6
+ ld b32 $r5 D[$r0 + #ctx_query_address_low]
+ iowr I[$r4 + 0x000] $r5
+ iowr I[$r4 + 0x100] $r0
+ mov $r5 0x4
+ iowr I[$r4 + 0x200] $r5
+ add b32 $r4 0x400
+ ld b32 $r5 D[$r0 + #ctx_query_address_high]
+ shl b32 $r5 16
+ iowr I[$r4 + 0x000] $r5
+ add b32 $r4 0x500
+ mov $r5 0x00000300
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00001110
+ sethi $r5 0x13120000
+ iowr I[$r4 + 0x100] $r5
+ ld b32 $r5 D[$r0 + #ctx_query_counter]
+ add b32 $r4 0x500
+ iowr I[$r4 + 0x000] $r5
+ mov $r5 0x00002601
+ sethi $r5 0x00010000
+ mov $r4 0x800
+ shl b32 $r4 6
+ iowr I[$r4 + 0x000] $r5
+ ret
+
+// Execute a copy operation
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// 000002000 QUERY_SHORT
+// 000001000 QUERY
+// 000000100 DST_LINEAR
+// 000000010 SRC_LINEAR
+// 000000001 FORMAT
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_exec:
+ call #cmd_exec_wait
+
+ // if format requested, call function to calculate it, otherwise
+ // fill in cpp/xcnt for both surfaces as if (cpp == 1)
+ xbit $r15 $r3 0
+ bra e #cmd_exec_no_format
+ call #cmd_exec_set_format
+ mov $r4 0x200
+ bra #cmd_exec_init_src_surface
+ cmd_exec_no_format:
+ mov $r6 0x810
+ shl b32 $r6 6
+ mov $r7 1
+ st b32 D[$r0 + #ctx_src_cpp] $r7
+ st b32 D[$r0 + #ctx_dst_cpp] $r7
+ ld b32 $r7 D[$r0 + #ctx_xcnt]
+ iowr I[$r6 + 0x000] $r7
+ iowr I[$r6 + 0x100] $r7
+ clear b32 $r4
+
+ cmd_exec_init_src_surface:
+ bclr $flags $p2
+ clear b32 $r5
+ xbit $r15 $r3 4
+ bra e #src_tiled
+ call #cmd_exec_set_surface_linear
+ bra #cmd_exec_init_dst_surface
+ src_tiled:
+ call #cmd_exec_set_surface_tiled
+ bset $r4 7
+
+ cmd_exec_init_dst_surface:
+ bset $flags $p2
+ mov $r5 #ctx_dst_address_high - #ctx_src_address_high
+ xbit $r15 $r3 8
+ bra e #dst_tiled
+ call #cmd_exec_set_surface_linear
+ bra #cmd_exec_kick
+ dst_tiled:
+ call #cmd_exec_set_surface_tiled
+ bset $r4 8
+
+ cmd_exec_kick:
+ mov $r5 0x800
+ shl b32 $r5 6
+ ld b32 $r6 D[$r0 + #ctx_ycnt]
+ iowr I[$r5 + 0x100] $r6
+ mov $r6 0x0041
+ // SRC_TARGET = 1, DST_TARGET = 2
+ sethi $r6 0x44000000
+ or $r4 $r6
+ iowr I[$r5] $r4
+
+ // if requested, queue up a QUERY write after the copy has completed
+ xbit $r15 $r3 12
+ bra e #cmd_exec_done
+ call #cmd_exec_query
+
+ cmd_exec_done:
+ ret
+
+// Flush write cache
+//
+// Inputs:
+// $r1: irqh state
+// $r2: hostirq state
+// $r3: data
+// $r4: dispatch table entry
+// Outputs:
+// $r1: irqh state
+// $p1: set on error
+// $r2: hostirq state
+// $r3: data
+cmd_wrcache_flush:
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x10000
+ iowr I[$r2] $r3
+ ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3
new file mode 100644
index 000000000000..36f0a99ac7a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3
@@ -0,0 +1,2 @@
+#define GF100
+#include "com.fuc"
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h
new file mode 100644
index 000000000000..d9af6e4e4585
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gf100.fuc3.h
@@ -0,0 +1,606 @@
+uint32_t gf100_pce_data[] = {
+/* 0x0000: ctx_object */
+ 0x00000000,
+/* 0x0004: ctx_query_address_high */
+ 0x00000000,
+/* 0x0008: ctx_query_address_low */
+ 0x00000000,
+/* 0x000c: ctx_query_counter */
+ 0x00000000,
+/* 0x0010: ctx_src_address_high */
+ 0x00000000,
+/* 0x0014: ctx_src_address_low */
+ 0x00000000,
+/* 0x0018: ctx_src_pitch */
+ 0x00000000,
+/* 0x001c: ctx_src_tile_mode */
+ 0x00000000,
+/* 0x0020: ctx_src_xsize */
+ 0x00000000,
+/* 0x0024: ctx_src_ysize */
+ 0x00000000,
+/* 0x0028: ctx_src_zsize */
+ 0x00000000,
+/* 0x002c: ctx_src_zoff */
+ 0x00000000,
+/* 0x0030: ctx_src_xoff */
+ 0x00000000,
+/* 0x0034: ctx_src_yoff */
+ 0x00000000,
+/* 0x0038: ctx_src_cpp */
+ 0x00000000,
+/* 0x003c: ctx_dst_address_high */
+ 0x00000000,
+/* 0x0040: ctx_dst_address_low */
+ 0x00000000,
+/* 0x0044: ctx_dst_pitch */
+ 0x00000000,
+/* 0x0048: ctx_dst_tile_mode */
+ 0x00000000,
+/* 0x004c: ctx_dst_xsize */
+ 0x00000000,
+/* 0x0050: ctx_dst_ysize */
+ 0x00000000,
+/* 0x0054: ctx_dst_zsize */
+ 0x00000000,
+/* 0x0058: ctx_dst_zoff */
+ 0x00000000,
+/* 0x005c: ctx_dst_xoff */
+ 0x00000000,
+/* 0x0060: ctx_dst_yoff */
+ 0x00000000,
+/* 0x0064: ctx_dst_cpp */
+ 0x00000000,
+/* 0x0068: ctx_format */
+ 0x00000000,
+/* 0x006c: ctx_swz_const0 */
+ 0x00000000,
+/* 0x0070: ctx_swz_const1 */
+ 0x00000000,
+/* 0x0074: ctx_xcnt */
+ 0x00000000,
+/* 0x0078: ctx_ycnt */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: dispatch_table */
+ 0x00010000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010040,
+ 0x0001019f,
+ 0x00000000,
+ 0x00010050,
+ 0x000101a1,
+ 0x00000000,
+ 0x00070080,
+ 0x0000001c,
+ 0xfffff000,
+ 0x00000020,
+ 0xfff80000,
+ 0x00000024,
+ 0xffffe000,
+ 0x00000028,
+ 0xfffff800,
+ 0x0000002c,
+ 0xfffff000,
+ 0x00000030,
+ 0xfff80000,
+ 0x00000034,
+ 0xffffe000,
+ 0x00070088,
+ 0x00000048,
+ 0xfffff000,
+ 0x0000004c,
+ 0xfff80000,
+ 0x00000050,
+ 0xffffe000,
+ 0x00000054,
+ 0xfffff800,
+ 0x00000058,
+ 0xfffff000,
+ 0x0000005c,
+ 0xfff80000,
+ 0x00000060,
+ 0xffffe000,
+ 0x000200c0,
+ 0x000104b8,
+ 0x00000000,
+ 0x00010541,
+ 0x00000000,
+ 0x000e00c3,
+ 0x00000010,
+ 0xffffff00,
+ 0x00000014,
+ 0x00000000,
+ 0x0000003c,
+ 0xffffff00,
+ 0x00000040,
+ 0x00000000,
+ 0x00000018,
+ 0xfff80000,
+ 0x00000044,
+ 0xfff80000,
+ 0x00000074,
+ 0xffff0000,
+ 0x00000078,
+ 0xffffe000,
+ 0x00000068,
+ 0xfccc0000,
+ 0x0000006c,
+ 0x00000000,
+ 0x00000070,
+ 0x00000000,
+ 0x00000004,
+ 0xffffff00,
+ 0x00000008,
+ 0x00000000,
+ 0x0000000c,
+ 0x00000000,
+ 0x00000800,
+};
+
+uint32_t gf100_pce_code[] = {
+/* 0x0000: main */
+ 0x04fe04bd,
+ 0x3517f000,
+ 0xf10010fe,
+ 0xf1040017,
+ 0xf0fff327,
+ 0x12d00023,
+ 0x0c25f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x27f01200,
+ 0x0012d003,
+/* 0x002f: spin */
+ 0xf40031f4,
+ 0x0ef40028,
+/* 0x0035: ih */
+ 0x8001cffd,
+ 0xf40812c4,
+ 0x21f4060b,
+/* 0x0041: ih_no_chsw */
+ 0x0412c4ca,
+ 0xf5070bf4,
+/* 0x004b: ih_no_cmd */
+ 0xc4010221,
+ 0x01d00c11,
+/* 0x0053: swctx */
+ 0xf101f840,
+ 0xfe770047,
+ 0x47f1004b,
+ 0x44cf2100,
+ 0x0144f000,
+ 0xb60444b6,
+ 0xf7f13040,
+ 0xf4b6061c,
+ 0x1457f106,
+ 0x00f5d101,
+ 0xb6043594,
+ 0x57fe0250,
+ 0x0145fe00,
+ 0x010052b7,
+ 0x00ff67f1,
+ 0x56fd60bd,
+ 0x0253f004,
+ 0xf80545fa,
+ 0x0053f003,
+ 0xd100e7f0,
+ 0x549800fe,
+ 0x0845b600,
+ 0xb6015698,
+ 0x46fd1864,
+ 0x0047fe05,
+ 0xf00204b9,
+ 0x01f40643,
+ 0x0604fa09,
+/* 0x00c3: swctx_load */
+ 0xfa060ef4,
+/* 0x00c6: swctx_done */
+ 0x03f80504,
+/* 0x00ca: chsw */
+ 0x27f100f8,
+ 0x23cf1400,
+ 0x1e3fc800,
+ 0xf4170bf4,
+ 0x21f40132,
+ 0x1e3af053,
+ 0xf00023d0,
+ 0x24d00147,
+/* 0x00eb: chsw_no_unload */
+ 0xcf00f880,
+ 0x3dc84023,
+ 0x090bf41e,
+ 0xf40131f4,
+/* 0x00fa: chsw_finish_load */
+ 0x37f05321,
+ 0x8023d002,
+/* 0x0102: dispatch */
+ 0x37f100f8,
+ 0x32cf1900,
+ 0x0033cf40,
+ 0x07ff24e4,
+ 0xf11024b6,
+ 0xbd010057,
+/* 0x011b: dispatch_loop */
+ 0x5874bd64,
+ 0x57580056,
+ 0x0450b601,
+ 0xf40446b8,
+ 0x76bb4d08,
+ 0x0447b800,
+ 0xbb0f08f4,
+ 0x74b60276,
+ 0x0057bb03,
+/* 0x013f: dispatch_valid_mthd */
+ 0xbbdf0ef4,
+ 0x44b60246,
+ 0x0045bb03,
+ 0xfd014598,
+ 0x54b00453,
+ 0x201bf400,
+ 0x58004558,
+ 0x64b00146,
+ 0x091bf400,
+ 0xf4005380,
+/* 0x0166: dispatch_cmd */
+ 0x32f4300e,
+ 0xf455f901,
+ 0x0ef40c01,
+/* 0x0171: dispatch_invalid_bitfield */
+ 0x0225f025,
+/* 0x0174: dispatch_illegal_mthd */
+/* 0x0177: dispatch_error */
+ 0xf10125f0,
+ 0xd0100047,
+ 0x43d00042,
+ 0x4027f040,
+/* 0x0187: hostirq_wait */
+ 0xcf0002d0,
+ 0x24f08002,
+ 0x0024b040,
+/* 0x0193: dispatch_done */
+ 0xf1f71bf4,
+ 0xf01d0027,
+ 0x23d00137,
+/* 0x019f: cmd_nop */
+ 0xf800f800,
+/* 0x01a1: cmd_pm_trigger */
+ 0x0027f100,
+ 0xf034bd22,
+ 0x23d00233,
+/* 0x01af: cmd_exec_set_format */
+ 0xf400f800,
+ 0x01b0f030,
+ 0x0101b000,
+ 0xb00201b0,
+ 0x04980301,
+ 0x3045c71a,
+ 0xc70150b6,
+ 0x60b63446,
+ 0x3847c701,
+ 0xf40170b6,
+ 0x84bd0232,
+/* 0x01da: ncomp_loop */
+ 0x4ac494bd,
+ 0x0445b60f,
+/* 0x01e2: bpc_loop */
+ 0xa430b4bd,
+ 0x0f18f404,
+ 0xbbc0a5ff,
+ 0x31f400cb,
+ 0x220ef402,
+/* 0x01f4: cmp_c0 */
+ 0xf00c1bf4,
+ 0xcbbb10c7,
+ 0x160ef400,
+/* 0x0200: cmp_c1 */
+ 0xf406a430,
+ 0xc7f00c18,
+ 0x00cbbb14,
+/* 0x020f: cmp_zero */
+ 0xf1070ef4,
+/* 0x0213: bpc_next */
+ 0x380080c7,
+ 0x80b601c8,
+ 0x01b0b601,
+ 0xf404b5b8,
+ 0x90b6c308,
+ 0x0497b801,
+ 0xfdb208f4,
+ 0x06800065,
+ 0x1d08980e,
+ 0xf40068fd,
+ 0x64bd0502,
+/* 0x023c: dst_xcnt */
+ 0x800075fd,
+ 0x78fd1907,
+ 0x1057f100,
+ 0x0654b608,
+ 0xd00056d0,
+ 0x50b74057,
+ 0x06980800,
+ 0x0162b619,
+ 0x980864b6,
+ 0x72b60e07,
+ 0x0567fd01,
+ 0xb70056d0,
+ 0xb4010050,
+ 0x56d00060,
+ 0x0160b400,
+ 0xb44056d0,
+ 0x56d00260,
+ 0x0360b480,
+ 0xb7c056d0,
+ 0x98040050,
+ 0x56d01b06,
+ 0x1c069800,
+ 0xf44056d0,
+ 0x00f81030,
+/* 0x029c: cmd_exec_set_surface_tiled */
+ 0xc7075798,
+ 0x78c76879,
+ 0x0380b664,
+ 0xb06077c7,
+ 0x1bf40e76,
+ 0x0477f009,
+/* 0x02b7: xtile64 */
+ 0xf00f0ef4,
+ 0x70b6027c,
+ 0x0947fd11,
+/* 0x02c3: xtileok */
+ 0x980677f0,
+ 0x5b980c5a,
+ 0x00abfd0e,
+ 0xbb01b7f0,
+ 0xb2b604b7,
+ 0xc4abff01,
+ 0x9805a7bb,
+ 0xe7f00d5d,
+ 0x04e8bb01,
+ 0xff01e2b6,
+ 0xd8bbb4de,
+ 0x01e0b605,
+ 0xbb0cef94,
+ 0xfefd02eb,
+ 0x026cf005,
+ 0x020860b7,
+ 0xd00864b6,
+ 0xb7bb006f,
+ 0x00cbbb04,
+ 0x98085f98,
+ 0xfbfd0e5b,
+ 0x01b7f000,
+ 0xb604b7bb,
+ 0xfbbb01b2,
+ 0x05f7bb00,
+ 0x5f98f0f9,
+ 0x01b7f009,
+ 0xb604b8bb,
+ 0xfbbb01b2,
+ 0x05f8bb00,
+ 0x78bbf0f9,
+ 0x0282b600,
+ 0xbb01b7f0,
+ 0xb9bb04b8,
+ 0x0b589804,
+ 0xbb01e7f0,
+ 0xe2b604e9,
+ 0xf48eff01,
+ 0xbb04f7bb,
+ 0x79bb00cf,
+ 0x0589bb00,
+ 0x90fcf0fc,
+ 0xbb00d9fd,
+ 0x89fd00ad,
+ 0x008ffd00,
+ 0xbb00a8bb,
+ 0x92b604a7,
+ 0x0497bb01,
+ 0x988069d0,
+ 0x58980557,
+ 0x00acbb04,
+ 0xb6007abb,
+ 0x84b60081,
+ 0x058bfd10,
+ 0x060062b7,
+ 0xb70067d0,
+ 0xd0040060,
+ 0x00f80068,
+/* 0x03a8: cmd_exec_set_surface_linear */
+ 0xb7026cf0,
+ 0xb6020260,
+ 0x57980864,
+ 0x0067d005,
+ 0x040060b7,
+ 0xb6045798,
+ 0x67d01074,
+ 0x0060b700,
+ 0x06579804,
+ 0xf80067d0,
+/* 0x03d1: cmd_exec_wait */
+ 0xf900f900,
+ 0x0007f110,
+ 0x0604b608,
+/* 0x03dc: loop */
+ 0xf00001cf,
+ 0x1bf40114,
+ 0xfc10fcfa,
+/* 0x03eb: cmd_exec_query */
+ 0xc800f800,
+ 0x1bf40d34,
+ 0xd121f570,
+ 0x0c47f103,
+ 0x0644b608,
+ 0xb6020598,
+ 0x45d00450,
+ 0x4040d000,
+ 0xd00c57f0,
+ 0x40b78045,
+ 0x05980400,
+ 0x1054b601,
+ 0xb70045d0,
+ 0xf1050040,
+ 0xf00b0057,
+ 0x45d00153,
+ 0x4057f100,
+ 0x0154b640,
+ 0x808053f1,
+ 0xf14045d0,
+ 0xf1111057,
+ 0xd0131253,
+ 0x57f18045,
+ 0x53f11514,
+ 0x45d01716,
+ 0x0157f1c0,
+ 0x0153f026,
+ 0x080047f1,
+ 0xd00644b6,
+/* 0x045e: query_counter */
+ 0x21f50045,
+ 0x47f103d1,
+ 0x44b6080c,
+ 0x02059806,
+ 0xd00045d0,
+ 0x57f04040,
+ 0x8045d004,
+ 0x040040b7,
+ 0xb6010598,
+ 0x45d01054,
+ 0x0040b700,
+ 0x0057f105,
+ 0x0045d003,
+ 0x111057f1,
+ 0x131253f1,
+ 0x984045d0,
+ 0x40b70305,
+ 0x45d00500,
+ 0x0157f100,
+ 0x0153f026,
+ 0x080047f1,
+ 0xd00644b6,
+ 0x00f80045,
+/* 0x04b8: cmd_exec */
+ 0x03d121f5,
+ 0xf4003fc8,
+ 0x21f50e0b,
+ 0x47f101af,
+ 0x0ef40200,
+/* 0x04cd: cmd_exec_no_format */
+ 0x1067f11e,
+ 0x0664b608,
+ 0x800177f0,
+ 0x07800e07,
+ 0x1d079819,
+ 0xd00067d0,
+ 0x44bd4067,
+/* 0x04e8: cmd_exec_init_src_surface */
+ 0xbd0232f4,
+ 0x043fc854,
+ 0xf50a0bf4,
+ 0xf403a821,
+/* 0x04fa: src_tiled */
+ 0x21f50a0e,
+ 0x49f0029c,
+/* 0x0501: cmd_exec_init_dst_surface */
+ 0x0231f407,
+ 0xc82c57f0,
+ 0x0bf4083f,
+ 0xa821f50a,
+ 0x0a0ef403,
+/* 0x0514: dst_tiled */
+ 0x029c21f5,
+/* 0x051b: cmd_exec_kick */
+ 0xf10849f0,
+ 0xb6080057,
+ 0x06980654,
+ 0x4056d01e,
+ 0xf14167f0,
+ 0xfd440063,
+ 0x54d00546,
+ 0x0c3fc800,
+ 0xf5070bf4,
+/* 0x053f: cmd_exec_done */
+ 0xf803eb21,
+/* 0x0541: cmd_wrcache_flush */
+ 0x0027f100,
+ 0xf034bd22,
+ 0x23d00133,
+ 0x0000f800,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3
new file mode 100644
index 000000000000..07bda93cfd79
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3
@@ -0,0 +1,2 @@
+#define GT215
+#include "com.fuc"
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h
new file mode 100644
index 000000000000..f42c0d0d6cee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/fuc/gt215.fuc3.h
@@ -0,0 +1,620 @@
+uint32_t gt215_pce_data[] = {
+/* 0x0000: ctx_object */
+ 0x00000000,
+/* 0x0004: ctx_dma */
+/* 0x0004: ctx_dma_query */
+ 0x00000000,
+/* 0x0008: ctx_dma_src */
+ 0x00000000,
+/* 0x000c: ctx_dma_dst */
+ 0x00000000,
+/* 0x0010: ctx_query_address_high */
+ 0x00000000,
+/* 0x0014: ctx_query_address_low */
+ 0x00000000,
+/* 0x0018: ctx_query_counter */
+ 0x00000000,
+/* 0x001c: ctx_src_address_high */
+ 0x00000000,
+/* 0x0020: ctx_src_address_low */
+ 0x00000000,
+/* 0x0024: ctx_src_pitch */
+ 0x00000000,
+/* 0x0028: ctx_src_tile_mode */
+ 0x00000000,
+/* 0x002c: ctx_src_xsize */
+ 0x00000000,
+/* 0x0030: ctx_src_ysize */
+ 0x00000000,
+/* 0x0034: ctx_src_zsize */
+ 0x00000000,
+/* 0x0038: ctx_src_zoff */
+ 0x00000000,
+/* 0x003c: ctx_src_xoff */
+ 0x00000000,
+/* 0x0040: ctx_src_yoff */
+ 0x00000000,
+/* 0x0044: ctx_src_cpp */
+ 0x00000000,
+/* 0x0048: ctx_dst_address_high */
+ 0x00000000,
+/* 0x004c: ctx_dst_address_low */
+ 0x00000000,
+/* 0x0050: ctx_dst_pitch */
+ 0x00000000,
+/* 0x0054: ctx_dst_tile_mode */
+ 0x00000000,
+/* 0x0058: ctx_dst_xsize */
+ 0x00000000,
+/* 0x005c: ctx_dst_ysize */
+ 0x00000000,
+/* 0x0060: ctx_dst_zsize */
+ 0x00000000,
+/* 0x0064: ctx_dst_zoff */
+ 0x00000000,
+/* 0x0068: ctx_dst_xoff */
+ 0x00000000,
+/* 0x006c: ctx_dst_yoff */
+ 0x00000000,
+/* 0x0070: ctx_dst_cpp */
+ 0x00000000,
+/* 0x0074: ctx_format */
+ 0x00000000,
+/* 0x0078: ctx_swz_const0 */
+ 0x00000000,
+/* 0x007c: ctx_swz_const1 */
+ 0x00000000,
+/* 0x0080: ctx_xcnt */
+ 0x00000000,
+/* 0x0084: ctx_ycnt */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: dispatch_table */
+ 0x00010000,
+ 0x00000000,
+ 0x00000000,
+ 0x00010040,
+ 0x00010160,
+ 0x00000000,
+ 0x00010050,
+ 0x00010162,
+ 0x00000000,
+ 0x00030060,
+/* 0x0128: dispatch_dma */
+ 0x00010170,
+ 0x00000000,
+ 0x00010170,
+ 0x00000000,
+ 0x00010170,
+ 0x00000000,
+ 0x00070080,
+ 0x00000028,
+ 0xfffff000,
+ 0x0000002c,
+ 0xfff80000,
+ 0x00000030,
+ 0xffffe000,
+ 0x00000034,
+ 0xfffff800,
+ 0x00000038,
+ 0xfffff000,
+ 0x0000003c,
+ 0xfff80000,
+ 0x00000040,
+ 0xffffe000,
+ 0x00070088,
+ 0x00000054,
+ 0xfffff000,
+ 0x00000058,
+ 0xfff80000,
+ 0x0000005c,
+ 0xffffe000,
+ 0x00000060,
+ 0xfffff800,
+ 0x00000064,
+ 0xfffff000,
+ 0x00000068,
+ 0xfff80000,
+ 0x0000006c,
+ 0xffffe000,
+ 0x000200c0,
+ 0x00010492,
+ 0x00000000,
+ 0x0001051b,
+ 0x00000000,
+ 0x000e00c3,
+ 0x0000001c,
+ 0xffffff00,
+ 0x00000020,
+ 0x00000000,
+ 0x00000048,
+ 0xffffff00,
+ 0x0000004c,
+ 0x00000000,
+ 0x00000024,
+ 0xfff80000,
+ 0x00000050,
+ 0xfff80000,
+ 0x00000080,
+ 0xffff0000,
+ 0x00000084,
+ 0xffffe000,
+ 0x00000074,
+ 0xfccc0000,
+ 0x00000078,
+ 0x00000000,
+ 0x0000007c,
+ 0x00000000,
+ 0x00000010,
+ 0xffffff00,
+ 0x00000014,
+ 0x00000000,
+ 0x00000018,
+ 0x00000000,
+ 0x00000800,
+};
+
+uint32_t gt215_pce_code[] = {
+/* 0x0000: main */
+ 0x04fe04bd,
+ 0x3517f000,
+ 0xf10010fe,
+ 0xf1040017,
+ 0xf0fff327,
+ 0x12d00023,
+ 0x0c25f0c0,
+ 0xf40012d0,
+ 0x17f11031,
+ 0x27f01200,
+ 0x0012d003,
+/* 0x002f: spin */
+ 0xf40031f4,
+ 0x0ef40028,
+/* 0x0035: ih */
+ 0x8001cffd,
+ 0xf40812c4,
+ 0x21f4060b,
+/* 0x0041: ih_no_chsw */
+ 0x0412c472,
+ 0xf4060bf4,
+/* 0x004a: ih_no_cmd */
+ 0x11c4c321,
+ 0x4001d00c,
+/* 0x0052: swctx */
+ 0x47f101f8,
+ 0x4bfe7700,
+ 0x0007fe00,
+ 0xf00204b9,
+ 0x01f40643,
+ 0x0604fa09,
+/* 0x006b: swctx_load */
+ 0xfa060ef4,
+/* 0x006e: swctx_done */
+ 0x03f80504,
+/* 0x0072: chsw */
+ 0x27f100f8,
+ 0x23cf1400,
+ 0x1e3fc800,
+ 0xf4170bf4,
+ 0x21f40132,
+ 0x1e3af052,
+ 0xf00023d0,
+ 0x24d00147,
+/* 0x0093: chsw_no_unload */
+ 0xcf00f880,
+ 0x3dc84023,
+ 0x220bf41e,
+ 0xf40131f4,
+ 0x57f05221,
+ 0x0367f004,
+/* 0x00a8: chsw_load_ctx_dma */
+ 0xa07856bc,
+ 0xb6018068,
+ 0x87d00884,
+ 0x0162b600,
+/* 0x00bb: chsw_finish_load */
+ 0xf0f018f4,
+ 0x23d00237,
+/* 0x00c3: dispatch */
+ 0xf100f880,
+ 0xcf190037,
+ 0x33cf4032,
+ 0xff24e400,
+ 0x1024b607,
+ 0x010057f1,
+ 0x74bd64bd,
+/* 0x00dc: dispatch_loop */
+ 0x58005658,
+ 0x50b60157,
+ 0x0446b804,
+ 0xbb4d08f4,
+ 0x47b80076,
+ 0x0f08f404,
+ 0xb60276bb,
+ 0x57bb0374,
+ 0xdf0ef400,
+/* 0x0100: dispatch_valid_mthd */
+ 0xb60246bb,
+ 0x45bb0344,
+ 0x01459800,
+ 0xb00453fd,
+ 0x1bf40054,
+ 0x00455820,
+ 0xb0014658,
+ 0x1bf40064,
+ 0x00538009,
+/* 0x0127: dispatch_cmd */
+ 0xf4300ef4,
+ 0x55f90132,
+ 0xf40c01f4,
+/* 0x0132: dispatch_invalid_bitfield */
+ 0x25f0250e,
+/* 0x0135: dispatch_illegal_mthd */
+ 0x0125f002,
+/* 0x0138: dispatch_error */
+ 0x100047f1,
+ 0xd00042d0,
+ 0x27f04043,
+ 0x0002d040,
+/* 0x0148: hostirq_wait */
+ 0xf08002cf,
+ 0x24b04024,
+ 0xf71bf400,
+/* 0x0154: dispatch_done */
+ 0x1d0027f1,
+ 0xd00137f0,
+ 0x00f80023,
+/* 0x0160: cmd_nop */
+/* 0x0162: cmd_pm_trigger */
+ 0x27f100f8,
+ 0x34bd2200,
+ 0xd00233f0,
+ 0x00f80023,
+/* 0x0170: cmd_dma */
+ 0x012842b7,
+ 0xf00145b6,
+ 0x43801e39,
+ 0x0040b701,
+ 0x0644b606,
+ 0xf80043d0,
+/* 0x0189: cmd_exec_set_format */
+ 0xf030f400,
+ 0xb00001b0,
+ 0x01b00101,
+ 0x0301b002,
+ 0xc71d0498,
+ 0x50b63045,
+ 0x3446c701,
+ 0xc70160b6,
+ 0x70b63847,
+ 0x0232f401,
+ 0x94bd84bd,
+/* 0x01b4: ncomp_loop */
+ 0xb60f4ac4,
+ 0xb4bd0445,
+/* 0x01bc: bpc_loop */
+ 0xf404a430,
+ 0xa5ff0f18,
+ 0x00cbbbc0,
+ 0xf40231f4,
+/* 0x01ce: cmp_c0 */
+ 0x1bf4220e,
+ 0x10c7f00c,
+ 0xf400cbbb,
+/* 0x01da: cmp_c1 */
+ 0xa430160e,
+ 0x0c18f406,
+ 0xbb14c7f0,
+ 0x0ef400cb,
+/* 0x01e9: cmp_zero */
+ 0x80c7f107,
+/* 0x01ed: bpc_next */
+ 0x01c83800,
+ 0xb60180b6,
+ 0xb5b801b0,
+ 0xc308f404,
+ 0xb80190b6,
+ 0x08f40497,
+ 0x0065fdb2,
+ 0x98110680,
+ 0x68fd2008,
+ 0x0502f400,
+/* 0x0216: dst_xcnt */
+ 0x75fd64bd,
+ 0x1c078000,
+ 0xf10078fd,
+ 0xb6081057,
+ 0x56d00654,
+ 0x4057d000,
+ 0x080050b7,
+ 0xb61c0698,
+ 0x64b60162,
+ 0x11079808,
+ 0xfd0172b6,
+ 0x56d00567,
+ 0x0050b700,
+ 0x0060b401,
+ 0xb40056d0,
+ 0x56d00160,
+ 0x0260b440,
+ 0xb48056d0,
+ 0x56d00360,
+ 0x0050b7c0,
+ 0x1e069804,
+ 0x980056d0,
+ 0x56d01f06,
+ 0x1030f440,
+/* 0x0276: cmd_exec_set_surface_tiled */
+ 0x579800f8,
+ 0x6879c70a,
+ 0xb66478c7,
+ 0x77c70280,
+ 0x0e76b060,
+ 0xf0091bf4,
+ 0x0ef40477,
+/* 0x0291: xtile64 */
+ 0x027cf00f,
+ 0xfd1170b6,
+ 0x77f00947,
+/* 0x029d: xtileok */
+ 0x0f5a9806,
+ 0xfd115b98,
+ 0xb7f000ab,
+ 0x04b7bb01,
+ 0xff01b2b6,
+ 0xa7bbc4ab,
+ 0x105d9805,
+ 0xbb01e7f0,
+ 0xe2b604e8,
+ 0xb4deff01,
+ 0xb605d8bb,
+ 0xef9401e0,
+ 0x02ebbb0c,
+ 0xf005fefd,
+ 0x60b7026c,
+ 0x64b60208,
+ 0x006fd008,
+ 0xbb04b7bb,
+ 0x5f9800cb,
+ 0x115b980b,
+ 0xf000fbfd,
+ 0xb7bb01b7,
+ 0x01b2b604,
+ 0xbb00fbbb,
+ 0xf0f905f7,
+ 0xf00c5f98,
+ 0xb8bb01b7,
+ 0x01b2b604,
+ 0xbb00fbbb,
+ 0xf0f905f8,
+ 0xb60078bb,
+ 0xb7f00282,
+ 0x04b8bb01,
+ 0x9804b9bb,
+ 0xe7f00e58,
+ 0x04e9bb01,
+ 0xff01e2b6,
+ 0xf7bbf48e,
+ 0x00cfbb04,
+ 0xbb0079bb,
+ 0xf0fc0589,
+ 0xd9fd90fc,
+ 0x00adbb00,
+ 0xfd0089fd,
+ 0xa8bb008f,
+ 0x04a7bb00,
+ 0xbb0192b6,
+ 0x69d00497,
+ 0x08579880,
+ 0xbb075898,
+ 0x7abb00ac,
+ 0x0081b600,
+ 0xfd1084b6,
+ 0x62b7058b,
+ 0x67d00600,
+ 0x0060b700,
+ 0x0068d004,
+/* 0x0382: cmd_exec_set_surface_linear */
+ 0x6cf000f8,
+ 0x0260b702,
+ 0x0864b602,
+ 0xd0085798,
+ 0x60b70067,
+ 0x57980400,
+ 0x1074b607,
+ 0xb70067d0,
+ 0x98040060,
+ 0x67d00957,
+/* 0x03ab: cmd_exec_wait */
+ 0xf900f800,
+ 0xf110f900,
+ 0xb6080007,
+/* 0x03b6: loop */
+ 0x01cf0604,
+ 0x0114f000,
+ 0xfcfa1bf4,
+ 0xf800fc10,
+/* 0x03c5: cmd_exec_query */
+ 0x0d34c800,
+ 0xf5701bf4,
+ 0xf103ab21,
+ 0xb6080c47,
+ 0x05980644,
+ 0x0450b605,
+ 0xd00045d0,
+ 0x57f04040,
+ 0x8045d00c,
+ 0x040040b7,
+ 0xb6040598,
+ 0x45d01054,
+ 0x0040b700,
+ 0x0057f105,
+ 0x0153f00b,
+ 0xf10045d0,
+ 0xb6404057,
+ 0x53f10154,
+ 0x45d08080,
+ 0x1057f140,
+ 0x1253f111,
+ 0x8045d013,
+ 0x151457f1,
+ 0x171653f1,
+ 0xf1c045d0,
+ 0xf0260157,
+ 0x47f10153,
+ 0x44b60800,
+ 0x0045d006,
+/* 0x0438: query_counter */
+ 0x03ab21f5,
+ 0x080c47f1,
+ 0x980644b6,
+ 0x45d00505,
+ 0x4040d000,
+ 0xd00457f0,
+ 0x40b78045,
+ 0x05980400,
+ 0x1054b604,
+ 0xb70045d0,
+ 0xf1050040,
+ 0xd0030057,
+ 0x57f10045,
+ 0x53f11110,
+ 0x45d01312,
+ 0x06059840,
+ 0x050040b7,
+ 0xf10045d0,
+ 0xf0260157,
+ 0x47f10153,
+ 0x44b60800,
+ 0x0045d006,
+/* 0x0492: cmd_exec */
+ 0x21f500f8,
+ 0x3fc803ab,
+ 0x0e0bf400,
+ 0x018921f5,
+ 0x020047f1,
+/* 0x04a7: cmd_exec_no_format */
+ 0xf11e0ef4,
+ 0xb6081067,
+ 0x77f00664,
+ 0x11078001,
+ 0x981c0780,
+ 0x67d02007,
+ 0x4067d000,
+/* 0x04c2: cmd_exec_init_src_surface */
+ 0x32f444bd,
+ 0xc854bd02,
+ 0x0bf4043f,
+ 0x8221f50a,
+ 0x0a0ef403,
+/* 0x04d4: src_tiled */
+ 0x027621f5,
+/* 0x04db: cmd_exec_init_dst_surface */
+ 0xf40749f0,
+ 0x57f00231,
+ 0x083fc82c,
+ 0xf50a0bf4,
+ 0xf4038221,
+/* 0x04ee: dst_tiled */
+ 0x21f50a0e,
+ 0x49f00276,
+/* 0x04f5: cmd_exec_kick */
+ 0x0057f108,
+ 0x0654b608,
+ 0xd0210698,
+ 0x67f04056,
+ 0x0063f141,
+ 0x0546fd44,
+ 0xc80054d0,
+ 0x0bf40c3f,
+ 0xc521f507,
+/* 0x0519: cmd_exec_done */
+/* 0x051b: cmd_wrcache_flush */
+ 0xf100f803,
+ 0xbd220027,
+ 0x0133f034,
+ 0xf80023d0,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c
new file mode 100644
index 000000000000..2d2e549c2e34
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gf100.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/ce.h>
+#include <engine/falcon.h>
+#include "fuc/gf100.fuc3.h"
+
+struct gf100_ce_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_ce0_sclass[] = {
+ { 0x90b5, &nvkm_object_ofuncs },
+ {},
+};
+
+static struct nvkm_oclass
+gf100_ce1_sclass[] = {
+ { 0x90b8, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_ofuncs
+gf100_ce_context_ofuncs = {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+};
+
+static struct nvkm_oclass
+gf100_ce0_cclass = {
+ .handle = NV_ENGCTX(CE0, 0xc0),
+ .ofuncs = &gf100_ce_context_ofuncs,
+};
+
+static struct nvkm_oclass
+gf100_ce1_cclass = {
+ .handle = NV_ENGCTX(CE1, 0xc0),
+ .ofuncs = &gf100_ce_context_ofuncs,
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_ce_init(struct nvkm_object *object)
+{
+ struct gf100_ce_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wo32(priv, 0x084, nv_engidx(&priv->base.base) - NVDEV_ENGINE_CE0);
+ return 0;
+}
+
+static int
+gf100_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_ce_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, true,
+ "PCE0", "ce0", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000040;
+ nv_subdev(priv)->intr = gt215_ce_intr;
+ nv_engine(priv)->cclass = &gf100_ce0_cclass;
+ nv_engine(priv)->sclass = gf100_ce0_sclass;
+ nv_falcon(priv)->code.data = gf100_pce_code;
+ nv_falcon(priv)->code.size = sizeof(gf100_pce_code);
+ nv_falcon(priv)->data.data = gf100_pce_data;
+ nv_falcon(priv)->data.size = sizeof(gf100_pce_data);
+ return 0;
+}
+
+static int
+gf100_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_ce_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x105000, true,
+ "PCE1", "ce1", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000080;
+ nv_subdev(priv)->intr = gt215_ce_intr;
+ nv_engine(priv)->cclass = &gf100_ce1_cclass;
+ nv_engine(priv)->sclass = gf100_ce1_sclass;
+ nv_falcon(priv)->code.data = gf100_pce_code;
+ nv_falcon(priv)->code.size = sizeof(gf100_pce_code);
+ nv_falcon(priv)->data.data = gf100_pce_data;
+ nv_falcon(priv)->data.size = sizeof(gf100_pce_data);
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_ce0_oclass = {
+ .handle = NV_ENGINE(CE0, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_ce0_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gf100_ce_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
+
+struct nvkm_oclass
+gf100_ce1_oclass = {
+ .handle = NV_ENGINE(CE1, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_ce1_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gf100_ce_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
new file mode 100644
index 000000000000..a998932fae45
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gk104.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/ce.h>
+
+#include <core/engctx.h>
+
+struct gk104_ce_priv {
+ struct nvkm_engine base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_ce_sclass[] = {
+ { 0xa0b5, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_ofuncs
+gk104_ce_context_ofuncs = {
+ .ctor = _nvkm_engctx_ctor,
+ .dtor = _nvkm_engctx_dtor,
+ .init = _nvkm_engctx_init,
+ .fini = _nvkm_engctx_fini,
+ .rd32 = _nvkm_engctx_rd32,
+ .wr32 = _nvkm_engctx_wr32,
+};
+
+static struct nvkm_oclass
+gk104_ce_cclass = {
+ .handle = NV_ENGCTX(CE0, 0xc0),
+ .ofuncs = &gk104_ce_context_ofuncs,
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static void
+gk104_ce_intr(struct nvkm_subdev *subdev)
+{
+ const int ce = nv_subidx(subdev) - NVDEV_ENGINE_CE0;
+ struct gk104_ce_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, 0x104908 + (ce * 0x1000));
+
+ if (stat) {
+ nv_warn(priv, "unhandled intr 0x%08x\n", stat);
+ nv_wr32(priv, 0x104908 + (ce * 0x1000), stat);
+ }
+}
+
+static int
+gk104_ce0_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_ce_priv *priv;
+ int ret;
+
+ ret = nvkm_engine_create(parent, engine, oclass, true,
+ "PCE0", "ce0", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000040;
+ nv_subdev(priv)->intr = gk104_ce_intr;
+ nv_engine(priv)->cclass = &gk104_ce_cclass;
+ nv_engine(priv)->sclass = gk104_ce_sclass;
+ return 0;
+}
+
+static int
+gk104_ce1_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_ce_priv *priv;
+ int ret;
+
+ ret = nvkm_engine_create(parent, engine, oclass, true,
+ "PCE1", "ce1", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000080;
+ nv_subdev(priv)->intr = gk104_ce_intr;
+ nv_engine(priv)->cclass = &gk104_ce_cclass;
+ nv_engine(priv)->sclass = gk104_ce_sclass;
+ return 0;
+}
+
+static int
+gk104_ce2_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_ce_priv *priv;
+ int ret;
+
+ ret = nvkm_engine_create(parent, engine, oclass, true,
+ "PCE2", "ce2", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00200000;
+ nv_subdev(priv)->intr = gk104_ce_intr;
+ nv_engine(priv)->cclass = &gk104_ce_cclass;
+ nv_engine(priv)->sclass = gk104_ce_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_ce0_oclass = {
+ .handle = NV_ENGINE(CE0, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_ce0_ctor,
+ .dtor = _nvkm_engine_dtor,
+ .init = _nvkm_engine_init,
+ .fini = _nvkm_engine_fini,
+ },
+};
+
+struct nvkm_oclass
+gk104_ce1_oclass = {
+ .handle = NV_ENGINE(CE1, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_ce1_ctor,
+ .dtor = _nvkm_engine_dtor,
+ .init = _nvkm_engine_init,
+ .fini = _nvkm_engine_fini,
+ },
+};
+
+struct nvkm_oclass
+gk104_ce2_oclass = {
+ .handle = NV_ENGINE(CE2, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_ce2_ctor,
+ .dtor = _nvkm_engine_dtor,
+ .init = _nvkm_engine_init,
+ .fini = _nvkm_engine_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
new file mode 100644
index 000000000000..d8bb4293bc11
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/ce/gt215.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/ce.h>
+#include <engine/falcon.h>
+#include <engine/fifo.h>
+#include "fuc/gt215.fuc3.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/enum.h>
+
+struct gt215_ce_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * Copy object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt215_ce_sclass[] = {
+ { 0x85b5, &nvkm_object_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PCE context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt215_ce_cclass = {
+ .handle = NV_ENGCTX(CE0, 0xa3),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+
+ },
+};
+
+/*******************************************************************************
+ * PCE engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_enum
+gt215_ce_isr_error_name[] = {
+ { 0x0001, "ILLEGAL_MTHD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "INVALID_BITFIELD" },
+ {}
+};
+
+void
+gt215_ce_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_falcon *falcon = (void *)subdev;
+ struct nvkm_object *engctx;
+ u32 dispatch = nv_ro32(falcon, 0x01c);
+ u32 stat = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+ u64 inst = nv_ro32(falcon, 0x050) & 0x3fffffff;
+ u32 ssta = nv_ro32(falcon, 0x040) & 0x0000ffff;
+ u32 addr = nv_ro32(falcon, 0x040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_ro32(falcon, 0x044);
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat & 0x00000040) {
+ nv_error(falcon, "DISPATCH_ERROR [");
+ nvkm_enum_print(gt215_ce_isr_error_name, ssta);
+ pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, inst << 12, nvkm_client_name(engctx), subc,
+ mthd, data);
+ nv_wo32(falcon, 0x004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ nv_error(falcon, "unhandled intr 0x%08x\n", stat);
+ nv_wo32(falcon, 0x004, stat);
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static int
+gt215_ce_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ bool enable = (nv_device(parent)->chipset != 0xaf);
+ struct gt215_ce_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x104000, enable,
+ "PCE0", "ce0", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00802000;
+ nv_subdev(priv)->intr = gt215_ce_intr;
+ nv_engine(priv)->cclass = &gt215_ce_cclass;
+ nv_engine(priv)->sclass = gt215_ce_sclass;
+ nv_falcon(priv)->code.data = gt215_pce_code;
+ nv_falcon(priv)->code.size = sizeof(gt215_pce_code);
+ nv_falcon(priv)->data.data = gt215_pce_data;
+ nv_falcon(priv)->data.size = sizeof(gt215_pce_data);
+ return 0;
+}
+
+struct nvkm_oclass
+gt215_ce_oclass = {
+ .handle = NV_ENGINE(CE0, 0xa3),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt215_ce_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = _nvkm_falcon_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild
new file mode 100644
index 000000000000..fa39945327ce
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/cipher/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
new file mode 100644
index 000000000000..13f30428a305
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/cipher/g84.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/cipher.h>
+#include <engine/fifo.h>
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+struct g84_cipher_priv {
+ struct nvkm_engine base;
+};
+
+/*******************************************************************************
+ * Crypt object classes
+ ******************************************************************************/
+
+static int
+g84_cipher_object_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj *obj;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+ 16, 16, 0, &obj);
+ *pobject = nv_object(obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, nv_mclass(obj));
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+g84_cipher_ofuncs = {
+ .ctor = g84_cipher_object_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+g84_cipher_sclass[] = {
+ { 0x74c1, &g84_cipher_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PCIPHER context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_cipher_cclass = {
+ .handle = NV_ENGCTX(CIPHER, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_engctx_ctor,
+ .dtor = _nvkm_engctx_dtor,
+ .init = _nvkm_engctx_init,
+ .fini = _nvkm_engctx_fini,
+ .rd32 = _nvkm_engctx_rd32,
+ .wr32 = _nvkm_engctx_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PCIPHER engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_bitfield
+g84_cipher_intr_mask[] = {
+ { 0x00000001, "INVALID_STATE" },
+ { 0x00000002, "ILLEGAL_MTHD" },
+ { 0x00000004, "ILLEGAL_CLASS" },
+ { 0x00000080, "QUERY" },
+ { 0x00000100, "FAULT" },
+ {}
+};
+
+static void
+g84_cipher_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct g84_cipher_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, 0x102130);
+ u32 mthd = nv_rd32(priv, 0x102190);
+ u32 data = nv_rd32(priv, 0x102194);
+ u32 inst = nv_rd32(priv, 0x102188) & 0x7fffffff;
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat) {
+ nv_error(priv, "%s", "");
+ nvkm_bitfield_print(g84_cipher_intr_mask, stat);
+ pr_cont(" ch %d [0x%010llx %s] mthd 0x%04x data 0x%08x\n",
+ chid, (u64)inst << 12, nvkm_client_name(engctx),
+ mthd, data);
+ }
+
+ nv_wr32(priv, 0x102130, stat);
+ nv_wr32(priv, 0x10200c, 0x10);
+
+ nvkm_engctx_put(engctx);
+}
+
+static int
+g84_cipher_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g84_cipher_priv *priv;
+ int ret;
+
+ ret = nvkm_engine_create(parent, engine, oclass, true,
+ "PCIPHER", "cipher", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00004000;
+ nv_subdev(priv)->intr = g84_cipher_intr;
+ nv_engine(priv)->cclass = &g84_cipher_cclass;
+ nv_engine(priv)->sclass = g84_cipher_sclass;
+ return 0;
+}
+
+static int
+g84_cipher_init(struct nvkm_object *object)
+{
+ struct g84_cipher_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_engine_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x102130, 0xffffffff);
+ nv_wr32(priv, 0x102140, 0xffffffbf);
+ nv_wr32(priv, 0x10200c, 0x00000010);
+ return 0;
+}
+
+struct nvkm_oclass
+g84_cipher_oclass = {
+ .handle = NV_ENGINE(CIPHER, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_cipher_ctor,
+ .dtor = _nvkm_engine_dtor,
+ .init = g84_cipher_init,
+ .fini = _nvkm_engine_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild
new file mode 100644
index 000000000000..de1bf092b2b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/Kbuild
@@ -0,0 +1,12 @@
+nvkm-y += nvkm/engine/device/acpi.o
+nvkm-y += nvkm/engine/device/base.o
+nvkm-y += nvkm/engine/device/ctrl.o
+nvkm-y += nvkm/engine/device/nv04.o
+nvkm-y += nvkm/engine/device/nv10.o
+nvkm-y += nvkm/engine/device/nv20.o
+nvkm-y += nvkm/engine/device/nv30.o
+nvkm-y += nvkm/engine/device/nv40.o
+nvkm-y += nvkm/engine/device/nv50.o
+nvkm-y += nvkm/engine/device/gf100.o
+nvkm-y += nvkm/engine/device/gk104.o
+nvkm-y += nvkm/engine/device/gm100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c
new file mode 100644
index 000000000000..f42706e1d5db
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "acpi.h"
+
+#include <core/device.h>
+
+#ifdef CONFIG_ACPI
+static int
+nvkm_acpi_ntfy(struct notifier_block *nb, unsigned long val, void *data)
+{
+ struct nvkm_device *device =
+ container_of(nb, typeof(*device), acpi.nb);
+ struct acpi_bus_event *info = data;
+
+ if (!strcmp(info->device_class, "ac_adapter"))
+ nvkm_event_send(&device->event, 1, 0, NULL, 0);
+
+ return NOTIFY_DONE;
+}
+#endif
+
+int
+nvkm_acpi_fini(struct nvkm_device *device, bool suspend)
+{
+#ifdef CONFIG_ACPI
+ unregister_acpi_notifier(&device->acpi.nb);
+#endif
+ return 0;
+}
+
+int
+nvkm_acpi_init(struct nvkm_device *device)
+{
+#ifdef CONFIG_ACPI
+ device->acpi.nb.notifier_call = nvkm_acpi_ntfy;
+ register_acpi_notifier(&device->acpi.nb);
+#endif
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h
new file mode 100644
index 000000000000..82dd359ddfa4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/acpi.h
@@ -0,0 +1,8 @@
+#ifndef __NVKM_DEVICE_ACPI_H__
+#define __NVKM_DEVICE_ACPI_H__
+#include <core/os.h>
+struct nvkm_device;
+
+int nvkm_acpi_init(struct nvkm_device *);
+int nvkm_acpi_fini(struct nvkm_device *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
new file mode 100644
index 000000000000..29bd539af183
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/base.c
@@ -0,0 +1,730 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "acpi.h"
+
+#include <core/client.h>
+#include <core/option.h>
+#include <core/notify.h>
+#include <core/parent.h>
+#include <subdev/bios.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static DEFINE_MUTEX(nv_devices_mutex);
+static LIST_HEAD(nv_devices);
+
+struct nvkm_device *
+nvkm_device_find(u64 name)
+{
+ struct nvkm_device *device, *match = NULL;
+ mutex_lock(&nv_devices_mutex);
+ list_for_each_entry(device, &nv_devices, head) {
+ if (device->handle == name) {
+ match = device;
+ break;
+ }
+ }
+ mutex_unlock(&nv_devices_mutex);
+ return match;
+}
+
+int
+nvkm_device_list(u64 *name, int size)
+{
+ struct nvkm_device *device;
+ int nr = 0;
+ mutex_lock(&nv_devices_mutex);
+ list_for_each_entry(device, &nv_devices, head) {
+ if (nr++ < size)
+ name[nr - 1] = device->handle;
+ }
+ mutex_unlock(&nv_devices_mutex);
+ return nr;
+}
+
+/******************************************************************************
+ * nvkm_devobj (0x0080): class implementation
+ *****************************************************************************/
+
+struct nvkm_devobj {
+ struct nvkm_parent base;
+ struct nvkm_object *subdev[NVDEV_SUBDEV_NR];
+};
+
+static int
+nvkm_devobj_info(struct nvkm_object *object, void *data, u32 size)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nvkm_fb *pfb = nvkm_fb(device);
+ struct nvkm_instmem *imem = nvkm_instmem(device);
+ union {
+ struct nv_device_info_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "device info size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "device info vers %d\n", args->v0.version);
+ } else
+ return ret;
+
+ switch (device->chipset) {
+ case 0x01a:
+ case 0x01f:
+ case 0x04c:
+ case 0x04e:
+ case 0x063:
+ case 0x067:
+ case 0x068:
+ case 0x0aa:
+ case 0x0ac:
+ case 0x0af:
+ args->v0.platform = NV_DEVICE_INFO_V0_IGP;
+ break;
+ default:
+ if (device->pdev) {
+ if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP))
+ args->v0.platform = NV_DEVICE_INFO_V0_AGP;
+ else
+ if (pci_is_pcie(device->pdev))
+ args->v0.platform = NV_DEVICE_INFO_V0_PCIE;
+ else
+ args->v0.platform = NV_DEVICE_INFO_V0_PCI;
+ } else {
+ args->v0.platform = NV_DEVICE_INFO_V0_SOC;
+ }
+ break;
+ }
+
+ switch (device->card_type) {
+ case NV_04: args->v0.family = NV_DEVICE_INFO_V0_TNT; break;
+ case NV_10:
+ case NV_11: args->v0.family = NV_DEVICE_INFO_V0_CELSIUS; break;
+ case NV_20: args->v0.family = NV_DEVICE_INFO_V0_KELVIN; break;
+ case NV_30: args->v0.family = NV_DEVICE_INFO_V0_RANKINE; break;
+ case NV_40: args->v0.family = NV_DEVICE_INFO_V0_CURIE; break;
+ case NV_50: args->v0.family = NV_DEVICE_INFO_V0_TESLA; break;
+ case NV_C0: args->v0.family = NV_DEVICE_INFO_V0_FERMI; break;
+ case NV_E0: args->v0.family = NV_DEVICE_INFO_V0_KEPLER; break;
+ case GM100: args->v0.family = NV_DEVICE_INFO_V0_MAXWELL; break;
+ default:
+ args->v0.family = 0;
+ break;
+ }
+
+ args->v0.chipset = device->chipset;
+ args->v0.revision = device->chiprev;
+ if (pfb) args->v0.ram_size = args->v0.ram_user = pfb->ram->size;
+ else args->v0.ram_size = args->v0.ram_user = 0;
+ if (imem) args->v0.ram_user = args->v0.ram_user - imem->reserved;
+ return 0;
+}
+
+static int
+nvkm_devobj_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ switch (mthd) {
+ case NV_DEVICE_V0_INFO:
+ return nvkm_devobj_info(object, data, size);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static u8
+nvkm_devobj_rd08(struct nvkm_object *object, u64 addr)
+{
+ return nv_rd08(object->engine, addr);
+}
+
+static u16
+nvkm_devobj_rd16(struct nvkm_object *object, u64 addr)
+{
+ return nv_rd16(object->engine, addr);
+}
+
+static u32
+nvkm_devobj_rd32(struct nvkm_object *object, u64 addr)
+{
+ return nv_rd32(object->engine, addr);
+}
+
+static void
+nvkm_devobj_wr08(struct nvkm_object *object, u64 addr, u8 data)
+{
+ nv_wr08(object->engine, addr, data);
+}
+
+static void
+nvkm_devobj_wr16(struct nvkm_object *object, u64 addr, u16 data)
+{
+ nv_wr16(object->engine, addr, data);
+}
+
+static void
+nvkm_devobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ nv_wr32(object->engine, addr, data);
+}
+
+static int
+nvkm_devobj_map(struct nvkm_object *object, u64 *addr, u32 *size)
+{
+ struct nvkm_device *device = nv_device(object);
+ *addr = nv_device_resource_start(device, 0);
+ *size = nv_device_resource_len(device, 0);
+ return 0;
+}
+
+static const u64 disable_map[] = {
+ [NVDEV_SUBDEV_VBIOS] = NV_DEVICE_V0_DISABLE_VBIOS,
+ [NVDEV_SUBDEV_DEVINIT] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_GPIO] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_I2C] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_CLK ] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_MXM] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_MC] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_BUS] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_TIMER] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_FB] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_LTC] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_IBUS] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_INSTMEM] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_MMU] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_BAR] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_VOLT] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_THERM] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_PMU] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_SUBDEV_FUSE] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_ENGINE_DMAOBJ] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_ENGINE_PM ] = NV_DEVICE_V0_DISABLE_CORE,
+ [NVDEV_ENGINE_FIFO] = NV_DEVICE_V0_DISABLE_FIFO,
+ [NVDEV_ENGINE_SW] = NV_DEVICE_V0_DISABLE_FIFO,
+ [NVDEV_ENGINE_GR] = NV_DEVICE_V0_DISABLE_GR,
+ [NVDEV_ENGINE_MPEG] = NV_DEVICE_V0_DISABLE_MPEG,
+ [NVDEV_ENGINE_ME] = NV_DEVICE_V0_DISABLE_ME,
+ [NVDEV_ENGINE_VP] = NV_DEVICE_V0_DISABLE_VP,
+ [NVDEV_ENGINE_CIPHER] = NV_DEVICE_V0_DISABLE_CIPHER,
+ [NVDEV_ENGINE_BSP] = NV_DEVICE_V0_DISABLE_BSP,
+ [NVDEV_ENGINE_MSPPP] = NV_DEVICE_V0_DISABLE_MSPPP,
+ [NVDEV_ENGINE_CE0] = NV_DEVICE_V0_DISABLE_CE0,
+ [NVDEV_ENGINE_CE1] = NV_DEVICE_V0_DISABLE_CE1,
+ [NVDEV_ENGINE_CE2] = NV_DEVICE_V0_DISABLE_CE2,
+ [NVDEV_ENGINE_VIC] = NV_DEVICE_V0_DISABLE_VIC,
+ [NVDEV_ENGINE_MSENC] = NV_DEVICE_V0_DISABLE_MSENC,
+ [NVDEV_ENGINE_DISP] = NV_DEVICE_V0_DISABLE_DISP,
+ [NVDEV_ENGINE_MSVLD] = NV_DEVICE_V0_DISABLE_MSVLD,
+ [NVDEV_ENGINE_SEC] = NV_DEVICE_V0_DISABLE_SEC,
+ [NVDEV_SUBDEV_NR] = 0,
+};
+
+static void
+nvkm_devobj_dtor(struct nvkm_object *object)
+{
+ struct nvkm_devobj *devobj = (void *)object;
+ int i;
+
+ for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--)
+ nvkm_object_ref(NULL, &devobj->subdev[i]);
+
+ nvkm_parent_destroy(&devobj->base);
+}
+
+static struct nvkm_oclass
+nvkm_devobj_oclass_super = {
+ .handle = NV_DEVICE,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .dtor = nvkm_devobj_dtor,
+ .init = _nvkm_parent_init,
+ .fini = _nvkm_parent_fini,
+ .mthd = nvkm_devobj_mthd,
+ .map = nvkm_devobj_map,
+ .rd08 = nvkm_devobj_rd08,
+ .rd16 = nvkm_devobj_rd16,
+ .rd32 = nvkm_devobj_rd32,
+ .wr08 = nvkm_devobj_wr08,
+ .wr16 = nvkm_devobj_wr16,
+ .wr32 = nvkm_devobj_wr32,
+ }
+};
+
+static int
+nvkm_devobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv_device_v0 v0;
+ } *args = data;
+ struct nvkm_client *client = nv_client(parent);
+ struct nvkm_device *device;
+ struct nvkm_devobj *devobj;
+ u32 boot0, strap;
+ u64 disable, mmio_base, mmio_size;
+ void __iomem *map;
+ int ret, i, c;
+
+ nv_ioctl(parent, "create device size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create device v%d device %016llx "
+ "disable %016llx debug0 %016llx\n",
+ args->v0.version, args->v0.device,
+ args->v0.disable, args->v0.debug0);
+ } else
+ return ret;
+
+ /* give priviledged clients register access */
+ if (client->super)
+ oclass = &nvkm_devobj_oclass_super;
+
+ /* find the device subdev that matches what the client requested */
+ device = nv_device(client->device);
+ if (args->v0.device != ~0) {
+ device = nvkm_device_find(args->v0.device);
+ if (!device)
+ return -ENODEV;
+ }
+
+ ret = nvkm_parent_create(parent, nv_object(device), oclass, 0,
+ nvkm_control_oclass,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_FIFO) |
+ (1ULL << NVDEV_ENGINE_DISP) |
+ (1ULL << NVDEV_ENGINE_PM), &devobj);
+ *pobject = nv_object(devobj);
+ if (ret)
+ return ret;
+
+ mmio_base = nv_device_resource_start(device, 0);
+ mmio_size = nv_device_resource_len(device, 0);
+
+ /* translate api disable mask into internal mapping */
+ disable = args->v0.debug0;
+ for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+ if (args->v0.disable & disable_map[i])
+ disable |= (1ULL << i);
+ }
+
+ /* identify the chipset, and determine classes of subdev/engines */
+ if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY) &&
+ !device->card_type) {
+ map = ioremap(mmio_base, 0x102000);
+ if (map == NULL)
+ return -ENOMEM;
+
+ /* switch mmio to cpu's native endianness */
+#ifndef __BIG_ENDIAN
+ if (ioread32_native(map + 0x000004) != 0x00000000)
+#else
+ if (ioread32_native(map + 0x000004) == 0x00000000)
+#endif
+ iowrite32_native(0x01000001, map + 0x000004);
+
+ /* read boot0 and strapping information */
+ boot0 = ioread32_native(map + 0x000000);
+ strap = ioread32_native(map + 0x101000);
+ iounmap(map);
+
+ /* determine chipset and derive architecture from it */
+ if ((boot0 & 0x1f000000) > 0) {
+ device->chipset = (boot0 & 0x1ff00000) >> 20;
+ device->chiprev = (boot0 & 0x000000ff);
+ switch (device->chipset & 0x1f0) {
+ case 0x010: {
+ if (0x461 & (1 << (device->chipset & 0xf)))
+ device->card_type = NV_10;
+ else
+ device->card_type = NV_11;
+ device->chiprev = 0x00;
+ break;
+ }
+ case 0x020: device->card_type = NV_20; break;
+ case 0x030: device->card_type = NV_30; break;
+ case 0x040:
+ case 0x060: device->card_type = NV_40; break;
+ case 0x050:
+ case 0x080:
+ case 0x090:
+ case 0x0a0: device->card_type = NV_50; break;
+ case 0x0c0:
+ case 0x0d0: device->card_type = NV_C0; break;
+ case 0x0e0:
+ case 0x0f0:
+ case 0x100: device->card_type = NV_E0; break;
+ case 0x110:
+ case 0x120: device->card_type = GM100; break;
+ default:
+ break;
+ }
+ } else
+ if ((boot0 & 0xff00fff0) == 0x20004000) {
+ if (boot0 & 0x00f00000)
+ device->chipset = 0x05;
+ else
+ device->chipset = 0x04;
+ device->card_type = NV_04;
+ }
+
+ switch (device->card_type) {
+ case NV_04: ret = nv04_identify(device); break;
+ case NV_10:
+ case NV_11: ret = nv10_identify(device); break;
+ case NV_20: ret = nv20_identify(device); break;
+ case NV_30: ret = nv30_identify(device); break;
+ case NV_40: ret = nv40_identify(device); break;
+ case NV_50: ret = nv50_identify(device); break;
+ case NV_C0: ret = gf100_identify(device); break;
+ case NV_E0: ret = gk104_identify(device); break;
+ case GM100: ret = gm100_identify(device); break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ if (ret) {
+ nv_error(device, "unknown chipset, 0x%08x\n", boot0);
+ return ret;
+ }
+
+ nv_info(device, "BOOT0 : 0x%08x\n", boot0);
+ nv_info(device, "Chipset: %s (NV%02X)\n",
+ device->cname, device->chipset);
+ nv_info(device, "Family : NV%02X\n", device->card_type);
+
+ /* determine frequency of timing crystal */
+ if ( device->card_type <= NV_10 || device->chipset < 0x17 ||
+ (device->chipset >= 0x20 && device->chipset < 0x25))
+ strap &= 0x00000040;
+ else
+ strap &= 0x00400040;
+
+ switch (strap) {
+ case 0x00000000: device->crystal = 13500; break;
+ case 0x00000040: device->crystal = 14318; break;
+ case 0x00400000: device->crystal = 27000; break;
+ case 0x00400040: device->crystal = 25000; break;
+ }
+
+ nv_debug(device, "crystal freq: %dKHz\n", device->crystal);
+ } else
+ if ( (args->v0.disable & NV_DEVICE_V0_DISABLE_IDENTIFY)) {
+ device->cname = "NULL";
+ device->oclass[NVDEV_SUBDEV_VBIOS] = &nvkm_bios_oclass;
+ }
+
+ if (!(args->v0.disable & NV_DEVICE_V0_DISABLE_MMIO) &&
+ !nv_subdev(device)->mmio) {
+ nv_subdev(device)->mmio = ioremap(mmio_base, mmio_size);
+ if (!nv_subdev(device)->mmio) {
+ nv_error(device, "unable to map device registers\n");
+ return -ENOMEM;
+ }
+ }
+
+ /* ensure requested subsystems are available for use */
+ for (i = 1, c = 1; i < NVDEV_SUBDEV_NR; i++) {
+ if (!(oclass = device->oclass[i]) || (disable & (1ULL << i)))
+ continue;
+
+ if (device->subdev[i]) {
+ nvkm_object_ref(device->subdev[i], &devobj->subdev[i]);
+ continue;
+ }
+
+ ret = nvkm_object_ctor(nv_object(device), NULL, oclass,
+ NULL, i, &devobj->subdev[i]);
+ if (ret == -ENODEV)
+ continue;
+ if (ret)
+ return ret;
+
+ device->subdev[i] = devobj->subdev[i];
+
+ /* note: can't init *any* subdevs until devinit has been run
+ * due to not knowing exactly what the vbios init tables will
+ * mess with. devinit also can't be run until all of its
+ * dependencies have been created.
+ *
+ * this code delays init of any subdev until all of devinit's
+ * dependencies have been created, and then initialises each
+ * subdev in turn as they're created.
+ */
+ while (i >= NVDEV_SUBDEV_DEVINIT_LAST && c <= i) {
+ struct nvkm_object *subdev = devobj->subdev[c++];
+ if (subdev && !nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nvkm_object_inc(subdev);
+ if (ret)
+ return ret;
+ atomic_dec(&nv_object(device)->usecount);
+ } else
+ if (subdev) {
+ nvkm_subdev_reset(subdev);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nvkm_devobj_ofuncs = {
+ .ctor = nvkm_devobj_ctor,
+ .dtor = nvkm_devobj_dtor,
+ .init = _nvkm_parent_init,
+ .fini = _nvkm_parent_fini,
+ .mthd = nvkm_devobj_mthd,
+};
+
+/******************************************************************************
+ * nvkm_device: engine functions
+ *****************************************************************************/
+
+struct nvkm_device *
+nv_device(void *obj)
+{
+ struct nvkm_object *device = nv_object(obj);
+ if (device->engine == NULL) {
+ while (device && device->parent)
+ device = device->parent;
+ } else {
+ device = &nv_object(obj)->engine->subdev.object;
+ if (device && device->parent)
+ device = device->parent;
+ }
+#if CONFIG_NOUVEAU_DEBUG >= NV_DBG_PARANOIA
+ if (unlikely(!device))
+ nv_assert("BAD CAST -> NvDevice, 0x%08x\n", nv_hclass(obj));
+#endif
+ return (void *)device;
+}
+
+static struct nvkm_oclass
+nvkm_device_sclass[] = {
+ { 0x0080, &nvkm_devobj_ofuncs },
+ {}
+};
+
+static int
+nvkm_device_event_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ if (!WARN_ON(size != 0)) {
+ notify->size = 0;
+ notify->types = 1;
+ notify->index = 0;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static const struct nvkm_event_func
+nvkm_device_event_func = {
+ .ctor = nvkm_device_event_ctor,
+};
+
+static int
+nvkm_device_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_device *device = (void *)object;
+ struct nvkm_object *subdev;
+ int ret, i;
+
+ for (i = NVDEV_SUBDEV_NR - 1; i >= 0; i--) {
+ if ((subdev = device->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nvkm_object_dec(subdev, suspend);
+ if (ret && suspend)
+ goto fail;
+ }
+ }
+ }
+
+ ret = nvkm_acpi_fini(device, suspend);
+fail:
+ for (; ret && i < NVDEV_SUBDEV_NR; i++) {
+ if ((subdev = device->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nvkm_object_inc(subdev);
+ if (ret) {
+ /* XXX */
+ }
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int
+nvkm_device_init(struct nvkm_object *object)
+{
+ struct nvkm_device *device = (void *)object;
+ struct nvkm_object *subdev;
+ int ret, i = 0;
+
+ ret = nvkm_acpi_init(device);
+ if (ret)
+ goto fail;
+
+ for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+ if ((subdev = device->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS)) {
+ ret = nvkm_object_inc(subdev);
+ if (ret)
+ goto fail;
+ } else {
+ nvkm_subdev_reset(subdev);
+ }
+ }
+ }
+
+ ret = 0;
+fail:
+ for (--i; ret && i >= 0; i--) {
+ if ((subdev = device->subdev[i])) {
+ if (!nv_iclass(subdev, NV_ENGINE_CLASS))
+ nvkm_object_dec(subdev, false);
+ }
+ }
+
+ if (ret)
+ nvkm_acpi_fini(device, false);
+ return ret;
+}
+
+static void
+nvkm_device_dtor(struct nvkm_object *object)
+{
+ struct nvkm_device *device = (void *)object;
+
+ nvkm_event_fini(&device->event);
+
+ mutex_lock(&nv_devices_mutex);
+ list_del(&device->head);
+ mutex_unlock(&nv_devices_mutex);
+
+ if (nv_subdev(device)->mmio)
+ iounmap(nv_subdev(device)->mmio);
+
+ nvkm_engine_destroy(&device->engine);
+}
+
+resource_size_t
+nv_device_resource_start(struct nvkm_device *device, unsigned int bar)
+{
+ if (nv_device_is_pci(device)) {
+ return pci_resource_start(device->pdev, bar);
+ } else {
+ struct resource *res;
+ res = platform_get_resource(device->platformdev,
+ IORESOURCE_MEM, bar);
+ if (!res)
+ return 0;
+ return res->start;
+ }
+}
+
+resource_size_t
+nv_device_resource_len(struct nvkm_device *device, unsigned int bar)
+{
+ if (nv_device_is_pci(device)) {
+ return pci_resource_len(device->pdev, bar);
+ } else {
+ struct resource *res;
+ res = platform_get_resource(device->platformdev,
+ IORESOURCE_MEM, bar);
+ if (!res)
+ return 0;
+ return resource_size(res);
+ }
+}
+
+int
+nv_device_get_irq(struct nvkm_device *device, bool stall)
+{
+ if (nv_device_is_pci(device)) {
+ return device->pdev->irq;
+ } else {
+ return platform_get_irq_byname(device->platformdev,
+ stall ? "stall" : "nonstall");
+ }
+}
+
+static struct nvkm_oclass
+nvkm_device_oclass = {
+ .handle = NV_ENGINE(DEVICE, 0x00),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .dtor = nvkm_device_dtor,
+ .init = nvkm_device_init,
+ .fini = nvkm_device_fini,
+ },
+};
+
+int
+nvkm_device_create_(void *dev, enum nv_bus_type type, u64 name,
+ const char *sname, const char *cfg, const char *dbg,
+ int length, void **pobject)
+{
+ struct nvkm_device *device;
+ int ret = -EEXIST;
+
+ mutex_lock(&nv_devices_mutex);
+ list_for_each_entry(device, &nv_devices, head) {
+ if (device->handle == name)
+ goto done;
+ }
+
+ ret = nvkm_engine_create_(NULL, NULL, &nvkm_device_oclass, true,
+ "DEVICE", "device", length, pobject);
+ device = *pobject;
+ if (ret)
+ goto done;
+
+ switch (type) {
+ case NVKM_BUS_PCI:
+ device->pdev = dev;
+ break;
+ case NVKM_BUS_PLATFORM:
+ device->platformdev = dev;
+ break;
+ }
+ device->handle = name;
+ device->cfgopt = cfg;
+ device->dbgopt = dbg;
+ device->name = sname;
+
+ nv_subdev(device)->debug = nvkm_dbgopt(device->dbgopt, "DEVICE");
+ nv_engine(device)->sclass = nvkm_device_sclass;
+ list_add(&device->head, &nv_devices);
+
+ ret = nvkm_event_init(&nvkm_device_event_func, 1, 1, &device->event);
+done:
+ mutex_unlock(&nv_devices_mutex);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
new file mode 100644
index 000000000000..0b794b13cec3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/ctrl.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <subdev/clk.h>
+
+#include <nvif/class.h>
+#include <nvif/ioctl.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_control_mthd_pstate_info(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nvif_control_pstate_info_v0 v0;
+ } *args = data;
+ struct nvkm_clk *clk = nvkm_clk(object);
+ int ret;
+
+ nv_ioctl(object, "control pstate info size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "control pstate info vers %d\n",
+ args->v0.version);
+ } else
+ return ret;
+
+ if (clk) {
+ args->v0.count = clk->state_nr;
+ args->v0.ustate_ac = clk->ustate_ac;
+ args->v0.ustate_dc = clk->ustate_dc;
+ args->v0.pwrsrc = clk->pwrsrc;
+ args->v0.pstate = clk->pstate;
+ } else {
+ args->v0.count = 0;
+ args->v0.ustate_ac = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
+ args->v0.ustate_dc = NVIF_CONTROL_PSTATE_INFO_V0_USTATE_DISABLE;
+ args->v0.pwrsrc = -ENOSYS;
+ args->v0.pstate = NVIF_CONTROL_PSTATE_INFO_V0_PSTATE_UNKNOWN;
+ }
+
+ return 0;
+}
+
+static int
+nvkm_control_mthd_pstate_attr(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nvif_control_pstate_attr_v0 v0;
+ } *args = data;
+ struct nvkm_clk *clk = nvkm_clk(object);
+ struct nvkm_domain *domain;
+ struct nvkm_pstate *pstate;
+ struct nvkm_cstate *cstate;
+ int i = 0, j = -1;
+ u32 lo, hi;
+ int ret;
+
+ nv_ioctl(object, "control pstate attr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "control pstate attr vers %d state %d "
+ "index %d\n",
+ args->v0.version, args->v0.state, args->v0.index);
+ if (!clk)
+ return -ENODEV;
+ if (args->v0.state < NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT)
+ return -EINVAL;
+ if (args->v0.state >= clk->state_nr)
+ return -EINVAL;
+ } else
+ return ret;
+ domain = clk->domains;
+
+ while (domain->name != nv_clk_src_max) {
+ if (domain->mname && ++j == args->v0.index)
+ break;
+ domain++;
+ }
+
+ if (domain->name == nv_clk_src_max)
+ return -EINVAL;
+
+ if (args->v0.state != NVIF_CONTROL_PSTATE_ATTR_V0_STATE_CURRENT) {
+ list_for_each_entry(pstate, &clk->states, head) {
+ if (i++ == args->v0.state)
+ break;
+ }
+
+ lo = pstate->base.domain[domain->name];
+ hi = lo;
+ list_for_each_entry(cstate, &pstate->list, head) {
+ lo = min(lo, cstate->domain[domain->name]);
+ hi = max(hi, cstate->domain[domain->name]);
+ }
+
+ args->v0.state = pstate->pstate;
+ } else {
+ lo = max(clk->read(clk, domain->name), 0);
+ hi = lo;
+ }
+
+ snprintf(args->v0.name, sizeof(args->v0.name), "%s", domain->mname);
+ snprintf(args->v0.unit, sizeof(args->v0.unit), "MHz");
+ args->v0.min = lo / domain->mdiv;
+ args->v0.max = hi / domain->mdiv;
+
+ args->v0.index = 0;
+ while ((++domain)->name != nv_clk_src_max) {
+ if (domain->mname) {
+ args->v0.index = ++j;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int
+nvkm_control_mthd_pstate_user(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nvif_control_pstate_user_v0 v0;
+ } *args = data;
+ struct nvkm_clk *clk = nvkm_clk(object);
+ int ret;
+
+ nv_ioctl(object, "control pstate user size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "control pstate user vers %d ustate %d "
+ "pwrsrc %d\n", args->v0.version,
+ args->v0.ustate, args->v0.pwrsrc);
+ if (!clk)
+ return -ENODEV;
+ } else
+ return ret;
+
+ if (args->v0.pwrsrc >= 0) {
+ ret |= nvkm_clk_ustate(clk, args->v0.ustate, args->v0.pwrsrc);
+ } else {
+ ret |= nvkm_clk_ustate(clk, args->v0.ustate, 0);
+ ret |= nvkm_clk_ustate(clk, args->v0.ustate, 1);
+ }
+
+ return ret;
+}
+
+static int
+nvkm_control_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ switch (mthd) {
+ case NVIF_CONTROL_PSTATE_INFO:
+ return nvkm_control_mthd_pstate_info(object, data, size);
+ case NVIF_CONTROL_PSTATE_ATTR:
+ return nvkm_control_mthd_pstate_attr(object, data, size);
+ case NVIF_CONTROL_PSTATE_USER:
+ return nvkm_control_mthd_pstate_user(object, data, size);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static struct nvkm_ofuncs
+nvkm_control_ofuncs = {
+ .ctor = _nvkm_object_ctor,
+ .dtor = nvkm_object_destroy,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ .mthd = nvkm_control_mthd,
+};
+
+struct nvkm_oclass
+nvkm_control_oclass[] = {
+ { .handle = NVIF_IOCTL_NEW_V0_CONTROL,
+ .ofuncs = &nvkm_control_ofuncs
+ },
+ {}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
new file mode 100644
index 000000000000..82b38d7e9730
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gf100.c
@@ -0,0 +1,358 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mspdec.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/msppp.h>
+#include <engine/ce.h>
+#include <engine/disp.h>
+#include <engine/pm.h>
+
+int
+gf100_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0xc0:
+ device->cname = "GF100";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf100_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xc4:
+ device->cname = "GF104";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xc3:
+ device->cname = "GF106";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xce:
+ device->cname = "GF114";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xcf:
+ device->cname = "GF116";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xc1:
+ device->cname = "GF108";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf108_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xc8:
+ device->cname = "GF110";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf100_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf100_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf100_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf110_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gf100_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xd9:
+ device->cname = "GF119";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf119_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ case 0xd7:
+ device->cname = "GF117";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gf110_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gf117_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gf100_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gf100_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gf100_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gf100_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gf100_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gf117_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gf100_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gf100_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gf100_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gf110_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gf100_pm_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Fermi chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
new file mode 100644
index 000000000000..bf5893458a47
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gk104.c
@@ -0,0 +1,326 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+#include <engine/ce.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/mspdec.h>
+#include <engine/msppp.h>
+#include <engine/pm.h>
+
+int
+gk104_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0xe4:
+ device->cname = "GK104";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass;
+ break;
+ case 0xe7:
+ device->cname = "GK107";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass;
+ break;
+ case 0xe6:
+ device->cname = "GK106";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk104_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk104_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk104_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass;
+ break;
+ case 0xea:
+ device->cname = "GK20A";
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk20a_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk20a_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk20a_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gk20a_bar_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk20a_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk20a_gr_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gk104_pm_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &gk20a_volt_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk20a_pmu_oclass;
+ break;
+ case 0xf0:
+ device->cname = "GK110";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk110_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass;
+ break;
+ case 0xf1:
+ device->cname = "GK110B";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gf106_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gf110_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk104_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk110b_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = &gk110_pm_oclass;
+ break;
+ case 0x106:
+ device->cname = "GK208B";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ break;
+ case 0x108:
+ device->cname = "GK208";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gk104_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gf100_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gf110_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gf100_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gk104_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gk104_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gk208_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gk110_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Kepler chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
new file mode 100644
index 000000000000..539561ed3281
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/gm100.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/ibus.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+#include <engine/ce.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/mspdec.h>
+#include <engine/msppp.h>
+#include <engine/pm.h>
+
+int
+gm100_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x117:
+ device->cname = "GM107";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gf110_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gm107_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass;
+
+#if 0
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+#endif
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gm107_disp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gk104_ce0_oclass;
+#if 0
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gk104_ce1_oclass;
+#endif
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gk104_ce2_oclass;
+#if 0
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+#endif
+ break;
+ case 0x124:
+ device->cname = "GM204";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = gk104_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = gm204_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &gm107_fuse_oclass;
+#if 0
+ /* looks to be some non-trivial changes */
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gk104_clk_oclass;
+ /* priv ring says no to 0x10eb14 writes */
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gm107_therm_oclass;
+#endif
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gm204_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = gk20a_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = gf100_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &gk20a_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gm107_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_LTC ] = gm107_ltc_oclass;
+ device->oclass[NVDEV_SUBDEV_IBUS ] = &gk104_ibus_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &gf100_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &gf100_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gk208_pmu_oclass;
+#if 0
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+#endif
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = gf110_dmaeng_oclass;
+#if 0
+ device->oclass[NVDEV_ENGINE_FIFO ] = gk208_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = gf100_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = gm107_gr_oclass;
+#endif
+ device->oclass[NVDEV_ENGINE_DISP ] = gm204_disp_oclass;
+#if 0
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gm204_ce0_oclass;
+ device->oclass[NVDEV_ENGINE_CE1 ] = &gm204_ce1_oclass;
+ device->oclass[NVDEV_ENGINE_CE2 ] = &gm204_ce2_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &gk104_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &gk104_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &gf100_msppp_oclass;
+#endif
+ break;
+ default:
+ nv_fatal(device, "unknown Maxwell chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
new file mode 100644
index 000000000000..5a2ae043b478
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv04.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+
+int
+nv04_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x04:
+ device->cname = "NV04";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv04_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x05:
+ device->cname = "NV05";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv05_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv04_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv04_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv04_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv04_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown RIVA chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
new file mode 100644
index 000000000000..94a1ca45e94a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv10.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+
+int
+nv10_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x10:
+ device->cname = "NV10";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x15:
+ device->cname = "NV15";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x16:
+ device->cname = "NV16";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x1a:
+ device->cname = "nForce";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x11:
+ device->cname = "NV11";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv10_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x17:
+ device->cname = "NV17";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x1f:
+ device->cname = "nForce2";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv1a_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x18:
+ device->cname = "NV18";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv10_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Celsius chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
new file mode 100644
index 000000000000..d5ec8937df68
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv20.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/disp.h>
+
+int
+nv20_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x20:
+ device->cname = "NV20";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv20_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv20_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x25:
+ device->cname = "NV25";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x28:
+ device->cname = "NV28";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv25_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x2a:
+ device->cname = "NV2A";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv25_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv2a_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Kelvin chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
new file mode 100644
index 000000000000..dda09621e898
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv30.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mpeg.h>
+#include <engine/disp.h>
+
+int
+nv30_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x30:
+ device->cname = "NV30";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x35:
+ device->cname = "NV35";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv04_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv35_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x31:
+ device->cname = "NV31";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv30_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv30_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x36:
+ device->cname = "NV36";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv20_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv36_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv35_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ case 0x34:
+ device->cname = "NV34";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv04_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv10_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv04_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv10_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv04_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv17_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv34_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv31_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Rankine chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
new file mode 100644
index 000000000000..c6301361d14f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv40.c
@@ -0,0 +1,427 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/mmu.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mpeg.h>
+#include <engine/disp.h>
+#include <engine/pm.h>
+
+int
+nv40_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x40:
+ device->cname = "NV40";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x41:
+ device->cname = "NV41";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x42:
+ device->cname = "NV42";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x43:
+ device->cname = "NV43";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv41_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv40_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x45:
+ device->cname = "NV45";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv40_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv04_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x47:
+ device->cname = "G70";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv47_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x49:
+ device->cname = "G71";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x4b:
+ device->cname = "G73";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv40_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv49_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv41_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x44:
+ device->cname = "NV44";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x46:
+ device->cname = "G72";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x4a:
+ device->cname = "NV44A";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv44_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv44_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x4c:
+ device->cname = "C61";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x4e:
+ device->cname = "C51";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv4e_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv4e_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x63:
+ device->cname = "C73";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x67:
+ device->cname = "C67";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ case 0x68:
+ device->cname = "C68";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv10_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv04_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &nv40_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv40_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv1a_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv4c_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv31_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv46_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv40_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv44_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv04_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv40_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv10_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv40_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv44_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv04_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv40_pm_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Curie chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
new file mode 100644
index 000000000000..249b84454612
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/nv50.c
@@ -0,0 +1,478 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bus.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/fuse.h>
+#include <subdev/clk.h>
+#include <subdev/therm.h>
+#include <subdev/mxm.h>
+#include <subdev/devinit.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/pmu.h>
+#include <subdev/volt.h>
+
+#include <engine/dmaobj.h>
+#include <engine/fifo.h>
+#include <engine/sw.h>
+#include <engine/gr.h>
+#include <engine/mpeg.h>
+#include <engine/vp.h>
+#include <engine/cipher.h>
+#include <engine/sec.h>
+#include <engine/bsp.h>
+#include <engine/msvld.h>
+#include <engine/mspdec.h>
+#include <engine/msppp.h>
+#include <engine/ce.h>
+#include <engine/disp.h>
+#include <engine/pm.h>
+
+int
+nv50_identify(struct nvkm_device *device)
+{
+ switch (device->chipset) {
+ case 0x50:
+ device->cname = "G80";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = nv50_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &nv50_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = nv50_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = nv50_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = nv50_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &nv50_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = nv50_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = nv50_pm_oclass;
+ break;
+ case 0x84:
+ device->cname = "G84";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0x86:
+ device->cname = "G86";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0x92:
+ device->cname = "G92";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = nv50_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = nv50_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = nv50_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g84_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0x94:
+ device->cname = "G94";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0x96:
+ device->cname = "G96";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g94_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0x98:
+ device->cname = "G98";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0xa0:
+ device->cname = "G200";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = nv50_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = g84_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g84_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = g84_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_VP ] = &g84_vp_oclass;
+ device->oclass[NVDEV_ENGINE_CIPHER ] = &g84_cipher_oclass;
+ device->oclass[NVDEV_ENGINE_BSP ] = &g84_bsp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt200_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0xaa:
+ device->cname = "MCP77/MCP78";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0xac:
+ device->cname = "MCP79/MCP7A";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = mcp77_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &g84_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = g98_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = mcp77_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_SEC ] = &g98_sec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = g94_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = g84_pm_oclass;
+ break;
+ case 0xa3:
+ device->cname = "GT215";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gt215_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MPEG ] = &g84_mpeg_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gt215_ce_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass;
+ break;
+ case 0xa5:
+ device->cname = "GT216";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gt215_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gt215_ce_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass;
+ break;
+ case 0xa8:
+ device->cname = "GT218";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gt215_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = gt215_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = gt215_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gt215_ce_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass;
+ break;
+ case 0xaf:
+ device->cname = "MCP89";
+ device->oclass[NVDEV_SUBDEV_VBIOS ] = &nvkm_bios_oclass;
+ device->oclass[NVDEV_SUBDEV_GPIO ] = g94_gpio_oclass;
+ device->oclass[NVDEV_SUBDEV_I2C ] = g94_i2c_oclass;
+ device->oclass[NVDEV_SUBDEV_FUSE ] = &nv50_fuse_oclass;
+ device->oclass[NVDEV_SUBDEV_CLK ] = &gt215_clk_oclass;
+ device->oclass[NVDEV_SUBDEV_THERM ] = &gt215_therm_oclass;
+ device->oclass[NVDEV_SUBDEV_MXM ] = &nv50_mxm_oclass;
+ device->oclass[NVDEV_SUBDEV_DEVINIT] = mcp89_devinit_oclass;
+ device->oclass[NVDEV_SUBDEV_MC ] = g98_mc_oclass;
+ device->oclass[NVDEV_SUBDEV_BUS ] = g94_bus_oclass;
+ device->oclass[NVDEV_SUBDEV_TIMER ] = &nv04_timer_oclass;
+ device->oclass[NVDEV_SUBDEV_FB ] = mcp89_fb_oclass;
+ device->oclass[NVDEV_SUBDEV_INSTMEM] = nv50_instmem_oclass;
+ device->oclass[NVDEV_SUBDEV_MMU ] = &nv50_mmu_oclass;
+ device->oclass[NVDEV_SUBDEV_BAR ] = &nv50_bar_oclass;
+ device->oclass[NVDEV_SUBDEV_PMU ] = gt215_pmu_oclass;
+ device->oclass[NVDEV_SUBDEV_VOLT ] = &nv40_volt_oclass;
+ device->oclass[NVDEV_ENGINE_DMAOBJ ] = nv50_dmaeng_oclass;
+ device->oclass[NVDEV_ENGINE_FIFO ] = g84_fifo_oclass;
+ device->oclass[NVDEV_ENGINE_SW ] = nv50_sw_oclass;
+ device->oclass[NVDEV_ENGINE_GR ] = &nv50_gr_oclass;
+ device->oclass[NVDEV_ENGINE_MSPDEC ] = &g98_mspdec_oclass;
+ device->oclass[NVDEV_ENGINE_MSVLD ] = &g98_msvld_oclass;
+ device->oclass[NVDEV_ENGINE_MSPPP ] = &g98_msppp_oclass;
+ device->oclass[NVDEV_ENGINE_CE0 ] = &gt215_ce_oclass;
+ device->oclass[NVDEV_ENGINE_DISP ] = gt215_disp_oclass;
+ device->oclass[NVDEV_ENGINE_PM ] = gt215_pm_oclass;
+ break;
+ default:
+ nv_fatal(device, "unknown Tesla chipset\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
new file mode 100644
index 000000000000..8d3590e7bd87
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/device/priv.h
@@ -0,0 +1,16 @@
+#ifndef __NVKM_DEVICE_PRIV_H__
+#define __NVKM_DEVICE_PRIV_H__
+#include <core/device.h>
+
+extern struct nvkm_oclass nvkm_control_oclass[];
+
+int nv04_identify(struct nvkm_device *);
+int nv10_identify(struct nvkm_device *);
+int nv20_identify(struct nvkm_device *);
+int nv30_identify(struct nvkm_device *);
+int nv40_identify(struct nvkm_device *);
+int nv50_identify(struct nvkm_device *);
+int gf100_identify(struct nvkm_device *);
+int gk104_identify(struct nvkm_device *);
+int gm100_identify(struct nvkm_device *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
new file mode 100644
index 000000000000..16a4e2a37008
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/Kbuild
@@ -0,0 +1,29 @@
+nvkm-y += nvkm/engine/disp/base.o
+nvkm-y += nvkm/engine/disp/conn.o
+nvkm-y += nvkm/engine/disp/outp.o
+nvkm-y += nvkm/engine/disp/outpdp.o
+nvkm-y += nvkm/engine/disp/nv04.o
+nvkm-y += nvkm/engine/disp/nv50.o
+nvkm-y += nvkm/engine/disp/g84.o
+nvkm-y += nvkm/engine/disp/g94.o
+nvkm-y += nvkm/engine/disp/gt200.o
+nvkm-y += nvkm/engine/disp/gt215.o
+nvkm-y += nvkm/engine/disp/gf110.o
+nvkm-y += nvkm/engine/disp/gk104.o
+nvkm-y += nvkm/engine/disp/gk110.o
+nvkm-y += nvkm/engine/disp/gm107.o
+nvkm-y += nvkm/engine/disp/gm204.o
+nvkm-y += nvkm/engine/disp/dacnv50.o
+nvkm-y += nvkm/engine/disp/dport.o
+nvkm-y += nvkm/engine/disp/hdagt215.o
+nvkm-y += nvkm/engine/disp/hdagf110.o
+nvkm-y += nvkm/engine/disp/hdmig84.o
+nvkm-y += nvkm/engine/disp/hdmigt215.o
+nvkm-y += nvkm/engine/disp/hdmigf110.o
+nvkm-y += nvkm/engine/disp/hdmigk104.o
+nvkm-y += nvkm/engine/disp/piornv50.o
+nvkm-y += nvkm/engine/disp/sornv50.o
+nvkm-y += nvkm/engine/disp/sorg94.o
+nvkm-y += nvkm/engine/disp/sorgf110.o
+nvkm-y += nvkm/engine/disp/sorgm204.o
+nvkm-y += nvkm/engine/disp/vga.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
new file mode 100644
index 000000000000..23d1b5c0dc16
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/base.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "conn.h"
+#include "outp.h"
+
+#include <core/notify.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+int
+nvkm_disp_vblank_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ struct nvkm_disp *disp =
+ container_of(notify->event, typeof(*disp), vblank);
+ union {
+ struct nvif_notify_head_req_v0 v0;
+ } *req = data;
+ int ret;
+
+ if (nvif_unpack(req->v0, 0, 0, false)) {
+ notify->size = sizeof(struct nvif_notify_head_rep_v0);
+ if (ret = -ENXIO, req->v0.head <= disp->vblank.index_nr) {
+ notify->types = 1;
+ notify->index = req->v0.head;
+ return 0;
+ }
+ }
+
+ return ret;
+}
+
+void
+nvkm_disp_vblank(struct nvkm_disp *disp, int head)
+{
+ struct nvif_notify_head_rep_v0 rep = {};
+ nvkm_event_send(&disp->vblank, 1, head, &rep, sizeof(rep));
+}
+
+static int
+nvkm_disp_hpd_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ struct nvkm_disp *disp =
+ container_of(notify->event, typeof(*disp), hpd);
+ union {
+ struct nvif_notify_conn_req_v0 v0;
+ } *req = data;
+ struct nvkm_output *outp;
+ int ret;
+
+ if (nvif_unpack(req->v0, 0, 0, false)) {
+ notify->size = sizeof(struct nvif_notify_conn_rep_v0);
+ list_for_each_entry(outp, &disp->outp, head) {
+ if (ret = -ENXIO, outp->conn->index == req->v0.conn) {
+ if (ret = -ENODEV, outp->conn->hpd.event) {
+ notify->types = req->v0.mask;
+ notify->index = req->v0.conn;
+ ret = 0;
+ }
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static const struct nvkm_event_func
+nvkm_disp_hpd_func = {
+ .ctor = nvkm_disp_hpd_ctor
+};
+
+int
+nvkm_disp_ntfy(struct nvkm_object *object, u32 type, struct nvkm_event **event)
+{
+ struct nvkm_disp *disp = (void *)object->engine;
+ switch (type) {
+ case NV04_DISP_NTFY_VBLANK:
+ *event = &disp->vblank;
+ return 0;
+ case NV04_DISP_NTFY_CONN:
+ *event = &disp->hpd;
+ return 0;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+int
+_nvkm_disp_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_disp *disp = (void *)object;
+ struct nvkm_output *outp;
+ int ret;
+
+ list_for_each_entry(outp, &disp->outp, head) {
+ ret = nv_ofuncs(outp)->fini(nv_object(outp), suspend);
+ if (ret && suspend)
+ goto fail_outp;
+ }
+
+ return nvkm_engine_fini(&disp->base, suspend);
+
+fail_outp:
+ list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
+ nv_ofuncs(outp)->init(nv_object(outp));
+ }
+
+ return ret;
+}
+
+int
+_nvkm_disp_init(struct nvkm_object *object)
+{
+ struct nvkm_disp *disp = (void *)object;
+ struct nvkm_output *outp;
+ int ret;
+
+ ret = nvkm_engine_init(&disp->base);
+ if (ret)
+ return ret;
+
+ list_for_each_entry(outp, &disp->outp, head) {
+ ret = nv_ofuncs(outp)->init(nv_object(outp));
+ if (ret)
+ goto fail_outp;
+ }
+
+ return ret;
+
+fail_outp:
+ list_for_each_entry_continue_reverse(outp, &disp->outp, head) {
+ nv_ofuncs(outp)->fini(nv_object(outp), false);
+ }
+
+ return ret;
+}
+
+void
+_nvkm_disp_dtor(struct nvkm_object *object)
+{
+ struct nvkm_disp *disp = (void *)object;
+ struct nvkm_output *outp, *outt;
+
+ nvkm_event_fini(&disp->vblank);
+ nvkm_event_fini(&disp->hpd);
+
+ if (disp->outp.next) {
+ list_for_each_entry_safe(outp, outt, &disp->outp, head) {
+ nvkm_object_ref(NULL, (struct nvkm_object **)&outp);
+ }
+ }
+
+ nvkm_engine_destroy(&disp->base);
+}
+
+int
+nvkm_disp_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int heads, const char *intname,
+ const char *extname, int length, void **pobject)
+{
+ struct nvkm_disp_impl *impl = (void *)oclass;
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct nvkm_disp *disp;
+ struct nvkm_oclass **sclass;
+ struct nvkm_object *object;
+ struct dcb_output dcbE;
+ u8 hpd = 0, ver, hdr;
+ u32 data;
+ int ret, i;
+
+ ret = nvkm_engine_create_(parent, engine, oclass, true, intname,
+ extname, length, pobject);
+ disp = *pobject;
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&disp->outp);
+
+ /* create output objects for each display path in the vbios */
+ i = -1;
+ while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &dcbE))) {
+ if (dcbE.type == DCB_OUTPUT_UNUSED)
+ continue;
+ if (dcbE.type == DCB_OUTPUT_EOL)
+ break;
+ data = dcbE.location << 4 | dcbE.type;
+
+ oclass = nvkm_output_oclass;
+ sclass = impl->outp;
+ while (sclass && sclass[0]) {
+ if (sclass[0]->handle == data) {
+ oclass = sclass[0];
+ break;
+ }
+ sclass++;
+ }
+
+ nvkm_object_ctor(*pobject, NULL, oclass, &dcbE, i, &object);
+ hpd = max(hpd, (u8)(dcbE.connector + 1));
+ }
+
+ ret = nvkm_event_init(&nvkm_disp_hpd_func, 3, hpd, &disp->hpd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(impl->vblank, 1, heads, &disp->vblank);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
new file mode 100644
index 000000000000..cf03e0240ced
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "conn.h"
+#include "outp.h"
+#include "priv.h"
+
+#include <subdev/gpio.h>
+
+#include <nvif/event.h>
+
+static int
+nvkm_connector_hpd(struct nvkm_notify *notify)
+{
+ struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
+ struct nvkm_disp *disp = nvkm_disp(conn);
+ struct nvkm_gpio *gpio = nvkm_gpio(conn);
+ const struct nvkm_gpio_ntfy_rep *line = notify->data;
+ struct nvif_notify_conn_rep_v0 rep;
+ int index = conn->index;
+
+ DBG("HPD: %d\n", line->mask);
+
+ if (!gpio->get(gpio, 0, DCB_GPIO_UNUSED, conn->hpd.index))
+ rep.mask = NVIF_NOTIFY_CONN_V0_UNPLUG;
+ else
+ rep.mask = NVIF_NOTIFY_CONN_V0_PLUG;
+ rep.version = 0;
+
+ nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+ return NVKM_NOTIFY_KEEP;
+}
+
+int
+_nvkm_connector_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_connector *conn = (void *)object;
+ nvkm_notify_put(&conn->hpd);
+ return nvkm_object_fini(&conn->base, suspend);
+}
+
+int
+_nvkm_connector_init(struct nvkm_object *object)
+{
+ struct nvkm_connector *conn = (void *)object;
+ int ret = nvkm_object_init(&conn->base);
+ if (ret == 0)
+ nvkm_notify_get(&conn->hpd);
+ return ret;
+}
+
+void
+_nvkm_connector_dtor(struct nvkm_object *object)
+{
+ struct nvkm_connector *conn = (void *)object;
+ nvkm_notify_fini(&conn->hpd);
+ nvkm_object_destroy(&conn->base);
+}
+
+int
+nvkm_connector_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass,
+ struct nvbios_connE *info, int index,
+ int length, void **pobject)
+{
+ static const u8 hpd[] = { 0x07, 0x08, 0x51, 0x52, 0x5e, 0x5f, 0x60 };
+ struct nvkm_disp *disp = nvkm_disp(parent);
+ struct nvkm_gpio *gpio = nvkm_gpio(parent);
+ struct nvkm_connector *conn;
+ struct nvkm_output *outp;
+ struct dcb_gpio_func func;
+ int ret;
+
+ list_for_each_entry(outp, &disp->outp, head) {
+ if (outp->conn && outp->conn->index == index) {
+ atomic_inc(&nv_object(outp->conn)->refcount);
+ *pobject = outp->conn;
+ return 1;
+ }
+ }
+
+ ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
+ conn = *pobject;
+ if (ret)
+ return ret;
+
+ conn->info = *info;
+ conn->index = index;
+
+ DBG("type %02x loc %d hpd %02x dp %x di %x sr %x lcdid %x\n",
+ info->type, info->location, info->hpd, info->dp,
+ info->di, info->sr, info->lcdid);
+
+ if ((info->hpd = ffs(info->hpd))) {
+ if (--info->hpd >= ARRAY_SIZE(hpd)) {
+ ERR("hpd %02x unknown\n", info->hpd);
+ return 0;
+ }
+ info->hpd = hpd[info->hpd];
+
+ ret = gpio->find(gpio, 0, info->hpd, DCB_GPIO_UNUSED, &func);
+ if (ret) {
+ ERR("func %02x lookup failed, %d\n", info->hpd, ret);
+ return 0;
+ }
+
+ ret = nvkm_notify_init(NULL, &gpio->event, nvkm_connector_hpd,
+ true, &(struct nvkm_gpio_ntfy_req) {
+ .mask = NVKM_GPIO_TOGGLED,
+ .line = func.line,
+ },
+ sizeof(struct nvkm_gpio_ntfy_req),
+ sizeof(struct nvkm_gpio_ntfy_rep),
+ &conn->hpd);
+ if (ret) {
+ ERR("func %02x failed, %d\n", info->hpd, ret);
+ } else {
+ DBG("func %02x (HPD)\n", info->hpd);
+ }
+ }
+
+ return 0;
+}
+
+int
+_nvkm_connector_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *info, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_connector *conn;
+ int ret;
+
+ ret = nvkm_connector_create(parent, engine, oclass, info, index, &conn);
+ *pobject = nv_object(conn);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nvkm_connector_oclass = &(struct nvkm_connector_impl) {
+ .base = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_connector_ctor,
+ .dtor = _nvkm_connector_dtor,
+ .init = _nvkm_connector_init,
+ .fini = _nvkm_connector_fini,
+ },
+ },
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
new file mode 100644
index 000000000000..c87a061f7f7d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/conn.h
@@ -0,0 +1,58 @@
+#ifndef __NVKM_DISP_CONN_H__
+#define __NVKM_DISP_CONN_H__
+#include <core/object.h>
+#include <core/notify.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+
+struct nvkm_connector {
+ struct nvkm_object base;
+ struct list_head head;
+
+ struct nvbios_connE info;
+ int index;
+
+ struct nvkm_notify hpd;
+};
+
+#define nvkm_connector_create(p,e,c,b,i,d) \
+ nvkm_connector_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
+#define nvkm_connector_destroy(d) ({ \
+ struct nvkm_connector *disp = (d); \
+ _nvkm_connector_dtor(nv_object(disp)); \
+})
+#define nvkm_connector_init(d) ({ \
+ struct nvkm_connector *disp = (d); \
+ _nvkm_connector_init(nv_object(disp)); \
+})
+#define nvkm_connector_fini(d,s) ({ \
+ struct nvkm_connector *disp = (d); \
+ _nvkm_connector_fini(nv_object(disp), (s)); \
+})
+
+int nvkm_connector_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, struct nvbios_connE *,
+ int, int, void **);
+
+int _nvkm_connector_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void _nvkm_connector_dtor(struct nvkm_object *);
+int _nvkm_connector_init(struct nvkm_object *);
+int _nvkm_connector_fini(struct nvkm_object *, bool);
+
+struct nvkm_connector_impl {
+ struct nvkm_oclass base;
+};
+
+#ifndef MSG
+#define MSG(l,f,a...) do { \
+ struct nvkm_connector *_conn = (void *)conn; \
+ nv_##l(_conn, "%02x:%02x%02x: "f, _conn->index, \
+ _conn->info.location, _conn->info.type, ##a); \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
new file mode 100644
index 000000000000..0f7d1ec4d37e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dacnv50.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+nv50_dac_power(NV50_DISP_MTHD_V1)
+{
+ const u32 doff = outp->or * 0x800;
+ union {
+ struct nv50_disp_dac_pwr_v0 v0;
+ } *args = data;
+ u32 stat;
+ int ret;
+
+ nv_ioctl(object, "disp dac pwr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp dac pwr vers %d state %d data %d "
+ "vsync %d hsync %d\n",
+ args->v0.version, args->v0.state, args->v0.data,
+ args->v0.vsync, args->v0.hsync);
+ stat = 0x00000040 * !args->v0.state;
+ stat |= 0x00000010 * !args->v0.data;
+ stat |= 0x00000004 * !args->v0.vsync;
+ stat |= 0x00000001 * !args->v0.hsync;
+ } else
+ return ret;
+
+ nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+ nv_mask(priv, 0x61a004 + doff, 0xc000007f, 0x80000000 | stat);
+ nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+ return 0;
+}
+
+int
+nv50_dac_sense(NV50_DISP_MTHD_V1)
+{
+ union {
+ struct nv50_disp_dac_load_v0 v0;
+ } *args = data;
+ const u32 doff = outp->or * 0x800;
+ u32 loadval;
+ int ret;
+
+ nv_ioctl(object, "disp dac load size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp dac load vers %d data %08x\n",
+ args->v0.version, args->v0.data);
+ if (args->v0.data & 0xfff00000)
+ return -EINVAL;
+ loadval = args->v0.data;
+ } else
+ return ret;
+
+ nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80150000);
+ nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+
+ nv_wr32(priv, 0x61a00c + doff, 0x00100000 | loadval);
+ mdelay(9);
+ udelay(500);
+ loadval = nv_mask(priv, 0x61a00c + doff, 0xffffffff, 0x00000000);
+
+ nv_mask(priv, 0x61a004 + doff, 0x807f0000, 0x80550000);
+ nv_wait(priv, 0x61a004 + doff, 0x80000000, 0x00000000);
+
+ nv_debug(priv, "DAC%d sense: 0x%08x\n", outp->or, loadval);
+ if (!(loadval & 0x80000000))
+ return -ETIMEDOUT;
+
+ args->v0.load = (loadval & 0x38000000) >> 27;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
new file mode 100644
index 000000000000..68347661adca
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "dport.h"
+#include "outpdp.h"
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/i2c.h>
+
+#include <nvif/class.h>
+
+/******************************************************************************
+ * link training
+ *****************************************************************************/
+struct dp_state {
+ struct nvkm_output_dp *outp;
+ int link_nr;
+ u32 link_bw;
+ u8 stat[6];
+ u8 conf[4];
+ bool pc2;
+ u8 pc2stat;
+ u8 pc2conf[2];
+};
+
+static int
+dp_set_link_config(struct dp_state *dp)
+{
+ struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
+ struct nvkm_output_dp *outp = dp->outp;
+ struct nvkm_disp *disp = nvkm_disp(outp);
+ struct nvkm_bios *bios = nvkm_bios(disp);
+ struct nvbios_init init = {
+ .subdev = nv_subdev(disp),
+ .bios = bios,
+ .offset = 0x0000,
+ .outp = &outp->base.info,
+ .crtc = -1,
+ .execute = 1,
+ };
+ u32 lnkcmp;
+ u8 sink[2];
+ int ret;
+
+ DBG("%d lanes at %d KB/s\n", dp->link_nr, dp->link_bw);
+
+ /* set desired link configuration on the source */
+ if ((lnkcmp = dp->outp->info.lnkcmp)) {
+ if (outp->version < 0x30) {
+ while ((dp->link_bw / 10) < nv_ro16(bios, lnkcmp))
+ lnkcmp += 4;
+ init.offset = nv_ro16(bios, lnkcmp + 2);
+ } else {
+ while ((dp->link_bw / 27000) < nv_ro08(bios, lnkcmp))
+ lnkcmp += 3;
+ init.offset = nv_ro16(bios, lnkcmp + 1);
+ }
+
+ nvbios_exec(&init);
+ }
+
+ ret = impl->lnk_ctl(outp, dp->link_nr, dp->link_bw / 27000,
+ outp->dpcd[DPCD_RC02] &
+ DPCD_RC02_ENHANCED_FRAME_CAP);
+ if (ret) {
+ if (ret < 0)
+ ERR("lnk_ctl failed with %d\n", ret);
+ return ret;
+ }
+
+ impl->lnk_pwr(outp, dp->link_nr);
+
+ /* set desired link configuration on the sink */
+ sink[0] = dp->link_bw / 27000;
+ sink[1] = dp->link_nr;
+ if (outp->dpcd[DPCD_RC02] & DPCD_RC02_ENHANCED_FRAME_CAP)
+ sink[1] |= DPCD_LC01_ENHANCED_FRAME_EN;
+
+ return nv_wraux(outp->base.edid, DPCD_LC00_LINK_BW_SET, sink, 2);
+}
+
+static void
+dp_set_training_pattern(struct dp_state *dp, u8 pattern)
+{
+ struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
+ struct nvkm_output_dp *outp = dp->outp;
+ u8 sink_tp;
+
+ DBG("training pattern %d\n", pattern);
+ impl->pattern(outp, pattern);
+
+ nv_rdaux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
+ sink_tp &= ~DPCD_LC02_TRAINING_PATTERN_SET;
+ sink_tp |= pattern;
+ nv_wraux(outp->base.edid, DPCD_LC02, &sink_tp, 1);
+}
+
+static int
+dp_link_train_commit(struct dp_state *dp, bool pc)
+{
+ struct nvkm_output_dp_impl *impl = (void *)nv_oclass(dp->outp);
+ struct nvkm_output_dp *outp = dp->outp;
+ int ret, i;
+
+ for (i = 0; i < dp->link_nr; i++) {
+ u8 lane = (dp->stat[4 + (i >> 1)] >> ((i & 1) * 4)) & 0xf;
+ u8 lpc2 = (dp->pc2stat >> (i * 2)) & 0x3;
+ u8 lpre = (lane & 0x0c) >> 2;
+ u8 lvsw = (lane & 0x03) >> 0;
+ u8 hivs = 3 - lpre;
+ u8 hipe = 3;
+ u8 hipc = 3;
+
+ if (lpc2 >= hipc)
+ lpc2 = hipc | DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED;
+ if (lpre >= hipe) {
+ lpre = hipe | DPCD_LC03_MAX_SWING_REACHED; /* yes. */
+ lvsw = hivs = 3 - (lpre & 3);
+ } else
+ if (lvsw >= hivs) {
+ lvsw = hivs | DPCD_LC03_MAX_SWING_REACHED;
+ }
+
+ dp->conf[i] = (lpre << 3) | lvsw;
+ dp->pc2conf[i >> 1] |= lpc2 << ((i & 1) * 4);
+
+ DBG("config lane %d %02x %02x\n", i, dp->conf[i], lpc2);
+ impl->drv_ctl(outp, i, lvsw & 3, lpre & 3, lpc2 & 3);
+ }
+
+ ret = nv_wraux(outp->base.edid, DPCD_LC03(0), dp->conf, 4);
+ if (ret)
+ return ret;
+
+ if (pc) {
+ ret = nv_wraux(outp->base.edid, DPCD_LC0F, dp->pc2conf, 2);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+dp_link_train_update(struct dp_state *dp, bool pc, u32 delay)
+{
+ struct nvkm_output_dp *outp = dp->outp;
+ int ret;
+
+ if (outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL])
+ mdelay(outp->dpcd[DPCD_RC0E_AUX_RD_INTERVAL] * 4);
+ else
+ udelay(delay);
+
+ ret = nv_rdaux(outp->base.edid, DPCD_LS02, dp->stat, 6);
+ if (ret)
+ return ret;
+
+ if (pc) {
+ ret = nv_rdaux(outp->base.edid, DPCD_LS0C, &dp->pc2stat, 1);
+ if (ret)
+ dp->pc2stat = 0x00;
+ DBG("status %6ph pc2 %02x\n", dp->stat, dp->pc2stat);
+ } else {
+ DBG("status %6ph\n", dp->stat);
+ }
+
+ return 0;
+}
+
+static int
+dp_link_train_cr(struct dp_state *dp)
+{
+ bool cr_done = false, abort = false;
+ int voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
+ int tries = 0, i;
+
+ dp_set_training_pattern(dp, 1);
+
+ do {
+ if (dp_link_train_commit(dp, false) ||
+ dp_link_train_update(dp, false, 100))
+ break;
+
+ cr_done = true;
+ for (i = 0; i < dp->link_nr; i++) {
+ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
+ if (!(lane & DPCD_LS02_LANE0_CR_DONE)) {
+ cr_done = false;
+ if (dp->conf[i] & DPCD_LC03_MAX_SWING_REACHED)
+ abort = true;
+ break;
+ }
+ }
+
+ if ((dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET) != voltage) {
+ voltage = dp->conf[0] & DPCD_LC03_VOLTAGE_SWING_SET;
+ tries = 0;
+ }
+ } while (!cr_done && !abort && ++tries < 5);
+
+ return cr_done ? 0 : -1;
+}
+
+static int
+dp_link_train_eq(struct dp_state *dp)
+{
+ struct nvkm_output_dp *outp = dp->outp;
+ bool eq_done = false, cr_done = true;
+ int tries = 0, i;
+
+ if (outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED)
+ dp_set_training_pattern(dp, 3);
+ else
+ dp_set_training_pattern(dp, 2);
+
+ do {
+ if ((tries &&
+ dp_link_train_commit(dp, dp->pc2)) ||
+ dp_link_train_update(dp, dp->pc2, 400))
+ break;
+
+ eq_done = !!(dp->stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE);
+ for (i = 0; i < dp->link_nr && eq_done; i++) {
+ u8 lane = (dp->stat[i >> 1] >> ((i & 1) * 4)) & 0xf;
+ if (!(lane & DPCD_LS02_LANE0_CR_DONE))
+ cr_done = false;
+ if (!(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
+ !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED))
+ eq_done = false;
+ }
+ } while (!eq_done && cr_done && ++tries <= 5);
+
+ return eq_done ? 0 : -1;
+}
+
+static void
+dp_link_train_init(struct dp_state *dp, bool spread)
+{
+ struct nvkm_output_dp *outp = dp->outp;
+ struct nvkm_disp *disp = nvkm_disp(outp);
+ struct nvkm_bios *bios = nvkm_bios(disp);
+ struct nvbios_init init = {
+ .subdev = nv_subdev(disp),
+ .bios = bios,
+ .outp = &outp->base.info,
+ .crtc = -1,
+ .execute = 1,
+ };
+
+ /* set desired spread */
+ if (spread)
+ init.offset = outp->info.script[2];
+ else
+ init.offset = outp->info.script[3];
+ nvbios_exec(&init);
+
+ /* pre-train script */
+ init.offset = outp->info.script[0];
+ nvbios_exec(&init);
+}
+
+static void
+dp_link_train_fini(struct dp_state *dp)
+{
+ struct nvkm_output_dp *outp = dp->outp;
+ struct nvkm_disp *disp = nvkm_disp(outp);
+ struct nvkm_bios *bios = nvkm_bios(disp);
+ struct nvbios_init init = {
+ .subdev = nv_subdev(disp),
+ .bios = bios,
+ .outp = &outp->base.info,
+ .crtc = -1,
+ .execute = 1,
+ };
+
+ /* post-train script */
+ init.offset = outp->info.script[1],
+ nvbios_exec(&init);
+}
+
+static const struct dp_rates {
+ u32 rate;
+ u8 bw;
+ u8 nr;
+} nvkm_dp_rates[] = {
+ { 2160000, 0x14, 4 },
+ { 1080000, 0x0a, 4 },
+ { 1080000, 0x14, 2 },
+ { 648000, 0x06, 4 },
+ { 540000, 0x0a, 2 },
+ { 540000, 0x14, 1 },
+ { 324000, 0x06, 2 },
+ { 270000, 0x0a, 1 },
+ { 162000, 0x06, 1 },
+ {}
+};
+
+void
+nvkm_dp_train(struct work_struct *w)
+{
+ struct nvkm_output_dp *outp = container_of(w, typeof(*outp), lt.work);
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const struct dp_rates *cfg = nvkm_dp_rates;
+ struct dp_state _dp = {
+ .outp = outp,
+ }, *dp = &_dp;
+ u32 datarate = 0;
+ int ret;
+
+ if (!outp->base.info.location && priv->sor.magic)
+ priv->sor.magic(&outp->base);
+
+ /* bring capabilities within encoder limits */
+ if (nv_mclass(priv) < GF110_DISP)
+ outp->dpcd[2] &= ~DPCD_RC02_TPS3_SUPPORTED;
+ if ((outp->dpcd[2] & 0x1f) > outp->base.info.dpconf.link_nr) {
+ outp->dpcd[2] &= ~DPCD_RC02_MAX_LANE_COUNT;
+ outp->dpcd[2] |= outp->base.info.dpconf.link_nr;
+ }
+ if (outp->dpcd[1] > outp->base.info.dpconf.link_bw)
+ outp->dpcd[1] = outp->base.info.dpconf.link_bw;
+ dp->pc2 = outp->dpcd[2] & DPCD_RC02_TPS3_SUPPORTED;
+
+ /* restrict link config to the lowest required rate, if requested */
+ if (datarate) {
+ datarate = (datarate / 8) * 10; /* 8B/10B coding overhead */
+ while (cfg[1].rate >= datarate)
+ cfg++;
+ }
+ cfg--;
+
+ /* disable link interrupt handling during link training */
+ nvkm_notify_put(&outp->irq);
+
+ /* enable down-spreading and execute pre-train script from vbios */
+ dp_link_train_init(dp, outp->dpcd[3] & 0x01);
+
+ while (ret = -EIO, (++cfg)->rate) {
+ /* select next configuration supported by encoder and sink */
+ while (cfg->nr > (outp->dpcd[2] & DPCD_RC02_MAX_LANE_COUNT) ||
+ cfg->bw > (outp->dpcd[DPCD_RC01_MAX_LINK_RATE]))
+ cfg++;
+ dp->link_bw = cfg->bw * 27000;
+ dp->link_nr = cfg->nr;
+
+ /* program selected link configuration */
+ ret = dp_set_link_config(dp);
+ if (ret == 0) {
+ /* attempt to train the link at this configuration */
+ memset(dp->stat, 0x00, sizeof(dp->stat));
+ if (!dp_link_train_cr(dp) &&
+ !dp_link_train_eq(dp))
+ break;
+ } else
+ if (ret) {
+ /* dp_set_link_config() handled training, or
+ * we failed to communicate with the sink.
+ */
+ break;
+ }
+ }
+
+ /* finish link training and execute post-train script from vbios */
+ dp_set_training_pattern(dp, 0);
+ if (ret < 0)
+ ERR("link training failed\n");
+
+ dp_link_train_fini(dp);
+
+ /* signal completion and enable link interrupt handling */
+ DBG("training complete\n");
+ atomic_set(&outp->lt.done, 1);
+ wake_up(&outp->lt.wait);
+ nvkm_notify_get(&outp->irq);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
new file mode 100644
index 000000000000..9596290329c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/dport.h
@@ -0,0 +1,75 @@
+#ifndef __NVKM_DISP_DPORT_H__
+#define __NVKM_DISP_DPORT_H__
+#include <core/os.h>
+
+/* DPCD Receiver Capabilities */
+#define DPCD_RC00_DPCD_REV 0x00000
+#define DPCD_RC01_MAX_LINK_RATE 0x00001
+#define DPCD_RC02 0x00002
+#define DPCD_RC02_ENHANCED_FRAME_CAP 0x80
+#define DPCD_RC02_TPS3_SUPPORTED 0x40
+#define DPCD_RC02_MAX_LANE_COUNT 0x1f
+#define DPCD_RC03 0x00003
+#define DPCD_RC03_MAX_DOWNSPREAD 0x01
+#define DPCD_RC0E_AUX_RD_INTERVAL 0x0000e
+
+/* DPCD Link Configuration */
+#define DPCD_LC00_LINK_BW_SET 0x00100
+#define DPCD_LC01 0x00101
+#define DPCD_LC01_ENHANCED_FRAME_EN 0x80
+#define DPCD_LC01_LANE_COUNT_SET 0x1f
+#define DPCD_LC02 0x00102
+#define DPCD_LC02_TRAINING_PATTERN_SET 0x03
+#define DPCD_LC03(l) ((l) + 0x00103)
+#define DPCD_LC03_MAX_PRE_EMPHASIS_REACHED 0x20
+#define DPCD_LC03_PRE_EMPHASIS_SET 0x18
+#define DPCD_LC03_MAX_SWING_REACHED 0x04
+#define DPCD_LC03_VOLTAGE_SWING_SET 0x03
+#define DPCD_LC0F 0x0010f
+#define DPCD_LC0F_LANE1_MAX_POST_CURSOR2_REACHED 0x40
+#define DPCD_LC0F_LANE1_POST_CURSOR2_SET 0x30
+#define DPCD_LC0F_LANE0_MAX_POST_CURSOR2_REACHED 0x04
+#define DPCD_LC0F_LANE0_POST_CURSOR2_SET 0x03
+#define DPCD_LC10 0x00110
+#define DPCD_LC10_LANE3_MAX_POST_CURSOR2_REACHED 0x40
+#define DPCD_LC10_LANE3_POST_CURSOR2_SET 0x30
+#define DPCD_LC10_LANE2_MAX_POST_CURSOR2_REACHED 0x04
+#define DPCD_LC10_LANE2_POST_CURSOR2_SET 0x03
+
+/* DPCD Link/Sink Status */
+#define DPCD_LS02 0x00202
+#define DPCD_LS02_LANE1_SYMBOL_LOCKED 0x40
+#define DPCD_LS02_LANE1_CHANNEL_EQ_DONE 0x20
+#define DPCD_LS02_LANE1_CR_DONE 0x10
+#define DPCD_LS02_LANE0_SYMBOL_LOCKED 0x04
+#define DPCD_LS02_LANE0_CHANNEL_EQ_DONE 0x02
+#define DPCD_LS02_LANE0_CR_DONE 0x01
+#define DPCD_LS03 0x00203
+#define DPCD_LS03_LANE3_SYMBOL_LOCKED 0x40
+#define DPCD_LS03_LANE3_CHANNEL_EQ_DONE 0x20
+#define DPCD_LS03_LANE3_CR_DONE 0x10
+#define DPCD_LS03_LANE2_SYMBOL_LOCKED 0x04
+#define DPCD_LS03_LANE2_CHANNEL_EQ_DONE 0x02
+#define DPCD_LS03_LANE2_CR_DONE 0x01
+#define DPCD_LS04 0x00204
+#define DPCD_LS04_LINK_STATUS_UPDATED 0x80
+#define DPCD_LS04_DOWNSTREAM_PORT_STATUS_CHANGED 0x40
+#define DPCD_LS04_INTERLANE_ALIGN_DONE 0x01
+#define DPCD_LS06 0x00206
+#define DPCD_LS06_LANE1_PRE_EMPHASIS 0xc0
+#define DPCD_LS06_LANE1_VOLTAGE_SWING 0x30
+#define DPCD_LS06_LANE0_PRE_EMPHASIS 0x0c
+#define DPCD_LS06_LANE0_VOLTAGE_SWING 0x03
+#define DPCD_LS07 0x00207
+#define DPCD_LS07_LANE3_PRE_EMPHASIS 0xc0
+#define DPCD_LS07_LANE3_VOLTAGE_SWING 0x30
+#define DPCD_LS07_LANE2_PRE_EMPHASIS 0x0c
+#define DPCD_LS07_LANE2_VOLTAGE_SWING 0x03
+#define DPCD_LS0C 0x0020c
+#define DPCD_LS0C_LANE3_POST_CURSOR2 0xc0
+#define DPCD_LS0C_LANE2_POST_CURSOR2 0x30
+#define DPCD_LS0C_LANE1_POST_CURSOR2 0x0c
+#define DPCD_LS0C_LANE0_POST_CURSOR2 0x03
+
+void nvkm_dp_train(struct work_struct *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
new file mode 100644
index 000000000000..a0dcf534cb20
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g84.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+g84_disp_core_mthd_dac = {
+ .mthd = 0x0080,
+ .addr = 0x000008,
+ .data = {
+ { 0x0400, 0x610b58 },
+ { 0x0404, 0x610bdc },
+ { 0x0420, 0x610bc4 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+g84_disp_core_mthd_head = {
+ .mthd = 0x0400,
+ .addr = 0x000540,
+ .data = {
+ { 0x0800, 0x610ad8 },
+ { 0x0804, 0x610ad0 },
+ { 0x0808, 0x610a48 },
+ { 0x080c, 0x610a78 },
+ { 0x0810, 0x610ac0 },
+ { 0x0814, 0x610af8 },
+ { 0x0818, 0x610b00 },
+ { 0x081c, 0x610ae8 },
+ { 0x0820, 0x610af0 },
+ { 0x0824, 0x610b08 },
+ { 0x0828, 0x610b10 },
+ { 0x082c, 0x610a68 },
+ { 0x0830, 0x610a60 },
+ { 0x0834, 0x000000 },
+ { 0x0838, 0x610a40 },
+ { 0x0840, 0x610a24 },
+ { 0x0844, 0x610a2c },
+ { 0x0848, 0x610aa8 },
+ { 0x084c, 0x610ab0 },
+ { 0x085c, 0x610c5c },
+ { 0x0860, 0x610a84 },
+ { 0x0864, 0x610a90 },
+ { 0x0868, 0x610b18 },
+ { 0x086c, 0x610b20 },
+ { 0x0870, 0x610ac8 },
+ { 0x0874, 0x610a38 },
+ { 0x0878, 0x610c50 },
+ { 0x0880, 0x610a58 },
+ { 0x0884, 0x610a9c },
+ { 0x089c, 0x610c68 },
+ { 0x08a0, 0x610a70 },
+ { 0x08a4, 0x610a50 },
+ { 0x08a8, 0x610ae0 },
+ { 0x08c0, 0x610b28 },
+ { 0x08c4, 0x610b30 },
+ { 0x08c8, 0x610b40 },
+ { 0x08d4, 0x610b38 },
+ { 0x08d8, 0x610b48 },
+ { 0x08dc, 0x610b50 },
+ { 0x0900, 0x610a18 },
+ { 0x0904, 0x610ab8 },
+ { 0x0910, 0x610c70 },
+ { 0x0914, 0x610c78 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+g84_disp_core_mthd_chan = {
+ .name = "Core",
+ .addr = 0x000000,
+ .data = {
+ { "Global", 1, &nv50_disp_core_mthd_base },
+ { "DAC", 3, &g84_disp_core_mthd_dac },
+ { "SOR", 2, &nv50_disp_core_mthd_sor },
+ { "PIOR", 3, &nv50_disp_core_mthd_pior },
+ { "HEAD", 2, &g84_disp_core_mthd_head },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+g84_disp_base_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x000000 },
+ { 0x0084, 0x0008c4 },
+ { 0x0088, 0x0008d0 },
+ { 0x008c, 0x0008dc },
+ { 0x0090, 0x0008e4 },
+ { 0x0094, 0x610884 },
+ { 0x00a0, 0x6108a0 },
+ { 0x00a4, 0x610878 },
+ { 0x00c0, 0x61086c },
+ { 0x00c4, 0x610800 },
+ { 0x00c8, 0x61080c },
+ { 0x00cc, 0x610818 },
+ { 0x00e0, 0x610858 },
+ { 0x00e4, 0x610860 },
+ { 0x00e8, 0x6108ac },
+ { 0x00ec, 0x6108b4 },
+ { 0x00fc, 0x610824 },
+ { 0x0100, 0x610894 },
+ { 0x0104, 0x61082c },
+ { 0x0110, 0x6108bc },
+ { 0x0114, 0x61088c },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+g84_disp_base_mthd_chan = {
+ .name = "Base",
+ .addr = 0x000540,
+ .data = {
+ { "Global", 1, &g84_disp_base_mthd_base },
+ { "Image", 2, &nv50_disp_base_mthd_image },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+g84_disp_ovly_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x000000 },
+ { 0x0084, 0x6109a0 },
+ { 0x0088, 0x6109c0 },
+ { 0x008c, 0x6109c8 },
+ { 0x0090, 0x6109b4 },
+ { 0x0094, 0x610970 },
+ { 0x00a0, 0x610998 },
+ { 0x00a4, 0x610964 },
+ { 0x00c0, 0x610958 },
+ { 0x00e0, 0x6109a8 },
+ { 0x00e4, 0x6109d0 },
+ { 0x00e8, 0x6109d8 },
+ { 0x0100, 0x61094c },
+ { 0x0104, 0x610984 },
+ { 0x0108, 0x61098c },
+ { 0x0800, 0x6109f8 },
+ { 0x0808, 0x610a08 },
+ { 0x080c, 0x610a10 },
+ { 0x0810, 0x610a00 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+g84_disp_ovly_mthd_chan = {
+ .name = "Overlay",
+ .addr = 0x000540,
+ .data = {
+ { "Global", 1, &g84_disp_ovly_mthd_base },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_disp_sclass[] = {
+ { G82_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+ { G82_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+ { G82_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+ { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+ { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+g84_disp_main_oclass[] = {
+ { G82_DISP, &nv50_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+g84_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+ "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = g84_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = nv50_disp_intr;
+ INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+ priv->sclass = g84_disp_sclass;
+ priv->head.nr = 2;
+ priv->dac.nr = 3;
+ priv->sor.nr = 2;
+ priv->pior.nr = 3;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hdmi = g84_hdmi_ctrl;
+ priv->pior.power = nv50_pior_power;
+ return 0;
+}
+
+struct nvkm_oclass *
+g84_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x82),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &nv50_disp_vblank_func,
+ .base.outp = nv50_disp_outp_sclass,
+ .mthd.core = &g84_disp_core_mthd_chan,
+ .mthd.base = &g84_disp_base_mthd_chan,
+ .mthd.ovly = &g84_disp_ovly_mthd_chan,
+ .mthd.prev = 0x000004,
+ .head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
new file mode 100644
index 000000000000..1ab0d0ae3cc8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/g94.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+g94_disp_core_mthd_sor = {
+ .mthd = 0x0040,
+ .addr = 0x000008,
+ .data = {
+ { 0x0600, 0x610794 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+g94_disp_core_mthd_chan = {
+ .name = "Core",
+ .addr = 0x000000,
+ .data = {
+ { "Global", 1, &nv50_disp_core_mthd_base },
+ { "DAC", 3, &g84_disp_core_mthd_dac },
+ { "SOR", 4, &g94_disp_core_mthd_sor },
+ { "PIOR", 3, &nv50_disp_core_mthd_pior },
+ { "HEAD", 2, &g84_disp_core_mthd_head },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g94_disp_sclass[] = {
+ { GT206_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+ { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+ { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+ { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+ { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+g94_disp_main_oclass[] = {
+ { GT206_DISP, &nv50_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+g94_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+ "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = g94_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = nv50_disp_intr;
+ INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+ priv->sclass = g94_disp_sclass;
+ priv->head.nr = 2;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->pior.nr = 3;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hdmi = g84_hdmi_ctrl;
+ priv->pior.power = nv50_pior_power;
+ return 0;
+}
+
+struct nvkm_oclass *
+g94_disp_outp_sclass[] = {
+ &nv50_pior_dp_impl.base.base,
+ &g94_sor_dp_impl.base.base,
+ NULL
+};
+
+struct nvkm_oclass *
+g94_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x88),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g94_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &nv50_disp_vblank_func,
+ .base.outp = g94_disp_outp_sclass,
+ .mthd.core = &g94_disp_core_mthd_chan,
+ .mthd.base = &g84_disp_base_mthd_chan,
+ .mthd.ovly = &g84_disp_ovly_mthd_chan,
+ .mthd.prev = 0x000004,
+ .head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
new file mode 100644
index 000000000000..0ebf466e9ef3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gf110.c
@@ -0,0 +1,1310 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+#include "outpdp.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <core/ramht.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/disp.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * EVO channel base class
+ ******************************************************************************/
+
+static void
+gf110_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+ nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000000 << index);
+ nv_wr32(priv, 0x61008c, 0x00000001 << index);
+}
+
+static void
+gf110_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
+{
+ struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+ nv_wr32(priv, 0x61008c, 0x00000001 << index);
+ nv_mask(priv, 0x610090, 0x00000001 << index, 0x00000001 << index);
+}
+
+const struct nvkm_event_func
+gf110_disp_chan_uevent = {
+ .ctor = nv50_disp_chan_uevent_ctor,
+ .init = gf110_disp_chan_uevent_init,
+ .fini = gf110_disp_chan_uevent_fini,
+};
+
+/*******************************************************************************
+ * EVO DMA channel base class
+ ******************************************************************************/
+
+static int
+gf110_disp_dmac_object_attach(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 name)
+{
+ struct nv50_disp_base *base = (void *)parent->parent;
+ struct nv50_disp_chan *chan = (void *)parent;
+ u32 addr = nv_gpuobj(object)->node->offset;
+ u32 data = (chan->chid << 27) | (addr << 9) | 0x00000001;
+ return nvkm_ramht_insert(base->ramht, chan->chid, name, data);
+}
+
+static void
+gf110_disp_dmac_object_detach(struct nvkm_object *parent, int cookie)
+{
+ struct nv50_disp_base *base = (void *)parent->parent;
+ nvkm_ramht_remove(base->ramht, cookie);
+}
+
+static int
+gf110_disp_dmac_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *dmac = (void *)object;
+ int chid = dmac->base.chid;
+ int ret;
+
+ ret = nv50_disp_chan_init(&dmac->base);
+ if (ret)
+ return ret;
+
+ /* enable error reporting */
+ nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
+
+ /* initialise channel for dma command submission */
+ nv_wr32(priv, 0x610494 + (chid * 0x0010), dmac->push);
+ nv_wr32(priv, 0x610498 + (chid * 0x0010), 0x00010000);
+ nv_wr32(priv, 0x61049c + (chid * 0x0010), 0x00000001);
+ nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000010, 0x00000010);
+ nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
+ nv_wr32(priv, 0x610490 + (chid * 0x0010), 0x00000013);
+
+ /* wait for it to go inactive */
+ if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x80000000, 0x00000000)) {
+ nv_error(dmac, "init: 0x%08x\n",
+ nv_rd32(priv, 0x610490 + (chid * 0x10)));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+gf110_disp_dmac_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *dmac = (void *)object;
+ int chid = dmac->base.chid;
+
+ /* deactivate channel */
+ nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00001010, 0x00001000);
+ nv_mask(priv, 0x610490 + (chid * 0x0010), 0x00000003, 0x00000000);
+ if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x001e0000, 0x00000000)) {
+ nv_error(dmac, "fini: 0x%08x\n",
+ nv_rd32(priv, 0x610490 + (chid * 0x10)));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ /* disable error reporting and completion notification */
+ nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
+ nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
+
+ return nv50_disp_chan_fini(&dmac->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x660080 },
+ { 0x0084, 0x660084 },
+ { 0x0088, 0x660088 },
+ { 0x008c, 0x000000 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_dac = {
+ .mthd = 0x0020,
+ .addr = 0x000020,
+ .data = {
+ { 0x0180, 0x660180 },
+ { 0x0184, 0x660184 },
+ { 0x0188, 0x660188 },
+ { 0x0190, 0x660190 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_sor = {
+ .mthd = 0x0020,
+ .addr = 0x000020,
+ .data = {
+ { 0x0200, 0x660200 },
+ { 0x0204, 0x660204 },
+ { 0x0208, 0x660208 },
+ { 0x0210, 0x660210 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_pior = {
+ .mthd = 0x0020,
+ .addr = 0x000020,
+ .data = {
+ { 0x0300, 0x660300 },
+ { 0x0304, 0x660304 },
+ { 0x0308, 0x660308 },
+ { 0x0310, 0x660310 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_list
+gf110_disp_core_mthd_head = {
+ .mthd = 0x0300,
+ .addr = 0x000300,
+ .data = {
+ { 0x0400, 0x660400 },
+ { 0x0404, 0x660404 },
+ { 0x0408, 0x660408 },
+ { 0x040c, 0x66040c },
+ { 0x0410, 0x660410 },
+ { 0x0414, 0x660414 },
+ { 0x0418, 0x660418 },
+ { 0x041c, 0x66041c },
+ { 0x0420, 0x660420 },
+ { 0x0424, 0x660424 },
+ { 0x0428, 0x660428 },
+ { 0x042c, 0x66042c },
+ { 0x0430, 0x660430 },
+ { 0x0434, 0x660434 },
+ { 0x0438, 0x660438 },
+ { 0x0440, 0x660440 },
+ { 0x0444, 0x660444 },
+ { 0x0448, 0x660448 },
+ { 0x044c, 0x66044c },
+ { 0x0450, 0x660450 },
+ { 0x0454, 0x660454 },
+ { 0x0458, 0x660458 },
+ { 0x045c, 0x66045c },
+ { 0x0460, 0x660460 },
+ { 0x0468, 0x660468 },
+ { 0x046c, 0x66046c },
+ { 0x0470, 0x660470 },
+ { 0x0474, 0x660474 },
+ { 0x0480, 0x660480 },
+ { 0x0484, 0x660484 },
+ { 0x048c, 0x66048c },
+ { 0x0490, 0x660490 },
+ { 0x0494, 0x660494 },
+ { 0x0498, 0x660498 },
+ { 0x04b0, 0x6604b0 },
+ { 0x04b8, 0x6604b8 },
+ { 0x04bc, 0x6604bc },
+ { 0x04c0, 0x6604c0 },
+ { 0x04c4, 0x6604c4 },
+ { 0x04c8, 0x6604c8 },
+ { 0x04d0, 0x6604d0 },
+ { 0x04d4, 0x6604d4 },
+ { 0x04e0, 0x6604e0 },
+ { 0x04e4, 0x6604e4 },
+ { 0x04e8, 0x6604e8 },
+ { 0x04ec, 0x6604ec },
+ { 0x04f0, 0x6604f0 },
+ { 0x04f4, 0x6604f4 },
+ { 0x04f8, 0x6604f8 },
+ { 0x04fc, 0x6604fc },
+ { 0x0500, 0x660500 },
+ { 0x0504, 0x660504 },
+ { 0x0508, 0x660508 },
+ { 0x050c, 0x66050c },
+ { 0x0510, 0x660510 },
+ { 0x0514, 0x660514 },
+ { 0x0518, 0x660518 },
+ { 0x051c, 0x66051c },
+ { 0x052c, 0x66052c },
+ { 0x0530, 0x660530 },
+ { 0x054c, 0x66054c },
+ { 0x0550, 0x660550 },
+ { 0x0554, 0x660554 },
+ { 0x0558, 0x660558 },
+ { 0x055c, 0x66055c },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_chan
+gf110_disp_core_mthd_chan = {
+ .name = "Core",
+ .addr = 0x000000,
+ .data = {
+ { "Global", 1, &gf110_disp_core_mthd_base },
+ { "DAC", 3, &gf110_disp_core_mthd_dac },
+ { "SOR", 8, &gf110_disp_core_mthd_sor },
+ { "PIOR", 4, &gf110_disp_core_mthd_pior },
+ { "HEAD", 4, &gf110_disp_core_mthd_head },
+ {}
+ }
+};
+
+static int
+gf110_disp_core_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *mast = (void *)object;
+ int ret;
+
+ ret = nv50_disp_chan_init(&mast->base);
+ if (ret)
+ return ret;
+
+ /* enable error reporting */
+ nv_mask(priv, 0x6100a0, 0x00000001, 0x00000001);
+
+ /* initialise channel for dma command submission */
+ nv_wr32(priv, 0x610494, mast->push);
+ nv_wr32(priv, 0x610498, 0x00010000);
+ nv_wr32(priv, 0x61049c, 0x00000001);
+ nv_mask(priv, 0x610490, 0x00000010, 0x00000010);
+ nv_wr32(priv, 0x640000, 0x00000000);
+ nv_wr32(priv, 0x610490, 0x01000013);
+
+ /* wait for it to go inactive */
+ if (!nv_wait(priv, 0x610490, 0x80000000, 0x00000000)) {
+ nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610490));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+gf110_disp_core_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *mast = (void *)object;
+
+ /* deactivate channel */
+ nv_mask(priv, 0x610490, 0x00000010, 0x00000000);
+ nv_mask(priv, 0x610490, 0x00000003, 0x00000000);
+ if (!nv_wait(priv, 0x610490, 0x001e0000, 0x00000000)) {
+ nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610490));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ /* disable error reporting and completion notification */
+ nv_mask(priv, 0x610090, 0x00000001, 0x00000000);
+ nv_mask(priv, 0x6100a0, 0x00000001, 0x00000000);
+
+ return nv50_disp_chan_fini(&mast->base, suspend);
+}
+
+struct nv50_disp_chan_impl
+gf110_disp_core_ofuncs = {
+ .base.ctor = nv50_disp_core_ctor,
+ .base.dtor = nv50_disp_dmac_dtor,
+ .base.init = gf110_disp_core_init,
+ .base.fini = gf110_disp_core_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 0,
+ .attach = gf110_disp_dmac_object_attach,
+ .detach = gf110_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gf110_disp_base_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x661080 },
+ { 0x0084, 0x661084 },
+ { 0x0088, 0x661088 },
+ { 0x008c, 0x66108c },
+ { 0x0090, 0x661090 },
+ { 0x0094, 0x661094 },
+ { 0x00a0, 0x6610a0 },
+ { 0x00a4, 0x6610a4 },
+ { 0x00c0, 0x6610c0 },
+ { 0x00c4, 0x6610c4 },
+ { 0x00c8, 0x6610c8 },
+ { 0x00cc, 0x6610cc },
+ { 0x00e0, 0x6610e0 },
+ { 0x00e4, 0x6610e4 },
+ { 0x00e8, 0x6610e8 },
+ { 0x00ec, 0x6610ec },
+ { 0x00fc, 0x6610fc },
+ { 0x0100, 0x661100 },
+ { 0x0104, 0x661104 },
+ { 0x0108, 0x661108 },
+ { 0x010c, 0x66110c },
+ { 0x0110, 0x661110 },
+ { 0x0114, 0x661114 },
+ { 0x0118, 0x661118 },
+ { 0x011c, 0x66111c },
+ { 0x0130, 0x661130 },
+ { 0x0134, 0x661134 },
+ { 0x0138, 0x661138 },
+ { 0x013c, 0x66113c },
+ { 0x0140, 0x661140 },
+ { 0x0144, 0x661144 },
+ { 0x0148, 0x661148 },
+ { 0x014c, 0x66114c },
+ { 0x0150, 0x661150 },
+ { 0x0154, 0x661154 },
+ { 0x0158, 0x661158 },
+ { 0x015c, 0x66115c },
+ { 0x0160, 0x661160 },
+ { 0x0164, 0x661164 },
+ { 0x0168, 0x661168 },
+ { 0x016c, 0x66116c },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_list
+gf110_disp_base_mthd_image = {
+ .mthd = 0x0400,
+ .addr = 0x000400,
+ .data = {
+ { 0x0400, 0x661400 },
+ { 0x0404, 0x661404 },
+ { 0x0408, 0x661408 },
+ { 0x040c, 0x66140c },
+ { 0x0410, 0x661410 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+gf110_disp_base_mthd_chan = {
+ .name = "Base",
+ .addr = 0x001000,
+ .data = {
+ { "Global", 1, &gf110_disp_base_mthd_base },
+ { "Image", 2, &gf110_disp_base_mthd_image },
+ {}
+ }
+};
+
+struct nv50_disp_chan_impl
+gf110_disp_base_ofuncs = {
+ .base.ctor = nv50_disp_base_ctor,
+ .base.dtor = nv50_disp_dmac_dtor,
+ .base.init = gf110_disp_dmac_init,
+ .base.fini = gf110_disp_dmac_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 1,
+ .attach = gf110_disp_dmac_object_attach,
+ .detach = gf110_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gf110_disp_ovly_mthd_base = {
+ .mthd = 0x0000,
+ .data = {
+ { 0x0080, 0x665080 },
+ { 0x0084, 0x665084 },
+ { 0x0088, 0x665088 },
+ { 0x008c, 0x66508c },
+ { 0x0090, 0x665090 },
+ { 0x0094, 0x665094 },
+ { 0x00a0, 0x6650a0 },
+ { 0x00a4, 0x6650a4 },
+ { 0x00b0, 0x6650b0 },
+ { 0x00b4, 0x6650b4 },
+ { 0x00b8, 0x6650b8 },
+ { 0x00c0, 0x6650c0 },
+ { 0x00e0, 0x6650e0 },
+ { 0x00e4, 0x6650e4 },
+ { 0x00e8, 0x6650e8 },
+ { 0x0100, 0x665100 },
+ { 0x0104, 0x665104 },
+ { 0x0108, 0x665108 },
+ { 0x010c, 0x66510c },
+ { 0x0110, 0x665110 },
+ { 0x0118, 0x665118 },
+ { 0x011c, 0x66511c },
+ { 0x0120, 0x665120 },
+ { 0x0124, 0x665124 },
+ { 0x0130, 0x665130 },
+ { 0x0134, 0x665134 },
+ { 0x0138, 0x665138 },
+ { 0x013c, 0x66513c },
+ { 0x0140, 0x665140 },
+ { 0x0144, 0x665144 },
+ { 0x0148, 0x665148 },
+ { 0x014c, 0x66514c },
+ { 0x0150, 0x665150 },
+ { 0x0154, 0x665154 },
+ { 0x0158, 0x665158 },
+ { 0x015c, 0x66515c },
+ { 0x0160, 0x665160 },
+ { 0x0164, 0x665164 },
+ { 0x0168, 0x665168 },
+ { 0x016c, 0x66516c },
+ { 0x0400, 0x665400 },
+ { 0x0408, 0x665408 },
+ { 0x040c, 0x66540c },
+ { 0x0410, 0x665410 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_chan
+gf110_disp_ovly_mthd_chan = {
+ .name = "Overlay",
+ .addr = 0x001000,
+ .data = {
+ { "Global", 1, &gf110_disp_ovly_mthd_base },
+ {}
+ }
+};
+
+struct nv50_disp_chan_impl
+gf110_disp_ovly_ofuncs = {
+ .base.ctor = nv50_disp_ovly_ctor,
+ .base.dtor = nv50_disp_dmac_dtor,
+ .base.init = gf110_disp_dmac_init,
+ .base.fini = gf110_disp_dmac_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 5,
+ .attach = gf110_disp_dmac_object_attach,
+ .detach = gf110_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO PIO channel base class
+ ******************************************************************************/
+
+static int
+gf110_disp_pioc_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_pioc *pioc = (void *)object;
+ int chid = pioc->base.chid;
+ int ret;
+
+ ret = nv50_disp_chan_init(&pioc->base);
+ if (ret)
+ return ret;
+
+ /* enable error reporting */
+ nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000001 << chid);
+
+ /* activate channel */
+ nv_wr32(priv, 0x610490 + (chid * 0x10), 0x00000001);
+ if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00010000)) {
+ nv_error(pioc, "init: 0x%08x\n",
+ nv_rd32(priv, 0x610490 + (chid * 0x10)));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+gf110_disp_pioc_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_pioc *pioc = (void *)object;
+ int chid = pioc->base.chid;
+
+ nv_mask(priv, 0x610490 + (chid * 0x10), 0x00000001, 0x00000000);
+ if (!nv_wait(priv, 0x610490 + (chid * 0x10), 0x00030000, 0x00000000)) {
+ nv_error(pioc, "timeout: 0x%08x\n",
+ nv_rd32(priv, 0x610490 + (chid * 0x10)));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ /* disable error reporting and completion notification */
+ nv_mask(priv, 0x610090, 0x00000001 << chid, 0x00000000);
+ nv_mask(priv, 0x6100a0, 0x00000001 << chid, 0x00000000);
+
+ return nv50_disp_chan_fini(&pioc->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO immediate overlay channel objects
+ ******************************************************************************/
+
+struct nv50_disp_chan_impl
+gf110_disp_oimm_ofuncs = {
+ .base.ctor = nv50_disp_oimm_ctor,
+ .base.dtor = nv50_disp_pioc_dtor,
+ .base.init = gf110_disp_pioc_init,
+ .base.fini = gf110_disp_pioc_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 9,
+};
+
+/*******************************************************************************
+ * EVO cursor channel objects
+ ******************************************************************************/
+
+struct nv50_disp_chan_impl
+gf110_disp_curs_ofuncs = {
+ .base.ctor = nv50_disp_curs_ctor,
+ .base.dtor = nv50_disp_pioc_dtor,
+ .base.init = gf110_disp_pioc_init,
+ .base.fini = gf110_disp_pioc_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 13,
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+int
+gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
+{
+ const u32 total = nv_rd32(priv, 0x640414 + (head * 0x300));
+ const u32 blanke = nv_rd32(priv, 0x64041c + (head * 0x300));
+ const u32 blanks = nv_rd32(priv, 0x640420 + (head * 0x300));
+ union {
+ struct nv04_disp_scanoutpos_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "disp scanoutpos size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+ args->v0.vblanke = (blanke & 0xffff0000) >> 16;
+ args->v0.hblanke = (blanke & 0x0000ffff);
+ args->v0.vblanks = (blanks & 0xffff0000) >> 16;
+ args->v0.hblanks = (blanks & 0x0000ffff);
+ args->v0.vtotal = ( total & 0xffff0000) >> 16;
+ args->v0.htotal = ( total & 0x0000ffff);
+ args->v0.time[0] = ktime_to_ns(ktime_get());
+ args->v0.vline = /* vline read locks hline */
+ nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+ args->v0.time[1] = ktime_to_ns(ktime_get());
+ args->v0.hline =
+ nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+ } else
+ return ret;
+
+ return 0;
+}
+
+static int
+gf110_disp_main_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_base *base = (void *)object;
+ int ret, i;
+ u32 tmp;
+
+ ret = nvkm_parent_init(&base->base);
+ if (ret)
+ return ret;
+
+ /* The below segments of code copying values from one register to
+ * another appear to inform EVO of the display capabilities or
+ * something similar.
+ */
+
+ /* ... CRTC caps */
+ for (i = 0; i < priv->head.nr; i++) {
+ tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
+ nv_wr32(priv, 0x6101b4 + (i * 0x800), tmp);
+ tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
+ nv_wr32(priv, 0x6101b8 + (i * 0x800), tmp);
+ tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
+ nv_wr32(priv, 0x6101bc + (i * 0x800), tmp);
+ }
+
+ /* ... DAC caps */
+ for (i = 0; i < priv->dac.nr; i++) {
+ tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
+ nv_wr32(priv, 0x6101c0 + (i * 0x800), tmp);
+ }
+
+ /* ... SOR caps */
+ for (i = 0; i < priv->sor.nr; i++) {
+ tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
+ nv_wr32(priv, 0x6301c4 + (i * 0x800), tmp);
+ }
+
+ /* steal display away from vbios, or something like that */
+ if (nv_rd32(priv, 0x6100ac) & 0x00000100) {
+ nv_wr32(priv, 0x6100ac, 0x00000100);
+ nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
+ if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
+ nv_error(priv, "timeout acquiring display\n");
+ return -EBUSY;
+ }
+ }
+
+ /* point at display engine memory area (hash table, objects) */
+ nv_wr32(priv, 0x610010, (nv_gpuobj(object->parent)->addr >> 8) | 9);
+
+ /* enable supervisor interrupts, disable everything else */
+ nv_wr32(priv, 0x610090, 0x00000000);
+ nv_wr32(priv, 0x6100a0, 0x00000000);
+ nv_wr32(priv, 0x6100b0, 0x00000307);
+
+ /* disable underflow reporting, preventing an intermittent issue
+ * on some gk104 boards where the production vbios left this
+ * setting enabled by default.
+ *
+ * ftp://download.nvidia.com/open-gpu-doc/gk104-disable-underflow-reporting/1/gk104-disable-underflow-reporting.txt
+ */
+ for (i = 0; i < priv->head.nr; i++)
+ nv_mask(priv, 0x616308 + (i * 0x800), 0x00000111, 0x00000010);
+
+ return 0;
+}
+
+static int
+gf110_disp_main_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_base *base = (void *)object;
+
+ /* disable all interrupts */
+ nv_wr32(priv, 0x6100b0, 0x00000000);
+
+ return nvkm_parent_fini(&base->base, suspend);
+}
+
+struct nvkm_ofuncs
+gf110_disp_main_ofuncs = {
+ .ctor = nv50_disp_main_ctor,
+ .dtor = nv50_disp_main_dtor,
+ .init = gf110_disp_main_init,
+ .fini = gf110_disp_main_fini,
+ .mthd = nv50_disp_main_mthd,
+ .ntfy = nvkm_disp_ntfy,
+};
+
+static struct nvkm_oclass
+gf110_disp_main_oclass[] = {
+ { GF110_DISP, &gf110_disp_main_ofuncs },
+ {}
+};
+
+static struct nvkm_oclass
+gf110_disp_sclass[] = {
+ { GF110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+ { GF110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+ { GF110_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+ { GF110_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+ { GF110_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+gf110_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+ nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000001);
+}
+
+static void
+gf110_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+ nv_mask(disp, 0x6100c0 + (head * 0x800), 0x00000001, 0x00000000);
+}
+
+const struct nvkm_event_func
+gf110_disp_vblank_func = {
+ .ctor = nvkm_disp_vblank_ctor,
+ .init = gf110_disp_vblank_init,
+ .fini = gf110_disp_vblank_fini,
+};
+
+static struct nvkm_output *
+exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
+ u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_outp *info)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvkm_output *outp;
+ u16 mask, type;
+
+ if (or < 4) {
+ type = DCB_OUTPUT_ANALOG;
+ mask = 0;
+ } else {
+ or -= 4;
+ switch (ctrl & 0x00000f00) {
+ case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
+ case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
+ case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
+ case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
+ case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
+ case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
+ default:
+ nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
+ return 0x0000;
+ }
+ }
+
+ mask = 0x00c0 & (mask << 6);
+ mask |= 0x0001 << or;
+ mask |= 0x0100 << head;
+
+ list_for_each_entry(outp, &priv->base.outp, head) {
+ if ((outp->info.hasht & 0xff) == type &&
+ (outp->info.hashm & mask) == mask) {
+ *data = nvbios_outp_match(bios, outp->info.hasht,
+ outp->info.hashm,
+ ver, hdr, cnt, len, info);
+ if (!*data)
+ return NULL;
+ return outp;
+ }
+ }
+
+ return NULL;
+}
+
+static struct nvkm_output *
+exec_script(struct nv50_disp_priv *priv, int head, int id)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvkm_output *outp;
+ struct nvbios_outp info;
+ u8 ver, hdr, cnt, len;
+ u32 data, ctrl = 0;
+ int or;
+
+ for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
+ ctrl = nv_rd32(priv, 0x640180 + (or * 0x20));
+ if (ctrl & (1 << head))
+ break;
+ }
+
+ if (or == 8)
+ return NULL;
+
+ outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
+ if (outp) {
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = bios,
+ .offset = info.script[id],
+ .outp = &outp->info,
+ .crtc = head,
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ }
+
+ return outp;
+}
+
+static struct nvkm_output *
+exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvkm_output *outp;
+ struct nvbios_outp info1;
+ struct nvbios_ocfg info2;
+ u8 ver, hdr, cnt, len;
+ u32 data, ctrl = 0;
+ int or;
+
+ for (or = 0; !(ctrl & (1 << head)) && or < 8; or++) {
+ ctrl = nv_rd32(priv, 0x660180 + (or * 0x20));
+ if (ctrl & (1 << head))
+ break;
+ }
+
+ if (or == 8)
+ return NULL;
+
+ outp = exec_lookup(priv, head, or, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
+ if (!outp)
+ return NULL;
+
+ switch (outp->info.type) {
+ case DCB_OUTPUT_TMDS:
+ *conf = (ctrl & 0x00000f00) >> 8;
+ if (pclk >= 165000)
+ *conf |= 0x0100;
+ break;
+ case DCB_OUTPUT_LVDS:
+ *conf = priv->sor.lvdsconf;
+ break;
+ case DCB_OUTPUT_DP:
+ *conf = (ctrl & 0x00000f00) >> 8;
+ break;
+ case DCB_OUTPUT_ANALOG:
+ default:
+ *conf = 0x00ff;
+ break;
+ }
+
+ data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
+ if (data && id < 0xff) {
+ data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
+ if (data) {
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = bios,
+ .offset = data,
+ .outp = &outp->info,
+ .crtc = head,
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ }
+ }
+
+ return outp;
+}
+
+static void
+gf110_disp_intr_unk1_0(struct nv50_disp_priv *priv, int head)
+{
+ exec_script(priv, head, 1);
+}
+
+static void
+gf110_disp_intr_unk2_0(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_output *outp = exec_script(priv, head, 2);
+
+ /* see note in nv50_disp_intr_unk20_0() */
+ if (outp && outp->info.type == DCB_OUTPUT_DP) {
+ struct nvkm_output_dp *outpdp = (void *)outp;
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = nvkm_bios(priv),
+ .outp = &outp->info,
+ .crtc = head,
+ .offset = outpdp->info.script[4],
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ atomic_set(&outpdp->lt.done, 0);
+ }
+}
+
+static void
+gf110_disp_intr_unk2_1(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_devinit *devinit = nvkm_devinit(priv);
+ u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+ if (pclk)
+ devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
+ nv_wr32(priv, 0x612200 + (head * 0x800), 0x00000000);
+}
+
+static void
+gf110_disp_intr_unk2_2_tu(struct nv50_disp_priv *priv, int head,
+ struct dcb_output *outp)
+{
+ const int or = ffs(outp->or) - 1;
+ const u32 ctrl = nv_rd32(priv, 0x660200 + (or * 0x020));
+ const u32 conf = nv_rd32(priv, 0x660404 + (head * 0x300));
+ const s32 vactive = nv_rd32(priv, 0x660414 + (head * 0x300)) & 0xffff;
+ const s32 vblanke = nv_rd32(priv, 0x66041c + (head * 0x300)) & 0xffff;
+ const s32 vblanks = nv_rd32(priv, 0x660420 + (head * 0x300)) & 0xffff;
+ const u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+ const u32 link = ((ctrl & 0xf00) == 0x800) ? 0 : 1;
+ const u32 hoff = (head * 0x800);
+ const u32 soff = ( or * 0x800);
+ const u32 loff = (link * 0x080) + soff;
+ const u32 symbol = 100000;
+ const u32 TU = 64;
+ u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
+ u32 clksor = nv_rd32(priv, 0x612300 + soff);
+ u32 datarate, link_nr, link_bw, bits;
+ u64 ratio, value;
+
+ link_nr = hweight32(dpctrl & 0x000f0000);
+ link_bw = (clksor & 0x007c0000) >> 18;
+ link_bw *= 27000;
+
+ /* symbols/hblank - algorithm taken from comments in tegra driver */
+ value = vblanke + vactive - vblanks - 7;
+ value = value * link_bw;
+ do_div(value, pclk);
+ value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
+ nv_mask(priv, 0x616620 + hoff, 0x0000ffff, value);
+
+ /* symbols/vblank - algorithm taken from comments in tegra driver */
+ value = vblanks - vblanke - 25;
+ value = value * link_bw;
+ do_div(value, pclk);
+ value = value - ((36 / link_nr) + 3) - 1;
+ nv_mask(priv, 0x616624 + hoff, 0x00ffffff, value);
+
+ /* watermark */
+ if ((conf & 0x3c0) == 0x180) bits = 30;
+ else if ((conf & 0x3c0) == 0x140) bits = 24;
+ else bits = 18;
+ datarate = (pclk * bits) / 8;
+
+ ratio = datarate;
+ ratio *= symbol;
+ do_div(ratio, link_nr * link_bw);
+
+ value = (symbol - ratio) * TU;
+ value *= ratio;
+ do_div(value, symbol);
+ do_div(value, symbol);
+
+ value += 5;
+ value |= 0x08000000;
+
+ nv_wr32(priv, 0x616610 + hoff, value);
+}
+
+static void
+gf110_disp_intr_unk2_2(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_output *outp;
+ u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+ u32 conf, addr, data;
+
+ outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
+ if (!outp)
+ return;
+
+ /* see note in nv50_disp_intr_unk20_2() */
+ if (outp->info.type == DCB_OUTPUT_DP) {
+ u32 sync = nv_rd32(priv, 0x660404 + (head * 0x300));
+ switch ((sync & 0x000003c0) >> 6) {
+ case 6: pclk = pclk * 30; break;
+ case 5: pclk = pclk * 24; break;
+ case 2:
+ default:
+ pclk = pclk * 18;
+ break;
+ }
+
+ if (nvkm_output_dp_train(outp, pclk, true))
+ ERR("link not trained before attach\n");
+ } else {
+ if (priv->sor.magic)
+ priv->sor.magic(outp);
+ }
+
+ exec_clkcmp(priv, head, 0, pclk, &conf);
+
+ if (outp->info.type == DCB_OUTPUT_ANALOG) {
+ addr = 0x612280 + (ffs(outp->info.or) - 1) * 0x800;
+ data = 0x00000000;
+ } else {
+ addr = 0x612300 + (ffs(outp->info.or) - 1) * 0x800;
+ data = (conf & 0x0100) ? 0x00000101 : 0x00000000;
+ switch (outp->info.type) {
+ case DCB_OUTPUT_TMDS:
+ nv_mask(priv, addr, 0x007c0000, 0x00280000);
+ break;
+ case DCB_OUTPUT_DP:
+ gf110_disp_intr_unk2_2_tu(priv, head, &outp->info);
+ break;
+ default:
+ break;
+ }
+ }
+
+ nv_mask(priv, addr, 0x00000707, data);
+}
+
+static void
+gf110_disp_intr_unk4_0(struct nv50_disp_priv *priv, int head)
+{
+ u32 pclk = nv_rd32(priv, 0x660450 + (head * 0x300)) / 1000;
+ u32 conf;
+
+ exec_clkcmp(priv, head, 1, pclk, &conf);
+}
+
+void
+gf110_disp_intr_supervisor(struct work_struct *work)
+{
+ struct nv50_disp_priv *priv =
+ container_of(work, struct nv50_disp_priv, supervisor);
+ struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+ u32 mask[4];
+ int head;
+
+ nv_debug(priv, "supervisor %d\n", ffs(priv->super));
+ for (head = 0; head < priv->head.nr; head++) {
+ mask[head] = nv_rd32(priv, 0x6101d4 + (head * 0x800));
+ nv_debug(priv, "head %d: 0x%08x\n", head, mask[head]);
+ }
+
+ if (priv->super & 0x00000001) {
+ nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(mask[head] & 0x00001000))
+ continue;
+ nv_debug(priv, "supervisor 1.0 - head %d\n", head);
+ gf110_disp_intr_unk1_0(priv, head);
+ }
+ } else
+ if (priv->super & 0x00000002) {
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(mask[head] & 0x00001000))
+ continue;
+ nv_debug(priv, "supervisor 2.0 - head %d\n", head);
+ gf110_disp_intr_unk2_0(priv, head);
+ }
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(mask[head] & 0x00010000))
+ continue;
+ nv_debug(priv, "supervisor 2.1 - head %d\n", head);
+ gf110_disp_intr_unk2_1(priv, head);
+ }
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(mask[head] & 0x00001000))
+ continue;
+ nv_debug(priv, "supervisor 2.2 - head %d\n", head);
+ gf110_disp_intr_unk2_2(priv, head);
+ }
+ } else
+ if (priv->super & 0x00000004) {
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(mask[head] & 0x00001000))
+ continue;
+ nv_debug(priv, "supervisor 3.0 - head %d\n", head);
+ gf110_disp_intr_unk4_0(priv, head);
+ }
+ }
+
+ for (head = 0; head < priv->head.nr; head++)
+ nv_wr32(priv, 0x6101d4 + (head * 0x800), 0x00000000);
+ nv_wr32(priv, 0x6101d0, 0x80000000);
+}
+
+static void
+gf110_disp_intr_error(struct nv50_disp_priv *priv, int chid)
+{
+ const struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+ u32 mthd = nv_rd32(priv, 0x6101f0 + (chid * 12));
+ u32 data = nv_rd32(priv, 0x6101f4 + (chid * 12));
+ u32 unkn = nv_rd32(priv, 0x6101f8 + (chid * 12));
+
+ nv_error(priv, "chid %d mthd 0x%04x data 0x%08x "
+ "0x%08x 0x%08x\n",
+ chid, (mthd & 0x0000ffc), data, mthd, unkn);
+
+ if (chid == 0) {
+ switch (mthd & 0xffc) {
+ case 0x0080:
+ nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
+ impl->mthd.core);
+ break;
+ default:
+ break;
+ }
+ } else
+ if (chid <= 4) {
+ switch (mthd & 0xffc) {
+ case 0x0080:
+ nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
+ impl->mthd.base);
+ break;
+ default:
+ break;
+ }
+ } else
+ if (chid <= 8) {
+ switch (mthd & 0xffc) {
+ case 0x0080:
+ nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 5,
+ impl->mthd.ovly);
+ break;
+ default:
+ break;
+ }
+ }
+
+ nv_wr32(priv, 0x61009c, (1 << chid));
+ nv_wr32(priv, 0x6101f0 + (chid * 12), 0x90000000);
+}
+
+void
+gf110_disp_intr(struct nvkm_subdev *subdev)
+{
+ struct nv50_disp_priv *priv = (void *)subdev;
+ u32 intr = nv_rd32(priv, 0x610088);
+ int i;
+
+ if (intr & 0x00000001) {
+ u32 stat = nv_rd32(priv, 0x61008c);
+ while (stat) {
+ int chid = __ffs(stat); stat &= ~(1 << chid);
+ nv50_disp_chan_uevent_send(priv, chid);
+ nv_wr32(priv, 0x61008c, 1 << chid);
+ }
+ intr &= ~0x00000001;
+ }
+
+ if (intr & 0x00000002) {
+ u32 stat = nv_rd32(priv, 0x61009c);
+ int chid = ffs(stat) - 1;
+ if (chid >= 0)
+ gf110_disp_intr_error(priv, chid);
+ intr &= ~0x00000002;
+ }
+
+ if (intr & 0x00100000) {
+ u32 stat = nv_rd32(priv, 0x6100ac);
+ if (stat & 0x00000007) {
+ priv->super = (stat & 0x00000007);
+ schedule_work(&priv->supervisor);
+ nv_wr32(priv, 0x6100ac, priv->super);
+ stat &= ~0x00000007;
+ }
+
+ if (stat) {
+ nv_info(priv, "unknown intr24 0x%08x\n", stat);
+ nv_wr32(priv, 0x6100ac, stat);
+ }
+
+ intr &= ~0x00100000;
+ }
+
+ for (i = 0; i < priv->head.nr; i++) {
+ u32 mask = 0x01000000 << i;
+ if (mask & intr) {
+ u32 stat = nv_rd32(priv, 0x6100bc + (i * 0x800));
+ if (stat & 0x00000001)
+ nvkm_disp_vblank(&priv->base, i);
+ nv_mask(priv, 0x6100bc + (i * 0x800), 0, 0);
+ nv_rd32(priv, 0x6100c0 + (i * 0x800));
+ }
+ }
+}
+
+static int
+gf110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int heads = nv_rd32(parent, 0x022448);
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, heads,
+ "PDISP", "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gf110_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = gf110_disp_intr;
+ INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+ priv->sclass = gf110_disp_sclass;
+ priv->head.nr = heads;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hda_eld = gf110_hda_eld;
+ priv->sor.hdmi = gf110_hdmi_ctrl;
+ return 0;
+}
+
+struct nvkm_oclass *
+gf110_disp_outp_sclass[] = {
+ &gf110_sor_dp_impl.base.base,
+ NULL
+};
+
+struct nvkm_oclass *
+gf110_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x90),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf110_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &gf110_disp_vblank_func,
+ .base.outp = gf110_disp_outp_sclass,
+ .mthd.core = &gf110_disp_core_mthd_chan,
+ .mthd.base = &gf110_disp_base_mthd_chan,
+ .mthd.ovly = &gf110_disp_ovly_mthd_chan,
+ .mthd.prev = -0x020000,
+ .head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
new file mode 100644
index 000000000000..6f4019ab4e65
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk104.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gk104_disp_core_mthd_head = {
+ .mthd = 0x0300,
+ .addr = 0x000300,
+ .data = {
+ { 0x0400, 0x660400 },
+ { 0x0404, 0x660404 },
+ { 0x0408, 0x660408 },
+ { 0x040c, 0x66040c },
+ { 0x0410, 0x660410 },
+ { 0x0414, 0x660414 },
+ { 0x0418, 0x660418 },
+ { 0x041c, 0x66041c },
+ { 0x0420, 0x660420 },
+ { 0x0424, 0x660424 },
+ { 0x0428, 0x660428 },
+ { 0x042c, 0x66042c },
+ { 0x0430, 0x660430 },
+ { 0x0434, 0x660434 },
+ { 0x0438, 0x660438 },
+ { 0x0440, 0x660440 },
+ { 0x0444, 0x660444 },
+ { 0x0448, 0x660448 },
+ { 0x044c, 0x66044c },
+ { 0x0450, 0x660450 },
+ { 0x0454, 0x660454 },
+ { 0x0458, 0x660458 },
+ { 0x045c, 0x66045c },
+ { 0x0460, 0x660460 },
+ { 0x0468, 0x660468 },
+ { 0x046c, 0x66046c },
+ { 0x0470, 0x660470 },
+ { 0x0474, 0x660474 },
+ { 0x047c, 0x66047c },
+ { 0x0480, 0x660480 },
+ { 0x0484, 0x660484 },
+ { 0x0488, 0x660488 },
+ { 0x048c, 0x66048c },
+ { 0x0490, 0x660490 },
+ { 0x0494, 0x660494 },
+ { 0x0498, 0x660498 },
+ { 0x04a0, 0x6604a0 },
+ { 0x04b0, 0x6604b0 },
+ { 0x04b8, 0x6604b8 },
+ { 0x04bc, 0x6604bc },
+ { 0x04c0, 0x6604c0 },
+ { 0x04c4, 0x6604c4 },
+ { 0x04c8, 0x6604c8 },
+ { 0x04d0, 0x6604d0 },
+ { 0x04d4, 0x6604d4 },
+ { 0x04e0, 0x6604e0 },
+ { 0x04e4, 0x6604e4 },
+ { 0x04e8, 0x6604e8 },
+ { 0x04ec, 0x6604ec },
+ { 0x04f0, 0x6604f0 },
+ { 0x04f4, 0x6604f4 },
+ { 0x04f8, 0x6604f8 },
+ { 0x04fc, 0x6604fc },
+ { 0x0500, 0x660500 },
+ { 0x0504, 0x660504 },
+ { 0x0508, 0x660508 },
+ { 0x050c, 0x66050c },
+ { 0x0510, 0x660510 },
+ { 0x0514, 0x660514 },
+ { 0x0518, 0x660518 },
+ { 0x051c, 0x66051c },
+ { 0x0520, 0x660520 },
+ { 0x0524, 0x660524 },
+ { 0x052c, 0x66052c },
+ { 0x0530, 0x660530 },
+ { 0x054c, 0x66054c },
+ { 0x0550, 0x660550 },
+ { 0x0554, 0x660554 },
+ { 0x0558, 0x660558 },
+ { 0x055c, 0x66055c },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+gk104_disp_core_mthd_chan = {
+ .name = "Core",
+ .addr = 0x000000,
+ .data = {
+ { "Global", 1, &gf110_disp_core_mthd_base },
+ { "DAC", 3, &gf110_disp_core_mthd_dac },
+ { "SOR", 8, &gf110_disp_core_mthd_sor },
+ { "PIOR", 4, &gf110_disp_core_mthd_pior },
+ { "HEAD", 4, &gk104_disp_core_mthd_head },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gk104_disp_ovly_mthd_base = {
+ .mthd = 0x0000,
+ .data = {
+ { 0x0080, 0x665080 },
+ { 0x0084, 0x665084 },
+ { 0x0088, 0x665088 },
+ { 0x008c, 0x66508c },
+ { 0x0090, 0x665090 },
+ { 0x0094, 0x665094 },
+ { 0x00a0, 0x6650a0 },
+ { 0x00a4, 0x6650a4 },
+ { 0x00b0, 0x6650b0 },
+ { 0x00b4, 0x6650b4 },
+ { 0x00b8, 0x6650b8 },
+ { 0x00c0, 0x6650c0 },
+ { 0x00c4, 0x6650c4 },
+ { 0x00e0, 0x6650e0 },
+ { 0x00e4, 0x6650e4 },
+ { 0x00e8, 0x6650e8 },
+ { 0x0100, 0x665100 },
+ { 0x0104, 0x665104 },
+ { 0x0108, 0x665108 },
+ { 0x010c, 0x66510c },
+ { 0x0110, 0x665110 },
+ { 0x0118, 0x665118 },
+ { 0x011c, 0x66511c },
+ { 0x0120, 0x665120 },
+ { 0x0124, 0x665124 },
+ { 0x0130, 0x665130 },
+ { 0x0134, 0x665134 },
+ { 0x0138, 0x665138 },
+ { 0x013c, 0x66513c },
+ { 0x0140, 0x665140 },
+ { 0x0144, 0x665144 },
+ { 0x0148, 0x665148 },
+ { 0x014c, 0x66514c },
+ { 0x0150, 0x665150 },
+ { 0x0154, 0x665154 },
+ { 0x0158, 0x665158 },
+ { 0x015c, 0x66515c },
+ { 0x0160, 0x665160 },
+ { 0x0164, 0x665164 },
+ { 0x0168, 0x665168 },
+ { 0x016c, 0x66516c },
+ { 0x0400, 0x665400 },
+ { 0x0404, 0x665404 },
+ { 0x0408, 0x665408 },
+ { 0x040c, 0x66540c },
+ { 0x0410, 0x665410 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_chan
+gk104_disp_ovly_mthd_chan = {
+ .name = "Overlay",
+ .addr = 0x001000,
+ .data = {
+ { "Global", 1, &gk104_disp_ovly_mthd_base },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_disp_sclass[] = {
+ { GK104_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+ { GK104_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+ { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+ { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+ { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+gk104_disp_main_oclass[] = {
+ { GK104_DISP, &gf110_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gk104_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int heads = nv_rd32(parent, 0x022448);
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, heads,
+ "PDISP", "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gk104_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = gf110_disp_intr;
+ INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+ priv->sclass = gk104_disp_sclass;
+ priv->head.nr = heads;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hda_eld = gf110_hda_eld;
+ priv->sor.hdmi = gk104_hdmi_ctrl;
+ return 0;
+}
+
+struct nvkm_oclass *
+gk104_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x91),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &gf110_disp_vblank_func,
+ .base.outp = gf110_disp_outp_sclass,
+ .mthd.core = &gk104_disp_core_mthd_chan,
+ .mthd.base = &gf110_disp_base_mthd_chan,
+ .mthd.ovly = &gk104_disp_ovly_mthd_chan,
+ .mthd.prev = -0x020000,
+ .head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
new file mode 100644
index 000000000000..daa4b460a6ba
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gk110.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk110_disp_sclass[] = {
+ { GK110_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+ { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+ { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+ { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+ { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+gk110_disp_main_oclass[] = {
+ { GK110_DISP, &gf110_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gk110_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int heads = nv_rd32(parent, 0x022448);
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, heads,
+ "PDISP", "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gk110_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = gf110_disp_intr;
+ INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+ priv->sclass = gk110_disp_sclass;
+ priv->head.nr = heads;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hda_eld = gf110_hda_eld;
+ priv->sor.hdmi = gk104_hdmi_ctrl;
+ return 0;
+}
+
+struct nvkm_oclass *
+gk110_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x92),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk110_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &gf110_disp_vblank_func,
+ .base.outp = gf110_disp_outp_sclass,
+ .mthd.core = &gk104_disp_core_mthd_chan,
+ .mthd.base = &gf110_disp_base_mthd_chan,
+ .mthd.ovly = &gk104_disp_ovly_mthd_chan,
+ .mthd.prev = -0x020000,
+ .head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
new file mode 100644
index 000000000000..881cc94385a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm107.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm107_disp_sclass[] = {
+ { GM107_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+ { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+ { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+ { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+ { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+gm107_disp_main_oclass[] = {
+ { GM107_DISP, &gf110_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gm107_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int heads = nv_rd32(parent, 0x022448);
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, heads,
+ "PDISP", "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gm107_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = gf110_disp_intr;
+ INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+ priv->sclass = gm107_disp_sclass;
+ priv->head.nr = heads;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hda_eld = gf110_hda_eld;
+ priv->sor.hdmi = gk104_hdmi_ctrl;
+ return 0;
+}
+
+struct nvkm_oclass *
+gm107_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x07),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm107_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &gf110_disp_vblank_func,
+ .base.outp = gf110_disp_outp_sclass,
+ .mthd.core = &gk104_disp_core_mthd_chan,
+ .mthd.base = &gf110_disp_base_mthd_chan,
+ .mthd.ovly = &gk104_disp_ovly_mthd_chan,
+ .mthd.prev = -0x020000,
+ .head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c
new file mode 100644
index 000000000000..67004f8302b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gm204.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm204_disp_sclass[] = {
+ { GM204_DISP_CORE_CHANNEL_DMA, &gf110_disp_core_ofuncs.base },
+ { GK110_DISP_BASE_CHANNEL_DMA, &gf110_disp_base_ofuncs.base },
+ { GK104_DISP_OVERLAY_CONTROL_DMA, &gf110_disp_ovly_ofuncs.base },
+ { GK104_DISP_OVERLAY, &gf110_disp_oimm_ofuncs.base },
+ { GK104_DISP_CURSOR, &gf110_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+gm204_disp_main_oclass[] = {
+ { GM204_DISP, &gf110_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gm204_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int heads = nv_rd32(parent, 0x022448);
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, heads,
+ "PDISP", "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gf110_disp_chan_uevent, 1, 17, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gm204_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = gf110_disp_intr;
+ INIT_WORK(&priv->supervisor, gf110_disp_intr_supervisor);
+ priv->sclass = gm204_disp_sclass;
+ priv->head.nr = heads;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hda_eld = gf110_hda_eld;
+ priv->sor.hdmi = gf110_hdmi_ctrl;
+ priv->sor.magic = gm204_sor_magic;
+ return 0;
+}
+
+struct nvkm_oclass *
+gm204_disp_outp_sclass[] = {
+ &gm204_sor_dp_impl.base.base,
+ NULL
+};
+
+struct nvkm_oclass *
+gm204_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x07),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm204_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &gf110_disp_vblank_func,
+ .base.outp = gm204_disp_outp_sclass,
+ .mthd.core = &gk104_disp_core_mthd_chan,
+ .mthd.base = &gf110_disp_base_mthd_chan,
+ .mthd.ovly = &gk104_disp_ovly_mthd_chan,
+ .mthd.prev = -0x020000,
+ .head.scanoutpos = gf110_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
new file mode 100644
index 000000000000..a45307213f4b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt200.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+gt200_disp_ovly_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x000000 },
+ { 0x0084, 0x6109a0 },
+ { 0x0088, 0x6109c0 },
+ { 0x008c, 0x6109c8 },
+ { 0x0090, 0x6109b4 },
+ { 0x0094, 0x610970 },
+ { 0x00a0, 0x610998 },
+ { 0x00a4, 0x610964 },
+ { 0x00b0, 0x610c98 },
+ { 0x00b4, 0x610ca4 },
+ { 0x00b8, 0x610cac },
+ { 0x00c0, 0x610958 },
+ { 0x00e0, 0x6109a8 },
+ { 0x00e4, 0x6109d0 },
+ { 0x00e8, 0x6109d8 },
+ { 0x0100, 0x61094c },
+ { 0x0104, 0x610984 },
+ { 0x0108, 0x61098c },
+ { 0x0800, 0x6109f8 },
+ { 0x0808, 0x610a08 },
+ { 0x080c, 0x610a10 },
+ { 0x0810, 0x610a00 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_chan
+gt200_disp_ovly_mthd_chan = {
+ .name = "Overlay",
+ .addr = 0x000540,
+ .data = {
+ { "Global", 1, &gt200_disp_ovly_mthd_base },
+ {}
+ }
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt200_disp_sclass[] = {
+ { GT200_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+ { GT200_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+ { GT200_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+ { G82_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+ { G82_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+gt200_disp_main_oclass[] = {
+ { GT200_DISP, &nv50_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gt200_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+ "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gt200_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = nv50_disp_intr;
+ INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+ priv->sclass = gt200_disp_sclass;
+ priv->head.nr = 2;
+ priv->dac.nr = 3;
+ priv->sor.nr = 2;
+ priv->pior.nr = 3;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hdmi = g84_hdmi_ctrl;
+ priv->pior.power = nv50_pior_power;
+ return 0;
+}
+
+struct nvkm_oclass *
+gt200_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x83),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt200_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &nv50_disp_vblank_func,
+ .base.outp = nv50_disp_outp_sclass,
+ .mthd.core = &g84_disp_core_mthd_chan,
+ .mthd.base = &g84_disp_base_mthd_chan,
+ .mthd.ovly = &gt200_disp_ovly_mthd_chan,
+ .mthd.prev = 0x000004,
+ .head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
new file mode 100644
index 000000000000..55f0d3ac591e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/gt215.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gt215_disp_sclass[] = {
+ { GT214_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+ { GT214_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+ { GT214_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+ { GT214_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+ { GT214_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+ {}
+};
+
+static struct nvkm_oclass
+gt215_disp_main_oclass[] = {
+ { GT214_DISP, &nv50_disp_main_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static int
+gt215_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+ "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = gt215_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = nv50_disp_intr;
+ INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+ priv->sclass = gt215_disp_sclass;
+ priv->head.nr = 2;
+ priv->dac.nr = 3;
+ priv->sor.nr = 4;
+ priv->pior.nr = 3;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->sor.hda_eld = gt215_hda_eld;
+ priv->sor.hdmi = gt215_hdmi_ctrl;
+ priv->pior.power = nv50_pior_power;
+ return 0;
+}
+
+struct nvkm_oclass *
+gt215_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x85),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt215_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &nv50_disp_vblank_func,
+ .base.outp = g94_disp_outp_sclass,
+ .mthd.core = &g94_disp_core_mthd_chan,
+ .mthd.base = &g84_disp_base_mthd_chan,
+ .mthd.ovly = &g84_disp_ovly_mthd_chan,
+ .mthd.prev = 0x000004,
+ .head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c
new file mode 100644
index 000000000000..b9813d246ba5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagf110.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gf110_hda_eld(NV50_DISP_MTHD_V1)
+{
+ union {
+ struct nv50_disp_sor_hda_eld_v0 v0;
+ } *args = data;
+ const u32 soff = outp->or * 0x030;
+ const u32 hoff = head * 0x800;
+ int ret, i;
+
+ nv_ioctl(object, "disp sor hda eld size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
+ if (size > 0x60)
+ return -E2BIG;
+ } else
+ return ret;
+
+ if (size && args->v0.data[0]) {
+ if (outp->info.type == DCB_OUTPUT_DP) {
+ nv_mask(priv, 0x616618 + hoff, 0x8000000c, 0x80000001);
+ nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
+ }
+ nv_mask(priv, 0x616548 + hoff, 0x00000070, 0x00000000);
+ for (i = 0; i < size; i++)
+ nv_wr32(priv, 0x10ec00 + soff, (i << 8) | args->v0.data[i]);
+ for (; i < 0x60; i++)
+ nv_wr32(priv, 0x10ec00 + soff, (i << 8));
+ nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000003);
+ } else {
+ if (outp->info.type == DCB_OUTPUT_DP) {
+ nv_mask(priv, 0x616618 + hoff, 0x80000001, 0x80000000);
+ nv_wait(priv, 0x616618 + hoff, 0x80000000, 0x00000000);
+ }
+ nv_mask(priv, 0x10ec10 + soff, 0x80000003, 0x80000000 | !!size);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
new file mode 100644
index 000000000000..891d1e7bf7d2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdagt215.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gt215_hda_eld(NV50_DISP_MTHD_V1)
+{
+ union {
+ struct nv50_disp_sor_hda_eld_v0 v0;
+ } *args = data;
+ const u32 soff = outp->or * 0x800;
+ int ret, i;
+
+ nv_ioctl(object, "disp sor hda eld size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "disp sor hda eld vers %d\n", args->v0.version);
+ if (size > 0x60)
+ return -E2BIG;
+ } else
+ return ret;
+
+ if (size && args->v0.data[0]) {
+ if (outp->info.type == DCB_OUTPUT_DP) {
+ nv_mask(priv, 0x61c1e0 + soff, 0x8000000d, 0x80000001);
+ nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
+ }
+ for (i = 0; i < size; i++)
+ nv_wr32(priv, 0x61c440 + soff, (i << 8) | args->v0.data[0]);
+ for (; i < 0x60; i++)
+ nv_wr32(priv, 0x61c440 + soff, (i << 8));
+ nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000003);
+ } else {
+ if (outp->info.type == DCB_OUTPUT_DP) {
+ nv_mask(priv, 0x61c1e0 + soff, 0x80000001, 0x80000000);
+ nv_wait(priv, 0x61c1e0 + soff, 0x80000000, 0x00000000);
+ }
+ nv_mask(priv, 0x61c448 + soff, 0x80000003, 0x80000000 | !!size);
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
new file mode 100644
index 000000000000..621cb0b7ff19
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmig84.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+g84_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+ const u32 hoff = (head * 0x800);
+ union {
+ struct nv50_disp_sor_hdmi_pwr_v0 v0;
+ } *args = data;
+ u32 ctrl;
+ int ret;
+
+ nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+ "max_ac_packet %d rekey %d\n",
+ args->v0.version, args->v0.state,
+ args->v0.max_ac_packet, args->v0.rekey);
+ if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+ return -EINVAL;
+ ctrl = 0x40000000 * !!args->v0.state;
+ ctrl |= args->v0.max_ac_packet << 16;
+ ctrl |= args->v0.rekey;
+ ctrl |= 0x1f000000; /* ??? */
+ } else
+ return ret;
+
+ if (!(ctrl & 0x40000000)) {
+ nv_mask(priv, 0x6165a4 + hoff, 0x40000000, 0x00000000);
+ nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
+ nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
+ return 0;
+ }
+
+ /* AVI InfoFrame */
+ nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x616528 + hoff, 0x000d0282);
+ nv_wr32(priv, 0x61652c + hoff, 0x0000006f);
+ nv_wr32(priv, 0x616530 + hoff, 0x00000000);
+ nv_wr32(priv, 0x616534 + hoff, 0x00000000);
+ nv_wr32(priv, 0x616538 + hoff, 0x00000000);
+ nv_mask(priv, 0x616520 + hoff, 0x00000001, 0x00000001);
+
+ /* Audio InfoFrame */
+ nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x616508 + hoff, 0x000a0184);
+ nv_wr32(priv, 0x61650c + hoff, 0x00000071);
+ nv_wr32(priv, 0x616510 + hoff, 0x00000000);
+ nv_mask(priv, 0x616500 + hoff, 0x00000001, 0x00000001);
+
+ nv_mask(priv, 0x6165d0 + hoff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+ nv_mask(priv, 0x616568 + hoff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+ nv_mask(priv, 0x616578 + hoff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
+ /* ??? */
+ nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
+ nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
+ nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
+
+ /* HDMI_CTRL */
+ nv_mask(priv, 0x6165a4 + hoff, 0x5f1f007f, ctrl);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c
new file mode 100644
index 000000000000..c28449061bbd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigf110.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gf110_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+ const u32 hoff = (head * 0x800);
+ union {
+ struct nv50_disp_sor_hdmi_pwr_v0 v0;
+ } *args = data;
+ u32 ctrl;
+ int ret;
+
+ nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+ "max_ac_packet %d rekey %d\n",
+ args->v0.version, args->v0.state,
+ args->v0.max_ac_packet, args->v0.rekey);
+ if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+ return -EINVAL;
+ ctrl = 0x40000000 * !!args->v0.state;
+ ctrl |= args->v0.max_ac_packet << 16;
+ ctrl |= args->v0.rekey;
+ } else
+ return ret;
+
+ if (!(ctrl & 0x40000000)) {
+ nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
+ nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
+ nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
+ return 0;
+ }
+
+ /* AVI InfoFrame */
+ nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x61671c + hoff, 0x000d0282);
+ nv_wr32(priv, 0x616720 + hoff, 0x0000006f);
+ nv_wr32(priv, 0x616724 + hoff, 0x00000000);
+ nv_wr32(priv, 0x616728 + hoff, 0x00000000);
+ nv_wr32(priv, 0x61672c + hoff, 0x00000000);
+ nv_mask(priv, 0x616714 + hoff, 0x00000001, 0x00000001);
+
+ /* ??? InfoFrame? */
+ nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x6167ac + hoff, 0x00000010);
+ nv_mask(priv, 0x6167a4 + hoff, 0x00000001, 0x00000001);
+
+ /* HDMI_CTRL */
+ nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
new file mode 100644
index 000000000000..ca34ff81ad7f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigk104.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gk104_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+ const u32 hoff = (head * 0x800);
+ const u32 hdmi = (head * 0x400);
+ union {
+ struct nv50_disp_sor_hdmi_pwr_v0 v0;
+ } *args = data;
+ u32 ctrl;
+ int ret;
+
+ nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+ "max_ac_packet %d rekey %d\n",
+ args->v0.version, args->v0.state,
+ args->v0.max_ac_packet, args->v0.rekey);
+ if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+ return -EINVAL;
+ ctrl = 0x40000000 * !!args->v0.state;
+ ctrl |= args->v0.max_ac_packet << 16;
+ ctrl |= args->v0.rekey;
+ } else
+ return ret;
+
+ if (!(ctrl & 0x40000000)) {
+ nv_mask(priv, 0x616798 + hoff, 0x40000000, 0x00000000);
+ nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
+ nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
+ return 0;
+ }
+
+ /* AVI InfoFrame */
+ nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x690008 + hdmi, 0x000d0282);
+ nv_wr32(priv, 0x69000c + hdmi, 0x0000006f);
+ nv_wr32(priv, 0x690010 + hdmi, 0x00000000);
+ nv_wr32(priv, 0x690014 + hdmi, 0x00000000);
+ nv_wr32(priv, 0x690018 + hdmi, 0x00000000);
+ nv_mask(priv, 0x690000 + hdmi, 0x00000001, 0x00000001);
+
+ /* ??? InfoFrame? */
+ nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x6900cc + hdmi, 0x00000010);
+ nv_mask(priv, 0x6900c0 + hdmi, 0x00000001, 0x00000001);
+
+ /* ??? */
+ nv_wr32(priv, 0x690080 + hdmi, 0x82000000);
+
+ /* HDMI_CTRL */
+ nv_mask(priv, 0x616798 + hoff, 0x401f007f, ctrl);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
new file mode 100644
index 000000000000..b641c167dcfa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/hdmigt215.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+gt215_hdmi_ctrl(NV50_DISP_MTHD_V1)
+{
+ const u32 soff = outp->or * 0x800;
+ union {
+ struct nv50_disp_sor_hdmi_pwr_v0 v0;
+ } *args = data;
+ u32 ctrl;
+ int ret;
+
+ nv_ioctl(object, "disp sor hdmi ctrl size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor hdmi ctrl vers %d state %d "
+ "max_ac_packet %d rekey %d\n",
+ args->v0.version, args->v0.state,
+ args->v0.max_ac_packet, args->v0.rekey);
+ if (args->v0.max_ac_packet > 0x1f || args->v0.rekey > 0x7f)
+ return -EINVAL;
+ ctrl = 0x40000000 * !!args->v0.state;
+ ctrl |= args->v0.max_ac_packet << 16;
+ ctrl |= args->v0.rekey;
+ ctrl |= 0x1f000000; /* ??? */
+ } else
+ return ret;
+
+ if (!(ctrl & 0x40000000)) {
+ nv_mask(priv, 0x61c5a4 + soff, 0x40000000, 0x00000000);
+ nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
+ nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
+ return 0;
+ }
+
+ /* AVI InfoFrame */
+ nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x61c528 + soff, 0x000d0282);
+ nv_wr32(priv, 0x61c52c + soff, 0x0000006f);
+ nv_wr32(priv, 0x61c530 + soff, 0x00000000);
+ nv_wr32(priv, 0x61c534 + soff, 0x00000000);
+ nv_wr32(priv, 0x61c538 + soff, 0x00000000);
+ nv_mask(priv, 0x61c520 + soff, 0x00000001, 0x00000001);
+
+ /* Audio InfoFrame */
+ nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000000);
+ nv_wr32(priv, 0x61c508 + soff, 0x000a0184);
+ nv_wr32(priv, 0x61c50c + soff, 0x00000071);
+ nv_wr32(priv, 0x61c510 + soff, 0x00000000);
+ nv_mask(priv, 0x61c500 + soff, 0x00000001, 0x00000001);
+
+ nv_mask(priv, 0x61c5d0 + soff, 0x00070001, 0x00010001); /* SPARE, HW_CTS */
+ nv_mask(priv, 0x61c568 + soff, 0x00010101, 0x00000000); /* ACR_CTRL, ?? */
+ nv_mask(priv, 0x61c578 + soff, 0x80000000, 0x80000000); /* ACR_0441_ENABLE */
+
+ /* ??? */
+ nv_mask(priv, 0x61733c, 0x00100000, 0x00100000); /* RESETF */
+ nv_mask(priv, 0x61733c, 0x10000000, 0x10000000); /* LOOKUP_EN */
+ nv_mask(priv, 0x61733c, 0x00100000, 0x00000000); /* !RESETF */
+
+ /* HDMI_CTRL */
+ nv_mask(priv, 0x61c5a4 + soff, 0x5f1f007f, ctrl);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
new file mode 100644
index 000000000000..ff09b2659c17
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv04.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/device.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct nv04_disp_priv {
+ struct nvkm_disp base;
+};
+
+static int
+nv04_disp_scanoutpos(struct nvkm_object *object, struct nv04_disp_priv *priv,
+ void *data, u32 size, int head)
+{
+ const u32 hoff = head * 0x2000;
+ union {
+ struct nv04_disp_scanoutpos_v0 v0;
+ } *args = data;
+ u32 line;
+ int ret;
+
+ nv_ioctl(object, "disp scanoutpos size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+ args->v0.vblanks = nv_rd32(priv, 0x680800 + hoff) & 0xffff;
+ args->v0.vtotal = nv_rd32(priv, 0x680804 + hoff) & 0xffff;
+ args->v0.vblanke = args->v0.vtotal - 1;
+
+ args->v0.hblanks = nv_rd32(priv, 0x680820 + hoff) & 0xffff;
+ args->v0.htotal = nv_rd32(priv, 0x680824 + hoff) & 0xffff;
+ args->v0.hblanke = args->v0.htotal - 1;
+
+ /*
+ * If output is vga instead of digital then vtotal/htotal is
+ * invalid so we have to give up and trigger the timestamping
+ * fallback in the drm core.
+ */
+ if (!args->v0.vtotal || !args->v0.htotal)
+ return -ENOTSUPP;
+
+ args->v0.time[0] = ktime_to_ns(ktime_get());
+ line = nv_rd32(priv, 0x600868 + hoff);
+ args->v0.time[1] = ktime_to_ns(ktime_get());
+ args->v0.hline = (line & 0xffff0000) >> 16;
+ args->v0.vline = (line & 0x0000ffff);
+ } else
+ return ret;
+
+ return 0;
+}
+
+static int
+nv04_disp_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ union {
+ struct nv04_disp_mthd_v0 v0;
+ } *args = data;
+ struct nv04_disp_priv *priv = (void *)object->engine;
+ int head, ret;
+
+ nv_ioctl(object, "disp mthd size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
+ args->v0.version, args->v0.method, args->v0.head);
+ mthd = args->v0.method;
+ head = args->v0.head;
+ } else
+ return ret;
+
+ if (head < 0 || head >= 2)
+ return -ENXIO;
+
+ switch (mthd) {
+ case NV04_DISP_SCANOUTPOS:
+ return nv04_disp_scanoutpos(object, priv, data, size, head);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static struct nvkm_ofuncs
+nv04_disp_ofuncs = {
+ .ctor = _nvkm_object_ctor,
+ .dtor = nvkm_object_destroy,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ .mthd = nv04_disp_mthd,
+ .ntfy = nvkm_disp_ntfy,
+};
+
+static struct nvkm_oclass
+nv04_disp_sclass[] = {
+ { NV04_DISP, &nv04_disp_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+nv04_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+ nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000001);
+}
+
+static void
+nv04_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+ nv_wr32(disp, 0x600140 + (head * 0x2000) , 0x00000000);
+}
+
+static const struct nvkm_event_func
+nv04_disp_vblank_func = {
+ .ctor = nvkm_disp_vblank_ctor,
+ .init = nv04_disp_vblank_init,
+ .fini = nv04_disp_vblank_fini,
+};
+
+static void
+nv04_disp_intr(struct nvkm_subdev *subdev)
+{
+ struct nv04_disp_priv *priv = (void *)subdev;
+ u32 crtc0 = nv_rd32(priv, 0x600100);
+ u32 crtc1 = nv_rd32(priv, 0x602100);
+ u32 pvideo;
+
+ if (crtc0 & 0x00000001) {
+ nvkm_disp_vblank(&priv->base, 0);
+ nv_wr32(priv, 0x600100, 0x00000001);
+ }
+
+ if (crtc1 & 0x00000001) {
+ nvkm_disp_vblank(&priv->base, 1);
+ nv_wr32(priv, 0x602100, 0x00000001);
+ }
+
+ if (nv_device(priv)->chipset >= 0x10 &&
+ nv_device(priv)->chipset <= 0x40) {
+ pvideo = nv_rd32(priv, 0x8100);
+ if (pvideo & ~0x11)
+ nv_info(priv, "PVIDEO intr: %08x\n", pvideo);
+ nv_wr32(priv, 0x8100, pvideo);
+ }
+}
+
+static int
+nv04_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_disp_priv *priv;
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, 2, "DISPLAY",
+ "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = nv04_disp_sclass;
+ nv_subdev(priv)->intr = nv04_disp_intr;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_disp_oclass = &(struct nvkm_disp_impl) {
+ .base.handle = NV_ENGINE(DISP, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .vblank = &nv04_disp_vblank_func,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
new file mode 100644
index 000000000000..84ade810e27c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.c
@@ -0,0 +1,2019 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+#include "outpdp.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+#include <core/handle.h>
+#include <core/ramht.h>
+#include <engine/dmaobj.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/disp.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/devinit.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * EVO channel base class
+ ******************************************************************************/
+
+static int
+nv50_disp_chan_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int head,
+ int length, void **pobject)
+{
+ const struct nv50_disp_chan_impl *impl = (void *)oclass->ofuncs;
+ struct nv50_disp_base *base = (void *)parent;
+ struct nv50_disp_chan *chan;
+ int chid = impl->chid + head;
+ int ret;
+
+ if (base->chan & (1 << chid))
+ return -EBUSY;
+ base->chan |= (1 << chid);
+
+ ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL,
+ (1ULL << NVDEV_ENGINE_DMAOBJ),
+ length, pobject);
+ chan = *pobject;
+ if (ret)
+ return ret;
+ chan->chid = chid;
+
+ nv_parent(chan)->object_attach = impl->attach;
+ nv_parent(chan)->object_detach = impl->detach;
+ return 0;
+}
+
+static void
+nv50_disp_chan_destroy(struct nv50_disp_chan *chan)
+{
+ struct nv50_disp_base *base = (void *)nv_object(chan)->parent;
+ base->chan &= ~(1 << chan->chid);
+ nvkm_namedb_destroy(&chan->base);
+}
+
+static void
+nv50_disp_chan_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+ nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000000 << index);
+ nv_wr32(priv, 0x610020, 0x00000001 << index);
+}
+
+static void
+nv50_disp_chan_uevent_init(struct nvkm_event *event, int types, int index)
+{
+ struct nv50_disp_priv *priv = container_of(event, typeof(*priv), uevent);
+ nv_wr32(priv, 0x610020, 0x00000001 << index);
+ nv_mask(priv, 0x610028, 0x00000001 << index, 0x00000001 << index);
+}
+
+void
+nv50_disp_chan_uevent_send(struct nv50_disp_priv *priv, int chid)
+{
+ struct nvif_notify_uevent_rep {
+ } rep;
+
+ nvkm_event_send(&priv->uevent, 1, chid, &rep, sizeof(rep));
+}
+
+int
+nv50_disp_chan_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ struct nv50_disp_dmac *dmac = (void *)object;
+ union {
+ struct nvif_notify_uevent_req none;
+ } *args = data;
+ int ret;
+
+ if (nvif_unvers(args->none)) {
+ notify->size = sizeof(struct nvif_notify_uevent_rep);
+ notify->types = 1;
+ notify->index = dmac->base.chid;
+ return 0;
+ }
+
+ return ret;
+}
+
+const struct nvkm_event_func
+nv50_disp_chan_uevent = {
+ .ctor = nv50_disp_chan_uevent_ctor,
+ .init = nv50_disp_chan_uevent_init,
+ .fini = nv50_disp_chan_uevent_fini,
+};
+
+int
+nv50_disp_chan_ntfy(struct nvkm_object *object, u32 type,
+ struct nvkm_event **pevent)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ switch (type) {
+ case NV50_DISP_CORE_CHANNEL_DMA_V0_NTFY_UEVENT:
+ *pevent = &priv->uevent;
+ return 0;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+int
+nv50_disp_chan_map(struct nvkm_object *object, u64 *addr, u32 *size)
+{
+ struct nv50_disp_chan *chan = (void *)object;
+ *addr = nv_device_resource_start(nv_device(object), 0) +
+ 0x640000 + (chan->chid * 0x1000);
+ *size = 0x001000;
+ return 0;
+}
+
+u32
+nv50_disp_chan_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_chan *chan = (void *)object;
+ return nv_rd32(priv, 0x640000 + (chan->chid * 0x1000) + addr);
+}
+
+void
+nv50_disp_chan_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_chan *chan = (void *)object;
+ nv_wr32(priv, 0x640000 + (chan->chid * 0x1000) + addr, data);
+}
+
+/*******************************************************************************
+ * EVO DMA channel base class
+ ******************************************************************************/
+
+static int
+nv50_disp_dmac_object_attach(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 name)
+{
+ struct nv50_disp_base *base = (void *)parent->parent;
+ struct nv50_disp_chan *chan = (void *)parent;
+ u32 addr = nv_gpuobj(object)->node->offset;
+ u32 chid = chan->chid;
+ u32 data = (chid << 28) | (addr << 10) | chid;
+ return nvkm_ramht_insert(base->ramht, chid, name, data);
+}
+
+static void
+nv50_disp_dmac_object_detach(struct nvkm_object *parent, int cookie)
+{
+ struct nv50_disp_base *base = (void *)parent->parent;
+ nvkm_ramht_remove(base->ramht, cookie);
+}
+
+static int
+nv50_disp_dmac_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 pushbuf, int head,
+ int length, void **pobject)
+{
+ struct nv50_disp_dmac *dmac;
+ int ret;
+
+ ret = nv50_disp_chan_create_(parent, engine, oclass, head,
+ length, pobject);
+ dmac = *pobject;
+ if (ret)
+ return ret;
+
+ dmac->pushdma = (void *)nvkm_handle_ref(parent, pushbuf);
+ if (!dmac->pushdma)
+ return -ENOENT;
+
+ switch (nv_mclass(dmac->pushdma)) {
+ case 0x0002:
+ case 0x003d:
+ if (dmac->pushdma->limit - dmac->pushdma->start != 0xfff)
+ return -EINVAL;
+
+ switch (dmac->pushdma->target) {
+ case NV_MEM_TARGET_VRAM:
+ dmac->push = 0x00000000 | dmac->pushdma->start >> 8;
+ break;
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ dmac->push = 0x00000003 | dmac->pushdma->start >> 8;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void
+nv50_disp_dmac_dtor(struct nvkm_object *object)
+{
+ struct nv50_disp_dmac *dmac = (void *)object;
+ nvkm_object_ref(NULL, (struct nvkm_object **)&dmac->pushdma);
+ nv50_disp_chan_destroy(&dmac->base);
+}
+
+static int
+nv50_disp_dmac_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *dmac = (void *)object;
+ int chid = dmac->base.chid;
+ int ret;
+
+ ret = nv50_disp_chan_init(&dmac->base);
+ if (ret)
+ return ret;
+
+ /* enable error reporting */
+ nv_mask(priv, 0x610028, 0x00010000 << chid, 0x00010000 << chid);
+
+ /* initialise channel for dma command submission */
+ nv_wr32(priv, 0x610204 + (chid * 0x0010), dmac->push);
+ nv_wr32(priv, 0x610208 + (chid * 0x0010), 0x00010000);
+ nv_wr32(priv, 0x61020c + (chid * 0x0010), chid);
+ nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000010, 0x00000010);
+ nv_wr32(priv, 0x640000 + (chid * 0x1000), 0x00000000);
+ nv_wr32(priv, 0x610200 + (chid * 0x0010), 0x00000013);
+
+ /* wait for it to go inactive */
+ if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x80000000, 0x00000000)) {
+ nv_error(dmac, "init timeout, 0x%08x\n",
+ nv_rd32(priv, 0x610200 + (chid * 0x10)));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv50_disp_dmac_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *dmac = (void *)object;
+ int chid = dmac->base.chid;
+
+ /* deactivate channel */
+ nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00001010, 0x00001000);
+ nv_mask(priv, 0x610200 + (chid * 0x0010), 0x00000003, 0x00000000);
+ if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x001e0000, 0x00000000)) {
+ nv_error(dmac, "fini timeout, 0x%08x\n",
+ nv_rd32(priv, 0x610200 + (chid * 0x10)));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ /* disable error reporting and completion notifications */
+ nv_mask(priv, 0x610028, 0x00010001 << chid, 0x00000000 << chid);
+
+ return nv50_disp_chan_fini(&dmac->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO master channel object
+ ******************************************************************************/
+
+static void
+nv50_disp_mthd_list(struct nv50_disp_priv *priv, int debug, u32 base, int c,
+ const struct nv50_disp_mthd_list *list, int inst)
+{
+ struct nvkm_object *disp = nv_object(priv);
+ int i;
+
+ for (i = 0; list->data[i].mthd; i++) {
+ if (list->data[i].addr) {
+ u32 next = nv_rd32(priv, list->data[i].addr + base + 0);
+ u32 prev = nv_rd32(priv, list->data[i].addr + base + c);
+ u32 mthd = list->data[i].mthd + (list->mthd * inst);
+ const char *name = list->data[i].name;
+ char mods[16];
+
+ if (prev != next)
+ snprintf(mods, sizeof(mods), "-> 0x%08x", next);
+ else
+ snprintf(mods, sizeof(mods), "%13c", ' ');
+
+ nv_printk_(disp, debug, "\t0x%04x: 0x%08x %s%s%s\n",
+ mthd, prev, mods, name ? " // " : "",
+ name ? name : "");
+ }
+ }
+}
+
+void
+nv50_disp_mthd_chan(struct nv50_disp_priv *priv, int debug, int head,
+ const struct nv50_disp_mthd_chan *chan)
+{
+ struct nvkm_object *disp = nv_object(priv);
+ const struct nv50_disp_impl *impl = (void *)disp->oclass;
+ const struct nv50_disp_mthd_list *list;
+ int i, j;
+
+ if (debug > nv_subdev(priv)->debug)
+ return;
+
+ for (i = 0; (list = chan->data[i].mthd) != NULL; i++) {
+ u32 base = head * chan->addr;
+ for (j = 0; j < chan->data[i].nr; j++, base += list->addr) {
+ const char *cname = chan->name;
+ const char *sname = "";
+ char cname_[16], sname_[16];
+
+ if (chan->addr) {
+ snprintf(cname_, sizeof(cname_), "%s %d",
+ chan->name, head);
+ cname = cname_;
+ }
+
+ if (chan->data[i].nr > 1) {
+ snprintf(sname_, sizeof(sname_), " - %s %d",
+ chan->data[i].name, j);
+ sname = sname_;
+ }
+
+ nv_printk_(disp, debug, "%s%s:\n", cname, sname);
+ nv50_disp_mthd_list(priv, debug, base, impl->mthd.prev,
+ list, j);
+ }
+ }
+}
+
+const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x000000 },
+ { 0x0084, 0x610bb8 },
+ { 0x0088, 0x610b9c },
+ { 0x008c, 0x000000 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_dac = {
+ .mthd = 0x0080,
+ .addr = 0x000008,
+ .data = {
+ { 0x0400, 0x610b58 },
+ { 0x0404, 0x610bdc },
+ { 0x0420, 0x610828 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_sor = {
+ .mthd = 0x0040,
+ .addr = 0x000008,
+ .data = {
+ { 0x0600, 0x610b70 },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_pior = {
+ .mthd = 0x0040,
+ .addr = 0x000008,
+ .data = {
+ { 0x0700, 0x610b80 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_list
+nv50_disp_core_mthd_head = {
+ .mthd = 0x0400,
+ .addr = 0x000540,
+ .data = {
+ { 0x0800, 0x610ad8 },
+ { 0x0804, 0x610ad0 },
+ { 0x0808, 0x610a48 },
+ { 0x080c, 0x610a78 },
+ { 0x0810, 0x610ac0 },
+ { 0x0814, 0x610af8 },
+ { 0x0818, 0x610b00 },
+ { 0x081c, 0x610ae8 },
+ { 0x0820, 0x610af0 },
+ { 0x0824, 0x610b08 },
+ { 0x0828, 0x610b10 },
+ { 0x082c, 0x610a68 },
+ { 0x0830, 0x610a60 },
+ { 0x0834, 0x000000 },
+ { 0x0838, 0x610a40 },
+ { 0x0840, 0x610a24 },
+ { 0x0844, 0x610a2c },
+ { 0x0848, 0x610aa8 },
+ { 0x084c, 0x610ab0 },
+ { 0x0860, 0x610a84 },
+ { 0x0864, 0x610a90 },
+ { 0x0868, 0x610b18 },
+ { 0x086c, 0x610b20 },
+ { 0x0870, 0x610ac8 },
+ { 0x0874, 0x610a38 },
+ { 0x0880, 0x610a58 },
+ { 0x0884, 0x610a9c },
+ { 0x08a0, 0x610a70 },
+ { 0x08a4, 0x610a50 },
+ { 0x08a8, 0x610ae0 },
+ { 0x08c0, 0x610b28 },
+ { 0x08c4, 0x610b30 },
+ { 0x08c8, 0x610b40 },
+ { 0x08d4, 0x610b38 },
+ { 0x08d8, 0x610b48 },
+ { 0x08dc, 0x610b50 },
+ { 0x0900, 0x610a18 },
+ { 0x0904, 0x610ab8 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_core_mthd_chan = {
+ .name = "Core",
+ .addr = 0x000000,
+ .data = {
+ { "Global", 1, &nv50_disp_core_mthd_base },
+ { "DAC", 3, &nv50_disp_core_mthd_dac },
+ { "SOR", 2, &nv50_disp_core_mthd_sor },
+ { "PIOR", 3, &nv50_disp_core_mthd_pior },
+ { "HEAD", 2, &nv50_disp_core_mthd_head },
+ {}
+ }
+};
+
+int
+nv50_disp_core_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_disp_core_channel_dma_v0 v0;
+ } *args = data;
+ struct nv50_disp_dmac *mast;
+ int ret;
+
+ nv_ioctl(parent, "create disp core channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create disp core channel dma vers %d "
+ "pushbuf %08x\n",
+ args->v0.version, args->v0.pushbuf);
+ } else
+ return ret;
+
+ ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
+ 0, sizeof(*mast), (void **)&mast);
+ *pobject = nv_object(mast);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv50_disp_core_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *mast = (void *)object;
+ int ret;
+
+ ret = nv50_disp_chan_init(&mast->base);
+ if (ret)
+ return ret;
+
+ /* enable error reporting */
+ nv_mask(priv, 0x610028, 0x00010000, 0x00010000);
+
+ /* attempt to unstick channel from some unknown state */
+ if ((nv_rd32(priv, 0x610200) & 0x009f0000) == 0x00020000)
+ nv_mask(priv, 0x610200, 0x00800000, 0x00800000);
+ if ((nv_rd32(priv, 0x610200) & 0x003f0000) == 0x00030000)
+ nv_mask(priv, 0x610200, 0x00600000, 0x00600000);
+
+ /* initialise channel for dma command submission */
+ nv_wr32(priv, 0x610204, mast->push);
+ nv_wr32(priv, 0x610208, 0x00010000);
+ nv_wr32(priv, 0x61020c, 0x00000000);
+ nv_mask(priv, 0x610200, 0x00000010, 0x00000010);
+ nv_wr32(priv, 0x640000, 0x00000000);
+ nv_wr32(priv, 0x610200, 0x01000013);
+
+ /* wait for it to go inactive */
+ if (!nv_wait(priv, 0x610200, 0x80000000, 0x00000000)) {
+ nv_error(mast, "init: 0x%08x\n", nv_rd32(priv, 0x610200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv50_disp_core_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_dmac *mast = (void *)object;
+
+ /* deactivate channel */
+ nv_mask(priv, 0x610200, 0x00000010, 0x00000000);
+ nv_mask(priv, 0x610200, 0x00000003, 0x00000000);
+ if (!nv_wait(priv, 0x610200, 0x001e0000, 0x00000000)) {
+ nv_error(mast, "fini: 0x%08x\n", nv_rd32(priv, 0x610200));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ /* disable error reporting and completion notifications */
+ nv_mask(priv, 0x610028, 0x00010001, 0x00000000);
+
+ return nv50_disp_chan_fini(&mast->base, suspend);
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_core_ofuncs = {
+ .base.ctor = nv50_disp_core_ctor,
+ .base.dtor = nv50_disp_dmac_dtor,
+ .base.init = nv50_disp_core_init,
+ .base.fini = nv50_disp_core_fini,
+ .base.map = nv50_disp_chan_map,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 0,
+ .attach = nv50_disp_dmac_object_attach,
+ .detach = nv50_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO sync channel objects
+ ******************************************************************************/
+
+static const struct nv50_disp_mthd_list
+nv50_disp_base_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x000000 },
+ { 0x0084, 0x0008c4 },
+ { 0x0088, 0x0008d0 },
+ { 0x008c, 0x0008dc },
+ { 0x0090, 0x0008e4 },
+ { 0x0094, 0x610884 },
+ { 0x00a0, 0x6108a0 },
+ { 0x00a4, 0x610878 },
+ { 0x00c0, 0x61086c },
+ { 0x00e0, 0x610858 },
+ { 0x00e4, 0x610860 },
+ { 0x00e8, 0x6108ac },
+ { 0x00ec, 0x6108b4 },
+ { 0x0100, 0x610894 },
+ { 0x0110, 0x6108bc },
+ { 0x0114, 0x61088c },
+ {}
+ }
+};
+
+const struct nv50_disp_mthd_list
+nv50_disp_base_mthd_image = {
+ .mthd = 0x0400,
+ .addr = 0x000000,
+ .data = {
+ { 0x0800, 0x6108f0 },
+ { 0x0804, 0x6108fc },
+ { 0x0808, 0x61090c },
+ { 0x080c, 0x610914 },
+ { 0x0810, 0x610904 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_base_mthd_chan = {
+ .name = "Base",
+ .addr = 0x000540,
+ .data = {
+ { "Global", 1, &nv50_disp_base_mthd_base },
+ { "Image", 2, &nv50_disp_base_mthd_image },
+ {}
+ }
+};
+
+int
+nv50_disp_base_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_disp_base_channel_dma_v0 v0;
+ } *args = data;
+ struct nv50_disp_priv *priv = (void *)engine;
+ struct nv50_disp_dmac *dmac;
+ int ret;
+
+ nv_ioctl(parent, "create disp base channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create disp base channel dma vers %d "
+ "pushbuf %08x head %d\n",
+ args->v0.version, args->v0.pushbuf, args->v0.head);
+ if (args->v0.head > priv->head.nr)
+ return -EINVAL;
+ } else
+ return ret;
+
+ ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
+ args->v0.head, sizeof(*dmac),
+ (void **)&dmac);
+ *pobject = nv_object(dmac);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_base_ofuncs = {
+ .base.ctor = nv50_disp_base_ctor,
+ .base.dtor = nv50_disp_dmac_dtor,
+ .base.init = nv50_disp_dmac_init,
+ .base.fini = nv50_disp_dmac_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 1,
+ .attach = nv50_disp_dmac_object_attach,
+ .detach = nv50_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO overlay channel objects
+ ******************************************************************************/
+
+const struct nv50_disp_mthd_list
+nv50_disp_ovly_mthd_base = {
+ .mthd = 0x0000,
+ .addr = 0x000000,
+ .data = {
+ { 0x0080, 0x000000 },
+ { 0x0084, 0x0009a0 },
+ { 0x0088, 0x0009c0 },
+ { 0x008c, 0x0009c8 },
+ { 0x0090, 0x6109b4 },
+ { 0x0094, 0x610970 },
+ { 0x00a0, 0x610998 },
+ { 0x00a4, 0x610964 },
+ { 0x00c0, 0x610958 },
+ { 0x00e0, 0x6109a8 },
+ { 0x00e4, 0x6109d0 },
+ { 0x00e8, 0x6109d8 },
+ { 0x0100, 0x61094c },
+ { 0x0104, 0x610984 },
+ { 0x0108, 0x61098c },
+ { 0x0800, 0x6109f8 },
+ { 0x0808, 0x610a08 },
+ { 0x080c, 0x610a10 },
+ { 0x0810, 0x610a00 },
+ {}
+ }
+};
+
+static const struct nv50_disp_mthd_chan
+nv50_disp_ovly_mthd_chan = {
+ .name = "Overlay",
+ .addr = 0x000540,
+ .data = {
+ { "Global", 1, &nv50_disp_ovly_mthd_base },
+ {}
+ }
+};
+
+int
+nv50_disp_ovly_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_disp_overlay_channel_dma_v0 v0;
+ } *args = data;
+ struct nv50_disp_priv *priv = (void *)engine;
+ struct nv50_disp_dmac *dmac;
+ int ret;
+
+ nv_ioctl(parent, "create disp overlay channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create disp overlay channel dma vers %d "
+ "pushbuf %08x head %d\n",
+ args->v0.version, args->v0.pushbuf, args->v0.head);
+ if (args->v0.head > priv->head.nr)
+ return -EINVAL;
+ } else
+ return ret;
+
+ ret = nv50_disp_dmac_create_(parent, engine, oclass, args->v0.pushbuf,
+ args->v0.head, sizeof(*dmac),
+ (void **)&dmac);
+ *pobject = nv_object(dmac);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_ovly_ofuncs = {
+ .base.ctor = nv50_disp_ovly_ctor,
+ .base.dtor = nv50_disp_dmac_dtor,
+ .base.init = nv50_disp_dmac_init,
+ .base.fini = nv50_disp_dmac_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 3,
+ .attach = nv50_disp_dmac_object_attach,
+ .detach = nv50_disp_dmac_object_detach,
+};
+
+/*******************************************************************************
+ * EVO PIO channel base class
+ ******************************************************************************/
+
+static int
+nv50_disp_pioc_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int head,
+ int length, void **pobject)
+{
+ return nv50_disp_chan_create_(parent, engine, oclass, head,
+ length, pobject);
+}
+
+void
+nv50_disp_pioc_dtor(struct nvkm_object *object)
+{
+ struct nv50_disp_pioc *pioc = (void *)object;
+ nv50_disp_chan_destroy(&pioc->base);
+}
+
+static int
+nv50_disp_pioc_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_pioc *pioc = (void *)object;
+ int chid = pioc->base.chid;
+ int ret;
+
+ ret = nv50_disp_chan_init(&pioc->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00002000);
+ if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00000000, 0x00000000)) {
+ nv_error(pioc, "timeout0: 0x%08x\n",
+ nv_rd32(priv, 0x610200 + (chid * 0x10)));
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x610200 + (chid * 0x10), 0x00000001);
+ if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00010000)) {
+ nv_error(pioc, "timeout1: 0x%08x\n",
+ nv_rd32(priv, 0x610200 + (chid * 0x10)));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static int
+nv50_disp_pioc_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_pioc *pioc = (void *)object;
+ int chid = pioc->base.chid;
+
+ nv_mask(priv, 0x610200 + (chid * 0x10), 0x00000001, 0x00000000);
+ if (!nv_wait(priv, 0x610200 + (chid * 0x10), 0x00030000, 0x00000000)) {
+ nv_error(pioc, "timeout: 0x%08x\n",
+ nv_rd32(priv, 0x610200 + (chid * 0x10)));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ return nv50_disp_chan_fini(&pioc->base, suspend);
+}
+
+/*******************************************************************************
+ * EVO immediate overlay channel objects
+ ******************************************************************************/
+
+int
+nv50_disp_oimm_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_disp_overlay_v0 v0;
+ } *args = data;
+ struct nv50_disp_priv *priv = (void *)engine;
+ struct nv50_disp_pioc *pioc;
+ int ret;
+
+ nv_ioctl(parent, "create disp overlay size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create disp overlay vers %d head %d\n",
+ args->v0.version, args->v0.head);
+ if (args->v0.head > priv->head.nr)
+ return -EINVAL;
+ } else
+ return ret;
+
+ ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
+ sizeof(*pioc), (void **)&pioc);
+ *pobject = nv_object(pioc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_oimm_ofuncs = {
+ .base.ctor = nv50_disp_oimm_ctor,
+ .base.dtor = nv50_disp_pioc_dtor,
+ .base.init = nv50_disp_pioc_init,
+ .base.fini = nv50_disp_pioc_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 5,
+};
+
+/*******************************************************************************
+ * EVO cursor channel objects
+ ******************************************************************************/
+
+int
+nv50_disp_curs_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_disp_cursor_v0 v0;
+ } *args = data;
+ struct nv50_disp_priv *priv = (void *)engine;
+ struct nv50_disp_pioc *pioc;
+ int ret;
+
+ nv_ioctl(parent, "create disp cursor size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create disp cursor vers %d head %d\n",
+ args->v0.version, args->v0.head);
+ if (args->v0.head > priv->head.nr)
+ return -EINVAL;
+ } else
+ return ret;
+
+ ret = nv50_disp_pioc_create_(parent, engine, oclass, args->v0.head,
+ sizeof(*pioc), (void **)&pioc);
+ *pobject = nv_object(pioc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nv50_disp_chan_impl
+nv50_disp_curs_ofuncs = {
+ .base.ctor = nv50_disp_curs_ctor,
+ .base.dtor = nv50_disp_pioc_dtor,
+ .base.init = nv50_disp_pioc_init,
+ .base.fini = nv50_disp_pioc_fini,
+ .base.ntfy = nv50_disp_chan_ntfy,
+ .base.map = nv50_disp_chan_map,
+ .base.rd32 = nv50_disp_chan_rd32,
+ .base.wr32 = nv50_disp_chan_wr32,
+ .chid = 7,
+};
+
+/*******************************************************************************
+ * Base display object
+ ******************************************************************************/
+
+int
+nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0)
+{
+ const u32 blanke = nv_rd32(priv, 0x610aec + (head * 0x540));
+ const u32 blanks = nv_rd32(priv, 0x610af4 + (head * 0x540));
+ const u32 total = nv_rd32(priv, 0x610afc + (head * 0x540));
+ union {
+ struct nv04_disp_scanoutpos_v0 v0;
+ } *args = data;
+ int ret;
+
+ nv_ioctl(object, "disp scanoutpos size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp scanoutpos vers %d\n", args->v0.version);
+ args->v0.vblanke = (blanke & 0xffff0000) >> 16;
+ args->v0.hblanke = (blanke & 0x0000ffff);
+ args->v0.vblanks = (blanks & 0xffff0000) >> 16;
+ args->v0.hblanks = (blanks & 0x0000ffff);
+ args->v0.vtotal = ( total & 0xffff0000) >> 16;
+ args->v0.htotal = ( total & 0x0000ffff);
+ args->v0.time[0] = ktime_to_ns(ktime_get());
+ args->v0.vline = /* vline read locks hline */
+ nv_rd32(priv, 0x616340 + (head * 0x800)) & 0xffff;
+ args->v0.time[1] = ktime_to_ns(ktime_get());
+ args->v0.hline =
+ nv_rd32(priv, 0x616344 + (head * 0x800)) & 0xffff;
+ } else
+ return ret;
+
+ return 0;
+}
+
+int
+nv50_disp_main_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ const struct nv50_disp_impl *impl = (void *)nv_oclass(object->engine);
+ union {
+ struct nv50_disp_mthd_v0 v0;
+ struct nv50_disp_mthd_v1 v1;
+ } *args = data;
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nvkm_output *outp = NULL;
+ struct nvkm_output *temp;
+ u16 type, mask = 0;
+ int head, ret;
+
+ if (mthd != NV50_DISP_MTHD)
+ return -EINVAL;
+
+ nv_ioctl(object, "disp mthd size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(object, "disp mthd vers %d mthd %02x head %d\n",
+ args->v0.version, args->v0.method, args->v0.head);
+ mthd = args->v0.method;
+ head = args->v0.head;
+ } else
+ if (nvif_unpack(args->v1, 1, 1, true)) {
+ nv_ioctl(object, "disp mthd vers %d mthd %02x "
+ "type %04x mask %04x\n",
+ args->v1.version, args->v1.method,
+ args->v1.hasht, args->v1.hashm);
+ mthd = args->v1.method;
+ type = args->v1.hasht;
+ mask = args->v1.hashm;
+ head = ffs((mask >> 8) & 0x0f) - 1;
+ } else
+ return ret;
+
+ if (head < 0 || head >= priv->head.nr)
+ return -ENXIO;
+
+ if (mask) {
+ list_for_each_entry(temp, &priv->base.outp, head) {
+ if ((temp->info.hasht == type) &&
+ (temp->info.hashm & mask) == mask) {
+ outp = temp;
+ break;
+ }
+ }
+ if (outp == NULL)
+ return -ENXIO;
+ }
+
+ switch (mthd) {
+ case NV50_DISP_SCANOUTPOS:
+ return impl->head.scanoutpos(object, priv, data, size, head);
+ default:
+ break;
+ }
+
+ switch (mthd * !!outp) {
+ case NV50_DISP_MTHD_V1_DAC_PWR:
+ return priv->dac.power(object, priv, data, size, head, outp);
+ case NV50_DISP_MTHD_V1_DAC_LOAD:
+ return priv->dac.sense(object, priv, data, size, head, outp);
+ case NV50_DISP_MTHD_V1_SOR_PWR:
+ return priv->sor.power(object, priv, data, size, head, outp);
+ case NV50_DISP_MTHD_V1_SOR_HDA_ELD:
+ if (!priv->sor.hda_eld)
+ return -ENODEV;
+ return priv->sor.hda_eld(object, priv, data, size, head, outp);
+ case NV50_DISP_MTHD_V1_SOR_HDMI_PWR:
+ if (!priv->sor.hdmi)
+ return -ENODEV;
+ return priv->sor.hdmi(object, priv, data, size, head, outp);
+ case NV50_DISP_MTHD_V1_SOR_LVDS_SCRIPT: {
+ union {
+ struct nv50_disp_sor_lvds_script_v0 v0;
+ } *args = data;
+ nv_ioctl(object, "disp sor lvds script size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor lvds script "
+ "vers %d name %04x\n",
+ args->v0.version, args->v0.script);
+ priv->sor.lvdsconf = args->v0.script;
+ return 0;
+ } else
+ return ret;
+ }
+ break;
+ case NV50_DISP_MTHD_V1_SOR_DP_PWR: {
+ struct nvkm_output_dp *outpdp = (void *)outp;
+ union {
+ struct nv50_disp_sor_dp_pwr_v0 v0;
+ } *args = data;
+ nv_ioctl(object, "disp sor dp pwr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor dp pwr vers %d state %d\n",
+ args->v0.version, args->v0.state);
+ if (args->v0.state == 0) {
+ nvkm_notify_put(&outpdp->irq);
+ ((struct nvkm_output_dp_impl *)nv_oclass(outp))
+ ->lnk_pwr(outpdp, 0);
+ atomic_set(&outpdp->lt.done, 0);
+ return 0;
+ } else
+ if (args->v0.state != 0) {
+ nvkm_output_dp_train(&outpdp->base, 0, true);
+ return 0;
+ }
+ } else
+ return ret;
+ }
+ break;
+ case NV50_DISP_MTHD_V1_PIOR_PWR:
+ if (!priv->pior.power)
+ return -ENODEV;
+ return priv->pior.power(object, priv, data, size, head, outp);
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+int
+nv50_disp_main_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv = (void *)engine;
+ struct nv50_disp_base *base;
+ int ret;
+
+ ret = nvkm_parent_create(parent, engine, oclass, 0,
+ priv->sclass, 0, &base);
+ *pobject = nv_object(base);
+ if (ret)
+ return ret;
+
+ return nvkm_ramht_new(nv_object(base), nv_object(base), 0x1000, 0,
+ &base->ramht);
+}
+
+void
+nv50_disp_main_dtor(struct nvkm_object *object)
+{
+ struct nv50_disp_base *base = (void *)object;
+ nvkm_ramht_ref(NULL, &base->ramht);
+ nvkm_parent_destroy(&base->base);
+}
+
+static int
+nv50_disp_main_init(struct nvkm_object *object)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_base *base = (void *)object;
+ int ret, i;
+ u32 tmp;
+
+ ret = nvkm_parent_init(&base->base);
+ if (ret)
+ return ret;
+
+ /* The below segments of code copying values from one register to
+ * another appear to inform EVO of the display capabilities or
+ * something similar. NFI what the 0x614004 caps are for..
+ */
+ tmp = nv_rd32(priv, 0x614004);
+ nv_wr32(priv, 0x610184, tmp);
+
+ /* ... CRTC caps */
+ for (i = 0; i < priv->head.nr; i++) {
+ tmp = nv_rd32(priv, 0x616100 + (i * 0x800));
+ nv_wr32(priv, 0x610190 + (i * 0x10), tmp);
+ tmp = nv_rd32(priv, 0x616104 + (i * 0x800));
+ nv_wr32(priv, 0x610194 + (i * 0x10), tmp);
+ tmp = nv_rd32(priv, 0x616108 + (i * 0x800));
+ nv_wr32(priv, 0x610198 + (i * 0x10), tmp);
+ tmp = nv_rd32(priv, 0x61610c + (i * 0x800));
+ nv_wr32(priv, 0x61019c + (i * 0x10), tmp);
+ }
+
+ /* ... DAC caps */
+ for (i = 0; i < priv->dac.nr; i++) {
+ tmp = nv_rd32(priv, 0x61a000 + (i * 0x800));
+ nv_wr32(priv, 0x6101d0 + (i * 0x04), tmp);
+ }
+
+ /* ... SOR caps */
+ for (i = 0; i < priv->sor.nr; i++) {
+ tmp = nv_rd32(priv, 0x61c000 + (i * 0x800));
+ nv_wr32(priv, 0x6101e0 + (i * 0x04), tmp);
+ }
+
+ /* ... PIOR caps */
+ for (i = 0; i < priv->pior.nr; i++) {
+ tmp = nv_rd32(priv, 0x61e000 + (i * 0x800));
+ nv_wr32(priv, 0x6101f0 + (i * 0x04), tmp);
+ }
+
+ /* steal display away from vbios, or something like that */
+ if (nv_rd32(priv, 0x610024) & 0x00000100) {
+ nv_wr32(priv, 0x610024, 0x00000100);
+ nv_mask(priv, 0x6194e8, 0x00000001, 0x00000000);
+ if (!nv_wait(priv, 0x6194e8, 0x00000002, 0x00000000)) {
+ nv_error(priv, "timeout acquiring display\n");
+ return -EBUSY;
+ }
+ }
+
+ /* point at display engine memory area (hash table, objects) */
+ nv_wr32(priv, 0x610010, (nv_gpuobj(base->ramht)->addr >> 8) | 9);
+
+ /* enable supervisor interrupts, disable everything else */
+ nv_wr32(priv, 0x61002c, 0x00000370);
+ nv_wr32(priv, 0x610028, 0x00000000);
+ return 0;
+}
+
+static int
+nv50_disp_main_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_disp_priv *priv = (void *)object->engine;
+ struct nv50_disp_base *base = (void *)object;
+
+ /* disable all interrupts */
+ nv_wr32(priv, 0x610024, 0x00000000);
+ nv_wr32(priv, 0x610020, 0x00000000);
+
+ return nvkm_parent_fini(&base->base, suspend);
+}
+
+struct nvkm_ofuncs
+nv50_disp_main_ofuncs = {
+ .ctor = nv50_disp_main_ctor,
+ .dtor = nv50_disp_main_dtor,
+ .init = nv50_disp_main_init,
+ .fini = nv50_disp_main_fini,
+ .mthd = nv50_disp_main_mthd,
+ .ntfy = nvkm_disp_ntfy,
+};
+
+static struct nvkm_oclass
+nv50_disp_main_oclass[] = {
+ { NV50_DISP, &nv50_disp_main_ofuncs },
+ {}
+};
+
+static struct nvkm_oclass
+nv50_disp_sclass[] = {
+ { NV50_DISP_CORE_CHANNEL_DMA, &nv50_disp_core_ofuncs.base },
+ { NV50_DISP_BASE_CHANNEL_DMA, &nv50_disp_base_ofuncs.base },
+ { NV50_DISP_OVERLAY_CHANNEL_DMA, &nv50_disp_ovly_ofuncs.base },
+ { NV50_DISP_OVERLAY, &nv50_disp_oimm_ofuncs.base },
+ { NV50_DISP_CURSOR, &nv50_disp_curs_ofuncs.base },
+ {}
+};
+
+/*******************************************************************************
+ * Display context, tracks instmem allocation and prevents more than one
+ * client using the display hardware at any time.
+ ******************************************************************************/
+
+static int
+nv50_disp_data_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv = (void *)engine;
+ struct nvkm_engctx *ectx;
+ int ret = -EBUSY;
+
+ /* no context needed for channel objects... */
+ if (nv_mclass(parent) != NV_DEVICE) {
+ atomic_inc(&parent->refcount);
+ *pobject = parent;
+ return 1;
+ }
+
+ /* allocate display hardware to client */
+ mutex_lock(&nv_subdev(priv)->mutex);
+ if (list_empty(&nv_engine(priv)->contexts)) {
+ ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000,
+ 0x10000, NVOBJ_FLAG_HEAP, &ectx);
+ *pobject = nv_object(ectx);
+ }
+ mutex_unlock(&nv_subdev(priv)->mutex);
+ return ret;
+}
+
+struct nvkm_oclass
+nv50_disp_cclass = {
+ .handle = NV_ENGCTX(DISP, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_disp_data_ctor,
+ .dtor = _nvkm_engctx_dtor,
+ .init = _nvkm_engctx_init,
+ .fini = _nvkm_engctx_fini,
+ .rd32 = _nvkm_engctx_rd32,
+ .wr32 = _nvkm_engctx_wr32,
+ },
+};
+
+/*******************************************************************************
+ * Display engine implementation
+ ******************************************************************************/
+
+static void
+nv50_disp_vblank_fini(struct nvkm_event *event, int type, int head)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+ nv_mask(disp, 0x61002c, (4 << head), 0);
+}
+
+static void
+nv50_disp_vblank_init(struct nvkm_event *event, int type, int head)
+{
+ struct nvkm_disp *disp = container_of(event, typeof(*disp), vblank);
+ nv_mask(disp, 0x61002c, (4 << head), (4 << head));
+}
+
+const struct nvkm_event_func
+nv50_disp_vblank_func = {
+ .ctor = nvkm_disp_vblank_ctor,
+ .init = nv50_disp_vblank_init,
+ .fini = nv50_disp_vblank_fini,
+};
+
+static const struct nvkm_enum
+nv50_disp_intr_error_type[] = {
+ { 3, "ILLEGAL_MTHD" },
+ { 4, "INVALID_VALUE" },
+ { 5, "INVALID_STATE" },
+ { 7, "INVALID_HANDLE" },
+ {}
+};
+
+static const struct nvkm_enum
+nv50_disp_intr_error_code[] = {
+ { 0x00, "" },
+ {}
+};
+
+static void
+nv50_disp_intr_error(struct nv50_disp_priv *priv, int chid)
+{
+ struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+ u32 data = nv_rd32(priv, 0x610084 + (chid * 0x08));
+ u32 addr = nv_rd32(priv, 0x610080 + (chid * 0x08));
+ u32 code = (addr & 0x00ff0000) >> 16;
+ u32 type = (addr & 0x00007000) >> 12;
+ u32 mthd = (addr & 0x00000ffc);
+ const struct nvkm_enum *ec, *et;
+ char ecunk[6], etunk[6];
+
+ et = nvkm_enum_find(nv50_disp_intr_error_type, type);
+ if (!et)
+ snprintf(etunk, sizeof(etunk), "UNK%02X", type);
+
+ ec = nvkm_enum_find(nv50_disp_intr_error_code, code);
+ if (!ec)
+ snprintf(ecunk, sizeof(ecunk), "UNK%02X", code);
+
+ nv_error(priv, "%s [%s] chid %d mthd 0x%04x data 0x%08x\n",
+ et ? et->name : etunk, ec ? ec->name : ecunk,
+ chid, mthd, data);
+
+ if (chid == 0) {
+ switch (mthd) {
+ case 0x0080:
+ nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 0,
+ impl->mthd.core);
+ break;
+ default:
+ break;
+ }
+ } else
+ if (chid <= 2) {
+ switch (mthd) {
+ case 0x0080:
+ nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 1,
+ impl->mthd.base);
+ break;
+ default:
+ break;
+ }
+ } else
+ if (chid <= 4) {
+ switch (mthd) {
+ case 0x0080:
+ nv50_disp_mthd_chan(priv, NV_DBG_ERROR, chid - 3,
+ impl->mthd.ovly);
+ break;
+ default:
+ break;
+ }
+ }
+
+ nv_wr32(priv, 0x610020, 0x00010000 << chid);
+ nv_wr32(priv, 0x610080 + (chid * 0x08), 0x90000000);
+}
+
+static struct nvkm_output *
+exec_lookup(struct nv50_disp_priv *priv, int head, int or, u32 ctrl,
+ u32 *data, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_outp *info)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvkm_output *outp;
+ u16 mask, type;
+
+ if (or < 4) {
+ type = DCB_OUTPUT_ANALOG;
+ mask = 0;
+ } else
+ if (or < 8) {
+ switch (ctrl & 0x00000f00) {
+ case 0x00000000: type = DCB_OUTPUT_LVDS; mask = 1; break;
+ case 0x00000100: type = DCB_OUTPUT_TMDS; mask = 1; break;
+ case 0x00000200: type = DCB_OUTPUT_TMDS; mask = 2; break;
+ case 0x00000500: type = DCB_OUTPUT_TMDS; mask = 3; break;
+ case 0x00000800: type = DCB_OUTPUT_DP; mask = 1; break;
+ case 0x00000900: type = DCB_OUTPUT_DP; mask = 2; break;
+ default:
+ nv_error(priv, "unknown SOR mc 0x%08x\n", ctrl);
+ return NULL;
+ }
+ or -= 4;
+ } else {
+ or = or - 8;
+ type = 0x0010;
+ mask = 0;
+ switch (ctrl & 0x00000f00) {
+ case 0x00000000: type |= priv->pior.type[or]; break;
+ default:
+ nv_error(priv, "unknown PIOR mc 0x%08x\n", ctrl);
+ return NULL;
+ }
+ }
+
+ mask = 0x00c0 & (mask << 6);
+ mask |= 0x0001 << or;
+ mask |= 0x0100 << head;
+
+ list_for_each_entry(outp, &priv->base.outp, head) {
+ if ((outp->info.hasht & 0xff) == type &&
+ (outp->info.hashm & mask) == mask) {
+ *data = nvbios_outp_match(bios, outp->info.hasht,
+ outp->info.hashm,
+ ver, hdr, cnt, len, info);
+ if (!*data)
+ return NULL;
+ return outp;
+ }
+ }
+
+ return NULL;
+}
+
+static struct nvkm_output *
+exec_script(struct nv50_disp_priv *priv, int head, int id)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvkm_output *outp;
+ struct nvbios_outp info;
+ u8 ver, hdr, cnt, len;
+ u32 data, ctrl = 0;
+ u32 reg;
+ int i;
+
+ /* DAC */
+ for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
+ ctrl = nv_rd32(priv, 0x610b5c + (i * 8));
+
+ /* SOR */
+ if (!(ctrl & (1 << head))) {
+ if (nv_device(priv)->chipset < 0x90 ||
+ nv_device(priv)->chipset == 0x92 ||
+ nv_device(priv)->chipset == 0xa0) {
+ reg = 0x610b74;
+ } else {
+ reg = 0x610798;
+ }
+ for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
+ ctrl = nv_rd32(priv, reg + (i * 8));
+ i += 4;
+ }
+
+ /* PIOR */
+ if (!(ctrl & (1 << head))) {
+ for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
+ ctrl = nv_rd32(priv, 0x610b84 + (i * 8));
+ i += 8;
+ }
+
+ if (!(ctrl & (1 << head)))
+ return NULL;
+ i--;
+
+ outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info);
+ if (outp) {
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = bios,
+ .offset = info.script[id],
+ .outp = &outp->info,
+ .crtc = head,
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ }
+
+ return outp;
+}
+
+static struct nvkm_output *
+exec_clkcmp(struct nv50_disp_priv *priv, int head, int id, u32 pclk, u32 *conf)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvkm_output *outp;
+ struct nvbios_outp info1;
+ struct nvbios_ocfg info2;
+ u8 ver, hdr, cnt, len;
+ u32 data, ctrl = 0;
+ u32 reg;
+ int i;
+
+ /* DAC */
+ for (i = 0; !(ctrl & (1 << head)) && i < priv->dac.nr; i++)
+ ctrl = nv_rd32(priv, 0x610b58 + (i * 8));
+
+ /* SOR */
+ if (!(ctrl & (1 << head))) {
+ if (nv_device(priv)->chipset < 0x90 ||
+ nv_device(priv)->chipset == 0x92 ||
+ nv_device(priv)->chipset == 0xa0) {
+ reg = 0x610b70;
+ } else {
+ reg = 0x610794;
+ }
+ for (i = 0; !(ctrl & (1 << head)) && i < priv->sor.nr; i++)
+ ctrl = nv_rd32(priv, reg + (i * 8));
+ i += 4;
+ }
+
+ /* PIOR */
+ if (!(ctrl & (1 << head))) {
+ for (i = 0; !(ctrl & (1 << head)) && i < priv->pior.nr; i++)
+ ctrl = nv_rd32(priv, 0x610b80 + (i * 8));
+ i += 8;
+ }
+
+ if (!(ctrl & (1 << head)))
+ return NULL;
+ i--;
+
+ outp = exec_lookup(priv, head, i, ctrl, &data, &ver, &hdr, &cnt, &len, &info1);
+ if (!outp)
+ return NULL;
+
+ if (outp->info.location == 0) {
+ switch (outp->info.type) {
+ case DCB_OUTPUT_TMDS:
+ *conf = (ctrl & 0x00000f00) >> 8;
+ if (pclk >= 165000)
+ *conf |= 0x0100;
+ break;
+ case DCB_OUTPUT_LVDS:
+ *conf = priv->sor.lvdsconf;
+ break;
+ case DCB_OUTPUT_DP:
+ *conf = (ctrl & 0x00000f00) >> 8;
+ break;
+ case DCB_OUTPUT_ANALOG:
+ default:
+ *conf = 0x00ff;
+ break;
+ }
+ } else {
+ *conf = (ctrl & 0x00000f00) >> 8;
+ pclk = pclk / 2;
+ }
+
+ data = nvbios_ocfg_match(bios, data, *conf, &ver, &hdr, &cnt, &len, &info2);
+ if (data && id < 0xff) {
+ data = nvbios_oclk_match(bios, info2.clkcmp[id], pclk);
+ if (data) {
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = bios,
+ .offset = data,
+ .outp = &outp->info,
+ .crtc = head,
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ }
+ }
+
+ return outp;
+}
+
+static void
+nv50_disp_intr_unk10_0(struct nv50_disp_priv *priv, int head)
+{
+ exec_script(priv, head, 1);
+}
+
+static void
+nv50_disp_intr_unk20_0(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_output *outp = exec_script(priv, head, 2);
+
+ /* the binary driver does this outside of the supervisor handling
+ * (after the third supervisor from a detach). we (currently?)
+ * allow both detach/attach to happen in the same set of
+ * supervisor interrupts, so it would make sense to execute this
+ * (full power down?) script after all the detach phases of the
+ * supervisor handling. like with training if needed from the
+ * second supervisor, nvidia doesn't do this, so who knows if it's
+ * entirely safe, but it does appear to work..
+ *
+ * without this script being run, on some configurations i've
+ * seen, switching from DP to TMDS on a DP connector may result
+ * in a blank screen (SOR_PWR off/on can restore it)
+ */
+ if (outp && outp->info.type == DCB_OUTPUT_DP) {
+ struct nvkm_output_dp *outpdp = (void *)outp;
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = nvkm_bios(priv),
+ .outp = &outp->info,
+ .crtc = head,
+ .offset = outpdp->info.script[4],
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ atomic_set(&outpdp->lt.done, 0);
+ }
+}
+
+static void
+nv50_disp_intr_unk20_1(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_devinit *devinit = nvkm_devinit(priv);
+ u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+ if (pclk)
+ devinit->pll_set(devinit, PLL_VPLL0 + head, pclk);
+}
+
+static void
+nv50_disp_intr_unk20_2_dp(struct nv50_disp_priv *priv, int head,
+ struct dcb_output *outp, u32 pclk)
+{
+ const int link = !(outp->sorconf.link & 1);
+ const int or = ffs(outp->or) - 1;
+ const u32 soff = ( or * 0x800);
+ const u32 loff = (link * 0x080) + soff;
+ const u32 ctrl = nv_rd32(priv, 0x610794 + (or * 8));
+ const u32 symbol = 100000;
+ const s32 vactive = nv_rd32(priv, 0x610af8 + (head * 0x540)) & 0xffff;
+ const s32 vblanke = nv_rd32(priv, 0x610ae8 + (head * 0x540)) & 0xffff;
+ const s32 vblanks = nv_rd32(priv, 0x610af0 + (head * 0x540)) & 0xffff;
+ u32 dpctrl = nv_rd32(priv, 0x61c10c + loff);
+ u32 clksor = nv_rd32(priv, 0x614300 + soff);
+ int bestTU = 0, bestVTUi = 0, bestVTUf = 0, bestVTUa = 0;
+ int TU, VTUi, VTUf, VTUa;
+ u64 link_data_rate, link_ratio, unk;
+ u32 best_diff = 64 * symbol;
+ u32 link_nr, link_bw, bits;
+ u64 value;
+
+ link_bw = (clksor & 0x000c0000) ? 270000 : 162000;
+ link_nr = hweight32(dpctrl & 0x000f0000);
+
+ /* symbols/hblank - algorithm taken from comments in tegra driver */
+ value = vblanke + vactive - vblanks - 7;
+ value = value * link_bw;
+ do_div(value, pclk);
+ value = value - (3 * !!(dpctrl & 0x00004000)) - (12 / link_nr);
+ nv_mask(priv, 0x61c1e8 + soff, 0x0000ffff, value);
+
+ /* symbols/vblank - algorithm taken from comments in tegra driver */
+ value = vblanks - vblanke - 25;
+ value = value * link_bw;
+ do_div(value, pclk);
+ value = value - ((36 / link_nr) + 3) - 1;
+ nv_mask(priv, 0x61c1ec + soff, 0x00ffffff, value);
+
+ /* watermark / activesym */
+ if ((ctrl & 0xf0000) == 0x60000) bits = 30;
+ else if ((ctrl & 0xf0000) == 0x50000) bits = 24;
+ else bits = 18;
+
+ link_data_rate = (pclk * bits / 8) / link_nr;
+
+ /* calculate ratio of packed data rate to link symbol rate */
+ link_ratio = link_data_rate * symbol;
+ do_div(link_ratio, link_bw);
+
+ for (TU = 64; TU >= 32; TU--) {
+ /* calculate average number of valid symbols in each TU */
+ u32 tu_valid = link_ratio * TU;
+ u32 calc, diff;
+
+ /* find a hw representation for the fraction.. */
+ VTUi = tu_valid / symbol;
+ calc = VTUi * symbol;
+ diff = tu_valid - calc;
+ if (diff) {
+ if (diff >= (symbol / 2)) {
+ VTUf = symbol / (symbol - diff);
+ if (symbol - (VTUf * diff))
+ VTUf++;
+
+ if (VTUf <= 15) {
+ VTUa = 1;
+ calc += symbol - (symbol / VTUf);
+ } else {
+ VTUa = 0;
+ VTUf = 1;
+ calc += symbol;
+ }
+ } else {
+ VTUa = 0;
+ VTUf = min((int)(symbol / diff), 15);
+ calc += symbol / VTUf;
+ }
+
+ diff = calc - tu_valid;
+ } else {
+ /* no remainder, but the hw doesn't like the fractional
+ * part to be zero. decrement the integer part and
+ * have the fraction add a whole symbol back
+ */
+ VTUa = 0;
+ VTUf = 1;
+ VTUi--;
+ }
+
+ if (diff < best_diff) {
+ best_diff = diff;
+ bestTU = TU;
+ bestVTUa = VTUa;
+ bestVTUf = VTUf;
+ bestVTUi = VTUi;
+ if (diff == 0)
+ break;
+ }
+ }
+
+ if (!bestTU) {
+ nv_error(priv, "unable to find suitable dp config\n");
+ return;
+ }
+
+ /* XXX close to vbios numbers, but not right */
+ unk = (symbol - link_ratio) * bestTU;
+ unk *= link_ratio;
+ do_div(unk, symbol);
+ do_div(unk, symbol);
+ unk += 6;
+
+ nv_mask(priv, 0x61c10c + loff, 0x000001fc, bestTU << 2);
+ nv_mask(priv, 0x61c128 + loff, 0x010f7f3f, bestVTUa << 24 |
+ bestVTUf << 16 |
+ bestVTUi << 8 | unk);
+}
+
+static void
+nv50_disp_intr_unk20_2(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_output *outp;
+ u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+ u32 hval, hreg = 0x614200 + (head * 0x800);
+ u32 oval, oreg;
+ u32 mask, conf;
+
+ outp = exec_clkcmp(priv, head, 0xff, pclk, &conf);
+ if (!outp)
+ return;
+
+ /* we allow both encoder attach and detach operations to occur
+ * within a single supervisor (ie. modeset) sequence. the
+ * encoder detach scripts quite often switch off power to the
+ * lanes, which requires the link to be re-trained.
+ *
+ * this is not generally an issue as the sink "must" (heh)
+ * signal an irq when it's lost sync so the driver can
+ * re-train.
+ *
+ * however, on some boards, if one does not configure at least
+ * the gpu side of the link *before* attaching, then various
+ * things can go horribly wrong (PDISP disappearing from mmio,
+ * third supervisor never happens, etc).
+ *
+ * the solution is simply to retrain here, if necessary. last
+ * i checked, the binary driver userspace does not appear to
+ * trigger this situation (it forces an UPDATE between steps).
+ */
+ if (outp->info.type == DCB_OUTPUT_DP) {
+ u32 soff = (ffs(outp->info.or) - 1) * 0x08;
+ u32 ctrl, datarate;
+
+ if (outp->info.location == 0) {
+ ctrl = nv_rd32(priv, 0x610794 + soff);
+ soff = 1;
+ } else {
+ ctrl = nv_rd32(priv, 0x610b80 + soff);
+ soff = 2;
+ }
+
+ switch ((ctrl & 0x000f0000) >> 16) {
+ case 6: datarate = pclk * 30; break;
+ case 5: datarate = pclk * 24; break;
+ case 2:
+ default:
+ datarate = pclk * 18;
+ break;
+ }
+
+ if (nvkm_output_dp_train(outp, datarate / soff, true))
+ ERR("link not trained before attach\n");
+ }
+
+ exec_clkcmp(priv, head, 0, pclk, &conf);
+
+ if (!outp->info.location && outp->info.type == DCB_OUTPUT_ANALOG) {
+ oreg = 0x614280 + (ffs(outp->info.or) - 1) * 0x800;
+ oval = 0x00000000;
+ hval = 0x00000000;
+ mask = 0xffffffff;
+ } else
+ if (!outp->info.location) {
+ if (outp->info.type == DCB_OUTPUT_DP)
+ nv50_disp_intr_unk20_2_dp(priv, head, &outp->info, pclk);
+ oreg = 0x614300 + (ffs(outp->info.or) - 1) * 0x800;
+ oval = (conf & 0x0100) ? 0x00000101 : 0x00000000;
+ hval = 0x00000000;
+ mask = 0x00000707;
+ } else {
+ oreg = 0x614380 + (ffs(outp->info.or) - 1) * 0x800;
+ oval = 0x00000001;
+ hval = 0x00000001;
+ mask = 0x00000707;
+ }
+
+ nv_mask(priv, hreg, 0x0000000f, hval);
+ nv_mask(priv, oreg, mask, oval);
+}
+
+/* If programming a TMDS output on a SOR that can also be configured for
+ * DisplayPort, make sure NV50_SOR_DP_CTRL_ENABLE is forced off.
+ *
+ * It looks like the VBIOS TMDS scripts make an attempt at this, however,
+ * the VBIOS scripts on at least one board I have only switch it off on
+ * link 0, causing a blank display if the output has previously been
+ * programmed for DisplayPort.
+ */
+static void
+nv50_disp_intr_unk40_0_tmds(struct nv50_disp_priv *priv,
+ struct dcb_output *outp)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ const int link = !(outp->sorconf.link & 1);
+ const int or = ffs(outp->or) - 1;
+ const u32 loff = (or * 0x800) + (link * 0x80);
+ const u16 mask = (outp->sorconf.link << 6) | outp->or;
+ struct dcb_output match;
+ u8 ver, hdr;
+
+ if (dcb_outp_match(bios, DCB_OUTPUT_DP, mask, &ver, &hdr, &match))
+ nv_mask(priv, 0x61c10c + loff, 0x00000001, 0x00000000);
+}
+
+static void
+nv50_disp_intr_unk40_0(struct nv50_disp_priv *priv, int head)
+{
+ struct nvkm_output *outp;
+ u32 pclk = nv_rd32(priv, 0x610ad0 + (head * 0x540)) & 0x3fffff;
+ u32 conf;
+
+ outp = exec_clkcmp(priv, head, 1, pclk, &conf);
+ if (!outp)
+ return;
+
+ if (outp->info.location == 0 && outp->info.type == DCB_OUTPUT_TMDS)
+ nv50_disp_intr_unk40_0_tmds(priv, &outp->info);
+}
+
+void
+nv50_disp_intr_supervisor(struct work_struct *work)
+{
+ struct nv50_disp_priv *priv =
+ container_of(work, struct nv50_disp_priv, supervisor);
+ struct nv50_disp_impl *impl = (void *)nv_object(priv)->oclass;
+ u32 super = nv_rd32(priv, 0x610030);
+ int head;
+
+ nv_debug(priv, "supervisor 0x%08x 0x%08x\n", priv->super, super);
+
+ if (priv->super & 0x00000010) {
+ nv50_disp_mthd_chan(priv, NV_DBG_DEBUG, 0, impl->mthd.core);
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(super & (0x00000020 << head)))
+ continue;
+ if (!(super & (0x00000080 << head)))
+ continue;
+ nv50_disp_intr_unk10_0(priv, head);
+ }
+ } else
+ if (priv->super & 0x00000020) {
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(super & (0x00000080 << head)))
+ continue;
+ nv50_disp_intr_unk20_0(priv, head);
+ }
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(super & (0x00000200 << head)))
+ continue;
+ nv50_disp_intr_unk20_1(priv, head);
+ }
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(super & (0x00000080 << head)))
+ continue;
+ nv50_disp_intr_unk20_2(priv, head);
+ }
+ } else
+ if (priv->super & 0x00000040) {
+ for (head = 0; head < priv->head.nr; head++) {
+ if (!(super & (0x00000080 << head)))
+ continue;
+ nv50_disp_intr_unk40_0(priv, head);
+ }
+ }
+
+ nv_wr32(priv, 0x610030, 0x80000000);
+}
+
+void
+nv50_disp_intr(struct nvkm_subdev *subdev)
+{
+ struct nv50_disp_priv *priv = (void *)subdev;
+ u32 intr0 = nv_rd32(priv, 0x610020);
+ u32 intr1 = nv_rd32(priv, 0x610024);
+
+ while (intr0 & 0x001f0000) {
+ u32 chid = __ffs(intr0 & 0x001f0000) - 16;
+ nv50_disp_intr_error(priv, chid);
+ intr0 &= ~(0x00010000 << chid);
+ }
+
+ while (intr0 & 0x0000001f) {
+ u32 chid = __ffs(intr0 & 0x0000001f);
+ nv50_disp_chan_uevent_send(priv, chid);
+ intr0 &= ~(0x00000001 << chid);
+ }
+
+ if (intr1 & 0x00000004) {
+ nvkm_disp_vblank(&priv->base, 0);
+ nv_wr32(priv, 0x610024, 0x00000004);
+ intr1 &= ~0x00000004;
+ }
+
+ if (intr1 & 0x00000008) {
+ nvkm_disp_vblank(&priv->base, 1);
+ nv_wr32(priv, 0x610024, 0x00000008);
+ intr1 &= ~0x00000008;
+ }
+
+ if (intr1 & 0x00000070) {
+ priv->super = (intr1 & 0x00000070);
+ schedule_work(&priv->supervisor);
+ nv_wr32(priv, 0x610024, priv->super);
+ intr1 &= ~0x00000070;
+ }
+}
+
+static int
+nv50_disp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_disp_priv *priv;
+ int ret;
+
+ ret = nvkm_disp_create(parent, engine, oclass, 2, "PDISP",
+ "display", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&nv50_disp_chan_uevent, 1, 9, &priv->uevent);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->sclass = nv50_disp_main_oclass;
+ nv_engine(priv)->cclass = &nv50_disp_cclass;
+ nv_subdev(priv)->intr = nv50_disp_intr;
+ INIT_WORK(&priv->supervisor, nv50_disp_intr_supervisor);
+ priv->sclass = nv50_disp_sclass;
+ priv->head.nr = 2;
+ priv->dac.nr = 3;
+ priv->sor.nr = 2;
+ priv->pior.nr = 3;
+ priv->dac.power = nv50_dac_power;
+ priv->dac.sense = nv50_dac_sense;
+ priv->sor.power = nv50_sor_power;
+ priv->pior.power = nv50_pior_power;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_disp_outp_sclass[] = {
+ &nv50_pior_dp_impl.base.base,
+ NULL
+};
+
+struct nvkm_oclass *
+nv50_disp_oclass = &(struct nv50_disp_impl) {
+ .base.base.handle = NV_ENGINE(DISP, 0x50),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_disp_ctor,
+ .dtor = _nvkm_disp_dtor,
+ .init = _nvkm_disp_init,
+ .fini = _nvkm_disp_fini,
+ },
+ .base.vblank = &nv50_disp_vblank_func,
+ .base.outp = nv50_disp_outp_sclass,
+ .mthd.core = &nv50_disp_core_mthd_chan,
+ .mthd.base = &nv50_disp_base_mthd_chan,
+ .mthd.ovly = &nv50_disp_ovly_mthd_chan,
+ .mthd.prev = 0x000004,
+ .head.scanoutpos = nv50_disp_main_scanoutpos,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
new file mode 100644
index 000000000000..b4ed620070fa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/nv50.h
@@ -0,0 +1,226 @@
+#ifndef __NV50_DISP_H__
+#define __NV50_DISP_H__
+#include "priv.h"
+struct nvkm_output;
+struct nvkm_output_dp;
+
+#define NV50_DISP_MTHD_ struct nvkm_object *object, \
+ struct nv50_disp_priv *priv, void *data, u32 size
+#define NV50_DISP_MTHD_V0 NV50_DISP_MTHD_, int head
+#define NV50_DISP_MTHD_V1 NV50_DISP_MTHD_, int head, struct nvkm_output *outp
+
+struct nv50_disp_priv {
+ struct nvkm_disp base;
+ struct nvkm_oclass *sclass;
+
+ struct work_struct supervisor;
+ u32 super;
+
+ struct nvkm_event uevent;
+
+ struct {
+ int nr;
+ } head;
+ struct {
+ int nr;
+ int (*power)(NV50_DISP_MTHD_V1);
+ int (*sense)(NV50_DISP_MTHD_V1);
+ } dac;
+ struct {
+ int nr;
+ int (*power)(NV50_DISP_MTHD_V1);
+ int (*hda_eld)(NV50_DISP_MTHD_V1);
+ int (*hdmi)(NV50_DISP_MTHD_V1);
+ u32 lvdsconf;
+ void (*magic)(struct nvkm_output *);
+ } sor;
+ struct {
+ int nr;
+ int (*power)(NV50_DISP_MTHD_V1);
+ u8 type[3];
+ } pior;
+};
+
+struct nv50_disp_impl {
+ struct nvkm_disp_impl base;
+ struct {
+ const struct nv50_disp_mthd_chan *core;
+ const struct nv50_disp_mthd_chan *base;
+ const struct nv50_disp_mthd_chan *ovly;
+ int prev;
+ } mthd;
+ struct {
+ int (*scanoutpos)(NV50_DISP_MTHD_V0);
+ } head;
+};
+
+int nv50_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
+int nv50_disp_main_mthd(struct nvkm_object *, u32, void *, u32);
+
+int gf110_disp_main_scanoutpos(NV50_DISP_MTHD_V0);
+
+int nv50_dac_power(NV50_DISP_MTHD_V1);
+int nv50_dac_sense(NV50_DISP_MTHD_V1);
+
+int gt215_hda_eld(NV50_DISP_MTHD_V1);
+int gf110_hda_eld(NV50_DISP_MTHD_V1);
+
+int g84_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int gt215_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int gf110_hdmi_ctrl(NV50_DISP_MTHD_V1);
+int gk104_hdmi_ctrl(NV50_DISP_MTHD_V1);
+
+int nv50_sor_power(NV50_DISP_MTHD_V1);
+int nv50_pior_power(NV50_DISP_MTHD_V1);
+
+#include <core/parent.h>
+
+struct nv50_disp_base {
+ struct nvkm_parent base;
+ struct nvkm_ramht *ramht;
+ u32 chan;
+};
+
+struct nv50_disp_chan_impl {
+ struct nvkm_ofuncs base;
+ int chid;
+ int (*attach)(struct nvkm_object *, struct nvkm_object *, u32);
+ void (*detach)(struct nvkm_object *, int);
+};
+
+#include <core/namedb.h>
+
+struct nv50_disp_chan {
+ struct nvkm_namedb base;
+ int chid;
+};
+
+int nv50_disp_chan_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
+int nv50_disp_chan_map(struct nvkm_object *, u64 *, u32 *);
+u32 nv50_disp_chan_rd32(struct nvkm_object *, u64);
+void nv50_disp_chan_wr32(struct nvkm_object *, u64, u32);
+extern const struct nvkm_event_func nv50_disp_chan_uevent;
+int nv50_disp_chan_uevent_ctor(struct nvkm_object *, void *, u32,
+ struct nvkm_notify *);
+void nv50_disp_chan_uevent_send(struct nv50_disp_priv *, int);
+
+extern const struct nvkm_event_func gf110_disp_chan_uevent;
+
+#define nv50_disp_chan_init(a) \
+ nvkm_namedb_init(&(a)->base)
+#define nv50_disp_chan_fini(a,b) \
+ nvkm_namedb_fini(&(a)->base, (b))
+
+struct nv50_disp_dmac {
+ struct nv50_disp_chan base;
+ struct nvkm_dmaobj *pushdma;
+ u32 push;
+};
+
+void nv50_disp_dmac_dtor(struct nvkm_object *);
+
+struct nv50_disp_pioc {
+ struct nv50_disp_chan base;
+};
+
+void nv50_disp_pioc_dtor(struct nvkm_object *);
+
+struct nv50_disp_mthd_list {
+ u32 mthd;
+ u32 addr;
+ struct {
+ u32 mthd;
+ u32 addr;
+ const char *name;
+ } data[];
+};
+
+struct nv50_disp_mthd_chan {
+ const char *name;
+ u32 addr;
+ struct {
+ const char *name;
+ int nr;
+ const struct nv50_disp_mthd_list *mthd;
+ } data[];
+};
+
+extern struct nv50_disp_chan_impl nv50_disp_core_ofuncs;
+int nv50_disp_core_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_base;
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_sor;
+extern const struct nv50_disp_mthd_list nv50_disp_core_mthd_pior;
+extern struct nv50_disp_chan_impl nv50_disp_base_ofuncs;
+int nv50_disp_base_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+extern const struct nv50_disp_mthd_list nv50_disp_base_mthd_image;
+extern struct nv50_disp_chan_impl nv50_disp_ovly_ofuncs;
+int nv50_disp_ovly_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+extern const struct nv50_disp_mthd_list nv50_disp_ovly_mthd_base;
+extern struct nv50_disp_chan_impl nv50_disp_oimm_ofuncs;
+int nv50_disp_oimm_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+extern struct nv50_disp_chan_impl nv50_disp_curs_ofuncs;
+int nv50_disp_curs_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+extern struct nvkm_ofuncs nv50_disp_main_ofuncs;
+int nv50_disp_main_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nv50_disp_main_dtor(struct nvkm_object *);
+extern struct nvkm_omthds nv50_disp_main_omthds[];
+extern struct nvkm_oclass nv50_disp_cclass;
+void nv50_disp_mthd_chan(struct nv50_disp_priv *, int debug, int head,
+ const struct nv50_disp_mthd_chan *);
+void nv50_disp_intr_supervisor(struct work_struct *);
+void nv50_disp_intr(struct nvkm_subdev *);
+extern const struct nvkm_event_func nv50_disp_vblank_func;
+
+extern const struct nv50_disp_mthd_chan g84_disp_core_mthd_chan;
+extern const struct nv50_disp_mthd_list g84_disp_core_mthd_dac;
+extern const struct nv50_disp_mthd_list g84_disp_core_mthd_head;
+extern const struct nv50_disp_mthd_chan g84_disp_base_mthd_chan;
+extern const struct nv50_disp_mthd_chan g84_disp_ovly_mthd_chan;
+
+extern const struct nv50_disp_mthd_chan g94_disp_core_mthd_chan;
+
+extern struct nv50_disp_chan_impl gf110_disp_core_ofuncs;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_base;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_dac;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_sor;
+extern const struct nv50_disp_mthd_list gf110_disp_core_mthd_pior;
+extern struct nv50_disp_chan_impl gf110_disp_base_ofuncs;
+extern struct nv50_disp_chan_impl gf110_disp_ovly_ofuncs;
+extern const struct nv50_disp_mthd_chan gf110_disp_base_mthd_chan;
+extern struct nv50_disp_chan_impl gf110_disp_oimm_ofuncs;
+extern struct nv50_disp_chan_impl gf110_disp_curs_ofuncs;
+extern struct nvkm_ofuncs gf110_disp_main_ofuncs;
+extern struct nvkm_oclass gf110_disp_cclass;
+void gf110_disp_intr_supervisor(struct work_struct *);
+void gf110_disp_intr(struct nvkm_subdev *);
+extern const struct nvkm_event_func gf110_disp_vblank_func;
+
+extern const struct nv50_disp_mthd_chan gk104_disp_core_mthd_chan;
+extern const struct nv50_disp_mthd_chan gk104_disp_ovly_mthd_chan;
+
+extern struct nvkm_output_dp_impl nv50_pior_dp_impl;
+extern struct nvkm_oclass *nv50_disp_outp_sclass[];
+
+extern struct nvkm_output_dp_impl g94_sor_dp_impl;
+int g94_sor_dp_lnk_pwr(struct nvkm_output_dp *, int);
+extern struct nvkm_oclass *g94_disp_outp_sclass[];
+
+extern struct nvkm_output_dp_impl gf110_sor_dp_impl;
+int gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *, int, int, bool);
+extern struct nvkm_oclass *gf110_disp_outp_sclass[];
+
+void gm204_sor_magic(struct nvkm_output *outp);
+extern struct nvkm_output_dp_impl gm204_sor_dp_impl;
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
new file mode 100644
index 000000000000..9224bcbf0159
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "outp.h"
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/i2c.h>
+
+int
+_nvkm_output_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_output *outp = (void *)object;
+ nv_ofuncs(outp->conn)->fini(nv_object(outp->conn), suspend);
+ return nvkm_object_fini(&outp->base, suspend);
+}
+
+int
+_nvkm_output_init(struct nvkm_object *object)
+{
+ struct nvkm_output *outp = (void *)object;
+ int ret = nvkm_object_init(&outp->base);
+ if (ret == 0)
+ nv_ofuncs(outp->conn)->init(nv_object(outp->conn));
+ return 0;
+}
+
+void
+_nvkm_output_dtor(struct nvkm_object *object)
+{
+ struct nvkm_output *outp = (void *)object;
+ list_del(&outp->head);
+ nvkm_object_ref(NULL, (void *)&outp->conn);
+ nvkm_object_destroy(&outp->base);
+}
+
+int
+nvkm_output_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass,
+ struct dcb_output *dcbE, int index,
+ int length, void **pobject)
+{
+ struct nvkm_disp *disp = nvkm_disp(parent);
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct nvkm_i2c *i2c = nvkm_i2c(parent);
+ struct nvbios_connE connE;
+ struct nvkm_output *outp;
+ u8 ver, hdr;
+ u32 data;
+ int ret;
+
+ ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
+ outp = *pobject;
+ if (ret)
+ return ret;
+
+ outp->info = *dcbE;
+ outp->index = index;
+ outp->or = ffs(outp->info.or) - 1;
+
+ DBG("type %02x loc %d or %d link %d con %x edid %x bus %d head %x\n",
+ dcbE->type, dcbE->location, dcbE->or, dcbE->type >= 2 ?
+ dcbE->sorconf.link : 0, dcbE->connector, dcbE->i2c_index,
+ dcbE->bus, dcbE->heads);
+
+ if (outp->info.type != DCB_OUTPUT_DP)
+ outp->port = i2c->find(i2c, NV_I2C_PORT(outp->info.i2c_index));
+ else
+ outp->port = i2c->find(i2c, NV_I2C_AUX(outp->info.i2c_index));
+ outp->edid = outp->port;
+
+ data = nvbios_connEp(bios, outp->info.connector, &ver, &hdr, &connE);
+ if (!data) {
+ DBG("vbios connector data not found\n");
+ memset(&connE, 0x00, sizeof(connE));
+ connE.type = DCB_CONNECTOR_NONE;
+ }
+
+ ret = nvkm_object_ctor(parent, NULL, nvkm_connector_oclass,
+ &connE, outp->info.connector,
+ (struct nvkm_object **)&outp->conn);
+ if (ret < 0) {
+ ERR("error %d creating connector, disabling\n", ret);
+ return ret;
+ }
+
+ list_add_tail(&outp->head, &disp->outp);
+ return 0;
+}
+
+int
+_nvkm_output_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *dcbE, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_output *outp;
+ int ret;
+
+ ret = nvkm_output_create(parent, engine, oclass, dcbE, index, &outp);
+ *pobject = nv_object(outp);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nvkm_output_oclass = &(struct nvkm_output_impl) {
+ .base = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_output_ctor,
+ .dtor = _nvkm_output_dtor,
+ .init = _nvkm_output_init,
+ .fini = _nvkm_output_fini,
+ },
+ },
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
new file mode 100644
index 000000000000..d9253d26c31b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outp.h
@@ -0,0 +1,61 @@
+#ifndef __NVKM_DISP_OUTP_H__
+#define __NVKM_DISP_OUTP_H__
+#include <core/object.h>
+
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+struct nvkm_output {
+ struct nvkm_object base;
+ struct list_head head;
+
+ struct dcb_output info;
+ int index;
+ int or;
+
+ struct nvkm_i2c_port *port;
+ struct nvkm_i2c_port *edid;
+
+ struct nvkm_connector *conn;
+};
+
+#define nvkm_output_create(p,e,c,b,i,d) \
+ nvkm_output_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
+#define nvkm_output_destroy(d) ({ \
+ struct nvkm_output *_outp = (d); \
+ _nvkm_output_dtor(nv_object(_outp)); \
+})
+#define nvkm_output_init(d) ({ \
+ struct nvkm_output *_outp = (d); \
+ _nvkm_output_init(nv_object(_outp)); \
+})
+#define nvkm_output_fini(d,s) ({ \
+ struct nvkm_output *_outp = (d); \
+ _nvkm_output_fini(nv_object(_outp), (s)); \
+})
+
+int nvkm_output_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, struct dcb_output *,
+ int, int, void **);
+
+int _nvkm_output_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void _nvkm_output_dtor(struct nvkm_object *);
+int _nvkm_output_init(struct nvkm_object *);
+int _nvkm_output_fini(struct nvkm_object *, bool);
+
+struct nvkm_output_impl {
+ struct nvkm_oclass base;
+};
+
+#ifndef MSG
+#define MSG(l,f,a...) do { \
+ struct nvkm_output *_outp = (void *)outp; \
+ nv_##l(_outp, "%02x:%04x:%04x: "f, _outp->index, \
+ _outp->info.hasht, _outp->info.hashm, ##a); \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
new file mode 100644
index 000000000000..0bde0fa5b59d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "outpdp.h"
+#include "conn.h"
+#include "dport.h"
+#include "priv.h"
+
+#include <subdev/i2c.h>
+
+#include <nvif/event.h>
+
+int
+nvkm_output_dp_train(struct nvkm_output *base, u32 datarate, bool wait)
+{
+ struct nvkm_output_dp *outp = (void *)base;
+ bool retrain = true;
+ u8 link[2], stat[3];
+ u32 linkrate;
+ int ret, i;
+
+ /* check that the link is trained at a high enough rate */
+ ret = nv_rdaux(outp->base.edid, DPCD_LC00_LINK_BW_SET, link, 2);
+ if (ret) {
+ DBG("failed to read link config, assuming no sink\n");
+ goto done;
+ }
+
+ linkrate = link[0] * 27000 * (link[1] & DPCD_LC01_LANE_COUNT_SET);
+ linkrate = (linkrate * 8) / 10; /* 8B/10B coding overhead */
+ datarate = (datarate + 9) / 10; /* -> decakilobits */
+ if (linkrate < datarate) {
+ DBG("link not trained at sufficient rate\n");
+ goto done;
+ }
+
+ /* check that link is still trained */
+ ret = nv_rdaux(outp->base.edid, DPCD_LS02, stat, 3);
+ if (ret) {
+ DBG("failed to read link status, assuming no sink\n");
+ goto done;
+ }
+
+ if (stat[2] & DPCD_LS04_INTERLANE_ALIGN_DONE) {
+ for (i = 0; i < (link[1] & DPCD_LC01_LANE_COUNT_SET); i++) {
+ u8 lane = (stat[i >> 1] >> ((i & 1) * 4)) & 0x0f;
+ if (!(lane & DPCD_LS02_LANE0_CR_DONE) ||
+ !(lane & DPCD_LS02_LANE0_CHANNEL_EQ_DONE) ||
+ !(lane & DPCD_LS02_LANE0_SYMBOL_LOCKED)) {
+ DBG("lane %d not equalised\n", lane);
+ goto done;
+ }
+ }
+ retrain = false;
+ } else {
+ DBG("no inter-lane alignment\n");
+ }
+
+done:
+ if (retrain || !atomic_read(&outp->lt.done)) {
+ /* no sink, but still need to configure source */
+ if (outp->dpcd[DPCD_RC00_DPCD_REV] == 0x00) {
+ outp->dpcd[DPCD_RC01_MAX_LINK_RATE] =
+ outp->base.info.dpconf.link_bw;
+ outp->dpcd[DPCD_RC02] =
+ outp->base.info.dpconf.link_nr;
+ }
+ atomic_set(&outp->lt.done, 0);
+ schedule_work(&outp->lt.work);
+ } else {
+ nvkm_notify_get(&outp->irq);
+ }
+
+ if (wait) {
+ if (!wait_event_timeout(outp->lt.wait,
+ atomic_read(&outp->lt.done),
+ msecs_to_jiffies(2000)))
+ ret = -ETIMEDOUT;
+ }
+
+ return ret;
+}
+
+static void
+nvkm_output_dp_enable(struct nvkm_output_dp *outp, bool present)
+{
+ struct nvkm_i2c_port *port = outp->base.edid;
+ if (present) {
+ if (!outp->present) {
+ nvkm_i2c(port)->acquire_pad(port, 0);
+ DBG("aux power -> always\n");
+ outp->present = true;
+ }
+ nvkm_output_dp_train(&outp->base, 0, true);
+ } else {
+ if (outp->present) {
+ nvkm_i2c(port)->release_pad(port);
+ DBG("aux power -> demand\n");
+ outp->present = false;
+ }
+ atomic_set(&outp->lt.done, 0);
+ }
+}
+
+static void
+nvkm_output_dp_detect(struct nvkm_output_dp *outp)
+{
+ struct nvkm_i2c_port *port = outp->base.edid;
+ int ret = nvkm_i2c(port)->acquire_pad(port, 0);
+ if (ret == 0) {
+ ret = nv_rdaux(outp->base.edid, DPCD_RC00_DPCD_REV,
+ outp->dpcd, sizeof(outp->dpcd));
+ nvkm_output_dp_enable(outp, ret == 0);
+ nvkm_i2c(port)->release_pad(port);
+ }
+}
+
+static int
+nvkm_output_dp_hpd(struct nvkm_notify *notify)
+{
+ struct nvkm_connector *conn = container_of(notify, typeof(*conn), hpd);
+ struct nvkm_output_dp *outp;
+ struct nvkm_disp *disp = nvkm_disp(conn);
+ const struct nvkm_i2c_ntfy_rep *line = notify->data;
+ struct nvif_notify_conn_rep_v0 rep = {};
+
+ list_for_each_entry(outp, &disp->outp, base.head) {
+ if (outp->base.conn == conn &&
+ outp->info.type == DCB_OUTPUT_DP) {
+ DBG("HPD: %d\n", line->mask);
+ nvkm_output_dp_detect(outp);
+
+ if (line->mask & NVKM_I2C_UNPLUG)
+ rep.mask |= NVIF_NOTIFY_CONN_V0_UNPLUG;
+ if (line->mask & NVKM_I2C_PLUG)
+ rep.mask |= NVIF_NOTIFY_CONN_V0_PLUG;
+
+ nvkm_event_send(&disp->hpd, rep.mask, conn->index,
+ &rep, sizeof(rep));
+ return NVKM_NOTIFY_KEEP;
+ }
+ }
+
+ WARN_ON(1);
+ return NVKM_NOTIFY_DROP;
+}
+
+static int
+nvkm_output_dp_irq(struct nvkm_notify *notify)
+{
+ struct nvkm_output_dp *outp = container_of(notify, typeof(*outp), irq);
+ struct nvkm_disp *disp = nvkm_disp(outp);
+ const struct nvkm_i2c_ntfy_rep *line = notify->data;
+ struct nvif_notify_conn_rep_v0 rep = {
+ .mask = NVIF_NOTIFY_CONN_V0_IRQ,
+ };
+ int index = outp->base.info.connector;
+
+ DBG("IRQ: %d\n", line->mask);
+ nvkm_output_dp_train(&outp->base, 0, true);
+
+ nvkm_event_send(&disp->hpd, rep.mask, index, &rep, sizeof(rep));
+ return NVKM_NOTIFY_DROP;
+}
+
+int
+_nvkm_output_dp_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_output_dp *outp = (void *)object;
+ nvkm_notify_put(&outp->irq);
+ nvkm_output_dp_enable(outp, false);
+ return nvkm_output_fini(&outp->base, suspend);
+}
+
+int
+_nvkm_output_dp_init(struct nvkm_object *object)
+{
+ struct nvkm_output_dp *outp = (void *)object;
+ nvkm_output_dp_detect(outp);
+ return nvkm_output_init(&outp->base);
+}
+
+void
+_nvkm_output_dp_dtor(struct nvkm_object *object)
+{
+ struct nvkm_output_dp *outp = (void *)object;
+ nvkm_notify_fini(&outp->irq);
+ nvkm_output_destroy(&outp->base);
+}
+
+int
+nvkm_output_dp_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass,
+ struct dcb_output *info, int index,
+ int length, void **pobject)
+{
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct nvkm_i2c *i2c = nvkm_i2c(parent);
+ struct nvkm_output_dp *outp;
+ u8 hdr, cnt, len;
+ u32 data;
+ int ret;
+
+ ret = nvkm_output_create_(parent, engine, oclass, info, index,
+ length, pobject);
+ outp = *pobject;
+ if (ret)
+ return ret;
+
+ nvkm_notify_fini(&outp->base.conn->hpd);
+
+ /* access to the aux channel is not optional... */
+ if (!outp->base.edid) {
+ ERR("aux channel not found\n");
+ return -ENODEV;
+ }
+
+ /* nor is the bios data for this output... */
+ data = nvbios_dpout_match(bios, outp->base.info.hasht,
+ outp->base.info.hashm, &outp->version,
+ &hdr, &cnt, &len, &outp->info);
+ if (!data) {
+ ERR("no bios dp data\n");
+ return -ENODEV;
+ }
+
+ DBG("bios dp %02x %02x %02x %02x\n", outp->version, hdr, cnt, len);
+
+ /* link training */
+ INIT_WORK(&outp->lt.work, nvkm_dp_train);
+ init_waitqueue_head(&outp->lt.wait);
+ atomic_set(&outp->lt.done, 0);
+
+ /* link maintenance */
+ ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_irq, true,
+ &(struct nvkm_i2c_ntfy_req) {
+ .mask = NVKM_I2C_IRQ,
+ .port = outp->base.edid->index,
+ },
+ sizeof(struct nvkm_i2c_ntfy_req),
+ sizeof(struct nvkm_i2c_ntfy_rep),
+ &outp->irq);
+ if (ret) {
+ ERR("error monitoring aux irq event: %d\n", ret);
+ return ret;
+ }
+
+ /* hotplug detect, replaces gpio-based mechanism with aux events */
+ ret = nvkm_notify_init(NULL, &i2c->event, nvkm_output_dp_hpd, true,
+ &(struct nvkm_i2c_ntfy_req) {
+ .mask = NVKM_I2C_PLUG | NVKM_I2C_UNPLUG,
+ .port = outp->base.edid->index,
+ },
+ sizeof(struct nvkm_i2c_ntfy_req),
+ sizeof(struct nvkm_i2c_ntfy_rep),
+ &outp->base.conn->hpd);
+ if (ret) {
+ ERR("error monitoring aux hpd events: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+int
+_nvkm_output_dp_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *info, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_output_dp *outp;
+ int ret;
+
+ ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
+ *pobject = nv_object(outp);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
new file mode 100644
index 000000000000..70c77aec4850
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/outpdp.h
@@ -0,0 +1,61 @@
+#ifndef __NVKM_DISP_OUTP_DP_H__
+#define __NVKM_DISP_OUTP_DP_H__
+#include "outp.h"
+
+#include <core/notify.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dp.h>
+
+struct nvkm_output_dp {
+ struct nvkm_output base;
+
+ struct nvbios_dpout info;
+ u8 version;
+
+ struct nvkm_notify irq;
+ bool present;
+ u8 dpcd[16];
+
+ struct {
+ struct work_struct work;
+ wait_queue_head_t wait;
+ atomic_t done;
+ } lt;
+};
+
+#define nvkm_output_dp_create(p,e,c,b,i,d) \
+ nvkm_output_dp_create_((p), (e), (c), (b), (i), sizeof(**d), (void **)d)
+#define nvkm_output_dp_destroy(d) ({ \
+ struct nvkm_output_dp *_outp = (d); \
+ _nvkm_output_dp_dtor(nv_object(_outp)); \
+})
+#define nvkm_output_dp_init(d) ({ \
+ struct nvkm_output_dp *_outp = (d); \
+ _nvkm_output_dp_init(nv_object(_outp)); \
+})
+#define nvkm_output_dp_fini(d,s) ({ \
+ struct nvkm_output_dp *_outp = (d); \
+ _nvkm_output_dp_fini(nv_object(_outp), (s)); \
+})
+
+int nvkm_output_dp_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, struct dcb_output *,
+ int, int, void **);
+
+int _nvkm_output_dp_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void _nvkm_output_dp_dtor(struct nvkm_object *);
+int _nvkm_output_dp_init(struct nvkm_object *);
+int _nvkm_output_dp_fini(struct nvkm_object *, bool);
+
+struct nvkm_output_dp_impl {
+ struct nvkm_output_impl base;
+ int (*pattern)(struct nvkm_output_dp *, int);
+ int (*lnk_pwr)(struct nvkm_output_dp *, int nr);
+ int (*lnk_ctl)(struct nvkm_output_dp *, int nr, int bw, bool ef);
+ int (*drv_ctl)(struct nvkm_output_dp *, int ln, int vs, int pe, int pc);
+};
+
+int nvkm_output_dp_train(struct nvkm_output *, u32 rate, bool wait);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
new file mode 100644
index 000000000000..2a1d8871bf82
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/piornv50.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <core/client.h>
+#include <subdev/i2c.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/******************************************************************************
+ * TMDS
+ *****************************************************************************/
+
+static int
+nv50_pior_tmds_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *info, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(parent);
+ struct nvkm_output *outp;
+ int ret;
+
+ ret = nvkm_output_create(parent, engine, oclass, info, index, &outp);
+ *pobject = nv_object(outp);
+ if (ret)
+ return ret;
+
+ outp->edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTDDC(outp->info.extdev));
+ return 0;
+}
+
+struct nvkm_output_impl
+nv50_pior_tmds_impl = {
+ .base.handle = DCB_OUTPUT_TMDS | 0x0100,
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_pior_tmds_ctor,
+ .dtor = _nvkm_output_dtor,
+ .init = _nvkm_output_init,
+ .fini = _nvkm_output_fini,
+ },
+};
+
+/******************************************************************************
+ * DisplayPort
+ *****************************************************************************/
+
+static int
+nv50_pior_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+ struct nvkm_i2c_port *port = outp->base.edid;
+ if (port && port->func->pattern)
+ return port->func->pattern(port, pattern);
+ return port ? 0 : -ENODEV;
+}
+
+static int
+nv50_pior_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+ return 0;
+}
+
+static int
+nv50_pior_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
+{
+ struct nvkm_i2c_port *port = outp->base.edid;
+ if (port && port->func->lnk_ctl)
+ return port->func->lnk_ctl(port, nr, bw, ef);
+ return port ? 0 : -ENODEV;
+}
+
+static int
+nv50_pior_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
+{
+ struct nvkm_i2c_port *port = outp->base.edid;
+ if (port && port->func->drv_ctl)
+ return port->func->drv_ctl(port, ln, vs, pe);
+ return port ? 0 : -ENODEV;
+}
+
+static int
+nv50_pior_dp_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *info, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(parent);
+ struct nvkm_output_dp *outp;
+ int ret;
+
+ ret = nvkm_output_dp_create(parent, engine, oclass, info, index, &outp);
+ *pobject = nv_object(outp);
+ if (ret)
+ return ret;
+
+ outp->base.edid = i2c->find_type(i2c, NV_I2C_TYPE_EXTAUX(
+ outp->base.info.extdev));
+ return 0;
+}
+
+struct nvkm_output_dp_impl
+nv50_pior_dp_impl = {
+ .base.base.handle = DCB_OUTPUT_DP | 0x0010,
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_pior_dp_ctor,
+ .dtor = _nvkm_output_dp_dtor,
+ .init = _nvkm_output_dp_init,
+ .fini = _nvkm_output_dp_fini,
+ },
+ .pattern = nv50_pior_dp_pattern,
+ .lnk_pwr = nv50_pior_dp_lnk_pwr,
+ .lnk_ctl = nv50_pior_dp_lnk_ctl,
+ .drv_ctl = nv50_pior_dp_drv_ctl,
+};
+
+/******************************************************************************
+ * General PIOR handling
+ *****************************************************************************/
+
+int
+nv50_pior_power(NV50_DISP_MTHD_V1)
+{
+ const u32 soff = outp->or * 0x800;
+ union {
+ struct nv50_disp_pior_pwr_v0 v0;
+ } *args = data;
+ u32 ctrl, type;
+ int ret;
+
+ nv_ioctl(object, "disp pior pwr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp pior pwr vers %d state %d type %x\n",
+ args->v0.version, args->v0.state, args->v0.type);
+ if (args->v0.type > 0x0f)
+ return -EINVAL;
+ ctrl = !!args->v0.state;
+ type = args->v0.type;
+ } else
+ return ret;
+
+ nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
+ nv_mask(priv, 0x61e004 + soff, 0x80000101, 0x80000000 | ctrl);
+ nv_wait(priv, 0x61e004 + soff, 0x80000000, 0x00000000);
+ priv->pior.type[outp->or] = type;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
new file mode 100644
index 000000000000..961ce8bb2135
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/priv.h
@@ -0,0 +1,42 @@
+#ifndef __NVKM_DISP_PRIV_H__
+#define __NVKM_DISP_PRIV_H__
+#include <engine/disp.h>
+
+struct nvkm_disp_impl {
+ struct nvkm_oclass base;
+ struct nvkm_oclass **outp;
+ struct nvkm_oclass **conn;
+ const struct nvkm_event_func *vblank;
+};
+
+#define nvkm_disp_create(p,e,c,h,i,x,d) \
+ nvkm_disp_create_((p), (e), (c), (h), (i), (x), \
+ sizeof(**d), (void **)d)
+#define nvkm_disp_destroy(d) ({ \
+ struct nvkm_disp *disp = (d); \
+ _nvkm_disp_dtor(nv_object(disp)); \
+})
+#define nvkm_disp_init(d) ({ \
+ struct nvkm_disp *disp = (d); \
+ _nvkm_disp_init(nv_object(disp)); \
+})
+#define nvkm_disp_fini(d,s) ({ \
+ struct nvkm_disp *disp = (d); \
+ _nvkm_disp_fini(nv_object(disp), (s)); \
+})
+
+int nvkm_disp_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int heads,
+ const char *, const char *, int, void **);
+void _nvkm_disp_dtor(struct nvkm_object *);
+int _nvkm_disp_init(struct nvkm_object *);
+int _nvkm_disp_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_oclass *nvkm_output_oclass;
+extern struct nvkm_oclass *nvkm_connector_oclass;
+
+int nvkm_disp_vblank_ctor(struct nvkm_object *, void *data, u32 size,
+ struct nvkm_notify *);
+void nvkm_disp_vblank(struct nvkm_disp *, int head);
+int nvkm_disp_ntfy(struct nvkm_object *, u32, struct nvkm_event **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
new file mode 100644
index 000000000000..8918da7ffdf2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorg94.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <core/device.h>
+#include <subdev/timer.h>
+
+static inline u32
+g94_sor_soff(struct nvkm_output_dp *outp)
+{
+ return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+g94_sor_loff(struct nvkm_output_dp *outp)
+{
+ return g94_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+static inline u32
+g94_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+ static const u8 mcp89[] = { 24, 16, 8, 0 }; /* thanks, apple.. */
+ static const u8 g94[] = { 16, 8, 0, 24 };
+ if (nv_device(priv)->chipset == 0xaf)
+ return mcp89[lane];
+ return g94[lane];
+}
+
+static int
+g94_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 loff = g94_sor_loff(outp);
+ nv_mask(priv, 0x61c10c + loff, 0x0f000000, pattern << 24);
+ return 0;
+}
+
+int
+g94_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 soff = g94_sor_soff(outp);
+ const u32 loff = g94_sor_loff(outp);
+ u32 mask = 0, i;
+
+ for (i = 0; i < nr; i++)
+ mask |= 1 << (g94_sor_dp_lane_map(priv, i) >> 3);
+
+ nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
+ nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
+ nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
+ return 0;
+}
+
+static int
+g94_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 soff = g94_sor_soff(outp);
+ const u32 loff = g94_sor_loff(outp);
+ u32 dpctrl = 0x00000000;
+ u32 clksor = 0x00000000;
+
+ dpctrl |= ((1 << nr) - 1) << 16;
+ if (ef)
+ dpctrl |= 0x00004000;
+ if (bw > 0x06)
+ clksor |= 0x00040000;
+
+ nv_mask(priv, 0x614300 + soff, 0x000c0000, clksor);
+ nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
+ return 0;
+}
+
+static int
+g94_sor_dp_drv_ctl(struct nvkm_output_dp *outp, int ln, int vs, int pe, int pc)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ const u32 shift = g94_sor_dp_lane_map(priv, ln);
+ const u32 loff = g94_sor_loff(outp);
+ u32 addr, data[3];
+ u8 ver, hdr, cnt, len;
+ struct nvbios_dpout info;
+ struct nvbios_dpcfg ocfg;
+
+ addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+ outp->base.info.hashm,
+ &ver, &hdr, &cnt, &len, &info);
+ if (!addr)
+ return -ENODEV;
+
+ addr = nvbios_dpcfg_match(bios, addr, 0, vs, pe,
+ &ver, &hdr, &cnt, &len, &ocfg);
+ if (!addr)
+ return -EINVAL;
+
+ data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+ data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+ data[2] = nv_rd32(priv, 0x61c130 + loff);
+ if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+ data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+ nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+ nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+ nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+ return 0;
+}
+
+struct nvkm_output_dp_impl
+g94_sor_dp_impl = {
+ .base.base.handle = DCB_OUTPUT_DP,
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_output_dp_ctor,
+ .dtor = _nvkm_output_dp_dtor,
+ .init = _nvkm_output_dp_init,
+ .fini = _nvkm_output_dp_fini,
+ },
+ .pattern = g94_sor_dp_pattern,
+ .lnk_pwr = g94_sor_dp_lnk_pwr,
+ .lnk_ctl = g94_sor_dp_lnk_ctl,
+ .drv_ctl = g94_sor_dp_drv_ctl,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c
new file mode 100644
index 000000000000..52fbe4880e13
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgf110.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+static inline u32
+gf110_sor_soff(struct nvkm_output_dp *outp)
+{
+ return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+gf110_sor_loff(struct nvkm_output_dp *outp)
+{
+ return gf110_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+static inline u32
+gf110_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+ static const u8 gf110[] = { 16, 8, 0, 24 };
+ return gf110[lane];
+}
+
+static int
+gf110_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 loff = gf110_sor_loff(outp);
+ nv_mask(priv, 0x61c110 + loff, 0x0f0f0f0f, 0x01010101 * pattern);
+ return 0;
+}
+
+int
+gf110_sor_dp_lnk_ctl(struct nvkm_output_dp *outp, int nr, int bw, bool ef)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 soff = gf110_sor_soff(outp);
+ const u32 loff = gf110_sor_loff(outp);
+ u32 dpctrl = 0x00000000;
+ u32 clksor = 0x00000000;
+
+ clksor |= bw << 18;
+ dpctrl |= ((1 << nr) - 1) << 16;
+ if (ef)
+ dpctrl |= 0x00004000;
+
+ nv_mask(priv, 0x612300 + soff, 0x007c0000, clksor);
+ nv_mask(priv, 0x61c10c + loff, 0x001f4000, dpctrl);
+ return 0;
+}
+
+static int
+gf110_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
+ int ln, int vs, int pe, int pc)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ const u32 shift = gf110_sor_dp_lane_map(priv, ln);
+ const u32 loff = gf110_sor_loff(outp);
+ u32 addr, data[4];
+ u8 ver, hdr, cnt, len;
+ struct nvbios_dpout info;
+ struct nvbios_dpcfg ocfg;
+
+ addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+ outp->base.info.hashm,
+ &ver, &hdr, &cnt, &len, &info);
+ if (!addr)
+ return -ENODEV;
+
+ addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
+ &ver, &hdr, &cnt, &len, &ocfg);
+ if (!addr)
+ return -EINVAL;
+
+ data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+ data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+ data[2] = nv_rd32(priv, 0x61c130 + loff);
+ if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+ data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+ nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+ nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+ nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+ data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
+ nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
+ return 0;
+}
+
+struct nvkm_output_dp_impl
+gf110_sor_dp_impl = {
+ .base.base.handle = DCB_OUTPUT_DP,
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_output_dp_ctor,
+ .dtor = _nvkm_output_dp_dtor,
+ .init = _nvkm_output_dp_init,
+ .fini = _nvkm_output_dp_fini,
+ },
+ .pattern = gf110_sor_dp_pattern,
+ .lnk_pwr = g94_sor_dp_lnk_pwr,
+ .lnk_ctl = gf110_sor_dp_lnk_ctl,
+ .drv_ctl = gf110_sor_dp_drv_ctl,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c
new file mode 100644
index 000000000000..1e40dfe11319
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sorgm204.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outpdp.h"
+
+#include <subdev/timer.h>
+
+static inline u32
+gm204_sor_soff(struct nvkm_output_dp *outp)
+{
+ return (ffs(outp->base.info.or) - 1) * 0x800;
+}
+
+static inline u32
+gm204_sor_loff(struct nvkm_output_dp *outp)
+{
+ return gm204_sor_soff(outp) + !(outp->base.info.sorconf.link & 1) * 0x80;
+}
+
+void
+gm204_sor_magic(struct nvkm_output *outp)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 soff = outp->or * 0x100;
+ const u32 data = outp->or + 1;
+ if (outp->info.sorconf.link & 1)
+ nv_mask(priv, 0x612308 + soff, 0x0000001f, 0x00000000 | data);
+ if (outp->info.sorconf.link & 2)
+ nv_mask(priv, 0x612388 + soff, 0x0000001f, 0x00000010 | data);
+}
+
+static inline u32
+gm204_sor_dp_lane_map(struct nv50_disp_priv *priv, u8 lane)
+{
+ return lane * 0x08;
+}
+
+static int
+gm204_sor_dp_pattern(struct nvkm_output_dp *outp, int pattern)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 soff = gm204_sor_soff(outp);
+ const u32 data = 0x01010101 * pattern;
+ if (outp->base.info.sorconf.link & 1)
+ nv_mask(priv, 0x61c110 + soff, 0x0f0f0f0f, data);
+ else
+ nv_mask(priv, 0x61c12c + soff, 0x0f0f0f0f, data);
+ return 0;
+}
+
+static int
+gm204_sor_dp_lnk_pwr(struct nvkm_output_dp *outp, int nr)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ const u32 soff = gm204_sor_soff(outp);
+ const u32 loff = gm204_sor_loff(outp);
+ u32 mask = 0, i;
+
+ for (i = 0; i < nr; i++)
+ mask |= 1 << (gm204_sor_dp_lane_map(priv, i) >> 3);
+
+ nv_mask(priv, 0x61c130 + loff, 0x0000000f, mask);
+ nv_mask(priv, 0x61c034 + soff, 0x80000000, 0x80000000);
+ nv_wait(priv, 0x61c034 + soff, 0x80000000, 0x00000000);
+ return 0;
+}
+
+static int
+gm204_sor_dp_drv_ctl(struct nvkm_output_dp *outp,
+ int ln, int vs, int pe, int pc)
+{
+ struct nv50_disp_priv *priv = (void *)nvkm_disp(outp);
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ const u32 shift = gm204_sor_dp_lane_map(priv, ln);
+ const u32 loff = gm204_sor_loff(outp);
+ u32 addr, data[4];
+ u8 ver, hdr, cnt, len;
+ struct nvbios_dpout info;
+ struct nvbios_dpcfg ocfg;
+
+ addr = nvbios_dpout_match(bios, outp->base.info.hasht,
+ outp->base.info.hashm,
+ &ver, &hdr, &cnt, &len, &info);
+ if (!addr)
+ return -ENODEV;
+
+ addr = nvbios_dpcfg_match(bios, addr, pc, vs, pe,
+ &ver, &hdr, &cnt, &len, &ocfg);
+ if (!addr)
+ return -EINVAL;
+
+ data[0] = nv_rd32(priv, 0x61c118 + loff) & ~(0x000000ff << shift);
+ data[1] = nv_rd32(priv, 0x61c120 + loff) & ~(0x000000ff << shift);
+ data[2] = nv_rd32(priv, 0x61c130 + loff);
+ if ((data[2] & 0x0000ff00) < (ocfg.tx_pu << 8) || ln == 0)
+ data[2] = (data[2] & ~0x0000ff00) | (ocfg.tx_pu << 8);
+ nv_wr32(priv, 0x61c118 + loff, data[0] | (ocfg.dc << shift));
+ nv_wr32(priv, 0x61c120 + loff, data[1] | (ocfg.pe << shift));
+ nv_wr32(priv, 0x61c130 + loff, data[2] | (ocfg.tx_pu << 8));
+ data[3] = nv_rd32(priv, 0x61c13c + loff) & ~(0x000000ff << shift);
+ nv_wr32(priv, 0x61c13c + loff, data[3] | (ocfg.pc << shift));
+ return 0;
+}
+
+struct nvkm_output_dp_impl
+gm204_sor_dp_impl = {
+ .base.base.handle = DCB_OUTPUT_DP,
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_output_dp_ctor,
+ .dtor = _nvkm_output_dp_dtor,
+ .init = _nvkm_output_dp_init,
+ .fini = _nvkm_output_dp_fini,
+ },
+ .pattern = gm204_sor_dp_pattern,
+ .lnk_pwr = gm204_sor_dp_lnk_pwr,
+ .lnk_ctl = gf110_sor_dp_lnk_ctl,
+ .drv_ctl = gm204_sor_dp_drv_ctl,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
new file mode 100644
index 000000000000..b229a311c78c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/sornv50.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "outp.h"
+
+#include <core/client.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+int
+nv50_sor_power(NV50_DISP_MTHD_V1)
+{
+ union {
+ struct nv50_disp_sor_pwr_v0 v0;
+ } *args = data;
+ const u32 soff = outp->or * 0x800;
+ u32 stat;
+ int ret;
+
+ nv_ioctl(object, "disp sor pwr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "disp sor pwr vers %d state %d\n",
+ args->v0.version, args->v0.state);
+ stat = !!args->v0.state;
+ } else
+ return ret;
+
+ nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
+ nv_mask(priv, 0x61c004 + soff, 0x80000001, 0x80000000 | stat);
+ nv_wait(priv, 0x61c004 + soff, 0x80000000, 0x00000000);
+ nv_wait(priv, 0x61c030 + soff, 0x10000000, 0x00000000);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c
new file mode 100644
index 000000000000..c4622c7388d0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/disp/vga.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/vga.h>
+
+#include <core/device.h>
+
+u8
+nv_rdport(void *obj, int head, u16 port)
+{
+ struct nvkm_device *device = nv_device(obj);
+
+ if (device->card_type >= NV_50)
+ return nv_rd08(obj, 0x601000 + port);
+
+ if (port == 0x03c0 || port == 0x03c1 || /* AR */
+ port == 0x03c2 || port == 0x03da || /* INP0 */
+ port == 0x03d4 || port == 0x03d5) /* CR */
+ return nv_rd08(obj, 0x601000 + (head * 0x2000) + port);
+
+ if (port == 0x03c2 || port == 0x03cc || /* MISC */
+ port == 0x03c4 || port == 0x03c5 || /* SR */
+ port == 0x03ce || port == 0x03cf) { /* GR */
+ if (device->card_type < NV_40)
+ head = 0; /* CR44 selects head */
+ return nv_rd08(obj, 0x0c0000 + (head * 0x2000) + port);
+ }
+
+ nv_error(obj, "unknown vga port 0x%04x\n", port);
+ return 0x00;
+}
+
+void
+nv_wrport(void *obj, int head, u16 port, u8 data)
+{
+ struct nvkm_device *device = nv_device(obj);
+
+ if (device->card_type >= NV_50)
+ nv_wr08(obj, 0x601000 + port, data);
+ else
+ if (port == 0x03c0 || port == 0x03c1 || /* AR */
+ port == 0x03c2 || port == 0x03da || /* INP0 */
+ port == 0x03d4 || port == 0x03d5) /* CR */
+ nv_wr08(obj, 0x601000 + (head * 0x2000) + port, data);
+ else
+ if (port == 0x03c2 || port == 0x03cc || /* MISC */
+ port == 0x03c4 || port == 0x03c5 || /* SR */
+ port == 0x03ce || port == 0x03cf) { /* GR */
+ if (device->card_type < NV_40)
+ head = 0; /* CR44 selects head */
+ nv_wr08(obj, 0x0c0000 + (head * 0x2000) + port, data);
+ } else
+ nv_error(obj, "unknown vga port 0x%04x\n", port);
+}
+
+u8
+nv_rdvgas(void *obj, int head, u8 index)
+{
+ nv_wrport(obj, head, 0x03c4, index);
+ return nv_rdport(obj, head, 0x03c5);
+}
+
+void
+nv_wrvgas(void *obj, int head, u8 index, u8 value)
+{
+ nv_wrport(obj, head, 0x03c4, index);
+ nv_wrport(obj, head, 0x03c5, value);
+}
+
+u8
+nv_rdvgag(void *obj, int head, u8 index)
+{
+ nv_wrport(obj, head, 0x03ce, index);
+ return nv_rdport(obj, head, 0x03cf);
+}
+
+void
+nv_wrvgag(void *obj, int head, u8 index, u8 value)
+{
+ nv_wrport(obj, head, 0x03ce, index);
+ nv_wrport(obj, head, 0x03cf, value);
+}
+
+u8
+nv_rdvgac(void *obj, int head, u8 index)
+{
+ nv_wrport(obj, head, 0x03d4, index);
+ return nv_rdport(obj, head, 0x03d5);
+}
+
+void
+nv_wrvgac(void *obj, int head, u8 index, u8 value)
+{
+ nv_wrport(obj, head, 0x03d4, index);
+ nv_wrport(obj, head, 0x03d5, value);
+}
+
+u8
+nv_rdvgai(void *obj, int head, u16 port, u8 index)
+{
+ if (port == 0x03c4) return nv_rdvgas(obj, head, index);
+ if (port == 0x03ce) return nv_rdvgag(obj, head, index);
+ if (port == 0x03d4) return nv_rdvgac(obj, head, index);
+ nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
+ return 0x00;
+}
+
+void
+nv_wrvgai(void *obj, int head, u16 port, u8 index, u8 value)
+{
+ if (port == 0x03c4) nv_wrvgas(obj, head, index, value);
+ else if (port == 0x03ce) nv_wrvgag(obj, head, index, value);
+ else if (port == 0x03d4) nv_wrvgac(obj, head, index, value);
+ else nv_error(obj, "unknown indexed vga port 0x%04x\n", port);
+}
+
+bool
+nv_lockvgac(void *obj, bool lock)
+{
+ struct nvkm_device *dev = nv_device(obj);
+
+ bool locked = !nv_rdvgac(obj, 0, 0x1f);
+ u8 data = lock ? 0x99 : 0x57;
+ if (dev->card_type < NV_50)
+ nv_wrvgac(obj, 0, 0x1f, data);
+ else
+ nv_wrvgac(obj, 0, 0x3f, data);
+ if (dev->chipset == 0x11) {
+ if (!(nv_rd32(obj, 0x001084) & 0x10000000))
+ nv_wrvgac(obj, 1, 0x1f, data);
+ }
+ return locked;
+}
+
+/* CR44 takes values 0 (head A), 3 (head B) and 4 (heads tied)
+ * it affects only the 8 bit vga io regs, which we access using mmio at
+ * 0xc{0,2}3c*, 0x60{1,3}3*, and 0x68{1,3}3d*
+ * in general, the set value of cr44 does not matter: reg access works as
+ * expected and values can be set for the appropriate head by using a 0x2000
+ * offset as required
+ * however:
+ * a) pre nv40, the head B range of PRMVIO regs at 0xc23c* was not exposed and
+ * cr44 must be set to 0 or 3 for accessing values on the correct head
+ * through the common 0xc03c* addresses
+ * b) in tied mode (4) head B is programmed to the values set on head A, and
+ * access using the head B addresses can have strange results, ergo we leave
+ * tied mode in init once we know to what cr44 should be restored on exit
+ *
+ * the owner parameter is slightly abused:
+ * 0 and 1 are treated as head values and so the set value is (owner * 3)
+ * other values are treated as literal values to set
+ */
+u8
+nv_rdvgaowner(void *obj)
+{
+ if (nv_device(obj)->card_type < NV_50) {
+ if (nv_device(obj)->chipset == 0x11) {
+ u32 tied = nv_rd32(obj, 0x001084) & 0x10000000;
+ if (tied == 0) {
+ u8 slA = nv_rdvgac(obj, 0, 0x28) & 0x80;
+ u8 tvA = nv_rdvgac(obj, 0, 0x33) & 0x01;
+ u8 slB = nv_rdvgac(obj, 1, 0x28) & 0x80;
+ u8 tvB = nv_rdvgac(obj, 1, 0x33) & 0x01;
+ if (slA && !tvA) return 0x00;
+ if (slB && !tvB) return 0x03;
+ if (slA) return 0x00;
+ if (slB) return 0x03;
+ return 0x00;
+ }
+ return 0x04;
+ }
+
+ return nv_rdvgac(obj, 0, 0x44);
+ }
+
+ nv_error(obj, "rdvgaowner after nv4x\n");
+ return 0x00;
+}
+
+void
+nv_wrvgaowner(void *obj, u8 select)
+{
+ if (nv_device(obj)->card_type < NV_50) {
+ u8 owner = (select == 1) ? 3 : select;
+ if (nv_device(obj)->chipset == 0x11) {
+ /* workaround hw lockup bug */
+ nv_rdvgac(obj, 0, 0x1f);
+ nv_rdvgac(obj, 1, 0x1f);
+ }
+
+ nv_wrvgac(obj, 0, 0x44, owner);
+
+ if (nv_device(obj)->chipset == 0x11) {
+ nv_wrvgac(obj, 0, 0x2e, owner);
+ nv_wrvgac(obj, 0, 0x2e, owner);
+ }
+ } else
+ nv_error(obj, "wrvgaowner after nv4x\n");
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild
new file mode 100644
index 000000000000..7529632dbedb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/Kbuild
@@ -0,0 +1,5 @@
+nvkm-y += nvkm/engine/dmaobj/base.o
+nvkm-y += nvkm/engine/dmaobj/nv04.o
+nvkm-y += nvkm/engine/dmaobj/nv50.o
+nvkm-y += nvkm/engine/dmaobj/gf100.o
+nvkm-y += nvkm/engine/dmaobj/gf110.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c
new file mode 100644
index 000000000000..a2b60d86baba
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/base.c
@@ -0,0 +1,164 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <subdev/fb.h>
+#include <subdev/instmem.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ const struct nvkm_dmaeng_impl *impl = (void *)
+ nv_oclass(nv_object(dmaobj)->engine);
+ int ret = 0;
+
+ if (nv_object(dmaobj) == parent) { /* ctor bind */
+ if (nv_mclass(parent->parent) == NV_DEVICE) {
+ /* delayed, or no, binding */
+ return 0;
+ }
+ ret = impl->bind(dmaobj, parent, pgpuobj);
+ if (ret == 0)
+ nvkm_object_ref(NULL, &parent);
+ return ret;
+ }
+
+ return impl->bind(dmaobj, parent, pgpuobj);
+}
+
+int
+nvkm_dmaobj_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void **pdata, u32 *psize,
+ int length, void **pobject)
+{
+ union {
+ struct nv_dma_v0 v0;
+ } *args = *pdata;
+ struct nvkm_instmem *instmem = nvkm_instmem(parent);
+ struct nvkm_client *client = nvkm_client(parent);
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_dmaobj *dmaobj;
+ void *data = *pdata;
+ u32 size = *psize;
+ int ret;
+
+ ret = nvkm_object_create_(parent, engine, oclass, 0, length, pobject);
+ dmaobj = *pobject;
+ if (ret)
+ return ret;
+
+ nv_ioctl(parent, "create dma size %d\n", *psize);
+ if (nvif_unpack(args->v0, 0, 0, true)) {
+ nv_ioctl(parent, "create dma vers %d target %d access %d "
+ "start %016llx limit %016llx\n",
+ args->v0.version, args->v0.target, args->v0.access,
+ args->v0.start, args->v0.limit);
+ dmaobj->target = args->v0.target;
+ dmaobj->access = args->v0.access;
+ dmaobj->start = args->v0.start;
+ dmaobj->limit = args->v0.limit;
+ } else
+ return ret;
+
+ *pdata = data;
+ *psize = size;
+
+ if (dmaobj->start > dmaobj->limit)
+ return -EINVAL;
+
+ switch (dmaobj->target) {
+ case NV_DMA_V0_TARGET_VM:
+ dmaobj->target = NV_MEM_TARGET_VM;
+ break;
+ case NV_DMA_V0_TARGET_VRAM:
+ if (!client->super) {
+ if (dmaobj->limit >= pfb->ram->size - instmem->reserved)
+ return -EACCES;
+ if (device->card_type >= NV_50)
+ return -EACCES;
+ }
+ dmaobj->target = NV_MEM_TARGET_VRAM;
+ break;
+ case NV_DMA_V0_TARGET_PCI:
+ if (!client->super)
+ return -EACCES;
+ dmaobj->target = NV_MEM_TARGET_PCI;
+ break;
+ case NV_DMA_V0_TARGET_PCI_US:
+ case NV_DMA_V0_TARGET_AGP:
+ if (!client->super)
+ return -EACCES;
+ dmaobj->target = NV_MEM_TARGET_PCI_NOSNOOP;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (dmaobj->access) {
+ case NV_DMA_V0_ACCESS_VM:
+ dmaobj->access = NV_MEM_ACCESS_VM;
+ break;
+ case NV_DMA_V0_ACCESS_RD:
+ dmaobj->access = NV_MEM_ACCESS_RO;
+ break;
+ case NV_DMA_V0_ACCESS_WR:
+ dmaobj->access = NV_MEM_ACCESS_WO;
+ break;
+ case NV_DMA_V0_ACCESS_RDWR:
+ dmaobj->access = NV_MEM_ACCESS_RW;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+int
+_nvkm_dmaeng_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ const struct nvkm_dmaeng_impl *impl = (void *)oclass;
+ struct nvkm_dmaeng *dmaeng;
+ int ret;
+
+ ret = nvkm_engine_create(parent, engine, oclass, true, "DMAOBJ",
+ "dmaobj", &dmaeng);
+ *pobject = nv_object(dmaeng);
+ if (ret)
+ return ret;
+
+ nv_engine(dmaeng)->sclass = impl->sclass;
+ dmaeng->bind = nvkm_dmaobj_bind;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c
new file mode 100644
index 000000000000..f880e5167e45
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf100.c
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct gf100_dmaobj_priv {
+ struct nvkm_dmaobj base;
+ u32 flags0;
+ u32 flags5;
+};
+
+static int
+gf100_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ struct gf100_dmaobj_priv *priv = (void *)dmaobj;
+ int ret;
+
+ if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+ switch (nv_mclass(parent->parent)) {
+ case GT214_DISP_CORE_CHANNEL_DMA:
+ case GT214_DISP_BASE_CHANNEL_DMA:
+ case GT214_DISP_OVERLAY_CHANNEL_DMA:
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else
+ return 0;
+
+ ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+ if (ret == 0) {
+ nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
+ nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
+ nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
+ nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
+ upper_32_bits(priv->base.start));
+ nv_wo32(*pgpuobj, 0x10, 0x00000000);
+ nv_wo32(*pgpuobj, 0x14, priv->flags5);
+ }
+
+ return ret;
+}
+
+static int
+gf100_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_dmaeng *dmaeng = (void *)engine;
+ union {
+ struct gf100_dma_v0 v0;
+ } *args;
+ struct gf100_dmaobj_priv *priv;
+ u32 kind, user, unkn;
+ int ret;
+
+ ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+ args = data;
+
+ nv_ioctl(parent, "create gf100 dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create gf100 dma vers %d priv %d kind %02x\n",
+ args->v0.version, args->v0.priv, args->v0.kind);
+ kind = args->v0.kind;
+ user = args->v0.priv;
+ unkn = 0;
+ } else
+ if (size == 0) {
+ if (priv->base.target != NV_MEM_TARGET_VM) {
+ kind = GF100_DMA_V0_KIND_PITCH;
+ user = GF100_DMA_V0_PRIV_US;
+ unkn = 2;
+ } else {
+ kind = GF100_DMA_V0_KIND_VM;
+ user = GF100_DMA_V0_PRIV_VM;
+ unkn = 0;
+ }
+ } else
+ return ret;
+
+ if (user > 2)
+ return -EINVAL;
+ priv->flags0 |= (kind << 22) | (user << 20);
+ priv->flags5 |= (unkn << 16);
+
+ switch (priv->base.target) {
+ case NV_MEM_TARGET_VM:
+ priv->flags0 |= 0x00000000;
+ break;
+ case NV_MEM_TARGET_VRAM:
+ priv->flags0 |= 0x00010000;
+ break;
+ case NV_MEM_TARGET_PCI:
+ priv->flags0 |= 0x00020000;
+ break;
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ priv->flags0 |= 0x00030000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (priv->base.access) {
+ case NV_MEM_ACCESS_VM:
+ break;
+ case NV_MEM_ACCESS_RO:
+ priv->flags0 |= 0x00040000;
+ break;
+ case NV_MEM_ACCESS_WO:
+ case NV_MEM_ACCESS_RW:
+ priv->flags0 |= 0x00080000;
+ break;
+ }
+
+ return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+gf100_dmaobj_ofuncs = {
+ .ctor = gf100_dmaobj_ctor,
+ .dtor = _nvkm_dmaobj_dtor,
+ .init = _nvkm_dmaobj_init,
+ .fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+gf100_dmaeng_sclass[] = {
+ { NV_DMA_FROM_MEMORY, &gf100_dmaobj_ofuncs },
+ { NV_DMA_TO_MEMORY, &gf100_dmaobj_ofuncs },
+ { NV_DMA_IN_MEMORY, &gf100_dmaobj_ofuncs },
+ {}
+};
+
+struct nvkm_oclass *
+gf100_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+ .base.handle = NV_ENGINE(DMAOBJ, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_dmaeng_ctor,
+ .dtor = _nvkm_dmaeng_dtor,
+ .init = _nvkm_dmaeng_init,
+ .fini = _nvkm_dmaeng_fini,
+ },
+ .sclass = gf100_dmaeng_sclass,
+ .bind = gf100_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c
new file mode 100644
index 000000000000..bf8f0f20976c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/gf110.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct gf110_dmaobj_priv {
+ struct nvkm_dmaobj base;
+ u32 flags0;
+};
+
+static int
+gf110_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ struct gf110_dmaobj_priv *priv = (void *)dmaobj;
+ int ret;
+
+ if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+ switch (nv_mclass(parent->parent)) {
+ case GF110_DISP_CORE_CHANNEL_DMA:
+ case GK104_DISP_CORE_CHANNEL_DMA:
+ case GK110_DISP_CORE_CHANNEL_DMA:
+ case GM107_DISP_CORE_CHANNEL_DMA:
+ case GM204_DISP_CORE_CHANNEL_DMA:
+ case GF110_DISP_BASE_CHANNEL_DMA:
+ case GK104_DISP_BASE_CHANNEL_DMA:
+ case GK110_DISP_BASE_CHANNEL_DMA:
+ case GF110_DISP_OVERLAY_CONTROL_DMA:
+ case GK104_DISP_OVERLAY_CONTROL_DMA:
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else
+ return 0;
+
+ ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+ if (ret == 0) {
+ nv_wo32(*pgpuobj, 0x00, priv->flags0);
+ nv_wo32(*pgpuobj, 0x04, priv->base.start >> 8);
+ nv_wo32(*pgpuobj, 0x08, priv->base.limit >> 8);
+ nv_wo32(*pgpuobj, 0x0c, 0x00000000);
+ nv_wo32(*pgpuobj, 0x10, 0x00000000);
+ nv_wo32(*pgpuobj, 0x14, 0x00000000);
+ }
+
+ return ret;
+}
+
+static int
+gf110_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_dmaeng *dmaeng = (void *)engine;
+ union {
+ struct gf110_dma_v0 v0;
+ } *args;
+ struct gf110_dmaobj_priv *priv;
+ u32 kind, page;
+ int ret;
+
+ ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+ args = data;
+
+ nv_ioctl(parent, "create gf110 dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create gf100 dma vers %d page %d kind %02x\n",
+ args->v0.version, args->v0.page, args->v0.kind);
+ kind = args->v0.kind;
+ page = args->v0.page;
+ } else
+ if (size == 0) {
+ if (priv->base.target != NV_MEM_TARGET_VM) {
+ kind = GF110_DMA_V0_KIND_PITCH;
+ page = GF110_DMA_V0_PAGE_SP;
+ } else {
+ kind = GF110_DMA_V0_KIND_VM;
+ page = GF110_DMA_V0_PAGE_LP;
+ }
+ } else
+ return ret;
+
+ if (page > 1)
+ return -EINVAL;
+ priv->flags0 = (kind << 20) | (page << 6);
+
+ switch (priv->base.target) {
+ case NV_MEM_TARGET_VRAM:
+ priv->flags0 |= 0x00000009;
+ break;
+ case NV_MEM_TARGET_VM:
+ case NV_MEM_TARGET_PCI:
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ /* XXX: don't currently know how to construct a real one
+ * of these. we only use them to represent pushbufs
+ * on these chipsets, and the classes that use them
+ * deal with the target themselves.
+ */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+gf110_dmaobj_ofuncs = {
+ .ctor = gf110_dmaobj_ctor,
+ .dtor = _nvkm_dmaobj_dtor,
+ .init = _nvkm_dmaobj_init,
+ .fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+gf110_dmaeng_sclass[] = {
+ { NV_DMA_FROM_MEMORY, &gf110_dmaobj_ofuncs },
+ { NV_DMA_TO_MEMORY, &gf110_dmaobj_ofuncs },
+ { NV_DMA_IN_MEMORY, &gf110_dmaobj_ofuncs },
+ {}
+};
+
+struct nvkm_oclass *
+gf110_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+ .base.handle = NV_ENGINE(DMAOBJ, 0xd0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_dmaeng_ctor,
+ .dtor = _nvkm_dmaeng_dtor,
+ .init = _nvkm_dmaeng_init,
+ .fini = _nvkm_dmaeng_fini,
+ },
+ .sclass = gf110_dmaeng_sclass,
+ .bind = gf110_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c
new file mode 100644
index 000000000000..b4379c2a2fb5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv04.c
@@ -0,0 +1,163 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+#include <subdev/mmu/nv04.h>
+
+#include <nvif/class.h>
+
+struct nv04_dmaobj_priv {
+ struct nvkm_dmaobj base;
+ bool clone;
+ u32 flags0;
+ u32 flags2;
+};
+
+static int
+nv04_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ struct nv04_dmaobj_priv *priv = (void *)dmaobj;
+ struct nvkm_gpuobj *gpuobj;
+ u64 offset = priv->base.start & 0xfffff000;
+ u64 adjust = priv->base.start & 0x00000fff;
+ u32 length = priv->base.limit - priv->base.start;
+ int ret;
+
+ if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+ switch (nv_mclass(parent->parent)) {
+ case NV03_CHANNEL_DMA:
+ case NV10_CHANNEL_DMA:
+ case NV17_CHANNEL_DMA:
+ case NV40_CHANNEL_DMA:
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ if (priv->clone) {
+ struct nv04_mmu_priv *mmu = nv04_mmu(dmaobj);
+ struct nvkm_gpuobj *pgt = mmu->vm->pgt[0].obj[0];
+ if (!dmaobj->start)
+ return nvkm_gpuobj_dup(parent, pgt, pgpuobj);
+ offset = nv_ro32(pgt, 8 + (offset >> 10));
+ offset &= 0xfffff000;
+ }
+
+ ret = nvkm_gpuobj_new(parent, parent, 16, 16, 0, &gpuobj);
+ *pgpuobj = gpuobj;
+ if (ret == 0) {
+ nv_wo32(*pgpuobj, 0x00, priv->flags0 | (adjust << 20));
+ nv_wo32(*pgpuobj, 0x04, length);
+ nv_wo32(*pgpuobj, 0x08, priv->flags2 | offset);
+ nv_wo32(*pgpuobj, 0x0c, priv->flags2 | offset);
+ }
+
+ return ret;
+}
+
+static int
+nv04_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_dmaeng *dmaeng = (void *)engine;
+ struct nv04_mmu_priv *mmu = nv04_mmu(engine);
+ struct nv04_dmaobj_priv *priv;
+ int ret;
+
+ ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+ *pobject = nv_object(priv);
+ if (ret || (ret = -ENOSYS, size))
+ return ret;
+
+ if (priv->base.target == NV_MEM_TARGET_VM) {
+ if (nv_object(mmu)->oclass == &nv04_mmu_oclass)
+ priv->clone = true;
+ priv->base.target = NV_MEM_TARGET_PCI;
+ priv->base.access = NV_MEM_ACCESS_RW;
+ }
+
+ priv->flags0 = nv_mclass(priv);
+ switch (priv->base.target) {
+ case NV_MEM_TARGET_VRAM:
+ priv->flags0 |= 0x00003000;
+ break;
+ case NV_MEM_TARGET_PCI:
+ priv->flags0 |= 0x00023000;
+ break;
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ priv->flags0 |= 0x00033000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (priv->base.access) {
+ case NV_MEM_ACCESS_RO:
+ priv->flags0 |= 0x00004000;
+ break;
+ case NV_MEM_ACCESS_WO:
+ priv->flags0 |= 0x00008000;
+ case NV_MEM_ACCESS_RW:
+ priv->flags2 |= 0x00000002;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+nv04_dmaobj_ofuncs = {
+ .ctor = nv04_dmaobj_ctor,
+ .dtor = _nvkm_dmaobj_dtor,
+ .init = _nvkm_dmaobj_init,
+ .fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+nv04_dmaeng_sclass[] = {
+ { NV_DMA_FROM_MEMORY, &nv04_dmaobj_ofuncs },
+ { NV_DMA_TO_MEMORY, &nv04_dmaobj_ofuncs },
+ { NV_DMA_IN_MEMORY, &nv04_dmaobj_ofuncs },
+ {}
+};
+
+struct nvkm_oclass *
+nv04_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+ .base.handle = NV_ENGINE(DMAOBJ, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_dmaeng_ctor,
+ .dtor = _nvkm_dmaeng_dtor,
+ .init = _nvkm_dmaeng_init,
+ .fini = _nvkm_dmaeng_fini,
+ },
+ .sclass = nv04_dmaeng_sclass,
+ .bind = nv04_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c
new file mode 100644
index 000000000000..4d3c828fe0e6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/nv50.c
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct nv50_dmaobj_priv {
+ struct nvkm_dmaobj base;
+ u32 flags0;
+ u32 flags5;
+};
+
+static int
+nv50_dmaobj_bind(struct nvkm_dmaobj *dmaobj, struct nvkm_object *parent,
+ struct nvkm_gpuobj **pgpuobj)
+{
+ struct nv50_dmaobj_priv *priv = (void *)dmaobj;
+ int ret;
+
+ if (!nv_iclass(parent, NV_ENGCTX_CLASS)) {
+ switch (nv_mclass(parent->parent)) {
+ case NV40_CHANNEL_DMA:
+ case NV50_CHANNEL_GPFIFO:
+ case G82_CHANNEL_GPFIFO:
+ case NV50_DISP_CORE_CHANNEL_DMA:
+ case G82_DISP_CORE_CHANNEL_DMA:
+ case GT206_DISP_CORE_CHANNEL_DMA:
+ case GT200_DISP_CORE_CHANNEL_DMA:
+ case GT214_DISP_CORE_CHANNEL_DMA:
+ case NV50_DISP_BASE_CHANNEL_DMA:
+ case G82_DISP_BASE_CHANNEL_DMA:
+ case GT200_DISP_BASE_CHANNEL_DMA:
+ case GT214_DISP_BASE_CHANNEL_DMA:
+ case NV50_DISP_OVERLAY_CHANNEL_DMA:
+ case G82_DISP_OVERLAY_CHANNEL_DMA:
+ case GT200_DISP_OVERLAY_CHANNEL_DMA:
+ case GT214_DISP_OVERLAY_CHANNEL_DMA:
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ ret = nvkm_gpuobj_new(parent, parent, 24, 32, 0, pgpuobj);
+ if (ret == 0) {
+ nv_wo32(*pgpuobj, 0x00, priv->flags0 | nv_mclass(dmaobj));
+ nv_wo32(*pgpuobj, 0x04, lower_32_bits(priv->base.limit));
+ nv_wo32(*pgpuobj, 0x08, lower_32_bits(priv->base.start));
+ nv_wo32(*pgpuobj, 0x0c, upper_32_bits(priv->base.limit) << 24 |
+ upper_32_bits(priv->base.start));
+ nv_wo32(*pgpuobj, 0x10, 0x00000000);
+ nv_wo32(*pgpuobj, 0x14, priv->flags5);
+ }
+
+ return ret;
+}
+
+static int
+nv50_dmaobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_dmaeng *dmaeng = (void *)engine;
+ union {
+ struct nv50_dma_v0 v0;
+ } *args;
+ struct nv50_dmaobj_priv *priv;
+ u32 user, part, comp, kind;
+ int ret;
+
+ ret = nvkm_dmaobj_create(parent, engine, oclass, &data, &size, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+ args = data;
+
+ nv_ioctl(parent, "create nv50 dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create nv50 dma vers %d priv %d part %d "
+ "comp %d kind %02x\n", args->v0.version,
+ args->v0.priv, args->v0.part, args->v0.comp,
+ args->v0.kind);
+ user = args->v0.priv;
+ part = args->v0.part;
+ comp = args->v0.comp;
+ kind = args->v0.kind;
+ } else
+ if (size == 0) {
+ if (priv->base.target != NV_MEM_TARGET_VM) {
+ user = NV50_DMA_V0_PRIV_US;
+ part = NV50_DMA_V0_PART_256;
+ comp = NV50_DMA_V0_COMP_NONE;
+ kind = NV50_DMA_V0_KIND_PITCH;
+ } else {
+ user = NV50_DMA_V0_PRIV_VM;
+ part = NV50_DMA_V0_PART_VM;
+ comp = NV50_DMA_V0_COMP_VM;
+ kind = NV50_DMA_V0_KIND_VM;
+ }
+ } else
+ return ret;
+
+ if (user > 2 || part > 2 || comp > 3 || kind > 0x7f)
+ return -EINVAL;
+ priv->flags0 = (comp << 29) | (kind << 22) | (user << 20);
+ priv->flags5 = (part << 16);
+
+ switch (priv->base.target) {
+ case NV_MEM_TARGET_VM:
+ priv->flags0 |= 0x00000000;
+ break;
+ case NV_MEM_TARGET_VRAM:
+ priv->flags0 |= 0x00010000;
+ break;
+ case NV_MEM_TARGET_PCI:
+ priv->flags0 |= 0x00020000;
+ break;
+ case NV_MEM_TARGET_PCI_NOSNOOP:
+ priv->flags0 |= 0x00030000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (priv->base.access) {
+ case NV_MEM_ACCESS_VM:
+ break;
+ case NV_MEM_ACCESS_RO:
+ priv->flags0 |= 0x00040000;
+ break;
+ case NV_MEM_ACCESS_WO:
+ case NV_MEM_ACCESS_RW:
+ priv->flags0 |= 0x00080000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return dmaeng->bind(&priv->base, nv_object(priv), (void *)pobject);
+}
+
+static struct nvkm_ofuncs
+nv50_dmaobj_ofuncs = {
+ .ctor = nv50_dmaobj_ctor,
+ .dtor = _nvkm_dmaobj_dtor,
+ .init = _nvkm_dmaobj_init,
+ .fini = _nvkm_dmaobj_fini,
+};
+
+static struct nvkm_oclass
+nv50_dmaeng_sclass[] = {
+ { NV_DMA_FROM_MEMORY, &nv50_dmaobj_ofuncs },
+ { NV_DMA_TO_MEMORY, &nv50_dmaobj_ofuncs },
+ { NV_DMA_IN_MEMORY, &nv50_dmaobj_ofuncs },
+ {}
+};
+
+struct nvkm_oclass *
+nv50_dmaeng_oclass = &(struct nvkm_dmaeng_impl) {
+ .base.handle = NV_ENGINE(DMAOBJ, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_dmaeng_ctor,
+ .dtor = _nvkm_dmaeng_dtor,
+ .init = _nvkm_dmaeng_init,
+ .fini = _nvkm_dmaeng_fini,
+ },
+ .sclass = nv50_dmaeng_sclass,
+ .bind = nv50_dmaobj_bind,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h
new file mode 100644
index 000000000000..44ae8a0ca65c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/dmaobj/priv.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_DMAOBJ_PRIV_H__
+#define __NVKM_DMAOBJ_PRIV_H__
+#include <engine/dmaobj.h>
+
+#define nvkm_dmaobj_create(p,e,c,pa,sa,d) \
+ nvkm_dmaobj_create_((p), (e), (c), (pa), (sa), sizeof(**d), (void **)d)
+
+int nvkm_dmaobj_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void **, u32 *,
+ int, void **);
+#define _nvkm_dmaobj_dtor nvkm_object_destroy
+#define _nvkm_dmaobj_init nvkm_object_init
+#define _nvkm_dmaobj_fini nvkm_object_fini
+
+int _nvkm_dmaeng_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+#define _nvkm_dmaeng_dtor _nvkm_engine_dtor
+#define _nvkm_dmaeng_init _nvkm_engine_init
+#define _nvkm_dmaeng_fini _nvkm_engine_fini
+
+struct nvkm_dmaeng_impl {
+ struct nvkm_oclass base;
+ struct nvkm_oclass *sclass;
+ int (*bind)(struct nvkm_dmaobj *, struct nvkm_object *,
+ struct nvkm_gpuobj **);
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
new file mode 100644
index 000000000000..30958c19e61d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/falcon.c
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <engine/falcon.h>
+
+#include <core/device.h>
+#include <subdev/timer.h>
+
+void
+nvkm_falcon_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_falcon *falcon = (void *)subdev;
+ u32 dispatch = nv_ro32(falcon, 0x01c);
+ u32 intr = nv_ro32(falcon, 0x008) & dispatch & ~(dispatch >> 16);
+
+ if (intr & 0x00000010) {
+ nv_debug(falcon, "ucode halted\n");
+ nv_wo32(falcon, 0x004, 0x00000010);
+ intr &= ~0x00000010;
+ }
+
+ if (intr) {
+ nv_error(falcon, "unhandled intr 0x%08x\n", intr);
+ nv_wo32(falcon, 0x004, intr);
+ }
+}
+
+u32
+_nvkm_falcon_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_falcon *falcon = (void *)object;
+ return nv_rd32(falcon, falcon->addr + addr);
+}
+
+void
+_nvkm_falcon_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nvkm_falcon *falcon = (void *)object;
+ nv_wr32(falcon, falcon->addr + addr, data);
+}
+
+static void *
+vmemdup(const void *src, size_t len)
+{
+ void *p = vmalloc(len);
+
+ if (p)
+ memcpy(p, src, len);
+ return p;
+}
+
+int
+_nvkm_falcon_init(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nvkm_falcon *falcon = (void *)object;
+ const struct firmware *fw;
+ char name[32] = "internal";
+ int ret, i;
+ u32 caps;
+
+ /* enable engine, and determine its capabilities */
+ ret = nvkm_engine_init(&falcon->base);
+ if (ret)
+ return ret;
+
+ if (device->chipset < 0xa3 ||
+ device->chipset == 0xaa || device->chipset == 0xac) {
+ falcon->version = 0;
+ falcon->secret = (falcon->addr == 0x087000) ? 1 : 0;
+ } else {
+ caps = nv_ro32(falcon, 0x12c);
+ falcon->version = (caps & 0x0000000f);
+ falcon->secret = (caps & 0x00000030) >> 4;
+ }
+
+ caps = nv_ro32(falcon, 0x108);
+ falcon->code.limit = (caps & 0x000001ff) << 8;
+ falcon->data.limit = (caps & 0x0003fe00) >> 1;
+
+ nv_debug(falcon, "falcon version: %d\n", falcon->version);
+ nv_debug(falcon, "secret level: %d\n", falcon->secret);
+ nv_debug(falcon, "code limit: %d\n", falcon->code.limit);
+ nv_debug(falcon, "data limit: %d\n", falcon->data.limit);
+
+ /* wait for 'uc halted' to be signalled before continuing */
+ if (falcon->secret && falcon->version < 4) {
+ if (!falcon->version)
+ nv_wait(falcon, 0x008, 0x00000010, 0x00000010);
+ else
+ nv_wait(falcon, 0x180, 0x80000000, 0);
+ nv_wo32(falcon, 0x004, 0x00000010);
+ }
+
+ /* disable all interrupts */
+ nv_wo32(falcon, 0x014, 0xffffffff);
+
+ /* no default ucode provided by the engine implementation, try and
+ * locate a "self-bootstrapping" firmware image for the engine
+ */
+ if (!falcon->code.data) {
+ snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03x",
+ device->chipset, falcon->addr >> 12);
+
+ ret = request_firmware(&fw, name, nv_device_base(device));
+ if (ret == 0) {
+ falcon->code.data = vmemdup(fw->data, fw->size);
+ falcon->code.size = fw->size;
+ falcon->data.data = NULL;
+ falcon->data.size = 0;
+ release_firmware(fw);
+ }
+
+ falcon->external = true;
+ }
+
+ /* next step is to try and load "static code/data segment" firmware
+ * images for the engine
+ */
+ if (!falcon->code.data) {
+ snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xd",
+ device->chipset, falcon->addr >> 12);
+
+ ret = request_firmware(&fw, name, nv_device_base(device));
+ if (ret) {
+ nv_error(falcon, "unable to load firmware data\n");
+ return ret;
+ }
+
+ falcon->data.data = vmemdup(fw->data, fw->size);
+ falcon->data.size = fw->size;
+ release_firmware(fw);
+ if (!falcon->data.data)
+ return -ENOMEM;
+
+ snprintf(name, sizeof(name), "nouveau/nv%02x_fuc%03xc",
+ device->chipset, falcon->addr >> 12);
+
+ ret = request_firmware(&fw, name, nv_device_base(device));
+ if (ret) {
+ nv_error(falcon, "unable to load firmware code\n");
+ return ret;
+ }
+
+ falcon->code.data = vmemdup(fw->data, fw->size);
+ falcon->code.size = fw->size;
+ release_firmware(fw);
+ if (!falcon->code.data)
+ return -ENOMEM;
+ }
+
+ nv_debug(falcon, "firmware: %s (%s)\n", name, falcon->data.data ?
+ "static code/data segments" : "self-bootstrapping");
+
+ /* ensure any "self-bootstrapping" firmware image is in vram */
+ if (!falcon->data.data && !falcon->core) {
+ ret = nvkm_gpuobj_new(object->parent, NULL, falcon->code.size,
+ 256, 0, &falcon->core);
+ if (ret) {
+ nv_error(falcon, "core allocation failed, %d\n", ret);
+ return ret;
+ }
+
+ for (i = 0; i < falcon->code.size; i += 4)
+ nv_wo32(falcon->core, i, falcon->code.data[i / 4]);
+ }
+
+ /* upload firmware bootloader (or the full code segments) */
+ if (falcon->core) {
+ if (device->card_type < NV_C0)
+ nv_wo32(falcon, 0x618, 0x04000000);
+ else
+ nv_wo32(falcon, 0x618, 0x00000114);
+ nv_wo32(falcon, 0x11c, 0);
+ nv_wo32(falcon, 0x110, falcon->core->addr >> 8);
+ nv_wo32(falcon, 0x114, 0);
+ nv_wo32(falcon, 0x118, 0x00006610);
+ } else {
+ if (falcon->code.size > falcon->code.limit ||
+ falcon->data.size > falcon->data.limit) {
+ nv_error(falcon, "ucode exceeds falcon limit(s)\n");
+ return -EINVAL;
+ }
+
+ if (falcon->version < 3) {
+ nv_wo32(falcon, 0xff8, 0x00100000);
+ for (i = 0; i < falcon->code.size / 4; i++)
+ nv_wo32(falcon, 0xff4, falcon->code.data[i]);
+ } else {
+ nv_wo32(falcon, 0x180, 0x01000000);
+ for (i = 0; i < falcon->code.size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wo32(falcon, 0x188, i >> 6);
+ nv_wo32(falcon, 0x184, falcon->code.data[i]);
+ }
+ }
+ }
+
+ /* upload data segment (if necessary), zeroing the remainder */
+ if (falcon->version < 3) {
+ nv_wo32(falcon, 0xff8, 0x00000000);
+ for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
+ nv_wo32(falcon, 0xff4, falcon->data.data[i]);
+ for (; i < falcon->data.limit; i += 4)
+ nv_wo32(falcon, 0xff4, 0x00000000);
+ } else {
+ nv_wo32(falcon, 0x1c0, 0x01000000);
+ for (i = 0; !falcon->core && i < falcon->data.size / 4; i++)
+ nv_wo32(falcon, 0x1c4, falcon->data.data[i]);
+ for (; i < falcon->data.limit / 4; i++)
+ nv_wo32(falcon, 0x1c4, 0x00000000);
+ }
+
+ /* start it running */
+ nv_wo32(falcon, 0x10c, 0x00000001); /* BLOCK_ON_FIFO */
+ nv_wo32(falcon, 0x104, 0x00000000); /* ENTRY */
+ nv_wo32(falcon, 0x100, 0x00000002); /* TRIGGER */
+ nv_wo32(falcon, 0x048, 0x00000003); /* FIFO | CHSW */
+ return 0;
+}
+
+int
+_nvkm_falcon_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_falcon *falcon = (void *)object;
+
+ if (!suspend) {
+ nvkm_gpuobj_ref(NULL, &falcon->core);
+ if (falcon->external) {
+ vfree(falcon->data.data);
+ vfree(falcon->code.data);
+ falcon->code.data = NULL;
+ }
+ }
+
+ nv_mo32(falcon, 0x048, 0x00000003, 0x00000000);
+ nv_wo32(falcon, 0x014, 0xffffffff);
+
+ return nvkm_engine_fini(&falcon->base, suspend);
+}
+
+int
+nvkm_falcon_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 addr, bool enable,
+ const char *iname, const char *fname,
+ int length, void **pobject)
+{
+ struct nvkm_falcon *falcon;
+ int ret;
+
+ ret = nvkm_engine_create_(parent, engine, oclass, enable, iname,
+ fname, length, pobject);
+ falcon = *pobject;
+ if (ret)
+ return ret;
+
+ falcon->addr = addr;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
new file mode 100644
index 000000000000..c5a2d8718c5b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/Kbuild
@@ -0,0 +1,11 @@
+nvkm-y += nvkm/engine/fifo/base.o
+nvkm-y += nvkm/engine/fifo/nv04.o
+nvkm-y += nvkm/engine/fifo/nv10.o
+nvkm-y += nvkm/engine/fifo/nv17.o
+nvkm-y += nvkm/engine/fifo/nv40.o
+nvkm-y += nvkm/engine/fifo/nv50.o
+nvkm-y += nvkm/engine/fifo/g84.o
+nvkm-y += nvkm/engine/fifo/gf100.o
+nvkm-y += nvkm/engine/fifo/gk104.o
+nvkm-y += nvkm/engine/fifo/gk20a.o
+nvkm-y += nvkm/engine/fifo/gk208.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
new file mode 100644
index 000000000000..fa223f88d25e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/base.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/fifo.h>
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/notify.h>
+#include <engine/dmaobj.h>
+
+#include <nvif/class.h>
+#include <nvif/event.h>
+#include <nvif/unpack.h>
+
+static int
+nvkm_fifo_event_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ if (size == 0) {
+ notify->size = 0;
+ notify->types = 1;
+ notify->index = 0;
+ return 0;
+ }
+ return -ENOSYS;
+}
+
+static const struct nvkm_event_func
+nvkm_fifo_event_func = {
+ .ctor = nvkm_fifo_event_ctor,
+};
+
+int
+nvkm_fifo_channel_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass,
+ int bar, u32 addr, u32 size, u32 pushbuf,
+ u64 engmask, int len, void **ptr)
+{
+ struct nvkm_device *device = nv_device(engine);
+ struct nvkm_fifo *priv = (void *)engine;
+ struct nvkm_fifo_chan *chan;
+ struct nvkm_dmaeng *dmaeng;
+ unsigned long flags;
+ int ret;
+
+ /* create base object class */
+ ret = nvkm_namedb_create_(parent, engine, oclass, 0, NULL,
+ engmask, len, ptr);
+ chan = *ptr;
+ if (ret)
+ return ret;
+
+ /* validate dma object representing push buffer */
+ chan->pushdma = (void *)nvkm_handle_ref(parent, pushbuf);
+ if (!chan->pushdma)
+ return -ENOENT;
+
+ dmaeng = (void *)chan->pushdma->base.engine;
+ switch (chan->pushdma->base.oclass->handle) {
+ case NV_DMA_FROM_MEMORY:
+ case NV_DMA_IN_MEMORY:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = dmaeng->bind(chan->pushdma, parent, &chan->pushgpu);
+ if (ret)
+ return ret;
+
+ /* find a free fifo channel */
+ spin_lock_irqsave(&priv->lock, flags);
+ for (chan->chid = priv->min; chan->chid < priv->max; chan->chid++) {
+ if (!priv->channel[chan->chid]) {
+ priv->channel[chan->chid] = nv_object(chan);
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (chan->chid == priv->max) {
+ nv_error(priv, "no free channels\n");
+ return -ENOSPC;
+ }
+
+ chan->addr = nv_device_resource_start(device, bar) +
+ addr + size * chan->chid;
+ chan->size = size;
+ nvkm_event_send(&priv->cevent, 1, 0, NULL, 0);
+ return 0;
+}
+
+void
+nvkm_fifo_channel_destroy(struct nvkm_fifo_chan *chan)
+{
+ struct nvkm_fifo *priv = (void *)nv_object(chan)->engine;
+ unsigned long flags;
+
+ if (chan->user)
+ iounmap(chan->user);
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->channel[chan->chid] = NULL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ nvkm_gpuobj_ref(NULL, &chan->pushgpu);
+ nvkm_object_ref(NULL, (struct nvkm_object **)&chan->pushdma);
+ nvkm_namedb_destroy(&chan->namedb);
+}
+
+void
+_nvkm_fifo_channel_dtor(struct nvkm_object *object)
+{
+ struct nvkm_fifo_chan *chan = (void *)object;
+ nvkm_fifo_channel_destroy(chan);
+}
+
+int
+_nvkm_fifo_channel_map(struct nvkm_object *object, u64 *addr, u32 *size)
+{
+ struct nvkm_fifo_chan *chan = (void *)object;
+ *addr = chan->addr;
+ *size = chan->size;
+ return 0;
+}
+
+u32
+_nvkm_fifo_channel_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_fifo_chan *chan = (void *)object;
+ if (unlikely(!chan->user)) {
+ chan->user = ioremap(chan->addr, chan->size);
+ if (WARN_ON_ONCE(chan->user == NULL))
+ return 0;
+ }
+ return ioread32_native(chan->user + addr);
+}
+
+void
+_nvkm_fifo_channel_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nvkm_fifo_chan *chan = (void *)object;
+ if (unlikely(!chan->user)) {
+ chan->user = ioremap(chan->addr, chan->size);
+ if (WARN_ON_ONCE(chan->user == NULL))
+ return;
+ }
+ iowrite32_native(data, chan->user + addr);
+}
+
+int
+nvkm_fifo_uevent_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ union {
+ struct nvif_notify_uevent_req none;
+ } *req = data;
+ int ret;
+
+ if (nvif_unvers(req->none)) {
+ notify->size = sizeof(struct nvif_notify_uevent_rep);
+ notify->types = 1;
+ notify->index = 0;
+ }
+
+ return ret;
+}
+
+void
+nvkm_fifo_uevent(struct nvkm_fifo *fifo)
+{
+ struct nvif_notify_uevent_rep rep = {
+ };
+ nvkm_event_send(&fifo->uevent, 1, 0, &rep, sizeof(rep));
+}
+
+int
+_nvkm_fifo_channel_ntfy(struct nvkm_object *object, u32 type,
+ struct nvkm_event **event)
+{
+ struct nvkm_fifo *fifo = (void *)object->engine;
+ switch (type) {
+ case G82_CHANNEL_DMA_V0_NTFY_UEVENT:
+ if (nv_mclass(object) >= G82_CHANNEL_DMA) {
+ *event = &fifo->uevent;
+ return 0;
+ }
+ break;
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static int
+nvkm_fifo_chid(struct nvkm_fifo *priv, struct nvkm_object *object)
+{
+ int engidx = nv_hclass(priv) & 0xff;
+
+ while (object && object->parent) {
+ if ( nv_iclass(object->parent, NV_ENGCTX_CLASS) &&
+ (nv_hclass(object->parent) & 0xff) == engidx)
+ return nvkm_fifo_chan(object)->chid;
+ object = object->parent;
+ }
+
+ return -1;
+}
+
+const char *
+nvkm_client_name_for_fifo_chid(struct nvkm_fifo *fifo, u32 chid)
+{
+ struct nvkm_fifo_chan *chan = NULL;
+ unsigned long flags;
+
+ spin_lock_irqsave(&fifo->lock, flags);
+ if (chid >= fifo->min && chid <= fifo->max)
+ chan = (void *)fifo->channel[chid];
+ spin_unlock_irqrestore(&fifo->lock, flags);
+
+ return nvkm_client_name(chan);
+}
+
+void
+nvkm_fifo_destroy(struct nvkm_fifo *priv)
+{
+ kfree(priv->channel);
+ nvkm_event_fini(&priv->uevent);
+ nvkm_event_fini(&priv->cevent);
+ nvkm_engine_destroy(&priv->base);
+}
+
+int
+nvkm_fifo_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass,
+ int min, int max, int length, void **pobject)
+{
+ struct nvkm_fifo *priv;
+ int ret;
+
+ ret = nvkm_engine_create_(parent, engine, oclass, true, "PFIFO",
+ "fifo", length, pobject);
+ priv = *pobject;
+ if (ret)
+ return ret;
+
+ priv->min = min;
+ priv->max = max;
+ priv->channel = kzalloc(sizeof(*priv->channel) * (max + 1), GFP_KERNEL);
+ if (!priv->channel)
+ return -ENOMEM;
+
+ ret = nvkm_event_init(&nvkm_fifo_event_func, 1, 1, &priv->cevent);
+ if (ret)
+ return ret;
+
+ priv->chid = nvkm_fifo_chid;
+ spin_lock_init(&priv->lock);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
new file mode 100644
index 000000000000..a04920b3cf84
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/g84.c
@@ -0,0 +1,487 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/bar.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+g84_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_base *base = (void *)parent->parent;
+ struct nvkm_gpuobj *ectx = (void *)object;
+ u64 limit = ectx->addr + ectx->size - 1;
+ u64 start = ectx->addr;
+ u32 addr;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0020; break;
+ case NVDEV_ENGINE_VP :
+ case NVDEV_ENGINE_MSPDEC: addr = 0x0040; break;
+ case NVDEV_ENGINE_MSPPP :
+ case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+ case NVDEV_ENGINE_BSP :
+ case NVDEV_ENGINE_MSVLD : addr = 0x0080; break;
+ case NVDEV_ENGINE_CIPHER:
+ case NVDEV_ENGINE_SEC : addr = 0x00a0; break;
+ case NVDEV_ENGINE_CE0 : addr = 0x00c0; break;
+ default:
+ return -EINVAL;
+ }
+
+ nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+ nv_wo32(base->eng, addr + 0x00, 0x00190000);
+ nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
+ nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
+ nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
+ upper_32_bits(start));
+ nv_wo32(base->eng, addr + 0x10, 0x00000000);
+ nv_wo32(base->eng, addr + 0x14, 0x00000000);
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+g84_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+ struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_priv *priv = (void *)parent->engine;
+ struct nv50_fifo_base *base = (void *)parent->parent;
+ struct nv50_fifo_chan *chan = (void *)parent;
+ u32 addr, save, engn;
+ bool done;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_GR : engn = 0; addr = 0x0020; break;
+ case NVDEV_ENGINE_VP :
+ case NVDEV_ENGINE_MSPDEC: engn = 3; addr = 0x0040; break;
+ case NVDEV_ENGINE_MSPPP :
+ case NVDEV_ENGINE_MPEG : engn = 1; addr = 0x0060; break;
+ case NVDEV_ENGINE_BSP :
+ case NVDEV_ENGINE_MSVLD : engn = 5; addr = 0x0080; break;
+ case NVDEV_ENGINE_CIPHER:
+ case NVDEV_ENGINE_SEC : engn = 4; addr = 0x00a0; break;
+ case NVDEV_ENGINE_CE0 : engn = 2; addr = 0x00c0; break;
+ default:
+ return -EINVAL;
+ }
+
+ save = nv_mask(priv, 0x002520, 0x0000003f, 1 << engn);
+ nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
+ done = nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff);
+ nv_wr32(priv, 0x002520, save);
+ if (!done) {
+ nv_error(priv, "channel %d [%s] unload timeout\n",
+ chan->base.chid, nvkm_client_name(chan));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ nv_wo32(base->eng, addr + 0x00, 0x00000000);
+ nv_wo32(base->eng, addr + 0x04, 0x00000000);
+ nv_wo32(base->eng, addr + 0x08, 0x00000000);
+ nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+ nv_wo32(base->eng, addr + 0x10, 0x00000000);
+ nv_wo32(base->eng, addr + 0x14, 0x00000000);
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+g84_fifo_object_attach(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 handle)
+{
+ struct nv50_fifo_chan *chan = (void *)parent;
+ u32 context;
+
+ if (nv_iclass(object, NV_GPUOBJ_CLASS))
+ context = nv_gpuobj(object)->node->offset >> 4;
+ else
+ context = 0x00000004; /* just non-zero */
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_DMAOBJ:
+ case NVDEV_ENGINE_SW : context |= 0x00000000; break;
+ case NVDEV_ENGINE_GR : context |= 0x00100000; break;
+ case NVDEV_ENGINE_MPEG :
+ case NVDEV_ENGINE_MSPPP : context |= 0x00200000; break;
+ case NVDEV_ENGINE_ME :
+ case NVDEV_ENGINE_CE0 : context |= 0x00300000; break;
+ case NVDEV_ENGINE_VP :
+ case NVDEV_ENGINE_MSPDEC: context |= 0x00400000; break;
+ case NVDEV_ENGINE_CIPHER:
+ case NVDEV_ENGINE_SEC :
+ case NVDEV_ENGINE_VIC : context |= 0x00500000; break;
+ case NVDEV_ENGINE_BSP :
+ case NVDEV_ENGINE_MSVLD : context |= 0x00600000; break;
+ default:
+ return -EINVAL;
+ }
+
+ return nvkm_ramht_insert(chan->ramht, 0, handle, context);
+}
+
+static int
+g84_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv03_channel_dma_v0 v0;
+ } *args = data;
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_base *base = (void *)parent;
+ struct nv50_fifo_chan *chan;
+ int ret;
+
+ nv_ioctl(parent, "create channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ "offset %016llx\n", args->v0.version,
+ args->v0.pushbuf, args->v0.offset);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+ 0x2000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_MPEG) |
+ (1ULL << NVDEV_ENGINE_ME) |
+ (1ULL << NVDEV_ENGINE_VP) |
+ (1ULL << NVDEV_ENGINE_CIPHER) |
+ (1ULL << NVDEV_ENGINE_SEC) |
+ (1ULL << NVDEV_ENGINE_BSP) |
+ (1ULL << NVDEV_ENGINE_MSVLD) |
+ (1ULL << NVDEV_ENGINE_MSPDEC) |
+ (1ULL << NVDEV_ENGINE_MSPPP) |
+ (1ULL << NVDEV_ENGINE_CE0) |
+ (1ULL << NVDEV_ENGINE_VIC), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ &chan->ramht);
+ if (ret)
+ return ret;
+
+ nv_parent(chan)->context_attach = g84_fifo_context_attach;
+ nv_parent(chan)->context_detach = g84_fifo_context_detach;
+ nv_parent(chan)->object_attach = g84_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+ nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x3c, 0x003f6078);
+ nv_wo32(base->ramfc, 0x44, 0x01003fff);
+ nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+ nv_wo32(base->ramfc, 0x4c, 0xffffffff);
+ nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+ nv_wo32(base->ramfc, 0x78, 0x00000000);
+ nv_wo32(base->ramfc, 0x7c, 0x30000001);
+ nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj.node->offset >> 4));
+ nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
+ nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+g84_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_channel_gpfifo_v0 v0;
+ } *args = data;
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_base *base = (void *)parent;
+ struct nv50_fifo_chan *chan;
+ u64 ioffset, ilength;
+ int ret;
+
+ nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ "ioffset %016llx ilength %08x\n",
+ args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+ args->v0.ilength);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+ 0x2000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_MPEG) |
+ (1ULL << NVDEV_ENGINE_ME) |
+ (1ULL << NVDEV_ENGINE_VP) |
+ (1ULL << NVDEV_ENGINE_CIPHER) |
+ (1ULL << NVDEV_ENGINE_SEC) |
+ (1ULL << NVDEV_ENGINE_BSP) |
+ (1ULL << NVDEV_ENGINE_MSVLD) |
+ (1ULL << NVDEV_ENGINE_MSPDEC) |
+ (1ULL << NVDEV_ENGINE_MSPPP) |
+ (1ULL << NVDEV_ENGINE_CE0) |
+ (1ULL << NVDEV_ENGINE_VIC), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ &chan->ramht);
+ if (ret)
+ return ret;
+
+ nv_parent(chan)->context_attach = g84_fifo_context_attach;
+ nv_parent(chan)->context_detach = g84_fifo_context_detach;
+ nv_parent(chan)->object_attach = g84_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+ ioffset = args->v0.ioffset;
+ ilength = order_base_2(args->v0.ilength / 8);
+
+ nv_wo32(base->ramfc, 0x3c, 0x403f6078);
+ nv_wo32(base->ramfc, 0x44, 0x01003fff);
+ nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+ nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
+ nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
+ nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+ nv_wo32(base->ramfc, 0x78, 0x00000000);
+ nv_wo32(base->ramfc, 0x7c, 0x30000001);
+ nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj.node->offset >> 4));
+ nv_wo32(base->ramfc, 0x88, base->cache->addr >> 10);
+ nv_wo32(base->ramfc, 0x98, nv_gpuobj(base)->addr >> 12);
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+g84_fifo_chan_init(struct nvkm_object *object)
+{
+ struct nv50_fifo_priv *priv = (void *)object->engine;
+ struct nv50_fifo_base *base = (void *)object->parent;
+ struct nv50_fifo_chan *chan = (void *)object;
+ struct nvkm_gpuobj *ramfc = base->ramfc;
+ u32 chid = chan->base.chid;
+ int ret;
+
+ ret = nvkm_fifo_channel_init(&chan->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 8);
+ nv50_fifo_playlist_update(priv);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+g84_fifo_ofuncs_dma = {
+ .ctor = g84_fifo_chan_ctor_dma,
+ .dtor = nv50_fifo_chan_dtor,
+ .init = g84_fifo_chan_init,
+ .fini = nv50_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_ofuncs
+g84_fifo_ofuncs_ind = {
+ .ctor = g84_fifo_chan_ctor_ind,
+ .dtor = nv50_fifo_chan_dtor,
+ .init = g84_fifo_chan_init,
+ .fini = nv50_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+g84_fifo_sclass[] = {
+ { G82_CHANNEL_DMA, &g84_fifo_ofuncs_dma },
+ { G82_CHANNEL_GPFIFO, &g84_fifo_ofuncs_ind },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static int
+g84_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_fifo_base *base;
+ int ret;
+
+ ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
+ 0x1000, NVOBJ_FLAG_HEAP, &base);
+ *pobject = nv_object(base);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200, 0,
+ NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0,
+ 0, &base->pgd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1000,
+ 0x400, NVOBJ_FLAG_ZERO_ALLOC, &base->cache);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0100,
+ 0x100, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct nvkm_oclass
+g84_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_fifo_context_ctor,
+ .dtor = nv50_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static void
+g84_fifo_uevent_init(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+ nv_mask(fifo, 0x002140, 0x40000000, 0x40000000);
+}
+
+static void
+g84_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+ nv_mask(fifo, 0x002140, 0x40000000, 0x00000000);
+}
+
+static const struct nvkm_event_func
+g84_fifo_uevent_func = {
+ .ctor = nvkm_fifo_uevent_ctor,
+ .init = g84_fifo_uevent_init,
+ .fini = g84_fifo_uevent_fini,
+};
+
+static int
+g84_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+ &priv->playlist[0]);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+ &priv->playlist[1]);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&g84_fifo_uevent_func, 1, 1, &priv->base.uevent);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = nv04_fifo_intr;
+ nv_engine(priv)->cclass = &g84_fifo_cclass;
+ nv_engine(priv)->sclass = g84_fifo_sclass;
+ priv->base.pause = nv04_fifo_pause;
+ priv->base.start = nv04_fifo_start;
+ return 0;
+}
+
+struct nvkm_oclass *
+g84_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_fifo_ctor,
+ .dtor = nv50_fifo_dtor,
+ .init = nv50_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
new file mode 100644
index 000000000000..b745252f2261
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gf100.c
@@ -0,0 +1,967 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/fifo.h>
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+#include <core/handle.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+struct gf100_fifo_priv {
+ struct nvkm_fifo base;
+
+ struct work_struct fault;
+ u64 mask;
+
+ struct {
+ struct nvkm_gpuobj *mem[2];
+ int active;
+ wait_queue_head_t wait;
+ } runlist;
+
+ struct {
+ struct nvkm_gpuobj *mem;
+ struct nvkm_vma bar;
+ } user;
+ int spoon_nr;
+};
+
+struct gf100_fifo_base {
+ struct nvkm_fifo_base base;
+ struct nvkm_gpuobj *pgd;
+ struct nvkm_vm *vm;
+};
+
+struct gf100_fifo_chan {
+ struct nvkm_fifo_chan base;
+ enum {
+ STOPPED,
+ RUNNING,
+ KILLED
+ } state;
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static void
+gf100_fifo_runlist_update(struct gf100_fifo_priv *priv)
+{
+ struct nvkm_bar *bar = nvkm_bar(priv);
+ struct nvkm_gpuobj *cur;
+ int i, p;
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ cur = priv->runlist.mem[priv->runlist.active];
+ priv->runlist.active = !priv->runlist.active;
+
+ for (i = 0, p = 0; i < 128; i++) {
+ struct gf100_fifo_chan *chan = (void *)priv->base.channel[i];
+ if (chan && chan->state == RUNNING) {
+ nv_wo32(cur, p + 0, i);
+ nv_wo32(cur, p + 4, 0x00000004);
+ p += 8;
+ }
+ }
+ bar->flush(bar);
+
+ nv_wr32(priv, 0x002270, cur->addr >> 12);
+ nv_wr32(priv, 0x002274, 0x01f00000 | (p >> 3));
+
+ if (wait_event_timeout(priv->runlist.wait,
+ !(nv_rd32(priv, 0x00227c) & 0x00100000),
+ msecs_to_jiffies(2000)) == 0)
+ nv_error(priv, "runlist update timeout\n");
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+gf100_fifo_context_attach(struct nvkm_object *parent,
+ struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gf100_fifo_base *base = (void *)parent->parent;
+ struct nvkm_engctx *ectx = (void *)object;
+ u32 addr;
+ int ret;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0210; break;
+ case NVDEV_ENGINE_CE0 : addr = 0x0230; break;
+ case NVDEV_ENGINE_CE1 : addr = 0x0240; break;
+ case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+ case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+ case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!ectx->vma.node) {
+ ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
+ NV_MEM_ACCESS_RW, &ectx->vma);
+ if (ret)
+ return ret;
+
+ nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+ }
+
+ nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
+ nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+gf100_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+ struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gf100_fifo_priv *priv = (void *)parent->engine;
+ struct gf100_fifo_base *base = (void *)parent->parent;
+ struct gf100_fifo_chan *chan = (void *)parent;
+ u32 addr;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0210; break;
+ case NVDEV_ENGINE_CE0 : addr = 0x0230; break;
+ case NVDEV_ENGINE_CE1 : addr = 0x0240; break;
+ case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+ case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+ case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+ default:
+ return -EINVAL;
+ }
+
+ nv_wr32(priv, 0x002634, chan->base.chid);
+ if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+ nv_error(priv, "channel %d [%s] kick timeout\n",
+ chan->base.chid, nvkm_client_name(chan));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ nv_wo32(base, addr + 0x00, 0x00000000);
+ nv_wo32(base, addr + 0x04, 0x00000000);
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+gf100_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_channel_gpfifo_v0 v0;
+ } *args = data;
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gf100_fifo_priv *priv = (void *)engine;
+ struct gf100_fifo_base *base = (void *)parent;
+ struct gf100_fifo_chan *chan;
+ u64 usermem, ioffset, ilength;
+ int ret, i;
+
+ nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ "ioffset %016llx ilength %08x\n",
+ args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+ args->v0.ilength);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 1,
+ priv->user.bar.offset, 0x1000,
+ args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_CE0) |
+ (1ULL << NVDEV_ENGINE_CE1) |
+ (1ULL << NVDEV_ENGINE_MSVLD) |
+ (1ULL << NVDEV_ENGINE_MSPDEC) |
+ (1ULL << NVDEV_ENGINE_MSPPP), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->context_attach = gf100_fifo_context_attach;
+ nv_parent(chan)->context_detach = gf100_fifo_context_detach;
+
+ usermem = chan->base.chid * 0x1000;
+ ioffset = args->v0.ioffset;
+ ilength = order_base_2(args->v0.ilength / 8);
+
+ for (i = 0; i < 0x1000; i += 4)
+ nv_wo32(priv->user.mem, usermem + i, 0x00000000);
+
+ nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
+ nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
+ nv_wo32(base, 0x10, 0x0000face);
+ nv_wo32(base, 0x30, 0xfffff902);
+ nv_wo32(base, 0x48, lower_32_bits(ioffset));
+ nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
+ nv_wo32(base, 0x54, 0x00000002);
+ nv_wo32(base, 0x84, 0x20400000);
+ nv_wo32(base, 0x94, 0x30000001);
+ nv_wo32(base, 0x9c, 0x00000100);
+ nv_wo32(base, 0xa4, 0x1f1f1f1f);
+ nv_wo32(base, 0xa8, 0x1f1f1f1f);
+ nv_wo32(base, 0xac, 0x0000001f);
+ nv_wo32(base, 0xb8, 0xf8000000);
+ nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
+ nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+gf100_fifo_chan_init(struct nvkm_object *object)
+{
+ struct nvkm_gpuobj *base = nv_gpuobj(object->parent);
+ struct gf100_fifo_priv *priv = (void *)object->engine;
+ struct gf100_fifo_chan *chan = (void *)object;
+ u32 chid = chan->base.chid;
+ int ret;
+
+ ret = nvkm_fifo_channel_init(&chan->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x003000 + (chid * 8), 0xc0000000 | base->addr >> 12);
+
+ if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
+ nv_wr32(priv, 0x003004 + (chid * 8), 0x001f0001);
+ gf100_fifo_runlist_update(priv);
+ }
+
+ return 0;
+}
+
+static void gf100_fifo_intr_engine(struct gf100_fifo_priv *priv);
+
+static int
+gf100_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gf100_fifo_priv *priv = (void *)object->engine;
+ struct gf100_fifo_chan *chan = (void *)object;
+ u32 chid = chan->base.chid;
+
+ if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
+ nv_mask(priv, 0x003004 + (chid * 8), 0x00000001, 0x00000000);
+ gf100_fifo_runlist_update(priv);
+ }
+
+ gf100_fifo_intr_engine(priv);
+
+ nv_wr32(priv, 0x003000 + (chid * 8), 0x00000000);
+ return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+gf100_fifo_ofuncs = {
+ .ctor = gf100_fifo_chan_ctor,
+ .dtor = _nvkm_fifo_channel_dtor,
+ .init = gf100_fifo_chan_init,
+ .fini = gf100_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+gf100_fifo_sclass[] = {
+ { FERMI_CHANNEL_GPFIFO, &gf100_fifo_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - instmem heap and vm setup
+ ******************************************************************************/
+
+static int
+gf100_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_fifo_base *base;
+ int ret;
+
+ ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC |
+ NVOBJ_FLAG_HEAP, &base);
+ *pobject = nv_object(base);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
+ &base->pgd);
+ if (ret)
+ return ret;
+
+ nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
+ nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
+ nv_wo32(base, 0x0208, 0xffffffff);
+ nv_wo32(base, 0x020c, 0x000000ff);
+
+ ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+gf100_fifo_context_dtor(struct nvkm_object *object)
+{
+ struct gf100_fifo_base *base = (void *)object;
+ nvkm_vm_ref(NULL, &base->vm, base->pgd);
+ nvkm_gpuobj_ref(NULL, &base->pgd);
+ nvkm_fifo_context_destroy(&base->base);
+}
+
+static struct nvkm_oclass
+gf100_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_fifo_context_ctor,
+ .dtor = gf100_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static inline int
+gf100_fifo_engidx(struct gf100_fifo_priv *priv, u32 engn)
+{
+ switch (engn) {
+ case NVDEV_ENGINE_GR : engn = 0; break;
+ case NVDEV_ENGINE_MSVLD : engn = 1; break;
+ case NVDEV_ENGINE_MSPPP : engn = 2; break;
+ case NVDEV_ENGINE_MSPDEC: engn = 3; break;
+ case NVDEV_ENGINE_CE0 : engn = 4; break;
+ case NVDEV_ENGINE_CE1 : engn = 5; break;
+ default:
+ return -1;
+ }
+
+ return engn;
+}
+
+static inline struct nvkm_engine *
+gf100_fifo_engine(struct gf100_fifo_priv *priv, u32 engn)
+{
+ switch (engn) {
+ case 0: engn = NVDEV_ENGINE_GR; break;
+ case 1: engn = NVDEV_ENGINE_MSVLD; break;
+ case 2: engn = NVDEV_ENGINE_MSPPP; break;
+ case 3: engn = NVDEV_ENGINE_MSPDEC; break;
+ case 4: engn = NVDEV_ENGINE_CE0; break;
+ case 5: engn = NVDEV_ENGINE_CE1; break;
+ default:
+ return NULL;
+ }
+
+ return nvkm_engine(priv, engn);
+}
+
+static void
+gf100_fifo_recover_work(struct work_struct *work)
+{
+ struct gf100_fifo_priv *priv = container_of(work, typeof(*priv), fault);
+ struct nvkm_object *engine;
+ unsigned long flags;
+ u32 engn, engm = 0;
+ u64 mask, todo;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ mask = priv->mask;
+ priv->mask = 0ULL;
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+
+ for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
+ engm |= 1 << gf100_fifo_engidx(priv, engn);
+ nv_mask(priv, 0x002630, engm, engm);
+
+ for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
+ if ((engine = (void *)nvkm_engine(priv, engn))) {
+ nv_ofuncs(engine)->fini(engine, false);
+ WARN_ON(nv_ofuncs(engine)->init(engine));
+ }
+ }
+
+ gf100_fifo_runlist_update(priv);
+ nv_wr32(priv, 0x00262c, engm);
+ nv_mask(priv, 0x002630, engm, 0x00000000);
+}
+
+static void
+gf100_fifo_recover(struct gf100_fifo_priv *priv, struct nvkm_engine *engine,
+ struct gf100_fifo_chan *chan)
+{
+ u32 chid = chan->base.chid;
+ unsigned long flags;
+
+ nv_error(priv, "%s engine fault on channel %d, recovering...\n",
+ nv_subdev(engine)->name, chid);
+
+ nv_mask(priv, 0x003004 + (chid * 0x08), 0x00000001, 0x00000000);
+ chan->state = KILLED;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ priv->mask |= 1ULL << nv_engidx(engine);
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ schedule_work(&priv->fault);
+}
+
+static int
+gf100_fifo_swmthd(struct gf100_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
+{
+ struct gf100_fifo_chan *chan = NULL;
+ struct nvkm_handle *bind;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ if (likely(chid >= priv->base.min && chid <= priv->base.max))
+ chan = (void *)priv->base.channel[chid];
+ if (unlikely(!chan))
+ goto out;
+
+ bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e);
+ if (likely(bind)) {
+ if (!mthd || !nv_call(bind->object, mthd, data))
+ ret = 0;
+ nvkm_namedb_put(bind);
+ }
+
+out:
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ return ret;
+}
+
+static const struct nvkm_enum
+gf100_fifo_sched_reason[] = {
+ { 0x0a, "CTXSW_TIMEOUT" },
+ {}
+};
+
+static void
+gf100_fifo_intr_sched_ctxsw(struct gf100_fifo_priv *priv)
+{
+ struct nvkm_engine *engine;
+ struct gf100_fifo_chan *chan;
+ u32 engn;
+
+ for (engn = 0; engn < 6; engn++) {
+ u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
+ u32 busy = (stat & 0x80000000);
+ u32 save = (stat & 0x00100000); /* maybe? */
+ u32 unk0 = (stat & 0x00040000);
+ u32 unk1 = (stat & 0x00001000);
+ u32 chid = (stat & 0x0000007f);
+ (void)save;
+
+ if (busy && unk0 && unk1) {
+ if (!(chan = (void *)priv->base.channel[chid]))
+ continue;
+ if (!(engine = gf100_fifo_engine(priv, engn)))
+ continue;
+ gf100_fifo_recover(priv, engine, chan);
+ }
+ }
+}
+
+static void
+gf100_fifo_intr_sched(struct gf100_fifo_priv *priv)
+{
+ u32 intr = nv_rd32(priv, 0x00254c);
+ u32 code = intr & 0x000000ff;
+ const struct nvkm_enum *en;
+ char enunk[6] = "";
+
+ en = nvkm_enum_find(gf100_fifo_sched_reason, code);
+ if (!en)
+ snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+ nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
+
+ switch (code) {
+ case 0x0a:
+ gf100_fifo_intr_sched_ctxsw(priv);
+ break;
+ default:
+ break;
+ }
+}
+
+static const struct nvkm_enum
+gf100_fifo_fault_engine[] = {
+ { 0x00, "PGRAPH", NULL, NVDEV_ENGINE_GR },
+ { 0x03, "PEEPHOLE", NULL, NVDEV_ENGINE_IFB },
+ { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
+ { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
+ { 0x07, "PFIFO", NULL, NVDEV_ENGINE_FIFO },
+ { 0x10, "PMSVLD", NULL, NVDEV_ENGINE_MSVLD },
+ { 0x11, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP },
+ { 0x13, "PCOUNTER" },
+ { 0x14, "PMSPDEC", NULL, NVDEV_ENGINE_MSPDEC },
+ { 0x15, "PCE0", NULL, NVDEV_ENGINE_CE0 },
+ { 0x16, "PCE1", NULL, NVDEV_ENGINE_CE1 },
+ { 0x17, "PDAEMON" },
+ {}
+};
+
+static const struct nvkm_enum
+gf100_fifo_fault_reason[] = {
+ { 0x00, "PT_NOT_PRESENT" },
+ { 0x01, "PT_TOO_SHORT" },
+ { 0x02, "PAGE_NOT_PRESENT" },
+ { 0x03, "VM_LIMIT_EXCEEDED" },
+ { 0x04, "NO_CHANNEL" },
+ { 0x05, "PAGE_SYSTEM_ONLY" },
+ { 0x06, "PAGE_READ_ONLY" },
+ { 0x0a, "COMPRESSED_SYSRAM" },
+ { 0x0c, "INVALID_STORAGE_TYPE" },
+ {}
+};
+
+static const struct nvkm_enum
+gf100_fifo_fault_hubclient[] = {
+ { 0x01, "PCOPY0" },
+ { 0x02, "PCOPY1" },
+ { 0x04, "DISPATCH" },
+ { 0x05, "CTXCTL" },
+ { 0x06, "PFIFO" },
+ { 0x07, "BAR_READ" },
+ { 0x08, "BAR_WRITE" },
+ { 0x0b, "PVP" },
+ { 0x0c, "PMSPPP" },
+ { 0x0d, "PMSVLD" },
+ { 0x11, "PCOUNTER" },
+ { 0x12, "PDAEMON" },
+ { 0x14, "CCACHE" },
+ { 0x15, "CCACHE_POST" },
+ {}
+};
+
+static const struct nvkm_enum
+gf100_fifo_fault_gpcclient[] = {
+ { 0x01, "TEX" },
+ { 0x0c, "ESETUP" },
+ { 0x0e, "CTXCTL" },
+ { 0x0f, "PROP" },
+ {}
+};
+
+static void
+gf100_fifo_intr_fault(struct gf100_fifo_priv *priv, int unit)
+{
+ u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
+ u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
+ u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
+ u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
+ u32 gpc = (stat & 0x1f000000) >> 24;
+ u32 client = (stat & 0x00001f00) >> 8;
+ u32 write = (stat & 0x00000080);
+ u32 hub = (stat & 0x00000040);
+ u32 reason = (stat & 0x0000000f);
+ struct nvkm_object *engctx = NULL, *object;
+ struct nvkm_engine *engine = NULL;
+ const struct nvkm_enum *er, *eu, *ec;
+ char erunk[6] = "";
+ char euunk[6] = "";
+ char ecunk[6] = "";
+ char gpcid[3] = "";
+
+ er = nvkm_enum_find(gf100_fifo_fault_reason, reason);
+ if (!er)
+ snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
+
+ eu = nvkm_enum_find(gf100_fifo_fault_engine, unit);
+ if (eu) {
+ switch (eu->data2) {
+ case NVDEV_SUBDEV_BAR:
+ nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+ break;
+ case NVDEV_SUBDEV_INSTMEM:
+ nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+ break;
+ case NVDEV_ENGINE_IFB:
+ nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
+ break;
+ default:
+ engine = nvkm_engine(priv, eu->data2);
+ if (engine)
+ engctx = nvkm_engctx_get(engine, inst);
+ break;
+ }
+ } else {
+ snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
+ }
+
+ if (hub) {
+ ec = nvkm_enum_find(gf100_fifo_fault_hubclient, client);
+ } else {
+ ec = nvkm_enum_find(gf100_fifo_fault_gpcclient, client);
+ snprintf(gpcid, sizeof(gpcid), "%d", gpc);
+ }
+
+ if (!ec)
+ snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
+
+ nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
+ "channel 0x%010llx [%s]\n", write ? "write" : "read",
+ (u64)vahi << 32 | valo, er ? er->name : erunk,
+ eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
+ ec ? ec->name : ecunk, (u64)inst << 12,
+ nvkm_client_name(engctx));
+
+ object = engctx;
+ while (object) {
+ switch (nv_mclass(object)) {
+ case FERMI_CHANNEL_GPFIFO:
+ gf100_fifo_recover(priv, engine, (void *)object);
+ break;
+ }
+ object = object->parent;
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static const struct nvkm_bitfield
+gf100_fifo_pbdma_intr[] = {
+/* { 0x00008000, "" } seen with null ib push */
+ { 0x00200000, "ILLEGAL_MTHD" },
+ { 0x00800000, "EMPTY_SUBC" },
+ {}
+};
+
+static void
+gf100_fifo_intr_pbdma(struct gf100_fifo_priv *priv, int unit)
+{
+ u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000));
+ u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
+ u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
+ u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0x7f;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00003ffc);
+ u32 show = stat;
+
+ if (stat & 0x00800000) {
+ if (!gf100_fifo_swmthd(priv, chid, mthd, data))
+ show &= ~0x00800000;
+ }
+
+ if (show) {
+ nv_error(priv, "PBDMA%d:", unit);
+ nvkm_bitfield_print(gf100_fifo_pbdma_intr, show);
+ pr_cont("\n");
+ nv_error(priv,
+ "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+ unit, chid,
+ nvkm_client_name_for_fifo_chid(&priv->base, chid),
+ subc, mthd, data);
+ }
+
+ nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
+ nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
+}
+
+static void
+gf100_fifo_intr_runlist(struct gf100_fifo_priv *priv)
+{
+ u32 intr = nv_rd32(priv, 0x002a00);
+
+ if (intr & 0x10000000) {
+ wake_up(&priv->runlist.wait);
+ nv_wr32(priv, 0x002a00, 0x10000000);
+ intr &= ~0x10000000;
+ }
+
+ if (intr) {
+ nv_error(priv, "RUNLIST 0x%08x\n", intr);
+ nv_wr32(priv, 0x002a00, intr);
+ }
+}
+
+static void
+gf100_fifo_intr_engine_unit(struct gf100_fifo_priv *priv, int engn)
+{
+ u32 intr = nv_rd32(priv, 0x0025a8 + (engn * 0x04));
+ u32 inte = nv_rd32(priv, 0x002628);
+ u32 unkn;
+
+ nv_wr32(priv, 0x0025a8 + (engn * 0x04), intr);
+
+ for (unkn = 0; unkn < 8; unkn++) {
+ u32 ints = (intr >> (unkn * 0x04)) & inte;
+ if (ints & 0x1) {
+ nvkm_fifo_uevent(&priv->base);
+ ints &= ~1;
+ }
+ if (ints) {
+ nv_error(priv, "ENGINE %d %d %01x", engn, unkn, ints);
+ nv_mask(priv, 0x002628, ints, 0);
+ }
+ }
+}
+
+static void
+gf100_fifo_intr_engine(struct gf100_fifo_priv *priv)
+{
+ u32 mask = nv_rd32(priv, 0x0025a4);
+ while (mask) {
+ u32 unit = __ffs(mask);
+ gf100_fifo_intr_engine_unit(priv, unit);
+ mask &= ~(1 << unit);
+ }
+}
+
+static void
+gf100_fifo_intr(struct nvkm_subdev *subdev)
+{
+ struct gf100_fifo_priv *priv = (void *)subdev;
+ u32 mask = nv_rd32(priv, 0x002140);
+ u32 stat = nv_rd32(priv, 0x002100) & mask;
+
+ if (stat & 0x00000001) {
+ u32 intr = nv_rd32(priv, 0x00252c);
+ nv_warn(priv, "INTR 0x00000001: 0x%08x\n", intr);
+ nv_wr32(priv, 0x002100, 0x00000001);
+ stat &= ~0x00000001;
+ }
+
+ if (stat & 0x00000100) {
+ gf100_fifo_intr_sched(priv);
+ nv_wr32(priv, 0x002100, 0x00000100);
+ stat &= ~0x00000100;
+ }
+
+ if (stat & 0x00010000) {
+ u32 intr = nv_rd32(priv, 0x00256c);
+ nv_warn(priv, "INTR 0x00010000: 0x%08x\n", intr);
+ nv_wr32(priv, 0x002100, 0x00010000);
+ stat &= ~0x00010000;
+ }
+
+ if (stat & 0x01000000) {
+ u32 intr = nv_rd32(priv, 0x00258c);
+ nv_warn(priv, "INTR 0x01000000: 0x%08x\n", intr);
+ nv_wr32(priv, 0x002100, 0x01000000);
+ stat &= ~0x01000000;
+ }
+
+ if (stat & 0x10000000) {
+ u32 mask = nv_rd32(priv, 0x00259c);
+ while (mask) {
+ u32 unit = __ffs(mask);
+ gf100_fifo_intr_fault(priv, unit);
+ nv_wr32(priv, 0x00259c, (1 << unit));
+ mask &= ~(1 << unit);
+ }
+ stat &= ~0x10000000;
+ }
+
+ if (stat & 0x20000000) {
+ u32 mask = nv_rd32(priv, 0x0025a0);
+ while (mask) {
+ u32 unit = __ffs(mask);
+ gf100_fifo_intr_pbdma(priv, unit);
+ nv_wr32(priv, 0x0025a0, (1 << unit));
+ mask &= ~(1 << unit);
+ }
+ stat &= ~0x20000000;
+ }
+
+ if (stat & 0x40000000) {
+ gf100_fifo_intr_runlist(priv);
+ stat &= ~0x40000000;
+ }
+
+ if (stat & 0x80000000) {
+ gf100_fifo_intr_engine(priv);
+ stat &= ~0x80000000;
+ }
+
+ if (stat) {
+ nv_error(priv, "INTR 0x%08x\n", stat);
+ nv_mask(priv, 0x002140, stat, 0x00000000);
+ nv_wr32(priv, 0x002100, stat);
+ }
+}
+
+static void
+gf100_fifo_uevent_init(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+ nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
+}
+
+static void
+gf100_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+ nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
+}
+
+static const struct nvkm_event_func
+gf100_fifo_uevent_func = {
+ .ctor = nvkm_fifo_uevent_ctor,
+ .init = gf100_fifo_uevent_init,
+ .fini = gf100_fifo_uevent_fini,
+};
+
+static int
+gf100_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 0, 127, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&priv->fault, gf100_fifo_recover_work);
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
+ &priv->runlist.mem[0]);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0x1000, 0,
+ &priv->runlist.mem[1]);
+ if (ret)
+ return ret;
+
+ init_waitqueue_head(&priv->runlist.wait);
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 0x1000, 0x1000, 0,
+ &priv->user.mem);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+ &priv->user.bar);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gf100_fifo_uevent_func, 1, 1, &priv->base.uevent);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = gf100_fifo_intr;
+ nv_engine(priv)->cclass = &gf100_fifo_cclass;
+ nv_engine(priv)->sclass = gf100_fifo_sclass;
+ return 0;
+}
+
+static void
+gf100_fifo_dtor(struct nvkm_object *object)
+{
+ struct gf100_fifo_priv *priv = (void *)object;
+
+ nvkm_gpuobj_unmap(&priv->user.bar);
+ nvkm_gpuobj_ref(NULL, &priv->user.mem);
+ nvkm_gpuobj_ref(NULL, &priv->runlist.mem[0]);
+ nvkm_gpuobj_ref(NULL, &priv->runlist.mem[1]);
+
+ nvkm_fifo_destroy(&priv->base);
+}
+
+static int
+gf100_fifo_init(struct nvkm_object *object)
+{
+ struct gf100_fifo_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nvkm_fifo_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x000204, 0xffffffff);
+ nv_wr32(priv, 0x002204, 0xffffffff);
+
+ priv->spoon_nr = hweight32(nv_rd32(priv, 0x002204));
+ nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
+
+ /* assign engines to PBDMAs */
+ if (priv->spoon_nr >= 3) {
+ nv_wr32(priv, 0x002208, ~(1 << 0)); /* PGRAPH */
+ nv_wr32(priv, 0x00220c, ~(1 << 1)); /* PVP */
+ nv_wr32(priv, 0x002210, ~(1 << 1)); /* PMSPP */
+ nv_wr32(priv, 0x002214, ~(1 << 1)); /* PMSVLD */
+ nv_wr32(priv, 0x002218, ~(1 << 2)); /* PCE0 */
+ nv_wr32(priv, 0x00221c, ~(1 << 1)); /* PCE1 */
+ }
+
+ /* PBDMA[n] */
+ for (i = 0; i < priv->spoon_nr; i++) {
+ nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+ nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+ nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+ }
+
+ nv_mask(priv, 0x002200, 0x00000001, 0x00000001);
+ nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+ nv_wr32(priv, 0x002100, 0xffffffff);
+ nv_wr32(priv, 0x002140, 0x7fffffff);
+ nv_wr32(priv, 0x002628, 0x00000001); /* ENGINE_INTR_EN */
+ return 0;
+}
+
+struct nvkm_oclass *
+gf100_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_fifo_ctor,
+ .dtor = gf100_fifo_dtor,
+ .init = gf100_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
new file mode 100644
index 000000000000..9585539e59f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.c
@@ -0,0 +1,1138 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gk104.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+#include <core/handle.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+#define _(a,b) { (a), ((1ULL << (a)) | (b)) }
+static const struct {
+ u64 subdev;
+ u64 mask;
+} fifo_engine[] = {
+ _(NVDEV_ENGINE_GR , (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_CE2)),
+ _(NVDEV_ENGINE_MSPDEC , 0),
+ _(NVDEV_ENGINE_MSPPP , 0),
+ _(NVDEV_ENGINE_MSVLD , 0),
+ _(NVDEV_ENGINE_CE0 , 0),
+ _(NVDEV_ENGINE_CE1 , 0),
+ _(NVDEV_ENGINE_MSENC , 0),
+};
+#undef _
+#define FIFO_ENGINE_NR ARRAY_SIZE(fifo_engine)
+
+struct gk104_fifo_engn {
+ struct nvkm_gpuobj *runlist[2];
+ int cur_runlist;
+ wait_queue_head_t wait;
+};
+
+struct gk104_fifo_priv {
+ struct nvkm_fifo base;
+
+ struct work_struct fault;
+ u64 mask;
+
+ struct gk104_fifo_engn engine[FIFO_ENGINE_NR];
+ struct {
+ struct nvkm_gpuobj *mem;
+ struct nvkm_vma bar;
+ } user;
+ int spoon_nr;
+};
+
+struct gk104_fifo_base {
+ struct nvkm_fifo_base base;
+ struct nvkm_gpuobj *pgd;
+ struct nvkm_vm *vm;
+};
+
+struct gk104_fifo_chan {
+ struct nvkm_fifo_chan base;
+ u32 engine;
+ enum {
+ STOPPED,
+ RUNNING,
+ KILLED
+ } state;
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static void
+gk104_fifo_runlist_update(struct gk104_fifo_priv *priv, u32 engine)
+{
+ struct nvkm_bar *bar = nvkm_bar(priv);
+ struct gk104_fifo_engn *engn = &priv->engine[engine];
+ struct nvkm_gpuobj *cur;
+ int i, p;
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ cur = engn->runlist[engn->cur_runlist];
+ engn->cur_runlist = !engn->cur_runlist;
+
+ for (i = 0, p = 0; i < priv->base.max; i++) {
+ struct gk104_fifo_chan *chan = (void *)priv->base.channel[i];
+ if (chan && chan->state == RUNNING && chan->engine == engine) {
+ nv_wo32(cur, p + 0, i);
+ nv_wo32(cur, p + 4, 0x00000000);
+ p += 8;
+ }
+ }
+ bar->flush(bar);
+
+ nv_wr32(priv, 0x002270, cur->addr >> 12);
+ nv_wr32(priv, 0x002274, (engine << 20) | (p >> 3));
+
+ if (wait_event_timeout(engn->wait, !(nv_rd32(priv, 0x002284 +
+ (engine * 0x08)) & 0x00100000),
+ msecs_to_jiffies(2000)) == 0)
+ nv_error(priv, "runlist %d update timeout\n", engine);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+gk104_fifo_context_attach(struct nvkm_object *parent,
+ struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gk104_fifo_base *base = (void *)parent->parent;
+ struct nvkm_engctx *ectx = (void *)object;
+ u32 addr;
+ int ret;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW :
+ return 0;
+ case NVDEV_ENGINE_CE0:
+ case NVDEV_ENGINE_CE1:
+ case NVDEV_ENGINE_CE2:
+ nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+ return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0210; break;
+ case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+ case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+ case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!ectx->vma.node) {
+ ret = nvkm_gpuobj_map_vm(nv_gpuobj(ectx), base->vm,
+ NV_MEM_ACCESS_RW, &ectx->vma);
+ if (ret)
+ return ret;
+
+ nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+ }
+
+ nv_wo32(base, addr + 0x00, lower_32_bits(ectx->vma.offset) | 4);
+ nv_wo32(base, addr + 0x04, upper_32_bits(ectx->vma.offset));
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+gk104_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+ struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gk104_fifo_priv *priv = (void *)parent->engine;
+ struct gk104_fifo_base *base = (void *)parent->parent;
+ struct gk104_fifo_chan *chan = (void *)parent;
+ u32 addr;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_CE0 :
+ case NVDEV_ENGINE_CE1 :
+ case NVDEV_ENGINE_CE2 : addr = 0x0000; break;
+ case NVDEV_ENGINE_GR : addr = 0x0210; break;
+ case NVDEV_ENGINE_MSVLD : addr = 0x0270; break;
+ case NVDEV_ENGINE_MSPDEC: addr = 0x0250; break;
+ case NVDEV_ENGINE_MSPPP : addr = 0x0260; break;
+ default:
+ return -EINVAL;
+ }
+
+ nv_wr32(priv, 0x002634, chan->base.chid);
+ if (!nv_wait(priv, 0x002634, 0xffffffff, chan->base.chid)) {
+ nv_error(priv, "channel %d [%s] kick timeout\n",
+ chan->base.chid, nvkm_client_name(chan));
+ if (suspend)
+ return -EBUSY;
+ }
+
+ if (addr) {
+ nv_wo32(base, addr + 0x00, 0x00000000);
+ nv_wo32(base, addr + 0x04, 0x00000000);
+ bar->flush(bar);
+ }
+
+ return 0;
+}
+
+static int
+gk104_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct kepler_channel_gpfifo_a_v0 v0;
+ } *args = data;
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct gk104_fifo_priv *priv = (void *)engine;
+ struct gk104_fifo_base *base = (void *)parent;
+ struct gk104_fifo_chan *chan;
+ u64 usermem, ioffset, ilength;
+ int ret, i;
+
+ nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ "ioffset %016llx ilength %08x engine %08x\n",
+ args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+ args->v0.ilength, args->v0.engine);
+ } else
+ return ret;
+
+ for (i = 0; i < FIFO_ENGINE_NR; i++) {
+ if (args->v0.engine & (1 << i)) {
+ if (nvkm_engine(parent, fifo_engine[i].subdev)) {
+ args->v0.engine = (1 << i);
+ break;
+ }
+ }
+ }
+
+ if (i == FIFO_ENGINE_NR) {
+ nv_error(priv, "unsupported engines 0x%08x\n", args->v0.engine);
+ return -ENODEV;
+ }
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 1,
+ priv->user.bar.offset, 0x200,
+ args->v0.pushbuf,
+ fifo_engine[i].mask, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->context_attach = gk104_fifo_context_attach;
+ nv_parent(chan)->context_detach = gk104_fifo_context_detach;
+ chan->engine = i;
+
+ usermem = chan->base.chid * 0x200;
+ ioffset = args->v0.ioffset;
+ ilength = order_base_2(args->v0.ilength / 8);
+
+ for (i = 0; i < 0x200; i += 4)
+ nv_wo32(priv->user.mem, usermem + i, 0x00000000);
+
+ nv_wo32(base, 0x08, lower_32_bits(priv->user.mem->addr + usermem));
+ nv_wo32(base, 0x0c, upper_32_bits(priv->user.mem->addr + usermem));
+ nv_wo32(base, 0x10, 0x0000face);
+ nv_wo32(base, 0x30, 0xfffff902);
+ nv_wo32(base, 0x48, lower_32_bits(ioffset));
+ nv_wo32(base, 0x4c, upper_32_bits(ioffset) | (ilength << 16));
+ nv_wo32(base, 0x84, 0x20400000);
+ nv_wo32(base, 0x94, 0x30000001);
+ nv_wo32(base, 0x9c, 0x00000100);
+ nv_wo32(base, 0xac, 0x0000001f);
+ nv_wo32(base, 0xe8, chan->base.chid);
+ nv_wo32(base, 0xb8, 0xf8000000);
+ nv_wo32(base, 0xf8, 0x10003080); /* 0x002310 */
+ nv_wo32(base, 0xfc, 0x10000010); /* 0x002350 */
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+gk104_fifo_chan_init(struct nvkm_object *object)
+{
+ struct nvkm_gpuobj *base = nv_gpuobj(object->parent);
+ struct gk104_fifo_priv *priv = (void *)object->engine;
+ struct gk104_fifo_chan *chan = (void *)object;
+ u32 chid = chan->base.chid;
+ int ret;
+
+ ret = nvkm_fifo_channel_init(&chan->base);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x800004 + (chid * 8), 0x000f0000, chan->engine << 16);
+ nv_wr32(priv, 0x800000 + (chid * 8), 0x80000000 | base->addr >> 12);
+
+ if (chan->state == STOPPED && (chan->state = RUNNING) == RUNNING) {
+ nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+ gk104_fifo_runlist_update(priv, chan->engine);
+ nv_mask(priv, 0x800004 + (chid * 8), 0x00000400, 0x00000400);
+ }
+
+ return 0;
+}
+
+static int
+gk104_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gk104_fifo_priv *priv = (void *)object->engine;
+ struct gk104_fifo_chan *chan = (void *)object;
+ u32 chid = chan->base.chid;
+
+ if (chan->state == RUNNING && (chan->state = STOPPED) == STOPPED) {
+ nv_mask(priv, 0x800004 + (chid * 8), 0x00000800, 0x00000800);
+ gk104_fifo_runlist_update(priv, chan->engine);
+ }
+
+ nv_wr32(priv, 0x800000 + (chid * 8), 0x00000000);
+ return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+gk104_fifo_ofuncs = {
+ .ctor = gk104_fifo_chan_ctor,
+ .dtor = _nvkm_fifo_channel_dtor,
+ .init = gk104_fifo_chan_init,
+ .fini = gk104_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+gk104_fifo_sclass[] = {
+ { KEPLER_CHANNEL_GPFIFO_A, &gk104_fifo_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - instmem heap and vm setup
+ ******************************************************************************/
+
+static int
+gk104_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_fifo_base *base;
+ int ret;
+
+ ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base);
+ *pobject = nv_object(base);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), NULL, 0x10000, 0x1000, 0,
+ &base->pgd);
+ if (ret)
+ return ret;
+
+ nv_wo32(base, 0x0200, lower_32_bits(base->pgd->addr));
+ nv_wo32(base, 0x0204, upper_32_bits(base->pgd->addr));
+ nv_wo32(base, 0x0208, 0xffffffff);
+ nv_wo32(base, 0x020c, 0x000000ff);
+
+ ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void
+gk104_fifo_context_dtor(struct nvkm_object *object)
+{
+ struct gk104_fifo_base *base = (void *)object;
+ nvkm_vm_ref(NULL, &base->vm, base->pgd);
+ nvkm_gpuobj_ref(NULL, &base->pgd);
+ nvkm_fifo_context_destroy(&base->base);
+}
+
+static struct nvkm_oclass
+gk104_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_fifo_context_ctor,
+ .dtor = gk104_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static inline int
+gk104_fifo_engidx(struct gk104_fifo_priv *priv, u32 engn)
+{
+ switch (engn) {
+ case NVDEV_ENGINE_GR :
+ case NVDEV_ENGINE_CE2 : engn = 0; break;
+ case NVDEV_ENGINE_MSVLD : engn = 1; break;
+ case NVDEV_ENGINE_MSPPP : engn = 2; break;
+ case NVDEV_ENGINE_MSPDEC: engn = 3; break;
+ case NVDEV_ENGINE_CE0 : engn = 4; break;
+ case NVDEV_ENGINE_CE1 : engn = 5; break;
+ case NVDEV_ENGINE_MSENC : engn = 6; break;
+ default:
+ return -1;
+ }
+
+ return engn;
+}
+
+static inline struct nvkm_engine *
+gk104_fifo_engine(struct gk104_fifo_priv *priv, u32 engn)
+{
+ if (engn >= ARRAY_SIZE(fifo_engine))
+ return NULL;
+ return nvkm_engine(priv, fifo_engine[engn].subdev);
+}
+
+static void
+gk104_fifo_recover_work(struct work_struct *work)
+{
+ struct gk104_fifo_priv *priv = container_of(work, typeof(*priv), fault);
+ struct nvkm_object *engine;
+ unsigned long flags;
+ u32 engn, engm = 0;
+ u64 mask, todo;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ mask = priv->mask;
+ priv->mask = 0ULL;
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+
+ for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn))
+ engm |= 1 << gk104_fifo_engidx(priv, engn);
+ nv_mask(priv, 0x002630, engm, engm);
+
+ for (todo = mask; engn = __ffs64(todo), todo; todo &= ~(1 << engn)) {
+ if ((engine = (void *)nvkm_engine(priv, engn))) {
+ nv_ofuncs(engine)->fini(engine, false);
+ WARN_ON(nv_ofuncs(engine)->init(engine));
+ }
+ gk104_fifo_runlist_update(priv, gk104_fifo_engidx(priv, engn));
+ }
+
+ nv_wr32(priv, 0x00262c, engm);
+ nv_mask(priv, 0x002630, engm, 0x00000000);
+}
+
+static void
+gk104_fifo_recover(struct gk104_fifo_priv *priv, struct nvkm_engine *engine,
+ struct gk104_fifo_chan *chan)
+{
+ u32 chid = chan->base.chid;
+ unsigned long flags;
+
+ nv_error(priv, "%s engine fault on channel %d, recovering...\n",
+ nv_subdev(engine)->name, chid);
+
+ nv_mask(priv, 0x800004 + (chid * 0x08), 0x00000800, 0x00000800);
+ chan->state = KILLED;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ priv->mask |= 1ULL << nv_engidx(engine);
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ schedule_work(&priv->fault);
+}
+
+static int
+gk104_fifo_swmthd(struct gk104_fifo_priv *priv, u32 chid, u32 mthd, u32 data)
+{
+ struct gk104_fifo_chan *chan = NULL;
+ struct nvkm_handle *bind;
+ unsigned long flags;
+ int ret = -EINVAL;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ if (likely(chid >= priv->base.min && chid <= priv->base.max))
+ chan = (void *)priv->base.channel[chid];
+ if (unlikely(!chan))
+ goto out;
+
+ bind = nvkm_namedb_get_class(nv_namedb(chan), 0x906e);
+ if (likely(bind)) {
+ if (!mthd || !nv_call(bind->object, mthd, data))
+ ret = 0;
+ nvkm_namedb_put(bind);
+ }
+
+out:
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ return ret;
+}
+
+static const struct nvkm_enum
+gk104_fifo_bind_reason[] = {
+ { 0x01, "BIND_NOT_UNBOUND" },
+ { 0x02, "SNOOP_WITHOUT_BAR1" },
+ { 0x03, "UNBIND_WHILE_RUNNING" },
+ { 0x05, "INVALID_RUNLIST" },
+ { 0x06, "INVALID_CTX_TGT" },
+ { 0x0b, "UNBIND_WHILE_PARKED" },
+ {}
+};
+
+static void
+gk104_fifo_intr_bind(struct gk104_fifo_priv *priv)
+{
+ u32 intr = nv_rd32(priv, 0x00252c);
+ u32 code = intr & 0x000000ff;
+ const struct nvkm_enum *en;
+ char enunk[6] = "";
+
+ en = nvkm_enum_find(gk104_fifo_bind_reason, code);
+ if (!en)
+ snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+ nv_error(priv, "BIND_ERROR [ %s ]\n", en ? en->name : enunk);
+}
+
+static const struct nvkm_enum
+gk104_fifo_sched_reason[] = {
+ { 0x0a, "CTXSW_TIMEOUT" },
+ {}
+};
+
+static void
+gk104_fifo_intr_sched_ctxsw(struct gk104_fifo_priv *priv)
+{
+ struct nvkm_engine *engine;
+ struct gk104_fifo_chan *chan;
+ u32 engn;
+
+ for (engn = 0; engn < ARRAY_SIZE(fifo_engine); engn++) {
+ u32 stat = nv_rd32(priv, 0x002640 + (engn * 0x04));
+ u32 busy = (stat & 0x80000000);
+ u32 next = (stat & 0x07ff0000) >> 16;
+ u32 chsw = (stat & 0x00008000);
+ u32 save = (stat & 0x00004000);
+ u32 load = (stat & 0x00002000);
+ u32 prev = (stat & 0x000007ff);
+ u32 chid = load ? next : prev;
+ (void)save;
+
+ if (busy && chsw) {
+ if (!(chan = (void *)priv->base.channel[chid]))
+ continue;
+ if (!(engine = gk104_fifo_engine(priv, engn)))
+ continue;
+ gk104_fifo_recover(priv, engine, chan);
+ }
+ }
+}
+
+static void
+gk104_fifo_intr_sched(struct gk104_fifo_priv *priv)
+{
+ u32 intr = nv_rd32(priv, 0x00254c);
+ u32 code = intr & 0x000000ff;
+ const struct nvkm_enum *en;
+ char enunk[6] = "";
+
+ en = nvkm_enum_find(gk104_fifo_sched_reason, code);
+ if (!en)
+ snprintf(enunk, sizeof(enunk), "UNK%02x", code);
+
+ nv_error(priv, "SCHED_ERROR [ %s ]\n", en ? en->name : enunk);
+
+ switch (code) {
+ case 0x0a:
+ gk104_fifo_intr_sched_ctxsw(priv);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+gk104_fifo_intr_chsw(struct gk104_fifo_priv *priv)
+{
+ u32 stat = nv_rd32(priv, 0x00256c);
+ nv_error(priv, "CHSW_ERROR 0x%08x\n", stat);
+ nv_wr32(priv, 0x00256c, stat);
+}
+
+static void
+gk104_fifo_intr_dropped_fault(struct gk104_fifo_priv *priv)
+{
+ u32 stat = nv_rd32(priv, 0x00259c);
+ nv_error(priv, "DROPPED_MMU_FAULT 0x%08x\n", stat);
+}
+
+static const struct nvkm_enum
+gk104_fifo_fault_engine[] = {
+ { 0x00, "GR", NULL, NVDEV_ENGINE_GR },
+ { 0x03, "IFB", NULL, NVDEV_ENGINE_IFB },
+ { 0x04, "BAR1", NULL, NVDEV_SUBDEV_BAR },
+ { 0x05, "BAR3", NULL, NVDEV_SUBDEV_INSTMEM },
+ { 0x07, "PBDMA0", NULL, NVDEV_ENGINE_FIFO },
+ { 0x08, "PBDMA1", NULL, NVDEV_ENGINE_FIFO },
+ { 0x09, "PBDMA2", NULL, NVDEV_ENGINE_FIFO },
+ { 0x10, "MSVLD", NULL, NVDEV_ENGINE_MSVLD },
+ { 0x11, "MSPPP", NULL, NVDEV_ENGINE_MSPPP },
+ { 0x13, "PERF" },
+ { 0x14, "MSPDEC", NULL, NVDEV_ENGINE_MSPDEC },
+ { 0x15, "CE0", NULL, NVDEV_ENGINE_CE0 },
+ { 0x16, "CE1", NULL, NVDEV_ENGINE_CE1 },
+ { 0x17, "PMU" },
+ { 0x19, "MSENC", NULL, NVDEV_ENGINE_MSENC },
+ { 0x1b, "CE2", NULL, NVDEV_ENGINE_CE2 },
+ {}
+};
+
+static const struct nvkm_enum
+gk104_fifo_fault_reason[] = {
+ { 0x00, "PDE" },
+ { 0x01, "PDE_SIZE" },
+ { 0x02, "PTE" },
+ { 0x03, "VA_LIMIT_VIOLATION" },
+ { 0x04, "UNBOUND_INST_BLOCK" },
+ { 0x05, "PRIV_VIOLATION" },
+ { 0x06, "RO_VIOLATION" },
+ { 0x07, "WO_VIOLATION" },
+ { 0x08, "PITCH_MASK_VIOLATION" },
+ { 0x09, "WORK_CREATION" },
+ { 0x0a, "UNSUPPORTED_APERTURE" },
+ { 0x0b, "COMPRESSION_FAILURE" },
+ { 0x0c, "UNSUPPORTED_KIND" },
+ { 0x0d, "REGION_VIOLATION" },
+ { 0x0e, "BOTH_PTES_VALID" },
+ { 0x0f, "INFO_TYPE_POISONED" },
+ {}
+};
+
+static const struct nvkm_enum
+gk104_fifo_fault_hubclient[] = {
+ { 0x00, "VIP" },
+ { 0x01, "CE0" },
+ { 0x02, "CE1" },
+ { 0x03, "DNISO" },
+ { 0x04, "FE" },
+ { 0x05, "FECS" },
+ { 0x06, "HOST" },
+ { 0x07, "HOST_CPU" },
+ { 0x08, "HOST_CPU_NB" },
+ { 0x09, "ISO" },
+ { 0x0a, "MMU" },
+ { 0x0b, "MSPDEC" },
+ { 0x0c, "MSPPP" },
+ { 0x0d, "MSVLD" },
+ { 0x0e, "NISO" },
+ { 0x0f, "P2P" },
+ { 0x10, "PD" },
+ { 0x11, "PERF" },
+ { 0x12, "PMU" },
+ { 0x13, "RASTERTWOD" },
+ { 0x14, "SCC" },
+ { 0x15, "SCC_NB" },
+ { 0x16, "SEC" },
+ { 0x17, "SSYNC" },
+ { 0x18, "GR_CE" },
+ { 0x19, "CE2" },
+ { 0x1a, "XV" },
+ { 0x1b, "MMU_NB" },
+ { 0x1c, "MSENC" },
+ { 0x1d, "DFALCON" },
+ { 0x1e, "SKED" },
+ { 0x1f, "AFALCON" },
+ {}
+};
+
+static const struct nvkm_enum
+gk104_fifo_fault_gpcclient[] = {
+ { 0x00, "L1_0" }, { 0x01, "T1_0" }, { 0x02, "PE_0" },
+ { 0x03, "L1_1" }, { 0x04, "T1_1" }, { 0x05, "PE_1" },
+ { 0x06, "L1_2" }, { 0x07, "T1_2" }, { 0x08, "PE_2" },
+ { 0x09, "L1_3" }, { 0x0a, "T1_3" }, { 0x0b, "PE_3" },
+ { 0x0c, "RAST" },
+ { 0x0d, "GCC" },
+ { 0x0e, "GPCCS" },
+ { 0x0f, "PROP_0" },
+ { 0x10, "PROP_1" },
+ { 0x11, "PROP_2" },
+ { 0x12, "PROP_3" },
+ { 0x13, "L1_4" }, { 0x14, "T1_4" }, { 0x15, "PE_4" },
+ { 0x16, "L1_5" }, { 0x17, "T1_5" }, { 0x18, "PE_5" },
+ { 0x19, "L1_6" }, { 0x1a, "T1_6" }, { 0x1b, "PE_6" },
+ { 0x1c, "L1_7" }, { 0x1d, "T1_7" }, { 0x1e, "PE_7" },
+ { 0x1f, "GPM" },
+ { 0x20, "LTP_UTLB_0" },
+ { 0x21, "LTP_UTLB_1" },
+ { 0x22, "LTP_UTLB_2" },
+ { 0x23, "LTP_UTLB_3" },
+ { 0x24, "GPC_RGG_UTLB" },
+ {}
+};
+
+static void
+gk104_fifo_intr_fault(struct gk104_fifo_priv *priv, int unit)
+{
+ u32 inst = nv_rd32(priv, 0x002800 + (unit * 0x10));
+ u32 valo = nv_rd32(priv, 0x002804 + (unit * 0x10));
+ u32 vahi = nv_rd32(priv, 0x002808 + (unit * 0x10));
+ u32 stat = nv_rd32(priv, 0x00280c + (unit * 0x10));
+ u32 gpc = (stat & 0x1f000000) >> 24;
+ u32 client = (stat & 0x00001f00) >> 8;
+ u32 write = (stat & 0x00000080);
+ u32 hub = (stat & 0x00000040);
+ u32 reason = (stat & 0x0000000f);
+ struct nvkm_object *engctx = NULL, *object;
+ struct nvkm_engine *engine = NULL;
+ const struct nvkm_enum *er, *eu, *ec;
+ char erunk[6] = "";
+ char euunk[6] = "";
+ char ecunk[6] = "";
+ char gpcid[3] = "";
+
+ er = nvkm_enum_find(gk104_fifo_fault_reason, reason);
+ if (!er)
+ snprintf(erunk, sizeof(erunk), "UNK%02X", reason);
+
+ eu = nvkm_enum_find(gk104_fifo_fault_engine, unit);
+ if (eu) {
+ switch (eu->data2) {
+ case NVDEV_SUBDEV_BAR:
+ nv_mask(priv, 0x001704, 0x00000000, 0x00000000);
+ break;
+ case NVDEV_SUBDEV_INSTMEM:
+ nv_mask(priv, 0x001714, 0x00000000, 0x00000000);
+ break;
+ case NVDEV_ENGINE_IFB:
+ nv_mask(priv, 0x001718, 0x00000000, 0x00000000);
+ break;
+ default:
+ engine = nvkm_engine(priv, eu->data2);
+ if (engine)
+ engctx = nvkm_engctx_get(engine, inst);
+ break;
+ }
+ } else {
+ snprintf(euunk, sizeof(euunk), "UNK%02x", unit);
+ }
+
+ if (hub) {
+ ec = nvkm_enum_find(gk104_fifo_fault_hubclient, client);
+ } else {
+ ec = nvkm_enum_find(gk104_fifo_fault_gpcclient, client);
+ snprintf(gpcid, sizeof(gpcid), "%d", gpc);
+ }
+
+ if (!ec)
+ snprintf(ecunk, sizeof(ecunk), "UNK%02x", client);
+
+ nv_error(priv, "%s fault at 0x%010llx [%s] from %s/%s%s%s%s on "
+ "channel 0x%010llx [%s]\n", write ? "write" : "read",
+ (u64)vahi << 32 | valo, er ? er->name : erunk,
+ eu ? eu->name : euunk, hub ? "" : "GPC", gpcid, hub ? "" : "/",
+ ec ? ec->name : ecunk, (u64)inst << 12,
+ nvkm_client_name(engctx));
+
+ object = engctx;
+ while (object) {
+ switch (nv_mclass(object)) {
+ case KEPLER_CHANNEL_GPFIFO_A:
+ gk104_fifo_recover(priv, engine, (void *)object);
+ break;
+ }
+ object = object->parent;
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static const struct nvkm_bitfield gk104_fifo_pbdma_intr_0[] = {
+ { 0x00000001, "MEMREQ" },
+ { 0x00000002, "MEMACK_TIMEOUT" },
+ { 0x00000004, "MEMACK_EXTRA" },
+ { 0x00000008, "MEMDAT_TIMEOUT" },
+ { 0x00000010, "MEMDAT_EXTRA" },
+ { 0x00000020, "MEMFLUSH" },
+ { 0x00000040, "MEMOP" },
+ { 0x00000080, "LBCONNECT" },
+ { 0x00000100, "LBREQ" },
+ { 0x00000200, "LBACK_TIMEOUT" },
+ { 0x00000400, "LBACK_EXTRA" },
+ { 0x00000800, "LBDAT_TIMEOUT" },
+ { 0x00001000, "LBDAT_EXTRA" },
+ { 0x00002000, "GPFIFO" },
+ { 0x00004000, "GPPTR" },
+ { 0x00008000, "GPENTRY" },
+ { 0x00010000, "GPCRC" },
+ { 0x00020000, "PBPTR" },
+ { 0x00040000, "PBENTRY" },
+ { 0x00080000, "PBCRC" },
+ { 0x00100000, "XBARCONNECT" },
+ { 0x00200000, "METHOD" },
+ { 0x00400000, "METHODCRC" },
+ { 0x00800000, "DEVICE" },
+ { 0x02000000, "SEMAPHORE" },
+ { 0x04000000, "ACQUIRE" },
+ { 0x08000000, "PRI" },
+ { 0x20000000, "NO_CTXSW_SEG" },
+ { 0x40000000, "PBSEG" },
+ { 0x80000000, "SIGNATURE" },
+ {}
+};
+
+static void
+gk104_fifo_intr_pbdma_0(struct gk104_fifo_priv *priv, int unit)
+{
+ u32 mask = nv_rd32(priv, 0x04010c + (unit * 0x2000));
+ u32 stat = nv_rd32(priv, 0x040108 + (unit * 0x2000)) & mask;
+ u32 addr = nv_rd32(priv, 0x0400c0 + (unit * 0x2000));
+ u32 data = nv_rd32(priv, 0x0400c4 + (unit * 0x2000));
+ u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00003ffc);
+ u32 show = stat;
+
+ if (stat & 0x00800000) {
+ if (!gk104_fifo_swmthd(priv, chid, mthd, data))
+ show &= ~0x00800000;
+ nv_wr32(priv, 0x0400c0 + (unit * 0x2000), 0x80600008);
+ }
+
+ if (show) {
+ nv_error(priv, "PBDMA%d:", unit);
+ nvkm_bitfield_print(gk104_fifo_pbdma_intr_0, show);
+ pr_cont("\n");
+ nv_error(priv,
+ "PBDMA%d: ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+ unit, chid,
+ nvkm_client_name_for_fifo_chid(&priv->base, chid),
+ subc, mthd, data);
+ }
+
+ nv_wr32(priv, 0x040108 + (unit * 0x2000), stat);
+}
+
+static const struct nvkm_bitfield gk104_fifo_pbdma_intr_1[] = {
+ { 0x00000001, "HCE_RE_ILLEGAL_OP" },
+ { 0x00000002, "HCE_RE_ALIGNB" },
+ { 0x00000004, "HCE_PRIV" },
+ { 0x00000008, "HCE_ILLEGAL_MTHD" },
+ { 0x00000010, "HCE_ILLEGAL_CLASS" },
+ {}
+};
+
+static void
+gk104_fifo_intr_pbdma_1(struct gk104_fifo_priv *priv, int unit)
+{
+ u32 mask = nv_rd32(priv, 0x04014c + (unit * 0x2000));
+ u32 stat = nv_rd32(priv, 0x040148 + (unit * 0x2000)) & mask;
+ u32 chid = nv_rd32(priv, 0x040120 + (unit * 0x2000)) & 0xfff;
+
+ if (stat) {
+ nv_error(priv, "PBDMA%d:", unit);
+ nvkm_bitfield_print(gk104_fifo_pbdma_intr_1, stat);
+ pr_cont("\n");
+ nv_error(priv, "PBDMA%d: ch %d %08x %08x\n", unit, chid,
+ nv_rd32(priv, 0x040150 + (unit * 0x2000)),
+ nv_rd32(priv, 0x040154 + (unit * 0x2000)));
+ }
+
+ nv_wr32(priv, 0x040148 + (unit * 0x2000), stat);
+}
+
+static void
+gk104_fifo_intr_runlist(struct gk104_fifo_priv *priv)
+{
+ u32 mask = nv_rd32(priv, 0x002a00);
+ while (mask) {
+ u32 engn = __ffs(mask);
+ wake_up(&priv->engine[engn].wait);
+ nv_wr32(priv, 0x002a00, 1 << engn);
+ mask &= ~(1 << engn);
+ }
+}
+
+static void
+gk104_fifo_intr_engine(struct gk104_fifo_priv *priv)
+{
+ nvkm_fifo_uevent(&priv->base);
+}
+
+static void
+gk104_fifo_intr(struct nvkm_subdev *subdev)
+{
+ struct gk104_fifo_priv *priv = (void *)subdev;
+ u32 mask = nv_rd32(priv, 0x002140);
+ u32 stat = nv_rd32(priv, 0x002100) & mask;
+
+ if (stat & 0x00000001) {
+ gk104_fifo_intr_bind(priv);
+ nv_wr32(priv, 0x002100, 0x00000001);
+ stat &= ~0x00000001;
+ }
+
+ if (stat & 0x00000010) {
+ nv_error(priv, "PIO_ERROR\n");
+ nv_wr32(priv, 0x002100, 0x00000010);
+ stat &= ~0x00000010;
+ }
+
+ if (stat & 0x00000100) {
+ gk104_fifo_intr_sched(priv);
+ nv_wr32(priv, 0x002100, 0x00000100);
+ stat &= ~0x00000100;
+ }
+
+ if (stat & 0x00010000) {
+ gk104_fifo_intr_chsw(priv);
+ nv_wr32(priv, 0x002100, 0x00010000);
+ stat &= ~0x00010000;
+ }
+
+ if (stat & 0x00800000) {
+ nv_error(priv, "FB_FLUSH_TIMEOUT\n");
+ nv_wr32(priv, 0x002100, 0x00800000);
+ stat &= ~0x00800000;
+ }
+
+ if (stat & 0x01000000) {
+ nv_error(priv, "LB_ERROR\n");
+ nv_wr32(priv, 0x002100, 0x01000000);
+ stat &= ~0x01000000;
+ }
+
+ if (stat & 0x08000000) {
+ gk104_fifo_intr_dropped_fault(priv);
+ nv_wr32(priv, 0x002100, 0x08000000);
+ stat &= ~0x08000000;
+ }
+
+ if (stat & 0x10000000) {
+ u32 mask = nv_rd32(priv, 0x00259c);
+ while (mask) {
+ u32 unit = __ffs(mask);
+ gk104_fifo_intr_fault(priv, unit);
+ nv_wr32(priv, 0x00259c, (1 << unit));
+ mask &= ~(1 << unit);
+ }
+ stat &= ~0x10000000;
+ }
+
+ if (stat & 0x20000000) {
+ u32 mask = nv_rd32(priv, 0x0025a0);
+ while (mask) {
+ u32 unit = __ffs(mask);
+ gk104_fifo_intr_pbdma_0(priv, unit);
+ gk104_fifo_intr_pbdma_1(priv, unit);
+ nv_wr32(priv, 0x0025a0, (1 << unit));
+ mask &= ~(1 << unit);
+ }
+ stat &= ~0x20000000;
+ }
+
+ if (stat & 0x40000000) {
+ gk104_fifo_intr_runlist(priv);
+ stat &= ~0x40000000;
+ }
+
+ if (stat & 0x80000000) {
+ nv_wr32(priv, 0x002100, 0x80000000);
+ gk104_fifo_intr_engine(priv);
+ stat &= ~0x80000000;
+ }
+
+ if (stat) {
+ nv_error(priv, "INTR 0x%08x\n", stat);
+ nv_mask(priv, 0x002140, stat, 0x00000000);
+ nv_wr32(priv, 0x002100, stat);
+ }
+}
+
+static void
+gk104_fifo_uevent_init(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+ nv_mask(fifo, 0x002140, 0x80000000, 0x80000000);
+}
+
+static void
+gk104_fifo_uevent_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_fifo *fifo = container_of(event, typeof(*fifo), uevent);
+ nv_mask(fifo, 0x002140, 0x80000000, 0x00000000);
+}
+
+static const struct nvkm_event_func
+gk104_fifo_uevent_func = {
+ .ctor = nvkm_fifo_uevent_ctor,
+ .init = gk104_fifo_uevent_init,
+ .fini = gk104_fifo_uevent_fini,
+};
+
+int
+gk104_fifo_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gk104_fifo_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fifo_fini(&priv->base, suspend);
+ if (ret)
+ return ret;
+
+ /* allow mmu fault interrupts, even when we're not using fifo */
+ nv_mask(priv, 0x002140, 0x10000000, 0x10000000);
+ return 0;
+}
+
+int
+gk104_fifo_init(struct nvkm_object *object)
+{
+ struct gk104_fifo_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nvkm_fifo_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* enable all available PBDMA units */
+ nv_wr32(priv, 0x000204, 0xffffffff);
+ priv->spoon_nr = hweight32(nv_rd32(priv, 0x000204));
+ nv_debug(priv, "%d PBDMA unit(s)\n", priv->spoon_nr);
+
+ /* PBDMA[n] */
+ for (i = 0; i < priv->spoon_nr; i++) {
+ nv_mask(priv, 0x04013c + (i * 0x2000), 0x10000100, 0x00000000);
+ nv_wr32(priv, 0x040108 + (i * 0x2000), 0xffffffff); /* INTR */
+ nv_wr32(priv, 0x04010c + (i * 0x2000), 0xfffffeff); /* INTREN */
+ }
+
+ /* PBDMA[n].HCE */
+ for (i = 0; i < priv->spoon_nr; i++) {
+ nv_wr32(priv, 0x040148 + (i * 0x2000), 0xffffffff); /* INTR */
+ nv_wr32(priv, 0x04014c + (i * 0x2000), 0xffffffff); /* INTREN */
+ }
+
+ nv_wr32(priv, 0x002254, 0x10000000 | priv->user.bar.offset >> 12);
+
+ nv_wr32(priv, 0x002100, 0xffffffff);
+ nv_wr32(priv, 0x002140, 0x7fffffff);
+ return 0;
+}
+
+void
+gk104_fifo_dtor(struct nvkm_object *object)
+{
+ struct gk104_fifo_priv *priv = (void *)object;
+ int i;
+
+ nvkm_gpuobj_unmap(&priv->user.bar);
+ nvkm_gpuobj_ref(NULL, &priv->user.mem);
+
+ for (i = 0; i < FIFO_ENGINE_NR; i++) {
+ nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[1]);
+ nvkm_gpuobj_ref(NULL, &priv->engine[i].runlist[0]);
+ }
+
+ nvkm_fifo_destroy(&priv->base);
+}
+
+int
+gk104_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_fifo_impl *impl = (void *)oclass;
+ struct gk104_fifo_priv *priv;
+ int ret, i;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 0,
+ impl->channels - 1, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ INIT_WORK(&priv->fault, gk104_fifo_recover_work);
+
+ for (i = 0; i < FIFO_ENGINE_NR; i++) {
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+ 0, &priv->engine[i].runlist[0]);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0x1000,
+ 0, &priv->engine[i].runlist[1]);
+ if (ret)
+ return ret;
+
+ init_waitqueue_head(&priv->engine[i].wait);
+ }
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, impl->channels * 0x200,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &priv->user.mem);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_map(priv->user.mem, NV_MEM_ACCESS_RW,
+ &priv->user.bar);
+ if (ret)
+ return ret;
+
+ ret = nvkm_event_init(&gk104_fifo_uevent_func, 1, 1, &priv->base.uevent);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = gk104_fifo_intr;
+ nv_engine(priv)->cclass = &gk104_fifo_cclass;
+ nv_engine(priv)->sclass = gk104_fifo_sclass;
+ return 0;
+}
+
+struct nvkm_oclass *
+gk104_fifo_oclass = &(struct gk104_fifo_impl) {
+ .base.handle = NV_ENGINE(FIFO, 0xe0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_fifo_ctor,
+ .dtor = gk104_fifo_dtor,
+ .init = gk104_fifo_init,
+ .fini = gk104_fifo_fini,
+ },
+ .channels = 4096,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
new file mode 100644
index 000000000000..3046e00ed6ba
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk104.h
@@ -0,0 +1,16 @@
+#ifndef __NVKM_FIFO_NVE0_H__
+#define __NVKM_FIFO_NVE0_H__
+#include <engine/fifo.h>
+
+int gk104_fifo_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void gk104_fifo_dtor(struct nvkm_object *);
+int gk104_fifo_init(struct nvkm_object *);
+int gk104_fifo_fini(struct nvkm_object *, bool);
+
+struct gk104_fifo_impl {
+ struct nvkm_oclass base;
+ u32 channels;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
new file mode 100644
index 000000000000..927092217a06
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk208.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gk104.h"
+
+struct nvkm_oclass *
+gk208_fifo_oclass = &(struct gk104_fifo_impl) {
+ .base.handle = NV_ENGINE(FIFO, 0x08),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_fifo_ctor,
+ .dtor = gk104_fifo_dtor,
+ .init = gk104_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+ .channels = 1024,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
new file mode 100644
index 000000000000..b30dc87a1357
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/gk20a.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "gk104.h"
+
+struct nvkm_oclass *
+gk20a_fifo_oclass = &(struct gk104_fifo_impl) {
+ .base.handle = NV_ENGINE(FIFO, 0xea),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_fifo_ctor,
+ .dtor = gk104_fifo_dtor,
+ .init = gk104_fifo_init,
+ .fini = gk104_fifo_fini,
+ },
+ .channels = 128,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
new file mode 100644
index 000000000000..b038b6eb51db
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.c
@@ -0,0 +1,650 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/handle.h>
+#include <core/ramht.h>
+#include <subdev/instmem/nv04.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv04_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 16, 0, 0x08, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x08, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_PULL1 },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+int
+nv04_fifo_object_attach(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 handle)
+{
+ struct nv04_fifo_priv *priv = (void *)parent->engine;
+ struct nv04_fifo_chan *chan = (void *)parent;
+ u32 context, chid = chan->base.chid;
+ int ret;
+
+ if (nv_iclass(object, NV_GPUOBJ_CLASS))
+ context = nv_gpuobj(object)->addr >> 4;
+ else
+ context = 0x00000004; /* just non-zero */
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_DMAOBJ:
+ case NVDEV_ENGINE_SW:
+ context |= 0x00000000;
+ break;
+ case NVDEV_ENGINE_GR:
+ context |= 0x00010000;
+ break;
+ case NVDEV_ENGINE_MPEG:
+ context |= 0x00020000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ context |= 0x80000000; /* valid */
+ context |= chid << 24;
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ ret = nvkm_ramht_insert(priv->ramht, chid, handle, context);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+ return ret;
+}
+
+void
+nv04_fifo_object_detach(struct nvkm_object *parent, int cookie)
+{
+ struct nv04_fifo_priv *priv = (void *)parent->engine;
+ mutex_lock(&nv_subdev(priv)->mutex);
+ nvkm_ramht_remove(priv->ramht, cookie);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+int
+nv04_fifo_context_attach(struct nvkm_object *parent,
+ struct nvkm_object *object)
+{
+ nv_engctx(object)->addr = nvkm_fifo_chan(parent)->chid;
+ return 0;
+}
+
+static int
+nv04_fifo_chan_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv03_channel_dma_v0 v0;
+ } *args = data;
+ struct nv04_fifo_priv *priv = (void *)engine;
+ struct nv04_fifo_chan *chan;
+ int ret;
+
+ nv_ioctl(parent, "create channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ "offset %016llx\n", args->v0.version,
+ args->v0.pushbuf, args->v0.offset);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+ 0x10000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+ nv_parent(chan)->context_attach = nv04_fifo_context_attach;
+ chan->ramfc = chan->base.chid * 32;
+
+ nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x08, chan->base.pushgpu->addr >> 4);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x10,
+ NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ return 0;
+}
+
+void
+nv04_fifo_chan_dtor(struct nvkm_object *object)
+{
+ struct nv04_fifo_priv *priv = (void *)object->engine;
+ struct nv04_fifo_chan *chan = (void *)object;
+ struct ramfc_desc *c = priv->ramfc_desc;
+
+ do {
+ nv_wo32(priv->ramfc, chan->ramfc + c->ctxp, 0x00000000);
+ } while ((++c)->bits);
+
+ nvkm_fifo_channel_destroy(&chan->base);
+}
+
+int
+nv04_fifo_chan_init(struct nvkm_object *object)
+{
+ struct nv04_fifo_priv *priv = (void *)object->engine;
+ struct nv04_fifo_chan *chan = (void *)object;
+ u32 mask = 1 << chan->base.chid;
+ unsigned long flags;
+ int ret;
+
+ ret = nvkm_fifo_channel_init(&chan->base);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ nv_mask(priv, NV04_PFIFO_MODE, mask, mask);
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ return 0;
+}
+
+int
+nv04_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv04_fifo_priv *priv = (void *)object->engine;
+ struct nv04_fifo_chan *chan = (void *)object;
+ struct nvkm_gpuobj *fctx = priv->ramfc;
+ struct ramfc_desc *c;
+ unsigned long flags;
+ u32 data = chan->ramfc;
+ u32 chid;
+
+ /* prevent fifo context switches */
+ spin_lock_irqsave(&priv->base.lock, flags);
+ nv_wr32(priv, NV03_PFIFO_CACHES, 0);
+
+ /* if this channel is active, replace it with a null context */
+ chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+ if (chid == chan->base.chid) {
+ nv_mask(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0x00000001, 0);
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 0);
+ nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0);
+
+ c = priv->ramfc_desc;
+ do {
+ u32 rm = ((1ULL << c->bits) - 1) << c->regs;
+ u32 cm = ((1ULL << c->bits) - 1) << c->ctxs;
+ u32 rv = (nv_rd32(priv, c->regp) & rm) >> c->regs;
+ u32 cv = (nv_ro32(fctx, c->ctxp + data) & ~cm);
+ nv_wo32(fctx, c->ctxp + data, cv | (rv << c->ctxs));
+ } while ((++c)->bits);
+
+ c = priv->ramfc_desc;
+ do {
+ nv_wr32(priv, c->regp, 0x00000000);
+ } while ((++c)->bits);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_GET, 0);
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUT, 0);
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+ }
+
+ /* restore normal operation, after disabling dma mode */
+ nv_mask(priv, NV04_PFIFO_MODE, 1 << chan->base.chid, 0);
+ nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+
+ return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+nv04_fifo_ofuncs = {
+ .ctor = nv04_fifo_chan_ctor,
+ .dtor = nv04_fifo_chan_dtor,
+ .init = nv04_fifo_chan_init,
+ .fini = nv04_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv04_fifo_sclass[] = {
+ { NV03_CHANNEL_DMA, &nv04_fifo_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+int
+nv04_fifo_context_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_fifo_base *base;
+ int ret;
+
+ ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x1000,
+ 0x1000, NVOBJ_FLAG_HEAP, &base);
+ *pobject = nv_object(base);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct nvkm_oclass
+nv04_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fifo_context_ctor,
+ .dtor = _nvkm_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+void
+nv04_fifo_pause(struct nvkm_fifo *pfifo, unsigned long *pflags)
+__acquires(priv->base.lock)
+{
+ struct nv04_fifo_priv *priv = (void *)pfifo;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ *pflags = flags;
+
+ nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000000);
+ nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000000);
+
+ /* in some cases the puller may be left in an inconsistent state
+ * if you try to stop it while it's busy translating handles.
+ * sometimes you get a CACHE_ERROR, sometimes it just fails
+ * silently; sending incorrect instance offsets to PGRAPH after
+ * it's started up again.
+ *
+ * to avoid this, we invalidate the most recently calculated
+ * instance.
+ */
+ if (!nv_wait(priv, NV04_PFIFO_CACHE1_PULL0,
+ NV04_PFIFO_CACHE1_PULL0_HASH_BUSY, 0x00000000))
+ nv_warn(priv, "timeout idling puller\n");
+
+ if (nv_rd32(priv, NV04_PFIFO_CACHE1_PULL0) &
+ NV04_PFIFO_CACHE1_PULL0_HASH_FAILED)
+ nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
+
+ nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0x00000000);
+}
+
+void
+nv04_fifo_start(struct nvkm_fifo *pfifo, unsigned long *pflags)
+__releases(priv->base.lock)
+{
+ struct nv04_fifo_priv *priv = (void *)pfifo;
+ unsigned long flags = *pflags;
+
+ nv_mask(priv, NV04_PFIFO_CACHE1_PULL0, 0x00000001, 0x00000001);
+ nv_wr32(priv, NV03_PFIFO_CACHES, 0x00000001);
+
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+}
+
+static const char *
+nv_dma_state_err(u32 state)
+{
+ static const char * const desc[] = {
+ "NONE", "CALL_SUBR_ACTIVE", "INVALID_MTHD", "RET_SUBR_INACTIVE",
+ "INVALID_CMD", "IB_EMPTY"/* NV50+ */, "MEM_FAULT", "UNK"
+ };
+ return desc[(state >> 29) & 0x7];
+}
+
+static bool
+nv04_fifo_swmthd(struct nv04_fifo_priv *priv, u32 chid, u32 addr, u32 data)
+{
+ struct nv04_fifo_chan *chan = NULL;
+ struct nvkm_handle *bind;
+ const int subc = (addr >> 13) & 0x7;
+ const int mthd = addr & 0x1ffc;
+ bool handled = false;
+ unsigned long flags;
+ u32 engine;
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ if (likely(chid >= priv->base.min && chid <= priv->base.max))
+ chan = (void *)priv->base.channel[chid];
+ if (unlikely(!chan))
+ goto out;
+
+ switch (mthd) {
+ case 0x0000:
+ bind = nvkm_namedb_get(nv_namedb(chan), data);
+ if (unlikely(!bind))
+ break;
+
+ if (nv_engidx(bind->object->engine) == NVDEV_ENGINE_SW) {
+ engine = 0x0000000f << (subc * 4);
+ chan->subc[subc] = data;
+ handled = true;
+
+ nv_mask(priv, NV04_PFIFO_CACHE1_ENGINE, engine, 0);
+ }
+
+ nvkm_namedb_put(bind);
+ break;
+ default:
+ engine = nv_rd32(priv, NV04_PFIFO_CACHE1_ENGINE);
+ if (unlikely(((engine >> (subc * 4)) & 0xf) != 0))
+ break;
+
+ bind = nvkm_namedb_get(nv_namedb(chan), chan->subc[subc]);
+ if (likely(bind)) {
+ if (!nv_call(bind->object, mthd, data))
+ handled = true;
+ nvkm_namedb_put(bind);
+ }
+ break;
+ }
+
+out:
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ return handled;
+}
+
+static void
+nv04_fifo_cache_error(struct nvkm_device *device,
+ struct nv04_fifo_priv *priv, u32 chid, u32 get)
+{
+ u32 mthd, data;
+ int ptr;
+
+ /* NV_PFIFO_CACHE1_GET actually goes to 0xffc before wrapping on my
+ * G80 chips, but CACHE1 isn't big enough for this much data.. Tests
+ * show that it wraps around to the start at GET=0x800.. No clue as to
+ * why..
+ */
+ ptr = (get & 0x7ff) >> 2;
+
+ if (device->card_type < NV_40) {
+ mthd = nv_rd32(priv, NV04_PFIFO_CACHE1_METHOD(ptr));
+ data = nv_rd32(priv, NV04_PFIFO_CACHE1_DATA(ptr));
+ } else {
+ mthd = nv_rd32(priv, NV40_PFIFO_CACHE1_METHOD(ptr));
+ data = nv_rd32(priv, NV40_PFIFO_CACHE1_DATA(ptr));
+ }
+
+ if (!nv04_fifo_swmthd(priv, chid, mthd, data)) {
+ const char *client_name =
+ nvkm_client_name_for_fifo_chid(&priv->base, chid);
+ nv_error(priv,
+ "CACHE_ERROR - ch %d [%s] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, client_name, (mthd >> 13) & 7, mthd & 0x1ffc,
+ data);
+ }
+
+ nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH, 0);
+ nv_wr32(priv, NV03_PFIFO_INTR_0, NV_PFIFO_INTR_CACHE_ERROR);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
+ nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) & ~1);
+ nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0,
+ nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH0) | 1);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_HASH, 0);
+
+ nv_wr32(priv, NV04_PFIFO_CACHE1_DMA_PUSH,
+ nv_rd32(priv, NV04_PFIFO_CACHE1_DMA_PUSH) | 1);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+}
+
+static void
+nv04_fifo_dma_pusher(struct nvkm_device *device,
+ struct nv04_fifo_priv *priv, u32 chid)
+{
+ const char *client_name;
+ u32 dma_get = nv_rd32(priv, 0x003244);
+ u32 dma_put = nv_rd32(priv, 0x003240);
+ u32 push = nv_rd32(priv, 0x003220);
+ u32 state = nv_rd32(priv, 0x003228);
+
+ client_name = nvkm_client_name_for_fifo_chid(&priv->base, chid);
+
+ if (device->card_type == NV_50) {
+ u32 ho_get = nv_rd32(priv, 0x003328);
+ u32 ho_put = nv_rd32(priv, 0x003320);
+ u32 ib_get = nv_rd32(priv, 0x003334);
+ u32 ib_put = nv_rd32(priv, 0x003330);
+
+ nv_error(priv,
+ "DMA_PUSHER - ch %d [%s] get 0x%02x%08x put 0x%02x%08x ib_get 0x%08x ib_put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
+ chid, client_name, ho_get, dma_get, ho_put, dma_put,
+ ib_get, ib_put, state, nv_dma_state_err(state), push);
+
+ /* METHOD_COUNT, in DMA_STATE on earlier chipsets */
+ nv_wr32(priv, 0x003364, 0x00000000);
+ if (dma_get != dma_put || ho_get != ho_put) {
+ nv_wr32(priv, 0x003244, dma_put);
+ nv_wr32(priv, 0x003328, ho_put);
+ } else
+ if (ib_get != ib_put)
+ nv_wr32(priv, 0x003334, ib_put);
+ } else {
+ nv_error(priv,
+ "DMA_PUSHER - ch %d [%s] get 0x%08x put 0x%08x state 0x%08x (err: %s) push 0x%08x\n",
+ chid, client_name, dma_get, dma_put, state,
+ nv_dma_state_err(state), push);
+
+ if (dma_get != dma_put)
+ nv_wr32(priv, 0x003244, dma_put);
+ }
+
+ nv_wr32(priv, 0x003228, 0x00000000);
+ nv_wr32(priv, 0x003220, 0x00000001);
+ nv_wr32(priv, 0x002100, NV_PFIFO_INTR_DMA_PUSHER);
+}
+
+void
+nv04_fifo_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_device *device = nv_device(subdev);
+ struct nv04_fifo_priv *priv = (void *)subdev;
+ uint32_t status, reassign;
+ int cnt = 0;
+
+ reassign = nv_rd32(priv, NV03_PFIFO_CACHES) & 1;
+ while ((status = nv_rd32(priv, NV03_PFIFO_INTR_0)) && (cnt++ < 100)) {
+ uint32_t chid, get;
+
+ nv_wr32(priv, NV03_PFIFO_CACHES, 0);
+
+ chid = nv_rd32(priv, NV03_PFIFO_CACHE1_PUSH1) & priv->base.max;
+ get = nv_rd32(priv, NV03_PFIFO_CACHE1_GET);
+
+ if (status & NV_PFIFO_INTR_CACHE_ERROR) {
+ nv04_fifo_cache_error(device, priv, chid, get);
+ status &= ~NV_PFIFO_INTR_CACHE_ERROR;
+ }
+
+ if (status & NV_PFIFO_INTR_DMA_PUSHER) {
+ nv04_fifo_dma_pusher(device, priv, chid);
+ status &= ~NV_PFIFO_INTR_DMA_PUSHER;
+ }
+
+ if (status & NV_PFIFO_INTR_SEMAPHORE) {
+ uint32_t sem;
+
+ status &= ~NV_PFIFO_INTR_SEMAPHORE;
+ nv_wr32(priv, NV03_PFIFO_INTR_0,
+ NV_PFIFO_INTR_SEMAPHORE);
+
+ sem = nv_rd32(priv, NV10_PFIFO_CACHE1_SEMAPHORE);
+ nv_wr32(priv, NV10_PFIFO_CACHE1_SEMAPHORE, sem | 0x1);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_GET, get + 4);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+ }
+
+ if (device->card_type == NV_50) {
+ if (status & 0x00000010) {
+ status &= ~0x00000010;
+ nv_wr32(priv, 0x002100, 0x00000010);
+ }
+
+ if (status & 0x40000000) {
+ nv_wr32(priv, 0x002100, 0x40000000);
+ nvkm_fifo_uevent(&priv->base);
+ status &= ~0x40000000;
+ }
+ }
+
+ if (status) {
+ nv_warn(priv, "unknown intr 0x%08x, ch %d\n",
+ status, chid);
+ nv_wr32(priv, NV03_PFIFO_INTR_0, status);
+ status = 0;
+ }
+
+ nv_wr32(priv, NV03_PFIFO_CACHES, reassign);
+ }
+
+ if (status) {
+ nv_error(priv, "still angry after %d spins, halt\n", cnt);
+ nv_wr32(priv, 0x002140, 0);
+ nv_wr32(priv, 0x000140, 0);
+ }
+
+ nv_wr32(priv, 0x000100, 0x00000100);
+}
+
+static int
+nv04_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_instmem_priv *imem = nv04_instmem(parent);
+ struct nv04_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 0, 15, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nvkm_ramht_ref(imem->ramht, &priv->ramht);
+ nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+ nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = nv04_fifo_intr;
+ nv_engine(priv)->cclass = &nv04_fifo_cclass;
+ nv_engine(priv)->sclass = nv04_fifo_sclass;
+ priv->base.pause = nv04_fifo_pause;
+ priv->base.start = nv04_fifo_start;
+ priv->ramfc_desc = nv04_ramfc;
+ return 0;
+}
+
+void
+nv04_fifo_dtor(struct nvkm_object *object)
+{
+ struct nv04_fifo_priv *priv = (void *)object;
+ nvkm_gpuobj_ref(NULL, &priv->ramfc);
+ nvkm_gpuobj_ref(NULL, &priv->ramro);
+ nvkm_ramht_ref(NULL, &priv->ramht);
+ nvkm_fifo_destroy(&priv->base);
+}
+
+int
+nv04_fifo_init(struct nvkm_object *object)
+{
+ struct nv04_fifo_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fifo_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
+ nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
+
+ nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+ ((priv->ramht->bits - 9) << 16) |
+ (priv->ramht->gpuobj.addr >> 8));
+ nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+ nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+ nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+ nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+ nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fifo_ctor,
+ .dtor = nv04_fifo_dtor,
+ .init = nv04_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
new file mode 100644
index 000000000000..e0e0c47cb4ca
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv04.h
@@ -0,0 +1,175 @@
+#ifndef __NV04_FIFO_H__
+#define __NV04_FIFO_H__
+#include <engine/fifo.h>
+
+#define NV04_PFIFO_DELAY_0 0x00002040
+#define NV04_PFIFO_DMA_TIMESLICE 0x00002044
+#define NV04_PFIFO_NEXT_CHANNEL 0x00002050
+#define NV03_PFIFO_INTR_0 0x00002100
+#define NV03_PFIFO_INTR_EN_0 0x00002140
+# define NV_PFIFO_INTR_CACHE_ERROR (1<<0)
+# define NV_PFIFO_INTR_RUNOUT (1<<4)
+# define NV_PFIFO_INTR_RUNOUT_OVERFLOW (1<<8)
+# define NV_PFIFO_INTR_DMA_PUSHER (1<<12)
+# define NV_PFIFO_INTR_DMA_PT (1<<16)
+# define NV_PFIFO_INTR_SEMAPHORE (1<<20)
+# define NV_PFIFO_INTR_ACQUIRE_TIMEOUT (1<<24)
+#define NV03_PFIFO_RAMHT 0x00002210
+#define NV03_PFIFO_RAMFC 0x00002214
+#define NV03_PFIFO_RAMRO 0x00002218
+#define NV40_PFIFO_RAMFC 0x00002220
+#define NV03_PFIFO_CACHES 0x00002500
+#define NV04_PFIFO_MODE 0x00002504
+#define NV04_PFIFO_DMA 0x00002508
+#define NV04_PFIFO_SIZE 0x0000250c
+#define NV50_PFIFO_CTX_TABLE(c) (0x2600+(c)*4)
+#define NV50_PFIFO_CTX_TABLE__SIZE 128
+#define NV50_PFIFO_CTX_TABLE_CHANNEL_ENABLED (1<<31)
+#define NV50_PFIFO_CTX_TABLE_UNK30_BAD (1<<30)
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G80 0x0FFFFFFF
+#define NV50_PFIFO_CTX_TABLE_INSTANCE_MASK_G84 0x00FFFFFF
+#define NV03_PFIFO_CACHE0_PUSH0 0x00003000
+#define NV03_PFIFO_CACHE0_PULL0 0x00003040
+#define NV04_PFIFO_CACHE0_PULL0 0x00003050
+#define NV04_PFIFO_CACHE0_PULL1 0x00003054
+#define NV03_PFIFO_CACHE1_PUSH0 0x00003200
+#define NV03_PFIFO_CACHE1_PUSH1 0x00003204
+#define NV03_PFIFO_CACHE1_PUSH1_DMA (1<<8)
+#define NV40_PFIFO_CACHE1_PUSH1_DMA (1<<16)
+#define NV03_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000000f
+#define NV10_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000001f
+#define NV50_PFIFO_CACHE1_PUSH1_CHID_MASK 0x0000007f
+#define NV03_PFIFO_CACHE1_PUT 0x00003210
+#define NV04_PFIFO_CACHE1_DMA_PUSH 0x00003220
+#define NV04_PFIFO_CACHE1_DMA_FETCH 0x00003224
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_8_BYTES 0x00000000
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_16_BYTES 0x00000008
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_24_BYTES 0x00000010
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_32_BYTES 0x00000018
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_40_BYTES 0x00000020
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_48_BYTES 0x00000028
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_56_BYTES 0x00000030
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_64_BYTES 0x00000038
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_72_BYTES 0x00000040
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_80_BYTES 0x00000048
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_88_BYTES 0x00000050
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_96_BYTES 0x00000058
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_104_BYTES 0x00000060
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_112_BYTES 0x00000068
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_120_BYTES 0x00000070
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES 0x00000078
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_136_BYTES 0x00000080
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_144_BYTES 0x00000088
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_152_BYTES 0x00000090
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_160_BYTES 0x00000098
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_168_BYTES 0x000000A0
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_176_BYTES 0x000000A8
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_184_BYTES 0x000000B0
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_192_BYTES 0x000000B8
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_200_BYTES 0x000000C0
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_208_BYTES 0x000000C8
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_216_BYTES 0x000000D0
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_224_BYTES 0x000000D8
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_232_BYTES 0x000000E0
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_240_BYTES 0x000000E8
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_248_BYTES 0x000000F0
+# define NV_PFIFO_CACHE1_DMA_FETCH_TRIG_256_BYTES 0x000000F8
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE 0x0000E000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_32_BYTES 0x00000000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_64_BYTES 0x00002000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_96_BYTES 0x00004000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES 0x00006000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_160_BYTES 0x00008000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_192_BYTES 0x0000A000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_224_BYTES 0x0000C000
+# define NV_PFIFO_CACHE1_DMA_FETCH_SIZE_256_BYTES 0x0000E000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS 0x001F0000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_0 0x00000000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_1 0x00010000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_2 0x00020000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_3 0x00030000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_4 0x00040000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_5 0x00050000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_6 0x00060000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_7 0x00070000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8 0x00080000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_9 0x00090000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_10 0x000A0000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_11 0x000B0000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_12 0x000C0000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_13 0x000D0000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_14 0x000E0000
+# define NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_15 0x000F0000
+# define NV_PFIFO_CACHE1_ENDIAN 0x80000000
+# define NV_PFIFO_CACHE1_LITTLE_ENDIAN 0x7FFFFFFF
+# define NV_PFIFO_CACHE1_BIG_ENDIAN 0x80000000
+#define NV04_PFIFO_CACHE1_DMA_STATE 0x00003228
+#define NV04_PFIFO_CACHE1_DMA_INSTANCE 0x0000322c
+#define NV04_PFIFO_CACHE1_DMA_CTL 0x00003230
+#define NV04_PFIFO_CACHE1_DMA_PUT 0x00003240
+#define NV04_PFIFO_CACHE1_DMA_GET 0x00003244
+#define NV10_PFIFO_CACHE1_REF_CNT 0x00003248
+#define NV10_PFIFO_CACHE1_DMA_SUBROUTINE 0x0000324C
+#define NV03_PFIFO_CACHE1_PULL0 0x00003240
+#define NV04_PFIFO_CACHE1_PULL0 0x00003250
+# define NV04_PFIFO_CACHE1_PULL0_HASH_FAILED 0x00000010
+# define NV04_PFIFO_CACHE1_PULL0_HASH_BUSY 0x00001000
+#define NV03_PFIFO_CACHE1_PULL1 0x00003250
+#define NV04_PFIFO_CACHE1_PULL1 0x00003254
+#define NV04_PFIFO_CACHE1_HASH 0x00003258
+#define NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT 0x00003260
+#define NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP 0x00003264
+#define NV10_PFIFO_CACHE1_ACQUIRE_VALUE 0x00003268
+#define NV10_PFIFO_CACHE1_SEMAPHORE 0x0000326C
+#define NV03_PFIFO_CACHE1_GET 0x00003270
+#define NV04_PFIFO_CACHE1_ENGINE 0x00003280
+#define NV04_PFIFO_CACHE1_DMA_DCOUNT 0x000032A0
+#define NV40_PFIFO_GRCTX_INSTANCE 0x000032E0
+#define NV40_PFIFO_UNK32E4 0x000032E4
+#define NV04_PFIFO_CACHE1_METHOD(i) (0x00003800+(i*8))
+#define NV04_PFIFO_CACHE1_DATA(i) (0x00003804+(i*8))
+#define NV40_PFIFO_CACHE1_METHOD(i) (0x00090000+(i*8))
+#define NV40_PFIFO_CACHE1_DATA(i) (0x00090004+(i*8))
+
+struct ramfc_desc {
+ unsigned bits:6;
+ unsigned ctxs:5;
+ unsigned ctxp:8;
+ unsigned regs:5;
+ unsigned regp;
+};
+
+struct nv04_fifo_priv {
+ struct nvkm_fifo base;
+ struct ramfc_desc *ramfc_desc;
+ struct nvkm_ramht *ramht;
+ struct nvkm_gpuobj *ramro;
+ struct nvkm_gpuobj *ramfc;
+};
+
+struct nv04_fifo_base {
+ struct nvkm_fifo_base base;
+};
+
+struct nv04_fifo_chan {
+ struct nvkm_fifo_chan base;
+ u32 subc[8];
+ u32 ramfc;
+};
+
+int nv04_fifo_object_attach(struct nvkm_object *, struct nvkm_object *, u32);
+void nv04_fifo_object_detach(struct nvkm_object *, int);
+
+void nv04_fifo_chan_dtor(struct nvkm_object *);
+int nv04_fifo_chan_init(struct nvkm_object *);
+int nv04_fifo_chan_fini(struct nvkm_object *, bool suspend);
+
+int nv04_fifo_context_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+void nv04_fifo_dtor(struct nvkm_object *);
+int nv04_fifo_init(struct nvkm_object *);
+void nv04_fifo_pause(struct nvkm_fifo *, unsigned long *);
+void nv04_fifo_start(struct nvkm_fifo *, unsigned long *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
new file mode 100644
index 000000000000..48ce4af6f543
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv10.c
@@ -0,0 +1,178 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/instmem/nv04.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv10_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+nv10_fifo_chan_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv03_channel_dma_v0 v0;
+ } *args = data;
+ struct nv04_fifo_priv *priv = (void *)engine;
+ struct nv04_fifo_chan *chan;
+ int ret;
+
+ nv_ioctl(parent, "create channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ "offset %016llx\n", args->v0.version,
+ args->v0.pushbuf, args->v0.offset);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+ 0x10000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+ nv_parent(chan)->context_attach = nv04_fifo_context_attach;
+ chan->ramfc = chan->base.chid * 32;
+
+ nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x14,
+ NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nv10_fifo_ofuncs = {
+ .ctor = nv10_fifo_chan_ctor,
+ .dtor = nv04_fifo_chan_dtor,
+ .init = nv04_fifo_chan_init,
+ .fini = nv04_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv10_fifo_sclass[] = {
+ { NV10_CHANNEL_DMA, &nv10_fifo_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv10_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0x10),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fifo_context_ctor,
+ .dtor = _nvkm_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv10_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_instmem_priv *imem = nv04_instmem(parent);
+ struct nv04_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nvkm_ramht_ref(imem->ramht, &priv->ramht);
+ nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+ nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = nv04_fifo_intr;
+ nv_engine(priv)->cclass = &nv10_fifo_cclass;
+ nv_engine(priv)->sclass = nv10_fifo_sclass;
+ priv->base.pause = nv04_fifo_pause;
+ priv->base.start = nv04_fifo_start;
+ priv->ramfc_desc = nv10_ramfc;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv10_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0x10),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv10_fifo_ctor,
+ .dtor = nv04_fifo_dtor,
+ .init = nv04_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
new file mode 100644
index 000000000000..4a20a6fd3887
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv17.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/instmem/nv04.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv17_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 16, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 16, 16, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 32, 0, 0x18, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_PULL1 },
+ { 32, 0, 0x20, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+ { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+ { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+ { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
+ { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+nv17_fifo_chan_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv03_channel_dma_v0 v0;
+ } *args = data;
+ struct nv04_fifo_priv *priv = (void *)engine;
+ struct nv04_fifo_chan *chan;
+ int ret;
+
+ nv_ioctl(parent, "create channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ "offset %016llx\n", args->v0.version,
+ args->v0.pushbuf, args->v0.offset);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0x800000,
+ 0x10000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_MPEG), /* NV31- */
+ &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->object_attach = nv04_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+ nv_parent(chan)->context_attach = nv04_fifo_context_attach;
+ chan->ramfc = chan->base.chid * 64;
+
+ nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x14,
+ NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nv17_fifo_ofuncs = {
+ .ctor = nv17_fifo_chan_ctor,
+ .dtor = nv04_fifo_chan_dtor,
+ .init = nv04_fifo_chan_init,
+ .fini = nv04_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv17_fifo_sclass[] = {
+ { NV17_CHANNEL_DMA, &nv17_fifo_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv17_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0x17),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fifo_context_ctor,
+ .dtor = _nvkm_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv17_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_instmem_priv *imem = nv04_instmem(parent);
+ struct nv04_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nvkm_ramht_ref(imem->ramht, &priv->ramht);
+ nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+ nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = nv04_fifo_intr;
+ nv_engine(priv)->cclass = &nv17_fifo_cclass;
+ nv_engine(priv)->sclass = nv17_fifo_sclass;
+ priv->base.pause = nv04_fifo_pause;
+ priv->base.start = nv04_fifo_start;
+ priv->ramfc_desc = nv17_ramfc;
+ return 0;
+}
+
+static int
+nv17_fifo_init(struct nvkm_object *object)
+{
+ struct nv04_fifo_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fifo_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, NV04_PFIFO_DELAY_0, 0x000000ff);
+ nv_wr32(priv, NV04_PFIFO_DMA_TIMESLICE, 0x0101ffff);
+
+ nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+ ((priv->ramht->bits - 9) << 16) |
+ (priv->ramht->gpuobj.addr >> 8));
+ nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+ nv_wr32(priv, NV03_PFIFO_RAMFC, priv->ramfc->addr >> 8 | 0x00010000);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+ nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+ nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+ nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv17_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0x17),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv17_fifo_ctor,
+ .dtor = nv04_fifo_dtor,
+ .init = nv17_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
new file mode 100644
index 000000000000..5bfc96265f3b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv40.c
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/fb.h>
+#include <subdev/instmem/nv04.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+static struct ramfc_desc
+nv40_ramfc[] = {
+ { 32, 0, 0x00, 0, NV04_PFIFO_CACHE1_DMA_PUT },
+ { 32, 0, 0x04, 0, NV04_PFIFO_CACHE1_DMA_GET },
+ { 32, 0, 0x08, 0, NV10_PFIFO_CACHE1_REF_CNT },
+ { 32, 0, 0x0c, 0, NV04_PFIFO_CACHE1_DMA_INSTANCE },
+ { 32, 0, 0x10, 0, NV04_PFIFO_CACHE1_DMA_DCOUNT },
+ { 32, 0, 0x14, 0, NV04_PFIFO_CACHE1_DMA_STATE },
+ { 28, 0, 0x18, 0, NV04_PFIFO_CACHE1_DMA_FETCH },
+ { 2, 28, 0x18, 28, 0x002058 },
+ { 32, 0, 0x1c, 0, NV04_PFIFO_CACHE1_ENGINE },
+ { 32, 0, 0x20, 0, NV04_PFIFO_CACHE1_PULL1 },
+ { 32, 0, 0x24, 0, NV10_PFIFO_CACHE1_ACQUIRE_VALUE },
+ { 32, 0, 0x28, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMESTAMP },
+ { 32, 0, 0x2c, 0, NV10_PFIFO_CACHE1_ACQUIRE_TIMEOUT },
+ { 32, 0, 0x30, 0, NV10_PFIFO_CACHE1_SEMAPHORE },
+ { 32, 0, 0x34, 0, NV10_PFIFO_CACHE1_DMA_SUBROUTINE },
+ { 32, 0, 0x38, 0, NV40_PFIFO_GRCTX_INSTANCE },
+ { 17, 0, 0x3c, 0, NV04_PFIFO_DMA_TIMESLICE },
+ { 32, 0, 0x40, 0, 0x0032e4 },
+ { 32, 0, 0x44, 0, 0x0032e8 },
+ { 32, 0, 0x4c, 0, 0x002088 },
+ { 32, 0, 0x50, 0, 0x003300 },
+ { 32, 0, 0x54, 0, 0x00330c },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static int
+nv40_fifo_object_attach(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 handle)
+{
+ struct nv04_fifo_priv *priv = (void *)parent->engine;
+ struct nv04_fifo_chan *chan = (void *)parent;
+ u32 context, chid = chan->base.chid;
+ int ret;
+
+ if (nv_iclass(object, NV_GPUOBJ_CLASS))
+ context = nv_gpuobj(object)->addr >> 4;
+ else
+ context = 0x00000004; /* just non-zero */
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_DMAOBJ:
+ case NVDEV_ENGINE_SW:
+ context |= 0x00000000;
+ break;
+ case NVDEV_ENGINE_GR:
+ context |= 0x00100000;
+ break;
+ case NVDEV_ENGINE_MPEG:
+ context |= 0x00200000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ context |= chid << 23;
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ ret = nvkm_ramht_insert(priv->ramht, chid, handle, context);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+ return ret;
+}
+
+static int
+nv40_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *engctx)
+{
+ struct nv04_fifo_priv *priv = (void *)parent->engine;
+ struct nv04_fifo_chan *chan = (void *)parent;
+ unsigned long flags;
+ u32 reg, ctx;
+
+ switch (nv_engidx(engctx->engine)) {
+ case NVDEV_ENGINE_SW:
+ return 0;
+ case NVDEV_ENGINE_GR:
+ reg = 0x32e0;
+ ctx = 0x38;
+ break;
+ case NVDEV_ENGINE_MPEG:
+ reg = 0x330c;
+ ctx = 0x54;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ nv_engctx(engctx)->addr = nv_gpuobj(engctx)->addr >> 4;
+ nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
+
+ if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
+ nv_wr32(priv, reg, nv_engctx(engctx)->addr);
+ nv_wo32(priv->ramfc, chan->ramfc + ctx, nv_engctx(engctx)->addr);
+
+ nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ return 0;
+}
+
+static int
+nv40_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+ struct nvkm_object *engctx)
+{
+ struct nv04_fifo_priv *priv = (void *)parent->engine;
+ struct nv04_fifo_chan *chan = (void *)parent;
+ unsigned long flags;
+ u32 reg, ctx;
+
+ switch (nv_engidx(engctx->engine)) {
+ case NVDEV_ENGINE_SW:
+ return 0;
+ case NVDEV_ENGINE_GR:
+ reg = 0x32e0;
+ ctx = 0x38;
+ break;
+ case NVDEV_ENGINE_MPEG:
+ reg = 0x330c;
+ ctx = 0x54;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&priv->base.lock, flags);
+ nv_mask(priv, 0x002500, 0x00000001, 0x00000000);
+
+ if ((nv_rd32(priv, 0x003204) & priv->base.max) == chan->base.chid)
+ nv_wr32(priv, reg, 0x00000000);
+ nv_wo32(priv->ramfc, chan->ramfc + ctx, 0x00000000);
+
+ nv_mask(priv, 0x002500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&priv->base.lock, flags);
+ return 0;
+}
+
+static int
+nv40_fifo_chan_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv03_channel_dma_v0 v0;
+ } *args = data;
+ struct nv04_fifo_priv *priv = (void *)engine;
+ struct nv04_fifo_chan *chan;
+ int ret;
+
+ nv_ioctl(parent, "create channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ "offset %016llx\n", args->v0.version,
+ args->v0.pushbuf, args->v0.offset);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+ 0x1000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_MPEG), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->context_attach = nv40_fifo_context_attach;
+ nv_parent(chan)->context_detach = nv40_fifo_context_detach;
+ nv_parent(chan)->object_attach = nv40_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv04_fifo_object_detach;
+ chan->ramfc = chan->base.chid * 128;
+
+ nv_wo32(priv->ramfc, chan->ramfc + 0x00, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x04, args->v0.offset);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x0c, chan->base.pushgpu->addr >> 4);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x18, 0x30000000 |
+ NV_PFIFO_CACHE1_DMA_FETCH_TRIG_128_BYTES |
+ NV_PFIFO_CACHE1_DMA_FETCH_SIZE_128_BYTES |
+#ifdef __BIG_ENDIAN
+ NV_PFIFO_CACHE1_BIG_ENDIAN |
+#endif
+ NV_PFIFO_CACHE1_DMA_FETCH_MAX_REQS_8);
+ nv_wo32(priv->ramfc, chan->ramfc + 0x3c, 0x0001ffff);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nv40_fifo_ofuncs = {
+ .ctor = nv40_fifo_chan_ctor,
+ .dtor = nv04_fifo_chan_dtor,
+ .init = nv04_fifo_chan_init,
+ .fini = nv04_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv40_fifo_sclass[] = {
+ { NV40_CHANNEL_DMA, &nv40_fifo_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv40_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fifo_context_ctor,
+ .dtor = _nvkm_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv40_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_instmem_priv *imem = nv04_instmem(parent);
+ struct nv04_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 0, 31, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nvkm_ramht_ref(imem->ramht, &priv->ramht);
+ nvkm_gpuobj_ref(imem->ramro, &priv->ramro);
+ nvkm_gpuobj_ref(imem->ramfc, &priv->ramfc);
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = nv04_fifo_intr;
+ nv_engine(priv)->cclass = &nv40_fifo_cclass;
+ nv_engine(priv)->sclass = nv40_fifo_sclass;
+ priv->base.pause = nv04_fifo_pause;
+ priv->base.start = nv04_fifo_start;
+ priv->ramfc_desc = nv40_ramfc;
+ return 0;
+}
+
+static int
+nv40_fifo_init(struct nvkm_object *object)
+{
+ struct nv04_fifo_priv *priv = (void *)object;
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ int ret;
+
+ ret = nvkm_fifo_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x002040, 0x000000ff);
+ nv_wr32(priv, 0x002044, 0x2101ffff);
+ nv_wr32(priv, 0x002058, 0x00000001);
+
+ nv_wr32(priv, NV03_PFIFO_RAMHT, (0x03 << 24) /* search 128 */ |
+ ((priv->ramht->bits - 9) << 16) |
+ (priv->ramht->gpuobj.addr >> 8));
+ nv_wr32(priv, NV03_PFIFO_RAMRO, priv->ramro->addr >> 8);
+
+ switch (nv_device(priv)->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ nv_wr32(priv, 0x002230, 0x00000001);
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x45:
+ case 0x48:
+ nv_wr32(priv, 0x002220, 0x00030002);
+ break;
+ default:
+ nv_wr32(priv, 0x002230, 0x00000000);
+ nv_wr32(priv, 0x002220, ((pfb->ram->size - 512 * 1024 +
+ priv->ramfc->addr) >> 16) |
+ 0x00030000);
+ break;
+ }
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH1, priv->base.max);
+
+ nv_wr32(priv, NV03_PFIFO_INTR_0, 0xffffffff);
+ nv_wr32(priv, NV03_PFIFO_INTR_EN_0, 0xffffffff);
+
+ nv_wr32(priv, NV03_PFIFO_CACHE1_PUSH0, 1);
+ nv_wr32(priv, NV04_PFIFO_CACHE1_PULL0, 1);
+ nv_wr32(priv, NV03_PFIFO_CACHES, 1);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv40_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_fifo_ctor,
+ .dtor = nv04_fifo_dtor,
+ .init = nv40_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
new file mode 100644
index 000000000000..f25f0fd0655d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.c
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "nv04.h"
+
+#include <core/client.h>
+#include <core/engctx.h>
+#include <core/ramht.h>
+#include <subdev/bar.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * FIFO channel objects
+ ******************************************************************************/
+
+static void
+nv50_fifo_playlist_update_locked(struct nv50_fifo_priv *priv)
+{
+ struct nvkm_bar *bar = nvkm_bar(priv);
+ struct nvkm_gpuobj *cur;
+ int i, p;
+
+ cur = priv->playlist[priv->cur_playlist];
+ priv->cur_playlist = !priv->cur_playlist;
+
+ for (i = priv->base.min, p = 0; i < priv->base.max; i++) {
+ if (nv_rd32(priv, 0x002600 + (i * 4)) & 0x80000000)
+ nv_wo32(cur, p++ * 4, i);
+ }
+
+ bar->flush(bar);
+
+ nv_wr32(priv, 0x0032f4, cur->addr >> 12);
+ nv_wr32(priv, 0x0032ec, p);
+ nv_wr32(priv, 0x002500, 0x00000101);
+}
+
+void
+nv50_fifo_playlist_update(struct nv50_fifo_priv *priv)
+{
+ mutex_lock(&nv_subdev(priv)->mutex);
+ nv50_fifo_playlist_update_locked(priv);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+nv50_fifo_context_attach(struct nvkm_object *parent, struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_base *base = (void *)parent->parent;
+ struct nvkm_gpuobj *ectx = (void *)object;
+ u64 limit = ectx->addr + ectx->size - 1;
+ u64 start = ectx->addr;
+ u32 addr;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0000; break;
+ case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+ default:
+ return -EINVAL;
+ }
+
+ nv_engctx(ectx)->addr = nv_gpuobj(base)->addr >> 12;
+ nv_wo32(base->eng, addr + 0x00, 0x00190000);
+ nv_wo32(base->eng, addr + 0x04, lower_32_bits(limit));
+ nv_wo32(base->eng, addr + 0x08, lower_32_bits(start));
+ nv_wo32(base->eng, addr + 0x0c, upper_32_bits(limit) << 24 |
+ upper_32_bits(start));
+ nv_wo32(base->eng, addr + 0x10, 0x00000000);
+ nv_wo32(base->eng, addr + 0x14, 0x00000000);
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+nv50_fifo_context_detach(struct nvkm_object *parent, bool suspend,
+ struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_priv *priv = (void *)parent->engine;
+ struct nv50_fifo_base *base = (void *)parent->parent;
+ struct nv50_fifo_chan *chan = (void *)parent;
+ u32 addr, me;
+ int ret = 0;
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_SW : return 0;
+ case NVDEV_ENGINE_GR : addr = 0x0000; break;
+ case NVDEV_ENGINE_MPEG : addr = 0x0060; break;
+ default:
+ return -EINVAL;
+ }
+
+ /* HW bug workaround:
+ *
+ * PFIFO will hang forever if the connected engines don't report
+ * that they've processed the context switch request.
+ *
+ * In order for the kickoff to work, we need to ensure all the
+ * connected engines are in a state where they can answer.
+ *
+ * Newer chipsets don't seem to suffer from this issue, and well,
+ * there's also a "ignore these engines" bitmask reg we can use
+ * if we hit the issue there..
+ */
+ me = nv_mask(priv, 0x00b860, 0x00000001, 0x00000001);
+
+ /* do the kickoff... */
+ nv_wr32(priv, 0x0032fc, nv_gpuobj(base)->addr >> 12);
+ if (!nv_wait_ne(priv, 0x0032fc, 0xffffffff, 0xffffffff)) {
+ nv_error(priv, "channel %d [%s] unload timeout\n",
+ chan->base.chid, nvkm_client_name(chan));
+ if (suspend)
+ ret = -EBUSY;
+ }
+ nv_wr32(priv, 0x00b860, me);
+
+ if (ret == 0) {
+ nv_wo32(base->eng, addr + 0x00, 0x00000000);
+ nv_wo32(base->eng, addr + 0x04, 0x00000000);
+ nv_wo32(base->eng, addr + 0x08, 0x00000000);
+ nv_wo32(base->eng, addr + 0x0c, 0x00000000);
+ nv_wo32(base->eng, addr + 0x10, 0x00000000);
+ nv_wo32(base->eng, addr + 0x14, 0x00000000);
+ bar->flush(bar);
+ }
+
+ return ret;
+}
+
+static int
+nv50_fifo_object_attach(struct nvkm_object *parent,
+ struct nvkm_object *object, u32 handle)
+{
+ struct nv50_fifo_chan *chan = (void *)parent;
+ u32 context;
+
+ if (nv_iclass(object, NV_GPUOBJ_CLASS))
+ context = nv_gpuobj(object)->node->offset >> 4;
+ else
+ context = 0x00000004; /* just non-zero */
+
+ switch (nv_engidx(object->engine)) {
+ case NVDEV_ENGINE_DMAOBJ:
+ case NVDEV_ENGINE_SW : context |= 0x00000000; break;
+ case NVDEV_ENGINE_GR : context |= 0x00100000; break;
+ case NVDEV_ENGINE_MPEG : context |= 0x00200000; break;
+ default:
+ return -EINVAL;
+ }
+
+ return nvkm_ramht_insert(chan->ramht, 0, handle, context);
+}
+
+void
+nv50_fifo_object_detach(struct nvkm_object *parent, int cookie)
+{
+ struct nv50_fifo_chan *chan = (void *)parent;
+ nvkm_ramht_remove(chan->ramht, cookie);
+}
+
+static int
+nv50_fifo_chan_ctor_dma(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv03_channel_dma_v0 v0;
+ } *args = data;
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_base *base = (void *)parent;
+ struct nv50_fifo_chan *chan;
+ int ret;
+
+ nv_ioctl(parent, "create channel dma size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel dma vers %d pushbuf %08x "
+ "offset %016llx\n", args->v0.version,
+ args->v0.pushbuf, args->v0.offset);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+ 0x2000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_MPEG), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->context_attach = nv50_fifo_context_attach;
+ nv_parent(chan)->context_detach = nv50_fifo_context_detach;
+ nv_parent(chan)->object_attach = nv50_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+ ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ &chan->ramht);
+ if (ret)
+ return ret;
+
+ nv_wo32(base->ramfc, 0x08, lower_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x0c, upper_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x10, lower_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x14, upper_32_bits(args->v0.offset));
+ nv_wo32(base->ramfc, 0x3c, 0x003f6078);
+ nv_wo32(base->ramfc, 0x44, 0x01003fff);
+ nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+ nv_wo32(base->ramfc, 0x4c, 0xffffffff);
+ nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+ nv_wo32(base->ramfc, 0x78, 0x00000000);
+ nv_wo32(base->ramfc, 0x7c, 0x30000001);
+ nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj.node->offset >> 4));
+ bar->flush(bar);
+ return 0;
+}
+
+static int
+nv50_fifo_chan_ctor_ind(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nv50_channel_gpfifo_v0 v0;
+ } *args = data;
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_fifo_base *base = (void *)parent;
+ struct nv50_fifo_chan *chan;
+ u64 ioffset, ilength;
+ int ret;
+
+ nv_ioctl(parent, "create channel gpfifo size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create channel gpfifo vers %d pushbuf %08x "
+ "ioffset %016llx ilength %08x\n",
+ args->v0.version, args->v0.pushbuf, args->v0.ioffset,
+ args->v0.ilength);
+ } else
+ return ret;
+
+ ret = nvkm_fifo_channel_create(parent, engine, oclass, 0, 0xc00000,
+ 0x2000, args->v0.pushbuf,
+ (1ULL << NVDEV_ENGINE_DMAOBJ) |
+ (1ULL << NVDEV_ENGINE_SW) |
+ (1ULL << NVDEV_ENGINE_GR) |
+ (1ULL << NVDEV_ENGINE_MPEG), &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ args->v0.chid = chan->base.chid;
+
+ nv_parent(chan)->context_attach = nv50_fifo_context_attach;
+ nv_parent(chan)->context_detach = nv50_fifo_context_detach;
+ nv_parent(chan)->object_attach = nv50_fifo_object_attach;
+ nv_parent(chan)->object_detach = nv50_fifo_object_detach;
+
+ ret = nvkm_ramht_new(nv_object(chan), nv_object(chan), 0x8000, 16,
+ &chan->ramht);
+ if (ret)
+ return ret;
+
+ ioffset = args->v0.ioffset;
+ ilength = order_base_2(args->v0.ilength / 8);
+
+ nv_wo32(base->ramfc, 0x3c, 0x403f6078);
+ nv_wo32(base->ramfc, 0x44, 0x01003fff);
+ nv_wo32(base->ramfc, 0x48, chan->base.pushgpu->node->offset >> 4);
+ nv_wo32(base->ramfc, 0x50, lower_32_bits(ioffset));
+ nv_wo32(base->ramfc, 0x54, upper_32_bits(ioffset) | (ilength << 16));
+ nv_wo32(base->ramfc, 0x60, 0x7fffffff);
+ nv_wo32(base->ramfc, 0x78, 0x00000000);
+ nv_wo32(base->ramfc, 0x7c, 0x30000001);
+ nv_wo32(base->ramfc, 0x80, ((chan->ramht->bits - 9) << 27) |
+ (4 << 24) /* SEARCH_FULL */ |
+ (chan->ramht->gpuobj.node->offset >> 4));
+ bar->flush(bar);
+ return 0;
+}
+
+void
+nv50_fifo_chan_dtor(struct nvkm_object *object)
+{
+ struct nv50_fifo_chan *chan = (void *)object;
+ nvkm_ramht_ref(NULL, &chan->ramht);
+ nvkm_fifo_channel_destroy(&chan->base);
+}
+
+static int
+nv50_fifo_chan_init(struct nvkm_object *object)
+{
+ struct nv50_fifo_priv *priv = (void *)object->engine;
+ struct nv50_fifo_base *base = (void *)object->parent;
+ struct nv50_fifo_chan *chan = (void *)object;
+ struct nvkm_gpuobj *ramfc = base->ramfc;
+ u32 chid = chan->base.chid;
+ int ret;
+
+ ret = nvkm_fifo_channel_init(&chan->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x002600 + (chid * 4), 0x80000000 | ramfc->addr >> 12);
+ nv50_fifo_playlist_update(priv);
+ return 0;
+}
+
+int
+nv50_fifo_chan_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_fifo_priv *priv = (void *)object->engine;
+ struct nv50_fifo_chan *chan = (void *)object;
+ u32 chid = chan->base.chid;
+
+ /* remove channel from playlist, fifo will unload context */
+ nv_mask(priv, 0x002600 + (chid * 4), 0x80000000, 0x00000000);
+ nv50_fifo_playlist_update(priv);
+ nv_wr32(priv, 0x002600 + (chid * 4), 0x00000000);
+
+ return nvkm_fifo_channel_fini(&chan->base, suspend);
+}
+
+static struct nvkm_ofuncs
+nv50_fifo_ofuncs_dma = {
+ .ctor = nv50_fifo_chan_ctor_dma,
+ .dtor = nv50_fifo_chan_dtor,
+ .init = nv50_fifo_chan_init,
+ .fini = nv50_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_ofuncs
+nv50_fifo_ofuncs_ind = {
+ .ctor = nv50_fifo_chan_ctor_ind,
+ .dtor = nv50_fifo_chan_dtor,
+ .init = nv50_fifo_chan_init,
+ .fini = nv50_fifo_chan_fini,
+ .map = _nvkm_fifo_channel_map,
+ .rd32 = _nvkm_fifo_channel_rd32,
+ .wr32 = _nvkm_fifo_channel_wr32,
+ .ntfy = _nvkm_fifo_channel_ntfy
+};
+
+static struct nvkm_oclass
+nv50_fifo_sclass[] = {
+ { NV50_CHANNEL_DMA, &nv50_fifo_ofuncs_dma },
+ { NV50_CHANNEL_GPFIFO, &nv50_fifo_ofuncs_ind },
+ {}
+};
+
+/*******************************************************************************
+ * FIFO context - basically just the instmem reserved for the channel
+ ******************************************************************************/
+
+static int
+nv50_fifo_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_fifo_base *base;
+ int ret;
+
+ ret = nvkm_fifo_context_create(parent, engine, oclass, NULL, 0x10000,
+ 0x1000, NVOBJ_FLAG_HEAP, &base);
+ *pobject = nv_object(base);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x0200,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &base->ramfc);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x1200, 0,
+ NVOBJ_FLAG_ZERO_ALLOC, &base->eng);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(base), nv_object(base), 0x4000, 0, 0,
+ &base->pgd);
+ if (ret)
+ return ret;
+
+ ret = nvkm_vm_ref(nvkm_client(parent)->vm, &base->vm, base->pgd);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void
+nv50_fifo_context_dtor(struct nvkm_object *object)
+{
+ struct nv50_fifo_base *base = (void *)object;
+ nvkm_vm_ref(NULL, &base->vm, base->pgd);
+ nvkm_gpuobj_ref(NULL, &base->pgd);
+ nvkm_gpuobj_ref(NULL, &base->eng);
+ nvkm_gpuobj_ref(NULL, &base->ramfc);
+ nvkm_gpuobj_ref(NULL, &base->cache);
+ nvkm_fifo_context_destroy(&base->base);
+}
+
+static struct nvkm_oclass
+nv50_fifo_cclass = {
+ .handle = NV_ENGCTX(FIFO, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fifo_context_ctor,
+ .dtor = nv50_fifo_context_dtor,
+ .init = _nvkm_fifo_context_init,
+ .fini = _nvkm_fifo_context_fini,
+ .rd32 = _nvkm_fifo_context_rd32,
+ .wr32 = _nvkm_fifo_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PFIFO engine
+ ******************************************************************************/
+
+static int
+nv50_fifo_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_fifo_priv *priv;
+ int ret;
+
+ ret = nvkm_fifo_create(parent, engine, oclass, 1, 127, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+ &priv->playlist[0]);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 128 * 4, 0x1000, 0,
+ &priv->playlist[1]);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000100;
+ nv_subdev(priv)->intr = nv04_fifo_intr;
+ nv_engine(priv)->cclass = &nv50_fifo_cclass;
+ nv_engine(priv)->sclass = nv50_fifo_sclass;
+ priv->base.pause = nv04_fifo_pause;
+ priv->base.start = nv04_fifo_start;
+ return 0;
+}
+
+void
+nv50_fifo_dtor(struct nvkm_object *object)
+{
+ struct nv50_fifo_priv *priv = (void *)object;
+
+ nvkm_gpuobj_ref(NULL, &priv->playlist[1]);
+ nvkm_gpuobj_ref(NULL, &priv->playlist[0]);
+
+ nvkm_fifo_destroy(&priv->base);
+}
+
+int
+nv50_fifo_init(struct nvkm_object *object)
+{
+ struct nv50_fifo_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nvkm_fifo_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+ nv_wr32(priv, 0x00250c, 0x6f3cfc34);
+ nv_wr32(priv, 0x002044, 0x01003fff);
+
+ nv_wr32(priv, 0x002100, 0xffffffff);
+ nv_wr32(priv, 0x002140, 0xbfffffff);
+
+ for (i = 0; i < 128; i++)
+ nv_wr32(priv, 0x002600 + (i * 4), 0x00000000);
+ nv50_fifo_playlist_update_locked(priv);
+
+ nv_wr32(priv, 0x003200, 0x00000001);
+ nv_wr32(priv, 0x003250, 0x00000001);
+ nv_wr32(priv, 0x002500, 0x00000001);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_fifo_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(FIFO, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fifo_ctor,
+ .dtor = nv50_fifo_dtor,
+ .init = nv50_fifo_init,
+ .fini = _nvkm_fifo_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
new file mode 100644
index 000000000000..09ed93c66567
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/fifo/nv50.h
@@ -0,0 +1,36 @@
+#ifndef __NV50_FIFO_H__
+#define __NV50_FIFO_H__
+#include <engine/fifo.h>
+
+struct nv50_fifo_priv {
+ struct nvkm_fifo base;
+ struct nvkm_gpuobj *playlist[2];
+ int cur_playlist;
+};
+
+struct nv50_fifo_base {
+ struct nvkm_fifo_base base;
+ struct nvkm_gpuobj *ramfc;
+ struct nvkm_gpuobj *cache;
+ struct nvkm_gpuobj *eng;
+ struct nvkm_gpuobj *pgd;
+ struct nvkm_vm *vm;
+};
+
+struct nv50_fifo_chan {
+ struct nvkm_fifo_chan base;
+ u32 subc[8];
+ struct nvkm_ramht *ramht;
+};
+
+void nv50_fifo_playlist_update(struct nv50_fifo_priv *);
+
+void nv50_fifo_object_detach(struct nvkm_object *, int);
+void nv50_fifo_chan_dtor(struct nvkm_object *);
+int nv50_fifo_chan_fini(struct nvkm_object *, bool);
+
+void nv50_fifo_context_dtor(struct nvkm_object *);
+
+void nv50_fifo_dtor(struct nvkm_object *);
+int nv50_fifo_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
new file mode 100644
index 000000000000..1771d944591b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/Kbuild
@@ -0,0 +1,36 @@
+nvkm-y += nvkm/engine/gr/ctxnv40.o
+nvkm-y += nvkm/engine/gr/ctxnv50.o
+nvkm-y += nvkm/engine/gr/ctxgf100.o
+nvkm-y += nvkm/engine/gr/ctxgf108.o
+nvkm-y += nvkm/engine/gr/ctxgf104.o
+nvkm-y += nvkm/engine/gr/ctxgf110.o
+nvkm-y += nvkm/engine/gr/ctxgf117.o
+nvkm-y += nvkm/engine/gr/ctxgf119.o
+nvkm-y += nvkm/engine/gr/ctxgk104.o
+nvkm-y += nvkm/engine/gr/ctxgk20a.o
+nvkm-y += nvkm/engine/gr/ctxgk110.o
+nvkm-y += nvkm/engine/gr/ctxgk110b.o
+nvkm-y += nvkm/engine/gr/ctxgk208.o
+nvkm-y += nvkm/engine/gr/ctxgm107.o
+nvkm-y += nvkm/engine/gr/nv04.o
+nvkm-y += nvkm/engine/gr/nv10.o
+nvkm-y += nvkm/engine/gr/nv20.o
+nvkm-y += nvkm/engine/gr/nv25.o
+nvkm-y += nvkm/engine/gr/nv2a.o
+nvkm-y += nvkm/engine/gr/nv30.o
+nvkm-y += nvkm/engine/gr/nv34.o
+nvkm-y += nvkm/engine/gr/nv35.o
+nvkm-y += nvkm/engine/gr/nv40.o
+nvkm-y += nvkm/engine/gr/nv50.o
+nvkm-y += nvkm/engine/gr/gf100.o
+nvkm-y += nvkm/engine/gr/gf108.o
+nvkm-y += nvkm/engine/gr/gf104.o
+nvkm-y += nvkm/engine/gr/gf110.o
+nvkm-y += nvkm/engine/gr/gf117.o
+nvkm-y += nvkm/engine/gr/gf119.o
+nvkm-y += nvkm/engine/gr/gk104.o
+nvkm-y += nvkm/engine/gr/gk20a.o
+nvkm-y += nvkm/engine/gr/gk110.o
+nvkm-y += nvkm/engine/gr/gk110b.o
+nvkm-y += nvkm/engine/gr/gk208.o
+nvkm-y += nvkm/engine/gr/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
new file mode 100644
index 000000000000..2e7ec389eea7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.c
@@ -0,0 +1,1390 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "ctxgf100.h"
+
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf100_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_icmd[] = {
+ { gf100_grctx_init_icmd_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_9097_0[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x002700, 8, 0x20, 0x00000000 },
+ { 0x002704, 8, 0x20, 0x00000000 },
+ { 0x002708, 8, 0x20, 0x00000000 },
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x002710, 8, 0x20, 0x00014000 },
+ { 0x002714, 8, 0x20, 0x00000040 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002200, 5, 0x10, 0x00000022 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00001fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x003fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 4, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 1, 0x04, 0x003fffff },
+ { 0x0002d0, 1, 0x04, 0x00000c48 },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00300008 },
+ { 0x001284, 1, 0x04, 0x04000080 },
+ { 0x001450, 1, 0x04, 0x00300008 },
+ { 0x001454, 1, 0x04, 0x04000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_902d_0[] = {
+ { 0x000200, 1, 0x04, 0x000000cf },
+ { 0x000204, 1, 0x04, 0x00000001 },
+ { 0x000208, 1, 0x04, 0x00000020 },
+ { 0x00020c, 1, 0x04, 0x00000001 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000214, 1, 0x04, 0x00000080 },
+ { 0x000218, 2, 0x04, 0x00000100 },
+ { 0x000220, 2, 0x04, 0x00000000 },
+ { 0x000230, 1, 0x04, 0x000000cf },
+ { 0x000234, 1, 0x04, 0x00000001 },
+ { 0x000238, 1, 0x04, 0x00000020 },
+ { 0x00023c, 1, 0x04, 0x00000001 },
+ { 0x000244, 1, 0x04, 0x00000080 },
+ { 0x000248, 2, 0x04, 0x00000100 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_9039_0[] = {
+ { 0x00030c, 3, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000238, 2, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_90c0_0[] = {
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x000758, 1, 0x04, 0x00000100 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x000204, 3, 0x04, 0x00000000 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ { 0x00024c, 1, 0x04, 0x00000000 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_mthd[] = {
+ { gf100_grctx_init_9097_0, 0x9097 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ { gf100_grctx_init_9039_0, 0x9039 },
+ { gf100_grctx_init_90c0_0, 0x90c0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_main_0[] = {
+ { 0x400204, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_fe_0[] = {
+ { 0x404004, 11, 0x04, 0x00000000 },
+ { 0x404044, 1, 0x04, 0x00000000 },
+ { 0x404094, 13, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf0000087 },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x404168, 1, 0x04, 0x00000000 },
+ { 0x404174, 3, 0x04, 0x00000000 },
+ { 0x404200, 8, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_pri_0[] = {
+ { 0x404404, 14, 0x04, 0x00000000 },
+ { 0x404460, 2, 0x04, 0x00000000 },
+ { 0x404468, 1, 0x04, 0x00ffffff },
+ { 0x40446c, 1, 0x04, 0x00000000 },
+ { 0x404480, 1, 0x04, 0x00000001 },
+ { 0x404498, 1, 0x04, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_memfmt_0[] = {
+ { 0x404604, 1, 0x04, 0x00000015 },
+ { 0x404608, 1, 0x04, 0x00000000 },
+ { 0x40460c, 1, 0x04, 0x00002e00 },
+ { 0x404610, 1, 0x04, 0x00000100 },
+ { 0x404618, 8, 0x04, 0x00000000 },
+ { 0x404638, 1, 0x04, 0x00000004 },
+ { 0x40463c, 8, 0x04, 0x00000000 },
+ { 0x40465c, 1, 0x04, 0x007f0100 },
+ { 0x404660, 7, 0x04, 0x00000000 },
+ { 0x40467c, 1, 0x04, 0x00000002 },
+ { 0x404680, 8, 0x04, 0x00000000 },
+ { 0x4046a0, 1, 0x04, 0x007f0080 },
+ { 0x4046a4, 18, 0x04, 0x00000000 },
+ { 0x4046f0, 2, 0x04, 0x00000000 },
+ { 0x404700, 13, 0x04, 0x00000000 },
+ { 0x404734, 1, 0x04, 0x00000100 },
+ { 0x404738, 8, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x078000bf },
+ { 0x405830, 1, 0x04, 0x02180000 },
+ { 0x405834, 2, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x000103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_rstr2d_0[] = {
+ { 0x407804, 1, 0x04, 0x00000023 },
+ { 0x40780c, 1, 0x04, 0x0a418820 },
+ { 0x407810, 1, 0x04, 0x062080e6 },
+ { 0x407814, 1, 0x04, 0x020398a4 },
+ { 0x407818, 1, 0x04, 0x0e629062 },
+ { 0x40781c, 1, 0x04, 0x0a418820 },
+ { 0x407820, 1, 0x04, 0x000000e6 },
+ { 0x4078bc, 1, 0x04, 0x00000103 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_scc_0[] = {
+ { 0x408000, 2, 0x04, 0x00000000 },
+ { 0x408008, 1, 0x04, 0x00000018 },
+ { 0x40800c, 2, 0x04, 0x00000000 },
+ { 0x408014, 1, 0x04, 0x00000069 },
+ { 0x408018, 1, 0x04, 0xe100e100 },
+ { 0x408064, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x0003e00d },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x02000001 },
+ { 0x408908, 1, 0x04, 0x00c80929 },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gf100_grctx_init_fe_0 },
+ { gf100_grctx_init_pri_0 },
+ { gf100_grctx_init_memfmt_0 },
+ { gf100_grctx_init_ds_0 },
+ { gf100_grctx_init_pd_0 },
+ { gf100_grctx_init_rstr2d_0 },
+ { gf100_grctx_init_scc_0 },
+ { gf100_grctx_init_be_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gpc_unk_0[] = {
+ { 0x418380, 1, 0x04, 0x00000016 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_prop_0[] = {
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x00200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gpc_unk_1[] = {
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 1, 0x04, 0x00000000 },
+ { 0x41870c, 1, 0x04, 0x07c80000 },
+ { 0x418710, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x0006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x00000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x00100000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_zcull_0[] = {
+ { 0x41891c, 1, 0x04, 0x00ff00ff },
+ { 0x418924, 1, 0x04, 0x00000000 },
+ { 0x418928, 1, 0x04, 0x00ffff00 },
+ { 0x41892c, 1, 0x04, 0x0000ff00 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_crstr_0[] = {
+ { 0x418b00, 1, 0x04, 0x00000000 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gpm_0[] = {
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_gcc_0[] = {
+ { 0x419000, 1, 0x04, 0x00000780 },
+ { 0x419004, 2, 0x04, 0x00000000 },
+ { 0x419014, 1, 0x04, 0x00000004 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf100_grctx_init_prop_0 },
+ { gf100_grctx_init_gpc_unk_1 },
+ { gf100_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf100_grctx_init_crstr_0 },
+ { gf100_grctx_init_gpm_0 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_zcullr_0[] = {
+ { 0x418a00, 3, 0x04, 0x00000000 },
+ { 0x418a0c, 1, 0x04, 0x00010000 },
+ { 0x418a10, 3, 0x04, 0x00000000 },
+ { 0x418a20, 3, 0x04, 0x00000000 },
+ { 0x418a2c, 1, 0x04, 0x00010000 },
+ { 0x418a30, 3, 0x04, 0x00000000 },
+ { 0x418a40, 3, 0x04, 0x00000000 },
+ { 0x418a4c, 1, 0x04, 0x00010000 },
+ { 0x418a50, 3, 0x04, 0x00000000 },
+ { 0x418a60, 3, 0x04, 0x00000000 },
+ { 0x418a6c, 1, 0x04, 0x00010000 },
+ { 0x418a70, 3, 0x04, 0x00000000 },
+ { 0x418a80, 3, 0x04, 0x00000000 },
+ { 0x418a8c, 1, 0x04, 0x00010000 },
+ { 0x418a90, 3, 0x04, 0x00000000 },
+ { 0x418aa0, 3, 0x04, 0x00000000 },
+ { 0x418aac, 1, 0x04, 0x00010000 },
+ { 0x418ab0, 3, 0x04, 0x00000000 },
+ { 0x418ac0, 3, 0x04, 0x00000000 },
+ { 0x418acc, 1, 0x04, 0x00010000 },
+ { 0x418ad0, 3, 0x04, 0x00000000 },
+ { 0x418ae0, 3, 0x04, 0x00000000 },
+ { 0x418aec, 1, 0x04, 0x00010000 },
+ { 0x418af0, 3, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_zcull[] = {
+ { gf100_grctx_init_zcullr_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_pe_0[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x0000012a },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_wwdx_0[] = {
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00000001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_mpc_0[] = {
+ { 0x419c00, 1, 0x04, 0x00000002 },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_l1c_0[] = {
+ { 0x419cb0, 1, 0x04, 0x00060048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_grctx_init_tpccs_0[] = {
+ { 0x419d20, 1, 0x04, 0x02180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_grctx_init_sm_0[] = {
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419f50, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf100_grctx_pack_tpc[] = {
+ { gf100_grctx_init_pe_0 },
+ { gf100_grctx_init_tex_0 },
+ { gf100_grctx_init_wwdx_0 },
+ { gf100_grctx_init_mpc_0 },
+ { gf100_grctx_init_l1c_0 },
+ { gf100_grctx_init_tpccs_0 },
+ { gf100_grctx_init_sm_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+int
+gf100_grctx_mmio_data(struct gf100_grctx *info, u32 size, u32 align, u32 access)
+{
+ if (info->data) {
+ info->buffer[info->buffer_nr] = round_up(info->addr, align);
+ info->addr = info->buffer[info->buffer_nr] + size;
+ info->data->size = size;
+ info->data->align = align;
+ info->data->access = access;
+ info->data++;
+ return info->buffer_nr++;
+ }
+ return -1;
+}
+
+void
+gf100_grctx_mmio_item(struct gf100_grctx *info, u32 addr, u32 data,
+ int shift, int buffer)
+{
+ if (info->data) {
+ if (shift >= 0) {
+ info->mmio->addr = addr;
+ info->mmio->data = data;
+ info->mmio->shift = shift;
+ info->mmio->buffer = buffer;
+ if (buffer >= 0)
+ data |= info->buffer[buffer] >> shift;
+ info->mmio++;
+ } else
+ return;
+ } else {
+ if (buffer >= 0)
+ return;
+ }
+
+ nv_wr32(info->priv, addr, data);
+}
+
+void
+gf100_grctx_generate_bundle(struct gf100_grctx *info)
+{
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+ const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+ const int s = 8;
+ const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
+ mmio_refn(info, 0x408004, 0x00000000, s, b);
+ mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+ mmio_refn(info, 0x418808, 0x00000000, s, b);
+ mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+}
+
+void
+gf100_grctx_generate_pagepool(struct gf100_grctx *info)
+{
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+ const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+ const int s = 8;
+ const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
+ mmio_refn(info, 0x40800c, 0x00000000, s, b);
+ mmio_wr32(info, 0x408010, 0x80000000);
+ mmio_refn(info, 0x419004, 0x00000000, s, b);
+ mmio_wr32(info, 0x419008, 0x00000000);
+}
+
+void
+gf100_grctx_generate_attrib(struct gf100_grctx *info)
+{
+ struct gf100_gr_priv *priv = info->priv;
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv);
+ const u32 attrib = impl->attrib_nr;
+ const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+ const u32 access = NV_MEM_ACCESS_RW;
+ const int s = 12;
+ const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+ int gpc, tpc;
+ u32 bo = 0;
+
+ mmio_refn(info, 0x418810, 0x80000000, s, b);
+ mmio_refn(info, 0x419848, 0x10000000, s, b);
+ mmio_wr32(info, 0x405830, (attrib << 16));
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ const u32 o = TPC_UNIT(gpc, tpc, 0x0520);
+ mmio_skip(info, o, (attrib << 16) | ++bo);
+ mmio_wr32(info, o, (attrib << 16) | --bo);
+ bo += impl->attrib_nr_max;
+ }
+ }
+}
+
+void
+gf100_grctx_generate_unkn(struct gf100_gr_priv *priv)
+{
+}
+
+void
+gf100_grctx_generate_tpcid(struct gf100_gr_priv *priv)
+{
+ int gpc, tpc, id;
+
+ for (tpc = 0, id = 0; tpc < 4; tpc++) {
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ if (tpc < priv->tpc_nr[gpc]) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x4e8), id);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+ id++;
+ }
+
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+ }
+ }
+}
+
+void
+gf100_grctx_generate_r406028(struct gf100_gr_priv *priv)
+{
+ u32 tmp[GPC_MAX / 8] = {}, i = 0;
+ for (i = 0; i < priv->gpc_nr; i++)
+ tmp[i / 8] |= priv->tpc_nr[i] << ((i % 8) * 4);
+ for (i = 0; i < 4; i++) {
+ nv_wr32(priv, 0x406028 + (i * 4), tmp[i]);
+ nv_wr32(priv, 0x405870 + (i * 4), tmp[i]);
+ }
+}
+
+void
+gf100_grctx_generate_r4060a8(struct gf100_gr_priv *priv)
+{
+ u8 tpcnr[GPC_MAX], data[TPC_MAX];
+ int gpc, tpc, i;
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ memset(data, 0x1f, sizeof(data));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+ data[tpc] = gpc;
+ }
+
+ for (i = 0; i < 4; i++)
+ nv_wr32(priv, 0x4060a8 + (i * 4), ((u32 *)data)[i]);
+}
+
+void
+gf100_grctx_generate_r418bb8(struct gf100_gr_priv *priv)
+{
+ u32 data[6] = {}, data2[2] = {};
+ u8 tpcnr[GPC_MAX];
+ u8 shift, ntpcv;
+ int gpc, tpc, i;
+
+ /* calculate first set of magics */
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+
+ data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+ }
+
+ for (; tpc < 32; tpc++)
+ data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+ /* and the second... */
+ shift = 0;
+ ntpcv = priv->tpc_total;
+ while (!(ntpcv & (1 << 4))) {
+ ntpcv <<= 1;
+ shift++;
+ }
+
+ data2[0] = (ntpcv << 16);
+ data2[0] |= (shift << 21);
+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+ for (i = 1; i < 7; i++)
+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+ /* GPC_BROADCAST */
+ nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+ /* GPC_BROADCAST.TP_BROADCAST */
+ nv_wr32(priv, 0x419bd0, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr | data2[0]);
+ nv_wr32(priv, 0x419be4, data2[1]);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x419b00 + (i * 4), data[i]);
+
+ /* UNK78xx */
+ nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+gf100_grctx_generate_r406800(struct gf100_gr_priv *priv)
+{
+ u64 tpc_mask = 0, tpc_set = 0;
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc;
+ int i, a, b;
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++)
+ tpc_mask |= ((1ULL << priv->tpc_nr[gpc]) - 1) << (gpc * 8);
+
+ for (i = 0, gpc = -1, b = -1; i < 32; i++) {
+ a = (i * (priv->tpc_total - 1)) / 32;
+ if (a != b) {
+ b = a;
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ tpc_set |= 1ULL << ((gpc * 8) + tpc);
+ }
+
+ nv_wr32(priv, 0x406800 + (i * 0x20), lower_32_bits(tpc_set));
+ nv_wr32(priv, 0x406c00 + (i * 0x20), lower_32_bits(tpc_set ^ tpc_mask));
+ if (priv->gpc_nr > 4) {
+ nv_wr32(priv, 0x406804 + (i * 0x20), upper_32_bits(tpc_set));
+ nv_wr32(priv, 0x406c04 + (i * 0x20), upper_32_bits(tpc_set ^ tpc_mask));
+ }
+ }
+}
+
+void
+gf100_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+ struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+
+ gf100_gr_mmio(priv, oclass->hub);
+ gf100_gr_mmio(priv, oclass->gpc);
+ gf100_gr_mmio(priv, oclass->zcull);
+ gf100_gr_mmio(priv, oclass->tpc);
+ gf100_gr_mmio(priv, oclass->ppc);
+
+ nv_wr32(priv, 0x404154, 0x00000000);
+
+ oclass->bundle(info);
+ oclass->pagepool(info);
+ oclass->attrib(info);
+ oclass->unkn(priv);
+
+ gf100_grctx_generate_tpcid(priv);
+ gf100_grctx_generate_r406028(priv);
+ gf100_grctx_generate_r4060a8(priv);
+ gf100_grctx_generate_r418bb8(priv);
+ gf100_grctx_generate_r406800(priv);
+
+ gf100_gr_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ gf100_gr_mthd(priv, oclass->mthd);
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+}
+
+int
+gf100_grctx_generate(struct gf100_gr_priv *priv)
+{
+ struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ struct nvkm_bar *bar = nvkm_bar(priv);
+ struct nvkm_gpuobj *chan;
+ struct gf100_grctx info;
+ int ret, i;
+
+ /* allocate memory to for a "channel", which we'll use to generate
+ * the default context values
+ */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x80000 + priv->size,
+ 0x1000, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ if (ret) {
+ nv_error(priv, "failed to allocate channel memory, %d\n", ret);
+ return ret;
+ }
+
+ /* PGD pointer */
+ nv_wo32(chan, 0x0200, lower_32_bits(chan->addr + 0x1000));
+ nv_wo32(chan, 0x0204, upper_32_bits(chan->addr + 0x1000));
+ nv_wo32(chan, 0x0208, 0xffffffff);
+ nv_wo32(chan, 0x020c, 0x000000ff);
+
+ /* PGT[0] pointer */
+ nv_wo32(chan, 0x1000, 0x00000000);
+ nv_wo32(chan, 0x1004, 0x00000001 | (chan->addr + 0x2000) >> 8);
+
+ /* identity-map the whole "channel" into its own vm */
+ for (i = 0; i < chan->size / 4096; i++) {
+ u64 addr = ((chan->addr + (i * 4096)) >> 8) | 1;
+ nv_wo32(chan, 0x2000 + (i * 8), lower_32_bits(addr));
+ nv_wo32(chan, 0x2004 + (i * 8), upper_32_bits(addr));
+ }
+
+ /* context pointer (virt) */
+ nv_wo32(chan, 0x0210, 0x00080004);
+ nv_wo32(chan, 0x0214, 0x00000000);
+
+ bar->flush(bar);
+
+ nv_wr32(priv, 0x100cb8, (chan->addr + 0x1000) >> 8);
+ nv_wr32(priv, 0x100cbc, 0x80000001);
+ nv_wait(priv, 0x100c80, 0x00008000, 0x00008000);
+
+ /* setup default state for mmio list construction */
+ info.priv = priv;
+ info.data = priv->mmio_data;
+ info.mmio = priv->mmio_list;
+ info.addr = 0x2000 + (i * 8);
+ info.buffer_nr = 0;
+
+ /* make channel current */
+ if (priv->firmware) {
+ nv_wr32(priv, 0x409840, 0x00000030);
+ nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+ nv_wr32(priv, 0x409504, 0x00000003);
+ if (!nv_wait(priv, 0x409800, 0x00000010, 0x00000010))
+ nv_error(priv, "load_ctx timeout\n");
+
+ nv_wo32(chan, 0x8001c, 1);
+ nv_wo32(chan, 0x80020, 0);
+ nv_wo32(chan, 0x80028, 0);
+ nv_wo32(chan, 0x8002c, 0);
+ bar->flush(bar);
+ } else {
+ nv_wr32(priv, 0x409840, 0x80000000);
+ nv_wr32(priv, 0x409500, 0x80000000 | chan->addr >> 12);
+ nv_wr32(priv, 0x409504, 0x00000001);
+ if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000))
+ nv_error(priv, "HUB_SET_CHAN timeout\n");
+ }
+
+ oclass->main(priv, &info);
+
+ /* trigger a context unload by unsetting the "next channel valid" bit
+ * and faking a context switch interrupt
+ */
+ nv_mask(priv, 0x409b04, 0x80000000, 0x00000000);
+ nv_wr32(priv, 0x409000, 0x00000100);
+ if (!nv_wait(priv, 0x409b00, 0x80000000, 0x00000000)) {
+ nv_error(priv, "grctx template channel unload timeout\n");
+ ret = -EBUSY;
+ goto done;
+ }
+
+ priv->data = kmalloc(priv->size, GFP_KERNEL);
+ if (priv->data) {
+ for (i = 0; i < priv->size; i += 4)
+ priv->data[i / 4] = nv_ro32(chan, 0x80000 + i);
+ ret = 0;
+ } else {
+ ret = -ENOMEM;
+ }
+
+done:
+ nvkm_gpuobj_ref(NULL, &chan);
+ return ret;
+}
+
+struct nvkm_oclass *
+gf100_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gf100_grctx_generate_main,
+ .unkn = gf100_grctx_generate_unkn,
+ .hub = gf100_grctx_pack_hub,
+ .gpc = gf100_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gf100_grctx_pack_tpc,
+ .icmd = gf100_grctx_pack_icmd,
+ .mthd = gf100_grctx_pack_mthd,
+ .bundle = gf100_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .pagepool = gf100_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf100_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
new file mode 100644
index 000000000000..1166b1aa1525
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf100.h
@@ -0,0 +1,199 @@
+#ifndef __NVKM_GRCTX_NVC0_H__
+#define __NVKM_GRCTX_NVC0_H__
+#include "gf100.h"
+
+struct gf100_grctx {
+ struct gf100_gr_priv *priv;
+ struct gf100_gr_data *data;
+ struct gf100_gr_mmio *mmio;
+ int buffer_nr;
+ u64 buffer[4];
+ u64 addr;
+};
+
+int gf100_grctx_mmio_data(struct gf100_grctx *, u32 size, u32 align, u32 access);
+void gf100_grctx_mmio_item(struct gf100_grctx *, u32 addr, u32 data, int s, int);
+
+#define mmio_vram(a,b,c,d) gf100_grctx_mmio_data((a), (b), (c), (d))
+#define mmio_refn(a,b,c,d,e) gf100_grctx_mmio_item((a), (b), (c), (d), (e))
+#define mmio_skip(a,b,c) mmio_refn((a), (b), (c), -1, -1)
+#define mmio_wr32(a,b,c) mmio_refn((a), (b), (c), 0, -1)
+
+struct gf100_grctx_oclass {
+ struct nvkm_oclass base;
+ /* main context generation function */
+ void (*main)(struct gf100_gr_priv *, struct gf100_grctx *);
+ /* context-specific modify-on-first-load list generation function */
+ void (*unkn)(struct gf100_gr_priv *);
+ /* mmio context data */
+ const struct gf100_gr_pack *hub;
+ const struct gf100_gr_pack *gpc;
+ const struct gf100_gr_pack *zcull;
+ const struct gf100_gr_pack *tpc;
+ const struct gf100_gr_pack *ppc;
+ /* indirect context data, generated with icmds/mthds */
+ const struct gf100_gr_pack *icmd;
+ const struct gf100_gr_pack *mthd;
+ /* bundle circular buffer */
+ void (*bundle)(struct gf100_grctx *);
+ u32 bundle_size;
+ u32 bundle_min_gpm_fifo_depth;
+ u32 bundle_token_limit;
+ /* pagepool */
+ void (*pagepool)(struct gf100_grctx *);
+ u32 pagepool_size;
+ /* attribute(/alpha) circular buffer */
+ void (*attrib)(struct gf100_grctx *);
+ u32 attrib_nr_max;
+ u32 attrib_nr;
+ u32 alpha_nr_max;
+ u32 alpha_nr;
+};
+
+static inline const struct gf100_grctx_oclass *
+gf100_grctx_impl(struct gf100_gr_priv *priv)
+{
+ return (void *)nv_engine(priv)->cclass;
+}
+
+extern struct nvkm_oclass *gf100_grctx_oclass;
+int gf100_grctx_generate(struct gf100_gr_priv *);
+void gf100_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *);
+void gf100_grctx_generate_bundle(struct gf100_grctx *);
+void gf100_grctx_generate_pagepool(struct gf100_grctx *);
+void gf100_grctx_generate_attrib(struct gf100_grctx *);
+void gf100_grctx_generate_unkn(struct gf100_gr_priv *);
+void gf100_grctx_generate_tpcid(struct gf100_gr_priv *);
+void gf100_grctx_generate_r406028(struct gf100_gr_priv *);
+void gf100_grctx_generate_r4060a8(struct gf100_gr_priv *);
+void gf100_grctx_generate_r418bb8(struct gf100_gr_priv *);
+void gf100_grctx_generate_r406800(struct gf100_gr_priv *);
+
+extern struct nvkm_oclass *gf108_grctx_oclass;
+void gf108_grctx_generate_attrib(struct gf100_grctx *);
+void gf108_grctx_generate_unkn(struct gf100_gr_priv *);
+
+extern struct nvkm_oclass *gf104_grctx_oclass;
+extern struct nvkm_oclass *gf110_grctx_oclass;
+
+extern struct nvkm_oclass *gf117_grctx_oclass;
+void gf117_grctx_generate_attrib(struct gf100_grctx *);
+
+extern struct nvkm_oclass *gf119_grctx_oclass;
+
+extern struct nvkm_oclass *gk104_grctx_oclass;
+extern struct nvkm_oclass *gk20a_grctx_oclass;
+void gk104_grctx_generate_main(struct gf100_gr_priv *, struct gf100_grctx *);
+void gk104_grctx_generate_bundle(struct gf100_grctx *);
+void gk104_grctx_generate_pagepool(struct gf100_grctx *);
+void gk104_grctx_generate_unkn(struct gf100_gr_priv *);
+void gk104_grctx_generate_r418bb8(struct gf100_gr_priv *);
+
+extern struct nvkm_oclass *gk110_grctx_oclass;
+extern struct nvkm_oclass *gk110b_grctx_oclass;
+extern struct nvkm_oclass *gk208_grctx_oclass;
+extern struct nvkm_oclass *gm107_grctx_oclass;
+
+/* context init value lists */
+
+extern const struct gf100_gr_pack gf100_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_mthd[];
+extern const struct gf100_gr_init gf100_grctx_init_902d_0[];
+extern const struct gf100_gr_init gf100_grctx_init_9039_0[];
+extern const struct gf100_gr_init gf100_grctx_init_90c0_0[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_hub[];
+extern const struct gf100_gr_init gf100_grctx_init_main_0[];
+extern const struct gf100_gr_init gf100_grctx_init_fe_0[];
+extern const struct gf100_gr_init gf100_grctx_init_pri_0[];
+extern const struct gf100_gr_init gf100_grctx_init_memfmt_0[];
+extern const struct gf100_gr_init gf100_grctx_init_rstr2d_0[];
+extern const struct gf100_gr_init gf100_grctx_init_scc_0[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_gpc[];
+extern const struct gf100_gr_init gf100_grctx_init_gpc_unk_0[];
+extern const struct gf100_gr_init gf100_grctx_init_prop_0[];
+extern const struct gf100_gr_init gf100_grctx_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf100_grctx_init_zcull_0[];
+extern const struct gf100_gr_init gf100_grctx_init_crstr_0[];
+extern const struct gf100_gr_init gf100_grctx_init_gpm_0[];
+extern const struct gf100_gr_init gf100_grctx_init_gcc_0[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_zcull[];
+
+extern const struct gf100_gr_pack gf100_grctx_pack_tpc[];
+extern const struct gf100_gr_init gf100_grctx_init_pe_0[];
+extern const struct gf100_gr_init gf100_grctx_init_wwdx_0[];
+extern const struct gf100_gr_init gf100_grctx_init_mpc_0[];
+extern const struct gf100_gr_init gf100_grctx_init_tpccs_0[];
+
+extern const struct gf100_gr_init gf104_grctx_init_tex_0[];
+extern const struct gf100_gr_init gf104_grctx_init_l1c_0[];
+extern const struct gf100_gr_init gf104_grctx_init_sm_0[];
+
+extern const struct gf100_gr_init gf108_grctx_init_9097_0[];
+
+extern const struct gf100_gr_init gf108_grctx_init_gpm_0[];
+
+extern const struct gf100_gr_init gf108_grctx_init_pe_0[];
+extern const struct gf100_gr_init gf108_grctx_init_wwdx_0[];
+extern const struct gf100_gr_init gf108_grctx_init_tpccs_0[];
+
+extern const struct gf100_gr_init gf110_grctx_init_9197_0[];
+extern const struct gf100_gr_init gf110_grctx_init_9297_0[];
+
+extern const struct gf100_gr_pack gf119_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gf119_grctx_pack_mthd[];
+
+extern const struct gf100_gr_init gf119_grctx_init_fe_0[];
+extern const struct gf100_gr_init gf119_grctx_init_be_0[];
+
+extern const struct gf100_gr_init gf119_grctx_init_prop_0[];
+extern const struct gf100_gr_init gf119_grctx_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf119_grctx_init_crstr_0[];
+
+extern const struct gf100_gr_init gf119_grctx_init_sm_0[];
+
+extern const struct gf100_gr_init gf117_grctx_init_pe_0[];
+
+extern const struct gf100_gr_init gf117_grctx_init_wwdx_0[];
+
+extern const struct gf100_gr_init gk104_grctx_init_memfmt_0[];
+extern const struct gf100_gr_init gk104_grctx_init_ds_0[];
+extern const struct gf100_gr_init gk104_grctx_init_scc_0[];
+
+extern const struct gf100_gr_init gk104_grctx_init_gpm_0[];
+
+extern const struct gf100_gr_init gk104_grctx_init_pes_0[];
+
+extern const struct gf100_gr_pack gk104_grctx_pack_hub[];
+extern const struct gf100_gr_pack gk104_grctx_pack_gpc[];
+extern const struct gf100_gr_pack gk104_grctx_pack_tpc[];
+extern const struct gf100_gr_pack gk104_grctx_pack_ppc[];
+extern const struct gf100_gr_pack gk104_grctx_pack_icmd[];
+extern const struct gf100_gr_init gk104_grctx_init_a097_0[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_icmd[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_mthd[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_hub[];
+extern const struct gf100_gr_init gk110_grctx_init_pri_0[];
+extern const struct gf100_gr_init gk110_grctx_init_cwd_0[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_gpc[];
+extern const struct gf100_gr_init gk110_grctx_init_gpc_unk_2[];
+
+extern const struct gf100_gr_init gk110_grctx_init_tex_0[];
+extern const struct gf100_gr_init gk110_grctx_init_mpc_0[];
+extern const struct gf100_gr_init gk110_grctx_init_l1c_0[];
+
+extern const struct gf100_gr_pack gk110_grctx_pack_ppc[];
+
+extern const struct gf100_gr_init gk208_grctx_init_rstr2d_0[];
+
+extern const struct gf100_gr_init gk208_grctx_init_prop_0[];
+extern const struct gf100_gr_init gk208_grctx_init_crstr_0[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
new file mode 100644
index 000000000000..c5a8d55e2cac
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf104.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf104_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00000000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0007f440 },
+ {}
+};
+
+const struct gf100_gr_init
+gf104_grctx_init_l1c_0[] = {
+ { 0x419cb0, 1, 0x04, 0x00020048 },
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000183 },
+ {}
+};
+
+const struct gf100_gr_init
+gf104_grctx_init_sm_0[] = {
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00011110 },
+ { 0x419f30, 11, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf104_grctx_pack_tpc[] = {
+ { gf100_grctx_init_pe_0 },
+ { gf104_grctx_init_tex_0 },
+ { gf100_grctx_init_wwdx_0 },
+ { gf100_grctx_init_mpc_0 },
+ { gf104_grctx_init_l1c_0 },
+ { gf100_grctx_init_tpccs_0 },
+ { gf104_grctx_init_sm_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf104_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc3),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gf100_grctx_generate_main,
+ .unkn = gf100_grctx_generate_unkn,
+ .hub = gf100_grctx_pack_hub,
+ .gpc = gf100_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gf104_grctx_pack_tpc,
+ .icmd = gf100_grctx_pack_icmd,
+ .mthd = gf100_grctx_pack_mthd,
+ .bundle = gf100_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .pagepool = gf100_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf100_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
new file mode 100644
index 000000000000..87c844a5f34b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf108.c
@@ -0,0 +1,806 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf108_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_icmd[] = {
+ { gf108_grctx_init_icmd_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_9097_0[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x002700, 8, 0x20, 0x00000000 },
+ { 0x002704, 8, 0x20, 0x00000000 },
+ { 0x002708, 8, 0x20, 0x00000000 },
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x002710, 8, 0x20, 0x00014000 },
+ { 0x002714, 8, 0x20, 0x00000040 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002200, 5, 0x10, 0x00000022 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00001fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x003fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 4, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 1, 0x04, 0x003fffff },
+ { 0x0002d0, 1, 0x04, 0x00000c48 },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00300008 },
+ { 0x001284, 1, 0x04, 0x04000080 },
+ { 0x001450, 1, 0x04, 0x00300008 },
+ { 0x001454, 1, 0x04, 0x04000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_9197_0[] = {
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_mthd[] = {
+ { gf108_grctx_init_9097_0, 0x9097 },
+ { gf108_grctx_init_9197_0, 0x9197 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ { gf100_grctx_init_9039_0, 0x9039 },
+ { gf100_grctx_init_90c0_0, 0x90c0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180218 },
+ { 0x405834, 2, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x000103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 2, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x80140078 },
+ { 0x4064c4, 1, 0x04, 0x0086ffff },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1003e005 },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c80929 },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gf100_grctx_init_fe_0 },
+ { gf100_grctx_init_pri_0 },
+ { gf100_grctx_init_memfmt_0 },
+ { gf108_grctx_init_ds_0 },
+ { gf108_grctx_init_pd_0 },
+ { gf100_grctx_init_rstr2d_0 },
+ { gf100_grctx_init_scc_0 },
+ { gf108_grctx_init_be_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x0006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x00100018 },
+ {}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_gpm_0[] = {
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf100_grctx_init_prop_0 },
+ { gf100_grctx_init_gpc_unk_1 },
+ { gf108_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf100_grctx_init_crstr_0 },
+ { gf108_grctx_init_gpm_0 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_pe_0[] = {
+ { 0x419818, 1, 0x04, 0x00000000 },
+ { 0x41983c, 1, 0x04, 0x00038bc7 },
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_wwdx_0[] = {
+ { 0x419b00, 1, 0x04, 0x0a418820 },
+ { 0x419b04, 1, 0x04, 0x062080e6 },
+ { 0x419b08, 1, 0x04, 0x020398a4 },
+ { 0x419b0c, 1, 0x04, 0x0e629062 },
+ { 0x419b10, 1, 0x04, 0x0a418820 },
+ { 0x419b14, 1, 0x04, 0x000000e6 },
+ { 0x419bd0, 1, 0x04, 0x00900103 },
+ { 0x419be0, 1, 0x04, 0x00400001 },
+ { 0x419be4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf108_grctx_init_tpccs_0[] = {
+ { 0x419d20, 1, 0x04, 0x12180000 },
+ { 0x419d24, 1, 0x04, 0x00001fff },
+ { 0x419d44, 1, 0x04, 0x02180218 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf108_grctx_pack_tpc[] = {
+ { gf108_grctx_init_pe_0 },
+ { gf104_grctx_init_tex_0 },
+ { gf108_grctx_init_wwdx_0 },
+ { gf100_grctx_init_mpc_0 },
+ { gf104_grctx_init_l1c_0 },
+ { gf108_grctx_init_tpccs_0 },
+ { gf104_grctx_init_sm_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+void
+gf108_grctx_generate_attrib(struct gf100_grctx *info)
+{
+ struct gf100_gr_priv *priv = info->priv;
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv);
+ const u32 alpha = impl->alpha_nr;
+ const u32 beta = impl->attrib_nr;
+ const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+ const u32 access = NV_MEM_ACCESS_RW;
+ const int s = 12;
+ const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+ const int timeslice_mode = 1;
+ const int max_batches = 0xffff;
+ u32 bo = 0;
+ u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
+ int gpc, tpc;
+
+ mmio_refn(info, 0x418810, 0x80000000, s, b);
+ mmio_refn(info, 0x419848, 0x10000000, s, b);
+ mmio_wr32(info, 0x405830, (beta << 16) | alpha);
+ mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ const u32 a = alpha;
+ const u32 b = beta;
+ const u32 t = timeslice_mode;
+ const u32 o = TPC_UNIT(gpc, tpc, 0x500);
+ mmio_skip(info, o + 0x20, (t << 28) | (b << 16) | ++bo);
+ mmio_wr32(info, o + 0x20, (t << 28) | (b << 16) | --bo);
+ bo += impl->attrib_nr_max;
+ mmio_wr32(info, o + 0x44, (a << 16) | ao);
+ ao += impl->alpha_nr_max;
+ }
+ }
+}
+
+void
+gf108_grctx_generate_unkn(struct gf100_gr_priv *priv)
+{
+ nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+ nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+ nv_mask(priv, 0x419814, 0x00000004, 0x00000004);
+ nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+ nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+ nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+struct nvkm_oclass *
+gf108_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc1),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gf100_grctx_generate_main,
+ .unkn = gf108_grctx_generate_unkn,
+ .hub = gf108_grctx_pack_hub,
+ .gpc = gf108_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gf108_grctx_pack_tpc,
+ .icmd = gf108_grctx_pack_icmd,
+ .mthd = gf108_grctx_pack_mthd,
+ .bundle = gf100_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .pagepool = gf100_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf108_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x324,
+ .alpha_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
new file mode 100644
index 000000000000..b3acd931b978
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf110.c
@@ -0,0 +1,359 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf110_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf110_grctx_pack_icmd[] = {
+ { gf110_grctx_init_icmd_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf110_grctx_init_9197_0[] = {
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ {}
+};
+
+const struct gf100_gr_init
+gf110_grctx_init_9297_0[] = {
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00036c, 2, 0x04, 0x00000000 },
+ { 0x0007a4, 2, 0x04, 0x00000000 },
+ { 0x000374, 1, 0x04, 0x00000000 },
+ { 0x000378, 1, 0x04, 0x00000020 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf110_grctx_pack_mthd[] = {
+ { gf108_grctx_init_9097_0, 0x9097 },
+ { gf110_grctx_init_9197_0, 0x9197 },
+ { gf110_grctx_init_9297_0, 0x9297 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ { gf100_grctx_init_9039_0, 0x9039 },
+ { gf100_grctx_init_90c0_0, 0x90c0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf110_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x0006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x00000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf110_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf100_grctx_init_prop_0 },
+ { gf100_grctx_init_gpc_unk_1 },
+ { gf110_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf100_grctx_init_crstr_0 },
+ { gf100_grctx_init_gpm_0 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf110_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xc8),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gf100_grctx_generate_main,
+ .unkn = gf100_grctx_generate_unkn,
+ .hub = gf100_grctx_pack_hub,
+ .gpc = gf110_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gf100_grctx_pack_tpc,
+ .icmd = gf110_grctx_pack_icmd,
+ .mthd = gf110_grctx_pack_mthd,
+ .bundle = gf100_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .pagepool = gf100_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf100_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
new file mode 100644
index 000000000000..9bbe2c97552e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf117.c
@@ -0,0 +1,284 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf117_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180324 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x000103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x801a0078 },
+ { 0x4064c4, 1, 0x04, 0x00c9ffff },
+ { 0x4064d0, 8, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gf119_grctx_init_fe_0 },
+ { gf100_grctx_init_pri_0 },
+ { gf100_grctx_init_memfmt_0 },
+ { gf117_grctx_init_ds_0 },
+ { gf117_grctx_init_pd_0 },
+ { gf100_grctx_init_rstr2d_0 },
+ { gf100_grctx_init_scc_0 },
+ { gf119_grctx_init_be_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100018 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf119_grctx_init_prop_0 },
+ { gf119_grctx_init_gpc_unk_1 },
+ { gf117_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf119_grctx_init_crstr_0 },
+ { gf108_grctx_init_gpm_0 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf117_grctx_init_pe_0[] = {
+ { 0x419848, 1, 0x04, 0x00000000 },
+ { 0x419864, 1, 0x04, 0x00000129 },
+ { 0x419888, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00008000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0017f440 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_mpc_0[] = {
+ { 0x419c00, 1, 0x04, 0x0000000a },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_tpc[] = {
+ { gf117_grctx_init_pe_0 },
+ { gf117_grctx_init_tex_0 },
+ { gf117_grctx_init_mpc_0 },
+ { gf104_grctx_init_l1c_0 },
+ { gf119_grctx_init_sm_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_pes_0[] = {
+ { 0x41be24, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf117_grctx_init_cbm_0[] = {
+ { 0x41bec0, 1, 0x04, 0x12180000 },
+ { 0x41bec4, 1, 0x04, 0x00003fff },
+ { 0x41bee4, 1, 0x04, 0x03240218 },
+ {}
+};
+
+const struct gf100_gr_init
+gf117_grctx_init_wwdx_0[] = {
+ { 0x41bf00, 1, 0x04, 0x0a418820 },
+ { 0x41bf04, 1, 0x04, 0x062080e6 },
+ { 0x41bf08, 1, 0x04, 0x020398a4 },
+ { 0x41bf0c, 1, 0x04, 0x0e629062 },
+ { 0x41bf10, 1, 0x04, 0x0a418820 },
+ { 0x41bf14, 1, 0x04, 0x000000e6 },
+ { 0x41bfd0, 1, 0x04, 0x00900103 },
+ { 0x41bfe0, 1, 0x04, 0x00400001 },
+ { 0x41bfe4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf117_grctx_pack_ppc[] = {
+ { gf117_grctx_init_pes_0 },
+ { gf117_grctx_init_cbm_0 },
+ { gf117_grctx_init_wwdx_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+void
+gf117_grctx_generate_attrib(struct gf100_grctx *info)
+{
+ struct gf100_gr_priv *priv = info->priv;
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(priv);
+ const u32 alpha = impl->alpha_nr;
+ const u32 beta = impl->attrib_nr;
+ const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+ const u32 access = NV_MEM_ACCESS_RW;
+ const int s = 12;
+ const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+ const int timeslice_mode = 1;
+ const int max_batches = 0xffff;
+ u32 bo = 0;
+ u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
+ int gpc, ppc;
+
+ mmio_refn(info, 0x418810, 0x80000000, s, b);
+ mmio_refn(info, 0x419848, 0x10000000, s, b);
+ mmio_wr32(info, 0x405830, (beta << 16) | alpha);
+ mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++) {
+ const u32 a = alpha * priv->ppc_tpc_nr[gpc][ppc];
+ const u32 b = beta * priv->ppc_tpc_nr[gpc][ppc];
+ const u32 t = timeslice_mode;
+ const u32 o = PPC_UNIT(gpc, ppc, 0);
+ mmio_skip(info, o + 0xc0, (t << 28) | (b << 16) | ++bo);
+ mmio_wr32(info, o + 0xc0, (t << 28) | (b << 16) | --bo);
+ bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+ mmio_wr32(info, o + 0xe4, (a << 16) | ao);
+ ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+ }
+ }
+}
+
+void
+gf117_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+ struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ int i;
+
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+
+ gf100_gr_mmio(priv, oclass->hub);
+ gf100_gr_mmio(priv, oclass->gpc);
+ gf100_gr_mmio(priv, oclass->zcull);
+ gf100_gr_mmio(priv, oclass->tpc);
+ gf100_gr_mmio(priv, oclass->ppc);
+
+ nv_wr32(priv, 0x404154, 0x00000000);
+
+ oclass->bundle(info);
+ oclass->pagepool(info);
+ oclass->attrib(info);
+ oclass->unkn(priv);
+
+ gf100_grctx_generate_tpcid(priv);
+ gf100_grctx_generate_r406028(priv);
+ gf100_grctx_generate_r4060a8(priv);
+ gk104_grctx_generate_r418bb8(priv);
+ gf100_grctx_generate_r406800(priv);
+
+ for (i = 0; i < 8; i++)
+ nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+ gf100_gr_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ gf100_gr_mthd(priv, oclass->mthd);
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+}
+
+struct nvkm_oclass *
+gf117_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xd7),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gf117_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gf117_grctx_pack_hub,
+ .gpc = gf117_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gf117_grctx_pack_tpc,
+ .ppc = gf117_grctx_pack_ppc,
+ .icmd = gf119_grctx_pack_icmd,
+ .mthd = gf119_grctx_pack_mthd,
+ .bundle = gf100_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .pagepool = gf100_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf117_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x7ff,
+ .alpha_nr = 0x324,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
new file mode 100644
index 000000000000..8d8761443809
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgf119.c
@@ -0,0 +1,529 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf119_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000b2, 40, 0x01, 0x00000000 },
+ { 0x000210, 8, 0x01, 0x00000040 },
+ { 0x000400, 24, 0x01, 0x00000040 },
+ { 0x000218, 8, 0x01, 0x0000c080 },
+ { 0x000440, 24, 0x01, 0x0000c080 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00001fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x003fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x0005e0, 5, 0x01, 0x00000022 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x00000c48 },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00300008 },
+ { 0x000841, 1, 0x01, 0x04000080 },
+ { 0x000842, 1, 0x01, 0x00300008 },
+ { 0x000843, 1, 0x01, 0x04000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x000944, 1, 0x01, 0x00000022 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000014 },
+ { 0x000351, 1, 0x01, 0x00000100 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095d, 1, 0x01, 0x00000001 },
+ { 0x00082b, 1, 0x01, 0x00000004 },
+ { 0x000942, 1, 0x01, 0x00010001 },
+ { 0x000943, 1, 0x01, 0x00000001 },
+ { 0x0007c5, 1, 0x01, 0x00010001 },
+ { 0x000834, 1, 0x01, 0x00000001 },
+ { 0x0007c7, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x00080c, 1, 0x01, 0x00000002 },
+ { 0x00080d, 2, 0x01, 0x00000100 },
+ { 0x00080f, 1, 0x01, 0x00000001 },
+ { 0x000823, 1, 0x01, 0x00000002 },
+ { 0x000824, 2, 0x01, 0x00000100 },
+ { 0x000826, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf119_grctx_pack_icmd[] = {
+ { gf119_grctx_init_icmd_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_90c0_0[] = {
+ { 0x002700, 8, 0x20, 0x00000000 },
+ { 0x002704, 8, 0x20, 0x00000000 },
+ { 0x002708, 8, 0x20, 0x00000000 },
+ { 0x00270c, 8, 0x20, 0x00000000 },
+ { 0x002710, 8, 0x20, 0x00014000 },
+ { 0x002714, 8, 0x20, 0x00000040 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x000758, 1, 0x04, 0x00000100 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x000204, 3, 0x04, 0x00000000 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ { 0x00024c, 1, 0x04, 0x00000000 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x001664, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gf119_grctx_pack_mthd[] = {
+ { gf108_grctx_init_9097_0, 0x9097 },
+ { gf110_grctx_init_9197_0, 0x9197 },
+ { gf110_grctx_init_9297_0, 0x9297 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ { gf100_grctx_init_9039_0, 0x9039 },
+ { gf119_grctx_init_90c0_0, 0x90c0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_fe_0[] = {
+ { 0x404004, 10, 0x04, 0x00000000 },
+ { 0x404044, 1, 0x04, 0x00000000 },
+ { 0x404094, 13, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf0000087 },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x404168, 1, 0x04, 0x00000000 },
+ { 0x404178, 2, 0x04, 0x00000000 },
+ { 0x404200, 8, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180218 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x000103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x80140078 },
+ { 0x4064c4, 1, 0x04, 0x0086ffff },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1043e005 },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf119_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gf119_grctx_init_fe_0 },
+ { gf100_grctx_init_pri_0 },
+ { gf100_grctx_init_memfmt_0 },
+ { gf119_grctx_init_ds_0 },
+ { gf119_grctx_init_pd_0 },
+ { gf100_grctx_init_rstr2d_0 },
+ { gf100_grctx_init_scc_0 },
+ { gf119_grctx_init_be_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_prop_0[] = {
+ { 0x418400, 1, 0x04, 0x38004e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x02200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_gpc_unk_1[] = {
+ { 0x418600, 1, 0x04, 0x0000001f },
+ { 0x418684, 1, 0x04, 0x0000000f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 3, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00008442 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100008 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_crstr_0[] = {
+ { 0x418b00, 1, 0x04, 0x00000006 },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf119_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf119_grctx_init_prop_0 },
+ { gf119_grctx_init_gpc_unk_1 },
+ { gf119_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf119_grctx_init_crstr_0 },
+ { gf108_grctx_init_gpm_0 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000001f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000023 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x00000000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419ac4, 1, 0x04, 0x0017f440 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_grctx_init_mpc_0[] = {
+ { 0x419c00, 1, 0x04, 0x0000000a },
+ { 0x419c04, 1, 0x04, 0x00000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3cf3cf3c },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_grctx_init_sm_0[] = {
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000002 },
+ { 0x419e44, 1, 0x04, 0x001beff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000000f },
+ { 0x419e50, 17, 0x04, 0x00000000 },
+ { 0x419e98, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00010110 },
+ { 0x419f30, 11, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf119_grctx_pack_tpc[] = {
+ { gf108_grctx_init_pe_0 },
+ { gf119_grctx_init_tex_0 },
+ { gf108_grctx_init_wwdx_0 },
+ { gf119_grctx_init_mpc_0 },
+ { gf104_grctx_init_l1c_0 },
+ { gf108_grctx_init_tpccs_0 },
+ { gf119_grctx_init_sm_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf119_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xd9),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gf100_grctx_generate_main,
+ .unkn = gf108_grctx_generate_unkn,
+ .hub = gf119_grctx_pack_hub,
+ .gpc = gf119_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gf119_grctx_pack_tpc,
+ .icmd = gf119_grctx_pack_icmd,
+ .mthd = gf119_grctx_pack_mthd,
+ .bundle = gf100_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .pagepool = gf100_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf108_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x324,
+ .alpha_nr = 0x218,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
new file mode 100644
index 000000000000..b52300d8861a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk104.c
@@ -0,0 +1,1022 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk104_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000383, 1, 0x01, 0x00000011 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x003fffff },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00400008 },
+ { 0x000841, 1, 0x01, 0x08000080 },
+ { 0x000842, 1, 0x01, 0x00400008 },
+ { 0x000843, 1, 0x01, 0x08000080 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000008 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_icmd[] = {
+ { gk104_grctx_init_icmd_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_a097_0[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00000fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x000fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00260c, 1, 0x04, 0x00000000 },
+ { 0x0007ac, 1, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ { 0x00036c, 2, 0x04, 0x00000000 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 4, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x0007a4, 2, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x000374, 1, 0x04, 0x00000000 },
+ { 0x000378, 1, 0x04, 0x00000020 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 2, 0x04, 0x003fffff },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00400008 },
+ { 0x001284, 1, 0x04, 0x08000080 },
+ { 0x001450, 1, 0x04, 0x00400008 },
+ { 0x001454, 1, 0x04, 0x08000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk104_grctx_pack_mthd[] = {
+ { gk104_grctx_init_a097_0, 0xa097 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_fe_0[] = {
+ { 0x404010, 5, 0x04, 0x00000000 },
+ { 0x404024, 1, 0x04, 0x0000e000 },
+ { 0x404028, 1, 0x04, 0x00000000 },
+ { 0x4040a8, 8, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf800008f },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x4041a0, 4, 0x04, 0x00000000 },
+ { 0x404200, 4, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_memfmt_0[] = {
+ { 0x404604, 1, 0x04, 0x00000014 },
+ { 0x404608, 1, 0x04, 0x00000000 },
+ { 0x40460c, 1, 0x04, 0x00003fff },
+ { 0x404610, 1, 0x04, 0x00000100 },
+ { 0x404618, 4, 0x04, 0x00000000 },
+ { 0x40462c, 2, 0x04, 0x00000000 },
+ { 0x404640, 1, 0x04, 0x00000000 },
+ { 0x404654, 1, 0x04, 0x00000000 },
+ { 0x404660, 1, 0x04, 0x00000000 },
+ { 0x404678, 1, 0x04, 0x00000000 },
+ { 0x40467c, 1, 0x04, 0x00000002 },
+ { 0x404680, 8, 0x04, 0x00000000 },
+ { 0x4046a0, 1, 0x04, 0x007f0080 },
+ { 0x4046a4, 8, 0x04, 0x00000000 },
+ { 0x4046c8, 3, 0x04, 0x00000000 },
+ { 0x404700, 3, 0x04, 0x00000000 },
+ { 0x404718, 7, 0x04, 0x00000000 },
+ { 0x404734, 1, 0x04, 0x00000100 },
+ { 0x404738, 2, 0x04, 0x00000000 },
+ { 0x404744, 2, 0x04, 0x00000000 },
+ { 0x404754, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180648 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_cwd_0[] = {
+ { 0x405b00, 1, 0x04, 0x00000000 },
+ { 0x405b10, 1, 0x04, 0x00001000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x004103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b4, 2, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x801a00f0 },
+ { 0x4064c4, 1, 0x04, 0x0192ffff },
+ { 0x4064c8, 1, 0x04, 0x01800600 },
+ { 0x4064cc, 9, 0x04, 0x00000000 },
+ { 0x4064fc, 1, 0x04, 0x0000022a },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_sked_0[] = {
+ { 0x407040, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_scc_0[] = {
+ { 0x408000, 2, 0x04, 0x00000000 },
+ { 0x408008, 1, 0x04, 0x00000030 },
+ { 0x40800c, 2, 0x04, 0x00000000 },
+ { 0x408014, 1, 0x04, 0x00000069 },
+ { 0x408018, 1, 0x04, 0xe100e100 },
+ { 0x408064, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x02802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1043e005 },
+ { 0x408840, 1, 0x04, 0x0000000b },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gk104_grctx_init_fe_0 },
+ { gf100_grctx_init_pri_0 },
+ { gk104_grctx_init_memfmt_0 },
+ { gk104_grctx_init_ds_0 },
+ { gk104_grctx_init_cwd_0 },
+ { gk104_grctx_init_pd_0 },
+ { gk104_grctx_init_sked_0 },
+ { gf100_grctx_init_rstr2d_0 },
+ { gk104_grctx_init_scc_0 },
+ { gk104_grctx_init_be_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 3, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00000044 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100018 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_gpm_0[] = {
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c40, 1, 0x04, 0xffffffff },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x20200004 },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf119_grctx_init_prop_0 },
+ { gf119_grctx_init_gpc_unk_1 },
+ { gk104_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf119_grctx_init_crstr_0 },
+ { gk104_grctx_init_gpm_0 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000000f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000021 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x0000c000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419a30, 1, 0x04, 0x00000001 },
+ { 0x419ac4, 1, 0x04, 0x0037f440 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_mpc_0[] = {
+ { 0x419c00, 1, 0x04, 0x0000000a },
+ { 0x419c04, 1, 0x04, 0x80000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_l1c_0[] = {
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00003203 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_sm_0[] = {
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00000402 },
+ { 0x419e44, 1, 0x04, 0x0013eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 19, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x00001f8f },
+ { 0x419eb0, 1, 0x04, 0x00000d3f },
+ { 0x419ec8, 1, 0x04, 0x0001304f },
+ { 0x419f30, 8, 0x04, 0x00000000 },
+ { 0x419f58, 1, 0x04, 0x00000000 },
+ { 0x419f70, 1, 0x04, 0x00000000 },
+ { 0x419f78, 1, 0x04, 0x0000000b },
+ { 0x419f7c, 1, 0x04, 0x0000027c },
+ {}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_tpc[] = {
+ { gf117_grctx_init_pe_0 },
+ { gk104_grctx_init_tex_0 },
+ { gk104_grctx_init_mpc_0 },
+ { gk104_grctx_init_l1c_0 },
+ { gk104_grctx_init_sm_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_grctx_init_pes_0[] = {
+ { 0x41be24, 1, 0x04, 0x00000006 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_grctx_init_cbm_0[] = {
+ { 0x41bec0, 1, 0x04, 0x12180000 },
+ { 0x41bec4, 1, 0x04, 0x00037f7f },
+ { 0x41bee4, 1, 0x04, 0x06480430 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk104_grctx_pack_ppc[] = {
+ { gk104_grctx_init_pes_0 },
+ { gk104_grctx_init_cbm_0 },
+ { gf117_grctx_init_wwdx_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+void
+gk104_grctx_generate_bundle(struct gf100_grctx *info)
+{
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+ const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
+ impl->bundle_size / 0x20);
+ const u32 token_limit = impl->bundle_token_limit;
+ const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+ const int s = 8;
+ const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
+ mmio_refn(info, 0x408004, 0x00000000, s, b);
+ mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+ mmio_refn(info, 0x418808, 0x00000000, s, b);
+ mmio_refn(info, 0x41880c, 0x80000000 | (impl->bundle_size >> s), 0, b);
+ mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
+}
+
+void
+gk104_grctx_generate_pagepool(struct gf100_grctx *info)
+{
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+ const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+ const int s = 8;
+ const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
+ mmio_refn(info, 0x40800c, 0x00000000, s, b);
+ mmio_wr32(info, 0x408010, 0x80000000);
+ mmio_refn(info, 0x419004, 0x00000000, s, b);
+ mmio_wr32(info, 0x419008, 0x00000000);
+ mmio_wr32(info, 0x4064cc, 0x80000000);
+}
+
+void
+gk104_grctx_generate_unkn(struct gf100_gr_priv *priv)
+{
+ nv_mask(priv, 0x418c6c, 0x00000001, 0x00000001);
+ nv_mask(priv, 0x41980c, 0x00000010, 0x00000010);
+ nv_mask(priv, 0x41be08, 0x00000004, 0x00000004);
+ nv_mask(priv, 0x4064c0, 0x80000000, 0x80000000);
+ nv_mask(priv, 0x405800, 0x08000000, 0x08000000);
+ nv_mask(priv, 0x419c00, 0x00000008, 0x00000008);
+}
+
+void
+gk104_grctx_generate_r418bb8(struct gf100_gr_priv *priv)
+{
+ u32 data[6] = {}, data2[2] = {};
+ u8 tpcnr[GPC_MAX];
+ u8 shift, ntpcv;
+ int gpc, tpc, i;
+
+ /* calculate first set of magics */
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+
+ gpc = -1;
+ for (tpc = 0; tpc < priv->tpc_total; tpc++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpcnr[gpc]--;
+
+ data[tpc / 6] |= gpc << ((tpc % 6) * 5);
+ }
+
+ for (; tpc < 32; tpc++)
+ data[tpc / 6] |= 7 << ((tpc % 6) * 5);
+
+ /* and the second... */
+ shift = 0;
+ ntpcv = priv->tpc_total;
+ while (!(ntpcv & (1 << 4))) {
+ ntpcv <<= 1;
+ shift++;
+ }
+
+ data2[0] = (ntpcv << 16);
+ data2[0] |= (shift << 21);
+ data2[0] |= (((1 << (0 + 5)) % ntpcv) << 24);
+ for (i = 1; i < 7; i++)
+ data2[1] |= ((1 << (i + 5)) % ntpcv) << ((i - 1) * 5);
+
+ /* GPC_BROADCAST */
+ nv_wr32(priv, 0x418bb8, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x418b08 + (i * 4), data[i]);
+
+ /* GPC_BROADCAST.TP_BROADCAST */
+ nv_wr32(priv, 0x41bfd0, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr | data2[0]);
+ nv_wr32(priv, 0x41bfe4, data2[1]);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x41bf00 + (i * 4), data[i]);
+
+ /* UNK78xx */
+ nv_wr32(priv, 0x4078bc, (priv->tpc_total << 8) |
+ priv->magic_not_rop_nr);
+ for (i = 0; i < 6; i++)
+ nv_wr32(priv, 0x40780c + (i * 4), data[i]);
+}
+
+void
+gk104_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+ struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ int i;
+
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+
+ gf100_gr_mmio(priv, oclass->hub);
+ gf100_gr_mmio(priv, oclass->gpc);
+ gf100_gr_mmio(priv, oclass->zcull);
+ gf100_gr_mmio(priv, oclass->tpc);
+ gf100_gr_mmio(priv, oclass->ppc);
+
+ nv_wr32(priv, 0x404154, 0x00000000);
+
+ oclass->bundle(info);
+ oclass->pagepool(info);
+ oclass->attrib(info);
+ oclass->unkn(priv);
+
+ gf100_grctx_generate_tpcid(priv);
+ gf100_grctx_generate_r406028(priv);
+ gk104_grctx_generate_r418bb8(priv);
+ gf100_grctx_generate_r406800(priv);
+
+ for (i = 0; i < 8; i++)
+ nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+
+ nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+ if (priv->gpc_nr == 1) {
+ nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+ nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+ } else {
+ nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+ nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+ }
+ nv_mask(priv, 0x419f78, 0x00000001, 0x00000000);
+
+ gf100_gr_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ gf100_gr_mthd(priv, oclass->mthd);
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+
+ nv_mask(priv, 0x418800, 0x00200000, 0x00200000);
+ nv_mask(priv, 0x41be10, 0x00800000, 0x00800000);
+}
+
+struct nvkm_oclass *
+gk104_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xe4),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gk104_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gk104_grctx_pack_hub,
+ .gpc = gk104_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gk104_grctx_pack_tpc,
+ .ppc = gk104_grctx_pack_ppc,
+ .icmd = gk104_grctx_pack_icmd,
+ .mthd = gk104_grctx_pack_mthd,
+ .bundle = gk104_grctx_generate_bundle,
+ .bundle_size = 0x3000,
+ .bundle_min_gpm_fifo_depth = 0x180,
+ .bundle_token_limit = 0x600,
+ .pagepool = gk104_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf117_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x7ff,
+ .alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
new file mode 100644
index 000000000000..b3f58be04e9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110.c
@@ -0,0 +1,842 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk110_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x0002f2, 2, 0x01, 0x00000001 },
+ { 0x0002f5, 1, 0x01, 0x00000001 },
+ { 0x0002f7, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000383, 1, 0x01, 0x00000011 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000662, 1, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x00080b, 1, 0x01, 0x00000002 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000a0d, 1, 0x01, 0x00000006 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x003fffff },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00400008 },
+ { 0x000841, 1, 0x01, 0x08000080 },
+ { 0x000842, 1, 0x01, 0x00400008 },
+ { 0x000843, 1, 0x01, 0x08000080 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000008 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_icmd[] = {
+ { gk110_grctx_init_icmd_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_a197_0[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x00163c, 1, 0x04, 0x00000000 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x000dec, 1, 0x04, 0x00000001 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x0012ac, 1, 0x04, 0x00000001 },
+ { 0x0002c4, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00000fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x000fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00260c, 1, 0x04, 0x00000000 },
+ { 0x0007ac, 1, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ { 0x00036c, 2, 0x04, 0x00000000 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 4, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x0007a4, 2, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x000ddc, 1, 0x04, 0x00000002 },
+ { 0x000374, 1, 0x04, 0x00000000 },
+ { 0x000378, 1, 0x04, 0x00000020 },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x0017bc, 2, 0x04, 0x00000000 },
+ { 0x0017c4, 1, 0x04, 0x00000001 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x00075c, 1, 0x04, 0x00000003 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x000208, 1, 0x04, 0x00000000 },
+ { 0x0002cc, 2, 0x04, 0x003fffff },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00400008 },
+ { 0x001284, 1, 0x04, 0x08000080 },
+ { 0x001450, 1, 0x04, 0x00400008 },
+ { 0x001454, 1, 0x04, 0x08000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_mthd[] = {
+ { gk110_grctx_init_a197_0, 0xa197 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_fe_0[] = {
+ { 0x404004, 8, 0x04, 0x00000000 },
+ { 0x404024, 1, 0x04, 0x0000e000 },
+ { 0x404028, 8, 0x04, 0x00000000 },
+ { 0x4040a8, 8, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf800008f },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404100, 10, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x40417c, 2, 0x04, 0x00000000 },
+ { 0x4041a0, 4, 0x04, 0x00000000 },
+ { 0x404200, 1, 0x04, 0x0000a197 },
+ { 0x404204, 1, 0x04, 0x0000a1c0 },
+ { 0x404208, 1, 0x04, 0x0000a140 },
+ { 0x40420c, 1, 0x04, 0x0000902d },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_pri_0[] = {
+ { 0x404404, 12, 0x04, 0x00000000 },
+ { 0x404438, 1, 0x04, 0x00000000 },
+ { 0x404460, 2, 0x04, 0x00000000 },
+ { 0x404468, 1, 0x04, 0x00ffffff },
+ { 0x40446c, 1, 0x04, 0x00000000 },
+ { 0x404480, 1, 0x04, 0x00000001 },
+ { 0x404498, 1, 0x04, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_cwd_0[] = {
+ { 0x405b00, 1, 0x04, 0x00000000 },
+ { 0x405b10, 1, 0x04, 0x00001000 },
+ { 0x405b20, 1, 0x04, 0x04000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x034103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b0, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x802000f0 },
+ { 0x4064c4, 1, 0x04, 0x0192ffff },
+ { 0x4064c8, 1, 0x04, 0x018007c0 },
+ { 0x4064cc, 9, 0x04, 0x00000000 },
+ { 0x4064fc, 1, 0x04, 0x0000022a },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x12802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1003e005 },
+ { 0x408840, 1, 0x04, 0x0000000b },
+ { 0x408900, 1, 0x04, 0x3080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x00c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gk110_grctx_init_fe_0 },
+ { gk110_grctx_init_pri_0 },
+ { gk104_grctx_init_memfmt_0 },
+ { gk104_grctx_init_ds_0 },
+ { gk110_grctx_init_cwd_0 },
+ { gk110_grctx_init_pd_0 },
+ { gf100_grctx_init_rstr2d_0 },
+ { gk104_grctx_init_scc_0 },
+ { gk110_grctx_init_be_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x7006860a },
+ { 0x418808, 1, 0x04, 0x00000000 },
+ { 0x41880c, 1, 0x04, 0x00000030 },
+ { 0x418810, 1, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00000044 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100018 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_gpc_unk_2[] = {
+ { 0x418d24, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gf119_grctx_init_prop_0 },
+ { gf119_grctx_init_gpc_unk_1 },
+ { gk110_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gf119_grctx_init_crstr_0 },
+ { gk104_grctx_init_gpm_0 },
+ { gk110_grctx_init_gpc_unk_2 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000000f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000021 },
+ { 0x419a0c, 1, 0x04, 0x00020000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x0000c000 },
+ { 0x419a20, 1, 0x04, 0x00020800 },
+ { 0x419a30, 1, 0x04, 0x00000001 },
+ { 0x419ac4, 1, 0x04, 0x0037f440 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_mpc_0[] = {
+ { 0x419c00, 1, 0x04, 0x0000001a },
+ { 0x419c04, 1, 0x04, 0x80000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_grctx_init_l1c_0[] = {
+ { 0x419ce8, 1, 0x04, 0x00000000 },
+ { 0x419cf4, 1, 0x04, 0x00000203 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_sm_0[] = {
+ { 0x419e04, 1, 0x04, 0x00000000 },
+ { 0x419e08, 1, 0x04, 0x0000001d },
+ { 0x419e0c, 1, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00001c02 },
+ { 0x419e44, 1, 0x04, 0x0013eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 2, 0x04, 0x00000000 },
+ { 0x419e58, 1, 0x04, 0x00000001 },
+ { 0x419e5c, 3, 0x04, 0x00000000 },
+ { 0x419e68, 1, 0x04, 0x00000002 },
+ { 0x419e6c, 12, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x00001f8f },
+ { 0x419eb0, 1, 0x04, 0x0db00d2f },
+ { 0x419eb8, 1, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0001304f },
+ { 0x419f30, 4, 0x04, 0x00000000 },
+ { 0x419f40, 1, 0x04, 0x00000018 },
+ { 0x419f44, 3, 0x04, 0x00000000 },
+ { 0x419f58, 1, 0x04, 0x00000000 },
+ { 0x419f70, 1, 0x04, 0x00007300 },
+ { 0x419f78, 1, 0x04, 0x000000eb },
+ { 0x419f7c, 1, 0x04, 0x00000404 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk110_grctx_pack_tpc[] = {
+ { gf117_grctx_init_pe_0 },
+ { gk110_grctx_init_tex_0 },
+ { gk110_grctx_init_mpc_0 },
+ { gk110_grctx_init_l1c_0 },
+ { gk110_grctx_init_sm_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_grctx_init_cbm_0[] = {
+ { 0x41bec0, 1, 0x04, 0x10000000 },
+ { 0x41bec4, 1, 0x04, 0x00037f7f },
+ { 0x41bee4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk110_grctx_pack_ppc[] = {
+ { gk104_grctx_init_pes_0 },
+ { gk110_grctx_init_cbm_0 },
+ { gf117_grctx_init_wwdx_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk110_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xf0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gk104_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gk110_grctx_pack_hub,
+ .gpc = gk110_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gk110_grctx_pack_tpc,
+ .ppc = gk110_grctx_pack_ppc,
+ .icmd = gk110_grctx_pack_icmd,
+ .mthd = gk110_grctx_pack_mthd,
+ .bundle = gk104_grctx_generate_bundle,
+ .bundle_size = 0x3000,
+ .bundle_min_gpm_fifo_depth = 0x180,
+ .bundle_token_limit = 0x7c0,
+ .pagepool = gk104_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf117_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x7ff,
+ .alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
new file mode 100644
index 000000000000..b11c26794fde
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk110b.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk110b_grctx_init_sm_0[] = {
+ { 0x419e04, 1, 0x04, 0x00000000 },
+ { 0x419e08, 1, 0x04, 0x0000001d },
+ { 0x419e0c, 1, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00001c02 },
+ { 0x419e44, 1, 0x04, 0x0013eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 2, 0x04, 0x00000000 },
+ { 0x419e58, 1, 0x04, 0x00000001 },
+ { 0x419e5c, 3, 0x04, 0x00000000 },
+ { 0x419e68, 1, 0x04, 0x00000002 },
+ { 0x419e6c, 12, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x00001f8f },
+ { 0x419eb0, 1, 0x04, 0x0db00d2f },
+ { 0x419eb8, 1, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0001304f },
+ { 0x419f30, 4, 0x04, 0x00000000 },
+ { 0x419f40, 1, 0x04, 0x00000018 },
+ { 0x419f44, 3, 0x04, 0x00000000 },
+ { 0x419f58, 1, 0x04, 0x00000000 },
+ { 0x419f70, 1, 0x04, 0x00006300 },
+ { 0x419f78, 1, 0x04, 0x000000eb },
+ { 0x419f7c, 1, 0x04, 0x00000404 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk110b_grctx_pack_tpc[] = {
+ { gf117_grctx_init_pe_0 },
+ { gk110_grctx_init_tex_0 },
+ { gk110_grctx_init_mpc_0 },
+ { gk110_grctx_init_l1c_0 },
+ { gk110b_grctx_init_sm_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk110b_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xf1),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gk104_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gk110_grctx_pack_hub,
+ .gpc = gk110_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gk110b_grctx_pack_tpc,
+ .ppc = gk110_grctx_pack_ppc,
+ .icmd = gk110_grctx_pack_icmd,
+ .mthd = gk110_grctx_pack_mthd,
+ .bundle = gk104_grctx_generate_bundle,
+ .bundle_size = 0x3000,
+ .bundle_min_gpm_fifo_depth = 0x180,
+ .bundle_token_limit = 0x600,
+ .pagepool = gk104_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf117_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x7ff,
+ .alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
new file mode 100644
index 000000000000..6e8ce9fc311a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk208.c
@@ -0,0 +1,564 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk208_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000b1, 1, 0x01, 0x00000001 },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002ec, 1, 0x01, 0x00000001 },
+ { 0x0002f2, 2, 0x01, 0x00000001 },
+ { 0x0002f5, 1, 0x01, 0x00000001 },
+ { 0x0002f7, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x000375, 1, 0x01, 0x00000001 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000383, 1, 0x01, 0x00000011 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000662, 1, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x00080b, 1, 0x01, 0x00000002 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000937, 1, 0x01, 0x00000001 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000979, 1, 0x01, 0x00000003 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000a0d, 1, 0x01, 0x00000006 },
+ { 0x00097d, 1, 0x01, 0x00000020 },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000685, 1, 0x01, 0x003fffff },
+ { 0x000687, 1, 0x01, 0x003fffff },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00400008 },
+ { 0x000841, 1, 0x01, 0x08000080 },
+ { 0x000842, 1, 0x01, 0x00400008 },
+ { 0x000843, 1, 0x01, 0x08000080 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000008 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x00c500, 1, 0x01, 0x00000003 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_icmd[] = {
+ { gk208_grctx_init_icmd_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_fe_0[] = {
+ { 0x404004, 8, 0x04, 0x00000000 },
+ { 0x404024, 1, 0x04, 0x0000e000 },
+ { 0x404028, 8, 0x04, 0x00000000 },
+ { 0x4040a8, 8, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf800008f },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040e8, 1, 0x04, 0x00001000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404100, 10, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404138, 1, 0x04, 0x20000040 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000055 },
+ { 0x40417c, 2, 0x04, 0x00000000 },
+ { 0x404194, 1, 0x04, 0x01000700 },
+ { 0x4041a0, 4, 0x04, 0x00000000 },
+ { 0x404200, 1, 0x04, 0x0000a197 },
+ { 0x404204, 1, 0x04, 0x0000a1c0 },
+ { 0x404208, 1, 0x04, 0x0000a140 },
+ { 0x40420c, 1, 0x04, 0x0000902d },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x0f8000bf },
+ { 0x405830, 1, 0x04, 0x02180648 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ { 0x405a1c, 1, 0x04, 0x000000ff },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x034103c1 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b0, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x802000f0 },
+ { 0x4064c4, 1, 0x04, 0x0192ffff },
+ { 0x4064c8, 1, 0x04, 0x00c20200 },
+ { 0x4064cc, 9, 0x04, 0x00000000 },
+ { 0x4064fc, 1, 0x04, 0x0000022a },
+ {}
+};
+
+const struct gf100_gr_init
+gk208_grctx_init_rstr2d_0[] = {
+ { 0x407804, 1, 0x04, 0x00000063 },
+ { 0x40780c, 1, 0x04, 0x0a418820 },
+ { 0x407810, 1, 0x04, 0x062080e6 },
+ { 0x407814, 1, 0x04, 0x020398a4 },
+ { 0x407818, 1, 0x04, 0x0e629062 },
+ { 0x40781c, 1, 0x04, 0x0a418820 },
+ { 0x407820, 1, 0x04, 0x000000e6 },
+ { 0x4078bc, 1, 0x04, 0x00000103 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x32802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1003e005 },
+ { 0x408840, 1, 0x04, 0x0000000b },
+ { 0x408900, 1, 0x04, 0xb080b801 },
+ { 0x408904, 1, 0x04, 0x62000001 },
+ { 0x408908, 1, 0x04, 0x02c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gk208_grctx_init_fe_0 },
+ { gk110_grctx_init_pri_0 },
+ { gk104_grctx_init_memfmt_0 },
+ { gk208_grctx_init_ds_0 },
+ { gk110_grctx_init_cwd_0 },
+ { gk208_grctx_init_pd_0 },
+ { gk208_grctx_init_rstr2d_0 },
+ { gk104_grctx_init_scc_0 },
+ { gk208_grctx_init_be_0 },
+ {}
+};
+
+const struct gf100_gr_init
+gk208_grctx_init_prop_0[] = {
+ { 0x418400, 1, 0x04, 0x38005e00 },
+ { 0x418404, 1, 0x04, 0x71e0ffff },
+ { 0x41840c, 1, 0x04, 0x00001008 },
+ { 0x418410, 1, 0x04, 0x0fff0fff },
+ { 0x418414, 1, 0x04, 0x02200fff },
+ { 0x418450, 6, 0x04, 0x00000000 },
+ { 0x418468, 1, 0x04, 0x00000001 },
+ { 0x41846c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_gpc_unk_1[] = {
+ { 0x418600, 1, 0x04, 0x0000007f },
+ { 0x418684, 1, 0x04, 0x0000001f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 2, 0x04, 0x00000080 },
+ { 0x41870c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x7006863a },
+ { 0x418808, 1, 0x04, 0x00000000 },
+ { 0x41880c, 1, 0x04, 0x00000030 },
+ { 0x418810, 1, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00000044 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100058 },
+ {}
+};
+
+const struct gf100_gr_init
+gk208_grctx_init_crstr_0[] = {
+ { 0x418b00, 1, 0x04, 0x0000001e },
+ { 0x418b08, 1, 0x04, 0x0a418820 },
+ { 0x418b0c, 1, 0x04, 0x062080e6 },
+ { 0x418b10, 1, 0x04, 0x020398a4 },
+ { 0x418b14, 1, 0x04, 0x0e629062 },
+ { 0x418b18, 1, 0x04, 0x0a418820 },
+ { 0x418b1c, 1, 0x04, 0x000000e6 },
+ { 0x418bb8, 1, 0x04, 0x00000103 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_gpm_0[] = {
+ { 0x418c08, 1, 0x04, 0x00000001 },
+ { 0x418c10, 8, 0x04, 0x00000000 },
+ { 0x418c40, 1, 0x04, 0xffffffff },
+ { 0x418c6c, 1, 0x04, 0x00000001 },
+ { 0x418c80, 1, 0x04, 0x2020000c },
+ { 0x418c8c, 1, 0x04, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_gpc[] = {
+ { gf100_grctx_init_gpc_unk_0 },
+ { gk208_grctx_init_prop_0 },
+ { gk208_grctx_init_gpc_unk_1 },
+ { gk208_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gk208_grctx_init_crstr_0 },
+ { gk208_grctx_init_gpm_0 },
+ { gk110_grctx_init_gpc_unk_2 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000100f0 },
+ { 0x419a04, 1, 0x04, 0x00000001 },
+ { 0x419a08, 1, 0x04, 0x00000421 },
+ { 0x419a0c, 1, 0x04, 0x00120000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00000200 },
+ { 0x419a1c, 1, 0x04, 0x0000c000 },
+ { 0x419a20, 1, 0x04, 0x00000800 },
+ { 0x419a30, 1, 0x04, 0x00000001 },
+ { 0x419ac4, 1, 0x04, 0x0037f440 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_sm_0[] = {
+ { 0x419e04, 1, 0x04, 0x00000000 },
+ { 0x419e08, 1, 0x04, 0x0000001d },
+ { 0x419e0c, 1, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00001c02 },
+ { 0x419e44, 1, 0x04, 0x0013eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 2, 0x04, 0x00000000 },
+ { 0x419e58, 1, 0x04, 0x00000001 },
+ { 0x419e5c, 3, 0x04, 0x00000000 },
+ { 0x419e68, 1, 0x04, 0x00000002 },
+ { 0x419e6c, 12, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x00001f8f },
+ { 0x419eb0, 1, 0x04, 0x0db00d2f },
+ { 0x419eb8, 1, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0001304f },
+ { 0x419f30, 4, 0x04, 0x00000000 },
+ { 0x419f40, 1, 0x04, 0x00000018 },
+ { 0x419f44, 3, 0x04, 0x00000000 },
+ { 0x419f58, 1, 0x04, 0x00000020 },
+ { 0x419f70, 1, 0x04, 0x00000000 },
+ { 0x419f78, 1, 0x04, 0x000001eb },
+ { 0x419f7c, 1, 0x04, 0x00000404 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_tpc[] = {
+ { gf117_grctx_init_pe_0 },
+ { gk208_grctx_init_tex_0 },
+ { gk110_grctx_init_mpc_0 },
+ { gk110_grctx_init_l1c_0 },
+ { gk208_grctx_init_sm_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_grctx_init_cbm_0[] = {
+ { 0x41bec0, 1, 0x04, 0x10000000 },
+ { 0x41bec4, 1, 0x04, 0x00037f7f },
+ { 0x41bee4, 1, 0x04, 0x00000000 },
+ { 0x41bef0, 1, 0x04, 0x000003ff },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk208_grctx_pack_ppc[] = {
+ { gk104_grctx_init_pes_0 },
+ { gk208_grctx_init_cbm_0 },
+ { gf117_grctx_init_wwdx_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk208_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0x08),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gk104_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gk208_grctx_pack_hub,
+ .gpc = gk208_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gk208_grctx_pack_tpc,
+ .ppc = gk208_grctx_pack_ppc,
+ .icmd = gk208_grctx_pack_icmd,
+ .mthd = gk110_grctx_pack_mthd,
+ .bundle = gk104_grctx_generate_bundle,
+ .bundle_size = 0x3000,
+ .bundle_min_gpm_fifo_depth = 0xc2,
+ .bundle_token_limit = 0x200,
+ .pagepool = gk104_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf117_grctx_generate_attrib,
+ .attrib_nr_max = 0x324,
+ .attrib_nr = 0x218,
+ .alpha_nr_max = 0x7ff,
+ .alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
new file mode 100644
index 000000000000..2f241f6f0f0a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgk20a.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "ctxgf100.h"
+
+static const struct gf100_gr_pack
+gk20a_grctx_pack_mthd[] = {
+ { gk104_grctx_init_a097_0, 0xa297 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ {}
+};
+
+struct nvkm_oclass *
+gk20a_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0xea),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gk104_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gk104_grctx_pack_hub,
+ .gpc = gk104_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gk104_grctx_pack_tpc,
+ .ppc = gk104_grctx_pack_ppc,
+ .icmd = gk104_grctx_pack_icmd,
+ .mthd = gk20a_grctx_pack_mthd,
+ .bundle = gk104_grctx_generate_bundle,
+ .bundle_size = 0x1800,
+ .bundle_min_gpm_fifo_depth = 0x62,
+ .bundle_token_limit = 0x100,
+ .pagepool = gk104_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gf117_grctx_generate_attrib,
+ .attrib_nr_max = 0x240,
+ .attrib_nr = 0x240,
+ .alpha_nr_max = 0x648 + (0x648 / 2),
+ .alpha_nr = 0x648,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
new file mode 100644
index 000000000000..956f4dce960c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxgm107.c
@@ -0,0 +1,1034 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "ctxgf100.h"
+
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+
+/*******************************************************************************
+ * PGRAPH context register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gm107_grctx_init_icmd_0[] = {
+ { 0x001000, 1, 0x01, 0x00000004 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x0000a9, 1, 0x01, 0x0000ffff },
+ { 0x000038, 1, 0x01, 0x0fac6881 },
+ { 0x00003d, 1, 0x01, 0x00000001 },
+ { 0x0000e8, 8, 0x01, 0x00000400 },
+ { 0x000078, 8, 0x01, 0x00000300 },
+ { 0x000050, 1, 0x01, 0x00000011 },
+ { 0x000058, 8, 0x01, 0x00000008 },
+ { 0x000208, 8, 0x01, 0x00000001 },
+ { 0x000081, 1, 0x01, 0x00000001 },
+ { 0x000085, 1, 0x01, 0x00000004 },
+ { 0x000088, 1, 0x01, 0x00000400 },
+ { 0x000090, 1, 0x01, 0x00000300 },
+ { 0x000098, 1, 0x01, 0x00001001 },
+ { 0x0000e3, 1, 0x01, 0x00000001 },
+ { 0x0000da, 1, 0x01, 0x00000001 },
+ { 0x0000f8, 1, 0x01, 0x00000003 },
+ { 0x0000fa, 1, 0x01, 0x00000001 },
+ { 0x0000b1, 2, 0x01, 0x00000001 },
+ { 0x00009f, 4, 0x01, 0x0000ffff },
+ { 0x0000a8, 1, 0x01, 0x0000ffff },
+ { 0x0000ad, 1, 0x01, 0x0000013e },
+ { 0x0000e1, 1, 0x01, 0x00000010 },
+ { 0x000290, 16, 0x01, 0x00000000 },
+ { 0x0003b0, 16, 0x01, 0x00000000 },
+ { 0x0002a0, 16, 0x01, 0x00000000 },
+ { 0x000420, 16, 0x01, 0x00000000 },
+ { 0x0002b0, 16, 0x01, 0x00000000 },
+ { 0x000430, 16, 0x01, 0x00000000 },
+ { 0x0002c0, 16, 0x01, 0x00000000 },
+ { 0x0004d0, 16, 0x01, 0x00000000 },
+ { 0x000720, 16, 0x01, 0x00000000 },
+ { 0x0008c0, 16, 0x01, 0x00000000 },
+ { 0x000890, 16, 0x01, 0x00000000 },
+ { 0x0008e0, 16, 0x01, 0x00000000 },
+ { 0x0008a0, 16, 0x01, 0x00000000 },
+ { 0x0008f0, 16, 0x01, 0x00000000 },
+ { 0x00094c, 1, 0x01, 0x000000ff },
+ { 0x00094d, 1, 0x01, 0xffffffff },
+ { 0x00094e, 1, 0x01, 0x00000002 },
+ { 0x0002f2, 2, 0x01, 0x00000001 },
+ { 0x0002f5, 1, 0x01, 0x00000001 },
+ { 0x0002f7, 1, 0x01, 0x00000001 },
+ { 0x000303, 1, 0x01, 0x00000001 },
+ { 0x0002e6, 1, 0x01, 0x00000001 },
+ { 0x000466, 1, 0x01, 0x00000052 },
+ { 0x000301, 1, 0x01, 0x3f800000 },
+ { 0x000304, 1, 0x01, 0x30201000 },
+ { 0x000305, 1, 0x01, 0x70605040 },
+ { 0x000306, 1, 0x01, 0xb8a89888 },
+ { 0x000307, 1, 0x01, 0xf8e8d8c8 },
+ { 0x00030a, 1, 0x01, 0x00ffff00 },
+ { 0x0000de, 1, 0x01, 0x00000001 },
+ { 0x00030b, 1, 0x01, 0x0000001a },
+ { 0x00030c, 1, 0x01, 0x00000001 },
+ { 0x000318, 1, 0x01, 0x00000001 },
+ { 0x000340, 1, 0x01, 0x00000000 },
+ { 0x00037d, 1, 0x01, 0x00000006 },
+ { 0x0003a0, 1, 0x01, 0x00000002 },
+ { 0x0003aa, 1, 0x01, 0x00000001 },
+ { 0x0003a9, 1, 0x01, 0x00000001 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000383, 1, 0x01, 0x00000011 },
+ { 0x000360, 1, 0x01, 0x00000040 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x00037a, 1, 0x01, 0x00000012 },
+ { 0x000619, 1, 0x01, 0x00000003 },
+ { 0x000811, 1, 0x01, 0x00000003 },
+ { 0x000812, 1, 0x01, 0x00000004 },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000815, 1, 0x01, 0x0000000b },
+ { 0x000800, 6, 0x01, 0x00000001 },
+ { 0x000632, 1, 0x01, 0x00000001 },
+ { 0x000633, 1, 0x01, 0x00000002 },
+ { 0x000634, 1, 0x01, 0x00000003 },
+ { 0x000635, 1, 0x01, 0x00000004 },
+ { 0x000654, 1, 0x01, 0x3f800000 },
+ { 0x000657, 1, 0x01, 0x3f800000 },
+ { 0x000655, 2, 0x01, 0x3f800000 },
+ { 0x0006cd, 1, 0x01, 0x3f800000 },
+ { 0x0007f5, 1, 0x01, 0x3f800000 },
+ { 0x0007dc, 1, 0x01, 0x39291909 },
+ { 0x0007dd, 1, 0x01, 0x79695949 },
+ { 0x0007de, 1, 0x01, 0xb9a99989 },
+ { 0x0007df, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007e8, 1, 0x01, 0x00003210 },
+ { 0x0007e9, 1, 0x01, 0x00007654 },
+ { 0x0007ea, 1, 0x01, 0x00000098 },
+ { 0x0007ec, 1, 0x01, 0x39291909 },
+ { 0x0007ed, 1, 0x01, 0x79695949 },
+ { 0x0007ee, 1, 0x01, 0xb9a99989 },
+ { 0x0007ef, 1, 0x01, 0xf9e9d9c9 },
+ { 0x0007f0, 1, 0x01, 0x00003210 },
+ { 0x0007f1, 1, 0x01, 0x00007654 },
+ { 0x0007f2, 1, 0x01, 0x00000098 },
+ { 0x0005a5, 1, 0x01, 0x00000001 },
+ { 0x0005d0, 1, 0x01, 0x20181008 },
+ { 0x0005d1, 1, 0x01, 0x40383028 },
+ { 0x0005d2, 1, 0x01, 0x60585048 },
+ { 0x0005d3, 1, 0x01, 0x80787068 },
+ { 0x000980, 128, 0x01, 0x00000000 },
+ { 0x000468, 1, 0x01, 0x00000004 },
+ { 0x00046c, 1, 0x01, 0x00000001 },
+ { 0x000470, 96, 0x01, 0x00000000 },
+ { 0x000510, 16, 0x01, 0x3f800000 },
+ { 0x000520, 1, 0x01, 0x000002b6 },
+ { 0x000529, 1, 0x01, 0x00000001 },
+ { 0x000530, 16, 0x01, 0xffff0000 },
+ { 0x000550, 32, 0x01, 0xffff0000 },
+ { 0x000585, 1, 0x01, 0x0000003f },
+ { 0x000576, 1, 0x01, 0x00000003 },
+ { 0x00057b, 1, 0x01, 0x00000059 },
+ { 0x000586, 1, 0x01, 0x00000040 },
+ { 0x000582, 2, 0x01, 0x00000080 },
+ { 0x000595, 1, 0x01, 0x00400040 },
+ { 0x000596, 1, 0x01, 0x00000492 },
+ { 0x000597, 1, 0x01, 0x08080203 },
+ { 0x0005ad, 1, 0x01, 0x00000008 },
+ { 0x000598, 1, 0x01, 0x00020001 },
+ { 0x0005c2, 1, 0x01, 0x00000001 },
+ { 0x000638, 2, 0x01, 0x00000001 },
+ { 0x00063a, 1, 0x01, 0x00000002 },
+ { 0x00063b, 2, 0x01, 0x00000001 },
+ { 0x00063d, 1, 0x01, 0x00000002 },
+ { 0x00063e, 1, 0x01, 0x00000001 },
+ { 0x0008b8, 8, 0x01, 0x00000001 },
+ { 0x000900, 8, 0x01, 0x00000001 },
+ { 0x000908, 8, 0x01, 0x00000002 },
+ { 0x000910, 16, 0x01, 0x00000001 },
+ { 0x000920, 8, 0x01, 0x00000002 },
+ { 0x000928, 8, 0x01, 0x00000001 },
+ { 0x000662, 1, 0x01, 0x00000001 },
+ { 0x000648, 9, 0x01, 0x00000001 },
+ { 0x000658, 1, 0x01, 0x0000000f },
+ { 0x0007ff, 1, 0x01, 0x0000000a },
+ { 0x00066a, 1, 0x01, 0x40000000 },
+ { 0x00066b, 1, 0x01, 0x10000000 },
+ { 0x00066c, 2, 0x01, 0xffff0000 },
+ { 0x0007af, 2, 0x01, 0x00000008 },
+ { 0x0007f6, 1, 0x01, 0x00000001 },
+ { 0x0006b2, 1, 0x01, 0x00000055 },
+ { 0x0007ad, 1, 0x01, 0x00000003 },
+ { 0x000971, 1, 0x01, 0x00000008 },
+ { 0x000972, 1, 0x01, 0x00000040 },
+ { 0x000973, 1, 0x01, 0x0000012c },
+ { 0x00097c, 1, 0x01, 0x00000040 },
+ { 0x000975, 1, 0x01, 0x00000020 },
+ { 0x000976, 1, 0x01, 0x00000001 },
+ { 0x000977, 1, 0x01, 0x00000020 },
+ { 0x000978, 1, 0x01, 0x00000001 },
+ { 0x000957, 1, 0x01, 0x00000003 },
+ { 0x00095e, 1, 0x01, 0x20164010 },
+ { 0x00095f, 1, 0x01, 0x00000020 },
+ { 0x000a0d, 1, 0x01, 0x00000006 },
+ { 0x00097d, 1, 0x01, 0x0000000c },
+ { 0x000683, 1, 0x01, 0x00000006 },
+ { 0x000687, 1, 0x01, 0x003fffff },
+ { 0x0006a0, 1, 0x01, 0x00000005 },
+ { 0x000840, 1, 0x01, 0x00400008 },
+ { 0x000841, 1, 0x01, 0x08000080 },
+ { 0x000842, 1, 0x01, 0x00400008 },
+ { 0x000843, 1, 0x01, 0x08000080 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ab, 1, 0x01, 0x00000002 },
+ { 0x0006ac, 1, 0x01, 0x00000080 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x0006bb, 1, 0x01, 0x000000cf },
+ { 0x0006ce, 1, 0x01, 0x2a712488 },
+ { 0x000739, 1, 0x01, 0x4085c000 },
+ { 0x00073a, 1, 0x01, 0x00000080 },
+ { 0x000786, 1, 0x01, 0x80000100 },
+ { 0x00073c, 1, 0x01, 0x00010100 },
+ { 0x00073d, 1, 0x01, 0x02800000 },
+ { 0x000787, 1, 0x01, 0x000000cf },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x000836, 1, 0x01, 0x00000001 },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x000833, 1, 0x01, 0x04444480 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c1b0, 8, 0x01, 0x0000000f },
+ { 0x00c1b8, 1, 0x01, 0x0fac6881 },
+ { 0x00c1b9, 1, 0x01, 0x00fac688 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000002 },
+ { 0x0006aa, 1, 0x01, 0x00000001 },
+ { 0x0006ad, 2, 0x01, 0x00000100 },
+ { 0x0006b1, 1, 0x01, 0x00000011 },
+ { 0x00078c, 1, 0x01, 0x00000008 },
+ { 0x000792, 1, 0x01, 0x00000001 },
+ { 0x000794, 3, 0x01, 0x00000001 },
+ { 0x000797, 1, 0x01, 0x000000cf },
+ { 0x00079a, 1, 0x01, 0x00000002 },
+ { 0x0007a1, 1, 0x01, 0x00000001 },
+ { 0x0007a3, 3, 0x01, 0x00000001 },
+ { 0x000831, 1, 0x01, 0x00000004 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000008 },
+ { 0x000039, 3, 0x01, 0x00000000 },
+ { 0x000380, 1, 0x01, 0x00000001 },
+ { 0x000366, 2, 0x01, 0x00000000 },
+ { 0x000368, 1, 0x01, 0x00000fff },
+ { 0x000370, 2, 0x01, 0x00000000 },
+ { 0x000372, 1, 0x01, 0x000fffff },
+ { 0x000813, 1, 0x01, 0x00000006 },
+ { 0x000814, 1, 0x01, 0x00000008 },
+ { 0x000818, 8, 0x01, 0x00000000 },
+ { 0x000848, 16, 0x01, 0x00000000 },
+ { 0x000738, 1, 0x01, 0x00000000 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x000a04, 1, 0x01, 0x000000ff },
+ { 0x000a0b, 1, 0x01, 0x00000040 },
+ { 0x00097f, 1, 0x01, 0x00000100 },
+ { 0x000a02, 1, 0x01, 0x00000001 },
+ { 0x000809, 1, 0x01, 0x00000007 },
+ { 0x00c221, 1, 0x01, 0x00000040 },
+ { 0x00c401, 1, 0x01, 0x00000001 },
+ { 0x00c402, 1, 0x01, 0x00010001 },
+ { 0x00c403, 2, 0x01, 0x00000001 },
+ { 0x00c40e, 1, 0x01, 0x00000020 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ { 0x001000, 1, 0x01, 0x00000001 },
+ { 0x000b07, 1, 0x01, 0x00000002 },
+ { 0x000b08, 2, 0x01, 0x00000100 },
+ { 0x000b0a, 1, 0x01, 0x00000001 },
+ { 0x01e100, 1, 0x01, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_icmd[] = {
+ { gm107_grctx_init_icmd_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_b097_0[] = {
+ { 0x000800, 8, 0x40, 0x00000000 },
+ { 0x000804, 8, 0x40, 0x00000000 },
+ { 0x000808, 8, 0x40, 0x00000400 },
+ { 0x00080c, 8, 0x40, 0x00000300 },
+ { 0x000810, 1, 0x04, 0x000000cf },
+ { 0x000850, 7, 0x40, 0x00000000 },
+ { 0x000814, 8, 0x40, 0x00000040 },
+ { 0x000818, 8, 0x40, 0x00000001 },
+ { 0x00081c, 8, 0x40, 0x00000000 },
+ { 0x000820, 8, 0x40, 0x00000000 },
+ { 0x001c00, 16, 0x10, 0x00000000 },
+ { 0x001c04, 16, 0x10, 0x00000000 },
+ { 0x001c08, 16, 0x10, 0x00000000 },
+ { 0x001c0c, 16, 0x10, 0x00000000 },
+ { 0x001d00, 16, 0x10, 0x00000000 },
+ { 0x001d04, 16, 0x10, 0x00000000 },
+ { 0x001d08, 16, 0x10, 0x00000000 },
+ { 0x001d0c, 16, 0x10, 0x00000000 },
+ { 0x001f00, 16, 0x08, 0x00000000 },
+ { 0x001f04, 16, 0x08, 0x00000000 },
+ { 0x001f80, 16, 0x08, 0x00000000 },
+ { 0x001f84, 16, 0x08, 0x00000000 },
+ { 0x002000, 1, 0x04, 0x00000000 },
+ { 0x002040, 1, 0x04, 0x00000011 },
+ { 0x002080, 1, 0x04, 0x00000020 },
+ { 0x0020c0, 1, 0x04, 0x00000030 },
+ { 0x002100, 1, 0x04, 0x00000040 },
+ { 0x002140, 1, 0x04, 0x00000051 },
+ { 0x00200c, 6, 0x40, 0x00000001 },
+ { 0x002010, 1, 0x04, 0x00000000 },
+ { 0x002050, 1, 0x04, 0x00000000 },
+ { 0x002090, 1, 0x04, 0x00000001 },
+ { 0x0020d0, 1, 0x04, 0x00000002 },
+ { 0x002110, 1, 0x04, 0x00000003 },
+ { 0x002150, 1, 0x04, 0x00000004 },
+ { 0x000380, 4, 0x20, 0x00000000 },
+ { 0x000384, 4, 0x20, 0x00000000 },
+ { 0x000388, 4, 0x20, 0x00000000 },
+ { 0x00038c, 4, 0x20, 0x00000000 },
+ { 0x000700, 4, 0x10, 0x00000000 },
+ { 0x000704, 4, 0x10, 0x00000000 },
+ { 0x000708, 4, 0x10, 0x00000000 },
+ { 0x002800, 128, 0x04, 0x00000000 },
+ { 0x000a00, 16, 0x20, 0x00000000 },
+ { 0x000a04, 16, 0x20, 0x00000000 },
+ { 0x000a08, 16, 0x20, 0x00000000 },
+ { 0x000a0c, 16, 0x20, 0x00000000 },
+ { 0x000a10, 16, 0x20, 0x00000000 },
+ { 0x000a14, 16, 0x20, 0x00000000 },
+ { 0x000c00, 16, 0x10, 0x00000000 },
+ { 0x000c04, 16, 0x10, 0x00000000 },
+ { 0x000c08, 16, 0x10, 0x00000000 },
+ { 0x000c0c, 16, 0x10, 0x3f800000 },
+ { 0x000d00, 8, 0x08, 0xffff0000 },
+ { 0x000d04, 8, 0x08, 0xffff0000 },
+ { 0x000e00, 16, 0x10, 0x00000000 },
+ { 0x000e04, 16, 0x10, 0xffff0000 },
+ { 0x000e08, 16, 0x10, 0xffff0000 },
+ { 0x000d40, 4, 0x08, 0x00000000 },
+ { 0x000d44, 4, 0x08, 0x00000000 },
+ { 0x001e00, 8, 0x20, 0x00000001 },
+ { 0x001e04, 8, 0x20, 0x00000001 },
+ { 0x001e08, 8, 0x20, 0x00000002 },
+ { 0x001e0c, 8, 0x20, 0x00000001 },
+ { 0x001e10, 8, 0x20, 0x00000001 },
+ { 0x001e14, 8, 0x20, 0x00000002 },
+ { 0x001e18, 8, 0x20, 0x00000001 },
+ { 0x001480, 8, 0x10, 0x00000000 },
+ { 0x001484, 8, 0x10, 0x00000000 },
+ { 0x001488, 8, 0x10, 0x00000000 },
+ { 0x003400, 128, 0x04, 0x00000000 },
+ { 0x00030c, 1, 0x04, 0x00000001 },
+ { 0x001944, 1, 0x04, 0x00000000 },
+ { 0x001514, 1, 0x04, 0x00000000 },
+ { 0x000d68, 1, 0x04, 0x0000ffff },
+ { 0x00121c, 1, 0x04, 0x0fac6881 },
+ { 0x000fac, 1, 0x04, 0x00000001 },
+ { 0x001538, 1, 0x04, 0x00000001 },
+ { 0x000fe0, 2, 0x04, 0x00000000 },
+ { 0x000fe8, 1, 0x04, 0x00000014 },
+ { 0x000fec, 1, 0x04, 0x00000040 },
+ { 0x000ff0, 1, 0x04, 0x00000000 },
+ { 0x00179c, 1, 0x04, 0x00000000 },
+ { 0x001228, 1, 0x04, 0x00000400 },
+ { 0x00122c, 1, 0x04, 0x00000300 },
+ { 0x001230, 1, 0x04, 0x00010001 },
+ { 0x0007f8, 1, 0x04, 0x00000000 },
+ { 0x0015b4, 1, 0x04, 0x00000001 },
+ { 0x0015cc, 1, 0x04, 0x00000000 },
+ { 0x001534, 1, 0x04, 0x00000000 },
+ { 0x000754, 1, 0x04, 0x00000001 },
+ { 0x000fb0, 1, 0x04, 0x00000000 },
+ { 0x0015d0, 1, 0x04, 0x00000000 },
+ { 0x00153c, 1, 0x04, 0x00000000 },
+ { 0x0016b4, 1, 0x04, 0x00000003 },
+ { 0x000fbc, 4, 0x04, 0x0000ffff },
+ { 0x000df8, 2, 0x04, 0x00000000 },
+ { 0x001948, 1, 0x04, 0x00000000 },
+ { 0x001970, 1, 0x04, 0x00000001 },
+ { 0x00161c, 1, 0x04, 0x000009f0 },
+ { 0x000dcc, 1, 0x04, 0x00000010 },
+ { 0x0015e4, 1, 0x04, 0x00000000 },
+ { 0x001160, 32, 0x04, 0x25e00040 },
+ { 0x001880, 32, 0x04, 0x00000000 },
+ { 0x000f84, 2, 0x04, 0x00000000 },
+ { 0x0017c8, 2, 0x04, 0x00000000 },
+ { 0x0017d0, 1, 0x04, 0x000000ff },
+ { 0x0017d4, 1, 0x04, 0xffffffff },
+ { 0x0017d8, 1, 0x04, 0x00000002 },
+ { 0x0017dc, 1, 0x04, 0x00000000 },
+ { 0x0015f4, 2, 0x04, 0x00000000 },
+ { 0x001434, 2, 0x04, 0x00000000 },
+ { 0x000d74, 1, 0x04, 0x00000000 },
+ { 0x0013a4, 1, 0x04, 0x00000000 },
+ { 0x001318, 1, 0x04, 0x00000001 },
+ { 0x001080, 2, 0x04, 0x00000000 },
+ { 0x001088, 2, 0x04, 0x00000001 },
+ { 0x001090, 1, 0x04, 0x00000000 },
+ { 0x001094, 1, 0x04, 0x00000001 },
+ { 0x001098, 1, 0x04, 0x00000000 },
+ { 0x00109c, 1, 0x04, 0x00000001 },
+ { 0x0010a0, 2, 0x04, 0x00000000 },
+ { 0x001644, 1, 0x04, 0x00000000 },
+ { 0x000748, 1, 0x04, 0x00000000 },
+ { 0x000de8, 1, 0x04, 0x00000000 },
+ { 0x001648, 1, 0x04, 0x00000000 },
+ { 0x0012a4, 1, 0x04, 0x00000000 },
+ { 0x001120, 4, 0x04, 0x00000000 },
+ { 0x001118, 1, 0x04, 0x00000000 },
+ { 0x00164c, 1, 0x04, 0x00000000 },
+ { 0x001658, 1, 0x04, 0x00000000 },
+ { 0x001910, 1, 0x04, 0x00000290 },
+ { 0x001518, 1, 0x04, 0x00000000 },
+ { 0x00165c, 1, 0x04, 0x00000001 },
+ { 0x001520, 1, 0x04, 0x00000000 },
+ { 0x001604, 1, 0x04, 0x00000000 },
+ { 0x001570, 1, 0x04, 0x00000000 },
+ { 0x0013b0, 2, 0x04, 0x3f800000 },
+ { 0x00020c, 1, 0x04, 0x00000000 },
+ { 0x001670, 1, 0x04, 0x30201000 },
+ { 0x001674, 1, 0x04, 0x70605040 },
+ { 0x001678, 1, 0x04, 0xb8a89888 },
+ { 0x00167c, 1, 0x04, 0xf8e8d8c8 },
+ { 0x00166c, 1, 0x04, 0x00000000 },
+ { 0x001680, 1, 0x04, 0x00ffff00 },
+ { 0x0012d0, 1, 0x04, 0x00000003 },
+ { 0x0012d4, 1, 0x04, 0x00000002 },
+ { 0x001684, 2, 0x04, 0x00000000 },
+ { 0x000dac, 2, 0x04, 0x00001b02 },
+ { 0x000db4, 1, 0x04, 0x00000000 },
+ { 0x00168c, 1, 0x04, 0x00000000 },
+ { 0x0015bc, 1, 0x04, 0x00000000 },
+ { 0x00156c, 1, 0x04, 0x00000000 },
+ { 0x00187c, 1, 0x04, 0x00000000 },
+ { 0x001110, 1, 0x04, 0x00000001 },
+ { 0x000dc0, 3, 0x04, 0x00000000 },
+ { 0x000f40, 5, 0x04, 0x00000000 },
+ { 0x001234, 1, 0x04, 0x00000000 },
+ { 0x001690, 1, 0x04, 0x00000000 },
+ { 0x000790, 5, 0x04, 0x00000000 },
+ { 0x00077c, 1, 0x04, 0x00000000 },
+ { 0x001000, 1, 0x04, 0x00000010 },
+ { 0x0010fc, 1, 0x04, 0x00000000 },
+ { 0x001290, 1, 0x04, 0x00000000 },
+ { 0x000218, 1, 0x04, 0x00000010 },
+ { 0x0012d8, 1, 0x04, 0x00000000 },
+ { 0x0012dc, 1, 0x04, 0x00000010 },
+ { 0x000d94, 1, 0x04, 0x00000001 },
+ { 0x00155c, 2, 0x04, 0x00000000 },
+ { 0x001564, 1, 0x04, 0x00000fff },
+ { 0x001574, 2, 0x04, 0x00000000 },
+ { 0x00157c, 1, 0x04, 0x000fffff },
+ { 0x001354, 1, 0x04, 0x00000000 },
+ { 0x001610, 1, 0x04, 0x00000012 },
+ { 0x001608, 2, 0x04, 0x00000000 },
+ { 0x00260c, 1, 0x04, 0x00000000 },
+ { 0x0007ac, 1, 0x04, 0x00000000 },
+ { 0x00162c, 1, 0x04, 0x00000003 },
+ { 0x000210, 1, 0x04, 0x00000000 },
+ { 0x000320, 1, 0x04, 0x00000000 },
+ { 0x000324, 6, 0x04, 0x3f800000 },
+ { 0x000750, 1, 0x04, 0x00000000 },
+ { 0x000760, 1, 0x04, 0x39291909 },
+ { 0x000764, 1, 0x04, 0x79695949 },
+ { 0x000768, 1, 0x04, 0xb9a99989 },
+ { 0x00076c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x000770, 1, 0x04, 0x30201000 },
+ { 0x000774, 1, 0x04, 0x70605040 },
+ { 0x000778, 1, 0x04, 0x00009080 },
+ { 0x000780, 1, 0x04, 0x39291909 },
+ { 0x000784, 1, 0x04, 0x79695949 },
+ { 0x000788, 1, 0x04, 0xb9a99989 },
+ { 0x00078c, 1, 0x04, 0xf9e9d9c9 },
+ { 0x0007d0, 1, 0x04, 0x30201000 },
+ { 0x0007d4, 1, 0x04, 0x70605040 },
+ { 0x0007d8, 1, 0x04, 0x00009080 },
+ { 0x00037c, 1, 0x04, 0x00000001 },
+ { 0x000740, 2, 0x04, 0x00000000 },
+ { 0x002600, 1, 0x04, 0x00000000 },
+ { 0x001918, 1, 0x04, 0x00000000 },
+ { 0x00191c, 1, 0x04, 0x00000900 },
+ { 0x001920, 1, 0x04, 0x00000405 },
+ { 0x001308, 1, 0x04, 0x00000001 },
+ { 0x001924, 1, 0x04, 0x00000000 },
+ { 0x0013ac, 1, 0x04, 0x00000000 },
+ { 0x00192c, 1, 0x04, 0x00000001 },
+ { 0x00193c, 1, 0x04, 0x00002c1c },
+ { 0x000d7c, 1, 0x04, 0x00000000 },
+ { 0x000f8c, 1, 0x04, 0x00000000 },
+ { 0x0002c0, 1, 0x04, 0x00000001 },
+ { 0x001510, 1, 0x04, 0x00000000 },
+ { 0x001940, 1, 0x04, 0x00000000 },
+ { 0x000ff4, 2, 0x04, 0x00000000 },
+ { 0x00194c, 2, 0x04, 0x00000000 },
+ { 0x001968, 1, 0x04, 0x00000000 },
+ { 0x001590, 1, 0x04, 0x0000003f },
+ { 0x0007e8, 4, 0x04, 0x00000000 },
+ { 0x00196c, 1, 0x04, 0x00000011 },
+ { 0x0002e4, 1, 0x04, 0x0000b001 },
+ { 0x00036c, 2, 0x04, 0x00000000 },
+ { 0x00197c, 1, 0x04, 0x00000000 },
+ { 0x000fcc, 2, 0x04, 0x00000000 },
+ { 0x0002d8, 1, 0x04, 0x00000040 },
+ { 0x001980, 1, 0x04, 0x00000080 },
+ { 0x001504, 1, 0x04, 0x00000080 },
+ { 0x001984, 1, 0x04, 0x00000000 },
+ { 0x000f60, 1, 0x04, 0x00000000 },
+ { 0x000f64, 1, 0x04, 0x00400040 },
+ { 0x000f68, 1, 0x04, 0x00002212 },
+ { 0x000f6c, 1, 0x04, 0x08080203 },
+ { 0x001108, 1, 0x04, 0x00000008 },
+ { 0x000f70, 1, 0x04, 0x00080001 },
+ { 0x000ffc, 1, 0x04, 0x00000000 },
+ { 0x000300, 1, 0x04, 0x00000001 },
+ { 0x0013a8, 1, 0x04, 0x00000000 },
+ { 0x0012ec, 1, 0x04, 0x00000000 },
+ { 0x001310, 1, 0x04, 0x00000000 },
+ { 0x001314, 1, 0x04, 0x00000001 },
+ { 0x001380, 1, 0x04, 0x00000000 },
+ { 0x001384, 4, 0x04, 0x00000001 },
+ { 0x001394, 1, 0x04, 0x00000000 },
+ { 0x00139c, 1, 0x04, 0x00000000 },
+ { 0x001398, 1, 0x04, 0x00000000 },
+ { 0x001594, 1, 0x04, 0x00000000 },
+ { 0x001598, 4, 0x04, 0x00000001 },
+ { 0x000f54, 3, 0x04, 0x00000000 },
+ { 0x0019bc, 1, 0x04, 0x00000000 },
+ { 0x000f9c, 2, 0x04, 0x00000000 },
+ { 0x0012cc, 1, 0x04, 0x00000000 },
+ { 0x0012e8, 1, 0x04, 0x00000000 },
+ { 0x00130c, 1, 0x04, 0x00000001 },
+ { 0x001360, 8, 0x04, 0x00000000 },
+ { 0x00133c, 2, 0x04, 0x00000001 },
+ { 0x001344, 1, 0x04, 0x00000002 },
+ { 0x001348, 2, 0x04, 0x00000001 },
+ { 0x001350, 1, 0x04, 0x00000002 },
+ { 0x001358, 1, 0x04, 0x00000001 },
+ { 0x0012e4, 1, 0x04, 0x00000000 },
+ { 0x00131c, 4, 0x04, 0x00000000 },
+ { 0x0019c0, 1, 0x04, 0x00000000 },
+ { 0x001140, 1, 0x04, 0x00000000 },
+ { 0x000dd0, 1, 0x04, 0x00000000 },
+ { 0x000dd4, 1, 0x04, 0x00000001 },
+ { 0x0002f4, 1, 0x04, 0x00000000 },
+ { 0x0019c4, 1, 0x04, 0x00000000 },
+ { 0x0019c8, 1, 0x04, 0x00001500 },
+ { 0x00135c, 1, 0x04, 0x00000000 },
+ { 0x000f90, 1, 0x04, 0x00000000 },
+ { 0x0019e0, 8, 0x04, 0x00000001 },
+ { 0x0019cc, 1, 0x04, 0x00000001 },
+ { 0x0015b8, 1, 0x04, 0x00000000 },
+ { 0x001a00, 1, 0x04, 0x00001111 },
+ { 0x001a04, 7, 0x04, 0x00000000 },
+ { 0x000d6c, 2, 0x04, 0xffff0000 },
+ { 0x0010f8, 1, 0x04, 0x00001010 },
+ { 0x000d80, 5, 0x04, 0x00000000 },
+ { 0x000da0, 1, 0x04, 0x00000000 },
+ { 0x0007a4, 2, 0x04, 0x00000000 },
+ { 0x001508, 1, 0x04, 0x80000000 },
+ { 0x00150c, 1, 0x04, 0x40000000 },
+ { 0x001668, 1, 0x04, 0x00000000 },
+ { 0x000318, 2, 0x04, 0x00000008 },
+ { 0x000d9c, 1, 0x04, 0x00000001 },
+ { 0x000f14, 1, 0x04, 0x00000000 },
+ { 0x000374, 1, 0x04, 0x00000000 },
+ { 0x000378, 1, 0x04, 0x0000000c },
+ { 0x0007dc, 1, 0x04, 0x00000000 },
+ { 0x00074c, 1, 0x04, 0x00000055 },
+ { 0x001420, 1, 0x04, 0x00000003 },
+ { 0x001008, 1, 0x04, 0x00000008 },
+ { 0x00100c, 1, 0x04, 0x00000040 },
+ { 0x001010, 1, 0x04, 0x0000012c },
+ { 0x000d60, 1, 0x04, 0x00000040 },
+ { 0x001018, 1, 0x04, 0x00000020 },
+ { 0x00101c, 1, 0x04, 0x00000001 },
+ { 0x001020, 1, 0x04, 0x00000020 },
+ { 0x001024, 1, 0x04, 0x00000001 },
+ { 0x001444, 3, 0x04, 0x00000000 },
+ { 0x000360, 1, 0x04, 0x20164010 },
+ { 0x000364, 1, 0x04, 0x00000020 },
+ { 0x000368, 1, 0x04, 0x00000000 },
+ { 0x000da8, 1, 0x04, 0x00000030 },
+ { 0x000de4, 1, 0x04, 0x00000000 },
+ { 0x000204, 1, 0x04, 0x00000006 },
+ { 0x0002d0, 1, 0x04, 0x003fffff },
+ { 0x001220, 1, 0x04, 0x00000005 },
+ { 0x000fdc, 1, 0x04, 0x00000000 },
+ { 0x000f98, 1, 0x04, 0x00400008 },
+ { 0x001284, 1, 0x04, 0x08000080 },
+ { 0x001450, 1, 0x04, 0x00400008 },
+ { 0x001454, 1, 0x04, 0x08000080 },
+ { 0x000214, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_mthd[] = {
+ { gm107_grctx_init_b097_0, 0xb097 },
+ { gf100_grctx_init_902d_0, 0x902d },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_fe_0[] = {
+ { 0x404004, 8, 0x04, 0x00000000 },
+ { 0x404024, 1, 0x04, 0x0000e000 },
+ { 0x404028, 8, 0x04, 0x00000000 },
+ { 0x4040a8, 8, 0x04, 0x00000000 },
+ { 0x4040c8, 1, 0x04, 0xf800008f },
+ { 0x4040d0, 6, 0x04, 0x00000000 },
+ { 0x4040f8, 1, 0x04, 0x00000000 },
+ { 0x404100, 10, 0x04, 0x00000000 },
+ { 0x404130, 2, 0x04, 0x00000000 },
+ { 0x404150, 1, 0x04, 0x0000002e },
+ { 0x404154, 1, 0x04, 0x00000400 },
+ { 0x404158, 1, 0x04, 0x00000200 },
+ { 0x404164, 1, 0x04, 0x00000045 },
+ { 0x40417c, 2, 0x04, 0x00000000 },
+ { 0x404194, 1, 0x04, 0x01000700 },
+ { 0x4041a0, 4, 0x04, 0x00000000 },
+ { 0x404200, 4, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_ds_0[] = {
+ { 0x405800, 1, 0x04, 0x0f8001bf },
+ { 0x405830, 1, 0x04, 0x0aa01000 },
+ { 0x405834, 1, 0x04, 0x08000000 },
+ { 0x405838, 1, 0x04, 0x00000000 },
+ { 0x405854, 1, 0x04, 0x00000000 },
+ { 0x405870, 4, 0x04, 0x00000001 },
+ { 0x405a00, 2, 0x04, 0x00000000 },
+ { 0x405a18, 1, 0x04, 0x00000000 },
+ { 0x405a1c, 1, 0x04, 0x000000ff },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_pd_0[] = {
+ { 0x406020, 1, 0x04, 0x07410001 },
+ { 0x406028, 4, 0x04, 0x00000001 },
+ { 0x4064a8, 1, 0x04, 0x00000000 },
+ { 0x4064ac, 1, 0x04, 0x00003fff },
+ { 0x4064b0, 3, 0x04, 0x00000000 },
+ { 0x4064c0, 1, 0x04, 0x80400280 },
+ { 0x4064c4, 1, 0x04, 0x0400ffff },
+ { 0x4064c8, 1, 0x04, 0x018001ff },
+ { 0x4064cc, 9, 0x04, 0x00000000 },
+ { 0x4064fc, 1, 0x04, 0x0000022a },
+ { 0x406500, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_be_0[] = {
+ { 0x408800, 1, 0x04, 0x32802a3c },
+ { 0x408804, 1, 0x04, 0x00000040 },
+ { 0x408808, 1, 0x04, 0x1003e005 },
+ { 0x408840, 1, 0x04, 0x0000000b },
+ { 0x408900, 1, 0x04, 0xb080b801 },
+ { 0x408904, 1, 0x04, 0x63038001 },
+ { 0x408908, 1, 0x04, 0x02c8102f },
+ { 0x408980, 1, 0x04, 0x0000011d },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_hub[] = {
+ { gf100_grctx_init_main_0 },
+ { gm107_grctx_init_fe_0 },
+ { gk110_grctx_init_pri_0 },
+ { gk104_grctx_init_memfmt_0 },
+ { gm107_grctx_init_ds_0 },
+ { gk110_grctx_init_cwd_0 },
+ { gm107_grctx_init_pd_0 },
+ { gk208_grctx_init_rstr2d_0 },
+ { gk104_grctx_init_scc_0 },
+ { gm107_grctx_init_be_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_gpc_unk_0[] = {
+ { 0x418380, 1, 0x04, 0x00000056 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_gpc_unk_1[] = {
+ { 0x418600, 1, 0x04, 0x0000007f },
+ { 0x418684, 1, 0x04, 0x0000001f },
+ { 0x418700, 1, 0x04, 0x00000002 },
+ { 0x418704, 1, 0x04, 0x00000080 },
+ { 0x418708, 1, 0x04, 0x40000000 },
+ { 0x41870c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_setup_0[] = {
+ { 0x418800, 1, 0x04, 0x7006863a },
+ { 0x418810, 1, 0x04, 0x00000000 },
+ { 0x418828, 1, 0x04, 0x00000044 },
+ { 0x418830, 1, 0x04, 0x10000001 },
+ { 0x4188d8, 1, 0x04, 0x00000008 },
+ { 0x4188e0, 1, 0x04, 0x01000000 },
+ { 0x4188e8, 5, 0x04, 0x00000000 },
+ { 0x4188fc, 1, 0x04, 0x20100058 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_gpc_unk_2[] = {
+ { 0x418d24, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x90000000 },
+ { 0x418e24, 1, 0x04, 0x00000000 },
+ { 0x418e28, 1, 0x04, 0x00000030 },
+ { 0x418e30, 1, 0x04, 0x00000000 },
+ { 0x418e34, 1, 0x04, 0x00010000 },
+ { 0x418e38, 1, 0x04, 0x00000000 },
+ { 0x418e40, 22, 0x04, 0x00000000 },
+ { 0x418ea0, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_gpc[] = {
+ { gm107_grctx_init_gpc_unk_0 },
+ { gk208_grctx_init_prop_0 },
+ { gm107_grctx_init_gpc_unk_1 },
+ { gm107_grctx_init_setup_0 },
+ { gf100_grctx_init_zcull_0 },
+ { gk208_grctx_init_crstr_0 },
+ { gk104_grctx_init_gpm_0 },
+ { gm107_grctx_init_gpc_unk_2 },
+ { gf100_grctx_init_gcc_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_tex_0[] = {
+ { 0x419a00, 1, 0x04, 0x000300f0 },
+ { 0x419a04, 1, 0x04, 0x00000005 },
+ { 0x419a08, 1, 0x04, 0x00000421 },
+ { 0x419a0c, 1, 0x04, 0x00120000 },
+ { 0x419a10, 1, 0x04, 0x00000000 },
+ { 0x419a14, 1, 0x04, 0x00002200 },
+ { 0x419a1c, 1, 0x04, 0x0000c000 },
+ { 0x419a20, 1, 0x04, 0x20008a00 },
+ { 0x419a30, 1, 0x04, 0x00000001 },
+ { 0x419a3c, 1, 0x04, 0x00000002 },
+ { 0x419ac4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_mpc_0[] = {
+ { 0x419c00, 1, 0x04, 0x0000001a },
+ { 0x419c04, 1, 0x04, 0x80000006 },
+ { 0x419c08, 1, 0x04, 0x00000002 },
+ { 0x419c20, 1, 0x04, 0x00000000 },
+ { 0x419c24, 1, 0x04, 0x00084210 },
+ { 0x419c28, 1, 0x04, 0x3efbefbe },
+ { 0x419c2c, 1, 0x04, 0x00000000 },
+ { 0x419c34, 1, 0x04, 0x01ff1ff3 },
+ { 0x419c3c, 1, 0x04, 0x00001919 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_l1c_0[] = {
+ { 0x419c84, 1, 0x04, 0x00000020 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_sm_0[] = {
+ { 0x419e04, 3, 0x04, 0x00000000 },
+ { 0x419e10, 1, 0x04, 0x00001c02 },
+ { 0x419e44, 1, 0x04, 0x00d3eff2 },
+ { 0x419e48, 1, 0x04, 0x00000000 },
+ { 0x419e4c, 1, 0x04, 0x0000007f },
+ { 0x419e50, 1, 0x04, 0x00000000 },
+ { 0x419e60, 4, 0x04, 0x00000000 },
+ { 0x419e74, 10, 0x04, 0x00000000 },
+ { 0x419eac, 1, 0x04, 0x0001cf8b },
+ { 0x419eb0, 1, 0x04, 0x00030300 },
+ { 0x419eb8, 1, 0x04, 0x00000000 },
+ { 0x419ef0, 24, 0x04, 0x00000000 },
+ { 0x419f68, 2, 0x04, 0x00000000 },
+ { 0x419f70, 1, 0x04, 0x00000020 },
+ { 0x419f78, 1, 0x04, 0x000003eb },
+ { 0x419f7c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_tpc[] = {
+ { gf117_grctx_init_pe_0 },
+ { gm107_grctx_init_tex_0 },
+ { gm107_grctx_init_mpc_0 },
+ { gm107_grctx_init_l1c_0 },
+ { gm107_grctx_init_sm_0 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_cbm_0[] = {
+ { 0x41bec0, 1, 0x04, 0x00000000 },
+ { 0x41bec4, 1, 0x04, 0x01050000 },
+ { 0x41bee4, 1, 0x04, 0x00000000 },
+ { 0x41bef0, 1, 0x04, 0x000003ff },
+ { 0x41bef4, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_grctx_init_wwdx_0[] = {
+ { 0x41bf00, 1, 0x04, 0x0a418820 },
+ { 0x41bf04, 1, 0x04, 0x062080e6 },
+ { 0x41bf08, 1, 0x04, 0x020398a4 },
+ { 0x41bf0c, 1, 0x04, 0x0e629062 },
+ { 0x41bf10, 1, 0x04, 0x0a418820 },
+ { 0x41bf14, 1, 0x04, 0x000000e6 },
+ { 0x41bfd0, 1, 0x04, 0x00900103 },
+ { 0x41bfe0, 1, 0x04, 0x80000000 },
+ { 0x41bfe4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_grctx_pack_ppc[] = {
+ { gk104_grctx_init_pes_0 },
+ { gm107_grctx_init_cbm_0 },
+ { gm107_grctx_init_wwdx_0 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context implementation
+ ******************************************************************************/
+
+static void
+gm107_grctx_generate_bundle(struct gf100_grctx *info)
+{
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+ const u32 state_limit = min(impl->bundle_min_gpm_fifo_depth,
+ impl->bundle_size / 0x20);
+ const u32 token_limit = impl->bundle_token_limit;
+ const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+ const int s = 8;
+ const int b = mmio_vram(info, impl->bundle_size, (1 << s), access);
+ mmio_refn(info, 0x408004, 0x00000000, s, b);
+ mmio_refn(info, 0x408008, 0x80000000 | (impl->bundle_size >> s), 0, b);
+ mmio_refn(info, 0x418e24, 0x00000000, s, b);
+ mmio_refn(info, 0x418e28, 0x80000000 | (impl->bundle_size >> s), 0, b);
+ mmio_wr32(info, 0x4064c8, (state_limit << 16) | token_limit);
+}
+
+static void
+gm107_grctx_generate_pagepool(struct gf100_grctx *info)
+{
+ const struct gf100_grctx_oclass *impl = gf100_grctx_impl(info->priv);
+ const u32 access = NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS;
+ const int s = 8;
+ const int b = mmio_vram(info, impl->pagepool_size, (1 << s), access);
+ mmio_refn(info, 0x40800c, 0x00000000, s, b);
+ mmio_wr32(info, 0x408010, 0x80000000);
+ mmio_refn(info, 0x419004, 0x00000000, s, b);
+ mmio_wr32(info, 0x419008, 0x00000000);
+ mmio_wr32(info, 0x4064cc, 0x80000000);
+ mmio_wr32(info, 0x418e30, 0x80000000); /* guess at it being related */
+}
+
+static void
+gm107_grctx_generate_attrib(struct gf100_grctx *info)
+{
+ struct gf100_gr_priv *priv = info->priv;
+ const struct gf100_grctx_oclass *impl = (void *)gf100_grctx_impl(priv);
+ const u32 alpha = impl->alpha_nr;
+ const u32 attrib = impl->attrib_nr;
+ const u32 size = 0x20 * (impl->attrib_nr_max + impl->alpha_nr_max);
+ const u32 access = NV_MEM_ACCESS_RW;
+ const int s = 12;
+ const int b = mmio_vram(info, size * priv->tpc_total, (1 << s), access);
+ const int max_batches = 0xffff;
+ u32 bo = 0;
+ u32 ao = bo + impl->attrib_nr_max * priv->tpc_total;
+ int gpc, ppc, n = 0;
+
+ mmio_refn(info, 0x418810, 0x80000000, s, b);
+ mmio_refn(info, 0x419848, 0x10000000, s, b);
+ mmio_refn(info, 0x419c2c, 0x10000000, s, b);
+ mmio_wr32(info, 0x405830, (attrib << 16) | alpha);
+ mmio_wr32(info, 0x4064c4, ((alpha / 4) << 16) | max_batches);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ for (ppc = 0; ppc < priv->ppc_nr[gpc]; ppc++, n++) {
+ const u32 as = alpha * priv->ppc_tpc_nr[gpc][ppc];
+ const u32 bs = attrib * priv->ppc_tpc_nr[gpc][ppc];
+ const u32 u = 0x418ea0 + (n * 0x04);
+ const u32 o = PPC_UNIT(gpc, ppc, 0);
+ mmio_wr32(info, o + 0xc0, bs);
+ mmio_wr32(info, o + 0xf4, bo);
+ bo += impl->attrib_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+ mmio_wr32(info, o + 0xe4, as);
+ mmio_wr32(info, o + 0xf8, ao);
+ ao += impl->alpha_nr_max * priv->ppc_tpc_nr[gpc][ppc];
+ mmio_wr32(info, u, (0x715 /*XXX*/ << 16) | bs);
+ }
+ }
+}
+
+static void
+gm107_grctx_generate_tpcid(struct gf100_gr_priv *priv)
+{
+ int gpc, tpc, id;
+
+ for (tpc = 0, id = 0; tpc < 4; tpc++) {
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ if (tpc < priv->tpc_nr[gpc]) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x698), id);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c10 + tpc * 4), id);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x088), id);
+ id++;
+ }
+
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c08), priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0c8c), priv->tpc_nr[gpc]);
+ }
+ }
+}
+
+static void
+gm107_grctx_generate_main(struct gf100_gr_priv *priv, struct gf100_grctx *info)
+{
+ struct gf100_grctx_oclass *oclass = (void *)nv_engine(priv)->cclass;
+ int i;
+
+ gf100_gr_mmio(priv, oclass->hub);
+ gf100_gr_mmio(priv, oclass->gpc);
+ gf100_gr_mmio(priv, oclass->zcull);
+ gf100_gr_mmio(priv, oclass->tpc);
+ gf100_gr_mmio(priv, oclass->ppc);
+
+ nv_wr32(priv, 0x404154, 0x00000000);
+
+ oclass->bundle(info);
+ oclass->pagepool(info);
+ oclass->attrib(info);
+ oclass->unkn(priv);
+
+ gm107_grctx_generate_tpcid(priv);
+ gf100_grctx_generate_r406028(priv);
+ gk104_grctx_generate_r418bb8(priv);
+ gf100_grctx_generate_r406800(priv);
+
+ nv_wr32(priv, 0x4064d0, 0x00000001);
+ for (i = 1; i < 8; i++)
+ nv_wr32(priv, 0x4064d0 + (i * 0x04), 0x00000000);
+ nv_wr32(priv, 0x406500, 0x00000001);
+
+ nv_wr32(priv, 0x405b00, (priv->tpc_total << 8) | priv->gpc_nr);
+
+ if (priv->gpc_nr == 1) {
+ nv_mask(priv, 0x408850, 0x0000000f, priv->tpc_nr[0]);
+ nv_mask(priv, 0x408958, 0x0000000f, priv->tpc_nr[0]);
+ } else {
+ nv_mask(priv, 0x408850, 0x0000000f, priv->gpc_nr);
+ nv_mask(priv, 0x408958, 0x0000000f, priv->gpc_nr);
+ }
+
+ gf100_gr_icmd(priv, oclass->icmd);
+ nv_wr32(priv, 0x404154, 0x00000400);
+ gf100_gr_mthd(priv, oclass->mthd);
+
+ nv_mask(priv, 0x419e00, 0x00808080, 0x00808080);
+ nv_mask(priv, 0x419ccc, 0x80000000, 0x80000000);
+ nv_mask(priv, 0x419f80, 0x80000000, 0x80000000);
+ nv_mask(priv, 0x419f88, 0x80000000, 0x80000000);
+}
+
+struct nvkm_oclass *
+gm107_grctx_oclass = &(struct gf100_grctx_oclass) {
+ .base.handle = NV_ENGCTX(GR, 0x08),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_context_ctor,
+ .dtor = gf100_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+ .main = gm107_grctx_generate_main,
+ .unkn = gk104_grctx_generate_unkn,
+ .hub = gm107_grctx_pack_hub,
+ .gpc = gm107_grctx_pack_gpc,
+ .zcull = gf100_grctx_pack_zcull,
+ .tpc = gm107_grctx_pack_tpc,
+ .ppc = gm107_grctx_pack_ppc,
+ .icmd = gm107_grctx_pack_icmd,
+ .mthd = gm107_grctx_pack_mthd,
+ .bundle = gm107_grctx_generate_bundle,
+ .bundle_size = 0x3000,
+ .bundle_min_gpm_fifo_depth = 0x180,
+ .bundle_token_limit = 0x2c0,
+ .pagepool = gm107_grctx_generate_pagepool,
+ .pagepool_size = 0x8000,
+ .attrib = gm107_grctx_generate_attrib,
+ .attrib_nr_max = 0xff0,
+ .attrib_nr = 0xaa0,
+ .alpha_nr_max = 0x1800,
+ .alpha_nr = 0x1000,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c
new file mode 100644
index 000000000000..dc31462afe65
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.c
@@ -0,0 +1,694 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* NVIDIA context programs handle a number of other conditions which are
+ * not implemented in our versions. It's not clear why NVIDIA context
+ * programs have this code, nor whether it's strictly necessary for
+ * correct operation. We'll implement additional handling if/when we
+ * discover it's necessary.
+ *
+ * - On context save, NVIDIA set 0x400314 bit 0 to 1 if the "3D state"
+ * flag is set, this gets saved into the context.
+ * - On context save, the context program for all cards load nsource
+ * into a flag register and check for ILLEGAL_MTHD. If it's set,
+ * opcode 0x60000d is called before resuming normal operation.
+ * - Some context programs check more conditions than the above. NV44
+ * checks: ((nsource & 0x0857) || (0x400718 & 0x0100) || (intr & 0x0001))
+ * and calls 0x60000d before resuming normal operation.
+ * - At the very beginning of NVIDIA's context programs, flag 9 is checked
+ * and if true 0x800001 is called with count=0, pos=0, the flag is cleared
+ * and then the ctxprog is aborted. It looks like a complicated NOP,
+ * its purpose is unknown.
+ * - In the section of code that loads the per-vs state, NVIDIA check
+ * flag 10. If it's set, they only transfer the small 0x300 byte block
+ * of state + the state for a single vs as opposed to the state for
+ * all vs units. It doesn't seem likely that it'll occur in normal
+ * operation, especially seeing as it appears NVIDIA may have screwed
+ * up the ctxprogs for some cards and have an invalid instruction
+ * rather than a cp_lsr(ctx, dwords_for_1_vs_unit) instruction.
+ * - There's a number of places where context offset 0 (where we place
+ * the PRAMIN offset of the context) is loaded into either 0x408000,
+ * 0x408004 or 0x408008. Not sure what's up there either.
+ * - The ctxprogs for some cards save 0x400a00 again during the cleanup
+ * path for auto-loadctx.
+ */
+
+#define CP_FLAG_CLEAR 0
+#define CP_FLAG_SET 1
+#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD 0
+#define CP_FLAG_SWAP_DIRECTION_SAVE 1
+#define CP_FLAG_USER_SAVE ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING 1
+#define CP_FLAG_USER_LOAD ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING 1
+#define CP_FLAG_STATUS ((3 * 32) + 0)
+#define CP_FLAG_STATUS_IDLE 0
+#define CP_FLAG_STATUS_BUSY 1
+#define CP_FLAG_AUTO_SAVE ((3 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING 1
+#define CP_FLAG_AUTO_LOAD ((3 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING 1
+#define CP_FLAG_UNK54 ((3 * 32) + 6)
+#define CP_FLAG_UNK54_CLEAR 0
+#define CP_FLAG_UNK54_SET 1
+#define CP_FLAG_ALWAYS ((3 * 32) + 8)
+#define CP_FLAG_ALWAYS_FALSE 0
+#define CP_FLAG_ALWAYS_TRUE 1
+#define CP_FLAG_UNK57 ((3 * 32) + 9)
+#define CP_FLAG_UNK57_CLEAR 0
+#define CP_FLAG_UNK57_SET 1
+
+#define CP_CTX 0x00100000
+#define CP_CTX_COUNT 0x000fc000
+#define CP_CTX_COUNT_SHIFT 14
+#define CP_CTX_REG 0x00003fff
+#define CP_LOAD_SR 0x00200000
+#define CP_LOAD_SR_VALUE 0x000fffff
+#define CP_BRA 0x00400000
+#define CP_BRA_IP 0x0000ff00
+#define CP_BRA_IP_SHIFT 8
+#define CP_BRA_IF_CLEAR 0x00000080
+#define CP_BRA_FLAG 0x0000007f
+#define CP_WAIT 0x00500000
+#define CP_WAIT_SET 0x00000080
+#define CP_WAIT_FLAG 0x0000007f
+#define CP_SET 0x00700000
+#define CP_SET_1 0x00000080
+#define CP_SET_FLAG 0x0000007f
+#define CP_NEXT_TO_SWAP 0x00600007
+#define CP_NEXT_TO_CURRENT 0x00600009
+#define CP_SET_CONTEXT_POINTER 0x0060000a
+#define CP_END 0x0060000e
+#define CP_LOAD_MAGIC_UNK01 0x00800001 /* unknown */
+#define CP_LOAD_MAGIC_NV44TCL 0x00800029 /* per-vs state (0x4497) */
+#define CP_LOAD_MAGIC_NV40TCL 0x00800041 /* per-vs state (0x4097) */
+
+#include "ctxnv40.h"
+#include "nv40.h"
+#include <core/device.h>
+
+/* TODO:
+ * - get vs count from 0x1540
+ */
+
+static int
+nv40_gr_vs_count(struct nvkm_device *device)
+{
+
+ switch (device->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ return 8;
+ case 0x40:
+ return 6;
+ case 0x41:
+ case 0x42:
+ return 5;
+ case 0x43:
+ case 0x44:
+ case 0x46:
+ case 0x4a:
+ return 3;
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ default:
+ return 1;
+ }
+}
+
+
+enum cp_label {
+ cp_check_load = 1,
+ cp_setup_auto_load,
+ cp_setup_load,
+ cp_setup_save,
+ cp_swap_state,
+ cp_swap_state3d_3_is_save,
+ cp_prepare_exit,
+ cp_exit,
+};
+
+static void
+nv40_gr_construct_general(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+
+ cp_ctx(ctx, 0x4000a4, 1);
+ gr_def(ctx, 0x4000a4, 0x00000008);
+ cp_ctx(ctx, 0x400144, 58);
+ gr_def(ctx, 0x400144, 0x00000001);
+ cp_ctx(ctx, 0x400314, 1);
+ gr_def(ctx, 0x400314, 0x00000000);
+ cp_ctx(ctx, 0x400400, 10);
+ cp_ctx(ctx, 0x400480, 10);
+ cp_ctx(ctx, 0x400500, 19);
+ gr_def(ctx, 0x400514, 0x00040000);
+ gr_def(ctx, 0x400524, 0x55555555);
+ gr_def(ctx, 0x400528, 0x55555555);
+ gr_def(ctx, 0x40052c, 0x55555555);
+ gr_def(ctx, 0x400530, 0x55555555);
+ cp_ctx(ctx, 0x400560, 6);
+ gr_def(ctx, 0x400568, 0x0000ffff);
+ gr_def(ctx, 0x40056c, 0x0000ffff);
+ cp_ctx(ctx, 0x40057c, 5);
+ cp_ctx(ctx, 0x400710, 3);
+ gr_def(ctx, 0x400710, 0x20010001);
+ gr_def(ctx, 0x400714, 0x0f73ef00);
+ cp_ctx(ctx, 0x400724, 1);
+ gr_def(ctx, 0x400724, 0x02008821);
+ cp_ctx(ctx, 0x400770, 3);
+ if (device->chipset == 0x40) {
+ cp_ctx(ctx, 0x400814, 4);
+ cp_ctx(ctx, 0x400828, 5);
+ cp_ctx(ctx, 0x400840, 5);
+ gr_def(ctx, 0x400850, 0x00000040);
+ cp_ctx(ctx, 0x400858, 4);
+ gr_def(ctx, 0x400858, 0x00000040);
+ gr_def(ctx, 0x40085c, 0x00000040);
+ gr_def(ctx, 0x400864, 0x80000000);
+ cp_ctx(ctx, 0x40086c, 9);
+ gr_def(ctx, 0x40086c, 0x80000000);
+ gr_def(ctx, 0x400870, 0x80000000);
+ gr_def(ctx, 0x400874, 0x80000000);
+ gr_def(ctx, 0x400878, 0x80000000);
+ gr_def(ctx, 0x400888, 0x00000040);
+ gr_def(ctx, 0x40088c, 0x80000000);
+ cp_ctx(ctx, 0x4009c0, 8);
+ gr_def(ctx, 0x4009cc, 0x80000000);
+ gr_def(ctx, 0x4009dc, 0x80000000);
+ } else {
+ cp_ctx(ctx, 0x400840, 20);
+ if (nv44_gr_class(ctx->device)) {
+ for (i = 0; i < 8; i++)
+ gr_def(ctx, 0x400860 + (i * 4), 0x00000001);
+ }
+ gr_def(ctx, 0x400880, 0x00000040);
+ gr_def(ctx, 0x400884, 0x00000040);
+ gr_def(ctx, 0x400888, 0x00000040);
+ cp_ctx(ctx, 0x400894, 11);
+ gr_def(ctx, 0x400894, 0x00000040);
+ if (!nv44_gr_class(ctx->device)) {
+ for (i = 0; i < 8; i++)
+ gr_def(ctx, 0x4008a0 + (i * 4), 0x80000000);
+ }
+ cp_ctx(ctx, 0x4008e0, 2);
+ cp_ctx(ctx, 0x4008f8, 2);
+ if (device->chipset == 0x4c ||
+ (device->chipset & 0xf0) == 0x60)
+ cp_ctx(ctx, 0x4009f8, 1);
+ }
+ cp_ctx(ctx, 0x400a00, 73);
+ gr_def(ctx, 0x400b0c, 0x0b0b0b0c);
+ cp_ctx(ctx, 0x401000, 4);
+ cp_ctx(ctx, 0x405004, 1);
+ switch (device->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x403448, 1);
+ gr_def(ctx, 0x403448, 0x00001010);
+ break;
+ default:
+ cp_ctx(ctx, 0x403440, 1);
+ switch (device->chipset) {
+ case 0x40:
+ gr_def(ctx, 0x403440, 0x00000010);
+ break;
+ case 0x44:
+ case 0x46:
+ case 0x4a:
+ gr_def(ctx, 0x403440, 0x00003010);
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ default:
+ gr_def(ctx, 0x403440, 0x00001010);
+ break;
+ }
+ break;
+ }
+}
+
+static void
+nv40_gr_construct_state3d(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+
+ if (device->chipset == 0x40) {
+ cp_ctx(ctx, 0x401880, 51);
+ gr_def(ctx, 0x401940, 0x00000100);
+ } else
+ if (device->chipset == 0x46 || device->chipset == 0x47 ||
+ device->chipset == 0x49 || device->chipset == 0x4b) {
+ cp_ctx(ctx, 0x401880, 32);
+ for (i = 0; i < 16; i++)
+ gr_def(ctx, 0x401880 + (i * 4), 0x00000111);
+ if (device->chipset == 0x46)
+ cp_ctx(ctx, 0x401900, 16);
+ cp_ctx(ctx, 0x401940, 3);
+ }
+ cp_ctx(ctx, 0x40194c, 18);
+ gr_def(ctx, 0x401954, 0x00000111);
+ gr_def(ctx, 0x401958, 0x00080060);
+ gr_def(ctx, 0x401974, 0x00000080);
+ gr_def(ctx, 0x401978, 0xffff0000);
+ gr_def(ctx, 0x40197c, 0x00000001);
+ gr_def(ctx, 0x401990, 0x46400000);
+ if (device->chipset == 0x40) {
+ cp_ctx(ctx, 0x4019a0, 2);
+ cp_ctx(ctx, 0x4019ac, 5);
+ } else {
+ cp_ctx(ctx, 0x4019a0, 1);
+ cp_ctx(ctx, 0x4019b4, 3);
+ }
+ gr_def(ctx, 0x4019bc, 0xffff0000);
+ switch (device->chipset) {
+ case 0x46:
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x4019c0, 18);
+ for (i = 0; i < 16; i++)
+ gr_def(ctx, 0x4019c0 + (i * 4), 0x88888888);
+ break;
+ }
+ cp_ctx(ctx, 0x401a08, 8);
+ gr_def(ctx, 0x401a10, 0x0fff0000);
+ gr_def(ctx, 0x401a14, 0x0fff0000);
+ gr_def(ctx, 0x401a1c, 0x00011100);
+ cp_ctx(ctx, 0x401a2c, 4);
+ cp_ctx(ctx, 0x401a44, 26);
+ for (i = 0; i < 16; i++)
+ gr_def(ctx, 0x401a44 + (i * 4), 0x07ff0000);
+ gr_def(ctx, 0x401a8c, 0x4b7fffff);
+ if (device->chipset == 0x40) {
+ cp_ctx(ctx, 0x401ab8, 3);
+ } else {
+ cp_ctx(ctx, 0x401ab8, 1);
+ cp_ctx(ctx, 0x401ac0, 1);
+ }
+ cp_ctx(ctx, 0x401ad0, 8);
+ gr_def(ctx, 0x401ad0, 0x30201000);
+ gr_def(ctx, 0x401ad4, 0x70605040);
+ gr_def(ctx, 0x401ad8, 0xb8a89888);
+ gr_def(ctx, 0x401adc, 0xf8e8d8c8);
+ cp_ctx(ctx, 0x401b10, device->chipset == 0x40 ? 2 : 1);
+ gr_def(ctx, 0x401b10, 0x40100000);
+ cp_ctx(ctx, 0x401b18, device->chipset == 0x40 ? 6 : 5);
+ gr_def(ctx, 0x401b28, device->chipset == 0x40 ?
+ 0x00000004 : 0x00000000);
+ cp_ctx(ctx, 0x401b30, 25);
+ gr_def(ctx, 0x401b34, 0x0000ffff);
+ gr_def(ctx, 0x401b68, 0x435185d6);
+ gr_def(ctx, 0x401b6c, 0x2155b699);
+ gr_def(ctx, 0x401b70, 0xfedcba98);
+ gr_def(ctx, 0x401b74, 0x00000098);
+ gr_def(ctx, 0x401b84, 0xffffffff);
+ gr_def(ctx, 0x401b88, 0x00ff7000);
+ gr_def(ctx, 0x401b8c, 0x0000ffff);
+ if (device->chipset != 0x44 && device->chipset != 0x4a &&
+ device->chipset != 0x4e)
+ cp_ctx(ctx, 0x401b94, 1);
+ cp_ctx(ctx, 0x401b98, 8);
+ gr_def(ctx, 0x401b9c, 0x00ff0000);
+ cp_ctx(ctx, 0x401bc0, 9);
+ gr_def(ctx, 0x401be0, 0x00ffff00);
+ cp_ctx(ctx, 0x401c00, 192);
+ for (i = 0; i < 16; i++) { /* fragment texture units */
+ gr_def(ctx, 0x401c40 + (i * 4), 0x00018488);
+ gr_def(ctx, 0x401c80 + (i * 4), 0x00028202);
+ gr_def(ctx, 0x401d00 + (i * 4), 0x0000aae4);
+ gr_def(ctx, 0x401d40 + (i * 4), 0x01012000);
+ gr_def(ctx, 0x401d80 + (i * 4), 0x00080008);
+ gr_def(ctx, 0x401e00 + (i * 4), 0x00100008);
+ }
+ for (i = 0; i < 4; i++) { /* vertex texture units */
+ gr_def(ctx, 0x401e90 + (i * 4), 0x0001bc80);
+ gr_def(ctx, 0x401ea0 + (i * 4), 0x00000202);
+ gr_def(ctx, 0x401ec0 + (i * 4), 0x00000008);
+ gr_def(ctx, 0x401ee0 + (i * 4), 0x00080008);
+ }
+ cp_ctx(ctx, 0x400f5c, 3);
+ gr_def(ctx, 0x400f5c, 0x00000002);
+ cp_ctx(ctx, 0x400f84, 1);
+}
+
+static void
+nv40_gr_construct_state3d_2(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+
+ cp_ctx(ctx, 0x402000, 1);
+ cp_ctx(ctx, 0x402404, device->chipset == 0x40 ? 1 : 2);
+ switch (device->chipset) {
+ case 0x40:
+ gr_def(ctx, 0x402404, 0x00000001);
+ break;
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ gr_def(ctx, 0x402404, 0x00000020);
+ break;
+ case 0x46:
+ case 0x49:
+ case 0x4b:
+ gr_def(ctx, 0x402404, 0x00000421);
+ break;
+ default:
+ gr_def(ctx, 0x402404, 0x00000021);
+ }
+ if (device->chipset != 0x40)
+ gr_def(ctx, 0x402408, 0x030c30c3);
+ switch (device->chipset) {
+ case 0x44:
+ case 0x46:
+ case 0x4a:
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ cp_ctx(ctx, 0x402440, 1);
+ gr_def(ctx, 0x402440, 0x00011001);
+ break;
+ default:
+ break;
+ }
+ cp_ctx(ctx, 0x402480, device->chipset == 0x40 ? 8 : 9);
+ gr_def(ctx, 0x402488, 0x3e020200);
+ gr_def(ctx, 0x40248c, 0x00ffffff);
+ switch (device->chipset) {
+ case 0x40:
+ gr_def(ctx, 0x402490, 0x60103f00);
+ break;
+ case 0x47:
+ gr_def(ctx, 0x402490, 0x40103f00);
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x49:
+ case 0x4b:
+ gr_def(ctx, 0x402490, 0x20103f00);
+ break;
+ default:
+ gr_def(ctx, 0x402490, 0x0c103f00);
+ break;
+ }
+ gr_def(ctx, 0x40249c, device->chipset <= 0x43 ?
+ 0x00020000 : 0x00040000);
+ cp_ctx(ctx, 0x402500, 31);
+ gr_def(ctx, 0x402530, 0x00008100);
+ if (device->chipset == 0x40)
+ cp_ctx(ctx, 0x40257c, 6);
+ cp_ctx(ctx, 0x402594, 16);
+ cp_ctx(ctx, 0x402800, 17);
+ gr_def(ctx, 0x402800, 0x00000001);
+ switch (device->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x402864, 1);
+ gr_def(ctx, 0x402864, 0x00001001);
+ cp_ctx(ctx, 0x402870, 3);
+ gr_def(ctx, 0x402878, 0x00000003);
+ if (device->chipset != 0x47) { /* belong at end!! */
+ cp_ctx(ctx, 0x402900, 1);
+ cp_ctx(ctx, 0x402940, 1);
+ cp_ctx(ctx, 0x402980, 1);
+ cp_ctx(ctx, 0x4029c0, 1);
+ cp_ctx(ctx, 0x402a00, 1);
+ cp_ctx(ctx, 0x402a40, 1);
+ cp_ctx(ctx, 0x402a80, 1);
+ cp_ctx(ctx, 0x402ac0, 1);
+ }
+ break;
+ case 0x40:
+ cp_ctx(ctx, 0x402844, 1);
+ gr_def(ctx, 0x402844, 0x00000001);
+ cp_ctx(ctx, 0x402850, 1);
+ break;
+ default:
+ cp_ctx(ctx, 0x402844, 1);
+ gr_def(ctx, 0x402844, 0x00001001);
+ cp_ctx(ctx, 0x402850, 2);
+ gr_def(ctx, 0x402854, 0x00000003);
+ break;
+ }
+
+ cp_ctx(ctx, 0x402c00, 4);
+ gr_def(ctx, 0x402c00, device->chipset == 0x40 ?
+ 0x80800001 : 0x00888001);
+ switch (device->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x402c20, 40);
+ for (i = 0; i < 32; i++)
+ gr_def(ctx, 0x402c40 + (i * 4), 0xffffffff);
+ cp_ctx(ctx, 0x4030b8, 13);
+ gr_def(ctx, 0x4030dc, 0x00000005);
+ gr_def(ctx, 0x4030e8, 0x0000ffff);
+ break;
+ default:
+ cp_ctx(ctx, 0x402c10, 4);
+ if (device->chipset == 0x40)
+ cp_ctx(ctx, 0x402c20, 36);
+ else
+ if (device->chipset <= 0x42)
+ cp_ctx(ctx, 0x402c20, 24);
+ else
+ if (device->chipset <= 0x4a)
+ cp_ctx(ctx, 0x402c20, 16);
+ else
+ cp_ctx(ctx, 0x402c20, 8);
+ cp_ctx(ctx, 0x402cb0, device->chipset == 0x40 ? 12 : 13);
+ gr_def(ctx, 0x402cd4, 0x00000005);
+ if (device->chipset != 0x40)
+ gr_def(ctx, 0x402ce0, 0x0000ffff);
+ break;
+ }
+
+ cp_ctx(ctx, 0x403400, device->chipset == 0x40 ? 4 : 3);
+ cp_ctx(ctx, 0x403410, device->chipset == 0x40 ? 4 : 3);
+ cp_ctx(ctx, 0x403420, nv40_gr_vs_count(ctx->device));
+ for (i = 0; i < nv40_gr_vs_count(ctx->device); i++)
+ gr_def(ctx, 0x403420 + (i * 4), 0x00005555);
+
+ if (device->chipset != 0x40) {
+ cp_ctx(ctx, 0x403600, 1);
+ gr_def(ctx, 0x403600, 0x00000001);
+ }
+ cp_ctx(ctx, 0x403800, 1);
+
+ cp_ctx(ctx, 0x403c18, 1);
+ gr_def(ctx, 0x403c18, 0x00000001);
+ switch (device->chipset) {
+ case 0x46:
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ cp_ctx(ctx, 0x405018, 1);
+ gr_def(ctx, 0x405018, 0x08e00001);
+ cp_ctx(ctx, 0x405c24, 1);
+ gr_def(ctx, 0x405c24, 0x000e3000);
+ break;
+ }
+ if (device->chipset != 0x4e)
+ cp_ctx(ctx, 0x405800, 11);
+ cp_ctx(ctx, 0x407000, 1);
+}
+
+static void
+nv40_gr_construct_state3d_3(struct nvkm_grctx *ctx)
+{
+ int len = nv44_gr_class(ctx->device) ? 0x0084 : 0x0684;
+
+ cp_out (ctx, 0x300000);
+ cp_lsr (ctx, len - 4);
+ cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_swap_state3d_3_is_save);
+ cp_lsr (ctx, len);
+ cp_name(ctx, cp_swap_state3d_3_is_save);
+ cp_out (ctx, 0x800001);
+
+ ctx->ctxvals_pos += len;
+}
+
+static void
+nv40_gr_construct_shader(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ struct nvkm_gpuobj *obj = ctx->data;
+ int vs, vs_nr, vs_len, vs_nr_b0, vs_nr_b1, b0_offset, b1_offset;
+ int offset, i;
+
+ vs_nr = nv40_gr_vs_count(ctx->device);
+ vs_nr_b0 = 363;
+ vs_nr_b1 = device->chipset == 0x40 ? 128 : 64;
+ if (device->chipset == 0x40) {
+ b0_offset = 0x2200/4; /* 33a0 */
+ b1_offset = 0x55a0/4; /* 1500 */
+ vs_len = 0x6aa0/4;
+ } else
+ if (device->chipset == 0x41 || device->chipset == 0x42) {
+ b0_offset = 0x2200/4; /* 2200 */
+ b1_offset = 0x4400/4; /* 0b00 */
+ vs_len = 0x4f00/4;
+ } else {
+ b0_offset = 0x1d40/4; /* 2200 */
+ b1_offset = 0x3f40/4; /* 0b00 : 0a40 */
+ vs_len = nv44_gr_class(device) ? 0x4980/4 : 0x4a40/4;
+ }
+
+ cp_lsr(ctx, vs_len * vs_nr + 0x300/4);
+ cp_out(ctx, nv44_gr_class(device) ? 0x800029 : 0x800041);
+
+ offset = ctx->ctxvals_pos;
+ ctx->ctxvals_pos += (0x0300/4 + (vs_nr * vs_len));
+
+ if (ctx->mode != NVKM_GRCTX_VALS)
+ return;
+
+ offset += 0x0280/4;
+ for (i = 0; i < 16; i++, offset += 2)
+ nv_wo32(obj, offset * 4, 0x3f800000);
+
+ for (vs = 0; vs < vs_nr; vs++, offset += vs_len) {
+ for (i = 0; i < vs_nr_b0 * 6; i += 6)
+ nv_wo32(obj, (offset + b0_offset + i) * 4, 0x00000001);
+ for (i = 0; i < vs_nr_b1 * 4; i += 4)
+ nv_wo32(obj, (offset + b1_offset + i) * 4, 0x3f800000);
+ }
+}
+
+static void
+nv40_grctx_generate(struct nvkm_grctx *ctx)
+{
+ /* decide whether we're loading/unloading the context */
+ cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+ cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+ cp_name(ctx, cp_check_load);
+ cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+ cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+ cp_bra (ctx, ALWAYS, TRUE, cp_exit);
+
+ /* setup for context load */
+ cp_name(ctx, cp_setup_auto_load);
+ cp_wait(ctx, STATUS, IDLE);
+ cp_out (ctx, CP_NEXT_TO_SWAP);
+ cp_name(ctx, cp_setup_load);
+ cp_wait(ctx, STATUS, IDLE);
+ cp_set (ctx, SWAP_DIRECTION, LOAD);
+ cp_out (ctx, 0x00910880); /* ?? */
+ cp_out (ctx, 0x00901ffe); /* ?? */
+ cp_out (ctx, 0x01940000); /* ?? */
+ cp_lsr (ctx, 0x20);
+ cp_out (ctx, 0x0060000b); /* ?? */
+ cp_wait(ctx, UNK57, CLEAR);
+ cp_out (ctx, 0x0060000c); /* ?? */
+ cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+ /* setup for context save */
+ cp_name(ctx, cp_setup_save);
+ cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+ /* general PGRAPH state */
+ cp_name(ctx, cp_swap_state);
+ cp_pos (ctx, 0x00020/4);
+ nv40_gr_construct_general(ctx);
+ cp_wait(ctx, STATUS, IDLE);
+
+ /* 3D state, block 1 */
+ cp_bra (ctx, UNK54, CLEAR, cp_prepare_exit);
+ nv40_gr_construct_state3d(ctx);
+ cp_wait(ctx, STATUS, IDLE);
+
+ /* 3D state, block 2 */
+ nv40_gr_construct_state3d_2(ctx);
+
+ /* Some other block of "random" state */
+ nv40_gr_construct_state3d_3(ctx);
+
+ /* Per-vertex shader state */
+ cp_pos (ctx, ctx->ctxvals_pos);
+ nv40_gr_construct_shader(ctx);
+
+ /* pre-exit state updates */
+ cp_name(ctx, cp_prepare_exit);
+ cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+ cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+ cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+ cp_name(ctx, cp_exit);
+ cp_set (ctx, USER_SAVE, NOT_PENDING);
+ cp_set (ctx, USER_LOAD, NOT_PENDING);
+ cp_out (ctx, CP_END);
+}
+
+void
+nv40_grctx_fill(struct nvkm_device *device, struct nvkm_gpuobj *mem)
+{
+ nv40_grctx_generate(&(struct nvkm_grctx) {
+ .device = device,
+ .mode = NVKM_GRCTX_VALS,
+ .data = mem,
+ });
+}
+
+int
+nv40_grctx_init(struct nvkm_device *device, u32 *size)
+{
+ u32 *ctxprog = kmalloc(256 * 4, GFP_KERNEL), i;
+ struct nvkm_grctx ctx = {
+ .device = device,
+ .mode = NVKM_GRCTX_PROG,
+ .data = ctxprog,
+ .ctxprog_max = 256,
+ };
+
+ if (!ctxprog)
+ return -ENOMEM;
+
+ nv40_grctx_generate(&ctx);
+
+ nv_wr32(device, 0x400324, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(device, 0x400328, ctxprog[i]);
+ *size = ctx.ctxvals_pos * 4;
+
+ kfree(ctxprog);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h
new file mode 100644
index 000000000000..8a89961956af
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv40.h
@@ -0,0 +1,129 @@
+#ifndef __NVKM_GRCTX_H__
+#define __NVKM_GRCTX_H__
+#include <core/gpuobj.h>
+
+struct nvkm_grctx {
+ struct nvkm_device *device;
+
+ enum {
+ NVKM_GRCTX_PROG,
+ NVKM_GRCTX_VALS
+ } mode;
+ void *data;
+
+ u32 ctxprog_max;
+ u32 ctxprog_len;
+ u32 ctxprog_reg;
+ int ctxprog_label[32];
+ u32 ctxvals_pos;
+ u32 ctxvals_base;
+};
+
+static inline void
+cp_out(struct nvkm_grctx *ctx, u32 inst)
+{
+ u32 *ctxprog = ctx->data;
+
+ if (ctx->mode != NVKM_GRCTX_PROG)
+ return;
+
+ BUG_ON(ctx->ctxprog_len == ctx->ctxprog_max);
+ ctxprog[ctx->ctxprog_len++] = inst;
+}
+
+static inline void
+cp_lsr(struct nvkm_grctx *ctx, u32 val)
+{
+ cp_out(ctx, CP_LOAD_SR | val);
+}
+
+static inline void
+cp_ctx(struct nvkm_grctx *ctx, u32 reg, u32 length)
+{
+ ctx->ctxprog_reg = (reg - 0x00400000) >> 2;
+
+ ctx->ctxvals_base = ctx->ctxvals_pos;
+ ctx->ctxvals_pos = ctx->ctxvals_base + length;
+
+ if (length > (CP_CTX_COUNT >> CP_CTX_COUNT_SHIFT)) {
+ cp_lsr(ctx, length);
+ length = 0;
+ }
+
+ cp_out(ctx, CP_CTX | (length << CP_CTX_COUNT_SHIFT) | ctx->ctxprog_reg);
+}
+
+static inline void
+cp_name(struct nvkm_grctx *ctx, int name)
+{
+ u32 *ctxprog = ctx->data;
+ int i;
+
+ if (ctx->mode != NVKM_GRCTX_PROG)
+ return;
+
+ ctx->ctxprog_label[name] = ctx->ctxprog_len;
+ for (i = 0; i < ctx->ctxprog_len; i++) {
+ if ((ctxprog[i] & 0xfff00000) != 0xff400000)
+ continue;
+ if ((ctxprog[i] & CP_BRA_IP) != ((name) << CP_BRA_IP_SHIFT))
+ continue;
+ ctxprog[i] = (ctxprog[i] & 0x00ff00ff) |
+ (ctx->ctxprog_len << CP_BRA_IP_SHIFT);
+ }
+}
+
+static inline void
+_cp_bra(struct nvkm_grctx *ctx, u32 mod, int flag, int state, int name)
+{
+ int ip = 0;
+
+ if (mod != 2) {
+ ip = ctx->ctxprog_label[name] << CP_BRA_IP_SHIFT;
+ if (ip == 0)
+ ip = 0xff000000 | (name << CP_BRA_IP_SHIFT);
+ }
+
+ cp_out(ctx, CP_BRA | (mod << 18) | ip | flag |
+ (state ? 0 : CP_BRA_IF_CLEAR));
+}
+#define cp_bra(c, f, s, n) _cp_bra((c), 0, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_cal(c, f, s, n) _cp_bra((c), 1, CP_FLAG_##f, CP_FLAG_##f##_##s, n)
+#define cp_ret(c, f, s) _cp_bra((c), 2, CP_FLAG_##f, CP_FLAG_##f##_##s, 0)
+
+static inline void
+_cp_wait(struct nvkm_grctx *ctx, int flag, int state)
+{
+ cp_out(ctx, CP_WAIT | flag | (state ? CP_WAIT_SET : 0));
+}
+#define cp_wait(c, f, s) _cp_wait((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+_cp_set(struct nvkm_grctx *ctx, int flag, int state)
+{
+ cp_out(ctx, CP_SET | flag | (state ? CP_SET_1 : 0));
+}
+#define cp_set(c, f, s) _cp_set((c), CP_FLAG_##f, CP_FLAG_##f##_##s)
+
+static inline void
+cp_pos(struct nvkm_grctx *ctx, int offset)
+{
+ ctx->ctxvals_pos = offset;
+ ctx->ctxvals_base = ctx->ctxvals_pos;
+
+ cp_lsr(ctx, ctx->ctxvals_pos);
+ cp_out(ctx, CP_SET_CONTEXT_POINTER);
+}
+
+static inline void
+gr_def(struct nvkm_grctx *ctx, u32 reg, u32 val)
+{
+ if (ctx->mode != NVKM_GRCTX_VALS)
+ return;
+
+ reg = (reg - 0x00400000) / 4;
+ reg = (reg - ctx->ctxprog_reg) + ctx->ctxvals_base;
+
+ nv_wo32(ctx->data, reg * 4, val);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c
new file mode 100644
index 000000000000..9c9528d2cd90
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/ctxnv50.c
@@ -0,0 +1,3345 @@
+/*
+ * Copyright 2009 Marcin Kościelnicki
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#define CP_FLAG_CLEAR 0
+#define CP_FLAG_SET 1
+#define CP_FLAG_SWAP_DIRECTION ((0 * 32) + 0)
+#define CP_FLAG_SWAP_DIRECTION_LOAD 0
+#define CP_FLAG_SWAP_DIRECTION_SAVE 1
+#define CP_FLAG_UNK01 ((0 * 32) + 1)
+#define CP_FLAG_UNK01_CLEAR 0
+#define CP_FLAG_UNK01_SET 1
+#define CP_FLAG_UNK03 ((0 * 32) + 3)
+#define CP_FLAG_UNK03_CLEAR 0
+#define CP_FLAG_UNK03_SET 1
+#define CP_FLAG_USER_SAVE ((0 * 32) + 5)
+#define CP_FLAG_USER_SAVE_NOT_PENDING 0
+#define CP_FLAG_USER_SAVE_PENDING 1
+#define CP_FLAG_USER_LOAD ((0 * 32) + 6)
+#define CP_FLAG_USER_LOAD_NOT_PENDING 0
+#define CP_FLAG_USER_LOAD_PENDING 1
+#define CP_FLAG_UNK0B ((0 * 32) + 0xb)
+#define CP_FLAG_UNK0B_CLEAR 0
+#define CP_FLAG_UNK0B_SET 1
+#define CP_FLAG_XFER_SWITCH ((0 * 32) + 0xe)
+#define CP_FLAG_XFER_SWITCH_DISABLE 0
+#define CP_FLAG_XFER_SWITCH_ENABLE 1
+#define CP_FLAG_STATE ((0 * 32) + 0x1c)
+#define CP_FLAG_STATE_STOPPED 0
+#define CP_FLAG_STATE_RUNNING 1
+#define CP_FLAG_UNK1D ((0 * 32) + 0x1d)
+#define CP_FLAG_UNK1D_CLEAR 0
+#define CP_FLAG_UNK1D_SET 1
+#define CP_FLAG_UNK20 ((1 * 32) + 0)
+#define CP_FLAG_UNK20_CLEAR 0
+#define CP_FLAG_UNK20_SET 1
+#define CP_FLAG_STATUS ((2 * 32) + 0)
+#define CP_FLAG_STATUS_BUSY 0
+#define CP_FLAG_STATUS_IDLE 1
+#define CP_FLAG_AUTO_SAVE ((2 * 32) + 4)
+#define CP_FLAG_AUTO_SAVE_NOT_PENDING 0
+#define CP_FLAG_AUTO_SAVE_PENDING 1
+#define CP_FLAG_AUTO_LOAD ((2 * 32) + 5)
+#define CP_FLAG_AUTO_LOAD_NOT_PENDING 0
+#define CP_FLAG_AUTO_LOAD_PENDING 1
+#define CP_FLAG_NEWCTX ((2 * 32) + 10)
+#define CP_FLAG_NEWCTX_BUSY 0
+#define CP_FLAG_NEWCTX_DONE 1
+#define CP_FLAG_XFER ((2 * 32) + 11)
+#define CP_FLAG_XFER_IDLE 0
+#define CP_FLAG_XFER_BUSY 1
+#define CP_FLAG_ALWAYS ((2 * 32) + 13)
+#define CP_FLAG_ALWAYS_FALSE 0
+#define CP_FLAG_ALWAYS_TRUE 1
+#define CP_FLAG_INTR ((2 * 32) + 15)
+#define CP_FLAG_INTR_NOT_PENDING 0
+#define CP_FLAG_INTR_PENDING 1
+
+#define CP_CTX 0x00100000
+#define CP_CTX_COUNT 0x000f0000
+#define CP_CTX_COUNT_SHIFT 16
+#define CP_CTX_REG 0x00003fff
+#define CP_LOAD_SR 0x00200000
+#define CP_LOAD_SR_VALUE 0x000fffff
+#define CP_BRA 0x00400000
+#define CP_BRA_IP 0x0001ff00
+#define CP_BRA_IP_SHIFT 8
+#define CP_BRA_IF_CLEAR 0x00000080
+#define CP_BRA_FLAG 0x0000007f
+#define CP_WAIT 0x00500000
+#define CP_WAIT_SET 0x00000080
+#define CP_WAIT_FLAG 0x0000007f
+#define CP_SET 0x00700000
+#define CP_SET_1 0x00000080
+#define CP_SET_FLAG 0x0000007f
+#define CP_NEWCTX 0x00600004
+#define CP_NEXT_TO_SWAP 0x00600005
+#define CP_SET_CONTEXT_POINTER 0x00600006
+#define CP_SET_XFER_POINTER 0x00600007
+#define CP_ENABLE 0x00600009
+#define CP_END 0x0060000c
+#define CP_NEXT_TO_CURRENT 0x0060000d
+#define CP_DISABLE1 0x0090ffff
+#define CP_DISABLE2 0x0091ffff
+#define CP_XFER_1 0x008000ff
+#define CP_XFER_2 0x008800ff
+#define CP_SEEK_1 0x00c000ff
+#define CP_SEEK_2 0x00c800ff
+
+#include "ctxnv40.h"
+
+#include <core/device.h>
+#include <subdev/fb.h>
+
+#define IS_NVA3F(x) (((x) > 0xa0 && (x) < 0xaa) || (x) == 0xaf)
+#define IS_NVAAF(x) ((x) >= 0xaa && (x) <= 0xac)
+
+/*
+ * This code deals with PGRAPH contexts on NV50 family cards. Like NV40, it's
+ * the GPU itself that does context-switching, but it needs a special
+ * microcode to do it. And it's the driver's task to supply this microcode,
+ * further known as ctxprog, as well as the initial context values, known
+ * as ctxvals.
+ *
+ * Without ctxprog, you cannot switch contexts. Not even in software, since
+ * the majority of context [xfer strands] isn't accessible directly. You're
+ * stuck with a single channel, and you also suffer all the problems resulting
+ * from missing ctxvals, since you cannot load them.
+ *
+ * Without ctxvals, you're stuck with PGRAPH's default context. It's enough to
+ * run 2d operations, but trying to utilise 3d or CUDA will just lock you up,
+ * since you don't have... some sort of needed setup.
+ *
+ * Nouveau will just disable acceleration if not given ctxprog + ctxvals, since
+ * it's too much hassle to handle no-ctxprog as a special case.
+ */
+
+/*
+ * How ctxprogs work.
+ *
+ * The ctxprog is written in its own kind of microcode, with very small and
+ * crappy set of available commands. You upload it to a small [512 insns]
+ * area of memory on PGRAPH, and it'll be run when PFIFO wants PGRAPH to
+ * switch channel. or when the driver explicitely requests it. Stuff visible
+ * to ctxprog consists of: PGRAPH MMIO registers, PGRAPH context strands,
+ * the per-channel context save area in VRAM [known as ctxvals or grctx],
+ * 4 flags registers, a scratch register, two grctx pointers, plus many
+ * random poorly-understood details.
+ *
+ * When ctxprog runs, it's supposed to check what operations are asked of it,
+ * save old context if requested, optionally reset PGRAPH and switch to the
+ * new channel, and load the new context. Context consists of three major
+ * parts: subset of MMIO registers and two "xfer areas".
+ */
+
+/* TODO:
+ * - document unimplemented bits compared to nvidia
+ * - NVAx: make a TP subroutine, use it.
+ * - use 0x4008fc instead of 0x1540?
+ */
+
+enum cp_label {
+ cp_check_load = 1,
+ cp_setup_auto_load,
+ cp_setup_load,
+ cp_setup_save,
+ cp_swap_state,
+ cp_prepare_exit,
+ cp_exit,
+};
+
+static void nv50_gr_construct_mmio(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_xfer1(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_xfer2(struct nvkm_grctx *ctx);
+
+/* Main function: construct the ctxprog skeleton, call the other functions. */
+
+static int
+nv50_grctx_generate(struct nvkm_grctx *ctx)
+{
+ cp_set (ctx, STATE, RUNNING);
+ cp_set (ctx, XFER_SWITCH, ENABLE);
+ /* decide whether we're loading/unloading the context */
+ cp_bra (ctx, AUTO_SAVE, PENDING, cp_setup_save);
+ cp_bra (ctx, USER_SAVE, PENDING, cp_setup_save);
+
+ cp_name(ctx, cp_check_load);
+ cp_bra (ctx, AUTO_LOAD, PENDING, cp_setup_auto_load);
+ cp_bra (ctx, USER_LOAD, PENDING, cp_setup_load);
+ cp_bra (ctx, ALWAYS, TRUE, cp_prepare_exit);
+
+ /* setup for context load */
+ cp_name(ctx, cp_setup_auto_load);
+ cp_out (ctx, CP_DISABLE1);
+ cp_out (ctx, CP_DISABLE2);
+ cp_out (ctx, CP_ENABLE);
+ cp_out (ctx, CP_NEXT_TO_SWAP);
+ cp_set (ctx, UNK01, SET);
+ cp_name(ctx, cp_setup_load);
+ cp_out (ctx, CP_NEWCTX);
+ cp_wait(ctx, NEWCTX, BUSY);
+ cp_set (ctx, UNK1D, CLEAR);
+ cp_set (ctx, SWAP_DIRECTION, LOAD);
+ cp_bra (ctx, UNK0B, SET, cp_prepare_exit);
+ cp_bra (ctx, ALWAYS, TRUE, cp_swap_state);
+
+ /* setup for context save */
+ cp_name(ctx, cp_setup_save);
+ cp_set (ctx, UNK1D, SET);
+ cp_wait(ctx, STATUS, BUSY);
+ cp_wait(ctx, INTR, PENDING);
+ cp_bra (ctx, STATUS, BUSY, cp_setup_save);
+ cp_set (ctx, UNK01, SET);
+ cp_set (ctx, SWAP_DIRECTION, SAVE);
+
+ /* general PGRAPH state */
+ cp_name(ctx, cp_swap_state);
+ cp_set (ctx, UNK03, SET);
+ cp_pos (ctx, 0x00004/4);
+ cp_ctx (ctx, 0x400828, 1); /* needed. otherwise, flickering happens. */
+ cp_pos (ctx, 0x00100/4);
+ nv50_gr_construct_mmio(ctx);
+ nv50_gr_construct_xfer1(ctx);
+ nv50_gr_construct_xfer2(ctx);
+
+ cp_bra (ctx, SWAP_DIRECTION, SAVE, cp_check_load);
+
+ cp_set (ctx, UNK20, SET);
+ cp_set (ctx, SWAP_DIRECTION, SAVE); /* no idea why this is needed, but fixes at least one lockup. */
+ cp_lsr (ctx, ctx->ctxvals_base);
+ cp_out (ctx, CP_SET_XFER_POINTER);
+ cp_lsr (ctx, 4);
+ cp_out (ctx, CP_SEEK_1);
+ cp_out (ctx, CP_XFER_1);
+ cp_wait(ctx, XFER, BUSY);
+
+ /* pre-exit state updates */
+ cp_name(ctx, cp_prepare_exit);
+ cp_set (ctx, UNK01, CLEAR);
+ cp_set (ctx, UNK03, CLEAR);
+ cp_set (ctx, UNK1D, CLEAR);
+
+ cp_bra (ctx, USER_SAVE, PENDING, cp_exit);
+ cp_out (ctx, CP_NEXT_TO_CURRENT);
+
+ cp_name(ctx, cp_exit);
+ cp_set (ctx, USER_SAVE, NOT_PENDING);
+ cp_set (ctx, USER_LOAD, NOT_PENDING);
+ cp_set (ctx, XFER_SWITCH, DISABLE);
+ cp_set (ctx, STATE, STOPPED);
+ cp_out (ctx, CP_END);
+ ctx->ctxvals_pos += 0x400; /* padding... no idea why you need it */
+
+ return 0;
+}
+
+void
+nv50_grctx_fill(struct nvkm_device *device, struct nvkm_gpuobj *mem)
+{
+ nv50_grctx_generate(&(struct nvkm_grctx) {
+ .device = device,
+ .mode = NVKM_GRCTX_VALS,
+ .data = mem,
+ });
+}
+
+int
+nv50_grctx_init(struct nvkm_device *device, u32 *size)
+{
+ u32 *ctxprog = kmalloc(512 * 4, GFP_KERNEL), i;
+ struct nvkm_grctx ctx = {
+ .device = device,
+ .mode = NVKM_GRCTX_PROG,
+ .data = ctxprog,
+ .ctxprog_max = 512,
+ };
+
+ if (!ctxprog)
+ return -ENOMEM;
+ nv50_grctx_generate(&ctx);
+
+ nv_wr32(device, 0x400324, 0);
+ for (i = 0; i < ctx.ctxprog_len; i++)
+ nv_wr32(device, 0x400328, ctxprog[i]);
+ *size = ctx.ctxvals_pos * 4;
+ kfree(ctxprog);
+ return 0;
+}
+
+/*
+ * Constructs MMIO part of ctxprog and ctxvals. Just a matter of knowing which
+ * registers to save/restore and the default values for them.
+ */
+
+static void
+nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx);
+
+static void
+nv50_gr_construct_mmio(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i, j;
+ int offset, base;
+ u32 units = nv_rd32 (ctx->device, 0x1540);
+
+ /* 0800: DISPATCH */
+ cp_ctx(ctx, 0x400808, 7);
+ gr_def(ctx, 0x400814, 0x00000030);
+ cp_ctx(ctx, 0x400834, 0x32);
+ if (device->chipset == 0x50) {
+ gr_def(ctx, 0x400834, 0xff400040);
+ gr_def(ctx, 0x400838, 0xfff00080);
+ gr_def(ctx, 0x40083c, 0xfff70090);
+ gr_def(ctx, 0x400840, 0xffe806a8);
+ }
+ gr_def(ctx, 0x400844, 0x00000002);
+ if (IS_NVA3F(device->chipset))
+ gr_def(ctx, 0x400894, 0x00001000);
+ gr_def(ctx, 0x4008e8, 0x00000003);
+ gr_def(ctx, 0x4008ec, 0x00001000);
+ if (device->chipset == 0x50)
+ cp_ctx(ctx, 0x400908, 0xb);
+ else if (device->chipset < 0xa0)
+ cp_ctx(ctx, 0x400908, 0xc);
+ else
+ cp_ctx(ctx, 0x400908, 0xe);
+
+ if (device->chipset >= 0xa0)
+ cp_ctx(ctx, 0x400b00, 0x1);
+ if (IS_NVA3F(device->chipset)) {
+ cp_ctx(ctx, 0x400b10, 0x1);
+ gr_def(ctx, 0x400b10, 0x0001629d);
+ cp_ctx(ctx, 0x400b20, 0x1);
+ gr_def(ctx, 0x400b20, 0x0001629d);
+ }
+
+ nv50_gr_construct_mmio_ddata(ctx);
+
+ /* 0C00: VFETCH */
+ cp_ctx(ctx, 0x400c08, 0x2);
+ gr_def(ctx, 0x400c08, 0x0000fe0c);
+
+ /* 1000 */
+ if (device->chipset < 0xa0) {
+ cp_ctx(ctx, 0x401008, 0x4);
+ gr_def(ctx, 0x401014, 0x00001000);
+ } else if (!IS_NVA3F(device->chipset)) {
+ cp_ctx(ctx, 0x401008, 0x5);
+ gr_def(ctx, 0x401018, 0x00001000);
+ } else {
+ cp_ctx(ctx, 0x401008, 0x5);
+ gr_def(ctx, 0x401018, 0x00004000);
+ }
+
+ /* 1400 */
+ cp_ctx(ctx, 0x401400, 0x8);
+ cp_ctx(ctx, 0x401424, 0x3);
+ if (device->chipset == 0x50)
+ gr_def(ctx, 0x40142c, 0x0001fd87);
+ else
+ gr_def(ctx, 0x40142c, 0x00000187);
+ cp_ctx(ctx, 0x401540, 0x5);
+ gr_def(ctx, 0x401550, 0x00001018);
+
+ /* 1800: STREAMOUT */
+ cp_ctx(ctx, 0x401814, 0x1);
+ gr_def(ctx, 0x401814, 0x000000ff);
+ if (device->chipset == 0x50) {
+ cp_ctx(ctx, 0x40181c, 0xe);
+ gr_def(ctx, 0x401850, 0x00000004);
+ } else if (device->chipset < 0xa0) {
+ cp_ctx(ctx, 0x40181c, 0xf);
+ gr_def(ctx, 0x401854, 0x00000004);
+ } else {
+ cp_ctx(ctx, 0x40181c, 0x13);
+ gr_def(ctx, 0x401864, 0x00000004);
+ }
+
+ /* 1C00 */
+ cp_ctx(ctx, 0x401c00, 0x1);
+ switch (device->chipset) {
+ case 0x50:
+ gr_def(ctx, 0x401c00, 0x0001005f);
+ break;
+ case 0x84:
+ case 0x86:
+ case 0x94:
+ gr_def(ctx, 0x401c00, 0x044d00df);
+ break;
+ case 0x92:
+ case 0x96:
+ case 0x98:
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ gr_def(ctx, 0x401c00, 0x042500df);
+ break;
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ case 0xaf:
+ gr_def(ctx, 0x401c00, 0x142500df);
+ break;
+ }
+
+ /* 2000 */
+
+ /* 2400 */
+ cp_ctx(ctx, 0x402400, 0x1);
+ if (device->chipset == 0x50)
+ cp_ctx(ctx, 0x402408, 0x1);
+ else
+ cp_ctx(ctx, 0x402408, 0x2);
+ gr_def(ctx, 0x402408, 0x00000600);
+
+ /* 2800: CSCHED */
+ cp_ctx(ctx, 0x402800, 0x1);
+ if (device->chipset == 0x50)
+ gr_def(ctx, 0x402800, 0x00000006);
+
+ /* 2C00: ZCULL */
+ cp_ctx(ctx, 0x402c08, 0x6);
+ if (device->chipset != 0x50)
+ gr_def(ctx, 0x402c14, 0x01000000);
+ gr_def(ctx, 0x402c18, 0x000000ff);
+ if (device->chipset == 0x50)
+ cp_ctx(ctx, 0x402ca0, 0x1);
+ else
+ cp_ctx(ctx, 0x402ca0, 0x2);
+ if (device->chipset < 0xa0)
+ gr_def(ctx, 0x402ca0, 0x00000400);
+ else if (!IS_NVA3F(device->chipset))
+ gr_def(ctx, 0x402ca0, 0x00000800);
+ else
+ gr_def(ctx, 0x402ca0, 0x00000400);
+ cp_ctx(ctx, 0x402cac, 0x4);
+
+ /* 3000: ENG2D */
+ cp_ctx(ctx, 0x403004, 0x1);
+ gr_def(ctx, 0x403004, 0x00000001);
+
+ /* 3400 */
+ if (device->chipset >= 0xa0) {
+ cp_ctx(ctx, 0x403404, 0x1);
+ gr_def(ctx, 0x403404, 0x00000001);
+ }
+
+ /* 5000: CCACHE */
+ cp_ctx(ctx, 0x405000, 0x1);
+ switch (device->chipset) {
+ case 0x50:
+ gr_def(ctx, 0x405000, 0x00300080);
+ break;
+ case 0x84:
+ case 0xa0:
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
+ gr_def(ctx, 0x405000, 0x000e0080);
+ break;
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ gr_def(ctx, 0x405000, 0x00000080);
+ break;
+ }
+ cp_ctx(ctx, 0x405014, 0x1);
+ gr_def(ctx, 0x405014, 0x00000004);
+ cp_ctx(ctx, 0x40501c, 0x1);
+ cp_ctx(ctx, 0x405024, 0x1);
+ cp_ctx(ctx, 0x40502c, 0x1);
+
+ /* 6000? */
+ if (device->chipset == 0x50)
+ cp_ctx(ctx, 0x4063e0, 0x1);
+
+ /* 6800: M2MF */
+ if (device->chipset < 0x90) {
+ cp_ctx(ctx, 0x406814, 0x2b);
+ gr_def(ctx, 0x406818, 0x00000f80);
+ gr_def(ctx, 0x406860, 0x007f0080);
+ gr_def(ctx, 0x40689c, 0x007f0080);
+ } else {
+ cp_ctx(ctx, 0x406814, 0x4);
+ if (device->chipset == 0x98)
+ gr_def(ctx, 0x406818, 0x00000f80);
+ else
+ gr_def(ctx, 0x406818, 0x00001f80);
+ if (IS_NVA3F(device->chipset))
+ gr_def(ctx, 0x40681c, 0x00000030);
+ cp_ctx(ctx, 0x406830, 0x3);
+ }
+
+ /* 7000: per-ROP group state */
+ for (i = 0; i < 8; i++) {
+ if (units & (1<<(i+16))) {
+ cp_ctx(ctx, 0x407000 + (i<<8), 3);
+ if (device->chipset == 0x50)
+ gr_def(ctx, 0x407000 + (i<<8), 0x1b74f820);
+ else if (device->chipset != 0xa5)
+ gr_def(ctx, 0x407000 + (i<<8), 0x3b74f821);
+ else
+ gr_def(ctx, 0x407000 + (i<<8), 0x7b74f821);
+ gr_def(ctx, 0x407004 + (i<<8), 0x89058001);
+
+ if (device->chipset == 0x50) {
+ cp_ctx(ctx, 0x407010 + (i<<8), 1);
+ } else if (device->chipset < 0xa0) {
+ cp_ctx(ctx, 0x407010 + (i<<8), 2);
+ gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
+ gr_def(ctx, 0x407014 + (i<<8), 0x0000001f);
+ } else {
+ cp_ctx(ctx, 0x407010 + (i<<8), 3);
+ gr_def(ctx, 0x407010 + (i<<8), 0x00001000);
+ if (device->chipset != 0xa5)
+ gr_def(ctx, 0x407014 + (i<<8), 0x000000ff);
+ else
+ gr_def(ctx, 0x407014 + (i<<8), 0x000001ff);
+ }
+
+ cp_ctx(ctx, 0x407080 + (i<<8), 4);
+ if (device->chipset != 0xa5)
+ gr_def(ctx, 0x407080 + (i<<8), 0x027c10fa);
+ else
+ gr_def(ctx, 0x407080 + (i<<8), 0x827c10fa);
+ if (device->chipset == 0x50)
+ gr_def(ctx, 0x407084 + (i<<8), 0x000000c0);
+ else
+ gr_def(ctx, 0x407084 + (i<<8), 0x400000c0);
+ gr_def(ctx, 0x407088 + (i<<8), 0xb7892080);
+
+ if (device->chipset < 0xa0)
+ cp_ctx(ctx, 0x407094 + (i<<8), 1);
+ else if (!IS_NVA3F(device->chipset))
+ cp_ctx(ctx, 0x407094 + (i<<8), 3);
+ else {
+ cp_ctx(ctx, 0x407094 + (i<<8), 4);
+ gr_def(ctx, 0x4070a0 + (i<<8), 1);
+ }
+ }
+ }
+
+ cp_ctx(ctx, 0x407c00, 0x3);
+ if (device->chipset < 0x90)
+ gr_def(ctx, 0x407c00, 0x00010040);
+ else if (device->chipset < 0xa0)
+ gr_def(ctx, 0x407c00, 0x00390040);
+ else
+ gr_def(ctx, 0x407c00, 0x003d0040);
+ gr_def(ctx, 0x407c08, 0x00000022);
+ if (device->chipset >= 0xa0) {
+ cp_ctx(ctx, 0x407c10, 0x3);
+ cp_ctx(ctx, 0x407c20, 0x1);
+ cp_ctx(ctx, 0x407c2c, 0x1);
+ }
+
+ if (device->chipset < 0xa0) {
+ cp_ctx(ctx, 0x407d00, 0x9);
+ } else {
+ cp_ctx(ctx, 0x407d00, 0x15);
+ }
+ if (device->chipset == 0x98)
+ gr_def(ctx, 0x407d08, 0x00380040);
+ else {
+ if (device->chipset < 0x90)
+ gr_def(ctx, 0x407d08, 0x00010040);
+ else if (device->chipset < 0xa0)
+ gr_def(ctx, 0x407d08, 0x00390040);
+ else {
+ if (nvkm_fb(device)->ram->type != NV_MEM_TYPE_GDDR5)
+ gr_def(ctx, 0x407d08, 0x003d0040);
+ else
+ gr_def(ctx, 0x407d08, 0x003c0040);
+ }
+ gr_def(ctx, 0x407d0c, 0x00000022);
+ }
+
+ /* 8000+: per-TP state */
+ for (i = 0; i < 10; i++) {
+ if (units & (1<<i)) {
+ if (device->chipset < 0xa0)
+ base = 0x408000 + (i<<12);
+ else
+ base = 0x408000 + (i<<11);
+ if (device->chipset < 0xa0)
+ offset = base + 0xc00;
+ else
+ offset = base + 0x80;
+ cp_ctx(ctx, offset + 0x00, 1);
+ gr_def(ctx, offset + 0x00, 0x0000ff0a);
+ cp_ctx(ctx, offset + 0x08, 1);
+
+ /* per-MP state */
+ for (j = 0; j < (device->chipset < 0xa0 ? 2 : 4); j++) {
+ if (!(units & (1 << (j+24)))) continue;
+ if (device->chipset < 0xa0)
+ offset = base + 0x200 + (j<<7);
+ else
+ offset = base + 0x100 + (j<<7);
+ cp_ctx(ctx, offset, 0x20);
+ gr_def(ctx, offset + 0x00, 0x01800000);
+ gr_def(ctx, offset + 0x04, 0x00160000);
+ gr_def(ctx, offset + 0x08, 0x01800000);
+ gr_def(ctx, offset + 0x18, 0x0003ffff);
+ switch (device->chipset) {
+ case 0x50:
+ gr_def(ctx, offset + 0x1c, 0x00080000);
+ break;
+ case 0x84:
+ gr_def(ctx, offset + 0x1c, 0x00880000);
+ break;
+ case 0x86:
+ gr_def(ctx, offset + 0x1c, 0x018c0000);
+ break;
+ case 0x92:
+ case 0x96:
+ case 0x98:
+ gr_def(ctx, offset + 0x1c, 0x118c0000);
+ break;
+ case 0x94:
+ gr_def(ctx, offset + 0x1c, 0x10880000);
+ break;
+ case 0xa0:
+ case 0xa5:
+ gr_def(ctx, offset + 0x1c, 0x310c0000);
+ break;
+ case 0xa3:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
+ gr_def(ctx, offset + 0x1c, 0x300c0000);
+ break;
+ }
+ gr_def(ctx, offset + 0x40, 0x00010401);
+ if (device->chipset == 0x50)
+ gr_def(ctx, offset + 0x48, 0x00000040);
+ else
+ gr_def(ctx, offset + 0x48, 0x00000078);
+ gr_def(ctx, offset + 0x50, 0x000000bf);
+ gr_def(ctx, offset + 0x58, 0x00001210);
+ if (device->chipset == 0x50)
+ gr_def(ctx, offset + 0x5c, 0x00000080);
+ else
+ gr_def(ctx, offset + 0x5c, 0x08000080);
+ if (device->chipset >= 0xa0)
+ gr_def(ctx, offset + 0x68, 0x0000003e);
+ }
+
+ if (device->chipset < 0xa0)
+ cp_ctx(ctx, base + 0x300, 0x4);
+ else
+ cp_ctx(ctx, base + 0x300, 0x5);
+ if (device->chipset == 0x50)
+ gr_def(ctx, base + 0x304, 0x00007070);
+ else if (device->chipset < 0xa0)
+ gr_def(ctx, base + 0x304, 0x00027070);
+ else if (!IS_NVA3F(device->chipset))
+ gr_def(ctx, base + 0x304, 0x01127070);
+ else
+ gr_def(ctx, base + 0x304, 0x05127070);
+
+ if (device->chipset < 0xa0)
+ cp_ctx(ctx, base + 0x318, 1);
+ else
+ cp_ctx(ctx, base + 0x320, 1);
+ if (device->chipset == 0x50)
+ gr_def(ctx, base + 0x318, 0x0003ffff);
+ else if (device->chipset < 0xa0)
+ gr_def(ctx, base + 0x318, 0x03ffffff);
+ else
+ gr_def(ctx, base + 0x320, 0x07ffffff);
+
+ if (device->chipset < 0xa0)
+ cp_ctx(ctx, base + 0x324, 5);
+ else
+ cp_ctx(ctx, base + 0x328, 4);
+
+ if (device->chipset < 0xa0) {
+ cp_ctx(ctx, base + 0x340, 9);
+ offset = base + 0x340;
+ } else if (!IS_NVA3F(device->chipset)) {
+ cp_ctx(ctx, base + 0x33c, 0xb);
+ offset = base + 0x344;
+ } else {
+ cp_ctx(ctx, base + 0x33c, 0xd);
+ offset = base + 0x344;
+ }
+ gr_def(ctx, offset + 0x0, 0x00120407);
+ gr_def(ctx, offset + 0x4, 0x05091507);
+ if (device->chipset == 0x84)
+ gr_def(ctx, offset + 0x8, 0x05100202);
+ else
+ gr_def(ctx, offset + 0x8, 0x05010202);
+ gr_def(ctx, offset + 0xc, 0x00030201);
+ if (device->chipset == 0xa3)
+ cp_ctx(ctx, base + 0x36c, 1);
+
+ cp_ctx(ctx, base + 0x400, 2);
+ gr_def(ctx, base + 0x404, 0x00000040);
+ cp_ctx(ctx, base + 0x40c, 2);
+ gr_def(ctx, base + 0x40c, 0x0d0c0b0a);
+ gr_def(ctx, base + 0x410, 0x00141210);
+
+ if (device->chipset < 0xa0)
+ offset = base + 0x800;
+ else
+ offset = base + 0x500;
+ cp_ctx(ctx, offset, 6);
+ gr_def(ctx, offset + 0x0, 0x000001f0);
+ gr_def(ctx, offset + 0x4, 0x00000001);
+ gr_def(ctx, offset + 0x8, 0x00000003);
+ if (device->chipset == 0x50 || IS_NVAAF(device->chipset))
+ gr_def(ctx, offset + 0xc, 0x00008000);
+ gr_def(ctx, offset + 0x14, 0x00039e00);
+ cp_ctx(ctx, offset + 0x1c, 2);
+ if (device->chipset == 0x50)
+ gr_def(ctx, offset + 0x1c, 0x00000040);
+ else
+ gr_def(ctx, offset + 0x1c, 0x00000100);
+ gr_def(ctx, offset + 0x20, 0x00003800);
+
+ if (device->chipset >= 0xa0) {
+ cp_ctx(ctx, base + 0x54c, 2);
+ if (!IS_NVA3F(device->chipset))
+ gr_def(ctx, base + 0x54c, 0x003fe006);
+ else
+ gr_def(ctx, base + 0x54c, 0x003fe007);
+ gr_def(ctx, base + 0x550, 0x003fe000);
+ }
+
+ if (device->chipset < 0xa0)
+ offset = base + 0xa00;
+ else
+ offset = base + 0x680;
+ cp_ctx(ctx, offset, 1);
+ gr_def(ctx, offset, 0x00404040);
+
+ if (device->chipset < 0xa0)
+ offset = base + 0xe00;
+ else
+ offset = base + 0x700;
+ cp_ctx(ctx, offset, 2);
+ if (device->chipset < 0xa0)
+ gr_def(ctx, offset, 0x0077f005);
+ else if (device->chipset == 0xa5)
+ gr_def(ctx, offset, 0x6cf7f007);
+ else if (device->chipset == 0xa8)
+ gr_def(ctx, offset, 0x6cfff007);
+ else if (device->chipset == 0xac)
+ gr_def(ctx, offset, 0x0cfff007);
+ else
+ gr_def(ctx, offset, 0x0cf7f007);
+ if (device->chipset == 0x50)
+ gr_def(ctx, offset + 0x4, 0x00007fff);
+ else if (device->chipset < 0xa0)
+ gr_def(ctx, offset + 0x4, 0x003f7fff);
+ else
+ gr_def(ctx, offset + 0x4, 0x02bf7fff);
+ cp_ctx(ctx, offset + 0x2c, 1);
+ if (device->chipset == 0x50) {
+ cp_ctx(ctx, offset + 0x50, 9);
+ gr_def(ctx, offset + 0x54, 0x000003ff);
+ gr_def(ctx, offset + 0x58, 0x00000003);
+ gr_def(ctx, offset + 0x5c, 0x00000003);
+ gr_def(ctx, offset + 0x60, 0x000001ff);
+ gr_def(ctx, offset + 0x64, 0x0000001f);
+ gr_def(ctx, offset + 0x68, 0x0000000f);
+ gr_def(ctx, offset + 0x6c, 0x0000000f);
+ } else if (device->chipset < 0xa0) {
+ cp_ctx(ctx, offset + 0x50, 1);
+ cp_ctx(ctx, offset + 0x70, 1);
+ } else {
+ cp_ctx(ctx, offset + 0x50, 1);
+ cp_ctx(ctx, offset + 0x60, 5);
+ }
+ }
+ }
+}
+
+static void
+dd_emit(struct nvkm_grctx *ctx, int num, u32 val) {
+ int i;
+ if (val && ctx->mode == NVKM_GRCTX_VALS)
+ for (i = 0; i < num; i++)
+ nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + i), val);
+ ctx->ctxvals_pos += num;
+}
+
+static void
+nv50_gr_construct_mmio_ddata(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int base, num;
+ base = ctx->ctxvals_pos;
+
+ /* tesla state */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK0F90 */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK135C */
+
+ /* SRC_TIC state */
+ dd_emit(ctx, 1, 0); /* 00000007 SRC_TILE_MODE_Z */
+ dd_emit(ctx, 1, 2); /* 00000007 SRC_TILE_MODE_Y */
+ dd_emit(ctx, 1, 1); /* 00000001 SRC_LINEAR #1 */
+ dd_emit(ctx, 1, 0); /* 000000ff SRC_ADDRESS_HIGH */
+ dd_emit(ctx, 1, 0); /* 00000001 SRC_SRGB */
+ if (device->chipset >= 0x94)
+ dd_emit(ctx, 1, 0); /* 00000003 eng2d UNK0258 */
+ dd_emit(ctx, 1, 1); /* 00000fff SRC_DEPTH */
+ dd_emit(ctx, 1, 0x100); /* 0000ffff SRC_HEIGHT */
+
+ /* turing state */
+ dd_emit(ctx, 1, 0); /* 0000000f TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f SAMPLERS_LOG2 */
+ dd_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */
+ dd_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */
+ dd_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */
+ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */
+ dd_emit(ctx, 1, 1); /* 0000ffff BLOCK_ALLOC_THREADS */
+ dd_emit(ctx, 1, 1); /* 00000001 LANES32 */
+ dd_emit(ctx, 1, 0); /* 000000ff UNK370 */
+ dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_UNK */
+ dd_emit(ctx, 1, 0); /* 000000ff USER_PARAM_COUNT */
+ dd_emit(ctx, 1, 1); /* 000000ff UNK384 bits 8-15 */
+ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
+ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
+ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_X */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_XMY */
+ dd_emit(ctx, 1, 0); /* 00000001 BLOCKDIM_XMY_OVERFLOW */
+ dd_emit(ctx, 1, 1); /* 0003ffff BLOCKDIM_XMYMZ */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCKDIM_Y */
+ dd_emit(ctx, 1, 1); /* 0000007f BLOCKDIM_Z */
+ dd_emit(ctx, 1, 4); /* 000000ff CP_REG_ALLOC_TEMP */
+ dd_emit(ctx, 1, 1); /* 00000001 BLOCKDIM_DIRTY */
+ if (IS_NVA3F(device->chipset))
+ dd_emit(ctx, 1, 0); /* 00000003 UNK03E8 */
+ dd_emit(ctx, 1, 1); /* 0000007f BLOCK_ALLOC_HALFWARPS */
+ dd_emit(ctx, 1, 1); /* 00000007 LOCAL_WARPS_NO_CLAMP */
+ dd_emit(ctx, 1, 7); /* 00000007 LOCAL_WARPS_LOG_ALLOC */
+ dd_emit(ctx, 1, 1); /* 00000007 STACK_WARPS_NO_CLAMP */
+ dd_emit(ctx, 1, 7); /* 00000007 STACK_WARPS_LOG_ALLOC */
+ dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_PACKED */
+ dd_emit(ctx, 1, 1); /* 00001fff BLOCK_ALLOC_REGSLOTS_STRIDED */
+ dd_emit(ctx, 1, 1); /* 000007ff BLOCK_ALLOC_THREADS */
+
+ /* compat 2d state */
+ if (device->chipset == 0x50) {
+ dd_emit(ctx, 4, 0); /* 0000ffff clip X, Y, W, H */
+
+ dd_emit(ctx, 1, 1); /* ffffffff chroma COLOR_FORMAT */
+
+ dd_emit(ctx, 1, 1); /* ffffffff pattern COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff pattern SHAPE */
+ dd_emit(ctx, 1, 1); /* ffffffff pattern PATTERN_SELECT */
+
+ dd_emit(ctx, 1, 0xa); /* ffffffff surf2d SRC_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff surf2d DMA_SRC */
+ dd_emit(ctx, 1, 0); /* 000000ff surf2d SRC_ADDRESS_HIGH */
+ dd_emit(ctx, 1, 0); /* ffffffff surf2d SRC_ADDRESS_LOW */
+ dd_emit(ctx, 1, 0x40); /* 0000ffff surf2d SRC_PITCH */
+ dd_emit(ctx, 1, 0); /* 0000000f surf2d SRC_TILE_MODE_Z */
+ dd_emit(ctx, 1, 2); /* 0000000f surf2d SRC_TILE_MODE_Y */
+ dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_HEIGHT */
+ dd_emit(ctx, 1, 1); /* 00000001 surf2d SRC_LINEAR */
+ dd_emit(ctx, 1, 0x100); /* ffffffff surf2d SRC_WIDTH */
+
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_B_Y */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_C_Y */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect CLIP_D_Y */
+ dd_emit(ctx, 1, 1); /* ffffffff gdirect COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff gdirect OPERATION */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_X */
+ dd_emit(ctx, 1, 0); /* 0000ffff gdirect POINT_Y */
+
+ dd_emit(ctx, 1, 0); /* 0000ffff blit SRC_Y */
+ dd_emit(ctx, 1, 0); /* ffffffff blit OPERATION */
+
+ dd_emit(ctx, 1, 0); /* ffffffff ifc OPERATION */
+
+ dd_emit(ctx, 1, 0); /* ffffffff iifc INDEX_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff iifc LUT_OFFSET */
+ dd_emit(ctx, 1, 4); /* ffffffff iifc COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff iifc OPERATION */
+ }
+
+ /* m2mf state */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_COUNT */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf LINE_LENGTH_IN */
+ dd_emit(ctx, 2, 0); /* ffffffff m2mf OFFSET_IN, OFFSET_OUT */
+ dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_OUT */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_OUT */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_OUT_Z */
+ dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_OUT */
+ dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_OUT_X, Y */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_OUT */
+ dd_emit(ctx, 1, 1); /* ffffffff m2mf TILING_DEPTH_IN */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_HEIGHT_IN */
+ dd_emit(ctx, 1, 0); /* ffffffff m2mf TILING_POSITION_IN_Z */
+ dd_emit(ctx, 1, 1); /* 00000001 m2mf LINEAR_IN */
+ dd_emit(ctx, 2, 0); /* 0000ffff m2mf TILING_POSITION_IN_X, Y */
+ dd_emit(ctx, 1, 0x100); /* ffffffff m2mf TILING_PITCH_IN */
+
+ /* more compat 2d state */
+ if (device->chipset == 0x50) {
+ dd_emit(ctx, 1, 1); /* ffffffff line COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff line OPERATION */
+
+ dd_emit(ctx, 1, 1); /* ffffffff triangle COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff triangle OPERATION */
+
+ dd_emit(ctx, 1, 0); /* 0000000f sifm TILE_MODE_Z */
+ dd_emit(ctx, 1, 2); /* 0000000f sifm TILE_MODE_Y */
+ dd_emit(ctx, 1, 0); /* 000000ff sifm FORMAT_FILTER */
+ dd_emit(ctx, 1, 1); /* 000000ff sifm FORMAT_ORIGIN */
+ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_PITCH */
+ dd_emit(ctx, 1, 1); /* 00000001 sifm SRC_LINEAR */
+ dd_emit(ctx, 1, 0); /* 000000ff sifm SRC_OFFSET_HIGH */
+ dd_emit(ctx, 1, 0); /* ffffffff sifm SRC_OFFSET */
+ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_HEIGHT */
+ dd_emit(ctx, 1, 0); /* 0000ffff sifm SRC_WIDTH */
+ dd_emit(ctx, 1, 3); /* ffffffff sifm COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff sifm OPERATION */
+
+ dd_emit(ctx, 1, 0); /* ffffffff sifc OPERATION */
+ }
+
+ /* tesla state */
+ dd_emit(ctx, 1, 0); /* 0000000f GP_TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f GP_SAMPLERS_LOG2 */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* ffffffff */
+ dd_emit(ctx, 1, 4); /* 000000ff UNK12B0_0 */
+ dd_emit(ctx, 1, 0x70); /* 000000ff UNK12B0_1 */
+ dd_emit(ctx, 1, 0x80); /* 000000ff UNK12B0_3 */
+ dd_emit(ctx, 1, 0); /* 000000ff UNK12B0_2 */
+ dd_emit(ctx, 1, 0); /* 0000000f FP_TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f FP_SAMPLERS_LOG2 */
+ if (IS_NVA3F(device->chipset)) {
+ dd_emit(ctx, 1, 0); /* ffffffff */
+ dd_emit(ctx, 1, 0); /* 0000007f MULTISAMPLE_SAMPLES_LOG2 */
+ } else {
+ dd_emit(ctx, 1, 0); /* 0000000f MULTISAMPLE_SAMPLES_LOG2 */
+ }
+ dd_emit(ctx, 1, 0xc); /* 000000ff SEMANTIC_COLOR.BFC0_ID */
+ if (device->chipset != 0x50)
+ dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_COLOR.CLMP_EN */
+ dd_emit(ctx, 1, 8); /* 000000ff SEMANTIC_COLOR.COLR_NR */
+ dd_emit(ctx, 1, 0x14); /* 000000ff SEMANTIC_COLOR.FFC0_ID */
+ if (device->chipset == 0x50) {
+ dd_emit(ctx, 1, 0); /* 000000ff SEMANTIC_LAYER */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ } else {
+ dd_emit(ctx, 1, 0); /* 00000001 SEMANTIC_PTSZ.ENABLE */
+ dd_emit(ctx, 1, 0x29); /* 000000ff SEMANTIC_PTSZ.PTSZ_ID */
+ dd_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM */
+ dd_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ dd_emit(ctx, 1, 8); /* 0000000f SMENATIC_CLIP.CLIP_HIGH */
+ dd_emit(ctx, 1, 4); /* 000000ff SEMANTIC_CLIP.CLIP_LO */
+ dd_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK1900 */
+ }
+ dd_emit(ctx, 1, 0); /* 00000007 RT_CONTROL_MAP0 */
+ dd_emit(ctx, 1, 1); /* 00000007 RT_CONTROL_MAP1 */
+ dd_emit(ctx, 1, 2); /* 00000007 RT_CONTROL_MAP2 */
+ dd_emit(ctx, 1, 3); /* 00000007 RT_CONTROL_MAP3 */
+ dd_emit(ctx, 1, 4); /* 00000007 RT_CONTROL_MAP4 */
+ dd_emit(ctx, 1, 5); /* 00000007 RT_CONTROL_MAP5 */
+ dd_emit(ctx, 1, 6); /* 00000007 RT_CONTROL_MAP6 */
+ dd_emit(ctx, 1, 7); /* 00000007 RT_CONTROL_MAP7 */
+ dd_emit(ctx, 1, 1); /* 0000000f RT_CONTROL_COUNT */
+ dd_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_UNK */
+ dd_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff RT_FORMAT */
+ dd_emit(ctx, 7, 0); /* 000000ff RT_FORMAT */
+ if (device->chipset != 0x50)
+ dd_emit(ctx, 3, 0); /* 1, 1, 1 */
+ else
+ dd_emit(ctx, 2, 0); /* 1, 1 */
+ dd_emit(ctx, 1, 0); /* ffffffff GP_ENABLE */
+ dd_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT*/
+ dd_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ dd_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ if (IS_NVA3F(device->chipset)) {
+ dd_emit(ctx, 1, 3); /* 00000003 */
+ dd_emit(ctx, 1, 0); /* 00000001 UNK1418. Alone. */
+ }
+ if (device->chipset != 0x50)
+ dd_emit(ctx, 1, 3); /* 00000003 UNK15AC */
+ dd_emit(ctx, 1, 1); /* ffffffff RASTERIZE_ENABLE */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.EXPORTS_Z */
+ if (device->chipset != 0x50)
+ dd_emit(ctx, 1, 0); /* 00000001 FP_CONTROL.MULTIPLE_RESULTS */
+ dd_emit(ctx, 1, 0x12); /* 000000ff FP_INTERPOLANT_CTRL.COUNT */
+ dd_emit(ctx, 1, 0x10); /* 000000ff FP_INTERPOLANT_CTRL.COUNT_NONFLAT */
+ dd_emit(ctx, 1, 0xc); /* 000000ff FP_INTERPOLANT_CTRL.OFFSET */
+ dd_emit(ctx, 1, 1); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.W */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.X */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Y */
+ dd_emit(ctx, 1, 0); /* 00000001 FP_INTERPOLANT_CTRL.UMASK.Z */
+ dd_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */
+ dd_emit(ctx, 1, 2); /* ffffffff REG_MODE */
+ dd_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
+ if (device->chipset >= 0xa0)
+ dd_emit(ctx, 1, 0); /* ffffffff */
+ dd_emit(ctx, 1, 0); /* 00000001 GP_BUILTIN_RESULT_EN.LAYER_IDX */
+ dd_emit(ctx, 1, 0); /* ffffffff STRMOUT_ENABLE */
+ dd_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
+ dd_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
+ dd_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE*/
+ if (device->chipset != 0x50)
+ dd_emit(ctx, 8, 0); /* 00000001 */
+ if (device->chipset >= 0xa0) {
+ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.COMP */
+ dd_emit(ctx, 1, 1); /* 00000007 VTX_ATTR_DEFINE.SIZE */
+ dd_emit(ctx, 1, 2); /* 00000007 VTX_ATTR_DEFINE.TYPE */
+ dd_emit(ctx, 1, 0); /* 000000ff VTX_ATTR_DEFINE.ATTR */
+ }
+ dd_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ dd_emit(ctx, 1, 0x14); /* 0000001f ZETA_FORMAT */
+ dd_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ dd_emit(ctx, 1, 0); /* 0000000f VP_TEXTURES_LOG2 */
+ dd_emit(ctx, 1, 0); /* 0000000f VP_SAMPLERS_LOG2 */
+ if (IS_NVA3F(device->chipset))
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_BACK */
+ if (device->chipset >= 0xa0)
+ dd_emit(ctx, 1, 0); /* 00000003 VTX_ATTR_DEFINE.SIZE - 1 */
+ dd_emit(ctx, 1, 0); /* 0000ffff CB_ADDR_INDEX */
+ if (device->chipset >= 0xa0)
+ dd_emit(ctx, 1, 0); /* 00000003 */
+ dd_emit(ctx, 1, 0); /* 00000001 CULL_FACE_ENABLE */
+ dd_emit(ctx, 1, 1); /* 00000003 CULL_FACE */
+ dd_emit(ctx, 1, 0); /* 00000001 FRONT_FACE */
+ dd_emit(ctx, 1, 2); /* 00000003 POLYGON_MODE_FRONT */
+ dd_emit(ctx, 1, 0x1000); /* 00007fff UNK141C */
+ if (device->chipset != 0x50) {
+ dd_emit(ctx, 1, 0xe00); /* 7fff */
+ dd_emit(ctx, 1, 0x1000); /* 7fff */
+ dd_emit(ctx, 1, 0x1e00); /* 7fff */
+ }
+ dd_emit(ctx, 1, 0); /* 00000001 BEGIN_END_ACTIVE */
+ dd_emit(ctx, 1, 1); /* 00000001 POLYGON_MODE_??? */
+ dd_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP / 4 rounded up */
+ dd_emit(ctx, 1, 1); /* 000000ff FP_REG_ALLOC_TEMP... without /4? */
+ dd_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP / 4 rounded up */
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK0 nonempty */
+ dd_emit(ctx, 1, 0); /* 00000001 VTX_ATTR_MASK_UNK1 nonempty */
+ dd_emit(ctx, 1, 0x200); /* 0003ffff GP_VERTEX_OUTPUT_COUNT*GP_REG_ALLOC_RESULT */
+ if (IS_NVA3F(device->chipset))
+ dd_emit(ctx, 1, 0x200);
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ if (device->chipset < 0xa0) {
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0x70); /* 000000ff */
+ dd_emit(ctx, 1, 0x80); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0x70); /* 000000ff */
+ dd_emit(ctx, 1, 0x80); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ } else {
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0xf0); /* 000000ff */
+ dd_emit(ctx, 1, 0xff); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 00000001 */
+ dd_emit(ctx, 1, 1); /* 00000001 */
+ dd_emit(ctx, 1, 0xf0); /* 000000ff */
+ dd_emit(ctx, 1, 0xff); /* 000000ff */
+ dd_emit(ctx, 1, 0); /* 000000ff */
+ dd_emit(ctx, 1, 9); /* 0000003f UNK114C.COMP,SIZE */
+ }
+
+ /* eng2d state */
+ dd_emit(ctx, 1, 0); /* 00000001 eng2d COLOR_KEY_ENABLE */
+ dd_emit(ctx, 1, 0); /* 00000007 eng2d COLOR_KEY_FORMAT */
+ dd_emit(ctx, 1, 1); /* ffffffff eng2d DST_DEPTH */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DST_FORMAT */
+ dd_emit(ctx, 1, 0); /* ffffffff eng2d DST_LAYER */
+ dd_emit(ctx, 1, 1); /* 00000001 eng2d DST_LINEAR */
+ dd_emit(ctx, 1, 0); /* 00000007 eng2d PATTERN_COLOR_FORMAT */
+ dd_emit(ctx, 1, 0); /* 00000007 eng2d OPERATION */
+ dd_emit(ctx, 1, 0); /* 00000003 eng2d PATTERN_SELECT */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SIFC_FORMAT */
+ dd_emit(ctx, 1, 0); /* 00000001 eng2d SIFC_BITMAP_ENABLE */
+ dd_emit(ctx, 1, 2); /* 00000003 eng2d SIFC_BITMAP_UNK808 */
+ dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DU_DX_FRACT */
+ dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DU_DX_INT */
+ dd_emit(ctx, 1, 0); /* ffffffff eng2d BLIT_DV_DY_FRACT */
+ dd_emit(ctx, 1, 1); /* ffffffff eng2d BLIT_DV_DY_INT */
+ dd_emit(ctx, 1, 0); /* 00000001 eng2d BLIT_CONTROL_FILTER */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d DRAW_COLOR_FORMAT */
+ dd_emit(ctx, 1, 0xcf); /* 000000ff eng2d SRC_FORMAT */
+ dd_emit(ctx, 1, 1); /* 00000001 eng2d SRC_LINEAR #2 */
+
+ num = ctx->ctxvals_pos - base;
+ ctx->ctxvals_pos = base;
+ if (IS_NVA3F(device->chipset))
+ cp_ctx(ctx, 0x404800, num);
+ else
+ cp_ctx(ctx, 0x405400, num);
+}
+
+/*
+ * xfer areas. These are a pain.
+ *
+ * There are 2 xfer areas: the first one is big and contains all sorts of
+ * stuff, the second is small and contains some per-TP context.
+ *
+ * Each area is split into 8 "strands". The areas, when saved to grctx,
+ * are made of 8-word blocks. Each block contains a single word from
+ * each strand. The strands are independent of each other, their
+ * addresses are unrelated to each other, and data in them is closely
+ * packed together. The strand layout varies a bit between cards: here
+ * and there, a single word is thrown out in the middle and the whole
+ * strand is offset by a bit from corresponding one on another chipset.
+ * For this reason, addresses of stuff in strands are almost useless.
+ * Knowing sequence of stuff and size of gaps between them is much more
+ * useful, and that's how we build the strands in our generator.
+ *
+ * NVA0 takes this mess to a whole new level by cutting the old strands
+ * into a few dozen pieces [known as genes], rearranging them randomly,
+ * and putting them back together to make new strands. Hopefully these
+ * genes correspond more or less directly to the same PGRAPH subunits
+ * as in 400040 register.
+ *
+ * The most common value in default context is 0, and when the genes
+ * are separated by 0's, gene bounduaries are quite speculative...
+ * some of them can be clearly deduced, others can be guessed, and yet
+ * others won't be resolved without figuring out the real meaning of
+ * given ctxval. For the same reason, ending point of each strand
+ * is unknown. Except for strand 0, which is the longest strand and
+ * its end corresponds to end of the whole xfer.
+ *
+ * An unsolved mystery is the seek instruction: it takes an argument
+ * in bits 8-18, and that argument is clearly the place in strands to
+ * seek to... but the offsets don't seem to correspond to offsets as
+ * seen in grctx. Perhaps there's another, real, not randomly-changing
+ * addressing in strands, and the xfer insn just happens to skip over
+ * the unused bits? NV10-NV30 PIPE comes to mind...
+ *
+ * As far as I know, there's no way to access the xfer areas directly
+ * without the help of ctxprog.
+ */
+
+static void
+xf_emit(struct nvkm_grctx *ctx, int num, u32 val) {
+ int i;
+ if (val && ctx->mode == NVKM_GRCTX_VALS)
+ for (i = 0; i < num; i++)
+ nv_wo32(ctx->data, 4 * (ctx->ctxvals_pos + (i << 3)), val);
+ ctx->ctxvals_pos += num << 3;
+}
+
+/* Gene declarations... */
+
+static void nv50_gr_construct_gene_dispatch(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_m2mf(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ccache(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk10xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk14xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_zcull(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_clipid(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk24xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_vfetch(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_eng2d(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_csched(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk1cxx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_strmout(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_unk34xx(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ropm1(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ropm2(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_gene_ropc(struct nvkm_grctx *ctx);
+static void nv50_gr_construct_xfer_tp(struct nvkm_grctx *ctx);
+
+static void
+nv50_gr_construct_xfer1(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+ int offset;
+ int size = 0;
+ u32 units = nv_rd32 (ctx->device, 0x1540);
+
+ offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
+ ctx->ctxvals_base = offset;
+
+ if (device->chipset < 0xa0) {
+ /* Strand 0 */
+ ctx->ctxvals_pos = offset;
+ nv50_gr_construct_gene_dispatch(ctx);
+ nv50_gr_construct_gene_m2mf(ctx);
+ nv50_gr_construct_gene_unk24xx(ctx);
+ nv50_gr_construct_gene_clipid(ctx);
+ nv50_gr_construct_gene_zcull(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 1 */
+ ctx->ctxvals_pos = offset + 0x1;
+ nv50_gr_construct_gene_vfetch(ctx);
+ nv50_gr_construct_gene_eng2d(ctx);
+ nv50_gr_construct_gene_csched(ctx);
+ nv50_gr_construct_gene_ropm1(ctx);
+ nv50_gr_construct_gene_ropm2(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 2 */
+ ctx->ctxvals_pos = offset + 0x2;
+ nv50_gr_construct_gene_ccache(ctx);
+ nv50_gr_construct_gene_unk1cxx(ctx);
+ nv50_gr_construct_gene_strmout(ctx);
+ nv50_gr_construct_gene_unk14xx(ctx);
+ nv50_gr_construct_gene_unk10xx(ctx);
+ nv50_gr_construct_gene_unk34xx(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 3: per-ROP group state */
+ ctx->ctxvals_pos = offset + 3;
+ for (i = 0; i < 6; i++)
+ if (units & (1 << (i + 16)))
+ nv50_gr_construct_gene_ropc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strands 4-7: per-TP state */
+ for (i = 0; i < 4; i++) {
+ ctx->ctxvals_pos = offset + 4 + i;
+ if (units & (1 << (2 * i)))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << (2 * i + 1)))
+ nv50_gr_construct_xfer_tp(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+ } else {
+ /* Strand 0 */
+ ctx->ctxvals_pos = offset;
+ nv50_gr_construct_gene_dispatch(ctx);
+ nv50_gr_construct_gene_m2mf(ctx);
+ nv50_gr_construct_gene_unk34xx(ctx);
+ nv50_gr_construct_gene_csched(ctx);
+ nv50_gr_construct_gene_unk1cxx(ctx);
+ nv50_gr_construct_gene_strmout(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 1 */
+ ctx->ctxvals_pos = offset + 1;
+ nv50_gr_construct_gene_unk10xx(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 2 */
+ ctx->ctxvals_pos = offset + 2;
+ if (device->chipset == 0xa0)
+ nv50_gr_construct_gene_unk14xx(ctx);
+ nv50_gr_construct_gene_unk24xx(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 3 */
+ ctx->ctxvals_pos = offset + 3;
+ nv50_gr_construct_gene_vfetch(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 4 */
+ ctx->ctxvals_pos = offset + 4;
+ nv50_gr_construct_gene_ccache(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 5 */
+ ctx->ctxvals_pos = offset + 5;
+ nv50_gr_construct_gene_ropm2(ctx);
+ nv50_gr_construct_gene_ropm1(ctx);
+ /* per-ROP context */
+ for (i = 0; i < 8; i++)
+ if (units & (1<<(i+16)))
+ nv50_gr_construct_gene_ropc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 6 */
+ ctx->ctxvals_pos = offset + 6;
+ nv50_gr_construct_gene_zcull(ctx);
+ nv50_gr_construct_gene_clipid(ctx);
+ nv50_gr_construct_gene_eng2d(ctx);
+ if (units & (1 << 0))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 1))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 2))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 3))
+ nv50_gr_construct_xfer_tp(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 7 */
+ ctx->ctxvals_pos = offset + 7;
+ if (device->chipset == 0xa0) {
+ if (units & (1 << 4))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 5))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 6))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 7))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 8))
+ nv50_gr_construct_xfer_tp(ctx);
+ if (units & (1 << 9))
+ nv50_gr_construct_xfer_tp(ctx);
+ } else {
+ nv50_gr_construct_gene_unk14xx(ctx);
+ }
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+
+ ctx->ctxvals_pos = offset + size * 8;
+ ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
+ cp_lsr (ctx, offset);
+ cp_out (ctx, CP_SET_XFER_POINTER);
+ cp_lsr (ctx, size);
+ cp_out (ctx, CP_SEEK_1);
+ cp_out (ctx, CP_XFER_1);
+ cp_wait(ctx, XFER, BUSY);
+}
+
+/*
+ * non-trivial demagiced parts of ctx init go here
+ */
+
+static void
+nv50_gr_construct_gene_dispatch(struct nvkm_grctx *ctx)
+{
+ /* start of strand 0 */
+ struct nvkm_device *device = ctx->device;
+ /* SEEK */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 5, 0);
+ else if (!IS_NVA3F(device->chipset))
+ xf_emit(ctx, 6, 0);
+ else
+ xf_emit(ctx, 4, 0);
+ /* SEEK */
+ /* the PGRAPH's internal FIFO */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 8*3, 0);
+ else
+ xf_emit(ctx, 0x100*3, 0);
+ /* and another bonus slot?!? */
+ xf_emit(ctx, 3, 0);
+ /* and YET ANOTHER bonus slot? */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 3, 0);
+ /* SEEK */
+ /* CTX_SWITCH: caches of gr objects bound to subchannels. 8 values, last used index */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ xf_emit(ctx, 9, 0);
+ /* SEEK */
+ if (device->chipset < 0x90)
+ xf_emit(ctx, 4, 0);
+ /* SEEK */
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 6*2, 0);
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 6*2, 0);
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 0x1c, 0);
+ else if (device->chipset < 0xa0)
+ xf_emit(ctx, 0x1e, 0);
+ else
+ xf_emit(ctx, 0x22, 0);
+ /* SEEK */
+ xf_emit(ctx, 0x15, 0);
+}
+
+static void
+nv50_gr_construct_gene_m2mf(struct nvkm_grctx *ctx)
+{
+ /* Strand 0, right after dispatch */
+ struct nvkm_device *device = ctx->device;
+ int smallm2mf = 0;
+ if (device->chipset < 0x92 || device->chipset == 0x98)
+ smallm2mf = 1;
+ /* SEEK */
+ xf_emit (ctx, 1, 0); /* DMA_NOTIFY instance >> 4 */
+ xf_emit (ctx, 1, 0); /* DMA_BUFFER_IN instance >> 4 */
+ xf_emit (ctx, 1, 0); /* DMA_BUFFER_OUT instance >> 4 */
+ xf_emit (ctx, 1, 0); /* OFFSET_IN */
+ xf_emit (ctx, 1, 0); /* OFFSET_OUT */
+ xf_emit (ctx, 1, 0); /* PITCH_IN */
+ xf_emit (ctx, 1, 0); /* PITCH_OUT */
+ xf_emit (ctx, 1, 0); /* LINE_LENGTH */
+ xf_emit (ctx, 1, 0); /* LINE_COUNT */
+ xf_emit (ctx, 1, 0x21); /* FORMAT: bits 0-4 INPUT_INC, bits 5-9 OUTPUT_INC */
+ xf_emit (ctx, 1, 1); /* LINEAR_IN */
+ xf_emit (ctx, 1, 0x2); /* TILING_MODE_IN: bits 0-2 y tiling, bits 3-5 z tiling */
+ xf_emit (ctx, 1, 0x100); /* TILING_PITCH_IN */
+ xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_IN */
+ xf_emit (ctx, 1, 1); /* TILING_DEPTH_IN */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_IN_Z */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_IN */
+ xf_emit (ctx, 1, 1); /* LINEAR_OUT */
+ xf_emit (ctx, 1, 0x2); /* TILING_MODE_OUT: bits 0-2 y tiling, bits 3-5 z tiling */
+ xf_emit (ctx, 1, 0x100); /* TILING_PITCH_OUT */
+ xf_emit (ctx, 1, 0x100); /* TILING_HEIGHT_OUT */
+ xf_emit (ctx, 1, 1); /* TILING_DEPTH_OUT */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT_Z */
+ xf_emit (ctx, 1, 0); /* TILING_POSITION_OUT */
+ xf_emit (ctx, 1, 0); /* OFFSET_IN_HIGH */
+ xf_emit (ctx, 1, 0); /* OFFSET_OUT_HIGH */
+ /* SEEK */
+ if (smallm2mf)
+ xf_emit(ctx, 0x40, 0); /* 20 * ffffffff, 3ffff */
+ else
+ xf_emit(ctx, 0x100, 0); /* 80 * ffffffff, 3ffff */
+ xf_emit(ctx, 4, 0); /* 1f/7f, 0, 1f/7f, 0 [1f for smallm2mf, 7f otherwise] */
+ /* SEEK */
+ if (smallm2mf)
+ xf_emit(ctx, 0x400, 0); /* ffffffff */
+ else
+ xf_emit(ctx, 0x800, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ff/1ff, 0, 0, 0 [ff for smallm2mf, 1ff otherwise] */
+ /* SEEK */
+ xf_emit(ctx, 0x40, 0); /* 20 * bits ffffffff, 3ffff */
+ xf_emit(ctx, 0x6, 0); /* 1f, 0, 1f, 0, 1f, 0 */
+}
+
+static void
+nv50_gr_construct_gene_ccache(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ xf_emit(ctx, 2, 0); /* RO */
+ xf_emit(ctx, 0x800, 0); /* ffffffff */
+ switch (device->chipset) {
+ case 0x50:
+ case 0x92:
+ case 0xa0:
+ xf_emit(ctx, 0x2b, 0);
+ break;
+ case 0x84:
+ xf_emit(ctx, 0x29, 0);
+ break;
+ case 0x94:
+ case 0x96:
+ case 0xa3:
+ xf_emit(ctx, 0x27, 0);
+ break;
+ case 0x86:
+ case 0x98:
+ case 0xa5:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
+ xf_emit(ctx, 0x25, 0);
+ break;
+ }
+ /* CB bindings, 0x80 of them. first word is address >> 8, second is
+ * size >> 4 | valid << 24 */
+ xf_emit(ctx, 0x100, 0); /* ffffffff CB_DEF */
+ xf_emit(ctx, 1, 0); /* 0000007f CB_ADDR_BUFFER */
+ xf_emit(ctx, 1, 0); /* 0 */
+ xf_emit(ctx, 0x30, 0); /* ff SET_PROGRAM_CB */
+ xf_emit(ctx, 1, 0); /* 3f last SET_PROGRAM_CB */
+ xf_emit(ctx, 4, 0); /* RO */
+ xf_emit(ctx, 0x100, 0); /* ffffffff */
+ xf_emit(ctx, 8, 0); /* 1f, 0, 0, ... */
+ xf_emit(ctx, 8, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 3 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_CODE_CB */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TIC */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TSC */
+ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */
+ xf_emit(ctx, 1, 0); /* 000000ff TIC_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff TIC_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x3fffff); /* 003fffff TIC_LIMIT */
+ xf_emit(ctx, 1, 0); /* 000000ff TSC_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff TSC_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x1fff); /* 000fffff TSC_LIMIT */
+ xf_emit(ctx, 1, 0); /* 000000ff VP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff VP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00ffffff VP_START_ID */
+ xf_emit(ctx, 1, 0); /* 000000ff CB_DEF_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff CB_DEF_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff GP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff GP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00ffffff GP_START_ID */
+ xf_emit(ctx, 1, 0); /* 000000ff FP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 00ffffff FP_START_ID */
+}
+
+static void
+nv50_gr_construct_gene_unk10xx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+ /* end of area 2 on pre-NVA0, area 1 on NVAx */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff);
+ else
+ xf_emit(ctx, 1, 0x7ff); /* 000007ff */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ for (i = 0; i < 8; i++) {
+ switch (device->chipset) {
+ case 0x50:
+ case 0x86:
+ case 0x98:
+ case 0xaa:
+ case 0xac:
+ xf_emit(ctx, 0xa0, 0); /* ffffffff */
+ break;
+ case 0x84:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 0x120, 0);
+ break;
+ case 0xa5:
+ case 0xa8:
+ xf_emit(ctx, 0x100, 0); /* ffffffff */
+ break;
+ case 0xa0:
+ case 0xa3:
+ case 0xaf:
+ xf_emit(ctx, 0x400, 0); /* ffffffff */
+ break;
+ }
+ xf_emit(ctx, 4, 0); /* 3f, 0, 0, 0 */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ }
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 1); /* 00000001 RASTERIZE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0x27); /* 000000ff UNK0FD4 */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+}
+
+static void
+nv50_gr_construct_gene_unk34xx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ /* end of area 2 on pre-NVA0, area 1 on NVAx */
+ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */
+ xf_emit(ctx, 1, 0); /* 00000003 VIEWPORT_CLIP_MODE */
+ xf_emit(ctx, 0x10, 0x04000000); /* 07ffffff VIEWPORT_CLIP_HORIZ*8, VIEWPORT_CLIP_VERT*8 */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */
+ xf_emit(ctx, 0x20, 0); /* ffffffff POLYGON_STIPPLE */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0x1fe21); /* 0001ffff tesla UNK0FAC */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0x0fac6881);
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 1);
+ xf_emit(ctx, 3, 0);
+ }
+}
+
+static void
+nv50_gr_construct_gene_unk14xx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ /* middle of area 2 on pre-NVA0, beginning of area 2 on NVA0, area 7 on >NVA0 */
+ if (device->chipset != 0x50) {
+ xf_emit(ctx, 5, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 2, 4); /* 7f, ff */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 000000ff VP_CLIP_DISTANCE_ENABLE */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 3ff */
+ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1940 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */
+ xf_emit(ctx, 1, 0x804); /* 00000fff SEMANTIC_CLIP */
+ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 0x7f); /* 000000ff tesla UNK0FFC */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 1); /* 00000001 SHADE_MODEL */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0D7C */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0F8C */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
+ else
+ xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_SCALE: X0, Y0, Z0, X1, Y1, ... */
+ xf_emit(ctx, 3, 0); /* f, 0, 0 */
+ xf_emit(ctx, 3, 0); /* ffffffff last VIEWPORT_SCALE? */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 1); /* 00000001 VIEWPORT_TRANSFORM_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
+ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 0x30, 0); /* ffffffff VIEWPORT_TRANSLATE */
+ xf_emit(ctx, 3, 0); /* f, 0, 0 */
+ xf_emit(ctx, 3, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 2, 0x88); /* 000001ff tesla UNK19D8 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
+ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+ if (device->chipset != 0x50) {
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ }
+ xf_emit(ctx, 0x20, 0); /* 10xbits ffffffff, 3fffff. SCISSOR_* */
+ xf_emit(ctx, 1, 0); /* f */
+ xf_emit(ctx, 1, 0); /* 0? */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 003fffff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0x26); /* 000000ff SEMANTIC_LAYER */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+}
+
+static void
+nv50_gr_construct_gene_zcull(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ /* end of strand 0 on pre-NVA0, beginning of strand 6 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */
+ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
+ xf_emit(ctx, 1, 0); /* 0000ffff */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1108 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */
+ /* SEEK */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
+ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
+ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff/3ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000001 VIEWPORT_CLIP_RECTS_EN */
+ xf_emit(ctx, 1, 3); /* 00000003 FP_CTRL_UNK196C */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1968 */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 0fffffff tesla UNK1104 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK151C */
+}
+
+static void
+nv50_gr_construct_gene_clipid(struct nvkm_grctx *ctx)
+{
+ /* middle of strand 0 on pre-NVA0 [after 24xx], middle of area 6 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000007 UNK0FB4 */
+ /* SEEK */
+ xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_HORIZ */
+ xf_emit(ctx, 4, 0); /* 07ffffff CLIPID_REGION_VERT */
+ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
+ xf_emit(ctx, 2, 0x04000000); /* 07ffffff UNK1508 */
+ xf_emit(ctx, 1, 0); /* 00000001 CLIPID_ENABLE */
+ xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_WIDTH */
+ xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ID */
+ xf_emit(ctx, 1, 0); /* 000000ff CLIPID_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff CLIPID_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x80); /* 00003fff CLIPID_HEIGHT */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_CLIPID */
+}
+
+static void
+nv50_gr_construct_gene_unk24xx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+ /* middle of strand 0 on pre-NVA0 [after m2mf], end of strand 2 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 0x33, 0);
+ /* SEEK */
+ xf_emit(ctx, 2, 0);
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ /* SEEK */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 4, 0); /* RO */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+ xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
+
+ xf_emit(ctx, 4, 0); /* RO */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+ xf_emit(ctx, 9, 0); /* ffffffff, 7ff */
+ } else {
+ xf_emit(ctx, 0xc, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+
+ /* SEEK */
+ xf_emit(ctx, 0xc, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0xe10, 0); /* 190 * 9: 8*ffffffff, 7ff */
+ xf_emit(ctx, 1, 0); /* 1ff */
+ xf_emit(ctx, 8, 0); /* 0? */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 1); /* 00000001 */
+ /* SEEK */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 2, 4); /* 000000ff */
+ xf_emit(ctx, 1, 0x80c14); /* 01ffffff SEMANTIC_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0x27); /* 000000ff SEMANTIC_PRIM_ID */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 1); /* 00000001 */
+ for (i = 0; i < 10; i++) {
+ /* SEEK */
+ xf_emit(ctx, 0x40, 0); /* ffffffff */
+ xf_emit(ctx, 0x10, 0); /* 3, 0, 0.... */
+ xf_emit(ctx, 0x10, 0); /* ffffffff */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_CTRL */
+ xf_emit(ctx, 1, 1); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ffffffff NOPERSPECTIVE_BITMAP */
+ xf_emit(ctx, 0x10, 0); /* 00ffffff POINT_COORD_REPLACE_MAP */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 000003ff */
+}
+
+static void
+nv50_gr_construct_gene_vfetch(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int acnt = 0x10, rep, i;
+ /* beginning of strand 1 on pre-NVA0, strand 3 on NVAx */
+ if (IS_NVA3F(device->chipset))
+ acnt = 0x20;
+ /* SEEK */
+ if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK13A4 */
+ xf_emit(ctx, 1, 1); /* 00000fff tesla UNK1318 */
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff VERTEX_BUFFER_FIRST */
+ xf_emit(ctx, 1, 0); /* 00000001 PRIMITIVE_RESTART_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK0DE8 */
+ xf_emit(ctx, 1, 0); /* ffffffff PRIMITIVE_RESTART_INDEX */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATR_MASK_UNK0DD0 */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 0x20); /* 0000ffff tesla UNK129C */
+ xf_emit(ctx, 1, 0); /* 000000ff turing UNK370??? */
+ xf_emit(ctx, 1, 0); /* 0000ffff turing USER_PARAM_COUNT */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0xb, 0); /* RO */
+ else if (device->chipset >= 0xa0)
+ xf_emit(ctx, 0x9, 0); /* RO */
+ else
+ xf_emit(ctx, 0x8, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 00000001 EDGE_FLAG */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ /* SEEK */
+ xf_emit(ctx, 0xc, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 7f/ff */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 4); /* 000001ff UNK1A28 */
+ xf_emit(ctx, 1, 8); /* 000001ff UNK0DF0 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff); /* 3ff tesla UNK0D68 */
+ else
+ xf_emit(ctx, 1, 0x7ff); /* 7ff tesla UNK0D68 */
+ if (device->chipset == 0xa8)
+ xf_emit(ctx, 1, 0x1e00); /* 7fff */
+ /* SEEK */
+ xf_emit(ctx, 0xc, 0); /* RO or close */
+ /* SEEK */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ if (device->chipset > 0x50 && device->chipset < 0xa0)
+ xf_emit(ctx, 2, 0); /* ffffffff */
+ else
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0FD8 */
+ /* SEEK */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 0x10, 0); /* 0? */
+ xf_emit(ctx, 2, 0); /* weird... */
+ xf_emit(ctx, 2, 0); /* RO */
+ } else {
+ xf_emit(ctx, 8, 0); /* 0? */
+ xf_emit(ctx, 1, 0); /* weird... */
+ xf_emit(ctx, 2, 0); /* RO */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffffffff VB_ELEMENT_BASE */
+ xf_emit(ctx, 1, 0); /* ffffffff UNK1438 */
+ xf_emit(ctx, acnt, 0); /* 1 tesla UNK1000 */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1118? */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */
+ xf_emit(ctx, 1, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_UNK90C */
+ xf_emit(ctx, 1, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* RO */
+ xf_emit(ctx, 2, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK111C? */
+ xf_emit(ctx, 1, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 000000ff UNK15F4_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff UNK15F4_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 000000ff UNK0F84_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff UNK0F84_ADDRESS_LOW */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 00003fff VERTEX_ARRAY_ATTRIB_OFFSET */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 00000fff VERTEX_ARRAY_STRIDE */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_ARRAY_LOW */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_ARRAY_HIGH */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* ffffffff VERTEX_LIMIT_LOW */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ xf_emit(ctx, acnt, 0); /* 000000ff VERTEX_LIMIT_HIGH */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ /* SEEK */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, acnt, 0); /* f */
+ xf_emit(ctx, 3, 0); /* f/1f */
+ }
+ /* SEEK */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 2, 0); /* RO */
+ else
+ xf_emit(ctx, 5, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffff DMA_VTXBUF */
+ /* SEEK */
+ if (device->chipset < 0xa0) {
+ xf_emit(ctx, 0x41, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0x11, 0); /* RO */
+ } else if (!IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x50, 0); /* RO */
+ else
+ xf_emit(ctx, 0x58, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, 1, 1); /* 1 UNK0DEC */
+ /* SEEK */
+ xf_emit(ctx, acnt*4, 0); /* ffffffff VTX_ATTR */
+ xf_emit(ctx, 4, 0); /* f/1f, 0, 0, 0 */
+ /* SEEK */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x1d, 0); /* RO */
+ else
+ xf_emit(ctx, 0x16, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ /* SEEK */
+ if (device->chipset < 0xa0)
+ xf_emit(ctx, 8, 0); /* RO */
+ else if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0xc, 0); /* RO */
+ else
+ xf_emit(ctx, 7, 0); /* RO */
+ /* SEEK */
+ xf_emit(ctx, 0xa, 0); /* RO */
+ if (device->chipset == 0xa0)
+ rep = 0xc;
+ else
+ rep = 4;
+ for (i = 0; i < rep; i++) {
+ /* SEEK */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x20, 0); /* ffffffff */
+ xf_emit(ctx, 0x200, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* 7f/ff, 0, 0, 0 */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ }
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 113/111 */
+ xf_emit(ctx, 1, 0xf); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, (acnt/8)-1, 0); /* ffffffff VP_ATTR_EN */
+ xf_emit(ctx, acnt/8, 0); /* ffffffff VTX_ATTR_MASK_UNK0DD0 */
+ xf_emit(ctx, 1, 0); /* 0000000f VP_GP_BUILTIN_ATTR_EN */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 7, 0); /* weird... */
+ else
+ xf_emit(ctx, 5, 0); /* weird... */
+}
+
+static void
+nv50_gr_construct_gene_eng2d(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ /* middle of strand 1 on pre-NVA0 [after vfetch], middle of strand 6 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 2, 0); /* 0001ffff CLIP_X, CLIP_Y */
+ xf_emit(ctx, 2, 0); /* 0000ffff CLIP_W, CLIP_H */
+ xf_emit(ctx, 1, 0); /* 00000001 CLIP_ENABLE */
+ if (device->chipset < 0xa0) {
+ /* this is useless on everything but the original NV50,
+ * guess they forgot to nuke it. Or just didn't bother. */
+ xf_emit(ctx, 2, 0); /* 0000ffff IFC_CLIP_X, Y */
+ xf_emit(ctx, 2, 1); /* 0000ffff IFC_CLIP_W, H */
+ xf_emit(ctx, 1, 0); /* 00000001 IFC_CLIP_ENABLE */
+ }
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */
+ xf_emit(ctx, 1, 0x11); /* 3f[NV50]/7f[NV84+] DST_FORMAT */
+ xf_emit(ctx, 1, 0); /* 0001ffff DRAW_POINT_X */
+ xf_emit(ctx, 1, 8); /* 0000000f DRAW_UNK58C */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_X_FRACT */
+ xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_X_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DST_Y_FRACT */
+ xf_emit(ctx, 1, 0); /* 0001ffff SIFC_DST_Y_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DX_DU_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DX_DU_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff SIFC_DY_DV_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff SIFC_DY_DV_INT */
+ xf_emit(ctx, 1, 1); /* 0000ffff SIFC_WIDTH */
+ xf_emit(ctx, 1, 1); /* 0000ffff SIFC_HEIGHT */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */
+ xf_emit(ctx, 1, 2); /* 00000003 SIFC_BITMAP_UNK808 */
+ xf_emit(ctx, 1, 0); /* 00000003 SIFC_BITMAP_LINE_PACK_MODE */
+ xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_LSB_FIRST */
+ xf_emit(ctx, 1, 0); /* 00000001 SIFC_BITMAP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_X */
+ xf_emit(ctx, 1, 0); /* 0000ffff BLIT_DST_Y */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_W */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLIT_DST_H */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_X_FRACT */
+ xf_emit(ctx, 1, 0); /* 0001ffff BLIT_SRC_X_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_SRC_Y_FRACT */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK888 */
+ xf_emit(ctx, 1, 4); /* 0000003f UNK884 */
+ xf_emit(ctx, 1, 0); /* 00000007 UNK880 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK0FB8 */
+ xf_emit(ctx, 1, 0x15); /* 000000ff tesla UNK128C */
+ xf_emit(ctx, 2, 0); /* 00000007, ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK260 */
+ xf_emit(ctx, 1, 0x4444480); /* 1fffffff UNK870 */
+ /* SEEK */
+ xf_emit(ctx, 0x10, 0);
+ /* SEEK */
+ xf_emit(ctx, 0x27, 0);
+}
+
+static void
+nv50_gr_construct_gene_csched(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ /* middle of strand 1 on pre-NVA0 [after eng2d], middle of strand 0 on NVAx */
+ /* SEEK */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY... what is it doing here??? */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1924 */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* ffffffff turing UNK364 */
+ xf_emit(ctx, 1, 0); /* 0000000f turing UNK36C */
+ xf_emit(ctx, 1, 0); /* 0000ffff USER_PARAM_COUNT */
+ xf_emit(ctx, 1, 0x100); /* 00ffffff turing UNK384 */
+ xf_emit(ctx, 1, 0); /* 0000000f turing UNK2A0 */
+ xf_emit(ctx, 1, 0); /* 0000ffff GRIDID */
+ xf_emit(ctx, 1, 0x10001); /* ffffffff GRIDDIM_XY */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */
+ xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */
+ xf_emit(ctx, 1, 1); /* 00000001 LANES32 */
+ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
+ /* SEEK */
+ xf_emit(ctx, 0x40, 0); /* ffffffff USER_PARAM */
+ switch (device->chipset) {
+ case 0x50:
+ case 0x92:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x80, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0x10*2, 0); /* ffffffff, 1f */
+ break;
+ case 0x84:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x60, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
+ break;
+ case 0x94:
+ case 0x96:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x40, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 8*2, 0); /* ffffffff, 1f */
+ break;
+ case 0x86:
+ case 0x98:
+ xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */
+ xf_emit(ctx, 0x10, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xa0:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0xf0, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0x1e*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xa3:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x60, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 0xc*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xa5:
+ case 0xaf:
+ xf_emit(ctx, 8, 0); /* 7, 0, 0, 0, ... */
+ xf_emit(ctx, 0x30, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 6*2, 0); /* ffffffff, 1f */
+ break;
+ case 0xaa:
+ xf_emit(ctx, 0x12, 0);
+ break;
+ case 0xa8:
+ case 0xac:
+ xf_emit(ctx, 4, 0); /* f, 0, 0, 0 */
+ xf_emit(ctx, 0x10, 0); /* fff */
+ xf_emit(ctx, 2, 0); /* ff, fff */
+ xf_emit(ctx, 2*2, 0); /* ffffffff, 1f */
+ break;
+ }
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000000 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 0000001f */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 4, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000003 turing UNK35C */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 000000ff */
+}
+
+static void
+nv50_gr_construct_gene_unk1cxx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 0x3f800000); /* ffffffff LINE_WIDTH */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */
+ xf_emit(ctx, 3, 0); /* 00000001 POLYGON_OFFSET_*_ENABLE */
+ xf_emit(ctx, 1, 4); /* 0000000f CULL_MODE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */
+ xf_emit(ctx, 0x10, 0); /* 00000001 SCISSOR_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_UNITS */
+ xf_emit(ctx, 1, 0); /* ffffffff POLYGON_OFFSET_FACTOR */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */
+ xf_emit(ctx, 2, 0); /* 07ffffff SCREEN_SCISSOR */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 8, 0); /* 00000001 RT_HORIZ_LINEAR */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 3); /* 00000003 UNK16B4 */
+ else if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 1); /* 00000001 UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 2, 0x04000000); /* 07ffffff tesla UNK0D6C */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 5); /* 0000000f UNK1408 */
+ xf_emit(ctx, 1, 0x52); /* 000001ff SEMANTIC_PTSZ */
+ xf_emit(ctx, 1, 0); /* ffffffff POINT_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000007 tesla UNK0FB4 */
+ if (device->chipset != 0x50) {
+ xf_emit(ctx, 1, 0); /* 3ff */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK1110 */
+ }
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */
+ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
+ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+ xf_emit(ctx, 1, 0x10); /* 000000ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 0x20, 0); /* 07ffffff VIEWPORT_HORIZ, then VIEWPORT_VERT. (W&0x3fff)<<13 | (X&0x1fff). */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK187C */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 1, 0x8100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 5); /* 0000000f tesla UNK1220 */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 000000ff tesla UNK1A20 */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
+ if (device->chipset < 0xa0)
+ xf_emit(ctx, 0x1c, 0); /* RO */
+ else if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x9, 0);
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+ xf_emit(ctx, 1, 0); /* 00000003 WINDOW_ORIGIN */
+ if (device->chipset != 0x50) {
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK1100 */
+ xf_emit(ctx, 1, 0); /* 3ff */
+ }
+ /* XXX: the following block could belong either to unk1cxx, or
+ * to STRMOUT. Rather hard to tell. */
+ if (device->chipset < 0xa0)
+ xf_emit(ctx, 0x25, 0);
+ else
+ xf_emit(ctx, 0x3b, 0);
+}
+
+static void
+nv50_gr_construct_gene_strmout(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */
+ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */
+ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */
+ if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */
+ }
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 4); /* 0000007f VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 1, 0x3ff); /* 000003ff tesla UNK0D68 */
+ else
+ xf_emit(ctx, 1, 0x7ff); /* 000007ff tesla UNK0D68 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ xf_emit(ctx, 1, 0x102); /* 0000ffff STRMOUT_BUFFER_CTRL */
+ xf_emit(ctx, 1, 0); /* ffffffff STRMOUT_PRIMITIVE_COUNT */
+ xf_emit(ctx, 4, 0); /* 000000ff STRMOUT_ADDRESS_HIGH */
+ xf_emit(ctx, 4, 0); /* ffffffff STRMOUT_ADDRESS_LOW */
+ xf_emit(ctx, 4, 4); /* 000000ff STRMOUT_NUM_ATTRIBS */
+ if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1A8C */
+ xf_emit(ctx, 4, 0); /* ffffffff UNK1780 */
+ }
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_STRMOUT */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
+ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
+ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW QUERY_COUNTER */
+ xf_emit(ctx, 2, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ /* SEEK */
+ xf_emit(ctx, 0x20, 0); /* ffffffff STRMOUT_MAP */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000000? */
+ xf_emit(ctx, 2, 0); /* ffffffff */
+}
+
+static void
+nv50_gr_construct_gene_ropm1(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_gr_construct_gene_ropm2(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 2, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
+ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 7 */
+ /* SEEK */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_QUERY */
+ xf_emit(ctx, 1, 0); /* 000000ff QUERY_ADDRESS_HIGH */
+ xf_emit(ctx, 2, 0); /* ffffffff QUERY_ADDRESS_LOW, COUNTER */
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x4e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 0); /* 00000001 eng2d UNK260 */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 0x11); /* 000000ff tesla UNK1968 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+}
+
+static void
+nv50_gr_construct_gene_ropc(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int magic2;
+ if (device->chipset == 0x50) {
+ magic2 = 0x00003e60;
+ } else if (!IS_NVA3F(device->chipset)) {
+ magic2 = 0x001ffe67;
+ } else {
+ magic2 = 0x00087e67;
+ }
+ xf_emit(ctx, 1, 0); /* f/7 MUTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ if (device->chipset >= 0xa0 && !IS_NVAAF(device->chipset))
+ xf_emit(ctx, 1, 0x15); /* 000000ff */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0x10); /* 3ff/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ if (device->chipset == 0x86 || device->chipset == 0x92 || device->chipset == 0x98 || device->chipset >= 0xa0) {
+ xf_emit(ctx, 3, 0); /* ff, ffffffff, ffffffff */
+ xf_emit(ctx, 1, 4); /* 7 */
+ xf_emit(ctx, 1, 0x400); /* fffffff */
+ xf_emit(ctx, 1, 0x300); /* ffff */
+ xf_emit(ctx, 1, 0x1001); /* 1fff */
+ if (device->chipset != 0xa0) {
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 0); /* 0000000f UNK15C8 */
+ else
+ xf_emit(ctx, 1, 0x15); /* ff */
+ }
+ }
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1900 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
+ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 0x10, 0); /* ffffffff DEPTH_RANGE_NEAR */
+ xf_emit(ctx, 0x10, 0x3f800000); /* ffffffff DEPTH_RANGE_FAR */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_BACK_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 2, 0); /* ffffffff DEPTH_BOUNDS */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000007 DEPTH_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff CLEAR_STENCIL */
+ xf_emit(ctx, 1, 0); /* 00000007 STENCIL_FRONT_FUNC_FUNC */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_FUNC_REF */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 1, 0x10); /* 7f/ff VIEW_VOLUME_CLIP_CTRL */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 0x3f); /* 0000003f UNK1590 */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 2, 0); /* ffff0ff3, ffff */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff CLEAR_DEPTH */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
+ if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 2, 0);
+ xf_emit(ctx, 1, 0x1001);
+ xf_emit(ctx, 0xb, 0);
+ } else {
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ }
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ if (device->chipset != 0x50) {
+ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */
+ xf_emit(ctx, 1, 0); /* 000000ff */
+ }
+ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 2, 1); /* 00000007 BLEND_EQUATION_RGB, ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK12E4 */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 0000000f */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ } else if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ } else {
+ xf_emit(ctx, 1, 0); /* 00000007 MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1430 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ }
+ xf_emit(ctx, 4, 0); /* ffffffff CLEAR_COLOR */
+ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR A R G B */
+ xf_emit(ctx, 1, 0); /* 00000fff eng2d UNK2B0 */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 2, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f LOGIC_OP */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4? NVA3+ only? */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK15C4 */
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1140 */
+ }
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* 00000007 PATTERN_COLOR_FORMAT */
+ xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 PATTERN_MONO_FORMAT */
+ xf_emit(ctx, 2, 0); /* ffffffff PATTERN_MONO_BITMAP */
+ xf_emit(ctx, 1, 0); /* 00000003 PATTERN_SELECT */
+ xf_emit(ctx, 1, 0); /* 000000ff ROP */
+ xf_emit(ctx, 1, 0); /* ffffffff BETA1 */
+ xf_emit(ctx, 1, 0); /* ffffffff BETA4 */
+ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
+ xf_emit(ctx, 0x50, 0); /* 10x ffffff, ffffff, ffffff, ffffff, 3 PATTERN */
+}
+
+static void
+nv50_gr_construct_xfer_unk84xx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int magic3;
+ switch (device->chipset) {
+ case 0x50:
+ magic3 = 0x1000;
+ break;
+ case 0x86:
+ case 0x98:
+ case 0xa8:
+ case 0xaa:
+ case 0xac:
+ case 0xaf:
+ magic3 = 0x1e00;
+ break;
+ default:
+ magic3 = 0;
+ }
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 7f/ff[NVA0+] VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113[NVA0+] */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x1f, 0); /* ffffffff */
+ else if (device->chipset >= 0xa0)
+ xf_emit(ctx, 0x0f, 0); /* ffffffff */
+ else
+ xf_emit(ctx, 0x10, 0); /* fffffff VP_RESULT_MAP_1 up */
+ xf_emit(ctx, 2, 0); /* f/1f[NVA3], fffffff/ffffffff[NVA0+] */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0x03020100); /* ffffffff */
+ else
+ xf_emit(ctx, 1, 0x00608080); /* fffffff VP_RESULT_MAP_0 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 2, 0); /* 111/113, 7f/ff */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ if (magic3)
+ xf_emit(ctx, 1, magic3); /* 00007fff tesla UNK141C */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ xf_emit(ctx, 0x1f, 0); /* ffffffff GP_RESULT_MAP_1 up */
+ xf_emit(ctx, 1, 0); /* 0000001f */
+ xf_emit(ctx, 1, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0x80); /* 0000ffff GP_VERTEX_OUTPUT_COUNT */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0x03020100); /* ffffffff GP_RESULT_MAP_0 */
+ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+ if (magic3)
+ xf_emit(ctx, 1, magic3); /* 7fff tesla UNK141C */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK13A0 */
+ xf_emit(ctx, 1, 4); /* 7f/ff VP_REG_ALLOC_RESULT */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ xf_emit(ctx, 1, 0); /* 111/113 */
+ if (device->chipset == 0x94 || device->chipset == 0x96)
+ xf_emit(ctx, 0x1020, 0); /* 4 x (0x400 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+ else if (device->chipset < 0xa0)
+ xf_emit(ctx, 0xa20, 0); /* 4 x (0x280 x 0xffffffff, ff, 0, 0, 0, 4 x ffffffff) */
+ else if (!IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x210, 0); /* ffffffff */
+ else
+ xf_emit(ctx, 0x410, 0); /* ffffffff */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff GP_RESULT_MAP_SIZE */
+ xf_emit(ctx, 1, 3); /* 00000003 GP_OUTPUT_PRIMITIVE_TYPE */
+ xf_emit(ctx, 1, 0); /* 00000001 PROVOKING_VERTEX_LAST */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+}
+
+static void
+nv50_gr_construct_xfer_tprop(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int magic1, magic2;
+ if (device->chipset == 0x50) {
+ magic1 = 0x3ff;
+ magic2 = 0x00003e60;
+ } else if (!IS_NVA3F(device->chipset)) {
+ magic1 = 0x7ff;
+ magic2 = 0x001ffe67;
+ } else {
+ magic1 = 0x7ff;
+ magic2 = 0x00087e67;
+ }
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* ffffffff ALPHA_TEST_REF */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000000f UNK16A0 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_BACK_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_BACK_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 4, 0); /* ffffffff BLEND_COLOR */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK19C0 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK0FDC */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ff[NV50]/3ff[NV84+] */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 3, 0); /* 00000007 STENCIL_FRONT_OP_FAIL, ZFAIL, ZPASS */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_BACK_ENABLE */
+ xf_emit(ctx, 2, 0); /* 00007fff WINDOW_OFFSET_XY */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff COLOR_KEY */
+ xf_emit(ctx, 1, 0); /* 00000001 COLOR_KEY_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 COLOR_KEY_FORMAT */
+ xf_emit(ctx, 2, 0); /* ffffffff SIFC_BITMAP_COLOR */
+ xf_emit(ctx, 1, 1); /* 00000001 SIFC_BITMAP_WRITE_BIT0_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1298 */
+ } else if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ } else {
+ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
+ }
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_DST_ALPHA */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ }
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* 00000007 OPERATION */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff SIFC_FORMAT */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff DRAW_COLOR_FORMAT */
+ xf_emit(ctx, 1, 0xcf); /* 000000ff SRC_FORMAT */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 7/f[NVA3] MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 8, 1); /* 00000001 UNK19E0 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 1, 0); /* ff */
+ else
+ xf_emit(ctx, 3, 0); /* 1, 7, 3ff */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DU_DX_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DU_DX_INT */
+ xf_emit(ctx, 1, 0); /* 000fffff BLIT_DV_DY_FRACT */
+ xf_emit(ctx, 1, 1); /* 0001ffff BLIT_DV_DY_INT */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, magic1); /* 3ff/7ff tesla UNK0D68 */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 8, 0); /* 0000ffff DMA_COLOR */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_GLOBAL */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_LOCAL */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_STACK */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_DST */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 8, 0); /* 000000ff RT_ADDRESS_HIGH */
+ xf_emit(ctx, 8, 0); /* ffffffff RT_LAYER_STRIDE */
+ xf_emit(ctx, 8, 0); /* ffffffff RT_ADDRESS_LOW */
+ xf_emit(ctx, 8, 8); /* 0000007f RT_TILE_MODE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 8, 0x400); /* 0fffffff RT_HORIZ */
+ xf_emit(ctx, 8, 0x300); /* 0000ffff RT_VERT */
+ xf_emit(ctx, 1, 1); /* 00001fff RT_ARRAY_MODE */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0x20); /* 00000fff DST_TILE_MODE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_HEIGHT */
+ xf_emit(ctx, 1, 0); /* 000007ff DST_LAYER */
+ xf_emit(ctx, 1, 1); /* 00000001 DST_LINEAR */
+ xf_emit(ctx, 1, 0); /* ffffffff DST_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0); /* 000000ff DST_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0x40); /* 0007ffff DST_PITCH */
+ xf_emit(ctx, 1, 0x100); /* 0001ffff DST_WIDTH */
+ xf_emit(ctx, 1, 0); /* 0000ffff */
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK15AC */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 2); /* 00000003 tesla UNK143C */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_ZETA */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 2, 0); /* ffff, ff/3ff */
+ xf_emit(ctx, 1, 0); /* 0001ffff GP_BUILTIN_RESULT_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 000000ff STENCIL_FRONT_MASK */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* ffffffff ZETA_LAYER_STRIDE */
+ xf_emit(ctx, 1, 0); /* 000000ff ZETA_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff ZETA_ADDRESS_LOW */
+ xf_emit(ctx, 1, 4); /* 00000007 ZETA_TILE_MODE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ xf_emit(ctx, 1, 0x400); /* 0fffffff ZETA_HORIZ */
+ xf_emit(ctx, 1, 0x300); /* 0000ffff ZETA_VERT */
+ xf_emit(ctx, 1, 0x1001); /* 00001fff ZETA_ARRAY_MODE */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 0); /* 00000001 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 3f/7f RT_FORMAT */
+ xf_emit(ctx, 1, 0x0fac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0xf); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 7, 0); /* 0000000f COLOR_MASK */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000003 UNK0F90 */
+ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
+ xf_emit(ctx, 1, 0); /* 7 */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ }
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0x0fac6881); /* fffffff */
+ xf_emit(ctx, 1, magic2); /* 001fffff tesla UNK0F78 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_BOUNDS_EN */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE_ENABLE */
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK0FB0 */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 STENCIL_FRONT_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK15B4 */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK19CC */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0); /* 00000001 SAMPLECNT_ENABLE */
+ xf_emit(ctx, 1, 0); /* 0000000f ZETA_FORMAT */
+ xf_emit(ctx, 1, 1); /* 00000001 ZETA_ENABLE */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 0000000f tesla UNK15C8 */
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A3C */
+ if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 3, 0); /* 7/f, 1, ffff0ff3 */
+ xf_emit(ctx, 1, 0xfac6881); /* fffffff */
+ xf_emit(ctx, 4, 0); /* 1, 1, 1, 3ff */
+ xf_emit(ctx, 1, 4); /* 7 */
+ xf_emit(ctx, 1, 0); /* 1 */
+ xf_emit(ctx, 2, 1); /* 1 */
+ xf_emit(ctx, 2, 0); /* 7, f */
+ xf_emit(ctx, 1, 1); /* 1 */
+ xf_emit(ctx, 1, 0); /* 7/f */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 0x9, 0); /* 1 */
+ else
+ xf_emit(ctx, 0x8, 0); /* 1 */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 8, 1); /* 1 */
+ xf_emit(ctx, 1, 0x11); /* 7f */
+ xf_emit(ctx, 7, 0); /* 7f */
+ xf_emit(ctx, 1, 0xfac6881); /* fffffff */
+ xf_emit(ctx, 1, 0xf); /* f */
+ xf_emit(ctx, 7, 0); /* f */
+ xf_emit(ctx, 1, 0x11); /* 7f */
+ xf_emit(ctx, 1, 1); /* 1 */
+ xf_emit(ctx, 5, 0); /* 1, 7, 3ff, 3, 7 */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ }
+ }
+}
+
+static void
+nv50_gr_construct_xfer_tex(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ xf_emit(ctx, 2, 0); /* 1 LINKED_TSC. yes, 2. */
+ if (device->chipset != 0x50)
+ xf_emit(ctx, 1, 0); /* 3 */
+ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DU_DX_INT */
+ xf_emit(ctx, 1, 0); /* fffff BLIT_DU_DX_FRACT */
+ xf_emit(ctx, 1, 1); /* 1ffff BLIT_DV_DY_INT */
+ xf_emit(ctx, 1, 0); /* fffff BLIT_DV_DY_FRACT */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 1, 0); /* 3 BLIT_CONTROL */
+ else
+ xf_emit(ctx, 2, 0); /* 3ff, 1 */
+ xf_emit(ctx, 1, 0x2a712488); /* ffffffff SRC_TIC_0 */
+ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_1 */
+ xf_emit(ctx, 1, 0x4085c000); /* ffffffff SRC_TIC_2 */
+ xf_emit(ctx, 1, 0x40); /* ffffffff SRC_TIC_3 */
+ xf_emit(ctx, 1, 0x100); /* ffffffff SRC_TIC_4 */
+ xf_emit(ctx, 1, 0x10100); /* ffffffff SRC_TIC_5 */
+ xf_emit(ctx, 1, 0x02800000); /* ffffffff SRC_TIC_6 */
+ xf_emit(ctx, 1, 0); /* ffffffff SRC_TIC_7 */
+ if (device->chipset == 0x50) {
+ xf_emit(ctx, 1, 0); /* 00000001 turing UNK358 */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */
+ xf_emit(ctx, 1, 0); /* 00000003 turing UNK37C tesla UNK1690 */
+ xf_emit(ctx, 1, 0); /* 00000003 BLIT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000001 turing UNK32C tesla UNK0F94 */
+ } else if (!IS_NVAAF(device->chipset)) {
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34? */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1664 / turing UNK03E8 */
+ xf_emit(ctx, 1, 0); /* 00000003 */
+ xf_emit(ctx, 1, 0); /* 000003ff */
+ } else {
+ xf_emit(ctx, 0x6, 0);
+ }
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_TEXTURE */
+ xf_emit(ctx, 1, 0); /* 0000ffff DMA_SRC */
+}
+
+static void
+nv50_gr_construct_xfer_unk8cxx(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 2, 0); /* 7, ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0D64 */
+ xf_emit(ctx, 1, 0x04e3bfdf); /* ffffffff UNK0DF4 */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK0F98 */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1668 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_STIPPLE_ENABLE */
+ xf_emit(ctx, 1, 0x00ffff00); /* 00ffffff LINE_STIPPLE_PATTERN */
+ xf_emit(ctx, 1, 0); /* 00000001 POLYGON_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1534 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1658 */
+ xf_emit(ctx, 1, 0); /* 00000001 LINE_SMOOTH_ENABLE */
+ xf_emit(ctx, 1, 0); /* ffff0ff3 */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 DEPTH_WRITE */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK15B4 */
+ xf_emit(ctx, 1, 0); /* 00000001 POINT_SPRITE_ENABLE */
+ xf_emit(ctx, 1, 1); /* 00000001 tesla UNK165C */
+ xf_emit(ctx, 1, 0x30201000); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0x70605040); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0xb8a89888); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0xf8e8d8c8); /* ffffffff tesla UNK1670 */
+ xf_emit(ctx, 1, 0); /* 00000001 VERTEX_TWO_SIDE_ENABLE */
+ xf_emit(ctx, 1, 0x1a); /* 0000001f POLYGON_MODE */
+}
+
+static void
+nv50_gr_construct_xfer_tp(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ if (device->chipset < 0xa0) {
+ nv50_gr_construct_xfer_unk84xx(ctx);
+ nv50_gr_construct_xfer_tprop(ctx);
+ nv50_gr_construct_xfer_tex(ctx);
+ nv50_gr_construct_xfer_unk8cxx(ctx);
+ } else {
+ nv50_gr_construct_xfer_tex(ctx);
+ nv50_gr_construct_xfer_tprop(ctx);
+ nv50_gr_construct_xfer_unk8cxx(ctx);
+ nv50_gr_construct_xfer_unk84xx(ctx);
+ }
+}
+
+static void
+nv50_gr_construct_xfer_mpc(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i, mpcnt = 2;
+ switch (device->chipset) {
+ case 0x98:
+ case 0xaa:
+ mpcnt = 1;
+ break;
+ case 0x50:
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0xa8:
+ case 0xac:
+ mpcnt = 2;
+ break;
+ case 0xa0:
+ case 0xa3:
+ case 0xa5:
+ case 0xaf:
+ mpcnt = 3;
+ break;
+ }
+ for (i = 0; i < mpcnt; i++) {
+ xf_emit(ctx, 1, 0); /* ff */
+ xf_emit(ctx, 1, 0x80); /* ffffffff tesla UNK1404 */
+ xf_emit(ctx, 1, 0x80007004); /* ffffffff tesla UNK12B0 */
+ xf_emit(ctx, 1, 0x04000400); /* ffffffff */
+ if (device->chipset >= 0xa0)
+ xf_emit(ctx, 1, 0xc0); /* 00007fff tesla UNK152C */
+ xf_emit(ctx, 1, 0x1000); /* 0000ffff tesla UNK0D60 */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A30 */
+ if (device->chipset == 0x86 || device->chipset == 0x98 || device->chipset == 0xa8 || IS_NVAAF(device->chipset)) {
+ xf_emit(ctx, 1, 0xe00); /* 7fff */
+ xf_emit(ctx, 1, 0x1e00); /* 7fff */
+ }
+ xf_emit(ctx, 1, 1); /* 000000ff VP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 0); /* 00000001 LINKED_TSC */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 2, 0x1000); /* 7fff tesla UNK141C */
+ xf_emit(ctx, 1, 1); /* 000000ff GP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 0); /* 00000001 GP_ENABLE */
+ xf_emit(ctx, 1, 4); /* 000000ff FP_REG_ALLOC_TEMP */
+ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
+ if (IS_NVAAF(device->chipset))
+ xf_emit(ctx, 0xb, 0); /* RO */
+ else if (device->chipset >= 0xa0)
+ xf_emit(ctx, 0xc, 0); /* RO */
+ else
+ xf_emit(ctx, 0xa, 0); /* RO */
+ }
+ xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ if (device->chipset >= 0xa0) {
+ xf_emit(ctx, 1, 0x1fe21); /* 0003ffff tesla UNK0FAC */
+ }
+ xf_emit(ctx, 3, 0); /* 7fff, 0, 0 */
+ xf_emit(ctx, 1, 0); /* 00000001 tesla UNK1534 */
+ xf_emit(ctx, 1, 0); /* 7/f MULTISAMPLE_SAMPLES_LOG2 */
+ xf_emit(ctx, 4, 0xffff); /* 0000ffff MSAA_MASK */
+ xf_emit(ctx, 1, 1); /* 00000001 LANES32 */
+ xf_emit(ctx, 1, 0x10001); /* 00ffffff BLOCK_ALLOC */
+ xf_emit(ctx, 1, 0x10001); /* ffffffff BLOCKDIM_XY */
+ xf_emit(ctx, 1, 1); /* 0000ffff BLOCKDIM_Z */
+ xf_emit(ctx, 1, 0); /* ffffffff SHARED_SIZE */
+ xf_emit(ctx, 1, 0x1fe21); /* 1ffff/3ffff[NVA0+] tesla UNk0FAC */
+ xf_emit(ctx, 1, 0); /* ffffffff tesla UNK1A34 */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 1); /* 0000001f tesla UNK169C */
+ xf_emit(ctx, 1, 0); /* ff/3ff */
+ xf_emit(ctx, 1, 0); /* 1 LINKED_TSC */
+ xf_emit(ctx, 1, 0); /* ff FP_ADDRESS_HIGH */
+ xf_emit(ctx, 1, 0); /* ffffffff FP_ADDRESS_LOW */
+ xf_emit(ctx, 1, 0x08100c12); /* 1fffffff FP_INTERPOLANT_CTRL */
+ xf_emit(ctx, 1, 4); /* 00000007 FP_CONTROL */
+ xf_emit(ctx, 1, 0); /* 000000ff FRAG_COLOR_CLAMP_EN */
+ xf_emit(ctx, 1, 2); /* 00000003 REG_MODE */
+ xf_emit(ctx, 1, 0x11); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 7, 0); /* 0000007f RT_FORMAT */
+ xf_emit(ctx, 1, 0); /* 00000007 */
+ xf_emit(ctx, 1, 0xfac6881); /* 0fffffff RT_CONTROL */
+ xf_emit(ctx, 1, 0); /* 00000003 MULTISAMPLE_CTRL */
+ if (IS_NVA3F(device->chipset))
+ xf_emit(ctx, 1, 3); /* 00000003 tesla UNK16B4 */
+ xf_emit(ctx, 1, 0); /* 00000001 ALPHA_TEST_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000007 ALPHA_TEST_FUNC */
+ xf_emit(ctx, 1, 0); /* 00000001 FRAMEBUFFER_SRGB */
+ xf_emit(ctx, 1, 4); /* ffffffff tesla UNK1400 */
+ xf_emit(ctx, 8, 0); /* 00000001 BLEND_ENABLE */
+ xf_emit(ctx, 1, 0); /* 00000001 LOGIC_OP_ENABLE */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_RGB */
+ xf_emit(ctx, 1, 2); /* 0000001f BLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 1, 1); /* 0000001f BLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000007 BLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 1, 1); /* 00000001 UNK133C */
+ if (IS_NVA3F(device->chipset)) {
+ xf_emit(ctx, 1, 0); /* 00000001 UNK12E4 */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_RGB */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_RGB */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_RGB */
+ xf_emit(ctx, 8, 2); /* 0000001f IBLEND_FUNC_SRC_ALPHA */
+ xf_emit(ctx, 8, 1); /* 0000001f IBLEND_FUNC_DST_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000007 IBLEND_EQUATION_ALPHA */
+ xf_emit(ctx, 8, 1); /* 00000001 IBLEND_UNK00 */
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK1928 */
+ xf_emit(ctx, 1, 0); /* 00000001 UNK1140 */
+ }
+ xf_emit(ctx, 1, 0); /* 00000003 tesla UNK0F90 */
+ xf_emit(ctx, 1, 4); /* 000000ff FP_RESULT_COUNT */
+ /* XXX: demagic this part some day */
+ if (device->chipset == 0x50)
+ xf_emit(ctx, 0x3a0, 0);
+ else if (device->chipset < 0x94)
+ xf_emit(ctx, 0x3a2, 0);
+ else if (device->chipset == 0x98 || device->chipset == 0xaa)
+ xf_emit(ctx, 0x39f, 0);
+ else
+ xf_emit(ctx, 0x3a3, 0);
+ xf_emit(ctx, 1, 0x11); /* 3f/7f DST_FORMAT */
+ xf_emit(ctx, 1, 0); /* 7 OPERATION */
+ xf_emit(ctx, 1, 1); /* 1 DST_LINEAR */
+ xf_emit(ctx, 0x2d, 0);
+}
+
+static void
+nv50_gr_construct_xfer2(struct nvkm_grctx *ctx)
+{
+ struct nvkm_device *device = ctx->device;
+ int i;
+ u32 offset;
+ u32 units = nv_rd32 (ctx->device, 0x1540);
+ int size = 0;
+
+ offset = (ctx->ctxvals_pos+0x3f)&~0x3f;
+
+ if (device->chipset < 0xa0) {
+ for (i = 0; i < 8; i++) {
+ ctx->ctxvals_pos = offset + i;
+ /* that little bugger belongs to csched. No idea
+ * what it's doing here. */
+ if (i == 0)
+ xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
+ if (units & (1 << i))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+ } else {
+ /* Strand 0: TPs 0, 1 */
+ ctx->ctxvals_pos = offset;
+ /* that little bugger belongs to csched. No idea
+ * what it's doing here. */
+ xf_emit(ctx, 1, 0x08100c12); /* FP_INTERPOLANT_CTRL */
+ if (units & (1 << 0))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if (units & (1 << 1))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 1: TPs 2, 3 */
+ ctx->ctxvals_pos = offset + 1;
+ if (units & (1 << 2))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if (units & (1 << 3))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 2: TPs 4, 5, 6 */
+ ctx->ctxvals_pos = offset + 2;
+ if (units & (1 << 4))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if (units & (1 << 5))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if (units & (1 << 6))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+
+ /* Strand 3: TPs 7, 8, 9 */
+ ctx->ctxvals_pos = offset + 3;
+ if (units & (1 << 7))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if (units & (1 << 8))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if (units & (1 << 9))
+ nv50_gr_construct_xfer_mpc(ctx);
+ if ((ctx->ctxvals_pos-offset)/8 > size)
+ size = (ctx->ctxvals_pos-offset)/8;
+ }
+ ctx->ctxvals_pos = offset + size * 8;
+ ctx->ctxvals_pos = (ctx->ctxvals_pos+0x3f)&~0x3f;
+ cp_lsr (ctx, offset);
+ cp_out (ctx, CP_SET_XFER_POINTER);
+ cp_lsr (ctx, size);
+ cp_out (ctx, CP_SEEK_2);
+ cp_out (ctx, CP_XFER_2);
+ cp_wait(ctx, XFER, BUSY);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc
new file mode 100644
index 000000000000..64208bf954cf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/com.fuc
@@ -0,0 +1,335 @@
+/* fuc microcode util functions for gf100 PGRAPH
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_CODE
+// queue_put - add request to queue
+//
+// In : $r13 queue pointer
+// $r14 command
+// $r15 data
+//
+queue_put:
+ // make sure we have space..
+ ld b32 $r8 D[$r13 + 0x0] // GET
+ ld b32 $r9 D[$r13 + 0x4] // PUT
+ xor $r8 8
+ cmpu b32 $r8 $r9
+ bra ne #queue_put_next
+ mov $r15 E_CMD_OVERFLOW
+ call(error)
+ ret
+
+ // store cmd/data on queue
+ queue_put_next:
+ and $r8 $r9 7
+ shl b32 $r8 3
+ add b32 $r8 $r13
+ add b32 $r8 8
+ st b32 D[$r8 + 0x0] $r14
+ st b32 D[$r8 + 0x4] $r15
+
+ // update PUT
+ add b32 $r9 1
+ and $r9 0xf
+ st b32 D[$r13 + 0x4] $r9
+ ret
+
+// queue_get - fetch request from queue
+//
+// In : $r13 queue pointer
+//
+// Out: $p1 clear on success (data available)
+// $r14 command
+// $r15 data
+//
+queue_get:
+ bset $flags $p1
+ ld b32 $r8 D[$r13 + 0x0] // GET
+ ld b32 $r9 D[$r13 + 0x4] // PUT
+ cmpu b32 $r8 $r9
+ bra e #queue_get_done
+ // fetch first cmd/data pair
+ and $r9 $r8 7
+ shl b32 $r9 3
+ add b32 $r9 $r13
+ add b32 $r9 8
+ ld b32 $r14 D[$r9 + 0x0]
+ ld b32 $r15 D[$r9 + 0x4]
+
+ // update GET
+ add b32 $r8 1
+ and $r8 0xf
+ st b32 D[$r13 + 0x0] $r8
+ bclr $flags $p1
+queue_get_done:
+ ret
+
+// nv_rd32 - read 32-bit value from nv register
+//
+// In : $r14 register
+// Out: $r15 value
+//
+nv_rd32:
+ mov b32 $r12 $r14
+ bset $r12 31 // MMIO_CTRL_PENDING
+ nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
+ nv_rd32_wait:
+ nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
+ xbit $r12 $r12 31
+ bra ne #nv_rd32_wait
+ mov $r10 6 // DONE_MMIO_RD
+ call(wait_doneo)
+ nv_iord($r15, NV_PGRAPH_FECS_MMIO_RDVAL, 0)
+ ret
+
+// nv_wr32 - write 32-bit value to nv register
+//
+// In : $r14 register
+// $r15 value
+//
+nv_wr32:
+ nv_iowr(NV_PGRAPH_FECS_MMIO_WRVAL, 0, $r15)
+ mov b32 $r12 $r14
+ bset $r12 31 // MMIO_CTRL_PENDING
+ bset $r12 30 // MMIO_CTRL_WRITE
+ nv_iowr(NV_PGRAPH_FECS_MMIO_CTRL, 0, $r12)
+ nv_wr32_wait:
+ nv_iord($r12, NV_PGRAPH_FECS_MMIO_CTRL, 0)
+ xbit $r12 $r12 31
+ bra ne #nv_wr32_wait
+ ret
+
+// wait_donez - wait on FUC_DONE bit to become clear
+//
+// In : $r10 bit to wait on
+//
+wait_donez:
+ trace_set(T_WAIT);
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
+ wait_donez_ne:
+ nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
+ xbit $r8 $r8 $r10
+ bra ne #wait_donez_ne
+ trace_clr(T_WAIT)
+ ret
+
+// wait_doneo - wait on FUC_DONE bit to become set
+//
+// In : $r10 bit to wait on
+//
+wait_doneo:
+ trace_set(T_WAIT);
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(6), 0, $r10)
+ wait_doneo_e:
+ nv_iord($r8, NV_PGRAPH_FECS_SIGNAL, 0)
+ xbit $r8 $r8 $r10
+ bra e #wait_doneo_e
+ trace_clr(T_WAIT)
+ ret
+
+// mmctx_size - determine size of a mmio list transfer
+//
+// In : $r14 mmio list head
+// $r15 mmio list tail
+// Out: $r15 transfer size (in bytes)
+//
+mmctx_size:
+ clear b32 $r9
+ nv_mmctx_size_loop:
+ ld b32 $r8 D[$r14]
+ shr b32 $r8 26
+ add b32 $r8 1
+ shl b32 $r8 2
+ add b32 $r9 $r8
+ add b32 $r14 4
+ cmpu b32 $r14 $r15
+ bra ne #nv_mmctx_size_loop
+ mov b32 $r15 $r9
+ ret
+
+// mmctx_xfer - execute a list of mmio transfers
+//
+// In : $r10 flags
+// bit 0: direction (0 = save, 1 = load)
+// bit 1: set if first transfer
+// bit 2: set if last transfer
+// $r11 base
+// $r12 mmio list head
+// $r13 mmio list tail
+// $r14 multi_stride
+// $r15 multi_mask
+//
+mmctx_xfer:
+ trace_set(T_MMCTX)
+ clear b32 $r9
+ or $r11 $r11
+ bra e #mmctx_base_disabled
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_BASE, 0, $r11)
+ bset $r9 0 // BASE_EN
+ mmctx_base_disabled:
+ or $r14 $r14
+ bra e #mmctx_multi_disabled
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_STRIDE, 0, $r14)
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_MULTI_MASK, 0, $r15)
+ bset $r9 1 // MULTI_EN
+ mmctx_multi_disabled:
+
+ xbit $r11 $r10 0
+ shl b32 $r11 16 // DIR
+ bset $r11 12 // QLIMIT = 0x10
+ xbit $r14 $r10 1
+ shl b32 $r14 17
+ or $r11 $r14 // START_TRIGGER
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
+
+ // loop over the mmio list, and send requests to the hw
+ mmctx_exec_loop:
+ // wait for space in mmctx queue
+ mmctx_wait_free:
+ nv_iord($r14, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
+ and $r14 0x1f
+ bra e #mmctx_wait_free
+
+ // queue up an entry
+ ld b32 $r14 D[$r12]
+ or $r14 $r9
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_QUEUE, 0, $r14)
+ add b32 $r12 4
+ cmpu b32 $r12 $r13
+ bra ne #mmctx_exec_loop
+
+ xbit $r11 $r10 2
+ bra ne #mmctx_stop
+ // wait for queue to empty
+ mmctx_fini_wait:
+ nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
+ and $r11 0x1f
+ cmpu b32 $r11 0x10
+ bra ne #mmctx_fini_wait
+ mov $r10 5 // DONE_MMCTX
+ call(wait_donez)
+ bra #mmctx_done
+ mmctx_stop:
+ xbit $r11 $r10 0
+ shl b32 $r11 16 // DIR
+ bset $r11 12 // QLIMIT = 0x10
+ bset $r11 18 // STOP_TRIGGER
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_CTRL, 0, $r11)
+ mmctx_stop_wait:
+ // wait for STOP_TRIGGER to clear
+ nv_iord($r11, NV_PGRAPH_FECS_MMCTX_CTRL, 0)
+ xbit $r11 $r11 18
+ bra ne #mmctx_stop_wait
+ mmctx_done:
+ trace_clr(T_MMCTX)
+ ret
+
+// Wait for DONE_STRAND
+//
+strand_wait:
+ push $r10
+ mov $r10 2
+ call(wait_donez)
+ pop $r10
+ ret
+
+// unknown - call before issuing strand commands
+//
+strand_pre:
+ mov $r9 NV_PGRAPH_FECS_STRAND_CMD_ENABLE
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
+ call(strand_wait)
+ ret
+
+// unknown - call after issuing strand commands
+//
+strand_post:
+ mov $r9 NV_PGRAPH_FECS_STRAND_CMD_DISABLE
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r9)
+ call(strand_wait)
+ ret
+
+// Selects strand set?!
+//
+// In: $r14 id
+//
+strand_set:
+ mov $r12 0xf
+ nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r12)
+ mov $r12 NV_PGRAPH_FECS_STRAND_CMD_DEACTIVATE_FILTER
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+ nv_iowr(NV_PGRAPH_FECS_STRAND_FILTER, 0x3f, $r14)
+ mov $r12 NV_PGRAPH_FECS_STRAND_CMD_ACTIVATE_FILTER
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+ call(strand_wait)
+ ret
+
+// Initialise strand context data
+//
+// In : $r15 context base
+// Out: $r15 context size (in bytes)
+//
+// Strandset(?) 3 hardcoded currently
+//
+strand_ctx_init:
+ trace_set(T_STRINIT)
+ call(strand_pre)
+ mov $r14 3
+ call(strand_set)
+
+ clear b32 $r12
+ nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r12)
+ mov $r12 NV_PGRAPH_FECS_STRAND_CMD_SEEK
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+ call(strand_wait)
+ sub b32 $r12 $r0 1
+ nv_iowr(NV_PGRAPH_FECS_STRAND_DATA, 0x3f, $r12)
+ mov $r12 NV_PGRAPH_FECS_STRAND_CMD_GET_INFO
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r12)
+ call(strand_wait)
+ call(strand_post)
+
+ // read the size of each strand, poke the context offset of
+ // each into STRAND_{SAVE,LOAD}_SWBASE now, no need to worry
+ // about it later then.
+ nv_mkio($r8, NV_PGRAPH_FECS_STRAND_SAVE_SWBASE, 0x00)
+ nv_iord($r9, NV_PGRAPH_FECS_STRANDS_CNT, 0x00)
+ shr b32 $r14 $r15 8
+ ctx_init_strand_loop:
+ iowr I[$r8 + 0x000] $r14 // STRAND_SAVE_SWBASE
+ iowr I[$r8 + 0x100] $r14 // STRAND_LOAD_SWBASE
+ iord $r10 I[$r8 + 0x200] // STRAND_SIZE
+ shr b32 $r10 6
+ add b32 $r10 1
+ add b32 $r14 $r10
+ add b32 $r8 4
+ sub b32 $r9 1
+ bra ne #ctx_init_strand_loop
+
+ shl b32 $r14 8
+ sub b32 $r15 $r14 $r15
+ trace_clr(T_STRINIT)
+ ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
new file mode 100644
index 000000000000..eaed1599b90f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpc.fuc
@@ -0,0 +1,378 @@
+/* fuc microcode for gf100 PGRAPH/GPC
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+/* TODO
+ * - bracket certain functions with scratch writes, useful for debugging
+ * - watchdog timer around ctx operations
+ */
+
+#ifdef INCLUDE_DATA
+gpc_mmio_list_head: .b32 #mmio_list_base
+gpc_mmio_list_tail:
+tpc_mmio_list_head: .b32 #mmio_list_base
+tpc_mmio_list_tail:
+unk_mmio_list_head: .b32 #mmio_list_base
+unk_mmio_list_tail: .b32 #mmio_list_base
+
+gpc_id: .b32 0
+
+tpc_count: .b32 0
+tpc_mask: .b32 0
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+unk_count: .b32 0
+unk_mask: .b32 0
+#endif
+
+cmd_queue: queue_init
+
+mmio_list_base:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see os.h)
+//
+error:
+ push $r14
+ nv_wr32(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), $r15)
+ mov $r15 1
+ nv_wr32(NV_PGRAPH_FECS_INTR_UP_SET, $r15)
+ pop $r14
+ ret
+
+// GPC fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Input:
+// CC_SCRATCH[1]: context base
+//
+// Output:
+// CC_SCRATCH[0]:
+// 31:31: set to signal completion
+// CC_SCRATCH[1]:
+// 31:0: GPC context size
+//
+init:
+ clear b32 $r0
+
+ // setup stack
+ nv_iord($r1, NV_PGRAPH_GPCX_GPCCS_CAPS, 0)
+ extr $r1 $r1 9:17
+ shl b32 $r1 8
+ mov $sp $r1
+
+ // enable fifo access
+ mov $r2 NV_PGRAPH_GPCX_GPCCS_ACCESS_FIFO
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_ACCESS, 0, $r2)
+
+ // setup i0 handler, and route all interrupts to it
+ mov $r1 #ih
+ mov $iv0 $r1
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ROUTE, 0, $r0)
+
+ // enable fifo interrupt
+ mov $r2 NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET_FIFO
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_EN_SET, 0, $r2)
+
+ // enable interrupts
+ bset $flags ie0
+
+ // figure out which GPC we are, and how many TPCs we have
+ nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_UNITS, 0)
+ mov $r3 1
+ and $r2 0x1f
+ shl b32 $r3 $r2
+ sub b32 $r3 1
+ st b32 D[$r0 + #tpc_count] $r2
+ st b32 D[$r0 + #tpc_mask] $r3
+ nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_MYINDEX, 0)
+ st b32 D[$r0 + #gpc_id] $r2
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+ // figure out which, and how many, UNKs are actually present
+ imm32($r14, 0x500c30)
+ clear b32 $r2
+ clear b32 $r3
+ clear b32 $r4
+ init_unk_loop:
+ call(nv_rd32)
+ cmp b32 $r15 0
+ bra z #init_unk_next
+ mov $r15 1
+ shl b32 $r15 $r2
+ or $r4 $r15
+ add b32 $r3 1
+ init_unk_next:
+ add b32 $r2 1
+ add b32 $r14 4
+ cmp b32 $r2 NV_PGRAPH_GPCX_UNK__SIZE
+ bra ne #init_unk_loop
+ init_unk_done:
+ st b32 D[$r0 + #unk_count] $r3
+ st b32 D[$r0 + #unk_mask] $r4
+#endif
+
+ // initialise context base, and size tracking
+ nv_iord($r2, NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0)
+ clear b32 $r3 // track GPC context size here
+
+ // set mmctx base addresses now so we don't have to do it later,
+ // they don't currently ever change
+ shr b32 $r5 $r2 8
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_SAVE_SWBASE, 0, $r5)
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_SWBASE, 0, $r5)
+
+ // calculate GPC mmio context size
+ ld b32 $r14 D[$r0 + #gpc_mmio_list_head]
+ ld b32 $r15 D[$r0 + #gpc_mmio_list_tail]
+ call(mmctx_size)
+ add b32 $r2 $r15
+ add b32 $r3 $r15
+
+ // calculate per-TPC mmio context size
+ ld b32 $r14 D[$r0 + #tpc_mmio_list_head]
+ ld b32 $r15 D[$r0 + #tpc_mmio_list_tail]
+ call(mmctx_size)
+ ld b32 $r14 D[$r0 + #tpc_count]
+ mulu $r14 $r15
+ add b32 $r2 $r14
+ add b32 $r3 $r14
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+ // calculate per-UNK mmio context size
+ ld b32 $r14 D[$r0 + #unk_mmio_list_head]
+ ld b32 $r15 D[$r0 + #unk_mmio_list_tail]
+ call(mmctx_size)
+ ld b32 $r14 D[$r0 + #unk_count]
+ mulu $r14 $r15
+ add b32 $r2 $r14
+ add b32 $r3 $r14
+#endif
+
+ // round up base/size to 256 byte boundary (for strand SWBASE)
+ shr b32 $r3 2
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_MMCTX_LOAD_COUNT, 0, $r3) // wtf for?!
+ shr b32 $r2 8
+ shr b32 $r3 6
+ add b32 $r2 1
+ add b32 $r3 1
+ shl b32 $r2 8
+ shl b32 $r3 8
+
+ // calculate size of strand context data
+ mov b32 $r15 $r2
+ call(strand_ctx_init)
+ add b32 $r3 $r15
+
+ // save context size, and tell HUB we're done
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_VAL(1), 0, $r3)
+ clear b32 $r2
+ bset $r2 31
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_CC_SCRATCH_SET(0), 0, $r2)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+ bset $flags $p0
+ sleep $p0
+ mov $r13 #cmd_queue
+ call(queue_get)
+ bra $p1 #main
+
+ // 0x0000-0x0003 are all context transfers
+ cmpu b32 $r14 0x04
+ bra nc #main_not_ctx_xfer
+ // fetch $flags and mask off $p1/$p2
+ mov $r1 $flags
+ mov $r2 0x0006
+ not b32 $r2
+ and $r1 $r2
+ // set $p1/$p2 according to transfer type
+ shl b32 $r14 1
+ or $r1 $r14
+ mov $flags $r1
+ // transfer context data
+ call(ctx_xfer)
+ bra #main
+
+ main_not_ctx_xfer:
+ shl b32 $r15 $r14 16
+ or $r15 E_BAD_COMMAND
+ call(error)
+ bra #main
+
+// interrupt handler
+ih:
+ push $r8
+ mov $r8 $flags
+ push $r8
+ push $r9
+ push $r10
+ push $r11
+ push $r13
+ push $r14
+ push $r15
+ clear b32 $r0
+
+ // incoming fifo command?
+ nv_iord($r10, NV_PGRAPH_GPCX_GPCCS_INTR, 0)
+ and $r11 $r10 NV_PGRAPH_GPCX_GPCCS_INTR_FIFO
+ bra e #ih_no_fifo
+ // queue incoming fifo command for later processing
+ mov $r13 #cmd_queue
+ nv_iord($r14, NV_PGRAPH_GPCX_GPCCS_FIFO_CMD, 0)
+ nv_iord($r15, NV_PGRAPH_GPCX_GPCCS_FIFO_DATA, 0)
+ call(queue_put)
+ mov $r14 1
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_FIFO_ACK, 0, $r14)
+
+ // ack, and wake up main()
+ ih_no_fifo:
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_INTR_ACK, 0, $r10)
+
+ pop $r15
+ pop $r14
+ pop $r13
+ pop $r11
+ pop $r10
+ pop $r9
+ pop $r8
+ mov $flags $r8
+ pop $r8
+ bclr $flags $p0
+ iret
+
+// Set this GPC's bit in HUB_BAR, used to signal completion of various
+// activities to the HUB fuc
+//
+hub_barrier_done:
+ mov $r15 1
+ ld b32 $r14 D[$r0 + #gpc_id]
+ shl b32 $r15 $r14
+ nv_wr32(0x409418, $r15) // 0x409418 - HUB_BAR_SET
+ ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off? Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+ mov $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_POWER
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
+ mov $r14 8
+ ctx_redswitch_delay:
+ sub b32 $r14 1
+ bra ne #ctx_redswitch_delay
+ or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_UNK11
+ or $r15 NV_PGRAPH_GPCX_GPCCS_RED_SWITCH_ENABLE
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_RED_SWITCH, 0, $r15)
+ ret
+
+// Transfer GPC context data between GPU and storage area
+//
+// In: $r15 context base address
+// $p1 clear on save, set on load
+// $p2 set if opposite direction done/will be done, so:
+// on save it means: "a load will follow this save"
+// on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+ // set context base address
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_MEM_BASE, 0, $r15)
+ bra not $p1 #ctx_xfer_not_load
+ call(ctx_redswitch)
+ ctx_xfer_not_load:
+
+ // strands
+ call(strand_pre)
+ clear b32 $r2
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_SELECT, 0x3f, $r2)
+ xbit $r2 $flags $p1 // SAVE/LOAD
+ add b32 $r2 NV_PGRAPH_GPCX_GPCCS_STRAND_CMD_SAVE
+ nv_iowr(NV_PGRAPH_GPCX_GPCCS_STRAND_CMD, 0x3f, $r2)
+
+ // mmio context
+ xbit $r10 $flags $p1 // direction
+ or $r10 2 // first
+ imm32($r11,0x500000)
+ ld b32 $r12 D[$r0 + #gpc_id]
+ shl b32 $r12 15
+ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn
+ ld b32 $r12 D[$r0 + #gpc_mmio_list_head]
+ ld b32 $r13 D[$r0 + #gpc_mmio_list_tail]
+ mov $r14 0 // not multi
+ call(mmctx_xfer)
+
+ // per-TPC mmio context
+ xbit $r10 $flags $p1 // direction
+#if !NV_PGRAPH_GPCX_UNK__SIZE
+ or $r10 4 // last
+#endif
+ imm32($r11, 0x504000)
+ ld b32 $r12 D[$r0 + #gpc_id]
+ shl b32 $r12 15
+ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_TPC0
+ ld b32 $r12 D[$r0 + #tpc_mmio_list_head]
+ ld b32 $r13 D[$r0 + #tpc_mmio_list_tail]
+ ld b32 $r15 D[$r0 + #tpc_mask]
+ mov $r14 0x800 // stride = 0x800
+ call(mmctx_xfer)
+
+#if NV_PGRAPH_GPCX_UNK__SIZE > 0
+ // per-UNK mmio context
+ xbit $r10 $flags $p1 // direction
+ or $r10 4 // last
+ imm32($r11, 0x503000)
+ ld b32 $r12 D[$r0 + #gpc_id]
+ shl b32 $r12 15
+ add b32 $r11 $r12 // base = NV_PGRAPH_GPCn_UNK0
+ ld b32 $r12 D[$r0 + #unk_mmio_list_head]
+ ld b32 $r13 D[$r0 + #unk_mmio_list_tail]
+ ld b32 $r15 D[$r0 + #unk_mask]
+ mov $r14 0x200 // stride = 0x200
+ call(mmctx_xfer)
+#endif
+
+ // wait for strands to finish
+ call(strand_wait)
+
+ // if load, or a save without a load following, do some
+ // unknown stuff that's done after finishing a block of
+ // strand commands
+ bra $p1 #ctx_xfer_post
+ bra not $p2 #ctx_xfer_done
+ ctx_xfer_post:
+ call(strand_post)
+
+ // mark completion in HUB's barrier
+ ctx_xfer_done:
+ call(hub_barrier_done)
+ ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3
new file mode 100644
index 000000000000..7cf2bf9d95a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000000
+
+#define CHIPSET GF100
+#include "macros.fuc"
+
+.section #gf100_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gf100_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h
new file mode 100644
index 000000000000..ea32f56c0a92
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf100.fuc3.h
@@ -0,0 +1,530 @@
+uint32_t gf100_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x00000064,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x00000064,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x00000064,
+/* 0x000c: unk_mmio_list_tail */
+ 0x00000064,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gf100_grgpc_code[] = {
+ 0x03a10ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0xe0f900f8,
+ 0xf102ffb9,
+ 0xf09814e7,
+ 0x21f440e3,
+ 0x01f7f09d,
+ 0xf102ffb9,
+ 0xf09c1ce7,
+ 0x21f440e3,
+ 0xf8e0fc9d,
+/* 0x03a1: init */
+ 0xf104bd00,
+ 0xf0420017,
+ 0x11cf0013,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf00014fe,
+ 0x07f10227,
+ 0x03f01200,
+ 0x0002d000,
+ 0x17f104bd,
+ 0x10fe04e6,
+ 0x0007f100,
+ 0x0003f007,
+ 0xbd0000d0,
+ 0x0427f004,
+ 0x040007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0xf11031f4,
+ 0xf0820027,
+ 0x22cf0123,
+ 0x0137f000,
+ 0xbb1f24f0,
+ 0x32b60432,
+ 0x05028001,
+ 0xf1060380,
+ 0xf0860027,
+ 0x22cf0123,
+ 0x04028000,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0xf1082595,
+ 0xf0c00007,
+ 0x05d00103,
+ 0xf104bd00,
+ 0xf0c10007,
+ 0x05d00103,
+ 0x9804bd00,
+ 0x0f98000e,
+ 0x5021f501,
+ 0x002fbb01,
+ 0x98003fbb,
+ 0x0f98010e,
+ 0x5021f502,
+ 0x050e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x0235b600,
+ 0xd30007f1,
+ 0xd00103f0,
+ 0x04bd0003,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb90834,
+ 0xd321f502,
+ 0x003fbb02,
+ 0x010007f1,
+ 0xd00203f0,
+ 0x04bd0003,
+ 0x29f024bd,
+ 0x0007f11f,
+ 0x0203f008,
+ 0xbd0002d0,
+/* 0x04a9: main */
+ 0x0031f404,
+ 0xf00028f4,
+ 0x21f41cd7,
+ 0xf401f439,
+ 0xf404e4b0,
+ 0x81fe1e18,
+ 0x0627f001,
+ 0x12fd20bd,
+ 0x01e4b604,
+ 0xfe051efd,
+ 0x21f50018,
+ 0x0ef4059e,
+/* 0x04d9: main_not_ctx_xfer */
+ 0x10ef94d3,
+ 0xf501f5f0,
+ 0xf4037e21,
+/* 0x04e6: ih */
+ 0x80f9c60e,
+ 0xf90188fe,
+ 0xf990f980,
+ 0xf9b0f9a0,
+ 0xf9e0f9d0,
+ 0xf104bdf0,
+ 0xf00200a7,
+ 0xaacf00a3,
+ 0x04abc400,
+ 0xf02c0bf4,
+ 0xe7f11cd7,
+ 0xe3f01a00,
+ 0x00eecf00,
+ 0x1900f7f1,
+ 0xcf00f3f0,
+ 0x21f400ff,
+ 0x01e7f004,
+ 0x1d0007f1,
+ 0xd00003f0,
+ 0x04bd000e,
+/* 0x0534: ih_no_fifo */
+ 0x010007f1,
+ 0xd00003f0,
+ 0x04bd000a,
+ 0xe0fcf0fc,
+ 0xb0fcd0fc,
+ 0x90fca0fc,
+ 0x88fe80fc,
+ 0xf480fc00,
+ 0x01f80032,
+/* 0x0558: hub_barrier_done */
+ 0x9801f7f0,
+ 0xfebb040e,
+ 0x02ffb904,
+ 0x9418e7f1,
+ 0xf440e3f0,
+ 0x00f89d21,
+/* 0x0570: ctx_redswitch */
+ 0xf120f7f0,
+ 0xf0850007,
+ 0x0fd00103,
+ 0xf004bd00,
+/* 0x0582: ctx_redswitch_delay */
+ 0xe2b608e7,
+ 0xfd1bf401,
+ 0x0800f5f1,
+ 0x0200f5f1,
+ 0x850007f1,
+ 0xd00103f0,
+ 0x04bd000f,
+/* 0x059e: ctx_xfer */
+ 0x07f100f8,
+ 0x03f08100,
+ 0x000fd002,
+ 0x11f404bd,
+ 0x7021f507,
+/* 0x05b1: ctx_xfer_not_load */
+ 0x6a21f505,
+ 0xf124bd02,
+ 0xf047fc07,
+ 0x02d00203,
+ 0xf004bd00,
+ 0x20b6012c,
+ 0xfc07f103,
+ 0x0203f04a,
+ 0xbd0002d0,
+ 0x01acf004,
+ 0xf102a5f0,
+ 0xf00000b7,
+ 0x0c9850b3,
+ 0x0fc4b604,
+ 0x9800bcbb,
+ 0x0d98000c,
+ 0x00e7f001,
+ 0x016f21f5,
+ 0xf001acf0,
+ 0xb7f104a5,
+ 0xb3f04000,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0xf1060f98,
+ 0xf50800e7,
+ 0xf5016f21,
+ 0xf4025e21,
+ 0x12f40601,
+/* 0x0629: ctx_xfer_post */
+ 0x7f21f507,
+/* 0x062d: ctx_xfer_done */
+ 0x5821f502,
+ 0x0000f805,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3
new file mode 100644
index 000000000000..c918f7d60004
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #gf117_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gf117_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
new file mode 100644
index 000000000000..9a36d9cbb8a5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgf117.fuc3.h
@@ -0,0 +1,537 @@
+uint32_t gf117_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: unk_count */
+ 0x00000000,
+/* 0x0020: unk_mask */
+ 0x00000000,
+/* 0x0024: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gf117_grgpc_code[] = {
+ 0x03a10ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0xe0f900f8,
+ 0xf102ffb9,
+ 0xf09814e7,
+ 0x21f440e3,
+ 0x01f7f09d,
+ 0xf102ffb9,
+ 0xf09c1ce7,
+ 0x21f440e3,
+ 0xf8e0fc9d,
+/* 0x03a1: init */
+ 0xf104bd00,
+ 0xf0420017,
+ 0x11cf0013,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf00014fe,
+ 0x07f10227,
+ 0x03f01200,
+ 0x0002d000,
+ 0x17f104bd,
+ 0x10fe0530,
+ 0x0007f100,
+ 0x0003f007,
+ 0xbd0000d0,
+ 0x0427f004,
+ 0x040007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0xf11031f4,
+ 0xf0820027,
+ 0x22cf0123,
+ 0x0137f000,
+ 0xbb1f24f0,
+ 0x32b60432,
+ 0x05028001,
+ 0xf1060380,
+ 0xf0860027,
+ 0x22cf0123,
+ 0x04028000,
+ 0x0c30e7f1,
+ 0xbd50e3f0,
+ 0xbd34bd24,
+/* 0x0421: init_unk_loop */
+ 0x6821f444,
+ 0xf400f6b0,
+ 0xf7f00f0b,
+ 0x04f2bb01,
+ 0xb6054ffd,
+/* 0x0436: init_unk_next */
+ 0x20b60130,
+ 0x04e0b601,
+ 0xf40126b0,
+/* 0x0442: init_unk_done */
+ 0x0380e21b,
+ 0x08048007,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0xf1082595,
+ 0xf0c00007,
+ 0x05d00103,
+ 0xf104bd00,
+ 0xf0c10007,
+ 0x05d00103,
+ 0x9804bd00,
+ 0x0f98000e,
+ 0x5021f501,
+ 0x002fbb01,
+ 0x98003fbb,
+ 0x0f98010e,
+ 0x5021f502,
+ 0x050e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x020e9800,
+ 0xf5030f98,
+ 0x98015021,
+ 0xeffd070e,
+ 0x002ebb00,
+ 0xb6003ebb,
+ 0x07f10235,
+ 0x03f0d300,
+ 0x0003d001,
+ 0x25b604bd,
+ 0x0635b608,
+ 0xb60120b6,
+ 0x24b60130,
+ 0x0834b608,
+ 0xf5022fb9,
+ 0xbb02d321,
+ 0x07f1003f,
+ 0x03f00100,
+ 0x0003d002,
+ 0x24bd04bd,
+ 0xf11f29f0,
+ 0xf0080007,
+ 0x02d00203,
+/* 0x04f3: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x24d7f000,
+ 0xf43921f4,
+ 0xe4b0f401,
+ 0x1e18f404,
+ 0xf00181fe,
+ 0x20bd0627,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+ 0x94d30ef4,
+ 0xf5f010ef,
+ 0x7e21f501,
+ 0xc60ef403,
+/* 0x0530: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x24d7f02c,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xf00421f4,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x057e: ih_no_fifo */
+ 0x07f104bd,
+ 0x03f00100,
+ 0x000ad000,
+ 0xf0fc04bd,
+ 0xd0fce0fc,
+ 0xa0fcb0fc,
+ 0x80fc90fc,
+ 0xfc0088fe,
+ 0x0032f480,
+/* 0x05a2: hub_barrier_done */
+ 0xf7f001f8,
+ 0x040e9801,
+ 0xb904febb,
+ 0xe7f102ff,
+ 0xe3f09418,
+ 0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+ 0xf7f000f8,
+ 0x0007f120,
+ 0x0103f085,
+ 0xbd000fd0,
+ 0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+ 0xf401e2b6,
+ 0xf5f1fd1b,
+ 0xf5f10800,
+ 0x07f10200,
+ 0x03f08500,
+ 0x000fd001,
+ 0x00f804bd,
+/* 0x05e8: ctx_xfer */
+ 0x810007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+ 0xf505ba21,
+ 0xbd026a21,
+ 0xfc07f124,
+ 0x0203f047,
+ 0xbd0002d0,
+ 0x012cf004,
+ 0xf10320b6,
+ 0xf04afc07,
+ 0x02d00203,
+ 0xf004bd00,
+ 0xa5f001ac,
+ 0x00b7f102,
+ 0x50b3f000,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xacf0016f,
+ 0x00b7f101,
+ 0x50b3f040,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x010c9800,
+ 0x98020d98,
+ 0xe7f1060f,
+ 0x21f50800,
+ 0xacf0016f,
+ 0x04a5f001,
+ 0x3000b7f1,
+ 0x9850b3f0,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98020c98,
+ 0x0f98030d,
+ 0x00e7f108,
+ 0x6f21f502,
+ 0x5e21f501,
+ 0x0601f402,
+/* 0x0697: ctx_xfer_post */
+ 0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+ 0xf5027f21,
+ 0xf805a221,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3
new file mode 100644
index 000000000000..b80cdfd337a9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
+
+#define CHIPSET GK100
+#include "macros.fuc"
+
+.section #gk104_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gk104_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
new file mode 100644
index 000000000000..49020fff4317
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk104.fuc3.h
@@ -0,0 +1,537 @@
+uint32_t gk104_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: unk_count */
+ 0x00000000,
+/* 0x0020: unk_mask */
+ 0x00000000,
+/* 0x0024: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gk104_grgpc_code[] = {
+ 0x03a10ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0xe0f900f8,
+ 0xf102ffb9,
+ 0xf09814e7,
+ 0x21f440e3,
+ 0x01f7f09d,
+ 0xf102ffb9,
+ 0xf09c1ce7,
+ 0x21f440e3,
+ 0xf8e0fc9d,
+/* 0x03a1: init */
+ 0xf104bd00,
+ 0xf0420017,
+ 0x11cf0013,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf00014fe,
+ 0x07f10227,
+ 0x03f01200,
+ 0x0002d000,
+ 0x17f104bd,
+ 0x10fe0530,
+ 0x0007f100,
+ 0x0003f007,
+ 0xbd0000d0,
+ 0x0427f004,
+ 0x040007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0xf11031f4,
+ 0xf0820027,
+ 0x22cf0123,
+ 0x0137f000,
+ 0xbb1f24f0,
+ 0x32b60432,
+ 0x05028001,
+ 0xf1060380,
+ 0xf0860027,
+ 0x22cf0123,
+ 0x04028000,
+ 0x0c30e7f1,
+ 0xbd50e3f0,
+ 0xbd34bd24,
+/* 0x0421: init_unk_loop */
+ 0x6821f444,
+ 0xf400f6b0,
+ 0xf7f00f0b,
+ 0x04f2bb01,
+ 0xb6054ffd,
+/* 0x0436: init_unk_next */
+ 0x20b60130,
+ 0x04e0b601,
+ 0xf40126b0,
+/* 0x0442: init_unk_done */
+ 0x0380e21b,
+ 0x08048007,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0xf1082595,
+ 0xf0c00007,
+ 0x05d00103,
+ 0xf104bd00,
+ 0xf0c10007,
+ 0x05d00103,
+ 0x9804bd00,
+ 0x0f98000e,
+ 0x5021f501,
+ 0x002fbb01,
+ 0x98003fbb,
+ 0x0f98010e,
+ 0x5021f502,
+ 0x050e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x020e9800,
+ 0xf5030f98,
+ 0x98015021,
+ 0xeffd070e,
+ 0x002ebb00,
+ 0xb6003ebb,
+ 0x07f10235,
+ 0x03f0d300,
+ 0x0003d001,
+ 0x25b604bd,
+ 0x0635b608,
+ 0xb60120b6,
+ 0x24b60130,
+ 0x0834b608,
+ 0xf5022fb9,
+ 0xbb02d321,
+ 0x07f1003f,
+ 0x03f00100,
+ 0x0003d002,
+ 0x24bd04bd,
+ 0xf11f29f0,
+ 0xf0080007,
+ 0x02d00203,
+/* 0x04f3: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x24d7f000,
+ 0xf43921f4,
+ 0xe4b0f401,
+ 0x1e18f404,
+ 0xf00181fe,
+ 0x20bd0627,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+ 0x94d30ef4,
+ 0xf5f010ef,
+ 0x7e21f501,
+ 0xc60ef403,
+/* 0x0530: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x24d7f02c,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xf00421f4,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x057e: ih_no_fifo */
+ 0x07f104bd,
+ 0x03f00100,
+ 0x000ad000,
+ 0xf0fc04bd,
+ 0xd0fce0fc,
+ 0xa0fcb0fc,
+ 0x80fc90fc,
+ 0xfc0088fe,
+ 0x0032f480,
+/* 0x05a2: hub_barrier_done */
+ 0xf7f001f8,
+ 0x040e9801,
+ 0xb904febb,
+ 0xe7f102ff,
+ 0xe3f09418,
+ 0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+ 0xf7f000f8,
+ 0x0007f120,
+ 0x0103f085,
+ 0xbd000fd0,
+ 0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+ 0xf401e2b6,
+ 0xf5f1fd1b,
+ 0xf5f10800,
+ 0x07f10200,
+ 0x03f08500,
+ 0x000fd001,
+ 0x00f804bd,
+/* 0x05e8: ctx_xfer */
+ 0x810007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+ 0xf505ba21,
+ 0xbd026a21,
+ 0xfc07f124,
+ 0x0203f047,
+ 0xbd0002d0,
+ 0x012cf004,
+ 0xf10320b6,
+ 0xf04afc07,
+ 0x02d00203,
+ 0xf004bd00,
+ 0xa5f001ac,
+ 0x00b7f102,
+ 0x50b3f000,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xacf0016f,
+ 0x00b7f101,
+ 0x50b3f040,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x010c9800,
+ 0x98020d98,
+ 0xe7f1060f,
+ 0x21f50800,
+ 0xacf0016f,
+ 0x04a5f001,
+ 0x3000b7f1,
+ 0x9850b3f0,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98020c98,
+ 0x0f98030d,
+ 0x00e7f108,
+ 0x6f21f502,
+ 0x5e21f501,
+ 0x0601f402,
+/* 0x0697: ctx_xfer_post */
+ 0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+ 0xf5027f21,
+ 0xf805a221,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3
new file mode 100644
index 000000000000..98d85fe210e8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000002
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #gk110_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gk110_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
new file mode 100644
index 000000000000..c95b07e3bce5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk110.fuc3.h
@@ -0,0 +1,537 @@
+uint32_t gk110_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: unk_count */
+ 0x00000000,
+/* 0x0020: unk_mask */
+ 0x00000000,
+/* 0x0024: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gk110_grgpc_code[] = {
+ 0x03a10ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0xe0f900f8,
+ 0xf102ffb9,
+ 0xf09814e7,
+ 0x21f440e3,
+ 0x01f7f09d,
+ 0xf102ffb9,
+ 0xf09c1ce7,
+ 0x21f440e3,
+ 0xf8e0fc9d,
+/* 0x03a1: init */
+ 0xf104bd00,
+ 0xf0420017,
+ 0x11cf0013,
+ 0x0911e700,
+ 0x0814b601,
+ 0xf00014fe,
+ 0x07f10227,
+ 0x03f01200,
+ 0x0002d000,
+ 0x17f104bd,
+ 0x10fe0530,
+ 0x0007f100,
+ 0x0003f007,
+ 0xbd0000d0,
+ 0x0427f004,
+ 0x040007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0xf11031f4,
+ 0xf0820027,
+ 0x22cf0123,
+ 0x0137f000,
+ 0xbb1f24f0,
+ 0x32b60432,
+ 0x05028001,
+ 0xf1060380,
+ 0xf0860027,
+ 0x22cf0123,
+ 0x04028000,
+ 0x0c30e7f1,
+ 0xbd50e3f0,
+ 0xbd34bd24,
+/* 0x0421: init_unk_loop */
+ 0x6821f444,
+ 0xf400f6b0,
+ 0xf7f00f0b,
+ 0x04f2bb01,
+ 0xb6054ffd,
+/* 0x0436: init_unk_next */
+ 0x20b60130,
+ 0x04e0b601,
+ 0xf40226b0,
+/* 0x0442: init_unk_done */
+ 0x0380e21b,
+ 0x08048007,
+ 0x010027f1,
+ 0xcf0223f0,
+ 0x34bd0022,
+ 0xf1082595,
+ 0xf0c00007,
+ 0x05d00103,
+ 0xf104bd00,
+ 0xf0c10007,
+ 0x05d00103,
+ 0x9804bd00,
+ 0x0f98000e,
+ 0x5021f501,
+ 0x002fbb01,
+ 0x98003fbb,
+ 0x0f98010e,
+ 0x5021f502,
+ 0x050e9801,
+ 0xbb00effd,
+ 0x3ebb002e,
+ 0x020e9800,
+ 0xf5030f98,
+ 0x98015021,
+ 0xeffd070e,
+ 0x002ebb00,
+ 0xb6003ebb,
+ 0x07f10235,
+ 0x03f0d300,
+ 0x0003d001,
+ 0x25b604bd,
+ 0x0635b608,
+ 0xb60120b6,
+ 0x24b60130,
+ 0x0834b608,
+ 0xf5022fb9,
+ 0xbb02d321,
+ 0x07f1003f,
+ 0x03f00100,
+ 0x0003d002,
+ 0x24bd04bd,
+ 0xf11f29f0,
+ 0xf0300007,
+ 0x02d00203,
+/* 0x04f3: main */
+ 0xf404bd00,
+ 0x28f40031,
+ 0x24d7f000,
+ 0xf43921f4,
+ 0xe4b0f401,
+ 0x1e18f404,
+ 0xf00181fe,
+ 0x20bd0627,
+ 0xb60412fd,
+ 0x1efd01e4,
+ 0x0018fe05,
+ 0x05e821f5,
+/* 0x0523: main_not_ctx_xfer */
+ 0x94d30ef4,
+ 0xf5f010ef,
+ 0x7e21f501,
+ 0xc60ef403,
+/* 0x0530: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x24d7f02c,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xf00421f4,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x057e: ih_no_fifo */
+ 0x07f104bd,
+ 0x03f00100,
+ 0x000ad000,
+ 0xf0fc04bd,
+ 0xd0fce0fc,
+ 0xa0fcb0fc,
+ 0x80fc90fc,
+ 0xfc0088fe,
+ 0x0032f480,
+/* 0x05a2: hub_barrier_done */
+ 0xf7f001f8,
+ 0x040e9801,
+ 0xb904febb,
+ 0xe7f102ff,
+ 0xe3f09418,
+ 0x9d21f440,
+/* 0x05ba: ctx_redswitch */
+ 0xf7f000f8,
+ 0x0007f120,
+ 0x0103f085,
+ 0xbd000fd0,
+ 0x08e7f004,
+/* 0x05cc: ctx_redswitch_delay */
+ 0xf401e2b6,
+ 0xf5f1fd1b,
+ 0xf5f10800,
+ 0x07f10200,
+ 0x03f08500,
+ 0x000fd001,
+ 0x00f804bd,
+/* 0x05e8: ctx_xfer */
+ 0x810007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0xf50711f4,
+/* 0x05fb: ctx_xfer_not_load */
+ 0xf505ba21,
+ 0xbd026a21,
+ 0xfc07f124,
+ 0x0203f047,
+ 0xbd0002d0,
+ 0x012cf004,
+ 0xf10320b6,
+ 0xf04afc07,
+ 0x02d00203,
+ 0xf004bd00,
+ 0xa5f001ac,
+ 0x00b7f102,
+ 0x50b3f000,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xacf0016f,
+ 0x00b7f101,
+ 0x50b3f040,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x010c9800,
+ 0x98020d98,
+ 0xe7f1060f,
+ 0x21f50800,
+ 0xacf0016f,
+ 0x04a5f001,
+ 0x3000b7f1,
+ 0x9850b3f0,
+ 0xc4b6040c,
+ 0x00bcbb0f,
+ 0x98020c98,
+ 0x0f98030d,
+ 0x00e7f108,
+ 0x6f21f502,
+ 0x5e21f501,
+ 0x0601f402,
+/* 0x0697: ctx_xfer_post */
+ 0xf50712f4,
+/* 0x069b: ctx_xfer_done */
+ 0xf5027f21,
+ 0xf805a221,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5
new file mode 100644
index 000000000000..8f64299a3b91
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define NV_PGRAPH_GPCX_UNK__SIZE 0x00000001
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #gk208_grgpc_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "gpc.fuc"
+#undef INCLUDE_DATA
+
+.section #gk208_grgpc_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "gpc.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
new file mode 100644
index 000000000000..7e1c28ee7591
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgk208.fuc5.h
@@ -0,0 +1,473 @@
+uint32_t gk208_grgpc_data[] = {
+/* 0x0000: gpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0004: gpc_mmio_list_tail */
+/* 0x0004: tpc_mmio_list_head */
+ 0x0000006c,
+/* 0x0008: tpc_mmio_list_tail */
+/* 0x0008: unk_mmio_list_head */
+ 0x0000006c,
+/* 0x000c: unk_mmio_list_tail */
+ 0x0000006c,
+/* 0x0010: gpc_id */
+ 0x00000000,
+/* 0x0014: tpc_count */
+ 0x00000000,
+/* 0x0018: tpc_mask */
+ 0x00000000,
+/* 0x001c: unk_count */
+ 0x00000000,
+/* 0x0020: unk_mask */
+ 0x00000000,
+/* 0x0024: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gk208_grgpc_code[] = {
+ 0x03140ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0xf489a408,
+ 0x020f0b1b,
+ 0x0002f87e,
+/* 0x001a: queue_put_next */
+ 0x98c400f8,
+ 0x0384b607,
+ 0xb6008dbb,
+ 0x8eb50880,
+ 0x018fb500,
+ 0xf00190b6,
+ 0xd9b50f94,
+/* 0x0037: queue_get */
+ 0xf400f801,
+ 0xd8980131,
+ 0x01d99800,
+ 0x0bf489a4,
+ 0x0789c421,
+ 0xbb0394b6,
+ 0x90b6009d,
+ 0x009e9808,
+ 0xb6019f98,
+ 0x84f00180,
+ 0x00d8b50f,
+/* 0x0063: queue_get_done */
+ 0xf80132f4,
+/* 0x0065: nv_rd32 */
+ 0xf0ecb200,
+ 0x00801fc9,
+ 0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+ 0x8c04bd00,
+ 0xcf01ca00,
+ 0xccc800cc,
+ 0xf61bf41f,
+ 0xec7e060a,
+ 0x008f0000,
+ 0xffcf01cb,
+/* 0x008f: nv_wr32 */
+ 0x8000f800,
+ 0xf601cc00,
+ 0x04bd000f,
+ 0xc9f0ecb2,
+ 0x1ec9f01f,
+ 0x01ca0080,
+ 0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+ 0xca008c04,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f61b,
+/* 0x00b8: wait_donez */
+ 0x99f094bd,
+ 0x37008000,
+ 0x0009f602,
+ 0x008004bd,
+ 0x0af60206,
+/* 0x00cf: wait_donez_ne */
+ 0x8804bd00,
+ 0xcf010000,
+ 0x8aff0088,
+ 0xf61bf488,
+ 0x99f094bd,
+ 0x17008000,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x00ec: wait_doneo */
+ 0x99f094bd,
+ 0x37008000,
+ 0x0009f602,
+ 0x008004bd,
+ 0x0af60206,
+/* 0x0103: wait_doneo_e */
+ 0x8804bd00,
+ 0xcf010000,
+ 0x8aff0088,
+ 0xf60bf488,
+ 0x99f094bd,
+ 0x17008000,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0x1bf4efa4,
+ 0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+ 0xf094bd00,
+ 0x00800199,
+ 0x09f60237,
+ 0xbd04bd00,
+ 0x05bbfd94,
+ 0x800f0bf4,
+ 0xf601c400,
+ 0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0xc6008018,
+ 0x000ef601,
+ 0x008004bd,
+ 0x0ff601c7,
+ 0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+ 0xabc80199,
+ 0x10b4b600,
+ 0xc80cb9f0,
+ 0xe4b601ae,
+ 0x05befd11,
+ 0x01c50080,
+ 0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+ 0xc5008e04,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f60b,
+ 0x05e9fd00,
+ 0x01c80080,
+ 0xbd000ef6,
+ 0x04c0b604,
+ 0x1bf4cda4,
+ 0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+ 0x8b1c1bf4,
+ 0xcf01c500,
+ 0xb4f000bb,
+ 0x10b4b01f,
+ 0x0af31bf4,
+ 0x00b87e05,
+ 0x250ef400,
+/* 0x01d8: mmctx_stop */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x12b9f00c,
+ 0x01c50080,
+ 0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+ 0xc5008b04,
+ 0x00bbcf01,
+ 0xf412bbc8,
+/* 0x01fa: mmctx_done */
+ 0x94bdf61b,
+ 0x800199f0,
+ 0xf6021700,
+ 0x04bd0009,
+/* 0x020a: strand_wait */
+ 0xa0f900f8,
+ 0xb87e020a,
+ 0xa0fc0000,
+/* 0x0216: strand_pre */
+ 0x0c0900f8,
+ 0x024afc80,
+ 0xbd0009f6,
+ 0x020a7e04,
+/* 0x0227: strand_post */
+ 0x0900f800,
+ 0x4afc800d,
+ 0x0009f602,
+ 0x0a7e04bd,
+ 0x00f80002,
+/* 0x0238: strand_set */
+ 0xfc800f0c,
+ 0x0cf6024f,
+ 0x0c04bd00,
+ 0x4afc800b,
+ 0x000cf602,
+ 0xfc8004bd,
+ 0x0ef6024f,
+ 0x0c04bd00,
+ 0x4afc800a,
+ 0x000cf602,
+ 0x0a7e04bd,
+ 0x00f80002,
+/* 0x0268: strand_ctx_init */
+ 0x99f094bd,
+ 0x37008003,
+ 0x0009f602,
+ 0x167e04bd,
+ 0x030e0002,
+ 0x0002387e,
+ 0xfc80c4bd,
+ 0x0cf60247,
+ 0x0c04bd00,
+ 0x4afc8001,
+ 0x000cf602,
+ 0x0a7e04bd,
+ 0x0c920002,
+ 0x46fc8001,
+ 0x000cf602,
+ 0x020c04bd,
+ 0x024afc80,
+ 0xbd000cf6,
+ 0x020a7e04,
+ 0x02277e00,
+ 0x42008800,
+ 0x20008902,
+ 0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+ 0xf608fe95,
+ 0x8ef6008e,
+ 0x808acf40,
+ 0xb606a5b6,
+ 0xeabb01a0,
+ 0x0480b600,
+ 0xf40192b6,
+ 0xe4b6e81b,
+ 0xf2efbc08,
+ 0x99f094bd,
+ 0x17008003,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x02f8: error */
+ 0xffb2e0f9,
+ 0x4098148e,
+ 0x00008f7e,
+ 0xffb2010f,
+ 0x409c1c8e,
+ 0x00008f7e,
+ 0x00f8e0fc,
+/* 0x0314: init */
+ 0x004104bd,
+ 0x0011cf42,
+ 0x010911e7,
+ 0xfe0814b6,
+ 0x02020014,
+ 0xf6120040,
+ 0x04bd0002,
+ 0xfe047241,
+ 0x00400010,
+ 0x0000f607,
+ 0x040204bd,
+ 0xf6040040,
+ 0x04bd0002,
+ 0x821031f4,
+ 0xcf018200,
+ 0x01030022,
+ 0xbb1f24f0,
+ 0x32b60432,
+ 0x0502b501,
+ 0x820603b5,
+ 0xcf018600,
+ 0x02b50022,
+ 0x0c308e04,
+ 0xbd24bd50,
+/* 0x0377: init_unk_loop */
+ 0x7e44bd34,
+ 0xb0000065,
+ 0x0bf400f6,
+ 0xbb010f0e,
+ 0x4ffd04f2,
+ 0x0130b605,
+/* 0x038c: init_unk_next */
+ 0xb60120b6,
+ 0x26b004e0,
+ 0xe21bf401,
+/* 0x0398: init_unk_done */
+ 0xb50703b5,
+ 0x00820804,
+ 0x22cf0201,
+ 0x9534bd00,
+ 0x00800825,
+ 0x05f601c0,
+ 0x8004bd00,
+ 0xf601c100,
+ 0x04bd0005,
+ 0x98000e98,
+ 0x207e010f,
+ 0x2fbb0001,
+ 0x003fbb00,
+ 0x98010e98,
+ 0x207e020f,
+ 0x0e980001,
+ 0x00effd05,
+ 0xbb002ebb,
+ 0x0e98003e,
+ 0x030f9802,
+ 0x0001207e,
+ 0xfd070e98,
+ 0x2ebb00ef,
+ 0x003ebb00,
+ 0x800235b6,
+ 0xf601d300,
+ 0x04bd0003,
+ 0xb60825b6,
+ 0x20b60635,
+ 0x0130b601,
+ 0xb60824b6,
+ 0x2fb20834,
+ 0x0002687e,
+ 0x80003fbb,
+ 0xf6020100,
+ 0x04bd0003,
+ 0x29f024bd,
+ 0x3000801f,
+ 0x0002f602,
+/* 0x0436: main */
+ 0x31f404bd,
+ 0x0028f400,
+ 0x377e240d,
+ 0x01f40000,
+ 0x04e4b0f4,
+ 0xfe1d18f4,
+ 0x06020181,
+ 0x12fd20bd,
+ 0x01e4b604,
+ 0xfe051efd,
+ 0x097e0018,
+ 0x0ef40005,
+/* 0x0465: main_not_ctx_xfer */
+ 0x10ef94d4,
+ 0x7e01f5f0,
+ 0xf40002f8,
+/* 0x0472: ih */
+ 0x80f9c70e,
+ 0xf90188fe,
+ 0xf990f980,
+ 0xf9b0f9a0,
+ 0xf9e0f9d0,
+ 0x4a04bdf0,
+ 0xaacf0200,
+ 0x04abc400,
+ 0x0d1f0bf4,
+ 0x1a004e24,
+ 0x4f00eecf,
+ 0xffcf1900,
+ 0x00047e00,
+ 0x40010e00,
+ 0x0ef61d00,
+/* 0x04af: ih_no_fifo */
+ 0x4004bd00,
+ 0x0af60100,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x04cf: hub_barrier_done */
+ 0x0f01f800,
+ 0x040e9801,
+ 0xb204febb,
+ 0x94188eff,
+ 0x008f7e40,
+/* 0x04e3: ctx_redswitch */
+ 0x0f00f800,
+ 0x85008020,
+ 0x000ff601,
+ 0x080e04bd,
+/* 0x04f0: ctx_redswitch_delay */
+ 0xf401e2b6,
+ 0xf5f1fd1b,
+ 0xf5f10800,
+ 0x00800200,
+ 0x0ff60185,
+ 0xf804bd00,
+/* 0x0509: ctx_xfer */
+ 0x81008000,
+ 0x000ff602,
+ 0x11f404bd,
+ 0x04e37e07,
+/* 0x0519: ctx_xfer_not_load */
+ 0x02167e00,
+ 0x8024bd00,
+ 0xf60247fc,
+ 0x04bd0002,
+ 0xb6012cf0,
+ 0xfc800320,
+ 0x02f6024a,
+ 0xf004bd00,
+ 0xa5f001ac,
+ 0x00008b02,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x010d9800,
+ 0x3d7e000e,
+ 0xacf00001,
+ 0x40008b01,
+ 0x040c9850,
+ 0xbb0fc4b6,
+ 0x0c9800bc,
+ 0x020d9801,
+ 0x4e060f98,
+ 0x3d7e0800,
+ 0xacf00001,
+ 0x04a5f001,
+ 0x5030008b,
+ 0xb6040c98,
+ 0xbcbb0fc4,
+ 0x020c9800,
+ 0x98030d98,
+ 0x004e080f,
+ 0x013d7e02,
+ 0x020a7e00,
+ 0x0601f400,
+/* 0x05a3: ctx_xfer_post */
+ 0x7e0712f4,
+/* 0x05a7: ctx_xfer_done */
+ 0x7e000227,
+ 0xf80004cf,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5
index e730603891d7..e730603891d7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
index 6d53b67dd3c4..6d53b67dd3c4 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/gpcgm107.fuc5.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/gpcgm107.fuc5.h
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc
new file mode 100644
index 000000000000..87f99e38acbf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hub.fuc
@@ -0,0 +1,696 @@
+/* fuc microcode for gf100 PGRAPH/HUB
+ *
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#ifdef INCLUDE_DATA
+hub_mmio_list_head: .b32 #hub_mmio_list_base
+hub_mmio_list_tail: .b32 #hub_mmio_list_next
+
+gpc_count: .b32 0
+rop_count: .b32 0
+cmd_queue: queue_init
+
+ctx_current: .b32 0
+
+.align 256
+chan_data:
+chan_mmio_count: .b32 0
+chan_mmio_address: .b32 0
+
+.align 256
+xfer_data: .skip 256
+
+hub_mmio_list_base:
+.b32 0x0417e91c // 0x17e91c, 2
+hub_mmio_list_next:
+#endif
+
+#ifdef INCLUDE_CODE
+// reports an exception to the host
+//
+// In: $r15 error code (see os.h)
+//
+error:
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(5), 0, $r15)
+ mov $r15 1
+ nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r15)
+ ret
+
+// HUB fuc initialisation, executed by triggering ucode start, will
+// fall through to main loop after completion.
+//
+// Output:
+// CC_SCRATCH[0]:
+// 31:31: set to signal completion
+// CC_SCRATCH[1]:
+// 31:0: total PGRAPH context size
+//
+init:
+ clear b32 $r0
+ mov $xdbase $r0
+
+ // setup stack
+ nv_iord($r1, NV_PGRAPH_FECS_CAPS, 0)
+ extr $r1 $r1 9:17
+ shl b32 $r1 8
+ mov $sp $r1
+
+ // enable fifo access
+ mov $r2 NV_PGRAPH_FECS_ACCESS_FIFO
+ nv_iowr(NV_PGRAPH_FECS_ACCESS, 0, $r2)
+
+ // setup i0 handler, and route all interrupts to it
+ mov $r1 #ih
+ mov $iv0 $r1
+
+ clear b32 $r2
+ nv_iowr(NV_PGRAPH_FECS_INTR_ROUTE, 0, $r2)
+
+ // route HUB_CHSW_PULSE to fuc interrupt 8
+ mov $r2 0x2003 // { HUB_CHSW_PULSE, ZERO } -> intr 8
+ nv_iowr(NV_PGRAPH_FECS_IROUTE, 0, $r2)
+
+ // not sure what these are, route them because NVIDIA does, and
+ // the IRQ handler will signal the host if we ever get one.. we
+ // may find out if/why we need to handle these if so..
+ //
+ mov $r2 0x2004 // { 0x04, ZERO } -> intr 9
+ nv_iowr(NV_PGRAPH_FECS_IROUTE, 1, $r2)
+ mov $r2 0x200b // { HUB_FIRMWARE_MTHD, ZERO } -> intr 10
+ nv_iowr(NV_PGRAPH_FECS_IROUTE, 2, $r2)
+ mov $r2 0x200c // { 0x0c, ZERO } -> intr 15
+ nv_iowr(NV_PGRAPH_FECS_IROUTE, 7, $r2)
+
+ // enable all INTR_UP interrupts
+ sub b32 $r3 $r0 1
+ nv_iowr(NV_PGRAPH_FECS_INTR_UP_EN, 0, $r3)
+
+ // enable fifo, ctxsw, 9, fwmthd, 15 interrupts
+ imm32($r2, 0x8704)
+ nv_iowr(NV_PGRAPH_FECS_INTR_EN_SET, 0, $r2)
+
+ // fifo level triggered, rest edge
+ mov $r2 NV_PGRAPH_FECS_INTR_MODE_FIFO_LEVEL
+ nv_iowr(NV_PGRAPH_FECS_INTR_MODE, 0, $r2)
+
+ // enable interrupts
+ bset $flags ie0
+
+ // fetch enabled GPC/ROP counts
+ nv_rd32($r14, 0x409604)
+ extr $r1 $r15 16:20
+ st b32 D[$r0 + #rop_count] $r1
+ and $r15 0x1f
+ st b32 D[$r0 + #gpc_count] $r15
+
+ // set BAR_REQMASK to GPC mask
+ mov $r1 1
+ shl b32 $r1 $r15
+ sub b32 $r1 1
+ nv_iowr(NV_PGRAPH_FECS_BAR_MASK0, 0, $r1)
+ nv_iowr(NV_PGRAPH_FECS_BAR_MASK1, 0, $r1)
+
+ // context size calculation, reserve first 256 bytes for use by fuc
+ mov $r1 256
+
+ //
+ mov $r15 2
+ call(ctx_4170s)
+ call(ctx_4170w)
+ mov $r15 0x10
+ call(ctx_86c)
+
+ // calculate size of mmio context data
+ ld b32 $r14 D[$r0 + #hub_mmio_list_head]
+ ld b32 $r15 D[$r0 + #hub_mmio_list_tail]
+ call(mmctx_size)
+
+ // set mmctx base addresses now so we don't have to do it later,
+ // they don't (currently) ever change
+ shr b32 $r4 $r1 8
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_SAVE_SWBASE, 0, $r4)
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_SWBASE, 0, $r4)
+ add b32 $r3 0x1300
+ add b32 $r1 $r15
+ shr b32 $r15 2
+ nv_iowr(NV_PGRAPH_FECS_MMCTX_LOAD_COUNT, 0, $r15) // wtf??
+
+ // strands, base offset needs to be aligned to 256 bytes
+ shr b32 $r1 8
+ add b32 $r1 1
+ shl b32 $r1 8
+ mov b32 $r15 $r1
+ call(strand_ctx_init)
+ add b32 $r1 $r15
+
+ // initialise each GPC in sequence by passing in the offset of its
+ // context data in GPCn_CC_SCRATCH[1], and starting its FUC (which
+ // has previously been uploaded by the host) running.
+ //
+ // the GPC fuc init sequence will set GPCn_CC_SCRATCH[0] bit 31
+ // when it has completed, and return the size of its context data
+ // in GPCn_CC_SCRATCH[1]
+ //
+ ld b32 $r3 D[$r0 + #gpc_count]
+ imm32($r4, 0x502000)
+ init_gpc:
+ // setup, and start GPC ucode running
+ add b32 $r14 $r4 0x804
+ mov b32 $r15 $r1
+ call(nv_wr32) // CC_SCRATCH[1] = ctx offset
+ add b32 $r14 $r4 0x10c
+ clear b32 $r15
+ call(nv_wr32)
+ add b32 $r14 $r4 0x104
+ call(nv_wr32) // ENTRY
+ add b32 $r14 $r4 0x100
+ mov $r15 2 // CTRL_START_TRIGGER
+ call(nv_wr32) // CTRL
+
+ // wait for it to complete, and adjust context size
+ add b32 $r14 $r4 0x800
+ init_gpc_wait:
+ call(nv_rd32)
+ xbit $r15 $r15 31
+ bra e #init_gpc_wait
+ add b32 $r14 $r4 0x804
+ call(nv_rd32)
+ add b32 $r1 $r15
+
+ // next!
+ add b32 $r4 0x8000
+ sub b32 $r3 1
+ bra ne #init_gpc
+
+ //
+ mov $r15 0
+ call(ctx_86c)
+ mov $r15 0
+ call(ctx_4170s)
+
+ // save context size, and tell host we're ready
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(1), 0, $r1)
+ clear b32 $r1
+ bset $r1 31
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r1)
+
+// Main program loop, very simple, sleeps until woken up by the interrupt
+// handler, pulls a command from the queue and executes its handler
+//
+main:
+ // sleep until we have something to do
+ bset $flags $p0
+ sleep $p0
+ mov $r13 #cmd_queue
+ call(queue_get)
+ bra $p1 #main
+
+ // context switch, requested by GPU?
+ cmpu b32 $r14 0x4001
+ bra ne #main_not_ctx_switch
+ trace_set(T_AUTO)
+ nv_iord($r1, NV_PGRAPH_FECS_CHAN_ADDR, 0)
+ nv_iord($r2, NV_PGRAPH_FECS_CHAN_NEXT, 0)
+
+ xbit $r3 $r1 31
+ bra e #chsw_no_prev
+ xbit $r3 $r2 31
+ bra e #chsw_prev_no_next
+ push $r2
+ mov b32 $r2 $r1
+ trace_set(T_SAVE)
+ bclr $flags $p1
+ bset $flags $p2
+ call(ctx_xfer)
+ trace_clr(T_SAVE);
+ pop $r2
+ trace_set(T_LOAD);
+ bset $flags $p1
+ call(ctx_xfer)
+ trace_clr(T_LOAD);
+ bra #chsw_done
+ chsw_prev_no_next:
+ push $r2
+ mov b32 $r2 $r1
+ bclr $flags $p1
+ bclr $flags $p2
+ call(ctx_xfer)
+ pop $r2
+ nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
+ bra #chsw_done
+ chsw_no_prev:
+ xbit $r3 $r2 31
+ bra e #chsw_done
+ bset $flags $p1
+ bclr $flags $p2
+ call(ctx_xfer)
+
+ // ack the context switch request
+ chsw_done:
+ mov $r2 NV_PGRAPH_FECS_CHSW_ACK
+ nv_iowr(NV_PGRAPH_FECS_CHSW, 0, $r2)
+ trace_clr(T_AUTO)
+ bra #main
+
+ // request to set current channel? (*not* a context switch)
+ main_not_ctx_switch:
+ cmpu b32 $r14 0x0001
+ bra ne #main_not_ctx_chan
+ mov b32 $r2 $r15
+ call(ctx_chan)
+ bra #main_done
+
+ // request to store current channel context?
+ main_not_ctx_chan:
+ cmpu b32 $r14 0x0002
+ bra ne #main_not_ctx_save
+ trace_set(T_SAVE)
+ bclr $flags $p1
+ bclr $flags $p2
+ call(ctx_xfer)
+ trace_clr(T_SAVE)
+ bra #main_done
+
+ main_not_ctx_save:
+ shl b32 $r15 $r14 16
+ or $r15 E_BAD_COMMAND
+ call(error)
+ bra #main
+
+ main_done:
+ clear b32 $r2
+ bset $r2 31
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_SET(0), 0, $r2)
+ bra #main
+
+// interrupt handler
+ih:
+ push $r8
+ mov $r8 $flags
+ push $r8
+ push $r9
+ push $r10
+ push $r11
+ push $r13
+ push $r14
+ push $r15
+ clear b32 $r0
+
+ // incoming fifo command?
+ nv_iord($r10, NV_PGRAPH_FECS_INTR, 0)
+ and $r11 $r10 NV_PGRAPH_FECS_INTR_FIFO
+ bra e #ih_no_fifo
+ // queue incoming fifo command for later processing
+ mov $r13 #cmd_queue
+ nv_iord($r14, NV_PGRAPH_FECS_FIFO_CMD, 0)
+ nv_iord($r15, NV_PGRAPH_FECS_FIFO_DATA, 0)
+ call(queue_put)
+ add b32 $r11 0x400
+ mov $r14 1
+ nv_iowr(NV_PGRAPH_FECS_FIFO_ACK, 0, $r14)
+
+ // context switch request?
+ ih_no_fifo:
+ and $r11 $r10 NV_PGRAPH_FECS_INTR_CHSW
+ bra e #ih_no_ctxsw
+ // enqueue a context switch for later processing
+ mov $r13 #cmd_queue
+ mov $r14 0x4001
+ call(queue_put)
+
+ // firmware method?
+ ih_no_ctxsw:
+ and $r11 $r10 NV_PGRAPH_FECS_INTR_FWMTHD
+ bra e #ih_no_fwmthd
+ // none we handle; report to host and ack
+ nv_rd32($r15, NV_PGRAPH_TRAPPED_DATA_LO)
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(4), 0, $r15)
+ nv_rd32($r15, NV_PGRAPH_TRAPPED_ADDR)
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(3), 0, $r15)
+ extr $r14 $r15 16:18
+ shl b32 $r14 $r14 2
+ imm32($r15, NV_PGRAPH_FE_OBJECT_TABLE(0))
+ add b32 $r14 $r15
+ call(nv_rd32)
+ nv_iowr(NV_PGRAPH_FECS_CC_SCRATCH_VAL(2), 0, $r15)
+ mov $r15 E_BAD_FWMTHD
+ call(error)
+ mov $r11 0x100
+ nv_wr32(0x400144, $r11)
+
+ // anything we didn't handle, bring it to the host's attention
+ ih_no_fwmthd:
+ mov $r11 0x504 // FIFO | CHSW | FWMTHD
+ not b32 $r11
+ and $r11 $r10 $r11
+ bra e #ih_no_other
+ nv_iowr(NV_PGRAPH_FECS_INTR_UP_SET, 0, $r11)
+
+ // ack, and wake up main()
+ ih_no_other:
+ nv_iowr(NV_PGRAPH_FECS_INTR_ACK, 0, $r10)
+
+ pop $r15
+ pop $r14
+ pop $r13
+ pop $r11
+ pop $r10
+ pop $r9
+ pop $r8
+ mov $flags $r8
+ pop $r8
+ bclr $flags $p0
+ iret
+
+#if CHIPSET < GK100
+// Not real sure, but, MEM_CMD 7 will hang forever if this isn't done
+ctx_4160s:
+ mov $r15 1
+ nv_wr32(0x404160, $r15)
+ ctx_4160s_wait:
+ nv_rd32($r15, 0x404160)
+ xbit $r15 $r15 4
+ bra e #ctx_4160s_wait
+ ret
+
+// Without clearing again at end of xfer, some things cause PGRAPH
+// to hang with STATUS=0x00000007 until it's cleared.. fbcon can
+// still function with it set however...
+ctx_4160c:
+ clear b32 $r15
+ nv_wr32(0x404160, $r15)
+ ret
+#endif
+
+// Again, not real sure
+//
+// In: $r15 value to set 0x404170 to
+//
+ctx_4170s:
+ or $r15 0x10
+ nv_wr32(0x404170, $r15)
+ ret
+
+// Waits for a ctx_4170s() call to complete
+//
+ctx_4170w:
+ nv_rd32($r15, 0x404170)
+ and $r15 0x10
+ bra ne #ctx_4170w
+ ret
+
+// Disables various things, waits a bit, and re-enables them..
+//
+// Not sure how exactly this helps, perhaps "ENABLE" is not such a
+// good description for the bits we turn off? Anyways, without this,
+// funny things happen.
+//
+ctx_redswitch:
+ mov $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_GPC
+ or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_ROP
+ or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_GPC
+ or $r14 NV_PGRAPH_FECS_RED_SWITCH_POWER_MAIN
+ nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
+ mov $r15 8
+ ctx_redswitch_delay:
+ sub b32 $r15 1
+ bra ne #ctx_redswitch_delay
+ or $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_ROP
+ or $r14 NV_PGRAPH_FECS_RED_SWITCH_ENABLE_MAIN
+ nv_iowr(NV_PGRAPH_FECS_RED_SWITCH, 0, $r14)
+ ret
+
+// Not a clue what this is for, except that unless the value is 0x10, the
+// strand context is saved (and presumably restored) incorrectly..
+//
+// In: $r15 value to set to (0x00/0x10 are used)
+//
+ctx_86c:
+ nv_iowr(NV_PGRAPH_FECS_UNK86C, 0, $r15)
+ nv_wr32(0x408a14, $r15)
+ nv_wr32(NV_PGRAPH_GPCX_GPCCS_UNK86C, $r15)
+ ret
+
+// In: $r15 NV_PGRAPH_FECS_MEM_CMD_*
+ctx_mem:
+ nv_iowr(NV_PGRAPH_FECS_MEM_CMD, 0, $r15)
+ ctx_mem_wait:
+ nv_iord($r15, NV_PGRAPH_FECS_MEM_CMD, 0)
+ or $r15 $r15
+ bra ne #ctx_mem_wait
+ ret
+
+// ctx_load - load's a channel's ctxctl data, and selects its vm
+//
+// In: $r2 channel address
+//
+ctx_load:
+ trace_set(T_CHAN)
+
+ // switch to channel, somewhat magic in parts..
+ mov $r10 12 // DONE_UNK12
+ call(wait_donez)
+ clear b32 $r15
+ nv_iowr(0x409a24, 0, $r15)
+ nv_iowr(NV_PGRAPH_FECS_CHAN_NEXT, 0, $r2)
+ nv_iowr(NV_PGRAPH_FECS_MEM_CHAN, 0, $r2)
+ mov $r15 NV_PGRAPH_FECS_MEM_CMD_LOAD_CHAN
+ call(ctx_mem)
+ nv_iowr(NV_PGRAPH_FECS_CHAN_ADDR, 0, $r2)
+
+ // load channel header, fetch PGRAPH context pointer
+ mov $xtargets $r0
+ bclr $r2 31
+ shl b32 $r2 4
+ add b32 $r2 2
+
+ trace_set(T_LCHAN)
+ nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r2)
+ imm32($r2, NV_PGRAPH_FECS_MEM_TARGET_UNK31)
+ or $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VRAM
+ nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
+ mov $r1 0x10 // chan + 0x0210
+ mov $r2 #xfer_data
+ sethi $r2 0x00020000 // 16 bytes
+ xdld $r1 $r2
+ xdwait
+ trace_clr(T_LCHAN)
+
+ // update current context
+ ld b32 $r1 D[$r0 + #xfer_data + 4]
+ shl b32 $r1 24
+ ld b32 $r2 D[$r0 + #xfer_data + 0]
+ shr b32 $r2 8
+ or $r1 $r2
+ st b32 D[$r0 + #ctx_current] $r1
+
+ // set transfer base to start of context, and fetch context header
+ trace_set(T_LCTXH)
+ nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r1)
+ mov $r2 NV_PGRAPH_FECS_MEM_TARGET_AS_VM
+ nv_iowr(NV_PGRAPH_FECS_MEM_TARGET, 0, $r2)
+ mov $r1 #chan_data
+ sethi $r1 0x00060000 // 256 bytes
+ xdld $r0 $r1
+ xdwait
+ trace_clr(T_LCTXH)
+
+ trace_clr(T_CHAN)
+ ret
+
+// ctx_chan - handler for HUB_SET_CHAN command, will set a channel as
+// the active channel for ctxctl, but not actually transfer
+// any context data. intended for use only during initial
+// context construction.
+//
+// In: $r2 channel address
+//
+ctx_chan:
+#if CHIPSET < GK100
+ call(ctx_4160s)
+#endif
+ call(ctx_load)
+ mov $r10 12 // DONE_UNK12
+ call(wait_donez)
+ mov $r15 5 // MEM_CMD 5 ???
+ call(ctx_mem)
+#if CHIPSET < GK100
+ call(ctx_4160c)
+#endif
+ ret
+
+// Execute per-context state overrides list
+//
+// Only executed on the first load of a channel. Might want to look into
+// removing this and having the host directly modify the channel's context
+// to change this state... The nouveau DRM already builds this list as
+// it's definitely needed for NVIDIA's, so we may as well use it for now
+//
+// Input: $r1 mmio list length
+//
+ctx_mmio_exec:
+ // set transfer base to be the mmio list
+ ld b32 $r3 D[$r0 + #chan_mmio_address]
+ nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
+
+ clear b32 $r3
+ ctx_mmio_loop:
+ // fetch next 256 bytes of mmio list if necessary
+ and $r4 $r3 0xff
+ bra ne #ctx_mmio_pull
+ mov $r5 #xfer_data
+ sethi $r5 0x00060000 // 256 bytes
+ xdld $r3 $r5
+ xdwait
+
+ // execute a single list entry
+ ctx_mmio_pull:
+ ld b32 $r14 D[$r4 + #xfer_data + 0x00]
+ ld b32 $r15 D[$r4 + #xfer_data + 0x04]
+ call(nv_wr32)
+
+ // next!
+ add b32 $r3 8
+ sub b32 $r1 1
+ bra ne #ctx_mmio_loop
+
+ // set transfer base back to the current context
+ ctx_mmio_done:
+ ld b32 $r3 D[$r0 + #ctx_current]
+ nv_iowr(NV_PGRAPH_FECS_MEM_BASE, 0, $r3)
+
+ // disable the mmio list now, we don't need/want to execute it again
+ st b32 D[$r0 + #chan_mmio_count] $r0
+ mov $r1 #chan_data
+ sethi $r1 0x00060000 // 256 bytes
+ xdst $r0 $r1
+ xdwait
+ ret
+
+// Transfer HUB context data between GPU and storage area
+//
+// In: $r2 channel address
+// $p1 clear on save, set on load
+// $p2 set if opposite direction done/will be done, so:
+// on save it means: "a load will follow this save"
+// on load it means: "a save preceeded this load"
+//
+ctx_xfer:
+ // according to mwk, some kind of wait for idle
+ mov $r14 4
+ nv_iowr(0x409c08, 0, $r14)
+ ctx_xfer_idle:
+ nv_iord($r14, 0x409c00, 0)
+ and $r14 0x2000
+ bra ne #ctx_xfer_idle
+
+ bra not $p1 #ctx_xfer_pre
+ bra $p2 #ctx_xfer_pre_load
+ ctx_xfer_pre:
+ mov $r15 0x10
+ call(ctx_86c)
+#if CHIPSET < GK100
+ call(ctx_4160s)
+#endif
+ bra not $p1 #ctx_xfer_exec
+
+ ctx_xfer_pre_load:
+ mov $r15 2
+ call(ctx_4170s)
+ call(ctx_4170w)
+ call(ctx_redswitch)
+ clear b32 $r15
+ call(ctx_4170s)
+ call(ctx_load)
+
+ // fetch context pointer, and initiate xfer on all GPCs
+ ctx_xfer_exec:
+ ld b32 $r1 D[$r0 + #ctx_current]
+
+ clear b32 $r2
+ nv_iowr(NV_PGRAPH_FECS_BAR, 0, $r2)
+
+ nv_wr32(0x41a500, $r1) // GPC_BCAST_WRCMD_DATA = ctx pointer
+ xbit $r15 $flags $p1
+ xbit $r2 $flags $p2
+ shl b32 $r2 1
+ or $r15 $r2
+ nv_wr32(0x41a504, $r15) // GPC_BCAST_WRCMD_CMD = GPC_XFER(type)
+
+ // strands
+ call(strand_pre)
+ clear b32 $r2
+ nv_iowr(NV_PGRAPH_FECS_STRAND_SELECT, 0x3f, $r2)
+ xbit $r2 $flags $p1 // SAVE/LOAD
+ add b32 $r2 NV_PGRAPH_FECS_STRAND_CMD_SAVE
+ nv_iowr(NV_PGRAPH_FECS_STRAND_CMD, 0x3f, $r2)
+
+ // mmio context
+ xbit $r10 $flags $p1 // direction
+ or $r10 6 // first, last
+ mov $r11 0 // base = 0
+ ld b32 $r12 D[$r0 + #hub_mmio_list_head]
+ ld b32 $r13 D[$r0 + #hub_mmio_list_tail]
+ mov $r14 0 // not multi
+ call(mmctx_xfer)
+
+ // wait for GPCs to all complete
+ mov $r10 8 // DONE_BAR
+ call(wait_doneo)
+
+ // wait for strand xfer to complete
+ call(strand_wait)
+
+ // post-op
+ bra $p1 #ctx_xfer_post
+ mov $r10 12 // DONE_UNK12
+ call(wait_donez)
+ mov $r15 5 // MEM_CMD 5 ???
+ call(ctx_mem)
+
+ bra $p2 #ctx_xfer_done
+ ctx_xfer_post:
+ mov $r15 2
+ call(ctx_4170s)
+ clear b32 $r15
+ call(ctx_86c)
+ call(strand_post)
+ call(ctx_4170w)
+ clear b32 $r15
+ call(ctx_4170s)
+
+ bra not $p1 #ctx_xfer_no_post_mmio
+ ld b32 $r1 D[$r0 + #chan_mmio_count]
+ or $r1 $r1
+ bra e #ctx_xfer_no_post_mmio
+ call(ctx_mmio_exec)
+
+ ctx_xfer_no_post_mmio:
+#if CHIPSET < GK100
+ call(ctx_4160c)
+#endif
+
+ ctx_xfer_done:
+ ret
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3
new file mode 100644
index 000000000000..2c28e7199b7f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GF100
+#include "macros.fuc"
+
+.section #gf100_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gf100_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h
new file mode 100644
index 000000000000..f6acda505677
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf100.fuc3.h
@@ -0,0 +1,1047 @@
+uint32_t gf100_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t gf100_grhub_code[] = {
+ 0x039b0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x039b: init */
+ 0xbd00f804,
+ 0x0007fe04,
+ 0x420017f1,
+ 0xcf0013f0,
+ 0x11e70011,
+ 0x14b60109,
+ 0x0014fe08,
+ 0xf10227f0,
+ 0xf0120007,
+ 0x02d00003,
+ 0xf104bd00,
+ 0xfe06c817,
+ 0x24bd0010,
+ 0x070007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0x200327f1,
+ 0x010007f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200427f1,
+ 0x010407f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200b27f1,
+ 0x010807f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200c27f1,
+ 0x011c07f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0xf1010392,
+ 0xf0090007,
+ 0x03d00303,
+ 0xf104bd00,
+ 0xf0870427,
+ 0x07f10023,
+ 0x03f00400,
+ 0x0002d000,
+ 0x27f004bd,
+ 0x0007f104,
+ 0x0003f003,
+ 0xbd0002d0,
+ 0x1031f404,
+ 0x9604e7f1,
+ 0xf440e3f0,
+ 0xfeb96821,
+ 0x90f1c702,
+ 0xf0030180,
+ 0x0f801ff4,
+ 0x0117f002,
+ 0xb6041fbb,
+ 0x07f10112,
+ 0x03f00300,
+ 0x0001d001,
+ 0x07f104bd,
+ 0x03f00400,
+ 0x0001d001,
+ 0x17f104bd,
+ 0xf7f00100,
+ 0x0d21f502,
+ 0x1f21f508,
+ 0x10f7f008,
+ 0x086c21f5,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x14950150,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0004d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0004d0,
+ 0x0030b704,
+ 0x001fbb13,
+ 0xf102f5b6,
+ 0xf0d30007,
+ 0x0fd00103,
+ 0xb604bd00,
+ 0x10b60815,
+ 0x0814b601,
+ 0xf5021fb9,
+ 0xbb02d321,
+ 0x0398001f,
+ 0x0047f102,
+ 0x5043f020,
+/* 0x04f4: init_gpc */
+ 0x08044ea0,
+ 0xf4021fb9,
+ 0x4ea09d21,
+ 0xf4bd010c,
+ 0xa09d21f4,
+ 0xf401044e,
+ 0x4ea09d21,
+ 0xf7f00100,
+ 0x9d21f402,
+ 0x08004ea0,
+/* 0x051c: init_gpc_wait */
+ 0xc86821f4,
+ 0x0bf41fff,
+ 0x044ea0fa,
+ 0x6821f408,
+ 0xb7001fbb,
+ 0xb6800040,
+ 0x1bf40132,
+ 0x00f7f0be,
+ 0x086c21f5,
+ 0xf500f7f0,
+ 0xf1080d21,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0564: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00e91b,
+ 0x0499f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xc00017f1,
+ 0xcf0213f0,
+ 0x27f10011,
+ 0x23f0c100,
+ 0x0022cf02,
+ 0xf51f13c8,
+ 0xc800890b,
+ 0x0bf41f23,
+ 0xb920f962,
+ 0x94bd0212,
+ 0xf10799f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x31f40132,
+ 0x4021f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x20fc04bd,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0131f404,
+ 0x0a4021f5,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+ 0x12b920f9,
+ 0x0132f402,
+ 0xf50232f4,
+ 0xfc0a4021,
+ 0x0007f120,
+ 0x0203f0c0,
+ 0xbd0002d0,
+ 0x130ef404,
+/* 0x062c: chsw_no_prev */
+ 0xf41f23c8,
+ 0x31f40d0b,
+ 0x0232f401,
+ 0x0a4021f5,
+/* 0x063c: chsw_done */
+ 0xf10127f0,
+ 0xf0c30007,
+ 0x02d00203,
+ 0xbd04bd00,
+ 0x0499f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+ 0xf401e4b0,
+ 0xf2b90d1b,
+ 0xd021f502,
+ 0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+ 0xf402e4b0,
+ 0x94bd321b,
+ 0xf10799f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x32f40132,
+ 0x4021f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+ 0x10ef9411,
+ 0xf501f5f0,
+ 0xf5037e21,
+/* 0x06b3: main_done */
+ 0xbdfeb50e,
+ 0x1f29f024,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xfea00ef5,
+/* 0x06c8: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x10d7f030,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x071a: ih_no_fifo */
+ 0xabe404bd,
+ 0x0bf40100,
+ 0x10d7f00d,
+ 0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+ 0xe40421f4,
+ 0xf40400ab,
+ 0xe7f16c0b,
+ 0xe3f00708,
+ 0x6821f440,
+ 0xf102ffb9,
+ 0xf0040007,
+ 0x0fd00203,
+ 0xf104bd00,
+ 0xf00704e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0x030007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0x9450fec7,
+ 0xf7f102ee,
+ 0xf3f00700,
+ 0x00efbb40,
+ 0xf16821f4,
+ 0xf0020007,
+ 0x0fd00203,
+ 0xf004bd00,
+ 0x21f503f7,
+ 0xb7f1037e,
+ 0xbfb90100,
+ 0x44e7f102,
+ 0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+ 0xf19d21f4,
+ 0xbd0504b7,
+ 0xb4abffb0,
+ 0xf10f0bf4,
+ 0xf0070007,
+ 0x0bd00303,
+/* 0x07b3: ih_no_other */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x07d7: ctx_4160s */
+ 0xf001f800,
+ 0xffb901f7,
+ 0x60e7f102,
+ 0x40e3f041,
+/* 0x07e7: ctx_4160s_wait */
+ 0xf19d21f4,
+ 0xf04160e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0xf404ffc8,
+ 0x00f8f00b,
+/* 0x07fc: ctx_4160c */
+ 0xffb9f4bd,
+ 0x60e7f102,
+ 0x40e3f041,
+ 0xf89d21f4,
+/* 0x080d: ctx_4170s */
+ 0x10f5f000,
+ 0xf102ffb9,
+ 0xf04170e7,
+ 0x21f440e3,
+/* 0x081f: ctx_4170w */
+ 0xf100f89d,
+ 0xf04170e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0xf410f4f0,
+ 0x00f8f01b,
+/* 0x0834: ctx_redswitch */
+ 0x0200e7f1,
+ 0xf040e5f0,
+ 0xe5f020e5,
+ 0x0007f110,
+ 0x0103f085,
+ 0xbd000ed0,
+ 0x08f7f004,
+/* 0x0850: ctx_redswitch_delay */
+ 0xf401f2b6,
+ 0xe5f1fd1b,
+ 0xe5f10400,
+ 0x07f10100,
+ 0x03f08500,
+ 0x000ed001,
+ 0x00f804bd,
+/* 0x086c: ctx_86c */
+ 0x1b0007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0xf102ffb9,
+ 0xf08a14e7,
+ 0x21f440e3,
+ 0x02ffb99d,
+ 0xa86ce7f1,
+ 0xf441e3f0,
+ 0x00f89d21,
+/* 0x0894: ctx_mem */
+ 0x840007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+/* 0x08a0: ctx_mem_wait */
+ 0x8400f7f1,
+ 0xcf02f3f0,
+ 0xfffd00ff,
+ 0xf31bf405,
+/* 0x08b2: ctx_load */
+ 0x94bd00f8,
+ 0xf10599f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf004bd00,
+ 0x21f40ca7,
+ 0xf1f4bdd0,
+ 0xf0890007,
+ 0x0fd00203,
+ 0xf104bd00,
+ 0xf0c10007,
+ 0x02d00203,
+ 0xf104bd00,
+ 0xf0830007,
+ 0x02d00203,
+ 0xf004bd00,
+ 0x21f507f7,
+ 0x07f10894,
+ 0x03f0c000,
+ 0x0002d002,
+ 0x0bfe04bd,
+ 0x1f2af000,
+ 0xb60424b6,
+ 0x94bd0220,
+ 0xf10899f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xf0810007,
+ 0x02d00203,
+ 0xf104bd00,
+ 0xf1000027,
+ 0xf0800023,
+ 0x07f10225,
+ 0x03f08800,
+ 0x0002d002,
+ 0x17f004bd,
+ 0x0027f110,
+ 0x0223f002,
+ 0xf80512fa,
+ 0xf094bd03,
+ 0x07f10899,
+ 0x03f01700,
+ 0x0009d002,
+ 0x019804bd,
+ 0x1814b681,
+ 0xb6800298,
+ 0x12fd0825,
+ 0x16018005,
+ 0x99f094bd,
+ 0x0007f109,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f081,
+ 0xbd0001d0,
+ 0x0127f004,
+ 0x880007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0x010017f1,
+ 0xfa0613f0,
+ 0x03f80501,
+ 0x99f094bd,
+ 0x0007f109,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0xf094bd04,
+ 0x07f10599,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x09d0: ctx_chan */
+ 0x07d721f5,
+ 0x08b221f5,
+ 0xf40ca7f0,
+ 0xf7f0d021,
+ 0x9421f505,
+ 0xfc21f508,
+/* 0x09eb: ctx_mmio_exec */
+ 0x9800f807,
+ 0x07f14103,
+ 0x03f08100,
+ 0x0003d002,
+ 0x34bd04bd,
+/* 0x09fc: ctx_mmio_loop */
+ 0xf4ff34c4,
+ 0x57f10f1b,
+ 0x53f00200,
+ 0x0535fa06,
+/* 0x0a0e: ctx_mmio_pull */
+ 0x4e9803f8,
+ 0x814f9880,
+ 0xb69d21f4,
+ 0x12b60830,
+ 0xdf1bf401,
+/* 0x0a20: ctx_mmio_done */
+ 0xf1160398,
+ 0xf0810007,
+ 0x03d00203,
+ 0x8004bd00,
+ 0x17f14000,
+ 0x13f00100,
+ 0x0601fa06,
+ 0x00f803f8,
+/* 0x0a40: ctx_xfer */
+ 0xf104e7f0,
+ 0xf0020007,
+ 0x0ed00303,
+/* 0x0a4f: ctx_xfer_idle */
+ 0xf104bd00,
+ 0xf00000e7,
+ 0xeecf03e3,
+ 0x00e4f100,
+ 0xf21bf420,
+ 0xf40611f4,
+/* 0x0a66: ctx_xfer_pre */
+ 0xf7f01102,
+ 0x6c21f510,
+ 0xd721f508,
+ 0x1c11f407,
+/* 0x0a74: ctx_xfer_pre_load */
+ 0xf502f7f0,
+ 0xf5080d21,
+ 0xf5081f21,
+ 0xbd083421,
+ 0x0d21f5f4,
+ 0xb221f508,
+/* 0x0a8d: ctx_xfer_exec */
+ 0x16019808,
+ 0x07f124bd,
+ 0x03f00500,
+ 0x0002d001,
+ 0x1fb904bd,
+ 0x00e7f102,
+ 0x41e3f0a5,
+ 0xf09d21f4,
+ 0x2cf001fc,
+ 0x0124b602,
+ 0xb905f2fd,
+ 0xe7f102ff,
+ 0xe3f0a504,
+ 0x9d21f441,
+ 0x026a21f5,
+ 0x07f124bd,
+ 0x03f047fc,
+ 0x0002d002,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xf001acf0,
+ 0xb7f006a5,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xa7f0016f,
+ 0x1021f508,
+ 0x5e21f501,
+ 0x1301f402,
+ 0xf40ca7f0,
+ 0xf7f0d021,
+ 0x9421f505,
+ 0x3202f408,
+/* 0x0b1c: ctx_xfer_post */
+ 0xf502f7f0,
+ 0xbd080d21,
+ 0x6c21f5f4,
+ 0x7f21f508,
+ 0x1f21f502,
+ 0xf5f4bd08,
+ 0xf4080d21,
+ 0x01981011,
+ 0x0511fd40,
+ 0xf5070bf4,
+/* 0x0b47: ctx_xfer_no_post_mmio */
+ 0xf509eb21,
+/* 0x0b4b: ctx_xfer_done */
+ 0xf807fc21,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3
new file mode 100644
index 000000000000..581b2d53ab0c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GF117
+#include "macros.fuc"
+
+.section #gf117_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gf117_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h
new file mode 100644
index 000000000000..7cb14e59dea1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgf117.fuc3.h
@@ -0,0 +1,1047 @@
+uint32_t gf117_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t gf117_grhub_code[] = {
+ 0x039b0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x039b: init */
+ 0xbd00f804,
+ 0x0007fe04,
+ 0x420017f1,
+ 0xcf0013f0,
+ 0x11e70011,
+ 0x14b60109,
+ 0x0014fe08,
+ 0xf10227f0,
+ 0xf0120007,
+ 0x02d00003,
+ 0xf104bd00,
+ 0xfe06c817,
+ 0x24bd0010,
+ 0x070007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0x200327f1,
+ 0x010007f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200427f1,
+ 0x010407f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200b27f1,
+ 0x010807f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200c27f1,
+ 0x011c07f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0xf1010392,
+ 0xf0090007,
+ 0x03d00303,
+ 0xf104bd00,
+ 0xf0870427,
+ 0x07f10023,
+ 0x03f00400,
+ 0x0002d000,
+ 0x27f004bd,
+ 0x0007f104,
+ 0x0003f003,
+ 0xbd0002d0,
+ 0x1031f404,
+ 0x9604e7f1,
+ 0xf440e3f0,
+ 0xfeb96821,
+ 0x90f1c702,
+ 0xf0030180,
+ 0x0f801ff4,
+ 0x0117f002,
+ 0xb6041fbb,
+ 0x07f10112,
+ 0x03f00300,
+ 0x0001d001,
+ 0x07f104bd,
+ 0x03f00400,
+ 0x0001d001,
+ 0x17f104bd,
+ 0xf7f00100,
+ 0x0d21f502,
+ 0x1f21f508,
+ 0x10f7f008,
+ 0x086c21f5,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x14950150,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0004d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0004d0,
+ 0x0030b704,
+ 0x001fbb13,
+ 0xf102f5b6,
+ 0xf0d30007,
+ 0x0fd00103,
+ 0xb604bd00,
+ 0x10b60815,
+ 0x0814b601,
+ 0xf5021fb9,
+ 0xbb02d321,
+ 0x0398001f,
+ 0x0047f102,
+ 0x5043f020,
+/* 0x04f4: init_gpc */
+ 0x08044ea0,
+ 0xf4021fb9,
+ 0x4ea09d21,
+ 0xf4bd010c,
+ 0xa09d21f4,
+ 0xf401044e,
+ 0x4ea09d21,
+ 0xf7f00100,
+ 0x9d21f402,
+ 0x08004ea0,
+/* 0x051c: init_gpc_wait */
+ 0xc86821f4,
+ 0x0bf41fff,
+ 0x044ea0fa,
+ 0x6821f408,
+ 0xb7001fbb,
+ 0xb6800040,
+ 0x1bf40132,
+ 0x00f7f0be,
+ 0x086c21f5,
+ 0xf500f7f0,
+ 0xf1080d21,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0564: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00e91b,
+ 0x0499f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xc00017f1,
+ 0xcf0213f0,
+ 0x27f10011,
+ 0x23f0c100,
+ 0x0022cf02,
+ 0xf51f13c8,
+ 0xc800890b,
+ 0x0bf41f23,
+ 0xb920f962,
+ 0x94bd0212,
+ 0xf10799f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x31f40132,
+ 0x4021f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x20fc04bd,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0131f404,
+ 0x0a4021f5,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+ 0x12b920f9,
+ 0x0132f402,
+ 0xf50232f4,
+ 0xfc0a4021,
+ 0x0007f120,
+ 0x0203f0c0,
+ 0xbd0002d0,
+ 0x130ef404,
+/* 0x062c: chsw_no_prev */
+ 0xf41f23c8,
+ 0x31f40d0b,
+ 0x0232f401,
+ 0x0a4021f5,
+/* 0x063c: chsw_done */
+ 0xf10127f0,
+ 0xf0c30007,
+ 0x02d00203,
+ 0xbd04bd00,
+ 0x0499f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+ 0xf401e4b0,
+ 0xf2b90d1b,
+ 0xd021f502,
+ 0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+ 0xf402e4b0,
+ 0x94bd321b,
+ 0xf10799f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x32f40132,
+ 0x4021f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+ 0x10ef9411,
+ 0xf501f5f0,
+ 0xf5037e21,
+/* 0x06b3: main_done */
+ 0xbdfeb50e,
+ 0x1f29f024,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xfea00ef5,
+/* 0x06c8: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x10d7f030,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x071a: ih_no_fifo */
+ 0xabe404bd,
+ 0x0bf40100,
+ 0x10d7f00d,
+ 0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+ 0xe40421f4,
+ 0xf40400ab,
+ 0xe7f16c0b,
+ 0xe3f00708,
+ 0x6821f440,
+ 0xf102ffb9,
+ 0xf0040007,
+ 0x0fd00203,
+ 0xf104bd00,
+ 0xf00704e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0x030007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0x9450fec7,
+ 0xf7f102ee,
+ 0xf3f00700,
+ 0x00efbb40,
+ 0xf16821f4,
+ 0xf0020007,
+ 0x0fd00203,
+ 0xf004bd00,
+ 0x21f503f7,
+ 0xb7f1037e,
+ 0xbfb90100,
+ 0x44e7f102,
+ 0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+ 0xf19d21f4,
+ 0xbd0504b7,
+ 0xb4abffb0,
+ 0xf10f0bf4,
+ 0xf0070007,
+ 0x0bd00303,
+/* 0x07b3: ih_no_other */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x07d7: ctx_4160s */
+ 0xf001f800,
+ 0xffb901f7,
+ 0x60e7f102,
+ 0x40e3f041,
+/* 0x07e7: ctx_4160s_wait */
+ 0xf19d21f4,
+ 0xf04160e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0xf404ffc8,
+ 0x00f8f00b,
+/* 0x07fc: ctx_4160c */
+ 0xffb9f4bd,
+ 0x60e7f102,
+ 0x40e3f041,
+ 0xf89d21f4,
+/* 0x080d: ctx_4170s */
+ 0x10f5f000,
+ 0xf102ffb9,
+ 0xf04170e7,
+ 0x21f440e3,
+/* 0x081f: ctx_4170w */
+ 0xf100f89d,
+ 0xf04170e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0xf410f4f0,
+ 0x00f8f01b,
+/* 0x0834: ctx_redswitch */
+ 0x0200e7f1,
+ 0xf040e5f0,
+ 0xe5f020e5,
+ 0x0007f110,
+ 0x0103f085,
+ 0xbd000ed0,
+ 0x08f7f004,
+/* 0x0850: ctx_redswitch_delay */
+ 0xf401f2b6,
+ 0xe5f1fd1b,
+ 0xe5f10400,
+ 0x07f10100,
+ 0x03f08500,
+ 0x000ed001,
+ 0x00f804bd,
+/* 0x086c: ctx_86c */
+ 0x1b0007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0xf102ffb9,
+ 0xf08a14e7,
+ 0x21f440e3,
+ 0x02ffb99d,
+ 0xa86ce7f1,
+ 0xf441e3f0,
+ 0x00f89d21,
+/* 0x0894: ctx_mem */
+ 0x840007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+/* 0x08a0: ctx_mem_wait */
+ 0x8400f7f1,
+ 0xcf02f3f0,
+ 0xfffd00ff,
+ 0xf31bf405,
+/* 0x08b2: ctx_load */
+ 0x94bd00f8,
+ 0xf10599f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf004bd00,
+ 0x21f40ca7,
+ 0xf1f4bdd0,
+ 0xf0890007,
+ 0x0fd00203,
+ 0xf104bd00,
+ 0xf0c10007,
+ 0x02d00203,
+ 0xf104bd00,
+ 0xf0830007,
+ 0x02d00203,
+ 0xf004bd00,
+ 0x21f507f7,
+ 0x07f10894,
+ 0x03f0c000,
+ 0x0002d002,
+ 0x0bfe04bd,
+ 0x1f2af000,
+ 0xb60424b6,
+ 0x94bd0220,
+ 0xf10899f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xf0810007,
+ 0x02d00203,
+ 0xf104bd00,
+ 0xf1000027,
+ 0xf0800023,
+ 0x07f10225,
+ 0x03f08800,
+ 0x0002d002,
+ 0x17f004bd,
+ 0x0027f110,
+ 0x0223f002,
+ 0xf80512fa,
+ 0xf094bd03,
+ 0x07f10899,
+ 0x03f01700,
+ 0x0009d002,
+ 0x019804bd,
+ 0x1814b681,
+ 0xb6800298,
+ 0x12fd0825,
+ 0x16018005,
+ 0x99f094bd,
+ 0x0007f109,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f081,
+ 0xbd0001d0,
+ 0x0127f004,
+ 0x880007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0x010017f1,
+ 0xfa0613f0,
+ 0x03f80501,
+ 0x99f094bd,
+ 0x0007f109,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0xf094bd04,
+ 0x07f10599,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x09d0: ctx_chan */
+ 0x07d721f5,
+ 0x08b221f5,
+ 0xf40ca7f0,
+ 0xf7f0d021,
+ 0x9421f505,
+ 0xfc21f508,
+/* 0x09eb: ctx_mmio_exec */
+ 0x9800f807,
+ 0x07f14103,
+ 0x03f08100,
+ 0x0003d002,
+ 0x34bd04bd,
+/* 0x09fc: ctx_mmio_loop */
+ 0xf4ff34c4,
+ 0x57f10f1b,
+ 0x53f00200,
+ 0x0535fa06,
+/* 0x0a0e: ctx_mmio_pull */
+ 0x4e9803f8,
+ 0x814f9880,
+ 0xb69d21f4,
+ 0x12b60830,
+ 0xdf1bf401,
+/* 0x0a20: ctx_mmio_done */
+ 0xf1160398,
+ 0xf0810007,
+ 0x03d00203,
+ 0x8004bd00,
+ 0x17f14000,
+ 0x13f00100,
+ 0x0601fa06,
+ 0x00f803f8,
+/* 0x0a40: ctx_xfer */
+ 0xf104e7f0,
+ 0xf0020007,
+ 0x0ed00303,
+/* 0x0a4f: ctx_xfer_idle */
+ 0xf104bd00,
+ 0xf00000e7,
+ 0xeecf03e3,
+ 0x00e4f100,
+ 0xf21bf420,
+ 0xf40611f4,
+/* 0x0a66: ctx_xfer_pre */
+ 0xf7f01102,
+ 0x6c21f510,
+ 0xd721f508,
+ 0x1c11f407,
+/* 0x0a74: ctx_xfer_pre_load */
+ 0xf502f7f0,
+ 0xf5080d21,
+ 0xf5081f21,
+ 0xbd083421,
+ 0x0d21f5f4,
+ 0xb221f508,
+/* 0x0a8d: ctx_xfer_exec */
+ 0x16019808,
+ 0x07f124bd,
+ 0x03f00500,
+ 0x0002d001,
+ 0x1fb904bd,
+ 0x00e7f102,
+ 0x41e3f0a5,
+ 0xf09d21f4,
+ 0x2cf001fc,
+ 0x0124b602,
+ 0xb905f2fd,
+ 0xe7f102ff,
+ 0xe3f0a504,
+ 0x9d21f441,
+ 0x026a21f5,
+ 0x07f124bd,
+ 0x03f047fc,
+ 0x0002d002,
+ 0x2cf004bd,
+ 0x0320b601,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xf001acf0,
+ 0xb7f006a5,
+ 0x000c9800,
+ 0xf0010d98,
+ 0x21f500e7,
+ 0xa7f0016f,
+ 0x1021f508,
+ 0x5e21f501,
+ 0x1301f402,
+ 0xf40ca7f0,
+ 0xf7f0d021,
+ 0x9421f505,
+ 0x3202f408,
+/* 0x0b1c: ctx_xfer_post */
+ 0xf502f7f0,
+ 0xbd080d21,
+ 0x6c21f5f4,
+ 0x7f21f508,
+ 0x1f21f502,
+ 0xf5f4bd08,
+ 0xf4080d21,
+ 0x01981011,
+ 0x0511fd40,
+ 0xf5070bf4,
+/* 0x0b47: ctx_xfer_no_post_mmio */
+ 0xf509eb21,
+/* 0x0b4b: ctx_xfer_done */
+ 0xf807fc21,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3
new file mode 100644
index 000000000000..d977d393b679
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK100
+#include "macros.fuc"
+
+.section #gk104_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gk104_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h
new file mode 100644
index 000000000000..95ac15110049
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk104.fuc3.h
@@ -0,0 +1,1044 @@
+uint32_t gk104_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t gk104_grhub_code[] = {
+ 0x039b0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x039b: init */
+ 0xbd00f804,
+ 0x0007fe04,
+ 0x420017f1,
+ 0xcf0013f0,
+ 0x11e70011,
+ 0x14b60109,
+ 0x0014fe08,
+ 0xf10227f0,
+ 0xf0120007,
+ 0x02d00003,
+ 0xf104bd00,
+ 0xfe06c817,
+ 0x24bd0010,
+ 0x070007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0x200327f1,
+ 0x010007f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200427f1,
+ 0x010407f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200b27f1,
+ 0x010807f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200c27f1,
+ 0x011c07f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0xf1010392,
+ 0xf0090007,
+ 0x03d00303,
+ 0xf104bd00,
+ 0xf0870427,
+ 0x07f10023,
+ 0x03f00400,
+ 0x0002d000,
+ 0x27f004bd,
+ 0x0007f104,
+ 0x0003f003,
+ 0xbd0002d0,
+ 0x1031f404,
+ 0x9604e7f1,
+ 0xf440e3f0,
+ 0xfeb96821,
+ 0x90f1c702,
+ 0xf0030180,
+ 0x0f801ff4,
+ 0x0117f002,
+ 0xb6041fbb,
+ 0x07f10112,
+ 0x03f00300,
+ 0x0001d001,
+ 0x07f104bd,
+ 0x03f00400,
+ 0x0001d001,
+ 0x17f104bd,
+ 0xf7f00100,
+ 0xd721f502,
+ 0xe921f507,
+ 0x10f7f007,
+ 0x083621f5,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x14950150,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0004d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0004d0,
+ 0x0030b704,
+ 0x001fbb13,
+ 0xf102f5b6,
+ 0xf0d30007,
+ 0x0fd00103,
+ 0xb604bd00,
+ 0x10b60815,
+ 0x0814b601,
+ 0xf5021fb9,
+ 0xbb02d321,
+ 0x0398001f,
+ 0x0047f102,
+ 0x5043f020,
+/* 0x04f4: init_gpc */
+ 0x08044ea0,
+ 0xf4021fb9,
+ 0x4ea09d21,
+ 0xf4bd010c,
+ 0xa09d21f4,
+ 0xf401044e,
+ 0x4ea09d21,
+ 0xf7f00100,
+ 0x9d21f402,
+ 0x08004ea0,
+/* 0x051c: init_gpc_wait */
+ 0xc86821f4,
+ 0x0bf41fff,
+ 0x044ea0fa,
+ 0x6821f408,
+ 0xb7001fbb,
+ 0xb6800040,
+ 0x1bf40132,
+ 0x00f7f0be,
+ 0x083621f5,
+ 0xf500f7f0,
+ 0xf107d721,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0564: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00e91b,
+ 0x0499f094,
+ 0x0f0007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xc00017f1,
+ 0xcf0213f0,
+ 0x27f10011,
+ 0x23f0c100,
+ 0x0022cf02,
+ 0xf51f13c8,
+ 0xc800890b,
+ 0x0bf41f23,
+ 0xb920f962,
+ 0x94bd0212,
+ 0xf10799f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x31f40132,
+ 0x0221f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x20fc04bd,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0131f404,
+ 0x0a0221f5,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+ 0x12b920f9,
+ 0x0132f402,
+ 0xf50232f4,
+ 0xfc0a0221,
+ 0x0007f120,
+ 0x0203f0c0,
+ 0xbd0002d0,
+ 0x130ef404,
+/* 0x062c: chsw_no_prev */
+ 0xf41f23c8,
+ 0x31f40d0b,
+ 0x0232f401,
+ 0x0a0221f5,
+/* 0x063c: chsw_done */
+ 0xf10127f0,
+ 0xf0c30007,
+ 0x02d00203,
+ 0xbd04bd00,
+ 0x0499f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+ 0xf401e4b0,
+ 0xf2b90d1b,
+ 0x9a21f502,
+ 0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+ 0xf402e4b0,
+ 0x94bd321b,
+ 0xf10799f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x32f40132,
+ 0x0221f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+ 0x10ef9411,
+ 0xf501f5f0,
+ 0xf5037e21,
+/* 0x06b3: main_done */
+ 0xbdfeb50e,
+ 0x1f29f024,
+ 0x080007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xfea00ef5,
+/* 0x06c8: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x10d7f030,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x071a: ih_no_fifo */
+ 0xabe404bd,
+ 0x0bf40100,
+ 0x10d7f00d,
+ 0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+ 0xe40421f4,
+ 0xf40400ab,
+ 0xe7f16c0b,
+ 0xe3f00708,
+ 0x6821f440,
+ 0xf102ffb9,
+ 0xf0040007,
+ 0x0fd00203,
+ 0xf104bd00,
+ 0xf00704e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0x030007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0x9450fec7,
+ 0xf7f102ee,
+ 0xf3f00700,
+ 0x00efbb40,
+ 0xf16821f4,
+ 0xf0020007,
+ 0x0fd00203,
+ 0xf004bd00,
+ 0x21f503f7,
+ 0xb7f1037e,
+ 0xbfb90100,
+ 0x44e7f102,
+ 0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+ 0xf19d21f4,
+ 0xbd0504b7,
+ 0xb4abffb0,
+ 0xf10f0bf4,
+ 0xf0070007,
+ 0x0bd00303,
+/* 0x07b3: ih_no_other */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x07d7: ctx_4170s */
+ 0xf001f800,
+ 0xffb910f5,
+ 0x70e7f102,
+ 0x40e3f041,
+ 0xf89d21f4,
+/* 0x07e9: ctx_4170w */
+ 0x70e7f100,
+ 0x40e3f041,
+ 0xb96821f4,
+ 0xf4f002ff,
+ 0xf01bf410,
+/* 0x07fe: ctx_redswitch */
+ 0xe7f100f8,
+ 0xe5f00200,
+ 0x20e5f040,
+ 0xf110e5f0,
+ 0xf0850007,
+ 0x0ed00103,
+ 0xf004bd00,
+/* 0x081a: ctx_redswitch_delay */
+ 0xf2b608f7,
+ 0xfd1bf401,
+ 0x0400e5f1,
+ 0x0100e5f1,
+ 0x850007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+/* 0x0836: ctx_86c */
+ 0x07f100f8,
+ 0x03f01b00,
+ 0x000fd002,
+ 0xffb904bd,
+ 0x14e7f102,
+ 0x40e3f08a,
+ 0xb99d21f4,
+ 0xe7f102ff,
+ 0xe3f0a86c,
+ 0x9d21f441,
+/* 0x085e: ctx_mem */
+ 0x07f100f8,
+ 0x03f08400,
+ 0x000fd002,
+/* 0x086a: ctx_mem_wait */
+ 0xf7f104bd,
+ 0xf3f08400,
+ 0x00ffcf02,
+ 0xf405fffd,
+ 0x00f8f31b,
+/* 0x087c: ctx_load */
+ 0x99f094bd,
+ 0x0007f105,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0ca7f004,
+ 0xbdd021f4,
+ 0x0007f1f4,
+ 0x0203f089,
+ 0xbd000fd0,
+ 0x0007f104,
+ 0x0203f0c1,
+ 0xbd0002d0,
+ 0x0007f104,
+ 0x0203f083,
+ 0xbd0002d0,
+ 0x07f7f004,
+ 0x085e21f5,
+ 0xc00007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xf0000bfe,
+ 0x24b61f2a,
+ 0x0220b604,
+ 0x99f094bd,
+ 0x0007f108,
+ 0x0203f00f,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f081,
+ 0xbd0002d0,
+ 0x0027f104,
+ 0x0023f100,
+ 0x0225f080,
+ 0x880007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xf11017f0,
+ 0xf0020027,
+ 0x12fa0223,
+ 0xbd03f805,
+ 0x0899f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xb6810198,
+ 0x02981814,
+ 0x0825b680,
+ 0x800512fd,
+ 0x94bd1601,
+ 0xf10999f0,
+ 0xf00f0007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xf0810007,
+ 0x01d00203,
+ 0xf004bd00,
+ 0x07f10127,
+ 0x03f08800,
+ 0x0002d002,
+ 0x17f104bd,
+ 0x13f00100,
+ 0x0501fa06,
+ 0x94bd03f8,
+ 0xf10999f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xbd04bd00,
+ 0x0599f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x099a: ctx_chan */
+ 0x21f500f8,
+ 0xa7f0087c,
+ 0xd021f40c,
+ 0xf505f7f0,
+ 0xf8085e21,
+/* 0x09ad: ctx_mmio_exec */
+ 0x41039800,
+ 0x810007f1,
+ 0xd00203f0,
+ 0x04bd0003,
+/* 0x09be: ctx_mmio_loop */
+ 0x34c434bd,
+ 0x0f1bf4ff,
+ 0x020057f1,
+ 0xfa0653f0,
+ 0x03f80535,
+/* 0x09d0: ctx_mmio_pull */
+ 0x98804e98,
+ 0x21f4814f,
+ 0x0830b69d,
+ 0xf40112b6,
+/* 0x09e2: ctx_mmio_done */
+ 0x0398df1b,
+ 0x0007f116,
+ 0x0203f081,
+ 0xbd0003d0,
+ 0x40008004,
+ 0x010017f1,
+ 0xfa0613f0,
+ 0x03f80601,
+/* 0x0a02: ctx_xfer */
+ 0xe7f000f8,
+ 0x0007f104,
+ 0x0303f002,
+ 0xbd000ed0,
+/* 0x0a11: ctx_xfer_idle */
+ 0x00e7f104,
+ 0x03e3f000,
+ 0xf100eecf,
+ 0xf42000e4,
+ 0x11f4f21b,
+ 0x0d02f406,
+/* 0x0a28: ctx_xfer_pre */
+ 0xf510f7f0,
+ 0xf4083621,
+/* 0x0a32: ctx_xfer_pre_load */
+ 0xf7f01c11,
+ 0xd721f502,
+ 0xe921f507,
+ 0xfe21f507,
+ 0xf5f4bd07,
+ 0xf507d721,
+/* 0x0a4b: ctx_xfer_exec */
+ 0x98087c21,
+ 0x24bd1601,
+ 0x050007f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0xf1021fb9,
+ 0xf0a500e7,
+ 0x21f441e3,
+ 0x01fcf09d,
+ 0xb6022cf0,
+ 0xf2fd0124,
+ 0x02ffb905,
+ 0xa504e7f1,
+ 0xf441e3f0,
+ 0x21f59d21,
+ 0x24bd026a,
+ 0x47fc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xb6012cf0,
+ 0x07f10320,
+ 0x03f04afc,
+ 0x0002d002,
+ 0xacf004bd,
+ 0x06a5f001,
+ 0x9800b7f0,
+ 0x0d98000c,
+ 0x00e7f001,
+ 0x016f21f5,
+ 0xf508a7f0,
+ 0xf5011021,
+ 0xf4025e21,
+ 0xa7f01301,
+ 0xd021f40c,
+ 0xf505f7f0,
+ 0xf4085e21,
+/* 0x0ada: ctx_xfer_post */
+ 0xf7f02e02,
+ 0xd721f502,
+ 0xf5f4bd07,
+ 0xf5083621,
+ 0xf5027f21,
+ 0xbd07e921,
+ 0xd721f5f4,
+ 0x1011f407,
+ 0xfd400198,
+ 0x0bf40511,
+ 0xad21f507,
+/* 0x0b05: ctx_xfer_no_post_mmio */
+/* 0x0b05: ctx_xfer_done */
+ 0x0000f809,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3
new file mode 100644
index 000000000000..760b4632f22d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK110
+#include "macros.fuc"
+
+.section #gk110_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gk110_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h
new file mode 100644
index 000000000000..89986878480f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk110.fuc3.h
@@ -0,0 +1,1044 @@
+uint32_t gk110_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t gk110_grhub_code[] = {
+ 0x039b0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0x0489b808,
+ 0xf00c1bf4,
+ 0x21f502f7,
+ 0x00f8037e,
+/* 0x001c: queue_put_next */
+ 0xb60798c4,
+ 0x8dbb0384,
+ 0x0880b600,
+ 0x80008e80,
+ 0x90b6018f,
+ 0x0f94f001,
+ 0xf801d980,
+/* 0x0039: queue_get */
+ 0x0131f400,
+ 0x9800d898,
+ 0x89b801d9,
+ 0x210bf404,
+ 0xb60789c4,
+ 0x9dbb0394,
+ 0x0890b600,
+ 0x98009e98,
+ 0x80b6019f,
+ 0x0f84f001,
+ 0xf400d880,
+/* 0x0066: queue_get_done */
+ 0x00f80132,
+/* 0x0068: nv_rd32 */
+ 0xf002ecb9,
+ 0x07f11fc9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x007a: nv_rd32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0xa7f0f31b,
+ 0x1021f506,
+ 0x00f7f101,
+ 0x01f3f0cb,
+ 0xf800ffcf,
+/* 0x009d: nv_wr32 */
+ 0x0007f100,
+ 0x0103f0cc,
+ 0xbd000fd0,
+ 0x02ecb904,
+ 0xf01fc9f0,
+ 0x07f11ec9,
+ 0x03f0ca00,
+ 0x000cd001,
+/* 0x00be: nv_wr32_wait */
+ 0xc7f104bd,
+ 0xc3f0ca00,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f31b,
+/* 0x00d0: wait_donez */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x00ed: wait_donez_ne */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x1bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0110: wait_doneo */
+ 0x99f094bd,
+ 0x0007f100,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f006,
+ 0xbd000ad0,
+/* 0x012d: wait_doneo_e */
+ 0x0087f104,
+ 0x0183f000,
+ 0xff0088cf,
+ 0x0bf4888a,
+ 0xf094bdf3,
+ 0x07f10099,
+ 0x03f01700,
+ 0x0009d002,
+ 0x00f804bd,
+/* 0x0150: mmctx_size */
+/* 0x0152: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0xf404efb8,
+ 0x9fb9eb1b,
+/* 0x016f: mmctx_xfer */
+ 0xbd00f802,
+ 0x0199f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xbbfd94bd,
+ 0x120bf405,
+ 0xc40007f1,
+ 0xd00103f0,
+ 0x04bd000b,
+/* 0x0197: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0x0007f11e,
+ 0x0103f0c6,
+ 0xbd000ed0,
+ 0x0007f104,
+ 0x0103f0c7,
+ 0xbd000fd0,
+ 0x0199f004,
+/* 0x01b8: mmctx_multi_disabled */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x01aec80c,
+ 0xfd11e4b6,
+ 0x07f105be,
+ 0x03f0c500,
+ 0x000bd001,
+/* 0x01d6: mmctx_exec_loop */
+/* 0x01d6: mmctx_wait_free */
+ 0xe7f104bd,
+ 0xe3f0c500,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f30b,
+ 0x05e9fd00,
+ 0xc80007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+ 0xb804c0b6,
+ 0x1bf404cd,
+ 0x02abc8d8,
+/* 0x0207: mmctx_fini_wait */
+ 0xf11f1bf4,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x1fb4f000,
+ 0xf410b4b0,
+ 0xa7f0f01b,
+ 0xd021f405,
+/* 0x0223: mmctx_stop */
+ 0xc82b0ef4,
+ 0xb4b600ab,
+ 0x0cb9f010,
+ 0xf112b9f0,
+ 0xf0c50007,
+ 0x0bd00103,
+/* 0x023b: mmctx_stop_wait */
+ 0xf104bd00,
+ 0xf0c500b7,
+ 0xbbcf01b3,
+ 0x12bbc800,
+/* 0x024b: mmctx_done */
+ 0xbdf31bf4,
+ 0x0199f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x025e: strand_wait */
+ 0xa0f900f8,
+ 0xf402a7f0,
+ 0xa0fcd021,
+/* 0x026a: strand_pre */
+ 0x97f000f8,
+ 0xfc07f10c,
+ 0x0203f04a,
+ 0xbd0009d0,
+ 0x5e21f504,
+/* 0x027f: strand_post */
+ 0xf000f802,
+ 0x07f10d97,
+ 0x03f04afc,
+ 0x0009d002,
+ 0x21f504bd,
+ 0x00f8025e,
+/* 0x0294: strand_set */
+ 0xf10fc7f0,
+ 0xf04ffc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f10bc7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x07f104bd,
+ 0x03f04ffc,
+ 0x000ed002,
+ 0xc7f004bd,
+ 0xfc07f10a,
+ 0x0203f04a,
+ 0xbd000cd0,
+ 0x5e21f504,
+/* 0x02d3: strand_ctx_init */
+ 0xbd00f802,
+ 0x0399f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0x026a21f5,
+ 0xf503e7f0,
+ 0xbd029421,
+ 0xfc07f1c4,
+ 0x0203f047,
+ 0xbd000cd0,
+ 0x01c7f004,
+ 0x4afc07f1,
+ 0xd00203f0,
+ 0x04bd000c,
+ 0x025e21f5,
+ 0xf1010c92,
+ 0xf046fc07,
+ 0x0cd00203,
+ 0xf004bd00,
+ 0x07f102c7,
+ 0x03f04afc,
+ 0x000cd002,
+ 0x21f504bd,
+ 0x21f5025e,
+ 0x87f1027f,
+ 0x83f04200,
+ 0x0097f102,
+ 0x0293f020,
+ 0x950099cf,
+/* 0x034a: ctx_init_strand_loop */
+ 0x8ed008fe,
+ 0x408ed000,
+ 0xb6808acf,
+ 0xa0b606a5,
+ 0x00eabb01,
+ 0xb60480b6,
+ 0x1bf40192,
+ 0x08e4b6e8,
+ 0xbdf2efbc,
+ 0x0399f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x037e: error */
+ 0x07f100f8,
+ 0x03f00500,
+ 0x000fd002,
+ 0xf7f004bd,
+ 0x0007f101,
+ 0x0303f007,
+ 0xbd000fd0,
+/* 0x039b: init */
+ 0xbd00f804,
+ 0x0007fe04,
+ 0x420017f1,
+ 0xcf0013f0,
+ 0x11e70011,
+ 0x14b60109,
+ 0x0014fe08,
+ 0xf10227f0,
+ 0xf0120007,
+ 0x02d00003,
+ 0xf104bd00,
+ 0xfe06c817,
+ 0x24bd0010,
+ 0x070007f1,
+ 0xd00003f0,
+ 0x04bd0002,
+ 0x200327f1,
+ 0x010007f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200427f1,
+ 0x010407f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200b27f1,
+ 0x010807f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0x200c27f1,
+ 0x011c07f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0xf1010392,
+ 0xf0090007,
+ 0x03d00303,
+ 0xf104bd00,
+ 0xf0870427,
+ 0x07f10023,
+ 0x03f00400,
+ 0x0002d000,
+ 0x27f004bd,
+ 0x0007f104,
+ 0x0003f003,
+ 0xbd0002d0,
+ 0x1031f404,
+ 0x9604e7f1,
+ 0xf440e3f0,
+ 0xfeb96821,
+ 0x90f1c702,
+ 0xf0030180,
+ 0x0f801ff4,
+ 0x0117f002,
+ 0xb6041fbb,
+ 0x07f10112,
+ 0x03f00300,
+ 0x0001d001,
+ 0x07f104bd,
+ 0x03f00400,
+ 0x0001d001,
+ 0x17f104bd,
+ 0xf7f00100,
+ 0xd721f502,
+ 0xe921f507,
+ 0x10f7f007,
+ 0x083621f5,
+ 0x98000e98,
+ 0x21f5010f,
+ 0x14950150,
+ 0x0007f108,
+ 0x0103f0c0,
+ 0xbd0004d0,
+ 0x0007f104,
+ 0x0103f0c1,
+ 0xbd0004d0,
+ 0x0030b704,
+ 0x001fbb13,
+ 0xf102f5b6,
+ 0xf0d30007,
+ 0x0fd00103,
+ 0xb604bd00,
+ 0x10b60815,
+ 0x0814b601,
+ 0xf5021fb9,
+ 0xbb02d321,
+ 0x0398001f,
+ 0x0047f102,
+ 0x5043f020,
+/* 0x04f4: init_gpc */
+ 0x08044ea0,
+ 0xf4021fb9,
+ 0x4ea09d21,
+ 0xf4bd010c,
+ 0xa09d21f4,
+ 0xf401044e,
+ 0x4ea09d21,
+ 0xf7f00100,
+ 0x9d21f402,
+ 0x08004ea0,
+/* 0x051c: init_gpc_wait */
+ 0xc86821f4,
+ 0x0bf41fff,
+ 0x044ea0fa,
+ 0x6821f408,
+ 0xb7001fbb,
+ 0xb6800040,
+ 0x1bf40132,
+ 0x00f7f0be,
+ 0x083621f5,
+ 0xf500f7f0,
+ 0xf107d721,
+ 0xf0010007,
+ 0x01d00203,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x300007f1,
+ 0xd00203f0,
+ 0x04bd0001,
+/* 0x0564: main */
+ 0xf40031f4,
+ 0xd7f00028,
+ 0x3921f410,
+ 0xb1f401f4,
+ 0xf54001e4,
+ 0xbd00e91b,
+ 0x0499f094,
+ 0x370007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xc00017f1,
+ 0xcf0213f0,
+ 0x27f10011,
+ 0x23f0c100,
+ 0x0022cf02,
+ 0xf51f13c8,
+ 0xc800890b,
+ 0x0bf41f23,
+ 0xb920f962,
+ 0x94bd0212,
+ 0xf10799f0,
+ 0xf0370007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x31f40132,
+ 0x0221f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x20fc04bd,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0131f404,
+ 0x0a0221f5,
+ 0x99f094bd,
+ 0x0007f106,
+ 0x0203f017,
+ 0xbd0009d0,
+ 0x330ef404,
+/* 0x060c: chsw_prev_no_next */
+ 0x12b920f9,
+ 0x0132f402,
+ 0xf50232f4,
+ 0xfc0a0221,
+ 0x0007f120,
+ 0x0203f0c0,
+ 0xbd0002d0,
+ 0x130ef404,
+/* 0x062c: chsw_no_prev */
+ 0xf41f23c8,
+ 0x31f40d0b,
+ 0x0232f401,
+ 0x0a0221f5,
+/* 0x063c: chsw_done */
+ 0xf10127f0,
+ 0xf0c30007,
+ 0x02d00203,
+ 0xbd04bd00,
+ 0x0499f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xff080ef5,
+/* 0x0660: main_not_ctx_switch */
+ 0xf401e4b0,
+ 0xf2b90d1b,
+ 0x9a21f502,
+ 0x460ef409,
+/* 0x0670: main_not_ctx_chan */
+ 0xf402e4b0,
+ 0x94bd321b,
+ 0xf10799f0,
+ 0xf0370007,
+ 0x09d00203,
+ 0xf404bd00,
+ 0x32f40132,
+ 0x0221f502,
+ 0xf094bd0a,
+ 0x07f10799,
+ 0x03f01700,
+ 0x0009d002,
+ 0x0ef404bd,
+/* 0x06a5: main_not_ctx_save */
+ 0x10ef9411,
+ 0xf501f5f0,
+ 0xf5037e21,
+/* 0x06b3: main_done */
+ 0xbdfeb50e,
+ 0x1f29f024,
+ 0x300007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xfea00ef5,
+/* 0x06c8: ih */
+ 0x88fe80f9,
+ 0xf980f901,
+ 0xf9a0f990,
+ 0xf9d0f9b0,
+ 0xbdf0f9e0,
+ 0x00a7f104,
+ 0x00a3f002,
+ 0xc400aacf,
+ 0x0bf404ab,
+ 0x10d7f030,
+ 0x1a00e7f1,
+ 0xcf00e3f0,
+ 0xf7f100ee,
+ 0xf3f01900,
+ 0x00ffcf00,
+ 0xb70421f4,
+ 0xf00400b0,
+ 0x07f101e7,
+ 0x03f01d00,
+ 0x000ed000,
+/* 0x071a: ih_no_fifo */
+ 0xabe404bd,
+ 0x0bf40100,
+ 0x10d7f00d,
+ 0x4001e7f1,
+/* 0x072b: ih_no_ctxsw */
+ 0xe40421f4,
+ 0xf40400ab,
+ 0xe7f16c0b,
+ 0xe3f00708,
+ 0x6821f440,
+ 0xf102ffb9,
+ 0xf0040007,
+ 0x0fd00203,
+ 0xf104bd00,
+ 0xf00704e7,
+ 0x21f440e3,
+ 0x02ffb968,
+ 0x030007f1,
+ 0xd00203f0,
+ 0x04bd000f,
+ 0x9450fec7,
+ 0xf7f102ee,
+ 0xf3f00700,
+ 0x00efbb40,
+ 0xf16821f4,
+ 0xf0020007,
+ 0x0fd00203,
+ 0xf004bd00,
+ 0x21f503f7,
+ 0xb7f1037e,
+ 0xbfb90100,
+ 0x44e7f102,
+ 0x40e3f001,
+/* 0x079b: ih_no_fwmthd */
+ 0xf19d21f4,
+ 0xbd0504b7,
+ 0xb4abffb0,
+ 0xf10f0bf4,
+ 0xf0070007,
+ 0x0bd00303,
+/* 0x07b3: ih_no_other */
+ 0xf104bd00,
+ 0xf0010007,
+ 0x0ad00003,
+ 0xfc04bd00,
+ 0xfce0fcf0,
+ 0xfcb0fcd0,
+ 0xfc90fca0,
+ 0x0088fe80,
+ 0x32f480fc,
+/* 0x07d7: ctx_4170s */
+ 0xf001f800,
+ 0xffb910f5,
+ 0x70e7f102,
+ 0x40e3f041,
+ 0xf89d21f4,
+/* 0x07e9: ctx_4170w */
+ 0x70e7f100,
+ 0x40e3f041,
+ 0xb96821f4,
+ 0xf4f002ff,
+ 0xf01bf410,
+/* 0x07fe: ctx_redswitch */
+ 0xe7f100f8,
+ 0xe5f00200,
+ 0x20e5f040,
+ 0xf110e5f0,
+ 0xf0850007,
+ 0x0ed00103,
+ 0xf004bd00,
+/* 0x081a: ctx_redswitch_delay */
+ 0xf2b608f7,
+ 0xfd1bf401,
+ 0x0400e5f1,
+ 0x0100e5f1,
+ 0x850007f1,
+ 0xd00103f0,
+ 0x04bd000e,
+/* 0x0836: ctx_86c */
+ 0x07f100f8,
+ 0x03f02300,
+ 0x000fd002,
+ 0xffb904bd,
+ 0x14e7f102,
+ 0x40e3f08a,
+ 0xb99d21f4,
+ 0xe7f102ff,
+ 0xe3f0a88c,
+ 0x9d21f441,
+/* 0x085e: ctx_mem */
+ 0x07f100f8,
+ 0x03f08400,
+ 0x000fd002,
+/* 0x086a: ctx_mem_wait */
+ 0xf7f104bd,
+ 0xf3f08400,
+ 0x00ffcf02,
+ 0xf405fffd,
+ 0x00f8f31b,
+/* 0x087c: ctx_load */
+ 0x99f094bd,
+ 0x0007f105,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0ca7f004,
+ 0xbdd021f4,
+ 0x0007f1f4,
+ 0x0203f089,
+ 0xbd000fd0,
+ 0x0007f104,
+ 0x0203f0c1,
+ 0xbd0002d0,
+ 0x0007f104,
+ 0x0203f083,
+ 0xbd0002d0,
+ 0x07f7f004,
+ 0x085e21f5,
+ 0xc00007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xf0000bfe,
+ 0x24b61f2a,
+ 0x0220b604,
+ 0x99f094bd,
+ 0x0007f108,
+ 0x0203f037,
+ 0xbd0009d0,
+ 0x0007f104,
+ 0x0203f081,
+ 0xbd0002d0,
+ 0x0027f104,
+ 0x0023f100,
+ 0x0225f080,
+ 0x880007f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xf11017f0,
+ 0xf0020027,
+ 0x12fa0223,
+ 0xbd03f805,
+ 0x0899f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+ 0xb6810198,
+ 0x02981814,
+ 0x0825b680,
+ 0x800512fd,
+ 0x94bd1601,
+ 0xf10999f0,
+ 0xf0370007,
+ 0x09d00203,
+ 0xf104bd00,
+ 0xf0810007,
+ 0x01d00203,
+ 0xf004bd00,
+ 0x07f10127,
+ 0x03f08800,
+ 0x0002d002,
+ 0x17f104bd,
+ 0x13f00100,
+ 0x0501fa06,
+ 0x94bd03f8,
+ 0xf10999f0,
+ 0xf0170007,
+ 0x09d00203,
+ 0xbd04bd00,
+ 0x0599f094,
+ 0x170007f1,
+ 0xd00203f0,
+ 0x04bd0009,
+/* 0x099a: ctx_chan */
+ 0x21f500f8,
+ 0xa7f0087c,
+ 0xd021f40c,
+ 0xf505f7f0,
+ 0xf8085e21,
+/* 0x09ad: ctx_mmio_exec */
+ 0x41039800,
+ 0x810007f1,
+ 0xd00203f0,
+ 0x04bd0003,
+/* 0x09be: ctx_mmio_loop */
+ 0x34c434bd,
+ 0x0f1bf4ff,
+ 0x020057f1,
+ 0xfa0653f0,
+ 0x03f80535,
+/* 0x09d0: ctx_mmio_pull */
+ 0x98804e98,
+ 0x21f4814f,
+ 0x0830b69d,
+ 0xf40112b6,
+/* 0x09e2: ctx_mmio_done */
+ 0x0398df1b,
+ 0x0007f116,
+ 0x0203f081,
+ 0xbd0003d0,
+ 0x40008004,
+ 0x010017f1,
+ 0xfa0613f0,
+ 0x03f80601,
+/* 0x0a02: ctx_xfer */
+ 0xe7f000f8,
+ 0x0007f104,
+ 0x0303f002,
+ 0xbd000ed0,
+/* 0x0a11: ctx_xfer_idle */
+ 0x00e7f104,
+ 0x03e3f000,
+ 0xf100eecf,
+ 0xf42000e4,
+ 0x11f4f21b,
+ 0x0d02f406,
+/* 0x0a28: ctx_xfer_pre */
+ 0xf510f7f0,
+ 0xf4083621,
+/* 0x0a32: ctx_xfer_pre_load */
+ 0xf7f01c11,
+ 0xd721f502,
+ 0xe921f507,
+ 0xfe21f507,
+ 0xf5f4bd07,
+ 0xf507d721,
+/* 0x0a4b: ctx_xfer_exec */
+ 0x98087c21,
+ 0x24bd1601,
+ 0x050007f1,
+ 0xd00103f0,
+ 0x04bd0002,
+ 0xf1021fb9,
+ 0xf0a500e7,
+ 0x21f441e3,
+ 0x01fcf09d,
+ 0xb6022cf0,
+ 0xf2fd0124,
+ 0x02ffb905,
+ 0xa504e7f1,
+ 0xf441e3f0,
+ 0x21f59d21,
+ 0x24bd026a,
+ 0x47fc07f1,
+ 0xd00203f0,
+ 0x04bd0002,
+ 0xb6012cf0,
+ 0x07f10320,
+ 0x03f04afc,
+ 0x0002d002,
+ 0xacf004bd,
+ 0x06a5f001,
+ 0x9800b7f0,
+ 0x0d98000c,
+ 0x00e7f001,
+ 0x016f21f5,
+ 0xf508a7f0,
+ 0xf5011021,
+ 0xf4025e21,
+ 0xa7f01301,
+ 0xd021f40c,
+ 0xf505f7f0,
+ 0xf4085e21,
+/* 0x0ada: ctx_xfer_post */
+ 0xf7f02e02,
+ 0xd721f502,
+ 0xf5f4bd07,
+ 0xf5083621,
+ 0xf5027f21,
+ 0xbd07e921,
+ 0xd721f5f4,
+ 0x1011f407,
+ 0xfd400198,
+ 0x0bf40511,
+ 0xad21f507,
+/* 0x0b05: ctx_xfer_no_post_mmio */
+/* 0x0b05: ctx_xfer_done */
+ 0x0000f809,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5
new file mode 100644
index 000000000000..43243a35f6dc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+
+#define CHIPSET GK208
+#include "macros.fuc"
+
+.section #gk208_grhub_data
+#define INCLUDE_DATA
+#include "com.fuc"
+#include "hub.fuc"
+#undef INCLUDE_DATA
+
+.section #gk208_grhub_code
+#define INCLUDE_CODE
+bra #init
+#include "com.fuc"
+#include "hub.fuc"
+.align 256
+#undef INCLUDE_CODE
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h
new file mode 100644
index 000000000000..0e98fa4a386e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgk208.fuc5.h
@@ -0,0 +1,916 @@
+uint32_t gk208_grhub_data[] = {
+/* 0x0000: hub_mmio_list_head */
+ 0x00000300,
+/* 0x0004: hub_mmio_list_tail */
+ 0x00000304,
+/* 0x0008: gpc_count */
+ 0x00000000,
+/* 0x000c: rop_count */
+ 0x00000000,
+/* 0x0010: cmd_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: ctx_current */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0100: chan_data */
+/* 0x0100: chan_mmio_count */
+ 0x00000000,
+/* 0x0104: chan_mmio_address */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0200: xfer_data */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0300: hub_mmio_list_base */
+ 0x0417e91c,
+};
+
+uint32_t gk208_grhub_code[] = {
+ 0x030e0ef5,
+/* 0x0004: queue_put */
+ 0x9800d898,
+ 0x86f001d9,
+ 0xf489a408,
+ 0x020f0b1b,
+ 0x0002f87e,
+/* 0x001a: queue_put_next */
+ 0x98c400f8,
+ 0x0384b607,
+ 0xb6008dbb,
+ 0x8eb50880,
+ 0x018fb500,
+ 0xf00190b6,
+ 0xd9b50f94,
+/* 0x0037: queue_get */
+ 0xf400f801,
+ 0xd8980131,
+ 0x01d99800,
+ 0x0bf489a4,
+ 0x0789c421,
+ 0xbb0394b6,
+ 0x90b6009d,
+ 0x009e9808,
+ 0xb6019f98,
+ 0x84f00180,
+ 0x00d8b50f,
+/* 0x0063: queue_get_done */
+ 0xf80132f4,
+/* 0x0065: nv_rd32 */
+ 0xf0ecb200,
+ 0x00801fc9,
+ 0x0cf601ca,
+/* 0x0073: nv_rd32_wait */
+ 0x8c04bd00,
+ 0xcf01ca00,
+ 0xccc800cc,
+ 0xf61bf41f,
+ 0xec7e060a,
+ 0x008f0000,
+ 0xffcf01cb,
+/* 0x008f: nv_wr32 */
+ 0x8000f800,
+ 0xf601cc00,
+ 0x04bd000f,
+ 0xc9f0ecb2,
+ 0x1ec9f01f,
+ 0x01ca0080,
+ 0xbd000cf6,
+/* 0x00a9: nv_wr32_wait */
+ 0xca008c04,
+ 0x00cccf01,
+ 0xf41fccc8,
+ 0x00f8f61b,
+/* 0x00b8: wait_donez */
+ 0x99f094bd,
+ 0x37008000,
+ 0x0009f602,
+ 0x008004bd,
+ 0x0af60206,
+/* 0x00cf: wait_donez_ne */
+ 0x8804bd00,
+ 0xcf010000,
+ 0x8aff0088,
+ 0xf61bf488,
+ 0x99f094bd,
+ 0x17008000,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x00ec: wait_doneo */
+ 0x99f094bd,
+ 0x37008000,
+ 0x0009f602,
+ 0x008004bd,
+ 0x0af60206,
+/* 0x0103: wait_doneo_e */
+ 0x8804bd00,
+ 0xcf010000,
+ 0x8aff0088,
+ 0xf60bf488,
+ 0x99f094bd,
+ 0x17008000,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x0120: mmctx_size */
+/* 0x0122: nv_mmctx_size_loop */
+ 0xe89894bd,
+ 0x1a85b600,
+ 0xb60180b6,
+ 0x98bb0284,
+ 0x04e0b600,
+ 0x1bf4efa4,
+ 0xf89fb2ec,
+/* 0x013d: mmctx_xfer */
+ 0xf094bd00,
+ 0x00800199,
+ 0x09f60237,
+ 0xbd04bd00,
+ 0x05bbfd94,
+ 0x800f0bf4,
+ 0xf601c400,
+ 0x04bd000b,
+/* 0x015f: mmctx_base_disabled */
+ 0xfd0099f0,
+ 0x0bf405ee,
+ 0xc6008018,
+ 0x000ef601,
+ 0x008004bd,
+ 0x0ff601c7,
+ 0xf004bd00,
+/* 0x017a: mmctx_multi_disabled */
+ 0xabc80199,
+ 0x10b4b600,
+ 0xc80cb9f0,
+ 0xe4b601ae,
+ 0x05befd11,
+ 0x01c50080,
+ 0xbd000bf6,
+/* 0x0195: mmctx_exec_loop */
+/* 0x0195: mmctx_wait_free */
+ 0xc5008e04,
+ 0x00eecf01,
+ 0xf41fe4f0,
+ 0xce98f60b,
+ 0x05e9fd00,
+ 0x01c80080,
+ 0xbd000ef6,
+ 0x04c0b604,
+ 0x1bf4cda4,
+ 0x02abc8df,
+/* 0x01bf: mmctx_fini_wait */
+ 0x8b1c1bf4,
+ 0xcf01c500,
+ 0xb4f000bb,
+ 0x10b4b01f,
+ 0x0af31bf4,
+ 0x00b87e05,
+ 0x250ef400,
+/* 0x01d8: mmctx_stop */
+ 0xb600abc8,
+ 0xb9f010b4,
+ 0x12b9f00c,
+ 0x01c50080,
+ 0xbd000bf6,
+/* 0x01ed: mmctx_stop_wait */
+ 0xc5008b04,
+ 0x00bbcf01,
+ 0xf412bbc8,
+/* 0x01fa: mmctx_done */
+ 0x94bdf61b,
+ 0x800199f0,
+ 0xf6021700,
+ 0x04bd0009,
+/* 0x020a: strand_wait */
+ 0xa0f900f8,
+ 0xb87e020a,
+ 0xa0fc0000,
+/* 0x0216: strand_pre */
+ 0x0c0900f8,
+ 0x024afc80,
+ 0xbd0009f6,
+ 0x020a7e04,
+/* 0x0227: strand_post */
+ 0x0900f800,
+ 0x4afc800d,
+ 0x0009f602,
+ 0x0a7e04bd,
+ 0x00f80002,
+/* 0x0238: strand_set */
+ 0xfc800f0c,
+ 0x0cf6024f,
+ 0x0c04bd00,
+ 0x4afc800b,
+ 0x000cf602,
+ 0xfc8004bd,
+ 0x0ef6024f,
+ 0x0c04bd00,
+ 0x4afc800a,
+ 0x000cf602,
+ 0x0a7e04bd,
+ 0x00f80002,
+/* 0x0268: strand_ctx_init */
+ 0x99f094bd,
+ 0x37008003,
+ 0x0009f602,
+ 0x167e04bd,
+ 0x030e0002,
+ 0x0002387e,
+ 0xfc80c4bd,
+ 0x0cf60247,
+ 0x0c04bd00,
+ 0x4afc8001,
+ 0x000cf602,
+ 0x0a7e04bd,
+ 0x0c920002,
+ 0x46fc8001,
+ 0x000cf602,
+ 0x020c04bd,
+ 0x024afc80,
+ 0xbd000cf6,
+ 0x020a7e04,
+ 0x02277e00,
+ 0x42008800,
+ 0x20008902,
+ 0x0099cf02,
+/* 0x02c7: ctx_init_strand_loop */
+ 0xf608fe95,
+ 0x8ef6008e,
+ 0x808acf40,
+ 0xb606a5b6,
+ 0xeabb01a0,
+ 0x0480b600,
+ 0xf40192b6,
+ 0xe4b6e81b,
+ 0xf2efbc08,
+ 0x99f094bd,
+ 0x17008003,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x02f8: error */
+ 0x02050080,
+ 0xbd000ff6,
+ 0x80010f04,
+ 0xf6030700,
+ 0x04bd000f,
+/* 0x030e: init */
+ 0x04bd00f8,
+ 0x410007fe,
+ 0x11cf4200,
+ 0x0911e700,
+ 0x0814b601,
+ 0x020014fe,
+ 0x12004002,
+ 0xbd0002f6,
+ 0x05c94104,
+ 0xbd0010fe,
+ 0x07004024,
+ 0xbd0002f6,
+ 0x20034204,
+ 0x01010080,
+ 0xbd0002f6,
+ 0x20044204,
+ 0x01010480,
+ 0xbd0002f6,
+ 0x200b4204,
+ 0x01010880,
+ 0xbd0002f6,
+ 0x200c4204,
+ 0x01011c80,
+ 0xbd0002f6,
+ 0x01039204,
+ 0x03090080,
+ 0xbd0003f6,
+ 0x87044204,
+ 0xf6040040,
+ 0x04bd0002,
+ 0x00400402,
+ 0x0002f603,
+ 0x31f404bd,
+ 0x96048e10,
+ 0x00657e40,
+ 0xc7feb200,
+ 0x01b590f1,
+ 0x1ff4f003,
+ 0x01020fb5,
+ 0x041fbb01,
+ 0x800112b6,
+ 0xf6010300,
+ 0x04bd0001,
+ 0x01040080,
+ 0xbd0001f6,
+ 0x01004104,
+ 0xa87e020f,
+ 0xb77e0006,
+ 0x100f0006,
+ 0x0006f97e,
+ 0x98000e98,
+ 0x207e010f,
+ 0x14950001,
+ 0xc0008008,
+ 0x0004f601,
+ 0x008004bd,
+ 0x04f601c1,
+ 0xb704bd00,
+ 0xbb130030,
+ 0xf5b6001f,
+ 0xd3008002,
+ 0x000ff601,
+ 0x15b604bd,
+ 0x0110b608,
+ 0xb20814b6,
+ 0x02687e1f,
+ 0x001fbb00,
+ 0x84020398,
+/* 0x041f: init_gpc */
+ 0xb8502000,
+ 0x0008044e,
+ 0x8f7e1fb2,
+ 0x4eb80000,
+ 0xbd00010c,
+ 0x008f7ef4,
+ 0x044eb800,
+ 0x8f7e0001,
+ 0x4eb80000,
+ 0x0f000100,
+ 0x008f7e02,
+ 0x004eb800,
+/* 0x044e: init_gpc_wait */
+ 0x657e0008,
+ 0xffc80000,
+ 0xf90bf41f,
+ 0x08044eb8,
+ 0x00657e00,
+ 0x001fbb00,
+ 0x800040b7,
+ 0xf40132b6,
+ 0x000fb41b,
+ 0x0006f97e,
+ 0xa87e000f,
+ 0x00800006,
+ 0x01f60201,
+ 0xbd04bd00,
+ 0x1f19f014,
+ 0x02300080,
+ 0xbd0001f6,
+/* 0x0491: main */
+ 0x0031f404,
+ 0x0d0028f4,
+ 0x00377e10,
+ 0xf401f400,
+ 0x4001e4b1,
+ 0x00c71bf5,
+ 0x99f094bd,
+ 0x37008004,
+ 0x0009f602,
+ 0x008104bd,
+ 0x11cf02c0,
+ 0xc1008200,
+ 0x0022cf02,
+ 0xf41f13c8,
+ 0x23c8770b,
+ 0x550bf41f,
+ 0x12b220f9,
+ 0x99f094bd,
+ 0x37008007,
+ 0x0009f602,
+ 0x32f404bd,
+ 0x0231f401,
+ 0x00087c7e,
+ 0x99f094bd,
+ 0x17008007,
+ 0x0009f602,
+ 0x20fc04bd,
+ 0x99f094bd,
+ 0x37008006,
+ 0x0009f602,
+ 0x31f404bd,
+ 0x087c7e01,
+ 0xf094bd00,
+ 0x00800699,
+ 0x09f60217,
+ 0xf404bd00,
+/* 0x0522: chsw_prev_no_next */
+ 0x20f92f0e,
+ 0x32f412b2,
+ 0x0232f401,
+ 0x00087c7e,
+ 0x008020fc,
+ 0x02f602c0,
+ 0xf404bd00,
+/* 0x053e: chsw_no_prev */
+ 0x23c8130e,
+ 0x0d0bf41f,
+ 0xf40131f4,
+ 0x7c7e0232,
+/* 0x054e: chsw_done */
+ 0x01020008,
+ 0x02c30080,
+ 0xbd0002f6,
+ 0xf094bd04,
+ 0x00800499,
+ 0x09f60217,
+ 0xf504bd00,
+/* 0x056b: main_not_ctx_switch */
+ 0xb0ff2a0e,
+ 0x1bf401e4,
+ 0x7ef2b20c,
+ 0xf400081c,
+/* 0x057a: main_not_ctx_chan */
+ 0xe4b0400e,
+ 0x2c1bf402,
+ 0x99f094bd,
+ 0x37008007,
+ 0x0009f602,
+ 0x32f404bd,
+ 0x0232f401,
+ 0x00087c7e,
+ 0x99f094bd,
+ 0x17008007,
+ 0x0009f602,
+ 0x0ef404bd,
+/* 0x05a9: main_not_ctx_save */
+ 0x10ef9411,
+ 0x7e01f5f0,
+ 0xf50002f8,
+/* 0x05b7: main_done */
+ 0xbdfede0e,
+ 0x1f29f024,
+ 0x02300080,
+ 0xbd0002f6,
+ 0xcc0ef504,
+/* 0x05c9: ih */
+ 0xfe80f9fe,
+ 0x80f90188,
+ 0xa0f990f9,
+ 0xd0f9b0f9,
+ 0xf0f9e0f9,
+ 0x004a04bd,
+ 0x00aacf02,
+ 0xf404abc4,
+ 0x100d230b,
+ 0xcf1a004e,
+ 0x004f00ee,
+ 0x00ffcf19,
+ 0x0000047e,
+ 0x0400b0b7,
+ 0x0040010e,
+ 0x000ef61d,
+/* 0x060a: ih_no_fifo */
+ 0xabe404bd,
+ 0x0bf40100,
+ 0x4e100d0c,
+ 0x047e4001,
+/* 0x061a: ih_no_ctxsw */
+ 0xabe40000,
+ 0x0bf40400,
+ 0x07088e56,
+ 0x00657e40,
+ 0x80ffb200,
+ 0xf6020400,
+ 0x04bd000f,
+ 0x4007048e,
+ 0x0000657e,
+ 0x0080ffb2,
+ 0x0ff60203,
+ 0xc704bd00,
+ 0xee9450fe,
+ 0x07008f02,
+ 0x00efbb40,
+ 0x0000657e,
+ 0x02020080,
+ 0xbd000ff6,
+ 0x7e030f04,
+ 0x4b0002f8,
+ 0xbfb20100,
+ 0x4001448e,
+ 0x00008f7e,
+/* 0x0674: ih_no_fwmthd */
+ 0xbd05044b,
+ 0xb4abffb0,
+ 0x800c0bf4,
+ 0xf6030700,
+ 0x04bd000b,
+/* 0x0688: ih_no_other */
+ 0xf6010040,
+ 0x04bd000a,
+ 0xe0fcf0fc,
+ 0xb0fcd0fc,
+ 0x90fca0fc,
+ 0x88fe80fc,
+ 0xf480fc00,
+ 0x01f80032,
+/* 0x06a8: ctx_4170s */
+ 0xb210f5f0,
+ 0x41708eff,
+ 0x008f7e40,
+/* 0x06b7: ctx_4170w */
+ 0x8e00f800,
+ 0x7e404170,
+ 0xb2000065,
+ 0x10f4f0ff,
+ 0xf8f31bf4,
+/* 0x06c9: ctx_redswitch */
+ 0x02004e00,
+ 0xf040e5f0,
+ 0xe5f020e5,
+ 0x85008010,
+ 0x000ef601,
+ 0x080f04bd,
+/* 0x06e0: ctx_redswitch_delay */
+ 0xf401f2b6,
+ 0xe5f1fd1b,
+ 0xe5f10400,
+ 0x00800100,
+ 0x0ef60185,
+ 0xf804bd00,
+/* 0x06f9: ctx_86c */
+ 0x23008000,
+ 0x000ff602,
+ 0xffb204bd,
+ 0x408a148e,
+ 0x00008f7e,
+ 0x8c8effb2,
+ 0x8f7e41a8,
+ 0x00f80000,
+/* 0x0718: ctx_mem */
+ 0x02840080,
+ 0xbd000ff6,
+/* 0x0721: ctx_mem_wait */
+ 0x84008f04,
+ 0x00ffcf02,
+ 0xf405fffd,
+ 0x00f8f61b,
+/* 0x0730: ctx_load */
+ 0x99f094bd,
+ 0x37008005,
+ 0x0009f602,
+ 0x0c0a04bd,
+ 0x0000b87e,
+ 0x0080f4bd,
+ 0x0ff60289,
+ 0x8004bd00,
+ 0xf602c100,
+ 0x04bd0002,
+ 0x02830080,
+ 0xbd0002f6,
+ 0x7e070f04,
+ 0x80000718,
+ 0xf602c000,
+ 0x04bd0002,
+ 0xf0000bfe,
+ 0x24b61f2a,
+ 0x0220b604,
+ 0x99f094bd,
+ 0x37008008,
+ 0x0009f602,
+ 0x008004bd,
+ 0x02f60281,
+ 0xd204bd00,
+ 0x80000000,
+ 0x800225f0,
+ 0xf6028800,
+ 0x04bd0002,
+ 0x00421001,
+ 0x0223f002,
+ 0xf80512fa,
+ 0xf094bd03,
+ 0x00800899,
+ 0x09f60217,
+ 0x9804bd00,
+ 0x14b68101,
+ 0x80029818,
+ 0xfd0825b6,
+ 0x01b50512,
+ 0xf094bd16,
+ 0x00800999,
+ 0x09f60237,
+ 0x8004bd00,
+ 0xf6028100,
+ 0x04bd0001,
+ 0x00800102,
+ 0x02f60288,
+ 0x4104bd00,
+ 0x13f00100,
+ 0x0501fa06,
+ 0x94bd03f8,
+ 0x800999f0,
+ 0xf6021700,
+ 0x04bd0009,
+ 0x99f094bd,
+ 0x17008005,
+ 0x0009f602,
+ 0x00f804bd,
+/* 0x081c: ctx_chan */
+ 0x0007307e,
+ 0xb87e0c0a,
+ 0x050f0000,
+ 0x0007187e,
+/* 0x082e: ctx_mmio_exec */
+ 0x039800f8,
+ 0x81008041,
+ 0x0003f602,
+ 0x34bd04bd,
+/* 0x083c: ctx_mmio_loop */
+ 0xf4ff34c4,
+ 0x00450e1b,
+ 0x0653f002,
+ 0xf80535fa,
+/* 0x084d: ctx_mmio_pull */
+ 0x804e9803,
+ 0x7e814f98,
+ 0xb600008f,
+ 0x12b60830,
+ 0xdf1bf401,
+/* 0x0860: ctx_mmio_done */
+ 0x80160398,
+ 0xf6028100,
+ 0x04bd0003,
+ 0x414000b5,
+ 0x13f00100,
+ 0x0601fa06,
+ 0x00f803f8,
+/* 0x087c: ctx_xfer */
+ 0x0080040e,
+ 0x0ef60302,
+/* 0x0887: ctx_xfer_idle */
+ 0x8e04bd00,
+ 0xcf030000,
+ 0xe4f100ee,
+ 0x1bf42000,
+ 0x0611f4f5,
+/* 0x089b: ctx_xfer_pre */
+ 0x0f0c02f4,
+ 0x06f97e10,
+ 0x1b11f400,
+/* 0x08a4: ctx_xfer_pre_load */
+ 0xa87e020f,
+ 0xb77e0006,
+ 0xc97e0006,
+ 0xf4bd0006,
+ 0x0006a87e,
+ 0x0007307e,
+/* 0x08bc: ctx_xfer_exec */
+ 0xbd160198,
+ 0x05008024,
+ 0x0002f601,
+ 0x1fb204bd,
+ 0x41a5008e,
+ 0x00008f7e,
+ 0xf001fcf0,
+ 0x24b6022c,
+ 0x05f2fd01,
+ 0x048effb2,
+ 0x8f7e41a5,
+ 0x167e0000,
+ 0x24bd0002,
+ 0x0247fc80,
+ 0xbd0002f6,
+ 0x012cf004,
+ 0x800320b6,
+ 0xf6024afc,
+ 0x04bd0002,
+ 0xf001acf0,
+ 0x000b06a5,
+ 0x98000c98,
+ 0x000e010d,
+ 0x00013d7e,
+ 0xec7e080a,
+ 0x0a7e0000,
+ 0x01f40002,
+ 0x7e0c0a12,
+ 0x0f0000b8,
+ 0x07187e05,
+ 0x2d02f400,
+/* 0x0938: ctx_xfer_post */
+ 0xa87e020f,
+ 0xf4bd0006,
+ 0x0006f97e,
+ 0x0002277e,
+ 0x0006b77e,
+ 0xa87ef4bd,
+ 0x11f40006,
+ 0x40019810,
+ 0xf40511fd,
+ 0x2e7e070b,
+/* 0x0962: ctx_xfer_no_post_mmio */
+/* 0x0962: ctx_xfer_done */
+ 0x00f80008,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5 b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5
index 27591b3086a5..27591b3086a5 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h
index 5f953c5c20b7..5f953c5c20b7 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/hubgm107.fuc5.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/hubgm107.fuc5.h
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/macros.fuc
index 2a0b0f844299..2a0b0f844299 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/macros.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/macros.fuc
diff --git a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/os.h
index 1718ae4e8224..1718ae4e8224 100644
--- a/drivers/gpu/drm/nouveau/core/engine/graph/fuc/os.h
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/fuc/os.h
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
new file mode 100644
index 000000000000..1dd482e9da77
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.c
@@ -0,0 +1,1678 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+#include "fuc/os.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/option.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+#include <subdev/mc.h>
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+#include <nvif/unpack.h>
+
+/*******************************************************************************
+ * Zero Bandwidth Clear
+ ******************************************************************************/
+
+static void
+gf100_gr_zbc_clear_color(struct gf100_gr_priv *priv, int zbc)
+{
+ if (priv->zbc_color[zbc].format) {
+ nv_wr32(priv, 0x405804, priv->zbc_color[zbc].ds[0]);
+ nv_wr32(priv, 0x405808, priv->zbc_color[zbc].ds[1]);
+ nv_wr32(priv, 0x40580c, priv->zbc_color[zbc].ds[2]);
+ nv_wr32(priv, 0x405810, priv->zbc_color[zbc].ds[3]);
+ }
+ nv_wr32(priv, 0x405814, priv->zbc_color[zbc].format);
+ nv_wr32(priv, 0x405820, zbc);
+ nv_wr32(priv, 0x405824, 0x00000004); /* TRIGGER | WRITE | COLOR */
+}
+
+static int
+gf100_gr_zbc_color_get(struct gf100_gr_priv *priv, int format,
+ const u32 ds[4], const u32 l2[4])
+{
+ struct nvkm_ltc *ltc = nvkm_ltc(priv);
+ int zbc = -ENOSPC, i;
+
+ for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+ if (priv->zbc_color[i].format) {
+ if (priv->zbc_color[i].format != format)
+ continue;
+ if (memcmp(priv->zbc_color[i].ds, ds, sizeof(
+ priv->zbc_color[i].ds)))
+ continue;
+ if (memcmp(priv->zbc_color[i].l2, l2, sizeof(
+ priv->zbc_color[i].l2))) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ return i;
+ } else {
+ zbc = (zbc < 0) ? i : zbc;
+ }
+ }
+
+ if (zbc < 0)
+ return zbc;
+
+ memcpy(priv->zbc_color[zbc].ds, ds, sizeof(priv->zbc_color[zbc].ds));
+ memcpy(priv->zbc_color[zbc].l2, l2, sizeof(priv->zbc_color[zbc].l2));
+ priv->zbc_color[zbc].format = format;
+ ltc->zbc_color_get(ltc, zbc, l2);
+ gf100_gr_zbc_clear_color(priv, zbc);
+ return zbc;
+}
+
+static void
+gf100_gr_zbc_clear_depth(struct gf100_gr_priv *priv, int zbc)
+{
+ if (priv->zbc_depth[zbc].format)
+ nv_wr32(priv, 0x405818, priv->zbc_depth[zbc].ds);
+ nv_wr32(priv, 0x40581c, priv->zbc_depth[zbc].format);
+ nv_wr32(priv, 0x405820, zbc);
+ nv_wr32(priv, 0x405824, 0x00000005); /* TRIGGER | WRITE | DEPTH */
+}
+
+static int
+gf100_gr_zbc_depth_get(struct gf100_gr_priv *priv, int format,
+ const u32 ds, const u32 l2)
+{
+ struct nvkm_ltc *ltc = nvkm_ltc(priv);
+ int zbc = -ENOSPC, i;
+
+ for (i = ltc->zbc_min; i <= ltc->zbc_max; i++) {
+ if (priv->zbc_depth[i].format) {
+ if (priv->zbc_depth[i].format != format)
+ continue;
+ if (priv->zbc_depth[i].ds != ds)
+ continue;
+ if (priv->zbc_depth[i].l2 != l2) {
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ return i;
+ } else {
+ zbc = (zbc < 0) ? i : zbc;
+ }
+ }
+
+ if (zbc < 0)
+ return zbc;
+
+ priv->zbc_depth[zbc].format = format;
+ priv->zbc_depth[zbc].ds = ds;
+ priv->zbc_depth[zbc].l2 = l2;
+ ltc->zbc_depth_get(ltc, zbc, l2);
+ gf100_gr_zbc_clear_depth(priv, zbc);
+ return zbc;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static int
+gf100_fermi_mthd_zbc_color(struct nvkm_object *object, void *data, u32 size)
+{
+ struct gf100_gr_priv *priv = (void *)object->engine;
+ union {
+ struct fermi_a_zbc_color_v0 v0;
+ } *args = data;
+ int ret;
+
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ switch (args->v0.format) {
+ case FERMI_A_ZBC_COLOR_V0_FMT_ZERO:
+ case FERMI_A_ZBC_COLOR_V0_FMT_UNORM_ONE:
+ case FERMI_A_ZBC_COLOR_V0_FMT_RF32_GF32_BF32_AF32:
+ case FERMI_A_ZBC_COLOR_V0_FMT_R16_G16_B16_A16:
+ case FERMI_A_ZBC_COLOR_V0_FMT_RN16_GN16_BN16_AN16:
+ case FERMI_A_ZBC_COLOR_V0_FMT_RS16_GS16_BS16_AS16:
+ case FERMI_A_ZBC_COLOR_V0_FMT_RU16_GU16_BU16_AU16:
+ case FERMI_A_ZBC_COLOR_V0_FMT_RF16_GF16_BF16_AF16:
+ case FERMI_A_ZBC_COLOR_V0_FMT_A8R8G8B8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_A8RL8GL8BL8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_A2B10G10R10:
+ case FERMI_A_ZBC_COLOR_V0_FMT_AU2BU10GU10RU10:
+ case FERMI_A_ZBC_COLOR_V0_FMT_A8B8G8R8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_A8BL8GL8RL8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_AN8BN8GN8RN8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_AS8BS8GS8RS8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_AU8BU8GU8RU8:
+ case FERMI_A_ZBC_COLOR_V0_FMT_A2R10G10B10:
+ case FERMI_A_ZBC_COLOR_V0_FMT_BF10GF11RF11:
+ ret = gf100_gr_zbc_color_get(priv, args->v0.format,
+ args->v0.ds,
+ args->v0.l2);
+ if (ret >= 0) {
+ args->v0.index = ret;
+ return 0;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int
+gf100_fermi_mthd_zbc_depth(struct nvkm_object *object, void *data, u32 size)
+{
+ struct gf100_gr_priv *priv = (void *)object->engine;
+ union {
+ struct fermi_a_zbc_depth_v0 v0;
+ } *args = data;
+ int ret;
+
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ switch (args->v0.format) {
+ case FERMI_A_ZBC_DEPTH_V0_FMT_FP32:
+ ret = gf100_gr_zbc_depth_get(priv, args->v0.format,
+ args->v0.ds,
+ args->v0.l2);
+ return (ret >= 0) ? 0 : -ENOSPC;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int
+gf100_fermi_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ switch (mthd) {
+ case FERMI_A_ZBC_COLOR:
+ return gf100_fermi_mthd_zbc_color(object, data, size);
+ case FERMI_A_ZBC_DEPTH:
+ return gf100_fermi_mthd_zbc_depth(object, data, size);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+struct nvkm_ofuncs
+gf100_fermi_ofuncs = {
+ .ctor = _nvkm_object_ctor,
+ .dtor = nvkm_object_destroy,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ .mthd = gf100_fermi_mthd,
+};
+
+static int
+gf100_gr_set_shader_exceptions(struct nvkm_object *object, u32 mthd,
+ void *pdata, u32 size)
+{
+ struct gf100_gr_priv *priv = (void *)nv_engine(object);
+ if (size >= sizeof(u32)) {
+ u32 data = *(u32 *)pdata ? 0xffffffff : 0x00000000;
+ nv_wr32(priv, 0x419e44, data);
+ nv_wr32(priv, 0x419e4c, data);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+struct nvkm_omthds
+gf100_gr_9097_omthds[] = {
+ { 0x1528, 0x1528, gf100_gr_set_shader_exceptions },
+ {}
+};
+
+struct nvkm_omthds
+gf100_gr_90c0_omthds[] = {
+ { 0x1528, 0x1528, gf100_gr_set_shader_exceptions },
+ {}
+};
+
+struct nvkm_oclass
+gf100_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0x9039, &nvkm_object_ofuncs },
+ { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+int
+gf100_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *args, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_vm *vm = nvkm_client(parent)->vm;
+ struct gf100_gr_priv *priv = (void *)engine;
+ struct gf100_gr_data *data = priv->mmio_data;
+ struct gf100_gr_mmio *mmio = priv->mmio_list;
+ struct gf100_gr_chan *chan;
+ int ret, i;
+
+ /* allocate memory for context, and fill with default values */
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL,
+ priv->size, 0x100,
+ NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ /* allocate memory for a "mmio list" buffer that's used by the HUB
+ * fuc to modify some per-context register settings on first load
+ * of the context.
+ */
+ ret = nvkm_gpuobj_new(nv_object(chan), NULL, 0x1000, 0x100, 0,
+ &chan->mmio);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_map_vm(nv_gpuobj(chan->mmio), vm,
+ NV_MEM_ACCESS_RW | NV_MEM_ACCESS_SYS,
+ &chan->mmio_vma);
+ if (ret)
+ return ret;
+
+ /* allocate buffers referenced by mmio list */
+ for (i = 0; data->size && i < ARRAY_SIZE(priv->mmio_data); i++) {
+ ret = nvkm_gpuobj_new(nv_object(chan), NULL, data->size,
+ data->align, 0, &chan->data[i].mem);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_map_vm(chan->data[i].mem, vm, data->access,
+ &chan->data[i].vma);
+ if (ret)
+ return ret;
+
+ data++;
+ }
+
+ /* finally, fill in the mmio list and point the context at it */
+ for (i = 0; mmio->addr && i < ARRAY_SIZE(priv->mmio_list); i++) {
+ u32 addr = mmio->addr;
+ u32 data = mmio->data;
+
+ if (mmio->buffer >= 0) {
+ u64 info = chan->data[mmio->buffer].vma.offset;
+ data |= info >> mmio->shift;
+ }
+
+ nv_wo32(chan->mmio, chan->mmio_nr++ * 4, addr);
+ nv_wo32(chan->mmio, chan->mmio_nr++ * 4, data);
+ mmio++;
+ }
+
+ for (i = 0; i < priv->size; i += 4)
+ nv_wo32(chan, i, priv->data[i / 4]);
+
+ if (!priv->firmware) {
+ nv_wo32(chan, 0x00, chan->mmio_nr / 2);
+ nv_wo32(chan, 0x04, chan->mmio_vma.offset >> 8);
+ } else {
+ nv_wo32(chan, 0xf4, 0);
+ nv_wo32(chan, 0xf8, 0);
+ nv_wo32(chan, 0x10, chan->mmio_nr / 2);
+ nv_wo32(chan, 0x14, lower_32_bits(chan->mmio_vma.offset));
+ nv_wo32(chan, 0x18, upper_32_bits(chan->mmio_vma.offset));
+ nv_wo32(chan, 0x1c, 1);
+ nv_wo32(chan, 0x20, 0);
+ nv_wo32(chan, 0x28, 0);
+ nv_wo32(chan, 0x2c, 0);
+ }
+
+ return 0;
+}
+
+void
+gf100_gr_context_dtor(struct nvkm_object *object)
+{
+ struct gf100_gr_chan *chan = (void *)object;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(chan->data); i++) {
+ nvkm_gpuobj_unmap(&chan->data[i].vma);
+ nvkm_gpuobj_ref(NULL, &chan->data[i].mem);
+ }
+
+ nvkm_gpuobj_unmap(&chan->mmio_vma);
+ nvkm_gpuobj_ref(NULL, &chan->mmio);
+
+ nvkm_gr_context_destroy(&chan->base);
+}
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf100_gr_init_main_0[] = {
+ { 0x400080, 1, 0x04, 0x003083c2 },
+ { 0x400088, 1, 0x04, 0x00006fe7 },
+ { 0x40008c, 1, 0x04, 0x00000000 },
+ { 0x400090, 1, 0x04, 0x00000030 },
+ { 0x40013c, 1, 0x04, 0x013901f7 },
+ { 0x400140, 1, 0x04, 0x00000100 },
+ { 0x400144, 1, 0x04, 0x00000000 },
+ { 0x400148, 1, 0x04, 0x00000110 },
+ { 0x400138, 1, 0x04, 0x00000000 },
+ { 0x400130, 2, 0x04, 0x00000000 },
+ { 0x400124, 1, 0x04, 0x00000002 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_fe_0[] = {
+ { 0x40415c, 1, 0x04, 0x00000000 },
+ { 0x404170, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pri_0[] = {
+ { 0x404488, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_rstr2d_0[] = {
+ { 0x407808, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pd_0[] = {
+ { 0x406024, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_scc_0[] = {
+ { 0x40803c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_prop_0[] = {
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gpc_unk_0[] = {
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x80000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_setup_0[] = {
+ { 0x418814, 3, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_crstr_0[] = {
+ { 0x418b04, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_setup_1[] = {
+ { 0x4188c8, 1, 0x04, 0x80000000 },
+ { 0x4188cc, 1, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_zcull_0[] = {
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gpm_0[] = {
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gpc_unk_1[] = {
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000050 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_gcc_0[] = {
+ { 0x41900c, 1, 0x04, 0x00000000 },
+ { 0x419018, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_tpccs_0[] = {
+ { 0x419d08, 2, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_tex_0[] = {
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pe_0[] = {
+ { 0x41980c, 3, 0x04, 0x00000000 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_l1c_0[] = {
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x80000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00008bf4 },
+ { 0x419cbc, 1, 0x04, 0x28137606 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_wwdx_0[] = {
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_tpccs_1[] = {
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_mpc_0[] = {
+ { 0x419c0c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf100_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x06060618 },
+ { 0x419ed0, 1, 0x04, 0x0eff0e38 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_be_0[] = {
+ { 0x40880c, 1, 0x04, 0x00000000 },
+ { 0x408910, 9, 0x04, 0x00000000 },
+ { 0x408950, 1, 0x04, 0x00000000 },
+ { 0x408954, 1, 0x04, 0x0000ffff },
+ { 0x408984, 1, 0x04, 0x00000000 },
+ { 0x408988, 1, 0x04, 0x08040201 },
+ { 0x40898c, 1, 0x04, 0x80402010 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_fe_1[] = {
+ { 0x4040f0, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf100_gr_init_pe_1[] = {
+ { 0x419880, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf100_gr_pack_mmio[] = {
+ { gf100_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf100_gr_init_pd_0 },
+ { gf100_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gf100_gr_init_prop_0 },
+ { gf100_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf100_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf100_gr_init_gpm_0 },
+ { gf100_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gf100_gr_init_tpccs_0 },
+ { gf100_gr_init_tex_0 },
+ { gf100_gr_init_pe_0 },
+ { gf100_gr_init_l1c_0 },
+ { gf100_gr_init_wwdx_0 },
+ { gf100_gr_init_tpccs_1 },
+ { gf100_gr_init_mpc_0 },
+ { gf100_gr_init_sm_0 },
+ { gf100_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ { gf100_gr_init_pe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+void
+gf100_gr_zbc_init(struct gf100_gr_priv *priv)
+{
+ const u32 zero[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
+ const u32 one[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
+ 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff };
+ const u32 f32_0[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000 };
+ const u32 f32_1[] = { 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000,
+ 0x3f800000, 0x3f800000, 0x3f800000, 0x3f800000 };
+ struct nvkm_ltc *ltc = nvkm_ltc(priv);
+ int index;
+
+ if (!priv->zbc_color[0].format) {
+ gf100_gr_zbc_color_get(priv, 1, & zero[0], &zero[4]);
+ gf100_gr_zbc_color_get(priv, 2, & one[0], &one[4]);
+ gf100_gr_zbc_color_get(priv, 4, &f32_0[0], &f32_0[4]);
+ gf100_gr_zbc_color_get(priv, 4, &f32_1[0], &f32_1[4]);
+ gf100_gr_zbc_depth_get(priv, 1, 0x00000000, 0x00000000);
+ gf100_gr_zbc_depth_get(priv, 1, 0x3f800000, 0x3f800000);
+ }
+
+ for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
+ gf100_gr_zbc_clear_color(priv, index);
+ for (index = ltc->zbc_min; index <= ltc->zbc_max; index++)
+ gf100_gr_zbc_clear_depth(priv, index);
+}
+
+void
+gf100_gr_mmio(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
+{
+ const struct gf100_gr_pack *pack;
+ const struct gf100_gr_init *init;
+
+ pack_for_each_init(init, pack, p) {
+ u32 next = init->addr + init->count * init->pitch;
+ u32 addr = init->addr;
+ while (addr < next) {
+ nv_wr32(priv, addr, init->data);
+ addr += init->pitch;
+ }
+ }
+}
+
+void
+gf100_gr_icmd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
+{
+ const struct gf100_gr_pack *pack;
+ const struct gf100_gr_init *init;
+ u32 data = 0;
+
+ nv_wr32(priv, 0x400208, 0x80000000);
+
+ pack_for_each_init(init, pack, p) {
+ u32 next = init->addr + init->count * init->pitch;
+ u32 addr = init->addr;
+
+ if ((pack == p && init == p->init) || data != init->data) {
+ nv_wr32(priv, 0x400204, init->data);
+ data = init->data;
+ }
+
+ while (addr < next) {
+ nv_wr32(priv, 0x400200, addr);
+ nv_wait(priv, 0x400700, 0x00000002, 0x00000000);
+ addr += init->pitch;
+ }
+ }
+
+ nv_wr32(priv, 0x400208, 0x00000000);
+}
+
+void
+gf100_gr_mthd(struct gf100_gr_priv *priv, const struct gf100_gr_pack *p)
+{
+ const struct gf100_gr_pack *pack;
+ const struct gf100_gr_init *init;
+ u32 data = 0;
+
+ pack_for_each_init(init, pack, p) {
+ u32 ctrl = 0x80000000 | pack->type;
+ u32 next = init->addr + init->count * init->pitch;
+ u32 addr = init->addr;
+
+ if ((pack == p && init == p->init) || data != init->data) {
+ nv_wr32(priv, 0x40448c, init->data);
+ data = init->data;
+ }
+
+ while (addr < next) {
+ nv_wr32(priv, 0x404488, ctrl | (addr << 14));
+ addr += init->pitch;
+ }
+ }
+}
+
+u64
+gf100_gr_units(struct nvkm_gr *gr)
+{
+ struct gf100_gr_priv *priv = (void *)gr;
+ u64 cfg;
+
+ cfg = (u32)priv->gpc_nr;
+ cfg |= (u32)priv->tpc_total << 8;
+ cfg |= (u64)priv->rop_nr << 32;
+
+ return cfg;
+}
+
+static const struct nvkm_enum gk104_sked_error[] = {
+ { 7, "CONSTANT_BUFFER_SIZE" },
+ { 9, "LOCAL_MEMORY_SIZE_POS" },
+ { 10, "LOCAL_MEMORY_SIZE_NEG" },
+ { 11, "WARP_CSTACK_SIZE" },
+ { 12, "TOTAL_TEMP_SIZE" },
+ { 13, "REGISTER_COUNT" },
+ { 18, "TOTAL_THREADS" },
+ { 20, "PROGRAM_OFFSET" },
+ { 21, "SHARED_MEMORY_SIZE" },
+ { 25, "SHARED_CONFIG_TOO_SMALL" },
+ { 26, "TOTAL_REGISTER_COUNT" },
+ {}
+};
+
+static const struct nvkm_enum gf100_gpc_rop_error[] = {
+ { 1, "RT_PITCH_OVERRUN" },
+ { 4, "RT_WIDTH_OVERRUN" },
+ { 5, "RT_HEIGHT_OVERRUN" },
+ { 7, "ZETA_STORAGE_TYPE_MISMATCH" },
+ { 8, "RT_STORAGE_TYPE_MISMATCH" },
+ { 10, "RT_LINEAR_MISMATCH" },
+ {}
+};
+
+static void
+gf100_gr_trap_gpc_rop(struct gf100_gr_priv *priv, int gpc)
+{
+ u32 trap[4];
+ int i;
+
+ trap[0] = nv_rd32(priv, GPC_UNIT(gpc, 0x0420));
+ trap[1] = nv_rd32(priv, GPC_UNIT(gpc, 0x0434));
+ trap[2] = nv_rd32(priv, GPC_UNIT(gpc, 0x0438));
+ trap[3] = nv_rd32(priv, GPC_UNIT(gpc, 0x043c));
+
+ nv_error(priv, "GPC%d/PROP trap:", gpc);
+ for (i = 0; i <= 29; ++i) {
+ if (!(trap[0] & (1 << i)))
+ continue;
+ pr_cont(" ");
+ nvkm_enum_print(gf100_gpc_rop_error, i);
+ }
+ pr_cont("\n");
+
+ nv_error(priv, "x = %u, y = %u, format = %x, storage type = %x\n",
+ trap[1] & 0xffff, trap[1] >> 16, (trap[2] >> 8) & 0x3f,
+ trap[3] & 0xff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+}
+
+static const struct nvkm_enum gf100_mp_warp_error[] = {
+ { 0x00, "NO_ERROR" },
+ { 0x01, "STACK_MISMATCH" },
+ { 0x05, "MISALIGNED_PC" },
+ { 0x08, "MISALIGNED_GPR" },
+ { 0x09, "INVALID_OPCODE" },
+ { 0x0d, "GPR_OUT_OF_BOUNDS" },
+ { 0x0e, "MEM_OUT_OF_BOUNDS" },
+ { 0x0f, "UNALIGNED_MEM_ACCESS" },
+ { 0x11, "INVALID_PARAM" },
+ {}
+};
+
+static const struct nvkm_bitfield gf100_mp_global_error[] = {
+ { 0x00000004, "MULTIPLE_WARP_ERRORS" },
+ { 0x00000008, "OUT_OF_STACK_SPACE" },
+ {}
+};
+
+static void
+gf100_gr_trap_mp(struct gf100_gr_priv *priv, int gpc, int tpc)
+{
+ u32 werr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x648));
+ u32 gerr = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x650));
+
+ nv_error(priv, "GPC%i/TPC%i/MP trap:", gpc, tpc);
+ nvkm_bitfield_print(gf100_mp_global_error, gerr);
+ if (werr) {
+ pr_cont(" ");
+ nvkm_enum_print(gf100_mp_warp_error, werr & 0xffff);
+ }
+ pr_cont("\n");
+
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x648), 0x00000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x650), gerr);
+}
+
+static void
+gf100_gr_trap_tpc(struct gf100_gr_priv *priv, int gpc, int tpc)
+{
+ u32 stat = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0508));
+
+ if (stat & 0x00000001) {
+ u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0224));
+ nv_error(priv, "GPC%d/TPC%d/TEX: 0x%08x\n", gpc, tpc, trap);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0224), 0xc0000000);
+ stat &= ~0x00000001;
+ }
+
+ if (stat & 0x00000002) {
+ gf100_gr_trap_mp(priv, gpc, tpc);
+ stat &= ~0x00000002;
+ }
+
+ if (stat & 0x00000004) {
+ u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x0084));
+ nv_error(priv, "GPC%d/TPC%d/POLY: 0x%08x\n", gpc, tpc, trap);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x0084), 0xc0000000);
+ stat &= ~0x00000004;
+ }
+
+ if (stat & 0x00000008) {
+ u32 trap = nv_rd32(priv, TPC_UNIT(gpc, tpc, 0x048c));
+ nv_error(priv, "GPC%d/TPC%d/L1C: 0x%08x\n", gpc, tpc, trap);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x048c), 0xc0000000);
+ stat &= ~0x00000008;
+ }
+
+ if (stat) {
+ nv_error(priv, "GPC%d/TPC%d/0x%08x: unknown\n", gpc, tpc, stat);
+ }
+}
+
+static void
+gf100_gr_trap_gpc(struct gf100_gr_priv *priv, int gpc)
+{
+ u32 stat = nv_rd32(priv, GPC_UNIT(gpc, 0x2c90));
+ int tpc;
+
+ if (stat & 0x00000001) {
+ gf100_gr_trap_gpc_rop(priv, gpc);
+ stat &= ~0x00000001;
+ }
+
+ if (stat & 0x00000002) {
+ u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0900));
+ nv_error(priv, "GPC%d/ZCULL: 0x%08x\n", gpc, trap);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ stat &= ~0x00000002;
+ }
+
+ if (stat & 0x00000004) {
+ u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x1028));
+ nv_error(priv, "GPC%d/CCACHE: 0x%08x\n", gpc, trap);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ stat &= ~0x00000004;
+ }
+
+ if (stat & 0x00000008) {
+ u32 trap = nv_rd32(priv, GPC_UNIT(gpc, 0x0824));
+ nv_error(priv, "GPC%d/ESETUP: 0x%08x\n", gpc, trap);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ stat &= ~0x00000009;
+ }
+
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ u32 mask = 0x00010000 << tpc;
+ if (stat & mask) {
+ gf100_gr_trap_tpc(priv, gpc, tpc);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), mask);
+ stat &= ~mask;
+ }
+ }
+
+ if (stat) {
+ nv_error(priv, "GPC%d/0x%08x: unknown\n", gpc, stat);
+ }
+}
+
+static void
+gf100_gr_trap_intr(struct gf100_gr_priv *priv)
+{
+ u32 trap = nv_rd32(priv, 0x400108);
+ int rop, gpc, i;
+
+ if (trap & 0x00000001) {
+ u32 stat = nv_rd32(priv, 0x404000);
+ nv_error(priv, "DISPATCH 0x%08x\n", stat);
+ nv_wr32(priv, 0x404000, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x00000001);
+ trap &= ~0x00000001;
+ }
+
+ if (trap & 0x00000002) {
+ u32 stat = nv_rd32(priv, 0x404600);
+ nv_error(priv, "M2MF 0x%08x\n", stat);
+ nv_wr32(priv, 0x404600, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x00000002);
+ trap &= ~0x00000002;
+ }
+
+ if (trap & 0x00000008) {
+ u32 stat = nv_rd32(priv, 0x408030);
+ nv_error(priv, "CCACHE 0x%08x\n", stat);
+ nv_wr32(priv, 0x408030, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x00000008);
+ trap &= ~0x00000008;
+ }
+
+ if (trap & 0x00000010) {
+ u32 stat = nv_rd32(priv, 0x405840);
+ nv_error(priv, "SHADER 0x%08x\n", stat);
+ nv_wr32(priv, 0x405840, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x00000010);
+ trap &= ~0x00000010;
+ }
+
+ if (trap & 0x00000040) {
+ u32 stat = nv_rd32(priv, 0x40601c);
+ nv_error(priv, "UNK6 0x%08x\n", stat);
+ nv_wr32(priv, 0x40601c, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x00000040);
+ trap &= ~0x00000040;
+ }
+
+ if (trap & 0x00000080) {
+ u32 stat = nv_rd32(priv, 0x404490);
+ nv_error(priv, "MACRO 0x%08x\n", stat);
+ nv_wr32(priv, 0x404490, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x00000080);
+ trap &= ~0x00000080;
+ }
+
+ if (trap & 0x00000100) {
+ u32 stat = nv_rd32(priv, 0x407020);
+
+ nv_error(priv, "SKED:");
+ for (i = 0; i <= 29; ++i) {
+ if (!(stat & (1 << i)))
+ continue;
+ pr_cont(" ");
+ nvkm_enum_print(gk104_sked_error, i);
+ }
+ pr_cont("\n");
+
+ if (stat & 0x3fffffff)
+ nv_wr32(priv, 0x407020, 0x40000000);
+ nv_wr32(priv, 0x400108, 0x00000100);
+ trap &= ~0x00000100;
+ }
+
+ if (trap & 0x01000000) {
+ u32 stat = nv_rd32(priv, 0x400118);
+ for (gpc = 0; stat && gpc < priv->gpc_nr; gpc++) {
+ u32 mask = 0x00000001 << gpc;
+ if (stat & mask) {
+ gf100_gr_trap_gpc(priv, gpc);
+ nv_wr32(priv, 0x400118, mask);
+ stat &= ~mask;
+ }
+ }
+ nv_wr32(priv, 0x400108, 0x01000000);
+ trap &= ~0x01000000;
+ }
+
+ if (trap & 0x02000000) {
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ u32 statz = nv_rd32(priv, ROP_UNIT(rop, 0x070));
+ u32 statc = nv_rd32(priv, ROP_UNIT(rop, 0x144));
+ nv_error(priv, "ROP%d 0x%08x 0x%08x\n",
+ rop, statz, statc);
+ nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+ }
+ nv_wr32(priv, 0x400108, 0x02000000);
+ trap &= ~0x02000000;
+ }
+
+ if (trap) {
+ nv_error(priv, "TRAP UNHANDLED 0x%08x\n", trap);
+ nv_wr32(priv, 0x400108, trap);
+ }
+}
+
+static void
+gf100_gr_ctxctl_debug_unit(struct gf100_gr_priv *priv, u32 base)
+{
+ nv_error(priv, "%06x - done 0x%08x\n", base,
+ nv_rd32(priv, base + 0x400));
+ nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+ nv_rd32(priv, base + 0x800), nv_rd32(priv, base + 0x804),
+ nv_rd32(priv, base + 0x808), nv_rd32(priv, base + 0x80c));
+ nv_error(priv, "%06x - stat 0x%08x 0x%08x 0x%08x 0x%08x\n", base,
+ nv_rd32(priv, base + 0x810), nv_rd32(priv, base + 0x814),
+ nv_rd32(priv, base + 0x818), nv_rd32(priv, base + 0x81c));
+}
+
+void
+gf100_gr_ctxctl_debug(struct gf100_gr_priv *priv)
+{
+ u32 gpcnr = nv_rd32(priv, 0x409604) & 0xffff;
+ u32 gpc;
+
+ gf100_gr_ctxctl_debug_unit(priv, 0x409000);
+ for (gpc = 0; gpc < gpcnr; gpc++)
+ gf100_gr_ctxctl_debug_unit(priv, 0x502000 + (gpc * 0x8000));
+}
+
+static void
+gf100_gr_ctxctl_isr(struct gf100_gr_priv *priv)
+{
+ u32 stat = nv_rd32(priv, 0x409c18);
+
+ if (stat & 0x00000001) {
+ u32 code = nv_rd32(priv, 0x409814);
+ if (code == E_BAD_FWMTHD) {
+ u32 class = nv_rd32(priv, 0x409808);
+ u32 addr = nv_rd32(priv, 0x40980c);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00003ffc);
+ u32 data = nv_rd32(priv, 0x409810);
+
+ nv_error(priv, "FECS MTHD subc %d class 0x%04x "
+ "mthd 0x%04x data 0x%08x\n",
+ subc, class, mthd, data);
+
+ nv_wr32(priv, 0x409c20, 0x00000001);
+ stat &= ~0x00000001;
+ } else {
+ nv_error(priv, "FECS ucode error %d\n", code);
+ }
+ }
+
+ if (stat & 0x00080000) {
+ nv_error(priv, "FECS watchdog timeout\n");
+ gf100_gr_ctxctl_debug(priv);
+ nv_wr32(priv, 0x409c20, 0x00080000);
+ stat &= ~0x00080000;
+ }
+
+ if (stat) {
+ nv_error(priv, "FECS 0x%08x\n", stat);
+ gf100_gr_ctxctl_debug(priv);
+ nv_wr32(priv, 0x409c20, stat);
+ }
+}
+
+static void
+gf100_gr_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct nvkm_handle *handle;
+ struct gf100_gr_priv *priv = (void *)subdev;
+ u64 inst = nv_rd32(priv, 0x409b00) & 0x0fffffff;
+ u32 stat = nv_rd32(priv, 0x400100);
+ u32 addr = nv_rd32(priv, 0x400704);
+ u32 mthd = (addr & 0x00003ffc);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 data = nv_rd32(priv, 0x400708);
+ u32 code = nv_rd32(priv, 0x400110);
+ u32 class = nv_rd32(priv, 0x404200 + (subc * 4));
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat & 0x00000010) {
+ handle = nvkm_handle_get_class(engctx, class);
+ if (!handle || nv_call(handle->object, mthd, data)) {
+ nv_error(priv,
+ "ILLEGAL_MTHD ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst << 12, nvkm_client_name(engctx),
+ subc, class, mthd, data);
+ }
+ nvkm_handle_put(handle);
+ nv_wr32(priv, 0x400100, 0x00000010);
+ stat &= ~0x00000010;
+ }
+
+ if (stat & 0x00000020) {
+ nv_error(priv,
+ "ILLEGAL_CLASS ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst << 12, nvkm_client_name(engctx), subc,
+ class, mthd, data);
+ nv_wr32(priv, 0x400100, 0x00000020);
+ stat &= ~0x00000020;
+ }
+
+ if (stat & 0x00100000) {
+ nv_error(priv, "DATA_ERROR [");
+ nvkm_enum_print(nv50_data_error_names, code);
+ pr_cont("] ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst << 12, nvkm_client_name(engctx), subc,
+ class, mthd, data);
+ nv_wr32(priv, 0x400100, 0x00100000);
+ stat &= ~0x00100000;
+ }
+
+ if (stat & 0x00200000) {
+ nv_error(priv, "TRAP ch %d [0x%010llx %s]\n", chid, inst << 12,
+ nvkm_client_name(engctx));
+ gf100_gr_trap_intr(priv);
+ nv_wr32(priv, 0x400100, 0x00200000);
+ stat &= ~0x00200000;
+ }
+
+ if (stat & 0x00080000) {
+ gf100_gr_ctxctl_isr(priv);
+ nv_wr32(priv, 0x400100, 0x00080000);
+ stat &= ~0x00080000;
+ }
+
+ if (stat) {
+ nv_error(priv, "unknown stat 0x%08x\n", stat);
+ nv_wr32(priv, 0x400100, stat);
+ }
+
+ nv_wr32(priv, 0x400500, 0x00010001);
+ nvkm_engctx_put(engctx);
+}
+
+void
+gf100_gr_init_fw(struct gf100_gr_priv *priv, u32 fuc_base,
+ struct gf100_gr_fuc *code, struct gf100_gr_fuc *data)
+{
+ int i;
+
+ nv_wr32(priv, fuc_base + 0x01c0, 0x01000000);
+ for (i = 0; i < data->size / 4; i++)
+ nv_wr32(priv, fuc_base + 0x01c4, data->data[i]);
+
+ nv_wr32(priv, fuc_base + 0x0180, 0x01000000);
+ for (i = 0; i < code->size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(priv, fuc_base + 0x0188, i >> 6);
+ nv_wr32(priv, fuc_base + 0x0184, code->data[i]);
+ }
+
+ /* code must be padded to 0x40 words */
+ for (; i & 0x3f; i++)
+ nv_wr32(priv, fuc_base + 0x0184, 0);
+}
+
+static void
+gf100_gr_init_csdata(struct gf100_gr_priv *priv,
+ const struct gf100_gr_pack *pack,
+ u32 falcon, u32 starstar, u32 base)
+{
+ const struct gf100_gr_pack *iter;
+ const struct gf100_gr_init *init;
+ u32 addr = ~0, prev = ~0, xfer = 0;
+ u32 star, temp;
+
+ nv_wr32(priv, falcon + 0x01c0, 0x02000000 + starstar);
+ star = nv_rd32(priv, falcon + 0x01c4);
+ temp = nv_rd32(priv, falcon + 0x01c4);
+ if (temp > star)
+ star = temp;
+ nv_wr32(priv, falcon + 0x01c0, 0x01000000 + star);
+
+ pack_for_each_init(init, iter, pack) {
+ u32 head = init->addr - base;
+ u32 tail = head + init->count * init->pitch;
+ while (head < tail) {
+ if (head != prev + 4 || xfer >= 32) {
+ if (xfer) {
+ u32 data = ((--xfer << 26) | addr);
+ nv_wr32(priv, falcon + 0x01c4, data);
+ star += 4;
+ }
+ addr = head;
+ xfer = 0;
+ }
+ prev = head;
+ xfer = xfer + 1;
+ head = head + init->pitch;
+ }
+ }
+
+ nv_wr32(priv, falcon + 0x01c4, (--xfer << 26) | addr);
+ nv_wr32(priv, falcon + 0x01c0, 0x01000004 + starstar);
+ nv_wr32(priv, falcon + 0x01c4, star + 4);
+}
+
+int
+gf100_gr_init_ctxctl(struct gf100_gr_priv *priv)
+{
+ struct gf100_gr_oclass *oclass = (void *)nv_object(priv)->oclass;
+ struct gf100_grctx_oclass *cclass = (void *)nv_engine(priv)->cclass;
+ int i;
+
+ if (priv->firmware) {
+ /* load fuc microcode */
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+ gf100_gr_init_fw(priv, 0x409000, &priv->fuc409c,
+ &priv->fuc409d);
+ gf100_gr_init_fw(priv, 0x41a000, &priv->fuc41ac,
+ &priv->fuc41ad);
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+
+ /* start both of them running */
+ nv_wr32(priv, 0x409840, 0xffffffff);
+ nv_wr32(priv, 0x41a10c, 0x00000000);
+ nv_wr32(priv, 0x40910c, 0x00000000);
+ nv_wr32(priv, 0x41a100, 0x00000002);
+ nv_wr32(priv, 0x409100, 0x00000002);
+ if (!nv_wait(priv, 0x409800, 0x00000001, 0x00000001))
+ nv_warn(priv, "0x409800 wait failed\n");
+
+ nv_wr32(priv, 0x409840, 0xffffffff);
+ nv_wr32(priv, 0x409500, 0x7fffffff);
+ nv_wr32(priv, 0x409504, 0x00000021);
+
+ nv_wr32(priv, 0x409840, 0xffffffff);
+ nv_wr32(priv, 0x409500, 0x00000000);
+ nv_wr32(priv, 0x409504, 0x00000010);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x10 timeout\n");
+ return -EBUSY;
+ }
+ priv->size = nv_rd32(priv, 0x409800);
+
+ nv_wr32(priv, 0x409840, 0xffffffff);
+ nv_wr32(priv, 0x409500, 0x00000000);
+ nv_wr32(priv, 0x409504, 0x00000016);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x16 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409840, 0xffffffff);
+ nv_wr32(priv, 0x409500, 0x00000000);
+ nv_wr32(priv, 0x409504, 0x00000025);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x25 timeout\n");
+ return -EBUSY;
+ }
+
+ if (nv_device(priv)->chipset >= 0xe0) {
+ nv_wr32(priv, 0x409800, 0x00000000);
+ nv_wr32(priv, 0x409500, 0x00000001);
+ nv_wr32(priv, 0x409504, 0x00000030);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x30 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409810, 0xb00095c8);
+ nv_wr32(priv, 0x409800, 0x00000000);
+ nv_wr32(priv, 0x409500, 0x00000001);
+ nv_wr32(priv, 0x409504, 0x00000031);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x31 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409810, 0x00080420);
+ nv_wr32(priv, 0x409800, 0x00000000);
+ nv_wr32(priv, 0x409500, 0x00000001);
+ nv_wr32(priv, 0x409504, 0x00000032);
+ if (!nv_wait_ne(priv, 0x409800, 0xffffffff, 0x00000000)) {
+ nv_error(priv, "fuc09 req 0x32 timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x409614, 0x00000070);
+ nv_wr32(priv, 0x409614, 0x00000770);
+ nv_wr32(priv, 0x40802c, 0x00000001);
+ }
+
+ if (priv->data == NULL) {
+ int ret = gf100_grctx_generate(priv);
+ if (ret) {
+ nv_error(priv, "failed to construct context\n");
+ return ret;
+ }
+ }
+
+ return 0;
+ } else
+ if (!oclass->fecs.ucode) {
+ return -ENOSYS;
+ }
+
+ /* load HUB microcode */
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 0);
+ nv_wr32(priv, 0x4091c0, 0x01000000);
+ for (i = 0; i < oclass->fecs.ucode->data.size / 4; i++)
+ nv_wr32(priv, 0x4091c4, oclass->fecs.ucode->data.data[i]);
+
+ nv_wr32(priv, 0x409180, 0x01000000);
+ for (i = 0; i < oclass->fecs.ucode->code.size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(priv, 0x409188, i >> 6);
+ nv_wr32(priv, 0x409184, oclass->fecs.ucode->code.data[i]);
+ }
+
+ /* load GPC microcode */
+ nv_wr32(priv, 0x41a1c0, 0x01000000);
+ for (i = 0; i < oclass->gpccs.ucode->data.size / 4; i++)
+ nv_wr32(priv, 0x41a1c4, oclass->gpccs.ucode->data.data[i]);
+
+ nv_wr32(priv, 0x41a180, 0x01000000);
+ for (i = 0; i < oclass->gpccs.ucode->code.size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(priv, 0x41a188, i >> 6);
+ nv_wr32(priv, 0x41a184, oclass->gpccs.ucode->code.data[i]);
+ }
+ nvkm_mc(priv)->unk260(nvkm_mc(priv), 1);
+
+ /* load register lists */
+ gf100_gr_init_csdata(priv, cclass->hub, 0x409000, 0x000, 0x000000);
+ gf100_gr_init_csdata(priv, cclass->gpc, 0x41a000, 0x000, 0x418000);
+ gf100_gr_init_csdata(priv, cclass->tpc, 0x41a000, 0x004, 0x419800);
+ gf100_gr_init_csdata(priv, cclass->ppc, 0x41a000, 0x008, 0x41be00);
+
+ /* start HUB ucode running, it'll init the GPCs */
+ nv_wr32(priv, 0x40910c, 0x00000000);
+ nv_wr32(priv, 0x409100, 0x00000002);
+ if (!nv_wait(priv, 0x409800, 0x80000000, 0x80000000)) {
+ nv_error(priv, "HUB_INIT timed out\n");
+ gf100_gr_ctxctl_debug(priv);
+ return -EBUSY;
+ }
+
+ priv->size = nv_rd32(priv, 0x409804);
+ if (priv->data == NULL) {
+ int ret = gf100_grctx_generate(priv);
+ if (ret) {
+ nv_error(priv, "failed to construct context\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+gf100_gr_init(struct nvkm_object *object)
+{
+ struct gf100_gr_oclass *oclass = (void *)object->oclass;
+ struct gf100_gr_priv *priv = (void *)object;
+ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+ u32 data[TPC_MAX / 8] = {};
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc, rop;
+ int ret, i;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+ nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+ gf100_gr_mmio(priv, oclass->mmio);
+
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+ priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+ priv->tpc_total);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+ }
+
+ if (nv_device(priv)->chipset != 0xd7)
+ nv_wr32(priv, GPC_BCAST(0x1bd4), magicgpc918);
+ else
+ nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+
+ nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+ nv_wr32(priv, 0x400500, 0x00010001);
+
+ nv_wr32(priv, 0x400100, 0xffffffff);
+ nv_wr32(priv, 0x40013c, 0xffffffff);
+
+ nv_wr32(priv, 0x409c24, 0x000f0000);
+ nv_wr32(priv, 0x404000, 0xc0000000);
+ nv_wr32(priv, 0x404600, 0xc0000000);
+ nv_wr32(priv, 0x408030, 0xc0000000);
+ nv_wr32(priv, 0x40601c, 0xc0000000);
+ nv_wr32(priv, 0x404490, 0xc0000000);
+ nv_wr32(priv, 0x406018, 0xc0000000);
+ nv_wr32(priv, 0x405840, 0xc0000000);
+ nv_wr32(priv, 0x405844, 0x00ffffff);
+ nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+ nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+ }
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+
+ nv_wr32(priv, 0x400108, 0xffffffff);
+ nv_wr32(priv, 0x400138, 0xffffffff);
+ nv_wr32(priv, 0x400118, 0xffffffff);
+ nv_wr32(priv, 0x400130, 0xffffffff);
+ nv_wr32(priv, 0x40011c, 0xffffffff);
+ nv_wr32(priv, 0x400134, 0xffffffff);
+
+ nv_wr32(priv, 0x400054, 0x34ce3464);
+
+ gf100_gr_zbc_init(priv);
+
+ return gf100_gr_init_ctxctl(priv);
+}
+
+static void
+gf100_gr_dtor_fw(struct gf100_gr_fuc *fuc)
+{
+ kfree(fuc->data);
+ fuc->data = NULL;
+}
+
+int
+gf100_gr_ctor_fw(struct gf100_gr_priv *priv, const char *fwname,
+ struct gf100_gr_fuc *fuc)
+{
+ struct nvkm_device *device = nv_device(priv);
+ const struct firmware *fw;
+ char f[32];
+ int ret;
+
+ snprintf(f, sizeof(f), "nouveau/nv%02x_%s", device->chipset, fwname);
+ ret = request_firmware(&fw, f, nv_device_base(device));
+ if (ret) {
+ snprintf(f, sizeof(f), "nouveau/%s", fwname);
+ ret = request_firmware(&fw, f, nv_device_base(device));
+ if (ret) {
+ nv_error(priv, "failed to load %s\n", fwname);
+ return ret;
+ }
+ }
+
+ fuc->size = fw->size;
+ fuc->data = kmemdup(fw->data, fuc->size, GFP_KERNEL);
+ release_firmware(fw);
+ return (fuc->data != NULL) ? 0 : -ENOMEM;
+}
+
+void
+gf100_gr_dtor(struct nvkm_object *object)
+{
+ struct gf100_gr_priv *priv = (void *)object;
+
+ kfree(priv->data);
+
+ gf100_gr_dtor_fw(&priv->fuc409c);
+ gf100_gr_dtor_fw(&priv->fuc409d);
+ gf100_gr_dtor_fw(&priv->fuc41ac);
+ gf100_gr_dtor_fw(&priv->fuc41ad);
+
+ nvkm_gpuobj_ref(NULL, &priv->unk4188b8);
+ nvkm_gpuobj_ref(NULL, &priv->unk4188b4);
+
+ nvkm_gr_destroy(&priv->base);
+}
+
+int
+gf100_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *bclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_gr_oclass *oclass = (void *)bclass;
+ struct nvkm_device *device = nv_device(parent);
+ struct gf100_gr_priv *priv;
+ bool use_ext_fw, enable;
+ int ret, i, j;
+
+ use_ext_fw = nvkm_boolopt(device->cfgopt, "NvGrUseFW",
+ oclass->fecs.ucode == NULL);
+ enable = use_ext_fw || oclass->fecs.ucode != NULL;
+
+ ret = nvkm_gr_create(parent, engine, bclass, enable, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x08001000;
+ nv_subdev(priv)->intr = gf100_gr_intr;
+
+ priv->base.units = gf100_gr_units;
+
+ if (use_ext_fw) {
+ nv_info(priv, "using external firmware\n");
+ if (gf100_gr_ctor_fw(priv, "fuc409c", &priv->fuc409c) ||
+ gf100_gr_ctor_fw(priv, "fuc409d", &priv->fuc409d) ||
+ gf100_gr_ctor_fw(priv, "fuc41ac", &priv->fuc41ac) ||
+ gf100_gr_ctor_fw(priv, "fuc41ad", &priv->fuc41ad))
+ return -ENODEV;
+ priv->firmware = true;
+ }
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
+ &priv->unk4188b4);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 256, 0,
+ &priv->unk4188b8);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < 0x1000; i += 4) {
+ nv_wo32(priv->unk4188b4, i, 0x00000010);
+ nv_wo32(priv->unk4188b8, i, 0x00000010);
+ }
+
+ priv->rop_nr = (nv_rd32(priv, 0x409604) & 0x001f0000) >> 16;
+ priv->gpc_nr = nv_rd32(priv, 0x409604) & 0x0000001f;
+ for (i = 0; i < priv->gpc_nr; i++) {
+ priv->tpc_nr[i] = nv_rd32(priv, GPC_UNIT(i, 0x2608));
+ priv->tpc_total += priv->tpc_nr[i];
+ priv->ppc_nr[i] = oclass->ppc_nr;
+ for (j = 0; j < priv->ppc_nr[i]; j++) {
+ u8 mask = nv_rd32(priv, GPC_UNIT(i, 0x0c30 + (j * 4)));
+ priv->ppc_tpc_nr[i][j] = hweight8(mask);
+ }
+ }
+
+ /*XXX: these need figuring out... though it might not even matter */
+ switch (nv_device(priv)->chipset) {
+ case 0xc0:
+ if (priv->tpc_total == 11) { /* 465, 3/4/4/0, 4 */
+ priv->magic_not_rop_nr = 0x07;
+ } else
+ if (priv->tpc_total == 14) { /* 470, 3/3/4/4, 5 */
+ priv->magic_not_rop_nr = 0x05;
+ } else
+ if (priv->tpc_total == 15) { /* 480, 3/4/4/4, 6 */
+ priv->magic_not_rop_nr = 0x06;
+ }
+ break;
+ case 0xc3: /* 450, 4/0/0/0, 2 */
+ priv->magic_not_rop_nr = 0x03;
+ break;
+ case 0xc4: /* 460, 3/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x01;
+ break;
+ case 0xc1: /* 2/0/0/0, 1 */
+ priv->magic_not_rop_nr = 0x01;
+ break;
+ case 0xc8: /* 4/4/3/4, 5 */
+ priv->magic_not_rop_nr = 0x06;
+ break;
+ case 0xce: /* 4/4/0/0, 4 */
+ priv->magic_not_rop_nr = 0x03;
+ break;
+ case 0xcf: /* 4/0/0/0, 3 */
+ priv->magic_not_rop_nr = 0x03;
+ break;
+ case 0xd7:
+ case 0xd9: /* 1/0/0/0, 1 */
+ priv->magic_not_rop_nr = 0x01;
+ break;
+ }
+
+ nv_engine(priv)->cclass = *oclass->cclass;
+ nv_engine(priv)->sclass = oclass->sclass;
+ return 0;
+}
+
+#include "fuc/hubgf100.fuc3.h"
+
+struct gf100_gr_ucode
+gf100_gr_fecs_ucode = {
+ .code.data = gf100_grhub_code,
+ .code.size = sizeof(gf100_grhub_code),
+ .data.data = gf100_grhub_data,
+ .data.size = sizeof(gf100_grhub_data),
+};
+
+#include "fuc/gpcgf100.fuc3.h"
+
+struct gf100_gr_ucode
+gf100_gr_gpccs_ucode = {
+ .code.data = gf100_grgpc_code,
+ .code.size = sizeof(gf100_grgpc_code),
+ .data.data = gf100_grgpc_data,
+ .data.size = sizeof(gf100_grgpc_data),
+};
+
+struct nvkm_oclass *
+gf100_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gf100_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gf100_grctx_oclass,
+ .sclass = gf100_gr_sclass,
+ .mmio = gf100_gr_pack_mmio,
+ .fecs.ucode = &gf100_gr_fecs_ucode,
+ .gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
new file mode 100644
index 000000000000..aeeca1be9cf0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf100.h
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#ifndef __NVC0_GR_H__
+#define __NVC0_GR_H__
+#include <engine/gr.h>
+
+#include <subdev/ltc.h>
+
+#define GPC_MAX 32
+#define TPC_MAX (GPC_MAX * 8)
+
+#define ROP_BCAST(r) (0x408800 + (r))
+#define ROP_UNIT(u, r) (0x410000 + (u) * 0x400 + (r))
+#define GPC_BCAST(r) (0x418000 + (r))
+#define GPC_UNIT(t, r) (0x500000 + (t) * 0x8000 + (r))
+#define PPC_UNIT(t, m, r) (0x503000 + (t) * 0x8000 + (m) * 0x200 + (r))
+#define TPC_UNIT(t, m, r) (0x504000 + (t) * 0x8000 + (m) * 0x800 + (r))
+
+struct gf100_gr_data {
+ u32 size;
+ u32 align;
+ u32 access;
+};
+
+struct gf100_gr_mmio {
+ u32 addr;
+ u32 data;
+ u32 shift;
+ int buffer;
+};
+
+struct gf100_gr_fuc {
+ u32 *data;
+ u32 size;
+};
+
+struct gf100_gr_zbc_color {
+ u32 format;
+ u32 ds[4];
+ u32 l2[4];
+};
+
+struct gf100_gr_zbc_depth {
+ u32 format;
+ u32 ds;
+ u32 l2;
+};
+
+struct gf100_gr_priv {
+ struct nvkm_gr base;
+
+ struct gf100_gr_fuc fuc409c;
+ struct gf100_gr_fuc fuc409d;
+ struct gf100_gr_fuc fuc41ac;
+ struct gf100_gr_fuc fuc41ad;
+ bool firmware;
+
+ struct gf100_gr_zbc_color zbc_color[NVKM_LTC_MAX_ZBC_CNT];
+ struct gf100_gr_zbc_depth zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
+
+ u8 rop_nr;
+ u8 gpc_nr;
+ u8 tpc_nr[GPC_MAX];
+ u8 tpc_total;
+ u8 ppc_nr[GPC_MAX];
+ u8 ppc_tpc_nr[GPC_MAX][4];
+
+ struct nvkm_gpuobj *unk4188b4;
+ struct nvkm_gpuobj *unk4188b8;
+
+ struct gf100_gr_data mmio_data[4];
+ struct gf100_gr_mmio mmio_list[4096/8];
+ u32 size;
+ u32 *data;
+
+ u8 magic_not_rop_nr;
+};
+
+struct gf100_gr_chan {
+ struct nvkm_gr_chan base;
+
+ struct nvkm_gpuobj *mmio;
+ struct nvkm_vma mmio_vma;
+ int mmio_nr;
+ struct {
+ struct nvkm_gpuobj *mem;
+ struct nvkm_vma vma;
+ } data[4];
+};
+
+int gf100_gr_context_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void gf100_gr_context_dtor(struct nvkm_object *);
+
+void gf100_gr_ctxctl_debug(struct gf100_gr_priv *);
+
+u64 gf100_gr_units(struct nvkm_gr *);
+int gf100_gr_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *data, u32 size,
+ struct nvkm_object **);
+void gf100_gr_dtor(struct nvkm_object *);
+int gf100_gr_init(struct nvkm_object *);
+void gf100_gr_zbc_init(struct gf100_gr_priv *);
+
+int gk104_gr_fini(struct nvkm_object *, bool);
+int gk104_gr_init(struct nvkm_object *);
+
+int gk110_gr_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_ofuncs gf100_fermi_ofuncs;
+
+extern struct nvkm_oclass gf100_gr_sclass[];
+extern struct nvkm_omthds gf100_gr_9097_omthds[];
+extern struct nvkm_omthds gf100_gr_90c0_omthds[];
+extern struct nvkm_oclass gf110_gr_sclass[];
+extern struct nvkm_oclass gk110_gr_sclass[];
+
+struct gf100_gr_init {
+ u32 addr;
+ u8 count;
+ u8 pitch;
+ u32 data;
+};
+
+struct gf100_gr_pack {
+ const struct gf100_gr_init *init;
+ u32 type;
+};
+
+#define pack_for_each_init(init, pack, head) \
+ for (pack = head; pack && pack->init; pack++) \
+ for (init = pack->init; init && init->count; init++)
+
+struct gf100_gr_ucode {
+ struct gf100_gr_fuc code;
+ struct gf100_gr_fuc data;
+};
+
+extern struct gf100_gr_ucode gf100_gr_fecs_ucode;
+extern struct gf100_gr_ucode gf100_gr_gpccs_ucode;
+
+extern struct gf100_gr_ucode gk110_gr_fecs_ucode;
+extern struct gf100_gr_ucode gk110_gr_gpccs_ucode;
+
+struct gf100_gr_oclass {
+ struct nvkm_oclass base;
+ struct nvkm_oclass **cclass;
+ struct nvkm_oclass *sclass;
+ const struct gf100_gr_pack *mmio;
+ struct {
+ struct gf100_gr_ucode *ucode;
+ } fecs;
+ struct {
+ struct gf100_gr_ucode *ucode;
+ } gpccs;
+ int ppc_nr;
+};
+
+void gf100_gr_mmio(struct gf100_gr_priv *, const struct gf100_gr_pack *);
+void gf100_gr_icmd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
+void gf100_gr_mthd(struct gf100_gr_priv *, const struct gf100_gr_pack *);
+int gf100_gr_init_ctxctl(struct gf100_gr_priv *);
+
+/* register init value lists */
+
+extern const struct gf100_gr_init gf100_gr_init_main_0[];
+extern const struct gf100_gr_init gf100_gr_init_fe_0[];
+extern const struct gf100_gr_init gf100_gr_init_pri_0[];
+extern const struct gf100_gr_init gf100_gr_init_rstr2d_0[];
+extern const struct gf100_gr_init gf100_gr_init_pd_0[];
+extern const struct gf100_gr_init gf100_gr_init_ds_0[];
+extern const struct gf100_gr_init gf100_gr_init_scc_0[];
+extern const struct gf100_gr_init gf100_gr_init_prop_0[];
+extern const struct gf100_gr_init gf100_gr_init_gpc_unk_0[];
+extern const struct gf100_gr_init gf100_gr_init_setup_0[];
+extern const struct gf100_gr_init gf100_gr_init_crstr_0[];
+extern const struct gf100_gr_init gf100_gr_init_setup_1[];
+extern const struct gf100_gr_init gf100_gr_init_zcull_0[];
+extern const struct gf100_gr_init gf100_gr_init_gpm_0[];
+extern const struct gf100_gr_init gf100_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf100_gr_init_gcc_0[];
+extern const struct gf100_gr_init gf100_gr_init_tpccs_0[];
+extern const struct gf100_gr_init gf100_gr_init_tex_0[];
+extern const struct gf100_gr_init gf100_gr_init_pe_0[];
+extern const struct gf100_gr_init gf100_gr_init_l1c_0[];
+extern const struct gf100_gr_init gf100_gr_init_wwdx_0[];
+extern const struct gf100_gr_init gf100_gr_init_tpccs_1[];
+extern const struct gf100_gr_init gf100_gr_init_mpc_0[];
+extern const struct gf100_gr_init gf100_gr_init_be_0[];
+extern const struct gf100_gr_init gf100_gr_init_fe_1[];
+extern const struct gf100_gr_init gf100_gr_init_pe_1[];
+
+extern const struct gf100_gr_init gf104_gr_init_ds_0[];
+extern const struct gf100_gr_init gf104_gr_init_tex_0[];
+extern const struct gf100_gr_init gf104_gr_init_sm_0[];
+
+extern const struct gf100_gr_init gf108_gr_init_gpc_unk_0[];
+extern const struct gf100_gr_init gf108_gr_init_setup_1[];
+
+extern const struct gf100_gr_init gf119_gr_init_pd_0[];
+extern const struct gf100_gr_init gf119_gr_init_ds_0[];
+extern const struct gf100_gr_init gf119_gr_init_prop_0[];
+extern const struct gf100_gr_init gf119_gr_init_gpm_0[];
+extern const struct gf100_gr_init gf119_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gf119_gr_init_tex_0[];
+extern const struct gf100_gr_init gf119_gr_init_sm_0[];
+extern const struct gf100_gr_init gf119_gr_init_fe_1[];
+
+extern const struct gf100_gr_init gf117_gr_init_pes_0[];
+extern const struct gf100_gr_init gf117_gr_init_wwdx_0[];
+extern const struct gf100_gr_init gf117_gr_init_cbm_0[];
+
+extern const struct gf100_gr_init gk104_gr_init_main_0[];
+extern const struct gf100_gr_init gk104_gr_init_tpccs_0[];
+extern const struct gf100_gr_init gk104_gr_init_pe_0[];
+extern const struct gf100_gr_init gk104_gr_init_be_0[];
+extern const struct gf100_gr_pack gk104_gr_pack_mmio[];
+
+extern const struct gf100_gr_init gk110_gr_init_fe_0[];
+extern const struct gf100_gr_init gk110_gr_init_ds_0[];
+extern const struct gf100_gr_init gk110_gr_init_sked_0[];
+extern const struct gf100_gr_init gk110_gr_init_cwd_0[];
+extern const struct gf100_gr_init gk110_gr_init_gpc_unk_1[];
+extern const struct gf100_gr_init gk110_gr_init_tex_0[];
+extern const struct gf100_gr_init gk110_gr_init_sm_0[];
+
+extern const struct gf100_gr_init gk208_gr_init_gpc_unk_0[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
new file mode 100644
index 000000000000..20d3b85db3b5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf104.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf104_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x00002834 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf104_gr_init_tex_0[] = {
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf104_gr_init_pe_0[] = {
+ { 0x41980c, 3, 0x04, 0x00000000 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419880, 1, 0x04, 0x00000002 },
+ {}
+};
+
+const struct gf100_gr_init
+gf104_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0e063818 },
+ { 0x419ecc, 1, 0x04, 0x0e060e06 },
+ { 0x419ed0, 1, 0x04, 0x00003818 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf104_gr_pack_mmio[] = {
+ { gf100_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf100_gr_init_pd_0 },
+ { gf104_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gf100_gr_init_prop_0 },
+ { gf100_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf100_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf100_gr_init_gpm_0 },
+ { gf100_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gf100_gr_init_tpccs_0 },
+ { gf104_gr_init_tex_0 },
+ { gf104_gr_init_pe_0 },
+ { gf100_gr_init_l1c_0 },
+ { gf100_gr_init_wwdx_0 },
+ { gf100_gr_init_tpccs_1 },
+ { gf100_gr_init_mpc_0 },
+ { gf104_gr_init_sm_0 },
+ { gf100_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf104_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc3),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gf100_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gf104_grctx_oclass,
+ .sclass = gf100_gr_sclass,
+ .mmio = gf104_gr_pack_mmio,
+ .fecs.ucode = &gf100_gr_fecs_ucode,
+ .gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
new file mode 100644
index 000000000000..5362c8176e64
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf108.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf108_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0x9039, &nvkm_object_ofuncs },
+ { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf108_gr_init_gpc_unk_0[] = {
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf108_gr_init_setup_1[] = {
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000001 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_gr_init_gpc_unk_1[] = {
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000003 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf108_gr_init_pe_0[] = {
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419810, 1, 0x04, 0x00000000 },
+ { 0x419814, 1, 0x04, 0x00000004 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc5 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419880, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf108_gr_pack_mmio[] = {
+ { gf100_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf100_gr_init_pd_0 },
+ { gf104_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gf100_gr_init_prop_0 },
+ { gf108_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf100_gr_init_gpm_0 },
+ { gf108_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gf100_gr_init_tpccs_0 },
+ { gf104_gr_init_tex_0 },
+ { gf108_gr_init_pe_0 },
+ { gf100_gr_init_l1c_0 },
+ { gf100_gr_init_wwdx_0 },
+ { gf100_gr_init_tpccs_1 },
+ { gf100_gr_init_mpc_0 },
+ { gf104_gr_init_sm_0 },
+ { gf100_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf108_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc1),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gf100_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gf108_grctx_oclass,
+ .sclass = gf108_gr_sclass,
+ .mmio = gf108_gr_pack_mmio,
+ .fecs.ucode = &gf100_gr_fecs_ucode,
+ .gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
new file mode 100644
index 000000000000..88beb491b7b8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf110.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+gf110_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0x9039, &nvkm_object_ofuncs },
+ { FERMI_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { FERMI_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { FERMI_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { FERMI_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf110_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00001100 },
+ { 0x419eac, 1, 0x04, 0x11100f02 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x06060618 },
+ { 0x419ed0, 1, 0x04, 0x0eff0e38 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf110_gr_pack_mmio[] = {
+ { gf100_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf100_gr_init_pd_0 },
+ { gf100_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gf100_gr_init_prop_0 },
+ { gf100_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf100_gr_init_gpm_0 },
+ { gf100_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gf100_gr_init_tpccs_0 },
+ { gf100_gr_init_tex_0 },
+ { gf100_gr_init_pe_0 },
+ { gf100_gr_init_l1c_0 },
+ { gf100_gr_init_wwdx_0 },
+ { gf100_gr_init_tpccs_1 },
+ { gf100_gr_init_mpc_0 },
+ { gf110_gr_init_sm_0 },
+ { gf100_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ { gf100_gr_init_pe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf110_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xc8),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gf100_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gf110_grctx_oclass,
+ .sclass = gf110_gr_sclass,
+ .mmio = gf110_gr_pack_mmio,
+ .fecs.ucode = &gf100_gr_fecs_ucode,
+ .gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
new file mode 100644
index 000000000000..871ac5f806f6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf117.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gf117_gr_init_pe_0[] = {
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x00005bc8 },
+ { 0x419850, 3, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf117_gr_init_pes_0[] = {
+ { 0x41be04, 1, 0x04, 0x00000000 },
+ { 0x41be08, 1, 0x04, 0x00000004 },
+ { 0x41be0c, 1, 0x04, 0x00000000 },
+ { 0x41be10, 1, 0x04, 0x003b8bc7 },
+ { 0x41be14, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf117_gr_init_wwdx_0[] = {
+ { 0x41bfd4, 1, 0x04, 0x00800000 },
+ { 0x41bfdc, 1, 0x04, 0x00000000 },
+ { 0x41bff8, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf117_gr_init_cbm_0[] = {
+ { 0x41becc, 1, 0x04, 0x00000000 },
+ { 0x41bee8, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf117_gr_pack_mmio[] = {
+ { gf100_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf119_gr_init_pd_0 },
+ { gf119_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gf119_gr_init_prop_0 },
+ { gf108_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf119_gr_init_gpm_0 },
+ { gf119_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gf100_gr_init_tpccs_0 },
+ { gf119_gr_init_tex_0 },
+ { gf117_gr_init_pe_0 },
+ { gf100_gr_init_l1c_0 },
+ { gf100_gr_init_mpc_0 },
+ { gf119_gr_init_sm_0 },
+ { gf117_gr_init_pes_0 },
+ { gf117_gr_init_wwdx_0 },
+ { gf117_gr_init_cbm_0 },
+ { gf100_gr_init_be_0 },
+ { gf119_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+#include "fuc/hubgf117.fuc3.h"
+
+struct gf100_gr_ucode
+gf117_gr_fecs_ucode = {
+ .code.data = gf117_grhub_code,
+ .code.size = sizeof(gf117_grhub_code),
+ .data.data = gf117_grhub_data,
+ .data.size = sizeof(gf117_grhub_data),
+};
+
+#include "fuc/gpcgf117.fuc3.h"
+
+struct gf100_gr_ucode
+gf117_gr_gpccs_ucode = {
+ .code.data = gf117_grgpc_code,
+ .code.size = sizeof(gf117_grgpc_code),
+ .data.data = gf117_grgpc_data,
+ .data.size = sizeof(gf117_grgpc_data),
+};
+
+struct nvkm_oclass *
+gf117_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xd7),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gf100_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gf117_grctx_oclass,
+ .sclass = gf110_gr_sclass,
+ .mmio = gf117_gr_pack_mmio,
+ .fecs.ucode = &gf117_gr_fecs_ucode,
+ .gpccs.ucode = &gf117_gr_gpccs_ucode,
+ .ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
new file mode 100644
index 000000000000..e6dd651e2636
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gf119.c
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gf119_gr_init_pd_0[] = {
+ { 0x406024, 1, 0x04, 0x00000000 },
+ { 0x4064f0, 3, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x00002834 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_prop_0[] = {
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x4184a0, 3, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_gpm_0[] = {
+ { 0x418c04, 1, 0x04, 0x00000000 },
+ { 0x418c64, 2, 0x04, 0x00000000 },
+ { 0x418c88, 1, 0x04, 0x00000000 },
+ { 0x418cb4, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_gpc_unk_1[] = {
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 2, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 2, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000003 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_tex_0[] = {
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_gr_init_pe_0[] = {
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419810, 1, 0x04, 0x00000000 },
+ { 0x419814, 1, 0x04, 0x00000004 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x41984c, 1, 0x04, 0x0000a918 },
+ { 0x419850, 4, 0x04, 0x00000000 },
+ { 0x419880, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_gr_init_wwdx_0[] = {
+ { 0x419bd4, 1, 0x04, 0x00800000 },
+ { 0x419bdc, 1, 0x04, 0x00000000 },
+ { 0x419bf8, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gf119_gr_init_tpccs_1[] = {
+ { 0x419d2c, 1, 0x04, 0x00000000 },
+ { 0x419d48, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x02001100 },
+ { 0x419eac, 1, 0x04, 0x11100702 },
+ { 0x419eb0, 1, 0x04, 0x00000003 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419ec8, 1, 0x04, 0x0e063818 },
+ { 0x419ecc, 1, 0x04, 0x0e060e06 },
+ { 0x419ed0, 1, 0x04, 0x00003818 },
+ { 0x419ed4, 1, 0x04, 0x011104f1 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f2c, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gf119_gr_init_fe_1[] = {
+ { 0x40402c, 1, 0x04, 0x00000000 },
+ { 0x4040f0, 1, 0x04, 0x00000000 },
+ { 0x404174, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gf119_gr_pack_mmio[] = {
+ { gf100_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf119_gr_init_pd_0 },
+ { gf119_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gf119_gr_init_prop_0 },
+ { gf108_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf119_gr_init_gpm_0 },
+ { gf119_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gf100_gr_init_tpccs_0 },
+ { gf119_gr_init_tex_0 },
+ { gf119_gr_init_pe_0 },
+ { gf100_gr_init_l1c_0 },
+ { gf119_gr_init_wwdx_0 },
+ { gf119_gr_init_tpccs_1 },
+ { gf100_gr_init_mpc_0 },
+ { gf119_gr_init_sm_0 },
+ { gf100_gr_init_be_0 },
+ { gf119_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf119_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xd9),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gf100_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gf119_grctx_oclass,
+ .sclass = gf110_gr_sclass,
+ .mmio = gf119_gr_pack_mmio,
+ .fecs.ucode = &gf100_gr_fecs_ucode,
+ .gpccs.ucode = &gf100_gr_gpccs_ucode,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
new file mode 100644
index 000000000000..489fdd94b885
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk104.c
@@ -0,0 +1,348 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/pmu.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0xa040, &nvkm_object_ofuncs },
+ { KEPLER_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gk104_gr_init_main_0[] = {
+ { 0x400080, 1, 0x04, 0x003083c2 },
+ { 0x400088, 1, 0x04, 0x0001ffe7 },
+ { 0x40008c, 1, 0x04, 0x00000000 },
+ { 0x400090, 1, 0x04, 0x00000030 },
+ { 0x40013c, 1, 0x04, 0x003901f7 },
+ { 0x400140, 1, 0x04, 0x00000100 },
+ { 0x400144, 1, 0x04, 0x00000000 },
+ { 0x400148, 1, 0x04, 0x00000110 },
+ { 0x400138, 1, 0x04, 0x00000000 },
+ { 0x400130, 2, 0x04, 0x00000000 },
+ { 0x400124, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x0000ff34 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_sked_0[] = {
+ { 0x407010, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_cwd_0[] = {
+ { 0x405b50, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_gpc_unk_1[] = {
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 2, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000000 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 2, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000060 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_gr_init_tpccs_0[] = {
+ { 0x419d0c, 1, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_gr_init_pe_0[] = {
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x419850, 1, 0x04, 0x00000004 },
+ { 0x419854, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_l1c_0[] = {
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x01000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00b08bea },
+ { 0x419c84, 1, 0x04, 0x00010384 },
+ { 0x419cbc, 1, 0x04, 0x28137646 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x00020232 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk104_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ee4, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00000000 },
+ { 0x419eb4, 4, 0x04, 0x00000000 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419f74, 1, 0x04, 0x00000555 },
+ {}
+};
+
+const struct gf100_gr_init
+gk104_gr_init_be_0[] = {
+ { 0x40880c, 1, 0x04, 0x00000000 },
+ { 0x408850, 1, 0x04, 0x00000004 },
+ { 0x408910, 9, 0x04, 0x00000000 },
+ { 0x408950, 1, 0x04, 0x00000000 },
+ { 0x408954, 1, 0x04, 0x0000ffff },
+ { 0x408958, 1, 0x04, 0x00000034 },
+ { 0x408984, 1, 0x04, 0x00000000 },
+ { 0x408988, 1, 0x04, 0x08040201 },
+ { 0x40898c, 1, 0x04, 0x80402010 },
+ {}
+};
+
+const struct gf100_gr_pack
+gk104_gr_pack_mmio[] = {
+ { gk104_gr_init_main_0 },
+ { gf100_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf119_gr_init_pd_0 },
+ { gk104_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gk104_gr_init_sked_0 },
+ { gk104_gr_init_cwd_0 },
+ { gf119_gr_init_prop_0 },
+ { gf108_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf119_gr_init_gpm_0 },
+ { gk104_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gk104_gr_init_tpccs_0 },
+ { gf119_gr_init_tex_0 },
+ { gk104_gr_init_pe_0 },
+ { gk104_gr_init_l1c_0 },
+ { gf100_gr_init_mpc_0 },
+ { gk104_gr_init_sm_0 },
+ { gf117_gr_init_pes_0 },
+ { gf117_gr_init_wwdx_0 },
+ { gf117_gr_init_cbm_0 },
+ { gk104_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+int
+gk104_gr_init(struct nvkm_object *object)
+{
+ struct gf100_gr_oclass *oclass = (void *)object->oclass;
+ struct gf100_gr_priv *priv = (void *)object;
+ struct nvkm_pmu *pmu = nvkm_pmu(priv);
+ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+ u32 data[TPC_MAX / 8] = {};
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc, rop;
+ int ret, i;
+
+ if (pmu)
+ pmu->pgob(pmu, false);
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08a4), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0888), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x088c), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+ nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+ gf100_gr_mmio(priv, oclass->mmio);
+
+ nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+ memset(data, 0x00, sizeof(data));
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+ priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+ priv->tpc_total);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+ nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+ nv_wr32(priv, 0x400500, 0x00010001);
+
+ nv_wr32(priv, 0x400100, 0xffffffff);
+ nv_wr32(priv, 0x40013c, 0xffffffff);
+
+ nv_wr32(priv, 0x409ffc, 0x00000000);
+ nv_wr32(priv, 0x409c14, 0x00003e3e);
+ nv_wr32(priv, 0x409c24, 0x000f0001);
+ nv_wr32(priv, 0x404000, 0xc0000000);
+ nv_wr32(priv, 0x404600, 0xc0000000);
+ nv_wr32(priv, 0x408030, 0xc0000000);
+ nv_wr32(priv, 0x404490, 0xc0000000);
+ nv_wr32(priv, 0x406018, 0xc0000000);
+ nv_wr32(priv, 0x407020, 0x40000000);
+ nv_wr32(priv, 0x405840, 0xc0000000);
+ nv_wr32(priv, 0x405844, 0x00ffffff);
+ nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+ nv_mask(priv, 0x419eb4, 0x00001000, 0x00001000);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x3038), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x001ffffe);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x0000000f);
+ }
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(priv, ROP_UNIT(rop, 0x144), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x070), 0xc0000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+
+ nv_wr32(priv, 0x400108, 0xffffffff);
+ nv_wr32(priv, 0x400138, 0xffffffff);
+ nv_wr32(priv, 0x400118, 0xffffffff);
+ nv_wr32(priv, 0x400130, 0xffffffff);
+ nv_wr32(priv, 0x40011c, 0xffffffff);
+ nv_wr32(priv, 0x400134, 0xffffffff);
+
+ nv_wr32(priv, 0x400054, 0x34ce3464);
+
+ gf100_gr_zbc_init(priv);
+
+ return gf100_gr_init_ctxctl(priv);
+}
+
+#include "fuc/hubgk104.fuc3.h"
+
+static struct gf100_gr_ucode
+gk104_gr_fecs_ucode = {
+ .code.data = gk104_grhub_code,
+ .code.size = sizeof(gk104_grhub_code),
+ .data.data = gk104_grhub_data,
+ .data.size = sizeof(gk104_grhub_data),
+};
+
+#include "fuc/gpcgk104.fuc3.h"
+
+static struct gf100_gr_ucode
+gk104_gr_gpccs_ucode = {
+ .code.data = gk104_grgpc_code,
+ .code.size = sizeof(gk104_grgpc_code),
+ .data.data = gk104_grgpc_data,
+ .data.size = sizeof(gk104_grgpc_data),
+};
+
+struct nvkm_oclass *
+gk104_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xe4),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gk104_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gk104_grctx_oclass,
+ .sclass = gk104_gr_sclass,
+ .mmio = gk104_gr_pack_mmio,
+ .fecs.ucode = &gk104_gr_fecs_ucode,
+ .gpccs.ucode = &gk104_gr_gpccs_ucode,
+ .ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
new file mode 100644
index 000000000000..78e03ab1608e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110.c
@@ -0,0 +1,248 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+gk110_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0xa140, &nvkm_object_ofuncs },
+ { KEPLER_B, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { KEPLER_COMPUTE_B, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+const struct gf100_gr_init
+gk110_gr_init_fe_0[] = {
+ { 0x40415c, 1, 0x04, 0x00000000 },
+ { 0x404170, 1, 0x04, 0x00000000 },
+ { 0x4041b4, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x0000ff00 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_sked_0[] = {
+ { 0x407010, 1, 0x04, 0x00000000 },
+ { 0x407040, 1, 0x04, 0x80440424 },
+ { 0x407048, 1, 0x04, 0x0000000a },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_cwd_0[] = {
+ { 0x405b44, 1, 0x04, 0x00000000 },
+ { 0x405b50, 1, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_gpc_unk_1[] = {
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418d28, 2, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000400 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418f20, 2, 0x04, 0x00000000 },
+ { 0x418e00, 1, 0x04, 0x00000000 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ { 0x418e1c, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_tex_0[] = {
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419aec, 1, 0x04, 0x00000000 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ { 0x419aa8, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110_gr_init_l1c_0[] = {
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x01000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00b08bea },
+ { 0x419c84, 1, 0x04, 0x00010384 },
+ { 0x419cbc, 1, 0x04, 0x281b3646 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x00020230 },
+ { 0x419ccc, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk110_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000080 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ee4, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00000000 },
+ { 0x419eb4, 1, 0x04, 0x00000000 },
+ { 0x419ebc, 2, 0x04, 0x00000000 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419ed0, 1, 0x04, 0x00003234 },
+ { 0x419f74, 1, 0x04, 0x00015555 },
+ { 0x419f80, 4, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk110_gr_pack_mmio[] = {
+ { gk104_gr_init_main_0 },
+ { gk110_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf119_gr_init_pd_0 },
+ { gk110_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gk110_gr_init_sked_0 },
+ { gk110_gr_init_cwd_0 },
+ { gf119_gr_init_prop_0 },
+ { gf108_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf119_gr_init_gpm_0 },
+ { gk110_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gk104_gr_init_tpccs_0 },
+ { gk110_gr_init_tex_0 },
+ { gk104_gr_init_pe_0 },
+ { gk110_gr_init_l1c_0 },
+ { gf100_gr_init_mpc_0 },
+ { gk110_gr_init_sm_0 },
+ { gf117_gr_init_pes_0 },
+ { gf117_gr_init_wwdx_0 },
+ { gf117_gr_init_cbm_0 },
+ { gk104_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+int
+gk110_gr_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gf100_gr_priv *priv = (void *)object;
+ static const struct {
+ u32 addr;
+ u32 data;
+ } magic[] = {
+ { 0x020520, 0xfffffffc },
+ { 0x020524, 0xfffffffe },
+ { 0x020524, 0xfffffffc },
+ { 0x020524, 0xfffffff8 },
+ { 0x020524, 0xffffffe0 },
+ { 0x020530, 0xfffffffe },
+ { 0x02052c, 0xfffffffa },
+ { 0x02052c, 0xfffffff0 },
+ { 0x02052c, 0xffffffc0 },
+ { 0x02052c, 0xffffff00 },
+ { 0x02052c, 0xfffffc00 },
+ { 0x02052c, 0xfffcfc00 },
+ { 0x02052c, 0xfff0fc00 },
+ { 0x02052c, 0xff80fc00 },
+ { 0x020528, 0xfffffffe },
+ { 0x020528, 0xfffffffc },
+ };
+ int i;
+
+ nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+ nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+ for (i = 0; i < ARRAY_SIZE(magic); i++) {
+ nv_wr32(priv, magic[i].addr, magic[i].data);
+ nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+ }
+
+ return nvkm_gr_fini(&priv->base, suspend);
+}
+
+#include "fuc/hubgk110.fuc3.h"
+
+struct gf100_gr_ucode
+gk110_gr_fecs_ucode = {
+ .code.data = gk110_grhub_code,
+ .code.size = sizeof(gk110_grhub_code),
+ .data.data = gk110_grhub_data,
+ .data.size = sizeof(gk110_grhub_data),
+};
+
+#include "fuc/gpcgk110.fuc3.h"
+
+struct gf100_gr_ucode
+gk110_gr_gpccs_ucode = {
+ .code.data = gk110_grgpc_code,
+ .code.size = sizeof(gk110_grgpc_code),
+ .data.data = gk110_grgpc_data,
+ .data.size = sizeof(gk110_grgpc_data),
+};
+
+struct nvkm_oclass *
+gk110_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xf0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gk104_gr_init,
+ .fini = gk110_gr_fini,
+ },
+ .cclass = &gk110_grctx_oclass,
+ .sclass = gk110_gr_sclass,
+ .mmio = gk110_gr_pack_mmio,
+ .fecs.ucode = &gk110_gr_fecs_ucode,
+ .gpccs.ucode = &gk110_gr_gpccs_ucode,
+ .ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
new file mode 100644
index 000000000000..5292c5a9a38c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk110b.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk110b_gr_init_l1c_0[] = {
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x09000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00b08bea },
+ { 0x419c84, 1, 0x04, 0x00010384 },
+ { 0x419cbc, 1, 0x04, 0x281b3646 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x00020230 },
+ { 0x419ccc, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk110b_gr_init_sm_0[] = {
+ { 0x419e00, 1, 0x04, 0x00000080 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ee4, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x00000000 },
+ { 0x419eb4, 1, 0x04, 0x00000000 },
+ { 0x419ebc, 2, 0x04, 0x00000000 },
+ { 0x419edc, 1, 0x04, 0x00000000 },
+ { 0x419f00, 1, 0x04, 0x00000000 },
+ { 0x419ed0, 1, 0x04, 0x00002616 },
+ { 0x419f74, 1, 0x04, 0x00015555 },
+ { 0x419f80, 4, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk110b_gr_pack_mmio[] = {
+ { gk104_gr_init_main_0 },
+ { gk110_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf119_gr_init_pd_0 },
+ { gk110_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gk110_gr_init_sked_0 },
+ { gk110_gr_init_cwd_0 },
+ { gf119_gr_init_prop_0 },
+ { gf108_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gf108_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf119_gr_init_gpm_0 },
+ { gk110_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gk104_gr_init_tpccs_0 },
+ { gk110_gr_init_tex_0 },
+ { gk104_gr_init_pe_0 },
+ { gk110b_gr_init_l1c_0 },
+ { gf100_gr_init_mpc_0 },
+ { gk110b_gr_init_sm_0 },
+ { gf117_gr_init_pes_0 },
+ { gf117_gr_init_wwdx_0 },
+ { gf117_gr_init_cbm_0 },
+ { gk104_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gk110b_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xf1),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gk104_gr_init,
+ .fini = gk110_gr_fini,
+ },
+ .cclass = &gk110b_grctx_oclass,
+ .sclass = gk110_gr_sclass,
+ .mmio = gk110b_gr_pack_mmio,
+ .fecs.ucode = &gk110_gr_fecs_ucode,
+ .gpccs.ucode = &gk110_gr_gpccs_ucode,
+ .ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
new file mode 100644
index 000000000000..ae6b853173b6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk208.c
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/timer.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk208_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0xa140, &nvkm_object_ofuncs },
+ { KEPLER_B, &gf100_fermi_ofuncs },
+ { 0xa1c0, &nvkm_object_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gk208_gr_init_main_0[] = {
+ { 0x400080, 1, 0x04, 0x003083c2 },
+ { 0x400088, 1, 0x04, 0x0001bfe7 },
+ { 0x40008c, 1, 0x04, 0x00000000 },
+ { 0x400090, 1, 0x04, 0x00000030 },
+ { 0x40013c, 1, 0x04, 0x003901f7 },
+ { 0x400140, 1, 0x04, 0x00000100 },
+ { 0x400144, 1, 0x04, 0x00000000 },
+ { 0x400148, 1, 0x04, 0x00000110 },
+ { 0x400138, 1, 0x04, 0x00000000 },
+ { 0x400130, 2, 0x04, 0x00000000 },
+ { 0x400124, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x00000000 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ { 0x405928, 2, 0x04, 0x00000000 },
+ {}
+};
+
+const struct gf100_gr_init
+gk208_gr_init_gpc_unk_0[] = {
+ { 0x418604, 1, 0x04, 0x00000000 },
+ { 0x418680, 1, 0x04, 0x00000000 },
+ { 0x418714, 1, 0x04, 0x00000000 },
+ { 0x418384, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_setup_1[] = {
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00000201 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_tex_0[] = {
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ac8, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 2, 0x04, 0x00000000 },
+ { 0x419ab4, 1, 0x04, 0x00000000 },
+ { 0x419aa8, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gk208_gr_init_l1c_0[] = {
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419ca8, 1, 0x04, 0x00000000 },
+ { 0x419cb0, 1, 0x04, 0x01000000 },
+ { 0x419cb4, 1, 0x04, 0x00000000 },
+ { 0x419cb8, 1, 0x04, 0x00b08bea },
+ { 0x419c84, 1, 0x04, 0x00010384 },
+ { 0x419cbc, 1, 0x04, 0x281b3646 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x00000230 },
+ { 0x419ccc, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gk208_gr_pack_mmio[] = {
+ { gk208_gr_init_main_0 },
+ { gk110_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf119_gr_init_pd_0 },
+ { gk208_gr_init_ds_0 },
+ { gf100_gr_init_scc_0 },
+ { gk110_gr_init_sked_0 },
+ { gk110_gr_init_cwd_0 },
+ { gf119_gr_init_prop_0 },
+ { gk208_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gk208_gr_init_setup_1 },
+ { gf100_gr_init_zcull_0 },
+ { gf119_gr_init_gpm_0 },
+ { gk110_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gk104_gr_init_tpccs_0 },
+ { gk208_gr_init_tex_0 },
+ { gk104_gr_init_pe_0 },
+ { gk208_gr_init_l1c_0 },
+ { gf100_gr_init_mpc_0 },
+ { gk110_gr_init_sm_0 },
+ { gf117_gr_init_pes_0 },
+ { gf117_gr_init_wwdx_0 },
+ { gf117_gr_init_cbm_0 },
+ { gk104_gr_init_be_0 },
+ { gf100_gr_init_fe_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+gk208_gr_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gf100_gr_priv *priv = (void *)object;
+ static const struct {
+ u32 addr;
+ u32 data;
+ } magic[] = {
+ { 0x020520, 0xfffffffc },
+ { 0x020524, 0xfffffffe },
+ { 0x020524, 0xfffffffc },
+ { 0x020524, 0xfffffff8 },
+ { 0x020524, 0xffffffe0 },
+ { 0x020530, 0xfffffffe },
+ { 0x02052c, 0xfffffffa },
+ { 0x02052c, 0xfffffff0 },
+ { 0x02052c, 0xffffffc0 },
+ { 0x02052c, 0xffffff00 },
+ { 0x02052c, 0xfffffc00 },
+ { 0x02052c, 0xfffcfc00 },
+ { 0x02052c, 0xfff0fc00 },
+ { 0x02052c, 0xff80fc00 },
+ { 0x020528, 0xfffffffe },
+ { 0x020528, 0xfffffffc },
+ };
+ int i;
+
+ nv_mask(priv, 0x000200, 0x08001000, 0x00000000);
+ nv_mask(priv, 0x0206b4, 0x00000000, 0x00000000);
+ for (i = 0; i < ARRAY_SIZE(magic); i++) {
+ nv_wr32(priv, magic[i].addr, magic[i].data);
+ nv_wait(priv, magic[i].addr, 0x80000000, 0x00000000);
+ }
+
+ return nvkm_gr_fini(&priv->base, suspend);
+}
+
+#include "fuc/hubgk208.fuc5.h"
+
+static struct gf100_gr_ucode
+gk208_gr_fecs_ucode = {
+ .code.data = gk208_grhub_code,
+ .code.size = sizeof(gk208_grhub_code),
+ .data.data = gk208_grhub_data,
+ .data.size = sizeof(gk208_grhub_data),
+};
+
+#include "fuc/gpcgk208.fuc5.h"
+
+static struct gf100_gr_ucode
+gk208_gr_gpccs_ucode = {
+ .code.data = gk208_grgpc_code,
+ .code.size = sizeof(gk208_grgpc_code),
+ .data.data = gk208_grgpc_data,
+ .data.size = sizeof(gk208_grgpc_data),
+};
+
+struct nvkm_oclass *
+gk208_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0x08),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gk104_gr_init,
+ .fini = gk208_gr_fini,
+ },
+ .cclass = &gk208_grctx_oclass,
+ .sclass = gk208_gr_sclass,
+ .mmio = gk208_gr_pack_mmio,
+ .fecs.ucode = &gk208_gr_fecs_ucode,
+ .gpccs.ucode = &gk208_gr_gpccs_ucode,
+ .ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
new file mode 100644
index 000000000000..213755534084
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gk20a.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "gf100.h"
+#include "ctxgf100.h"
+
+#include <nvif/class.h>
+
+static struct nvkm_oclass
+gk20a_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0xa040, &nvkm_object_ofuncs },
+ { KEPLER_C, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { KEPLER_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+struct nvkm_oclass *
+gk20a_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0xea),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gk104_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gk20a_grctx_oclass,
+ .sclass = gk20a_gr_sclass,
+ .mmio = gk104_gr_pack_mmio,
+ .ppc_nr = 1,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
new file mode 100644
index 000000000000..124492b8a2d6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/gm107.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "gf100.h"
+#include "ctxgf100.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/P0260.h>
+
+#include <nvif/class.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gm107_gr_sclass[] = {
+ { 0x902d, &nvkm_object_ofuncs },
+ { 0xa140, &nvkm_object_ofuncs },
+ { MAXWELL_A, &gf100_fermi_ofuncs, gf100_gr_9097_omthds },
+ { MAXWELL_COMPUTE_A, &nvkm_object_ofuncs, gf100_gr_90c0_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH register lists
+ ******************************************************************************/
+
+static const struct gf100_gr_init
+gm107_gr_init_main_0[] = {
+ { 0x400080, 1, 0x04, 0x003003c2 },
+ { 0x400088, 1, 0x04, 0x0001bfe7 },
+ { 0x40008c, 1, 0x04, 0x00060000 },
+ { 0x400090, 1, 0x04, 0x00000030 },
+ { 0x40013c, 1, 0x04, 0x003901f3 },
+ { 0x400140, 1, 0x04, 0x00000100 },
+ { 0x400144, 1, 0x04, 0x00000000 },
+ { 0x400148, 1, 0x04, 0x00000110 },
+ { 0x400138, 1, 0x04, 0x00000000 },
+ { 0x400130, 2, 0x04, 0x00000000 },
+ { 0x400124, 1, 0x04, 0x00000002 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_ds_0[] = {
+ { 0x405844, 1, 0x04, 0x00ffffff },
+ { 0x405850, 1, 0x04, 0x00000000 },
+ { 0x405900, 1, 0x04, 0x00000000 },
+ { 0x405908, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_scc_0[] = {
+ { 0x40803c, 1, 0x04, 0x00000010 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_sked_0[] = {
+ { 0x407010, 1, 0x04, 0x00000000 },
+ { 0x407040, 1, 0x04, 0x40440424 },
+ { 0x407048, 1, 0x04, 0x0000000a },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_prop_0[] = {
+ { 0x418408, 1, 0x04, 0x00000000 },
+ { 0x4184a0, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_setup_1[] = {
+ { 0x4188c8, 2, 0x04, 0x00000000 },
+ { 0x4188d0, 1, 0x04, 0x00010000 },
+ { 0x4188d4, 1, 0x04, 0x00010201 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_zcull_0[] = {
+ { 0x418910, 1, 0x04, 0x00010001 },
+ { 0x418914, 1, 0x04, 0x00000301 },
+ { 0x418918, 1, 0x04, 0x00800000 },
+ { 0x418930, 2, 0x04, 0x00000000 },
+ { 0x418980, 1, 0x04, 0x77777770 },
+ { 0x418984, 3, 0x04, 0x77777777 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_gpc_unk_1[] = {
+ { 0x418d00, 1, 0x04, 0x00000000 },
+ { 0x418f00, 1, 0x04, 0x00000400 },
+ { 0x418f08, 1, 0x04, 0x00000000 },
+ { 0x418e08, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_tpccs_0[] = {
+ { 0x419dc4, 1, 0x04, 0x00000000 },
+ { 0x419dc8, 1, 0x04, 0x00000501 },
+ { 0x419dd0, 1, 0x04, 0x00000000 },
+ { 0x419dd4, 1, 0x04, 0x00000100 },
+ { 0x419dd8, 1, 0x04, 0x00000001 },
+ { 0x419ddc, 1, 0x04, 0x00000002 },
+ { 0x419de0, 1, 0x04, 0x00000001 },
+ { 0x419d0c, 1, 0x04, 0x00000000 },
+ { 0x419d10, 1, 0x04, 0x00000014 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_tex_0[] = {
+ { 0x419ab0, 1, 0x04, 0x00000000 },
+ { 0x419ab8, 1, 0x04, 0x000000e7 },
+ { 0x419abc, 1, 0x04, 0x00000000 },
+ { 0x419acc, 1, 0x04, 0x000000ff },
+ { 0x419ac0, 1, 0x04, 0x00000000 },
+ { 0x419aa8, 2, 0x04, 0x00000000 },
+ { 0x419ad0, 2, 0x04, 0x00000000 },
+ { 0x419ae0, 2, 0x04, 0x00000000 },
+ { 0x419af0, 4, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_pe_0[] = {
+ { 0x419900, 1, 0x04, 0x000000ff },
+ { 0x41980c, 1, 0x04, 0x00000010 },
+ { 0x419844, 1, 0x04, 0x00000000 },
+ { 0x419838, 1, 0x04, 0x000000ff },
+ { 0x419850, 1, 0x04, 0x00000004 },
+ { 0x419854, 2, 0x04, 0x00000000 },
+ { 0x419894, 3, 0x04, 0x00100401 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_l1c_0[] = {
+ { 0x419c98, 1, 0x04, 0x00000000 },
+ { 0x419cc0, 2, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_sm_0[] = {
+ { 0x419e30, 1, 0x04, 0x000000ff },
+ { 0x419e00, 1, 0x04, 0x00000000 },
+ { 0x419ea0, 1, 0x04, 0x00000000 },
+ { 0x419ee4, 1, 0x04, 0x00000000 },
+ { 0x419ea4, 1, 0x04, 0x00000100 },
+ { 0x419ea8, 1, 0x04, 0x01000000 },
+ { 0x419ee8, 1, 0x04, 0x00000091 },
+ { 0x419eb4, 1, 0x04, 0x00000000 },
+ { 0x419ebc, 2, 0x04, 0x00000000 },
+ { 0x419edc, 1, 0x04, 0x000c1810 },
+ { 0x419ed8, 1, 0x04, 0x00000000 },
+ { 0x419ee0, 1, 0x04, 0x00000000 },
+ { 0x419f74, 1, 0x04, 0x00005155 },
+ { 0x419f80, 4, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_l1c_1[] = {
+ { 0x419ccc, 2, 0x04, 0x00000000 },
+ { 0x419c80, 1, 0x04, 0x3f006022 },
+ { 0x419c88, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_pes_0[] = {
+ { 0x41be50, 1, 0x04, 0x000000ff },
+ { 0x41be04, 1, 0x04, 0x00000000 },
+ { 0x41be08, 1, 0x04, 0x00000004 },
+ { 0x41be0c, 1, 0x04, 0x00000008 },
+ { 0x41be10, 1, 0x04, 0x0e3b8bc7 },
+ { 0x41be14, 2, 0x04, 0x00000000 },
+ { 0x41be3c, 5, 0x04, 0x00100401 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_wwdx_0[] = {
+ { 0x41bfd4, 1, 0x04, 0x00800000 },
+ { 0x41bfdc, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_cbm_0[] = {
+ { 0x41becc, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_be_0[] = {
+ { 0x408890, 1, 0x04, 0x000000ff },
+ { 0x40880c, 1, 0x04, 0x00000000 },
+ { 0x408850, 1, 0x04, 0x00000004 },
+ { 0x408878, 1, 0x04, 0x00c81603 },
+ { 0x40887c, 1, 0x04, 0x80543432 },
+ { 0x408880, 1, 0x04, 0x0010581e },
+ { 0x408884, 1, 0x04, 0x00001205 },
+ { 0x408974, 1, 0x04, 0x000000ff },
+ { 0x408910, 9, 0x04, 0x00000000 },
+ { 0x408950, 1, 0x04, 0x00000000 },
+ { 0x408954, 1, 0x04, 0x0000ffff },
+ { 0x408958, 1, 0x04, 0x00000034 },
+ { 0x40895c, 1, 0x04, 0x8531a003 },
+ { 0x408960, 1, 0x04, 0x0561985a },
+ { 0x408964, 1, 0x04, 0x04e15c4f },
+ { 0x408968, 1, 0x04, 0x02808833 },
+ { 0x40896c, 1, 0x04, 0x01f02438 },
+ { 0x408970, 1, 0x04, 0x00012c00 },
+ { 0x408984, 1, 0x04, 0x00000000 },
+ { 0x408988, 1, 0x04, 0x08040201 },
+ { 0x40898c, 1, 0x04, 0x80402010 },
+ {}
+};
+
+static const struct gf100_gr_init
+gm107_gr_init_sm_1[] = {
+ { 0x419e5c, 1, 0x04, 0x00000000 },
+ { 0x419e58, 1, 0x04, 0x00000000 },
+ {}
+};
+
+static const struct gf100_gr_pack
+gm107_gr_pack_mmio[] = {
+ { gm107_gr_init_main_0 },
+ { gk110_gr_init_fe_0 },
+ { gf100_gr_init_pri_0 },
+ { gf100_gr_init_rstr2d_0 },
+ { gf100_gr_init_pd_0 },
+ { gm107_gr_init_ds_0 },
+ { gm107_gr_init_scc_0 },
+ { gm107_gr_init_sked_0 },
+ { gk110_gr_init_cwd_0 },
+ { gm107_gr_init_prop_0 },
+ { gk208_gr_init_gpc_unk_0 },
+ { gf100_gr_init_setup_0 },
+ { gf100_gr_init_crstr_0 },
+ { gm107_gr_init_setup_1 },
+ { gm107_gr_init_zcull_0 },
+ { gf100_gr_init_gpm_0 },
+ { gm107_gr_init_gpc_unk_1 },
+ { gf100_gr_init_gcc_0 },
+ { gm107_gr_init_tpccs_0 },
+ { gm107_gr_init_tex_0 },
+ { gm107_gr_init_pe_0 },
+ { gm107_gr_init_l1c_0 },
+ { gf100_gr_init_mpc_0 },
+ { gm107_gr_init_sm_0 },
+ { gm107_gr_init_l1c_1 },
+ { gm107_gr_init_pes_0 },
+ { gm107_gr_init_wwdx_0 },
+ { gm107_gr_init_cbm_0 },
+ { gm107_gr_init_be_0 },
+ { gm107_gr_init_sm_1 },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+gm107_gr_init_bios(struct gf100_gr_priv *priv)
+{
+ static const struct {
+ u32 ctrl;
+ u32 data;
+ } regs[] = {
+ { 0x419ed8, 0x419ee0 },
+ { 0x419ad0, 0x419ad4 },
+ { 0x419ae0, 0x419ae4 },
+ { 0x419af0, 0x419af4 },
+ { 0x419af8, 0x419afc },
+ };
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_P0260E infoE;
+ struct nvbios_P0260X infoX;
+ int E = -1, X;
+ u8 ver, hdr;
+
+ while (nvbios_P0260Ep(bios, ++E, &ver, &hdr, &infoE)) {
+ if (X = -1, E < ARRAY_SIZE(regs)) {
+ nv_wr32(priv, regs[E].ctrl, infoE.data);
+ while (nvbios_P0260Xp(bios, ++X, &ver, &hdr, &infoX))
+ nv_wr32(priv, regs[E].data, infoX.data);
+ }
+ }
+}
+
+int
+gm107_gr_init(struct nvkm_object *object)
+{
+ struct gf100_gr_oclass *oclass = (void *)object->oclass;
+ struct gf100_gr_priv *priv = (void *)object;
+ const u32 magicgpc918 = DIV_ROUND_UP(0x00800000, priv->tpc_total);
+ u32 data[TPC_MAX / 8] = {};
+ u8 tpcnr[GPC_MAX];
+ int gpc, tpc, ppc, rop;
+ int ret, i;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, GPC_BCAST(0x0880), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0890), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x0894), 0x00000000);
+ nv_wr32(priv, GPC_BCAST(0x08b4), priv->unk4188b4->addr >> 8);
+ nv_wr32(priv, GPC_BCAST(0x08b8), priv->unk4188b8->addr >> 8);
+
+ gf100_gr_mmio(priv, oclass->mmio);
+
+ gm107_gr_init_bios(priv);
+
+ nv_wr32(priv, GPC_UNIT(0, 0x3018), 0x00000001);
+
+ memset(data, 0x00, sizeof(data));
+ memcpy(tpcnr, priv->tpc_nr, sizeof(priv->tpc_nr));
+ for (i = 0, gpc = -1; i < priv->tpc_total; i++) {
+ do {
+ gpc = (gpc + 1) % priv->gpc_nr;
+ } while (!tpcnr[gpc]);
+ tpc = priv->tpc_nr[gpc] - tpcnr[gpc]--;
+
+ data[i / 8] |= tpc << ((i % 8) * 4);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x0980), data[0]);
+ nv_wr32(priv, GPC_BCAST(0x0984), data[1]);
+ nv_wr32(priv, GPC_BCAST(0x0988), data[2]);
+ nv_wr32(priv, GPC_BCAST(0x098c), data[3]);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0914),
+ priv->magic_not_rop_nr << 8 | priv->tpc_nr[gpc]);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0910), 0x00040000 |
+ priv->tpc_total);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0918), magicgpc918);
+ }
+
+ nv_wr32(priv, GPC_BCAST(0x3fd4), magicgpc918);
+ nv_wr32(priv, GPC_BCAST(0x08ac), nv_rd32(priv, 0x100800));
+
+ nv_wr32(priv, 0x400500, 0x00010001);
+
+ nv_wr32(priv, 0x400100, 0xffffffff);
+ nv_wr32(priv, 0x40013c, 0xffffffff);
+ nv_wr32(priv, 0x400124, 0x00000002);
+ nv_wr32(priv, 0x409c24, 0x000e0000);
+
+ nv_wr32(priv, 0x404000, 0xc0000000);
+ nv_wr32(priv, 0x404600, 0xc0000000);
+ nv_wr32(priv, 0x408030, 0xc0000000);
+ nv_wr32(priv, 0x404490, 0xc0000000);
+ nv_wr32(priv, 0x406018, 0xc0000000);
+ nv_wr32(priv, 0x407020, 0x40000000);
+ nv_wr32(priv, 0x405840, 0xc0000000);
+ nv_wr32(priv, 0x405844, 0x00ffffff);
+ nv_mask(priv, 0x419cc0, 0x00000008, 0x00000008);
+
+ for (gpc = 0; gpc < priv->gpc_nr; gpc++) {
+ for (ppc = 0; ppc < 2 /* priv->ppc_nr[gpc] */; ppc++)
+ nv_wr32(priv, PPC_UNIT(gpc, ppc, 0x038), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0420), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0900), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x1028), 0xc0000000);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x0824), 0xc0000000);
+ for (tpc = 0; tpc < priv->tpc_nr[gpc]; tpc++) {
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x508), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x50c), 0xffffffff);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x224), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x48c), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x084), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x430), 0xc0000000);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x644), 0x00dffffe);
+ nv_wr32(priv, TPC_UNIT(gpc, tpc, 0x64c), 0x00000005);
+ }
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c90), 0xffffffff);
+ nv_wr32(priv, GPC_UNIT(gpc, 0x2c94), 0xffffffff);
+ }
+
+ for (rop = 0; rop < priv->rop_nr; rop++) {
+ nv_wr32(priv, ROP_UNIT(rop, 0x144), 0x40000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x070), 0x40000000);
+ nv_wr32(priv, ROP_UNIT(rop, 0x204), 0xffffffff);
+ nv_wr32(priv, ROP_UNIT(rop, 0x208), 0xffffffff);
+ }
+
+ nv_wr32(priv, 0x400108, 0xffffffff);
+ nv_wr32(priv, 0x400138, 0xffffffff);
+ nv_wr32(priv, 0x400118, 0xffffffff);
+ nv_wr32(priv, 0x400130, 0xffffffff);
+ nv_wr32(priv, 0x40011c, 0xffffffff);
+ nv_wr32(priv, 0x400134, 0xffffffff);
+
+ nv_wr32(priv, 0x400054, 0x2c350f63);
+
+ gf100_gr_zbc_init(priv);
+
+ return gf100_gr_init_ctxctl(priv);
+}
+
+#include "fuc/hubgm107.fuc5.h"
+
+static struct gf100_gr_ucode
+gm107_gr_fecs_ucode = {
+ .code.data = gm107_grhub_code,
+ .code.size = sizeof(gm107_grhub_code),
+ .data.data = gm107_grhub_data,
+ .data.size = sizeof(gm107_grhub_data),
+};
+
+#include "fuc/gpcgm107.fuc5.h"
+
+static struct gf100_gr_ucode
+gm107_gr_gpccs_ucode = {
+ .code.data = gm107_grgpc_code,
+ .code.size = sizeof(gm107_grgpc_code),
+ .data.data = gm107_grgpc_data,
+ .data.size = sizeof(gm107_grgpc_data),
+};
+
+struct nvkm_oclass *
+gm107_gr_oclass = &(struct gf100_gr_oclass) {
+ .base.handle = NV_ENGINE(GR, 0x07),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_gr_ctor,
+ .dtor = gf100_gr_dtor,
+ .init = gm107_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+ .cclass = &gm107_grctx_oclass,
+ .sclass = gm107_gr_sclass,
+ .mmio = gm107_gr_pack_mmio,
+ .fecs.ucode = 0 ? &gm107_gr_fecs_ucode : NULL,
+ .gpccs.ucode = &gm107_gr_gpccs_ucode,
+ .ppc_nr = 2,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
new file mode 100644
index 000000000000..2614510c28d0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv04.c
@@ -0,0 +1,1382 @@
+/*
+ * Copyright 2007 Stephane Marchesin
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragr) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <engine/gr.h>
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/instmem.h>
+#include <subdev/timer.h>
+
+static u32
+nv04_gr_ctx_regs[] = {
+ 0x0040053c,
+ 0x00400544,
+ 0x00400540,
+ 0x00400548,
+ NV04_PGRAPH_CTX_SWITCH1,
+ NV04_PGRAPH_CTX_SWITCH2,
+ NV04_PGRAPH_CTX_SWITCH3,
+ NV04_PGRAPH_CTX_SWITCH4,
+ NV04_PGRAPH_CTX_CACHE1,
+ NV04_PGRAPH_CTX_CACHE2,
+ NV04_PGRAPH_CTX_CACHE3,
+ NV04_PGRAPH_CTX_CACHE4,
+ 0x00400184,
+ 0x004001a4,
+ 0x004001c4,
+ 0x004001e4,
+ 0x00400188,
+ 0x004001a8,
+ 0x004001c8,
+ 0x004001e8,
+ 0x0040018c,
+ 0x004001ac,
+ 0x004001cc,
+ 0x004001ec,
+ 0x00400190,
+ 0x004001b0,
+ 0x004001d0,
+ 0x004001f0,
+ 0x00400194,
+ 0x004001b4,
+ 0x004001d4,
+ 0x004001f4,
+ 0x00400198,
+ 0x004001b8,
+ 0x004001d8,
+ 0x004001f8,
+ 0x0040019c,
+ 0x004001bc,
+ 0x004001dc,
+ 0x004001fc,
+ 0x00400174,
+ NV04_PGRAPH_DMA_START_0,
+ NV04_PGRAPH_DMA_START_1,
+ NV04_PGRAPH_DMA_LENGTH,
+ NV04_PGRAPH_DMA_MISC,
+ NV04_PGRAPH_DMA_PITCH,
+ NV04_PGRAPH_BOFFSET0,
+ NV04_PGRAPH_BBASE0,
+ NV04_PGRAPH_BLIMIT0,
+ NV04_PGRAPH_BOFFSET1,
+ NV04_PGRAPH_BBASE1,
+ NV04_PGRAPH_BLIMIT1,
+ NV04_PGRAPH_BOFFSET2,
+ NV04_PGRAPH_BBASE2,
+ NV04_PGRAPH_BLIMIT2,
+ NV04_PGRAPH_BOFFSET3,
+ NV04_PGRAPH_BBASE3,
+ NV04_PGRAPH_BLIMIT3,
+ NV04_PGRAPH_BOFFSET4,
+ NV04_PGRAPH_BBASE4,
+ NV04_PGRAPH_BLIMIT4,
+ NV04_PGRAPH_BOFFSET5,
+ NV04_PGRAPH_BBASE5,
+ NV04_PGRAPH_BLIMIT5,
+ NV04_PGRAPH_BPITCH0,
+ NV04_PGRAPH_BPITCH1,
+ NV04_PGRAPH_BPITCH2,
+ NV04_PGRAPH_BPITCH3,
+ NV04_PGRAPH_BPITCH4,
+ NV04_PGRAPH_SURFACE,
+ NV04_PGRAPH_STATE,
+ NV04_PGRAPH_BSWIZZLE2,
+ NV04_PGRAPH_BSWIZZLE5,
+ NV04_PGRAPH_BPIXEL,
+ NV04_PGRAPH_NOTIFY,
+ NV04_PGRAPH_PATT_COLOR0,
+ NV04_PGRAPH_PATT_COLOR1,
+ NV04_PGRAPH_PATT_COLORRAM+0x00,
+ NV04_PGRAPH_PATT_COLORRAM+0x04,
+ NV04_PGRAPH_PATT_COLORRAM+0x08,
+ NV04_PGRAPH_PATT_COLORRAM+0x0c,
+ NV04_PGRAPH_PATT_COLORRAM+0x10,
+ NV04_PGRAPH_PATT_COLORRAM+0x14,
+ NV04_PGRAPH_PATT_COLORRAM+0x18,
+ NV04_PGRAPH_PATT_COLORRAM+0x1c,
+ NV04_PGRAPH_PATT_COLORRAM+0x20,
+ NV04_PGRAPH_PATT_COLORRAM+0x24,
+ NV04_PGRAPH_PATT_COLORRAM+0x28,
+ NV04_PGRAPH_PATT_COLORRAM+0x2c,
+ NV04_PGRAPH_PATT_COLORRAM+0x30,
+ NV04_PGRAPH_PATT_COLORRAM+0x34,
+ NV04_PGRAPH_PATT_COLORRAM+0x38,
+ NV04_PGRAPH_PATT_COLORRAM+0x3c,
+ NV04_PGRAPH_PATT_COLORRAM+0x40,
+ NV04_PGRAPH_PATT_COLORRAM+0x44,
+ NV04_PGRAPH_PATT_COLORRAM+0x48,
+ NV04_PGRAPH_PATT_COLORRAM+0x4c,
+ NV04_PGRAPH_PATT_COLORRAM+0x50,
+ NV04_PGRAPH_PATT_COLORRAM+0x54,
+ NV04_PGRAPH_PATT_COLORRAM+0x58,
+ NV04_PGRAPH_PATT_COLORRAM+0x5c,
+ NV04_PGRAPH_PATT_COLORRAM+0x60,
+ NV04_PGRAPH_PATT_COLORRAM+0x64,
+ NV04_PGRAPH_PATT_COLORRAM+0x68,
+ NV04_PGRAPH_PATT_COLORRAM+0x6c,
+ NV04_PGRAPH_PATT_COLORRAM+0x70,
+ NV04_PGRAPH_PATT_COLORRAM+0x74,
+ NV04_PGRAPH_PATT_COLORRAM+0x78,
+ NV04_PGRAPH_PATT_COLORRAM+0x7c,
+ NV04_PGRAPH_PATT_COLORRAM+0x80,
+ NV04_PGRAPH_PATT_COLORRAM+0x84,
+ NV04_PGRAPH_PATT_COLORRAM+0x88,
+ NV04_PGRAPH_PATT_COLORRAM+0x8c,
+ NV04_PGRAPH_PATT_COLORRAM+0x90,
+ NV04_PGRAPH_PATT_COLORRAM+0x94,
+ NV04_PGRAPH_PATT_COLORRAM+0x98,
+ NV04_PGRAPH_PATT_COLORRAM+0x9c,
+ NV04_PGRAPH_PATT_COLORRAM+0xa0,
+ NV04_PGRAPH_PATT_COLORRAM+0xa4,
+ NV04_PGRAPH_PATT_COLORRAM+0xa8,
+ NV04_PGRAPH_PATT_COLORRAM+0xac,
+ NV04_PGRAPH_PATT_COLORRAM+0xb0,
+ NV04_PGRAPH_PATT_COLORRAM+0xb4,
+ NV04_PGRAPH_PATT_COLORRAM+0xb8,
+ NV04_PGRAPH_PATT_COLORRAM+0xbc,
+ NV04_PGRAPH_PATT_COLORRAM+0xc0,
+ NV04_PGRAPH_PATT_COLORRAM+0xc4,
+ NV04_PGRAPH_PATT_COLORRAM+0xc8,
+ NV04_PGRAPH_PATT_COLORRAM+0xcc,
+ NV04_PGRAPH_PATT_COLORRAM+0xd0,
+ NV04_PGRAPH_PATT_COLORRAM+0xd4,
+ NV04_PGRAPH_PATT_COLORRAM+0xd8,
+ NV04_PGRAPH_PATT_COLORRAM+0xdc,
+ NV04_PGRAPH_PATT_COLORRAM+0xe0,
+ NV04_PGRAPH_PATT_COLORRAM+0xe4,
+ NV04_PGRAPH_PATT_COLORRAM+0xe8,
+ NV04_PGRAPH_PATT_COLORRAM+0xec,
+ NV04_PGRAPH_PATT_COLORRAM+0xf0,
+ NV04_PGRAPH_PATT_COLORRAM+0xf4,
+ NV04_PGRAPH_PATT_COLORRAM+0xf8,
+ NV04_PGRAPH_PATT_COLORRAM+0xfc,
+ NV04_PGRAPH_PATTERN,
+ 0x0040080c,
+ NV04_PGRAPH_PATTERN_SHAPE,
+ 0x00400600,
+ NV04_PGRAPH_ROP3,
+ NV04_PGRAPH_CHROMA,
+ NV04_PGRAPH_BETA_AND,
+ NV04_PGRAPH_BETA_PREMULT,
+ NV04_PGRAPH_CONTROL0,
+ NV04_PGRAPH_CONTROL1,
+ NV04_PGRAPH_CONTROL2,
+ NV04_PGRAPH_BLEND,
+ NV04_PGRAPH_STORED_FMT,
+ NV04_PGRAPH_SOURCE_COLOR,
+ 0x00400560,
+ 0x00400568,
+ 0x00400564,
+ 0x0040056c,
+ 0x00400400,
+ 0x00400480,
+ 0x00400404,
+ 0x00400484,
+ 0x00400408,
+ 0x00400488,
+ 0x0040040c,
+ 0x0040048c,
+ 0x00400410,
+ 0x00400490,
+ 0x00400414,
+ 0x00400494,
+ 0x00400418,
+ 0x00400498,
+ 0x0040041c,
+ 0x0040049c,
+ 0x00400420,
+ 0x004004a0,
+ 0x00400424,
+ 0x004004a4,
+ 0x00400428,
+ 0x004004a8,
+ 0x0040042c,
+ 0x004004ac,
+ 0x00400430,
+ 0x004004b0,
+ 0x00400434,
+ 0x004004b4,
+ 0x00400438,
+ 0x004004b8,
+ 0x0040043c,
+ 0x004004bc,
+ 0x00400440,
+ 0x004004c0,
+ 0x00400444,
+ 0x004004c4,
+ 0x00400448,
+ 0x004004c8,
+ 0x0040044c,
+ 0x004004cc,
+ 0x00400450,
+ 0x004004d0,
+ 0x00400454,
+ 0x004004d4,
+ 0x00400458,
+ 0x004004d8,
+ 0x0040045c,
+ 0x004004dc,
+ 0x00400460,
+ 0x004004e0,
+ 0x00400464,
+ 0x004004e4,
+ 0x00400468,
+ 0x004004e8,
+ 0x0040046c,
+ 0x004004ec,
+ 0x00400470,
+ 0x004004f0,
+ 0x00400474,
+ 0x004004f4,
+ 0x00400478,
+ 0x004004f8,
+ 0x0040047c,
+ 0x004004fc,
+ 0x00400534,
+ 0x00400538,
+ 0x00400514,
+ 0x00400518,
+ 0x0040051c,
+ 0x00400520,
+ 0x00400524,
+ 0x00400528,
+ 0x0040052c,
+ 0x00400530,
+ 0x00400d00,
+ 0x00400d40,
+ 0x00400d80,
+ 0x00400d04,
+ 0x00400d44,
+ 0x00400d84,
+ 0x00400d08,
+ 0x00400d48,
+ 0x00400d88,
+ 0x00400d0c,
+ 0x00400d4c,
+ 0x00400d8c,
+ 0x00400d10,
+ 0x00400d50,
+ 0x00400d90,
+ 0x00400d14,
+ 0x00400d54,
+ 0x00400d94,
+ 0x00400d18,
+ 0x00400d58,
+ 0x00400d98,
+ 0x00400d1c,
+ 0x00400d5c,
+ 0x00400d9c,
+ 0x00400d20,
+ 0x00400d60,
+ 0x00400da0,
+ 0x00400d24,
+ 0x00400d64,
+ 0x00400da4,
+ 0x00400d28,
+ 0x00400d68,
+ 0x00400da8,
+ 0x00400d2c,
+ 0x00400d6c,
+ 0x00400dac,
+ 0x00400d30,
+ 0x00400d70,
+ 0x00400db0,
+ 0x00400d34,
+ 0x00400d74,
+ 0x00400db4,
+ 0x00400d38,
+ 0x00400d78,
+ 0x00400db8,
+ 0x00400d3c,
+ 0x00400d7c,
+ 0x00400dbc,
+ 0x00400590,
+ 0x00400594,
+ 0x00400598,
+ 0x0040059c,
+ 0x004005a8,
+ 0x004005ac,
+ 0x004005b0,
+ 0x004005b4,
+ 0x004005c0,
+ 0x004005c4,
+ 0x004005c8,
+ 0x004005cc,
+ 0x004005d0,
+ 0x004005d4,
+ 0x004005d8,
+ 0x004005dc,
+ 0x004005e0,
+ NV04_PGRAPH_PASSTHRU_0,
+ NV04_PGRAPH_PASSTHRU_1,
+ NV04_PGRAPH_PASSTHRU_2,
+ NV04_PGRAPH_DVD_COLORFMT,
+ NV04_PGRAPH_SCALED_FORMAT,
+ NV04_PGRAPH_MISC24_0,
+ NV04_PGRAPH_MISC24_1,
+ NV04_PGRAPH_MISC24_2,
+ 0x00400500,
+ 0x00400504,
+ NV04_PGRAPH_VALID1,
+ NV04_PGRAPH_VALID2,
+ NV04_PGRAPH_DEBUG_3
+};
+
+struct nv04_gr_priv {
+ struct nvkm_gr base;
+ struct nv04_gr_chan *chan[16];
+ spinlock_t lock;
+};
+
+struct nv04_gr_chan {
+ struct nvkm_object base;
+ int chid;
+ u32 nv04[ARRAY_SIZE(nv04_gr_ctx_regs)];
+};
+
+
+static inline struct nv04_gr_priv *
+nv04_gr_priv(struct nv04_gr_chan *chan)
+{
+ return (void *)nv_object(chan)->engine;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+/*
+ * Software methods, why they are needed, and how they all work:
+ *
+ * NV04 and NV05 keep most of the state in PGRAPH context itself, but some
+ * 2d engine settings are kept inside the grobjs themselves. The grobjs are
+ * 3 words long on both. grobj format on NV04 is:
+ *
+ * word 0:
+ * - bits 0-7: class
+ * - bit 12: color key active
+ * - bit 13: clip rect active
+ * - bit 14: if set, destination surface is swizzled and taken from buffer 5
+ * [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
+ * from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
+ * NV03_CONTEXT_SURFACE_DST].
+ * - bits 15-17: 2d operation [aka patch config]
+ * - bit 24: patch valid [enables rendering using this object]
+ * - bit 25: surf3d valid [for tex_tri and multitex_tri only]
+ * word 1:
+ * - bits 0-1: mono format
+ * - bits 8-13: color format
+ * - bits 16-31: DMA_NOTIFY instance
+ * word 2:
+ * - bits 0-15: DMA_A instance
+ * - bits 16-31: DMA_B instance
+ *
+ * On NV05 it's:
+ *
+ * word 0:
+ * - bits 0-7: class
+ * - bit 12: color key active
+ * - bit 13: clip rect active
+ * - bit 14: if set, destination surface is swizzled and taken from buffer 5
+ * [set by NV04_SWIZZLED_SURFACE], otherwise it's linear and taken
+ * from buffer 0 [set by NV04_CONTEXT_SURFACES_2D or
+ * NV03_CONTEXT_SURFACE_DST].
+ * - bits 15-17: 2d operation [aka patch config]
+ * - bits 20-22: dither mode
+ * - bit 24: patch valid [enables rendering using this object]
+ * - bit 25: surface_dst/surface_color/surf2d/surf3d valid
+ * - bit 26: surface_src/surface_zeta valid
+ * - bit 27: pattern valid
+ * - bit 28: rop valid
+ * - bit 29: beta1 valid
+ * - bit 30: beta4 valid
+ * word 1:
+ * - bits 0-1: mono format
+ * - bits 8-13: color format
+ * - bits 16-31: DMA_NOTIFY instance
+ * word 2:
+ * - bits 0-15: DMA_A instance
+ * - bits 16-31: DMA_B instance
+ *
+ * NV05 will set/unset the relevant valid bits when you poke the relevant
+ * object-binding methods with object of the proper type, or with the NULL
+ * type. It'll only allow rendering using the grobj if all needed objects
+ * are bound. The needed set of objects depends on selected operation: for
+ * example rop object is needed by ROP_AND, but not by SRCCOPY_AND.
+ *
+ * NV04 doesn't have these methods implemented at all, and doesn't have the
+ * relevant bits in grobj. Instead, it'll allow rendering whenever bit 24
+ * is set. So we have to emulate them in software, internally keeping the
+ * same bits as NV05 does. Since grobjs are aligned to 16 bytes on nv04,
+ * but the last word isn't actually used for anything, we abuse it for this
+ * purpose.
+ *
+ * Actually, NV05 can optionally check bit 24 too, but we disable this since
+ * there's no use for it.
+ *
+ * For unknown reasons, NV04 implements surf3d binding in hardware as an
+ * exception. Also for unknown reasons, NV04 doesn't implement the clipping
+ * methods on the surf3d object, so we have to emulate them too.
+ */
+
+static void
+nv04_gr_set_ctx1(struct nvkm_object *object, u32 mask, u32 value)
+{
+ struct nv04_gr_priv *priv = (void *)object->engine;
+ int subc = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 13) & 0x7;
+ u32 tmp;
+
+ tmp = nv_ro32(object, 0x00);
+ tmp &= ~mask;
+ tmp |= value;
+ nv_wo32(object, 0x00, tmp);
+
+ nv_wr32(priv, NV04_PGRAPH_CTX_SWITCH1, tmp);
+ nv_wr32(priv, NV04_PGRAPH_CTX_CACHE1 + (subc<<2), tmp);
+}
+
+static void
+nv04_gr_set_ctx_val(struct nvkm_object *object, u32 mask, u32 value)
+{
+ int class, op, valid = 1;
+ u32 tmp, ctx1;
+
+ ctx1 = nv_ro32(object, 0x00);
+ class = ctx1 & 0xff;
+ op = (ctx1 >> 15) & 7;
+
+ tmp = nv_ro32(object, 0x0c);
+ tmp &= ~mask;
+ tmp |= value;
+ nv_wo32(object, 0x0c, tmp);
+
+ /* check for valid surf2d/surf_dst/surf_color */
+ if (!(tmp & 0x02000000))
+ valid = 0;
+ /* check for valid surf_src/surf_zeta */
+ if ((class == 0x1f || class == 0x48) && !(tmp & 0x04000000))
+ valid = 0;
+
+ switch (op) {
+ /* SRCCOPY_AND, SRCCOPY: no extra objects required */
+ case 0:
+ case 3:
+ break;
+ /* ROP_AND: requires pattern and rop */
+ case 1:
+ if (!(tmp & 0x18000000))
+ valid = 0;
+ break;
+ /* BLEND_AND: requires beta1 */
+ case 2:
+ if (!(tmp & 0x20000000))
+ valid = 0;
+ break;
+ /* SRCCOPY_PREMULT, BLEND_PREMULT: beta4 required */
+ case 4:
+ case 5:
+ if (!(tmp & 0x40000000))
+ valid = 0;
+ break;
+ }
+
+ nv04_gr_set_ctx1(object, 0x01000000, valid << 24);
+}
+
+static int
+nv04_gr_mthd_set_operation(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ u32 class = nv_ro32(object, 0) & 0xff;
+ u32 data = *(u32 *)args;
+ if (data > 5)
+ return 1;
+ /* Old versions of the objects only accept first three operations. */
+ if (data > 2 && class < 0x40)
+ return 1;
+ nv04_gr_set_ctx1(object, 0x00038000, data << 15);
+ /* changing operation changes set of objects needed for validation */
+ nv04_gr_set_ctx_val(object, 0, 0);
+ return 0;
+}
+
+static int
+nv04_gr_mthd_surf3d_clip_h(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv04_gr_priv *priv = (void *)object->engine;
+ u32 data = *(u32 *)args;
+ u32 min = data & 0xffff, max;
+ u32 w = data >> 16;
+ if (min & 0x8000)
+ /* too large */
+ return 1;
+ if (w & 0x8000)
+ /* yes, it accepts negative for some reason. */
+ w |= 0xffff0000;
+ max = min + w;
+ max &= 0x3ffff;
+ nv_wr32(priv, 0x40053c, min);
+ nv_wr32(priv, 0x400544, max);
+ return 0;
+}
+
+static int
+nv04_gr_mthd_surf3d_clip_v(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv04_gr_priv *priv = (void *)object->engine;
+ u32 data = *(u32 *)args;
+ u32 min = data & 0xffff, max;
+ u32 w = data >> 16;
+ if (min & 0x8000)
+ /* too large */
+ return 1;
+ if (w & 0x8000)
+ /* yes, it accepts negative for some reason. */
+ w |= 0xffff0000;
+ max = min + w;
+ max &= 0x3ffff;
+ nv_wr32(priv, 0x400540, min);
+ nv_wr32(priv, 0x400548, max);
+ return 0;
+}
+
+static u16
+nv04_gr_mthd_bind_class(struct nvkm_object *object, u32 *args, u32 size)
+{
+ struct nvkm_instmem *imem = nvkm_instmem(object);
+ u32 inst = *(u32 *)args << 4;
+ return nv_ro32(imem, inst);
+}
+
+static int
+nv04_gr_mthd_bind_surf2d(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx1(object, 0x00004000, 0);
+ nv04_gr_set_ctx_val(object, 0x02000000, 0);
+ return 0;
+ case 0x42:
+ nv04_gr_set_ctx1(object, 0x00004000, 0);
+ nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf2d_swzsurf(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx1(object, 0x00004000, 0);
+ nv04_gr_set_ctx_val(object, 0x02000000, 0);
+ return 0;
+ case 0x42:
+ nv04_gr_set_ctx1(object, 0x00004000, 0);
+ nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+ return 0;
+ case 0x52:
+ nv04_gr_set_ctx1(object, 0x00004000, 0x00004000);
+ nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv01_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x08000000, 0);
+ return 0;
+ case 0x18:
+ nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_patt(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x08000000, 0);
+ return 0;
+ case 0x44:
+ nv04_gr_set_ctx_val(object, 0x08000000, 0x08000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_rop(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x10000000, 0);
+ return 0;
+ case 0x43:
+ nv04_gr_set_ctx_val(object, 0x10000000, 0x10000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_beta1(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x20000000, 0);
+ return 0;
+ case 0x12:
+ nv04_gr_set_ctx_val(object, 0x20000000, 0x20000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_beta4(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x40000000, 0);
+ return 0;
+ case 0x72:
+ nv04_gr_set_ctx_val(object, 0x40000000, 0x40000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_dst(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x02000000, 0);
+ return 0;
+ case 0x58:
+ nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_src(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x04000000, 0);
+ return 0;
+ case 0x59:
+ nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_color(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x02000000, 0);
+ return 0;
+ case 0x5a:
+ nv04_gr_set_ctx_val(object, 0x02000000, 0x02000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv04_gr_mthd_bind_surf_zeta(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx_val(object, 0x04000000, 0);
+ return 0;
+ case 0x5b:
+ nv04_gr_set_ctx_val(object, 0x04000000, 0x04000000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv01_gr_mthd_bind_clip(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx1(object, 0x2000, 0);
+ return 0;
+ case 0x19:
+ nv04_gr_set_ctx1(object, 0x2000, 0x2000);
+ return 0;
+ }
+ return 1;
+}
+
+static int
+nv01_gr_mthd_bind_chroma(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ switch (nv04_gr_mthd_bind_class(object, args, size)) {
+ case 0x30:
+ nv04_gr_set_ctx1(object, 0x1000, 0);
+ return 0;
+ /* Yes, for some reason even the old versions of objects
+ * accept 0x57 and not 0x17. Consistency be damned.
+ */
+ case 0x57:
+ nv04_gr_set_ctx1(object, 0x1000, 0x1000);
+ return 0;
+ }
+ return 1;
+}
+
+static struct nvkm_omthds
+nv03_gr_gdi_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_patt },
+ { 0x0188, 0x0188, nv04_gr_mthd_bind_rop },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_beta1 },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_surf_dst },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_gdi_omthds[] = {
+ { 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv01_gr_blit_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+ { 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
+ { 0x019c, 0x019c, nv04_gr_mthd_bind_surf_src },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_blit_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
+ { 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_iifc_omthds[] = {
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_chroma },
+ { 0x018c, 0x018c, nv01_gr_mthd_bind_clip },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_patt },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_rop },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_beta1 },
+ { 0x019c, 0x019c, nv04_gr_mthd_bind_beta4 },
+ { 0x01a0, 0x01a0, nv04_gr_mthd_bind_surf2d_swzsurf },
+ { 0x03e4, 0x03e4, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv01_gr_ifc_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+ { 0x018c, 0x018c, nv01_gr_mthd_bind_patt },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_surf_dst },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_ifc_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_patt },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_rop },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta1 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_beta4 },
+ { 0x019c, 0x019c, nv04_gr_mthd_bind_surf2d },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv03_gr_sifc_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_sifc_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_chroma },
+ { 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv03_gr_sifm_omthds[] = {
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
+ { 0x0304, 0x0304, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_sifm_omthds[] = {
+ { 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+ { 0x0304, 0x0304, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_surf3d_omthds[] = {
+ { 0x02f8, 0x02f8, nv04_gr_mthd_surf3d_clip_h },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_surf3d_clip_v },
+ {}
+};
+
+static struct nvkm_omthds
+nv03_gr_ttri_omthds[] = {
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_clip },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_surf_color },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_surf_zeta },
+ {}
+};
+
+static struct nvkm_omthds
+nv01_gr_prim_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
+ { 0x0188, 0x0188, nv01_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_surf_dst },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static struct nvkm_omthds
+nv04_gr_prim_omthds[] = {
+ { 0x0184, 0x0184, nv01_gr_mthd_bind_clip },
+ { 0x0188, 0x0188, nv04_gr_mthd_bind_patt },
+ { 0x018c, 0x018c, nv04_gr_mthd_bind_rop },
+ { 0x0190, 0x0190, nv04_gr_mthd_bind_beta1 },
+ { 0x0194, 0x0194, nv04_gr_mthd_bind_beta4 },
+ { 0x0198, 0x0198, nv04_gr_mthd_bind_surf2d },
+ { 0x02fc, 0x02fc, nv04_gr_mthd_set_operation },
+ {}
+};
+
+static int
+nv04_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj *obj;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+ 16, 16, 0, &obj);
+ *pobject = nv_object(obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, nv_mclass(obj));
+#ifdef __BIG_ENDIAN
+ nv_mo32(obj, 0x00, 0x00080000, 0x00080000);
+#endif
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ return 0;
+}
+
+struct nvkm_ofuncs
+nv04_gr_ofuncs = {
+ .ctor = nv04_gr_object_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv04_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+ { 0x0017, &nv04_gr_ofuncs }, /* chroma */
+ { 0x0018, &nv04_gr_ofuncs }, /* pattern (nv01) */
+ { 0x0019, &nv04_gr_ofuncs }, /* clip */
+ { 0x001c, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* line */
+ { 0x001d, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* tri */
+ { 0x001e, &nv04_gr_ofuncs, nv01_gr_prim_omthds }, /* rect */
+ { 0x001f, &nv04_gr_ofuncs, nv01_gr_blit_omthds },
+ { 0x0021, &nv04_gr_ofuncs, nv01_gr_ifc_omthds },
+ { 0x0030, &nv04_gr_ofuncs }, /* null */
+ { 0x0036, &nv04_gr_ofuncs, nv03_gr_sifc_omthds },
+ { 0x0037, &nv04_gr_ofuncs, nv03_gr_sifm_omthds },
+ { 0x0038, &nv04_gr_ofuncs }, /* dvd subpicture */
+ { 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+ { 0x0042, &nv04_gr_ofuncs }, /* surf2d */
+ { 0x0043, &nv04_gr_ofuncs }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs }, /* pattern */
+ { 0x0048, &nv04_gr_ofuncs, nv03_gr_ttri_omthds },
+ { 0x004a, &nv04_gr_ofuncs, nv04_gr_gdi_omthds },
+ { 0x004b, &nv04_gr_ofuncs, nv03_gr_gdi_omthds },
+ { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+ { 0x0053, &nv04_gr_ofuncs, nv04_gr_surf3d_omthds },
+ { 0x0054, &nv04_gr_ofuncs }, /* ttri */
+ { 0x0055, &nv04_gr_ofuncs }, /* mtri */
+ { 0x0057, &nv04_gr_ofuncs }, /* chroma */
+ { 0x0058, &nv04_gr_ofuncs }, /* surf_dst */
+ { 0x0059, &nv04_gr_ofuncs }, /* surf_src */
+ { 0x005a, &nv04_gr_ofuncs }, /* surf_color */
+ { 0x005b, &nv04_gr_ofuncs }, /* surf_zeta */
+ { 0x005c, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* line */
+ { 0x005d, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* tri */
+ { 0x005e, &nv04_gr_ofuncs, nv04_gr_prim_omthds }, /* rect */
+ { 0x005f, &nv04_gr_ofuncs, nv04_gr_blit_omthds },
+ { 0x0060, &nv04_gr_ofuncs, nv04_gr_iifc_omthds },
+ { 0x0061, &nv04_gr_ofuncs, nv04_gr_ifc_omthds },
+ { 0x0064, &nv04_gr_ofuncs }, /* iifc (nv05) */
+ { 0x0065, &nv04_gr_ofuncs }, /* ifc (nv05) */
+ { 0x0066, &nv04_gr_ofuncs }, /* sifc (nv05) */
+ { 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+ { 0x0076, &nv04_gr_ofuncs, nv04_gr_sifc_omthds },
+ { 0x0077, &nv04_gr_ofuncs, nv04_gr_sifm_omthds },
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv04_gr_chan *
+nv04_gr_channel(struct nv04_gr_priv *priv)
+{
+ struct nv04_gr_chan *chan = NULL;
+ if (nv_rd32(priv, NV04_PGRAPH_CTX_CONTROL) & 0x00010000) {
+ int chid = nv_rd32(priv, NV04_PGRAPH_CTX_USER) >> 24;
+ if (chid < ARRAY_SIZE(priv->chan))
+ chan = priv->chan[chid];
+ }
+ return chan;
+}
+
+static int
+nv04_gr_load_context(struct nv04_gr_chan *chan, int chid)
+{
+ struct nv04_gr_priv *priv = nv04_gr_priv(chan);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
+ nv_wr32(priv, nv04_gr_ctx_regs[i], chan->nv04[i]);
+
+ nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10010100);
+ nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+ nv_mask(priv, NV04_PGRAPH_FFINTFC_ST2, 0xfff00000, 0x00000000);
+ return 0;
+}
+
+static int
+nv04_gr_unload_context(struct nv04_gr_chan *chan)
+{
+ struct nv04_gr_priv *priv = nv04_gr_priv(chan);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++)
+ chan->nv04[i] = nv_rd32(priv, nv04_gr_ctx_regs[i]);
+
+ nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL, 0x10000000);
+ nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+ return 0;
+}
+
+static void
+nv04_gr_context_switch(struct nv04_gr_priv *priv)
+{
+ struct nv04_gr_chan *prev = NULL;
+ struct nv04_gr_chan *next = NULL;
+ unsigned long flags;
+ int chid;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ nv04_gr_idle(priv);
+
+ /* If previous context is valid, we need to save it */
+ prev = nv04_gr_channel(priv);
+ if (prev)
+ nv04_gr_unload_context(prev);
+
+ /* load context for next channel */
+ chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 24) & 0x0f;
+ next = priv->chan[chid];
+ if (next)
+ nv04_gr_load_context(next, chid);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static u32 *ctx_reg(struct nv04_gr_chan *chan, u32 reg)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nv04_gr_ctx_regs); i++) {
+ if (nv04_gr_ctx_regs[i] == reg)
+ return &chan->nv04[i];
+ }
+
+ return NULL;
+}
+
+static int
+nv04_gr_context_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fifo_chan *fifo = (void *)parent;
+ struct nv04_gr_priv *priv = (void *)engine;
+ struct nv04_gr_chan *chan;
+ unsigned long flags;
+ int ret;
+
+ ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->chan[fifo->chid]) {
+ *pobject = nv_object(priv->chan[fifo->chid]);
+ atomic_inc(&(*pobject)->refcount);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ nvkm_object_destroy(&chan->base);
+ return 1;
+ }
+
+ *ctx_reg(chan, NV04_PGRAPH_DEBUG_3) = 0xfad4ff31;
+
+ priv->chan[fifo->chid] = chan;
+ chan->chid = fifo->chid;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static void
+nv04_gr_context_dtor(struct nvkm_object *object)
+{
+ struct nv04_gr_priv *priv = (void *)object->engine;
+ struct nv04_gr_chan *chan = (void *)object;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->chan[chan->chid] = NULL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ nvkm_object_destroy(&chan->base);
+}
+
+static int
+nv04_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv04_gr_priv *priv = (void *)object->engine;
+ struct nv04_gr_chan *chan = (void *)object;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+ if (nv04_gr_channel(priv) == chan)
+ nv04_gr_unload_context(chan);
+ nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return nvkm_object_fini(&chan->base, suspend);
+}
+
+static struct nvkm_oclass
+nv04_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_gr_context_ctor,
+ .dtor = nv04_gr_context_dtor,
+ .init = nvkm_object_init,
+ .fini = nv04_gr_context_fini,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+bool
+nv04_gr_idle(void *obj)
+{
+ struct nvkm_gr *gr = nvkm_gr(obj);
+ u32 mask = 0xffffffff;
+
+ if (nv_device(obj)->card_type == NV_40)
+ mask &= ~NV40_PGRAPH_STATUS_SYNC_STALL;
+
+ if (!nv_wait(gr, NV04_PGRAPH_STATUS, mask, 0)) {
+ nv_error(gr, "idle timed out with status 0x%08x\n",
+ nv_rd32(gr, NV04_PGRAPH_STATUS));
+ return false;
+ }
+
+ return true;
+}
+
+static const struct nvkm_bitfield
+nv04_gr_intr_name[] = {
+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+ {}
+};
+
+static const struct nvkm_bitfield
+nv04_gr_nstatus[] = {
+ { NV04_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
+ { NV04_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
+ { NV04_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
+ { NV04_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
+ {}
+};
+
+const struct nvkm_bitfield
+nv04_gr_nsource[] = {
+ { NV03_PGRAPH_NSOURCE_NOTIFICATION, "NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DATA_ERROR, "DATA_ERROR" },
+ { NV03_PGRAPH_NSOURCE_PROTECTION_ERROR, "PROTECTION_ERROR" },
+ { NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION, "RANGE_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_COLOR, "LIMIT_COLOR" },
+ { NV03_PGRAPH_NSOURCE_LIMIT_ZETA, "LIMIT_ZETA" },
+ { NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD, "ILLEGAL_MTHD" },
+ { NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION, "DMA_R_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION, "DMA_W_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION, "FORMAT_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION, "PATCH_EXCEPTION" },
+ { NV03_PGRAPH_NSOURCE_STATE_INVALID, "STATE_INVALID" },
+ { NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY, "DOUBLE_NOTIFY" },
+ { NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE, "NOTIFY_IN_USE" },
+ { NV03_PGRAPH_NSOURCE_METHOD_CNT, "METHOD_CNT" },
+ { NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION, "BFR_NOTIFICATION" },
+ { NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION, "DMA_VTX_PROTECTION" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_A, "DMA_WIDTH_A" },
+ { NV03_PGRAPH_NSOURCE_DMA_WIDTH_B, "DMA_WIDTH_B" },
+ {}
+};
+
+static void
+nv04_gr_intr(struct nvkm_subdev *subdev)
+{
+ struct nv04_gr_priv *priv = (void *)subdev;
+ struct nv04_gr_chan *chan = NULL;
+ struct nvkm_namedb *namedb = NULL;
+ struct nvkm_handle *handle = NULL;
+ u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+ u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x0f000000) >> 24;
+ u32 subc = (addr & 0x0000e000) >> 13;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(priv, 0x400180 + subc * 4) & 0xff;
+ u32 inst = (nv_rd32(priv, 0x40016c) & 0xffff) << 4;
+ u32 show = stat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ chan = priv->chan[chid];
+ if (chan)
+ namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (stat & NV_PGRAPH_INTR_NOTIFY) {
+ if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+ handle = nvkm_namedb_get_vinst(namedb, inst);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~NV_PGRAPH_INTR_NOTIFY;
+ }
+ }
+
+ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ nv04_gr_context_switch(priv);
+ }
+
+ nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+ nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show) {
+ nv_error(priv, "%s", "");
+ nvkm_bitfield_print(nv04_gr_intr_name, show);
+ pr_cont(" nsource:");
+ nvkm_bitfield_print(nv04_gr_nsource, nsource);
+ pr_cont(" nstatus:");
+ nvkm_bitfield_print(nv04_gr_nstatus, nstatus);
+ pr_cont("\n");
+ nv_error(priv,
+ "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, nvkm_client_name(chan), subc, class, mthd,
+ data);
+ }
+
+ nvkm_namedb_put(handle);
+}
+
+static int
+nv04_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv04_gr_intr;
+ nv_engine(priv)->cclass = &nv04_gr_cclass;
+ nv_engine(priv)->sclass = nv04_gr_sclass;
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+static int
+nv04_gr_init(struct nvkm_object *object)
+{
+ struct nvkm_engine *engine = nv_engine(object);
+ struct nv04_gr_priv *priv = (void *)engine;
+ int ret;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* Enable PGRAPH interrupts */
+ nv_wr32(priv, NV03_PGRAPH_INTR, 0xFFFFFFFF);
+ nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(priv, NV04_PGRAPH_VALID1, 0);
+ nv_wr32(priv, NV04_PGRAPH_VALID2, 0);
+ /*nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x000001FF);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x001FFFFF);*/
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x1231c000);
+ /*1231C000 blob, 001 haiku*/
+ /*V_WRITE(NV04_PGRAPH_DEBUG_1, 0xf2d91100);*/
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x72111100);
+ /*0x72111100 blob , 01 haiku*/
+ /*nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f870);*/
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x11d5f071);
+ /*haiku same*/
+
+ /*nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xfad4ff31);*/
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf0d4ff31);
+ /*haiku and blob 10d4*/
+
+ nv_wr32(priv, NV04_PGRAPH_STATE , 0xFFFFFFFF);
+ nv_wr32(priv, NV04_PGRAPH_CTX_CONTROL , 0x10000100);
+ nv_mask(priv, NV04_PGRAPH_CTX_USER, 0xff000000, 0x0f000000);
+
+ /* These don't belong here, they're part of a per-channel context */
+ nv_wr32(priv, NV04_PGRAPH_PATTERN_SHAPE, 0x00000000);
+ nv_wr32(priv, NV04_PGRAPH_BETA_AND , 0xFFFFFFFF);
+ return 0;
+}
+
+struct nvkm_oclass
+nv04_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_gr_ctor,
+ .dtor = _nvkm_gr_dtor,
+ .init = nv04_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
new file mode 100644
index 000000000000..389904eb603f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv10.c
@@ -0,0 +1,1315 @@
+/*
+ * Copyright 2007 Matthieu CASTET <castet.matthieu@free.fr>
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragr) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * PRECISION INSIGHT AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+#include <engine/gr.h>
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+
+struct pipe_state {
+ u32 pipe_0x0000[0x040/4];
+ u32 pipe_0x0040[0x010/4];
+ u32 pipe_0x0200[0x0c0/4];
+ u32 pipe_0x4400[0x080/4];
+ u32 pipe_0x6400[0x3b0/4];
+ u32 pipe_0x6800[0x2f0/4];
+ u32 pipe_0x6c00[0x030/4];
+ u32 pipe_0x7000[0x130/4];
+ u32 pipe_0x7400[0x0c0/4];
+ u32 pipe_0x7800[0x0c0/4];
+};
+
+static int nv10_gr_ctx_regs[] = {
+ NV10_PGRAPH_CTX_SWITCH(0),
+ NV10_PGRAPH_CTX_SWITCH(1),
+ NV10_PGRAPH_CTX_SWITCH(2),
+ NV10_PGRAPH_CTX_SWITCH(3),
+ NV10_PGRAPH_CTX_SWITCH(4),
+ NV10_PGRAPH_CTX_CACHE(0, 0),
+ NV10_PGRAPH_CTX_CACHE(0, 1),
+ NV10_PGRAPH_CTX_CACHE(0, 2),
+ NV10_PGRAPH_CTX_CACHE(0, 3),
+ NV10_PGRAPH_CTX_CACHE(0, 4),
+ NV10_PGRAPH_CTX_CACHE(1, 0),
+ NV10_PGRAPH_CTX_CACHE(1, 1),
+ NV10_PGRAPH_CTX_CACHE(1, 2),
+ NV10_PGRAPH_CTX_CACHE(1, 3),
+ NV10_PGRAPH_CTX_CACHE(1, 4),
+ NV10_PGRAPH_CTX_CACHE(2, 0),
+ NV10_PGRAPH_CTX_CACHE(2, 1),
+ NV10_PGRAPH_CTX_CACHE(2, 2),
+ NV10_PGRAPH_CTX_CACHE(2, 3),
+ NV10_PGRAPH_CTX_CACHE(2, 4),
+ NV10_PGRAPH_CTX_CACHE(3, 0),
+ NV10_PGRAPH_CTX_CACHE(3, 1),
+ NV10_PGRAPH_CTX_CACHE(3, 2),
+ NV10_PGRAPH_CTX_CACHE(3, 3),
+ NV10_PGRAPH_CTX_CACHE(3, 4),
+ NV10_PGRAPH_CTX_CACHE(4, 0),
+ NV10_PGRAPH_CTX_CACHE(4, 1),
+ NV10_PGRAPH_CTX_CACHE(4, 2),
+ NV10_PGRAPH_CTX_CACHE(4, 3),
+ NV10_PGRAPH_CTX_CACHE(4, 4),
+ NV10_PGRAPH_CTX_CACHE(5, 0),
+ NV10_PGRAPH_CTX_CACHE(5, 1),
+ NV10_PGRAPH_CTX_CACHE(5, 2),
+ NV10_PGRAPH_CTX_CACHE(5, 3),
+ NV10_PGRAPH_CTX_CACHE(5, 4),
+ NV10_PGRAPH_CTX_CACHE(6, 0),
+ NV10_PGRAPH_CTX_CACHE(6, 1),
+ NV10_PGRAPH_CTX_CACHE(6, 2),
+ NV10_PGRAPH_CTX_CACHE(6, 3),
+ NV10_PGRAPH_CTX_CACHE(6, 4),
+ NV10_PGRAPH_CTX_CACHE(7, 0),
+ NV10_PGRAPH_CTX_CACHE(7, 1),
+ NV10_PGRAPH_CTX_CACHE(7, 2),
+ NV10_PGRAPH_CTX_CACHE(7, 3),
+ NV10_PGRAPH_CTX_CACHE(7, 4),
+ NV10_PGRAPH_CTX_USER,
+ NV04_PGRAPH_DMA_START_0,
+ NV04_PGRAPH_DMA_START_1,
+ NV04_PGRAPH_DMA_LENGTH,
+ NV04_PGRAPH_DMA_MISC,
+ NV10_PGRAPH_DMA_PITCH,
+ NV04_PGRAPH_BOFFSET0,
+ NV04_PGRAPH_BBASE0,
+ NV04_PGRAPH_BLIMIT0,
+ NV04_PGRAPH_BOFFSET1,
+ NV04_PGRAPH_BBASE1,
+ NV04_PGRAPH_BLIMIT1,
+ NV04_PGRAPH_BOFFSET2,
+ NV04_PGRAPH_BBASE2,
+ NV04_PGRAPH_BLIMIT2,
+ NV04_PGRAPH_BOFFSET3,
+ NV04_PGRAPH_BBASE3,
+ NV04_PGRAPH_BLIMIT3,
+ NV04_PGRAPH_BOFFSET4,
+ NV04_PGRAPH_BBASE4,
+ NV04_PGRAPH_BLIMIT4,
+ NV04_PGRAPH_BOFFSET5,
+ NV04_PGRAPH_BBASE5,
+ NV04_PGRAPH_BLIMIT5,
+ NV04_PGRAPH_BPITCH0,
+ NV04_PGRAPH_BPITCH1,
+ NV04_PGRAPH_BPITCH2,
+ NV04_PGRAPH_BPITCH3,
+ NV04_PGRAPH_BPITCH4,
+ NV10_PGRAPH_SURFACE,
+ NV10_PGRAPH_STATE,
+ NV04_PGRAPH_BSWIZZLE2,
+ NV04_PGRAPH_BSWIZZLE5,
+ NV04_PGRAPH_BPIXEL,
+ NV10_PGRAPH_NOTIFY,
+ NV04_PGRAPH_PATT_COLOR0,
+ NV04_PGRAPH_PATT_COLOR1,
+ NV04_PGRAPH_PATT_COLORRAM, /* 64 values from 0x400900 to 0x4009fc */
+ 0x00400904,
+ 0x00400908,
+ 0x0040090c,
+ 0x00400910,
+ 0x00400914,
+ 0x00400918,
+ 0x0040091c,
+ 0x00400920,
+ 0x00400924,
+ 0x00400928,
+ 0x0040092c,
+ 0x00400930,
+ 0x00400934,
+ 0x00400938,
+ 0x0040093c,
+ 0x00400940,
+ 0x00400944,
+ 0x00400948,
+ 0x0040094c,
+ 0x00400950,
+ 0x00400954,
+ 0x00400958,
+ 0x0040095c,
+ 0x00400960,
+ 0x00400964,
+ 0x00400968,
+ 0x0040096c,
+ 0x00400970,
+ 0x00400974,
+ 0x00400978,
+ 0x0040097c,
+ 0x00400980,
+ 0x00400984,
+ 0x00400988,
+ 0x0040098c,
+ 0x00400990,
+ 0x00400994,
+ 0x00400998,
+ 0x0040099c,
+ 0x004009a0,
+ 0x004009a4,
+ 0x004009a8,
+ 0x004009ac,
+ 0x004009b0,
+ 0x004009b4,
+ 0x004009b8,
+ 0x004009bc,
+ 0x004009c0,
+ 0x004009c4,
+ 0x004009c8,
+ 0x004009cc,
+ 0x004009d0,
+ 0x004009d4,
+ 0x004009d8,
+ 0x004009dc,
+ 0x004009e0,
+ 0x004009e4,
+ 0x004009e8,
+ 0x004009ec,
+ 0x004009f0,
+ 0x004009f4,
+ 0x004009f8,
+ 0x004009fc,
+ NV04_PGRAPH_PATTERN, /* 2 values from 0x400808 to 0x40080c */
+ 0x0040080c,
+ NV04_PGRAPH_PATTERN_SHAPE,
+ NV03_PGRAPH_MONO_COLOR0,
+ NV04_PGRAPH_ROP3,
+ NV04_PGRAPH_CHROMA,
+ NV04_PGRAPH_BETA_AND,
+ NV04_PGRAPH_BETA_PREMULT,
+ 0x00400e70,
+ 0x00400e74,
+ 0x00400e78,
+ 0x00400e7c,
+ 0x00400e80,
+ 0x00400e84,
+ 0x00400e88,
+ 0x00400e8c,
+ 0x00400ea0,
+ 0x00400ea4,
+ 0x00400ea8,
+ 0x00400e90,
+ 0x00400e94,
+ 0x00400e98,
+ 0x00400e9c,
+ NV10_PGRAPH_WINDOWCLIP_HORIZONTAL, /* 8 values from 0x400f00-0x400f1c */
+ NV10_PGRAPH_WINDOWCLIP_VERTICAL, /* 8 values from 0x400f20-0x400f3c */
+ 0x00400f04,
+ 0x00400f24,
+ 0x00400f08,
+ 0x00400f28,
+ 0x00400f0c,
+ 0x00400f2c,
+ 0x00400f10,
+ 0x00400f30,
+ 0x00400f14,
+ 0x00400f34,
+ 0x00400f18,
+ 0x00400f38,
+ 0x00400f1c,
+ 0x00400f3c,
+ NV10_PGRAPH_XFMODE0,
+ NV10_PGRAPH_XFMODE1,
+ NV10_PGRAPH_GLOBALSTATE0,
+ NV10_PGRAPH_GLOBALSTATE1,
+ NV04_PGRAPH_STORED_FMT,
+ NV04_PGRAPH_SOURCE_COLOR,
+ NV03_PGRAPH_ABS_X_RAM, /* 32 values from 0x400400 to 0x40047c */
+ NV03_PGRAPH_ABS_Y_RAM, /* 32 values from 0x400480 to 0x4004fc */
+ 0x00400404,
+ 0x00400484,
+ 0x00400408,
+ 0x00400488,
+ 0x0040040c,
+ 0x0040048c,
+ 0x00400410,
+ 0x00400490,
+ 0x00400414,
+ 0x00400494,
+ 0x00400418,
+ 0x00400498,
+ 0x0040041c,
+ 0x0040049c,
+ 0x00400420,
+ 0x004004a0,
+ 0x00400424,
+ 0x004004a4,
+ 0x00400428,
+ 0x004004a8,
+ 0x0040042c,
+ 0x004004ac,
+ 0x00400430,
+ 0x004004b0,
+ 0x00400434,
+ 0x004004b4,
+ 0x00400438,
+ 0x004004b8,
+ 0x0040043c,
+ 0x004004bc,
+ 0x00400440,
+ 0x004004c0,
+ 0x00400444,
+ 0x004004c4,
+ 0x00400448,
+ 0x004004c8,
+ 0x0040044c,
+ 0x004004cc,
+ 0x00400450,
+ 0x004004d0,
+ 0x00400454,
+ 0x004004d4,
+ 0x00400458,
+ 0x004004d8,
+ 0x0040045c,
+ 0x004004dc,
+ 0x00400460,
+ 0x004004e0,
+ 0x00400464,
+ 0x004004e4,
+ 0x00400468,
+ 0x004004e8,
+ 0x0040046c,
+ 0x004004ec,
+ 0x00400470,
+ 0x004004f0,
+ 0x00400474,
+ 0x004004f4,
+ 0x00400478,
+ 0x004004f8,
+ 0x0040047c,
+ 0x004004fc,
+ NV03_PGRAPH_ABS_UCLIP_XMIN,
+ NV03_PGRAPH_ABS_UCLIP_XMAX,
+ NV03_PGRAPH_ABS_UCLIP_YMIN,
+ NV03_PGRAPH_ABS_UCLIP_YMAX,
+ 0x00400550,
+ 0x00400558,
+ 0x00400554,
+ 0x0040055c,
+ NV03_PGRAPH_ABS_UCLIPA_XMIN,
+ NV03_PGRAPH_ABS_UCLIPA_XMAX,
+ NV03_PGRAPH_ABS_UCLIPA_YMIN,
+ NV03_PGRAPH_ABS_UCLIPA_YMAX,
+ NV03_PGRAPH_ABS_ICLIP_XMAX,
+ NV03_PGRAPH_ABS_ICLIP_YMAX,
+ NV03_PGRAPH_XY_LOGIC_MISC0,
+ NV03_PGRAPH_XY_LOGIC_MISC1,
+ NV03_PGRAPH_XY_LOGIC_MISC2,
+ NV03_PGRAPH_XY_LOGIC_MISC3,
+ NV03_PGRAPH_CLIPX_0,
+ NV03_PGRAPH_CLIPX_1,
+ NV03_PGRAPH_CLIPY_0,
+ NV03_PGRAPH_CLIPY_1,
+ NV10_PGRAPH_COMBINER0_IN_ALPHA,
+ NV10_PGRAPH_COMBINER1_IN_ALPHA,
+ NV10_PGRAPH_COMBINER0_IN_RGB,
+ NV10_PGRAPH_COMBINER1_IN_RGB,
+ NV10_PGRAPH_COMBINER_COLOR0,
+ NV10_PGRAPH_COMBINER_COLOR1,
+ NV10_PGRAPH_COMBINER0_OUT_ALPHA,
+ NV10_PGRAPH_COMBINER1_OUT_ALPHA,
+ NV10_PGRAPH_COMBINER0_OUT_RGB,
+ NV10_PGRAPH_COMBINER1_OUT_RGB,
+ NV10_PGRAPH_COMBINER_FINAL0,
+ NV10_PGRAPH_COMBINER_FINAL1,
+ 0x00400e00,
+ 0x00400e04,
+ 0x00400e08,
+ 0x00400e0c,
+ 0x00400e10,
+ 0x00400e14,
+ 0x00400e18,
+ 0x00400e1c,
+ 0x00400e20,
+ 0x00400e24,
+ 0x00400e28,
+ 0x00400e2c,
+ 0x00400e30,
+ 0x00400e34,
+ 0x00400e38,
+ 0x00400e3c,
+ NV04_PGRAPH_PASSTHRU_0,
+ NV04_PGRAPH_PASSTHRU_1,
+ NV04_PGRAPH_PASSTHRU_2,
+ NV10_PGRAPH_DIMX_TEXTURE,
+ NV10_PGRAPH_WDIMX_TEXTURE,
+ NV10_PGRAPH_DVD_COLORFMT,
+ NV10_PGRAPH_SCALED_FORMAT,
+ NV04_PGRAPH_MISC24_0,
+ NV04_PGRAPH_MISC24_1,
+ NV04_PGRAPH_MISC24_2,
+ NV03_PGRAPH_X_MISC,
+ NV03_PGRAPH_Y_MISC,
+ NV04_PGRAPH_VALID1,
+ NV04_PGRAPH_VALID2,
+};
+
+static int nv17_gr_ctx_regs[] = {
+ NV10_PGRAPH_DEBUG_4,
+ 0x004006b0,
+ 0x00400eac,
+ 0x00400eb0,
+ 0x00400eb4,
+ 0x00400eb8,
+ 0x00400ebc,
+ 0x00400ec0,
+ 0x00400ec4,
+ 0x00400ec8,
+ 0x00400ecc,
+ 0x00400ed0,
+ 0x00400ed4,
+ 0x00400ed8,
+ 0x00400edc,
+ 0x00400ee0,
+ 0x00400a00,
+ 0x00400a04,
+};
+
+struct nv10_gr_priv {
+ struct nvkm_gr base;
+ struct nv10_gr_chan *chan[32];
+ spinlock_t lock;
+};
+
+struct nv10_gr_chan {
+ struct nvkm_object base;
+ int chid;
+ int nv10[ARRAY_SIZE(nv10_gr_ctx_regs)];
+ int nv17[ARRAY_SIZE(nv17_gr_ctx_regs)];
+ struct pipe_state pipe_state;
+ u32 lma_window[4];
+};
+
+
+static inline struct nv10_gr_priv *
+nv10_gr_priv(struct nv10_gr_chan *chan)
+{
+ return (void *)nv_object(chan)->engine;
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+#define PIPE_SAVE(priv, state, addr) \
+ do { \
+ int __i; \
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \
+ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \
+ state[__i] = nv_rd32(priv, NV10_PGRAPH_PIPE_DATA); \
+ } while (0)
+
+#define PIPE_RESTORE(priv, state, addr) \
+ do { \
+ int __i; \
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, addr); \
+ for (__i = 0; __i < ARRAY_SIZE(state); __i++) \
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, state[__i]); \
+ } while (0)
+
+static struct nvkm_oclass
+nv10_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs }, /* null */
+ { 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs }, /* pattern */
+ { 0x004a, &nv04_gr_ofuncs }, /* gdi */
+ { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+ { 0x005f, &nv04_gr_ofuncs }, /* blit */
+ { 0x0062, &nv04_gr_ofuncs }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs }, /* ifc */
+ { 0x009f, &nv04_gr_ofuncs }, /* blit */
+ { 0x0093, &nv04_gr_ofuncs }, /* surf3d */
+ { 0x0094, &nv04_gr_ofuncs }, /* ttri */
+ { 0x0095, &nv04_gr_ofuncs }, /* mtri */
+ { 0x0056, &nv04_gr_ofuncs }, /* celcius */
+ {},
+};
+
+static struct nvkm_oclass
+nv15_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs }, /* null */
+ { 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs }, /* pattern */
+ { 0x004a, &nv04_gr_ofuncs }, /* gdi */
+ { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+ { 0x005f, &nv04_gr_ofuncs }, /* blit */
+ { 0x0062, &nv04_gr_ofuncs }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs }, /* ifc */
+ { 0x009f, &nv04_gr_ofuncs }, /* blit */
+ { 0x0093, &nv04_gr_ofuncs }, /* surf3d */
+ { 0x0094, &nv04_gr_ofuncs }, /* ttri */
+ { 0x0095, &nv04_gr_ofuncs }, /* mtri */
+ { 0x0096, &nv04_gr_ofuncs }, /* celcius */
+ {},
+};
+
+static int
+nv17_gr_mthd_lma_window(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv10_gr_chan *chan = (void *)object->parent;
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ struct pipe_state *pipe = &chan->pipe_state;
+ u32 pipe_0x0040[1], pipe_0x64c0[8], pipe_0x6a80[3], pipe_0x6ab0[3];
+ u32 xfmode0, xfmode1;
+ u32 data = *(u32 *)args;
+ int i;
+
+ chan->lma_window[(mthd - 0x1638) / 4] = data;
+
+ if (mthd != 0x1644)
+ return 0;
+
+ nv04_gr_idle(priv);
+
+ PIPE_SAVE(priv, pipe_0x0040, 0x0040);
+ PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+
+ PIPE_RESTORE(priv, chan->lma_window, 0x6790);
+
+ nv04_gr_idle(priv);
+
+ xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+ xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+
+ PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+ PIPE_SAVE(priv, pipe_0x64c0, 0x64c0);
+ PIPE_SAVE(priv, pipe_0x6ab0, 0x6ab0);
+ PIPE_SAVE(priv, pipe_0x6a80, 0x6a80);
+
+ nv04_gr_idle(priv);
+
+ nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+ nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+ for (i = 0; i < 4; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+ for (i = 0; i < 4; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+ for (i = 0; i < 3; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+ for (i = 0; i < 3; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+ PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+
+ nv04_gr_idle(priv);
+
+ PIPE_RESTORE(priv, pipe_0x0040, 0x0040);
+
+ nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+ nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+
+ PIPE_RESTORE(priv, pipe_0x64c0, 0x64c0);
+ PIPE_RESTORE(priv, pipe_0x6ab0, 0x6ab0);
+ PIPE_RESTORE(priv, pipe_0x6a80, 0x6a80);
+ PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000000c0);
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv04_gr_idle(priv);
+
+ return 0;
+}
+
+static int
+nv17_gr_mthd_lma_enable(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv10_gr_chan *chan = (void *)object->parent;
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+
+ nv04_gr_idle(priv);
+
+ nv_mask(priv, NV10_PGRAPH_DEBUG_4, 0x00000100, 0x00000100);
+ nv_mask(priv, 0x4006b0, 0x08000000, 0x08000000);
+ return 0;
+}
+
+static struct nvkm_omthds
+nv17_celcius_omthds[] = {
+ { 0x1638, 0x1638, nv17_gr_mthd_lma_window },
+ { 0x163c, 0x163c, nv17_gr_mthd_lma_window },
+ { 0x1640, 0x1640, nv17_gr_mthd_lma_window },
+ { 0x1644, 0x1644, nv17_gr_mthd_lma_window },
+ { 0x1658, 0x1658, nv17_gr_mthd_lma_enable },
+ {}
+};
+
+static struct nvkm_oclass
+nv17_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs }, /* null */
+ { 0x0039, &nv04_gr_ofuncs }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs }, /* pattern */
+ { 0x004a, &nv04_gr_ofuncs }, /* gdi */
+ { 0x0052, &nv04_gr_ofuncs }, /* swzsurf */
+ { 0x005f, &nv04_gr_ofuncs }, /* blit */
+ { 0x0062, &nv04_gr_ofuncs }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs }, /* ifc */
+ { 0x009f, &nv04_gr_ofuncs }, /* blit */
+ { 0x0093, &nv04_gr_ofuncs }, /* surf3d */
+ { 0x0094, &nv04_gr_ofuncs }, /* ttri */
+ { 0x0095, &nv04_gr_ofuncs }, /* mtri */
+ { 0x0099, &nv04_gr_ofuncs, nv17_celcius_omthds },
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static struct nv10_gr_chan *
+nv10_gr_channel(struct nv10_gr_priv *priv)
+{
+ struct nv10_gr_chan *chan = NULL;
+ if (nv_rd32(priv, 0x400144) & 0x00010000) {
+ int chid = nv_rd32(priv, 0x400148) >> 24;
+ if (chid < ARRAY_SIZE(priv->chan))
+ chan = priv->chan[chid];
+ }
+ return chan;
+}
+
+static void
+nv10_gr_save_pipe(struct nv10_gr_chan *chan)
+{
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ struct pipe_state *pipe = &chan->pipe_state;
+
+ PIPE_SAVE(priv, pipe->pipe_0x4400, 0x4400);
+ PIPE_SAVE(priv, pipe->pipe_0x0200, 0x0200);
+ PIPE_SAVE(priv, pipe->pipe_0x6400, 0x6400);
+ PIPE_SAVE(priv, pipe->pipe_0x6800, 0x6800);
+ PIPE_SAVE(priv, pipe->pipe_0x6c00, 0x6c00);
+ PIPE_SAVE(priv, pipe->pipe_0x7000, 0x7000);
+ PIPE_SAVE(priv, pipe->pipe_0x7400, 0x7400);
+ PIPE_SAVE(priv, pipe->pipe_0x7800, 0x7800);
+ PIPE_SAVE(priv, pipe->pipe_0x0040, 0x0040);
+ PIPE_SAVE(priv, pipe->pipe_0x0000, 0x0000);
+}
+
+static void
+nv10_gr_load_pipe(struct nv10_gr_chan *chan)
+{
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ struct pipe_state *pipe = &chan->pipe_state;
+ u32 xfmode0, xfmode1;
+ int i;
+
+ nv04_gr_idle(priv);
+ /* XXX check haiku comments */
+ xfmode0 = nv_rd32(priv, NV10_PGRAPH_XFMODE0);
+ xfmode1 = nv_rd32(priv, NV10_PGRAPH_XFMODE1);
+ nv_wr32(priv, NV10_PGRAPH_XFMODE0, 0x10000000);
+ nv_wr32(priv, NV10_PGRAPH_XFMODE1, 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x000064c0);
+ for (i = 0; i < 4; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+ for (i = 0; i < 4; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006ab0);
+ for (i = 0; i < 3; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x3f800000);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00006a80);
+ for (i = 0; i < 3; i++)
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000000);
+
+ nv_wr32(priv, NV10_PGRAPH_PIPE_ADDRESS, 0x00000040);
+ nv_wr32(priv, NV10_PGRAPH_PIPE_DATA, 0x00000008);
+
+
+ PIPE_RESTORE(priv, pipe->pipe_0x0200, 0x0200);
+ nv04_gr_idle(priv);
+
+ /* restore XFMODE */
+ nv_wr32(priv, NV10_PGRAPH_XFMODE0, xfmode0);
+ nv_wr32(priv, NV10_PGRAPH_XFMODE1, xfmode1);
+ PIPE_RESTORE(priv, pipe->pipe_0x6400, 0x6400);
+ PIPE_RESTORE(priv, pipe->pipe_0x6800, 0x6800);
+ PIPE_RESTORE(priv, pipe->pipe_0x6c00, 0x6c00);
+ PIPE_RESTORE(priv, pipe->pipe_0x7000, 0x7000);
+ PIPE_RESTORE(priv, pipe->pipe_0x7400, 0x7400);
+ PIPE_RESTORE(priv, pipe->pipe_0x7800, 0x7800);
+ PIPE_RESTORE(priv, pipe->pipe_0x4400, 0x4400);
+ PIPE_RESTORE(priv, pipe->pipe_0x0000, 0x0000);
+ PIPE_RESTORE(priv, pipe->pipe_0x0040, 0x0040);
+ nv04_gr_idle(priv);
+}
+
+static void
+nv10_gr_create_pipe(struct nv10_gr_chan *chan)
+{
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ struct pipe_state *pipe_state = &chan->pipe_state;
+ u32 *pipe_state_addr;
+ int i;
+#define PIPE_INIT(addr) \
+ do { \
+ pipe_state_addr = pipe_state->pipe_##addr; \
+ } while (0)
+#define PIPE_INIT_END(addr) \
+ do { \
+ u32 *__end_addr = pipe_state->pipe_##addr + \
+ ARRAY_SIZE(pipe_state->pipe_##addr); \
+ if (pipe_state_addr != __end_addr) \
+ nv_error(priv, "incomplete pipe init for 0x%x : %p/%p\n", \
+ addr, pipe_state_addr, __end_addr); \
+ } while (0)
+#define NV_WRITE_PIPE_INIT(value) *(pipe_state_addr++) = value
+
+ PIPE_INIT(0x0200);
+ for (i = 0; i < 48; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x0200);
+
+ PIPE_INIT(0x6400);
+ for (i = 0; i < 211; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ NV_WRITE_PIPE_INIT(0x40000000);
+ NV_WRITE_PIPE_INIT(0x40000000);
+ NV_WRITE_PIPE_INIT(0x40000000);
+ NV_WRITE_PIPE_INIT(0x40000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x3f000000);
+ NV_WRITE_PIPE_INIT(0x3f000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ PIPE_INIT_END(0x6400);
+
+ PIPE_INIT(0x6800);
+ for (i = 0; i < 162; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x3f800000);
+ for (i = 0; i < 25; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x6800);
+
+ PIPE_INIT(0x6c00);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0xbf800000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x6c00);
+
+ PIPE_INIT(0x7000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x00000000);
+ NV_WRITE_PIPE_INIT(0x7149f2ca);
+ for (i = 0; i < 35; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x7000);
+
+ PIPE_INIT(0x7400);
+ for (i = 0; i < 48; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x7400);
+
+ PIPE_INIT(0x7800);
+ for (i = 0; i < 48; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x7800);
+
+ PIPE_INIT(0x4400);
+ for (i = 0; i < 32; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x4400);
+
+ PIPE_INIT(0x0000);
+ for (i = 0; i < 16; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x0000);
+
+ PIPE_INIT(0x0040);
+ for (i = 0; i < 4; i++)
+ NV_WRITE_PIPE_INIT(0x00000000);
+ PIPE_INIT_END(0x0040);
+
+#undef PIPE_INIT
+#undef PIPE_INIT_END
+#undef NV_WRITE_PIPE_INIT
+}
+
+static int
+nv10_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++) {
+ if (nv10_gr_ctx_regs[i] == reg)
+ return i;
+ }
+ nv_error(priv, "unknow offset nv10_ctx_regs %d\n", reg);
+ return -1;
+}
+
+static int
+nv17_gr_ctx_regs_find_offset(struct nv10_gr_priv *priv, int reg)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++) {
+ if (nv17_gr_ctx_regs[i] == reg)
+ return i;
+ }
+ nv_error(priv, "unknow offset nv17_ctx_regs %d\n", reg);
+ return -1;
+}
+
+static void
+nv10_gr_load_dma_vtxbuf(struct nv10_gr_chan *chan, int chid, u32 inst)
+{
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ u32 st2, st2_dl, st2_dh, fifo_ptr, fifo[0x60/4];
+ u32 ctx_user, ctx_switch[5];
+ int i, subchan = -1;
+
+ /* NV10TCL_DMA_VTXBUF (method 0x18c) modifies hidden state
+ * that cannot be restored via MMIO. Do it through the FIFO
+ * instead.
+ */
+
+ /* Look for a celsius object */
+ for (i = 0; i < 8; i++) {
+ int class = nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(i, 0)) & 0xfff;
+
+ if (class == 0x56 || class == 0x96 || class == 0x99) {
+ subchan = i;
+ break;
+ }
+ }
+
+ if (subchan < 0 || !inst)
+ return;
+
+ /* Save the current ctx object */
+ ctx_user = nv_rd32(priv, NV10_PGRAPH_CTX_USER);
+ for (i = 0; i < 5; i++)
+ ctx_switch[i] = nv_rd32(priv, NV10_PGRAPH_CTX_SWITCH(i));
+
+ /* Save the FIFO state */
+ st2 = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2);
+ st2_dl = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DL);
+ st2_dh = nv_rd32(priv, NV10_PGRAPH_FFINTFC_ST2_DH);
+ fifo_ptr = nv_rd32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR);
+
+ for (i = 0; i < ARRAY_SIZE(fifo); i++)
+ fifo[i] = nv_rd32(priv, 0x4007a0 + 4 * i);
+
+ /* Switch to the celsius subchannel */
+ for (i = 0; i < 5; i++)
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i),
+ nv_rd32(priv, NV10_PGRAPH_CTX_CACHE(subchan, i)));
+ nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xe000, subchan << 13);
+
+ /* Inject NV10TCL_DMA_VTXBUF */
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, 0);
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2,
+ 0x2c000000 | chid << 20 | subchan << 16 | 0x18c);
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, inst);
+ nv_mask(priv, NV10_PGRAPH_CTX_CONTROL, 0, 0x10000);
+ nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+ nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+
+ /* Restore the FIFO state */
+ for (i = 0; i < ARRAY_SIZE(fifo); i++)
+ nv_wr32(priv, 0x4007a0 + 4 * i, fifo[i]);
+
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_FIFO_PTR, fifo_ptr);
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, st2);
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DL, st2_dl);
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2_DH, st2_dh);
+
+ /* Restore the current ctx object */
+ for (i = 0; i < 5; i++)
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(i), ctx_switch[i]);
+ nv_wr32(priv, NV10_PGRAPH_CTX_USER, ctx_user);
+}
+
+static int
+nv10_gr_load_context(struct nv10_gr_chan *chan, int chid)
+{
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ u32 inst;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
+ nv_wr32(priv, nv10_gr_ctx_regs[i], chan->nv10[i]);
+
+ if (nv_device(priv)->card_type >= NV_11 &&
+ nv_device(priv)->chipset >= 0x17) {
+ for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
+ nv_wr32(priv, nv17_gr_ctx_regs[i], chan->nv17[i]);
+ }
+
+ nv10_gr_load_pipe(chan);
+
+ inst = nv_rd32(priv, NV10_PGRAPH_GLOBALSTATE1) & 0xffff;
+ nv10_gr_load_dma_vtxbuf(chan, chid, inst);
+
+ nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+ nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, chid << 24);
+ nv_mask(priv, NV10_PGRAPH_FFINTFC_ST2, 0x30000000, 0x00000000);
+ return 0;
+}
+
+static int
+nv10_gr_unload_context(struct nv10_gr_chan *chan)
+{
+ struct nv10_gr_priv *priv = nv10_gr_priv(chan);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(nv10_gr_ctx_regs); i++)
+ chan->nv10[i] = nv_rd32(priv, nv10_gr_ctx_regs[i]);
+
+ if (nv_device(priv)->card_type >= NV_11 &&
+ nv_device(priv)->chipset >= 0x17) {
+ for (i = 0; i < ARRAY_SIZE(nv17_gr_ctx_regs); i++)
+ chan->nv17[i] = nv_rd32(priv, nv17_gr_ctx_regs[i]);
+ }
+
+ nv10_gr_save_pipe(chan);
+
+ nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000000);
+ nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+ return 0;
+}
+
+static void
+nv10_gr_context_switch(struct nv10_gr_priv *priv)
+{
+ struct nv10_gr_chan *prev = NULL;
+ struct nv10_gr_chan *next = NULL;
+ unsigned long flags;
+ int chid;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ nv04_gr_idle(priv);
+
+ /* If previous context is valid, we need to save it */
+ prev = nv10_gr_channel(priv);
+ if (prev)
+ nv10_gr_unload_context(prev);
+
+ /* load context for next channel */
+ chid = (nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR) >> 20) & 0x1f;
+ next = priv->chan[chid];
+ if (next)
+ nv10_gr_load_context(next, chid);
+
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+#define NV_WRITE_CTX(reg, val) do { \
+ int offset = nv10_gr_ctx_regs_find_offset(priv, reg); \
+ if (offset > 0) \
+ chan->nv10[offset] = val; \
+ } while (0)
+
+#define NV17_WRITE_CTX(reg, val) do { \
+ int offset = nv17_gr_ctx_regs_find_offset(priv, reg); \
+ if (offset > 0) \
+ chan->nv17[offset] = val; \
+ } while (0)
+
+static int
+nv10_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fifo_chan *fifo = (void *)parent;
+ struct nv10_gr_priv *priv = (void *)engine;
+ struct nv10_gr_chan *chan;
+ unsigned long flags;
+ int ret;
+
+ ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (priv->chan[fifo->chid]) {
+ *pobject = nv_object(priv->chan[fifo->chid]);
+ atomic_inc(&(*pobject)->refcount);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ nvkm_object_destroy(&chan->base);
+ return 1;
+ }
+
+ NV_WRITE_CTX(0x00400e88, 0x08000000);
+ NV_WRITE_CTX(0x00400e9c, 0x4b7fffff);
+ NV_WRITE_CTX(NV03_PGRAPH_XY_LOGIC_MISC0, 0x0001ffff);
+ NV_WRITE_CTX(0x00400e10, 0x00001000);
+ NV_WRITE_CTX(0x00400e14, 0x00001000);
+ NV_WRITE_CTX(0x00400e30, 0x00080008);
+ NV_WRITE_CTX(0x00400e34, 0x00080008);
+ if (nv_device(priv)->card_type >= NV_11 &&
+ nv_device(priv)->chipset >= 0x17) {
+ /* is it really needed ??? */
+ NV17_WRITE_CTX(NV10_PGRAPH_DEBUG_4,
+ nv_rd32(priv, NV10_PGRAPH_DEBUG_4));
+ NV17_WRITE_CTX(0x004006b0, nv_rd32(priv, 0x004006b0));
+ NV17_WRITE_CTX(0x00400eac, 0x0fff0000);
+ NV17_WRITE_CTX(0x00400eb0, 0x0fff0000);
+ NV17_WRITE_CTX(0x00400ec0, 0x00000080);
+ NV17_WRITE_CTX(0x00400ed0, 0x00000080);
+ }
+ NV_WRITE_CTX(NV10_PGRAPH_CTX_USER, chan->chid << 24);
+
+ nv10_gr_create_pipe(chan);
+
+ priv->chan[fifo->chid] = chan;
+ chan->chid = fifo->chid;
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return 0;
+}
+
+static void
+nv10_gr_context_dtor(struct nvkm_object *object)
+{
+ struct nv10_gr_priv *priv = (void *)object->engine;
+ struct nv10_gr_chan *chan = (void *)object;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ priv->chan[chan->chid] = NULL;
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ nvkm_object_destroy(&chan->base);
+}
+
+static int
+nv10_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv10_gr_priv *priv = (void *)object->engine;
+ struct nv10_gr_chan *chan = (void *)object;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000000);
+ if (nv10_gr_channel(priv) == chan)
+ nv10_gr_unload_context(chan);
+ nv_mask(priv, NV04_PGRAPH_FIFO, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ return nvkm_object_fini(&chan->base, suspend);
+}
+
+static struct nvkm_oclass
+nv10_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x10),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv10_gr_context_ctor,
+ .dtor = nv10_gr_context_dtor,
+ .init = nvkm_object_init,
+ .fini = nv10_gr_context_fini,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv10_gr_tile_prog(struct nvkm_engine *engine, int i)
+{
+ struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+ struct nvkm_fifo *pfifo = nvkm_fifo(engine);
+ struct nv10_gr_priv *priv = (void *)engine;
+ unsigned long flags;
+
+ pfifo->pause(pfifo, &flags);
+ nv04_gr_idle(priv);
+
+ nv_wr32(priv, NV10_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(priv, NV10_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(priv, NV10_PGRAPH_TILE(i), tile->addr);
+
+ pfifo->start(pfifo, &flags);
+}
+
+const struct nvkm_bitfield nv10_gr_intr_name[] = {
+ { NV_PGRAPH_INTR_NOTIFY, "NOTIFY" },
+ { NV_PGRAPH_INTR_ERROR, "ERROR" },
+ {}
+};
+
+const struct nvkm_bitfield nv10_gr_nstatus[] = {
+ { NV10_PGRAPH_NSTATUS_STATE_IN_USE, "STATE_IN_USE" },
+ { NV10_PGRAPH_NSTATUS_INVALID_STATE, "INVALID_STATE" },
+ { NV10_PGRAPH_NSTATUS_BAD_ARGUMENT, "BAD_ARGUMENT" },
+ { NV10_PGRAPH_NSTATUS_PROTECTION_FAULT, "PROTECTION_FAULT" },
+ {}
+};
+
+static void
+nv10_gr_intr(struct nvkm_subdev *subdev)
+{
+ struct nv10_gr_priv *priv = (void *)subdev;
+ struct nv10_gr_chan *chan = NULL;
+ struct nvkm_namedb *namedb = NULL;
+ struct nvkm_handle *handle = NULL;
+ u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+ u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x01f00000) >> 20;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+ u32 show = stat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ chan = priv->chan[chid];
+ if (chan)
+ namedb = (void *)nv_pclass(nv_object(chan), NV_NAMEDB_CLASS);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (stat & NV_PGRAPH_INTR_ERROR) {
+ if (chan && (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD)) {
+ handle = nvkm_namedb_get_class(namedb, class);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~NV_PGRAPH_INTR_ERROR;
+ }
+ }
+
+ if (stat & NV_PGRAPH_INTR_CONTEXT_SWITCH) {
+ nv_wr32(priv, NV03_PGRAPH_INTR, NV_PGRAPH_INTR_CONTEXT_SWITCH);
+ stat &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ show &= ~NV_PGRAPH_INTR_CONTEXT_SWITCH;
+ nv10_gr_context_switch(priv);
+ }
+
+ nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+ nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show) {
+ nv_error(priv, "%s", "");
+ nvkm_bitfield_print(nv10_gr_intr_name, show);
+ pr_cont(" nsource:");
+ nvkm_bitfield_print(nv04_gr_nsource, nsource);
+ pr_cont(" nstatus:");
+ nvkm_bitfield_print(nv10_gr_nstatus, nstatus);
+ pr_cont("\n");
+ nv_error(priv,
+ "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, nvkm_client_name(chan), subc, class, mthd,
+ data);
+ }
+
+ nvkm_namedb_put(handle);
+}
+
+static int
+nv10_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv10_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv10_gr_intr;
+ nv_engine(priv)->cclass = &nv10_gr_cclass;
+
+ if (nv_device(priv)->chipset <= 0x10)
+ nv_engine(priv)->sclass = nv10_gr_sclass;
+ else
+ if (nv_device(priv)->chipset < 0x17 ||
+ nv_device(priv)->card_type < NV_11)
+ nv_engine(priv)->sclass = nv15_gr_sclass;
+ else
+ nv_engine(priv)->sclass = nv17_gr_sclass;
+
+ nv_engine(priv)->tile_prog = nv10_gr_tile_prog;
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+static void
+nv10_gr_dtor(struct nvkm_object *object)
+{
+ struct nv10_gr_priv *priv = (void *)object;
+ nvkm_gr_destroy(&priv->base);
+}
+
+static int
+nv10_gr_init(struct nvkm_object *object)
+{
+ struct nvkm_engine *engine = nv_engine(object);
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ struct nv10_gr_priv *priv = (void *)engine;
+ int ret, i;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
+ nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+ /* nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x24E00810); */ /* 0x25f92ad9 */
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_2, 0x25f92ad9);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0x55DE0830 | (1 << 29) | (1 << 31));
+
+ if (nv_device(priv)->card_type >= NV_11 &&
+ nv_device(priv)->chipset >= 0x17) {
+ nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x1f000000);
+ nv_wr32(priv, 0x400a10, 0x03ff3fb6);
+ nv_wr32(priv, 0x400838, 0x002f8684);
+ nv_wr32(priv, 0x40083c, 0x00115f3f);
+ nv_wr32(priv, 0x4006b0, 0x40000020);
+ } else {
+ nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
+ }
+
+ /* Turn all the tiling regions off. */
+ for (i = 0; i < pfb->tile.regions; i++)
+ engine->tile_prog(engine, i);
+
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(0), 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(1), 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(2), 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(3), 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_CTX_SWITCH(4), 0x00000000);
+ nv_wr32(priv, NV10_PGRAPH_STATE, 0xFFFFFFFF);
+
+ nv_mask(priv, NV10_PGRAPH_CTX_USER, 0xff000000, 0x1f000000);
+ nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+ nv_wr32(priv, NV10_PGRAPH_FFINTFC_ST2, 0x08000000);
+ return 0;
+}
+
+static int
+nv10_gr_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv10_gr_priv *priv = (void *)object;
+ return nvkm_gr_fini(&priv->base, suspend);
+}
+
+struct nvkm_oclass
+nv10_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x10),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv10_gr_ctor,
+ .dtor = nv10_gr_dtor,
+ .init = nv10_gr_init,
+ .fini = nv10_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
new file mode 100644
index 000000000000..1713ffb669e8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.c
@@ -0,0 +1,376 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv20_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+ { 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */
+ { 0x0097, &nv04_gr_ofuncs, NULL }, /* kelvin */
+ { 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */
+ { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv20_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_chan *chan;
+ int ret, i;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x37f0,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ chan->chid = nvkm_fifo_chan(parent)->chid;
+
+ nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+ nv_wo32(chan, 0x033c, 0xffff0000);
+ nv_wo32(chan, 0x03a0, 0x0fff0000);
+ nv_wo32(chan, 0x03a4, 0x0fff0000);
+ nv_wo32(chan, 0x047c, 0x00000101);
+ nv_wo32(chan, 0x0490, 0x00000111);
+ nv_wo32(chan, 0x04a8, 0x44400000);
+ for (i = 0x04d4; i <= 0x04e0; i += 4)
+ nv_wo32(chan, i, 0x00030303);
+ for (i = 0x04f4; i <= 0x0500; i += 4)
+ nv_wo32(chan, i, 0x00080000);
+ for (i = 0x050c; i <= 0x0518; i += 4)
+ nv_wo32(chan, i, 0x01012000);
+ for (i = 0x051c; i <= 0x0528; i += 4)
+ nv_wo32(chan, i, 0x000105b8);
+ for (i = 0x052c; i <= 0x0538; i += 4)
+ nv_wo32(chan, i, 0x00080008);
+ for (i = 0x055c; i <= 0x0598; i += 4)
+ nv_wo32(chan, i, 0x07ff0000);
+ nv_wo32(chan, 0x05a4, 0x4b7fffff);
+ nv_wo32(chan, 0x05fc, 0x00000001);
+ nv_wo32(chan, 0x0604, 0x00004000);
+ nv_wo32(chan, 0x0610, 0x00000001);
+ nv_wo32(chan, 0x0618, 0x00040000);
+ nv_wo32(chan, 0x061c, 0x00010000);
+ for (i = 0x1c1c; i <= 0x248c; i += 16) {
+ nv_wo32(chan, (i + 0), 0x10700ff9);
+ nv_wo32(chan, (i + 4), 0x0436086c);
+ nv_wo32(chan, (i + 8), 0x000c001b);
+ }
+ nv_wo32(chan, 0x281c, 0x3f800000);
+ nv_wo32(chan, 0x2830, 0x3f800000);
+ nv_wo32(chan, 0x285c, 0x40000000);
+ nv_wo32(chan, 0x2860, 0x3f800000);
+ nv_wo32(chan, 0x2864, 0x3f000000);
+ nv_wo32(chan, 0x286c, 0x40000000);
+ nv_wo32(chan, 0x2870, 0x3f800000);
+ nv_wo32(chan, 0x2878, 0xbf800000);
+ nv_wo32(chan, 0x2880, 0xbf800000);
+ nv_wo32(chan, 0x34a4, 0x000fe000);
+ nv_wo32(chan, 0x3530, 0x000003f8);
+ nv_wo32(chan, 0x3540, 0x002fe000);
+ for (i = 0x355c; i <= 0x3578; i += 4)
+ nv_wo32(chan, i, 0x001c527c);
+ return 0;
+}
+
+int
+nv20_gr_context_init(struct nvkm_object *object)
+{
+ struct nv20_gr_priv *priv = (void *)object->engine;
+ struct nv20_gr_chan *chan = (void *)object;
+ int ret;
+
+ ret = nvkm_gr_context_init(&chan->base);
+ if (ret)
+ return ret;
+
+ nv_wo32(priv->ctxtab, chan->chid * 4, nv_gpuobj(chan)->addr >> 4);
+ return 0;
+}
+
+int
+nv20_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv20_gr_priv *priv = (void *)object->engine;
+ struct nv20_gr_chan *chan = (void *)object;
+ int chid = -1;
+
+ nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+ if (nv_rd32(priv, 0x400144) & 0x00010000)
+ chid = (nv_rd32(priv, 0x400148) & 0x1f000000) >> 24;
+ if (chan->chid == chid) {
+ nv_wr32(priv, 0x400784, nv_gpuobj(chan)->addr >> 4);
+ nv_wr32(priv, 0x400788, 0x00000002);
+ nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+ nv_wr32(priv, 0x400144, 0x10000000);
+ nv_mask(priv, 0x400148, 0xff000000, 0x1f000000);
+ }
+ nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
+
+ nv_wo32(priv->ctxtab, chan->chid * 4, 0x00000000);
+ return nvkm_gr_context_fini(&chan->base, suspend);
+}
+
+static struct nvkm_oclass
+nv20_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x20),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv20_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = nv20_gr_context_init,
+ .fini = nv20_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+void
+nv20_gr_tile_prog(struct nvkm_engine *engine, int i)
+{
+ struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+ struct nvkm_fifo *pfifo = nvkm_fifo(engine);
+ struct nv20_gr_priv *priv = (void *)engine;
+ unsigned long flags;
+
+ pfifo->pause(pfifo, &flags);
+ nv04_gr_idle(priv);
+
+ nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0030 + 4 * i);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->limit);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0050 + 4 * i);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->pitch);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0010 + 4 * i);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->addr);
+
+ if (nv_device(engine)->chipset != 0x34) {
+ nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00ea0090 + 4 * i);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, tile->zcomp);
+ }
+
+ pfifo->start(pfifo, &flags);
+}
+
+void
+nv20_gr_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct nvkm_handle *handle;
+ struct nv20_gr_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+ u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+ u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 chid = (addr & 0x01f00000) >> 20;
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xfff;
+ u32 show = stat;
+
+ engctx = nvkm_engctx_get(engine, chid);
+ if (stat & NV_PGRAPH_INTR_ERROR) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ handle = nvkm_handle_get_class(engctx, class);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~NV_PGRAPH_INTR_ERROR;
+ nvkm_handle_put(handle);
+ }
+ }
+
+ nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+ nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show) {
+ nv_error(priv, "%s", "");
+ nvkm_bitfield_print(nv10_gr_intr_name, show);
+ pr_cont(" nsource:");
+ nvkm_bitfield_print(nv04_gr_nsource, nsource);
+ pr_cont(" nstatus:");
+ nvkm_bitfield_print(nv10_gr_nstatus, nstatus);
+ pr_cont("\n");
+ nv_error(priv,
+ "ch %d [%s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, nvkm_client_name(engctx), subc, class, mthd,
+ data);
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static int
+nv20_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv20_gr_intr;
+ nv_engine(priv)->cclass = &nv20_gr_cclass;
+ nv_engine(priv)->sclass = nv20_gr_sclass;
+ nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+ return 0;
+}
+
+void
+nv20_gr_dtor(struct nvkm_object *object)
+{
+ struct nv20_gr_priv *priv = (void *)object;
+ nvkm_gpuobj_ref(NULL, &priv->ctxtab);
+ nvkm_gr_destroy(&priv->base);
+}
+
+int
+nv20_gr_init(struct nvkm_object *object)
+{
+ struct nvkm_engine *engine = nv_engine(object);
+ struct nv20_gr_priv *priv = (void *)engine;
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ u32 tmp, vramsz;
+ int ret, i;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
+
+ if (nv_device(priv)->chipset == 0x20) {
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x003d0000);
+ for (i = 0; i < 15; i++)
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+ nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+ } else {
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x02c80000);
+ for (i = 0; i < 32; i++)
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, 0x00000000);
+ nv_wait(priv, 0x400700, 0xffffffff, 0x00000000);
+ }
+
+ nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
+ nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x00118700);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xF3CE0475); /* 0x4 = auto ctx switch */
+ nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00000000);
+ nv_wr32(priv, 0x40009C , 0x00000040);
+
+ if (nv_device(priv)->chipset >= 0x25) {
+ nv_wr32(priv, 0x400890, 0x00a8cfff);
+ nv_wr32(priv, 0x400610, 0x304B1FB6);
+ nv_wr32(priv, 0x400B80, 0x1cbd3883);
+ nv_wr32(priv, 0x400B84, 0x44000000);
+ nv_wr32(priv, 0x400098, 0x40000080);
+ nv_wr32(priv, 0x400B88, 0x000000ff);
+
+ } else {
+ nv_wr32(priv, 0x400880, 0x0008c7df);
+ nv_wr32(priv, 0x400094, 0x00000005);
+ nv_wr32(priv, 0x400B80, 0x45eae20e);
+ nv_wr32(priv, 0x400B84, 0x24000000);
+ nv_wr32(priv, 0x400098, 0x00000040);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00038);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E10038);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000030);
+ }
+
+ /* Turn all the tiling regions off. */
+ for (i = 0; i < pfb->tile.regions; i++)
+ engine->tile_prog(engine, i);
+
+ nv_wr32(priv, 0x4009a0, nv_rd32(priv, 0x100324));
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA000C);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA, nv_rd32(priv, 0x100324));
+
+ nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+ nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
+
+ tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) & 0x0007ff00;
+ nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
+ tmp = nv_rd32(priv, NV10_PGRAPH_SURFACE) | 0x00020100;
+ nv_wr32(priv, NV10_PGRAPH_SURFACE, tmp);
+
+ /* begin RAM config */
+ vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
+ nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100200));
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , nv_rd32(priv, 0x100204));
+ nv_wr32(priv, 0x400820, 0);
+ nv_wr32(priv, 0x400824, 0);
+ nv_wr32(priv, 0x400864, vramsz - 1);
+ nv_wr32(priv, 0x400868, vramsz - 1);
+
+ /* interesting.. the below overwrites some of the tile setup above.. */
+ nv_wr32(priv, 0x400B20, 0x00000000);
+ nv_wr32(priv, 0x400B04, 0xFFFFFFFF);
+
+ nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMIN, 0);
+ nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMIN, 0);
+ nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_XMAX, 0x7fff);
+ nv_wr32(priv, NV03_PGRAPH_ABS_UCLIP_YMAX, 0x7fff);
+ return 0;
+}
+
+struct nvkm_oclass
+nv20_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x20),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv20_gr_ctor,
+ .dtor = nv20_gr_dtor,
+ .init = nv20_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
new file mode 100644
index 000000000000..ac4dc048fed1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv20.h
@@ -0,0 +1,26 @@
+#ifndef __NV20_GR_H__
+#define __NV20_GR_H__
+#include <engine/gr.h>
+
+struct nv20_gr_priv {
+ struct nvkm_gr base;
+ struct nvkm_gpuobj *ctxtab;
+};
+
+struct nv20_gr_chan {
+ struct nvkm_gr_chan base;
+ int chid;
+};
+
+extern struct nvkm_oclass nv25_gr_sclass[];
+int nv20_gr_context_init(struct nvkm_object *);
+int nv20_gr_context_fini(struct nvkm_object *, bool);
+
+void nv20_gr_tile_prog(struct nvkm_engine *, int);
+void nv20_gr_intr(struct nvkm_subdev *);
+
+void nv20_gr_dtor(struct nvkm_object *);
+int nv20_gr_init(struct nvkm_object *);
+
+int nv30_gr_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
new file mode 100644
index 000000000000..bc362519cebb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv25.c
@@ -0,0 +1,158 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+struct nvkm_oclass
+nv25_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+ { 0x0096, &nv04_gr_ofuncs, NULL }, /* celcius */
+ { 0x009e, &nv04_gr_ofuncs, NULL }, /* swzsurf */
+ { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+ { 0x0597, &nv04_gr_ofuncs, NULL }, /* kelvin */
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv25_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_chan *chan;
+ int ret, i;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x3724,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ chan->chid = nvkm_fifo_chan(parent)->chid;
+
+ nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+ nv_wo32(chan, 0x035c, 0xffff0000);
+ nv_wo32(chan, 0x03c0, 0x0fff0000);
+ nv_wo32(chan, 0x03c4, 0x0fff0000);
+ nv_wo32(chan, 0x049c, 0x00000101);
+ nv_wo32(chan, 0x04b0, 0x00000111);
+ nv_wo32(chan, 0x04c8, 0x00000080);
+ nv_wo32(chan, 0x04cc, 0xffff0000);
+ nv_wo32(chan, 0x04d0, 0x00000001);
+ nv_wo32(chan, 0x04e4, 0x44400000);
+ nv_wo32(chan, 0x04fc, 0x4b800000);
+ for (i = 0x0510; i <= 0x051c; i += 4)
+ nv_wo32(chan, i, 0x00030303);
+ for (i = 0x0530; i <= 0x053c; i += 4)
+ nv_wo32(chan, i, 0x00080000);
+ for (i = 0x0548; i <= 0x0554; i += 4)
+ nv_wo32(chan, i, 0x01012000);
+ for (i = 0x0558; i <= 0x0564; i += 4)
+ nv_wo32(chan, i, 0x000105b8);
+ for (i = 0x0568; i <= 0x0574; i += 4)
+ nv_wo32(chan, i, 0x00080008);
+ for (i = 0x0598; i <= 0x05d4; i += 4)
+ nv_wo32(chan, i, 0x07ff0000);
+ nv_wo32(chan, 0x05e0, 0x4b7fffff);
+ nv_wo32(chan, 0x0620, 0x00000080);
+ nv_wo32(chan, 0x0624, 0x30201000);
+ nv_wo32(chan, 0x0628, 0x70605040);
+ nv_wo32(chan, 0x062c, 0xb0a09080);
+ nv_wo32(chan, 0x0630, 0xf0e0d0c0);
+ nv_wo32(chan, 0x0664, 0x00000001);
+ nv_wo32(chan, 0x066c, 0x00004000);
+ nv_wo32(chan, 0x0678, 0x00000001);
+ nv_wo32(chan, 0x0680, 0x00040000);
+ nv_wo32(chan, 0x0684, 0x00010000);
+ for (i = 0x1b04; i <= 0x2374; i += 16) {
+ nv_wo32(chan, (i + 0), 0x10700ff9);
+ nv_wo32(chan, (i + 4), 0x0436086c);
+ nv_wo32(chan, (i + 8), 0x000c001b);
+ }
+ nv_wo32(chan, 0x2704, 0x3f800000);
+ nv_wo32(chan, 0x2718, 0x3f800000);
+ nv_wo32(chan, 0x2744, 0x40000000);
+ nv_wo32(chan, 0x2748, 0x3f800000);
+ nv_wo32(chan, 0x274c, 0x3f000000);
+ nv_wo32(chan, 0x2754, 0x40000000);
+ nv_wo32(chan, 0x2758, 0x3f800000);
+ nv_wo32(chan, 0x2760, 0xbf800000);
+ nv_wo32(chan, 0x2768, 0xbf800000);
+ nv_wo32(chan, 0x308c, 0x000fe000);
+ nv_wo32(chan, 0x3108, 0x000003f8);
+ nv_wo32(chan, 0x3468, 0x002fe000);
+ for (i = 0x3484; i <= 0x34a0; i += 4)
+ nv_wo32(chan, i, 0x001c527c);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv25_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x25),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv25_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = nv20_gr_context_init,
+ .fini = nv20_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv25_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv20_gr_intr;
+ nv_engine(priv)->cclass = &nv25_gr_cclass;
+ nv_engine(priv)->sclass = nv25_gr_sclass;
+ nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv25_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x25),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv25_gr_ctor,
+ .dtor = nv20_gr_dtor,
+ .init = nv20_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
new file mode 100644
index 000000000000..22a5096e283d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv2a.c
@@ -0,0 +1,125 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv2a_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_chan *chan;
+ int ret, i;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x36b0,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ chan->chid = nvkm_fifo_chan(parent)->chid;
+
+ nv_wo32(chan, 0x0000, 0x00000001 | (chan->chid << 24));
+ nv_wo32(chan, 0x033c, 0xffff0000);
+ nv_wo32(chan, 0x03a0, 0x0fff0000);
+ nv_wo32(chan, 0x03a4, 0x0fff0000);
+ nv_wo32(chan, 0x047c, 0x00000101);
+ nv_wo32(chan, 0x0490, 0x00000111);
+ nv_wo32(chan, 0x04a8, 0x44400000);
+ for (i = 0x04d4; i <= 0x04e0; i += 4)
+ nv_wo32(chan, i, 0x00030303);
+ for (i = 0x04f4; i <= 0x0500; i += 4)
+ nv_wo32(chan, i, 0x00080000);
+ for (i = 0x050c; i <= 0x0518; i += 4)
+ nv_wo32(chan, i, 0x01012000);
+ for (i = 0x051c; i <= 0x0528; i += 4)
+ nv_wo32(chan, i, 0x000105b8);
+ for (i = 0x052c; i <= 0x0538; i += 4)
+ nv_wo32(chan, i, 0x00080008);
+ for (i = 0x055c; i <= 0x0598; i += 4)
+ nv_wo32(chan, i, 0x07ff0000);
+ nv_wo32(chan, 0x05a4, 0x4b7fffff);
+ nv_wo32(chan, 0x05fc, 0x00000001);
+ nv_wo32(chan, 0x0604, 0x00004000);
+ nv_wo32(chan, 0x0610, 0x00000001);
+ nv_wo32(chan, 0x0618, 0x00040000);
+ nv_wo32(chan, 0x061c, 0x00010000);
+ for (i = 0x1a9c; i <= 0x22fc; i += 16) { /*XXX: check!! */
+ nv_wo32(chan, (i + 0), 0x10700ff9);
+ nv_wo32(chan, (i + 4), 0x0436086c);
+ nv_wo32(chan, (i + 8), 0x000c001b);
+ }
+ nv_wo32(chan, 0x269c, 0x3f800000);
+ nv_wo32(chan, 0x26b0, 0x3f800000);
+ nv_wo32(chan, 0x26dc, 0x40000000);
+ nv_wo32(chan, 0x26e0, 0x3f800000);
+ nv_wo32(chan, 0x26e4, 0x3f000000);
+ nv_wo32(chan, 0x26ec, 0x40000000);
+ nv_wo32(chan, 0x26f0, 0x3f800000);
+ nv_wo32(chan, 0x26f8, 0xbf800000);
+ nv_wo32(chan, 0x2700, 0xbf800000);
+ nv_wo32(chan, 0x3024, 0x000fe000);
+ nv_wo32(chan, 0x30a0, 0x000003f8);
+ nv_wo32(chan, 0x33fc, 0x002fe000);
+ for (i = 0x341c; i <= 0x3438; i += 4)
+ nv_wo32(chan, i, 0x001c527c);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv2a_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x2a),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv2a_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = nv20_gr_context_init,
+ .fini = nv20_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv2a_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv20_gr_intr;
+ nv_engine(priv)->cclass = &nv2a_gr_cclass;
+ nv_engine(priv)->sclass = nv25_gr_sclass;
+ nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv2a_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x2a),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv2a_gr_ctor,
+ .dtor = nv20_gr_dtor,
+ .init = nv20_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
new file mode 100644
index 000000000000..dcc84eb54fb6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv30.c
@@ -0,0 +1,231 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <core/device.h>
+#include <engine/fifo.h>
+#include <subdev/fb.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv30_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+ { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+ { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */
+ { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */
+ { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */
+ { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */
+ { 0x0397, &nv04_gr_ofuncs, NULL }, /* rankine */
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv30_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_chan *chan;
+ int ret, i;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x5f48,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ chan->chid = nvkm_fifo_chan(parent)->chid;
+
+ nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+ nv_wo32(chan, 0x0410, 0x00000101);
+ nv_wo32(chan, 0x0424, 0x00000111);
+ nv_wo32(chan, 0x0428, 0x00000060);
+ nv_wo32(chan, 0x0444, 0x00000080);
+ nv_wo32(chan, 0x0448, 0xffff0000);
+ nv_wo32(chan, 0x044c, 0x00000001);
+ nv_wo32(chan, 0x0460, 0x44400000);
+ nv_wo32(chan, 0x048c, 0xffff0000);
+ for (i = 0x04e0; i < 0x04e8; i += 4)
+ nv_wo32(chan, i, 0x0fff0000);
+ nv_wo32(chan, 0x04ec, 0x00011100);
+ for (i = 0x0508; i < 0x0548; i += 4)
+ nv_wo32(chan, i, 0x07ff0000);
+ nv_wo32(chan, 0x0550, 0x4b7fffff);
+ nv_wo32(chan, 0x058c, 0x00000080);
+ nv_wo32(chan, 0x0590, 0x30201000);
+ nv_wo32(chan, 0x0594, 0x70605040);
+ nv_wo32(chan, 0x0598, 0xb8a89888);
+ nv_wo32(chan, 0x059c, 0xf8e8d8c8);
+ nv_wo32(chan, 0x05b0, 0xb0000000);
+ for (i = 0x0600; i < 0x0640; i += 4)
+ nv_wo32(chan, i, 0x00010588);
+ for (i = 0x0640; i < 0x0680; i += 4)
+ nv_wo32(chan, i, 0x00030303);
+ for (i = 0x06c0; i < 0x0700; i += 4)
+ nv_wo32(chan, i, 0x0008aae4);
+ for (i = 0x0700; i < 0x0740; i += 4)
+ nv_wo32(chan, i, 0x01012000);
+ for (i = 0x0740; i < 0x0780; i += 4)
+ nv_wo32(chan, i, 0x00080008);
+ nv_wo32(chan, 0x085c, 0x00040000);
+ nv_wo32(chan, 0x0860, 0x00010000);
+ for (i = 0x0864; i < 0x0874; i += 4)
+ nv_wo32(chan, i, 0x00040004);
+ for (i = 0x1f18; i <= 0x3088 ; i += 16) {
+ nv_wo32(chan, i + 0, 0x10700ff9);
+ nv_wo32(chan, i + 1, 0x0436086c);
+ nv_wo32(chan, i + 2, 0x000c001b);
+ }
+ for (i = 0x30b8; i < 0x30c8; i += 4)
+ nv_wo32(chan, i, 0x0000ffff);
+ nv_wo32(chan, 0x344c, 0x3f800000);
+ nv_wo32(chan, 0x3808, 0x3f800000);
+ nv_wo32(chan, 0x381c, 0x3f800000);
+ nv_wo32(chan, 0x3848, 0x40000000);
+ nv_wo32(chan, 0x384c, 0x3f800000);
+ nv_wo32(chan, 0x3850, 0x3f000000);
+ nv_wo32(chan, 0x3858, 0x40000000);
+ nv_wo32(chan, 0x385c, 0x3f800000);
+ nv_wo32(chan, 0x3864, 0xbf800000);
+ nv_wo32(chan, 0x386c, 0xbf800000);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv30_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x30),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv30_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = nv20_gr_context_init,
+ .fini = nv20_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv30_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv20_gr_intr;
+ nv_engine(priv)->cclass = &nv30_gr_cclass;
+ nv_engine(priv)->sclass = nv30_gr_sclass;
+ nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+ return 0;
+}
+
+int
+nv30_gr_init(struct nvkm_object *object)
+{
+ struct nvkm_engine *engine = nv_engine(object);
+ struct nv20_gr_priv *priv = (void *)engine;
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ int ret, i;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, NV20_PGRAPH_CHANNEL_CTX_TABLE, priv->ctxtab->addr >> 4);
+
+ nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
+ nv_wr32(priv, NV03_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+ nv_wr32(priv, 0x400890, 0x01b463ff);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xf2de0475);
+ nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+ nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0xf04bdff6);
+ nv_wr32(priv, 0x400B80, 0x1003d888);
+ nv_wr32(priv, 0x400B84, 0x0c000000);
+ nv_wr32(priv, 0x400098, 0x00000000);
+ nv_wr32(priv, 0x40009C, 0x0005ad00);
+ nv_wr32(priv, 0x400B88, 0x62ff00ff); /* suspiciously like PGRAPH_DEBUG_2 */
+ nv_wr32(priv, 0x4000a0, 0x00000000);
+ nv_wr32(priv, 0x4000a4, 0x00000008);
+ nv_wr32(priv, 0x4008a8, 0xb784a400);
+ nv_wr32(priv, 0x400ba0, 0x002f8685);
+ nv_wr32(priv, 0x400ba4, 0x00231f3f);
+ nv_wr32(priv, 0x4008a4, 0x40000020);
+
+ if (nv_device(priv)->chipset == 0x34) {
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0004);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00200201);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0008);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000008);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00EA0000);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000032);
+ nv_wr32(priv, NV10_PGRAPH_RDI_INDEX, 0x00E00004);
+ nv_wr32(priv, NV10_PGRAPH_RDI_DATA , 0x00000002);
+ }
+
+ nv_wr32(priv, 0x4000c0, 0x00000016);
+
+ /* Turn all the tiling regions off. */
+ for (i = 0; i < pfb->tile.regions; i++)
+ engine->tile_prog(engine, i);
+
+ nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10000100);
+ nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
+ nv_wr32(priv, 0x0040075c , 0x00000001);
+
+ /* begin RAM config */
+ /* vramsz = pci_resource_len(priv->dev->pdev, 0) - 1; */
+ nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+ if (nv_device(priv)->chipset != 0x34) {
+ nv_wr32(priv, 0x400750, 0x00EA0000);
+ nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x400750, 0x00EA0004);
+ nv_wr32(priv, 0x400754, nv_rd32(priv, 0x100204));
+ }
+ return 0;
+}
+
+struct nvkm_oclass
+nv30_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x30),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv30_gr_ctor,
+ .dtor = nv20_gr_dtor,
+ .init = nv30_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
new file mode 100644
index 000000000000..985b7f3306ae
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv34.c
@@ -0,0 +1,159 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv34_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+ { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+ { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */
+ { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */
+ { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */
+ { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */
+ { 0x0697, &nv04_gr_ofuncs, NULL }, /* rankine */
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv34_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_chan *chan;
+ int ret, i;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x46dc,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ chan->chid = nvkm_fifo_chan(parent)->chid;
+
+ nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+ nv_wo32(chan, 0x040c, 0x01000101);
+ nv_wo32(chan, 0x0420, 0x00000111);
+ nv_wo32(chan, 0x0424, 0x00000060);
+ nv_wo32(chan, 0x0440, 0x00000080);
+ nv_wo32(chan, 0x0444, 0xffff0000);
+ nv_wo32(chan, 0x0448, 0x00000001);
+ nv_wo32(chan, 0x045c, 0x44400000);
+ nv_wo32(chan, 0x0480, 0xffff0000);
+ for (i = 0x04d4; i < 0x04dc; i += 4)
+ nv_wo32(chan, i, 0x0fff0000);
+ nv_wo32(chan, 0x04e0, 0x00011100);
+ for (i = 0x04fc; i < 0x053c; i += 4)
+ nv_wo32(chan, i, 0x07ff0000);
+ nv_wo32(chan, 0x0544, 0x4b7fffff);
+ nv_wo32(chan, 0x057c, 0x00000080);
+ nv_wo32(chan, 0x0580, 0x30201000);
+ nv_wo32(chan, 0x0584, 0x70605040);
+ nv_wo32(chan, 0x0588, 0xb8a89888);
+ nv_wo32(chan, 0x058c, 0xf8e8d8c8);
+ nv_wo32(chan, 0x05a0, 0xb0000000);
+ for (i = 0x05f0; i < 0x0630; i += 4)
+ nv_wo32(chan, i, 0x00010588);
+ for (i = 0x0630; i < 0x0670; i += 4)
+ nv_wo32(chan, i, 0x00030303);
+ for (i = 0x06b0; i < 0x06f0; i += 4)
+ nv_wo32(chan, i, 0x0008aae4);
+ for (i = 0x06f0; i < 0x0730; i += 4)
+ nv_wo32(chan, i, 0x01012000);
+ for (i = 0x0730; i < 0x0770; i += 4)
+ nv_wo32(chan, i, 0x00080008);
+ nv_wo32(chan, 0x0850, 0x00040000);
+ nv_wo32(chan, 0x0854, 0x00010000);
+ for (i = 0x0858; i < 0x0868; i += 4)
+ nv_wo32(chan, i, 0x00040004);
+ for (i = 0x15ac; i <= 0x271c ; i += 16) {
+ nv_wo32(chan, i + 0, 0x10700ff9);
+ nv_wo32(chan, i + 1, 0x0436086c);
+ nv_wo32(chan, i + 2, 0x000c001b);
+ }
+ for (i = 0x274c; i < 0x275c; i += 4)
+ nv_wo32(chan, i, 0x0000ffff);
+ nv_wo32(chan, 0x2ae0, 0x3f800000);
+ nv_wo32(chan, 0x2e9c, 0x3f800000);
+ nv_wo32(chan, 0x2eb0, 0x3f800000);
+ nv_wo32(chan, 0x2edc, 0x40000000);
+ nv_wo32(chan, 0x2ee0, 0x3f800000);
+ nv_wo32(chan, 0x2ee4, 0x3f000000);
+ nv_wo32(chan, 0x2eec, 0x40000000);
+ nv_wo32(chan, 0x2ef0, 0x3f800000);
+ nv_wo32(chan, 0x2ef8, 0xbf800000);
+ nv_wo32(chan, 0x2f00, 0xbf800000);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv34_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x34),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv34_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = nv20_gr_context_init,
+ .fini = nv20_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv34_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv20_gr_intr;
+ nv_engine(priv)->cclass = &nv34_gr_cclass;
+ nv_engine(priv)->sclass = nv34_gr_sclass;
+ nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv34_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x34),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv34_gr_ctor,
+ .dtor = nv20_gr_dtor,
+ .init = nv30_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
new file mode 100644
index 000000000000..707625f19ff5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv35.c
@@ -0,0 +1,159 @@
+#include "nv20.h"
+#include "regs.h"
+
+#include <engine/fifo.h>
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+nv35_gr_sclass[] = {
+ { 0x0012, &nv04_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv04_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv04_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv04_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv04_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv04_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv04_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv04_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv04_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv04_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv04_gr_ofuncs, NULL }, /* ifc */
+ { 0x009f, &nv04_gr_ofuncs, NULL }, /* imageblit */
+ { 0x0362, &nv04_gr_ofuncs, NULL }, /* surf2d (nv30) */
+ { 0x0389, &nv04_gr_ofuncs, NULL }, /* sifm (nv30) */
+ { 0x038a, &nv04_gr_ofuncs, NULL }, /* ifc (nv30) */
+ { 0x039e, &nv04_gr_ofuncs, NULL }, /* swzsurf (nv30) */
+ { 0x0497, &nv04_gr_ofuncs, NULL }, /* rankine */
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv35_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_chan *chan;
+ int ret, i;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, 0x577c,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ chan->chid = nvkm_fifo_chan(parent)->chid;
+
+ nv_wo32(chan, 0x0028, 0x00000001 | (chan->chid << 24));
+ nv_wo32(chan, 0x040c, 0x00000101);
+ nv_wo32(chan, 0x0420, 0x00000111);
+ nv_wo32(chan, 0x0424, 0x00000060);
+ nv_wo32(chan, 0x0440, 0x00000080);
+ nv_wo32(chan, 0x0444, 0xffff0000);
+ nv_wo32(chan, 0x0448, 0x00000001);
+ nv_wo32(chan, 0x045c, 0x44400000);
+ nv_wo32(chan, 0x0488, 0xffff0000);
+ for (i = 0x04dc; i < 0x04e4; i += 4)
+ nv_wo32(chan, i, 0x0fff0000);
+ nv_wo32(chan, 0x04e8, 0x00011100);
+ for (i = 0x0504; i < 0x0544; i += 4)
+ nv_wo32(chan, i, 0x07ff0000);
+ nv_wo32(chan, 0x054c, 0x4b7fffff);
+ nv_wo32(chan, 0x0588, 0x00000080);
+ nv_wo32(chan, 0x058c, 0x30201000);
+ nv_wo32(chan, 0x0590, 0x70605040);
+ nv_wo32(chan, 0x0594, 0xb8a89888);
+ nv_wo32(chan, 0x0598, 0xf8e8d8c8);
+ nv_wo32(chan, 0x05ac, 0xb0000000);
+ for (i = 0x0604; i < 0x0644; i += 4)
+ nv_wo32(chan, i, 0x00010588);
+ for (i = 0x0644; i < 0x0684; i += 4)
+ nv_wo32(chan, i, 0x00030303);
+ for (i = 0x06c4; i < 0x0704; i += 4)
+ nv_wo32(chan, i, 0x0008aae4);
+ for (i = 0x0704; i < 0x0744; i += 4)
+ nv_wo32(chan, i, 0x01012000);
+ for (i = 0x0744; i < 0x0784; i += 4)
+ nv_wo32(chan, i, 0x00080008);
+ nv_wo32(chan, 0x0860, 0x00040000);
+ nv_wo32(chan, 0x0864, 0x00010000);
+ for (i = 0x0868; i < 0x0878; i += 4)
+ nv_wo32(chan, i, 0x00040004);
+ for (i = 0x1f1c; i <= 0x308c ; i += 16) {
+ nv_wo32(chan, i + 0, 0x10700ff9);
+ nv_wo32(chan, i + 4, 0x0436086c);
+ nv_wo32(chan, i + 8, 0x000c001b);
+ }
+ for (i = 0x30bc; i < 0x30cc; i += 4)
+ nv_wo32(chan, i, 0x0000ffff);
+ nv_wo32(chan, 0x3450, 0x3f800000);
+ nv_wo32(chan, 0x380c, 0x3f800000);
+ nv_wo32(chan, 0x3820, 0x3f800000);
+ nv_wo32(chan, 0x384c, 0x40000000);
+ nv_wo32(chan, 0x3850, 0x3f800000);
+ nv_wo32(chan, 0x3854, 0x3f000000);
+ nv_wo32(chan, 0x385c, 0x40000000);
+ nv_wo32(chan, 0x3860, 0x3f800000);
+ nv_wo32(chan, 0x3868, 0xbf800000);
+ nv_wo32(chan, 0x3870, 0xbf800000);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv35_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x35),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv35_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = nv20_gr_context_init,
+ .fini = nv20_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv35_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv20_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 32 * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ctxtab);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv20_gr_intr;
+ nv_engine(priv)->cclass = &nv35_gr_cclass;
+ nv_engine(priv)->sclass = nv35_gr_sclass;
+ nv_engine(priv)->tile_prog = nv20_gr_tile_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv35_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x35),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv35_gr_ctor,
+ .dtor = nv20_gr_dtor,
+ .init = nv30_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
new file mode 100644
index 000000000000..7e1937980e3f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.c
@@ -0,0 +1,527 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+#include "regs.h"
+
+#include <core/client.h>
+#include <core/handle.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+#include <engine/fifo.h>
+
+struct nv40_gr_priv {
+ struct nvkm_gr base;
+ u32 size;
+};
+
+struct nv40_gr_chan {
+ struct nvkm_gr_chan base;
+};
+
+static u64
+nv40_gr_units(struct nvkm_gr *gr)
+{
+ struct nv40_gr_priv *priv = (void *)gr;
+
+ return nv_rd32(priv, 0x1540);
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static int
+nv40_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj *obj;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+ 20, 16, 0, &obj);
+ *pobject = nv_object(obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, nv_mclass(obj));
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+#ifdef __BIG_ENDIAN
+ nv_mo32(obj, 0x08, 0x01000000, 0x01000000);
+#endif
+ nv_wo32(obj, 0x0c, 0x00000000);
+ nv_wo32(obj, 0x10, 0x00000000);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nv40_gr_ofuncs = {
+ .ctor = nv40_gr_object_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv40_gr_sclass[] = {
+ { 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv40_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */
+ { 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */
+ { 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */
+ { 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */
+ { 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */
+ { 0x4097, &nv40_gr_ofuncs, NULL }, /* curie */
+ {},
+};
+
+static struct nvkm_oclass
+nv44_gr_sclass[] = {
+ { 0x0012, &nv40_gr_ofuncs, NULL }, /* beta1 */
+ { 0x0019, &nv40_gr_ofuncs, NULL }, /* clip */
+ { 0x0030, &nv40_gr_ofuncs, NULL }, /* null */
+ { 0x0039, &nv40_gr_ofuncs, NULL }, /* m2mf */
+ { 0x0043, &nv40_gr_ofuncs, NULL }, /* rop */
+ { 0x0044, &nv40_gr_ofuncs, NULL }, /* patt */
+ { 0x004a, &nv40_gr_ofuncs, NULL }, /* gdi */
+ { 0x0062, &nv40_gr_ofuncs, NULL }, /* surf2d */
+ { 0x0072, &nv40_gr_ofuncs, NULL }, /* beta4 */
+ { 0x0089, &nv40_gr_ofuncs, NULL }, /* sifm */
+ { 0x008a, &nv40_gr_ofuncs, NULL }, /* ifc */
+ { 0x009f, &nv40_gr_ofuncs, NULL }, /* imageblit */
+ { 0x3062, &nv40_gr_ofuncs, NULL }, /* surf2d (nv40) */
+ { 0x3089, &nv40_gr_ofuncs, NULL }, /* sifm (nv40) */
+ { 0x309e, &nv40_gr_ofuncs, NULL }, /* swzsurf (nv40) */
+ { 0x4497, &nv40_gr_ofuncs, NULL }, /* curie */
+ {},
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv40_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv40_gr_priv *priv = (void *)engine;
+ struct nv40_gr_chan *chan;
+ int ret;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ nv40_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+ nv_wo32(chan, 0x00000, nv_gpuobj(chan)->addr >> 4);
+ return 0;
+}
+
+static int
+nv40_gr_context_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv40_gr_priv *priv = (void *)object->engine;
+ struct nv40_gr_chan *chan = (void *)object;
+ u32 inst = 0x01000000 | nv_gpuobj(chan)->addr >> 4;
+ int ret = 0;
+
+ nv_mask(priv, 0x400720, 0x00000001, 0x00000000);
+
+ if (nv_rd32(priv, 0x40032c) == inst) {
+ if (suspend) {
+ nv_wr32(priv, 0x400720, 0x00000000);
+ nv_wr32(priv, 0x400784, inst);
+ nv_mask(priv, 0x400310, 0x00000020, 0x00000020);
+ nv_mask(priv, 0x400304, 0x00000001, 0x00000001);
+ if (!nv_wait(priv, 0x400300, 0x00000001, 0x00000000)) {
+ u32 insn = nv_rd32(priv, 0x400308);
+ nv_warn(priv, "ctxprog timeout 0x%08x\n", insn);
+ ret = -EBUSY;
+ }
+ }
+
+ nv_mask(priv, 0x40032c, 0x01000000, 0x00000000);
+ }
+
+ if (nv_rd32(priv, 0x400330) == inst)
+ nv_mask(priv, 0x400330, 0x01000000, 0x00000000);
+
+ nv_mask(priv, 0x400720, 0x00000001, 0x00000001);
+ return ret;
+}
+
+static struct nvkm_oclass
+nv40_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = nv40_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_gr_tile_prog(struct nvkm_engine *engine, int i)
+{
+ struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+ struct nvkm_fifo *pfifo = nvkm_fifo(engine);
+ struct nv40_gr_priv *priv = (void *)engine;
+ unsigned long flags;
+
+ pfifo->pause(pfifo, &flags);
+ nv04_gr_idle(priv);
+
+ switch (nv_device(priv)->chipset) {
+ case 0x40:
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x45:
+ case 0x4e:
+ nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+ nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+ nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+ nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
+ switch (nv_device(priv)->chipset) {
+ case 0x40:
+ case 0x45:
+ nv_wr32(priv, NV20_PGRAPH_ZCOMP(i), tile->zcomp);
+ nv_wr32(priv, NV40_PGRAPH_ZCOMP1(i), tile->zcomp);
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ nv_wr32(priv, NV41_PGRAPH_ZCOMP0(i), tile->zcomp);
+ nv_wr32(priv, NV41_PGRAPH_ZCOMP1(i), tile->zcomp);
+ break;
+ default:
+ break;
+ }
+ break;
+ case 0x44:
+ case 0x4a:
+ nv_wr32(priv, NV20_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(priv, NV20_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(priv, NV20_PGRAPH_TILE(i), tile->addr);
+ break;
+ case 0x46:
+ case 0x4c:
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ case 0x63:
+ case 0x67:
+ case 0x68:
+ nv_wr32(priv, NV47_PGRAPH_TSIZE(i), tile->pitch);
+ nv_wr32(priv, NV47_PGRAPH_TLIMIT(i), tile->limit);
+ nv_wr32(priv, NV47_PGRAPH_TILE(i), tile->addr);
+ nv_wr32(priv, NV40_PGRAPH_TSIZE1(i), tile->pitch);
+ nv_wr32(priv, NV40_PGRAPH_TLIMIT1(i), tile->limit);
+ nv_wr32(priv, NV40_PGRAPH_TILE1(i), tile->addr);
+ switch (nv_device(priv)->chipset) {
+ case 0x47:
+ case 0x49:
+ case 0x4b:
+ nv_wr32(priv, NV47_PGRAPH_ZCOMP0(i), tile->zcomp);
+ nv_wr32(priv, NV47_PGRAPH_ZCOMP1(i), tile->zcomp);
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ pfifo->start(pfifo, &flags);
+}
+
+static void
+nv40_gr_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct nvkm_handle *handle = NULL;
+ struct nv40_gr_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, NV03_PGRAPH_INTR);
+ u32 nsource = nv_rd32(priv, NV03_PGRAPH_NSOURCE);
+ u32 nstatus = nv_rd32(priv, NV03_PGRAPH_NSTATUS);
+ u32 inst = nv_rd32(priv, 0x40032c) & 0x000fffff;
+ u32 addr = nv_rd32(priv, NV04_PGRAPH_TRAPPED_ADDR);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(priv, NV04_PGRAPH_TRAPPED_DATA);
+ u32 class = nv_rd32(priv, 0x400160 + subc * 4) & 0xffff;
+ u32 show = stat;
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat & NV_PGRAPH_INTR_ERROR) {
+ if (nsource & NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD) {
+ handle = nvkm_handle_get_class(engctx, class);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~NV_PGRAPH_INTR_ERROR;
+ nvkm_handle_put(handle);
+ }
+
+ if (nsource & NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION) {
+ nv_mask(priv, 0x402000, 0, 0);
+ }
+ }
+
+ nv_wr32(priv, NV03_PGRAPH_INTR, stat);
+ nv_wr32(priv, NV04_PGRAPH_FIFO, 0x00000001);
+
+ if (show) {
+ nv_error(priv, "%s", "");
+ nvkm_bitfield_print(nv10_gr_intr_name, show);
+ pr_cont(" nsource:");
+ nvkm_bitfield_print(nv04_gr_nsource, nsource);
+ pr_cont(" nstatus:");
+ nvkm_bitfield_print(nv10_gr_nstatus, nstatus);
+ pr_cont("\n");
+ nv_error(priv,
+ "ch %d [0x%08x %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, inst << 4, nvkm_client_name(engctx), subc,
+ class, mthd, data);
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static int
+nv40_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv40_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00001000;
+ nv_subdev(priv)->intr = nv40_gr_intr;
+ nv_engine(priv)->cclass = &nv40_gr_cclass;
+ if (nv44_gr_class(priv))
+ nv_engine(priv)->sclass = nv44_gr_sclass;
+ else
+ nv_engine(priv)->sclass = nv40_gr_sclass;
+ nv_engine(priv)->tile_prog = nv40_gr_tile_prog;
+
+ priv->base.units = nv40_gr_units;
+ return 0;
+}
+
+static int
+nv40_gr_init(struct nvkm_object *object)
+{
+ struct nvkm_engine *engine = nv_engine(object);
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ struct nv40_gr_priv *priv = (void *)engine;
+ int ret, i, j;
+ u32 vramsz;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* generate and upload context program */
+ ret = nv40_grctx_init(nv_device(priv), &priv->size);
+ if (ret)
+ return ret;
+
+ /* No context present currently */
+ nv_wr32(priv, NV40_PGRAPH_CTXCTL_CUR, 0x00000000);
+
+ nv_wr32(priv, NV03_PGRAPH_INTR , 0xFFFFFFFF);
+ nv_wr32(priv, NV40_PGRAPH_INTR_EN, 0xFFFFFFFF);
+
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0xFFFFFFFF);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_0, 0x00000000);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_1, 0x401287c0);
+ nv_wr32(priv, NV04_PGRAPH_DEBUG_3, 0xe0de8055);
+ nv_wr32(priv, NV10_PGRAPH_DEBUG_4, 0x00008000);
+ nv_wr32(priv, NV04_PGRAPH_LIMIT_VIOL_PIX, 0x00be3c5f);
+
+ nv_wr32(priv, NV10_PGRAPH_CTX_CONTROL, 0x10010100);
+ nv_wr32(priv, NV10_PGRAPH_STATE , 0xFFFFFFFF);
+
+ j = nv_rd32(priv, 0x1540) & 0xff;
+ if (j) {
+ for (i = 0; !(j & 1); j >>= 1, i++)
+ ;
+ nv_wr32(priv, 0x405000, i);
+ }
+
+ if (nv_device(priv)->chipset == 0x40) {
+ nv_wr32(priv, 0x4009b0, 0x83280fff);
+ nv_wr32(priv, 0x4009b4, 0x000000a0);
+ } else {
+ nv_wr32(priv, 0x400820, 0x83280eff);
+ nv_wr32(priv, 0x400824, 0x000000a0);
+ }
+
+ switch (nv_device(priv)->chipset) {
+ case 0x40:
+ case 0x45:
+ nv_wr32(priv, 0x4009b8, 0x0078e366);
+ nv_wr32(priv, 0x4009bc, 0x0000014c);
+ break;
+ case 0x41:
+ case 0x42: /* pciid also 0x00Cx */
+ /* case 0x0120: XXX (pciid) */
+ nv_wr32(priv, 0x400828, 0x007596ff);
+ nv_wr32(priv, 0x40082c, 0x00000108);
+ break;
+ case 0x43:
+ nv_wr32(priv, 0x400828, 0x0072cb77);
+ nv_wr32(priv, 0x40082c, 0x00000108);
+ break;
+ case 0x44:
+ case 0x46: /* G72 */
+ case 0x4a:
+ case 0x4c: /* G7x-based C51 */
+ case 0x4e:
+ nv_wr32(priv, 0x400860, 0);
+ nv_wr32(priv, 0x400864, 0);
+ break;
+ case 0x47: /* G70 */
+ case 0x49: /* G71 */
+ case 0x4b: /* G73 */
+ nv_wr32(priv, 0x400828, 0x07830610);
+ nv_wr32(priv, 0x40082c, 0x0000016A);
+ break;
+ default:
+ break;
+ }
+
+ nv_wr32(priv, 0x400b38, 0x2ffff800);
+ nv_wr32(priv, 0x400b3c, 0x00006000);
+
+ /* Tiling related stuff. */
+ switch (nv_device(priv)->chipset) {
+ case 0x44:
+ case 0x4a:
+ nv_wr32(priv, 0x400bc4, 0x1003d888);
+ nv_wr32(priv, 0x400bbc, 0xb7a7b500);
+ break;
+ case 0x46:
+ nv_wr32(priv, 0x400bc4, 0x0000e024);
+ nv_wr32(priv, 0x400bbc, 0xb7a7b520);
+ break;
+ case 0x4c:
+ case 0x4e:
+ case 0x67:
+ nv_wr32(priv, 0x400bc4, 0x1003d888);
+ nv_wr32(priv, 0x400bbc, 0xb7a7b540);
+ break;
+ default:
+ break;
+ }
+
+ /* Turn all the tiling regions off. */
+ for (i = 0; i < pfb->tile.regions; i++)
+ engine->tile_prog(engine, i);
+
+ /* begin RAM config */
+ vramsz = nv_device_resource_len(nv_device(priv), 0) - 1;
+ switch (nv_device(priv)->chipset) {
+ case 0x40:
+ nv_wr32(priv, 0x4009A4, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x4009A8, nv_rd32(priv, 0x100204));
+ nv_wr32(priv, 0x4069A4, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x4069A8, nv_rd32(priv, 0x100204));
+ nv_wr32(priv, 0x400820, 0);
+ nv_wr32(priv, 0x400824, 0);
+ nv_wr32(priv, 0x400864, vramsz);
+ nv_wr32(priv, 0x400868, vramsz);
+ break;
+ default:
+ switch (nv_device(priv)->chipset) {
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x45:
+ case 0x4e:
+ case 0x44:
+ case 0x4a:
+ nv_wr32(priv, 0x4009F0, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x4009F4, nv_rd32(priv, 0x100204));
+ break;
+ default:
+ nv_wr32(priv, 0x400DF0, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x400DF4, nv_rd32(priv, 0x100204));
+ break;
+ }
+ nv_wr32(priv, 0x4069F0, nv_rd32(priv, 0x100200));
+ nv_wr32(priv, 0x4069F4, nv_rd32(priv, 0x100204));
+ nv_wr32(priv, 0x400840, 0);
+ nv_wr32(priv, 0x400844, 0);
+ nv_wr32(priv, 0x4008A0, vramsz);
+ nv_wr32(priv, 0x4008A4, vramsz);
+ break;
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass
+nv40_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_gr_ctor,
+ .dtor = _nvkm_gr_dtor,
+ .init = nv40_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
new file mode 100644
index 000000000000..d852bd6de571
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv40.h
@@ -0,0 +1,24 @@
+#ifndef __NV40_GR_H__
+#define __NV40_GR_H__
+#include <engine/gr.h>
+
+#include <core/device.h>
+struct nvkm_gpuobj;
+
+/* returns 1 if device is one of the nv4x using the 0x4497 object class,
+ * helpful to determine a number of other hardware features
+ */
+static inline int
+nv44_gr_class(void *priv)
+{
+ struct nvkm_device *device = nv_device(priv);
+
+ if ((device->chipset & 0xf0) == 0x60)
+ return 1;
+
+ return !(0x0baf & (1 << (device->chipset & 0x0f)));
+}
+
+int nv40_grctx_init(struct nvkm_device *, u32 *size);
+void nv40_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
new file mode 100644
index 000000000000..270d7cd63fc7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.c
@@ -0,0 +1,999 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/timer.h>
+
+struct nv50_gr_priv {
+ struct nvkm_gr base;
+ spinlock_t lock;
+ u32 size;
+};
+
+struct nv50_gr_chan {
+ struct nvkm_gr_chan base;
+};
+
+static u64
+nv50_gr_units(struct nvkm_gr *gr)
+{
+ struct nv50_gr_priv *priv = (void *)gr;
+
+ return nv_rd32(priv, 0x1540);
+}
+
+/*******************************************************************************
+ * Graphics object classes
+ ******************************************************************************/
+
+static int
+nv50_gr_object_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj *obj;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+ 16, 16, 0, &obj);
+ *pobject = nv_object(obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, nv_mclass(obj));
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nv50_gr_ofuncs = {
+ .ctor = nv50_gr_object_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv50_gr_sclass[] = {
+ { 0x0030, &nv50_gr_ofuncs },
+ { 0x502d, &nv50_gr_ofuncs },
+ { 0x5039, &nv50_gr_ofuncs },
+ { 0x5097, &nv50_gr_ofuncs },
+ { 0x50c0, &nv50_gr_ofuncs },
+ {}
+};
+
+static struct nvkm_oclass
+g84_gr_sclass[] = {
+ { 0x0030, &nv50_gr_ofuncs },
+ { 0x502d, &nv50_gr_ofuncs },
+ { 0x5039, &nv50_gr_ofuncs },
+ { 0x50c0, &nv50_gr_ofuncs },
+ { 0x8297, &nv50_gr_ofuncs },
+ {}
+};
+
+static struct nvkm_oclass
+gt200_gr_sclass[] = {
+ { 0x0030, &nv50_gr_ofuncs },
+ { 0x502d, &nv50_gr_ofuncs },
+ { 0x5039, &nv50_gr_ofuncs },
+ { 0x50c0, &nv50_gr_ofuncs },
+ { 0x8397, &nv50_gr_ofuncs },
+ {}
+};
+
+static struct nvkm_oclass
+gt215_gr_sclass[] = {
+ { 0x0030, &nv50_gr_ofuncs },
+ { 0x502d, &nv50_gr_ofuncs },
+ { 0x5039, &nv50_gr_ofuncs },
+ { 0x50c0, &nv50_gr_ofuncs },
+ { 0x8597, &nv50_gr_ofuncs },
+ { 0x85c0, &nv50_gr_ofuncs },
+ {}
+};
+
+static struct nvkm_oclass
+mcp89_gr_sclass[] = {
+ { 0x0030, &nv50_gr_ofuncs },
+ { 0x502d, &nv50_gr_ofuncs },
+ { 0x5039, &nv50_gr_ofuncs },
+ { 0x50c0, &nv50_gr_ofuncs },
+ { 0x85c0, &nv50_gr_ofuncs },
+ { 0x8697, &nv50_gr_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PGRAPH context
+ ******************************************************************************/
+
+static int
+nv50_gr_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_gr_priv *priv = (void *)engine;
+ struct nv50_gr_chan *chan;
+ int ret;
+
+ ret = nvkm_gr_context_create(parent, engine, oclass, NULL, priv->size,
+ 0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ nv50_grctx_fill(nv_device(priv), nv_gpuobj(chan));
+ return 0;
+}
+
+static struct nvkm_oclass
+nv50_gr_cclass = {
+ .handle = NV_ENGCTX(GR, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_gr_context_ctor,
+ .dtor = _nvkm_gr_context_dtor,
+ .init = _nvkm_gr_context_init,
+ .fini = _nvkm_gr_context_fini,
+ .rd32 = _nvkm_gr_context_rd32,
+ .wr32 = _nvkm_gr_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PGRAPH engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_bitfield nv50_pgr_status[] = {
+ { 0x00000001, "BUSY" }, /* set when any bit is set */
+ { 0x00000002, "DISPATCH" },
+ { 0x00000004, "UNK2" },
+ { 0x00000008, "UNK3" },
+ { 0x00000010, "UNK4" },
+ { 0x00000020, "UNK5" },
+ { 0x00000040, "M2MF" },
+ { 0x00000080, "UNK7" },
+ { 0x00000100, "CTXPROG" },
+ { 0x00000200, "VFETCH" },
+ { 0x00000400, "CCACHE_PREGEOM" },
+ { 0x00000800, "STRMOUT_VATTR_POSTGEOM" },
+ { 0x00001000, "VCLIP" },
+ { 0x00002000, "RATTR_APLANE" },
+ { 0x00004000, "TRAST" },
+ { 0x00008000, "CLIPID" },
+ { 0x00010000, "ZCULL" },
+ { 0x00020000, "ENG2D" },
+ { 0x00040000, "RMASK" },
+ { 0x00080000, "TPC_RAST" },
+ { 0x00100000, "TPC_PROP" },
+ { 0x00200000, "TPC_TEX" },
+ { 0x00400000, "TPC_GEOM" },
+ { 0x00800000, "TPC_MP" },
+ { 0x01000000, "ROP" },
+ {}
+};
+
+static const char *const nv50_pgr_vstatus_0[] = {
+ "VFETCH", "CCACHE", "PREGEOM", "POSTGEOM", "VATTR", "STRMOUT", "VCLIP",
+ NULL
+};
+
+static const char *const nv50_pgr_vstatus_1[] = {
+ "TPC_RAST", "TPC_PROP", "TPC_TEX", "TPC_GEOM", "TPC_MP", NULL
+};
+
+static const char *const nv50_pgr_vstatus_2[] = {
+ "RATTR", "APLANE", "TRAST", "CLIPID", "ZCULL", "ENG2D", "RMASK",
+ "ROP", NULL
+};
+
+static void
+nvkm_pgr_vstatus_print(struct nv50_gr_priv *priv, int r,
+ const char *const units[], u32 status)
+{
+ int i;
+
+ nv_error(priv, "PGRAPH_VSTATUS%d: 0x%08x", r, status);
+
+ for (i = 0; units[i] && status; i++) {
+ if ((status & 7) == 1)
+ pr_cont(" %s", units[i]);
+ status >>= 3;
+ }
+ if (status)
+ pr_cont(" (invalid: 0x%x)", status);
+ pr_cont("\n");
+}
+
+static int
+g84_gr_tlb_flush(struct nvkm_engine *engine)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(engine);
+ struct nv50_gr_priv *priv = (void *)engine;
+ bool idle, timeout = false;
+ unsigned long flags;
+ u64 start;
+ u32 tmp;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ nv_mask(priv, 0x400500, 0x00000001, 0x00000000);
+
+ start = ptimer->read(ptimer);
+ do {
+ idle = true;
+
+ for (tmp = nv_rd32(priv, 0x400380); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+
+ for (tmp = nv_rd32(priv, 0x400384); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+
+ for (tmp = nv_rd32(priv, 0x400388); tmp && idle; tmp >>= 3) {
+ if ((tmp & 7) == 1)
+ idle = false;
+ }
+ } while (!idle &&
+ !(timeout = ptimer->read(ptimer) - start > 2000000000));
+
+ if (timeout) {
+ nv_error(priv, "PGRAPH TLB flush idle timeout fail\n");
+
+ tmp = nv_rd32(priv, 0x400700);
+ nv_error(priv, "PGRAPH_STATUS : 0x%08x", tmp);
+ nvkm_bitfield_print(nv50_pgr_status, tmp);
+ pr_cont("\n");
+
+ nvkm_pgr_vstatus_print(priv, 0, nv50_pgr_vstatus_0,
+ nv_rd32(priv, 0x400380));
+ nvkm_pgr_vstatus_print(priv, 1, nv50_pgr_vstatus_1,
+ nv_rd32(priv, 0x400384));
+ nvkm_pgr_vstatus_print(priv, 2, nv50_pgr_vstatus_2,
+ nv_rd32(priv, 0x400388));
+ }
+
+
+ nv_wr32(priv, 0x100c80, 0x00000001);
+ if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+ nv_error(priv, "vm flush timeout\n");
+ nv_mask(priv, 0x400500, 0x00000001, 0x00000001);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return timeout ? -EBUSY : 0;
+}
+
+static const struct nvkm_bitfield nv50_mp_exec_errors[] = {
+ { 0x01, "STACK_UNDERFLOW" },
+ { 0x02, "STACK_MISMATCH" },
+ { 0x04, "QUADON_ACTIVE" },
+ { 0x08, "TIMEOUT" },
+ { 0x10, "INVALID_OPCODE" },
+ { 0x20, "PM_OVERFLOW" },
+ { 0x40, "BREAKPOINT" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_mpc_traps[] = {
+ { 0x0000001, "LOCAL_LIMIT_READ" },
+ { 0x0000010, "LOCAL_LIMIT_WRITE" },
+ { 0x0000040, "STACK_LIMIT" },
+ { 0x0000100, "GLOBAL_LIMIT_READ" },
+ { 0x0001000, "GLOBAL_LIMIT_WRITE" },
+ { 0x0010000, "MP0" },
+ { 0x0020000, "MP1" },
+ { 0x0040000, "GLOBAL_LIMIT_RED" },
+ { 0x0400000, "GLOBAL_LIMIT_ATOM" },
+ { 0x4000000, "MP2" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_tex_traps[] = {
+ { 0x00000001, "" }, /* any bit set? */
+ { 0x00000002, "FAULT" },
+ { 0x00000004, "STORAGE_TYPE_MISMATCH" },
+ { 0x00000008, "LINEAR_MISMATCH" },
+ { 0x00000020, "WRONG_MEMTYPE" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_m2mf[] = {
+ { 0x00000001, "NOTIFY" },
+ { 0x00000002, "IN" },
+ { 0x00000004, "OUT" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_vfetch[] = {
+ { 0x00000001, "FAULT" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_strmout[] = {
+ { 0x00000001, "FAULT" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_ccache[] = {
+ { 0x00000001, "FAULT" },
+ {}
+};
+
+/* There must be a *lot* of these. Will take some time to gather them up. */
+const struct nvkm_enum nv50_data_error_names[] = {
+ { 0x00000003, "INVALID_OPERATION", NULL },
+ { 0x00000004, "INVALID_VALUE", NULL },
+ { 0x00000005, "INVALID_ENUM", NULL },
+ { 0x00000008, "INVALID_OBJECT", NULL },
+ { 0x00000009, "READ_ONLY_OBJECT", NULL },
+ { 0x0000000a, "SUPERVISOR_OBJECT", NULL },
+ { 0x0000000b, "INVALID_ADDRESS_ALIGNMENT", NULL },
+ { 0x0000000c, "INVALID_BITFIELD", NULL },
+ { 0x0000000d, "BEGIN_END_ACTIVE", NULL },
+ { 0x0000000e, "SEMANTIC_COLOR_BACK_OVER_LIMIT", NULL },
+ { 0x0000000f, "VIEWPORT_ID_NEEDS_GP", NULL },
+ { 0x00000010, "RT_DOUBLE_BIND", NULL },
+ { 0x00000011, "RT_TYPES_MISMATCH", NULL },
+ { 0x00000012, "RT_LINEAR_WITH_ZETA", NULL },
+ { 0x00000015, "FP_TOO_FEW_REGS", NULL },
+ { 0x00000016, "ZETA_FORMAT_CSAA_MISMATCH", NULL },
+ { 0x00000017, "RT_LINEAR_WITH_MSAA", NULL },
+ { 0x00000018, "FP_INTERPOLANT_START_OVER_LIMIT", NULL },
+ { 0x00000019, "SEMANTIC_LAYER_OVER_LIMIT", NULL },
+ { 0x0000001a, "RT_INVALID_ALIGNMENT", NULL },
+ { 0x0000001b, "SAMPLER_OVER_LIMIT", NULL },
+ { 0x0000001c, "TEXTURE_OVER_LIMIT", NULL },
+ { 0x0000001e, "GP_TOO_MANY_OUTPUTS", NULL },
+ { 0x0000001f, "RT_BPP128_WITH_MS8", NULL },
+ { 0x00000021, "Z_OUT_OF_BOUNDS", NULL },
+ { 0x00000023, "XY_OUT_OF_BOUNDS", NULL },
+ { 0x00000024, "VP_ZERO_INPUTS", NULL },
+ { 0x00000027, "CP_MORE_PARAMS_THAN_SHARED", NULL },
+ { 0x00000028, "CP_NO_REG_SPACE_STRIPED", NULL },
+ { 0x00000029, "CP_NO_REG_SPACE_PACKED", NULL },
+ { 0x0000002a, "CP_NOT_ENOUGH_WARPS", NULL },
+ { 0x0000002b, "CP_BLOCK_SIZE_MISMATCH", NULL },
+ { 0x0000002c, "CP_NOT_ENOUGH_LOCAL_WARPS", NULL },
+ { 0x0000002d, "CP_NOT_ENOUGH_STACK_WARPS", NULL },
+ { 0x0000002e, "CP_NO_BLOCKDIM_LATCH", NULL },
+ { 0x00000031, "ENG2D_FORMAT_MISMATCH", NULL },
+ { 0x0000003f, "PRIMITIVE_ID_NEEDS_GP", NULL },
+ { 0x00000044, "SEMANTIC_VIEWPORT_OVER_LIMIT", NULL },
+ { 0x00000045, "SEMANTIC_COLOR_FRONT_OVER_LIMIT", NULL },
+ { 0x00000046, "LAYER_ID_NEEDS_GP", NULL },
+ { 0x00000047, "SEMANTIC_CLIP_OVER_LIMIT", NULL },
+ { 0x00000048, "SEMANTIC_PTSZ_OVER_LIMIT", NULL },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_gr_intr_name[] = {
+ { 0x00000001, "NOTIFY" },
+ { 0x00000002, "COMPUTE_QUERY" },
+ { 0x00000010, "ILLEGAL_MTHD" },
+ { 0x00000020, "ILLEGAL_CLASS" },
+ { 0x00000040, "DOUBLE_NOTIFY" },
+ { 0x00001000, "CONTEXT_SWITCH" },
+ { 0x00010000, "BUFFER_NOTIFY" },
+ { 0x00100000, "DATA_ERROR" },
+ { 0x00200000, "TRAP" },
+ { 0x01000000, "SINGLE_STEP" },
+ {}
+};
+
+static const struct nvkm_bitfield nv50_gr_trap_prop[] = {
+ { 0x00000004, "SURF_WIDTH_OVERRUN" },
+ { 0x00000008, "SURF_HEIGHT_OVERRUN" },
+ { 0x00000010, "DST2D_FAULT" },
+ { 0x00000020, "ZETA_FAULT" },
+ { 0x00000040, "RT_FAULT" },
+ { 0x00000080, "CUDA_FAULT" },
+ { 0x00000100, "DST2D_STORAGE_TYPE_MISMATCH" },
+ { 0x00000200, "ZETA_STORAGE_TYPE_MISMATCH" },
+ { 0x00000400, "RT_STORAGE_TYPE_MISMATCH" },
+ { 0x00000800, "DST2D_LINEAR_MISMATCH" },
+ { 0x00001000, "RT_LINEAR_MISMATCH" },
+ {}
+};
+
+static void
+nv50_priv_prop_trap(struct nv50_gr_priv *priv,
+ u32 ustatus_addr, u32 ustatus, u32 tp)
+{
+ u32 e0c = nv_rd32(priv, ustatus_addr + 0x04);
+ u32 e10 = nv_rd32(priv, ustatus_addr + 0x08);
+ u32 e14 = nv_rd32(priv, ustatus_addr + 0x0c);
+ u32 e18 = nv_rd32(priv, ustatus_addr + 0x10);
+ u32 e1c = nv_rd32(priv, ustatus_addr + 0x14);
+ u32 e20 = nv_rd32(priv, ustatus_addr + 0x18);
+ u32 e24 = nv_rd32(priv, ustatus_addr + 0x1c);
+
+ /* CUDA memory: l[], g[] or stack. */
+ if (ustatus & 0x00000080) {
+ if (e18 & 0x80000000) {
+ /* g[] read fault? */
+ nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global read fault at address %02x%08x\n",
+ tp, e14, e10 | ((e18 >> 24) & 0x1f));
+ e18 &= ~0x1f000000;
+ } else if (e18 & 0xc) {
+ /* g[] write fault? */
+ nv_error(priv, "TRAP_PROP - TP %d - CUDA_FAULT - Global write fault at address %02x%08x\n",
+ tp, e14, e10 | ((e18 >> 7) & 0x1f));
+ e18 &= ~0x00000f80;
+ } else {
+ nv_error(priv, "TRAP_PROP - TP %d - Unknown CUDA fault at address %02x%08x\n",
+ tp, e14, e10);
+ }
+ ustatus &= ~0x00000080;
+ }
+ if (ustatus) {
+ nv_error(priv, "TRAP_PROP - TP %d -", tp);
+ nvkm_bitfield_print(nv50_gr_trap_prop, ustatus);
+ pr_cont(" - Address %02x%08x\n", e14, e10);
+ }
+ nv_error(priv, "TRAP_PROP - TP %d - e0c: %08x, e18: %08x, e1c: %08x, e20: %08x, e24: %08x\n",
+ tp, e0c, e18, e1c, e20, e24);
+}
+
+static void
+nv50_priv_mp_trap(struct nv50_gr_priv *priv, int tpid, int display)
+{
+ u32 units = nv_rd32(priv, 0x1540);
+ u32 addr, mp10, status, pc, oplow, ophigh;
+ int i;
+ int mps = 0;
+ for (i = 0; i < 4; i++) {
+ if (!(units & 1 << (i+24)))
+ continue;
+ if (nv_device(priv)->chipset < 0xa0)
+ addr = 0x408200 + (tpid << 12) + (i << 7);
+ else
+ addr = 0x408100 + (tpid << 11) + (i << 7);
+ mp10 = nv_rd32(priv, addr + 0x10);
+ status = nv_rd32(priv, addr + 0x14);
+ if (!status)
+ continue;
+ if (display) {
+ nv_rd32(priv, addr + 0x20);
+ pc = nv_rd32(priv, addr + 0x24);
+ oplow = nv_rd32(priv, addr + 0x70);
+ ophigh = nv_rd32(priv, addr + 0x74);
+ nv_error(priv, "TRAP_MP_EXEC - "
+ "TP %d MP %d:", tpid, i);
+ nvkm_bitfield_print(nv50_mp_exec_errors, status);
+ pr_cont(" at %06x warp %d, opcode %08x %08x\n",
+ pc&0xffffff, pc >> 24,
+ oplow, ophigh);
+ }
+ nv_wr32(priv, addr + 0x10, mp10);
+ nv_wr32(priv, addr + 0x14, 0);
+ mps++;
+ }
+ if (!mps && display)
+ nv_error(priv, "TRAP_MP_EXEC - TP %d: "
+ "No MPs claiming errors?\n", tpid);
+}
+
+static void
+nv50_priv_tp_trap(struct nv50_gr_priv *priv, int type, u32 ustatus_old,
+ u32 ustatus_new, int display, const char *name)
+{
+ int tps = 0;
+ u32 units = nv_rd32(priv, 0x1540);
+ int i, r;
+ u32 ustatus_addr, ustatus;
+ for (i = 0; i < 16; i++) {
+ if (!(units & (1 << i)))
+ continue;
+ if (nv_device(priv)->chipset < 0xa0)
+ ustatus_addr = ustatus_old + (i << 12);
+ else
+ ustatus_addr = ustatus_new + (i << 11);
+ ustatus = nv_rd32(priv, ustatus_addr) & 0x7fffffff;
+ if (!ustatus)
+ continue;
+ tps++;
+ switch (type) {
+ case 6: /* texture error... unknown for now */
+ if (display) {
+ nv_error(priv, "magic set %d:\n", i);
+ for (r = ustatus_addr + 4; r <= ustatus_addr + 0x10; r += 4)
+ nv_error(priv, "\t0x%08x: 0x%08x\n", r,
+ nv_rd32(priv, r));
+ if (ustatus) {
+ nv_error(priv, "%s - TP%d:", name, i);
+ nvkm_bitfield_print(nv50_tex_traps,
+ ustatus);
+ pr_cont("\n");
+ ustatus = 0;
+ }
+ }
+ break;
+ case 7: /* MP error */
+ if (ustatus & 0x04030000) {
+ nv50_priv_mp_trap(priv, i, display);
+ ustatus &= ~0x04030000;
+ }
+ if (ustatus && display) {
+ nv_error(priv, "%s - TP%d:", name, i);
+ nvkm_bitfield_print(nv50_mpc_traps, ustatus);
+ pr_cont("\n");
+ ustatus = 0;
+ }
+ break;
+ case 8: /* PROP error */
+ if (display)
+ nv50_priv_prop_trap(
+ priv, ustatus_addr, ustatus, i);
+ ustatus = 0;
+ break;
+ }
+ if (ustatus) {
+ if (display)
+ nv_error(priv, "%s - TP%d: Unhandled ustatus 0x%08x\n", name, i, ustatus);
+ }
+ nv_wr32(priv, ustatus_addr, 0xc0000000);
+ }
+
+ if (!tps && display)
+ nv_warn(priv, "%s - No TPs claiming errors?\n", name);
+}
+
+static int
+nv50_gr_trap_handler(struct nv50_gr_priv *priv, u32 display,
+ int chid, u64 inst, struct nvkm_object *engctx)
+{
+ u32 status = nv_rd32(priv, 0x400108);
+ u32 ustatus;
+
+ if (!status && display) {
+ nv_error(priv, "TRAP: no units reporting traps?\n");
+ return 1;
+ }
+
+ /* DISPATCH: Relays commands to other units and handles NOTIFY,
+ * COND, QUERY. If you get a trap from it, the command is still stuck
+ * in DISPATCH and you need to do something about it. */
+ if (status & 0x001) {
+ ustatus = nv_rd32(priv, 0x400804) & 0x7fffffff;
+ if (!ustatus && display) {
+ nv_error(priv, "TRAP_DISPATCH - no ustatus?\n");
+ }
+
+ nv_wr32(priv, 0x400500, 0x00000000);
+
+ /* Known to be triggered by screwed up NOTIFY and COND... */
+ if (ustatus & 0x00000001) {
+ u32 addr = nv_rd32(priv, 0x400808);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 datal = nv_rd32(priv, 0x40080c);
+ u32 datah = nv_rd32(priv, 0x400810);
+ u32 class = nv_rd32(priv, 0x400814);
+ u32 r848 = nv_rd32(priv, 0x400848);
+
+ nv_error(priv, "TRAP DISPATCH_FAULT\n");
+ if (display && (addr & 0x80000000)) {
+ nv_error(priv,
+ "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x%08x 400808 0x%08x 400848 0x%08x\n",
+ chid, inst,
+ nvkm_client_name(engctx), subc,
+ class, mthd, datah, datal, addr, r848);
+ } else
+ if (display) {
+ nv_error(priv, "no stuck command?\n");
+ }
+
+ nv_wr32(priv, 0x400808, 0);
+ nv_wr32(priv, 0x4008e8, nv_rd32(priv, 0x4008e8) & 3);
+ nv_wr32(priv, 0x400848, 0);
+ ustatus &= ~0x00000001;
+ }
+
+ if (ustatus & 0x00000002) {
+ u32 addr = nv_rd32(priv, 0x40084c);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(priv, 0x40085c);
+ u32 class = nv_rd32(priv, 0x400814);
+
+ nv_error(priv, "TRAP DISPATCH_QUERY\n");
+ if (display && (addr & 0x80000000)) {
+ nv_error(priv,
+ "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x 40084c 0x%08x\n",
+ chid, inst,
+ nvkm_client_name(engctx), subc,
+ class, mthd, data, addr);
+ } else
+ if (display) {
+ nv_error(priv, "no stuck command?\n");
+ }
+
+ nv_wr32(priv, 0x40084c, 0);
+ ustatus &= ~0x00000002;
+ }
+
+ if (ustatus && display) {
+ nv_error(priv, "TRAP_DISPATCH (unknown "
+ "0x%08x)\n", ustatus);
+ }
+
+ nv_wr32(priv, 0x400804, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x001);
+ status &= ~0x001;
+ if (!status)
+ return 0;
+ }
+
+ /* M2MF: Memory to memory copy engine. */
+ if (status & 0x002) {
+ u32 ustatus = nv_rd32(priv, 0x406800) & 0x7fffffff;
+ if (display) {
+ nv_error(priv, "TRAP_M2MF");
+ nvkm_bitfield_print(nv50_gr_trap_m2mf, ustatus);
+ pr_cont("\n");
+ nv_error(priv, "TRAP_M2MF %08x %08x %08x %08x\n",
+ nv_rd32(priv, 0x406804), nv_rd32(priv, 0x406808),
+ nv_rd32(priv, 0x40680c), nv_rd32(priv, 0x406810));
+
+ }
+
+ /* No sane way found yet -- just reset the bugger. */
+ nv_wr32(priv, 0x400040, 2);
+ nv_wr32(priv, 0x400040, 0);
+ nv_wr32(priv, 0x406800, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x002);
+ status &= ~0x002;
+ }
+
+ /* VFETCH: Fetches data from vertex buffers. */
+ if (status & 0x004) {
+ u32 ustatus = nv_rd32(priv, 0x400c04) & 0x7fffffff;
+ if (display) {
+ nv_error(priv, "TRAP_VFETCH");
+ nvkm_bitfield_print(nv50_gr_trap_vfetch, ustatus);
+ pr_cont("\n");
+ nv_error(priv, "TRAP_VFETCH %08x %08x %08x %08x\n",
+ nv_rd32(priv, 0x400c00), nv_rd32(priv, 0x400c08),
+ nv_rd32(priv, 0x400c0c), nv_rd32(priv, 0x400c10));
+ }
+
+ nv_wr32(priv, 0x400c04, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x004);
+ status &= ~0x004;
+ }
+
+ /* STRMOUT: DirectX streamout / OpenGL transform feedback. */
+ if (status & 0x008) {
+ ustatus = nv_rd32(priv, 0x401800) & 0x7fffffff;
+ if (display) {
+ nv_error(priv, "TRAP_STRMOUT");
+ nvkm_bitfield_print(nv50_gr_trap_strmout, ustatus);
+ pr_cont("\n");
+ nv_error(priv, "TRAP_STRMOUT %08x %08x %08x %08x\n",
+ nv_rd32(priv, 0x401804), nv_rd32(priv, 0x401808),
+ nv_rd32(priv, 0x40180c), nv_rd32(priv, 0x401810));
+
+ }
+
+ /* No sane way found yet -- just reset the bugger. */
+ nv_wr32(priv, 0x400040, 0x80);
+ nv_wr32(priv, 0x400040, 0);
+ nv_wr32(priv, 0x401800, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x008);
+ status &= ~0x008;
+ }
+
+ /* CCACHE: Handles code and c[] caches and fills them. */
+ if (status & 0x010) {
+ ustatus = nv_rd32(priv, 0x405018) & 0x7fffffff;
+ if (display) {
+ nv_error(priv, "TRAP_CCACHE");
+ nvkm_bitfield_print(nv50_gr_trap_ccache, ustatus);
+ pr_cont("\n");
+ nv_error(priv, "TRAP_CCACHE %08x %08x %08x %08x"
+ " %08x %08x %08x\n",
+ nv_rd32(priv, 0x405000), nv_rd32(priv, 0x405004),
+ nv_rd32(priv, 0x405008), nv_rd32(priv, 0x40500c),
+ nv_rd32(priv, 0x405010), nv_rd32(priv, 0x405014),
+ nv_rd32(priv, 0x40501c));
+
+ }
+
+ nv_wr32(priv, 0x405018, 0xc0000000);
+ nv_wr32(priv, 0x400108, 0x010);
+ status &= ~0x010;
+ }
+
+ /* Unknown, not seen yet... 0x402000 is the only trap status reg
+ * remaining, so try to handle it anyway. Perhaps related to that
+ * unknown DMA slot on tesla? */
+ if (status & 0x20) {
+ ustatus = nv_rd32(priv, 0x402000) & 0x7fffffff;
+ if (display)
+ nv_error(priv, "TRAP_UNKC04 0x%08x\n", ustatus);
+ nv_wr32(priv, 0x402000, 0xc0000000);
+ /* no status modifiction on purpose */
+ }
+
+ /* TEXTURE: CUDA texturing units */
+ if (status & 0x040) {
+ nv50_priv_tp_trap(priv, 6, 0x408900, 0x408600, display,
+ "TRAP_TEXTURE");
+ nv_wr32(priv, 0x400108, 0x040);
+ status &= ~0x040;
+ }
+
+ /* MP: CUDA execution engines. */
+ if (status & 0x080) {
+ nv50_priv_tp_trap(priv, 7, 0x408314, 0x40831c, display,
+ "TRAP_MP");
+ nv_wr32(priv, 0x400108, 0x080);
+ status &= ~0x080;
+ }
+
+ /* PROP: Handles TP-initiated uncached memory accesses:
+ * l[], g[], stack, 2d surfaces, render targets. */
+ if (status & 0x100) {
+ nv50_priv_tp_trap(priv, 8, 0x408e08, 0x408708, display,
+ "TRAP_PROP");
+ nv_wr32(priv, 0x400108, 0x100);
+ status &= ~0x100;
+ }
+
+ if (status) {
+ if (display)
+ nv_error(priv, "TRAP: unknown 0x%08x\n", status);
+ nv_wr32(priv, 0x400108, status);
+ }
+
+ return 1;
+}
+
+static void
+nv50_gr_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct nvkm_handle *handle = NULL;
+ struct nv50_gr_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, 0x400100);
+ u32 inst = nv_rd32(priv, 0x40032c) & 0x0fffffff;
+ u32 addr = nv_rd32(priv, 0x400704);
+ u32 subc = (addr & 0x00070000) >> 16;
+ u32 mthd = (addr & 0x00001ffc);
+ u32 data = nv_rd32(priv, 0x400708);
+ u32 class = nv_rd32(priv, 0x400814);
+ u32 show = stat, show_bitfield = stat;
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat & 0x00000010) {
+ handle = nvkm_handle_get_class(engctx, class);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~0x00000010;
+ nvkm_handle_put(handle);
+ }
+
+ if (show & 0x00100000) {
+ u32 ecode = nv_rd32(priv, 0x400110);
+ nv_error(priv, "DATA_ERROR ");
+ nvkm_enum_print(nv50_data_error_names, ecode);
+ pr_cont("\n");
+ show_bitfield &= ~0x00100000;
+ }
+
+ if (stat & 0x00200000) {
+ if (!nv50_gr_trap_handler(priv, show, chid, (u64)inst << 12,
+ engctx))
+ show &= ~0x00200000;
+ show_bitfield &= ~0x00200000;
+ }
+
+ nv_wr32(priv, 0x400100, stat);
+ nv_wr32(priv, 0x400500, 0x00010001);
+
+ if (show) {
+ show &= show_bitfield;
+ if (show) {
+ nv_error(priv, "%s", "");
+ nvkm_bitfield_print(nv50_gr_intr_name, show);
+ pr_cont("\n");
+ }
+ nv_error(priv,
+ "ch %d [0x%010llx %s] subc %d class 0x%04x mthd 0x%04x data 0x%08x\n",
+ chid, (u64)inst << 12, nvkm_client_name(engctx),
+ subc, class, mthd, data);
+ }
+
+ if (nv_rd32(priv, 0x400824) & (1 << 31))
+ nv_wr32(priv, 0x400824, nv_rd32(priv, 0x400824) & ~(1 << 31));
+
+ nvkm_engctx_put(engctx);
+}
+
+static int
+nv50_gr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_gr_priv *priv;
+ int ret;
+
+ ret = nvkm_gr_create(parent, engine, oclass, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00201000;
+ nv_subdev(priv)->intr = nv50_gr_intr;
+ nv_engine(priv)->cclass = &nv50_gr_cclass;
+
+ priv->base.units = nv50_gr_units;
+
+ switch (nv_device(priv)->chipset) {
+ case 0x50:
+ nv_engine(priv)->sclass = nv50_gr_sclass;
+ break;
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ nv_engine(priv)->sclass = g84_gr_sclass;
+ break;
+ case 0xa0:
+ case 0xaa:
+ case 0xac:
+ nv_engine(priv)->sclass = gt200_gr_sclass;
+ break;
+ case 0xa3:
+ case 0xa5:
+ case 0xa8:
+ nv_engine(priv)->sclass = gt215_gr_sclass;
+ break;
+ case 0xaf:
+ nv_engine(priv)->sclass = mcp89_gr_sclass;
+ break;
+
+ }
+
+ /* unfortunate hw bug workaround... */
+ if (nv_device(priv)->chipset != 0x50 &&
+ nv_device(priv)->chipset != 0xac)
+ nv_engine(priv)->tlb_flush = g84_gr_tlb_flush;
+
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+static int
+nv50_gr_init(struct nvkm_object *object)
+{
+ struct nv50_gr_priv *priv = (void *)object;
+ int ret, units, i;
+
+ ret = nvkm_gr_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* NV_PGRAPH_DEBUG_3_HW_CTX_SWITCH_ENABLED */
+ nv_wr32(priv, 0x40008c, 0x00000004);
+
+ /* reset/enable traps and interrupts */
+ nv_wr32(priv, 0x400804, 0xc0000000);
+ nv_wr32(priv, 0x406800, 0xc0000000);
+ nv_wr32(priv, 0x400c04, 0xc0000000);
+ nv_wr32(priv, 0x401800, 0xc0000000);
+ nv_wr32(priv, 0x405018, 0xc0000000);
+ nv_wr32(priv, 0x402000, 0xc0000000);
+
+ units = nv_rd32(priv, 0x001540);
+ for (i = 0; i < 16; i++) {
+ if (!(units & (1 << i)))
+ continue;
+
+ if (nv_device(priv)->chipset < 0xa0) {
+ nv_wr32(priv, 0x408900 + (i << 12), 0xc0000000);
+ nv_wr32(priv, 0x408e08 + (i << 12), 0xc0000000);
+ nv_wr32(priv, 0x408314 + (i << 12), 0xc0000000);
+ } else {
+ nv_wr32(priv, 0x408600 + (i << 11), 0xc0000000);
+ nv_wr32(priv, 0x408708 + (i << 11), 0xc0000000);
+ nv_wr32(priv, 0x40831c + (i << 11), 0xc0000000);
+ }
+ }
+
+ nv_wr32(priv, 0x400108, 0xffffffff);
+ nv_wr32(priv, 0x400138, 0xffffffff);
+ nv_wr32(priv, 0x400100, 0xffffffff);
+ nv_wr32(priv, 0x40013c, 0xffffffff);
+ nv_wr32(priv, 0x400500, 0x00010001);
+
+ /* upload context program, initialise ctxctl defaults */
+ ret = nv50_grctx_init(nv_device(priv), &priv->size);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x400824, 0x00000000);
+ nv_wr32(priv, 0x400828, 0x00000000);
+ nv_wr32(priv, 0x40082c, 0x00000000);
+ nv_wr32(priv, 0x400830, 0x00000000);
+ nv_wr32(priv, 0x40032c, 0x00000000);
+ nv_wr32(priv, 0x400330, 0x00000000);
+
+ /* some unknown zcull magic */
+ switch (nv_device(priv)->chipset & 0xf0) {
+ case 0x50:
+ case 0x80:
+ case 0x90:
+ nv_wr32(priv, 0x402ca8, 0x00000800);
+ break;
+ case 0xa0:
+ default:
+ if (nv_device(priv)->chipset == 0xa0 ||
+ nv_device(priv)->chipset == 0xaa ||
+ nv_device(priv)->chipset == 0xac) {
+ nv_wr32(priv, 0x402ca8, 0x00000802);
+ } else {
+ nv_wr32(priv, 0x402cc0, 0x00000000);
+ nv_wr32(priv, 0x402ca8, 0x00000002);
+ }
+
+ break;
+ }
+
+ /* zero out zcull regions */
+ for (i = 0; i < 8; i++) {
+ nv_wr32(priv, 0x402c20 + (i * 0x10), 0x00000000);
+ nv_wr32(priv, 0x402c24 + (i * 0x10), 0x00000000);
+ nv_wr32(priv, 0x402c28 + (i * 0x10), 0x00000000);
+ nv_wr32(priv, 0x402c2c + (i * 0x10), 0x00000000);
+ }
+ return 0;
+}
+
+struct nvkm_oclass
+nv50_gr_oclass = {
+ .handle = NV_ENGINE(GR, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_gr_ctor,
+ .dtor = _nvkm_gr_dtor,
+ .init = nv50_gr_init,
+ .fini = _nvkm_gr_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
new file mode 100644
index 000000000000..bcf786f6b731
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/nv50.h
@@ -0,0 +1,9 @@
+#ifndef __NV50_GR_H__
+#define __NV50_GR_H__
+#include <engine/gr.h>
+struct nvkm_device;
+struct nvkm_gpuobj;
+
+int nv50_grctx_init(struct nvkm_device *, u32 *size);
+void nv50_grctx_fill(struct nvkm_device *, struct nvkm_gpuobj *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h b/drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h
new file mode 100644
index 000000000000..90a9873ce522
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/gr/regs.h
@@ -0,0 +1,274 @@
+#ifndef __NVKM_GR_REGS_H__
+#define __NVKM_GR_REGS_H__
+
+#define NV04_PGRAPH_DEBUG_0 0x00400080
+#define NV04_PGRAPH_DEBUG_1 0x00400084
+#define NV04_PGRAPH_DEBUG_2 0x00400088
+#define NV04_PGRAPH_DEBUG_3 0x0040008c
+#define NV10_PGRAPH_DEBUG_4 0x00400090
+#define NV03_PGRAPH_INTR 0x00400100
+#define NV03_PGRAPH_NSTATUS 0x00400104
+# define NV04_PGRAPH_NSTATUS_STATE_IN_USE (1<<11)
+# define NV04_PGRAPH_NSTATUS_INVALID_STATE (1<<12)
+# define NV04_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<13)
+# define NV04_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<14)
+# define NV10_PGRAPH_NSTATUS_STATE_IN_USE (1<<23)
+# define NV10_PGRAPH_NSTATUS_INVALID_STATE (1<<24)
+# define NV10_PGRAPH_NSTATUS_BAD_ARGUMENT (1<<25)
+# define NV10_PGRAPH_NSTATUS_PROTECTION_FAULT (1<<26)
+#define NV03_PGRAPH_NSOURCE 0x00400108
+# define NV03_PGRAPH_NSOURCE_NOTIFICATION (1<<0)
+# define NV03_PGRAPH_NSOURCE_DATA_ERROR (1<<1)
+# define NV03_PGRAPH_NSOURCE_PROTECTION_ERROR (1<<2)
+# define NV03_PGRAPH_NSOURCE_RANGE_EXCEPTION (1<<3)
+# define NV03_PGRAPH_NSOURCE_LIMIT_COLOR (1<<4)
+# define NV03_PGRAPH_NSOURCE_LIMIT_ZETA (1<<5)
+# define NV03_PGRAPH_NSOURCE_ILLEGAL_MTHD (1<<6)
+# define NV03_PGRAPH_NSOURCE_DMA_R_PROTECTION (1<<7)
+# define NV03_PGRAPH_NSOURCE_DMA_W_PROTECTION (1<<8)
+# define NV03_PGRAPH_NSOURCE_FORMAT_EXCEPTION (1<<9)
+# define NV03_PGRAPH_NSOURCE_PATCH_EXCEPTION (1<<10)
+# define NV03_PGRAPH_NSOURCE_STATE_INVALID (1<<11)
+# define NV03_PGRAPH_NSOURCE_DOUBLE_NOTIFY (1<<12)
+# define NV03_PGRAPH_NSOURCE_NOTIFY_IN_USE (1<<13)
+# define NV03_PGRAPH_NSOURCE_METHOD_CNT (1<<14)
+# define NV03_PGRAPH_NSOURCE_BFR_NOTIFICATION (1<<15)
+# define NV03_PGRAPH_NSOURCE_DMA_VTX_PROTECTION (1<<16)
+# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_A (1<<17)
+# define NV03_PGRAPH_NSOURCE_DMA_WIDTH_B (1<<18)
+#define NV03_PGRAPH_INTR_EN 0x00400140
+#define NV40_PGRAPH_INTR_EN 0x0040013C
+# define NV_PGRAPH_INTR_NOTIFY (1<<0)
+# define NV_PGRAPH_INTR_MISSING_HW (1<<4)
+# define NV_PGRAPH_INTR_CONTEXT_SWITCH (1<<12)
+# define NV_PGRAPH_INTR_BUFFER_NOTIFY (1<<16)
+# define NV_PGRAPH_INTR_ERROR (1<<20)
+#define NV10_PGRAPH_CTX_CONTROL 0x00400144
+#define NV10_PGRAPH_CTX_USER 0x00400148
+#define NV10_PGRAPH_CTX_SWITCH(i) (0x0040014C + 0x4*(i))
+#define NV04_PGRAPH_CTX_SWITCH1 0x00400160
+#define NV10_PGRAPH_CTX_CACHE(i, j) (0x00400160 \
+ + 0x4*(i) + 0x20*(j))
+#define NV04_PGRAPH_CTX_SWITCH2 0x00400164
+#define NV04_PGRAPH_CTX_SWITCH3 0x00400168
+#define NV04_PGRAPH_CTX_SWITCH4 0x0040016C
+#define NV04_PGRAPH_CTX_CONTROL 0x00400170
+#define NV04_PGRAPH_CTX_USER 0x00400174
+#define NV04_PGRAPH_CTX_CACHE1 0x00400180
+#define NV03_PGRAPH_CTX_CONTROL 0x00400190
+#define NV03_PGRAPH_CTX_USER 0x00400194
+#define NV04_PGRAPH_CTX_CACHE2 0x004001A0
+#define NV04_PGRAPH_CTX_CACHE3 0x004001C0
+#define NV04_PGRAPH_CTX_CACHE4 0x004001E0
+#define NV40_PGRAPH_CTXCTL_0304 0x00400304
+#define NV40_PGRAPH_CTXCTL_0304_XFER_CTX 0x00000001
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT 0x00400308
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_MASK 0xff000000
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_IP_SHIFT 24
+#define NV40_PGRAPH_CTXCTL_UCODE_STAT_OP_MASK 0x00ffffff
+#define NV40_PGRAPH_CTXCTL_0310 0x00400310
+#define NV40_PGRAPH_CTXCTL_0310_XFER_SAVE 0x00000020
+#define NV40_PGRAPH_CTXCTL_0310_XFER_LOAD 0x00000040
+#define NV40_PGRAPH_CTXCTL_030C 0x0040030c
+#define NV40_PGRAPH_CTXCTL_UCODE_INDEX 0x00400324
+#define NV40_PGRAPH_CTXCTL_UCODE_DATA 0x00400328
+#define NV40_PGRAPH_CTXCTL_CUR 0x0040032c
+#define NV40_PGRAPH_CTXCTL_CUR_LOADED 0x01000000
+#define NV40_PGRAPH_CTXCTL_CUR_INSTANCE 0x000FFFFF
+#define NV40_PGRAPH_CTXCTL_NEXT 0x00400330
+#define NV40_PGRAPH_CTXCTL_NEXT_INSTANCE 0x000fffff
+#define NV50_PGRAPH_CTXCTL_CUR 0x0040032c
+#define NV50_PGRAPH_CTXCTL_CUR_LOADED 0x80000000
+#define NV50_PGRAPH_CTXCTL_CUR_INSTANCE 0x00ffffff
+#define NV50_PGRAPH_CTXCTL_NEXT 0x00400330
+#define NV50_PGRAPH_CTXCTL_NEXT_INSTANCE 0x00ffffff
+#define NV03_PGRAPH_ABS_X_RAM 0x00400400
+#define NV03_PGRAPH_ABS_Y_RAM 0x00400480
+#define NV03_PGRAPH_X_MISC 0x00400500
+#define NV03_PGRAPH_Y_MISC 0x00400504
+#define NV04_PGRAPH_VALID1 0x00400508
+#define NV04_PGRAPH_SOURCE_COLOR 0x0040050C
+#define NV04_PGRAPH_MISC24_0 0x00400510
+#define NV03_PGRAPH_XY_LOGIC_MISC0 0x00400514
+#define NV03_PGRAPH_XY_LOGIC_MISC1 0x00400518
+#define NV03_PGRAPH_XY_LOGIC_MISC2 0x0040051C
+#define NV03_PGRAPH_XY_LOGIC_MISC3 0x00400520
+#define NV03_PGRAPH_CLIPX_0 0x00400524
+#define NV03_PGRAPH_CLIPX_1 0x00400528
+#define NV03_PGRAPH_CLIPY_0 0x0040052C
+#define NV03_PGRAPH_CLIPY_1 0x00400530
+#define NV03_PGRAPH_ABS_ICLIP_XMAX 0x00400534
+#define NV03_PGRAPH_ABS_ICLIP_YMAX 0x00400538
+#define NV03_PGRAPH_ABS_UCLIP_XMIN 0x0040053C
+#define NV03_PGRAPH_ABS_UCLIP_YMIN 0x00400540
+#define NV03_PGRAPH_ABS_UCLIP_XMAX 0x00400544
+#define NV03_PGRAPH_ABS_UCLIP_YMAX 0x00400548
+#define NV03_PGRAPH_ABS_UCLIPA_XMIN 0x00400560
+#define NV03_PGRAPH_ABS_UCLIPA_YMIN 0x00400564
+#define NV03_PGRAPH_ABS_UCLIPA_XMAX 0x00400568
+#define NV03_PGRAPH_ABS_UCLIPA_YMAX 0x0040056C
+#define NV04_PGRAPH_MISC24_1 0x00400570
+#define NV04_PGRAPH_MISC24_2 0x00400574
+#define NV04_PGRAPH_VALID2 0x00400578
+#define NV04_PGRAPH_PASSTHRU_0 0x0040057C
+#define NV04_PGRAPH_PASSTHRU_1 0x00400580
+#define NV04_PGRAPH_PASSTHRU_2 0x00400584
+#define NV10_PGRAPH_DIMX_TEXTURE 0x00400588
+#define NV10_PGRAPH_WDIMX_TEXTURE 0x0040058C
+#define NV04_PGRAPH_COMBINE_0_ALPHA 0x00400590
+#define NV04_PGRAPH_COMBINE_0_COLOR 0x00400594
+#define NV04_PGRAPH_COMBINE_1_ALPHA 0x00400598
+#define NV04_PGRAPH_COMBINE_1_COLOR 0x0040059C
+#define NV04_PGRAPH_FORMAT_0 0x004005A8
+#define NV04_PGRAPH_FORMAT_1 0x004005AC
+#define NV04_PGRAPH_FILTER_0 0x004005B0
+#define NV04_PGRAPH_FILTER_1 0x004005B4
+#define NV03_PGRAPH_MONO_COLOR0 0x00400600
+#define NV04_PGRAPH_ROP3 0x00400604
+#define NV04_PGRAPH_BETA_AND 0x00400608
+#define NV04_PGRAPH_BETA_PREMULT 0x0040060C
+#define NV04_PGRAPH_LIMIT_VIOL_PIX 0x00400610
+#define NV04_PGRAPH_FORMATS 0x00400618
+#define NV10_PGRAPH_DEBUG_2 0x00400620
+#define NV04_PGRAPH_BOFFSET0 0x00400640
+#define NV04_PGRAPH_BOFFSET1 0x00400644
+#define NV04_PGRAPH_BOFFSET2 0x00400648
+#define NV04_PGRAPH_BOFFSET3 0x0040064C
+#define NV04_PGRAPH_BOFFSET4 0x00400650
+#define NV04_PGRAPH_BOFFSET5 0x00400654
+#define NV04_PGRAPH_BBASE0 0x00400658
+#define NV04_PGRAPH_BBASE1 0x0040065C
+#define NV04_PGRAPH_BBASE2 0x00400660
+#define NV04_PGRAPH_BBASE3 0x00400664
+#define NV04_PGRAPH_BBASE4 0x00400668
+#define NV04_PGRAPH_BBASE5 0x0040066C
+#define NV04_PGRAPH_BPITCH0 0x00400670
+#define NV04_PGRAPH_BPITCH1 0x00400674
+#define NV04_PGRAPH_BPITCH2 0x00400678
+#define NV04_PGRAPH_BPITCH3 0x0040067C
+#define NV04_PGRAPH_BPITCH4 0x00400680
+#define NV04_PGRAPH_BLIMIT0 0x00400684
+#define NV04_PGRAPH_BLIMIT1 0x00400688
+#define NV04_PGRAPH_BLIMIT2 0x0040068C
+#define NV04_PGRAPH_BLIMIT3 0x00400690
+#define NV04_PGRAPH_BLIMIT4 0x00400694
+#define NV04_PGRAPH_BLIMIT5 0x00400698
+#define NV04_PGRAPH_BSWIZZLE2 0x0040069C
+#define NV04_PGRAPH_BSWIZZLE5 0x004006A0
+#define NV03_PGRAPH_STATUS 0x004006B0
+#define NV04_PGRAPH_STATUS 0x00400700
+# define NV40_PGRAPH_STATUS_SYNC_STALL 0x00004000
+#define NV04_PGRAPH_TRAPPED_ADDR 0x00400704
+#define NV04_PGRAPH_TRAPPED_DATA 0x00400708
+#define NV04_PGRAPH_SURFACE 0x0040070C
+#define NV10_PGRAPH_TRAPPED_DATA_HIGH 0x0040070C
+#define NV04_PGRAPH_STATE 0x00400710
+#define NV10_PGRAPH_SURFACE 0x00400710
+#define NV04_PGRAPH_NOTIFY 0x00400714
+#define NV10_PGRAPH_STATE 0x00400714
+#define NV10_PGRAPH_NOTIFY 0x00400718
+
+#define NV04_PGRAPH_FIFO 0x00400720
+
+#define NV04_PGRAPH_BPIXEL 0x00400724
+#define NV10_PGRAPH_RDI_INDEX 0x00400750
+#define NV04_PGRAPH_FFINTFC_ST2 0x00400754
+#define NV10_PGRAPH_RDI_DATA 0x00400754
+#define NV04_PGRAPH_DMA_PITCH 0x00400760
+#define NV10_PGRAPH_FFINTFC_FIFO_PTR 0x00400760
+#define NV04_PGRAPH_DVD_COLORFMT 0x00400764
+#define NV10_PGRAPH_FFINTFC_ST2 0x00400764
+#define NV04_PGRAPH_SCALED_FORMAT 0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DL 0x00400768
+#define NV10_PGRAPH_FFINTFC_ST2_DH 0x0040076c
+#define NV10_PGRAPH_DMA_PITCH 0x00400770
+#define NV10_PGRAPH_DVD_COLORFMT 0x00400774
+#define NV10_PGRAPH_SCALED_FORMAT 0x00400778
+#define NV20_PGRAPH_CHANNEL_CTX_TABLE 0x00400780
+#define NV20_PGRAPH_CHANNEL_CTX_POINTER 0x00400784
+#define NV20_PGRAPH_CHANNEL_CTX_XFER 0x00400788
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_LOAD 0x00000001
+#define NV20_PGRAPH_CHANNEL_CTX_XFER_SAVE 0x00000002
+#define NV04_PGRAPH_PATT_COLOR0 0x00400800
+#define NV04_PGRAPH_PATT_COLOR1 0x00400804
+#define NV04_PGRAPH_PATTERN 0x00400808
+#define NV04_PGRAPH_PATTERN_SHAPE 0x00400810
+#define NV04_PGRAPH_CHROMA 0x00400814
+#define NV04_PGRAPH_CONTROL0 0x00400818
+#define NV04_PGRAPH_CONTROL1 0x0040081C
+#define NV04_PGRAPH_CONTROL2 0x00400820
+#define NV04_PGRAPH_BLEND 0x00400824
+#define NV04_PGRAPH_STORED_FMT 0x00400830
+#define NV04_PGRAPH_PATT_COLORRAM 0x00400900
+#define NV20_PGRAPH_TILE(i) (0x00400900 + (i*16))
+#define NV20_PGRAPH_TLIMIT(i) (0x00400904 + (i*16))
+#define NV20_PGRAPH_TSIZE(i) (0x00400908 + (i*16))
+#define NV20_PGRAPH_TSTATUS(i) (0x0040090C + (i*16))
+#define NV20_PGRAPH_ZCOMP(i) (0x00400980 + 4*(i))
+#define NV41_PGRAPH_ZCOMP0(i) (0x004009c0 + 4*(i))
+#define NV10_PGRAPH_TILE(i) (0x00400B00 + (i*16))
+#define NV10_PGRAPH_TLIMIT(i) (0x00400B04 + (i*16))
+#define NV10_PGRAPH_TSIZE(i) (0x00400B08 + (i*16))
+#define NV10_PGRAPH_TSTATUS(i) (0x00400B0C + (i*16))
+#define NV04_PGRAPH_U_RAM 0x00400D00
+#define NV47_PGRAPH_TILE(i) (0x00400D00 + (i*16))
+#define NV47_PGRAPH_TLIMIT(i) (0x00400D04 + (i*16))
+#define NV47_PGRAPH_TSIZE(i) (0x00400D08 + (i*16))
+#define NV47_PGRAPH_TSTATUS(i) (0x00400D0C + (i*16))
+#define NV04_PGRAPH_V_RAM 0x00400D40
+#define NV04_PGRAPH_W_RAM 0x00400D80
+#define NV47_PGRAPH_ZCOMP0(i) (0x00400e00 + 4*(i))
+#define NV10_PGRAPH_COMBINER0_IN_ALPHA 0x00400E40
+#define NV10_PGRAPH_COMBINER1_IN_ALPHA 0x00400E44
+#define NV10_PGRAPH_COMBINER0_IN_RGB 0x00400E48
+#define NV10_PGRAPH_COMBINER1_IN_RGB 0x00400E4C
+#define NV10_PGRAPH_COMBINER_COLOR0 0x00400E50
+#define NV10_PGRAPH_COMBINER_COLOR1 0x00400E54
+#define NV10_PGRAPH_COMBINER0_OUT_ALPHA 0x00400E58
+#define NV10_PGRAPH_COMBINER1_OUT_ALPHA 0x00400E5C
+#define NV10_PGRAPH_COMBINER0_OUT_RGB 0x00400E60
+#define NV10_PGRAPH_COMBINER1_OUT_RGB 0x00400E64
+#define NV10_PGRAPH_COMBINER_FINAL0 0x00400E68
+#define NV10_PGRAPH_COMBINER_FINAL1 0x00400E6C
+#define NV10_PGRAPH_WINDOWCLIP_HORIZONTAL 0x00400F00
+#define NV10_PGRAPH_WINDOWCLIP_VERTICAL 0x00400F20
+#define NV10_PGRAPH_XFMODE0 0x00400F40
+#define NV10_PGRAPH_XFMODE1 0x00400F44
+#define NV10_PGRAPH_GLOBALSTATE0 0x00400F48
+#define NV10_PGRAPH_GLOBALSTATE1 0x00400F4C
+#define NV10_PGRAPH_PIPE_ADDRESS 0x00400F50
+#define NV10_PGRAPH_PIPE_DATA 0x00400F54
+#define NV04_PGRAPH_DMA_START_0 0x00401000
+#define NV04_PGRAPH_DMA_START_1 0x00401004
+#define NV04_PGRAPH_DMA_LENGTH 0x00401008
+#define NV04_PGRAPH_DMA_MISC 0x0040100C
+#define NV04_PGRAPH_DMA_DATA_0 0x00401020
+#define NV04_PGRAPH_DMA_DATA_1 0x00401024
+#define NV04_PGRAPH_DMA_RM 0x00401030
+#define NV04_PGRAPH_DMA_A_XLATE_INST 0x00401040
+#define NV04_PGRAPH_DMA_A_CONTROL 0x00401044
+#define NV04_PGRAPH_DMA_A_LIMIT 0x00401048
+#define NV04_PGRAPH_DMA_A_TLB_PTE 0x0040104C
+#define NV04_PGRAPH_DMA_A_TLB_TAG 0x00401050
+#define NV04_PGRAPH_DMA_A_ADJ_OFFSET 0x00401054
+#define NV04_PGRAPH_DMA_A_OFFSET 0x00401058
+#define NV04_PGRAPH_DMA_A_SIZE 0x0040105C
+#define NV04_PGRAPH_DMA_A_Y_SIZE 0x00401060
+#define NV04_PGRAPH_DMA_B_XLATE_INST 0x00401080
+#define NV04_PGRAPH_DMA_B_CONTROL 0x00401084
+#define NV04_PGRAPH_DMA_B_LIMIT 0x00401088
+#define NV04_PGRAPH_DMA_B_TLB_PTE 0x0040108C
+#define NV04_PGRAPH_DMA_B_TLB_TAG 0x00401090
+#define NV04_PGRAPH_DMA_B_ADJ_OFFSET 0x00401094
+#define NV04_PGRAPH_DMA_B_OFFSET 0x00401098
+#define NV04_PGRAPH_DMA_B_SIZE 0x0040109C
+#define NV04_PGRAPH_DMA_B_Y_SIZE 0x004010A0
+#define NV47_PGRAPH_ZCOMP1(i) (0x004068c0 + 4*(i))
+#define NV40_PGRAPH_TILE1(i) (0x00406900 + (i*16))
+#define NV40_PGRAPH_TLIMIT1(i) (0x00406904 + (i*16))
+#define NV40_PGRAPH_TSIZE1(i) (0x00406908 + (i*16))
+#define NV40_PGRAPH_TSTATUS1(i) (0x0040690C + (i*16))
+#define NV40_PGRAPH_ZCOMP1(i) (0x00406980 + 4*(i))
+#define NV41_PGRAPH_ZCOMP1(i) (0x004069c0 + 4*(i))
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild
new file mode 100644
index 000000000000..61b7b5f98f3c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/Kbuild
@@ -0,0 +1,5 @@
+nvkm-y += nvkm/engine/mpeg/nv31.o
+nvkm-y += nvkm/engine/mpeg/nv40.o
+nvkm-y += nvkm/engine/mpeg/nv44.o
+nvkm-y += nvkm/engine/mpeg/nv50.o
+nvkm-y += nvkm/engine/mpeg/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c
new file mode 100644
index 000000000000..0df889fa2611
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/g84.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mpeg.h>
+
+struct g84_mpeg_priv {
+ struct nvkm_mpeg base;
+};
+
+struct g84_mpeg_chan {
+ struct nvkm_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_mpeg_sclass[] = {
+ { 0x8274, &nv50_mpeg_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_mpeg_cclass = {
+ .handle = NV_ENGCTX(MPEG, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_mpeg_context_ctor,
+ .dtor = _nvkm_mpeg_context_dtor,
+ .init = _nvkm_mpeg_context_init,
+ .fini = _nvkm_mpeg_context_fini,
+ .rd32 = _nvkm_mpeg_context_rd32,
+ .wr32 = _nvkm_mpeg_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static int
+g84_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g84_mpeg_priv *priv;
+ int ret;
+
+ ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000002;
+ nv_subdev(priv)->intr = nv50_mpeg_intr;
+ nv_engine(priv)->cclass = &g84_mpeg_cclass;
+ nv_engine(priv)->sclass = g84_mpeg_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+g84_mpeg_oclass = {
+ .handle = NV_ENGINE(MPEG, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_mpeg_ctor,
+ .dtor = _nvkm_mpeg_dtor,
+ .init = nv50_mpeg_init,
+ .fini = _nvkm_mpeg_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
new file mode 100644
index 000000000000..b5bef0718359
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.c
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv31.h"
+
+#include <core/client.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+#include <subdev/instmem.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static int
+nv31_mpeg_object_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj *obj;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+ 20, 16, 0, &obj);
+ *pobject = nv_object(obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, nv_mclass(obj));
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ return 0;
+}
+
+static int
+nv31_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len)
+{
+ struct nvkm_instmem *imem = nvkm_instmem(object);
+ struct nv31_mpeg_priv *priv = (void *)object->engine;
+ u32 inst = *(u32 *)arg << 4;
+ u32 dma0 = nv_ro32(imem, inst + 0);
+ u32 dma1 = nv_ro32(imem, inst + 4);
+ u32 dma2 = nv_ro32(imem, inst + 8);
+ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+ u32 size = dma1 + 1;
+
+ /* only allow linear DMA objects */
+ if (!(dma0 & 0x00002000))
+ return -EINVAL;
+
+ if (mthd == 0x0190) {
+ /* DMA_CMD */
+ nv_mask(priv, 0x00b300, 0x00010000, (dma0 & 0x00030000) ? 0x00010000 : 0);
+ nv_wr32(priv, 0x00b334, base);
+ nv_wr32(priv, 0x00b324, size);
+ } else
+ if (mthd == 0x01a0) {
+ /* DMA_DATA */
+ nv_mask(priv, 0x00b300, 0x00020000, (dma0 & 0x00030000) ? 0x00020000 : 0);
+ nv_wr32(priv, 0x00b360, base);
+ nv_wr32(priv, 0x00b364, size);
+ } else {
+ /* DMA_IMAGE, VRAM only */
+ if (dma0 & 0x00030000)
+ return -EINVAL;
+
+ nv_wr32(priv, 0x00b370, base);
+ nv_wr32(priv, 0x00b374, size);
+ }
+
+ return 0;
+}
+
+struct nvkm_ofuncs
+nv31_mpeg_ofuncs = {
+ .ctor = nv31_mpeg_object_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_omthds
+nv31_mpeg_omthds[] = {
+ { 0x0190, 0x0190, nv31_mpeg_mthd_dma },
+ { 0x01a0, 0x01a0, nv31_mpeg_mthd_dma },
+ { 0x01b0, 0x01b0, nv31_mpeg_mthd_dma },
+ {}
+};
+
+struct nvkm_oclass
+nv31_mpeg_sclass[] = {
+ { 0x3174, &nv31_mpeg_ofuncs, nv31_mpeg_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static int
+nv31_mpeg_context_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv31_mpeg_priv *priv = (void *)engine;
+ struct nv31_mpeg_chan *chan;
+ unsigned long flags;
+ int ret;
+
+ ret = nvkm_object_create(parent, engine, oclass, 0, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+ if (priv->chan) {
+ spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+ nvkm_object_destroy(&chan->base);
+ *pobject = NULL;
+ return -EBUSY;
+ }
+ priv->chan = chan;
+ spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+ return 0;
+}
+
+static void
+nv31_mpeg_context_dtor(struct nvkm_object *object)
+{
+ struct nv31_mpeg_priv *priv = (void *)object->engine;
+ struct nv31_mpeg_chan *chan = (void *)object;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+ priv->chan = NULL;
+ spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+ nvkm_object_destroy(&chan->base);
+}
+
+struct nvkm_oclass
+nv31_mpeg_cclass = {
+ .handle = NV_ENGCTX(MPEG, 0x31),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv31_mpeg_context_ctor,
+ .dtor = nv31_mpeg_context_dtor,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ },
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+void
+nv31_mpeg_tile_prog(struct nvkm_engine *engine, int i)
+{
+ struct nvkm_fb_tile *tile = &nvkm_fb(engine)->tile.region[i];
+ struct nv31_mpeg_priv *priv = (void *)engine;
+
+ nv_wr32(priv, 0x00b008 + (i * 0x10), tile->pitch);
+ nv_wr32(priv, 0x00b004 + (i * 0x10), tile->limit);
+ nv_wr32(priv, 0x00b000 + (i * 0x10), tile->addr);
+}
+
+void
+nv31_mpeg_intr(struct nvkm_subdev *subdev)
+{
+ struct nv31_mpeg_priv *priv = (void *)subdev;
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_handle *handle;
+ struct nvkm_object *engctx;
+ u32 stat = nv_rd32(priv, 0x00b100);
+ u32 type = nv_rd32(priv, 0x00b230);
+ u32 mthd = nv_rd32(priv, 0x00b234);
+ u32 data = nv_rd32(priv, 0x00b238);
+ u32 show = stat;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nv_engine(priv)->lock, flags);
+ engctx = nv_object(priv->chan);
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
+ show &= ~0x01000000;
+ }
+
+ if (type == 0x00000010 && engctx) {
+ handle = nvkm_handle_get_class(engctx, 0x3174);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~0x01000000;
+ nvkm_handle_put(handle);
+ }
+ }
+
+ nv_wr32(priv, 0x00b100, stat);
+ nv_wr32(priv, 0x00b230, 0x00000001);
+
+ if (show) {
+ nv_error(priv, "ch %d [%s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ pfifo->chid(pfifo, engctx),
+ nvkm_client_name(engctx), stat, type, mthd, data);
+ }
+
+ spin_unlock_irqrestore(&nv_engine(priv)->lock, flags);
+}
+
+static int
+nv31_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv31_mpeg_priv *priv;
+ int ret;
+
+ ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000002;
+ nv_subdev(priv)->intr = nv31_mpeg_intr;
+ nv_engine(priv)->cclass = &nv31_mpeg_cclass;
+ nv_engine(priv)->sclass = nv31_mpeg_sclass;
+ nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+ return 0;
+}
+
+int
+nv31_mpeg_init(struct nvkm_object *object)
+{
+ struct nvkm_engine *engine = nv_engine(object);
+ struct nv31_mpeg_priv *priv = (void *)object;
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ int ret, i;
+
+ ret = nvkm_mpeg_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* VPE init */
+ nv_wr32(priv, 0x00b0e0, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+ nv_wr32(priv, 0x00b0e8, 0x00000020); /* nvidia: rd 0x01, wr 0x20 */
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ engine->tile_prog(engine, i);
+
+ /* PMPEG init */
+ nv_wr32(priv, 0x00b32c, 0x00000000);
+ nv_wr32(priv, 0x00b314, 0x00000100);
+ nv_wr32(priv, 0x00b220, 0x00000031);
+ nv_wr32(priv, 0x00b300, 0x02001ec1);
+ nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+
+ nv_wr32(priv, 0x00b100, 0xffffffff);
+ nv_wr32(priv, 0x00b140, 0xffffffff);
+
+ if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
+ nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass
+nv31_mpeg_oclass = {
+ .handle = NV_ENGINE(MPEG, 0x31),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv31_mpeg_ctor,
+ .dtor = _nvkm_mpeg_dtor,
+ .init = nv31_mpeg_init,
+ .fini = _nvkm_mpeg_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h
new file mode 100644
index 000000000000..782b796d7458
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv31.h
@@ -0,0 +1,13 @@
+#ifndef __NV31_MPEG_H__
+#define __NV31_MPEG_H__
+#include <engine/mpeg.h>
+
+struct nv31_mpeg_chan {
+ struct nvkm_object base;
+};
+
+struct nv31_mpeg_priv {
+ struct nvkm_mpeg base;
+ struct nv31_mpeg_chan *chan;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c
new file mode 100644
index 000000000000..9508bf9e140f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv40.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv31.h"
+
+#include <subdev/instmem.h>
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static int
+nv40_mpeg_mthd_dma(struct nvkm_object *object, u32 mthd, void *arg, u32 len)
+{
+ struct nvkm_instmem *imem = nvkm_instmem(object);
+ struct nv31_mpeg_priv *priv = (void *)object->engine;
+ u32 inst = *(u32 *)arg << 4;
+ u32 dma0 = nv_ro32(imem, inst + 0);
+ u32 dma1 = nv_ro32(imem, inst + 4);
+ u32 dma2 = nv_ro32(imem, inst + 8);
+ u32 base = (dma2 & 0xfffff000) | (dma0 >> 20);
+ u32 size = dma1 + 1;
+
+ /* only allow linear DMA objects */
+ if (!(dma0 & 0x00002000))
+ return -EINVAL;
+
+ if (mthd == 0x0190) {
+ /* DMA_CMD */
+ nv_mask(priv, 0x00b300, 0x00030000, (dma0 & 0x00030000));
+ nv_wr32(priv, 0x00b334, base);
+ nv_wr32(priv, 0x00b324, size);
+ } else
+ if (mthd == 0x01a0) {
+ /* DMA_DATA */
+ nv_mask(priv, 0x00b300, 0x000c0000, (dma0 & 0x00030000) << 2);
+ nv_wr32(priv, 0x00b360, base);
+ nv_wr32(priv, 0x00b364, size);
+ } else {
+ /* DMA_IMAGE, VRAM only */
+ if (dma0 & 0x00030000)
+ return -EINVAL;
+
+ nv_wr32(priv, 0x00b370, base);
+ nv_wr32(priv, 0x00b374, size);
+ }
+
+ return 0;
+}
+
+static struct nvkm_omthds
+nv40_mpeg_omthds[] = {
+ { 0x0190, 0x0190, nv40_mpeg_mthd_dma },
+ { 0x01a0, 0x01a0, nv40_mpeg_mthd_dma },
+ { 0x01b0, 0x01b0, nv40_mpeg_mthd_dma },
+ {}
+};
+
+struct nvkm_oclass
+nv40_mpeg_sclass[] = {
+ { 0x3174, &nv31_mpeg_ofuncs, nv40_mpeg_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv40_mpeg_intr(struct nvkm_subdev *subdev)
+{
+ struct nv31_mpeg_priv *priv = (void *)subdev;
+ u32 stat;
+
+ if ((stat = nv_rd32(priv, 0x00b100)))
+ nv31_mpeg_intr(subdev);
+
+ if ((stat = nv_rd32(priv, 0x00b800))) {
+ nv_error(priv, "PMSRCH 0x%08x\n", stat);
+ nv_wr32(priv, 0x00b800, stat);
+ }
+}
+
+static int
+nv40_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv31_mpeg_priv *priv;
+ int ret;
+
+ ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000002;
+ nv_subdev(priv)->intr = nv40_mpeg_intr;
+ nv_engine(priv)->cclass = &nv31_mpeg_cclass;
+ nv_engine(priv)->sclass = nv40_mpeg_sclass;
+ nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv40_mpeg_oclass = {
+ .handle = NV_ENGINE(MPEG, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_mpeg_ctor,
+ .dtor = _nvkm_mpeg_dtor,
+ .init = nv31_mpeg_init,
+ .fini = _nvkm_mpeg_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
new file mode 100644
index 000000000000..4720ac884468
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv44.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mpeg.h>
+
+#include <core/client.h>
+#include <core/handle.h>
+#include <engine/fifo.h>
+
+struct nv44_mpeg_priv {
+ struct nvkm_mpeg base;
+};
+
+struct nv44_mpeg_chan {
+ struct nvkm_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+static int
+nv44_mpeg_context_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv44_mpeg_chan *chan;
+ int ret;
+
+ ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 264 * 4,
+ 16, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ nv_wo32(&chan->base.base, 0x78, 0x02001ec1);
+ return 0;
+}
+
+static int
+nv44_mpeg_context_fini(struct nvkm_object *object, bool suspend)
+{
+
+ struct nv44_mpeg_priv *priv = (void *)object->engine;
+ struct nv44_mpeg_chan *chan = (void *)object;
+ u32 inst = 0x80000000 | nv_gpuobj(chan)->addr >> 4;
+
+ nv_mask(priv, 0x00b32c, 0x00000001, 0x00000000);
+ if (nv_rd32(priv, 0x00b318) == inst)
+ nv_mask(priv, 0x00b318, 0x80000000, 0x00000000);
+ nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv44_mpeg_cclass = {
+ .handle = NV_ENGCTX(MPEG, 0x44),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv44_mpeg_context_ctor,
+ .dtor = _nvkm_mpeg_context_dtor,
+ .init = _nvkm_mpeg_context_init,
+ .fini = nv44_mpeg_context_fini,
+ .rd32 = _nvkm_mpeg_context_rd32,
+ .wr32 = _nvkm_mpeg_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+static void
+nv44_mpeg_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct nvkm_handle *handle;
+ struct nv44_mpeg_priv *priv = (void *)subdev;
+ u32 inst = nv_rd32(priv, 0x00b318) & 0x000fffff;
+ u32 stat = nv_rd32(priv, 0x00b100);
+ u32 type = nv_rd32(priv, 0x00b230);
+ u32 mthd = nv_rd32(priv, 0x00b234);
+ u32 data = nv_rd32(priv, 0x00b238);
+ u32 show = stat;
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_mask(priv, 0x00b308, 0x00000000, 0x00000000);
+ show &= ~0x01000000;
+ }
+
+ if (type == 0x00000010) {
+ handle = nvkm_handle_get_class(engctx, 0x3174);
+ if (handle && !nv_call(handle->object, mthd, data))
+ show &= ~0x01000000;
+ nvkm_handle_put(handle);
+ }
+ }
+
+ nv_wr32(priv, 0x00b100, stat);
+ nv_wr32(priv, 0x00b230, 0x00000001);
+
+ if (show) {
+ nv_error(priv,
+ "ch %d [0x%08x %s] 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ chid, inst << 4, nvkm_client_name(engctx), stat,
+ type, mthd, data);
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static void
+nv44_mpeg_me_intr(struct nvkm_subdev *subdev)
+{
+ struct nv44_mpeg_priv *priv = (void *)subdev;
+ u32 stat;
+
+ if ((stat = nv_rd32(priv, 0x00b100)))
+ nv44_mpeg_intr(subdev);
+
+ if ((stat = nv_rd32(priv, 0x00b800))) {
+ nv_error(priv, "PMSRCH 0x%08x\n", stat);
+ nv_wr32(priv, 0x00b800, stat);
+ }
+}
+
+static int
+nv44_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv44_mpeg_priv *priv;
+ int ret;
+
+ ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000002;
+ nv_subdev(priv)->intr = nv44_mpeg_me_intr;
+ nv_engine(priv)->cclass = &nv44_mpeg_cclass;
+ nv_engine(priv)->sclass = nv40_mpeg_sclass;
+ nv_engine(priv)->tile_prog = nv31_mpeg_tile_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv44_mpeg_oclass = {
+ .handle = NV_ENGINE(MPEG, 0x44),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv44_mpeg_ctor,
+ .dtor = _nvkm_mpeg_dtor,
+ .init = nv31_mpeg_init,
+ .fini = _nvkm_mpeg_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c
new file mode 100644
index 000000000000..b3463f3739ce
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mpeg/nv50.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mpeg.h>
+
+#include <subdev/bar.h>
+#include <subdev/timer.h>
+
+struct nv50_mpeg_priv {
+ struct nvkm_mpeg base;
+};
+
+struct nv50_mpeg_chan {
+ struct nvkm_mpeg_chan base;
+};
+
+/*******************************************************************************
+ * MPEG object classes
+ ******************************************************************************/
+
+static int
+nv50_mpeg_object_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpuobj *obj;
+ int ret;
+
+ ret = nvkm_gpuobj_create(parent, engine, oclass, 0, parent,
+ 16, 16, 0, &obj);
+ *pobject = nv_object(obj);
+ if (ret)
+ return ret;
+
+ nv_wo32(obj, 0x00, nv_mclass(obj));
+ nv_wo32(obj, 0x04, 0x00000000);
+ nv_wo32(obj, 0x08, 0x00000000);
+ nv_wo32(obj, 0x0c, 0x00000000);
+ return 0;
+}
+
+struct nvkm_ofuncs
+nv50_mpeg_ofuncs = {
+ .ctor = nv50_mpeg_object_ctor,
+ .dtor = _nvkm_gpuobj_dtor,
+ .init = _nvkm_gpuobj_init,
+ .fini = _nvkm_gpuobj_fini,
+ .rd32 = _nvkm_gpuobj_rd32,
+ .wr32 = _nvkm_gpuobj_wr32,
+};
+
+static struct nvkm_oclass
+nv50_mpeg_sclass[] = {
+ { 0x3174, &nv50_mpeg_ofuncs },
+ {}
+};
+
+/*******************************************************************************
+ * PMPEG context
+ ******************************************************************************/
+
+int
+nv50_mpeg_context_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_bar *bar = nvkm_bar(parent);
+ struct nv50_mpeg_chan *chan;
+ int ret;
+
+ ret = nvkm_mpeg_context_create(parent, engine, oclass, NULL, 128 * 4,
+ 0, NVOBJ_FLAG_ZERO_ALLOC, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ nv_wo32(chan, 0x0070, 0x00801ec1);
+ nv_wo32(chan, 0x007c, 0x0000037c);
+ bar->flush(bar);
+ return 0;
+}
+
+static struct nvkm_oclass
+nv50_mpeg_cclass = {
+ .handle = NV_ENGCTX(MPEG, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_mpeg_context_ctor,
+ .dtor = _nvkm_mpeg_context_dtor,
+ .init = _nvkm_mpeg_context_init,
+ .fini = _nvkm_mpeg_context_fini,
+ .rd32 = _nvkm_mpeg_context_rd32,
+ .wr32 = _nvkm_mpeg_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMPEG engine/subdev functions
+ ******************************************************************************/
+
+void
+nv50_mpeg_intr(struct nvkm_subdev *subdev)
+{
+ struct nv50_mpeg_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, 0x00b100);
+ u32 type = nv_rd32(priv, 0x00b230);
+ u32 mthd = nv_rd32(priv, 0x00b234);
+ u32 data = nv_rd32(priv, 0x00b238);
+ u32 show = stat;
+
+ if (stat & 0x01000000) {
+ /* happens on initial binding of the object */
+ if (type == 0x00000020 && mthd == 0x0000) {
+ nv_wr32(priv, 0x00b308, 0x00000100);
+ show &= ~0x01000000;
+ }
+ }
+
+ if (show) {
+ nv_info(priv, "0x%08x 0x%08x 0x%08x 0x%08x\n",
+ stat, type, mthd, data);
+ }
+
+ nv_wr32(priv, 0x00b100, stat);
+ nv_wr32(priv, 0x00b230, 0x00000001);
+}
+
+static void
+nv50_vpe_intr(struct nvkm_subdev *subdev)
+{
+ struct nv50_mpeg_priv *priv = (void *)subdev;
+
+ if (nv_rd32(priv, 0x00b100))
+ nv50_mpeg_intr(subdev);
+
+ if (nv_rd32(priv, 0x00b800)) {
+ u32 stat = nv_rd32(priv, 0x00b800);
+ nv_info(priv, "PMSRCH: 0x%08x\n", stat);
+ nv_wr32(priv, 0xb800, stat);
+ }
+}
+
+static int
+nv50_mpeg_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_mpeg_priv *priv;
+ int ret;
+
+ ret = nvkm_mpeg_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00400002;
+ nv_subdev(priv)->intr = nv50_vpe_intr;
+ nv_engine(priv)->cclass = &nv50_mpeg_cclass;
+ nv_engine(priv)->sclass = nv50_mpeg_sclass;
+ return 0;
+}
+
+int
+nv50_mpeg_init(struct nvkm_object *object)
+{
+ struct nv50_mpeg_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_mpeg_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x00b32c, 0x00000000);
+ nv_wr32(priv, 0x00b314, 0x00000100);
+ nv_wr32(priv, 0x00b0e0, 0x0000001a);
+
+ nv_wr32(priv, 0x00b220, 0x00000044);
+ nv_wr32(priv, 0x00b300, 0x00801ec1);
+ nv_wr32(priv, 0x00b390, 0x00000000);
+ nv_wr32(priv, 0x00b394, 0x00000000);
+ nv_wr32(priv, 0x00b398, 0x00000000);
+ nv_mask(priv, 0x00b32c, 0x00000001, 0x00000001);
+
+ nv_wr32(priv, 0x00b100, 0xffffffff);
+ nv_wr32(priv, 0x00b140, 0xffffffff);
+
+ if (!nv_wait(priv, 0x00b200, 0x00000001, 0x00000000)) {
+ nv_error(priv, "timeout 0x%08x\n", nv_rd32(priv, 0x00b200));
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass
+nv50_mpeg_oclass = {
+ .handle = NV_ENGINE(MPEG, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_mpeg_ctor,
+ .dtor = _nvkm_mpeg_dtor,
+ .init = nv50_mpeg_init,
+ .fini = _nvkm_mpeg_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild
new file mode 100644
index 000000000000..c59c83a67315
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/engine/mspdec/g98.o
+nvkm-y += nvkm/engine/mspdec/gf100.o
+nvkm-y += nvkm/engine/mspdec/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c
new file mode 100644
index 000000000000..2174577793a4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/g98.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
+ */
+#include <engine/mspdec.h>
+#include <engine/falcon.h>
+
+struct g98_mspdec_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPDEC object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_mspdec_sclass[] = {
+ { 0x88b2, &nvkm_object_ofuncs },
+ { 0x85b2, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSPDEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_mspdec_cclass = {
+ .handle = NV_ENGCTX(MSPDEC, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSPDEC engine/subdev functions
+ ******************************************************************************/
+
+static int
+g98_mspdec_init(struct nvkm_object *object)
+{
+ struct g98_mspdec_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x085010, 0x0000ffd2);
+ nv_wr32(priv, 0x08501c, 0x0000fff2);
+ return 0;
+}
+
+static int
+g98_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g98_mspdec_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true,
+ "PMSPDEC", "mspdec", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x01020000;
+ nv_engine(priv)->cclass = &g98_mspdec_cclass;
+ nv_engine(priv)->sclass = g98_mspdec_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+g98_mspdec_oclass = {
+ .handle = NV_ENGINE(MSPDEC, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g98_mspdec_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = g98_mspdec_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c
new file mode 100644
index 000000000000..c814a5f65eb0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gf100.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Maarten Lankhorst
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Maarten Lankhorst
+ */
+#include <engine/mspdec.h>
+#include <engine/falcon.h>
+
+struct gf100_mspdec_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPDEC object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_mspdec_sclass[] = {
+ { 0x90b2, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSPDEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_mspdec_cclass = {
+ .handle = NV_ENGCTX(MSPDEC, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSPDEC engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_mspdec_init(struct nvkm_object *object)
+{
+ struct gf100_mspdec_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x085010, 0x0000fff2);
+ nv_wr32(priv, 0x08501c, 0x0000fff2);
+ return 0;
+}
+
+static int
+gf100_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_mspdec_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true,
+ "PMSPDEC", "mspdec", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00020000;
+ nv_subdev(priv)->intr = nvkm_falcon_intr;
+ nv_engine(priv)->cclass = &gf100_mspdec_cclass;
+ nv_engine(priv)->sclass = gf100_mspdec_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_mspdec_oclass = {
+ .handle = NV_ENGINE(MSPDEC, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_mspdec_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gf100_mspdec_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c
new file mode 100644
index 000000000000..979920650dbd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/mspdec/gk104.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/mspdec.h>
+#include <engine/falcon.h>
+
+struct gk104_mspdec_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPDEC object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_mspdec_sclass[] = {
+ { 0x95b2, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSPDEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_mspdec_cclass = {
+ .handle = NV_ENGCTX(MSPDEC, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSPDEC engine/subdev functions
+ ******************************************************************************/
+
+static int
+gk104_mspdec_init(struct nvkm_object *object)
+{
+ struct gk104_mspdec_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x085010, 0x0000fff2);
+ nv_wr32(priv, 0x08501c, 0x0000fff2);
+ return 0;
+}
+
+static int
+gk104_mspdec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_mspdec_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x085000, true,
+ "PMSPDEC", "mspdec", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00020000;
+ nv_subdev(priv)->intr = nvkm_falcon_intr;
+ nv_engine(priv)->cclass = &gk104_mspdec_cclass;
+ nv_engine(priv)->sclass = gk104_mspdec_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_mspdec_oclass = {
+ .handle = NV_ENGINE(MSPDEC, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_mspdec_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gk104_mspdec_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild
new file mode 100644
index 000000000000..4576a9eee39d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/Kbuild
@@ -0,0 +1,2 @@
+nvkm-y += nvkm/engine/msppp/g98.o
+nvkm-y += nvkm/engine/msppp/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c
new file mode 100644
index 000000000000..7a602a2dec94
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/g98.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
+ */
+#include <engine/msppp.h>
+#include <engine/falcon.h>
+
+struct g98_msppp_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPPP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msppp_sclass[] = {
+ { 0x88b3, &nvkm_object_ofuncs },
+ { 0x85b3, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSPPP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msppp_cclass = {
+ .handle = NV_ENGCTX(MSPPP, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSPPP engine/subdev functions
+ ******************************************************************************/
+
+static int
+g98_msppp_init(struct nvkm_object *object)
+{
+ struct g98_msppp_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x086010, 0x0000ffd2);
+ nv_wr32(priv, 0x08601c, 0x0000fff2);
+ return 0;
+}
+
+static int
+g98_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g98_msppp_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true,
+ "PMSPPP", "msppp", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00400002;
+ nv_engine(priv)->cclass = &g98_msppp_cclass;
+ nv_engine(priv)->sclass = g98_msppp_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+g98_msppp_oclass = {
+ .handle = NV_ENGINE(MSPPP, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g98_msppp_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = g98_msppp_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c
new file mode 100644
index 000000000000..6047baee1f75
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msppp/gf100.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Maarten Lankhorst
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Maarten Lankhorst
+ */
+#include <engine/msppp.h>
+#include <engine/falcon.h>
+
+struct gf100_msppp_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSPPP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msppp_sclass[] = {
+ { 0x90b3, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSPPP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msppp_cclass = {
+ .handle = NV_ENGCTX(MSPPP, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSPPP engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_msppp_init(struct nvkm_object *object)
+{
+ struct gf100_msppp_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x086010, 0x0000fff2);
+ nv_wr32(priv, 0x08601c, 0x0000fff2);
+ return 0;
+}
+
+static int
+gf100_msppp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_msppp_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x086000, true,
+ "PMSPPP", "msppp", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00000002;
+ nv_subdev(priv)->intr = nvkm_falcon_intr;
+ nv_engine(priv)->cclass = &gf100_msppp_cclass;
+ nv_engine(priv)->sclass = gf100_msppp_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_msppp_oclass = {
+ .handle = NV_ENGINE(MSPPP, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_msppp_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gf100_msppp_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild
new file mode 100644
index 000000000000..0c9811009e28
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/engine/msvld/g98.o
+nvkm-y += nvkm/engine/msvld/gf100.o
+nvkm-y += nvkm/engine/msvld/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c
new file mode 100644
index 000000000000..c8a6b4ef52a1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/g98.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs, Maarten Lankhorst, Ilia Mirkin
+ */
+#include <engine/msvld.h>
+#include <engine/falcon.h>
+
+struct g98_msvld_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSVLD object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msvld_sclass[] = {
+ { 0x88b1, &nvkm_object_ofuncs },
+ { 0x85b1, &nvkm_object_ofuncs },
+ { 0x86b1, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSVLD context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_msvld_cclass = {
+ .handle = NV_ENGCTX(MSVLD, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSVLD engine/subdev functions
+ ******************************************************************************/
+
+static int
+g98_msvld_init(struct nvkm_object *object)
+{
+ struct g98_msvld_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x084010, 0x0000ffd2);
+ nv_wr32(priv, 0x08401c, 0x0000fff2);
+ return 0;
+}
+
+static int
+g98_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g98_msvld_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true,
+ "PMSVLD", "msvld", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x04008000;
+ nv_engine(priv)->cclass = &g98_msvld_cclass;
+ nv_engine(priv)->sclass = g98_msvld_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+g98_msvld_oclass = {
+ .handle = NV_ENGINE(MSVLD, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g98_msvld_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = g98_msvld_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c
new file mode 100644
index 000000000000..b8d1e0f521ef
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gf100.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Maarten Lankhorst
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Maarten Lankhorst
+ */
+#include <engine/msvld.h>
+#include <engine/falcon.h>
+
+struct gf100_msvld_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSVLD object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msvld_sclass[] = {
+ { 0x90b1, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSVLD context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gf100_msvld_cclass = {
+ .handle = NV_ENGCTX(MSVLD, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSVLD engine/subdev functions
+ ******************************************************************************/
+
+static int
+gf100_msvld_init(struct nvkm_object *object)
+{
+ struct gf100_msvld_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x084010, 0x0000fff2);
+ nv_wr32(priv, 0x08401c, 0x0000fff2);
+ return 0;
+}
+
+static int
+gf100_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_msvld_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true,
+ "PMSVLD", "msvld", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00008000;
+ nv_subdev(priv)->intr = nvkm_falcon_intr;
+ nv_engine(priv)->cclass = &gf100_msvld_cclass;
+ nv_engine(priv)->sclass = gf100_msvld_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_msvld_oclass = {
+ .handle = NV_ENGINE(MSVLD, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_msvld_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gf100_msvld_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c
new file mode 100644
index 000000000000..a0b0927834df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/msvld/gk104.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/msvld.h>
+#include <engine/falcon.h>
+
+struct gk104_msvld_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * MSVLD object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_msvld_sclass[] = {
+ { 0x95b1, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PMSVLD context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+gk104_msvld_cclass = {
+ .handle = NV_ENGCTX(MSVLD, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PMSVLD engine/subdev functions
+ ******************************************************************************/
+
+static int
+gk104_msvld_init(struct nvkm_object *object)
+{
+ struct gk104_msvld_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_falcon_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x084010, 0x0000fff2);
+ nv_wr32(priv, 0x08401c, 0x0000fff2);
+ return 0;
+}
+
+static int
+gk104_msvld_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_msvld_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x084000, true,
+ "PMSVLD", "msvld", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00008000;
+ nv_subdev(priv)->intr = nvkm_falcon_intr;
+ nv_engine(priv)->cclass = &gk104_msvld_cclass;
+ nv_engine(priv)->sclass = gk104_msvld_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_msvld_oclass = {
+ .handle = NV_ENGINE(MSVLD, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_msvld_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = gk104_msvld_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild
new file mode 100644
index 000000000000..413b6091e256
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/Kbuild
@@ -0,0 +1,9 @@
+nvkm-y += nvkm/engine/pm/base.o
+nvkm-y += nvkm/engine/pm/daemon.o
+nvkm-y += nvkm/engine/pm/nv40.o
+nvkm-y += nvkm/engine/pm/nv50.o
+nvkm-y += nvkm/engine/pm/g84.o
+nvkm-y += nvkm/engine/pm/gt215.o
+nvkm-y += nvkm/engine/pm/gf100.o
+nvkm-y += nvkm/engine/pm/gk104.o
+nvkm-y += nvkm/engine/pm/gk110.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
new file mode 100644
index 000000000000..2006c445938d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/base.c
@@ -0,0 +1,476 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/option.h>
+
+#include <nvif/class.h>
+#include <nvif/ioctl.h>
+#include <nvif/unpack.h>
+
+#define QUAD_MASK 0x0f
+#define QUAD_FREE 0x01
+
+static struct nvkm_perfsig *
+nvkm_perfsig_find_(struct nvkm_perfdom *dom, const char *name, u32 size)
+{
+ char path[64];
+ int i;
+
+ if (name[0] != '/') {
+ for (i = 0; i < dom->signal_nr; i++) {
+ if ( dom->signal[i].name &&
+ !strncmp(name, dom->signal[i].name, size))
+ return &dom->signal[i];
+ }
+ } else {
+ for (i = 0; i < dom->signal_nr; i++) {
+ snprintf(path, sizeof(path), "/%s/%02x", dom->name, i);
+ if (!strncmp(name, path, size))
+ return &dom->signal[i];
+ }
+ }
+
+ return NULL;
+}
+
+struct nvkm_perfsig *
+nvkm_perfsig_find(struct nvkm_pm *ppm, const char *name, u32 size,
+ struct nvkm_perfdom **pdom)
+{
+ struct nvkm_perfdom *dom = *pdom;
+ struct nvkm_perfsig *sig;
+
+ if (dom == NULL) {
+ list_for_each_entry(dom, &ppm->domains, head) {
+ sig = nvkm_perfsig_find_(dom, name, size);
+ if (sig) {
+ *pdom = dom;
+ return sig;
+ }
+ }
+
+ return NULL;
+ }
+
+ return nvkm_perfsig_find_(dom, name, size);
+}
+
+struct nvkm_perfctr *
+nvkm_perfsig_wrap(struct nvkm_pm *ppm, const char *name,
+ struct nvkm_perfdom **pdom)
+{
+ struct nvkm_perfsig *sig;
+ struct nvkm_perfctr *ctr;
+
+ sig = nvkm_perfsig_find(ppm, name, strlen(name), pdom);
+ if (!sig)
+ return NULL;
+
+ ctr = kzalloc(sizeof(*ctr), GFP_KERNEL);
+ if (ctr) {
+ ctr->signal[0] = sig;
+ ctr->logic_op = 0xaaaa;
+ }
+
+ return ctr;
+}
+
+/*******************************************************************************
+ * Perfmon object classes
+ ******************************************************************************/
+static int
+nvkm_perfctr_query(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nvif_perfctr_query_v0 v0;
+ } *args = data;
+ struct nvkm_device *device = nv_device(object);
+ struct nvkm_pm *ppm = (void *)object->engine;
+ struct nvkm_perfdom *dom = NULL, *chk;
+ const bool all = nvkm_boolopt(device->cfgopt, "NvPmShowAll", false);
+ const bool raw = nvkm_boolopt(device->cfgopt, "NvPmUnnamed", all);
+ const char *name;
+ int tmp = 0, di, si;
+ int ret;
+
+ nv_ioctl(object, "perfctr query size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "perfctr query vers %d iter %08x\n",
+ args->v0.version, args->v0.iter);
+ di = (args->v0.iter & 0xff000000) >> 24;
+ si = (args->v0.iter & 0x00ffffff) - 1;
+ } else
+ return ret;
+
+ list_for_each_entry(chk, &ppm->domains, head) {
+ if (tmp++ == di) {
+ dom = chk;
+ break;
+ }
+ }
+
+ if (dom == NULL || si >= (int)dom->signal_nr)
+ return -EINVAL;
+
+ if (si >= 0) {
+ if (raw || !(name = dom->signal[si].name)) {
+ snprintf(args->v0.name, sizeof(args->v0.name),
+ "/%s/%02x", dom->name, si);
+ } else {
+ strncpy(args->v0.name, name, sizeof(args->v0.name));
+ }
+ }
+
+ do {
+ while (++si < dom->signal_nr) {
+ if (all || dom->signal[si].name) {
+ args->v0.iter = (di << 24) | ++si;
+ return 0;
+ }
+ }
+ si = -1;
+ di = di + 1;
+ dom = list_entry(dom->head.next, typeof(*dom), head);
+ } while (&dom->head != &ppm->domains);
+
+ args->v0.iter = 0xffffffff;
+ return 0;
+}
+
+static int
+nvkm_perfctr_sample(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nvif_perfctr_sample none;
+ } *args = data;
+ struct nvkm_pm *ppm = (void *)object->engine;
+ struct nvkm_perfctr *ctr, *tmp;
+ struct nvkm_perfdom *dom;
+ int ret;
+
+ nv_ioctl(object, "perfctr sample size %d\n", size);
+ if (nvif_unvers(args->none)) {
+ nv_ioctl(object, "perfctr sample\n");
+ } else
+ return ret;
+ ppm->sequence++;
+
+ list_for_each_entry(dom, &ppm->domains, head) {
+ /* sample previous batch of counters */
+ if (dom->quad != QUAD_MASK) {
+ dom->func->next(ppm, dom);
+ tmp = NULL;
+ while (!list_empty(&dom->list)) {
+ ctr = list_first_entry(&dom->list,
+ typeof(*ctr), head);
+ if (ctr->slot < 0) break;
+ if ( tmp && tmp == ctr) break;
+ if (!tmp) tmp = ctr;
+ dom->func->read(ppm, dom, ctr);
+ ctr->slot = -1;
+ list_move_tail(&ctr->head, &dom->list);
+ }
+ }
+
+ dom->quad = QUAD_MASK;
+
+ /* setup next batch of counters for sampling */
+ list_for_each_entry(ctr, &dom->list, head) {
+ ctr->slot = ffs(dom->quad) - 1;
+ if (ctr->slot < 0)
+ break;
+ dom->quad &= ~(QUAD_FREE << ctr->slot);
+ dom->func->init(ppm, dom, ctr);
+ }
+
+ if (dom->quad != QUAD_MASK)
+ dom->func->next(ppm, dom);
+ }
+
+ return 0;
+}
+
+static int
+nvkm_perfctr_read(struct nvkm_object *object, void *data, u32 size)
+{
+ union {
+ struct nvif_perfctr_read_v0 v0;
+ } *args = data;
+ struct nvkm_perfctr *ctr = (void *)object;
+ int ret;
+
+ nv_ioctl(object, "perfctr read size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(object, "perfctr read vers %d\n", args->v0.version);
+ } else
+ return ret;
+
+ if (!ctr->clk)
+ return -EAGAIN;
+
+ args->v0.clk = ctr->clk;
+ args->v0.ctr = ctr->ctr;
+ return 0;
+}
+
+static int
+nvkm_perfctr_mthd(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ switch (mthd) {
+ case NVIF_PERFCTR_V0_QUERY:
+ return nvkm_perfctr_query(object, data, size);
+ case NVIF_PERFCTR_V0_SAMPLE:
+ return nvkm_perfctr_sample(object, data, size);
+ case NVIF_PERFCTR_V0_READ:
+ return nvkm_perfctr_read(object, data, size);
+ default:
+ break;
+ }
+ return -EINVAL;
+}
+
+static void
+nvkm_perfctr_dtor(struct nvkm_object *object)
+{
+ struct nvkm_perfctr *ctr = (void *)object;
+ if (ctr->head.next)
+ list_del(&ctr->head);
+ nvkm_object_destroy(&ctr->base);
+}
+
+static int
+nvkm_perfctr_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ union {
+ struct nvif_perfctr_v0 v0;
+ } *args = data;
+ struct nvkm_pm *ppm = (void *)engine;
+ struct nvkm_perfdom *dom = NULL;
+ struct nvkm_perfsig *sig[4] = {};
+ struct nvkm_perfctr *ctr;
+ int ret, i;
+
+ nv_ioctl(parent, "create perfctr size %d\n", size);
+ if (nvif_unpack(args->v0, 0, 0, false)) {
+ nv_ioctl(parent, "create perfctr vers %d logic_op %04x\n",
+ args->v0.version, args->v0.logic_op);
+ } else
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(args->v0.name) && args->v0.name[i][0]; i++) {
+ sig[i] = nvkm_perfsig_find(ppm, args->v0.name[i],
+ strnlen(args->v0.name[i],
+ sizeof(args->v0.name[i])),
+ &dom);
+ if (!sig[i])
+ return -EINVAL;
+ }
+
+ ret = nvkm_object_create(parent, engine, oclass, 0, &ctr);
+ *pobject = nv_object(ctr);
+ if (ret)
+ return ret;
+
+ ctr->slot = -1;
+ ctr->logic_op = args->v0.logic_op;
+ ctr->signal[0] = sig[0];
+ ctr->signal[1] = sig[1];
+ ctr->signal[2] = sig[2];
+ ctr->signal[3] = sig[3];
+ if (dom)
+ list_add_tail(&ctr->head, &dom->list);
+ return 0;
+}
+
+static struct nvkm_ofuncs
+nvkm_perfctr_ofuncs = {
+ .ctor = nvkm_perfctr_ctor,
+ .dtor = nvkm_perfctr_dtor,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ .mthd = nvkm_perfctr_mthd,
+};
+
+struct nvkm_oclass
+nvkm_pm_sclass[] = {
+ { .handle = NVIF_IOCTL_NEW_V0_PERFCTR,
+ .ofuncs = &nvkm_perfctr_ofuncs,
+ },
+ {},
+};
+
+/*******************************************************************************
+ * PPM context
+ ******************************************************************************/
+static void
+nvkm_perfctx_dtor(struct nvkm_object *object)
+{
+ struct nvkm_pm *ppm = (void *)object->engine;
+ mutex_lock(&nv_subdev(ppm)->mutex);
+ nvkm_engctx_destroy(&ppm->context->base);
+ ppm->context = NULL;
+ mutex_unlock(&nv_subdev(ppm)->mutex);
+}
+
+static int
+nvkm_perfctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_pm *ppm = (void *)engine;
+ struct nvkm_perfctx *ctx;
+ int ret;
+
+ ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0, 0, 0, &ctx);
+ *pobject = nv_object(ctx);
+ if (ret)
+ return ret;
+
+ mutex_lock(&nv_subdev(ppm)->mutex);
+ if (ppm->context == NULL)
+ ppm->context = ctx;
+ mutex_unlock(&nv_subdev(ppm)->mutex);
+
+ if (ctx != ppm->context)
+ return -EBUSY;
+
+ return 0;
+}
+
+struct nvkm_oclass
+nvkm_pm_cclass = {
+ .handle = NV_ENGCTX(PM, 0x00),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nvkm_perfctx_ctor,
+ .dtor = nvkm_perfctx_dtor,
+ .init = _nvkm_engctx_init,
+ .fini = _nvkm_engctx_fini,
+ },
+};
+
+/*******************************************************************************
+ * PPM engine/subdev functions
+ ******************************************************************************/
+int
+nvkm_perfdom_new(struct nvkm_pm *ppm, const char *name, u32 mask,
+ u32 base, u32 size_unit, u32 size_domain,
+ const struct nvkm_specdom *spec)
+{
+ const struct nvkm_specdom *sdom;
+ const struct nvkm_specsig *ssig;
+ struct nvkm_perfdom *dom;
+ int i;
+
+ for (i = 0; i == 0 || mask; i++) {
+ u32 addr = base + (i * size_unit);
+ if (i && !(mask & (1 << i)))
+ continue;
+
+ sdom = spec;
+ while (sdom->signal_nr) {
+ dom = kzalloc(sizeof(*dom) + sdom->signal_nr *
+ sizeof(*dom->signal), GFP_KERNEL);
+ if (!dom)
+ return -ENOMEM;
+
+ if (mask) {
+ snprintf(dom->name, sizeof(dom->name),
+ "%s/%02x/%02x", name, i,
+ (int)(sdom - spec));
+ } else {
+ snprintf(dom->name, sizeof(dom->name),
+ "%s/%02x", name, (int)(sdom - spec));
+ }
+
+ list_add_tail(&dom->head, &ppm->domains);
+ INIT_LIST_HEAD(&dom->list);
+ dom->func = sdom->func;
+ dom->addr = addr;
+ dom->quad = QUAD_MASK;
+ dom->signal_nr = sdom->signal_nr;
+
+ ssig = (sdom++)->signal;
+ while (ssig->name) {
+ dom->signal[ssig->signal].name = ssig->name;
+ ssig++;
+ }
+
+ addr += size_domain;
+ }
+
+ mask &= ~(1 << i);
+ }
+
+ return 0;
+}
+
+int
+_nvkm_pm_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_pm *ppm = (void *)object;
+ return nvkm_engine_fini(&ppm->base, suspend);
+}
+
+int
+_nvkm_pm_init(struct nvkm_object *object)
+{
+ struct nvkm_pm *ppm = (void *)object;
+ return nvkm_engine_init(&ppm->base);
+}
+
+void
+_nvkm_pm_dtor(struct nvkm_object *object)
+{
+ struct nvkm_pm *ppm = (void *)object;
+ struct nvkm_perfdom *dom, *tmp;
+
+ list_for_each_entry_safe(dom, tmp, &ppm->domains, head) {
+ list_del(&dom->head);
+ kfree(dom);
+ }
+
+ nvkm_engine_destroy(&ppm->base);
+}
+
+int
+nvkm_pm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_pm *ppm;
+ int ret;
+
+ ret = nvkm_engine_create_(parent, engine, oclass, true, "PPM",
+ "pm", length, pobject);
+ ppm = *pobject;
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&ppm->domains);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c
new file mode 100644
index 000000000000..a7a5f3a3c91b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/daemon.c
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static void
+pwr_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+ struct nvkm_perfctr *ctr)
+{
+ u32 mask = 0x00000000;
+ u32 ctrl = 0x00000001;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(ctr->signal) && ctr->signal[i]; i++)
+ mask |= 1 << (ctr->signal[i] - dom->signal);
+
+ nv_wr32(ppm, 0x10a504 + (ctr->slot * 0x10), mask);
+ nv_wr32(ppm, 0x10a50c + (ctr->slot * 0x10), ctrl);
+ nv_wr32(ppm, 0x10a50c + (ppm->last * 0x10), 0x00000003);
+}
+
+static void
+pwr_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+ struct nvkm_perfctr *ctr)
+{
+ ctr->ctr = ppm->pwr[ctr->slot];
+ ctr->clk = ppm->pwr[ppm->last];
+}
+
+static void
+pwr_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom)
+{
+ int i;
+
+ for (i = 0; i <= ppm->last; i++) {
+ ppm->pwr[i] = nv_rd32(ppm, 0x10a508 + (i * 0x10));
+ nv_wr32(ppm, 0x10a508 + (i * 0x10), 0x80000000);
+ }
+}
+
+static const struct nvkm_funcdom
+pwr_perfctr_func = {
+ .init = pwr_perfctr_init,
+ .read = pwr_perfctr_read,
+ .next = pwr_perfctr_next,
+};
+
+const struct nvkm_specdom
+gt215_pm_pwr[] = {
+ { 0x20, (const struct nvkm_specsig[]) {
+ { 0x00, "pwr_gr_idle" },
+ { 0x04, "pwr_bsp_idle" },
+ { 0x05, "pwr_vp_idle" },
+ { 0x06, "pwr_ppp_idle" },
+ { 0x13, "pwr_ce0_idle" },
+ {}
+ }, &pwr_perfctr_func },
+ {}
+};
+
+const struct nvkm_specdom
+gf100_pm_pwr[] = {
+ { 0x20, (const struct nvkm_specsig[]) {
+ { 0x00, "pwr_gr_idle" },
+ { 0x04, "pwr_bsp_idle" },
+ { 0x05, "pwr_vp_idle" },
+ { 0x06, "pwr_ppp_idle" },
+ { 0x13, "pwr_ce0_idle" },
+ { 0x14, "pwr_ce1_idle" },
+ {}
+ }, &pwr_perfctr_func },
+ {}
+};
+
+const struct nvkm_specdom
+gk104_pm_pwr[] = {
+ { 0x20, (const struct nvkm_specsig[]) {
+ { 0x00, "pwr_gr_idle" },
+ { 0x04, "pwr_bsp_idle" },
+ { 0x05, "pwr_vp_idle" },
+ { 0x06, "pwr_ppp_idle" },
+ { 0x13, "pwr_ce0_idle" },
+ { 0x14, "pwr_ce1_idle" },
+ { 0x15, "pwr_ce2_idle" },
+ {}
+ }, &pwr_perfctr_func },
+ {}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c
new file mode 100644
index 000000000000..d54c6705ba17
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/g84.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static const struct nvkm_specdom
+g84_pm[] = {
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ {}
+};
+
+struct nvkm_oclass *
+g84_pm_oclass = &(struct nv40_pm_oclass) {
+ .base.handle = NV_ENGINE(PM, 0x84),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = _nvkm_pm_fini,
+ },
+ .doms = g84_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c
new file mode 100644
index 000000000000..008fed73dd82
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+static const struct nvkm_specdom
+gf100_pm_hub[] = {
+ {}
+};
+
+static const struct nvkm_specdom
+gf100_pm_gpc[] = {
+ {}
+};
+
+static const struct nvkm_specdom
+gf100_pm_part[] = {
+ {}
+};
+
+static void
+gf100_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+ struct nvkm_perfctr *ctr)
+{
+ struct gf100_pm_priv *priv = (void *)ppm;
+ struct gf100_pm_cntr *cntr = (void *)ctr;
+ u32 log = ctr->logic_op;
+ u32 src = 0x00000000;
+ int i;
+
+ for (i = 0; i < 4 && ctr->signal[i]; i++)
+ src |= (ctr->signal[i] - dom->signal) << (i * 8);
+
+ nv_wr32(priv, dom->addr + 0x09c, 0x00040002);
+ nv_wr32(priv, dom->addr + 0x100, 0x00000000);
+ nv_wr32(priv, dom->addr + 0x040 + (cntr->base.slot * 0x08), src);
+ nv_wr32(priv, dom->addr + 0x044 + (cntr->base.slot * 0x08), log);
+}
+
+static void
+gf100_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+ struct nvkm_perfctr *ctr)
+{
+ struct gf100_pm_priv *priv = (void *)ppm;
+ struct gf100_pm_cntr *cntr = (void *)ctr;
+
+ switch (cntr->base.slot) {
+ case 0: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x08c); break;
+ case 1: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x088); break;
+ case 2: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x080); break;
+ case 3: cntr->base.ctr = nv_rd32(priv, dom->addr + 0x090); break;
+ }
+ cntr->base.clk = nv_rd32(priv, dom->addr + 0x070);
+}
+
+static void
+gf100_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom)
+{
+ struct gf100_pm_priv *priv = (void *)ppm;
+ nv_wr32(priv, dom->addr + 0x06c, dom->signal_nr - 0x40 + 0x27);
+ nv_wr32(priv, dom->addr + 0x0ec, 0x00000011);
+}
+
+const struct nvkm_funcdom
+gf100_perfctr_func = {
+ .init = gf100_perfctr_init,
+ .read = gf100_perfctr_read,
+ .next = gf100_perfctr_next,
+};
+
+int
+gf100_pm_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gf100_pm_priv *priv = (void *)object;
+ nv_mask(priv, 0x000200, 0x10000000, 0x00000000);
+ nv_mask(priv, 0x000200, 0x10000000, 0x10000000);
+ return nvkm_pm_fini(&priv->base, suspend);
+}
+
+static int
+gf100_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_pm_priv *priv;
+ u32 mask;
+ int ret;
+
+ ret = nvkm_pm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gf100_pm_pwr);
+ if (ret)
+ return ret;
+
+ /* HUB */
+ ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
+ gf100_pm_hub);
+ if (ret)
+ return ret;
+
+ /* GPC */
+ mask = (1 << nv_rd32(priv, 0x022430)) - 1;
+ mask &= ~nv_rd32(priv, 0x022504);
+ mask &= ~nv_rd32(priv, 0x022584);
+
+ ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000,
+ 0x1000, 0x200, gf100_pm_gpc);
+ if (ret)
+ return ret;
+
+ /* PART */
+ mask = (1 << nv_rd32(priv, 0x022438)) - 1;
+ mask &= ~nv_rd32(priv, 0x022548);
+ mask &= ~nv_rd32(priv, 0x0225c8);
+
+ ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000,
+ 0x1000, 0x200, gf100_pm_part);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = &nvkm_pm_cclass;
+ nv_engine(priv)->sclass = nvkm_pm_sclass;
+ priv->base.last = 7;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_pm_oclass = {
+ .handle = NV_ENGINE(PM, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = gf100_pm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h
new file mode 100644
index 000000000000..6a01fc7fec6f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gf100.h
@@ -0,0 +1,15 @@
+#ifndef __NVKM_PM_NVC0_H__
+#define __NVKM_PM_NVC0_H__
+#include "priv.h"
+
+struct gf100_pm_priv {
+ struct nvkm_pm base;
+};
+
+struct gf100_pm_cntr {
+ struct nvkm_perfctr base;
+};
+
+extern const struct nvkm_funcdom gf100_perfctr_func;
+int gf100_pm_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c
new file mode 100644
index 000000000000..75b9ff3d1a2c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk104.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+static const struct nvkm_specdom
+gk104_pm_hub[] = {
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "hub00_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x40, (const struct nvkm_specsig[]) {
+ { 0x27, "hub01_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "hub02_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "hub03_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x40, (const struct nvkm_specsig[]) {
+ { 0x03, "host_mmio_rd" },
+ { 0x27, "hub04_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "hub05_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0xc0, (const struct nvkm_specsig[]) {
+ { 0x74, "host_fb_rd3x" },
+ { 0x75, "host_fb_rd3x_2" },
+ { 0xa7, "hub06_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "hub07_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ {}
+};
+
+static const struct nvkm_specdom
+gk104_pm_gpc[] = {
+ { 0xe0, (const struct nvkm_specsig[]) {
+ { 0xc7, "gpc00_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ {}
+};
+
+static const struct nvkm_specdom
+gk104_pm_part[] = {
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "part00_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ { 0x60, (const struct nvkm_specsig[]) {
+ { 0x47, "part01_user_0" },
+ {}
+ }, &gf100_perfctr_func },
+ {}
+};
+
+static int
+gk104_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_pm_priv *priv;
+ u32 mask;
+ int ret;
+
+ ret = nvkm_pm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ /* PDAEMON */
+ ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr);
+ if (ret)
+ return ret;
+
+ /* HUB */
+ ret = nvkm_perfdom_new(&priv->base, "hub", 0, 0x1b0000, 0, 0x200,
+ gk104_pm_hub);
+ if (ret)
+ return ret;
+
+ /* GPC */
+ mask = (1 << nv_rd32(priv, 0x022430)) - 1;
+ mask &= ~nv_rd32(priv, 0x022504);
+ mask &= ~nv_rd32(priv, 0x022584);
+
+ ret = nvkm_perfdom_new(&priv->base, "gpc", mask, 0x180000,
+ 0x1000, 0x200, gk104_pm_gpc);
+ if (ret)
+ return ret;
+
+ /* PART */
+ mask = (1 << nv_rd32(priv, 0x022438)) - 1;
+ mask &= ~nv_rd32(priv, 0x022548);
+ mask &= ~nv_rd32(priv, 0x0225c8);
+
+ ret = nvkm_perfdom_new(&priv->base, "part", mask, 0x1a0000,
+ 0x1000, 0x200, gk104_pm_part);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = &nvkm_pm_cclass;
+ nv_engine(priv)->sclass = nvkm_pm_sclass;
+ priv->base.last = 7;
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_pm_oclass = {
+ .handle = NV_ENGINE(PM, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = gf100_pm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c
new file mode 100644
index 000000000000..6820176e5f78
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gk110.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+static int
+gk110_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_pm_priv *priv;
+ int ret;
+
+ ret = nvkm_pm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0, gk104_pm_pwr);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = &nvkm_pm_cclass;
+ nv_engine(priv)->sclass = nvkm_pm_sclass;
+ return 0;
+}
+
+struct nvkm_oclass
+gk110_pm_oclass = {
+ .handle = NV_ENGINE(PM, 0xf0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk110_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = gf100_pm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c
new file mode 100644
index 000000000000..d065bfc59bbf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/gt215.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static const struct nvkm_specdom
+gt215_pm[] = {
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ {}
+};
+
+static int
+gt215_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **object)
+{
+ int ret = nv40_pm_ctor(parent, engine, oclass, data, size, object);
+ if (ret == 0) {
+ struct nv40_pm_priv *priv = (void *)*object;
+ ret = nvkm_perfdom_new(&priv->base, "pwr", 0, 0, 0, 0,
+ gt215_pm_pwr);
+ if (ret)
+ return ret;
+
+ priv->base.last = 3;
+ }
+ return ret;
+}
+
+struct nvkm_oclass *
+gt215_pm_oclass = &(struct nv40_pm_oclass) {
+ .base.handle = NV_ENGINE(PM, 0xa3),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt215_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = _nvkm_pm_fini,
+ },
+ .doms = gt215_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
new file mode 100644
index 000000000000..ff22f06b22b8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.c
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static void
+nv40_perfctr_init(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+ struct nvkm_perfctr *ctr)
+{
+ struct nv40_pm_priv *priv = (void *)ppm;
+ struct nv40_pm_cntr *cntr = (void *)ctr;
+ u32 log = ctr->logic_op;
+ u32 src = 0x00000000;
+ int i;
+
+ for (i = 0; i < 4 && ctr->signal[i]; i++)
+ src |= (ctr->signal[i] - dom->signal) << (i * 8);
+
+ nv_wr32(priv, 0x00a7c0 + dom->addr, 0x00000001);
+ nv_wr32(priv, 0x00a400 + dom->addr + (cntr->base.slot * 0x40), src);
+ nv_wr32(priv, 0x00a420 + dom->addr + (cntr->base.slot * 0x40), log);
+}
+
+static void
+nv40_perfctr_read(struct nvkm_pm *ppm, struct nvkm_perfdom *dom,
+ struct nvkm_perfctr *ctr)
+{
+ struct nv40_pm_priv *priv = (void *)ppm;
+ struct nv40_pm_cntr *cntr = (void *)ctr;
+
+ switch (cntr->base.slot) {
+ case 0: cntr->base.ctr = nv_rd32(priv, 0x00a700 + dom->addr); break;
+ case 1: cntr->base.ctr = nv_rd32(priv, 0x00a6c0 + dom->addr); break;
+ case 2: cntr->base.ctr = nv_rd32(priv, 0x00a680 + dom->addr); break;
+ case 3: cntr->base.ctr = nv_rd32(priv, 0x00a740 + dom->addr); break;
+ }
+ cntr->base.clk = nv_rd32(priv, 0x00a600 + dom->addr);
+}
+
+static void
+nv40_perfctr_next(struct nvkm_pm *ppm, struct nvkm_perfdom *dom)
+{
+ struct nv40_pm_priv *priv = (void *)ppm;
+ if (priv->sequence != ppm->sequence) {
+ nv_wr32(priv, 0x400084, 0x00000020);
+ priv->sequence = ppm->sequence;
+ }
+}
+
+const struct nvkm_funcdom
+nv40_perfctr_func = {
+ .init = nv40_perfctr_init,
+ .read = nv40_perfctr_read,
+ .next = nv40_perfctr_next,
+};
+
+static const struct nvkm_specdom
+nv40_pm[] = {
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x20, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ {}
+};
+
+int
+nv40_pm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv40_pm_oclass *mclass = (void *)oclass;
+ struct nv40_pm_priv *priv;
+ int ret;
+
+ ret = nvkm_pm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_perfdom_new(&priv->base, "pm", 0, 0, 0, 4, mclass->doms);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = &nvkm_pm_cclass;
+ nv_engine(priv)->sclass = nvkm_pm_sclass;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv40_pm_oclass = &(struct nv40_pm_oclass) {
+ .base.handle = NV_ENGINE(PM, 0x40),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = _nvkm_pm_fini,
+ },
+ .doms = nv40_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h
new file mode 100644
index 000000000000..2338e150420e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv40.h
@@ -0,0 +1,24 @@
+#ifndef __NVKM_PM_NV40_H__
+#define __NVKM_PM_NV40_H__
+#include "priv.h"
+
+struct nv40_pm_oclass {
+ struct nvkm_oclass base;
+ const struct nvkm_specdom *doms;
+};
+
+struct nv40_pm_priv {
+ struct nvkm_pm base;
+ u32 sequence;
+};
+
+int nv40_pm_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *data, u32 size,
+ struct nvkm_object **pobject);
+
+struct nv40_pm_cntr {
+ struct nvkm_perfctr base;
+};
+
+extern const struct nvkm_funcdom nv40_perfctr_func;
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c
new file mode 100644
index 000000000000..6af83b5d1b11
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/nv50.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static const struct nvkm_specdom
+nv50_pm[] = {
+ { 0x040, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x100, (const struct nvkm_specsig[]) {
+ { 0xc8, "gr_idle" },
+ {}
+ }, &nv40_perfctr_func },
+ { 0x100, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x020, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ { 0x040, (const struct nvkm_specsig[]) {
+ {}
+ }, &nv40_perfctr_func },
+ {}
+};
+
+struct nvkm_oclass *
+nv50_pm_oclass = &(struct nv40_pm_oclass) {
+ .base.handle = NV_ENGINE(PM, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_pm_ctor,
+ .dtor = _nvkm_pm_dtor,
+ .init = _nvkm_pm_init,
+ .fini = _nvkm_pm_fini,
+ },
+ .doms = nv50_pm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
new file mode 100644
index 000000000000..1e6eff2a6d79
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/pm/priv.h
@@ -0,0 +1,90 @@
+#ifndef __NVKM_PM_PRIV_H__
+#define __NVKM_PM_PRIV_H__
+#include <engine/pm.h>
+
+struct nvkm_perfctr {
+ struct nvkm_object base;
+ struct list_head head;
+ struct nvkm_perfsig *signal[4];
+ int slot;
+ u32 logic_op;
+ u32 clk;
+ u32 ctr;
+};
+
+extern struct nvkm_oclass nvkm_pm_sclass[];
+
+#include <core/engctx.h>
+
+struct nvkm_perfctx {
+ struct nvkm_engctx base;
+};
+
+extern struct nvkm_oclass nvkm_pm_cclass;
+
+struct nvkm_specsig {
+ u8 signal;
+ const char *name;
+};
+
+struct nvkm_perfsig {
+ const char *name;
+};
+
+struct nvkm_perfdom;
+struct nvkm_perfctr *
+nvkm_perfsig_wrap(struct nvkm_pm *, const char *, struct nvkm_perfdom **);
+
+struct nvkm_specdom {
+ u16 signal_nr;
+ const struct nvkm_specsig *signal;
+ const struct nvkm_funcdom *func;
+};
+
+extern const struct nvkm_specdom gt215_pm_pwr[];
+extern const struct nvkm_specdom gf100_pm_pwr[];
+extern const struct nvkm_specdom gk104_pm_pwr[];
+
+struct nvkm_perfdom {
+ struct list_head head;
+ struct list_head list;
+ const struct nvkm_funcdom *func;
+ char name[32];
+ u32 addr;
+ u8 quad;
+ u32 signal_nr;
+ struct nvkm_perfsig signal[];
+};
+
+struct nvkm_funcdom {
+ void (*init)(struct nvkm_pm *, struct nvkm_perfdom *,
+ struct nvkm_perfctr *);
+ void (*read)(struct nvkm_pm *, struct nvkm_perfdom *,
+ struct nvkm_perfctr *);
+ void (*next)(struct nvkm_pm *, struct nvkm_perfdom *);
+};
+
+int nvkm_perfdom_new(struct nvkm_pm *, const char *, u32, u32, u32, u32,
+ const struct nvkm_specdom *);
+
+#define nvkm_pm_create(p,e,o,d) \
+ nvkm_pm_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_pm_dtor(p) ({ \
+ struct nvkm_pm *c = (p); \
+ _nvkm_pm_dtor(nv_object(c)); \
+})
+#define nvkm_pm_init(p) ({ \
+ struct nvkm_pm *c = (p); \
+ _nvkm_pm_init(nv_object(c)); \
+})
+#define nvkm_pm_fini(p,s) ({ \
+ struct nvkm_pm *c = (p); \
+ _nvkm_pm_fini(nv_object(c), (s)); \
+})
+
+int nvkm_pm_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_pm_dtor(struct nvkm_object *);
+int _nvkm_pm_init(struct nvkm_object *);
+int _nvkm_pm_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild
new file mode 100644
index 000000000000..552d40a4641f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/sec/g98.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s
new file mode 100644
index 000000000000..06ee06071104
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s
@@ -0,0 +1,698 @@
+/*
+ * fuc microcode for g98 psec engine
+ * Copyright (C) 2010 Marcin Kościelnicki
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+.section #g98_psec_data
+
+ctx_dma:
+ctx_dma_query: .b32 0
+ctx_dma_src: .b32 0
+ctx_dma_dst: .b32 0
+.equ #dma_count 3
+ctx_query_address_high: .b32 0
+ctx_query_address_low: .b32 0
+ctx_query_counter: .b32 0
+ctx_cond_address_high: .b32 0
+ctx_cond_address_low: .b32 0
+ctx_cond_off: .b32 0
+ctx_src_address_high: .b32 0
+ctx_src_address_low: .b32 0
+ctx_dst_address_high: .b32 0
+ctx_dst_address_low: .b32 0
+ctx_mode: .b32 0
+.align 16
+ctx_key: .skip 16
+ctx_iv: .skip 16
+
+.align 0x80
+swap:
+.skip 32
+
+.align 8
+common_cmd_dtable:
+.b32 #ctx_query_address_high + 0x20000 ~0xff
+.b32 #ctx_query_address_low + 0x20000 ~0xfffffff0
+.b32 #ctx_query_counter + 0x20000 ~0xffffffff
+.b32 #cmd_query_get + 0x00000 ~1
+.b32 #ctx_cond_address_high + 0x20000 ~0xff
+.b32 #ctx_cond_address_low + 0x20000 ~0xfffffff0
+.b32 #cmd_cond_mode + 0x00000 ~7
+.b32 #cmd_wrcache_flush + 0x00000 ~0
+.equ #common_cmd_max 0x88
+
+
+.align 8
+engine_cmd_dtable:
+.b32 #ctx_key + 0x0 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0x4 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0x8 + 0x20000 ~0xffffffff
+.b32 #ctx_key + 0xc + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x0 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x4 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0x8 + 0x20000 ~0xffffffff
+.b32 #ctx_iv + 0xc + 0x20000 ~0xffffffff
+.b32 #ctx_src_address_high + 0x20000 ~0xff
+.b32 #ctx_src_address_low + 0x20000 ~0xfffffff0
+.b32 #ctx_dst_address_high + 0x20000 ~0xff
+.b32 #ctx_dst_address_low + 0x20000 ~0xfffffff0
+.b32 #sec_cmd_mode + 0x00000 ~0xf
+.b32 #sec_cmd_length + 0x10000 ~0x0ffffff0
+.equ #engine_cmd_max 0xce
+
+.align 4
+sec_dtable:
+.b16 #sec_copy_prep #sec_do_inout
+.b16 #sec_store_prep #sec_do_out
+.b16 #sec_ecb_e_prep #sec_do_inout
+.b16 #sec_ecb_d_prep #sec_do_inout
+.b16 #sec_cbc_e_prep #sec_do_inout
+.b16 #sec_cbc_d_prep #sec_do_inout
+.b16 #sec_pcbc_e_prep #sec_do_inout
+.b16 #sec_pcbc_d_prep #sec_do_inout
+.b16 #sec_cfb_e_prep #sec_do_inout
+.b16 #sec_cfb_d_prep #sec_do_inout
+.b16 #sec_ofb_prep #sec_do_inout
+.b16 #sec_ctr_prep #sec_do_inout
+.b16 #sec_cbc_mac_prep #sec_do_in
+.b16 #sec_cmac_finish_complete_prep #sec_do_in
+.b16 #sec_cmac_finish_partial_prep #sec_do_in
+
+.align 0x100
+
+.section #g98_psec_code
+
+ // $r0 is always set to 0 in our code - this allows some space savings.
+ clear b32 $r0
+
+ // set up the interrupt handler
+ mov $r1 #ih
+ mov $iv0 $r1
+
+ // init stack pointer
+ mov $sp $r0
+
+ // set interrupt dispatch - route timer, fifo, ctxswitch to i0, others to host
+ movw $r1 0xfff0
+ sethi $r1 0
+ mov $r2 0x400
+ iowr I[$r2 + 0x300] $r1
+
+ // enable the interrupts
+ or $r1 0xc
+ iowr I[$r2] $r1
+
+ // enable fifo access and context switching
+ mov $r1 3
+ mov $r2 0x1200
+ iowr I[$r2] $r1
+
+ // enable i0 delivery
+ bset $flags ie0
+
+ // sleep forver, waking only for interrupts.
+ bset $flags $p0
+ spin:
+ sleep $p0
+ bra #spin
+
+// i0 handler
+ih:
+ // see which interrupts we got
+ iord $r1 I[$r0 + 0x200]
+
+ and $r2 $r1 0x8
+ cmpu b32 $r2 0
+ bra e #noctx
+
+ // context switch... prepare the regs for xfer
+ mov $r2 0x7700
+ mov $xtargets $r2
+ mov $xdbase $r0
+ // 128-byte context.
+ mov $r2 0
+ sethi $r2 0x50000
+
+ // read current channel
+ mov $r3 0x1400
+ iord $r4 I[$r3]
+ // if bit 30 set, it's active, so we have to unload it first.
+ shl b32 $r5 $r4 1
+ cmps b32 $r5 0
+ bra nc #ctxload
+
+ // unload the current channel - save the context
+ xdst $r0 $r2
+ xdwait
+ // and clear bit 30, then write back
+ bclr $r4 0x1e
+ iowr I[$r3] $r4
+ // tell PFIFO we unloaded
+ mov $r4 1
+ iowr I[$r3 + 0x200] $r4
+
+ bra #noctx
+
+ ctxload:
+ // no channel loaded - perhaps we're requested to load one
+ iord $r4 I[$r3 + 0x100]
+ shl b32 $r15 $r4 1
+ cmps b32 $r15 0
+ // if bit 30 of next channel not set, probably PFIFO is just
+ // killing a context. do a faux load, without the active bit.
+ bra nc #dummyload
+
+ // ok, do a real context load.
+ xdld $r0 $r2
+ xdwait
+ mov $r5 #ctx_dma
+ mov $r6 #dma_count - 1
+ ctxload_dma_loop:
+ ld b32 $r7 D[$r5 + $r6 * 4]
+ add b32 $r8 $r6 0x180
+ shl b32 $r8 8
+ iowr I[$r8] $r7
+ sub b32 $r6 1
+ bra nc #ctxload_dma_loop
+
+ dummyload:
+ // tell PFIFO we're done
+ mov $r5 2
+ iowr I[$r3 + 0x200] $r5
+
+ noctx:
+ and $r2 $r1 0x4
+ cmpu b32 $r2 0
+ bra e #nocmd
+
+ // incoming fifo command.
+ mov $r3 0x1900
+ iord $r2 I[$r3 + 0x100]
+ iord $r3 I[$r3]
+ // extract the method
+ and $r4 $r2 0x7ff
+ // shift the addr to proper position if we need to interrupt later
+ shl b32 $r2 0x10
+
+ // mthd 0 and 0x100 [NAME, NOP]: ignore
+ and $r5 $r4 0x7bf
+ cmpu b32 $r5 0
+ bra e #cmddone
+
+ mov $r5 #engine_cmd_dtable - 0xc0 * 8
+ mov $r6 #engine_cmd_max
+ cmpu b32 $r4 0xc0
+ bra nc #dtable_cmd
+ mov $r5 #common_cmd_dtable - 0x80 * 8
+ mov $r6 #common_cmd_max
+ cmpu b32 $r4 0x80
+ bra nc #dtable_cmd
+ cmpu b32 $r4 0x60
+ bra nc #dma_cmd
+ cmpu b32 $r4 0x50
+ bra ne #illegal_mthd
+
+ // mthd 0x140: PM_TRIGGER
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x20000
+ iowr I[$r2] $r3
+ bra #cmddone
+
+ dma_cmd:
+ // mthd 0x180...: DMA_*
+ cmpu b32 $r4 0x60+#dma_count
+ bra nc #illegal_mthd
+ shl b32 $r5 $r4 2
+ add b32 $r5 ((#ctx_dma - 0x60 * 4) & 0xffff)
+ bset $r3 0x1e
+ st b32 D[$r5] $r3
+ add b32 $r4 0x180 - 0x60
+ shl b32 $r4 8
+ iowr I[$r4] $r3
+ bra #cmddone
+
+ dtable_cmd:
+ cmpu b32 $r4 $r6
+ bra nc #illegal_mthd
+ shl b32 $r4 3
+ add b32 $r4 $r5
+ ld b32 $r5 D[$r4 + 4]
+ and $r5 $r3
+ cmpu b32 $r5 0
+ bra ne #invalid_bitfield
+ ld b16 $r5 D[$r4]
+ ld b16 $r6 D[$r4 + 2]
+ cmpu b32 $r6 2
+ bra e #cmd_setctx
+ ld b32 $r7 D[$r0 + #ctx_cond_off]
+ and $r6 $r7
+ cmpu b32 $r6 1
+ bra e #cmddone
+ call $r5
+ bra $p1 #dispatch_error
+ bra #cmddone
+
+ cmd_setctx:
+ st b32 D[$r5] $r3
+ bra #cmddone
+
+
+ invalid_bitfield:
+ or $r2 1
+ dispatch_error:
+ illegal_mthd:
+ mov $r4 0x1000
+ iowr I[$r4] $r2
+ iowr I[$r4 + 0x100] $r3
+ mov $r4 0x40
+ iowr I[$r0] $r4
+
+ im_loop:
+ iord $r4 I[$r0 + 0x200]
+ and $r4 0x40
+ cmpu b32 $r4 0
+ bra ne #im_loop
+
+ cmddone:
+ // remove the command from FIFO
+ mov $r3 0x1d00
+ mov $r4 1
+ iowr I[$r3] $r4
+
+ nocmd:
+ // ack the processed interrupts
+ and $r1 $r1 0xc
+ iowr I[$r0 + 0x100] $r1
+iret
+
+cmd_query_get:
+ // if bit 0 of param set, trigger interrupt afterwards.
+ setp $p1 $r3
+ or $r2 3
+
+ // read PTIMER, beware of races...
+ mov $r4 0xb00
+ ptimer_retry:
+ iord $r6 I[$r4 + 0x100]
+ iord $r5 I[$r4]
+ iord $r7 I[$r4 + 0x100]
+ cmpu b32 $r6 $r7
+ bra ne #ptimer_retry
+
+ // prepare the query structure
+ ld b32 $r4 D[$r0 + #ctx_query_counter]
+ st b32 D[$r0 + #swap + 0x0] $r4
+ st b32 D[$r0 + #swap + 0x4] $r0
+ st b32 D[$r0 + #swap + 0x8] $r5
+ st b32 D[$r0 + #swap + 0xc] $r6
+
+ // will use target 0, DMA_QUERY.
+ mov $xtargets $r0
+
+ ld b32 $r4 D[$r0 + #ctx_query_address_high]
+ shl b32 $r4 0x18
+ mov $xdbase $r4
+
+ ld b32 $r4 D[$r0 + #ctx_query_address_low]
+ mov $r5 #swap
+ sethi $r5 0x20000
+ xdst $r4 $r5
+ xdwait
+
+ ret
+
+cmd_cond_mode:
+ // if >= 5, INVALID_ENUM
+ bset $flags $p1
+ or $r2 2
+ cmpu b32 $r3 5
+ bra nc #return
+
+ // otherwise, no error.
+ bclr $flags $p1
+
+ // if < 2, no QUERY object is involved
+ cmpu b32 $r3 2
+ bra nc #cmd_cond_mode_queryful
+
+ xor $r3 1
+ st b32 D[$r0 + #ctx_cond_off] $r3
+ return:
+ ret
+
+ cmd_cond_mode_queryful:
+ // ok, will need to pull a QUERY object, prepare offsets
+ ld b32 $r4 D[$r0 + #ctx_cond_address_high]
+ ld b32 $r5 D[$r0 + #ctx_cond_address_low]
+ and $r6 $r5 0xff
+ shr b32 $r5 8
+ shl b32 $r4 0x18
+ or $r4 $r5
+ mov $xdbase $r4
+ mov $xtargets $r0
+
+ // pull the first one
+ mov $r5 #swap
+ sethi $r5 0x20000
+ xdld $r6 $r5
+
+ // if == 2, only a single QUERY is involved...
+ cmpu b32 $r3 2
+ bra ne #cmd_cond_mode_double
+
+ xdwait
+ ld b32 $r4 D[$r0 + #swap + 4]
+ cmpu b32 $r4 0
+ xbit $r4 $flags z
+ st b32 D[$r0 + #ctx_cond_off] $r4
+ ret
+
+ // ok, we'll need to pull second one too
+ cmd_cond_mode_double:
+ add b32 $r6 0x10
+ add b32 $r5 0x10
+ xdld $r6 $r5
+ xdwait
+
+ // compare COUNTERs
+ ld b32 $r5 D[$r0 + #swap + 0x00]
+ ld b32 $r6 D[$r0 + #swap + 0x10]
+ cmpu b32 $r5 $r6
+ xbit $r4 $flags z
+
+ // compare RESen
+ ld b32 $r5 D[$r0 + #swap + 0x04]
+ ld b32 $r6 D[$r0 + #swap + 0x14]
+ cmpu b32 $r5 $r6
+ xbit $r5 $flags z
+ and $r4 $r5
+
+ // and negate or not, depending on mode
+ cmpu b32 $r3 3
+ xbit $r5 $flags z
+ xor $r4 $r5
+ st b32 D[$r0 + #ctx_cond_off] $r4
+ ret
+
+cmd_wrcache_flush:
+ bclr $flags $p1
+ mov $r2 0x2200
+ clear b32 $r3
+ sethi $r3 0x10000
+ iowr I[$r2] $r3
+ ret
+
+sec_cmd_mode:
+ // if >= 0xf, INVALID_ENUM
+ bset $flags $p1
+ or $r2 2
+ cmpu b32 $r3 0xf
+ bra nc #sec_cmd_mode_return
+
+ bclr $flags $p1
+ st b32 D[$r0 + #ctx_mode] $r3
+
+ sec_cmd_mode_return:
+ ret
+
+sec_cmd_length:
+ // nop if length == 0
+ cmpu b32 $r3 0
+ bra e #sec_cmd_mode_return
+
+ // init key, IV
+ cxset 3
+ mov $r4 #ctx_key
+ sethi $r4 0x70000
+ xdst $r0 $r4
+ mov $r4 #ctx_iv
+ sethi $r4 0x60000
+ xdst $r0 $r4
+ xdwait
+ ckeyreg $c7
+
+ // prepare the targets
+ mov $r4 0x2100
+ mov $xtargets $r4
+
+ // prepare src address
+ ld b32 $r4 D[$r0 + #ctx_src_address_high]
+ ld b32 $r5 D[$r0 + #ctx_src_address_low]
+ shr b32 $r8 $r5 8
+ shl b32 $r4 0x18
+ or $r4 $r8
+ and $r5 $r5 0xff
+
+ // prepare dst address
+ ld b32 $r6 D[$r0 + #ctx_dst_address_high]
+ ld b32 $r7 D[$r0 + #ctx_dst_address_low]
+ shr b32 $r8 $r7 8
+ shl b32 $r6 0x18
+ or $r6 $r8
+ and $r7 $r7 0xff
+
+ // find the proper prep & do functions
+ ld b32 $r8 D[$r0 + #ctx_mode]
+ shl b32 $r8 2
+
+ // run prep
+ ld b16 $r9 D[$r8 + #sec_dtable]
+ call $r9
+
+ // do it
+ ld b16 $r9 D[$r8 + #sec_dtable + 2]
+ call $r9
+ cxset 1
+ xdwait
+ cxset 0x61
+ xdwait
+ xdwait
+
+ // update src address
+ shr b32 $r8 $r4 0x18
+ shl b32 $r9 $r4 8
+ add b32 $r9 $r5
+ adc b32 $r8 0
+ st b32 D[$r0 + #ctx_src_address_high] $r8
+ st b32 D[$r0 + #ctx_src_address_low] $r9
+
+ // update dst address
+ shr b32 $r8 $r6 0x18
+ shl b32 $r9 $r6 8
+ add b32 $r9 $r7
+ adc b32 $r8 0
+ st b32 D[$r0 + #ctx_dst_address_high] $r8
+ st b32 D[$r0 + #ctx_dst_address_low] $r9
+
+ // pull updated IV
+ cxset 2
+ mov $r4 #ctx_iv
+ sethi $r4 0x60000
+ xdld $r0 $r4
+ xdwait
+
+ ret
+
+
+sec_copy_prep:
+ cs0begin 2
+ cxsin $c0
+ cxsout $c0
+ ret
+
+sec_store_prep:
+ cs0begin 1
+ cxsout $c6
+ ret
+
+sec_ecb_e_prep:
+ cs0begin 3
+ cxsin $c0
+ cenc $c0 $c0
+ cxsout $c0
+ ret
+
+sec_ecb_d_prep:
+ ckexp $c7 $c7
+ cs0begin 3
+ cxsin $c0
+ cdec $c0 $c0
+ cxsout $c0
+ ret
+
+sec_cbc_e_prep:
+ cs0begin 4
+ cxsin $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ cxsout $c6
+ ret
+
+sec_cbc_d_prep:
+ ckexp $c7 $c7
+ cs0begin 5
+ cmov $c2 $c6
+ cxsin $c6
+ cdec $c0 $c6
+ cxor $c0 $c2
+ cxsout $c0
+ ret
+
+sec_pcbc_e_prep:
+ cs0begin 5
+ cxsin $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ cxsout $c6
+ cxor $c6 $c0
+ ret
+
+sec_pcbc_d_prep:
+ ckexp $c7 $c7
+ cs0begin 5
+ cxsin $c0
+ cdec $c1 $c0
+ cxor $c6 $c1
+ cxsout $c6
+ cxor $c6 $c0
+ ret
+
+sec_cfb_e_prep:
+ cs0begin 4
+ cenc $c6 $c6
+ cxsin $c0
+ cxor $c6 $c0
+ cxsout $c6
+ ret
+
+sec_cfb_d_prep:
+ cs0begin 4
+ cenc $c0 $c6
+ cxsin $c6
+ cxor $c0 $c6
+ cxsout $c0
+ ret
+
+sec_ofb_prep:
+ cs0begin 4
+ cenc $c6 $c6
+ cxsin $c0
+ cxor $c0 $c6
+ cxsout $c0
+ ret
+
+sec_ctr_prep:
+ cs0begin 5
+ cenc $c1 $c6
+ cadd $c6 1
+ cxsin $c0
+ cxor $c0 $c1
+ cxsout $c0
+ ret
+
+sec_cbc_mac_prep:
+ cs0begin 3
+ cxsin $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ ret
+
+sec_cmac_finish_complete_prep:
+ cs0begin 7
+ cxsin $c0
+ cxor $c6 $c0
+ cxor $c0 $c0
+ cenc $c0 $c0
+ cprecmac $c0 $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ ret
+
+sec_cmac_finish_partial_prep:
+ cs0begin 8
+ cxsin $c0
+ cxor $c6 $c0
+ cxor $c0 $c0
+ cenc $c0 $c0
+ cprecmac $c0 $c0
+ cprecmac $c0 $c0
+ cxor $c6 $c0
+ cenc $c6 $c6
+ ret
+
+// TODO
+sec_do_in:
+ add b32 $r3 $r5
+ mov $xdbase $r4
+ mov $r9 #swap
+ sethi $r9 0x20000
+ sec_do_in_loop:
+ xdld $r5 $r9
+ xdwait
+ cxset 0x22
+ xdst $r0 $r9
+ cs0exec 1
+ xdwait
+ add b32 $r5 0x10
+ cmpu b32 $r5 $r3
+ bra ne #sec_do_in_loop
+ cxset 1
+ xdwait
+ ret
+
+sec_do_out:
+ add b32 $r3 $r7
+ mov $xdbase $r6
+ mov $r9 #swap
+ sethi $r9 0x20000
+ sec_do_out_loop:
+ cs0exec 1
+ cxset 0x61
+ xdld $r7 $r9
+ xdst $r7 $r9
+ cxset 1
+ xdwait
+ add b32 $r7 0x10
+ cmpu b32 $r7 $r3
+ bra ne #sec_do_out_loop
+ ret
+
+sec_do_inout:
+ add b32 $r3 $r5
+ mov $r9 #swap
+ sethi $r9 0x20000
+ sec_do_inout_loop:
+ mov $xdbase $r4
+ xdld $r5 $r9
+ xdwait
+ cxset 0x21
+ xdst $r0 $r9
+ cs0exec 1
+ cxset 0x61
+ mov $xdbase $r6
+ xdld $r7 $r9
+ xdst $r7 $r9
+ cxset 1
+ xdwait
+ add b32 $r5 0x10
+ add b32 $r7 0x10
+ cmpu b32 $r5 $r3
+ bra ne #sec_do_inout_loop
+ ret
+
+.align 0x100
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h
new file mode 100644
index 000000000000..5d65c4fbb087
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/fuc/g98.fuc0s.h
@@ -0,0 +1,584 @@
+uint32_t g98_psec_data[] = {
+/* 0x0000: ctx_dma */
+/* 0x0000: ctx_dma_query */
+ 0x00000000,
+/* 0x0004: ctx_dma_src */
+ 0x00000000,
+/* 0x0008: ctx_dma_dst */
+ 0x00000000,
+/* 0x000c: ctx_query_address_high */
+ 0x00000000,
+/* 0x0010: ctx_query_address_low */
+ 0x00000000,
+/* 0x0014: ctx_query_counter */
+ 0x00000000,
+/* 0x0018: ctx_cond_address_high */
+ 0x00000000,
+/* 0x001c: ctx_cond_address_low */
+ 0x00000000,
+/* 0x0020: ctx_cond_off */
+ 0x00000000,
+/* 0x0024: ctx_src_address_high */
+ 0x00000000,
+/* 0x0028: ctx_src_address_low */
+ 0x00000000,
+/* 0x002c: ctx_dst_address_high */
+ 0x00000000,
+/* 0x0030: ctx_dst_address_low */
+ 0x00000000,
+/* 0x0034: ctx_mode */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0040: ctx_key */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0050: ctx_iv */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0080: swap */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x00a0: common_cmd_dtable */
+ 0x0002000c,
+ 0xffffff00,
+ 0x00020010,
+ 0x0000000f,
+ 0x00020014,
+ 0x00000000,
+ 0x00000192,
+ 0xfffffffe,
+ 0x00020018,
+ 0xffffff00,
+ 0x0002001c,
+ 0x0000000f,
+ 0x000001d7,
+ 0xfffffff8,
+ 0x00000260,
+ 0xffffffff,
+/* 0x00e0: engine_cmd_dtable */
+ 0x00020040,
+ 0x00000000,
+ 0x00020044,
+ 0x00000000,
+ 0x00020048,
+ 0x00000000,
+ 0x0002004c,
+ 0x00000000,
+ 0x00020050,
+ 0x00000000,
+ 0x00020054,
+ 0x00000000,
+ 0x00020058,
+ 0x00000000,
+ 0x0002005c,
+ 0x00000000,
+ 0x00020024,
+ 0xffffff00,
+ 0x00020028,
+ 0x0000000f,
+ 0x0002002c,
+ 0xffffff00,
+ 0x00020030,
+ 0x0000000f,
+ 0x00000271,
+ 0xfffffff0,
+ 0x00010285,
+ 0xf000000f,
+/* 0x0150: sec_dtable */
+ 0x04db0321,
+ 0x04b1032f,
+ 0x04db0339,
+ 0x04db034b,
+ 0x04db0361,
+ 0x04db0377,
+ 0x04db0395,
+ 0x04db03af,
+ 0x04db03cd,
+ 0x04db03e3,
+ 0x04db03f9,
+ 0x04db040f,
+ 0x04830429,
+ 0x0483043b,
+ 0x0483045d,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t g98_psec_code[] = {
+ 0x17f004bd,
+ 0x0010fe35,
+ 0xf10004fe,
+ 0xf0fff017,
+ 0x27f10013,
+ 0x21d00400,
+ 0x0c15f0c0,
+ 0xf00021d0,
+ 0x27f10317,
+ 0x21d01200,
+ 0x1031f400,
+/* 0x002f: spin */
+ 0xf40031f4,
+ 0x0ef40028,
+/* 0x0035: ih */
+ 0x8001cffd,
+ 0xb00812c4,
+ 0x0bf40024,
+ 0x0027f167,
+ 0x002bfe77,
+ 0xf00007fe,
+ 0x23f00027,
+ 0x0037f105,
+ 0x0034cf14,
+ 0xb0014594,
+ 0x18f40055,
+ 0x0602fa17,
+ 0x4af003f8,
+ 0x0034d01e,
+ 0xd00147f0,
+ 0x0ef48034,
+/* 0x0075: ctxload */
+ 0x4034cf33,
+ 0xb0014f94,
+ 0x18f400f5,
+ 0x0502fa21,
+ 0x57f003f8,
+ 0x0267f000,
+/* 0x008c: ctxload_dma_loop */
+ 0xa07856bc,
+ 0xb6018068,
+ 0x87d00884,
+ 0x0162b600,
+/* 0x009f: dummyload */
+ 0xf0f018f4,
+ 0x35d00257,
+/* 0x00a5: noctx */
+ 0x0412c480,
+ 0xf50024b0,
+ 0xf100df0b,
+ 0xcf190037,
+ 0x33cf4032,
+ 0xff24e400,
+ 0x1024b607,
+ 0x07bf45e4,
+ 0xf50054b0,
+ 0xf100b90b,
+ 0xf1fae057,
+ 0xb000ce67,
+ 0x18f4c044,
+ 0xa057f14d,
+ 0x8867f1fc,
+ 0x8044b000,
+ 0xb03f18f4,
+ 0x18f46044,
+ 0x5044b019,
+ 0xf1741bf4,
+ 0xbd220027,
+ 0x0233f034,
+ 0xf50023d0,
+/* 0x0103: dma_cmd */
+ 0xb000810e,
+ 0x18f46344,
+ 0x0245945e,
+ 0xfe8050b7,
+ 0x801e39f0,
+ 0x40b70053,
+ 0x44b60120,
+ 0x0043d008,
+/* 0x0123: dtable_cmd */
+ 0xb8600ef4,
+ 0x18f40446,
+ 0x0344b63e,
+ 0x980045bb,
+ 0x53fd0145,
+ 0x0054b004,
+ 0x58291bf4,
+ 0x46580045,
+ 0x0264b001,
+ 0x98170bf4,
+ 0x67fd0807,
+ 0x0164b004,
+ 0xf9300bf4,
+ 0x0f01f455,
+/* 0x015b: cmd_setctx */
+ 0x80280ef4,
+ 0x0ef40053,
+/* 0x0161: invalid_bitfield */
+ 0x0125f022,
+/* 0x0164: dispatch_error */
+/* 0x0164: illegal_mthd */
+ 0x100047f1,
+ 0xd00042d0,
+ 0x47f04043,
+ 0x0004d040,
+/* 0x0174: im_loop */
+ 0xf08004cf,
+ 0x44b04044,
+ 0xf71bf400,
+/* 0x0180: cmddone */
+ 0x1d0037f1,
+ 0xd00147f0,
+/* 0x018a: nocmd */
+ 0x11c40034,
+ 0x4001d00c,
+/* 0x0192: cmd_query_get */
+ 0x38f201f8,
+ 0x0325f001,
+ 0x0b0047f1,
+/* 0x019c: ptimer_retry */
+ 0xcf4046cf,
+ 0x47cf0045,
+ 0x0467b840,
+ 0x98f41bf4,
+ 0x04800504,
+ 0x21008020,
+ 0x80220580,
+ 0x0bfe2306,
+ 0x03049800,
+ 0xfe1844b6,
+ 0x04980047,
+ 0x8057f104,
+ 0x0253f000,
+ 0xf80645fa,
+/* 0x01d7: cmd_cond_mode */
+ 0xf400f803,
+ 0x25f00131,
+ 0x0534b002,
+ 0xf41218f4,
+ 0x34b00132,
+ 0x0b18f402,
+ 0x800136f0,
+/* 0x01f2: return */
+ 0x00f80803,
+/* 0x01f4: cmd_cond_mode_queryful */
+ 0x98060498,
+ 0x56c40705,
+ 0x0855b6ff,
+ 0xfd1844b6,
+ 0x47fe0545,
+ 0x000bfe00,
+ 0x008057f1,
+ 0xfa0253f0,
+ 0x34b00565,
+ 0x131bf402,
+ 0x049803f8,
+ 0x0044b021,
+ 0x800b4cf0,
+ 0x00f80804,
+/* 0x022c: cmd_cond_mode_double */
+ 0xb61060b6,
+ 0x65fa1050,
+ 0x9803f805,
+ 0x06982005,
+ 0x0456b824,
+ 0x980b4cf0,
+ 0x06982105,
+ 0x0456b825,
+ 0xfd0b5cf0,
+ 0x34b00445,
+ 0x0b5cf003,
+ 0x800645fd,
+ 0x00f80804,
+/* 0x0260: cmd_wrcache_flush */
+ 0xf10132f4,
+ 0xbd220027,
+ 0x0133f034,
+ 0xf80023d0,
+/* 0x0271: sec_cmd_mode */
+ 0x0131f400,
+ 0xb00225f0,
+ 0x18f40f34,
+ 0x0132f409,
+/* 0x0283: sec_cmd_mode_return */
+ 0xf80d0380,
+/* 0x0285: sec_cmd_length */
+ 0x0034b000,
+ 0xf4fb0bf4,
+ 0x47f0033c,
+ 0x0743f040,
+ 0xf00604fa,
+ 0x43f05047,
+ 0x0604fa06,
+ 0x3cf503f8,
+ 0x47f1c407,
+ 0x4bfe2100,
+ 0x09049800,
+ 0x950a0598,
+ 0x44b60858,
+ 0x0548fd18,
+ 0x98ff55c4,
+ 0x07980b06,
+ 0x0878950c,
+ 0xfd1864b6,
+ 0x77c40568,
+ 0x0d0898ff,
+ 0x580284b6,
+ 0x95f9a889,
+ 0xf9a98958,
+ 0x013cf495,
+ 0x3cf403f8,
+ 0xf803f861,
+ 0x18489503,
+ 0xbb084994,
+ 0x81b60095,
+ 0x09088000,
+ 0x950a0980,
+ 0x69941868,
+ 0x0097bb08,
+ 0x800081b6,
+ 0x09800b08,
+ 0x023cf40c,
+ 0xf05047f0,
+ 0x04fa0643,
+ 0xf803f805,
+/* 0x0321: sec_copy_prep */
+ 0x203cf500,
+ 0x003cf594,
+ 0x003cf588,
+/* 0x032f: sec_store_prep */
+ 0xf500f88c,
+ 0xf594103c,
+ 0xf88c063c,
+/* 0x0339: sec_ecb_e_prep */
+ 0x303cf500,
+ 0x003cf594,
+ 0x003cf588,
+ 0x003cf5d0,
+/* 0x034b: sec_ecb_d_prep */
+ 0xf500f88c,
+ 0xf5c8773c,
+ 0xf594303c,
+ 0xf588003c,
+ 0xf5d4003c,
+ 0xf88c003c,
+/* 0x0361: sec_cbc_e_prep */
+ 0x403cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x663cf5ac,
+ 0x063cf5d0,
+/* 0x0377: sec_cbc_d_prep */
+ 0xf500f88c,
+ 0xf5c8773c,
+ 0xf594503c,
+ 0xf584623c,
+ 0xf588063c,
+ 0xf5d4603c,
+ 0xf5ac203c,
+ 0xf88c003c,
+/* 0x0395: sec_pcbc_e_prep */
+ 0x503cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x663cf5ac,
+ 0x063cf5d0,
+ 0x063cf58c,
+/* 0x03af: sec_pcbc_d_prep */
+ 0xf500f8ac,
+ 0xf5c8773c,
+ 0xf594503c,
+ 0xf588003c,
+ 0xf5d4013c,
+ 0xf5ac163c,
+ 0xf58c063c,
+ 0xf8ac063c,
+/* 0x03cd: sec_cfb_e_prep */
+ 0x403cf500,
+ 0x663cf594,
+ 0x003cf5d0,
+ 0x063cf588,
+ 0x063cf5ac,
+/* 0x03e3: sec_cfb_d_prep */
+ 0xf500f88c,
+ 0xf594403c,
+ 0xf5d0603c,
+ 0xf588063c,
+ 0xf5ac603c,
+ 0xf88c003c,
+/* 0x03f9: sec_ofb_prep */
+ 0x403cf500,
+ 0x663cf594,
+ 0x003cf5d0,
+ 0x603cf588,
+ 0x003cf5ac,
+/* 0x040f: sec_ctr_prep */
+ 0xf500f88c,
+ 0xf594503c,
+ 0xf5d0613c,
+ 0xf5b0163c,
+ 0xf588003c,
+ 0xf5ac103c,
+ 0xf88c003c,
+/* 0x0429: sec_cbc_mac_prep */
+ 0x303cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x663cf5ac,
+/* 0x043b: sec_cmac_finish_complete_prep */
+ 0xf500f8d0,
+ 0xf594703c,
+ 0xf588003c,
+ 0xf5ac063c,
+ 0xf5ac003c,
+ 0xf5d0003c,
+ 0xf5bc003c,
+ 0xf5ac063c,
+ 0xf8d0663c,
+/* 0x045d: sec_cmac_finish_partial_prep */
+ 0x803cf500,
+ 0x003cf594,
+ 0x063cf588,
+ 0x003cf5ac,
+ 0x003cf5ac,
+ 0x003cf5d0,
+ 0x003cf5bc,
+ 0x063cf5bc,
+ 0x663cf5ac,
+/* 0x0483: sec_do_in */
+ 0xbb00f8d0,
+ 0x47fe0035,
+ 0x8097f100,
+ 0x0293f000,
+/* 0x0490: sec_do_in_loop */
+ 0xf80559fa,
+ 0x223cf403,
+ 0xf50609fa,
+ 0xf898103c,
+ 0x1050b603,
+ 0xf40453b8,
+ 0x3cf4e91b,
+ 0xf803f801,
+/* 0x04b1: sec_do_out */
+ 0x0037bb00,
+ 0xf10067fe,
+ 0xf0008097,
+/* 0x04be: sec_do_out_loop */
+ 0x3cf50293,
+ 0x3cf49810,
+ 0x0579fa61,
+ 0xf40679fa,
+ 0x03f8013c,
+ 0xb81070b6,
+ 0x1bf40473,
+/* 0x04db: sec_do_inout */
+ 0xbb00f8e8,
+ 0x97f10035,
+ 0x93f00080,
+/* 0x04e5: sec_do_inout_loop */
+ 0x0047fe02,
+ 0xf80559fa,
+ 0x213cf403,
+ 0xf50609fa,
+ 0xf498103c,
+ 0x67fe613c,
+ 0x0579fa00,
+ 0xf40679fa,
+ 0x03f8013c,
+ 0xb61050b6,
+ 0x53b81070,
+ 0xd41bf404,
+ 0x000000f8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
new file mode 100644
index 000000000000..9d5c1b8b1f8c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sec/g98.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/sec.h>
+#include <engine/falcon.h>
+#include "fuc/g98.fuc0s.h"
+
+#include <core/client.h>
+#include <core/enum.h>
+#include <engine/fifo.h>
+
+struct g98_sec_priv {
+ struct nvkm_falcon base;
+};
+
+/*******************************************************************************
+ * Crypt object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_sec_sclass[] = {
+ { 0x88b4, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PSEC context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g98_sec_cclass = {
+ .handle = NV_ENGCTX(SEC, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_falcon_context_ctor,
+ .dtor = _nvkm_falcon_context_dtor,
+ .init = _nvkm_falcon_context_init,
+ .fini = _nvkm_falcon_context_fini,
+ .rd32 = _nvkm_falcon_context_rd32,
+ .wr32 = _nvkm_falcon_context_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PSEC engine/subdev functions
+ ******************************************************************************/
+
+static const struct nvkm_enum g98_sec_isr_error_name[] = {
+ { 0x0000, "ILLEGAL_MTHD" },
+ { 0x0001, "INVALID_BITFIELD" },
+ { 0x0002, "INVALID_ENUM" },
+ { 0x0003, "QUERY" },
+ {}
+};
+
+static void
+g98_sec_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(subdev);
+ struct nvkm_engine *engine = nv_engine(subdev);
+ struct nvkm_object *engctx;
+ struct g98_sec_priv *priv = (void *)subdev;
+ u32 disp = nv_rd32(priv, 0x08701c);
+ u32 stat = nv_rd32(priv, 0x087008) & disp & ~(disp >> 16);
+ u32 inst = nv_rd32(priv, 0x087050) & 0x3fffffff;
+ u32 ssta = nv_rd32(priv, 0x087040) & 0x0000ffff;
+ u32 addr = nv_rd32(priv, 0x087040) >> 16;
+ u32 mthd = (addr & 0x07ff) << 2;
+ u32 subc = (addr & 0x3800) >> 11;
+ u32 data = nv_rd32(priv, 0x087044);
+ int chid;
+
+ engctx = nvkm_engctx_get(engine, inst);
+ chid = pfifo->chid(pfifo, engctx);
+
+ if (stat & 0x00000040) {
+ nv_error(priv, "DISPATCH_ERROR [");
+ nvkm_enum_print(g98_sec_isr_error_name, ssta);
+ pr_cont("] ch %d [0x%010llx %s] subc %d mthd 0x%04x data 0x%08x\n",
+ chid, (u64)inst << 12, nvkm_client_name(engctx),
+ subc, mthd, data);
+ nv_wr32(priv, 0x087004, 0x00000040);
+ stat &= ~0x00000040;
+ }
+
+ if (stat) {
+ nv_error(priv, "unhandled intr 0x%08x\n", stat);
+ nv_wr32(priv, 0x087004, stat);
+ }
+
+ nvkm_engctx_put(engctx);
+}
+
+static int
+g98_sec_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g98_sec_priv *priv;
+ int ret;
+
+ ret = nvkm_falcon_create(parent, engine, oclass, 0x087000, true,
+ "PSEC", "sec", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x00004000;
+ nv_subdev(priv)->intr = g98_sec_intr;
+ nv_engine(priv)->cclass = &g98_sec_cclass;
+ nv_engine(priv)->sclass = g98_sec_sclass;
+ nv_falcon(priv)->code.data = g98_psec_code;
+ nv_falcon(priv)->code.size = sizeof(g98_psec_code);
+ nv_falcon(priv)->data.data = g98_psec_data;
+ nv_falcon(priv)->data.size = sizeof(g98_psec_data);
+ return 0;
+}
+
+struct nvkm_oclass
+g98_sec_oclass = {
+ .handle = NV_ENGINE(SEC, 0x98),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g98_sec_ctor,
+ .dtor = _nvkm_falcon_dtor,
+ .init = _nvkm_falcon_init,
+ .fini = _nvkm_falcon_fini,
+ .rd32 = _nvkm_falcon_rd32,
+ .wr32 = _nvkm_falcon_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild
new file mode 100644
index 000000000000..bdc3a05907d5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/engine/sw/nv04.o
+nvkm-y += nvkm/engine/sw/nv10.o
+nvkm-y += nvkm/engine/sw/nv50.o
+nvkm-y += nvkm/engine/sw/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
new file mode 100644
index 000000000000..533d5d8ed363
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/gf100.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bar.h>
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+gf100_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ u64 data = *(u32 *)args;
+ if (mthd == 0x0400) {
+ chan->vblank.offset &= 0x00ffffffffULL;
+ chan->vblank.offset |= data << 32;
+ } else {
+ chan->vblank.offset &= 0xff00000000ULL;
+ chan->vblank.offset |= data;
+ }
+ return 0;
+}
+
+static int
+gf100_sw_mthd_mp_control(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine;
+ u32 data = *(u32 *)args;
+
+ switch (mthd) {
+ case 0x600:
+ nv_wr32(priv, 0x419e00, data); /* MP.PM_UNK000 */
+ break;
+ case 0x644:
+ if (data & ~0x1ffffe)
+ return -EINVAL;
+ nv_wr32(priv, 0x419e44, data); /* MP.TRAP_WARP_ERROR_EN */
+ break;
+ case 0x6ac:
+ nv_wr32(priv, 0x419eac, data); /* MP.PM_UNK0AC */
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct nvkm_omthds
+gf100_sw_omthds[] = {
+ { 0x0400, 0x0400, gf100_sw_mthd_vblsem_offset },
+ { 0x0404, 0x0404, gf100_sw_mthd_vblsem_offset },
+ { 0x0408, 0x0408, nv50_sw_mthd_vblsem_value },
+ { 0x040c, 0x040c, nv50_sw_mthd_vblsem_release },
+ { 0x0500, 0x0500, nv50_sw_mthd_flip },
+ { 0x0600, 0x0600, gf100_sw_mthd_mp_control },
+ { 0x0644, 0x0644, gf100_sw_mthd_mp_control },
+ { 0x06ac, 0x06ac, gf100_sw_mthd_mp_control },
+ {}
+};
+
+static struct nvkm_oclass
+gf100_sw_sclass[] = {
+ { 0x906e, &nvkm_object_ofuncs, gf100_sw_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+gf100_sw_vblsem_release(struct nvkm_notify *notify)
+{
+ struct nv50_sw_chan *chan =
+ container_of(notify, typeof(*chan), vblank.notify[notify->index]);
+ struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine;
+ struct nvkm_bar *bar = nvkm_bar(priv);
+
+ nv_wr32(priv, 0x001718, 0x80000000 | chan->vblank.channel);
+ bar->flush(bar);
+ nv_wr32(priv, 0x06000c, upper_32_bits(chan->vblank.offset));
+ nv_wr32(priv, 0x060010, lower_32_bits(chan->vblank.offset));
+ nv_wr32(priv, 0x060014, chan->vblank.value);
+
+ return NVKM_NOTIFY_DROP;
+}
+
+static struct nv50_sw_cclass
+gf100_sw_cclass = {
+ .base.handle = NV_ENGCTX(SW, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_sw_context_ctor,
+ .dtor = nv50_sw_context_dtor,
+ .init = _nvkm_sw_context_init,
+ .fini = _nvkm_sw_context_fini,
+ },
+ .vblank = gf100_sw_vblsem_release,
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+struct nvkm_oclass *
+gf100_sw_oclass = &(struct nv50_sw_oclass) {
+ .base.handle = NV_ENGINE(SW, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_sw_ctor,
+ .dtor = _nvkm_sw_dtor,
+ .init = _nvkm_sw_init,
+ .fini = _nvkm_sw_fini,
+ },
+ .cclass = &gf100_sw_cclass.base,
+ .sclass = gf100_sw_sclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
new file mode 100644
index 000000000000..897024421d36
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv04.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/sw.h>
+#include <engine/fifo.h>
+
+struct nv04_sw_priv {
+ struct nvkm_sw base;
+};
+
+struct nv04_sw_chan {
+ struct nvkm_sw_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv04_sw_set_ref(struct nvkm_object *object, u32 mthd, void *data, u32 size)
+{
+ struct nvkm_object *channel = (void *)nv_engctx(object->parent);
+ struct nvkm_fifo_chan *fifo = (void *)channel->parent;
+ atomic_set(&fifo->refcnt, *(u32*)data);
+ return 0;
+}
+
+static int
+nv04_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size)
+{
+ struct nv04_sw_chan *chan = (void *)nv_engctx(object->parent);
+ if (chan->base.flip)
+ return chan->base.flip(chan->base.flip_data);
+ return -EINVAL;
+}
+
+static struct nvkm_omthds
+nv04_sw_omthds[] = {
+ { 0x0150, 0x0150, nv04_sw_set_ref },
+ { 0x0500, 0x0500, nv04_sw_flip },
+ {}
+};
+
+static struct nvkm_oclass
+nv04_sw_sclass[] = {
+ { 0x006e, &nvkm_object_ofuncs, nv04_sw_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv04_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_sw_chan *chan;
+ int ret;
+
+ ret = nvkm_sw_context_create(parent, engine, oclass, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct nvkm_oclass
+nv04_sw_cclass = {
+ .handle = NV_ENGCTX(SW, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_sw_context_ctor,
+ .dtor = _nvkm_sw_context_dtor,
+ .init = _nvkm_sw_context_init,
+ .fini = _nvkm_sw_context_fini,
+ },
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+void
+nv04_sw_intr(struct nvkm_subdev *subdev)
+{
+ nv_mask(subdev, 0x000100, 0x80000000, 0x00000000);
+}
+
+static int
+nv04_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_sw_priv *priv;
+ int ret;
+
+ ret = nvkm_sw_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = &nv04_sw_cclass;
+ nv_engine(priv)->sclass = nv04_sw_sclass;
+ nv_subdev(priv)->intr = nv04_sw_intr;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_sw_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(SW, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_sw_ctor,
+ .dtor = _nvkm_sw_dtor,
+ .init = _nvkm_sw_init,
+ .fini = _nvkm_sw_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
new file mode 100644
index 000000000000..c61153a3fb8b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv10.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <engine/sw.h>
+
+struct nv10_sw_priv {
+ struct nvkm_sw base;
+};
+
+struct nv10_sw_chan {
+ struct nvkm_sw_chan base;
+};
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv10_sw_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size)
+{
+ struct nv10_sw_chan *chan = (void *)nv_engctx(object->parent);
+ if (chan->base.flip)
+ return chan->base.flip(chan->base.flip_data);
+ return -EINVAL;
+}
+
+static struct nvkm_omthds
+nv10_sw_omthds[] = {
+ { 0x0500, 0x0500, nv10_sw_flip },
+ {}
+};
+
+static struct nvkm_oclass
+nv10_sw_sclass[] = {
+ { 0x016e, &nvkm_object_ofuncs, nv10_sw_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv10_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv10_sw_chan *chan;
+ int ret;
+
+ ret = nvkm_sw_context_create(parent, engine, oclass, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct nvkm_oclass
+nv10_sw_cclass = {
+ .handle = NV_ENGCTX(SW, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv10_sw_context_ctor,
+ .dtor = _nvkm_sw_context_dtor,
+ .init = _nvkm_sw_context_init,
+ .fini = _nvkm_sw_context_fini,
+ },
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+static int
+nv10_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv10_sw_priv *priv;
+ int ret;
+
+ ret = nvkm_sw_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = &nv10_sw_cclass;
+ nv_engine(priv)->sclass = nv10_sw_sclass;
+ nv_subdev(priv)->intr = nv04_sw_intr;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv10_sw_oclass = &(struct nvkm_oclass) {
+ .handle = NV_ENGINE(SW, 0x10),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv10_sw_ctor,
+ .dtor = _nvkm_sw_dtor,
+ .init = _nvkm_sw_init,
+ .fini = _nvkm_sw_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
new file mode 100644
index 000000000000..401fcd73086b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/device.h>
+#include <core/handle.h>
+#include <core/namedb.h>
+#include <engine/disp.h>
+#include <subdev/bar.h>
+
+#include <nvif/event.h>
+
+/*******************************************************************************
+ * software object classes
+ ******************************************************************************/
+
+static int
+nv50_sw_mthd_dma_vblsem(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ struct nvkm_fifo_chan *fifo = (void *)nv_object(chan)->parent;
+ struct nvkm_handle *handle;
+ int ret = -EINVAL;
+
+ handle = nvkm_namedb_get(nv_namedb(fifo), *(u32 *)args);
+ if (!handle)
+ return -ENOENT;
+
+ if (nv_iclass(handle->object, NV_GPUOBJ_CLASS)) {
+ struct nvkm_gpuobj *gpuobj = nv_gpuobj(handle->object);
+ chan->vblank.ctxdma = gpuobj->node->offset >> 4;
+ ret = 0;
+ }
+ nvkm_namedb_put(handle);
+ return ret;
+}
+
+static int
+nv50_sw_mthd_vblsem_offset(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ chan->vblank.offset = *(u32 *)args;
+ return 0;
+}
+
+int
+nv50_sw_mthd_vblsem_value(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ chan->vblank.value = *(u32 *)args;
+ return 0;
+}
+
+int
+nv50_sw_mthd_vblsem_release(struct nvkm_object *object, u32 mthd,
+ void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ u32 head = *(u32 *)args;
+ if (head >= nvkm_disp(chan)->vblank.index_nr)
+ return -EINVAL;
+
+ nvkm_notify_get(&chan->vblank.notify[head]);
+ return 0;
+}
+
+int
+nv50_sw_mthd_flip(struct nvkm_object *object, u32 mthd, void *args, u32 size)
+{
+ struct nv50_sw_chan *chan = (void *)nv_engctx(object->parent);
+ if (chan->base.flip)
+ return chan->base.flip(chan->base.flip_data);
+ return -EINVAL;
+}
+
+static struct nvkm_omthds
+nv50_sw_omthds[] = {
+ { 0x018c, 0x018c, nv50_sw_mthd_dma_vblsem },
+ { 0x0400, 0x0400, nv50_sw_mthd_vblsem_offset },
+ { 0x0404, 0x0404, nv50_sw_mthd_vblsem_value },
+ { 0x0408, 0x0408, nv50_sw_mthd_vblsem_release },
+ { 0x0500, 0x0500, nv50_sw_mthd_flip },
+ {}
+};
+
+static struct nvkm_oclass
+nv50_sw_sclass[] = {
+ { 0x506e, &nvkm_object_ofuncs, nv50_sw_omthds },
+ {}
+};
+
+/*******************************************************************************
+ * software context
+ ******************************************************************************/
+
+static int
+nv50_sw_vblsem_release(struct nvkm_notify *notify)
+{
+ struct nv50_sw_chan *chan =
+ container_of(notify, typeof(*chan), vblank.notify[notify->index]);
+ struct nv50_sw_priv *priv = (void *)nv_object(chan)->engine;
+ struct nvkm_bar *bar = nvkm_bar(priv);
+
+ nv_wr32(priv, 0x001704, chan->vblank.channel);
+ nv_wr32(priv, 0x001710, 0x80000000 | chan->vblank.ctxdma);
+ bar->flush(bar);
+
+ if (nv_device(priv)->chipset == 0x50) {
+ nv_wr32(priv, 0x001570, chan->vblank.offset);
+ nv_wr32(priv, 0x001574, chan->vblank.value);
+ } else {
+ nv_wr32(priv, 0x060010, chan->vblank.offset);
+ nv_wr32(priv, 0x060014, chan->vblank.value);
+ }
+
+ return NVKM_NOTIFY_DROP;
+}
+
+void
+nv50_sw_context_dtor(struct nvkm_object *object)
+{
+ struct nv50_sw_chan *chan = (void *)object;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(chan->vblank.notify); i++)
+ nvkm_notify_fini(&chan->vblank.notify[i]);
+
+ nvkm_sw_context_destroy(&chan->base);
+}
+
+int
+nv50_sw_context_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_disp *pdisp = nvkm_disp(parent);
+ struct nv50_sw_cclass *pclass = (void *)oclass;
+ struct nv50_sw_chan *chan;
+ int ret, i;
+
+ ret = nvkm_sw_context_create(parent, engine, oclass, &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ for (i = 0; pdisp && i < pdisp->vblank.index_nr; i++) {
+ ret = nvkm_notify_init(NULL, &pdisp->vblank, pclass->vblank,
+ false,
+ &(struct nvif_notify_head_req_v0) {
+ .head = i,
+ },
+ sizeof(struct nvif_notify_head_req_v0),
+ sizeof(struct nvif_notify_head_rep_v0),
+ &chan->vblank.notify[i]);
+ if (ret)
+ return ret;
+ }
+
+ chan->vblank.channel = nv_gpuobj(parent->parent)->addr >> 12;
+ return 0;
+}
+
+static struct nv50_sw_cclass
+nv50_sw_cclass = {
+ .base.handle = NV_ENGCTX(SW, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_sw_context_ctor,
+ .dtor = nv50_sw_context_dtor,
+ .init = _nvkm_sw_context_init,
+ .fini = _nvkm_sw_context_fini,
+ },
+ .vblank = nv50_sw_vblsem_release,
+};
+
+/*******************************************************************************
+ * software engine/subdev functions
+ ******************************************************************************/
+
+int
+nv50_sw_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_sw_oclass *pclass = (void *)oclass;
+ struct nv50_sw_priv *priv;
+ int ret;
+
+ ret = nvkm_sw_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_engine(priv)->cclass = pclass->cclass;
+ nv_engine(priv)->sclass = pclass->sclass;
+ nv_subdev(priv)->intr = nv04_sw_intr;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_sw_oclass = &(struct nv50_sw_oclass) {
+ .base.handle = NV_ENGINE(SW, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_sw_ctor,
+ .dtor = _nvkm_sw_dtor,
+ .init = _nvkm_sw_init,
+ .fini = _nvkm_sw_fini,
+ },
+ .cclass = &nv50_sw_cclass.base,
+ .sclass = nv50_sw_sclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
new file mode 100644
index 000000000000..d8adc1108467
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/sw/nv50.h
@@ -0,0 +1,45 @@
+#ifndef __NVKM_SW_NV50_H__
+#define __NVKM_SW_NV50_H__
+#include <engine/sw.h>
+#include <core/notify.h>
+
+struct nv50_sw_oclass {
+ struct nvkm_oclass base;
+ struct nvkm_oclass *cclass;
+ struct nvkm_oclass *sclass;
+};
+
+struct nv50_sw_priv {
+ struct nvkm_sw base;
+};
+
+int nv50_sw_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+struct nv50_sw_cclass {
+ struct nvkm_oclass base;
+ int (*vblank)(struct nvkm_notify *);
+};
+
+struct nv50_sw_chan {
+ struct nvkm_sw_chan base;
+ struct {
+ struct nvkm_notify notify[4];
+ u32 channel;
+ u32 ctxdma;
+ u64 offset;
+ u32 value;
+ } vblank;
+};
+
+int nv50_sw_context_ctor(struct nvkm_object *,
+ struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nv50_sw_context_dtor(struct nvkm_object *);
+
+int nv50_sw_mthd_vblsem_value(struct nvkm_object *, u32, void *, u32);
+int nv50_sw_mthd_vblsem_release(struct nvkm_object *, u32, void *, u32);
+int nv50_sw_mthd_flip(struct nvkm_object *, u32, void *, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild b/drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild
new file mode 100644
index 000000000000..6b390eb92b0e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/Kbuild
@@ -0,0 +1 @@
+nvkm-y += nvkm/engine/vp/g84.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c
new file mode 100644
index 000000000000..45f4e186befc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/vp/g84.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs, Ilia Mirkin
+ */
+#include <engine/vp.h>
+#include <engine/xtensa.h>
+
+#include <core/engctx.h>
+
+/*******************************************************************************
+ * VP object classes
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_vp_sclass[] = {
+ { 0x7476, &nvkm_object_ofuncs },
+ {},
+};
+
+/*******************************************************************************
+ * PVP context
+ ******************************************************************************/
+
+static struct nvkm_oclass
+g84_vp_cclass = {
+ .handle = NV_ENGCTX(VP, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_xtensa_engctx_ctor,
+ .dtor = _nvkm_engctx_dtor,
+ .init = _nvkm_engctx_init,
+ .fini = _nvkm_engctx_fini,
+ .rd32 = _nvkm_engctx_rd32,
+ .wr32 = _nvkm_engctx_wr32,
+ },
+};
+
+/*******************************************************************************
+ * PVP engine/subdev functions
+ ******************************************************************************/
+
+static int
+g84_vp_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_xtensa *priv;
+ int ret;
+
+ ret = nvkm_xtensa_create(parent, engine, oclass, 0xf000, true,
+ "PVP", "vp", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->unit = 0x01020000;
+ nv_engine(priv)->cclass = &g84_vp_cclass;
+ nv_engine(priv)->sclass = g84_vp_sclass;
+ priv->fifo_val = 0x111;
+ priv->unkd28 = 0x9c544;
+ return 0;
+}
+
+struct nvkm_oclass
+g84_vp_oclass = {
+ .handle = NV_ENGINE(VP, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_vp_ctor,
+ .dtor = _nvkm_xtensa_dtor,
+ .init = _nvkm_xtensa_init,
+ .fini = _nvkm_xtensa_fini,
+ .rd32 = _nvkm_xtensa_rd32,
+ .wr32 = _nvkm_xtensa_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c
new file mode 100644
index 000000000000..cea90df533d9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/engine/xtensa.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2013 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include <engine/xtensa.h>
+#include <core/device.h>
+
+#include <core/engctx.h>
+
+u32
+_nvkm_xtensa_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_xtensa *xtensa = (void *)object;
+ return nv_rd32(xtensa, xtensa->addr + addr);
+}
+
+void
+_nvkm_xtensa_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nvkm_xtensa *xtensa = (void *)object;
+ nv_wr32(xtensa, xtensa->addr + addr, data);
+}
+
+int
+_nvkm_xtensa_engctx_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_engctx *engctx;
+ int ret;
+
+ ret = nvkm_engctx_create(parent, engine, oclass, NULL, 0x10000, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &engctx);
+ *pobject = nv_object(engctx);
+ return ret;
+}
+
+void
+_nvkm_xtensa_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_xtensa *xtensa = (void *)subdev;
+ u32 unk104 = nv_ro32(xtensa, 0xd04);
+ u32 intr = nv_ro32(xtensa, 0xc20);
+ u32 chan = nv_ro32(xtensa, 0xc28);
+ u32 unk10c = nv_ro32(xtensa, 0xd0c);
+
+ if (intr & 0x10)
+ nv_warn(xtensa, "Watchdog interrupt, engine hung.\n");
+ nv_wo32(xtensa, 0xc20, intr);
+ intr = nv_ro32(xtensa, 0xc20);
+ if (unk104 == 0x10001 && unk10c == 0x200 && chan && !intr) {
+ nv_debug(xtensa, "Enabling FIFO_CTRL\n");
+ nv_mask(xtensa, xtensa->addr + 0xd94, 0, xtensa->fifo_val);
+ }
+}
+
+int
+nvkm_xtensa_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 addr, bool enable,
+ const char *iname, const char *fname,
+ int length, void **pobject)
+{
+ struct nvkm_xtensa *xtensa;
+ int ret;
+
+ ret = nvkm_engine_create_(parent, engine, oclass, enable, iname,
+ fname, length, pobject);
+ xtensa = *pobject;
+ if (ret)
+ return ret;
+
+ nv_subdev(xtensa)->intr = _nvkm_xtensa_intr;
+ xtensa->addr = addr;
+ return 0;
+}
+
+int
+_nvkm_xtensa_init(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nvkm_xtensa *xtensa = (void *)object;
+ const struct firmware *fw;
+ char name[32];
+ int i, ret;
+ u32 tmp;
+
+ ret = nvkm_engine_init(&xtensa->base);
+ if (ret)
+ return ret;
+
+ if (!xtensa->gpu_fw) {
+ snprintf(name, sizeof(name), "nouveau/nv84_xuc%03x",
+ xtensa->addr >> 12);
+
+ ret = request_firmware(&fw, name, nv_device_base(device));
+ if (ret) {
+ nv_warn(xtensa, "unable to load firmware %s\n", name);
+ return ret;
+ }
+
+ if (fw->size > 0x40000) {
+ nv_warn(xtensa, "firmware %s too large\n", name);
+ release_firmware(fw);
+ return -EINVAL;
+ }
+
+ ret = nvkm_gpuobj_new(object, NULL, 0x40000, 0x1000, 0,
+ &xtensa->gpu_fw);
+ if (ret) {
+ release_firmware(fw);
+ return ret;
+ }
+
+ nv_debug(xtensa, "Loading firmware to address: 0x%llx\n",
+ xtensa->gpu_fw->addr);
+
+ for (i = 0; i < fw->size / 4; i++)
+ nv_wo32(xtensa->gpu_fw, i * 4, *((u32 *)fw->data + i));
+ release_firmware(fw);
+ }
+
+ nv_wo32(xtensa, 0xd10, 0x1fffffff); /* ?? */
+ nv_wo32(xtensa, 0xd08, 0x0fffffff); /* ?? */
+
+ nv_wo32(xtensa, 0xd28, xtensa->unkd28); /* ?? */
+ nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+ nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+
+ nv_wo32(xtensa, 0xcc0, xtensa->gpu_fw->addr >> 8); /* XT_REGION_BASE */
+ nv_wo32(xtensa, 0xcc4, 0x1c); /* XT_REGION_SETUP */
+ nv_wo32(xtensa, 0xcc8, xtensa->gpu_fw->size >> 8); /* XT_REGION_LIMIT */
+
+ tmp = nv_rd32(xtensa, 0x0);
+ nv_wo32(xtensa, 0xde0, tmp); /* SCRATCH_H2X */
+
+ nv_wo32(xtensa, 0xce8, 0xf); /* XT_REGION_SETUP */
+
+ nv_wo32(xtensa, 0xc20, 0x3f); /* INTR */
+ nv_wo32(xtensa, 0xd84, 0x3f); /* INTR_EN */
+ return 0;
+}
+
+int
+_nvkm_xtensa_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_xtensa *xtensa = (void *)object;
+
+ nv_wo32(xtensa, 0xd84, 0); /* INTR_EN */
+ nv_wo32(xtensa, 0xd94, 0); /* FIFO_CTRL */
+
+ if (!suspend)
+ nvkm_gpuobj_ref(NULL, &xtensa->gpu_fw);
+
+ return nvkm_engine_fini(&xtensa->base, suspend);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
new file mode 100644
index 000000000000..a1bb3e48739c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/Kbuild
@@ -0,0 +1,19 @@
+include $(src)/nvkm/subdev/bar/Kbuild
+include $(src)/nvkm/subdev/bios/Kbuild
+include $(src)/nvkm/subdev/bus/Kbuild
+include $(src)/nvkm/subdev/clk/Kbuild
+include $(src)/nvkm/subdev/devinit/Kbuild
+include $(src)/nvkm/subdev/fb/Kbuild
+include $(src)/nvkm/subdev/fuse/Kbuild
+include $(src)/nvkm/subdev/gpio/Kbuild
+include $(src)/nvkm/subdev/i2c/Kbuild
+include $(src)/nvkm/subdev/ibus/Kbuild
+include $(src)/nvkm/subdev/instmem/Kbuild
+include $(src)/nvkm/subdev/ltc/Kbuild
+include $(src)/nvkm/subdev/mc/Kbuild
+include $(src)/nvkm/subdev/mmu/Kbuild
+include $(src)/nvkm/subdev/mxm/Kbuild
+include $(src)/nvkm/subdev/pmu/Kbuild
+include $(src)/nvkm/subdev/therm/Kbuild
+include $(src)/nvkm/subdev/timer/Kbuild
+include $(src)/nvkm/subdev/volt/Kbuild
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
new file mode 100644
index 000000000000..1ab554a0b5e0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/bar/base.o
+nvkm-y += nvkm/subdev/bar/nv50.o
+nvkm-y += nvkm/subdev/bar/gf100.o
+nvkm-y += nvkm/subdev/bar/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c
new file mode 100644
index 000000000000..3502d00122ef
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/base.c
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+
+struct nvkm_barobj {
+ struct nvkm_object base;
+ struct nvkm_vma vma;
+ void __iomem *iomem;
+};
+
+static int
+nvkm_barobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_bar *bar = nvkm_bar(device);
+ struct nvkm_mem *mem = data;
+ struct nvkm_barobj *barobj;
+ int ret;
+
+ ret = nvkm_object_create(parent, engine, oclass, 0, &barobj);
+ *pobject = nv_object(barobj);
+ if (ret)
+ return ret;
+
+ ret = bar->kmap(bar, mem, NV_MEM_ACCESS_RW, &barobj->vma);
+ if (ret)
+ return ret;
+
+ barobj->iomem = ioremap(nv_device_resource_start(device, 3) +
+ (u32)barobj->vma.offset, mem->size << 12);
+ if (!barobj->iomem) {
+ nv_warn(bar, "PRAMIN ioremap failed\n");
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void
+nvkm_barobj_dtor(struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = nvkm_bar(object);
+ struct nvkm_barobj *barobj = (void *)object;
+ if (barobj->vma.node) {
+ if (barobj->iomem)
+ iounmap(barobj->iomem);
+ bar->unmap(bar, &barobj->vma);
+ }
+ nvkm_object_destroy(&barobj->base);
+}
+
+static u32
+nvkm_barobj_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_barobj *barobj = (void *)object;
+ return ioread32_native(barobj->iomem + addr);
+}
+
+static void
+nvkm_barobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nvkm_barobj *barobj = (void *)object;
+ iowrite32_native(data, barobj->iomem + addr);
+}
+
+static struct nvkm_oclass
+nvkm_barobj_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nvkm_barobj_ctor,
+ .dtor = nvkm_barobj_dtor,
+ .init = nvkm_object_init,
+ .fini = nvkm_object_fini,
+ .rd32 = nvkm_barobj_rd32,
+ .wr32 = nvkm_barobj_wr32,
+ },
+};
+
+int
+nvkm_bar_alloc(struct nvkm_bar *bar, struct nvkm_object *parent,
+ struct nvkm_mem *mem, struct nvkm_object **pobject)
+{
+ struct nvkm_object *gpuobj;
+ int ret = nvkm_object_ctor(parent, &parent->engine->subdev.object,
+ &nvkm_barobj_oclass, mem, 0, &gpuobj);
+ if (ret == 0)
+ *pobject = gpuobj;
+ return ret;
+}
+
+int
+nvkm_bar_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_bar *bar;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "BARCTL",
+ "bar", length, pobject);
+ bar = *pobject;
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+void
+nvkm_bar_destroy(struct nvkm_bar *bar)
+{
+ nvkm_subdev_destroy(&bar->base);
+}
+
+void
+_nvkm_bar_dtor(struct nvkm_object *object)
+{
+ struct nvkm_bar *bar = (void *)object;
+ nvkm_bar_destroy(bar);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
new file mode 100644
index 000000000000..12a1aebd9a96
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gf100.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+
+struct gf100_bar_priv_vm {
+ struct nvkm_gpuobj *mem;
+ struct nvkm_gpuobj *pgd;
+ struct nvkm_vm *vm;
+};
+
+struct gf100_bar_priv {
+ struct nvkm_bar base;
+ spinlock_t lock;
+ struct gf100_bar_priv_vm bar[2];
+};
+
+static int
+gf100_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+ struct nvkm_vma *vma)
+{
+ struct gf100_bar_priv *priv = (void *)bar;
+ int ret;
+
+ ret = nvkm_vm_get(priv->bar[0].vm, mem->size << 12, 12, flags, vma);
+ if (ret)
+ return ret;
+
+ nvkm_vm_map(vma, mem);
+ return 0;
+}
+
+static int
+gf100_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+ struct nvkm_vma *vma)
+{
+ struct gf100_bar_priv *priv = (void *)bar;
+ int ret;
+
+ ret = nvkm_vm_get(priv->bar[1].vm, mem->size << 12,
+ mem->page_shift, flags, vma);
+ if (ret)
+ return ret;
+
+ nvkm_vm_map(vma, mem);
+ return 0;
+}
+
+static void
+gf100_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma)
+{
+ nvkm_vm_unmap(vma);
+ nvkm_vm_put(vma);
+}
+
+static int
+gf100_bar_ctor_vm(struct gf100_bar_priv *priv, struct gf100_bar_priv_vm *bar_vm,
+ int bar_nr)
+{
+ struct nvkm_device *device = nv_device(&priv->base);
+ struct nvkm_vm *vm;
+ resource_size_t bar_len;
+ int ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x1000, 0, 0,
+ &bar_vm->mem);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x8000, 0, 0,
+ &bar_vm->pgd);
+ if (ret)
+ return ret;
+
+ bar_len = nv_device_resource_len(device, bar_nr);
+
+ ret = nvkm_vm_new(device, 0, bar_len, 0, &vm);
+ if (ret)
+ return ret;
+
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
+ /*
+ * Bootstrap page table lookup.
+ */
+ if (bar_nr == 3) {
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+ (bar_len >> 12) * 8, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &vm->pgt[0].obj[0]);
+ vm->pgt[0].refcount[0] = 1;
+ if (ret)
+ return ret;
+ }
+
+ ret = nvkm_vm_ref(vm, &bar_vm->vm, bar_vm->pgd);
+ nvkm_vm_ref(NULL, &vm, NULL);
+ if (ret)
+ return ret;
+
+ nv_wo32(bar_vm->mem, 0x0200, lower_32_bits(bar_vm->pgd->addr));
+ nv_wo32(bar_vm->mem, 0x0204, upper_32_bits(bar_vm->pgd->addr));
+ nv_wo32(bar_vm->mem, 0x0208, lower_32_bits(bar_len - 1));
+ nv_wo32(bar_vm->mem, 0x020c, upper_32_bits(bar_len - 1));
+ return 0;
+}
+
+int
+gf100_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct gf100_bar_priv *priv;
+ bool has_bar3 = nv_device_resource_len(device, 3) != 0;
+ int ret;
+
+ ret = nvkm_bar_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ /* BAR3 */
+ if (has_bar3) {
+ ret = gf100_bar_ctor_vm(priv, &priv->bar[0], 3);
+ if (ret)
+ return ret;
+ }
+
+ /* BAR1 */
+ ret = gf100_bar_ctor_vm(priv, &priv->bar[1], 1);
+ if (ret)
+ return ret;
+
+ if (has_bar3) {
+ priv->base.alloc = nvkm_bar_alloc;
+ priv->base.kmap = gf100_bar_kmap;
+ }
+ priv->base.umap = gf100_bar_umap;
+ priv->base.unmap = gf100_bar_unmap;
+ priv->base.flush = g84_bar_flush;
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+void
+gf100_bar_dtor(struct nvkm_object *object)
+{
+ struct gf100_bar_priv *priv = (void *)object;
+
+ nvkm_vm_ref(NULL, &priv->bar[1].vm, priv->bar[1].pgd);
+ nvkm_gpuobj_ref(NULL, &priv->bar[1].pgd);
+ nvkm_gpuobj_ref(NULL, &priv->bar[1].mem);
+
+ if (priv->bar[0].vm) {
+ nvkm_gpuobj_ref(NULL, &priv->bar[0].vm->pgt[0].obj[0]);
+ nvkm_vm_ref(NULL, &priv->bar[0].vm, priv->bar[0].pgd);
+ }
+ nvkm_gpuobj_ref(NULL, &priv->bar[0].pgd);
+ nvkm_gpuobj_ref(NULL, &priv->bar[0].mem);
+
+ nvkm_bar_destroy(&priv->base);
+}
+
+int
+gf100_bar_init(struct nvkm_object *object)
+{
+ struct gf100_bar_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_bar_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+
+ nv_wr32(priv, 0x001704, 0x80000000 | priv->bar[1].mem->addr >> 12);
+ if (priv->bar[0].mem)
+ nv_wr32(priv, 0x001714,
+ 0xc0000000 | priv->bar[0].mem->addr >> 12);
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_bar_oclass = {
+ .handle = NV_SUBDEV(BAR, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_bar_ctor,
+ .dtor = gf100_bar_dtor,
+ .init = gf100_bar_init,
+ .fini = _nvkm_bar_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c
new file mode 100644
index 000000000000..148f739a276e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/gk20a.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "priv.h"
+
+int
+gk20a_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_bar *bar;
+ int ret;
+
+ ret = gf100_bar_ctor(parent, engine, oclass, data, size, pobject);
+ if (ret)
+ return ret;
+
+ bar = (struct nvkm_bar *)*pobject;
+ bar->iomap_uncached = true;
+ return 0;
+}
+
+struct nvkm_oclass
+gk20a_bar_oclass = {
+ .handle = NV_SUBDEV(BAR, 0xea),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_bar_ctor,
+ .dtor = gf100_bar_dtor,
+ .init = gf100_bar_init,
+ .fini = _nvkm_bar_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
new file mode 100644
index 000000000000..8548adb91dcc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/nv50.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <subdev/fb.h>
+#include <subdev/mmu.h>
+#include <subdev/timer.h>
+
+struct nv50_bar_priv {
+ struct nvkm_bar base;
+ spinlock_t lock;
+ struct nvkm_gpuobj *mem;
+ struct nvkm_gpuobj *pad;
+ struct nvkm_gpuobj *pgd;
+ struct nvkm_vm *bar1_vm;
+ struct nvkm_gpuobj *bar1;
+ struct nvkm_vm *bar3_vm;
+ struct nvkm_gpuobj *bar3;
+};
+
+static int
+nv50_bar_kmap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+ struct nvkm_vma *vma)
+{
+ struct nv50_bar_priv *priv = (void *)bar;
+ int ret;
+
+ ret = nvkm_vm_get(priv->bar3_vm, mem->size << 12, 12, flags, vma);
+ if (ret)
+ return ret;
+
+ nvkm_vm_map(vma, mem);
+ return 0;
+}
+
+static int
+nv50_bar_umap(struct nvkm_bar *bar, struct nvkm_mem *mem, u32 flags,
+ struct nvkm_vma *vma)
+{
+ struct nv50_bar_priv *priv = (void *)bar;
+ int ret;
+
+ ret = nvkm_vm_get(priv->bar1_vm, mem->size << 12, 12, flags, vma);
+ if (ret)
+ return ret;
+
+ nvkm_vm_map(vma, mem);
+ return 0;
+}
+
+static void
+nv50_bar_unmap(struct nvkm_bar *bar, struct nvkm_vma *vma)
+{
+ nvkm_vm_unmap(vma);
+ nvkm_vm_put(vma);
+}
+
+static void
+nv50_bar_flush(struct nvkm_bar *bar)
+{
+ struct nv50_bar_priv *priv = (void *)bar;
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
+ nv_wr32(priv, 0x00330c, 0x00000001);
+ if (!nv_wait(priv, 0x00330c, 0x00000002, 0x00000000))
+ nv_warn(priv, "flush timeout\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+void
+g84_bar_flush(struct nvkm_bar *bar)
+{
+ struct nv50_bar_priv *priv = (void *)bar;
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
+ nv_wr32(bar, 0x070000, 0x00000001);
+ if (!nv_wait(priv, 0x070000, 0x00000002, 0x00000000))
+ nv_warn(priv, "flush timeout\n");
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static int
+nv50_bar_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_object *heap;
+ struct nvkm_vm *vm;
+ struct nv50_bar_priv *priv;
+ u64 start, limit;
+ int ret;
+
+ ret = nvkm_bar_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
+ NVOBJ_FLAG_HEAP, &priv->mem);
+ heap = nv_object(priv->mem);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), heap,
+ (device->chipset == 0x50) ? 0x1400 : 0x0200,
+ 0, 0, &priv->pad);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), heap, 0x4000, 0, 0, &priv->pgd);
+ if (ret)
+ return ret;
+
+ /* BAR3 */
+ start = 0x0100000000ULL;
+ limit = start + nv_device_resource_len(device, 3);
+
+ ret = nvkm_vm_new(device, start, limit, start, &vm);
+ if (ret)
+ return ret;
+
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
+ ret = nvkm_gpuobj_new(nv_object(priv), heap,
+ ((limit-- - start) >> 12) * 8, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &vm->pgt[0].obj[0]);
+ vm->pgt[0].refcount[0] = 1;
+ if (ret)
+ return ret;
+
+ ret = nvkm_vm_ref(vm, &priv->bar3_vm, priv->pgd);
+ nvkm_vm_ref(NULL, &vm, NULL);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar3);
+ if (ret)
+ return ret;
+
+ nv_wo32(priv->bar3, 0x00, 0x7fc00000);
+ nv_wo32(priv->bar3, 0x04, lower_32_bits(limit));
+ nv_wo32(priv->bar3, 0x08, lower_32_bits(start));
+ nv_wo32(priv->bar3, 0x0c, upper_32_bits(limit) << 24 |
+ upper_32_bits(start));
+ nv_wo32(priv->bar3, 0x10, 0x00000000);
+ nv_wo32(priv->bar3, 0x14, 0x00000000);
+
+ /* BAR1 */
+ start = 0x0000000000ULL;
+ limit = start + nv_device_resource_len(device, 1);
+
+ ret = nvkm_vm_new(device, start, limit--, start, &vm);
+ if (ret)
+ return ret;
+
+ atomic_inc(&vm->engref[NVDEV_SUBDEV_BAR]);
+
+ ret = nvkm_vm_ref(vm, &priv->bar1_vm, priv->pgd);
+ nvkm_vm_ref(NULL, &vm, NULL);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), heap, 24, 16, 0, &priv->bar1);
+ if (ret)
+ return ret;
+
+ nv_wo32(priv->bar1, 0x00, 0x7fc00000);
+ nv_wo32(priv->bar1, 0x04, lower_32_bits(limit));
+ nv_wo32(priv->bar1, 0x08, lower_32_bits(start));
+ nv_wo32(priv->bar1, 0x0c, upper_32_bits(limit) << 24 |
+ upper_32_bits(start));
+ nv_wo32(priv->bar1, 0x10, 0x00000000);
+ nv_wo32(priv->bar1, 0x14, 0x00000000);
+
+ priv->base.alloc = nvkm_bar_alloc;
+ priv->base.kmap = nv50_bar_kmap;
+ priv->base.umap = nv50_bar_umap;
+ priv->base.unmap = nv50_bar_unmap;
+ if (device->chipset == 0x50)
+ priv->base.flush = nv50_bar_flush;
+ else
+ priv->base.flush = g84_bar_flush;
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+static void
+nv50_bar_dtor(struct nvkm_object *object)
+{
+ struct nv50_bar_priv *priv = (void *)object;
+ nvkm_gpuobj_ref(NULL, &priv->bar1);
+ nvkm_vm_ref(NULL, &priv->bar1_vm, priv->pgd);
+ nvkm_gpuobj_ref(NULL, &priv->bar3);
+ if (priv->bar3_vm) {
+ nvkm_gpuobj_ref(NULL, &priv->bar3_vm->pgt[0].obj[0]);
+ nvkm_vm_ref(NULL, &priv->bar3_vm, priv->pgd);
+ }
+ nvkm_gpuobj_ref(NULL, &priv->pgd);
+ nvkm_gpuobj_ref(NULL, &priv->pad);
+ nvkm_gpuobj_ref(NULL, &priv->mem);
+ nvkm_bar_destroy(&priv->base);
+}
+
+static int
+nv50_bar_init(struct nvkm_object *object)
+{
+ struct nv50_bar_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nvkm_bar_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x000200, 0x00000100, 0x00000000);
+ nv_mask(priv, 0x000200, 0x00000100, 0x00000100);
+ nv_wr32(priv, 0x100c80, 0x00060001);
+ if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000)) {
+ nv_error(priv, "vm flush timeout\n");
+ return -EBUSY;
+ }
+
+ nv_wr32(priv, 0x001704, 0x00000000 | priv->mem->addr >> 12);
+ nv_wr32(priv, 0x001704, 0x40000000 | priv->mem->addr >> 12);
+ nv_wr32(priv, 0x001708, 0x80000000 | priv->bar1->node->offset >> 4);
+ nv_wr32(priv, 0x00170c, 0x80000000 | priv->bar3->node->offset >> 4);
+ for (i = 0; i < 8; i++)
+ nv_wr32(priv, 0x001900 + (i * 4), 0x00000000);
+ return 0;
+}
+
+static int
+nv50_bar_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_bar_priv *priv = (void *)object;
+ return nvkm_bar_fini(&priv->base, suspend);
+}
+
+struct nvkm_oclass
+nv50_bar_oclass = {
+ .handle = NV_SUBDEV(BAR, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_bar_ctor,
+ .dtor = nv50_bar_dtor,
+ .init = nv50_bar_init,
+ .fini = nv50_bar_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h
new file mode 100644
index 000000000000..aa85f61b48c2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bar/priv.h
@@ -0,0 +1,30 @@
+#ifndef __NVKM_BAR_PRIV_H__
+#define __NVKM_BAR_PRIV_H__
+#include <subdev/bar.h>
+
+#define nvkm_bar_create(p,e,o,d) \
+ nvkm_bar_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_bar_init(p) \
+ nvkm_subdev_init(&(p)->base)
+#define nvkm_bar_fini(p,s) \
+ nvkm_subdev_fini(&(p)->base, (s))
+
+int nvkm_bar_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void nvkm_bar_destroy(struct nvkm_bar *);
+
+void _nvkm_bar_dtor(struct nvkm_object *);
+#define _nvkm_bar_init _nvkm_subdev_init
+#define _nvkm_bar_fini _nvkm_subdev_fini
+
+int nvkm_bar_alloc(struct nvkm_bar *, struct nvkm_object *,
+ struct nvkm_mem *, struct nvkm_object **);
+
+void g84_bar_flush(struct nvkm_bar *);
+
+int gf100_bar_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void gf100_bar_dtor(struct nvkm_object *);
+int gf100_bar_init(struct nvkm_object *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
new file mode 100644
index 000000000000..64730d5e9351
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/Kbuild
@@ -0,0 +1,37 @@
+nvkm-y += nvkm/subdev/bios/base.o
+nvkm-y += nvkm/subdev/bios/bit.o
+nvkm-y += nvkm/subdev/bios/boost.o
+nvkm-y += nvkm/subdev/bios/conn.o
+nvkm-y += nvkm/subdev/bios/cstep.o
+nvkm-y += nvkm/subdev/bios/dcb.o
+nvkm-y += nvkm/subdev/bios/disp.o
+nvkm-y += nvkm/subdev/bios/dp.o
+nvkm-y += nvkm/subdev/bios/extdev.o
+nvkm-y += nvkm/subdev/bios/fan.o
+nvkm-y += nvkm/subdev/bios/gpio.o
+nvkm-y += nvkm/subdev/bios/i2c.o
+nvkm-y += nvkm/subdev/bios/image.o
+nvkm-y += nvkm/subdev/bios/init.o
+nvkm-y += nvkm/subdev/bios/mxm.o
+nvkm-y += nvkm/subdev/bios/npde.o
+nvkm-y += nvkm/subdev/bios/pcir.o
+nvkm-y += nvkm/subdev/bios/perf.o
+nvkm-y += nvkm/subdev/bios/pll.o
+nvkm-y += nvkm/subdev/bios/pmu.o
+nvkm-y += nvkm/subdev/bios/ramcfg.o
+nvkm-y += nvkm/subdev/bios/rammap.o
+nvkm-y += nvkm/subdev/bios/shadow.o
+nvkm-y += nvkm/subdev/bios/shadowacpi.o
+nvkm-y += nvkm/subdev/bios/shadowof.o
+nvkm-y += nvkm/subdev/bios/shadowpci.o
+nvkm-y += nvkm/subdev/bios/shadowramin.o
+nvkm-y += nvkm/subdev/bios/shadowrom.o
+nvkm-y += nvkm/subdev/bios/timing.o
+nvkm-y += nvkm/subdev/bios/therm.o
+nvkm-y += nvkm/subdev/bios/vmap.o
+nvkm-y += nvkm/subdev/bios/volt.o
+nvkm-y += nvkm/subdev/bios/xpio.o
+nvkm-y += nvkm/subdev/bios/M0203.o
+nvkm-y += nvkm/subdev/bios/M0205.o
+nvkm-y += nvkm/subdev/bios/M0209.o
+nvkm-y += nvkm/subdev/bios/P0260.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c
new file mode 100644
index 000000000000..08eb03fbc203
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0203.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0203.h>
+
+u32
+nvbios_M0203Te(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry bit_M;
+ u32 data = 0x00000000;
+
+ if (!bit_entry(bios, 'M', &bit_M)) {
+ if (bit_M.version == 2 && bit_M.length > 0x04)
+ data = nv_ro16(bios, bit_M.offset + 0x03);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0x00);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, data + 0x01);
+ *len = nv_ro08(bios, data + 0x02);
+ *cnt = nv_ro08(bios, data + 0x03);
+ return data;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x00000000;
+}
+
+u32
+nvbios_M0203Tp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_M0203T *info)
+{
+ u32 data = nvbios_M0203Te(bios, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->type = nv_ro08(bios, data + 0x04);
+ info->pointer = nv_ro16(bios, data + 0x05);
+ break;
+ default:
+ break;
+ }
+ return data;
+}
+
+u32
+nvbios_M0203Ee(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+ u8 cnt, len;
+ u32 data = nvbios_M0203Te(bios, ver, hdr, &cnt, &len);
+ if (data && idx < cnt) {
+ data = data + *hdr + idx * len;
+ *hdr = len;
+ return data;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0203Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_M0203E *info)
+{
+ u32 data = nvbios_M0203Ee(bios, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->type = (nv_ro08(bios, data + 0x00) & 0x0f) >> 0;
+ info->strap = (nv_ro08(bios, data + 0x00) & 0xf0) >> 4;
+ info->group = (nv_ro08(bios, data + 0x01) & 0x0f) >> 0;
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0203Em(struct nvkm_bios *bios, u8 ramcfg, u8 *ver, u8 *hdr,
+ struct nvbios_M0203E *info)
+{
+ struct nvbios_M0203T M0203T;
+ u8 cnt, len, idx = 0xff;
+ u32 data;
+
+ if (!nvbios_M0203Tp(bios, ver, hdr, &cnt, &len, &M0203T)) {
+ nv_warn(bios, "M0203T not found\n");
+ return 0x00000000;
+ }
+
+ while ((data = nvbios_M0203Ep(bios, ++idx, ver, hdr, info))) {
+ switch (M0203T.type) {
+ case M0203T_TYPE_RAMCFG:
+ if (info->strap != ramcfg)
+ continue;
+ return data;
+ default:
+ nv_warn(bios, "M0203T type %02x\n", M0203T.type);
+ return 0x00000000;
+ }
+ }
+
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c
new file mode 100644
index 000000000000..e1a8ad5f3066
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0205.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0205.h>
+
+u32
+nvbios_M0205Te(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+ struct bit_entry bit_M;
+ u32 data = 0x00000000;
+
+ if (!bit_entry(bios, 'M', &bit_M)) {
+ if (bit_M.version == 2 && bit_M.length > 0x08)
+ data = nv_ro32(bios, bit_M.offset + 0x05);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0x00);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, data + 0x01);
+ *len = nv_ro08(bios, data + 0x02);
+ *ssz = nv_ro08(bios, data + 0x03);
+ *snr = nv_ro08(bios, data + 0x04);
+ *cnt = nv_ro08(bios, data + 0x05);
+ return data;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x00000000;
+}
+
+u32
+nvbios_M0205Tp(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz,
+ struct nvbios_M0205T *info)
+{
+ u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, snr, ssz);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->freq = nv_ro16(bios, data + 0x06);
+ break;
+ default:
+ break;
+ }
+ return data;
+}
+
+u32
+nvbios_M0205Ee(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 snr, ssz;
+ u32 data = nvbios_M0205Te(bios, ver, hdr, cnt, len, &snr, &ssz);
+ if (data && idx < *cnt) {
+ data = data + *hdr + idx * (*len + (snr * ssz));
+ *hdr = *len;
+ *cnt = snr;
+ *len = ssz;
+ return data;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0205Ep(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_M0205E *info)
+{
+ u32 data = nvbios_M0205Ee(bios, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->type = nv_ro08(bios, data + 0x00) & 0x0f;
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0205Se(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
+{
+
+ u8 cnt, len;
+ u32 data = nvbios_M0205Ee(bios, ent, ver, hdr, &cnt, &len);
+ if (data && idx < cnt) {
+ data = data + *hdr + idx * len;
+ *hdr = len;
+ return data;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0205Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_M0205S *info)
+{
+ u32 data = nvbios_M0205Se(bios, ent, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->data = nv_ro08(bios, data + 0x00);
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c
new file mode 100644
index 000000000000..3026920c3358
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/M0209.c
@@ -0,0 +1,135 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/M0209.h>
+
+u32
+nvbios_M0209Te(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+ struct bit_entry bit_M;
+ u32 data = 0x00000000;
+
+ if (!bit_entry(bios, 'M', &bit_M)) {
+ if (bit_M.version == 2 && bit_M.length > 0x0c)
+ data = nv_ro32(bios, bit_M.offset + 0x09);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0x00);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, data + 0x01);
+ *len = nv_ro08(bios, data + 0x02);
+ *ssz = nv_ro08(bios, data + 0x03);
+ *snr = 1;
+ *cnt = nv_ro08(bios, data + 0x04);
+ return data;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x00000000;
+}
+
+u32
+nvbios_M0209Ee(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 snr, ssz;
+ u32 data = nvbios_M0209Te(bios, ver, hdr, cnt, len, &snr, &ssz);
+ if (data && idx < *cnt) {
+ data = data + *hdr + idx * (*len + (snr * ssz));
+ *hdr = *len;
+ *cnt = snr;
+ *len = ssz;
+ return data;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0209Ep(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_M0209E *info)
+{
+ u32 data = nvbios_M0209Ee(bios, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->v00_40 = (nv_ro08(bios, data + 0x00) & 0x40) >> 6;
+ info->bits = nv_ro08(bios, data + 0x00) & 0x3f;
+ info->modulo = nv_ro08(bios, data + 0x01);
+ info->v02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+ info->v02_07 = nv_ro08(bios, data + 0x02) & 0x07;
+ info->v03 = nv_ro08(bios, data + 0x03);
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0209Se(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr)
+{
+
+ u8 cnt, len;
+ u32 data = nvbios_M0209Ee(bios, ent, ver, hdr, &cnt, &len);
+ if (data && idx < cnt) {
+ data = data + *hdr + idx * len;
+ *hdr = len;
+ return data;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_M0209Sp(struct nvkm_bios *bios, int ent, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_M0209S *info)
+{
+ struct nvbios_M0209E M0209E;
+ u8 cnt, len;
+ u32 data = nvbios_M0209Ep(bios, ent, ver, hdr, &cnt, &len, &M0209E);
+ if (data) {
+ u32 i, data = nvbios_M0209Se(bios, ent, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ for (i = 0; i < ARRAY_SIZE(info->data); i++) {
+ u32 bits = (i % M0209E.modulo) * M0209E.bits;
+ u32 mask = (1ULL << M0209E.bits) - 1;
+ u16 off = bits / 8;
+ u8 mod = bits % 8;
+ info->data[i] = nv_ro32(bios, data + off);
+ info->data[i] = info->data[i] >> mod;
+ info->data[i] = info->data[i] & mask;
+ }
+ return data;
+ default:
+ break;
+ }
+ }
+ return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c
new file mode 100644
index 000000000000..b72edcf849b6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/P0260.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/P0260.h>
+
+u32
+nvbios_P0260Te(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
+{
+ struct bit_entry bit_P;
+ u32 data = 0x00000000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2 && bit_P.length > 0x63)
+ data = nv_ro32(bios, bit_P.offset + 0x60);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, data + 1);
+ *cnt = nv_ro08(bios, data + 2);
+ *len = 4;
+ *xnr = nv_ro08(bios, data + 3);
+ *xsz = 4;
+ return data;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x00000000;
+}
+
+u32
+nvbios_P0260Ee(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt, xnr, xsz;
+ u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, len, &xnr, &xsz);
+ if (data && idx < cnt)
+ return data + hdr + (idx * *len);
+ return 0x00000000;
+}
+
+u32
+nvbios_P0260Ep(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
+ struct nvbios_P0260E *info)
+{
+ u32 data = nvbios_P0260Ee(bios, idx, ver, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->data = nv_ro32(bios, data);
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_P0260Xe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *xsz)
+{
+ u8 hdr, cnt, len, xnr;
+ u32 data = nvbios_P0260Te(bios, ver, &hdr, &cnt, &len, &xnr, xsz);
+ if (data && idx < xnr)
+ return data + hdr + (cnt * len) + (idx * *xsz);
+ return 0x00000000;
+}
+
+u32
+nvbios_P0260Xp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_P0260X *info)
+{
+ u32 data = nvbios_P0260Xe(bios, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x10:
+ info->data = nv_ro32(bios, data);
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
new file mode 100644
index 000000000000..8db204f92ed3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/base.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/bit.h>
+
+u8
+nvbios_checksum(const u8 *data, int size)
+{
+ u8 sum = 0;
+ while (size--)
+ sum += *data++;
+ return sum;
+}
+
+u16
+nvbios_findstr(const u8 *data, int size, const char *str, int len)
+{
+ int i, j;
+
+ for (i = 0; i <= (size - len); i++) {
+ for (j = 0; j < len; j++)
+ if ((char)data[i + j] != str[j])
+ break;
+ if (j == len)
+ return i;
+ }
+
+ return 0;
+}
+
+int
+nvbios_extend(struct nvkm_bios *bios, u32 length)
+{
+ if (bios->size < length) {
+ u8 *prev = bios->data;
+ if (!(bios->data = kmalloc(length, GFP_KERNEL))) {
+ bios->data = prev;
+ return -ENOMEM;
+ }
+ memcpy(bios->data, prev, bios->size);
+ bios->size = length;
+ kfree(prev);
+ return 1;
+ }
+ return 0;
+}
+
+static u8
+nvkm_bios_rd08(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_bios *bios = (void *)object;
+ return bios->data[addr];
+}
+
+static u16
+nvkm_bios_rd16(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_bios *bios = (void *)object;
+ return get_unaligned_le16(&bios->data[addr]);
+}
+
+static u32
+nvkm_bios_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_bios *bios = (void *)object;
+ return get_unaligned_le32(&bios->data[addr]);
+}
+
+static void
+nvkm_bios_wr08(struct nvkm_object *object, u64 addr, u8 data)
+{
+ struct nvkm_bios *bios = (void *)object;
+ bios->data[addr] = data;
+}
+
+static void
+nvkm_bios_wr16(struct nvkm_object *object, u64 addr, u16 data)
+{
+ struct nvkm_bios *bios = (void *)object;
+ put_unaligned_le16(data, &bios->data[addr]);
+}
+
+static void
+nvkm_bios_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nvkm_bios *bios = (void *)object;
+ put_unaligned_le32(data, &bios->data[addr]);
+}
+
+static int
+nvkm_bios_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_bios *bios;
+ struct bit_entry bit_i;
+ int ret;
+
+ ret = nvkm_subdev_create(parent, engine, oclass, 0,
+ "VBIOS", "bios", &bios);
+ *pobject = nv_object(bios);
+ if (ret)
+ return ret;
+
+ ret = nvbios_shadow(bios);
+ if (ret)
+ return ret;
+
+ /* detect type of vbios we're dealing with */
+ bios->bmp_offset = nvbios_findstr(bios->data, bios->size,
+ "\xff\x7f""NV\0", 5);
+ if (bios->bmp_offset) {
+ nv_info(bios, "BMP version %x.%x\n",
+ bmp_version(bios) >> 8,
+ bmp_version(bios) & 0xff);
+ }
+
+ bios->bit_offset = nvbios_findstr(bios->data, bios->size,
+ "\xff\xb8""BIT", 5);
+ if (bios->bit_offset)
+ nv_info(bios, "BIT signature found\n");
+
+ /* determine the vbios version number */
+ if (!bit_entry(bios, 'i', &bit_i) && bit_i.length >= 4) {
+ bios->version.major = nv_ro08(bios, bit_i.offset + 3);
+ bios->version.chip = nv_ro08(bios, bit_i.offset + 2);
+ bios->version.minor = nv_ro08(bios, bit_i.offset + 1);
+ bios->version.micro = nv_ro08(bios, bit_i.offset + 0);
+ bios->version.patch = nv_ro08(bios, bit_i.offset + 4);
+ } else
+ if (bmp_version(bios)) {
+ bios->version.major = nv_ro08(bios, bios->bmp_offset + 13);
+ bios->version.chip = nv_ro08(bios, bios->bmp_offset + 12);
+ bios->version.minor = nv_ro08(bios, bios->bmp_offset + 11);
+ bios->version.micro = nv_ro08(bios, bios->bmp_offset + 10);
+ }
+
+ nv_info(bios, "version %02x.%02x.%02x.%02x.%02x\n",
+ bios->version.major, bios->version.chip,
+ bios->version.minor, bios->version.micro, bios->version.patch);
+
+ return 0;
+}
+
+static void
+nvkm_bios_dtor(struct nvkm_object *object)
+{
+ struct nvkm_bios *bios = (void *)object;
+ kfree(bios->data);
+ nvkm_subdev_destroy(&bios->base);
+}
+
+static int
+nvkm_bios_init(struct nvkm_object *object)
+{
+ struct nvkm_bios *bios = (void *)object;
+ return nvkm_subdev_init(&bios->base);
+}
+
+static int
+nvkm_bios_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_bios *bios = (void *)object;
+ return nvkm_subdev_fini(&bios->base, suspend);
+}
+
+struct nvkm_oclass
+nvkm_bios_oclass = {
+ .handle = NV_SUBDEV(VBIOS, 0x00),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nvkm_bios_ctor,
+ .dtor = nvkm_bios_dtor,
+ .init = nvkm_bios_init,
+ .fini = nvkm_bios_fini,
+ .rd08 = nvkm_bios_rd08,
+ .rd16 = nvkm_bios_rd16,
+ .rd32 = nvkm_bios_rd32,
+ .wr08 = nvkm_bios_wr08,
+ .wr16 = nvkm_bios_wr16,
+ .wr32 = nvkm_bios_wr32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c
new file mode 100644
index 000000000000..eab540496cdf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/bit.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+
+int
+bit_entry(struct nvkm_bios *bios, u8 id, struct bit_entry *bit)
+{
+ if (likely(bios->bit_offset)) {
+ u8 entries = nv_ro08(bios, bios->bit_offset + 10);
+ u32 entry = bios->bit_offset + 12;
+ while (entries--) {
+ if (nv_ro08(bios, entry + 0) == id) {
+ bit->id = nv_ro08(bios, entry + 0);
+ bit->version = nv_ro08(bios, entry + 1);
+ bit->length = nv_ro16(bios, entry + 2);
+ bit->offset = nv_ro16(bios, entry + 4);
+ return 0;
+ }
+
+ entry += nv_ro08(bios, bios->bit_offset + 9);
+ }
+
+ return -ENOENT;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c
new file mode 100644
index 000000000000..12e958533f46
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/boost.c
@@ -0,0 +1,126 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/boost.h>
+
+u16
+nvbios_boostTe(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+ struct bit_entry bit_P;
+ u16 boost = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2)
+ boost = nv_ro16(bios, bit_P.offset + 0x30);
+
+ if (boost) {
+ *ver = nv_ro08(bios, boost + 0);
+ switch (*ver) {
+ case 0x11:
+ *hdr = nv_ro08(bios, boost + 1);
+ *cnt = nv_ro08(bios, boost + 5);
+ *len = nv_ro08(bios, boost + 2);
+ *snr = nv_ro08(bios, boost + 4);
+ *ssz = nv_ro08(bios, boost + 3);
+ return boost;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_boostEe(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 snr, ssz;
+ u16 data = nvbios_boostTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+ if (data && idx < *cnt) {
+ data = data + *hdr + (idx * (*len + (snr * ssz)));
+ *hdr = *len;
+ *cnt = snr;
+ *len = ssz;
+ return data;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_boostEp(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
+{
+ u16 data = nvbios_boostEe(bios, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
+ info->min = nv_ro16(bios, data + 0x02) * 1000;
+ info->max = nv_ro16(bios, data + 0x04) * 1000;
+ }
+ return data;
+}
+
+u16
+nvbios_boostEm(struct nvkm_bios *bios, u8 pstate,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_boostE *info)
+{
+ u32 data, idx = 0;
+ while ((data = nvbios_boostEp(bios, idx++, ver, hdr, cnt, len, info))) {
+ if (info->pstate == pstate)
+ break;
+ }
+ return data;
+}
+
+u16
+nvbios_boostSe(struct nvkm_bios *bios, int idx,
+ u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len)
+{
+ if (data && idx < cnt) {
+ data = data + *hdr + (idx * len);
+ *hdr = len;
+ return data;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_boostSp(struct nvkm_bios *bios, int idx,
+ u16 data, u8 *ver, u8 *hdr, u8 cnt, u8 len,
+ struct nvbios_boostS *info)
+{
+ data = nvbios_boostSe(bios, idx, data, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ info->domain = nv_ro08(bios, data + 0x00);
+ info->percent = nv_ro08(bios, data + 0x01);
+ info->min = nv_ro16(bios, data + 0x02) * 1000;
+ info->max = nv_ro16(bios, data + 0x04) * 1000;
+ }
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c
new file mode 100644
index 000000000000..706a1650a4f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/conn.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/conn.h>
+
+u32
+nvbios_connTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u32 dcb = dcb_table(bios, ver, hdr, cnt, len);
+ if (dcb && *ver >= 0x30 && *hdr >= 0x16) {
+ u32 data = nv_ro16(bios, dcb + 0x14);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0);
+ *hdr = nv_ro08(bios, data + 1);
+ *cnt = nv_ro08(bios, data + 2);
+ *len = nv_ro08(bios, data + 3);
+ return data;
+ }
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_connTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_connT *info)
+{
+ u32 data = nvbios_connTe(bios, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x30:
+ case 0x40:
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
+
+u32
+nvbios_connEe(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u32 data = nvbios_connTe(bios, ver, &hdr, &cnt, len);
+ if (data && idx < cnt)
+ return data + hdr + (idx * *len);
+ return 0x00000000;
+}
+
+u32
+nvbios_connEp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len,
+ struct nvbios_connE *info)
+{
+ u32 data = nvbios_connEe(bios, idx, ver, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x30:
+ case 0x40:
+ info->type = nv_ro08(bios, data + 0x00);
+ info->location = nv_ro08(bios, data + 0x01) & 0x0f;
+ info->hpd = (nv_ro08(bios, data + 0x01) & 0x30) >> 4;
+ info->dp = (nv_ro08(bios, data + 0x01) & 0xc0) >> 6;
+ if (*len < 4)
+ return data;
+ info->hpd |= (nv_ro08(bios, data + 0x02) & 0x03) << 2;
+ info->dp |= nv_ro08(bios, data + 0x02) & 0x0c;
+ info->di = (nv_ro08(bios, data + 0x02) & 0xf0) >> 4;
+ info->hpd |= (nv_ro08(bios, data + 0x03) & 0x07) << 4;
+ info->sr = (nv_ro08(bios, data + 0x03) & 0x08) >> 3;
+ info->lcdid = (nv_ro08(bios, data + 0x03) & 0x70) >> 4;
+ return data;
+ default:
+ break;
+ }
+ return 0x00000000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c
new file mode 100644
index 000000000000..16f7ad8a4f80
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/cstep.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/cstep.h>
+
+u16
+nvbios_cstepTe(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *xnr, u8 *xsz)
+{
+ struct bit_entry bit_P;
+ u16 cstep = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2)
+ cstep = nv_ro16(bios, bit_P.offset + 0x34);
+
+ if (cstep) {
+ *ver = nv_ro08(bios, cstep + 0);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, cstep + 1);
+ *cnt = nv_ro08(bios, cstep + 3);
+ *len = nv_ro08(bios, cstep + 2);
+ *xnr = nv_ro08(bios, cstep + 5);
+ *xsz = nv_ro08(bios, cstep + 4);
+ return cstep;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_cstepEe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+ u8 cnt, len, xnr, xsz;
+ u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
+ if (data && idx < cnt) {
+ data = data + *hdr + (idx * len);
+ *hdr = len;
+ return data;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_cstepEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_cstepE *info)
+{
+ u16 data = nvbios_cstepEe(bios, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ info->pstate = (nv_ro16(bios, data + 0x00) & 0x01e0) >> 5;
+ info->index = nv_ro08(bios, data + 0x03);
+ }
+ return data;
+}
+
+u16
+nvbios_cstepEm(struct nvkm_bios *bios, u8 pstate, u8 *ver, u8 *hdr,
+ struct nvbios_cstepE *info)
+{
+ u32 data, idx = 0;
+ while ((data = nvbios_cstepEp(bios, idx++, ver, hdr, info))) {
+ if (info->pstate == pstate)
+ break;
+ }
+ return data;
+}
+
+u16
+nvbios_cstepXe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+ u8 cnt, len, xnr, xsz;
+ u16 data = nvbios_cstepTe(bios, ver, hdr, &cnt, &len, &xnr, &xsz);
+ if (data && idx < xnr) {
+ data = data + *hdr + (cnt * len) + (idx * xsz);
+ *hdr = xsz;
+ return data;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_cstepXp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_cstepX *info)
+{
+ u16 data = nvbios_cstepXe(bios, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ info->freq = nv_ro16(bios, data + 0x00) * 1000;
+ info->unkn[0] = nv_ro08(bios, data + 0x02);
+ info->unkn[1] = nv_ro08(bios, data + 0x03);
+ info->voltage = nv_ro08(bios, data + 0x04);
+ }
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
new file mode 100644
index 000000000000..8d78140f9401
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dcb.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+#include <core/device.h>
+
+u16
+dcb_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct nvkm_device *device = nv_device(bios);
+ u16 dcb = 0x0000;
+
+ if (device->card_type > NV_04)
+ dcb = nv_ro16(bios, 0x36);
+ if (!dcb) {
+ nv_warn(bios, "DCB table not found\n");
+ return dcb;
+ }
+
+ *ver = nv_ro08(bios, dcb);
+
+ if (*ver >= 0x42) {
+ nv_warn(bios, "DCB version 0x%02x unknown\n", *ver);
+ return 0x0000;
+ } else
+ if (*ver >= 0x30) {
+ if (nv_ro32(bios, dcb + 6) == 0x4edcbdcb) {
+ *hdr = nv_ro08(bios, dcb + 1);
+ *cnt = nv_ro08(bios, dcb + 2);
+ *len = nv_ro08(bios, dcb + 3);
+ return dcb;
+ }
+ } else
+ if (*ver >= 0x20) {
+ if (nv_ro32(bios, dcb + 4) == 0x4edcbdcb) {
+ u16 i2c = nv_ro16(bios, dcb + 2);
+ *hdr = 8;
+ *cnt = (i2c - dcb) / 8;
+ *len = 8;
+ return dcb;
+ }
+ } else
+ if (*ver >= 0x15) {
+ if (!nv_memcmp(bios, dcb - 7, "DEV_REC", 7)) {
+ u16 i2c = nv_ro16(bios, dcb + 2);
+ *hdr = 4;
+ *cnt = (i2c - dcb) / 10;
+ *len = 10;
+ return dcb;
+ }
+ } else {
+ /*
+ * v1.4 (some NV15/16, NV11+) seems the same as v1.5, but
+ * always has the same single (crt) entry, even when tv-out
+ * present, so the conclusion is this version cannot really
+ * be used.
+ *
+ * v1.2 tables (some NV6/10, and NV15+) normally have the
+ * same 5 entries, which are not specific to the card and so
+ * no use.
+ *
+ * v1.2 does have an I2C table that read_dcb_i2c_table can
+ * handle, but cards exist (nv11 in #14821) with a bad i2c
+ * table pointer, so use the indices parsed in
+ * parse_bmp_structure.
+ *
+ * v1.1 (NV5+, maybe some NV4) is entirely unhelpful
+ */
+ nv_warn(bios, "DCB contains no useful data\n");
+ return 0x0000;
+ }
+
+ nv_warn(bios, "DCB header validation failed\n");
+ return 0x0000;
+}
+
+u16
+dcb_outp(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u16 dcb = dcb_table(bios, ver, &hdr, &cnt, len);
+ if (dcb && idx < cnt)
+ return dcb + hdr + (idx * *len);
+ return 0x0000;
+}
+
+static inline u16
+dcb_outp_hasht(struct dcb_output *outp)
+{
+ return (outp->extdev << 8) | (outp->location << 4) | outp->type;
+}
+
+static inline u16
+dcb_outp_hashm(struct dcb_output *outp)
+{
+ return (outp->heads << 8) | (outp->link << 6) | outp->or;
+}
+
+u16
+dcb_outp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len,
+ struct dcb_output *outp)
+{
+ u16 dcb = dcb_outp(bios, idx, ver, len);
+ memset(outp, 0x00, sizeof(*outp));
+ if (dcb) {
+ if (*ver >= 0x20) {
+ u32 conn = nv_ro32(bios, dcb + 0x00);
+ outp->or = (conn & 0x0f000000) >> 24;
+ outp->location = (conn & 0x00300000) >> 20;
+ outp->bus = (conn & 0x000f0000) >> 16;
+ outp->connector = (conn & 0x0000f000) >> 12;
+ outp->heads = (conn & 0x00000f00) >> 8;
+ outp->i2c_index = (conn & 0x000000f0) >> 4;
+ outp->type = (conn & 0x0000000f);
+ outp->link = 0;
+ } else {
+ dcb = 0x0000;
+ }
+
+ if (*ver >= 0x40) {
+ u32 conf = nv_ro32(bios, dcb + 0x04);
+ switch (outp->type) {
+ case DCB_OUTPUT_DP:
+ switch (conf & 0x00e00000) {
+ case 0x00000000:
+ outp->dpconf.link_bw = 0x06;
+ break;
+ case 0x00200000:
+ outp->dpconf.link_bw = 0x0a;
+ break;
+ case 0x00400000:
+ default:
+ outp->dpconf.link_bw = 0x14;
+ break;
+ }
+
+ outp->dpconf.link_nr = (conf & 0x0f000000) >> 24;
+ if (*ver < 0x41) {
+ switch (outp->dpconf.link_nr) {
+ case 0x0f:
+ outp->dpconf.link_nr = 4;
+ break;
+ case 0x03:
+ outp->dpconf.link_nr = 2;
+ break;
+ case 0x01:
+ default:
+ outp->dpconf.link_nr = 1;
+ break;
+ }
+ }
+
+ /* fall-through... */
+ case DCB_OUTPUT_TMDS:
+ case DCB_OUTPUT_LVDS:
+ outp->link = (conf & 0x00000030) >> 4;
+ outp->sorconf.link = outp->link; /*XXX*/
+ outp->extdev = 0x00;
+ if (outp->location != 0)
+ outp->extdev = (conf & 0x0000ff00) >> 8;
+ break;
+ default:
+ break;
+ }
+ }
+
+ outp->hasht = dcb_outp_hasht(outp);
+ outp->hashm = dcb_outp_hashm(outp);
+ }
+ return dcb;
+}
+
+u16
+dcb_outp_match(struct nvkm_bios *bios, u16 type, u16 mask,
+ u8 *ver, u8 *len, struct dcb_output *outp)
+{
+ u16 dcb, idx = 0;
+ while ((dcb = dcb_outp_parse(bios, idx++, ver, len, outp))) {
+ if ((dcb_outp_hasht(outp) & 0x00ff) == (type & 0x00ff)) {
+ if ((dcb_outp_hashm(outp) & mask) == mask)
+ break;
+ }
+ }
+ return dcb;
+}
+
+int
+dcb_outp_foreach(struct nvkm_bios *bios, void *data,
+ int (*exec)(struct nvkm_bios *, void *, int, u16))
+{
+ int ret, idx = -1;
+ u8 ver, len;
+ u16 outp;
+
+ while ((outp = dcb_outp(bios, ++idx, &ver, &len))) {
+ if (nv_ro32(bios, outp) == 0x00000000)
+ break; /* seen on an NV11 with DCB v1.5 */
+ if (nv_ro32(bios, outp) == 0xffffffff)
+ break; /* seen on an NV17 with DCB v2.0 */
+
+ if (nv_ro08(bios, outp) == DCB_OUTPUT_UNUSED)
+ continue;
+ if (nv_ro08(bios, outp) == DCB_OUTPUT_EOL)
+ break;
+
+ ret = exec(bios, data, idx, outp);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c
new file mode 100644
index 000000000000..262c410b7ee2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/disp.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/disp.h>
+
+u16
+nvbios_disp_table(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *sub)
+{
+ struct bit_entry U;
+
+ if (!bit_entry(bios, 'U', &U)) {
+ if (U.version == 1) {
+ u16 data = nv_ro16(bios, U.offset);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0x00);
+ switch (*ver) {
+ case 0x20:
+ case 0x21:
+ case 0x22:
+ *hdr = nv_ro08(bios, data + 0x01);
+ *len = nv_ro08(bios, data + 0x02);
+ *cnt = nv_ro08(bios, data + 0x03);
+ *sub = nv_ro08(bios, data + 0x04);
+ return data;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_disp_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, u8 *sub)
+{
+ u8 hdr, cnt;
+ u16 data = nvbios_disp_table(bios, ver, &hdr, &cnt, len, sub);
+ if (data && idx < cnt)
+ return data + hdr + (idx * *len);
+ *ver = 0x00;
+ return 0x0000;
+}
+
+u16
+nvbios_disp_parse(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len, u8 *sub,
+ struct nvbios_disp *info)
+{
+ u16 data = nvbios_disp_entry(bios, idx, ver, len, sub);
+ if (data && *len >= 2) {
+ info->data = nv_ro16(bios, data + 0);
+ return data;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_outp_entry(struct nvkm_bios *bios, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct nvbios_disp info;
+ u16 data = nvbios_disp_parse(bios, idx, ver, len, hdr, &info);
+ if (data) {
+ *cnt = nv_ro08(bios, info.data + 0x05);
+ *len = 0x06;
+ data = info.data;
+ }
+ return data;
+}
+
+u16
+nvbios_outp_parse(struct nvkm_bios *bios, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info)
+{
+ u16 data = nvbios_outp_entry(bios, idx, ver, hdr, cnt, len);
+ if (data && *hdr >= 0x0a) {
+ info->type = nv_ro16(bios, data + 0x00);
+ info->mask = nv_ro32(bios, data + 0x02);
+ if (*ver <= 0x20) /* match any link */
+ info->mask |= 0x00c0;
+ info->script[0] = nv_ro16(bios, data + 0x06);
+ info->script[1] = nv_ro16(bios, data + 0x08);
+ info->script[2] = 0x0000;
+ if (*hdr >= 0x0c)
+ info->script[2] = nv_ro16(bios, data + 0x0a);
+ return data;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_outp_match(struct nvkm_bios *bios, u16 type, u16 mask,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_outp *info)
+{
+ u16 data, idx = 0;
+ while ((data = nvbios_outp_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
+ if (data && info->type == type) {
+ if ((info->mask & mask) == mask)
+ break;
+ }
+ }
+ return data;
+}
+
+u16
+nvbios_ocfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ if (idx < *cnt)
+ return outp + *hdr + (idx * *len);
+ return 0x0000;
+}
+
+u16
+nvbios_ocfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info)
+{
+ u16 data = nvbios_ocfg_entry(bios, outp, idx, ver, hdr, cnt, len);
+ if (data) {
+ info->match = nv_ro16(bios, data + 0x00);
+ info->clkcmp[0] = nv_ro16(bios, data + 0x02);
+ info->clkcmp[1] = nv_ro16(bios, data + 0x04);
+ }
+ return data;
+}
+
+u16
+nvbios_ocfg_match(struct nvkm_bios *bios, u16 outp, u16 type,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ocfg *info)
+{
+ u16 data, idx = 0;
+ while ((data = nvbios_ocfg_parse(bios, outp, idx++, ver, hdr, cnt, len, info))) {
+ if (info->match == type)
+ break;
+ }
+ return data;
+}
+
+u16
+nvbios_oclk_match(struct nvkm_bios *bios, u16 cmp, u32 khz)
+{
+ while (cmp) {
+ if (khz / 10 >= nv_ro16(bios, cmp + 0x00))
+ return nv_ro16(bios, cmp + 0x02);
+ cmp += 0x04;
+ }
+ return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
new file mode 100644
index 000000000000..95970faae6c8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/dp.c
@@ -0,0 +1,215 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/dp.h>
+
+static u16
+nvbios_dp_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry d;
+
+ if (!bit_entry(bios, 'd', &d)) {
+ if (d.version == 1 && d.length >= 2) {
+ u16 data = nv_ro16(bios, d.offset);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0x00);
+ switch (*ver) {
+ case 0x21:
+ case 0x30:
+ case 0x40:
+ case 0x41:
+ *hdr = nv_ro08(bios, data + 0x01);
+ *len = nv_ro08(bios, data + 0x02);
+ *cnt = nv_ro08(bios, data + 0x03);
+ return data;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+static u16
+nvbios_dpout_entry(struct nvkm_bios *bios, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u16 data = nvbios_dp_table(bios, ver, hdr, cnt, len);
+ if (data && idx < *cnt) {
+ u16 outp = nv_ro16(bios, data + *hdr + idx * *len);
+ switch (*ver * !!outp) {
+ case 0x21:
+ case 0x30:
+ *hdr = nv_ro08(bios, data + 0x04);
+ *len = nv_ro08(bios, data + 0x05);
+ *cnt = nv_ro08(bios, outp + 0x04);
+ break;
+ case 0x40:
+ case 0x41:
+ *hdr = nv_ro08(bios, data + 0x04);
+ *cnt = 0;
+ *len = 0;
+ break;
+ default:
+ break;
+ }
+ return outp;
+ }
+ *ver = 0x00;
+ return 0x0000;
+}
+
+u16
+nvbios_dpout_parse(struct nvkm_bios *bios, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_dpout *info)
+{
+ u16 data = nvbios_dpout_entry(bios, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ if (data && *ver) {
+ info->type = nv_ro16(bios, data + 0x00);
+ info->mask = nv_ro16(bios, data + 0x02);
+ switch (*ver) {
+ case 0x21:
+ case 0x30:
+ info->flags = nv_ro08(bios, data + 0x05);
+ info->script[0] = nv_ro16(bios, data + 0x06);
+ info->script[1] = nv_ro16(bios, data + 0x08);
+ info->lnkcmp = nv_ro16(bios, data + 0x0a);
+ if (*len >= 0x0f) {
+ info->script[2] = nv_ro16(bios, data + 0x0c);
+ info->script[3] = nv_ro16(bios, data + 0x0e);
+ }
+ if (*len >= 0x11)
+ info->script[4] = nv_ro16(bios, data + 0x10);
+ break;
+ case 0x40:
+ case 0x41:
+ info->flags = nv_ro08(bios, data + 0x04);
+ info->script[0] = nv_ro16(bios, data + 0x05);
+ info->script[1] = nv_ro16(bios, data + 0x07);
+ info->lnkcmp = nv_ro16(bios, data + 0x09);
+ info->script[2] = nv_ro16(bios, data + 0x0b);
+ info->script[3] = nv_ro16(bios, data + 0x0d);
+ info->script[4] = nv_ro16(bios, data + 0x0f);
+ break;
+ default:
+ data = 0x0000;
+ break;
+ }
+ }
+ return data;
+}
+
+u16
+nvbios_dpout_match(struct nvkm_bios *bios, u16 type, u16 mask,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_dpout *info)
+{
+ u16 data, idx = 0;
+ while ((data = nvbios_dpout_parse(bios, idx++, ver, hdr, cnt, len, info)) || *ver) {
+ if (data && info->type == type) {
+ if ((info->mask & mask) == mask)
+ break;
+ }
+ }
+ return data;
+}
+
+static u16
+nvbios_dpcfg_entry(struct nvkm_bios *bios, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ if (*ver >= 0x40) {
+ outp = nvbios_dp_table(bios, ver, hdr, cnt, len);
+ *hdr = *hdr + (*len * * cnt);
+ *len = nv_ro08(bios, outp + 0x06);
+ *cnt = nv_ro08(bios, outp + 0x07);
+ }
+
+ if (idx < *cnt)
+ return outp + *hdr + (idx * *len);
+
+ return 0x0000;
+}
+
+u16
+nvbios_dpcfg_parse(struct nvkm_bios *bios, u16 outp, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_dpcfg *info)
+{
+ u16 data = nvbios_dpcfg_entry(bios, outp, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ switch (*ver) {
+ case 0x21:
+ info->dc = nv_ro08(bios, data + 0x02);
+ info->pe = nv_ro08(bios, data + 0x03);
+ info->tx_pu = nv_ro08(bios, data + 0x04);
+ break;
+ case 0x30:
+ case 0x40:
+ case 0x41:
+ info->pc = nv_ro08(bios, data + 0x00);
+ info->dc = nv_ro08(bios, data + 0x01);
+ info->pe = nv_ro08(bios, data + 0x02);
+ info->tx_pu = nv_ro08(bios, data + 0x03) & 0x0f;
+ break;
+ default:
+ data = 0x0000;
+ break;
+ }
+ }
+ return data;
+}
+
+u16
+nvbios_dpcfg_match(struct nvkm_bios *bios, u16 outp, u8 pc, u8 vs, u8 pe,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_dpcfg *info)
+{
+ u8 idx = 0xff;
+ u16 data;
+
+ if (*ver >= 0x30) {
+ /*XXX: there's a second set of these on at least 4.1, that
+ * i've witnessed nvidia using instead of the first
+ * on gm204. figure out what/why
+ */
+ const u8 vsoff[] = { 0, 4, 7, 9 };
+ idx = (pc * 10) + vsoff[vs] + pe;
+ } else {
+ while ((data = nvbios_dpcfg_entry(bios, outp, ++idx,
+ ver, hdr, cnt, len))) {
+ if (nv_ro08(bios, data + 0x00) == vs &&
+ nv_ro08(bios, data + 0x01) == pe)
+ break;
+ }
+ }
+
+ return nvbios_dpcfg_parse(bios, outp, idx, ver, hdr, cnt, len, info);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c
new file mode 100644
index 000000000000..a8503a1854c4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/extdev.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/extdev.h>
+
+static u16
+extdev_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
+{
+ u8 dcb_ver, dcb_hdr, dcb_cnt, dcb_len;
+ u16 dcb, extdev = 0;
+
+ dcb = dcb_table(bios, &dcb_ver, &dcb_hdr, &dcb_cnt, &dcb_len);
+ if (!dcb || (dcb_ver != 0x30 && dcb_ver != 0x40))
+ return 0x0000;
+
+ extdev = nv_ro16(bios, dcb + 18);
+ if (!extdev)
+ return 0x0000;
+
+ *ver = nv_ro08(bios, extdev + 0);
+ *hdr = nv_ro08(bios, extdev + 1);
+ *cnt = nv_ro08(bios, extdev + 2);
+ *len = nv_ro08(bios, extdev + 3);
+ return extdev + *hdr;
+}
+
+static u16
+nvbios_extdev_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u16 extdev = extdev_table(bios, ver, &hdr, len, &cnt);
+ if (extdev && idx < cnt)
+ return extdev + idx * *len;
+ return 0x0000;
+}
+
+static void
+extdev_parse_entry(struct nvkm_bios *bios, u16 offset,
+ struct nvbios_extdev_func *entry)
+{
+ entry->type = nv_ro08(bios, offset + 0);
+ entry->addr = nv_ro08(bios, offset + 1);
+ entry->bus = (nv_ro08(bios, offset + 2) >> 4) & 1;
+}
+
+int
+nvbios_extdev_parse(struct nvkm_bios *bios, int idx,
+ struct nvbios_extdev_func *func)
+{
+ u8 ver, len;
+ u16 entry;
+
+ if (!(entry = nvbios_extdev_entry(bios, idx, &ver, &len)))
+ return -EINVAL;
+
+ extdev_parse_entry(bios, entry, func);
+ return 0;
+}
+
+int
+nvbios_extdev_find(struct nvkm_bios *bios, enum nvbios_extdev_type type,
+ struct nvbios_extdev_func *func)
+{
+ u8 ver, len, i;
+ u16 entry;
+
+ i = 0;
+ while ((entry = nvbios_extdev_entry(bios, i++, &ver, &len))) {
+ extdev_parse_entry(bios, entry, func);
+ if (func->type == type)
+ return 0;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
new file mode 100644
index 000000000000..8dba70d9d9a9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/fan.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/fan.h>
+
+u16
+nvbios_fan_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry bit_P;
+ u16 fan = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2 && bit_P.length >= 0x5a)
+ fan = nv_ro16(bios, bit_P.offset + 0x58);
+
+ if (fan) {
+ *ver = nv_ro08(bios, fan + 0);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, fan + 1);
+ *len = nv_ro08(bios, fan + 2);
+ *cnt = nv_ro08(bios, fan + 3);
+ return fan;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_fan_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+ u8 *cnt, u8 *len)
+{
+ u16 data = nvbios_fan_table(bios, ver, hdr, cnt, len);
+ if (data && idx < *cnt)
+ return data + *hdr + (idx * (*len));
+ return 0x0000;
+}
+
+u16
+nvbios_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
+{
+ u8 ver, hdr, cnt, len;
+
+ u16 data = nvbios_fan_entry(bios, 0, &ver, &hdr, &cnt, &len);
+ if (data) {
+ u8 type = nv_ro08(bios, data + 0x00);
+ switch (type) {
+ case 0:
+ fan->type = NVBIOS_THERM_FAN_TOGGLE;
+ break;
+ case 1:
+ case 2:
+ /* TODO: Understand the difference between the two! */
+ fan->type = NVBIOS_THERM_FAN_PWM;
+ break;
+ default:
+ fan->type = NVBIOS_THERM_FAN_UNK;
+ }
+
+ fan->min_duty = nv_ro08(bios, data + 0x02);
+ fan->max_duty = nv_ro08(bios, data + 0x03);
+
+ fan->pwm_freq = nv_ro32(bios, data + 0x0b) & 0xffffff;
+ }
+
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c
new file mode 100644
index 000000000000..8ce154d88f51
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/gpio.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/xpio.h>
+
+u16
+dcb_gpio_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u16 data = 0x0000;
+ u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
+ if (dcb) {
+ if (*ver >= 0x30 && *hdr >= 0x0c)
+ data = nv_ro16(bios, dcb + 0x0a);
+ else
+ if (*ver >= 0x22 && nv_ro08(bios, dcb - 1) >= 0x13)
+ data = nv_ro16(bios, dcb - 0x0f);
+
+ if (data) {
+ *ver = nv_ro08(bios, data + 0x00);
+ if (*ver < 0x30) {
+ *hdr = 3;
+ *cnt = nv_ro08(bios, data + 0x02);
+ *len = nv_ro08(bios, data + 0x01);
+ } else
+ if (*ver <= 0x41) {
+ *hdr = nv_ro08(bios, data + 0x01);
+ *cnt = nv_ro08(bios, data + 0x02);
+ *len = nv_ro08(bios, data + 0x03);
+ } else {
+ data = 0x0000;
+ }
+ }
+ }
+ return data;
+}
+
+u16
+dcb_gpio_entry(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt, xver; /* use gpio version for xpio entry parsing */
+ u16 gpio;
+
+ if (!idx--)
+ gpio = dcb_gpio_table(bios, ver, &hdr, &cnt, len);
+ else
+ gpio = dcb_xpio_table(bios, idx, &xver, &hdr, &cnt, len);
+
+ if (gpio && ent < cnt)
+ return gpio + hdr + (ent * *len);
+
+ return 0x0000;
+}
+
+u16
+dcb_gpio_parse(struct nvkm_bios *bios, int idx, int ent, u8 *ver, u8 *len,
+ struct dcb_gpio_func *gpio)
+{
+ u16 data = dcb_gpio_entry(bios, idx, ent, ver, len);
+ if (data) {
+ if (*ver < 0x40) {
+ u16 info = nv_ro16(bios, data);
+ *gpio = (struct dcb_gpio_func) {
+ .line = (info & 0x001f) >> 0,
+ .func = (info & 0x07e0) >> 5,
+ .log[0] = (info & 0x1800) >> 11,
+ .log[1] = (info & 0x6000) >> 13,
+ .param = !!(info & 0x8000),
+ };
+ } else
+ if (*ver < 0x41) {
+ u32 info = nv_ro32(bios, data);
+ *gpio = (struct dcb_gpio_func) {
+ .line = (info & 0x0000001f) >> 0,
+ .func = (info & 0x0000ff00) >> 8,
+ .log[0] = (info & 0x18000000) >> 27,
+ .log[1] = (info & 0x60000000) >> 29,
+ .param = !!(info & 0x80000000),
+ };
+ } else {
+ u32 info = nv_ro32(bios, data + 0);
+ u8 info1 = nv_ro32(bios, data + 4);
+ *gpio = (struct dcb_gpio_func) {
+ .line = (info & 0x0000003f) >> 0,
+ .func = (info & 0x0000ff00) >> 8,
+ .log[0] = (info1 & 0x30) >> 4,
+ .log[1] = (info1 & 0xc0) >> 6,
+ .param = !!(info & 0x80000000),
+ };
+ }
+ }
+
+ return data;
+}
+
+u16
+dcb_gpio_match(struct nvkm_bios *bios, int idx, u8 func, u8 line,
+ u8 *ver, u8 *len, struct dcb_gpio_func *gpio)
+{
+ u8 hdr, cnt, i = 0;
+ u16 data;
+
+ while ((data = dcb_gpio_parse(bios, idx, i++, ver, len, gpio))) {
+ if ((line == 0xff || line == gpio->line) &&
+ (func == 0xff || func == gpio->func))
+ return data;
+ }
+
+ /* DCB 2.2, fixed TVDAC GPIO data */
+ if ((data = dcb_table(bios, ver, &hdr, &cnt, len))) {
+ if (*ver >= 0x22 && *ver < 0x30 && func == DCB_GPIO_TVDAC0) {
+ u8 conf = nv_ro08(bios, data - 5);
+ u8 addr = nv_ro08(bios, data - 4);
+ if (conf & 0x01) {
+ *gpio = (struct dcb_gpio_func) {
+ .func = DCB_GPIO_TVDAC0,
+ .line = addr >> 4,
+ .log[0] = !!(conf & 0x02),
+ .log[1] = !(conf & 0x02),
+ };
+ *ver = 0x00;
+ return data;
+ }
+ }
+ }
+
+ return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
new file mode 100644
index 000000000000..d1a89b2bd5c1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/i2c.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/i2c.h>
+
+u16
+dcb_i2c_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u16 i2c = 0x0000;
+ u16 dcb = dcb_table(bios, ver, hdr, cnt, len);
+ if (dcb) {
+ if (*ver >= 0x15)
+ i2c = nv_ro16(bios, dcb + 2);
+ if (*ver >= 0x30)
+ i2c = nv_ro16(bios, dcb + 4);
+ }
+
+ if (i2c && *ver >= 0x42) {
+ nv_warn(bios, "ccb %02x not supported\n", *ver);
+ return 0x0000;
+ }
+
+ if (i2c && *ver >= 0x30) {
+ *ver = nv_ro08(bios, i2c + 0);
+ *hdr = nv_ro08(bios, i2c + 1);
+ *cnt = nv_ro08(bios, i2c + 2);
+ *len = nv_ro08(bios, i2c + 3);
+ } else {
+ *ver = *ver; /* use DCB version */
+ *hdr = 0;
+ *cnt = 16;
+ *len = 4;
+ }
+
+ return i2c;
+}
+
+u16
+dcb_i2c_entry(struct nvkm_bios *bios, u8 idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u16 i2c = dcb_i2c_table(bios, ver, &hdr, &cnt, len);
+ if (i2c && idx < cnt)
+ return i2c + hdr + (idx * *len);
+ return 0x0000;
+}
+
+int
+dcb_i2c_parse(struct nvkm_bios *bios, u8 idx, struct dcb_i2c_entry *info)
+{
+ u8 ver, len;
+ u16 ent = dcb_i2c_entry(bios, idx, &ver, &len);
+ if (ent) {
+ if (ver >= 0x41) {
+ if (!(nv_ro32(bios, ent) & 0x80000000))
+ info->type = DCB_I2C_UNUSED;
+ else
+ info->type = DCB_I2C_PMGR;
+ } else
+ if (ver >= 0x30) {
+ info->type = nv_ro08(bios, ent + 0x03);
+ } else {
+ info->type = nv_ro08(bios, ent + 0x03) & 0x07;
+ if (info->type == 0x07)
+ info->type = DCB_I2C_UNUSED;
+ }
+
+ info->drive = DCB_I2C_UNUSED;
+ info->sense = DCB_I2C_UNUSED;
+ info->share = DCB_I2C_UNUSED;
+ info->auxch = DCB_I2C_UNUSED;
+
+ switch (info->type) {
+ case DCB_I2C_NV04_BIT:
+ info->drive = nv_ro08(bios, ent + 0);
+ info->sense = nv_ro08(bios, ent + 1);
+ return 0;
+ case DCB_I2C_NV4E_BIT:
+ info->drive = nv_ro08(bios, ent + 1);
+ return 0;
+ case DCB_I2C_NVIO_BIT:
+ info->drive = nv_ro08(bios, ent + 0) & 0x0f;
+ if (nv_ro08(bios, ent + 1) & 0x01)
+ info->share = nv_ro08(bios, ent + 1) >> 1;
+ return 0;
+ case DCB_I2C_NVIO_AUX:
+ info->auxch = nv_ro08(bios, ent + 0) & 0x0f;
+ if (nv_ro08(bios, ent + 1) & 0x01)
+ info->share = info->auxch;
+ return 0;
+ case DCB_I2C_PMGR:
+ info->drive = (nv_ro16(bios, ent + 0) & 0x01f) >> 0;
+ if (info->drive == 0x1f)
+ info->drive = DCB_I2C_UNUSED;
+ info->auxch = (nv_ro16(bios, ent + 0) & 0x3e0) >> 5;
+ if (info->auxch == 0x1f)
+ info->auxch = DCB_I2C_UNUSED;
+ info->share = info->auxch;
+ return 0;
+ case DCB_I2C_UNUSED:
+ return 0;
+ default:
+ nv_warn(bios, "unknown i2c type %d\n", info->type);
+ info->type = DCB_I2C_UNUSED;
+ return 0;
+ }
+ }
+
+ if (bios->bmp_offset && idx < 2) {
+ /* BMP (from v4.0 has i2c info in the structure, it's in a
+ * fixed location on earlier VBIOS
+ */
+ if (nv_ro08(bios, bios->bmp_offset + 5) < 4)
+ ent = 0x0048;
+ else
+ ent = 0x0036 + bios->bmp_offset;
+
+ if (idx == 0) {
+ info->drive = nv_ro08(bios, ent + 4);
+ if (!info->drive) info->drive = 0x3f;
+ info->sense = nv_ro08(bios, ent + 5);
+ if (!info->sense) info->sense = 0x3e;
+ } else
+ if (idx == 1) {
+ info->drive = nv_ro08(bios, ent + 6);
+ if (!info->drive) info->drive = 0x37;
+ info->sense = nv_ro08(bios, ent + 7);
+ if (!info->sense) info->sense = 0x36;
+ }
+
+ info->type = DCB_I2C_NV04_BIT;
+ info->share = DCB_I2C_UNUSED;
+ return 0;
+ }
+
+ return -ENOENT;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
new file mode 100644
index 000000000000..1815540a0e8b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/image.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/image.h>
+#include <subdev/bios/pcir.h>
+#include <subdev/bios/npde.h>
+
+static bool
+nvbios_imagen(struct nvkm_bios *bios, struct nvbios_image *image)
+{
+ struct nvbios_pcirT pcir;
+ struct nvbios_npdeT npde;
+ u8 ver;
+ u16 hdr;
+ u32 data;
+
+ switch ((data = nv_ro16(bios, image->base + 0x00))) {
+ case 0xaa55:
+ case 0xbb77:
+ case 0x4e56: /* NV */
+ break;
+ default:
+ nv_debug(bios, "%08x: ROM signature (%04x) unknown\n",
+ image->base, data);
+ return false;
+ }
+
+ if (!(data = nvbios_pcirTp(bios, image->base, &ver, &hdr, &pcir)))
+ return false;
+ image->size = pcir.image_size;
+ image->type = pcir.image_type;
+ image->last = pcir.last;
+
+ if (image->type != 0x70) {
+ if (!(data = nvbios_npdeTp(bios, image->base, &npde)))
+ return true;
+ image->size = npde.image_size;
+ image->last = npde.last;
+ } else {
+ image->last = true;
+ }
+
+ return true;
+}
+
+bool
+nvbios_image(struct nvkm_bios *bios, int idx, struct nvbios_image *image)
+{
+ memset(image, 0x00, sizeof(*image));
+ do {
+ image->base += image->size;
+ if (image->last || !nvbios_imagen(bios, image))
+ return false;
+ } while(idx--);
+ return true;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
new file mode 100644
index 000000000000..f67cdae1e90a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/init.c
@@ -0,0 +1,2247 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/conn.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/dp.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/ramcfg.h>
+
+#include <core/device.h>
+#include <subdev/devinit.h>
+#include <subdev/gpio.h>
+#include <subdev/i2c.h>
+#include <subdev/vga.h>
+
+#define bioslog(lvl, fmt, args...) do { \
+ nv_printk(init->bios, lvl, "0x%04x[%c]: "fmt, init->offset, \
+ init_exec(init) ? '0' + (init->nested - 1) : ' ', ##args); \
+} while(0)
+#define cont(fmt, args...) do { \
+ if (nv_subdev(init->bios)->debug >= NV_DBG_TRACE) \
+ printk(fmt, ##args); \
+} while(0)
+#define trace(fmt, args...) bioslog(TRACE, fmt, ##args)
+#define warn(fmt, args...) bioslog(WARN, fmt, ##args)
+#define error(fmt, args...) bioslog(ERROR, fmt, ##args)
+
+/******************************************************************************
+ * init parser control flow helpers
+ *****************************************************************************/
+
+static inline bool
+init_exec(struct nvbios_init *init)
+{
+ return (init->execute == 1) || ((init->execute & 5) == 5);
+}
+
+static inline void
+init_exec_set(struct nvbios_init *init, bool exec)
+{
+ if (exec) init->execute &= 0xfd;
+ else init->execute |= 0x02;
+}
+
+static inline void
+init_exec_inv(struct nvbios_init *init)
+{
+ init->execute ^= 0x02;
+}
+
+static inline void
+init_exec_force(struct nvbios_init *init, bool exec)
+{
+ if (exec) init->execute |= 0x04;
+ else init->execute &= 0xfb;
+}
+
+/******************************************************************************
+ * init parser wrappers for normal register/i2c/whatever accessors
+ *****************************************************************************/
+
+static inline int
+init_or(struct nvbios_init *init)
+{
+ if (init_exec(init)) {
+ if (init->outp)
+ return ffs(init->outp->or) - 1;
+ error("script needs OR!!\n");
+ }
+ return 0;
+}
+
+static inline int
+init_link(struct nvbios_init *init)
+{
+ if (init_exec(init)) {
+ if (init->outp)
+ return !(init->outp->sorconf.link & 1);
+ error("script needs OR link\n");
+ }
+ return 0;
+}
+
+static inline int
+init_crtc(struct nvbios_init *init)
+{
+ if (init_exec(init)) {
+ if (init->crtc >= 0)
+ return init->crtc;
+ error("script needs crtc\n");
+ }
+ return 0;
+}
+
+static u8
+init_conn(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ struct nvbios_connE connE;
+ u8 ver, hdr;
+ u32 conn;
+
+ if (init_exec(init)) {
+ if (init->outp) {
+ conn = init->outp->connector;
+ conn = nvbios_connEp(bios, conn, &ver, &hdr, &connE);
+ if (conn)
+ return connE.type;
+ }
+
+ error("script needs connector type\n");
+ }
+
+ return 0xff;
+}
+
+static inline u32
+init_nvreg(struct nvbios_init *init, u32 reg)
+{
+ struct nvkm_devinit *devinit = nvkm_devinit(init->bios);
+
+ /* C51 (at least) sometimes has the lower bits set which the VBIOS
+ * interprets to mean that access needs to go through certain IO
+ * ports instead. The NVIDIA binary driver has been seen to access
+ * these through the NV register address, so lets assume we can
+ * do the same
+ */
+ reg &= ~0x00000003;
+
+ /* GF8+ display scripts need register addresses mangled a bit to
+ * select a specific CRTC/OR
+ */
+ if (nv_device(init->bios)->card_type >= NV_50) {
+ if (reg & 0x80000000) {
+ reg += init_crtc(init) * 0x800;
+ reg &= ~0x80000000;
+ }
+
+ if (reg & 0x40000000) {
+ reg += init_or(init) * 0x800;
+ reg &= ~0x40000000;
+ if (reg & 0x20000000) {
+ reg += init_link(init) * 0x80;
+ reg &= ~0x20000000;
+ }
+ }
+ }
+
+ if (reg & ~0x00fffffc)
+ warn("unknown bits in register 0x%08x\n", reg);
+
+ if (devinit->mmio)
+ reg = devinit->mmio(devinit, reg);
+ return reg;
+}
+
+static u32
+init_rd32(struct nvbios_init *init, u32 reg)
+{
+ reg = init_nvreg(init, reg);
+ if (reg != ~0 && init_exec(init))
+ return nv_rd32(init->subdev, reg);
+ return 0x00000000;
+}
+
+static void
+init_wr32(struct nvbios_init *init, u32 reg, u32 val)
+{
+ reg = init_nvreg(init, reg);
+ if (reg != ~0 && init_exec(init))
+ nv_wr32(init->subdev, reg, val);
+}
+
+static u32
+init_mask(struct nvbios_init *init, u32 reg, u32 mask, u32 val)
+{
+ reg = init_nvreg(init, reg);
+ if (reg != ~0 && init_exec(init)) {
+ u32 tmp = nv_rd32(init->subdev, reg);
+ nv_wr32(init->subdev, reg, (tmp & ~mask) | val);
+ return tmp;
+ }
+ return 0x00000000;
+}
+
+static u8
+init_rdport(struct nvbios_init *init, u16 port)
+{
+ if (init_exec(init))
+ return nv_rdport(init->subdev, init->crtc, port);
+ return 0x00;
+}
+
+static void
+init_wrport(struct nvbios_init *init, u16 port, u8 value)
+{
+ if (init_exec(init))
+ nv_wrport(init->subdev, init->crtc, port, value);
+}
+
+static u8
+init_rdvgai(struct nvbios_init *init, u16 port, u8 index)
+{
+ struct nvkm_subdev *subdev = init->subdev;
+ if (init_exec(init)) {
+ int head = init->crtc < 0 ? 0 : init->crtc;
+ return nv_rdvgai(subdev, head, port, index);
+ }
+ return 0x00;
+}
+
+static void
+init_wrvgai(struct nvbios_init *init, u16 port, u8 index, u8 value)
+{
+ /* force head 0 for updates to cr44, it only exists on first head */
+ if (nv_device(init->subdev)->card_type < NV_50) {
+ if (port == 0x03d4 && index == 0x44)
+ init->crtc = 0;
+ }
+
+ if (init_exec(init)) {
+ int head = init->crtc < 0 ? 0 : init->crtc;
+ nv_wrvgai(init->subdev, head, port, index, value);
+ }
+
+ /* select head 1 if cr44 write selected it */
+ if (nv_device(init->subdev)->card_type < NV_50) {
+ if (port == 0x03d4 && index == 0x44 && value == 3)
+ init->crtc = 1;
+ }
+}
+
+static struct nvkm_i2c_port *
+init_i2c(struct nvbios_init *init, int index)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(init->bios);
+
+ if (index == 0xff) {
+ index = NV_I2C_DEFAULT(0);
+ if (init->outp && init->outp->i2c_upper_default)
+ index = NV_I2C_DEFAULT(1);
+ } else
+ if (index < 0) {
+ if (!init->outp) {
+ if (init_exec(init))
+ error("script needs output for i2c\n");
+ return NULL;
+ }
+
+ if (index == -2 && init->outp->location) {
+ index = NV_I2C_TYPE_EXTAUX(init->outp->extdev);
+ return i2c->find_type(i2c, index);
+ }
+
+ index = init->outp->i2c_index;
+ if (init->outp->type == DCB_OUTPUT_DP)
+ index += NV_I2C_AUX(0);
+ }
+
+ return i2c->find(i2c, index);
+}
+
+static int
+init_rdi2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg)
+{
+ struct nvkm_i2c_port *port = init_i2c(init, index);
+ if (port && init_exec(init))
+ return nv_rdi2cr(port, addr, reg);
+ return -ENODEV;
+}
+
+static int
+init_wri2cr(struct nvbios_init *init, u8 index, u8 addr, u8 reg, u8 val)
+{
+ struct nvkm_i2c_port *port = init_i2c(init, index);
+ if (port && init_exec(init))
+ return nv_wri2cr(port, addr, reg, val);
+ return -ENODEV;
+}
+
+static u8
+init_rdauxr(struct nvbios_init *init, u32 addr)
+{
+ struct nvkm_i2c_port *port = init_i2c(init, -2);
+ u8 data;
+
+ if (port && init_exec(init)) {
+ int ret = nv_rdaux(port, addr, &data, 1);
+ if (ret == 0)
+ return data;
+ trace("auxch read failed with %d\n", ret);
+ }
+
+ return 0x00;
+}
+
+static int
+init_wrauxr(struct nvbios_init *init, u32 addr, u8 data)
+{
+ struct nvkm_i2c_port *port = init_i2c(init, -2);
+ if (port && init_exec(init)) {
+ int ret = nv_wraux(port, addr, &data, 1);
+ if (ret)
+ trace("auxch write failed with %d\n", ret);
+ return ret;
+ }
+ return -ENODEV;
+}
+
+static void
+init_prog_pll(struct nvbios_init *init, u32 id, u32 freq)
+{
+ struct nvkm_devinit *devinit = nvkm_devinit(init->bios);
+ if (devinit->pll_set && init_exec(init)) {
+ int ret = devinit->pll_set(devinit, id, freq);
+ if (ret)
+ warn("failed to prog pll 0x%08x to %dkHz\n", id, freq);
+ }
+}
+
+/******************************************************************************
+ * parsing of bios structures that are required to execute init tables
+ *****************************************************************************/
+
+static u16
+init_table(struct nvkm_bios *bios, u16 *len)
+{
+ struct bit_entry bit_I;
+
+ if (!bit_entry(bios, 'I', &bit_I)) {
+ *len = bit_I.length;
+ return bit_I.offset;
+ }
+
+ if (bmp_version(bios) >= 0x0510) {
+ *len = 14;
+ return bios->bmp_offset + 75;
+ }
+
+ return 0x0000;
+}
+
+static u16
+init_table_(struct nvbios_init *init, u16 offset, const char *name)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 len, data = init_table(bios, &len);
+ if (data) {
+ if (len >= offset + 2) {
+ data = nv_ro16(bios, data + offset);
+ if (data)
+ return data;
+
+ warn("%s pointer invalid\n", name);
+ return 0x0000;
+ }
+
+ warn("init data too short for %s pointer", name);
+ return 0x0000;
+ }
+
+ warn("init data not found\n");
+ return 0x0000;
+}
+
+#define init_script_table(b) init_table_((b), 0x00, "script table")
+#define init_macro_index_table(b) init_table_((b), 0x02, "macro index table")
+#define init_macro_table(b) init_table_((b), 0x04, "macro table")
+#define init_condition_table(b) init_table_((b), 0x06, "condition table")
+#define init_io_condition_table(b) init_table_((b), 0x08, "io condition table")
+#define init_io_flag_condition_table(b) init_table_((b), 0x0a, "io flag conditon table")
+#define init_function_table(b) init_table_((b), 0x0c, "function table")
+#define init_xlat_table(b) init_table_((b), 0x10, "xlat table");
+
+static u16
+init_script(struct nvkm_bios *bios, int index)
+{
+ struct nvbios_init init = { .bios = bios };
+ u16 bmp_ver = bmp_version(bios), data;
+
+ if (bmp_ver && bmp_ver < 0x0510) {
+ if (index > 1 || bmp_ver < 0x0100)
+ return 0x0000;
+
+ data = bios->bmp_offset + (bmp_ver < 0x0200 ? 14 : 18);
+ return nv_ro16(bios, data + (index * 2));
+ }
+
+ data = init_script_table(&init);
+ if (data)
+ return nv_ro16(bios, data + (index * 2));
+
+ return 0x0000;
+}
+
+static u16
+init_unknown_script(struct nvkm_bios *bios)
+{
+ u16 len, data = init_table(bios, &len);
+ if (data && len >= 16)
+ return nv_ro16(bios, data + 14);
+ return 0x0000;
+}
+
+static u8
+init_ram_restrict_group_count(struct nvbios_init *init)
+{
+ return nvbios_ramcfg_count(init->bios);
+}
+
+static u8
+init_ram_restrict(struct nvbios_init *init)
+{
+ /* This appears to be the behaviour of the VBIOS parser, and *is*
+ * important to cache the NV_PEXTDEV_BOOT0 on later chipsets to
+ * avoid fucking up the memory controller (somehow) by reading it
+ * on every INIT_RAM_RESTRICT_ZM_GROUP opcode.
+ *
+ * Preserving the non-caching behaviour on earlier chipsets just
+ * in case *not* re-reading the strap causes similar breakage.
+ */
+ if (!init->ramcfg || init->bios->version.major < 0x70)
+ init->ramcfg = 0x80000000 | nvbios_ramcfg_index(init->subdev);
+ return (init->ramcfg & 0x7fffffff);
+}
+
+static u8
+init_xlat_(struct nvbios_init *init, u8 index, u8 offset)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 table = init_xlat_table(init);
+ if (table) {
+ u16 data = nv_ro16(bios, table + (index * 2));
+ if (data)
+ return nv_ro08(bios, data + offset);
+ warn("xlat table pointer %d invalid\n", index);
+ }
+ return 0x00;
+}
+
+/******************************************************************************
+ * utility functions used by various init opcode handlers
+ *****************************************************************************/
+
+static bool
+init_condition_met(struct nvbios_init *init, u8 cond)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 table = init_condition_table(init);
+ if (table) {
+ u32 reg = nv_ro32(bios, table + (cond * 12) + 0);
+ u32 msk = nv_ro32(bios, table + (cond * 12) + 4);
+ u32 val = nv_ro32(bios, table + (cond * 12) + 8);
+ trace("\t[0x%02x] (R[0x%06x] & 0x%08x) == 0x%08x\n",
+ cond, reg, msk, val);
+ return (init_rd32(init, reg) & msk) == val;
+ }
+ return false;
+}
+
+static bool
+init_io_condition_met(struct nvbios_init *init, u8 cond)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 table = init_io_condition_table(init);
+ if (table) {
+ u16 port = nv_ro16(bios, table + (cond * 5) + 0);
+ u8 index = nv_ro08(bios, table + (cond * 5) + 2);
+ u8 mask = nv_ro08(bios, table + (cond * 5) + 3);
+ u8 value = nv_ro08(bios, table + (cond * 5) + 4);
+ trace("\t[0x%02x] (0x%04x[0x%02x] & 0x%02x) == 0x%02x\n",
+ cond, port, index, mask, value);
+ return (init_rdvgai(init, port, index) & mask) == value;
+ }
+ return false;
+}
+
+static bool
+init_io_flag_condition_met(struct nvbios_init *init, u8 cond)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 table = init_io_flag_condition_table(init);
+ if (table) {
+ u16 port = nv_ro16(bios, table + (cond * 9) + 0);
+ u8 index = nv_ro08(bios, table + (cond * 9) + 2);
+ u8 mask = nv_ro08(bios, table + (cond * 9) + 3);
+ u8 shift = nv_ro08(bios, table + (cond * 9) + 4);
+ u16 data = nv_ro16(bios, table + (cond * 9) + 5);
+ u8 dmask = nv_ro08(bios, table + (cond * 9) + 7);
+ u8 value = nv_ro08(bios, table + (cond * 9) + 8);
+ u8 ioval = (init_rdvgai(init, port, index) & mask) >> shift;
+ return (nv_ro08(bios, data + ioval) & dmask) == value;
+ }
+ return false;
+}
+
+static inline u32
+init_shift(u32 data, u8 shift)
+{
+ if (shift < 0x80)
+ return data >> shift;
+ return data << (0x100 - shift);
+}
+
+static u32
+init_tmds_reg(struct nvbios_init *init, u8 tmds)
+{
+ /* For mlv < 0x80, it is an index into a table of TMDS base addresses.
+ * For mlv == 0x80 use the "or" value of the dcb_entry indexed by
+ * CR58 for CR57 = 0 to index a table of offsets to the basic
+ * 0x6808b0 address.
+ * For mlv == 0x81 use the "or" value of the dcb_entry indexed by
+ * CR58 for CR57 = 0 to index a table of offsets to the basic
+ * 0x6808b0 address, and then flip the offset by 8.
+ */
+ const int pramdac_offset[13] = {
+ 0, 0, 0x8, 0, 0x2000, 0, 0, 0, 0x2008, 0, 0, 0, 0x2000 };
+ const u32 pramdac_table[4] = {
+ 0x6808b0, 0x6808b8, 0x6828b0, 0x6828b8 };
+
+ if (tmds >= 0x80) {
+ if (init->outp) {
+ u32 dacoffset = pramdac_offset[init->outp->or];
+ if (tmds == 0x81)
+ dacoffset ^= 8;
+ return 0x6808b0 + dacoffset;
+ }
+
+ if (init_exec(init))
+ error("tmds opcodes need dcb\n");
+ } else {
+ if (tmds < ARRAY_SIZE(pramdac_table))
+ return pramdac_table[tmds];
+
+ error("tmds selector 0x%02x unknown\n", tmds);
+ }
+
+ return 0;
+}
+
+/******************************************************************************
+ * init opcode handlers
+ *****************************************************************************/
+
+/**
+ * init_reserved - stub for various unknown/unused single-byte opcodes
+ *
+ */
+static void
+init_reserved(struct nvbios_init *init)
+{
+ u8 opcode = nv_ro08(init->bios, init->offset);
+ u8 length, i;
+
+ switch (opcode) {
+ case 0xaa:
+ length = 4;
+ break;
+ default:
+ length = 1;
+ break;
+ }
+
+ trace("RESERVED 0x%02x\t", opcode);
+ for (i = 1; i < length; i++)
+ cont(" 0x%02x", nv_ro08(init->bios, init->offset + i));
+ cont("\n");
+ init->offset += length;
+}
+
+/**
+ * INIT_DONE - opcode 0x71
+ *
+ */
+static void
+init_done(struct nvbios_init *init)
+{
+ trace("DONE\n");
+ init->offset = 0x0000;
+}
+
+/**
+ * INIT_IO_RESTRICT_PROG - opcode 0x32
+ *
+ */
+static void
+init_io_restrict_prog(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 port = nv_ro16(bios, init->offset + 1);
+ u8 index = nv_ro08(bios, init->offset + 3);
+ u8 mask = nv_ro08(bios, init->offset + 4);
+ u8 shift = nv_ro08(bios, init->offset + 5);
+ u8 count = nv_ro08(bios, init->offset + 6);
+ u32 reg = nv_ro32(bios, init->offset + 7);
+ u8 conf, i;
+
+ trace("IO_RESTRICT_PROG\tR[0x%06x] = "
+ "((0x%04x[0x%02x] & 0x%02x) >> %d) [{\n",
+ reg, port, index, mask, shift);
+ init->offset += 11;
+
+ conf = (init_rdvgai(init, port, index) & mask) >> shift;
+ for (i = 0; i < count; i++) {
+ u32 data = nv_ro32(bios, init->offset);
+
+ if (i == conf) {
+ trace("\t0x%08x *\n", data);
+ init_wr32(init, reg, data);
+ } else {
+ trace("\t0x%08x\n", data);
+ }
+
+ init->offset += 4;
+ }
+ trace("}]\n");
+}
+
+/**
+ * INIT_REPEAT - opcode 0x33
+ *
+ */
+static void
+init_repeat(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 count = nv_ro08(bios, init->offset + 1);
+ u16 repeat = init->repeat;
+
+ trace("REPEAT\t0x%02x\n", count);
+ init->offset += 2;
+
+ init->repeat = init->offset;
+ init->repend = init->offset;
+ while (count--) {
+ init->offset = init->repeat;
+ nvbios_exec(init);
+ if (count)
+ trace("REPEAT\t0x%02x\n", count);
+ }
+ init->offset = init->repend;
+ init->repeat = repeat;
+}
+
+/**
+ * INIT_IO_RESTRICT_PLL - opcode 0x34
+ *
+ */
+static void
+init_io_restrict_pll(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 port = nv_ro16(bios, init->offset + 1);
+ u8 index = nv_ro08(bios, init->offset + 3);
+ u8 mask = nv_ro08(bios, init->offset + 4);
+ u8 shift = nv_ro08(bios, init->offset + 5);
+ s8 iofc = nv_ro08(bios, init->offset + 6);
+ u8 count = nv_ro08(bios, init->offset + 7);
+ u32 reg = nv_ro32(bios, init->offset + 8);
+ u8 conf, i;
+
+ trace("IO_RESTRICT_PLL\tR[0x%06x] =PLL= "
+ "((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) IOFCOND 0x%02x [{\n",
+ reg, port, index, mask, shift, iofc);
+ init->offset += 12;
+
+ conf = (init_rdvgai(init, port, index) & mask) >> shift;
+ for (i = 0; i < count; i++) {
+ u32 freq = nv_ro16(bios, init->offset) * 10;
+
+ if (i == conf) {
+ trace("\t%dkHz *\n", freq);
+ if (iofc > 0 && init_io_flag_condition_met(init, iofc))
+ freq *= 2;
+ init_prog_pll(init, reg, freq);
+ } else {
+ trace("\t%dkHz\n", freq);
+ }
+
+ init->offset += 2;
+ }
+ trace("}]\n");
+}
+
+/**
+ * INIT_END_REPEAT - opcode 0x36
+ *
+ */
+static void
+init_end_repeat(struct nvbios_init *init)
+{
+ trace("END_REPEAT\n");
+ init->offset += 1;
+
+ if (init->repeat) {
+ init->repend = init->offset;
+ init->offset = 0;
+ }
+}
+
+/**
+ * INIT_COPY - opcode 0x37
+ *
+ */
+static void
+init_copy(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u8 shift = nv_ro08(bios, init->offset + 5);
+ u8 smask = nv_ro08(bios, init->offset + 6);
+ u16 port = nv_ro16(bios, init->offset + 7);
+ u8 index = nv_ro08(bios, init->offset + 9);
+ u8 mask = nv_ro08(bios, init->offset + 10);
+ u8 data;
+
+ trace("COPY\t0x%04x[0x%02x] &= 0x%02x |= "
+ "((R[0x%06x] %s 0x%02x) & 0x%02x)\n",
+ port, index, mask, reg, (shift & 0x80) ? "<<" : ">>",
+ (shift & 0x80) ? (0x100 - shift) : shift, smask);
+ init->offset += 11;
+
+ data = init_rdvgai(init, port, index) & mask;
+ data |= init_shift(init_rd32(init, reg), shift) & smask;
+ init_wrvgai(init, port, index, data);
+}
+
+/**
+ * INIT_NOT - opcode 0x38
+ *
+ */
+static void
+init_not(struct nvbios_init *init)
+{
+ trace("NOT\n");
+ init->offset += 1;
+ init_exec_inv(init);
+}
+
+/**
+ * INIT_IO_FLAG_CONDITION - opcode 0x39
+ *
+ */
+static void
+init_io_flag_condition(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 cond = nv_ro08(bios, init->offset + 1);
+
+ trace("IO_FLAG_CONDITION\t0x%02x\n", cond);
+ init->offset += 2;
+
+ if (!init_io_flag_condition_met(init, cond))
+ init_exec_set(init, false);
+}
+
+/**
+ * INIT_DP_CONDITION - opcode 0x3a
+ *
+ */
+static void
+init_dp_condition(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ struct nvbios_dpout info;
+ u8 cond = nv_ro08(bios, init->offset + 1);
+ u8 unkn = nv_ro08(bios, init->offset + 2);
+ u8 ver, hdr, cnt, len;
+ u16 data;
+
+ trace("DP_CONDITION\t0x%02x 0x%02x\n", cond, unkn);
+ init->offset += 3;
+
+ switch (cond) {
+ case 0:
+ if (init_conn(init) != DCB_CONNECTOR_eDP)
+ init_exec_set(init, false);
+ break;
+ case 1:
+ case 2:
+ if ( init->outp &&
+ (data = nvbios_dpout_match(bios, DCB_OUTPUT_DP,
+ (init->outp->or << 0) |
+ (init->outp->sorconf.link << 6),
+ &ver, &hdr, &cnt, &len, &info)))
+ {
+ if (!(info.flags & cond))
+ init_exec_set(init, false);
+ break;
+ }
+
+ if (init_exec(init))
+ warn("script needs dp output table data\n");
+ break;
+ case 5:
+ if (!(init_rdauxr(init, 0x0d) & 1))
+ init_exec_set(init, false);
+ break;
+ default:
+ warn("unknown dp condition 0x%02x\n", cond);
+ break;
+ }
+}
+
+/**
+ * INIT_IO_MASK_OR - opcode 0x3b
+ *
+ */
+static void
+init_io_mask_or(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 or = init_or(init);
+ u8 data;
+
+ trace("IO_MASK_OR\t0x03d4[0x%02x] &= ~(1 << 0x%02x)\n", index, or);
+ init->offset += 2;
+
+ data = init_rdvgai(init, 0x03d4, index);
+ init_wrvgai(init, 0x03d4, index, data &= ~(1 << or));
+}
+
+/**
+ * INIT_IO_OR - opcode 0x3c
+ *
+ */
+static void
+init_io_or(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 or = init_or(init);
+ u8 data;
+
+ trace("IO_OR\t0x03d4[0x%02x] |= (1 << 0x%02x)\n", index, or);
+ init->offset += 2;
+
+ data = init_rdvgai(init, 0x03d4, index);
+ init_wrvgai(init, 0x03d4, index, data | (1 << or));
+}
+
+/**
+ * INIT_ANDN_REG - opcode 0x47
+ *
+ */
+static void
+init_andn_reg(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u32 mask = nv_ro32(bios, init->offset + 5);
+
+ trace("ANDN_REG\tR[0x%06x] &= ~0x%08x\n", reg, mask);
+ init->offset += 9;
+
+ init_mask(init, reg, mask, 0);
+}
+
+/**
+ * INIT_OR_REG - opcode 0x48
+ *
+ */
+static void
+init_or_reg(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u32 mask = nv_ro32(bios, init->offset + 5);
+
+ trace("OR_REG\tR[0x%06x] |= 0x%08x\n", reg, mask);
+ init->offset += 9;
+
+ init_mask(init, reg, 0, mask);
+}
+
+/**
+ * INIT_INDEX_ADDRESS_LATCHED - opcode 0x49
+ *
+ */
+static void
+init_idx_addr_latched(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 creg = nv_ro32(bios, init->offset + 1);
+ u32 dreg = nv_ro32(bios, init->offset + 5);
+ u32 mask = nv_ro32(bios, init->offset + 9);
+ u32 data = nv_ro32(bios, init->offset + 13);
+ u8 count = nv_ro08(bios, init->offset + 17);
+
+ trace("INDEX_ADDRESS_LATCHED\tR[0x%06x] : R[0x%06x]\n", creg, dreg);
+ trace("\tCTRL &= 0x%08x |= 0x%08x\n", mask, data);
+ init->offset += 18;
+
+ while (count--) {
+ u8 iaddr = nv_ro08(bios, init->offset + 0);
+ u8 idata = nv_ro08(bios, init->offset + 1);
+
+ trace("\t[0x%02x] = 0x%02x\n", iaddr, idata);
+ init->offset += 2;
+
+ init_wr32(init, dreg, idata);
+ init_mask(init, creg, ~mask, data | iaddr);
+ }
+}
+
+/**
+ * INIT_IO_RESTRICT_PLL2 - opcode 0x4a
+ *
+ */
+static void
+init_io_restrict_pll2(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 port = nv_ro16(bios, init->offset + 1);
+ u8 index = nv_ro08(bios, init->offset + 3);
+ u8 mask = nv_ro08(bios, init->offset + 4);
+ u8 shift = nv_ro08(bios, init->offset + 5);
+ u8 count = nv_ro08(bios, init->offset + 6);
+ u32 reg = nv_ro32(bios, init->offset + 7);
+ u8 conf, i;
+
+ trace("IO_RESTRICT_PLL2\t"
+ "R[0x%06x] =PLL= ((0x%04x[0x%02x] & 0x%02x) >> 0x%02x) [{\n",
+ reg, port, index, mask, shift);
+ init->offset += 11;
+
+ conf = (init_rdvgai(init, port, index) & mask) >> shift;
+ for (i = 0; i < count; i++) {
+ u32 freq = nv_ro32(bios, init->offset);
+ if (i == conf) {
+ trace("\t%dkHz *\n", freq);
+ init_prog_pll(init, reg, freq);
+ } else {
+ trace("\t%dkHz\n", freq);
+ }
+ init->offset += 4;
+ }
+ trace("}]\n");
+}
+
+/**
+ * INIT_PLL2 - opcode 0x4b
+ *
+ */
+static void
+init_pll2(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u32 freq = nv_ro32(bios, init->offset + 5);
+
+ trace("PLL2\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
+ init->offset += 9;
+
+ init_prog_pll(init, reg, freq);
+}
+
+/**
+ * INIT_I2C_BYTE - opcode 0x4c
+ *
+ */
+static void
+init_i2c_byte(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
+ u8 count = nv_ro08(bios, init->offset + 3);
+
+ trace("I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
+ init->offset += 4;
+
+ while (count--) {
+ u8 reg = nv_ro08(bios, init->offset + 0);
+ u8 mask = nv_ro08(bios, init->offset + 1);
+ u8 data = nv_ro08(bios, init->offset + 2);
+ int val;
+
+ trace("\t[0x%02x] &= 0x%02x |= 0x%02x\n", reg, mask, data);
+ init->offset += 3;
+
+ val = init_rdi2cr(init, index, addr, reg);
+ if (val < 0)
+ continue;
+ init_wri2cr(init, index, addr, reg, (val & mask) | data);
+ }
+}
+
+/**
+ * INIT_ZM_I2C_BYTE - opcode 0x4d
+ *
+ */
+static void
+init_zm_i2c_byte(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
+ u8 count = nv_ro08(bios, init->offset + 3);
+
+ trace("ZM_I2C_BYTE\tI2C[0x%02x][0x%02x]\n", index, addr);
+ init->offset += 4;
+
+ while (count--) {
+ u8 reg = nv_ro08(bios, init->offset + 0);
+ u8 data = nv_ro08(bios, init->offset + 1);
+
+ trace("\t[0x%02x] = 0x%02x\n", reg, data);
+ init->offset += 2;
+
+ init_wri2cr(init, index, addr, reg, data);
+ }
+}
+
+/**
+ * INIT_ZM_I2C - opcode 0x4e
+ *
+ */
+static void
+init_zm_i2c(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
+ u8 count = nv_ro08(bios, init->offset + 3);
+ u8 data[256], i;
+
+ trace("ZM_I2C\tI2C[0x%02x][0x%02x]\n", index, addr);
+ init->offset += 4;
+
+ for (i = 0; i < count; i++) {
+ data[i] = nv_ro08(bios, init->offset);
+ trace("\t0x%02x\n", data[i]);
+ init->offset++;
+ }
+
+ if (init_exec(init)) {
+ struct nvkm_i2c_port *port = init_i2c(init, index);
+ struct i2c_msg msg = {
+ .addr = addr, .flags = 0, .len = count, .buf = data,
+ };
+ int ret;
+
+ if (port && (ret = i2c_transfer(&port->adapter, &msg, 1)) != 1)
+ warn("i2c wr failed, %d\n", ret);
+ }
+}
+
+/**
+ * INIT_TMDS - opcode 0x4f
+ *
+ */
+static void
+init_tmds(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 tmds = nv_ro08(bios, init->offset + 1);
+ u8 addr = nv_ro08(bios, init->offset + 2);
+ u8 mask = nv_ro08(bios, init->offset + 3);
+ u8 data = nv_ro08(bios, init->offset + 4);
+ u32 reg = init_tmds_reg(init, tmds);
+
+ trace("TMDS\tT[0x%02x][0x%02x] &= 0x%02x |= 0x%02x\n",
+ tmds, addr, mask, data);
+ init->offset += 5;
+
+ if (reg == 0)
+ return;
+
+ init_wr32(init, reg + 0, addr | 0x00010000);
+ init_wr32(init, reg + 4, data | (init_rd32(init, reg + 4) & mask));
+ init_wr32(init, reg + 0, addr);
+}
+
+/**
+ * INIT_ZM_TMDS_GROUP - opcode 0x50
+ *
+ */
+static void
+init_zm_tmds_group(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 tmds = nv_ro08(bios, init->offset + 1);
+ u8 count = nv_ro08(bios, init->offset + 2);
+ u32 reg = init_tmds_reg(init, tmds);
+
+ trace("TMDS_ZM_GROUP\tT[0x%02x]\n", tmds);
+ init->offset += 3;
+
+ while (count--) {
+ u8 addr = nv_ro08(bios, init->offset + 0);
+ u8 data = nv_ro08(bios, init->offset + 1);
+
+ trace("\t[0x%02x] = 0x%02x\n", addr, data);
+ init->offset += 2;
+
+ init_wr32(init, reg + 4, data);
+ init_wr32(init, reg + 0, addr);
+ }
+}
+
+/**
+ * INIT_CR_INDEX_ADDRESS_LATCHED - opcode 0x51
+ *
+ */
+static void
+init_cr_idx_adr_latch(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 addr0 = nv_ro08(bios, init->offset + 1);
+ u8 addr1 = nv_ro08(bios, init->offset + 2);
+ u8 base = nv_ro08(bios, init->offset + 3);
+ u8 count = nv_ro08(bios, init->offset + 4);
+ u8 save0;
+
+ trace("CR_INDEX_ADDR C[%02x] C[%02x]\n", addr0, addr1);
+ init->offset += 5;
+
+ save0 = init_rdvgai(init, 0x03d4, addr0);
+ while (count--) {
+ u8 data = nv_ro08(bios, init->offset);
+
+ trace("\t\t[0x%02x] = 0x%02x\n", base, data);
+ init->offset += 1;
+
+ init_wrvgai(init, 0x03d4, addr0, base++);
+ init_wrvgai(init, 0x03d4, addr1, data);
+ }
+ init_wrvgai(init, 0x03d4, addr0, save0);
+}
+
+/**
+ * INIT_CR - opcode 0x52
+ *
+ */
+static void
+init_cr(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 addr = nv_ro08(bios, init->offset + 1);
+ u8 mask = nv_ro08(bios, init->offset + 2);
+ u8 data = nv_ro08(bios, init->offset + 3);
+ u8 val;
+
+ trace("CR\t\tC[0x%02x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
+ init->offset += 4;
+
+ val = init_rdvgai(init, 0x03d4, addr) & mask;
+ init_wrvgai(init, 0x03d4, addr, val | data);
+}
+
+/**
+ * INIT_ZM_CR - opcode 0x53
+ *
+ */
+static void
+init_zm_cr(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 addr = nv_ro08(bios, init->offset + 1);
+ u8 data = nv_ro08(bios, init->offset + 2);
+
+ trace("ZM_CR\tC[0x%02x] = 0x%02x\n", addr, data);
+ init->offset += 3;
+
+ init_wrvgai(init, 0x03d4, addr, data);
+}
+
+/**
+ * INIT_ZM_CR_GROUP - opcode 0x54
+ *
+ */
+static void
+init_zm_cr_group(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 count = nv_ro08(bios, init->offset + 1);
+
+ trace("ZM_CR_GROUP\n");
+ init->offset += 2;
+
+ while (count--) {
+ u8 addr = nv_ro08(bios, init->offset + 0);
+ u8 data = nv_ro08(bios, init->offset + 1);
+
+ trace("\t\tC[0x%02x] = 0x%02x\n", addr, data);
+ init->offset += 2;
+
+ init_wrvgai(init, 0x03d4, addr, data);
+ }
+}
+
+/**
+ * INIT_CONDITION_TIME - opcode 0x56
+ *
+ */
+static void
+init_condition_time(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 cond = nv_ro08(bios, init->offset + 1);
+ u8 retry = nv_ro08(bios, init->offset + 2);
+ u8 wait = min((u16)retry * 50, 100);
+
+ trace("CONDITION_TIME\t0x%02x 0x%02x\n", cond, retry);
+ init->offset += 3;
+
+ if (!init_exec(init))
+ return;
+
+ while (wait--) {
+ if (init_condition_met(init, cond))
+ return;
+ mdelay(20);
+ }
+
+ init_exec_set(init, false);
+}
+
+/**
+ * INIT_LTIME - opcode 0x57
+ *
+ */
+static void
+init_ltime(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 msec = nv_ro16(bios, init->offset + 1);
+
+ trace("LTIME\t0x%04x\n", msec);
+ init->offset += 3;
+
+ if (init_exec(init))
+ mdelay(msec);
+}
+
+/**
+ * INIT_ZM_REG_SEQUENCE - opcode 0x58
+ *
+ */
+static void
+init_zm_reg_sequence(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 base = nv_ro32(bios, init->offset + 1);
+ u8 count = nv_ro08(bios, init->offset + 5);
+
+ trace("ZM_REG_SEQUENCE\t0x%02x\n", count);
+ init->offset += 6;
+
+ while (count--) {
+ u32 data = nv_ro32(bios, init->offset);
+
+ trace("\t\tR[0x%06x] = 0x%08x\n", base, data);
+ init->offset += 4;
+
+ init_wr32(init, base, data);
+ base += 4;
+ }
+}
+
+/**
+ * INIT_SUB_DIRECT - opcode 0x5b
+ *
+ */
+static void
+init_sub_direct(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 addr = nv_ro16(bios, init->offset + 1);
+ u16 save;
+
+ trace("SUB_DIRECT\t0x%04x\n", addr);
+
+ if (init_exec(init)) {
+ save = init->offset;
+ init->offset = addr;
+ if (nvbios_exec(init)) {
+ error("error parsing sub-table\n");
+ return;
+ }
+ init->offset = save;
+ }
+
+ init->offset += 3;
+}
+
+/**
+ * INIT_JUMP - opcode 0x5c
+ *
+ */
+static void
+init_jump(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 offset = nv_ro16(bios, init->offset + 1);
+
+ trace("JUMP\t0x%04x\n", offset);
+
+ if (init_exec(init))
+ init->offset = offset;
+ else
+ init->offset += 3;
+}
+
+/**
+ * INIT_I2C_IF - opcode 0x5e
+ *
+ */
+static void
+init_i2c_if(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 addr = nv_ro08(bios, init->offset + 2);
+ u8 reg = nv_ro08(bios, init->offset + 3);
+ u8 mask = nv_ro08(bios, init->offset + 4);
+ u8 data = nv_ro08(bios, init->offset + 5);
+ u8 value;
+
+ trace("I2C_IF\tI2C[0x%02x][0x%02x][0x%02x] & 0x%02x == 0x%02x\n",
+ index, addr, reg, mask, data);
+ init->offset += 6;
+ init_exec_force(init, true);
+
+ value = init_rdi2cr(init, index, addr, reg);
+ if ((value & mask) != data)
+ init_exec_set(init, false);
+
+ init_exec_force(init, false);
+}
+
+/**
+ * INIT_COPY_NV_REG - opcode 0x5f
+ *
+ */
+static void
+init_copy_nv_reg(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 sreg = nv_ro32(bios, init->offset + 1);
+ u8 shift = nv_ro08(bios, init->offset + 5);
+ u32 smask = nv_ro32(bios, init->offset + 6);
+ u32 sxor = nv_ro32(bios, init->offset + 10);
+ u32 dreg = nv_ro32(bios, init->offset + 14);
+ u32 dmask = nv_ro32(bios, init->offset + 18);
+ u32 data;
+
+ trace("COPY_NV_REG\tR[0x%06x] &= 0x%08x |= "
+ "((R[0x%06x] %s 0x%02x) & 0x%08x ^ 0x%08x)\n",
+ dreg, dmask, sreg, (shift & 0x80) ? "<<" : ">>",
+ (shift & 0x80) ? (0x100 - shift) : shift, smask, sxor);
+ init->offset += 22;
+
+ data = init_shift(init_rd32(init, sreg), shift);
+ init_mask(init, dreg, ~dmask, (data & smask) ^ sxor);
+}
+
+/**
+ * INIT_ZM_INDEX_IO - opcode 0x62
+ *
+ */
+static void
+init_zm_index_io(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 port = nv_ro16(bios, init->offset + 1);
+ u8 index = nv_ro08(bios, init->offset + 3);
+ u8 data = nv_ro08(bios, init->offset + 4);
+
+ trace("ZM_INDEX_IO\tI[0x%04x][0x%02x] = 0x%02x\n", port, index, data);
+ init->offset += 5;
+
+ init_wrvgai(init, port, index, data);
+}
+
+/**
+ * INIT_COMPUTE_MEM - opcode 0x63
+ *
+ */
+static void
+init_compute_mem(struct nvbios_init *init)
+{
+ struct nvkm_devinit *devinit = nvkm_devinit(init->bios);
+
+ trace("COMPUTE_MEM\n");
+ init->offset += 1;
+
+ init_exec_force(init, true);
+ if (init_exec(init) && devinit->meminit)
+ devinit->meminit(devinit);
+ init_exec_force(init, false);
+}
+
+/**
+ * INIT_RESET - opcode 0x65
+ *
+ */
+static void
+init_reset(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u32 data1 = nv_ro32(bios, init->offset + 5);
+ u32 data2 = nv_ro32(bios, init->offset + 9);
+ u32 savepci19;
+
+ trace("RESET\tR[0x%08x] = 0x%08x, 0x%08x", reg, data1, data2);
+ init->offset += 13;
+ init_exec_force(init, true);
+
+ savepci19 = init_mask(init, 0x00184c, 0x00000f00, 0x00000000);
+ init_wr32(init, reg, data1);
+ udelay(10);
+ init_wr32(init, reg, data2);
+ init_wr32(init, 0x00184c, savepci19);
+ init_mask(init, 0x001850, 0x00000001, 0x00000000);
+
+ init_exec_force(init, false);
+}
+
+/**
+ * INIT_CONFIGURE_MEM - opcode 0x66
+ *
+ */
+static u16
+init_configure_mem_clk(struct nvbios_init *init)
+{
+ u16 mdata = bmp_mem_init_table(init->bios);
+ if (mdata)
+ mdata += (init_rdvgai(init, 0x03d4, 0x3c) >> 4) * 66;
+ return mdata;
+}
+
+static void
+init_configure_mem(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 mdata, sdata;
+ u32 addr, data;
+
+ trace("CONFIGURE_MEM\n");
+ init->offset += 1;
+
+ if (bios->version.major > 2) {
+ init_done(init);
+ return;
+ }
+ init_exec_force(init, true);
+
+ mdata = init_configure_mem_clk(init);
+ sdata = bmp_sdr_seq_table(bios);
+ if (nv_ro08(bios, mdata) & 0x01)
+ sdata = bmp_ddr_seq_table(bios);
+ mdata += 6; /* skip to data */
+
+ data = init_rdvgai(init, 0x03c4, 0x01);
+ init_wrvgai(init, 0x03c4, 0x01, data | 0x20);
+
+ for (; (addr = nv_ro32(bios, sdata)) != 0xffffffff; sdata += 4) {
+ switch (addr) {
+ case 0x10021c: /* CKE_NORMAL */
+ case 0x1002d0: /* CMD_REFRESH */
+ case 0x1002d4: /* CMD_PRECHARGE */
+ data = 0x00000001;
+ break;
+ default:
+ data = nv_ro32(bios, mdata);
+ mdata += 4;
+ if (data == 0xffffffff)
+ continue;
+ break;
+ }
+
+ init_wr32(init, addr, data);
+ }
+
+ init_exec_force(init, false);
+}
+
+/**
+ * INIT_CONFIGURE_CLK - opcode 0x67
+ *
+ */
+static void
+init_configure_clk(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 mdata, clock;
+
+ trace("CONFIGURE_CLK\n");
+ init->offset += 1;
+
+ if (bios->version.major > 2) {
+ init_done(init);
+ return;
+ }
+ init_exec_force(init, true);
+
+ mdata = init_configure_mem_clk(init);
+
+ /* NVPLL */
+ clock = nv_ro16(bios, mdata + 4) * 10;
+ init_prog_pll(init, 0x680500, clock);
+
+ /* MPLL */
+ clock = nv_ro16(bios, mdata + 2) * 10;
+ if (nv_ro08(bios, mdata) & 0x01)
+ clock *= 2;
+ init_prog_pll(init, 0x680504, clock);
+
+ init_exec_force(init, false);
+}
+
+/**
+ * INIT_CONFIGURE_PREINIT - opcode 0x68
+ *
+ */
+static void
+init_configure_preinit(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 strap;
+
+ trace("CONFIGURE_PREINIT\n");
+ init->offset += 1;
+
+ if (bios->version.major > 2) {
+ init_done(init);
+ return;
+ }
+ init_exec_force(init, true);
+
+ strap = init_rd32(init, 0x101000);
+ strap = ((strap << 2) & 0xf0) | ((strap & 0x40) >> 6);
+ init_wrvgai(init, 0x03d4, 0x3c, strap);
+
+ init_exec_force(init, false);
+}
+
+/**
+ * INIT_IO - opcode 0x69
+ *
+ */
+static void
+init_io(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 port = nv_ro16(bios, init->offset + 1);
+ u8 mask = nv_ro16(bios, init->offset + 3);
+ u8 data = nv_ro16(bios, init->offset + 4);
+ u8 value;
+
+ trace("IO\t\tI[0x%04x] &= 0x%02x |= 0x%02x\n", port, mask, data);
+ init->offset += 5;
+
+ /* ummm.. yes.. should really figure out wtf this is and why it's
+ * needed some day.. it's almost certainly wrong, but, it also
+ * somehow makes things work...
+ */
+ if (nv_device(init->bios)->card_type >= NV_50 &&
+ port == 0x03c3 && data == 0x01) {
+ init_mask(init, 0x614100, 0xf0800000, 0x00800000);
+ init_mask(init, 0x00e18c, 0x00020000, 0x00020000);
+ init_mask(init, 0x614900, 0xf0800000, 0x00800000);
+ init_mask(init, 0x000200, 0x40000000, 0x00000000);
+ mdelay(10);
+ init_mask(init, 0x00e18c, 0x00020000, 0x00000000);
+ init_mask(init, 0x000200, 0x40000000, 0x40000000);
+ init_wr32(init, 0x614100, 0x00800018);
+ init_wr32(init, 0x614900, 0x00800018);
+ mdelay(10);
+ init_wr32(init, 0x614100, 0x10000018);
+ init_wr32(init, 0x614900, 0x10000018);
+ }
+
+ value = init_rdport(init, port) & mask;
+ init_wrport(init, port, data | value);
+}
+
+/**
+ * INIT_SUB - opcode 0x6b
+ *
+ */
+static void
+init_sub(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u16 addr, save;
+
+ trace("SUB\t0x%02x\n", index);
+
+ addr = init_script(bios, index);
+ if (addr && init_exec(init)) {
+ save = init->offset;
+ init->offset = addr;
+ if (nvbios_exec(init)) {
+ error("error parsing sub-table\n");
+ return;
+ }
+ init->offset = save;
+ }
+
+ init->offset += 2;
+}
+
+/**
+ * INIT_RAM_CONDITION - opcode 0x6d
+ *
+ */
+static void
+init_ram_condition(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 mask = nv_ro08(bios, init->offset + 1);
+ u8 value = nv_ro08(bios, init->offset + 2);
+
+ trace("RAM_CONDITION\t"
+ "(R[0x100000] & 0x%02x) == 0x%02x\n", mask, value);
+ init->offset += 3;
+
+ if ((init_rd32(init, 0x100000) & mask) != value)
+ init_exec_set(init, false);
+}
+
+/**
+ * INIT_NV_REG - opcode 0x6e
+ *
+ */
+static void
+init_nv_reg(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u32 mask = nv_ro32(bios, init->offset + 5);
+ u32 data = nv_ro32(bios, init->offset + 9);
+
+ trace("NV_REG\tR[0x%06x] &= 0x%08x |= 0x%08x\n", reg, mask, data);
+ init->offset += 13;
+
+ init_mask(init, reg, ~mask, data);
+}
+
+/**
+ * INIT_MACRO - opcode 0x6f
+ *
+ */
+static void
+init_macro(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 macro = nv_ro08(bios, init->offset + 1);
+ u16 table;
+
+ trace("MACRO\t0x%02x\n", macro);
+
+ table = init_macro_table(init);
+ if (table) {
+ u32 addr = nv_ro32(bios, table + (macro * 8) + 0);
+ u32 data = nv_ro32(bios, table + (macro * 8) + 4);
+ trace("\t\tR[0x%06x] = 0x%08x\n", addr, data);
+ init_wr32(init, addr, data);
+ }
+
+ init->offset += 2;
+}
+
+/**
+ * INIT_RESUME - opcode 0x72
+ *
+ */
+static void
+init_resume(struct nvbios_init *init)
+{
+ trace("RESUME\n");
+ init->offset += 1;
+ init_exec_set(init, true);
+}
+
+/**
+ * INIT_TIME - opcode 0x74
+ *
+ */
+static void
+init_time(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 usec = nv_ro16(bios, init->offset + 1);
+
+ trace("TIME\t0x%04x\n", usec);
+ init->offset += 3;
+
+ if (init_exec(init)) {
+ if (usec < 1000)
+ udelay(usec);
+ else
+ mdelay((usec + 900) / 1000);
+ }
+}
+
+/**
+ * INIT_CONDITION - opcode 0x75
+ *
+ */
+static void
+init_condition(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 cond = nv_ro08(bios, init->offset + 1);
+
+ trace("CONDITION\t0x%02x\n", cond);
+ init->offset += 2;
+
+ if (!init_condition_met(init, cond))
+ init_exec_set(init, false);
+}
+
+/**
+ * INIT_IO_CONDITION - opcode 0x76
+ *
+ */
+static void
+init_io_condition(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 cond = nv_ro08(bios, init->offset + 1);
+
+ trace("IO_CONDITION\t0x%02x\n", cond);
+ init->offset += 2;
+
+ if (!init_io_condition_met(init, cond))
+ init_exec_set(init, false);
+}
+
+/**
+ * INIT_INDEX_IO - opcode 0x78
+ *
+ */
+static void
+init_index_io(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u16 port = nv_ro16(bios, init->offset + 1);
+ u8 index = nv_ro16(bios, init->offset + 3);
+ u8 mask = nv_ro08(bios, init->offset + 4);
+ u8 data = nv_ro08(bios, init->offset + 5);
+ u8 value;
+
+ trace("INDEX_IO\tI[0x%04x][0x%02x] &= 0x%02x |= 0x%02x\n",
+ port, index, mask, data);
+ init->offset += 6;
+
+ value = init_rdvgai(init, port, index) & mask;
+ init_wrvgai(init, port, index, data | value);
+}
+
+/**
+ * INIT_PLL - opcode 0x79
+ *
+ */
+static void
+init_pll(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 reg = nv_ro32(bios, init->offset + 1);
+ u32 freq = nv_ro16(bios, init->offset + 5) * 10;
+
+ trace("PLL\tR[0x%06x] =PLL= %dkHz\n", reg, freq);
+ init->offset += 7;
+
+ init_prog_pll(init, reg, freq);
+}
+
+/**
+ * INIT_ZM_REG - opcode 0x7a
+ *
+ */
+static void
+init_zm_reg(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 addr = nv_ro32(bios, init->offset + 1);
+ u32 data = nv_ro32(bios, init->offset + 5);
+
+ trace("ZM_REG\tR[0x%06x] = 0x%08x\n", addr, data);
+ init->offset += 9;
+
+ if (addr == 0x000200)
+ data |= 0x00000001;
+
+ init_wr32(init, addr, data);
+}
+
+/**
+ * INIT_RAM_RESTRICT_PLL - opcde 0x87
+ *
+ */
+static void
+init_ram_restrict_pll(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 type = nv_ro08(bios, init->offset + 1);
+ u8 count = init_ram_restrict_group_count(init);
+ u8 strap = init_ram_restrict(init);
+ u8 cconf;
+
+ trace("RAM_RESTRICT_PLL\t0x%02x\n", type);
+ init->offset += 2;
+
+ for (cconf = 0; cconf < count; cconf++) {
+ u32 freq = nv_ro32(bios, init->offset);
+
+ if (cconf == strap) {
+ trace("%dkHz *\n", freq);
+ init_prog_pll(init, type, freq);
+ } else {
+ trace("%dkHz\n", freq);
+ }
+
+ init->offset += 4;
+ }
+}
+
+/**
+ * INIT_GPIO - opcode 0x8e
+ *
+ */
+static void
+init_gpio(struct nvbios_init *init)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(init->bios);
+
+ trace("GPIO\n");
+ init->offset += 1;
+
+ if (init_exec(init) && gpio && gpio->reset)
+ gpio->reset(gpio, DCB_GPIO_UNUSED);
+}
+
+/**
+ * INIT_RAM_RESTRICT_ZM_GROUP - opcode 0x8f
+ *
+ */
+static void
+init_ram_restrict_zm_reg_group(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 addr = nv_ro32(bios, init->offset + 1);
+ u8 incr = nv_ro08(bios, init->offset + 5);
+ u8 num = nv_ro08(bios, init->offset + 6);
+ u8 count = init_ram_restrict_group_count(init);
+ u8 index = init_ram_restrict(init);
+ u8 i, j;
+
+ trace("RAM_RESTRICT_ZM_REG_GROUP\t"
+ "R[0x%08x] 0x%02x 0x%02x\n", addr, incr, num);
+ init->offset += 7;
+
+ for (i = 0; i < num; i++) {
+ trace("\tR[0x%06x] = {\n", addr);
+ for (j = 0; j < count; j++) {
+ u32 data = nv_ro32(bios, init->offset);
+
+ if (j == index) {
+ trace("\t\t0x%08x *\n", data);
+ init_wr32(init, addr, data);
+ } else {
+ trace("\t\t0x%08x\n", data);
+ }
+
+ init->offset += 4;
+ }
+ trace("\t}\n");
+ addr += incr;
+ }
+}
+
+/**
+ * INIT_COPY_ZM_REG - opcode 0x90
+ *
+ */
+static void
+init_copy_zm_reg(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 sreg = nv_ro32(bios, init->offset + 1);
+ u32 dreg = nv_ro32(bios, init->offset + 5);
+
+ trace("COPY_ZM_REG\tR[0x%06x] = R[0x%06x]\n", dreg, sreg);
+ init->offset += 9;
+
+ init_wr32(init, dreg, init_rd32(init, sreg));
+}
+
+/**
+ * INIT_ZM_REG_GROUP - opcode 0x91
+ *
+ */
+static void
+init_zm_reg_group(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 addr = nv_ro32(bios, init->offset + 1);
+ u8 count = nv_ro08(bios, init->offset + 5);
+
+ trace("ZM_REG_GROUP\tR[0x%06x] =\n", addr);
+ init->offset += 6;
+
+ while (count--) {
+ u32 data = nv_ro32(bios, init->offset);
+ trace("\t0x%08x\n", data);
+ init_wr32(init, addr, data);
+ init->offset += 4;
+ }
+}
+
+/**
+ * INIT_XLAT - opcode 0x96
+ *
+ */
+static void
+init_xlat(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 saddr = nv_ro32(bios, init->offset + 1);
+ u8 sshift = nv_ro08(bios, init->offset + 5);
+ u8 smask = nv_ro08(bios, init->offset + 6);
+ u8 index = nv_ro08(bios, init->offset + 7);
+ u32 daddr = nv_ro32(bios, init->offset + 8);
+ u32 dmask = nv_ro32(bios, init->offset + 12);
+ u8 shift = nv_ro08(bios, init->offset + 16);
+ u32 data;
+
+ trace("INIT_XLAT\tR[0x%06x] &= 0x%08x |= "
+ "(X%02x((R[0x%06x] %s 0x%02x) & 0x%02x) << 0x%02x)\n",
+ daddr, dmask, index, saddr, (sshift & 0x80) ? "<<" : ">>",
+ (sshift & 0x80) ? (0x100 - sshift) : sshift, smask, shift);
+ init->offset += 17;
+
+ data = init_shift(init_rd32(init, saddr), sshift) & smask;
+ data = init_xlat_(init, index, data) << shift;
+ init_mask(init, daddr, ~dmask, data);
+}
+
+/**
+ * INIT_ZM_MASK_ADD - opcode 0x97
+ *
+ */
+static void
+init_zm_mask_add(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 addr = nv_ro32(bios, init->offset + 1);
+ u32 mask = nv_ro32(bios, init->offset + 5);
+ u32 add = nv_ro32(bios, init->offset + 9);
+ u32 data;
+
+ trace("ZM_MASK_ADD\tR[0x%06x] &= 0x%08x += 0x%08x\n", addr, mask, add);
+ init->offset += 13;
+
+ data = init_rd32(init, addr);
+ data = (data & mask) | ((data + add) & ~mask);
+ init_wr32(init, addr, data);
+}
+
+/**
+ * INIT_AUXCH - opcode 0x98
+ *
+ */
+static void
+init_auxch(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 addr = nv_ro32(bios, init->offset + 1);
+ u8 count = nv_ro08(bios, init->offset + 5);
+
+ trace("AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
+ init->offset += 6;
+
+ while (count--) {
+ u8 mask = nv_ro08(bios, init->offset + 0);
+ u8 data = nv_ro08(bios, init->offset + 1);
+ trace("\tAUX[0x%08x] &= 0x%02x |= 0x%02x\n", addr, mask, data);
+ mask = init_rdauxr(init, addr) & mask;
+ init_wrauxr(init, addr, mask | data);
+ init->offset += 2;
+ }
+}
+
+/**
+ * INIT_AUXCH - opcode 0x99
+ *
+ */
+static void
+init_zm_auxch(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u32 addr = nv_ro32(bios, init->offset + 1);
+ u8 count = nv_ro08(bios, init->offset + 5);
+
+ trace("ZM_AUXCH\tAUX[0x%08x] 0x%02x\n", addr, count);
+ init->offset += 6;
+
+ while (count--) {
+ u8 data = nv_ro08(bios, init->offset + 0);
+ trace("\tAUX[0x%08x] = 0x%02x\n", addr, data);
+ init_wrauxr(init, addr, data);
+ init->offset += 1;
+ }
+}
+
+/**
+ * INIT_I2C_LONG_IF - opcode 0x9a
+ *
+ */
+static void
+init_i2c_long_if(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ u8 index = nv_ro08(bios, init->offset + 1);
+ u8 addr = nv_ro08(bios, init->offset + 2) >> 1;
+ u8 reglo = nv_ro08(bios, init->offset + 3);
+ u8 reghi = nv_ro08(bios, init->offset + 4);
+ u8 mask = nv_ro08(bios, init->offset + 5);
+ u8 data = nv_ro08(bios, init->offset + 6);
+ struct nvkm_i2c_port *port;
+
+ trace("I2C_LONG_IF\t"
+ "I2C[0x%02x][0x%02x][0x%02x%02x] & 0x%02x == 0x%02x\n",
+ index, addr, reglo, reghi, mask, data);
+ init->offset += 7;
+
+ port = init_i2c(init, index);
+ if (port) {
+ u8 i[2] = { reghi, reglo };
+ u8 o[1] = {};
+ struct i2c_msg msg[] = {
+ { .addr = addr, .flags = 0, .len = 2, .buf = i },
+ { .addr = addr, .flags = I2C_M_RD, .len = 1, .buf = o }
+ };
+ int ret;
+
+ ret = i2c_transfer(&port->adapter, msg, 2);
+ if (ret == 2 && ((o[0] & mask) == data))
+ return;
+ }
+
+ init_exec_set(init, false);
+}
+
+/**
+ * INIT_GPIO_NE - opcode 0xa9
+ *
+ */
+static void
+init_gpio_ne(struct nvbios_init *init)
+{
+ struct nvkm_bios *bios = init->bios;
+ struct nvkm_gpio *gpio = nvkm_gpio(bios);
+ struct dcb_gpio_func func;
+ u8 count = nv_ro08(bios, init->offset + 1);
+ u8 idx = 0, ver, len;
+ u16 data, i;
+
+ trace("GPIO_NE\t");
+ init->offset += 2;
+
+ for (i = init->offset; i < init->offset + count; i++)
+ cont("0x%02x ", nv_ro08(bios, i));
+ cont("\n");
+
+ while ((data = dcb_gpio_parse(bios, 0, idx++, &ver, &len, &func))) {
+ if (func.func != DCB_GPIO_UNUSED) {
+ for (i = init->offset; i < init->offset + count; i++) {
+ if (func.func == nv_ro08(bios, i))
+ break;
+ }
+
+ trace("\tFUNC[0x%02x]", func.func);
+ if (i == (init->offset + count)) {
+ cont(" *");
+ if (init_exec(init) && gpio && gpio->reset)
+ gpio->reset(gpio, func.func);
+ }
+ cont("\n");
+ }
+ }
+
+ init->offset += count;
+}
+
+static struct nvbios_init_opcode {
+ void (*exec)(struct nvbios_init *);
+} init_opcode[] = {
+ [0x32] = { init_io_restrict_prog },
+ [0x33] = { init_repeat },
+ [0x34] = { init_io_restrict_pll },
+ [0x36] = { init_end_repeat },
+ [0x37] = { init_copy },
+ [0x38] = { init_not },
+ [0x39] = { init_io_flag_condition },
+ [0x3a] = { init_dp_condition },
+ [0x3b] = { init_io_mask_or },
+ [0x3c] = { init_io_or },
+ [0x47] = { init_andn_reg },
+ [0x48] = { init_or_reg },
+ [0x49] = { init_idx_addr_latched },
+ [0x4a] = { init_io_restrict_pll2 },
+ [0x4b] = { init_pll2 },
+ [0x4c] = { init_i2c_byte },
+ [0x4d] = { init_zm_i2c_byte },
+ [0x4e] = { init_zm_i2c },
+ [0x4f] = { init_tmds },
+ [0x50] = { init_zm_tmds_group },
+ [0x51] = { init_cr_idx_adr_latch },
+ [0x52] = { init_cr },
+ [0x53] = { init_zm_cr },
+ [0x54] = { init_zm_cr_group },
+ [0x56] = { init_condition_time },
+ [0x57] = { init_ltime },
+ [0x58] = { init_zm_reg_sequence },
+ [0x5b] = { init_sub_direct },
+ [0x5c] = { init_jump },
+ [0x5e] = { init_i2c_if },
+ [0x5f] = { init_copy_nv_reg },
+ [0x62] = { init_zm_index_io },
+ [0x63] = { init_compute_mem },
+ [0x65] = { init_reset },
+ [0x66] = { init_configure_mem },
+ [0x67] = { init_configure_clk },
+ [0x68] = { init_configure_preinit },
+ [0x69] = { init_io },
+ [0x6b] = { init_sub },
+ [0x6d] = { init_ram_condition },
+ [0x6e] = { init_nv_reg },
+ [0x6f] = { init_macro },
+ [0x71] = { init_done },
+ [0x72] = { init_resume },
+ [0x74] = { init_time },
+ [0x75] = { init_condition },
+ [0x76] = { init_io_condition },
+ [0x78] = { init_index_io },
+ [0x79] = { init_pll },
+ [0x7a] = { init_zm_reg },
+ [0x87] = { init_ram_restrict_pll },
+ [0x8c] = { init_reserved },
+ [0x8d] = { init_reserved },
+ [0x8e] = { init_gpio },
+ [0x8f] = { init_ram_restrict_zm_reg_group },
+ [0x90] = { init_copy_zm_reg },
+ [0x91] = { init_zm_reg_group },
+ [0x92] = { init_reserved },
+ [0x96] = { init_xlat },
+ [0x97] = { init_zm_mask_add },
+ [0x98] = { init_auxch },
+ [0x99] = { init_zm_auxch },
+ [0x9a] = { init_i2c_long_if },
+ [0xa9] = { init_gpio_ne },
+ [0xaa] = { init_reserved },
+};
+
+#define init_opcode_nr (sizeof(init_opcode) / sizeof(init_opcode[0]))
+
+int
+nvbios_exec(struct nvbios_init *init)
+{
+ init->nested++;
+ while (init->offset) {
+ u8 opcode = nv_ro08(init->bios, init->offset);
+ if (opcode >= init_opcode_nr || !init_opcode[opcode].exec) {
+ error("unknown opcode 0x%02x\n", opcode);
+ return -EINVAL;
+ }
+
+ init_opcode[opcode].exec(init);
+ }
+ init->nested--;
+ return 0;
+}
+
+int
+nvbios_init(struct nvkm_subdev *subdev, bool execute)
+{
+ struct nvkm_bios *bios = nvkm_bios(subdev);
+ int ret = 0;
+ int i = -1;
+ u16 data;
+
+ if (execute)
+ nv_info(bios, "running init tables\n");
+ while (!ret && (data = (init_script(bios, ++i)))) {
+ struct nvbios_init init = {
+ .subdev = subdev,
+ .bios = bios,
+ .offset = data,
+ .outp = NULL,
+ .crtc = -1,
+ .execute = execute ? 1 : 0,
+ };
+
+ ret = nvbios_exec(&init);
+ }
+
+ /* the vbios parser will run this right after the normal init
+ * tables, whereas the binary driver appears to run it later.
+ */
+ if (!ret && (data = init_unknown_script(bios))) {
+ struct nvbios_init init = {
+ .subdev = subdev,
+ .bios = bios,
+ .offset = data,
+ .outp = NULL,
+ .crtc = -1,
+ .execute = execute ? 1 : 0,
+ };
+
+ ret = nvbios_exec(&init);
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c
new file mode 100644
index 000000000000..c4087df4f85e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/mxm.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/mxm.h>
+
+u16
+mxm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr)
+{
+ struct bit_entry x;
+
+ if (bit_entry(bios, 'x', &x)) {
+ nv_debug(bios, "BIT 'x' table not present\n");
+ return 0x0000;
+ }
+
+ *ver = x.version;
+ *hdr = x.length;
+ if (*ver != 1 || *hdr < 3) {
+ nv_warn(bios, "BIT 'x' table %d/%d unknown\n", *ver, *hdr);
+ return 0x0000;
+ }
+
+ return x.offset;
+}
+
+/* These map MXM v2.x digital connection values to the appropriate SOR/link,
+ * hopefully they're correct for all boards within the same chipset...
+ *
+ * MXM v3.x VBIOS are nicer and provide pointers to these tables.
+ */
+static u8 g84_sor_map[16] = {
+ 0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static u8 g92_sor_map[16] = {
+ 0x00, 0x12, 0x22, 0x11, 0x32, 0x31, 0x11, 0x31,
+ 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static u8 g94_sor_map[16] = {
+ 0x00, 0x14, 0x24, 0x11, 0x34, 0x31, 0x11, 0x31,
+ 0x11, 0x31, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static u8 g98_sor_map[16] = {
+ 0x00, 0x14, 0x12, 0x11, 0x00, 0x31, 0x11, 0x31,
+ 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+u8
+mxm_sor_map(struct nvkm_bios *bios, u8 conn)
+{
+ u8 ver, hdr;
+ u16 mxm = mxm_table(bios, &ver, &hdr);
+ if (mxm && hdr >= 6) {
+ u16 map = nv_ro16(bios, mxm + 4);
+ if (map) {
+ ver = nv_ro08(bios, map);
+ if (ver == 0x10) {
+ if (conn < nv_ro08(bios, map + 3)) {
+ map += nv_ro08(bios, map + 1);
+ map += conn;
+ return nv_ro08(bios, map);
+ }
+
+ return 0x00;
+ }
+
+ nv_warn(bios, "unknown sor map v%02x\n", ver);
+ }
+ }
+
+ if (bios->version.chip == 0x84 || bios->version.chip == 0x86)
+ return g84_sor_map[conn];
+ if (bios->version.chip == 0x92)
+ return g92_sor_map[conn];
+ if (bios->version.chip == 0x94 || bios->version.chip == 0x96)
+ return g94_sor_map[conn];
+ if (bios->version.chip == 0x98)
+ return g98_sor_map[conn];
+
+ nv_warn(bios, "missing sor map\n");
+ return 0x00;
+}
+
+u8
+mxm_ddc_map(struct nvkm_bios *bios, u8 port)
+{
+ u8 ver, hdr;
+ u16 mxm = mxm_table(bios, &ver, &hdr);
+ if (mxm && hdr >= 8) {
+ u16 map = nv_ro16(bios, mxm + 6);
+ if (map) {
+ ver = nv_ro08(bios, map);
+ if (ver == 0x10) {
+ if (port < nv_ro08(bios, map + 3)) {
+ map += nv_ro08(bios, map + 1);
+ map += port;
+ return nv_ro08(bios, map);
+ }
+
+ return 0x00;
+ }
+
+ nv_warn(bios, "unknown ddc map v%02x\n", ver);
+ }
+ }
+
+ /* v2.x: directly write port as dcb i2cidx */
+ return (port << 4) | port;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c
new file mode 100644
index 000000000000..fd7dd718b2bf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/npde.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/npde.h>
+#include <subdev/bios/pcir.h>
+
+u32
+nvbios_npdeTe(struct nvkm_bios *bios, u32 base)
+{
+ struct nvbios_pcirT pcir;
+ u8 ver; u16 hdr;
+ u32 data = nvbios_pcirTp(bios, base, &ver, &hdr, &pcir);
+ if (data = (data + hdr + 0x0f) & ~0x0f, data) {
+ switch (nv_ro32(bios, data + 0x00)) {
+ case 0x4544504e: /* NPDE */
+ break;
+ default:
+ nv_debug(bios, "%08x: NPDE signature (%08x) unknown\n",
+ data, nv_ro32(bios, data + 0x00));
+ data = 0;
+ break;
+ }
+ }
+ return data;
+}
+
+u32
+nvbios_npdeTp(struct nvkm_bios *bios, u32 base, struct nvbios_npdeT *info)
+{
+ u32 data = nvbios_npdeTe(bios, base);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ info->image_size = nv_ro16(bios, data + 0x08) * 512;
+ info->last = nv_ro08(bios, data + 0x0a) & 0x80;
+ }
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c
new file mode 100644
index 000000000000..df5978753ae8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pcir.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/pcir.h>
+
+u32
+nvbios_pcirTe(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr)
+{
+ u32 data = nv_ro16(bios, base + 0x18);
+ if (data) {
+ data += base;
+ switch (nv_ro32(bios, data + 0x00)) {
+ case 0x52494350: /* PCIR */
+ case 0x53494752: /* RGIS */
+ case 0x5344504e: /* NPDS */
+ *hdr = nv_ro16(bios, data + 0x0a);
+ *ver = nv_ro08(bios, data + 0x0c);
+ break;
+ default:
+ nv_debug(bios, "%08x: PCIR signature (%08x) unknown\n",
+ data, nv_ro32(bios, data + 0x00));
+ data = 0;
+ break;
+ }
+ }
+ return data;
+}
+
+u32
+nvbios_pcirTp(struct nvkm_bios *bios, u32 base, u8 *ver, u16 *hdr,
+ struct nvbios_pcirT *info)
+{
+ u32 data = nvbios_pcirTe(bios, base, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ if (data) {
+ info->vendor_id = nv_ro16(bios, data + 0x04);
+ info->device_id = nv_ro16(bios, data + 0x06);
+ info->class_code[0] = nv_ro08(bios, data + 0x0d);
+ info->class_code[1] = nv_ro08(bios, data + 0x0e);
+ info->class_code[2] = nv_ro08(bios, data + 0x0f);
+ info->image_size = nv_ro16(bios, data + 0x10) * 512;
+ info->image_rev = nv_ro16(bios, data + 0x12);
+ info->image_type = nv_ro08(bios, data + 0x14);
+ info->last = nv_ro08(bios, data + 0x15) & 0x80;
+ }
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
new file mode 100644
index 000000000000..382ae9cdbf58
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/perf.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/perf.h>
+
+#include <core/device.h>
+
+u16
+nvbios_perf_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
+ u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+ struct bit_entry bit_P;
+ u16 perf = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version <= 2) {
+ perf = nv_ro16(bios, bit_P.offset + 0);
+ if (perf) {
+ *ver = nv_ro08(bios, perf + 0);
+ *hdr = nv_ro08(bios, perf + 1);
+ if (*ver >= 0x40 && *ver < 0x41) {
+ *cnt = nv_ro08(bios, perf + 5);
+ *len = nv_ro08(bios, perf + 2);
+ *snr = nv_ro08(bios, perf + 4);
+ *ssz = nv_ro08(bios, perf + 3);
+ return perf;
+ } else
+ if (*ver >= 0x20 && *ver < 0x40) {
+ *cnt = nv_ro08(bios, perf + 2);
+ *len = nv_ro08(bios, perf + 3);
+ *snr = nv_ro08(bios, perf + 4);
+ *ssz = nv_ro08(bios, perf + 5);
+ return perf;
+ }
+ }
+ }
+ }
+
+ if (bios->bmp_offset) {
+ if (nv_ro08(bios, bios->bmp_offset + 6) >= 0x25) {
+ perf = nv_ro16(bios, bios->bmp_offset + 0x94);
+ if (perf) {
+ *hdr = nv_ro08(bios, perf + 0);
+ *ver = nv_ro08(bios, perf + 1);
+ *cnt = nv_ro08(bios, perf + 2);
+ *len = nv_ro08(bios, perf + 3);
+ *snr = 0;
+ *ssz = 0;
+ return perf;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_perf_entry(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 snr, ssz;
+ u16 perf = nvbios_perf_table(bios, ver, hdr, cnt, len, &snr, &ssz);
+ if (perf && idx < *cnt) {
+ perf = perf + *hdr + (idx * (*len + (snr * ssz)));
+ *hdr = *len;
+ *cnt = snr;
+ *len = ssz;
+ return perf;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_perfEp(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_perfE *info)
+{
+ u16 perf = nvbios_perf_entry(bios, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ info->pstate = nv_ro08(bios, perf + 0x00);
+ switch (!!perf * *ver) {
+ case 0x12:
+ case 0x13:
+ case 0x14:
+ info->core = nv_ro32(bios, perf + 0x01) * 10;
+ info->memory = nv_ro32(bios, perf + 0x05) * 20;
+ info->fanspeed = nv_ro08(bios, perf + 0x37);
+ if (*hdr > 0x38)
+ info->voltage = nv_ro08(bios, perf + 0x38);
+ break;
+ case 0x21:
+ case 0x23:
+ case 0x24:
+ info->fanspeed = nv_ro08(bios, perf + 0x04);
+ info->voltage = nv_ro08(bios, perf + 0x05);
+ info->shader = nv_ro16(bios, perf + 0x06) * 1000;
+ info->core = info->shader + (signed char)
+ nv_ro08(bios, perf + 0x08) * 1000;
+ switch (nv_device(bios)->chipset) {
+ case 0x49:
+ case 0x4b:
+ info->memory = nv_ro16(bios, perf + 0x0b) * 1000;
+ break;
+ default:
+ info->memory = nv_ro16(bios, perf + 0x0b) * 2000;
+ break;
+ }
+ break;
+ case 0x25:
+ info->fanspeed = nv_ro08(bios, perf + 0x04);
+ info->voltage = nv_ro08(bios, perf + 0x05);
+ info->core = nv_ro16(bios, perf + 0x06) * 1000;
+ info->shader = nv_ro16(bios, perf + 0x0a) * 1000;
+ info->memory = nv_ro16(bios, perf + 0x0c) * 1000;
+ break;
+ case 0x30:
+ info->script = nv_ro16(bios, perf + 0x02);
+ case 0x35:
+ info->fanspeed = nv_ro08(bios, perf + 0x06);
+ info->voltage = nv_ro08(bios, perf + 0x07);
+ info->core = nv_ro16(bios, perf + 0x08) * 1000;
+ info->shader = nv_ro16(bios, perf + 0x0a) * 1000;
+ info->memory = nv_ro16(bios, perf + 0x0c) * 1000;
+ info->vdec = nv_ro16(bios, perf + 0x10) * 1000;
+ info->disp = nv_ro16(bios, perf + 0x14) * 1000;
+ break;
+ case 0x40:
+ info->voltage = nv_ro08(bios, perf + 0x02);
+ break;
+ default:
+ return 0x0000;
+ }
+ return perf;
+}
+
+u32
+nvbios_perfSe(struct nvkm_bios *bios, u32 perfE, int idx,
+ u8 *ver, u8 *hdr, u8 cnt, u8 len)
+{
+ u32 data = 0x00000000;
+ if (idx < cnt) {
+ data = perfE + *hdr + (idx * len);
+ *hdr = len;
+ }
+ return data;
+}
+
+u32
+nvbios_perfSp(struct nvkm_bios *bios, u32 perfE, int idx,
+ u8 *ver, u8 *hdr, u8 cnt, u8 len,
+ struct nvbios_perfS *info)
+{
+ u32 data = nvbios_perfSe(bios, perfE, idx, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ case 0x40:
+ info->v40.freq = (nv_ro16(bios, data + 0x00) & 0x3fff) * 1000;
+ break;
+ default:
+ break;
+ }
+ return data;
+}
+
+int
+nvbios_perf_fan_parse(struct nvkm_bios *bios,
+ struct nvbios_perf_fan *fan)
+{
+ u8 ver, hdr, cnt, len, snr, ssz;
+ u16 perf = nvbios_perf_table(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
+ if (!perf)
+ return -ENODEV;
+
+ if (ver >= 0x20 && ver < 0x40 && hdr > 6)
+ fan->pwm_divisor = nv_ro16(bios, perf + 6);
+ else
+ fan->pwm_divisor = 0;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c
new file mode 100644
index 000000000000..ebd402e19dbf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pll.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright 2005-2006 Erik Waling
+ * Copyright 2006 Stephane Marchesin
+ * Copyright 2007-2009 Stuart Bennett
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION 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 <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/pll.h>
+#include <subdev/vga.h>
+
+#include <core/device.h>
+
+struct pll_mapping {
+ u8 type;
+ u32 reg;
+};
+
+static struct pll_mapping
+nv04_pll_mapping[] = {
+ { PLL_CORE , 0x680500 },
+ { PLL_MEMORY, 0x680504 },
+ { PLL_VPLL0 , 0x680508 },
+ { PLL_VPLL1 , 0x680520 },
+ {}
+};
+
+static struct pll_mapping
+nv40_pll_mapping[] = {
+ { PLL_CORE , 0x004000 },
+ { PLL_MEMORY, 0x004020 },
+ { PLL_VPLL0 , 0x680508 },
+ { PLL_VPLL1 , 0x680520 },
+ {}
+};
+
+static struct pll_mapping
+nv50_pll_mapping[] = {
+ { PLL_CORE , 0x004028 },
+ { PLL_SHADER, 0x004020 },
+ { PLL_UNK03 , 0x004000 },
+ { PLL_MEMORY, 0x004008 },
+ { PLL_UNK40 , 0x00e810 },
+ { PLL_UNK41 , 0x00e818 },
+ { PLL_UNK42 , 0x00e824 },
+ { PLL_VPLL0 , 0x614100 },
+ { PLL_VPLL1 , 0x614900 },
+ {}
+};
+
+static struct pll_mapping
+g84_pll_mapping[] = {
+ { PLL_CORE , 0x004028 },
+ { PLL_SHADER, 0x004020 },
+ { PLL_MEMORY, 0x004008 },
+ { PLL_VDEC , 0x004030 },
+ { PLL_UNK41 , 0x00e818 },
+ { PLL_VPLL0 , 0x614100 },
+ { PLL_VPLL1 , 0x614900 },
+ {}
+};
+
+static u16
+pll_limits_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry bit_C;
+
+ if (!bit_entry(bios, 'C', &bit_C) && bit_C.length >= 10) {
+ u16 data = nv_ro16(bios, bit_C.offset + 8);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0);
+ *hdr = nv_ro08(bios, data + 1);
+ *len = nv_ro08(bios, data + 2);
+ *cnt = nv_ro08(bios, data + 3);
+ return data;
+ }
+ }
+
+ if (bmp_version(bios) >= 0x0524) {
+ u16 data = nv_ro16(bios, bios->bmp_offset + 142);
+ if (data) {
+ *ver = nv_ro08(bios, data + 0);
+ *hdr = 1;
+ *cnt = 1;
+ *len = 0x18;
+ return data;
+ }
+ }
+
+ *ver = 0x00;
+ return 0x0000;
+}
+
+static struct pll_mapping *
+pll_map(struct nvkm_bios *bios)
+{
+ switch (nv_device(bios)->card_type) {
+ case NV_04:
+ case NV_10:
+ case NV_11:
+ case NV_20:
+ case NV_30:
+ return nv04_pll_mapping;
+ break;
+ case NV_40:
+ return nv40_pll_mapping;
+ case NV_50:
+ if (nv_device(bios)->chipset == 0x50)
+ return nv50_pll_mapping;
+ else
+ if (nv_device(bios)->chipset < 0xa3 ||
+ nv_device(bios)->chipset == 0xaa ||
+ nv_device(bios)->chipset == 0xac)
+ return g84_pll_mapping;
+ default:
+ return NULL;
+ }
+}
+
+static u16
+pll_map_reg(struct nvkm_bios *bios, u32 reg, u32 *type, u8 *ver, u8 *len)
+{
+ struct pll_mapping *map;
+ u8 hdr, cnt;
+ u16 data;
+
+ data = pll_limits_table(bios, ver, &hdr, &cnt, len);
+ if (data && *ver >= 0x30) {
+ data += hdr;
+ while (cnt--) {
+ if (nv_ro32(bios, data + 3) == reg) {
+ *type = nv_ro08(bios, data + 0);
+ return data;
+ }
+ data += *len;
+ }
+ return 0x0000;
+ }
+
+ map = pll_map(bios);
+ while (map->reg) {
+ if (map->reg == reg && *ver >= 0x20) {
+ u16 addr = (data += hdr);
+ *type = map->type;
+ while (cnt--) {
+ if (nv_ro32(bios, data) == map->reg)
+ return data;
+ data += *len;
+ }
+ return addr;
+ } else
+ if (map->reg == reg) {
+ *type = map->type;
+ return data + 1;
+ }
+ map++;
+ }
+
+ return 0x0000;
+}
+
+static u16
+pll_map_type(struct nvkm_bios *bios, u8 type, u32 *reg, u8 *ver, u8 *len)
+{
+ struct pll_mapping *map;
+ u8 hdr, cnt;
+ u16 data;
+
+ data = pll_limits_table(bios, ver, &hdr, &cnt, len);
+ if (data && *ver >= 0x30) {
+ data += hdr;
+ while (cnt--) {
+ if (nv_ro08(bios, data + 0) == type) {
+ *reg = nv_ro32(bios, data + 3);
+ return data;
+ }
+ data += *len;
+ }
+ return 0x0000;
+ }
+
+ map = pll_map(bios);
+ while (map->reg) {
+ if (map->type == type && *ver >= 0x20) {
+ u16 addr = (data += hdr);
+ *reg = map->reg;
+ while (cnt--) {
+ if (nv_ro32(bios, data) == map->reg)
+ return data;
+ data += *len;
+ }
+ return addr;
+ } else
+ if (map->type == type) {
+ *reg = map->reg;
+ return data + 1;
+ }
+ map++;
+ }
+
+ return 0x0000;
+}
+
+int
+nvbios_pll_parse(struct nvkm_bios *bios, u32 type, struct nvbios_pll *info)
+{
+ u8 ver, len;
+ u32 reg = type;
+ u16 data;
+
+ if (type > PLL_MAX) {
+ reg = type;
+ data = pll_map_reg(bios, reg, &type, &ver, &len);
+ } else {
+ data = pll_map_type(bios, type, &reg, &ver, &len);
+ }
+
+ if (ver && !data)
+ return -ENOENT;
+
+ memset(info, 0, sizeof(*info));
+ info->type = type;
+ info->reg = reg;
+
+ switch (ver) {
+ case 0x00:
+ break;
+ case 0x10:
+ case 0x11:
+ info->vco1.min_freq = nv_ro32(bios, data + 0);
+ info->vco1.max_freq = nv_ro32(bios, data + 4);
+ info->vco2.min_freq = nv_ro32(bios, data + 8);
+ info->vco2.max_freq = nv_ro32(bios, data + 12);
+ info->vco1.min_inputfreq = nv_ro32(bios, data + 16);
+ info->vco2.min_inputfreq = nv_ro32(bios, data + 20);
+ info->vco1.max_inputfreq = INT_MAX;
+ info->vco2.max_inputfreq = INT_MAX;
+
+ info->max_p = 0x7;
+ info->max_p_usable = 0x6;
+
+ /* these values taken from nv30/31/36 */
+ switch (bios->version.chip) {
+ case 0x36:
+ info->vco1.min_n = 0x5;
+ break;
+ default:
+ info->vco1.min_n = 0x1;
+ break;
+ }
+ info->vco1.max_n = 0xff;
+ info->vco1.min_m = 0x1;
+ info->vco1.max_m = 0xd;
+
+ /*
+ * On nv30, 31, 36 (i.e. all cards with two stage PLLs with this
+ * table version (apart from nv35)), N2 is compared to
+ * maxN2 (0x46) and 10 * maxM2 (0x4), so set maxN2 to 0x28 and
+ * save a comparison
+ */
+ info->vco2.min_n = 0x4;
+ switch (bios->version.chip) {
+ case 0x30:
+ case 0x35:
+ info->vco2.max_n = 0x1f;
+ break;
+ default:
+ info->vco2.max_n = 0x28;
+ break;
+ }
+ info->vco2.min_m = 0x1;
+ info->vco2.max_m = 0x4;
+ break;
+ case 0x20:
+ case 0x21:
+ info->vco1.min_freq = nv_ro16(bios, data + 4) * 1000;
+ info->vco1.max_freq = nv_ro16(bios, data + 6) * 1000;
+ info->vco2.min_freq = nv_ro16(bios, data + 8) * 1000;
+ info->vco2.max_freq = nv_ro16(bios, data + 10) * 1000;
+ info->vco1.min_inputfreq = nv_ro16(bios, data + 12) * 1000;
+ info->vco2.min_inputfreq = nv_ro16(bios, data + 14) * 1000;
+ info->vco1.max_inputfreq = nv_ro16(bios, data + 16) * 1000;
+ info->vco2.max_inputfreq = nv_ro16(bios, data + 18) * 1000;
+ info->vco1.min_n = nv_ro08(bios, data + 20);
+ info->vco1.max_n = nv_ro08(bios, data + 21);
+ info->vco1.min_m = nv_ro08(bios, data + 22);
+ info->vco1.max_m = nv_ro08(bios, data + 23);
+ info->vco2.min_n = nv_ro08(bios, data + 24);
+ info->vco2.max_n = nv_ro08(bios, data + 25);
+ info->vco2.min_m = nv_ro08(bios, data + 26);
+ info->vco2.max_m = nv_ro08(bios, data + 27);
+
+ info->max_p = nv_ro08(bios, data + 29);
+ info->max_p_usable = info->max_p;
+ if (bios->version.chip < 0x60)
+ info->max_p_usable = 0x6;
+ info->bias_p = nv_ro08(bios, data + 30);
+
+ if (len > 0x22)
+ info->refclk = nv_ro32(bios, data + 31);
+ break;
+ case 0x30:
+ data = nv_ro16(bios, data + 1);
+
+ info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
+ info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
+ info->vco2.min_freq = nv_ro16(bios, data + 4) * 1000;
+ info->vco2.max_freq = nv_ro16(bios, data + 6) * 1000;
+ info->vco1.min_inputfreq = nv_ro16(bios, data + 8) * 1000;
+ info->vco2.min_inputfreq = nv_ro16(bios, data + 10) * 1000;
+ info->vco1.max_inputfreq = nv_ro16(bios, data + 12) * 1000;
+ info->vco2.max_inputfreq = nv_ro16(bios, data + 14) * 1000;
+ info->vco1.min_n = nv_ro08(bios, data + 16);
+ info->vco1.max_n = nv_ro08(bios, data + 17);
+ info->vco1.min_m = nv_ro08(bios, data + 18);
+ info->vco1.max_m = nv_ro08(bios, data + 19);
+ info->vco2.min_n = nv_ro08(bios, data + 20);
+ info->vco2.max_n = nv_ro08(bios, data + 21);
+ info->vco2.min_m = nv_ro08(bios, data + 22);
+ info->vco2.max_m = nv_ro08(bios, data + 23);
+ info->max_p_usable = info->max_p = nv_ro08(bios, data + 25);
+ info->bias_p = nv_ro08(bios, data + 27);
+ info->refclk = nv_ro32(bios, data + 28);
+ break;
+ case 0x40:
+ info->refclk = nv_ro16(bios, data + 9) * 1000;
+ data = nv_ro16(bios, data + 1);
+
+ info->vco1.min_freq = nv_ro16(bios, data + 0) * 1000;
+ info->vco1.max_freq = nv_ro16(bios, data + 2) * 1000;
+ info->vco1.min_inputfreq = nv_ro16(bios, data + 4) * 1000;
+ info->vco1.max_inputfreq = nv_ro16(bios, data + 6) * 1000;
+ info->vco1.min_m = nv_ro08(bios, data + 8);
+ info->vco1.max_m = nv_ro08(bios, data + 9);
+ info->vco1.min_n = nv_ro08(bios, data + 10);
+ info->vco1.max_n = nv_ro08(bios, data + 11);
+ info->min_p = nv_ro08(bios, data + 12);
+ info->max_p = nv_ro08(bios, data + 13);
+ break;
+ default:
+ nv_error(bios, "unknown pll limits version 0x%02x\n", ver);
+ return -EINVAL;
+ }
+
+ if (!info->refclk) {
+ info->refclk = nv_device(bios)->crystal;
+ if (bios->version.chip == 0x51) {
+ u32 sel_clk = nv_rd32(bios, 0x680524);
+ if ((info->reg == 0x680508 && sel_clk & 0x20) ||
+ (info->reg == 0x680520 && sel_clk & 0x80)) {
+ if (nv_rdvgac(bios, 0, 0x27) < 0xa3)
+ info->refclk = 200000;
+ else
+ info->refclk = 25000;
+ }
+ }
+ }
+
+ /*
+ * By now any valid limit table ought to have set a max frequency for
+ * vco1, so if it's zero it's either a pre limit table bios, or one
+ * with an empty limit table (seen on nv18)
+ */
+ if (!info->vco1.max_freq) {
+ info->vco1.max_freq = nv_ro32(bios, bios->bmp_offset + 67);
+ info->vco1.min_freq = nv_ro32(bios, bios->bmp_offset + 71);
+ if (bmp_version(bios) < 0x0506) {
+ info->vco1.max_freq = 256000;
+ info->vco1.min_freq = 128000;
+ }
+
+ info->vco1.min_inputfreq = 0;
+ info->vco1.max_inputfreq = INT_MAX;
+ info->vco1.min_n = 0x1;
+ info->vco1.max_n = 0xff;
+ info->vco1.min_m = 0x1;
+
+ if (nv_device(bios)->crystal == 13500) {
+ /* nv05 does this, nv11 doesn't, nv10 unknown */
+ if (bios->version.chip < 0x11)
+ info->vco1.min_m = 0x7;
+ info->vco1.max_m = 0xd;
+ } else {
+ if (bios->version.chip < 0x11)
+ info->vco1.min_m = 0x8;
+ info->vco1.max_m = 0xe;
+ }
+
+ if (bios->version.chip < 0x17 ||
+ bios->version.chip == 0x1a ||
+ bios->version.chip == 0x20)
+ info->max_p = 4;
+ else
+ info->max_p = 5;
+ info->max_p_usable = info->max_p;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c
new file mode 100644
index 000000000000..20c5ce0cd573
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/pmu.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/image.h>
+#include <subdev/bios/pmu.h>
+
+static u32
+weirdo_pointer(struct nvkm_bios *bios, u32 data)
+{
+ struct nvbios_image image;
+ int idx = 0;
+ if (nvbios_image(bios, idx++, &image)) {
+ data -= image.size;
+ while (nvbios_image(bios, idx++, &image)) {
+ if (image.type == 0xe0)
+ return image.base + data;
+ }
+ }
+ return 0;
+}
+
+u32
+nvbios_pmuTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry bit_p;
+ u32 data = 0;
+
+ if (!bit_entry(bios, 'p', &bit_p)) {
+ if (bit_p.version == 2 && bit_p.length >= 4)
+ data = nv_ro32(bios, bit_p.offset + 0x00);
+ if ((data = weirdo_pointer(bios, data))) {
+ *ver = nv_ro08(bios, data + 0x00); /* maybe? */
+ *hdr = nv_ro08(bios, data + 0x01);
+ *len = nv_ro08(bios, data + 0x02);
+ *cnt = nv_ro08(bios, data + 0x03);
+ }
+ }
+
+ return data;
+}
+
+u32
+nvbios_pmuTp(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_pmuT *info)
+{
+ u32 data = nvbios_pmuTe(bios, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ default:
+ break;
+ }
+ return data;
+}
+
+u32
+nvbios_pmuEe(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr)
+{
+ u8 cnt, len;
+ u32 data = nvbios_pmuTe(bios, ver, hdr, &cnt, &len);
+ if (data && idx < cnt) {
+ data = data + *hdr + (idx * len);
+ *hdr = len;
+ return data;
+ }
+ return 0;
+}
+
+u32
+nvbios_pmuEp(struct nvkm_bios *bios, int idx, u8 *ver, u8 *hdr,
+ struct nvbios_pmuE *info)
+{
+ u32 data = nvbios_pmuEe(bios, idx, ver, hdr);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!data * *ver) {
+ default:
+ info->type = nv_ro08(bios, data + 0x00);
+ info->data = nv_ro32(bios, data + 0x02);
+ break;
+ }
+ return data;
+}
+
+bool
+nvbios_pmuRm(struct nvkm_bios *bios, u8 type, struct nvbios_pmuR *info)
+{
+ struct nvbios_pmuE pmuE;
+ u8 ver, hdr, idx = 0;
+ u32 data;
+ memset(info, 0x00, sizeof(*info));
+ while ((data = nvbios_pmuEp(bios, idx++, &ver, &hdr, &pmuE))) {
+ if ( pmuE.type == type &&
+ (data = weirdo_pointer(bios, pmuE.data))) {
+ info->init_addr_pmu = nv_ro32(bios, data + 0x08);
+ info->args_addr_pmu = nv_ro32(bios, data + 0x0c);
+ info->boot_addr = data + 0x30;
+ info->boot_addr_pmu = nv_ro32(bios, data + 0x10) +
+ nv_ro32(bios, data + 0x18);
+ info->boot_size = nv_ro32(bios, data + 0x1c) -
+ nv_ro32(bios, data + 0x18);
+ info->code_addr = info->boot_addr + info->boot_size;
+ info->code_addr_pmu = info->boot_addr_pmu +
+ info->boot_size;
+ info->code_size = nv_ro32(bios, data + 0x20);
+ info->data_addr = data + 0x30 +
+ nv_ro32(bios, data + 0x24);
+ info->data_addr_pmu = nv_ro32(bios, data + 0x28);
+ info->data_size = nv_ro32(bios, data + 0x2c);
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
new file mode 100644
index 000000000000..95e4fa1531d6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/priv.h
@@ -0,0 +1,23 @@
+#ifndef __NVKM_BIOS_PRIV_H__
+#define __NVKM_BIOS_PRIV_H__
+#include <subdev/bios.h>
+
+struct nvbios_source {
+ const char *name;
+ void *(*init)(struct nvkm_bios *, const char *);
+ void (*fini)(void *);
+ u32 (*read)(void *, u32 offset, u32 length, struct nvkm_bios *);
+ bool rw;
+};
+
+int nvbios_extend(struct nvkm_bios *, u32 length);
+int nvbios_shadow(struct nvkm_bios *);
+
+extern const struct nvbios_source nvbios_rom;
+extern const struct nvbios_source nvbios_ramin;
+extern const struct nvbios_source nvbios_acpi_fast;
+extern const struct nvbios_source nvbios_acpi_slow;
+extern const struct nvbios_source nvbios_pcirom;
+extern const struct nvbios_source nvbios_platform;
+extern const struct nvbios_source nvbios_of;
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c
new file mode 100644
index 000000000000..a17b221119b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/ramcfg.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/ramcfg.h>
+#include <subdev/bios/M0203.h>
+
+static u8
+nvbios_ramcfg_strap(struct nvkm_subdev *subdev)
+{
+ return (nv_rd32(subdev, 0x101000) & 0x0000003c) >> 2;
+}
+
+u8
+nvbios_ramcfg_count(struct nvkm_bios *bios)
+{
+ struct bit_entry bit_M;
+
+ if (!bit_entry(bios, 'M', &bit_M)) {
+ if (bit_M.version == 1 && bit_M.length >= 5)
+ return nv_ro08(bios, bit_M.offset + 2);
+ if (bit_M.version == 2 && bit_M.length >= 3)
+ return nv_ro08(bios, bit_M.offset + 0);
+ }
+
+ return 0x00;
+}
+
+u8
+nvbios_ramcfg_index(struct nvkm_subdev *subdev)
+{
+ struct nvkm_bios *bios = nvkm_bios(subdev);
+ u8 strap = nvbios_ramcfg_strap(subdev);
+ u32 xlat = 0x00000000;
+ struct bit_entry bit_M;
+ struct nvbios_M0203E M0203E;
+ u8 ver, hdr;
+
+ if (!bit_entry(bios, 'M', &bit_M)) {
+ if (bit_M.version == 1 && bit_M.length >= 5)
+ xlat = nv_ro16(bios, bit_M.offset + 3);
+ if (bit_M.version == 2 && bit_M.length >= 3) {
+ /*XXX: is M ever shorter than this?
+ * if not - what is xlat used for now?
+ * also - sigh..
+ */
+ if (bit_M.length >= 7 &&
+ nvbios_M0203Em(bios, strap, &ver, &hdr, &M0203E))
+ return M0203E.group;
+ xlat = nv_ro16(bios, bit_M.offset + 1);
+ }
+ }
+
+ if (xlat)
+ strap = nv_ro08(bios, xlat + strap);
+ return strap;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c
new file mode 100644
index 000000000000..8b17bb4b220c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/rammap.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/rammap.h>
+
+u32
+nvbios_rammapTe(struct nvkm_bios *bios, u8 *ver, u8 *hdr,
+ u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+ struct bit_entry bit_P;
+ u16 rammap = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2)
+ rammap = nv_ro16(bios, bit_P.offset + 4);
+
+ if (rammap) {
+ *ver = nv_ro08(bios, rammap + 0);
+ switch (*ver) {
+ case 0x10:
+ case 0x11:
+ *hdr = nv_ro08(bios, rammap + 1);
+ *cnt = nv_ro08(bios, rammap + 5);
+ *len = nv_ro08(bios, rammap + 2);
+ *snr = nv_ro08(bios, rammap + 4);
+ *ssz = nv_ro08(bios, rammap + 3);
+ return rammap;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u32
+nvbios_rammapEe(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 snr, ssz;
+ u16 rammap = nvbios_rammapTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+ if (rammap && idx < *cnt) {
+ rammap = rammap + *hdr + (idx * (*len + (snr * ssz)));
+ *hdr = *len;
+ *cnt = snr;
+ *len = ssz;
+ return rammap;
+ }
+ return 0x0000;
+}
+
+u32
+nvbios_rammapEp(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p)
+{
+ u32 data = nvbios_rammapEe(bios, idx, ver, hdr, cnt, len), temp;
+ memset(p, 0x00, sizeof(*p));
+ p->rammap_ver = *ver;
+ p->rammap_hdr = *hdr;
+ switch (!!data * *ver) {
+ case 0x10:
+ p->rammap_min = nv_ro16(bios, data + 0x00);
+ p->rammap_max = nv_ro16(bios, data + 0x02);
+ p->rammap_10_04_02 = (nv_ro08(bios, data + 0x04) & 0x02) >> 1;
+ p->rammap_10_04_08 = (nv_ro08(bios, data + 0x04) & 0x08) >> 3;
+ break;
+ case 0x11:
+ p->rammap_min = nv_ro16(bios, data + 0x00);
+ p->rammap_max = nv_ro16(bios, data + 0x02);
+ p->rammap_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
+ p->rammap_11_08_0c = (nv_ro08(bios, data + 0x08) & 0x0c) >> 2;
+ p->rammap_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
+ temp = nv_ro32(bios, data + 0x09);
+ p->rammap_11_09_01ff = (temp & 0x000001ff) >> 0;
+ p->rammap_11_0a_03fe = (temp & 0x0003fe00) >> 9;
+ p->rammap_11_0a_0400 = (temp & 0x00040000) >> 18;
+ p->rammap_11_0a_0800 = (temp & 0x00080000) >> 19;
+ p->rammap_11_0b_01f0 = (temp & 0x01f00000) >> 20;
+ p->rammap_11_0b_0200 = (temp & 0x02000000) >> 25;
+ p->rammap_11_0b_0400 = (temp & 0x04000000) >> 26;
+ p->rammap_11_0b_0800 = (temp & 0x08000000) >> 27;
+ p->rammap_11_0d = nv_ro08(bios, data + 0x0d);
+ p->rammap_11_0e = nv_ro08(bios, data + 0x0e);
+ p->rammap_11_0f = nv_ro08(bios, data + 0x0f);
+ p->rammap_11_11_0c = (nv_ro08(bios, data + 0x11) & 0x0c) >> 2;
+ break;
+ default:
+ data = 0;
+ break;
+ }
+ return data;
+}
+
+u32
+nvbios_rammapEm(struct nvkm_bios *bios, u16 mhz,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *info)
+{
+ int idx = 0;
+ u32 data;
+ while ((data = nvbios_rammapEp(bios, idx++, ver, hdr, cnt, len, info))) {
+ if (mhz >= info->rammap_min && mhz <= info->rammap_max)
+ break;
+ }
+ return data;
+}
+
+u32
+nvbios_rammapSe(struct nvkm_bios *bios, u32 data,
+ u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx, u8 *ver, u8 *hdr)
+{
+ if (idx < ecnt) {
+ data = data + ehdr + (idx * elen);
+ *ver = ever;
+ *hdr = elen;
+ return data;
+ }
+ return 0;
+}
+
+u32
+nvbios_rammapSp(struct nvkm_bios *bios, u32 data,
+ u8 ever, u8 ehdr, u8 ecnt, u8 elen, int idx,
+ u8 *ver, u8 *hdr, struct nvbios_ramcfg *p)
+{
+ data = nvbios_rammapSe(bios, data, ever, ehdr, ecnt, elen, idx, ver, hdr);
+ p->ramcfg_ver = *ver;
+ p->ramcfg_hdr = *hdr;
+ switch (!!data * *ver) {
+ case 0x10:
+ p->ramcfg_timing = nv_ro08(bios, data + 0x01);
+ p->ramcfg_10_02_01 = (nv_ro08(bios, data + 0x02) & 0x01) >> 0;
+ p->ramcfg_10_02_02 = (nv_ro08(bios, data + 0x02) & 0x02) >> 1;
+ p->ramcfg_10_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
+ p->ramcfg_10_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
+ p->ramcfg_10_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
+ p->ramcfg_10_02_20 = (nv_ro08(bios, data + 0x02) & 0x20) >> 5;
+ p->ramcfg_10_DLLoff = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+ p->ramcfg_10_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+ p->ramcfg_10_04_01 = (nv_ro08(bios, data + 0x04) & 0x01) >> 0;
+ p->ramcfg_10_05 = (nv_ro08(bios, data + 0x05) & 0xff) >> 0;
+ p->ramcfg_10_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
+ p->ramcfg_10_07 = (nv_ro08(bios, data + 0x07) & 0xff) >> 0;
+ p->ramcfg_10_08 = (nv_ro08(bios, data + 0x08) & 0xff) >> 0;
+ p->ramcfg_10_09_0f = (nv_ro08(bios, data + 0x09) & 0x0f) >> 0;
+ p->ramcfg_10_09_f0 = (nv_ro08(bios, data + 0x09) & 0xf0) >> 4;
+ break;
+ case 0x11:
+ p->ramcfg_timing = nv_ro08(bios, data + 0x00);
+ p->ramcfg_11_01_01 = (nv_ro08(bios, data + 0x01) & 0x01) >> 0;
+ p->ramcfg_11_01_02 = (nv_ro08(bios, data + 0x01) & 0x02) >> 1;
+ p->ramcfg_11_01_04 = (nv_ro08(bios, data + 0x01) & 0x04) >> 2;
+ p->ramcfg_11_01_08 = (nv_ro08(bios, data + 0x01) & 0x08) >> 3;
+ p->ramcfg_11_01_10 = (nv_ro08(bios, data + 0x01) & 0x10) >> 4;
+ p->ramcfg_11_01_20 = (nv_ro08(bios, data + 0x01) & 0x20) >> 5;
+ p->ramcfg_11_01_40 = (nv_ro08(bios, data + 0x01) & 0x40) >> 6;
+ p->ramcfg_11_01_80 = (nv_ro08(bios, data + 0x01) & 0x80) >> 7;
+ p->ramcfg_11_02_03 = (nv_ro08(bios, data + 0x02) & 0x03) >> 0;
+ p->ramcfg_11_02_04 = (nv_ro08(bios, data + 0x02) & 0x04) >> 2;
+ p->ramcfg_11_02_08 = (nv_ro08(bios, data + 0x02) & 0x08) >> 3;
+ p->ramcfg_11_02_10 = (nv_ro08(bios, data + 0x02) & 0x10) >> 4;
+ p->ramcfg_11_02_40 = (nv_ro08(bios, data + 0x02) & 0x40) >> 6;
+ p->ramcfg_11_02_80 = (nv_ro08(bios, data + 0x02) & 0x80) >> 7;
+ p->ramcfg_11_03_0f = (nv_ro08(bios, data + 0x03) & 0x0f) >> 0;
+ p->ramcfg_11_03_30 = (nv_ro08(bios, data + 0x03) & 0x30) >> 4;
+ p->ramcfg_11_03_c0 = (nv_ro08(bios, data + 0x03) & 0xc0) >> 6;
+ p->ramcfg_11_03_f0 = (nv_ro08(bios, data + 0x03) & 0xf0) >> 4;
+ p->ramcfg_11_04 = (nv_ro08(bios, data + 0x04) & 0xff) >> 0;
+ p->ramcfg_11_06 = (nv_ro08(bios, data + 0x06) & 0xff) >> 0;
+ p->ramcfg_11_07_02 = (nv_ro08(bios, data + 0x07) & 0x02) >> 1;
+ p->ramcfg_11_07_04 = (nv_ro08(bios, data + 0x07) & 0x04) >> 2;
+ p->ramcfg_11_07_08 = (nv_ro08(bios, data + 0x07) & 0x08) >> 3;
+ p->ramcfg_11_07_10 = (nv_ro08(bios, data + 0x07) & 0x10) >> 4;
+ p->ramcfg_11_07_40 = (nv_ro08(bios, data + 0x07) & 0x40) >> 6;
+ p->ramcfg_11_07_80 = (nv_ro08(bios, data + 0x07) & 0x80) >> 7;
+ p->ramcfg_11_08_01 = (nv_ro08(bios, data + 0x08) & 0x01) >> 0;
+ p->ramcfg_11_08_02 = (nv_ro08(bios, data + 0x08) & 0x02) >> 1;
+ p->ramcfg_11_08_04 = (nv_ro08(bios, data + 0x08) & 0x04) >> 2;
+ p->ramcfg_11_08_08 = (nv_ro08(bios, data + 0x08) & 0x08) >> 3;
+ p->ramcfg_11_08_10 = (nv_ro08(bios, data + 0x08) & 0x10) >> 4;
+ p->ramcfg_11_08_20 = (nv_ro08(bios, data + 0x08) & 0x20) >> 5;
+ p->ramcfg_11_09 = (nv_ro08(bios, data + 0x09) & 0xff) >> 0;
+ break;
+ default:
+ data = 0;
+ break;
+ }
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
new file mode 100644
index 000000000000..8c2b7cba5cff
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadow.c
@@ -0,0 +1,272 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/image.h>
+
+struct shadow {
+ struct nvkm_oclass base;
+ u32 skip;
+ const struct nvbios_source *func;
+ void *data;
+ u32 size;
+ int score;
+};
+
+static bool
+shadow_fetch(struct nvkm_bios *bios, u32 upto)
+{
+ struct shadow *mthd = (void *)nv_object(bios)->oclass;
+ const u32 limit = (upto + 3) & ~3;
+ const u32 start = bios->size;
+ void *data = mthd->data;
+ if (nvbios_extend(bios, limit) > 0) {
+ u32 read = mthd->func->read(data, start, limit - start, bios);
+ bios->size = start + read;
+ }
+ return bios->size >= limit;
+}
+
+static u8
+shadow_rd08(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_bios *bios = (void *)object;
+ if (shadow_fetch(bios, addr + 1))
+ return bios->data[addr];
+ return 0x00;
+}
+
+static u16
+shadow_rd16(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_bios *bios = (void *)object;
+ if (shadow_fetch(bios, addr + 2))
+ return get_unaligned_le16(&bios->data[addr]);
+ return 0x0000;
+}
+
+static u32
+shadow_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nvkm_bios *bios = (void *)object;
+ if (shadow_fetch(bios, addr + 4))
+ return get_unaligned_le32(&bios->data[addr]);
+ return 0x00000000;
+}
+
+static struct nvkm_oclass
+shadow_class = {
+ .handle = NV_SUBDEV(VBIOS, 0x00),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .rd08 = shadow_rd08,
+ .rd16 = shadow_rd16,
+ .rd32 = shadow_rd32,
+ },
+};
+
+static int
+shadow_image(struct nvkm_bios *bios, int idx, struct shadow *mthd)
+{
+ struct nvbios_image image;
+ int score = 1;
+
+ if (!nvbios_image(bios, idx, &image)) {
+ nv_debug(bios, "image %d invalid\n", idx);
+ return 0;
+ }
+ nv_debug(bios, "%08x: type %02x, %d bytes\n",
+ image.base, image.type, image.size);
+
+ if (!shadow_fetch(bios, image.size)) {
+ nv_debug(bios, "%08x: fetch failed\n", image.base);
+ return 0;
+ }
+
+ switch (image.type) {
+ case 0x00:
+ if (nvbios_checksum(&bios->data[image.base], image.size)) {
+ nv_debug(bios, "%08x: checksum failed\n", image.base);
+ if (mthd->func->rw)
+ score += 1;
+ score += 1;
+ } else {
+ score += 3;
+ }
+ break;
+ default:
+ score += 3;
+ break;
+ }
+
+ if (!image.last)
+ score += shadow_image(bios, idx + 1, mthd);
+ return score;
+}
+
+static int
+shadow_score(struct nvkm_bios *bios, struct shadow *mthd)
+{
+ struct nvkm_oclass *oclass = nv_object(bios)->oclass;
+ int score;
+ nv_object(bios)->oclass = &mthd->base;
+ score = shadow_image(bios, 0, mthd);
+ nv_object(bios)->oclass = oclass;
+ return score;
+
+}
+
+static int
+shadow_method(struct nvkm_bios *bios, struct shadow *mthd, const char *name)
+{
+ const struct nvbios_source *func = mthd->func;
+ if (func->name) {
+ nv_debug(bios, "trying %s...\n", name ? name : func->name);
+ if (func->init) {
+ mthd->data = func->init(bios, name);
+ if (IS_ERR(mthd->data)) {
+ mthd->data = NULL;
+ return 0;
+ }
+ }
+ mthd->score = shadow_score(bios, mthd);
+ if (func->fini)
+ func->fini(mthd->data);
+ nv_debug(bios, "scored %d\n", mthd->score);
+ mthd->data = bios->data;
+ mthd->size = bios->size;
+ bios->data = NULL;
+ bios->size = 0;
+ }
+ return mthd->score;
+}
+
+static u32
+shadow_fw_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ const struct firmware *fw = data;
+ if (offset + length <= fw->size) {
+ memcpy(bios->data + offset, fw->data + offset, length);
+ return length;
+ }
+ return 0;
+}
+
+static void *
+shadow_fw_init(struct nvkm_bios *bios, const char *name)
+{
+ struct device *dev = &nv_device(bios)->pdev->dev;
+ const struct firmware *fw;
+ int ret = request_firmware(&fw, name, dev);
+ if (ret)
+ return ERR_PTR(-ENOENT);
+ return (void *)fw;
+}
+
+static const struct nvbios_source
+shadow_fw = {
+ .name = "firmware",
+ .init = shadow_fw_init,
+ .fini = (void(*)(void *))release_firmware,
+ .read = shadow_fw_read,
+ .rw = false,
+};
+
+int
+nvbios_shadow(struct nvkm_bios *bios)
+{
+ struct shadow mthds[] = {
+ { shadow_class, 0, &nvbios_of },
+ { shadow_class, 0, &nvbios_ramin },
+ { shadow_class, 0, &nvbios_rom },
+ { shadow_class, 0, &nvbios_acpi_fast },
+ { shadow_class, 4, &nvbios_acpi_slow },
+ { shadow_class, 1, &nvbios_pcirom },
+ { shadow_class, 1, &nvbios_platform },
+ { shadow_class }
+ }, *mthd = mthds, *best = NULL;
+ const char *optarg;
+ char *source;
+ int optlen;
+
+ /* handle user-specified bios source */
+ optarg = nvkm_stropt(nv_device(bios)->cfgopt, "NvBios", &optlen);
+ source = optarg ? kstrndup(optarg, optlen, GFP_KERNEL) : NULL;
+ if (source) {
+ /* try to match one of the built-in methods */
+ for (mthd = mthds; mthd->func; mthd++) {
+ if (mthd->func->name &&
+ !strcasecmp(source, mthd->func->name)) {
+ best = mthd;
+ if (shadow_method(bios, mthd, NULL))
+ break;
+ }
+ }
+
+ /* otherwise, attempt to load as firmware */
+ if (!best && (best = mthd)) {
+ mthd->func = &shadow_fw;
+ shadow_method(bios, mthd, source);
+ mthd->func = NULL;
+ }
+
+ if (!best->score) {
+ nv_error(bios, "%s invalid\n", source);
+ kfree(source);
+ source = NULL;
+ }
+ }
+
+ /* scan all potential bios sources, looking for best image */
+ if (!best || !best->score) {
+ for (mthd = mthds, best = mthd; mthd->func; mthd++) {
+ if (!mthd->skip || best->score < mthd->skip) {
+ if (shadow_method(bios, mthd, NULL)) {
+ if (mthd->score > best->score)
+ best = mthd;
+ }
+ }
+ }
+ }
+
+ /* cleanup the ones we didn't use */
+ for (mthd = mthds; mthd->func; mthd++) {
+ if (mthd != best)
+ kfree(mthd->data);
+ }
+
+ if (!best->score) {
+ nv_fatal(bios, "unable to locate usable image\n");
+ return -EINVAL;
+ }
+
+ nv_info(bios, "using image from %s\n", best->func ?
+ best->func->name : source);
+ bios->data = best->data;
+ bios->size = best->size;
+ kfree(source);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
new file mode 100644
index 000000000000..1fbd93bbb561
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowacpi.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_X86)
+int nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len);
+bool nouveau_acpi_rom_supported(struct pci_dev *pdev);
+#else
+static inline bool
+nouveau_acpi_rom_supported(struct pci_dev *pdev)
+{
+ return false;
+}
+
+static inline int
+nouveau_acpi_get_bios_chunk(uint8_t *bios, int offset, int len)
+{
+ return -EINVAL;
+}
+#endif
+
+/* This version of the shadow function disobeys the ACPI spec and tries
+ * to fetch in units of more than 4KiB at a time. This is a LOT faster
+ * on some systems, such as Lenovo W530.
+ */
+static u32
+acpi_read_fast(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ u32 limit = (offset + length + 0xfff) & ~0xfff;
+ u32 start = offset & ~0x00000fff;
+ u32 fetch = limit - start;
+
+ if (nvbios_extend(bios, limit) > 0) {
+ int ret = nouveau_acpi_get_bios_chunk(bios->data, start, fetch);
+ if (ret == fetch)
+ return fetch;
+ }
+
+ return 0;
+}
+
+/* Other systems, such as the one in fdo#55948, will report a success
+ * but only return 4KiB of data. The common bios fetching logic will
+ * detect an invalid image, and fall back to this version of the read
+ * function.
+ */
+static u32
+acpi_read_slow(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ u32 limit = (offset + length + 0xfff) & ~0xfff;
+ u32 start = offset & ~0xfff;
+ u32 fetch = 0;
+
+ if (nvbios_extend(bios, limit) > 0) {
+ while (start + fetch < limit) {
+ int ret = nouveau_acpi_get_bios_chunk(bios->data,
+ start + fetch,
+ 0x1000);
+ if (ret != 0x1000)
+ break;
+ fetch += 0x1000;
+ }
+ }
+
+ return fetch;
+}
+
+static void *
+acpi_init(struct nvkm_bios *bios, const char *name)
+{
+ if (!nouveau_acpi_rom_supported(nv_device(bios)->pdev))
+ return ERR_PTR(-ENODEV);
+ return NULL;
+}
+
+const struct nvbios_source
+nvbios_acpi_fast = {
+ .name = "ACPI",
+ .init = acpi_init,
+ .read = acpi_read_fast,
+ .rw = false,
+};
+
+const struct nvbios_source
+nvbios_acpi_slow = {
+ .name = "ACPI",
+ .init = acpi_init,
+ .read = acpi_read_slow,
+ .rw = false,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
new file mode 100644
index 000000000000..4c19a7dba803
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowof.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+#if defined(__powerpc__)
+struct priv {
+ const void __iomem *data;
+ int size;
+};
+
+static u32
+of_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ struct priv *priv = data;
+ if (offset + length <= priv->size) {
+ memcpy_fromio(bios->data + offset, priv->data + offset, length);
+ return length;
+ }
+ return 0;
+}
+
+static void *
+of_init(struct nvkm_bios *bios, const char *name)
+{
+ struct pci_dev *pdev = nv_device(bios)->pdev;
+ struct device_node *dn;
+ struct priv *priv;
+ if (!(dn = pci_device_to_OF_node(pdev)))
+ return ERR_PTR(-ENODEV);
+ if (!(priv = kzalloc(sizeof(*priv), GFP_KERNEL)))
+ return ERR_PTR(-ENOMEM);
+ if ((priv->data = of_get_property(dn, "NVDA,BMP", &priv->size)))
+ return priv;
+ kfree(priv);
+ return ERR_PTR(-EINVAL);
+}
+
+const struct nvbios_source
+nvbios_of = {
+ .name = "OpenFirmware",
+ .init = of_init,
+ .fini = (void(*)(void *))kfree,
+ .read = of_read,
+ .rw = false,
+};
+#else
+const struct nvbios_source
+nvbios_of = {
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
new file mode 100644
index 000000000000..1b045483dc87
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowpci.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct priv {
+ struct pci_dev *pdev;
+ void __iomem *rom;
+ size_t size;
+};
+
+static u32
+pcirom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ struct priv *priv = data;
+ if (offset + length <= priv->size) {
+ memcpy_fromio(bios->data + offset, priv->rom + offset, length);
+ return length;
+ }
+ return 0;
+}
+
+static void
+pcirom_fini(void *data)
+{
+ struct priv *priv = data;
+ pci_unmap_rom(priv->pdev, priv->rom);
+ pci_disable_rom(priv->pdev);
+ kfree(priv);
+}
+
+static void *
+pcirom_init(struct nvkm_bios *bios, const char *name)
+{
+ struct pci_dev *pdev = nv_device(bios)->pdev;
+ struct priv *priv = NULL;
+ int ret;
+
+ if (!(ret = pci_enable_rom(pdev))) {
+ if (ret = -ENOMEM,
+ (priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+ if (ret = -EFAULT,
+ (priv->rom = pci_map_rom(pdev, &priv->size))) {
+ priv->pdev = pdev;
+ return priv;
+ }
+ kfree(priv);
+ }
+ pci_disable_rom(pdev);
+ }
+
+ return ERR_PTR(ret);
+}
+
+const struct nvbios_source
+nvbios_pcirom = {
+ .name = "PCIROM",
+ .init = pcirom_init,
+ .fini = pcirom_fini,
+ .read = pcirom_read,
+ .rw = true,
+};
+
+static void *
+platform_init(struct nvkm_bios *bios, const char *name)
+{
+ struct pci_dev *pdev = nv_device(bios)->pdev;
+ struct priv *priv;
+ int ret = -ENOMEM;
+
+ if ((priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+ if (ret = -ENODEV,
+ (priv->rom = pci_platform_rom(pdev, &priv->size)))
+ return priv;
+ kfree(priv);
+ }
+
+ return ERR_PTR(ret);
+}
+
+const struct nvbios_source
+nvbios_platform = {
+ .name = "PLATFORM",
+ .init = platform_init,
+ .fini = (void(*)(void *))kfree,
+ .read = pcirom_read,
+ .rw = true,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c
new file mode 100644
index 000000000000..abe8ae4d3a9f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowramin.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct priv {
+ struct nvkm_bios *bios;
+ u32 bar0;
+};
+
+static u32
+pramin_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ u32 i;
+ if (offset + length <= 0x00100000) {
+ for (i = offset; i < offset + length; i += 4)
+ *(u32 *)&bios->data[i] = nv_rd32(bios, 0x700000 + i);
+ return length;
+ }
+ return 0;
+}
+
+static void
+pramin_fini(void *data)
+{
+ struct priv *priv = data;
+ if (priv) {
+ nv_wr32(priv->bios, 0x001700, priv->bar0);
+ kfree(priv);
+ }
+}
+
+static void *
+pramin_init(struct nvkm_bios *bios, const char *name)
+{
+ struct priv *priv = NULL;
+ u64 addr = 0;
+
+ /* PRAMIN always potentially available prior to nv50 */
+ if (nv_device(bios)->card_type < NV_50)
+ return NULL;
+
+ /* we can't get the bios image pointer without PDISP */
+ if (nv_device(bios)->card_type >= GM100)
+ addr = nv_rd32(bios, 0x021c04);
+ else
+ if (nv_device(bios)->card_type >= NV_C0)
+ addr = nv_rd32(bios, 0x022500);
+ if (addr & 0x00000001) {
+ nv_debug(bios, "... display disabled\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ /* check that the window is enabled and in vram, particularly
+ * important as we don't want to be touching vram on an
+ * uninitialised board
+ */
+ addr = nv_rd32(bios, 0x619f04);
+ if (!(addr & 0x00000008)) {
+ nv_debug(bios, "... not enabled\n");
+ return ERR_PTR(-ENODEV);
+ }
+ if ( (addr & 0x00000003) != 1) {
+ nv_debug(bios, "... not in vram\n");
+ return ERR_PTR(-ENODEV);
+ }
+
+ /* some alternate method inherited from xf86-video-nv... */
+ addr = (addr & 0xffffff00) << 8;
+ if (!addr) {
+ addr = (u64)nv_rd32(bios, 0x001700) << 16;
+ addr += 0xf0000;
+ }
+
+ /* modify bar0 PRAMIN window to cover the bios image */
+ if (!(priv = kmalloc(sizeof(*priv), GFP_KERNEL))) {
+ nv_error(bios, "... out of memory\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ priv->bios = bios;
+ priv->bar0 = nv_rd32(bios, 0x001700);
+ nv_wr32(bios, 0x001700, addr >> 16);
+ return priv;
+}
+
+const struct nvbios_source
+nvbios_ramin = {
+ .name = "PRAMIN",
+ .init = pramin_init,
+ .fini = pramin_fini,
+ .read = pramin_read,
+ .rw = true,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c
new file mode 100644
index 000000000000..6ec3b237925e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/shadowrom.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+static u32
+prom_read(void *data, u32 offset, u32 length, struct nvkm_bios *bios)
+{
+ u32 i;
+ if (offset + length <= 0x00100000) {
+ for (i = offset; i < offset + length; i += 4)
+ *(u32 *)&bios->data[i] = nv_rd32(bios, 0x300000 + i);
+ return length;
+ }
+ return 0;
+}
+
+static void
+prom_fini(void *data)
+{
+ struct nvkm_bios *bios = data;
+ if (nv_device(bios)->card_type < NV_50)
+ nv_mask(bios, 0x001850, 0x00000001, 0x00000001);
+ else
+ nv_mask(bios, 0x088050, 0x00000001, 0x00000001);
+}
+
+static void *
+prom_init(struct nvkm_bios *bios, const char *name)
+{
+ if (nv_device(bios)->card_type < NV_50) {
+ if (nv_device(bios)->card_type == NV_40 &&
+ nv_device(bios)->chipset >= 0x4c)
+ return ERR_PTR(-ENODEV);
+ nv_mask(bios, 0x001850, 0x00000001, 0x00000000);
+ } else {
+ nv_mask(bios, 0x088050, 0x00000001, 0x00000000);
+ }
+ return bios;
+}
+
+const struct nvbios_source
+nvbios_rom = {
+ .name = "PROM",
+ .init = prom_init,
+ .fini = prom_fini,
+ .read = prom_read,
+ .rw = false,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c
new file mode 100644
index 000000000000..249ff6d583df
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/therm.c
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/therm.h>
+
+#include <core/device.h>
+
+static u16
+therm_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *len, u8 *cnt)
+{
+ struct bit_entry bit_P;
+ u16 therm = 0;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 1)
+ therm = nv_ro16(bios, bit_P.offset + 12);
+ else if (bit_P.version == 2)
+ therm = nv_ro16(bios, bit_P.offset + 16);
+ else
+ nv_error(bios,
+ "unknown offset for thermal in BIT P %d\n",
+ bit_P.version);
+ }
+
+ /* exit now if we haven't found the thermal table */
+ if (!therm)
+ return 0x0000;
+
+ *ver = nv_ro08(bios, therm + 0);
+ *hdr = nv_ro08(bios, therm + 1);
+ *len = nv_ro08(bios, therm + 2);
+ *cnt = nv_ro08(bios, therm + 3);
+ return therm + nv_ro08(bios, therm + 1);
+}
+
+static u16
+nvbios_therm_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u16 therm = therm_table(bios, ver, &hdr, len, &cnt);
+ if (therm && idx < cnt)
+ return therm + idx * *len;
+ return 0x0000;
+}
+
+int
+nvbios_therm_sensor_parse(struct nvkm_bios *bios,
+ enum nvbios_therm_domain domain,
+ struct nvbios_therm_sensor *sensor)
+{
+ s8 thrs_section, sensor_section, offset;
+ u8 ver, len, i;
+ u16 entry;
+
+ /* we only support the core domain for now */
+ if (domain != NVBIOS_THERM_DOMAIN_CORE)
+ return -EINVAL;
+
+ /* Read the entries from the table */
+ thrs_section = 0;
+ sensor_section = -1;
+ i = 0;
+ while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
+ s16 value = nv_ro16(bios, entry + 1);
+
+ switch (nv_ro08(bios, entry + 0)) {
+ case 0x0:
+ thrs_section = value;
+ if (value > 0)
+ return 0; /* we do not try to support ambient */
+ break;
+ case 0x01:
+ sensor_section++;
+ if (sensor_section == 0) {
+ offset = ((s8) nv_ro08(bios, entry + 2)) / 2;
+ sensor->offset_constant = offset;
+ }
+ break;
+
+ case 0x04:
+ if (thrs_section == 0) {
+ sensor->thrs_critical.temp = (value & 0xff0) >> 4;
+ sensor->thrs_critical.hysteresis = value & 0xf;
+ }
+ break;
+
+ case 0x07:
+ if (thrs_section == 0) {
+ sensor->thrs_down_clock.temp = (value & 0xff0) >> 4;
+ sensor->thrs_down_clock.hysteresis = value & 0xf;
+ }
+ break;
+
+ case 0x08:
+ if (thrs_section == 0) {
+ sensor->thrs_fan_boost.temp = (value & 0xff0) >> 4;
+ sensor->thrs_fan_boost.hysteresis = value & 0xf;
+ }
+ break;
+
+ case 0x10:
+ if (sensor_section == 0)
+ sensor->offset_num = value;
+ break;
+
+ case 0x11:
+ if (sensor_section == 0)
+ sensor->offset_den = value;
+ break;
+
+ case 0x12:
+ if (sensor_section == 0)
+ sensor->slope_mult = value;
+ break;
+
+ case 0x13:
+ if (sensor_section == 0)
+ sensor->slope_div = value;
+ break;
+ case 0x32:
+ if (thrs_section == 0) {
+ sensor->thrs_shutdown.temp = (value & 0xff0) >> 4;
+ sensor->thrs_shutdown.hysteresis = value & 0xf;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int
+nvbios_therm_fan_parse(struct nvkm_bios *bios, struct nvbios_therm_fan *fan)
+{
+ struct nvbios_therm_trip_point *cur_trip = NULL;
+ u8 ver, len, i;
+ u16 entry;
+
+ uint8_t duty_lut[] = { 0, 0, 25, 0, 40, 0, 50, 0,
+ 75, 0, 85, 0, 100, 0, 100, 0 };
+
+ i = 0;
+ fan->nr_fan_trip = 0;
+ fan->fan_mode = NVBIOS_THERM_FAN_OTHER;
+ while ((entry = nvbios_therm_entry(bios, i++, &ver, &len))) {
+ s16 value = nv_ro16(bios, entry + 1);
+
+ switch (nv_ro08(bios, entry + 0)) {
+ case 0x22:
+ fan->min_duty = value & 0xff;
+ fan->max_duty = (value & 0xff00) >> 8;
+ break;
+ case 0x24:
+ fan->nr_fan_trip++;
+ if (fan->fan_mode > NVBIOS_THERM_FAN_TRIP)
+ fan->fan_mode = NVBIOS_THERM_FAN_TRIP;
+ cur_trip = &fan->trip[fan->nr_fan_trip - 1];
+ cur_trip->hysteresis = value & 0xf;
+ cur_trip->temp = (value & 0xff0) >> 4;
+ cur_trip->fan_duty = duty_lut[(value & 0xf000) >> 12];
+ break;
+ case 0x25:
+ cur_trip = &fan->trip[fan->nr_fan_trip - 1];
+ cur_trip->fan_duty = value;
+ break;
+ case 0x26:
+ if (!fan->pwm_freq)
+ fan->pwm_freq = value;
+ break;
+ case 0x3b:
+ fan->bump_period = value;
+ break;
+ case 0x3c:
+ fan->slow_down_period = value;
+ break;
+ case 0x46:
+ if (fan->fan_mode > NVBIOS_THERM_FAN_LINEAR)
+ fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
+ fan->linear_min_temp = nv_ro08(bios, entry + 1);
+ fan->linear_max_temp = nv_ro08(bios, entry + 2);
+ break;
+ }
+ }
+
+ /* starting from fermi, fan management is always linear */
+ if (nv_device(bios)->card_type >= NV_C0 &&
+ fan->fan_mode == NVBIOS_THERM_FAN_OTHER) {
+ fan->fan_mode = NVBIOS_THERM_FAN_LINEAR;
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c
new file mode 100644
index 000000000000..763fd29a58f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/timing.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/timing.h>
+
+u16
+nvbios_timingTe(struct nvkm_bios *bios,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, u8 *snr, u8 *ssz)
+{
+ struct bit_entry bit_P;
+ u16 timing = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 1)
+ timing = nv_ro16(bios, bit_P.offset + 4);
+ else
+ if (bit_P.version == 2)
+ timing = nv_ro16(bios, bit_P.offset + 8);
+
+ if (timing) {
+ *ver = nv_ro08(bios, timing + 0);
+ switch (*ver) {
+ case 0x10:
+ *hdr = nv_ro08(bios, timing + 1);
+ *cnt = nv_ro08(bios, timing + 2);
+ *len = nv_ro08(bios, timing + 3);
+ *snr = 0;
+ *ssz = 0;
+ return timing;
+ case 0x20:
+ *hdr = nv_ro08(bios, timing + 1);
+ *cnt = nv_ro08(bios, timing + 5);
+ *len = nv_ro08(bios, timing + 2);
+ *snr = nv_ro08(bios, timing + 4);
+ *ssz = nv_ro08(bios, timing + 3);
+ return timing;
+ default:
+ break;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_timingEe(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u8 snr, ssz;
+ u16 timing = nvbios_timingTe(bios, ver, hdr, cnt, len, &snr, &ssz);
+ if (timing && idx < *cnt) {
+ timing += *hdr + idx * (*len + (snr * ssz));
+ *hdr = *len;
+ *cnt = snr;
+ *len = ssz;
+ return timing;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_timingEp(struct nvkm_bios *bios, int idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_ramcfg *p)
+{
+ u16 data = nvbios_timingEe(bios, idx, ver, hdr, cnt, len), temp;
+ p->timing_ver = *ver;
+ p->timing_hdr = *hdr;
+ switch (!!data * *ver) {
+ case 0x10:
+ p->timing_10_WR = nv_ro08(bios, data + 0x00);
+ p->timing_10_WTR = nv_ro08(bios, data + 0x01);
+ p->timing_10_CL = nv_ro08(bios, data + 0x02);
+ p->timing_10_RC = nv_ro08(bios, data + 0x03);
+ p->timing_10_RFC = nv_ro08(bios, data + 0x05);
+ p->timing_10_RAS = nv_ro08(bios, data + 0x07);
+ p->timing_10_RP = nv_ro08(bios, data + 0x09);
+ p->timing_10_RCDRD = nv_ro08(bios, data + 0x0a);
+ p->timing_10_RCDWR = nv_ro08(bios, data + 0x0b);
+ p->timing_10_RRD = nv_ro08(bios, data + 0x0c);
+ p->timing_10_13 = nv_ro08(bios, data + 0x0d);
+ p->timing_10_ODT = nv_ro08(bios, data + 0x0e) & 0x07;
+
+ p->timing_10_24 = 0xff;
+ p->timing_10_21 = 0;
+ p->timing_10_20 = 0;
+ p->timing_10_CWL = 0;
+ p->timing_10_18 = 0;
+ p->timing_10_16 = 0;
+
+ switch (min_t(u8, *hdr, 25)) {
+ case 25:
+ p->timing_10_24 = nv_ro08(bios, data + 0x18);
+ case 24:
+ case 23:
+ case 22:
+ p->timing_10_21 = nv_ro08(bios, data + 0x15);
+ case 21:
+ p->timing_10_20 = nv_ro08(bios, data + 0x14);
+ case 20:
+ p->timing_10_CWL = nv_ro08(bios, data + 0x13);
+ case 19:
+ p->timing_10_18 = nv_ro08(bios, data + 0x12);
+ case 18:
+ case 17:
+ p->timing_10_16 = nv_ro08(bios, data + 0x10);
+ }
+
+ break;
+ case 0x20:
+ p->timing[0] = nv_ro32(bios, data + 0x00);
+ p->timing[1] = nv_ro32(bios, data + 0x04);
+ p->timing[2] = nv_ro32(bios, data + 0x08);
+ p->timing[3] = nv_ro32(bios, data + 0x0c);
+ p->timing[4] = nv_ro32(bios, data + 0x10);
+ p->timing[5] = nv_ro32(bios, data + 0x14);
+ p->timing[6] = nv_ro32(bios, data + 0x18);
+ p->timing[7] = nv_ro32(bios, data + 0x1c);
+ p->timing[8] = nv_ro32(bios, data + 0x20);
+ p->timing[9] = nv_ro32(bios, data + 0x24);
+ p->timing[10] = nv_ro32(bios, data + 0x28);
+ p->timing_20_2e_03 = (nv_ro08(bios, data + 0x2e) & 0x03) >> 0;
+ p->timing_20_2e_30 = (nv_ro08(bios, data + 0x2e) & 0x30) >> 4;
+ p->timing_20_2e_c0 = (nv_ro08(bios, data + 0x2e) & 0xc0) >> 6;
+ p->timing_20_2f_03 = (nv_ro08(bios, data + 0x2f) & 0x03) >> 0;
+ temp = nv_ro16(bios, data + 0x2c);
+ p->timing_20_2c_003f = (temp & 0x003f) >> 0;
+ p->timing_20_2c_1fc0 = (temp & 0x1fc0) >> 6;
+ p->timing_20_30_07 = (nv_ro08(bios, data + 0x30) & 0x07) >> 0;
+ p->timing_20_30_f8 = (nv_ro08(bios, data + 0x30) & 0xf8) >> 3;
+ temp = nv_ro16(bios, data + 0x31);
+ p->timing_20_31_0007 = (temp & 0x0007) >> 0;
+ p->timing_20_31_0078 = (temp & 0x0078) >> 3;
+ p->timing_20_31_0780 = (temp & 0x0780) >> 7;
+ p->timing_20_31_0800 = (temp & 0x0800) >> 11;
+ p->timing_20_31_7000 = (temp & 0x7000) >> 12;
+ p->timing_20_31_8000 = (temp & 0x8000) >> 15;
+ break;
+ default:
+ data = 0;
+ break;
+ }
+ return data;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
new file mode 100644
index 000000000000..e95b69faa82e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/vmap.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/vmap.h>
+
+u16
+nvbios_vmap_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry bit_P;
+ u16 vmap = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2) {
+ vmap = nv_ro16(bios, bit_P.offset + 0x20);
+ if (vmap) {
+ *ver = nv_ro08(bios, vmap + 0);
+ switch (*ver) {
+ case 0x10:
+ case 0x20:
+ *hdr = nv_ro08(bios, vmap + 1);
+ *cnt = nv_ro08(bios, vmap + 3);
+ *len = nv_ro08(bios, vmap + 2);
+ return vmap;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_vmap_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_vmap *info)
+{
+ u16 vmap = nvbios_vmap_table(bios, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!vmap * *ver) {
+ case 0x10:
+ case 0x20:
+ break;
+ }
+ return vmap;
+}
+
+u16
+nvbios_vmap_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u16 vmap = nvbios_vmap_table(bios, ver, &hdr, &cnt, len);
+ if (vmap && idx < cnt) {
+ vmap = vmap + hdr + (idx * *len);
+ return vmap;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_vmap_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
+ struct nvbios_vmap_entry *info)
+{
+ u16 vmap = nvbios_vmap_entry(bios, idx, ver, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!vmap * *ver) {
+ case 0x10:
+ info->link = 0xff;
+ info->min = nv_ro32(bios, vmap + 0x00);
+ info->max = nv_ro32(bios, vmap + 0x04);
+ info->arg[0] = nv_ro32(bios, vmap + 0x08);
+ info->arg[1] = nv_ro32(bios, vmap + 0x0c);
+ info->arg[2] = nv_ro32(bios, vmap + 0x10);
+ break;
+ case 0x20:
+ info->unk0 = nv_ro08(bios, vmap + 0x00);
+ info->link = nv_ro08(bios, vmap + 0x01);
+ info->min = nv_ro32(bios, vmap + 0x02);
+ info->max = nv_ro32(bios, vmap + 0x06);
+ info->arg[0] = nv_ro32(bios, vmap + 0x0a);
+ info->arg[1] = nv_ro32(bios, vmap + 0x0e);
+ info->arg[2] = nv_ro32(bios, vmap + 0x12);
+ info->arg[3] = nv_ro32(bios, vmap + 0x16);
+ info->arg[4] = nv_ro32(bios, vmap + 0x1a);
+ info->arg[5] = nv_ro32(bios, vmap + 0x1e);
+ break;
+ }
+ return vmap;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
new file mode 100644
index 000000000000..8454ab7c4a3d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/volt.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/volt.h>
+
+u16
+nvbios_volt_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ struct bit_entry bit_P;
+ u16 volt = 0x0000;
+
+ if (!bit_entry(bios, 'P', &bit_P)) {
+ if (bit_P.version == 2)
+ volt = nv_ro16(bios, bit_P.offset + 0x0c);
+ else
+ if (bit_P.version == 1)
+ volt = nv_ro16(bios, bit_P.offset + 0x10);
+
+ if (volt) {
+ *ver = nv_ro08(bios, volt + 0);
+ switch (*ver) {
+ case 0x12:
+ *hdr = 5;
+ *cnt = nv_ro08(bios, volt + 2);
+ *len = nv_ro08(bios, volt + 1);
+ return volt;
+ case 0x20:
+ *hdr = nv_ro08(bios, volt + 1);
+ *cnt = nv_ro08(bios, volt + 2);
+ *len = nv_ro08(bios, volt + 3);
+ return volt;
+ case 0x30:
+ case 0x40:
+ case 0x50:
+ *hdr = nv_ro08(bios, volt + 1);
+ *cnt = nv_ro08(bios, volt + 3);
+ *len = nv_ro08(bios, volt + 2);
+ return volt;
+ }
+ }
+ }
+
+ return 0x0000;
+}
+
+u16
+nvbios_volt_parse(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len,
+ struct nvbios_volt *info)
+{
+ u16 volt = nvbios_volt_table(bios, ver, hdr, cnt, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!volt * *ver) {
+ case 0x12:
+ info->vidmask = nv_ro08(bios, volt + 0x04);
+ break;
+ case 0x20:
+ info->vidmask = nv_ro08(bios, volt + 0x05);
+ break;
+ case 0x30:
+ info->vidmask = nv_ro08(bios, volt + 0x04);
+ break;
+ case 0x40:
+ info->base = nv_ro32(bios, volt + 0x04);
+ info->step = nv_ro16(bios, volt + 0x08);
+ info->vidmask = nv_ro08(bios, volt + 0x0b);
+ /*XXX*/
+ info->min = 0;
+ info->max = info->base;
+ break;
+ case 0x50:
+ info->vidmask = nv_ro08(bios, volt + 0x06);
+ info->min = nv_ro32(bios, volt + 0x0a);
+ info->max = nv_ro32(bios, volt + 0x0e);
+ info->base = nv_ro32(bios, volt + 0x12) & 0x00ffffff;
+ info->step = nv_ro16(bios, volt + 0x16);
+ break;
+ }
+ return volt;
+}
+
+u16
+nvbios_volt_entry(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len)
+{
+ u8 hdr, cnt;
+ u16 volt = nvbios_volt_table(bios, ver, &hdr, &cnt, len);
+ if (volt && idx < cnt) {
+ volt = volt + hdr + (idx * *len);
+ return volt;
+ }
+ return 0x0000;
+}
+
+u16
+nvbios_volt_entry_parse(struct nvkm_bios *bios, int idx, u8 *ver, u8 *len,
+ struct nvbios_volt_entry *info)
+{
+ u16 volt = nvbios_volt_entry(bios, idx, ver, len);
+ memset(info, 0x00, sizeof(*info));
+ switch (!!volt * *ver) {
+ case 0x12:
+ case 0x20:
+ info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
+ info->vid = nv_ro08(bios, volt + 0x01);
+ break;
+ case 0x30:
+ info->voltage = nv_ro08(bios, volt + 0x00) * 10000;
+ info->vid = nv_ro08(bios, volt + 0x01) >> 2;
+ break;
+ case 0x40:
+ case 0x50:
+ break;
+ }
+ return volt;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c
new file mode 100644
index 000000000000..63a5e1b5cb3c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bios/xpio.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/bios.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/xpio.h>
+
+static u16
+dcb_xpiod_table(struct nvkm_bios *bios, u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u16 data = dcb_gpio_table(bios, ver, hdr, cnt, len);
+ if (data && *ver >= 0x40 && *hdr >= 0x06) {
+ u16 xpio = nv_ro16(bios, data + 0x04);
+ if (xpio) {
+ *ver = nv_ro08(bios, data + 0x00);
+ *hdr = nv_ro08(bios, data + 0x01);
+ *cnt = nv_ro08(bios, data + 0x02);
+ *len = nv_ro08(bios, data + 0x03);
+ return xpio;
+ }
+ }
+ return 0x0000;
+}
+
+u16
+dcb_xpio_table(struct nvkm_bios *bios, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len)
+{
+ u16 data = dcb_xpiod_table(bios, ver, hdr, cnt, len);
+ if (data && idx < *cnt) {
+ u16 xpio = nv_ro16(bios, data + *hdr + (idx * *len));
+ if (xpio) {
+ *ver = nv_ro08(bios, data + 0x00);
+ *hdr = nv_ro08(bios, data + 0x01);
+ *cnt = nv_ro08(bios, data + 0x02);
+ *len = nv_ro08(bios, data + 0x03);
+ return xpio;
+ }
+ }
+ return 0x0000;
+}
+
+u16
+dcb_xpio_parse(struct nvkm_bios *bios, u8 idx,
+ u8 *ver, u8 *hdr, u8 *cnt, u8 *len, struct nvbios_xpio *info)
+{
+ u16 data = dcb_xpio_table(bios, idx, ver, hdr, cnt, len);
+ if (data && *len >= 6) {
+ info->type = nv_ro08(bios, data + 0x04);
+ info->addr = nv_ro08(bios, data + 0x05);
+ info->flags = nv_ro08(bios, data + 0x06);
+ }
+ return 0x0000;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild
new file mode 100644
index 000000000000..83d80b13f149
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/Kbuild
@@ -0,0 +1,6 @@
+nvkm-y += nvkm/subdev/bus/hwsq.o
+nvkm-y += nvkm/subdev/bus/nv04.o
+nvkm-y += nvkm/subdev/bus/nv31.o
+nvkm-y += nvkm/subdev/bus/nv50.o
+nvkm-y += nvkm/subdev/bus/g94.o
+nvkm-y += nvkm/subdev/bus/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c
new file mode 100644
index 000000000000..cbe699e82593
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/g94.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ * Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <subdev/timer.h>
+
+static int
+g94_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size)
+{
+ struct nv50_bus_priv *priv = (void *)pbus;
+ int i;
+
+ nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
+ nv_wr32(pbus, 0x001304, 0x00000000);
+ nv_wr32(pbus, 0x001318, 0x00000000);
+ for (i = 0; i < size; i++)
+ nv_wr32(priv, 0x080000 + (i * 4), data[i]);
+ nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
+ nv_wr32(pbus, 0x00130c, 0x00000001);
+
+ return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
+}
+
+struct nvkm_oclass *
+g94_bus_oclass = &(struct nv04_bus_impl) {
+ .base.handle = NV_SUBDEV(BUS, 0x94),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_bus_ctor,
+ .dtor = _nvkm_bus_dtor,
+ .init = nv50_bus_init,
+ .fini = _nvkm_bus_fini,
+ },
+ .intr = nv50_bus_intr,
+ .hwsq_exec = g94_bus_hwsq_exec,
+ .hwsq_size = 128,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c
new file mode 100644
index 000000000000..ebc63ba968d4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/gf100.c
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ * Ben Skeggs
+ */
+#include "nv04.h"
+
+static void
+gf100_bus_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_bus *pbus = nvkm_bus(subdev);
+ u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+
+ if (stat & 0x0000000e) {
+ u32 addr = nv_rd32(pbus, 0x009084);
+ u32 data = nv_rd32(pbus, 0x009088);
+
+ nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x [ %s%s%s]\n",
+ (addr & 0x00000002) ? "write" : "read", data,
+ (addr & 0x00fffffc),
+ (stat & 0x00000002) ? "!ENGINE " : "",
+ (stat & 0x00000004) ? "IBUS " : "",
+ (stat & 0x00000008) ? "TIMEOUT " : "");
+
+ nv_wr32(pbus, 0x009084, 0x00000000);
+ nv_wr32(pbus, 0x001100, (stat & 0x0000000e));
+ stat &= ~0x0000000e;
+ }
+
+ if (stat) {
+ nv_error(pbus, "unknown intr 0x%08x\n", stat);
+ nv_mask(pbus, 0x001140, stat, 0x00000000);
+ }
+}
+
+static int
+gf100_bus_init(struct nvkm_object *object)
+{
+ struct nv04_bus_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_bus_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x001100, 0xffffffff);
+ nv_wr32(priv, 0x001140, 0x0000000e);
+ return 0;
+}
+
+struct nvkm_oclass *
+gf100_bus_oclass = &(struct nv04_bus_impl) {
+ .base.handle = NV_SUBDEV(BUS, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_bus_ctor,
+ .dtor = _nvkm_bus_dtor,
+ .init = gf100_bus_init,
+ .fini = _nvkm_bus_fini,
+ },
+ .intr = gf100_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c
new file mode 100644
index 000000000000..b8853bf16b23
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.c
@@ -0,0 +1,143 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include <subdev/bus.h>
+
+struct nvkm_hwsq {
+ struct nvkm_bus *pbus;
+ u32 addr;
+ u32 data;
+ struct {
+ u8 data[512];
+ u8 size;
+ } c;
+};
+
+static void
+hwsq_cmd(struct nvkm_hwsq *hwsq, int size, u8 data[])
+{
+ memcpy(&hwsq->c.data[hwsq->c.size], data, size * sizeof(data[0]));
+ hwsq->c.size += size;
+}
+
+int
+nvkm_hwsq_init(struct nvkm_bus *pbus, struct nvkm_hwsq **phwsq)
+{
+ struct nvkm_hwsq *hwsq;
+
+ hwsq = *phwsq = kmalloc(sizeof(*hwsq), GFP_KERNEL);
+ if (hwsq) {
+ hwsq->pbus = pbus;
+ hwsq->addr = ~0;
+ hwsq->data = ~0;
+ memset(hwsq->c.data, 0x7f, sizeof(hwsq->c.data));
+ hwsq->c.size = 0;
+ }
+
+ return hwsq ? 0 : -ENOMEM;
+}
+
+int
+nvkm_hwsq_fini(struct nvkm_hwsq **phwsq, bool exec)
+{
+ struct nvkm_hwsq *hwsq = *phwsq;
+ int ret = 0, i;
+ if (hwsq) {
+ struct nvkm_bus *pbus = hwsq->pbus;
+ hwsq->c.size = (hwsq->c.size + 4) / 4;
+ if (hwsq->c.size <= pbus->hwsq_size) {
+ if (exec)
+ ret = pbus->hwsq_exec(pbus, (u32 *)hwsq->c.data,
+ hwsq->c.size);
+ if (ret)
+ nv_error(pbus, "hwsq exec failed: %d\n", ret);
+ } else {
+ nv_error(pbus, "hwsq ucode too large\n");
+ ret = -ENOSPC;
+ }
+
+ for (i = 0; ret && i < hwsq->c.size; i++)
+ nv_error(pbus, "\t0x%08x\n", ((u32 *)hwsq->c.data)[i]);
+
+ *phwsq = NULL;
+ kfree(hwsq);
+ }
+ return ret;
+}
+
+void
+nvkm_hwsq_wr32(struct nvkm_hwsq *hwsq, u32 addr, u32 data)
+{
+ nv_debug(hwsq->pbus, "R[%06x] = 0x%08x\n", addr, data);
+
+ if (hwsq->data != data) {
+ if ((data & 0xffff0000) != (hwsq->data & 0xffff0000)) {
+ hwsq_cmd(hwsq, 5, (u8[]){ 0xe2, data, data >> 8,
+ data >> 16, data >> 24 });
+ } else {
+ hwsq_cmd(hwsq, 3, (u8[]){ 0x42, data, data >> 8 });
+ }
+ }
+
+ if ((addr & 0xffff0000) != (hwsq->addr & 0xffff0000)) {
+ hwsq_cmd(hwsq, 5, (u8[]){ 0xe0, addr, addr >> 8,
+ addr >> 16, addr >> 24 });
+ } else {
+ hwsq_cmd(hwsq, 3, (u8[]){ 0x40, addr, addr >> 8 });
+ }
+
+ hwsq->addr = addr;
+ hwsq->data = data;
+}
+
+void
+nvkm_hwsq_setf(struct nvkm_hwsq *hwsq, u8 flag, int data)
+{
+ nv_debug(hwsq->pbus, " FLAG[%02x] = %d\n", flag, data);
+ flag += 0x80;
+ if (data >= 0)
+ flag += 0x20;
+ if (data >= 1)
+ flag += 0x20;
+ hwsq_cmd(hwsq, 1, (u8[]){ flag });
+}
+
+void
+nvkm_hwsq_wait(struct nvkm_hwsq *hwsq, u8 flag, u8 data)
+{
+ nv_debug(hwsq->pbus, " WAIT[%02x] = %d\n", flag, data);
+ hwsq_cmd(hwsq, 3, (u8[]){ 0x5f, flag, data });
+}
+
+void
+nvkm_hwsq_nsec(struct nvkm_hwsq *hwsq, u32 nsec)
+{
+ u8 shift = 0, usec = nsec / 1000;
+ while (usec & ~3) {
+ usec >>= 2;
+ shift++;
+ }
+
+ nv_debug(hwsq->pbus, " DELAY = %d ns\n", nsec);
+ hwsq_cmd(hwsq, 1, (u8[]){ 0x00 | (shift << 2) | usec });
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
new file mode 100644
index 000000000000..3394a5ea8a9f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/hwsq.h
@@ -0,0 +1,111 @@
+#ifndef __NVKM_BUS_HWSQ_H__
+#define __NVKM_BUS_HWSQ_H__
+#include <subdev/bus.h>
+
+struct hwsq {
+ struct nvkm_subdev *subdev;
+ struct nvkm_hwsq *hwsq;
+ int sequence;
+};
+
+struct hwsq_reg {
+ int sequence;
+ bool force;
+ u32 addr[2];
+ u32 data;
+};
+
+static inline struct hwsq_reg
+hwsq_reg2(u32 addr1, u32 addr2)
+{
+ return (struct hwsq_reg) {
+ .sequence = 0,
+ .force = 0,
+ .addr = { addr1, addr2 },
+ .data = 0xdeadbeef,
+ };
+}
+
+static inline struct hwsq_reg
+hwsq_reg(u32 addr)
+{
+ return hwsq_reg2(addr, addr);
+}
+
+static inline int
+hwsq_init(struct hwsq *ram, struct nvkm_subdev *subdev)
+{
+ struct nvkm_bus *pbus = nvkm_bus(subdev);
+ int ret;
+
+ ret = nvkm_hwsq_init(pbus, &ram->hwsq);
+ if (ret)
+ return ret;
+
+ ram->sequence++;
+ ram->subdev = subdev;
+ return 0;
+}
+
+static inline int
+hwsq_exec(struct hwsq *ram, bool exec)
+{
+ int ret = 0;
+ if (ram->subdev) {
+ ret = nvkm_hwsq_fini(&ram->hwsq, exec);
+ ram->subdev = NULL;
+ }
+ return ret;
+}
+
+static inline u32
+hwsq_rd32(struct hwsq *ram, struct hwsq_reg *reg)
+{
+ if (reg->sequence != ram->sequence)
+ reg->data = nv_rd32(ram->subdev, reg->addr[0]);
+ return reg->data;
+}
+
+static inline void
+hwsq_wr32(struct hwsq *ram, struct hwsq_reg *reg, u32 data)
+{
+ reg->sequence = ram->sequence;
+ reg->data = data;
+ if (reg->addr[0] != reg->addr[1])
+ nvkm_hwsq_wr32(ram->hwsq, reg->addr[1], reg->data);
+ nvkm_hwsq_wr32(ram->hwsq, reg->addr[0], reg->data);
+}
+
+static inline void
+hwsq_nuke(struct hwsq *ram, struct hwsq_reg *reg)
+{
+ reg->force = true;
+}
+
+static inline u32
+hwsq_mask(struct hwsq *ram, struct hwsq_reg *reg, u32 mask, u32 data)
+{
+ u32 temp = hwsq_rd32(ram, reg);
+ if (temp != ((temp & ~mask) | data) || reg->force)
+ hwsq_wr32(ram, reg, (temp & ~mask) | data);
+ return temp;
+}
+
+static inline void
+hwsq_setf(struct hwsq *ram, u8 flag, int data)
+{
+ nvkm_hwsq_setf(ram->hwsq, flag, data);
+}
+
+static inline void
+hwsq_wait(struct hwsq *ram, u8 flag, u8 data)
+{
+ nvkm_hwsq_wait(ram->hwsq, flag, data);
+}
+
+static inline void
+hwsq_nsec(struct hwsq *ram, u32 nsec)
+{
+ nvkm_hwsq_nsec(ram->hwsq, nsec);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c
new file mode 100644
index 000000000000..19c8e50eeff7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ * Ben Skeggs
+ */
+#include "nv04.h"
+
+static void
+nv04_bus_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_bus *pbus = nvkm_bus(subdev);
+ u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+
+ if (stat & 0x00000001) {
+ nv_error(pbus, "BUS ERROR\n");
+ stat &= ~0x00000001;
+ nv_wr32(pbus, 0x001100, 0x00000001);
+ }
+
+ if (stat & 0x00000110) {
+ subdev = nvkm_subdev(subdev, NVDEV_SUBDEV_GPIO);
+ if (subdev && subdev->intr)
+ subdev->intr(subdev);
+ stat &= ~0x00000110;
+ nv_wr32(pbus, 0x001100, 0x00000110);
+ }
+
+ if (stat) {
+ nv_error(pbus, "unknown intr 0x%08x\n", stat);
+ nv_mask(pbus, 0x001140, stat, 0x00000000);
+ }
+}
+
+static int
+nv04_bus_init(struct nvkm_object *object)
+{
+ struct nv04_bus_priv *priv = (void *)object;
+
+ nv_wr32(priv, 0x001100, 0xffffffff);
+ nv_wr32(priv, 0x001140, 0x00000111);
+
+ return nvkm_bus_init(&priv->base);
+}
+
+int
+nv04_bus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_bus_impl *impl = (void *)oclass;
+ struct nv04_bus_priv *priv;
+ int ret;
+
+ ret = nvkm_bus_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->intr = impl->intr;
+ priv->base.hwsq_exec = impl->hwsq_exec;
+ priv->base.hwsq_size = impl->hwsq_size;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_bus_oclass = &(struct nv04_bus_impl) {
+ .base.handle = NV_SUBDEV(BUS, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_bus_ctor,
+ .dtor = _nvkm_bus_dtor,
+ .init = nv04_bus_init,
+ .fini = _nvkm_bus_fini,
+ },
+ .intr = nv04_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h
new file mode 100644
index 000000000000..3ddc8f91b1e3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv04.h
@@ -0,0 +1,21 @@
+#ifndef __NVKM_BUS_NV04_H__
+#define __NVKM_BUS_NV04_H__
+#include <subdev/bus.h>
+
+struct nv04_bus_priv {
+ struct nvkm_bus base;
+};
+
+int nv04_bus_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+int nv50_bus_init(struct nvkm_object *);
+void nv50_bus_intr(struct nvkm_subdev *);
+
+struct nv04_bus_impl {
+ struct nvkm_oclass base;
+ void (*intr)(struct nvkm_subdev *);
+ int (*hwsq_exec)(struct nvkm_bus *, u32 *, u32);
+ u32 hwsq_size;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c
new file mode 100644
index 000000000000..c5739bce8052
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv31.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ * Ben Skeggs
+ */
+#include "nv04.h"
+
+static void
+nv31_bus_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_bus *pbus = nvkm_bus(subdev);
+ u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+ u32 gpio = nv_rd32(pbus, 0x001104) & nv_rd32(pbus, 0x001144);
+
+ if (gpio) {
+ subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_GPIO);
+ if (subdev && subdev->intr)
+ subdev->intr(subdev);
+ }
+
+ if (stat & 0x00000008) { /* NV41- */
+ u32 addr = nv_rd32(pbus, 0x009084);
+ u32 data = nv_rd32(pbus, 0x009088);
+
+ nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
+ (addr & 0x00000002) ? "write" : "read", data,
+ (addr & 0x00fffffc));
+
+ stat &= ~0x00000008;
+ nv_wr32(pbus, 0x001100, 0x00000008);
+ }
+
+ if (stat & 0x00070000) {
+ subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM);
+ if (subdev && subdev->intr)
+ subdev->intr(subdev);
+ stat &= ~0x00070000;
+ nv_wr32(pbus, 0x001100, 0x00070000);
+ }
+
+ if (stat) {
+ nv_error(pbus, "unknown intr 0x%08x\n", stat);
+ nv_mask(pbus, 0x001140, stat, 0x00000000);
+ }
+}
+
+static int
+nv31_bus_init(struct nvkm_object *object)
+{
+ struct nv04_bus_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_bus_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x001100, 0xffffffff);
+ nv_wr32(priv, 0x001140, 0x00070008);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv31_bus_oclass = &(struct nv04_bus_impl) {
+ .base.handle = NV_SUBDEV(BUS, 0x31),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_bus_ctor,
+ .dtor = _nvkm_bus_dtor,
+ .init = nv31_bus_init,
+ .fini = _nvkm_bus_fini,
+ },
+ .intr = nv31_bus_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c
new file mode 100644
index 000000000000..1987863d71ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/bus/nv50.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2012 Nouveau Community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres <martin.peres@labri.fr>
+ * Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <subdev/timer.h>
+
+static int
+nv50_bus_hwsq_exec(struct nvkm_bus *pbus, u32 *data, u32 size)
+{
+ struct nv50_bus_priv *priv = (void *)pbus;
+ int i;
+
+ nv_mask(pbus, 0x001098, 0x00000008, 0x00000000);
+ nv_wr32(pbus, 0x001304, 0x00000000);
+ for (i = 0; i < size; i++)
+ nv_wr32(priv, 0x001400 + (i * 4), data[i]);
+ nv_mask(pbus, 0x001098, 0x00000018, 0x00000018);
+ nv_wr32(pbus, 0x00130c, 0x00000003);
+
+ return nv_wait(pbus, 0x001308, 0x00000100, 0x00000000) ? 0 : -ETIMEDOUT;
+}
+
+void
+nv50_bus_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_bus *pbus = nvkm_bus(subdev);
+ u32 stat = nv_rd32(pbus, 0x001100) & nv_rd32(pbus, 0x001140);
+
+ if (stat & 0x00000008) {
+ u32 addr = nv_rd32(pbus, 0x009084);
+ u32 data = nv_rd32(pbus, 0x009088);
+
+ nv_error(pbus, "MMIO %s of 0x%08x FAULT at 0x%06x\n",
+ (addr & 0x00000002) ? "write" : "read", data,
+ (addr & 0x00fffffc));
+
+ stat &= ~0x00000008;
+ nv_wr32(pbus, 0x001100, 0x00000008);
+ }
+
+ if (stat & 0x00010000) {
+ subdev = nvkm_subdev(pbus, NVDEV_SUBDEV_THERM);
+ if (subdev && subdev->intr)
+ subdev->intr(subdev);
+ stat &= ~0x00010000;
+ nv_wr32(pbus, 0x001100, 0x00010000);
+ }
+
+ if (stat) {
+ nv_error(pbus, "unknown intr 0x%08x\n", stat);
+ nv_mask(pbus, 0x001140, stat, 0);
+ }
+}
+
+int
+nv50_bus_init(struct nvkm_object *object)
+{
+ struct nv04_bus_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_bus_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x001100, 0xffffffff);
+ nv_wr32(priv, 0x001140, 0x00010008);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_bus_oclass = &(struct nv04_bus_impl) {
+ .base.handle = NV_SUBDEV(BUS, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_bus_ctor,
+ .dtor = _nvkm_bus_dtor,
+ .init = nv50_bus_init,
+ .fini = _nvkm_bus_fini,
+ },
+ .intr = nv50_bus_intr,
+ .hwsq_exec = nv50_bus_hwsq_exec,
+ .hwsq_size = 64,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild
new file mode 100644
index 000000000000..9c2f688c9602
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/Kbuild
@@ -0,0 +1,12 @@
+nvkm-y += nvkm/subdev/clk/base.o
+nvkm-y += nvkm/subdev/clk/nv04.o
+nvkm-y += nvkm/subdev/clk/nv40.o
+nvkm-y += nvkm/subdev/clk/nv50.o
+nvkm-y += nvkm/subdev/clk/g84.o
+nvkm-y += nvkm/subdev/clk/gt215.o
+nvkm-y += nvkm/subdev/clk/mcp77.o
+nvkm-y += nvkm/subdev/clk/gf100.o
+nvkm-y += nvkm/subdev/clk/gk104.o
+nvkm-y += nvkm/subdev/clk/gk20a.o
+nvkm-y += nvkm/subdev/clk/pllnv04.o
+nvkm-y += nvkm/subdev/clk/pllgt215.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
new file mode 100644
index 000000000000..b24a9cc04b73
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/base.c
@@ -0,0 +1,591 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include <subdev/bios.h>
+#include <subdev/bios/boost.h>
+#include <subdev/bios/cstep.h>
+#include <subdev/bios/perf.h>
+#include <subdev/fb.h>
+#include <subdev/therm.h>
+#include <subdev/volt.h>
+
+#include <core/device.h>
+#include <core/option.h>
+
+/******************************************************************************
+ * misc
+ *****************************************************************************/
+static u32
+nvkm_clk_adjust(struct nvkm_clk *clk, bool adjust,
+ u8 pstate, u8 domain, u32 input)
+{
+ struct nvkm_bios *bios = nvkm_bios(clk);
+ struct nvbios_boostE boostE;
+ u8 ver, hdr, cnt, len;
+ u16 data;
+
+ data = nvbios_boostEm(bios, pstate, &ver, &hdr, &cnt, &len, &boostE);
+ if (data) {
+ struct nvbios_boostS boostS;
+ u8 idx = 0, sver, shdr;
+ u16 subd;
+
+ input = max(boostE.min, input);
+ input = min(boostE.max, input);
+ do {
+ sver = ver;
+ shdr = hdr;
+ subd = nvbios_boostSp(bios, idx++, data, &sver, &shdr,
+ cnt, len, &boostS);
+ if (subd && boostS.domain == domain) {
+ if (adjust)
+ input = input * boostS.percent / 100;
+ input = max(boostS.min, input);
+ input = min(boostS.max, input);
+ break;
+ }
+ } while (subd);
+ }
+
+ return input;
+}
+
+/******************************************************************************
+ * C-States
+ *****************************************************************************/
+static int
+nvkm_cstate_prog(struct nvkm_clk *clk, struct nvkm_pstate *pstate, int cstatei)
+{
+ struct nvkm_therm *ptherm = nvkm_therm(clk);
+ struct nvkm_volt *volt = nvkm_volt(clk);
+ struct nvkm_cstate *cstate;
+ int ret;
+
+ if (!list_empty(&pstate->list)) {
+ cstate = list_entry(pstate->list.prev, typeof(*cstate), head);
+ } else {
+ cstate = &pstate->base;
+ }
+
+ if (ptherm) {
+ ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, +1);
+ if (ret && ret != -ENODEV) {
+ nv_error(clk, "failed to raise fan speed: %d\n", ret);
+ return ret;
+ }
+ }
+
+ if (volt) {
+ ret = volt->set_id(volt, cstate->voltage, +1);
+ if (ret && ret != -ENODEV) {
+ nv_error(clk, "failed to raise voltage: %d\n", ret);
+ return ret;
+ }
+ }
+
+ ret = clk->calc(clk, cstate);
+ if (ret == 0) {
+ ret = clk->prog(clk);
+ clk->tidy(clk);
+ }
+
+ if (volt) {
+ ret = volt->set_id(volt, cstate->voltage, -1);
+ if (ret && ret != -ENODEV)
+ nv_error(clk, "failed to lower voltage: %d\n", ret);
+ }
+
+ if (ptherm) {
+ ret = nvkm_therm_cstate(ptherm, pstate->fanspeed, -1);
+ if (ret && ret != -ENODEV)
+ nv_error(clk, "failed to lower fan speed: %d\n", ret);
+ }
+
+ return 0;
+}
+
+static void
+nvkm_cstate_del(struct nvkm_cstate *cstate)
+{
+ list_del(&cstate->head);
+ kfree(cstate);
+}
+
+static int
+nvkm_cstate_new(struct nvkm_clk *clk, int idx, struct nvkm_pstate *pstate)
+{
+ struct nvkm_bios *bios = nvkm_bios(clk);
+ struct nvkm_domain *domain = clk->domains;
+ struct nvkm_cstate *cstate = NULL;
+ struct nvbios_cstepX cstepX;
+ u8 ver, hdr;
+ u16 data;
+
+ data = nvbios_cstepXp(bios, idx, &ver, &hdr, &cstepX);
+ if (!data)
+ return -ENOENT;
+
+ cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
+ if (!cstate)
+ return -ENOMEM;
+
+ *cstate = pstate->base;
+ cstate->voltage = cstepX.voltage;
+
+ while (domain && domain->name != nv_clk_src_max) {
+ if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
+ u32 freq = nvkm_clk_adjust(clk, true, pstate->pstate,
+ domain->bios, cstepX.freq);
+ cstate->domain[domain->name] = freq;
+ }
+ domain++;
+ }
+
+ list_add(&cstate->head, &pstate->list);
+ return 0;
+}
+
+/******************************************************************************
+ * P-States
+ *****************************************************************************/
+static int
+nvkm_pstate_prog(struct nvkm_clk *clk, int pstatei)
+{
+ struct nvkm_fb *pfb = nvkm_fb(clk);
+ struct nvkm_pstate *pstate;
+ int ret, idx = 0;
+
+ list_for_each_entry(pstate, &clk->states, head) {
+ if (idx++ == pstatei)
+ break;
+ }
+
+ nv_debug(clk, "setting performance state %d\n", pstatei);
+ clk->pstate = pstatei;
+
+ if (pfb->ram->calc) {
+ int khz = pstate->base.domain[nv_clk_src_mem];
+ do {
+ ret = pfb->ram->calc(pfb, khz);
+ if (ret == 0)
+ ret = pfb->ram->prog(pfb);
+ } while (ret > 0);
+ pfb->ram->tidy(pfb);
+ }
+
+ return nvkm_cstate_prog(clk, pstate, 0);
+}
+
+static void
+nvkm_pstate_work(struct work_struct *work)
+{
+ struct nvkm_clk *clk = container_of(work, typeof(*clk), work);
+ int pstate;
+
+ if (!atomic_xchg(&clk->waiting, 0))
+ return;
+ clk->pwrsrc = power_supply_is_system_supplied();
+
+ nv_trace(clk, "P %d PWR %d U(AC) %d U(DC) %d A %d T %d D %d\n",
+ clk->pstate, clk->pwrsrc, clk->ustate_ac, clk->ustate_dc,
+ clk->astate, clk->tstate, clk->dstate);
+
+ pstate = clk->pwrsrc ? clk->ustate_ac : clk->ustate_dc;
+ if (clk->state_nr && pstate != -1) {
+ pstate = (pstate < 0) ? clk->astate : pstate;
+ pstate = min(pstate, clk->state_nr - 1 - clk->tstate);
+ pstate = max(pstate, clk->dstate);
+ } else {
+ pstate = clk->pstate = -1;
+ }
+
+ nv_trace(clk, "-> %d\n", pstate);
+ if (pstate != clk->pstate) {
+ int ret = nvkm_pstate_prog(clk, pstate);
+ if (ret) {
+ nv_error(clk, "error setting pstate %d: %d\n",
+ pstate, ret);
+ }
+ }
+
+ wake_up_all(&clk->wait);
+ nvkm_notify_get(&clk->pwrsrc_ntfy);
+}
+
+static int
+nvkm_pstate_calc(struct nvkm_clk *clk, bool wait)
+{
+ atomic_set(&clk->waiting, 1);
+ schedule_work(&clk->work);
+ if (wait)
+ wait_event(clk->wait, !atomic_read(&clk->waiting));
+ return 0;
+}
+
+static void
+nvkm_pstate_info(struct nvkm_clk *clk, struct nvkm_pstate *pstate)
+{
+ struct nvkm_domain *clock = clk->domains - 1;
+ struct nvkm_cstate *cstate;
+ char info[3][32] = { "", "", "" };
+ char name[4] = "--";
+ int i = -1;
+
+ if (pstate->pstate != 0xff)
+ snprintf(name, sizeof(name), "%02x", pstate->pstate);
+
+ while ((++clock)->name != nv_clk_src_max) {
+ u32 lo = pstate->base.domain[clock->name];
+ u32 hi = lo;
+ if (hi == 0)
+ continue;
+
+ nv_debug(clk, "%02x: %10d KHz\n", clock->name, lo);
+ list_for_each_entry(cstate, &pstate->list, head) {
+ u32 freq = cstate->domain[clock->name];
+ lo = min(lo, freq);
+ hi = max(hi, freq);
+ nv_debug(clk, "%10d KHz\n", freq);
+ }
+
+ if (clock->mname && ++i < ARRAY_SIZE(info)) {
+ lo /= clock->mdiv;
+ hi /= clock->mdiv;
+ if (lo == hi) {
+ snprintf(info[i], sizeof(info[i]), "%s %d MHz",
+ clock->mname, lo);
+ } else {
+ snprintf(info[i], sizeof(info[i]),
+ "%s %d-%d MHz", clock->mname, lo, hi);
+ }
+ }
+ }
+
+ nv_info(clk, "%s: %s %s %s\n", name, info[0], info[1], info[2]);
+}
+
+static void
+nvkm_pstate_del(struct nvkm_pstate *pstate)
+{
+ struct nvkm_cstate *cstate, *temp;
+
+ list_for_each_entry_safe(cstate, temp, &pstate->list, head) {
+ nvkm_cstate_del(cstate);
+ }
+
+ list_del(&pstate->head);
+ kfree(pstate);
+}
+
+static int
+nvkm_pstate_new(struct nvkm_clk *clk, int idx)
+{
+ struct nvkm_bios *bios = nvkm_bios(clk);
+ struct nvkm_domain *domain = clk->domains - 1;
+ struct nvkm_pstate *pstate;
+ struct nvkm_cstate *cstate;
+ struct nvbios_cstepE cstepE;
+ struct nvbios_perfE perfE;
+ u8 ver, hdr, cnt, len;
+ u16 data;
+
+ data = nvbios_perfEp(bios, idx, &ver, &hdr, &cnt, &len, &perfE);
+ if (!data)
+ return -EINVAL;
+ if (perfE.pstate == 0xff)
+ return 0;
+
+ pstate = kzalloc(sizeof(*pstate), GFP_KERNEL);
+ cstate = &pstate->base;
+ if (!pstate)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&pstate->list);
+
+ pstate->pstate = perfE.pstate;
+ pstate->fanspeed = perfE.fanspeed;
+ cstate->voltage = perfE.voltage;
+ cstate->domain[nv_clk_src_core] = perfE.core;
+ cstate->domain[nv_clk_src_shader] = perfE.shader;
+ cstate->domain[nv_clk_src_mem] = perfE.memory;
+ cstate->domain[nv_clk_src_vdec] = perfE.vdec;
+ cstate->domain[nv_clk_src_dom6] = perfE.disp;
+
+ while (ver >= 0x40 && (++domain)->name != nv_clk_src_max) {
+ struct nvbios_perfS perfS;
+ u8 sver = ver, shdr = hdr;
+ u32 perfSe = nvbios_perfSp(bios, data, domain->bios,
+ &sver, &shdr, cnt, len, &perfS);
+ if (perfSe == 0 || sver != 0x40)
+ continue;
+
+ if (domain->flags & NVKM_CLK_DOM_FLAG_CORE) {
+ perfS.v40.freq = nvkm_clk_adjust(clk, false,
+ pstate->pstate,
+ domain->bios,
+ perfS.v40.freq);
+ }
+
+ cstate->domain[domain->name] = perfS.v40.freq;
+ }
+
+ data = nvbios_cstepEm(bios, pstate->pstate, &ver, &hdr, &cstepE);
+ if (data) {
+ int idx = cstepE.index;
+ do {
+ nvkm_cstate_new(clk, idx, pstate);
+ } while(idx--);
+ }
+
+ nvkm_pstate_info(clk, pstate);
+ list_add_tail(&pstate->head, &clk->states);
+ clk->state_nr++;
+ return 0;
+}
+
+/******************************************************************************
+ * Adjustment triggers
+ *****************************************************************************/
+static int
+nvkm_clk_ustate_update(struct nvkm_clk *clk, int req)
+{
+ struct nvkm_pstate *pstate;
+ int i = 0;
+
+ if (!clk->allow_reclock)
+ return -ENOSYS;
+
+ if (req != -1 && req != -2) {
+ list_for_each_entry(pstate, &clk->states, head) {
+ if (pstate->pstate == req)
+ break;
+ i++;
+ }
+
+ if (pstate->pstate != req)
+ return -EINVAL;
+ req = i;
+ }
+
+ return req + 2;
+}
+
+static int
+nvkm_clk_nstate(struct nvkm_clk *clk, const char *mode, int arglen)
+{
+ int ret = 1;
+
+ if (clk->allow_reclock && !strncasecmpz(mode, "auto", arglen))
+ return -2;
+
+ if (strncasecmpz(mode, "disabled", arglen)) {
+ char save = mode[arglen];
+ long v;
+
+ ((char *)mode)[arglen] = '\0';
+ if (!kstrtol(mode, 0, &v)) {
+ ret = nvkm_clk_ustate_update(clk, v);
+ if (ret < 0)
+ ret = 1;
+ }
+ ((char *)mode)[arglen] = save;
+ }
+
+ return ret - 2;
+}
+
+int
+nvkm_clk_ustate(struct nvkm_clk *clk, int req, int pwr)
+{
+ int ret = nvkm_clk_ustate_update(clk, req);
+ if (ret >= 0) {
+ if (ret -= 2, pwr) clk->ustate_ac = ret;
+ else clk->ustate_dc = ret;
+ return nvkm_pstate_calc(clk, true);
+ }
+ return ret;
+}
+
+int
+nvkm_clk_astate(struct nvkm_clk *clk, int req, int rel, bool wait)
+{
+ if (!rel) clk->astate = req;
+ if ( rel) clk->astate += rel;
+ clk->astate = min(clk->astate, clk->state_nr - 1);
+ clk->astate = max(clk->astate, 0);
+ return nvkm_pstate_calc(clk, wait);
+}
+
+int
+nvkm_clk_tstate(struct nvkm_clk *clk, int req, int rel)
+{
+ if (!rel) clk->tstate = req;
+ if ( rel) clk->tstate += rel;
+ clk->tstate = min(clk->tstate, 0);
+ clk->tstate = max(clk->tstate, -(clk->state_nr - 1));
+ return nvkm_pstate_calc(clk, true);
+}
+
+int
+nvkm_clk_dstate(struct nvkm_clk *clk, int req, int rel)
+{
+ if (!rel) clk->dstate = req;
+ if ( rel) clk->dstate += rel;
+ clk->dstate = min(clk->dstate, clk->state_nr - 1);
+ clk->dstate = max(clk->dstate, 0);
+ return nvkm_pstate_calc(clk, true);
+}
+
+static int
+nvkm_clk_pwrsrc(struct nvkm_notify *notify)
+{
+ struct nvkm_clk *clk =
+ container_of(notify, typeof(*clk), pwrsrc_ntfy);
+ nvkm_pstate_calc(clk, false);
+ return NVKM_NOTIFY_DROP;
+}
+
+/******************************************************************************
+ * subdev base class implementation
+ *****************************************************************************/
+
+int
+_nvkm_clk_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_clk *clk = (void *)object;
+ nvkm_notify_put(&clk->pwrsrc_ntfy);
+ return nvkm_subdev_fini(&clk->base, suspend);
+}
+
+int
+_nvkm_clk_init(struct nvkm_object *object)
+{
+ struct nvkm_clk *clk = (void *)object;
+ struct nvkm_domain *clock = clk->domains;
+ int ret;
+
+ ret = nvkm_subdev_init(&clk->base);
+ if (ret)
+ return ret;
+
+ memset(&clk->bstate, 0x00, sizeof(clk->bstate));
+ INIT_LIST_HEAD(&clk->bstate.list);
+ clk->bstate.pstate = 0xff;
+
+ while (clock->name != nv_clk_src_max) {
+ ret = clk->read(clk, clock->name);
+ if (ret < 0) {
+ nv_error(clk, "%02x freq unknown\n", clock->name);
+ return ret;
+ }
+ clk->bstate.base.domain[clock->name] = ret;
+ clock++;
+ }
+
+ nvkm_pstate_info(clk, &clk->bstate);
+
+ clk->astate = clk->state_nr - 1;
+ clk->tstate = 0;
+ clk->dstate = 0;
+ clk->pstate = -1;
+ nvkm_pstate_calc(clk, true);
+ return 0;
+}
+
+void
+_nvkm_clk_dtor(struct nvkm_object *object)
+{
+ struct nvkm_clk *clk = (void *)object;
+ struct nvkm_pstate *pstate, *temp;
+
+ nvkm_notify_fini(&clk->pwrsrc_ntfy);
+
+ list_for_each_entry_safe(pstate, temp, &clk->states, head) {
+ nvkm_pstate_del(pstate);
+ }
+
+ nvkm_subdev_destroy(&clk->base);
+}
+
+int
+nvkm_clk_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, struct nvkm_domain *clocks,
+ struct nvkm_pstate *pstates, int nb_pstates,
+ bool allow_reclock, int length, void **object)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_clk *clk;
+ int ret, idx, arglen;
+ const char *mode;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "CLK",
+ "clock", length, object);
+ clk = *object;
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&clk->states);
+ clk->domains = clocks;
+ clk->ustate_ac = -1;
+ clk->ustate_dc = -1;
+
+ INIT_WORK(&clk->work, nvkm_pstate_work);
+ init_waitqueue_head(&clk->wait);
+ atomic_set(&clk->waiting, 0);
+
+ /* If no pstates are provided, try and fetch them from the BIOS */
+ if (!pstates) {
+ idx = 0;
+ do {
+ ret = nvkm_pstate_new(clk, idx++);
+ } while (ret == 0);
+ } else {
+ for (idx = 0; idx < nb_pstates; idx++)
+ list_add_tail(&pstates[idx].head, &clk->states);
+ clk->state_nr = nb_pstates;
+ }
+
+ clk->allow_reclock = allow_reclock;
+
+ ret = nvkm_notify_init(NULL, &device->event, nvkm_clk_pwrsrc, true,
+ NULL, 0, 0, &clk->pwrsrc_ntfy);
+ if (ret)
+ return ret;
+
+ mode = nvkm_stropt(device->cfgopt, "NvClkMode", &arglen);
+ if (mode) {
+ clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen);
+ clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
+ }
+
+ mode = nvkm_stropt(device->cfgopt, "NvClkModeAC", &arglen);
+ if (mode)
+ clk->ustate_ac = nvkm_clk_nstate(clk, mode, arglen);
+
+ mode = nvkm_stropt(device->cfgopt, "NvClkModeDC", &arglen);
+ if (mode)
+ clk->ustate_dc = nvkm_clk_nstate(clk, mode, arglen);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c
new file mode 100644
index 000000000000..4c90b9769d64
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/g84.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "nv50.h"
+
+static struct nvkm_domain
+g84_domains[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_href , 0xff },
+ { nv_clk_src_core , 0xff, 0, "core", 1000 },
+ { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+ { nv_clk_src_mem , 0xff, 0, "memory", 1000 },
+ { nv_clk_src_vdec , 0xff },
+ { nv_clk_src_max }
+};
+
+struct nvkm_oclass *
+g84_clk_oclass = &(struct nv50_clk_oclass) {
+ .base.handle = NV_SUBDEV(CLK, 0x84),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+ .domains = g84_domains,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
new file mode 100644
index 000000000000..3d7330d54b02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gf100.c
@@ -0,0 +1,462 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/timer.h>
+
+struct gf100_clk_info {
+ u32 freq;
+ u32 ssel;
+ u32 mdiv;
+ u32 dsrc;
+ u32 ddiv;
+ u32 coef;
+};
+
+struct gf100_clk_priv {
+ struct nvkm_clk base;
+ struct gf100_clk_info eng[16];
+};
+
+static u32 read_div(struct gf100_clk_priv *, int, u32, u32);
+
+static u32
+read_vco(struct gf100_clk_priv *priv, u32 dsrc)
+{
+ struct nvkm_clk *clk = &priv->base;
+ u32 ssrc = nv_rd32(priv, dsrc);
+ if (!(ssrc & 0x00000100))
+ return clk->read(clk, nv_clk_src_sppll0);
+ return clk->read(clk, nv_clk_src_sppll1);
+}
+
+static u32
+read_pll(struct gf100_clk_priv *priv, u32 pll)
+{
+ struct nvkm_clk *clk = &priv->base;
+ u32 ctrl = nv_rd32(priv, pll + 0x00);
+ u32 coef = nv_rd32(priv, pll + 0x04);
+ u32 P = (coef & 0x003f0000) >> 16;
+ u32 N = (coef & 0x0000ff00) >> 8;
+ u32 M = (coef & 0x000000ff) >> 0;
+ u32 sclk;
+
+ if (!(ctrl & 0x00000001))
+ return 0;
+
+ switch (pll) {
+ case 0x00e800:
+ case 0x00e820:
+ sclk = nv_device(priv)->crystal;
+ P = 1;
+ break;
+ case 0x132000:
+ sclk = clk->read(clk, nv_clk_src_mpllsrc);
+ break;
+ case 0x132020:
+ sclk = clk->read(clk, nv_clk_src_mpllsrcref);
+ break;
+ case 0x137000:
+ case 0x137020:
+ case 0x137040:
+ case 0x1370e0:
+ sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+ break;
+ default:
+ return 0;
+ }
+
+ return sclk * N / M / P;
+}
+
+static u32
+read_div(struct gf100_clk_priv *priv, int doff, u32 dsrc, u32 dctl)
+{
+ u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
+ u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+
+ switch (ssrc & 0x00000003) {
+ case 0:
+ if ((ssrc & 0x00030000) != 0x00030000)
+ return nv_device(priv)->crystal;
+ return 108000;
+ case 2:
+ return 100000;
+ case 3:
+ if (sctl & 0x80000000) {
+ u32 sclk = read_vco(priv, dsrc + (doff * 4));
+ u32 sdiv = (sctl & 0x0000003f) + 2;
+ return (sclk * 2) / sdiv;
+ }
+
+ return read_vco(priv, dsrc + (doff * 4));
+ default:
+ return 0;
+ }
+}
+
+static u32
+read_clk(struct gf100_clk_priv *priv, int clk)
+{
+ u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+ u32 ssel = nv_rd32(priv, 0x137100);
+ u32 sclk, sdiv;
+
+ if (ssel & (1 << clk)) {
+ if (clk < 7)
+ sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+ else
+ sclk = read_pll(priv, 0x1370e0);
+ sdiv = ((sctl & 0x00003f00) >> 8) + 2;
+ } else {
+ sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+ sdiv = ((sctl & 0x0000003f) >> 0) + 2;
+ }
+
+ if (sctl & 0x80000000)
+ return (sclk * 2) / sdiv;
+
+ return sclk;
+}
+
+static int
+gf100_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct nvkm_device *device = nv_device(clk);
+ struct gf100_clk_priv *priv = (void *)clk;
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return device->crystal;
+ case nv_clk_src_href:
+ return 100000;
+ case nv_clk_src_sppll0:
+ return read_pll(priv, 0x00e800);
+ case nv_clk_src_sppll1:
+ return read_pll(priv, 0x00e820);
+
+ case nv_clk_src_mpllsrcref:
+ return read_div(priv, 0, 0x137320, 0x137330);
+ case nv_clk_src_mpllsrc:
+ return read_pll(priv, 0x132020);
+ case nv_clk_src_mpll:
+ return read_pll(priv, 0x132000);
+ case nv_clk_src_mdiv:
+ return read_div(priv, 0, 0x137300, 0x137310);
+ case nv_clk_src_mem:
+ if (nv_rd32(priv, 0x1373f0) & 0x00000002)
+ return clk->read(clk, nv_clk_src_mpll);
+ return clk->read(clk, nv_clk_src_mdiv);
+
+ case nv_clk_src_gpc:
+ return read_clk(priv, 0x00);
+ case nv_clk_src_rop:
+ return read_clk(priv, 0x01);
+ case nv_clk_src_hubk07:
+ return read_clk(priv, 0x02);
+ case nv_clk_src_hubk06:
+ return read_clk(priv, 0x07);
+ case nv_clk_src_hubk01:
+ return read_clk(priv, 0x08);
+ case nv_clk_src_copy:
+ return read_clk(priv, 0x09);
+ case nv_clk_src_daemon:
+ return read_clk(priv, 0x0c);
+ case nv_clk_src_vdec:
+ return read_clk(priv, 0x0e);
+ default:
+ nv_error(clk, "invalid clock source %d\n", src);
+ return -EINVAL;
+ }
+}
+
+static u32
+calc_div(struct gf100_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+{
+ u32 div = min((ref * 2) / freq, (u32)65);
+ if (div < 2)
+ div = 2;
+
+ *ddiv = div - 2;
+ return (ref * 2) / div;
+}
+
+static u32
+calc_src(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+{
+ u32 sclk;
+
+ /* use one of the fixed frequencies if possible */
+ *ddiv = 0x00000000;
+ switch (freq) {
+ case 27000:
+ case 108000:
+ *dsrc = 0x00000000;
+ if (freq == 108000)
+ *dsrc |= 0x00030000;
+ return freq;
+ case 100000:
+ *dsrc = 0x00000002;
+ return freq;
+ default:
+ *dsrc = 0x00000003;
+ break;
+ }
+
+ /* otherwise, calculate the closest divider */
+ sclk = read_vco(priv, 0x137160 + (clk * 4));
+ if (clk < 7)
+ sclk = calc_div(priv, clk, sclk, freq, ddiv);
+ return sclk;
+}
+
+static u32
+calc_pll(struct gf100_clk_priv *priv, int clk, u32 freq, u32 *coef)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll limits;
+ int N, M, P, ret;
+
+ ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+ if (ret)
+ return 0;
+
+ limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+ if (!limits.refclk)
+ return 0;
+
+ ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+ if (ret <= 0)
+ return 0;
+
+ *coef = (P << 16) | (N << 8) | M;
+ return ret;
+}
+
+static int
+calc_clk(struct gf100_clk_priv *priv,
+ struct nvkm_cstate *cstate, int clk, int dom)
+{
+ struct gf100_clk_info *info = &priv->eng[clk];
+ u32 freq = cstate->domain[dom];
+ u32 src0, div0, div1D, div1P = 0;
+ u32 clk0, clk1 = 0;
+
+ /* invalid clock domain */
+ if (!freq)
+ return 0;
+
+ /* first possible path, using only dividers */
+ clk0 = calc_src(priv, clk, freq, &src0, &div0);
+ clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+
+ /* see if we can get any closer using PLLs */
+ if (clk0 != freq && (0x00004387 & (1 << clk))) {
+ if (clk <= 7)
+ clk1 = calc_pll(priv, clk, freq, &info->coef);
+ else
+ clk1 = cstate->domain[nv_clk_src_hubk06];
+ clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+ }
+
+ /* select the method which gets closest to target freq */
+ if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
+ info->dsrc = src0;
+ if (div0) {
+ info->ddiv |= 0x80000000;
+ info->ddiv |= div0 << 8;
+ info->ddiv |= div0;
+ }
+ if (div1D) {
+ info->mdiv |= 0x80000000;
+ info->mdiv |= div1D;
+ }
+ info->ssel = info->coef = 0;
+ info->freq = clk0;
+ } else {
+ if (div1P) {
+ info->mdiv |= 0x80000000;
+ info->mdiv |= div1P << 8;
+ }
+ info->ssel = (1 << clk);
+ info->freq = clk1;
+ }
+
+ return 0;
+}
+
+static int
+gf100_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct gf100_clk_priv *priv = (void *)clk;
+ int ret;
+
+ if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
+ (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
+ (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
+ (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
+ (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
+ (ret = calc_clk(priv, cstate, 0x09, nv_clk_src_copy)) ||
+ (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
+ (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+ return ret;
+
+ return 0;
+}
+
+static void
+gf100_clk_prog_0(struct gf100_clk_priv *priv, int clk)
+{
+ struct gf100_clk_info *info = &priv->eng[clk];
+ if (clk < 7 && !info->ssel) {
+ nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x80003f3f, info->ddiv);
+ nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+ }
+}
+
+static void
+gf100_clk_prog_1(struct gf100_clk_priv *priv, int clk)
+{
+ nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
+ nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+}
+
+static void
+gf100_clk_prog_2(struct gf100_clk_priv *priv, int clk)
+{
+ struct gf100_clk_info *info = &priv->eng[clk];
+ const u32 addr = 0x137000 + (clk * 0x20);
+ if (clk <= 7) {
+ nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
+ nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+ if (info->coef) {
+ nv_wr32(priv, addr + 0x04, info->coef);
+ nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
+ nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
+ nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+ }
+ }
+}
+
+static void
+gf100_clk_prog_3(struct gf100_clk_priv *priv, int clk)
+{
+ struct gf100_clk_info *info = &priv->eng[clk];
+ if (info->ssel) {
+ nv_mask(priv, 0x137100, (1 << clk), info->ssel);
+ nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+ }
+}
+
+static void
+gf100_clk_prog_4(struct gf100_clk_priv *priv, int clk)
+{
+ struct gf100_clk_info *info = &priv->eng[clk];
+ nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f3f, info->mdiv);
+}
+
+static int
+gf100_clk_prog(struct nvkm_clk *clk)
+{
+ struct gf100_clk_priv *priv = (void *)clk;
+ struct {
+ void (*exec)(struct gf100_clk_priv *, int);
+ } stage[] = {
+ { gf100_clk_prog_0 }, /* div programming */
+ { gf100_clk_prog_1 }, /* select div mode */
+ { gf100_clk_prog_2 }, /* (maybe) program pll */
+ { gf100_clk_prog_3 }, /* (maybe) select pll mode */
+ { gf100_clk_prog_4 }, /* final divider */
+ };
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(stage); i++) {
+ for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+ if (!priv->eng[j].freq)
+ continue;
+ stage[i].exec(priv, j);
+ }
+ }
+
+ return 0;
+}
+
+static void
+gf100_clk_tidy(struct nvkm_clk *clk)
+{
+ struct gf100_clk_priv *priv = (void *)clk;
+ memset(priv->eng, 0x00, sizeof(priv->eng));
+}
+
+static struct nvkm_domain
+gf100_domain[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_href , 0xff },
+ { nv_clk_src_hubk06 , 0x00 },
+ { nv_clk_src_hubk01 , 0x01 },
+ { nv_clk_src_copy , 0x02 },
+ { nv_clk_src_gpc , 0x03, 0, "core", 2000 },
+ { nv_clk_src_rop , 0x04 },
+ { nv_clk_src_mem , 0x05, 0, "memory", 1000 },
+ { nv_clk_src_vdec , 0x06 },
+ { nv_clk_src_daemon , 0x0a },
+ { nv_clk_src_hubk07 , 0x0b },
+ { nv_clk_src_max }
+};
+
+static int
+gf100_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, gf100_domain,
+ NULL, 0, false, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.read = gf100_clk_read;
+ priv->base.calc = gf100_clk_calc;
+ priv->base.prog = gf100_clk_prog;
+ priv->base.tidy = gf100_clk_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_clk_oclass = {
+ .handle = NV_SUBDEV(CLK, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
new file mode 100644
index 000000000000..e9b2310bdfbb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk104.c
@@ -0,0 +1,500 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/timer.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+struct gk104_clk_info {
+ u32 freq;
+ u32 ssel;
+ u32 mdiv;
+ u32 dsrc;
+ u32 ddiv;
+ u32 coef;
+};
+
+struct gk104_clk_priv {
+ struct nvkm_clk base;
+ struct gk104_clk_info eng[16];
+};
+
+static u32 read_div(struct gk104_clk_priv *, int, u32, u32);
+static u32 read_pll(struct gk104_clk_priv *, u32);
+
+static u32
+read_vco(struct gk104_clk_priv *priv, u32 dsrc)
+{
+ u32 ssrc = nv_rd32(priv, dsrc);
+ if (!(ssrc & 0x00000100))
+ return read_pll(priv, 0x00e800);
+ return read_pll(priv, 0x00e820);
+}
+
+static u32
+read_pll(struct gk104_clk_priv *priv, u32 pll)
+{
+ u32 ctrl = nv_rd32(priv, pll + 0x00);
+ u32 coef = nv_rd32(priv, pll + 0x04);
+ u32 P = (coef & 0x003f0000) >> 16;
+ u32 N = (coef & 0x0000ff00) >> 8;
+ u32 M = (coef & 0x000000ff) >> 0;
+ u32 sclk;
+ u16 fN = 0xf000;
+
+ if (!(ctrl & 0x00000001))
+ return 0;
+
+ switch (pll) {
+ case 0x00e800:
+ case 0x00e820:
+ sclk = nv_device(priv)->crystal;
+ P = 1;
+ break;
+ case 0x132000:
+ sclk = read_pll(priv, 0x132020);
+ P = (coef & 0x10000000) ? 2 : 1;
+ break;
+ case 0x132020:
+ sclk = read_div(priv, 0, 0x137320, 0x137330);
+ fN = nv_rd32(priv, pll + 0x10) >> 16;
+ break;
+ case 0x137000:
+ case 0x137020:
+ case 0x137040:
+ case 0x1370e0:
+ sclk = read_div(priv, (pll & 0xff) / 0x20, 0x137120, 0x137140);
+ break;
+ default:
+ return 0;
+ }
+
+ if (P == 0)
+ P = 1;
+
+ sclk = (sclk * N) + (((u16)(fN + 4096) * sclk) >> 13);
+ return sclk / (M * P);
+}
+
+static u32
+read_div(struct gk104_clk_priv *priv, int doff, u32 dsrc, u32 dctl)
+{
+ u32 ssrc = nv_rd32(priv, dsrc + (doff * 4));
+ u32 sctl = nv_rd32(priv, dctl + (doff * 4));
+
+ switch (ssrc & 0x00000003) {
+ case 0:
+ if ((ssrc & 0x00030000) != 0x00030000)
+ return nv_device(priv)->crystal;
+ return 108000;
+ case 2:
+ return 100000;
+ case 3:
+ if (sctl & 0x80000000) {
+ u32 sclk = read_vco(priv, dsrc + (doff * 4));
+ u32 sdiv = (sctl & 0x0000003f) + 2;
+ return (sclk * 2) / sdiv;
+ }
+
+ return read_vco(priv, dsrc + (doff * 4));
+ default:
+ return 0;
+ }
+}
+
+static u32
+read_mem(struct gk104_clk_priv *priv)
+{
+ switch (nv_rd32(priv, 0x1373f4) & 0x0000000f) {
+ case 1: return read_pll(priv, 0x132020);
+ case 2: return read_pll(priv, 0x132000);
+ default:
+ return 0;
+ }
+}
+
+static u32
+read_clk(struct gk104_clk_priv *priv, int clk)
+{
+ u32 sctl = nv_rd32(priv, 0x137250 + (clk * 4));
+ u32 sclk, sdiv;
+
+ if (clk < 7) {
+ u32 ssel = nv_rd32(priv, 0x137100);
+ if (ssel & (1 << clk)) {
+ sclk = read_pll(priv, 0x137000 + (clk * 0x20));
+ sdiv = 1;
+ } else {
+ sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+ sdiv = 0;
+ }
+ } else {
+ u32 ssrc = nv_rd32(priv, 0x137160 + (clk * 0x04));
+ if ((ssrc & 0x00000003) == 0x00000003) {
+ sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+ if (ssrc & 0x00000100) {
+ if (ssrc & 0x40000000)
+ sclk = read_pll(priv, 0x1370e0);
+ sdiv = 1;
+ } else {
+ sdiv = 0;
+ }
+ } else {
+ sclk = read_div(priv, clk, 0x137160, 0x1371d0);
+ sdiv = 0;
+ }
+ }
+
+ if (sctl & 0x80000000) {
+ if (sdiv)
+ sdiv = ((sctl & 0x00003f00) >> 8) + 2;
+ else
+ sdiv = ((sctl & 0x0000003f) >> 0) + 2;
+ return (sclk * 2) / sdiv;
+ }
+
+ return sclk;
+}
+
+static int
+gk104_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct nvkm_device *device = nv_device(clk);
+ struct gk104_clk_priv *priv = (void *)clk;
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return device->crystal;
+ case nv_clk_src_href:
+ return 100000;
+ case nv_clk_src_mem:
+ return read_mem(priv);
+ case nv_clk_src_gpc:
+ return read_clk(priv, 0x00);
+ case nv_clk_src_rop:
+ return read_clk(priv, 0x01);
+ case nv_clk_src_hubk07:
+ return read_clk(priv, 0x02);
+ case nv_clk_src_hubk06:
+ return read_clk(priv, 0x07);
+ case nv_clk_src_hubk01:
+ return read_clk(priv, 0x08);
+ case nv_clk_src_daemon:
+ return read_clk(priv, 0x0c);
+ case nv_clk_src_vdec:
+ return read_clk(priv, 0x0e);
+ default:
+ nv_error(clk, "invalid clock source %d\n", src);
+ return -EINVAL;
+ }
+}
+
+static u32
+calc_div(struct gk104_clk_priv *priv, int clk, u32 ref, u32 freq, u32 *ddiv)
+{
+ u32 div = min((ref * 2) / freq, (u32)65);
+ if (div < 2)
+ div = 2;
+
+ *ddiv = div - 2;
+ return (ref * 2) / div;
+}
+
+static u32
+calc_src(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *dsrc, u32 *ddiv)
+{
+ u32 sclk;
+
+ /* use one of the fixed frequencies if possible */
+ *ddiv = 0x00000000;
+ switch (freq) {
+ case 27000:
+ case 108000:
+ *dsrc = 0x00000000;
+ if (freq == 108000)
+ *dsrc |= 0x00030000;
+ return freq;
+ case 100000:
+ *dsrc = 0x00000002;
+ return freq;
+ default:
+ *dsrc = 0x00000003;
+ break;
+ }
+
+ /* otherwise, calculate the closest divider */
+ sclk = read_vco(priv, 0x137160 + (clk * 4));
+ if (clk < 7)
+ sclk = calc_div(priv, clk, sclk, freq, ddiv);
+ return sclk;
+}
+
+static u32
+calc_pll(struct gk104_clk_priv *priv, int clk, u32 freq, u32 *coef)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll limits;
+ int N, M, P, ret;
+
+ ret = nvbios_pll_parse(bios, 0x137000 + (clk * 0x20), &limits);
+ if (ret)
+ return 0;
+
+ limits.refclk = read_div(priv, clk, 0x137120, 0x137140);
+ if (!limits.refclk)
+ return 0;
+
+ ret = gt215_pll_calc(nv_subdev(priv), &limits, freq, &N, NULL, &M, &P);
+ if (ret <= 0)
+ return 0;
+
+ *coef = (P << 16) | (N << 8) | M;
+ return ret;
+}
+
+static int
+calc_clk(struct gk104_clk_priv *priv,
+ struct nvkm_cstate *cstate, int clk, int dom)
+{
+ struct gk104_clk_info *info = &priv->eng[clk];
+ u32 freq = cstate->domain[dom];
+ u32 src0, div0, div1D, div1P = 0;
+ u32 clk0, clk1 = 0;
+
+ /* invalid clock domain */
+ if (!freq)
+ return 0;
+
+ /* first possible path, using only dividers */
+ clk0 = calc_src(priv, clk, freq, &src0, &div0);
+ clk0 = calc_div(priv, clk, clk0, freq, &div1D);
+
+ /* see if we can get any closer using PLLs */
+ if (clk0 != freq && (0x0000ff87 & (1 << clk))) {
+ if (clk <= 7)
+ clk1 = calc_pll(priv, clk, freq, &info->coef);
+ else
+ clk1 = cstate->domain[nv_clk_src_hubk06];
+ clk1 = calc_div(priv, clk, clk1, freq, &div1P);
+ }
+
+ /* select the method which gets closest to target freq */
+ if (abs((int)freq - clk0) <= abs((int)freq - clk1)) {
+ info->dsrc = src0;
+ if (div0) {
+ info->ddiv |= 0x80000000;
+ info->ddiv |= div0;
+ }
+ if (div1D) {
+ info->mdiv |= 0x80000000;
+ info->mdiv |= div1D;
+ }
+ info->ssel = 0;
+ info->freq = clk0;
+ } else {
+ if (div1P) {
+ info->mdiv |= 0x80000000;
+ info->mdiv |= div1P << 8;
+ }
+ info->ssel = (1 << clk);
+ info->dsrc = 0x40000100;
+ info->freq = clk1;
+ }
+
+ return 0;
+}
+
+static int
+gk104_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct gk104_clk_priv *priv = (void *)clk;
+ int ret;
+
+ if ((ret = calc_clk(priv, cstate, 0x00, nv_clk_src_gpc)) ||
+ (ret = calc_clk(priv, cstate, 0x01, nv_clk_src_rop)) ||
+ (ret = calc_clk(priv, cstate, 0x02, nv_clk_src_hubk07)) ||
+ (ret = calc_clk(priv, cstate, 0x07, nv_clk_src_hubk06)) ||
+ (ret = calc_clk(priv, cstate, 0x08, nv_clk_src_hubk01)) ||
+ (ret = calc_clk(priv, cstate, 0x0c, nv_clk_src_daemon)) ||
+ (ret = calc_clk(priv, cstate, 0x0e, nv_clk_src_vdec)))
+ return ret;
+
+ return 0;
+}
+
+static void
+gk104_clk_prog_0(struct gk104_clk_priv *priv, int clk)
+{
+ struct gk104_clk_info *info = &priv->eng[clk];
+ if (!info->ssel) {
+ nv_mask(priv, 0x1371d0 + (clk * 0x04), 0x8000003f, info->ddiv);
+ nv_wr32(priv, 0x137160 + (clk * 0x04), info->dsrc);
+ }
+}
+
+static void
+gk104_clk_prog_1_0(struct gk104_clk_priv *priv, int clk)
+{
+ nv_mask(priv, 0x137100, (1 << clk), 0x00000000);
+ nv_wait(priv, 0x137100, (1 << clk), 0x00000000);
+}
+
+static void
+gk104_clk_prog_1_1(struct gk104_clk_priv *priv, int clk)
+{
+ nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000000);
+}
+
+static void
+gk104_clk_prog_2(struct gk104_clk_priv *priv, int clk)
+{
+ struct gk104_clk_info *info = &priv->eng[clk];
+ const u32 addr = 0x137000 + (clk * 0x20);
+ nv_mask(priv, addr + 0x00, 0x00000004, 0x00000000);
+ nv_mask(priv, addr + 0x00, 0x00000001, 0x00000000);
+ if (info->coef) {
+ nv_wr32(priv, addr + 0x04, info->coef);
+ nv_mask(priv, addr + 0x00, 0x00000001, 0x00000001);
+ nv_wait(priv, addr + 0x00, 0x00020000, 0x00020000);
+ nv_mask(priv, addr + 0x00, 0x00020004, 0x00000004);
+ }
+}
+
+static void
+gk104_clk_prog_3(struct gk104_clk_priv *priv, int clk)
+{
+ struct gk104_clk_info *info = &priv->eng[clk];
+ if (info->ssel)
+ nv_mask(priv, 0x137250 + (clk * 0x04), 0x00003f00, info->mdiv);
+ else
+ nv_mask(priv, 0x137250 + (clk * 0x04), 0x0000003f, info->mdiv);
+}
+
+static void
+gk104_clk_prog_4_0(struct gk104_clk_priv *priv, int clk)
+{
+ struct gk104_clk_info *info = &priv->eng[clk];
+ if (info->ssel) {
+ nv_mask(priv, 0x137100, (1 << clk), info->ssel);
+ nv_wait(priv, 0x137100, (1 << clk), info->ssel);
+ }
+}
+
+static void
+gk104_clk_prog_4_1(struct gk104_clk_priv *priv, int clk)
+{
+ struct gk104_clk_info *info = &priv->eng[clk];
+ if (info->ssel) {
+ nv_mask(priv, 0x137160 + (clk * 0x04), 0x40000000, 0x40000000);
+ nv_mask(priv, 0x137160 + (clk * 0x04), 0x00000100, 0x00000100);
+ }
+}
+
+static int
+gk104_clk_prog(struct nvkm_clk *clk)
+{
+ struct gk104_clk_priv *priv = (void *)clk;
+ struct {
+ u32 mask;
+ void (*exec)(struct gk104_clk_priv *, int);
+ } stage[] = {
+ { 0x007f, gk104_clk_prog_0 }, /* div programming */
+ { 0x007f, gk104_clk_prog_1_0 }, /* select div mode */
+ { 0xff80, gk104_clk_prog_1_1 },
+ { 0x00ff, gk104_clk_prog_2 }, /* (maybe) program pll */
+ { 0xff80, gk104_clk_prog_3 }, /* final divider */
+ { 0x007f, gk104_clk_prog_4_0 }, /* (maybe) select pll mode */
+ { 0xff80, gk104_clk_prog_4_1 },
+ };
+ int i, j;
+
+ for (i = 0; i < ARRAY_SIZE(stage); i++) {
+ for (j = 0; j < ARRAY_SIZE(priv->eng); j++) {
+ if (!(stage[i].mask & (1 << j)))
+ continue;
+ if (!priv->eng[j].freq)
+ continue;
+ stage[i].exec(priv, j);
+ }
+ }
+
+ return 0;
+}
+
+static void
+gk104_clk_tidy(struct nvkm_clk *clk)
+{
+ struct gk104_clk_priv *priv = (void *)clk;
+ memset(priv->eng, 0x00, sizeof(priv->eng));
+}
+
+static struct nvkm_domain
+gk104_domain[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_href , 0xff },
+ { nv_clk_src_gpc , 0x00, NVKM_CLK_DOM_FLAG_CORE, "core", 2000 },
+ { nv_clk_src_hubk07 , 0x01, NVKM_CLK_DOM_FLAG_CORE },
+ { nv_clk_src_rop , 0x02, NVKM_CLK_DOM_FLAG_CORE },
+ { nv_clk_src_mem , 0x03, 0, "memory", 500 },
+ { nv_clk_src_hubk06 , 0x04, NVKM_CLK_DOM_FLAG_CORE },
+ { nv_clk_src_hubk01 , 0x05 },
+ { nv_clk_src_vdec , 0x06 },
+ { nv_clk_src_daemon , 0x07 },
+ { nv_clk_src_max }
+};
+
+static int
+gk104_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, gk104_domain,
+ NULL, 0, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.read = gk104_clk_read;
+ priv->base.calc = gk104_clk_calc;
+ priv->base.prog = gk104_clk_prog;
+ priv->base.tidy = gk104_clk_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_clk_oclass = {
+ .handle = NV_SUBDEV(CLK, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
new file mode 100644
index 000000000000..65c532742b08
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gk20a.c
@@ -0,0 +1,680 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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.
+ *
+ * Shamelessly ripped off from ChromeOS's gk20a/clk_pllg.c
+ *
+ */
+#include <subdev/clk.h>
+#include <subdev/timer.h>
+
+#include <core/device.h>
+
+#ifdef __KERNEL__
+#include <nouveau_platform.h>
+#endif
+
+#define MHZ (1000 * 1000)
+
+#define MASK(w) ((1 << w) - 1)
+
+#define SYS_GPCPLL_CFG_BASE 0x00137000
+#define GPC_BCASE_GPCPLL_CFG_BASE 0x00132800
+
+#define GPCPLL_CFG (SYS_GPCPLL_CFG_BASE + 0)
+#define GPCPLL_CFG_ENABLE BIT(0)
+#define GPCPLL_CFG_IDDQ BIT(1)
+#define GPCPLL_CFG_LOCK_DET_OFF BIT(4)
+#define GPCPLL_CFG_LOCK BIT(17)
+
+#define GPCPLL_COEFF (SYS_GPCPLL_CFG_BASE + 4)
+#define GPCPLL_COEFF_M_SHIFT 0
+#define GPCPLL_COEFF_M_WIDTH 8
+#define GPCPLL_COEFF_N_SHIFT 8
+#define GPCPLL_COEFF_N_WIDTH 8
+#define GPCPLL_COEFF_P_SHIFT 16
+#define GPCPLL_COEFF_P_WIDTH 6
+
+#define GPCPLL_CFG2 (SYS_GPCPLL_CFG_BASE + 0xc)
+#define GPCPLL_CFG2_SETUP2_SHIFT 16
+#define GPCPLL_CFG2_PLL_STEPA_SHIFT 24
+
+#define GPCPLL_CFG3 (SYS_GPCPLL_CFG_BASE + 0x18)
+#define GPCPLL_CFG3_PLL_STEPB_SHIFT 16
+
+#define GPCPLL_NDIV_SLOWDOWN (SYS_GPCPLL_CFG_BASE + 0x1c)
+#define GPCPLL_NDIV_SLOWDOWN_NDIV_LO_SHIFT 0
+#define GPCPLL_NDIV_SLOWDOWN_NDIV_MID_SHIFT 8
+#define GPCPLL_NDIV_SLOWDOWN_STEP_SIZE_LO2MID_SHIFT 16
+#define GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT 22
+#define GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT 31
+
+#define SEL_VCO (SYS_GPCPLL_CFG_BASE + 0x100)
+#define SEL_VCO_GPC2CLK_OUT_SHIFT 0
+
+#define GPC2CLK_OUT (SYS_GPCPLL_CFG_BASE + 0x250)
+#define GPC2CLK_OUT_SDIV14_INDIV4_WIDTH 1
+#define GPC2CLK_OUT_SDIV14_INDIV4_SHIFT 31
+#define GPC2CLK_OUT_SDIV14_INDIV4_MODE 1
+#define GPC2CLK_OUT_VCODIV_WIDTH 6
+#define GPC2CLK_OUT_VCODIV_SHIFT 8
+#define GPC2CLK_OUT_VCODIV1 0
+#define GPC2CLK_OUT_VCODIV_MASK (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << \
+ GPC2CLK_OUT_VCODIV_SHIFT)
+#define GPC2CLK_OUT_BYPDIV_WIDTH 6
+#define GPC2CLK_OUT_BYPDIV_SHIFT 0
+#define GPC2CLK_OUT_BYPDIV31 0x3c
+#define GPC2CLK_OUT_INIT_MASK ((MASK(GPC2CLK_OUT_SDIV14_INDIV4_WIDTH) << \
+ GPC2CLK_OUT_SDIV14_INDIV4_SHIFT)\
+ | (MASK(GPC2CLK_OUT_VCODIV_WIDTH) << GPC2CLK_OUT_VCODIV_SHIFT)\
+ | (MASK(GPC2CLK_OUT_BYPDIV_WIDTH) << GPC2CLK_OUT_BYPDIV_SHIFT))
+#define GPC2CLK_OUT_INIT_VAL ((GPC2CLK_OUT_SDIV14_INDIV4_MODE << \
+ GPC2CLK_OUT_SDIV14_INDIV4_SHIFT) \
+ | (GPC2CLK_OUT_VCODIV1 << GPC2CLK_OUT_VCODIV_SHIFT) \
+ | (GPC2CLK_OUT_BYPDIV31 << GPC2CLK_OUT_BYPDIV_SHIFT))
+
+#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG (GPC_BCASE_GPCPLL_CFG_BASE + 0xa0)
+#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT 24
+#define GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK \
+ (0x1 << GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_SHIFT)
+
+static const u8 pl_to_div[] = {
+/* PL: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14 */
+/* p: */ 1, 2, 3, 4, 5, 6, 8, 10, 12, 16, 12, 16, 20, 24, 32,
+};
+
+/* All frequencies in Mhz */
+struct gk20a_clk_pllg_params {
+ u32 min_vco, max_vco;
+ u32 min_u, max_u;
+ u32 min_m, max_m;
+ u32 min_n, max_n;
+ u32 min_pl, max_pl;
+};
+
+static const struct gk20a_clk_pllg_params gk20a_pllg_params = {
+ .min_vco = 1000, .max_vco = 2064,
+ .min_u = 12, .max_u = 38,
+ .min_m = 1, .max_m = 255,
+ .min_n = 8, .max_n = 255,
+ .min_pl = 1, .max_pl = 32,
+};
+
+struct gk20a_clk_priv {
+ struct nvkm_clk base;
+ const struct gk20a_clk_pllg_params *params;
+ u32 m, n, pl;
+ u32 parent_rate;
+};
+#define to_gk20a_clk(base) container_of(base, struct gk20a_clk_priv, base)
+
+static void
+gk20a_pllg_read_mnp(struct gk20a_clk_priv *priv)
+{
+ u32 val;
+
+ val = nv_rd32(priv, GPCPLL_COEFF);
+ priv->m = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
+ priv->n = (val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH);
+ priv->pl = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
+}
+
+static u32
+gk20a_pllg_calc_rate(struct gk20a_clk_priv *priv)
+{
+ u32 rate;
+ u32 divider;
+
+ rate = priv->parent_rate * priv->n;
+ divider = priv->m * pl_to_div[priv->pl];
+ do_div(rate, divider);
+
+ return rate / 2;
+}
+
+static int
+gk20a_pllg_calc_mnp(struct gk20a_clk_priv *priv, unsigned long rate)
+{
+ u32 target_clk_f, ref_clk_f, target_freq;
+ u32 min_vco_f, max_vco_f;
+ u32 low_pl, high_pl, best_pl;
+ u32 target_vco_f, vco_f;
+ u32 best_m, best_n;
+ u32 u_f;
+ u32 m, n, n2;
+ u32 delta, lwv, best_delta = ~0;
+ u32 pl;
+
+ target_clk_f = rate * 2 / MHZ;
+ ref_clk_f = priv->parent_rate / MHZ;
+
+ max_vco_f = priv->params->max_vco;
+ min_vco_f = priv->params->min_vco;
+ best_m = priv->params->max_m;
+ best_n = priv->params->min_n;
+ best_pl = priv->params->min_pl;
+
+ target_vco_f = target_clk_f + target_clk_f / 50;
+ if (max_vco_f < target_vco_f)
+ max_vco_f = target_vco_f;
+
+ /* min_pl <= high_pl <= max_pl */
+ high_pl = (max_vco_f + target_vco_f - 1) / target_vco_f;
+ high_pl = min(high_pl, priv->params->max_pl);
+ high_pl = max(high_pl, priv->params->min_pl);
+
+ /* min_pl <= low_pl <= max_pl */
+ low_pl = min_vco_f / target_vco_f;
+ low_pl = min(low_pl, priv->params->max_pl);
+ low_pl = max(low_pl, priv->params->min_pl);
+
+ /* Find Indices of high_pl and low_pl */
+ for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
+ if (pl_to_div[pl] >= low_pl) {
+ low_pl = pl;
+ break;
+ }
+ }
+ for (pl = 0; pl < ARRAY_SIZE(pl_to_div) - 1; pl++) {
+ if (pl_to_div[pl] >= high_pl) {
+ high_pl = pl;
+ break;
+ }
+ }
+
+ nv_debug(priv, "low_PL %d(div%d), high_PL %d(div%d)", low_pl,
+ pl_to_div[low_pl], high_pl, pl_to_div[high_pl]);
+
+ /* Select lowest possible VCO */
+ for (pl = low_pl; pl <= high_pl; pl++) {
+ target_vco_f = target_clk_f * pl_to_div[pl];
+ for (m = priv->params->min_m; m <= priv->params->max_m; m++) {
+ u_f = ref_clk_f / m;
+
+ if (u_f < priv->params->min_u)
+ break;
+ if (u_f > priv->params->max_u)
+ continue;
+
+ n = (target_vco_f * m) / ref_clk_f;
+ n2 = ((target_vco_f * m) + (ref_clk_f - 1)) / ref_clk_f;
+
+ if (n > priv->params->max_n)
+ break;
+
+ for (; n <= n2; n++) {
+ if (n < priv->params->min_n)
+ continue;
+ if (n > priv->params->max_n)
+ break;
+
+ vco_f = ref_clk_f * n / m;
+
+ if (vco_f >= min_vco_f && vco_f <= max_vco_f) {
+ lwv = (vco_f + (pl_to_div[pl] / 2))
+ / pl_to_div[pl];
+ delta = abs(lwv - target_clk_f);
+
+ if (delta < best_delta) {
+ best_delta = delta;
+ best_m = m;
+ best_n = n;
+ best_pl = pl;
+
+ if (best_delta == 0)
+ goto found_match;
+ }
+ }
+ }
+ }
+ }
+
+found_match:
+ WARN_ON(best_delta == ~0);
+
+ if (best_delta != 0)
+ nv_debug(priv, "no best match for target @ %dMHz on gpc_pll",
+ target_clk_f);
+
+ priv->m = best_m;
+ priv->n = best_n;
+ priv->pl = best_pl;
+
+ target_freq = gk20a_pllg_calc_rate(priv) / MHZ;
+
+ nv_debug(priv, "actual target freq %d MHz, M %d, N %d, PL %d(div%d)\n",
+ target_freq, priv->m, priv->n, priv->pl, pl_to_div[priv->pl]);
+ return 0;
+}
+
+static int
+gk20a_pllg_slide(struct gk20a_clk_priv *priv, u32 n)
+{
+ u32 val;
+ int ramp_timeout;
+
+ /* get old coefficients */
+ val = nv_rd32(priv, GPCPLL_COEFF);
+ /* do nothing if NDIV is the same */
+ if (n == ((val >> GPCPLL_COEFF_N_SHIFT) & MASK(GPCPLL_COEFF_N_WIDTH)))
+ return 0;
+
+ /* setup */
+ nv_mask(priv, GPCPLL_CFG2, 0xff << GPCPLL_CFG2_PLL_STEPA_SHIFT,
+ 0x2b << GPCPLL_CFG2_PLL_STEPA_SHIFT);
+ nv_mask(priv, GPCPLL_CFG3, 0xff << GPCPLL_CFG3_PLL_STEPB_SHIFT,
+ 0xb << GPCPLL_CFG3_PLL_STEPB_SHIFT);
+
+ /* pll slowdown mode */
+ nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
+ BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT),
+ BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT));
+
+ /* new ndiv ready for ramp */
+ val = nv_rd32(priv, GPCPLL_COEFF);
+ val &= ~(MASK(GPCPLL_COEFF_N_WIDTH) << GPCPLL_COEFF_N_SHIFT);
+ val |= (n & MASK(GPCPLL_COEFF_N_WIDTH)) << GPCPLL_COEFF_N_SHIFT;
+ udelay(1);
+ nv_wr32(priv, GPCPLL_COEFF, val);
+
+ /* dynamic ramp to new ndiv */
+ val = nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
+ val |= 0x1 << GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT;
+ udelay(1);
+ nv_wr32(priv, GPCPLL_NDIV_SLOWDOWN, val);
+
+ for (ramp_timeout = 500; ramp_timeout > 0; ramp_timeout--) {
+ udelay(1);
+ val = nv_rd32(priv, GPC_BCAST_NDIV_SLOWDOWN_DEBUG);
+ if (val & GPC_BCAST_NDIV_SLOWDOWN_DEBUG_PLL_DYNRAMP_DONE_SYNCED_MASK)
+ break;
+ }
+
+ /* exit slowdown mode */
+ nv_mask(priv, GPCPLL_NDIV_SLOWDOWN,
+ BIT(GPCPLL_NDIV_SLOWDOWN_SLOWDOWN_USING_PLL_SHIFT) |
+ BIT(GPCPLL_NDIV_SLOWDOWN_EN_DYNRAMP_SHIFT), 0);
+ nv_rd32(priv, GPCPLL_NDIV_SLOWDOWN);
+
+ if (ramp_timeout <= 0) {
+ nv_error(priv, "gpcpll dynamic ramp timeout\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static void
+_gk20a_pllg_enable(struct gk20a_clk_priv *priv)
+{
+ nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, GPCPLL_CFG_ENABLE);
+ nv_rd32(priv, GPCPLL_CFG);
+}
+
+static void
+_gk20a_pllg_disable(struct gk20a_clk_priv *priv)
+{
+ nv_mask(priv, GPCPLL_CFG, GPCPLL_CFG_ENABLE, 0);
+ nv_rd32(priv, GPCPLL_CFG);
+}
+
+static int
+_gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv, bool allow_slide)
+{
+ u32 val, cfg;
+ u32 m_old, pl_old, n_lo;
+
+ /* get old coefficients */
+ val = nv_rd32(priv, GPCPLL_COEFF);
+ m_old = (val >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
+ pl_old = (val >> GPCPLL_COEFF_P_SHIFT) & MASK(GPCPLL_COEFF_P_WIDTH);
+
+ /* do NDIV slide if there is no change in M and PL */
+ cfg = nv_rd32(priv, GPCPLL_CFG);
+ if (allow_slide && priv->m == m_old && priv->pl == pl_old &&
+ (cfg & GPCPLL_CFG_ENABLE)) {
+ return gk20a_pllg_slide(priv, priv->n);
+ }
+
+ /* slide down to NDIV_LO */
+ n_lo = DIV_ROUND_UP(m_old * priv->params->min_vco,
+ priv->parent_rate / MHZ);
+ if (allow_slide && (cfg & GPCPLL_CFG_ENABLE)) {
+ int ret = gk20a_pllg_slide(priv, n_lo);
+
+ if (ret)
+ return ret;
+ }
+
+ /* split FO-to-bypass jump in halfs by setting out divider 1:2 */
+ nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_VCODIV_MASK,
+ 0x2 << GPC2CLK_OUT_VCODIV_SHIFT);
+
+ /* put PLL in bypass before programming it */
+ val = nv_rd32(priv, SEL_VCO);
+ val &= ~(BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
+ udelay(2);
+ nv_wr32(priv, SEL_VCO, val);
+
+ /* get out from IDDQ */
+ val = nv_rd32(priv, GPCPLL_CFG);
+ if (val & GPCPLL_CFG_IDDQ) {
+ val &= ~GPCPLL_CFG_IDDQ;
+ nv_wr32(priv, GPCPLL_CFG, val);
+ nv_rd32(priv, GPCPLL_CFG);
+ udelay(2);
+ }
+
+ _gk20a_pllg_disable(priv);
+
+ nv_debug(priv, "%s: m=%d n=%d pl=%d\n", __func__, priv->m, priv->n,
+ priv->pl);
+
+ n_lo = DIV_ROUND_UP(priv->m * priv->params->min_vco,
+ priv->parent_rate / MHZ);
+ val = priv->m << GPCPLL_COEFF_M_SHIFT;
+ val |= (allow_slide ? n_lo : priv->n) << GPCPLL_COEFF_N_SHIFT;
+ val |= priv->pl << GPCPLL_COEFF_P_SHIFT;
+ nv_wr32(priv, GPCPLL_COEFF, val);
+
+ _gk20a_pllg_enable(priv);
+
+ val = nv_rd32(priv, GPCPLL_CFG);
+ if (val & GPCPLL_CFG_LOCK_DET_OFF) {
+ val &= ~GPCPLL_CFG_LOCK_DET_OFF;
+ nv_wr32(priv, GPCPLL_CFG, val);
+ }
+
+ if (!nvkm_timer_wait_eq(priv, 300000, GPCPLL_CFG, GPCPLL_CFG_LOCK,
+ GPCPLL_CFG_LOCK)) {
+ nv_error(priv, "%s: timeout waiting for pllg lock\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ /* switch to VCO mode */
+ nv_mask(priv, SEL_VCO, 0, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT));
+
+ /* restore out divider 1:1 */
+ val = nv_rd32(priv, GPC2CLK_OUT);
+ val &= ~GPC2CLK_OUT_VCODIV_MASK;
+ udelay(2);
+ nv_wr32(priv, GPC2CLK_OUT, val);
+
+ /* slide up to new NDIV */
+ return allow_slide ? gk20a_pllg_slide(priv, priv->n) : 0;
+}
+
+static int
+gk20a_pllg_program_mnp(struct gk20a_clk_priv *priv)
+{
+ int err;
+
+ err = _gk20a_pllg_program_mnp(priv, true);
+ if (err)
+ err = _gk20a_pllg_program_mnp(priv, false);
+
+ return err;
+}
+
+static void
+gk20a_pllg_disable(struct gk20a_clk_priv *priv)
+{
+ u32 val;
+
+ /* slide to VCO min */
+ val = nv_rd32(priv, GPCPLL_CFG);
+ if (val & GPCPLL_CFG_ENABLE) {
+ u32 coeff, m, n_lo;
+
+ coeff = nv_rd32(priv, GPCPLL_COEFF);
+ m = (coeff >> GPCPLL_COEFF_M_SHIFT) & MASK(GPCPLL_COEFF_M_WIDTH);
+ n_lo = DIV_ROUND_UP(m * priv->params->min_vco,
+ priv->parent_rate / MHZ);
+ gk20a_pllg_slide(priv, n_lo);
+ }
+
+ /* put PLL in bypass before disabling it */
+ nv_mask(priv, SEL_VCO, BIT(SEL_VCO_GPC2CLK_OUT_SHIFT), 0);
+
+ _gk20a_pllg_disable(priv);
+}
+
+#define GK20A_CLK_GPC_MDIV 1000
+
+static struct nvkm_domain
+gk20a_domains[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_gpc, 0xff, 0, "core", GK20A_CLK_GPC_MDIV },
+ { nv_clk_src_max }
+};
+
+static struct nvkm_pstate
+gk20a_pstates[] = {
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 72000,
+ .voltage = 0,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 108000,
+ .voltage = 1,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 180000,
+ .voltage = 2,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 252000,
+ .voltage = 3,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 324000,
+ .voltage = 4,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 396000,
+ .voltage = 5,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 468000,
+ .voltage = 6,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 540000,
+ .voltage = 7,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 612000,
+ .voltage = 8,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 648000,
+ .voltage = 9,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 684000,
+ .voltage = 10,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 708000,
+ .voltage = 11,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 756000,
+ .voltage = 12,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 804000,
+ .voltage = 13,
+ },
+ },
+ {
+ .base = {
+ .domain[nv_clk_src_gpc] = 852000,
+ .voltage = 14,
+ },
+ },
+};
+
+static int
+gk20a_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct gk20a_clk_priv *priv = (void *)clk;
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return nv_device(clk)->crystal;
+ case nv_clk_src_gpc:
+ gk20a_pllg_read_mnp(priv);
+ return gk20a_pllg_calc_rate(priv) / GK20A_CLK_GPC_MDIV;
+ default:
+ nv_error(clk, "invalid clock source %d\n", src);
+ return -EINVAL;
+ }
+}
+
+static int
+gk20a_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct gk20a_clk_priv *priv = (void *)clk;
+
+ return gk20a_pllg_calc_mnp(priv, cstate->domain[nv_clk_src_gpc] *
+ GK20A_CLK_GPC_MDIV);
+}
+
+static int
+gk20a_clk_prog(struct nvkm_clk *clk)
+{
+ struct gk20a_clk_priv *priv = (void *)clk;
+
+ return gk20a_pllg_program_mnp(priv);
+}
+
+static void
+gk20a_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static int
+gk20a_clk_fini(struct nvkm_object *object, bool suspend)
+{
+ struct gk20a_clk_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_clk_fini(&priv->base, false);
+
+ gk20a_pllg_disable(priv);
+
+ return ret;
+}
+
+static int
+gk20a_clk_init(struct nvkm_object *object)
+{
+ struct gk20a_clk_priv *priv = (void *)object;
+ int ret;
+
+ nv_mask(priv, GPC2CLK_OUT, GPC2CLK_OUT_INIT_MASK, GPC2CLK_OUT_INIT_VAL);
+
+ ret = nvkm_clk_init(&priv->base);
+ if (ret)
+ return ret;
+
+ ret = gk20a_clk_prog(&priv->base);
+ if (ret) {
+ nv_error(priv, "cannot initialize clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+gk20a_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk20a_clk_priv *priv;
+ struct nouveau_platform_device *plat;
+ int ret;
+ int i;
+
+ /* Finish initializing the pstates */
+ for (i = 0; i < ARRAY_SIZE(gk20a_pstates); i++) {
+ INIT_LIST_HEAD(&gk20a_pstates[i].list);
+ gk20a_pstates[i].pstate = i + 1;
+ }
+
+ ret = nvkm_clk_create(parent, engine, oclass, gk20a_domains,
+ gk20a_pstates, ARRAY_SIZE(gk20a_pstates),
+ true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->params = &gk20a_pllg_params;
+
+ plat = nv_device_to_platform(nv_device(parent));
+ priv->parent_rate = clk_get_rate(plat->gpu->clk);
+ nv_info(priv, "parent clock rate: %d Mhz\n", priv->parent_rate / MHZ);
+
+ priv->base.read = gk20a_clk_read;
+ priv->base.calc = gk20a_clk_calc;
+ priv->base.prog = gk20a_clk_prog;
+ priv->base.tidy = gk20a_clk_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+gk20a_clk_oclass = {
+ .handle = NV_SUBDEV(CLK, 0xea),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_clk_ctor,
+ .dtor = _nvkm_subdev_dtor,
+ .init = gk20a_clk_init,
+ .fini = gk20a_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
new file mode 100644
index 000000000000..822d32a28d6e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.c
@@ -0,0 +1,533 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Roy Spliet
+ */
+#include "gt215.h"
+#include "pll.h"
+
+#include <core/device.h>
+#include <engine/fifo.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/timer.h>
+
+struct gt215_clk_priv {
+ struct nvkm_clk base;
+ struct gt215_clk_info eng[nv_clk_src_max];
+};
+
+static u32 read_clk(struct gt215_clk_priv *, int, bool);
+static u32 read_pll(struct gt215_clk_priv *, int, u32);
+
+static u32
+read_vco(struct gt215_clk_priv *priv, int clk)
+{
+ u32 sctl = nv_rd32(priv, 0x4120 + (clk * 4));
+
+ switch (sctl & 0x00000030) {
+ case 0x00000000:
+ return nv_device(priv)->crystal;
+ case 0x00000020:
+ return read_pll(priv, 0x41, 0x00e820);
+ case 0x00000030:
+ return read_pll(priv, 0x42, 0x00e8a0);
+ default:
+ return 0;
+ }
+}
+
+static u32
+read_clk(struct gt215_clk_priv *priv, int clk, bool ignore_en)
+{
+ u32 sctl, sdiv, sclk;
+
+ /* refclk for the 0xe8xx plls is a fixed frequency */
+ if (clk >= 0x40) {
+ if (nv_device(priv)->chipset == 0xaf) {
+ /* no joke.. seriously.. sigh.. */
+ return nv_rd32(priv, 0x00471c) * 1000;
+ }
+
+ return nv_device(priv)->crystal;
+ }
+
+ sctl = nv_rd32(priv, 0x4120 + (clk * 4));
+ if (!ignore_en && !(sctl & 0x00000100))
+ return 0;
+
+ /* out_alt */
+ if (sctl & 0x00000400)
+ return 108000;
+
+ /* vco_out */
+ switch (sctl & 0x00003000) {
+ case 0x00000000:
+ if (!(sctl & 0x00000200))
+ return nv_device(priv)->crystal;
+ return 0;
+ case 0x00002000:
+ if (sctl & 0x00000040)
+ return 108000;
+ return 100000;
+ case 0x00003000:
+ /* vco_enable */
+ if (!(sctl & 0x00000001))
+ return 0;
+
+ sclk = read_vco(priv, clk);
+ sdiv = ((sctl & 0x003f0000) >> 16) + 2;
+ return (sclk * 2) / sdiv;
+ default:
+ return 0;
+ }
+}
+
+static u32
+read_pll(struct gt215_clk_priv *priv, int clk, u32 pll)
+{
+ u32 ctrl = nv_rd32(priv, pll + 0);
+ u32 sclk = 0, P = 1, N = 1, M = 1;
+
+ if (!(ctrl & 0x00000008)) {
+ if (ctrl & 0x00000001) {
+ u32 coef = nv_rd32(priv, pll + 4);
+ M = (coef & 0x000000ff) >> 0;
+ N = (coef & 0x0000ff00) >> 8;
+ P = (coef & 0x003f0000) >> 16;
+
+ /* no post-divider on these..
+ * XXX: it looks more like two post-"dividers" that
+ * cross each other out in the default RPLL config */
+ if ((pll & 0x00ff00) == 0x00e800)
+ P = 1;
+
+ sclk = read_clk(priv, 0x00 + clk, false);
+ }
+ } else {
+ sclk = read_clk(priv, 0x10 + clk, false);
+ }
+
+ if (M * P)
+ return sclk * N / (M * P);
+
+ return 0;
+}
+
+static int
+gt215_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct gt215_clk_priv *priv = (void *)clk;
+ u32 hsrc;
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return nv_device(priv)->crystal;
+ case nv_clk_src_core:
+ case nv_clk_src_core_intm:
+ return read_pll(priv, 0x00, 0x4200);
+ case nv_clk_src_shader:
+ return read_pll(priv, 0x01, 0x4220);
+ case nv_clk_src_mem:
+ return read_pll(priv, 0x02, 0x4000);
+ case nv_clk_src_disp:
+ return read_clk(priv, 0x20, false);
+ case nv_clk_src_vdec:
+ return read_clk(priv, 0x21, false);
+ case nv_clk_src_daemon:
+ return read_clk(priv, 0x25, false);
+ case nv_clk_src_host:
+ hsrc = (nv_rd32(priv, 0xc040) & 0x30000000) >> 28;
+ switch (hsrc) {
+ case 0:
+ return read_clk(priv, 0x1d, false);
+ case 2:
+ case 3:
+ return 277000;
+ default:
+ nv_error(clk, "unknown HOST clock source %d\n", hsrc);
+ return -EINVAL;
+ }
+ default:
+ nv_error(clk, "invalid clock source %d\n", src);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int
+gt215_clk_info(struct nvkm_clk *clock, int clk, u32 khz,
+ struct gt215_clk_info *info)
+{
+ struct gt215_clk_priv *priv = (void *)clock;
+ u32 oclk, sclk, sdiv, diff;
+
+ info->clk = 0;
+
+ switch (khz) {
+ case 27000:
+ info->clk = 0x00000100;
+ return khz;
+ case 100000:
+ info->clk = 0x00002100;
+ return khz;
+ case 108000:
+ info->clk = 0x00002140;
+ return khz;
+ default:
+ sclk = read_vco(priv, clk);
+ sdiv = min((sclk * 2) / khz, (u32)65);
+ oclk = (sclk * 2) / sdiv;
+ diff = ((khz + 3000) - oclk);
+
+ /* When imprecise, play it safe and aim for a clock lower than
+ * desired rather than higher */
+ if (diff < 0) {
+ sdiv++;
+ oclk = (sclk * 2) / sdiv;
+ }
+
+ /* divider can go as low as 2, limited here because NVIDIA
+ * and the VBIOS on my NVA8 seem to prefer using the PLL
+ * for 810MHz - is there a good reason?
+ * XXX: PLLs with refclk 810MHz? */
+ if (sdiv > 4) {
+ info->clk = (((sdiv - 2) << 16) | 0x00003100);
+ return oclk;
+ }
+
+ break;
+ }
+
+ return -ERANGE;
+}
+
+int
+gt215_pll_info(struct nvkm_clk *clock, int clk, u32 pll, u32 khz,
+ struct gt215_clk_info *info)
+{
+ struct nvkm_bios *bios = nvkm_bios(clock);
+ struct gt215_clk_priv *priv = (void *)clock;
+ struct nvbios_pll limits;
+ int P, N, M, diff;
+ int ret;
+
+ info->pll = 0;
+
+ /* If we can get a within [-2, 3) MHz of a divider, we'll disable the
+ * PLL and use the divider instead. */
+ ret = gt215_clk_info(clock, clk, khz, info);
+ diff = khz - ret;
+ if (!pll || (diff >= -2000 && diff < 3000)) {
+ goto out;
+ }
+
+ /* Try with PLL */
+ ret = nvbios_pll_parse(bios, pll, &limits);
+ if (ret)
+ return ret;
+
+ ret = gt215_clk_info(clock, clk - 0x10, limits.refclk, info);
+ if (ret != limits.refclk)
+ return -EINVAL;
+
+ ret = gt215_pll_calc(nv_subdev(priv), &limits, khz, &N, NULL, &M, &P);
+ if (ret >= 0) {
+ info->pll = (P << 16) | (N << 8) | M;
+ }
+
+out:
+ info->fb_delay = max(((khz + 7566) / 15133), (u32) 18);
+ return ret ? ret : -ERANGE;
+}
+
+static int
+calc_clk(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate,
+ int clk, u32 pll, int idx)
+{
+ int ret = gt215_pll_info(&priv->base, clk, pll, cstate->domain[idx],
+ &priv->eng[idx]);
+ if (ret >= 0)
+ return 0;
+ return ret;
+}
+
+static int
+calc_host(struct gt215_clk_priv *priv, struct nvkm_cstate *cstate)
+{
+ int ret = 0;
+ u32 kHz = cstate->domain[nv_clk_src_host];
+ struct gt215_clk_info *info = &priv->eng[nv_clk_src_host];
+
+ if (kHz == 277000) {
+ info->clk = 0;
+ info->host_out = NVA3_HOST_277;
+ return 0;
+ }
+
+ info->host_out = NVA3_HOST_CLK;
+
+ ret = gt215_clk_info(&priv->base, 0x1d, kHz, info);
+ if (ret >= 0)
+ return 0;
+
+ return ret;
+}
+
+int
+gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(clk);
+
+ /* halt and idle execution engines */
+ nv_mask(clk, 0x020060, 0x00070000, 0x00000000);
+ nv_mask(clk, 0x002504, 0x00000001, 0x00000001);
+ /* Wait until the interrupt handler is finished */
+ if (!nv_wait(clk, 0x000100, 0xffffffff, 0x00000000))
+ return -EBUSY;
+
+ if (pfifo)
+ pfifo->pause(pfifo, flags);
+
+ if (!nv_wait(clk, 0x002504, 0x00000010, 0x00000010))
+ return -EIO;
+ if (!nv_wait(clk, 0x00251c, 0x0000003f, 0x0000003f))
+ return -EIO;
+
+ return 0;
+}
+
+void
+gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags)
+{
+ struct nvkm_fifo *pfifo = nvkm_fifo(clk);
+
+ if (pfifo && flags)
+ pfifo->start(pfifo, flags);
+
+ nv_mask(clk, 0x002504, 0x00000001, 0x00000000);
+ nv_mask(clk, 0x020060, 0x00070000, 0x00040000);
+}
+
+static void
+disable_clk_src(struct gt215_clk_priv *priv, u32 src)
+{
+ nv_mask(priv, src, 0x00000100, 0x00000000);
+ nv_mask(priv, src, 0x00000001, 0x00000000);
+}
+
+static void
+prog_pll(struct gt215_clk_priv *priv, int clk, u32 pll, int idx)
+{
+ struct gt215_clk_info *info = &priv->eng[idx];
+ const u32 src0 = 0x004120 + (clk * 4);
+ const u32 src1 = 0x004160 + (clk * 4);
+ const u32 ctrl = pll + 0;
+ const u32 coef = pll + 4;
+ u32 bypass;
+
+ if (info->pll) {
+ /* Always start from a non-PLL clock */
+ bypass = nv_rd32(priv, ctrl) & 0x00000008;
+ if (!bypass) {
+ nv_mask(priv, src1, 0x00000101, 0x00000101);
+ nv_mask(priv, ctrl, 0x00000008, 0x00000008);
+ udelay(20);
+ }
+
+ nv_mask(priv, src0, 0x003f3141, 0x00000101 | info->clk);
+ nv_wr32(priv, coef, info->pll);
+ nv_mask(priv, ctrl, 0x00000015, 0x00000015);
+ nv_mask(priv, ctrl, 0x00000010, 0x00000000);
+ if (!nv_wait(priv, ctrl, 0x00020000, 0x00020000)) {
+ nv_mask(priv, ctrl, 0x00000010, 0x00000010);
+ nv_mask(priv, src0, 0x00000101, 0x00000000);
+ return;
+ }
+ nv_mask(priv, ctrl, 0x00000010, 0x00000010);
+ nv_mask(priv, ctrl, 0x00000008, 0x00000000);
+ disable_clk_src(priv, src1);
+ } else {
+ nv_mask(priv, src1, 0x003f3141, 0x00000101 | info->clk);
+ nv_mask(priv, ctrl, 0x00000018, 0x00000018);
+ udelay(20);
+ nv_mask(priv, ctrl, 0x00000001, 0x00000000);
+ disable_clk_src(priv, src0);
+ }
+}
+
+static void
+prog_clk(struct gt215_clk_priv *priv, int clk, int idx)
+{
+ struct gt215_clk_info *info = &priv->eng[idx];
+ nv_mask(priv, 0x004120 + (clk * 4), 0x003f3141, 0x00000101 | info->clk);
+}
+
+static void
+prog_host(struct gt215_clk_priv *priv)
+{
+ struct gt215_clk_info *info = &priv->eng[nv_clk_src_host];
+ u32 hsrc = (nv_rd32(priv, 0xc040));
+
+ switch (info->host_out) {
+ case NVA3_HOST_277:
+ if ((hsrc & 0x30000000) == 0) {
+ nv_wr32(priv, 0xc040, hsrc | 0x20000000);
+ disable_clk_src(priv, 0x4194);
+ }
+ break;
+ case NVA3_HOST_CLK:
+ prog_clk(priv, 0x1d, nv_clk_src_host);
+ if ((hsrc & 0x30000000) >= 0x20000000) {
+ nv_wr32(priv, 0xc040, hsrc & ~0x30000000);
+ }
+ break;
+ default:
+ break;
+ }
+
+ /* This seems to be a clock gating factor on idle, always set to 64 */
+ nv_wr32(priv, 0xc044, 0x3e);
+}
+
+static void
+prog_core(struct gt215_clk_priv *priv, int idx)
+{
+ struct gt215_clk_info *info = &priv->eng[idx];
+ u32 fb_delay = nv_rd32(priv, 0x10002c);
+
+ if (fb_delay < info->fb_delay)
+ nv_wr32(priv, 0x10002c, info->fb_delay);
+
+ prog_pll(priv, 0x00, 0x004200, idx);
+
+ if (fb_delay > info->fb_delay)
+ nv_wr32(priv, 0x10002c, info->fb_delay);
+}
+
+static int
+gt215_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct gt215_clk_priv *priv = (void *)clk;
+ struct gt215_clk_info *core = &priv->eng[nv_clk_src_core];
+ int ret;
+
+ if ((ret = calc_clk(priv, cstate, 0x10, 0x4200, nv_clk_src_core)) ||
+ (ret = calc_clk(priv, cstate, 0x11, 0x4220, nv_clk_src_shader)) ||
+ (ret = calc_clk(priv, cstate, 0x20, 0x0000, nv_clk_src_disp)) ||
+ (ret = calc_clk(priv, cstate, 0x21, 0x0000, nv_clk_src_vdec)) ||
+ (ret = calc_host(priv, cstate)))
+ return ret;
+
+ /* XXX: Should be reading the highest bit in the VBIOS clock to decide
+ * whether to use a PLL or not... but using a PLL defeats the purpose */
+ if (core->pll) {
+ ret = gt215_clk_info(clk, 0x10,
+ cstate->domain[nv_clk_src_core_intm],
+ &priv->eng[nv_clk_src_core_intm]);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int
+gt215_clk_prog(struct nvkm_clk *clk)
+{
+ struct gt215_clk_priv *priv = (void *)clk;
+ struct gt215_clk_info *core = &priv->eng[nv_clk_src_core];
+ int ret = 0;
+ unsigned long flags;
+ unsigned long *f = &flags;
+
+ ret = gt215_clk_pre(clk, f);
+ if (ret)
+ goto out;
+
+ if (core->pll)
+ prog_core(priv, nv_clk_src_core_intm);
+
+ prog_core(priv, nv_clk_src_core);
+ prog_pll(priv, 0x01, 0x004220, nv_clk_src_shader);
+ prog_clk(priv, 0x20, nv_clk_src_disp);
+ prog_clk(priv, 0x21, nv_clk_src_vdec);
+ prog_host(priv);
+
+out:
+ if (ret == -EBUSY)
+ f = NULL;
+
+ gt215_clk_post(clk, f);
+ return ret;
+}
+
+static void
+gt215_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static struct nvkm_domain
+gt215_domain[] = {
+ { nv_clk_src_crystal , 0xff },
+ { nv_clk_src_core , 0x00, 0, "core", 1000 },
+ { nv_clk_src_shader , 0x01, 0, "shader", 1000 },
+ { nv_clk_src_mem , 0x02, 0, "memory", 1000 },
+ { nv_clk_src_vdec , 0x03 },
+ { nv_clk_src_disp , 0x04 },
+ { nv_clk_src_host , 0x05 },
+ { nv_clk_src_core_intm, 0x06 },
+ { nv_clk_src_max }
+};
+
+static int
+gt215_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gt215_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, gt215_domain,
+ NULL, 0, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.read = gt215_clk_read;
+ priv->base.calc = gt215_clk_calc;
+ priv->base.prog = gt215_clk_prog;
+ priv->base.tidy = gt215_clk_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+gt215_clk_oclass = {
+ .handle = NV_SUBDEV(CLK, 0xa3),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt215_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h
new file mode 100644
index 000000000000..b447d9cd4d37
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/gt215.h
@@ -0,0 +1,18 @@
+#ifndef __NVKM_CLK_NVA3_H__
+#define __NVKM_CLK_NVA3_H__
+#include <subdev/clk.h>
+
+struct gt215_clk_info {
+ u32 clk;
+ u32 pll;
+ enum {
+ NVA3_HOST_277,
+ NVA3_HOST_CLK,
+ } host_out;
+ u32 fb_delay;
+};
+
+int gt215_pll_info(struct nvkm_clk *, int, u32, u32, struct gt215_clk_info *);
+int gt215_clk_pre(struct nvkm_clk *clk, unsigned long *flags);
+void gt215_clk_post(struct nvkm_clk *clk, unsigned long *flags);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c
new file mode 100644
index 000000000000..c54417b146c7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/mcp77.c
@@ -0,0 +1,429 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gt215.h"
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/timer.h>
+
+struct mcp77_clk_priv {
+ struct nvkm_clk base;
+ enum nv_clk_src csrc, ssrc, vsrc;
+ u32 cctrl, sctrl;
+ u32 ccoef, scoef;
+ u32 cpost, spost;
+ u32 vdiv;
+};
+
+static u32
+read_div(struct nvkm_clk *clk)
+{
+ return nv_rd32(clk, 0x004600);
+}
+
+static u32
+read_pll(struct nvkm_clk *clk, u32 base)
+{
+ u32 ctrl = nv_rd32(clk, base + 0);
+ u32 coef = nv_rd32(clk, base + 4);
+ u32 ref = clk->read(clk, nv_clk_src_href);
+ u32 post_div = 0;
+ u32 clock = 0;
+ int N1, M1;
+
+ switch (base){
+ case 0x4020:
+ post_div = 1 << ((nv_rd32(clk, 0x4070) & 0x000f0000) >> 16);
+ break;
+ case 0x4028:
+ post_div = (nv_rd32(clk, 0x4040) & 0x000f0000) >> 16;
+ break;
+ default:
+ break;
+ }
+
+ N1 = (coef & 0x0000ff00) >> 8;
+ M1 = (coef & 0x000000ff);
+ if ((ctrl & 0x80000000) && M1) {
+ clock = ref * N1 / M1;
+ clock = clock / post_div;
+ }
+
+ return clock;
+}
+
+static int
+mcp77_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct mcp77_clk_priv *priv = (void *)clk;
+ u32 mast = nv_rd32(clk, 0x00c054);
+ u32 P = 0;
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return nv_device(priv)->crystal;
+ case nv_clk_src_href:
+ return 100000; /* PCIE reference clock */
+ case nv_clk_src_hclkm4:
+ return clk->read(clk, nv_clk_src_href) * 4;
+ case nv_clk_src_hclkm2d3:
+ return clk->read(clk, nv_clk_src_href) * 2 / 3;
+ case nv_clk_src_host:
+ switch (mast & 0x000c0000) {
+ case 0x00000000: return clk->read(clk, nv_clk_src_hclkm2d3);
+ case 0x00040000: break;
+ case 0x00080000: return clk->read(clk, nv_clk_src_hclkm4);
+ case 0x000c0000: return clk->read(clk, nv_clk_src_cclk);
+ }
+ break;
+ case nv_clk_src_core:
+ P = (nv_rd32(clk, 0x004028) & 0x00070000) >> 16;
+
+ switch (mast & 0x00000003) {
+ case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
+ case 0x00000001: return 0;
+ case 0x00000002: return clk->read(clk, nv_clk_src_hclkm4) >> P;
+ case 0x00000003: return read_pll(clk, 0x004028) >> P;
+ }
+ break;
+ case nv_clk_src_cclk:
+ if ((mast & 0x03000000) != 0x03000000)
+ return clk->read(clk, nv_clk_src_core);
+
+ if ((mast & 0x00000200) == 0x00000000)
+ return clk->read(clk, nv_clk_src_core);
+
+ switch (mast & 0x00000c00) {
+ case 0x00000000: return clk->read(clk, nv_clk_src_href);
+ case 0x00000400: return clk->read(clk, nv_clk_src_hclkm4);
+ case 0x00000800: return clk->read(clk, nv_clk_src_hclkm2d3);
+ default: return 0;
+ }
+ case nv_clk_src_shader:
+ P = (nv_rd32(clk, 0x004020) & 0x00070000) >> 16;
+ switch (mast & 0x00000030) {
+ case 0x00000000:
+ if (mast & 0x00000040)
+ return clk->read(clk, nv_clk_src_href) >> P;
+ return clk->read(clk, nv_clk_src_crystal) >> P;
+ case 0x00000010: break;
+ case 0x00000020: return read_pll(clk, 0x004028) >> P;
+ case 0x00000030: return read_pll(clk, 0x004020) >> P;
+ }
+ break;
+ case nv_clk_src_mem:
+ return 0;
+ break;
+ case nv_clk_src_vdec:
+ P = (read_div(clk) & 0x00000700) >> 8;
+
+ switch (mast & 0x00400000) {
+ case 0x00400000:
+ return clk->read(clk, nv_clk_src_core) >> P;
+ break;
+ default:
+ return 500000 >> P;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+ return 0;
+}
+
+static u32
+calc_pll(struct mcp77_clk_priv *priv, u32 reg,
+ u32 clock, int *N, int *M, int *P)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll pll;
+ struct nvkm_clk *clk = &priv->base;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, reg, &pll);
+ if (ret)
+ return 0;
+
+ pll.vco2.max_freq = 0;
+ pll.refclk = clk->read(clk, nv_clk_src_href);
+ if (!pll.refclk)
+ return 0;
+
+ return nv04_pll_calc(nv_subdev(priv), &pll, clock, N, M, NULL, NULL, P);
+}
+
+static inline u32
+calc_P(u32 src, u32 target, int *div)
+{
+ u32 clk0 = src, clk1 = src;
+ for (*div = 0; *div <= 7; (*div)++) {
+ if (clk0 <= target) {
+ clk1 = clk0 << (*div ? 1 : 0);
+ break;
+ }
+ clk0 >>= 1;
+ }
+
+ if (target - clk0 <= clk1 - target)
+ return clk0;
+ (*div)--;
+ return clk1;
+}
+
+static int
+mcp77_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct mcp77_clk_priv *priv = (void *)clk;
+ const int shader = cstate->domain[nv_clk_src_shader];
+ const int core = cstate->domain[nv_clk_src_core];
+ const int vdec = cstate->domain[nv_clk_src_vdec];
+ u32 out = 0, clock = 0;
+ int N, M, P1, P2 = 0;
+ int divs = 0;
+
+ /* cclk: find suitable source, disable PLL if we can */
+ if (core < clk->read(clk, nv_clk_src_hclkm4))
+ out = calc_P(clk->read(clk, nv_clk_src_hclkm4), core, &divs);
+
+ /* Calculate clock * 2, so shader clock can use it too */
+ clock = calc_pll(priv, 0x4028, (core << 1), &N, &M, &P1);
+
+ if (abs(core - out) <= abs(core - (clock >> 1))) {
+ priv->csrc = nv_clk_src_hclkm4;
+ priv->cctrl = divs << 16;
+ } else {
+ /* NVCTRL is actually used _after_ NVPOST, and after what we
+ * call NVPLL. To make matters worse, NVPOST is an integer
+ * divider instead of a right-shift number. */
+ if(P1 > 2) {
+ P2 = P1 - 2;
+ P1 = 2;
+ }
+
+ priv->csrc = nv_clk_src_core;
+ priv->ccoef = (N << 8) | M;
+
+ priv->cctrl = (P2 + 1) << 16;
+ priv->cpost = (1 << P1) << 16;
+ }
+
+ /* sclk: nvpll + divisor, href or spll */
+ out = 0;
+ if (shader == clk->read(clk, nv_clk_src_href)) {
+ priv->ssrc = nv_clk_src_href;
+ } else {
+ clock = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
+ if (priv->csrc == nv_clk_src_core)
+ out = calc_P((core << 1), shader, &divs);
+
+ if (abs(shader - out) <=
+ abs(shader - clock) &&
+ (divs + P2) <= 7) {
+ priv->ssrc = nv_clk_src_core;
+ priv->sctrl = (divs + P2) << 16;
+ } else {
+ priv->ssrc = nv_clk_src_shader;
+ priv->scoef = (N << 8) | M;
+ priv->sctrl = P1 << 16;
+ }
+ }
+
+ /* vclk */
+ out = calc_P(core, vdec, &divs);
+ clock = calc_P(500000, vdec, &P1);
+ if(abs(vdec - out) <= abs(vdec - clock)) {
+ priv->vsrc = nv_clk_src_cclk;
+ priv->vdiv = divs << 16;
+ } else {
+ priv->vsrc = nv_clk_src_vdec;
+ priv->vdiv = P1 << 16;
+ }
+
+ /* Print strategy! */
+ nv_debug(priv, "nvpll: %08x %08x %08x\n",
+ priv->ccoef, priv->cpost, priv->cctrl);
+ nv_debug(priv, " spll: %08x %08x %08x\n",
+ priv->scoef, priv->spost, priv->sctrl);
+ nv_debug(priv, " vdiv: %08x\n", priv->vdiv);
+ if (priv->csrc == nv_clk_src_hclkm4)
+ nv_debug(priv, "core: hrefm4\n");
+ else
+ nv_debug(priv, "core: nvpll\n");
+
+ if (priv->ssrc == nv_clk_src_hclkm4)
+ nv_debug(priv, "shader: hrefm4\n");
+ else if (priv->ssrc == nv_clk_src_core)
+ nv_debug(priv, "shader: nvpll\n");
+ else
+ nv_debug(priv, "shader: spll\n");
+
+ if (priv->vsrc == nv_clk_src_hclkm4)
+ nv_debug(priv, "vdec: 500MHz\n");
+ else
+ nv_debug(priv, "vdec: core\n");
+
+ return 0;
+}
+
+static int
+mcp77_clk_prog(struct nvkm_clk *clk)
+{
+ struct mcp77_clk_priv *priv = (void *)clk;
+ u32 pllmask = 0, mast;
+ unsigned long flags;
+ unsigned long *f = &flags;
+ int ret = 0;
+
+ ret = gt215_clk_pre(clk, f);
+ if (ret)
+ goto out;
+
+ /* First switch to safe clocks: href */
+ mast = nv_mask(clk, 0xc054, 0x03400e70, 0x03400640);
+ mast &= ~0x00400e73;
+ mast |= 0x03000000;
+
+ switch (priv->csrc) {
+ case nv_clk_src_hclkm4:
+ nv_mask(clk, 0x4028, 0x00070000, priv->cctrl);
+ mast |= 0x00000002;
+ break;
+ case nv_clk_src_core:
+ nv_wr32(clk, 0x402c, priv->ccoef);
+ nv_wr32(clk, 0x4028, 0x80000000 | priv->cctrl);
+ nv_wr32(clk, 0x4040, priv->cpost);
+ pllmask |= (0x3 << 8);
+ mast |= 0x00000003;
+ break;
+ default:
+ nv_warn(priv,"Reclocking failed: unknown core clock\n");
+ goto resume;
+ }
+
+ switch (priv->ssrc) {
+ case nv_clk_src_href:
+ nv_mask(clk, 0x4020, 0x00070000, 0x00000000);
+ /* mast |= 0x00000000; */
+ break;
+ case nv_clk_src_core:
+ nv_mask(clk, 0x4020, 0x00070000, priv->sctrl);
+ mast |= 0x00000020;
+ break;
+ case nv_clk_src_shader:
+ nv_wr32(clk, 0x4024, priv->scoef);
+ nv_wr32(clk, 0x4020, 0x80000000 | priv->sctrl);
+ nv_wr32(clk, 0x4070, priv->spost);
+ pllmask |= (0x3 << 12);
+ mast |= 0x00000030;
+ break;
+ default:
+ nv_warn(priv,"Reclocking failed: unknown sclk clock\n");
+ goto resume;
+ }
+
+ if (!nv_wait(clk, 0x004080, pllmask, pllmask)) {
+ nv_warn(priv,"Reclocking failed: unstable PLLs\n");
+ goto resume;
+ }
+
+ switch (priv->vsrc) {
+ case nv_clk_src_cclk:
+ mast |= 0x00400000;
+ default:
+ nv_wr32(clk, 0x4600, priv->vdiv);
+ }
+
+ nv_wr32(clk, 0xc054, mast);
+
+resume:
+ /* Disable some PLLs and dividers when unused */
+ if (priv->csrc != nv_clk_src_core) {
+ nv_wr32(clk, 0x4040, 0x00000000);
+ nv_mask(clk, 0x4028, 0x80000000, 0x00000000);
+ }
+
+ if (priv->ssrc != nv_clk_src_shader) {
+ nv_wr32(clk, 0x4070, 0x00000000);
+ nv_mask(clk, 0x4020, 0x80000000, 0x00000000);
+ }
+
+out:
+ if (ret == -EBUSY)
+ f = NULL;
+
+ gt215_clk_post(clk, f);
+ return ret;
+}
+
+static void
+mcp77_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static struct nvkm_domain
+mcp77_domains[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_href , 0xff },
+ { nv_clk_src_core , 0xff, 0, "core", 1000 },
+ { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+ { nv_clk_src_vdec , 0xff, 0, "vdec", 1000 },
+ { nv_clk_src_max }
+};
+
+static int
+mcp77_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct mcp77_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, mcp77_domains,
+ NULL, 0, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.read = mcp77_clk_read;
+ priv->base.calc = mcp77_clk_calc;
+ priv->base.prog = mcp77_clk_prog;
+ priv->base.tidy = mcp77_clk_tidy;
+ return 0;
+}
+
+struct nvkm_oclass *
+mcp77_clk_oclass = &(struct nvkm_oclass) {
+ .handle = NV_SUBDEV(CLK, 0xaa),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = mcp77_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c
new file mode 100644
index 000000000000..63dbbb575228
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv04.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/devinit/nv04.h>
+
+struct nv04_clk_priv {
+ struct nvkm_clk base;
+};
+
+int
+nv04_clk_pll_calc(struct nvkm_clk *clock, struct nvbios_pll *info,
+ int clk, struct nvkm_pll_vals *pv)
+{
+ int N1, M1, N2, M2, P;
+ int ret = nv04_pll_calc(nv_subdev(clock), info, clk, &N1, &M1, &N2, &M2, &P);
+ if (ret) {
+ pv->refclk = info->refclk;
+ pv->N1 = N1;
+ pv->M1 = M1;
+ pv->N2 = N2;
+ pv->M2 = M2;
+ pv->log2P = P;
+ }
+ return ret;
+}
+
+int
+nv04_clk_pll_prog(struct nvkm_clk *clk, u32 reg1, struct nvkm_pll_vals *pv)
+{
+ struct nvkm_devinit *devinit = nvkm_devinit(clk);
+ int cv = nvkm_bios(clk)->version.chip;
+
+ if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
+ cv >= 0x40) {
+ if (reg1 > 0x405c)
+ setPLL_double_highregs(devinit, reg1, pv);
+ else
+ setPLL_double_lowregs(devinit, reg1, pv);
+ } else
+ setPLL_single(devinit, reg1, pv);
+
+ return 0;
+}
+
+static struct nvkm_domain
+nv04_domain[] = {
+ { nv_clk_src_max }
+};
+
+static int
+nv04_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, nv04_domain,
+ NULL, 0, false, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.pll_calc = nv04_clk_pll_calc;
+ priv->base.pll_prog = nv04_clk_pll_prog;
+ return 0;
+}
+
+struct nvkm_oclass
+nv04_clk_oclass = {
+ .handle = NV_SUBDEV(CLK, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c
new file mode 100644
index 000000000000..ed838130c89d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv40.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/clk.h>
+#include "pll.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+struct nv40_clk_priv {
+ struct nvkm_clk base;
+ u32 ctrl;
+ u32 npll_ctrl;
+ u32 npll_coef;
+ u32 spll;
+};
+
+static struct nvkm_domain
+nv40_domain[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_href , 0xff },
+ { nv_clk_src_core , 0xff, 0, "core", 1000 },
+ { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+ { nv_clk_src_mem , 0xff, 0, "memory", 1000 },
+ { nv_clk_src_max }
+};
+
+static u32
+read_pll_1(struct nv40_clk_priv *priv, u32 reg)
+{
+ u32 ctrl = nv_rd32(priv, reg + 0x00);
+ int P = (ctrl & 0x00070000) >> 16;
+ int N = (ctrl & 0x0000ff00) >> 8;
+ int M = (ctrl & 0x000000ff) >> 0;
+ u32 ref = 27000, clk = 0;
+
+ if (ctrl & 0x80000000)
+ clk = ref * N / M;
+
+ return clk >> P;
+}
+
+static u32
+read_pll_2(struct nv40_clk_priv *priv, u32 reg)
+{
+ u32 ctrl = nv_rd32(priv, reg + 0x00);
+ u32 coef = nv_rd32(priv, reg + 0x04);
+ int N2 = (coef & 0xff000000) >> 24;
+ int M2 = (coef & 0x00ff0000) >> 16;
+ int N1 = (coef & 0x0000ff00) >> 8;
+ int M1 = (coef & 0x000000ff) >> 0;
+ int P = (ctrl & 0x00070000) >> 16;
+ u32 ref = 27000, clk = 0;
+
+ if ((ctrl & 0x80000000) && M1) {
+ clk = ref * N1 / M1;
+ if ((ctrl & 0x40000100) == 0x40000000) {
+ if (M2)
+ clk = clk * N2 / M2;
+ else
+ clk = 0;
+ }
+ }
+
+ return clk >> P;
+}
+
+static u32
+read_clk(struct nv40_clk_priv *priv, u32 src)
+{
+ switch (src) {
+ case 3:
+ return read_pll_2(priv, 0x004000);
+ case 2:
+ return read_pll_1(priv, 0x004008);
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+nv40_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct nv40_clk_priv *priv = (void *)clk;
+ u32 mast = nv_rd32(priv, 0x00c040);
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return nv_device(priv)->crystal;
+ case nv_clk_src_href:
+ return 100000; /*XXX: PCIE/AGP differ*/
+ case nv_clk_src_core:
+ return read_clk(priv, (mast & 0x00000003) >> 0);
+ case nv_clk_src_shader:
+ return read_clk(priv, (mast & 0x00000030) >> 4);
+ case nv_clk_src_mem:
+ return read_pll_2(priv, 0x4020);
+ default:
+ break;
+ }
+
+ nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+ return -EINVAL;
+}
+
+static int
+nv40_clk_calc_pll(struct nv40_clk_priv *priv, u32 reg, u32 clk,
+ int *N1, int *M1, int *N2, int *M2, int *log2P)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll pll;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, reg, &pll);
+ if (ret)
+ return ret;
+
+ if (clk < pll.vco1.max_freq)
+ pll.vco2.max_freq = 0;
+
+ ret = nv04_pll_calc(nv_subdev(priv), &pll, clk, N1, M1, N2, M2, log2P);
+ if (ret == 0)
+ return -ERANGE;
+
+ return ret;
+}
+
+static int
+nv40_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct nv40_clk_priv *priv = (void *)clk;
+ int gclk = cstate->domain[nv_clk_src_core];
+ int sclk = cstate->domain[nv_clk_src_shader];
+ int N1, M1, N2, M2, log2P;
+ int ret;
+
+ /* core/geometric clock */
+ ret = nv40_clk_calc_pll(priv, 0x004000, gclk,
+ &N1, &M1, &N2, &M2, &log2P);
+ if (ret < 0)
+ return ret;
+
+ if (N2 == M2) {
+ priv->npll_ctrl = 0x80000100 | (log2P << 16);
+ priv->npll_coef = (N1 << 8) | M1;
+ } else {
+ priv->npll_ctrl = 0xc0000000 | (log2P << 16);
+ priv->npll_coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
+ }
+
+ /* use the second pll for shader/rop clock, if it differs from core */
+ if (sclk && sclk != gclk) {
+ ret = nv40_clk_calc_pll(priv, 0x004008, sclk,
+ &N1, &M1, NULL, NULL, &log2P);
+ if (ret < 0)
+ return ret;
+
+ priv->spll = 0xc0000000 | (log2P << 16) | (N1 << 8) | M1;
+ priv->ctrl = 0x00000223;
+ } else {
+ priv->spll = 0x00000000;
+ priv->ctrl = 0x00000333;
+ }
+
+ return 0;
+}
+
+static int
+nv40_clk_prog(struct nvkm_clk *clk)
+{
+ struct nv40_clk_priv *priv = (void *)clk;
+ nv_mask(priv, 0x00c040, 0x00000333, 0x00000000);
+ nv_wr32(priv, 0x004004, priv->npll_coef);
+ nv_mask(priv, 0x004000, 0xc0070100, priv->npll_ctrl);
+ nv_mask(priv, 0x004008, 0xc007ffff, priv->spll);
+ mdelay(5);
+ nv_mask(priv, 0x00c040, 0x00000333, priv->ctrl);
+ return 0;
+}
+
+static void
+nv40_clk_tidy(struct nvkm_clk *clk)
+{
+}
+
+static int
+nv40_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv40_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, nv40_domain,
+ NULL, 0, true, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.pll_calc = nv04_clk_pll_calc;
+ priv->base.pll_prog = nv04_clk_pll_prog;
+ priv->base.read = nv40_clk_read;
+ priv->base.calc = nv40_clk_calc;
+ priv->base.prog = nv40_clk_prog;
+ priv->base.tidy = nv40_clk_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+nv40_clk_oclass = {
+ .handle = NV_SUBDEV(CLK, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
new file mode 100644
index 000000000000..9b4ffd6347ce
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.c
@@ -0,0 +1,561 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "pll.h"
+#include "seq.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+static u32
+read_div(struct nv50_clk_priv *priv)
+{
+ switch (nv_device(priv)->chipset) {
+ case 0x50: /* it exists, but only has bit 31, not the dividers.. */
+ case 0x84:
+ case 0x86:
+ case 0x98:
+ case 0xa0:
+ return nv_rd32(priv, 0x004700);
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ return nv_rd32(priv, 0x004800);
+ default:
+ return 0x00000000;
+ }
+}
+
+static u32
+read_pll_src(struct nv50_clk_priv *priv, u32 base)
+{
+ struct nvkm_clk *clk = &priv->base;
+ u32 coef, ref = clk->read(clk, nv_clk_src_crystal);
+ u32 rsel = nv_rd32(priv, 0x00e18c);
+ int P, N, M, id;
+
+ switch (nv_device(priv)->chipset) {
+ case 0x50:
+ case 0xa0:
+ switch (base) {
+ case 0x4020:
+ case 0x4028: id = !!(rsel & 0x00000004); break;
+ case 0x4008: id = !!(rsel & 0x00000008); break;
+ case 0x4030: id = 0; break;
+ default:
+ nv_error(priv, "ref: bad pll 0x%06x\n", base);
+ return 0;
+ }
+
+ coef = nv_rd32(priv, 0x00e81c + (id * 0x0c));
+ ref *= (coef & 0x01000000) ? 2 : 4;
+ P = (coef & 0x00070000) >> 16;
+ N = ((coef & 0x0000ff00) >> 8) + 1;
+ M = ((coef & 0x000000ff) >> 0) + 1;
+ break;
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ coef = nv_rd32(priv, 0x00e81c);
+ P = (coef & 0x00070000) >> 16;
+ N = (coef & 0x0000ff00) >> 8;
+ M = (coef & 0x000000ff) >> 0;
+ break;
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ rsel = nv_rd32(priv, 0x00c050);
+ switch (base) {
+ case 0x4020: rsel = (rsel & 0x00000003) >> 0; break;
+ case 0x4008: rsel = (rsel & 0x0000000c) >> 2; break;
+ case 0x4028: rsel = (rsel & 0x00001800) >> 11; break;
+ case 0x4030: rsel = 3; break;
+ default:
+ nv_error(priv, "ref: bad pll 0x%06x\n", base);
+ return 0;
+ }
+
+ switch (rsel) {
+ case 0: id = 1; break;
+ case 1: return clk->read(clk, nv_clk_src_crystal);
+ case 2: return clk->read(clk, nv_clk_src_href);
+ case 3: id = 0; break;
+ }
+
+ coef = nv_rd32(priv, 0x00e81c + (id * 0x28));
+ P = (nv_rd32(priv, 0x00e824 + (id * 0x28)) >> 16) & 7;
+ P += (coef & 0x00070000) >> 16;
+ N = (coef & 0x0000ff00) >> 8;
+ M = (coef & 0x000000ff) >> 0;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ if (M)
+ return (ref * N / M) >> P;
+
+ return 0;
+}
+
+static u32
+read_pll_ref(struct nv50_clk_priv *priv, u32 base)
+{
+ struct nvkm_clk *clk = &priv->base;
+ u32 src, mast = nv_rd32(priv, 0x00c040);
+
+ switch (base) {
+ case 0x004028:
+ src = !!(mast & 0x00200000);
+ break;
+ case 0x004020:
+ src = !!(mast & 0x00400000);
+ break;
+ case 0x004008:
+ src = !!(mast & 0x00010000);
+ break;
+ case 0x004030:
+ src = !!(mast & 0x02000000);
+ break;
+ case 0x00e810:
+ return clk->read(clk, nv_clk_src_crystal);
+ default:
+ nv_error(priv, "bad pll 0x%06x\n", base);
+ return 0;
+ }
+
+ if (src)
+ return clk->read(clk, nv_clk_src_href);
+
+ return read_pll_src(priv, base);
+}
+
+static u32
+read_pll(struct nv50_clk_priv *priv, u32 base)
+{
+ struct nvkm_clk *clk = &priv->base;
+ u32 mast = nv_rd32(priv, 0x00c040);
+ u32 ctrl = nv_rd32(priv, base + 0);
+ u32 coef = nv_rd32(priv, base + 4);
+ u32 ref = read_pll_ref(priv, base);
+ u32 freq = 0;
+ int N1, N2, M1, M2;
+
+ if (base == 0x004028 && (mast & 0x00100000)) {
+ /* wtf, appears to only disable post-divider on gt200 */
+ if (nv_device(priv)->chipset != 0xa0)
+ return clk->read(clk, nv_clk_src_dom6);
+ }
+
+ N2 = (coef & 0xff000000) >> 24;
+ M2 = (coef & 0x00ff0000) >> 16;
+ N1 = (coef & 0x0000ff00) >> 8;
+ M1 = (coef & 0x000000ff);
+ if ((ctrl & 0x80000000) && M1) {
+ freq = ref * N1 / M1;
+ if ((ctrl & 0x40000100) == 0x40000000) {
+ if (M2)
+ freq = freq * N2 / M2;
+ else
+ freq = 0;
+ }
+ }
+
+ return freq;
+}
+
+static int
+nv50_clk_read(struct nvkm_clk *clk, enum nv_clk_src src)
+{
+ struct nv50_clk_priv *priv = (void *)clk;
+ u32 mast = nv_rd32(priv, 0x00c040);
+ u32 P = 0;
+
+ switch (src) {
+ case nv_clk_src_crystal:
+ return nv_device(priv)->crystal;
+ case nv_clk_src_href:
+ return 100000; /* PCIE reference clock */
+ case nv_clk_src_hclk:
+ return div_u64((u64)clk->read(clk, nv_clk_src_href) * 27778, 10000);
+ case nv_clk_src_hclkm3:
+ return clk->read(clk, nv_clk_src_hclk) * 3;
+ case nv_clk_src_hclkm3d2:
+ return clk->read(clk, nv_clk_src_hclk) * 3 / 2;
+ case nv_clk_src_host:
+ switch (mast & 0x30000000) {
+ case 0x00000000: return clk->read(clk, nv_clk_src_href);
+ case 0x10000000: break;
+ case 0x20000000: /* !0x50 */
+ case 0x30000000: return clk->read(clk, nv_clk_src_hclk);
+ }
+ break;
+ case nv_clk_src_core:
+ if (!(mast & 0x00100000))
+ P = (nv_rd32(priv, 0x004028) & 0x00070000) >> 16;
+ switch (mast & 0x00000003) {
+ case 0x00000000: return clk->read(clk, nv_clk_src_crystal) >> P;
+ case 0x00000001: return clk->read(clk, nv_clk_src_dom6);
+ case 0x00000002: return read_pll(priv, 0x004020) >> P;
+ case 0x00000003: return read_pll(priv, 0x004028) >> P;
+ }
+ break;
+ case nv_clk_src_shader:
+ P = (nv_rd32(priv, 0x004020) & 0x00070000) >> 16;
+ switch (mast & 0x00000030) {
+ case 0x00000000:
+ if (mast & 0x00000080)
+ return clk->read(clk, nv_clk_src_host) >> P;
+ return clk->read(clk, nv_clk_src_crystal) >> P;
+ case 0x00000010: break;
+ case 0x00000020: return read_pll(priv, 0x004028) >> P;
+ case 0x00000030: return read_pll(priv, 0x004020) >> P;
+ }
+ break;
+ case nv_clk_src_mem:
+ P = (nv_rd32(priv, 0x004008) & 0x00070000) >> 16;
+ if (nv_rd32(priv, 0x004008) & 0x00000200) {
+ switch (mast & 0x0000c000) {
+ case 0x00000000:
+ return clk->read(clk, nv_clk_src_crystal) >> P;
+ case 0x00008000:
+ case 0x0000c000:
+ return clk->read(clk, nv_clk_src_href) >> P;
+ }
+ } else {
+ return read_pll(priv, 0x004008) >> P;
+ }
+ break;
+ case nv_clk_src_vdec:
+ P = (read_div(priv) & 0x00000700) >> 8;
+ switch (nv_device(priv)->chipset) {
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0xa0:
+ switch (mast & 0x00000c00) {
+ case 0x00000000:
+ if (nv_device(priv)->chipset == 0xa0) /* wtf?? */
+ return clk->read(clk, nv_clk_src_core) >> P;
+ return clk->read(clk, nv_clk_src_crystal) >> P;
+ case 0x00000400:
+ return 0;
+ case 0x00000800:
+ if (mast & 0x01000000)
+ return read_pll(priv, 0x004028) >> P;
+ return read_pll(priv, 0x004030) >> P;
+ case 0x00000c00:
+ return clk->read(clk, nv_clk_src_core) >> P;
+ }
+ break;
+ case 0x98:
+ switch (mast & 0x00000c00) {
+ case 0x00000000:
+ return clk->read(clk, nv_clk_src_core) >> P;
+ case 0x00000400:
+ return 0;
+ case 0x00000800:
+ return clk->read(clk, nv_clk_src_hclkm3d2) >> P;
+ case 0x00000c00:
+ return clk->read(clk, nv_clk_src_mem) >> P;
+ }
+ break;
+ }
+ break;
+ case nv_clk_src_dom6:
+ switch (nv_device(priv)->chipset) {
+ case 0x50:
+ case 0xa0:
+ return read_pll(priv, 0x00e810) >> 2;
+ case 0x84:
+ case 0x86:
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ case 0x98:
+ P = (read_div(priv) & 0x00000007) >> 0;
+ switch (mast & 0x0c000000) {
+ case 0x00000000: return clk->read(clk, nv_clk_src_href);
+ case 0x04000000: break;
+ case 0x08000000: return clk->read(clk, nv_clk_src_hclk);
+ case 0x0c000000:
+ return clk->read(clk, nv_clk_src_hclkm3) >> P;
+ }
+ break;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ nv_debug(priv, "unknown clock source %d 0x%08x\n", src, mast);
+ return -EINVAL;
+}
+
+static u32
+calc_pll(struct nv50_clk_priv *priv, u32 reg, u32 clk, int *N, int *M, int *P)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll pll;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, reg, &pll);
+ if (ret)
+ return 0;
+
+ pll.vco2.max_freq = 0;
+ pll.refclk = read_pll_ref(priv, reg);
+ if (!pll.refclk)
+ return 0;
+
+ return nv04_pll_calc(nv_subdev(priv), &pll, clk, N, M, NULL, NULL, P);
+}
+
+static inline u32
+calc_div(u32 src, u32 target, int *div)
+{
+ u32 clk0 = src, clk1 = src;
+ for (*div = 0; *div <= 7; (*div)++) {
+ if (clk0 <= target) {
+ clk1 = clk0 << (*div ? 1 : 0);
+ break;
+ }
+ clk0 >>= 1;
+ }
+
+ if (target - clk0 <= clk1 - target)
+ return clk0;
+ (*div)--;
+ return clk1;
+}
+
+static inline u32
+clk_same(u32 a, u32 b)
+{
+ return ((a / 1000) == (b / 1000));
+}
+
+static int
+nv50_clk_calc(struct nvkm_clk *clk, struct nvkm_cstate *cstate)
+{
+ struct nv50_clk_priv *priv = (void *)clk;
+ struct nv50_clk_hwsq *hwsq = &priv->hwsq;
+ const int shader = cstate->domain[nv_clk_src_shader];
+ const int core = cstate->domain[nv_clk_src_core];
+ const int vdec = cstate->domain[nv_clk_src_vdec];
+ const int dom6 = cstate->domain[nv_clk_src_dom6];
+ u32 mastm = 0, mastv = 0;
+ u32 divsm = 0, divsv = 0;
+ int N, M, P1, P2;
+ int freq, out;
+
+ /* prepare a hwsq script from which we'll perform the reclock */
+ out = clk_init(hwsq, nv_subdev(clk));
+ if (out)
+ return out;
+
+ clk_wr32(hwsq, fifo, 0x00000001); /* block fifo */
+ clk_nsec(hwsq, 8000);
+ clk_setf(hwsq, 0x10, 0x00); /* disable fb */
+ clk_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
+
+ /* vdec: avoid modifying xpll until we know exactly how the other
+ * clock domains work, i suspect at least some of them can also be
+ * tied to xpll...
+ */
+ if (vdec) {
+ /* see how close we can get using nvclk as a source */
+ freq = calc_div(core, vdec, &P1);
+
+ /* see how close we can get using xpll/hclk as a source */
+ if (nv_device(priv)->chipset != 0x98)
+ out = read_pll(priv, 0x004030);
+ else
+ out = clk->read(clk, nv_clk_src_hclkm3d2);
+ out = calc_div(out, vdec, &P2);
+
+ /* select whichever gets us closest */
+ if (abs(vdec - freq) <= abs(vdec - out)) {
+ if (nv_device(priv)->chipset != 0x98)
+ mastv |= 0x00000c00;
+ divsv |= P1 << 8;
+ } else {
+ mastv |= 0x00000800;
+ divsv |= P2 << 8;
+ }
+
+ mastm |= 0x00000c00;
+ divsm |= 0x00000700;
+ }
+
+ /* dom6: nfi what this is, but we're limited to various combinations
+ * of the host clock frequency
+ */
+ if (dom6) {
+ if (clk_same(dom6, clk->read(clk, nv_clk_src_href))) {
+ mastv |= 0x00000000;
+ } else
+ if (clk_same(dom6, clk->read(clk, nv_clk_src_hclk))) {
+ mastv |= 0x08000000;
+ } else {
+ freq = clk->read(clk, nv_clk_src_hclk) * 3;
+ freq = calc_div(freq, dom6, &P1);
+
+ mastv |= 0x0c000000;
+ divsv |= P1;
+ }
+
+ mastm |= 0x0c000000;
+ divsm |= 0x00000007;
+ }
+
+ /* vdec/dom6: switch to "safe" clocks temporarily, update dividers
+ * and then switch to target clocks
+ */
+ clk_mask(hwsq, mast, mastm, 0x00000000);
+ clk_mask(hwsq, divs, divsm, divsv);
+ clk_mask(hwsq, mast, mastm, mastv);
+
+ /* core/shader: disconnect nvclk/sclk from their PLLs (nvclk to dom6,
+ * sclk to hclk) before reprogramming
+ */
+ if (nv_device(priv)->chipset < 0x92)
+ clk_mask(hwsq, mast, 0x001000b0, 0x00100080);
+ else
+ clk_mask(hwsq, mast, 0x000000b3, 0x00000081);
+
+ /* core: for the moment at least, always use nvpll */
+ freq = calc_pll(priv, 0x4028, core, &N, &M, &P1);
+ if (freq == 0)
+ return -ERANGE;
+
+ clk_mask(hwsq, nvpll[0], 0xc03f0100,
+ 0x80000000 | (P1 << 19) | (P1 << 16));
+ clk_mask(hwsq, nvpll[1], 0x0000ffff, (N << 8) | M);
+
+ /* shader: tie to nvclk if possible, otherwise use spll. have to be
+ * very careful that the shader clock is at least twice the core, or
+ * some chipsets will be very unhappy. i expect most or all of these
+ * cases will be handled by tying to nvclk, but it's possible there's
+ * corners
+ */
+ if (P1-- && shader == (core << 1)) {
+ clk_mask(hwsq, spll[0], 0xc03f0100, (P1 << 19) | (P1 << 16));
+ clk_mask(hwsq, mast, 0x00100033, 0x00000023);
+ } else {
+ freq = calc_pll(priv, 0x4020, shader, &N, &M, &P1);
+ if (freq == 0)
+ return -ERANGE;
+
+ clk_mask(hwsq, spll[0], 0xc03f0100,
+ 0x80000000 | (P1 << 19) | (P1 << 16));
+ clk_mask(hwsq, spll[1], 0x0000ffff, (N << 8) | M);
+ clk_mask(hwsq, mast, 0x00100033, 0x00000033);
+ }
+
+ /* restore normal operation */
+ clk_setf(hwsq, 0x10, 0x01); /* enable fb */
+ clk_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
+ clk_wr32(hwsq, fifo, 0x00000000); /* un-block fifo */
+ return 0;
+}
+
+static int
+nv50_clk_prog(struct nvkm_clk *clk)
+{
+ struct nv50_clk_priv *priv = (void *)clk;
+ return clk_exec(&priv->hwsq, true);
+}
+
+static void
+nv50_clk_tidy(struct nvkm_clk *clk)
+{
+ struct nv50_clk_priv *priv = (void *)clk;
+ clk_exec(&priv->hwsq, false);
+}
+
+int
+nv50_clk_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_clk_oclass *pclass = (void *)oclass;
+ struct nv50_clk_priv *priv;
+ int ret;
+
+ ret = nvkm_clk_create(parent, engine, oclass, pclass->domains,
+ NULL, 0, false, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->hwsq.r_fifo = hwsq_reg(0x002504);
+ priv->hwsq.r_spll[0] = hwsq_reg(0x004020);
+ priv->hwsq.r_spll[1] = hwsq_reg(0x004024);
+ priv->hwsq.r_nvpll[0] = hwsq_reg(0x004028);
+ priv->hwsq.r_nvpll[1] = hwsq_reg(0x00402c);
+ switch (nv_device(priv)->chipset) {
+ case 0x92:
+ case 0x94:
+ case 0x96:
+ priv->hwsq.r_divs = hwsq_reg(0x004800);
+ break;
+ default:
+ priv->hwsq.r_divs = hwsq_reg(0x004700);
+ break;
+ }
+ priv->hwsq.r_mast = hwsq_reg(0x00c040);
+
+ priv->base.read = nv50_clk_read;
+ priv->base.calc = nv50_clk_calc;
+ priv->base.prog = nv50_clk_prog;
+ priv->base.tidy = nv50_clk_tidy;
+ return 0;
+}
+
+static struct nvkm_domain
+nv50_domains[] = {
+ { nv_clk_src_crystal, 0xff },
+ { nv_clk_src_href , 0xff },
+ { nv_clk_src_core , 0xff, 0, "core", 1000 },
+ { nv_clk_src_shader , 0xff, 0, "shader", 1000 },
+ { nv_clk_src_mem , 0xff, 0, "memory", 1000 },
+ { nv_clk_src_max }
+};
+
+struct nvkm_oclass *
+nv50_clk_oclass = &(struct nv50_clk_oclass) {
+ .base.handle = NV_SUBDEV(CLK, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_clk_ctor,
+ .dtor = _nvkm_clk_dtor,
+ .init = _nvkm_clk_init,
+ .fini = _nvkm_clk_fini,
+ },
+ .domains = nv50_domains,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h
new file mode 100644
index 000000000000..0ead76a32f10
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/nv50.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_CLK_NV50_H__
+#define __NVKM_CLK_NV50_H__
+#include <subdev/bus/hwsq.h>
+#include <subdev/clk.h>
+
+struct nv50_clk_hwsq {
+ struct hwsq base;
+ struct hwsq_reg r_fifo;
+ struct hwsq_reg r_spll[2];
+ struct hwsq_reg r_nvpll[2];
+ struct hwsq_reg r_divs;
+ struct hwsq_reg r_mast;
+};
+
+struct nv50_clk_priv {
+ struct nvkm_clk base;
+ struct nv50_clk_hwsq hwsq;
+};
+
+int nv50_clk_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+struct nv50_clk_oclass {
+ struct nvkm_oclass base;
+ struct nvkm_domain *domains;
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h
new file mode 100644
index 000000000000..44020a30dee8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pll.h
@@ -0,0 +1,11 @@
+#ifndef __NVKM_PLL_H__
+#define __NVKM_PLL_H__
+#include <core/os.h>
+struct nvkm_subdev;
+struct nvbios_pll;
+
+int nv04_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq,
+ int *N1, int *M1, int *N2, int *M2, int *P);
+int gt215_pll_calc(struct nvkm_subdev *, struct nvbios_pll *, u32 freq,
+ int *N, int *fN, int *M, int *P);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c
new file mode 100644
index 000000000000..783a3e78d632
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllgt215.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pll.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+int
+gt215_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info,
+ u32 freq, int *pN, int *pfN, int *pM, int *P)
+{
+ u32 best_err = ~0, err;
+ int M, lM, hM, N, fN;
+
+ *P = info->vco1.max_freq / freq;
+ if (*P > info->max_p)
+ *P = info->max_p;
+ if (*P < info->min_p)
+ *P = info->min_p;
+
+ lM = (info->refclk + info->vco1.max_inputfreq) / info->vco1.max_inputfreq;
+ lM = max(lM, (int)info->vco1.min_m);
+ hM = (info->refclk + info->vco1.min_inputfreq) / info->vco1.min_inputfreq;
+ hM = min(hM, (int)info->vco1.max_m);
+ lM = min(lM, hM);
+
+ for (M = lM; M <= hM; M++) {
+ u32 tmp = freq * *P * M;
+ N = tmp / info->refclk;
+ fN = tmp % info->refclk;
+
+ if (!pfN) {
+ if (fN >= info->refclk / 2)
+ N++;
+ } else {
+ if (fN < info->refclk / 2)
+ N--;
+ fN = tmp - (N * info->refclk);
+ }
+
+ if (N < info->vco1.min_n)
+ continue;
+ if (N > info->vco1.max_n)
+ break;
+
+ err = abs(freq - (info->refclk * N / M / *P));
+ if (err < best_err) {
+ best_err = err;
+ *pN = N;
+ *pM = M;
+ }
+
+ if (pfN) {
+ *pfN = ((fN << 13) + info->refclk / 2) / info->refclk;
+ *pfN = (*pfN - 4096) & 0xffff;
+ return freq;
+ }
+ }
+
+ if (unlikely(best_err == ~0)) {
+ nv_error(subdev, "unable to find matching pll values\n");
+ return -EINVAL;
+ }
+
+ return info->refclk * *pN / *pM / *P;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c
new file mode 100644
index 000000000000..f2292895a1a8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/pllnv04.c
@@ -0,0 +1,245 @@
+/*
+ * Copyright 1993-2003 NVIDIA, Corporation
+ * Copyright 2007-2009 Stuart Bennett
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION 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 "pll.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+
+static int
+getMNP_single(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
+ int *pN, int *pM, int *pP)
+{
+ /* Find M, N and P for a single stage PLL
+ *
+ * Note that some bioses (NV3x) have lookup tables of precomputed MNP
+ * values, but we're too lazy to use those atm
+ *
+ * "clk" parameter in kHz
+ * returns calculated clock
+ */
+ struct nvkm_bios *bios = nvkm_bios(subdev);
+ int minvco = info->vco1.min_freq, maxvco = info->vco1.max_freq;
+ int minM = info->vco1.min_m, maxM = info->vco1.max_m;
+ int minN = info->vco1.min_n, maxN = info->vco1.max_n;
+ int minU = info->vco1.min_inputfreq;
+ int maxU = info->vco1.max_inputfreq;
+ int minP = info->min_p;
+ int maxP = info->max_p_usable;
+ int crystal = info->refclk;
+ int M, N, thisP, P;
+ int clkP, calcclk;
+ int delta, bestdelta = INT_MAX;
+ int bestclk = 0;
+
+ /* this division verified for nv20, nv18, nv28 (Haiku), and nv34 */
+ /* possibly correlated with introduction of 27MHz crystal */
+ if (bios->version.major < 0x60) {
+ int cv = bios->version.chip;
+ if (cv < 0x17 || cv == 0x1a || cv == 0x20) {
+ if (clk > 250000)
+ maxM = 6;
+ if (clk > 340000)
+ maxM = 2;
+ } else if (cv < 0x40) {
+ if (clk > 150000)
+ maxM = 6;
+ if (clk > 200000)
+ maxM = 4;
+ if (clk > 340000)
+ maxM = 2;
+ }
+ }
+
+ P = 1 << maxP;
+ if ((clk * P) < minvco) {
+ minvco = clk * maxP;
+ maxvco = minvco * 2;
+ }
+
+ if (clk + clk/200 > maxvco) /* +0.5% */
+ maxvco = clk + clk/200;
+
+ /* NV34 goes maxlog2P->0, NV20 goes 0->maxlog2P */
+ for (thisP = minP; thisP <= maxP; thisP++) {
+ P = 1 << thisP;
+ clkP = clk * P;
+
+ if (clkP < minvco)
+ continue;
+ if (clkP > maxvco)
+ return bestclk;
+
+ for (M = minM; M <= maxM; M++) {
+ if (crystal/M < minU)
+ return bestclk;
+ if (crystal/M > maxU)
+ continue;
+
+ /* add crystal/2 to round better */
+ N = (clkP * M + crystal/2) / crystal;
+
+ if (N < minN)
+ continue;
+ if (N > maxN)
+ break;
+
+ /* more rounding additions */
+ calcclk = ((N * crystal + P/2) / P + M/2) / M;
+ delta = abs(calcclk - clk);
+ /* we do an exhaustive search rather than terminating
+ * on an optimality condition...
+ */
+ if (delta < bestdelta) {
+ bestdelta = delta;
+ bestclk = calcclk;
+ *pN = N;
+ *pM = M;
+ *pP = thisP;
+ if (delta == 0) /* except this one */
+ return bestclk;
+ }
+ }
+ }
+
+ return bestclk;
+}
+
+static int
+getMNP_double(struct nvkm_subdev *subdev, struct nvbios_pll *info, int clk,
+ int *pN1, int *pM1, int *pN2, int *pM2, int *pP)
+{
+ /* Find M, N and P for a two stage PLL
+ *
+ * Note that some bioses (NV30+) have lookup tables of precomputed MNP
+ * values, but we're too lazy to use those atm
+ *
+ * "clk" parameter in kHz
+ * returns calculated clock
+ */
+ int chip_version = nvkm_bios(subdev)->version.chip;
+ int minvco1 = info->vco1.min_freq, maxvco1 = info->vco1.max_freq;
+ int minvco2 = info->vco2.min_freq, maxvco2 = info->vco2.max_freq;
+ int minU1 = info->vco1.min_inputfreq, minU2 = info->vco2.min_inputfreq;
+ int maxU1 = info->vco1.max_inputfreq, maxU2 = info->vco2.max_inputfreq;
+ int minM1 = info->vco1.min_m, maxM1 = info->vco1.max_m;
+ int minN1 = info->vco1.min_n, maxN1 = info->vco1.max_n;
+ int minM2 = info->vco2.min_m, maxM2 = info->vco2.max_m;
+ int minN2 = info->vco2.min_n, maxN2 = info->vco2.max_n;
+ int maxlog2P = info->max_p_usable;
+ int crystal = info->refclk;
+ bool fixedgain2 = (minM2 == maxM2 && minN2 == maxN2);
+ int M1, N1, M2, N2, log2P;
+ int clkP, calcclk1, calcclk2, calcclkout;
+ int delta, bestdelta = INT_MAX;
+ int bestclk = 0;
+
+ int vco2 = (maxvco2 - maxvco2/200) / 2;
+ for (log2P = 0; clk && log2P < maxlog2P && clk <= (vco2 >> log2P); log2P++)
+ ;
+ clkP = clk << log2P;
+
+ if (maxvco2 < clk + clk/200) /* +0.5% */
+ maxvco2 = clk + clk/200;
+
+ for (M1 = minM1; M1 <= maxM1; M1++) {
+ if (crystal/M1 < minU1)
+ return bestclk;
+ if (crystal/M1 > maxU1)
+ continue;
+
+ for (N1 = minN1; N1 <= maxN1; N1++) {
+ calcclk1 = crystal * N1 / M1;
+ if (calcclk1 < minvco1)
+ continue;
+ if (calcclk1 > maxvco1)
+ break;
+
+ for (M2 = minM2; M2 <= maxM2; M2++) {
+ if (calcclk1/M2 < minU2)
+ break;
+ if (calcclk1/M2 > maxU2)
+ continue;
+
+ /* add calcclk1/2 to round better */
+ N2 = (clkP * M2 + calcclk1/2) / calcclk1;
+ if (N2 < minN2)
+ continue;
+ if (N2 > maxN2)
+ break;
+
+ if (!fixedgain2) {
+ if (chip_version < 0x60)
+ if (N2/M2 < 4 || N2/M2 > 10)
+ continue;
+
+ calcclk2 = calcclk1 * N2 / M2;
+ if (calcclk2 < minvco2)
+ break;
+ if (calcclk2 > maxvco2)
+ continue;
+ } else
+ calcclk2 = calcclk1;
+
+ calcclkout = calcclk2 >> log2P;
+ delta = abs(calcclkout - clk);
+ /* we do an exhaustive search rather than terminating
+ * on an optimality condition...
+ */
+ if (delta < bestdelta) {
+ bestdelta = delta;
+ bestclk = calcclkout;
+ *pN1 = N1;
+ *pM1 = M1;
+ *pN2 = N2;
+ *pM2 = M2;
+ *pP = log2P;
+ if (delta == 0) /* except this one */
+ return bestclk;
+ }
+ }
+ }
+ }
+
+ return bestclk;
+}
+
+int
+nv04_pll_calc(struct nvkm_subdev *subdev, struct nvbios_pll *info, u32 freq,
+ int *N1, int *M1, int *N2, int *M2, int *P)
+{
+ int ret;
+
+ if (!info->vco2.max_freq || !N2) {
+ ret = getMNP_single(subdev, info, freq, N1, M1, P);
+ if (N2) {
+ *N2 = 1;
+ *M2 = 1;
+ }
+ } else {
+ ret = getMNP_double(subdev, info, freq, N1, M1, N2, M2, P);
+ }
+
+ if (!ret)
+ nv_error(subdev, "unable to compute acceptable pll values\n");
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h
new file mode 100644
index 000000000000..d717e8b8f679
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/clk/seq.h
@@ -0,0 +1,14 @@
+#ifndef __NVKM_CLK_SEQ_H__
+#define __NVKM_CLK_SEQ_H__
+#include <subdev/bus/hwsq.h>
+
+#define clk_init(s,p) hwsq_init(&(s)->base, (p))
+#define clk_exec(s,e) hwsq_exec(&(s)->base, (e))
+#define clk_have(s,r) ((s)->r_##r.addr != 0x000000)
+#define clk_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r)
+#define clk_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
+#define clk_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define clk_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d))
+#define clk_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d))
+#define clk_nsec(s,n) hwsq_nsec(&(s)->base, (n))
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
new file mode 100644
index 000000000000..793e73d16dac
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/Kbuild
@@ -0,0 +1,14 @@
+nvkm-y += nvkm/subdev/devinit/base.o
+nvkm-y += nvkm/subdev/devinit/nv04.o
+nvkm-y += nvkm/subdev/devinit/nv05.o
+nvkm-y += nvkm/subdev/devinit/nv10.o
+nvkm-y += nvkm/subdev/devinit/nv1a.o
+nvkm-y += nvkm/subdev/devinit/nv20.o
+nvkm-y += nvkm/subdev/devinit/nv50.o
+nvkm-y += nvkm/subdev/devinit/g84.o
+nvkm-y += nvkm/subdev/devinit/g98.o
+nvkm-y += nvkm/subdev/devinit/gt215.o
+nvkm-y += nvkm/subdev/devinit/mcp89.o
+nvkm-y += nvkm/subdev/devinit/gf100.o
+nvkm-y += nvkm/subdev/devinit/gm107.o
+nvkm-y += nvkm/subdev/devinit/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
new file mode 100644
index 000000000000..b0d7c5f40db1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/base.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/vga.h>
+
+int
+_nvkm_devinit_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_devinit *devinit = (void *)object;
+
+ /* force full reinit on resume */
+ if (suspend)
+ devinit->post = true;
+
+ /* unlock the extended vga crtc regs */
+ nv_lockvgac(devinit, false);
+
+ return nvkm_subdev_fini(&devinit->base, suspend);
+}
+
+int
+_nvkm_devinit_init(struct nvkm_object *object)
+{
+ struct nvkm_devinit_impl *impl = (void *)object->oclass;
+ struct nvkm_devinit *devinit = (void *)object;
+ int ret;
+
+ ret = nvkm_subdev_init(&devinit->base);
+ if (ret)
+ return ret;
+
+ ret = impl->post(&devinit->base, devinit->post);
+ if (ret)
+ return ret;
+
+ if (impl->disable)
+ nv_device(devinit)->disable_mask |= impl->disable(devinit);
+ return 0;
+}
+
+void
+_nvkm_devinit_dtor(struct nvkm_object *object)
+{
+ struct nvkm_devinit *devinit = (void *)object;
+
+ /* lock crtc regs */
+ nv_lockvgac(devinit, true);
+
+ nvkm_subdev_destroy(&devinit->base);
+}
+
+int
+nvkm_devinit_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int size, void **pobject)
+{
+ struct nvkm_devinit_impl *impl = (void *)oclass;
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_devinit *devinit;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "DEVINIT",
+ "init", size, pobject);
+ devinit = *pobject;
+ if (ret)
+ return ret;
+
+ devinit->post = nvkm_boolopt(device->cfgopt, "NvForcePost", false);
+ devinit->meminit = impl->meminit;
+ devinit->pll_set = impl->pll_set;
+ devinit->mmio = impl->mmio;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h
new file mode 100644
index 000000000000..36684c3f9e9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/fbmem.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <core/device.h>
+#include <subdev/fb/regsnv04.h>
+
+#define NV04_PFB_DEBUG_0 0x00100080
+# define NV04_PFB_DEBUG_0_PAGE_MODE 0x00000001
+# define NV04_PFB_DEBUG_0_REFRESH_OFF 0x00000010
+# define NV04_PFB_DEBUG_0_REFRESH_COUNTX64 0x00003f00
+# define NV04_PFB_DEBUG_0_REFRESH_SLOW_CLK 0x00004000
+# define NV04_PFB_DEBUG_0_SAFE_MODE 0x00008000
+# define NV04_PFB_DEBUG_0_ALOM_ENABLE 0x00010000
+# define NV04_PFB_DEBUG_0_CASOE 0x00100000
+# define NV04_PFB_DEBUG_0_CKE_INVERT 0x10000000
+# define NV04_PFB_DEBUG_0_REFINC 0x20000000
+# define NV04_PFB_DEBUG_0_SAVE_POWER_OFF 0x40000000
+#define NV04_PFB_CFG0 0x00100200
+# define NV04_PFB_CFG0_SCRAMBLE 0x20000000
+#define NV04_PFB_CFG1 0x00100204
+#define NV04_PFB_SCRAMBLE(i) (0x00100400 + 4 * (i))
+
+#define NV10_PFB_REFCTRL 0x00100210
+# define NV10_PFB_REFCTRL_VALID_1 (1 << 31)
+
+static inline struct io_mapping *
+fbmem_init(struct nvkm_device *dev)
+{
+ return io_mapping_create_wc(nv_device_resource_start(dev, 1),
+ nv_device_resource_len(dev, 1));
+}
+
+static inline void
+fbmem_fini(struct io_mapping *fb)
+{
+ io_mapping_free(fb);
+}
+
+static inline u32
+fbmem_peek(struct io_mapping *fb, u32 off)
+{
+ u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
+ u32 val = ioread32(p + (off & ~PAGE_MASK));
+ io_mapping_unmap_atomic(p);
+ return val;
+}
+
+static inline void
+fbmem_poke(struct io_mapping *fb, u32 off, u32 val)
+{
+ u8 __iomem *p = io_mapping_map_atomic_wc(fb, off & PAGE_MASK);
+ iowrite32(val, p + (off & ~PAGE_MASK));
+ wmb();
+ io_mapping_unmap_atomic(p);
+}
+
+static inline bool
+fbmem_readback(struct io_mapping *fb, u32 off, u32 val)
+{
+ fbmem_poke(fb, off, val);
+ return val == fbmem_peek(fb, off);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
new file mode 100644
index 000000000000..ca776ce75f4f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g84.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static u64
+g84_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r001540 = nv_rd32(priv, 0x001540);
+ u32 r00154c = nv_rd32(priv, 0x00154c);
+ u64 disable = 0ULL;
+
+ if (!(r001540 & 0x40000000)) {
+ disable |= (1ULL << NVDEV_ENGINE_MPEG);
+ disable |= (1ULL << NVDEV_ENGINE_VP);
+ disable |= (1ULL << NVDEV_ENGINE_BSP);
+ disable |= (1ULL << NVDEV_ENGINE_CIPHER);
+ }
+
+ if (!(r00154c & 0x00000004))
+ disable |= (1ULL << NVDEV_ENGINE_DISP);
+ if (!(r00154c & 0x00000020))
+ disable |= (1ULL << NVDEV_ENGINE_BSP);
+ if (!(r00154c & 0x00000040))
+ disable |= (1ULL << NVDEV_ENGINE_CIPHER);
+
+ return disable;
+}
+
+struct nvkm_oclass *
+g84_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x84),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = nv50_devinit_pll_set,
+ .disable = g84_devinit_disable,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
new file mode 100644
index 000000000000..d29bacee65ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/g98.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static u64
+g98_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r001540 = nv_rd32(priv, 0x001540);
+ u32 r00154c = nv_rd32(priv, 0x00154c);
+ u64 disable = 0ULL;
+
+ if (!(r001540 & 0x40000000)) {
+ disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+ disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+ disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+ }
+
+ if (!(r00154c & 0x00000004))
+ disable |= (1ULL << NVDEV_ENGINE_DISP);
+ if (!(r00154c & 0x00000020))
+ disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+ if (!(r00154c & 0x00000040))
+ disable |= (1ULL << NVDEV_ENGINE_SEC);
+
+ return disable;
+}
+
+struct nvkm_oclass *
+g98_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x98),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = nv50_devinit_pll_set,
+ .disable = g98_devinit_disable,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
new file mode 100644
index 000000000000..e8778c67578e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gf100.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+
+int
+gf100_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll info;
+ int N, fN, M, P;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, type, &info);
+ if (ret)
+ return ret;
+
+ ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+ if (ret < 0)
+ return ret;
+
+ switch (info.type) {
+ case PLL_VPLL0:
+ case PLL_VPLL1:
+ case PLL_VPLL2:
+ case PLL_VPLL3:
+ nv_mask(priv, info.reg + 0x0c, 0x00000000, 0x00000100);
+ nv_wr32(priv, info.reg + 0x04, (P << 16) | (N << 8) | M);
+ nv_wr32(priv, info.reg + 0x10, fN << 16);
+ break;
+ default:
+ nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static u64
+gf100_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r022500 = nv_rd32(priv, 0x022500);
+ u64 disable = 0ULL;
+
+ if (r022500 & 0x00000001)
+ disable |= (1ULL << NVDEV_ENGINE_DISP);
+
+ if (r022500 & 0x00000002) {
+ disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+ disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+ }
+
+ if (r022500 & 0x00000004)
+ disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+ if (r022500 & 0x00000008)
+ disable |= (1ULL << NVDEV_ENGINE_MSENC);
+ if (r022500 & 0x00000100)
+ disable |= (1ULL << NVDEV_ENGINE_CE0);
+ if (r022500 & 0x00000200)
+ disable |= (1ULL << NVDEV_ENGINE_CE1);
+
+ return disable;
+}
+
+static int
+gf100_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_devinit_priv *priv;
+ int ret;
+
+ ret = nvkm_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ if (nv_rd32(priv, 0x022500) & 0x00000001)
+ priv->base.post = true;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+gf100_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = gf100_devinit_pll_set,
+ .disable = gf100_devinit_disable,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
new file mode 100644
index 000000000000..b345a53e881d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm107.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+u64
+gm107_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r021c00 = nv_rd32(priv, 0x021c00);
+ u32 r021c04 = nv_rd32(priv, 0x021c04);
+ u64 disable = 0ULL;
+
+ if (r021c00 & 0x00000001)
+ disable |= (1ULL << NVDEV_ENGINE_CE0);
+ if (r021c00 & 0x00000004)
+ disable |= (1ULL << NVDEV_ENGINE_CE2);
+ if (r021c04 & 0x00000001)
+ disable |= (1ULL << NVDEV_ENGINE_DISP);
+
+ return disable;
+}
+
+struct nvkm_oclass *
+gm107_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x07),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = gf100_devinit_pll_set,
+ .disable = gm107_devinit_disable,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
new file mode 100644
index 000000000000..535172c5f1ad
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gm204.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/pmu.h>
+
+static void
+pmu_code(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len, bool sec)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ int i;
+
+ nv_wr32(priv, 0x10a180, 0x01000000 | (sec ? 0x10000000 : 0) | pmu);
+ for (i = 0; i < len; i += 4) {
+ if ((i & 0xff) == 0)
+ nv_wr32(priv, 0x10a188, (pmu + i) >> 8);
+ nv_wr32(priv, 0x10a184, nv_ro32(bios, img + i));
+ }
+
+ while (i & 0xff) {
+ nv_wr32(priv, 0x10a184, 0x00000000);
+ i += 4;
+ }
+}
+
+static void
+pmu_data(struct nv50_devinit_priv *priv, u32 pmu, u32 img, u32 len)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ int i;
+
+ nv_wr32(priv, 0x10a1c0, 0x01000000 | pmu);
+ for (i = 0; i < len; i += 4)
+ nv_wr32(priv, 0x10a1c4, nv_ro32(bios, img + i));
+}
+
+static u32
+pmu_args(struct nv50_devinit_priv *priv, u32 argp, u32 argi)
+{
+ nv_wr32(priv, 0x10a1c0, argp);
+ nv_wr32(priv, 0x10a1c0, nv_rd32(priv, 0x10a1c4) + argi);
+ return nv_rd32(priv, 0x10a1c4);
+}
+
+static void
+pmu_exec(struct nv50_devinit_priv *priv, u32 init_addr)
+{
+ nv_wr32(priv, 0x10a104, init_addr);
+ nv_wr32(priv, 0x10a10c, 0x00000000);
+ nv_wr32(priv, 0x10a100, 0x00000002);
+}
+
+static int
+pmu_load(struct nv50_devinit_priv *priv, u8 type, bool post,
+ u32 *init_addr_pmu, u32 *args_addr_pmu)
+{
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pmuR pmu;
+
+ if (!nvbios_pmuRm(bios, type, &pmu)) {
+ nv_error(priv, "VBIOS PMU fuc %02x not found\n", type);
+ return -EINVAL;
+ }
+
+ if (!post)
+ return 0;
+
+ pmu_code(priv, pmu.boot_addr_pmu, pmu.boot_addr, pmu.boot_size, false);
+ pmu_code(priv, pmu.code_addr_pmu, pmu.code_addr, pmu.code_size, true);
+ pmu_data(priv, pmu.data_addr_pmu, pmu.data_addr, pmu.data_size);
+
+ if (init_addr_pmu) {
+ *init_addr_pmu = pmu.init_addr_pmu;
+ *args_addr_pmu = pmu.args_addr_pmu;
+ return 0;
+ }
+
+ return pmu_exec(priv, pmu.init_addr_pmu), 0;
+}
+
+static int
+gm204_devinit_post(struct nvkm_subdev *subdev, bool post)
+{
+ struct nv50_devinit_priv *priv = (void *)nvkm_devinit(subdev);
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct bit_entry bit_I;
+ u32 init, args;
+ int ret;
+
+ if (bit_entry(bios, 'I', &bit_I) || bit_I.version != 1 ||
+ bit_I.length < 0x1c) {
+ nv_error(priv, "VBIOS PMU init data not found\n");
+ return -EINVAL;
+ }
+
+ /* reset PMU and load init table parser ucode */
+ if (post) {
+ nv_mask(priv, 0x000200, 0x00002000, 0x00000000);
+ nv_mask(priv, 0x000200, 0x00002000, 0x00002000);
+ nv_rd32(priv, 0x000200);
+ while (nv_rd32(priv, 0x10a10c) & 0x00000006) {
+ }
+ }
+
+ ret = pmu_load(priv, 0x04, post, &init, &args);
+ if (ret)
+ return ret;
+
+ /* upload first chunk of init data */
+ if (post) {
+ u32 pmu = pmu_args(priv, args + 0x08, 0x08);
+ u32 img = nv_ro16(bios, bit_I.offset + 0x14);
+ u32 len = nv_ro16(bios, bit_I.offset + 0x16);
+ pmu_data(priv, pmu, img, len);
+ }
+
+ /* upload second chunk of init data */
+ if (post) {
+ u32 pmu = pmu_args(priv, args + 0x08, 0x10);
+ u32 img = nv_ro16(bios, bit_I.offset + 0x18);
+ u32 len = nv_ro16(bios, bit_I.offset + 0x1a);
+ pmu_data(priv, pmu, img, len);
+ }
+
+ /* execute init tables */
+ if (post) {
+ nv_wr32(priv, 0x10a040, 0x00005000);
+ pmu_exec(priv, init);
+ while (!(nv_rd32(priv, 0x10a040) & 0x00002000)) {
+ }
+ }
+
+ /* load and execute some other ucode image (bios therm?) */
+ return pmu_load(priv, 0x01, post, NULL, NULL);
+}
+
+struct nvkm_oclass *
+gm204_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x07),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = gf100_devinit_pll_set,
+ .disable = gm107_devinit_disable,
+ .post = gm204_devinit_post,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
new file mode 100644
index 000000000000..6a3e8d4efed7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/gt215.c
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+
+int
+gt215_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll info;
+ int N, fN, M, P;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, type, &info);
+ if (ret)
+ return ret;
+
+ ret = gt215_pll_calc(nv_subdev(devinit), &info, freq, &N, &fN, &M, &P);
+ if (ret < 0)
+ return ret;
+
+ switch (info.type) {
+ case PLL_VPLL0:
+ case PLL_VPLL1:
+ nv_wr32(priv, info.reg + 0, 0x50000610);
+ nv_mask(priv, info.reg + 4, 0x003fffff,
+ (P << 16) | (M << 8) | N);
+ nv_wr32(priv, info.reg + 8, fN);
+ break;
+ default:
+ nv_warn(priv, "0x%08x/%dKhz unimplemented\n", type, freq);
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static u64
+gt215_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r001540 = nv_rd32(priv, 0x001540);
+ u32 r00154c = nv_rd32(priv, 0x00154c);
+ u64 disable = 0ULL;
+
+ if (!(r001540 & 0x40000000)) {
+ disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+ disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+ }
+
+ if (!(r00154c & 0x00000004))
+ disable |= (1ULL << NVDEV_ENGINE_DISP);
+ if (!(r00154c & 0x00000020))
+ disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+ if (!(r00154c & 0x00000200))
+ disable |= (1ULL << NVDEV_ENGINE_CE0);
+
+ return disable;
+}
+
+static u32
+gt215_devinit_mmio_part[] = {
+ 0x100720, 0x1008bc, 4,
+ 0x100a20, 0x100adc, 4,
+ 0x100d80, 0x100ddc, 4,
+ 0x110000, 0x110f9c, 4,
+ 0x111000, 0x11103c, 8,
+ 0x111080, 0x1110fc, 4,
+ 0x111120, 0x1111fc, 4,
+ 0x111300, 0x1114bc, 4,
+ 0,
+};
+
+static u32
+gt215_devinit_mmio(struct nvkm_devinit *devinit, u32 addr)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 *mmio = gt215_devinit_mmio_part;
+
+ /* the init tables on some boards have INIT_RAM_RESTRICT_ZM_REG_GROUP
+ * instructions which touch registers that may not even exist on
+ * some configurations (Quadro 400), which causes the register
+ * interface to screw up for some amount of time after attempting to
+ * write to one of these, and results in all sorts of things going
+ * horribly wrong.
+ *
+ * the binary driver avoids touching these registers at all, however,
+ * the video bios doesn't care and does what the scripts say. it's
+ * presumed that the io-port access to priv registers isn't effected
+ * by the screw-up bug mentioned above.
+ *
+ * really, a new opcode should've been invented to handle these
+ * requirements, but whatever, it's too late for that now.
+ */
+ while (mmio[0]) {
+ if (addr >= mmio[0] && addr <= mmio[1]) {
+ u32 part = (addr / mmio[2]) & 7;
+ if (!priv->r001540)
+ priv->r001540 = nv_rd32(priv, 0x001540);
+ if (part >= hweight8((priv->r001540 >> 16) & 0xff))
+ return ~0;
+ return addr;
+ }
+ mmio += 3;
+ }
+
+ return addr;
+}
+
+struct nvkm_oclass *
+gt215_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0xa3),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = gt215_devinit_pll_set,
+ .disable = gt215_devinit_disable,
+ .mmio = gt215_devinit_mmio,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
new file mode 100644
index 000000000000..55cf48bbca1c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/mcp89.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static u64
+mcp89_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r001540 = nv_rd32(priv, 0x001540);
+ u32 r00154c = nv_rd32(priv, 0x00154c);
+ u64 disable = 0;
+
+ if (!(r001540 & 0x40000000)) {
+ disable |= (1ULL << NVDEV_ENGINE_MSPDEC);
+ disable |= (1ULL << NVDEV_ENGINE_MSPPP);
+ }
+
+ if (!(r00154c & 0x00000004))
+ disable |= (1ULL << NVDEV_ENGINE_DISP);
+ if (!(r00154c & 0x00000020))
+ disable |= (1ULL << NVDEV_ENGINE_MSVLD);
+ if (!(r00154c & 0x00000040))
+ disable |= (1ULL << NVDEV_ENGINE_VIC);
+ if (!(r00154c & 0x00000200))
+ disable |= (1ULL << NVDEV_ENGINE_CE0);
+
+ return disable;
+}
+
+struct nvkm_oclass *
+mcp89_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0xaf),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = gt215_devinit_pll_set,
+ .disable = mcp89_devinit_disable,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
new file mode 100644
index 000000000000..03a0da834244
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.c
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+#include <subdev/vga.h>
+
+static void
+nv04_devinit_meminit(struct nvkm_devinit *devinit)
+{
+ struct nv04_devinit_priv *priv = (void *)devinit;
+ u32 patt = 0xdeadbeef;
+ struct io_mapping *fb;
+ int i;
+
+ /* Map the framebuffer aperture */
+ fb = fbmem_init(nv_device(priv));
+ if (!fb) {
+ nv_error(priv, "failed to map fb\n");
+ return;
+ }
+
+ /* Sequencer and refresh off */
+ nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
+ nv_mask(priv, NV04_PFB_DEBUG_0, 0, NV04_PFB_DEBUG_0_REFRESH_OFF);
+
+ nv_mask(priv, NV04_PFB_BOOT_0, ~0,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_16MB |
+ NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+ NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT);
+
+ for (i = 0; i < 4; i++)
+ fbmem_poke(fb, 4 * i, patt);
+
+ fbmem_poke(fb, 0x400000, patt + 1);
+
+ if (fbmem_peek(fb, 0) == patt + 1) {
+ nv_mask(priv, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_TYPE,
+ NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT);
+ nv_mask(priv, NV04_PFB_DEBUG_0,
+ NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+
+ for (i = 0; i < 4; i++)
+ fbmem_poke(fb, 4 * i, patt);
+
+ if ((fbmem_peek(fb, 0xc) & 0xffff) != (patt & 0xffff))
+ nv_mask(priv, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+ } else
+ if ((fbmem_peek(fb, 0xc) & 0xffff0000) != (patt & 0xffff0000)) {
+ nv_mask(priv, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_WIDTH_128 |
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+ } else
+ if (fbmem_peek(fb, 0) != patt) {
+ if (fbmem_readback(fb, 0x800000, patt))
+ nv_mask(priv, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+ else
+ nv_mask(priv, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+ nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_TYPE,
+ NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT);
+ } else
+ if (!fbmem_readback(fb, 0x800000, patt)) {
+ nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+ }
+
+ /* Refresh on, sequencer on */
+ nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+ nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
+ fbmem_fini(fb);
+}
+
+static int
+powerctrl_1_shift(int chip_version, int reg)
+{
+ int shift = -4;
+
+ if (chip_version < 0x17 || chip_version == 0x1a || chip_version == 0x20)
+ return shift;
+
+ switch (reg) {
+ case 0x680520:
+ shift += 4;
+ case 0x680508:
+ shift += 4;
+ case 0x680504:
+ shift += 4;
+ case 0x680500:
+ shift += 4;
+ }
+
+ /*
+ * the shift for vpll regs is only used for nv3x chips with a single
+ * stage pll
+ */
+ if (shift > 4 && (chip_version < 0x32 || chip_version == 0x35 ||
+ chip_version == 0x36 || chip_version >= 0x40))
+ shift = -4;
+
+ return shift;
+}
+
+void
+setPLL_single(struct nvkm_devinit *devinit, u32 reg,
+ struct nvkm_pll_vals *pv)
+{
+ int chip_version = nvkm_bios(devinit)->version.chip;
+ uint32_t oldpll = nv_rd32(devinit, reg);
+ int oldN = (oldpll >> 8) & 0xff, oldM = oldpll & 0xff;
+ uint32_t pll = (oldpll & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+ uint32_t saved_powerctrl_1 = 0;
+ int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg);
+
+ if (oldpll == pll)
+ return; /* already set */
+
+ if (shift_powerctrl_1 >= 0) {
+ saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+ nv_wr32(devinit, 0x001584,
+ (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+ 1 << shift_powerctrl_1);
+ }
+
+ if (oldM && pv->M1 && (oldN / oldM < pv->N1 / pv->M1))
+ /* upclock -- write new post divider first */
+ nv_wr32(devinit, reg, pv->log2P << 16 | (oldpll & 0xffff));
+ else
+ /* downclock -- write new NM first */
+ nv_wr32(devinit, reg, (oldpll & 0xffff0000) | pv->NM1);
+
+ if ((chip_version < 0x17 || chip_version == 0x1a) &&
+ chip_version != 0x11)
+ /* wait a bit on older chips */
+ msleep(64);
+ nv_rd32(devinit, reg);
+
+ /* then write the other half as well */
+ nv_wr32(devinit, reg, pll);
+
+ if (shift_powerctrl_1 >= 0)
+ nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+}
+
+static uint32_t
+new_ramdac580(uint32_t reg1, bool ss, uint32_t ramdac580)
+{
+ bool head_a = (reg1 == 0x680508);
+
+ if (ss) /* single stage pll mode */
+ ramdac580 |= head_a ? 0x00000100 : 0x10000000;
+ else
+ ramdac580 &= head_a ? 0xfffffeff : 0xefffffff;
+
+ return ramdac580;
+}
+
+void
+setPLL_double_highregs(struct nvkm_devinit *devinit, u32 reg1,
+ struct nvkm_pll_vals *pv)
+{
+ int chip_version = nvkm_bios(devinit)->version.chip;
+ bool nv3035 = chip_version == 0x30 || chip_version == 0x35;
+ uint32_t reg2 = reg1 + ((reg1 == 0x680520) ? 0x5c : 0x70);
+ uint32_t oldpll1 = nv_rd32(devinit, reg1);
+ uint32_t oldpll2 = !nv3035 ? nv_rd32(devinit, reg2) : 0;
+ uint32_t pll1 = (oldpll1 & 0xfff80000) | pv->log2P << 16 | pv->NM1;
+ uint32_t pll2 = (oldpll2 & 0x7fff0000) | 1 << 31 | pv->NM2;
+ uint32_t oldramdac580 = 0, ramdac580 = 0;
+ bool single_stage = !pv->NM2 || pv->N2 == pv->M2; /* nv41+ only */
+ uint32_t saved_powerctrl_1 = 0, savedc040 = 0;
+ int shift_powerctrl_1 = powerctrl_1_shift(chip_version, reg1);
+
+ /* model specific additions to generic pll1 and pll2 set up above */
+ if (nv3035) {
+ pll1 = (pll1 & 0xfcc7ffff) | (pv->N2 & 0x18) << 21 |
+ (pv->N2 & 0x7) << 19 | 8 << 4 | (pv->M2 & 7) << 4;
+ pll2 = 0;
+ }
+ if (chip_version > 0x40 && reg1 >= 0x680508) { /* !nv40 */
+ oldramdac580 = nv_rd32(devinit, 0x680580);
+ ramdac580 = new_ramdac580(reg1, single_stage, oldramdac580);
+ if (oldramdac580 != ramdac580)
+ oldpll1 = ~0; /* force mismatch */
+ if (single_stage)
+ /* magic value used by nvidia in single stage mode */
+ pll2 |= 0x011f;
+ }
+ if (chip_version > 0x70)
+ /* magic bits set by the blob (but not the bios) on g71-73 */
+ pll1 = (pll1 & 0x7fffffff) | (single_stage ? 0x4 : 0xc) << 28;
+
+ if (oldpll1 == pll1 && oldpll2 == pll2)
+ return; /* already set */
+
+ if (shift_powerctrl_1 >= 0) {
+ saved_powerctrl_1 = nv_rd32(devinit, 0x001584);
+ nv_wr32(devinit, 0x001584,
+ (saved_powerctrl_1 & ~(0xf << shift_powerctrl_1)) |
+ 1 << shift_powerctrl_1);
+ }
+
+ if (chip_version >= 0x40) {
+ int shift_c040 = 14;
+
+ switch (reg1) {
+ case 0x680504:
+ shift_c040 += 2;
+ case 0x680500:
+ shift_c040 += 2;
+ case 0x680520:
+ shift_c040 += 2;
+ case 0x680508:
+ shift_c040 += 2;
+ }
+
+ savedc040 = nv_rd32(devinit, 0xc040);
+ if (shift_c040 != 14)
+ nv_wr32(devinit, 0xc040, savedc040 & ~(3 << shift_c040));
+ }
+
+ if (oldramdac580 != ramdac580)
+ nv_wr32(devinit, 0x680580, ramdac580);
+
+ if (!nv3035)
+ nv_wr32(devinit, reg2, pll2);
+ nv_wr32(devinit, reg1, pll1);
+
+ if (shift_powerctrl_1 >= 0)
+ nv_wr32(devinit, 0x001584, saved_powerctrl_1);
+ if (chip_version >= 0x40)
+ nv_wr32(devinit, 0xc040, savedc040);
+}
+
+void
+setPLL_double_lowregs(struct nvkm_devinit *devinit, u32 NMNMreg,
+ struct nvkm_pll_vals *pv)
+{
+ /* When setting PLLs, there is a merry game of disabling and enabling
+ * various bits of hardware during the process. This function is a
+ * synthesis of six nv4x traces, nearly each card doing a subtly
+ * different thing. With luck all the necessary bits for each card are
+ * combined herein. Without luck it deviates from each card's formula
+ * so as to not work on any :)
+ */
+
+ uint32_t Preg = NMNMreg - 4;
+ bool mpll = Preg == 0x4020;
+ uint32_t oldPval = nv_rd32(devinit, Preg);
+ uint32_t NMNM = pv->NM2 << 16 | pv->NM1;
+ uint32_t Pval = (oldPval & (mpll ? ~(0x77 << 16) : ~(7 << 16))) |
+ 0xc << 28 | pv->log2P << 16;
+ uint32_t saved4600 = 0;
+ /* some cards have different maskc040s */
+ uint32_t maskc040 = ~(3 << 14), savedc040;
+ bool single_stage = !pv->NM2 || pv->N2 == pv->M2;
+
+ if (nv_rd32(devinit, NMNMreg) == NMNM && (oldPval & 0xc0070000) == Pval)
+ return;
+
+ if (Preg == 0x4000)
+ maskc040 = ~0x333;
+ if (Preg == 0x4058)
+ maskc040 = ~(0xc << 24);
+
+ if (mpll) {
+ struct nvbios_pll info;
+ uint8_t Pval2;
+
+ if (nvbios_pll_parse(nvkm_bios(devinit), Preg, &info))
+ return;
+
+ Pval2 = pv->log2P + info.bias_p;
+ if (Pval2 > info.max_p)
+ Pval2 = info.max_p;
+ Pval |= 1 << 28 | Pval2 << 20;
+
+ saved4600 = nv_rd32(devinit, 0x4600);
+ nv_wr32(devinit, 0x4600, saved4600 | 8 << 28);
+ }
+ if (single_stage)
+ Pval |= mpll ? 1 << 12 : 1 << 8;
+
+ nv_wr32(devinit, Preg, oldPval | 1 << 28);
+ nv_wr32(devinit, Preg, Pval & ~(4 << 28));
+ if (mpll) {
+ Pval |= 8 << 20;
+ nv_wr32(devinit, 0x4020, Pval & ~(0xc << 28));
+ nv_wr32(devinit, 0x4038, Pval & ~(0xc << 28));
+ }
+
+ savedc040 = nv_rd32(devinit, 0xc040);
+ nv_wr32(devinit, 0xc040, savedc040 & maskc040);
+
+ nv_wr32(devinit, NMNMreg, NMNM);
+ if (NMNMreg == 0x4024)
+ nv_wr32(devinit, 0x403c, NMNM);
+
+ nv_wr32(devinit, Preg, Pval);
+ if (mpll) {
+ Pval &= ~(8 << 20);
+ nv_wr32(devinit, 0x4020, Pval);
+ nv_wr32(devinit, 0x4038, Pval);
+ nv_wr32(devinit, 0x4600, saved4600);
+ }
+
+ nv_wr32(devinit, 0xc040, savedc040);
+
+ if (mpll) {
+ nv_wr32(devinit, 0x4020, Pval & ~(1 << 28));
+ nv_wr32(devinit, 0x4038, Pval & ~(1 << 28));
+ }
+}
+
+int
+nv04_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+ struct nvkm_bios *bios = nvkm_bios(devinit);
+ struct nvkm_pll_vals pv;
+ struct nvbios_pll info;
+ int cv = bios->version.chip;
+ int N1, M1, N2, M2, P;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, type > 0x405c ? type : type - 4, &info);
+ if (ret)
+ return ret;
+
+ ret = nv04_pll_calc(nv_subdev(devinit), &info, freq,
+ &N1, &M1, &N2, &M2, &P);
+ if (!ret)
+ return -EINVAL;
+
+ pv.refclk = info.refclk;
+ pv.N1 = N1;
+ pv.M1 = M1;
+ pv.N2 = N2;
+ pv.M2 = M2;
+ pv.log2P = P;
+
+ if (cv == 0x30 || cv == 0x31 || cv == 0x35 || cv == 0x36 ||
+ cv >= 0x40) {
+ if (type > 0x405c)
+ setPLL_double_highregs(devinit, type, &pv);
+ else
+ setPLL_double_lowregs(devinit, type, &pv);
+ } else
+ setPLL_single(devinit, type, &pv);
+
+ return 0;
+}
+
+int
+nv04_devinit_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv04_devinit_priv *priv = (void *)object;
+ int ret;
+
+ /* make i2c busses accessible */
+ nv_mask(priv, 0x000200, 0x00000001, 0x00000001);
+
+ ret = nvkm_devinit_fini(&priv->base, suspend);
+ if (ret)
+ return ret;
+
+ /* unslave crtcs */
+ if (priv->owner < 0)
+ priv->owner = nv_rdvgaowner(priv);
+ nv_wrvgaowner(priv, 0);
+ return 0;
+}
+
+int
+nv04_devinit_init(struct nvkm_object *object)
+{
+ struct nv04_devinit_priv *priv = (void *)object;
+
+ if (!priv->base.post) {
+ u32 htotal = nv_rdvgac(priv, 0, 0x06);
+ htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x01) << 8;
+ htotal |= (nv_rdvgac(priv, 0, 0x07) & 0x20) << 4;
+ htotal |= (nv_rdvgac(priv, 0, 0x25) & 0x01) << 10;
+ htotal |= (nv_rdvgac(priv, 0, 0x41) & 0x01) << 11;
+ if (!htotal) {
+ nv_info(priv, "adaptor not initialised\n");
+ priv->base.post = true;
+ }
+ }
+
+ return nvkm_devinit_init(&priv->base);
+}
+
+void
+nv04_devinit_dtor(struct nvkm_object *object)
+{
+ struct nv04_devinit_priv *priv = (void *)object;
+
+ /* restore vga owner saved at first init */
+ nv_wrvgaowner(priv, priv->owner);
+
+ nvkm_devinit_destroy(&priv->base);
+}
+
+int
+nv04_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_devinit_priv *priv;
+ int ret;
+
+ ret = nvkm_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->owner = -1;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_devinit_ctor,
+ .dtor = nv04_devinit_dtor,
+ .init = nv04_devinit_init,
+ .fini = nv04_devinit_fini,
+ },
+ .meminit = nv04_devinit_meminit,
+ .pll_set = nv04_devinit_pll_set,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h
new file mode 100644
index 000000000000..14a51a9ff7d0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv04.h
@@ -0,0 +1,22 @@
+#ifndef __NVKM_DEVINIT_NV04_H__
+#define __NVKM_DEVINIT_NV04_H__
+#include "priv.h"
+struct nvkm_pll_vals;
+
+struct nv04_devinit_priv {
+ struct nvkm_devinit base;
+ u8 owner;
+};
+
+int nv04_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nv04_devinit_dtor(struct nvkm_object *);
+int nv04_devinit_init(struct nvkm_object *);
+int nv04_devinit_fini(struct nvkm_object *, bool);
+int nv04_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+void setPLL_single(struct nvkm_devinit *, u32, struct nvkm_pll_vals *);
+void setPLL_double_highregs(struct nvkm_devinit *, u32, struct nvkm_pll_vals *);
+void setPLL_double_lowregs(struct nvkm_devinit *, u32, struct nvkm_pll_vals *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c
new file mode 100644
index 000000000000..def8649216c2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv05.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/bmp.h>
+#include <subdev/bios/init.h>
+#include <subdev/vga.h>
+
+static void
+nv05_devinit_meminit(struct nvkm_devinit *devinit)
+{
+ static const u8 default_config_tab[][2] = {
+ { 0x24, 0x00 },
+ { 0x28, 0x00 },
+ { 0x24, 0x01 },
+ { 0x1f, 0x00 },
+ { 0x0f, 0x00 },
+ { 0x17, 0x00 },
+ { 0x06, 0x00 },
+ { 0x00, 0x00 }
+ };
+ struct nv04_devinit_priv *priv = (void *)devinit;
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct io_mapping *fb;
+ u32 patt = 0xdeadbeef;
+ u16 data;
+ u8 strap, ramcfg[2];
+ int i, v;
+
+ /* Map the framebuffer aperture */
+ fb = fbmem_init(nv_device(priv));
+ if (!fb) {
+ nv_error(priv, "failed to map fb\n");
+ return;
+ }
+
+ strap = (nv_rd32(priv, 0x101000) & 0x0000003c) >> 2;
+ if ((data = bmp_mem_init_table(bios))) {
+ ramcfg[0] = nv_ro08(bios, data + 2 * strap + 0);
+ ramcfg[1] = nv_ro08(bios, data + 2 * strap + 1);
+ } else {
+ ramcfg[0] = default_config_tab[strap][0];
+ ramcfg[1] = default_config_tab[strap][1];
+ }
+
+ /* Sequencer off */
+ nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) | 0x20);
+
+ if (nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_UMA_ENABLE)
+ goto out;
+
+ nv_mask(priv, NV04_PFB_DEBUG_0, NV04_PFB_DEBUG_0_REFRESH_OFF, 0);
+
+ /* If present load the hardcoded scrambling table */
+ if (data) {
+ for (i = 0, data += 0x10; i < 8; i++, data += 4) {
+ u32 scramble = nv_ro32(bios, data);
+ nv_wr32(priv, NV04_PFB_SCRAMBLE(i), scramble);
+ }
+ }
+
+ /* Set memory type/width/length defaults depending on the straps */
+ nv_mask(priv, NV04_PFB_BOOT_0, 0x3f, ramcfg[0]);
+
+ if (ramcfg[1] & 0x80)
+ nv_mask(priv, NV04_PFB_CFG0, 0, NV04_PFB_CFG0_SCRAMBLE);
+
+ nv_mask(priv, NV04_PFB_CFG1, 0x700001, (ramcfg[1] & 1) << 20);
+ nv_mask(priv, NV04_PFB_CFG1, 0, 1);
+
+ /* Probe memory bus width */
+ for (i = 0; i < 4; i++)
+ fbmem_poke(fb, 4 * i, patt);
+
+ if (fbmem_peek(fb, 0xc) != patt)
+ nv_mask(priv, NV04_PFB_BOOT_0,
+ NV04_PFB_BOOT_0_RAM_WIDTH_128, 0);
+
+ /* Probe memory length */
+ v = nv_rd32(priv, NV04_PFB_BOOT_0) & NV04_PFB_BOOT_0_RAM_AMOUNT;
+
+ if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_32MB &&
+ (!fbmem_readback(fb, 0x1000000, ++patt) ||
+ !fbmem_readback(fb, 0, ++patt)))
+ nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_16MB);
+
+ if (v == NV04_PFB_BOOT_0_RAM_AMOUNT_16MB &&
+ !fbmem_readback(fb, 0x800000, ++patt))
+ nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_8MB);
+
+ if (!fbmem_readback(fb, 0x400000, ++patt))
+ nv_mask(priv, NV04_PFB_BOOT_0, NV04_PFB_BOOT_0_RAM_AMOUNT,
+ NV04_PFB_BOOT_0_RAM_AMOUNT_4MB);
+
+out:
+ /* Sequencer on */
+ nv_wrvgas(priv, 0, 1, nv_rdvgas(priv, 0, 1) & ~0x20);
+ fbmem_fini(fb);
+}
+
+struct nvkm_oclass *
+nv05_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x05),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_devinit_ctor,
+ .dtor = nv04_devinit_dtor,
+ .init = nv04_devinit_init,
+ .fini = nv04_devinit_fini,
+ },
+ .meminit = nv05_devinit_meminit,
+ .pll_set = nv04_devinit_pll_set,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c
new file mode 100644
index 000000000000..7aabc1bf0640
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv10.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static void
+nv10_devinit_meminit(struct nvkm_devinit *devinit)
+{
+ struct nv04_devinit_priv *priv = (void *)devinit;
+ static const int mem_width[] = { 0x10, 0x00, 0x20 };
+ int mem_width_count;
+ uint32_t patt = 0xdeadbeef;
+ struct io_mapping *fb;
+ int i, j, k;
+
+ if (nv_device(priv)->card_type >= NV_11 &&
+ nv_device(priv)->chipset >= 0x17)
+ mem_width_count = 3;
+ else
+ mem_width_count = 2;
+
+ /* Map the framebuffer aperture */
+ fb = fbmem_init(nv_device(priv));
+ if (!fb) {
+ nv_error(priv, "failed to map fb\n");
+ return;
+ }
+
+ nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
+
+ /* Probe memory bus width */
+ for (i = 0; i < mem_width_count; i++) {
+ nv_mask(priv, NV04_PFB_CFG0, 0x30, mem_width[i]);
+
+ for (j = 0; j < 4; j++) {
+ for (k = 0; k < 4; k++)
+ fbmem_poke(fb, 0x1c, 0);
+
+ fbmem_poke(fb, 0x1c, patt);
+ fbmem_poke(fb, 0x3c, 0);
+
+ if (fbmem_peek(fb, 0x1c) == patt)
+ goto mem_width_found;
+ }
+ }
+
+mem_width_found:
+ patt <<= 1;
+
+ /* Probe amount of installed memory */
+ for (i = 0; i < 4; i++) {
+ int off = nv_rd32(priv, 0x10020c) - 0x100000;
+
+ fbmem_poke(fb, off, patt);
+ fbmem_poke(fb, 0, 0);
+
+ fbmem_peek(fb, 0);
+ fbmem_peek(fb, 0);
+ fbmem_peek(fb, 0);
+ fbmem_peek(fb, 0);
+
+ if (fbmem_peek(fb, off) == patt)
+ goto amount_found;
+ }
+
+ /* IC missing - disable the upper half memory space. */
+ nv_mask(priv, NV04_PFB_CFG0, 0x1000, 0);
+
+amount_found:
+ fbmem_fini(fb);
+}
+
+struct nvkm_oclass *
+nv10_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x10),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_devinit_ctor,
+ .dtor = nv04_devinit_dtor,
+ .init = nv04_devinit_init,
+ .fini = nv04_devinit_fini,
+ },
+ .meminit = nv10_devinit_meminit,
+ .pll_set = nv04_devinit_pll_set,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c
new file mode 100644
index 000000000000..9f36fff5a1c3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv1a.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+struct nvkm_oclass *
+nv1a_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x1a),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_devinit_ctor,
+ .dtor = nv04_devinit_dtor,
+ .init = nv04_devinit_init,
+ .fini = nv04_devinit_fini,
+ },
+ .pll_set = nv04_devinit_pll_set,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c
new file mode 100644
index 000000000000..02fcfd921c42
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv20.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+#include "fbmem.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+
+static void
+nv20_devinit_meminit(struct nvkm_devinit *devinit)
+{
+ struct nv04_devinit_priv *priv = (void *)devinit;
+ struct nvkm_device *device = nv_device(priv);
+ uint32_t mask = (device->chipset >= 0x25 ? 0x300 : 0x900);
+ uint32_t amount, off;
+ struct io_mapping *fb;
+
+ /* Map the framebuffer aperture */
+ fb = fbmem_init(nv_device(priv));
+ if (!fb) {
+ nv_error(priv, "failed to map fb\n");
+ return;
+ }
+
+ nv_wr32(priv, NV10_PFB_REFCTRL, NV10_PFB_REFCTRL_VALID_1);
+
+ /* Allow full addressing */
+ nv_mask(priv, NV04_PFB_CFG0, 0, mask);
+
+ amount = nv_rd32(priv, 0x10020c);
+ for (off = amount; off > 0x2000000; off -= 0x2000000)
+ fbmem_poke(fb, off - 4, off);
+
+ amount = nv_rd32(priv, 0x10020c);
+ if (amount != fbmem_peek(fb, amount - 4))
+ /* IC missing - disable the upper half memory space. */
+ nv_mask(priv, NV04_PFB_CFG0, mask, 0);
+
+ fbmem_fini(fb);
+}
+
+struct nvkm_oclass *
+nv20_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x20),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_devinit_ctor,
+ .dtor = nv04_devinit_dtor,
+ .init = nv04_devinit_init,
+ .fini = nv04_devinit_fini,
+ },
+ .meminit = nv20_devinit_meminit,
+ .pll_set = nv04_devinit_pll_set,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
new file mode 100644
index 000000000000..26b7cb13e167
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/disp.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+#include <subdev/ibus.h>
+#include <subdev/vga.h>
+
+int
+nv50_devinit_pll_set(struct nvkm_devinit *devinit, u32 type, u32 freq)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ struct nvkm_bios *bios = nvkm_bios(priv);
+ struct nvbios_pll info;
+ int N1, M1, N2, M2, P;
+ int ret;
+
+ ret = nvbios_pll_parse(bios, type, &info);
+ if (ret) {
+ nv_error(devinit, "failed to retrieve pll data, %d\n", ret);
+ return ret;
+ }
+
+ ret = nv04_pll_calc(nv_subdev(devinit), &info, freq, &N1, &M1, &N2, &M2, &P);
+ if (!ret) {
+ nv_error(devinit, "failed pll calculation\n");
+ return ret;
+ }
+
+ switch (info.type) {
+ case PLL_VPLL0:
+ case PLL_VPLL1:
+ nv_wr32(priv, info.reg + 0, 0x10000611);
+ nv_mask(priv, info.reg + 4, 0x00ff00ff, (M1 << 16) | N1);
+ nv_mask(priv, info.reg + 8, 0x7fff00ff, (P << 28) |
+ (M2 << 16) | N2);
+ break;
+ case PLL_MEMORY:
+ nv_mask(priv, info.reg + 0, 0x01ff0000, (P << 22) |
+ (info.bias_p << 19) |
+ (P << 16));
+ nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+ break;
+ default:
+ nv_mask(priv, info.reg + 0, 0x00070000, (P << 16));
+ nv_wr32(priv, info.reg + 4, (N1 << 8) | M1);
+ break;
+ }
+
+ return 0;
+}
+
+static u64
+nv50_devinit_disable(struct nvkm_devinit *devinit)
+{
+ struct nv50_devinit_priv *priv = (void *)devinit;
+ u32 r001540 = nv_rd32(priv, 0x001540);
+ u64 disable = 0ULL;
+
+ if (!(r001540 & 0x40000000))
+ disable |= (1ULL << NVDEV_ENGINE_MPEG);
+
+ return disable;
+}
+
+int
+nv50_devinit_init(struct nvkm_object *object)
+{
+ struct nvkm_bios *bios = nvkm_bios(object);
+ struct nvkm_ibus *ibus = nvkm_ibus(object);
+ struct nv50_devinit_priv *priv = (void *)object;
+ struct nvbios_outp info;
+ struct dcb_output outp;
+ u8 ver = 0xff, hdr, cnt, len;
+ int ret, i = 0;
+
+ if (!priv->base.post) {
+ if (!nv_rdvgac(priv, 0, 0x00) &&
+ !nv_rdvgac(priv, 0, 0x1a)) {
+ nv_info(priv, "adaptor not initialised\n");
+ priv->base.post = true;
+ }
+ }
+
+ /* some boards appear to require certain priv register timeouts
+ * to be bumped before runing devinit scripts. not a clue why
+ * the vbios engineers didn't make the scripts just work...
+ */
+ if (priv->base.post && ibus)
+ nv_ofuncs(ibus)->init(nv_object(ibus));
+
+ ret = nvkm_devinit_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* if we ran the init tables, we have to execute the first script
+ * pointer of each dcb entry's display encoder table in order
+ * to properly initialise each encoder.
+ */
+ while (priv->base.post && dcb_outp_parse(bios, i, &ver, &hdr, &outp)) {
+ if (nvbios_outp_match(bios, outp.hasht, outp.hashm,
+ &ver, &hdr, &cnt, &len, &info)) {
+ struct nvbios_init init = {
+ .subdev = nv_subdev(priv),
+ .bios = bios,
+ .offset = info.script[0],
+ .outp = &outp,
+ .crtc = -1,
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+int
+nv50_devinit_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_devinit_priv *priv;
+ int ret;
+
+ ret = nvkm_devinit_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_devinit_oclass = &(struct nvkm_devinit_impl) {
+ .base.handle = NV_SUBDEV(DEVINIT, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_devinit_ctor,
+ .dtor = _nvkm_devinit_dtor,
+ .init = nv50_devinit_init,
+ .fini = _nvkm_devinit_fini,
+ },
+ .pll_set = nv50_devinit_pll_set,
+ .disable = nv50_devinit_disable,
+ .post = nvbios_init,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
new file mode 100644
index 000000000000..b882b65ff3cd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/nv50.h
@@ -0,0 +1,21 @@
+#ifndef __NVKM_DEVINIT_NV50_H__
+#define __NVKM_DEVINIT_NV50_H__
+#include "priv.h"
+
+struct nv50_devinit_priv {
+ struct nvkm_devinit base;
+ u32 r001540;
+};
+
+int nv50_devinit_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+int nv50_devinit_init(struct nvkm_object *);
+int nv50_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+int gt215_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+int gf100_devinit_pll_set(struct nvkm_devinit *, u32, u32);
+
+u64 gm107_devinit_disable(struct nvkm_devinit *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
new file mode 100644
index 000000000000..bb51a95d8012
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/devinit/priv.h
@@ -0,0 +1,34 @@
+#ifndef __NVKM_DEVINIT_PRIV_H__
+#define __NVKM_DEVINIT_PRIV_H__
+#include <subdev/devinit.h>
+
+struct nvkm_devinit_impl {
+ struct nvkm_oclass base;
+ void (*meminit)(struct nvkm_devinit *);
+ int (*pll_set)(struct nvkm_devinit *, u32 type, u32 freq);
+ u64 (*disable)(struct nvkm_devinit *);
+ u32 (*mmio)(struct nvkm_devinit *, u32);
+ int (*post)(struct nvkm_subdev *, bool);
+};
+
+#define nvkm_devinit_create(p,e,o,d) \
+ nvkm_devinit_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_devinit_destroy(p) ({ \
+ struct nvkm_devinit *d = (p); \
+ _nvkm_devinit_dtor(nv_object(d)); \
+})
+#define nvkm_devinit_init(p) ({ \
+ struct nvkm_devinit *d = (p); \
+ _nvkm_devinit_init(nv_object(d)); \
+})
+#define nvkm_devinit_fini(p,s) ({ \
+ struct nvkm_devinit *d = (p); \
+ _nvkm_devinit_fini(nv_object(d), (s)); \
+})
+
+int nvkm_devinit_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_devinit_dtor(struct nvkm_object *);
+int _nvkm_devinit_init(struct nvkm_object *);
+int _nvkm_devinit_fini(struct nvkm_object *, bool suspend);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
new file mode 100644
index 000000000000..904d601e8a50
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/Kbuild
@@ -0,0 +1,45 @@
+nvkm-y += nvkm/subdev/fb/base.o
+nvkm-y += nvkm/subdev/fb/nv04.o
+nvkm-y += nvkm/subdev/fb/nv10.o
+nvkm-y += nvkm/subdev/fb/nv1a.o
+nvkm-y += nvkm/subdev/fb/nv20.o
+nvkm-y += nvkm/subdev/fb/nv25.o
+nvkm-y += nvkm/subdev/fb/nv30.o
+nvkm-y += nvkm/subdev/fb/nv35.o
+nvkm-y += nvkm/subdev/fb/nv36.o
+nvkm-y += nvkm/subdev/fb/nv40.o
+nvkm-y += nvkm/subdev/fb/nv41.o
+nvkm-y += nvkm/subdev/fb/nv44.o
+nvkm-y += nvkm/subdev/fb/nv46.o
+nvkm-y += nvkm/subdev/fb/nv47.o
+nvkm-y += nvkm/subdev/fb/nv49.o
+nvkm-y += nvkm/subdev/fb/nv4e.o
+nvkm-y += nvkm/subdev/fb/nv50.o
+nvkm-y += nvkm/subdev/fb/g84.o
+nvkm-y += nvkm/subdev/fb/gt215.o
+nvkm-y += nvkm/subdev/fb/mcp77.o
+nvkm-y += nvkm/subdev/fb/mcp89.o
+nvkm-y += nvkm/subdev/fb/gf100.o
+nvkm-y += nvkm/subdev/fb/gk104.o
+nvkm-y += nvkm/subdev/fb/gk20a.o
+nvkm-y += nvkm/subdev/fb/gm107.o
+nvkm-y += nvkm/subdev/fb/ramnv04.o
+nvkm-y += nvkm/subdev/fb/ramnv10.o
+nvkm-y += nvkm/subdev/fb/ramnv1a.o
+nvkm-y += nvkm/subdev/fb/ramnv20.o
+nvkm-y += nvkm/subdev/fb/ramnv40.o
+nvkm-y += nvkm/subdev/fb/ramnv41.o
+nvkm-y += nvkm/subdev/fb/ramnv44.o
+nvkm-y += nvkm/subdev/fb/ramnv49.o
+nvkm-y += nvkm/subdev/fb/ramnv4e.o
+nvkm-y += nvkm/subdev/fb/ramnv50.o
+nvkm-y += nvkm/subdev/fb/ramgt215.o
+nvkm-y += nvkm/subdev/fb/rammcp77.o
+nvkm-y += nvkm/subdev/fb/ramgf100.o
+nvkm-y += nvkm/subdev/fb/ramgk104.o
+nvkm-y += nvkm/subdev/fb/ramgk20a.o
+nvkm-y += nvkm/subdev/fb/ramgm107.o
+nvkm-y += nvkm/subdev/fb/sddr2.o
+nvkm-y += nvkm/subdev/fb/sddr3.o
+nvkm-y += nvkm/subdev/fb/gddr3.o
+nvkm-y += nvkm/subdev/fb/gddr5.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
new file mode 100644
index 000000000000..16589fa613cd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/base.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/M0203.h>
+
+int
+nvkm_fb_bios_memtype(struct nvkm_bios *bios)
+{
+ const u8 ramcfg = (nv_rd32(bios, 0x101000) & 0x0000003c) >> 2;
+ struct nvbios_M0203E M0203E;
+ u8 ver, hdr;
+
+ if (nvbios_M0203Em(bios, ramcfg, &ver, &hdr, &M0203E)) {
+ switch (M0203E.type) {
+ case M0203E_TYPE_DDR2 : return NV_MEM_TYPE_DDR2;
+ case M0203E_TYPE_DDR3 : return NV_MEM_TYPE_DDR3;
+ case M0203E_TYPE_GDDR3: return NV_MEM_TYPE_GDDR3;
+ case M0203E_TYPE_GDDR5: return NV_MEM_TYPE_GDDR5;
+ default:
+ nv_warn(bios, "M0203E type %02x\n", M0203E.type);
+ return NV_MEM_TYPE_UNKNOWN;
+ }
+ }
+
+ nv_warn(bios, "M0203E not matched!\n");
+ return NV_MEM_TYPE_UNKNOWN;
+}
+
+int
+_nvkm_fb_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_fb *pfb = (void *)object;
+ int ret;
+
+ ret = nv_ofuncs(pfb->ram)->fini(nv_object(pfb->ram), suspend);
+ if (ret && suspend)
+ return ret;
+
+ return nvkm_subdev_fini(&pfb->base, suspend);
+}
+
+int
+_nvkm_fb_init(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = (void *)object;
+ int ret, i;
+
+ ret = nvkm_subdev_init(&pfb->base);
+ if (ret)
+ return ret;
+
+ ret = nv_ofuncs(pfb->ram)->init(nv_object(pfb->ram));
+ if (ret)
+ return ret;
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.prog(pfb, i, &pfb->tile.region[i]);
+
+ return 0;
+}
+
+void
+_nvkm_fb_dtor(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = (void *)object;
+ int i;
+
+ for (i = 0; i < pfb->tile.regions; i++)
+ pfb->tile.fini(pfb, i, &pfb->tile.region[i]);
+ nvkm_mm_fini(&pfb->tags);
+ nvkm_mm_fini(&pfb->vram);
+
+ nvkm_object_ref(NULL, (struct nvkm_object **)&pfb->ram);
+ nvkm_subdev_destroy(&pfb->base);
+}
+
+int
+nvkm_fb_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_fb_impl *impl = (void *)oclass;
+ static const char *name[] = {
+ [NV_MEM_TYPE_UNKNOWN] = "unknown",
+ [NV_MEM_TYPE_STOLEN ] = "stolen system memory",
+ [NV_MEM_TYPE_SGRAM ] = "SGRAM",
+ [NV_MEM_TYPE_SDRAM ] = "SDRAM",
+ [NV_MEM_TYPE_DDR1 ] = "DDR1",
+ [NV_MEM_TYPE_DDR2 ] = "DDR2",
+ [NV_MEM_TYPE_DDR3 ] = "DDR3",
+ [NV_MEM_TYPE_GDDR2 ] = "GDDR2",
+ [NV_MEM_TYPE_GDDR3 ] = "GDDR3",
+ [NV_MEM_TYPE_GDDR4 ] = "GDDR4",
+ [NV_MEM_TYPE_GDDR5 ] = "GDDR5",
+ };
+ struct nvkm_object *ram;
+ struct nvkm_fb *pfb;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PFB", "fb",
+ length, pobject);
+ pfb = *pobject;
+ if (ret)
+ return ret;
+
+ pfb->memtype_valid = impl->memtype;
+
+ ret = nvkm_object_ctor(nv_object(pfb), NULL, impl->ram, NULL, 0, &ram);
+ if (ret) {
+ nv_fatal(pfb, "error detecting memory configuration!!\n");
+ return ret;
+ }
+
+ pfb->ram = (void *)ram;
+
+ if (!nvkm_mm_initialised(&pfb->vram)) {
+ ret = nvkm_mm_init(&pfb->vram, 0, pfb->ram->size >> 12, 1);
+ if (ret)
+ return ret;
+ }
+
+ if (!nvkm_mm_initialised(&pfb->tags)) {
+ ret = nvkm_mm_init(&pfb->tags, 0, pfb->ram->tags ?
+ ++pfb->ram->tags : 0, 1);
+ if (ret)
+ return ret;
+ }
+
+ nv_info(pfb, "RAM type: %s\n", name[pfb->ram->type]);
+ nv_info(pfb, "RAM size: %d MiB\n", (int)(pfb->ram->size >> 20));
+ nv_info(pfb, " ZCOMP: %d tags\n", pfb->ram->tags);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c
new file mode 100644
index 000000000000..6c968d1e98b3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/g84.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+g84_fb_oclass = &(struct nv50_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x84),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fb_ctor,
+ .dtor = nv50_fb_dtor,
+ .init = nv50_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv50_fb_memtype_valid,
+ .base.ram = &nv50_ram_oclass,
+ .trap = 0x001d07ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
new file mode 100644
index 000000000000..15b462ae33cb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr3.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ * Roy Spliet <rspliet@eclipso.eu>
+ */
+#include "priv.h"
+
+struct ramxlat {
+ int id;
+ u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+ while (xlat->id >= 0) {
+ if (xlat->id == id)
+ return xlat->enc;
+ xlat++;
+ }
+ return -EINVAL;
+}
+
+static const struct ramxlat
+ramgddr3_cl_lo[] = {
+ { 7, 7 }, { 8, 0 }, { 9, 1 }, { 10, 2 }, { 11, 3 },
+ /* the below are mentioned in some, but not all, gddr3 docs */
+ { 12, 4 }, { 13, 5 }, { 14, 6 },
+ /* XXX: Per Samsung docs, are these used? They overlap with Qimonda */
+ /* { 4, 4 }, { 5, 5 }, { 6, 6 }, { 12, 8 }, { 13, 9 }, { 14, 10 },
+ * { 15, 11 }, */
+ { -1 }
+};
+
+static const struct ramxlat
+ramgddr3_cl_hi[] = {
+ { 10, 2 }, { 11, 3 }, { 12, 4 }, { 13, 5 }, { 14, 6 }, { 15, 7 },
+ { 16, 0 }, { 17, 1 },
+ { -1 }
+};
+
+static const struct ramxlat
+ramgddr3_wr_lo[] = {
+ { 5, 2 }, { 7, 4 }, { 8, 5 }, { 9, 6 }, { 10, 7 },
+ { 11, 0 },
+ /* the below are mentioned in some, but not all, gddr3 docs */
+ { 4, 1 }, { 6, 3 }, { 12, 1 }, { 13 , 2 },
+ { -1 }
+};
+
+int
+nvkm_gddr3_calc(struct nvkm_ram *ram)
+{
+ int CL, WR, CWL, DLL = 0, ODT = 0, hi;
+
+ switch (ram->next->bios.timing_ver) {
+ case 0x10:
+ CWL = ram->next->bios.timing_10_CWL;
+ CL = ram->next->bios.timing_10_CL;
+ WR = ram->next->bios.timing_10_WR;
+ DLL = !ram->next->bios.ramcfg_10_DLLoff;
+ ODT = ram->next->bios.timing_10_ODT;
+ break;
+ case 0x20:
+ CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+ CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
+ WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+ /* XXX: Get these values from the VBIOS instead */
+ DLL = !(ram->mr[1] & 0x1);
+ ODT = (ram->mr[1] & 0x004) >> 2 |
+ (ram->mr[1] & 0x040) >> 5 |
+ (ram->mr[1] & 0x200) >> 7;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ hi = ram->mr[2] & 0x1;
+ CL = ramxlat(hi ? ramgddr3_cl_hi : ramgddr3_cl_lo, CL);
+ WR = ramxlat(ramgddr3_wr_lo, WR);
+ if (CL < 0 || CWL < 1 || CWL > 7 || WR < 0)
+ return -EINVAL;
+
+ ram->mr[0] &= ~0xf74;
+ ram->mr[0] |= (CWL & 0x07) << 9;
+ ram->mr[0] |= (CL & 0x07) << 4;
+ ram->mr[0] |= (CL & 0x08) >> 1;
+
+ ram->mr[1] &= ~0x3fc;
+ ram->mr[1] |= (ODT & 0x03) << 2;
+ ram->mr[1] |= (ODT & 0x03) << 8;
+ ram->mr[1] |= (WR & 0x03) << 4;
+ ram->mr[1] |= (WR & 0x04) << 5;
+ ram->mr[1] |= !DLL << 6;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c
new file mode 100644
index 000000000000..f6f9eee1dcd0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gddr5.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+/* binary driver only executes this path if the condition (a) is true
+ * for any configuration (combination of rammap+ramcfg+timing) that
+ * can be reached on a given card. for now, we will execute the branch
+ * unconditionally in the hope that a "false everywhere" in the bios
+ * tables doesn't actually mean "don't touch this".
+ */
+#define NOTE00(a) 1
+
+int
+nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts)
+{
+ int pd, lf, xd, vh, vr, vo, l3;
+ int WL, CL, WR, at[2], dt, ds;
+ int rq = ram->freq < 1000000; /* XXX */
+
+ switch (ram->next->bios.ramcfg_ver) {
+ case 0x11:
+ pd = ram->next->bios.ramcfg_11_01_80;
+ lf = ram->next->bios.ramcfg_11_01_40;
+ xd = !ram->next->bios.ramcfg_11_01_20;
+ vh = ram->next->bios.ramcfg_11_02_10;
+ vr = ram->next->bios.ramcfg_11_02_04;
+ vo = ram->next->bios.ramcfg_11_06;
+ l3 = !ram->next->bios.ramcfg_11_07_02;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ switch (ram->next->bios.timing_ver) {
+ case 0x20:
+ WL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+ CL = (ram->next->bios.timing[1] & 0x0000001f);
+ WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+ at[0] = ram->next->bios.timing_20_2e_c0;
+ at[1] = ram->next->bios.timing_20_2e_30;
+ dt = ram->next->bios.timing_20_2e_03;
+ ds = ram->next->bios.timing_20_2f_03;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ if (WL < 1 || WL > 7 || CL < 5 || CL > 36 || WR < 4 || WR > 35)
+ return -EINVAL;
+ CL -= 5;
+ WR -= 4;
+
+ ram->mr[0] &= ~0xf7f;
+ ram->mr[0] |= (WR & 0x0f) << 8;
+ ram->mr[0] |= (CL & 0x0f) << 3;
+ ram->mr[0] |= (WL & 0x07) << 0;
+
+ ram->mr[1] &= ~0x0bf;
+ ram->mr[1] |= (xd & 0x01) << 7;
+ ram->mr[1] |= (at[0] & 0x03) << 4;
+ ram->mr[1] |= (dt & 0x03) << 2;
+ ram->mr[1] |= (ds & 0x03) << 0;
+
+ /* this seems wrong, alternate field used for the broadcast
+ * on nuts vs non-nuts configs.. meh, it matches for now.
+ */
+ ram->mr1_nuts = ram->mr[1];
+ if (nuts) {
+ ram->mr[1] &= ~0x030;
+ ram->mr[1] |= (at[1] & 0x03) << 4;
+ }
+
+ ram->mr[3] &= ~0x020;
+ ram->mr[3] |= (rq & 0x01) << 5;
+
+ ram->mr[5] &= ~0x004;
+ ram->mr[5] |= (l3 << 2);
+
+ if (!vo)
+ vo = (ram->mr[6] & 0xff0) >> 4;
+ if (ram->mr[6] & 0x001)
+ pd = 1; /* binary driver does this.. bug? */
+ ram->mr[6] &= ~0xff1;
+ ram->mr[6] |= (vo & 0xff) << 4;
+ ram->mr[6] |= (pd & 0x01) << 0;
+
+ if (NOTE00(vr)) {
+ ram->mr[7] &= ~0x300;
+ ram->mr[7] |= (vr & 0x03) << 8;
+ }
+ ram->mr[7] &= ~0x088;
+ ram->mr[7] |= (vh & 0x01) << 7;
+ ram->mr[7] |= (lf & 0x01) << 3;
+
+ ram->mr[8] &= ~0x003;
+ ram->mr[8] |= (WR & 0x10) >> 3;
+ ram->mr[8] |= (CL & 0x10) >> 4;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
new file mode 100644
index 000000000000..d51aa0237baf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+#include <core/device.h>
+
+extern const u8 gf100_pte_storage_type_map[256];
+
+bool
+gf100_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags)
+{
+ u8 memtype = (tile_flags & 0x0000ff00) >> 8;
+ return likely((gf100_pte_storage_type_map[memtype] != 0xff));
+}
+
+static void
+gf100_fb_intr(struct nvkm_subdev *subdev)
+{
+ struct gf100_fb_priv *priv = (void *)subdev;
+ u32 intr = nv_rd32(priv, 0x000100);
+ if (intr & 0x08000000) {
+ nv_debug(priv, "PFFB intr\n");
+ intr &= ~0x08000000;
+ }
+ if (intr & 0x00002000) {
+ nv_debug(priv, "PBFB intr\n");
+ intr &= ~0x00002000;
+ }
+}
+
+int
+gf100_fb_init(struct nvkm_object *object)
+{
+ struct gf100_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ if (priv->r100c10_page)
+ nv_wr32(priv, 0x100c10, priv->r100c10 >> 8);
+
+ nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
+ return 0;
+}
+
+void
+gf100_fb_dtor(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct gf100_fb_priv *priv = (void *)object;
+
+ if (priv->r100c10_page) {
+ dma_unmap_page(nv_device_base(device), priv->r100c10, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ __free_page(priv->r100c10_page);
+ }
+
+ nvkm_fb_destroy(&priv->base);
+}
+
+int
+gf100_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct gf100_fb_priv *priv;
+ int ret;
+
+ ret = nvkm_fb_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->r100c10_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (priv->r100c10_page) {
+ priv->r100c10 = dma_map_page(nv_device_base(device),
+ priv->r100c10_page, 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(nv_device_base(device), priv->r100c10))
+ return -EFAULT;
+ }
+
+ nv_subdev(priv)->intr = gf100_fb_intr;
+ return 0;
+}
+
+struct nvkm_oclass *
+gf100_fb_oclass = &(struct nvkm_fb_impl) {
+ .base.handle = NV_SUBDEV(FB, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_fb_ctor,
+ .dtor = gf100_fb_dtor,
+ .init = gf100_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .memtype = gf100_fb_memtype_valid,
+ .ram = &gf100_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
new file mode 100644
index 000000000000..0af4da259471
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gf100.h
@@ -0,0 +1,28 @@
+#ifndef __NVKM_RAM_NVC0_H__
+#define __NVKM_RAM_NVC0_H__
+#include "priv.h"
+#include "nv50.h"
+
+struct gf100_fb_priv {
+ struct nvkm_fb base;
+ struct page *r100c10_page;
+ dma_addr_t r100c10;
+};
+
+int gf100_fb_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void gf100_fb_dtor(struct nvkm_object *);
+int gf100_fb_init(struct nvkm_object *);
+bool gf100_fb_memtype_valid(struct nvkm_fb *, u32);
+
+#define gf100_ram_create(p,e,o,m,d) \
+ gf100_ram_create_((p), (e), (o), (m), sizeof(**d), (void **)d)
+int gf100_ram_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u32, int, void **);
+int gf100_ram_get(struct nvkm_fb *, u64, u32, u32, u32,
+ struct nvkm_mem **);
+void gf100_ram_put(struct nvkm_fb *, struct nvkm_mem **);
+
+int gk104_ram_init(struct nvkm_object*);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c
new file mode 100644
index 000000000000..1c08317665bb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk104.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+struct nvkm_oclass *
+gk104_fb_oclass = &(struct nvkm_fb_impl) {
+ .base.handle = NV_SUBDEV(FB, 0xe0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_fb_ctor,
+ .dtor = gf100_fb_dtor,
+ .init = gf100_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .memtype = gf100_fb_memtype_valid,
+ .ram = &gk104_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c
new file mode 100644
index 000000000000..6762847c05e8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gk20a.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "gf100.h"
+
+struct gk20a_fb_priv {
+ struct nvkm_fb base;
+};
+
+static int
+gk20a_fb_init(struct nvkm_object *object)
+{
+ struct gk20a_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x100c80, 0x00000001, 0x00000000); /* 128KiB lpg */
+ return 0;
+}
+
+static int
+gk20a_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk20a_fb_priv *priv;
+ int ret;
+
+ ret = nvkm_fb_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+gk20a_fb_oclass = &(struct nvkm_fb_impl) {
+ .base.handle = NV_SUBDEV(FB, 0xea),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = gk20a_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .memtype = gf100_fb_memtype_valid,
+ .ram = &gk20a_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
new file mode 100644
index 000000000000..843f9356b360
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gm107.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+struct nvkm_oclass *
+gm107_fb_oclass = &(struct nvkm_fb_impl) {
+ .base.handle = NV_SUBDEV(FB, 0x07),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_fb_ctor,
+ .dtor = gf100_fb_dtor,
+ .init = gf100_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .memtype = gf100_fb_memtype_valid,
+ .ram = &gm107_ram_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c
new file mode 100644
index 000000000000..dd9b8a0a3c8e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/gt215.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+gt215_fb_oclass = &(struct nv50_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0xa3),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fb_ctor,
+ .dtor = nv50_fb_dtor,
+ .init = nv50_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv50_fb_memtype_valid,
+ .base.ram = &gt215_ram_oclass,
+ .trap = 0x000d0fff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c
new file mode 100644
index 000000000000..7be4a47ef4ad
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp77.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+mcp77_fb_oclass = &(struct nv50_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0xaa),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fb_ctor,
+ .dtor = nv50_fb_dtor,
+ .init = nv50_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv50_fb_memtype_valid,
+ .base.ram = &mcp77_ram_oclass,
+ .trap = 0x001d07ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c
new file mode 100644
index 000000000000..2d00656faef5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/mcp89.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+mcp89_fb_oclass = &(struct nv50_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0xaf),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fb_ctor,
+ .dtor = nv50_fb_dtor,
+ .init = nv50_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv50_fb_memtype_valid,
+ .base.ram = &mcp77_ram_oclass,
+ .trap = 0x089d1fff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c
new file mode 100644
index 000000000000..c063dec7d03a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+#include "regsnv04.h"
+
+bool
+nv04_fb_memtype_valid(struct nvkm_fb *pfb, u32 tile_flags)
+{
+ if (!(tile_flags & 0xff00))
+ return true;
+
+ return false;
+}
+
+static int
+nv04_fb_init(struct nvkm_object *object)
+{
+ struct nv04_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* This is what the DDX did for NV_ARCH_04, but a mmio-trace shows
+ * nvidia reading PFB_CFG_0, then writing back its original value.
+ * (which was 0x701114 in this case)
+ */
+ nv_wr32(priv, NV04_PFB_CFG0, 0x1114);
+ return 0;
+}
+
+int
+nv04_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_fb_impl *impl = (void *)oclass;
+ struct nv04_fb_priv *priv;
+ int ret;
+
+ ret = nvkm_fb_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.tile.regions = impl->tile.regions;
+ priv->base.tile.init = impl->tile.init;
+ priv->base.tile.comp = impl->tile.comp;
+ priv->base.tile.fini = impl->tile.fini;
+ priv->base.tile.prog = impl->tile.prog;
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x04),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv04_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv04_ram_oclass,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h
new file mode 100644
index 000000000000..caa0d03aaacc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv04.h
@@ -0,0 +1,53 @@
+#ifndef __NVKM_FB_NV04_H__
+#define __NVKM_FB_NV04_H__
+#include "priv.h"
+
+struct nv04_fb_priv {
+ struct nvkm_fb base;
+};
+
+int nv04_fb_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+struct nv04_fb_impl {
+ struct nvkm_fb_impl base;
+ struct {
+ int regions;
+ void (*init)(struct nvkm_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nvkm_fb_tile *);
+ void (*comp)(struct nvkm_fb *, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *);
+ void (*fini)(struct nvkm_fb *, int i,
+ struct nvkm_fb_tile *);
+ void (*prog)(struct nvkm_fb *, int i,
+ struct nvkm_fb_tile *);
+ } tile;
+};
+
+void nv10_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nvkm_fb_tile *);
+void nv10_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+void nv10_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+void nv20_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nvkm_fb_tile *);
+void nv20_fb_tile_fini(struct nvkm_fb *, int i, struct nvkm_fb_tile *);
+void nv20_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+int nv30_fb_init(struct nvkm_object *);
+void nv30_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nvkm_fb_tile *);
+
+void nv40_fb_tile_comp(struct nvkm_fb *, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *);
+
+int nv41_fb_init(struct nvkm_object *);
+void nv41_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+int nv44_fb_init(struct nvkm_object *);
+void nv44_fb_tile_prog(struct nvkm_fb *, int, struct nvkm_fb_tile *);
+
+void nv46_fb_tile_init(struct nvkm_fb *, int i, u32 addr, u32 size,
+ u32 pitch, u32 flags, struct nvkm_fb_tile *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c
new file mode 100644
index 000000000000..f3530e4a6760
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv10.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+void
+nv10_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+ u32 flags, struct nvkm_fb_tile *tile)
+{
+ tile->addr = 0x80000000 | addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+}
+
+void
+nv10_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+ tile->addr = 0;
+ tile->limit = 0;
+ tile->pitch = 0;
+ tile->zcomp = 0;
+}
+
+void
+nv10_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+ nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
+ nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
+ nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
+ nv_rd32(pfb, 0x100240 + (i * 0x10));
+}
+
+struct nvkm_oclass *
+nv10_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x10),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = _nvkm_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv10_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv10_fb_tile_init,
+ .tile.fini = nv10_fb_tile_fini,
+ .tile.prog = nv10_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c
new file mode 100644
index 000000000000..83bcb73caf0a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv1a.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv1a_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x1a),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = _nvkm_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv1a_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv10_fb_tile_init,
+ .tile.fini = nv10_fb_tile_fini,
+ .tile.prog = nv10_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c
new file mode 100644
index 000000000000..e37084b8d05e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv20.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+void
+nv20_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+ u32 flags, struct nvkm_fb_tile *tile)
+{
+ tile->addr = 0x00000001 | addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+ if (flags & 4) {
+ pfb->tile.comp(pfb, i, size, flags, tile);
+ tile->addr |= 2;
+ }
+}
+
+static void
+nv20_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *tile)
+{
+ u32 tiles = DIV_ROUND_UP(size, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
+ if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+ if (!(flags & 2)) tile->zcomp = 0x00000000; /* Z16 */
+ else tile->zcomp = 0x04000000; /* Z24S8 */
+ tile->zcomp |= tile->tag->offset;
+ tile->zcomp |= 0x80000000; /* enable */
+#ifdef __BIG_ENDIAN
+ tile->zcomp |= 0x08000000;
+#endif
+ }
+}
+
+void
+nv20_fb_tile_fini(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+ tile->addr = 0;
+ tile->limit = 0;
+ tile->pitch = 0;
+ tile->zcomp = 0;
+ nvkm_mm_free(&pfb->tags, &tile->tag);
+}
+
+void
+nv20_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+ nv_wr32(pfb, 0x100244 + (i * 0x10), tile->limit);
+ nv_wr32(pfb, 0x100248 + (i * 0x10), tile->pitch);
+ nv_wr32(pfb, 0x100240 + (i * 0x10), tile->addr);
+ nv_rd32(pfb, 0x100240 + (i * 0x10));
+ nv_wr32(pfb, 0x100300 + (i * 0x04), tile->zcomp);
+}
+
+struct nvkm_oclass *
+nv20_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x20),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = _nvkm_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv20_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv20_fb_tile_init,
+ .tile.comp = nv20_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c
new file mode 100644
index 000000000000..bc9f54f38fba
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv25.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv25_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *tile)
+{
+ u32 tiles = DIV_ROUND_UP(size, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
+ if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+ if (!(flags & 2)) tile->zcomp = 0x00100000; /* Z16 */
+ else tile->zcomp = 0x00200000; /* Z24S8 */
+ tile->zcomp |= tile->tag->offset;
+#ifdef __BIG_ENDIAN
+ tile->zcomp |= 0x01000000;
+#endif
+ }
+}
+
+struct nvkm_oclass *
+nv25_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x25),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = _nvkm_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv20_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv20_fb_tile_init,
+ .tile.comp = nv25_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c
new file mode 100644
index 000000000000..09ebb9477e00
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv30.c
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+
+void
+nv30_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+ u32 flags, struct nvkm_fb_tile *tile)
+{
+ /* for performance, select alternate bank offset for zeta */
+ if (!(flags & 4)) {
+ tile->addr = (0 << 4);
+ } else {
+ if (pfb->tile.comp) /* z compression */
+ pfb->tile.comp(pfb, i, size, flags, tile);
+ tile->addr = (1 << 4);
+ }
+
+ tile->addr |= 0x00000001; /* enable */
+ tile->addr |= addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+}
+
+static void
+nv30_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *tile)
+{
+ u32 tiles = DIV_ROUND_UP(size, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
+ if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+ if (flags & 2) tile->zcomp |= 0x01000000; /* Z16 */
+ else tile->zcomp |= 0x02000000; /* Z24S8 */
+ tile->zcomp |= ((tile->tag->offset ) >> 6);
+ tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 12;
+#ifdef __BIG_ENDIAN
+ tile->zcomp |= 0x10000000;
+#endif
+ }
+}
+
+static int
+calc_bias(struct nv04_fb_priv *priv, int k, int i, int j)
+{
+ struct nvkm_device *device = nv_device(priv);
+ int b = (device->chipset > 0x30 ?
+ nv_rd32(priv, 0x122c + 0x10 * k + 0x4 * j) >> (4 * (i ^ 1)) :
+ 0) & 0xf;
+
+ return 2 * (b & 0x8 ? b - 0x10 : b);
+}
+
+static int
+calc_ref(struct nv04_fb_priv *priv, int l, int k, int i)
+{
+ int j, x = 0;
+
+ for (j = 0; j < 4; j++) {
+ int m = (l >> (8 * i) & 0xff) + calc_bias(priv, k, i, j);
+
+ x |= (0x80 | clamp(m, 0, 0x1f)) << (8 * j);
+ }
+
+ return x;
+}
+
+int
+nv30_fb_init(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nv04_fb_priv *priv = (void *)object;
+ int ret, i, j;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* Init the memory timing regs at 0x10037c/0x1003ac */
+ if (device->chipset == 0x30 ||
+ device->chipset == 0x31 ||
+ device->chipset == 0x35) {
+ /* Related to ROP count */
+ int n = (device->chipset == 0x31 ? 2 : 4);
+ int l = nv_rd32(priv, 0x1003d0);
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < 3; j++)
+ nv_wr32(priv, 0x10037c + 0xc * i + 0x4 * j,
+ calc_ref(priv, l, 0, j));
+
+ for (j = 0; j < 2; j++)
+ nv_wr32(priv, 0x1003ac + 0x8 * i + 0x4 * j,
+ calc_ref(priv, l, 1, j));
+ }
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nv30_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x30),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv30_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv20_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv30_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c
new file mode 100644
index 000000000000..c01dc1839ea4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv35.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv35_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *tile)
+{
+ u32 tiles = DIV_ROUND_UP(size, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
+ if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+ if (flags & 2) tile->zcomp |= 0x04000000; /* Z16 */
+ else tile->zcomp |= 0x08000000; /* Z24S8 */
+ tile->zcomp |= ((tile->tag->offset ) >> 6);
+ tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 13;
+#ifdef __BIG_ENDIAN
+ tile->zcomp |= 0x40000000;
+#endif
+ }
+}
+
+struct nvkm_oclass *
+nv35_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x35),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv30_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv20_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv35_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c
new file mode 100644
index 000000000000..cad75a1cef22
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv36.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv36_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *tile)
+{
+ u32 tiles = DIV_ROUND_UP(size, 0x40);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x40);
+ if (!nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+ if (flags & 2) tile->zcomp |= 0x10000000; /* Z16 */
+ else tile->zcomp |= 0x20000000; /* Z24S8 */
+ tile->zcomp |= ((tile->tag->offset ) >> 6);
+ tile->zcomp |= ((tile->tag->offset + tags - 1) >> 6) << 14;
+#ifdef __BIG_ENDIAN
+ tile->zcomp |= 0x80000000;
+#endif
+ }
+}
+
+struct nvkm_oclass *
+nv36_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x36),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv30_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv20_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv36_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c
new file mode 100644
index 000000000000..dbe5c1910c2c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.c
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+void
+nv40_fb_tile_comp(struct nvkm_fb *pfb, int i, u32 size, u32 flags,
+ struct nvkm_fb_tile *tile)
+{
+ u32 tiles = DIV_ROUND_UP(size, 0x80);
+ u32 tags = round_up(tiles / pfb->ram->parts, 0x100);
+ if ( (flags & 2) &&
+ !nvkm_mm_head(&pfb->tags, 0, 1, tags, tags, 1, &tile->tag)) {
+ tile->zcomp = 0x28000000; /* Z24S8_SPLIT_GRAD */
+ tile->zcomp |= ((tile->tag->offset ) >> 8);
+ tile->zcomp |= ((tile->tag->offset + tags - 1) >> 8) << 13;
+#ifdef __BIG_ENDIAN
+ tile->zcomp |= 0x40000000;
+#endif
+ }
+}
+
+static int
+nv40_fb_init(struct nvkm_object *object)
+{
+ struct nv04_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x10033c, 0x00008000, 0x00000000);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv40_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x40),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv40_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv40_ram_oclass,
+ .tile.regions = 8,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv40_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv20_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h
new file mode 100644
index 000000000000..602182661820
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv40.h
@@ -0,0 +1,14 @@
+#ifndef __NVKM_FB_NV40_H__
+#define __NVKM_FB_NV40_H__
+#include "priv.h"
+
+struct nv40_ram {
+ struct nvkm_ram base;
+ u32 ctrl;
+ u32 coef;
+};
+
+int nv40_ram_calc(struct nvkm_fb *, u32);
+int nv40_ram_prog(struct nvkm_fb *);
+void nv40_ram_tidy(struct nvkm_fb *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c
new file mode 100644
index 000000000000..d9e1a40a2955
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv41.c
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+void
+nv41_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+ nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
+ nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
+ nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
+ nv_rd32(pfb, 0x100600 + (i * 0x10));
+ nv_wr32(pfb, 0x100700 + (i * 0x04), tile->zcomp);
+}
+
+int
+nv41_fb_init(struct nvkm_object *object)
+{
+ struct nv04_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x100800, 0x00000001);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv41_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x41),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv41_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv41_ram_oclass,
+ .tile.regions = 12,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv40_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv41_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c
new file mode 100644
index 000000000000..20b97c83c4af
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv44.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+static void
+nv44_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+ u32 flags, struct nvkm_fb_tile *tile)
+{
+ tile->addr = 0x00000001; /* mode = vram */
+ tile->addr |= addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+}
+
+void
+nv44_fb_tile_prog(struct nvkm_fb *pfb, int i, struct nvkm_fb_tile *tile)
+{
+ nv_wr32(pfb, 0x100604 + (i * 0x10), tile->limit);
+ nv_wr32(pfb, 0x100608 + (i * 0x10), tile->pitch);
+ nv_wr32(pfb, 0x100600 + (i * 0x10), tile->addr);
+ nv_rd32(pfb, 0x100600 + (i * 0x10));
+}
+
+int
+nv44_fb_init(struct nvkm_object *object)
+{
+ struct nv04_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x100850, 0x80000000);
+ nv_wr32(priv, 0x100800, 0x00000001);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv44_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x44),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv44_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv44_ram_oclass,
+ .tile.regions = 12,
+ .tile.init = nv44_fb_tile_init,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv44_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c
new file mode 100644
index 000000000000..5bfac38cdf24
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv46.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+void
+nv46_fb_tile_init(struct nvkm_fb *pfb, int i, u32 addr, u32 size, u32 pitch,
+ u32 flags, struct nvkm_fb_tile *tile)
+{
+ /* for performance, select alternate bank offset for zeta */
+ if (!(flags & 4)) tile->addr = (0 << 3);
+ else tile->addr = (1 << 3);
+
+ tile->addr |= 0x00000001; /* mode = vram */
+ tile->addr |= addr;
+ tile->limit = max(1u, addr + size) - 1;
+ tile->pitch = pitch;
+}
+
+struct nvkm_oclass *
+nv46_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x46),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv44_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv44_ram_oclass,
+ .tile.regions = 15,
+ .tile.init = nv46_fb_tile_init,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv44_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c
new file mode 100644
index 000000000000..d3b3988d1d49
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv47.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv47_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x47),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv41_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv41_ram_oclass,
+ .tile.regions = 15,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv40_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv41_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c
new file mode 100644
index 000000000000..236e36c5054e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv49.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv49_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x49),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv41_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv49_ram_oclass,
+ .tile.regions = 15,
+ .tile.init = nv30_fb_tile_init,
+ .tile.comp = nv40_fb_tile_comp,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv41_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c
new file mode 100644
index 000000000000..1352b6a73fb0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv4e.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv4e_fb_oclass = &(struct nv04_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x4e),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_fb_ctor,
+ .dtor = _nvkm_fb_dtor,
+ .init = nv44_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv04_fb_memtype_valid,
+ .base.ram = &nv4e_ram_oclass,
+ .tile.regions = 12,
+ .tile.init = nv46_fb_tile_init,
+ .tile.fini = nv20_fb_tile_fini,
+ .tile.prog = nv44_fb_tile_prog,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
new file mode 100644
index 000000000000..0480ce52aa06
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#include <core/client.h>
+#include <core/device.h>
+#include <core/engctx.h>
+#include <core/enum.h>
+
+int
+nv50_fb_memtype[0x80] = {
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 0, 0, 0, 0, 2, 2, 2, 2, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 2, 2, 2, 2, 2, 2, 2, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 2, 2, 2, 2,
+ 1, 0, 2, 0, 1, 0, 2, 0, 1, 1, 2, 2, 1, 1, 0, 0
+};
+
+bool
+nv50_fb_memtype_valid(struct nvkm_fb *pfb, u32 memtype)
+{
+ return nv50_fb_memtype[(memtype & 0xff00) >> 8] != 0;
+}
+
+static const struct nvkm_enum vm_dispatch_subclients[] = {
+ { 0x00000000, "GRCTX", NULL },
+ { 0x00000001, "NOTIFY", NULL },
+ { 0x00000002, "QUERY", NULL },
+ { 0x00000003, "COND", NULL },
+ { 0x00000004, "M2M_IN", NULL },
+ { 0x00000005, "M2M_OUT", NULL },
+ { 0x00000006, "M2M_NOTIFY", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_ccache_subclients[] = {
+ { 0x00000000, "CB", NULL },
+ { 0x00000001, "TIC", NULL },
+ { 0x00000002, "TSC", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_prop_subclients[] = {
+ { 0x00000000, "RT0", NULL },
+ { 0x00000001, "RT1", NULL },
+ { 0x00000002, "RT2", NULL },
+ { 0x00000003, "RT3", NULL },
+ { 0x00000004, "RT4", NULL },
+ { 0x00000005, "RT5", NULL },
+ { 0x00000006, "RT6", NULL },
+ { 0x00000007, "RT7", NULL },
+ { 0x00000008, "ZETA", NULL },
+ { 0x00000009, "LOCAL", NULL },
+ { 0x0000000a, "GLOBAL", NULL },
+ { 0x0000000b, "STACK", NULL },
+ { 0x0000000c, "DST2D", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_pfifo_subclients[] = {
+ { 0x00000000, "PUSHBUF", NULL },
+ { 0x00000001, "SEMAPHORE", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_bar_subclients[] = {
+ { 0x00000000, "FB", NULL },
+ { 0x00000001, "IN", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_client[] = {
+ { 0x00000000, "STRMOUT", NULL },
+ { 0x00000003, "DISPATCH", vm_dispatch_subclients },
+ { 0x00000004, "PFIFO_WRITE", NULL },
+ { 0x00000005, "CCACHE", vm_ccache_subclients },
+ { 0x00000006, "PMSPPP", NULL },
+ { 0x00000007, "CLIPID", NULL },
+ { 0x00000008, "PFIFO_READ", NULL },
+ { 0x00000009, "VFETCH", NULL },
+ { 0x0000000a, "TEXTURE", NULL },
+ { 0x0000000b, "PROP", vm_prop_subclients },
+ { 0x0000000c, "PVP", NULL },
+ { 0x0000000d, "PBSP", NULL },
+ { 0x0000000e, "PCRYPT", NULL },
+ { 0x0000000f, "PCOUNTER", NULL },
+ { 0x00000011, "PDAEMON", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_engine[] = {
+ { 0x00000000, "PGRAPH", NULL, NVDEV_ENGINE_GR },
+ { 0x00000001, "PVP", NULL, NVDEV_ENGINE_VP },
+ { 0x00000004, "PEEPHOLE", NULL },
+ { 0x00000005, "PFIFO", vm_pfifo_subclients, NVDEV_ENGINE_FIFO },
+ { 0x00000006, "BAR", vm_bar_subclients },
+ { 0x00000008, "PMSPPP", NULL, NVDEV_ENGINE_MSPPP },
+ { 0x00000008, "PMPEG", NULL, NVDEV_ENGINE_MPEG },
+ { 0x00000009, "PBSP", NULL, NVDEV_ENGINE_BSP },
+ { 0x0000000a, "PCRYPT", NULL, NVDEV_ENGINE_CIPHER },
+ { 0x0000000b, "PCOUNTER", NULL },
+ { 0x0000000c, "SEMAPHORE_BG", NULL },
+ { 0x0000000d, "PCE0", NULL, NVDEV_ENGINE_CE0 },
+ { 0x0000000e, "PDAEMON", NULL },
+ {}
+};
+
+static const struct nvkm_enum vm_fault[] = {
+ { 0x00000000, "PT_NOT_PRESENT", NULL },
+ { 0x00000001, "PT_TOO_SHORT", NULL },
+ { 0x00000002, "PAGE_NOT_PRESENT", NULL },
+ { 0x00000003, "PAGE_SYSTEM_ONLY", NULL },
+ { 0x00000004, "PAGE_READ_ONLY", NULL },
+ { 0x00000006, "NULL_DMAOBJ", NULL },
+ { 0x00000007, "WRONG_MEMTYPE", NULL },
+ { 0x0000000b, "VRAM_LIMIT", NULL },
+ { 0x0000000f, "DMAOBJ_LIMIT", NULL },
+ {}
+};
+
+static void
+nv50_fb_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_device *device = nv_device(subdev);
+ struct nvkm_engine *engine;
+ struct nv50_fb_priv *priv = (void *)subdev;
+ const struct nvkm_enum *en, *cl;
+ struct nvkm_object *engctx = NULL;
+ u32 trap[6], idx, chan;
+ u8 st0, st1, st2, st3;
+ int i;
+
+ idx = nv_rd32(priv, 0x100c90);
+ if (!(idx & 0x80000000))
+ return;
+ idx &= 0x00ffffff;
+
+ for (i = 0; i < 6; i++) {
+ nv_wr32(priv, 0x100c90, idx | i << 24);
+ trap[i] = nv_rd32(priv, 0x100c94);
+ }
+ nv_wr32(priv, 0x100c90, idx | 0x80000000);
+
+ /* decode status bits into something more useful */
+ if (device->chipset < 0xa3 ||
+ device->chipset == 0xaa || device->chipset == 0xac) {
+ st0 = (trap[0] & 0x0000000f) >> 0;
+ st1 = (trap[0] & 0x000000f0) >> 4;
+ st2 = (trap[0] & 0x00000f00) >> 8;
+ st3 = (trap[0] & 0x0000f000) >> 12;
+ } else {
+ st0 = (trap[0] & 0x000000ff) >> 0;
+ st1 = (trap[0] & 0x0000ff00) >> 8;
+ st2 = (trap[0] & 0x00ff0000) >> 16;
+ st3 = (trap[0] & 0xff000000) >> 24;
+ }
+ chan = (trap[2] << 16) | trap[1];
+
+ en = nvkm_enum_find(vm_engine, st0);
+
+ if (en && en->data2) {
+ const struct nvkm_enum *orig_en = en;
+ while (en->name && en->value == st0 && en->data2) {
+ engine = nvkm_engine(subdev, en->data2);
+ /*XXX: clean this up */
+ if (!engine && en->data2 == NVDEV_ENGINE_BSP)
+ engine = nvkm_engine(subdev, NVDEV_ENGINE_MSVLD);
+ if (!engine && en->data2 == NVDEV_ENGINE_CIPHER)
+ engine = nvkm_engine(subdev, NVDEV_ENGINE_SEC);
+ if (!engine && en->data2 == NVDEV_ENGINE_VP)
+ engine = nvkm_engine(subdev, NVDEV_ENGINE_MSPDEC);
+ if (engine) {
+ engctx = nvkm_engctx_get(engine, chan);
+ if (engctx)
+ break;
+ }
+ en++;
+ }
+ if (!engctx)
+ en = orig_en;
+ }
+
+ nv_error(priv, "trapped %s at 0x%02x%04x%04x on channel 0x%08x [%s] ",
+ (trap[5] & 0x00000100) ? "read" : "write",
+ trap[5] & 0xff, trap[4] & 0xffff, trap[3] & 0xffff, chan,
+ nvkm_client_name(engctx));
+
+ nvkm_engctx_put(engctx);
+
+ if (en)
+ pr_cont("%s/", en->name);
+ else
+ pr_cont("%02x/", st0);
+
+ cl = nvkm_enum_find(vm_client, st2);
+ if (cl)
+ pr_cont("%s/", cl->name);
+ else
+ pr_cont("%02x/", st2);
+
+ if (cl && cl->data) cl = nvkm_enum_find(cl->data, st3);
+ else if (en && en->data) cl = nvkm_enum_find(en->data, st3);
+ else cl = NULL;
+ if (cl)
+ pr_cont("%s", cl->name);
+ else
+ pr_cont("%02x", st3);
+
+ pr_cont(" reason: ");
+ en = nvkm_enum_find(vm_fault, st1);
+ if (en)
+ pr_cont("%s\n", en->name);
+ else
+ pr_cont("0x%08x\n", st1);
+}
+
+int
+nv50_fb_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nv50_fb_priv *priv;
+ int ret;
+
+ ret = nvkm_fb_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->r100c08_page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (priv->r100c08_page) {
+ priv->r100c08 = dma_map_page(nv_device_base(device),
+ priv->r100c08_page, 0, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ if (dma_mapping_error(nv_device_base(device), priv->r100c08))
+ return -EFAULT;
+ } else {
+ nv_warn(priv, "failed 0x100c08 page alloc\n");
+ }
+
+ nv_subdev(priv)->intr = nv50_fb_intr;
+ return 0;
+}
+
+void
+nv50_fb_dtor(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nv50_fb_priv *priv = (void *)object;
+
+ if (priv->r100c08_page) {
+ dma_unmap_page(nv_device_base(device), priv->r100c08, PAGE_SIZE,
+ DMA_BIDIRECTIONAL);
+ __free_page(priv->r100c08_page);
+ }
+
+ nvkm_fb_destroy(&priv->base);
+}
+
+int
+nv50_fb_init(struct nvkm_object *object)
+{
+ struct nv50_fb_impl *impl = (void *)object->oclass;
+ struct nv50_fb_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_fb_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* Not a clue what this is exactly. Without pointing it at a
+ * scratch page, VRAM->GART blits with M2MF (as in DDX DFS)
+ * cause IOMMU "read from address 0" errors (rh#561267)
+ */
+ nv_wr32(priv, 0x100c08, priv->r100c08 >> 8);
+
+ /* This is needed to get meaningful information from 100c90
+ * on traps. No idea what these values mean exactly. */
+ nv_wr32(priv, 0x100c90, impl->trap);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_fb_oclass = &(struct nv50_fb_impl) {
+ .base.base.handle = NV_SUBDEV(FB, 0x50),
+ .base.base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fb_ctor,
+ .dtor = nv50_fb_dtor,
+ .init = nv50_fb_init,
+ .fini = _nvkm_fb_fini,
+ },
+ .base.memtype = nv50_fb_memtype_valid,
+ .base.ram = &nv50_ram_oclass,
+ .trap = 0x000707ff,
+}.base.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
new file mode 100644
index 000000000000..f3cde3f1f511
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/nv50.h
@@ -0,0 +1,31 @@
+#ifndef __NVKM_FB_NV50_H__
+#define __NVKM_FB_NV50_H__
+#include "priv.h"
+
+struct nv50_fb_priv {
+ struct nvkm_fb base;
+ struct page *r100c08_page;
+ dma_addr_t r100c08;
+};
+
+int nv50_fb_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nv50_fb_dtor(struct nvkm_object *);
+int nv50_fb_init(struct nvkm_object *);
+
+struct nv50_fb_impl {
+ struct nvkm_fb_impl base;
+ u32 trap;
+};
+
+#define nv50_ram_create(p,e,o,d) \
+ nv50_ram_create_((p), (e), (o), sizeof(**d), (void **)d)
+int nv50_ram_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+int nv50_ram_get(struct nvkm_fb *, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nvkm_mem **);
+void nv50_ram_put(struct nvkm_fb *, struct nvkm_mem **);
+void __nv50_ram_put(struct nvkm_fb *, struct nvkm_mem *);
+extern int nv50_fb_memtype[0x80];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
new file mode 100644
index 000000000000..d82da02daa1f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/priv.h
@@ -0,0 +1,74 @@
+#ifndef __NVKM_FB_PRIV_H__
+#define __NVKM_FB_PRIV_H__
+#include <subdev/fb.h>
+struct nvkm_bios;
+
+#define nvkm_ram_create(p,e,o,d) \
+ nvkm_object_create_((p), (e), (o), 0, sizeof(**d), (void **)d)
+#define nvkm_ram_destroy(p) \
+ nvkm_object_destroy(&(p)->base)
+#define nvkm_ram_init(p) \
+ nvkm_object_init(&(p)->base)
+#define nvkm_ram_fini(p,s) \
+ nvkm_object_fini(&(p)->base, (s))
+
+#define nvkm_ram_create_(p,e,o,s,d) \
+ nvkm_object_create_((p), (e), (o), 0, (s), (void **)d)
+#define _nvkm_ram_dtor nvkm_object_destroy
+#define _nvkm_ram_init nvkm_object_init
+#define _nvkm_ram_fini nvkm_object_fini
+
+extern struct nvkm_oclass nv04_ram_oclass;
+extern struct nvkm_oclass nv10_ram_oclass;
+extern struct nvkm_oclass nv1a_ram_oclass;
+extern struct nvkm_oclass nv20_ram_oclass;
+extern struct nvkm_oclass nv40_ram_oclass;
+extern struct nvkm_oclass nv41_ram_oclass;
+extern struct nvkm_oclass nv44_ram_oclass;
+extern struct nvkm_oclass nv49_ram_oclass;
+extern struct nvkm_oclass nv4e_ram_oclass;
+extern struct nvkm_oclass nv50_ram_oclass;
+extern struct nvkm_oclass gt215_ram_oclass;
+extern struct nvkm_oclass mcp77_ram_oclass;
+extern struct nvkm_oclass gf100_ram_oclass;
+extern struct nvkm_oclass gk104_ram_oclass;
+extern struct nvkm_oclass gk20a_ram_oclass;
+extern struct nvkm_oclass gm107_ram_oclass;
+
+int nvkm_sddr2_calc(struct nvkm_ram *ram);
+int nvkm_sddr3_calc(struct nvkm_ram *ram);
+int nvkm_gddr3_calc(struct nvkm_ram *ram);
+int nvkm_gddr5_calc(struct nvkm_ram *ram, bool nuts);
+
+#define nvkm_fb_create(p,e,c,d) \
+ nvkm_fb_create_((p), (e), (c), sizeof(**d), (void **)d)
+#define nvkm_fb_destroy(p) ({ \
+ struct nvkm_fb *pfb = (p); \
+ _nvkm_fb_dtor(nv_object(pfb)); \
+})
+#define nvkm_fb_init(p) ({ \
+ struct nvkm_fb *pfb = (p); \
+ _nvkm_fb_init(nv_object(pfb)); \
+})
+#define nvkm_fb_fini(p,s) ({ \
+ struct nvkm_fb *pfb = (p); \
+ _nvkm_fb_fini(nv_object(pfb), (s)); \
+})
+
+int nvkm_fb_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_fb_dtor(struct nvkm_object *);
+int _nvkm_fb_init(struct nvkm_object *);
+int _nvkm_fb_fini(struct nvkm_object *, bool);
+
+struct nvkm_fb_impl {
+ struct nvkm_oclass base;
+ struct nvkm_oclass *ram;
+ bool (*memtype)(struct nvkm_fb *, u32);
+};
+
+bool nv04_fb_memtype_valid(struct nvkm_fb *, u32 memtype);
+bool nv50_fb_memtype_valid(struct nvkm_fb *, u32 memtype);
+
+int nvkm_fb_bios_memtype(struct nvkm_bios *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h
new file mode 100644
index 000000000000..f343682b1387
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramfuc.h
@@ -0,0 +1,180 @@
+#ifndef __NVKM_FBRAM_FUC_H__
+#define __NVKM_FBRAM_FUC_H__
+#include <subdev/pmu.h>
+
+struct ramfuc {
+ struct nvkm_memx *memx;
+ struct nvkm_fb *pfb;
+ int sequence;
+};
+
+struct ramfuc_reg {
+ int sequence;
+ bool force;
+ u32 addr;
+ u32 stride; /* in bytes */
+ u32 mask;
+ u32 data;
+};
+
+static inline struct ramfuc_reg
+ramfuc_stride(u32 addr, u32 stride, u32 mask)
+{
+ return (struct ramfuc_reg) {
+ .sequence = 0,
+ .addr = addr,
+ .stride = stride,
+ .mask = mask,
+ .data = 0xdeadbeef,
+ };
+}
+
+static inline struct ramfuc_reg
+ramfuc_reg2(u32 addr1, u32 addr2)
+{
+ return (struct ramfuc_reg) {
+ .sequence = 0,
+ .addr = addr1,
+ .stride = addr2 - addr1,
+ .mask = 0x3,
+ .data = 0xdeadbeef,
+ };
+}
+
+static noinline struct ramfuc_reg
+ramfuc_reg(u32 addr)
+{
+ return (struct ramfuc_reg) {
+ .sequence = 0,
+ .addr = addr,
+ .stride = 0,
+ .mask = 0x1,
+ .data = 0xdeadbeef,
+ };
+}
+
+static inline int
+ramfuc_init(struct ramfuc *ram, struct nvkm_fb *pfb)
+{
+ struct nvkm_pmu *pmu = nvkm_pmu(pfb);
+ int ret;
+
+ ret = nvkm_memx_init(pmu, &ram->memx);
+ if (ret)
+ return ret;
+
+ ram->sequence++;
+ ram->pfb = pfb;
+ return 0;
+}
+
+static inline int
+ramfuc_exec(struct ramfuc *ram, bool exec)
+{
+ int ret = 0;
+ if (ram->pfb) {
+ ret = nvkm_memx_fini(&ram->memx, exec);
+ ram->pfb = NULL;
+ }
+ return ret;
+}
+
+static inline u32
+ramfuc_rd32(struct ramfuc *ram, struct ramfuc_reg *reg)
+{
+ if (reg->sequence != ram->sequence)
+ reg->data = nv_rd32(ram->pfb, reg->addr);
+ return reg->data;
+}
+
+static inline void
+ramfuc_wr32(struct ramfuc *ram, struct ramfuc_reg *reg, u32 data)
+{
+ unsigned int mask, off = 0;
+
+ reg->sequence = ram->sequence;
+ reg->data = data;
+
+ for (mask = reg->mask; mask > 0; mask = (mask & ~1) >> 1) {
+ if (mask & 1)
+ nvkm_memx_wr32(ram->memx, reg->addr+off, reg->data);
+ off += reg->stride;
+ }
+}
+
+static inline void
+ramfuc_nuke(struct ramfuc *ram, struct ramfuc_reg *reg)
+{
+ reg->force = true;
+}
+
+static inline u32
+ramfuc_mask(struct ramfuc *ram, struct ramfuc_reg *reg, u32 mask, u32 data)
+{
+ u32 temp = ramfuc_rd32(ram, reg);
+ if (temp != ((temp & ~mask) | data) || reg->force) {
+ ramfuc_wr32(ram, reg, (temp & ~mask) | data);
+ reg->force = false;
+ }
+ return temp;
+}
+
+static inline void
+ramfuc_wait(struct ramfuc *ram, u32 addr, u32 mask, u32 data, u32 nsec)
+{
+ nvkm_memx_wait(ram->memx, addr, mask, data, nsec);
+}
+
+static inline void
+ramfuc_nsec(struct ramfuc *ram, u32 nsec)
+{
+ nvkm_memx_nsec(ram->memx, nsec);
+}
+
+static inline void
+ramfuc_wait_vblank(struct ramfuc *ram)
+{
+ nvkm_memx_wait_vblank(ram->memx);
+}
+
+static inline void
+ramfuc_train(struct ramfuc *ram)
+{
+ nvkm_memx_train(ram->memx);
+}
+
+static inline int
+ramfuc_train_result(struct nvkm_fb *pfb, u32 *result, u32 rsize)
+{
+ struct nvkm_pmu *pmu = nvkm_pmu(pfb);
+
+ return nvkm_memx_train_result(pmu, result, rsize);
+}
+
+static inline void
+ramfuc_block(struct ramfuc *ram)
+{
+ nvkm_memx_block(ram->memx);
+}
+
+static inline void
+ramfuc_unblock(struct ramfuc *ram)
+{
+ nvkm_memx_unblock(ram->memx);
+}
+
+#define ram_init(s,p) ramfuc_init(&(s)->base, (p))
+#define ram_exec(s,e) ramfuc_exec(&(s)->base, (e))
+#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r) ramfuc_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d) ramfuc_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r) ramfuc_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d) ramfuc_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_wait(s,r,m,d,n) ramfuc_wait(&(s)->base, (r), (m), (d), (n))
+#define ram_nsec(s,n) ramfuc_nsec(&(s)->base, (n))
+#define ram_wait_vblank(s) ramfuc_wait_vblank(&(s)->base)
+#define ram_train(s) ramfuc_train(&(s)->base)
+#define ram_train_result(s,r,l) ramfuc_train_result((s), (r), (l))
+#define ram_block(s) ramfuc_block(&(s)->base)
+#define ram_unblock(s) ramfuc_unblock(&(s)->base)
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
new file mode 100644
index 000000000000..de9f39569943
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgf100.c
@@ -0,0 +1,731 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+#include "ramfuc.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk.h>
+#include <subdev/clk/pll.h>
+#include <subdev/ltc.h>
+
+struct gf100_ramfuc {
+ struct ramfuc base;
+
+ struct ramfuc_reg r_0x10fe20;
+ struct ramfuc_reg r_0x10fe24;
+ struct ramfuc_reg r_0x137320;
+ struct ramfuc_reg r_0x137330;
+
+ struct ramfuc_reg r_0x132000;
+ struct ramfuc_reg r_0x132004;
+ struct ramfuc_reg r_0x132100;
+
+ struct ramfuc_reg r_0x137390;
+
+ struct ramfuc_reg r_0x10f290;
+ struct ramfuc_reg r_0x10f294;
+ struct ramfuc_reg r_0x10f298;
+ struct ramfuc_reg r_0x10f29c;
+ struct ramfuc_reg r_0x10f2a0;
+
+ struct ramfuc_reg r_0x10f300;
+ struct ramfuc_reg r_0x10f338;
+ struct ramfuc_reg r_0x10f340;
+ struct ramfuc_reg r_0x10f344;
+ struct ramfuc_reg r_0x10f348;
+
+ struct ramfuc_reg r_0x10f910;
+ struct ramfuc_reg r_0x10f914;
+
+ struct ramfuc_reg r_0x100b0c;
+ struct ramfuc_reg r_0x10f050;
+ struct ramfuc_reg r_0x10f090;
+ struct ramfuc_reg r_0x10f200;
+ struct ramfuc_reg r_0x10f210;
+ struct ramfuc_reg r_0x10f310;
+ struct ramfuc_reg r_0x10f314;
+ struct ramfuc_reg r_0x10f610;
+ struct ramfuc_reg r_0x10f614;
+ struct ramfuc_reg r_0x10f800;
+ struct ramfuc_reg r_0x10f808;
+ struct ramfuc_reg r_0x10f824;
+ struct ramfuc_reg r_0x10f830;
+ struct ramfuc_reg r_0x10f988;
+ struct ramfuc_reg r_0x10f98c;
+ struct ramfuc_reg r_0x10f990;
+ struct ramfuc_reg r_0x10f998;
+ struct ramfuc_reg r_0x10f9b0;
+ struct ramfuc_reg r_0x10f9b4;
+ struct ramfuc_reg r_0x10fb04;
+ struct ramfuc_reg r_0x10fb08;
+ struct ramfuc_reg r_0x137300;
+ struct ramfuc_reg r_0x137310;
+ struct ramfuc_reg r_0x137360;
+ struct ramfuc_reg r_0x1373ec;
+ struct ramfuc_reg r_0x1373f0;
+ struct ramfuc_reg r_0x1373f8;
+
+ struct ramfuc_reg r_0x61c140;
+ struct ramfuc_reg r_0x611200;
+
+ struct ramfuc_reg r_0x13d8f4;
+};
+
+struct gf100_ram {
+ struct nvkm_ram base;
+ struct gf100_ramfuc fuc;
+ struct nvbios_pll refpll;
+ struct nvbios_pll mempll;
+};
+
+static void
+gf100_ram_train(struct gf100_ramfuc *fuc, u32 magic)
+{
+ struct gf100_ram *ram = container_of(fuc, typeof(*ram), fuc);
+ struct nvkm_fb *pfb = nvkm_fb(ram);
+ u32 part = nv_rd32(pfb, 0x022438), i;
+ u32 mask = nv_rd32(pfb, 0x022554);
+ u32 addr = 0x110974;
+
+ ram_wr32(fuc, 0x10f910, magic);
+ ram_wr32(fuc, 0x10f914, magic);
+
+ for (i = 0; (magic & 0x80000000) && i < part; addr += 0x1000, i++) {
+ if (mask & (1 << i))
+ continue;
+ ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
+ }
+}
+
+static int
+gf100_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+ struct nvkm_clk *clk = nvkm_clk(pfb);
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct gf100_ram *ram = (void *)pfb->ram;
+ struct gf100_ramfuc *fuc = &ram->fuc;
+ struct nvbios_ramcfg cfg;
+ u8 ver, cnt, len, strap;
+ struct {
+ u32 data;
+ u8 size;
+ } rammap, ramcfg, timing;
+ int ref, div, out;
+ int from, mode;
+ int N1, M1, P;
+ int ret;
+
+ /* lookup memory config data relevant to the target frequency */
+ rammap.data = nvbios_rammapEm(bios, freq / 1000, &ver, &rammap.size,
+ &cnt, &ramcfg.size, &cfg);
+ if (!rammap.data || ver != 0x10 || rammap.size < 0x0e) {
+ nv_error(pfb, "invalid/missing rammap entry\n");
+ return -EINVAL;
+ }
+
+ /* locate specific data set for the attached memory */
+ strap = nvbios_ramcfg_index(nv_subdev(pfb));
+ if (strap >= cnt) {
+ nv_error(pfb, "invalid ramcfg strap\n");
+ return -EINVAL;
+ }
+
+ ramcfg.data = rammap.data + rammap.size + (strap * ramcfg.size);
+ if (!ramcfg.data || ver != 0x10 || ramcfg.size < 0x0e) {
+ nv_error(pfb, "invalid/missing ramcfg entry\n");
+ return -EINVAL;
+ }
+
+ /* lookup memory timings, if bios says they're present */
+ strap = nv_ro08(bios, ramcfg.data + 0x01);
+ if (strap != 0xff) {
+ timing.data = nvbios_timingEe(bios, strap, &ver, &timing.size,
+ &cnt, &len);
+ if (!timing.data || ver != 0x10 || timing.size < 0x19) {
+ nv_error(pfb, "invalid/missing timing entry\n");
+ return -EINVAL;
+ }
+ } else {
+ timing.data = 0;
+ }
+
+ ret = ram_init(fuc, pfb);
+ if (ret)
+ return ret;
+
+ /* determine current mclk configuration */
+ from = !!(ram_rd32(fuc, 0x1373f0) & 0x00000002); /*XXX: ok? */
+
+ /* determine target mclk configuration */
+ if (!(ram_rd32(fuc, 0x137300) & 0x00000100))
+ ref = clk->read(clk, nv_clk_src_sppll0);
+ else
+ ref = clk->read(clk, nv_clk_src_sppll1);
+ div = max(min((ref * 2) / freq, (u32)65), (u32)2) - 2;
+ out = (ref * 2) / (div + 2);
+ mode = freq != out;
+
+ ram_mask(fuc, 0x137360, 0x00000002, 0x00000000);
+
+ if ((ram_rd32(fuc, 0x132000) & 0x00000002) || 0 /*XXX*/) {
+ ram_nuke(fuc, 0x132000);
+ ram_mask(fuc, 0x132000, 0x00000002, 0x00000002);
+ ram_mask(fuc, 0x132000, 0x00000002, 0x00000000);
+ }
+
+ if (mode == 1) {
+ ram_nuke(fuc, 0x10fe20);
+ ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000002);
+ ram_mask(fuc, 0x10fe20, 0x00000002, 0x00000000);
+ }
+
+// 0x00020034 // 0x0000000a
+ ram_wr32(fuc, 0x132100, 0x00000001);
+
+ if (mode == 1 && from == 0) {
+ /* calculate refpll */
+ ret = gt215_pll_calc(nv_subdev(pfb), &ram->refpll,
+ ram->mempll.refclk, &N1, NULL, &M1, &P);
+ if (ret <= 0) {
+ nv_error(pfb, "unable to calc refpll\n");
+ return ret ? ret : -ERANGE;
+ }
+
+ ram_wr32(fuc, 0x10fe20, 0x20010000);
+ ram_wr32(fuc, 0x137320, 0x00000003);
+ ram_wr32(fuc, 0x137330, 0x81200006);
+ ram_wr32(fuc, 0x10fe24, (P << 16) | (N1 << 8) | M1);
+ ram_wr32(fuc, 0x10fe20, 0x20010001);
+ ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+
+ /* calculate mempll */
+ ret = gt215_pll_calc(nv_subdev(pfb), &ram->mempll, freq,
+ &N1, NULL, &M1, &P);
+ if (ret <= 0) {
+ nv_error(pfb, "unable to calc refpll\n");
+ return ret ? ret : -ERANGE;
+ }
+
+ ram_wr32(fuc, 0x10fe20, 0x20010005);
+ ram_wr32(fuc, 0x132004, (P << 16) | (N1 << 8) | M1);
+ ram_wr32(fuc, 0x132000, 0x18010101);
+ ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
+ } else
+ if (mode == 0) {
+ ram_wr32(fuc, 0x137300, 0x00000003);
+ }
+
+ if (from == 0) {
+ ram_nuke(fuc, 0x10fb04);
+ ram_mask(fuc, 0x10fb04, 0x0000ffff, 0x00000000);
+ ram_nuke(fuc, 0x10fb08);
+ ram_mask(fuc, 0x10fb08, 0x0000ffff, 0x00000000);
+ ram_wr32(fuc, 0x10f988, 0x2004ff00);
+ ram_wr32(fuc, 0x10f98c, 0x003fc040);
+ ram_wr32(fuc, 0x10f990, 0x20012001);
+ ram_wr32(fuc, 0x10f998, 0x00011a00);
+ ram_wr32(fuc, 0x13d8f4, 0x00000000);
+ } else {
+ ram_wr32(fuc, 0x10f988, 0x20010000);
+ ram_wr32(fuc, 0x10f98c, 0x00000000);
+ ram_wr32(fuc, 0x10f990, 0x20012001);
+ ram_wr32(fuc, 0x10f998, 0x00010a00);
+ }
+
+ if (from == 0) {
+// 0x00020039 // 0x000000ba
+ }
+
+// 0x0002003a // 0x00000002
+ ram_wr32(fuc, 0x100b0c, 0x00080012);
+// 0x00030014 // 0x00000000 // 0x02b5f070
+// 0x00030014 // 0x00010000 // 0x02b5f070
+ ram_wr32(fuc, 0x611200, 0x00003300);
+// 0x00020034 // 0x0000000a
+// 0x00030020 // 0x00000001 // 0x00000000
+
+ ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+ ram_wr32(fuc, 0x10f210, 0x00000000);
+ ram_nsec(fuc, 1000);
+ if (mode == 0)
+ gf100_ram_train(fuc, 0x000c1001);
+ ram_wr32(fuc, 0x10f310, 0x00000001);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f090, 0x00000061);
+ ram_wr32(fuc, 0x10f090, 0xc000007f);
+ ram_nsec(fuc, 1000);
+
+ if (from == 0) {
+ ram_wr32(fuc, 0x10f824, 0x00007fd4);
+ } else {
+ ram_wr32(fuc, 0x1373ec, 0x00020404);
+ }
+
+ if (mode == 0) {
+ ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
+ ram_mask(fuc, 0x10f200, 0x00008000, 0x00008000);
+ ram_wr32(fuc, 0x10f830, 0x41500010);
+ ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+ ram_mask(fuc, 0x132100, 0x00000100, 0x00000100);
+ ram_wr32(fuc, 0x10f050, 0xff000090);
+ ram_wr32(fuc, 0x1373ec, 0x00020f0f);
+ ram_wr32(fuc, 0x1373f0, 0x00000003);
+ ram_wr32(fuc, 0x137310, 0x81201616);
+ ram_wr32(fuc, 0x132100, 0x00000001);
+// 0x00020039 // 0x000000ba
+ ram_wr32(fuc, 0x10f830, 0x00300017);
+ ram_wr32(fuc, 0x1373f0, 0x00000001);
+ ram_wr32(fuc, 0x10f824, 0x00007e77);
+ ram_wr32(fuc, 0x132000, 0x18030001);
+ ram_wr32(fuc, 0x10f090, 0x4000007e);
+ ram_nsec(fuc, 2000);
+ ram_wr32(fuc, 0x10f314, 0x00000001);
+ ram_wr32(fuc, 0x10f210, 0x80000000);
+ ram_wr32(fuc, 0x10f338, 0x00300220);
+ ram_wr32(fuc, 0x10f300, 0x0000011d);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f290, 0x02060505);
+ ram_wr32(fuc, 0x10f294, 0x34208288);
+ ram_wr32(fuc, 0x10f298, 0x44050411);
+ ram_wr32(fuc, 0x10f29c, 0x0000114c);
+ ram_wr32(fuc, 0x10f2a0, 0x42e10069);
+ ram_wr32(fuc, 0x10f614, 0x40044f77);
+ ram_wr32(fuc, 0x10f610, 0x40044f77);
+ ram_wr32(fuc, 0x10f344, 0x00600009);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f348, 0x00700008);
+ ram_wr32(fuc, 0x61c140, 0x19240000);
+ ram_wr32(fuc, 0x10f830, 0x00300017);
+ gf100_ram_train(fuc, 0x80021001);
+ gf100_ram_train(fuc, 0x80081001);
+ ram_wr32(fuc, 0x10f340, 0x00500004);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f830, 0x01300017);
+ ram_wr32(fuc, 0x10f830, 0x00300017);
+// 0x00030020 // 0x00000000 // 0x00000000
+// 0x00020034 // 0x0000000b
+ ram_wr32(fuc, 0x100b0c, 0x00080028);
+ ram_wr32(fuc, 0x611200, 0x00003330);
+ } else {
+ ram_wr32(fuc, 0x10f800, 0x00001800);
+ ram_wr32(fuc, 0x13d8f4, 0x00000000);
+ ram_wr32(fuc, 0x1373ec, 0x00020404);
+ ram_wr32(fuc, 0x1373f0, 0x00000003);
+ ram_wr32(fuc, 0x10f830, 0x40700010);
+ ram_wr32(fuc, 0x10f830, 0x40500010);
+ ram_wr32(fuc, 0x13d8f4, 0x00000000);
+ ram_wr32(fuc, 0x1373f8, 0x00000000);
+ ram_wr32(fuc, 0x132100, 0x00000101);
+ ram_wr32(fuc, 0x137310, 0x89201616);
+ ram_wr32(fuc, 0x10f050, 0xff000090);
+ ram_wr32(fuc, 0x1373ec, 0x00030404);
+ ram_wr32(fuc, 0x1373f0, 0x00000002);
+ // 0x00020039 // 0x00000011
+ ram_wr32(fuc, 0x132100, 0x00000001);
+ ram_wr32(fuc, 0x1373f8, 0x00002000);
+ ram_nsec(fuc, 2000);
+ ram_wr32(fuc, 0x10f808, 0x7aaa0050);
+ ram_wr32(fuc, 0x10f830, 0x00500010);
+ ram_wr32(fuc, 0x10f200, 0x00ce1000);
+ ram_wr32(fuc, 0x10f090, 0x4000007e);
+ ram_nsec(fuc, 2000);
+ ram_wr32(fuc, 0x10f314, 0x00000001);
+ ram_wr32(fuc, 0x10f210, 0x80000000);
+ ram_wr32(fuc, 0x10f338, 0x00300200);
+ ram_wr32(fuc, 0x10f300, 0x0000084d);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f290, 0x0b343825);
+ ram_wr32(fuc, 0x10f294, 0x3483028e);
+ ram_wr32(fuc, 0x10f298, 0x440c0600);
+ ram_wr32(fuc, 0x10f29c, 0x0000214c);
+ ram_wr32(fuc, 0x10f2a0, 0x42e20069);
+ ram_wr32(fuc, 0x10f200, 0x00ce0000);
+ ram_wr32(fuc, 0x10f614, 0x60044e77);
+ ram_wr32(fuc, 0x10f610, 0x60044e77);
+ ram_wr32(fuc, 0x10f340, 0x00500000);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f344, 0x00600228);
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f348, 0x00700000);
+ ram_wr32(fuc, 0x13d8f4, 0x00000000);
+ ram_wr32(fuc, 0x61c140, 0x09a40000);
+
+ gf100_ram_train(fuc, 0x800e1008);
+
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f800, 0x00001804);
+ // 0x00030020 // 0x00000000 // 0x00000000
+ // 0x00020034 // 0x0000000b
+ ram_wr32(fuc, 0x13d8f4, 0x00000000);
+ ram_wr32(fuc, 0x100b0c, 0x00080028);
+ ram_wr32(fuc, 0x611200, 0x00003330);
+ ram_nsec(fuc, 100000);
+ ram_wr32(fuc, 0x10f9b0, 0x05313f41);
+ ram_wr32(fuc, 0x10f9b4, 0x00002f50);
+
+ gf100_ram_train(fuc, 0x010c1001);
+ }
+
+ ram_mask(fuc, 0x10f200, 0x00000800, 0x00000800);
+// 0x00020016 // 0x00000000
+
+ if (mode == 0)
+ ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+
+ return 0;
+}
+
+static int
+gf100_ram_prog(struct nvkm_fb *pfb)
+{
+ struct nvkm_device *device = nv_device(pfb);
+ struct gf100_ram *ram = (void *)pfb->ram;
+ struct gf100_ramfuc *fuc = &ram->fuc;
+ ram_exec(fuc, nvkm_boolopt(device->cfgopt, "NvMemExec", true));
+ return 0;
+}
+
+static void
+gf100_ram_tidy(struct nvkm_fb *pfb)
+{
+ struct gf100_ram *ram = (void *)pfb->ram;
+ struct gf100_ramfuc *fuc = &ram->fuc;
+ ram_exec(fuc, false);
+}
+
+extern const u8 gf100_pte_storage_type_map[256];
+
+void
+gf100_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
+{
+ struct nvkm_ltc *ltc = nvkm_ltc(pfb);
+ struct nvkm_mem *mem = *pmem;
+
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
+
+ mutex_lock(&pfb->base.mutex);
+ if (mem->tag)
+ ltc->tags_free(ltc, &mem->tag);
+ __nv50_ram_put(pfb, mem);
+ mutex_unlock(&pfb->base.mutex);
+
+ kfree(mem);
+}
+
+int
+gf100_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nvkm_mem **pmem)
+{
+ struct nvkm_mm *mm = &pfb->vram;
+ struct nvkm_mm_node *r;
+ struct nvkm_mem *mem;
+ int type = (memtype & 0x0ff);
+ int back = (memtype & 0x800);
+ const bool comp = gf100_pte_storage_type_map[type] != type;
+ int ret;
+
+ size >>= 12;
+ align >>= 12;
+ ncmin >>= 12;
+ if (!ncmin)
+ ncmin = size;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&mem->regions);
+ mem->size = size;
+
+ mutex_lock(&pfb->base.mutex);
+ if (comp) {
+ struct nvkm_ltc *ltc = nvkm_ltc(pfb);
+
+ /* compression only works with lpages */
+ if (align == (1 << (17 - 12))) {
+ int n = size >> 5;
+ ltc->tags_alloc(ltc, n, &mem->tag);
+ }
+
+ if (unlikely(!mem->tag))
+ type = gf100_pte_storage_type_map[type];
+ }
+ mem->memtype = type;
+
+ do {
+ if (back)
+ ret = nvkm_mm_tail(mm, 0, 1, size, ncmin, align, &r);
+ else
+ ret = nvkm_mm_head(mm, 0, 1, size, ncmin, align, &r);
+ if (ret) {
+ mutex_unlock(&pfb->base.mutex);
+ pfb->ram->put(pfb, &mem);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &mem->regions);
+ size -= r->length;
+ } while (size);
+ mutex_unlock(&pfb->base.mutex);
+
+ r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry);
+ mem->offset = (u64)r->offset << 12;
+ *pmem = mem;
+ return 0;
+}
+
+int
+gf100_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u32 maskaddr, int size,
+ void **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nvkm_ram *ram;
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ u32 parts = nv_rd32(pfb, 0x022438);
+ u32 pmask = nv_rd32(pfb, maskaddr);
+ u32 bsize = nv_rd32(pfb, 0x10f20c);
+ u32 offset, length;
+ bool uniform = true;
+ int ret, part;
+
+ ret = nvkm_ram_create_(parent, engine, oclass, size, pobject);
+ ram = *pobject;
+ if (ret)
+ return ret;
+
+ nv_debug(pfb, "0x100800: 0x%08x\n", nv_rd32(pfb, 0x100800));
+ nv_debug(pfb, "parts 0x%08x mask 0x%08x\n", parts, pmask);
+
+ ram->type = nvkm_fb_bios_memtype(bios);
+ ram->ranks = (nv_rd32(pfb, 0x10f200) & 0x00000004) ? 2 : 1;
+
+ /* read amount of vram attached to each memory controller */
+ for (part = 0; part < parts; part++) {
+ if (!(pmask & (1 << part))) {
+ u32 psize = nv_rd32(pfb, 0x11020c + (part * 0x1000));
+ if (psize != bsize) {
+ if (psize < bsize)
+ bsize = psize;
+ uniform = false;
+ }
+
+ nv_debug(pfb, "%d: mem_amount 0x%08x\n", part, psize);
+ ram->size += (u64)psize << 20;
+ }
+ }
+
+ /* if all controllers have the same amount attached, there's no holes */
+ if (uniform) {
+ offset = rsvd_head;
+ length = (ram->size >> 12) - rsvd_head - rsvd_tail;
+ ret = nvkm_mm_init(&pfb->vram, offset, length, 1);
+ } else {
+ /* otherwise, address lowest common amount from 0GiB */
+ ret = nvkm_mm_init(&pfb->vram, rsvd_head,
+ (bsize << 8) * parts - rsvd_head, 1);
+ if (ret)
+ return ret;
+
+ /* and the rest starting from (8GiB + common_size) */
+ offset = (0x0200000000ULL >> 12) + (bsize << 8);
+ length = (ram->size >> 12) - ((bsize * parts) << 8) - rsvd_tail;
+
+ ret = nvkm_mm_init(&pfb->vram, offset, length, 1);
+ if (ret)
+ nvkm_mm_fini(&pfb->vram);
+ }
+
+ if (ret)
+ return ret;
+
+ ram->get = gf100_ram_get;
+ ram->put = gf100_ram_put;
+ return 0;
+}
+
+static int
+gf100_ram_init(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = (void *)object->parent;
+ struct gf100_ram *ram = (void *)object;
+ int ret, i;
+
+ ret = nvkm_ram_init(&ram->base);
+ if (ret)
+ return ret;
+
+ /* prepare for ddr link training, and load training patterns */
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_GDDR5: {
+ static const u8 train0[] = {
+ 0x00, 0xff, 0x55, 0xaa, 0x33, 0xcc,
+ 0x00, 0xff, 0xff, 0x00, 0xff, 0x00,
+ };
+ static const u32 train1[] = {
+ 0x00000000, 0xffffffff,
+ 0x55555555, 0xaaaaaaaa,
+ 0x33333333, 0xcccccccc,
+ 0xf0f0f0f0, 0x0f0f0f0f,
+ 0x00ff00ff, 0xff00ff00,
+ 0x0000ffff, 0xffff0000,
+ };
+
+ for (i = 0; i < 0x30; i++) {
+ nv_wr32(pfb, 0x10f968, 0x00000000 | (i << 8));
+ nv_wr32(pfb, 0x10f96c, 0x00000000 | (i << 8));
+ nv_wr32(pfb, 0x10f920, 0x00000100 | train0[i % 12]);
+ nv_wr32(pfb, 0x10f924, 0x00000100 | train0[i % 12]);
+ nv_wr32(pfb, 0x10f918, train1[i % 12]);
+ nv_wr32(pfb, 0x10f91c, train1[i % 12]);
+ nv_wr32(pfb, 0x10f920, 0x00000000 | train0[i % 12]);
+ nv_wr32(pfb, 0x10f924, 0x00000000 | train0[i % 12]);
+ nv_wr32(pfb, 0x10f918, train1[i % 12]);
+ nv_wr32(pfb, 0x10f91c, train1[i % 12]);
+ }
+ } break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int
+gf100_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct gf100_ram *ram;
+ int ret;
+
+ ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ ret = nvbios_pll_parse(bios, 0x0c, &ram->refpll);
+ if (ret) {
+ nv_error(ram, "mclk refpll data not found\n");
+ return ret;
+ }
+
+ ret = nvbios_pll_parse(bios, 0x04, &ram->mempll);
+ if (ret) {
+ nv_error(ram, "mclk pll data not found\n");
+ return ret;
+ }
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_GDDR5:
+ ram->base.calc = gf100_ram_calc;
+ ram->base.prog = gf100_ram_prog;
+ ram->base.tidy = gf100_ram_tidy;
+ break;
+ default:
+ nv_warn(ram, "reclocking of this ram type unsupported\n");
+ return 0;
+ }
+
+ ram->fuc.r_0x10fe20 = ramfuc_reg(0x10fe20);
+ ram->fuc.r_0x10fe24 = ramfuc_reg(0x10fe24);
+ ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
+ ram->fuc.r_0x137330 = ramfuc_reg(0x137330);
+
+ ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
+ ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
+ ram->fuc.r_0x132100 = ramfuc_reg(0x132100);
+
+ ram->fuc.r_0x137390 = ramfuc_reg(0x137390);
+
+ ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
+ ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
+ ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
+ ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
+ ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
+
+ ram->fuc.r_0x10f300 = ramfuc_reg(0x10f300);
+ ram->fuc.r_0x10f338 = ramfuc_reg(0x10f338);
+ ram->fuc.r_0x10f340 = ramfuc_reg(0x10f340);
+ ram->fuc.r_0x10f344 = ramfuc_reg(0x10f344);
+ ram->fuc.r_0x10f348 = ramfuc_reg(0x10f348);
+
+ ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
+ ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
+
+ ram->fuc.r_0x100b0c = ramfuc_reg(0x100b0c);
+ ram->fuc.r_0x10f050 = ramfuc_reg(0x10f050);
+ ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
+ ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
+ ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
+ ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
+ ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
+ ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
+ ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
+ ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
+ ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
+ ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
+ ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
+ ram->fuc.r_0x10f988 = ramfuc_reg(0x10f988);
+ ram->fuc.r_0x10f98c = ramfuc_reg(0x10f98c);
+ ram->fuc.r_0x10f990 = ramfuc_reg(0x10f990);
+ ram->fuc.r_0x10f998 = ramfuc_reg(0x10f998);
+ ram->fuc.r_0x10f9b0 = ramfuc_reg(0x10f9b0);
+ ram->fuc.r_0x10f9b4 = ramfuc_reg(0x10f9b4);
+ ram->fuc.r_0x10fb04 = ramfuc_reg(0x10fb04);
+ ram->fuc.r_0x10fb08 = ramfuc_reg(0x10fb08);
+ ram->fuc.r_0x137310 = ramfuc_reg(0x137300);
+ ram->fuc.r_0x137310 = ramfuc_reg(0x137310);
+ ram->fuc.r_0x137360 = ramfuc_reg(0x137360);
+ ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
+ ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
+ ram->fuc.r_0x1373f8 = ramfuc_reg(0x1373f8);
+
+ ram->fuc.r_0x61c140 = ramfuc_reg(0x61c140);
+ ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
+
+ ram->fuc.r_0x13d8f4 = ramfuc_reg(0x13d8f4);
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_ram_ctor,
+ .dtor = _nvkm_ram_dtor,
+ .init = gf100_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
new file mode 100644
index 000000000000..1ef15c3e6a81
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk104.c
@@ -0,0 +1,1639 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "ramfuc.h"
+#include "gf100.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/M0205.h>
+#include <subdev/bios/M0209.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk.h>
+#include <subdev/clk/pll.h>
+#include <subdev/gpio.h>
+
+struct gk104_ramfuc {
+ struct ramfuc base;
+
+ struct nvbios_pll refpll;
+ struct nvbios_pll mempll;
+
+ struct ramfuc_reg r_gpioMV;
+ u32 r_funcMV[2];
+ struct ramfuc_reg r_gpio2E;
+ u32 r_func2E[2];
+ struct ramfuc_reg r_gpiotrig;
+
+ struct ramfuc_reg r_0x132020;
+ struct ramfuc_reg r_0x132028;
+ struct ramfuc_reg r_0x132024;
+ struct ramfuc_reg r_0x132030;
+ struct ramfuc_reg r_0x132034;
+ struct ramfuc_reg r_0x132000;
+ struct ramfuc_reg r_0x132004;
+ struct ramfuc_reg r_0x132040;
+
+ struct ramfuc_reg r_0x10f248;
+ struct ramfuc_reg r_0x10f290;
+ struct ramfuc_reg r_0x10f294;
+ struct ramfuc_reg r_0x10f298;
+ struct ramfuc_reg r_0x10f29c;
+ struct ramfuc_reg r_0x10f2a0;
+ struct ramfuc_reg r_0x10f2a4;
+ struct ramfuc_reg r_0x10f2a8;
+ struct ramfuc_reg r_0x10f2ac;
+ struct ramfuc_reg r_0x10f2cc;
+ struct ramfuc_reg r_0x10f2e8;
+ struct ramfuc_reg r_0x10f250;
+ struct ramfuc_reg r_0x10f24c;
+ struct ramfuc_reg r_0x10fec4;
+ struct ramfuc_reg r_0x10fec8;
+ struct ramfuc_reg r_0x10f604;
+ struct ramfuc_reg r_0x10f614;
+ struct ramfuc_reg r_0x10f610;
+ struct ramfuc_reg r_0x100770;
+ struct ramfuc_reg r_0x100778;
+ struct ramfuc_reg r_0x10f224;
+
+ struct ramfuc_reg r_0x10f870;
+ struct ramfuc_reg r_0x10f698;
+ struct ramfuc_reg r_0x10f694;
+ struct ramfuc_reg r_0x10f6b8;
+ struct ramfuc_reg r_0x10f808;
+ struct ramfuc_reg r_0x10f670;
+ struct ramfuc_reg r_0x10f60c;
+ struct ramfuc_reg r_0x10f830;
+ struct ramfuc_reg r_0x1373ec;
+ struct ramfuc_reg r_0x10f800;
+ struct ramfuc_reg r_0x10f82c;
+
+ struct ramfuc_reg r_0x10f978;
+ struct ramfuc_reg r_0x10f910;
+ struct ramfuc_reg r_0x10f914;
+
+ struct ramfuc_reg r_mr[16]; /* MR0 - MR8, MR15 */
+
+ struct ramfuc_reg r_0x62c000;
+
+ struct ramfuc_reg r_0x10f200;
+
+ struct ramfuc_reg r_0x10f210;
+ struct ramfuc_reg r_0x10f310;
+ struct ramfuc_reg r_0x10f314;
+ struct ramfuc_reg r_0x10f318;
+ struct ramfuc_reg r_0x10f090;
+ struct ramfuc_reg r_0x10f69c;
+ struct ramfuc_reg r_0x10f824;
+ struct ramfuc_reg r_0x1373f0;
+ struct ramfuc_reg r_0x1373f4;
+ struct ramfuc_reg r_0x137320;
+ struct ramfuc_reg r_0x10f65c;
+ struct ramfuc_reg r_0x10f6bc;
+ struct ramfuc_reg r_0x100710;
+ struct ramfuc_reg r_0x100750;
+};
+
+struct gk104_ram {
+ struct nvkm_ram base;
+ struct gk104_ramfuc fuc;
+
+ struct list_head cfg;
+ u32 parts;
+ u32 pmask;
+ u32 pnuts;
+
+ struct nvbios_ramcfg diff;
+ int from;
+ int mode;
+ int N1, fN1, M1, P1;
+ int N2, M2, P2;
+};
+
+/*******************************************************************************
+ * GDDR5
+ ******************************************************************************/
+static void
+gk104_ram_train(struct gk104_ramfuc *fuc, u32 mask, u32 data)
+{
+ struct gk104_ram *ram = container_of(fuc, typeof(*ram), fuc);
+ u32 addr = 0x110974, i;
+
+ ram_mask(fuc, 0x10f910, mask, data);
+ ram_mask(fuc, 0x10f914, mask, data);
+
+ for (i = 0; (data & 0x80000000) && i < ram->parts; addr += 0x1000, i++) {
+ if (ram->pmask & (1 << i))
+ continue;
+ ram_wait(fuc, addr, 0x0000000f, 0x00000000, 500000);
+ }
+}
+
+static void
+r1373f4_init(struct gk104_ramfuc *fuc)
+{
+ struct gk104_ram *ram = container_of(fuc, typeof(*ram), fuc);
+ const u32 mcoef = ((--ram->P2 << 28) | (ram->N2 << 8) | ram->M2);
+ const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
+ const u32 runk0 = ram->fN1 << 16;
+ const u32 runk1 = ram->fN1;
+
+ if (ram->from == 2) {
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
+ } else {
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
+ }
+
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
+ ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
+
+ /* (re)program refpll, if required */
+ if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
+ (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
+ ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+ ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
+ ram_wr32(fuc, 0x137320, 0x00000000);
+ ram_mask(fuc, 0x132030, 0xffff0000, runk0);
+ ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
+ ram_wr32(fuc, 0x132024, rcoef);
+ ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
+ ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
+ ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+ ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
+ }
+
+ /* (re)program mempll, if required */
+ if (ram->mode == 2) {
+ ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
+ ram_mask(fuc, 0x132000, 0x80000000, 0x80000000);
+ ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+ ram_mask(fuc, 0x132004, 0x103fffff, mcoef);
+ ram_mask(fuc, 0x132000, 0x00000001, 0x00000001);
+ ram_wait(fuc, 0x137390, 0x00000002, 0x00000002, 64000);
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00001100);
+ } else {
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010100);
+ }
+
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00000010);
+}
+
+static void
+r1373f4_fini(struct gk104_ramfuc *fuc)
+{
+ struct gk104_ram *ram = container_of(fuc, typeof(*ram), fuc);
+ struct nvkm_ram_data *next = ram->base.next;
+ u8 v0 = next->bios.ramcfg_11_03_c0;
+ u8 v1 = next->bios.ramcfg_11_03_30;
+ u32 tmp;
+
+ tmp = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
+ ram_wr32(fuc, 0x1373ec, tmp | (v1 << 16));
+ ram_mask(fuc, 0x1373f0, (~ram->mode & 3), 0x00000000);
+ if (ram->mode == 2) {
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000002);
+ ram_mask(fuc, 0x1373f4, 0x00001100, 0x000000000);
+ } else {
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x000000001);
+ ram_mask(fuc, 0x1373f4, 0x00010000, 0x000000000);
+ }
+ ram_mask(fuc, 0x10f800, 0x00000030, (v0 ^ v1) << 4);
+}
+
+static void
+gk104_ram_nuts(struct gk104_ram *ram, struct ramfuc_reg *reg,
+ u32 _mask, u32 _data, u32 _copy)
+{
+ struct gk104_fb_priv *priv = (void *)nvkm_fb(ram);
+ struct ramfuc *fuc = &ram->fuc.base;
+ u32 addr = 0x110000 + (reg->addr & 0xfff);
+ u32 mask = _mask | _copy;
+ u32 data = (_data & _mask) | (reg->data & _copy);
+ u32 i;
+
+ for (i = 0; i < 16; i++, addr += 0x1000) {
+ if (ram->pnuts & (1 << i)) {
+ u32 prev = nv_rd32(priv, addr);
+ u32 next = (prev & ~mask) | data;
+ nvkm_memx_wr32(fuc->memx, addr, next);
+ }
+ }
+}
+#define ram_nuts(s,r,m,d,c) \
+ gk104_ram_nuts((s), &(s)->fuc.r_##r, (m), (d), (c))
+
+static int
+gk104_ram_calc_gddr5(struct nvkm_fb *pfb, u32 freq)
+{
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct gk104_ramfuc *fuc = &ram->fuc;
+ struct nvkm_ram_data *next = ram->base.next;
+ int vc = !next->bios.ramcfg_11_02_08;
+ int mv = !next->bios.ramcfg_11_02_04;
+ u32 mask, data;
+
+ ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+ ram_block(fuc);
+ ram_wr32(fuc, 0x62c000, 0x0f0f0000);
+
+ /* MR1: turn termination on early, for some reason.. */
+ if ((ram->base.mr[1] & 0x03c) != 0x030) {
+ ram_mask(fuc, mr[1], 0x03c, ram->base.mr[1] & 0x03c);
+ ram_nuts(ram, mr[1], 0x03c, ram->base.mr1_nuts & 0x03c, 0x000);
+ }
+
+ if (vc == 1 && ram_have(fuc, gpio2E)) {
+ u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
+ if (temp != ram_rd32(fuc, gpio2E)) {
+ ram_wr32(fuc, gpiotrig, 1);
+ ram_nsec(fuc, 20000);
+ }
+ }
+
+ ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+
+ gk104_ram_train(fuc, 0x01020000, 0x000c0000);
+
+ ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+ ram_nsec(fuc, 1000);
+
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+ ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+ ram_wr32(fuc, 0x10f090, 0x00000061);
+ ram_wr32(fuc, 0x10f090, 0xc000007f);
+ ram_nsec(fuc, 1000);
+
+ ram_wr32(fuc, 0x10f698, 0x00000000);
+ ram_wr32(fuc, 0x10f69c, 0x00000000);
+
+ /*XXX: there does appear to be some kind of condition here, simply
+ * modifying these bits in the vbios from the default pl0
+ * entries shows no change. however, the data does appear to
+ * be correct and may be required for the transition back
+ */
+ mask = 0x800f07e0;
+ data = 0x00030000;
+ if (ram_rd32(fuc, 0x10f978) & 0x00800000)
+ data |= 0x00040000;
+
+ if (1) {
+ data |= 0x800807e0;
+ switch (next->bios.ramcfg_11_03_c0) {
+ case 3: data &= ~0x00000040; break;
+ case 2: data &= ~0x00000100; break;
+ case 1: data &= ~0x80000000; break;
+ case 0: data &= ~0x00000400; break;
+ }
+
+ switch (next->bios.ramcfg_11_03_30) {
+ case 3: data &= ~0x00000020; break;
+ case 2: data &= ~0x00000080; break;
+ case 1: data &= ~0x00080000; break;
+ case 0: data &= ~0x00000200; break;
+ }
+ }
+
+ if (next->bios.ramcfg_11_02_80)
+ mask |= 0x03000000;
+ if (next->bios.ramcfg_11_02_40)
+ mask |= 0x00002000;
+ if (next->bios.ramcfg_11_07_10)
+ mask |= 0x00004000;
+ if (next->bios.ramcfg_11_07_08)
+ mask |= 0x00000003;
+ else {
+ mask |= 0x34000000;
+ if (ram_rd32(fuc, 0x10f978) & 0x00800000)
+ mask |= 0x40000000;
+ }
+ ram_mask(fuc, 0x10f824, mask, data);
+
+ ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
+
+ if (ram->from == 2 && ram->mode != 2) {
+ ram_mask(fuc, 0x10f808, 0x00080000, 0x00000000);
+ ram_mask(fuc, 0x10f200, 0x18008000, 0x00008000);
+ ram_mask(fuc, 0x10f800, 0x00000000, 0x00000004);
+ ram_mask(fuc, 0x10f830, 0x00008000, 0x01040010);
+ ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+ r1373f4_init(fuc);
+ ram_mask(fuc, 0x1373f0, 0x00000002, 0x00000001);
+ r1373f4_fini(fuc);
+ ram_mask(fuc, 0x10f830, 0x00c00000, 0x00240001);
+ } else
+ if (ram->from != 2 && ram->mode != 2) {
+ r1373f4_init(fuc);
+ r1373f4_fini(fuc);
+ }
+
+ if (ram_have(fuc, gpioMV)) {
+ u32 temp = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
+ if (temp != ram_rd32(fuc, gpioMV)) {
+ ram_wr32(fuc, gpiotrig, 1);
+ ram_nsec(fuc, 64000);
+ }
+ }
+
+ if (next->bios.ramcfg_11_02_40 ||
+ next->bios.ramcfg_11_07_10) {
+ ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
+ ram_nsec(fuc, 20000);
+ }
+
+ if (ram->from != 2 && ram->mode == 2) {
+ if (0 /*XXX: Titan */)
+ ram_mask(fuc, 0x10f200, 0x18000000, 0x18000000);
+ ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
+ ram_mask(fuc, 0x1373f0, 0x00000000, 0x00000002);
+ ram_mask(fuc, 0x10f830, 0x00800001, 0x00408010);
+ r1373f4_init(fuc);
+ r1373f4_fini(fuc);
+ ram_mask(fuc, 0x10f808, 0x00000000, 0x00080000);
+ ram_mask(fuc, 0x10f200, 0x00808000, 0x00800000);
+ } else
+ if (ram->from == 2 && ram->mode == 2) {
+ ram_mask(fuc, 0x10f800, 0x00000004, 0x00000000);
+ r1373f4_init(fuc);
+ r1373f4_fini(fuc);
+ }
+
+ if (ram->mode != 2) /*XXX*/ {
+ if (next->bios.ramcfg_11_07_40)
+ ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
+ }
+
+ ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
+ ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
+ ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
+
+ if (!next->bios.ramcfg_11_07_08 && !next->bios.ramcfg_11_07_04) {
+ ram_wr32(fuc, 0x10f698, 0x01010101 * next->bios.ramcfg_11_04);
+ ram_wr32(fuc, 0x10f69c, 0x01010101 * next->bios.ramcfg_11_04);
+ } else
+ if (!next->bios.ramcfg_11_07_08) {
+ ram_wr32(fuc, 0x10f698, 0x00000000);
+ ram_wr32(fuc, 0x10f69c, 0x00000000);
+ }
+
+ if (ram->mode != 2) {
+ u32 data = 0x01000100 * next->bios.ramcfg_11_04;
+ ram_nuke(fuc, 0x10f694);
+ ram_mask(fuc, 0x10f694, 0xff00ff00, data);
+ }
+
+ if (ram->mode == 2 && next->bios.ramcfg_11_08_10)
+ data = 0x00000080;
+ else
+ data = 0x00000000;
+ ram_mask(fuc, 0x10f60c, 0x00000080, data);
+
+ mask = 0x00070000;
+ data = 0x00000000;
+ if (!next->bios.ramcfg_11_02_80)
+ data |= 0x03000000;
+ if (!next->bios.ramcfg_11_02_40)
+ data |= 0x00002000;
+ if (!next->bios.ramcfg_11_07_10)
+ data |= 0x00004000;
+ if (!next->bios.ramcfg_11_07_08)
+ data |= 0x00000003;
+ else
+ data |= 0x74000000;
+ ram_mask(fuc, 0x10f824, mask, data);
+
+ if (next->bios.ramcfg_11_01_08)
+ data = 0x00000000;
+ else
+ data = 0x00001000;
+ ram_mask(fuc, 0x10f200, 0x00001000, data);
+
+ if (ram_rd32(fuc, 0x10f670) & 0x80000000) {
+ ram_nsec(fuc, 10000);
+ ram_mask(fuc, 0x10f670, 0x80000000, 0x00000000);
+ }
+
+ if (next->bios.ramcfg_11_08_01)
+ data = 0x00100000;
+ else
+ data = 0x00000000;
+ ram_mask(fuc, 0x10f82c, 0x00100000, data);
+
+ data = 0x00000000;
+ if (next->bios.ramcfg_11_08_08)
+ data |= 0x00002000;
+ if (next->bios.ramcfg_11_08_04)
+ data |= 0x00001000;
+ if (next->bios.ramcfg_11_08_02)
+ data |= 0x00004000;
+ ram_mask(fuc, 0x10f830, 0x00007000, data);
+
+ /* PFB timing */
+ ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
+ ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
+ ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
+ ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
+ ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
+ ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
+ ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
+ ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
+ ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
+ ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
+ ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
+
+ data = mask = 0x00000000;
+ if (ram->diff.ramcfg_11_08_20) {
+ if (next->bios.ramcfg_11_08_20)
+ data |= 0x01000000;
+ mask |= 0x01000000;
+ }
+ ram_mask(fuc, 0x10f200, mask, data);
+
+ data = mask = 0x00000000;
+ if (ram->diff.ramcfg_11_02_03) {
+ data |= next->bios.ramcfg_11_02_03 << 8;
+ mask |= 0x00000300;
+ }
+ if (ram->diff.ramcfg_11_01_10) {
+ if (next->bios.ramcfg_11_01_10)
+ data |= 0x70000000;
+ mask |= 0x70000000;
+ }
+ ram_mask(fuc, 0x10f604, mask, data);
+
+ data = mask = 0x00000000;
+ if (ram->diff.timing_20_30_07) {
+ data |= next->bios.timing_20_30_07 << 28;
+ mask |= 0x70000000;
+ }
+ if (ram->diff.ramcfg_11_01_01) {
+ if (next->bios.ramcfg_11_01_01)
+ data |= 0x00000100;
+ mask |= 0x00000100;
+ }
+ ram_mask(fuc, 0x10f614, mask, data);
+
+ data = mask = 0x00000000;
+ if (ram->diff.timing_20_30_07) {
+ data |= next->bios.timing_20_30_07 << 28;
+ mask |= 0x70000000;
+ }
+ if (ram->diff.ramcfg_11_01_02) {
+ if (next->bios.ramcfg_11_01_02)
+ data |= 0x00000100;
+ mask |= 0x00000100;
+ }
+ ram_mask(fuc, 0x10f610, mask, data);
+
+ mask = 0x33f00000;
+ data = 0x00000000;
+ if (!next->bios.ramcfg_11_01_04)
+ data |= 0x20200000;
+ if (!next->bios.ramcfg_11_07_80)
+ data |= 0x12800000;
+ /*XXX: see note above about there probably being some condition
+ * for the 10f824 stuff that uses ramcfg 3...
+ */
+ if (next->bios.ramcfg_11_03_f0) {
+ if (next->bios.rammap_11_08_0c) {
+ if (!next->bios.ramcfg_11_07_80)
+ mask |= 0x00000020;
+ else
+ data |= 0x00000020;
+ mask |= 0x00000004;
+ }
+ } else {
+ mask |= 0x40000020;
+ data |= 0x00000004;
+ }
+
+ ram_mask(fuc, 0x10f808, mask, data);
+
+ ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
+
+ data = mask = 0x00000000;
+ if (ram->diff.ramcfg_11_02_03) {
+ data |= next->bios.ramcfg_11_02_03;
+ mask |= 0x00000003;
+ }
+ if (ram->diff.ramcfg_11_01_10) {
+ if (next->bios.ramcfg_11_01_10)
+ data |= 0x00000004;
+ mask |= 0x00000004;
+ }
+
+ if ((ram_mask(fuc, 0x100770, mask, data) & mask & 4) != (data & 4)) {
+ ram_mask(fuc, 0x100750, 0x00000008, 0x00000008);
+ ram_wr32(fuc, 0x100710, 0x00000000);
+ ram_wait(fuc, 0x100710, 0x80000000, 0x80000000, 200000);
+ }
+
+ data = next->bios.timing_20_30_07 << 8;
+ if (next->bios.ramcfg_11_01_01)
+ data |= 0x80000000;
+ ram_mask(fuc, 0x100778, 0x00000700, data);
+
+ ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
+ data = (next->bios.timing[10] & 0x7f000000) >> 24;
+ if (data < next->bios.timing_20_2c_1fc0)
+ data = next->bios.timing_20_2c_1fc0;
+ ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
+ ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
+
+ ram_mask(fuc, 0x10fec4, 0x041e0f07, next->bios.timing_20_31_0800 << 26 |
+ next->bios.timing_20_31_0780 << 17 |
+ next->bios.timing_20_31_0078 << 8 |
+ next->bios.timing_20_31_0007);
+ ram_mask(fuc, 0x10fec8, 0x00000027, next->bios.timing_20_31_8000 << 5 |
+ next->bios.timing_20_31_7000);
+
+ ram_wr32(fuc, 0x10f090, 0x4000007e);
+ ram_nsec(fuc, 2000);
+ ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+ ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+ ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
+
+ if (next->bios.ramcfg_11_08_10 && (ram->mode == 2) /*XXX*/) {
+ u32 temp = ram_mask(fuc, 0x10f294, 0xff000000, 0x24000000);
+ gk104_ram_train(fuc, 0xbc0e0000, 0xa4010000); /*XXX*/
+ ram_nsec(fuc, 1000);
+ ram_wr32(fuc, 0x10f294, temp);
+ }
+
+ ram_mask(fuc, mr[3], 0xfff, ram->base.mr[3]);
+ ram_wr32(fuc, mr[0], ram->base.mr[0]);
+ ram_mask(fuc, mr[8], 0xfff, ram->base.mr[8]);
+ ram_nsec(fuc, 1000);
+ ram_mask(fuc, mr[1], 0xfff, ram->base.mr[1]);
+ ram_mask(fuc, mr[5], 0xfff, ram->base.mr[5] & ~0x004); /* LP3 later */
+ ram_mask(fuc, mr[6], 0xfff, ram->base.mr[6]);
+ ram_mask(fuc, mr[7], 0xfff, ram->base.mr[7]);
+
+ if (vc == 0 && ram_have(fuc, gpio2E)) {
+ u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
+ if (temp != ram_rd32(fuc, gpio2E)) {
+ ram_wr32(fuc, gpiotrig, 1);
+ ram_nsec(fuc, 20000);
+ }
+ }
+
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+ ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+ ram_nsec(fuc, 1000);
+ ram_nuts(ram, 0x10f200, 0x18808800, 0x00000000, 0x18808800);
+
+ data = ram_rd32(fuc, 0x10f978);
+ data &= ~0x00046144;
+ data |= 0x0000000b;
+ if (!next->bios.ramcfg_11_07_08) {
+ if (!next->bios.ramcfg_11_07_04)
+ data |= 0x0000200c;
+ else
+ data |= 0x00000000;
+ } else {
+ data |= 0x00040044;
+ }
+ ram_wr32(fuc, 0x10f978, data);
+
+ if (ram->mode == 1) {
+ data = ram_rd32(fuc, 0x10f830) | 0x00000001;
+ ram_wr32(fuc, 0x10f830, data);
+ }
+
+ if (!next->bios.ramcfg_11_07_08) {
+ data = 0x88020000;
+ if ( next->bios.ramcfg_11_07_04)
+ data |= 0x10000000;
+ if (!next->bios.rammap_11_08_10)
+ data |= 0x00080000;
+ } else {
+ data = 0xa40e0000;
+ }
+ gk104_ram_train(fuc, 0xbc0f0000, data);
+ if (1) /* XXX: not always? */
+ ram_nsec(fuc, 1000);
+
+ if (ram->mode == 2) { /*XXX*/
+ ram_mask(fuc, 0x10f800, 0x00000004, 0x00000004);
+ }
+
+ /* LP3 */
+ if (ram_mask(fuc, mr[5], 0x004, ram->base.mr[5]) != ram->base.mr[5])
+ ram_nsec(fuc, 1000);
+
+ if (ram->mode != 2) {
+ ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
+ ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+ }
+
+ if (next->bios.ramcfg_11_07_02)
+ gk104_ram_train(fuc, 0x80020000, 0x01000000);
+
+ ram_unblock(fuc);
+ ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
+
+ if (next->bios.rammap_11_08_01)
+ data = 0x00000800;
+ else
+ data = 0x00000000;
+ ram_mask(fuc, 0x10f200, 0x00000800, data);
+ ram_nuts(ram, 0x10f200, 0x18808800, data, 0x18808800);
+ return 0;
+}
+
+/*******************************************************************************
+ * DDR3
+ ******************************************************************************/
+
+static int
+gk104_ram_calc_sddr3(struct nvkm_fb *pfb, u32 freq)
+{
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct gk104_ramfuc *fuc = &ram->fuc;
+ const u32 rcoef = (( ram->P1 << 16) | (ram->N1 << 8) | ram->M1);
+ const u32 runk0 = ram->fN1 << 16;
+ const u32 runk1 = ram->fN1;
+ struct nvkm_ram_data *next = ram->base.next;
+ int vc = !next->bios.ramcfg_11_02_08;
+ int mv = !next->bios.ramcfg_11_02_04;
+ u32 mask, data;
+
+ ram_mask(fuc, 0x10f808, 0x40000000, 0x40000000);
+ ram_block(fuc);
+ ram_wr32(fuc, 0x62c000, 0x0f0f0000);
+
+ if (vc == 1 && ram_have(fuc, gpio2E)) {
+ u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[1]);
+ if (temp != ram_rd32(fuc, gpio2E)) {
+ ram_wr32(fuc, gpiotrig, 1);
+ ram_nsec(fuc, 20000);
+ }
+ }
+
+ ram_mask(fuc, 0x10f200, 0x00000800, 0x00000000);
+ if (next->bios.ramcfg_11_03_f0)
+ ram_mask(fuc, 0x10f808, 0x04000000, 0x04000000);
+
+ ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+ ram_wr32(fuc, 0x10f210, 0x00000000); /* REFRESH_AUTO = 0 */
+ ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+ ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+ ram_nsec(fuc, 1000);
+
+ ram_wr32(fuc, 0x10f090, 0x00000060);
+ ram_wr32(fuc, 0x10f090, 0xc000007e);
+
+ /*XXX: there does appear to be some kind of condition here, simply
+ * modifying these bits in the vbios from the default pl0
+ * entries shows no change. however, the data does appear to
+ * be correct and may be required for the transition back
+ */
+ mask = 0x00010000;
+ data = 0x00010000;
+
+ if (1) {
+ mask |= 0x800807e0;
+ data |= 0x800807e0;
+ switch (next->bios.ramcfg_11_03_c0) {
+ case 3: data &= ~0x00000040; break;
+ case 2: data &= ~0x00000100; break;
+ case 1: data &= ~0x80000000; break;
+ case 0: data &= ~0x00000400; break;
+ }
+
+ switch (next->bios.ramcfg_11_03_30) {
+ case 3: data &= ~0x00000020; break;
+ case 2: data &= ~0x00000080; break;
+ case 1: data &= ~0x00080000; break;
+ case 0: data &= ~0x00000200; break;
+ }
+ }
+
+ if (next->bios.ramcfg_11_02_80)
+ mask |= 0x03000000;
+ if (next->bios.ramcfg_11_02_40)
+ mask |= 0x00002000;
+ if (next->bios.ramcfg_11_07_10)
+ mask |= 0x00004000;
+ if (next->bios.ramcfg_11_07_08)
+ mask |= 0x00000003;
+ else
+ mask |= 0x14000000;
+ ram_mask(fuc, 0x10f824, mask, data);
+
+ ram_mask(fuc, 0x132040, 0x00010000, 0x00000000);
+
+ ram_mask(fuc, 0x1373f4, 0x00000000, 0x00010010);
+ data = ram_rd32(fuc, 0x1373ec) & ~0x00030000;
+ data |= next->bios.ramcfg_11_03_30 << 16;
+ ram_wr32(fuc, 0x1373ec, data);
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000000);
+ ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000000);
+
+ /* (re)program refpll, if required */
+ if ((ram_rd32(fuc, 0x132024) & 0xffffffff) != rcoef ||
+ (ram_rd32(fuc, 0x132034) & 0x0000ffff) != runk1) {
+ ram_mask(fuc, 0x132000, 0x00000001, 0x00000000);
+ ram_mask(fuc, 0x132020, 0x00000001, 0x00000000);
+ ram_wr32(fuc, 0x137320, 0x00000000);
+ ram_mask(fuc, 0x132030, 0xffff0000, runk0);
+ ram_mask(fuc, 0x132034, 0x0000ffff, runk1);
+ ram_wr32(fuc, 0x132024, rcoef);
+ ram_mask(fuc, 0x132028, 0x00080000, 0x00080000);
+ ram_mask(fuc, 0x132020, 0x00000001, 0x00000001);
+ ram_wait(fuc, 0x137390, 0x00020000, 0x00020000, 64000);
+ ram_mask(fuc, 0x132028, 0x00080000, 0x00000000);
+ }
+
+ ram_mask(fuc, 0x1373f4, 0x00000010, 0x00000010);
+ ram_mask(fuc, 0x1373f4, 0x00000003, 0x00000001);
+ ram_mask(fuc, 0x1373f4, 0x00010000, 0x00000000);
+
+ if (ram_have(fuc, gpioMV)) {
+ u32 temp = ram_mask(fuc, gpioMV, 0x3000, fuc->r_funcMV[mv]);
+ if (temp != ram_rd32(fuc, gpioMV)) {
+ ram_wr32(fuc, gpiotrig, 1);
+ ram_nsec(fuc, 64000);
+ }
+ }
+
+ if (next->bios.ramcfg_11_02_40 ||
+ next->bios.ramcfg_11_07_10) {
+ ram_mask(fuc, 0x132040, 0x00010000, 0x00010000);
+ ram_nsec(fuc, 20000);
+ }
+
+ if (ram->mode != 2) /*XXX*/ {
+ if (next->bios.ramcfg_11_07_40)
+ ram_mask(fuc, 0x10f670, 0x80000000, 0x80000000);
+ }
+
+ ram_wr32(fuc, 0x10f65c, 0x00000011 * next->bios.rammap_11_11_0c);
+ ram_wr32(fuc, 0x10f6b8, 0x01010101 * next->bios.ramcfg_11_09);
+ ram_wr32(fuc, 0x10f6bc, 0x01010101 * next->bios.ramcfg_11_09);
+
+ mask = 0x00010000;
+ data = 0x00000000;
+ if (!next->bios.ramcfg_11_02_80)
+ data |= 0x03000000;
+ if (!next->bios.ramcfg_11_02_40)
+ data |= 0x00002000;
+ if (!next->bios.ramcfg_11_07_10)
+ data |= 0x00004000;
+ if (!next->bios.ramcfg_11_07_08)
+ data |= 0x00000003;
+ else
+ data |= 0x14000000;
+ ram_mask(fuc, 0x10f824, mask, data);
+ ram_nsec(fuc, 1000);
+
+ if (next->bios.ramcfg_11_08_01)
+ data = 0x00100000;
+ else
+ data = 0x00000000;
+ ram_mask(fuc, 0x10f82c, 0x00100000, data);
+
+ /* PFB timing */
+ ram_mask(fuc, 0x10f248, 0xffffffff, next->bios.timing[10]);
+ ram_mask(fuc, 0x10f290, 0xffffffff, next->bios.timing[0]);
+ ram_mask(fuc, 0x10f294, 0xffffffff, next->bios.timing[1]);
+ ram_mask(fuc, 0x10f298, 0xffffffff, next->bios.timing[2]);
+ ram_mask(fuc, 0x10f29c, 0xffffffff, next->bios.timing[3]);
+ ram_mask(fuc, 0x10f2a0, 0xffffffff, next->bios.timing[4]);
+ ram_mask(fuc, 0x10f2a4, 0xffffffff, next->bios.timing[5]);
+ ram_mask(fuc, 0x10f2a8, 0xffffffff, next->bios.timing[6]);
+ ram_mask(fuc, 0x10f2ac, 0xffffffff, next->bios.timing[7]);
+ ram_mask(fuc, 0x10f2cc, 0xffffffff, next->bios.timing[8]);
+ ram_mask(fuc, 0x10f2e8, 0xffffffff, next->bios.timing[9]);
+
+ mask = 0x33f00000;
+ data = 0x00000000;
+ if (!next->bios.ramcfg_11_01_04)
+ data |= 0x20200000;
+ if (!next->bios.ramcfg_11_07_80)
+ data |= 0x12800000;
+ /*XXX: see note above about there probably being some condition
+ * for the 10f824 stuff that uses ramcfg 3...
+ */
+ if (next->bios.ramcfg_11_03_f0) {
+ if (next->bios.rammap_11_08_0c) {
+ if (!next->bios.ramcfg_11_07_80)
+ mask |= 0x00000020;
+ else
+ data |= 0x00000020;
+ mask |= 0x08000004;
+ }
+ data |= 0x04000000;
+ } else {
+ mask |= 0x44000020;
+ data |= 0x08000004;
+ }
+
+ ram_mask(fuc, 0x10f808, mask, data);
+
+ ram_wr32(fuc, 0x10f870, 0x11111111 * next->bios.ramcfg_11_03_0f);
+
+ ram_mask(fuc, 0x10f250, 0x000003f0, next->bios.timing_20_2c_003f << 4);
+
+ data = (next->bios.timing[10] & 0x7f000000) >> 24;
+ if (data < next->bios.timing_20_2c_1fc0)
+ data = next->bios.timing_20_2c_1fc0;
+ ram_mask(fuc, 0x10f24c, 0x7f000000, data << 24);
+
+ ram_mask(fuc, 0x10f224, 0x001f0000, next->bios.timing_20_30_f8 << 16);
+
+ ram_wr32(fuc, 0x10f090, 0x4000007f);
+ ram_nsec(fuc, 1000);
+
+ ram_wr32(fuc, 0x10f314, 0x00000001); /* PRECHARGE */
+ ram_wr32(fuc, 0x10f310, 0x00000001); /* REFRESH */
+ ram_wr32(fuc, 0x10f210, 0x80000000); /* REFRESH_AUTO = 1 */
+ ram_nsec(fuc, 1000);
+
+ ram_nuke(fuc, mr[0]);
+ ram_mask(fuc, mr[0], 0x100, 0x100);
+ ram_mask(fuc, mr[0], 0x100, 0x000);
+
+ ram_mask(fuc, mr[2], 0xfff, ram->base.mr[2]);
+ ram_wr32(fuc, mr[0], ram->base.mr[0]);
+ ram_nsec(fuc, 1000);
+
+ ram_nuke(fuc, mr[0]);
+ ram_mask(fuc, mr[0], 0x100, 0x100);
+ ram_mask(fuc, mr[0], 0x100, 0x000);
+
+ if (vc == 0 && ram_have(fuc, gpio2E)) {
+ u32 temp = ram_mask(fuc, gpio2E, 0x3000, fuc->r_func2E[0]);
+ if (temp != ram_rd32(fuc, gpio2E)) {
+ ram_wr32(fuc, gpiotrig, 1);
+ ram_nsec(fuc, 20000);
+ }
+ }
+
+ if (ram->mode != 2) {
+ ram_mask(fuc, 0x10f830, 0x01000000, 0x01000000);
+ ram_mask(fuc, 0x10f830, 0x01000000, 0x00000000);
+ }
+
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x80000000);
+ ram_wr32(fuc, 0x10f318, 0x00000001); /* NOP? */
+ ram_mask(fuc, 0x10f200, 0x80000000, 0x00000000);
+ ram_nsec(fuc, 1000);
+
+ ram_unblock(fuc);
+ ram_wr32(fuc, 0x62c000, 0x0f0f0f00);
+
+ if (next->bios.rammap_11_08_01)
+ data = 0x00000800;
+ else
+ data = 0x00000000;
+ ram_mask(fuc, 0x10f200, 0x00000800, data);
+ return 0;
+}
+
+/*******************************************************************************
+ * main hooks
+ ******************************************************************************/
+
+static int
+gk104_ram_calc_data(struct nvkm_fb *pfb, u32 khz, struct nvkm_ram_data *data)
+{
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct nvkm_ram_data *cfg;
+ u32 mhz = khz / 1000;
+
+ list_for_each_entry(cfg, &ram->cfg, head) {
+ if (mhz >= cfg->bios.rammap_min &&
+ mhz <= cfg->bios.rammap_max) {
+ *data = *cfg;
+ data->freq = khz;
+ return 0;
+ }
+ }
+
+ nv_error(ram, "ramcfg data for %dMHz not found\n", mhz);
+ return -EINVAL;
+}
+
+static int
+gk104_ram_calc_xits(struct nvkm_fb *pfb, struct nvkm_ram_data *next)
+{
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct gk104_ramfuc *fuc = &ram->fuc;
+ int refclk, i;
+ int ret;
+
+ ret = ram_init(fuc, pfb);
+ if (ret)
+ return ret;
+
+ ram->mode = (next->freq > fuc->refpll.vco1.max_freq) ? 2 : 1;
+ ram->from = ram_rd32(fuc, 0x1373f4) & 0x0000000f;
+
+ /* XXX: this is *not* what nvidia do. on fermi nvidia generally
+ * select, based on some unknown condition, one of the two possible
+ * reference frequencies listed in the vbios table for mempll and
+ * program refpll to that frequency.
+ *
+ * so far, i've seen very weird values being chosen by nvidia on
+ * kepler boards, no idea how/why they're chosen.
+ */
+ refclk = next->freq;
+ if (ram->mode == 2)
+ refclk = fuc->mempll.refclk;
+
+ /* calculate refpll coefficients */
+ ret = gt215_pll_calc(nv_subdev(pfb), &fuc->refpll, refclk, &ram->N1,
+ &ram->fN1, &ram->M1, &ram->P1);
+ fuc->mempll.refclk = ret;
+ if (ret <= 0) {
+ nv_error(pfb, "unable to calc refpll\n");
+ return -EINVAL;
+ }
+
+ /* calculate mempll coefficients, if we're using it */
+ if (ram->mode == 2) {
+ /* post-divider doesn't work... the reg takes the values but
+ * appears to completely ignore it. there *is* a bit at
+ * bit 28 that appears to divide the clock by 2 if set.
+ */
+ fuc->mempll.min_p = 1;
+ fuc->mempll.max_p = 2;
+
+ ret = gt215_pll_calc(nv_subdev(pfb), &fuc->mempll, next->freq,
+ &ram->N2, NULL, &ram->M2, &ram->P2);
+ if (ret <= 0) {
+ nv_error(pfb, "unable to calc mempll\n");
+ return -EINVAL;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fuc->r_mr); i++) {
+ if (ram_have(fuc, mr[i]))
+ ram->base.mr[i] = ram_rd32(fuc, mr[i]);
+ }
+ ram->base.freq = next->freq;
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR3:
+ ret = nvkm_sddr3_calc(&ram->base);
+ if (ret == 0)
+ ret = gk104_ram_calc_sddr3(pfb, next->freq);
+ break;
+ case NV_MEM_TYPE_GDDR5:
+ ret = nvkm_gddr5_calc(&ram->base, ram->pnuts != 0);
+ if (ret == 0)
+ ret = gk104_ram_calc_gddr5(pfb, next->freq);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ return ret;
+}
+
+static int
+gk104_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+ struct nvkm_clk *clk = nvkm_clk(pfb);
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct nvkm_ram_data *xits = &ram->base.xition;
+ struct nvkm_ram_data *copy;
+ int ret;
+
+ if (ram->base.next == NULL) {
+ ret = gk104_ram_calc_data(pfb, clk->read(clk, nv_clk_src_mem),
+ &ram->base.former);
+ if (ret)
+ return ret;
+
+ ret = gk104_ram_calc_data(pfb, freq, &ram->base.target);
+ if (ret)
+ return ret;
+
+ if (ram->base.target.freq < ram->base.former.freq) {
+ *xits = ram->base.target;
+ copy = &ram->base.former;
+ } else {
+ *xits = ram->base.former;
+ copy = &ram->base.target;
+ }
+
+ xits->bios.ramcfg_11_02_04 = copy->bios.ramcfg_11_02_04;
+ xits->bios.ramcfg_11_02_03 = copy->bios.ramcfg_11_02_03;
+ xits->bios.timing_20_30_07 = copy->bios.timing_20_30_07;
+
+ ram->base.next = &ram->base.target;
+ if (memcmp(xits, &ram->base.former, sizeof(xits->bios)))
+ ram->base.next = &ram->base.xition;
+ } else {
+ BUG_ON(ram->base.next != &ram->base.xition);
+ ram->base.next = &ram->base.target;
+ }
+
+ return gk104_ram_calc_xits(pfb, ram->base.next);
+}
+
+static void
+gk104_ram_prog_0(struct nvkm_fb *pfb, u32 freq)
+{
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct nvkm_ram_data *cfg;
+ u32 mhz = freq / 1000;
+ u32 mask, data;
+
+ list_for_each_entry(cfg, &ram->cfg, head) {
+ if (mhz >= cfg->bios.rammap_min &&
+ mhz <= cfg->bios.rammap_max)
+ break;
+ }
+
+ if (&cfg->head == &ram->cfg)
+ return;
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0a_03fe) {
+ data |= cfg->bios.rammap_11_0a_03fe << 12;
+ mask |= 0x001ff000;
+ }
+ if (ram->diff.rammap_11_09_01ff) {
+ data |= cfg->bios.rammap_11_09_01ff;
+ mask |= 0x000001ff;
+ }
+ nv_mask(pfb, 0x10f468, mask, data);
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0a_0400) {
+ data |= cfg->bios.rammap_11_0a_0400;
+ mask |= 0x00000001;
+ }
+ nv_mask(pfb, 0x10f420, mask, data);
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0a_0800) {
+ data |= cfg->bios.rammap_11_0a_0800;
+ mask |= 0x00000001;
+ }
+ nv_mask(pfb, 0x10f430, mask, data);
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0b_01f0) {
+ data |= cfg->bios.rammap_11_0b_01f0;
+ mask |= 0x0000001f;
+ }
+ nv_mask(pfb, 0x10f400, mask, data);
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0b_0200) {
+ data |= cfg->bios.rammap_11_0b_0200 << 9;
+ mask |= 0x00000200;
+ }
+ nv_mask(pfb, 0x10f410, mask, data);
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0d) {
+ data |= cfg->bios.rammap_11_0d << 16;
+ mask |= 0x00ff0000;
+ }
+ if (ram->diff.rammap_11_0f) {
+ data |= cfg->bios.rammap_11_0f << 8;
+ mask |= 0x0000ff00;
+ }
+ nv_mask(pfb, 0x10f440, mask, data);
+
+ if (mask = 0, data = 0, ram->diff.rammap_11_0e) {
+ data |= cfg->bios.rammap_11_0e << 8;
+ mask |= 0x0000ff00;
+ }
+ if (ram->diff.rammap_11_0b_0800) {
+ data |= cfg->bios.rammap_11_0b_0800 << 7;
+ mask |= 0x00000080;
+ }
+ if (ram->diff.rammap_11_0b_0400) {
+ data |= cfg->bios.rammap_11_0b_0400 << 5;
+ mask |= 0x00000020;
+ }
+ nv_mask(pfb, 0x10f444, mask, data);
+}
+
+static int
+gk104_ram_prog(struct nvkm_fb *pfb)
+{
+ struct nvkm_device *device = nv_device(pfb);
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct gk104_ramfuc *fuc = &ram->fuc;
+ struct nvkm_ram_data *next = ram->base.next;
+
+ if (!nvkm_boolopt(device->cfgopt, "NvMemExec", true)) {
+ ram_exec(fuc, false);
+ return (ram->base.next == &ram->base.xition);
+ }
+
+ gk104_ram_prog_0(pfb, 1000);
+ ram_exec(fuc, true);
+ gk104_ram_prog_0(pfb, next->freq);
+
+ return (ram->base.next == &ram->base.xition);
+}
+
+static void
+gk104_ram_tidy(struct nvkm_fb *pfb)
+{
+ struct gk104_ram *ram = (void *)pfb->ram;
+ struct gk104_ramfuc *fuc = &ram->fuc;
+ ram->base.next = NULL;
+ ram_exec(fuc, false);
+}
+
+struct gk104_ram_train {
+ u16 mask;
+ struct nvbios_M0209S remap;
+ struct nvbios_M0209S type00;
+ struct nvbios_M0209S type01;
+ struct nvbios_M0209S type04;
+ struct nvbios_M0209S type06;
+ struct nvbios_M0209S type07;
+ struct nvbios_M0209S type08;
+ struct nvbios_M0209S type09;
+};
+
+static int
+gk104_ram_train_type(struct nvkm_fb *pfb, int i, u8 ramcfg,
+ struct gk104_ram_train *train)
+{
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nvbios_M0205E M0205E;
+ struct nvbios_M0205S M0205S;
+ struct nvbios_M0209E M0209E;
+ struct nvbios_M0209S *remap = &train->remap;
+ struct nvbios_M0209S *value;
+ u8 ver, hdr, cnt, len;
+ u32 data;
+
+ /* determine type of data for this index */
+ if (!(data = nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E)))
+ return -ENOENT;
+
+ switch (M0205E.type) {
+ case 0x00: value = &train->type00; break;
+ case 0x01: value = &train->type01; break;
+ case 0x04: value = &train->type04; break;
+ case 0x06: value = &train->type06; break;
+ case 0x07: value = &train->type07; break;
+ case 0x08: value = &train->type08; break;
+ case 0x09: value = &train->type09; break;
+ default:
+ return 0;
+ }
+
+ /* training data index determined by ramcfg strap */
+ if (!(data = nvbios_M0205Sp(bios, i, ramcfg, &ver, &hdr, &M0205S)))
+ return -EINVAL;
+ i = M0205S.data;
+
+ /* training data format information */
+ if (!(data = nvbios_M0209Ep(bios, i, &ver, &hdr, &cnt, &len, &M0209E)))
+ return -EINVAL;
+
+ /* ... and the raw data */
+ if (!(data = nvbios_M0209Sp(bios, i, 0, &ver, &hdr, value)))
+ return -EINVAL;
+
+ if (M0209E.v02_07 == 2) {
+ /* of course! why wouldn't we have a pointer to another entry
+ * in the same table, and use the first one as an array of
+ * remap indices...
+ */
+ if (!(data = nvbios_M0209Sp(bios, M0209E.v03, 0, &ver, &hdr,
+ remap)))
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(value->data); i++)
+ value->data[i] = remap->data[value->data[i]];
+ } else
+ if (M0209E.v02_07 != 1)
+ return -EINVAL;
+
+ train->mask |= 1 << M0205E.type;
+ return 0;
+}
+
+static int
+gk104_ram_train_init_0(struct nvkm_fb *pfb, struct gk104_ram_train *train)
+{
+ int i, j;
+
+ if ((train->mask & 0x03d3) != 0x03d3) {
+ nv_warn(pfb, "missing link training data\n");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < 0x30; i++) {
+ for (j = 0; j < 8; j += 4) {
+ nv_wr32(pfb, 0x10f968 + j, 0x00000000 | (i << 8));
+ nv_wr32(pfb, 0x10f920 + j, 0x00000000 |
+ train->type08.data[i] << 4 |
+ train->type06.data[i]);
+ nv_wr32(pfb, 0x10f918 + j, train->type00.data[i]);
+ nv_wr32(pfb, 0x10f920 + j, 0x00000100 |
+ train->type09.data[i] << 4 |
+ train->type07.data[i]);
+ nv_wr32(pfb, 0x10f918 + j, train->type01.data[i]);
+ }
+ }
+
+ for (j = 0; j < 8; j += 4) {
+ for (i = 0; i < 0x100; i++) {
+ nv_wr32(pfb, 0x10f968 + j, i);
+ nv_wr32(pfb, 0x10f900 + j, train->type04.data[i]);
+ }
+ }
+
+ return 0;
+}
+
+static int
+gk104_ram_train_init(struct nvkm_fb *pfb)
+{
+ u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+ struct gk104_ram_train *train;
+ int ret = -ENOMEM, i;
+
+ if ((train = kzalloc(sizeof(*train), GFP_KERNEL))) {
+ for (i = 0; i < 0x100; i++) {
+ ret = gk104_ram_train_type(pfb, i, ramcfg, train);
+ if (ret && ret != -ENOENT)
+ break;
+ }
+ }
+
+ switch (pfb->ram->type) {
+ case NV_MEM_TYPE_GDDR5:
+ ret = gk104_ram_train_init_0(pfb, train);
+ break;
+ default:
+ ret = 0;
+ break;
+ }
+
+ kfree(train);
+ return ret;
+}
+
+int
+gk104_ram_init(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = (void *)object->parent;
+ struct gk104_ram *ram = (void *)object;
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ u8 ver, hdr, cnt, len, snr, ssz;
+ u32 data, save;
+ int ret, i;
+
+ ret = nvkm_ram_init(&ram->base);
+ if (ret)
+ return ret;
+
+ /* run a bunch of tables from rammap table. there's actually
+ * individual pointers for each rammap entry too, but, nvidia
+ * seem to just run the last two entries' scripts early on in
+ * their init, and never again.. we'll just run 'em all once
+ * for now.
+ *
+ * i strongly suspect that each script is for a separate mode
+ * (likely selected by 0x10f65c's lower bits?), and the
+ * binary driver skips the one that's already been setup by
+ * the init tables.
+ */
+ data = nvbios_rammapTe(bios, &ver, &hdr, &cnt, &len, &snr, &ssz);
+ if (!data || hdr < 0x15)
+ return -EINVAL;
+
+ cnt = nv_ro08(bios, data + 0x14); /* guess at count */
+ data = nv_ro32(bios, data + 0x10); /* guess u32... */
+ save = nv_rd32(pfb, 0x10f65c) & 0x000000f0;
+ for (i = 0; i < cnt; i++, data += 4) {
+ if (i != save >> 4) {
+ nv_mask(pfb, 0x10f65c, 0x000000f0, i << 4);
+ nvbios_exec(&(struct nvbios_init) {
+ .subdev = nv_subdev(pfb),
+ .bios = bios,
+ .offset = nv_ro32(bios, data),
+ .execute = 1,
+ });
+ }
+ }
+ nv_mask(pfb, 0x10f65c, 0x000000f0, save);
+ nv_mask(pfb, 0x10f584, 0x11000000, 0x00000000);
+ nv_wr32(pfb, 0x10ecc0, 0xffffffff);
+ nv_mask(pfb, 0x10f160, 0x00000010, 0x00000010);
+
+ return gk104_ram_train_init(pfb);
+}
+
+static int
+gk104_ram_ctor_data(struct gk104_ram *ram, u8 ramcfg, int i)
+{
+ struct nvkm_fb *pfb = (void *)nv_object(ram)->parent;
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nvkm_ram_data *cfg;
+ struct nvbios_ramcfg *d = &ram->diff;
+ struct nvbios_ramcfg *p, *n;
+ u8 ver, hdr, cnt, len;
+ u32 data;
+ int ret;
+
+ if (!(cfg = kmalloc(sizeof(*cfg), GFP_KERNEL)))
+ return -ENOMEM;
+ p = &list_last_entry(&ram->cfg, typeof(*cfg), head)->bios;
+ n = &cfg->bios;
+
+ /* memory config data for a range of target frequencies */
+ data = nvbios_rammapEp(bios, i, &ver, &hdr, &cnt, &len, &cfg->bios);
+ if (ret = -ENOENT, !data)
+ goto done;
+ if (ret = -ENOSYS, ver != 0x11 || hdr < 0x12)
+ goto done;
+
+ /* ... and a portion specific to the attached memory */
+ data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, ramcfg,
+ &ver, &hdr, &cfg->bios);
+ if (ret = -EINVAL, !data)
+ goto done;
+ if (ret = -ENOSYS, ver != 0x11 || hdr < 0x0a)
+ goto done;
+
+ /* lookup memory timings, if bios says they're present */
+ if (cfg->bios.ramcfg_timing != 0xff) {
+ data = nvbios_timingEp(bios, cfg->bios.ramcfg_timing,
+ &ver, &hdr, &cnt, &len,
+ &cfg->bios);
+ if (ret = -EINVAL, !data)
+ goto done;
+ if (ret = -ENOSYS, ver != 0x20 || hdr < 0x33)
+ goto done;
+ }
+
+ list_add_tail(&cfg->head, &ram->cfg);
+ if (ret = 0, i == 0)
+ goto done;
+
+ d->rammap_11_0a_03fe |= p->rammap_11_0a_03fe != n->rammap_11_0a_03fe;
+ d->rammap_11_09_01ff |= p->rammap_11_09_01ff != n->rammap_11_09_01ff;
+ d->rammap_11_0a_0400 |= p->rammap_11_0a_0400 != n->rammap_11_0a_0400;
+ d->rammap_11_0a_0800 |= p->rammap_11_0a_0800 != n->rammap_11_0a_0800;
+ d->rammap_11_0b_01f0 |= p->rammap_11_0b_01f0 != n->rammap_11_0b_01f0;
+ d->rammap_11_0b_0200 |= p->rammap_11_0b_0200 != n->rammap_11_0b_0200;
+ d->rammap_11_0d |= p->rammap_11_0d != n->rammap_11_0d;
+ d->rammap_11_0f |= p->rammap_11_0f != n->rammap_11_0f;
+ d->rammap_11_0e |= p->rammap_11_0e != n->rammap_11_0e;
+ d->rammap_11_0b_0800 |= p->rammap_11_0b_0800 != n->rammap_11_0b_0800;
+ d->rammap_11_0b_0400 |= p->rammap_11_0b_0400 != n->rammap_11_0b_0400;
+ d->ramcfg_11_01_01 |= p->ramcfg_11_01_01 != n->ramcfg_11_01_01;
+ d->ramcfg_11_01_02 |= p->ramcfg_11_01_02 != n->ramcfg_11_01_02;
+ d->ramcfg_11_01_10 |= p->ramcfg_11_01_10 != n->ramcfg_11_01_10;
+ d->ramcfg_11_02_03 |= p->ramcfg_11_02_03 != n->ramcfg_11_02_03;
+ d->ramcfg_11_08_20 |= p->ramcfg_11_08_20 != n->ramcfg_11_08_20;
+ d->timing_20_30_07 |= p->timing_20_30_07 != n->timing_20_30_07;
+done:
+ if (ret)
+ kfree(cfg);
+ return ret;
+}
+
+static void
+gk104_ram_dtor(struct nvkm_object *object)
+{
+ struct gk104_ram *ram = (void *)object;
+ struct nvkm_ram_data *cfg, *tmp;
+
+ list_for_each_entry_safe(cfg, tmp, &ram->cfg, head) {
+ kfree(cfg);
+ }
+
+ nvkm_ram_destroy(&ram->base);
+}
+
+static int
+gk104_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nvkm_gpio *gpio = nvkm_gpio(pfb);
+ struct dcb_gpio_func func;
+ struct gk104_ram *ram;
+ int ret, i;
+ u8 ramcfg = nvbios_ramcfg_index(nv_subdev(pfb));
+ u32 tmp;
+
+ ret = gf100_ram_create(parent, engine, oclass, 0x022554, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&ram->cfg);
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR3:
+ case NV_MEM_TYPE_GDDR5:
+ ram->base.calc = gk104_ram_calc;
+ ram->base.prog = gk104_ram_prog;
+ ram->base.tidy = gk104_ram_tidy;
+ break;
+ default:
+ nv_warn(pfb, "reclocking of this RAM type is unsupported\n");
+ break;
+ }
+
+ /* calculate a mask of differently configured memory partitions,
+ * because, of course reclocking wasn't complicated enough
+ * already without having to treat some of them differently to
+ * the others....
+ */
+ ram->parts = nv_rd32(pfb, 0x022438);
+ ram->pmask = nv_rd32(pfb, 0x022554);
+ ram->pnuts = 0;
+ for (i = 0, tmp = 0; i < ram->parts; i++) {
+ if (!(ram->pmask & (1 << i))) {
+ u32 cfg1 = nv_rd32(pfb, 0x110204 + (i * 0x1000));
+ if (tmp && tmp != cfg1) {
+ ram->pnuts |= (1 << i);
+ continue;
+ }
+ tmp = cfg1;
+ }
+ }
+
+ /* parse bios data for all rammap table entries up-front, and
+ * build information on whether certain fields differ between
+ * any of the entries.
+ *
+ * the binary driver appears to completely ignore some fields
+ * when all entries contain the same value. at first, it was
+ * hoped that these were mere optimisations and the bios init
+ * tables had configured as per the values here, but there is
+ * evidence now to suggest that this isn't the case and we do
+ * need to treat this condition as a "don't touch" indicator.
+ */
+ for (i = 0; !ret; i++) {
+ ret = gk104_ram_ctor_data(ram, ramcfg, i);
+ if (ret && ret != -ENOENT) {
+ nv_error(pfb, "failed to parse ramcfg data\n");
+ return ret;
+ }
+ }
+
+ /* parse bios data for both pll's */
+ ret = nvbios_pll_parse(bios, 0x0c, &ram->fuc.refpll);
+ if (ret) {
+ nv_error(pfb, "mclk refpll data not found\n");
+ return ret;
+ }
+
+ ret = nvbios_pll_parse(bios, 0x04, &ram->fuc.mempll);
+ if (ret) {
+ nv_error(pfb, "mclk pll data not found\n");
+ return ret;
+ }
+
+ /* lookup memory voltage gpios */
+ ret = gpio->find(gpio, 0, 0x18, DCB_GPIO_UNUSED, &func);
+ if (ret == 0) {
+ ram->fuc.r_gpioMV = ramfuc_reg(0x00d610 + (func.line * 0x04));
+ ram->fuc.r_funcMV[0] = (func.log[0] ^ 2) << 12;
+ ram->fuc.r_funcMV[1] = (func.log[1] ^ 2) << 12;
+ }
+
+ ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+ if (ret == 0) {
+ ram->fuc.r_gpio2E = ramfuc_reg(0x00d610 + (func.line * 0x04));
+ ram->fuc.r_func2E[0] = (func.log[0] ^ 2) << 12;
+ ram->fuc.r_func2E[1] = (func.log[1] ^ 2) << 12;
+ }
+
+ ram->fuc.r_gpiotrig = ramfuc_reg(0x00d604);
+
+ ram->fuc.r_0x132020 = ramfuc_reg(0x132020);
+ ram->fuc.r_0x132028 = ramfuc_reg(0x132028);
+ ram->fuc.r_0x132024 = ramfuc_reg(0x132024);
+ ram->fuc.r_0x132030 = ramfuc_reg(0x132030);
+ ram->fuc.r_0x132034 = ramfuc_reg(0x132034);
+ ram->fuc.r_0x132000 = ramfuc_reg(0x132000);
+ ram->fuc.r_0x132004 = ramfuc_reg(0x132004);
+ ram->fuc.r_0x132040 = ramfuc_reg(0x132040);
+
+ ram->fuc.r_0x10f248 = ramfuc_reg(0x10f248);
+ ram->fuc.r_0x10f290 = ramfuc_reg(0x10f290);
+ ram->fuc.r_0x10f294 = ramfuc_reg(0x10f294);
+ ram->fuc.r_0x10f298 = ramfuc_reg(0x10f298);
+ ram->fuc.r_0x10f29c = ramfuc_reg(0x10f29c);
+ ram->fuc.r_0x10f2a0 = ramfuc_reg(0x10f2a0);
+ ram->fuc.r_0x10f2a4 = ramfuc_reg(0x10f2a4);
+ ram->fuc.r_0x10f2a8 = ramfuc_reg(0x10f2a8);
+ ram->fuc.r_0x10f2ac = ramfuc_reg(0x10f2ac);
+ ram->fuc.r_0x10f2cc = ramfuc_reg(0x10f2cc);
+ ram->fuc.r_0x10f2e8 = ramfuc_reg(0x10f2e8);
+ ram->fuc.r_0x10f250 = ramfuc_reg(0x10f250);
+ ram->fuc.r_0x10f24c = ramfuc_reg(0x10f24c);
+ ram->fuc.r_0x10fec4 = ramfuc_reg(0x10fec4);
+ ram->fuc.r_0x10fec8 = ramfuc_reg(0x10fec8);
+ ram->fuc.r_0x10f604 = ramfuc_reg(0x10f604);
+ ram->fuc.r_0x10f614 = ramfuc_reg(0x10f614);
+ ram->fuc.r_0x10f610 = ramfuc_reg(0x10f610);
+ ram->fuc.r_0x100770 = ramfuc_reg(0x100770);
+ ram->fuc.r_0x100778 = ramfuc_reg(0x100778);
+ ram->fuc.r_0x10f224 = ramfuc_reg(0x10f224);
+
+ ram->fuc.r_0x10f870 = ramfuc_reg(0x10f870);
+ ram->fuc.r_0x10f698 = ramfuc_reg(0x10f698);
+ ram->fuc.r_0x10f694 = ramfuc_reg(0x10f694);
+ ram->fuc.r_0x10f6b8 = ramfuc_reg(0x10f6b8);
+ ram->fuc.r_0x10f808 = ramfuc_reg(0x10f808);
+ ram->fuc.r_0x10f670 = ramfuc_reg(0x10f670);
+ ram->fuc.r_0x10f60c = ramfuc_reg(0x10f60c);
+ ram->fuc.r_0x10f830 = ramfuc_reg(0x10f830);
+ ram->fuc.r_0x1373ec = ramfuc_reg(0x1373ec);
+ ram->fuc.r_0x10f800 = ramfuc_reg(0x10f800);
+ ram->fuc.r_0x10f82c = ramfuc_reg(0x10f82c);
+
+ ram->fuc.r_0x10f978 = ramfuc_reg(0x10f978);
+ ram->fuc.r_0x10f910 = ramfuc_reg(0x10f910);
+ ram->fuc.r_0x10f914 = ramfuc_reg(0x10f914);
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_GDDR5:
+ ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+ ram->fuc.r_mr[1] = ramfuc_reg(0x10f330);
+ ram->fuc.r_mr[2] = ramfuc_reg(0x10f334);
+ ram->fuc.r_mr[3] = ramfuc_reg(0x10f338);
+ ram->fuc.r_mr[4] = ramfuc_reg(0x10f33c);
+ ram->fuc.r_mr[5] = ramfuc_reg(0x10f340);
+ ram->fuc.r_mr[6] = ramfuc_reg(0x10f344);
+ ram->fuc.r_mr[7] = ramfuc_reg(0x10f348);
+ ram->fuc.r_mr[8] = ramfuc_reg(0x10f354);
+ ram->fuc.r_mr[15] = ramfuc_reg(0x10f34c);
+ break;
+ case NV_MEM_TYPE_DDR3:
+ ram->fuc.r_mr[0] = ramfuc_reg(0x10f300);
+ ram->fuc.r_mr[2] = ramfuc_reg(0x10f320);
+ break;
+ default:
+ break;
+ }
+
+ ram->fuc.r_0x62c000 = ramfuc_reg(0x62c000);
+ ram->fuc.r_0x10f200 = ramfuc_reg(0x10f200);
+ ram->fuc.r_0x10f210 = ramfuc_reg(0x10f210);
+ ram->fuc.r_0x10f310 = ramfuc_reg(0x10f310);
+ ram->fuc.r_0x10f314 = ramfuc_reg(0x10f314);
+ ram->fuc.r_0x10f318 = ramfuc_reg(0x10f318);
+ ram->fuc.r_0x10f090 = ramfuc_reg(0x10f090);
+ ram->fuc.r_0x10f69c = ramfuc_reg(0x10f69c);
+ ram->fuc.r_0x10f824 = ramfuc_reg(0x10f824);
+ ram->fuc.r_0x1373f0 = ramfuc_reg(0x1373f0);
+ ram->fuc.r_0x1373f4 = ramfuc_reg(0x1373f4);
+ ram->fuc.r_0x137320 = ramfuc_reg(0x137320);
+ ram->fuc.r_0x10f65c = ramfuc_reg(0x10f65c);
+ ram->fuc.r_0x10f6bc = ramfuc_reg(0x10f6bc);
+ ram->fuc.r_0x100710 = ramfuc_reg(0x100710);
+ ram->fuc.r_0x100750 = ramfuc_reg(0x100750);
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_ram_ctor,
+ .dtor = gk104_ram_dtor,
+ .init = gk104_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c
new file mode 100644
index 000000000000..5f30db140b47
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgk20a.c
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "priv.h"
+
+#include <core/device.h>
+
+struct gk20a_mem {
+ struct nvkm_mem base;
+ void *cpuaddr;
+ dma_addr_t handle;
+};
+#define to_gk20a_mem(m) container_of(m, struct gk20a_mem, base)
+
+static void
+gk20a_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
+{
+ struct device *dev = nv_device_base(nv_device(pfb));
+ struct gk20a_mem *mem = to_gk20a_mem(*pmem);
+
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
+
+ if (likely(mem->cpuaddr))
+ dma_free_coherent(dev, mem->base.size << PAGE_SHIFT,
+ mem->cpuaddr, mem->handle);
+
+ kfree(mem->base.pages);
+ kfree(mem);
+}
+
+static int
+gk20a_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nvkm_mem **pmem)
+{
+ struct device *dev = nv_device_base(nv_device(pfb));
+ struct gk20a_mem *mem;
+ u32 type = memtype & 0xff;
+ u32 npages, order;
+ int i;
+
+ nv_debug(pfb, "%s: size: %llx align: %x, ncmin: %x\n", __func__, size,
+ align, ncmin);
+
+ npages = size >> PAGE_SHIFT;
+ if (npages == 0)
+ npages = 1;
+
+ if (align == 0)
+ align = PAGE_SIZE;
+ align >>= PAGE_SHIFT;
+
+ /* round alignment to the next power of 2, if needed */
+ order = fls(align);
+ if ((align & (align - 1)) == 0)
+ order--;
+ align = BIT(order);
+
+ /* ensure returned address is correctly aligned */
+ npages = max(align, npages);
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ mem->base.size = npages;
+ mem->base.memtype = type;
+
+ mem->base.pages = kzalloc(sizeof(dma_addr_t) * npages, GFP_KERNEL);
+ if (!mem->base.pages) {
+ kfree(mem);
+ return -ENOMEM;
+ }
+
+ *pmem = &mem->base;
+
+ mem->cpuaddr = dma_alloc_coherent(dev, npages << PAGE_SHIFT,
+ &mem->handle, GFP_KERNEL);
+ if (!mem->cpuaddr) {
+ nv_error(pfb, "%s: cannot allocate memory!\n", __func__);
+ gk20a_ram_put(pfb, pmem);
+ return -ENOMEM;
+ }
+
+ align <<= PAGE_SHIFT;
+
+ /* alignment check */
+ if (unlikely(mem->handle & (align - 1)))
+ nv_warn(pfb, "memory not aligned as requested: %pad (0x%x)\n",
+ &mem->handle, align);
+
+ nv_debug(pfb, "alloc size: 0x%x, align: 0x%x, paddr: %pad, vaddr: %p\n",
+ npages << PAGE_SHIFT, align, &mem->handle, mem->cpuaddr);
+
+ for (i = 0; i < npages; i++)
+ mem->base.pages[i] = mem->handle + (PAGE_SIZE * i);
+
+ mem->base.offset = (u64)mem->base.pages[0];
+ return 0;
+}
+
+static int
+gk20a_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 datasize,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_ram *ram;
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+ ram->type = NV_MEM_TYPE_STOLEN;
+ ram->size = get_num_physpages() << PAGE_SHIFT;
+
+ ram->get = gk20a_ram_get;
+ ram->put = gk20a_ram_put;
+ return 0;
+}
+
+struct nvkm_oclass
+gk20a_ram_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_ram_ctor,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
new file mode 100644
index 000000000000..a298b39f55c5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgm107.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "gf100.h"
+
+struct gm107_ram {
+ struct nvkm_ram base;
+};
+
+static int
+gm107_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gm107_ram *ram;
+ int ret;
+
+ ret = gf100_ram_create(parent, engine, oclass, 0x021c14, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass
+gm107_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm107_ram_ctor,
+ .dtor = _nvkm_ram_dtor,
+ .init = gk104_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c
new file mode 100644
index 000000000000..24176401b49b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramgt215.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Roy Spliet <rspliet@eclipso.eu>
+ */
+
+#include "ramfuc.h"
+#include "nv50.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/M0205.h>
+#include <subdev/bios/rammap.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk/gt215.h>
+#include <subdev/gpio.h>
+
+/* XXX: Remove when memx gains GPIO support */
+extern int nv50_gpio_location(int line, u32 *reg, u32 *shift);
+
+struct gt215_ramfuc {
+ struct ramfuc base;
+ struct ramfuc_reg r_0x001610;
+ struct ramfuc_reg r_0x001700;
+ struct ramfuc_reg r_0x002504;
+ struct ramfuc_reg r_0x004000;
+ struct ramfuc_reg r_0x004004;
+ struct ramfuc_reg r_0x004018;
+ struct ramfuc_reg r_0x004128;
+ struct ramfuc_reg r_0x004168;
+ struct ramfuc_reg r_0x100080;
+ struct ramfuc_reg r_0x100200;
+ struct ramfuc_reg r_0x100210;
+ struct ramfuc_reg r_0x100220[9];
+ struct ramfuc_reg r_0x100264;
+ struct ramfuc_reg r_0x1002d0;
+ struct ramfuc_reg r_0x1002d4;
+ struct ramfuc_reg r_0x1002dc;
+ struct ramfuc_reg r_0x10053c;
+ struct ramfuc_reg r_0x1005a0;
+ struct ramfuc_reg r_0x1005a4;
+ struct ramfuc_reg r_0x100700;
+ struct ramfuc_reg r_0x100714;
+ struct ramfuc_reg r_0x100718;
+ struct ramfuc_reg r_0x10071c;
+ struct ramfuc_reg r_0x100720;
+ struct ramfuc_reg r_0x100760;
+ struct ramfuc_reg r_0x1007a0;
+ struct ramfuc_reg r_0x1007e0;
+ struct ramfuc_reg r_0x100da0;
+ struct ramfuc_reg r_0x10f804;
+ struct ramfuc_reg r_0x1110e0;
+ struct ramfuc_reg r_0x111100;
+ struct ramfuc_reg r_0x111104;
+ struct ramfuc_reg r_0x1111e0;
+ struct ramfuc_reg r_0x111400;
+ struct ramfuc_reg r_0x611200;
+ struct ramfuc_reg r_mr[4];
+ struct ramfuc_reg r_gpioFBVREF;
+};
+
+struct gt215_ltrain {
+ enum {
+ NVA3_TRAIN_UNKNOWN,
+ NVA3_TRAIN_UNSUPPORTED,
+ NVA3_TRAIN_ONCE,
+ NVA3_TRAIN_EXEC,
+ NVA3_TRAIN_DONE
+ } state;
+ u32 r_100720;
+ u32 r_1111e0;
+ u32 r_111400;
+ struct nvkm_mem *mem;
+};
+
+struct gt215_ram {
+ struct nvkm_ram base;
+ struct gt215_ramfuc fuc;
+ struct gt215_ltrain ltrain;
+};
+
+void
+gt215_link_train_calc(u32 *vals, struct gt215_ltrain *train)
+{
+ int i, lo, hi;
+ u8 median[8], bins[4] = {0, 0, 0, 0}, bin = 0, qty = 0;
+
+ for (i = 0; i < 8; i++) {
+ for (lo = 0; lo < 0x40; lo++) {
+ if (!(vals[lo] & 0x80000000))
+ continue;
+ if (vals[lo] & (0x101 << i))
+ break;
+ }
+
+ if (lo == 0x40)
+ return;
+
+ for (hi = lo + 1; hi < 0x40; hi++) {
+ if (!(vals[lo] & 0x80000000))
+ continue;
+ if (!(vals[hi] & (0x101 << i))) {
+ hi--;
+ break;
+ }
+ }
+
+ median[i] = ((hi - lo) >> 1) + lo;
+ bins[(median[i] & 0xf0) >> 4]++;
+ median[i] += 0x30;
+ }
+
+ /* Find the best value for 0x1111e0 */
+ for (i = 0; i < 4; i++) {
+ if (bins[i] > qty) {
+ bin = i + 3;
+ qty = bins[i];
+ }
+ }
+
+ train->r_100720 = 0;
+ for (i = 0; i < 8; i++) {
+ median[i] = max(median[i], (u8) (bin << 4));
+ median[i] = min(median[i], (u8) ((bin << 4) | 0xf));
+
+ train->r_100720 |= ((median[i] & 0x0f) << (i << 2));
+ }
+
+ train->r_1111e0 = 0x02000000 | (bin * 0x101);
+ train->r_111400 = 0x0;
+}
+
+/*
+ * Link training for (at least) DDR3
+ */
+int
+gt215_link_train(struct nvkm_fb *pfb)
+{
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct gt215_ram *ram = (void *)pfb->ram;
+ struct nvkm_clk *clk = nvkm_clk(pfb);
+ struct gt215_ltrain *train = &ram->ltrain;
+ struct nvkm_device *device = nv_device(pfb);
+ struct gt215_ramfuc *fuc = &ram->fuc;
+ u32 *result, r1700;
+ int ret, i;
+ struct nvbios_M0205T M0205T = { 0 };
+ u8 ver, hdr, cnt, len, snr, ssz;
+ unsigned int clk_current;
+ unsigned long flags;
+ unsigned long *f = &flags;
+
+ if (nvkm_boolopt(device->cfgopt, "NvMemExec", true) != true)
+ return -ENOSYS;
+
+ /* XXX: Multiple partitions? */
+ result = kmalloc(64 * sizeof(u32), GFP_KERNEL);
+ if (!result)
+ return -ENOMEM;
+
+ train->state = NVA3_TRAIN_EXEC;
+
+ /* Clock speeds for training and back */
+ nvbios_M0205Tp(bios, &ver, &hdr, &cnt, &len, &snr, &ssz, &M0205T);
+ if (M0205T.freq == 0)
+ return -ENOENT;
+
+ clk_current = clk->read(clk, nv_clk_src_mem);
+
+ ret = gt215_clk_pre(clk, f);
+ if (ret)
+ goto out;
+
+ /* First: clock up/down */
+ ret = ram->base.calc(pfb, (u32) M0205T.freq * 1000);
+ if (ret)
+ goto out;
+
+ /* Do this *after* calc, eliminates write in script */
+ nv_wr32(pfb, 0x111400, 0x00000000);
+ /* XXX: Magic writes that improve train reliability? */
+ nv_mask(pfb, 0x100674, 0x0000ffff, 0x00000000);
+ nv_mask(pfb, 0x1005e4, 0x0000ffff, 0x00000000);
+ nv_mask(pfb, 0x100b0c, 0x000000ff, 0x00000000);
+ nv_wr32(pfb, 0x100c04, 0x00000400);
+
+ /* Now the training script */
+ r1700 = ram_rd32(fuc, 0x001700);
+
+ ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+ ram_wr32(fuc, 0x611200, 0x3300);
+ ram_wait_vblank(fuc);
+ ram_wait(fuc, 0x611200, 0x00000003, 0x00000000, 500000);
+ ram_mask(fuc, 0x001610, 0x00000083, 0x00000003);
+ ram_mask(fuc, 0x100080, 0x00000020, 0x00000000);
+ ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
+ ram_wr32(fuc, 0x001700, 0x00000000);
+
+ ram_train(fuc);
+
+ /* Reset */
+ ram_mask(fuc, 0x10f804, 0x80000000, 0x80000000);
+ ram_wr32(fuc, 0x10053c, 0x0);
+ ram_wr32(fuc, 0x100720, train->r_100720);
+ ram_wr32(fuc, 0x1111e0, train->r_1111e0);
+ ram_wr32(fuc, 0x111400, train->r_111400);
+ ram_nuke(fuc, 0x100080);
+ ram_mask(fuc, 0x100080, 0x00000020, 0x00000020);
+ ram_nsec(fuc, 1000);
+
+ ram_wr32(fuc, 0x001700, r1700);
+ ram_mask(fuc, 0x001610, 0x00000083, 0x00000080);
+ ram_wr32(fuc, 0x611200, 0x3330);
+ ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
+
+ ram_exec(fuc, true);
+
+ ram->base.calc(pfb, clk_current);
+ ram_exec(fuc, true);
+
+ /* Post-processing, avoids flicker */
+ nv_mask(pfb, 0x616308, 0x10, 0x10);
+ nv_mask(pfb, 0x616b08, 0x10, 0x10);
+
+ gt215_clk_post(clk, f);
+
+ ram_train_result(pfb, result, 64);
+ for (i = 0; i < 64; i++)
+ nv_debug(pfb, "Train: %08x", result[i]);
+ gt215_link_train_calc(result, train);
+
+ nv_debug(pfb, "Train: %08x %08x %08x", train->r_100720,
+ train->r_1111e0, train->r_111400);
+
+ kfree(result);
+
+ train->state = NVA3_TRAIN_DONE;
+
+ return ret;
+
+out:
+ if(ret == -EBUSY)
+ f = NULL;
+
+ train->state = NVA3_TRAIN_UNSUPPORTED;
+
+ gt215_clk_post(clk, f);
+ return ret;
+}
+
+int
+gt215_link_train_init(struct nvkm_fb *pfb)
+{
+ static const u32 pattern[16] = {
+ 0xaaaaaaaa, 0xcccccccc, 0xdddddddd, 0xeeeeeeee,
+ 0x00000000, 0x11111111, 0x44444444, 0xdddddddd,
+ 0x33333333, 0x55555555, 0x77777777, 0x66666666,
+ 0x99999999, 0x88888888, 0xeeeeeeee, 0xbbbbbbbb,
+ };
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct gt215_ram *ram = (void *)pfb->ram;
+ struct gt215_ltrain *train = &ram->ltrain;
+ struct nvkm_mem *mem;
+ struct nvbios_M0205E M0205E;
+ u8 ver, hdr, cnt, len;
+ u32 r001700;
+ int ret, i = 0;
+
+ train->state = NVA3_TRAIN_UNSUPPORTED;
+
+ /* We support type "5"
+ * XXX: training pattern table appears to be unused for this routine */
+ if (!nvbios_M0205Ep(bios, i, &ver, &hdr, &cnt, &len, &M0205E))
+ return -ENOENT;
+
+ if (M0205E.type != 5)
+ return 0;
+
+ train->state = NVA3_TRAIN_ONCE;
+
+ ret = pfb->ram->get(pfb, 0x8000, 0x10000, 0, 0x800, &ram->ltrain.mem);
+ if (ret)
+ return ret;
+
+ mem = ram->ltrain.mem;
+
+ nv_wr32(pfb, 0x100538, 0x10000000 | (mem->offset >> 16));
+ nv_wr32(pfb, 0x1005a8, 0x0000ffff);
+ nv_mask(pfb, 0x10f800, 0x00000001, 0x00000001);
+
+ for (i = 0; i < 0x30; i++) {
+ nv_wr32(pfb, 0x10f8c0, (i << 8) | i);
+ nv_wr32(pfb, 0x10f900, pattern[i % 16]);
+ }
+
+ for (i = 0; i < 0x30; i++) {
+ nv_wr32(pfb, 0x10f8e0, (i << 8) | i);
+ nv_wr32(pfb, 0x10f920, pattern[i % 16]);
+ }
+
+ /* And upload the pattern */
+ r001700 = nv_rd32(pfb, 0x1700);
+ nv_wr32(pfb, 0x1700, mem->offset >> 16);
+ for (i = 0; i < 16; i++)
+ nv_wr32(pfb, 0x700000 + (i << 2), pattern[i]);
+ for (i = 0; i < 16; i++)
+ nv_wr32(pfb, 0x700100 + (i << 2), pattern[i]);
+ nv_wr32(pfb, 0x1700, r001700);
+
+ train->r_100720 = nv_rd32(pfb, 0x100720);
+ train->r_1111e0 = nv_rd32(pfb, 0x1111e0);
+ train->r_111400 = nv_rd32(pfb, 0x111400);
+ return 0;
+}
+
+void
+gt215_link_train_fini(struct nvkm_fb *pfb)
+{
+ struct gt215_ram *ram = (void *)pfb->ram;
+
+ if (ram->ltrain.mem)
+ pfb->ram->put(pfb, &ram->ltrain.mem);
+}
+
+/*
+ * RAM reclocking
+ */
+#define T(t) cfg->timing_10_##t
+static int
+gt215_ram_timing_calc(struct nvkm_fb *pfb, u32 *timing)
+{
+ struct gt215_ram *ram = (void *)pfb->ram;
+ struct nvbios_ramcfg *cfg = &ram->base.target.bios;
+ int tUNK_base, tUNK_40_0, prevCL;
+ u32 cur2, cur3, cur7, cur8;
+
+ cur2 = nv_rd32(pfb, 0x100228);
+ cur3 = nv_rd32(pfb, 0x10022c);
+ cur7 = nv_rd32(pfb, 0x10023c);
+ cur8 = nv_rd32(pfb, 0x100240);
+
+
+ switch ((!T(CWL)) * ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ T(CWL) = T(CL) - 1;
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ T(CWL) = ((cur2 & 0xff000000) >> 24) + 1;
+ break;
+ }
+
+ prevCL = (cur3 & 0x000000ff) + 1;
+ tUNK_base = ((cur7 & 0x00ff0000) >> 16) - prevCL;
+
+ timing[0] = (T(RP) << 24 | T(RAS) << 16 | T(RFC) << 8 | T(RC));
+ timing[1] = (T(WR) + 1 + T(CWL)) << 24 |
+ max_t(u8,T(18), 1) << 16 |
+ (T(WTR) + 1 + T(CWL)) << 8 |
+ (5 + T(CL) - T(CWL));
+ timing[2] = (T(CWL) - 1) << 24 |
+ (T(RRD) << 16) |
+ (T(RCDWR) << 8) |
+ T(RCDRD);
+ timing[3] = (cur3 & 0x00ff0000) |
+ (0x30 + T(CL)) << 24 |
+ (0xb + T(CL)) << 8 |
+ (T(CL) - 1);
+ timing[4] = T(20) << 24 |
+ T(21) << 16 |
+ T(13) << 8 |
+ T(13);
+ timing[5] = T(RFC) << 24 |
+ max_t(u8,T(RCDRD), T(RCDWR)) << 16 |
+ max_t(u8, (T(CWL) + 6), (T(CL) + 2)) << 8 |
+ T(RP);
+ timing[6] = (0x5a + T(CL)) << 16 |
+ max_t(u8, 1, (6 - T(CL) + T(CWL))) << 8 |
+ (0x50 + T(CL) - T(CWL));
+ timing[7] = (cur7 & 0xff000000) |
+ ((tUNK_base + T(CL)) << 16) |
+ 0x202;
+ timing[8] = cur8 & 0xffffff00;
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ case NV_MEM_TYPE_GDDR3:
+ tUNK_40_0 = prevCL - (cur8 & 0xff);
+ if (tUNK_40_0 > 0)
+ timing[8] |= T(CL);
+ break;
+ default:
+ break;
+ }
+
+ nv_debug(pfb, "Entry: 220: %08x %08x %08x %08x\n",
+ timing[0], timing[1], timing[2], timing[3]);
+ nv_debug(pfb, " 230: %08x %08x %08x %08x\n",
+ timing[4], timing[5], timing[6], timing[7]);
+ nv_debug(pfb, " 240: %08x\n", timing[8]);
+ return 0;
+}
+#undef T
+
+static void
+nvkm_sddr2_dll_reset(struct gt215_ramfuc *fuc)
+{
+ ram_mask(fuc, mr[0], 0x100, 0x100);
+ ram_nsec(fuc, 1000);
+ ram_mask(fuc, mr[0], 0x100, 0x000);
+ ram_nsec(fuc, 1000);
+}
+
+static void
+nvkm_sddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr)
+{
+ u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+ if (!(mr1_old & 0x1)) {
+ ram_wr32(fuc, 0x1002d4, 0x00000001);
+ ram_wr32(fuc, mr[1], mr[1]);
+ ram_nsec(fuc, 1000);
+ }
+}
+
+static void
+nvkm_gddr3_dll_disable(struct gt215_ramfuc *fuc, u32 *mr)
+{
+ u32 mr1_old = ram_rd32(fuc, mr[1]);
+
+ if (!(mr1_old & 0x40)) {
+ ram_wr32(fuc, mr[1], mr[1]);
+ ram_nsec(fuc, 1000);
+ }
+}
+
+static void
+gt215_ram_lock_pll(struct gt215_ramfuc *fuc, struct gt215_clk_info *mclk)
+{
+ ram_wr32(fuc, 0x004004, mclk->pll);
+ ram_mask(fuc, 0x004000, 0x00000001, 0x00000001);
+ ram_mask(fuc, 0x004000, 0x00000010, 0x00000000);
+ ram_wait(fuc, 0x004000, 0x00020000, 0x00020000, 64000);
+ ram_mask(fuc, 0x004000, 0x00000010, 0x00000010);
+}
+
+static void
+gt215_ram_fbvref(struct gt215_ramfuc *fuc, u32 val)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(fuc->base.pfb);
+ struct dcb_gpio_func func;
+ u32 reg, sh, gpio_val;
+ int ret;
+
+ if (gpio->get(gpio, 0, 0x2e, DCB_GPIO_UNUSED) != val) {
+ ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+ if (ret)
+ return;
+
+ nv50_gpio_location(func.line, &reg, &sh);
+ gpio_val = ram_rd32(fuc, gpioFBVREF);
+ if (gpio_val & (8 << sh))
+ val = !val;
+
+ ram_mask(fuc, gpioFBVREF, (0x3 << sh), ((val | 0x2) << sh));
+ ram_nsec(fuc, 20000);
+ }
+}
+
+static int
+gt215_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct gt215_ram *ram = (void *)pfb->ram;
+ struct gt215_ramfuc *fuc = &ram->fuc;
+ struct gt215_ltrain *train = &ram->ltrain;
+ struct gt215_clk_info mclk;
+ struct nvkm_ram_data *next;
+ u8 ver, hdr, cnt, len, strap;
+ u32 data;
+ u32 r004018, r100760, r100da0, r111100, ctrl;
+ u32 unk714, unk718, unk71c;
+ int ret, i;
+ u32 timing[9];
+ bool pll2pll;
+
+ next = &ram->base.target;
+ next->freq = freq;
+ ram->base.next = next;
+
+ if (ram->ltrain.state == NVA3_TRAIN_ONCE)
+ gt215_link_train(pfb);
+
+ /* lookup memory config data relevant to the target frequency */
+ i = 0;
+ data = nvbios_rammapEm(bios, freq / 1000, &ver, &hdr, &cnt, &len,
+ &next->bios);
+ if (!data || ver != 0x10 || hdr < 0x05) {
+ nv_error(pfb, "invalid/missing rammap entry\n");
+ return -EINVAL;
+ }
+
+ /* locate specific data set for the attached memory */
+ strap = nvbios_ramcfg_index(nv_subdev(pfb));
+ if (strap >= cnt) {
+ nv_error(pfb, "invalid ramcfg strap\n");
+ return -EINVAL;
+ }
+
+ data = nvbios_rammapSp(bios, data, ver, hdr, cnt, len, strap,
+ &ver, &hdr, &next->bios);
+ if (!data || ver != 0x10 || hdr < 0x09) {
+ nv_error(pfb, "invalid/missing ramcfg entry\n");
+ return -EINVAL;
+ }
+
+ /* lookup memory timings, if bios says they're present */
+ if (next->bios.ramcfg_timing != 0xff) {
+ data = nvbios_timingEp(bios, next->bios.ramcfg_timing,
+ &ver, &hdr, &cnt, &len,
+ &next->bios);
+ if (!data || ver != 0x10 || hdr < 0x17) {
+ nv_error(pfb, "invalid/missing timing entry\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = gt215_pll_info(nvkm_clk(pfb), 0x12, 0x4000, freq, &mclk);
+ if (ret < 0) {
+ nv_error(pfb, "failed mclk calculation\n");
+ return ret;
+ }
+
+ gt215_ram_timing_calc(pfb, timing);
+
+ ret = ram_init(fuc, pfb);
+ if (ret)
+ return ret;
+
+ /* Determine ram-specific MR values */
+ ram->base.mr[0] = ram_rd32(fuc, mr[0]);
+ ram->base.mr[1] = ram_rd32(fuc, mr[1]);
+ ram->base.mr[2] = ram_rd32(fuc, mr[2]);
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ ret = nvkm_sddr2_calc(&ram->base);
+ break;
+ case NV_MEM_TYPE_DDR3:
+ ret = nvkm_sddr3_calc(&ram->base);
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ ret = nvkm_gddr3_calc(&ram->base);
+ break;
+ default:
+ ret = -ENOSYS;
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ /* XXX: where the fuck does 750MHz come from? */
+ if (freq <= 750000) {
+ r004018 = 0x10000000;
+ r100760 = 0x22222222;
+ r100da0 = 0x00000010;
+ } else {
+ r004018 = 0x00000000;
+ r100760 = 0x00000000;
+ r100da0 = 0x00000000;
+ }
+
+ if (!next->bios.ramcfg_10_DLLoff)
+ r004018 |= 0x00004000;
+
+ /* pll2pll requires to switch to a safe clock first */
+ ctrl = ram_rd32(fuc, 0x004000);
+ pll2pll = (!(ctrl & 0x00000008)) && mclk.pll;
+
+ /* Pre, NVIDIA does this outside the script */
+ if (next->bios.ramcfg_10_02_10) {
+ ram_mask(fuc, 0x111104, 0x00000600, 0x00000000);
+ } else {
+ ram_mask(fuc, 0x111100, 0x40000000, 0x40000000);
+ ram_mask(fuc, 0x111104, 0x00000180, 0x00000000);
+ }
+ /* Always disable this bit during reclock */
+ ram_mask(fuc, 0x100200, 0x00000800, 0x00000000);
+
+ /* If switching from non-pll to pll, lock before disabling FB */
+ if (mclk.pll && !pll2pll) {
+ ram_mask(fuc, 0x004128, 0x003f3141, mclk.clk | 0x00000101);
+ gt215_ram_lock_pll(fuc, &mclk);
+ }
+
+ /* Start with disabling some CRTCs and PFIFO? */
+ ram_wait_vblank(fuc);
+ ram_wr32(fuc, 0x611200, 0x3300);
+ ram_mask(fuc, 0x002504, 0x1, 0x1);
+ ram_nsec(fuc, 10000);
+ ram_wait(fuc, 0x002504, 0x10, 0x10, 20000); /* XXX: or longer? */
+ ram_block(fuc);
+ ram_nsec(fuc, 2000);
+
+ if (!next->bios.ramcfg_10_02_10) {
+ if (ram->base.type == NV_MEM_TYPE_GDDR3)
+ ram_mask(fuc, 0x111100, 0x04020000, 0x00020000);
+ else
+ ram_mask(fuc, 0x111100, 0x04020000, 0x04020000);
+ }
+
+ /* If we're disabling the DLL, do it now */
+ switch (next->bios.ramcfg_10_DLLoff * ram->base.type) {
+ case NV_MEM_TYPE_DDR3:
+ nvkm_sddr3_dll_disable(fuc, ram->base.mr);
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ nvkm_gddr3_dll_disable(fuc, ram->base.mr);
+ break;
+ }
+
+ if (fuc->r_gpioFBVREF.addr && next->bios.timing_10_ODT)
+ gt215_ram_fbvref(fuc, 0);
+
+ /* Brace RAM for impact */
+ ram_wr32(fuc, 0x1002d4, 0x00000001);
+ ram_wr32(fuc, 0x1002d0, 0x00000001);
+ ram_wr32(fuc, 0x1002d0, 0x00000001);
+ ram_wr32(fuc, 0x100210, 0x00000000);
+ ram_wr32(fuc, 0x1002dc, 0x00000001);
+ ram_nsec(fuc, 2000);
+
+ if (nv_device(pfb)->chipset == 0xa3 && freq <= 500000)
+ ram_mask(fuc, 0x100700, 0x00000006, 0x00000006);
+
+ /* Fiddle with clocks */
+ /* There's 4 scenario's
+ * pll->pll: first switch to a 324MHz clock, set up new PLL, switch
+ * clk->pll: Set up new PLL, switch
+ * pll->clk: Set up clock, switch
+ * clk->clk: Overwrite ctrl and other bits, switch */
+
+ /* Switch to regular clock - 324MHz */
+ if (pll2pll) {
+ ram_mask(fuc, 0x004000, 0x00000004, 0x00000004);
+ ram_mask(fuc, 0x004168, 0x003f3141, 0x00083101);
+ ram_mask(fuc, 0x004000, 0x00000008, 0x00000008);
+ ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
+ ram_wr32(fuc, 0x004018, 0x00001000);
+ gt215_ram_lock_pll(fuc, &mclk);
+ }
+
+ if (mclk.pll) {
+ ram_mask(fuc, 0x004000, 0x00000105, 0x00000105);
+ ram_wr32(fuc, 0x004018, 0x00001000 | r004018);
+ ram_wr32(fuc, 0x100da0, r100da0);
+ } else {
+ ram_mask(fuc, 0x004168, 0x003f3141, mclk.clk | 0x00000101);
+ ram_mask(fuc, 0x004000, 0x00000108, 0x00000008);
+ ram_mask(fuc, 0x1110e0, 0x00088000, 0x00088000);
+ ram_wr32(fuc, 0x004018, 0x00009000 | r004018);
+ ram_wr32(fuc, 0x100da0, r100da0);
+ }
+ ram_nsec(fuc, 20000);
+
+ if (next->bios.rammap_10_04_08) {
+ ram_wr32(fuc, 0x1005a0, next->bios.ramcfg_10_06 << 16 |
+ next->bios.ramcfg_10_05 << 8 |
+ next->bios.ramcfg_10_05);
+ ram_wr32(fuc, 0x1005a4, next->bios.ramcfg_10_08 << 8 |
+ next->bios.ramcfg_10_07);
+ ram_wr32(fuc, 0x10f804, next->bios.ramcfg_10_09_f0 << 20 |
+ next->bios.ramcfg_10_03_0f << 16 |
+ next->bios.ramcfg_10_09_0f |
+ 0x80000000);
+ ram_mask(fuc, 0x10053c, 0x00001000, 0x00000000);
+ } else {
+ if (train->state == NVA3_TRAIN_DONE) {
+ ram_wr32(fuc, 0x100080, 0x1020);
+ ram_mask(fuc, 0x111400, 0xffffffff, train->r_111400);
+ ram_mask(fuc, 0x1111e0, 0xffffffff, train->r_1111e0);
+ ram_mask(fuc, 0x100720, 0xffffffff, train->r_100720);
+ }
+ ram_mask(fuc, 0x10053c, 0x00001000, 0x00001000);
+ ram_mask(fuc, 0x10f804, 0x80000000, 0x00000000);
+ ram_mask(fuc, 0x100760, 0x22222222, r100760);
+ ram_mask(fuc, 0x1007a0, 0x22222222, r100760);
+ ram_mask(fuc, 0x1007e0, 0x22222222, r100760);
+ }
+
+ if (nv_device(pfb)->chipset == 0xa3 && freq > 500000) {
+ ram_mask(fuc, 0x100700, 0x00000006, 0x00000000);
+ }
+
+ /* Final switch */
+ if (mclk.pll) {
+ ram_mask(fuc, 0x1110e0, 0x00088000, 0x00011000);
+ ram_mask(fuc, 0x004000, 0x00000008, 0x00000000);
+ }
+
+ ram_wr32(fuc, 0x1002dc, 0x00000000);
+ ram_wr32(fuc, 0x1002d4, 0x00000001);
+ ram_wr32(fuc, 0x100210, 0x80000000);
+ ram_nsec(fuc, 2000);
+
+ /* Set RAM MR parameters and timings */
+ for (i = 2; i >= 0; i--) {
+ if (ram_rd32(fuc, mr[i]) != ram->base.mr[i]) {
+ ram_wr32(fuc, mr[i], ram->base.mr[i]);
+ ram_nsec(fuc, 1000);
+ }
+ }
+
+ ram_wr32(fuc, 0x100220[3], timing[3]);
+ ram_wr32(fuc, 0x100220[1], timing[1]);
+ ram_wr32(fuc, 0x100220[6], timing[6]);
+ ram_wr32(fuc, 0x100220[7], timing[7]);
+ ram_wr32(fuc, 0x100220[2], timing[2]);
+ ram_wr32(fuc, 0x100220[4], timing[4]);
+ ram_wr32(fuc, 0x100220[5], timing[5]);
+ ram_wr32(fuc, 0x100220[0], timing[0]);
+ ram_wr32(fuc, 0x100220[8], timing[8]);
+
+ /* Misc */
+ ram_mask(fuc, 0x100200, 0x00001000, !next->bios.ramcfg_10_02_08 << 12);
+
+ /* XXX: A lot of "chipset"/"ram type" specific stuff...? */
+ unk714 = ram_rd32(fuc, 0x100714) & ~0xf0000130;
+ unk718 = ram_rd32(fuc, 0x100718) & ~0x00000100;
+ unk71c = ram_rd32(fuc, 0x10071c) & ~0x00000100;
+ r111100 = ram_rd32(fuc, 0x111100) & ~0x3a800000;
+
+ if (next->bios.ramcfg_10_02_04) {
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR3:
+ if (nv_device(pfb)->chipset != 0xa8)
+ r111100 |= 0x00000004;
+ /* no break */
+ case NV_MEM_TYPE_DDR2:
+ r111100 |= 0x08000000;
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ r111100 |= 0x1a800000;
+ unk714 |= 0x00000010;
+ break;
+ case NV_MEM_TYPE_DDR3:
+ if (nv_device(pfb)->chipset == 0xa8) {
+ r111100 |= 0x08000000;
+ } else {
+ r111100 &= ~0x00000004;
+ r111100 |= 0x12800000;
+ }
+ unk714 |= 0x00000010;
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ r111100 |= 0x30000000;
+ unk714 |= 0x00000020;
+ break;
+ default:
+ break;
+ }
+ }
+
+ unk714 |= (next->bios.ramcfg_10_04_01) << 8;
+
+ if (next->bios.ramcfg_10_02_20)
+ unk714 |= 0xf0000000;
+ if (next->bios.ramcfg_10_02_02)
+ unk718 |= 0x00000100;
+ if (next->bios.ramcfg_10_02_01)
+ unk71c |= 0x00000100;
+ if (next->bios.timing_10_24 != 0xff) {
+ unk718 &= ~0xf0000000;
+ unk718 |= next->bios.timing_10_24 << 28;
+ }
+ if (next->bios.ramcfg_10_02_10)
+ r111100 &= ~0x04020000;
+
+ ram_mask(fuc, 0x100714, 0xffffffff, unk714);
+ ram_mask(fuc, 0x10071c, 0xffffffff, unk71c);
+ ram_mask(fuc, 0x100718, 0xffffffff, unk718);
+ ram_mask(fuc, 0x111100, 0xffffffff, r111100);
+
+ if (fuc->r_gpioFBVREF.addr && !next->bios.timing_10_ODT)
+ gt215_ram_fbvref(fuc, 1);
+
+ /* Reset DLL */
+ if (!next->bios.ramcfg_10_DLLoff)
+ nvkm_sddr2_dll_reset(fuc);
+
+ if (ram->base.type == NV_MEM_TYPE_GDDR3) {
+ ram_nsec(fuc, 31000);
+ } else {
+ ram_nsec(fuc, 14000);
+ }
+
+ if (ram->base.type == NV_MEM_TYPE_DDR3) {
+ ram_wr32(fuc, 0x100264, 0x1);
+ ram_nsec(fuc, 2000);
+ }
+
+ ram_nuke(fuc, 0x100700);
+ ram_mask(fuc, 0x100700, 0x01000000, 0x01000000);
+ ram_mask(fuc, 0x100700, 0x01000000, 0x00000000);
+
+ /* Re-enable FB */
+ ram_unblock(fuc);
+ ram_wr32(fuc, 0x611200, 0x3330);
+
+ /* Post fiddlings */
+ if (next->bios.rammap_10_04_02)
+ ram_mask(fuc, 0x100200, 0x00000800, 0x00000800);
+ if (next->bios.ramcfg_10_02_10) {
+ ram_mask(fuc, 0x111104, 0x00000180, 0x00000180);
+ ram_mask(fuc, 0x111100, 0x40000000, 0x00000000);
+ } else {
+ ram_mask(fuc, 0x111104, 0x00000600, 0x00000600);
+ }
+
+ if (mclk.pll) {
+ ram_mask(fuc, 0x004168, 0x00000001, 0x00000000);
+ ram_mask(fuc, 0x004168, 0x00000100, 0x00000000);
+ } else {
+ ram_mask(fuc, 0x004000, 0x00000001, 0x00000000);
+ ram_mask(fuc, 0x004128, 0x00000001, 0x00000000);
+ ram_mask(fuc, 0x004128, 0x00000100, 0x00000000);
+ }
+
+ return 0;
+}
+
+static int
+gt215_ram_prog(struct nvkm_fb *pfb)
+{
+ struct nvkm_device *device = nv_device(pfb);
+ struct gt215_ram *ram = (void *)pfb->ram;
+ struct gt215_ramfuc *fuc = &ram->fuc;
+ bool exec = nvkm_boolopt(device->cfgopt, "NvMemExec", true);
+
+ if (exec) {
+ nv_mask(pfb, 0x001534, 0x2, 0x2);
+
+ ram_exec(fuc, true);
+
+ /* Post-processing, avoids flicker */
+ nv_mask(pfb, 0x002504, 0x1, 0x0);
+ nv_mask(pfb, 0x001534, 0x2, 0x0);
+
+ nv_mask(pfb, 0x616308, 0x10, 0x10);
+ nv_mask(pfb, 0x616b08, 0x10, 0x10);
+ } else {
+ ram_exec(fuc, false);
+ }
+ return 0;
+}
+
+static void
+gt215_ram_tidy(struct nvkm_fb *pfb)
+{
+ struct gt215_ram *ram = (void *)pfb->ram;
+ struct gt215_ramfuc *fuc = &ram->fuc;
+ ram_exec(fuc, false);
+}
+
+static int
+gt215_ram_init(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = (void *)object->parent;
+ struct gt215_ram *ram = (void *)object;
+ int ret;
+
+ ret = nvkm_ram_init(&ram->base);
+ if (ret)
+ return ret;
+
+ gt215_link_train_init(pfb);
+ return 0;
+}
+
+static int
+gt215_ram_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_fb *pfb = (void *)object->parent;
+
+ if (!suspend)
+ gt215_link_train_fini(pfb);
+
+ return 0;
+}
+
+static int
+gt215_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 datasize,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_gpio *gpio = nvkm_gpio(pfb);
+ struct dcb_gpio_func func;
+ struct gt215_ram *ram;
+ int ret, i;
+ u32 reg, shift;
+
+ ret = nv50_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ case NV_MEM_TYPE_DDR3:
+ case NV_MEM_TYPE_GDDR3:
+ ram->base.calc = gt215_ram_calc;
+ ram->base.prog = gt215_ram_prog;
+ ram->base.tidy = gt215_ram_tidy;
+ break;
+ default:
+ nv_warn(ram, "reclocking of this ram type unsupported\n");
+ return 0;
+ }
+
+ ram->fuc.r_0x001610 = ramfuc_reg(0x001610);
+ ram->fuc.r_0x001700 = ramfuc_reg(0x001700);
+ ram->fuc.r_0x002504 = ramfuc_reg(0x002504);
+ ram->fuc.r_0x004000 = ramfuc_reg(0x004000);
+ ram->fuc.r_0x004004 = ramfuc_reg(0x004004);
+ ram->fuc.r_0x004018 = ramfuc_reg(0x004018);
+ ram->fuc.r_0x004128 = ramfuc_reg(0x004128);
+ ram->fuc.r_0x004168 = ramfuc_reg(0x004168);
+ ram->fuc.r_0x100080 = ramfuc_reg(0x100080);
+ ram->fuc.r_0x100200 = ramfuc_reg(0x100200);
+ ram->fuc.r_0x100210 = ramfuc_reg(0x100210);
+ for (i = 0; i < 9; i++)
+ ram->fuc.r_0x100220[i] = ramfuc_reg(0x100220 + (i * 4));
+ ram->fuc.r_0x100264 = ramfuc_reg(0x100264);
+ ram->fuc.r_0x1002d0 = ramfuc_reg(0x1002d0);
+ ram->fuc.r_0x1002d4 = ramfuc_reg(0x1002d4);
+ ram->fuc.r_0x1002dc = ramfuc_reg(0x1002dc);
+ ram->fuc.r_0x10053c = ramfuc_reg(0x10053c);
+ ram->fuc.r_0x1005a0 = ramfuc_reg(0x1005a0);
+ ram->fuc.r_0x1005a4 = ramfuc_reg(0x1005a4);
+ ram->fuc.r_0x100700 = ramfuc_reg(0x100700);
+ ram->fuc.r_0x100714 = ramfuc_reg(0x100714);
+ ram->fuc.r_0x100718 = ramfuc_reg(0x100718);
+ ram->fuc.r_0x10071c = ramfuc_reg(0x10071c);
+ ram->fuc.r_0x100720 = ramfuc_reg(0x100720);
+ ram->fuc.r_0x100760 = ramfuc_stride(0x100760, 4, ram->base.part_mask);
+ ram->fuc.r_0x1007a0 = ramfuc_stride(0x1007a0, 4, ram->base.part_mask);
+ ram->fuc.r_0x1007e0 = ramfuc_stride(0x1007e0, 4, ram->base.part_mask);
+ ram->fuc.r_0x100da0 = ramfuc_stride(0x100da0, 4, ram->base.part_mask);
+ ram->fuc.r_0x10f804 = ramfuc_reg(0x10f804);
+ ram->fuc.r_0x1110e0 = ramfuc_stride(0x1110e0, 4, ram->base.part_mask);
+ ram->fuc.r_0x111100 = ramfuc_reg(0x111100);
+ ram->fuc.r_0x111104 = ramfuc_reg(0x111104);
+ ram->fuc.r_0x1111e0 = ramfuc_reg(0x1111e0);
+ ram->fuc.r_0x111400 = ramfuc_reg(0x111400);
+ ram->fuc.r_0x611200 = ramfuc_reg(0x611200);
+
+ if (ram->base.ranks > 1) {
+ ram->fuc.r_mr[0] = ramfuc_reg2(0x1002c0, 0x1002c8);
+ ram->fuc.r_mr[1] = ramfuc_reg2(0x1002c4, 0x1002cc);
+ ram->fuc.r_mr[2] = ramfuc_reg2(0x1002e0, 0x1002e8);
+ ram->fuc.r_mr[3] = ramfuc_reg2(0x1002e4, 0x1002ec);
+ } else {
+ ram->fuc.r_mr[0] = ramfuc_reg(0x1002c0);
+ ram->fuc.r_mr[1] = ramfuc_reg(0x1002c4);
+ ram->fuc.r_mr[2] = ramfuc_reg(0x1002e0);
+ ram->fuc.r_mr[3] = ramfuc_reg(0x1002e4);
+ }
+
+ ret = gpio->find(gpio, 0, 0x2e, DCB_GPIO_UNUSED, &func);
+ if (ret == 0) {
+ nv50_gpio_location(func.line, &reg, &shift);
+ ram->fuc.r_gpioFBVREF = ramfuc_reg(reg);
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass
+gt215_ram_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt215_ram_ctor,
+ .dtor = _nvkm_ram_dtor,
+ .init = gt215_ram_init,
+ .fini = gt215_ram_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c
new file mode 100644
index 000000000000..abc18e89a97c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/rammcp77.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct mcp77_ram_priv {
+ struct nvkm_ram base;
+ u64 poller_base;
+};
+
+static int
+mcp77_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 datasize,
+ struct nvkm_object **pobject)
+{
+ u32 rsvd_head = ( 256 * 1024); /* vga memory */
+ u32 rsvd_tail = (1024 * 1024); /* vbios etc */
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct mcp77_ram_priv *priv;
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.type = NV_MEM_TYPE_STOLEN;
+ priv->base.stolen = (u64)nv_rd32(pfb, 0x100e10) << 12;
+ priv->base.size = (u64)nv_rd32(pfb, 0x100e14) << 12;
+
+ rsvd_tail += 0x1000;
+ priv->poller_base = priv->base.size - rsvd_tail;
+
+ ret = nvkm_mm_init(&pfb->vram, rsvd_head >> 12,
+ (priv->base.size - (rsvd_head + rsvd_tail)) >> 12,
+ 1);
+ if (ret)
+ return ret;
+
+ priv->base.get = nv50_ram_get;
+ priv->base.put = nv50_ram_put;
+ return 0;
+}
+
+static int
+mcp77_ram_init(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ struct mcp77_ram_priv *priv = (void *)object;
+ int ret;
+ u64 dniso, hostnb, flush;
+
+ ret = nvkm_ram_init(&priv->base);
+ if (ret)
+ return ret;
+
+ dniso = ((priv->base.size - (priv->poller_base + 0x00)) >> 5) - 1;
+ hostnb = ((priv->base.size - (priv->poller_base + 0x20)) >> 5) - 1;
+ flush = ((priv->base.size - (priv->poller_base + 0x40)) >> 5) - 1;
+
+ /* Enable NISO poller for various clients and set their associated
+ * read address, only for MCP77/78 and MCP79/7A. (fd#25701)
+ */
+ nv_wr32(pfb, 0x100c18, dniso);
+ nv_mask(pfb, 0x100c14, 0x00000000, 0x00000001);
+ nv_wr32(pfb, 0x100c1c, hostnb);
+ nv_mask(pfb, 0x100c14, 0x00000000, 0x00000002);
+ nv_wr32(pfb, 0x100c24, flush);
+ nv_mask(pfb, 0x100c14, 0x00000000, 0x00010000);
+ return 0;
+}
+
+struct nvkm_oclass
+mcp77_ram_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = mcp77_ram_ctor,
+ .dtor = _nvkm_ram_dtor,
+ .init = mcp77_ram_init,
+ .fini = _nvkm_ram_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c
new file mode 100644
index 000000000000..855de1617229
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv04.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "regsnv04.h"
+
+static int
+nv04_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ram *ram;
+ u32 boot0 = nv_rd32(pfb, NV04_PFB_BOOT_0);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (boot0 & 0x00000100) {
+ ram->size = ((boot0 >> 12) & 0xf) * 2 + 2;
+ ram->size *= 1024 * 1024;
+ } else {
+ switch (boot0 & NV04_PFB_BOOT_0_RAM_AMOUNT) {
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_32MB:
+ ram->size = 32 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_16MB:
+ ram->size = 16 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_8MB:
+ ram->size = 8 * 1024 * 1024;
+ break;
+ case NV04_PFB_BOOT_0_RAM_AMOUNT_4MB:
+ ram->size = 4 * 1024 * 1024;
+ break;
+ }
+ }
+
+ if ((boot0 & 0x00000038) <= 0x10)
+ ram->type = NV_MEM_TYPE_SGRAM;
+ else
+ ram->type = NV_MEM_TYPE_SDRAM;
+
+ return 0;
+}
+
+struct nvkm_oclass
+nv04_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c
new file mode 100644
index 000000000000..3b8a1eda5b64
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv10.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nv10_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ram *ram;
+ u32 cfg0 = nv_rd32(pfb, 0x100200);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (cfg0 & 0x00000001)
+ ram->type = NV_MEM_TYPE_DDR1;
+ else
+ ram->type = NV_MEM_TYPE_SDRAM;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ return 0;
+}
+
+struct nvkm_oclass
+nv10_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv10_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c
new file mode 100644
index 000000000000..fbae05db4ffd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv1a.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+static int
+nv1a_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ram *ram;
+ struct pci_dev *bridge;
+ u32 mem, mib;
+ int ret;
+
+ bridge = pci_get_bus_and_slot(0, PCI_DEVFN(0, 1));
+ if (!bridge) {
+ nv_fatal(pfb, "no bridge device\n");
+ return -ENODEV;
+ }
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (nv_device(pfb)->chipset == 0x1a) {
+ pci_read_config_dword(bridge, 0x7c, &mem);
+ mib = ((mem >> 6) & 31) + 1;
+ } else {
+ pci_read_config_dword(bridge, 0x84, &mem);
+ mib = ((mem >> 4) & 127) + 1;
+ }
+
+ ram->type = NV_MEM_TYPE_STOLEN;
+ ram->size = mib * 1024 * 1024;
+ return 0;
+}
+
+struct nvkm_oclass
+nv1a_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv1a_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c
new file mode 100644
index 000000000000..d9e7187bd235
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv20.c
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nv20_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ram *ram;
+ u32 pbus1218 = nv_rd32(pfb, 0x001218);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: ram->type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: ram->type = NV_MEM_TYPE_GDDR2; break;
+ }
+ ram->size = (nv_rd32(pfb, 0x10020c) & 0xff000000);
+ ram->parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ return 0;
+}
+
+struct nvkm_oclass
+nv20_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv20_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
new file mode 100644
index 000000000000..3d31fa45c1a6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv40.c
@@ -0,0 +1,212 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+#include <core/device.h>
+#include <subdev/bios.h>
+#include <subdev/bios/bit.h>
+#include <subdev/bios/init.h>
+#include <subdev/bios/pll.h>
+#include <subdev/clk/pll.h>
+#include <subdev/timer.h>
+
+int
+nv40_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nv40_ram *ram = (void *)pfb->ram;
+ struct nvbios_pll pll;
+ int N1, M1, N2, M2;
+ int log2P, ret;
+
+ ret = nvbios_pll_parse(bios, 0x04, &pll);
+ if (ret) {
+ nv_error(pfb, "mclk pll data not found\n");
+ return ret;
+ }
+
+ ret = nv04_pll_calc(nv_subdev(pfb), &pll, freq,
+ &N1, &M1, &N2, &M2, &log2P);
+ if (ret < 0)
+ return ret;
+
+ ram->ctrl = 0x80000000 | (log2P << 16);
+ ram->ctrl |= min(pll.bias_p + log2P, (int)pll.max_p) << 20;
+ if (N2 == M2) {
+ ram->ctrl |= 0x00000100;
+ ram->coef = (N1 << 8) | M1;
+ } else {
+ ram->ctrl |= 0x40000000;
+ ram->coef = (N2 << 24) | (M2 << 16) | (N1 << 8) | M1;
+ }
+
+ return 0;
+}
+
+int
+nv40_ram_prog(struct nvkm_fb *pfb)
+{
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nv40_ram *ram = (void *)pfb->ram;
+ struct bit_entry M;
+ u32 crtc_mask = 0;
+ u8 sr1[2];
+ int i;
+
+ /* determine which CRTCs are active, fetch VGA_SR1 for each */
+ for (i = 0; i < 2; i++) {
+ u32 vbl = nv_rd32(pfb, 0x600808 + (i * 0x2000));
+ u32 cnt = 0;
+ do {
+ if (vbl != nv_rd32(pfb, 0x600808 + (i * 0x2000))) {
+ nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+ sr1[i] = nv_rd08(pfb, 0x0c03c5 + (i * 0x2000));
+ if (!(sr1[i] & 0x20))
+ crtc_mask |= (1 << i);
+ break;
+ }
+ udelay(1);
+ } while (cnt++ < 32);
+ }
+
+ /* wait for vblank start on active crtcs, disable memory access */
+ for (i = 0; i < 2; i++) {
+ if (!(crtc_mask & (1 << i)))
+ continue;
+ nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00000000);
+ nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+ nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+ nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i] | 0x20);
+ }
+
+ /* prepare ram for reclocking */
+ nv_wr32(pfb, 0x1002d4, 0x00000001); /* precharge */
+ nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
+ nv_wr32(pfb, 0x1002d0, 0x00000001); /* refresh */
+ nv_mask(pfb, 0x100210, 0x80000000, 0x00000000); /* no auto refresh */
+ nv_wr32(pfb, 0x1002dc, 0x00000001); /* enable self-refresh */
+
+ /* change the PLL of each memory partition */
+ nv_mask(pfb, 0x00c040, 0x0000c000, 0x00000000);
+ switch (nv_device(pfb)->chipset) {
+ case 0x40:
+ case 0x45:
+ case 0x41:
+ case 0x42:
+ case 0x47:
+ nv_mask(pfb, 0x004044, 0xc0771100, ram->ctrl);
+ nv_mask(pfb, 0x00402c, 0xc0771100, ram->ctrl);
+ nv_wr32(pfb, 0x004048, ram->coef);
+ nv_wr32(pfb, 0x004030, ram->coef);
+ case 0x43:
+ case 0x49:
+ case 0x4b:
+ nv_mask(pfb, 0x004038, 0xc0771100, ram->ctrl);
+ nv_wr32(pfb, 0x00403c, ram->coef);
+ default:
+ nv_mask(pfb, 0x004020, 0xc0771100, ram->ctrl);
+ nv_wr32(pfb, 0x004024, ram->coef);
+ break;
+ }
+ udelay(100);
+ nv_mask(pfb, 0x00c040, 0x0000c000, 0x0000c000);
+
+ /* re-enable normal operation of memory controller */
+ nv_wr32(pfb, 0x1002dc, 0x00000000);
+ nv_mask(pfb, 0x100210, 0x80000000, 0x80000000);
+ udelay(100);
+
+ /* execute memory reset script from vbios */
+ if (!bit_entry(bios, 'M', &M)) {
+ struct nvbios_init init = {
+ .subdev = nv_subdev(pfb),
+ .bios = bios,
+ .offset = nv_ro16(bios, M.offset + 0x00),
+ .execute = 1,
+ };
+
+ nvbios_exec(&init);
+ }
+
+ /* make sure we're in vblank (hopefully the same one as before), and
+ * then re-enable crtc memory access
+ */
+ for (i = 0; i < 2; i++) {
+ if (!(crtc_mask & (1 << i)))
+ continue;
+ nv_wait(pfb, 0x600808 + (i * 0x2000), 0x00010000, 0x00010000);
+ nv_wr08(pfb, 0x0c03c4 + (i * 0x2000), 0x01);
+ nv_wr08(pfb, 0x0c03c5 + (i * 0x2000), sr1[i]);
+ }
+
+ return 0;
+}
+
+void
+nv40_ram_tidy(struct nvkm_fb *pfb)
+{
+}
+
+static int
+nv40_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nv40_ram *ram;
+ u32 pbus1218 = nv_rd32(pfb, 0x001218);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pbus1218 & 0x00000300) {
+ case 0x00000000: ram->base.type = NV_MEM_TYPE_SDRAM; break;
+ case 0x00000100: ram->base.type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000200: ram->base.type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000300: ram->base.type = NV_MEM_TYPE_DDR2; break;
+ }
+
+ ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->base.tags = nv_rd32(pfb, 0x100320);
+ ram->base.calc = nv40_ram_calc;
+ ram->base.prog = nv40_ram_prog;
+ ram->base.tidy = nv40_ram_tidy;
+ return 0;
+}
+
+
+struct nvkm_oclass
+nv40_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c
new file mode 100644
index 000000000000..33c612b1355f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv41.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static int
+nv41_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nv40_ram *ram;
+ u32 pfb474 = nv_rd32(pfb, 0x100474);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (pfb474 & 0x00000004)
+ ram->base.type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ ram->base.type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ ram->base.type = NV_MEM_TYPE_DDR1;
+
+ ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->base.tags = nv_rd32(pfb, 0x100320);
+ ram->base.calc = nv40_ram_calc;
+ ram->base.prog = nv40_ram_prog;
+ ram->base.tidy = nv40_ram_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+nv41_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv41_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c
new file mode 100644
index 000000000000..f575a7246403
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv44.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static int
+nv44_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nv40_ram *ram;
+ u32 pfb474 = nv_rd32(pfb, 0x100474);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ if (pfb474 & 0x00000004)
+ ram->base.type = NV_MEM_TYPE_GDDR3;
+ if (pfb474 & 0x00000002)
+ ram->base.type = NV_MEM_TYPE_DDR2;
+ if (pfb474 & 0x00000001)
+ ram->base.type = NV_MEM_TYPE_DDR1;
+
+ ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->base.calc = nv40_ram_calc;
+ ram->base.prog = nv40_ram_prog;
+ ram->base.tidy = nv40_ram_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+nv44_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv44_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c
new file mode 100644
index 000000000000..51b44cdb2732
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv49.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv40.h"
+
+static int
+nv49_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nv40_ram *ram;
+ u32 pfb914 = nv_rd32(pfb, 0x100914);
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (pfb914 & 0x00000003) {
+ case 0x00000000: ram->base.type = NV_MEM_TYPE_DDR1; break;
+ case 0x00000001: ram->base.type = NV_MEM_TYPE_DDR2; break;
+ case 0x00000002: ram->base.type = NV_MEM_TYPE_GDDR3; break;
+ case 0x00000003: break;
+ }
+
+ ram->base.size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->base.parts = (nv_rd32(pfb, 0x100200) & 0x00000003) + 1;
+ ram->base.tags = nv_rd32(pfb, 0x100320);
+ ram->base.calc = nv40_ram_calc;
+ ram->base.prog = nv40_ram_prog;
+ ram->base.tidy = nv40_ram_tidy;
+ return 0;
+}
+
+struct nvkm_oclass
+nv49_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv49_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c
new file mode 100644
index 000000000000..f3ed1c60d730
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv4e.c
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nv4e_ram_create(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ram *ram;
+ int ret;
+
+ ret = nvkm_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ ram->size = nv_rd32(pfb, 0x10020c) & 0xff000000;
+ ram->type = NV_MEM_TYPE_STOLEN;
+ return 0;
+}
+
+struct nvkm_oclass
+nv4e_ram_oclass = {
+ .handle = 0,
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv4e_ram_create,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c
new file mode 100644
index 000000000000..d2c81dd635dc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramnv50.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+#include "ramseq.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/perf.h>
+#include <subdev/bios/pll.h>
+#include <subdev/bios/timing.h>
+#include <subdev/clk/pll.h>
+
+struct nv50_ramseq {
+ struct hwsq base;
+ struct hwsq_reg r_0x002504;
+ struct hwsq_reg r_0x004008;
+ struct hwsq_reg r_0x00400c;
+ struct hwsq_reg r_0x00c040;
+ struct hwsq_reg r_0x100210;
+ struct hwsq_reg r_0x1002d0;
+ struct hwsq_reg r_0x1002d4;
+ struct hwsq_reg r_0x1002dc;
+ struct hwsq_reg r_0x100da0[8];
+ struct hwsq_reg r_0x100e20;
+ struct hwsq_reg r_0x100e24;
+ struct hwsq_reg r_0x611200;
+ struct hwsq_reg r_timing[9];
+ struct hwsq_reg r_mr[4];
+};
+
+struct nv50_ram {
+ struct nvkm_ram base;
+ struct nv50_ramseq hwsq;
+};
+
+#define QFX5800NVA0 1
+
+static int
+nv50_ram_calc(struct nvkm_fb *pfb, u32 freq)
+{
+ struct nvkm_bios *bios = nvkm_bios(pfb);
+ struct nv50_ram *ram = (void *)pfb->ram;
+ struct nv50_ramseq *hwsq = &ram->hwsq;
+ struct nvbios_perfE perfE;
+ struct nvbios_pll mpll;
+ struct {
+ u32 data;
+ u8 size;
+ } ramcfg, timing;
+ u8 ver, hdr, cnt, len, strap;
+ int N1, M1, N2, M2, P;
+ int ret, i;
+
+ /* lookup closest matching performance table entry for frequency */
+ i = 0;
+ do {
+ ramcfg.data = nvbios_perfEp(bios, i++, &ver, &hdr, &cnt,
+ &ramcfg.size, &perfE);
+ if (!ramcfg.data || (ver < 0x25 || ver >= 0x40) ||
+ (ramcfg.size < 2)) {
+ nv_error(pfb, "invalid/missing perftab entry\n");
+ return -EINVAL;
+ }
+ } while (perfE.memory < freq);
+
+ /* locate specific data set for the attached memory */
+ strap = nvbios_ramcfg_index(nv_subdev(pfb));
+ if (strap >= cnt) {
+ nv_error(pfb, "invalid ramcfg strap\n");
+ return -EINVAL;
+ }
+
+ ramcfg.data += hdr + (strap * ramcfg.size);
+
+ /* lookup memory timings, if bios says they're present */
+ strap = nv_ro08(bios, ramcfg.data + 0x01);
+ if (strap != 0xff) {
+ timing.data = nvbios_timingEe(bios, strap, &ver, &hdr,
+ &cnt, &len);
+ if (!timing.data || ver != 0x10 || hdr < 0x12) {
+ nv_error(pfb, "invalid/missing timing entry "
+ "%02x %04x %02x %02x\n",
+ strap, timing.data, ver, hdr);
+ return -EINVAL;
+ }
+ } else {
+ timing.data = 0;
+ }
+
+ ret = ram_init(hwsq, nv_subdev(pfb));
+ if (ret)
+ return ret;
+
+ ram_wait(hwsq, 0x01, 0x00); /* wait for !vblank */
+ ram_wait(hwsq, 0x01, 0x01); /* wait for vblank */
+ ram_wr32(hwsq, 0x611200, 0x00003300);
+ ram_wr32(hwsq, 0x002504, 0x00000001); /* block fifo */
+ ram_nsec(hwsq, 8000);
+ ram_setf(hwsq, 0x10, 0x00); /* disable fb */
+ ram_wait(hwsq, 0x00, 0x01); /* wait for fb disabled */
+
+ ram_wr32(hwsq, 0x1002d4, 0x00000001); /* precharge */
+ ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
+ ram_wr32(hwsq, 0x1002d0, 0x00000001); /* refresh */
+ ram_wr32(hwsq, 0x100210, 0x00000000); /* disable auto-refresh */
+ ram_wr32(hwsq, 0x1002dc, 0x00000001); /* enable self-refresh */
+
+ ret = nvbios_pll_parse(bios, 0x004008, &mpll);
+ mpll.vco2.max_freq = 0;
+ if (ret == 0) {
+ ret = nv04_pll_calc(nv_subdev(pfb), &mpll, freq,
+ &N1, &M1, &N2, &M2, &P);
+ if (ret == 0)
+ ret = -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ ram_mask(hwsq, 0x00c040, 0xc000c000, 0x0000c000);
+ ram_mask(hwsq, 0x004008, 0x00000200, 0x00000200);
+ ram_mask(hwsq, 0x00400c, 0x0000ffff, (N1 << 8) | M1);
+ ram_mask(hwsq, 0x004008, 0x81ff0000, 0x80000000 | (mpll.bias_p << 19) |
+ (P << 22) | (P << 16));
+#if QFX5800NVA0
+ for (i = 0; i < 8; i++)
+ ram_mask(hwsq, 0x100da0[i], 0x00000000, 0x00000000); /*XXX*/
+#endif
+ ram_nsec(hwsq, 96000); /*XXX*/
+ ram_mask(hwsq, 0x004008, 0x00002200, 0x00002000);
+
+ ram_wr32(hwsq, 0x1002dc, 0x00000000); /* disable self-refresh */
+ ram_wr32(hwsq, 0x100210, 0x80000000); /* enable auto-refresh */
+
+ ram_nsec(hwsq, 12000);
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ ram_nuke(hwsq, mr[0]); /* force update */
+ ram_mask(hwsq, mr[0], 0x000, 0x000);
+ break;
+ case NV_MEM_TYPE_GDDR3:
+ ram_mask(hwsq, mr[2], 0x000, 0x000);
+ ram_nuke(hwsq, mr[0]); /* force update */
+ ram_mask(hwsq, mr[0], 0x000, 0x000);
+ break;
+ default:
+ break;
+ }
+
+ ram_mask(hwsq, timing[3], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[1], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[6], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[7], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[8], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[2], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[4], 0x00000000, 0x00000000); /*XXX*/
+ ram_mask(hwsq, timing[5], 0x00000000, 0x00000000); /*XXX*/
+
+ ram_mask(hwsq, timing[0], 0x00000000, 0x00000000); /*XXX*/
+
+#if QFX5800NVA0
+ ram_nuke(hwsq, 0x100e24);
+ ram_mask(hwsq, 0x100e24, 0x00000000, 0x00000000);
+ ram_nuke(hwsq, 0x100e20);
+ ram_mask(hwsq, 0x100e20, 0x00000000, 0x00000000);
+#endif
+
+ ram_mask(hwsq, mr[0], 0x100, 0x100);
+ ram_mask(hwsq, mr[0], 0x100, 0x000);
+
+ ram_setf(hwsq, 0x10, 0x01); /* enable fb */
+ ram_wait(hwsq, 0x00, 0x00); /* wait for fb enabled */
+ ram_wr32(hwsq, 0x611200, 0x00003330);
+ ram_wr32(hwsq, 0x002504, 0x00000000); /* un-block fifo */
+ return 0;
+}
+
+static int
+nv50_ram_prog(struct nvkm_fb *pfb)
+{
+ struct nvkm_device *device = nv_device(pfb);
+ struct nv50_ram *ram = (void *)pfb->ram;
+ struct nv50_ramseq *hwsq = &ram->hwsq;
+
+ ram_exec(hwsq, nvkm_boolopt(device->cfgopt, "NvMemExec", true));
+ return 0;
+}
+
+static void
+nv50_ram_tidy(struct nvkm_fb *pfb)
+{
+ struct nv50_ram *ram = (void *)pfb->ram;
+ struct nv50_ramseq *hwsq = &ram->hwsq;
+ ram_exec(hwsq, false);
+}
+
+void
+__nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem *mem)
+{
+ struct nvkm_mm_node *this;
+
+ while (!list_empty(&mem->regions)) {
+ this = list_first_entry(&mem->regions, typeof(*this), rl_entry);
+
+ list_del(&this->rl_entry);
+ nvkm_mm_free(&pfb->vram, &this);
+ }
+
+ nvkm_mm_free(&pfb->tags, &mem->tag);
+}
+
+void
+nv50_ram_put(struct nvkm_fb *pfb, struct nvkm_mem **pmem)
+{
+ struct nvkm_mem *mem = *pmem;
+
+ *pmem = NULL;
+ if (unlikely(mem == NULL))
+ return;
+
+ mutex_lock(&pfb->base.mutex);
+ __nv50_ram_put(pfb, mem);
+ mutex_unlock(&pfb->base.mutex);
+
+ kfree(mem);
+}
+
+int
+nv50_ram_get(struct nvkm_fb *pfb, u64 size, u32 align, u32 ncmin,
+ u32 memtype, struct nvkm_mem **pmem)
+{
+ struct nvkm_mm *heap = &pfb->vram;
+ struct nvkm_mm *tags = &pfb->tags;
+ struct nvkm_mm_node *r;
+ struct nvkm_mem *mem;
+ int comp = (memtype & 0x300) >> 8;
+ int type = (memtype & 0x07f);
+ int back = (memtype & 0x800);
+ int min, max, ret;
+
+ max = (size >> 12);
+ min = ncmin ? (ncmin >> 12) : max;
+ align >>= 12;
+
+ mem = kzalloc(sizeof(*mem), GFP_KERNEL);
+ if (!mem)
+ return -ENOMEM;
+
+ mutex_lock(&pfb->base.mutex);
+ if (comp) {
+ if (align == 16) {
+ int n = (max >> 4) * comp;
+
+ ret = nvkm_mm_head(tags, 0, 1, n, n, 1, &mem->tag);
+ if (ret)
+ mem->tag = NULL;
+ }
+
+ if (unlikely(!mem->tag))
+ comp = 0;
+ }
+
+ INIT_LIST_HEAD(&mem->regions);
+ mem->memtype = (comp << 7) | type;
+ mem->size = max;
+
+ type = nv50_fb_memtype[type];
+ do {
+ if (back)
+ ret = nvkm_mm_tail(heap, 0, type, max, min, align, &r);
+ else
+ ret = nvkm_mm_head(heap, 0, type, max, min, align, &r);
+ if (ret) {
+ mutex_unlock(&pfb->base.mutex);
+ pfb->ram->put(pfb, &mem);
+ return ret;
+ }
+
+ list_add_tail(&r->rl_entry, &mem->regions);
+ max -= r->length;
+ } while (max);
+ mutex_unlock(&pfb->base.mutex);
+
+ r = list_first_entry(&mem->regions, struct nvkm_mm_node, rl_entry);
+ mem->offset = (u64)r->offset << 12;
+ *pmem = mem;
+ return 0;
+}
+
+static u32
+nv50_fb_vram_rblock(struct nvkm_fb *pfb, struct nvkm_ram *ram)
+{
+ int colbits, rowbitsa, rowbitsb, banks;
+ u64 rowsize, predicted;
+ u32 r0, r4, rt, rblock_size;
+
+ r0 = nv_rd32(pfb, 0x100200);
+ r4 = nv_rd32(pfb, 0x100204);
+ rt = nv_rd32(pfb, 0x100250);
+ nv_debug(pfb, "memcfg 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ r0, r4, rt, nv_rd32(pfb, 0x001540));
+
+ colbits = (r4 & 0x0000f000) >> 12;
+ rowbitsa = ((r4 & 0x000f0000) >> 16) + 8;
+ rowbitsb = ((r4 & 0x00f00000) >> 20) + 8;
+ banks = 1 << (((r4 & 0x03000000) >> 24) + 2);
+
+ rowsize = ram->parts * banks * (1 << colbits) * 8;
+ predicted = rowsize << rowbitsa;
+ if (r0 & 0x00000004)
+ predicted += rowsize << rowbitsb;
+
+ if (predicted != ram->size) {
+ nv_warn(pfb, "memory controller reports %d MiB VRAM\n",
+ (u32)(ram->size >> 20));
+ }
+
+ rblock_size = rowsize;
+ if (rt & 1)
+ rblock_size *= 3;
+
+ nv_debug(pfb, "rblock %d bytes\n", rblock_size);
+ return rblock_size;
+}
+
+int
+nv50_ram_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ const u32 rsvd_head = ( 256 * 1024) >> 12; /* vga memory */
+ const u32 rsvd_tail = (1024 * 1024) >> 12; /* vbios etc */
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ram *ram;
+ int ret;
+
+ ret = nvkm_ram_create_(parent, engine, oclass, length, pobject);
+ ram = *pobject;
+ if (ret)
+ return ret;
+
+ ram->size = nv_rd32(pfb, 0x10020c);
+ ram->size = (ram->size & 0xffffff00) | ((ram->size & 0x000000ff) << 32);
+
+ ram->part_mask = (nv_rd32(pfb, 0x001540) & 0x00ff0000) >> 16;
+ ram->parts = hweight8(ram->part_mask);
+
+ switch (nv_rd32(pfb, 0x100714) & 0x00000007) {
+ case 0: ram->type = NV_MEM_TYPE_DDR1; break;
+ case 1:
+ if (nvkm_fb_bios_memtype(bios) == NV_MEM_TYPE_DDR3)
+ ram->type = NV_MEM_TYPE_DDR3;
+ else
+ ram->type = NV_MEM_TYPE_DDR2;
+ break;
+ case 2: ram->type = NV_MEM_TYPE_GDDR3; break;
+ case 3: ram->type = NV_MEM_TYPE_GDDR4; break;
+ case 4: ram->type = NV_MEM_TYPE_GDDR5; break;
+ default:
+ break;
+ }
+
+ ret = nvkm_mm_init(&pfb->vram, rsvd_head, (ram->size >> 12) -
+ (rsvd_head + rsvd_tail),
+ nv50_fb_vram_rblock(pfb, ram) >> 12);
+ if (ret)
+ return ret;
+
+ ram->ranks = (nv_rd32(pfb, 0x100200) & 0x4) ? 2 : 1;
+ ram->tags = nv_rd32(pfb, 0x100320);
+ ram->get = nv50_ram_get;
+ ram->put = nv50_ram_put;
+ return 0;
+}
+
+static int
+nv50_ram_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 datasize,
+ struct nvkm_object **pobject)
+{
+ struct nv50_ram *ram;
+ int ret, i;
+
+ ret = nv50_ram_create(parent, engine, oclass, &ram);
+ *pobject = nv_object(ram);
+ if (ret)
+ return ret;
+
+ switch (ram->base.type) {
+ case NV_MEM_TYPE_DDR2:
+ case NV_MEM_TYPE_GDDR3:
+ ram->base.calc = nv50_ram_calc;
+ ram->base.prog = nv50_ram_prog;
+ ram->base.tidy = nv50_ram_tidy;
+ break;
+ default:
+ nv_warn(ram, "reclocking of this ram type unsupported\n");
+ return 0;
+ }
+
+ ram->hwsq.r_0x002504 = hwsq_reg(0x002504);
+ ram->hwsq.r_0x00c040 = hwsq_reg(0x00c040);
+ ram->hwsq.r_0x004008 = hwsq_reg(0x004008);
+ ram->hwsq.r_0x00400c = hwsq_reg(0x00400c);
+ ram->hwsq.r_0x100210 = hwsq_reg(0x100210);
+ ram->hwsq.r_0x1002d0 = hwsq_reg(0x1002d0);
+ ram->hwsq.r_0x1002d4 = hwsq_reg(0x1002d4);
+ ram->hwsq.r_0x1002dc = hwsq_reg(0x1002dc);
+ for (i = 0; i < 8; i++)
+ ram->hwsq.r_0x100da0[i] = hwsq_reg(0x100da0 + (i * 0x04));
+ ram->hwsq.r_0x100e20 = hwsq_reg(0x100e20);
+ ram->hwsq.r_0x100e24 = hwsq_reg(0x100e24);
+ ram->hwsq.r_0x611200 = hwsq_reg(0x611200);
+
+ for (i = 0; i < 9; i++)
+ ram->hwsq.r_timing[i] = hwsq_reg(0x100220 + (i * 0x04));
+
+ if (ram->base.ranks > 1) {
+ ram->hwsq.r_mr[0] = hwsq_reg2(0x1002c0, 0x1002c8);
+ ram->hwsq.r_mr[1] = hwsq_reg2(0x1002c4, 0x1002cc);
+ ram->hwsq.r_mr[2] = hwsq_reg2(0x1002e0, 0x1002e8);
+ ram->hwsq.r_mr[3] = hwsq_reg2(0x1002e4, 0x1002ec);
+ } else {
+ ram->hwsq.r_mr[0] = hwsq_reg(0x1002c0);
+ ram->hwsq.r_mr[1] = hwsq_reg(0x1002c4);
+ ram->hwsq.r_mr[2] = hwsq_reg(0x1002e0);
+ ram->hwsq.r_mr[3] = hwsq_reg(0x1002e4);
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass
+nv50_ram_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_ram_ctor,
+ .dtor = _nvkm_ram_dtor,
+ .init = _nvkm_ram_init,
+ .fini = _nvkm_ram_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h
new file mode 100644
index 000000000000..0f1f97ccd5f6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/ramseq.h
@@ -0,0 +1,15 @@
+#ifndef __NVKM_FBRAM_SEQ_H__
+#define __NVKM_FBRAM_SEQ_H__
+#include <subdev/bus/hwsq.h>
+
+#define ram_init(s,p) hwsq_init(&(s)->base, (p))
+#define ram_exec(s,e) hwsq_exec(&(s)->base, (e))
+#define ram_have(s,r) ((s)->r_##r.addr != 0x000000)
+#define ram_rd32(s,r) hwsq_rd32(&(s)->base, &(s)->r_##r)
+#define ram_wr32(s,r,d) hwsq_wr32(&(s)->base, &(s)->r_##r, (d))
+#define ram_nuke(s,r) hwsq_nuke(&(s)->base, &(s)->r_##r)
+#define ram_mask(s,r,m,d) hwsq_mask(&(s)->base, &(s)->r_##r, (m), (d))
+#define ram_setf(s,f,d) hwsq_setf(&(s)->base, (f), (d))
+#define ram_wait(s,f,d) hwsq_wait(&(s)->base, (f), (d))
+#define ram_nsec(s,n) hwsq_nsec(&(s)->base, (n))
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h
new file mode 100644
index 000000000000..1f865f61504e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/regsnv04.h
@@ -0,0 +1,22 @@
+#ifndef __NVKM_FB_REGS_04_H__
+#define __NVKM_FB_REGS_04_H__
+
+#define NV04_PFB_BOOT_0 0x00100000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT 0x00000003
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_32MB 0x00000000
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_4MB 0x00000001
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_8MB 0x00000002
+# define NV04_PFB_BOOT_0_RAM_AMOUNT_16MB 0x00000003
+# define NV04_PFB_BOOT_0_RAM_WIDTH_128 0x00000004
+# define NV04_PFB_BOOT_0_RAM_TYPE 0x00000028
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_8MBIT 0x00000000
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT 0x00000008
+# define NV04_PFB_BOOT_0_RAM_TYPE_SGRAM_16MBIT_4BANK 0x00000010
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_16MBIT 0x00000018
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBIT 0x00000020
+# define NV04_PFB_BOOT_0_RAM_TYPE_SDRAM_64MBITX16 0x00000028
+# define NV04_PFB_BOOT_0_UMA_ENABLE 0x00000100
+# define NV04_PFB_BOOT_0_UMA_SIZE 0x0000f000
+#define NV04_PFB_CFG0 0x00100200
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c
new file mode 100644
index 000000000000..afab42df28d4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr2.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Roy Spliet
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Roy Spliet <rspliet@eclipso.eu>
+ * Ben Skeggs
+ */
+#include "priv.h"
+
+struct ramxlat {
+ int id;
+ u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+ while (xlat->id >= 0) {
+ if (xlat->id == id)
+ return xlat->enc;
+ xlat++;
+ }
+ return -EINVAL;
+}
+
+static const struct ramxlat
+ramddr2_cl[] = {
+ { 2, 2 }, { 3, 3 }, { 4, 4 }, { 5, 5 }, { 6, 6 },
+ /* The following are available in some, but not all DDR2 docs */
+ { 7, 7 },
+ { -1 }
+};
+
+static const struct ramxlat
+ramddr2_wr[] = {
+ { 2, 1 }, { 3, 2 }, { 4, 3 }, { 5, 4 }, { 6, 5 },
+ /* The following are available in some, but not all DDR2 docs */
+ { 7, 6 },
+ { -1 }
+};
+
+int
+nvkm_sddr2_calc(struct nvkm_ram *ram)
+{
+ int CL, WR, DLL = 0, ODT = 0;
+
+ switch (ram->next->bios.timing_ver) {
+ case 0x10:
+ CL = ram->next->bios.timing_10_CL;
+ WR = ram->next->bios.timing_10_WR;
+ DLL = !ram->next->bios.ramcfg_10_DLLoff;
+ ODT = ram->next->bios.timing_10_ODT & 3;
+ break;
+ case 0x20:
+ CL = (ram->next->bios.timing[1] & 0x0000001f);
+ WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ CL = ramxlat(ramddr2_cl, CL);
+ WR = ramxlat(ramddr2_wr, WR);
+ if (CL < 0 || WR < 0)
+ return -EINVAL;
+
+ ram->mr[0] &= ~0xf70;
+ ram->mr[0] |= (WR & 0x07) << 9;
+ ram->mr[0] |= (CL & 0x07) << 4;
+
+ ram->mr[1] &= ~0x045;
+ ram->mr[1] |= (ODT & 0x1) << 2;
+ ram->mr[1] |= (ODT & 0x2) << 5;
+ ram->mr[1] |= !DLL;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c
new file mode 100644
index 000000000000..10844355c3f3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fb/sddr3.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ * Roy Spliet <rspliet@eclipso.eu>
+ */
+#include "priv.h"
+
+struct ramxlat {
+ int id;
+ u8 enc;
+};
+
+static inline int
+ramxlat(const struct ramxlat *xlat, int id)
+{
+ while (xlat->id >= 0) {
+ if (xlat->id == id)
+ return xlat->enc;
+ xlat++;
+ }
+ return -EINVAL;
+}
+
+static const struct ramxlat
+ramddr3_cl[] = {
+ { 5, 2 }, { 6, 4 }, { 7, 6 }, { 8, 8 }, { 9, 10 }, { 10, 12 },
+ { 11, 14 },
+ /* the below are mentioned in some, but not all, ddr3 docs */
+ { 12, 1 }, { 13, 3 }, { 14, 5 },
+ { -1 }
+};
+
+static const struct ramxlat
+ramddr3_wr[] = {
+ { 5, 1 }, { 6, 2 }, { 7, 3 }, { 8, 4 }, { 10, 5 }, { 12, 6 },
+ /* the below are mentioned in some, but not all, ddr3 docs */
+ { 14, 7 }, { 16, 0 },
+ { -1 }
+};
+
+static const struct ramxlat
+ramddr3_cwl[] = {
+ { 5, 0 }, { 6, 1 }, { 7, 2 }, { 8, 3 },
+ /* the below are mentioned in some, but not all, ddr3 docs */
+ { 9, 4 },
+ { -1 }
+};
+
+int
+nvkm_sddr3_calc(struct nvkm_ram *ram)
+{
+ int CWL, CL, WR, DLL = 0, ODT = 0;
+
+ switch (ram->next->bios.timing_ver) {
+ case 0x10:
+ if (ram->next->bios.timing_hdr < 0x17) {
+ /* XXX: NV50: Get CWL from the timing register */
+ return -ENOSYS;
+ }
+ CWL = ram->next->bios.timing_10_CWL;
+ CL = ram->next->bios.timing_10_CL;
+ WR = ram->next->bios.timing_10_WR;
+ DLL = !ram->next->bios.ramcfg_10_DLLoff;
+ ODT = ram->next->bios.timing_10_ODT;
+ break;
+ case 0x20:
+ CWL = (ram->next->bios.timing[1] & 0x00000f80) >> 7;
+ CL = (ram->next->bios.timing[1] & 0x0000001f) >> 0;
+ WR = (ram->next->bios.timing[2] & 0x007f0000) >> 16;
+ /* XXX: Get these values from the VBIOS instead */
+ DLL = !(ram->mr[1] & 0x1);
+ ODT = (ram->mr[1] & 0x004) >> 2 |
+ (ram->mr[1] & 0x040) >> 5 |
+ (ram->mr[1] & 0x200) >> 7;
+ break;
+ default:
+ return -ENOSYS;
+ }
+
+ CWL = ramxlat(ramddr3_cwl, CWL);
+ CL = ramxlat(ramddr3_cl, CL);
+ WR = ramxlat(ramddr3_wr, WR);
+ if (CL < 0 || CWL < 0 || WR < 0)
+ return -EINVAL;
+
+ ram->mr[0] &= ~0xf74;
+ ram->mr[0] |= (WR & 0x07) << 9;
+ ram->mr[0] |= (CL & 0x0e) << 3;
+ ram->mr[0] |= (CL & 0x01) << 2;
+
+ ram->mr[1] &= ~0x245;
+ ram->mr[1] |= (ODT & 0x1) << 2;
+ ram->mr[1] |= (ODT & 0x2) << 5;
+ ram->mr[1] |= (ODT & 0x4) << 7;
+ ram->mr[1] |= !DLL;
+
+ ram->mr[2] &= ~0x038;
+ ram->mr[2] |= (CWL & 0x07) << 3;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild
new file mode 100644
index 000000000000..f3d4e6e131b6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/fuse/base.o
+nvkm-y += nvkm/subdev/fuse/nv50.o
+nvkm-y += nvkm/subdev/fuse/gf100.o
+nvkm-y += nvkm/subdev/fuse/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c
new file mode 100644
index 000000000000..b7b7193bbce7
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/base.c
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/fuse.h>
+
+int
+_nvkm_fuse_init(struct nvkm_object *object)
+{
+ struct nvkm_fuse *fuse = (void *)object;
+ return nvkm_subdev_init(&fuse->base);
+}
+
+void
+_nvkm_fuse_dtor(struct nvkm_object *object)
+{
+ struct nvkm_fuse *fuse = (void *)object;
+ nvkm_subdev_destroy(&fuse->base);
+}
+
+int
+nvkm_fuse_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_fuse *fuse;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "FUSE",
+ "fuse", length, pobject);
+ fuse = *pobject;
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c
new file mode 100644
index 000000000000..393ef3a0faaf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gf100.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+struct gf100_fuse_priv {
+ struct nvkm_fuse base;
+
+ spinlock_t fuse_enable_lock;
+};
+
+static u32
+gf100_fuse_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct gf100_fuse_priv *priv = (void *)object;
+ unsigned long flags;
+ u32 fuse_enable, unk, val;
+
+ /* racy if another part of nvkm start writing to these regs */
+ spin_lock_irqsave(&priv->fuse_enable_lock, flags);
+ fuse_enable = nv_mask(priv, 0x22400, 0x800, 0x800);
+ unk = nv_mask(priv, 0x21000, 0x1, 0x1);
+ val = nv_rd32(priv, 0x21100 + addr);
+ nv_wr32(priv, 0x21000, unk);
+ nv_wr32(priv, 0x22400, fuse_enable);
+ spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
+ return val;
+}
+
+
+static int
+gf100_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_fuse_priv *priv;
+ int ret;
+
+ ret = nvkm_fuse_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&priv->fuse_enable_lock);
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_fuse_oclass = {
+ .handle = NV_SUBDEV(FUSE, 0xC0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_fuse_ctor,
+ .dtor = _nvkm_fuse_dtor,
+ .init = _nvkm_fuse_init,
+ .fini = _nvkm_fuse_fini,
+ .rd32 = gf100_fuse_rd32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c
new file mode 100644
index 000000000000..ba19158a5912
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/gm107.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+struct gm107_fuse_priv {
+ struct nvkm_fuse base;
+};
+
+static u32
+gm107_fuse_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct gf100_fuse_priv *priv = (void *)object;
+ return nv_rd32(priv, 0x21100 + addr);
+}
+
+
+static int
+gm107_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gm107_fuse_priv *priv;
+ int ret;
+
+ ret = nvkm_fuse_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass
+gm107_fuse_oclass = {
+ .handle = NV_SUBDEV(FUSE, 0x117),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm107_fuse_ctor,
+ .dtor = _nvkm_fuse_dtor,
+ .init = _nvkm_fuse_init,
+ .fini = _nvkm_fuse_fini,
+ .rd32 = gm107_fuse_rd32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c
new file mode 100644
index 000000000000..0d2afc426100
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/nv50.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+struct nv50_fuse_priv {
+ struct nvkm_fuse base;
+
+ spinlock_t fuse_enable_lock;
+};
+
+static u32
+nv50_fuse_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nv50_fuse_priv *priv = (void *)object;
+ unsigned long flags;
+ u32 fuse_enable, val;
+
+ /* racy if another part of nvkm start writing to this reg */
+ spin_lock_irqsave(&priv->fuse_enable_lock, flags);
+ fuse_enable = nv_mask(priv, 0x1084, 0x800, 0x800);
+ val = nv_rd32(priv, 0x21000 + addr);
+ nv_wr32(priv, 0x1084, fuse_enable);
+ spin_unlock_irqrestore(&priv->fuse_enable_lock, flags);
+ return val;
+}
+
+
+static int
+nv50_fuse_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_fuse_priv *priv;
+ int ret;
+
+ ret = nvkm_fuse_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&priv->fuse_enable_lock);
+ return 0;
+}
+
+struct nvkm_oclass
+nv50_fuse_oclass = {
+ .handle = NV_SUBDEV(FUSE, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_fuse_ctor,
+ .dtor = _nvkm_fuse_dtor,
+ .init = _nvkm_fuse_init,
+ .fini = _nvkm_fuse_fini,
+ .rd32 = nv50_fuse_rd32,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h
new file mode 100644
index 000000000000..7e050f789384
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/fuse/priv.h
@@ -0,0 +1,7 @@
+#ifndef __NVKM_FUSE_PRIV_H__
+#define __NVKM_FUSE_PRIV_H__
+#include <subdev/fuse.h>
+
+int _nvkm_fuse_init(struct nvkm_object *object);
+void _nvkm_fuse_dtor(struct nvkm_object *object);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild
new file mode 100644
index 000000000000..ea42a9ed1821
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/Kbuild
@@ -0,0 +1,6 @@
+nvkm-y += nvkm/subdev/gpio/base.o
+nvkm-y += nvkm/subdev/gpio/nv10.o
+nvkm-y += nvkm/subdev/gpio/nv50.o
+nvkm-y += nvkm/subdev/gpio/g94.o
+nvkm-y += nvkm/subdev/gpio/gf110.o
+nvkm-y += nvkm/subdev/gpio/gk104.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
new file mode 100644
index 000000000000..dea58161ba46
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/base.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/notify.h>
+
+static int
+nvkm_gpio_drive(struct nvkm_gpio *gpio, int idx, int line, int dir, int out)
+{
+ const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+ return impl->drive ? impl->drive(gpio, line, dir, out) : -ENODEV;
+}
+
+static int
+nvkm_gpio_sense(struct nvkm_gpio *gpio, int idx, int line)
+{
+ const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+ return impl->sense ? impl->sense(gpio, line) : -ENODEV;
+}
+
+static int
+nvkm_gpio_find(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line,
+ struct dcb_gpio_func *func)
+{
+ struct nvkm_bios *bios = nvkm_bios(gpio);
+ u8 ver, len;
+ u16 data;
+
+ if (line == 0xff && tag == 0xff)
+ return -EINVAL;
+
+ data = dcb_gpio_match(bios, idx, tag, line, &ver, &len, func);
+ if (data)
+ return 0;
+
+ /* Apple iMac G4 NV18 */
+ if (nv_device_match(nv_object(gpio), 0x0189, 0x10de, 0x0010)) {
+ if (tag == DCB_GPIO_TVDAC0) {
+ *func = (struct dcb_gpio_func) {
+ .func = DCB_GPIO_TVDAC0,
+ .line = 4,
+ .log[0] = 0,
+ .log[1] = 1,
+ };
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+static int
+nvkm_gpio_set(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line, int state)
+{
+ struct dcb_gpio_func func;
+ int ret;
+
+ ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
+ if (ret == 0) {
+ int dir = !!(func.log[state] & 0x02);
+ int out = !!(func.log[state] & 0x01);
+ ret = nvkm_gpio_drive(gpio, idx, func.line, dir, out);
+ }
+
+ return ret;
+}
+
+static int
+nvkm_gpio_get(struct nvkm_gpio *gpio, int idx, u8 tag, u8 line)
+{
+ struct dcb_gpio_func func;
+ int ret;
+
+ ret = nvkm_gpio_find(gpio, idx, tag, line, &func);
+ if (ret == 0) {
+ ret = nvkm_gpio_sense(gpio, idx, func.line);
+ if (ret >= 0)
+ ret = (ret == (func.log[1] & 1));
+ }
+
+ return ret;
+}
+
+static void
+nvkm_gpio_intr_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
+ const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+ impl->intr_mask(gpio, type, 1 << index, 0);
+}
+
+static void
+nvkm_gpio_intr_init(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_gpio *gpio = container_of(event, typeof(*gpio), event);
+ const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+ impl->intr_mask(gpio, type, 1 << index, 1 << index);
+}
+
+static int
+nvkm_gpio_intr_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ struct nvkm_gpio_ntfy_req *req = data;
+ if (!WARN_ON(size != sizeof(*req))) {
+ notify->size = sizeof(struct nvkm_gpio_ntfy_rep);
+ notify->types = req->mask;
+ notify->index = req->line;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void
+nvkm_gpio_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(subdev);
+ const struct nvkm_gpio_impl *impl = (void *)nv_object(gpio)->oclass;
+ u32 hi, lo, i;
+
+ impl->intr_stat(gpio, &hi, &lo);
+
+ for (i = 0; (hi | lo) && i < impl->lines; i++) {
+ struct nvkm_gpio_ntfy_rep rep = {
+ .mask = (NVKM_GPIO_HI * !!(hi & (1 << i))) |
+ (NVKM_GPIO_LO * !!(lo & (1 << i))),
+ };
+ nvkm_event_send(&gpio->event, rep.mask, i, &rep, sizeof(rep));
+ }
+}
+
+static const struct nvkm_event_func
+nvkm_gpio_intr_func = {
+ .ctor = nvkm_gpio_intr_ctor,
+ .init = nvkm_gpio_intr_init,
+ .fini = nvkm_gpio_intr_fini,
+};
+
+int
+_nvkm_gpio_fini(struct nvkm_object *object, bool suspend)
+{
+ const struct nvkm_gpio_impl *impl = (void *)object->oclass;
+ struct nvkm_gpio *gpio = nvkm_gpio(object);
+ u32 mask = (1 << impl->lines) - 1;
+
+ impl->intr_mask(gpio, NVKM_GPIO_TOGGLED, mask, 0);
+ impl->intr_stat(gpio, &mask, &mask);
+
+ return nvkm_subdev_fini(&gpio->base, suspend);
+}
+
+static struct dmi_system_id gpio_reset_ids[] = {
+ {
+ .ident = "Apple Macbook 10,1",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Apple Inc."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "MacBookPro10,1"),
+ }
+ },
+ { }
+};
+
+int
+_nvkm_gpio_init(struct nvkm_object *object)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(object);
+ int ret;
+
+ ret = nvkm_subdev_init(&gpio->base);
+ if (ret)
+ return ret;
+
+ if (gpio->reset && dmi_check_system(gpio_reset_ids))
+ gpio->reset(gpio, DCB_GPIO_UNUSED);
+
+ return ret;
+}
+
+void
+_nvkm_gpio_dtor(struct nvkm_object *object)
+{
+ struct nvkm_gpio *gpio = (void *)object;
+ nvkm_event_fini(&gpio->event);
+ nvkm_subdev_destroy(&gpio->base);
+}
+
+int
+nvkm_gpio_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ const struct nvkm_gpio_impl *impl = (void *)oclass;
+ struct nvkm_gpio *gpio;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "GPIO",
+ "gpio", length, pobject);
+ gpio = *pobject;
+ if (ret)
+ return ret;
+
+ gpio->find = nvkm_gpio_find;
+ gpio->set = nvkm_gpio_set;
+ gpio->get = nvkm_gpio_get;
+ gpio->reset = impl->reset;
+
+ ret = nvkm_event_init(&nvkm_gpio_intr_func, 2, impl->lines,
+ &gpio->event);
+ if (ret)
+ return ret;
+
+ nv_subdev(gpio)->intr = nvkm_gpio_intr;
+ return 0;
+}
+
+int
+_nvkm_gpio_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_gpio *gpio;
+ int ret;
+
+ ret = nvkm_gpio_create(parent, engine, oclass, &gpio);
+ *pobject = nv_object(gpio);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c
new file mode 100644
index 000000000000..12b3e01fca8e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/g94.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+void
+g94_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+ u32 intr0 = nv_rd32(gpio, 0x00e054);
+ u32 intr1 = nv_rd32(gpio, 0x00e074);
+ u32 stat0 = nv_rd32(gpio, 0x00e050) & intr0;
+ u32 stat1 = nv_rd32(gpio, 0x00e070) & intr1;
+ *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
+ *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
+ nv_wr32(gpio, 0x00e054, intr0);
+ nv_wr32(gpio, 0x00e074, intr1);
+}
+
+void
+g94_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+ u32 inte0 = nv_rd32(gpio, 0x00e050);
+ u32 inte1 = nv_rd32(gpio, 0x00e070);
+ if (type & NVKM_GPIO_LO)
+ inte0 = (inte0 & ~(mask << 16)) | (data << 16);
+ if (type & NVKM_GPIO_HI)
+ inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
+ mask >>= 16;
+ data >>= 16;
+ if (type & NVKM_GPIO_LO)
+ inte1 = (inte1 & ~(mask << 16)) | (data << 16);
+ if (type & NVKM_GPIO_HI)
+ inte1 = (inte1 & ~mask) | data;
+ nv_wr32(gpio, 0x00e050, inte0);
+ nv_wr32(gpio, 0x00e070, inte1);
+}
+
+struct nvkm_oclass *
+g94_gpio_oclass = &(struct nvkm_gpio_impl) {
+ .base.handle = NV_SUBDEV(GPIO, 0x94),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_gpio_ctor,
+ .dtor = _nvkm_gpio_dtor,
+ .init = _nvkm_gpio_init,
+ .fini = _nvkm_gpio_fini,
+ },
+ .lines = 32,
+ .intr_stat = g94_gpio_intr_stat,
+ .intr_mask = g94_gpio_intr_mask,
+ .drive = nv50_gpio_drive,
+ .sense = nv50_gpio_sense,
+ .reset = nv50_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c
new file mode 100644
index 000000000000..2c3bb255d1f8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gf110.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+void
+gf110_gpio_reset(struct nvkm_gpio *gpio, u8 match)
+{
+ struct nvkm_bios *bios = nvkm_bios(gpio);
+ u8 ver, len;
+ u16 entry;
+ int ent = -1;
+
+ while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
+ u32 data = nv_ro32(bios, entry);
+ u8 line = (data & 0x0000003f);
+ u8 defs = !!(data & 0x00000080);
+ u8 func = (data & 0x0000ff00) >> 8;
+ u8 unk0 = (data & 0x00ff0000) >> 16;
+ u8 unk1 = (data & 0x1f000000) >> 24;
+
+ if ( func == DCB_GPIO_UNUSED ||
+ (match != DCB_GPIO_UNUSED && match != func))
+ continue;
+
+ gpio->set(gpio, 0, func, line, defs);
+
+ nv_mask(gpio, 0x00d610 + (line * 4), 0xff, unk0);
+ if (unk1--)
+ nv_mask(gpio, 0x00d740 + (unk1 * 4), 0xff, line);
+ }
+}
+
+int
+gf110_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
+{
+ u32 data = ((dir ^ 1) << 13) | (out << 12);
+ nv_mask(gpio, 0x00d610 + (line * 4), 0x00003000, data);
+ nv_mask(gpio, 0x00d604, 0x00000001, 0x00000001); /* update? */
+ return 0;
+}
+
+int
+gf110_gpio_sense(struct nvkm_gpio *gpio, int line)
+{
+ return !!(nv_rd32(gpio, 0x00d610 + (line * 4)) & 0x00004000);
+}
+
+struct nvkm_oclass *
+gf110_gpio_oclass = &(struct nvkm_gpio_impl) {
+ .base.handle = NV_SUBDEV(GPIO, 0xd0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_gpio_ctor,
+ .dtor = _nvkm_gpio_dtor,
+ .init = _nvkm_gpio_init,
+ .fini = _nvkm_gpio_fini,
+ },
+ .lines = 32,
+ .intr_stat = g94_gpio_intr_stat,
+ .intr_mask = g94_gpio_intr_mask,
+ .drive = gf110_gpio_drive,
+ .sense = gf110_gpio_sense,
+ .reset = gf110_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c
new file mode 100644
index 000000000000..42fd2faaaa4f
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/gk104.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static void
+gk104_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+ u32 intr0 = nv_rd32(gpio, 0x00dc00);
+ u32 intr1 = nv_rd32(gpio, 0x00dc80);
+ u32 stat0 = nv_rd32(gpio, 0x00dc08) & intr0;
+ u32 stat1 = nv_rd32(gpio, 0x00dc88) & intr1;
+ *lo = (stat1 & 0xffff0000) | (stat0 >> 16);
+ *hi = (stat1 << 16) | (stat0 & 0x0000ffff);
+ nv_wr32(gpio, 0x00dc00, intr0);
+ nv_wr32(gpio, 0x00dc80, intr1);
+}
+
+void
+gk104_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+ u32 inte0 = nv_rd32(gpio, 0x00dc08);
+ u32 inte1 = nv_rd32(gpio, 0x00dc88);
+ if (type & NVKM_GPIO_LO)
+ inte0 = (inte0 & ~(mask << 16)) | (data << 16);
+ if (type & NVKM_GPIO_HI)
+ inte0 = (inte0 & ~(mask & 0xffff)) | (data & 0xffff);
+ mask >>= 16;
+ data >>= 16;
+ if (type & NVKM_GPIO_LO)
+ inte1 = (inte1 & ~(mask << 16)) | (data << 16);
+ if (type & NVKM_GPIO_HI)
+ inte1 = (inte1 & ~mask) | data;
+ nv_wr32(gpio, 0x00dc08, inte0);
+ nv_wr32(gpio, 0x00dc88, inte1);
+}
+
+struct nvkm_oclass *
+gk104_gpio_oclass = &(struct nvkm_gpio_impl) {
+ .base.handle = NV_SUBDEV(GPIO, 0xe0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_gpio_ctor,
+ .dtor = _nvkm_gpio_dtor,
+ .init = _nvkm_gpio_init,
+ .fini = _nvkm_gpio_fini,
+ },
+ .lines = 32,
+ .intr_stat = gk104_gpio_intr_stat,
+ .intr_mask = gk104_gpio_intr_mask,
+ .drive = gf110_gpio_drive,
+ .sense = gf110_gpio_sense,
+ .reset = gf110_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c
new file mode 100644
index 000000000000..2b295154247e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv10.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2009 Francisco Jerez.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include "priv.h"
+
+static int
+nv10_gpio_sense(struct nvkm_gpio *gpio, int line)
+{
+ if (line < 2) {
+ line = line * 16;
+ line = nv_rd32(gpio, 0x600818) >> line;
+ return !!(line & 0x0100);
+ } else
+ if (line < 10) {
+ line = (line - 2) * 4;
+ line = nv_rd32(gpio, 0x60081c) >> line;
+ return !!(line & 0x04);
+ } else
+ if (line < 14) {
+ line = (line - 10) * 4;
+ line = nv_rd32(gpio, 0x600850) >> line;
+ return !!(line & 0x04);
+ }
+
+ return -EINVAL;
+}
+
+static int
+nv10_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
+{
+ u32 reg, mask, data;
+
+ if (line < 2) {
+ line = line * 16;
+ reg = 0x600818;
+ mask = 0x00000011;
+ data = (dir << 4) | out;
+ } else
+ if (line < 10) {
+ line = (line - 2) * 4;
+ reg = 0x60081c;
+ mask = 0x00000003;
+ data = (dir << 1) | out;
+ } else
+ if (line < 14) {
+ line = (line - 10) * 4;
+ reg = 0x600850;
+ mask = 0x00000003;
+ data = (dir << 1) | out;
+ } else {
+ return -EINVAL;
+ }
+
+ nv_mask(gpio, reg, mask << line, data << line);
+ return 0;
+}
+
+static void
+nv10_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+ u32 intr = nv_rd32(gpio, 0x001104);
+ u32 stat = nv_rd32(gpio, 0x001144) & intr;
+ *lo = (stat & 0xffff0000) >> 16;
+ *hi = (stat & 0x0000ffff);
+ nv_wr32(gpio, 0x001104, intr);
+}
+
+static void
+nv10_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+ u32 inte = nv_rd32(gpio, 0x001144);
+ if (type & NVKM_GPIO_LO)
+ inte = (inte & ~(mask << 16)) | (data << 16);
+ if (type & NVKM_GPIO_HI)
+ inte = (inte & ~mask) | data;
+ nv_wr32(gpio, 0x001144, inte);
+}
+
+struct nvkm_oclass *
+nv10_gpio_oclass = &(struct nvkm_gpio_impl) {
+ .base.handle = NV_SUBDEV(GPIO, 0x10),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_gpio_ctor,
+ .dtor = _nvkm_gpio_dtor,
+ .init = _nvkm_gpio_init,
+ .fini = _nvkm_gpio_fini,
+ },
+ .lines = 16,
+ .intr_stat = nv10_gpio_intr_stat,
+ .intr_mask = nv10_gpio_intr_mask,
+ .drive = nv10_gpio_drive,
+ .sense = nv10_gpio_sense,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c
new file mode 100644
index 000000000000..6a031035bd27
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/nv50.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+void
+nv50_gpio_reset(struct nvkm_gpio *gpio, u8 match)
+{
+ struct nvkm_bios *bios = nvkm_bios(gpio);
+ u8 ver, len;
+ u16 entry;
+ int ent = -1;
+
+ while ((entry = dcb_gpio_entry(bios, 0, ++ent, &ver, &len))) {
+ static const u32 regs[] = { 0xe100, 0xe28c };
+ u32 data = nv_ro32(bios, entry);
+ u8 line = (data & 0x0000001f);
+ u8 func = (data & 0x0000ff00) >> 8;
+ u8 defs = !!(data & 0x01000000);
+ u8 unk0 = !!(data & 0x02000000);
+ u8 unk1 = !!(data & 0x04000000);
+ u32 val = (unk1 << 16) | unk0;
+ u32 reg = regs[line >> 4];
+ u32 lsh = line & 0x0f;
+
+ if ( func == DCB_GPIO_UNUSED ||
+ (match != DCB_GPIO_UNUSED && match != func))
+ continue;
+
+ gpio->set(gpio, 0, func, line, defs);
+
+ nv_mask(gpio, reg, 0x00010001 << lsh, val << lsh);
+ }
+}
+
+int
+nv50_gpio_location(int line, u32 *reg, u32 *shift)
+{
+ const u32 nv50_gpio_reg[4] = { 0xe104, 0xe108, 0xe280, 0xe284 };
+
+ if (line >= 32)
+ return -EINVAL;
+
+ *reg = nv50_gpio_reg[line >> 3];
+ *shift = (line & 7) << 2;
+ return 0;
+}
+
+int
+nv50_gpio_drive(struct nvkm_gpio *gpio, int line, int dir, int out)
+{
+ u32 reg, shift;
+
+ if (nv50_gpio_location(line, &reg, &shift))
+ return -EINVAL;
+
+ nv_mask(gpio, reg, 3 << shift, (((dir ^ 1) << 1) | out) << shift);
+ return 0;
+}
+
+int
+nv50_gpio_sense(struct nvkm_gpio *gpio, int line)
+{
+ u32 reg, shift;
+
+ if (nv50_gpio_location(line, &reg, &shift))
+ return -EINVAL;
+
+ return !!(nv_rd32(gpio, reg) & (4 << shift));
+}
+
+static void
+nv50_gpio_intr_stat(struct nvkm_gpio *gpio, u32 *hi, u32 *lo)
+{
+ u32 intr = nv_rd32(gpio, 0x00e054);
+ u32 stat = nv_rd32(gpio, 0x00e050) & intr;
+ *lo = (stat & 0xffff0000) >> 16;
+ *hi = (stat & 0x0000ffff);
+ nv_wr32(gpio, 0x00e054, intr);
+}
+
+static void
+nv50_gpio_intr_mask(struct nvkm_gpio *gpio, u32 type, u32 mask, u32 data)
+{
+ u32 inte = nv_rd32(gpio, 0x00e050);
+ if (type & NVKM_GPIO_LO)
+ inte = (inte & ~(mask << 16)) | (data << 16);
+ if (type & NVKM_GPIO_HI)
+ inte = (inte & ~mask) | data;
+ nv_wr32(gpio, 0x00e050, inte);
+}
+
+struct nvkm_oclass *
+nv50_gpio_oclass = &(struct nvkm_gpio_impl) {
+ .base.handle = NV_SUBDEV(GPIO, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_gpio_ctor,
+ .dtor = _nvkm_gpio_dtor,
+ .init = _nvkm_gpio_init,
+ .fini = _nvkm_gpio_fini,
+ },
+ .lines = 16,
+ .intr_stat = nv50_gpio_intr_stat,
+ .intr_mask = nv50_gpio_intr_mask,
+ .drive = nv50_gpio_drive,
+ .sense = nv50_gpio_sense,
+ .reset = nv50_gpio_reset,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h
new file mode 100644
index 000000000000..382f8d44e140
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/gpio/priv.h
@@ -0,0 +1,64 @@
+#ifndef __NVKM_GPIO_PRIV_H__
+#define __NVKM_GPIO_PRIV_H__
+#include <subdev/gpio.h>
+
+#define nvkm_gpio_create(p,e,o,d) \
+ nvkm_gpio_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_gpio_destroy(p) ({ \
+ struct nvkm_gpio *gpio = (p); \
+ _nvkm_gpio_dtor(nv_object(gpio)); \
+})
+#define nvkm_gpio_init(p) ({ \
+ struct nvkm_gpio *gpio = (p); \
+ _nvkm_gpio_init(nv_object(gpio)); \
+})
+#define nvkm_gpio_fini(p,s) ({ \
+ struct nvkm_gpio *gpio = (p); \
+ _nvkm_gpio_fini(nv_object(gpio), (s)); \
+})
+
+int nvkm_gpio_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+int _nvkm_gpio_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void _nvkm_gpio_dtor(struct nvkm_object *);
+int _nvkm_gpio_init(struct nvkm_object *);
+int _nvkm_gpio_fini(struct nvkm_object *, bool);
+
+struct nvkm_gpio_impl {
+ struct nvkm_oclass base;
+ int lines;
+
+ /* read and ack pending interrupts, returning only data
+ * for lines that have not been masked off, while still
+ * performing the ack for anything that was pending.
+ */
+ void (*intr_stat)(struct nvkm_gpio *, u32 *, u32 *);
+
+ /* mask on/off interrupts for hi/lo transitions on a
+ * given set of gpio lines
+ */
+ void (*intr_mask)(struct nvkm_gpio *, u32, u32, u32);
+
+ /* configure gpio direction and output value */
+ int (*drive)(struct nvkm_gpio *, int line, int dir, int out);
+
+ /* sense current state of given gpio line */
+ int (*sense)(struct nvkm_gpio *, int line);
+
+ /*XXX*/
+ void (*reset)(struct nvkm_gpio *, u8);
+};
+
+void nv50_gpio_reset(struct nvkm_gpio *, u8);
+int nv50_gpio_drive(struct nvkm_gpio *, int, int, int);
+int nv50_gpio_sense(struct nvkm_gpio *, int);
+
+void g94_gpio_intr_stat(struct nvkm_gpio *, u32 *, u32 *);
+void g94_gpio_intr_mask(struct nvkm_gpio *, u32, u32, u32);
+
+void gf110_gpio_reset(struct nvkm_gpio *, u8);
+int gf110_gpio_drive(struct nvkm_gpio *, int, int, int);
+int gf110_gpio_sense(struct nvkm_gpio *, int);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
new file mode 100644
index 000000000000..d68307409980
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/Kbuild
@@ -0,0 +1,16 @@
+nvkm-y += nvkm/subdev/i2c/base.o
+nvkm-y += nvkm/subdev/i2c/anx9805.o
+nvkm-y += nvkm/subdev/i2c/aux.o
+nvkm-y += nvkm/subdev/i2c/bit.o
+nvkm-y += nvkm/subdev/i2c/pad.o
+nvkm-y += nvkm/subdev/i2c/padnv04.o
+nvkm-y += nvkm/subdev/i2c/padg94.o
+nvkm-y += nvkm/subdev/i2c/padgm204.o
+nvkm-y += nvkm/subdev/i2c/nv04.o
+nvkm-y += nvkm/subdev/i2c/nv4e.o
+nvkm-y += nvkm/subdev/i2c/nv50.o
+nvkm-y += nvkm/subdev/i2c/g94.o
+nvkm-y += nvkm/subdev/i2c/gf110.o
+nvkm-y += nvkm/subdev/i2c/gf117.o
+nvkm-y += nvkm/subdev/i2c/gk104.o
+nvkm-y += nvkm/subdev/i2c/gm204.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
new file mode 100644
index 000000000000..d17dd1cf3c34
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/anx9805.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "port.h"
+
+struct anx9805_i2c_port {
+ struct nvkm_i2c_port base;
+ u32 addr;
+ u32 ctrl;
+};
+
+static int
+anx9805_train(struct nvkm_i2c_port *port, int link_nr, int link_bw, bool enh)
+{
+ struct anx9805_i2c_port *chan = (void *)port;
+ struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent;
+ u8 tmp, i;
+
+ DBG("ANX9805 train %d 0x%02x %d\n", link_nr, link_bw, enh);
+
+ nv_wri2cr(mast, chan->addr, 0xa0, link_bw);
+ nv_wri2cr(mast, chan->addr, 0xa1, link_nr | (enh ? 0x80 : 0x00));
+ nv_wri2cr(mast, chan->addr, 0xa2, 0x01);
+ nv_wri2cr(mast, chan->addr, 0xa8, 0x01);
+
+ i = 0;
+ while ((tmp = nv_rdi2cr(mast, chan->addr, 0xa8)) & 0x01) {
+ mdelay(5);
+ if (i++ == 100) {
+ nv_error(port, "link training timed out\n");
+ return -ETIMEDOUT;
+ }
+ }
+
+ if (tmp & 0x70) {
+ nv_error(port, "link training failed: 0x%02x\n", tmp);
+ return -EIO;
+ }
+
+ return 1;
+}
+
+static int
+anx9805_aux(struct nvkm_i2c_port *port, bool retry,
+ u8 type, u32 addr, u8 *data, u8 size)
+{
+ struct anx9805_i2c_port *chan = (void *)port;
+ struct nvkm_i2c_port *mast = (void *)nv_object(chan)->parent;
+ int i, ret = -ETIMEDOUT;
+ u8 buf[16] = {};
+ u8 tmp;
+
+ DBG("%02x %05x %d\n", type, addr, size);
+
+ tmp = nv_rdi2cr(mast, chan->ctrl, 0x07) & ~0x04;
+ nv_wri2cr(mast, chan->ctrl, 0x07, tmp | 0x04);
+ nv_wri2cr(mast, chan->ctrl, 0x07, tmp);
+ nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
+
+ nv_wri2cr(mast, chan->addr, 0xe4, 0x80);
+ if (!(type & 1)) {
+ memcpy(buf, data, size);
+ DBG("%16ph", buf);
+ for (i = 0; i < size; i++)
+ nv_wri2cr(mast, chan->addr, 0xf0 + i, buf[i]);
+ }
+ nv_wri2cr(mast, chan->addr, 0xe5, ((size - 1) << 4) | type);
+ nv_wri2cr(mast, chan->addr, 0xe6, (addr & 0x000ff) >> 0);
+ nv_wri2cr(mast, chan->addr, 0xe7, (addr & 0x0ff00) >> 8);
+ nv_wri2cr(mast, chan->addr, 0xe8, (addr & 0xf0000) >> 16);
+ nv_wri2cr(mast, chan->addr, 0xe9, 0x01);
+
+ i = 0;
+ while ((tmp = nv_rdi2cr(mast, chan->addr, 0xe9)) & 0x01) {
+ mdelay(5);
+ if (i++ == 32)
+ goto done;
+ }
+
+ if ((tmp = nv_rdi2cr(mast, chan->ctrl, 0xf7)) & 0x01) {
+ ret = -EIO;
+ goto done;
+ }
+
+ if (type & 1) {
+ for (i = 0; i < size; i++)
+ buf[i] = nv_rdi2cr(mast, chan->addr, 0xf0 + i);
+ DBG("%16ph", buf);
+ memcpy(data, buf, size);
+ }
+
+ ret = 0;
+done:
+ nv_wri2cr(mast, chan->ctrl, 0xf7, 0x01);
+ return ret;
+}
+
+static const struct nvkm_i2c_func
+anx9805_aux_func = {
+ .aux = anx9805_aux,
+ .lnk_ctl = anx9805_train,
+};
+
+static int
+anx9805_aux_chan_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_i2c_port *mast = (void *)parent;
+ struct anx9805_i2c_port *chan;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_aux_algo, &anx9805_aux_func,
+ &chan);
+ *pobject = nv_object(chan);
+ if (ret)
+ return ret;
+
+ switch ((oclass->handle & 0xff00) >> 8) {
+ case 0x0d:
+ chan->addr = 0x38;
+ chan->ctrl = 0x39;
+ break;
+ case 0x0e:
+ chan->addr = 0x3c;
+ chan->ctrl = 0x3b;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ if (mast->adapter.algo == &i2c_bit_algo) {
+ struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
+ algo->udelay = max(algo->udelay, 40);
+ }
+
+ return 0;
+}
+
+static struct nvkm_ofuncs
+anx9805_aux_ofuncs = {
+ .ctor = anx9805_aux_chan_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+};
+
+static int
+anx9805_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct anx9805_i2c_port *port = adap->algo_data;
+ struct nvkm_i2c_port *mast = (void *)nv_object(port)->parent;
+ struct i2c_msg *msg = msgs;
+ int ret = -ETIMEDOUT;
+ int i, j, cnt = num;
+ u8 seg = 0x00, off = 0x00, tmp;
+
+ tmp = nv_rdi2cr(mast, port->ctrl, 0x07) & ~0x10;
+ nv_wri2cr(mast, port->ctrl, 0x07, tmp | 0x10);
+ nv_wri2cr(mast, port->ctrl, 0x07, tmp);
+ nv_wri2cr(mast, port->addr, 0x43, 0x05);
+ mdelay(5);
+
+ while (cnt--) {
+ if ( (msg->flags & I2C_M_RD) && msg->addr == 0x50) {
+ nv_wri2cr(mast, port->addr, 0x40, msg->addr << 1);
+ nv_wri2cr(mast, port->addr, 0x41, seg);
+ nv_wri2cr(mast, port->addr, 0x42, off);
+ nv_wri2cr(mast, port->addr, 0x44, msg->len);
+ nv_wri2cr(mast, port->addr, 0x45, 0x00);
+ nv_wri2cr(mast, port->addr, 0x43, 0x01);
+ for (i = 0; i < msg->len; i++) {
+ j = 0;
+ while (nv_rdi2cr(mast, port->addr, 0x46) & 0x10) {
+ mdelay(5);
+ if (j++ == 32)
+ goto done;
+ }
+ msg->buf[i] = nv_rdi2cr(mast, port->addr, 0x47);
+ }
+ } else
+ if (!(msg->flags & I2C_M_RD)) {
+ if (msg->addr == 0x50 && msg->len == 0x01) {
+ off = msg->buf[0];
+ } else
+ if (msg->addr == 0x30 && msg->len == 0x01) {
+ seg = msg->buf[0];
+ } else
+ goto done;
+ } else {
+ goto done;
+ }
+ msg++;
+ }
+
+ ret = num;
+done:
+ nv_wri2cr(mast, port->addr, 0x43, 0x00);
+ return ret;
+}
+
+static u32
+anx9805_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm
+anx9805_i2c_algo = {
+ .master_xfer = anx9805_xfer,
+ .functionality = anx9805_func
+};
+
+static const struct nvkm_i2c_func
+anx9805_i2c_func = {
+};
+
+static int
+anx9805_ddc_port_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_i2c_port *mast = (void *)parent;
+ struct anx9805_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &anx9805_i2c_algo, &anx9805_i2c_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ switch ((oclass->handle & 0xff00) >> 8) {
+ case 0x0d:
+ port->addr = 0x3d;
+ port->ctrl = 0x39;
+ break;
+ case 0x0e:
+ port->addr = 0x3f;
+ port->ctrl = 0x3b;
+ break;
+ default:
+ BUG_ON(1);
+ }
+
+ if (mast->adapter.algo == &i2c_bit_algo) {
+ struct i2c_algo_bit_data *algo = mast->adapter.algo_data;
+ algo->udelay = max(algo->udelay, 40);
+ }
+
+ return 0;
+}
+
+static struct nvkm_ofuncs
+anx9805_ddc_ofuncs = {
+ .ctor = anx9805_ddc_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+};
+
+struct nvkm_oclass
+nvkm_anx9805_sclass[] = {
+ { .handle = NV_I2C_TYPE_EXTDDC(0x0d), .ofuncs = &anx9805_ddc_ofuncs },
+ { .handle = NV_I2C_TYPE_EXTAUX(0x0d), .ofuncs = &anx9805_aux_ofuncs },
+ { .handle = NV_I2C_TYPE_EXTDDC(0x0e), .ofuncs = &anx9805_ddc_ofuncs },
+ { .handle = NV_I2C_TYPE_EXTAUX(0x0e), .ofuncs = &anx9805_aux_ofuncs },
+ {}
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
new file mode 100644
index 000000000000..1c18860f80d1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/aux.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2009 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+int
+nv_rdaux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(port);
+ if (port->func->aux) {
+ int ret = i2c->acquire(port, 0);
+ if (ret == 0) {
+ ret = port->func->aux(port, true, 9, addr, data, size);
+ i2c->release(port);
+ }
+ return ret;
+ }
+ return -ENODEV;
+}
+
+int
+nv_wraux(struct nvkm_i2c_port *port, u32 addr, u8 *data, u8 size)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(port);
+ if (port->func->aux) {
+ int ret = i2c->acquire(port, 0);
+ if (ret == 0) {
+ ret = port->func->aux(port, true, 8, addr, data, size);
+ i2c->release(port);
+ }
+ return ret;
+ }
+ return -ENODEV;
+}
+
+static int
+aux_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct nvkm_i2c_port *port = adap->algo_data;
+ struct nvkm_i2c *i2c = nvkm_i2c(port);
+ struct i2c_msg *msg = msgs;
+ int ret, mcnt = num;
+
+ if (!port->func->aux)
+ return -ENODEV;
+
+ ret = i2c->acquire(port, 0);
+ if (ret)
+ return ret;
+
+ while (mcnt--) {
+ u8 remaining = msg->len;
+ u8 *ptr = msg->buf;
+
+ while (remaining) {
+ u8 cnt = (remaining > 16) ? 16 : remaining;
+ u8 cmd;
+
+ if (msg->flags & I2C_M_RD)
+ cmd = 1;
+ else
+ cmd = 0;
+
+ if (mcnt || remaining > 16)
+ cmd |= 4; /* MOT */
+
+ ret = port->func->aux(port, true, cmd, msg->addr, ptr, cnt);
+ if (ret < 0) {
+ i2c->release(port);
+ return ret;
+ }
+
+ ptr += cnt;
+ remaining -= cnt;
+ }
+
+ msg++;
+ }
+
+ i2c->release(port);
+ return num;
+}
+
+static u32
+aux_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nvkm_i2c_aux_algo = {
+ .master_xfer = aux_xfer,
+ .functionality = aux_func
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
new file mode 100644
index 000000000000..9200f122c02c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/base.c
@@ -0,0 +1,622 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "pad.h"
+
+#include <core/device.h>
+#include <core/notify.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/dcb.h>
+
+/******************************************************************************
+ * interface to linux i2c bit-banging algorithm
+ *****************************************************************************/
+
+#ifdef CONFIG_NOUVEAU_I2C_INTERNAL_DEFAULT
+#define CSTMSEL true
+#else
+#define CSTMSEL false
+#endif
+
+static int
+nvkm_i2c_pre_xfer(struct i2c_adapter *adap)
+{
+ struct i2c_algo_bit_data *bit = adap->algo_data;
+ struct nvkm_i2c_port *port = bit->data;
+ return nvkm_i2c(port)->acquire(port, bit->timeout);
+}
+
+static void
+nvkm_i2c_post_xfer(struct i2c_adapter *adap)
+{
+ struct i2c_algo_bit_data *bit = adap->algo_data;
+ struct nvkm_i2c_port *port = bit->data;
+ return nvkm_i2c(port)->release(port);
+}
+
+static void
+nvkm_i2c_setscl(void *data, int state)
+{
+ struct nvkm_i2c_port *port = data;
+ port->func->drive_scl(port, state);
+}
+
+static void
+nvkm_i2c_setsda(void *data, int state)
+{
+ struct nvkm_i2c_port *port = data;
+ port->func->drive_sda(port, state);
+}
+
+static int
+nvkm_i2c_getscl(void *data)
+{
+ struct nvkm_i2c_port *port = data;
+ return port->func->sense_scl(port);
+}
+
+static int
+nvkm_i2c_getsda(void *data)
+{
+ struct nvkm_i2c_port *port = data;
+ return port->func->sense_sda(port);
+}
+
+/******************************************************************************
+ * base i2c "port" class implementation
+ *****************************************************************************/
+
+int
+_nvkm_i2c_port_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_i2c_port *port = (void *)object;
+ struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
+ nv_ofuncs(pad)->fini(nv_object(pad), suspend);
+ return nvkm_object_fini(&port->base, suspend);
+}
+
+void
+_nvkm_i2c_port_dtor(struct nvkm_object *object)
+{
+ struct nvkm_i2c_port *port = (void *)object;
+ i2c_del_adapter(&port->adapter);
+ nvkm_object_destroy(&port->base);
+}
+
+int
+nvkm_i2c_port_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, u8 index,
+ const struct i2c_algorithm *algo,
+ const struct nvkm_i2c_func *func,
+ int size, void **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_i2c *i2c = nvkm_i2c(parent);
+ struct nvkm_i2c_port *port;
+ int ret;
+
+ ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject);
+ port = *pobject;
+ if (ret)
+ return ret;
+
+ snprintf(port->adapter.name, sizeof(port->adapter.name),
+ "nvkm-%s-%d", device->name, index);
+ port->adapter.owner = THIS_MODULE;
+ port->adapter.dev.parent = nv_device_base(device);
+ port->index = index;
+ port->aux = -1;
+ port->func = func;
+ mutex_init(&port->mutex);
+
+ if ( algo == &nvkm_i2c_bit_algo &&
+ !nvkm_boolopt(device->cfgopt, "NvI2C", CSTMSEL)) {
+ struct i2c_algo_bit_data *bit;
+
+ bit = kzalloc(sizeof(*bit), GFP_KERNEL);
+ if (!bit)
+ return -ENOMEM;
+
+ bit->udelay = 10;
+ bit->timeout = usecs_to_jiffies(2200);
+ bit->data = port;
+ bit->pre_xfer = nvkm_i2c_pre_xfer;
+ bit->post_xfer = nvkm_i2c_post_xfer;
+ bit->setsda = nvkm_i2c_setsda;
+ bit->setscl = nvkm_i2c_setscl;
+ bit->getsda = nvkm_i2c_getsda;
+ bit->getscl = nvkm_i2c_getscl;
+
+ port->adapter.algo_data = bit;
+ ret = i2c_bit_add_bus(&port->adapter);
+ } else {
+ port->adapter.algo_data = port;
+ port->adapter.algo = algo;
+ ret = i2c_add_adapter(&port->adapter);
+ }
+
+ if (ret == 0)
+ list_add_tail(&port->head, &i2c->ports);
+ return ret;
+}
+
+/******************************************************************************
+ * base i2c subdev class implementation
+ *****************************************************************************/
+
+static struct nvkm_i2c_port *
+nvkm_i2c_find(struct nvkm_i2c *i2c, u8 index)
+{
+ struct nvkm_bios *bios = nvkm_bios(i2c);
+ struct nvkm_i2c_port *port;
+
+ if (index == NV_I2C_DEFAULT(0) ||
+ index == NV_I2C_DEFAULT(1)) {
+ u8 ver, hdr, cnt, len;
+ u16 i2c = dcb_i2c_table(bios, &ver, &hdr, &cnt, &len);
+ if (i2c && ver >= 0x30) {
+ u8 auxidx = nv_ro08(bios, i2c + 4);
+ if (index == NV_I2C_DEFAULT(0))
+ index = (auxidx & 0x0f) >> 0;
+ else
+ index = (auxidx & 0xf0) >> 4;
+ } else {
+ index = 2;
+ }
+ }
+
+ list_for_each_entry(port, &i2c->ports, head) {
+ if (port->index == index)
+ return port;
+ }
+
+ return NULL;
+}
+
+static struct nvkm_i2c_port *
+nvkm_i2c_find_type(struct nvkm_i2c *i2c, u16 type)
+{
+ struct nvkm_i2c_port *port;
+
+ list_for_each_entry(port, &i2c->ports, head) {
+ if (nv_hclass(port) == type)
+ return port;
+ }
+
+ return NULL;
+}
+
+static void
+nvkm_i2c_release_pad(struct nvkm_i2c_port *port)
+{
+ struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
+ struct nvkm_i2c *i2c = nvkm_i2c(port);
+
+ if (atomic_dec_and_test(&nv_object(pad)->usecount)) {
+ nv_ofuncs(pad)->fini(nv_object(pad), false);
+ wake_up_all(&i2c->wait);
+ }
+}
+
+static int
+nvkm_i2c_try_acquire_pad(struct nvkm_i2c_port *port)
+{
+ struct nvkm_i2c_pad *pad = nvkm_i2c_pad(port);
+
+ if (atomic_add_return(1, &nv_object(pad)->usecount) != 1) {
+ struct nvkm_object *owner = (void *)pad->port;
+ do {
+ if (owner == (void *)port)
+ return 0;
+ owner = owner->parent;
+ } while(owner);
+ nvkm_i2c_release_pad(port);
+ return -EBUSY;
+ }
+
+ pad->next = port;
+ nv_ofuncs(pad)->init(nv_object(pad));
+ return 0;
+}
+
+static int
+nvkm_i2c_acquire_pad(struct nvkm_i2c_port *port, unsigned long timeout)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(port);
+
+ if (timeout) {
+ if (wait_event_timeout(i2c->wait,
+ nvkm_i2c_try_acquire_pad(port) == 0,
+ timeout) == 0)
+ return -EBUSY;
+ } else {
+ wait_event(i2c->wait, nvkm_i2c_try_acquire_pad(port) == 0);
+ }
+
+ return 0;
+}
+
+static void
+nvkm_i2c_release(struct nvkm_i2c_port *port)
+__releases(pad->mutex)
+{
+ nvkm_i2c(port)->release_pad(port);
+ mutex_unlock(&port->mutex);
+}
+
+static int
+nvkm_i2c_acquire(struct nvkm_i2c_port *port, unsigned long timeout)
+__acquires(pad->mutex)
+{
+ int ret;
+ mutex_lock(&port->mutex);
+ if ((ret = nvkm_i2c(port)->acquire_pad(port, timeout)))
+ mutex_unlock(&port->mutex);
+ return ret;
+}
+
+static int
+nvkm_i2c_identify(struct nvkm_i2c *i2c, int index, const char *what,
+ struct nvkm_i2c_board_info *info,
+ bool (*match)(struct nvkm_i2c_port *,
+ struct i2c_board_info *, void *), void *data)
+{
+ struct nvkm_i2c_port *port = nvkm_i2c_find(i2c, index);
+ int i;
+
+ if (!port) {
+ nv_debug(i2c, "no bus when probing %s on %d\n", what, index);
+ return -ENODEV;
+ }
+
+ nv_debug(i2c, "probing %ss on bus: %d\n", what, port->index);
+ for (i = 0; info[i].dev.addr; i++) {
+ u8 orig_udelay = 0;
+
+ if ((port->adapter.algo == &i2c_bit_algo) &&
+ (info[i].udelay != 0)) {
+ struct i2c_algo_bit_data *algo = port->adapter.algo_data;
+ nv_debug(i2c, "using custom udelay %d instead of %d\n",
+ info[i].udelay, algo->udelay);
+ orig_udelay = algo->udelay;
+ algo->udelay = info[i].udelay;
+ }
+
+ if (nv_probe_i2c(port, info[i].dev.addr) &&
+ (!match || match(port, &info[i].dev, data))) {
+ nv_info(i2c, "detected %s: %s\n", what,
+ info[i].dev.type);
+ return i;
+ }
+
+ if (orig_udelay) {
+ struct i2c_algo_bit_data *algo = port->adapter.algo_data;
+ algo->udelay = orig_udelay;
+ }
+ }
+
+ nv_debug(i2c, "no devices found.\n");
+ return -ENODEV;
+}
+
+static void
+nvkm_i2c_intr_fini(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
+ struct nvkm_i2c_port *port = i2c->find(i2c, index);
+ const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
+ if (port && port->aux >= 0)
+ impl->aux_mask(i2c, type, 1 << port->aux, 0);
+}
+
+static void
+nvkm_i2c_intr_init(struct nvkm_event *event, int type, int index)
+{
+ struct nvkm_i2c *i2c = container_of(event, typeof(*i2c), event);
+ struct nvkm_i2c_port *port = i2c->find(i2c, index);
+ const struct nvkm_i2c_impl *impl = (void *)nv_object(i2c)->oclass;
+ if (port && port->aux >= 0)
+ impl->aux_mask(i2c, type, 1 << port->aux, 1 << port->aux);
+}
+
+static int
+nvkm_i2c_intr_ctor(struct nvkm_object *object, void *data, u32 size,
+ struct nvkm_notify *notify)
+{
+ struct nvkm_i2c_ntfy_req *req = data;
+ if (!WARN_ON(size != sizeof(*req))) {
+ notify->size = sizeof(struct nvkm_i2c_ntfy_rep);
+ notify->types = req->mask;
+ notify->index = req->port;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void
+nvkm_i2c_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_i2c_impl *impl = (void *)nv_oclass(subdev);
+ struct nvkm_i2c *i2c = nvkm_i2c(subdev);
+ struct nvkm_i2c_port *port;
+ u32 hi, lo, rq, tx, e;
+
+ if (impl->aux_stat) {
+ impl->aux_stat(i2c, &hi, &lo, &rq, &tx);
+ if (hi || lo || rq || tx) {
+ list_for_each_entry(port, &i2c->ports, head) {
+ if (e = 0, port->aux < 0)
+ continue;
+
+ if (hi & (1 << port->aux)) e |= NVKM_I2C_PLUG;
+ if (lo & (1 << port->aux)) e |= NVKM_I2C_UNPLUG;
+ if (rq & (1 << port->aux)) e |= NVKM_I2C_IRQ;
+ if (tx & (1 << port->aux)) e |= NVKM_I2C_DONE;
+ if (e) {
+ struct nvkm_i2c_ntfy_rep rep = {
+ .mask = e,
+ };
+ nvkm_event_send(&i2c->event, rep.mask,
+ port->index, &rep,
+ sizeof(rep));
+ }
+ }
+ }
+ }
+}
+
+static const struct nvkm_event_func
+nvkm_i2c_intr_func = {
+ .ctor = nvkm_i2c_intr_ctor,
+ .init = nvkm_i2c_intr_init,
+ .fini = nvkm_i2c_intr_fini,
+};
+
+int
+_nvkm_i2c_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_i2c_impl *impl = (void *)nv_oclass(object);
+ struct nvkm_i2c *i2c = (void *)object;
+ struct nvkm_i2c_port *port;
+ u32 mask;
+ int ret;
+
+ list_for_each_entry(port, &i2c->ports, head) {
+ ret = nv_ofuncs(port)->fini(nv_object(port), suspend);
+ if (ret && suspend)
+ goto fail;
+ }
+
+ if ((mask = (1 << impl->aux) - 1), impl->aux_stat) {
+ impl->aux_mask(i2c, NVKM_I2C_ANY, mask, 0);
+ impl->aux_stat(i2c, &mask, &mask, &mask, &mask);
+ }
+
+ return nvkm_subdev_fini(&i2c->base, suspend);
+fail:
+ list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
+ nv_ofuncs(port)->init(nv_object(port));
+ }
+
+ return ret;
+}
+
+int
+_nvkm_i2c_init(struct nvkm_object *object)
+{
+ struct nvkm_i2c *i2c = (void *)object;
+ struct nvkm_i2c_port *port;
+ int ret;
+
+ ret = nvkm_subdev_init(&i2c->base);
+ if (ret == 0) {
+ list_for_each_entry(port, &i2c->ports, head) {
+ ret = nv_ofuncs(port)->init(nv_object(port));
+ if (ret)
+ goto fail;
+ }
+ }
+
+ return ret;
+fail:
+ list_for_each_entry_continue_reverse(port, &i2c->ports, head) {
+ nv_ofuncs(port)->fini(nv_object(port), false);
+ }
+
+ return ret;
+}
+
+void
+_nvkm_i2c_dtor(struct nvkm_object *object)
+{
+ struct nvkm_i2c *i2c = (void *)object;
+ struct nvkm_i2c_port *port, *temp;
+
+ nvkm_event_fini(&i2c->event);
+
+ list_for_each_entry_safe(port, temp, &i2c->ports, head) {
+ nvkm_object_ref(NULL, (struct nvkm_object **)&port);
+ }
+
+ nvkm_subdev_destroy(&i2c->base);
+}
+
+static struct nvkm_oclass *
+nvkm_i2c_extdev_sclass[] = {
+ nvkm_anx9805_sclass,
+};
+
+static void
+nvkm_i2c_create_port(struct nvkm_i2c *i2c, int index, u8 type,
+ struct dcb_i2c_entry *info)
+{
+ const struct nvkm_i2c_impl *impl = (void *)nv_oclass(i2c);
+ struct nvkm_oclass *oclass;
+ struct nvkm_object *parent;
+ struct nvkm_object *object;
+ int ret, pad;
+
+ if (info->share != DCB_I2C_UNUSED) {
+ pad = info->share;
+ oclass = impl->pad_s;
+ } else {
+ if (type != DCB_I2C_NVIO_AUX)
+ pad = 0x100 + info->drive;
+ else
+ pad = 0x100 + info->auxch;
+ oclass = impl->pad_x;
+ }
+
+ ret = nvkm_object_ctor(nv_object(i2c), NULL, oclass,
+ NULL, pad, &parent);
+ if (ret < 0)
+ return;
+
+ oclass = impl->sclass;
+ do {
+ ret = -EINVAL;
+ if (oclass->handle == type) {
+ ret = nvkm_object_ctor(parent, NULL, oclass,
+ info, index, &object);
+ }
+ } while (ret && (++oclass)->handle);
+
+ nvkm_object_ref(NULL, &parent);
+}
+
+int
+nvkm_i2c_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct nvkm_i2c *i2c;
+ struct nvkm_object *object;
+ struct dcb_i2c_entry info;
+ int ret, i, j, index = -1;
+ struct dcb_output outp;
+ u8 ver, hdr;
+ u32 data;
+
+ ret = nvkm_subdev_create(parent, engine, oclass, 0, "I2C", "i2c", &i2c);
+ *pobject = nv_object(i2c);
+ if (ret)
+ return ret;
+
+ nv_subdev(i2c)->intr = nvkm_i2c_intr;
+ i2c->find = nvkm_i2c_find;
+ i2c->find_type = nvkm_i2c_find_type;
+ i2c->acquire_pad = nvkm_i2c_acquire_pad;
+ i2c->release_pad = nvkm_i2c_release_pad;
+ i2c->acquire = nvkm_i2c_acquire;
+ i2c->release = nvkm_i2c_release;
+ i2c->identify = nvkm_i2c_identify;
+ init_waitqueue_head(&i2c->wait);
+ INIT_LIST_HEAD(&i2c->ports);
+
+ while (!dcb_i2c_parse(bios, ++index, &info)) {
+ switch (info.type) {
+ case DCB_I2C_NV04_BIT:
+ case DCB_I2C_NV4E_BIT:
+ case DCB_I2C_NVIO_BIT:
+ nvkm_i2c_create_port(i2c, NV_I2C_PORT(index),
+ info.type, &info);
+ break;
+ case DCB_I2C_NVIO_AUX:
+ nvkm_i2c_create_port(i2c, NV_I2C_AUX(index),
+ info.type, &info);
+ break;
+ case DCB_I2C_PMGR:
+ if (info.drive != DCB_I2C_UNUSED) {
+ nvkm_i2c_create_port(i2c, NV_I2C_PORT(index),
+ DCB_I2C_NVIO_BIT, &info);
+ }
+ if (info.auxch != DCB_I2C_UNUSED) {
+ nvkm_i2c_create_port(i2c, NV_I2C_AUX(index),
+ DCB_I2C_NVIO_AUX, &info);
+ }
+ break;
+ case DCB_I2C_UNUSED:
+ default:
+ continue;
+ }
+ }
+
+ /* in addition to the busses specified in the i2c table, there
+ * may be ddc/aux channels hiding behind external tmds/dp/etc
+ * transmitters.
+ */
+ index = NV_I2C_EXT(0);
+ i = -1;
+ while ((data = dcb_outp_parse(bios, ++i, &ver, &hdr, &outp))) {
+ if (!outp.location || !outp.extdev)
+ continue;
+
+ switch (outp.type) {
+ case DCB_OUTPUT_TMDS:
+ info.type = NV_I2C_TYPE_EXTDDC(outp.extdev);
+ break;
+ case DCB_OUTPUT_DP:
+ info.type = NV_I2C_TYPE_EXTAUX(outp.extdev);
+ break;
+ default:
+ continue;
+ }
+
+ ret = -ENODEV;
+ j = -1;
+ while (ret && ++j < ARRAY_SIZE(nvkm_i2c_extdev_sclass)) {
+ parent = nv_object(i2c->find(i2c, outp.i2c_index));
+ oclass = nvkm_i2c_extdev_sclass[j];
+ do {
+ if (oclass->handle != info.type)
+ continue;
+ ret = nvkm_object_ctor(parent, NULL, oclass,
+ NULL, index++, &object);
+ } while (ret && (++oclass)->handle);
+ }
+ }
+
+ ret = nvkm_event_init(&nvkm_i2c_intr_func, 4, index, &i2c->event);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+int
+_nvkm_i2c_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_i2c *i2c;
+ int ret;
+
+ ret = nvkm_i2c_create(parent, engine, oclass, &i2c);
+ *pobject = nv_object(i2c);
+ if (ret)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
new file mode 100644
index 000000000000..861a453d2a67
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/bit.c
@@ -0,0 +1,233 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#ifdef CONFIG_NOUVEAU_I2C_INTERNAL
+#define T_TIMEOUT 2200000
+#define T_RISEFALL 1000
+#define T_HOLD 5000
+
+static inline void
+i2c_drive_scl(struct nvkm_i2c_port *port, int state)
+{
+ port->func->drive_scl(port, state);
+}
+
+static inline void
+i2c_drive_sda(struct nvkm_i2c_port *port, int state)
+{
+ port->func->drive_sda(port, state);
+}
+
+static inline int
+i2c_sense_scl(struct nvkm_i2c_port *port)
+{
+ return port->func->sense_scl(port);
+}
+
+static inline int
+i2c_sense_sda(struct nvkm_i2c_port *port)
+{
+ return port->func->sense_sda(port);
+}
+
+static void
+i2c_delay(struct nvkm_i2c_port *port, u32 nsec)
+{
+ udelay((nsec + 500) / 1000);
+}
+
+static bool
+i2c_raise_scl(struct nvkm_i2c_port *port)
+{
+ u32 timeout = T_TIMEOUT / T_RISEFALL;
+
+ i2c_drive_scl(port, 1);
+ do {
+ i2c_delay(port, T_RISEFALL);
+ } while (!i2c_sense_scl(port) && --timeout);
+
+ return timeout != 0;
+}
+
+static int
+i2c_start(struct nvkm_i2c_port *port)
+{
+ int ret = 0;
+
+ if (!i2c_sense_scl(port) ||
+ !i2c_sense_sda(port)) {
+ i2c_drive_scl(port, 0);
+ i2c_drive_sda(port, 1);
+ if (!i2c_raise_scl(port))
+ ret = -EBUSY;
+ }
+
+ i2c_drive_sda(port, 0);
+ i2c_delay(port, T_HOLD);
+ i2c_drive_scl(port, 0);
+ i2c_delay(port, T_HOLD);
+ return ret;
+}
+
+static void
+i2c_stop(struct nvkm_i2c_port *port)
+{
+ i2c_drive_scl(port, 0);
+ i2c_drive_sda(port, 0);
+ i2c_delay(port, T_RISEFALL);
+
+ i2c_drive_scl(port, 1);
+ i2c_delay(port, T_HOLD);
+ i2c_drive_sda(port, 1);
+ i2c_delay(port, T_HOLD);
+}
+
+static int
+i2c_bitw(struct nvkm_i2c_port *port, int sda)
+{
+ i2c_drive_sda(port, sda);
+ i2c_delay(port, T_RISEFALL);
+
+ if (!i2c_raise_scl(port))
+ return -ETIMEDOUT;
+ i2c_delay(port, T_HOLD);
+
+ i2c_drive_scl(port, 0);
+ i2c_delay(port, T_HOLD);
+ return 0;
+}
+
+static int
+i2c_bitr(struct nvkm_i2c_port *port)
+{
+ int sda;
+
+ i2c_drive_sda(port, 1);
+ i2c_delay(port, T_RISEFALL);
+
+ if (!i2c_raise_scl(port))
+ return -ETIMEDOUT;
+ i2c_delay(port, T_HOLD);
+
+ sda = i2c_sense_sda(port);
+
+ i2c_drive_scl(port, 0);
+ i2c_delay(port, T_HOLD);
+ return sda;
+}
+
+static int
+i2c_get_byte(struct nvkm_i2c_port *port, u8 *byte, bool last)
+{
+ int i, bit;
+
+ *byte = 0;
+ for (i = 7; i >= 0; i--) {
+ bit = i2c_bitr(port);
+ if (bit < 0)
+ return bit;
+ *byte |= bit << i;
+ }
+
+ return i2c_bitw(port, last ? 1 : 0);
+}
+
+static int
+i2c_put_byte(struct nvkm_i2c_port *port, u8 byte)
+{
+ int i, ret;
+ for (i = 7; i >= 0; i--) {
+ ret = i2c_bitw(port, !!(byte & (1 << i)));
+ if (ret < 0)
+ return ret;
+ }
+
+ ret = i2c_bitr(port);
+ if (ret == 1) /* nack */
+ ret = -EIO;
+ return ret;
+}
+
+static int
+i2c_addr(struct nvkm_i2c_port *port, struct i2c_msg *msg)
+{
+ u32 addr = msg->addr << 1;
+ if (msg->flags & I2C_M_RD)
+ addr |= 1;
+ return i2c_put_byte(port, addr);
+}
+
+static int
+i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct nvkm_i2c_port *port = adap->algo_data;
+ struct i2c_msg *msg = msgs;
+ int ret = 0, mcnt = num;
+
+ ret = nvkm_i2c(port)->acquire(port, nsecs_to_jiffies(T_TIMEOUT));
+ if (ret)
+ return ret;
+
+ while (!ret && mcnt--) {
+ u8 remaining = msg->len;
+ u8 *ptr = msg->buf;
+
+ ret = i2c_start(port);
+ if (ret == 0)
+ ret = i2c_addr(port, msg);
+
+ if (msg->flags & I2C_M_RD) {
+ while (!ret && remaining--)
+ ret = i2c_get_byte(port, ptr++, !remaining);
+ } else {
+ while (!ret && remaining--)
+ ret = i2c_put_byte(port, *ptr++);
+ }
+
+ msg++;
+ }
+
+ i2c_stop(port);
+ nvkm_i2c(port)->release(port);
+ return (ret < 0) ? ret : num;
+}
+#else
+static int
+i2c_bit_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ return -ENODEV;
+}
+#endif
+
+static u32
+i2c_bit_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+const struct i2c_algorithm nvkm_i2c_bit_algo = {
+ .master_xfer = i2c_bit_xfer,
+ .functionality = i2c_bit_func
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
new file mode 100644
index 000000000000..2a2dd47b9835
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/g94.c
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+void
+g94_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
+{
+ u32 intr = nv_rd32(i2c, 0x00e06c);
+ u32 stat = nv_rd32(i2c, 0x00e068) & intr, i;
+ for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
+ if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
+ if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
+ if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
+ if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
+ }
+ nv_wr32(i2c, 0x00e06c, intr);
+}
+
+void
+g94_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
+{
+ u32 temp = nv_rd32(i2c, 0x00e068), i;
+ for (i = 0; i < 8; i++) {
+ if (mask & (1 << i)) {
+ if (!(data & (1 << i))) {
+ temp &= ~(type << (i * 4));
+ continue;
+ }
+ temp |= type << (i * 4);
+ }
+ }
+ nv_wr32(i2c, 0x00e068, temp);
+}
+
+#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
+#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
+
+static void
+auxch_fini(struct nvkm_i2c *aux, int ch)
+{
+ nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00310000, 0x00000000);
+}
+
+static int
+auxch_init(struct nvkm_i2c *aux, int ch)
+{
+ const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+ const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+ const u32 urep = unksel ? 0x01000000 : 0x02000000;
+ u32 ctrl, timeout;
+
+ /* wait up to 1ms for any previous transaction to be done... */
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+ udelay(1);
+ if (!timeout--) {
+ AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
+ return -EBUSY;
+ }
+ } while (ctrl & 0x03010000);
+
+ /* set some magic, and wait up to 1ms for it to appear */
+ nv_mask(aux, 0x00e4e4 + (ch * 0x50), 0x00300000, ureq);
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+ udelay(1);
+ if (!timeout--) {
+ AUX_ERR("magic wait 0x%08x\n", ctrl);
+ auxch_fini(aux, ch);
+ return -EBUSY;
+ }
+ } while ((ctrl & 0x03000000) != urep);
+
+ return 0;
+}
+
+int
+g94_aux(struct nvkm_i2c_port *base, bool retry,
+ u8 type, u32 addr, u8 *data, u8 size)
+{
+ struct nvkm_i2c *aux = nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ u32 ctrl, stat, timeout, retries;
+ u32 xbuf[4] = {};
+ int ch = port->addr;
+ int ret, i;
+
+ AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+
+ ret = auxch_init(aux, ch);
+ if (ret)
+ goto out;
+
+ stat = nv_rd32(aux, 0x00e4e8 + (ch * 0x50));
+ if (!(stat & 0x10000000)) {
+ AUX_DBG("sink not detected\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (!(type & 1)) {
+ memcpy(xbuf, data, size);
+ for (i = 0; i < 16; i += 4) {
+ AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
+ nv_wr32(aux, 0x00e4c0 + (ch * 0x50) + i, xbuf[i / 4]);
+ }
+ }
+
+ ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+ ctrl &= ~0x0001f0ff;
+ ctrl |= type << 12;
+ ctrl |= size - 1;
+ nv_wr32(aux, 0x00e4e0 + (ch * 0x50), addr);
+
+ /* (maybe) retry transaction a number of times on failure... */
+ for (retries = 0; !ret && retries < 32; retries++) {
+ /* reset, and delay a while if this is a retry */
+ nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x80000000 | ctrl);
+ nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00000000 | ctrl);
+ if (retries)
+ udelay(400);
+
+ /* transaction request, wait up to 1ms for it to complete */
+ nv_wr32(aux, 0x00e4e4 + (ch * 0x50), 0x00010000 | ctrl);
+
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(aux, 0x00e4e4 + (ch * 0x50));
+ udelay(1);
+ if (!timeout--) {
+ AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+ ret = -EIO;
+ goto out;
+ }
+ } while (ctrl & 0x00010000);
+ ret = 1;
+
+ /* read status, and check if transaction completed ok */
+ stat = nv_mask(aux, 0x00e4e8 + (ch * 0x50), 0, 0);
+ if ((stat & 0x000f0000) == 0x00080000 ||
+ (stat & 0x000f0000) == 0x00020000)
+ ret = retry ? 0 : 1;
+ if ((stat & 0x00000100))
+ ret = -ETIMEDOUT;
+ if ((stat & 0x00000e00))
+ ret = -EIO;
+
+ AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+ }
+
+ if (type & 1) {
+ for (i = 0; i < 16; i += 4) {
+ xbuf[i / 4] = nv_rd32(aux, 0x00e4d0 + (ch * 0x50) + i);
+ AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+ }
+ memcpy(data, xbuf, size);
+ }
+
+out:
+ auxch_fini(aux, ch);
+ return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
+}
+
+static const struct nvkm_i2c_func
+g94_i2c_func = {
+ .drive_scl = nv50_i2c_drive_scl,
+ .drive_sda = nv50_i2c_drive_sda,
+ .sense_scl = nv50_i2c_sense_scl,
+ .sense_sda = nv50_i2c_sense_sda,
+};
+
+static int
+g94_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv50_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_bit_algo, &g94_i2c_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ if (info->drive >= nv50_i2c_addr_nr)
+ return -EINVAL;
+
+ port->state = 7;
+ port->addr = nv50_i2c_addr[info->drive];
+ return 0;
+}
+
+static const struct nvkm_i2c_func
+g94_aux_func = {
+ .aux = g94_aux,
+};
+
+int
+g94_aux_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv50_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_aux_algo, &g94_aux_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ port->base.aux = info->auxch;
+ port->addr = info->auxch;
+ return 0;
+}
+
+static struct nvkm_oclass
+g94_i2c_sclass[] = {
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g94_i2c_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = nv50_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g94_aux_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ {}
+};
+
+struct nvkm_oclass *
+g94_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0x94),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = g94_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+ .pad_s = &g94_i2c_pad_oclass,
+ .aux = 4,
+ .aux_stat = g94_aux_stat,
+ .aux_mask = g94_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
new file mode 100644
index 000000000000..4d4ac6638140
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf110.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+static int
+gf110_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ return !!(nv_rd32(priv, port->addr) & 0x00000010);
+}
+
+static int
+gf110_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ return !!(nv_rd32(priv, port->addr) & 0x00000020);
+}
+
+static const struct nvkm_i2c_func
+gf110_i2c_func = {
+ .drive_scl = nv50_i2c_drive_scl,
+ .drive_sda = nv50_i2c_drive_sda,
+ .sense_scl = gf110_i2c_sense_scl,
+ .sense_sda = gf110_i2c_sense_sda,
+};
+
+int
+gf110_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv50_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_bit_algo, &gf110_i2c_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ port->state = 0x00000007;
+ port->addr = 0x00d014 + (info->drive * 0x20);
+ return 0;
+}
+
+struct nvkm_oclass
+gf110_i2c_sclass[] = {
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf110_i2c_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = nv50_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g94_aux_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ {}
+};
+
+struct nvkm_oclass *
+gf110_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0xd0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = gf110_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+ .pad_s = &g94_i2c_pad_oclass,
+ .aux = 4,
+ .aux_stat = g94_aux_stat,
+ .aux_mask = g94_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
new file mode 100644
index 000000000000..e290b40f2d13
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gf117.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+struct nvkm_oclass *
+gf117_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0xd7),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = gf110_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+ .pad_s = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
new file mode 100644
index 000000000000..1a464903a992
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gk104.c
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+void
+gk104_aux_stat(struct nvkm_i2c *i2c, u32 *hi, u32 *lo, u32 *rq, u32 *tx)
+{
+ u32 intr = nv_rd32(i2c, 0x00dc60);
+ u32 stat = nv_rd32(i2c, 0x00dc68) & intr, i;
+ for (i = 0, *hi = *lo = *rq = *tx = 0; i < 8; i++) {
+ if ((stat & (1 << (i * 4)))) *hi |= 1 << i;
+ if ((stat & (2 << (i * 4)))) *lo |= 1 << i;
+ if ((stat & (4 << (i * 4)))) *rq |= 1 << i;
+ if ((stat & (8 << (i * 4)))) *tx |= 1 << i;
+ }
+ nv_wr32(i2c, 0x00dc60, intr);
+}
+
+void
+gk104_aux_mask(struct nvkm_i2c *i2c, u32 type, u32 mask, u32 data)
+{
+ u32 temp = nv_rd32(i2c, 0x00dc68), i;
+ for (i = 0; i < 8; i++) {
+ if (mask & (1 << i)) {
+ if (!(data & (1 << i))) {
+ temp &= ~(type << (i * 4));
+ continue;
+ }
+ temp |= type << (i * 4);
+ }
+ }
+ nv_wr32(i2c, 0x00dc68, temp);
+}
+
+struct nvkm_oclass *
+gk104_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0xe0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = gf110_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+ .pad_s = &g94_i2c_pad_oclass,
+ .aux = 4,
+ .aux_stat = gk104_aux_stat,
+ .aux_mask = gk104_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
new file mode 100644
index 000000000000..ab64237b3842
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/gm204.c
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+#define AUX_DBG(fmt, args...) nv_debug(aux, "AUXCH(%d): " fmt, ch, ##args)
+#define AUX_ERR(fmt, args...) nv_error(aux, "AUXCH(%d): " fmt, ch, ##args)
+
+static void
+auxch_fini(struct nvkm_i2c *aux, int ch)
+{
+ nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00310000, 0x00000000);
+}
+
+static int
+auxch_init(struct nvkm_i2c *aux, int ch)
+{
+ const u32 unksel = 1; /* nfi which to use, or if it matters.. */
+ const u32 ureq = unksel ? 0x00100000 : 0x00200000;
+ const u32 urep = unksel ? 0x01000000 : 0x02000000;
+ u32 ctrl, timeout;
+
+ /* wait up to 1ms for any previous transaction to be done... */
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+ udelay(1);
+ if (!timeout--) {
+ AUX_ERR("begin idle timeout 0x%08x\n", ctrl);
+ return -EBUSY;
+ }
+ } while (ctrl & 0x03010000);
+
+ /* set some magic, and wait up to 1ms for it to appear */
+ nv_mask(aux, 0x00d954 + (ch * 0x50), 0x00300000, ureq);
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+ udelay(1);
+ if (!timeout--) {
+ AUX_ERR("magic wait 0x%08x\n", ctrl);
+ auxch_fini(aux, ch);
+ return -EBUSY;
+ }
+ } while ((ctrl & 0x03000000) != urep);
+
+ return 0;
+}
+
+int
+gm204_aux(struct nvkm_i2c_port *base, bool retry,
+ u8 type, u32 addr, u8 *data, u8 size)
+{
+ struct nvkm_i2c *aux = nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ u32 ctrl, stat, timeout, retries;
+ u32 xbuf[4] = {};
+ int ch = port->addr;
+ int ret, i;
+
+ AUX_DBG("%d: 0x%08x %d\n", type, addr, size);
+
+ ret = auxch_init(aux, ch);
+ if (ret)
+ goto out;
+
+ stat = nv_rd32(aux, 0x00d958 + (ch * 0x50));
+ if (!(stat & 0x10000000)) {
+ AUX_DBG("sink not detected\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ if (!(type & 1)) {
+ memcpy(xbuf, data, size);
+ for (i = 0; i < 16; i += 4) {
+ AUX_DBG("wr 0x%08x\n", xbuf[i / 4]);
+ nv_wr32(aux, 0x00d930 + (ch * 0x50) + i, xbuf[i / 4]);
+ }
+ }
+
+ ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+ ctrl &= ~0x0001f0ff;
+ ctrl |= type << 12;
+ ctrl |= size - 1;
+ nv_wr32(aux, 0x00d950 + (ch * 0x50), addr);
+
+ /* (maybe) retry transaction a number of times on failure... */
+ for (retries = 0; !ret && retries < 32; retries++) {
+ /* reset, and delay a while if this is a retry */
+ nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x80000000 | ctrl);
+ nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00000000 | ctrl);
+ if (retries)
+ udelay(400);
+
+ /* transaction request, wait up to 1ms for it to complete */
+ nv_wr32(aux, 0x00d954 + (ch * 0x50), 0x00010000 | ctrl);
+
+ timeout = 1000;
+ do {
+ ctrl = nv_rd32(aux, 0x00d954 + (ch * 0x50));
+ udelay(1);
+ if (!timeout--) {
+ AUX_ERR("tx req timeout 0x%08x\n", ctrl);
+ ret = -EIO;
+ goto out;
+ }
+ } while (ctrl & 0x00010000);
+ ret = 1;
+
+ /* read status, and check if transaction completed ok */
+ stat = nv_mask(aux, 0x00d958 + (ch * 0x50), 0, 0);
+ if ((stat & 0x000f0000) == 0x00080000 ||
+ (stat & 0x000f0000) == 0x00020000)
+ ret = retry ? 0 : 1;
+ if ((stat & 0x00000100))
+ ret = -ETIMEDOUT;
+ if ((stat & 0x00000e00))
+ ret = -EIO;
+
+ AUX_DBG("%02d 0x%08x 0x%08x\n", retries, ctrl, stat);
+ }
+
+ if (type & 1) {
+ for (i = 0; i < 16; i += 4) {
+ xbuf[i / 4] = nv_rd32(aux, 0x00d940 + (ch * 0x50) + i);
+ AUX_DBG("rd 0x%08x\n", xbuf[i / 4]);
+ }
+ memcpy(data, xbuf, size);
+ }
+
+out:
+ auxch_fini(aux, ch);
+ return ret < 0 ? ret : (stat & 0x000f0000) >> 16;
+}
+
+static const struct nvkm_i2c_func
+gm204_aux_func = {
+ .aux = gm204_aux,
+};
+
+int
+gm204_aux_port_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv50_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_aux_algo, &gm204_aux_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ port->base.aux = info->auxch;
+ port->addr = info->auxch;
+ return 0;
+}
+
+struct nvkm_oclass
+gm204_i2c_sclass[] = {
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf110_i2c_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = nv50_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm204_aux_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ {}
+};
+
+struct nvkm_oclass *
+gm204_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0x24),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = gm204_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+ .pad_s = &gm204_i2c_pad_oclass,
+ .aux = 8,
+ .aux_stat = gk104_aux_stat,
+ .aux_mask = gk104_aux_mask,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
new file mode 100644
index 000000000000..4cdf1c489353
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv04.c
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/vga.h>
+
+struct nv04_i2c_priv {
+ struct nvkm_i2c base;
+};
+
+struct nv04_i2c_port {
+ struct nvkm_i2c_port base;
+ u8 drive;
+ u8 sense;
+};
+
+static void
+nv04_i2c_drive_scl(struct nvkm_i2c_port *base, int state)
+{
+ struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv04_i2c_port *port = (void *)base;
+ u8 val = nv_rdvgac(priv, 0, port->drive);
+ if (state) val |= 0x20;
+ else val &= 0xdf;
+ nv_wrvgac(priv, 0, port->drive, val | 0x01);
+}
+
+static void
+nv04_i2c_drive_sda(struct nvkm_i2c_port *base, int state)
+{
+ struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv04_i2c_port *port = (void *)base;
+ u8 val = nv_rdvgac(priv, 0, port->drive);
+ if (state) val |= 0x10;
+ else val &= 0xef;
+ nv_wrvgac(priv, 0, port->drive, val | 0x01);
+}
+
+static int
+nv04_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+ struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv04_i2c_port *port = (void *)base;
+ return !!(nv_rdvgac(priv, 0, port->sense) & 0x04);
+}
+
+static int
+nv04_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+ struct nv04_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv04_i2c_port *port = (void *)base;
+ return !!(nv_rdvgac(priv, 0, port->sense) & 0x08);
+}
+
+static const struct nvkm_i2c_func
+nv04_i2c_func = {
+ .drive_scl = nv04_i2c_drive_scl,
+ .drive_sda = nv04_i2c_drive_sda,
+ .sense_scl = nv04_i2c_sense_scl,
+ .sense_sda = nv04_i2c_sense_sda,
+};
+
+static int
+nv04_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv04_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_bit_algo, &nv04_i2c_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ port->drive = info->drive;
+ port->sense = info->sense;
+ return 0;
+}
+
+static struct nvkm_oclass
+nv04_i2c_sclass[] = {
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV04_BIT),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_i2c_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ {}
+};
+
+struct nvkm_oclass *
+nv04_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = nv04_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
new file mode 100644
index 000000000000..046fe5e2ea19
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv4e.c
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/vga.h>
+
+struct nv4e_i2c_priv {
+ struct nvkm_i2c base;
+};
+
+struct nv4e_i2c_port {
+ struct nvkm_i2c_port base;
+ u32 addr;
+};
+
+static void
+nv4e_i2c_drive_scl(struct nvkm_i2c_port *base, int state)
+{
+ struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv4e_i2c_port *port = (void *)base;
+ nv_mask(priv, port->addr, 0x2f, state ? 0x21 : 0x01);
+}
+
+static void
+nv4e_i2c_drive_sda(struct nvkm_i2c_port *base, int state)
+{
+ struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv4e_i2c_port *port = (void *)base;
+ nv_mask(priv, port->addr, 0x1f, state ? 0x11 : 0x01);
+}
+
+static int
+nv4e_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+ struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv4e_i2c_port *port = (void *)base;
+ return !!(nv_rd32(priv, port->addr) & 0x00040000);
+}
+
+static int
+nv4e_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+ struct nv4e_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv4e_i2c_port *port = (void *)base;
+ return !!(nv_rd32(priv, port->addr) & 0x00080000);
+}
+
+static const struct nvkm_i2c_func
+nv4e_i2c_func = {
+ .drive_scl = nv4e_i2c_drive_scl,
+ .drive_sda = nv4e_i2c_drive_sda,
+ .sense_scl = nv4e_i2c_sense_scl,
+ .sense_sda = nv4e_i2c_sense_sda,
+};
+
+static int
+nv4e_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv4e_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_bit_algo, &nv4e_i2c_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ port->addr = 0x600800 + info->drive;
+ return 0;
+}
+
+static struct nvkm_oclass
+nv4e_i2c_sclass[] = {
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NV4E_BIT),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv4e_i2c_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = _nvkm_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ {}
+};
+
+struct nvkm_oclass *
+nv4e_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0x4e),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = nv4e_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
new file mode 100644
index 000000000000..fba5b26a5682
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.c
@@ -0,0 +1,133 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv50.h"
+
+void
+nv50_i2c_drive_scl(struct nvkm_i2c_port *base, int state)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ if (state) port->state |= 0x01;
+ else port->state &= 0xfe;
+ nv_wr32(priv, port->addr, port->state);
+}
+
+void
+nv50_i2c_drive_sda(struct nvkm_i2c_port *base, int state)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ if (state) port->state |= 0x02;
+ else port->state &= 0xfd;
+ nv_wr32(priv, port->addr, port->state);
+}
+
+int
+nv50_i2c_sense_scl(struct nvkm_i2c_port *base)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ return !!(nv_rd32(priv, port->addr) & 0x00000001);
+}
+
+int
+nv50_i2c_sense_sda(struct nvkm_i2c_port *base)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(base);
+ struct nv50_i2c_port *port = (void *)base;
+ return !!(nv_rd32(priv, port->addr) & 0x00000002);
+}
+
+static const struct nvkm_i2c_func
+nv50_i2c_func = {
+ .drive_scl = nv50_i2c_drive_scl,
+ .drive_sda = nv50_i2c_drive_sda,
+ .sense_scl = nv50_i2c_sense_scl,
+ .sense_sda = nv50_i2c_sense_sda,
+};
+
+const u32 nv50_i2c_addr[] = {
+ 0x00e138, 0x00e150, 0x00e168, 0x00e180,
+ 0x00e254, 0x00e274, 0x00e764, 0x00e780,
+ 0x00e79c, 0x00e7b8
+};
+const int nv50_i2c_addr_nr = ARRAY_SIZE(nv50_i2c_addr);
+
+static int
+nv50_i2c_port_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct dcb_i2c_entry *info = data;
+ struct nv50_i2c_port *port;
+ int ret;
+
+ ret = nvkm_i2c_port_create(parent, engine, oclass, index,
+ &nvkm_i2c_bit_algo, &nv50_i2c_func, &port);
+ *pobject = nv_object(port);
+ if (ret)
+ return ret;
+
+ if (info->drive >= nv50_i2c_addr_nr)
+ return -EINVAL;
+
+ port->state = 0x00000007;
+ port->addr = nv50_i2c_addr[info->drive];
+ return 0;
+}
+
+int
+nv50_i2c_port_init(struct nvkm_object *object)
+{
+ struct nv50_i2c_priv *priv = (void *)nvkm_i2c(object);
+ struct nv50_i2c_port *port = (void *)object;
+ nv_wr32(priv, port->addr, port->state);
+ return nvkm_i2c_port_init(&port->base);
+}
+
+static struct nvkm_oclass
+nv50_i2c_sclass[] = {
+ { .handle = NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_i2c_port_ctor,
+ .dtor = _nvkm_i2c_port_dtor,
+ .init = nv50_i2c_port_init,
+ .fini = _nvkm_i2c_port_fini,
+ },
+ },
+ {}
+};
+
+struct nvkm_oclass *
+nv50_i2c_oclass = &(struct nvkm_i2c_impl) {
+ .base.handle = NV_SUBDEV(I2C, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_ctor,
+ .dtor = _nvkm_i2c_dtor,
+ .init = _nvkm_i2c_init,
+ .fini = _nvkm_i2c_fini,
+ },
+ .sclass = nv50_i2c_sclass,
+ .pad_x = &nv04_i2c_pad_oclass,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
new file mode 100644
index 000000000000..b3139e721b02
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/nv50.h
@@ -0,0 +1,32 @@
+#ifndef __NV50_I2C_H__
+#define __NV50_I2C_H__
+#include "priv.h"
+
+struct nv50_i2c_priv {
+ struct nvkm_i2c base;
+};
+
+struct nv50_i2c_port {
+ struct nvkm_i2c_port base;
+ u32 addr;
+ u32 state;
+};
+
+extern const u32 nv50_i2c_addr[];
+extern const int nv50_i2c_addr_nr;
+int nv50_i2c_port_init(struct nvkm_object *);
+int nv50_i2c_sense_scl(struct nvkm_i2c_port *);
+int nv50_i2c_sense_sda(struct nvkm_i2c_port *);
+void nv50_i2c_drive_scl(struct nvkm_i2c_port *, int state);
+void nv50_i2c_drive_sda(struct nvkm_i2c_port *, int state);
+
+int g94_aux_port_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void g94_i2c_acquire(struct nvkm_i2c_port *);
+void g94_i2c_release(struct nvkm_i2c_port *);
+
+int gf110_i2c_port_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
new file mode 100644
index 000000000000..a242eeb67829
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+int
+_nvkm_i2c_pad_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_i2c_pad *pad = (void *)object;
+ DBG("-> NULL\n");
+ pad->port = NULL;
+ return nvkm_object_fini(&pad->base, suspend);
+}
+
+int
+_nvkm_i2c_pad_init(struct nvkm_object *object)
+{
+ struct nvkm_i2c_pad *pad = (void *)object;
+ DBG("-> PORT:%02x\n", pad->next->index);
+ pad->port = pad->next;
+ return nvkm_object_init(&pad->base);
+}
+
+int
+nvkm_i2c_pad_create_(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int index,
+ int size, void **pobject)
+{
+ struct nvkm_i2c *i2c = nvkm_i2c(parent);
+ struct nvkm_i2c_port *port;
+ struct nvkm_i2c_pad *pad;
+ int ret;
+
+ list_for_each_entry(port, &i2c->ports, head) {
+ pad = nvkm_i2c_pad(port);
+ if (pad->index == index) {
+ atomic_inc(&nv_object(pad)->refcount);
+ *pobject = pad;
+ return 1;
+ }
+ }
+
+ ret = nvkm_object_create_(parent, engine, oclass, 0, size, pobject);
+ pad = *pobject;
+ if (ret)
+ return ret;
+
+ pad->index = index;
+ return 0;
+}
+
+int
+_nvkm_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_i2c_pad *pad;
+ int ret;
+ ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+ *pobject = nv_object(pad);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
new file mode 100644
index 000000000000..f3422cc6f8db
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/pad.h
@@ -0,0 +1,56 @@
+#ifndef __NVKM_I2C_PAD_H__
+#define __NVKM_I2C_PAD_H__
+#include "priv.h"
+
+struct nvkm_i2c_pad {
+ struct nvkm_object base;
+ int index;
+ struct nvkm_i2c_port *port;
+ struct nvkm_i2c_port *next;
+};
+
+static inline struct nvkm_i2c_pad *
+nvkm_i2c_pad(struct nvkm_i2c_port *port)
+{
+ struct nvkm_object *pad = nv_object(port);
+ while (!nv_iclass(pad->parent, NV_SUBDEV_CLASS))
+ pad = pad->parent;
+ return (void *)pad;
+}
+
+#define nvkm_i2c_pad_create(p,e,o,i,d) \
+ nvkm_i2c_pad_create_((p), (e), (o), (i), sizeof(**d), (void **)d)
+#define nvkm_i2c_pad_destroy(p) ({ \
+ struct nvkm_i2c_pad *_p = (p); \
+ _nvkm_i2c_pad_dtor(nv_object(_p)); \
+})
+#define nvkm_i2c_pad_init(p) ({ \
+ struct nvkm_i2c_pad *_p = (p); \
+ _nvkm_i2c_pad_init(nv_object(_p)); \
+})
+#define nvkm_i2c_pad_fini(p,s) ({ \
+ struct nvkm_i2c_pad *_p = (p); \
+ _nvkm_i2c_pad_fini(nv_object(_p), (s)); \
+})
+
+int nvkm_i2c_pad_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int index, int, void **);
+
+int _nvkm_i2c_pad_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+#define _nvkm_i2c_pad_dtor nvkm_object_destroy
+int _nvkm_i2c_pad_init(struct nvkm_object *);
+int _nvkm_i2c_pad_fini(struct nvkm_object *, bool);
+
+#ifndef MSG
+#define MSG(l,f,a...) do { \
+ struct nvkm_i2c_pad *_pad = (void *)pad; \
+ nv_##l(_pad, "PAD:%c:%02x: "f, \
+ _pad->index >= 0x100 ? 'X' : 'S', \
+ _pad->index >= 0x100 ? _pad->index - 0x100 : _pad->index, ##a); \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
new file mode 100644
index 000000000000..e9832f7a7e38
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padg94.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+struct g94_i2c_pad {
+ struct nvkm_i2c_pad base;
+ int addr;
+};
+
+static int
+g94_i2c_pad_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+ struct g94_i2c_pad *pad = (void *)object;
+ nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000001);
+ return nvkm_i2c_pad_fini(&pad->base, suspend);
+}
+
+static int
+g94_i2c_pad_init(struct nvkm_object *object)
+{
+ struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+ struct g94_i2c_pad *pad = (void *)object;
+
+ switch (nv_oclass(pad->base.next)->handle) {
+ case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
+ nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x00000002);
+ break;
+ case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
+ default:
+ nv_mask(i2c, 0x00e500 + pad->addr, 0x0000c003, 0x0000c001);
+ break;
+ }
+
+ nv_mask(i2c, 0x00e50c + pad->addr, 0x00000001, 0x00000000);
+ return nvkm_i2c_pad_init(&pad->base);
+}
+
+static int
+g94_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct g94_i2c_pad *pad;
+ int ret;
+
+ ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+ *pobject = nv_object(pad);
+ if (ret)
+ return ret;
+
+ pad->addr = index * 0x50;;
+ return 0;
+}
+
+struct nvkm_oclass
+g94_i2c_pad_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g94_i2c_pad_ctor,
+ .dtor = _nvkm_i2c_pad_dtor,
+ .init = g94_i2c_pad_init,
+ .fini = g94_i2c_pad_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
new file mode 100644
index 000000000000..be590405444d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padgm204.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+struct gm204_i2c_pad {
+ struct nvkm_i2c_pad base;
+ int addr;
+};
+
+static int
+gm204_i2c_pad_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+ struct gm204_i2c_pad *pad = (void *)object;
+ nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000001);
+ return nvkm_i2c_pad_fini(&pad->base, suspend);
+}
+
+static int
+gm204_i2c_pad_init(struct nvkm_object *object)
+{
+ struct nvkm_i2c *i2c = (void *)nvkm_i2c(object);
+ struct gm204_i2c_pad *pad = (void *)object;
+
+ switch (nv_oclass(pad->base.next)->handle) {
+ case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_AUX):
+ nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x00000002);
+ break;
+ case NV_I2C_TYPE_DCBI2C(DCB_I2C_NVIO_BIT):
+ default:
+ nv_mask(i2c, 0x00d970 + pad->addr, 0x0000c003, 0x0000c001);
+ break;
+ }
+
+ nv_mask(i2c, 0x00d97c + pad->addr, 0x00000001, 0x00000000);
+ return nvkm_i2c_pad_init(&pad->base);
+}
+
+static int
+gm204_i2c_pad_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 index,
+ struct nvkm_object **pobject)
+{
+ struct gm204_i2c_pad *pad;
+ int ret;
+
+ ret = nvkm_i2c_pad_create(parent, engine, oclass, index, &pad);
+ *pobject = nv_object(pad);
+ if (ret)
+ return ret;
+
+ pad->addr = index * 0x50;;
+ return 0;
+}
+
+struct nvkm_oclass
+gm204_i2c_pad_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm204_i2c_pad_ctor,
+ .dtor = _nvkm_i2c_pad_dtor,
+ .init = gm204_i2c_pad_init,
+ .fini = gm204_i2c_pad_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
new file mode 100644
index 000000000000..22c7daaad3a0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/padnv04.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "pad.h"
+
+struct nvkm_oclass
+nv04_i2c_pad_oclass = {
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_i2c_pad_ctor,
+ .dtor = _nvkm_i2c_pad_dtor,
+ .init = _nvkm_i2c_pad_init,
+ .fini = _nvkm_i2c_pad_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
new file mode 100644
index 000000000000..586f53dad813
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/port.h
@@ -0,0 +1,13 @@
+#ifndef __NVKM_I2C_PORT_H__
+#define __NVKM_I2C_PORT_H__
+#include "priv.h"
+
+#ifndef MSG
+#define MSG(l,f,a...) do { \
+ struct nvkm_i2c_port *_port = (void *)port; \
+ nv_##l(_port, "PORT:%02x: "f, _port->index, ##a); \
+} while(0)
+#define DBG(f,a...) MSG(debug, f, ##a)
+#define ERR(f,a...) MSG(error, f, ##a)
+#endif
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
new file mode 100644
index 000000000000..6586e1567fcf
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/i2c/priv.h
@@ -0,0 +1,87 @@
+#ifndef __NVKM_I2C_PRIV_H__
+#define __NVKM_I2C_PRIV_H__
+#include <subdev/i2c.h>
+
+extern struct nvkm_oclass nv04_i2c_pad_oclass;
+extern struct nvkm_oclass g94_i2c_pad_oclass;
+extern struct nvkm_oclass gm204_i2c_pad_oclass;
+
+#define nvkm_i2c_port_create(p,e,o,i,a,f,d) \
+ nvkm_i2c_port_create_((p), (e), (o), (i), (a), (f), \
+ sizeof(**d), (void **)d)
+#define nvkm_i2c_port_destroy(p) ({ \
+ struct nvkm_i2c_port *port = (p); \
+ _nvkm_i2c_port_dtor(nv_object(i2c)); \
+})
+#define nvkm_i2c_port_init(p) \
+ nvkm_object_init(&(p)->base)
+#define nvkm_i2c_port_fini(p,s) \
+ nvkm_object_fini(&(p)->base, (s))
+
+int nvkm_i2c_port_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, u8,
+ const struct i2c_algorithm *,
+ const struct nvkm_i2c_func *,
+ int, void **);
+void _nvkm_i2c_port_dtor(struct nvkm_object *);
+#define _nvkm_i2c_port_init nvkm_object_init
+int _nvkm_i2c_port_fini(struct nvkm_object *, bool);
+
+#define nvkm_i2c_create(p,e,o,d) \
+ nvkm_i2c_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_i2c_destroy(p) ({ \
+ struct nvkm_i2c *i2c = (p); \
+ _nvkm_i2c_dtor(nv_object(i2c)); \
+})
+#define nvkm_i2c_init(p) ({ \
+ struct nvkm_i2c *i2c = (p); \
+ _nvkm_i2c_init(nv_object(i2c)); \
+})
+#define nvkm_i2c_fini(p,s) ({ \
+ struct nvkm_i2c *i2c = (p); \
+ _nvkm_i2c_fini(nv_object(i2c), (s)); \
+})
+
+int nvkm_i2c_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+int _nvkm_i2c_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void _nvkm_i2c_dtor(struct nvkm_object *);
+int _nvkm_i2c_init(struct nvkm_object *);
+int _nvkm_i2c_fini(struct nvkm_object *, bool);
+
+extern struct nvkm_oclass nvkm_anx9805_sclass[];
+extern struct nvkm_oclass gf110_i2c_sclass[];
+
+extern const struct i2c_algorithm nvkm_i2c_bit_algo;
+extern const struct i2c_algorithm nvkm_i2c_aux_algo;
+
+struct nvkm_i2c_impl {
+ struct nvkm_oclass base;
+
+ /* supported i2c port classes */
+ struct nvkm_oclass *sclass;
+ struct nvkm_oclass *pad_x;
+ struct nvkm_oclass *pad_s;
+
+ /* number of native dp aux channels present */
+ int aux;
+
+ /* read and ack pending interrupts, returning only data
+ * for ports that have not been masked off, while still
+ * performing the ack for anything that was pending.
+ */
+ void (*aux_stat)(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
+
+ /* mask on/off interrupt types for a given set of auxch
+ */
+ void (*aux_mask)(struct nvkm_i2c *, u32, u32, u32);
+};
+
+void g94_aux_stat(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
+void g94_aux_mask(struct nvkm_i2c *, u32, u32, u32);
+
+void gk104_aux_stat(struct nvkm_i2c *, u32 *, u32 *, u32 *, u32 *);
+void gk104_aux_mask(struct nvkm_i2c *, u32, u32, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
new file mode 100644
index 000000000000..a0b12d27284a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/subdev/ibus/gf100.o
+nvkm-y += nvkm/subdev/ibus/gk104.o
+nvkm-y += nvkm/subdev/ibus/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c
new file mode 100644
index 000000000000..8e578f802f66
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gf100.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/ibus.h>
+
+struct gf100_ibus_priv {
+ struct nvkm_ibus base;
+};
+
+static void
+gf100_ibus_intr_hub(struct gf100_ibus_priv *priv, int i)
+{
+ u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0400));
+ u32 data = nv_rd32(priv, 0x122124 + (i * 0x0400));
+ u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0400));
+ nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+ nv_mask(priv, 0x122128 + (i * 0x0400), 0x00000200, 0x00000000);
+}
+
+static void
+gf100_ibus_intr_rop(struct gf100_ibus_priv *priv, int i)
+{
+ u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0400));
+ u32 data = nv_rd32(priv, 0x124124 + (i * 0x0400));
+ u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0400));
+ nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+ nv_mask(priv, 0x124128 + (i * 0x0400), 0x00000200, 0x00000000);
+}
+
+static void
+gf100_ibus_intr_gpc(struct gf100_ibus_priv *priv, int i)
+{
+ u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0400));
+ u32 data = nv_rd32(priv, 0x128124 + (i * 0x0400));
+ u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0400));
+ nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+ nv_mask(priv, 0x128128 + (i * 0x0400), 0x00000200, 0x00000000);
+}
+
+static void
+gf100_ibus_intr(struct nvkm_subdev *subdev)
+{
+ struct gf100_ibus_priv *priv = (void *)subdev;
+ u32 intr0 = nv_rd32(priv, 0x121c58);
+ u32 intr1 = nv_rd32(priv, 0x121c5c);
+ u32 hubnr = nv_rd32(priv, 0x121c70);
+ u32 ropnr = nv_rd32(priv, 0x121c74);
+ u32 gpcnr = nv_rd32(priv, 0x121c78);
+ u32 i;
+
+ for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
+ u32 stat = 0x00000100 << i;
+ if (intr0 & stat) {
+ gf100_ibus_intr_hub(priv, i);
+ intr0 &= ~stat;
+ }
+ }
+
+ for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
+ u32 stat = 0x00010000 << i;
+ if (intr0 & stat) {
+ gf100_ibus_intr_rop(priv, i);
+ intr0 &= ~stat;
+ }
+ }
+
+ for (i = 0; intr1 && i < gpcnr; i++) {
+ u32 stat = 0x00000001 << i;
+ if (intr1 & stat) {
+ gf100_ibus_intr_gpc(priv, i);
+ intr1 &= ~stat;
+ }
+ }
+}
+
+static int
+gf100_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_ibus_priv *priv;
+ int ret;
+
+ ret = nvkm_ibus_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->intr = gf100_ibus_intr;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_ibus_oclass = {
+ .handle = NV_SUBDEV(IBUS, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_ibus_ctor,
+ .dtor = _nvkm_ibus_dtor,
+ .init = _nvkm_ibus_init,
+ .fini = _nvkm_ibus_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
new file mode 100644
index 000000000000..7b6e9a6cd7b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk104.c
@@ -0,0 +1,139 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/ibus.h>
+
+struct gk104_ibus_priv {
+ struct nvkm_ibus base;
+};
+
+static void
+gk104_ibus_intr_hub(struct gk104_ibus_priv *priv, int i)
+{
+ u32 addr = nv_rd32(priv, 0x122120 + (i * 0x0800));
+ u32 data = nv_rd32(priv, 0x122124 + (i * 0x0800));
+ u32 stat = nv_rd32(priv, 0x122128 + (i * 0x0800));
+ nv_error(priv, "HUB%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+ nv_mask(priv, 0x122128 + (i * 0x0800), 0x00000200, 0x00000000);
+}
+
+static void
+gk104_ibus_intr_rop(struct gk104_ibus_priv *priv, int i)
+{
+ u32 addr = nv_rd32(priv, 0x124120 + (i * 0x0800));
+ u32 data = nv_rd32(priv, 0x124124 + (i * 0x0800));
+ u32 stat = nv_rd32(priv, 0x124128 + (i * 0x0800));
+ nv_error(priv, "ROP%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+ nv_mask(priv, 0x124128 + (i * 0x0800), 0x00000200, 0x00000000);
+}
+
+static void
+gk104_ibus_intr_gpc(struct gk104_ibus_priv *priv, int i)
+{
+ u32 addr = nv_rd32(priv, 0x128120 + (i * 0x0800));
+ u32 data = nv_rd32(priv, 0x128124 + (i * 0x0800));
+ u32 stat = nv_rd32(priv, 0x128128 + (i * 0x0800));
+ nv_error(priv, "GPC%d: 0x%06x 0x%08x (0x%08x)\n", i, addr, data, stat);
+ nv_mask(priv, 0x128128 + (i * 0x0800), 0x00000200, 0x00000000);
+}
+
+static void
+gk104_ibus_intr(struct nvkm_subdev *subdev)
+{
+ struct gk104_ibus_priv *priv = (void *)subdev;
+ u32 intr0 = nv_rd32(priv, 0x120058);
+ u32 intr1 = nv_rd32(priv, 0x12005c);
+ u32 hubnr = nv_rd32(priv, 0x120070);
+ u32 ropnr = nv_rd32(priv, 0x120074);
+ u32 gpcnr = nv_rd32(priv, 0x120078);
+ u32 i;
+
+ for (i = 0; (intr0 & 0x0000ff00) && i < hubnr; i++) {
+ u32 stat = 0x00000100 << i;
+ if (intr0 & stat) {
+ gk104_ibus_intr_hub(priv, i);
+ intr0 &= ~stat;
+ }
+ }
+
+ for (i = 0; (intr0 & 0xffff0000) && i < ropnr; i++) {
+ u32 stat = 0x00010000 << i;
+ if (intr0 & stat) {
+ gk104_ibus_intr_rop(priv, i);
+ intr0 &= ~stat;
+ }
+ }
+
+ for (i = 0; intr1 && i < gpcnr; i++) {
+ u32 stat = 0x00000001 << i;
+ if (intr1 & stat) {
+ gk104_ibus_intr_gpc(priv, i);
+ intr1 &= ~stat;
+ }
+ }
+}
+
+static int
+gk104_ibus_init(struct nvkm_object *object)
+{
+ struct gk104_ibus_priv *priv = (void *)object;
+ int ret = nvkm_ibus_init(&priv->base);
+ if (ret == 0) {
+ nv_mask(priv, 0x122318, 0x0003ffff, 0x00001000);
+ nv_mask(priv, 0x12231c, 0x0003ffff, 0x00000200);
+ nv_mask(priv, 0x122310, 0x0003ffff, 0x00000800);
+ nv_mask(priv, 0x122348, 0x0003ffff, 0x00000100);
+ nv_mask(priv, 0x1223b0, 0x0003ffff, 0x00000fff);
+ nv_mask(priv, 0x122348, 0x0003ffff, 0x00000200);
+ nv_mask(priv, 0x122358, 0x0003ffff, 0x00002880);
+ }
+ return ret;
+}
+
+static int
+gk104_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk104_ibus_priv *priv;
+ int ret;
+
+ ret = nvkm_ibus_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->intr = gk104_ibus_intr;
+ return 0;
+}
+
+struct nvkm_oclass
+gk104_ibus_oclass = {
+ .handle = NV_SUBDEV(IBUS, 0xe0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk104_ibus_ctor,
+ .dtor = _nvkm_ibus_dtor,
+ .init = gk104_ibus_init,
+ .fini = _nvkm_ibus_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
new file mode 100644
index 000000000000..c0fdb89e74ac
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ibus/gk20a.c
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 <subdev/ibus.h>
+#include <subdev/timer.h>
+
+struct gk20a_ibus_priv {
+ struct nvkm_ibus base;
+};
+
+static void
+gk20a_ibus_init_priv_ring(struct gk20a_ibus_priv *priv)
+{
+ nv_mask(priv, 0x137250, 0x3f, 0);
+
+ nv_mask(priv, 0x000200, 0x20, 0);
+ usleep_range(20, 30);
+ nv_mask(priv, 0x000200, 0x20, 0x20);
+
+ nv_wr32(priv, 0x12004c, 0x4);
+ nv_wr32(priv, 0x122204, 0x2);
+ nv_rd32(priv, 0x122204);
+}
+
+static void
+gk20a_ibus_intr(struct nvkm_subdev *subdev)
+{
+ struct gk20a_ibus_priv *priv = (void *)subdev;
+ u32 status0 = nv_rd32(priv, 0x120058);
+
+ if (status0 & 0x7) {
+ nv_debug(priv, "resetting priv ring\n");
+ gk20a_ibus_init_priv_ring(priv);
+ }
+
+ /* Acknowledge interrupt */
+ nv_mask(priv, 0x12004c, 0x2, 0x2);
+
+ if (!nv_wait(subdev, 0x12004c, 0x3f, 0x00))
+ nv_warn(priv, "timeout waiting for ringmaster ack\n");
+}
+
+static int
+gk20a_ibus_init(struct nvkm_object *object)
+{
+ struct gk20a_ibus_priv *priv = (void *)object;
+ int ret;
+
+ ret = _nvkm_ibus_init(object);
+ if (ret)
+ return ret;
+
+ gk20a_ibus_init_priv_ring(priv);
+
+ return 0;
+}
+
+static int
+gk20a_ibus_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk20a_ibus_priv *priv;
+ int ret;
+
+ ret = nvkm_ibus_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->intr = gk20a_ibus_intr;
+ return 0;
+}
+
+struct nvkm_oclass
+gk20a_ibus_oclass = {
+ .handle = NV_SUBDEV(IBUS, 0xea),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_ibus_ctor,
+ .dtor = _nvkm_ibus_dtor,
+ .init = gk20a_ibus_init,
+ .fini = _nvkm_ibus_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
new file mode 100644
index 000000000000..e6f35abe7879
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/instmem/base.o
+nvkm-y += nvkm/subdev/instmem/nv04.o
+nvkm-y += nvkm/subdev/instmem/nv40.o
+nvkm-y += nvkm/subdev/instmem/nv50.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
new file mode 100644
index 000000000000..d16358cc6cbb
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/base.c
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/engine.h>
+
+/******************************************************************************
+ * instmem object base implementation
+ *****************************************************************************/
+
+void
+_nvkm_instobj_dtor(struct nvkm_object *object)
+{
+ struct nvkm_instmem *imem = nvkm_instmem(object);
+ struct nvkm_instobj *iobj = (void *)object;
+
+ mutex_lock(&nv_subdev(imem)->mutex);
+ list_del(&iobj->head);
+ mutex_unlock(&nv_subdev(imem)->mutex);
+
+ return nvkm_object_destroy(&iobj->base);
+}
+
+int
+nvkm_instobj_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_instmem *imem = nvkm_instmem(parent);
+ struct nvkm_instobj *iobj;
+ int ret;
+
+ ret = nvkm_object_create_(parent, engine, oclass, NV_MEMOBJ_CLASS,
+ length, pobject);
+ iobj = *pobject;
+ if (ret)
+ return ret;
+
+ mutex_lock(&imem->base.mutex);
+ list_add(&iobj->head, &imem->list);
+ mutex_unlock(&imem->base.mutex);
+ return 0;
+}
+
+/******************************************************************************
+ * instmem subdev base implementation
+ *****************************************************************************/
+
+static int
+nvkm_instmem_alloc(struct nvkm_instmem *imem, struct nvkm_object *parent,
+ u32 size, u32 align, struct nvkm_object **pobject)
+{
+ struct nvkm_instmem_impl *impl = (void *)imem->base.object.oclass;
+ struct nvkm_instobj_args args = { .size = size, .align = align };
+ return nvkm_object_ctor(parent, &parent->engine->subdev.object,
+ impl->instobj, &args, sizeof(args), pobject);
+}
+
+int
+_nvkm_instmem_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_instmem *imem = (void *)object;
+ struct nvkm_instobj *iobj;
+ int i, ret = 0;
+
+ if (suspend) {
+ mutex_lock(&imem->base.mutex);
+ list_for_each_entry(iobj, &imem->list, head) {
+ iobj->suspend = vmalloc(iobj->size);
+ if (!iobj->suspend) {
+ ret = -ENOMEM;
+ break;
+ }
+
+ for (i = 0; i < iobj->size; i += 4)
+ iobj->suspend[i / 4] = nv_ro32(iobj, i);
+ }
+ mutex_unlock(&imem->base.mutex);
+ if (ret)
+ return ret;
+ }
+
+ return nvkm_subdev_fini(&imem->base, suspend);
+}
+
+int
+_nvkm_instmem_init(struct nvkm_object *object)
+{
+ struct nvkm_instmem *imem = (void *)object;
+ struct nvkm_instobj *iobj;
+ int ret, i;
+
+ ret = nvkm_subdev_init(&imem->base);
+ if (ret)
+ return ret;
+
+ mutex_lock(&imem->base.mutex);
+ list_for_each_entry(iobj, &imem->list, head) {
+ if (iobj->suspend) {
+ for (i = 0; i < iobj->size; i += 4)
+ nv_wo32(iobj, i, iobj->suspend[i / 4]);
+ vfree(iobj->suspend);
+ iobj->suspend = NULL;
+ }
+ }
+ mutex_unlock(&imem->base.mutex);
+ return 0;
+}
+
+int
+nvkm_instmem_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_instmem *imem;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "INSTMEM",
+ "instmem", length, pobject);
+ imem = *pobject;
+ if (ret)
+ return ret;
+
+ INIT_LIST_HEAD(&imem->list);
+ imem->alloc = nvkm_instmem_alloc;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
new file mode 100644
index 000000000000..80614f1b2074
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.c
@@ -0,0 +1,185 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/ramht.h>
+
+/******************************************************************************
+ * instmem object implementation
+ *****************************************************************************/
+
+static u32
+nv04_instobj_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
+ struct nv04_instobj_priv *node = (void *)object;
+ return nv_ro32(priv, node->mem->offset + addr);
+}
+
+static void
+nv04_instobj_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
+ struct nv04_instobj_priv *node = (void *)object;
+ nv_wo32(priv, node->mem->offset + addr, data);
+}
+
+static void
+nv04_instobj_dtor(struct nvkm_object *object)
+{
+ struct nv04_instmem_priv *priv = (void *)nvkm_instmem(object);
+ struct nv04_instobj_priv *node = (void *)object;
+ nvkm_mm_free(&priv->heap, &node->mem);
+ nvkm_instobj_destroy(&node->base);
+}
+
+static int
+nv04_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_instmem_priv *priv = (void *)nvkm_instmem(parent);
+ struct nv04_instobj_priv *node;
+ struct nvkm_instobj_args *args = data;
+ int ret;
+
+ if (!args->align)
+ args->align = 1;
+
+ ret = nvkm_instobj_create(parent, engine, oclass, &node);
+ *pobject = nv_object(node);
+ if (ret)
+ return ret;
+
+ ret = nvkm_mm_head(&priv->heap, 0, 1, args->size, args->size,
+ args->align, &node->mem);
+ if (ret)
+ return ret;
+
+ node->base.addr = node->mem->offset;
+ node->base.size = node->mem->length;
+ return 0;
+}
+
+struct nvkm_instobj_impl
+nv04_instobj_oclass = {
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_instobj_ctor,
+ .dtor = nv04_instobj_dtor,
+ .init = _nvkm_instobj_init,
+ .fini = _nvkm_instobj_fini,
+ .rd32 = nv04_instobj_rd32,
+ .wr32 = nv04_instobj_wr32,
+ },
+};
+
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static u32
+nv04_instmem_rd32(struct nvkm_object *object, u64 addr)
+{
+ return nv_rd32(object, 0x700000 + addr);
+}
+
+static void
+nv04_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ return nv_wr32(object, 0x700000 + addr, data);
+}
+
+void
+nv04_instmem_dtor(struct nvkm_object *object)
+{
+ struct nv04_instmem_priv *priv = (void *)object;
+ nvkm_gpuobj_ref(NULL, &priv->ramfc);
+ nvkm_gpuobj_ref(NULL, &priv->ramro);
+ nvkm_ramht_ref(NULL, &priv->ramht);
+ nvkm_gpuobj_ref(NULL, &priv->vbios);
+ nvkm_mm_fini(&priv->heap);
+ if (priv->iomem)
+ iounmap(priv->iomem);
+ nvkm_instmem_destroy(&priv->base);
+}
+
+static int
+nv04_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_instmem_priv *priv;
+ int ret;
+
+ ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ /* PRAMIN aperture maps over the end of VRAM, reserve it */
+ priv->base.reserved = 512 * 1024;
+
+ ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1);
+ if (ret)
+ return ret;
+
+ /* 0x00000-0x10000: reserve for probable vbios image */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
+ &priv->vbios);
+ if (ret)
+ return ret;
+
+ /* 0x10000-0x18000: reserve for RAMHT */
+ ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht);
+ if (ret)
+ return ret;
+
+ /* 0x18000-0x18800: reserve for RAMFC (enough for 32 nv30 channels) */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00800, 0,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
+ if (ret)
+ return ret;
+
+ /* 0x18800-0x18a00: reserve for RAMRO */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x00200, 0, 0,
+ &priv->ramro);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_instmem_oclass = &(struct nvkm_instmem_impl) {
+ .base.handle = NV_SUBDEV(INSTMEM, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_instmem_ctor,
+ .dtor = nv04_instmem_dtor,
+ .init = _nvkm_instmem_init,
+ .fini = _nvkm_instmem_fini,
+ .rd32 = nv04_instmem_rd32,
+ .wr32 = nv04_instmem_wr32,
+ },
+ .instobj = &nv04_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h
new file mode 100644
index 000000000000..42b6c928047c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv04.h
@@ -0,0 +1,36 @@
+#ifndef __NV04_INSTMEM_H__
+#define __NV04_INSTMEM_H__
+#include "priv.h"
+
+#include <core/mm.h>
+
+extern struct nvkm_instobj_impl nv04_instobj_oclass;
+
+struct nv04_instmem_priv {
+ struct nvkm_instmem base;
+
+ void __iomem *iomem;
+ struct nvkm_mm heap;
+
+ struct nvkm_gpuobj *vbios;
+ struct nvkm_ramht *ramht;
+ struct nvkm_gpuobj *ramro;
+ struct nvkm_gpuobj *ramfc;
+};
+
+static inline struct nv04_instmem_priv *
+nv04_instmem(void *obj)
+{
+ return (void *)nvkm_instmem(obj);
+}
+
+struct nv04_instobj_priv {
+ struct nvkm_instobj base;
+ struct nvkm_mm_node *mem;
+};
+
+void nv04_instmem_dtor(struct nvkm_object *);
+
+int nv04_instmem_alloc(struct nvkm_instmem *, struct nvkm_object *,
+ u32 size, u32 align, struct nvkm_object **pobject);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c
new file mode 100644
index 000000000000..b42b8588fc0e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv40.c
@@ -0,0 +1,136 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/ramht.h>
+#include <engine/gr/nv40.h>
+
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static u32
+nv40_instmem_rd32(struct nvkm_object *object, u64 addr)
+{
+ struct nv04_instmem_priv *priv = (void *)object;
+ return ioread32_native(priv->iomem + addr);
+}
+
+static void
+nv40_instmem_wr32(struct nvkm_object *object, u64 addr, u32 data)
+{
+ struct nv04_instmem_priv *priv = (void *)object;
+ iowrite32_native(data, priv->iomem + addr);
+}
+
+static int
+nv40_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nv04_instmem_priv *priv;
+ int ret, bar, vs;
+
+ ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ /* map bar */
+ if (nv_device_resource_len(device, 2))
+ bar = 2;
+ else
+ bar = 3;
+
+ priv->iomem = ioremap(nv_device_resource_start(device, bar),
+ nv_device_resource_len(device, bar));
+ if (!priv->iomem) {
+ nv_error(priv, "unable to map PRAMIN BAR\n");
+ return -EFAULT;
+ }
+
+ /* PRAMIN aperture maps over the end of vram, reserve enough space
+ * to fit graphics contexts for every channel, the magics come
+ * from engine/gr/nv40.c
+ */
+ vs = hweight8((nv_rd32(priv, 0x001540) & 0x0000ff00) >> 8);
+ if (device->chipset == 0x40) priv->base.reserved = 0x6aa0 * vs;
+ else if (device->chipset < 0x43) priv->base.reserved = 0x4f00 * vs;
+ else if (nv44_gr_class(priv)) priv->base.reserved = 0x4980 * vs;
+ else priv->base.reserved = 0x4a40 * vs;
+ priv->base.reserved += 16 * 1024;
+ priv->base.reserved *= 32; /* per-channel */
+ priv->base.reserved += 512 * 1024; /* pci(e)gart table */
+ priv->base.reserved += 512 * 1024; /* object storage */
+
+ priv->base.reserved = round_up(priv->base.reserved, 4096);
+
+ ret = nvkm_mm_init(&priv->heap, 0, priv->base.reserved, 1);
+ if (ret)
+ return ret;
+
+ /* 0x00000-0x10000: reserve for probable vbios image */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x10000, 0, 0,
+ &priv->vbios);
+ if (ret)
+ return ret;
+
+ /* 0x10000-0x18000: reserve for RAMHT */
+ ret = nvkm_ramht_new(nv_object(priv), NULL, 0x08000, 0, &priv->ramht);
+ if (ret)
+ return ret;
+
+ /* 0x18000-0x18200: reserve for RAMRO
+ * 0x18200-0x20000: padding
+ */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x08000, 0, 0,
+ &priv->ramro);
+ if (ret)
+ return ret;
+
+ /* 0x20000-0x21000: reserve for RAMFC
+ * 0x21000-0x40000: padding and some unknown crap
+ */
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL, 0x20000, 0,
+ NVOBJ_FLAG_ZERO_ALLOC, &priv->ramfc);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nv40_instmem_oclass = &(struct nvkm_instmem_impl) {
+ .base.handle = NV_SUBDEV(INSTMEM, 0x40),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_instmem_ctor,
+ .dtor = nv04_instmem_dtor,
+ .init = _nvkm_instmem_init,
+ .fini = _nvkm_instmem_fini,
+ .rd32 = nv40_instmem_rd32,
+ .wr32 = nv40_instmem_wr32,
+ },
+ .instobj = &nv04_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
new file mode 100644
index 000000000000..8404143f93ee
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/nv50.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/fb.h>
+
+struct nv50_instmem_priv {
+ struct nvkm_instmem base;
+ spinlock_t lock;
+ u64 addr;
+};
+
+struct nv50_instobj_priv {
+ struct nvkm_instobj base;
+ struct nvkm_mem *mem;
+};
+
+/******************************************************************************
+ * instmem object implementation
+ *****************************************************************************/
+
+static u32
+nv50_instobj_rd32(struct nvkm_object *object, u64 offset)
+{
+ struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object);
+ struct nv50_instobj_priv *node = (void *)object;
+ unsigned long flags;
+ u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
+ u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
+ u32 data;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (unlikely(priv->addr != base)) {
+ nv_wr32(priv, 0x001700, base >> 16);
+ priv->addr = base;
+ }
+ data = nv_rd32(priv, 0x700000 + addr);
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return data;
+}
+
+static void
+nv50_instobj_wr32(struct nvkm_object *object, u64 offset, u32 data)
+{
+ struct nv50_instmem_priv *priv = (void *)nvkm_instmem(object);
+ struct nv50_instobj_priv *node = (void *)object;
+ unsigned long flags;
+ u64 base = (node->mem->offset + offset) & 0xffffff00000ULL;
+ u64 addr = (node->mem->offset + offset) & 0x000000fffffULL;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (unlikely(priv->addr != base)) {
+ nv_wr32(priv, 0x001700, base >> 16);
+ priv->addr = base;
+ }
+ nv_wr32(priv, 0x700000 + addr, data);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nv50_instobj_dtor(struct nvkm_object *object)
+{
+ struct nv50_instobj_priv *node = (void *)object;
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ pfb->ram->put(pfb, &node->mem);
+ nvkm_instobj_destroy(&node->base);
+}
+
+static int
+nv50_instobj_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_instobj_args *args = data;
+ struct nv50_instobj_priv *node;
+ int ret;
+
+ args->size = max((args->size + 4095) & ~4095, (u32)4096);
+ args->align = max((args->align + 4095) & ~4095, (u32)4096);
+
+ ret = nvkm_instobj_create(parent, engine, oclass, &node);
+ *pobject = nv_object(node);
+ if (ret)
+ return ret;
+
+ ret = pfb->ram->get(pfb, args->size, args->align, 0, 0x800, &node->mem);
+ if (ret)
+ return ret;
+
+ node->base.addr = node->mem->offset;
+ node->base.size = node->mem->size << 12;
+ node->mem->page_shift = 12;
+ return 0;
+}
+
+static struct nvkm_instobj_impl
+nv50_instobj_oclass = {
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_instobj_ctor,
+ .dtor = nv50_instobj_dtor,
+ .init = _nvkm_instobj_init,
+ .fini = _nvkm_instobj_fini,
+ .rd32 = nv50_instobj_rd32,
+ .wr32 = nv50_instobj_wr32,
+ },
+};
+
+/******************************************************************************
+ * instmem subdev implementation
+ *****************************************************************************/
+
+static int
+nv50_instmem_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv50_instmem_priv *priv = (void *)object;
+ priv->addr = ~0ULL;
+ return nvkm_instmem_fini(&priv->base, suspend);
+}
+
+static int
+nv50_instmem_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_instmem_priv *priv;
+ int ret;
+
+ ret = nvkm_instmem_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+struct nvkm_oclass *
+nv50_instmem_oclass = &(struct nvkm_instmem_impl) {
+ .base.handle = NV_SUBDEV(INSTMEM, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_instmem_ctor,
+ .dtor = _nvkm_instmem_dtor,
+ .init = _nvkm_instmem_init,
+ .fini = nv50_instmem_fini,
+ },
+ .instobj = &nv50_instobj_oclass.base,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
new file mode 100644
index 000000000000..b10e292e5607
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/instmem/priv.h
@@ -0,0 +1,54 @@
+#ifndef __NVKM_INSTMEM_PRIV_H__
+#define __NVKM_INSTMEM_PRIV_H__
+#include <subdev/instmem.h>
+
+struct nvkm_instobj_impl {
+ struct nvkm_oclass base;
+};
+
+struct nvkm_instobj_args {
+ u32 size;
+ u32 align;
+};
+
+#define nvkm_instobj_create(p,e,o,d) \
+ nvkm_instobj_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_instobj_destroy(p) ({ \
+ struct nvkm_instobj *iobj = (p); \
+ _nvkm_instobj_dtor(nv_object(iobj)); \
+})
+#define nvkm_instobj_init(p) \
+ nvkm_object_init(&(p)->base)
+#define nvkm_instobj_fini(p,s) \
+ nvkm_object_fini(&(p)->base, (s))
+
+int nvkm_instobj_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_instobj_dtor(struct nvkm_object *);
+#define _nvkm_instobj_init nvkm_object_init
+#define _nvkm_instobj_fini nvkm_object_fini
+
+struct nvkm_instmem_impl {
+ struct nvkm_oclass base;
+ struct nvkm_oclass *instobj;
+};
+
+#define nvkm_instmem_create(p,e,o,d) \
+ nvkm_instmem_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_instmem_destroy(p) \
+ nvkm_subdev_destroy(&(p)->base)
+#define nvkm_instmem_init(p) ({ \
+ struct nvkm_instmem *imem = (p); \
+ _nvkm_instmem_init(nv_object(imem)); \
+})
+#define nvkm_instmem_fini(p,s) ({ \
+ struct nvkm_instmem *imem = (p); \
+ _nvkm_instmem_fini(nv_object(imem), (s)); \
+})
+
+int nvkm_instmem_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+#define _nvkm_instmem_dtor _nvkm_subdev_dtor
+int _nvkm_instmem_init(struct nvkm_object *);
+int _nvkm_instmem_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
new file mode 100644
index 000000000000..e5df3d865f0c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/ltc/base.o
+nvkm-y += nvkm/subdev/ltc/gf100.o
+nvkm-y += nvkm/subdev/ltc/gk104.o
+nvkm-y += nvkm/subdev/ltc/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
new file mode 100644
index 000000000000..2fb87fbfd11c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/base.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs <bskeggs@redhat.com>
+ */
+#include "priv.h"
+
+static int
+nvkm_ltc_tags_alloc(struct nvkm_ltc *ltc, u32 n, struct nvkm_mm_node **pnode)
+{
+ struct nvkm_ltc_priv *priv = (void *)ltc;
+ int ret;
+
+ ret = nvkm_mm_head(&priv->tags, 0, 1, n, n, 1, pnode);
+ if (ret)
+ *pnode = NULL;
+
+ return ret;
+}
+
+static void
+nvkm_ltc_tags_free(struct nvkm_ltc *ltc, struct nvkm_mm_node **pnode)
+{
+ struct nvkm_ltc_priv *priv = (void *)ltc;
+ nvkm_mm_free(&priv->tags, pnode);
+}
+
+static void
+nvkm_ltc_tags_clear(struct nvkm_ltc *ltc, u32 first, u32 count)
+{
+ const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
+ struct nvkm_ltc_priv *priv = (void *)ltc;
+ const u32 limit = first + count - 1;
+
+ BUG_ON((first > limit) || (limit >= priv->num_tags));
+
+ impl->cbc_clear(priv, first, limit);
+ impl->cbc_wait(priv);
+}
+
+static int
+nvkm_ltc_zbc_color_get(struct nvkm_ltc *ltc, int index, const u32 color[4])
+{
+ const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
+ struct nvkm_ltc_priv *priv = (void *)ltc;
+ memcpy(priv->zbc_color[index], color, sizeof(priv->zbc_color[index]));
+ impl->zbc_clear_color(priv, index, color);
+ return index;
+}
+
+static int
+nvkm_ltc_zbc_depth_get(struct nvkm_ltc *ltc, int index, const u32 depth)
+{
+ const struct nvkm_ltc_impl *impl = (void *)nv_oclass(ltc);
+ struct nvkm_ltc_priv *priv = (void *)ltc;
+ priv->zbc_depth[index] = depth;
+ impl->zbc_clear_depth(priv, index, depth);
+ return index;
+}
+
+int
+_nvkm_ltc_init(struct nvkm_object *object)
+{
+ const struct nvkm_ltc_impl *impl = (void *)nv_oclass(object);
+ struct nvkm_ltc_priv *priv = (void *)object;
+ int ret, i;
+
+ ret = nvkm_subdev_init(&priv->base.base);
+ if (ret)
+ return ret;
+
+ for (i = priv->base.zbc_min; i <= priv->base.zbc_max; i++) {
+ impl->zbc_clear_color(priv, i, priv->zbc_color[i]);
+ impl->zbc_clear_depth(priv, i, priv->zbc_depth[i]);
+ }
+
+ return 0;
+}
+
+int
+nvkm_ltc_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ const struct nvkm_ltc_impl *impl = (void *)oclass;
+ struct nvkm_ltc_priv *priv;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PLTCG",
+ "l2c", length, pobject);
+ priv = *pobject;
+ if (ret)
+ return ret;
+
+ memset(priv->zbc_color, 0x00, sizeof(priv->zbc_color));
+ memset(priv->zbc_depth, 0x00, sizeof(priv->zbc_depth));
+
+ priv->base.base.intr = impl->intr;
+ priv->base.tags_alloc = nvkm_ltc_tags_alloc;
+ priv->base.tags_free = nvkm_ltc_tags_free;
+ priv->base.tags_clear = nvkm_ltc_tags_clear;
+ priv->base.zbc_min = 1; /* reserve 0 for disabled */
+ priv->base.zbc_max = min(impl->zbc, NVKM_LTC_MAX_ZBC_CNT) - 1;
+ priv->base.zbc_color_get = nvkm_ltc_zbc_color_get;
+ priv->base.zbc_depth_get = nvkm_ltc_zbc_depth_get;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
new file mode 100644
index 000000000000..8e7cc6200d60
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gf100.c
@@ -0,0 +1,236 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/enum.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+void
+gf100_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
+{
+ nv_wr32(priv, 0x17e8cc, start);
+ nv_wr32(priv, 0x17e8d0, limit);
+ nv_wr32(priv, 0x17e8c8, 0x00000004);
+}
+
+void
+gf100_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
+{
+ int c, s;
+ for (c = 0; c < priv->ltc_nr; c++) {
+ for (s = 0; s < priv->lts_nr; s++)
+ nv_wait(priv, 0x1410c8 + c * 0x2000 + s * 0x400, ~0, 0);
+ }
+}
+
+void
+gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
+{
+ nv_mask(priv, 0x17ea44, 0x0000000f, i);
+ nv_wr32(priv, 0x17ea48, color[0]);
+ nv_wr32(priv, 0x17ea4c, color[1]);
+ nv_wr32(priv, 0x17ea50, color[2]);
+ nv_wr32(priv, 0x17ea54, color[3]);
+}
+
+void
+gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
+{
+ nv_mask(priv, 0x17ea44, 0x0000000f, i);
+ nv_wr32(priv, 0x17ea58, depth);
+}
+
+static const struct nvkm_bitfield
+gf100_ltc_lts_intr_name[] = {
+ { 0x00000001, "IDLE_ERROR_IQ" },
+ { 0x00000002, "IDLE_ERROR_CBC" },
+ { 0x00000004, "IDLE_ERROR_TSTG" },
+ { 0x00000008, "IDLE_ERROR_DSTG" },
+ { 0x00000010, "EVICTED_CB" },
+ { 0x00000020, "ILLEGAL_COMPSTAT" },
+ { 0x00000040, "BLOCKLINEAR_CB" },
+ { 0x00000100, "ECC_SEC_ERROR" },
+ { 0x00000200, "ECC_DED_ERROR" },
+ { 0x00000400, "DEBUG" },
+ { 0x00000800, "ATOMIC_TO_Z" },
+ { 0x00001000, "ILLEGAL_ATOMIC" },
+ { 0x00002000, "BLKACTIVITY_ERR" },
+ {}
+};
+
+static void
+gf100_ltc_lts_intr(struct nvkm_ltc_priv *priv, int ltc, int lts)
+{
+ u32 base = 0x141000 + (ltc * 0x2000) + (lts * 0x400);
+ u32 intr = nv_rd32(priv, base + 0x020);
+ u32 stat = intr & 0x0000ffff;
+
+ if (stat) {
+ nv_info(priv, "LTC%d_LTS%d:", ltc, lts);
+ nvkm_bitfield_print(gf100_ltc_lts_intr_name, stat);
+ pr_cont("\n");
+ }
+
+ nv_wr32(priv, base + 0x020, intr);
+}
+
+void
+gf100_ltc_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_ltc_priv *priv = (void *)subdev;
+ u32 mask;
+
+ mask = nv_rd32(priv, 0x00017c);
+ while (mask) {
+ u32 lts, ltc = __ffs(mask);
+ for (lts = 0; lts < priv->lts_nr; lts++)
+ gf100_ltc_lts_intr(priv, ltc, lts);
+ mask &= ~(1 << ltc);
+ }
+}
+
+static int
+gf100_ltc_init(struct nvkm_object *object)
+{
+ struct nvkm_ltc_priv *priv = (void *)object;
+ u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
+ int ret;
+
+ ret = nvkm_ltc_init(priv);
+ if (ret)
+ return ret;
+
+ nv_mask(priv, 0x17e820, 0x00100000, 0x00000000); /* INTR_EN &= ~0x10 */
+ nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
+ nv_wr32(priv, 0x17e8d4, priv->tag_base);
+ nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
+ return 0;
+}
+
+void
+gf100_ltc_dtor(struct nvkm_object *object)
+{
+ struct nvkm_fb *pfb = nvkm_fb(object);
+ struct nvkm_ltc_priv *priv = (void *)object;
+
+ nvkm_mm_fini(&priv->tags);
+ nvkm_mm_free(&pfb->vram, &priv->tag_ram);
+
+ nvkm_ltc_destroy(priv);
+}
+
+/* TODO: Figure out tag memory details and drop the over-cautious allocation.
+ */
+int
+gf100_ltc_init_tag_ram(struct nvkm_fb *pfb, struct nvkm_ltc_priv *priv)
+{
+ u32 tag_size, tag_margin, tag_align;
+ int ret;
+
+ /* tags for 1/4 of VRAM should be enough (8192/4 per GiB of VRAM) */
+ priv->num_tags = (pfb->ram->size >> 17) / 4;
+ if (priv->num_tags > (1 << 17))
+ priv->num_tags = 1 << 17; /* we have 17 bits in PTE */
+ priv->num_tags = (priv->num_tags + 63) & ~63; /* round up to 64 */
+
+ tag_align = priv->ltc_nr * 0x800;
+ tag_margin = (tag_align < 0x6000) ? 0x6000 : tag_align;
+
+ /* 4 part 4 sub: 0x2000 bytes for 56 tags */
+ /* 3 part 4 sub: 0x6000 bytes for 168 tags */
+ /*
+ * About 147 bytes per tag. Let's be safe and allocate x2, which makes
+ * 0x4980 bytes for 64 tags, and round up to 0x6000 bytes for 64 tags.
+ *
+ * For 4 GiB of memory we'll have 8192 tags which makes 3 MiB, < 0.1 %.
+ */
+ tag_size = (priv->num_tags / 64) * 0x6000 + tag_margin;
+ tag_size += tag_align;
+ tag_size = (tag_size + 0xfff) >> 12; /* round up */
+
+ ret = nvkm_mm_tail(&pfb->vram, 1, 1, tag_size, tag_size, 1,
+ &priv->tag_ram);
+ if (ret) {
+ priv->num_tags = 0;
+ } else {
+ u64 tag_base = ((u64)priv->tag_ram->offset << 12) + tag_margin;
+
+ tag_base += tag_align - 1;
+ ret = do_div(tag_base, tag_align);
+
+ priv->tag_base = tag_base;
+ }
+
+ ret = nvkm_mm_init(&priv->tags, 0, priv->num_tags, 1);
+ return ret;
+}
+
+int
+gf100_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ltc_priv *priv;
+ u32 parts, mask;
+ int ret, i;
+
+ ret = nvkm_ltc_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ parts = nv_rd32(priv, 0x022438);
+ mask = nv_rd32(priv, 0x022554);
+ for (i = 0; i < parts; i++) {
+ if (!(mask & (1 << i)))
+ priv->ltc_nr++;
+ }
+ priv->lts_nr = nv_rd32(priv, 0x17e8dc) >> 28;
+
+ ret = gf100_ltc_init_tag_ram(pfb, priv);
+ if (ret)
+ return ret;
+
+ nv_subdev(priv)->intr = gf100_ltc_intr;
+ return 0;
+}
+
+struct nvkm_oclass *
+gf100_ltc_oclass = &(struct nvkm_ltc_impl) {
+ .base.handle = NV_SUBDEV(LTC, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_ltc_ctor,
+ .dtor = gf100_ltc_dtor,
+ .init = gf100_ltc_init,
+ .fini = _nvkm_ltc_fini,
+ },
+ .intr = gf100_ltc_intr,
+ .cbc_clear = gf100_ltc_cbc_clear,
+ .cbc_wait = gf100_ltc_cbc_wait,
+ .zbc = 16,
+ .zbc_clear_color = gf100_ltc_zbc_clear_color,
+ .zbc_clear_depth = gf100_ltc_zbc_clear_depth,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
new file mode 100644
index 000000000000..d53959b5ec67
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gk104.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+gk104_ltc_init(struct nvkm_object *object)
+{
+ struct nvkm_ltc_priv *priv = (void *)object;
+ u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
+ int ret;
+
+ ret = nvkm_ltc_init(priv);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x17e8d8, priv->ltc_nr);
+ nv_wr32(priv, 0x17e000, priv->ltc_nr);
+ nv_wr32(priv, 0x17e8d4, priv->tag_base);
+ nv_mask(priv, 0x17e8c0, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
+ return 0;
+}
+
+struct nvkm_oclass *
+gk104_ltc_oclass = &(struct nvkm_ltc_impl) {
+ .base.handle = NV_SUBDEV(LTC, 0xe4),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_ltc_ctor,
+ .dtor = gf100_ltc_dtor,
+ .init = gk104_ltc_init,
+ .fini = _nvkm_ltc_fini,
+ },
+ .intr = gf100_ltc_intr,
+ .cbc_clear = gf100_ltc_cbc_clear,
+ .cbc_wait = gf100_ltc_cbc_wait,
+ .zbc = 16,
+ .zbc_clear_color = gf100_ltc_zbc_clear_color,
+ .zbc_clear_depth = gf100_ltc_zbc_clear_depth,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
new file mode 100644
index 000000000000..6b3f6f4ce107
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/gm107.c
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2014 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+static void
+gm107_ltc_cbc_clear(struct nvkm_ltc_priv *priv, u32 start, u32 limit)
+{
+ nv_wr32(priv, 0x17e270, start);
+ nv_wr32(priv, 0x17e274, limit);
+ nv_wr32(priv, 0x17e26c, 0x00000004);
+}
+
+static void
+gm107_ltc_cbc_wait(struct nvkm_ltc_priv *priv)
+{
+ int c, s;
+ for (c = 0; c < priv->ltc_nr; c++) {
+ for (s = 0; s < priv->lts_nr; s++)
+ nv_wait(priv, 0x14046c + c * 0x2000 + s * 0x200, ~0, 0);
+ }
+}
+
+static void
+gm107_ltc_zbc_clear_color(struct nvkm_ltc_priv *priv, int i, const u32 color[4])
+{
+ nv_mask(priv, 0x17e338, 0x0000000f, i);
+ nv_wr32(priv, 0x17e33c, color[0]);
+ nv_wr32(priv, 0x17e340, color[1]);
+ nv_wr32(priv, 0x17e344, color[2]);
+ nv_wr32(priv, 0x17e348, color[3]);
+}
+
+static void
+gm107_ltc_zbc_clear_depth(struct nvkm_ltc_priv *priv, int i, const u32 depth)
+{
+ nv_mask(priv, 0x17e338, 0x0000000f, i);
+ nv_wr32(priv, 0x17e34c, depth);
+}
+
+static void
+gm107_ltc_lts_isr(struct nvkm_ltc_priv *priv, int ltc, int lts)
+{
+ u32 base = 0x140000 + (ltc * 0x2000) + (lts * 0x400);
+ u32 stat = nv_rd32(priv, base + 0x00c);
+
+ if (stat) {
+ nv_info(priv, "LTC%d_LTS%d: 0x%08x\n", ltc, lts, stat);
+ nv_wr32(priv, base + 0x00c, stat);
+ }
+}
+
+static void
+gm107_ltc_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_ltc_priv *priv = (void *)subdev;
+ u32 mask;
+
+ mask = nv_rd32(priv, 0x00017c);
+ while (mask) {
+ u32 lts, ltc = __ffs(mask);
+ for (lts = 0; lts < priv->lts_nr; lts++)
+ gm107_ltc_lts_isr(priv, ltc, lts);
+ mask &= ~(1 << ltc);
+ }
+}
+
+static int
+gm107_ltc_init(struct nvkm_object *object)
+{
+ struct nvkm_ltc_priv *priv = (void *)object;
+ u32 lpg128 = !(nv_rd32(priv, 0x100c80) & 0x00000001);
+ int ret;
+
+ ret = nvkm_ltc_init(priv);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x17e27c, priv->ltc_nr);
+ nv_wr32(priv, 0x17e278, priv->tag_base);
+ nv_mask(priv, 0x17e264, 0x00000002, lpg128 ? 0x00000002 : 0x00000000);
+ return 0;
+}
+
+static int
+gm107_ltc_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_fb *pfb = nvkm_fb(parent);
+ struct nvkm_ltc_priv *priv;
+ u32 parts, mask;
+ int ret, i;
+
+ ret = nvkm_ltc_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ parts = nv_rd32(priv, 0x022438);
+ mask = nv_rd32(priv, 0x021c14);
+ for (i = 0; i < parts; i++) {
+ if (!(mask & (1 << i)))
+ priv->ltc_nr++;
+ }
+ priv->lts_nr = nv_rd32(priv, 0x17e280) >> 28;
+
+ ret = gf100_ltc_init_tag_ram(pfb, priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+gm107_ltc_oclass = &(struct nvkm_ltc_impl) {
+ .base.handle = NV_SUBDEV(LTC, 0xff),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm107_ltc_ctor,
+ .dtor = gf100_ltc_dtor,
+ .init = gm107_ltc_init,
+ .fini = _nvkm_ltc_fini,
+ },
+ .intr = gm107_ltc_intr,
+ .cbc_clear = gm107_ltc_cbc_clear,
+ .cbc_wait = gm107_ltc_cbc_wait,
+ .zbc = 16,
+ .zbc_clear_color = gm107_ltc_zbc_clear_color,
+ .zbc_clear_depth = gm107_ltc_zbc_clear_depth,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
new file mode 100644
index 000000000000..09537d7b6783
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/ltc/priv.h
@@ -0,0 +1,69 @@
+#ifndef __NVKM_LTC_PRIV_H__
+#define __NVKM_LTC_PRIV_H__
+#include <subdev/ltc.h>
+
+#include <core/mm.h>
+struct nvkm_fb;
+
+struct nvkm_ltc_priv {
+ struct nvkm_ltc base;
+ u32 ltc_nr;
+ u32 lts_nr;
+
+ u32 num_tags;
+ u32 tag_base;
+ struct nvkm_mm tags;
+ struct nvkm_mm_node *tag_ram;
+
+ u32 zbc_color[NVKM_LTC_MAX_ZBC_CNT][4];
+ u32 zbc_depth[NVKM_LTC_MAX_ZBC_CNT];
+};
+
+#define nvkm_ltc_create(p,e,o,d) \
+ nvkm_ltc_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_ltc_destroy(p) ({ \
+ struct nvkm_ltc_priv *_priv = (p); \
+ _nvkm_ltc_dtor(nv_object(_priv)); \
+})
+#define nvkm_ltc_init(p) ({ \
+ struct nvkm_ltc_priv *_priv = (p); \
+ _nvkm_ltc_init(nv_object(_priv)); \
+})
+#define nvkm_ltc_fini(p,s) ({ \
+ struct nvkm_ltc_priv *_priv = (p); \
+ _nvkm_ltc_fini(nv_object(_priv), (s)); \
+})
+
+int nvkm_ltc_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+
+#define _nvkm_ltc_dtor _nvkm_subdev_dtor
+int _nvkm_ltc_init(struct nvkm_object *);
+#define _nvkm_ltc_fini _nvkm_subdev_fini
+
+int gf100_ltc_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void gf100_ltc_dtor(struct nvkm_object *);
+int gf100_ltc_init_tag_ram(struct nvkm_fb *, struct nvkm_ltc_priv *);
+int gf100_ltc_tags_alloc(struct nvkm_ltc *, u32, struct nvkm_mm_node **);
+void gf100_ltc_tags_free(struct nvkm_ltc *, struct nvkm_mm_node **);
+
+struct nvkm_ltc_impl {
+ struct nvkm_oclass base;
+ void (*intr)(struct nvkm_subdev *);
+
+ void (*cbc_clear)(struct nvkm_ltc_priv *, u32 start, u32 limit);
+ void (*cbc_wait)(struct nvkm_ltc_priv *);
+
+ int zbc;
+ void (*zbc_clear_color)(struct nvkm_ltc_priv *, int, const u32[4]);
+ void (*zbc_clear_depth)(struct nvkm_ltc_priv *, int, const u32);
+};
+
+void gf100_ltc_intr(struct nvkm_subdev *);
+void gf100_ltc_cbc_clear(struct nvkm_ltc_priv *, u32, u32);
+void gf100_ltc_cbc_wait(struct nvkm_ltc_priv *);
+void gf100_ltc_zbc_clear_color(struct nvkm_ltc_priv *, int, const u32[4]);
+void gf100_ltc_zbc_clear_depth(struct nvkm_ltc_priv *, int, const u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
new file mode 100644
index 000000000000..721643f04bb5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/Kbuild
@@ -0,0 +1,11 @@
+nvkm-y += nvkm/subdev/mc/base.o
+nvkm-y += nvkm/subdev/mc/nv04.o
+nvkm-y += nvkm/subdev/mc/nv40.o
+nvkm-y += nvkm/subdev/mc/nv44.o
+nvkm-y += nvkm/subdev/mc/nv4c.o
+nvkm-y += nvkm/subdev/mc/nv50.o
+nvkm-y += nvkm/subdev/mc/g94.o
+nvkm-y += nvkm/subdev/mc/g98.o
+nvkm-y += nvkm/subdev/mc/gf100.o
+nvkm-y += nvkm/subdev/mc/gf106.o
+nvkm-y += nvkm/subdev/mc/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
new file mode 100644
index 000000000000..5b051a26653e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/base.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+
+static inline void
+nvkm_mc_unk260(struct nvkm_mc *pmc, u32 data)
+{
+ const struct nvkm_mc_oclass *impl = (void *)nv_oclass(pmc);
+ if (impl->unk260)
+ impl->unk260(pmc, data);
+}
+
+static inline u32
+nvkm_mc_intr_mask(struct nvkm_mc *pmc)
+{
+ u32 intr = nv_rd32(pmc, 0x000100);
+ if (intr == 0xffffffff) /* likely fallen off the bus */
+ intr = 0x00000000;
+ return intr;
+}
+
+static irqreturn_t
+nvkm_mc_intr(int irq, void *arg)
+{
+ struct nvkm_mc *pmc = arg;
+ const struct nvkm_mc_oclass *oclass = (void *)nv_object(pmc)->oclass;
+ const struct nvkm_mc_intr *map = oclass->intr;
+ struct nvkm_subdev *unit;
+ u32 intr;
+
+ nv_wr32(pmc, 0x000140, 0x00000000);
+ nv_rd32(pmc, 0x000140);
+ intr = nvkm_mc_intr_mask(pmc);
+ if (pmc->use_msi)
+ oclass->msi_rearm(pmc);
+
+ if (intr) {
+ u32 stat = intr = nvkm_mc_intr_mask(pmc);
+ while (map->stat) {
+ if (intr & map->stat) {
+ unit = nvkm_subdev(pmc, map->unit);
+ if (unit && unit->intr)
+ unit->intr(unit);
+ stat &= ~map->stat;
+ }
+ map++;
+ }
+
+ if (stat)
+ nv_error(pmc, "unknown intr 0x%08x\n", stat);
+ }
+
+ nv_wr32(pmc, 0x000140, 0x00000001);
+ return intr ? IRQ_HANDLED : IRQ_NONE;
+}
+
+int
+_nvkm_mc_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_mc *pmc = (void *)object;
+ nv_wr32(pmc, 0x000140, 0x00000000);
+ return nvkm_subdev_fini(&pmc->base, suspend);
+}
+
+int
+_nvkm_mc_init(struct nvkm_object *object)
+{
+ struct nvkm_mc *pmc = (void *)object;
+ int ret = nvkm_subdev_init(&pmc->base);
+ if (ret)
+ return ret;
+ nv_wr32(pmc, 0x000140, 0x00000001);
+ return 0;
+}
+
+void
+_nvkm_mc_dtor(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nvkm_mc *pmc = (void *)object;
+ free_irq(pmc->irq, pmc);
+ if (pmc->use_msi)
+ pci_disable_msi(device->pdev);
+ nvkm_subdev_destroy(&pmc->base);
+}
+
+int
+nvkm_mc_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *bclass, int length, void **pobject)
+{
+ const struct nvkm_mc_oclass *oclass = (void *)bclass;
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_mc *pmc;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, bclass, 0, "PMC",
+ "master", length, pobject);
+ pmc = *pobject;
+ if (ret)
+ return ret;
+
+ pmc->unk260 = nvkm_mc_unk260;
+
+ if (nv_device_is_pci(device)) {
+ switch (device->pdev->device & 0x0ff0) {
+ case 0x00f0:
+ case 0x02e0:
+ /* BR02? NFI how these would be handled yet exactly */
+ break;
+ default:
+ switch (device->chipset) {
+ case 0xaa:
+ /* reported broken, nv also disable it */
+ break;
+ default:
+ pmc->use_msi = true;
+ break;
+ }
+ }
+
+ pmc->use_msi = nvkm_boolopt(device->cfgopt, "NvMSI",
+ pmc->use_msi);
+
+ if (pmc->use_msi && oclass->msi_rearm) {
+ pmc->use_msi = pci_enable_msi(device->pdev) == 0;
+ if (pmc->use_msi) {
+ nv_info(pmc, "MSI interrupts enabled\n");
+ oclass->msi_rearm(pmc);
+ }
+ } else {
+ pmc->use_msi = false;
+ }
+ }
+
+ ret = nv_device_get_irq(device, true);
+ if (ret < 0)
+ return ret;
+ pmc->irq = ret;
+
+ ret = request_irq(pmc->irq, nvkm_mc_intr, IRQF_SHARED, "nvkm", pmc);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c
new file mode 100644
index 000000000000..f042e7d8321d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g94.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+g94_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x94),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv50_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = nv50_mc_intr,
+ .msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
new file mode 100644
index 000000000000..8ab7f1272a14
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/g98.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+static const struct nvkm_mc_intr
+g98_mc_intr[] = {
+ { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work */
+ { 0x00000001, NVDEV_ENGINE_MSPPP },
+ { 0x00000100, NVDEV_ENGINE_FIFO },
+ { 0x00001000, NVDEV_ENGINE_GR },
+ { 0x00004000, NVDEV_ENGINE_SEC }, /* NV84:NVA3 */
+ { 0x00008000, NVDEV_ENGINE_MSVLD },
+ { 0x00020000, NVDEV_ENGINE_MSPDEC },
+ { 0x00040000, NVDEV_SUBDEV_PMU }, /* NVA3:NVC0 */
+ { 0x00080000, NVDEV_SUBDEV_THERM }, /* NVA3:NVC0 */
+ { 0x00100000, NVDEV_SUBDEV_TIMER },
+ { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
+ { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
+ { 0x00400000, NVDEV_ENGINE_CE0 }, /* NVA3- */
+ { 0x10000000, NVDEV_SUBDEV_BUS },
+ { 0x80000000, NVDEV_ENGINE_SW },
+ { 0x0042d101, NVDEV_SUBDEV_FB },
+ {},
+};
+
+struct nvkm_oclass *
+g98_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x98),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv50_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = g98_mc_intr,
+ .msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
new file mode 100644
index 000000000000..2425984b045e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf100.c
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+const struct nvkm_mc_intr
+gf100_mc_intr[] = {
+ { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP first, so pageflip timestamps work. */
+ { 0x00000001, NVDEV_ENGINE_MSPPP },
+ { 0x00000020, NVDEV_ENGINE_CE0 },
+ { 0x00000040, NVDEV_ENGINE_CE1 },
+ { 0x00000080, NVDEV_ENGINE_CE2 },
+ { 0x00000100, NVDEV_ENGINE_FIFO },
+ { 0x00001000, NVDEV_ENGINE_GR },
+ { 0x00002000, NVDEV_SUBDEV_FB },
+ { 0x00008000, NVDEV_ENGINE_MSVLD },
+ { 0x00040000, NVDEV_SUBDEV_THERM },
+ { 0x00020000, NVDEV_ENGINE_MSPDEC },
+ { 0x00100000, NVDEV_SUBDEV_TIMER },
+ { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
+ { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
+ { 0x01000000, NVDEV_SUBDEV_PMU },
+ { 0x02000000, NVDEV_SUBDEV_LTC },
+ { 0x08000000, NVDEV_SUBDEV_FB },
+ { 0x10000000, NVDEV_SUBDEV_BUS },
+ { 0x40000000, NVDEV_SUBDEV_IBUS },
+ { 0x80000000, NVDEV_ENGINE_SW },
+ {},
+};
+
+static void
+gf100_mc_msi_rearm(struct nvkm_mc *pmc)
+{
+ struct nv04_mc_priv *priv = (void *)pmc;
+ nv_wr32(priv, 0x088704, 0x00000000);
+}
+
+void
+gf100_mc_unk260(struct nvkm_mc *pmc, u32 data)
+{
+ nv_wr32(pmc, 0x000260, data);
+}
+
+struct nvkm_oclass *
+gf100_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv50_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = gf100_mc_intr,
+ .msi_rearm = gf100_mc_msi_rearm,
+ .unk260 = gf100_mc_unk260,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c
new file mode 100644
index 000000000000..8d2a8f457778
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gf106.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+gf106_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0xc3),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv50_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = gf100_mc_intr,
+ .msi_rearm = nv40_mc_msi_rearm,
+ .unk260 = gf100_mc_unk260,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
new file mode 100644
index 000000000000..43b27742956d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/gk20a.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+gk20a_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0xea),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv50_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = gf100_mc_intr,
+ .msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
new file mode 100644
index 000000000000..32713827b4dc
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+const struct nvkm_mc_intr
+nv04_mc_intr[] = {
+ { 0x00000001, NVDEV_ENGINE_MPEG }, /* NV17- MPEG/ME */
+ { 0x00000100, NVDEV_ENGINE_FIFO },
+ { 0x00001000, NVDEV_ENGINE_GR },
+ { 0x00010000, NVDEV_ENGINE_DISP },
+ { 0x00020000, NVDEV_ENGINE_VP }, /* NV40- */
+ { 0x00100000, NVDEV_SUBDEV_TIMER },
+ { 0x01000000, NVDEV_ENGINE_DISP }, /* NV04- PCRTC0 */
+ { 0x02000000, NVDEV_ENGINE_DISP }, /* NV11- PCRTC1 */
+ { 0x10000000, NVDEV_SUBDEV_BUS },
+ { 0x80000000, NVDEV_ENGINE_SW },
+ {}
+};
+
+int
+nv04_mc_init(struct nvkm_object *object)
+{
+ struct nv04_mc_priv *priv = (void *)object;
+
+ nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
+ nv_wr32(priv, 0x001850, 0x00000001); /* disable rom access */
+
+ return nvkm_mc_init(&priv->base);
+}
+
+int
+nv04_mc_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_mc_priv *priv;
+ int ret;
+
+ ret = nvkm_mc_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass *
+nv04_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x04),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv04_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = nv04_mc_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h
new file mode 100644
index 000000000000..411de3d08ab6
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv04.h
@@ -0,0 +1,20 @@
+#ifndef __NVKM_MC_NV04_H__
+#define __NVKM_MC_NV04_H__
+#include "priv.h"
+
+struct nv04_mc_priv {
+ struct nvkm_mc base;
+};
+
+int nv04_mc_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+
+extern const struct nvkm_mc_intr nv04_mc_intr[];
+int nv04_mc_init(struct nvkm_object *);
+void nv40_mc_msi_rearm(struct nvkm_mc *);
+int nv44_mc_init(struct nvkm_object *object);
+int nv50_mc_init(struct nvkm_object *);
+extern const struct nvkm_mc_intr nv50_mc_intr[];
+extern const struct nvkm_mc_intr gf100_mc_intr[];
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c
new file mode 100644
index 000000000000..b7613059da08
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv40.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+void
+nv40_mc_msi_rearm(struct nvkm_mc *pmc)
+{
+ struct nv04_mc_priv *priv = (void *)pmc;
+ nv_wr08(priv, 0x088068, 0xff);
+}
+
+struct nvkm_oclass *
+nv40_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x40),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv04_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = nv04_mc_intr,
+ .msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
new file mode 100644
index 000000000000..2c7f7c701a2b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv44.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+int
+nv44_mc_init(struct nvkm_object *object)
+{
+ struct nv04_mc_priv *priv = (void *)object;
+ u32 tmp = nv_rd32(priv, 0x10020c);
+
+ nv_wr32(priv, 0x000200, 0xffffffff); /* everything enabled */
+
+ nv_wr32(priv, 0x001700, tmp);
+ nv_wr32(priv, 0x001704, 0);
+ nv_wr32(priv, 0x001708, 0);
+ nv_wr32(priv, 0x00170c, tmp);
+
+ return nvkm_mc_init(&priv->base);
+}
+
+struct nvkm_oclass *
+nv44_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x44),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv44_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = nv04_mc_intr,
+ .msi_rearm = nv40_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c
new file mode 100644
index 000000000000..c0aac7e20d45
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv4c.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2014 Ilia Mirkin
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ilia Mirkin
+ */
+#include "nv04.h"
+
+struct nvkm_oclass *
+nv4c_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x4c),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv44_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = nv04_mc_intr,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
new file mode 100644
index 000000000000..40e3019e1fde
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/nv50.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+
+const struct nvkm_mc_intr
+nv50_mc_intr[] = {
+ { 0x04000000, NVDEV_ENGINE_DISP }, /* DISP before FIFO, so pageflip-timestamping works! */
+ { 0x00000001, NVDEV_ENGINE_MPEG },
+ { 0x00000100, NVDEV_ENGINE_FIFO },
+ { 0x00001000, NVDEV_ENGINE_GR },
+ { 0x00004000, NVDEV_ENGINE_CIPHER }, /* NV84- */
+ { 0x00008000, NVDEV_ENGINE_BSP }, /* NV84- */
+ { 0x00020000, NVDEV_ENGINE_VP }, /* NV84- */
+ { 0x00100000, NVDEV_SUBDEV_TIMER },
+ { 0x00200000, NVDEV_SUBDEV_GPIO }, /* PMGR->GPIO */
+ { 0x00200000, NVDEV_SUBDEV_I2C }, /* PMGR->I2C/AUX */
+ { 0x10000000, NVDEV_SUBDEV_BUS },
+ { 0x80000000, NVDEV_ENGINE_SW },
+ { 0x0002d101, NVDEV_SUBDEV_FB },
+ {},
+};
+
+static void
+nv50_mc_msi_rearm(struct nvkm_mc *pmc)
+{
+ struct nvkm_device *device = nv_device(pmc);
+ pci_write_config_byte(device->pdev, 0x68, 0xff);
+}
+
+int
+nv50_mc_init(struct nvkm_object *object)
+{
+ struct nv04_mc_priv *priv = (void *)object;
+ nv_wr32(priv, 0x000200, 0xffffffff); /* everything on */
+ return nvkm_mc_init(&priv->base);
+}
+
+struct nvkm_oclass *
+nv50_mc_oclass = &(struct nvkm_mc_oclass) {
+ .base.handle = NV_SUBDEV(MC, 0x50),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mc_ctor,
+ .dtor = _nvkm_mc_dtor,
+ .init = nv50_mc_init,
+ .fini = _nvkm_mc_fini,
+ },
+ .intr = nv50_mc_intr,
+ .msi_rearm = nv50_mc_msi_rearm,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
new file mode 100644
index 000000000000..d2cad07afd1a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mc/priv.h
@@ -0,0 +1,36 @@
+#ifndef __NVKM_MC_PRIV_H__
+#define __NVKM_MC_PRIV_H__
+#include <subdev/mc.h>
+
+#define nvkm_mc_create(p,e,o,d) \
+ nvkm_mc_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_mc_destroy(p) ({ \
+ struct nvkm_mc *pmc = (p); _nvkm_mc_dtor(nv_object(pmc)); \
+})
+#define nvkm_mc_init(p) ({ \
+ struct nvkm_mc *pmc = (p); _nvkm_mc_init(nv_object(pmc)); \
+})
+#define nvkm_mc_fini(p,s) ({ \
+ struct nvkm_mc *pmc = (p); _nvkm_mc_fini(nv_object(pmc), (s)); \
+})
+
+int nvkm_mc_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+void _nvkm_mc_dtor(struct nvkm_object *);
+int _nvkm_mc_init(struct nvkm_object *);
+int _nvkm_mc_fini(struct nvkm_object *, bool);
+
+struct nvkm_mc_intr {
+ u32 stat;
+ u32 unit;
+};
+
+struct nvkm_mc_oclass {
+ struct nvkm_oclass base;
+ const struct nvkm_mc_intr *intr;
+ void (*msi_rearm)(struct nvkm_mc *);
+ void (*unk260)(struct nvkm_mc *, u32);
+};
+
+void gf100_mc_unk260(struct nvkm_mc *, u32);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
new file mode 100644
index 000000000000..012c9db687b2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/Kbuild
@@ -0,0 +1,6 @@
+nvkm-y += nvkm/subdev/mmu/base.o
+nvkm-y += nvkm/subdev/mmu/nv04.o
+nvkm-y += nvkm/subdev/mmu/nv41.o
+nvkm-y += nvkm/subdev/mmu/nv44.o
+nvkm-y += nvkm/subdev/mmu/nv50.o
+nvkm-y += nvkm/subdev/mmu/gf100.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
new file mode 100644
index 000000000000..277b6ec04e24
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/base.c
@@ -0,0 +1,480 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/mmu.h>
+#include <subdev/fb.h>
+
+#include <core/gpuobj.h>
+
+void
+nvkm_vm_map_at(struct nvkm_vma *vma, u64 delta, struct nvkm_mem *node)
+{
+ struct nvkm_vm *vm = vma->vm;
+ struct nvkm_mmu *mmu = vm->mmu;
+ struct nvkm_mm_node *r;
+ int big = vma->node->type != mmu->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 pde = (offset >> mmu->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (mmu->pgt_bits - bits);
+ u32 end, len;
+
+ delta = 0;
+ list_for_each_entry(r, &node->regions, rl_entry) {
+ u64 phys = (u64)r->offset << 12;
+ u32 num = r->length >> bits;
+
+ while (num) {
+ struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+ end = (pte + num);
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ mmu->map(vma, pgt, node, pte, len, phys, delta);
+
+ num -= len;
+ pte += len;
+ if (unlikely(end >= max)) {
+ phys += len << (bits + 12);
+ pde++;
+ pte = 0;
+ }
+
+ delta += (u64)len << vma->node->type;
+ }
+ }
+
+ mmu->flush(vm);
+}
+
+static void
+nvkm_vm_map_sg_table(struct nvkm_vma *vma, u64 delta, u64 length,
+ struct nvkm_mem *mem)
+{
+ struct nvkm_vm *vm = vma->vm;
+ struct nvkm_mmu *mmu = vm->mmu;
+ int big = vma->node->type != mmu->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 num = length >> vma->node->type;
+ u32 pde = (offset >> mmu->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (mmu->pgt_bits - bits);
+ unsigned m, sglen;
+ u32 end, len;
+ int i;
+ struct scatterlist *sg;
+
+ for_each_sg(mem->sg->sgl, sg, mem->sg->nents, i) {
+ struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+ sglen = sg_dma_len(sg) >> PAGE_SHIFT;
+
+ end = pte + sglen;
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ for (m = 0; m < len; m++) {
+ dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+
+ mmu->map_sg(vma, pgt, mem, pte, 1, &addr);
+ num--;
+ pte++;
+
+ if (num == 0)
+ goto finish;
+ }
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ if (m < sglen) {
+ for (; m < sglen; m++) {
+ dma_addr_t addr = sg_dma_address(sg) + (m << PAGE_SHIFT);
+
+ mmu->map_sg(vma, pgt, mem, pte, 1, &addr);
+ num--;
+ pte++;
+ if (num == 0)
+ goto finish;
+ }
+ }
+
+ }
+finish:
+ mmu->flush(vm);
+}
+
+static void
+nvkm_vm_map_sg(struct nvkm_vma *vma, u64 delta, u64 length,
+ struct nvkm_mem *mem)
+{
+ struct nvkm_vm *vm = vma->vm;
+ struct nvkm_mmu *mmu = vm->mmu;
+ dma_addr_t *list = mem->pages;
+ int big = vma->node->type != mmu->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 num = length >> vma->node->type;
+ u32 pde = (offset >> mmu->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (mmu->pgt_bits - bits);
+ u32 end, len;
+
+ while (num) {
+ struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+ end = (pte + num);
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ mmu->map_sg(vma, pgt, mem, pte, len, list);
+
+ num -= len;
+ pte += len;
+ list += len;
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ }
+
+ mmu->flush(vm);
+}
+
+void
+nvkm_vm_map(struct nvkm_vma *vma, struct nvkm_mem *node)
+{
+ if (node->sg)
+ nvkm_vm_map_sg_table(vma, 0, node->size << 12, node);
+ else
+ if (node->pages)
+ nvkm_vm_map_sg(vma, 0, node->size << 12, node);
+ else
+ nvkm_vm_map_at(vma, 0, node);
+}
+
+void
+nvkm_vm_unmap_at(struct nvkm_vma *vma, u64 delta, u64 length)
+{
+ struct nvkm_vm *vm = vma->vm;
+ struct nvkm_mmu *mmu = vm->mmu;
+ int big = vma->node->type != mmu->spg_shift;
+ u32 offset = vma->node->offset + (delta >> 12);
+ u32 bits = vma->node->type - 12;
+ u32 num = length >> vma->node->type;
+ u32 pde = (offset >> mmu->pgt_bits) - vm->fpde;
+ u32 pte = (offset & ((1 << mmu->pgt_bits) - 1)) >> bits;
+ u32 max = 1 << (mmu->pgt_bits - bits);
+ u32 end, len;
+
+ while (num) {
+ struct nvkm_gpuobj *pgt = vm->pgt[pde].obj[big];
+
+ end = (pte + num);
+ if (unlikely(end >= max))
+ end = max;
+ len = end - pte;
+
+ mmu->unmap(pgt, pte, len);
+
+ num -= len;
+ pte += len;
+ if (unlikely(end >= max)) {
+ pde++;
+ pte = 0;
+ }
+ }
+
+ mmu->flush(vm);
+}
+
+void
+nvkm_vm_unmap(struct nvkm_vma *vma)
+{
+ nvkm_vm_unmap_at(vma, 0, (u64)vma->node->length << 12);
+}
+
+static void
+nvkm_vm_unmap_pgt(struct nvkm_vm *vm, int big, u32 fpde, u32 lpde)
+{
+ struct nvkm_mmu *mmu = vm->mmu;
+ struct nvkm_vm_pgd *vpgd;
+ struct nvkm_vm_pgt *vpgt;
+ struct nvkm_gpuobj *pgt;
+ u32 pde;
+
+ for (pde = fpde; pde <= lpde; pde++) {
+ vpgt = &vm->pgt[pde - vm->fpde];
+ if (--vpgt->refcount[big])
+ continue;
+
+ pgt = vpgt->obj[big];
+ vpgt->obj[big] = NULL;
+
+ list_for_each_entry(vpgd, &vm->pgd_list, head) {
+ mmu->map_pgt(vpgd->obj, pde, vpgt->obj);
+ }
+
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+ nvkm_gpuobj_ref(NULL, &pgt);
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ }
+}
+
+static int
+nvkm_vm_map_pgt(struct nvkm_vm *vm, u32 pde, u32 type)
+{
+ struct nvkm_mmu *mmu = vm->mmu;
+ struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
+ struct nvkm_vm_pgd *vpgd;
+ struct nvkm_gpuobj *pgt;
+ int big = (type != mmu->spg_shift);
+ u32 pgt_size;
+ int ret;
+
+ pgt_size = (1 << (mmu->pgt_bits + 12)) >> type;
+ pgt_size *= 8;
+
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+ ret = nvkm_gpuobj_new(nv_object(vm->mmu), NULL, pgt_size, 0x1000,
+ NVOBJ_FLAG_ZERO_ALLOC, &pgt);
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ if (unlikely(ret))
+ return ret;
+
+ /* someone beat us to filling the PDE while we didn't have the lock */
+ if (unlikely(vpgt->refcount[big]++)) {
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+ nvkm_gpuobj_ref(NULL, &pgt);
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ return 0;
+ }
+
+ vpgt->obj[big] = pgt;
+ list_for_each_entry(vpgd, &vm->pgd_list, head) {
+ mmu->map_pgt(vpgd->obj, pde, vpgt->obj);
+ }
+
+ return 0;
+}
+
+int
+nvkm_vm_get(struct nvkm_vm *vm, u64 size, u32 page_shift, u32 access,
+ struct nvkm_vma *vma)
+{
+ struct nvkm_mmu *mmu = vm->mmu;
+ u32 align = (1 << page_shift) >> 12;
+ u32 msize = size >> 12;
+ u32 fpde, lpde, pde;
+ int ret;
+
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ ret = nvkm_mm_head(&vm->mm, 0, page_shift, msize, msize, align,
+ &vma->node);
+ if (unlikely(ret != 0)) {
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+ return ret;
+ }
+
+ fpde = (vma->node->offset >> mmu->pgt_bits);
+ lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits;
+
+ for (pde = fpde; pde <= lpde; pde++) {
+ struct nvkm_vm_pgt *vpgt = &vm->pgt[pde - vm->fpde];
+ int big = (vma->node->type != mmu->spg_shift);
+
+ if (likely(vpgt->refcount[big])) {
+ vpgt->refcount[big]++;
+ continue;
+ }
+
+ ret = nvkm_vm_map_pgt(vm, pde, vma->node->type);
+ if (ret) {
+ if (pde != fpde)
+ nvkm_vm_unmap_pgt(vm, big, fpde, pde - 1);
+ nvkm_mm_free(&vm->mm, &vma->node);
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+ return ret;
+ }
+ }
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+
+ vma->vm = NULL;
+ nvkm_vm_ref(vm, &vma->vm, NULL);
+ vma->offset = (u64)vma->node->offset << 12;
+ vma->access = access;
+ return 0;
+}
+
+void
+nvkm_vm_put(struct nvkm_vma *vma)
+{
+ struct nvkm_vm *vm = vma->vm;
+ struct nvkm_mmu *mmu = vm->mmu;
+ u32 fpde, lpde;
+
+ if (unlikely(vma->node == NULL))
+ return;
+ fpde = (vma->node->offset >> mmu->pgt_bits);
+ lpde = (vma->node->offset + vma->node->length - 1) >> mmu->pgt_bits;
+
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ nvkm_vm_unmap_pgt(vm, vma->node->type != mmu->spg_shift, fpde, lpde);
+ nvkm_mm_free(&vm->mm, &vma->node);
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+
+ nvkm_vm_ref(NULL, &vma->vm, NULL);
+}
+
+int
+nvkm_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
+ u32 block, struct nvkm_vm **pvm)
+{
+ struct nvkm_vm *vm;
+ u64 mm_length = (offset + length) - mm_offset;
+ int ret;
+
+ vm = kzalloc(sizeof(*vm), GFP_KERNEL);
+ if (!vm)
+ return -ENOMEM;
+
+ INIT_LIST_HEAD(&vm->pgd_list);
+ vm->mmu = mmu;
+ kref_init(&vm->refcount);
+ vm->fpde = offset >> (mmu->pgt_bits + 12);
+ vm->lpde = (offset + length - 1) >> (mmu->pgt_bits + 12);
+
+ vm->pgt = vzalloc((vm->lpde - vm->fpde + 1) * sizeof(*vm->pgt));
+ if (!vm->pgt) {
+ kfree(vm);
+ return -ENOMEM;
+ }
+
+ ret = nvkm_mm_init(&vm->mm, mm_offset >> 12, mm_length >> 12,
+ block >> 12);
+ if (ret) {
+ vfree(vm->pgt);
+ kfree(vm);
+ return ret;
+ }
+
+ *pvm = vm;
+
+ return 0;
+}
+
+int
+nvkm_vm_new(struct nvkm_device *device, u64 offset, u64 length, u64 mm_offset,
+ struct nvkm_vm **pvm)
+{
+ struct nvkm_mmu *mmu = nvkm_mmu(device);
+ return mmu->create(mmu, offset, length, mm_offset, pvm);
+}
+
+static int
+nvkm_vm_link(struct nvkm_vm *vm, struct nvkm_gpuobj *pgd)
+{
+ struct nvkm_mmu *mmu = vm->mmu;
+ struct nvkm_vm_pgd *vpgd;
+ int i;
+
+ if (!pgd)
+ return 0;
+
+ vpgd = kzalloc(sizeof(*vpgd), GFP_KERNEL);
+ if (!vpgd)
+ return -ENOMEM;
+
+ nvkm_gpuobj_ref(pgd, &vpgd->obj);
+
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ for (i = vm->fpde; i <= vm->lpde; i++)
+ mmu->map_pgt(pgd, i, vm->pgt[i - vm->fpde].obj);
+ list_add(&vpgd->head, &vm->pgd_list);
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+ return 0;
+}
+
+static void
+nvkm_vm_unlink(struct nvkm_vm *vm, struct nvkm_gpuobj *mpgd)
+{
+ struct nvkm_mmu *mmu = vm->mmu;
+ struct nvkm_vm_pgd *vpgd, *tmp;
+ struct nvkm_gpuobj *pgd = NULL;
+
+ if (!mpgd)
+ return;
+
+ mutex_lock(&nv_subdev(mmu)->mutex);
+ list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+ if (vpgd->obj == mpgd) {
+ pgd = vpgd->obj;
+ list_del(&vpgd->head);
+ kfree(vpgd);
+ break;
+ }
+ }
+ mutex_unlock(&nv_subdev(mmu)->mutex);
+
+ nvkm_gpuobj_ref(NULL, &pgd);
+}
+
+static void
+nvkm_vm_del(struct kref *kref)
+{
+ struct nvkm_vm *vm = container_of(kref, typeof(*vm), refcount);
+ struct nvkm_vm_pgd *vpgd, *tmp;
+
+ list_for_each_entry_safe(vpgd, tmp, &vm->pgd_list, head) {
+ nvkm_vm_unlink(vm, vpgd->obj);
+ }
+
+ nvkm_mm_fini(&vm->mm);
+ vfree(vm->pgt);
+ kfree(vm);
+}
+
+int
+nvkm_vm_ref(struct nvkm_vm *ref, struct nvkm_vm **ptr, struct nvkm_gpuobj *pgd)
+{
+ if (ref) {
+ int ret = nvkm_vm_link(ref, pgd);
+ if (ret)
+ return ret;
+
+ kref_get(&ref->refcount);
+ }
+
+ if (*ptr) {
+ nvkm_vm_unlink(*ptr, pgd);
+ kref_put(&(*ptr)->refcount, nvkm_vm_del);
+ }
+
+ *ptr = ref;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
new file mode 100644
index 000000000000..294cda37f068
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/gf100.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/ltc.h>
+#include <subdev/timer.h>
+
+#include <core/gpuobj.h>
+
+struct gf100_mmu_priv {
+ struct nvkm_mmu base;
+};
+
+
+/* Map from compressed to corresponding uncompressed storage type.
+ * The value 0xff represents an invalid storage type.
+ */
+const u8 gf100_pte_storage_type_map[256] =
+{
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0xff, 0x01, /* 0x00 */
+ 0x01, 0x01, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff, 0x11, /* 0x10 */
+ 0x11, 0x11, 0x11, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x26, 0x27, /* 0x20 */
+ 0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x30 */
+ 0xff, 0xff, 0x26, 0x27, 0x28, 0x29, 0x26, 0x27,
+ 0x28, 0x29, 0xff, 0xff, 0xff, 0xff, 0x46, 0xff, /* 0x40 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x46, 0x46, 0x46, 0x46, 0xff, 0xff, 0xff, /* 0x50 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x60 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x70 */
+ 0xff, 0xff, 0xff, 0x7b, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x7b, 0x7b, /* 0x80 */
+ 0x7b, 0x7b, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0x90 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x8b, 0x8c, 0x8d, 0x8e, 0xa7, /* 0xa0 */
+ 0xa8, 0xa9, 0xaa, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xb0 */
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xc3, 0xff, 0xff, 0xff, 0xff, /* 0xc0 */
+ 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xc3, 0xc3,
+ 0xc3, 0xc3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, /* 0xd0 */
+ 0xfe, 0xff, 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe,
+ 0xfe, 0xff, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xff, /* 0xe0 */
+ 0xff, 0xfe, 0xff, 0xfe, 0xff, 0xfe, 0xfe, 0xff,
+ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, /* 0xf0 */
+ 0xfe, 0xfe, 0xfe, 0xfe, 0xff, 0xfd, 0xfe, 0xff
+};
+
+
+static void
+gf100_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 index, struct nvkm_gpuobj *pgt[2])
+{
+ u32 pde[2] = { 0, 0 };
+
+ if (pgt[0])
+ pde[1] = 0x00000001 | (pgt[0]->addr >> 8);
+ if (pgt[1])
+ pde[0] = 0x00000001 | (pgt[1]->addr >> 8);
+
+ nv_wo32(pgd, (index * 8) + 0, pde[0]);
+ nv_wo32(pgd, (index * 8) + 4, pde[1]);
+}
+
+static inline u64
+gf100_vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target)
+{
+ phys >>= 8;
+
+ phys |= 0x00000001; /* present */
+ if (vma->access & NV_MEM_ACCESS_SYS)
+ phys |= 0x00000002;
+
+ phys |= ((u64)target << 32);
+ phys |= ((u64)memtype << 36);
+ return phys;
+}
+
+static void
+gf100_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
+{
+ u64 next = 1 << (vma->node->type - 8);
+
+ phys = gf100_vm_addr(vma, phys, mem->memtype, 0);
+ pte <<= 3;
+
+ if (mem->tag) {
+ struct nvkm_ltc *ltc = nvkm_ltc(vma->vm->mmu);
+ u32 tag = mem->tag->offset + (delta >> 17);
+ phys |= (u64)tag << (32 + 12);
+ next |= (u64)1 << (32 + 12);
+ ltc->tags_clear(ltc, tag, cnt);
+ }
+
+ while (cnt--) {
+ nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+ nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+ phys += next;
+ pte += 8;
+ }
+}
+
+static void
+gf100_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+ u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 7 : 5;
+ /* compressed storage types are invalid for system memory */
+ u32 memtype = gf100_pte_storage_type_map[mem->memtype & 0xff];
+
+ pte <<= 3;
+ while (cnt--) {
+ u64 phys = gf100_vm_addr(vma, *list++, memtype, target);
+ nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+ nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+ pte += 8;
+ }
+}
+
+static void
+gf100_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ pte <<= 3;
+ while (cnt--) {
+ nv_wo32(pgt, pte + 0, 0x00000000);
+ nv_wo32(pgt, pte + 4, 0x00000000);
+ pte += 8;
+ }
+}
+
+static void
+gf100_vm_flush(struct nvkm_vm *vm)
+{
+ struct gf100_mmu_priv *priv = (void *)vm->mmu;
+ struct nvkm_bar *bar = nvkm_bar(priv);
+ struct nvkm_vm_pgd *vpgd;
+ u32 type;
+
+ bar->flush(bar);
+
+ type = 0x00000001; /* PAGE_ALL */
+ if (atomic_read(&vm->engref[NVDEV_SUBDEV_BAR]))
+ type |= 0x00000004; /* HUB_ONLY */
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ list_for_each_entry(vpgd, &vm->pgd_list, head) {
+ /* looks like maybe a "free flush slots" counter, the
+ * faster you write to 0x100cbc to more it decreases
+ */
+ if (!nv_wait_ne(priv, 0x100c80, 0x00ff0000, 0x00000000)) {
+ nv_error(priv, "vm timeout 0: 0x%08x %d\n",
+ nv_rd32(priv, 0x100c80), type);
+ }
+
+ nv_wr32(priv, 0x100cb8, vpgd->obj->addr >> 8);
+ nv_wr32(priv, 0x100cbc, 0x80000000 | type);
+
+ /* wait for flush to be queued? */
+ if (!nv_wait(priv, 0x100c80, 0x00008000, 0x00008000)) {
+ nv_error(priv, "vm timeout 1: 0x%08x %d\n",
+ nv_rd32(priv, 0x100c80), type);
+ }
+ }
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+gf100_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mm_offset,
+ struct nvkm_vm **pvm)
+{
+ return nvkm_vm_create(mmu, offset, length, mm_offset, 4096, pvm);
+}
+
+static int
+gf100_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf100_mmu_priv *priv;
+ int ret;
+
+ ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.limit = 1ULL << 40;
+ priv->base.dma_bits = 40;
+ priv->base.pgt_bits = 27 - 12;
+ priv->base.spg_shift = 12;
+ priv->base.lpg_shift = 17;
+ priv->base.create = gf100_vm_create;
+ priv->base.map_pgt = gf100_vm_map_pgt;
+ priv->base.map = gf100_vm_map;
+ priv->base.map_sg = gf100_vm_map_sg;
+ priv->base.unmap = gf100_vm_unmap;
+ priv->base.flush = gf100_vm_flush;
+ return 0;
+}
+
+struct nvkm_oclass
+gf100_mmu_oclass = {
+ .handle = NV_SUBDEV(MMU, 0xc0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf100_mmu_ctor,
+ .dtor = _nvkm_mmu_dtor,
+ .init = _nvkm_mmu_init,
+ .fini = _nvkm_mmu_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c
new file mode 100644
index 000000000000..fe93ea2711c9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+
+#define NV04_PDMA_SIZE (128 * 1024 * 1024)
+#define NV04_PDMA_PAGE ( 4 * 1024)
+
+/*******************************************************************************
+ * VM map/unmap callbacks
+ ******************************************************************************/
+
+static void
+nv04_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+ pte = 0x00008 + (pte * 4);
+ while (cnt) {
+ u32 page = PAGE_SIZE / NV04_PDMA_PAGE;
+ u32 phys = (u32)*list++;
+ while (cnt && page--) {
+ nv_wo32(pgt, pte, phys | 3);
+ phys += NV04_PDMA_PAGE;
+ pte += 4;
+ cnt -= 1;
+ }
+ }
+}
+
+static void
+nv04_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ pte = 0x00008 + (pte * 4);
+ while (cnt--) {
+ nv_wo32(pgt, pte, 0x00000000);
+ pte += 4;
+ }
+}
+
+static void
+nv04_vm_flush(struct nvkm_vm *vm)
+{
+}
+
+/*******************************************************************************
+ * VM object
+ ******************************************************************************/
+
+int
+nv04_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length, u64 mmstart,
+ struct nvkm_vm **pvm)
+{
+ return -EINVAL;
+}
+
+/*******************************************************************************
+ * MMU subdev
+ ******************************************************************************/
+
+static int
+nv04_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_mmu_priv *priv;
+ struct nvkm_gpuobj *dma;
+ int ret;
+
+ ret = nvkm_mmu_create(parent, engine, oclass, "PCIGART",
+ "pcigart", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.create = nv04_vm_create;
+ priv->base.limit = NV04_PDMA_SIZE;
+ priv->base.dma_bits = 32;
+ priv->base.pgt_bits = 32 - 12;
+ priv->base.spg_shift = 12;
+ priv->base.lpg_shift = 12;
+ priv->base.map_sg = nv04_vm_map_sg;
+ priv->base.unmap = nv04_vm_unmap;
+ priv->base.flush = nv04_vm_flush;
+
+ ret = nvkm_vm_create(&priv->base, 0, NV04_PDMA_SIZE, 0, 4096,
+ &priv->vm);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+ (NV04_PDMA_SIZE / NV04_PDMA_PAGE) * 4 + 8,
+ 16, NVOBJ_FLAG_ZERO_ALLOC,
+ &priv->vm->pgt[0].obj[0]);
+ dma = priv->vm->pgt[0].obj[0];
+ priv->vm->pgt[0].refcount[0] = 1;
+ if (ret)
+ return ret;
+
+ nv_wo32(dma, 0x00000, 0x0002103d); /* PCI, RW, PT, !LN */
+ nv_wo32(dma, 0x00004, NV04_PDMA_SIZE - 1);
+ return 0;
+}
+
+void
+nv04_mmu_dtor(struct nvkm_object *object)
+{
+ struct nv04_mmu_priv *priv = (void *)object;
+ if (priv->vm) {
+ nvkm_gpuobj_ref(NULL, &priv->vm->pgt[0].obj[0]);
+ nvkm_vm_ref(NULL, &priv->vm, NULL);
+ }
+ if (priv->nullp) {
+ pci_free_consistent(nv_device(priv)->pdev, 16 * 1024,
+ priv->nullp, priv->null);
+ }
+ nvkm_mmu_destroy(&priv->base);
+}
+
+struct nvkm_oclass
+nv04_mmu_oclass = {
+ .handle = NV_SUBDEV(MMU, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_mmu_ctor,
+ .dtor = nv04_mmu_dtor,
+ .init = _nvkm_mmu_init,
+ .fini = _nvkm_mmu_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h
new file mode 100644
index 000000000000..7bf6f4b38f1d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv04.h
@@ -0,0 +1,19 @@
+#ifndef __NV04_MMU_PRIV__
+#define __NV04_MMU_PRIV__
+
+#include <subdev/mmu.h>
+
+struct nv04_mmu_priv {
+ struct nvkm_mmu base;
+ struct nvkm_vm *vm;
+ dma_addr_t null;
+ void *nullp;
+};
+
+static inline struct nv04_mmu_priv *
+nv04_mmu(void *obj)
+{
+ return (void *)nvkm_mmu(obj);
+}
+
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c
new file mode 100644
index 000000000000..61ee3ab11660
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv41.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <core/option.h>
+#include <subdev/timer.h>
+
+#define NV41_GART_SIZE (512 * 1024 * 1024)
+#define NV41_GART_PAGE ( 4 * 1024)
+
+/*******************************************************************************
+ * VM map/unmap callbacks
+ ******************************************************************************/
+
+static void
+nv41_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+ pte = pte * 4;
+ while (cnt) {
+ u32 page = PAGE_SIZE / NV41_GART_PAGE;
+ u64 phys = (u64)*list++;
+ while (cnt && page--) {
+ nv_wo32(pgt, pte, (phys >> 7) | 1);
+ phys += NV41_GART_PAGE;
+ pte += 4;
+ cnt -= 1;
+ }
+ }
+}
+
+static void
+nv41_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ pte = pte * 4;
+ while (cnt--) {
+ nv_wo32(pgt, pte, 0x00000000);
+ pte += 4;
+ }
+}
+
+static void
+nv41_vm_flush(struct nvkm_vm *vm)
+{
+ struct nv04_mmu_priv *priv = (void *)vm->mmu;
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ nv_wr32(priv, 0x100810, 0x00000022);
+ if (!nv_wait(priv, 0x100810, 0x00000020, 0x00000020)) {
+ nv_warn(priv, "flush timeout, 0x%08x\n",
+ nv_rd32(priv, 0x100810));
+ }
+ nv_wr32(priv, 0x100810, 0x00000000);
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+/*******************************************************************************
+ * MMU subdev
+ ******************************************************************************/
+
+static int
+nv41_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nv04_mmu_priv *priv;
+ int ret;
+
+ if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
+ !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) {
+ return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass,
+ data, size, pobject);
+ }
+
+ ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART",
+ "pciegart", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.create = nv04_vm_create;
+ priv->base.limit = NV41_GART_SIZE;
+ priv->base.dma_bits = 39;
+ priv->base.pgt_bits = 32 - 12;
+ priv->base.spg_shift = 12;
+ priv->base.lpg_shift = 12;
+ priv->base.map_sg = nv41_vm_map_sg;
+ priv->base.unmap = nv41_vm_unmap;
+ priv->base.flush = nv41_vm_flush;
+
+ ret = nvkm_vm_create(&priv->base, 0, NV41_GART_SIZE, 0, 4096,
+ &priv->vm);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+ (NV41_GART_SIZE / NV41_GART_PAGE) * 4, 16,
+ NVOBJ_FLAG_ZERO_ALLOC,
+ &priv->vm->pgt[0].obj[0]);
+ priv->vm->pgt[0].refcount[0] = 1;
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv41_mmu_init(struct nvkm_object *object)
+{
+ struct nv04_mmu_priv *priv = (void *)object;
+ struct nvkm_gpuobj *dma = priv->vm->pgt[0].obj[0];
+ int ret;
+
+ ret = nvkm_mmu_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_wr32(priv, 0x100800, dma->addr | 0x00000002);
+ nv_mask(priv, 0x10008c, 0x00000100, 0x00000100);
+ nv_wr32(priv, 0x100820, 0x00000000);
+ return 0;
+}
+
+struct nvkm_oclass
+nv41_mmu_oclass = {
+ .handle = NV_SUBDEV(MMU, 0x41),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv41_mmu_ctor,
+ .dtor = nv04_mmu_dtor,
+ .init = nv41_mmu_init,
+ .fini = _nvkm_mmu_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c
new file mode 100644
index 000000000000..b90ded1887aa
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv44.c
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+#include <core/gpuobj.h>
+#include <core/option.h>
+#include <subdev/timer.h>
+
+#define NV44_GART_SIZE (512 * 1024 * 1024)
+#define NV44_GART_PAGE ( 4 * 1024)
+
+/*******************************************************************************
+ * VM map/unmap callbacks
+ ******************************************************************************/
+
+static void
+nv44_vm_fill(struct nvkm_gpuobj *pgt, dma_addr_t null,
+ dma_addr_t *list, u32 pte, u32 cnt)
+{
+ u32 base = (pte << 2) & ~0x0000000f;
+ u32 tmp[4];
+
+ tmp[0] = nv_ro32(pgt, base + 0x0);
+ tmp[1] = nv_ro32(pgt, base + 0x4);
+ tmp[2] = nv_ro32(pgt, base + 0x8);
+ tmp[3] = nv_ro32(pgt, base + 0xc);
+
+ while (cnt--) {
+ u32 addr = list ? (*list++ >> 12) : (null >> 12);
+ switch (pte++ & 0x3) {
+ case 0:
+ tmp[0] &= ~0x07ffffff;
+ tmp[0] |= addr;
+ break;
+ case 1:
+ tmp[0] &= ~0xf8000000;
+ tmp[0] |= addr << 27;
+ tmp[1] &= ~0x003fffff;
+ tmp[1] |= addr >> 5;
+ break;
+ case 2:
+ tmp[1] &= ~0xffc00000;
+ tmp[1] |= addr << 22;
+ tmp[2] &= ~0x0001ffff;
+ tmp[2] |= addr >> 10;
+ break;
+ case 3:
+ tmp[2] &= ~0xfffe0000;
+ tmp[2] |= addr << 17;
+ tmp[3] &= ~0x00000fff;
+ tmp[3] |= addr >> 15;
+ break;
+ }
+ }
+
+ nv_wo32(pgt, base + 0x0, tmp[0]);
+ nv_wo32(pgt, base + 0x4, tmp[1]);
+ nv_wo32(pgt, base + 0x8, tmp[2]);
+ nv_wo32(pgt, base + 0xc, tmp[3] | 0x40000000);
+}
+
+static void
+nv44_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+ struct nv04_mmu_priv *priv = (void *)vma->vm->mmu;
+ u32 tmp[4];
+ int i;
+
+ if (pte & 3) {
+ u32 max = 4 - (pte & 3);
+ u32 part = (cnt > max) ? max : cnt;
+ nv44_vm_fill(pgt, priv->null, list, pte, part);
+ pte += part;
+ list += part;
+ cnt -= part;
+ }
+
+ while (cnt >= 4) {
+ for (i = 0; i < 4; i++)
+ tmp[i] = *list++ >> 12;
+ nv_wo32(pgt, pte++ * 4, tmp[0] >> 0 | tmp[1] << 27);
+ nv_wo32(pgt, pte++ * 4, tmp[1] >> 5 | tmp[2] << 22);
+ nv_wo32(pgt, pte++ * 4, tmp[2] >> 10 | tmp[3] << 17);
+ nv_wo32(pgt, pte++ * 4, tmp[3] >> 15 | 0x40000000);
+ cnt -= 4;
+ }
+
+ if (cnt)
+ nv44_vm_fill(pgt, priv->null, list, pte, cnt);
+}
+
+static void
+nv44_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ struct nv04_mmu_priv *priv = (void *)nvkm_mmu(pgt);
+
+ if (pte & 3) {
+ u32 max = 4 - (pte & 3);
+ u32 part = (cnt > max) ? max : cnt;
+ nv44_vm_fill(pgt, priv->null, NULL, pte, part);
+ pte += part;
+ cnt -= part;
+ }
+
+ while (cnt >= 4) {
+ nv_wo32(pgt, pte++ * 4, 0x00000000);
+ nv_wo32(pgt, pte++ * 4, 0x00000000);
+ nv_wo32(pgt, pte++ * 4, 0x00000000);
+ nv_wo32(pgt, pte++ * 4, 0x00000000);
+ cnt -= 4;
+ }
+
+ if (cnt)
+ nv44_vm_fill(pgt, priv->null, NULL, pte, cnt);
+}
+
+static void
+nv44_vm_flush(struct nvkm_vm *vm)
+{
+ struct nv04_mmu_priv *priv = (void *)vm->mmu;
+ nv_wr32(priv, 0x100814, priv->base.limit - NV44_GART_PAGE);
+ nv_wr32(priv, 0x100808, 0x00000020);
+ if (!nv_wait(priv, 0x100808, 0x00000001, 0x00000001))
+ nv_error(priv, "timeout: 0x%08x\n", nv_rd32(priv, 0x100808));
+ nv_wr32(priv, 0x100808, 0x00000000);
+}
+
+/*******************************************************************************
+ * MMU subdev
+ ******************************************************************************/
+
+static int
+nv44_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nv04_mmu_priv *priv;
+ int ret;
+
+ if (pci_find_capability(device->pdev, PCI_CAP_ID_AGP) ||
+ !nvkm_boolopt(device->cfgopt, "NvPCIE", true)) {
+ return nvkm_object_ctor(parent, engine, &nv04_mmu_oclass,
+ data, size, pobject);
+ }
+
+ ret = nvkm_mmu_create(parent, engine, oclass, "PCIEGART",
+ "pciegart", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.create = nv04_vm_create;
+ priv->base.limit = NV44_GART_SIZE;
+ priv->base.dma_bits = 39;
+ priv->base.pgt_bits = 32 - 12;
+ priv->base.spg_shift = 12;
+ priv->base.lpg_shift = 12;
+ priv->base.map_sg = nv44_vm_map_sg;
+ priv->base.unmap = nv44_vm_unmap;
+ priv->base.flush = nv44_vm_flush;
+
+ priv->nullp = pci_alloc_consistent(device->pdev, 16 * 1024, &priv->null);
+ if (!priv->nullp) {
+ nv_error(priv, "unable to allocate dummy pages\n");
+ return -ENOMEM;
+ }
+
+ ret = nvkm_vm_create(&priv->base, 0, NV44_GART_SIZE, 0, 4096,
+ &priv->vm);
+ if (ret)
+ return ret;
+
+ ret = nvkm_gpuobj_new(nv_object(priv), NULL,
+ (NV44_GART_SIZE / NV44_GART_PAGE) * 4,
+ 512 * 1024, NVOBJ_FLAG_ZERO_ALLOC,
+ &priv->vm->pgt[0].obj[0]);
+ priv->vm->pgt[0].refcount[0] = 1;
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int
+nv44_mmu_init(struct nvkm_object *object)
+{
+ struct nv04_mmu_priv *priv = (void *)object;
+ struct nvkm_gpuobj *gart = priv->vm->pgt[0].obj[0];
+ u32 addr;
+ int ret;
+
+ ret = nvkm_mmu_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* calculate vram address of this PRAMIN block, object must be
+ * allocated on 512KiB alignment, and not exceed a total size
+ * of 512KiB for this to work correctly
+ */
+ addr = nv_rd32(priv, 0x10020c);
+ addr -= ((gart->addr >> 19) + 1) << 19;
+
+ nv_wr32(priv, 0x100850, 0x80000000);
+ nv_wr32(priv, 0x100818, priv->null);
+ nv_wr32(priv, 0x100804, NV44_GART_SIZE);
+ nv_wr32(priv, 0x100850, 0x00008000);
+ nv_mask(priv, 0x10008c, 0x00000200, 0x00000200);
+ nv_wr32(priv, 0x100820, 0x00000000);
+ nv_wr32(priv, 0x10082c, 0x00000001);
+ nv_wr32(priv, 0x100800, addr | 0x00000010);
+ return 0;
+}
+
+struct nvkm_oclass
+nv44_mmu_oclass = {
+ .handle = NV_SUBDEV(MMU, 0x44),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv44_mmu_ctor,
+ .dtor = nv04_mmu_dtor,
+ .init = nv44_mmu_init,
+ .fini = _nvkm_mmu_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
new file mode 100644
index 000000000000..b83550fa7f96
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mmu/nv50.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2010 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/mmu.h>
+#include <subdev/bar.h>
+#include <subdev/fb.h>
+#include <subdev/timer.h>
+
+#include <core/engine.h>
+#include <core/gpuobj.h>
+
+struct nv50_mmu_priv {
+ struct nvkm_mmu base;
+};
+
+static void
+nv50_vm_map_pgt(struct nvkm_gpuobj *pgd, u32 pde, struct nvkm_gpuobj *pgt[2])
+{
+ u64 phys = 0xdeadcafe00000000ULL;
+ u32 coverage = 0;
+
+ if (pgt[0]) {
+ phys = 0x00000003 | pgt[0]->addr; /* present, 4KiB pages */
+ coverage = (pgt[0]->size >> 3) << 12;
+ } else
+ if (pgt[1]) {
+ phys = 0x00000001 | pgt[1]->addr; /* present */
+ coverage = (pgt[1]->size >> 3) << 16;
+ }
+
+ if (phys & 1) {
+ if (coverage <= 32 * 1024 * 1024)
+ phys |= 0x60;
+ else if (coverage <= 64 * 1024 * 1024)
+ phys |= 0x40;
+ else if (coverage <= 128 * 1024 * 1024)
+ phys |= 0x20;
+ }
+
+ nv_wo32(pgd, (pde * 8) + 0, lower_32_bits(phys));
+ nv_wo32(pgd, (pde * 8) + 4, upper_32_bits(phys));
+}
+
+static inline u64
+vm_addr(struct nvkm_vma *vma, u64 phys, u32 memtype, u32 target)
+{
+ phys |= 1; /* present */
+ phys |= (u64)memtype << 40;
+ phys |= target << 4;
+ if (vma->access & NV_MEM_ACCESS_SYS)
+ phys |= (1 << 6);
+ if (!(vma->access & NV_MEM_ACCESS_WO))
+ phys |= (1 << 3);
+ return phys;
+}
+
+static void
+nv50_vm_map(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, u64 phys, u64 delta)
+{
+ u32 comp = (mem->memtype & 0x180) >> 7;
+ u32 block, target;
+ int i;
+
+ /* IGPs don't have real VRAM, re-target to stolen system memory */
+ target = 0;
+ if (nvkm_fb(vma->vm->mmu)->ram->stolen) {
+ phys += nvkm_fb(vma->vm->mmu)->ram->stolen;
+ target = 3;
+ }
+
+ phys = vm_addr(vma, phys, mem->memtype, target);
+ pte <<= 3;
+ cnt <<= 3;
+
+ while (cnt) {
+ u32 offset_h = upper_32_bits(phys);
+ u32 offset_l = lower_32_bits(phys);
+
+ for (i = 7; i >= 0; i--) {
+ block = 1 << (i + 3);
+ if (cnt >= block && !(pte & (block - 1)))
+ break;
+ }
+ offset_l |= (i << 7);
+
+ phys += block << (vma->node->type - 3);
+ cnt -= block;
+ if (comp) {
+ u32 tag = mem->tag->offset + ((delta >> 16) * comp);
+ offset_h |= (tag << 17);
+ delta += block << (vma->node->type - 3);
+ }
+
+ while (block) {
+ nv_wo32(pgt, pte + 0, offset_l);
+ nv_wo32(pgt, pte + 4, offset_h);
+ pte += 8;
+ block -= 8;
+ }
+ }
+}
+
+static void
+nv50_vm_map_sg(struct nvkm_vma *vma, struct nvkm_gpuobj *pgt,
+ struct nvkm_mem *mem, u32 pte, u32 cnt, dma_addr_t *list)
+{
+ u32 target = (vma->access & NV_MEM_ACCESS_NOSNOOP) ? 3 : 2;
+ pte <<= 3;
+ while (cnt--) {
+ u64 phys = vm_addr(vma, (u64)*list++, mem->memtype, target);
+ nv_wo32(pgt, pte + 0, lower_32_bits(phys));
+ nv_wo32(pgt, pte + 4, upper_32_bits(phys));
+ pte += 8;
+ }
+}
+
+static void
+nv50_vm_unmap(struct nvkm_gpuobj *pgt, u32 pte, u32 cnt)
+{
+ pte <<= 3;
+ while (cnt--) {
+ nv_wo32(pgt, pte + 0, 0x00000000);
+ nv_wo32(pgt, pte + 4, 0x00000000);
+ pte += 8;
+ }
+}
+
+static void
+nv50_vm_flush(struct nvkm_vm *vm)
+{
+ struct nv50_mmu_priv *priv = (void *)vm->mmu;
+ struct nvkm_bar *bar = nvkm_bar(priv);
+ struct nvkm_engine *engine;
+ int i, vme;
+
+ bar->flush(bar);
+
+ mutex_lock(&nv_subdev(priv)->mutex);
+ for (i = 0; i < NVDEV_SUBDEV_NR; i++) {
+ if (!atomic_read(&vm->engref[i]))
+ continue;
+
+ /* unfortunate hw bug workaround... */
+ engine = nvkm_engine(priv, i);
+ if (engine && engine->tlb_flush) {
+ engine->tlb_flush(engine);
+ continue;
+ }
+
+ switch (i) {
+ case NVDEV_ENGINE_GR : vme = 0x00; break;
+ case NVDEV_ENGINE_VP :
+ case NVDEV_ENGINE_MSPDEC: vme = 0x01; break;
+ case NVDEV_SUBDEV_BAR : vme = 0x06; break;
+ case NVDEV_ENGINE_MSPPP :
+ case NVDEV_ENGINE_MPEG : vme = 0x08; break;
+ case NVDEV_ENGINE_BSP :
+ case NVDEV_ENGINE_MSVLD : vme = 0x09; break;
+ case NVDEV_ENGINE_CIPHER:
+ case NVDEV_ENGINE_SEC : vme = 0x0a; break;
+ case NVDEV_ENGINE_CE0 : vme = 0x0d; break;
+ default:
+ continue;
+ }
+
+ nv_wr32(priv, 0x100c80, (vme << 16) | 1);
+ if (!nv_wait(priv, 0x100c80, 0x00000001, 0x00000000))
+ nv_error(priv, "vm flush timeout: engine %d\n", vme);
+ }
+ mutex_unlock(&nv_subdev(priv)->mutex);
+}
+
+static int
+nv50_vm_create(struct nvkm_mmu *mmu, u64 offset, u64 length,
+ u64 mm_offset, struct nvkm_vm **pvm)
+{
+ u32 block = (1 << (mmu->pgt_bits + 12));
+ if (block > length)
+ block = length;
+
+ return nvkm_vm_create(mmu, offset, length, mm_offset, block, pvm);
+}
+
+static int
+nv50_mmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_mmu_priv *priv;
+ int ret;
+
+ ret = nvkm_mmu_create(parent, engine, oclass, "VM", "vm", &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.limit = 1ULL << 40;
+ priv->base.dma_bits = 40;
+ priv->base.pgt_bits = 29 - 12;
+ priv->base.spg_shift = 12;
+ priv->base.lpg_shift = 16;
+ priv->base.create = nv50_vm_create;
+ priv->base.map_pgt = nv50_vm_map_pgt;
+ priv->base.map = nv50_vm_map;
+ priv->base.map_sg = nv50_vm_map_sg;
+ priv->base.unmap = nv50_vm_unmap;
+ priv->base.flush = nv50_vm_flush;
+ return 0;
+}
+
+struct nvkm_oclass
+nv50_mmu_oclass = {
+ .handle = NV_SUBDEV(MMU, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_mmu_ctor,
+ .dtor = _nvkm_mmu_dtor,
+ .init = _nvkm_mmu_init,
+ .fini = _nvkm_mmu_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild
new file mode 100644
index 000000000000..1a479e050b54
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/subdev/mxm/base.o
+nvkm-y += nvkm/subdev/mxm/mxms.o
+nvkm-y += nvkm/subdev/mxm/nv50.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
new file mode 100644
index 000000000000..0ca9dcabb6d3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/base.c
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "mxms.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/mxm.h>
+#include <subdev/i2c.h>
+
+static bool
+mxm_shadow_rom_fetch(struct nvkm_i2c_port *i2c, u8 addr,
+ u8 offset, u8 size, u8 *data)
+{
+ struct i2c_msg msgs[] = {
+ { .addr = addr, .flags = 0, .len = 1, .buf = &offset },
+ { .addr = addr, .flags = I2C_M_RD, .len = size, .buf = data, },
+ };
+
+ return i2c_transfer(&i2c->adapter, msgs, 2) == 2;
+}
+
+static bool
+mxm_shadow_rom(struct nvkm_mxm *mxm, u8 version)
+{
+ struct nvkm_bios *bios = nvkm_bios(mxm);
+ struct nvkm_i2c *i2c = nvkm_i2c(mxm);
+ struct nvkm_i2c_port *port = NULL;
+ u8 i2cidx, mxms[6], addr, size;
+
+ i2cidx = mxm_ddc_map(bios, 1 /* LVDS_DDC */) & 0x0f;
+ if (i2cidx < 0x0f)
+ port = i2c->find(i2c, i2cidx);
+ if (!port)
+ return false;
+
+ addr = 0x54;
+ if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms)) {
+ addr = 0x56;
+ if (!mxm_shadow_rom_fetch(port, addr, 0, 6, mxms))
+ return false;
+ }
+
+ mxm->mxms = mxms;
+ size = mxms_headerlen(mxm) + mxms_structlen(mxm);
+ mxm->mxms = kmalloc(size, GFP_KERNEL);
+
+ if (mxm->mxms &&
+ mxm_shadow_rom_fetch(port, addr, 0, size, mxm->mxms))
+ return true;
+
+ kfree(mxm->mxms);
+ mxm->mxms = NULL;
+ return false;
+}
+
+#if defined(CONFIG_ACPI)
+static bool
+mxm_shadow_dsm(struct nvkm_mxm *mxm, u8 version)
+{
+ struct nvkm_device *device = nv_device(mxm);
+ static char muid[] = {
+ 0x00, 0xA4, 0x04, 0x40, 0x7D, 0x91, 0xF2, 0x4C,
+ 0xB8, 0x9C, 0x79, 0xB6, 0x2F, 0xD5, 0x56, 0x65
+ };
+ u32 mxms_args[] = { 0x00000000 };
+ union acpi_object argv4 = {
+ .buffer.type = ACPI_TYPE_BUFFER,
+ .buffer.length = sizeof(mxms_args),
+ .buffer.pointer = (char *)mxms_args,
+ };
+ union acpi_object *obj;
+ acpi_handle handle;
+ int rev;
+
+ handle = ACPI_HANDLE(nv_device_base(device));
+ if (!handle)
+ return false;
+
+ /*
+ * spec says this can be zero to mean "highest revision", but
+ * of course there's at least one bios out there which fails
+ * unless you pass in exactly the version it supports..
+ */
+ rev = (version & 0xf0) << 4 | (version & 0x0f);
+ obj = acpi_evaluate_dsm(handle, muid, rev, 0x00000010, &argv4);
+ if (!obj) {
+ nv_debug(mxm, "DSM MXMS failed\n");
+ return false;
+ }
+
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ mxm->mxms = kmemdup(obj->buffer.pointer,
+ obj->buffer.length, GFP_KERNEL);
+ } else if (obj->type == ACPI_TYPE_INTEGER) {
+ nv_debug(mxm, "DSM MXMS returned 0x%llx\n", obj->integer.value);
+ }
+
+ ACPI_FREE(obj);
+ return mxm->mxms != NULL;
+}
+#endif
+
+#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
+
+#define WMI_WMMX_GUID "F6CB5C3C-9CAE-4EBD-B577-931EA32A2CC0"
+
+static u8
+wmi_wmmx_mxmi(struct nvkm_mxm *mxm, u8 version)
+{
+ u32 mxmi_args[] = { 0x494D584D /* MXMI */, version, 0 };
+ struct acpi_buffer args = { sizeof(mxmi_args), mxmi_args };
+ struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+
+ status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+ if (ACPI_FAILURE(status)) {
+ nv_debug(mxm, "WMMX MXMI returned %d\n", status);
+ return 0x00;
+ }
+
+ obj = retn.pointer;
+ if (obj->type == ACPI_TYPE_INTEGER) {
+ version = obj->integer.value;
+ nv_debug(mxm, "WMMX MXMI version %d.%d\n",
+ (version >> 4), version & 0x0f);
+ } else {
+ version = 0;
+ nv_debug(mxm, "WMMX MXMI returned non-integer\n");
+ }
+
+ kfree(obj);
+ return version;
+}
+
+static bool
+mxm_shadow_wmi(struct nvkm_mxm *mxm, u8 version)
+{
+ u32 mxms_args[] = { 0x534D584D /* MXMS */, version, 0 };
+ struct acpi_buffer args = { sizeof(mxms_args), mxms_args };
+ struct acpi_buffer retn = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj;
+ acpi_status status;
+
+ if (!wmi_has_guid(WMI_WMMX_GUID)) {
+ nv_debug(mxm, "WMMX GUID not found\n");
+ return false;
+ }
+
+ mxms_args[1] = wmi_wmmx_mxmi(mxm, 0x00);
+ if (!mxms_args[1])
+ mxms_args[1] = wmi_wmmx_mxmi(mxm, version);
+ if (!mxms_args[1])
+ return false;
+
+ status = wmi_evaluate_method(WMI_WMMX_GUID, 0, 0, &args, &retn);
+ if (ACPI_FAILURE(status)) {
+ nv_debug(mxm, "WMMX MXMS returned %d\n", status);
+ return false;
+ }
+
+ obj = retn.pointer;
+ if (obj->type == ACPI_TYPE_BUFFER) {
+ mxm->mxms = kmemdup(obj->buffer.pointer,
+ obj->buffer.length, GFP_KERNEL);
+ }
+
+ kfree(obj);
+ return mxm->mxms != NULL;
+}
+#endif
+
+static struct mxm_shadow_h {
+ const char *name;
+ bool (*exec)(struct nvkm_mxm *, u8 version);
+} _mxm_shadow[] = {
+ { "ROM", mxm_shadow_rom },
+#if defined(CONFIG_ACPI)
+ { "DSM", mxm_shadow_dsm },
+#endif
+#if defined(CONFIG_ACPI_WMI) || defined(CONFIG_ACPI_WMI_MODULE)
+ { "WMI", mxm_shadow_wmi },
+#endif
+ {}
+};
+
+static int
+mxm_shadow(struct nvkm_mxm *mxm, u8 version)
+{
+ struct mxm_shadow_h *shadow = _mxm_shadow;
+ do {
+ nv_debug(mxm, "checking %s\n", shadow->name);
+ if (shadow->exec(mxm, version)) {
+ if (mxms_valid(mxm))
+ return 0;
+ kfree(mxm->mxms);
+ mxm->mxms = NULL;
+ }
+ } while ((++shadow)->name);
+ return -ENOENT;
+}
+
+int
+nvkm_mxm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_device *device = nv_device(parent);
+ struct nvkm_bios *bios = nvkm_bios(device);
+ struct nvkm_mxm *mxm;
+ u8 ver, len;
+ u16 data;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "MXM", "mxm",
+ length, pobject);
+ mxm = *pobject;
+ if (ret)
+ return ret;
+
+ data = mxm_table(bios, &ver, &len);
+ if (!data || !(ver = nv_ro08(bios, data))) {
+ nv_debug(mxm, "no VBIOS data, nothing to do\n");
+ return 0;
+ }
+
+ nv_info(mxm, "BIOS version %d.%d\n", ver >> 4, ver & 0x0f);
+
+ if (mxm_shadow(mxm, ver)) {
+ nv_info(mxm, "failed to locate valid SIS\n");
+#if 0
+ /* we should, perhaps, fall back to some kind of limited
+ * mode here if the x86 vbios hasn't already done the
+ * work for us (so we prevent loading with completely
+ * whacked vbios tables).
+ */
+ return -EINVAL;
+#else
+ return 0;
+#endif
+ }
+
+ nv_info(mxm, "MXMS Version %d.%d\n",
+ mxms_version(mxm) >> 8, mxms_version(mxm) & 0xff);
+ mxms_foreach(mxm, 0, NULL, NULL);
+
+ if (nvkm_boolopt(device->cfgopt, "NvMXMDCB", true))
+ mxm->action |= MXM_SANITISE_DCB;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
new file mode 100644
index 000000000000..a9b1d63fed58
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "mxms.h"
+
+#define ROM16(x) le16_to_cpu(*(u16 *)&(x))
+#define ROM32(x) le32_to_cpu(*(u32 *)&(x))
+
+static u8 *
+mxms_data(struct nvkm_mxm *mxm)
+{
+ return mxm->mxms;
+
+}
+
+u16
+mxms_version(struct nvkm_mxm *mxm)
+{
+ u8 *mxms = mxms_data(mxm);
+ u16 version = (mxms[4] << 8) | mxms[5];
+ switch (version ) {
+ case 0x0200:
+ case 0x0201:
+ case 0x0300:
+ return version;
+ default:
+ break;
+ }
+
+ nv_debug(mxm, "unknown version %d.%d\n", mxms[4], mxms[5]);
+ return 0x0000;
+}
+
+u16
+mxms_headerlen(struct nvkm_mxm *mxm)
+{
+ return 8;
+}
+
+u16
+mxms_structlen(struct nvkm_mxm *mxm)
+{
+ return *(u16 *)&mxms_data(mxm)[6];
+}
+
+bool
+mxms_checksum(struct nvkm_mxm *mxm)
+{
+ u16 size = mxms_headerlen(mxm) + mxms_structlen(mxm);
+ u8 *mxms = mxms_data(mxm), sum = 0;
+ while (size--)
+ sum += *mxms++;
+ if (sum) {
+ nv_debug(mxm, "checksum invalid\n");
+ return false;
+ }
+ return true;
+}
+
+bool
+mxms_valid(struct nvkm_mxm *mxm)
+{
+ u8 *mxms = mxms_data(mxm);
+ if (*(u32 *)mxms != 0x5f4d584d) {
+ nv_debug(mxm, "signature invalid\n");
+ return false;
+ }
+
+ if (!mxms_version(mxm) || !mxms_checksum(mxm))
+ return false;
+
+ return true;
+}
+
+bool
+mxms_foreach(struct nvkm_mxm *mxm, u8 types,
+ bool (*exec)(struct nvkm_mxm *, u8 *, void *), void *info)
+{
+ u8 *mxms = mxms_data(mxm);
+ u8 *desc = mxms + mxms_headerlen(mxm);
+ u8 *fini = desc + mxms_structlen(mxm) - 1;
+ while (desc < fini) {
+ u8 type = desc[0] & 0x0f;
+ u8 headerlen = 0;
+ u8 recordlen = 0;
+ u8 entries = 0;
+
+ switch (type) {
+ case 0: /* Output Device Structure */
+ if (mxms_version(mxm) >= 0x0300)
+ headerlen = 8;
+ else
+ headerlen = 6;
+ break;
+ case 1: /* System Cooling Capability Structure */
+ case 2: /* Thermal Structure */
+ case 3: /* Input Power Structure */
+ headerlen = 4;
+ break;
+ case 4: /* GPIO Device Structure */
+ headerlen = 4;
+ recordlen = 2;
+ entries = (ROM32(desc[0]) & 0x01f00000) >> 20;
+ break;
+ case 5: /* Vendor Specific Structure */
+ headerlen = 8;
+ break;
+ case 6: /* Backlight Control Structure */
+ if (mxms_version(mxm) >= 0x0300) {
+ headerlen = 4;
+ recordlen = 8;
+ entries = (desc[1] & 0xf0) >> 4;
+ } else {
+ headerlen = 8;
+ }
+ break;
+ case 7: /* Fan Control Structure */
+ headerlen = 8;
+ recordlen = 4;
+ entries = desc[1] & 0x07;
+ break;
+ default:
+ nv_debug(mxm, "unknown descriptor type %d\n", type);
+ return false;
+ }
+
+ if (nv_subdev(mxm)->debug >= NV_DBG_DEBUG && (exec == NULL)) {
+ static const char * mxms_desc_name[] = {
+ "ODS", "SCCS", "TS", "IPS",
+ "GSD", "VSS", "BCS", "FCS",
+ };
+ u8 *dump = desc;
+ int i, j;
+
+ nv_debug(mxm, "%4s: ", mxms_desc_name[type]);
+ for (j = headerlen - 1; j >= 0; j--)
+ pr_cont("%02x", dump[j]);
+ pr_cont("\n");
+ dump += headerlen;
+
+ for (i = 0; i < entries; i++, dump += recordlen) {
+ nv_debug(mxm, " ");
+ for (j = recordlen - 1; j >= 0; j--)
+ pr_cont("%02x", dump[j]);
+ pr_cont("\n");
+ }
+ }
+
+ if (types & (1 << type)) {
+ if (!exec(mxm, desc, info))
+ return false;
+ }
+
+ desc += headerlen + (entries * recordlen);
+ }
+
+ return true;
+}
+
+void
+mxms_output_device(struct nvkm_mxm *mxm, u8 *pdata, struct mxms_odev *desc)
+{
+ u64 data = ROM32(pdata[0]);
+ if (mxms_version(mxm) >= 0x0300)
+ data |= (u64)ROM16(pdata[4]) << 32;
+
+ desc->outp_type = (data & 0x00000000000000f0ULL) >> 4;
+ desc->ddc_port = (data & 0x0000000000000f00ULL) >> 8;
+ desc->conn_type = (data & 0x000000000001f000ULL) >> 12;
+ desc->dig_conn = (data & 0x0000000000780000ULL) >> 19;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h
new file mode 100644
index 000000000000..4ef804012d06
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/mxms.h
@@ -0,0 +1,22 @@
+#ifndef __NVMXM_MXMS_H__
+#define __NVMXM_MXMS_H__
+#include <subdev/mxm.h>
+
+struct mxms_odev {
+ u8 outp_type;
+ u8 conn_type;
+ u8 ddc_port;
+ u8 dig_conn;
+};
+
+void mxms_output_device(struct nvkm_mxm *, u8 *, struct mxms_odev *);
+
+u16 mxms_version(struct nvkm_mxm *);
+u16 mxms_headerlen(struct nvkm_mxm *);
+u16 mxms_structlen(struct nvkm_mxm *);
+bool mxms_checksum(struct nvkm_mxm *);
+bool mxms_valid(struct nvkm_mxm *);
+
+bool mxms_foreach(struct nvkm_mxm *, u8,
+ bool (*)(struct nvkm_mxm *, u8 *, void *), void *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c
new file mode 100644
index 000000000000..42cac13ca629
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/mxm/nv50.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright 2011 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "mxms.h"
+
+#include <subdev/bios.h>
+#include <subdev/bios/conn.h>
+#include <subdev/bios/dcb.h>
+#include <subdev/bios/mxm.h>
+
+struct nv50_mxm_priv {
+ struct nvkm_mxm base;
+};
+
+struct context {
+ u32 *outp;
+ struct mxms_odev desc;
+};
+
+static bool
+mxm_match_tmds_partner(struct nvkm_mxm *mxm, u8 *data, void *info)
+{
+ struct context *ctx = info;
+ struct mxms_odev desc;
+
+ mxms_output_device(mxm, data, &desc);
+ if (desc.outp_type == 2 &&
+ desc.dig_conn == ctx->desc.dig_conn)
+ return false;
+ return true;
+}
+
+static bool
+mxm_match_dcb(struct nvkm_mxm *mxm, u8 *data, void *info)
+{
+ struct nvkm_bios *bios = nvkm_bios(mxm);
+ struct context *ctx = info;
+ u64 desc = *(u64 *)data;
+
+ mxms_output_device(mxm, data, &ctx->desc);
+
+ /* match dcb encoder type to mxm-ods device type */
+ if ((ctx->outp[0] & 0x0000000f) != ctx->desc.outp_type)
+ return true;
+
+ /* digital output, have some extra stuff to match here, there's a
+ * table in the vbios that provides a mapping from the mxm digital
+ * connection enum values to SOR/link
+ */
+ if ((desc & 0x00000000000000f0) >= 0x20) {
+ /* check against sor index */
+ u8 link = mxm_sor_map(bios, ctx->desc.dig_conn);
+ if ((ctx->outp[0] & 0x0f000000) != (link & 0x0f) << 24)
+ return true;
+
+ /* check dcb entry has a compatible link field */
+ link = (link & 0x30) >> 4;
+ if ((link & ((ctx->outp[1] & 0x00000030) >> 4)) != link)
+ return true;
+ }
+
+ /* mark this descriptor accounted for by setting invalid device type,
+ * except of course some manufactures don't follow specs properly and
+ * we need to avoid killing off the TMDS function on DP connectors
+ * if MXM-SIS is missing an entry for it.
+ */
+ data[0] &= ~0xf0;
+ if (ctx->desc.outp_type == 6 && ctx->desc.conn_type == 6 &&
+ mxms_foreach(mxm, 0x01, mxm_match_tmds_partner, ctx)) {
+ data[0] |= 0x20; /* modify descriptor to match TMDS now */
+ } else {
+ data[0] |= 0xf0;
+ }
+
+ return false;
+}
+
+static int
+mxm_dcb_sanitise_entry(struct nvkm_bios *bios, void *data, int idx, u16 pdcb)
+{
+ struct nvkm_mxm *mxm = data;
+ struct context ctx = { .outp = (u32 *)(bios->data + pdcb) };
+ u8 type, i2cidx, link, ver, len;
+ u8 *conn;
+
+ /* look for an output device structure that matches this dcb entry.
+ * if one isn't found, disable it.
+ */
+ if (mxms_foreach(mxm, 0x01, mxm_match_dcb, &ctx)) {
+ nv_debug(mxm, "disable %d: 0x%08x 0x%08x\n",
+ idx, ctx.outp[0], ctx.outp[1]);
+ ctx.outp[0] |= 0x0000000f;
+ return 0;
+ }
+
+ /* modify the output's ddc/aux port, there's a pointer to a table
+ * with the mapping from mxm ddc/aux port to dcb i2c_index in the
+ * vbios mxm table
+ */
+ i2cidx = mxm_ddc_map(bios, ctx.desc.ddc_port);
+ if ((ctx.outp[0] & 0x0000000f) != DCB_OUTPUT_DP)
+ i2cidx = (i2cidx & 0x0f) << 4;
+ else
+ i2cidx = (i2cidx & 0xf0);
+
+ if (i2cidx != 0xf0) {
+ ctx.outp[0] &= ~0x000000f0;
+ ctx.outp[0] |= i2cidx;
+ }
+
+ /* override dcb sorconf.link, based on what mxm data says */
+ switch (ctx.desc.outp_type) {
+ case 0x00: /* Analog CRT */
+ case 0x01: /* Analog TV/HDTV */
+ break;
+ default:
+ link = mxm_sor_map(bios, ctx.desc.dig_conn) & 0x30;
+ ctx.outp[1] &= ~0x00000030;
+ ctx.outp[1] |= link;
+ break;
+ }
+
+ /* we may need to fixup various other vbios tables based on what
+ * the descriptor says the connector type should be.
+ *
+ * in a lot of cases, the vbios tables will claim DVI-I is possible,
+ * and the mxm data says the connector is really HDMI. another
+ * common example is DP->eDP.
+ */
+ conn = bios->data;
+ conn += nvbios_connEe(bios, (ctx.outp[0] & 0x0000f000) >> 12, &ver, &len);
+ type = conn[0];
+ switch (ctx.desc.conn_type) {
+ case 0x01: /* LVDS */
+ ctx.outp[1] |= 0x00000004; /* use_power_scripts */
+ /* XXX: modify default link width in LVDS table */
+ break;
+ case 0x02: /* HDMI */
+ type = DCB_CONNECTOR_HDMI_1;
+ break;
+ case 0x03: /* DVI-D */
+ type = DCB_CONNECTOR_DVI_D;
+ break;
+ case 0x0e: /* eDP, falls through to DPint */
+ ctx.outp[1] |= 0x00010000;
+ case 0x07: /* DP internal, wtf is this?? HP8670w */
+ ctx.outp[1] |= 0x00000004; /* use_power_scripts? */
+ type = DCB_CONNECTOR_eDP;
+ break;
+ default:
+ break;
+ }
+
+ if (mxms_version(mxm) >= 0x0300)
+ conn[0] = type;
+
+ return 0;
+}
+
+static bool
+mxm_show_unmatched(struct nvkm_mxm *mxm, u8 *data, void *info)
+{
+ u64 desc = *(u64 *)data;
+ if ((desc & 0xf0) != 0xf0)
+ nv_info(mxm, "unmatched output device 0x%016llx\n", desc);
+ return true;
+}
+
+static void
+mxm_dcb_sanitise(struct nvkm_mxm *mxm)
+{
+ struct nvkm_bios *bios = nvkm_bios(mxm);
+ u8 ver, hdr, cnt, len;
+ u16 dcb = dcb_table(bios, &ver, &hdr, &cnt, &len);
+ if (dcb == 0x0000 || ver != 0x40) {
+ nv_debug(mxm, "unsupported DCB version\n");
+ return;
+ }
+
+ dcb_outp_foreach(bios, mxm, mxm_dcb_sanitise_entry);
+ mxms_foreach(mxm, 0x01, mxm_show_unmatched, NULL);
+}
+
+static int
+nv50_mxm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_mxm_priv *priv;
+ int ret;
+
+ ret = nvkm_mxm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ if (priv->base.action & MXM_SANITISE_DCB)
+ mxm_dcb_sanitise(&priv->base);
+ return 0;
+}
+
+struct nvkm_oclass
+nv50_mxm_oclass = {
+ .handle = NV_SUBDEV(MXM, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_mxm_ctor,
+ .dtor = _nvkm_mxm_dtor,
+ .init = _nvkm_mxm_init,
+ .fini = _nvkm_mxm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild
new file mode 100644
index 000000000000..9a150d520225
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/Kbuild
@@ -0,0 +1,8 @@
+nvkm-y += nvkm/subdev/pmu/base.o
+nvkm-y += nvkm/subdev/pmu/memx.o
+nvkm-y += nvkm/subdev/pmu/gt215.o
+nvkm-y += nvkm/subdev/pmu/gf100.o
+nvkm-y += nvkm/subdev/pmu/gf110.o
+nvkm-y += nvkm/subdev/pmu/gk104.o
+nvkm-y += nvkm/subdev/pmu/gk208.o
+nvkm-y += nvkm/subdev/pmu/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
new file mode 100644
index 000000000000..054b2d2eec35
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/base.c
@@ -0,0 +1,268 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <subdev/timer.h>
+
+void
+nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
+{
+ const struct nvkm_pmu_impl *impl = (void *)nv_oclass(pmu);
+ if (impl->pgob)
+ impl->pgob(pmu, enable);
+}
+
+static int
+nvkm_pmu_send(struct nvkm_pmu *pmu, u32 reply[2],
+ u32 process, u32 message, u32 data0, u32 data1)
+{
+ struct nvkm_subdev *subdev = nv_subdev(pmu);
+ u32 addr;
+
+ /* wait for a free slot in the fifo */
+ addr = nv_rd32(pmu, 0x10a4a0);
+ if (!nv_wait_ne(pmu, 0x10a4b0, 0xffffffff, addr ^ 8))
+ return -EBUSY;
+
+ /* we currently only support a single process at a time waiting
+ * on a synchronous reply, take the PMU mutex and tell the
+ * receive handler what we're waiting for
+ */
+ if (reply) {
+ mutex_lock(&subdev->mutex);
+ pmu->recv.message = message;
+ pmu->recv.process = process;
+ }
+
+ /* acquire data segment access */
+ do {
+ nv_wr32(pmu, 0x10a580, 0x00000001);
+ } while (nv_rd32(pmu, 0x10a580) != 0x00000001);
+
+ /* write the packet */
+ nv_wr32(pmu, 0x10a1c0, 0x01000000 | (((addr & 0x07) << 4) +
+ pmu->send.base));
+ nv_wr32(pmu, 0x10a1c4, process);
+ nv_wr32(pmu, 0x10a1c4, message);
+ nv_wr32(pmu, 0x10a1c4, data0);
+ nv_wr32(pmu, 0x10a1c4, data1);
+ nv_wr32(pmu, 0x10a4a0, (addr + 1) & 0x0f);
+
+ /* release data segment access */
+ nv_wr32(pmu, 0x10a580, 0x00000000);
+
+ /* wait for reply, if requested */
+ if (reply) {
+ wait_event(pmu->recv.wait, (pmu->recv.process == 0));
+ reply[0] = pmu->recv.data[0];
+ reply[1] = pmu->recv.data[1];
+ mutex_unlock(&subdev->mutex);
+ }
+
+ return 0;
+}
+
+static void
+nvkm_pmu_recv(struct work_struct *work)
+{
+ struct nvkm_pmu *pmu = container_of(work, struct nvkm_pmu, recv.work);
+ u32 process, message, data0, data1;
+
+ /* nothing to do if GET == PUT */
+ u32 addr = nv_rd32(pmu, 0x10a4cc);
+ if (addr == nv_rd32(pmu, 0x10a4c8))
+ return;
+
+ /* acquire data segment access */
+ do {
+ nv_wr32(pmu, 0x10a580, 0x00000002);
+ } while (nv_rd32(pmu, 0x10a580) != 0x00000002);
+
+ /* read the packet */
+ nv_wr32(pmu, 0x10a1c0, 0x02000000 | (((addr & 0x07) << 4) +
+ pmu->recv.base));
+ process = nv_rd32(pmu, 0x10a1c4);
+ message = nv_rd32(pmu, 0x10a1c4);
+ data0 = nv_rd32(pmu, 0x10a1c4);
+ data1 = nv_rd32(pmu, 0x10a1c4);
+ nv_wr32(pmu, 0x10a4cc, (addr + 1) & 0x0f);
+
+ /* release data segment access */
+ nv_wr32(pmu, 0x10a580, 0x00000000);
+
+ /* wake process if it's waiting on a synchronous reply */
+ if (pmu->recv.process) {
+ if (process == pmu->recv.process &&
+ message == pmu->recv.message) {
+ pmu->recv.data[0] = data0;
+ pmu->recv.data[1] = data1;
+ pmu->recv.process = 0;
+ wake_up(&pmu->recv.wait);
+ return;
+ }
+ }
+
+ /* right now there's no other expected responses from the engine,
+ * so assume that any unexpected message is an error.
+ */
+ nv_warn(pmu, "%c%c%c%c 0x%08x 0x%08x 0x%08x 0x%08x\n",
+ (char)((process & 0x000000ff) >> 0),
+ (char)((process & 0x0000ff00) >> 8),
+ (char)((process & 0x00ff0000) >> 16),
+ (char)((process & 0xff000000) >> 24),
+ process, message, data0, data1);
+}
+
+static void
+nvkm_pmu_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_pmu *pmu = (void *)subdev;
+ u32 disp = nv_rd32(pmu, 0x10a01c);
+ u32 intr = nv_rd32(pmu, 0x10a008) & disp & ~(disp >> 16);
+
+ if (intr & 0x00000020) {
+ u32 stat = nv_rd32(pmu, 0x10a16c);
+ if (stat & 0x80000000) {
+ nv_error(pmu, "UAS fault at 0x%06x addr 0x%08x\n",
+ stat & 0x00ffffff, nv_rd32(pmu, 0x10a168));
+ nv_wr32(pmu, 0x10a16c, 0x00000000);
+ intr &= ~0x00000020;
+ }
+ }
+
+ if (intr & 0x00000040) {
+ schedule_work(&pmu->recv.work);
+ nv_wr32(pmu, 0x10a004, 0x00000040);
+ intr &= ~0x00000040;
+ }
+
+ if (intr & 0x00000080) {
+ nv_info(pmu, "wr32 0x%06x 0x%08x\n", nv_rd32(pmu, 0x10a7a0),
+ nv_rd32(pmu, 0x10a7a4));
+ nv_wr32(pmu, 0x10a004, 0x00000080);
+ intr &= ~0x00000080;
+ }
+
+ if (intr) {
+ nv_error(pmu, "intr 0x%08x\n", intr);
+ nv_wr32(pmu, 0x10a004, intr);
+ }
+}
+
+int
+_nvkm_pmu_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_pmu *pmu = (void *)object;
+
+ nv_wr32(pmu, 0x10a014, 0x00000060);
+ flush_work(&pmu->recv.work);
+
+ return nvkm_subdev_fini(&pmu->base, suspend);
+}
+
+int
+_nvkm_pmu_init(struct nvkm_object *object)
+{
+ const struct nvkm_pmu_impl *impl = (void *)object->oclass;
+ struct nvkm_pmu *pmu = (void *)object;
+ int ret, i;
+
+ ret = nvkm_subdev_init(&pmu->base);
+ if (ret)
+ return ret;
+
+ nv_subdev(pmu)->intr = nvkm_pmu_intr;
+ pmu->message = nvkm_pmu_send;
+ pmu->pgob = nvkm_pmu_pgob;
+
+ /* prevent previous ucode from running, wait for idle, reset */
+ nv_wr32(pmu, 0x10a014, 0x0000ffff); /* INTR_EN_CLR = ALL */
+ nv_wait(pmu, 0x10a04c, 0xffffffff, 0x00000000);
+ nv_mask(pmu, 0x000200, 0x00002000, 0x00000000);
+ nv_mask(pmu, 0x000200, 0x00002000, 0x00002000);
+ nv_rd32(pmu, 0x000200);
+ nv_wait(pmu, 0x10a10c, 0x00000006, 0x00000000);
+
+ /* upload data segment */
+ nv_wr32(pmu, 0x10a1c0, 0x01000000);
+ for (i = 0; i < impl->data.size / 4; i++)
+ nv_wr32(pmu, 0x10a1c4, impl->data.data[i]);
+
+ /* upload code segment */
+ nv_wr32(pmu, 0x10a180, 0x01000000);
+ for (i = 0; i < impl->code.size / 4; i++) {
+ if ((i & 0x3f) == 0)
+ nv_wr32(pmu, 0x10a188, i >> 6);
+ nv_wr32(pmu, 0x10a184, impl->code.data[i]);
+ }
+
+ /* start it running */
+ nv_wr32(pmu, 0x10a10c, 0x00000000);
+ nv_wr32(pmu, 0x10a104, 0x00000000);
+ nv_wr32(pmu, 0x10a100, 0x00000002);
+
+ /* wait for valid host->pmu ring configuration */
+ if (!nv_wait_ne(pmu, 0x10a4d0, 0xffffffff, 0x00000000))
+ return -EBUSY;
+ pmu->send.base = nv_rd32(pmu, 0x10a4d0) & 0x0000ffff;
+ pmu->send.size = nv_rd32(pmu, 0x10a4d0) >> 16;
+
+ /* wait for valid pmu->host ring configuration */
+ if (!nv_wait_ne(pmu, 0x10a4dc, 0xffffffff, 0x00000000))
+ return -EBUSY;
+ pmu->recv.base = nv_rd32(pmu, 0x10a4dc) & 0x0000ffff;
+ pmu->recv.size = nv_rd32(pmu, 0x10a4dc) >> 16;
+
+ nv_wr32(pmu, 0x10a010, 0x000000e0);
+ return 0;
+}
+
+int
+nvkm_pmu_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_pmu *pmu;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PMU",
+ "pmu", length, pobject);
+ pmu = *pobject;
+ if (ret)
+ return ret;
+
+ INIT_WORK(&pmu->recv.work, nvkm_pmu_recv);
+ init_waitqueue_head(&pmu->recv.wait);
+ return 0;
+}
+
+int
+_nvkm_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nvkm_pmu *pmu;
+ int ret = nvkm_pmu_create(parent, engine, oclass, &pmu);
+ *pobject = nv_object(pmu);
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/arith.fuc
index 214a6d9e088d..214a6d9e088d 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/arith.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/arith.fuc
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3
new file mode 100644
index 000000000000..37e8407b7462
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GF100
+#define HW_TICKS_PER_US 203 // should be 202.5
+
+//#define NVKM_FALCON_PC24
+//#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gf100_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gf100_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
new file mode 100644
index 000000000000..302557c52d03
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf100.fuc3.h
@@ -0,0 +1,1865 @@
+uint32_t gf100_pmu_data[] = {
+/* 0x0000: proc_kern */
+ 0x52544e49,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: proc_list_head */
+ 0x54534f48,
+ 0x00000512,
+ 0x000004af,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x584d454d,
+ 0x0000075e,
+ 0x00000750,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x46524550,
+ 0x00000762,
+ 0x00000760,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x5f433249,
+ 0x00000b92,
+ 0x00000a35,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x54534554,
+ 0x00000bbb,
+ 0x00000b94,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x454c4449,
+ 0x00000bc7,
+ 0x00000bc5,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+ 0x00000000,
+/* 0x026c: time_next */
+ 0x00000000,
+/* 0x0270: fifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x02f0: rfifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0370: memx_func_head */
+ 0x00000001,
+ 0x00000000,
+ 0x00000551,
+/* 0x037c: memx_func_next */
+ 0x00000002,
+ 0x00000000,
+ 0x000005db,
+ 0x00000003,
+ 0x00000002,
+ 0x000006a5,
+ 0x00040004,
+ 0x00000000,
+ 0x000006c1,
+ 0x00010005,
+ 0x00000000,
+ 0x000006de,
+ 0x00010006,
+ 0x00000000,
+ 0x00000663,
+ 0x00000007,
+ 0x00000000,
+ 0x000006e9,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+ 0x00000000,
+/* 0x03c8: memx_ts_end */
+ 0x00000000,
+/* 0x03cc: memx_data_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+ 0x00001000,
+ 0x00004000,
+ 0x00010000,
+ 0x00000100,
+ 0x00040000,
+ 0x00100000,
+ 0x00400000,
+ 0x01000000,
+ 0x04000000,
+ 0x10000000,
+/* 0x0cf4: i2c_sda_map */
+ 0x00002000,
+ 0x00008000,
+ 0x00020000,
+ 0x00000200,
+ 0x00080000,
+ 0x00200000,
+ 0x00800000,
+ 0x02000000,
+ 0x08000000,
+ 0x20000000,
+/* 0x0d1c: i2c_ctrl */
+ 0x0000e138,
+ 0x0000e150,
+ 0x0000e168,
+ 0x0000e180,
+ 0x0000e254,
+ 0x0000e274,
+ 0x0000e764,
+ 0x0000e780,
+ 0x0000e79c,
+ 0x0000e7b8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gf100_pmu_code[] = {
+ 0x039e0ef5,
+/* 0x0004: rd32 */
+ 0x07a007f1,
+ 0xd00604b6,
+ 0x04bd000e,
+ 0xf001d7f0,
+ 0x07f101d3,
+ 0x04b607ac,
+ 0x000dd006,
+/* 0x0022: rd32_wait */
+ 0xd7f104bd,
+ 0xd4b607ac,
+ 0x00ddcf06,
+ 0x7000d4f1,
+ 0xf1f21bf4,
+ 0xb607a4d7,
+ 0xddcf06d4,
+/* 0x003f: wr32 */
+ 0xf100f800,
+ 0xb607a007,
+ 0x0ed00604,
+ 0xf104bd00,
+ 0xb607a407,
+ 0x0dd00604,
+ 0xf004bd00,
+ 0xd5f002d7,
+ 0x01d3f0f0,
+ 0x07ac07f1,
+ 0xd00604b6,
+ 0x04bd000d,
+/* 0x006c: wr32_wait */
+ 0x07acd7f1,
+ 0xcf06d4b6,
+ 0xd4f100dd,
+ 0x1bf47000,
+/* 0x007f: nsec */
+ 0xf900f8f2,
+ 0xf080f990,
+ 0x84b62c87,
+ 0x0088cf06,
+/* 0x008c: nsec_loop */
+ 0xb62c97f0,
+ 0x99cf0694,
+ 0x0298bb00,
+ 0xf4069eb8,
+ 0x80fcf11e,
+ 0x00f890fc,
+/* 0x00a4: wait */
+ 0x80f990f9,
+ 0xb62c87f0,
+ 0x88cf0684,
+/* 0x00b1: wait_loop */
+ 0x02eeb900,
+ 0xb90421f4,
+ 0xadfd02da,
+ 0x06acb804,
+ 0xf0150bf4,
+ 0x94b62c97,
+ 0x0099cf06,
+ 0xb80298bb,
+ 0x1ef4069b,
+/* 0x00d5: wait_done */
+ 0xfc80fcdf,
+/* 0x00db: intr_watchdog */
+ 0x9800f890,
+ 0x96b003e9,
+ 0x2a0bf400,
+ 0xbb9a0a98,
+ 0x1cf4029a,
+ 0x01d7f00f,
+ 0x02dd21f5,
+ 0x0ef494bd,
+/* 0x00f9: intr_watchdog_next_time */
+ 0x9b0a9815,
+ 0xf400a6b0,
+ 0x9ab8090b,
+ 0x061cf406,
+/* 0x0108: intr_watchdog_next_time_set */
+/* 0x010b: intr_watchdog_next_proc */
+ 0x809b0980,
+ 0xe0b603e9,
+ 0x68e6b158,
+ 0xc61bf402,
+/* 0x011a: intr */
+ 0x00f900f8,
+ 0x80f904bd,
+ 0xa0f990f9,
+ 0xc0f9b0f9,
+ 0xe0f9d0f9,
+ 0xf7f0f0f9,
+ 0x0188fe00,
+ 0x87f180f9,
+ 0x84b605d0,
+ 0x0088cf06,
+ 0xf10180b6,
+ 0xb605d007,
+ 0x08d00604,
+ 0xf004bd00,
+ 0x84b60887,
+ 0x0088cf06,
+ 0xf40289c4,
+ 0x0080230b,
+ 0x58e7f09b,
+ 0x98db21f4,
+ 0x96b09b09,
+ 0x110bf400,
+ 0xb63407f0,
+ 0x09d00604,
+ 0x8004bd00,
+/* 0x017e: intr_skip_watchdog */
+ 0x89e49a09,
+ 0x0bf40800,
+ 0x8897f148,
+ 0x0694b606,
+ 0xc40099cf,
+ 0x0bf4029a,
+ 0xc0c7f12c,
+ 0x06c4b604,
+ 0xf900cccf,
+ 0x48e7f1c0,
+ 0x53e3f14f,
+ 0x00d7f054,
+ 0x034221f5,
+ 0x07f1c0fc,
+ 0x04b604c0,
+ 0x000cd006,
+/* 0x01be: intr_subintr_skip_fifo */
+ 0x07f104bd,
+ 0x04b60688,
+ 0x0009d006,
+/* 0x01ca: intr_skip_subintr */
+ 0x89c404bd,
+ 0x070bf420,
+ 0xffbfa4f1,
+/* 0x01d4: intr_skip_pause */
+ 0xf44089c4,
+ 0xa4f1070b,
+/* 0x01de: intr_skip_user0 */
+ 0x07f0ffbf,
+ 0x0604b604,
+ 0xbd0008d0,
+ 0xfe80fc04,
+ 0xf0fc0088,
+ 0xd0fce0fc,
+ 0xb0fcc0fc,
+ 0x90fca0fc,
+ 0x00fc80fc,
+ 0xf80032f4,
+/* 0x0205: ticks_from_ns */
+ 0xf9c0f901,
+ 0xcbd7f1b0,
+ 0x00d3f000,
+ 0x041321f5,
+ 0x03e8ccec,
+ 0xf400b4b0,
+ 0xeeec120b,
+ 0xd7f103e8,
+ 0xd3f000cb,
+ 0x1321f500,
+/* 0x022d: ticks_from_ns_quit */
+ 0x02ceb904,
+ 0xc0fcb0fc,
+/* 0x0236: ticks_from_us */
+ 0xc0f900f8,
+ 0xd7f1b0f9,
+ 0xd3f000cb,
+ 0x1321f500,
+ 0x02ceb904,
+ 0xf400b4b0,
+ 0xe4bd050b,
+/* 0x0250: ticks_from_us_quit */
+ 0xc0fcb0fc,
+/* 0x0256: ticks_to_us */
+ 0xd7f100f8,
+ 0xd3f000cb,
+ 0xecedff00,
+/* 0x0262: timer */
+ 0x90f900f8,
+ 0x32f480f9,
+ 0x03f89810,
+ 0xf40086b0,
+ 0x84bd651c,
+ 0xb63807f0,
+ 0x08d00604,
+ 0xf004bd00,
+ 0x84b63487,
+ 0x0088cf06,
+ 0xbb9a0998,
+ 0xe9bb0298,
+ 0x03fe8000,
+ 0xb60887f0,
+ 0x88cf0684,
+ 0x0284f000,
+ 0xf0261bf4,
+ 0x84b63487,
+ 0x0088cf06,
+ 0xf406e0b8,
+ 0xe8b8090b,
+ 0x111cf406,
+/* 0x02b8: timer_reset */
+ 0xb63407f0,
+ 0x0ed00604,
+ 0x8004bd00,
+/* 0x02c6: timer_enable */
+ 0x87f09a0e,
+ 0x3807f001,
+ 0xd00604b6,
+ 0x04bd0008,
+/* 0x02d4: timer_done */
+ 0xfc1031f4,
+ 0xf890fc80,
+/* 0x02dd: send_proc */
+ 0xf980f900,
+ 0x05e89890,
+ 0xf004e998,
+ 0x89b80486,
+ 0x2a0bf406,
+ 0x940398c4,
+ 0x80b60488,
+ 0x008ebb18,
+ 0x8000fa98,
+ 0x8d80008a,
+ 0x028c8001,
+ 0xb6038b80,
+ 0x94f00190,
+ 0x04e98007,
+/* 0x0317: send_done */
+ 0xfc0231f4,
+ 0xf880fc90,
+/* 0x031d: find */
+ 0xf080f900,
+ 0x31f45887,
+/* 0x0325: find_loop */
+ 0x008a9801,
+ 0xf406aeb8,
+ 0x80b6100b,
+ 0x6886b158,
+ 0xf01bf402,
+/* 0x033b: find_done */
+ 0xb90132f4,
+ 0x80fc028e,
+/* 0x0342: send */
+ 0x21f500f8,
+ 0x01f4031d,
+/* 0x034b: recv */
+ 0xf900f897,
+ 0x9880f990,
+ 0xe99805e8,
+ 0x0132f404,
+ 0xf40689b8,
+ 0x89c43d0b,
+ 0x0180b603,
+ 0x800784f0,
+ 0xea9805e8,
+ 0xfef0f902,
+ 0xf0f9018f,
+ 0x9402efb9,
+ 0xe9bb0499,
+ 0x18e0b600,
+ 0x9803eb98,
+ 0xed9802ec,
+ 0x00ee9801,
+ 0xf0fca5f9,
+ 0xf400f8fe,
+ 0xf0fc0131,
+/* 0x0398: recv_done */
+ 0x90fc80fc,
+/* 0x039e: init */
+ 0x17f100f8,
+ 0x14b60108,
+ 0x0011cf06,
+ 0x010911e7,
+ 0xfe0814b6,
+ 0x17f10014,
+ 0x13f000e0,
+ 0x1c07f000,
+ 0xd00604b6,
+ 0x04bd0001,
+ 0xf0ff17f0,
+ 0x04b61407,
+ 0x0001d006,
+ 0x17f004bd,
+ 0x0015f102,
+ 0x1007f008,
+ 0xd00604b6,
+ 0x04bd0001,
+ 0x011a17f1,
+ 0xfe0013f0,
+ 0x31f40010,
+ 0x0117f010,
+ 0xb63807f0,
+ 0x01d00604,
+ 0xf004bd00,
+/* 0x0402: init_proc */
+ 0xf19858f7,
+ 0x0016b001,
+ 0xf9fa0bf4,
+ 0x58f0b615,
+/* 0x0413: mulu32_32_64 */
+ 0xf9f20ef4,
+ 0xf920f910,
+ 0x9540f930,
+ 0xd29510e1,
+ 0xbdc4bd10,
+ 0xc0edffb4,
+ 0xb9301dff,
+ 0x34f10234,
+ 0x34b6ffff,
+ 0x1045b610,
+ 0xbb00c3bb,
+ 0xe2ff01b4,
+ 0x0234b930,
+ 0xffff34f1,
+ 0xb61034b6,
+ 0xc3bb1045,
+ 0x01b4bb00,
+ 0xbb3012ff,
+ 0x40fc00b3,
+ 0x20fc30fc,
+ 0x00f810fc,
+/* 0x0464: host_send */
+ 0x04b017f1,
+ 0xcf0614b6,
+ 0x27f10011,
+ 0x24b604a0,
+ 0x0022cf06,
+ 0xf40612b8,
+ 0x1ec4320b,
+ 0x04ee9407,
+ 0x0270e0b7,
+ 0x9803eb98,
+ 0xed9802ec,
+ 0x00ee9801,
+ 0x034221f5,
+ 0xc40110b6,
+ 0x07f10f1e,
+ 0x04b604b0,
+ 0x000ed006,
+ 0x0ef404bd,
+/* 0x04ad: host_send_done */
+/* 0x04af: host_recv */
+ 0xf100f8ba,
+ 0xf14e4917,
+ 0xb8525413,
+ 0x0bf406e1,
+/* 0x04bd: host_recv_wait */
+ 0xcc17f1aa,
+ 0x0614b604,
+ 0xf10011cf,
+ 0xb604c827,
+ 0x22cf0624,
+ 0x0816f000,
+ 0xf40612b8,
+ 0x23c4e60b,
+ 0x0434b607,
+ 0x02f030b7,
+ 0x80033b80,
+ 0x3d80023c,
+ 0x003e8001,
+ 0xf00120b6,
+ 0x07f10f24,
+ 0x04b604c8,
+ 0x0002d006,
+ 0x27f004bd,
+ 0x0007f040,
+ 0xd00604b6,
+ 0x04bd0002,
+/* 0x0512: host_init */
+ 0x17f100f8,
+ 0x14b60080,
+ 0x7015f110,
+ 0xd007f102,
+ 0x0604b604,
+ 0xbd0001d0,
+ 0x8017f104,
+ 0x1014b600,
+ 0x02f015f1,
+ 0x04dc07f1,
+ 0xd00604b6,
+ 0x04bd0001,
+ 0xf10117f0,
+ 0xb604c407,
+ 0x01d00604,
+ 0xf804bd00,
+/* 0x0551: memx_func_enter */
+ 0x2067f100,
+ 0x5d77f116,
+ 0xff73f1f5,
+ 0x026eb9ff,
+ 0xb90421f4,
+ 0x87fd02d8,
+ 0xf960f904,
+ 0xfcd0fc80,
+ 0x3f21f4e0,
+ 0xfffe77f1,
+ 0xffff73f1,
+ 0xf4026eb9,
+ 0xd8b90421,
+ 0x0487fd02,
+ 0x80f960f9,
+ 0xe0fcd0fc,
+ 0xf13f21f4,
+ 0xb926f067,
+ 0x21f4026e,
+ 0x02d8b904,
+ 0xf90487fd,
+ 0xfc80f960,
+ 0xf4e0fcd0,
+ 0x67f03f21,
+ 0xe007f104,
+ 0x0604b607,
+ 0xbd0006d0,
+/* 0x05bd: memx_func_enter_wait */
+ 0xc067f104,
+ 0x0664b607,
+ 0xf00066cf,
+ 0x0bf40464,
+ 0x2c67f0f3,
+ 0xcf0664b6,
+ 0x06800066,
+/* 0x05db: memx_func_leave */
+ 0xf000f8f1,
+ 0x64b62c67,
+ 0x0066cf06,
+ 0xf0f20680,
+ 0x07f10467,
+ 0x04b607e4,
+ 0x0006d006,
+/* 0x05f6: memx_func_leave_wait */
+ 0x67f104bd,
+ 0x64b607c0,
+ 0x0066cf06,
+ 0xf40464f0,
+ 0x67f1f31b,
+ 0x77f126f0,
+ 0x73f00001,
+ 0x026eb900,
+ 0xb90421f4,
+ 0x87fd02d8,
+ 0xf960f905,
+ 0xfcd0fc80,
+ 0x3f21f4e0,
+ 0x162067f1,
+ 0xf4026eb9,
+ 0xd8b90421,
+ 0x0587fd02,
+ 0x80f960f9,
+ 0xe0fcd0fc,
+ 0xf13f21f4,
+ 0xf00aa277,
+ 0x6eb90073,
+ 0x0421f402,
+ 0xfd02d8b9,
+ 0x60f90587,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+/* 0x0663: memx_func_wait_vblank */
+ 0x9800f83f,
+ 0x66b00016,
+ 0x130bf400,
+ 0xf40166b0,
+ 0x0ef4060b,
+/* 0x0675: memx_func_wait_vblank_head1 */
+ 0x2077f12e,
+ 0x070ef400,
+/* 0x067c: memx_func_wait_vblank_head0 */
+ 0x000877f1,
+/* 0x0680: memx_func_wait_vblank_0 */
+ 0x07c467f1,
+ 0xcf0664b6,
+ 0x67fd0066,
+ 0xf31bf404,
+/* 0x0690: memx_func_wait_vblank_1 */
+ 0x07c467f1,
+ 0xcf0664b6,
+ 0x67fd0066,
+ 0xf30bf404,
+/* 0x06a0: memx_func_wait_vblank_fini */
+ 0xf80410b6,
+/* 0x06a5: memx_func_wr32 */
+ 0x00169800,
+ 0xb6011598,
+ 0x60f90810,
+ 0xd0fc50f9,
+ 0x21f4e0fc,
+ 0x0242b63f,
+ 0xf8e91bf4,
+/* 0x06c1: memx_func_wait */
+ 0x2c87f000,
+ 0xcf0684b6,
+ 0x1e980088,
+ 0x011d9800,
+ 0x98021c98,
+ 0x10b6031b,
+ 0xa421f410,
+/* 0x06de: memx_func_delay */
+ 0x1e9800f8,
+ 0x0410b600,
+ 0xf87f21f4,
+/* 0x06e9: memx_func_train */
+/* 0x06eb: memx_exec */
+ 0xf900f800,
+ 0xb9d0f9e0,
+ 0xb2b902c1,
+/* 0x06f5: memx_exec_next */
+ 0x00139802,
+ 0xe70410b6,
+ 0xe701f034,
+ 0xb601e033,
+ 0x30f00132,
+ 0xde35980c,
+ 0x12b855f9,
+ 0xe41ef406,
+ 0x98f10b98,
+ 0xcbbbf20c,
+ 0xc4b7f102,
+ 0x06b4b607,
+ 0xfc00bbcf,
+ 0xf5e0fcd0,
+ 0xf8034221,
+/* 0x0731: memx_info */
+ 0x01c67000,
+/* 0x0737: memx_info_data */
+ 0xf10e0bf4,
+ 0xf103ccc7,
+ 0xf40800b7,
+/* 0x0742: memx_info_train */
+ 0xc7f10b0e,
+ 0xb7f10bcc,
+/* 0x074a: memx_info_send */
+ 0x21f50100,
+ 0x00f80342,
+/* 0x0750: memx_recv */
+ 0xf401d6b0,
+ 0xd6b0980b,
+ 0xd80bf400,
+/* 0x075e: memx_init */
+ 0x00f800f8,
+/* 0x0760: perf_recv */
+/* 0x0762: perf_init */
+ 0x00f800f8,
+/* 0x0764: i2c_drive_scl */
+ 0xf40036b0,
+ 0x07f1110b,
+ 0x04b607e0,
+ 0x0001d006,
+ 0x00f804bd,
+/* 0x0778: i2c_drive_scl_lo */
+ 0x07e407f1,
+ 0xd00604b6,
+ 0x04bd0001,
+/* 0x0786: i2c_drive_sda */
+ 0x36b000f8,
+ 0x110bf400,
+ 0x07e007f1,
+ 0xd00604b6,
+ 0x04bd0002,
+/* 0x079a: i2c_drive_sda_lo */
+ 0x07f100f8,
+ 0x04b607e4,
+ 0x0002d006,
+ 0x00f804bd,
+/* 0x07a8: i2c_sense_scl */
+ 0xf10132f4,
+ 0xb607c437,
+ 0x33cf0634,
+ 0x0431fd00,
+ 0xf4060bf4,
+/* 0x07be: i2c_sense_scl_done */
+ 0x00f80131,
+/* 0x07c0: i2c_sense_sda */
+ 0xf10132f4,
+ 0xb607c437,
+ 0x33cf0634,
+ 0x0432fd00,
+ 0xf4060bf4,
+/* 0x07d6: i2c_sense_sda_done */
+ 0x00f80131,
+/* 0x07d8: i2c_raise_scl */
+ 0x47f140f9,
+ 0x37f00898,
+ 0x6421f501,
+/* 0x07e5: i2c_raise_scl_wait */
+ 0xe8e7f107,
+ 0x7f21f403,
+ 0x07a821f5,
+ 0xb60901f4,
+ 0x1bf40142,
+/* 0x07f9: i2c_raise_scl_done */
+ 0xf840fcef,
+/* 0x07fd: i2c_start */
+ 0xa821f500,
+ 0x0d11f407,
+ 0x07c021f5,
+ 0xf40611f4,
+/* 0x080e: i2c_start_rep */
+ 0x37f0300e,
+ 0x6421f500,
+ 0x0137f007,
+ 0x078621f5,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xd821f550,
+ 0x0464b607,
+/* 0x083b: i2c_start_send */
+ 0xf01f11f4,
+ 0x21f50037,
+ 0xe7f10786,
+ 0x21f41388,
+ 0x0037f07f,
+ 0x076421f5,
+ 0x1388e7f1,
+/* 0x0857: i2c_start_out */
+ 0xf87f21f4,
+/* 0x0859: i2c_stop */
+ 0x0037f000,
+ 0x076421f5,
+ 0xf50037f0,
+ 0xf1078621,
+ 0xf403e8e7,
+ 0x37f07f21,
+ 0x6421f501,
+ 0x88e7f107,
+ 0x7f21f413,
+ 0xf50137f0,
+ 0xf1078621,
+ 0xf41388e7,
+ 0x00f87f21,
+/* 0x088c: i2c_bitw */
+ 0x078621f5,
+ 0x03e8e7f1,
+ 0xbb7f21f4,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x07d821f5,
+ 0xf40464b6,
+ 0xe7f11811,
+ 0x21f41388,
+ 0x0037f07f,
+ 0x076421f5,
+ 0x1388e7f1,
+/* 0x08cb: i2c_bitw_out */
+ 0xf87f21f4,
+/* 0x08cd: i2c_bitr */
+ 0x0137f000,
+ 0x078621f5,
+ 0x03e8e7f1,
+ 0xbb7f21f4,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x07d821f5,
+ 0xf40464b6,
+ 0x21f51b11,
+ 0x37f007c0,
+ 0x6421f500,
+ 0x88e7f107,
+ 0x7f21f413,
+ 0xf4013cf0,
+/* 0x0912: i2c_bitr_done */
+ 0x00f80131,
+/* 0x0914: i2c_get_byte */
+ 0xf00057f0,
+/* 0x091a: i2c_get_byte_next */
+ 0x54b60847,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b608cd,
+ 0x2b11f404,
+ 0xb60553fd,
+ 0x1bf40142,
+ 0x0137f0d8,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x8c21f550,
+ 0x0464b608,
+/* 0x0964: i2c_get_byte_done */
+/* 0x0966: i2c_put_byte */
+ 0x47f000f8,
+/* 0x0969: i2c_put_byte_next */
+ 0x0142b608,
+ 0xbb3854ff,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x088c21f5,
+ 0xf40464b6,
+ 0x46b03411,
+ 0xd81bf400,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xcd21f550,
+ 0x0464b608,
+ 0xbb0f11f4,
+ 0x36b00076,
+ 0x061bf401,
+/* 0x09bf: i2c_put_byte_done */
+ 0xf80132f4,
+/* 0x09c1: i2c_addr */
+ 0x0076bb00,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b607fd,
+ 0x2911f404,
+ 0x012ec3e7,
+ 0xfd0134b6,
+ 0x76bb0553,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb6096621,
+/* 0x0a06: i2c_addr_done */
+ 0x00f80464,
+/* 0x0a08: i2c_acquire_addr */
+ 0xb6f8cec7,
+ 0xe0b702e4,
+ 0xee980d1c,
+/* 0x0a17: i2c_acquire */
+ 0xf500f800,
+ 0xf40a0821,
+ 0xd9f00421,
+ 0x3f21f403,
+/* 0x0a26: i2c_release */
+ 0x21f500f8,
+ 0x21f40a08,
+ 0x03daf004,
+ 0xf83f21f4,
+/* 0x0a35: i2c_recv */
+ 0x0132f400,
+ 0xb6f8c1c7,
+ 0x16b00214,
+ 0x3a1ff528,
+ 0xf413a001,
+ 0x0032980c,
+ 0x0ccc13a0,
+ 0xf4003198,
+ 0xd0f90231,
+ 0xd0f9e0f9,
+ 0x000067f1,
+ 0x100063f1,
+ 0xbb016792,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x0a1721f5,
+ 0xfc0464b6,
+ 0x00d6b0d0,
+ 0x00b31bf5,
+ 0xbb0057f0,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x09c121f5,
+ 0xf50464b6,
+ 0xc700d011,
+ 0x76bbe0c5,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb6096621,
+ 0x11f50464,
+ 0x57f000ad,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b609c1,
+ 0x8a11f504,
+ 0x0076bb00,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b60914,
+ 0x6a11f404,
+ 0xbbe05bcb,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x085921f5,
+ 0xb90464b6,
+ 0x74bd025b,
+/* 0x0b3b: i2c_recv_not_rd08 */
+ 0xb0430ef4,
+ 0x1bf401d6,
+ 0x0057f03d,
+ 0x09c121f5,
+ 0xc73311f4,
+ 0x21f5e0c5,
+ 0x11f40966,
+ 0x0057f029,
+ 0x09c121f5,
+ 0xc71f11f4,
+ 0x21f5e0b5,
+ 0x11f40966,
+ 0x5921f515,
+ 0xc774bd08,
+ 0x1bf408c5,
+ 0x0232f409,
+/* 0x0b7b: i2c_recv_not_wr08 */
+/* 0x0b7b: i2c_recv_done */
+ 0xc7030ef4,
+ 0x21f5f8ce,
+ 0xe0fc0a26,
+ 0x12f4d0fc,
+ 0x027cb90a,
+ 0x034221f5,
+/* 0x0b90: i2c_recv_exit */
+/* 0x0b92: i2c_init */
+ 0x00f800f8,
+/* 0x0b94: test_recv */
+ 0x05d817f1,
+ 0xcf0614b6,
+ 0x10b60011,
+ 0xd807f101,
+ 0x0604b605,
+ 0xbd0001d0,
+ 0x00e7f104,
+ 0x4fe3f1d9,
+ 0x6221f513,
+/* 0x0bbb: test_init */
+ 0xf100f802,
+ 0xf50800e7,
+ 0xf8026221,
+/* 0x0bc5: idle_recv */
+/* 0x0bc7: idle */
+ 0xf400f800,
+ 0x17f10031,
+ 0x14b605d4,
+ 0x0011cf06,
+ 0xf10110b6,
+ 0xb605d407,
+ 0x01d00604,
+/* 0x0be3: idle_loop */
+ 0xf004bd00,
+ 0x32f45817,
+/* 0x0be9: idle_proc */
+/* 0x0be9: idle_proc_exec */
+ 0xb910f902,
+ 0x21f5021e,
+ 0x10fc034b,
+ 0xf40911f4,
+ 0x0ef40231,
+/* 0x0bfd: idle_proc_next */
+ 0x5810b6ef,
+ 0xf4061fb8,
+ 0x02f4e61b,
+ 0x0028f4dd,
+ 0x00bb0ef4,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4
new file mode 100644
index 000000000000..ae9c3f18ae01
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GF119
+#define HW_TICKS_PER_US 324
+
+//#define NVKM_FALCON_PC24
+#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gf110_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gf110_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h
new file mode 100644
index 000000000000..a0c499e4543c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gf110.fuc4.h
@@ -0,0 +1,1795 @@
+uint32_t gf110_pmu_data[] = {
+/* 0x0000: proc_kern */
+ 0x52544e49,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: proc_list_head */
+ 0x54534f48,
+ 0x0000049d,
+ 0x00000446,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x584d454d,
+ 0x0000068b,
+ 0x0000067d,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x46524550,
+ 0x0000068f,
+ 0x0000068d,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x5f433249,
+ 0x00000aaa,
+ 0x0000094d,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x54534554,
+ 0x00000acd,
+ 0x00000aac,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x454c4449,
+ 0x00000ad9,
+ 0x00000ad7,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+ 0x00000000,
+/* 0x026c: time_next */
+ 0x00000000,
+/* 0x0270: fifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x02f0: rfifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0370: memx_func_head */
+ 0x00000001,
+ 0x00000000,
+ 0x000004d3,
+/* 0x037c: memx_func_next */
+ 0x00000002,
+ 0x00000000,
+ 0x00000554,
+ 0x00000003,
+ 0x00000002,
+ 0x000005d8,
+ 0x00040004,
+ 0x00000000,
+ 0x000005f4,
+ 0x00010005,
+ 0x00000000,
+ 0x0000060e,
+ 0x00010006,
+ 0x00000000,
+ 0x000005d3,
+ 0x00000007,
+ 0x00000000,
+ 0x00000619,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+ 0x00000000,
+/* 0x03c8: memx_ts_end */
+ 0x00000000,
+/* 0x03cc: memx_data_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+ 0x00000400,
+ 0x00000800,
+ 0x00001000,
+ 0x00002000,
+ 0x00004000,
+ 0x00008000,
+ 0x00010000,
+ 0x00020000,
+ 0x00040000,
+ 0x00080000,
+/* 0x0cf4: i2c_sda_map */
+ 0x00100000,
+ 0x00200000,
+ 0x00400000,
+ 0x00800000,
+ 0x01000000,
+ 0x02000000,
+ 0x04000000,
+ 0x08000000,
+ 0x10000000,
+ 0x20000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gf110_pmu_code[] = {
+ 0x034d0ef5,
+/* 0x0004: rd32 */
+ 0x07a007f1,
+ 0xbd000ed0,
+ 0x01d7f004,
+ 0xf101d3f0,
+ 0xd007ac07,
+ 0x04bd000d,
+/* 0x001c: rd32_wait */
+ 0x07acd7f1,
+ 0xf100ddcf,
+ 0xf47000d4,
+ 0xd7f1f51b,
+ 0xddcf07a4,
+/* 0x0033: wr32 */
+ 0xf100f800,
+ 0xd007a007,
+ 0x04bd000e,
+ 0x07a407f1,
+ 0xbd000dd0,
+ 0x02d7f004,
+ 0xf0f0d5f0,
+ 0x07f101d3,
+ 0x0dd007ac,
+/* 0x0057: wr32_wait */
+ 0xf104bd00,
+ 0xcf07acd7,
+ 0xd4f100dd,
+ 0x1bf47000,
+/* 0x0067: nsec */
+ 0xf900f8f5,
+ 0xf080f990,
+ 0x88cf2c87,
+/* 0x0071: nsec_loop */
+ 0x2c97f000,
+ 0xbb0099cf,
+ 0x9eb80298,
+ 0xf41ef406,
+ 0x90fc80fc,
+/* 0x0086: wait */
+ 0x90f900f8,
+ 0x87f080f9,
+ 0x0088cf2c,
+/* 0x0090: wait_loop */
+ 0xf402eeb9,
+ 0xdab90421,
+ 0x04adfd02,
+ 0xf406acb8,
+ 0x97f0120b,
+ 0x0099cf2c,
+ 0xb80298bb,
+ 0x1ef4069b,
+/* 0x00b1: wait_done */
+ 0xfc80fce2,
+/* 0x00b7: intr_watchdog */
+ 0x9800f890,
+ 0x96b003e9,
+ 0x2a0bf400,
+ 0xbb9a0a98,
+ 0x1cf4029a,
+ 0x01d7f00f,
+ 0x028c21f5,
+ 0x0ef494bd,
+/* 0x00d5: intr_watchdog_next_time */
+ 0x9b0a9815,
+ 0xf400a6b0,
+ 0x9ab8090b,
+ 0x061cf406,
+/* 0x00e4: intr_watchdog_next_time_set */
+/* 0x00e7: intr_watchdog_next_proc */
+ 0x809b0980,
+ 0xe0b603e9,
+ 0x68e6b158,
+ 0xc61bf402,
+/* 0x00f6: intr */
+ 0x00f900f8,
+ 0x80f904bd,
+ 0xa0f990f9,
+ 0xc0f9b0f9,
+ 0xe0f9d0f9,
+ 0xf7f0f0f9,
+ 0x0188fe00,
+ 0x87f180f9,
+ 0x88cf05d0,
+ 0x0180b600,
+ 0x05d007f1,
+ 0xbd0008d0,
+ 0x0887f004,
+ 0xc40088cf,
+ 0x0bf40289,
+ 0x9b008020,
+ 0xf458e7f0,
+ 0x0998b721,
+ 0x0096b09b,
+ 0xf00e0bf4,
+ 0x09d03407,
+ 0x8004bd00,
+/* 0x014e: intr_skip_watchdog */
+ 0x89e49a09,
+ 0x0bf40800,
+ 0x8897f13c,
+ 0x0099cf06,
+ 0xf4029ac4,
+ 0xc7f1260b,
+ 0xcccf04c0,
+ 0xf1c0f900,
+ 0xf14f48e7,
+ 0xf05453e3,
+ 0x21f500d7,
+ 0xc0fc02f1,
+ 0x04c007f1,
+ 0xbd000cd0,
+/* 0x0185: intr_subintr_skip_fifo */
+ 0x8807f104,
+ 0x0009d006,
+/* 0x018e: intr_skip_subintr */
+ 0x89c404bd,
+ 0x070bf420,
+ 0xffbfa4f1,
+/* 0x0198: intr_skip_pause */
+ 0xf44089c4,
+ 0xa4f1070b,
+/* 0x01a2: intr_skip_user0 */
+ 0x07f0ffbf,
+ 0x0008d004,
+ 0x80fc04bd,
+ 0xfc0088fe,
+ 0xfce0fcf0,
+ 0xfcc0fcd0,
+ 0xfca0fcb0,
+ 0xfc80fc90,
+ 0x0032f400,
+/* 0x01c6: ticks_from_ns */
+ 0xc0f901f8,
+ 0xd7f1b0f9,
+ 0xd3f00144,
+ 0xb321f500,
+ 0xe8ccec03,
+ 0x00b4b003,
+ 0xec120bf4,
+ 0xf103e8ee,
+ 0xf00144d7,
+ 0x21f500d3,
+/* 0x01ee: ticks_from_ns_quit */
+ 0xceb903b3,
+ 0xfcb0fc02,
+/* 0x01f7: ticks_from_us */
+ 0xf900f8c0,
+ 0xf1b0f9c0,
+ 0xf00144d7,
+ 0x21f500d3,
+ 0xceb903b3,
+ 0x00b4b002,
+ 0xbd050bf4,
+/* 0x0211: ticks_from_us_quit */
+ 0xfcb0fce4,
+/* 0x0217: ticks_to_us */
+ 0xf100f8c0,
+ 0xf00144d7,
+ 0xedff00d3,
+/* 0x0223: timer */
+ 0xf900f8ec,
+ 0xf480f990,
+ 0xf8981032,
+ 0x0086b003,
+ 0xbd531cf4,
+ 0x3807f084,
+ 0xbd0008d0,
+ 0x3487f004,
+ 0x980088cf,
+ 0x98bb9a09,
+ 0x00e9bb02,
+ 0xf003fe80,
+ 0x88cf0887,
+ 0x0284f000,
+ 0xf0201bf4,
+ 0x88cf3487,
+ 0x06e0b800,
+ 0xb8090bf4,
+ 0x1cf406e8,
+/* 0x026d: timer_reset */
+ 0x3407f00e,
+ 0xbd000ed0,
+ 0x9a0e8004,
+/* 0x0278: timer_enable */
+ 0xf00187f0,
+ 0x08d03807,
+/* 0x0283: timer_done */
+ 0xf404bd00,
+ 0x80fc1031,
+ 0x00f890fc,
+/* 0x028c: send_proc */
+ 0x90f980f9,
+ 0x9805e898,
+ 0x86f004e9,
+ 0x0689b804,
+ 0xc42a0bf4,
+ 0x88940398,
+ 0x1880b604,
+ 0x98008ebb,
+ 0x8a8000fa,
+ 0x018d8000,
+ 0x80028c80,
+ 0x90b6038b,
+ 0x0794f001,
+ 0xf404e980,
+/* 0x02c6: send_done */
+ 0x90fc0231,
+ 0x00f880fc,
+/* 0x02cc: find */
+ 0x87f080f9,
+ 0x0131f458,
+/* 0x02d4: find_loop */
+ 0xb8008a98,
+ 0x0bf406ae,
+ 0x5880b610,
+ 0x026886b1,
+ 0xf4f01bf4,
+/* 0x02ea: find_done */
+ 0x8eb90132,
+ 0xf880fc02,
+/* 0x02f1: send */
+ 0xcc21f500,
+ 0x9701f402,
+/* 0x02fa: recv */
+ 0x90f900f8,
+ 0xe89880f9,
+ 0x04e99805,
+ 0xb80132f4,
+ 0x0bf40689,
+ 0x0389c43d,
+ 0xf00180b6,
+ 0xe8800784,
+ 0x02ea9805,
+ 0x8ffef0f9,
+ 0xb9f0f901,
+ 0x999402ef,
+ 0x00e9bb04,
+ 0x9818e0b6,
+ 0xec9803eb,
+ 0x01ed9802,
+ 0xf900ee98,
+ 0xfef0fca5,
+ 0x31f400f8,
+/* 0x0347: recv_done */
+ 0xfcf0fc01,
+ 0xf890fc80,
+/* 0x034d: init */
+ 0x0817f100,
+ 0x0011cf01,
+ 0x010911e7,
+ 0xfe0814b6,
+ 0x17f10014,
+ 0x13f000e0,
+ 0x1c07f000,
+ 0xbd0001d0,
+ 0xff17f004,
+ 0xd01407f0,
+ 0x04bd0001,
+ 0xf10217f0,
+ 0xf0080015,
+ 0x01d01007,
+ 0xf104bd00,
+ 0xf000f617,
+ 0x10fe0013,
+ 0x1031f400,
+ 0xf00117f0,
+ 0x01d03807,
+ 0xf004bd00,
+/* 0x03a2: init_proc */
+ 0xf19858f7,
+ 0x0016b001,
+ 0xf9fa0bf4,
+ 0x58f0b615,
+/* 0x03b3: mulu32_32_64 */
+ 0xf9f20ef4,
+ 0xf920f910,
+ 0x9540f930,
+ 0xd29510e1,
+ 0xbdc4bd10,
+ 0xc0edffb4,
+ 0xb9301dff,
+ 0x34f10234,
+ 0x34b6ffff,
+ 0x1045b610,
+ 0xbb00c3bb,
+ 0xe2ff01b4,
+ 0x0234b930,
+ 0xffff34f1,
+ 0xb61034b6,
+ 0xc3bb1045,
+ 0x01b4bb00,
+ 0xbb3012ff,
+ 0x40fc00b3,
+ 0x20fc30fc,
+ 0x00f810fc,
+/* 0x0404: host_send */
+ 0x04b017f1,
+ 0xf10011cf,
+ 0xcf04a027,
+ 0x12b80022,
+ 0x2f0bf406,
+ 0x94071ec4,
+ 0xe0b704ee,
+ 0xeb980270,
+ 0x02ec9803,
+ 0x9801ed98,
+ 0x21f500ee,
+ 0x10b602f1,
+ 0x0f1ec401,
+ 0x04b007f1,
+ 0xbd000ed0,
+ 0xc30ef404,
+/* 0x0444: host_send_done */
+/* 0x0446: host_recv */
+ 0x17f100f8,
+ 0x13f14e49,
+ 0xe1b85254,
+ 0xb30bf406,
+/* 0x0454: host_recv_wait */
+ 0x04cc17f1,
+ 0xf10011cf,
+ 0xcf04c827,
+ 0x16f00022,
+ 0x0612b808,
+ 0xc4ec0bf4,
+ 0x34b60723,
+ 0xf030b704,
+ 0x033b8002,
+ 0x80023c80,
+ 0x3e80013d,
+ 0x0120b600,
+ 0xf10f24f0,
+ 0xd004c807,
+ 0x04bd0002,
+ 0xf04027f0,
+ 0x02d00007,
+ 0xf804bd00,
+/* 0x049d: host_init */
+ 0x8017f100,
+ 0x1014b600,
+ 0x027015f1,
+ 0x04d007f1,
+ 0xbd0001d0,
+ 0x8017f104,
+ 0x1014b600,
+ 0x02f015f1,
+ 0x04dc07f1,
+ 0xbd0001d0,
+ 0x0117f004,
+ 0x04c407f1,
+ 0xbd0001d0,
+/* 0x04d3: memx_func_enter */
+ 0xf100f804,
+ 0xf1162067,
+ 0xf1f55d77,
+ 0xb9ffff73,
+ 0x21f4026e,
+ 0x02d8b904,
+ 0xf90487fd,
+ 0xfc80f960,
+ 0xf4e0fcd0,
+ 0x77f13321,
+ 0x73f1fffe,
+ 0x6eb9ffff,
+ 0x0421f402,
+ 0xfd02d8b9,
+ 0x60f90487,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+ 0xf067f133,
+ 0x026eb926,
+ 0xb90421f4,
+ 0x87fd02d8,
+ 0xf960f904,
+ 0xfcd0fc80,
+ 0x3321f4e0,
+ 0xf10467f0,
+ 0xd007e007,
+ 0x04bd0006,
+/* 0x053c: memx_func_enter_wait */
+ 0x07c067f1,
+ 0xf00066cf,
+ 0x0bf40464,
+ 0x2c67f0f6,
+ 0x800066cf,
+ 0x00f8f106,
+/* 0x0554: memx_func_leave */
+ 0xcf2c67f0,
+ 0x06800066,
+ 0x0467f0f2,
+ 0x07e407f1,
+ 0xbd0006d0,
+/* 0x0569: memx_func_leave_wait */
+ 0xc067f104,
+ 0x0066cf07,
+ 0xf40464f0,
+ 0x67f1f61b,
+ 0x77f126f0,
+ 0x73f00001,
+ 0x026eb900,
+ 0xb90421f4,
+ 0x87fd02d8,
+ 0xf960f905,
+ 0xfcd0fc80,
+ 0x3321f4e0,
+ 0x162067f1,
+ 0xf4026eb9,
+ 0xd8b90421,
+ 0x0587fd02,
+ 0x80f960f9,
+ 0xe0fcd0fc,
+ 0xf13321f4,
+ 0xf00aa277,
+ 0x6eb90073,
+ 0x0421f402,
+ 0xfd02d8b9,
+ 0x60f90587,
+ 0xd0fc80f9,
+ 0x21f4e0fc,
+/* 0x05d3: memx_func_wait_vblank */
+ 0xb600f833,
+ 0x00f80410,
+/* 0x05d8: memx_func_wr32 */
+ 0x98001698,
+ 0x10b60115,
+ 0xf960f908,
+ 0xfcd0fc50,
+ 0x3321f4e0,
+ 0xf40242b6,
+ 0x00f8e91b,
+/* 0x05f4: memx_func_wait */
+ 0xcf2c87f0,
+ 0x1e980088,
+ 0x011d9800,
+ 0x98021c98,
+ 0x10b6031b,
+ 0x8621f410,
+/* 0x060e: memx_func_delay */
+ 0x1e9800f8,
+ 0x0410b600,
+ 0xf86721f4,
+/* 0x0619: memx_func_train */
+/* 0x061b: memx_exec */
+ 0xf900f800,
+ 0xb9d0f9e0,
+ 0xb2b902c1,
+/* 0x0625: memx_exec_next */
+ 0x00139802,
+ 0xe70410b6,
+ 0xe701f034,
+ 0xb601e033,
+ 0x30f00132,
+ 0xde35980c,
+ 0x12b855f9,
+ 0xe41ef406,
+ 0x98f10b98,
+ 0xcbbbf20c,
+ 0xc4b7f102,
+ 0x00bbcf07,
+ 0xe0fcd0fc,
+ 0x02f121f5,
+/* 0x065e: memx_info */
+ 0xc67000f8,
+ 0x0e0bf401,
+/* 0x0664: memx_info_data */
+ 0x03ccc7f1,
+ 0x0800b7f1,
+/* 0x066f: memx_info_train */
+ 0xf10b0ef4,
+ 0xf10bccc7,
+/* 0x0677: memx_info_send */
+ 0xf50100b7,
+ 0xf802f121,
+/* 0x067d: memx_recv */
+ 0x01d6b000,
+ 0xb09b0bf4,
+ 0x0bf400d6,
+/* 0x068b: memx_init */
+ 0xf800f8d8,
+/* 0x068d: perf_recv */
+/* 0x068f: perf_init */
+ 0xf800f800,
+/* 0x0691: i2c_drive_scl */
+ 0x0036b000,
+ 0xf10e0bf4,
+ 0xd007e007,
+ 0x04bd0001,
+/* 0x06a2: i2c_drive_scl_lo */
+ 0x07f100f8,
+ 0x01d007e4,
+ 0xf804bd00,
+/* 0x06ad: i2c_drive_sda */
+ 0x0036b000,
+ 0xf10e0bf4,
+ 0xd007e007,
+ 0x04bd0002,
+/* 0x06be: i2c_drive_sda_lo */
+ 0x07f100f8,
+ 0x02d007e4,
+ 0xf804bd00,
+/* 0x06c9: i2c_sense_scl */
+ 0x0132f400,
+ 0x07c437f1,
+ 0xfd0033cf,
+ 0x0bf40431,
+ 0x0131f406,
+/* 0x06dc: i2c_sense_scl_done */
+/* 0x06de: i2c_sense_sda */
+ 0x32f400f8,
+ 0xc437f101,
+ 0x0033cf07,
+ 0xf40432fd,
+ 0x31f4060b,
+/* 0x06f1: i2c_sense_sda_done */
+/* 0x06f3: i2c_raise_scl */
+ 0xf900f801,
+ 0x9847f140,
+ 0x0137f008,
+ 0x069121f5,
+/* 0x0700: i2c_raise_scl_wait */
+ 0x03e8e7f1,
+ 0xf56721f4,
+ 0xf406c921,
+ 0x42b60901,
+ 0xef1bf401,
+/* 0x0714: i2c_raise_scl_done */
+ 0x00f840fc,
+/* 0x0718: i2c_start */
+ 0x06c921f5,
+ 0xf50d11f4,
+ 0xf406de21,
+ 0x0ef40611,
+/* 0x0729: i2c_start_rep */
+ 0x0037f030,
+ 0x069121f5,
+ 0xf50137f0,
+ 0xbb06ad21,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x06f321f5,
+ 0xf40464b6,
+/* 0x0756: i2c_start_send */
+ 0x37f01f11,
+ 0xad21f500,
+ 0x88e7f106,
+ 0x6721f413,
+ 0xf50037f0,
+ 0xf1069121,
+ 0xf41388e7,
+/* 0x0772: i2c_start_out */
+ 0x00f86721,
+/* 0x0774: i2c_stop */
+ 0xf50037f0,
+ 0xf0069121,
+ 0x21f50037,
+ 0xe7f106ad,
+ 0x21f403e8,
+ 0x0137f067,
+ 0x069121f5,
+ 0x1388e7f1,
+ 0xf06721f4,
+ 0x21f50137,
+ 0xe7f106ad,
+ 0x21f41388,
+/* 0x07a7: i2c_bitw */
+ 0xf500f867,
+ 0xf106ad21,
+ 0xf403e8e7,
+ 0x76bb6721,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb606f321,
+ 0x11f40464,
+ 0x88e7f118,
+ 0x6721f413,
+ 0xf50037f0,
+ 0xf1069121,
+ 0xf41388e7,
+/* 0x07e6: i2c_bitw_out */
+ 0x00f86721,
+/* 0x07e8: i2c_bitr */
+ 0xf50137f0,
+ 0xf106ad21,
+ 0xf403e8e7,
+ 0x76bb6721,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb606f321,
+ 0x11f40464,
+ 0xde21f51b,
+ 0x0037f006,
+ 0x069121f5,
+ 0x1388e7f1,
+ 0xf06721f4,
+ 0x31f4013c,
+/* 0x082d: i2c_bitr_done */
+/* 0x082f: i2c_get_byte */
+ 0xf000f801,
+ 0x47f00057,
+/* 0x0835: i2c_get_byte_next */
+ 0x0154b608,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xe821f550,
+ 0x0464b607,
+ 0xfd2b11f4,
+ 0x42b60553,
+ 0xd81bf401,
+ 0xbb0137f0,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x07a721f5,
+/* 0x087f: i2c_get_byte_done */
+ 0xf80464b6,
+/* 0x0881: i2c_put_byte */
+ 0x0847f000,
+/* 0x0884: i2c_put_byte_next */
+ 0xff0142b6,
+ 0x76bb3854,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb607a721,
+ 0x11f40464,
+ 0x0046b034,
+ 0xbbd81bf4,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x07e821f5,
+ 0xf40464b6,
+ 0x76bb0f11,
+ 0x0136b000,
+ 0xf4061bf4,
+/* 0x08da: i2c_put_byte_done */
+ 0x00f80132,
+/* 0x08dc: i2c_addr */
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x1821f550,
+ 0x0464b607,
+ 0xe72911f4,
+ 0xb6012ec3,
+ 0x53fd0134,
+ 0x0076bb05,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b60881,
+/* 0x0921: i2c_addr_done */
+/* 0x0923: i2c_acquire_addr */
+ 0xc700f804,
+ 0xe4b6f8ce,
+ 0x14e0b705,
+/* 0x092f: i2c_acquire */
+ 0xf500f8d0,
+ 0xf4092321,
+ 0xd9f00421,
+ 0x3321f403,
+/* 0x093e: i2c_release */
+ 0x21f500f8,
+ 0x21f40923,
+ 0x03daf004,
+ 0xf83321f4,
+/* 0x094d: i2c_recv */
+ 0x0132f400,
+ 0xb6f8c1c7,
+ 0x16b00214,
+ 0x3a1ff528,
+ 0xf413a001,
+ 0x0032980c,
+ 0x0ccc13a0,
+ 0xf4003198,
+ 0xd0f90231,
+ 0xd0f9e0f9,
+ 0x000067f1,
+ 0x100063f1,
+ 0xbb016792,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x092f21f5,
+ 0xfc0464b6,
+ 0x00d6b0d0,
+ 0x00b31bf5,
+ 0xbb0057f0,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x08dc21f5,
+ 0xf50464b6,
+ 0xc700d011,
+ 0x76bbe0c5,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb6088121,
+ 0x11f50464,
+ 0x57f000ad,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b608dc,
+ 0x8a11f504,
+ 0x0076bb00,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b6082f,
+ 0x6a11f404,
+ 0xbbe05bcb,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x077421f5,
+ 0xb90464b6,
+ 0x74bd025b,
+/* 0x0a53: i2c_recv_not_rd08 */
+ 0xb0430ef4,
+ 0x1bf401d6,
+ 0x0057f03d,
+ 0x08dc21f5,
+ 0xc73311f4,
+ 0x21f5e0c5,
+ 0x11f40881,
+ 0x0057f029,
+ 0x08dc21f5,
+ 0xc71f11f4,
+ 0x21f5e0b5,
+ 0x11f40881,
+ 0x7421f515,
+ 0xc774bd07,
+ 0x1bf408c5,
+ 0x0232f409,
+/* 0x0a93: i2c_recv_not_wr08 */
+/* 0x0a93: i2c_recv_done */
+ 0xc7030ef4,
+ 0x21f5f8ce,
+ 0xe0fc093e,
+ 0x12f4d0fc,
+ 0x027cb90a,
+ 0x02f121f5,
+/* 0x0aa8: i2c_recv_exit */
+/* 0x0aaa: i2c_init */
+ 0x00f800f8,
+/* 0x0aac: test_recv */
+ 0x05d817f1,
+ 0xb60011cf,
+ 0x07f10110,
+ 0x01d005d8,
+ 0xf104bd00,
+ 0xf1d900e7,
+ 0xf5134fe3,
+ 0xf8022321,
+/* 0x0acd: test_init */
+ 0x00e7f100,
+ 0x2321f508,
+/* 0x0ad7: idle_recv */
+ 0xf800f802,
+/* 0x0ad9: idle */
+ 0x0031f400,
+ 0x05d417f1,
+ 0xb60011cf,
+ 0x07f10110,
+ 0x01d005d4,
+/* 0x0aef: idle_loop */
+ 0xf004bd00,
+ 0x32f45817,
+/* 0x0af5: idle_proc */
+/* 0x0af5: idle_proc_exec */
+ 0xb910f902,
+ 0x21f5021e,
+ 0x10fc02fa,
+ 0xf40911f4,
+ 0x0ef40231,
+/* 0x0b09: idle_proc_next */
+ 0x5810b6ef,
+ 0xf4061fb8,
+ 0x02f4e61b,
+ 0x0028f4dd,
+ 0x00c10ef4,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5
new file mode 100644
index 000000000000..093dc81880f4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GK208
+#define HW_TICKS_PER_US 324
+
+#define NVKM_FALCON_PC24
+#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gk208_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gk208_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
new file mode 100644
index 000000000000..fe4f63deeaab
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gk208.fuc5.h
@@ -0,0 +1,1731 @@
+uint32_t gk208_pmu_data[] = {
+/* 0x0000: proc_kern */
+ 0x52544e49,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: proc_list_head */
+ 0x54534f48,
+ 0x00000453,
+ 0x00000404,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x584d454d,
+ 0x0000062d,
+ 0x0000061f,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x46524550,
+ 0x00000631,
+ 0x0000062f,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x5f433249,
+ 0x00000a35,
+ 0x000008dc,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x54534554,
+ 0x00000a56,
+ 0x00000a37,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x454c4449,
+ 0x00000a61,
+ 0x00000a5f,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+ 0x00000000,
+/* 0x026c: time_next */
+ 0x00000000,
+/* 0x0270: fifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x02f0: rfifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0370: memx_func_head */
+ 0x00000001,
+ 0x00000000,
+ 0x00000483,
+/* 0x037c: memx_func_next */
+ 0x00000002,
+ 0x00000000,
+ 0x00000500,
+ 0x00000003,
+ 0x00000002,
+ 0x00000580,
+ 0x00040004,
+ 0x00000000,
+ 0x0000059d,
+ 0x00010005,
+ 0x00000000,
+ 0x000005b7,
+ 0x00010006,
+ 0x00000000,
+ 0x0000057b,
+ 0x00000007,
+ 0x00000000,
+ 0x000005c3,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+ 0x00000000,
+/* 0x03c8: memx_ts_end */
+ 0x00000000,
+/* 0x03cc: memx_data_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+ 0x00000400,
+ 0x00000800,
+ 0x00001000,
+ 0x00002000,
+ 0x00004000,
+ 0x00008000,
+ 0x00010000,
+ 0x00020000,
+ 0x00040000,
+ 0x00080000,
+/* 0x0cf4: i2c_sda_map */
+ 0x00100000,
+ 0x00200000,
+ 0x00400000,
+ 0x00800000,
+ 0x01000000,
+ 0x02000000,
+ 0x04000000,
+ 0x08000000,
+ 0x10000000,
+ 0x20000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gk208_pmu_code[] = {
+ 0x031c0ef5,
+/* 0x0004: rd32 */
+ 0xf607a040,
+ 0x04bd000e,
+ 0xd3f0010d,
+ 0x07ac4001,
+ 0xbd000df6,
+/* 0x0019: rd32_wait */
+ 0x07ac4d04,
+ 0xf100ddcf,
+ 0xf47000d4,
+ 0xa44df61b,
+ 0x00ddcf07,
+/* 0x002e: wr32 */
+ 0xa04000f8,
+ 0x000ef607,
+ 0xa44004bd,
+ 0x000df607,
+ 0x020d04bd,
+ 0xf0f0d5f0,
+ 0xac4001d3,
+ 0x000df607,
+/* 0x004e: wr32_wait */
+ 0xac4d04bd,
+ 0x00ddcf07,
+ 0x7000d4f1,
+ 0xf8f61bf4,
+/* 0x005d: nsec */
+ 0xf990f900,
+ 0xcf2c0880,
+/* 0x0066: nsec_loop */
+ 0x2c090088,
+ 0xbb0099cf,
+ 0x9ea60298,
+ 0xfcf61ef4,
+ 0xf890fc80,
+/* 0x0079: wait */
+ 0xf990f900,
+ 0xcf2c0880,
+/* 0x0082: wait_loop */
+ 0xeeb20088,
+ 0x0000047e,
+ 0xadfddab2,
+ 0xf4aca604,
+ 0x2c09100b,
+ 0xbb0099cf,
+ 0x9ba60298,
+/* 0x009f: wait_done */
+ 0xfce61ef4,
+ 0xf890fc80,
+/* 0x00a5: intr_watchdog */
+ 0x03e99800,
+ 0xf40096b0,
+ 0x0a98280b,
+ 0x029abb9a,
+ 0x0d0e1cf4,
+ 0x02617e01,
+ 0xf494bd00,
+/* 0x00c2: intr_watchdog_next_time */
+ 0x0a98140e,
+ 0x00a6b09b,
+ 0xa6080bf4,
+ 0x061cf49a,
+/* 0x00d0: intr_watchdog_next_time_set */
+/* 0x00d3: intr_watchdog_next_proc */
+ 0xb59b09b5,
+ 0xe0b603e9,
+ 0x68e6b158,
+ 0xc81bf402,
+/* 0x00e2: intr */
+ 0x00f900f8,
+ 0x80f904bd,
+ 0xa0f990f9,
+ 0xc0f9b0f9,
+ 0xe0f9d0f9,
+ 0x000ff0f9,
+ 0xf90188fe,
+ 0x04504880,
+ 0xb60088cf,
+ 0x50400180,
+ 0x0008f604,
+ 0x080804bd,
+ 0xc40088cf,
+ 0x0bf40289,
+ 0x9b00b51f,
+ 0xa57e580e,
+ 0x09980000,
+ 0x0096b09b,
+ 0x000d0bf4,
+ 0x0009f634,
+ 0x09b504bd,
+/* 0x0135: intr_skip_watchdog */
+ 0x0089e49a,
+ 0x360bf408,
+ 0xcf068849,
+ 0x9ac40099,
+ 0x220bf402,
+ 0xcf04c04c,
+ 0xc0f900cc,
+ 0xf14f484e,
+ 0x0d5453e3,
+ 0x02c27e00,
+ 0x40c0fc00,
+ 0x0cf604c0,
+/* 0x0167: intr_subintr_skip_fifo */
+ 0x4004bd00,
+ 0x09f60688,
+/* 0x016f: intr_skip_subintr */
+ 0xc404bd00,
+ 0x0bf42089,
+ 0xbfa4f107,
+/* 0x0179: intr_skip_pause */
+ 0x4089c4ff,
+ 0xf1070bf4,
+/* 0x0183: intr_skip_user0 */
+ 0x00ffbfa4,
+ 0x0008f604,
+ 0x80fc04bd,
+ 0xfc0088fe,
+ 0xfce0fcf0,
+ 0xfcc0fcd0,
+ 0xfca0fcb0,
+ 0xfc80fc90,
+ 0x0032f400,
+/* 0x01a6: ticks_from_ns */
+ 0xc0f901f8,
+ 0xd7f1b0f9,
+ 0xd3f00144,
+ 0x7721f500,
+ 0xe8ccec03,
+ 0x00b4b003,
+ 0xec120bf4,
+ 0xf103e8ee,
+ 0xf00144d7,
+ 0x21f500d3,
+/* 0x01ce: ticks_from_ns_quit */
+ 0xceb20377,
+ 0xc0fcb0fc,
+/* 0x01d6: ticks_from_us */
+ 0xc0f900f8,
+ 0xd7f1b0f9,
+ 0xd3f00144,
+ 0x7721f500,
+ 0xb0ceb203,
+ 0x0bf400b4,
+/* 0x01ef: ticks_from_us_quit */
+ 0xfce4bd05,
+ 0xf8c0fcb0,
+/* 0x01f5: ticks_to_us */
+ 0x44d7f100,
+ 0x00d3f001,
+ 0xf8ecedff,
+/* 0x0201: timer */
+ 0xf990f900,
+ 0x1032f480,
+ 0xb003f898,
+ 0x1cf40086,
+ 0x0084bd4a,
+ 0x0008f638,
+ 0x340804bd,
+ 0x980088cf,
+ 0x98bb9a09,
+ 0x00e9bb02,
+ 0x0803feb5,
+ 0x0088cf08,
+ 0xf40284f0,
+ 0x34081c1b,
+ 0xa60088cf,
+ 0x080bf4e0,
+ 0x1cf4e8a6,
+/* 0x0245: timer_reset */
+ 0xf634000d,
+ 0x04bd000e,
+/* 0x024f: timer_enable */
+ 0x089a0eb5,
+ 0xf6380001,
+ 0x04bd0008,
+/* 0x0258: timer_done */
+ 0xfc1031f4,
+ 0xf890fc80,
+/* 0x0261: send_proc */
+ 0xf980f900,
+ 0x05e89890,
+ 0xf004e998,
+ 0x89a60486,
+ 0xc42a0bf4,
+ 0x88940398,
+ 0x1880b604,
+ 0x98008ebb,
+ 0x8ab500fa,
+ 0x018db500,
+ 0xb5028cb5,
+ 0x90b6038b,
+ 0x0794f001,
+ 0xf404e9b5,
+/* 0x029a: send_done */
+ 0x90fc0231,
+ 0x00f880fc,
+/* 0x02a0: find */
+ 0x580880f9,
+/* 0x02a7: find_loop */
+ 0x980131f4,
+ 0xaea6008a,
+ 0xb6100bf4,
+ 0x86b15880,
+ 0x1bf40268,
+ 0x0132f4f1,
+/* 0x02bc: find_done */
+ 0x80fc8eb2,
+/* 0x02c2: send */
+ 0xa07e00f8,
+ 0x01f40002,
+/* 0x02cb: recv */
+ 0xf900f89b,
+ 0x9880f990,
+ 0xe99805e8,
+ 0x0132f404,
+ 0x0bf489a6,
+ 0x0389c43c,
+ 0xf00180b6,
+ 0xe8b50784,
+ 0x02ea9805,
+ 0x8ffef0f9,
+ 0xb2f0f901,
+ 0x049994ef,
+ 0xb600e9bb,
+ 0xeb9818e0,
+ 0x02ec9803,
+ 0x9801ed98,
+ 0xa5f900ee,
+ 0xf8fef0fc,
+ 0x0131f400,
+/* 0x0316: recv_done */
+ 0x80fcf0fc,
+ 0x00f890fc,
+/* 0x031c: init */
+ 0xcf010841,
+ 0x11e70011,
+ 0x14b60109,
+ 0x0014fe08,
+ 0xf000e041,
+ 0x1c000013,
+ 0xbd0001f6,
+ 0x00ff0104,
+ 0x0001f614,
+ 0x020104bd,
+ 0x080015f1,
+ 0x01f61000,
+ 0x4104bd00,
+ 0x13f000e2,
+ 0x0010fe00,
+ 0x011031f4,
+ 0xf6380001,
+ 0x04bd0001,
+/* 0x0366: init_proc */
+ 0xf198580f,
+ 0x0016b001,
+ 0xf9fa0bf4,
+ 0x58f0b615,
+/* 0x0377: mulu32_32_64 */
+ 0xf9f20ef4,
+ 0xf920f910,
+ 0x9540f930,
+ 0xd29510e1,
+ 0xbdc4bd10,
+ 0xc0edffb4,
+ 0xb2301dff,
+ 0xff34f134,
+ 0x1034b6ff,
+ 0xbb1045b6,
+ 0xb4bb00c3,
+ 0x30e2ff01,
+ 0x34f134b2,
+ 0x34b6ffff,
+ 0x1045b610,
+ 0xbb00c3bb,
+ 0x12ff01b4,
+ 0x00b3bb30,
+ 0x30fc40fc,
+ 0x10fc20fc,
+/* 0x03c6: host_send */
+ 0xb04100f8,
+ 0x0011cf04,
+ 0xcf04a042,
+ 0x12a60022,
+ 0xc42e0bf4,
+ 0xee94071e,
+ 0x70e0b704,
+ 0x03eb9802,
+ 0x9802ec98,
+ 0xee9801ed,
+ 0x02c27e00,
+ 0x0110b600,
+ 0x400f1ec4,
+ 0x0ef604b0,
+ 0xf404bd00,
+/* 0x0402: host_send_done */
+ 0x00f8c70e,
+/* 0x0404: host_recv */
+ 0xf14e4941,
+ 0xa6525413,
+ 0xb90bf4e1,
+/* 0x0410: host_recv_wait */
+ 0xcf04cc41,
+ 0xc8420011,
+ 0x0022cf04,
+ 0xa60816f0,
+ 0xef0bf412,
+ 0xb60723c4,
+ 0x30b70434,
+ 0x3bb502f0,
+ 0x023cb503,
+ 0xb5013db5,
+ 0x20b6003e,
+ 0x0f24f001,
+ 0xf604c840,
+ 0x04bd0002,
+ 0x00004002,
+ 0xbd0002f6,
+/* 0x0453: host_init */
+ 0x4100f804,
+ 0x14b60080,
+ 0x7015f110,
+ 0x04d04002,
+ 0xbd0001f6,
+ 0x00804104,
+ 0xf11014b6,
+ 0x4002f015,
+ 0x01f604dc,
+ 0x0104bd00,
+ 0x04c44001,
+ 0xbd0001f6,
+/* 0x0483: memx_func_enter */
+ 0xf100f804,
+ 0xf1162067,
+ 0xf1f55d77,
+ 0xb2ffff73,
+ 0x00047e6e,
+ 0xfdd8b200,
+ 0x60f90487,
+ 0xd0fc80f9,
+ 0x2e7ee0fc,
+ 0x77f10000,
+ 0x73f1fffe,
+ 0x6eb2ffff,
+ 0x0000047e,
+ 0x87fdd8b2,
+ 0xf960f904,
+ 0xfcd0fc80,
+ 0x002e7ee0,
+ 0xf067f100,
+ 0x7e6eb226,
+ 0xb2000004,
+ 0x0487fdd8,
+ 0x80f960f9,
+ 0xe0fcd0fc,
+ 0x00002e7e,
+ 0xe0400406,
+ 0x0006f607,
+/* 0x04ea: memx_func_enter_wait */
+ 0xc04604bd,
+ 0x0066cf07,
+ 0xf40464f0,
+ 0x2c06f70b,
+ 0xb50066cf,
+ 0x00f8f106,
+/* 0x0500: memx_func_leave */
+ 0x66cf2c06,
+ 0xf206b500,
+ 0xe4400406,
+ 0x0006f607,
+/* 0x0512: memx_func_leave_wait */
+ 0xc04604bd,
+ 0x0066cf07,
+ 0xf40464f0,
+ 0x67f1f71b,
+ 0x77f126f0,
+ 0x73f00001,
+ 0x7e6eb200,
+ 0xb2000004,
+ 0x0587fdd8,
+ 0x80f960f9,
+ 0xe0fcd0fc,
+ 0x00002e7e,
+ 0x162067f1,
+ 0x047e6eb2,
+ 0xd8b20000,
+ 0xf90587fd,
+ 0xfc80f960,
+ 0x7ee0fcd0,
+ 0xf100002e,
+ 0xf00aa277,
+ 0x6eb20073,
+ 0x0000047e,
+ 0x87fdd8b2,
+ 0xf960f905,
+ 0xfcd0fc80,
+ 0x002e7ee0,
+/* 0x057b: memx_func_wait_vblank */
+ 0xb600f800,
+ 0x00f80410,
+/* 0x0580: memx_func_wr32 */
+ 0x98001698,
+ 0x10b60115,
+ 0xf960f908,
+ 0xfcd0fc50,
+ 0x002e7ee0,
+ 0x0242b600,
+ 0xf8e81bf4,
+/* 0x059d: memx_func_wait */
+ 0xcf2c0800,
+ 0x1e980088,
+ 0x011d9800,
+ 0x98021c98,
+ 0x10b6031b,
+ 0x00797e10,
+/* 0x05b7: memx_func_delay */
+ 0x9800f800,
+ 0x10b6001e,
+ 0x005d7e04,
+/* 0x05c3: memx_func_train */
+ 0xf800f800,
+/* 0x05c5: memx_exec */
+ 0xf9e0f900,
+ 0xb2c1b2d0,
+/* 0x05cd: memx_exec_next */
+ 0x001398b2,
+ 0xe70410b6,
+ 0xe701f034,
+ 0xb601e033,
+ 0x30f00132,
+ 0xde35980c,
+ 0x12a655f9,
+ 0x98e51ef4,
+ 0x0c98f10b,
+ 0x02cbbbf2,
+ 0xcf07c44b,
+ 0xd0fc00bb,
+ 0xc27ee0fc,
+ 0x00f80002,
+/* 0x0604: memx_info */
+ 0xf401c670,
+/* 0x060a: memx_info_data */
+ 0xcc4c0c0b,
+ 0x08004b03,
+/* 0x0613: memx_info_train */
+ 0x4c090ef4,
+ 0x004b0bcc,
+/* 0x0619: memx_info_send */
+ 0x02c27e01,
+/* 0x061f: memx_recv */
+ 0xb000f800,
+ 0x0bf401d6,
+ 0x00d6b0a3,
+ 0xf8dc0bf4,
+/* 0x062d: memx_init */
+/* 0x062f: perf_recv */
+ 0xf800f800,
+/* 0x0631: perf_init */
+/* 0x0633: i2c_drive_scl */
+ 0xb000f800,
+ 0x0bf40036,
+ 0x07e0400d,
+ 0xbd0001f6,
+/* 0x0643: i2c_drive_scl_lo */
+ 0x4000f804,
+ 0x01f607e4,
+ 0xf804bd00,
+/* 0x064d: i2c_drive_sda */
+ 0x0036b000,
+ 0x400d0bf4,
+ 0x02f607e0,
+ 0xf804bd00,
+/* 0x065d: i2c_drive_sda_lo */
+ 0x07e44000,
+ 0xbd0002f6,
+/* 0x0667: i2c_sense_scl */
+ 0xf400f804,
+ 0xc4430132,
+ 0x0033cf07,
+ 0xf40431fd,
+ 0x31f4060b,
+/* 0x0679: i2c_sense_scl_done */
+/* 0x067b: i2c_sense_sda */
+ 0xf400f801,
+ 0xc4430132,
+ 0x0033cf07,
+ 0xf40432fd,
+ 0x31f4060b,
+/* 0x068d: i2c_sense_sda_done */
+/* 0x068f: i2c_raise_scl */
+ 0xf900f801,
+ 0x08984440,
+ 0x337e0103,
+/* 0x069a: i2c_raise_scl_wait */
+ 0xe84e0006,
+ 0x005d7e03,
+ 0x06677e00,
+ 0x0901f400,
+ 0xf40142b6,
+/* 0x06ae: i2c_raise_scl_done */
+ 0x40fcef1b,
+/* 0x06b2: i2c_start */
+ 0x677e00f8,
+ 0x11f40006,
+ 0x067b7e0d,
+ 0x0611f400,
+/* 0x06c3: i2c_start_rep */
+ 0x032e0ef4,
+ 0x06337e00,
+ 0x7e010300,
+ 0xbb00064d,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x00068f7e,
+ 0xf40464b6,
+/* 0x06ee: i2c_start_send */
+ 0x00031d11,
+ 0x00064d7e,
+ 0x7e13884e,
+ 0x0300005d,
+ 0x06337e00,
+ 0x13884e00,
+ 0x00005d7e,
+/* 0x0708: i2c_start_out */
+/* 0x070a: i2c_stop */
+ 0x000300f8,
+ 0x0006337e,
+ 0x4d7e0003,
+ 0xe84e0006,
+ 0x005d7e03,
+ 0x7e010300,
+ 0x4e000633,
+ 0x5d7e1388,
+ 0x01030000,
+ 0x00064d7e,
+ 0x7e13884e,
+ 0xf800005d,
+/* 0x0739: i2c_bitw */
+ 0x064d7e00,
+ 0x03e84e00,
+ 0x00005d7e,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x068f7e50,
+ 0x0464b600,
+ 0x4e1711f4,
+ 0x5d7e1388,
+ 0x00030000,
+ 0x0006337e,
+ 0x7e13884e,
+/* 0x0777: i2c_bitw_out */
+ 0xf800005d,
+/* 0x0779: i2c_bitr */
+ 0x7e010300,
+ 0x4e00064d,
+ 0x5d7e03e8,
+ 0x76bb0000,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0x7e50fc04,
+ 0xb600068f,
+ 0x11f40464,
+ 0x067b7e1a,
+ 0x7e000300,
+ 0x4e000633,
+ 0x5d7e1388,
+ 0x3cf00000,
+ 0x0131f401,
+/* 0x07bc: i2c_bitr_done */
+/* 0x07be: i2c_get_byte */
+ 0x000500f8,
+/* 0x07c2: i2c_get_byte_next */
+ 0x54b60804,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x797e50fc,
+ 0x64b60007,
+ 0x2a11f404,
+ 0xb60553fd,
+ 0x1bf40142,
+ 0xbb0103d8,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x0007397e,
+/* 0x080b: i2c_get_byte_done */
+ 0xf80464b6,
+/* 0x080d: i2c_put_byte */
+/* 0x080f: i2c_put_byte_next */
+ 0xb6080400,
+ 0x54ff0142,
+ 0x0076bb38,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x397e50fc,
+ 0x64b60007,
+ 0x3411f404,
+ 0xf40046b0,
+ 0x76bbd81b,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0x7e50fc04,
+ 0xb6000779,
+ 0x11f40464,
+ 0x0076bb0f,
+ 0xf40136b0,
+ 0x32f4061b,
+/* 0x0865: i2c_put_byte_done */
+/* 0x0867: i2c_addr */
+ 0xbb00f801,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x0006b27e,
+ 0xf40464b6,
+ 0xc3e72911,
+ 0x34b6012e,
+ 0x0553fd01,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x080d7e50,
+ 0x0464b600,
+/* 0x08ac: i2c_addr_done */
+/* 0x08ae: i2c_acquire_addr */
+ 0xcec700f8,
+ 0x05e4b6f8,
+ 0xd014e0b7,
+/* 0x08ba: i2c_acquire */
+ 0xae7e00f8,
+ 0x047e0008,
+ 0xd9f00000,
+ 0x002e7e03,
+/* 0x08cb: i2c_release */
+ 0x7e00f800,
+ 0x7e0008ae,
+ 0xf0000004,
+ 0x2e7e03da,
+ 0x00f80000,
+/* 0x08dc: i2c_recv */
+ 0xc70132f4,
+ 0x14b6f8c1,
+ 0x2816b002,
+ 0x01371ff5,
+ 0x0cf413b8,
+ 0x00329800,
+ 0x0ccc13b8,
+ 0x00319800,
+ 0xf90231f4,
+ 0xf9e0f9d0,
+ 0x0067f1d0,
+ 0x0063f100,
+ 0x01679210,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x08ba7e50,
+ 0x0464b600,
+ 0xd6b0d0fc,
+ 0xb01bf500,
+ 0xbb000500,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x0008677e,
+ 0xf50464b6,
+ 0xc700cc11,
+ 0x76bbe0c5,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0x7e50fc04,
+ 0xb600080d,
+ 0x11f50464,
+ 0x010500a9,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x08677e50,
+ 0x0464b600,
+ 0x008711f5,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x07be7e50,
+ 0x0464b600,
+ 0xcb6711f4,
+ 0x76bbe05b,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0x7e50fc04,
+ 0xb600070a,
+ 0x5bb20464,
+ 0x0ef474bd,
+/* 0x09e1: i2c_recv_not_rd08 */
+ 0x01d6b041,
+ 0x053b1bf4,
+ 0x08677e00,
+ 0x3211f400,
+ 0x7ee0c5c7,
+ 0xf400080d,
+ 0x00052811,
+ 0x0008677e,
+ 0xc71f11f4,
+ 0x0d7ee0b5,
+ 0x11f40008,
+ 0x070a7e15,
+ 0xc774bd00,
+ 0x1bf408c5,
+ 0x0232f409,
+/* 0x0a1f: i2c_recv_not_wr08 */
+/* 0x0a1f: i2c_recv_done */
+ 0xc7030ef4,
+ 0xcb7ef8ce,
+ 0xe0fc0008,
+ 0x12f4d0fc,
+ 0x7e7cb209,
+/* 0x0a33: i2c_recv_exit */
+ 0xf80002c2,
+/* 0x0a35: i2c_init */
+/* 0x0a37: test_recv */
+ 0x4100f800,
+ 0x11cf0458,
+ 0x0110b600,
+ 0xf6045840,
+ 0x04bd0001,
+ 0xd900e7f1,
+ 0x134fe3f1,
+ 0x0002017e,
+/* 0x0a56: test_init */
+ 0x004e00f8,
+ 0x02017e08,
+/* 0x0a5f: idle_recv */
+ 0xf800f800,
+/* 0x0a61: idle */
+ 0x0031f400,
+ 0xcf045441,
+ 0x10b60011,
+ 0x04544001,
+ 0xbd0001f6,
+/* 0x0a75: idle_loop */
+ 0xf4580104,
+/* 0x0a7a: idle_proc */
+/* 0x0a7a: idle_proc_exec */
+ 0x10f90232,
+ 0xcb7e1eb2,
+ 0x10fc0002,
+ 0xf40911f4,
+ 0x0ef40231,
+/* 0x0a8d: idle_proc_next */
+ 0x5810b6f0,
+ 0x1bf41fa6,
+ 0xe002f4e8,
+ 0xf40028f4,
+ 0x0000c60e,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3 b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3
new file mode 100644
index 000000000000..393049fc8b2d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+
+#define NVKM_PPWR_CHIPSET GT215
+#define HW_TICKS_PER_US 203 // should be 202.5
+
+//#define NVKM_FALCON_PC24
+//#define NVKM_FALCON_UNSHIFTED_IO
+//#define NVKM_FALCON_MMIO_UAS
+//#define NVKM_FALCON_MMIO_TRAP
+
+#include "macros.fuc"
+
+.section #gt215_pmu_data
+#define INCLUDE_PROC
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_PROC
+
+#define INCLUDE_DATA
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_DATA
+.align 256
+
+.section #gt215_pmu_code
+#define INCLUDE_CODE
+#include "kernel.fuc"
+#include "arith.fuc"
+#include "host.fuc"
+#include "memx.fuc"
+#include "perf.fuc"
+#include "i2c_.fuc"
+#include "test.fuc"
+#include "idle.fuc"
+#undef INCLUDE_CODE
+.align 256
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
new file mode 100644
index 000000000000..2686f8fad0f5
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/gt215.fuc3.h
@@ -0,0 +1,1868 @@
+uint32_t gt215_pmu_data[] = {
+/* 0x0000: proc_kern */
+ 0x52544e49,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0058: proc_list_head */
+ 0x54534f48,
+ 0x00000512,
+ 0x000004af,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x584d454d,
+ 0x00000842,
+ 0x00000834,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x46524550,
+ 0x00000846,
+ 0x00000844,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x5f433249,
+ 0x00000c76,
+ 0x00000b19,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x54534554,
+ 0x00000c9f,
+ 0x00000c78,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x454c4449,
+ 0x00000cab,
+ 0x00000ca9,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0268: proc_list_tail */
+/* 0x0268: time_prev */
+ 0x00000000,
+/* 0x026c: time_next */
+ 0x00000000,
+/* 0x0270: fifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x02f0: rfifo_queue */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0370: memx_func_head */
+ 0x00000001,
+ 0x00000000,
+ 0x00000551,
+/* 0x037c: memx_func_next */
+ 0x00000002,
+ 0x00000000,
+ 0x000005a8,
+ 0x00000003,
+ 0x00000002,
+ 0x0000063a,
+ 0x00040004,
+ 0x00000000,
+ 0x00000656,
+ 0x00010005,
+ 0x00000000,
+ 0x00000673,
+ 0x00010006,
+ 0x00000000,
+ 0x000005f8,
+ 0x00000007,
+ 0x00000000,
+ 0x0000067e,
+/* 0x03c4: memx_func_tail */
+/* 0x03c4: memx_ts_start */
+ 0x00000000,
+/* 0x03c8: memx_ts_end */
+ 0x00000000,
+/* 0x03cc: memx_data_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0bcc: memx_data_tail */
+/* 0x0bcc: memx_train_head */
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+/* 0x0ccc: memx_train_tail */
+/* 0x0ccc: i2c_scl_map */
+ 0x00001000,
+ 0x00004000,
+ 0x00010000,
+ 0x00000100,
+ 0x00040000,
+ 0x00100000,
+ 0x00400000,
+ 0x01000000,
+ 0x04000000,
+ 0x10000000,
+/* 0x0cf4: i2c_sda_map */
+ 0x00002000,
+ 0x00008000,
+ 0x00020000,
+ 0x00000200,
+ 0x00080000,
+ 0x00200000,
+ 0x00800000,
+ 0x02000000,
+ 0x08000000,
+ 0x20000000,
+/* 0x0d1c: i2c_ctrl */
+ 0x0000e138,
+ 0x0000e150,
+ 0x0000e168,
+ 0x0000e180,
+ 0x0000e254,
+ 0x0000e274,
+ 0x0000e764,
+ 0x0000e780,
+ 0x0000e79c,
+ 0x0000e7b8,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
+
+uint32_t gt215_pmu_code[] = {
+ 0x039e0ef5,
+/* 0x0004: rd32 */
+ 0x07a007f1,
+ 0xd00604b6,
+ 0x04bd000e,
+ 0xf001d7f0,
+ 0x07f101d3,
+ 0x04b607ac,
+ 0x000dd006,
+/* 0x0022: rd32_wait */
+ 0xd7f104bd,
+ 0xd4b607ac,
+ 0x00ddcf06,
+ 0x7000d4f1,
+ 0xf1f21bf4,
+ 0xb607a4d7,
+ 0xddcf06d4,
+/* 0x003f: wr32 */
+ 0xf100f800,
+ 0xb607a007,
+ 0x0ed00604,
+ 0xf104bd00,
+ 0xb607a407,
+ 0x0dd00604,
+ 0xf004bd00,
+ 0xd5f002d7,
+ 0x01d3f0f0,
+ 0x07ac07f1,
+ 0xd00604b6,
+ 0x04bd000d,
+/* 0x006c: wr32_wait */
+ 0x07acd7f1,
+ 0xcf06d4b6,
+ 0xd4f100dd,
+ 0x1bf47000,
+/* 0x007f: nsec */
+ 0xf900f8f2,
+ 0xf080f990,
+ 0x84b62c87,
+ 0x0088cf06,
+/* 0x008c: nsec_loop */
+ 0xb62c97f0,
+ 0x99cf0694,
+ 0x0298bb00,
+ 0xf4069eb8,
+ 0x80fcf11e,
+ 0x00f890fc,
+/* 0x00a4: wait */
+ 0x80f990f9,
+ 0xb62c87f0,
+ 0x88cf0684,
+/* 0x00b1: wait_loop */
+ 0x02eeb900,
+ 0xb90421f4,
+ 0xadfd02da,
+ 0x06acb804,
+ 0xf0150bf4,
+ 0x94b62c97,
+ 0x0099cf06,
+ 0xb80298bb,
+ 0x1ef4069b,
+/* 0x00d5: wait_done */
+ 0xfc80fcdf,
+/* 0x00db: intr_watchdog */
+ 0x9800f890,
+ 0x96b003e9,
+ 0x2a0bf400,
+ 0xbb9a0a98,
+ 0x1cf4029a,
+ 0x01d7f00f,
+ 0x02dd21f5,
+ 0x0ef494bd,
+/* 0x00f9: intr_watchdog_next_time */
+ 0x9b0a9815,
+ 0xf400a6b0,
+ 0x9ab8090b,
+ 0x061cf406,
+/* 0x0108: intr_watchdog_next_time_set */
+/* 0x010b: intr_watchdog_next_proc */
+ 0x809b0980,
+ 0xe0b603e9,
+ 0x68e6b158,
+ 0xc61bf402,
+/* 0x011a: intr */
+ 0x00f900f8,
+ 0x80f904bd,
+ 0xa0f990f9,
+ 0xc0f9b0f9,
+ 0xe0f9d0f9,
+ 0xf7f0f0f9,
+ 0x0188fe00,
+ 0x87f180f9,
+ 0x84b605d0,
+ 0x0088cf06,
+ 0xf10180b6,
+ 0xb605d007,
+ 0x08d00604,
+ 0xf004bd00,
+ 0x84b60887,
+ 0x0088cf06,
+ 0xf40289c4,
+ 0x0080230b,
+ 0x58e7f09b,
+ 0x98db21f4,
+ 0x96b09b09,
+ 0x110bf400,
+ 0xb63407f0,
+ 0x09d00604,
+ 0x8004bd00,
+/* 0x017e: intr_skip_watchdog */
+ 0x89e49a09,
+ 0x0bf40800,
+ 0x8897f148,
+ 0x0694b606,
+ 0xc40099cf,
+ 0x0bf4029a,
+ 0xc0c7f12c,
+ 0x06c4b604,
+ 0xf900cccf,
+ 0x48e7f1c0,
+ 0x53e3f14f,
+ 0x00d7f054,
+ 0x034221f5,
+ 0x07f1c0fc,
+ 0x04b604c0,
+ 0x000cd006,
+/* 0x01be: intr_subintr_skip_fifo */
+ 0x07f104bd,
+ 0x04b60688,
+ 0x0009d006,
+/* 0x01ca: intr_skip_subintr */
+ 0x89c404bd,
+ 0x070bf420,
+ 0xffbfa4f1,
+/* 0x01d4: intr_skip_pause */
+ 0xf44089c4,
+ 0xa4f1070b,
+/* 0x01de: intr_skip_user0 */
+ 0x07f0ffbf,
+ 0x0604b604,
+ 0xbd0008d0,
+ 0xfe80fc04,
+ 0xf0fc0088,
+ 0xd0fce0fc,
+ 0xb0fcc0fc,
+ 0x90fca0fc,
+ 0x00fc80fc,
+ 0xf80032f4,
+/* 0x0205: ticks_from_ns */
+ 0xf9c0f901,
+ 0xcbd7f1b0,
+ 0x00d3f000,
+ 0x041321f5,
+ 0x03e8ccec,
+ 0xf400b4b0,
+ 0xeeec120b,
+ 0xd7f103e8,
+ 0xd3f000cb,
+ 0x1321f500,
+/* 0x022d: ticks_from_ns_quit */
+ 0x02ceb904,
+ 0xc0fcb0fc,
+/* 0x0236: ticks_from_us */
+ 0xc0f900f8,
+ 0xd7f1b0f9,
+ 0xd3f000cb,
+ 0x1321f500,
+ 0x02ceb904,
+ 0xf400b4b0,
+ 0xe4bd050b,
+/* 0x0250: ticks_from_us_quit */
+ 0xc0fcb0fc,
+/* 0x0256: ticks_to_us */
+ 0xd7f100f8,
+ 0xd3f000cb,
+ 0xecedff00,
+/* 0x0262: timer */
+ 0x90f900f8,
+ 0x32f480f9,
+ 0x03f89810,
+ 0xf40086b0,
+ 0x84bd651c,
+ 0xb63807f0,
+ 0x08d00604,
+ 0xf004bd00,
+ 0x84b63487,
+ 0x0088cf06,
+ 0xbb9a0998,
+ 0xe9bb0298,
+ 0x03fe8000,
+ 0xb60887f0,
+ 0x88cf0684,
+ 0x0284f000,
+ 0xf0261bf4,
+ 0x84b63487,
+ 0x0088cf06,
+ 0xf406e0b8,
+ 0xe8b8090b,
+ 0x111cf406,
+/* 0x02b8: timer_reset */
+ 0xb63407f0,
+ 0x0ed00604,
+ 0x8004bd00,
+/* 0x02c6: timer_enable */
+ 0x87f09a0e,
+ 0x3807f001,
+ 0xd00604b6,
+ 0x04bd0008,
+/* 0x02d4: timer_done */
+ 0xfc1031f4,
+ 0xf890fc80,
+/* 0x02dd: send_proc */
+ 0xf980f900,
+ 0x05e89890,
+ 0xf004e998,
+ 0x89b80486,
+ 0x2a0bf406,
+ 0x940398c4,
+ 0x80b60488,
+ 0x008ebb18,
+ 0x8000fa98,
+ 0x8d80008a,
+ 0x028c8001,
+ 0xb6038b80,
+ 0x94f00190,
+ 0x04e98007,
+/* 0x0317: send_done */
+ 0xfc0231f4,
+ 0xf880fc90,
+/* 0x031d: find */
+ 0xf080f900,
+ 0x31f45887,
+/* 0x0325: find_loop */
+ 0x008a9801,
+ 0xf406aeb8,
+ 0x80b6100b,
+ 0x6886b158,
+ 0xf01bf402,
+/* 0x033b: find_done */
+ 0xb90132f4,
+ 0x80fc028e,
+/* 0x0342: send */
+ 0x21f500f8,
+ 0x01f4031d,
+/* 0x034b: recv */
+ 0xf900f897,
+ 0x9880f990,
+ 0xe99805e8,
+ 0x0132f404,
+ 0xf40689b8,
+ 0x89c43d0b,
+ 0x0180b603,
+ 0x800784f0,
+ 0xea9805e8,
+ 0xfef0f902,
+ 0xf0f9018f,
+ 0x9402efb9,
+ 0xe9bb0499,
+ 0x18e0b600,
+ 0x9803eb98,
+ 0xed9802ec,
+ 0x00ee9801,
+ 0xf0fca5f9,
+ 0xf400f8fe,
+ 0xf0fc0131,
+/* 0x0398: recv_done */
+ 0x90fc80fc,
+/* 0x039e: init */
+ 0x17f100f8,
+ 0x14b60108,
+ 0x0011cf06,
+ 0x010911e7,
+ 0xfe0814b6,
+ 0x17f10014,
+ 0x13f000e0,
+ 0x1c07f000,
+ 0xd00604b6,
+ 0x04bd0001,
+ 0xf0ff17f0,
+ 0x04b61407,
+ 0x0001d006,
+ 0x17f004bd,
+ 0x0015f102,
+ 0x1007f008,
+ 0xd00604b6,
+ 0x04bd0001,
+ 0x011a17f1,
+ 0xfe0013f0,
+ 0x31f40010,
+ 0x0117f010,
+ 0xb63807f0,
+ 0x01d00604,
+ 0xf004bd00,
+/* 0x0402: init_proc */
+ 0xf19858f7,
+ 0x0016b001,
+ 0xf9fa0bf4,
+ 0x58f0b615,
+/* 0x0413: mulu32_32_64 */
+ 0xf9f20ef4,
+ 0xf920f910,
+ 0x9540f930,
+ 0xd29510e1,
+ 0xbdc4bd10,
+ 0xc0edffb4,
+ 0xb9301dff,
+ 0x34f10234,
+ 0x34b6ffff,
+ 0x1045b610,
+ 0xbb00c3bb,
+ 0xe2ff01b4,
+ 0x0234b930,
+ 0xffff34f1,
+ 0xb61034b6,
+ 0xc3bb1045,
+ 0x01b4bb00,
+ 0xbb3012ff,
+ 0x40fc00b3,
+ 0x20fc30fc,
+ 0x00f810fc,
+/* 0x0464: host_send */
+ 0x04b017f1,
+ 0xcf0614b6,
+ 0x27f10011,
+ 0x24b604a0,
+ 0x0022cf06,
+ 0xf40612b8,
+ 0x1ec4320b,
+ 0x04ee9407,
+ 0x0270e0b7,
+ 0x9803eb98,
+ 0xed9802ec,
+ 0x00ee9801,
+ 0x034221f5,
+ 0xc40110b6,
+ 0x07f10f1e,
+ 0x04b604b0,
+ 0x000ed006,
+ 0x0ef404bd,
+/* 0x04ad: host_send_done */
+/* 0x04af: host_recv */
+ 0xf100f8ba,
+ 0xf14e4917,
+ 0xb8525413,
+ 0x0bf406e1,
+/* 0x04bd: host_recv_wait */
+ 0xcc17f1aa,
+ 0x0614b604,
+ 0xf10011cf,
+ 0xb604c827,
+ 0x22cf0624,
+ 0x0816f000,
+ 0xf40612b8,
+ 0x23c4e60b,
+ 0x0434b607,
+ 0x02f030b7,
+ 0x80033b80,
+ 0x3d80023c,
+ 0x003e8001,
+ 0xf00120b6,
+ 0x07f10f24,
+ 0x04b604c8,
+ 0x0002d006,
+ 0x27f004bd,
+ 0x0007f040,
+ 0xd00604b6,
+ 0x04bd0002,
+/* 0x0512: host_init */
+ 0x17f100f8,
+ 0x14b60080,
+ 0x7015f110,
+ 0xd007f102,
+ 0x0604b604,
+ 0xbd0001d0,
+ 0x8017f104,
+ 0x1014b600,
+ 0x02f015f1,
+ 0x04dc07f1,
+ 0xd00604b6,
+ 0x04bd0001,
+ 0xf10117f0,
+ 0xb604c407,
+ 0x01d00604,
+ 0xf804bd00,
+/* 0x0551: memx_func_enter */
+ 0x1087f100,
+ 0x028eb916,
+ 0xb90421f4,
+ 0x67f102d7,
+ 0x63f1fffc,
+ 0x76fdffff,
+ 0x0267f104,
+ 0x0576fd00,
+ 0x70f980f9,
+ 0xe0fcd0fc,
+ 0xf03f21f4,
+ 0x07f10467,
+ 0x04b607e0,
+ 0x0006d006,
+/* 0x058a: memx_func_enter_wait */
+ 0x67f104bd,
+ 0x64b607c0,
+ 0x0066cf06,
+ 0xf40464f0,
+ 0x67f0f30b,
+ 0x0664b62c,
+ 0x800066cf,
+ 0x00f8f106,
+/* 0x05a8: memx_func_leave */
+ 0xb62c67f0,
+ 0x66cf0664,
+ 0xf2068000,
+ 0xf10467f0,
+ 0xb607e407,
+ 0x06d00604,
+/* 0x05c3: memx_func_leave_wait */
+ 0xf104bd00,
+ 0xb607c067,
+ 0x66cf0664,
+ 0x0464f000,
+ 0xf1f31bf4,
+ 0xb9161087,
+ 0x21f4028e,
+ 0x02d7b904,
+ 0xffcc67f1,
+ 0xffff63f1,
+ 0xf90476fd,
+ 0xfc70f980,
+ 0xf4e0fcd0,
+ 0x00f83f21,
+/* 0x05f8: memx_func_wait_vblank */
+ 0xb0001698,
+ 0x0bf40066,
+ 0x0166b013,
+ 0xf4060bf4,
+/* 0x060a: memx_func_wait_vblank_head1 */
+ 0x77f12e0e,
+ 0x0ef40020,
+/* 0x0611: memx_func_wait_vblank_head0 */
+ 0x0877f107,
+/* 0x0615: memx_func_wait_vblank_0 */
+ 0xc467f100,
+ 0x0664b607,
+ 0xfd0066cf,
+ 0x1bf40467,
+/* 0x0625: memx_func_wait_vblank_1 */
+ 0xc467f1f3,
+ 0x0664b607,
+ 0xfd0066cf,
+ 0x0bf40467,
+/* 0x0635: memx_func_wait_vblank_fini */
+ 0x0410b6f3,
+/* 0x063a: memx_func_wr32 */
+ 0x169800f8,
+ 0x01159800,
+ 0xf90810b6,
+ 0xfc50f960,
+ 0xf4e0fcd0,
+ 0x42b63f21,
+ 0xe91bf402,
+/* 0x0656: memx_func_wait */
+ 0x87f000f8,
+ 0x0684b62c,
+ 0x980088cf,
+ 0x1d98001e,
+ 0x021c9801,
+ 0xb6031b98,
+ 0x21f41010,
+/* 0x0673: memx_func_delay */
+ 0x9800f8a4,
+ 0x10b6001e,
+ 0x7f21f404,
+/* 0x067e: memx_func_train */
+ 0x57f100f8,
+ 0x77f10003,
+ 0x97f10000,
+ 0x93f00000,
+ 0x029eb970,
+ 0xb90421f4,
+ 0xe7f102d8,
+ 0x21f42710,
+/* 0x069d: memx_func_train_loop_outer */
+ 0x0158e07f,
+ 0x0083f101,
+ 0xe097f102,
+ 0x1193f011,
+ 0x80f990f9,
+ 0xe0fcd0fc,
+ 0xf93f21f4,
+ 0x0067f150,
+/* 0x06bd: memx_func_train_loop_inner */
+ 0x1187f100,
+ 0x9068ff11,
+ 0xfd109894,
+ 0x97f10589,
+ 0x93f00720,
+ 0xf990f910,
+ 0xfcd0fc80,
+ 0x3f21f4e0,
+ 0x008097f1,
+ 0xb91093f0,
+ 0x21f4029e,
+ 0x02d8b904,
+ 0xf92088c5,
+ 0xfc80f990,
+ 0xf4e0fcd0,
+ 0x97f13f21,
+ 0x93f0053c,
+ 0x0287f110,
+ 0x0083f130,
+ 0xf990f980,
+ 0xfcd0fc80,
+ 0x3f21f4e0,
+ 0x0560e7f1,
+ 0xf110e3f0,
+ 0xf10000d7,
+ 0x908000d3,
+ 0xb7f100dc,
+ 0xb3f08480,
+ 0xa421f41e,
+ 0x000057f1,
+ 0xffff97f1,
+ 0x830093f1,
+/* 0x073c: memx_func_train_loop_4x */
+ 0x0080a7f1,
+ 0xb910a3f0,
+ 0x21f402ae,
+ 0x02d8b904,
+ 0xffdfb7f1,
+ 0xffffb3f1,
+ 0xf9048bfd,
+ 0xfc80f9a0,
+ 0xf4e0fcd0,
+ 0xa7f13f21,
+ 0xa3f0053c,
+ 0x0287f110,
+ 0x0083f130,
+ 0xf9a0f980,
+ 0xfcd0fc80,
+ 0x3f21f4e0,
+ 0x0560e7f1,
+ 0xf110e3f0,
+ 0xf10000d7,
+ 0xb98000d3,
+ 0xb7f102dc,
+ 0xb3f02710,
+ 0xa421f400,
+ 0xf402eeb9,
+ 0xddb90421,
+ 0x949dff02,
+ 0x700150b6,
+ 0x1ef40456,
+ 0xcc7aa092,
+ 0x00a9800b,
+ 0xb60160b6,
+ 0x66700470,
+ 0x001ef510,
+ 0xb650fcff,
+ 0x56700150,
+ 0xd41ef507,
+/* 0x07cf: memx_exec */
+ 0xf900f8fe,
+ 0xb9d0f9e0,
+ 0xb2b902c1,
+/* 0x07d9: memx_exec_next */
+ 0x00139802,
+ 0xe70410b6,
+ 0xe701f034,
+ 0xb601e033,
+ 0x30f00132,
+ 0xde35980c,
+ 0x12b855f9,
+ 0xe41ef406,
+ 0x98f10b98,
+ 0xcbbbf20c,
+ 0xc4b7f102,
+ 0x06b4b607,
+ 0xfc00bbcf,
+ 0xf5e0fcd0,
+ 0xf8034221,
+/* 0x0815: memx_info */
+ 0x01c67000,
+/* 0x081b: memx_info_data */
+ 0xf10e0bf4,
+ 0xf103ccc7,
+ 0xf40800b7,
+/* 0x0826: memx_info_train */
+ 0xc7f10b0e,
+ 0xb7f10bcc,
+/* 0x082e: memx_info_send */
+ 0x21f50100,
+ 0x00f80342,
+/* 0x0834: memx_recv */
+ 0xf401d6b0,
+ 0xd6b0980b,
+ 0xd80bf400,
+/* 0x0842: memx_init */
+ 0x00f800f8,
+/* 0x0844: perf_recv */
+/* 0x0846: perf_init */
+ 0x00f800f8,
+/* 0x0848: i2c_drive_scl */
+ 0xf40036b0,
+ 0x07f1110b,
+ 0x04b607e0,
+ 0x0001d006,
+ 0x00f804bd,
+/* 0x085c: i2c_drive_scl_lo */
+ 0x07e407f1,
+ 0xd00604b6,
+ 0x04bd0001,
+/* 0x086a: i2c_drive_sda */
+ 0x36b000f8,
+ 0x110bf400,
+ 0x07e007f1,
+ 0xd00604b6,
+ 0x04bd0002,
+/* 0x087e: i2c_drive_sda_lo */
+ 0x07f100f8,
+ 0x04b607e4,
+ 0x0002d006,
+ 0x00f804bd,
+/* 0x088c: i2c_sense_scl */
+ 0xf10132f4,
+ 0xb607c437,
+ 0x33cf0634,
+ 0x0431fd00,
+ 0xf4060bf4,
+/* 0x08a2: i2c_sense_scl_done */
+ 0x00f80131,
+/* 0x08a4: i2c_sense_sda */
+ 0xf10132f4,
+ 0xb607c437,
+ 0x33cf0634,
+ 0x0432fd00,
+ 0xf4060bf4,
+/* 0x08ba: i2c_sense_sda_done */
+ 0x00f80131,
+/* 0x08bc: i2c_raise_scl */
+ 0x47f140f9,
+ 0x37f00898,
+ 0x4821f501,
+/* 0x08c9: i2c_raise_scl_wait */
+ 0xe8e7f108,
+ 0x7f21f403,
+ 0x088c21f5,
+ 0xb60901f4,
+ 0x1bf40142,
+/* 0x08dd: i2c_raise_scl_done */
+ 0xf840fcef,
+/* 0x08e1: i2c_start */
+ 0x8c21f500,
+ 0x0d11f408,
+ 0x08a421f5,
+ 0xf40611f4,
+/* 0x08f2: i2c_start_rep */
+ 0x37f0300e,
+ 0x4821f500,
+ 0x0137f008,
+ 0x086a21f5,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xbc21f550,
+ 0x0464b608,
+/* 0x091f: i2c_start_send */
+ 0xf01f11f4,
+ 0x21f50037,
+ 0xe7f1086a,
+ 0x21f41388,
+ 0x0037f07f,
+ 0x084821f5,
+ 0x1388e7f1,
+/* 0x093b: i2c_start_out */
+ 0xf87f21f4,
+/* 0x093d: i2c_stop */
+ 0x0037f000,
+ 0x084821f5,
+ 0xf50037f0,
+ 0xf1086a21,
+ 0xf403e8e7,
+ 0x37f07f21,
+ 0x4821f501,
+ 0x88e7f108,
+ 0x7f21f413,
+ 0xf50137f0,
+ 0xf1086a21,
+ 0xf41388e7,
+ 0x00f87f21,
+/* 0x0970: i2c_bitw */
+ 0x086a21f5,
+ 0x03e8e7f1,
+ 0xbb7f21f4,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x08bc21f5,
+ 0xf40464b6,
+ 0xe7f11811,
+ 0x21f41388,
+ 0x0037f07f,
+ 0x084821f5,
+ 0x1388e7f1,
+/* 0x09af: i2c_bitw_out */
+ 0xf87f21f4,
+/* 0x09b1: i2c_bitr */
+ 0x0137f000,
+ 0x086a21f5,
+ 0x03e8e7f1,
+ 0xbb7f21f4,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x08bc21f5,
+ 0xf40464b6,
+ 0x21f51b11,
+ 0x37f008a4,
+ 0x4821f500,
+ 0x88e7f108,
+ 0x7f21f413,
+ 0xf4013cf0,
+/* 0x09f6: i2c_bitr_done */
+ 0x00f80131,
+/* 0x09f8: i2c_get_byte */
+ 0xf00057f0,
+/* 0x09fe: i2c_get_byte_next */
+ 0x54b60847,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b609b1,
+ 0x2b11f404,
+ 0xb60553fd,
+ 0x1bf40142,
+ 0x0137f0d8,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0x7021f550,
+ 0x0464b609,
+/* 0x0a48: i2c_get_byte_done */
+/* 0x0a4a: i2c_put_byte */
+ 0x47f000f8,
+/* 0x0a4d: i2c_put_byte_next */
+ 0x0142b608,
+ 0xbb3854ff,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x097021f5,
+ 0xf40464b6,
+ 0x46b03411,
+ 0xd81bf400,
+ 0xb60076bb,
+ 0x50f90465,
+ 0xbb046594,
+ 0x50bd0256,
+ 0xfc0475fd,
+ 0xb121f550,
+ 0x0464b609,
+ 0xbb0f11f4,
+ 0x36b00076,
+ 0x061bf401,
+/* 0x0aa3: i2c_put_byte_done */
+ 0xf80132f4,
+/* 0x0aa5: i2c_addr */
+ 0x0076bb00,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b608e1,
+ 0x2911f404,
+ 0x012ec3e7,
+ 0xfd0134b6,
+ 0x76bb0553,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb60a4a21,
+/* 0x0aea: i2c_addr_done */
+ 0x00f80464,
+/* 0x0aec: i2c_acquire_addr */
+ 0xb6f8cec7,
+ 0xe0b702e4,
+ 0xee980d1c,
+/* 0x0afb: i2c_acquire */
+ 0xf500f800,
+ 0xf40aec21,
+ 0xd9f00421,
+ 0x3f21f403,
+/* 0x0b0a: i2c_release */
+ 0x21f500f8,
+ 0x21f40aec,
+ 0x03daf004,
+ 0xf83f21f4,
+/* 0x0b19: i2c_recv */
+ 0x0132f400,
+ 0xb6f8c1c7,
+ 0x16b00214,
+ 0x3a1ff528,
+ 0xf413a001,
+ 0x0032980c,
+ 0x0ccc13a0,
+ 0xf4003198,
+ 0xd0f90231,
+ 0xd0f9e0f9,
+ 0x000067f1,
+ 0x100063f1,
+ 0xbb016792,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x0afb21f5,
+ 0xfc0464b6,
+ 0x00d6b0d0,
+ 0x00b31bf5,
+ 0xbb0057f0,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x0aa521f5,
+ 0xf50464b6,
+ 0xc700d011,
+ 0x76bbe0c5,
+ 0x0465b600,
+ 0x659450f9,
+ 0x0256bb04,
+ 0x75fd50bd,
+ 0xf550fc04,
+ 0xb60a4a21,
+ 0x11f50464,
+ 0x57f000ad,
+ 0x0076bb01,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b60aa5,
+ 0x8a11f504,
+ 0x0076bb00,
+ 0xf90465b6,
+ 0x04659450,
+ 0xbd0256bb,
+ 0x0475fd50,
+ 0x21f550fc,
+ 0x64b609f8,
+ 0x6a11f404,
+ 0xbbe05bcb,
+ 0x65b60076,
+ 0x9450f904,
+ 0x56bb0465,
+ 0xfd50bd02,
+ 0x50fc0475,
+ 0x093d21f5,
+ 0xb90464b6,
+ 0x74bd025b,
+/* 0x0c1f: i2c_recv_not_rd08 */
+ 0xb0430ef4,
+ 0x1bf401d6,
+ 0x0057f03d,
+ 0x0aa521f5,
+ 0xc73311f4,
+ 0x21f5e0c5,
+ 0x11f40a4a,
+ 0x0057f029,
+ 0x0aa521f5,
+ 0xc71f11f4,
+ 0x21f5e0b5,
+ 0x11f40a4a,
+ 0x3d21f515,
+ 0xc774bd09,
+ 0x1bf408c5,
+ 0x0232f409,
+/* 0x0c5f: i2c_recv_not_wr08 */
+/* 0x0c5f: i2c_recv_done */
+ 0xc7030ef4,
+ 0x21f5f8ce,
+ 0xe0fc0b0a,
+ 0x12f4d0fc,
+ 0x027cb90a,
+ 0x034221f5,
+/* 0x0c74: i2c_recv_exit */
+/* 0x0c76: i2c_init */
+ 0x00f800f8,
+/* 0x0c78: test_recv */
+ 0x05d817f1,
+ 0xcf0614b6,
+ 0x10b60011,
+ 0xd807f101,
+ 0x0604b605,
+ 0xbd0001d0,
+ 0x00e7f104,
+ 0x4fe3f1d9,
+ 0x6221f513,
+/* 0x0c9f: test_init */
+ 0xf100f802,
+ 0xf50800e7,
+ 0xf8026221,
+/* 0x0ca9: idle_recv */
+/* 0x0cab: idle */
+ 0xf400f800,
+ 0x17f10031,
+ 0x14b605d4,
+ 0x0011cf06,
+ 0xf10110b6,
+ 0xb605d407,
+ 0x01d00604,
+/* 0x0cc7: idle_loop */
+ 0xf004bd00,
+ 0x32f45817,
+/* 0x0ccd: idle_proc */
+/* 0x0ccd: idle_proc_exec */
+ 0xb910f902,
+ 0x21f5021e,
+ 0x10fc034b,
+ 0xf40911f4,
+ 0x0ef40231,
+/* 0x0ce1: idle_proc_next */
+ 0x5810b6ef,
+ 0xf4061fb8,
+ 0x02f4e61b,
+ 0x0028f4dd,
+ 0x00bb0ef4,
+ 0x00000000,
+ 0x00000000,
+ 0x00000000,
+};
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/host.fuc
index c2bb616a8da5..c2bb616a8da5 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/host.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/host.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/i2c_.fuc
index 757dda700024..757dda700024 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/i2c_.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/i2c_.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/idle.fuc
index 98f1c3738b42..98f1c3738b42 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/idle.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/idle.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
index 5cf5be63cbef..5cf5be63cbef 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/kernel.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/kernel.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/macros.fuc
index 96fc984dafdc..96fc984dafdc 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/macros.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/macros.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc
index ec03f9a4290b..ec03f9a4290b 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/memx.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/memx.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/os.h
index c8b06cb77e72..c8b06cb77e72 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/os.h
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/os.h
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/perf.fuc
index 38eadf705cbf..38eadf705cbf 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/perf.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/perf.fuc
diff --git a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/test.fuc
index 0c3a71bf5459..0c3a71bf5459 100644
--- a/drivers/gpu/drm/nouveau/core/subdev/pwr/fuc/test.fuc
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/fuc/test.fuc
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c
new file mode 100644
index 000000000000..78a4ea0101f1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf100.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gf100.fuc3.h"
+
+struct nvkm_oclass *
+gf100_pmu_oclass = &(struct nvkm_pmu_impl) {
+ .base.handle = NV_SUBDEV(PMU, 0xc0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_pmu_ctor,
+ .dtor = _nvkm_pmu_dtor,
+ .init = _nvkm_pmu_init,
+ .fini = _nvkm_pmu_fini,
+ },
+ .code.data = gf100_pmu_code,
+ .code.size = sizeof(gf100_pmu_code),
+ .data.data = gf100_pmu_data,
+ .data.size = sizeof(gf100_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c
new file mode 100644
index 000000000000..6b3a23839ff0
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gf110.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gf110.fuc4.h"
+
+struct nvkm_oclass *
+gf110_pmu_oclass = &(struct nvkm_pmu_impl) {
+ .base.handle = NV_SUBDEV(PMU, 0xd0),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_pmu_ctor,
+ .dtor = _nvkm_pmu_dtor,
+ .init = _nvkm_pmu_init,
+ .fini = _nvkm_pmu_fini,
+ },
+ .code.data = gf110_pmu_code,
+ .code.size = sizeof(gf110_pmu_code),
+ .data.data = gf110_pmu_data,
+ .data.size = sizeof(gf110_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
new file mode 100644
index 000000000000..28fdb8ea9ed8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk104.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#define gf110_pmu_code gk104_pmu_code
+#define gf110_pmu_data gk104_pmu_data
+#include "priv.h"
+#include "fuc/gf110.fuc4.h"
+
+static void
+gk104_pmu_pgob(struct nvkm_pmu *pmu, bool enable)
+{
+ nv_mask(pmu, 0x000200, 0x00001000, 0x00000000);
+ nv_rd32(pmu, 0x000200);
+ nv_mask(pmu, 0x000200, 0x08000000, 0x08000000);
+ msleep(50);
+
+ nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000002);
+ nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001);
+ nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000);
+
+ nv_mask(pmu, 0x020004, 0xc0000000, enable ? 0xc0000000 : 0x40000000);
+ msleep(50);
+
+ nv_mask(pmu, 0x10a78c, 0x00000002, 0x00000000);
+ nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000001);
+ nv_mask(pmu, 0x10a78c, 0x00000001, 0x00000000);
+
+ nv_mask(pmu, 0x000200, 0x08000000, 0x00000000);
+ nv_mask(pmu, 0x000200, 0x00001000, 0x00001000);
+ nv_rd32(pmu, 0x000200);
+}
+
+struct nvkm_oclass *
+gk104_pmu_oclass = &(struct nvkm_pmu_impl) {
+ .base.handle = NV_SUBDEV(PMU, 0xe4),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_pmu_ctor,
+ .dtor = _nvkm_pmu_dtor,
+ .init = _nvkm_pmu_init,
+ .fini = _nvkm_pmu_fini,
+ },
+ .code.data = gk104_pmu_code,
+ .code.size = sizeof(gk104_pmu_code),
+ .data.data = gk104_pmu_data,
+ .data.size = sizeof(gk104_pmu_data),
+ .pgob = gk104_pmu_pgob,
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c
new file mode 100644
index 000000000000..6f9c09af1a49
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk208.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gk208.fuc5.h"
+
+struct nvkm_oclass *
+gk208_pmu_oclass = &(struct nvkm_pmu_impl) {
+ .base.handle = NV_SUBDEV(PMU, 0x00),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_pmu_ctor,
+ .dtor = _nvkm_pmu_dtor,
+ .init = _nvkm_pmu_init,
+ .fini = _nvkm_pmu_fini,
+ },
+ .code.data = gk208_pmu_code,
+ .code.size = sizeof(gk208_pmu_code),
+ .data.data = gk208_pmu_data,
+ .data.size = sizeof(gk208_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
new file mode 100644
index 000000000000..a49934bbe637
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gk20a.c
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 "priv.h"
+
+#include <subdev/clk.h>
+#include <subdev/timer.h>
+#include <subdev/volt.h>
+
+#define BUSY_SLOT 0
+#define CLK_SLOT 7
+
+struct gk20a_pmu_dvfs_data {
+ int p_load_target;
+ int p_load_max;
+ int p_smooth;
+ unsigned int avg_load;
+};
+
+struct gk20a_pmu_priv {
+ struct nvkm_pmu base;
+ struct nvkm_alarm alarm;
+ struct gk20a_pmu_dvfs_data *data;
+};
+
+struct gk20a_pmu_dvfs_dev_status {
+ unsigned long total;
+ unsigned long busy;
+ int cur_state;
+};
+
+static int
+gk20a_pmu_dvfs_target(struct gk20a_pmu_priv *priv, int *state)
+{
+ struct nvkm_clk *clk = nvkm_clk(priv);
+
+ return nvkm_clk_astate(clk, *state, 0, false);
+}
+
+static int
+gk20a_pmu_dvfs_get_cur_state(struct gk20a_pmu_priv *priv, int *state)
+{
+ struct nvkm_clk *clk = nvkm_clk(priv);
+
+ *state = clk->pstate;
+ return 0;
+}
+
+static int
+gk20a_pmu_dvfs_get_target_state(struct gk20a_pmu_priv *priv,
+ int *state, int load)
+{
+ struct gk20a_pmu_dvfs_data *data = priv->data;
+ struct nvkm_clk *clk = nvkm_clk(priv);
+ int cur_level, level;
+
+ /* For GK20A, the performance level is directly mapped to pstate */
+ level = cur_level = clk->pstate;
+
+ if (load > data->p_load_max) {
+ level = min(clk->state_nr - 1, level + (clk->state_nr / 3));
+ } else {
+ level += ((load - data->p_load_target) * 10 /
+ data->p_load_target) / 2;
+ level = max(0, level);
+ level = min(clk->state_nr - 1, level);
+ }
+
+ nv_trace(priv, "cur level = %d, new level = %d\n", cur_level, level);
+
+ *state = level;
+
+ if (level == cur_level)
+ return 0;
+ else
+ return 1;
+}
+
+static int
+gk20a_pmu_dvfs_get_dev_status(struct gk20a_pmu_priv *priv,
+ struct gk20a_pmu_dvfs_dev_status *status)
+{
+ status->busy = nv_rd32(priv, 0x10a508 + (BUSY_SLOT * 0x10));
+ status->total= nv_rd32(priv, 0x10a508 + (CLK_SLOT * 0x10));
+ return 0;
+}
+
+static void
+gk20a_pmu_dvfs_reset_dev_status(struct gk20a_pmu_priv *priv)
+{
+ nv_wr32(priv, 0x10a508 + (BUSY_SLOT * 0x10), 0x80000000);
+ nv_wr32(priv, 0x10a508 + (CLK_SLOT * 0x10), 0x80000000);
+}
+
+static void
+gk20a_pmu_dvfs_work(struct nvkm_alarm *alarm)
+{
+ struct gk20a_pmu_priv *priv =
+ container_of(alarm, struct gk20a_pmu_priv, alarm);
+ struct gk20a_pmu_dvfs_data *data = priv->data;
+ struct gk20a_pmu_dvfs_dev_status status;
+ struct nvkm_clk *clk = nvkm_clk(priv);
+ struct nvkm_volt *volt = nvkm_volt(priv);
+ u32 utilization = 0;
+ int state, ret;
+
+ /*
+ * The PMU is initialized before CLK and VOLT, so we have to make sure the
+ * CLK and VOLT are ready here.
+ */
+ if (!clk || !volt)
+ goto resched;
+
+ ret = gk20a_pmu_dvfs_get_dev_status(priv, &status);
+ if (ret) {
+ nv_warn(priv, "failed to get device status\n");
+ goto resched;
+ }
+
+ if (status.total)
+ utilization = div_u64((u64)status.busy * 100, status.total);
+
+ data->avg_load = (data->p_smooth * data->avg_load) + utilization;
+ data->avg_load /= data->p_smooth + 1;
+ nv_trace(priv, "utilization = %d %%, avg_load = %d %%\n",
+ utilization, data->avg_load);
+
+ ret = gk20a_pmu_dvfs_get_cur_state(priv, &state);
+ if (ret) {
+ nv_warn(priv, "failed to get current state\n");
+ goto resched;
+ }
+
+ if (gk20a_pmu_dvfs_get_target_state(priv, &state, data->avg_load)) {
+ nv_trace(priv, "set new state to %d\n", state);
+ gk20a_pmu_dvfs_target(priv, &state);
+ }
+
+resched:
+ gk20a_pmu_dvfs_reset_dev_status(priv);
+ nvkm_timer_alarm(priv, 100000000, alarm);
+}
+
+int
+gk20a_pmu_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_pmu *pmu = (void *)object;
+ struct gk20a_pmu_priv *priv = (void *)pmu;
+
+ nvkm_timer_alarm_cancel(priv, &priv->alarm);
+
+ return nvkm_subdev_fini(&pmu->base, suspend);
+}
+
+int
+gk20a_pmu_init(struct nvkm_object *object)
+{
+ struct nvkm_pmu *pmu = (void *)object;
+ struct gk20a_pmu_priv *priv = (void *)pmu;
+ int ret;
+
+ ret = nvkm_subdev_init(&pmu->base);
+ if (ret)
+ return ret;
+
+ pmu->pgob = nvkm_pmu_pgob;
+
+ /* init pwr perf counter */
+ nv_wr32(pmu, 0x10a504 + (BUSY_SLOT * 0x10), 0x00200001);
+ nv_wr32(pmu, 0x10a50c + (BUSY_SLOT * 0x10), 0x00000002);
+ nv_wr32(pmu, 0x10a50c + (CLK_SLOT * 0x10), 0x00000003);
+
+ nvkm_timer_alarm(pmu, 2000000000, &priv->alarm);
+ return ret;
+}
+
+struct gk20a_pmu_dvfs_data gk20a_dvfs_data= {
+ .p_load_target = 70,
+ .p_load_max = 90,
+ .p_smooth = 1,
+};
+
+static int
+gk20a_pmu_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk20a_pmu_priv *priv;
+ int ret;
+
+ ret = nvkm_pmu_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->data = &gk20a_dvfs_data;
+
+ nvkm_alarm_init(&priv->alarm, gk20a_pmu_dvfs_work);
+ return 0;
+}
+
+struct nvkm_oclass *
+gk20a_pmu_oclass = &(struct nvkm_pmu_impl) {
+ .base.handle = NV_SUBDEV(PMU, 0xea),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_pmu_ctor,
+ .dtor = _nvkm_pmu_dtor,
+ .init = gk20a_pmu_init,
+ .fini = gk20a_pmu_fini,
+ },
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
new file mode 100644
index 000000000000..30aaeb21de41
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/gt215.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+#include "fuc/gt215.fuc3.h"
+
+static int
+gt215_pmu_init(struct nvkm_object *object)
+{
+ struct nvkm_pmu *pmu = (void *)object;
+ nv_mask(pmu, 0x022210, 0x00000001, 0x00000000);
+ nv_mask(pmu, 0x022210, 0x00000001, 0x00000001);
+ return nvkm_pmu_init(pmu);
+}
+
+struct nvkm_oclass *
+gt215_pmu_oclass = &(struct nvkm_pmu_impl) {
+ .base.handle = NV_SUBDEV(PMU, 0xa3),
+ .base.ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = _nvkm_pmu_ctor,
+ .dtor = _nvkm_pmu_dtor,
+ .init = gt215_pmu_init,
+ .fini = _nvkm_pmu_fini,
+ },
+ .code.data = gt215_pmu_code,
+ .code.size = sizeof(gt215_pmu_code),
+ .data.data = gt215_pmu_data,
+ .data.size = sizeof(gt215_pmu_data),
+}.base;
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
new file mode 100644
index 000000000000..b75c5b885980
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/memx.c
@@ -0,0 +1,200 @@
+#ifndef __NVKM_PMU_MEMX_H__
+#define __NVKM_PMU_MEMX_H__
+#include "priv.h"
+
+#include <core/device.h>
+
+struct nvkm_memx {
+ struct nvkm_pmu *pmu;
+ u32 base;
+ u32 size;
+ struct {
+ u32 mthd;
+ u32 size;
+ u32 data[64];
+ } c;
+};
+
+static void
+memx_out(struct nvkm_memx *memx)
+{
+ struct nvkm_pmu *pmu = memx->pmu;
+ int i;
+
+ if (memx->c.mthd) {
+ nv_wr32(pmu, 0x10a1c4, (memx->c.size << 16) | memx->c.mthd);
+ for (i = 0; i < memx->c.size; i++)
+ nv_wr32(pmu, 0x10a1c4, memx->c.data[i]);
+ memx->c.mthd = 0;
+ memx->c.size = 0;
+ }
+}
+
+static void
+memx_cmd(struct nvkm_memx *memx, u32 mthd, u32 size, u32 data[])
+{
+ if ((memx->c.size + size >= ARRAY_SIZE(memx->c.data)) ||
+ (memx->c.mthd && memx->c.mthd != mthd))
+ memx_out(memx);
+ memcpy(&memx->c.data[memx->c.size], data, size * sizeof(data[0]));
+ memx->c.size += size;
+ memx->c.mthd = mthd;
+}
+
+int
+nvkm_memx_init(struct nvkm_pmu *pmu, struct nvkm_memx **pmemx)
+{
+ struct nvkm_memx *memx;
+ u32 reply[2];
+ int ret;
+
+ ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO,
+ MEMX_INFO_DATA, 0);
+ if (ret)
+ return ret;
+
+ memx = *pmemx = kzalloc(sizeof(*memx), GFP_KERNEL);
+ if (!memx)
+ return -ENOMEM;
+ memx->pmu = pmu;
+ memx->base = reply[0];
+ memx->size = reply[1];
+
+ /* acquire data segment access */
+ do {
+ nv_wr32(pmu, 0x10a580, 0x00000003);
+ } while (nv_rd32(pmu, 0x10a580) != 0x00000003);
+ nv_wr32(pmu, 0x10a1c0, 0x01000000 | memx->base);
+ return 0;
+}
+
+int
+nvkm_memx_fini(struct nvkm_memx **pmemx, bool exec)
+{
+ struct nvkm_memx *memx = *pmemx;
+ struct nvkm_pmu *pmu = memx->pmu;
+ u32 finish, reply[2];
+
+ /* flush the cache... */
+ memx_out(memx);
+
+ /* release data segment access */
+ finish = nv_rd32(pmu, 0x10a1c0) & 0x00ffffff;
+ nv_wr32(pmu, 0x10a580, 0x00000000);
+
+ /* call MEMX process to execute the script, and wait for reply */
+ if (exec) {
+ pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_EXEC,
+ memx->base, finish);
+ }
+
+ nv_debug(memx->pmu, "Exec took %uns, PMU_IN %08x\n",
+ reply[0], reply[1]);
+ kfree(memx);
+ return 0;
+}
+
+void
+nvkm_memx_wr32(struct nvkm_memx *memx, u32 addr, u32 data)
+{
+ nv_debug(memx->pmu, "R[%06x] = 0x%08x\n", addr, data);
+ memx_cmd(memx, MEMX_WR32, 2, (u32[]){ addr, data });
+}
+
+void
+nvkm_memx_wait(struct nvkm_memx *memx,
+ u32 addr, u32 mask, u32 data, u32 nsec)
+{
+ nv_debug(memx->pmu, "R[%06x] & 0x%08x == 0x%08x, %d us\n",
+ addr, mask, data, nsec);
+ memx_cmd(memx, MEMX_WAIT, 4, (u32[]){ addr, mask, data, nsec });
+ memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nvkm_memx_nsec(struct nvkm_memx *memx, u32 nsec)
+{
+ nv_debug(memx->pmu, " DELAY = %d ns\n", nsec);
+ memx_cmd(memx, MEMX_DELAY, 1, (u32[]){ nsec });
+ memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nvkm_memx_wait_vblank(struct nvkm_memx *memx)
+{
+ struct nvkm_pmu *pmu = memx->pmu;
+ u32 heads, x, y, px = 0;
+ int i, head_sync;
+
+ if (nv_device(pmu)->chipset < 0xd0) {
+ heads = nv_rd32(pmu, 0x610050);
+ for (i = 0; i < 2; i++) {
+ /* Heuristic: sync to head with biggest resolution */
+ if (heads & (2 << (i << 3))) {
+ x = nv_rd32(pmu, 0x610b40 + (0x540 * i));
+ y = (x & 0xffff0000) >> 16;
+ x &= 0x0000ffff;
+ if ((x * y) > px) {
+ px = (x * y);
+ head_sync = i;
+ }
+ }
+ }
+ }
+
+ if (px == 0) {
+ nv_debug(memx->pmu, "WAIT VBLANK !NO ACTIVE HEAD\n");
+ return;
+ }
+
+ nv_debug(memx->pmu, "WAIT VBLANK HEAD%d\n", head_sync);
+ memx_cmd(memx, MEMX_VBLANK, 1, (u32[]){ head_sync });
+ memx_out(memx); /* fuc can't handle multiple */
+}
+
+void
+nvkm_memx_train(struct nvkm_memx *memx)
+{
+ nv_debug(memx->pmu, " MEM TRAIN\n");
+ memx_cmd(memx, MEMX_TRAIN, 0, NULL);
+}
+
+int
+nvkm_memx_train_result(struct nvkm_pmu *pmu, u32 *res, int rsize)
+{
+ u32 reply[2], base, size, i;
+ int ret;
+
+ ret = pmu->message(pmu, reply, PROC_MEMX, MEMX_MSG_INFO,
+ MEMX_INFO_TRAIN, 0);
+ if (ret)
+ return ret;
+
+ base = reply[0];
+ size = reply[1] >> 2;
+ if (size > rsize)
+ return -ENOMEM;
+
+ /* read the packet */
+ nv_wr32(pmu, 0x10a1c0, 0x02000000 | base);
+
+ for (i = 0; i < size; i++)
+ res[i] = nv_rd32(pmu, 0x10a1c4);
+
+ return 0;
+}
+
+void
+nvkm_memx_block(struct nvkm_memx *memx)
+{
+ nv_debug(memx->pmu, " HOST BLOCKED\n");
+ memx_cmd(memx, MEMX_ENTER, 0, NULL);
+}
+
+void
+nvkm_memx_unblock(struct nvkm_memx *memx)
+{
+ nv_debug(memx->pmu, " HOST UNBLOCKED\n");
+ memx_cmd(memx, MEMX_LEAVE, 0, NULL);
+}
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
new file mode 100644
index 000000000000..998410563bfd
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/pmu/priv.h
@@ -0,0 +1,43 @@
+#ifndef __NVKM_PMU_PRIV_H__
+#define __NVKM_PMU_PRIV_H__
+#include <subdev/pmu.h>
+#include <subdev/pmu/fuc/os.h>
+
+#define nvkm_pmu_create(p, e, o, d) \
+ nvkm_pmu_create_((p), (e), (o), sizeof(**d), (void **)d)
+#define nvkm_pmu_destroy(p) \
+ nvkm_subdev_destroy(&(p)->base)
+#define nvkm_pmu_init(p) ({ \
+ struct nvkm_pmu *_pmu = (p); \
+ _nvkm_pmu_init(nv_object(_pmu)); \
+})
+#define nvkm_pmu_fini(p,s) ({ \
+ struct nvkm_pmu *_pmu = (p); \
+ _nvkm_pmu_fini(nv_object(_pmu), (s)); \
+})
+
+int nvkm_pmu_create_(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, int, void **);
+
+int _nvkm_pmu_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+#define _nvkm_pmu_dtor _nvkm_subdev_dtor
+int _nvkm_pmu_init(struct nvkm_object *);
+int _nvkm_pmu_fini(struct nvkm_object *, bool);
+void nvkm_pmu_pgob(struct nvkm_pmu *pmu, bool enable);
+
+struct nvkm_pmu_impl {
+ struct nvkm_oclass base;
+ struct {
+ u32 *data;
+ u32 size;
+ } code;
+ struct {
+ u32 *data;
+ u32 size;
+ } data;
+
+ void (*pgob)(struct nvkm_pmu *, bool);
+};
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
new file mode 100644
index 000000000000..5837cf1292d9
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/Kbuild
@@ -0,0 +1,13 @@
+nvkm-y += nvkm/subdev/therm/base.o
+nvkm-y += nvkm/subdev/therm/fan.o
+nvkm-y += nvkm/subdev/therm/fannil.o
+nvkm-y += nvkm/subdev/therm/fanpwm.o
+nvkm-y += nvkm/subdev/therm/fantog.o
+nvkm-y += nvkm/subdev/therm/ic.o
+nvkm-y += nvkm/subdev/therm/temp.o
+nvkm-y += nvkm/subdev/therm/nv40.o
+nvkm-y += nvkm/subdev/therm/nv50.o
+nvkm-y += nvkm/subdev/therm/g84.o
+nvkm-y += nvkm/subdev/therm/gt215.o
+nvkm-y += nvkm/subdev/therm/gf110.o
+nvkm-y += nvkm/subdev/therm/gm107.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
new file mode 100644
index 000000000000..ec327cb64a0d
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/base.c
@@ -0,0 +1,367 @@
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+static int
+nvkm_therm_update_trip(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_trip_point *trip = priv->fan->bios.trip,
+ *cur_trip = NULL,
+ *last_trip = priv->last_trip;
+ u8 temp = therm->temp_get(therm);
+ u16 duty, i;
+
+ /* look for the trip point corresponding to the current temperature */
+ cur_trip = NULL;
+ for (i = 0; i < priv->fan->bios.nr_fan_trip; i++) {
+ if (temp >= trip[i].temp)
+ cur_trip = &trip[i];
+ }
+
+ /* account for the hysteresis cycle */
+ if (last_trip && temp <= (last_trip->temp) &&
+ temp > (last_trip->temp - last_trip->hysteresis))
+ cur_trip = last_trip;
+
+ if (cur_trip) {
+ duty = cur_trip->fan_duty;
+ priv->last_trip = cur_trip;
+ } else {
+ duty = 0;
+ priv->last_trip = NULL;
+ }
+
+ return duty;
+}
+
+static int
+nvkm_therm_update_linear(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ u8 linear_min_temp = priv->fan->bios.linear_min_temp;
+ u8 linear_max_temp = priv->fan->bios.linear_max_temp;
+ u8 temp = therm->temp_get(therm);
+ u16 duty;
+
+ /* handle the non-linear part first */
+ if (temp < linear_min_temp)
+ return priv->fan->bios.min_duty;
+ else if (temp > linear_max_temp)
+ return priv->fan->bios.max_duty;
+
+ /* we are in the linear zone */
+ duty = (temp - linear_min_temp);
+ duty *= (priv->fan->bios.max_duty - priv->fan->bios.min_duty);
+ duty /= (linear_max_temp - linear_min_temp);
+ duty += priv->fan->bios.min_duty;
+ return duty;
+}
+
+static void
+nvkm_therm_update(struct nvkm_therm *therm, int mode)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(therm);
+ struct nvkm_therm_priv *priv = (void *)therm;
+ unsigned long flags;
+ bool immd = true;
+ bool poll = true;
+ int duty = -1;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (mode < 0)
+ mode = priv->mode;
+ priv->mode = mode;
+
+ switch (mode) {
+ case NVKM_THERM_CTRL_MANUAL:
+ ptimer->alarm_cancel(ptimer, &priv->alarm);
+ duty = nvkm_therm_fan_get(therm);
+ if (duty < 0)
+ duty = 100;
+ poll = false;
+ break;
+ case NVKM_THERM_CTRL_AUTO:
+ switch(priv->fan->bios.fan_mode) {
+ case NVBIOS_THERM_FAN_TRIP:
+ duty = nvkm_therm_update_trip(therm);
+ break;
+ case NVBIOS_THERM_FAN_LINEAR:
+ duty = nvkm_therm_update_linear(therm);
+ break;
+ case NVBIOS_THERM_FAN_OTHER:
+ if (priv->cstate)
+ duty = priv->cstate;
+ poll = false;
+ break;
+ }
+ immd = false;
+ break;
+ case NVKM_THERM_CTRL_NONE:
+ default:
+ ptimer->alarm_cancel(ptimer, &priv->alarm);
+ poll = false;
+ }
+
+ if (list_empty(&priv->alarm.head) && poll)
+ ptimer->alarm(ptimer, 1000000000ULL, &priv->alarm);
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ if (duty >= 0) {
+ nv_debug(therm, "FAN target request: %d%%\n", duty);
+ nvkm_therm_fan_set(therm, immd, duty);
+ }
+}
+
+int
+nvkm_therm_cstate(struct nvkm_therm *ptherm, int fan, int dir)
+{
+ struct nvkm_therm_priv *priv = (void *)ptherm;
+ if (!dir || (dir < 0 && fan < priv->cstate) ||
+ (dir > 0 && fan > priv->cstate)) {
+ nv_debug(ptherm, "default fan speed -> %d%%\n", fan);
+ priv->cstate = fan;
+ nvkm_therm_update(ptherm, -1);
+ }
+ return 0;
+}
+
+static void
+nvkm_therm_alarm(struct nvkm_alarm *alarm)
+{
+ struct nvkm_therm_priv *priv =
+ container_of(alarm, struct nvkm_therm_priv, alarm);
+ nvkm_therm_update(&priv->base, -1);
+}
+
+int
+nvkm_therm_fan_mode(struct nvkm_therm *therm, int mode)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_device *device = nv_device(therm);
+ static const char *name[] = {
+ "disabled",
+ "manual",
+ "automatic"
+ };
+
+ /* The default PPWR ucode on fermi interferes with fan management */
+ if ((mode >= ARRAY_SIZE(name)) ||
+ (mode != NVKM_THERM_CTRL_NONE && device->card_type >= NV_C0 &&
+ !nvkm_subdev(device, NVDEV_SUBDEV_PMU)))
+ return -EINVAL;
+
+ /* do not allow automatic fan management if the thermal sensor is
+ * not available */
+ if (mode == NVKM_THERM_CTRL_AUTO && therm->temp_get(therm) < 0)
+ return -EINVAL;
+
+ if (priv->mode == mode)
+ return 0;
+
+ nv_info(therm, "fan management: %s\n", name[mode]);
+ nvkm_therm_update(therm, mode);
+ return 0;
+}
+
+int
+nvkm_therm_attr_get(struct nvkm_therm *therm,
+ enum nvkm_therm_attr_type type)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ switch (type) {
+ case NVKM_THERM_ATTR_FAN_MIN_DUTY:
+ return priv->fan->bios.min_duty;
+ case NVKM_THERM_ATTR_FAN_MAX_DUTY:
+ return priv->fan->bios.max_duty;
+ case NVKM_THERM_ATTR_FAN_MODE:
+ return priv->mode;
+ case NVKM_THERM_ATTR_THRS_FAN_BOOST:
+ return priv->bios_sensor.thrs_fan_boost.temp;
+ case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST:
+ return priv->bios_sensor.thrs_fan_boost.hysteresis;
+ case NVKM_THERM_ATTR_THRS_DOWN_CLK:
+ return priv->bios_sensor.thrs_down_clock.temp;
+ case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST:
+ return priv->bios_sensor.thrs_down_clock.hysteresis;
+ case NVKM_THERM_ATTR_THRS_CRITICAL:
+ return priv->bios_sensor.thrs_critical.temp;
+ case NVKM_THERM_ATTR_THRS_CRITICAL_HYST:
+ return priv->bios_sensor.thrs_critical.hysteresis;
+ case NVKM_THERM_ATTR_THRS_SHUTDOWN:
+ return priv->bios_sensor.thrs_shutdown.temp;
+ case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST:
+ return priv->bios_sensor.thrs_shutdown.hysteresis;
+ }
+
+ return -EINVAL;
+}
+
+int
+nvkm_therm_attr_set(struct nvkm_therm *therm,
+ enum nvkm_therm_attr_type type, int value)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ switch (type) {
+ case NVKM_THERM_ATTR_FAN_MIN_DUTY:
+ if (value < 0)
+ value = 0;
+ if (value > priv->fan->bios.max_duty)
+ value = priv->fan->bios.max_duty;
+ priv->fan->bios.min_duty = value;
+ return 0;
+ case NVKM_THERM_ATTR_FAN_MAX_DUTY:
+ if (value < 0)
+ value = 0;
+ if (value < priv->fan->bios.min_duty)
+ value = priv->fan->bios.min_duty;
+ priv->fan->bios.max_duty = value;
+ return 0;
+ case NVKM_THERM_ATTR_FAN_MODE:
+ return nvkm_therm_fan_mode(therm, value);
+ case NVKM_THERM_ATTR_THRS_FAN_BOOST:
+ priv->bios_sensor.thrs_fan_boost.temp = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_FAN_BOOST_HYST:
+ priv->bios_sensor.thrs_fan_boost.hysteresis = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_DOWN_CLK:
+ priv->bios_sensor.thrs_down_clock.temp = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_DOWN_CLK_HYST:
+ priv->bios_sensor.thrs_down_clock.hysteresis = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_CRITICAL:
+ priv->bios_sensor.thrs_critical.temp = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_CRITICAL_HYST:
+ priv->bios_sensor.thrs_critical.hysteresis = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_SHUTDOWN:
+ priv->bios_sensor.thrs_shutdown.temp = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ case NVKM_THERM_ATTR_THRS_SHUTDOWN_HYST:
+ priv->bios_sensor.thrs_shutdown.hysteresis = value;
+ priv->sensor.program_alarms(therm);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int
+_nvkm_therm_init(struct nvkm_object *object)
+{
+ struct nvkm_therm *therm = (void *)object;
+ struct nvkm_therm_priv *priv = (void *)therm;
+ int ret;
+
+ ret = nvkm_subdev_init(&therm->base);
+ if (ret)
+ return ret;
+
+ if (priv->suspend >= 0) {
+ /* restore the pwm value only when on manual or auto mode */
+ if (priv->suspend > 0)
+ nvkm_therm_fan_set(therm, true, priv->fan->percent);
+
+ nvkm_therm_fan_mode(therm, priv->suspend);
+ }
+ nvkm_therm_sensor_init(therm);
+ nvkm_therm_fan_init(therm);
+ return 0;
+}
+
+int
+_nvkm_therm_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nvkm_therm *therm = (void *)object;
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ nvkm_therm_fan_fini(therm, suspend);
+ nvkm_therm_sensor_fini(therm, suspend);
+ if (suspend) {
+ priv->suspend = priv->mode;
+ priv->mode = NVKM_THERM_CTRL_NONE;
+ }
+
+ return nvkm_subdev_fini(&therm->base, suspend);
+}
+
+int
+nvkm_therm_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "PTHERM",
+ "therm", length, pobject);
+ priv = *pobject;
+ if (ret)
+ return ret;
+
+ nvkm_alarm_init(&priv->alarm, nvkm_therm_alarm);
+ spin_lock_init(&priv->lock);
+ spin_lock_init(&priv->sensor.alarm_program_lock);
+
+ priv->base.fan_get = nvkm_therm_fan_user_get;
+ priv->base.fan_set = nvkm_therm_fan_user_set;
+ priv->base.fan_sense = nvkm_therm_fan_sense;
+ priv->base.attr_get = nvkm_therm_attr_get;
+ priv->base.attr_set = nvkm_therm_attr_set;
+ priv->mode = priv->suspend = -1; /* undefined */
+ return 0;
+}
+
+int
+nvkm_therm_preinit(struct nvkm_therm *therm)
+{
+ nvkm_therm_sensor_ctor(therm);
+ nvkm_therm_ic_ctor(therm);
+ nvkm_therm_fan_ctor(therm);
+
+ nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO);
+ nvkm_therm_sensor_preinit(therm);
+ return 0;
+}
+
+void
+_nvkm_therm_dtor(struct nvkm_object *object)
+{
+ struct nvkm_therm_priv *priv = (void *)object;
+ kfree(priv->fan);
+ nvkm_subdev_destroy(&priv->base.base);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
new file mode 100644
index 000000000000..434fa745ca40
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fan.c
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/bios/fan.h>
+#include <subdev/gpio.h>
+#include <subdev/timer.h>
+
+static int
+nvkm_fan_update(struct nvkm_fan *fan, bool immediate, int target)
+{
+ struct nvkm_therm *therm = fan->parent;
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_timer *ptimer = nvkm_timer(priv);
+ unsigned long flags;
+ int ret = 0;
+ int duty;
+
+ /* update target fan speed, restricting to allowed range */
+ spin_lock_irqsave(&fan->lock, flags);
+ if (target < 0)
+ target = fan->percent;
+ target = max_t(u8, target, fan->bios.min_duty);
+ target = min_t(u8, target, fan->bios.max_duty);
+ if (fan->percent != target) {
+ nv_debug(therm, "FAN target: %d\n", target);
+ fan->percent = target;
+ }
+
+ /* check that we're not already at the target duty cycle */
+ duty = fan->get(therm);
+ if (duty == target) {
+ spin_unlock_irqrestore(&fan->lock, flags);
+ return 0;
+ }
+
+ /* smooth out the fanspeed increase/decrease */
+ if (!immediate && duty >= 0) {
+ /* the constant "3" is a rough approximation taken from
+ * nvidia's behaviour.
+ * it is meant to bump the fan speed more incrementally
+ */
+ if (duty < target)
+ duty = min(duty + 3, target);
+ else if (duty > target)
+ duty = max(duty - 3, target);
+ } else {
+ duty = target;
+ }
+
+ nv_debug(therm, "FAN update: %d\n", duty);
+ ret = fan->set(therm, duty);
+ if (ret) {
+ spin_unlock_irqrestore(&fan->lock, flags);
+ return ret;
+ }
+
+ /* fan speed updated, drop the fan lock before grabbing the
+ * alarm-scheduling lock and risking a deadlock
+ */
+ spin_unlock_irqrestore(&fan->lock, flags);
+
+ /* schedule next fan update, if not at target speed already */
+ if (list_empty(&fan->alarm.head) && target != duty) {
+ u16 bump_period = fan->bios.bump_period;
+ u16 slow_down_period = fan->bios.slow_down_period;
+ u64 delay;
+
+ if (duty > target)
+ delay = slow_down_period;
+ else if (duty == target)
+ delay = min(bump_period, slow_down_period) ;
+ else
+ delay = bump_period;
+
+ ptimer->alarm(ptimer, delay * 1000 * 1000, &fan->alarm);
+ }
+
+ return ret;
+}
+
+static void
+nvkm_fan_alarm(struct nvkm_alarm *alarm)
+{
+ struct nvkm_fan *fan = container_of(alarm, struct nvkm_fan, alarm);
+ nvkm_fan_update(fan, false, -1);
+}
+
+int
+nvkm_therm_fan_get(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ return priv->fan->get(therm);
+}
+
+int
+nvkm_therm_fan_set(struct nvkm_therm *therm, bool immediate, int percent)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ return nvkm_fan_update(priv->fan, immediate, percent);
+}
+
+int
+nvkm_therm_fan_sense(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_timer *ptimer = nvkm_timer(therm);
+ struct nvkm_gpio *gpio = nvkm_gpio(therm);
+ u32 cycles, cur, prev;
+ u64 start, end, tach;
+
+ if (priv->fan->tach.func == DCB_GPIO_UNUSED)
+ return -ENODEV;
+
+ /* Time a complete rotation and extrapolate to RPM:
+ * When the fan spins, it changes the value of GPIO FAN_SENSE.
+ * We get 4 changes (0 -> 1 -> 0 -> 1) per complete rotation.
+ */
+ start = ptimer->read(ptimer);
+ prev = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
+ cycles = 0;
+ do {
+ usleep_range(500, 1000); /* supports 0 < rpm < 7500 */
+
+ cur = gpio->get(gpio, 0, priv->fan->tach.func, priv->fan->tach.line);
+ if (prev != cur) {
+ if (!start)
+ start = ptimer->read(ptimer);
+ cycles++;
+ prev = cur;
+ }
+ } while (cycles < 5 && ptimer->read(ptimer) - start < 250000000);
+ end = ptimer->read(ptimer);
+
+ if (cycles == 5) {
+ tach = (u64)60000000000ULL;
+ do_div(tach, (end - start));
+ return tach;
+ } else
+ return 0;
+}
+
+int
+nvkm_therm_fan_user_get(struct nvkm_therm *therm)
+{
+ return nvkm_therm_fan_get(therm);
+}
+
+int
+nvkm_therm_fan_user_set(struct nvkm_therm *therm, int percent)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ if (priv->mode != NVKM_THERM_CTRL_MANUAL)
+ return -EINVAL;
+
+ return nvkm_therm_fan_set(therm, true, percent);
+}
+
+static void
+nvkm_therm_fan_set_defaults(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ priv->fan->bios.pwm_freq = 0;
+ priv->fan->bios.min_duty = 0;
+ priv->fan->bios.max_duty = 100;
+ priv->fan->bios.bump_period = 500;
+ priv->fan->bios.slow_down_period = 2000;
+ priv->fan->bios.linear_min_temp = 40;
+ priv->fan->bios.linear_max_temp = 85;
+}
+
+static void
+nvkm_therm_fan_safety_checks(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ if (priv->fan->bios.min_duty > 100)
+ priv->fan->bios.min_duty = 100;
+ if (priv->fan->bios.max_duty > 100)
+ priv->fan->bios.max_duty = 100;
+
+ if (priv->fan->bios.min_duty > priv->fan->bios.max_duty)
+ priv->fan->bios.min_duty = priv->fan->bios.max_duty;
+}
+
+int
+nvkm_therm_fan_init(struct nvkm_therm *therm)
+{
+ return 0;
+}
+
+int
+nvkm_therm_fan_fini(struct nvkm_therm *therm, bool suspend)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_timer *ptimer = nvkm_timer(therm);
+
+ if (suspend)
+ ptimer->alarm_cancel(ptimer, &priv->fan->alarm);
+ return 0;
+}
+
+int
+nvkm_therm_fan_ctor(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_gpio *gpio = nvkm_gpio(therm);
+ struct nvkm_bios *bios = nvkm_bios(therm);
+ struct dcb_gpio_func func;
+ int ret;
+
+ /* attempt to locate a drivable fan, and determine control method */
+ ret = gpio->find(gpio, 0, DCB_GPIO_FAN, 0xff, &func);
+ if (ret == 0) {
+ /* FIXME: is this really the place to perform such checks ? */
+ if (func.line != 16 && func.log[0] & DCB_GPIO_LOG_DIR_IN) {
+ nv_debug(therm, "GPIO_FAN is in input mode\n");
+ ret = -EINVAL;
+ } else {
+ ret = nvkm_fanpwm_create(therm, &func);
+ if (ret != 0)
+ ret = nvkm_fantog_create(therm, &func);
+ }
+ }
+
+ /* no controllable fan found, create a dummy fan module */
+ if (ret != 0) {
+ ret = nvkm_fannil_create(therm);
+ if (ret)
+ return ret;
+ }
+
+ nv_info(therm, "FAN control: %s\n", priv->fan->type);
+
+ /* read the current speed, it is useful when resuming */
+ priv->fan->percent = nvkm_therm_fan_get(therm);
+
+ /* attempt to detect a tachometer connection */
+ ret = gpio->find(gpio, 0, DCB_GPIO_FAN_SENSE, 0xff, &priv->fan->tach);
+ if (ret)
+ priv->fan->tach.func = DCB_GPIO_UNUSED;
+
+ /* initialise fan bump/slow update handling */
+ priv->fan->parent = therm;
+ nvkm_alarm_init(&priv->fan->alarm, nvkm_fan_alarm);
+ spin_lock_init(&priv->fan->lock);
+
+ /* other random init... */
+ nvkm_therm_fan_set_defaults(therm);
+ nvbios_perf_fan_parse(bios, &priv->fan->perf);
+ if (!nvbios_fan_parse(bios, &priv->fan->bios)) {
+ nv_debug(therm, "parsing the fan table failed\n");
+ if (nvbios_therm_fan_parse(bios, &priv->fan->bios))
+ nv_error(therm, "parsing both fan tables failed\n");
+ }
+ nvkm_therm_fan_safety_checks(therm);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c
new file mode 100644
index 000000000000..534e5970ec9c
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fannil.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+static int
+nvkm_fannil_get(struct nvkm_therm *therm)
+{
+ return -ENODEV;
+}
+
+static int
+nvkm_fannil_set(struct nvkm_therm *therm, int percent)
+{
+ return -ENODEV;
+}
+
+int
+nvkm_fannil_create(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_fan *priv;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ tpriv->fan = priv;
+ if (!priv)
+ return -ENOMEM;
+
+ priv->type = "none / external";
+ priv->get = nvkm_fannil_get;
+ priv->set = nvkm_fannil_set;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c
new file mode 100644
index 000000000000..bde5ceaeb70a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fanpwm.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <core/option.h>
+#include <subdev/bios.h>
+#include <subdev/bios/fan.h>
+#include <subdev/gpio.h>
+
+struct nvkm_fanpwm_priv {
+ struct nvkm_fan base;
+ struct dcb_gpio_func func;
+};
+
+static int
+nvkm_fanpwm_get(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan;
+ struct nvkm_gpio *gpio = nvkm_gpio(therm);
+ int card_type = nv_device(therm)->card_type;
+ u32 divs, duty;
+ int ret;
+
+ ret = therm->pwm_get(therm, priv->func.line, &divs, &duty);
+ if (ret == 0 && divs) {
+ divs = max(divs, duty);
+ if (card_type <= NV_40 || (priv->func.log[0] & 1))
+ duty = divs - duty;
+ return (duty * 100) / divs;
+ }
+
+ return gpio->get(gpio, 0, priv->func.func, priv->func.line) * 100;
+}
+
+static int
+nvkm_fanpwm_set(struct nvkm_therm *therm, int percent)
+{
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_fanpwm_priv *priv = (void *)tpriv->fan;
+ int card_type = nv_device(therm)->card_type;
+ u32 divs, duty;
+ int ret;
+
+ divs = priv->base.perf.pwm_divisor;
+ if (priv->base.bios.pwm_freq) {
+ divs = 1;
+ if (therm->pwm_clock)
+ divs = therm->pwm_clock(therm, priv->func.line);
+ divs /= priv->base.bios.pwm_freq;
+ }
+
+ duty = ((divs * percent) + 99) / 100;
+ if (card_type <= NV_40 || (priv->func.log[0] & 1))
+ duty = divs - duty;
+
+ ret = therm->pwm_set(therm, priv->func.line, divs, duty);
+ if (ret == 0)
+ ret = therm->pwm_ctrl(therm, priv->func.line, true);
+ return ret;
+}
+
+int
+nvkm_fanpwm_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
+{
+ struct nvkm_device *device = nv_device(therm);
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_bios *bios = nvkm_bios(therm);
+ struct nvkm_fanpwm_priv *priv;
+ struct nvbios_therm_fan fan;
+ u32 divs, duty;
+
+ nvbios_fan_parse(bios, &fan);
+
+ if (!nvkm_boolopt(device->cfgopt, "NvFanPWM", func->param) ||
+ !therm->pwm_ctrl || fan.type == NVBIOS_THERM_FAN_TOGGLE ||
+ therm->pwm_get(therm, func->line, &divs, &duty) == -ENODEV)
+ return -ENODEV;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ tpriv->fan = &priv->base;
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.type = "PWM";
+ priv->base.get = nvkm_fanpwm_get;
+ priv->base.set = nvkm_fanpwm_set;
+ priv->func = *func;
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c
new file mode 100644
index 000000000000..4ce041e81371
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/fantog.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/gpio.h>
+#include <subdev/timer.h>
+
+struct nvkm_fantog_priv {
+ struct nvkm_fan base;
+ struct nvkm_alarm alarm;
+ spinlock_t lock;
+ u32 period_us;
+ u32 percent;
+ struct dcb_gpio_func func;
+};
+
+static void
+nvkm_fantog_update(struct nvkm_fantog_priv *priv, int percent)
+{
+ struct nvkm_therm_priv *tpriv = (void *)priv->base.parent;
+ struct nvkm_timer *ptimer = nvkm_timer(tpriv);
+ struct nvkm_gpio *gpio = nvkm_gpio(tpriv);
+ unsigned long flags;
+ int duty;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ if (percent < 0)
+ percent = priv->percent;
+ priv->percent = percent;
+
+ duty = !gpio->get(gpio, 0, DCB_GPIO_FAN, 0xff);
+ gpio->set(gpio, 0, DCB_GPIO_FAN, 0xff, duty);
+
+ if (list_empty(&priv->alarm.head) && percent != (duty * 100)) {
+ u64 next_change = (percent * priv->period_us) / 100;
+ if (!duty)
+ next_change = priv->period_us - next_change;
+ ptimer->alarm(ptimer, next_change * 1000, &priv->alarm);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nvkm_fantog_alarm(struct nvkm_alarm *alarm)
+{
+ struct nvkm_fantog_priv *priv =
+ container_of(alarm, struct nvkm_fantog_priv, alarm);
+ nvkm_fantog_update(priv, -1);
+}
+
+static int
+nvkm_fantog_get(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_fantog_priv *priv = (void *)tpriv->fan;
+ return priv->percent;
+}
+
+static int
+nvkm_fantog_set(struct nvkm_therm *therm, int percent)
+{
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_fantog_priv *priv = (void *)tpriv->fan;
+ if (therm->pwm_ctrl)
+ therm->pwm_ctrl(therm, priv->func.line, false);
+ nvkm_fantog_update(priv, percent);
+ return 0;
+}
+
+int
+nvkm_fantog_create(struct nvkm_therm *therm, struct dcb_gpio_func *func)
+{
+ struct nvkm_therm_priv *tpriv = (void *)therm;
+ struct nvkm_fantog_priv *priv;
+ int ret;
+
+ if (therm->pwm_ctrl) {
+ ret = therm->pwm_ctrl(therm, func->line, false);
+ if (ret)
+ return ret;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ tpriv->fan = &priv->base;
+ if (!priv)
+ return -ENOMEM;
+
+ priv->base.type = "toggle";
+ priv->base.get = nvkm_fantog_get;
+ priv->base.set = nvkm_fantog_set;
+ nvkm_alarm_init(&priv->alarm, nvkm_fantog_alarm);
+ priv->period_us = 100000; /* 10Hz */
+ priv->percent = 100;
+ priv->func = *func;
+ spin_lock_init(&priv->lock);
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c
new file mode 100644
index 000000000000..85b5d0c18c0b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/g84.c
@@ -0,0 +1,266 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/fuse.h>
+
+struct g84_therm_priv {
+ struct nvkm_therm_priv base;
+};
+
+int
+g84_temp_get(struct nvkm_therm *therm)
+{
+ struct nvkm_fuse *fuse = nvkm_fuse(therm);
+
+ if (nv_ro32(fuse, 0x1a8) == 1)
+ return nv_rd32(therm, 0x20400);
+ else
+ return -ENODEV;
+}
+
+void
+g84_sensor_setup(struct nvkm_therm *therm)
+{
+ struct nvkm_fuse *fuse = nvkm_fuse(therm);
+
+ /* enable temperature reading for cards with insane defaults */
+ if (nv_ro32(fuse, 0x1a8) == 1) {
+ nv_mask(therm, 0x20008, 0x80008000, 0x80000000);
+ nv_mask(therm, 0x2000c, 0x80000003, 0x00000000);
+ mdelay(20); /* wait for the temperature to stabilize */
+ }
+}
+
+static void
+g84_therm_program_alarms(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
+
+ /* enable RISING and FALLING IRQs for shutdown, THRS 0, 1, 2 and 4 */
+ nv_wr32(therm, 0x20000, 0x000003ff);
+
+ /* shutdown: The computer should be shutdown when reached */
+ nv_wr32(therm, 0x20484, sensor->thrs_shutdown.hysteresis);
+ nv_wr32(therm, 0x20480, sensor->thrs_shutdown.temp);
+
+ /* THRS_1 : fan boost*/
+ nv_wr32(therm, 0x204c4, sensor->thrs_fan_boost.temp);
+
+ /* THRS_2 : critical */
+ nv_wr32(therm, 0x204c0, sensor->thrs_critical.temp);
+
+ /* THRS_4 : down clock */
+ nv_wr32(therm, 0x20414, sensor->thrs_down_clock.temp);
+ spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
+
+ nv_debug(therm,
+ "Programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
+ sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
+ sensor->thrs_down_clock.temp,
+ sensor->thrs_down_clock.hysteresis,
+ sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
+ sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
+
+}
+
+/* must be called with alarm_program_lock taken ! */
+static void
+g84_therm_threshold_hyst_emulation(struct nvkm_therm *therm,
+ uint32_t thrs_reg, u8 status_bit,
+ const struct nvbios_therm_threshold *thrs,
+ enum nvkm_therm_thrs thrs_name)
+{
+ enum nvkm_therm_thrs_direction direction;
+ enum nvkm_therm_thrs_state prev_state, new_state;
+ int temp, cur;
+
+ prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name);
+ temp = nv_rd32(therm, thrs_reg);
+
+ /* program the next threshold */
+ if (temp == thrs->temp) {
+ nv_wr32(therm, thrs_reg, thrs->temp - thrs->hysteresis);
+ new_state = NVKM_THERM_THRS_HIGHER;
+ } else {
+ nv_wr32(therm, thrs_reg, thrs->temp);
+ new_state = NVKM_THERM_THRS_LOWER;
+ }
+
+ /* fix the state (in case someone reprogrammed the alarms) */
+ cur = therm->temp_get(therm);
+ if (new_state == NVKM_THERM_THRS_LOWER && cur > thrs->temp)
+ new_state = NVKM_THERM_THRS_HIGHER;
+ else if (new_state == NVKM_THERM_THRS_HIGHER &&
+ cur < thrs->temp - thrs->hysteresis)
+ new_state = NVKM_THERM_THRS_LOWER;
+ nvkm_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
+
+ /* find the direction */
+ if (prev_state < new_state)
+ direction = NVKM_THERM_THRS_RISING;
+ else if (prev_state > new_state)
+ direction = NVKM_THERM_THRS_FALLING;
+ else
+ return;
+
+ /* advertise a change in direction */
+ nvkm_therm_sensor_event(therm, thrs_name, direction);
+}
+
+static void
+g84_therm_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_therm *therm = nvkm_therm(subdev);
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+ unsigned long flags;
+ uint32_t intr;
+
+ spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
+
+ intr = nv_rd32(therm, 0x20100) & 0x3ff;
+
+ /* THRS_4: downclock */
+ if (intr & 0x002) {
+ g84_therm_threshold_hyst_emulation(therm, 0x20414, 24,
+ &sensor->thrs_down_clock,
+ NVKM_THERM_THRS_DOWNCLOCK);
+ intr &= ~0x002;
+ }
+
+ /* shutdown */
+ if (intr & 0x004) {
+ g84_therm_threshold_hyst_emulation(therm, 0x20480, 20,
+ &sensor->thrs_shutdown,
+ NVKM_THERM_THRS_SHUTDOWN);
+ intr &= ~0x004;
+ }
+
+ /* THRS_1 : fan boost */
+ if (intr & 0x008) {
+ g84_therm_threshold_hyst_emulation(therm, 0x204c4, 21,
+ &sensor->thrs_fan_boost,
+ NVKM_THERM_THRS_FANBOOST);
+ intr &= ~0x008;
+ }
+
+ /* THRS_2 : critical */
+ if (intr & 0x010) {
+ g84_therm_threshold_hyst_emulation(therm, 0x204c0, 22,
+ &sensor->thrs_critical,
+ NVKM_THERM_THRS_CRITICAL);
+ intr &= ~0x010;
+ }
+
+ if (intr)
+ nv_error(therm, "unhandled intr 0x%08x\n", intr);
+
+ /* ACK everything */
+ nv_wr32(therm, 0x20100, 0xffffffff);
+ nv_wr32(therm, 0x1100, 0x10000); /* PBUS */
+
+ spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
+}
+
+static int
+g84_therm_init(struct nvkm_object *object)
+{
+ struct g84_therm_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_therm_init(&priv->base.base);
+ if (ret)
+ return ret;
+
+ g84_sensor_setup(&priv->base.base);
+ return 0;
+}
+
+static int
+g84_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct g84_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_therm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
+ priv->base.base.pwm_get = nv50_fan_pwm_get;
+ priv->base.base.pwm_set = nv50_fan_pwm_set;
+ priv->base.base.pwm_clock = nv50_fan_pwm_clock;
+ priv->base.base.temp_get = g84_temp_get;
+ priv->base.sensor.program_alarms = g84_therm_program_alarms;
+ nv_subdev(priv)->intr = g84_therm_intr;
+
+ /* init the thresholds */
+ nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+ NVKM_THERM_THRS_SHUTDOWN,
+ NVKM_THERM_THRS_LOWER);
+ nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+ NVKM_THERM_THRS_FANBOOST,
+ NVKM_THERM_THRS_LOWER);
+ nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+ NVKM_THERM_THRS_CRITICAL,
+ NVKM_THERM_THRS_LOWER);
+ nvkm_therm_sensor_set_threshold_state(&priv->base.base,
+ NVKM_THERM_THRS_DOWNCLOCK,
+ NVKM_THERM_THRS_LOWER);
+
+ return nvkm_therm_preinit(&priv->base.base);
+}
+
+int
+g84_therm_fini(struct nvkm_object *object, bool suspend)
+{
+ /* Disable PTherm IRQs */
+ nv_wr32(object, 0x20000, 0x00000000);
+
+ /* ACK all PTherm IRQs */
+ nv_wr32(object, 0x20100, 0xffffffff);
+ nv_wr32(object, 0x1100, 0x10000); /* PBUS */
+
+ return _nvkm_therm_fini(object, suspend);
+}
+
+struct nvkm_oclass
+g84_therm_oclass = {
+ .handle = NV_SUBDEV(THERM, 0x84),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = g84_therm_ctor,
+ .dtor = _nvkm_therm_dtor,
+ .init = g84_therm_init,
+ .fini = g84_therm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c
new file mode 100644
index 000000000000..46b7e656a752
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gf110.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct gf110_therm_priv {
+ struct nvkm_therm_priv base;
+};
+
+static int
+pwm_info(struct nvkm_therm *therm, int line)
+{
+ u32 gpio = nv_rd32(therm, 0x00d610 + (line * 0x04));
+
+ switch (gpio & 0x000000c0) {
+ case 0x00000000: /* normal mode, possibly pwm forced off by us */
+ case 0x00000040: /* nvio special */
+ switch (gpio & 0x0000001f) {
+ case 0x00: return 2;
+ case 0x19: return 1;
+ case 0x1c: return 0;
+ case 0x1e: return 2;
+ default:
+ break;
+ }
+ default:
+ break;
+ }
+
+ nv_error(therm, "GPIO %d unknown PWM: 0x%08x\n", line, gpio);
+ return -ENODEV;
+}
+
+static int
+gf110_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+ u32 data = enable ? 0x00000040 : 0x00000000;
+ int indx = pwm_info(therm, line);
+ if (indx < 0)
+ return indx;
+ else if (indx < 2)
+ nv_mask(therm, 0x00d610 + (line * 0x04), 0x000000c0, data);
+ /* nothing to do for indx == 2, it seems hardwired to PTHERM */
+ return 0;
+}
+
+static int
+gf110_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+ int indx = pwm_info(therm, line);
+ if (indx < 0)
+ return indx;
+ else if (indx < 2) {
+ if (nv_rd32(therm, 0x00d610 + (line * 0x04)) & 0x00000040) {
+ *divs = nv_rd32(therm, 0x00e114 + (indx * 8));
+ *duty = nv_rd32(therm, 0x00e118 + (indx * 8));
+ return 0;
+ }
+ } else if (indx == 2) {
+ *divs = nv_rd32(therm, 0x0200d8) & 0x1fff;
+ *duty = nv_rd32(therm, 0x0200dc) & 0x1fff;
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static int
+gf110_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+ int indx = pwm_info(therm, line);
+ if (indx < 0)
+ return indx;
+ else if (indx < 2) {
+ nv_wr32(therm, 0x00e114 + (indx * 8), divs);
+ nv_wr32(therm, 0x00e118 + (indx * 8), duty | 0x80000000);
+ } else if (indx == 2) {
+ nv_mask(therm, 0x0200d8, 0x1fff, divs); /* keep the high bits */
+ nv_wr32(therm, 0x0200dc, duty | 0x40000000);
+ }
+ return 0;
+}
+
+static int
+gf110_fan_pwm_clock(struct nvkm_therm *therm, int line)
+{
+ int indx = pwm_info(therm, line);
+ if (indx < 0)
+ return 0;
+ else if (indx < 2)
+ return (nv_device(therm)->crystal * 1000) / 20;
+ else
+ return nv_device(therm)->crystal * 1000 / 10;
+}
+
+int
+gf110_therm_init(struct nvkm_object *object)
+{
+ struct gf110_therm_priv *priv = (void *)object;
+ int ret;
+
+ ret = nvkm_therm_init(&priv->base.base);
+ if (ret)
+ return ret;
+
+ /* enable fan tach, count revolutions per-second */
+ nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
+ if (priv->base.fan->tach.func != DCB_GPIO_UNUSED) {
+ nv_mask(priv, 0x00d79c, 0x000000ff, priv->base.fan->tach.line);
+ nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
+ nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
+ }
+ nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
+
+ return 0;
+}
+
+static int
+gf110_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gf110_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_therm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ g84_sensor_setup(&priv->base.base);
+
+ priv->base.base.pwm_ctrl = gf110_fan_pwm_ctrl;
+ priv->base.base.pwm_get = gf110_fan_pwm_get;
+ priv->base.base.pwm_set = gf110_fan_pwm_set;
+ priv->base.base.pwm_clock = gf110_fan_pwm_clock;
+ priv->base.base.temp_get = g84_temp_get;
+ priv->base.base.fan_sense = gt215_therm_fan_sense;
+ priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+ return nvkm_therm_preinit(&priv->base.base);
+}
+
+struct nvkm_oclass
+gf110_therm_oclass = {
+ .handle = NV_SUBDEV(THERM, 0xd0),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gf110_therm_ctor,
+ .dtor = _nvkm_therm_dtor,
+ .init = gf110_therm_init,
+ .fini = g84_therm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
new file mode 100644
index 000000000000..2fd110f09878
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gm107.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2014 Martin Peres
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct gm107_therm_priv {
+ struct nvkm_therm_priv base;
+};
+
+static int
+gm107_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+ /* nothing to do, it seems hardwired */
+ return 0;
+}
+
+static int
+gm107_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+ *divs = nv_rd32(therm, 0x10eb20) & 0x1fff;
+ *duty = nv_rd32(therm, 0x10eb24) & 0x1fff;
+ return 0;
+}
+
+static int
+gm107_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+ nv_mask(therm, 0x10eb10, 0x1fff, divs); /* keep the high bits */
+ nv_wr32(therm, 0x10eb14, duty | 0x80000000);
+ return 0;
+}
+
+static int
+gm107_fan_pwm_clock(struct nvkm_therm *therm, int line)
+{
+ return nv_device(therm)->crystal * 1000;
+}
+
+static int
+gm107_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gm107_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_therm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.base.pwm_ctrl = gm107_fan_pwm_ctrl;
+ priv->base.base.pwm_get = gm107_fan_pwm_get;
+ priv->base.base.pwm_set = gm107_fan_pwm_set;
+ priv->base.base.pwm_clock = gm107_fan_pwm_clock;
+ priv->base.base.temp_get = g84_temp_get;
+ priv->base.base.fan_sense = gt215_therm_fan_sense;
+ priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+ return nvkm_therm_preinit(&priv->base.base);
+}
+
+struct nvkm_oclass
+gm107_therm_oclass = {
+ .handle = NV_SUBDEV(THERM, 0x117),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gm107_therm_ctor,
+ .dtor = _nvkm_therm_dtor,
+ .init = gf110_therm_init,
+ .fini = g84_therm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c
new file mode 100644
index 000000000000..e99be20332f2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/gt215.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "priv.h"
+
+#include <core/device.h>
+#include <subdev/gpio.h>
+
+struct gt215_therm_priv {
+ struct nvkm_therm_priv base;
+};
+
+int
+gt215_therm_fan_sense(struct nvkm_therm *therm)
+{
+ u32 tach = nv_rd32(therm, 0x00e728) & 0x0000ffff;
+ u32 ctrl = nv_rd32(therm, 0x00e720);
+ if (ctrl & 0x00000001)
+ return tach * 60 / 2;
+ return -ENODEV;
+}
+
+static int
+gt215_therm_init(struct nvkm_object *object)
+{
+ struct gt215_therm_priv *priv = (void *)object;
+ struct dcb_gpio_func *tach = &priv->base.fan->tach;
+ int ret;
+
+ ret = nvkm_therm_init(&priv->base.base);
+ if (ret)
+ return ret;
+
+ g84_sensor_setup(&priv->base.base);
+
+ /* enable fan tach, count revolutions per-second */
+ nv_mask(priv, 0x00e720, 0x00000003, 0x00000002);
+ if (tach->func != DCB_GPIO_UNUSED) {
+ nv_wr32(priv, 0x00e724, nv_device(priv)->crystal * 1000);
+ nv_mask(priv, 0x00e720, 0x001f0000, tach->line << 16);
+ nv_mask(priv, 0x00e720, 0x00000001, 0x00000001);
+ }
+ nv_mask(priv, 0x00e720, 0x00000002, 0x00000000);
+
+ return 0;
+}
+
+static int
+gt215_therm_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gt215_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_therm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
+ priv->base.base.pwm_get = nv50_fan_pwm_get;
+ priv->base.base.pwm_set = nv50_fan_pwm_set;
+ priv->base.base.pwm_clock = nv50_fan_pwm_clock;
+ priv->base.base.temp_get = g84_temp_get;
+ priv->base.base.fan_sense = gt215_therm_fan_sense;
+ priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+ return nvkm_therm_preinit(&priv->base.base);
+}
+
+struct nvkm_oclass
+gt215_therm_oclass = {
+ .handle = NV_SUBDEV(THERM, 0xa3),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gt215_therm_ctor,
+ .dtor = _nvkm_therm_dtor,
+ .init = gt215_therm_init,
+ .fini = g84_therm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
new file mode 100644
index 000000000000..09fc4605e853
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/ic.c
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2012 Nouveau community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+#include <subdev/bios/extdev.h>
+#include <subdev/i2c.h>
+
+static bool
+probe_monitoring_device(struct nvkm_i2c_port *i2c,
+ struct i2c_board_info *info, void *data)
+{
+ struct nvkm_therm_priv *priv = data;
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+ struct i2c_client *client;
+
+ request_module("%s%s", I2C_MODULE_PREFIX, info->type);
+
+ client = i2c_new_device(&i2c->adapter, info);
+ if (!client)
+ return false;
+
+ if (!client->dev.driver ||
+ to_i2c_driver(client->dev.driver)->detect(client, info)) {
+ i2c_unregister_device(client);
+ return false;
+ }
+
+ nv_info(priv,
+ "Found an %s at address 0x%x (controlled by lm_sensors, "
+ "temp offset %+i C)\n",
+ info->type, info->addr, sensor->offset_constant);
+ priv->ic = client;
+ return true;
+}
+
+static struct nvkm_i2c_board_info
+nv_board_infos[] = {
+ { { I2C_BOARD_INFO("w83l785ts", 0x2d) }, 0 },
+ { { I2C_BOARD_INFO("w83781d", 0x2d) }, 0 },
+ { { I2C_BOARD_INFO("adt7473", 0x2e) }, 40 },
+ { { I2C_BOARD_INFO("adt7473", 0x2d) }, 40 },
+ { { I2C_BOARD_INFO("adt7473", 0x2c) }, 40 },
+ { { I2C_BOARD_INFO("f75375", 0x2e) }, 0 },
+ { { I2C_BOARD_INFO("lm99", 0x4c) }, 0 },
+ { { I2C_BOARD_INFO("lm90", 0x4c) }, 0 },
+ { { I2C_BOARD_INFO("lm90", 0x4d) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x18) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x19) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x1a) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x29) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x2a) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x2b) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x4c) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x4d) }, 0 },
+ { { I2C_BOARD_INFO("adm1021", 0x4e) }, 0 },
+ { { I2C_BOARD_INFO("lm63", 0x18) }, 0 },
+ { { I2C_BOARD_INFO("lm63", 0x4e) }, 0 },
+ { }
+};
+
+void
+nvkm_therm_ic_ctor(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_bios *bios = nvkm_bios(therm);
+ struct nvkm_i2c *i2c = nvkm_i2c(therm);
+ struct nvbios_extdev_func extdev_entry;
+
+ if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_LM89, &extdev_entry)) {
+ struct nvkm_i2c_board_info board[] = {
+ { { I2C_BOARD_INFO("lm90", extdev_entry.addr >> 1) }, 0},
+ { }
+ };
+
+ i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
+ board, probe_monitoring_device, therm);
+ if (priv->ic)
+ return;
+ }
+
+ if (!nvbios_extdev_find(bios, NVBIOS_EXTDEV_ADT7473, &extdev_entry)) {
+ struct nvkm_i2c_board_info board[] = {
+ { { I2C_BOARD_INFO("adt7473", extdev_entry.addr >> 1) }, 20 },
+ { }
+ };
+
+ i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
+ board, probe_monitoring_device, therm);
+ if (priv->ic)
+ return;
+ }
+
+ /* The vbios doesn't provide the address of an exisiting monitoring
+ device. Let's try our static list.
+ */
+ i2c->identify(i2c, NV_I2C_DEFAULT(0), "monitoring device",
+ nv_board_infos, probe_monitoring_device, therm);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
new file mode 100644
index 000000000000..8496fffd4688
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv40.c
@@ -0,0 +1,225 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct nv40_therm_priv {
+ struct nvkm_therm_priv base;
+};
+
+enum nv40_sensor_style { INVALID_STYLE = -1, OLD_STYLE = 0, NEW_STYLE = 1 };
+
+static enum nv40_sensor_style
+nv40_sensor_style(struct nvkm_therm *therm)
+{
+ struct nvkm_device *device = nv_device(therm);
+
+ switch (device->chipset) {
+ case 0x43:
+ case 0x44:
+ case 0x4a:
+ case 0x47:
+ return OLD_STYLE;
+
+ case 0x46:
+ case 0x49:
+ case 0x4b:
+ case 0x4e:
+ case 0x4c:
+ case 0x67:
+ case 0x68:
+ case 0x63:
+ return NEW_STYLE;
+ default:
+ return INVALID_STYLE;
+ }
+}
+
+static int
+nv40_sensor_setup(struct nvkm_therm *therm)
+{
+ enum nv40_sensor_style style = nv40_sensor_style(therm);
+
+ /* enable ADC readout and disable the ALARM threshold */
+ if (style == NEW_STYLE) {
+ nv_mask(therm, 0x15b8, 0x80000000, 0);
+ nv_wr32(therm, 0x15b0, 0x80003fff);
+ mdelay(20); /* wait for the temperature to stabilize */
+ return nv_rd32(therm, 0x15b4) & 0x3fff;
+ } else if (style == OLD_STYLE) {
+ nv_wr32(therm, 0x15b0, 0xff);
+ mdelay(20); /* wait for the temperature to stabilize */
+ return nv_rd32(therm, 0x15b4) & 0xff;
+ } else
+ return -ENODEV;
+}
+
+static int
+nv40_temp_get(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+ enum nv40_sensor_style style = nv40_sensor_style(therm);
+ int core_temp;
+
+ if (style == NEW_STYLE) {
+ nv_wr32(therm, 0x15b0, 0x80003fff);
+ core_temp = nv_rd32(therm, 0x15b4) & 0x3fff;
+ } else if (style == OLD_STYLE) {
+ nv_wr32(therm, 0x15b0, 0xff);
+ core_temp = nv_rd32(therm, 0x15b4) & 0xff;
+ } else
+ return -ENODEV;
+
+ /* if the slope or the offset is unset, do no use the sensor */
+ if (!sensor->slope_div || !sensor->slope_mult ||
+ !sensor->offset_num || !sensor->offset_den)
+ return -ENODEV;
+
+ core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+ core_temp = core_temp + sensor->offset_num / sensor->offset_den;
+ core_temp = core_temp + sensor->offset_constant - 8;
+
+ /* reserve negative temperatures for errors */
+ if (core_temp < 0)
+ core_temp = 0;
+
+ return core_temp;
+}
+
+static int
+nv40_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+ u32 mask = enable ? 0x80000000 : 0x0000000;
+ if (line == 2) nv_mask(therm, 0x0010f0, 0x80000000, mask);
+ else if (line == 9) nv_mask(therm, 0x0015f4, 0x80000000, mask);
+ else {
+ nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int
+nv40_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+ if (line == 2) {
+ u32 reg = nv_rd32(therm, 0x0010f0);
+ if (reg & 0x80000000) {
+ *duty = (reg & 0x7fff0000) >> 16;
+ *divs = (reg & 0x00007fff);
+ return 0;
+ }
+ } else
+ if (line == 9) {
+ u32 reg = nv_rd32(therm, 0x0015f4);
+ if (reg & 0x80000000) {
+ *divs = nv_rd32(therm, 0x0015f8);
+ *duty = (reg & 0x7fffffff);
+ return 0;
+ }
+ } else {
+ nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
+ return -ENODEV;
+ }
+
+ return -EINVAL;
+}
+
+static int
+nv40_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+ if (line == 2) {
+ nv_mask(therm, 0x0010f0, 0x7fff7fff, (duty << 16) | divs);
+ } else
+ if (line == 9) {
+ nv_wr32(therm, 0x0015f8, divs);
+ nv_mask(therm, 0x0015f4, 0x7fffffff, duty);
+ } else {
+ nv_error(therm, "unknown pwm ctrl for gpio %d\n", line);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void
+nv40_therm_intr(struct nvkm_subdev *subdev)
+{
+ struct nvkm_therm *therm = nvkm_therm(subdev);
+ uint32_t stat = nv_rd32(therm, 0x1100);
+
+ /* traitement */
+
+ /* ack all IRQs */
+ nv_wr32(therm, 0x1100, 0x70000);
+
+ nv_error(therm, "THERM received an IRQ: stat = %x\n", stat);
+}
+
+static int
+nv40_therm_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv40_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_therm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.base.pwm_ctrl = nv40_fan_pwm_ctrl;
+ priv->base.base.pwm_get = nv40_fan_pwm_get;
+ priv->base.base.pwm_set = nv40_fan_pwm_set;
+ priv->base.base.temp_get = nv40_temp_get;
+ priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+ nv_subdev(priv)->intr = nv40_therm_intr;
+ return nvkm_therm_preinit(&priv->base.base);
+}
+
+static int
+nv40_therm_init(struct nvkm_object *object)
+{
+ struct nvkm_therm *therm = (void *)object;
+
+ nv40_sensor_setup(therm);
+
+ return _nvkm_therm_init(object);
+}
+
+struct nvkm_oclass
+nv40_therm_oclass = {
+ .handle = NV_SUBDEV(THERM, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_therm_ctor,
+ .dtor = _nvkm_therm_dtor,
+ .init = nv40_therm_init,
+ .fini = _nvkm_therm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c
new file mode 100644
index 000000000000..1ef59e8922d4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/nv50.c
@@ -0,0 +1,198 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ * Martin Peres
+ */
+#include "priv.h"
+
+#include <core/device.h>
+
+struct nv50_therm_priv {
+ struct nvkm_therm_priv base;
+};
+
+static int
+pwm_info(struct nvkm_therm *therm, int *line, int *ctrl, int *indx)
+{
+ if (*line == 0x04) {
+ *ctrl = 0x00e100;
+ *line = 4;
+ *indx = 0;
+ } else
+ if (*line == 0x09) {
+ *ctrl = 0x00e100;
+ *line = 9;
+ *indx = 1;
+ } else
+ if (*line == 0x10) {
+ *ctrl = 0x00e28c;
+ *line = 0;
+ *indx = 0;
+ } else {
+ nv_error(therm, "unknown pwm ctrl for gpio %d\n", *line);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+int
+nv50_fan_pwm_ctrl(struct nvkm_therm *therm, int line, bool enable)
+{
+ u32 data = enable ? 0x00000001 : 0x00000000;
+ int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
+ if (ret == 0)
+ nv_mask(therm, ctrl, 0x00010001 << line, data << line);
+ return ret;
+}
+
+int
+nv50_fan_pwm_get(struct nvkm_therm *therm, int line, u32 *divs, u32 *duty)
+{
+ int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
+ if (ret)
+ return ret;
+
+ if (nv_rd32(therm, ctrl) & (1 << line)) {
+ *divs = nv_rd32(therm, 0x00e114 + (id * 8));
+ *duty = nv_rd32(therm, 0x00e118 + (id * 8));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+int
+nv50_fan_pwm_set(struct nvkm_therm *therm, int line, u32 divs, u32 duty)
+{
+ int ctrl, id, ret = pwm_info(therm, &line, &ctrl, &id);
+ if (ret)
+ return ret;
+
+ nv_wr32(therm, 0x00e114 + (id * 8), divs);
+ nv_wr32(therm, 0x00e118 + (id * 8), duty | 0x80000000);
+ return 0;
+}
+
+int
+nv50_fan_pwm_clock(struct nvkm_therm *therm, int line)
+{
+ int chipset = nv_device(therm)->chipset;
+ int crystal = nv_device(therm)->crystal;
+ int pwm_clock;
+
+ /* determine the PWM source clock */
+ if (chipset > 0x50 && chipset < 0x94) {
+ u8 pwm_div = nv_rd32(therm, 0x410c);
+ if (nv_rd32(therm, 0xc040) & 0x800000) {
+ /* Use the HOST clock (100 MHz)
+ * Where does this constant(2.4) comes from? */
+ pwm_clock = (100000000 >> pwm_div) * 10 / 24;
+ } else {
+ /* Where does this constant(20) comes from? */
+ pwm_clock = (crystal * 1000) >> pwm_div;
+ pwm_clock /= 20;
+ }
+ } else {
+ pwm_clock = (crystal * 1000) / 20;
+ }
+
+ return pwm_clock;
+}
+
+static void
+nv50_sensor_setup(struct nvkm_therm *therm)
+{
+ nv_mask(therm, 0x20010, 0x40000000, 0x0);
+ mdelay(20); /* wait for the temperature to stabilize */
+}
+
+static int
+nv50_temp_get(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+ int core_temp;
+
+ core_temp = nv_rd32(therm, 0x20014) & 0x3fff;
+
+ /* if the slope or the offset is unset, do no use the sensor */
+ if (!sensor->slope_div || !sensor->slope_mult ||
+ !sensor->offset_num || !sensor->offset_den)
+ return -ENODEV;
+
+ core_temp = core_temp * sensor->slope_mult / sensor->slope_div;
+ core_temp = core_temp + sensor->offset_num / sensor->offset_den;
+ core_temp = core_temp + sensor->offset_constant - 8;
+
+ /* reserve negative temperatures for errors */
+ if (core_temp < 0)
+ core_temp = 0;
+
+ return core_temp;
+}
+
+static int
+nv50_therm_ctor(struct nvkm_object *parent,
+ struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv50_therm_priv *priv;
+ int ret;
+
+ ret = nvkm_therm_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.base.pwm_ctrl = nv50_fan_pwm_ctrl;
+ priv->base.base.pwm_get = nv50_fan_pwm_get;
+ priv->base.base.pwm_set = nv50_fan_pwm_set;
+ priv->base.base.pwm_clock = nv50_fan_pwm_clock;
+ priv->base.base.temp_get = nv50_temp_get;
+ priv->base.sensor.program_alarms = nvkm_therm_program_alarms_polling;
+ nv_subdev(priv)->intr = nv40_therm_intr;
+
+ return nvkm_therm_preinit(&priv->base.base);
+}
+
+static int
+nv50_therm_init(struct nvkm_object *object)
+{
+ struct nvkm_therm *therm = (void *)object;
+
+ nv50_sensor_setup(therm);
+
+ return _nvkm_therm_init(object);
+}
+
+struct nvkm_oclass
+nv50_therm_oclass = {
+ .handle = NV_SUBDEV(THERM, 0x50),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv50_therm_ctor,
+ .dtor = _nvkm_therm_dtor,
+ .init = nv50_therm_init,
+ .fini = _nvkm_therm_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
new file mode 100644
index 000000000000..916a149efe6e
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/priv.h
@@ -0,0 +1,153 @@
+#ifndef __NVTHERM_PRIV_H__
+#define __NVTHERM_PRIV_H__
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include <subdev/therm.h>
+#include <subdev/bios.h>
+#include <subdev/bios/extdev.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/bios/perf.h>
+#include <subdev/bios/therm.h>
+#include <subdev/timer.h>
+
+struct nvkm_fan {
+ struct nvkm_therm *parent;
+ const char *type;
+
+ struct nvbios_therm_fan bios;
+ struct nvbios_perf_fan perf;
+
+ struct nvkm_alarm alarm;
+ spinlock_t lock;
+ int percent;
+
+ int (*get)(struct nvkm_therm *);
+ int (*set)(struct nvkm_therm *, int percent);
+
+ struct dcb_gpio_func tach;
+};
+
+enum nvkm_therm_thrs_direction {
+ NVKM_THERM_THRS_FALLING = 0,
+ NVKM_THERM_THRS_RISING = 1
+};
+
+enum nvkm_therm_thrs_state {
+ NVKM_THERM_THRS_LOWER = 0,
+ NVKM_THERM_THRS_HIGHER = 1
+};
+
+enum nvkm_therm_thrs {
+ NVKM_THERM_THRS_FANBOOST = 0,
+ NVKM_THERM_THRS_DOWNCLOCK = 1,
+ NVKM_THERM_THRS_CRITICAL = 2,
+ NVKM_THERM_THRS_SHUTDOWN = 3,
+ NVKM_THERM_THRS_NR
+};
+
+struct nvkm_therm_priv {
+ struct nvkm_therm base;
+
+ /* automatic thermal management */
+ struct nvkm_alarm alarm;
+ spinlock_t lock;
+ struct nvbios_therm_trip_point *last_trip;
+ int mode;
+ int cstate;
+ int suspend;
+
+ /* bios */
+ struct nvbios_therm_sensor bios_sensor;
+
+ /* fan priv */
+ struct nvkm_fan *fan;
+
+ /* alarms priv */
+ struct {
+ spinlock_t alarm_program_lock;
+ struct nvkm_alarm therm_poll_alarm;
+ enum nvkm_therm_thrs_state alarm_state[NVKM_THERM_THRS_NR];
+ void (*program_alarms)(struct nvkm_therm *);
+ } sensor;
+
+ /* what should be done if the card overheats */
+ struct {
+ void (*downclock)(struct nvkm_therm *, bool active);
+ void (*pause)(struct nvkm_therm *, bool active);
+ } emergency;
+
+ /* ic */
+ struct i2c_client *ic;
+};
+
+int nvkm_therm_fan_mode(struct nvkm_therm *, int mode);
+int nvkm_therm_attr_get(struct nvkm_therm *, enum nvkm_therm_attr_type);
+int nvkm_therm_attr_set(struct nvkm_therm *, enum nvkm_therm_attr_type, int);
+
+void nvkm_therm_ic_ctor(struct nvkm_therm *);
+
+int nvkm_therm_sensor_ctor(struct nvkm_therm *);
+
+int nvkm_therm_fan_ctor(struct nvkm_therm *);
+int nvkm_therm_fan_init(struct nvkm_therm *);
+int nvkm_therm_fan_fini(struct nvkm_therm *, bool suspend);
+int nvkm_therm_fan_get(struct nvkm_therm *);
+int nvkm_therm_fan_set(struct nvkm_therm *, bool now, int percent);
+int nvkm_therm_fan_user_get(struct nvkm_therm *);
+int nvkm_therm_fan_user_set(struct nvkm_therm *, int percent);
+
+int nvkm_therm_fan_sense(struct nvkm_therm *);
+
+int nvkm_therm_preinit(struct nvkm_therm *);
+
+int nvkm_therm_sensor_init(struct nvkm_therm *);
+int nvkm_therm_sensor_fini(struct nvkm_therm *, bool suspend);
+void nvkm_therm_sensor_preinit(struct nvkm_therm *);
+void nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *,
+ enum nvkm_therm_thrs,
+ enum nvkm_therm_thrs_state);
+enum nvkm_therm_thrs_state
+nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *,
+ enum nvkm_therm_thrs);
+void nvkm_therm_sensor_event(struct nvkm_therm *, enum nvkm_therm_thrs,
+ enum nvkm_therm_thrs_direction);
+void nvkm_therm_program_alarms_polling(struct nvkm_therm *);
+
+void nv40_therm_intr(struct nvkm_subdev *);
+int nv50_fan_pwm_ctrl(struct nvkm_therm *, int, bool);
+int nv50_fan_pwm_get(struct nvkm_therm *, int, u32 *, u32 *);
+int nv50_fan_pwm_set(struct nvkm_therm *, int, u32, u32);
+int nv50_fan_pwm_clock(struct nvkm_therm *, int);
+int g84_temp_get(struct nvkm_therm *);
+void g84_sensor_setup(struct nvkm_therm *);
+int g84_therm_fini(struct nvkm_object *, bool suspend);
+
+int gt215_therm_fan_sense(struct nvkm_therm *);
+
+int gf110_therm_init(struct nvkm_object *);
+
+int nvkm_fanpwm_create(struct nvkm_therm *, struct dcb_gpio_func *);
+int nvkm_fantog_create(struct nvkm_therm *, struct dcb_gpio_func *);
+int nvkm_fannil_create(struct nvkm_therm *);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
new file mode 100644
index 000000000000..aa13744f3854
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/therm/temp.c
@@ -0,0 +1,259 @@
+/*
+ * Copyright 2012 The Nouveau community
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Martin Peres
+ */
+#include "priv.h"
+
+static void
+nvkm_therm_temp_set_defaults(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+
+ priv->bios_sensor.offset_constant = 0;
+
+ priv->bios_sensor.thrs_fan_boost.temp = 90;
+ priv->bios_sensor.thrs_fan_boost.hysteresis = 3;
+
+ priv->bios_sensor.thrs_down_clock.temp = 95;
+ priv->bios_sensor.thrs_down_clock.hysteresis = 3;
+
+ priv->bios_sensor.thrs_critical.temp = 105;
+ priv->bios_sensor.thrs_critical.hysteresis = 5;
+
+ priv->bios_sensor.thrs_shutdown.temp = 135;
+ priv->bios_sensor.thrs_shutdown.hysteresis = 5; /*not that it matters */
+}
+
+
+static void
+nvkm_therm_temp_safety_checks(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_sensor *s = &priv->bios_sensor;
+
+ /* enforce a minimum hysteresis on thresholds */
+ s->thrs_fan_boost.hysteresis = max_t(u8, s->thrs_fan_boost.hysteresis, 2);
+ s->thrs_down_clock.hysteresis = max_t(u8, s->thrs_down_clock.hysteresis, 2);
+ s->thrs_critical.hysteresis = max_t(u8, s->thrs_critical.hysteresis, 2);
+ s->thrs_shutdown.hysteresis = max_t(u8, s->thrs_shutdown.hysteresis, 2);
+}
+
+/* must be called with alarm_program_lock taken ! */
+void
+nvkm_therm_sensor_set_threshold_state(struct nvkm_therm *therm,
+ enum nvkm_therm_thrs thrs,
+ enum nvkm_therm_thrs_state st)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ priv->sensor.alarm_state[thrs] = st;
+}
+
+/* must be called with alarm_program_lock taken ! */
+enum nvkm_therm_thrs_state
+nvkm_therm_sensor_get_threshold_state(struct nvkm_therm *therm,
+ enum nvkm_therm_thrs thrs)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ return priv->sensor.alarm_state[thrs];
+}
+
+static void
+nv_poweroff_work(struct work_struct *work)
+{
+ orderly_poweroff(true);
+ kfree(work);
+}
+
+void
+nvkm_therm_sensor_event(struct nvkm_therm *therm, enum nvkm_therm_thrs thrs,
+ enum nvkm_therm_thrs_direction dir)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ bool active;
+ const char *thresolds[] = {
+ "fanboost", "downclock", "critical", "shutdown"
+ };
+ int temperature = therm->temp_get(therm);
+
+ if (thrs < 0 || thrs > 3)
+ return;
+
+ if (dir == NVKM_THERM_THRS_FALLING)
+ nv_info(therm, "temperature (%i C) went below the '%s' threshold\n",
+ temperature, thresolds[thrs]);
+ else
+ nv_info(therm, "temperature (%i C) hit the '%s' threshold\n",
+ temperature, thresolds[thrs]);
+
+ active = (dir == NVKM_THERM_THRS_RISING);
+ switch (thrs) {
+ case NVKM_THERM_THRS_FANBOOST:
+ if (active) {
+ nvkm_therm_fan_set(therm, true, 100);
+ nvkm_therm_fan_mode(therm, NVKM_THERM_CTRL_AUTO);
+ }
+ break;
+ case NVKM_THERM_THRS_DOWNCLOCK:
+ if (priv->emergency.downclock)
+ priv->emergency.downclock(therm, active);
+ break;
+ case NVKM_THERM_THRS_CRITICAL:
+ if (priv->emergency.pause)
+ priv->emergency.pause(therm, active);
+ break;
+ case NVKM_THERM_THRS_SHUTDOWN:
+ if (active) {
+ struct work_struct *work;
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (work) {
+ INIT_WORK(work, nv_poweroff_work);
+ schedule_work(work);
+ }
+ }
+ break;
+ case NVKM_THERM_THRS_NR:
+ break;
+ }
+
+}
+
+/* must be called with alarm_program_lock taken ! */
+static void
+nvkm_therm_threshold_hyst_polling(struct nvkm_therm *therm,
+ const struct nvbios_therm_threshold *thrs,
+ enum nvkm_therm_thrs thrs_name)
+{
+ enum nvkm_therm_thrs_direction direction;
+ enum nvkm_therm_thrs_state prev_state, new_state;
+ int temp = therm->temp_get(therm);
+
+ prev_state = nvkm_therm_sensor_get_threshold_state(therm, thrs_name);
+
+ if (temp >= thrs->temp && prev_state == NVKM_THERM_THRS_LOWER) {
+ direction = NVKM_THERM_THRS_RISING;
+ new_state = NVKM_THERM_THRS_HIGHER;
+ } else if (temp <= thrs->temp - thrs->hysteresis &&
+ prev_state == NVKM_THERM_THRS_HIGHER) {
+ direction = NVKM_THERM_THRS_FALLING;
+ new_state = NVKM_THERM_THRS_LOWER;
+ } else
+ return; /* nothing to do */
+
+ nvkm_therm_sensor_set_threshold_state(therm, thrs_name, new_state);
+ nvkm_therm_sensor_event(therm, thrs_name, direction);
+}
+
+static void
+alarm_timer_callback(struct nvkm_alarm *alarm)
+{
+ struct nvkm_therm_priv *priv =
+ container_of(alarm, struct nvkm_therm_priv, sensor.therm_poll_alarm);
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+ struct nvkm_timer *ptimer = nvkm_timer(priv);
+ struct nvkm_therm *therm = &priv->base;
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->sensor.alarm_program_lock, flags);
+
+ nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_fan_boost,
+ NVKM_THERM_THRS_FANBOOST);
+
+ nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_down_clock,
+ NVKM_THERM_THRS_DOWNCLOCK);
+
+ nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_critical,
+ NVKM_THERM_THRS_CRITICAL);
+
+ nvkm_therm_threshold_hyst_polling(therm, &sensor->thrs_shutdown,
+ NVKM_THERM_THRS_SHUTDOWN);
+
+ spin_unlock_irqrestore(&priv->sensor.alarm_program_lock, flags);
+
+ /* schedule the next poll in one second */
+ if (therm->temp_get(therm) >= 0 && list_empty(&alarm->head))
+ ptimer->alarm(ptimer, 1000000000ULL, alarm);
+}
+
+void
+nvkm_therm_program_alarms_polling(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvbios_therm_sensor *sensor = &priv->bios_sensor;
+
+ nv_debug(therm,
+ "programmed thresholds [ %d(%d), %d(%d), %d(%d), %d(%d) ]\n",
+ sensor->thrs_fan_boost.temp, sensor->thrs_fan_boost.hysteresis,
+ sensor->thrs_down_clock.temp,
+ sensor->thrs_down_clock.hysteresis,
+ sensor->thrs_critical.temp, sensor->thrs_critical.hysteresis,
+ sensor->thrs_shutdown.temp, sensor->thrs_shutdown.hysteresis);
+
+ alarm_timer_callback(&priv->sensor.therm_poll_alarm);
+}
+
+int
+nvkm_therm_sensor_init(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ priv->sensor.program_alarms(therm);
+ return 0;
+}
+
+int
+nvkm_therm_sensor_fini(struct nvkm_therm *therm, bool suspend)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_timer *ptimer = nvkm_timer(therm);
+
+ if (suspend)
+ ptimer->alarm_cancel(ptimer, &priv->sensor.therm_poll_alarm);
+ return 0;
+}
+
+void
+nvkm_therm_sensor_preinit(struct nvkm_therm *therm)
+{
+ const char *sensor_avail = "yes";
+
+ if (therm->temp_get(therm) < 0)
+ sensor_avail = "no";
+
+ nv_info(therm, "internal sensor: %s\n", sensor_avail);
+}
+
+int
+nvkm_therm_sensor_ctor(struct nvkm_therm *therm)
+{
+ struct nvkm_therm_priv *priv = (void *)therm;
+ struct nvkm_bios *bios = nvkm_bios(therm);
+
+ nvkm_alarm_init(&priv->sensor.therm_poll_alarm, alarm_timer_callback);
+
+ nvkm_therm_temp_set_defaults(therm);
+ if (nvbios_therm_sensor_parse(bios, NVBIOS_THERM_DOMAIN_CORE,
+ &priv->bios_sensor))
+ nv_error(therm, "nvbios_therm_sensor_parse failed\n");
+ nvkm_therm_temp_safety_checks(therm);
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild
new file mode 100644
index 000000000000..d1d38b4ba30a
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/Kbuild
@@ -0,0 +1,3 @@
+nvkm-y += nvkm/subdev/timer/base.o
+nvkm-y += nvkm/subdev/timer/nv04.o
+nvkm-y += nvkm/subdev/timer/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
new file mode 100644
index 000000000000..d894061ced52
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/base.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/timer.h>
+
+bool
+nvkm_timer_wait_eq(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(obj);
+ u64 time0;
+
+ time0 = ptimer->read(ptimer);
+ do {
+ if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
+ if ((nv_rd32(obj, addr) & mask) == data)
+ return true;
+ } else {
+ if ((nv_ro32(obj, addr) & mask) == data)
+ return true;
+ }
+ } while (ptimer->read(ptimer) - time0 < nsec);
+
+ return false;
+}
+
+bool
+nvkm_timer_wait_ne(void *obj, u64 nsec, u32 addr, u32 mask, u32 data)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(obj);
+ u64 time0;
+
+ time0 = ptimer->read(ptimer);
+ do {
+ if (nv_iclass(obj, NV_SUBDEV_CLASS)) {
+ if ((nv_rd32(obj, addr) & mask) != data)
+ return true;
+ } else {
+ if ((nv_ro32(obj, addr) & mask) != data)
+ return true;
+ }
+ } while (ptimer->read(ptimer) - time0 < nsec);
+
+ return false;
+}
+
+bool
+nvkm_timer_wait_cb(void *obj, u64 nsec, bool (*func)(void *), void *data)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(obj);
+ u64 time0;
+
+ time0 = ptimer->read(ptimer);
+ do {
+ if (func(data) == true)
+ return true;
+ } while (ptimer->read(ptimer) - time0 < nsec);
+
+ return false;
+}
+
+void
+nvkm_timer_alarm(void *obj, u32 nsec, struct nvkm_alarm *alarm)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(obj);
+ ptimer->alarm(ptimer, nsec, alarm);
+}
+
+void
+nvkm_timer_alarm_cancel(void *obj, struct nvkm_alarm *alarm)
+{
+ struct nvkm_timer *ptimer = nvkm_timer(obj);
+ ptimer->alarm_cancel(ptimer, alarm);
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c
new file mode 100644
index 000000000000..80e38063dd9b
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/gk20a.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+static int
+gk20a_timer_init(struct nvkm_object *object)
+{
+ struct nv04_timer_priv *priv = (void *)object;
+ u32 hi = upper_32_bits(priv->suspend_time);
+ u32 lo = lower_32_bits(priv->suspend_time);
+ int ret;
+
+ ret = nvkm_timer_init(&priv->base);
+ if (ret)
+ return ret;
+
+ nv_debug(priv, "time low : 0x%08x\n", lo);
+ nv_debug(priv, "time high : 0x%08x\n", hi);
+
+ /* restore the time before suspend */
+ nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+ nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+ return 0;
+}
+
+struct nvkm_oclass
+gk20a_timer_oclass = {
+ .handle = NV_SUBDEV(TIMER, 0xff),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_timer_ctor,
+ .dtor = nv04_timer_dtor,
+ .init = gk20a_timer_init,
+ .fini = nv04_timer_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
new file mode 100644
index 000000000000..6b7facbe59a2
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright 2012 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include "nv04.h"
+
+#include <core/device.h>
+
+static u64
+nv04_timer_read(struct nvkm_timer *ptimer)
+{
+ struct nv04_timer_priv *priv = (void *)ptimer;
+ u32 hi, lo;
+
+ do {
+ hi = nv_rd32(priv, NV04_PTIMER_TIME_1);
+ lo = nv_rd32(priv, NV04_PTIMER_TIME_0);
+ } while (hi != nv_rd32(priv, NV04_PTIMER_TIME_1));
+
+ return ((u64)hi << 32 | lo);
+}
+
+static void
+nv04_timer_alarm_trigger(struct nvkm_timer *ptimer)
+{
+ struct nv04_timer_priv *priv = (void *)ptimer;
+ struct nvkm_alarm *alarm, *atemp;
+ unsigned long flags;
+ LIST_HEAD(exec);
+
+ /* move any due alarms off the pending list */
+ spin_lock_irqsave(&priv->lock, flags);
+ list_for_each_entry_safe(alarm, atemp, &priv->alarms, head) {
+ if (alarm->timestamp <= ptimer->read(ptimer))
+ list_move_tail(&alarm->head, &exec);
+ }
+
+ /* reschedule interrupt for next alarm time */
+ if (!list_empty(&priv->alarms)) {
+ alarm = list_first_entry(&priv->alarms, typeof(*alarm), head);
+ nv_wr32(priv, NV04_PTIMER_ALARM_0, alarm->timestamp);
+ nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000001);
+ } else {
+ nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* execute any pending alarm handlers */
+ list_for_each_entry_safe(alarm, atemp, &exec, head) {
+ list_del_init(&alarm->head);
+ alarm->func(alarm);
+ }
+}
+
+static void
+nv04_timer_alarm(struct nvkm_timer *ptimer, u64 time, struct nvkm_alarm *alarm)
+{
+ struct nv04_timer_priv *priv = (void *)ptimer;
+ struct nvkm_alarm *list;
+ unsigned long flags;
+
+ alarm->timestamp = ptimer->read(ptimer) + time;
+
+ /* append new alarm to list, in soonest-alarm-first order */
+ spin_lock_irqsave(&priv->lock, flags);
+ if (!time) {
+ if (!list_empty(&alarm->head))
+ list_del(&alarm->head);
+ } else {
+ list_for_each_entry(list, &priv->alarms, head) {
+ if (list->timestamp > alarm->timestamp)
+ break;
+ }
+ list_add_tail(&alarm->head, &list->head);
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+
+ /* process pending alarms */
+ nv04_timer_alarm_trigger(ptimer);
+}
+
+static void
+nv04_timer_alarm_cancel(struct nvkm_timer *ptimer, struct nvkm_alarm *alarm)
+{
+ struct nv04_timer_priv *priv = (void *)ptimer;
+ unsigned long flags;
+ spin_lock_irqsave(&priv->lock, flags);
+ list_del_init(&alarm->head);
+ spin_unlock_irqrestore(&priv->lock, flags);
+}
+
+static void
+nv04_timer_intr(struct nvkm_subdev *subdev)
+{
+ struct nv04_timer_priv *priv = (void *)subdev;
+ u32 stat = nv_rd32(priv, NV04_PTIMER_INTR_0);
+
+ if (stat & 0x00000001) {
+ nv04_timer_alarm_trigger(&priv->base);
+ nv_wr32(priv, NV04_PTIMER_INTR_0, 0x00000001);
+ stat &= ~0x00000001;
+ }
+
+ if (stat) {
+ nv_error(priv, "unknown stat 0x%08x\n", stat);
+ nv_wr32(priv, NV04_PTIMER_INTR_0, stat);
+ }
+}
+
+int
+nv04_timer_fini(struct nvkm_object *object, bool suspend)
+{
+ struct nv04_timer_priv *priv = (void *)object;
+ if (suspend)
+ priv->suspend_time = nv04_timer_read(&priv->base);
+ nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+ return nvkm_timer_fini(&priv->base, suspend);
+}
+
+static int
+nv04_timer_init(struct nvkm_object *object)
+{
+ struct nvkm_device *device = nv_device(object);
+ struct nv04_timer_priv *priv = (void *)object;
+ u32 m = 1, f, n, d, lo, hi;
+ int ret;
+
+ ret = nvkm_timer_init(&priv->base);
+ if (ret)
+ return ret;
+
+ /* aim for 31.25MHz, which gives us nanosecond timestamps */
+ d = 1000000 / 32;
+
+ /* determine base clock for timer source */
+#if 0 /*XXX*/
+ if (device->chipset < 0x40) {
+ n = nvkm_hw_get_clock(device, PLL_CORE);
+ } else
+#endif
+ if (device->chipset <= 0x40) {
+ /*XXX: figure this out */
+ f = -1;
+ n = 0;
+ } else {
+ f = device->crystal;
+ n = f;
+ while (n < (d * 2)) {
+ n += (n / m);
+ m++;
+ }
+
+ nv_wr32(priv, 0x009220, m - 1);
+ }
+
+ if (!n) {
+ nv_warn(priv, "unknown input clock freq\n");
+ if (!nv_rd32(priv, NV04_PTIMER_NUMERATOR) ||
+ !nv_rd32(priv, NV04_PTIMER_DENOMINATOR)) {
+ nv_wr32(priv, NV04_PTIMER_NUMERATOR, 1);
+ nv_wr32(priv, NV04_PTIMER_DENOMINATOR, 1);
+ }
+ return 0;
+ }
+
+ /* reduce ratio to acceptable values */
+ while (((n % 5) == 0) && ((d % 5) == 0)) {
+ n /= 5;
+ d /= 5;
+ }
+
+ while (((n % 2) == 0) && ((d % 2) == 0)) {
+ n /= 2;
+ d /= 2;
+ }
+
+ while (n > 0xffff || d > 0xffff) {
+ n >>= 1;
+ d >>= 1;
+ }
+
+ /* restore the time before suspend */
+ lo = priv->suspend_time;
+ hi = (priv->suspend_time >> 32);
+
+ nv_debug(priv, "input frequency : %dHz\n", f);
+ nv_debug(priv, "input multiplier: %d\n", m);
+ nv_debug(priv, "numerator : 0x%08x\n", n);
+ nv_debug(priv, "denominator : 0x%08x\n", d);
+ nv_debug(priv, "timer frequency : %dHz\n", (f * m) * d / n);
+ nv_debug(priv, "time low : 0x%08x\n", lo);
+ nv_debug(priv, "time high : 0x%08x\n", hi);
+
+ nv_wr32(priv, NV04_PTIMER_NUMERATOR, n);
+ nv_wr32(priv, NV04_PTIMER_DENOMINATOR, d);
+ nv_wr32(priv, NV04_PTIMER_INTR_0, 0xffffffff);
+ nv_wr32(priv, NV04_PTIMER_INTR_EN_0, 0x00000000);
+ nv_wr32(priv, NV04_PTIMER_TIME_1, hi);
+ nv_wr32(priv, NV04_PTIMER_TIME_0, lo);
+ return 0;
+}
+
+void
+nv04_timer_dtor(struct nvkm_object *object)
+{
+ struct nv04_timer_priv *priv = (void *)object;
+ return nvkm_timer_destroy(&priv->base);
+}
+
+int
+nv04_timer_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv04_timer_priv *priv;
+ int ret;
+
+ ret = nvkm_timer_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ priv->base.base.intr = nv04_timer_intr;
+ priv->base.read = nv04_timer_read;
+ priv->base.alarm = nv04_timer_alarm;
+ priv->base.alarm_cancel = nv04_timer_alarm_cancel;
+ priv->suspend_time = 0;
+
+ INIT_LIST_HEAD(&priv->alarms);
+ spin_lock_init(&priv->lock);
+ return 0;
+}
+
+struct nvkm_oclass
+nv04_timer_oclass = {
+ .handle = NV_SUBDEV(TIMER, 0x04),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv04_timer_ctor,
+ .dtor = nv04_timer_dtor,
+ .init = nv04_timer_init,
+ .fini = nv04_timer_fini,
+ }
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h
new file mode 100644
index 000000000000..89996a9826b1
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/nv04.h
@@ -0,0 +1,25 @@
+#ifndef __NVKM_TIMER_NV04_H__
+#define __NVKM_TIMER_NV04_H__
+#include "priv.h"
+
+#define NV04_PTIMER_INTR_0 0x009100
+#define NV04_PTIMER_INTR_EN_0 0x009140
+#define NV04_PTIMER_NUMERATOR 0x009200
+#define NV04_PTIMER_DENOMINATOR 0x009210
+#define NV04_PTIMER_TIME_0 0x009400
+#define NV04_PTIMER_TIME_1 0x009410
+#define NV04_PTIMER_ALARM_0 0x009420
+
+struct nv04_timer_priv {
+ struct nvkm_timer base;
+ struct list_head alarms;
+ spinlock_t lock;
+ u64 suspend_time;
+};
+
+int nv04_timer_ctor(struct nvkm_object *, struct nvkm_object *,
+ struct nvkm_oclass *, void *, u32,
+ struct nvkm_object **);
+void nv04_timer_dtor(struct nvkm_object *);
+int nv04_timer_fini(struct nvkm_object *, bool);
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h
new file mode 100644
index 000000000000..08e29a3da188
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/timer/priv.h
@@ -0,0 +1,4 @@
+#ifndef __NVKM_TIMER_PRIV_H__
+#define __NVKM_TIMER_PRIV_H__
+#include <subdev/timer.h>
+#endif
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
new file mode 100644
index 000000000000..6b46ff4213a3
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/Kbuild
@@ -0,0 +1,4 @@
+nvkm-y += nvkm/subdev/volt/base.o
+nvkm-y += nvkm/subdev/volt/gpio.o
+nvkm-y += nvkm/subdev/volt/nv40.o
+nvkm-y += nvkm/subdev/volt/gk20a.o
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
new file mode 100644
index 000000000000..39f15803f2d4
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/base.c
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/volt.h>
+#include <subdev/bios.h>
+#include <subdev/bios/vmap.h>
+#include <subdev/bios/volt.h>
+
+static int
+nvkm_volt_get(struct nvkm_volt *volt)
+{
+ if (volt->vid_get) {
+ int ret = volt->vid_get(volt), i;
+ if (ret >= 0) {
+ for (i = 0; i < volt->vid_nr; i++) {
+ if (volt->vid[i].vid == ret)
+ return volt->vid[i].uv;
+ }
+ ret = -EINVAL;
+ }
+ return ret;
+ }
+ return -ENODEV;
+}
+
+static int
+nvkm_volt_set(struct nvkm_volt *volt, u32 uv)
+{
+ if (volt->vid_set) {
+ int i, ret = -EINVAL;
+ for (i = 0; i < volt->vid_nr; i++) {
+ if (volt->vid[i].uv == uv) {
+ ret = volt->vid_set(volt, volt->vid[i].vid);
+ nv_debug(volt, "set %duv: %d\n", uv, ret);
+ break;
+ }
+ }
+ return ret;
+ }
+ return -ENODEV;
+}
+
+static int
+nvkm_volt_map(struct nvkm_volt *volt, u8 id)
+{
+ struct nvkm_bios *bios = nvkm_bios(volt);
+ struct nvbios_vmap_entry info;
+ u8 ver, len;
+ u16 vmap;
+
+ vmap = nvbios_vmap_entry_parse(bios, id, &ver, &len, &info);
+ if (vmap) {
+ if (info.link != 0xff) {
+ int ret = nvkm_volt_map(volt, info.link);
+ if (ret < 0)
+ return ret;
+ info.min += ret;
+ }
+ return info.min;
+ }
+
+ return id ? id * 10000 : -ENODEV;
+}
+
+static int
+nvkm_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
+{
+ int ret = nvkm_volt_map(volt, id);
+ if (ret >= 0) {
+ int prev = nvkm_volt_get(volt);
+ if (!condition || prev < 0 ||
+ (condition < 0 && ret < prev) ||
+ (condition > 0 && ret > prev)) {
+ ret = nvkm_volt_set(volt, ret);
+ } else {
+ ret = 0;
+ }
+ }
+ return ret;
+}
+
+static void
+nvkm_volt_parse_bios(struct nvkm_bios *bios, struct nvkm_volt *volt)
+{
+ struct nvbios_volt_entry ivid;
+ struct nvbios_volt info;
+ u8 ver, hdr, cnt, len;
+ u16 data;
+ int i;
+
+ data = nvbios_volt_parse(bios, &ver, &hdr, &cnt, &len, &info);
+ if (data && info.vidmask && info.base && info.step) {
+ for (i = 0; i < info.vidmask + 1; i++) {
+ if (info.base >= info.min &&
+ info.base <= info.max) {
+ volt->vid[volt->vid_nr].uv = info.base;
+ volt->vid[volt->vid_nr].vid = i;
+ volt->vid_nr++;
+ }
+ info.base += info.step;
+ }
+ volt->vid_mask = info.vidmask;
+ } else if (data && info.vidmask) {
+ for (i = 0; i < cnt; i++) {
+ data = nvbios_volt_entry_parse(bios, i, &ver, &hdr,
+ &ivid);
+ if (data) {
+ volt->vid[volt->vid_nr].uv = ivid.voltage;
+ volt->vid[volt->vid_nr].vid = ivid.vid;
+ volt->vid_nr++;
+ }
+ }
+ volt->vid_mask = info.vidmask;
+ }
+}
+
+int
+_nvkm_volt_init(struct nvkm_object *object)
+{
+ struct nvkm_volt *volt = (void *)object;
+ int ret;
+
+ ret = nvkm_subdev_init(&volt->base);
+ if (ret)
+ return ret;
+
+ ret = volt->get(volt);
+ if (ret < 0) {
+ if (ret != -ENODEV)
+ nv_debug(volt, "current voltage unknown\n");
+ return 0;
+ }
+
+ nv_info(volt, "GPU voltage: %duv\n", ret);
+ return 0;
+}
+
+void
+_nvkm_volt_dtor(struct nvkm_object *object)
+{
+ struct nvkm_volt *volt = (void *)object;
+ nvkm_subdev_destroy(&volt->base);
+}
+
+int
+nvkm_volt_create_(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, int length, void **pobject)
+{
+ struct nvkm_bios *bios = nvkm_bios(parent);
+ struct nvkm_volt *volt;
+ int ret, i;
+
+ ret = nvkm_subdev_create_(parent, engine, oclass, 0, "VOLT",
+ "voltage", length, pobject);
+ volt = *pobject;
+ if (ret)
+ return ret;
+
+ volt->get = nvkm_volt_get;
+ volt->set = nvkm_volt_set;
+ volt->set_id = nvkm_volt_set_id;
+
+ /* Assuming the non-bios device should build the voltage table later */
+ if (bios)
+ nvkm_volt_parse_bios(bios, volt);
+
+ if (volt->vid_nr) {
+ for (i = 0; i < volt->vid_nr; i++) {
+ nv_debug(volt, "VID %02x: %duv\n",
+ volt->vid[i].vid, volt->vid[i].uv);
+ }
+
+ /*XXX: this is an assumption.. there probably exists boards
+ * out there with i2c-connected voltage controllers too..
+ */
+ ret = nvkm_voltgpio_init(volt);
+ if (ret == 0) {
+ volt->vid_get = nvkm_voltgpio_get;
+ volt->vid_set = nvkm_voltgpio_set;
+ }
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c
new file mode 100644
index 000000000000..871fd51011db
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gk20a.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 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 <subdev/volt.h>
+#ifdef __KERNEL__
+#include <nouveau_platform.h>
+#endif
+
+struct cvb_coef {
+ int c0;
+ int c1;
+ int c2;
+ int c3;
+ int c4;
+ int c5;
+};
+
+struct gk20a_volt_priv {
+ struct nvkm_volt base;
+ struct regulator *vdd;
+};
+
+const struct cvb_coef gk20a_cvb_coef[] = {
+ /* MHz, c0, c1, c2, c3, c4, c5 */
+ /* 72 */ { 1209886, -36468, 515, 417, -13123, 203},
+ /* 108 */ { 1130804, -27659, 296, 298, -10834, 221},
+ /* 180 */ { 1162871, -27110, 247, 238, -10681, 268},
+ /* 252 */ { 1220458, -28654, 247, 179, -10376, 298},
+ /* 324 */ { 1280953, -30204, 247, 119, -9766, 304},
+ /* 396 */ { 1344547, -31777, 247, 119, -8545, 292},
+ /* 468 */ { 1420168, -34227, 269, 60, -7172, 256},
+ /* 540 */ { 1490757, -35955, 274, 60, -5188, 197},
+ /* 612 */ { 1599112, -42583, 398, 0, -1831, 119},
+ /* 648 */ { 1366986, -16459, -274, 0, -3204, 72},
+ /* 684 */ { 1391884, -17078, -274, -60, -1526, 30},
+ /* 708 */ { 1415522, -17497, -274, -60, -458, 0},
+ /* 756 */ { 1464061, -18331, -274, -119, 1831, -72},
+ /* 804 */ { 1524225, -20064, -254, -119, 4272, -155},
+ /* 852 */ { 1608418, -21643, -269, 0, 763, -48},
+};
+
+/**
+ * cvb_mv = ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0)
+ */
+static inline int
+gk20a_volt_get_cvb_voltage(int speedo, int s_scale, const struct cvb_coef *coef)
+{
+ int mv;
+
+ mv = DIV_ROUND_CLOSEST(coef->c2 * speedo, s_scale);
+ mv = DIV_ROUND_CLOSEST((mv + coef->c1) * speedo, s_scale) + coef->c0;
+ return mv;
+}
+
+/**
+ * cvb_t_mv =
+ * ((c2 * speedo / s_scale + c1) * speedo / s_scale + c0) +
+ * ((c3 * speedo / s_scale + c4 + c5 * T / t_scale) * T / t_scale)
+ */
+static inline int
+gk20a_volt_get_cvb_t_voltage(int speedo, int temp, int s_scale, int t_scale,
+ const struct cvb_coef *coef)
+{
+ int cvb_mv, mv;
+
+ cvb_mv = gk20a_volt_get_cvb_voltage(speedo, s_scale, coef);
+
+ mv = DIV_ROUND_CLOSEST(coef->c3 * speedo, s_scale) + coef->c4 +
+ DIV_ROUND_CLOSEST(coef->c5 * temp, t_scale);
+ mv = DIV_ROUND_CLOSEST(mv * temp, t_scale) + cvb_mv;
+ return mv;
+}
+
+static int
+gk20a_volt_calc_voltage(const struct cvb_coef *coef, int speedo)
+{
+ int mv;
+
+ mv = gk20a_volt_get_cvb_t_voltage(speedo, -10, 100, 10, coef);
+ mv = DIV_ROUND_UP(mv, 1000);
+
+ return mv * 1000;
+}
+
+static int
+gk20a_volt_vid_get(struct nvkm_volt *volt)
+{
+ struct gk20a_volt_priv *priv = (void *)volt;
+ int i, uv;
+
+ uv = regulator_get_voltage(priv->vdd);
+
+ for (i = 0; i < volt->vid_nr; i++)
+ if (volt->vid[i].uv >= uv)
+ return i;
+
+ return -EINVAL;
+}
+
+static int
+gk20a_volt_vid_set(struct nvkm_volt *volt, u8 vid)
+{
+ struct gk20a_volt_priv *priv = (void *)volt;
+
+ nv_debug(volt, "set voltage as %duv\n", volt->vid[vid].uv);
+ return regulator_set_voltage(priv->vdd, volt->vid[vid].uv, 1200000);
+}
+
+static int
+gk20a_volt_set_id(struct nvkm_volt *volt, u8 id, int condition)
+{
+ struct gk20a_volt_priv *priv = (void *)volt;
+ int prev_uv = regulator_get_voltage(priv->vdd);
+ int target_uv = volt->vid[id].uv;
+ int ret;
+
+ nv_debug(volt, "prev=%d, target=%d, condition=%d\n",
+ prev_uv, target_uv, condition);
+ if (!condition ||
+ (condition < 0 && target_uv < prev_uv) ||
+ (condition > 0 && target_uv > prev_uv)) {
+ ret = gk20a_volt_vid_set(volt, volt->vid[id].vid);
+ } else {
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int
+gk20a_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct gk20a_volt_priv *priv;
+ struct nvkm_volt *volt;
+ struct nouveau_platform_device *plat;
+ int i, ret, uv;
+
+ ret = nvkm_volt_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ volt = &priv->base;
+
+ plat = nv_device_to_platform(nv_device(parent));
+
+ uv = regulator_get_voltage(plat->gpu->vdd);
+ nv_info(priv, "The default voltage is %duV\n", uv);
+
+ priv->vdd = plat->gpu->vdd;
+ priv->base.vid_get = gk20a_volt_vid_get;
+ priv->base.vid_set = gk20a_volt_vid_set;
+ priv->base.set_id = gk20a_volt_set_id;
+
+ volt->vid_nr = ARRAY_SIZE(gk20a_cvb_coef);
+ nv_debug(priv, "%s - vid_nr = %d\n", __func__, volt->vid_nr);
+ for (i = 0; i < volt->vid_nr; i++) {
+ volt->vid[i].vid = i;
+ volt->vid[i].uv = gk20a_volt_calc_voltage(&gk20a_cvb_coef[i],
+ plat->gpu_speedo);
+ nv_debug(priv, "%2d: vid=%d, uv=%d\n", i, volt->vid[i].vid,
+ volt->vid[i].uv);
+ }
+
+ return 0;
+}
+
+struct nvkm_oclass
+gk20a_volt_oclass = {
+ .handle = NV_SUBDEV(VOLT, 0xea),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = gk20a_volt_ctor,
+ .dtor = _nvkm_volt_dtor,
+ .init = _nvkm_volt_init,
+ .fini = _nvkm_volt_fini,
+ },
+};
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c
new file mode 100644
index 000000000000..b778deb32d93
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/gpio.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/volt.h>
+#include <subdev/bios.h>
+#include <subdev/bios/gpio.h>
+#include <subdev/gpio.h>
+
+static const u8 tags[] = {
+ DCB_GPIO_VID0, DCB_GPIO_VID1, DCB_GPIO_VID2, DCB_GPIO_VID3,
+ DCB_GPIO_VID4, DCB_GPIO_VID5, DCB_GPIO_VID6, DCB_GPIO_VID7,
+};
+
+int
+nvkm_voltgpio_get(struct nvkm_volt *volt)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(volt);
+ u8 vid = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tags); i++) {
+ if (volt->vid_mask & (1 << i)) {
+ int ret = gpio->get(gpio, 0, tags[i], 0xff);
+ if (ret < 0)
+ return ret;
+ vid |= ret << i;
+ }
+ }
+
+ return vid;
+}
+
+int
+nvkm_voltgpio_set(struct nvkm_volt *volt, u8 vid)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(volt);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(tags); i++, vid >>= 1) {
+ if (volt->vid_mask & (1 << i)) {
+ int ret = gpio->set(gpio, 0, tags[i], 0xff, vid & 1);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+int
+nvkm_voltgpio_init(struct nvkm_volt *volt)
+{
+ struct nvkm_gpio *gpio = nvkm_gpio(volt);
+ struct dcb_gpio_func func;
+ int i;
+
+ /* check we have gpio function info for each vid bit. on some
+ * boards (ie. nvs295) the vid mask has more bits than there
+ * are valid gpio functions... from traces, nvidia appear to
+ * just touch the existing ones, so let's mask off the invalid
+ * bits and continue with life
+ */
+ for (i = 0; i < ARRAY_SIZE(tags); i++) {
+ if (volt->vid_mask & (1 << i)) {
+ int ret = gpio->find(gpio, 0, tags[i], 0xff, &func);
+ if (ret) {
+ if (ret != -ENOENT)
+ return ret;
+ nv_debug(volt, "VID bit %d has no GPIO\n", i);
+ volt->vid_mask &= ~(1 << i);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c
new file mode 100644
index 000000000000..0ac5a3f8c9a8
--- /dev/null
+++ b/drivers/gpu/drm/nouveau/nvkm/subdev/volt/nv40.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013 Red Hat Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Ben Skeggs
+ */
+#include <subdev/volt.h>
+
+struct nv40_volt_priv {
+ struct nvkm_volt base;
+};
+
+static int
+nv40_volt_ctor(struct nvkm_object *parent, struct nvkm_object *engine,
+ struct nvkm_oclass *oclass, void *data, u32 size,
+ struct nvkm_object **pobject)
+{
+ struct nv40_volt_priv *priv;
+ int ret;
+
+ ret = nvkm_volt_create(parent, engine, oclass, &priv);
+ *pobject = nv_object(priv);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+struct nvkm_oclass
+nv40_volt_oclass = {
+ .handle = NV_SUBDEV(VOLT, 0x40),
+ .ofuncs = &(struct nvkm_ofuncs) {
+ .ctor = nv40_volt_ctor,
+ .dtor = _nvkm_volt_dtor,
+ .init = _nvkm_volt_init,
+ .fini = _nvkm_volt_fini,
+ },
+};
diff --git a/drivers/gpu/drm/omapdrm/omap_fbdev.c b/drivers/gpu/drm/omapdrm/omap_fbdev.c
index 8436c6857cda..d292d24b3a6e 100644
--- a/drivers/gpu/drm/omapdrm/omap_fbdev.c
+++ b/drivers/gpu/drm/omapdrm/omap_fbdev.c
@@ -334,17 +334,23 @@ struct drm_fb_helper *omap_fbdev_init(struct drm_device *dev)
goto fail;
}
- drm_fb_helper_single_add_all_connectors(helper);
+ ret = drm_fb_helper_single_add_all_connectors(helper);
+ if (ret)
+ goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
- drm_fb_helper_initial_config(helper, 32);
+ ret = drm_fb_helper_initial_config(helper, 32);
+ if (ret)
+ goto fini;
priv->fbdev = helper;
return helper;
+fini:
+ drm_fb_helper_fini(helper);
fail:
kfree(fbdev);
return NULL;
diff --git a/drivers/gpu/drm/panel/Kconfig b/drivers/gpu/drm/panel/Kconfig
index 024e98ef8e4d..d84583776d50 100644
--- a/drivers/gpu/drm/panel/Kconfig
+++ b/drivers/gpu/drm/panel/Kconfig
@@ -10,6 +10,7 @@ menu "Display Panels"
config DRM_PANEL_SIMPLE
tristate "support for simple panels"
depends on OF
+ depends on BACKLIGHT_CLASS_DEVICE
help
DRM panel driver for dumb panels that need at most a regulator and
a GPIO to be powered up. Optionally a backlight can be attached so
@@ -31,6 +32,7 @@ config DRM_PANEL_SHARP_LQ101R1SX01
tristate "Sharp LQ101R1SX01 panel"
depends on OF
depends on DRM_MIPI_DSI
+ depends on BACKLIGHT_CLASS_DEVICE
help
Say Y here if you want to enable support for Sharp LQ101R1SX01
TFT-LCD modules. The panel has a 2560x1600 resolution and uses
diff --git a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
index 9d81759d82fc..3cce3ca19601 100644
--- a/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
+++ b/drivers/gpu/drm/panel/panel-sharp-lq101r1sx01.c
@@ -19,8 +19,6 @@
#include <video/mipi_display.h>
-#include <linux/host1x.h>
-
struct sharp_panel {
struct drm_panel base;
/* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */
@@ -41,6 +39,16 @@ static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel)
return container_of(panel, struct sharp_panel, base);
}
+static void sharp_wait_frames(struct sharp_panel *sharp, unsigned int frames)
+{
+ unsigned int refresh = drm_mode_vrefresh(sharp->mode);
+
+ if (WARN_ON(frames > refresh))
+ return;
+
+ msleep(1000 / (refresh / frames));
+}
+
static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value)
{
u8 payload[3] = { offset >> 8, offset & 0xff, value };
@@ -106,6 +114,8 @@ static int sharp_panel_unprepare(struct drm_panel *panel)
if (!sharp->prepared)
return 0;
+ sharp_wait_frames(sharp, 4);
+
err = mipi_dsi_dcs_set_display_off(sharp->link1);
if (err < 0)
dev_err(panel->dev, "failed to set display off: %d\n", err);
@@ -170,15 +180,13 @@ static int sharp_panel_prepare(struct drm_panel *panel)
if (err < 0)
return err;
- usleep_range(10000, 20000);
-
- err = mipi_dsi_dcs_soft_reset(sharp->link1);
- if (err < 0) {
- dev_err(panel->dev, "soft reset failed: %d\n", err);
- goto poweroff;
- }
-
- msleep(120);
+ /*
+ * According to the datasheet, the panel needs around 10 ms to fully
+ * power up. At least another 120 ms is required before exiting sleep
+ * mode to make sure the panel is ready. Throw in another 20 ms for
+ * good measure.
+ */
+ msleep(150);
err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1);
if (err < 0) {
@@ -238,6 +246,9 @@ static int sharp_panel_prepare(struct drm_panel *panel)
sharp->prepared = true;
+ /* wait for 6 frames before continuing */
+ sharp_wait_frames(sharp, 6);
+
return 0;
poweroff:
diff --git a/drivers/gpu/drm/panel/panel-simple.c b/drivers/gpu/drm/panel/panel-simple.c
index e95385bf8356..39806c335339 100644
--- a/drivers/gpu/drm/panel/panel-simple.c
+++ b/drivers/gpu/drm/panel/panel-simple.c
@@ -61,6 +61,8 @@ struct panel_desc {
unsigned int disable;
unsigned int unprepare;
} delay;
+
+ u32 bus_format;
};
struct panel_simple {
@@ -111,6 +113,9 @@ static int panel_simple_get_fixed_modes(struct panel_simple *panel)
connector->display_info.bpc = panel->desc->bpc;
connector->display_info.width_mm = panel->desc->size.width;
connector->display_info.height_mm = panel->desc->size.height;
+ if (panel->desc->bus_format)
+ drm_display_info_set_bus_formats(&connector->display_info,
+ &panel->desc->bus_format, 1);
return num;
}
@@ -443,6 +448,34 @@ static const struct panel_desc auo_b133htn01 = {
},
};
+static const struct drm_display_mode avic_tm070ddh03_mode = {
+ .clock = 51200,
+ .hdisplay = 1024,
+ .hsync_start = 1024 + 160,
+ .hsync_end = 1024 + 160 + 4,
+ .htotal = 1024 + 160 + 4 + 156,
+ .vdisplay = 600,
+ .vsync_start = 600 + 17,
+ .vsync_end = 600 + 17 + 1,
+ .vtotal = 600 + 17 + 1 + 17,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc avic_tm070ddh03 = {
+ .modes = &avic_tm070ddh03_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 154,
+ .height = 90,
+ },
+ .delay = {
+ .prepare = 20,
+ .enable = 200,
+ .disable = 200,
+ },
+};
+
static const struct drm_display_mode chunghwa_claa101wa01a_mode = {
.clock = 72070,
.hdisplay = 1366,
@@ -558,6 +591,30 @@ static const struct panel_desc foxlink_fl500wvr00_a0t = {
.width = 108,
.height = 65,
},
+ .bus_format = MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+static const struct drm_display_mode giantplus_gpg482739qs5_mode = {
+ .clock = 9000,
+ .hdisplay = 480,
+ .hsync_start = 480 + 5,
+ .hsync_end = 480 + 5 + 1,
+ .htotal = 480 + 5 + 1 + 40,
+ .vdisplay = 272,
+ .vsync_start = 272 + 8,
+ .vsync_end = 272 + 8 + 1,
+ .vtotal = 272 + 8 + 1 + 8,
+ .vrefresh = 60,
+};
+
+static const struct panel_desc giantplus_gpg482739qs5 = {
+ .modes = &giantplus_gpg482739qs5_mode,
+ .num_modes = 1,
+ .bpc = 8,
+ .size = {
+ .width = 95,
+ .height = 54,
+ },
};
static const struct drm_display_mode hannstar_hsd070pww1_mode = {
@@ -739,6 +796,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "auo,b133xtn01",
.data = &auo_b133xtn01,
}, {
+ .compatible = "avic,tm070ddh03",
+ .data = &avic_tm070ddh03,
+ }, {
.compatible = "chunghwa,claa101wa01a",
.data = &chunghwa_claa101wa01a
}, {
@@ -757,6 +817,9 @@ static const struct of_device_id platform_of_match[] = {
.compatible = "foxlink,fl500wvr00-a0t",
.data = &foxlink_fl500wvr00_a0t,
}, {
+ .compatible = "giantplus,gpg482739qs5",
+ .data = &giantplus_gpg482739qs5
+ }, {
.compatible = "hannstar,hsd070pww1",
.data = &hannstar_hsd070pww1,
}, {
diff --git a/drivers/gpu/drm/qxl/qxl_fb.c b/drivers/gpu/drm/qxl/qxl_fb.c
index 3d7c1d00a424..f778c0e8ae3c 100644
--- a/drivers/gpu/drm/qxl/qxl_fb.c
+++ b/drivers/gpu/drm/qxl/qxl_fb.c
@@ -686,14 +686,24 @@ int qxl_fbdev_init(struct qxl_device *qdev)
ret = drm_fb_helper_init(qdev->ddev, &qfbdev->helper,
qxl_num_crtc /* num_crtc - QXL supports just 1 */,
QXLFB_CONN_LIMIT);
- if (ret) {
- kfree(qfbdev);
- return ret;
- }
+ if (ret)
+ goto free;
+
+ ret = drm_fb_helper_single_add_all_connectors(&qfbdev->helper);
+ if (ret)
+ goto fini;
+
+ ret = drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel);
+ if (ret)
+ goto fini;
- drm_fb_helper_single_add_all_connectors(&qfbdev->helper);
- drm_fb_helper_initial_config(&qfbdev->helper, bpp_sel);
return 0;
+
+fini:
+ drm_fb_helper_fini(&qfbdev->helper);
+free:
+ kfree(qfbdev);
+ return ret;
}
void qxl_fbdev_fini(struct qxl_device *qdev)
diff --git a/drivers/gpu/drm/radeon/Makefile b/drivers/gpu/drm/radeon/Makefile
index 12bc21219a0e..4605633e253b 100644
--- a/drivers/gpu/drm/radeon/Makefile
+++ b/drivers/gpu/drm/radeon/Makefile
@@ -2,7 +2,7 @@
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
-ccflags-y := -Iinclude/drm
+ccflags-y := -Iinclude/drm -Idrivers/gpu/drm/amd/include
hostprogs-y := mkregtable
clean-files := rn50_reg_safe.h r100_reg_safe.h r200_reg_safe.h rv515_reg_safe.h r300_reg_safe.h r420_reg_safe.h rs600_reg_safe.h r600_reg_safe.h evergreen_reg_safe.h cayman_reg_safe.h
@@ -80,8 +80,10 @@ radeon-y += radeon_device.o radeon_asic.o radeon_kms.o \
r600_dpm.o rs780_dpm.o rv6xx_dpm.o rv770_dpm.o rv730_dpm.o rv740_dpm.o \
rv770_smc.o cypress_dpm.o btc_dpm.o sumo_dpm.o sumo_smc.o trinity_dpm.o \
trinity_smc.o ni_dpm.o si_smc.o si_dpm.o kv_smc.o kv_dpm.o ci_smc.o \
- ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o radeon_mn.o \
- radeon_sync.o
+ ci_dpm.o dce6_afmt.o radeon_vm.o radeon_ucode.o radeon_ib.o \
+ radeon_sync.o radeon_audio.o
+
+radeon-$(CONFIG_MMU_NOTIFIER) += radeon_mn.o
# add async DMA block
radeon-y += \
diff --git a/drivers/gpu/drm/radeon/atombios_dp.c b/drivers/gpu/drm/radeon/atombios_dp.c
index db42a670f995..8d74de82456e 100644
--- a/drivers/gpu/drm/radeon/atombios_dp.c
+++ b/drivers/gpu/drm/radeon/atombios_dp.c
@@ -178,6 +178,13 @@ radeon_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
switch (msg->request & ~DP_AUX_I2C_MOT) {
case DP_AUX_NATIVE_WRITE:
case DP_AUX_I2C_WRITE:
+ /* The atom implementation only supports writes with a max payload of
+ * 12 bytes since it uses 4 bits for the total count (header + payload)
+ * in the parameter space. The atom interface supports 16 byte
+ * payloads for reads. The hw itself supports up to 16 bytes of payload.
+ */
+ if (WARN_ON_ONCE(msg->size > 12))
+ return -E2BIG;
/* tx_size needs to be 4 even for bare address packets since the atom
* table needs the info in tx_buf[3].
*/
@@ -623,10 +630,8 @@ static int radeon_dp_link_train_init(struct radeon_dp_link_train_info *dp_info)
drm_dp_dpcd_writeb(dp_info->aux,
DP_DOWNSPREAD_CTRL, 0);
- if ((dp_info->connector->connector_type == DRM_MODE_CONNECTOR_eDP) &&
- (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)) {
+ if (dig->panel_mode == DP_PANEL_MODE_INTERNAL_DP2_MODE)
drm_dp_dpcd_writeb(dp_info->aux, DP_EDP_CONFIGURATION_SET, 1);
- }
/* set the lane count on the sink */
tmp = dp_info->dp_lane_count;
diff --git a/drivers/gpu/drm/radeon/atombios_encoders.c b/drivers/gpu/drm/radeon/atombios_encoders.c
index b8cd7975f797..7fe7b749e182 100644
--- a/drivers/gpu/drm/radeon/atombios_encoders.c
+++ b/drivers/gpu/drm/radeon/atombios_encoders.c
@@ -27,6 +27,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
+#include "radeon_audio.h"
#include "atom.h"
#include <linux/backlight.h>
@@ -664,6 +665,8 @@ atombios_digital_setup(struct drm_encoder *encoder, int action)
int
atombios_get_encoder_mode(struct drm_encoder *encoder)
{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct drm_connector *connector;
struct radeon_connector *radeon_connector;
@@ -728,6 +731,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
dig_connector = radeon_connector->con_priv;
if ((dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT) ||
(dig_connector->dp_sink_type == CONNECTOR_OBJECT_ID_eDP)) {
+ if (radeon_audio != 0 &&
+ drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
+ ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+ return ATOM_ENCODER_MODE_DP_AUDIO;
return ATOM_ENCODER_MODE_DP;
} else if (radeon_audio != 0) {
if (radeon_connector->audio == RADEON_AUDIO_ENABLE)
@@ -742,6 +749,10 @@ atombios_get_encoder_mode(struct drm_encoder *encoder)
}
break;
case DRM_MODE_CONNECTOR_eDP:
+ if (radeon_audio != 0 &&
+ drm_detect_monitor_audio(radeon_connector_edid(connector)) &&
+ ASIC_IS_DCE4(rdev) && !ASIC_IS_DCE5(rdev))
+ return ATOM_ENCODER_MODE_DP_AUDIO;
return ATOM_ENCODER_MODE_DP;
case DRM_MODE_CONNECTOR_DVIA:
case DRM_MODE_CONNECTOR_VGA:
@@ -1615,6 +1626,7 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
struct radeon_connector *radeon_connector = NULL;
struct radeon_connector_atom_dig *radeon_dig_connector = NULL;
bool travis_quirk = false;
+ int encoder_mode;
if (connector) {
radeon_connector = to_radeon_connector(connector);
@@ -1710,6 +1722,13 @@ radeon_atom_encoder_dpms_dig(struct drm_encoder *encoder, int mode)
}
break;
}
+
+ encoder_mode = atombios_get_encoder_mode(encoder);
+ if (connector && (radeon_audio != 0) &&
+ ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
+ (ENCODER_MODE_IS_DP(encoder_mode) &&
+ drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+ radeon_audio_dpms(encoder, mode);
}
static void
@@ -2123,6 +2142,8 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ int encoder_mode;
radeon_encoder->pixel_clock = adjusted_mode->clock;
@@ -2149,6 +2170,12 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
case ENCODER_OBJECT_ID_INTERNAL_UNIPHY3:
case ENCODER_OBJECT_ID_INTERNAL_KLDSCP_LVTMA:
/* handled in dpms */
+ encoder_mode = atombios_get_encoder_mode(encoder);
+ if (connector && (radeon_audio != 0) &&
+ ((encoder_mode == ATOM_ENCODER_MODE_HDMI) ||
+ (ENCODER_MODE_IS_DP(encoder_mode) &&
+ drm_detect_monitor_audio(radeon_connector_edid(connector)))))
+ radeon_audio_mode_set(encoder, adjusted_mode);
break;
case ENCODER_OBJECT_ID_INTERNAL_DDI:
case ENCODER_OBJECT_ID_INTERNAL_DVO1:
@@ -2170,13 +2197,6 @@ radeon_atom_encoder_mode_set(struct drm_encoder *encoder,
}
atombios_apply_encoder_quirks(encoder, adjusted_mode);
-
- if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
- if (rdev->asic->display.hdmi_enable)
- radeon_hdmi_enable(rdev, encoder, true);
- if (rdev->asic->display.hdmi_setmode)
- radeon_hdmi_setmode(rdev, encoder, adjusted_mode);
- }
}
static bool
@@ -2442,10 +2462,6 @@ static void radeon_atom_encoder_disable(struct drm_encoder *encoder)
disable_done:
if (radeon_encoder_is_digital(encoder)) {
- if (atombios_get_encoder_mode(encoder) == ATOM_ENCODER_MODE_HDMI) {
- if (rdev->asic->display.hdmi_enable)
- radeon_hdmi_enable(rdev, encoder, false);
- }
dig = radeon_encoder->enc_priv;
dig->dig_encoder = -1;
}
diff --git a/drivers/gpu/drm/radeon/btc_dpm.c b/drivers/gpu/drm/radeon/btc_dpm.c
index 0b2929de9f41..db08f17be76b 100644
--- a/drivers/gpu/drm/radeon/btc_dpm.c
+++ b/drivers/gpu/drm/radeon/btc_dpm.c
@@ -2277,6 +2277,7 @@ static void btc_update_requested_ps(struct radeon_device *rdev,
eg_pi->requested_rps.ps_priv = &eg_pi->requested_ps;
}
+#if 0
void btc_dpm_reset_asic(struct radeon_device *rdev)
{
rv770_restrict_performance_levels_before_switch(rdev);
@@ -2284,6 +2285,7 @@ void btc_dpm_reset_asic(struct radeon_device *rdev)
btc_set_boot_state_timing(rdev);
rv770_set_boot_state(rdev);
}
+#endif
int btc_dpm_pre_set_power_state(struct radeon_device *rdev)
{
diff --git a/drivers/gpu/drm/radeon/ci_dpm.c b/drivers/gpu/drm/radeon/ci_dpm.c
index f373a81ba3d5..bcd2f1fe803f 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.c
+++ b/drivers/gpu/drm/radeon/ci_dpm.c
@@ -187,6 +187,9 @@ static int ci_update_uvd_dpm(struct radeon_device *rdev, bool gate);
static PPSMC_Result ci_send_msg_to_smc_with_parameter(struct radeon_device *rdev,
PPSMC_Msg msg, u32 parameter);
+static void ci_thermal_start_smc_fan_control(struct radeon_device *rdev);
+static void ci_fan_ctrl_set_default_mode(struct radeon_device *rdev);
+
static struct ci_power_info *ci_get_pi(struct radeon_device *rdev)
{
struct ci_power_info *pi = rdev->pm.dpm.priv;
@@ -1043,22 +1046,24 @@ static int ci_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
return -EINVAL;
}
+ pi->fan_is_controlled_by_smc = true;
return 0;
}
-#if 0
static int ci_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
{
PPSMC_Result ret;
+ struct ci_power_info *pi = ci_get_pi(rdev);
ret = ci_send_msg_to_smc(rdev, PPSMC_StopFanControl);
- if (ret == PPSMC_Result_OK)
+ if (ret == PPSMC_Result_OK) {
+ pi->fan_is_controlled_by_smc = false;
return 0;
- else
+ } else
return -EINVAL;
}
-static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
u32 *speed)
{
u32 duty, duty100;
@@ -1083,21 +1088,22 @@ static int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
return 0;
}
-static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
u32 speed)
{
u32 tmp;
u32 duty, duty100;
u64 tmp64;
+ struct ci_power_info *pi = ci_get_pi(rdev);
if (rdev->pm.no_fan)
return -ENOENT;
- if (speed > 100)
+ if (pi->fan_is_controlled_by_smc)
return -EINVAL;
- if (rdev->pm.dpm.fan.ucode_fan_control)
- ci_fan_ctrl_stop_smc_fan_control(rdev);
+ if (speed > 100)
+ return -EINVAL;
duty100 = (RREG32_SMC(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
@@ -1112,11 +1118,38 @@ static int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
tmp |= FDO_STATIC_DUTY(duty);
WREG32_SMC(CG_FDO_CTRL0, tmp);
- ci_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
-
return 0;
}
+void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
+{
+ if (mode) {
+ /* stop auto-manage */
+ if (rdev->pm.dpm.fan.ucode_fan_control)
+ ci_fan_ctrl_stop_smc_fan_control(rdev);
+ ci_fan_ctrl_set_static_mode(rdev, mode);
+ } else {
+ /* restart auto-manage */
+ if (rdev->pm.dpm.fan.ucode_fan_control)
+ ci_thermal_start_smc_fan_control(rdev);
+ else
+ ci_fan_ctrl_set_default_mode(rdev);
+ }
+}
+
+u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev)
+{
+ struct ci_power_info *pi = ci_get_pi(rdev);
+ u32 tmp;
+
+ if (pi->fan_is_controlled_by_smc)
+ return 0;
+
+ tmp = RREG32_SMC(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+ return (tmp >> FDO_PWM_MODE_SHIFT);
+}
+
+#if 0
static int ci_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
u32 *speed)
{
@@ -1698,10 +1731,12 @@ static int ci_set_overdrive_target_tdp(struct radeon_device *rdev,
return 0;
}
+#if 0
static int ci_set_boot_state(struct radeon_device *rdev)
{
return ci_enable_sclk_mclk_dpm(rdev, false);
}
+#endif
static u32 ci_get_average_sclk_freq(struct radeon_device *rdev)
{
@@ -5343,10 +5378,12 @@ int ci_dpm_set_power_state(struct radeon_device *rdev)
return 0;
}
+#if 0
void ci_dpm_reset_asic(struct radeon_device *rdev)
{
ci_set_boot_state(rdev);
}
+#endif
void ci_dpm_display_configuration_changed(struct radeon_device *rdev)
{
diff --git a/drivers/gpu/drm/radeon/ci_dpm.h b/drivers/gpu/drm/radeon/ci_dpm.h
index 84e3d3bcf9f3..723220ffbea2 100644
--- a/drivers/gpu/drm/radeon/ci_dpm.h
+++ b/drivers/gpu/drm/radeon/ci_dpm.h
@@ -291,6 +291,7 @@ struct ci_power_info {
struct ci_ps requested_ps;
/* fan control */
bool fan_ctrl_is_in_default_mode;
+ bool fan_is_controlled_by_smc;
u32 t_min;
u32 fan_ctrl_default_mode;
};
diff --git a/drivers/gpu/drm/radeon/ci_smc.c b/drivers/gpu/drm/radeon/ci_smc.c
index e78bcad7a43e..35c6f648ba04 100644
--- a/drivers/gpu/drm/radeon/ci_smc.c
+++ b/drivers/gpu/drm/radeon/ci_smc.c
@@ -184,6 +184,7 @@ PPSMC_Result ci_send_msg_to_smc(struct radeon_device *rdev, PPSMC_Msg msg)
return (PPSMC_Result)tmp;
}
+#if 0
PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
{
u32 tmp;
@@ -201,6 +202,7 @@ PPSMC_Result ci_wait_for_smc_inactive(struct radeon_device *rdev)
return PPSMC_Result_OK;
}
+#endif
int ci_load_smc_ucode(struct radeon_device *rdev, u32 limit)
{
diff --git a/drivers/gpu/drm/radeon/cik.c b/drivers/gpu/drm/radeon/cik.c
index 64fdae558d36..0c993da9c8fb 100644
--- a/drivers/gpu/drm/radeon/cik.c
+++ b/drivers/gpu/drm/radeon/cik.c
@@ -27,6 +27,7 @@
#include "drmP.h"
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "cikd.h"
#include "atom.h"
#include "cik_blit_shaders.h"
@@ -3612,6 +3613,8 @@ static void cik_gpu_init(struct radeon_device *rdev)
}
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ WREG32(SRBM_INT_CNTL, 0x1);
+ WREG32(SRBM_INT_ACK, 0x1);
WREG32(BIF_FB_EN, FB_READ_EN | FB_WRITE_EN);
@@ -3904,7 +3907,21 @@ void cik_fence_gfx_ring_emit(struct radeon_device *rdev,
struct radeon_ring *ring = &rdev->ring[fence->ring];
u64 addr = rdev->fence_drv[fence->ring].gpu_addr;
- /* EVENT_WRITE_EOP - flush caches, send int */
+ /* Workaround for cache flush problems. First send a dummy EOP
+ * event down the pipe with seq one below.
+ */
+ radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
+ radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
+ EOP_TC_ACTION_EN |
+ EVENT_TYPE(CACHE_FLUSH_AND_INV_TS_EVENT) |
+ EVENT_INDEX(5)));
+ radeon_ring_write(ring, addr & 0xfffffffc);
+ radeon_ring_write(ring, (upper_32_bits(addr) & 0xffff) |
+ DATA_SEL(1) | INT_SEL(0));
+ radeon_ring_write(ring, fence->seq - 1);
+ radeon_ring_write(ring, 0);
+
+ /* Then send the real EOP event down the pipe. */
radeon_ring_write(ring, PACKET3(PACKET3_EVENT_WRITE_EOP, 4));
radeon_ring_write(ring, (EOP_TCL1_ACTION_EN |
EOP_TC_ACTION_EN |
@@ -5707,6 +5724,28 @@ void cik_pcie_gart_tlb_flush(struct radeon_device *rdev)
WREG32(VM_INVALIDATE_REQUEST, 0x1);
}
+static void cik_pcie_init_compute_vmid(struct radeon_device *rdev)
+{
+ int i;
+ uint32_t sh_mem_bases, sh_mem_config;
+
+ sh_mem_bases = 0x6000 | 0x6000 << 16;
+ sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
+ sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
+
+ mutex_lock(&rdev->srbm_mutex);
+ for (i = 8; i < 16; i++) {
+ cik_srbm_select(rdev, 0, 0, 0, i);
+ /* CP and shaders */
+ WREG32(SH_MEM_CONFIG, sh_mem_config);
+ WREG32(SH_MEM_APE1_BASE, 1);
+ WREG32(SH_MEM_APE1_LIMIT, 0);
+ WREG32(SH_MEM_BASES, sh_mem_bases);
+ }
+ cik_srbm_select(rdev, 0, 0, 0, 0);
+ mutex_unlock(&rdev->srbm_mutex);
+}
+
/**
* cik_pcie_gart_enable - gart enable
*
@@ -5820,6 +5859,8 @@ static int cik_pcie_gart_enable(struct radeon_device *rdev)
cik_srbm_select(rdev, 0, 0, 0, 0);
mutex_unlock(&rdev->srbm_mutex);
+ cik_pcie_init_compute_vmid(rdev);
+
cik_pcie_gart_tlb_flush(rdev);
DRM_INFO("PCIE GART of %uM enabled (table at 0x%016llX).\n",
(unsigned)(rdev->mc.gtt_size >> 20),
@@ -7191,6 +7232,8 @@ static void cik_disable_interrupt_state(struct radeon_device *rdev)
WREG32(CP_ME2_PIPE3_INT_CNTL, 0);
/* grbm */
WREG32(GRBM_INT_CNTL, 0);
+ /* SRBM */
+ WREG32(SRBM_INT_CNTL, 0);
/* vline/vblank, etc. */
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(LB_INTERRUPT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -7334,7 +7377,6 @@ int cik_irq_set(struct radeon_device *rdev)
u32 hpd1, hpd2, hpd3, hpd4, hpd5, hpd6;
u32 grbm_int_cntl = 0;
u32 dma_cntl, dma_cntl1;
- u32 thermal_int;
if (!rdev->irq.installed) {
WARN(1, "Can't enable IRQ/MSI because no handler is installed\n");
@@ -7364,13 +7406,6 @@ int cik_irq_set(struct radeon_device *rdev)
cp_m1p0 = RREG32(CP_ME1_PIPE0_INT_CNTL) & ~TIME_STAMP_INT_ENABLE;
- if (rdev->flags & RADEON_IS_IGP)
- thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL) &
- ~(THERM_INTH_MASK | THERM_INTL_MASK);
- else
- thermal_int = RREG32_SMC(CG_THERMAL_INT) &
- ~(THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW);
-
/* enable CP interrupts on all rings */
if (atomic_read(&rdev->irq.ring_int[RADEON_RING_TYPE_GFX_INDEX])) {
DRM_DEBUG("cik_irq_set: sw int gfx\n");
@@ -7474,14 +7509,6 @@ int cik_irq_set(struct radeon_device *rdev)
hpd6 |= DC_HPDx_INT_EN;
}
- if (rdev->irq.dpm_thermal) {
- DRM_DEBUG("dpm thermal\n");
- if (rdev->flags & RADEON_IS_IGP)
- thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK;
- else
- thermal_int |= THERM_INT_MASK_HIGH | THERM_INT_MASK_LOW;
- }
-
WREG32(CP_INT_CNTL_RING0, cp_int_cntl);
WREG32(SDMA0_CNTL + SDMA0_REGISTER_OFFSET, dma_cntl);
@@ -7528,11 +7555,6 @@ int cik_irq_set(struct radeon_device *rdev)
WREG32(DC_HPD5_INT_CONTROL, hpd5);
WREG32(DC_HPD6_INT_CONTROL, hpd6);
- if (rdev->flags & RADEON_IS_IGP)
- WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int);
- else
- WREG32_SMC(CG_THERMAL_INT, thermal_int);
-
return 0;
}
@@ -8028,6 +8050,10 @@ restart_ih:
break;
}
break;
+ case 96:
+ DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+ WREG32(SRBM_INT_ACK, 0x1);
+ break;
case 124: /* UVD */
DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -8493,7 +8519,7 @@ static int cik_startup(struct radeon_device *rdev)
return r;
}
- r = dce6_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r)
return r;
@@ -8551,7 +8577,7 @@ int cik_suspend(struct radeon_device *rdev)
{
radeon_kfd_suspend(rdev);
radeon_pm_suspend(rdev);
- dce6_audio_fini(rdev);
+ radeon_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
cik_cp_enable(rdev, false);
cik_sdma_enable(rdev, false);
diff --git a/drivers/gpu/drm/radeon/cik_reg.h b/drivers/gpu/drm/radeon/cik_reg.h
index 79c45e8a536b..f667347d8157 100644
--- a/drivers/gpu/drm/radeon/cik_reg.h
+++ b/drivers/gpu/drm/radeon/cik_reg.h
@@ -147,140 +147,41 @@
#define CIK_LB_DESKTOP_HEIGHT 0x6b0c
+#define KFD_CIK_SDMA_QUEUE_OFFSET 0x200
+
#define CP_HQD_IQ_RPTR 0xC970u
#define AQL_ENABLE (1U << 0)
-
-#define IDLE (1 << 2)
-
-struct cik_mqd {
- uint32_t header;
- uint32_t compute_dispatch_initiator;
- uint32_t compute_dim_x;
- uint32_t compute_dim_y;
- uint32_t compute_dim_z;
- uint32_t compute_start_x;
- uint32_t compute_start_y;
- uint32_t compute_start_z;
- uint32_t compute_num_thread_x;
- uint32_t compute_num_thread_y;
- uint32_t compute_num_thread_z;
- uint32_t compute_pipelinestat_enable;
- uint32_t compute_perfcount_enable;
- uint32_t compute_pgm_lo;
- uint32_t compute_pgm_hi;
- uint32_t compute_tba_lo;
- uint32_t compute_tba_hi;
- uint32_t compute_tma_lo;
- uint32_t compute_tma_hi;
- uint32_t compute_pgm_rsrc1;
- uint32_t compute_pgm_rsrc2;
- uint32_t compute_vmid;
- uint32_t compute_resource_limits;
- uint32_t compute_static_thread_mgmt_se0;
- uint32_t compute_static_thread_mgmt_se1;
- uint32_t compute_tmpring_size;
- uint32_t compute_static_thread_mgmt_se2;
- uint32_t compute_static_thread_mgmt_se3;
- uint32_t compute_restart_x;
- uint32_t compute_restart_y;
- uint32_t compute_restart_z;
- uint32_t compute_thread_trace_enable;
- uint32_t compute_misc_reserved;
- uint32_t compute_user_data_0;
- uint32_t compute_user_data_1;
- uint32_t compute_user_data_2;
- uint32_t compute_user_data_3;
- uint32_t compute_user_data_4;
- uint32_t compute_user_data_5;
- uint32_t compute_user_data_6;
- uint32_t compute_user_data_7;
- uint32_t compute_user_data_8;
- uint32_t compute_user_data_9;
- uint32_t compute_user_data_10;
- uint32_t compute_user_data_11;
- uint32_t compute_user_data_12;
- uint32_t compute_user_data_13;
- uint32_t compute_user_data_14;
- uint32_t compute_user_data_15;
- uint32_t cp_compute_csinvoc_count_lo;
- uint32_t cp_compute_csinvoc_count_hi;
- uint32_t cp_mqd_base_addr_lo;
- uint32_t cp_mqd_base_addr_hi;
- uint32_t cp_hqd_active;
- uint32_t cp_hqd_vmid;
- uint32_t cp_hqd_persistent_state;
- uint32_t cp_hqd_pipe_priority;
- uint32_t cp_hqd_queue_priority;
- uint32_t cp_hqd_quantum;
- uint32_t cp_hqd_pq_base_lo;
- uint32_t cp_hqd_pq_base_hi;
- uint32_t cp_hqd_pq_rptr;
- uint32_t cp_hqd_pq_rptr_report_addr_lo;
- uint32_t cp_hqd_pq_rptr_report_addr_hi;
- uint32_t cp_hqd_pq_wptr_poll_addr_lo;
- uint32_t cp_hqd_pq_wptr_poll_addr_hi;
- uint32_t cp_hqd_pq_doorbell_control;
- uint32_t cp_hqd_pq_wptr;
- uint32_t cp_hqd_pq_control;
- uint32_t cp_hqd_ib_base_addr_lo;
- uint32_t cp_hqd_ib_base_addr_hi;
- uint32_t cp_hqd_ib_rptr;
- uint32_t cp_hqd_ib_control;
- uint32_t cp_hqd_iq_timer;
- uint32_t cp_hqd_iq_rptr;
- uint32_t cp_hqd_dequeue_request;
- uint32_t cp_hqd_dma_offload;
- uint32_t cp_hqd_sema_cmd;
- uint32_t cp_hqd_msg_type;
- uint32_t cp_hqd_atomic0_preop_lo;
- uint32_t cp_hqd_atomic0_preop_hi;
- uint32_t cp_hqd_atomic1_preop_lo;
- uint32_t cp_hqd_atomic1_preop_hi;
- uint32_t cp_hqd_hq_status0;
- uint32_t cp_hqd_hq_control0;
- uint32_t cp_mqd_control;
- uint32_t cp_mqd_query_time_lo;
- uint32_t cp_mqd_query_time_hi;
- uint32_t cp_mqd_connect_start_time_lo;
- uint32_t cp_mqd_connect_start_time_hi;
- uint32_t cp_mqd_connect_end_time_lo;
- uint32_t cp_mqd_connect_end_time_hi;
- uint32_t cp_mqd_connect_end_wf_count;
- uint32_t cp_mqd_connect_end_pq_rptr;
- uint32_t cp_mqd_connect_end_pq_wptr;
- uint32_t cp_mqd_connect_end_ib_rptr;
- uint32_t reserved_96;
- uint32_t reserved_97;
- uint32_t reserved_98;
- uint32_t reserved_99;
- uint32_t iqtimer_pkt_header;
- uint32_t iqtimer_pkt_dw0;
- uint32_t iqtimer_pkt_dw1;
- uint32_t iqtimer_pkt_dw2;
- uint32_t iqtimer_pkt_dw3;
- uint32_t iqtimer_pkt_dw4;
- uint32_t iqtimer_pkt_dw5;
- uint32_t iqtimer_pkt_dw6;
- uint32_t reserved_108;
- uint32_t reserved_109;
- uint32_t reserved_110;
- uint32_t reserved_111;
- uint32_t queue_doorbell_id0;
- uint32_t queue_doorbell_id1;
- uint32_t queue_doorbell_id2;
- uint32_t queue_doorbell_id3;
- uint32_t queue_doorbell_id4;
- uint32_t queue_doorbell_id5;
- uint32_t queue_doorbell_id6;
- uint32_t queue_doorbell_id7;
- uint32_t queue_doorbell_id8;
- uint32_t queue_doorbell_id9;
- uint32_t queue_doorbell_id10;
- uint32_t queue_doorbell_id11;
- uint32_t queue_doorbell_id12;
- uint32_t queue_doorbell_id13;
- uint32_t queue_doorbell_id14;
- uint32_t queue_doorbell_id15;
-};
+#define SDMA0_RLC0_RB_CNTL 0xD400u
+#define SDMA_RB_VMID(x) (x << 24)
+#define SDMA0_RLC0_RB_BASE 0xD404u
+#define SDMA0_RLC0_RB_BASE_HI 0xD408u
+#define SDMA0_RLC0_RB_RPTR 0xD40Cu
+#define SDMA0_RLC0_RB_WPTR 0xD410u
+#define SDMA0_RLC0_RB_WPTR_POLL_CNTL 0xD414u
+#define SDMA0_RLC0_RB_WPTR_POLL_ADDR_HI 0xD418u
+#define SDMA0_RLC0_RB_WPTR_POLL_ADDR_LO 0xD41Cu
+#define SDMA0_RLC0_RB_RPTR_ADDR_HI 0xD420u
+#define SDMA0_RLC0_RB_RPTR_ADDR_LO 0xD424u
+#define SDMA0_RLC0_IB_CNTL 0xD428u
+#define SDMA0_RLC0_IB_RPTR 0xD42Cu
+#define SDMA0_RLC0_IB_OFFSET 0xD430u
+#define SDMA0_RLC0_IB_BASE_LO 0xD434u
+#define SDMA0_RLC0_IB_BASE_HI 0xD438u
+#define SDMA0_RLC0_IB_SIZE 0xD43Cu
+#define SDMA0_RLC0_SKIP_CNTL 0xD440u
+#define SDMA0_RLC0_CONTEXT_STATUS 0xD444u
+#define SDMA_RLC_IDLE (1 << 2)
+#define SDMA0_RLC0_DOORBELL 0xD448u
+#define SDMA_OFFSET(x) (x << 0)
+#define SDMA_DB_ENABLE (1 << 28)
+#define SDMA0_RLC0_VIRTUAL_ADDR 0xD49Cu
+#define SDMA_ATC (1 << 0)
+#define SDMA_VA_PTR32 (1 << 4)
+#define SDMA_VA_SHARED_BASE(x) (x << 8)
+#define SDMA0_RLC0_APE1_CNTL 0xD4A0u
+#define SDMA0_RLC0_DOORBELL_LOG 0xD4A4u
+#define SDMA0_RLC0_WATERMARK 0xD4A8u
+#define SDMA0_CNTL 0xD010
+#define SDMA1_CNTL 0xD810
#endif
diff --git a/drivers/gpu/drm/radeon/cik_sdma.c b/drivers/gpu/drm/radeon/cik_sdma.c
index 42cd0cffe210..f86eb54e7763 100644
--- a/drivers/gpu/drm/radeon/cik_sdma.c
+++ b/drivers/gpu/drm/radeon/cik_sdma.c
@@ -283,6 +283,33 @@ static void cik_sdma_rlc_stop(struct radeon_device *rdev)
}
/**
+ * cik_sdma_ctx_switch_enable - enable/disable sdma engine preemption
+ *
+ * @rdev: radeon_device pointer
+ * @enable: enable/disable preemption.
+ *
+ * Halt or unhalt the async dma engines (CIK).
+ */
+static void cik_sdma_ctx_switch_enable(struct radeon_device *rdev, bool enable)
+{
+ uint32_t reg_offset, value;
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ if (i == 0)
+ reg_offset = SDMA0_REGISTER_OFFSET;
+ else
+ reg_offset = SDMA1_REGISTER_OFFSET;
+ value = RREG32(SDMA0_CNTL + reg_offset);
+ if (enable)
+ value |= AUTO_CTXSW_ENABLE;
+ else
+ value &= ~AUTO_CTXSW_ENABLE;
+ WREG32(SDMA0_CNTL + reg_offset, value);
+ }
+}
+
+/**
* cik_sdma_enable - stop the async dma engines
*
* @rdev: radeon_device pointer
@@ -312,6 +339,8 @@ void cik_sdma_enable(struct radeon_device *rdev, bool enable)
me_cntl |= SDMA_HALT;
WREG32(SDMA0_ME_CNTL + reg_offset, me_cntl);
}
+
+ cik_sdma_ctx_switch_enable(rdev, enable);
}
/**
diff --git a/drivers/gpu/drm/radeon/cikd.h b/drivers/gpu/drm/radeon/cikd.h
index 03003f8a6de6..c648e1996dab 100644
--- a/drivers/gpu/drm/radeon/cikd.h
+++ b/drivers/gpu/drm/radeon/cikd.h
@@ -482,6 +482,10 @@
#define SOFT_RESET_ORB (1 << 23)
#define SOFT_RESET_VCE (1 << 24)
+#define SRBM_READ_ERROR 0xE98
+#define SRBM_INT_CNTL 0xEA0
+#define SRBM_INT_ACK 0xEA8
+
#define VM_L2_CNTL 0x1400
#define ENABLE_L2_CACHE (1 << 0)
#define ENABLE_L2_FRAGMENT_PROCESSING (1 << 1)
diff --git a/drivers/gpu/drm/radeon/cypress_dpm.c b/drivers/gpu/drm/radeon/cypress_dpm.c
index 9aad0327e4d1..ca058589ddef 100644
--- a/drivers/gpu/drm/radeon/cypress_dpm.c
+++ b/drivers/gpu/drm/radeon/cypress_dpm.c
@@ -2005,11 +2005,13 @@ int cypress_dpm_set_power_state(struct radeon_device *rdev)
return 0;
}
+#if 0
void cypress_dpm_reset_asic(struct radeon_device *rdev)
{
rv770_restrict_performance_levels_before_switch(rdev);
rv770_set_boot_state(rdev);
}
+#endif
void cypress_dpm_display_configuration_changed(struct radeon_device *rdev)
{
diff --git a/drivers/gpu/drm/radeon/dce3_1_afmt.c b/drivers/gpu/drm/radeon/dce3_1_afmt.c
index bafdf92a5732..f04205170b8a 100644
--- a/drivers/gpu/drm/radeon/dce3_1_afmt.c
+++ b/drivers/gpu/drm/radeon/dce3_1_afmt.c
@@ -24,37 +24,17 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "r600d.h"
-static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
u32 tmp;
- u8 *sadb = NULL;
- int sad_count;
-
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
- sad_count = drm_edid_to_speaker_allocation(radeon_connector->edid, &sadb);
- if (sad_count < 0) {
- DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
- sad_count = 0;
- }
/* program the speaker allocation */
- tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+ tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
@@ -62,19 +42,32 @@ static void dce3_2_afmt_write_speaker_allocation(struct drm_encoder *encoder)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
- WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
-
- kfree(sadb);
+ WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
}
-static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
+void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
- struct cea_sad *sads;
- int i, sad_count;
+ u32 tmp;
+
+ /* program the speaker allocation */
+ tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+ tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
+ /* set DP mode */
+ tmp |= DP_CONNECTION;
+ if (sad_count)
+ tmp |= SPEAKER_ALLOCATION(sadb[0]);
+ else
+ tmp |= SPEAKER_ALLOCATION(5); /* stereo */
+ WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
+}
+void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count)
+{
+ int i;
+ struct radeon_device *rdev = encoder->dev->dev_private;
static const u16 eld_reg_to_type[][2] = {
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@@ -90,25 +83,6 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
- sad_count = drm_edid_to_sad(radeon_connector->edid, &sads);
- if (sad_count <= 0) {
- DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
- return;
- }
- BUG_ON(!sads);
-
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
u32 value = 0;
u8 stereo_freqs = 0;
@@ -135,110 +109,124 @@ static void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder)
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
- WREG32(eld_reg_to_type[i][0], value);
+ WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
}
-
- kfree(sads);
}
-/*
- * update the info frames with the data from the current display mode
- */
-void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+void dce3_2_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
- struct hdmi_avi_infoframe frame;
- uint32_t offset;
- ssize_t err;
-
- if (!dig || !dig->afmt)
- return;
-
- /* Silent, r600_hdmi_enable will raise WARN for us */
- if (!dig->afmt->enabled)
+ struct radeon_encoder *radeon_encoder;
+ struct radeon_encoder_atom_dig *dig;
+ unsigned int max_ratio = clock / 24000;
+ u32 dto_phase;
+ u32 wallclock_ratio;
+ u32 dto_cntl;
+
+ if (!crtc)
return;
- offset = dig->afmt->offset;
-
- /* disable audio prior to setting up hw */
- dig->afmt->pin = r600_audio_get_pin(rdev);
- r600_audio_enable(rdev, dig->afmt->pin, 0);
- r600_audio_set_dto(encoder, mode->clock);
+ radeon_encoder = to_radeon_encoder(crtc->encoder);
+ dig = radeon_encoder->enc_priv;
- WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
- HDMI0_NULL_SEND); /* send null packets when required */
-
- WREG32(HDMI0_AUDIO_CRC_CONTROL + offset, 0x1000);
+ if (!dig)
+ return;
- if (ASIC_IS_DCE32(rdev)) {
- WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
- HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
- HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
- WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
- AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
- AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
+ if (max_ratio >= 8) {
+ dto_phase = 192 * 1000;
+ wallclock_ratio = 3;
+ } else if (max_ratio >= 4) {
+ dto_phase = 96 * 1000;
+ wallclock_ratio = 2;
+ } else if (max_ratio >= 2) {
+ dto_phase = 48 * 1000;
+ wallclock_ratio = 1;
} else {
- WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
- HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
- HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
- HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
- HDMI0_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
+ dto_phase = 24 * 1000;
+ wallclock_ratio = 0;
}
- if (ASIC_IS_DCE32(rdev)) {
- dce3_2_afmt_write_speaker_allocation(encoder);
- dce3_2_afmt_write_sad_regs(encoder);
+ /* Express [24MHz / target pixel clock] as an exact rational
+ * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
+ * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+ */
+ if (dig->dig_encoder == 0) {
+ dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+ WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+ WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
+ WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
+ } else {
+ dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+ WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
+ WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
+ WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
+ WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
}
+}
+
+void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
WREG32(HDMI0_ACR_PACKET_CONTROL + offset,
- HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
- HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
-
- WREG32(HDMI0_VBI_PACKET_CONTROL + offset,
- HDMI0_NULL_SEND | /* send null packets when required */
- HDMI0_GC_SEND | /* send general control packets */
- HDMI0_GC_CONT); /* send general control packets every frame */
-
- /* TODO: HDMI0_AUDIO_INFO_UPDATE */
- WREG32(HDMI0_INFOFRAME_CONTROL0 + offset,
- HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
- HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
- HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
- HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
-
- WREG32(HDMI0_INFOFRAME_CONTROL1 + offset,
- HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
- HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
- WREG32(HDMI0_GC + offset, 0); /* unset HDMI0_GC_AVMUTE */
-
- err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
- if (err < 0) {
- DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
- return;
- }
+ HDMI0_ACR_SOURCE | /* select SW CTS value */
+ HDMI0_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
+
+ WREG32_P(HDMI0_ACR_32_0 + offset,
+ HDMI0_ACR_CTS_32(acr->cts_32khz),
+ ~HDMI0_ACR_CTS_32_MASK);
+ WREG32_P(HDMI0_ACR_32_1 + offset,
+ HDMI0_ACR_N_32(acr->n_32khz),
+ ~HDMI0_ACR_N_32_MASK);
+
+ WREG32_P(HDMI0_ACR_44_0 + offset,
+ HDMI0_ACR_CTS_44(acr->cts_44_1khz),
+ ~HDMI0_ACR_CTS_44_MASK);
+ WREG32_P(HDMI0_ACR_44_1 + offset,
+ HDMI0_ACR_N_44(acr->n_44_1khz),
+ ~HDMI0_ACR_N_44_MASK);
+
+ WREG32_P(HDMI0_ACR_48_0 + offset,
+ HDMI0_ACR_CTS_48(acr->cts_48khz),
+ ~HDMI0_ACR_CTS_48_MASK);
+ WREG32_P(HDMI0_ACR_48_1 + offset,
+ HDMI0_ACR_N_48(acr->n_48khz),
+ ~HDMI0_ACR_N_48_MASK);
+}
- err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
- if (err < 0) {
- DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
- return;
- }
+void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
- r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
- r600_hdmi_update_ACR(encoder, mode->clock);
+ WREG32(HDMI0_AUDIO_PACKET_CONTROL + offset,
+ HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
+ HDMI0_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
- /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
- WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
- WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
- WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
- WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
+ AFMT_AUDIO_SAMPLE_SEND | /* send audio packets */
+ AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
- r600_hdmi_audio_workaround(encoder);
+ WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
+ HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+ HDMI0_AUDIO_INFO_CONT); /* send audio info frames every frame/field */
- /* enable audio after to setting up hw */
- r600_audio_enable(rdev, dig->afmt->pin, 0xf);
+ WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
+ HDMI0_AUDIO_INFO_LINE(2)); /* anything other than 0 */
+}
+
+void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+
+ if (mute)
+ WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE);
+ else
+ WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE);
}
diff --git a/drivers/gpu/drm/radeon/dce6_afmt.c b/drivers/gpu/drm/radeon/dce6_afmt.c
index f312edf4d50e..192c80389151 100644
--- a/drivers/gpu/drm/radeon/dce6_afmt.c
+++ b/drivers/gpu/drm/radeon/dce6_afmt.c
@@ -23,9 +23,10 @@
#include <linux/hdmi.h>
#include <drm/drmP.h>
#include "radeon.h"
+#include "radeon_audio.h"
#include "sid.h"
-static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
+u32 dce6_endpoint_rreg(struct radeon_device *rdev,
u32 block_offset, u32 reg)
{
unsigned long flags;
@@ -39,7 +40,7 @@ static u32 dce6_endpoint_rreg(struct radeon_device *rdev,
return r;
}
-static void dce6_endpoint_wreg(struct radeon_device *rdev,
+void dce6_endpoint_wreg(struct radeon_device *rdev,
u32 block_offset, u32 reg, u32 v)
{
unsigned long flags;
@@ -54,10 +55,6 @@ static void dce6_endpoint_wreg(struct radeon_device *rdev,
spin_unlock_irqrestore(&rdev->end_idx_lock, flags);
}
-#define RREG32_ENDPOINT(block, reg) dce6_endpoint_rreg(rdev, (block), (reg))
-#define WREG32_ENDPOINT(block, reg, v) dce6_endpoint_wreg(rdev, (block), (reg), (v))
-
-
static void dce6_afmt_get_connected_pins(struct radeon_device *rdev)
{
int i;
@@ -105,13 +102,11 @@ void dce6_afmt_select_pin(struct drm_encoder *encoder)
}
void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
- struct drm_display_mode *mode)
+ struct drm_connector *connector, struct drm_display_mode *mode)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
u32 tmp = 0, offset;
if (!dig || !dig->afmt || !dig->afmt->pin)
@@ -119,18 +114,6 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
offset = dig->afmt->pin->offset;
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
if (connector->latency_present[1])
tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
@@ -147,40 +130,19 @@ void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_RESPONSE_LIPSYNC, tmp);
}
-void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
u32 offset, tmp;
- u8 *sadb = NULL;
- int sad_count;
if (!dig || !dig->afmt || !dig->afmt->pin)
return;
offset = dig->afmt->pin->offset;
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
- sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb);
- if (sad_count < 0) {
- DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
- sad_count = 0;
- }
-
/* program the speaker allocation */
tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
@@ -191,21 +153,41 @@ void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder)
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
-
- kfree(sadb);
}
-void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
+void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- u32 offset;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
- struct cea_sad *sads;
- int i, sad_count;
+ u32 offset, tmp;
+
+ if (!dig || !dig->afmt || !dig->afmt->pin)
+ return;
+ offset = dig->afmt->pin->offset;
+
+ /* program the speaker allocation */
+ tmp = RREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER);
+ tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
+ /* set DP mode */
+ tmp |= DP_CONNECTION;
+ if (sad_count)
+ tmp |= SPEAKER_ALLOCATION(sadb[0]);
+ else
+ tmp |= SPEAKER_ALLOCATION(5); /* stereo */
+ WREG32_ENDPOINT(offset, AZ_F0_CODEC_PIN_CONTROL_CHANNEL_SPEAKER, tmp);
+}
+
+void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count)
+{
+ u32 offset;
+ int i;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ struct radeon_device *rdev = encoder->dev->dev_private;
static const u16 eld_reg_to_type[][2] = {
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
{ AZ_F0_CODEC_PIN_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@@ -226,25 +208,6 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
offset = dig->afmt->pin->offset;
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
- sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
- if (sad_count <= 0) {
- DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
- return;
- }
- BUG_ON(!sads);
-
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
u32 value = 0;
u8 stereo_freqs = 0;
@@ -273,13 +236,6 @@ void dce6_afmt_write_sad_regs(struct drm_encoder *encoder)
WREG32_ENDPOINT(offset, eld_reg_to_type[i][0], value);
}
-
- kfree(sads);
-}
-
-static int dce6_audio_chipset_supported(struct radeon_device *rdev)
-{
- return !ASIC_IS_NODCE(rdev);
}
void dce6_audio_enable(struct radeon_device *rdev,
@@ -293,64 +249,76 @@ void dce6_audio_enable(struct radeon_device *rdev,
enable_mask ? AUDIO_ENABLED : 0);
}
-static const u32 pin_offsets[7] =
-{
- (0x5e00 - 0x5e00),
- (0x5e18 - 0x5e00),
- (0x5e30 - 0x5e00),
- (0x5e48 - 0x5e00),
- (0x5e60 - 0x5e00),
- (0x5e78 - 0x5e00),
- (0x5e90 - 0x5e00),
-};
-
-int dce6_audio_init(struct radeon_device *rdev)
+void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock)
{
- int i;
+ /* Two dtos; generally use dto0 for HDMI */
+ u32 value = 0;
- if (!radeon_audio || !dce6_audio_chipset_supported(rdev))
- return 0;
+ if (crtc)
+ value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
- rdev->audio.enabled = true;
+ WREG32(DCCG_AUDIO_DTO_SOURCE, value);
- if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */
- rdev->audio.num_pins = 7;
- else if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */
- rdev->audio.num_pins = 3;
- else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */
- rdev->audio.num_pins = 7;
- else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */
- rdev->audio.num_pins = 6;
- else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */
- rdev->audio.num_pins = 2;
- else /* SI: 6 streams, 6 endpoints */
- rdev->audio.num_pins = 6;
+ /* Express [24MHz / target pixel clock] as an exact rational
+ * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
+ * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+ */
+ WREG32(DCCG_AUDIO_DTO0_PHASE, 24000);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
+}
- for (i = 0; i < rdev->audio.num_pins; i++) {
- rdev->audio.pin[i].channels = -1;
- rdev->audio.pin[i].rate = -1;
- rdev->audio.pin[i].bits_per_sample = -1;
- rdev->audio.pin[i].status_bits = 0;
- rdev->audio.pin[i].category_code = 0;
- rdev->audio.pin[i].connected = false;
- rdev->audio.pin[i].offset = pin_offsets[i];
- rdev->audio.pin[i].id = i;
- /* disable audio. it will be set up later */
- dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
- }
+void dce6_dp_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock)
+{
+ /* Two dtos; generally use dto1 for DP */
+ u32 value = 0;
+ value |= DCCG_AUDIO_DTO_SEL;
+
+ if (crtc)
+ value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
+
+ WREG32(DCCG_AUDIO_DTO_SOURCE, value);
- return 0;
+ /* Express [24MHz / target pixel clock] as an exact rational
+ * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
+ * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+ */
+ WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+ WREG32(DCCG_AUDIO_DTO1_MODULE, clock);
}
-void dce6_audio_fini(struct radeon_device *rdev)
+void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
{
- int i;
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset;
- if (!rdev->audio.enabled)
+ if (!dig || !dig->afmt)
return;
- for (i = 0; i < rdev->audio.num_pins; i++)
- dce6_audio_enable(rdev, &rdev->audio.pin[i], false);
+ offset = dig->afmt->offset;
+
+ if (enable) {
+ if (dig->afmt->enabled)
+ return;
+
+ WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+ WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+ EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */
+ EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */
+ EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */
+ EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
+ radeon_audio_enable(rdev, dig->afmt->pin, true);
+ } else {
+ if (!dig->afmt->enabled)
+ return;
+
+ WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
+ radeon_audio_enable(rdev, dig->afmt->pin, false);
+ }
- rdev->audio.enabled = false;
+ dig->afmt->enabled = enable;
}
diff --git a/drivers/gpu/drm/radeon/evergreen.c b/drivers/gpu/drm/radeon/evergreen.c
index 85995b4e3338..4c0e24b3bb90 100644
--- a/drivers/gpu/drm/radeon/evergreen.c
+++ b/drivers/gpu/drm/radeon/evergreen.c
@@ -26,6 +26,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "evergreend.h"
#include "atom.h"
@@ -3252,6 +3253,8 @@ static void evergreen_gpu_init(struct radeon_device *rdev)
}
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ WREG32(SRBM_INT_CNTL, 0x1);
+ WREG32(SRBM_INT_ACK, 0x1);
evergreen_fix_pci_max_read_req_size(rdev);
@@ -4323,6 +4326,7 @@ void evergreen_disable_interrupt_state(struct radeon_device *rdev)
tmp = RREG32(DMA_CNTL) & ~TRAP_ENABLE;
WREG32(DMA_CNTL, tmp);
WREG32(GRBM_INT_CNTL, 0);
+ WREG32(SRBM_INT_CNTL, 0);
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
if (rdev->num_crtc >= 4) {
@@ -5065,6 +5069,10 @@ restart_ih:
DRM_ERROR("Unhandled interrupt: %d %d\n", src_id, src_data);
break;
}
+ case 96:
+ DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+ WREG32(SRBM_INT_ACK, 0x1);
+ break;
case 124: /* UVD */
DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -5286,7 +5294,7 @@ static int evergreen_startup(struct radeon_device *rdev)
return r;
}
- r = r600_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
@@ -5332,7 +5340,7 @@ int evergreen_resume(struct radeon_device *rdev)
int evergreen_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_suspend(rdev);
r700_cp_stop(rdev);
@@ -5482,7 +5490,7 @@ int evergreen_init(struct radeon_device *rdev)
void evergreen_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r700_cp_fini(rdev);
r600_dma_fini(rdev);
r600_irq_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/evergreen_cs.c b/drivers/gpu/drm/radeon/evergreen_cs.c
index 924b1b7ab455..c9e0fbbf76a3 100644
--- a/drivers/gpu/drm/radeon/evergreen_cs.c
+++ b/drivers/gpu/drm/radeon/evergreen_cs.c
@@ -83,6 +83,7 @@ struct evergreen_cs_track {
u32 htile_offset;
u32 htile_surface;
struct radeon_bo *htile_bo;
+ unsigned long indirect_draw_buffer_size;
};
static u32 evergreen_cs_get_aray_mode(u32 tiling_flags)
@@ -1896,6 +1897,14 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
}
break;
}
+ case PACKET3_INDEX_BUFFER_SIZE:
+ {
+ if (pkt->count != 0) {
+ DRM_ERROR("bad INDEX_BUFFER_SIZE\n");
+ return -EINVAL;
+ }
+ break;
+ }
case PACKET3_DRAW_INDEX:
{
uint64_t offset;
@@ -2006,6 +2015,67 @@ static int evergreen_packet3_check(struct radeon_cs_parser *p,
return r;
}
break;
+ case PACKET3_SET_BASE:
+ {
+ /*
+ DW 1 HEADER Header of the packet. Shader_Type in bit 1 of the Header will correspond to the shader type of the Load, see Type-3 Packet.
+ 2 BASE_INDEX Bits [3:0] BASE_INDEX - Base Index specifies which base address is specified in the last two DWs.
+ 0001: DX11 Draw_Index_Indirect Patch Table Base: Base address for Draw_Index_Indirect data.
+ 3 ADDRESS_LO Bits [31:3] - Lower bits of QWORD-Aligned Address. Bits [2:0] - Reserved
+ 4 ADDRESS_HI Bits [31:8] - Reserved. Bits [7:0] - Upper bits of Address [47:32]
+ */
+ if (pkt->count != 2) {
+ DRM_ERROR("bad SET_BASE\n");
+ return -EINVAL;
+ }
+
+ /* currently only supporting setting indirect draw buffer base address */
+ if (idx_value != 1) {
+ DRM_ERROR("bad SET_BASE\n");
+ return -EINVAL;
+ }
+
+ r = radeon_cs_packet_next_reloc(p, &reloc, 0);
+ if (r) {
+ DRM_ERROR("bad SET_BASE\n");
+ return -EINVAL;
+ }
+
+ track->indirect_draw_buffer_size = radeon_bo_size(reloc->robj);
+
+ ib[idx+1] = reloc->gpu_offset;
+ ib[idx+2] = upper_32_bits(reloc->gpu_offset) & 0xff;
+
+ break;
+ }
+ case PACKET3_DRAW_INDIRECT:
+ case PACKET3_DRAW_INDEX_INDIRECT:
+ {
+ u64 size = pkt->opcode == PACKET3_DRAW_INDIRECT ? 16 : 20;
+
+ /*
+ DW 1 HEADER
+ 2 DATA_OFFSET Bits [31:0] + byte aligned offset where the required data structure starts. Bits 1:0 are zero
+ 3 DRAW_INITIATOR Draw Initiator Register. Written to the VGT_DRAW_INITIATOR register for the assigned context
+ */
+ if (pkt->count != 1) {
+ DRM_ERROR("bad DRAW_INDIRECT\n");
+ return -EINVAL;
+ }
+
+ if (idx_value + size > track->indirect_draw_buffer_size) {
+ dev_warn(p->dev, "DRAW_INDIRECT buffer too small %u + %llu > %lu\n",
+ idx_value, size, track->indirect_draw_buffer_size);
+ return -EINVAL;
+ }
+
+ r = evergreen_cs_track_check(p);
+ if (r) {
+ dev_warn(p->dev, "%s:%d invalid cmd stream\n", __func__, __LINE__);
+ return r;
+ }
+ break;
+ }
case PACKET3_DISPATCH_DIRECT:
if (pkt->count != 3) {
DRM_ERROR("bad DISPATCH_DIRECT\n");
@@ -3243,7 +3313,13 @@ static int evergreen_vm_packet3_check(struct radeon_device *rdev,
switch (pkt->opcode) {
case PACKET3_NOP:
+ break;
case PACKET3_SET_BASE:
+ if (idx_value != 1) {
+ DRM_ERROR("bad SET_BASE");
+ return -EINVAL;
+ }
+ break;
case PACKET3_CLEAR_STATE:
case PACKET3_INDEX_BUFFER_SIZE:
case PACKET3_DISPATCH_DIRECT:
diff --git a/drivers/gpu/drm/radeon/evergreen_hdmi.c b/drivers/gpu/drm/radeon/evergreen_hdmi.c
index 53abd9b17a50..1d9aebc79595 100644
--- a/drivers/gpu/drm/radeon/evergreen_hdmi.c
+++ b/drivers/gpu/drm/radeon/evergreen_hdmi.c
@@ -29,17 +29,12 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "evergreend.h"
#include "atom.h"
-extern void dce6_afmt_write_speaker_allocation(struct drm_encoder *encoder);
-extern void dce6_afmt_write_sad_regs(struct drm_encoder *encoder);
-extern void dce6_afmt_select_pin(struct drm_encoder *encoder);
-extern void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
- struct drm_display_mode *mode);
-
/* enable the audio stream */
-static void dce4_audio_enable(struct radeon_device *rdev,
+void dce4_audio_enable(struct radeon_device *rdev,
struct r600_audio_pin *pin,
u8 enable_mask)
{
@@ -69,48 +64,42 @@ static void dce4_audio_enable(struct radeon_device *rdev,
WREG32(AZ_HOT_PLUG_CONTROL, tmp);
}
-/*
- * update the N and CTS parameters for a given pixel clock rate
- */
-static void evergreen_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- uint32_t offset = dig->afmt->offset;
+ int bpc = 8;
- WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr.cts_32khz));
- WREG32(HDMI_ACR_32_1 + offset, acr.n_32khz);
+ if (encoder->crtc) {
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+ bpc = radeon_crtc->bpc;
+ }
- WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr.cts_44_1khz));
- WREG32(HDMI_ACR_44_1 + offset, acr.n_44_1khz);
+ if (bpc > 8)
+ WREG32(HDMI_ACR_PACKET_CONTROL + offset,
+ HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
+ else
+ WREG32(HDMI_ACR_PACKET_CONTROL + offset,
+ HDMI_ACR_SOURCE | /* select SW CTS value */
+ HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
+
+ WREG32(HDMI_ACR_32_0 + offset, HDMI_ACR_CTS_32(acr->cts_32khz));
+ WREG32(HDMI_ACR_32_1 + offset, acr->n_32khz);
- WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr.cts_48khz));
- WREG32(HDMI_ACR_48_1 + offset, acr.n_48khz);
+ WREG32(HDMI_ACR_44_0 + offset, HDMI_ACR_CTS_44(acr->cts_44_1khz));
+ WREG32(HDMI_ACR_44_1 + offset, acr->n_44_1khz);
+
+ WREG32(HDMI_ACR_48_0 + offset, HDMI_ACR_CTS_48(acr->cts_48khz));
+ WREG32(HDMI_ACR_48_1 + offset, acr->n_48khz);
}
-static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
- struct drm_display_mode *mode)
+void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
+ struct drm_connector *connector, struct drm_display_mode *mode)
{
struct radeon_device *rdev = encoder->dev->dev_private;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
u32 tmp = 0;
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
if (mode->flags & DRM_MODE_FLAG_INTERLACE) {
if (connector->latency_present[1])
tmp = VIDEO_LIPSYNC(connector->video_latency[1]) |
@@ -124,38 +113,17 @@ static void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
else
tmp = VIDEO_LIPSYNC(255) | AUDIO_LIPSYNC(255);
}
- WREG32(AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
+ WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_RESPONSE_LIPSYNC, tmp);
}
-static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
+void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
u32 tmp;
- u8 *sadb = NULL;
- int sad_count;
-
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
- sad_count = drm_edid_to_speaker_allocation(radeon_connector_edid(connector), &sadb);
- if (sad_count < 0) {
- DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n", sad_count);
- sad_count = 0;
- }
/* program the speaker allocation */
- tmp = RREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+ tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
tmp &= ~(DP_CONNECTION | SPEAKER_ALLOCATION_MASK);
/* set HDMI mode */
tmp |= HDMI_CONNECTION;
@@ -163,19 +131,32 @@ static void dce4_afmt_write_speaker_allocation(struct drm_encoder *encoder)
tmp |= SPEAKER_ALLOCATION(sadb[0]);
else
tmp |= SPEAKER_ALLOCATION(5); /* stereo */
- WREG32(AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
-
- kfree(sadb);
+ WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
}
-static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
+void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count)
{
struct radeon_device *rdev = encoder->dev->dev_private;
- struct drm_connector *connector;
- struct radeon_connector *radeon_connector = NULL;
- struct cea_sad *sads;
- int i, sad_count;
+ u32 tmp;
+ /* program the speaker allocation */
+ tmp = RREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER);
+ tmp &= ~(HDMI_CONNECTION | SPEAKER_ALLOCATION_MASK);
+ /* set DP mode */
+ tmp |= DP_CONNECTION;
+ if (sad_count)
+ tmp |= SPEAKER_ALLOCATION(sadb[0]);
+ else
+ tmp |= SPEAKER_ALLOCATION(5); /* stereo */
+ WREG32_ENDPOINT(0, AZ_F0_CODEC_PIN0_CONTROL_CHANNEL_SPEAKER, tmp);
+}
+
+void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count)
+{
+ int i;
+ struct radeon_device *rdev = encoder->dev->dev_private;
static const u16 eld_reg_to_type[][2] = {
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR0, HDMI_AUDIO_CODING_TYPE_PCM },
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR1, HDMI_AUDIO_CODING_TYPE_AC3 },
@@ -191,25 +172,6 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
{ AZ_F0_CODEC_PIN0_CONTROL_AUDIO_DESCRIPTOR13, HDMI_AUDIO_CODING_TYPE_WMA_PRO },
};
- list_for_each_entry(connector, &encoder->dev->mode_config.connector_list, head) {
- if (connector->encoder == encoder) {
- radeon_connector = to_radeon_connector(connector);
- break;
- }
- }
-
- if (!radeon_connector) {
- DRM_ERROR("Couldn't find encoder's connector\n");
- return;
- }
-
- sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
- if (sad_count <= 0) {
- DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
- return;
- }
- BUG_ON(!sads);
-
for (i = 0; i < ARRAY_SIZE(eld_reg_to_type); i++) {
u32 value = 0;
u8 stereo_freqs = 0;
@@ -236,25 +198,17 @@ static void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder)
value |= SUPPORTED_FREQUENCIES_STEREO(stereo_freqs);
- WREG32(eld_reg_to_type[i][0], value);
+ WREG32_ENDPOINT(0, eld_reg_to_type[i][0], value);
}
-
- kfree(sads);
}
/*
- * build a HDMI Video Info Frame
+ * build a AVI Info Frame
*/
-static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
- void *buffer, size_t size)
+void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
+ unsigned char *buffer, size_t size)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- uint32_t offset = dig->afmt->offset;
uint8_t *frame = buffer + 3;
- uint8_t *header = buffer;
WREG32(AFMT_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -263,104 +217,103 @@ static void evergreen_hdmi_update_avi_infoframe(struct drm_encoder *encoder,
WREG32(AFMT_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(AFMT_AVI_INFO3 + offset,
- frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
+ frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
+
+ WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
+ HDMI_AVI_INFO_SEND | /* enable AVI info frames */
+ HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
+
+ WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
+ HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
+ ~HDMI_AVI_INFO_LINE_MASK);
}
-static void evergreen_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
- u32 base_rate = 24000;
- u32 max_ratio = clock / base_rate;
+ unsigned int max_ratio = clock / 24000;
u32 dto_phase;
- u32 dto_modulo = clock;
u32 wallclock_ratio;
- u32 dto_cntl;
-
- if (!dig || !dig->afmt)
- return;
-
- if (ASIC_IS_DCE6(rdev)) {
- dto_phase = 24 * 1000;
+ u32 value;
+
+ if (max_ratio >= 8) {
+ dto_phase = 192 * 1000;
+ wallclock_ratio = 3;
+ } else if (max_ratio >= 4) {
+ dto_phase = 96 * 1000;
+ wallclock_ratio = 2;
+ } else if (max_ratio >= 2) {
+ dto_phase = 48 * 1000;
+ wallclock_ratio = 1;
} else {
- if (max_ratio >= 8) {
- dto_phase = 192 * 1000;
- wallclock_ratio = 3;
- } else if (max_ratio >= 4) {
- dto_phase = 96 * 1000;
- wallclock_ratio = 2;
- } else if (max_ratio >= 2) {
- dto_phase = 48 * 1000;
- wallclock_ratio = 1;
- } else {
- dto_phase = 24 * 1000;
- wallclock_ratio = 0;
- }
- dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
- dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
- WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
+ dto_phase = 24 * 1000;
+ wallclock_ratio = 0;
}
- /* XXX two dtos; generally use dto0 for hdmi */
+ value = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ value |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
+ value &= ~DCCG_AUDIO_DTO1_USE_512FBR_DTO;
+ WREG32(DCCG_AUDIO_DTO0_CNTL, value);
+
+ /* Two dtos; generally use dto0 for HDMI */
+ value = 0;
+
+ if (crtc)
+ value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
+
+ WREG32(DCCG_AUDIO_DTO_SOURCE, value);
+
/* Express [24MHz / target pixel clock] as an exact rational
* number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
* is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
*/
- WREG32(DCCG_AUDIO_DTO_SOURCE, DCCG_AUDIO_DTO0_SOURCE_SEL(radeon_crtc->crtc_id));
WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
- WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, clock);
}
-
-/*
- * update the info frames with the data from the current display mode
- */
-void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+void dce4_dp_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
- u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
- struct hdmi_avi_infoframe frame;
- uint32_t offset;
- ssize_t err;
- uint32_t val;
- int bpc = 8;
+ u32 value;
- if (!dig || !dig->afmt)
- return;
+ value = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
+ value |= DCCG_AUDIO_DTO1_USE_512FBR_DTO;
+ WREG32(DCCG_AUDIO_DTO1_CNTL, value);
- /* Silent, r600_hdmi_enable will raise WARN for us */
- if (!dig->afmt->enabled)
- return;
- offset = dig->afmt->offset;
+ /* Two dtos; generally use dto1 for DP */
+ value = 0;
+ value |= DCCG_AUDIO_DTO_SEL;
- /* hdmi deep color mode general control packets setup, if bpc > 8 */
- if (encoder->crtc) {
- struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
- bpc = radeon_crtc->bpc;
- }
+ if (crtc)
+ value |= DCCG_AUDIO_DTO0_SOURCE_SEL(crtc->crtc_id);
- /* disable audio prior to setting up hw */
- if (ASIC_IS_DCE6(rdev)) {
- dig->afmt->pin = dce6_audio_get_pin(rdev);
- dce6_audio_enable(rdev, dig->afmt->pin, 0);
- } else {
- dig->afmt->pin = r600_audio_get_pin(rdev);
- dce4_audio_enable(rdev, dig->afmt->pin, 0);
- }
+ WREG32(DCCG_AUDIO_DTO_SOURCE, value);
+
+ /* Express [24MHz / target pixel clock] as an exact rational
+ * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
+ * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
+ */
+ WREG32(DCCG_AUDIO_DTO1_PHASE, 24000);
+ WREG32(DCCG_AUDIO_DTO1_MODULE, rdev->clock.max_pixel_clock * 10);
+}
- evergreen_audio_set_dto(encoder, mode->clock);
+void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
WREG32(HDMI_VBI_PACKET_CONTROL + offset,
- HDMI_NULL_SEND); /* send null packets when required */
+ HDMI_NULL_SEND | /* send null packets when required */
+ HDMI_GC_SEND | /* send general control packets */
+ HDMI_GC_CONT); /* send general control packets every frame */
+}
- WREG32(AFMT_AUDIO_CRC_CONTROL + offset, 0x1000);
+void dce4_hdmi_set_color_depth(struct drm_encoder *encoder, u32 offset, int bpc)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ uint32_t val;
val = RREG32(HDMI_CONTROL + offset);
val &= ~HDMI_DEEP_COLOR_ENABLE;
@@ -390,113 +343,59 @@ void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode
}
WREG32(HDMI_CONTROL + offset, val);
+}
- WREG32(HDMI_VBI_PACKET_CONTROL + offset,
- HDMI_NULL_SEND | /* send null packets when required */
- HDMI_GC_SEND | /* send general control packets */
- HDMI_GC_CONT); /* send general control packets every frame */
+void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
WREG32(HDMI_INFOFRAME_CONTROL0 + offset,
- HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
- HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
+ HDMI_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+ HDMI_AUDIO_INFO_CONT); /* required for audio info values to be updated */
WREG32(AFMT_INFOFRAME_CONTROL0 + offset,
- AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
+ AFMT_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
WREG32(HDMI_INFOFRAME_CONTROL1 + offset,
- HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
-
- WREG32(HDMI_GC + offset, 0); /* unset HDMI_GC_AVMUTE */
+ HDMI_AUDIO_INFO_LINE(2)); /* anything other than 0 */
WREG32(HDMI_AUDIO_PACKET_CONTROL + offset,
- HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
- HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
-
- WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
- AFMT_60958_CS_UPDATE); /* allow 60958 channel status fields to be updated */
-
- /* fglrx clears sth in AFMT_AUDIO_PACKET_CONTROL2 here */
-
- if (bpc > 8)
- WREG32(HDMI_ACR_PACKET_CONTROL + offset,
- HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
- else
- WREG32(HDMI_ACR_PACKET_CONTROL + offset,
- HDMI_ACR_SOURCE | /* select SW CTS value */
- HDMI_ACR_AUTO_SEND); /* allow hw to sent ACR packets when required */
-
- evergreen_hdmi_update_ACR(encoder, mode->clock);
+ HDMI_AUDIO_DELAY_EN(1) | /* set the default audio delay */
+ HDMI_AUDIO_PACKETS_PER_LINE(3)); /* should be suffient for all audio modes and small enough for all hblanks */
WREG32(AFMT_60958_0 + offset,
- AFMT_60958_CS_CHANNEL_NUMBER_L(1));
+ AFMT_60958_CS_CHANNEL_NUMBER_L(1));
WREG32(AFMT_60958_1 + offset,
- AFMT_60958_CS_CHANNEL_NUMBER_R(2));
+ AFMT_60958_CS_CHANNEL_NUMBER_R(2));
WREG32(AFMT_60958_2 + offset,
- AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
- AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
- AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
- AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
- AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
- AFMT_60958_CS_CHANNEL_NUMBER_7(8));
-
- if (ASIC_IS_DCE6(rdev)) {
- dce6_afmt_write_speaker_allocation(encoder);
- } else {
- dce4_afmt_write_speaker_allocation(encoder);
- }
+ AFMT_60958_CS_CHANNEL_NUMBER_2(3) |
+ AFMT_60958_CS_CHANNEL_NUMBER_3(4) |
+ AFMT_60958_CS_CHANNEL_NUMBER_4(5) |
+ AFMT_60958_CS_CHANNEL_NUMBER_5(6) |
+ AFMT_60958_CS_CHANNEL_NUMBER_6(7) |
+ AFMT_60958_CS_CHANNEL_NUMBER_7(8));
WREG32(AFMT_AUDIO_PACKET_CONTROL2 + offset,
- AFMT_AUDIO_CHANNEL_ENABLE(0xff));
-
- /* fglrx sets 0x40 in 0x5f80 here */
-
- if (ASIC_IS_DCE6(rdev)) {
- dce6_afmt_select_pin(encoder);
- dce6_afmt_write_sad_regs(encoder);
- dce6_afmt_write_latency_fields(encoder, mode);
- } else {
- evergreen_hdmi_write_sad_regs(encoder);
- dce4_afmt_write_latency_fields(encoder, mode);
- }
-
- err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
- if (err < 0) {
- DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
- return;
- }
-
- err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
- if (err < 0) {
- DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
- return;
- }
-
- evergreen_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
-
- WREG32_OR(HDMI_INFOFRAME_CONTROL0 + offset,
- HDMI_AVI_INFO_SEND | /* enable AVI info frames */
- HDMI_AVI_INFO_CONT); /* required for audio info values to be updated */
+ AFMT_AUDIO_CHANNEL_ENABLE(0xff));
- WREG32_P(HDMI_INFOFRAME_CONTROL1 + offset,
- HDMI_AVI_INFO_LINE(2), /* anything other than 0 */
- ~HDMI_AVI_INFO_LINE_MASK);
+ /* allow 60958 channel status and send audio packets fields to be updated */
+ WREG32(AFMT_AUDIO_PACKET_CONTROL + offset,
+ AFMT_AUDIO_SAMPLE_SEND | AFMT_RESET_FIFO_WHEN_AUDIO_DIS | AFMT_60958_CS_UPDATE);
+}
- WREG32_OR(AFMT_AUDIO_PACKET_CONTROL + offset,
- AFMT_AUDIO_SAMPLE_SEND); /* send audio packets */
- /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
- WREG32(AFMT_RAMP_CONTROL0 + offset, 0x00FFFFFF);
- WREG32(AFMT_RAMP_CONTROL1 + offset, 0x007FFFFF);
- WREG32(AFMT_RAMP_CONTROL2 + offset, 0x00000001);
- WREG32(AFMT_RAMP_CONTROL3 + offset, 0x00000001);
+void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
- /* enable audio after to setting up hw */
- if (ASIC_IS_DCE6(rdev))
- dce6_audio_enable(rdev, dig->afmt->pin, 1);
+ if (mute)
+ WREG32_OR(HDMI_GC + offset, HDMI_GC_AVMUTE);
else
- dce4_audio_enable(rdev, dig->afmt->pin, 0xf);
+ WREG32_AND(HDMI_GC + offset, ~HDMI_GC_AVMUTE);
}
void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
@@ -516,10 +415,7 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
return;
if (!enable && dig->afmt->pin) {
- if (ASIC_IS_DCE6(rdev))
- dce6_audio_enable(rdev, dig->afmt->pin, 0);
- else
- dce4_audio_enable(rdev, dig->afmt->pin, 0);
+ radeon_audio_enable(rdev, dig->afmt->pin, 0);
dig->afmt->pin = NULL;
}
@@ -528,3 +424,57 @@ void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable)
DRM_DEBUG("%sabling HDMI interface @ 0x%04X for encoder 0x%x\n",
enable ? "En" : "Dis", dig->afmt->offset, radeon_encoder->encoder_id);
}
+
+void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ uint32_t offset;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ offset = dig->afmt->offset;
+
+ if (enable) {
+ struct drm_connector *connector = radeon_get_connector_for_encoder(encoder);
+ struct radeon_connector *radeon_connector = to_radeon_connector(connector);
+ struct radeon_connector_atom_dig *dig_connector;
+ uint32_t val;
+
+ if (dig->afmt->enabled)
+ return;
+
+ WREG32(EVERGREEN_DP_SEC_TIMESTAMP + offset, EVERGREEN_DP_SEC_TIMESTAMP_MODE(1));
+
+ if (radeon_connector->con_priv) {
+ dig_connector = radeon_connector->con_priv;
+ val = RREG32(EVERGREEN_DP_SEC_AUD_N + offset);
+ val &= ~EVERGREEN_DP_SEC_N_BASE_MULTIPLE(0xf);
+
+ if (dig_connector->dp_clock == 162000)
+ val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(3);
+ else
+ val |= EVERGREEN_DP_SEC_N_BASE_MULTIPLE(5);
+
+ WREG32(EVERGREEN_DP_SEC_AUD_N + offset, val);
+ }
+
+ WREG32(EVERGREEN_DP_SEC_CNTL + offset,
+ EVERGREEN_DP_SEC_ASP_ENABLE | /* Audio packet transmission */
+ EVERGREEN_DP_SEC_ATP_ENABLE | /* Audio timestamp packet transmission */
+ EVERGREEN_DP_SEC_AIP_ENABLE | /* Audio infoframe packet transmission */
+ EVERGREEN_DP_SEC_STREAM_ENABLE); /* Master enable for secondary stream engine */
+ radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+ } else {
+ if (!dig->afmt->enabled)
+ return;
+
+ WREG32(EVERGREEN_DP_SEC_CNTL + offset, 0);
+ radeon_audio_enable(rdev, dig->afmt->pin, 0);
+ }
+
+ dig->afmt->enabled = enable;
+}
diff --git a/drivers/gpu/drm/radeon/evergreen_reg.h b/drivers/gpu/drm/radeon/evergreen_reg.h
index 23bff590fb6e..aa939dfed3a3 100644
--- a/drivers/gpu/drm/radeon/evergreen_reg.h
+++ b/drivers/gpu/drm/radeon/evergreen_reg.h
@@ -251,4 +251,19 @@
/* HDMI blocks at 0x7030, 0x7c30, 0x10830, 0x11430, 0x12030, 0x12c30 */
#define EVERGREEN_HDMI_BASE 0x7030
+/* Display Port block */
+#define EVERGREEN_DP_SEC_CNTL 0x7280
+# define EVERGREEN_DP_SEC_STREAM_ENABLE (1 << 0)
+# define EVERGREEN_DP_SEC_ASP_ENABLE (1 << 4)
+# define EVERGREEN_DP_SEC_ATP_ENABLE (1 << 8)
+# define EVERGREEN_DP_SEC_AIP_ENABLE (1 << 12)
+# define EVERGREEN_DP_SEC_GSP_ENABLE (1 << 20)
+# define EVERGREEN_DP_SEC_AVI_ENABLE (1 << 24)
+# define EVERGREEN_DP_SEC_MPG_ENABLE (1 << 28)
+#define EVERGREEN_DP_SEC_TIMESTAMP 0x72a4
+# define EVERGREEN_DP_SEC_TIMESTAMP_MODE(x) (((x) & 0x3) << 0)
+#define EVERGREEN_DP_SEC_AUD_N 0x7294
+# define EVERGREEN_DP_SEC_N_BASE_MULTIPLE(x) (((x) & 0xf) << 24)
+# define EVERGREEN_DP_SEC_SS_EN (1 << 28)
+
#endif
diff --git a/drivers/gpu/drm/radeon/evergreend.h b/drivers/gpu/drm/radeon/evergreend.h
index b066d6711b8d..a8d1d5240fcb 100644
--- a/drivers/gpu/drm/radeon/evergreend.h
+++ b/drivers/gpu/drm/radeon/evergreend.h
@@ -509,6 +509,7 @@
#define DCCG_AUDIO_DTO1_MODULE 0x05c4
#define DCCG_AUDIO_DTO1_LOAD 0x05c8
#define DCCG_AUDIO_DTO1_CNTL 0x05cc
+# define DCCG_AUDIO_DTO1_USE_512FBR_DTO (1 << 3)
/* DCE 4.0 AFMT */
#define HDMI_CONTROL 0x7030
@@ -1190,6 +1191,10 @@
#define SOFT_RESET_REGBB (1 << 22)
#define SOFT_RESET_ORB (1 << 23)
+#define SRBM_READ_ERROR 0xE98
+#define SRBM_INT_CNTL 0xEA0
+#define SRBM_INT_ACK 0xEA8
+
/* display watermarks */
#define DC_LB_MEMORY_SPLIT 0x6b0c
#define PRIORITY_A_CNT 0x6b18
diff --git a/drivers/gpu/drm/radeon/kv_dpm.c b/drivers/gpu/drm/radeon/kv_dpm.c
index e3e9c10cfba9..0e236d067d66 100644
--- a/drivers/gpu/drm/radeon/kv_dpm.c
+++ b/drivers/gpu/drm/radeon/kv_dpm.c
@@ -1169,6 +1169,19 @@ void kv_dpm_enable_bapm(struct radeon_device *rdev, bool enable)
}
}
+static void kv_enable_thermal_int(struct radeon_device *rdev, bool enable)
+{
+ u32 thermal_int;
+
+ thermal_int = RREG32_SMC(CG_THERMAL_INT_CTRL);
+ if (enable)
+ thermal_int |= THERM_INTH_MASK | THERM_INTL_MASK;
+ else
+ thermal_int &= ~(THERM_INTH_MASK | THERM_INTL_MASK);
+ WREG32_SMC(CG_THERMAL_INT_CTRL, thermal_int);
+
+}
+
int kv_dpm_enable(struct radeon_device *rdev)
{
struct kv_power_info *pi = kv_get_pi(rdev);
@@ -1280,8 +1293,7 @@ int kv_dpm_late_enable(struct radeon_device *rdev)
DRM_ERROR("kv_set_thermal_temperature_range failed\n");
return ret;
}
- rdev->irq.dpm_thermal = true;
- radeon_irq_set(rdev);
+ kv_enable_thermal_int(rdev, true);
}
/* powerdown unused blocks for now */
@@ -1312,6 +1324,7 @@ void kv_dpm_disable(struct radeon_device *rdev)
kv_stop_dpm(rdev);
kv_enable_ulv(rdev, false);
kv_reset_am(rdev);
+ kv_enable_thermal_int(rdev, false);
kv_update_current_ps(rdev, rdev->pm.dpm.boot_ps);
}
@@ -1925,6 +1938,7 @@ void kv_dpm_setup_asic(struct radeon_device *rdev)
kv_init_sclk_t(rdev);
}
+#if 0
void kv_dpm_reset_asic(struct radeon_device *rdev)
{
struct kv_power_info *pi = kv_get_pi(rdev);
@@ -1945,6 +1959,7 @@ void kv_dpm_reset_asic(struct radeon_device *rdev)
kv_set_enabled_level(rdev, pi->graphics_boot_level);
}
}
+#endif
//XXX use sumo_dpm_display_configuration_changed
diff --git a/drivers/gpu/drm/radeon/ni.c b/drivers/gpu/drm/radeon/ni.c
index aea48c89b241..dab00812abaa 100644
--- a/drivers/gpu/drm/radeon/ni.c
+++ b/drivers/gpu/drm/radeon/ni.c
@@ -27,6 +27,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "nid.h"
#include "atom.h"
@@ -961,6 +962,8 @@ static void cayman_gpu_init(struct radeon_device *rdev)
}
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ WREG32(SRBM_INT_CNTL, 0x1);
+ WREG32(SRBM_INT_ACK, 0x1);
evergreen_fix_pci_max_read_req_size(rdev);
@@ -1085,12 +1088,12 @@ static void cayman_gpu_init(struct radeon_device *rdev)
if ((rdev->config.cayman.max_backends_per_se == 1) &&
(rdev->flags & RADEON_IS_IGP)) {
- if ((disabled_rb_mask & 3) == 1) {
- /* RB0 disabled, RB1 enabled */
- tmp = 0x11111111;
- } else {
+ if ((disabled_rb_mask & 3) == 2) {
/* RB1 disabled, RB0 enabled */
tmp = 0x00000000;
+ } else {
+ /* RB0 disabled, RB1 enabled */
+ tmp = 0x11111111;
}
} else {
tmp = gb_addr_config & NUM_PIPES_MASK;
@@ -2097,15 +2100,9 @@ static int cayman_startup(struct radeon_device *rdev)
return r;
}
- if (ASIC_IS_DCE6(rdev)) {
- r = dce6_audio_init(rdev);
- if (r)
- return r;
- } else {
- r = r600_audio_init(rdev);
- if (r)
- return r;
- }
+ r = radeon_audio_init(rdev);
+ if (r)
+ return r;
return 0;
}
@@ -2140,10 +2137,7 @@ int cayman_resume(struct radeon_device *rdev)
int cayman_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- if (ASIC_IS_DCE6(rdev))
- dce6_audio_fini(rdev);
- else
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
cayman_cp_enable(rdev, false);
cayman_dma_stop(rdev);
diff --git a/drivers/gpu/drm/radeon/ni_dpm.c b/drivers/gpu/drm/radeon/ni_dpm.c
index 6d2f16cf2c1c..7bc9f8d9804a 100644
--- a/drivers/gpu/drm/radeon/ni_dpm.c
+++ b/drivers/gpu/drm/radeon/ni_dpm.c
@@ -3862,11 +3862,13 @@ void ni_dpm_post_set_power_state(struct radeon_device *rdev)
ni_update_current_ps(rdev, new_ps);
}
+#if 0
void ni_dpm_reset_asic(struct radeon_device *rdev)
{
ni_restrict_performance_levels_before_switch(rdev);
rv770_set_boot_state(rdev);
}
+#endif
union power_info {
struct _ATOM_POWERPLAY_INFO info;
diff --git a/drivers/gpu/drm/radeon/nid.h b/drivers/gpu/drm/radeon/nid.h
index ad7125486894..6b44580440d0 100644
--- a/drivers/gpu/drm/radeon/nid.h
+++ b/drivers/gpu/drm/radeon/nid.h
@@ -82,6 +82,10 @@
#define SOFT_RESET_REGBB (1 << 22)
#define SOFT_RESET_ORB (1 << 23)
+#define SRBM_READ_ERROR 0xE98
+#define SRBM_INT_CNTL 0xEA0
+#define SRBM_INT_ACK 0xEA8
+
#define SRBM_STATUS2 0x0EC4
#define DMA_BUSY (1 << 5)
#define DMA1_BUSY (1 << 6)
diff --git a/drivers/gpu/drm/radeon/r600.c b/drivers/gpu/drm/radeon/r600.c
index ef5d6066fa5b..07a71a2488c9 100644
--- a/drivers/gpu/drm/radeon/r600.c
+++ b/drivers/gpu/drm/radeon/r600.c
@@ -33,6 +33,7 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "radeon_mode.h"
#include "r600d.h"
#include "atom.h"
@@ -3054,7 +3055,7 @@ static int r600_startup(struct radeon_device *rdev)
return r;
}
- r = r600_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
@@ -3105,7 +3106,7 @@ int r600_resume(struct radeon_device *rdev)
int r600_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r600_cp_stop(rdev);
if (rdev->has_uvd) {
uvd_v1_0_fini(rdev);
@@ -3224,7 +3225,7 @@ int r600_init(struct radeon_device *rdev)
void r600_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r600_cp_fini(rdev);
r600_irq_fini(rdev);
if (rdev->has_uvd) {
diff --git a/drivers/gpu/drm/radeon/r600_dpm.c b/drivers/gpu/drm/radeon/r600_dpm.c
index 843b65f46ece..fa2154493cf1 100644
--- a/drivers/gpu/drm/radeon/r600_dpm.c
+++ b/drivers/gpu/drm/radeon/r600_dpm.c
@@ -188,7 +188,7 @@ u32 r600_dpm_get_vrefresh(struct radeon_device *rdev)
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
radeon_crtc = to_radeon_crtc(crtc);
if (crtc->enabled && radeon_crtc->enabled && radeon_crtc->hw_mode.clock) {
- vrefresh = radeon_crtc->hw_mode.vrefresh;
+ vrefresh = drm_mode_vrefresh(&radeon_crtc->hw_mode);
break;
}
}
diff --git a/drivers/gpu/drm/radeon/r600_hdmi.c b/drivers/gpu/drm/radeon/r600_hdmi.c
index b90dc0eb08e6..62c91ed669ce 100644
--- a/drivers/gpu/drm/radeon/r600_hdmi.c
+++ b/drivers/gpu/drm/radeon/r600_hdmi.c
@@ -29,6 +29,7 @@
#include <drm/radeon_drm.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "r600d.h"
#include "atom.h"
@@ -55,30 +56,6 @@ enum r600_hdmi_iec_status_bits {
AUDIO_STATUS_LEVEL = 0x80
};
-static const struct radeon_hdmi_acr r600_hdmi_predefined_acr[] = {
- /* 32kHz 44.1kHz 48kHz */
- /* Clock N CTS N CTS N CTS */
- { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */
- { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */
- { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */
- { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */
- { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */
- { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */
- { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */
- { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
- { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */
- { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
-};
-
-
-/*
- * check if the chipset is supported
- */
-static int r600_audio_chipset_supported(struct radeon_device *rdev)
-{
- return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
-}
-
static struct r600_audio_pin r600_audio_status(struct radeon_device *rdev)
{
struct r600_audio_pin status;
@@ -191,155 +168,56 @@ void r600_audio_enable(struct radeon_device *rdev,
WREG32(AZ_HOT_PLUG_CONTROL, tmp);
}
-/*
- * initialize the audio vars
- */
-int r600_audio_init(struct radeon_device *rdev)
-{
- if (!radeon_audio || !r600_audio_chipset_supported(rdev))
- return 0;
-
- rdev->audio.enabled = true;
-
- rdev->audio.num_pins = 1;
- rdev->audio.pin[0].channels = -1;
- rdev->audio.pin[0].rate = -1;
- rdev->audio.pin[0].bits_per_sample = -1;
- rdev->audio.pin[0].status_bits = 0;
- rdev->audio.pin[0].category_code = 0;
- rdev->audio.pin[0].id = 0;
- /* disable audio. it will be set up later */
- r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
-
- return 0;
-}
-
-/*
- * release the audio timer
- * TODO: How to do this correctly on SMP systems?
- */
-void r600_audio_fini(struct radeon_device *rdev)
-{
- if (!rdev->audio.enabled)
- return;
-
- r600_audio_enable(rdev, &rdev->audio.pin[0], 0);
-
- rdev->audio.enabled = false;
-}
-
struct r600_audio_pin *r600_audio_get_pin(struct radeon_device *rdev)
{
/* only one pin on 6xx-NI */
return &rdev->audio.pin[0];
}
-/*
- * calculate CTS and N values if they are not found in the table
- */
-static void r600_hdmi_calc_cts(uint32_t clock, int *CTS, int *N, int freq)
-{
- int n, cts;
- unsigned long div, mul;
-
- /* Safe, but overly large values */
- n = 128 * freq;
- cts = clock * 1000;
-
- /* Smallest valid fraction */
- div = gcd(n, cts);
-
- n /= div;
- cts /= div;
-
- /*
- * The optimal N is 128*freq/1000. Calculate the closest larger
- * value that doesn't truncate any bits.
- */
- mul = ((128*freq/1000) + (n-1))/n;
-
- n *= mul;
- cts *= mul;
-
- /* Check that we are in spec (not always possible) */
- if (n < (128*freq/1500))
- printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
- if (n > (128*freq/300))
- printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
-
- *N = n;
- *CTS = cts;
-
- DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
- *N, *CTS, freq);
-}
-
-struct radeon_hdmi_acr r600_hdmi_acr(uint32_t clock)
-{
- struct radeon_hdmi_acr res;
- u8 i;
-
- /* Precalculated values for common clocks */
- for (i = 0; i < ARRAY_SIZE(r600_hdmi_predefined_acr); i++) {
- if (r600_hdmi_predefined_acr[i].clock == clock)
- return r600_hdmi_predefined_acr[i];
- }
-
- /* And odd clocks get manually calculated */
- r600_hdmi_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
- r600_hdmi_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
- r600_hdmi_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
-
- return res;
-}
-
-/*
- * update the N and CTS parameters for a given pixel clock rate
- */
-void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock)
+void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- struct radeon_hdmi_acr acr = r600_hdmi_acr(clock);
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- uint32_t offset = dig->afmt->offset;
+
+ /* DCE 3.0 uses register that's normally for CRC_CONTROL */
+ uint32_t acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
+ HDMI0_ACR_PACKET_CONTROL;
+ WREG32_P(acr_ctl + offset,
+ HDMI0_ACR_SOURCE | /* select SW CTS value */
+ HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
+ ~(HDMI0_ACR_SOURCE |
+ HDMI0_ACR_AUTO_SEND));
WREG32_P(HDMI0_ACR_32_0 + offset,
- HDMI0_ACR_CTS_32(acr.cts_32khz),
- ~HDMI0_ACR_CTS_32_MASK);
+ HDMI0_ACR_CTS_32(acr->cts_32khz),
+ ~HDMI0_ACR_CTS_32_MASK);
WREG32_P(HDMI0_ACR_32_1 + offset,
- HDMI0_ACR_N_32(acr.n_32khz),
- ~HDMI0_ACR_N_32_MASK);
+ HDMI0_ACR_N_32(acr->n_32khz),
+ ~HDMI0_ACR_N_32_MASK);
WREG32_P(HDMI0_ACR_44_0 + offset,
- HDMI0_ACR_CTS_44(acr.cts_44_1khz),
- ~HDMI0_ACR_CTS_44_MASK);
+ HDMI0_ACR_CTS_44(acr->cts_44_1khz),
+ ~HDMI0_ACR_CTS_44_MASK);
WREG32_P(HDMI0_ACR_44_1 + offset,
- HDMI0_ACR_N_44(acr.n_44_1khz),
- ~HDMI0_ACR_N_44_MASK);
+ HDMI0_ACR_N_44(acr->n_44_1khz),
+ ~HDMI0_ACR_N_44_MASK);
WREG32_P(HDMI0_ACR_48_0 + offset,
- HDMI0_ACR_CTS_48(acr.cts_48khz),
- ~HDMI0_ACR_CTS_48_MASK);
+ HDMI0_ACR_CTS_48(acr->cts_48khz),
+ ~HDMI0_ACR_CTS_48_MASK);
WREG32_P(HDMI0_ACR_48_1 + offset,
- HDMI0_ACR_N_48(acr.n_48khz),
- ~HDMI0_ACR_N_48_MASK);
+ HDMI0_ACR_N_48(acr->n_48khz),
+ ~HDMI0_ACR_N_48_MASK);
}
/*
* build a HDMI Video Info Frame
*/
-void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
- size_t size)
+void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
+ unsigned char *buffer, size_t size)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- uint32_t offset = dig->afmt->offset;
uint8_t *frame = buffer + 3;
- uint8_t *header = buffer;
WREG32(HDMI0_AVI_INFO0 + offset,
frame[0x0] | (frame[0x1] << 8) | (frame[0x2] << 16) | (frame[0x3] << 24));
@@ -348,7 +226,14 @@ void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
WREG32(HDMI0_AVI_INFO2 + offset,
frame[0x8] | (frame[0x9] << 8) | (frame[0xA] << 16) | (frame[0xB] << 24));
WREG32(HDMI0_AVI_INFO3 + offset,
- frame[0xC] | (frame[0xD] << 8) | (header[1] << 24));
+ frame[0xC] | (frame[0xD] << 8) | (buffer[1] << 24));
+
+ WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
+ HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
+ HDMI0_AVI_INFO_CONT); /* send AVI info frames every frame/field */
+
+ WREG32_OR(HDMI0_INFOFRAME_CONTROL1 + offset,
+ HDMI0_AVI_INFO_LINE(2)); /* anything other than 0 */
}
/*
@@ -425,188 +310,94 @@ void r600_hdmi_audio_workaround(struct drm_encoder *encoder)
value, ~HDMI0_AUDIO_TEST_EN);
}
-void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock)
+void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock)
{
- struct drm_device *dev = encoder->dev;
- struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- u32 base_rate = 24000;
- u32 max_ratio = clock / base_rate;
- u32 dto_phase;
- u32 dto_modulo = clock;
- u32 wallclock_ratio;
- u32 dto_cntl;
+ struct radeon_encoder *radeon_encoder;
+ struct radeon_encoder_atom_dig *dig;
- if (!dig || !dig->afmt)
+ if (!crtc)
return;
- if (max_ratio >= 8) {
- dto_phase = 192 * 1000;
- wallclock_ratio = 3;
- } else if (max_ratio >= 4) {
- dto_phase = 96 * 1000;
- wallclock_ratio = 2;
- } else if (max_ratio >= 2) {
- dto_phase = 48 * 1000;
- wallclock_ratio = 1;
- } else {
- dto_phase = 24 * 1000;
- wallclock_ratio = 0;
- }
+ radeon_encoder = to_radeon_encoder(crtc->encoder);
+ dig = radeon_encoder->enc_priv;
- /* there are two DTOs selected by DCCG_AUDIO_DTO_SELECT.
- * doesn't matter which one you use. Just use the first one.
- */
- /* XXX two dtos; generally use dto0 for hdmi */
- /* Express [24MHz / target pixel clock] as an exact rational
- * number (coefficient of two integer numbers. DCCG_AUDIO_DTOx_PHASE
- * is the numerator, DCCG_AUDIO_DTOx_MODULE is the denominator
- */
- if (ASIC_IS_DCE32(rdev)) {
- if (dig->dig_encoder == 0) {
- dto_cntl = RREG32(DCCG_AUDIO_DTO0_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
- dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
- WREG32(DCCG_AUDIO_DTO0_CNTL, dto_cntl);
- WREG32(DCCG_AUDIO_DTO0_PHASE, dto_phase);
- WREG32(DCCG_AUDIO_DTO0_MODULE, dto_modulo);
- WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
- } else {
- dto_cntl = RREG32(DCCG_AUDIO_DTO1_CNTL) & ~DCCG_AUDIO_DTO_WALLCLOCK_RATIO_MASK;
- dto_cntl |= DCCG_AUDIO_DTO_WALLCLOCK_RATIO(wallclock_ratio);
- WREG32(DCCG_AUDIO_DTO1_CNTL, dto_cntl);
- WREG32(DCCG_AUDIO_DTO1_PHASE, dto_phase);
- WREG32(DCCG_AUDIO_DTO1_MODULE, dto_modulo);
- WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
- }
+ if (!dig)
+ return;
+
+ if (dig->dig_encoder == 0) {
+ WREG32(DCCG_AUDIO_DTO0_PHASE, 24000 * 100);
+ WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
+ WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
} else {
- /* according to the reg specs, this should DCE3.2 only, but in
- * practice it seems to cover DCE2.0/3.0/3.1 as well.
- */
- if (dig->dig_encoder == 0) {
- WREG32(DCCG_AUDIO_DTO0_PHASE, base_rate * 100);
- WREG32(DCCG_AUDIO_DTO0_MODULE, clock * 100);
- WREG32(DCCG_AUDIO_DTO_SELECT, 0); /* select DTO0 */
- } else {
- WREG32(DCCG_AUDIO_DTO1_PHASE, base_rate * 100);
- WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
- WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
- }
+ WREG32(DCCG_AUDIO_DTO1_PHASE, 24000 * 100);
+ WREG32(DCCG_AUDIO_DTO1_MODULE, clock * 100);
+ WREG32(DCCG_AUDIO_DTO_SELECT, 1); /* select DTO1 */
}
}
-/*
- * update the info frames with the data from the current display mode
- */
-void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode)
+void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset)
{
struct drm_device *dev = encoder->dev;
struct radeon_device *rdev = dev->dev_private;
- struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
- struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
- u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
- struct hdmi_avi_infoframe frame;
- uint32_t offset;
- uint32_t acr_ctl;
- ssize_t err;
-
- if (!dig || !dig->afmt)
- return;
-
- /* Silent, r600_hdmi_enable will raise WARN for us */
- if (!dig->afmt->enabled)
- return;
- offset = dig->afmt->offset;
- /* disable audio prior to setting up hw */
- dig->afmt->pin = r600_audio_get_pin(rdev);
- r600_audio_enable(rdev, dig->afmt->pin, 0xf);
+ WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
+ HDMI0_NULL_SEND | /* send null packets when required */
+ HDMI0_GC_SEND | /* send general control packets */
+ HDMI0_GC_CONT); /* send general control packets every frame */
+}
- r600_audio_set_dto(encoder, mode->clock);
+void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
WREG32_P(HDMI0_AUDIO_PACKET_CONTROL + offset,
- HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
- HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
- HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
- HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
- ~(HDMI0_AUDIO_SAMPLE_SEND |
- HDMI0_AUDIO_DELAY_EN_MASK |
- HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
- HDMI0_60958_CS_UPDATE));
-
- /* DCE 3.0 uses register that's normally for CRC_CONTROL */
- acr_ctl = ASIC_IS_DCE3(rdev) ? DCE3_HDMI0_ACR_PACKET_CONTROL :
- HDMI0_ACR_PACKET_CONTROL;
- WREG32_P(acr_ctl + offset,
- HDMI0_ACR_SOURCE | /* select SW CTS value - XXX verify that hw CTS works on all families */
- HDMI0_ACR_AUTO_SEND, /* allow hw to sent ACR packets when required */
- ~(HDMI0_ACR_SOURCE |
- HDMI0_ACR_AUTO_SEND));
-
- WREG32_OR(HDMI0_VBI_PACKET_CONTROL + offset,
- HDMI0_NULL_SEND | /* send null packets when required */
- HDMI0_GC_SEND | /* send general control packets */
- HDMI0_GC_CONT); /* send general control packets every frame */
+ HDMI0_AUDIO_SAMPLE_SEND | /* send audio packets */
+ HDMI0_AUDIO_DELAY_EN(1) | /* default audio delay */
+ HDMI0_AUDIO_PACKETS_PER_LINE(3) | /* should be suffient for all audio modes and small enough for all hblanks */
+ HDMI0_60958_CS_UPDATE, /* allow 60958 channel status fields to be updated */
+ ~(HDMI0_AUDIO_SAMPLE_SEND |
+ HDMI0_AUDIO_DELAY_EN_MASK |
+ HDMI0_AUDIO_PACKETS_PER_LINE_MASK |
+ HDMI0_60958_CS_UPDATE));
WREG32_OR(HDMI0_INFOFRAME_CONTROL0 + offset,
- HDMI0_AVI_INFO_SEND | /* enable AVI info frames */
- HDMI0_AVI_INFO_CONT | /* send AVI info frames every frame/field */
- HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
- HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
+ HDMI0_AUDIO_INFO_SEND | /* enable audio info frames (frames won't be set until audio is enabled) */
+ HDMI0_AUDIO_INFO_UPDATE); /* required for audio info values to be updated */
WREG32_P(HDMI0_INFOFRAME_CONTROL1 + offset,
- HDMI0_AVI_INFO_LINE(2) | /* anything other than 0 */
- HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
- ~(HDMI0_AVI_INFO_LINE_MASK |
- HDMI0_AUDIO_INFO_LINE_MASK));
-
- WREG32_AND(HDMI0_GC + offset,
- ~HDMI0_GC_AVMUTE); /* unset HDMI0_GC_AVMUTE */
-
- err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
- if (err < 0) {
- DRM_ERROR("failed to setup AVI infoframe: %zd\n", err);
- return;
- }
-
- err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
- if (err < 0) {
- DRM_ERROR("failed to pack AVI infoframe: %zd\n", err);
- return;
- }
-
- r600_hdmi_update_avi_infoframe(encoder, buffer, sizeof(buffer));
-
- /* fglrx duplicates INFOFRAME_CONTROL0 & INFOFRAME_CONTROL1 ops here */
+ HDMI0_AUDIO_INFO_LINE(2), /* anything other than 0 */
+ ~HDMI0_AUDIO_INFO_LINE_MASK);
WREG32_AND(HDMI0_GENERIC_PACKET_CONTROL + offset,
- ~(HDMI0_GENERIC0_SEND |
- HDMI0_GENERIC0_CONT |
- HDMI0_GENERIC0_UPDATE |
- HDMI0_GENERIC1_SEND |
- HDMI0_GENERIC1_CONT |
- HDMI0_GENERIC0_LINE_MASK |
- HDMI0_GENERIC1_LINE_MASK));
-
- r600_hdmi_update_ACR(encoder, mode->clock);
+ ~(HDMI0_GENERIC0_SEND |
+ HDMI0_GENERIC0_CONT |
+ HDMI0_GENERIC0_UPDATE |
+ HDMI0_GENERIC1_SEND |
+ HDMI0_GENERIC1_CONT |
+ HDMI0_GENERIC0_LINE_MASK |
+ HDMI0_GENERIC1_LINE_MASK));
WREG32_P(HDMI0_60958_0 + offset,
- HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
- ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
- HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
+ HDMI0_60958_CS_CHANNEL_NUMBER_L(1),
+ ~(HDMI0_60958_CS_CHANNEL_NUMBER_L_MASK |
+ HDMI0_60958_CS_CLOCK_ACCURACY_MASK));
WREG32_P(HDMI0_60958_1 + offset,
- HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
- ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
+ HDMI0_60958_CS_CHANNEL_NUMBER_R(2),
+ ~HDMI0_60958_CS_CHANNEL_NUMBER_R_MASK);
+}
- /* it's unknown what these bits do excatly, but it's indeed quite useful for debugging */
- WREG32(HDMI0_RAMP_CONTROL0 + offset, 0x00FFFFFF);
- WREG32(HDMI0_RAMP_CONTROL1 + offset, 0x007FFFFF);
- WREG32(HDMI0_RAMP_CONTROL2 + offset, 0x00000001);
- WREG32(HDMI0_RAMP_CONTROL3 + offset, 0x00000001);
+void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
- /* enable audio after to setting up hw */
- r600_audio_enable(rdev, dig->afmt->pin, 0xf);
+ if (mute)
+ WREG32_OR(HDMI0_GC + offset, HDMI0_GC_AVMUTE);
+ else
+ WREG32_AND(HDMI0_GC + offset, ~HDMI0_GC_AVMUTE);
}
/**
@@ -692,7 +483,7 @@ void r600_hdmi_enable(struct drm_encoder *encoder, bool enable)
return;
if (!enable && dig->afmt->pin) {
- r600_audio_enable(rdev, dig->afmt->pin, 0);
+ radeon_audio_enable(rdev, dig->afmt->pin, 0);
dig->afmt->pin = NULL;
}
diff --git a/drivers/gpu/drm/radeon/radeon.h b/drivers/gpu/drm/radeon/radeon.h
index 3f2a8d3febca..5587603b4a89 100644
--- a/drivers/gpu/drm/radeon/radeon.h
+++ b/drivers/gpu/drm/radeon/radeon.h
@@ -1758,6 +1758,9 @@ struct r600_audio {
bool enabled;
struct r600_audio_pin pin[RADEON_MAX_AFMT_BLOCKS];
int num_pins;
+ struct radeon_audio_funcs *hdmi_funcs;
+ struct radeon_audio_funcs *dp_funcs;
+ struct radeon_audio_basic_funcs *funcs;
};
/*
@@ -1778,8 +1781,16 @@ void radeon_test_syncing(struct radeon_device *rdev);
/*
* MMU Notifier
*/
+#if defined(CONFIG_MMU_NOTIFIER)
int radeon_mn_register(struct radeon_bo *bo, unsigned long addr);
void radeon_mn_unregister(struct radeon_bo *bo);
+#else
+static inline int radeon_mn_register(struct radeon_bo *bo, unsigned long addr)
+{
+ return -ENODEV;
+}
+static inline void radeon_mn_unregister(struct radeon_bo *bo) {}
+#endif
/*
* Debugfs
@@ -1969,6 +1980,10 @@ struct radeon_asic {
bool (*vblank_too_short)(struct radeon_device *rdev);
void (*powergate_uvd)(struct radeon_device *rdev, bool gate);
void (*enable_bapm)(struct radeon_device *rdev, bool enable);
+ void (*fan_ctrl_set_mode)(struct radeon_device *rdev, u32 mode);
+ u32 (*fan_ctrl_get_mode)(struct radeon_device *rdev);
+ int (*set_fan_speed_percent)(struct radeon_device *rdev, u32 speed);
+ int (*get_fan_speed_percent)(struct radeon_device *rdev, u32 *speed);
} dpm;
/* pageflipping */
struct {
diff --git a/drivers/gpu/drm/radeon/radeon_asic.c b/drivers/gpu/drm/radeon/radeon_asic.c
index ed0e10eee2dc..c0ecd128b14b 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.c
+++ b/drivers/gpu/drm/radeon/radeon_asic.c
@@ -647,8 +647,6 @@ static struct radeon_asic rs600_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &r600_hdmi_enable,
- .hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r100_copy_blit,
@@ -716,8 +714,6 @@ static struct radeon_asic rs690_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &r600_hdmi_enable,
- .hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r100_copy_blit,
@@ -948,8 +944,6 @@ static struct radeon_asic r600_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &r600_hdmi_enable,
- .hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1035,8 +1029,6 @@ static struct radeon_asic rv6xx_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &r600_hdmi_enable,
- .hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1127,8 +1119,6 @@ static struct radeon_asic rs780_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &r600_hdmi_enable,
- .hdmi_setmode = &r600_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1232,8 +1222,6 @@ static struct radeon_asic rv770_asic = {
.wait_for_vblank = &avivo_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &r600_hdmi_enable,
- .hdmi_setmode = &dce3_1_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1351,8 +1339,6 @@ static struct radeon_asic evergreen_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1444,8 +1430,6 @@ static struct radeon_asic sumo_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1536,8 +1520,6 @@ static struct radeon_asic btc_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1683,8 +1665,6 @@ static struct radeon_asic cayman_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1787,8 +1767,6 @@ static struct radeon_asic trinity_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1921,8 +1899,6 @@ static struct radeon_asic si_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &r600_copy_cpdma,
@@ -1975,6 +1951,10 @@ static struct radeon_asic si_asic = {
.debugfs_print_current_performance_level = &si_dpm_debugfs_print_current_performance_level,
.force_performance_level = &si_dpm_force_performance_level,
.vblank_too_short = &ni_dpm_vblank_too_short,
+ .fan_ctrl_set_mode = &si_fan_ctrl_set_mode,
+ .fan_ctrl_get_mode = &si_fan_ctrl_get_mode,
+ .get_fan_speed_percent = &si_fan_ctrl_get_fan_speed_percent,
+ .set_fan_speed_percent = &si_fan_ctrl_set_fan_speed_percent,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@@ -2085,8 +2065,6 @@ static struct radeon_asic ci_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &cik_copy_cpdma,
@@ -2141,6 +2119,10 @@ static struct radeon_asic ci_asic = {
.force_performance_level = &ci_dpm_force_performance_level,
.vblank_too_short = &ci_dpm_vblank_too_short,
.powergate_uvd = &ci_dpm_powergate_uvd,
+ .fan_ctrl_set_mode = &ci_fan_ctrl_set_mode,
+ .fan_ctrl_get_mode = &ci_fan_ctrl_get_mode,
+ .get_fan_speed_percent = &ci_fan_ctrl_get_fan_speed_percent,
+ .set_fan_speed_percent = &ci_fan_ctrl_set_fan_speed_percent,
},
.pflip = {
.page_flip = &evergreen_page_flip,
@@ -2193,8 +2175,6 @@ static struct radeon_asic kv_asic = {
.wait_for_vblank = &dce4_wait_for_vblank,
.set_backlight_level = &atombios_set_backlight_level,
.get_backlight_level = &atombios_get_backlight_level,
- .hdmi_enable = &evergreen_hdmi_enable,
- .hdmi_setmode = &evergreen_hdmi_setmode,
},
.copy = {
.blit = &cik_copy_cpdma,
diff --git a/drivers/gpu/drm/radeon/radeon_asic.h b/drivers/gpu/drm/radeon/radeon_asic.h
index 8d787d115653..72bdd3bf0d8e 100644
--- a/drivers/gpu/drm/radeon/radeon_asic.h
+++ b/drivers/gpu/drm/radeon/radeon_asic.h
@@ -394,7 +394,6 @@ void r600_irq_suspend(struct radeon_device *rdev);
void r600_disable_interrupts(struct radeon_device *rdev);
void r600_rlc_stop(struct radeon_device *rdev);
/* r600 audio */
-int r600_audio_init(struct radeon_device *rdev);
void r600_audio_fini(struct radeon_device *rdev);
void r600_audio_set_dto(struct drm_encoder *encoder, u32 clock);
void r600_hdmi_update_avi_infoframe(struct drm_encoder *encoder, void *buffer,
@@ -403,8 +402,6 @@ void r600_hdmi_update_ACR(struct drm_encoder *encoder, uint32_t clock);
void r600_hdmi_audio_workaround(struct drm_encoder *encoder);
int r600_hdmi_buffer_status_changed(struct drm_encoder *encoder);
void r600_hdmi_update_audio_settings(struct drm_encoder *encoder);
-void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
-void r600_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
int r600_mc_wait_for_idle(struct radeon_device *rdev);
u32 r600_get_xclk(struct radeon_device *rdev);
uint64_t r600_get_gpu_clock_counter(struct radeon_device *rdev);
@@ -473,8 +470,6 @@ struct radeon_fence *rv770_copy_dma(struct radeon_device *rdev,
u32 rv770_get_xclk(struct radeon_device *rdev);
int rv770_set_uvd_clocks(struct radeon_device *rdev, u32 vclk, u32 dclk);
int rv770_get_temp(struct radeon_device *rdev);
-/* hdmi */
-void dce3_1_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
/* rv7xx pm */
int rv770_dpm_init(struct radeon_device *rdev);
int rv770_dpm_enable(struct radeon_device *rdev);
@@ -544,8 +539,6 @@ struct radeon_fence *evergreen_copy_dma(struct radeon_device *rdev,
uint64_t src_offset, uint64_t dst_offset,
unsigned num_gpu_pages,
struct reservation_object *resv);
-void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
-void evergreen_hdmi_setmode(struct drm_encoder *encoder, struct drm_display_mode *mode);
int evergreen_get_temp(struct radeon_device *rdev);
int sumo_get_temp(struct radeon_device *rdev);
int tn_get_temp(struct radeon_device *rdev);
@@ -684,7 +677,6 @@ void trinity_dpm_enable_bapm(struct radeon_device *rdev, bool enable);
/* DCE6 - SI */
void dce6_bandwidth_update(struct radeon_device *rdev);
-int dce6_audio_init(struct radeon_device *rdev);
void dce6_audio_fini(struct radeon_device *rdev);
/*
@@ -748,6 +740,12 @@ void si_dpm_debugfs_print_current_performance_level(struct radeon_device *rdev,
struct seq_file *m);
int si_dpm_force_performance_level(struct radeon_device *rdev,
enum radeon_dpm_forced_level level);
+int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+ u32 *speed);
+int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+ u32 speed);
+u32 si_fan_ctrl_get_mode(struct radeon_device *rdev);
+void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
/* DCE8 - CIK */
void dce8_bandwidth_update(struct radeon_device *rdev);
@@ -865,6 +863,13 @@ int ci_dpm_force_performance_level(struct radeon_device *rdev,
bool ci_dpm_vblank_too_short(struct radeon_device *rdev);
void ci_dpm_powergate_uvd(struct radeon_device *rdev, bool gate);
+int ci_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+ u32 *speed);
+int ci_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+ u32 speed);
+u32 ci_fan_ctrl_get_mode(struct radeon_device *rdev);
+void ci_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode);
+
int kv_dpm_init(struct radeon_device *rdev);
int kv_dpm_enable(struct radeon_device *rdev);
int kv_dpm_late_enable(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_atombios.c b/drivers/gpu/drm/radeon/radeon_atombios.c
index dbc94f300297..fc1b3f34cf18 100644
--- a/drivers/gpu/drm/radeon/radeon_atombios.c
+++ b/drivers/gpu/drm/radeon/radeon_atombios.c
@@ -3289,6 +3289,7 @@ int radeon_atom_get_voltage_evv(struct radeon_device *rdev,
args.in.ucVoltageType = VOLTAGE_TYPE_VDDC;
args.in.ucVoltageMode = ATOM_GET_VOLTAGE_EVV_VOLTAGE;
+ args.in.usVoltageLevel = cpu_to_le16(virtual_voltage_id);
args.in.ulSCLKFreq =
cpu_to_le32(rdev->pm.dpm.dyn_state.vddc_dependency_on_sclk.entries[entry_id].clk);
diff --git a/drivers/gpu/drm/radeon/radeon_audio.c b/drivers/gpu/drm/radeon/radeon_audio.c
new file mode 100644
index 000000000000..a3ceef6d9632
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_audio.c
@@ -0,0 +1,766 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Slava Grigorev <slava.grigorev@amd.com>
+ */
+
+#include <linux/gcd.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc.h>
+#include "radeon.h"
+#include "atom.h"
+#include "radeon_audio.h"
+
+void r600_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
+ u8 enable_mask);
+void dce4_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
+ u8 enable_mask);
+void dce6_audio_enable(struct radeon_device *rdev, struct r600_audio_pin *pin,
+ u8 enable_mask);
+u32 dce6_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg);
+void dce6_endpoint_wreg(struct radeon_device *rdev,
+ u32 offset, u32 reg, u32 v);
+void dce3_2_afmt_write_sad_regs(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count);
+void evergreen_hdmi_write_sad_regs(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count);
+void dce6_afmt_write_sad_regs(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count);
+void dce3_2_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+void dce3_2_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+void dce4_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+void dce4_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+void dce6_afmt_hdmi_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+void dce6_afmt_dp_write_speaker_allocation(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+void dce4_afmt_write_latency_fields(struct drm_encoder *encoder,
+ struct drm_connector *connector, struct drm_display_mode *mode);
+void dce6_afmt_write_latency_fields(struct drm_encoder *encoder,
+ struct drm_connector *connector, struct drm_display_mode *mode);
+struct r600_audio_pin* r600_audio_get_pin(struct radeon_device *rdev);
+struct r600_audio_pin* dce6_audio_get_pin(struct radeon_device *rdev);
+void dce6_afmt_select_pin(struct drm_encoder *encoder);
+void r600_hdmi_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+void dce3_2_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+void dce4_hdmi_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+void dce4_dp_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+void dce6_hdmi_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+void dce6_dp_audio_set_dto(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+void r600_set_avi_packet(struct radeon_device *rdev, u32 offset,
+ unsigned char *buffer, size_t size);
+void evergreen_set_avi_packet(struct radeon_device *rdev, u32 offset,
+ unsigned char *buffer, size_t size);
+void r600_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr);
+void dce3_2_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr);
+void evergreen_hdmi_update_acr(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr);
+void r600_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
+void dce4_set_vbi_packet(struct drm_encoder *encoder, u32 offset);
+void dce4_hdmi_set_color_depth(struct drm_encoder *encoder,
+ u32 offset, int bpc);
+void r600_set_audio_packet(struct drm_encoder *encoder, u32 offset);
+void dce3_2_set_audio_packet(struct drm_encoder *encoder, u32 offset);
+void dce4_set_audio_packet(struct drm_encoder *encoder, u32 offset);
+void r600_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
+void dce3_2_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
+void dce4_set_mute(struct drm_encoder *encoder, u32 offset, bool mute);
+static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode);
+static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode);
+void r600_hdmi_enable(struct drm_encoder *encoder, bool enable);
+void evergreen_hdmi_enable(struct drm_encoder *encoder, bool enable);
+void evergreen_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
+void dce6_enable_dp_audio_packets(struct drm_encoder *encoder, bool enable);
+
+static const u32 pin_offsets[7] =
+{
+ (0x5e00 - 0x5e00),
+ (0x5e18 - 0x5e00),
+ (0x5e30 - 0x5e00),
+ (0x5e48 - 0x5e00),
+ (0x5e60 - 0x5e00),
+ (0x5e78 - 0x5e00),
+ (0x5e90 - 0x5e00),
+};
+
+static u32 radeon_audio_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
+{
+ return RREG32(reg);
+}
+
+static void radeon_audio_wreg(struct radeon_device *rdev, u32 offset,
+ u32 reg, u32 v)
+{
+ WREG32(reg, v);
+}
+
+static struct radeon_audio_basic_funcs r600_funcs = {
+ .endpoint_rreg = radeon_audio_rreg,
+ .endpoint_wreg = radeon_audio_wreg,
+ .enable = r600_audio_enable,
+};
+
+static struct radeon_audio_basic_funcs dce32_funcs = {
+ .endpoint_rreg = radeon_audio_rreg,
+ .endpoint_wreg = radeon_audio_wreg,
+ .enable = r600_audio_enable,
+};
+
+static struct radeon_audio_basic_funcs dce4_funcs = {
+ .endpoint_rreg = radeon_audio_rreg,
+ .endpoint_wreg = radeon_audio_wreg,
+ .enable = dce4_audio_enable,
+};
+
+static struct radeon_audio_basic_funcs dce6_funcs = {
+ .endpoint_rreg = dce6_endpoint_rreg,
+ .endpoint_wreg = dce6_endpoint_wreg,
+ .enable = dce6_audio_enable,
+};
+
+static struct radeon_audio_funcs r600_hdmi_funcs = {
+ .get_pin = r600_audio_get_pin,
+ .set_dto = r600_hdmi_audio_set_dto,
+ .update_acr = r600_hdmi_update_acr,
+ .set_vbi_packet = r600_set_vbi_packet,
+ .set_avi_packet = r600_set_avi_packet,
+ .set_audio_packet = r600_set_audio_packet,
+ .set_mute = r600_set_mute,
+ .mode_set = radeon_audio_hdmi_mode_set,
+ .dpms = r600_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce32_hdmi_funcs = {
+ .get_pin = r600_audio_get_pin,
+ .write_sad_regs = dce3_2_afmt_write_sad_regs,
+ .write_speaker_allocation = dce3_2_afmt_hdmi_write_speaker_allocation,
+ .set_dto = dce3_2_audio_set_dto,
+ .update_acr = dce3_2_hdmi_update_acr,
+ .set_vbi_packet = r600_set_vbi_packet,
+ .set_avi_packet = r600_set_avi_packet,
+ .set_audio_packet = dce3_2_set_audio_packet,
+ .set_mute = dce3_2_set_mute,
+ .mode_set = radeon_audio_hdmi_mode_set,
+ .dpms = r600_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce32_dp_funcs = {
+ .get_pin = r600_audio_get_pin,
+ .write_sad_regs = dce3_2_afmt_write_sad_regs,
+ .write_speaker_allocation = dce3_2_afmt_dp_write_speaker_allocation,
+ .set_dto = dce3_2_audio_set_dto,
+ .set_avi_packet = r600_set_avi_packet,
+ .set_audio_packet = dce3_2_set_audio_packet,
+};
+
+static struct radeon_audio_funcs dce4_hdmi_funcs = {
+ .get_pin = r600_audio_get_pin,
+ .write_sad_regs = evergreen_hdmi_write_sad_regs,
+ .write_speaker_allocation = dce4_afmt_hdmi_write_speaker_allocation,
+ .write_latency_fields = dce4_afmt_write_latency_fields,
+ .set_dto = dce4_hdmi_audio_set_dto,
+ .update_acr = evergreen_hdmi_update_acr,
+ .set_vbi_packet = dce4_set_vbi_packet,
+ .set_color_depth = dce4_hdmi_set_color_depth,
+ .set_avi_packet = evergreen_set_avi_packet,
+ .set_audio_packet = dce4_set_audio_packet,
+ .set_mute = dce4_set_mute,
+ .mode_set = radeon_audio_hdmi_mode_set,
+ .dpms = evergreen_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce4_dp_funcs = {
+ .get_pin = r600_audio_get_pin,
+ .write_sad_regs = evergreen_hdmi_write_sad_regs,
+ .write_speaker_allocation = dce4_afmt_dp_write_speaker_allocation,
+ .write_latency_fields = dce4_afmt_write_latency_fields,
+ .set_dto = dce4_dp_audio_set_dto,
+ .set_avi_packet = evergreen_set_avi_packet,
+ .set_audio_packet = dce4_set_audio_packet,
+ .mode_set = radeon_audio_dp_mode_set,
+ .dpms = evergreen_enable_dp_audio_packets,
+};
+
+static struct radeon_audio_funcs dce6_hdmi_funcs = {
+ .select_pin = dce6_afmt_select_pin,
+ .get_pin = dce6_audio_get_pin,
+ .write_sad_regs = dce6_afmt_write_sad_regs,
+ .write_speaker_allocation = dce6_afmt_hdmi_write_speaker_allocation,
+ .write_latency_fields = dce6_afmt_write_latency_fields,
+ .set_dto = dce6_hdmi_audio_set_dto,
+ .update_acr = evergreen_hdmi_update_acr,
+ .set_vbi_packet = dce4_set_vbi_packet,
+ .set_color_depth = dce4_hdmi_set_color_depth,
+ .set_avi_packet = evergreen_set_avi_packet,
+ .set_audio_packet = dce4_set_audio_packet,
+ .set_mute = dce4_set_mute,
+ .mode_set = radeon_audio_hdmi_mode_set,
+ .dpms = evergreen_hdmi_enable,
+};
+
+static struct radeon_audio_funcs dce6_dp_funcs = {
+ .select_pin = dce6_afmt_select_pin,
+ .get_pin = dce6_audio_get_pin,
+ .write_sad_regs = dce6_afmt_write_sad_regs,
+ .write_speaker_allocation = dce6_afmt_dp_write_speaker_allocation,
+ .write_latency_fields = dce6_afmt_write_latency_fields,
+ .set_dto = dce6_dp_audio_set_dto,
+ .set_avi_packet = evergreen_set_avi_packet,
+ .set_audio_packet = dce4_set_audio_packet,
+ .mode_set = radeon_audio_dp_mode_set,
+ .dpms = dce6_enable_dp_audio_packets,
+};
+
+static void radeon_audio_interface_init(struct radeon_device *rdev)
+{
+ if (ASIC_IS_DCE6(rdev)) {
+ rdev->audio.funcs = &dce6_funcs;
+ rdev->audio.hdmi_funcs = &dce6_hdmi_funcs;
+ rdev->audio.dp_funcs = &dce6_dp_funcs;
+ } else if (ASIC_IS_DCE4(rdev)) {
+ rdev->audio.funcs = &dce4_funcs;
+ rdev->audio.hdmi_funcs = &dce4_hdmi_funcs;
+ rdev->audio.dp_funcs = &dce4_dp_funcs;
+ } else if (ASIC_IS_DCE32(rdev)) {
+ rdev->audio.funcs = &dce32_funcs;
+ rdev->audio.hdmi_funcs = &dce32_hdmi_funcs;
+ rdev->audio.dp_funcs = &dce32_dp_funcs;
+ } else {
+ rdev->audio.funcs = &r600_funcs;
+ rdev->audio.hdmi_funcs = &r600_hdmi_funcs;
+ rdev->audio.dp_funcs = 0;
+ }
+}
+
+static int radeon_audio_chipset_supported(struct radeon_device *rdev)
+{
+ return ASIC_IS_DCE2(rdev) && !ASIC_IS_NODCE(rdev);
+}
+
+int radeon_audio_init(struct radeon_device *rdev)
+{
+ int i;
+
+ if (!radeon_audio || !radeon_audio_chipset_supported(rdev))
+ return 0;
+
+ rdev->audio.enabled = true;
+
+ if (ASIC_IS_DCE83(rdev)) /* KB: 2 streams, 3 endpoints */
+ rdev->audio.num_pins = 3;
+ else if (ASIC_IS_DCE81(rdev)) /* KV: 4 streams, 7 endpoints */
+ rdev->audio.num_pins = 7;
+ else if (ASIC_IS_DCE8(rdev)) /* BN/HW: 6 streams, 7 endpoints */
+ rdev->audio.num_pins = 7;
+ else if (ASIC_IS_DCE64(rdev)) /* OL: 2 streams, 2 endpoints */
+ rdev->audio.num_pins = 2;
+ else if (ASIC_IS_DCE61(rdev)) /* TN: 4 streams, 6 endpoints */
+ rdev->audio.num_pins = 6;
+ else if (ASIC_IS_DCE6(rdev)) /* SI: 6 streams, 6 endpoints */
+ rdev->audio.num_pins = 6;
+ else
+ rdev->audio.num_pins = 1;
+
+ for (i = 0; i < rdev->audio.num_pins; i++) {
+ rdev->audio.pin[i].channels = -1;
+ rdev->audio.pin[i].rate = -1;
+ rdev->audio.pin[i].bits_per_sample = -1;
+ rdev->audio.pin[i].status_bits = 0;
+ rdev->audio.pin[i].category_code = 0;
+ rdev->audio.pin[i].connected = false;
+ rdev->audio.pin[i].offset = pin_offsets[i];
+ rdev->audio.pin[i].id = i;
+ }
+
+ radeon_audio_interface_init(rdev);
+
+ /* disable audio. it will be set up later */
+ for (i = 0; i < rdev->audio.num_pins; i++)
+ radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
+
+ return 0;
+}
+
+u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev, u32 offset, u32 reg)
+{
+ if (rdev->audio.funcs->endpoint_rreg)
+ return rdev->audio.funcs->endpoint_rreg(rdev, offset, reg);
+
+ return 0;
+}
+
+void radeon_audio_endpoint_wreg(struct radeon_device *rdev, u32 offset,
+ u32 reg, u32 v)
+{
+ if (rdev->audio.funcs->endpoint_wreg)
+ rdev->audio.funcs->endpoint_wreg(rdev, offset, reg, v);
+}
+
+static void radeon_audio_write_sad_regs(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder;
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector = NULL;
+ struct cea_sad *sads;
+ int sad_count;
+
+ list_for_each_entry(connector,
+ &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ radeon_connector = to_radeon_connector(connector);
+ break;
+ }
+ }
+
+ if (!radeon_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ sad_count = drm_edid_to_sad(radeon_connector_edid(connector), &sads);
+ if (sad_count <= 0) {
+ DRM_ERROR("Couldn't read SADs: %d\n", sad_count);
+ return;
+ }
+ BUG_ON(!sads);
+
+ radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->write_sad_regs)
+ radeon_encoder->audio->write_sad_regs(encoder, sads, sad_count);
+
+ kfree(sads);
+}
+
+static void radeon_audio_write_speaker_allocation(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector = NULL;
+ u8 *sadb = NULL;
+ int sad_count;
+
+ list_for_each_entry(connector,
+ &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ radeon_connector = to_radeon_connector(connector);
+ break;
+ }
+ }
+
+ if (!radeon_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ sad_count = drm_edid_to_speaker_allocation(
+ radeon_connector_edid(connector), &sadb);
+ if (sad_count < 0) {
+ DRM_DEBUG("Couldn't read Speaker Allocation Data Block: %d\n",
+ sad_count);
+ sad_count = 0;
+ }
+
+ if (radeon_encoder->audio && radeon_encoder->audio->write_speaker_allocation)
+ radeon_encoder->audio->write_speaker_allocation(encoder, sadb, sad_count);
+
+ kfree(sadb);
+}
+
+static void radeon_audio_write_latency_fields(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct radeon_encoder *radeon_encoder;
+ struct drm_connector *connector;
+ struct radeon_connector *radeon_connector = 0;
+
+ list_for_each_entry(connector,
+ &encoder->dev->mode_config.connector_list, head) {
+ if (connector->encoder == encoder) {
+ radeon_connector = to_radeon_connector(connector);
+ break;
+ }
+ }
+
+ if (!radeon_connector) {
+ DRM_ERROR("Couldn't find encoder's connector\n");
+ return;
+ }
+
+ radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->write_latency_fields)
+ radeon_encoder->audio->write_latency_fields(encoder, connector, mode);
+}
+
+struct r600_audio_pin* radeon_audio_get_pin(struct drm_encoder *encoder)
+{
+ struct radeon_device *rdev = encoder->dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->get_pin)
+ return radeon_encoder->audio->get_pin(rdev);
+
+ return NULL;
+}
+
+static void radeon_audio_select_pin(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->select_pin)
+ radeon_encoder->audio->select_pin(encoder);
+}
+
+void radeon_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin, u8 enable_mask)
+{
+ if (rdev->audio.funcs->enable)
+ rdev->audio.funcs->enable(rdev, pin, enable_mask);
+}
+
+void radeon_audio_detect(struct drm_connector *connector,
+ enum drm_connector_status status)
+{
+ struct radeon_device *rdev;
+ struct radeon_encoder *radeon_encoder;
+ struct radeon_encoder_atom_dig *dig;
+
+ if (!connector || !connector->encoder)
+ return;
+
+ rdev = connector->encoder->dev->dev_private;
+ radeon_encoder = to_radeon_encoder(connector->encoder);
+ dig = radeon_encoder->enc_priv;
+
+ if (status == connector_status_connected) {
+ struct radeon_connector *radeon_connector;
+ int sink_type;
+
+ if (!drm_detect_monitor_audio(radeon_connector_edid(connector))) {
+ radeon_encoder->audio = NULL;
+ return;
+ }
+
+ radeon_connector = to_radeon_connector(connector);
+ sink_type = radeon_dp_getsinktype(radeon_connector);
+
+ if (connector->connector_type == DRM_MODE_CONNECTOR_DisplayPort &&
+ sink_type == CONNECTOR_OBJECT_ID_DISPLAYPORT)
+ radeon_encoder->audio = rdev->audio.dp_funcs;
+ else
+ radeon_encoder->audio = rdev->audio.hdmi_funcs;
+
+ radeon_audio_write_speaker_allocation(connector->encoder);
+ radeon_audio_write_sad_regs(connector->encoder);
+ if (connector->encoder->crtc)
+ radeon_audio_write_latency_fields(connector->encoder,
+ &connector->encoder->crtc->mode);
+ radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+ } else {
+ radeon_audio_enable(rdev, dig->afmt->pin, 0);
+ }
+}
+
+void radeon_audio_fini(struct radeon_device *rdev)
+{
+ int i;
+
+ if (!rdev->audio.enabled)
+ return;
+
+ for (i = 0; i < rdev->audio.num_pins; i++)
+ radeon_audio_enable(rdev, &rdev->audio.pin[i], false);
+
+ rdev->audio.enabled = false;
+}
+
+static void radeon_audio_set_dto(struct drm_encoder *encoder, unsigned int clock)
+{
+ struct radeon_device *rdev = encoder->dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_crtc *crtc = to_radeon_crtc(encoder->crtc);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->set_dto)
+ radeon_encoder->audio->set_dto(rdev, crtc, clock);
+}
+
+static int radeon_audio_set_avi_packet(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct radeon_device *rdev = encoder->dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+ u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+ struct hdmi_avi_infoframe frame;
+ int err;
+
+ err = drm_hdmi_avi_infoframe_from_display_mode(&frame, mode);
+ if (err < 0) {
+ DRM_ERROR("failed to setup AVI infoframe: %d\n", err);
+ return err;
+ }
+
+ err = hdmi_avi_infoframe_pack(&frame, buffer, sizeof(buffer));
+ if (err < 0) {
+ DRM_ERROR("failed to pack AVI infoframe: %d\n", err);
+ return err;
+ }
+
+ if (dig && dig->afmt &&
+ radeon_encoder->audio && radeon_encoder->audio->set_avi_packet)
+ radeon_encoder->audio->set_avi_packet(rdev, dig->afmt->offset,
+ buffer, sizeof(buffer));
+
+ return 0;
+}
+
+/*
+ * calculate CTS and N values if they are not found in the table
+ */
+static void radeon_audio_calc_cts(unsigned int clock, int *CTS, int *N, int freq)
+{
+ int n, cts;
+ unsigned long div, mul;
+
+ /* Safe, but overly large values */
+ n = 128 * freq;
+ cts = clock * 1000;
+
+ /* Smallest valid fraction */
+ div = gcd(n, cts);
+
+ n /= div;
+ cts /= div;
+
+ /*
+ * The optimal N is 128*freq/1000. Calculate the closest larger
+ * value that doesn't truncate any bits.
+ */
+ mul = ((128*freq/1000) + (n-1))/n;
+
+ n *= mul;
+ cts *= mul;
+
+ /* Check that we are in spec (not always possible) */
+ if (n < (128*freq/1500))
+ printk(KERN_WARNING "Calculated ACR N value is too small. You may experience audio problems.\n");
+ if (n > (128*freq/300))
+ printk(KERN_WARNING "Calculated ACR N value is too large. You may experience audio problems.\n");
+
+ *N = n;
+ *CTS = cts;
+
+ DRM_DEBUG("Calculated ACR timing N=%d CTS=%d for frequency %d\n",
+ *N, *CTS, freq);
+}
+
+static const struct radeon_hdmi_acr* radeon_audio_acr(unsigned int clock)
+{
+ static struct radeon_hdmi_acr res;
+ u8 i;
+
+ static const struct radeon_hdmi_acr hdmi_predefined_acr[] = {
+ /* 32kHz 44.1kHz 48kHz */
+ /* Clock N CTS N CTS N CTS */
+ { 25175, 4096, 25175, 28224, 125875, 6144, 25175 }, /* 25,20/1.001 MHz */
+ { 25200, 4096, 25200, 6272, 28000, 6144, 25200 }, /* 25.20 MHz */
+ { 27000, 4096, 27000, 6272, 30000, 6144, 27000 }, /* 27.00 MHz */
+ { 27027, 4096, 27027, 6272, 30030, 6144, 27027 }, /* 27.00*1.001 MHz */
+ { 54000, 4096, 54000, 6272, 60000, 6144, 54000 }, /* 54.00 MHz */
+ { 54054, 4096, 54054, 6272, 60060, 6144, 54054 }, /* 54.00*1.001 MHz */
+ { 74176, 4096, 74176, 5733, 75335, 6144, 74176 }, /* 74.25/1.001 MHz */
+ { 74250, 4096, 74250, 6272, 82500, 6144, 74250 }, /* 74.25 MHz */
+ { 148352, 4096, 148352, 5733, 150670, 6144, 148352 }, /* 148.50/1.001 MHz */
+ { 148500, 4096, 148500, 6272, 165000, 6144, 148500 }, /* 148.50 MHz */
+ };
+
+ /* Precalculated values for common clocks */
+ for (i = 0; i < ARRAY_SIZE(hdmi_predefined_acr); i++)
+ if (hdmi_predefined_acr[i].clock == clock)
+ return &hdmi_predefined_acr[i];
+
+ /* And odd clocks get manually calculated */
+ radeon_audio_calc_cts(clock, &res.cts_32khz, &res.n_32khz, 32000);
+ radeon_audio_calc_cts(clock, &res.cts_44_1khz, &res.n_44_1khz, 44100);
+ radeon_audio_calc_cts(clock, &res.cts_48khz, &res.n_48khz, 48000);
+
+ return &res;
+}
+
+/*
+ * update the N and CTS parameters for a given pixel clock rate
+ */
+static void radeon_audio_update_acr(struct drm_encoder *encoder, unsigned int clock)
+{
+ const struct radeon_hdmi_acr *acr = radeon_audio_acr(clock);
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ if (radeon_encoder->audio && radeon_encoder->audio->update_acr)
+ radeon_encoder->audio->update_acr(encoder, dig->afmt->offset, acr);
+}
+
+static void radeon_audio_set_vbi_packet(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ if (radeon_encoder->audio && radeon_encoder->audio->set_vbi_packet)
+ radeon_encoder->audio->set_vbi_packet(encoder, dig->afmt->offset);
+}
+
+static void radeon_hdmi_set_color_depth(struct drm_encoder *encoder)
+{
+ int bpc = 8;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ if (encoder->crtc) {
+ struct radeon_crtc *radeon_crtc = to_radeon_crtc(encoder->crtc);
+ bpc = radeon_crtc->bpc;
+ }
+
+ if (radeon_encoder->audio && radeon_encoder->audio->set_color_depth)
+ radeon_encoder->audio->set_color_depth(encoder, dig->afmt->offset, bpc);
+}
+
+static void radeon_audio_set_audio_packet(struct drm_encoder *encoder)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ if (radeon_encoder->audio && radeon_encoder->audio->set_audio_packet)
+ radeon_encoder->audio->set_audio_packet(encoder, dig->afmt->offset);
+}
+
+static void radeon_audio_set_mute(struct drm_encoder *encoder, bool mute)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ if (radeon_encoder->audio && radeon_encoder->audio->set_mute)
+ radeon_encoder->audio->set_mute(encoder, dig->afmt->offset, mute);
+}
+
+/*
+ * update the info frames with the data from the current display mode
+ */
+static void radeon_audio_hdmi_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct radeon_device *rdev = encoder->dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* disable audio prior to setting up hw */
+ dig->afmt->pin = radeon_audio_get_pin(encoder);
+ radeon_audio_enable(rdev, dig->afmt->pin, 0);
+
+ radeon_audio_set_dto(encoder, mode->clock);
+ radeon_audio_set_vbi_packet(encoder);
+ radeon_hdmi_set_color_depth(encoder);
+ radeon_audio_set_mute(encoder, false);
+ radeon_audio_update_acr(encoder, mode->clock);
+ radeon_audio_set_audio_packet(encoder);
+ radeon_audio_select_pin(encoder);
+
+ if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+ return;
+
+ /* enable audio after to setting up hw */
+ radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+}
+
+static void radeon_audio_dp_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct drm_device *dev = encoder->dev;
+ struct radeon_device *rdev = dev->dev_private;
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+ struct radeon_encoder_atom_dig *dig = radeon_encoder->enc_priv;
+
+ if (!dig || !dig->afmt)
+ return;
+
+ /* disable audio prior to setting up hw */
+ dig->afmt->pin = radeon_audio_get_pin(encoder);
+ radeon_audio_enable(rdev, dig->afmt->pin, 0);
+
+ radeon_audio_set_dto(encoder, rdev->clock.default_dispclk * 10);
+ radeon_audio_set_audio_packet(encoder);
+ radeon_audio_select_pin(encoder);
+
+ if (radeon_audio_set_avi_packet(encoder, mode) < 0)
+ return;
+
+ /* enable audio after to setting up hw */
+ radeon_audio_enable(rdev, dig->afmt->pin, 0xf);
+}
+
+void radeon_audio_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->mode_set)
+ radeon_encoder->audio->mode_set(encoder, mode);
+}
+
+void radeon_audio_dpms(struct drm_encoder *encoder, int mode)
+{
+ struct radeon_encoder *radeon_encoder = to_radeon_encoder(encoder);
+
+ if (radeon_encoder->audio && radeon_encoder->audio->dpms)
+ radeon_encoder->audio->dpms(encoder, mode == DRM_MODE_DPMS_ON);
+}
diff --git a/drivers/gpu/drm/radeon/radeon_audio.h b/drivers/gpu/drm/radeon/radeon_audio.h
new file mode 100644
index 000000000000..c92d059ab204
--- /dev/null
+++ b/drivers/gpu/drm/radeon/radeon_audio.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2014 Advanced Micro Devices, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * Authors: Slava Grigorev <slava.grigorev@amd.com>
+ */
+
+#ifndef __RADEON_AUDIO_H__
+#define __RADEON_AUDIO_H__
+
+#include <linux/types.h>
+
+#define RREG32_ENDPOINT(block, reg) \
+ radeon_audio_endpoint_rreg(rdev, (block), (reg))
+#define WREG32_ENDPOINT(block, reg, v) \
+ radeon_audio_endpoint_wreg(rdev, (block), (reg), (v))
+
+struct radeon_audio_basic_funcs
+{
+ u32 (*endpoint_rreg)(struct radeon_device *rdev, u32 offset, u32 reg);
+ void (*endpoint_wreg)(struct radeon_device *rdev,
+ u32 offset, u32 reg, u32 v);
+ void (*enable)(struct radeon_device *rdev,
+ struct r600_audio_pin *pin, u8 enable_mask);
+};
+
+struct radeon_audio_funcs
+{
+ void (*select_pin)(struct drm_encoder *encoder);
+ struct r600_audio_pin* (*get_pin)(struct radeon_device *rdev);
+ void (*write_latency_fields)(struct drm_encoder *encoder,
+ struct drm_connector *connector, struct drm_display_mode *mode);
+ void (*write_sad_regs)(struct drm_encoder *encoder,
+ struct cea_sad *sads, int sad_count);
+ void (*write_speaker_allocation)(struct drm_encoder *encoder,
+ u8 *sadb, int sad_count);
+ void (*set_dto)(struct radeon_device *rdev,
+ struct radeon_crtc *crtc, unsigned int clock);
+ void (*update_acr)(struct drm_encoder *encoder, long offset,
+ const struct radeon_hdmi_acr *acr);
+ void (*set_vbi_packet)(struct drm_encoder *encoder, u32 offset);
+ void (*set_color_depth)(struct drm_encoder *encoder, u32 offset, int bpc);
+ void (*set_avi_packet)(struct radeon_device *rdev, u32 offset,
+ unsigned char *buffer, size_t size);
+ void (*set_audio_packet)(struct drm_encoder *encoder, u32 offset);
+ void (*set_mute)(struct drm_encoder *encoder, u32 offset, bool mute);
+ void (*mode_set)(struct drm_encoder *encoder,
+ struct drm_display_mode *mode);
+ void (*dpms)(struct drm_encoder *encoder, bool mode);
+};
+
+int radeon_audio_init(struct radeon_device *rdev);
+void radeon_audio_detect(struct drm_connector *connector,
+ enum drm_connector_status status);
+u32 radeon_audio_endpoint_rreg(struct radeon_device *rdev,
+ u32 offset, u32 reg);
+void radeon_audio_endpoint_wreg(struct radeon_device *rdev,
+ u32 offset, u32 reg, u32 v);
+struct r600_audio_pin *radeon_audio_get_pin(struct drm_encoder *encoder);
+void radeon_audio_enable(struct radeon_device *rdev,
+ struct r600_audio_pin *pin, u8 enable_mask);
+void radeon_audio_fini(struct radeon_device *rdev);
+void radeon_audio_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode);
+void radeon_audio_dpms(struct drm_encoder *encoder, int mode);
+
+#endif
diff --git a/drivers/gpu/drm/radeon/radeon_benchmark.c b/drivers/gpu/drm/radeon/radeon_benchmark.c
index 9e7f23dd14bd..87d5fb21cb61 100644
--- a/drivers/gpu/drm/radeon/radeon_benchmark.c
+++ b/drivers/gpu/drm/radeon/radeon_benchmark.c
@@ -34,7 +34,8 @@
static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size,
uint64_t saddr, uint64_t daddr,
- int flag, int n)
+ int flag, int n,
+ struct reservation_object *resv)
{
unsigned long start_jiffies;
unsigned long end_jiffies;
@@ -47,12 +48,12 @@ static int radeon_benchmark_do_move(struct radeon_device *rdev, unsigned size,
case RADEON_BENCHMARK_COPY_DMA:
fence = radeon_copy_dma(rdev, saddr, daddr,
size / RADEON_GPU_PAGE_SIZE,
- NULL);
+ resv);
break;
case RADEON_BENCHMARK_COPY_BLIT:
fence = radeon_copy_blit(rdev, saddr, daddr,
size / RADEON_GPU_PAGE_SIZE,
- NULL);
+ resv);
break;
default:
DRM_ERROR("Unknown copy method\n");
@@ -120,7 +121,8 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
if (rdev->asic->copy.dma) {
time = radeon_benchmark_do_move(rdev, size, saddr, daddr,
- RADEON_BENCHMARK_COPY_DMA, n);
+ RADEON_BENCHMARK_COPY_DMA, n,
+ dobj->tbo.resv);
if (time < 0)
goto out_cleanup;
if (time > 0)
@@ -130,7 +132,8 @@ static void radeon_benchmark_move(struct radeon_device *rdev, unsigned size,
if (rdev->asic->copy.blit) {
time = radeon_benchmark_do_move(rdev, size, saddr, daddr,
- RADEON_BENCHMARK_COPY_BLIT, n);
+ RADEON_BENCHMARK_COPY_BLIT, n,
+ dobj->tbo.resv);
if (time < 0)
goto out_cleanup;
if (time > 0)
diff --git a/drivers/gpu/drm/radeon/radeon_connectors.c b/drivers/gpu/drm/radeon/radeon_connectors.c
index 26baa9c05f6c..27def67cb6be 100644
--- a/drivers/gpu/drm/radeon/radeon_connectors.c
+++ b/drivers/gpu/drm/radeon/radeon_connectors.c
@@ -29,6 +29,7 @@
#include <drm/drm_fb_helper.h>
#include <drm/radeon_drm.h>
#include "radeon.h"
+#include "radeon_audio.h"
#include "atom.h"
#include <linux/pm_runtime.h>
@@ -1332,6 +1333,9 @@ out:
/* updated in get modes as well since we need to know if it's analog or digital */
radeon_connector_update_scratch_regs(connector, ret);
+ if (radeon_audio != 0)
+ radeon_audio_detect(connector, ret);
+
exit:
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
@@ -1654,6 +1658,10 @@ radeon_dp_detect(struct drm_connector *connector, bool force)
}
radeon_connector_update_scratch_regs(connector, ret);
+
+ if (radeon_audio != 0)
+ radeon_audio_detect(connector, ret);
+
out:
pm_runtime_mark_last_busy(connector->dev->dev);
pm_runtime_put_autosuspend(connector->dev->dev);
diff --git a/drivers/gpu/drm/radeon/radeon_cs.c b/drivers/gpu/drm/radeon/radeon_cs.c
index c830863bc98a..a579ed379f20 100644
--- a/drivers/gpu/drm/radeon/radeon_cs.c
+++ b/drivers/gpu/drm/radeon/radeon_cs.c
@@ -715,6 +715,7 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
struct radeon_cs_chunk *ib_chunk = p->chunk_ib;
struct radeon_device *rdev = p->rdev;
uint32_t header;
+ int ret = 0, i;
if (idx >= ib_chunk->length_dw) {
DRM_ERROR("Can not parse packet at %d after CS end %d !\n",
@@ -743,14 +744,25 @@ int radeon_cs_packet_parse(struct radeon_cs_parser *p,
break;
default:
DRM_ERROR("Unknown packet type %d at %d !\n", pkt->type, idx);
- return -EINVAL;
+ ret = -EINVAL;
+ goto dump_ib;
}
if ((pkt->count + 1 + pkt->idx) >= ib_chunk->length_dw) {
DRM_ERROR("Packet (%d:%d:%d) end after CS buffer (%d) !\n",
pkt->idx, pkt->type, pkt->count, ib_chunk->length_dw);
- return -EINVAL;
+ ret = -EINVAL;
+ goto dump_ib;
}
return 0;
+
+dump_ib:
+ for (i = 0; i < ib_chunk->length_dw; i++) {
+ if (i == idx)
+ printk("\t0x%08x <---\n", radeon_get_ib_value(p, i));
+ else
+ printk("\t0x%08x\n", radeon_get_ib_value(p, i));
+ }
+ return ret;
}
/**
diff --git a/drivers/gpu/drm/radeon/radeon_display.c b/drivers/gpu/drm/radeon/radeon_display.c
index 102116902a07..913fafa597ad 100644
--- a/drivers/gpu/drm/radeon/radeon_display.c
+++ b/drivers/gpu/drm/radeon/radeon_display.c
@@ -960,6 +960,9 @@ void radeon_compute_pll_avivo(struct radeon_pll *pll,
if (pll->flags & RADEON_PLL_USE_FRAC_FB_DIV &&
pll->flags & RADEON_PLL_USE_REF_DIV)
ref_div_max = pll->reference_div;
+ else if (pll->flags & RADEON_PLL_PREFER_MINM_OVER_MAXP)
+ /* fix for problems on RS880 */
+ ref_div_max = min(pll->max_ref_div, 7u);
else
ref_div_max = pll->max_ref_div;
diff --git a/drivers/gpu/drm/radeon/radeon_drv.c b/drivers/gpu/drm/radeon/radeon_drv.c
index 4f50fb0e3d93..5d684beb48d3 100644
--- a/drivers/gpu/drm/radeon/radeon_drv.c
+++ b/drivers/gpu/drm/radeon/radeon_drv.c
@@ -88,9 +88,10 @@
* 2.39.0 - Add INFO query for number of active CUs
* 2.40.0 - Add RADEON_GEM_GTT_WC/UC, flush HDP cache before submitting
* CS to GPU on >= r600
+ * 2.41.0 - evergreen/cayman: Add SET_BASE/DRAW_INDIRECT command parsing support
*/
#define KMS_DRIVER_MAJOR 2
-#define KMS_DRIVER_MINOR 40
+#define KMS_DRIVER_MINOR 41
#define KMS_DRIVER_PATCHLEVEL 0
int radeon_driver_load_kms(struct drm_device *dev, unsigned long flags);
int radeon_driver_unload_kms(struct drm_device *dev);
diff --git a/drivers/gpu/drm/radeon/radeon_encoders.c b/drivers/gpu/drm/radeon/radeon_encoders.c
index 6b670b0bc47b..3a297037cc17 100644
--- a/drivers/gpu/drm/radeon/radeon_encoders.c
+++ b/drivers/gpu/drm/radeon/radeon_encoders.c
@@ -179,9 +179,12 @@ static void radeon_encoder_add_backlight(struct radeon_encoder *radeon_encoder,
(rdev->pdev->subsystem_vendor == 0x1734) &&
(rdev->pdev->subsystem_device == 0x1107))
use_bl = false;
+/* Older PPC macs use on-GPU backlight controller */
+#ifndef CONFIG_PPC_PMAC
/* disable native backlight control on older asics */
else if (rdev->family < CHIP_R600)
use_bl = false;
+#endif
else
use_bl = true;
}
diff --git a/drivers/gpu/drm/radeon/radeon_fb.c b/drivers/gpu/drm/radeon/radeon_fb.c
index 29b9220ec399..ea276ff6d174 100644
--- a/drivers/gpu/drm/radeon/radeon_fb.c
+++ b/drivers/gpu/drm/radeon/radeon_fb.c
@@ -390,18 +390,27 @@ int radeon_fbdev_init(struct radeon_device *rdev)
ret = drm_fb_helper_init(rdev->ddev, &rfbdev->helper,
rdev->num_crtc,
RADEONFB_CONN_LIMIT);
- if (ret) {
- kfree(rfbdev);
- return ret;
- }
+ if (ret)
+ goto free;
- drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
+ ret = drm_fb_helper_single_add_all_connectors(&rfbdev->helper);
+ if (ret)
+ goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(rdev->ddev);
- drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
+ ret = drm_fb_helper_initial_config(&rfbdev->helper, bpp_sel);
+ if (ret)
+ goto fini;
+
return 0;
+
+fini:
+ drm_fb_helper_fini(&rfbdev->helper);
+free:
+ kfree(rfbdev);
+ return ret;
}
void radeon_fbdev_fini(struct radeon_device *rdev)
@@ -419,16 +428,6 @@ void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state)
fb_set_suspend(rdev->mode_info.rfbdev->helper.fbdev, state);
}
-int radeon_fbdev_total_size(struct radeon_device *rdev)
-{
- struct radeon_bo *robj;
- int size = 0;
-
- robj = gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj);
- size += radeon_bo_size(robj);
- return size;
-}
-
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj)
{
if (robj == gem_to_radeon_bo(rdev->mode_info.rfbdev->rfb.obj))
diff --git a/drivers/gpu/drm/radeon/radeon_gem.c b/drivers/gpu/drm/radeon/radeon_gem.c
index d0b4f7d1140d..ac3c1310b953 100644
--- a/drivers/gpu/drm/radeon/radeon_gem.c
+++ b/drivers/gpu/drm/radeon/radeon_gem.c
@@ -146,7 +146,8 @@ int radeon_gem_object_open(struct drm_gem_object *obj, struct drm_file *file_pri
struct radeon_bo_va *bo_va;
int r;
- if (rdev->family < CHIP_CAYMAN) {
+ if ((rdev->family < CHIP_CAYMAN) ||
+ (!rdev->accel_working)) {
return 0;
}
@@ -176,7 +177,8 @@ void radeon_gem_object_close(struct drm_gem_object *obj,
struct radeon_bo_va *bo_va;
int r;
- if (rdev->family < CHIP_CAYMAN) {
+ if ((rdev->family < CHIP_CAYMAN) ||
+ (!rdev->accel_working)) {
return;
}
diff --git a/drivers/gpu/drm/radeon/radeon_i2c.c b/drivers/gpu/drm/radeon/radeon_i2c.c
index add622008407..9590bcd321c0 100644
--- a/drivers/gpu/drm/radeon/radeon_i2c.c
+++ b/drivers/gpu/drm/radeon/radeon_i2c.c
@@ -1048,11 +1048,6 @@ struct radeon_i2c_chan *radeon_i2c_lookup(struct radeon_device *rdev,
return NULL;
}
-struct drm_encoder *radeon_best_encoder(struct drm_connector *connector)
-{
- return NULL;
-}
-
void radeon_i2c_get_byte(struct radeon_i2c_chan *i2c_bus,
u8 slave_addr,
u8 addr,
diff --git a/drivers/gpu/drm/radeon/radeon_kfd.c b/drivers/gpu/drm/radeon/radeon_kfd.c
index bef9a0953284..061eaa9c19c7 100644
--- a/drivers/gpu/drm/radeon/radeon_kfd.c
+++ b/drivers/gpu/drm/radeon/radeon_kfd.c
@@ -30,22 +30,22 @@
#include "radeon_kfd.h"
#include "radeon_ucode.h"
#include <linux/firmware.h>
+#include "cik_structs.h"
#define CIK_PIPE_PER_MEC (4)
struct kgd_mem {
- struct radeon_sa_bo *sa_bo;
+ struct radeon_bo *bo;
uint64_t gpu_addr;
- void *ptr;
+ void *cpu_ptr;
};
-static int init_sa_manager(struct kgd_dev *kgd, unsigned int size);
-static void fini_sa_manager(struct kgd_dev *kgd);
-static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
- enum kgd_memory_pool pool, struct kgd_mem **mem);
+static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+ void **mem_obj, uint64_t *gpu_addr,
+ void **cpu_ptr);
-static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem);
+static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj);
static uint64_t get_vmem_size(struct kgd_dev *kgd);
static uint64_t get_gpu_clock_counter(struct kgd_dev *kgd);
@@ -64,36 +64,37 @@ static void kgd_program_sh_mem_settings(struct kgd_dev *kgd, uint32_t vmid,
static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
unsigned int vmid);
-static int kgd_init_memory(struct kgd_dev *kgd);
-
static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
uint32_t hpd_size, uint64_t hpd_gpu_addr);
static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr);
-
+static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd);
static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
uint32_t pipe_id, uint32_t queue_id);
static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id);
+static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd);
+static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
+ unsigned int timeout);
static const struct kfd2kgd_calls kfd2kgd = {
- .init_sa_manager = init_sa_manager,
- .fini_sa_manager = fini_sa_manager,
- .allocate_mem = allocate_mem,
- .free_mem = free_mem,
+ .init_gtt_mem_allocation = alloc_gtt_mem,
+ .free_gtt_mem = free_gtt_mem,
.get_vmem_size = get_vmem_size,
.get_gpu_clock_counter = get_gpu_clock_counter,
.get_max_engine_clock_in_mhz = get_max_engine_clock_in_mhz,
.program_sh_mem_settings = kgd_program_sh_mem_settings,
.set_pasid_vmid_mapping = kgd_set_pasid_vmid_mapping,
- .init_memory = kgd_init_memory,
.init_pipeline = kgd_init_pipeline,
.hqd_load = kgd_hqd_load,
+ .hqd_sdma_load = kgd_hqd_sdma_load,
.hqd_is_occupied = kgd_hqd_is_occupied,
+ .hqd_sdma_is_occupied = kgd_hqd_sdma_is_occupied,
.hqd_destroy = kgd_hqd_destroy,
+ .hqd_sdma_destroy = kgd_hqd_sdma_destroy,
.get_fw_version = get_fw_version
};
@@ -194,87 +195,78 @@ int radeon_kfd_resume(struct radeon_device *rdev)
return r;
}
-static u32 pool_to_domain(enum kgd_memory_pool p)
-{
- switch (p) {
- case KGD_POOL_FRAMEBUFFER: return RADEON_GEM_DOMAIN_VRAM;
- default: return RADEON_GEM_DOMAIN_GTT;
- }
-}
-
-static int init_sa_manager(struct kgd_dev *kgd, unsigned int size)
+static int alloc_gtt_mem(struct kgd_dev *kgd, size_t size,
+ void **mem_obj, uint64_t *gpu_addr,
+ void **cpu_ptr)
{
struct radeon_device *rdev = (struct radeon_device *)kgd;
+ struct kgd_mem **mem = (struct kgd_mem **) mem_obj;
int r;
BUG_ON(kgd == NULL);
+ BUG_ON(gpu_addr == NULL);
+ BUG_ON(cpu_ptr == NULL);
- r = radeon_sa_bo_manager_init(rdev, &rdev->kfd_bo,
- size,
- RADEON_GPU_PAGE_SIZE,
- RADEON_GEM_DOMAIN_GTT,
- RADEON_GEM_GTT_WC);
+ *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL);
+ if ((*mem) == NULL)
+ return -ENOMEM;
- if (r)
+ r = radeon_bo_create(rdev, size, PAGE_SIZE, true, RADEON_GEM_DOMAIN_GTT,
+ RADEON_GEM_GTT_WC, NULL, NULL, &(*mem)->bo);
+ if (r) {
+ dev_err(rdev->dev,
+ "failed to allocate BO for amdkfd (%d)\n", r);
return r;
+ }
- r = radeon_sa_bo_manager_start(rdev, &rdev->kfd_bo);
- if (r)
- radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
-
- return r;
-}
-
-static void fini_sa_manager(struct kgd_dev *kgd)
-{
- struct radeon_device *rdev = (struct radeon_device *)kgd;
-
- BUG_ON(kgd == NULL);
-
- radeon_sa_bo_manager_suspend(rdev, &rdev->kfd_bo);
- radeon_sa_bo_manager_fini(rdev, &rdev->kfd_bo);
-}
-
-static int allocate_mem(struct kgd_dev *kgd, size_t size, size_t alignment,
- enum kgd_memory_pool pool, struct kgd_mem **mem)
-{
- struct radeon_device *rdev = (struct radeon_device *)kgd;
- u32 domain;
- int r;
-
- BUG_ON(kgd == NULL);
-
- domain = pool_to_domain(pool);
- if (domain != RADEON_GEM_DOMAIN_GTT) {
- dev_err(rdev->dev,
- "Only allowed to allocate gart memory for kfd\n");
- return -EINVAL;
+ /* map the buffer */
+ r = radeon_bo_reserve((*mem)->bo, true);
+ if (r) {
+ dev_err(rdev->dev, "(%d) failed to reserve bo for amdkfd\n", r);
+ goto allocate_mem_reserve_bo_failed;
}
- *mem = kmalloc(sizeof(struct kgd_mem), GFP_KERNEL);
- if ((*mem) == NULL)
- return -ENOMEM;
+ r = radeon_bo_pin((*mem)->bo, RADEON_GEM_DOMAIN_GTT,
+ &(*mem)->gpu_addr);
+ if (r) {
+ dev_err(rdev->dev, "(%d) failed to pin bo for amdkfd\n", r);
+ goto allocate_mem_pin_bo_failed;
+ }
+ *gpu_addr = (*mem)->gpu_addr;
- r = radeon_sa_bo_new(rdev, &rdev->kfd_bo, &(*mem)->sa_bo, size,
- alignment);
+ r = radeon_bo_kmap((*mem)->bo, &(*mem)->cpu_ptr);
if (r) {
- dev_err(rdev->dev, "failed to get memory for kfd (%d)\n", r);
- return r;
+ dev_err(rdev->dev,
+ "(%d) failed to map bo to kernel for amdkfd\n", r);
+ goto allocate_mem_kmap_bo_failed;
}
+ *cpu_ptr = (*mem)->cpu_ptr;
- (*mem)->ptr = radeon_sa_bo_cpu_addr((*mem)->sa_bo);
- (*mem)->gpu_addr = radeon_sa_bo_gpu_addr((*mem)->sa_bo);
+ radeon_bo_unreserve((*mem)->bo);
return 0;
+
+allocate_mem_kmap_bo_failed:
+ radeon_bo_unpin((*mem)->bo);
+allocate_mem_pin_bo_failed:
+ radeon_bo_unreserve((*mem)->bo);
+allocate_mem_reserve_bo_failed:
+ radeon_bo_unref(&(*mem)->bo);
+
+ return r;
}
-static void free_mem(struct kgd_dev *kgd, struct kgd_mem *mem)
+static void free_gtt_mem(struct kgd_dev *kgd, void *mem_obj)
{
- struct radeon_device *rdev = (struct radeon_device *)kgd;
+ struct kgd_mem *mem = (struct kgd_mem *) mem_obj;
- BUG_ON(kgd == NULL);
+ BUG_ON(mem == NULL);
- radeon_sa_bo_free(rdev, &mem->sa_bo, NULL);
+ radeon_bo_reserve(mem->bo, true);
+ radeon_bo_kunmap(mem->bo);
+ radeon_bo_unpin(mem->bo);
+ radeon_bo_unreserve(mem->bo);
+ radeon_bo_unref(&(mem->bo));
kfree(mem);
}
@@ -397,42 +389,6 @@ static int kgd_set_pasid_vmid_mapping(struct kgd_dev *kgd, unsigned int pasid,
return 0;
}
-static int kgd_init_memory(struct kgd_dev *kgd)
-{
- /*
- * Configure apertures:
- * LDS: 0x60000000'00000000 - 0x60000001'00000000 (4GB)
- * Scratch: 0x60000001'00000000 - 0x60000002'00000000 (4GB)
- * GPUVM: 0x60010000'00000000 - 0x60020000'00000000 (1TB)
- */
- int i;
- uint32_t sh_mem_bases = PRIVATE_BASE(0x6000) | SHARED_BASE(0x6000);
-
- for (i = 8; i < 16; i++) {
- uint32_t sh_mem_config;
-
- lock_srbm(kgd, 0, 0, 0, i);
-
- sh_mem_config = ALIGNMENT_MODE(SH_MEM_ALIGNMENT_MODE_UNALIGNED);
- sh_mem_config |= DEFAULT_MTYPE(MTYPE_NONCACHED);
-
- write_register(kgd, SH_MEM_CONFIG, sh_mem_config);
-
- write_register(kgd, SH_MEM_BASES, sh_mem_bases);
-
- /* Scratch aperture is not supported for now. */
- write_register(kgd, SH_STATIC_MEM_CONFIG, 0);
-
- /* APE1 disabled for now. */
- write_register(kgd, SH_MEM_APE1_BASE, 1);
- write_register(kgd, SH_MEM_APE1_LIMIT, 0);
-
- unlock_srbm(kgd);
- }
-
- return 0;
-}
-
static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
uint32_t hpd_size, uint64_t hpd_gpu_addr)
{
@@ -451,11 +407,28 @@ static int kgd_init_pipeline(struct kgd_dev *kgd, uint32_t pipe_id,
return 0;
}
+static inline uint32_t get_sdma_base_addr(struct cik_sdma_rlc_registers *m)
+{
+ uint32_t retval;
+
+ retval = m->sdma_engine_id * SDMA1_REGISTER_OFFSET +
+ m->sdma_queue_id * KFD_CIK_SDMA_QUEUE_OFFSET;
+
+ pr_debug("kfd: sdma base address: 0x%x\n", retval);
+
+ return retval;
+}
+
static inline struct cik_mqd *get_mqd(void *mqd)
{
return (struct cik_mqd *)mqd;
}
+static inline struct cik_sdma_rlc_registers *get_sdma_mqd(void *mqd)
+{
+ return (struct cik_sdma_rlc_registers *)mqd;
+}
+
static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
uint32_t queue_id, uint32_t __user *wptr)
{
@@ -533,6 +506,45 @@ static int kgd_hqd_load(struct kgd_dev *kgd, void *mqd, uint32_t pipe_id,
return 0;
}
+static int kgd_hqd_sdma_load(struct kgd_dev *kgd, void *mqd)
+{
+ struct cik_sdma_rlc_registers *m;
+ uint32_t sdma_base_addr;
+
+ m = get_sdma_mqd(mqd);
+ sdma_base_addr = get_sdma_base_addr(m);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_VIRTUAL_ADDR,
+ m->sdma_rlc_virtual_addr);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_RB_BASE,
+ m->sdma_rlc_rb_base);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_RB_BASE_HI,
+ m->sdma_rlc_rb_base_hi);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_LO,
+ m->sdma_rlc_rb_rptr_addr_lo);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_RB_RPTR_ADDR_HI,
+ m->sdma_rlc_rb_rptr_addr_hi);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_DOORBELL,
+ m->sdma_rlc_doorbell);
+
+ write_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_RB_CNTL,
+ m->sdma_rlc_rb_cntl);
+
+ return 0;
+}
+
static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
uint32_t pipe_id, uint32_t queue_id)
{
@@ -554,6 +566,24 @@ static bool kgd_hqd_is_occupied(struct kgd_dev *kgd, uint64_t queue_address,
return retval;
}
+static bool kgd_hqd_sdma_is_occupied(struct kgd_dev *kgd, void *mqd)
+{
+ struct cik_sdma_rlc_registers *m;
+ uint32_t sdma_base_addr;
+ uint32_t sdma_rlc_rb_cntl;
+
+ m = get_sdma_mqd(mqd);
+ sdma_base_addr = get_sdma_base_addr(m);
+
+ sdma_rlc_rb_cntl = read_register(kgd,
+ sdma_base_addr + SDMA0_RLC0_RB_CNTL);
+
+ if (sdma_rlc_rb_cntl & SDMA_RB_ENABLE)
+ return true;
+
+ return false;
+}
+
static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
unsigned int timeout, uint32_t pipe_id,
uint32_t queue_id)
@@ -583,6 +613,39 @@ static int kgd_hqd_destroy(struct kgd_dev *kgd, uint32_t reset_type,
return 0;
}
+static int kgd_hqd_sdma_destroy(struct kgd_dev *kgd, void *mqd,
+ unsigned int timeout)
+{
+ struct cik_sdma_rlc_registers *m;
+ uint32_t sdma_base_addr;
+ uint32_t temp;
+
+ m = get_sdma_mqd(mqd);
+ sdma_base_addr = get_sdma_base_addr(m);
+
+ temp = read_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL);
+ temp = temp & ~SDMA_RB_ENABLE;
+ write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_CNTL, temp);
+
+ while (true) {
+ temp = read_register(kgd, sdma_base_addr +
+ SDMA0_RLC0_CONTEXT_STATUS);
+ if (temp & SDMA_RLC_IDLE)
+ break;
+ if (timeout == 0)
+ return -ETIME;
+ msleep(20);
+ timeout -= 20;
+ }
+
+ write_register(kgd, sdma_base_addr + SDMA0_RLC0_DOORBELL, 0);
+ write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_RPTR, 0);
+ write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_WPTR, 0);
+ write_register(kgd, sdma_base_addr + SDMA0_RLC0_RB_BASE, 0);
+
+ return 0;
+}
+
static uint16_t get_fw_version(struct kgd_dev *kgd, enum kgd_engine_type type)
{
struct radeon_device *rdev = (struct radeon_device *) kgd;
diff --git a/drivers/gpu/drm/radeon/radeon_kfd.h b/drivers/gpu/drm/radeon/radeon_kfd.h
index f90e161ca507..1103f9082f6b 100644
--- a/drivers/gpu/drm/radeon/radeon_kfd.h
+++ b/drivers/gpu/drm/radeon/radeon_kfd.h
@@ -29,7 +29,7 @@
#define RADEON_KFD_H_INCLUDED
#include <linux/types.h>
-#include "../amd/include/kgd_kfd_interface.h"
+#include "kgd_kfd_interface.h"
struct radeon_device;
diff --git a/drivers/gpu/drm/radeon/radeon_kms.c b/drivers/gpu/drm/radeon/radeon_kms.c
index 3cf9c1fa6475..686411e4e4f6 100644
--- a/drivers/gpu/drm/radeon/radeon_kms.c
+++ b/drivers/gpu/drm/radeon/radeon_kms.c
@@ -605,14 +605,14 @@ int radeon_driver_open_kms(struct drm_device *dev, struct drm_file *file_priv)
return -ENOMEM;
}
- vm = &fpriv->vm;
- r = radeon_vm_init(rdev, vm);
- if (r) {
- kfree(fpriv);
- return r;
- }
-
if (rdev->accel_working) {
+ vm = &fpriv->vm;
+ r = radeon_vm_init(rdev, vm);
+ if (r) {
+ kfree(fpriv);
+ return r;
+ }
+
r = radeon_bo_reserve(rdev->ring_tmp_bo.bo, false);
if (r) {
radeon_vm_fini(rdev, vm);
@@ -668,9 +668,9 @@ void radeon_driver_postclose_kms(struct drm_device *dev,
radeon_vm_bo_rmv(rdev, vm->ib_bo_va);
radeon_bo_unreserve(rdev->ring_tmp_bo.bo);
}
+ radeon_vm_fini(rdev, vm);
}
- radeon_vm_fini(rdev, vm);
kfree(fpriv);
file_priv->driver_priv = NULL;
}
diff --git a/drivers/gpu/drm/radeon/radeon_mode.h b/drivers/gpu/drm/radeon/radeon_mode.h
index 390db897f322..920a8be8abad 100644
--- a/drivers/gpu/drm/radeon/radeon_mode.h
+++ b/drivers/gpu/drm/radeon/radeon_mode.h
@@ -449,6 +449,7 @@ struct radeon_encoder {
int audio_polling_active;
bool is_ext_encoder;
u16 caps;
+ struct radeon_audio_funcs *audio;
};
struct radeon_connector_atom_dig {
@@ -745,8 +746,6 @@ extern void radeon_router_select_ddc_port(struct radeon_connector *radeon_connec
extern void radeon_router_select_cd_port(struct radeon_connector *radeon_connector);
extern bool radeon_ddc_probe(struct radeon_connector *radeon_connector, bool use_aux);
-extern struct drm_encoder *radeon_best_encoder(struct drm_connector *connector);
-
extern bool radeon_atombios_get_ppll_ss_info(struct radeon_device *rdev,
struct radeon_atom_ss *ss,
int id);
@@ -925,7 +924,6 @@ void dce8_program_fmt(struct drm_encoder *encoder);
int radeon_fbdev_init(struct radeon_device *rdev);
void radeon_fbdev_fini(struct radeon_device *rdev);
void radeon_fbdev_set_suspend(struct radeon_device *rdev, int state);
-int radeon_fbdev_total_size(struct radeon_device *rdev);
bool radeon_fbdev_robj_is_fb(struct radeon_device *rdev, struct radeon_bo *robj);
void radeon_fb_output_poll_changed(struct radeon_device *rdev);
diff --git a/drivers/gpu/drm/radeon/radeon_object.c b/drivers/gpu/drm/radeon/radeon_object.c
index 86fc56434b28..43e09942823e 100644
--- a/drivers/gpu/drm/radeon/radeon_object.c
+++ b/drivers/gpu/drm/radeon/radeon_object.c
@@ -238,6 +238,18 @@ int radeon_bo_create(struct radeon_device *rdev,
* See https://bugs.freedesktop.org/show_bug.cgi?id=84627
*/
bo->flags &= ~RADEON_GEM_GTT_WC;
+#elif defined(CONFIG_X86) && !defined(CONFIG_X86_PAT)
+ /* Don't try to enable write-combining when it can't work, or things
+ * may be slow
+ * See https://bugs.freedesktop.org/show_bug.cgi?id=88758
+ */
+
+#warning Please enable CONFIG_MTRR and CONFIG_X86_PAT for better performance \
+ thanks to write-combining
+
+ DRM_INFO_ONCE("Please enable CONFIG_MTRR and CONFIG_X86_PAT for "
+ "better performance thanks to write-combining\n");
+ bo->flags &= ~RADEON_GEM_GTT_WC;
#endif
radeon_ttm_placement_from_domain(bo, domain);
@@ -576,12 +588,6 @@ int radeon_bo_list_validate(struct radeon_device *rdev,
return 0;
}
-int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
- struct vm_area_struct *vma)
-{
- return ttm_fbdev_mmap(vma, &bo->tbo);
-}
-
int radeon_bo_get_surface_reg(struct radeon_bo *bo)
{
struct radeon_device *rdev = bo->rdev;
diff --git a/drivers/gpu/drm/radeon/radeon_object.h b/drivers/gpu/drm/radeon/radeon_object.h
index 3b0b377f76cb..d8d295ee7c12 100644
--- a/drivers/gpu/drm/radeon/radeon_object.h
+++ b/drivers/gpu/drm/radeon/radeon_object.h
@@ -143,8 +143,6 @@ extern void radeon_bo_fini(struct radeon_device *rdev);
extern int radeon_bo_list_validate(struct radeon_device *rdev,
struct ww_acquire_ctx *ticket,
struct list_head *head, int ring);
-extern int radeon_bo_fbdev_mmap(struct radeon_bo *bo,
- struct vm_area_struct *vma);
extern int radeon_bo_set_tiling_flags(struct radeon_bo *bo,
u32 tiling_flags, u32 pitch);
extern void radeon_bo_get_tiling_flags(struct radeon_bo *bo,
diff --git a/drivers/gpu/drm/radeon/radeon_pm.c b/drivers/gpu/drm/radeon/radeon_pm.c
index f7da8fe96a66..33cf4108386d 100644
--- a/drivers/gpu/drm/radeon/radeon_pm.c
+++ b/drivers/gpu/drm/radeon/radeon_pm.c
@@ -24,6 +24,7 @@
#include "radeon.h"
#include "avivod.h"
#include "atom.h"
+#include "r600_dpm.h"
#include <linux/power_supply.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
@@ -554,6 +555,100 @@ fail:
return count;
}
+static ssize_t radeon_hwmon_get_pwm1_enable(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct radeon_device *rdev = dev_get_drvdata(dev);
+ u32 pwm_mode = 0;
+
+ if (rdev->asic->dpm.fan_ctrl_get_mode)
+ pwm_mode = rdev->asic->dpm.fan_ctrl_get_mode(rdev);
+
+ /* never 0 (full-speed), fuse or smc-controlled always */
+ return sprintf(buf, "%i\n", pwm_mode == FDO_PWM_MODE_STATIC ? 1 : 2);
+}
+
+static ssize_t radeon_hwmon_set_pwm1_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct radeon_device *rdev = dev_get_drvdata(dev);
+ int err;
+ int value;
+
+ if(!rdev->asic->dpm.fan_ctrl_set_mode)
+ return -EINVAL;
+
+ err = kstrtoint(buf, 10, &value);
+ if (err)
+ return err;
+
+ switch (value) {
+ case 1: /* manual, percent-based */
+ rdev->asic->dpm.fan_ctrl_set_mode(rdev, FDO_PWM_MODE_STATIC);
+ break;
+ default: /* disable */
+ rdev->asic->dpm.fan_ctrl_set_mode(rdev, 0);
+ break;
+ }
+
+ return count;
+}
+
+static ssize_t radeon_hwmon_get_pwm1_min(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%i\n", 0);
+}
+
+static ssize_t radeon_hwmon_get_pwm1_max(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%i\n", 255);
+}
+
+static ssize_t radeon_hwmon_set_pwm1(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct radeon_device *rdev = dev_get_drvdata(dev);
+ int err;
+ u32 value;
+
+ err = kstrtou32(buf, 10, &value);
+ if (err)
+ return err;
+
+ value = (value * 100) / 255;
+
+ err = rdev->asic->dpm.set_fan_speed_percent(rdev, value);
+ if (err)
+ return err;
+
+ return count;
+}
+
+static ssize_t radeon_hwmon_get_pwm1(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct radeon_device *rdev = dev_get_drvdata(dev);
+ int err;
+ u32 speed;
+
+ err = rdev->asic->dpm.get_fan_speed_percent(rdev, &speed);
+ if (err)
+ return err;
+
+ speed = (speed * 255) / 100;
+
+ return sprintf(buf, "%i\n", speed);
+}
+
static DEVICE_ATTR(power_profile, S_IRUGO | S_IWUSR, radeon_get_pm_profile, radeon_set_pm_profile);
static DEVICE_ATTR(power_method, S_IRUGO | S_IWUSR, radeon_get_pm_method, radeon_set_pm_method);
static DEVICE_ATTR(power_dpm_state, S_IRUGO | S_IWUSR, radeon_get_dpm_state, radeon_set_dpm_state);
@@ -601,11 +696,20 @@ static ssize_t radeon_hwmon_show_temp_thresh(struct device *dev,
static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, radeon_hwmon_show_temp, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 0);
static SENSOR_DEVICE_ATTR(temp1_crit_hyst, S_IRUGO, radeon_hwmon_show_temp_thresh, NULL, 1);
+static SENSOR_DEVICE_ATTR(pwm1, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1, radeon_hwmon_set_pwm1, 0);
+static SENSOR_DEVICE_ATTR(pwm1_enable, S_IRUGO | S_IWUSR, radeon_hwmon_get_pwm1_enable, radeon_hwmon_set_pwm1_enable, 0);
+static SENSOR_DEVICE_ATTR(pwm1_min, S_IRUGO, radeon_hwmon_get_pwm1_min, NULL, 0);
+static SENSOR_DEVICE_ATTR(pwm1_max, S_IRUGO, radeon_hwmon_get_pwm1_max, NULL, 0);
+
static struct attribute *hwmon_attributes[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp1_crit.dev_attr.attr,
&sensor_dev_attr_temp1_crit_hyst.dev_attr.attr,
+ &sensor_dev_attr_pwm1.dev_attr.attr,
+ &sensor_dev_attr_pwm1_enable.dev_attr.attr,
+ &sensor_dev_attr_pwm1_min.dev_attr.attr,
+ &sensor_dev_attr_pwm1_max.dev_attr.attr,
NULL
};
@@ -614,6 +718,7 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
{
struct device *dev = container_of(kobj, struct device, kobj);
struct radeon_device *rdev = dev_get_drvdata(dev);
+ umode_t effective_mode = attr->mode;
/* Skip limit attributes if DPM is not enabled */
if (rdev->pm.pm_method != PM_METHOD_DPM &&
@@ -621,7 +726,35 @@ static umode_t hwmon_attributes_visible(struct kobject *kobj,
attr == &sensor_dev_attr_temp1_crit_hyst.dev_attr.attr))
return 0;
- return attr->mode;
+ /* Skip fan attributes if fan is not present */
+ if (rdev->pm.no_fan &&
+ (attr == &sensor_dev_attr_pwm1.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+ return 0;
+
+ /* mask fan attributes if we have no bindings for this asic to expose */
+ if ((!rdev->asic->dpm.get_fan_speed_percent &&
+ attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't query fan */
+ (!rdev->asic->dpm.fan_ctrl_get_mode &&
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't query state */
+ effective_mode &= ~S_IRUGO;
+
+ if ((!rdev->asic->dpm.set_fan_speed_percent &&
+ attr == &sensor_dev_attr_pwm1.dev_attr.attr) || /* can't manage fan */
+ (!rdev->asic->dpm.fan_ctrl_set_mode &&
+ attr == &sensor_dev_attr_pwm1_enable.dev_attr.attr)) /* can't manage state */
+ effective_mode &= ~S_IWUSR;
+
+ /* hide max/min values if we can't both query and manage the fan */
+ if ((!rdev->asic->dpm.set_fan_speed_percent &&
+ !rdev->asic->dpm.get_fan_speed_percent) &&
+ (attr == &sensor_dev_attr_pwm1_max.dev_attr.attr ||
+ attr == &sensor_dev_attr_pwm1_min.dev_attr.attr))
+ return 0;
+
+ return effective_mode;
}
static const struct attribute_group hwmon_attrgroup = {
@@ -719,6 +852,12 @@ static struct radeon_ps *radeon_dpm_pick_power_state(struct radeon_device *rdev,
single_display = false;
}
+ /* 120hz tends to be problematic even if they are under the
+ * vblank limit.
+ */
+ if (single_display && (r600_dpm_get_vrefresh(rdev) >= 120))
+ single_display = false;
+
/* certain older asics have a separare 3D performance state,
* so try that first if the user selected performance
*/
diff --git a/drivers/gpu/drm/radeon/radeon_test.c b/drivers/gpu/drm/radeon/radeon_test.c
index 07b506b41008..791818165c76 100644
--- a/drivers/gpu/drm/radeon/radeon_test.c
+++ b/drivers/gpu/drm/radeon/radeon_test.c
@@ -119,11 +119,11 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
if (ring == R600_RING_TYPE_DMA_INDEX)
fence = radeon_copy_dma(rdev, gtt_addr, vram_addr,
size / RADEON_GPU_PAGE_SIZE,
- NULL);
+ vram_obj->tbo.resv);
else
fence = radeon_copy_blit(rdev, gtt_addr, vram_addr,
size / RADEON_GPU_PAGE_SIZE,
- NULL);
+ vram_obj->tbo.resv);
if (IS_ERR(fence)) {
DRM_ERROR("Failed GTT->VRAM copy %d\n", i);
r = PTR_ERR(fence);
@@ -170,11 +170,11 @@ static void radeon_do_test_moves(struct radeon_device *rdev, int flag)
if (ring == R600_RING_TYPE_DMA_INDEX)
fence = radeon_copy_dma(rdev, vram_addr, gtt_addr,
size / RADEON_GPU_PAGE_SIZE,
- NULL);
+ vram_obj->tbo.resv);
else
fence = radeon_copy_blit(rdev, vram_addr, gtt_addr,
size / RADEON_GPU_PAGE_SIZE,
- NULL);
+ vram_obj->tbo.resv);
if (IS_ERR(fence)) {
DRM_ERROR("Failed VRAM->GTT copy %d\n", i);
r = PTR_ERR(fence);
diff --git a/drivers/gpu/drm/radeon/radeon_vm.c b/drivers/gpu/drm/radeon/radeon_vm.c
index 06d2246d07f1..2a5a4a9e772d 100644
--- a/drivers/gpu/drm/radeon/radeon_vm.c
+++ b/drivers/gpu/drm/radeon/radeon_vm.c
@@ -743,9 +743,11 @@ static void radeon_vm_frag_ptes(struct radeon_device *rdev,
*/
/* NI is optimized for 256KB fragments, SI and newer for 64KB */
- uint64_t frag_flags = rdev->family == CHIP_CAYMAN ?
+ uint64_t frag_flags = ((rdev->family == CHIP_CAYMAN) ||
+ (rdev->family == CHIP_ARUBA)) ?
R600_PTE_FRAG_256KB : R600_PTE_FRAG_64KB;
- uint64_t frag_align = rdev->family == CHIP_CAYMAN ? 0x200 : 0x80;
+ uint64_t frag_align = ((rdev->family == CHIP_CAYMAN) ||
+ (rdev->family == CHIP_ARUBA)) ? 0x200 : 0x80;
uint64_t frag_start = ALIGN(pe_start, frag_align);
uint64_t frag_end = pe_end & ~(frag_align - 1);
diff --git a/drivers/gpu/drm/radeon/rs600.c b/drivers/gpu/drm/radeon/rs600.c
index 74bce91aecc1..d81182ad53ec 100644
--- a/drivers/gpu/drm/radeon/rs600.c
+++ b/drivers/gpu/drm/radeon/rs600.c
@@ -38,6 +38,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "atom.h"
#include "rs600d.h"
@@ -1016,7 +1017,7 @@ static int rs600_startup(struct radeon_device *rdev)
return r;
}
- r = r600_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r) {
dev_err(rdev->dev, "failed initializing audio\n");
return r;
@@ -1057,7 +1058,7 @@ int rs600_resume(struct radeon_device *rdev)
int rs600_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r100_cp_disable(rdev);
radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
@@ -1068,7 +1069,7 @@ int rs600_suspend(struct radeon_device *rdev)
void rs600_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r100_cp_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rs690.c b/drivers/gpu/drm/radeon/rs690.c
index 0a2d36e81108..516ca27cfa12 100644
--- a/drivers/gpu/drm/radeon/rs690.c
+++ b/drivers/gpu/drm/radeon/rs690.c
@@ -28,6 +28,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include "atom.h"
#include "rs690d.h"
@@ -729,7 +730,7 @@ static int rs690_startup(struct radeon_device *rdev)
return r;
}
- r = r600_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r) {
dev_err(rdev->dev, "failed initializing audio\n");
return r;
@@ -770,7 +771,7 @@ int rs690_resume(struct radeon_device *rdev)
int rs690_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r100_cp_disable(rdev);
radeon_wb_disable(rdev);
rs600_irq_disable(rdev);
@@ -781,7 +782,7 @@ int rs690_suspend(struct radeon_device *rdev)
void rs690_fini(struct radeon_device *rdev)
{
radeon_pm_fini(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
r100_cp_fini(rdev);
radeon_wb_fini(rdev);
radeon_ib_pool_fini(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770.c b/drivers/gpu/drm/radeon/rv770.c
index 372016e266d0..01ee96acb398 100644
--- a/drivers/gpu/drm/radeon/rv770.c
+++ b/drivers/gpu/drm/radeon/rv770.c
@@ -30,6 +30,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "rv770d.h"
#include "atom.h"
@@ -1788,7 +1789,7 @@ static int rv770_startup(struct radeon_device *rdev)
return r;
}
- r = r600_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r) {
DRM_ERROR("radeon: audio init failed\n");
return r;
@@ -1829,7 +1830,7 @@ int rv770_resume(struct radeon_device *rdev)
int rv770_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- r600_audio_fini(rdev);
+ radeon_audio_fini(rdev);
uvd_v1_0_fini(rdev);
radeon_uvd_suspend(rdev);
r700_cp_stop(rdev);
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.c b/drivers/gpu/drm/radeon/rv770_dpm.c
index 755a8f96fe46..306732641b23 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.c
+++ b/drivers/gpu/drm/radeon/rv770_dpm.c
@@ -231,6 +231,7 @@ u8 rv770_get_seq_value(struct radeon_device *rdev,
MC_CG_SEQ_DRAMCONF_S0 : MC_CG_SEQ_DRAMCONF_S1;
}
+#if 0
int rv770_read_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 *value)
{
@@ -240,6 +241,7 @@ int rv770_read_smc_soft_register(struct radeon_device *rdev,
pi->soft_regs_start + reg_offset,
value, pi->sram_end);
}
+#endif
int rv770_write_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 value)
@@ -2075,6 +2077,7 @@ int rv770_dpm_set_power_state(struct radeon_device *rdev)
return 0;
}
+#if 0
void rv770_dpm_reset_asic(struct radeon_device *rdev)
{
struct rv7xx_power_info *pi = rv770_get_pi(rdev);
@@ -2087,6 +2090,7 @@ void rv770_dpm_reset_asic(struct radeon_device *rdev)
if (pi->dcodt)
rv770_program_dcodt_after_state_switch(rdev, boot_ps, boot_ps);
}
+#endif
void rv770_dpm_setup_asic(struct radeon_device *rdev)
{
diff --git a/drivers/gpu/drm/radeon/rv770_dpm.h b/drivers/gpu/drm/radeon/rv770_dpm.h
index f776634840c9..d12beab7f3e6 100644
--- a/drivers/gpu/drm/radeon/rv770_dpm.h
+++ b/drivers/gpu/drm/radeon/rv770_dpm.h
@@ -278,8 +278,6 @@ void rv770_set_uvd_clock_after_set_eng_clock(struct radeon_device *rdev,
void rv770_get_engine_memory_ss(struct radeon_device *rdev);
/* smc */
-int rv770_read_smc_soft_register(struct radeon_device *rdev,
- u16 reg_offset, u32 *value);
int rv770_write_smc_soft_register(struct radeon_device *rdev,
u16 reg_offset, u32 value);
diff --git a/drivers/gpu/drm/radeon/si.c b/drivers/gpu/drm/radeon/si.c
index 5d89b874a1a2..bcf516a8a2f1 100644
--- a/drivers/gpu/drm/radeon/si.c
+++ b/drivers/gpu/drm/radeon/si.c
@@ -27,6 +27,7 @@
#include <drm/drmP.h>
#include "radeon.h"
#include "radeon_asic.h"
+#include "radeon_audio.h"
#include <drm/radeon_drm.h>
#include "sid.h"
#include "atom.h"
@@ -3161,6 +3162,8 @@ static void si_gpu_init(struct radeon_device *rdev)
}
WREG32(GRBM_CNTL, GRBM_READ_TIMEOUT(0xff));
+ WREG32(SRBM_INT_CNTL, 1);
+ WREG32(SRBM_INT_ACK, 1);
evergreen_fix_pci_max_read_req_size(rdev);
@@ -4698,12 +4701,6 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
switch (pkt.type) {
case RADEON_PACKET_TYPE0:
dev_err(rdev->dev, "Packet0 not allowed!\n");
- for (i = 0; i < ib->length_dw; i++) {
- if (i == idx)
- printk("\t0x%08x <---\n", ib->ptr[i]);
- else
- printk("\t0x%08x\n", ib->ptr[i]);
- }
ret = -EINVAL;
break;
case RADEON_PACKET_TYPE2:
@@ -4735,8 +4732,15 @@ int si_ib_parse(struct radeon_device *rdev, struct radeon_ib *ib)
ret = -EINVAL;
break;
}
- if (ret)
+ if (ret) {
+ for (i = 0; i < ib->length_dw; i++) {
+ if (i == idx)
+ printk("\t0x%08x <---\n", ib->ptr[i]);
+ else
+ printk("\t0x%08x\n", ib->ptr[i]);
+ }
break;
+ }
} while (idx < ib->length_dw);
return ret;
@@ -5909,6 +5913,7 @@ static void si_disable_interrupt_state(struct radeon_device *rdev)
tmp = RREG32(DMA_CNTL + DMA1_REGISTER_OFFSET) & ~TRAP_ENABLE;
WREG32(DMA_CNTL + DMA1_REGISTER_OFFSET, tmp);
WREG32(GRBM_INT_CNTL, 0);
+ WREG32(SRBM_INT_CNTL, 0);
if (rdev->num_crtc >= 2) {
WREG32(INT_MASK + EVERGREEN_CRTC0_REGISTER_OFFSET, 0);
WREG32(INT_MASK + EVERGREEN_CRTC1_REGISTER_OFFSET, 0);
@@ -6608,6 +6613,10 @@ restart_ih:
break;
}
break;
+ case 96:
+ DRM_ERROR("SRBM_READ_ERROR: 0x%x\n", RREG32(SRBM_READ_ERROR));
+ WREG32(SRBM_INT_ACK, 0x1);
+ break;
case 124: /* UVD */
DRM_DEBUG("IH: UVD int: 0x%08x\n", src_data);
radeon_fence_process(rdev, R600_RING_TYPE_UVD_INDEX);
@@ -6869,7 +6878,7 @@ static int si_startup(struct radeon_device *rdev)
return r;
}
- r = dce6_audio_init(rdev);
+ r = radeon_audio_init(rdev);
if (r)
return r;
@@ -6908,7 +6917,7 @@ int si_resume(struct radeon_device *rdev)
int si_suspend(struct radeon_device *rdev)
{
radeon_pm_suspend(rdev);
- dce6_audio_fini(rdev);
+ radeon_audio_fini(rdev);
radeon_vm_manager_fini(rdev);
si_cp_enable(rdev, false);
cayman_dma_stop(rdev);
diff --git a/drivers/gpu/drm/radeon/si_dpm.c b/drivers/gpu/drm/radeon/si_dpm.c
index eff8a6444956..7be11651b7e6 100644
--- a/drivers/gpu/drm/radeon/si_dpm.c
+++ b/drivers/gpu/drm/radeon/si_dpm.c
@@ -1756,6 +1756,9 @@ static int si_calculate_sclk_params(struct radeon_device *rdev,
u32 engine_clock,
SISLANDS_SMC_SCLK_VALUE *sclk);
+static void si_thermal_start_smc_fan_control(struct radeon_device *rdev);
+static void si_fan_ctrl_set_default_mode(struct radeon_device *rdev);
+
static struct si_power_info *si_get_pi(struct radeon_device *rdev)
{
struct si_power_info *pi = rdev->pm.dpm.priv;
@@ -3359,11 +3362,13 @@ int si_dpm_force_performance_level(struct radeon_device *rdev,
return 0;
}
+#if 0
static int si_set_boot_state(struct radeon_device *rdev)
{
return (si_send_msg_to_smc(rdev, PPSMC_MSG_SwitchToInitialState) == PPSMC_Result_OK) ?
0 : -EINVAL;
}
+#endif
static int si_set_sw_state(struct radeon_device *rdev)
{
@@ -5973,6 +5978,10 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev)
slope1 = (u16)((50 + ((16 * duty100 * pwm_diff1) / t_diff1)) / 100);
slope2 = (u16)((50 + ((16 * duty100 * pwm_diff2) / t_diff2)) / 100);
+ fan_table.temp_min = cpu_to_be16((50 + rdev->pm.dpm.fan.t_min) / 100);
+ fan_table.temp_med = cpu_to_be16((50 + rdev->pm.dpm.fan.t_med) / 100);
+ fan_table.temp_max = cpu_to_be16((50 + rdev->pm.dpm.fan.t_max) / 100);
+
fan_table.slope1 = cpu_to_be16(slope1);
fan_table.slope2 = cpu_to_be16(slope2);
@@ -6012,29 +6021,35 @@ static int si_thermal_setup_fan_table(struct radeon_device *rdev)
static int si_fan_ctrl_start_smc_fan_control(struct radeon_device *rdev)
{
+ struct si_power_info *si_pi = si_get_pi(rdev);
PPSMC_Result ret;
ret = si_send_msg_to_smc(rdev, PPSMC_StartFanControl);
- if (ret == PPSMC_Result_OK)
+ if (ret == PPSMC_Result_OK) {
+ si_pi->fan_is_controlled_by_smc = true;
return 0;
- else
+ } else {
return -EINVAL;
+ }
}
static int si_fan_ctrl_stop_smc_fan_control(struct radeon_device *rdev)
{
+ struct si_power_info *si_pi = si_get_pi(rdev);
PPSMC_Result ret;
ret = si_send_msg_to_smc(rdev, PPSMC_StopFanControl);
- if (ret == PPSMC_Result_OK)
+
+ if (ret == PPSMC_Result_OK) {
+ si_pi->fan_is_controlled_by_smc = false;
return 0;
- else
+ } else {
return -EINVAL;
+ }
}
-#if 0
-static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
- u32 *speed)
+int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
+ u32 *speed)
{
u32 duty, duty100;
u64 tmp64;
@@ -6058,9 +6073,10 @@ static int si_fan_ctrl_get_fan_speed_percent(struct radeon_device *rdev,
return 0;
}
-static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
- u32 speed)
+int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
+ u32 speed)
{
+ struct si_power_info *si_pi = si_get_pi(rdev);
u32 tmp;
u32 duty, duty100;
u64 tmp64;
@@ -6068,11 +6084,11 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
if (rdev->pm.no_fan)
return -ENOENT;
- if (speed > 100)
+ if (si_pi->fan_is_controlled_by_smc)
return -EINVAL;
- if (rdev->pm.dpm.fan.ucode_fan_control)
- si_fan_ctrl_stop_smc_fan_control(rdev);
+ if (speed > 100)
+ return -EINVAL;
duty100 = (RREG32(CG_FDO_CTRL1) & FMAX_DUTY100_MASK) >> FMAX_DUTY100_SHIFT;
@@ -6087,11 +6103,38 @@ static int si_fan_ctrl_set_fan_speed_percent(struct radeon_device *rdev,
tmp |= FDO_STATIC_DUTY(duty);
WREG32(CG_FDO_CTRL0, tmp);
- si_fan_ctrl_set_static_mode(rdev, FDO_PWM_MODE_STATIC);
-
return 0;
}
+void si_fan_ctrl_set_mode(struct radeon_device *rdev, u32 mode)
+{
+ if (mode) {
+ /* stop auto-manage */
+ if (rdev->pm.dpm.fan.ucode_fan_control)
+ si_fan_ctrl_stop_smc_fan_control(rdev);
+ si_fan_ctrl_set_static_mode(rdev, mode);
+ } else {
+ /* restart auto-manage */
+ if (rdev->pm.dpm.fan.ucode_fan_control)
+ si_thermal_start_smc_fan_control(rdev);
+ else
+ si_fan_ctrl_set_default_mode(rdev);
+ }
+}
+
+u32 si_fan_ctrl_get_mode(struct radeon_device *rdev)
+{
+ struct si_power_info *si_pi = si_get_pi(rdev);
+ u32 tmp;
+
+ if (si_pi->fan_is_controlled_by_smc)
+ return 0;
+
+ tmp = RREG32(CG_FDO_CTRL2) & FDO_PWM_MODE_MASK;
+ return (tmp >> FDO_PWM_MODE_SHIFT);
+}
+
+#if 0
static int si_fan_ctrl_get_fan_speed_rpm(struct radeon_device *rdev,
u32 *speed)
{
@@ -6538,13 +6581,14 @@ void si_dpm_post_set_power_state(struct radeon_device *rdev)
ni_update_current_ps(rdev, new_ps);
}
-
+#if 0
void si_dpm_reset_asic(struct radeon_device *rdev)
{
si_restrict_performance_levels_before_switch(rdev);
si_disable_ulv(rdev);
si_set_boot_state(rdev);
}
+#endif
void si_dpm_display_configuration_changed(struct radeon_device *rdev)
{
@@ -6912,7 +6956,6 @@ int si_dpm_init(struct radeon_device *rdev)
rdev->pm.dpm.dyn_state.max_clock_voltage_on_ac;
si_pi->fan_ctrl_is_in_default_mode = true;
- rdev->pm.dpm.fan.ucode_fan_control = false;
return 0;
}
diff --git a/drivers/gpu/drm/radeon/si_dpm.h b/drivers/gpu/drm/radeon/si_dpm.h
index d16bb1b5f10f..1032a68be792 100644
--- a/drivers/gpu/drm/radeon/si_dpm.h
+++ b/drivers/gpu/drm/radeon/si_dpm.h
@@ -202,6 +202,7 @@ struct si_power_info {
bool fan_ctrl_is_in_default_mode;
u32 t_min;
u32 fan_ctrl_default_mode;
+ bool fan_is_controlled_by_smc;
};
#define SISLANDS_INITIAL_STATE_ARB_INDEX 0
diff --git a/drivers/gpu/drm/radeon/sid.h b/drivers/gpu/drm/radeon/sid.h
index 84999242c747..c27118cab16a 100644
--- a/drivers/gpu/drm/radeon/sid.h
+++ b/drivers/gpu/drm/radeon/sid.h
@@ -358,6 +358,10 @@
#define CC_SYS_RB_BACKEND_DISABLE 0xe80
#define GC_USER_SYS_RB_BACKEND_DISABLE 0xe84
+#define SRBM_READ_ERROR 0xE98
+#define SRBM_INT_CNTL 0xEA0
+#define SRBM_INT_ACK 0xEA8
+
#define SRBM_STATUS2 0x0EC4
#define DMA_BUSY (1 << 5)
#define DMA1_BUSY (1 << 6)
@@ -901,6 +905,16 @@
/* 0x6e98, 0x7a98, 0x10698, 0x11298, 0x11e98, 0x12a98 */
#define CRTC_STATUS_FRAME_COUNT 0x6e98
+/* Audio clocks */
+#define DCCG_AUDIO_DTO_SOURCE 0x05ac
+# define DCCG_AUDIO_DTO0_SOURCE_SEL(x) ((x) << 0) /* crtc0 - crtc5 */
+# define DCCG_AUDIO_DTO_SEL (1 << 4) /* 0=dto0 1=dto1 */
+
+#define DCCG_AUDIO_DTO0_PHASE 0x05b0
+#define DCCG_AUDIO_DTO0_MODULE 0x05b4
+#define DCCG_AUDIO_DTO1_PHASE 0x05b8
+#define DCCG_AUDIO_DTO1_MODULE 0x05bc
+
#define AFMT_AUDIO_SRC_CONTROL 0x713c
#define AFMT_AUDIO_SRC_SELECT(x) (((x) & 7) << 0)
/* AFMT_AUDIO_SRC_SELECT
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.c b/drivers/gpu/drm/radeon/sumo_dpm.c
index 1f8a8833e1be..25fd4ced36c8 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.c
+++ b/drivers/gpu/drm/radeon/sumo_dpm.c
@@ -1338,6 +1338,7 @@ void sumo_dpm_post_set_power_state(struct radeon_device *rdev)
sumo_update_current_ps(rdev, new_ps);
}
+#if 0
void sumo_dpm_reset_asic(struct radeon_device *rdev)
{
sumo_program_bootup_state(rdev);
@@ -1349,6 +1350,7 @@ void sumo_dpm_reset_asic(struct radeon_device *rdev)
sumo_set_forced_mode_enabled(rdev);
sumo_set_forced_mode_disabled(rdev);
}
+#endif
void sumo_dpm_setup_asic(struct radeon_device *rdev)
{
@@ -1537,6 +1539,7 @@ u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_7bit;
}
+#if 0
u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
struct sumo_vid_mapping_table *vid_mapping_table,
u32 vid_7bit)
@@ -1550,6 +1553,7 @@ u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
return vid_mapping_table->entries[vid_mapping_table->num_entries - 1].vid_2bit;
}
+#endif
static u16 sumo_convert_voltage_index_to_value(struct radeon_device *rdev,
u32 vid_2bit)
diff --git a/drivers/gpu/drm/radeon/sumo_dpm.h b/drivers/gpu/drm/radeon/sumo_dpm.h
index db1ea32a907b..07dda299c784 100644
--- a/drivers/gpu/drm/radeon/sumo_dpm.h
+++ b/drivers/gpu/drm/radeon/sumo_dpm.h
@@ -202,9 +202,6 @@ void sumo_construct_vid_mapping_table(struct radeon_device *rdev,
u32 sumo_convert_vid2_to_vid7(struct radeon_device *rdev,
struct sumo_vid_mapping_table *vid_mapping_table,
u32 vid_2bit);
-u32 sumo_convert_vid7_to_vid2(struct radeon_device *rdev,
- struct sumo_vid_mapping_table *vid_mapping_table,
- u32 vid_7bit);
u32 sumo_get_sleep_divider_from_id(u32 id);
u32 sumo_get_sleep_divider_id_from_clock(struct radeon_device *rdev,
u32 sclk,
diff --git a/drivers/gpu/drm/radeon/trinity_dpm.c b/drivers/gpu/drm/radeon/trinity_dpm.c
index b4ec5c4e7969..38dacb7a3689 100644
--- a/drivers/gpu/drm/radeon/trinity_dpm.c
+++ b/drivers/gpu/drm/radeon/trinity_dpm.c
@@ -1269,6 +1269,7 @@ void trinity_dpm_setup_asic(struct radeon_device *rdev)
trinity_release_mutex(rdev);
}
+#if 0
void trinity_dpm_reset_asic(struct radeon_device *rdev)
{
struct trinity_power_info *pi = trinity_get_pi(rdev);
@@ -1284,6 +1285,7 @@ void trinity_dpm_reset_asic(struct radeon_device *rdev)
}
trinity_release_mutex(rdev);
}
+#endif
static u16 trinity_convert_voltage_index_to_value(struct radeon_device *rdev,
u32 vid_2bit)
diff --git a/drivers/gpu/drm/rcar-du/Kconfig b/drivers/gpu/drm/rcar-du/Kconfig
index 2324a526de65..11485a4a16ae 100644
--- a/drivers/gpu/drm/rcar-du/Kconfig
+++ b/drivers/gpu/drm/rcar-du/Kconfig
@@ -1,6 +1,6 @@
config DRM_RCAR_DU
tristate "DRM Support for R-Car Display Unit"
- depends on DRM && ARM
+ depends on DRM && ARM && HAVE_DMA_ATTRS
depends on ARCH_SHMOBILE || COMPILE_TEST
select DRM_KMS_HELPER
select DRM_KMS_CMA_HELPER
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
index 23cc910951f4..25c7a998fc2c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.c
@@ -74,39 +74,77 @@ static int rcar_du_crtc_get(struct rcar_du_crtc *rcrtc)
if (ret < 0)
return ret;
+ ret = clk_prepare_enable(rcrtc->extclock);
+ if (ret < 0)
+ goto error_clock;
+
ret = rcar_du_group_get(rcrtc->group);
if (ret < 0)
- clk_disable_unprepare(rcrtc->clock);
+ goto error_group;
+
+ return 0;
+error_group:
+ clk_disable_unprepare(rcrtc->extclock);
+error_clock:
+ clk_disable_unprepare(rcrtc->clock);
return ret;
}
static void rcar_du_crtc_put(struct rcar_du_crtc *rcrtc)
{
rcar_du_group_put(rcrtc->group);
+
+ clk_disable_unprepare(rcrtc->extclock);
clk_disable_unprepare(rcrtc->clock);
}
static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
{
const struct drm_display_mode *mode = &rcrtc->crtc.mode;
+ unsigned long mode_clock = mode->clock * 1000;
unsigned long clk;
u32 value;
+ u32 escr;
u32 div;
- /* Dot clock */
+ /* Compute the clock divisor and select the internal or external dot
+ * clock based on the requested frequency.
+ */
clk = clk_get_rate(rcrtc->clock);
- div = DIV_ROUND_CLOSEST(clk, mode->clock * 1000);
+ div = DIV_ROUND_CLOSEST(clk, mode_clock);
div = clamp(div, 1U, 64U) - 1;
+ escr = div | ESCR_DCLKSEL_CLKS;
+
+ if (rcrtc->extclock) {
+ unsigned long extclk;
+ unsigned long extrate;
+ unsigned long rate;
+ u32 extdiv;
+
+ extclk = clk_get_rate(rcrtc->extclock);
+ extdiv = DIV_ROUND_CLOSEST(extclk, mode_clock);
+ extdiv = clamp(extdiv, 1U, 64U) - 1;
+
+ rate = clk / (div + 1);
+ extrate = extclk / (extdiv + 1);
+
+ if (abs((long)extrate - (long)mode_clock) <
+ abs((long)rate - (long)mode_clock)) {
+ dev_dbg(rcrtc->group->dev->dev,
+ "crtc%u: using external clock\n", rcrtc->index);
+ escr = extdiv | ESCR_DCLKSEL_DCLKIN;
+ }
+ }
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? ESCR2 : ESCR,
- ESCR_DCLKSEL_CLKS | div);
+ escr);
rcar_du_group_write(rcrtc->group, rcrtc->index % 2 ? OTAR2 : OTAR, 0);
/* Signal polarities */
value = ((mode->flags & DRM_MODE_FLAG_PVSYNC) ? 0 : DSMR_VSL)
| ((mode->flags & DRM_MODE_FLAG_PHSYNC) ? 0 : DSMR_HSL)
- | DSMR_DIPM_DE;
+ | DSMR_DIPM_DE | DSMR_CSPM;
rcar_du_crtc_write(rcrtc, DSMR, value);
/* Display timings */
@@ -117,12 +155,15 @@ static void rcar_du_crtc_set_display_timing(struct rcar_du_crtc *rcrtc)
mode->hsync_start - 1);
rcar_du_crtc_write(rcrtc, HCR, mode->htotal - 1);
- rcar_du_crtc_write(rcrtc, VDSR, mode->vtotal - mode->vsync_end - 2);
- rcar_du_crtc_write(rcrtc, VDER, mode->vtotal - mode->vsync_end +
- mode->vdisplay - 2);
- rcar_du_crtc_write(rcrtc, VSPR, mode->vtotal - mode->vsync_end +
- mode->vsync_start - 1);
- rcar_du_crtc_write(rcrtc, VCR, mode->vtotal - 1);
+ rcar_du_crtc_write(rcrtc, VDSR, mode->crtc_vtotal -
+ mode->crtc_vsync_end - 2);
+ rcar_du_crtc_write(rcrtc, VDER, mode->crtc_vtotal -
+ mode->crtc_vsync_end +
+ mode->crtc_vdisplay - 2);
+ rcar_du_crtc_write(rcrtc, VSPR, mode->crtc_vtotal -
+ mode->crtc_vsync_end +
+ mode->crtc_vsync_start - 1);
+ rcar_du_crtc_write(rcrtc, VCR, mode->crtc_vtotal - 1);
rcar_du_crtc_write(rcrtc, DESR, mode->htotal - mode->hsync_start);
rcar_du_crtc_write(rcrtc, DEWR, mode->hdisplay);
@@ -139,9 +180,10 @@ void rcar_du_crtc_route_output(struct drm_crtc *crtc,
*/
rcrtc->outputs |= BIT(output);
- /* Store RGB routing to DPAD0 for R8A7790. */
- if (rcar_du_has(rcdu, RCAR_DU_FEATURE_DEFR8) &&
- output == RCAR_DU_OUTPUT_DPAD0)
+ /* Store RGB routing to DPAD0, the hardware will be configured when
+ * starting the CRTC.
+ */
+ if (output == RCAR_DU_OUTPUT_DPAD0)
rcdu->dpad0_source = rcrtc->index;
}
@@ -217,6 +259,7 @@ void rcar_du_crtc_update_planes(struct drm_crtc *crtc)
static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
{
struct drm_crtc *crtc = &rcrtc->crtc;
+ bool interlaced;
unsigned int i;
if (rcrtc->started)
@@ -252,7 +295,10 @@ static void rcar_du_crtc_start(struct rcar_du_crtc *rcrtc)
* sync mode (with the HSYNC and VSYNC signals configured as outputs and
* actively driven).
*/
- rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK, DSYSR_TVM_MASTER);
+ interlaced = rcrtc->crtc.mode.flags & DRM_MODE_FLAG_INTERLACE;
+ rcar_du_crtc_clr_set(rcrtc, DSYSR, DSYSR_TVM_MASK | DSYSR_SCM_MASK,
+ (interlaced ? DSYSR_SCM_INT_VIDEO : 0) |
+ DSYSR_TVM_MASTER);
rcar_du_group_start_stop(rcrtc->group, true);
@@ -308,6 +354,9 @@ static void rcar_du_crtc_dpms(struct drm_crtc *crtc, int mode)
{
struct rcar_du_crtc *rcrtc = to_rcar_crtc(crtc);
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
if (rcrtc->dpms == mode)
return;
@@ -486,7 +535,7 @@ static irqreturn_t rcar_du_crtc_irq(int irq, void *arg)
status = rcar_du_crtc_read(rcrtc, DSSR);
rcar_du_crtc_write(rcrtc, DSRCR, status & DSRCR_MASK);
- if (status & DSSR_VBK) {
+ if (status & DSSR_FRM) {
drm_handle_vblank(rcrtc->crtc.dev, rcrtc->index);
rcar_du_crtc_finish_page_flip(rcrtc);
ret = IRQ_HANDLED;
@@ -542,12 +591,13 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
struct rcar_du_crtc *rcrtc = &rcdu->crtcs[index];
struct drm_crtc *crtc = &rcrtc->crtc;
unsigned int irqflags;
- char clk_name[5];
+ struct clk *clk;
+ char clk_name[9];
char *name;
int irq;
int ret;
- /* Get the CRTC clock. */
+ /* Get the CRTC clock and the optional external clock. */
if (rcar_du_has(rcdu, RCAR_DU_FEATURE_CRTC_IRQ_CLOCK)) {
sprintf(clk_name, "du.%u", index);
name = clk_name;
@@ -561,6 +611,15 @@ int rcar_du_crtc_create(struct rcar_du_group *rgrp, unsigned int index)
return PTR_ERR(rcrtc->clock);
}
+ sprintf(clk_name, "dclkin.%u", index);
+ clk = devm_clk_get(rcdu->dev, clk_name);
+ if (!IS_ERR(clk)) {
+ rcrtc->extclock = clk;
+ } else if (PTR_ERR(rcrtc->clock) == -EPROBE_DEFER) {
+ dev_info(rcdu->dev, "can't get external clock %u\n", index);
+ return -EPROBE_DEFER;
+ }
+
rcrtc->group = rgrp;
rcrtc->mmio_offset = mmio_offsets[index];
rcrtc->index = index;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
index 984e6083699f..d2f89f7d2e5e 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_crtc.h
@@ -26,6 +26,7 @@ struct rcar_du_crtc {
struct drm_crtc crtc;
struct clk *clock;
+ struct clk *extclock;
unsigned int mmio_offset;
unsigned int index;
bool started;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.c b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
index 7bfa09cf18d5..e0d74f821416 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.c
@@ -56,7 +56,8 @@ static const struct rcar_du_device_info rcar_du_r8a7779_info = {
};
static const struct rcar_du_device_info rcar_du_r8a7790_info = {
- .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+ .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+ | RCAR_DU_FEATURE_EXT_CTRL_REGS,
.quirks = RCAR_DU_QUIRK_ALIGN_128B | RCAR_DU_QUIRK_LVDS_LANES,
.num_crtcs = 3,
.routes = {
@@ -83,7 +84,8 @@ static const struct rcar_du_device_info rcar_du_r8a7790_info = {
};
static const struct rcar_du_device_info rcar_du_r8a7791_info = {
- .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK | RCAR_DU_FEATURE_DEFR8,
+ .features = RCAR_DU_FEATURE_CRTC_IRQ_CLOCK
+ | RCAR_DU_FEATURE_EXT_CTRL_REGS,
.num_crtcs = 2,
.routes = {
/* R8A7791 has one RGB output, one LVDS output and one
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_drv.h b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
index 0a724669f02d..c5b9ea6a7eaa 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_drv.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_drv.h
@@ -27,7 +27,7 @@ struct rcar_du_device;
struct rcar_du_lvdsenc;
#define RCAR_DU_FEATURE_CRTC_IRQ_CLOCK (1 << 0) /* Per-CRTC IRQ and clock */
-#define RCAR_DU_FEATURE_DEFR8 (1 << 1) /* Has DEFR8 register */
+#define RCAR_DU_FEATURE_EXT_CTRL_REGS (1 << 1) /* Has extended control registers */
#define RCAR_DU_QUIRK_ALIGN_128B (1 << 0) /* Align pitches to 128 bytes */
#define RCAR_DU_QUIRK_LVDS_LANES (1 << 1) /* LVDS lanes 1 and 3 inverted */
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
index 34a122a39664..279167f783f6 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_encoder.c
@@ -46,6 +46,9 @@ static void rcar_du_encoder_dpms(struct drm_encoder *encoder, int mode)
{
struct rcar_du_encoder *renc = to_rcar_encoder(encoder);
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
if (renc->lvds)
rcar_du_lvdsenc_dpms(renc->lvds, encoder->crtc, mode);
}
@@ -190,35 +193,42 @@ int rcar_du_encoder_init(struct rcar_du_device *rcdu,
}
if (type == RCAR_DU_ENCODER_HDMI) {
- if (renc->lvds) {
- dev_err(rcdu->dev,
- "Chaining LVDS and HDMI encoders not supported\n");
- return -EINVAL;
- }
-
ret = rcar_du_hdmienc_init(rcdu, renc, enc_node);
if (ret < 0)
- return ret;
+ goto done;
} else {
ret = drm_encoder_init(rcdu->ddev, encoder, &encoder_funcs,
encoder_type);
if (ret < 0)
- return ret;
+ goto done;
drm_encoder_helper_add(encoder, &encoder_helper_funcs);
}
switch (encoder_type) {
case DRM_MODE_ENCODER_LVDS:
- return rcar_du_lvds_connector_init(rcdu, renc, con_node);
+ ret = rcar_du_lvds_connector_init(rcdu, renc, con_node);
+ break;
case DRM_MODE_ENCODER_DAC:
- return rcar_du_vga_connector_init(rcdu, renc);
+ ret = rcar_du_vga_connector_init(rcdu, renc);
+ break;
case DRM_MODE_ENCODER_TMDS:
- return rcar_du_hdmi_connector_init(rcdu, renc);
+ ret = rcar_du_hdmi_connector_init(rcdu, renc);
+ break;
default:
- return -EINVAL;
+ ret = -EINVAL;
+ break;
}
+
+done:
+ if (ret < 0) {
+ if (encoder->name)
+ encoder->funcs->destroy(encoder);
+ devm_kfree(rcdu->dev, renc);
+ }
+
+ return ret;
}
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_group.c b/drivers/gpu/drm/rcar-du/rcar_du_group.c
index 4e7614b145db..1bdc0ee0c248 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_group.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_group.c
@@ -48,9 +48,6 @@ static void rcar_du_group_setup_defr8(struct rcar_du_group *rgrp)
{
u32 defr8 = DEFR8_CODE | DEFR8_DEFE8;
- if (!rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_DEFR8))
- return;
-
/* The DEFR8 register for the first group also controls RGB output
* routing to DPAD0
*/
@@ -69,7 +66,20 @@ static void rcar_du_group_setup(struct rcar_du_group *rgrp)
rcar_du_group_write(rgrp, DEFR4, DEFR4_CODE);
rcar_du_group_write(rgrp, DEFR5, DEFR5_CODE | DEFR5_DEFE5);
- rcar_du_group_setup_defr8(rgrp);
+ if (rcar_du_has(rgrp->dev, RCAR_DU_FEATURE_EXT_CTRL_REGS)) {
+ rcar_du_group_setup_defr8(rgrp);
+
+ /* Configure input dot clock routing. We currently hardcode the
+ * configuration to routing DOTCLKINn to DUn.
+ */
+ rcar_du_group_write(rgrp, DIDSR, DIDSR_CODE |
+ DIDSR_LCDS_DCLKIN(2) |
+ DIDSR_LCDS_DCLKIN(1) |
+ DIDSR_LCDS_DCLKIN(0) |
+ DIDSR_PDCS_CLK(2, 0) |
+ DIDSR_PDCS_CLK(1, 0) |
+ DIDSR_PDCS_CLK(0, 0));
+ }
/* Use DS1PR and DS2PR to configure planes priorities and connects the
* superposition 0 to DU0 pins. DU1 pins will be configured dynamically.
@@ -149,6 +159,9 @@ static int rcar_du_set_dpad0_routing(struct rcar_du_device *rcdu)
{
int ret;
+ if (!rcar_du_has(rcdu, RCAR_DU_FEATURE_EXT_CTRL_REGS))
+ return 0;
+
/* RGB output routing to DPAD0 is configured in the DEFR8 register of
* the first group. As this function can be called with the DU0 and DU1
* CRTCs disabled, we need to enable the first group clock before
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
index 4d7d4dd46d26..ca94b029ac80 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmicon.c
@@ -95,6 +95,8 @@ int rcar_du_hdmi_connector_init(struct rcar_du_device *rcdu,
connector = &rcon->connector;
connector->display_info.width_mm = 0;
connector->display_info.height_mm = 0;
+ connector->interlace_allowed = true;
+ connector->polled = DRM_CONNECTOR_POLL_HPD;
ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_HDMIA);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
index 359bc999a9c8..221f0a17fd6a 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_hdmienc.c
@@ -21,6 +21,7 @@
#include "rcar_du_drv.h"
#include "rcar_du_encoder.h"
#include "rcar_du_hdmienc.h"
+#include "rcar_du_lvdsenc.h"
struct rcar_du_hdmienc {
struct rcar_du_encoder *renc;
@@ -36,12 +37,21 @@ static void rcar_du_hdmienc_dpms(struct drm_encoder *encoder, int mode)
struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ if (mode != DRM_MODE_DPMS_ON)
+ mode = DRM_MODE_DPMS_OFF;
+
if (hdmienc->dpms == mode)
return;
+ if (mode == DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
+ rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+
if (sfuncs->dpms)
sfuncs->dpms(encoder, mode);
+ if (mode != DRM_MODE_DPMS_ON && hdmienc->renc->lvds)
+ rcar_du_lvdsenc_dpms(hdmienc->renc->lvds, encoder->crtc, mode);
+
hdmienc->dpms = mode;
}
@@ -49,8 +59,16 @@ static bool rcar_du_hdmienc_mode_fixup(struct drm_encoder *encoder,
const struct drm_display_mode *mode,
struct drm_display_mode *adjusted_mode)
{
+ struct rcar_du_hdmienc *hdmienc = to_rcar_hdmienc(encoder);
struct drm_encoder_slave_funcs *sfuncs = to_slave_funcs(encoder);
+ /* The internal LVDS encoder has a clock frequency operating range of
+ * 30MHz to 150MHz. Clamp the clock accordingly.
+ */
+ if (hdmienc->renc->lvds)
+ adjusted_mode->clock = clamp(adjusted_mode->clock,
+ 30000, 150000);
+
if (sfuncs->mode_fixup == NULL)
return true;
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_kms.c b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
index 0c5ee616b5a3..cc9136e8ee9c 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_kms.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_kms.c
@@ -346,8 +346,14 @@ static int rcar_du_encoders_init(struct rcar_du_device *rcdu)
/* Process the output pipeline. */
ret = rcar_du_encoders_init_one(rcdu, output, &ep);
if (ret < 0) {
- of_node_put(ep_node);
- return ret;
+ if (ret == -EPROBE_DEFER) {
+ of_node_put(ep_node);
+ return ret;
+ }
+
+ dev_info(rcdu->dev,
+ "encoder initialization failed, skipping\n");
+ continue;
}
num_encoders += ret;
@@ -413,6 +419,11 @@ int rcar_du_modeset_init(struct rcar_du_device *rcdu)
if (ret < 0)
return ret;
+ if (ret == 0) {
+ dev_err(rcdu->dev, "error: no encoder could be initialized\n");
+ return -EINVAL;
+ }
+
num_encoders = ret;
/* Set the possible CRTCs and possible clones. There's always at least
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_plane.c b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
index 72a7cb47bd9f..50f2f2b20d39 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_plane.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_plane.c
@@ -104,14 +104,22 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
{
struct rcar_du_group *rgrp = plane->group;
unsigned int index = plane->hwindex;
+ bool interlaced;
u32 mwr;
- /* Memory pitch (expressed in pixels) */
+ interlaced = plane->crtc->mode.flags & DRM_MODE_FLAG_INTERLACE;
+
+ /* Memory pitch (expressed in pixels). Must be doubled for interlaced
+ * operation with 32bpp formats.
+ */
if (plane->format->planes == 2)
mwr = plane->pitch;
else
mwr = plane->pitch * 8 / plane->format->bpp;
+ if (interlaced && plane->format->bpp == 32)
+ mwr *= 2;
+
rcar_du_plane_write(rgrp, index, PnMWR, mwr);
/* The Y position is expressed in raster line units and must be doubled
@@ -119,17 +127,23 @@ void rcar_du_plane_update_base(struct rcar_du_plane *plane)
* doubling the Y position is found in the R8A7779 datasheet, but the
* rule seems to apply there as well.
*
+ * Despite not being documented, doubling seem not to be needed when
+ * operating in interlaced mode.
+ *
* Similarly, for the second plane, NV12 and NV21 formats seem to
- * require a halved Y position value.
+ * require a halved Y position value, in both progressive and interlaced
+ * modes.
*/
rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
- (plane->format->bpp == 32 ? 2 : 1));
+ (!interlaced && plane->format->bpp == 32 ? 2 : 1));
rcar_du_plane_write(rgrp, index, PnDSA0R, plane->dma[0]);
if (plane->format->planes == 2) {
index = (index + 1) % 8;
+ rcar_du_plane_write(rgrp, index, PnMWR, plane->pitch);
+
rcar_du_plane_write(rgrp, index, PnSPXR, plane->src_x);
rcar_du_plane_write(rgrp, index, PnSPYR, plane->src_y *
(plane->format->bpp == 16 ? 2 : 1) / 2);
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_regs.h b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
index 73f7347f740b..70fcbc471ebd 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_regs.h
+++ b/drivers/gpu/drm/rcar-du/rcar_du_regs.h
@@ -34,6 +34,7 @@
#define DSYSR_SCM_INT_NONE (0 << 4)
#define DSYSR_SCM_INT_SYNC (2 << 4)
#define DSYSR_SCM_INT_VIDEO (3 << 4)
+#define DSYSR_SCM_MASK (3 << 4)
#define DSMR 0x00004
#define DSMR_VSPM (1 << 28)
@@ -256,8 +257,8 @@
#define DIDSR_LCDS_LVDS0(n) (2 << (8 + (n) * 2))
#define DIDSR_LCDS_LVDS1(n) (3 << (8 + (n) * 2))
#define DIDSR_LCDS_MASK(n) (3 << (8 + (n) * 2))
-#define DIDSR_PCDS_CLK(n, clk) (clk << ((n) * 2))
-#define DIDSR_PCDS_MASK(n) (3 << ((n) * 2))
+#define DIDSR_PDCS_CLK(n, clk) (clk << ((n) * 2))
+#define DIDSR_PDCS_MASK(n) (3 << ((n) * 2))
/* -----------------------------------------------------------------------------
* Display Timing Generation Registers
diff --git a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
index 752747a5e920..9d4879921cc7 100644
--- a/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
+++ b/drivers/gpu/drm/rcar-du/rcar_du_vgacon.c
@@ -64,6 +64,7 @@ int rcar_du_vga_connector_init(struct rcar_du_device *rcdu,
connector = &rcon->connector;
connector->display_info.width_mm = 0;
connector->display_info.height_mm = 0;
+ connector->interlace_allowed = true;
ret = drm_connector_init(rcdu->ddev, connector, &connector_funcs,
DRM_MODE_CONNECTOR_VGA);
diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index ca9f085efa92..35215f6867d3 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -1,13 +1,13 @@
config DRM_ROCKCHIP
tristate "DRM Support for Rockchip"
depends on DRM && ROCKCHIP_IOMMU
+ depends on RESET_CONTROLLER
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select DRM_PANEL
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
- select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
select VIDEOMODE_HELPERS
help
Choose this option if you have a Rockchip soc chipset.
@@ -15,3 +15,13 @@ config DRM_ROCKCHIP
management to userspace. This driver does not provide
2D or 3D acceleration; acceleration is performed by other
IP found on the SoC.
+
+config ROCKCHIP_DW_HDMI
+ tristate "Rockchip specific extensions for Synopsys DW HDMI"
+ depends on DRM_ROCKCHIP
+ select DRM_DW_HDMI
+ help
+ This selects support for Rockchip SoC specific extensions
+ for the Synopsys DesignWare HDMI driver. If you want to
+ enable HDMI on RK3288 based SoC, you should selet this
+ option.
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 2cb0672f57ed..f3d8a19c641f 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -5,4 +5,6 @@
rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o rockchip_drm_fbdev.o \
rockchip_drm_gem.o
+obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
+
obj-$(CONFIG_DRM_ROCKCHIP) += rockchipdrm.o rockchip_drm_vop.o
diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
new file mode 100644
index 000000000000..d236faa05b19
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_encoder_slave.h>
+#include <drm/bridge/dw_hdmi.h>
+
+#include "rockchip_drm_drv.h"
+#include "rockchip_drm_vop.h"
+
+#define GRF_SOC_CON6 0x025c
+#define HDMI_SEL_VOP_LIT (1 << 4)
+
+struct rockchip_hdmi {
+ struct device *dev;
+ struct regmap *regmap;
+ struct drm_encoder encoder;
+};
+
+#define to_rockchip_hdmi(x) container_of(x, struct rockchip_hdmi, x)
+
+static const struct dw_hdmi_mpll_config rockchip_mpll_cfg[] = {
+ {
+ 27000000, {
+ { 0x00b3, 0x0000},
+ { 0x2153, 0x0000},
+ { 0x40f3, 0x0000}
+ },
+ }, {
+ 36000000, {
+ { 0x00b3, 0x0000},
+ { 0x2153, 0x0000},
+ { 0x40f3, 0x0000}
+ },
+ }, {
+ 40000000, {
+ { 0x00b3, 0x0000},
+ { 0x2153, 0x0000},
+ { 0x40f3, 0x0000}
+ },
+ }, {
+ 54000000, {
+ { 0x0072, 0x0001},
+ { 0x2142, 0x0001},
+ { 0x40a2, 0x0001},
+ },
+ }, {
+ 65000000, {
+ { 0x0072, 0x0001},
+ { 0x2142, 0x0001},
+ { 0x40a2, 0x0001},
+ },
+ }, {
+ 66000000, {
+ { 0x013e, 0x0003},
+ { 0x217e, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 74250000, {
+ { 0x0072, 0x0001},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 83500000, {
+ { 0x0072, 0x0001},
+ },
+ }, {
+ 108000000, {
+ { 0x0051, 0x0002},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 106500000, {
+ { 0x0051, 0x0002},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 146250000, {
+ { 0x0051, 0x0002},
+ { 0x2145, 0x0002},
+ { 0x4061, 0x0002}
+ },
+ }, {
+ 148500000, {
+ { 0x0051, 0x0003},
+ { 0x214c, 0x0003},
+ { 0x4064, 0x0003}
+ },
+ }, {
+ ~0UL, {
+ { 0x00a0, 0x000a },
+ { 0x2001, 0x000f },
+ { 0x4002, 0x000f },
+ },
+ }
+};
+
+static const struct dw_hdmi_curr_ctrl rockchip_cur_ctr[] = {
+ /* pixelclk bpp8 bpp10 bpp12 */
+ {
+ 40000000, { 0x0018, 0x0018, 0x0018 },
+ }, {
+ 65000000, { 0x0028, 0x0028, 0x0028 },
+ }, {
+ 66000000, { 0x0038, 0x0038, 0x0038 },
+ }, {
+ 74250000, { 0x0028, 0x0038, 0x0038 },
+ }, {
+ 83500000, { 0x0028, 0x0038, 0x0038 },
+ }, {
+ 146250000, { 0x0038, 0x0038, 0x0038 },
+ }, {
+ 148500000, { 0x0000, 0x0038, 0x0038 },
+ }, {
+ ~0UL, { 0x0000, 0x0000, 0x0000},
+ }
+};
+
+static const struct dw_hdmi_sym_term rockchip_sym_term[] = {
+ /*pixelclk symbol term*/
+ { 74250000, 0x8009, 0x0004 },
+ { 148500000, 0x8029, 0x0004 },
+ { 297000000, 0x8039, 0x0005 },
+ { ~0UL, 0x0000, 0x0000 }
+};
+
+static int rockchip_hdmi_parse_dt(struct rockchip_hdmi *hdmi)
+{
+ struct device_node *np = hdmi->dev->of_node;
+
+ hdmi->regmap = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+ if (IS_ERR(hdmi->regmap)) {
+ dev_err(hdmi->dev, "Unable to get rockchip,grf\n");
+ return PTR_ERR(hdmi->regmap);
+ }
+
+ return 0;
+}
+
+static enum drm_mode_status
+dw_hdmi_rockchip_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ const struct dw_hdmi_mpll_config *mpll_cfg = rockchip_mpll_cfg;
+ int pclk = mode->clock * 1000;
+ bool valid = false;
+ int i;
+
+ for (i = 0; mpll_cfg[i].mpixelclock != (~0UL); i++) {
+ if (pclk == mpll_cfg[i].mpixelclock) {
+ valid = true;
+ break;
+ }
+ }
+
+ return (valid) ? MODE_OK : MODE_BAD;
+}
+
+static struct drm_encoder_funcs dw_hdmi_rockchip_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static void dw_hdmi_rockchip_encoder_disable(struct drm_encoder *encoder)
+{
+}
+
+static bool
+dw_hdmi_rockchip_encoder_mode_fixup(struct drm_encoder *encoder,
+ const struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ return true;
+}
+
+static void dw_hdmi_rockchip_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+}
+
+static void dw_hdmi_rockchip_encoder_commit(struct drm_encoder *encoder)
+{
+ struct rockchip_hdmi *hdmi = to_rockchip_hdmi(encoder);
+ u32 val;
+ int mux;
+
+ mux = rockchip_drm_encoder_get_mux_id(hdmi->dev->of_node, encoder);
+ if (mux)
+ val = HDMI_SEL_VOP_LIT | (HDMI_SEL_VOP_LIT << 16);
+ else
+ val = HDMI_SEL_VOP_LIT << 16;
+
+ regmap_write(hdmi->regmap, GRF_SOC_CON6, val);
+ dev_dbg(hdmi->dev, "vop %s output to hdmi\n",
+ (mux) ? "LIT" : "BIG");
+}
+
+static void dw_hdmi_rockchip_encoder_prepare(struct drm_encoder *encoder)
+{
+ rockchip_drm_crtc_mode_config(encoder->crtc, DRM_MODE_CONNECTOR_HDMIA,
+ ROCKCHIP_OUT_MODE_AAAA);
+}
+
+static struct drm_encoder_helper_funcs dw_hdmi_rockchip_encoder_helper_funcs = {
+ .mode_fixup = dw_hdmi_rockchip_encoder_mode_fixup,
+ .mode_set = dw_hdmi_rockchip_encoder_mode_set,
+ .prepare = dw_hdmi_rockchip_encoder_prepare,
+ .commit = dw_hdmi_rockchip_encoder_commit,
+ .disable = dw_hdmi_rockchip_encoder_disable,
+};
+
+static const struct dw_hdmi_plat_data rockchip_hdmi_drv_data = {
+ .mode_valid = dw_hdmi_rockchip_mode_valid,
+ .mpll_cfg = rockchip_mpll_cfg,
+ .cur_ctr = rockchip_cur_ctr,
+ .sym_term = rockchip_sym_term,
+ .dev_type = RK3288_HDMI,
+};
+
+static const struct of_device_id dw_hdmi_rockchip_dt_ids[] = {
+ { .compatible = "rockchip,rk3288-dw-hdmi",
+ .data = &rockchip_hdmi_drv_data
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, dw_hdmi_rockchip_dt_ids);
+
+static int dw_hdmi_rockchip_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ const struct dw_hdmi_plat_data *plat_data;
+ const struct of_device_id *match;
+ struct drm_device *drm = data;
+ struct drm_encoder *encoder;
+ struct rockchip_hdmi *hdmi;
+ struct resource *iores;
+ int irq;
+ int ret;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ match = of_match_node(dw_hdmi_rockchip_dt_ids, pdev->dev.of_node);
+ plat_data = match->data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!iores)
+ return -ENXIO;
+
+ platform_set_drvdata(pdev, hdmi);
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (encoder->possible_crtcs == 0)
+ return -EPROBE_DEFER;
+
+ ret = rockchip_hdmi_parse_dt(hdmi);
+ if (ret) {
+ dev_err(hdmi->dev, "Unable to parse OF data\n");
+ return ret;
+ }
+
+ drm_encoder_helper_add(encoder, &dw_hdmi_rockchip_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &dw_hdmi_rockchip_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+
+ return dw_hdmi_bind(dev, master, data, encoder, iores, irq, plat_data);
+}
+
+static void dw_hdmi_rockchip_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ return dw_hdmi_unbind(dev, master, data);
+}
+
+static const struct component_ops dw_hdmi_rockchip_ops = {
+ .bind = dw_hdmi_rockchip_bind,
+ .unbind = dw_hdmi_rockchip_unbind,
+};
+
+static int dw_hdmi_rockchip_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &dw_hdmi_rockchip_ops);
+}
+
+static int dw_hdmi_rockchip_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &dw_hdmi_rockchip_ops);
+
+ return 0;
+}
+
+static struct platform_driver dw_hdmi_rockchip_pltfm_driver = {
+ .probe = dw_hdmi_rockchip_probe,
+ .remove = dw_hdmi_rockchip_remove,
+ .driver = {
+ .name = "dwhdmi-rockchip",
+ .of_match_table = dw_hdmi_rockchip_dt_ids,
+ },
+};
+
+module_platform_driver(dw_hdmi_rockchip_pltfm_driver);
+
+MODULE_AUTHOR("Andy Yan <andy.yan@rock-chips.com>");
+MODULE_AUTHOR("Yakir Yang <ykk@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip Specific DW-HDMI Driver Extension");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:dwhdmi-rockchip");
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index a798c7c71f91..21a481b224eb 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -390,6 +390,7 @@ int rockchip_drm_encoder_get_mux_id(struct device_node *node,
return -EINVAL;
}
+EXPORT_SYMBOL_GPL(rockchip_drm_encoder_get_mux_id);
static int compare_of(struct device *dev, void *data)
{
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
index bc98a227dc76..7ca8799ef784 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_gem.c
@@ -34,12 +34,9 @@ static int rockchip_gem_alloc_buf(struct rockchip_gem_object *rk_obj)
rk_obj->kvaddr = dma_alloc_attrs(drm->dev, obj->size,
&rk_obj->dma_addr, GFP_KERNEL,
&rk_obj->dma_attrs);
- if (IS_ERR(rk_obj->kvaddr)) {
- int ret = PTR_ERR(rk_obj->kvaddr);
-
- DRM_ERROR("failed to allocate %#x byte dma buffer, %d",
- obj->size, ret);
- return ret;
+ if (!rk_obj->kvaddr) {
+ DRM_ERROR("failed to allocate %#x byte dma buffer", obj->size);
+ return -ENOMEM;
}
return 0;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index e7ca25b3fb38..9a5c571b95fc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -735,6 +735,7 @@ int rockchip_drm_crtc_mode_config(struct drm_crtc *crtc,
return 0;
}
+EXPORT_SYMBOL_GPL(rockchip_drm_crtc_mode_config);
static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
{
diff --git a/drivers/gpu/drm/shmobile/Kconfig b/drivers/gpu/drm/shmobile/Kconfig
index a50fe0eeaa0d..b9202aa6f8ab 100644
--- a/drivers/gpu/drm/shmobile/Kconfig
+++ b/drivers/gpu/drm/shmobile/Kconfig
@@ -1,8 +1,10 @@
config DRM_SHMOBILE
tristate "DRM Support for SH Mobile"
- depends on DRM && ARM
+ depends on DRM && ARM && HAVE_DMA_ATTRS
depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on FB_SH_MOBILE_MERAM || !FB_SH_MOBILE_MERAM
select BACKLIGHT_CLASS_DEVICE
+ select BACKLIGHT_LCD_SUPPORT
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select DRM_KMS_CMA_HELPER
diff --git a/drivers/gpu/drm/sti/Kconfig b/drivers/gpu/drm/sti/Kconfig
index d6d6b705b8c1..fbccc105819b 100644
--- a/drivers/gpu/drm/sti/Kconfig
+++ b/drivers/gpu/drm/sti/Kconfig
@@ -1,10 +1,11 @@
config DRM_STI
tristate "DRM Support for STMicroelectronics SoC stiH41x Series"
- depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM)
+ depends on DRM && (SOC_STIH415 || SOC_STIH416 || ARCH_MULTIPLATFORM) && HAVE_DMA_ATTRS
select RESET_CONTROLLER
select DRM_KMS_HELPER
select DRM_GEM_CMA_HELPER
select DRM_KMS_CMA_HELPER
+ select DRM_PANEL
select FW_LOADER_USER_HELPER_FALLBACK
help
Choose this option to enable DRM on STM stiH41x chipset
diff --git a/drivers/gpu/drm/sti/Makefile b/drivers/gpu/drm/sti/Makefile
index 6ba9d27c1b90..f0f1e4ee2d92 100644
--- a/drivers/gpu/drm/sti/Makefile
+++ b/drivers/gpu/drm/sti/Makefile
@@ -12,6 +12,9 @@ stihdmi-y := sti_hdmi.o \
sti_hdmi_tx3g0c55phy.o \
sti_hdmi_tx3g4c28phy.o \
+stidvo-y := sti_dvo.o \
+ sti_awg_utils.o
+
obj-$(CONFIG_DRM_STI) = \
sti_vtg.o \
sti_vtac.o \
@@ -20,4 +23,5 @@ obj-$(CONFIG_DRM_STI) = \
sti_tvout.o \
sticompositor.o \
sti_hqvdp.o \
+ stidvo.o \
sti_drm_drv.o
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.c b/drivers/gpu/drm/sti/sti_awg_utils.c
new file mode 100644
index 000000000000..6029a2e3db1d
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_awg_utils.c
@@ -0,0 +1,182 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include "sti_awg_utils.h"
+
+#define AWG_OPCODE_OFFSET 10
+
+enum opcode {
+ SET,
+ RPTSET,
+ RPLSET,
+ SKIP,
+ STOP,
+ REPEAT,
+ REPLAY,
+ JUMP,
+ HOLD,
+};
+
+static int awg_generate_instr(enum opcode opcode,
+ long int arg,
+ long int mux_sel,
+ long int data_en,
+ struct awg_code_generation_params *fwparams)
+{
+ u32 instruction = 0;
+ u32 mux = (mux_sel << 8) & 0x1ff;
+ u32 data_enable = (data_en << 9) & 0x2ff;
+ long int arg_tmp = arg;
+
+ /* skip, repeat and replay arg should not exceed 1023.
+ * If user wants to exceed this value, the instruction should be
+ * duplicate and arg should be adjust for each duplicated instruction.
+ */
+
+ while (arg_tmp > 0) {
+ arg = arg_tmp;
+ if (fwparams->instruction_offset >= AWG_MAX_INST) {
+ DRM_ERROR("too many number of instructions\n");
+ return -EINVAL;
+ }
+
+ switch (opcode) {
+ case SKIP:
+ /* leave 'arg' + 1 pixel elapsing without changing
+ * output bus */
+ arg--; /* pixel adjustment */
+ arg_tmp--;
+
+ if (arg < 0) {
+ /* SKIP instruction not needed */
+ return 0;
+ }
+
+ if (arg == 0) {
+ /* SKIP 0 not permitted but we want to skip 1
+ * pixel. So we transform SKIP into SET
+ * instruction */
+ opcode = SET;
+ break;
+ }
+
+ mux = 0;
+ data_enable = 0;
+ arg = (arg << 22) >> 22;
+ arg &= (0x3ff);
+ break;
+ case REPEAT:
+ case REPLAY:
+ if (arg == 0) {
+ /* REPEAT or REPLAY instruction not needed */
+ return 0;
+ }
+
+ mux = 0;
+ data_enable = 0;
+ arg = (arg << 22) >> 22;
+ arg &= (0x3ff);
+ break;
+ case JUMP:
+ mux = 0;
+ data_enable = 0;
+ arg |= 0x40; /* for jump instruction 7th bit is 1 */
+ arg = (arg << 22) >> 22;
+ arg &= 0x3ff;
+ break;
+ case STOP:
+ arg = 0;
+ break;
+ case SET:
+ case RPTSET:
+ case RPLSET:
+ case HOLD:
+ arg = (arg << 24) >> 24;
+ arg &= (0x0ff);
+ break;
+ default:
+ DRM_ERROR("instruction %d does not exist\n", opcode);
+ return -EINVAL;
+ }
+
+ arg_tmp = arg_tmp - arg;
+
+ arg = ((arg + mux) + data_enable);
+
+ instruction = ((opcode) << AWG_OPCODE_OFFSET) | arg;
+ fwparams->ram_code[fwparams->instruction_offset] =
+ instruction & (0x3fff);
+ fwparams->instruction_offset++;
+ }
+ return 0;
+}
+
+int sti_awg_generate_code_data_enable_mode(
+ struct awg_code_generation_params *fwparams,
+ struct awg_timing *timing)
+{
+ long int val;
+ long int data_en;
+ int ret = 0;
+
+ if (timing->trailing_lines > 0) {
+ /* skip trailing lines */
+ val = timing->blanking_level;
+ data_en = 0;
+ ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
+
+ val = timing->trailing_lines - 1;
+ data_en = 0;
+ ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
+ }
+
+ if (timing->trailing_pixels > 0) {
+ /* skip trailing pixel */
+ val = timing->blanking_level;
+ data_en = 0;
+ ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
+
+ val = timing->trailing_pixels - 1;
+ data_en = 0;
+ ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
+ }
+
+ /* set DE signal high */
+ val = timing->blanking_level;
+ data_en = 1;
+ ret |= awg_generate_instr((timing->trailing_pixels > 0) ? SET : RPLSET,
+ val, 0, data_en, fwparams);
+
+ if (timing->blanking_pixels > 0) {
+ /* skip the number of active pixel */
+ val = timing->active_pixels - 1;
+ data_en = 1;
+ ret |= awg_generate_instr(SKIP, val, 0, data_en, fwparams);
+
+ /* set DE signal low */
+ val = timing->blanking_level;
+ data_en = 0;
+ ret |= awg_generate_instr(SET, val, 0, data_en, fwparams);
+ }
+
+ /* replay the sequence as many active lines defined */
+ val = timing->active_lines - 1;
+ data_en = 0;
+ ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
+
+ if (timing->blanking_lines > 0) {
+ /* skip blanking lines */
+ val = timing->blanking_level;
+ data_en = 0;
+ ret |= awg_generate_instr(RPLSET, val, 0, data_en, fwparams);
+
+ val = timing->blanking_lines - 1;
+ data_en = 0;
+ ret |= awg_generate_instr(REPLAY, val, 0, data_en, fwparams);
+ }
+
+ return ret;
+}
diff --git a/drivers/gpu/drm/sti/sti_awg_utils.h b/drivers/gpu/drm/sti/sti_awg_utils.h
new file mode 100644
index 000000000000..45d599bd570a
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_awg_utils.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#ifndef _STI_AWG_UTILS_H_
+#define _STI_AWG_UTILS_H_
+
+#include <drm/drmP.h>
+
+#define AWG_MAX_INST 64
+
+struct awg_code_generation_params {
+ u32 *ram_code;
+ u8 instruction_offset;
+};
+
+struct awg_timing {
+ u32 total_lines;
+ u32 active_lines;
+ u32 blanking_lines;
+ u32 trailing_lines;
+ u32 total_pixels;
+ u32 active_pixels;
+ u32 blanking_pixels;
+ u32 trailing_pixels;
+ u32 blanking_level;
+};
+
+int sti_awg_generate_code_data_enable_mode(
+ struct awg_code_generation_params *fw_gen_params,
+ struct awg_timing *timing);
+#endif
diff --git a/drivers/gpu/drm/sti/sti_drm_crtc.c b/drivers/gpu/drm/sti/sti_drm_crtc.c
index 4c651c200f20..e6f6ef7c4866 100644
--- a/drivers/gpu/drm/sti/sti_drm_crtc.c
+++ b/drivers/gpu/drm/sti/sti_drm_crtc.c
@@ -190,11 +190,6 @@ out:
return ret;
}
-static void sti_drm_crtc_load_lut(struct drm_crtc *crtc)
-{
- /* do nothing */
-}
-
static void sti_drm_crtc_disable(struct drm_crtc *crtc)
{
struct sti_mixer *mixer = to_sti_mixer(crtc);
@@ -249,7 +244,6 @@ static struct drm_crtc_helper_funcs sti_crtc_helper_funcs = {
.mode_fixup = sti_drm_crtc_mode_fixup,
.mode_set = sti_drm_crtc_mode_set,
.mode_set_base = sti_drm_crtc_mode_set_base,
- .load_lut = sti_drm_crtc_load_lut,
.disable = sti_drm_crtc_disable,
};
diff --git a/drivers/gpu/drm/sti/sti_dvo.c b/drivers/gpu/drm/sti/sti_dvo.c
new file mode 100644
index 000000000000..aeb5070c8363
--- /dev/null
+++ b/drivers/gpu/drm/sti/sti_dvo.c
@@ -0,0 +1,560 @@
+/*
+ * Copyright (C) STMicroelectronics SA 2014
+ * Author: Vincent Abriou <vincent.abriou@st.com> for STMicroelectronics.
+ * License terms: GNU General Public License (GPL), version 2
+ */
+
+#include <linux/clk.h>
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_panel.h>
+
+#include "sti_awg_utils.h"
+#include "sti_mixer.h"
+
+/* DVO registers */
+#define DVO_AWG_DIGSYNC_CTRL 0x0000
+#define DVO_DOF_CFG 0x0004
+#define DVO_LUT_PROG_LOW 0x0008
+#define DVO_LUT_PROG_MID 0x000C
+#define DVO_LUT_PROG_HIGH 0x0010
+#define DVO_DIGSYNC_INSTR_I 0x0100
+
+#define DVO_AWG_CTRL_EN BIT(0)
+#define DVO_AWG_FRAME_BASED_SYNC BIT(2)
+
+#define DVO_DOF_EN_LOWBYTE BIT(0)
+#define DVO_DOF_EN_MIDBYTE BIT(1)
+#define DVO_DOF_EN_HIGHBYTE BIT(2)
+#define DVO_DOF_EN BIT(6)
+#define DVO_DOF_MOD_COUNT_SHIFT 8
+
+#define DVO_LUT_ZERO 0
+#define DVO_LUT_Y_G 1
+#define DVO_LUT_Y_G_DEL 2
+#define DVO_LUT_CB_B 3
+#define DVO_LUT_CB_B_DEL 4
+#define DVO_LUT_CR_R 5
+#define DVO_LUT_CR_R_DEL 6
+#define DVO_LUT_HOLD 7
+
+struct dvo_config {
+ u32 flags;
+ u32 lowbyte;
+ u32 midbyte;
+ u32 highbyte;
+ int (*awg_fwgen_fct)(
+ struct awg_code_generation_params *fw_gen_params,
+ struct awg_timing *timing);
+};
+
+static struct dvo_config rgb_24bit_de_cfg = {
+ .flags = (0L << DVO_DOF_MOD_COUNT_SHIFT),
+ .lowbyte = DVO_LUT_CR_R,
+ .midbyte = DVO_LUT_Y_G,
+ .highbyte = DVO_LUT_CB_B,
+ .awg_fwgen_fct = sti_awg_generate_code_data_enable_mode,
+};
+
+/**
+ * STI digital video output structure
+ *
+ * @dev: driver device
+ * @drm_dev: pointer to drm device
+ * @mode: current display mode selected
+ * @regs: dvo registers
+ * @clk_pix: pixel clock for dvo
+ * @clk: clock for dvo
+ * @clk_main_parent: dvo parent clock if main path used
+ * @clk_aux_parent: dvo parent clock if aux path used
+ * @panel_node: panel node reference from device tree
+ * @panel: reference to the panel connected to the dvo
+ * @enabled: true if dvo is enabled else false
+ * @encoder: drm_encoder it is bound
+ */
+struct sti_dvo {
+ struct device dev;
+ struct drm_device *drm_dev;
+ struct drm_display_mode mode;
+ void __iomem *regs;
+ struct clk *clk_pix;
+ struct clk *clk;
+ struct clk *clk_main_parent;
+ struct clk *clk_aux_parent;
+ struct device_node *panel_node;
+ struct drm_panel *panel;
+ struct dvo_config *config;
+ bool enabled;
+ struct drm_encoder *encoder;
+ struct drm_bridge *bridge;
+};
+
+struct sti_dvo_connector {
+ struct drm_connector drm_connector;
+ struct drm_encoder *encoder;
+ struct sti_dvo *dvo;
+};
+
+#define to_sti_dvo_connector(x) \
+ container_of(x, struct sti_dvo_connector, drm_connector)
+
+#define BLANKING_LEVEL 16
+int dvo_awg_generate_code(struct sti_dvo *dvo, u8 *ram_size, u32 *ram_code)
+{
+ struct drm_display_mode *mode = &dvo->mode;
+ struct dvo_config *config = dvo->config;
+ struct awg_code_generation_params fw_gen_params;
+ struct awg_timing timing;
+
+ fw_gen_params.ram_code = ram_code;
+ fw_gen_params.instruction_offset = 0;
+
+ timing.total_lines = mode->vtotal;
+ timing.active_lines = mode->vdisplay;
+ timing.blanking_lines = mode->vsync_start - mode->vdisplay;
+ timing.trailing_lines = mode->vtotal - mode->vsync_start;
+ timing.total_pixels = mode->htotal;
+ timing.active_pixels = mode->hdisplay;
+ timing.blanking_pixels = mode->hsync_start - mode->hdisplay;
+ timing.trailing_pixels = mode->htotal - mode->hsync_start;
+ timing.blanking_level = BLANKING_LEVEL;
+
+ if (config->awg_fwgen_fct(&fw_gen_params, &timing)) {
+ DRM_ERROR("AWG firmware not properly generated\n");
+ return -EINVAL;
+ }
+
+ *ram_size = fw_gen_params.instruction_offset;
+
+ return 0;
+}
+
+/* Configure AWG, writing instructions
+ *
+ * @dvo: pointer to DVO structure
+ * @awg_ram_code: pointer to AWG instructions table
+ * @nb: nb of AWG instructions
+ */
+static void dvo_awg_configure(struct sti_dvo *dvo, u32 *awg_ram_code, int nb)
+{
+ int i;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ for (i = 0; i < nb; i++)
+ writel(awg_ram_code[i],
+ dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
+ for (i = nb; i < AWG_MAX_INST; i++)
+ writel(0, dvo->regs + DVO_DIGSYNC_INSTR_I + i * 4);
+
+ writel(DVO_AWG_CTRL_EN, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
+}
+
+static void sti_dvo_disable(struct drm_bridge *bridge)
+{
+ struct sti_dvo *dvo = bridge->driver_private;
+
+ if (!dvo->enabled)
+ return;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (dvo->config->awg_fwgen_fct)
+ writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
+
+ writel(0x00000000, dvo->regs + DVO_DOF_CFG);
+
+ if (dvo->panel)
+ dvo->panel->funcs->disable(dvo->panel);
+
+ /* Disable/unprepare dvo clock */
+ clk_disable_unprepare(dvo->clk_pix);
+ clk_disable_unprepare(dvo->clk);
+
+ dvo->enabled = false;
+}
+
+static void sti_dvo_pre_enable(struct drm_bridge *bridge)
+{
+ struct sti_dvo *dvo = bridge->driver_private;
+ struct dvo_config *config = dvo->config;
+ u32 val;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (dvo->enabled)
+ return;
+
+ /* Make sure DVO is disabled */
+ writel(0x00000000, dvo->regs + DVO_DOF_CFG);
+ writel(0x00000000, dvo->regs + DVO_AWG_DIGSYNC_CTRL);
+
+ if (config->awg_fwgen_fct) {
+ u8 nb_instr;
+ u32 awg_ram_code[AWG_MAX_INST];
+ /* Configure AWG */
+ if (!dvo_awg_generate_code(dvo, &nb_instr, awg_ram_code))
+ dvo_awg_configure(dvo, awg_ram_code, nb_instr);
+ else
+ return;
+ }
+
+ /* Prepare/enable clocks */
+ if (clk_prepare_enable(dvo->clk_pix))
+ DRM_ERROR("Failed to prepare/enable dvo_pix clk\n");
+ if (clk_prepare_enable(dvo->clk))
+ DRM_ERROR("Failed to prepare/enable dvo clk\n");
+
+ if (dvo->panel)
+ dvo->panel->funcs->enable(dvo->panel);
+
+ /* Set LUT */
+ writel(config->lowbyte, dvo->regs + DVO_LUT_PROG_LOW);
+ writel(config->midbyte, dvo->regs + DVO_LUT_PROG_MID);
+ writel(config->highbyte, dvo->regs + DVO_LUT_PROG_HIGH);
+
+ /* Digital output formatter config */
+ val = (config->flags | DVO_DOF_EN);
+ writel(val, dvo->regs + DVO_DOF_CFG);
+
+ dvo->enabled = true;
+}
+
+static void sti_dvo_set_mode(struct drm_bridge *bridge,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted_mode)
+{
+ struct sti_dvo *dvo = bridge->driver_private;
+ struct sti_mixer *mixer = to_sti_mixer(dvo->encoder->crtc);
+ int rate = mode->clock * 1000;
+ struct clk *clkp;
+ int ret;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ memcpy(&dvo->mode, mode, sizeof(struct drm_display_mode));
+
+ /* According to the path used (main or aux), the dvo clocks should
+ * have a different parent clock. */
+ if (mixer->id == STI_MIXER_MAIN)
+ clkp = dvo->clk_main_parent;
+ else
+ clkp = dvo->clk_aux_parent;
+
+ if (clkp) {
+ clk_set_parent(dvo->clk_pix, clkp);
+ clk_set_parent(dvo->clk, clkp);
+ }
+
+ /* DVO clocks = compositor clock */
+ ret = clk_set_rate(dvo->clk_pix, rate);
+ if (ret < 0) {
+ DRM_ERROR("Cannot set rate (%dHz) for dvo_pix clk\n", rate);
+ return;
+ }
+
+ ret = clk_set_rate(dvo->clk, rate);
+ if (ret < 0) {
+ DRM_ERROR("Cannot set rate (%dHz) for dvo clk\n", rate);
+ return;
+ }
+
+ /* For now, we only support 24bit data enable (DE) synchro format */
+ dvo->config = &rgb_24bit_de_cfg;
+}
+
+static void sti_dvo_bridge_nope(struct drm_bridge *bridge)
+{
+ /* do nothing */
+}
+
+static const struct drm_bridge_funcs sti_dvo_bridge_funcs = {
+ .pre_enable = sti_dvo_pre_enable,
+ .enable = sti_dvo_bridge_nope,
+ .disable = sti_dvo_disable,
+ .post_disable = sti_dvo_bridge_nope,
+ .mode_set = sti_dvo_set_mode,
+};
+
+static int sti_dvo_connector_get_modes(struct drm_connector *connector)
+{
+ struct sti_dvo_connector *dvo_connector
+ = to_sti_dvo_connector(connector);
+ struct sti_dvo *dvo = dvo_connector->dvo;
+
+ if (dvo->panel)
+ return dvo->panel->funcs->get_modes(dvo->panel);
+
+ return 0;
+}
+
+#define CLK_TOLERANCE_HZ 50
+
+static int sti_dvo_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ int target = mode->clock * 1000;
+ int target_min = target - CLK_TOLERANCE_HZ;
+ int target_max = target + CLK_TOLERANCE_HZ;
+ int result;
+ struct sti_dvo_connector *dvo_connector
+ = to_sti_dvo_connector(connector);
+ struct sti_dvo *dvo = dvo_connector->dvo;
+
+ result = clk_round_rate(dvo->clk_pix, target);
+
+ DRM_DEBUG_DRIVER("target rate = %d => available rate = %d\n",
+ target, result);
+
+ if ((result < target_min) || (result > target_max)) {
+ DRM_DEBUG_DRIVER("dvo pixclk=%d not supported\n", target);
+ return MODE_BAD;
+ }
+
+ return MODE_OK;
+}
+
+struct drm_encoder *sti_dvo_best_encoder(struct drm_connector *connector)
+{
+ struct sti_dvo_connector *dvo_connector
+ = to_sti_dvo_connector(connector);
+
+ /* Best encoder is the one associated during connector creation */
+ return dvo_connector->encoder;
+}
+
+static struct drm_connector_helper_funcs sti_dvo_connector_helper_funcs = {
+ .get_modes = sti_dvo_connector_get_modes,
+ .mode_valid = sti_dvo_connector_mode_valid,
+ .best_encoder = sti_dvo_best_encoder,
+};
+
+static enum drm_connector_status
+sti_dvo_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct sti_dvo_connector *dvo_connector
+ = to_sti_dvo_connector(connector);
+ struct sti_dvo *dvo = dvo_connector->dvo;
+
+ DRM_DEBUG_DRIVER("\n");
+
+ if (!dvo->panel)
+ dvo->panel = of_drm_find_panel(dvo->panel_node);
+
+ if (dvo->panel)
+ if (!drm_panel_attach(dvo->panel, connector))
+ return connector_status_connected;
+
+ return connector_status_disconnected;
+}
+
+static void sti_dvo_connector_destroy(struct drm_connector *connector)
+{
+ struct sti_dvo_connector *dvo_connector
+ = to_sti_dvo_connector(connector);
+
+ drm_connector_unregister(connector);
+ drm_connector_cleanup(connector);
+ kfree(dvo_connector);
+}
+
+static struct drm_connector_funcs sti_dvo_connector_funcs = {
+ .dpms = drm_helper_connector_dpms,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .detect = sti_dvo_connector_detect,
+ .destroy = sti_dvo_connector_destroy,
+};
+
+static struct drm_encoder *sti_dvo_find_encoder(struct drm_device *dev)
+{
+ struct drm_encoder *encoder;
+
+ list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+ if (encoder->encoder_type == DRM_MODE_ENCODER_LVDS)
+ return encoder;
+ }
+
+ return NULL;
+}
+
+static int sti_dvo_bind(struct device *dev, struct device *master, void *data)
+{
+ struct sti_dvo *dvo = dev_get_drvdata(dev);
+ struct drm_device *drm_dev = data;
+ struct drm_encoder *encoder;
+ struct sti_dvo_connector *connector;
+ struct drm_connector *drm_connector;
+ struct drm_bridge *bridge;
+ int err;
+
+ /* Set the drm device handle */
+ dvo->drm_dev = drm_dev;
+
+ encoder = sti_dvo_find_encoder(drm_dev);
+ if (!encoder)
+ return -ENOMEM;
+
+ connector = devm_kzalloc(dev, sizeof(*connector), GFP_KERNEL);
+ if (!connector)
+ return -ENOMEM;
+
+ connector->dvo = dvo;
+
+ bridge = devm_kzalloc(dev, sizeof(*bridge), GFP_KERNEL);
+ if (!bridge)
+ return -ENOMEM;
+
+ bridge->driver_private = dvo;
+ bridge->funcs = &sti_dvo_bridge_funcs;
+ bridge->of_node = dvo->dev.of_node;
+ err = drm_bridge_add(bridge);
+ if (err) {
+ DRM_ERROR("Failed to add bridge\n");
+ return err;
+ }
+
+ err = drm_bridge_attach(drm_dev, bridge);
+ if (err) {
+ DRM_ERROR("Failed to attach bridge\n");
+ return err;
+ }
+
+ dvo->bridge = bridge;
+ encoder->bridge = bridge;
+ connector->encoder = encoder;
+ dvo->encoder = encoder;
+
+ drm_connector = (struct drm_connector *)connector;
+
+ drm_connector->polled = DRM_CONNECTOR_POLL_HPD;
+
+ drm_connector_init(drm_dev, drm_connector,
+ &sti_dvo_connector_funcs, DRM_MODE_CONNECTOR_LVDS);
+ drm_connector_helper_add(drm_connector,
+ &sti_dvo_connector_helper_funcs);
+
+ err = drm_connector_register(drm_connector);
+ if (err)
+ goto err_connector;
+
+ err = drm_mode_connector_attach_encoder(drm_connector, encoder);
+ if (err) {
+ DRM_ERROR("Failed to attach a connector to a encoder\n");
+ goto err_sysfs;
+ }
+
+ return 0;
+
+err_sysfs:
+ drm_connector_unregister(drm_connector);
+err_connector:
+ drm_bridge_remove(bridge);
+ drm_connector_cleanup(drm_connector);
+ return -EINVAL;
+}
+
+static void sti_dvo_unbind(struct device *dev,
+ struct device *master, void *data)
+{
+ struct sti_dvo *dvo = dev_get_drvdata(dev);
+
+ drm_bridge_remove(dvo->bridge);
+}
+
+static const struct component_ops sti_dvo_ops = {
+ .bind = sti_dvo_bind,
+ .unbind = sti_dvo_unbind,
+};
+
+static int sti_dvo_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct sti_dvo *dvo;
+ struct resource *res;
+ struct device_node *np = dev->of_node;
+
+ DRM_INFO("%s\n", __func__);
+
+ dvo = devm_kzalloc(dev, sizeof(*dvo), GFP_KERNEL);
+ if (!dvo) {
+ DRM_ERROR("Failed to allocate memory for DVO\n");
+ return -ENOMEM;
+ }
+
+ dvo->dev = pdev->dev;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dvo-reg");
+ if (!res) {
+ DRM_ERROR("Invalid dvo resource\n");
+ return -ENOMEM;
+ }
+ dvo->regs = devm_ioremap_nocache(dev, res->start,
+ resource_size(res));
+ if (IS_ERR(dvo->regs))
+ return PTR_ERR(dvo->regs);
+
+ dvo->clk_pix = devm_clk_get(dev, "dvo_pix");
+ if (IS_ERR(dvo->clk_pix)) {
+ DRM_ERROR("Cannot get dvo_pix clock\n");
+ return PTR_ERR(dvo->clk_pix);
+ }
+
+ dvo->clk = devm_clk_get(dev, "dvo");
+ if (IS_ERR(dvo->clk)) {
+ DRM_ERROR("Cannot get dvo clock\n");
+ return PTR_ERR(dvo->clk);
+ }
+
+ dvo->clk_main_parent = devm_clk_get(dev, "main_parent");
+ if (IS_ERR(dvo->clk_main_parent)) {
+ DRM_DEBUG_DRIVER("Cannot get main_parent clock\n");
+ dvo->clk_main_parent = NULL;
+ }
+
+ dvo->clk_aux_parent = devm_clk_get(dev, "aux_parent");
+ if (IS_ERR(dvo->clk_aux_parent)) {
+ DRM_DEBUG_DRIVER("Cannot get aux_parent clock\n");
+ dvo->clk_aux_parent = NULL;
+ }
+
+ dvo->panel_node = of_parse_phandle(np, "sti,panel", 0);
+ if (!dvo->panel_node)
+ DRM_ERROR("No panel associated to the dvo output\n");
+
+ platform_set_drvdata(pdev, dvo);
+
+ return component_add(&pdev->dev, &sti_dvo_ops);
+}
+
+static int sti_dvo_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &sti_dvo_ops);
+ return 0;
+}
+
+static struct of_device_id dvo_of_match[] = {
+ { .compatible = "st,stih407-dvo", },
+ { /* end node */ }
+};
+MODULE_DEVICE_TABLE(of, dvo_of_match);
+
+struct platform_driver sti_dvo_driver = {
+ .driver = {
+ .name = "sti-dvo",
+ .owner = THIS_MODULE,
+ .of_match_table = dvo_of_match,
+ },
+ .probe = sti_dvo_probe,
+ .remove = sti_dvo_remove,
+};
+
+module_platform_driver(sti_dvo_driver);
+
+MODULE_AUTHOR("Benjamin Gaignard <benjamin.gaignard@st.com>");
+MODULE_DESCRIPTION("STMicroelectronics SoC DRM driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sti/sti_gdp.c b/drivers/gpu/drm/sti/sti_gdp.c
index 32448d1d1e8f..087906fd8846 100644
--- a/drivers/gpu/drm/sti/sti_gdp.c
+++ b/drivers/gpu/drm/sti/sti_gdp.c
@@ -14,15 +14,19 @@
#include "sti_layer.h"
#include "sti_vtg.h"
+#define ALPHASWITCH BIT(6)
#define ENA_COLOR_FILL BIT(8)
+#define BIGNOTLITTLE BIT(23)
#define WAIT_NEXT_VSYNC BIT(31)
/* GDP color formats */
#define GDP_RGB565 0x00
#define GDP_RGB888 0x01
#define GDP_RGB888_32 0x02
+#define GDP_XBGR8888 (GDP_RGB888_32 | BIGNOTLITTLE | ALPHASWITCH)
#define GDP_ARGB8565 0x04
#define GDP_ARGB8888 0x05
+#define GDP_ABGR8888 (GDP_ARGB8888 | BIGNOTLITTLE | ALPHASWITCH)
#define GDP_ARGB1555 0x06
#define GDP_ARGB4444 0x07
#define GDP_CLUT8 0x0B
@@ -103,7 +107,9 @@ struct sti_gdp {
static const uint32_t gdp_supported_formats[] = {
DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_XBGR8888,
DRM_FORMAT_ARGB8888,
+ DRM_FORMAT_ABGR8888,
DRM_FORMAT_ARGB4444,
DRM_FORMAT_ARGB1555,
DRM_FORMAT_RGB565,
@@ -129,8 +135,12 @@ static int sti_gdp_fourcc2format(int fourcc)
switch (fourcc) {
case DRM_FORMAT_XRGB8888:
return GDP_RGB888_32;
+ case DRM_FORMAT_XBGR8888:
+ return GDP_XBGR8888;
case DRM_FORMAT_ARGB8888:
return GDP_ARGB8888;
+ case DRM_FORMAT_ABGR8888:
+ return GDP_ABGR8888;
case DRM_FORMAT_ARGB4444:
return GDP_ARGB4444;
case DRM_FORMAT_ARGB1555:
@@ -157,6 +167,7 @@ static int sti_gdp_get_alpharange(int format)
case GDP_ARGB8565:
case GDP_ARGB8888:
case GDP_AYCBR8888:
+ case GDP_ABGR8888:
return GAM_GDP_ALPHARANGE_255;
}
return 0;
diff --git a/drivers/gpu/drm/sti/sti_hda.c b/drivers/gpu/drm/sti/sti_hda.c
index 2ae9a9b73666..a9bbb081ecad 100644
--- a/drivers/gpu/drm/sti/sti_hda.c
+++ b/drivers/gpu/drm/sti/sti_hda.c
@@ -508,19 +508,12 @@ static void sti_hda_bridge_nope(struct drm_bridge *bridge)
/* do nothing */
}
-static void sti_hda_brigde_destroy(struct drm_bridge *bridge)
-{
- drm_bridge_cleanup(bridge);
- kfree(bridge);
-}
-
static const struct drm_bridge_funcs sti_hda_bridge_funcs = {
.pre_enable = sti_hda_pre_enable,
.enable = sti_hda_bridge_nope,
.disable = sti_hda_disable,
.post_disable = sti_hda_bridge_nope,
.mode_set = sti_hda_set_mode,
- .destroy = sti_hda_brigde_destroy,
};
static int sti_hda_connector_get_modes(struct drm_connector *connector)
@@ -664,7 +657,8 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
return -ENOMEM;
bridge->driver_private = hda;
- drm_bridge_init(drm_dev, bridge, &sti_hda_bridge_funcs);
+ bridge->funcs = &sti_hda_bridge_funcs;
+ drm_bridge_attach(drm_dev, bridge);
encoder->bridge = bridge;
connector->encoder = encoder;
@@ -693,7 +687,6 @@ static int sti_hda_bind(struct device *dev, struct device *master, void *data)
err_sysfs:
drm_connector_unregister(drm_connector);
err_connector:
- drm_bridge_cleanup(bridge);
drm_connector_cleanup(drm_connector);
return -EINVAL;
}
diff --git a/drivers/gpu/drm/sti/sti_hdmi.c b/drivers/gpu/drm/sti/sti_hdmi.c
index d032e024b0b8..1485ade98710 100644
--- a/drivers/gpu/drm/sti/sti_hdmi.c
+++ b/drivers/gpu/drm/sti/sti_hdmi.c
@@ -42,8 +42,17 @@
#define HDMI_SW_DI_1_PKT_WORD5 0x0228
#define HDMI_SW_DI_1_PKT_WORD6 0x022C
#define HDMI_SW_DI_CFG 0x0230
+#define HDMI_SW_DI_2_HEAD_WORD 0x0600
+#define HDMI_SW_DI_2_PKT_WORD0 0x0604
+#define HDMI_SW_DI_2_PKT_WORD1 0x0608
+#define HDMI_SW_DI_2_PKT_WORD2 0x060C
+#define HDMI_SW_DI_2_PKT_WORD3 0x0610
+#define HDMI_SW_DI_2_PKT_WORD4 0x0614
+#define HDMI_SW_DI_2_PKT_WORD5 0x0618
+#define HDMI_SW_DI_2_PKT_WORD6 0x061C
#define HDMI_IFRAME_SLOT_AVI 1
+#define HDMI_IFRAME_SLOT_AUDIO 2
#define XCAT(prefix, x, suffix) prefix ## x ## suffix
#define HDMI_SW_DI_N_HEAD_WORD(x) XCAT(HDMI_SW_DI_, x, _HEAD_WORD)
@@ -99,6 +108,10 @@
#define HDMI_STA_SW_RST BIT(1)
+#define HDMI_INFOFRAME_HEADER_TYPE(x) (((x) & 0xff) << 0)
+#define HDMI_INFOFRAME_HEADER_VERSION(x) (((x) & 0xff) << 8)
+#define HDMI_INFOFRAME_HEADER_LEN(x) (((x) & 0x0f) << 16)
+
struct sti_hdmi_connector {
struct drm_connector drm_connector;
struct drm_encoder *encoder;
@@ -228,6 +241,90 @@ static void hdmi_config(struct sti_hdmi *hdmi)
}
/**
+ * Helper to concatenate infoframe in 32 bits word
+ *
+ * @ptr: pointer on the hdmi internal structure
+ * @data: infoframe to write
+ * @size: size to write
+ */
+static inline unsigned int hdmi_infoframe_subpack(const u8 *ptr, size_t size)
+{
+ unsigned long value = 0;
+ size_t i;
+
+ for (i = size; i > 0; i--)
+ value = (value << 8) | ptr[i - 1];
+
+ return value;
+}
+
+/**
+ * Helper to write info frame
+ *
+ * @hdmi: pointer on the hdmi internal structure
+ * @data: infoframe to write
+ * @size: size to write
+ */
+static void hdmi_infoframe_write_infopack(struct sti_hdmi *hdmi, const u8 *data)
+{
+ const u8 *ptr = data;
+ u32 val, slot, mode, i;
+ u32 head_offset, pack_offset;
+ size_t size;
+
+ switch (*ptr) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ slot = HDMI_IFRAME_SLOT_AVI;
+ mode = HDMI_IFRAME_FIELD;
+ head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI);
+ pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI);
+ size = HDMI_AVI_INFOFRAME_SIZE;
+ break;
+
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ slot = HDMI_IFRAME_SLOT_AUDIO;
+ mode = HDMI_IFRAME_FRAME;
+ head_offset = HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AUDIO);
+ pack_offset = HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AUDIO);
+ size = HDMI_AUDIO_INFOFRAME_SIZE;
+ break;
+
+ default:
+ DRM_ERROR("unsupported infoframe type: %#x\n", *ptr);
+ return;
+ }
+
+ /* Disable transmission slot for updated infoframe */
+ val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
+ val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, slot);
+ hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+
+ val = HDMI_INFOFRAME_HEADER_TYPE(*ptr++);
+ val |= HDMI_INFOFRAME_HEADER_VERSION(*ptr++);
+ val |= HDMI_INFOFRAME_HEADER_LEN(*ptr++);
+ writel(val, hdmi->regs + head_offset);
+
+ /*
+ * Each subpack contains 4 bytes
+ * The First Bytes of the first subpacket must contain the checksum
+ * Packet size in increase by one.
+ */
+ for (i = 0; i < size; i += sizeof(u32)) {
+ size_t num;
+
+ num = min_t(size_t, size - i, sizeof(u32));
+ val = hdmi_infoframe_subpack(ptr, num);
+ ptr += sizeof(u32);
+ writel(val, hdmi->regs + pack_offset + i);
+ }
+
+ /* Enable transmission slot for updated infoframe */
+ val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
+ val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, slot);
+ hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+}
+
+/**
* Prepare and configure the AVI infoframe
*
* AVI infoframe are transmitted at least once per two video field and
@@ -243,8 +340,6 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
struct drm_display_mode *mode = &hdmi->mode;
struct hdmi_avi_infoframe infoframe;
u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
- u8 *frame = buffer + HDMI_INFOFRAME_HEADER_SIZE;
- u32 val;
int ret;
DRM_DEBUG_DRIVER("\n");
@@ -266,47 +361,43 @@ static int hdmi_avi_infoframe_config(struct sti_hdmi *hdmi)
return ret;
}
- /* Disable transmission slot for AVI infoframe */
- val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
- val &= ~HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_MASK, HDMI_IFRAME_SLOT_AVI);
- hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+ hdmi_infoframe_write_infopack(hdmi, buffer);
- /* Infoframe header */
- val = buffer[0];
- val |= buffer[1] << 8;
- val |= buffer[2] << 16;
- hdmi_write(hdmi, val, HDMI_SW_DI_N_HEAD_WORD(HDMI_IFRAME_SLOT_AVI));
-
- /* Infoframe packet bytes */
- val = buffer[3];
- val |= *(frame++) << 8;
- val |= *(frame++) << 16;
- val |= *(frame++) << 24;
- hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD0(HDMI_IFRAME_SLOT_AVI));
-
- val = *(frame++);
- val |= *(frame++) << 8;
- val |= *(frame++) << 16;
- val |= *(frame++) << 24;
- hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD1(HDMI_IFRAME_SLOT_AVI));
-
- val = *(frame++);
- val |= *(frame++) << 8;
- val |= *(frame++) << 16;
- val |= *(frame++) << 24;
- hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD2(HDMI_IFRAME_SLOT_AVI));
-
- val = *(frame++);
- val |= *(frame) << 8;
- hdmi_write(hdmi, val, HDMI_SW_DI_N_PKT_WORD3(HDMI_IFRAME_SLOT_AVI));
-
- /* Enable transmission slot for AVI infoframe
- * According to the hdmi specification, AVI infoframe should be
- * transmitted at least once per two video fields
- */
- val = hdmi_read(hdmi, HDMI_SW_DI_CFG);
- val |= HDMI_IFRAME_CFG_DI_N(HDMI_IFRAME_FIELD, HDMI_IFRAME_SLOT_AVI);
- hdmi_write(hdmi, val, HDMI_SW_DI_CFG);
+ return 0;
+}
+
+/**
+ * Prepare and configure the AUDIO infoframe
+ *
+ * AUDIO infoframe are transmitted once per frame and
+ * contains information about HDMI transmission mode such as audio codec,
+ * sample size, ...
+ *
+ * @hdmi: pointer on the hdmi internal structure
+ *
+ * Return negative value if error occurs
+ */
+static int hdmi_audio_infoframe_config(struct sti_hdmi *hdmi)
+{
+ struct hdmi_audio_infoframe infofame;
+ u8 buffer[HDMI_INFOFRAME_SIZE(AUDIO)];
+ int ret;
+
+ ret = hdmi_audio_infoframe_init(&infofame);
+ if (ret < 0) {
+ DRM_ERROR("failed to setup audio infoframe: %d\n", ret);
+ return ret;
+ }
+
+ infofame.channels = 2;
+
+ ret = hdmi_audio_infoframe_pack(&infofame, buffer, sizeof(buffer));
+ if (ret < 0) {
+ DRM_ERROR("failed to pack audio infoframe: %d\n", ret);
+ return ret;
+ }
+
+ hdmi_infoframe_write_infopack(hdmi, buffer);
return 0;
}
@@ -427,6 +518,10 @@ static void sti_hdmi_pre_enable(struct drm_bridge *bridge)
if (hdmi_avi_infoframe_config(hdmi))
DRM_ERROR("Unable to configure AVI infoframe\n");
+ /* Program AUDIO infoframe */
+ if (hdmi_audio_infoframe_config(hdmi))
+ DRM_ERROR("Unable to configure AUDIO infoframe\n");
+
/* Sw reset */
hdmi_swreset(hdmi);
}
@@ -463,19 +558,12 @@ static void sti_hdmi_bridge_nope(struct drm_bridge *bridge)
/* do nothing */
}
-static void sti_hdmi_brigde_destroy(struct drm_bridge *bridge)
-{
- drm_bridge_cleanup(bridge);
- kfree(bridge);
-}
-
static const struct drm_bridge_funcs sti_hdmi_bridge_funcs = {
.pre_enable = sti_hdmi_pre_enable,
.enable = sti_hdmi_bridge_nope,
.disable = sti_hdmi_disable,
.post_disable = sti_hdmi_bridge_nope,
.mode_set = sti_hdmi_set_mode,
- .destroy = sti_hdmi_brigde_destroy,
};
static int sti_hdmi_connector_get_modes(struct drm_connector *connector)
@@ -635,7 +723,8 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
goto err_adapt;
bridge->driver_private = hdmi;
- drm_bridge_init(drm_dev, bridge, &sti_hdmi_bridge_funcs);
+ bridge->funcs = &sti_hdmi_bridge_funcs;
+ drm_bridge_attach(drm_dev, bridge);
encoder->bridge = bridge;
connector->encoder = encoder;
@@ -667,7 +756,6 @@ static int sti_hdmi_bind(struct device *dev, struct device *master, void *data)
err_sysfs:
drm_connector_unregister(drm_connector);
err_connector:
- drm_bridge_cleanup(bridge);
drm_connector_cleanup(drm_connector);
err_adapt:
put_device(&hdmi->ddc_adapt->dev);
diff --git a/drivers/gpu/drm/sti/sti_hqvdp.c b/drivers/gpu/drm/sti/sti_hqvdp.c
index f3db05dab0ab..b0eb62de1b2e 100644
--- a/drivers/gpu/drm/sti/sti_hqvdp.c
+++ b/drivers/gpu/drm/sti/sti_hqvdp.c
@@ -1025,7 +1025,7 @@ static int sti_hqvdp_probe(struct platform_device *pdev)
/* Get clock resources */
hqvdp->clk = devm_clk_get(dev, "hqvdp");
hqvdp->clk_pix_main = devm_clk_get(dev, "pix_main");
- if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk)) {
+ if (IS_ERR(hqvdp->clk) || IS_ERR(hqvdp->clk_pix_main)) {
DRM_ERROR("Cannot get clocks\n");
return -ENXIO;
}
diff --git a/drivers/gpu/drm/sti/sti_tvout.c b/drivers/gpu/drm/sti/sti_tvout.c
index cb924aa2b321..5cc53116508e 100644
--- a/drivers/gpu/drm/sti/sti_tvout.c
+++ b/drivers/gpu/drm/sti/sti_tvout.c
@@ -48,6 +48,9 @@
#define TVO_HDMI_CLIP_VALUE_R_CR 0x514
#define TVO_HDMI_SYNC_SEL 0x518
#define TVO_HDMI_DFV_OBS 0x540
+#define TVO_VIP_DVO 0x600
+#define TVO_DVO_SYNC_SEL 0x618
+#define TVO_DVO_CONFIG 0x620
#define TVO_IN_FMT_SIGNED BIT(0)
#define TVO_SYNC_EXT BIT(4)
@@ -98,6 +101,9 @@
#define TVO_SYNC_HD_DCS_SHIFT 8
+#define TVO_SYNC_DVO_PAD_HSYNC_SHIFT 8
+#define TVO_SYNC_DVO_PAD_VSYNC_SHIFT 16
+
#define ENCODER_CRTC_MASK (BIT(0) | BIT(1))
/* enum listing the supported output data format */
@@ -113,6 +119,7 @@ struct sti_tvout {
struct reset_control *reset;
struct drm_encoder *hdmi;
struct drm_encoder *hda;
+ struct drm_encoder *dvo;
};
struct sti_tvout_encoder {
@@ -262,6 +269,66 @@ static void tvout_vip_set_in_vid_fmt(struct sti_tvout *tvout,
}
/**
+ * Start VIP block for DVO output
+ *
+ * @tvout: pointer on tvout structure
+ * @main_path: true if main path has to be used in the vip configuration
+ * else aux path is used.
+ */
+static void tvout_dvo_start(struct sti_tvout *tvout, bool main_path)
+{
+ struct device_node *node = tvout->dev->of_node;
+ bool sel_input_logic_inverted = false;
+ u32 tvo_in_vid_format;
+ int val;
+
+ dev_dbg(tvout->dev, "%s\n", __func__);
+
+ if (main_path) {
+ DRM_DEBUG_DRIVER("main vip for DVO\n");
+ /* Select the input sync for dvo = VTG set 4 */
+ val = TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
+ val |= TVO_SYNC_MAIN_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
+ val |= TVO_SYNC_MAIN_VTG_SET_4;
+ tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
+ tvo_in_vid_format = TVO_MAIN_IN_VID_FORMAT;
+ } else {
+ DRM_DEBUG_DRIVER("aux vip for DVO\n");
+ /* Select the input sync for dvo = VTG set 4 */
+ val = TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_VSYNC_SHIFT;
+ val |= TVO_SYNC_AUX_VTG_SET_4 << TVO_SYNC_DVO_PAD_HSYNC_SHIFT;
+ val |= TVO_SYNC_AUX_VTG_SET_4;
+ tvout_write(tvout, val, TVO_DVO_SYNC_SEL);
+ tvo_in_vid_format = TVO_AUX_IN_VID_FORMAT;
+ }
+
+ /* Set color channel order */
+ tvout_vip_set_color_order(tvout, TVO_VIP_DVO,
+ TVO_VIP_REORDER_CR_R_SEL,
+ TVO_VIP_REORDER_Y_G_SEL,
+ TVO_VIP_REORDER_CB_B_SEL);
+
+ /* Set clipping mode (Limited range RGB/Y) */
+ tvout_vip_set_clip_mode(tvout, TVO_VIP_DVO,
+ TVO_VIP_CLIP_LIMITED_RANGE_RGB_Y);
+
+ /* Set round mode (rounded to 8-bit per component) */
+ tvout_vip_set_rnd(tvout, TVO_VIP_DVO, TVO_VIP_RND_8BIT_ROUNDED);
+
+ if (of_device_is_compatible(node, "st,stih407-tvout")) {
+ /* Set input video format */
+ tvout_vip_set_in_vid_fmt(tvout, tvo_in_vid_format,
+ TVO_IN_FMT_SIGNED);
+ sel_input_logic_inverted = true;
+ }
+
+ /* Input selection */
+ tvout_vip_set_sel_input(tvout, TVO_VIP_DVO, main_path,
+ sel_input_logic_inverted,
+ STI_TVOUT_VIDEO_OUT_RGB);
+}
+
+/**
* Start VIP block for HDMI output
*
* @tvout: pointer on tvout structure
@@ -402,6 +469,56 @@ static const struct drm_encoder_funcs sti_tvout_encoder_funcs = {
.destroy = sti_tvout_encoder_destroy,
};
+static void sti_dvo_encoder_commit(struct drm_encoder *encoder)
+{
+ struct sti_tvout *tvout = to_sti_tvout(encoder);
+
+ tvout_dvo_start(tvout, sti_drm_crtc_is_main(encoder->crtc));
+}
+
+static void sti_dvo_encoder_disable(struct drm_encoder *encoder)
+{
+ struct sti_tvout *tvout = to_sti_tvout(encoder);
+
+ /* Reset VIP register */
+ tvout_write(tvout, 0x0, TVO_VIP_DVO);
+}
+
+static const struct drm_encoder_helper_funcs sti_dvo_encoder_helper_funcs = {
+ .dpms = sti_tvout_encoder_dpms,
+ .mode_fixup = sti_tvout_encoder_mode_fixup,
+ .mode_set = sti_tvout_encoder_mode_set,
+ .prepare = sti_tvout_encoder_prepare,
+ .commit = sti_dvo_encoder_commit,
+ .disable = sti_dvo_encoder_disable,
+};
+
+static struct drm_encoder *
+sti_tvout_create_dvo_encoder(struct drm_device *dev,
+ struct sti_tvout *tvout)
+{
+ struct sti_tvout_encoder *encoder;
+ struct drm_encoder *drm_encoder;
+
+ encoder = devm_kzalloc(tvout->dev, sizeof(*encoder), GFP_KERNEL);
+ if (!encoder)
+ return NULL;
+
+ encoder->tvout = tvout;
+
+ drm_encoder = (struct drm_encoder *)encoder;
+
+ drm_encoder->possible_crtcs = ENCODER_CRTC_MASK;
+ drm_encoder->possible_clones = 1 << 0;
+
+ drm_encoder_init(dev, drm_encoder,
+ &sti_tvout_encoder_funcs, DRM_MODE_ENCODER_LVDS);
+
+ drm_encoder_helper_add(drm_encoder, &sti_dvo_encoder_helper_funcs);
+
+ return drm_encoder;
+}
+
static void sti_hda_encoder_commit(struct drm_encoder *encoder)
{
struct sti_tvout *tvout = to_sti_tvout(encoder);
@@ -508,6 +625,7 @@ static void sti_tvout_create_encoders(struct drm_device *dev,
{
tvout->hdmi = sti_tvout_create_hdmi_encoder(dev, tvout);
tvout->hda = sti_tvout_create_hda_encoder(dev, tvout);
+ tvout->dvo = sti_tvout_create_dvo_encoder(dev, tvout);
}
static void sti_tvout_destroy_encoders(struct sti_tvout *tvout)
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index 978993fa3a36..1a52522f5da7 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -18,9 +18,12 @@
#include "drm.h"
#include "gem.h"
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_plane_helper.h>
struct tegra_dc_soc_info {
+ bool supports_border_color;
bool supports_interlacing;
bool supports_cursor;
bool supports_block_linear;
@@ -38,63 +41,122 @@ static inline struct tegra_plane *to_tegra_plane(struct drm_plane *plane)
return container_of(plane, struct tegra_plane, base);
}
-static void tegra_dc_window_commit(struct tegra_dc *dc, unsigned int index)
+struct tegra_dc_state {
+ struct drm_crtc_state base;
+
+ struct clk *clk;
+ unsigned long pclk;
+ unsigned int div;
+
+ u32 planes;
+};
+
+static inline struct tegra_dc_state *to_dc_state(struct drm_crtc_state *state)
{
- u32 value = WIN_A_ACT_REQ << index;
+ if (state)
+ return container_of(state, struct tegra_dc_state, base);
- tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
+ return NULL;
}
-static void tegra_dc_cursor_commit(struct tegra_dc *dc)
+struct tegra_plane_state {
+ struct drm_plane_state base;
+
+ struct tegra_bo_tiling tiling;
+ u32 format;
+ u32 swap;
+};
+
+static inline struct tegra_plane_state *
+to_tegra_plane_state(struct drm_plane_state *state)
+{
+ if (state)
+ return container_of(state, struct tegra_plane_state, base);
+
+ return NULL;
+}
+
+/*
+ * Reads the active copy of a register. This takes the dc->lock spinlock to
+ * prevent races with the VBLANK processing which also needs access to the
+ * active copy of some registers.
+ */
+static u32 tegra_dc_readl_active(struct tegra_dc *dc, unsigned long offset)
{
- tegra_dc_writel(dc, CURSOR_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, CURSOR_ACT_REQ, DC_CMD_STATE_CONTROL);
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&dc->lock, flags);
+
+ tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
+ value = tegra_dc_readl(dc, offset);
+ tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
+
+ spin_unlock_irqrestore(&dc->lock, flags);
+ return value;
}
-static void tegra_dc_commit(struct tegra_dc *dc)
+/*
+ * Double-buffered registers have two copies: ASSEMBLY and ACTIVE. When the
+ * *_ACT_REQ bits are set the ASSEMBLY copy is latched into the ACTIVE copy.
+ * Latching happens mmediately if the display controller is in STOP mode or
+ * on the next frame boundary otherwise.
+ *
+ * Triple-buffered registers have three copies: ASSEMBLY, ARM and ACTIVE. The
+ * ASSEMBLY copy is latched into the ARM copy immediately after *_UPDATE bits
+ * are written. When the *_ACT_REQ bits are written, the ARM copy is latched
+ * into the ACTIVE copy, either immediately if the display controller is in
+ * STOP mode, or at the next frame boundary otherwise.
+ */
+void tegra_dc_commit(struct tegra_dc *dc)
{
tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
}
-static unsigned int tegra_dc_format(uint32_t format, uint32_t *swap)
+static int tegra_dc_format(u32 fourcc, u32 *format, u32 *swap)
{
/* assume no swapping of fetched data */
if (swap)
*swap = BYTE_SWAP_NOSWAP;
- switch (format) {
+ switch (fourcc) {
case DRM_FORMAT_XBGR8888:
- return WIN_COLOR_DEPTH_R8G8B8A8;
+ *format = WIN_COLOR_DEPTH_R8G8B8A8;
+ break;
case DRM_FORMAT_XRGB8888:
- return WIN_COLOR_DEPTH_B8G8R8A8;
+ *format = WIN_COLOR_DEPTH_B8G8R8A8;
+ break;
case DRM_FORMAT_RGB565:
- return WIN_COLOR_DEPTH_B5G6R5;
+ *format = WIN_COLOR_DEPTH_B5G6R5;
+ break;
case DRM_FORMAT_UYVY:
- return WIN_COLOR_DEPTH_YCbCr422;
+ *format = WIN_COLOR_DEPTH_YCbCr422;
+ break;
case DRM_FORMAT_YUYV:
if (swap)
*swap = BYTE_SWAP_SWAP2;
- return WIN_COLOR_DEPTH_YCbCr422;
+ *format = WIN_COLOR_DEPTH_YCbCr422;
+ break;
case DRM_FORMAT_YUV420:
- return WIN_COLOR_DEPTH_YCbCr420P;
+ *format = WIN_COLOR_DEPTH_YCbCr420P;
+ break;
case DRM_FORMAT_YUV422:
- return WIN_COLOR_DEPTH_YCbCr422P;
+ *format = WIN_COLOR_DEPTH_YCbCr422P;
+ break;
default:
- break;
+ return -EINVAL;
}
- WARN(1, "unsupported pixel format %u, using default\n", format);
- return WIN_COLOR_DEPTH_B8G8R8A8;
+ return 0;
}
static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
@@ -121,6 +183,9 @@ static bool tegra_dc_format_is_yuv(unsigned int format, bool *planar)
return true;
}
+ if (planar)
+ *planar = false;
+
return false;
}
@@ -164,8 +229,8 @@ static inline u32 compute_initial_dda(unsigned int in)
return dfixed_frac(inf);
}
-static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
- const struct tegra_dc_window *window)
+static void tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
+ const struct tegra_dc_window *window)
{
unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
unsigned long value, flags;
@@ -274,9 +339,11 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
break;
case TEGRA_BO_TILING_MODE_BLOCK:
- DRM_ERROR("hardware doesn't support block linear mode\n");
- spin_unlock_irqrestore(&dc->lock, flags);
- return -EINVAL;
+ /*
+ * No need to handle this here because ->atomic_check
+ * will already have filtered it out.
+ */
+ break;
}
tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
@@ -332,109 +399,245 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
break;
}
- tegra_dc_window_commit(dc, index);
-
spin_unlock_irqrestore(&dc->lock, flags);
-
- return 0;
}
-static int tegra_window_plane_disable(struct drm_plane *plane)
+static void tegra_plane_destroy(struct drm_plane *plane)
{
- struct tegra_dc *dc = to_tegra_dc(plane->crtc);
struct tegra_plane *p = to_tegra_plane(plane);
- unsigned long flags;
- u32 value;
- if (!plane->crtc)
- return 0;
+ drm_plane_cleanup(plane);
+ kfree(p);
+}
- spin_lock_irqsave(&dc->lock, flags);
+static const u32 tegra_primary_plane_formats[] = {
+ DRM_FORMAT_XBGR8888,
+ DRM_FORMAT_XRGB8888,
+ DRM_FORMAT_RGB565,
+};
- value = WINDOW_A_SELECT << p->index;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+static void tegra_primary_plane_destroy(struct drm_plane *plane)
+{
+ tegra_plane_destroy(plane);
+}
- value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
- value &= ~WIN_ENABLE;
- tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+static void tegra_plane_reset(struct drm_plane *plane)
+{
+ struct tegra_plane_state *state;
- tegra_dc_window_commit(dc, p->index);
+ if (plane->state && plane->state->fb)
+ drm_framebuffer_unreference(plane->state->fb);
- spin_unlock_irqrestore(&dc->lock, flags);
+ kfree(plane->state);
+ plane->state = NULL;
- return 0;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state) {
+ plane->state = &state->base;
+ plane->state->plane = plane;
+ }
}
-static void tegra_plane_destroy(struct drm_plane *plane)
+static struct drm_plane_state *tegra_plane_atomic_duplicate_state(struct drm_plane *plane)
{
- struct tegra_plane *p = to_tegra_plane(plane);
+ struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
+ struct tegra_plane_state *copy;
- drm_plane_cleanup(plane);
- kfree(p);
+ copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ if (copy->base.fb)
+ drm_framebuffer_reference(copy->base.fb);
+
+ return &copy->base;
}
-static const u32 tegra_primary_plane_formats[] = {
- DRM_FORMAT_XBGR8888,
- DRM_FORMAT_XRGB8888,
- DRM_FORMAT_RGB565,
+static void tegra_plane_atomic_destroy_state(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ if (state->fb)
+ drm_framebuffer_unreference(state->fb);
+
+ kfree(state);
+}
+
+static const struct drm_plane_funcs tegra_primary_plane_funcs = {
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
+ .destroy = tegra_primary_plane_destroy,
+ .reset = tegra_plane_reset,
+ .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
+ .atomic_destroy_state = tegra_plane_atomic_destroy_state,
};
-static int tegra_primary_plane_update(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x,
- int crtc_y, unsigned int crtc_w,
- unsigned int crtc_h, uint32_t src_x,
- uint32_t src_y, uint32_t src_w,
- uint32_t src_h)
+static int tegra_plane_prepare_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb)
{
- struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
- struct tegra_plane *p = to_tegra_plane(plane);
- struct tegra_dc *dc = to_tegra_dc(crtc);
- struct tegra_dc_window window;
+ return 0;
+}
+
+static void tegra_plane_cleanup_fb(struct drm_plane *plane,
+ struct drm_framebuffer *fb)
+{
+}
+
+static int tegra_plane_state_add(struct tegra_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct drm_crtc_state *crtc_state;
+ struct tegra_dc_state *tegra;
+
+ /* Propagate errors from allocation or locking failures. */
+ crtc_state = drm_atomic_get_crtc_state(state->state, state->crtc);
+ if (IS_ERR(crtc_state))
+ return PTR_ERR(crtc_state);
+
+ tegra = to_dc_state(crtc_state);
+
+ tegra->planes |= WIN_A_ACT_REQ << plane->index;
+
+ return 0;
+}
+
+static int tegra_plane_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
+{
+ struct tegra_plane_state *plane_state = to_tegra_plane_state(state);
+ struct tegra_bo_tiling *tiling = &plane_state->tiling;
+ struct tegra_plane *tegra = to_tegra_plane(plane);
+ struct tegra_dc *dc = to_tegra_dc(state->crtc);
int err;
- memset(&window, 0, sizeof(window));
- window.src.x = src_x >> 16;
- window.src.y = src_y >> 16;
- window.src.w = src_w >> 16;
- window.src.h = src_h >> 16;
- window.dst.x = crtc_x;
- window.dst.y = crtc_y;
- window.dst.w = crtc_w;
- window.dst.h = crtc_h;
- window.format = tegra_dc_format(fb->pixel_format, &window.swap);
- window.bits_per_pixel = fb->bits_per_pixel;
- window.bottom_up = tegra_fb_is_bottom_up(fb);
+ /* no need for further checks if the plane is being disabled */
+ if (!state->crtc)
+ return 0;
+
+ err = tegra_dc_format(state->fb->pixel_format, &plane_state->format,
+ &plane_state->swap);
+ if (err < 0)
+ return err;
- err = tegra_fb_get_tiling(fb, &window.tiling);
+ err = tegra_fb_get_tiling(state->fb, tiling);
if (err < 0)
return err;
- window.base[0] = bo->paddr + fb->offsets[0];
- window.stride[0] = fb->pitches[0];
+ if (tiling->mode == TEGRA_BO_TILING_MODE_BLOCK &&
+ !dc->soc->supports_block_linear) {
+ DRM_ERROR("hardware doesn't support block linear mode\n");
+ return -EINVAL;
+ }
- err = tegra_dc_setup_window(dc, p->index, &window);
+ /*
+ * Tegra doesn't support different strides for U and V planes so we
+ * error out if the user tries to display a framebuffer with such a
+ * configuration.
+ */
+ if (drm_format_num_planes(state->fb->pixel_format) > 2) {
+ if (state->fb->pitches[2] != state->fb->pitches[1]) {
+ DRM_ERROR("unsupported UV-plane configuration\n");
+ return -EINVAL;
+ }
+ }
+
+ err = tegra_plane_state_add(tegra, state);
if (err < 0)
return err;
return 0;
}
-static void tegra_primary_plane_destroy(struct drm_plane *plane)
+static void tegra_plane_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
- tegra_window_plane_disable(plane);
- tegra_plane_destroy(plane);
+ struct tegra_plane_state *state = to_tegra_plane_state(plane->state);
+ struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
+ struct drm_framebuffer *fb = plane->state->fb;
+ struct tegra_plane *p = to_tegra_plane(plane);
+ struct tegra_dc_window window;
+ unsigned int i;
+
+ /* rien ne va plus */
+ if (!plane->state->crtc || !plane->state->fb)
+ return;
+
+ memset(&window, 0, sizeof(window));
+ window.src.x = plane->state->src_x >> 16;
+ window.src.y = plane->state->src_y >> 16;
+ window.src.w = plane->state->src_w >> 16;
+ window.src.h = plane->state->src_h >> 16;
+ window.dst.x = plane->state->crtc_x;
+ window.dst.y = plane->state->crtc_y;
+ window.dst.w = plane->state->crtc_w;
+ window.dst.h = plane->state->crtc_h;
+ window.bits_per_pixel = fb->bits_per_pixel;
+ window.bottom_up = tegra_fb_is_bottom_up(fb);
+
+ /* copy from state */
+ window.tiling = state->tiling;
+ window.format = state->format;
+ window.swap = state->swap;
+
+ for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
+ struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
+
+ window.base[i] = bo->paddr + fb->offsets[i];
+ window.stride[i] = fb->pitches[i];
+ }
+
+ tegra_dc_setup_window(dc, p->index, &window);
}
-static const struct drm_plane_funcs tegra_primary_plane_funcs = {
- .update_plane = tegra_primary_plane_update,
- .disable_plane = tegra_window_plane_disable,
- .destroy = tegra_primary_plane_destroy,
+static void tegra_plane_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct tegra_plane *p = to_tegra_plane(plane);
+ struct tegra_dc *dc;
+ unsigned long flags;
+ u32 value;
+
+ /* rien ne va plus */
+ if (!old_state || !old_state->crtc)
+ return;
+
+ dc = to_tegra_dc(old_state->crtc);
+
+ spin_lock_irqsave(&dc->lock, flags);
+
+ value = WINDOW_A_SELECT << p->index;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
+
+ value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
+ value &= ~WIN_ENABLE;
+ tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
+
+ spin_unlock_irqrestore(&dc->lock, flags);
+}
+
+static const struct drm_plane_helper_funcs tegra_primary_plane_helper_funcs = {
+ .prepare_fb = tegra_plane_prepare_fb,
+ .cleanup_fb = tegra_plane_cleanup_fb,
+ .atomic_check = tegra_plane_atomic_check,
+ .atomic_update = tegra_plane_atomic_update,
+ .atomic_disable = tegra_plane_atomic_disable,
};
static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
struct tegra_dc *dc)
{
+ /*
+ * Ideally this would use drm_crtc_mask(), but that would require the
+ * CRTC to already be in the mode_config's list of CRTCs. However, it
+ * will only be added to that list in the drm_crtc_init_with_planes()
+ * (in tegra_dc_init()), which in turn requires registration of these
+ * planes. So we have ourselves a nice little chicken and egg problem
+ * here.
+ *
+ * We work around this by manually creating the mask from the number
+ * of CRTCs that have been registered, and should therefore always be
+ * the same as drm_crtc_index() after registration.
+ */
+ unsigned long possible_crtcs = 1 << drm->mode_config.num_crtc;
struct tegra_plane *plane;
unsigned int num_formats;
const u32 *formats;
@@ -447,7 +650,7 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
num_formats = ARRAY_SIZE(tegra_primary_plane_formats);
formats = tegra_primary_plane_formats;
- err = drm_universal_plane_init(drm, &plane->base, 1 << dc->pipe,
+ err = drm_universal_plane_init(drm, &plane->base, possible_crtcs,
&tegra_primary_plane_funcs, formats,
num_formats, DRM_PLANE_TYPE_PRIMARY);
if (err < 0) {
@@ -455,6 +658,8 @@ static struct drm_plane *tegra_dc_primary_plane_create(struct drm_device *drm,
return ERR_PTR(err);
}
+ drm_plane_helper_add(&plane->base, &tegra_primary_plane_helper_funcs);
+
return &plane->base;
}
@@ -462,27 +667,49 @@ static const u32 tegra_cursor_plane_formats[] = {
DRM_FORMAT_RGBA8888,
};
-static int tegra_cursor_plane_update(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x,
- int crtc_y, unsigned int crtc_w,
- unsigned int crtc_h, uint32_t src_x,
- uint32_t src_y, uint32_t src_w,
- uint32_t src_h)
+static int tegra_cursor_atomic_check(struct drm_plane *plane,
+ struct drm_plane_state *state)
{
- struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
- struct tegra_dc *dc = to_tegra_dc(crtc);
- u32 value = CURSOR_CLIP_DISPLAY;
+ struct tegra_plane *tegra = to_tegra_plane(plane);
+ int err;
+
+ /* no need for further checks if the plane is being disabled */
+ if (!state->crtc)
+ return 0;
/* scaling not supported for cursor */
- if ((src_w >> 16 != crtc_w) || (src_h >> 16 != crtc_h))
+ if ((state->src_w >> 16 != state->crtc_w) ||
+ (state->src_h >> 16 != state->crtc_h))
return -EINVAL;
/* only square cursors supported */
- if (src_w != src_h)
+ if (state->src_w != state->src_h)
+ return -EINVAL;
+
+ if (state->crtc_w != 32 && state->crtc_w != 64 &&
+ state->crtc_w != 128 && state->crtc_w != 256)
return -EINVAL;
- switch (crtc_w) {
+ err = tegra_plane_state_add(tegra, state);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+static void tegra_cursor_atomic_update(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
+{
+ struct tegra_bo *bo = tegra_fb_get_plane(plane->state->fb, 0);
+ struct tegra_dc *dc = to_tegra_dc(plane->state->crtc);
+ struct drm_plane_state *state = plane->state;
+ u32 value = CURSOR_CLIP_DISPLAY;
+
+ /* rien ne va plus */
+ if (!plane->state->crtc || !plane->state->fb)
+ return;
+
+ switch (state->crtc_w) {
case 32:
value |= CURSOR_SIZE_32x32;
break;
@@ -500,7 +727,9 @@ static int tegra_cursor_plane_update(struct drm_plane *plane,
break;
default:
- return -EINVAL;
+ WARN(1, "cursor size %ux%u not supported\n", state->crtc_w,
+ state->crtc_h);
+ return;
}
value |= (bo->paddr >> 10) & 0x3fffff;
@@ -526,38 +755,43 @@ static int tegra_cursor_plane_update(struct drm_plane *plane,
tegra_dc_writel(dc, value, DC_DISP_BLEND_CURSOR_CONTROL);
/* position the cursor */
- value = (crtc_y & 0x3fff) << 16 | (crtc_x & 0x3fff);
+ value = (state->crtc_y & 0x3fff) << 16 | (state->crtc_x & 0x3fff);
tegra_dc_writel(dc, value, DC_DISP_CURSOR_POSITION);
- /* apply changes */
- tegra_dc_cursor_commit(dc);
- tegra_dc_commit(dc);
-
- return 0;
}
-static int tegra_cursor_plane_disable(struct drm_plane *plane)
+static void tegra_cursor_atomic_disable(struct drm_plane *plane,
+ struct drm_plane_state *old_state)
{
- struct tegra_dc *dc = to_tegra_dc(plane->crtc);
+ struct tegra_dc *dc;
u32 value;
- if (!plane->crtc)
- return 0;
+ /* rien ne va plus */
+ if (!old_state || !old_state->crtc)
+ return;
+
+ dc = to_tegra_dc(old_state->crtc);
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
value &= ~CURSOR_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
- tegra_dc_cursor_commit(dc);
- tegra_dc_commit(dc);
-
- return 0;
}
static const struct drm_plane_funcs tegra_cursor_plane_funcs = {
- .update_plane = tegra_cursor_plane_update,
- .disable_plane = tegra_cursor_plane_disable,
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
.destroy = tegra_plane_destroy,
+ .reset = tegra_plane_reset,
+ .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
+ .atomic_destroy_state = tegra_plane_atomic_destroy_state,
+};
+
+static const struct drm_plane_helper_funcs tegra_cursor_plane_helper_funcs = {
+ .prepare_fb = tegra_plane_prepare_fb,
+ .cleanup_fb = tegra_plane_cleanup_fb,
+ .atomic_check = tegra_cursor_atomic_check,
+ .atomic_update = tegra_cursor_atomic_update,
+ .atomic_disable = tegra_cursor_atomic_disable,
};
static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
@@ -572,6 +806,13 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
if (!plane)
return ERR_PTR(-ENOMEM);
+ /*
+ * We'll treat the cursor as an overlay plane with index 6 here so
+ * that the update and activation request bits in DC_CMD_STATE_CONTROL
+ * match up.
+ */
+ plane->index = 6;
+
num_formats = ARRAY_SIZE(tegra_cursor_plane_formats);
formats = tegra_cursor_plane_formats;
@@ -583,71 +824,23 @@ static struct drm_plane *tegra_dc_cursor_plane_create(struct drm_device *drm,
return ERR_PTR(err);
}
- return &plane->base;
-}
-
-static int tegra_overlay_plane_update(struct drm_plane *plane,
- struct drm_crtc *crtc,
- struct drm_framebuffer *fb, int crtc_x,
- int crtc_y, unsigned int crtc_w,
- unsigned int crtc_h, uint32_t src_x,
- uint32_t src_y, uint32_t src_w,
- uint32_t src_h)
-{
- struct tegra_plane *p = to_tegra_plane(plane);
- struct tegra_dc *dc = to_tegra_dc(crtc);
- struct tegra_dc_window window;
- unsigned int i;
- int err;
+ drm_plane_helper_add(&plane->base, &tegra_cursor_plane_helper_funcs);
- memset(&window, 0, sizeof(window));
- window.src.x = src_x >> 16;
- window.src.y = src_y >> 16;
- window.src.w = src_w >> 16;
- window.src.h = src_h >> 16;
- window.dst.x = crtc_x;
- window.dst.y = crtc_y;
- window.dst.w = crtc_w;
- window.dst.h = crtc_h;
- window.format = tegra_dc_format(fb->pixel_format, &window.swap);
- window.bits_per_pixel = fb->bits_per_pixel;
- window.bottom_up = tegra_fb_is_bottom_up(fb);
-
- err = tegra_fb_get_tiling(fb, &window.tiling);
- if (err < 0)
- return err;
-
- for (i = 0; i < drm_format_num_planes(fb->pixel_format); i++) {
- struct tegra_bo *bo = tegra_fb_get_plane(fb, i);
-
- window.base[i] = bo->paddr + fb->offsets[i];
-
- /*
- * Tegra doesn't support different strides for U and V planes
- * so we display a warning if the user tries to display a
- * framebuffer with such a configuration.
- */
- if (i >= 2) {
- if (fb->pitches[i] != window.stride[1])
- DRM_ERROR("unsupported UV-plane configuration\n");
- } else {
- window.stride[i] = fb->pitches[i];
- }
- }
-
- return tegra_dc_setup_window(dc, p->index, &window);
+ return &plane->base;
}
static void tegra_overlay_plane_destroy(struct drm_plane *plane)
{
- tegra_window_plane_disable(plane);
tegra_plane_destroy(plane);
}
static const struct drm_plane_funcs tegra_overlay_plane_funcs = {
- .update_plane = tegra_overlay_plane_update,
- .disable_plane = tegra_window_plane_disable,
+ .update_plane = drm_atomic_helper_update_plane,
+ .disable_plane = drm_atomic_helper_disable_plane,
.destroy = tegra_overlay_plane_destroy,
+ .reset = tegra_plane_reset,
+ .atomic_duplicate_state = tegra_plane_atomic_duplicate_state,
+ .atomic_destroy_state = tegra_plane_atomic_destroy_state,
};
static const uint32_t tegra_overlay_plane_formats[] = {
@@ -660,6 +853,14 @@ static const uint32_t tegra_overlay_plane_formats[] = {
DRM_FORMAT_YUV422,
};
+static const struct drm_plane_helper_funcs tegra_overlay_plane_helper_funcs = {
+ .prepare_fb = tegra_plane_prepare_fb,
+ .cleanup_fb = tegra_plane_cleanup_fb,
+ .atomic_check = tegra_plane_atomic_check,
+ .atomic_update = tegra_plane_atomic_update,
+ .atomic_disable = tegra_plane_atomic_disable,
+};
+
static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
struct tegra_dc *dc,
unsigned int index)
@@ -686,6 +887,8 @@ static struct drm_plane *tegra_dc_overlay_plane_create(struct drm_device *drm,
return ERR_PTR(err);
}
+ drm_plane_helper_add(&plane->base, &tegra_overlay_plane_helper_funcs);
+
return &plane->base;
}
@@ -703,99 +906,6 @@ static int tegra_dc_add_planes(struct drm_device *drm, struct tegra_dc *dc)
return 0;
}
-static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
- struct drm_framebuffer *fb)
-{
- struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
- unsigned int h_offset = 0, v_offset = 0;
- struct tegra_bo_tiling tiling;
- unsigned long value, flags;
- unsigned int format, swap;
- int err;
-
- err = tegra_fb_get_tiling(fb, &tiling);
- if (err < 0)
- return err;
-
- spin_lock_irqsave(&dc->lock, flags);
-
- tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
-
- value = fb->offsets[0] + y * fb->pitches[0] +
- x * fb->bits_per_pixel / 8;
-
- tegra_dc_writel(dc, bo->paddr + value, DC_WINBUF_START_ADDR);
- tegra_dc_writel(dc, fb->pitches[0], DC_WIN_LINE_STRIDE);
-
- format = tegra_dc_format(fb->pixel_format, &swap);
- tegra_dc_writel(dc, format, DC_WIN_COLOR_DEPTH);
- tegra_dc_writel(dc, swap, DC_WIN_BYTE_SWAP);
-
- if (dc->soc->supports_block_linear) {
- unsigned long height = tiling.value;
-
- switch (tiling.mode) {
- case TEGRA_BO_TILING_MODE_PITCH:
- value = DC_WINBUF_SURFACE_KIND_PITCH;
- break;
-
- case TEGRA_BO_TILING_MODE_TILED:
- value = DC_WINBUF_SURFACE_KIND_TILED;
- break;
-
- case TEGRA_BO_TILING_MODE_BLOCK:
- value = DC_WINBUF_SURFACE_KIND_BLOCK_HEIGHT(height) |
- DC_WINBUF_SURFACE_KIND_BLOCK;
- break;
- }
-
- tegra_dc_writel(dc, value, DC_WINBUF_SURFACE_KIND);
- } else {
- switch (tiling.mode) {
- case TEGRA_BO_TILING_MODE_PITCH:
- value = DC_WIN_BUFFER_ADDR_MODE_LINEAR_UV |
- DC_WIN_BUFFER_ADDR_MODE_LINEAR;
- break;
-
- case TEGRA_BO_TILING_MODE_TILED:
- value = DC_WIN_BUFFER_ADDR_MODE_TILE_UV |
- DC_WIN_BUFFER_ADDR_MODE_TILE;
- break;
-
- case TEGRA_BO_TILING_MODE_BLOCK:
- DRM_ERROR("hardware doesn't support block linear mode\n");
- spin_unlock_irqrestore(&dc->lock, flags);
- return -EINVAL;
- }
-
- tegra_dc_writel(dc, value, DC_WIN_BUFFER_ADDR_MODE);
- }
-
- /* make sure bottom-up buffers are properly displayed */
- if (tegra_fb_is_bottom_up(fb)) {
- value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
- value |= V_DIRECTION;
- tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
-
- v_offset += fb->height - 1;
- } else {
- value = tegra_dc_readl(dc, DC_WIN_WIN_OPTIONS);
- value &= ~V_DIRECTION;
- tegra_dc_writel(dc, value, DC_WIN_WIN_OPTIONS);
- }
-
- tegra_dc_writel(dc, h_offset, DC_WINBUF_ADDR_H_OFFSET);
- tegra_dc_writel(dc, v_offset, DC_WINBUF_ADDR_V_OFFSET);
-
- value = GENERAL_ACT_REQ | WIN_A_ACT_REQ;
- tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
-
- spin_unlock_irqrestore(&dc->lock, flags);
-
- return 0;
-}
-
void tegra_dc_enable_vblank(struct tegra_dc *dc)
{
unsigned long value, flags;
@@ -838,7 +948,7 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
bo = tegra_fb_get_plane(crtc->primary->fb, 0);
- spin_lock_irqsave(&dc->lock, flags);
+ spin_lock(&dc->lock);
/* check if new start address has been latched */
tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
@@ -846,7 +956,7 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
- spin_unlock_irqrestore(&dc->lock, flags);
+ spin_unlock(&dc->lock);
if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
drm_crtc_send_vblank_event(crtc, dc->event);
@@ -874,64 +984,133 @@ void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file)
spin_unlock_irqrestore(&drm->event_lock, flags);
}
-static int tegra_dc_page_flip(struct drm_crtc *crtc, struct drm_framebuffer *fb,
- struct drm_pending_vblank_event *event, uint32_t page_flip_flags)
+static void tegra_dc_destroy(struct drm_crtc *crtc)
{
- unsigned int pipe = drm_crtc_index(crtc);
- struct tegra_dc *dc = to_tegra_dc(crtc);
-
- if (dc->event)
- return -EBUSY;
+ drm_crtc_cleanup(crtc);
+}
- if (event) {
- event->pipe = pipe;
- dc->event = event;
- drm_crtc_vblank_get(crtc);
- }
+static void tegra_crtc_reset(struct drm_crtc *crtc)
+{
+ struct tegra_dc_state *state;
- tegra_dc_set_base(dc, 0, 0, fb);
- crtc->primary->fb = fb;
+ kfree(crtc->state);
+ crtc->state = NULL;
- return 0;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state) {
+ crtc->state = &state->base;
+ crtc->state->crtc = crtc;
+ }
}
-static void drm_crtc_clear(struct drm_crtc *crtc)
+static struct drm_crtc_state *
+tegra_crtc_atomic_duplicate_state(struct drm_crtc *crtc)
{
- memset(crtc, 0, sizeof(*crtc));
+ struct tegra_dc_state *state = to_dc_state(crtc->state);
+ struct tegra_dc_state *copy;
+
+ copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ copy->base.mode_changed = false;
+ copy->base.active_changed = false;
+ copy->base.planes_changed = false;
+ copy->base.event = NULL;
+
+ return &copy->base;
}
-static void tegra_dc_destroy(struct drm_crtc *crtc)
+static void tegra_crtc_atomic_destroy_state(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
{
- drm_crtc_cleanup(crtc);
- drm_crtc_clear(crtc);
+ kfree(state);
}
static const struct drm_crtc_funcs tegra_crtc_funcs = {
- .page_flip = tegra_dc_page_flip,
- .set_config = drm_crtc_helper_set_config,
+ .page_flip = drm_atomic_helper_page_flip,
+ .set_config = drm_atomic_helper_set_config,
.destroy = tegra_dc_destroy,
+ .reset = tegra_crtc_reset,
+ .atomic_duplicate_state = tegra_crtc_atomic_duplicate_state,
+ .atomic_destroy_state = tegra_crtc_atomic_destroy_state,
};
+static void tegra_dc_stop(struct tegra_dc *dc)
+{
+ u32 value;
+
+ /* stop the display controller */
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+ value &= ~DISP_CTRL_MODE_MASK;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
+
+ tegra_dc_commit(dc);
+}
+
+static bool tegra_dc_idle(struct tegra_dc *dc)
+{
+ u32 value;
+
+ value = tegra_dc_readl_active(dc, DC_CMD_DISPLAY_COMMAND);
+
+ return (value & DISP_CTRL_MODE_MASK) == 0;
+}
+
+static int tegra_dc_wait_idle(struct tegra_dc *dc, unsigned long timeout)
+{
+ timeout = jiffies + msecs_to_jiffies(timeout);
+
+ while (time_before(jiffies, timeout)) {
+ if (tegra_dc_idle(dc))
+ return 0;
+
+ usleep_range(1000, 2000);
+ }
+
+ dev_dbg(dc->dev, "timeout waiting for DC to become idle\n");
+ return -ETIMEDOUT;
+}
+
static void tegra_crtc_disable(struct drm_crtc *crtc)
{
struct tegra_dc *dc = to_tegra_dc(crtc);
- struct drm_device *drm = crtc->dev;
- struct drm_plane *plane;
+ u32 value;
- drm_for_each_legacy_plane(plane, &drm->mode_config.plane_list) {
- if (plane->crtc == crtc) {
- tegra_window_plane_disable(plane);
- plane->crtc = NULL;
+ if (!tegra_dc_idle(dc)) {
+ tegra_dc_stop(dc);
- if (plane->fb) {
- drm_framebuffer_unreference(plane->fb);
- plane->fb = NULL;
- }
- }
+ /*
+ * Ignore the return value, there isn't anything useful to do
+ * in case this fails.
+ */
+ tegra_dc_wait_idle(dc, 100);
+ }
+
+ /*
+ * This should really be part of the RGB encoder driver, but clearing
+ * these bits has the side-effect of stopping the display controller.
+ * When that happens no VBLANK interrupts will be raised. At the same
+ * time the encoder is disabled before the display controller, so the
+ * above code is always going to timeout waiting for the controller
+ * to go idle.
+ *
+ * Given the close coupling between the RGB encoder and the display
+ * controller doing it here is still kind of okay. None of the other
+ * encoder drivers require these bits to be cleared.
+ *
+ * XXX: Perhaps given that the display controller is switched off at
+ * this point anyway maybe clearing these bits isn't even useful for
+ * the RGB encoder?
+ */
+ if (dc->rgb) {
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+ value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+ PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
}
drm_crtc_vblank_off(crtc);
- tegra_dc_commit(dc);
}
static bool tegra_crtc_mode_fixup(struct drm_crtc *crtc,
@@ -971,33 +1150,15 @@ static int tegra_dc_set_timings(struct tegra_dc *dc,
return 0;
}
-static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
- struct drm_display_mode *mode)
+int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
+ unsigned long pclk, unsigned int div)
{
- unsigned long pclk = mode->clock * 1000;
- struct tegra_dc *dc = to_tegra_dc(crtc);
- struct tegra_output *output = NULL;
- struct drm_encoder *encoder;
- unsigned int div;
u32 value;
- long err;
-
- list_for_each_entry(encoder, &crtc->dev->mode_config.encoder_list, head)
- if (encoder->crtc == crtc) {
- output = encoder_to_output(encoder);
- break;
- }
-
- if (!output)
- return -ENODEV;
+ int err;
- /*
- * This assumes that the parent clock is pll_d_out0 or pll_d2_out
- * respectively, each of which divides the base pll_d by 2.
- */
- err = tegra_output_setup_clock(output, dc->clk, pclk, &div);
+ err = clk_set_parent(dc->clk, parent);
if (err < 0) {
- dev_err(dc->dev, "failed to setup clock: %ld\n", err);
+ dev_err(dc->dev, "failed to set parent clock: %d\n", err);
return err;
}
@@ -1009,23 +1170,63 @@ static int tegra_crtc_setup_clk(struct drm_crtc *crtc,
return 0;
}
-static int tegra_crtc_mode_set(struct drm_crtc *crtc,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted,
- int x, int y, struct drm_framebuffer *old_fb)
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+ struct drm_crtc_state *crtc_state,
+ struct clk *clk, unsigned long pclk,
+ unsigned int div)
+{
+ struct tegra_dc_state *state = to_dc_state(crtc_state);
+
+ state->clk = clk;
+ state->pclk = pclk;
+ state->div = div;
+
+ return 0;
+}
+
+static void tegra_dc_commit_state(struct tegra_dc *dc,
+ struct tegra_dc_state *state)
{
- struct tegra_bo *bo = tegra_fb_get_plane(crtc->primary->fb, 0);
- struct tegra_dc *dc = to_tegra_dc(crtc);
- struct tegra_dc_window window;
u32 value;
int err;
- err = tegra_crtc_setup_clk(crtc, mode);
- if (err) {
- dev_err(dc->dev, "failed to setup clock for CRTC: %d\n", err);
- return err;
+ err = clk_set_parent(dc->clk, state->clk);
+ if (err < 0)
+ dev_err(dc->dev, "failed to set parent clock: %d\n", err);
+
+ /*
+ * Outputs may not want to change the parent clock rate. This is only
+ * relevant to Tegra20 where only a single display PLL is available.
+ * Since that PLL would typically be used for HDMI, an internal LVDS
+ * panel would need to be driven by some other clock such as PLL_P
+ * which is shared with other peripherals. Changing the clock rate
+ * should therefore be avoided.
+ */
+ if (state->pclk > 0) {
+ err = clk_set_rate(state->clk, state->pclk);
+ if (err < 0)
+ dev_err(dc->dev,
+ "failed to set clock rate to %lu Hz\n",
+ state->pclk);
}
+ DRM_DEBUG_KMS("rate: %lu, div: %u\n", clk_get_rate(dc->clk),
+ state->div);
+ DRM_DEBUG_KMS("pclk: %lu\n", state->pclk);
+
+ value = SHIFT_CLK_DIVIDER(state->div) | PIXEL_CLK_DIVIDER_PCD1;
+ tegra_dc_writel(dc, value, DC_DISP_DISP_CLOCK_CONTROL);
+}
+
+static void tegra_crtc_mode_set_nofb(struct drm_crtc *crtc)
+{
+ struct drm_display_mode *mode = &crtc->state->adjusted_mode;
+ struct tegra_dc_state *state = to_dc_state(crtc->state);
+ struct tegra_dc *dc = to_tegra_dc(crtc);
+ u32 value;
+
+ tegra_dc_commit_state(dc, state);
+
/* program display mode */
tegra_dc_set_timings(dc, mode);
@@ -1036,101 +1237,69 @@ static int tegra_crtc_mode_set(struct drm_crtc *crtc,
tegra_dc_writel(dc, value, DC_DISP_INTERLACE_CONTROL);
}
- /* setup window parameters */
- memset(&window, 0, sizeof(window));
- window.src.x = 0;
- window.src.y = 0;
- window.src.w = mode->hdisplay;
- window.src.h = mode->vdisplay;
- window.dst.x = 0;
- window.dst.y = 0;
- window.dst.w = mode->hdisplay;
- window.dst.h = mode->vdisplay;
- window.format = tegra_dc_format(crtc->primary->fb->pixel_format,
- &window.swap);
- window.bits_per_pixel = crtc->primary->fb->bits_per_pixel;
- window.stride[0] = crtc->primary->fb->pitches[0];
- window.base[0] = bo->paddr;
-
- err = tegra_dc_setup_window(dc, 0, &window);
- if (err < 0)
- dev_err(dc->dev, "failed to enable root plane\n");
-
- return 0;
-}
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
+ value &= ~DISP_CTRL_MODE_MASK;
+ value |= DISP_CTRL_MODE_C_DISPLAY;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-static int tegra_crtc_mode_set_base(struct drm_crtc *crtc, int x, int y,
- struct drm_framebuffer *old_fb)
-{
- struct tegra_dc *dc = to_tegra_dc(crtc);
+ value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
+ value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
+ PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
+ tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
- return tegra_dc_set_base(dc, x, y, crtc->primary->fb);
+ tegra_dc_commit(dc);
}
static void tegra_crtc_prepare(struct drm_crtc *crtc)
{
- struct tegra_dc *dc = to_tegra_dc(crtc);
- unsigned int syncpt;
- unsigned long value;
-
drm_crtc_vblank_off(crtc);
+}
- /* hardware initialization */
- reset_control_deassert(dc->rst);
- usleep_range(10000, 20000);
-
- if (dc->pipe)
- syncpt = SYNCPT_VBLANK1;
- else
- syncpt = SYNCPT_VBLANK0;
-
- /* initialize display controller */
- tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
- tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
-
- value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
- tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
+static void tegra_crtc_commit(struct drm_crtc *crtc)
+{
+ drm_crtc_vblank_on(crtc);
+}
- value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
- WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
- tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
+static int tegra_crtc_atomic_check(struct drm_crtc *crtc,
+ struct drm_crtc_state *state)
+{
+ return 0;
+}
- /* initialize timer */
- value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
- WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
- tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
+static void tegra_crtc_atomic_begin(struct drm_crtc *crtc)
+{
+ struct tegra_dc *dc = to_tegra_dc(crtc);
- value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
- WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
- tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
+ if (crtc->state->event) {
+ crtc->state->event->pipe = drm_crtc_index(crtc);
- value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
- tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
+ WARN_ON(drm_crtc_vblank_get(crtc) != 0);
- value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
- tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
+ dc->event = crtc->state->event;
+ crtc->state->event = NULL;
+ }
}
-static void tegra_crtc_commit(struct drm_crtc *crtc)
+static void tegra_crtc_atomic_flush(struct drm_crtc *crtc)
{
+ struct tegra_dc_state *state = to_dc_state(crtc->state);
struct tegra_dc *dc = to_tegra_dc(crtc);
- drm_crtc_vblank_on(crtc);
- tegra_dc_commit(dc);
-}
-
-static void tegra_crtc_load_lut(struct drm_crtc *crtc)
-{
+ tegra_dc_writel(dc, state->planes << 8, DC_CMD_STATE_CONTROL);
+ tegra_dc_writel(dc, state->planes, DC_CMD_STATE_CONTROL);
}
static const struct drm_crtc_helper_funcs tegra_crtc_helper_funcs = {
.disable = tegra_crtc_disable,
.mode_fixup = tegra_crtc_mode_fixup,
- .mode_set = tegra_crtc_mode_set,
- .mode_set_base = tegra_crtc_mode_set_base,
+ .mode_set = drm_helper_crtc_mode_set,
+ .mode_set_nofb = tegra_crtc_mode_set_nofb,
+ .mode_set_base = drm_helper_crtc_mode_set_base,
.prepare = tegra_crtc_prepare,
.commit = tegra_crtc_commit,
- .load_lut = tegra_crtc_load_lut,
+ .atomic_check = tegra_crtc_atomic_check,
+ .atomic_begin = tegra_crtc_atomic_begin,
+ .atomic_flush = tegra_crtc_atomic_flush,
};
static irqreturn_t tegra_dc_irq(int irq, void *data)
@@ -1460,6 +1629,8 @@ static int tegra_dc_init(struct host1x_client *client)
struct tegra_drm *tegra = drm->dev_private;
struct drm_plane *primary = NULL;
struct drm_plane *cursor = NULL;
+ unsigned int syncpt;
+ u32 value;
int err;
if (tegra->domain) {
@@ -1526,6 +1697,40 @@ static int tegra_dc_init(struct host1x_client *client)
goto cleanup;
}
+ /* initialize display controller */
+ if (dc->pipe)
+ syncpt = SYNCPT_VBLANK1;
+ else
+ syncpt = SYNCPT_VBLANK0;
+
+ tegra_dc_writel(dc, 0x00000100, DC_CMD_GENERAL_INCR_SYNCPT_CNTRL);
+ tegra_dc_writel(dc, 0x100 | syncpt, DC_CMD_CONT_SYNCPT_VSYNC);
+
+ value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT | WIN_A_OF_INT;
+ tegra_dc_writel(dc, value, DC_CMD_INT_TYPE);
+
+ value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT |
+ WIN_A_OF_INT | WIN_B_OF_INT | WIN_C_OF_INT;
+ tegra_dc_writel(dc, value, DC_CMD_INT_POLARITY);
+
+ /* initialize timer */
+ value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(0x20) |
+ WINDOW_B_THRESHOLD(0x20) | WINDOW_C_THRESHOLD(0x20);
+ tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY);
+
+ value = CURSOR_THRESHOLD(0) | WINDOW_A_THRESHOLD(1) |
+ WINDOW_B_THRESHOLD(1) | WINDOW_C_THRESHOLD(1);
+ tegra_dc_writel(dc, value, DC_DISP_DISP_MEM_HIGH_PRIORITY_TIMER);
+
+ value = VBLANK_INT | WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
+ tegra_dc_writel(dc, value, DC_CMD_INT_ENABLE);
+
+ value = WIN_A_UF_INT | WIN_B_UF_INT | WIN_C_UF_INT;
+ tegra_dc_writel(dc, value, DC_CMD_INT_MASK);
+
+ if (dc->soc->supports_border_color)
+ tegra_dc_writel(dc, 0, DC_DISP_BORDER_COLOR);
+
return 0;
cleanup:
@@ -1576,6 +1781,7 @@ static const struct host1x_client_ops dc_client_ops = {
};
static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
+ .supports_border_color = true,
.supports_interlacing = false,
.supports_cursor = false,
.supports_block_linear = false,
@@ -1584,6 +1790,7 @@ static const struct tegra_dc_soc_info tegra20_dc_soc_info = {
};
static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
+ .supports_border_color = true,
.supports_interlacing = false,
.supports_cursor = false,
.supports_block_linear = false,
@@ -1592,6 +1799,7 @@ static const struct tegra_dc_soc_info tegra30_dc_soc_info = {
};
static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
+ .supports_border_color = true,
.supports_interlacing = false,
.supports_cursor = false,
.supports_block_linear = false,
@@ -1600,6 +1808,7 @@ static const struct tegra_dc_soc_info tegra114_dc_soc_info = {
};
static const struct tegra_dc_soc_info tegra124_dc_soc_info = {
+ .supports_border_color = false,
.supports_interlacing = true,
.supports_cursor = true,
.supports_block_linear = true,
diff --git a/drivers/gpu/drm/tegra/drm.c b/drivers/gpu/drm/tegra/drm.c
index d4f827593dfa..7dd328d77996 100644
--- a/drivers/gpu/drm/tegra/drm.c
+++ b/drivers/gpu/drm/tegra/drm.c
@@ -10,6 +10,9 @@
#include <linux/host1x.h>
#include <linux/iommu.h>
+#include <drm/drm_atomic.h>
+#include <drm/drm_atomic_helper.h>
+
#include "drm.h"
#include "gem.h"
@@ -24,6 +27,92 @@ struct tegra_drm_file {
struct list_head contexts;
};
+static void tegra_atomic_schedule(struct tegra_drm *tegra,
+ struct drm_atomic_state *state)
+{
+ tegra->commit.state = state;
+ schedule_work(&tegra->commit.work);
+}
+
+static void tegra_atomic_complete(struct tegra_drm *tegra,
+ struct drm_atomic_state *state)
+{
+ struct drm_device *drm = tegra->drm;
+
+ /*
+ * Everything below can be run asynchronously without the need to grab
+ * any modeset locks at all under one condition: It must be guaranteed
+ * that the asynchronous work has either been cancelled (if the driver
+ * supports it, which at least requires that the framebuffers get
+ * cleaned up with drm_atomic_helper_cleanup_planes()) or completed
+ * before the new state gets committed on the software side with
+ * drm_atomic_helper_swap_state().
+ *
+ * This scheme allows new atomic state updates to be prepared and
+ * checked in parallel to the asynchronous completion of the previous
+ * update. Which is important since compositors need to figure out the
+ * composition of the next frame right after having submitted the
+ * current layout.
+ */
+
+ drm_atomic_helper_commit_pre_planes(drm, state);
+ drm_atomic_helper_commit_planes(drm, state);
+ drm_atomic_helper_commit_post_planes(drm, state);
+
+ drm_atomic_helper_wait_for_vblanks(drm, state);
+
+ drm_atomic_helper_cleanup_planes(drm, state);
+ drm_atomic_state_free(state);
+}
+
+static void tegra_atomic_work(struct work_struct *work)
+{
+ struct tegra_drm *tegra = container_of(work, struct tegra_drm,
+ commit.work);
+
+ tegra_atomic_complete(tegra, tegra->commit.state);
+}
+
+static int tegra_atomic_commit(struct drm_device *drm,
+ struct drm_atomic_state *state, bool async)
+{
+ struct tegra_drm *tegra = drm->dev_private;
+ int err;
+
+ err = drm_atomic_helper_prepare_planes(drm, state);
+ if (err)
+ return err;
+
+ /* serialize outstanding asynchronous commits */
+ mutex_lock(&tegra->commit.lock);
+ flush_work(&tegra->commit.work);
+
+ /*
+ * This is the point of no return - everything below never fails except
+ * when the hw goes bonghits. Which means we can commit the new state on
+ * the software side now.
+ */
+
+ drm_atomic_helper_swap_state(drm, state);
+
+ if (async)
+ tegra_atomic_schedule(tegra, state);
+ else
+ tegra_atomic_complete(tegra, state);
+
+ mutex_unlock(&tegra->commit.lock);
+ return 0;
+}
+
+static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
+ .fb_create = tegra_fb_create,
+#ifdef CONFIG_DRM_TEGRA_FBDEV
+ .output_poll_changed = tegra_fb_output_poll_changed,
+#endif
+ .atomic_check = drm_atomic_helper_check,
+ .atomic_commit = tegra_atomic_commit,
+};
+
static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
{
struct host1x_device *device = to_host1x_device(drm->dev);
@@ -36,8 +125,8 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (iommu_present(&platform_bus_type)) {
tegra->domain = iommu_domain_alloc(&platform_bus_type);
- if (IS_ERR(tegra->domain)) {
- err = PTR_ERR(tegra->domain);
+ if (!tegra->domain) {
+ err = -ENOMEM;
goto free;
}
@@ -47,11 +136,23 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
mutex_init(&tegra->clients_lock);
INIT_LIST_HEAD(&tegra->clients);
+
+ mutex_init(&tegra->commit.lock);
+ INIT_WORK(&tegra->commit.work, tegra_atomic_work);
+
drm->dev_private = tegra;
tegra->drm = drm;
drm_mode_config_init(drm);
+ drm->mode_config.min_width = 0;
+ drm->mode_config.min_height = 0;
+
+ drm->mode_config.max_width = 4096;
+ drm->mode_config.max_height = 4096;
+
+ drm->mode_config.funcs = &tegra_drm_mode_funcs;
+
err = tegra_drm_fb_prepare(drm);
if (err < 0)
goto config;
@@ -62,6 +163,8 @@ static int tegra_drm_load(struct drm_device *drm, unsigned long flags)
if (err < 0)
goto fbdev;
+ drm_mode_config_reset(drm);
+
/*
* We don't use the drm_irq_install() helpers provided by the DRM
* core, so we need to set this manually in order to allow the
@@ -106,8 +209,8 @@ static int tegra_drm_unload(struct drm_device *drm)
drm_kms_helper_poll_fini(drm);
tegra_drm_fb_exit(drm);
- drm_vblank_cleanup(drm);
drm_mode_config_cleanup(drm);
+ drm_vblank_cleanup(drm);
err = host1x_device_exit(device);
if (err < 0)
@@ -190,7 +293,7 @@ static int host1x_reloc_copy_from_user(struct host1x_reloc *dest,
if (err < 0)
return err;
- err = get_user(dest->target.offset, &src->cmdbuf.offset);
+ err = get_user(dest->target.offset, &src->target.offset);
if (err < 0)
return err;
@@ -893,6 +996,30 @@ static int host1x_drm_remove(struct host1x_device *dev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int host1x_drm_suspend(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ drm_kms_helper_poll_disable(drm);
+
+ return 0;
+}
+
+static int host1x_drm_resume(struct device *dev)
+{
+ struct drm_device *drm = dev_get_drvdata(dev);
+
+ drm_kms_helper_poll_enable(drm);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops host1x_drm_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(host1x_drm_suspend, host1x_drm_resume)
+};
+
static const struct of_device_id host1x_drm_subdevs[] = {
{ .compatible = "nvidia,tegra20-dc", },
{ .compatible = "nvidia,tegra20-hdmi", },
@@ -912,7 +1039,10 @@ static const struct of_device_id host1x_drm_subdevs[] = {
};
static struct host1x_driver host1x_drm_driver = {
- .name = "drm",
+ .driver = {
+ .name = "drm",
+ .pm = &host1x_drm_pm_ops,
+ },
.probe = host1x_drm_probe,
.remove = host1x_drm_remove,
.subdevs = host1x_drm_subdevs,
diff --git a/drivers/gpu/drm/tegra/drm.h b/drivers/gpu/drm/tegra/drm.h
index 3a3b2e7b5b3f..8cb2dfeaa957 100644
--- a/drivers/gpu/drm/tegra/drm.h
+++ b/drivers/gpu/drm/tegra/drm.h
@@ -50,6 +50,12 @@ struct tegra_drm {
#endif
unsigned int pitch_align;
+
+ struct {
+ struct drm_atomic_state *state;
+ struct work_struct work;
+ struct mutex lock;
+ } commit;
};
struct tegra_drm_client;
@@ -164,45 +170,31 @@ struct tegra_dc_window {
unsigned int h;
} dst;
unsigned int bits_per_pixel;
- unsigned int format;
- unsigned int swap;
unsigned int stride[2];
unsigned long base[3];
bool bottom_up;
struct tegra_bo_tiling tiling;
+ u32 format;
+ u32 swap;
};
/* from dc.c */
void tegra_dc_enable_vblank(struct tegra_dc *dc);
void tegra_dc_disable_vblank(struct tegra_dc *dc);
void tegra_dc_cancel_page_flip(struct drm_crtc *crtc, struct drm_file *file);
-
-struct tegra_output_ops {
- int (*enable)(struct tegra_output *output);
- int (*disable)(struct tegra_output *output);
- int (*setup_clock)(struct tegra_output *output, struct clk *clk,
- unsigned long pclk, unsigned int *div);
- int (*check_mode)(struct tegra_output *output,
- struct drm_display_mode *mode,
- enum drm_mode_status *status);
- enum drm_connector_status (*detect)(struct tegra_output *output);
-};
-
-enum tegra_output_type {
- TEGRA_OUTPUT_RGB,
- TEGRA_OUTPUT_HDMI,
- TEGRA_OUTPUT_DSI,
- TEGRA_OUTPUT_EDP,
-};
+void tegra_dc_commit(struct tegra_dc *dc);
+int tegra_dc_setup_clock(struct tegra_dc *dc, struct clk *parent,
+ unsigned long pclk, unsigned int div);
+int tegra_dc_state_setup_clock(struct tegra_dc *dc,
+ struct drm_crtc_state *crtc_state,
+ struct clk *clk, unsigned long pclk,
+ unsigned int div);
struct tegra_output {
struct device_node *of_node;
struct device *dev;
- const struct tegra_output_ops *ops;
- enum tegra_output_type type;
-
struct drm_panel *panel;
struct i2c_adapter *ddc;
const struct edid *edid;
@@ -223,42 +215,6 @@ static inline struct tegra_output *connector_to_output(struct drm_connector *c)
return container_of(c, struct tegra_output, connector);
}
-static inline int tegra_output_enable(struct tegra_output *output)
-{
- if (output && output->ops && output->ops->enable)
- return output->ops->enable(output);
-
- return output ? -ENOSYS : -EINVAL;
-}
-
-static inline int tegra_output_disable(struct tegra_output *output)
-{
- if (output && output->ops && output->ops->disable)
- return output->ops->disable(output);
-
- return output ? -ENOSYS : -EINVAL;
-}
-
-static inline int tegra_output_setup_clock(struct tegra_output *output,
- struct clk *clk, unsigned long pclk,
- unsigned int *div)
-{
- if (output && output->ops && output->ops->setup_clock)
- return output->ops->setup_clock(output, clk, pclk, div);
-
- return output ? -ENOSYS : -EINVAL;
-}
-
-static inline int tegra_output_check_mode(struct tegra_output *output,
- struct drm_display_mode *mode,
- enum drm_mode_status *status)
-{
- if (output && output->ops && output->ops->check_mode)
- return output->ops->check_mode(output, mode, status);
-
- return output ? -ENOSYS : -EINVAL;
-}
-
/* from rgb.c */
int tegra_dc_rgb_probe(struct tegra_dc *dc);
int tegra_dc_rgb_remove(struct tegra_dc *dc);
@@ -267,9 +223,18 @@ int tegra_dc_rgb_exit(struct tegra_dc *dc);
/* from output.c */
int tegra_output_probe(struct tegra_output *output);
-int tegra_output_remove(struct tegra_output *output);
+void tegra_output_remove(struct tegra_output *output);
int tegra_output_init(struct drm_device *drm, struct tegra_output *output);
-int tegra_output_exit(struct tegra_output *output);
+void tegra_output_exit(struct tegra_output *output);
+
+int tegra_output_connector_get_modes(struct drm_connector *connector);
+struct drm_encoder *
+tegra_output_connector_best_encoder(struct drm_connector *connector);
+enum drm_connector_status
+tegra_output_connector_detect(struct drm_connector *connector, bool force);
+void tegra_output_connector_destroy(struct drm_connector *connector);
+
+void tegra_output_encoder_destroy(struct drm_encoder *encoder);
/* from dpaux.c */
struct tegra_dpaux;
@@ -291,12 +256,16 @@ struct tegra_bo *tegra_fb_get_plane(struct drm_framebuffer *framebuffer,
bool tegra_fb_is_bottom_up(struct drm_framebuffer *framebuffer);
int tegra_fb_get_tiling(struct drm_framebuffer *framebuffer,
struct tegra_bo_tiling *tiling);
+struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
+ struct drm_file *file,
+ struct drm_mode_fb_cmd2 *cmd);
int tegra_drm_fb_prepare(struct drm_device *drm);
void tegra_drm_fb_free(struct drm_device *drm);
int tegra_drm_fb_init(struct drm_device *drm);
void tegra_drm_fb_exit(struct drm_device *drm);
#ifdef CONFIG_DRM_TEGRA_FBDEV
void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev);
+void tegra_fb_output_poll_changed(struct drm_device *drm);
#endif
extern struct platform_driver tegra_dc_driver;
diff --git a/drivers/gpu/drm/tegra/dsi.c b/drivers/gpu/drm/tegra/dsi.c
index 33f67fd601c6..ed970f622903 100644
--- a/drivers/gpu/drm/tegra/dsi.c
+++ b/drivers/gpu/drm/tegra/dsi.c
@@ -17,6 +17,7 @@
#include <linux/regulator/consumer.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_mipi_dsi.h>
#include <drm/drm_panel.h>
@@ -27,6 +28,28 @@
#include "dsi.h"
#include "mipi-phy.h"
+struct tegra_dsi_state {
+ struct drm_connector_state base;
+
+ struct mipi_dphy_timing timing;
+ unsigned long period;
+
+ unsigned int vrefresh;
+ unsigned int lanes;
+ unsigned long pclk;
+ unsigned long bclk;
+
+ enum tegra_dsi_format format;
+ unsigned int mul;
+ unsigned int div;
+};
+
+static inline struct tegra_dsi_state *
+to_dsi_state(struct drm_connector_state *state)
+{
+ return container_of(state, struct tegra_dsi_state, base);
+}
+
struct tegra_dsi {
struct host1x_client client;
struct tegra_output output;
@@ -51,7 +74,6 @@ struct tegra_dsi {
struct mipi_dsi_host host;
struct regulator *vdd;
- bool enabled;
unsigned int video_fifo_depth;
unsigned int host_fifo_depth;
@@ -77,13 +99,17 @@ static inline struct tegra_dsi *to_dsi(struct tegra_output *output)
return container_of(output, struct tegra_dsi, output);
}
-static inline unsigned long tegra_dsi_readl(struct tegra_dsi *dsi,
- unsigned long reg)
+static struct tegra_dsi_state *tegra_dsi_get_state(struct tegra_dsi *dsi)
+{
+ return to_dsi_state(dsi->output.connector.state);
+}
+
+static inline u32 tegra_dsi_readl(struct tegra_dsi *dsi, unsigned long reg)
{
return readl(dsi->regs + (reg << 2));
}
-static inline void tegra_dsi_writel(struct tegra_dsi *dsi, unsigned long value,
+static inline void tegra_dsi_writel(struct tegra_dsi *dsi, u32 value,
unsigned long reg)
{
writel(value, dsi->regs + (reg << 2));
@@ -95,7 +121,7 @@ static int tegra_dsi_show_regs(struct seq_file *s, void *data)
struct tegra_dsi *dsi = node->info_ent->data;
#define DUMP_REG(name) \
- seq_printf(s, "%-32s %#05x %08lx\n", #name, name, \
+ seq_printf(s, "%-32s %#05x %08x\n", #name, name, \
tegra_dsi_readl(dsi, name))
DUMP_REG(DSI_INCR_SYNCPT);
@@ -230,7 +256,7 @@ remove:
return err;
}
-static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
+static void tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
{
drm_debugfs_remove_files(dsi->debugfs_files, ARRAY_SIZE(debugfs_files),
dsi->minor);
@@ -241,8 +267,6 @@ static int tegra_dsi_debugfs_exit(struct tegra_dsi *dsi)
debugfs_remove(dsi->debugfs);
dsi->debugfs = NULL;
-
- return 0;
}
#define PKT_ID0(id) ((((id) & 0x3f) << 3) | (1 << 9))
@@ -338,61 +362,36 @@ static const u32 pkt_seq_command_mode[NUM_PKT_SEQ] = {
[11] = 0,
};
-static int tegra_dsi_set_phy_timing(struct tegra_dsi *dsi)
+static void tegra_dsi_set_phy_timing(struct tegra_dsi *dsi,
+ unsigned long period,
+ const struct mipi_dphy_timing *timing)
{
- struct mipi_dphy_timing timing;
- unsigned long value, period;
- long rate;
- int err;
-
- rate = clk_get_rate(dsi->clk);
- if (rate < 0)
- return rate;
-
- period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, rate * 2);
-
- err = mipi_dphy_timing_get_default(&timing, period);
- if (err < 0)
- return err;
-
- err = mipi_dphy_timing_validate(&timing, period);
- if (err < 0) {
- dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
- return err;
- }
-
- /*
- * The D-PHY timing fields below are expressed in byte-clock cycles,
- * so multiply the period by 8.
- */
- period *= 8;
+ u32 value;
- value = DSI_TIMING_FIELD(timing.hsexit, period, 1) << 24 |
- DSI_TIMING_FIELD(timing.hstrail, period, 0) << 16 |
- DSI_TIMING_FIELD(timing.hszero, period, 3) << 8 |
- DSI_TIMING_FIELD(timing.hsprepare, period, 1);
+ value = DSI_TIMING_FIELD(timing->hsexit, period, 1) << 24 |
+ DSI_TIMING_FIELD(timing->hstrail, period, 0) << 16 |
+ DSI_TIMING_FIELD(timing->hszero, period, 3) << 8 |
+ DSI_TIMING_FIELD(timing->hsprepare, period, 1);
tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_0);
- value = DSI_TIMING_FIELD(timing.clktrail, period, 1) << 24 |
- DSI_TIMING_FIELD(timing.clkpost, period, 1) << 16 |
- DSI_TIMING_FIELD(timing.clkzero, period, 1) << 8 |
- DSI_TIMING_FIELD(timing.lpx, period, 1);
+ value = DSI_TIMING_FIELD(timing->clktrail, period, 1) << 24 |
+ DSI_TIMING_FIELD(timing->clkpost, period, 1) << 16 |
+ DSI_TIMING_FIELD(timing->clkzero, period, 1) << 8 |
+ DSI_TIMING_FIELD(timing->lpx, period, 1);
tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_1);
- value = DSI_TIMING_FIELD(timing.clkprepare, period, 1) << 16 |
- DSI_TIMING_FIELD(timing.clkpre, period, 1) << 8 |
+ value = DSI_TIMING_FIELD(timing->clkprepare, period, 1) << 16 |
+ DSI_TIMING_FIELD(timing->clkpre, period, 1) << 8 |
DSI_TIMING_FIELD(0xff * period, period, 0) << 0;
tegra_dsi_writel(dsi, value, DSI_PHY_TIMING_2);
- value = DSI_TIMING_FIELD(timing.taget, period, 1) << 16 |
- DSI_TIMING_FIELD(timing.tasure, period, 1) << 8 |
- DSI_TIMING_FIELD(timing.tago, period, 1);
+ value = DSI_TIMING_FIELD(timing->taget, period, 1) << 16 |
+ DSI_TIMING_FIELD(timing->tasure, period, 1) << 8 |
+ DSI_TIMING_FIELD(timing->tago, period, 1);
tegra_dsi_writel(dsi, value, DSI_BTA_TIMING);
if (dsi->slave)
- return tegra_dsi_set_phy_timing(dsi->slave);
-
- return 0;
+ tegra_dsi_set_phy_timing(dsi->slave, period, timing);
}
static int tegra_dsi_get_muldiv(enum mipi_dsi_pixel_format format,
@@ -484,14 +483,22 @@ static unsigned int tegra_dsi_get_lanes(struct tegra_dsi *dsi)
return dsi->lanes;
}
-static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
- const struct drm_display_mode *mode)
+static void tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
+ const struct drm_display_mode *mode)
{
unsigned int hact, hsw, hbp, hfp, i, mul, div;
- enum tegra_dsi_format format;
+ struct tegra_dsi_state *state;
const u32 *pkt_seq;
u32 value;
- int err;
+
+ /* XXX: pass in state into this function? */
+ if (dsi->master)
+ state = tegra_dsi_get_state(dsi->master);
+ else
+ state = tegra_dsi_get_state(dsi);
+
+ mul = state->mul;
+ div = state->div;
if (dsi->flags & MIPI_DSI_MODE_VIDEO_SYNC_PULSE) {
DRM_DEBUG_KMS("Non-burst video mode with sync pulses\n");
@@ -504,15 +511,8 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
pkt_seq = pkt_seq_command_mode;
}
- err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
- if (err < 0)
- return err;
-
- err = tegra_dsi_get_format(dsi->format, &format);
- if (err < 0)
- return err;
-
- value = DSI_CONTROL_CHANNEL(0) | DSI_CONTROL_FORMAT(format) |
+ value = DSI_CONTROL_CHANNEL(0) |
+ DSI_CONTROL_FORMAT(state->format) |
DSI_CONTROL_LANES(dsi->lanes - 1) |
DSI_CONTROL_SOURCE(pipe);
tegra_dsi_writel(dsi, value, DSI_CONTROL);
@@ -591,8 +591,8 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
/* set SOL delay */
if (dsi->master || dsi->slave) {
- unsigned int lanes = tegra_dsi_get_lanes(dsi);
unsigned long delay, bclk, bclk_ganged;
+ unsigned int lanes = state->lanes;
/* SOL to valid, valid to FIFO and FIFO write delay */
delay = 4 + 4 + 2;
@@ -612,9 +612,7 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
}
if (dsi->slave) {
- err = tegra_dsi_configure(dsi->slave, pipe, mode);
- if (err < 0)
- return err;
+ tegra_dsi_configure(dsi->slave, pipe, mode);
/*
* TODO: Support modes other than symmetrical left-right
@@ -624,49 +622,6 @@ static int tegra_dsi_configure(struct tegra_dsi *dsi, unsigned int pipe,
tegra_dsi_ganged_enable(dsi->slave, mode->hdisplay / 2,
mode->hdisplay / 2);
}
-
- return 0;
-}
-
-static int tegra_output_dsi_enable(struct tegra_output *output)
-{
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
- const struct drm_display_mode *mode = &dc->base.mode;
- struct tegra_dsi *dsi = to_dsi(output);
- u32 value;
- int err;
-
- if (dsi->enabled)
- return 0;
-
- err = tegra_dsi_configure(dsi, dc->pipe, mode);
- if (err < 0)
- return err;
-
- /* enable display controller */
- value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
- value |= DSI_ENABLE;
- tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
-
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- value |= DISP_CTRL_MODE_C_DISPLAY;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
- tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
- /* enable DSI controller */
- tegra_dsi_enable(dsi);
-
- dsi->enabled = true;
-
- return 0;
}
static int tegra_dsi_wait_idle(struct tegra_dsi *dsi, unsigned long timeout)
@@ -705,6 +660,29 @@ static void tegra_dsi_ganged_disable(struct tegra_dsi *dsi)
tegra_dsi_writel(dsi, 0, DSI_GANGED_MODE_CONTROL);
}
+static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
+ unsigned int vrefresh)
+{
+ unsigned int timeout;
+ u32 value;
+
+ /* one frame high-speed transmission timeout */
+ timeout = (bclk / vrefresh) / 512;
+ value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
+ tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
+
+ /* 2 ms peripheral timeout for panel */
+ timeout = 2 * bclk / 512 * 1000;
+ value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
+ tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
+
+ value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
+ tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+
+ if (dsi->slave)
+ tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
+}
+
static void tegra_dsi_disable(struct tegra_dsi *dsi)
{
u32 value;
@@ -724,15 +702,149 @@ static void tegra_dsi_disable(struct tegra_dsi *dsi)
usleep_range(5000, 10000);
}
-static int tegra_output_dsi_disable(struct tegra_output *output)
+static void tegra_dsi_soft_reset(struct tegra_dsi *dsi)
+{
+ u32 value;
+
+ value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+ value &= ~DSI_POWER_CONTROL_ENABLE;
+ tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+ usleep_range(300, 1000);
+
+ value = tegra_dsi_readl(dsi, DSI_POWER_CONTROL);
+ value |= DSI_POWER_CONTROL_ENABLE;
+ tegra_dsi_writel(dsi, value, DSI_POWER_CONTROL);
+
+ usleep_range(300, 1000);
+
+ value = tegra_dsi_readl(dsi, DSI_TRIGGER);
+ if (value)
+ tegra_dsi_writel(dsi, 0, DSI_TRIGGER);
+
+ if (dsi->slave)
+ tegra_dsi_soft_reset(dsi->slave);
+}
+
+static void tegra_dsi_connector_dpms(struct drm_connector *connector, int mode)
+{
+}
+
+static void tegra_dsi_connector_reset(struct drm_connector *connector)
+{
+ struct tegra_dsi_state *state;
+
+ kfree(connector->state);
+ connector->state = NULL;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (state)
+ connector->state = &state->base;
+}
+
+static struct drm_connector_state *
+tegra_dsi_connector_duplicate_state(struct drm_connector *connector)
+{
+ struct tegra_dsi_state *state = to_dsi_state(connector->state);
+ struct tegra_dsi_state *copy;
+
+ copy = kmemdup(state, sizeof(*state), GFP_KERNEL);
+ if (!copy)
+ return NULL;
+
+ return &copy->base;
+}
+
+static const struct drm_connector_funcs tegra_dsi_connector_funcs = {
+ .dpms = tegra_dsi_connector_dpms,
+ .reset = tegra_dsi_connector_reset,
+ .detect = tegra_output_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = tegra_output_connector_destroy,
+ .atomic_duplicate_state = tegra_dsi_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum drm_mode_status
+tegra_dsi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs tegra_dsi_connector_helper_funcs = {
+ .get_modes = tegra_output_connector_get_modes,
+ .mode_valid = tegra_dsi_connector_mode_valid,
+ .best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_dsi_encoder_funcs = {
+ .destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_dsi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_dsi_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_dsi_encoder_commit(struct drm_encoder *encoder)
{
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+}
+
+static void tegra_dsi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
+{
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+ struct tegra_dsi *dsi = to_dsi(output);
+ struct tegra_dsi_state *state;
+ u32 value;
+
+ state = tegra_dsi_get_state(dsi);
+
+ tegra_dsi_set_timeout(dsi, state->bclk, state->vrefresh);
+
+ /*
+ * The D-PHY timing fields are expressed in byte-clock cycles, so
+ * multiply the period by 8.
+ */
+ tegra_dsi_set_phy_timing(dsi, state->period * 8, &state->timing);
+
+ if (output->panel)
+ drm_panel_prepare(output->panel);
+
+ tegra_dsi_configure(dsi, dc->pipe, mode);
+
+ /* enable display controller */
+ value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
+ value |= DSI_ENABLE;
+ tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
+
+ tegra_dc_commit(dc);
+
+ /* enable DSI controller */
+ tegra_dsi_enable(dsi);
+
+ if (output->panel)
+ drm_panel_enable(output->panel);
+
+ return;
+}
+
+static void tegra_dsi_encoder_disable(struct drm_encoder *encoder)
+{
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
struct tegra_dsi *dsi = to_dsi(output);
- unsigned long value;
+ u32 value;
int err;
- if (!dsi->enabled)
- return 0;
+ if (output->panel)
+ drm_panel_disable(output->panel);
tegra_dsi_video_disable(dsi);
@@ -741,85 +853,78 @@ static int tegra_output_dsi_disable(struct tegra_output *output)
* sure it's only executed when the output is attached to one.
*/
if (dc) {
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
value &= ~DSI_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
- tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ tegra_dc_commit(dc);
}
err = tegra_dsi_wait_idle(dsi, 100);
if (err < 0)
dev_dbg(dsi->dev, "failed to idle DSI: %d\n", err);
- tegra_dsi_disable(dsi);
+ tegra_dsi_soft_reset(dsi);
- dsi->enabled = false;
+ if (output->panel)
+ drm_panel_unprepare(output->panel);
- return 0;
-}
-
-static void tegra_dsi_set_timeout(struct tegra_dsi *dsi, unsigned long bclk,
- unsigned int vrefresh)
-{
- unsigned int timeout;
- u32 value;
-
- /* one frame high-speed transmission timeout */
- timeout = (bclk / vrefresh) / 512;
- value = DSI_TIMEOUT_LRX(0x2000) | DSI_TIMEOUT_HTX(timeout);
- tegra_dsi_writel(dsi, value, DSI_TIMEOUT_0);
-
- /* 2 ms peripheral timeout for panel */
- timeout = 2 * bclk / 512 * 1000;
- value = DSI_TIMEOUT_PR(timeout) | DSI_TIMEOUT_TA(0x2000);
- tegra_dsi_writel(dsi, value, DSI_TIMEOUT_1);
-
- value = DSI_TALLY_TA(0) | DSI_TALLY_LRX(0) | DSI_TALLY_HTX(0);
- tegra_dsi_writel(dsi, value, DSI_TO_TALLY);
+ tegra_dsi_disable(dsi);
- if (dsi->slave)
- tegra_dsi_set_timeout(dsi->slave, bclk, vrefresh);
+ return;
}
-static int tegra_output_dsi_setup_clock(struct tegra_output *output,
- struct clk *clk, unsigned long pclk,
- unsigned int *divp)
+static int
+tegra_dsi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
- struct drm_display_mode *mode = &dc->base.mode;
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dsi_state *state = to_dsi_state(conn_state);
+ struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
struct tegra_dsi *dsi = to_dsi(output);
- unsigned int mul, div, vrefresh, lanes;
- unsigned long bclk, plld;
+ unsigned int scdiv;
+ unsigned long plld;
int err;
- lanes = tegra_dsi_get_lanes(dsi);
+ state->pclk = crtc_state->mode.clock * 1000;
+
+ err = tegra_dsi_get_muldiv(dsi->format, &state->mul, &state->div);
+ if (err < 0)
+ return err;
+
+ state->lanes = tegra_dsi_get_lanes(dsi);
- err = tegra_dsi_get_muldiv(dsi->format, &mul, &div);
+ err = tegra_dsi_get_format(dsi->format, &state->format);
if (err < 0)
return err;
- DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", mul, div, lanes);
- vrefresh = drm_mode_vrefresh(mode);
- DRM_DEBUG_KMS("vrefresh: %u\n", vrefresh);
+ state->vrefresh = drm_mode_vrefresh(&crtc_state->mode);
/* compute byte clock */
- bclk = (pclk * mul) / (div * lanes);
+ state->bclk = (state->pclk * state->mul) / (state->div * state->lanes);
+
+ DRM_DEBUG_KMS("mul: %u, div: %u, lanes: %u\n", state->mul, state->div,
+ state->lanes);
+ DRM_DEBUG_KMS("format: %u, vrefresh: %u\n", state->format,
+ state->vrefresh);
+ DRM_DEBUG_KMS("bclk: %lu\n", state->bclk);
/*
* Compute bit clock and round up to the next MHz.
*/
- plld = DIV_ROUND_UP(bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
+ plld = DIV_ROUND_UP(state->bclk * 8, USEC_PER_SEC) * USEC_PER_SEC;
+ state->period = DIV_ROUND_CLOSEST(NSEC_PER_SEC, plld);
+
+ err = mipi_dphy_timing_get_default(&state->timing, state->period);
+ if (err < 0)
+ return err;
+
+ err = mipi_dphy_timing_validate(&state->timing, state->period);
+ if (err < 0) {
+ dev_err(dsi->dev, "failed to validate D-PHY timing: %d\n", err);
+ return err;
+ }
/*
* We divide the frequency by two here, but we make up for that by
@@ -828,19 +933,6 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output,
*/
plld /= 2;
- err = clk_set_parent(clk, dsi->clk_parent);
- if (err < 0) {
- dev_err(dsi->dev, "failed to set parent clock: %d\n", err);
- return err;
- }
-
- err = clk_set_rate(dsi->clk_parent, plld);
- if (err < 0) {
- dev_err(dsi->dev, "failed to set base clock rate to %lu Hz\n",
- plld);
- return err;
- }
-
/*
* Derive pixel clock from bit clock using the shift clock divider.
* Note that this is only half of what we would expect, but we need
@@ -851,44 +943,30 @@ static int tegra_output_dsi_setup_clock(struct tegra_output *output,
* not working properly otherwise. Perhaps the PLLs cannot generate
* frequencies sufficiently high.
*/
- *divp = ((8 * mul) / (div * lanes)) - 2;
+ scdiv = ((8 * state->mul) / (state->div * state->lanes)) - 2;
- /*
- * XXX: Move the below somewhere else so that we don't need to have
- * access to the vrefresh in this function?
- */
- tegra_dsi_set_timeout(dsi, bclk, vrefresh);
-
- err = tegra_dsi_set_phy_timing(dsi);
- if (err < 0)
+ err = tegra_dc_state_setup_clock(dc, crtc_state, dsi->clk_parent,
+ plld, scdiv);
+ if (err < 0) {
+ dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
return err;
+ }
- return 0;
-}
-
-static int tegra_output_dsi_check_mode(struct tegra_output *output,
- struct drm_display_mode *mode,
- enum drm_mode_status *status)
-{
- /*
- * FIXME: For now, always assume that the mode is okay.
- */
-
- *status = MODE_OK;
-
- return 0;
+ return err;
}
-static const struct tegra_output_ops dsi_ops = {
- .enable = tegra_output_dsi_enable,
- .disable = tegra_output_dsi_disable,
- .setup_clock = tegra_output_dsi_setup_clock,
- .check_mode = tegra_output_dsi_check_mode,
+static const struct drm_encoder_helper_funcs tegra_dsi_encoder_helper_funcs = {
+ .dpms = tegra_dsi_encoder_dpms,
+ .prepare = tegra_dsi_encoder_prepare,
+ .commit = tegra_dsi_encoder_commit,
+ .mode_set = tegra_dsi_encoder_mode_set,
+ .disable = tegra_dsi_encoder_disable,
+ .atomic_check = tegra_dsi_encoder_atomic_check,
};
static int tegra_dsi_pad_enable(struct tegra_dsi *dsi)
{
- unsigned long value;
+ u32 value;
value = DSI_PAD_CONTROL_VS1_PULLDN(0) | DSI_PAD_CONTROL_VS1_PDIO(0);
tegra_dsi_writel(dsi, value, DSI_PAD_CONTROL_0);
@@ -923,17 +1001,44 @@ static int tegra_dsi_init(struct host1x_client *client)
struct tegra_dsi *dsi = host1x_client_to_dsi(client);
int err;
+ reset_control_deassert(dsi->rst);
+
+ err = tegra_dsi_pad_calibrate(dsi);
+ if (err < 0) {
+ dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
+ goto reset;
+ }
+
/* Gangsters must not register their own outputs. */
if (!dsi->master) {
- dsi->output.type = TEGRA_OUTPUT_DSI;
dsi->output.dev = client->dev;
- dsi->output.ops = &dsi_ops;
+
+ drm_connector_init(drm, &dsi->output.connector,
+ &tegra_dsi_connector_funcs,
+ DRM_MODE_CONNECTOR_DSI);
+ drm_connector_helper_add(&dsi->output.connector,
+ &tegra_dsi_connector_helper_funcs);
+ dsi->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+ drm_encoder_init(drm, &dsi->output.encoder,
+ &tegra_dsi_encoder_funcs,
+ DRM_MODE_ENCODER_DSI);
+ drm_encoder_helper_add(&dsi->output.encoder,
+ &tegra_dsi_encoder_helper_funcs);
+
+ drm_mode_connector_attach_encoder(&dsi->output.connector,
+ &dsi->output.encoder);
+ drm_connector_register(&dsi->output.connector);
err = tegra_output_init(drm, &dsi->output);
if (err < 0) {
- dev_err(client->dev, "output setup failed: %d\n", err);
- return err;
+ dev_err(client->dev,
+ "failed to initialize output: %d\n",
+ err);
+ goto reset;
}
+
+ dsi->output.encoder.possible_crtcs = 0x3;
}
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
@@ -943,34 +1048,22 @@ static int tegra_dsi_init(struct host1x_client *client)
}
return 0;
+
+reset:
+ reset_control_assert(dsi->rst);
+ return err;
}
static int tegra_dsi_exit(struct host1x_client *client)
{
struct tegra_dsi *dsi = host1x_client_to_dsi(client);
- int err;
- if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_dsi_debugfs_exit(dsi);
- if (err < 0)
- dev_err(dsi->dev, "debugfs cleanup failed: %d\n", err);
- }
+ tegra_output_exit(&dsi->output);
- if (!dsi->master) {
- err = tegra_output_disable(&dsi->output);
- if (err < 0) {
- dev_err(client->dev, "output failed to disable: %d\n",
- err);
- return err;
- }
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ tegra_dsi_debugfs_exit(dsi);
- err = tegra_output_exit(&dsi->output);
- if (err < 0) {
- dev_err(client->dev, "output cleanup failed: %d\n",
- err);
- return err;
- }
- }
+ reset_control_assert(dsi->rst);
return 0;
}
@@ -1398,13 +1491,6 @@ static int tegra_dsi_probe(struct platform_device *pdev)
if (IS_ERR(dsi->rst))
return PTR_ERR(dsi->rst);
- err = reset_control_deassert(dsi->rst);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to bring DSI out of reset: %d\n",
- err);
- return err;
- }
-
dsi->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(dsi->clk)) {
dev_err(&pdev->dev, "cannot get DSI clock\n");
@@ -1470,12 +1556,6 @@ static int tegra_dsi_probe(struct platform_device *pdev)
goto disable_vdd;
}
- err = tegra_dsi_pad_calibrate(dsi);
- if (err < 0) {
- dev_err(dsi->dev, "MIPI calibration failed: %d\n", err);
- goto mipi_free;
- }
-
dsi->host.ops = &tegra_dsi_host_ops;
dsi->host.dev = &pdev->dev;
@@ -1527,6 +1607,8 @@ static int tegra_dsi_remove(struct platform_device *pdev)
return err;
}
+ tegra_output_remove(&dsi->output);
+
mipi_dsi_host_unregister(&dsi->host);
tegra_mipi_free(dsi->mipi);
@@ -1535,12 +1617,6 @@ static int tegra_dsi_remove(struct platform_device *pdev)
clk_disable_unprepare(dsi->clk);
reset_control_assert(dsi->rst);
- err = tegra_output_remove(&dsi->output);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to remove output: %d\n", err);
- return err;
- }
-
return 0;
}
diff --git a/drivers/gpu/drm/tegra/fb.c b/drivers/gpu/drm/tegra/fb.c
index e9c715d89261..397fb34d5d5b 100644
--- a/drivers/gpu/drm/tegra/fb.c
+++ b/drivers/gpu/drm/tegra/fb.c
@@ -129,9 +129,9 @@ static struct tegra_fb *tegra_fb_alloc(struct drm_device *drm,
return fb;
}
-static struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
- struct drm_file *file,
- struct drm_mode_fb_cmd2 *cmd)
+struct drm_framebuffer *tegra_fb_create(struct drm_device *drm,
+ struct drm_file *file,
+ struct drm_mode_fb_cmd2 *cmd)
{
unsigned int hsub, vsub, i;
struct tegra_bo *planes[4];
@@ -377,7 +377,7 @@ void tegra_fbdev_restore_mode(struct tegra_fbdev *fbdev)
drm_fb_helper_restore_fbdev_mode_unlocked(&fbdev->base);
}
-static void tegra_fb_output_poll_changed(struct drm_device *drm)
+void tegra_fb_output_poll_changed(struct drm_device *drm)
{
struct tegra_drm *tegra = drm->dev_private;
@@ -386,28 +386,11 @@ static void tegra_fb_output_poll_changed(struct drm_device *drm)
}
#endif
-static const struct drm_mode_config_funcs tegra_drm_mode_funcs = {
- .fb_create = tegra_fb_create,
-#ifdef CONFIG_DRM_TEGRA_FBDEV
- .output_poll_changed = tegra_fb_output_poll_changed,
-#endif
-};
-
int tegra_drm_fb_prepare(struct drm_device *drm)
{
#ifdef CONFIG_DRM_TEGRA_FBDEV
struct tegra_drm *tegra = drm->dev_private;
-#endif
- drm->mode_config.min_width = 0;
- drm->mode_config.min_height = 0;
-
- drm->mode_config.max_width = 4096;
- drm->mode_config.max_height = 4096;
-
- drm->mode_config.funcs = &tegra_drm_mode_funcs;
-
-#ifdef CONFIG_DRM_TEGRA_FBDEV
tegra->fbdev = tegra_fbdev_create(drm);
if (IS_ERR(tegra->fbdev))
return PTR_ERR(tegra->fbdev);
diff --git a/drivers/gpu/drm/tegra/gem.c b/drivers/gpu/drm/tegra/gem.c
index 8777b7f75791..cfb481943b6b 100644
--- a/drivers/gpu/drm/tegra/gem.c
+++ b/drivers/gpu/drm/tegra/gem.c
@@ -92,36 +92,6 @@ static const struct host1x_bo_ops tegra_bo_ops = {
.kunmap = tegra_bo_kunmap,
};
-/*
- * A generic iommu_map_sg() function is being reviewed and will hopefully be
- * merged soon. At that point this function can be dropped in favour of the
- * one provided by the IOMMU API.
- */
-static ssize_t __iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
- struct scatterlist *sg, unsigned int nents,
- int prot)
-{
- struct scatterlist *s;
- size_t offset = 0;
- unsigned int i;
- int err;
-
- for_each_sg(sg, s, nents, i) {
- phys_addr_t phys = page_to_phys(sg_page(s));
- size_t length = s->offset + s->length;
-
- err = iommu_map(domain, iova + offset, phys, length, prot);
- if (err < 0) {
- iommu_unmap(domain, iova, offset);
- return err;
- }
-
- offset += length;
- }
-
- return offset;
-}
-
static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
{
int prot = IOMMU_READ | IOMMU_WRITE;
@@ -144,8 +114,8 @@ static int tegra_bo_iommu_map(struct tegra_drm *tegra, struct tegra_bo *bo)
bo->paddr = bo->mm->start;
- err = __iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl,
- bo->sgt->nents, prot);
+ err = iommu_map_sg(tegra->domain, bo->paddr, bo->sgt->sgl,
+ bo->sgt->nents, prot);
if (err < 0) {
dev_err(tegra->drm->dev, "failed to map buffer: %zd\n", err);
goto remove;
@@ -244,10 +214,8 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
for_each_sg(sgt->sgl, s, sgt->nents, i)
sg_dma_address(s) = sg_phys(s);
- if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0) {
- sgt = ERR_PTR(-ENOMEM);
+ if (dma_map_sg(drm->dev, sgt->sgl, sgt->nents, DMA_TO_DEVICE) == 0)
goto release_sgt;
- }
bo->sgt = sgt;
@@ -256,6 +224,7 @@ static int tegra_bo_get_pages(struct drm_device *drm, struct tegra_bo *bo)
release_sgt:
sg_free_table(sgt);
kfree(sgt);
+ sgt = ERR_PTR(-ENOMEM);
put_pages:
drm_gem_put_pages(&bo->gem, bo->pages, false, false);
return PTR_ERR(sgt);
diff --git a/drivers/gpu/drm/tegra/hdmi.c b/drivers/gpu/drm/tegra/hdmi.c
index ffe26547328d..7eaaee74a039 100644
--- a/drivers/gpu/drm/tegra/hdmi.c
+++ b/drivers/gpu/drm/tegra/hdmi.c
@@ -9,10 +9,15 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
+#include <linux/gpio.h>
#include <linux/hdmi.h>
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+
#include "hdmi.h"
#include "drm.h"
#include "dc.h"
@@ -31,7 +36,7 @@ struct tegra_hdmi_config {
unsigned int num_tmds;
unsigned long fuse_override_offset;
- unsigned long fuse_override_value;
+ u32 fuse_override_value;
bool has_sor_io_peak_current;
};
@@ -40,7 +45,6 @@ struct tegra_hdmi {
struct host1x_client client;
struct tegra_output output;
struct device *dev;
- bool enabled;
struct regulator *hdmi;
struct regulator *pll;
@@ -85,16 +89,16 @@ enum {
HDA,
};
-static inline unsigned long tegra_hdmi_readl(struct tegra_hdmi *hdmi,
- unsigned long reg)
+static inline u32 tegra_hdmi_readl(struct tegra_hdmi *hdmi,
+ unsigned long offset)
{
- return readl(hdmi->regs + (reg << 2));
+ return readl(hdmi->regs + (offset << 2));
}
-static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, unsigned long val,
- unsigned long reg)
+static inline void tegra_hdmi_writel(struct tegra_hdmi *hdmi, u32 value,
+ unsigned long offset)
{
- writel(val, hdmi->regs + (reg << 2));
+ writel(value, hdmi->regs + (offset << 2));
}
struct tegra_hdmi_audio_config {
@@ -455,8 +459,8 @@ static void tegra_hdmi_setup_audio_fs_tables(struct tegra_hdmi *hdmi)
for (i = 0; i < ARRAY_SIZE(freqs); i++) {
unsigned int f = freqs[i];
unsigned int eight_half;
- unsigned long value;
unsigned int delta;
+ u32 value;
if (f > 96000)
delta = 2;
@@ -477,7 +481,7 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk)
struct device_node *node = hdmi->dev->of_node;
const struct tegra_hdmi_audio_config *config;
unsigned int offset = 0;
- unsigned long value;
+ u32 value;
switch (hdmi->audio_source) {
case HDA:
@@ -571,9 +575,9 @@ static int tegra_hdmi_setup_audio(struct tegra_hdmi *hdmi, unsigned int pclk)
return 0;
}
-static inline unsigned long tegra_hdmi_subpack(const u8 *ptr, size_t size)
+static inline u32 tegra_hdmi_subpack(const u8 *ptr, size_t size)
{
- unsigned long value = 0;
+ u32 value = 0;
size_t i;
for (i = size; i > 0; i--)
@@ -587,8 +591,8 @@ static void tegra_hdmi_write_infopack(struct tegra_hdmi *hdmi, const void *data,
{
const u8 *ptr = data;
unsigned long offset;
- unsigned long value;
size_t i, j;
+ u32 value;
switch (ptr[0]) {
case HDMI_INFOFRAME_TYPE_AVI:
@@ -707,9 +711,9 @@ static void tegra_hdmi_setup_audio_infoframe(struct tegra_hdmi *hdmi)
static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi)
{
struct hdmi_vendor_infoframe frame;
- unsigned long value;
u8 buffer[10];
ssize_t err;
+ u32 value;
if (!hdmi->stereo) {
value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_HDMI_GENERIC_CTRL);
@@ -738,7 +742,7 @@ static void tegra_hdmi_setup_stereo_infoframe(struct tegra_hdmi *hdmi)
static void tegra_hdmi_setup_tmds(struct tegra_hdmi *hdmi,
const struct tmds_config *tmds)
{
- unsigned long value;
+ u32 value;
tegra_hdmi_writel(hdmi, tmds->pll0, HDMI_NV_PDISP_SOR_PLL0);
tegra_hdmi_writel(hdmi, tmds->pll1, HDMI_NV_PDISP_SOR_PLL1);
@@ -768,21 +772,78 @@ static bool tegra_output_is_hdmi(struct tegra_output *output)
return drm_detect_hdmi_monitor(edid);
}
-static int tegra_output_hdmi_enable(struct tegra_output *output)
+static void tegra_hdmi_connector_dpms(struct drm_connector *connector,
+ int mode)
+{
+}
+
+static const struct drm_connector_funcs tegra_hdmi_connector_funcs = {
+ .dpms = tegra_hdmi_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = tegra_output_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = tegra_output_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum drm_mode_status
+tegra_hdmi_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ struct tegra_output *output = connector_to_output(connector);
+ struct tegra_hdmi *hdmi = to_hdmi(output);
+ unsigned long pclk = mode->clock * 1000;
+ enum drm_mode_status status = MODE_OK;
+ struct clk *parent;
+ long err;
+
+ parent = clk_get_parent(hdmi->clk_parent);
+
+ err = clk_round_rate(parent, pclk * 4);
+ if (err <= 0)
+ status = MODE_NOCLOCK;
+
+ return status;
+}
+
+static const struct drm_connector_helper_funcs
+tegra_hdmi_connector_helper_funcs = {
+ .get_modes = tegra_output_connector_get_modes,
+ .mode_valid = tegra_hdmi_connector_mode_valid,
+ .best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_hdmi_encoder_funcs = {
+ .destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_hdmi_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_hdmi_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_hdmi_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
{
unsigned int h_sync_width, h_front_porch, h_back_porch, i, rekey;
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
- struct drm_display_mode *mode = &dc->base.mode;
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+ struct device_node *node = output->dev->of_node;
struct tegra_hdmi *hdmi = to_hdmi(output);
- struct device_node *node = hdmi->dev->of_node;
unsigned int pulse_start, div82, pclk;
- unsigned long value;
int retries = 1000;
+ u32 value;
int err;
- if (hdmi->enabled)
- return 0;
-
hdmi->dvi = !tegra_output_is_hdmi(output);
pclk = mode->clock * 1000;
@@ -790,31 +851,13 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
h_back_porch = mode->htotal - mode->hsync_end;
h_front_porch = mode->hsync_start - mode->hdisplay;
- err = regulator_enable(hdmi->pll);
- if (err < 0) {
- dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err);
- return err;
- }
-
- err = regulator_enable(hdmi->vdd);
- if (err < 0) {
- dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err);
- return err;
- }
-
err = clk_set_rate(hdmi->clk, pclk);
- if (err < 0)
- return err;
-
- err = clk_prepare_enable(hdmi->clk);
if (err < 0) {
- dev_err(hdmi->dev, "failed to enable clock: %d\n", err);
- return err;
+ dev_err(hdmi->dev, "failed to set HDMI clock frequency: %d\n",
+ err);
}
- reset_control_assert(hdmi->rst);
- usleep_range(1000, 2000);
- reset_control_deassert(hdmi->rst);
+ DRM_DEBUG_KMS("HDMI clock rate: %lu Hz\n", clk_get_rate(hdmi->clk));
/* power up sequence */
value = tegra_hdmi_readl(hdmi, HDMI_NV_PDISP_SOR_PLL0);
@@ -987,123 +1030,57 @@ static int tegra_output_hdmi_enable(struct tegra_output *output)
value |= HDMI_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- value |= DISP_CTRL_MODE_C_DISPLAY;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
- tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ tegra_dc_commit(dc);
/* TODO: add HDCP support */
-
- hdmi->enabled = true;
-
- return 0;
}
-static int tegra_output_hdmi_disable(struct tegra_output *output)
+static void tegra_hdmi_encoder_disable(struct drm_encoder *encoder)
{
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
- struct tegra_hdmi *hdmi = to_hdmi(output);
- unsigned long value;
-
- if (!hdmi->enabled)
- return 0;
+ struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
+ u32 value;
/*
* The following accesses registers of the display controller, so make
* sure it's only executed when the output is attached to one.
*/
if (dc) {
- /*
- * XXX: We can't do this here because it causes HDMI to go
- * into an erroneous state with the result that HDMI won't
- * properly work once disabled. See also a similar symptom
- * for the SOR output.
- */
- /*
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
- */
-
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
value &= ~HDMI_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
- tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ tegra_dc_commit(dc);
}
-
- clk_disable_unprepare(hdmi->clk);
- reset_control_assert(hdmi->rst);
- regulator_disable(hdmi->vdd);
- regulator_disable(hdmi->pll);
-
- hdmi->enabled = false;
-
- return 0;
}
-static int tegra_output_hdmi_setup_clock(struct tegra_output *output,
- struct clk *clk, unsigned long pclk,
- unsigned int *div)
+static int
+tegra_hdmi_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+ unsigned long pclk = crtc_state->mode.clock * 1000;
struct tegra_hdmi *hdmi = to_hdmi(output);
int err;
- err = clk_set_parent(clk, hdmi->clk_parent);
+ err = tegra_dc_state_setup_clock(dc, crtc_state, hdmi->clk_parent,
+ pclk, 0);
if (err < 0) {
- dev_err(output->dev, "failed to set parent: %d\n", err);
+ dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
return err;
}
- err = clk_set_rate(hdmi->clk_parent, pclk);
- if (err < 0)
- dev_err(output->dev, "failed to set clock rate to %lu Hz\n",
- pclk);
-
- *div = 0;
-
- return 0;
-}
-
-static int tegra_output_hdmi_check_mode(struct tegra_output *output,
- struct drm_display_mode *mode,
- enum drm_mode_status *status)
-{
- struct tegra_hdmi *hdmi = to_hdmi(output);
- unsigned long pclk = mode->clock * 1000;
- struct clk *parent;
- long err;
-
- parent = clk_get_parent(hdmi->clk_parent);
-
- err = clk_round_rate(parent, pclk * 4);
- if (err <= 0)
- *status = MODE_NOCLOCK;
- else
- *status = MODE_OK;
-
- return 0;
+ return err;
}
-static const struct tegra_output_ops hdmi_ops = {
- .enable = tegra_output_hdmi_enable,
- .disable = tegra_output_hdmi_disable,
- .setup_clock = tegra_output_hdmi_setup_clock,
- .check_mode = tegra_output_hdmi_check_mode,
+static const struct drm_encoder_helper_funcs tegra_hdmi_encoder_helper_funcs = {
+ .dpms = tegra_hdmi_encoder_dpms,
+ .prepare = tegra_hdmi_encoder_prepare,
+ .commit = tegra_hdmi_encoder_commit,
+ .mode_set = tegra_hdmi_encoder_mode_set,
+ .disable = tegra_hdmi_encoder_disable,
+ .atomic_check = tegra_hdmi_encoder_atomic_check,
};
static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
@@ -1117,8 +1094,8 @@ static int tegra_hdmi_show_regs(struct seq_file *s, void *data)
return err;
#define DUMP_REG(name) \
- seq_printf(s, "%-56s %#05x %08lx\n", #name, name, \
- tegra_hdmi_readl(hdmi, name))
+ seq_printf(s, "%-56s %#05x %08x\n", #name, name, \
+ tegra_hdmi_readl(hdmi, name))
DUMP_REG(HDMI_CTXSW);
DUMP_REG(HDMI_NV_PDISP_SOR_STATE0);
@@ -1330,7 +1307,7 @@ remove:
return err;
}
-static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
+static void tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
{
drm_debugfs_remove_files(hdmi->debugfs_files, ARRAY_SIZE(debugfs_files),
hdmi->minor);
@@ -1341,8 +1318,6 @@ static int tegra_hdmi_debugfs_exit(struct tegra_hdmi *hdmi)
debugfs_remove(hdmi->debugfs);
hdmi->debugfs = NULL;
-
- return 0;
}
static int tegra_hdmi_init(struct host1x_client *client)
@@ -1351,16 +1326,32 @@ static int tegra_hdmi_init(struct host1x_client *client)
struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
int err;
- hdmi->output.type = TEGRA_OUTPUT_HDMI;
hdmi->output.dev = client->dev;
- hdmi->output.ops = &hdmi_ops;
+
+ drm_connector_init(drm, &hdmi->output.connector,
+ &tegra_hdmi_connector_funcs,
+ DRM_MODE_CONNECTOR_HDMIA);
+ drm_connector_helper_add(&hdmi->output.connector,
+ &tegra_hdmi_connector_helper_funcs);
+ hdmi->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+ drm_encoder_init(drm, &hdmi->output.encoder, &tegra_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(&hdmi->output.encoder,
+ &tegra_hdmi_encoder_helper_funcs);
+
+ drm_mode_connector_attach_encoder(&hdmi->output.connector,
+ &hdmi->output.encoder);
+ drm_connector_register(&hdmi->output.connector);
err = tegra_output_init(drm, &hdmi->output);
if (err < 0) {
- dev_err(client->dev, "output setup failed: %d\n", err);
+ dev_err(client->dev, "failed to initialize output: %d\n", err);
return err;
}
+ hdmi->output.encoder.possible_crtcs = 0x3;
+
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_hdmi_debugfs_init(hdmi, drm->primary);
if (err < 0)
@@ -1374,34 +1365,44 @@ static int tegra_hdmi_init(struct host1x_client *client)
return err;
}
+ err = regulator_enable(hdmi->pll);
+ if (err < 0) {
+ dev_err(hdmi->dev, "failed to enable PLL regulator: %d\n", err);
+ return err;
+ }
+
+ err = regulator_enable(hdmi->vdd);
+ if (err < 0) {
+ dev_err(hdmi->dev, "failed to enable VDD regulator: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(hdmi->clk);
+ if (err < 0) {
+ dev_err(hdmi->dev, "failed to enable clock: %d\n", err);
+ return err;
+ }
+
+ reset_control_deassert(hdmi->rst);
+
return 0;
}
static int tegra_hdmi_exit(struct host1x_client *client)
{
struct tegra_hdmi *hdmi = host1x_client_to_hdmi(client);
- int err;
- regulator_disable(hdmi->hdmi);
+ tegra_output_exit(&hdmi->output);
- if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_hdmi_debugfs_exit(hdmi);
- if (err < 0)
- dev_err(client->dev, "debugfs cleanup failed: %d\n",
- err);
- }
+ clk_disable_unprepare(hdmi->clk);
+ reset_control_assert(hdmi->rst);
- err = tegra_output_disable(&hdmi->output);
- if (err < 0) {
- dev_err(client->dev, "output failed to disable: %d\n", err);
- return err;
- }
+ regulator_disable(hdmi->vdd);
+ regulator_disable(hdmi->pll);
+ regulator_disable(hdmi->hdmi);
- err = tegra_output_exit(&hdmi->output);
- if (err < 0) {
- dev_err(client->dev, "output cleanup failed: %d\n", err);
- return err;
- }
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ tegra_hdmi_debugfs_exit(hdmi);
return 0;
}
@@ -1559,11 +1560,7 @@ static int tegra_hdmi_remove(struct platform_device *pdev)
return err;
}
- err = tegra_output_remove(&hdmi->output);
- if (err < 0) {
- dev_err(&pdev->dev, "failed to remove output: %d\n", err);
- return err;
- }
+ tegra_output_remove(&hdmi->output);
clk_disable_unprepare(hdmi->clk_parent);
clk_disable_unprepare(hdmi->clk);
diff --git a/drivers/gpu/drm/tegra/mipi-phy.c b/drivers/gpu/drm/tegra/mipi-phy.c
index 486d19d589c8..ba2ae6511957 100644
--- a/drivers/gpu/drm/tegra/mipi-phy.c
+++ b/drivers/gpu/drm/tegra/mipi-phy.c
@@ -12,9 +12,9 @@
#include "mipi-phy.h"
/*
- * Default D-PHY timings based on MIPI D-PHY specification. Derived from
- * the valid ranges specified in Section 5.9 of the D-PHY specification
- * with minor adjustments.
+ * Default D-PHY timings based on MIPI D-PHY specification. Derived from the
+ * valid ranges specified in Section 6.9, Table 14, Page 40 of the D-PHY
+ * specification (v1.2) with minor adjustments.
*/
int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
unsigned long period)
@@ -34,7 +34,20 @@ int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
timing->hszero = 145 + 5 * period;
timing->hssettle = 85 + 6 * period;
timing->hsskip = 40;
- timing->hstrail = max(8 * period, 60 + 4 * period);
+
+ /*
+ * The MIPI D-PHY specification (Section 6.9, v1.2, Table 14, Page 40)
+ * contains this formula as:
+ *
+ * T_HS-TRAIL = max(n * 8 * period, 60 + n * 4 * period)
+ *
+ * where n = 1 for forward-direction HS mode and n = 4 for reverse-
+ * direction HS mode. There's only one setting and this function does
+ * not parameterize on anything other that period, so this code will
+ * assumes that reverse-direction HS mode is supported and uses n = 4.
+ */
+ timing->hstrail = max(4 * 8 * period, 60 + 4 * 4 * period);
+
timing->init = 100000;
timing->lpx = 60;
timing->taget = 5 * timing->lpx;
@@ -46,8 +59,8 @@ int mipi_dphy_timing_get_default(struct mipi_dphy_timing *timing,
}
/*
- * Validate D-PHY timing according to MIPI Alliance Specification for D-PHY,
- * Section 5.9 "Global Operation Timing Parameters".
+ * Validate D-PHY timing according to MIPI D-PHY specification (v1.2, Section
+ * Section 6.9 "Global Operation Timing Parameters").
*/
int mipi_dphy_timing_validate(struct mipi_dphy_timing *timing,
unsigned long period)
diff --git a/drivers/gpu/drm/tegra/output.c b/drivers/gpu/drm/tegra/output.c
index 6a5c7b81fbc5..37db47975d48 100644
--- a/drivers/gpu/drm/tegra/output.c
+++ b/drivers/gpu/drm/tegra/output.c
@@ -9,10 +9,11 @@
#include <linux/of_gpio.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_panel.h>
#include "drm.h"
-static int tegra_connector_get_modes(struct drm_connector *connector)
+int tegra_output_connector_get_modes(struct drm_connector *connector)
{
struct tegra_output *output = connector_to_output(connector);
struct edid *edid = NULL;
@@ -43,43 +44,20 @@ static int tegra_connector_get_modes(struct drm_connector *connector)
return err;
}
-static int tegra_connector_mode_valid(struct drm_connector *connector,
- struct drm_display_mode *mode)
-{
- struct tegra_output *output = connector_to_output(connector);
- enum drm_mode_status status = MODE_OK;
- int err;
-
- err = tegra_output_check_mode(output, mode, &status);
- if (err < 0)
- return MODE_ERROR;
-
- return status;
-}
-
-static struct drm_encoder *
-tegra_connector_best_encoder(struct drm_connector *connector)
+struct drm_encoder *
+tegra_output_connector_best_encoder(struct drm_connector *connector)
{
struct tegra_output *output = connector_to_output(connector);
return &output->encoder;
}
-static const struct drm_connector_helper_funcs connector_helper_funcs = {
- .get_modes = tegra_connector_get_modes,
- .mode_valid = tegra_connector_mode_valid,
- .best_encoder = tegra_connector_best_encoder,
-};
-
-static enum drm_connector_status
-tegra_connector_detect(struct drm_connector *connector, bool force)
+enum drm_connector_status
+tegra_output_connector_detect(struct drm_connector *connector, bool force)
{
struct tegra_output *output = connector_to_output(connector);
enum drm_connector_status status = connector_status_unknown;
- if (output->ops->detect)
- return output->ops->detect(output);
-
if (gpio_is_valid(output->hpd_gpio)) {
if (gpio_get_value(output->hpd_gpio) == 0)
status = connector_status_disconnected;
@@ -90,95 +68,22 @@ tegra_connector_detect(struct drm_connector *connector, bool force)
status = connector_status_disconnected;
else
status = connector_status_connected;
-
- if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
- status = connector_status_connected;
}
return status;
}
-static void drm_connector_clear(struct drm_connector *connector)
-{
- memset(connector, 0, sizeof(*connector));
-}
-
-static void tegra_connector_destroy(struct drm_connector *connector)
+void tegra_output_connector_destroy(struct drm_connector *connector)
{
drm_connector_unregister(connector);
drm_connector_cleanup(connector);
- drm_connector_clear(connector);
}
-static const struct drm_connector_funcs connector_funcs = {
- .dpms = drm_helper_connector_dpms,
- .detect = tegra_connector_detect,
- .fill_modes = drm_helper_probe_single_connector_modes,
- .destroy = tegra_connector_destroy,
-};
-
-static void drm_encoder_clear(struct drm_encoder *encoder)
-{
- memset(encoder, 0, sizeof(*encoder));
-}
-
-static void tegra_encoder_destroy(struct drm_encoder *encoder)
+void tegra_output_encoder_destroy(struct drm_encoder *encoder)
{
drm_encoder_cleanup(encoder);
- drm_encoder_clear(encoder);
}
-static const struct drm_encoder_funcs encoder_funcs = {
- .destroy = tegra_encoder_destroy,
-};
-
-static void tegra_encoder_dpms(struct drm_encoder *encoder, int mode)
-{
- struct tegra_output *output = encoder_to_output(encoder);
- struct drm_panel *panel = output->panel;
-
- if (mode != DRM_MODE_DPMS_ON) {
- drm_panel_disable(panel);
- tegra_output_disable(output);
- drm_panel_unprepare(panel);
- } else {
- drm_panel_prepare(panel);
- tegra_output_enable(output);
- drm_panel_enable(panel);
- }
-}
-
-static bool tegra_encoder_mode_fixup(struct drm_encoder *encoder,
- const struct drm_display_mode *mode,
- struct drm_display_mode *adjusted)
-{
- return true;
-}
-
-static void tegra_encoder_prepare(struct drm_encoder *encoder)
-{
- tegra_encoder_dpms(encoder, DRM_MODE_DPMS_OFF);
-}
-
-static void tegra_encoder_commit(struct drm_encoder *encoder)
-{
- tegra_encoder_dpms(encoder, DRM_MODE_DPMS_ON);
-}
-
-static void tegra_encoder_mode_set(struct drm_encoder *encoder,
- struct drm_display_mode *mode,
- struct drm_display_mode *adjusted)
-{
-}
-
-static const struct drm_encoder_helper_funcs encoder_helper_funcs = {
- .dpms = tegra_encoder_dpms,
- .mode_fixup = tegra_encoder_mode_fixup,
- .prepare = tegra_encoder_prepare,
- .commit = tegra_encoder_commit,
- .mode_set = tegra_encoder_mode_set,
-};
-
static irqreturn_t hpd_irq(int irq, void *data)
{
struct tegra_output *output = data;
@@ -268,7 +173,7 @@ int tegra_output_probe(struct tegra_output *output)
return 0;
}
-int tegra_output_remove(struct tegra_output *output)
+void tegra_output_remove(struct tegra_output *output)
{
if (gpio_is_valid(output->hpd_gpio)) {
free_irq(output->hpd_irq, output);
@@ -277,56 +182,17 @@ int tegra_output_remove(struct tegra_output *output)
if (output->ddc)
put_device(&output->ddc->dev);
-
- return 0;
}
int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
{
- int connector, encoder;
-
- switch (output->type) {
- case TEGRA_OUTPUT_RGB:
- connector = DRM_MODE_CONNECTOR_LVDS;
- encoder = DRM_MODE_ENCODER_LVDS;
- break;
-
- case TEGRA_OUTPUT_HDMI:
- connector = DRM_MODE_CONNECTOR_HDMIA;
- encoder = DRM_MODE_ENCODER_TMDS;
- break;
-
- case TEGRA_OUTPUT_DSI:
- connector = DRM_MODE_CONNECTOR_DSI;
- encoder = DRM_MODE_ENCODER_DSI;
- break;
-
- case TEGRA_OUTPUT_EDP:
- connector = DRM_MODE_CONNECTOR_eDP;
- encoder = DRM_MODE_ENCODER_TMDS;
- break;
-
- default:
- connector = DRM_MODE_CONNECTOR_Unknown;
- encoder = DRM_MODE_ENCODER_NONE;
- break;
- }
-
- drm_connector_init(drm, &output->connector, &connector_funcs,
- connector);
- drm_connector_helper_add(&output->connector, &connector_helper_funcs);
- output->connector.dpms = DRM_MODE_DPMS_OFF;
-
- if (output->panel)
- drm_panel_attach(output->panel, &output->connector);
-
- drm_encoder_init(drm, &output->encoder, &encoder_funcs, encoder);
- drm_encoder_helper_add(&output->encoder, &encoder_helper_funcs);
-
- drm_mode_connector_attach_encoder(&output->connector, &output->encoder);
- drm_connector_register(&output->connector);
+ int err;
- output->encoder.possible_crtcs = 0x3;
+ if (output->panel) {
+ err = drm_panel_attach(output->panel, &output->connector);
+ if (err < 0)
+ return err;
+ }
/*
* The connector is now registered and ready to receive hotplug events
@@ -338,7 +204,7 @@ int tegra_output_init(struct drm_device *drm, struct tegra_output *output)
return 0;
}
-int tegra_output_exit(struct tegra_output *output)
+void tegra_output_exit(struct tegra_output *output)
{
/*
* The connector is going away, so the interrupt must be disabled to
@@ -349,6 +215,4 @@ int tegra_output_exit(struct tegra_output *output)
if (output->panel)
drm_panel_detach(output->panel);
-
- return 0;
}
diff --git a/drivers/gpu/drm/tegra/rgb.c b/drivers/gpu/drm/tegra/rgb.c
index d6af9be48f42..7cd833f5b5b5 100644
--- a/drivers/gpu/drm/tegra/rgb.c
+++ b/drivers/gpu/drm/tegra/rgb.c
@@ -9,6 +9,9 @@
#include <linux/clk.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_panel.h>
+
#include "drm.h"
#include "dc.h"
@@ -85,13 +88,65 @@ static void tegra_dc_write_regs(struct tegra_dc *dc,
tegra_dc_writel(dc, table[i].value, table[i].offset);
}
-static int tegra_output_rgb_enable(struct tegra_output *output)
+static void tegra_rgb_connector_dpms(struct drm_connector *connector,
+ int mode)
+{
+}
+
+static const struct drm_connector_funcs tegra_rgb_connector_funcs = {
+ .dpms = tegra_rgb_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = tegra_output_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = tegra_output_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static enum drm_mode_status
+tegra_rgb_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ /*
+ * FIXME: For now, always assume that the mode is okay. There are
+ * unresolved issues with clk_round_rate(), which doesn't always
+ * reliably report whether a frequency can be set or not.
+ */
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs tegra_rgb_connector_helper_funcs = {
+ .get_modes = tegra_output_connector_get_modes,
+ .mode_valid = tegra_rgb_connector_mode_valid,
+ .best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_rgb_encoder_funcs = {
+ .destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_rgb_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_rgb_encoder_prepare(struct drm_encoder *encoder)
{
+}
+
+static void tegra_rgb_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_rgb_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
+{
+ struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output);
- unsigned long value;
+ u32 value;
- if (rgb->enabled)
- return 0;
+ if (output->panel)
+ drm_panel_prepare(output->panel);
tegra_dc_write_regs(rgb->dc, rgb_enable, ARRAY_SIZE(rgb_enable));
@@ -113,64 +168,39 @@ static int tegra_output_rgb_enable(struct tegra_output *output)
value = SC0_H_QUALIFIER_NONE | SC1_H_QUALIFIER_NONE;
tegra_dc_writel(rgb->dc, value, DC_DISP_SHIFT_CLOCK_OPTIONS);
- value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- value |= DISP_CTRL_MODE_C_DISPLAY;
- tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
+ tegra_dc_commit(rgb->dc);
- value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
- tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
- tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
- rgb->enabled = true;
-
- return 0;
+ if (output->panel)
+ drm_panel_enable(output->panel);
}
-static int tegra_output_rgb_disable(struct tegra_output *output)
+static void tegra_rgb_encoder_disable(struct drm_encoder *encoder)
{
+ struct tegra_output *output = encoder_to_output(encoder);
struct tegra_rgb *rgb = to_rgb(output);
- unsigned long value;
-
- if (!rgb->enabled)
- return 0;
-
- value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
- tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
- value = tegra_dc_readl(rgb->dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- tegra_dc_writel(rgb->dc, value, DC_CMD_DISPLAY_COMMAND);
- tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(rgb->dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ if (output->panel)
+ drm_panel_disable(output->panel);
tegra_dc_write_regs(rgb->dc, rgb_disable, ARRAY_SIZE(rgb_disable));
+ tegra_dc_commit(rgb->dc);
- rgb->enabled = false;
-
- return 0;
+ if (output->panel)
+ drm_panel_unprepare(output->panel);
}
-static int tegra_output_rgb_setup_clock(struct tegra_output *output,
- struct clk *clk, unsigned long pclk,
- unsigned int *div)
+static int
+tegra_rgb_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+ unsigned long pclk = crtc_state->mode.clock * 1000;
struct tegra_rgb *rgb = to_rgb(output);
+ unsigned int div;
int err;
- err = clk_set_parent(clk, rgb->clk_parent);
- if (err < 0) {
- dev_err(output->dev, "failed to set parent: %d\n", err);
- return err;
- }
-
/*
* We may not want to change the frequency of the parent clock, since
* it may be a parent for other peripherals. This is due to the fact
@@ -187,32 +217,26 @@ static int tegra_output_rgb_setup_clock(struct tegra_output *output,
* and hope that the desired frequency can be matched (or at least
* matched sufficiently close that the panel will still work).
*/
+ div = ((clk_get_rate(rgb->clk) * 2) / pclk) - 2;
+ pclk = 0;
- *div = ((clk_get_rate(clk) * 2) / pclk) - 2;
-
- return 0;
-}
-
-static int tegra_output_rgb_check_mode(struct tegra_output *output,
- struct drm_display_mode *mode,
- enum drm_mode_status *status)
-{
- /*
- * FIXME: For now, always assume that the mode is okay. There are
- * unresolved issues with clk_round_rate(), which doesn't always
- * reliably report whether a frequency can be set or not.
- */
-
- *status = MODE_OK;
+ err = tegra_dc_state_setup_clock(dc, crtc_state, rgb->clk_parent,
+ pclk, div);
+ if (err < 0) {
+ dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
+ return err;
+ }
- return 0;
+ return err;
}
-static const struct tegra_output_ops rgb_ops = {
- .enable = tegra_output_rgb_enable,
- .disable = tegra_output_rgb_disable,
- .setup_clock = tegra_output_rgb_setup_clock,
- .check_mode = tegra_output_rgb_check_mode,
+static const struct drm_encoder_helper_funcs tegra_rgb_encoder_helper_funcs = {
+ .dpms = tegra_rgb_encoder_dpms,
+ .prepare = tegra_rgb_encoder_prepare,
+ .commit = tegra_rgb_encoder_commit,
+ .mode_set = tegra_rgb_encoder_mode_set,
+ .disable = tegra_rgb_encoder_disable,
+ .atomic_check = tegra_rgb_encoder_atomic_check,
};
int tegra_dc_rgb_probe(struct tegra_dc *dc)
@@ -262,64 +286,58 @@ int tegra_dc_rgb_probe(struct tegra_dc *dc)
int tegra_dc_rgb_remove(struct tegra_dc *dc)
{
- int err;
-
if (!dc->rgb)
return 0;
- err = tegra_output_remove(dc->rgb);
- if (err < 0)
- return err;
+ tegra_output_remove(dc->rgb);
+ dc->rgb = NULL;
return 0;
}
int tegra_dc_rgb_init(struct drm_device *drm, struct tegra_dc *dc)
{
- struct tegra_rgb *rgb = to_rgb(dc->rgb);
+ struct tegra_output *output = dc->rgb;
int err;
if (!dc->rgb)
return -ENODEV;
- rgb->output.type = TEGRA_OUTPUT_RGB;
- rgb->output.ops = &rgb_ops;
+ drm_connector_init(drm, &output->connector, &tegra_rgb_connector_funcs,
+ DRM_MODE_CONNECTOR_LVDS);
+ drm_connector_helper_add(&output->connector,
+ &tegra_rgb_connector_helper_funcs);
+ output->connector.dpms = DRM_MODE_DPMS_OFF;
+
+ drm_encoder_init(drm, &output->encoder, &tegra_rgb_encoder_funcs,
+ DRM_MODE_ENCODER_LVDS);
+ drm_encoder_helper_add(&output->encoder,
+ &tegra_rgb_encoder_helper_funcs);
- err = tegra_output_init(dc->base.dev, &rgb->output);
+ drm_mode_connector_attach_encoder(&output->connector,
+ &output->encoder);
+ drm_connector_register(&output->connector);
+
+ err = tegra_output_init(drm, output);
if (err < 0) {
- dev_err(dc->dev, "output setup failed: %d\n", err);
+ dev_err(output->dev, "failed to initialize output: %d\n", err);
return err;
}
/*
- * By default, outputs can be associated with each display controller.
- * RGB outputs are an exception, so we make sure they can be attached
- * to only their parent display controller.
+ * Other outputs can be attached to either display controller. The RGB
+ * outputs are an exception and work only with their parent display
+ * controller.
*/
- rgb->output.encoder.possible_crtcs = drm_crtc_mask(&dc->base);
+ output->encoder.possible_crtcs = drm_crtc_mask(&dc->base);
return 0;
}
int tegra_dc_rgb_exit(struct tegra_dc *dc)
{
- if (dc->rgb) {
- int err;
-
- err = tegra_output_disable(dc->rgb);
- if (err < 0) {
- dev_err(dc->dev, "output failed to disable: %d\n", err);
- return err;
- }
-
- err = tegra_output_exit(dc->rgb);
- if (err < 0) {
- dev_err(dc->dev, "output cleanup failed: %d\n", err);
- return err;
- }
-
- dc->rgb = NULL;
- }
+ if (dc->rgb)
+ tegra_output_exit(dc->rgb);
return 0;
}
diff --git a/drivers/gpu/drm/tegra/sor.c b/drivers/gpu/drm/tegra/sor.c
index 7829e81f065d..2afe478ded3b 100644
--- a/drivers/gpu/drm/tegra/sor.c
+++ b/drivers/gpu/drm/tegra/sor.c
@@ -8,13 +8,16 @@
#include <linux/clk.h>
#include <linux/debugfs.h>
+#include <linux/gpio.h>
#include <linux/io.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
#include <soc/tegra/pmc.h>
+#include <drm/drm_atomic_helper.h>
#include <drm/drm_dp_helper.h>
+#include <drm/drm_panel.h>
#include "dc.h"
#include "drm.h"
@@ -258,18 +261,8 @@ static int tegra_sor_attach(struct tegra_sor *sor)
static int tegra_sor_wakeup(struct tegra_sor *sor)
{
- struct tegra_dc *dc = to_tegra_dc(sor->output.encoder.crtc);
unsigned long value, timeout;
- /* enable display controller outputs */
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value |= PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
-
- tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
-
timeout = jiffies + msecs_to_jiffies(250);
/* wait for head to wake up */
@@ -482,10 +475,317 @@ static int tegra_sor_calc_config(struct tegra_sor *sor,
return 0;
}
-static int tegra_output_sor_enable(struct tegra_output *output)
+static int tegra_sor_detach(struct tegra_sor *sor)
+{
+ unsigned long value, timeout;
+
+ /* switch to safe mode */
+ value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+ value &= ~SOR_SUPER_STATE_MODE_NORMAL;
+ tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+ tegra_sor_super_update(sor);
+
+ timeout = jiffies + msecs_to_jiffies(250);
+
+ while (time_before(jiffies, timeout)) {
+ value = tegra_sor_readl(sor, SOR_PWR);
+ if (value & SOR_PWR_MODE_SAFE)
+ break;
+ }
+
+ if ((value & SOR_PWR_MODE_SAFE) == 0)
+ return -ETIMEDOUT;
+
+ /* go to sleep */
+ value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+ value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
+ tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+ tegra_sor_super_update(sor);
+
+ /* detach */
+ value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
+ value &= ~SOR_SUPER_STATE_ATTACHED;
+ tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
+ tegra_sor_super_update(sor);
+
+ timeout = jiffies + msecs_to_jiffies(250);
+
+ while (time_before(jiffies, timeout)) {
+ value = tegra_sor_readl(sor, SOR_TEST);
+ if ((value & SOR_TEST_ATTACHED) == 0)
+ break;
+
+ usleep_range(25, 100);
+ }
+
+ if ((value & SOR_TEST_ATTACHED) != 0)
+ return -ETIMEDOUT;
+
+ return 0;
+}
+
+static int tegra_sor_power_down(struct tegra_sor *sor)
+{
+ unsigned long value, timeout;
+ int err;
+
+ value = tegra_sor_readl(sor, SOR_PWR);
+ value &= ~SOR_PWR_NORMAL_STATE_PU;
+ value |= SOR_PWR_TRIGGER;
+ tegra_sor_writel(sor, value, SOR_PWR);
+
+ timeout = jiffies + msecs_to_jiffies(250);
+
+ while (time_before(jiffies, timeout)) {
+ value = tegra_sor_readl(sor, SOR_PWR);
+ if ((value & SOR_PWR_TRIGGER) == 0)
+ return 0;
+
+ usleep_range(25, 100);
+ }
+
+ if ((value & SOR_PWR_TRIGGER) != 0)
+ return -ETIMEDOUT;
+
+ err = clk_set_parent(sor->clk, sor->clk_safe);
+ if (err < 0)
+ dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
+
+ value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
+ value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
+ SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
+ tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
+
+ /* stop lane sequencer */
+ value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP |
+ SOR_LANE_SEQ_CTL_POWER_STATE_DOWN;
+ tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
+
+ timeout = jiffies + msecs_to_jiffies(250);
+
+ while (time_before(jiffies, timeout)) {
+ value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
+ if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
+ break;
+
+ usleep_range(25, 100);
+ }
+
+ if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
+ return -ETIMEDOUT;
+
+ value = tegra_sor_readl(sor, SOR_PLL_2);
+ value |= SOR_PLL_2_PORT_POWERDOWN;
+ tegra_sor_writel(sor, value, SOR_PLL_2);
+
+ usleep_range(20, 100);
+
+ value = tegra_sor_readl(sor, SOR_PLL_0);
+ value |= SOR_PLL_0_POWER_OFF;
+ value |= SOR_PLL_0_VCOPD;
+ tegra_sor_writel(sor, value, SOR_PLL_0);
+
+ value = tegra_sor_readl(sor, SOR_PLL_2);
+ value |= SOR_PLL_2_SEQ_PLLCAPPD;
+ value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
+ tegra_sor_writel(sor, value, SOR_PLL_2);
+
+ usleep_range(20, 100);
+
+ return 0;
+}
+
+static int tegra_sor_crc_open(struct inode *inode, struct file *file)
+{
+ file->private_data = inode->i_private;
+
+ return 0;
+}
+
+static int tegra_sor_crc_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
+{
+ u32 value;
+
+ timeout = jiffies + msecs_to_jiffies(timeout);
+
+ while (time_before(jiffies, timeout)) {
+ value = tegra_sor_readl(sor, SOR_CRC_A);
+ if (value & SOR_CRC_A_VALID)
+ return 0;
+
+ usleep_range(100, 200);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
+ size_t size, loff_t *ppos)
+{
+ struct tegra_sor *sor = file->private_data;
+ ssize_t num, err;
+ char buf[10];
+ u32 value;
+
+ mutex_lock(&sor->lock);
+
+ if (!sor->enabled) {
+ err = -EAGAIN;
+ goto unlock;
+ }
+
+ value = tegra_sor_readl(sor, SOR_STATE_1);
+ value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
+ tegra_sor_writel(sor, value, SOR_STATE_1);
+
+ value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
+ value |= SOR_CRC_CNTRL_ENABLE;
+ tegra_sor_writel(sor, value, SOR_CRC_CNTRL);
+
+ value = tegra_sor_readl(sor, SOR_TEST);
+ value &= ~SOR_TEST_CRC_POST_SERIALIZE;
+ tegra_sor_writel(sor, value, SOR_TEST);
+
+ err = tegra_sor_crc_wait(sor, 100);
+ if (err < 0)
+ goto unlock;
+
+ tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
+ value = tegra_sor_readl(sor, SOR_CRC_B);
+
+ num = scnprintf(buf, sizeof(buf), "%08x\n", value);
+
+ err = simple_read_from_buffer(buffer, size, ppos, buf, num);
+
+unlock:
+ mutex_unlock(&sor->lock);
+ return err;
+}
+
+static const struct file_operations tegra_sor_crc_fops = {
+ .owner = THIS_MODULE,
+ .open = tegra_sor_crc_open,
+ .read = tegra_sor_crc_read,
+ .release = tegra_sor_crc_release,
+};
+
+static int tegra_sor_debugfs_init(struct tegra_sor *sor,
+ struct drm_minor *minor)
+{
+ struct dentry *entry;
+ int err = 0;
+
+ sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
+ if (!sor->debugfs)
+ return -ENOMEM;
+
+ entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
+ &tegra_sor_crc_fops);
+ if (!entry) {
+ dev_err(sor->dev,
+ "cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
+ minor->debugfs_root->d_name.name);
+ err = -ENOMEM;
+ goto remove;
+ }
+
+ return err;
+
+remove:
+ debugfs_remove(sor->debugfs);
+ sor->debugfs = NULL;
+ return err;
+}
+
+static void tegra_sor_debugfs_exit(struct tegra_sor *sor)
+{
+ debugfs_remove_recursive(sor->debugfs);
+ sor->debugfs = NULL;
+}
+
+static void tegra_sor_connector_dpms(struct drm_connector *connector, int mode)
+{
+}
+
+static enum drm_connector_status
+tegra_sor_connector_detect(struct drm_connector *connector, bool force)
+{
+ struct tegra_output *output = connector_to_output(connector);
+ struct tegra_sor *sor = to_sor(output);
+
+ if (sor->dpaux)
+ return tegra_dpaux_detect(sor->dpaux);
+
+ return connector_status_unknown;
+}
+
+static const struct drm_connector_funcs tegra_sor_connector_funcs = {
+ .dpms = tegra_sor_connector_dpms,
+ .reset = drm_atomic_helper_connector_reset,
+ .detect = tegra_sor_connector_detect,
+ .fill_modes = drm_helper_probe_single_connector_modes,
+ .destroy = tegra_output_connector_destroy,
+ .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+ .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int tegra_sor_connector_get_modes(struct drm_connector *connector)
{
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
- struct drm_display_mode *mode = &dc->base.mode;
+ struct tegra_output *output = connector_to_output(connector);
+ struct tegra_sor *sor = to_sor(output);
+ int err;
+
+ if (sor->dpaux)
+ tegra_dpaux_enable(sor->dpaux);
+
+ err = tegra_output_connector_get_modes(connector);
+
+ if (sor->dpaux)
+ tegra_dpaux_disable(sor->dpaux);
+
+ return err;
+}
+
+static enum drm_mode_status
+tegra_sor_connector_mode_valid(struct drm_connector *connector,
+ struct drm_display_mode *mode)
+{
+ return MODE_OK;
+}
+
+static const struct drm_connector_helper_funcs tegra_sor_connector_helper_funcs = {
+ .get_modes = tegra_sor_connector_get_modes,
+ .mode_valid = tegra_sor_connector_mode_valid,
+ .best_encoder = tegra_output_connector_best_encoder,
+};
+
+static const struct drm_encoder_funcs tegra_sor_encoder_funcs = {
+ .destroy = tegra_output_encoder_destroy,
+};
+
+static void tegra_sor_encoder_dpms(struct drm_encoder *encoder, int mode)
+{
+}
+
+static void tegra_sor_encoder_prepare(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_sor_encoder_commit(struct drm_encoder *encoder)
+{
+}
+
+static void tegra_sor_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adjusted)
+{
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
unsigned int vbe, vse, hbe, hse, vbs, hbs, i;
struct tegra_sor *sor = to_sor(output);
struct tegra_sor_config config;
@@ -505,6 +805,9 @@ static int tegra_output_sor_enable(struct tegra_output *output)
reset_control_deassert(sor->rst);
+ if (output->panel)
+ drm_panel_prepare(output->panel);
+
/* FIXME: properly convert to struct drm_dp_aux */
aux = (struct drm_dp_aux *)sor->dpaux;
@@ -800,18 +1103,6 @@ static int tegra_output_sor_enable(struct tegra_output *output)
goto unlock;
}
- /* start display controller in continuous mode */
- value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
- value |= WRITE_MUX;
- tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
-
- tegra_dc_writel(dc, VSYNC_H_POSITION(1), DC_DISP_DISP_TIMING_OPTIONS);
- tegra_dc_writel(dc, DISP_CTRL_MODE_C_DISPLAY, DC_CMD_DISPLAY_COMMAND);
-
- value = tegra_dc_readl(dc, DC_CMD_STATE_ACCESS);
- value &= ~WRITE_MUX;
- tegra_dc_writel(dc, value, DC_CMD_STATE_ACCESS);
-
/*
* configure panel (24bpp, vsync-, hsync-, DP-A protocol, complete
* raster, associate with display controller)
@@ -886,11 +1177,13 @@ static int tegra_output_sor_enable(struct tegra_output *output)
goto unlock;
}
+ tegra_sor_update(sor);
+
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
value |= SOR_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
- tegra_sor_update(sor);
+ tegra_dc_commit(dc);
err = tegra_sor_attach(sor);
if (err < 0) {
@@ -904,145 +1197,31 @@ static int tegra_output_sor_enable(struct tegra_output *output)
goto unlock;
}
+ if (output->panel)
+ drm_panel_enable(output->panel);
+
sor->enabled = true;
unlock:
mutex_unlock(&sor->lock);
- return err;
}
-static int tegra_sor_detach(struct tegra_sor *sor)
+static void tegra_sor_encoder_disable(struct drm_encoder *encoder)
{
- unsigned long value, timeout;
-
- /* switch to safe mode */
- value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
- value &= ~SOR_SUPER_STATE_MODE_NORMAL;
- tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
- tegra_sor_super_update(sor);
-
- timeout = jiffies + msecs_to_jiffies(250);
-
- while (time_before(jiffies, timeout)) {
- value = tegra_sor_readl(sor, SOR_PWR);
- if (value & SOR_PWR_MODE_SAFE)
- break;
- }
-
- if ((value & SOR_PWR_MODE_SAFE) == 0)
- return -ETIMEDOUT;
-
- /* go to sleep */
- value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
- value &= ~SOR_SUPER_STATE_HEAD_MODE_MASK;
- tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
- tegra_sor_super_update(sor);
-
- /* detach */
- value = tegra_sor_readl(sor, SOR_SUPER_STATE_1);
- value &= ~SOR_SUPER_STATE_ATTACHED;
- tegra_sor_writel(sor, value, SOR_SUPER_STATE_1);
- tegra_sor_super_update(sor);
-
- timeout = jiffies + msecs_to_jiffies(250);
-
- while (time_before(jiffies, timeout)) {
- value = tegra_sor_readl(sor, SOR_TEST);
- if ((value & SOR_TEST_ATTACHED) == 0)
- break;
-
- usleep_range(25, 100);
- }
-
- if ((value & SOR_TEST_ATTACHED) != 0)
- return -ETIMEDOUT;
-
- return 0;
-}
-
-static int tegra_sor_power_down(struct tegra_sor *sor)
-{
- unsigned long value, timeout;
- int err;
-
- value = tegra_sor_readl(sor, SOR_PWR);
- value &= ~SOR_PWR_NORMAL_STATE_PU;
- value |= SOR_PWR_TRIGGER;
- tegra_sor_writel(sor, value, SOR_PWR);
-
- timeout = jiffies + msecs_to_jiffies(250);
-
- while (time_before(jiffies, timeout)) {
- value = tegra_sor_readl(sor, SOR_PWR);
- if ((value & SOR_PWR_TRIGGER) == 0)
- return 0;
-
- usleep_range(25, 100);
- }
-
- if ((value & SOR_PWR_TRIGGER) != 0)
- return -ETIMEDOUT;
-
- err = clk_set_parent(sor->clk, sor->clk_safe);
- if (err < 0)
- dev_err(sor->dev, "failed to set safe parent clock: %d\n", err);
-
- value = tegra_sor_readl(sor, SOR_DP_PADCTL_0);
- value &= ~(SOR_DP_PADCTL_PD_TXD_3 | SOR_DP_PADCTL_PD_TXD_0 |
- SOR_DP_PADCTL_PD_TXD_1 | SOR_DP_PADCTL_PD_TXD_2);
- tegra_sor_writel(sor, value, SOR_DP_PADCTL_0);
-
- /* stop lane sequencer */
- value = SOR_LANE_SEQ_CTL_TRIGGER | SOR_LANE_SEQ_CTL_SEQUENCE_UP |
- SOR_LANE_SEQ_CTL_POWER_STATE_DOWN;
- tegra_sor_writel(sor, value, SOR_LANE_SEQ_CTL);
-
- timeout = jiffies + msecs_to_jiffies(250);
-
- while (time_before(jiffies, timeout)) {
- value = tegra_sor_readl(sor, SOR_LANE_SEQ_CTL);
- if ((value & SOR_LANE_SEQ_CTL_TRIGGER) == 0)
- break;
-
- usleep_range(25, 100);
- }
-
- if ((value & SOR_LANE_SEQ_CTL_TRIGGER) != 0)
- return -ETIMEDOUT;
-
- value = tegra_sor_readl(sor, SOR_PLL_2);
- value |= SOR_PLL_2_PORT_POWERDOWN;
- tegra_sor_writel(sor, value, SOR_PLL_2);
-
- usleep_range(20, 100);
-
- value = tegra_sor_readl(sor, SOR_PLL_0);
- value |= SOR_PLL_0_POWER_OFF;
- value |= SOR_PLL_0_VCOPD;
- tegra_sor_writel(sor, value, SOR_PLL_0);
-
- value = tegra_sor_readl(sor, SOR_PLL_2);
- value |= SOR_PLL_2_SEQ_PLLCAPPD;
- value |= SOR_PLL_2_SEQ_PLLCAPPD_ENFORCE;
- tegra_sor_writel(sor, value, SOR_PLL_2);
-
- usleep_range(20, 100);
-
- return 0;
-}
-
-static int tegra_output_sor_disable(struct tegra_output *output)
-{
- struct tegra_dc *dc = to_tegra_dc(output->encoder.crtc);
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(encoder->crtc);
struct tegra_sor *sor = to_sor(output);
- unsigned long value;
- int err = 0;
+ u32 value;
+ int err;
mutex_lock(&sor->lock);
if (!sor->enabled)
goto unlock;
+ if (output->panel)
+ drm_panel_disable(output->panel);
+
err = tegra_sor_detach(sor);
if (err < 0) {
dev_err(sor->dev, "failed to detach SOR: %d\n", err);
@@ -1057,31 +1236,11 @@ static int tegra_output_sor_disable(struct tegra_output *output)
* sure it's only executed when the output is attached to one.
*/
if (dc) {
- /*
- * XXX: We can't do this here because it causes the SOR to go
- * into an erroneous state and the output will look scrambled
- * the next time it is enabled. Presumably this is because we
- * should be doing this only on the next VBLANK. A possible
- * solution would be to queue a "power-off" event to trigger
- * this code to be run during the next VBLANK.
- */
- /*
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_POWER_CONTROL);
- value &= ~(PW0_ENABLE | PW1_ENABLE | PW2_ENABLE | PW3_ENABLE |
- PW4_ENABLE | PM0_ENABLE | PM1_ENABLE);
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_POWER_CONTROL);
- */
-
- value = tegra_dc_readl(dc, DC_CMD_DISPLAY_COMMAND);
- value &= ~DISP_CTRL_MODE_MASK;
- tegra_dc_writel(dc, value, DC_CMD_DISPLAY_COMMAND);
-
value = tegra_dc_readl(dc, DC_DISP_DISP_WIN_OPTIONS);
value &= ~SOR_ENABLE;
tegra_dc_writel(dc, value, DC_DISP_DISP_WIN_OPTIONS);
- tegra_dc_writel(dc, GENERAL_ACT_REQ << 8, DC_CMD_STATE_CONTROL);
- tegra_dc_writel(dc, GENERAL_ACT_REQ, DC_CMD_STATE_CONTROL);
+ tegra_dc_commit(dc);
}
err = tegra_sor_power_down(sor);
@@ -1104,187 +1263,48 @@ static int tegra_output_sor_disable(struct tegra_output *output)
goto unlock;
}
- reset_control_assert(sor->rst);
+ if (output->panel)
+ drm_panel_unprepare(output->panel);
+
clk_disable_unprepare(sor->clk);
+ reset_control_assert(sor->rst);
sor->enabled = false;
unlock:
mutex_unlock(&sor->lock);
- return err;
}
-static int tegra_output_sor_setup_clock(struct tegra_output *output,
- struct clk *clk, unsigned long pclk,
- unsigned int *div)
+static int
+tegra_sor_encoder_atomic_check(struct drm_encoder *encoder,
+ struct drm_crtc_state *crtc_state,
+ struct drm_connector_state *conn_state)
{
+ struct tegra_output *output = encoder_to_output(encoder);
+ struct tegra_dc *dc = to_tegra_dc(conn_state->crtc);
+ unsigned long pclk = crtc_state->mode.clock * 1000;
struct tegra_sor *sor = to_sor(output);
int err;
- err = clk_set_parent(clk, sor->clk_parent);
- if (err < 0) {
- dev_err(sor->dev, "failed to set parent clock: %d\n", err);
- return err;
- }
-
- err = clk_set_rate(sor->clk_parent, pclk);
+ err = tegra_dc_state_setup_clock(dc, crtc_state, sor->clk_parent,
+ pclk, 0);
if (err < 0) {
- dev_err(sor->dev, "failed to set clock rate to %lu Hz\n", pclk);
+ dev_err(output->dev, "failed to setup CRTC state: %d\n", err);
return err;
}
- *div = 0;
-
return 0;
}
-static int tegra_output_sor_check_mode(struct tegra_output *output,
- struct drm_display_mode *mode,
- enum drm_mode_status *status)
-{
- /*
- * FIXME: For now, always assume that the mode is okay.
- */
-
- *status = MODE_OK;
-
- return 0;
-}
-
-static enum drm_connector_status
-tegra_output_sor_detect(struct tegra_output *output)
-{
- struct tegra_sor *sor = to_sor(output);
-
- if (sor->dpaux)
- return tegra_dpaux_detect(sor->dpaux);
-
- return connector_status_unknown;
-}
-
-static const struct tegra_output_ops sor_ops = {
- .enable = tegra_output_sor_enable,
- .disable = tegra_output_sor_disable,
- .setup_clock = tegra_output_sor_setup_clock,
- .check_mode = tegra_output_sor_check_mode,
- .detect = tegra_output_sor_detect,
+static const struct drm_encoder_helper_funcs tegra_sor_encoder_helper_funcs = {
+ .dpms = tegra_sor_encoder_dpms,
+ .prepare = tegra_sor_encoder_prepare,
+ .commit = tegra_sor_encoder_commit,
+ .mode_set = tegra_sor_encoder_mode_set,
+ .disable = tegra_sor_encoder_disable,
+ .atomic_check = tegra_sor_encoder_atomic_check,
};
-static int tegra_sor_crc_open(struct inode *inode, struct file *file)
-{
- file->private_data = inode->i_private;
-
- return 0;
-}
-
-static int tegra_sor_crc_release(struct inode *inode, struct file *file)
-{
- return 0;
-}
-
-static int tegra_sor_crc_wait(struct tegra_sor *sor, unsigned long timeout)
-{
- u32 value;
-
- timeout = jiffies + msecs_to_jiffies(timeout);
-
- while (time_before(jiffies, timeout)) {
- value = tegra_sor_readl(sor, SOR_CRC_A);
- if (value & SOR_CRC_A_VALID)
- return 0;
-
- usleep_range(100, 200);
- }
-
- return -ETIMEDOUT;
-}
-
-static ssize_t tegra_sor_crc_read(struct file *file, char __user *buffer,
- size_t size, loff_t *ppos)
-{
- struct tegra_sor *sor = file->private_data;
- ssize_t num, err;
- char buf[10];
- u32 value;
-
- mutex_lock(&sor->lock);
-
- if (!sor->enabled) {
- err = -EAGAIN;
- goto unlock;
- }
-
- value = tegra_sor_readl(sor, SOR_STATE_1);
- value &= ~SOR_STATE_ASY_CRC_MODE_MASK;
- tegra_sor_writel(sor, value, SOR_STATE_1);
-
- value = tegra_sor_readl(sor, SOR_CRC_CNTRL);
- value |= SOR_CRC_CNTRL_ENABLE;
- tegra_sor_writel(sor, value, SOR_CRC_CNTRL);
-
- value = tegra_sor_readl(sor, SOR_TEST);
- value &= ~SOR_TEST_CRC_POST_SERIALIZE;
- tegra_sor_writel(sor, value, SOR_TEST);
-
- err = tegra_sor_crc_wait(sor, 100);
- if (err < 0)
- goto unlock;
-
- tegra_sor_writel(sor, SOR_CRC_A_RESET, SOR_CRC_A);
- value = tegra_sor_readl(sor, SOR_CRC_B);
-
- num = scnprintf(buf, sizeof(buf), "%08x\n", value);
-
- err = simple_read_from_buffer(buffer, size, ppos, buf, num);
-
-unlock:
- mutex_unlock(&sor->lock);
- return err;
-}
-
-static const struct file_operations tegra_sor_crc_fops = {
- .owner = THIS_MODULE,
- .open = tegra_sor_crc_open,
- .read = tegra_sor_crc_read,
- .release = tegra_sor_crc_release,
-};
-
-static int tegra_sor_debugfs_init(struct tegra_sor *sor,
- struct drm_minor *minor)
-{
- struct dentry *entry;
- int err = 0;
-
- sor->debugfs = debugfs_create_dir("sor", minor->debugfs_root);
- if (!sor->debugfs)
- return -ENOMEM;
-
- entry = debugfs_create_file("crc", 0644, sor->debugfs, sor,
- &tegra_sor_crc_fops);
- if (!entry) {
- dev_err(sor->dev,
- "cannot create /sys/kernel/debug/dri/%s/sor/crc\n",
- minor->debugfs_root->d_name.name);
- err = -ENOMEM;
- goto remove;
- }
-
- return err;
-
-remove:
- debugfs_remove(sor->debugfs);
- sor->debugfs = NULL;
- return err;
-}
-
-static int tegra_sor_debugfs_exit(struct tegra_sor *sor)
-{
- debugfs_remove_recursive(sor->debugfs);
- sor->debugfs = NULL;
-
- return 0;
-}
-
static int tegra_sor_init(struct host1x_client *client)
{
struct drm_device *drm = dev_get_drvdata(client->parent);
@@ -1294,17 +1314,32 @@ static int tegra_sor_init(struct host1x_client *client)
if (!sor->dpaux)
return -ENODEV;
- sor->output.type = TEGRA_OUTPUT_EDP;
-
sor->output.dev = sor->dev;
- sor->output.ops = &sor_ops;
+
+ drm_connector_init(drm, &sor->output.connector,
+ &tegra_sor_connector_funcs,
+ DRM_MODE_CONNECTOR_eDP);
+ drm_connector_helper_add(&sor->output.connector,
+ &tegra_sor_connector_helper_funcs);
+ sor->output.connector.dpms = DRM_MODE_DPMS_OFF;
+
+ drm_encoder_init(drm, &sor->output.encoder, &tegra_sor_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS);
+ drm_encoder_helper_add(&sor->output.encoder,
+ &tegra_sor_encoder_helper_funcs);
+
+ drm_mode_connector_attach_encoder(&sor->output.connector,
+ &sor->output.encoder);
+ drm_connector_register(&sor->output.connector);
err = tegra_output_init(drm, &sor->output);
if (err < 0) {
- dev_err(sor->dev, "output setup failed: %d\n", err);
+ dev_err(client->dev, "failed to initialize output: %d\n", err);
return err;
}
+ sor->output.encoder.possible_crtcs = 0x3;
+
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_sor_debugfs_init(sor, drm->primary);
if (err < 0)
@@ -1319,6 +1354,20 @@ static int tegra_sor_init(struct host1x_client *client)
}
}
+ err = clk_prepare_enable(sor->clk);
+ if (err < 0) {
+ dev_err(sor->dev, "failed to enable clock: %d\n", err);
+ return err;
+ }
+
+ err = clk_prepare_enable(sor->clk_safe);
+ if (err < 0)
+ return err;
+
+ err = clk_prepare_enable(sor->clk_dp);
+ if (err < 0)
+ return err;
+
return 0;
}
@@ -1327,11 +1376,7 @@ static int tegra_sor_exit(struct host1x_client *client)
struct tegra_sor *sor = host1x_client_to_sor(client);
int err;
- err = tegra_output_disable(&sor->output);
- if (err < 0) {
- dev_err(sor->dev, "output failed to disable: %d\n", err);
- return err;
- }
+ tegra_output_exit(&sor->output);
if (sor->dpaux) {
err = tegra_dpaux_detach(sor->dpaux);
@@ -1341,17 +1386,12 @@ static int tegra_sor_exit(struct host1x_client *client)
}
}
- if (IS_ENABLED(CONFIG_DEBUG_FS)) {
- err = tegra_sor_debugfs_exit(sor);
- if (err < 0)
- dev_err(sor->dev, "debugfs cleanup failed: %d\n", err);
- }
+ clk_disable_unprepare(sor->clk_safe);
+ clk_disable_unprepare(sor->clk_dp);
+ clk_disable_unprepare(sor->clk);
- err = tegra_output_exit(&sor->output);
- if (err < 0) {
- dev_err(sor->dev, "output cleanup failed: %d\n", err);
- return err;
- }
+ if (IS_ENABLED(CONFIG_DEBUG_FS))
+ tegra_sor_debugfs_exit(sor);
return 0;
}
@@ -1404,26 +1444,14 @@ static int tegra_sor_probe(struct platform_device *pdev)
if (IS_ERR(sor->clk_parent))
return PTR_ERR(sor->clk_parent);
- err = clk_prepare_enable(sor->clk_parent);
- if (err < 0)
- return err;
-
sor->clk_safe = devm_clk_get(&pdev->dev, "safe");
if (IS_ERR(sor->clk_safe))
return PTR_ERR(sor->clk_safe);
- err = clk_prepare_enable(sor->clk_safe);
- if (err < 0)
- return err;
-
sor->clk_dp = devm_clk_get(&pdev->dev, "dp");
if (IS_ERR(sor->clk_dp))
return PTR_ERR(sor->clk_dp);
- err = clk_prepare_enable(sor->clk_dp);
- if (err < 0)
- return err;
-
INIT_LIST_HEAD(&sor->client.list);
sor->client.ops = &sor_client_ops;
sor->client.dev = &pdev->dev;
@@ -1454,10 +1482,7 @@ static int tegra_sor_remove(struct platform_device *pdev)
return err;
}
- clk_disable_unprepare(sor->clk_parent);
- clk_disable_unprepare(sor->clk_safe);
- clk_disable_unprepare(sor->clk_dp);
- clk_disable_unprepare(sor->clk);
+ tegra_output_remove(&sor->output);
return 0;
}
diff --git a/drivers/gpu/drm/tilcdc/Kconfig b/drivers/gpu/drm/tilcdc/Kconfig
index 7c3ef79fcb37..8394a0b3993e 100644
--- a/drivers/gpu/drm/tilcdc/Kconfig
+++ b/drivers/gpu/drm/tilcdc/Kconfig
@@ -1,6 +1,6 @@
config DRM_TILCDC
tristate "DRM Support for TI LCDC Display Controller"
- depends on DRM && OF && ARM
+ depends on DRM && OF && ARM && HAVE_DMA_ATTRS
select DRM_KMS_HELPER
select DRM_KMS_FB_HELPER
select DRM_KMS_CMA_HELPER
diff --git a/drivers/gpu/drm/udl/udl_fb.c b/drivers/gpu/drm/udl/udl_fb.c
index 8cbcb4589bd3..5fc16cecd3ba 100644
--- a/drivers/gpu/drm/udl/udl_fb.c
+++ b/drivers/gpu/drm/udl/udl_fb.c
@@ -589,19 +589,27 @@ int udl_fbdev_init(struct drm_device *dev)
ret = drm_fb_helper_init(dev, &ufbdev->helper,
1, 1);
- if (ret) {
- kfree(ufbdev);
- return ret;
-
- }
+ if (ret)
+ goto free;
- drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
+ ret = drm_fb_helper_single_add_all_connectors(&ufbdev->helper);
+ if (ret)
+ goto fini;
/* disable all the possible outputs/crtcs before entering KMS mode */
drm_helper_disable_unused_functions(dev);
- drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
+ ret = drm_fb_helper_initial_config(&ufbdev->helper, bpp_sel);
+ if (ret)
+ goto fini;
+
return 0;
+
+fini:
+ drm_fb_helper_fini(&ufbdev->helper);
+free:
+ kfree(ufbdev);
+ return ret;
}
void udl_fbdev_cleanup(struct drm_device *dev)
diff --git a/drivers/gpu/drm/udl/udl_modeset.c b/drivers/gpu/drm/udl/udl_modeset.c
index 1701f1dfb23f..677190a65e82 100644
--- a/drivers/gpu/drm/udl/udl_modeset.c
+++ b/drivers/gpu/drm/udl/udl_modeset.c
@@ -340,11 +340,11 @@ static int udl_crtc_mode_set(struct drm_crtc *crtc,
wrptr = udl_dummy_render(wrptr);
- ufb->active_16 = true;
if (old_fb) {
struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
uold_fb->active_16 = false;
}
+ ufb->active_16 = true;
udl->mode_buf_len = wrptr - buf;
/* damage all of it */
@@ -373,6 +373,13 @@ static int udl_crtc_page_flip(struct drm_crtc *crtc,
struct drm_device *dev = crtc->dev;
unsigned long flags;
+ struct drm_framebuffer *old_fb = crtc->primary->fb;
+ if (old_fb) {
+ struct udl_framebuffer *uold_fb = to_udl_fb(old_fb);
+ uold_fb->active_16 = false;
+ }
+ ufb->active_16 = true;
+
udl_handle_damage(ufb, 0, 0, fb->width, fb->height);
spin_lock_irqsave(&dev->event_lock, flags);
diff --git a/drivers/gpu/drm/udl/udl_transfer.c b/drivers/gpu/drm/udl/udl_transfer.c
index f343db73e095..917dcb978c2c 100644
--- a/drivers/gpu/drm/udl/udl_transfer.c
+++ b/drivers/gpu/drm/udl/udl_transfer.c
@@ -82,12 +82,14 @@ static inline u16 pixel32_to_be16(const uint32_t pixel)
((pixel >> 8) & 0xf800));
}
-static bool pixel_repeats(const void *pixel, const uint32_t repeat, int bpp)
+static inline u16 get_pixel_val16(const uint8_t *pixel, int bpp)
{
+ u16 pixel_val16 = 0;
if (bpp == 2)
- return *(const uint16_t *)pixel == repeat;
- else
- return *(const uint32_t *)pixel == repeat;
+ pixel_val16 = *(const uint16_t *)pixel;
+ else if (bpp == 4)
+ pixel_val16 = pixel32_to_be16(*(const uint32_t *)pixel);
+ return pixel_val16;
}
/*
@@ -134,6 +136,7 @@ static void udl_compress_hline16(
uint8_t *cmd_pixels_count_byte = NULL;
const u8 *raw_pixel_start = NULL;
const u8 *cmd_pixel_start, *cmd_pixel_end = NULL;
+ uint16_t pixel_val16;
prefetchw((void *) cmd); /* pull in one cache line at least */
@@ -154,33 +157,29 @@ static void udl_compress_hline16(
(int)(cmd_buffer_end - cmd) / 2))) * bpp;
prefetch_range((void *) pixel, (cmd_pixel_end - pixel) * bpp);
+ pixel_val16 = get_pixel_val16(pixel, bpp);
while (pixel < cmd_pixel_end) {
const u8 *const start = pixel;
- u32 repeating_pixel;
-
- if (bpp == 2) {
- repeating_pixel = *(uint16_t *)pixel;
- *(uint16_t *)cmd = cpu_to_be16(repeating_pixel);
- } else {
- repeating_pixel = *(uint32_t *)pixel;
- *(uint16_t *)cmd = cpu_to_be16(pixel32_to_be16(repeating_pixel));
- }
+ const uint16_t repeating_pixel_val16 = pixel_val16;
+
+ *(uint16_t *)cmd = cpu_to_be16(pixel_val16);
cmd += 2;
pixel += bpp;
- if (unlikely((pixel < cmd_pixel_end) &&
- (pixel_repeats(pixel, repeating_pixel, bpp)))) {
+ while (pixel < cmd_pixel_end) {
+ pixel_val16 = get_pixel_val16(pixel, bpp);
+ if (pixel_val16 != repeating_pixel_val16)
+ break;
+ pixel += bpp;
+ }
+
+ if (unlikely(pixel > start + bpp)) {
/* go back and fill in raw pixel count */
*raw_pixels_count_byte = (((start -
raw_pixel_start) / bpp) + 1) & 0xFF;
- while ((pixel < cmd_pixel_end) &&
- (pixel_repeats(pixel, repeating_pixel, bpp))) {
- pixel += bpp;
- }
-
/* immediately after raw data is repeat byte */
*cmd++ = (((pixel - start) / bpp) - 1) & 0xFF;
diff --git a/drivers/gpu/host1x/bus.c b/drivers/gpu/host1x/bus.c
index aaf54859adb0..4a99c6416e6a 100644
--- a/drivers/gpu/host1x/bus.c
+++ b/drivers/gpu/host1x/bus.c
@@ -72,13 +72,14 @@ static void host1x_subdev_del(struct host1x_subdev *subdev)
/**
* host1x_device_parse_dt() - scan device tree and add matching subdevices
*/
-static int host1x_device_parse_dt(struct host1x_device *device)
+static int host1x_device_parse_dt(struct host1x_device *device,
+ struct host1x_driver *driver)
{
struct device_node *np;
int err;
for_each_child_of_node(device->dev.parent->of_node, np) {
- if (of_match_node(device->driver->subdevs, np) &&
+ if (of_match_node(driver->subdevs, np) &&
of_device_is_available(np)) {
err = host1x_subdev_add(device, np);
if (err < 0)
@@ -109,14 +110,12 @@ static void host1x_subdev_register(struct host1x_device *device,
mutex_unlock(&device->clients_lock);
mutex_unlock(&device->subdevs_lock);
- /*
- * When all subdevices have been registered, the composite device is
- * ready to be probed.
- */
if (list_empty(&device->subdevs)) {
- err = device->driver->probe(device);
+ err = device_add(&device->dev);
if (err < 0)
- dev_err(&device->dev, "probe failed: %d\n", err);
+ dev_err(&device->dev, "failed to add: %d\n", err);
+ else
+ device->registered = true;
}
}
@@ -124,16 +123,16 @@ static void __host1x_subdev_unregister(struct host1x_device *device,
struct host1x_subdev *subdev)
{
struct host1x_client *client = subdev->client;
- int err;
/*
* If all subdevices have been activated, we're about to remove the
* first active subdevice, so unload the driver first.
*/
if (list_empty(&device->subdevs)) {
- err = device->driver->remove(device);
- if (err < 0)
- dev_err(&device->dev, "remove failed: %d\n", err);
+ if (device->registered) {
+ device->registered = false;
+ device_del(&device->dev);
+ }
}
/*
@@ -260,24 +259,113 @@ static int host1x_del_client(struct host1x *host1x,
return -ENODEV;
}
-static struct bus_type host1x_bus_type = {
- .name = "host1x",
-};
+static int host1x_device_match(struct device *dev, struct device_driver *drv)
+{
+ return strcmp(dev_name(dev), drv->name) == 0;
+}
+
+static int host1x_device_probe(struct device *dev)
+{
+ struct host1x_driver *driver = to_host1x_driver(dev->driver);
+ struct host1x_device *device = to_host1x_device(dev);
+
+ if (driver->probe)
+ return driver->probe(device);
+
+ return 0;
+}
-int host1x_bus_init(void)
+static int host1x_device_remove(struct device *dev)
{
- return bus_register(&host1x_bus_type);
+ struct host1x_driver *driver = to_host1x_driver(dev->driver);
+ struct host1x_device *device = to_host1x_device(dev);
+
+ if (driver->remove)
+ return driver->remove(device);
+
+ return 0;
+}
+
+static void host1x_device_shutdown(struct device *dev)
+{
+ struct host1x_driver *driver = to_host1x_driver(dev->driver);
+ struct host1x_device *device = to_host1x_device(dev);
+
+ if (driver->shutdown)
+ driver->shutdown(device);
}
-void host1x_bus_exit(void)
+static const struct dev_pm_ops host1x_device_pm_ops = {
+ .suspend = pm_generic_suspend,
+ .resume = pm_generic_resume,
+ .freeze = pm_generic_freeze,
+ .thaw = pm_generic_thaw,
+ .poweroff = pm_generic_poweroff,
+ .restore = pm_generic_restore,
+};
+
+struct bus_type host1x_bus_type = {
+ .name = "host1x",
+ .match = host1x_device_match,
+ .probe = host1x_device_probe,
+ .remove = host1x_device_remove,
+ .shutdown = host1x_device_shutdown,
+ .pm = &host1x_device_pm_ops,
+};
+
+static void __host1x_device_del(struct host1x_device *device)
{
- bus_unregister(&host1x_bus_type);
+ struct host1x_subdev *subdev, *sd;
+ struct host1x_client *client, *cl;
+
+ mutex_lock(&device->subdevs_lock);
+
+ /* unregister subdevices */
+ list_for_each_entry_safe(subdev, sd, &device->active, list) {
+ /*
+ * host1x_subdev_unregister() will remove the client from
+ * any lists, so we'll need to manually add it back to the
+ * list of idle clients.
+ *
+ * XXX: Alternatively, perhaps don't remove the client from
+ * any lists in host1x_subdev_unregister() and instead do
+ * that explicitly from host1x_unregister_client()?
+ */
+ client = subdev->client;
+
+ __host1x_subdev_unregister(device, subdev);
+
+ /* add the client to the list of idle clients */
+ mutex_lock(&clients_lock);
+ list_add_tail(&client->list, &clients);
+ mutex_unlock(&clients_lock);
+ }
+
+ /* remove subdevices */
+ list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
+ host1x_subdev_del(subdev);
+
+ mutex_unlock(&device->subdevs_lock);
+
+ /* move clients to idle list */
+ mutex_lock(&clients_lock);
+ mutex_lock(&device->clients_lock);
+
+ list_for_each_entry_safe(client, cl, &device->clients, list)
+ list_move_tail(&client->list, &clients);
+
+ mutex_unlock(&device->clients_lock);
+ mutex_unlock(&clients_lock);
+
+ /* finally remove the device */
+ list_del_init(&device->list);
}
static void host1x_device_release(struct device *dev)
{
struct host1x_device *device = to_host1x_device(dev);
+ __host1x_device_del(device);
kfree(device);
}
@@ -293,6 +381,8 @@ static int host1x_device_add(struct host1x *host1x,
if (!device)
return -ENOMEM;
+ device_initialize(&device->dev);
+
mutex_init(&device->subdevs_lock);
INIT_LIST_HEAD(&device->subdevs);
INIT_LIST_HEAD(&device->active);
@@ -303,24 +393,18 @@ static int host1x_device_add(struct host1x *host1x,
device->dev.coherent_dma_mask = host1x->dev->coherent_dma_mask;
device->dev.dma_mask = &device->dev.coherent_dma_mask;
+ dev_set_name(&device->dev, "%s", driver->driver.name);
device->dev.release = host1x_device_release;
- dev_set_name(&device->dev, "%s", driver->name);
device->dev.bus = &host1x_bus_type;
device->dev.parent = host1x->dev;
- err = device_register(&device->dev);
- if (err < 0)
- return err;
-
- err = host1x_device_parse_dt(device);
+ err = host1x_device_parse_dt(device, driver);
if (err < 0) {
- device_unregister(&device->dev);
+ kfree(device);
return err;
}
- mutex_lock(&host1x->devices_lock);
list_add_tail(&device->list, &host1x->devices);
- mutex_unlock(&host1x->devices_lock);
mutex_lock(&clients_lock);
@@ -347,51 +431,12 @@ static int host1x_device_add(struct host1x *host1x,
static void host1x_device_del(struct host1x *host1x,
struct host1x_device *device)
{
- struct host1x_subdev *subdev, *sd;
- struct host1x_client *client, *cl;
-
- mutex_lock(&device->subdevs_lock);
-
- /* unregister subdevices */
- list_for_each_entry_safe(subdev, sd, &device->active, list) {
- /*
- * host1x_subdev_unregister() will remove the client from
- * any lists, so we'll need to manually add it back to the
- * list of idle clients.
- *
- * XXX: Alternatively, perhaps don't remove the client from
- * any lists in host1x_subdev_unregister() and instead do
- * that explicitly from host1x_unregister_client()?
- */
- client = subdev->client;
-
- __host1x_subdev_unregister(device, subdev);
-
- /* add the client to the list of idle clients */
- mutex_lock(&clients_lock);
- list_add_tail(&client->list, &clients);
- mutex_unlock(&clients_lock);
+ if (device->registered) {
+ device->registered = false;
+ device_del(&device->dev);
}
- /* remove subdevices */
- list_for_each_entry_safe(subdev, sd, &device->subdevs, list)
- host1x_subdev_del(subdev);
-
- mutex_unlock(&device->subdevs_lock);
-
- /* move clients to idle list */
- mutex_lock(&clients_lock);
- mutex_lock(&device->clients_lock);
-
- list_for_each_entry_safe(client, cl, &device->clients, list)
- list_move_tail(&client->list, &clients);
-
- mutex_unlock(&device->clients_lock);
- mutex_unlock(&clients_lock);
-
- /* finally remove the device */
- list_del_init(&device->list);
- device_unregister(&device->dev);
+ put_device(&device->dev);
}
static void host1x_attach_driver(struct host1x *host1x,
@@ -409,11 +454,11 @@ static void host1x_attach_driver(struct host1x *host1x,
}
}
- mutex_unlock(&host1x->devices_lock);
-
err = host1x_device_add(host1x, driver);
if (err < 0)
dev_err(host1x->dev, "failed to allocate device: %d\n", err);
+
+ mutex_unlock(&host1x->devices_lock);
}
static void host1x_detach_driver(struct host1x *host1x,
@@ -466,7 +511,8 @@ int host1x_unregister(struct host1x *host1x)
return 0;
}
-int host1x_driver_register(struct host1x_driver *driver)
+int host1x_driver_register_full(struct host1x_driver *driver,
+ struct module *owner)
{
struct host1x *host1x;
@@ -483,9 +529,12 @@ int host1x_driver_register(struct host1x_driver *driver)
mutex_unlock(&devices_lock);
- return 0;
+ driver->driver.bus = &host1x_bus_type;
+ driver->driver.owner = owner;
+
+ return driver_register(&driver->driver);
}
-EXPORT_SYMBOL(host1x_driver_register);
+EXPORT_SYMBOL(host1x_driver_register_full);
void host1x_driver_unregister(struct host1x_driver *driver)
{
diff --git a/drivers/gpu/host1x/bus.h b/drivers/gpu/host1x/bus.h
index 4099e99212c8..88fb1c4aac68 100644
--- a/drivers/gpu/host1x/bus.h
+++ b/drivers/gpu/host1x/bus.h
@@ -18,10 +18,10 @@
#ifndef HOST1X_BUS_H
#define HOST1X_BUS_H
+struct bus_type;
struct host1x;
-int host1x_bus_init(void);
-void host1x_bus_exit(void);
+extern struct bus_type host1x_bus_type;
int host1x_register(struct host1x *host1x);
int host1x_unregister(struct host1x *host1x);
diff --git a/drivers/gpu/host1x/dev.c b/drivers/gpu/host1x/dev.c
index 2529908d304b..53d3d1d45b48 100644
--- a/drivers/gpu/host1x/dev.c
+++ b/drivers/gpu/host1x/dev.c
@@ -216,7 +216,7 @@ static int __init tegra_host1x_init(void)
{
int err;
- err = host1x_bus_init();
+ err = bus_register(&host1x_bus_type);
if (err < 0)
return err;
@@ -233,7 +233,7 @@ static int __init tegra_host1x_init(void)
unregister_host1x:
platform_driver_unregister(&tegra_host1x_driver);
unregister_bus:
- host1x_bus_exit();
+ bus_unregister(&host1x_bus_type);
return err;
}
module_init(tegra_host1x_init);
@@ -242,7 +242,7 @@ static void __exit tegra_host1x_exit(void)
{
platform_driver_unregister(&tegra_mipi_driver);
platform_driver_unregister(&tegra_host1x_driver);
- host1x_bus_exit();
+ bus_unregister(&host1x_bus_type);
}
module_exit(tegra_host1x_exit);
diff --git a/drivers/gpu/ipu-v3/ipu-common.c b/drivers/gpu/ipu-v3/ipu-common.c
index f707d25ae78f..67bab5c36056 100644
--- a/drivers/gpu/ipu-v3/ipu-common.c
+++ b/drivers/gpu/ipu-v3/ipu-common.c
@@ -742,7 +742,7 @@ static struct ipu_devtype ipu_type_imx51 = {
.tpm_ofs = 0x1f060000,
.csi0_ofs = 0x1f030000,
.csi1_ofs = 0x1f038000,
- .ic_ofs = 0x1f020000,
+ .ic_ofs = 0x1e020000,
.disp0_ofs = 0x1e040000,
.disp1_ofs = 0x1e048000,
.dc_tmpl_ofs = 0x1f080000,
@@ -758,7 +758,7 @@ static struct ipu_devtype ipu_type_imx53 = {
.tpm_ofs = 0x07060000,
.csi0_ofs = 0x07030000,
.csi1_ofs = 0x07038000,
- .ic_ofs = 0x07020000,
+ .ic_ofs = 0x06020000,
.disp0_ofs = 0x06040000,
.disp1_ofs = 0x06048000,
.dc_tmpl_ofs = 0x07080000,
diff --git a/drivers/gpu/ipu-v3/ipu-dc.c b/drivers/gpu/ipu-v3/ipu-dc.c
index 2326c752d89b..4864f8300797 100644
--- a/drivers/gpu/ipu-v3/ipu-dc.c
+++ b/drivers/gpu/ipu-v3/ipu-dc.c
@@ -114,6 +114,7 @@ struct ipu_dc_priv {
struct completion comp;
int dc_irq;
int dp_irq;
+ int use_count;
};
static void dc_link_event(struct ipu_dc *dc, int event, int addr, int priority)
@@ -232,7 +233,16 @@ EXPORT_SYMBOL_GPL(ipu_dc_init_sync);
void ipu_dc_enable(struct ipu_soc *ipu)
{
- ipu_module_enable(ipu, IPU_CONF_DC_EN);
+ struct ipu_dc_priv *priv = ipu->dc_priv;
+
+ mutex_lock(&priv->mutex);
+
+ if (!priv->use_count)
+ ipu_module_enable(priv->ipu, IPU_CONF_DC_EN);
+
+ priv->use_count++;
+
+ mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL_GPL(ipu_dc_enable);
@@ -267,7 +277,8 @@ static irqreturn_t dc_irq_handler(int irq, void *dev_id)
void ipu_dc_disable_channel(struct ipu_dc *dc)
{
struct ipu_dc_priv *priv = dc->priv;
- int irq, ret;
+ int irq;
+ unsigned long ret;
u32 val;
/* TODO: Handle MEM_FG_SYNC differently from MEM_BG_SYNC */
@@ -282,7 +293,7 @@ void ipu_dc_disable_channel(struct ipu_dc *dc)
enable_irq(irq);
ret = wait_for_completion_timeout(&priv->comp, msecs_to_jiffies(50));
disable_irq(irq);
- if (ret <= 0) {
+ if (ret == 0) {
dev_warn(priv->dev, "DC stop timeout after 50 ms\n");
val = readl(dc->base + DC_WR_CH_CONF);
@@ -294,7 +305,18 @@ EXPORT_SYMBOL_GPL(ipu_dc_disable_channel);
void ipu_dc_disable(struct ipu_soc *ipu)
{
- ipu_module_disable(ipu, IPU_CONF_DC_EN);
+ struct ipu_dc_priv *priv = ipu->dc_priv;
+
+ mutex_lock(&priv->mutex);
+
+ priv->use_count--;
+ if (!priv->use_count)
+ ipu_module_disable(priv->ipu, IPU_CONF_DC_EN);
+
+ if (priv->use_count < 0)
+ priv->use_count = 0;
+
+ mutex_unlock(&priv->mutex);
}
EXPORT_SYMBOL_GPL(ipu_dc_disable);
diff --git a/drivers/gpu/ipu-v3/ipu-di.c b/drivers/gpu/ipu-v3/ipu-di.c
index c490ba4384fc..b61d6be97602 100644
--- a/drivers/gpu/ipu-v3/ipu-di.c
+++ b/drivers/gpu/ipu-v3/ipu-di.c
@@ -207,10 +207,10 @@ static void ipu_di_sync_config(struct ipu_di *di, struct di_sync_config *config,
static void ipu_di_sync_config_interlaced(struct ipu_di *di,
struct ipu_di_signal_cfg *sig)
{
- u32 h_total = sig->width + sig->h_sync_width +
- sig->h_start_width + sig->h_end_width;
- u32 v_total = sig->height + sig->v_sync_width +
- sig->v_start_width + sig->v_end_width;
+ u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+ sig->mode.hback_porch + sig->mode.hfront_porch;
+ u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+ sig->mode.vback_porch + sig->mode.vfront_porch;
u32 reg;
struct di_sync_config cfg[] = {
{
@@ -229,13 +229,13 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
}, {
.run_count = v_total / 2 - 1,
.run_src = DI_SYNC_HSYNC,
- .offset_count = sig->v_start_width,
+ .offset_count = sig->mode.vback_porch,
.offset_src = DI_SYNC_HSYNC,
.repeat_count = 2,
.cnt_clr_src = DI_SYNC_VSYNC,
}, {
.run_src = DI_SYNC_HSYNC,
- .repeat_count = sig->height / 2,
+ .repeat_count = sig->mode.vactive / 2,
.cnt_clr_src = 4,
}, {
.run_count = v_total - 1,
@@ -249,9 +249,9 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
.cnt_clr_src = DI_SYNC_VSYNC,
}, {
.run_src = DI_SYNC_CLK,
- .offset_count = sig->h_start_width,
+ .offset_count = sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
+ .repeat_count = sig->mode.hactive,
.cnt_clr_src = 5,
}, {
.run_count = v_total - 1,
@@ -277,10 +277,10 @@ static void ipu_di_sync_config_interlaced(struct ipu_di *di,
static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
struct ipu_di_signal_cfg *sig, int div)
{
- u32 h_total = sig->width + sig->h_sync_width + sig->h_start_width +
- sig->h_end_width;
- u32 v_total = sig->height + sig->v_sync_width + sig->v_start_width +
- sig->v_end_width;
+ u32 h_total = sig->mode.hactive + sig->mode.hsync_len +
+ sig->mode.hback_porch + sig->mode.hfront_porch;
+ u32 v_total = sig->mode.vactive + sig->mode.vsync_len +
+ sig->mode.vback_porch + sig->mode.vfront_porch;
struct di_sync_config cfg[] = {
{
/* 1: INT_HSYNC */
@@ -294,27 +294,29 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_CLK,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
+ .cnt_down = sig->mode.hsync_len * 2,
} , {
/* PIN3: VSYNC */
.run_count = v_total - 1,
.run_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
+ .cnt_down = sig->mode.vsync_len * 2,
} , {
/* 4: Line Active */
.run_src = DI_SYNC_HSYNC,
- .offset_count = sig->v_sync_width + sig->v_start_width,
+ .offset_count = sig->mode.vsync_len +
+ sig->mode.vback_porch,
.offset_src = DI_SYNC_HSYNC,
- .repeat_count = sig->height,
+ .repeat_count = sig->mode.vactive,
.cnt_clr_src = DI_SYNC_VSYNC,
} , {
/* 5: Pixel Active, referenced by DC */
.run_src = DI_SYNC_CLK,
- .offset_count = sig->h_sync_width + sig->h_start_width,
+ .offset_count = sig->mode.hsync_len +
+ sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
+ .repeat_count = sig->mode.hactive,
.cnt_clr_src = 5, /* Line Active */
} , {
/* unused */
@@ -339,9 +341,10 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
} , {
/* 3: Line Active */
.run_src = DI_SYNC_INT_HSYNC,
- .offset_count = sig->v_sync_width + sig->v_start_width,
+ .offset_count = sig->mode.vsync_len +
+ sig->mode.vback_porch,
.offset_src = DI_SYNC_INT_HSYNC,
- .repeat_count = sig->height,
+ .repeat_count = sig->mode.vactive,
.cnt_clr_src = 3 /* VSYNC */,
} , {
/* PIN4: HSYNC for VGA via TVEv2 on TQ MBa53 */
@@ -351,13 +354,14 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_CLK,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
+ .cnt_down = sig->mode.hsync_len * 2,
} , {
/* 5: Pixel Active signal to DC */
.run_src = DI_SYNC_CLK,
- .offset_count = sig->h_sync_width + sig->h_start_width,
+ .offset_count = sig->mode.hsync_len +
+ sig->mode.hback_porch,
.offset_src = DI_SYNC_CLK,
- .repeat_count = sig->width,
+ .repeat_count = sig->mode.hactive,
.cnt_clr_src = 4, /* Line Active */
} , {
/* PIN6: VSYNC for VGA via TVEv2 on TQ MBa53 */
@@ -367,7 +371,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
+ .cnt_down = sig->mode.vsync_len * 2,
} , {
/* PIN4: HSYNC for VGA via TVEv2 on i.MX53-QSB */
.run_count = h_total - 1,
@@ -376,7 +380,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_CLK,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_CLK,
- .cnt_down = sig->h_sync_width * 2,
+ .cnt_down = sig->mode.hsync_len * 2,
} , {
/* PIN6: VSYNC for VGA via TVEv2 on i.MX53-QSB */
.run_count = v_total - 1,
@@ -385,7 +389,7 @@ static void ipu_di_sync_config_noninterlaced(struct ipu_di *di,
.offset_src = DI_SYNC_INT_HSYNC,
.cnt_polarity_gen_en = 1,
.cnt_polarity_trigger_src = DI_SYNC_INT_HSYNC,
- .cnt_down = sig->v_sync_width * 2,
+ .cnt_down = sig->mode.vsync_len * 2,
} , {
/* unused */
},
@@ -433,10 +437,10 @@ static void ipu_di_config_clock(struct ipu_di *di,
unsigned long in_rate;
unsigned div;
- clk_set_rate(clk, sig->pixelclock);
+ clk_set_rate(clk, sig->mode.pixelclock);
in_rate = clk_get_rate(clk);
- div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
if (div == 0)
div = 1;
@@ -454,10 +458,10 @@ static void ipu_di_config_clock(struct ipu_di *di,
unsigned div, error;
clkrate = clk_get_rate(di->clk_ipu);
- div = (clkrate + sig->pixelclock / 2) / sig->pixelclock;
+ div = DIV_ROUND_CLOSEST(clkrate, sig->mode.pixelclock);
rate = clkrate / div;
- error = rate / (sig->pixelclock / 1000);
+ error = rate / (sig->mode.pixelclock / 1000);
dev_dbg(di->ipu->dev, " IPU clock can give %lu with divider %u, error %d.%u%%\n",
rate, div, (signed)(error - 1000) / 10, error % 10);
@@ -473,10 +477,10 @@ static void ipu_di_config_clock(struct ipu_di *di,
clk = di->clk_di;
- clk_set_rate(clk, sig->pixelclock);
+ clk_set_rate(clk, sig->mode.pixelclock);
in_rate = clk_get_rate(clk);
- div = (in_rate + sig->pixelclock / 2) / sig->pixelclock;
+ div = DIV_ROUND_CLOSEST(in_rate, sig->mode.pixelclock);
if (div == 0)
div = 1;
@@ -504,35 +508,58 @@ static void ipu_di_config_clock(struct ipu_di *di,
ipu_di_write(di, val, DI_GENERAL);
dev_dbg(di->ipu->dev, "Want %luHz IPU %luHz DI %luHz using %s, %luHz\n",
- sig->pixelclock,
+ sig->mode.pixelclock,
clk_get_rate(di->clk_ipu),
clk_get_rate(di->clk_di),
clk == di->clk_di ? "DI" : "IPU",
clk_get_rate(di->clk_di_pixel) / (clkgen0 >> 4));
}
+/*
+ * This function is called to adjust a video mode to IPU restrictions.
+ * It is meant to be called from drm crtc mode_fixup() methods.
+ */
+int ipu_di_adjust_videomode(struct ipu_di *di, struct videomode *mode)
+{
+ u32 diff;
+
+ if (mode->vfront_porch >= 2)
+ return 0;
+
+ diff = 2 - mode->vfront_porch;
+
+ if (mode->vback_porch >= diff) {
+ mode->vfront_porch = 2;
+ mode->vback_porch -= diff;
+ } else if (mode->vsync_len > diff) {
+ mode->vfront_porch = 2;
+ mode->vsync_len = mode->vsync_len - diff;
+ } else {
+ dev_warn(di->ipu->dev, "failed to adjust videomode\n");
+ return -EINVAL;
+ }
+
+ dev_warn(di->ipu->dev, "videomode adapted for IPU restrictions\n");
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ipu_di_adjust_videomode);
+
int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
{
u32 reg;
u32 di_gen, vsync_cnt;
u32 div;
- u32 h_total, v_total;
dev_dbg(di->ipu->dev, "disp %d: panel size = %d x %d\n",
- di->id, sig->width, sig->height);
+ di->id, sig->mode.hactive, sig->mode.vactive);
- if ((sig->v_sync_width == 0) || (sig->h_sync_width == 0))
+ if ((sig->mode.vsync_len == 0) || (sig->mode.hsync_len == 0))
return -EINVAL;
- h_total = sig->width + sig->h_sync_width + sig->h_start_width +
- sig->h_end_width;
- v_total = sig->height + sig->v_sync_width + sig->v_start_width +
- sig->v_end_width;
-
dev_dbg(di->ipu->dev, "Clocks: IPU %luHz DI %luHz Needed %luHz\n",
clk_get_rate(di->clk_ipu),
clk_get_rate(di->clk_di),
- sig->pixelclock);
+ sig->mode.pixelclock);
mutex_lock(&di_mutex);
@@ -551,7 +578,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
di_gen = ipu_di_read(di, DI_GENERAL) & DI_GEN_DI_CLK_EXT;
di_gen |= DI_GEN_DI_VSYNC_EXT;
- if (sig->interlaced) {
+ if (sig->mode.flags & DISPLAY_FLAGS_INTERLACED) {
ipu_di_sync_config_interlaced(di, sig);
/* set y_sel = 1 */
@@ -561,9 +588,9 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
vsync_cnt = 7;
- if (sig->Hsync_pol)
+ if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH)
di_gen |= DI_GEN_POLARITY_3;
- if (sig->Vsync_pol)
+ if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH)
di_gen |= DI_GEN_POLARITY_2;
} else {
ipu_di_sync_config_noninterlaced(di, sig, div);
@@ -577,7 +604,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
if (!(sig->hsync_pin == 2 && sig->vsync_pin == 3))
vsync_cnt = 6;
- if (sig->Hsync_pol) {
+ if (sig->mode.flags & DISPLAY_FLAGS_HSYNC_HIGH) {
if (sig->hsync_pin == 2)
di_gen |= DI_GEN_POLARITY_2;
else if (sig->hsync_pin == 4)
@@ -585,7 +612,7 @@ int ipu_di_init_sync_panel(struct ipu_di *di, struct ipu_di_signal_cfg *sig)
else if (sig->hsync_pin == 7)
di_gen |= DI_GEN_POLARITY_7;
}
- if (sig->Vsync_pol) {
+ if (sig->mode.flags & DISPLAY_FLAGS_VSYNC_HIGH) {
if (sig->vsync_pin == 3)
di_gen |= DI_GEN_POLARITY_3;
else if (sig->vsync_pin == 6)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index dfdc26970022..152b006833cd 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -147,6 +147,16 @@ config HID_BELKIN
---help---
Support for Belkin Flip KVM and Wireless keyboard.
+config HID_BETOP_FF
+ tristate "Betop Production Inc. force feedback support"
+ depends on USB_HID
+ select INPUT_FF_MEMLESS
+ ---help---
+ Say Y here if you want to enable force feedback support for devices by
+ BETOP Production Ltd.
+ Currently the following devices are known to be supported:
+ - BETOP 2185 PC & BFM MODE
+
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
depends on HID
@@ -389,7 +399,7 @@ config HID_LOGITECH_HIDPP
Say Y if you want support for Logitech devices relying on the HID++
specification. Such devices are the various Logitech Touchpads (T650,
T651, TK820), some mice (Zone Touch mouse), or even keyboards (Solar
- Keayboard).
+ Keyboard).
config LOGITECH_FF
bool "Logitech force feedback support"
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index debd15b44b59..6f19958dfc38 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -2,10 +2,7 @@
# Makefile for the HID driver
#
hid-y := hid-core.o hid-input.o
-
-ifdef CONFIG_DEBUG_FS
- hid-objs += hid-debug.o
-endif
+hid-$(CONFIG_DEBUG_FS) += hid-debug.o
obj-$(CONFIG_HID) += hid.o
obj-$(CONFIG_UHID) += uhid.o
@@ -15,23 +12,13 @@ obj-$(CONFIG_HID_GENERIC) += hid-generic.o
hid-$(CONFIG_HIDRAW) += hidraw.o
hid-logitech-y := hid-lg.o
-ifdef CONFIG_LOGITECH_FF
- hid-logitech-y += hid-lgff.o
-endif
-ifdef CONFIG_LOGIRUMBLEPAD2_FF
- hid-logitech-y += hid-lg2ff.o
-endif
-ifdef CONFIG_LOGIG940_FF
- hid-logitech-y += hid-lg3ff.o
-endif
-ifdef CONFIG_LOGIWHEELS_FF
- hid-logitech-y += hid-lg4ff.o
-endif
+hid-logitech-$(CONFIG_LOGITECH_FF) += hid-lgff.o
+hid-logitech-$(CONFIG_LOGIRUMBLEPAD2_FF) += hid-lg2ff.o
+hid-logitech-$(CONFIG_LOGIG940_FF) += hid-lg3ff.o
+hid-logitech-$(CONFIG_LOGIWHEELS_FF) += hid-lg4ff.o
hid-wiimote-y := hid-wiimote-core.o hid-wiimote-modules.o
-ifdef CONFIG_DEBUG_FS
- hid-wiimote-y += hid-wiimote-debug.o
-endif
+hid-wiimote-$(CONFIG_DEBUG_FS) += hid-wiimote-debug.o
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
@@ -39,6 +26,7 @@ obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
+obj-$(CONFIG_HID_BETOP_FF) += hid-betopff.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
obj-$(CONFIG_HID_CHICONY) += hid-chicony.o
obj-$(CONFIG_HID_CP2112) += hid-cp2112.o
@@ -76,24 +64,12 @@ obj-$(CONFIG_HID_PENMOUNT) += hid-penmount.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
hid-picolcd-y += hid-picolcd_core.o
-ifdef CONFIG_HID_PICOLCD_FB
-hid-picolcd-y += hid-picolcd_fb.o
-endif
-ifdef CONFIG_HID_PICOLCD_BACKLIGHT
-hid-picolcd-y += hid-picolcd_backlight.o
-endif
-ifdef CONFIG_HID_PICOLCD_LCD
-hid-picolcd-y += hid-picolcd_lcd.o
-endif
-ifdef CONFIG_HID_PICOLCD_LEDS
-hid-picolcd-y += hid-picolcd_leds.o
-endif
-ifdef CONFIG_HID_PICOLCD_CIR
-hid-picolcd-y += hid-picolcd_cir.o
-endif
-ifdef CONFIG_DEBUG_FS
-hid-picolcd-y += hid-picolcd_debugfs.o
-endif
+hid-picolcd-$(CONFIG_HID_PICOLCD_FB) += hid-picolcd_fb.o
+hid-picolcd-$(CONFIG_HID_PICOLCD_BACKLIGHT) += hid-picolcd_backlight.o
+hid-picolcd-$(CONFIG_HID_PICOLCD_LCD) += hid-picolcd_lcd.o
+hid-picolcd-$(CONFIG_HID_PICOLCD_LEDS) += hid-picolcd_leds.o
+hid-picolcd-$(CONFIG_HID_PICOLCD_CIR) += hid-picolcd_cir.o
+hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o
obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
diff --git a/drivers/hid/hid-betopff.c b/drivers/hid/hid-betopff.c
new file mode 100644
index 000000000000..69cfc8dc6af1
--- /dev/null
+++ b/drivers/hid/hid-betopff.c
@@ -0,0 +1,160 @@
+/*
+ * Force feedback support for Betop based devices
+ *
+ * The devices are distributed under various names and the same USB device ID
+ * can be used in both adapters and actual game controllers.
+ *
+ * 0x11c2:0x2208 "BTP2185 BFM mode Joystick"
+ * - tested with BTP2185 BFM Mode.
+ *
+ * 0x11C0:0x5506 "BTP2185 PC mode Joystick"
+ * - tested with BTP2185 PC Mode.
+ *
+ * 0x8380:0x1850 "BTP2185 V2 PC mode USB Gamepad"
+ * - tested with BTP2185 PC Mode with another version.
+ *
+ * 0x20bc:0x5500 "BTP2185 V2 BFM mode Joystick"
+ * - tested with BTP2171s.
+ * Copyright (c) 2014 Huang Bo <huangbobupt@163.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/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/hid.h>
+
+#include "hid-ids.h"
+
+struct betopff_device {
+ struct hid_report *report;
+};
+
+static int hid_betopff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct betopff_device *betopff = data;
+ __u16 left, right;
+
+ left = effect->u.rumble.strong_magnitude;
+ right = effect->u.rumble.weak_magnitude;
+
+ betopff->report->field[2]->value[0] = left / 256;
+ betopff->report->field[3]->value[0] = right / 256;
+
+ hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
+
+ return 0;
+}
+
+static int betopff_init(struct hid_device *hid)
+{
+ struct betopff_device *betopff;
+ struct hid_report *report;
+ struct hid_input *hidinput =
+ list_first_entry(&hid->inputs, struct hid_input, list);
+ struct list_head *report_list =
+ &hid->report_enum[HID_OUTPUT_REPORT].report_list;
+ struct input_dev *dev = hidinput->input;
+ int field_count = 0;
+ int error;
+ int i, j;
+
+ if (list_empty(report_list)) {
+ hid_err(hid, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report = list_first_entry(report_list, struct hid_report, list);
+ /*
+ * Actually there are 4 fields for 4 Bytes as below:
+ * -----------------------------------------
+ * Byte0 Byte1 Byte2 Byte3
+ * 0x00 0x00 left_motor right_motor
+ * -----------------------------------------
+ * Do init them with default value.
+ */
+ for (i = 0; i < report->maxfield; i++) {
+ for (j = 0; j < report->field[i]->report_count; j++) {
+ report->field[i]->value[j] = 0x00;
+ field_count++;
+ }
+ }
+
+ if (field_count < 4) {
+ hid_err(hid, "not enough fields in the report: %d\n",
+ field_count);
+ return -ENODEV;
+ }
+
+ betopff = kzalloc(sizeof(*betopff), GFP_KERNEL);
+ if (!betopff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, betopff, hid_betopff_play);
+ if (error) {
+ kfree(betopff);
+ return error;
+ }
+
+ betopff->report = report;
+ hid_hw_request(hid, betopff->report, HID_REQ_SET_REPORT);
+
+ hid_info(hid, "Force feedback for betop devices by huangbo <huangbobupt@163.com>\n");
+
+ return 0;
+}
+
+static int betop_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ if (id->driver_data)
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ betopff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id betop_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, betop_devices);
+
+static struct hid_driver betop_driver = {
+ .name = "betop",
+ .id_table = betop_devices,
+ .probe = betop_probe,
+};
+module_hid_driver(betop_driver);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 8b638792cb43..7c669c328c4c 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -698,15 +698,25 @@ static void hid_scan_feature_usage(struct hid_parser *parser, u32 usage)
static void hid_scan_collection(struct hid_parser *parser, unsigned type)
{
struct hid_device *hid = parser->device;
+ int i;
if (((parser->global.usage_page << 16) == HID_UP_SENSOR) &&
type == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
if (hid->vendor == USB_VENDOR_ID_MICROSOFT &&
- hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 &&
+ (hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3 ||
+ hid->product == USB_DEVICE_ID_MS_TYPE_COVER_3_JP) &&
hid->group == HID_GROUP_MULTITOUCH)
hid->group = HID_GROUP_GENERIC;
+
+ if ((parser->global.usage_page << 16) == HID_UP_GENDESK)
+ for (i = 0; i < parser->local.usage_index; i++)
+ if (parser->local.usage[i] == HID_GD_POINTER)
+ parser->scan_flags |= HID_SCAN_FLAG_GD_POINTER;
+
+ if ((parser->global.usage_page << 16) >= HID_UP_MSVENDOR)
+ parser->scan_flags |= HID_SCAN_FLAG_VENDOR_SPECIFIC;
}
static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
@@ -792,11 +802,14 @@ static int hid_scan_report(struct hid_device *hid)
hid->group = HID_GROUP_WACOM;
break;
case USB_VENDOR_ID_SYNAPTICS:
- if ((hid->group == HID_GROUP_GENERIC) &&
- (hid->bus != BUS_USB || hid->type == HID_TYPE_USBMOUSE))
- /* hid-rmi should only bind to the mouse interface of
- * composite USB devices */
- hid->group = HID_GROUP_RMI;
+ if (hid->group == HID_GROUP_GENERIC)
+ if ((parser->scan_flags & HID_SCAN_FLAG_VENDOR_SPECIFIC)
+ && (parser->scan_flags & HID_SCAN_FLAG_GD_POINTER))
+ /*
+ * hid-rmi should take care of them,
+ * not hid-generic
+ */
+ hid->group = HID_GROUP_RMI;
break;
}
@@ -1757,6 +1770,10 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_AUREAL, USB_DEVICE_ID_AUREAL_W01RN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185BFM, 0x2208) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185PC, 0x5506) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2PC, 0x1850) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_BETOP_2185V2BFM, 0x5500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
@@ -1855,12 +1872,14 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_OFFICE_KB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MONTEREY, USB_DEVICE_ID_GENIUS_KB29E) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN) },
@@ -1908,6 +1927,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
#endif
#if IS_ENABLED(CONFIG_HID_SAITEK)
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_MMO7) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9) },
@@ -1971,6 +1991,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14) },
{ }
};
@@ -2328,6 +2349,7 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MCC, USB_DEVICE_ID_MCC_PMD1208LS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICKIT2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROCHIP, USB_DEVICE_ID_PICK16F1454) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR, USB_DEVICE_ID_N_S_HARMONY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ONTRAK, USB_DEVICE_ID_ONTRAK_ADU100 + 20) },
diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c
index 31fad641b744..6039f071fab1 100644
--- a/drivers/hid/hid-hyperv.c
+++ b/drivers/hid/hid-hyperv.c
@@ -381,7 +381,7 @@ static void mousevsc_on_channel_callback(void *context)
static int mousevsc_connect_to_vsp(struct hv_device *device)
{
int ret = 0;
- int t;
+ unsigned long t;
struct mousevsc_dev *input_dev = hv_get_drvdata(device);
struct mousevsc_prt_msg *request;
struct mousevsc_prt_msg *response;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 9243359c1821..204312bfab2c 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -189,6 +189,11 @@
#define USB_VENDOR_ID_BERKSHIRE 0x0c98
#define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140
+#define USB_VENDOR_ID_BETOP_2185BFM 0x11c2
+#define USB_VENDOR_ID_BETOP_2185PC 0x11c0
+#define USB_VENDOR_ID_BETOP_2185V2PC 0x8380
+#define USB_VENDOR_ID_BETOP_2185V2BFM 0x20bc
+
#define USB_VENDOR_ID_BTC 0x046e
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
@@ -638,6 +643,7 @@
#define USB_DEVICE_ID_PICKIT2 0x0033
#define USB_DEVICE_ID_PICOLCD 0xc002
#define USB_DEVICE_ID_PICOLCD_BOOTLOADER 0xf002
+#define USB_DEVICE_ID_PICK16F1454 0x0042
#define USB_VENDOR_ID_MICROSOFT 0x045e
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
@@ -648,12 +654,14 @@
#define USB_DEVICE_ID_MS_LK6K 0x00f9
#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
+#define USB_DEVICE_ID_MS_NE7K 0x071d
#define USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K 0x0730
#define USB_DEVICE_ID_MS_COMFORT_MOUSE_4500 0x076c
#define USB_DEVICE_ID_MS_SURFACE_PRO_2 0x0799
#define USB_DEVICE_ID_MS_TOUCH_COVER_2 0x07a7
#define USB_DEVICE_ID_MS_TYPE_COVER_2 0x07a9
#define USB_DEVICE_ID_MS_TYPE_COVER_3 0x07dc
+#define USB_DEVICE_ID_MS_TYPE_COVER_3_JP 0x07dd
#define USB_VENDOR_ID_MOJO 0x8282
#define USB_DEVICE_ID_RETRO_ADAPTER 0x3201
@@ -768,6 +776,9 @@
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008
+#define USB_VENDOR_ID_RAZER 0x1532
+#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D
+
#define USB_VENDOR_ID_REALTEK 0x0bda
#define USB_DEVICE_ID_REALTEK_READER 0x0152
@@ -792,6 +803,7 @@
#define USB_VENDOR_ID_SAITEK 0x06a3
#define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
#define USB_DEVICE_ID_SAITEK_PS1000 0x0621
+#define USB_DEVICE_ID_SAITEK_RAT7_OLD 0x0ccb
#define USB_DEVICE_ID_SAITEK_RAT7 0x0cd7
#define USB_DEVICE_ID_SAITEK_MMO7 0x0cd0
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index 9505605b6e22..052869d0ab78 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -306,10 +306,13 @@ static enum power_supply_property hidinput_battery_props[] = {
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
- USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
- HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
+ HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
+ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
+ HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
- USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
+ USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO),
@@ -1104,6 +1107,23 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
+ /*
+ * Ignore reports for absolute data if the data didn't change. This is
+ * not only an optimization but also fixes 'dead' key reports. Some
+ * RollOver implementations for localized keys (like BACKSLASH/PIPE; HID
+ * 0x31 and 0x32) report multiple keys, even though a localized keyboard
+ * can only have one of them physically available. The 'dead' keys
+ * report constant 0. As all map to the same keycode, they'd confuse
+ * the input layer. If we filter the 'dead' keys on the HID level, we
+ * skip the keycode translation and only forward real events.
+ */
+ if (!(field->flags & (HID_MAIN_ITEM_RELATIVE |
+ HID_MAIN_ITEM_BUFFERED_BYTE)) &&
+ (field->flags & HID_MAIN_ITEM_VARIABLE) &&
+ usage->usage_index < field->maxusage &&
+ value == field->value[usage->usage_index])
+ return;
+
/* report the usage code as scancode if the key status has changed */
if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
input_event(input, EV_MSC, MSC_SCAN, usage->hid);
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 4c55f4d95798..c4c3f0952521 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -38,6 +38,7 @@ struct lenovo_drvdata_tpkbd {
struct lenovo_drvdata_cptkbd {
bool fn_lock;
+ int sensitivity;
};
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
@@ -91,6 +92,38 @@ static int lenovo_input_mapping_cptkbd(struct hid_device *hdev,
case 0x00fa: /* Fn-Esc: Fn-lock toggle */
map_key_clear(KEY_FN_ESC);
return 1;
+ case 0x00fb: /* Middle mouse button (in native mode) */
+ map_key_clear(BTN_MIDDLE);
+ return 1;
+ }
+ }
+
+ /* Compatibility middle/wheel mappings should be ignored */
+ if (usage->hid == HID_GD_WHEEL)
+ return -1;
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON &&
+ (usage->hid & HID_USAGE) == 0x003)
+ return -1;
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_CONSUMER &&
+ (usage->hid & HID_USAGE) == 0x238)
+ return -1;
+
+ /* Map wheel emulation reports: 0xffa1 = USB, 0xff10 = BT */
+ if ((usage->hid & HID_USAGE_PAGE) == 0xff100000 ||
+ (usage->hid & HID_USAGE_PAGE) == 0xffa10000) {
+ field->flags |= HID_MAIN_ITEM_RELATIVE | HID_MAIN_ITEM_VARIABLE;
+ field->logical_minimum = -127;
+ field->logical_maximum = 127;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x0000:
+ hid_map_usage(hi, usage, bit, max, EV_REL, 0x06);
+ return 1;
+ case 0x0001:
+ hid_map_usage(hi, usage, bit, max, EV_REL, 0x08);
+ return 1;
+ default:
+ return -1;
}
}
@@ -145,6 +178,7 @@ static void lenovo_features_set_cptkbd(struct hid_device *hdev)
struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
ret = lenovo_send_cmd_cptkbd(hdev, 0x05, cptkbd_data->fn_lock);
+ ret = lenovo_send_cmd_cptkbd(hdev, 0x02, cptkbd_data->sensitivity);
if (ret)
hid_err(hdev, "Fn-lock setting failed: %d\n", ret);
}
@@ -179,13 +213,50 @@ static ssize_t attr_fn_lock_store_cptkbd(struct device *dev,
return count;
}
+static ssize_t attr_sensitivity_show_cptkbd(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ cptkbd_data->sensitivity);
+}
+
+static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t count)
+{
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+ struct lenovo_drvdata_cptkbd *cptkbd_data = hid_get_drvdata(hdev);
+ int value;
+
+ if (kstrtoint(buf, 10, &value) || value < 1 || value > 255)
+ return -EINVAL;
+
+ cptkbd_data->sensitivity = value;
+ lenovo_features_set_cptkbd(hdev);
+
+ return count;
+}
+
+
static struct device_attribute dev_attr_fn_lock_cptkbd =
__ATTR(fn_lock, S_IWUSR | S_IRUGO,
attr_fn_lock_show_cptkbd,
attr_fn_lock_store_cptkbd);
+static struct device_attribute dev_attr_sensitivity_cptkbd =
+ __ATTR(sensitivity, S_IWUSR | S_IRUGO,
+ attr_sensitivity_show_cptkbd,
+ attr_sensitivity_store_cptkbd);
+
+
static struct attribute *lenovo_attributes_cptkbd[] = {
&dev_attr_fn_lock_cptkbd.attr,
+ &dev_attr_sensitivity_cptkbd.attr,
NULL
};
@@ -594,8 +665,14 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
if (ret)
hid_warn(hdev, "Failed to switch F7/9/11 mode: %d\n", ret);
- /* Turn Fn-Lock on by default */
+ /* Switch middle button to native mode */
+ ret = lenovo_send_cmd_cptkbd(hdev, 0x09, 0x01);
+ if (ret)
+ hid_warn(hdev, "Failed to switch middle button: %d\n", ret);
+
+ /* Set keyboard settings to known state */
cptkbd_data->fn_lock = true;
+ cptkbd_data->sensitivity = 0x05;
lenovo_features_set_cptkbd(hdev);
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 7835717bc020..db0dd9b17e53 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -49,10 +49,6 @@
static void hid_lg4ff_set_range_dfp(struct hid_device *hid, u16 range);
static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range);
-static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf);
-static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count);
-
-static DEVICE_ATTR(range, S_IRWXU | S_IRWXG | S_IROTH, lg4ff_range_show, lg4ff_range_store);
struct lg4ff_device_entry {
__u32 product_id;
@@ -416,7 +412,8 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
}
/* Read current range and display it in terminal */
-static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *attr, char *buf)
+static ssize_t range_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct hid_device *hid = to_hid_device(dev);
struct lg4ff_device_entry *entry;
@@ -441,7 +438,8 @@ static ssize_t lg4ff_range_show(struct device *dev, struct device_attribute *att
/* Set range to user specified value, call appropriate function
* according to the type of the wheel */
-static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
+static ssize_t range_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct hid_device *hid = to_hid_device(dev);
struct lg4ff_device_entry *entry;
@@ -472,6 +470,7 @@ static ssize_t lg4ff_range_store(struct device *dev, struct device_attribute *at
return count;
}
+static DEVICE_ATTR_RW(range);
#ifdef CONFIG_LEDS_CLASS
static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c
index a93cefe0e522..e77658cd037c 100644
--- a/drivers/hid/hid-logitech-hidpp.c
+++ b/drivers/hid/hid-logitech-hidpp.c
@@ -89,6 +89,7 @@ struct hidpp_device {
struct hid_device *hid_dev;
struct mutex send_mutex;
void *send_receive_buf;
+ char *name; /* will never be NULL and should not be freed */
wait_queue_head_t wait;
bool answer_available;
u8 protocol_major;
@@ -105,6 +106,7 @@ struct hidpp_device {
};
+/* HID++ 1.0 error codes */
#define HIDPP_ERROR 0x8f
#define HIDPP_ERROR_SUCCESS 0x00
#define HIDPP_ERROR_INVALID_SUBID 0x01
@@ -119,6 +121,8 @@ struct hidpp_device {
#define HIDPP_ERROR_REQUEST_UNAVAILABLE 0x0a
#define HIDPP_ERROR_INVALID_PARAM_VALUE 0x0b
#define HIDPP_ERROR_WRONG_PIN_CODE 0x0c
+/* HID++ 2.0 error codes */
+#define HIDPP20_ERROR 0xff
static void hidpp_connect_event(struct hidpp_device *hidpp_dev);
@@ -192,9 +196,16 @@ static int hidpp_send_message_sync(struct hidpp_device *hidpp,
}
if (response->report_id == REPORT_ID_HIDPP_SHORT &&
- response->fap.feature_index == HIDPP_ERROR) {
+ response->rap.sub_id == HIDPP_ERROR) {
+ ret = response->rap.params[1];
+ dbg_hid("%s:got hidpp error %02X\n", __func__, ret);
+ goto exit;
+ }
+
+ if (response->report_id == REPORT_ID_HIDPP_LONG &&
+ response->fap.feature_index == HIDPP20_ERROR) {
ret = response->fap.params[1];
- dbg_hid("__hidpp_send_report got hidpp error %02X\n", ret);
+ dbg_hid("%s:got hidpp 2.0 error %02X\n", __func__, ret);
goto exit;
}
@@ -271,7 +282,8 @@ static inline bool hidpp_match_answer(struct hidpp_report *question,
static inline bool hidpp_match_error(struct hidpp_report *question,
struct hidpp_report *answer)
{
- return (answer->fap.feature_index == HIDPP_ERROR) &&
+ return ((answer->rap.sub_id == HIDPP_ERROR) ||
+ (answer->fap.feature_index == HIDPP20_ERROR)) &&
(answer->fap.funcindex_clientid == question->fap.feature_index) &&
(answer->fap.params[0] == question->fap.funcindex_clientid);
}
@@ -903,24 +915,24 @@ static int wtp_allocate(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
};
-static void wtp_connect(struct hid_device *hdev, bool connected)
+static int wtp_connect(struct hid_device *hdev, bool connected)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
struct wtp_data *wd = hidpp->private_data;
int ret;
if (!connected)
- return;
+ return 0;
if (!wd->x_size) {
ret = wtp_get_config(hidpp);
if (ret) {
hid_err(hdev, "Can not get wtp config: %d\n", ret);
- return;
+ return ret;
}
}
- hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index,
+ return hidpp_touchpad_set_raw_report_state(hidpp, wd->mt_feature_index,
true, true);
}
@@ -965,7 +977,7 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
/*
* If the mutex is locked then we have a pending answer from a
- * previoulsly sent command
+ * previously sent command.
*/
if (unlikely(mutex_is_locked(&hidpp->send_mutex))) {
/*
@@ -996,9 +1008,6 @@ static int hidpp_raw_hidpp_event(struct hidpp_device *hidpp, u8 *data,
return 1;
}
- if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
- return wtp_raw_event(hidpp->hid_dev, data, size);
-
return 0;
}
@@ -1006,7 +1015,9 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct hidpp_device *hidpp = hid_get_drvdata(hdev);
+ int ret = 0;
+ /* Generic HID++ processing. */
switch (data[0]) {
case REPORT_ID_HIDPP_LONG:
if (size != HIDPP_REPORT_LONG_LENGTH) {
@@ -1014,16 +1025,23 @@ static int hidpp_raw_event(struct hid_device *hdev, struct hid_report *report,
size);
return 1;
}
- return hidpp_raw_hidpp_event(hidpp, data, size);
+ ret = hidpp_raw_hidpp_event(hidpp, data, size);
+ break;
case REPORT_ID_HIDPP_SHORT:
if (size != HIDPP_REPORT_SHORT_LENGTH) {
hid_err(hdev, "received hid++ report of bad size (%d)",
size);
return 1;
}
- return hidpp_raw_hidpp_event(hidpp, data, size);
+ ret = hidpp_raw_hidpp_event(hidpp, data, size);
+ break;
}
+ /* If no report is available for further processing, skip calling
+ * raw_event of subclasses. */
+ if (ret != 0)
+ return ret;
+
if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
return wtp_raw_event(hdev, data, size);
@@ -1070,6 +1088,7 @@ static void hidpp_input_close(struct input_dev *dev)
static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
{
struct input_dev *input_dev = devm_input_allocate_device(&hdev->dev);
+ struct hidpp_device *hidpp = hid_get_drvdata(hdev);
if (!input_dev)
return NULL;
@@ -1078,7 +1097,7 @@ static struct input_dev *hidpp_allocate_input(struct hid_device *hdev)
input_dev->open = hidpp_input_open;
input_dev->close = hidpp_input_close;
- input_dev->name = hdev->name;
+ input_dev->name = hidpp->name;
input_dev->phys = hdev->phys;
input_dev->uniq = hdev->uniq;
input_dev->id.bustype = hdev->bus;
@@ -1098,8 +1117,11 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
struct input_dev *input;
char *name, *devm_name;
- if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP)
- wtp_connect(hdev, connected);
+ if (hidpp->quirks & HIDPP_QUIRK_CLASS_WTP) {
+ ret = wtp_connect(hdev, connected);
+ if (ret)
+ return;
+ }
if (!connected || hidpp->delayed_input)
return;
@@ -1117,22 +1139,28 @@ static void hidpp_connect_event(struct hidpp_device *hidpp)
hid_info(hdev, "HID++ %u.%u device connected.\n",
hidpp->protocol_major, hidpp->protocol_minor);
+ if (!hidpp->name || hidpp->name == hdev->name) {
+ name = hidpp_get_device_name(hidpp);
+ if (!name) {
+ hid_err(hdev,
+ "unable to retrieve the name of the device");
+ return;
+ }
+
+ devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name);
+ kfree(name);
+ if (!devm_name)
+ return;
+
+ hidpp->name = devm_name;
+ }
+
input = hidpp_allocate_input(hdev);
if (!input) {
hid_err(hdev, "cannot allocate new input device: %d\n", ret);
return;
}
- name = hidpp_get_device_name(hidpp);
- if (!name) {
- hid_err(hdev, "unable to retrieve the name of the device");
- } else {
- devm_name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s", name);
- if (devm_name)
- input->name = devm_name;
- kfree(name);
- }
-
hidpp_populate_input(hidpp, input, false);
ret = input_register_device(input);
@@ -1155,6 +1183,7 @@ static int hidpp_probe(struct hid_device *hdev, const struct hid_device_id *id)
return -ENOMEM;
hidpp->hid_dev = hdev;
+ hidpp->name = hdev->name;
hid_set_drvdata(hdev, hidpp);
hidpp->quirks = id->driver_data;
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index cacda43f6a6f..af935eb198c9 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -264,6 +264,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
.driver_data = MS_ERGONOMY },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE7K),
+ .driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
.driver_data = MS_ERGONOMY | MS_RDESC },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),
@@ -276,6 +278,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_DUPLICATE_USAGES },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3),
.driver_data = MS_HIDINPUT },
+ { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP),
+ .driver_data = MS_HIDINPUT },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT),
.driver_data = MS_PRESENTER },
diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c
index b51200fe2f33..49d4fe4f5987 100644
--- a/drivers/hid/hid-rmi.c
+++ b/drivers/hid/hid-rmi.c
@@ -33,6 +33,10 @@
#define RMI_READ_DATA_PENDING BIT(1)
#define RMI_STARTED BIT(2)
+/* device flags */
+#define RMI_DEVICE BIT(0)
+#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1)
+
enum rmi_mode_type {
RMI_MODE_OFF = 0,
RMI_MODE_ATTN_REPORTS = 1,
@@ -118,6 +122,8 @@ struct rmi_data {
struct work_struct reset_work;
struct hid_device *hdev;
+
+ unsigned long device_flags;
};
#define RMI_PAGE(addr) (((addr) >> 8) & 0xff)
@@ -452,9 +458,32 @@ static int rmi_raw_event(struct hid_device *hdev,
return rmi_read_data_event(hdev, data, size);
case RMI_ATTN_REPORT_ID:
return rmi_input_event(hdev, data, size);
- case RMI_MOUSE_REPORT_ID:
+ default:
+ return 1;
+ }
+
+ return 0;
+}
+
+static int rmi_event(struct hid_device *hdev, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct rmi_data *data = hid_get_drvdata(hdev);
+
+ if ((data->device_flags & RMI_DEVICE) &&
+ (field->application == HID_GD_POINTER ||
+ field->application == HID_GD_MOUSE)) {
+ if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) {
+ if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
+ return 0;
+
+ if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y)
+ && !value)
+ return 1;
+ }
+
rmi_schedule_reset(hdev);
- break;
+ return 1;
}
return 0;
@@ -856,6 +885,9 @@ static void rmi_input_configured(struct hid_device *hdev, struct hid_input *hi)
if (ret)
return;
+ if (!(data->device_flags & RMI_DEVICE))
+ return;
+
/* Allow incoming hid reports */
hid_device_io_start(hdev);
@@ -914,8 +946,38 @@ static int rmi_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
- /* we want to make HID ignore the advertised HID collection */
- return -1;
+ struct rmi_data *data = hid_get_drvdata(hdev);
+
+ /*
+ * we want to make HID ignore the advertised HID collection
+ * for RMI deivces
+ */
+ if (data->device_flags & RMI_DEVICE) {
+ if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) &&
+ ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON))
+ return 0;
+
+ return -1;
+ }
+
+ return 0;
+}
+
+static int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type,
+ unsigned id, struct hid_report **report)
+{
+ int i;
+
+ *report = hdev->report_enum[type].report_id_hash[id];
+ if (*report) {
+ for (i = 0; i < (*report)->maxfield; i++) {
+ unsigned app = (*report)->field[i]->application;
+ if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR)
+ return 1;
+ }
+ }
+
+ return 0;
}
static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -925,6 +987,7 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
size_t alloc_size;
struct hid_report *input_report;
struct hid_report *output_report;
+ struct hid_report *feature_report;
data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL);
if (!data)
@@ -943,27 +1006,37 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
- input_report = hdev->report_enum[HID_INPUT_REPORT]
- .report_id_hash[RMI_ATTN_REPORT_ID];
- if (!input_report) {
- hid_err(hdev, "device does not have expected input report\n");
- ret = -ENODEV;
- return ret;
+ if (id->driver_data)
+ data->device_flags = id->driver_data;
+
+ /*
+ * Check for the RMI specific report ids. If they are misisng
+ * simply return and let the events be processed by hid-input
+ */
+ if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT,
+ RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) {
+ hid_dbg(hdev, "device does not have set mode feature report\n");
+ goto start;
}
- data->input_report_size = (input_report->size >> 3) + 1 /* report id */;
+ if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT,
+ RMI_ATTN_REPORT_ID, &input_report)) {
+ hid_dbg(hdev, "device does not have attention input report\n");
+ goto start;
+ }
- output_report = hdev->report_enum[HID_OUTPUT_REPORT]
- .report_id_hash[RMI_WRITE_REPORT_ID];
- if (!output_report) {
- hid_err(hdev, "device does not have expected output report\n");
- ret = -ENODEV;
- return ret;
+ data->input_report_size = hid_report_len(input_report);
+
+ if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT,
+ RMI_WRITE_REPORT_ID, &output_report)) {
+ hid_dbg(hdev,
+ "device does not have rmi write output report\n");
+ goto start;
}
- data->output_report_size = (output_report->size >> 3)
- + 1 /* report id */;
+ data->output_report_size = hid_report_len(output_report);
+ data->device_flags |= RMI_DEVICE;
alloc_size = data->output_report_size + data->input_report_size;
data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL);
@@ -978,13 +1051,15 @@ static int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id)
mutex_init(&data->page_mutex);
+start:
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
hid_err(hdev, "hw start failed\n");
return ret;
}
- if (!test_bit(RMI_STARTED, &data->flags))
+ if ((data->device_flags & RMI_DEVICE) &&
+ !test_bit(RMI_STARTED, &data->flags))
/*
* The device maybe in the bootloader if rmi_input_configured
* failed to find F11 in the PDT. Print an error, but don't
@@ -1007,6 +1082,8 @@ static void rmi_remove(struct hid_device *hdev)
}
static const struct hid_device_id rmi_id[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14),
+ .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS },
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) },
{ }
};
@@ -1017,6 +1094,7 @@ static struct hid_driver rmi_driver = {
.id_table = rmi_id,
.probe = rmi_probe,
.remove = rmi_remove,
+ .event = rmi_event,
.raw_event = rmi_raw_event,
.input_mapping = rmi_input_mapping,
.input_configured = rmi_input_configured,
diff --git a/drivers/hid/hid-saitek.c b/drivers/hid/hid-saitek.c
index 5632c54eadf0..a014f21275d8 100644
--- a/drivers/hid/hid-saitek.c
+++ b/drivers/hid/hid-saitek.c
@@ -177,6 +177,8 @@ static int saitek_event(struct hid_device *hdev, struct hid_field *field,
static const struct hid_device_id saitek_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000),
.driver_data = SAITEK_FIX_PS1000 },
+ { HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7_OLD),
+ .driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_RAT7),
.driver_data = SAITEK_RELEASE_MODE_RAT7 },
{ HID_USB_DEVICE(USB_VENDOR_ID_MADCATZ, USB_DEVICE_ID_MADCATZ_RAT9),
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index 6a58b6c723aa..e54ce1097e2c 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -135,8 +135,9 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
{
struct hid_sensor_hub_callbacks_list *callback;
struct sensor_hub_data *pdata = hid_get_drvdata(hdev);
+ unsigned long flags;
- spin_lock(&pdata->dyn_callback_lock);
+ spin_lock_irqsave(&pdata->dyn_callback_lock, flags);
list_for_each_entry(callback, &pdata->dyn_callback_list, list)
if (callback->usage_id == usage_id &&
(collection_index >=
@@ -145,10 +146,11 @@ static struct hid_sensor_hub_callbacks *sensor_hub_get_callback(
callback->hsdev->end_collection_index)) {
*priv = callback->priv;
*hsdev = callback->hsdev;
- spin_unlock(&pdata->dyn_callback_lock);
+ spin_unlock_irqrestore(&pdata->dyn_callback_lock,
+ flags);
return callback->usage_callback;
}
- spin_unlock(&pdata->dyn_callback_lock);
+ spin_unlock_irqrestore(&pdata->dyn_callback_lock, flags);
return NULL;
}
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 31e9d2561106..1896c019e302 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -804,7 +804,7 @@ union sixaxis_output_report_01 {
#define DS4_REPORT_0x81_SIZE 7
#define SIXAXIS_REPORT_0xF2_SIZE 18
-static spinlock_t sony_dev_list_lock;
+static DEFINE_SPINLOCK(sony_dev_list_lock);
static LIST_HEAD(sony_device_list);
static DEFINE_IDA(sony_device_id_allocator);
@@ -1944,6 +1944,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
return -ENOMEM;
}
+ spin_lock_init(&sc->lock);
+
sc->quirks = quirks;
hid_set_drvdata(hdev, sc);
sc->hdev = hdev;
@@ -2147,8 +2149,8 @@ static void __exit sony_exit(void)
{
dbg_hid("Sony:%s\n", __func__);
- ida_destroy(&sony_device_id_allocator);
hid_unregister_driver(&sony_driver);
+ ida_destroy(&sony_device_id_allocator);
}
module_init(sony_init);
module_exit(sony_exit);
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index d43e967e7533..36053f33d6d9 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -370,7 +370,10 @@ static int i2c_hid_hwreset(struct i2c_client *client)
static void i2c_hid_get_input(struct i2c_hid *ihid)
{
int ret, ret_size;
- int size = ihid->bufsize;
+ int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
+
+ if (size > ihid->bufsize)
+ size = ihid->bufsize;
ret = i2c_master_recv(ihid->client, ihid->inbuf, size);
if (ret != size) {
@@ -785,7 +788,7 @@ static int i2c_hid_init_irq(struct i2c_client *client)
dev_dbg(&client->dev, "Requesting IRQ: %d\n", client->irq);
ret = request_threaded_irq(client->irq, NULL, i2c_hid_irq,
- IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
client->name, ihid);
if (ret < 0) {
dev_warn(&client->dev,
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index db3cf31c6fa1..890f2914a8ff 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -2,17 +2,9 @@
# Makefile for the USB input drivers
#
-# Multipart objects.
usbhid-y := hid-core.o hid-quirks.o
-
-# Optional parts of multipart objects.
-
-ifeq ($(CONFIG_USB_HIDDEV),y)
- usbhid-y += hiddev.o
-endif
-ifeq ($(CONFIG_HID_PID),y)
- usbhid-y += hid-pidff.o
-endif
+usbhid-$(CONFIG_USB_HIDDEV) += hiddev.o
+usbhid-$(CONFIG_HID_PID) += hid-pidff.o
obj-$(CONFIG_USB_HID) += usbhid.o
obj-$(CONFIG_USB_KBD) += usbkbd.o
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index 10b616702780..0b531c6a76a5 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -1252,6 +1252,8 @@ int hid_pidff_init(struct hid_device *hid)
pidff->hid = hid;
+ hid_device_io_start(hid);
+
pidff_find_reports(hid, HID_OUTPUT_REPORT, pidff);
pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
@@ -1315,9 +1317,13 @@ int hid_pidff_init(struct hid_device *hid)
hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_device_io_stop(hid);
+
return 0;
fail:
+ hid_device_io_stop(hid);
+
kfree(pidff);
return error;
}
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index b27b3d33ebab..9be99a67bfe2 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -80,6 +80,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_FREESCALE, USB_DEVICE_ID_FREESCALE_MX28, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MGE, USB_DEVICE_ID_MGE_UPS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3, HID_QUIRK_NO_INIT_REPORTS },
+ { USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_TYPE_COVER_3_JP, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NEXIO, USB_DEVICE_ID_NEXIO_MULTITOUCH_PTI0750, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_NOVATEK, USB_DEVICE_ID_NOVATEK_MOUSE, HID_QUIRK_NO_INIT_REPORTS },
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 654202941d30..f0568a7e6de9 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -173,10 +173,8 @@ static void wacom_usage_mapping(struct hid_device *hdev,
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_features *features = &wacom->wacom_wac.features;
- bool finger = (field->logical == HID_DG_FINGER) ||
- (field->physical == HID_DG_FINGER);
- bool pen = (field->logical == HID_DG_STYLUS) ||
- (field->physical == HID_DG_STYLUS);
+ bool finger = WACOM_FINGER_FIELD(field);
+ bool pen = WACOM_PEN_FIELD(field);
/*
* Requiring Stylus Usage will ignore boot mouse
@@ -405,6 +403,9 @@ static int wacom_query_tablet_data(struct hid_device *hdev,
else if (features->type == WACOM_24HDT || features->type == CINTIQ_HYBRID) {
return wacom_set_device_mode(hdev, 18, 3, 2);
}
+ else if (features->type == WACOM_27QHDT) {
+ return wacom_set_device_mode(hdev, 131, 3, 2);
+ }
} else if (features->device_type == BTN_TOOL_PEN) {
if (features->type <= BAMBOO_PT && features->type != WIRELESS) {
return wacom_set_device_mode(hdev, 2, 2, 2);
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index ac7447c7b82e..046351cf17f3 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -15,7 +15,6 @@
#include "wacom_wac.h"
#include "wacom.h"
#include <linux/input/mt.h>
-#include <linux/hid.h>
/* resolution for penabled devices */
#define WACOM_PL_RES 20
@@ -444,9 +443,6 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
/* Enter report */
if ((data[1] & 0xfc) == 0xc0) {
- if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
- wacom->shared->stylus_in_proximity = true;
-
/* serial number of the tool */
wacom->serial[idx] = ((data[3] & 0x0f) << 28) +
(data[4] << 20) + (data[5] << 12) +
@@ -535,24 +531,46 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
return 1;
}
+ /*
+ * don't report events for invalid data
+ */
/* older I4 styli don't work with new Cintiqs */
- if (!((wacom->id[idx] >> 20) & 0x01) &&
- (features->type == WACOM_21UX2))
+ if ((!((wacom->id[idx] >> 20) & 0x01) &&
+ (features->type == WACOM_21UX2)) ||
+ /* Only large Intuos support Lense Cursor */
+ (wacom->tool[idx] == BTN_TOOL_LENS &&
+ (features->type == INTUOS3 ||
+ features->type == INTUOS3S ||
+ features->type == INTUOS4 ||
+ features->type == INTUOS4S ||
+ features->type == INTUOS5 ||
+ features->type == INTUOS5S ||
+ features->type == INTUOSPM ||
+ features->type == INTUOSPS)) ||
+ /* Cintiq doesn't send data when RDY bit isn't set */
+ (features->type == CINTIQ && !(data[1] & 0x40)))
return 1;
- /* Range Report */
- if ((data[1] & 0xfe) == 0x20) {
+ if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
+ wacom->shared->stylus_in_proximity = true;
+
+ /* in Range while exiting */
+ if (((data[1] & 0xfe) == 0x20) && wacom->reporting_data) {
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_report_abs(input, ABS_DISTANCE, wacom->features.distance_max);
- if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
- wacom->shared->stylus_in_proximity = true;
+ return 2;
}
/* Exit report */
if ((data[1] & 0xfe) == 0x80) {
if (features->quirks & WACOM_QUIRK_MULTI_INPUT)
wacom->shared->stylus_in_proximity = false;
+ wacom->reporting_data = false;
+
+ /* don't report exit if we don't know the ID */
+ if (!wacom->id[idx])
+ return 1;
/*
* Reset all states otherwise we lose the initial states
@@ -586,6 +604,11 @@ static int wacom_intuos_inout(struct wacom_wac *wacom)
wacom->id[idx] = 0;
return 2;
}
+
+ /* don't report other events if we don't know the ID */
+ if (!wacom->id[idx])
+ return 1;
+
return 0;
}
@@ -633,6 +656,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
data[0] != WACOM_REPORT_INTUOSREAD &&
data[0] != WACOM_REPORT_INTUOSWRITE &&
data[0] != WACOM_REPORT_INTUOSPAD &&
+ data[0] != WACOM_REPORT_CINTIQ &&
+ data[0] != WACOM_REPORT_CINTIQPAD &&
data[0] != WACOM_REPORT_INTUOS5PAD) {
dev_dbg(input->dev.parent,
"%s: received unknown report #%d\n", __func__, data[0]);
@@ -644,7 +669,8 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
idx = data[1] & 0x01;
/* pad packets. Works as a second tool and is always in prox */
- if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD) {
+ if (data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
+ data[0] == WACOM_REPORT_CINTIQPAD) {
input = wacom->pad_input;
if (features->type >= INTUOS4S && features->type <= INTUOS4L) {
input_report_key(input, BTN_0, (data[2] & 0x01));
@@ -744,6 +770,19 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
} else {
input_report_abs(input, ABS_MISC, 0);
}
+ } else if (features->type == WACOM_27QHD) {
+ input_report_key(input, KEY_PROG1, data[2] & 0x01);
+ input_report_key(input, KEY_PROG2, data[2] & 0x02);
+ input_report_key(input, KEY_PROG3, data[2] & 0x04);
+
+ input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
+ input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
+ input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
+ if ((data[2] & 0x07) | data[4] | data[5] | data[6] | data[7] | data[8] | data[9]) {
+ input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+ } else {
+ input_report_abs(input, ABS_MISC, 0);
+ }
} else if (features->type == CINTIQ_HYBRID) {
/*
* Do not send hardware buttons under Android. They
@@ -760,6 +799,12 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_key(input, BTN_7, (data[4] & 0x40)); /* Left */
input_report_key(input, BTN_8, (data[4] & 0x80)); /* Down */
input_report_key(input, BTN_0, (data[3] & 0x01)); /* Center */
+
+ if (data[4] | (data[3] & 0x01)) {
+ input_report_abs(input, ABS_MISC, PAD_DEVICE_ID);
+ } else {
+ input_report_abs(input, ABS_MISC, 0);
+ }
} else if (features->type >= INTUOS5S && features->type <= INTUOSPL) {
int i;
@@ -843,28 +888,6 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
if (result)
return result - 1;
- /* don't proceed if we don't know the ID */
- if (!wacom->id[idx])
- return 0;
-
- /* Only large Intuos support Lense Cursor */
- if (wacom->tool[idx] == BTN_TOOL_LENS &&
- (features->type == INTUOS3 ||
- features->type == INTUOS3S ||
- features->type == INTUOS4 ||
- features->type == INTUOS4S ||
- features->type == INTUOS5 ||
- features->type == INTUOS5S ||
- features->type == INTUOSPM ||
- features->type == INTUOSPS)) {
-
- return 0;
- }
-
- /* Cintiq doesn't send data when RDY bit isn't set */
- if (features->type == CINTIQ && !(data[1] & 0x40))
- return 0;
-
if (features->type >= INTUOS3S) {
input_report_abs(input, ABS_X, (data[2] << 9) | (data[3] << 1) | ((data[9] >> 1) & 1));
input_report_abs(input, ABS_Y, (data[4] << 9) | (data[5] << 1) | (data[9] & 1));
@@ -951,6 +974,7 @@ static int wacom_intuos_irq(struct wacom_wac *wacom)
input_report_abs(input, ABS_MISC, wacom->id[idx]); /* report tool id */
input_report_key(input, wacom->tool[idx], 1);
input_event(input, EV_MSC, MSC_SERIAL, wacom->serial[idx]);
+ wacom->reporting_data = true;
return 1;
}
@@ -1019,8 +1043,20 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
int i;
- int current_num_contacts = data[61];
+ int current_num_contacts = 0;
int contacts_to_send = 0;
+ int num_contacts_left = 4; /* maximum contacts per packet */
+ int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
+ int y_offset = 2;
+
+ if (wacom->features.type == WACOM_27QHDT) {
+ current_num_contacts = data[63];
+ num_contacts_left = 10;
+ byte_per_packet = WACOM_BYTES_PER_QHDTHID_PACKET;
+ y_offset = 0;
+ } else {
+ current_num_contacts = data[61];
+ }
/*
* First packet resets the counter since only the first
@@ -1029,12 +1065,11 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
if (current_num_contacts)
wacom->num_contacts_left = current_num_contacts;
- /* There are at most 4 contacts per packet */
- contacts_to_send = min(4, wacom->num_contacts_left);
+ contacts_to_send = min(num_contacts_left, wacom->num_contacts_left);
for (i = 0; i < contacts_to_send; i++) {
- int offset = (WACOM_BYTES_PER_24HDT_PACKET * i) + 1;
- bool touch = data[offset] & 0x1 && !wacom->shared->stylus_in_proximity;
+ int offset = (byte_per_packet * i) + 1;
+ bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
int slot = input_mt_get_slot_by_key(input, data[offset + 1]);
if (slot < 0)
@@ -1044,18 +1079,23 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
if (touch) {
int t_x = get_unaligned_le16(&data[offset + 2]);
- int c_x = get_unaligned_le16(&data[offset + 4]);
- int t_y = get_unaligned_le16(&data[offset + 6]);
- int c_y = get_unaligned_le16(&data[offset + 8]);
- int w = get_unaligned_le16(&data[offset + 10]);
- int h = get_unaligned_le16(&data[offset + 12]);
+ int t_y = get_unaligned_le16(&data[offset + 4 + y_offset]);
input_report_abs(input, ABS_MT_POSITION_X, t_x);
input_report_abs(input, ABS_MT_POSITION_Y, t_y);
- input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
- input_report_abs(input, ABS_MT_WIDTH_MAJOR, min(w, h) + int_dist(t_x, t_y, c_x, c_y));
- input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
- input_report_abs(input, ABS_MT_ORIENTATION, w > h);
+
+ if (wacom->features.type != WACOM_27QHDT) {
+ int c_x = get_unaligned_le16(&data[offset + 4]);
+ int c_y = get_unaligned_le16(&data[offset + 8]);
+ int w = get_unaligned_le16(&data[offset + 10]);
+ int h = get_unaligned_le16(&data[offset + 12]);
+
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR, min(w,h));
+ input_report_abs(input, ABS_MT_WIDTH_MAJOR,
+ min(w, h) + int_dist(t_x, t_y, c_x, c_y));
+ input_report_abs(input, ABS_MT_WIDTH_MINOR, min(w, h));
+ input_report_abs(input, ABS_MT_ORIENTATION, w > h);
+ }
}
}
input_mt_report_pointer_emulation(input, true);
@@ -1064,6 +1104,7 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
if (wacom->num_contacts_left <= 0)
wacom->num_contacts_left = 0;
+ wacom->shared->touch_down = (wacom->num_contacts_left > 0);
return 1;
}
@@ -1092,7 +1133,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
for (i = 0; i < contacts_to_send; i++) {
int offset = (WACOM_BYTES_PER_MT_PACKET + x_offset) * i + 3;
- bool touch = data[offset] & 0x1;
+ bool touch = (data[offset] & 0x1) && !wacom->shared->stylus_in_proximity;
int id = get_unaligned_le16(&data[offset + 1]);
int slot = input_mt_get_slot_by_key(input, id);
@@ -1114,6 +1155,7 @@ static int wacom_mt_touch(struct wacom_wac *wacom)
if (wacom->num_contacts_left < 0)
wacom->num_contacts_left = 0;
+ wacom->shared->touch_down = (wacom->num_contacts_left > 0);
return 1;
}
@@ -1514,13 +1556,6 @@ static void wacom_wac_finger_report(struct hid_device *hdev,
wacom_wac->shared->touch_down = wacom_wac_finger_count_touches(hdev);
}
-#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
- ((f)->physical == HID_DG_STYLUS) || \
- ((f)->application == HID_DG_PEN))
-#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \
- ((f)->physical == HID_DG_FINGER) || \
- ((f)->application == HID_DG_TOUCHSCREEN))
-
void wacom_wac_usage_mapping(struct hid_device *hdev,
struct hid_field *field, struct hid_usage *usage)
{
@@ -1891,6 +1926,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
case WACOM_21UX2:
case WACOM_22HD:
case WACOM_24HD:
+ case WACOM_27QHD:
case DTK:
case CINTIQ_HYBRID:
sync = wacom_intuos_irq(wacom_wac);
@@ -1901,6 +1937,7 @@ void wacom_wac_irq(struct wacom_wac *wacom_wac, size_t len)
break;
case WACOM_24HDT:
+ case WACOM_27QHDT:
sync = wacom_24hdt_irq(wacom_wac);
break;
@@ -2086,32 +2123,17 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
wacom_abs_set_axis(input_dev, wacom_wac);
switch (features->type) {
- case WACOM_MO:
- case WACOM_G4:
- /* fall through */
-
- case GRAPHIRE:
- input_set_capability(input_dev, EV_REL, REL_WHEEL);
-
- __set_bit(BTN_LEFT, input_dev->keybit);
- __set_bit(BTN_RIGHT, input_dev->keybit);
- __set_bit(BTN_MIDDLE, input_dev->keybit);
-
- __set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
- __set_bit(BTN_TOOL_PEN, input_dev->keybit);
- __set_bit(BTN_TOOL_MOUSE, input_dev->keybit);
- __set_bit(BTN_STYLUS, input_dev->keybit);
- __set_bit(BTN_STYLUS2, input_dev->keybit);
-
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
- break;
-
case GRAPHIRE_BT:
__clear_bit(ABS_MISC, input_dev->absbit);
+
+ case WACOM_MO:
+ case WACOM_G4:
input_set_abs_params(input_dev, ABS_DISTANCE, 0,
features->distance_max,
0, 0);
+ /* fall through */
+ case GRAPHIRE:
input_set_capability(input_dev, EV_REL, REL_WHEEL);
__set_bit(BTN_LEFT, input_dev->keybit);
@@ -2127,31 +2149,15 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
__set_bit(INPUT_PROP_POINTER, input_dev->propbit);
break;
+ case WACOM_27QHD:
case WACOM_24HD:
- input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
- input_abs_set_res(input_dev, ABS_Z, 287);
- input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
- /* fall through */
-
case DTK:
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-
- wacom_setup_cintiq(wacom_wac);
- break;
-
case WACOM_22HD:
case WACOM_21UX2:
case WACOM_BEE:
case CINTIQ:
- input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
- input_abs_set_res(input_dev, ABS_Z, 287);
-
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-
- wacom_setup_cintiq(wacom_wac);
- break;
-
case WACOM_13HD:
+ case CINTIQ_HYBRID:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
input_abs_set_res(input_dev, ABS_Z, 287);
__set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
@@ -2161,6 +2167,10 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
case INTUOS3:
case INTUOS3L:
case INTUOS3S:
+ case INTUOS4:
+ case INTUOS4WL:
+ case INTUOS4L:
+ case INTUOS4S:
input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
input_abs_set_res(input_dev, ABS_Z, 287);
/* fall through */
@@ -2199,17 +2209,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
}
break;
- case INTUOS4:
- case INTUOS4WL:
- case INTUOS4L:
- case INTUOS4S:
- input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
- input_abs_set_res(input_dev, ABS_Z, 287);
- wacom_setup_intuos(wacom_wac);
-
- __set_bit(INPUT_PROP_POINTER, input_dev->propbit);
- break;
-
case WACOM_24HDT:
if (features->device_type == BTN_TOOL_FINGER) {
input_set_abs_params(input_dev, ABS_MT_TOUCH_MAJOR, 0, features->x_max, 0, 0);
@@ -2219,6 +2218,7 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
}
/* fall through */
+ case WACOM_27QHDT:
case MTSCREEN:
case MTTPC:
case MTTPC_B:
@@ -2305,14 +2305,6 @@ int wacom_setup_pentouch_input_capabilities(struct input_dev *input_dev,
0, 0);
}
break;
-
- case CINTIQ_HYBRID:
- input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0);
- input_abs_set_res(input_dev, ABS_Z, 287);
- __set_bit(INPUT_PROP_DIRECT, input_dev->propbit);
-
- wacom_setup_cintiq(wacom_wac);
- break;
}
return 0;
}
@@ -2374,6 +2366,19 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
break;
+ case WACOM_27QHD:
+ __set_bit(KEY_PROG1, input_dev->keybit);
+ __set_bit(KEY_PROG2, input_dev->keybit);
+ __set_bit(KEY_PROG3, input_dev->keybit);
+ input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0);
+ input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
+ input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0);
+ input_abs_set_res(input_dev, ABS_Y, 1024);
+ input_set_abs_params(input_dev, ABS_Z, -2048, 2048, 0, 0);
+ input_abs_set_res(input_dev, ABS_Z, 1024);
+ __set_bit(INPUT_PROP_ACCELEROMETER, input_dev->propbit);
+ break;
+
case DTK:
for (i = 0; i < 6; i++)
__set_bit(BTN_0 + i, input_dev->keybit);
@@ -2724,6 +2729,18 @@ static const struct wacom_features wacom_features_0xF6 =
{ "Wacom Cintiq 24HD touch", .type = WACOM_24HDT, /* Touch */
.oVid = USB_VENDOR_ID_WACOM, .oPid = 0xf8, .touch_max = 10,
.check_for_hid_type = true, .hid_type = HID_TYPE_USBNONE };
+static const struct wacom_features wacom_features_0x32A =
+ { "Wacom Cintiq 27QHD", 119740, 67520, 2047, 63,
+ WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET };
+static const struct wacom_features wacom_features_0x32B =
+ { "Wacom Cintiq 27QHD touch", 119740, 67520, 2047, 63,
+ WACOM_27QHD, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES,
+ WACOM_CINTIQ_OFFSET, WACOM_CINTIQ_OFFSET,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32C };
+static const struct wacom_features wacom_features_0x32C =
+ { "Wacom Cintiq 27QHD touch", .type = WACOM_27QHDT,
+ .oVid = USB_VENDOR_ID_WACOM, .oPid = 0x32B, .touch_max = 10 };
static const struct wacom_features wacom_features_0x3F =
{ "Wacom Cintiq 21UX", 87200, 65600, 1023, 63,
CINTIQ, WACOM_INTUOS3_RES, WACOM_INTUOS3_RES };
@@ -3090,6 +3107,9 @@ const struct hid_device_id wacom_ids[] = {
{ USB_DEVICE_WACOM(0x315) },
{ USB_DEVICE_WACOM(0x317) },
{ USB_DEVICE_WACOM(0x323) },
+ { USB_DEVICE_WACOM(0x32A) },
+ { USB_DEVICE_WACOM(0x32B) },
+ { USB_DEVICE_WACOM(0x32C) },
{ USB_DEVICE_WACOM(0x32F) },
{ USB_DEVICE_WACOM(0x4001) },
{ USB_DEVICE_WACOM(0x4004) },
diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h
index bfad815cda8a..021ee1c1980a 100644
--- a/drivers/hid/wacom_wac.h
+++ b/drivers/hid/wacom_wac.h
@@ -10,9 +10,10 @@
#define WACOM_WAC_H
#include <linux/types.h>
+#include <linux/hid.h>
/* maximum packet length for USB devices */
-#define WACOM_PKGLEN_MAX 68
+#define WACOM_PKGLEN_MAX 192
#define WACOM_NAME_MAX 64
@@ -36,6 +37,7 @@
/* wacom data size per MT contact */
#define WACOM_BYTES_PER_MT_PACKET 11
#define WACOM_BYTES_PER_24HDT_PACKET 14
+#define WACOM_BYTES_PER_QHDTHID_PACKET 6
/* device IDs */
#define STYLUS_DEVICE_ID 0x02
@@ -57,6 +59,8 @@
#define WACOM_REPORT_TPCMT 13
#define WACOM_REPORT_TPCMT2 3
#define WACOM_REPORT_TPCHID 15
+#define WACOM_REPORT_CINTIQ 16
+#define WACOM_REPORT_CINTIQPAD 17
#define WACOM_REPORT_TPCST 16
#define WACOM_REPORT_DTUS 17
#define WACOM_REPORT_TPC1FGE 18
@@ -71,6 +75,14 @@
#define WACOM_QUIRK_MONITOR 0x0008
#define WACOM_QUIRK_BATTERY 0x0010
+#define WACOM_PEN_FIELD(f) (((f)->logical == HID_DG_STYLUS) || \
+ ((f)->physical == HID_DG_STYLUS) || \
+ ((f)->physical == HID_DG_PEN) || \
+ ((f)->application == HID_DG_PEN))
+#define WACOM_FINGER_FIELD(f) (((f)->logical == HID_DG_FINGER) || \
+ ((f)->physical == HID_DG_FINGER) || \
+ ((f)->application == HID_DG_TOUCHSCREEN))
+
enum {
PENPARTNER = 0,
GRAPHIRE,
@@ -100,6 +112,7 @@ enum {
WACOM_22HD,
DTK,
WACOM_24HD,
+ WACOM_27QHD,
CINTIQ_HYBRID,
CINTIQ,
WACOM_BEE,
@@ -108,6 +121,7 @@ enum {
WIRELESS,
BAMBOO_PT,
WACOM_24HDT,
+ WACOM_27QHDT,
TABLETPC, /* add new TPC below */
TABLETPCE,
TABLETPC2FG,
@@ -180,6 +194,7 @@ struct wacom_wac {
int tool[2];
int id[2];
__u32 serial[2];
+ bool reporting_data;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
diff --git a/drivers/hsi/clients/nokia-modem.c b/drivers/hsi/clients/nokia-modem.c
index f0c21458962c..eb4dc63dbc93 100644
--- a/drivers/hsi/clients/nokia-modem.c
+++ b/drivers/hsi/clients/nokia-modem.c
@@ -162,6 +162,7 @@ static int nokia_modem_probe(struct device *dev)
return -ENOMEM;
}
dev_set_drvdata(dev, modem);
+ modem->device = dev;
irq = irq_of_parse_and_map(np, 0);
if (!irq) {
diff --git a/drivers/hv/channel.c b/drivers/hv/channel.c
index 433f72a1c006..2978f5ee8d2a 100644
--- a/drivers/hv/channel.c
+++ b/drivers/hv/channel.c
@@ -73,14 +73,14 @@ int vmbus_open(struct vmbus_channel *newchannel, u32 send_ringbuffer_size,
unsigned long flags;
int ret, t, err = 0;
- spin_lock_irqsave(&newchannel->sc_lock, flags);
+ spin_lock_irqsave(&newchannel->lock, flags);
if (newchannel->state == CHANNEL_OPEN_STATE) {
newchannel->state = CHANNEL_OPENING_STATE;
} else {
- spin_unlock_irqrestore(&newchannel->sc_lock, flags);
+ spin_unlock_irqrestore(&newchannel->lock, flags);
return -EINVAL;
}
- spin_unlock_irqrestore(&newchannel->sc_lock, flags);
+ spin_unlock_irqrestore(&newchannel->lock, flags);
newchannel->onchannel_callback = onchannelcallback;
newchannel->channel_callback_context = context;
@@ -366,8 +366,8 @@ int vmbus_establish_gpadl(struct vmbus_channel *channel, void *kbuffer,
unsigned long flags;
int ret = 0;
- next_gpadl_handle = atomic_read(&vmbus_connection.next_gpadl_handle);
- atomic_inc(&vmbus_connection.next_gpadl_handle);
+ next_gpadl_handle =
+ (atomic_inc_return(&vmbus_connection.next_gpadl_handle) - 1);
ret = create_gpadl_header(kbuffer, size, &msginfo, &msgcount);
if (ret)
@@ -686,6 +686,50 @@ EXPORT_SYMBOL_GPL(vmbus_sendpacket_pagebuffer);
/*
* vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
* using a GPADL Direct packet type.
+ * The buffer includes the vmbus descriptor.
+ */
+int vmbus_sendpacket_mpb_desc(struct vmbus_channel *channel,
+ struct vmbus_packet_mpb_array *desc,
+ u32 desc_size,
+ void *buffer, u32 bufferlen, u64 requestid)
+{
+ int ret;
+ u32 packetlen;
+ u32 packetlen_aligned;
+ struct kvec bufferlist[3];
+ u64 aligned_data = 0;
+ bool signal = false;
+
+ packetlen = desc_size + bufferlen;
+ packetlen_aligned = ALIGN(packetlen, sizeof(u64));
+
+ /* Setup the descriptor */
+ desc->type = VM_PKT_DATA_USING_GPA_DIRECT;
+ desc->flags = VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED;
+ desc->dataoffset8 = desc_size >> 3; /* in 8-bytes grandularity */
+ desc->length8 = (u16)(packetlen_aligned >> 3);
+ desc->transactionid = requestid;
+ desc->rangecount = 1;
+
+ bufferlist[0].iov_base = desc;
+ bufferlist[0].iov_len = desc_size;
+ bufferlist[1].iov_base = buffer;
+ bufferlist[1].iov_len = bufferlen;
+ bufferlist[2].iov_base = &aligned_data;
+ bufferlist[2].iov_len = (packetlen_aligned - packetlen);
+
+ ret = hv_ringbuffer_write(&channel->outbound, bufferlist, 3, &signal);
+
+ if (ret == 0 && signal)
+ vmbus_setevent(channel);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(vmbus_sendpacket_mpb_desc);
+
+/*
+ * vmbus_sendpacket_multipagebuffer - Send a multi-page buffer packet
+ * using a GPADL Direct packet type.
*/
int vmbus_sendpacket_multipagebuffer(struct vmbus_channel *channel,
struct hv_multipage_buffer *multi_pagebuffer,
diff --git a/drivers/hv/channel_mgmt.c b/drivers/hv/channel_mgmt.c
index 2c59f030546b..3736f71bdec5 100644
--- a/drivers/hv/channel_mgmt.c
+++ b/drivers/hv/channel_mgmt.c
@@ -146,7 +146,7 @@ static struct vmbus_channel *alloc_channel(void)
return NULL;
spin_lock_init(&channel->inbound_lock);
- spin_lock_init(&channel->sc_lock);
+ spin_lock_init(&channel->lock);
INIT_LIST_HEAD(&channel->sc_list);
INIT_LIST_HEAD(&channel->percpu_list);
@@ -246,9 +246,9 @@ static void vmbus_process_rescind_offer(struct work_struct *work)
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
} else {
primary_channel = channel->primary_channel;
- spin_lock_irqsave(&primary_channel->sc_lock, flags);
+ spin_lock_irqsave(&primary_channel->lock, flags);
list_del(&channel->sc_list);
- spin_unlock_irqrestore(&primary_channel->sc_lock, flags);
+ spin_unlock_irqrestore(&primary_channel->lock, flags);
}
free_channel(channel);
}
@@ -279,9 +279,6 @@ static void vmbus_process_offer(struct work_struct *work)
int ret;
unsigned long flags;
- /* The next possible work is rescind handling */
- INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
-
/* Make sure this is a new offer */
spin_lock_irqsave(&vmbus_connection.channel_lock, flags);
@@ -323,9 +320,9 @@ static void vmbus_process_offer(struct work_struct *work)
* Process the sub-channel.
*/
newchannel->primary_channel = channel;
- spin_lock_irqsave(&channel->sc_lock, flags);
+ spin_lock_irqsave(&channel->lock, flags);
list_add_tail(&newchannel->sc_list, &channel->sc_list);
- spin_unlock_irqrestore(&channel->sc_lock, flags);
+ spin_unlock_irqrestore(&channel->lock, flags);
if (newchannel->target_cpu != get_cpu()) {
put_cpu();
@@ -341,11 +338,10 @@ static void vmbus_process_offer(struct work_struct *work)
if (channel->sc_creation_callback != NULL)
channel->sc_creation_callback(newchannel);
- return;
+ goto done_init_rescind;
}
- free_channel(newchannel);
- return;
+ goto err_free_chan;
}
/*
@@ -364,6 +360,8 @@ static void vmbus_process_offer(struct work_struct *work)
&newchannel->offermsg.offer.if_type,
&newchannel->offermsg.offer.if_instance,
newchannel);
+ if (!newchannel->device_obj)
+ goto err_free_chan;
/*
* Add the new device to the bus. This will kick off device-driver
@@ -379,9 +377,19 @@ static void vmbus_process_offer(struct work_struct *work)
list_del(&newchannel->listentry);
spin_unlock_irqrestore(&vmbus_connection.channel_lock, flags);
kfree(newchannel->device_obj);
-
- free_channel(newchannel);
+ goto err_free_chan;
}
+done_init_rescind:
+ spin_lock_irqsave(&newchannel->lock, flags);
+ /* The next possible work is rescind handling */
+ INIT_WORK(&newchannel->work, vmbus_process_rescind_offer);
+ /* Check if rescind offer was already received */
+ if (newchannel->rescind)
+ queue_work(newchannel->controlwq, &newchannel->work);
+ spin_unlock_irqrestore(&newchannel->lock, flags);
+ return;
+err_free_chan:
+ free_channel(newchannel);
}
enum {
@@ -516,6 +524,7 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
{
struct vmbus_channel_rescind_offer *rescind;
struct vmbus_channel *channel;
+ unsigned long flags;
rescind = (struct vmbus_channel_rescind_offer *)hdr;
channel = relid2channel(rescind->child_relid);
@@ -524,11 +533,20 @@ static void vmbus_onoffer_rescind(struct vmbus_channel_message_header *hdr)
/* Just return here, no channel found */
return;
+ spin_lock_irqsave(&channel->lock, flags);
channel->rescind = true;
+ /*
+ * channel->work.func != vmbus_process_rescind_offer means we are still
+ * processing offer request and the rescind offer processing should be
+ * postponed. It will be done at the very end of vmbus_process_offer()
+ * as rescind flag is being checked there.
+ */
+ if (channel->work.func == vmbus_process_rescind_offer)
+ /* work is initialized for vmbus_process_rescind_offer() from
+ * vmbus_process_offer() where the channel got created */
+ queue_work(channel->controlwq, &channel->work);
- /* work is initialized for vmbus_process_rescind_offer() from
- * vmbus_process_offer() where the channel got created */
- queue_work(channel->controlwq, &channel->work);
+ spin_unlock_irqrestore(&channel->lock, flags);
}
/*
@@ -815,7 +833,7 @@ cleanup:
struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
{
struct list_head *cur, *tmp;
- int cur_cpu = hv_context.vp_index[smp_processor_id()];
+ int cur_cpu;
struct vmbus_channel *cur_channel;
struct vmbus_channel *outgoing_channel = primary;
int cpu_distance, new_cpu_distance;
@@ -823,6 +841,8 @@ struct vmbus_channel *vmbus_get_outgoing_channel(struct vmbus_channel *primary)
if (list_empty(&primary->sc_list))
return outgoing_channel;
+ cur_cpu = hv_context.vp_index[get_cpu()];
+ put_cpu();
list_for_each_safe(cur, tmp, &primary->sc_list) {
cur_channel = list_entry(cur, struct vmbus_channel, sc_list);
if (cur_channel->state != CHANNEL_OPENED_STATE)
diff --git a/drivers/hv/connection.c b/drivers/hv/connection.c
index e206619b946e..a63a795300b9 100644
--- a/drivers/hv/connection.c
+++ b/drivers/hv/connection.c
@@ -80,8 +80,10 @@ static int vmbus_negotiate_version(struct vmbus_channel_msginfo *msginfo,
msg->interrupt_page = virt_to_phys(vmbus_connection.int_page);
msg->monitor_page1 = virt_to_phys(vmbus_connection.monitor_pages[0]);
msg->monitor_page2 = virt_to_phys(vmbus_connection.monitor_pages[1]);
- if (version == VERSION_WIN8_1)
- msg->target_vcpu = hv_context.vp_index[smp_processor_id()];
+ if (version == VERSION_WIN8_1) {
+ msg->target_vcpu = hv_context.vp_index[get_cpu()];
+ put_cpu();
+ }
/*
* Add to list before we send the request since we may
diff --git a/drivers/hv/hv.c b/drivers/hv/hv.c
index 3e4235c7a47f..50e51a51ff8b 100644
--- a/drivers/hv/hv.c
+++ b/drivers/hv/hv.c
@@ -28,7 +28,9 @@
#include <linux/hyperv.h>
#include <linux/version.h>
#include <linux/interrupt.h>
+#include <linux/clockchips.h>
#include <asm/hyperv.h>
+#include <asm/mshyperv.h>
#include "hyperv_vmbus.h"
/* The one and only */
@@ -37,6 +39,10 @@ struct hv_context hv_context = {
.hypercall_page = NULL,
};
+#define HV_TIMER_FREQUENCY (10 * 1000 * 1000) /* 100ns period */
+#define HV_MAX_MAX_DELTA_TICKS 0xffffffff
+#define HV_MIN_DELTA_TICKS 1
+
/*
* query_hypervisor_info - Get version info of the windows hypervisor
*/
@@ -144,6 +150,8 @@ int hv_init(void)
sizeof(int) * NR_CPUS);
memset(hv_context.event_dpc, 0,
sizeof(void *) * NR_CPUS);
+ memset(hv_context.clk_evt, 0,
+ sizeof(void *) * NR_CPUS);
max_leaf = query_hypervisor_info();
@@ -258,10 +266,63 @@ u16 hv_signal_event(void *con_id)
return status;
}
+static int hv_ce_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ cycle_t current_tick;
+
+ WARN_ON(evt->mode != CLOCK_EVT_MODE_ONESHOT);
+
+ rdmsrl(HV_X64_MSR_TIME_REF_COUNT, current_tick);
+ current_tick += delta;
+ wrmsrl(HV_X64_MSR_STIMER0_COUNT, current_tick);
+ return 0;
+}
+
+static void hv_ce_setmode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ union hv_timer_config timer_cfg;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* unsupported */
+ break;
+
+ case CLOCK_EVT_MODE_ONESHOT:
+ timer_cfg.enable = 1;
+ timer_cfg.auto_enable = 1;
+ timer_cfg.sintx = VMBUS_MESSAGE_SINT;
+ wrmsrl(HV_X64_MSR_STIMER0_CONFIG, timer_cfg.as_uint64);
+ break;
+
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ wrmsrl(HV_X64_MSR_STIMER0_COUNT, 0);
+ wrmsrl(HV_X64_MSR_STIMER0_CONFIG, 0);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ break;
+ }
+}
+
+static void hv_init_clockevent_device(struct clock_event_device *dev, int cpu)
+{
+ dev->name = "Hyper-V clockevent";
+ dev->features = CLOCK_EVT_FEAT_ONESHOT;
+ dev->cpumask = cpumask_of(cpu);
+ dev->rating = 1000;
+ dev->owner = THIS_MODULE;
+
+ dev->set_mode = hv_ce_setmode;
+ dev->set_next_event = hv_ce_set_next_event;
+}
+
int hv_synic_alloc(void)
{
size_t size = sizeof(struct tasklet_struct);
+ size_t ced_size = sizeof(struct clock_event_device);
int cpu;
for_each_online_cpu(cpu) {
@@ -272,6 +333,13 @@ int hv_synic_alloc(void)
}
tasklet_init(hv_context.event_dpc[cpu], vmbus_on_event, cpu);
+ hv_context.clk_evt[cpu] = kzalloc(ced_size, GFP_ATOMIC);
+ if (hv_context.clk_evt[cpu] == NULL) {
+ pr_err("Unable to allocate clock event device\n");
+ goto err;
+ }
+ hv_init_clockevent_device(hv_context.clk_evt[cpu], cpu);
+
hv_context.synic_message_page[cpu] =
(void *)get_zeroed_page(GFP_ATOMIC);
@@ -305,6 +373,7 @@ err:
static void hv_synic_free_cpu(int cpu)
{
kfree(hv_context.event_dpc[cpu]);
+ kfree(hv_context.clk_evt[cpu]);
if (hv_context.synic_event_page[cpu])
free_page((unsigned long)hv_context.synic_event_page[cpu]);
if (hv_context.synic_message_page[cpu])
@@ -388,6 +457,15 @@ void hv_synic_init(void *arg)
hv_context.vp_index[cpu] = (u32)vp_index;
INIT_LIST_HEAD(&hv_context.percpu_list[cpu]);
+
+ /*
+ * Register the per-cpu clockevent source.
+ */
+ if (ms_hyperv.features & HV_X64_MSR_SYNTIMER_AVAILABLE)
+ clockevents_config_and_register(hv_context.clk_evt[cpu],
+ HV_TIMER_FREQUENCY,
+ HV_MIN_DELTA_TICKS,
+ HV_MAX_MAX_DELTA_TICKS);
return;
}
diff --git a/drivers/hv/hv_balloon.c b/drivers/hv/hv_balloon.c
index b958ded8ac7e..ff169386b2c7 100644
--- a/drivers/hv/hv_balloon.c
+++ b/drivers/hv/hv_balloon.c
@@ -533,6 +533,9 @@ struct hv_dynmem_device {
*/
struct task_struct *thread;
+ struct mutex ha_region_mutex;
+ struct completion waiter_event;
+
/*
* A list of hot-add regions.
*/
@@ -549,7 +552,59 @@ struct hv_dynmem_device {
static struct hv_dynmem_device dm_device;
static void post_status(struct hv_dynmem_device *dm);
+
#ifdef CONFIG_MEMORY_HOTPLUG
+static void acquire_region_mutex(bool trylock)
+{
+ if (trylock) {
+ reinit_completion(&dm_device.waiter_event);
+ while (!mutex_trylock(&dm_device.ha_region_mutex))
+ wait_for_completion(&dm_device.waiter_event);
+ } else {
+ mutex_lock(&dm_device.ha_region_mutex);
+ }
+}
+
+static void release_region_mutex(bool trylock)
+{
+ if (trylock) {
+ mutex_unlock(&dm_device.ha_region_mutex);
+ } else {
+ mutex_unlock(&dm_device.ha_region_mutex);
+ complete(&dm_device.waiter_event);
+ }
+}
+
+static int hv_memory_notifier(struct notifier_block *nb, unsigned long val,
+ void *v)
+{
+ switch (val) {
+ case MEM_GOING_ONLINE:
+ acquire_region_mutex(true);
+ break;
+
+ case MEM_ONLINE:
+ case MEM_CANCEL_ONLINE:
+ release_region_mutex(true);
+ if (dm_device.ha_waiting) {
+ dm_device.ha_waiting = false;
+ complete(&dm_device.ol_waitevent);
+ }
+ break;
+
+ case MEM_GOING_OFFLINE:
+ case MEM_OFFLINE:
+ case MEM_CANCEL_OFFLINE:
+ break;
+ }
+ return NOTIFY_OK;
+}
+
+static struct notifier_block hv_memory_nb = {
+ .notifier_call = hv_memory_notifier,
+ .priority = 0
+};
+
static void hv_bring_pgs_online(unsigned long start_pfn, unsigned long size)
{
@@ -591,6 +646,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
init_completion(&dm_device.ol_waitevent);
dm_device.ha_waiting = true;
+ release_region_mutex(false);
nid = memory_add_physaddr_to_nid(PFN_PHYS(start_pfn));
ret = add_memory(nid, PFN_PHYS((start_pfn)),
(HA_CHUNK << PAGE_SHIFT));
@@ -619,6 +675,7 @@ static void hv_mem_hot_add(unsigned long start, unsigned long size,
* have not been "onlined" within the allowed time.
*/
wait_for_completion_timeout(&dm_device.ol_waitevent, 5*HZ);
+ acquire_region_mutex(false);
post_status(&dm_device);
}
@@ -632,11 +689,6 @@ static void hv_online_page(struct page *pg)
unsigned long cur_start_pgp;
unsigned long cur_end_pgp;
- if (dm_device.ha_waiting) {
- dm_device.ha_waiting = false;
- complete(&dm_device.ol_waitevent);
- }
-
list_for_each(cur, &dm_device.ha_region_list) {
has = list_entry(cur, struct hv_hotadd_state, list);
cur_start_pgp = (unsigned long)
@@ -834,6 +886,7 @@ static void hot_add_req(struct work_struct *dummy)
resp.hdr.size = sizeof(struct dm_hot_add_response);
#ifdef CONFIG_MEMORY_HOTPLUG
+ acquire_region_mutex(false);
pg_start = dm->ha_wrk.ha_page_range.finfo.start_page;
pfn_cnt = dm->ha_wrk.ha_page_range.finfo.page_cnt;
@@ -865,6 +918,7 @@ static void hot_add_req(struct work_struct *dummy)
if (do_hot_add)
resp.page_count = process_hot_add(pg_start, pfn_cnt,
rg_start, rg_sz);
+ release_region_mutex(false);
#endif
/*
* The result field of the response structure has the
@@ -928,9 +982,8 @@ static unsigned long compute_balloon_floor(void)
* 128 72 (1/2)
* 512 168 (1/4)
* 2048 360 (1/8)
- * 8192 552 (1/32)
- * 32768 1320
- * 131072 4392
+ * 8192 768 (1/16)
+ * 32768 1536 (1/32)
*/
if (totalram_pages < MB2PAGES(128))
min_pages = MB2PAGES(8) + (totalram_pages >> 1);
@@ -938,8 +991,10 @@ static unsigned long compute_balloon_floor(void)
min_pages = MB2PAGES(40) + (totalram_pages >> 2);
else if (totalram_pages < MB2PAGES(2048))
min_pages = MB2PAGES(104) + (totalram_pages >> 3);
+ else if (totalram_pages < MB2PAGES(8192))
+ min_pages = MB2PAGES(256) + (totalram_pages >> 4);
else
- min_pages = MB2PAGES(296) + (totalram_pages >> 5);
+ min_pages = MB2PAGES(512) + (totalram_pages >> 5);
#undef MB2PAGES
return min_pages;
}
@@ -1171,7 +1226,7 @@ static void balloon_down(struct hv_dynmem_device *dm,
for (i = 0; i < range_count; i++) {
free_balloon_pages(dm, &range_array[i]);
- post_status(&dm_device);
+ complete(&dm_device.config_event);
}
if (req->more_pages == 1)
@@ -1195,19 +1250,16 @@ static void balloon_onchannelcallback(void *context);
static int dm_thread_func(void *dm_dev)
{
struct hv_dynmem_device *dm = dm_dev;
- int t;
while (!kthread_should_stop()) {
- t = wait_for_completion_interruptible_timeout(
+ wait_for_completion_interruptible_timeout(
&dm_device.config_event, 1*HZ);
/*
* The host expects us to post information on the memory
* pressure every second.
*/
-
- if (t == 0)
- post_status(dm);
-
+ reinit_completion(&dm_device.config_event);
+ post_status(dm);
}
return 0;
@@ -1387,7 +1439,9 @@ static int balloon_probe(struct hv_device *dev,
dm_device.next_version = DYNMEM_PROTOCOL_VERSION_WIN7;
init_completion(&dm_device.host_event);
init_completion(&dm_device.config_event);
+ init_completion(&dm_device.waiter_event);
INIT_LIST_HEAD(&dm_device.ha_region_list);
+ mutex_init(&dm_device.ha_region_mutex);
INIT_WORK(&dm_device.balloon_wrk.wrk, balloon_up);
INIT_WORK(&dm_device.ha_wrk.wrk, hot_add_req);
dm_device.host_specified_ha_region = false;
@@ -1401,6 +1455,7 @@ static int balloon_probe(struct hv_device *dev,
#ifdef CONFIG_MEMORY_HOTPLUG
set_online_page_callback(&hv_online_page);
+ register_memory_notifier(&hv_memory_nb);
#endif
hv_set_drvdata(dev, &dm_device);
@@ -1519,6 +1574,7 @@ static int balloon_remove(struct hv_device *dev)
kfree(send_buffer);
#ifdef CONFIG_MEMORY_HOTPLUG
restore_online_page_callback(&hv_online_page);
+ unregister_memory_notifier(&hv_memory_nb);
#endif
list_for_each_safe(cur, tmp, &dm->ha_region_list) {
has = list_entry(cur, struct hv_hotadd_state, list);
diff --git a/drivers/hv/hv_fcopy.c b/drivers/hv/hv_fcopy.c
index 23b2ce294c4c..cd453e4b2a07 100644
--- a/drivers/hv/hv_fcopy.c
+++ b/drivers/hv/hv_fcopy.c
@@ -86,6 +86,18 @@ static void fcopy_work_func(struct work_struct *dummy)
* process the pending transaction.
*/
fcopy_respond_to_host(HV_E_FAIL);
+
+ /* In the case the user-space daemon crashes, hangs or is killed, we
+ * need to down the semaphore, otherwise, after the daemon starts next
+ * time, the obsolete data in fcopy_transaction.message or
+ * fcopy_transaction.fcopy_msg will be used immediately.
+ *
+ * NOTE: fcopy_read() happens to get the semaphore (very rare)? We're
+ * still OK, because we've reported the failure to the host.
+ */
+ if (down_trylock(&fcopy_transaction.read_sema))
+ ;
+
}
static int fcopy_handle_handshake(u32 version)
@@ -344,6 +356,14 @@ static int fcopy_open(struct inode *inode, struct file *f)
return 0;
}
+/* XXX: there are still some tricky corner cases, e.g.,
+ * 1) In a SMP guest, when fcopy_release() runs between
+ * schedule_delayed_work() and fcopy_send_data(), there is
+ * still a chance an obsolete message will be queued.
+ *
+ * 2) When the fcopy daemon is running, if we unload the driver,
+ * we'll notice a kernel oops when we kill the daemon later.
+ */
static int fcopy_release(struct inode *inode, struct file *f)
{
/*
@@ -351,6 +371,13 @@ static int fcopy_release(struct inode *inode, struct file *f)
*/
in_hand_shake = true;
opened = false;
+
+ if (cancel_delayed_work_sync(&fcopy_work)) {
+ /* We haven't up()-ed the semaphore(very rare)? */
+ if (down_trylock(&fcopy_transaction.read_sema))
+ ;
+ fcopy_respond_to_host(HV_E_FAIL);
+ }
return 0;
}
diff --git a/drivers/hv/hyperv_vmbus.h b/drivers/hv/hyperv_vmbus.h
index c386d8dc7223..44b1c9424712 100644
--- a/drivers/hv/hyperv_vmbus.h
+++ b/drivers/hv/hyperv_vmbus.h
@@ -178,6 +178,23 @@ struct hv_message_header {
};
};
+/*
+ * Timer configuration register.
+ */
+union hv_timer_config {
+ u64 as_uint64;
+ struct {
+ u64 enable:1;
+ u64 periodic:1;
+ u64 lazy:1;
+ u64 auto_enable:1;
+ u64 reserved_z0:12;
+ u64 sintx:4;
+ u64 reserved_z1:44;
+ };
+};
+
+
/* Define timer message payload structure. */
struct hv_timer_message_payload {
u32 timer_index;
@@ -519,6 +536,10 @@ struct hv_context {
* buffer to post messages to the host.
*/
void *post_msg_page[NR_CPUS];
+ /*
+ * Support PV clockevent device.
+ */
+ struct clock_event_device *clk_evt[NR_CPUS];
};
extern struct hv_context hv_context;
diff --git a/drivers/hv/vmbus_drv.c b/drivers/hv/vmbus_drv.c
index 4d6b26979fbd..f518b8d7a5b5 100644
--- a/drivers/hv/vmbus_drv.c
+++ b/drivers/hv/vmbus_drv.c
@@ -32,6 +32,7 @@
#include <linux/completion.h>
#include <linux/hyperv.h>
#include <linux/kernel_stat.h>
+#include <linux/clockchips.h>
#include <asm/hyperv.h>
#include <asm/hypervisor.h>
#include <asm/mshyperv.h>
@@ -578,6 +579,34 @@ static void vmbus_onmessage_work(struct work_struct *work)
kfree(ctx);
}
+static void hv_process_timer_expiration(struct hv_message *msg, int cpu)
+{
+ struct clock_event_device *dev = hv_context.clk_evt[cpu];
+
+ if (dev->event_handler)
+ dev->event_handler(dev);
+
+ msg->header.message_type = HVMSG_NONE;
+
+ /*
+ * Make sure the write to MessageType (ie set to
+ * HVMSG_NONE) happens before we read the
+ * MessagePending and EOMing. Otherwise, the EOMing
+ * will not deliver any more messages since there is
+ * no empty slot
+ */
+ mb();
+
+ if (msg->header.message_flags.msg_pending) {
+ /*
+ * This will cause message queue rescan to
+ * possibly deliver another msg from the
+ * hypervisor
+ */
+ wrmsrl(HV_X64_MSR_EOM, 0);
+ }
+}
+
static void vmbus_on_msg_dpc(unsigned long data)
{
int cpu = smp_processor_id();
@@ -667,8 +696,12 @@ static void vmbus_isr(void)
msg = (struct hv_message *)page_addr + VMBUS_MESSAGE_SINT;
/* Check if there are actual msgs to be processed */
- if (msg->header.message_type != HVMSG_NONE)
- tasklet_schedule(&msg_dpc);
+ if (msg->header.message_type != HVMSG_NONE) {
+ if (msg->header.message_type == HVMSG_TIMER_EXPIRED)
+ hv_process_timer_expiration(msg, cpu);
+ else
+ tasklet_schedule(&msg_dpc);
+ }
}
/*
@@ -861,8 +894,8 @@ static acpi_status vmbus_walk_resources(struct acpi_resource *res, void *ctx)
break;
case ACPI_RESOURCE_TYPE_ADDRESS64:
- hyperv_mmio.start = res->data.address64.minimum;
- hyperv_mmio.end = res->data.address64.maximum;
+ hyperv_mmio.start = res->data.address64.address.minimum;
+ hyperv_mmio.end = res->data.address64.address.maximum;
break;
}
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index a7de26d1ac80..110fade9cb74 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1389,6 +1389,7 @@ config SENSORS_ADS1015
config SENSORS_ADS7828
tristate "Texas Instruments ADS7828 and compatibles"
depends on I2C
+ select REGMAP_I2C
help
If you say yes here you get support for Texas Instruments ADS7828 and
ADS7830 8-channel A/D converters. ADS7828 resolution is 12-bit, while
@@ -1430,8 +1431,8 @@ config SENSORS_INA2XX
tristate "Texas Instruments INA219 and compatibles"
depends on I2C
help
- If you say yes here you get support for INA219, INA220, INA226, and
- INA230 power monitor chips.
+ If you say yes here you get support for INA219, INA220, INA226,
+ INA230, and INA231 power monitor chips.
The INA2xx driver is configured for the default configuration of
the part as described in the datasheet.
@@ -1605,7 +1606,7 @@ config SENSORS_W83795
will be called w83795.
config SENSORS_W83795_FANCTRL
- boolean "Include automatic fan control support (DANGEROUS)"
+ bool "Include automatic fan control support (DANGEROUS)"
depends on SENSORS_W83795
default n
help
diff --git a/drivers/hwmon/abx500.c b/drivers/hwmon/abx500.c
index 13875968c844..6cb89c0ebab6 100644
--- a/drivers/hwmon/abx500.c
+++ b/drivers/hwmon/abx500.c
@@ -221,7 +221,7 @@ static ssize_t show_min(struct device *dev,
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- return sprintf(buf, "%ld\n", data->min[attr->index]);
+ return sprintf(buf, "%lu\n", data->min[attr->index]);
}
static ssize_t show_max(struct device *dev,
@@ -230,7 +230,7 @@ static ssize_t show_max(struct device *dev,
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- return sprintf(buf, "%ld\n", data->max[attr->index]);
+ return sprintf(buf, "%lu\n", data->max[attr->index]);
}
static ssize_t show_max_hyst(struct device *dev,
@@ -239,7 +239,7 @@ static ssize_t show_max_hyst(struct device *dev,
struct abx500_temp *data = dev_get_drvdata(dev);
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
- return sprintf(buf, "%ld\n", data->max_hyst[attr->index]);
+ return sprintf(buf, "%lu\n", data->max_hyst[attr->index]);
}
static ssize_t show_min_alarm(struct device *dev,
diff --git a/drivers/hwmon/ad7314.c b/drivers/hwmon/ad7314.c
index f4f9b219bf16..11955467fc0f 100644
--- a/drivers/hwmon/ad7314.c
+++ b/drivers/hwmon/ad7314.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
+#include <linux/bitops.h>
/*
* AD7314 temperature masks
@@ -67,7 +68,7 @@ static ssize_t ad7314_show_temperature(struct device *dev,
switch (spi_get_device_id(chip->spi_dev)->driver_data) {
case ad7314:
data = (ret & AD7314_TEMP_MASK) >> AD7314_TEMP_SHIFT;
- data = (data << 6) >> 6;
+ data = sign_extend32(data, 9);
return sprintf(buf, "%d\n", 250 * data);
case adt7301:
@@ -78,7 +79,7 @@ static ssize_t ad7314_show_temperature(struct device *dev,
* register. 1lsb - 31.25 milli degrees centigrade
*/
data = ret & ADT7301_TEMP_MASK;
- data = (data << 2) >> 2;
+ data = sign_extend32(data, 13);
return sprintf(buf, "%d\n",
DIV_ROUND_CLOSEST(data * 3125, 100));
diff --git a/drivers/hwmon/adc128d818.c b/drivers/hwmon/adc128d818.c
index 0625e50d7a6e..ad2b47e40345 100644
--- a/drivers/hwmon/adc128d818.c
+++ b/drivers/hwmon/adc128d818.c
@@ -27,6 +27,7 @@
#include <linux/err.h>
#include <linux/regulator/consumer.h>
#include <linux/mutex.h>
+#include <linux/bitops.h>
/* Addresses to scan
* The chip also supports addresses 0x35..0x37. Don't scan those addresses
@@ -189,7 +190,7 @@ static ssize_t adc128_show_temp(struct device *dev,
if (IS_ERR(data))
return PTR_ERR(data);
- temp = (data->temp[index] << 7) >> 7; /* sign extend */
+ temp = sign_extend32(data->temp[index], 8);
return sprintf(buf, "%d\n", temp * 500);/* 0.5 degrees C resolution */
}
diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c
index a622d40eec17..6c99ee7bafa3 100644
--- a/drivers/hwmon/ads7828.c
+++ b/drivers/hwmon/ads7828.c
@@ -30,14 +30,12 @@
#include <linux/hwmon-sysfs.h>
#include <linux/i2c.h>
#include <linux/init.h>
-#include <linux/jiffies.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/platform_data/ads7828.h>
+#include <linux/regmap.h>
#include <linux/slab.h>
/* The ADS7828 registers */
-#define ADS7828_NCH 8 /* 8 channels supported */
#define ADS7828_CMD_SD_SE 0x80 /* Single ended inputs */
#define ADS7828_CMD_PD1 0x04 /* Internal vref OFF && A/D ON */
#define ADS7828_CMD_PD3 0x0C /* Internal vref ON && A/D ON */
@@ -50,17 +48,9 @@ enum ads7828_chips { ads7828, ads7830 };
/* Client specific data */
struct ads7828_data {
- struct i2c_client *client;
- struct mutex update_lock; /* Mutex protecting updates */
- unsigned long last_updated; /* Last updated time (in jiffies) */
- u16 adc_input[ADS7828_NCH]; /* ADS7828_NCH samples */
- bool valid; /* Validity flag */
- bool diff_input; /* Differential input */
- bool ext_vref; /* External voltage reference */
- unsigned int vref_mv; /* voltage reference value */
+ struct regmap *regmap;
u8 cmd_byte; /* Command byte without channel bits */
unsigned int lsb_resol; /* Resolution of the ADC sample LSB */
- s32 (*read_channel)(const struct i2c_client *client, u8 command);
};
/* Command byte C2,C1,C0 - see datasheet */
@@ -69,42 +59,22 @@ static inline u8 ads7828_cmd_byte(u8 cmd, int ch)
return cmd | (((ch >> 1) | (ch & 0x01) << 2) << 4);
}
-/* Update data for the device (all 8 channels) */
-static struct ads7828_data *ads7828_update_device(struct device *dev)
-{
- struct ads7828_data *data = dev_get_drvdata(dev);
- struct i2c_client *client = data->client;
-
- mutex_lock(&data->update_lock);
-
- if (time_after(jiffies, data->last_updated + HZ + HZ / 2)
- || !data->valid) {
- unsigned int ch;
- dev_dbg(&client->dev, "Starting ads7828 update\n");
-
- for (ch = 0; ch < ADS7828_NCH; ch++) {
- u8 cmd = ads7828_cmd_byte(data->cmd_byte, ch);
- data->adc_input[ch] = data->read_channel(client, cmd);
- }
- data->last_updated = jiffies;
- data->valid = true;
- }
-
- mutex_unlock(&data->update_lock);
-
- return data;
-}
-
/* sysfs callback function */
static ssize_t ads7828_show_in(struct device *dev, struct device_attribute *da,
char *buf)
{
struct sensor_device_attribute *attr = to_sensor_dev_attr(da);
- struct ads7828_data *data = ads7828_update_device(dev);
- unsigned int value = DIV_ROUND_CLOSEST(data->adc_input[attr->index] *
- data->lsb_resol, 1000);
+ struct ads7828_data *data = dev_get_drvdata(dev);
+ u8 cmd = ads7828_cmd_byte(data->cmd_byte, attr->index);
+ unsigned int regval;
+ int err;
+
+ err = regmap_read(data->regmap, cmd, &regval);
+ if (err < 0)
+ return err;
- return sprintf(buf, "%d\n", value);
+ return sprintf(buf, "%d\n",
+ DIV_ROUND_CLOSEST(regval * data->lsb_resol, 1000));
}
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ads7828_show_in, NULL, 0);
@@ -130,6 +100,16 @@ static struct attribute *ads7828_attrs[] = {
ATTRIBUTE_GROUPS(ads7828);
+static const struct regmap_config ads2828_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 16,
+};
+
+static const struct regmap_config ads2830_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
static int ads7828_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -137,41 +117,42 @@ static int ads7828_probe(struct i2c_client *client,
struct ads7828_platform_data *pdata = dev_get_platdata(dev);
struct ads7828_data *data;
struct device *hwmon_dev;
+ unsigned int vref_mv = ADS7828_INT_VREF_MV;
+ bool diff_input = false;
+ bool ext_vref = false;
data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
if (!data)
return -ENOMEM;
if (pdata) {
- data->diff_input = pdata->diff_input;
- data->ext_vref = pdata->ext_vref;
- if (data->ext_vref)
- data->vref_mv = pdata->vref_mv;
+ diff_input = pdata->diff_input;
+ ext_vref = pdata->ext_vref;
+ if (ext_vref && pdata->vref_mv)
+ vref_mv = pdata->vref_mv;
}
- /* Bound Vref with min/max values if it was provided */
- if (data->vref_mv)
- data->vref_mv = clamp_val(data->vref_mv,
- ADS7828_EXT_VREF_MV_MIN,
- ADS7828_EXT_VREF_MV_MAX);
- else
- data->vref_mv = ADS7828_INT_VREF_MV;
+ /* Bound Vref with min/max values */
+ vref_mv = clamp_val(vref_mv, ADS7828_EXT_VREF_MV_MIN,
+ ADS7828_EXT_VREF_MV_MAX);
/* ADS7828 uses 12-bit samples, while ADS7830 is 8-bit */
if (id->driver_data == ads7828) {
- data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 4096);
- data->read_channel = i2c_smbus_read_word_swapped;
+ data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 4096);
+ data->regmap = devm_regmap_init_i2c(client,
+ &ads2828_regmap_config);
} else {
- data->lsb_resol = DIV_ROUND_CLOSEST(data->vref_mv * 1000, 256);
- data->read_channel = i2c_smbus_read_byte_data;
+ data->lsb_resol = DIV_ROUND_CLOSEST(vref_mv * 1000, 256);
+ data->regmap = devm_regmap_init_i2c(client,
+ &ads2830_regmap_config);
}
- data->cmd_byte = data->ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
- if (!data->diff_input)
- data->cmd_byte |= ADS7828_CMD_SD_SE;
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
- data->client = client;
- mutex_init(&data->update_lock);
+ data->cmd_byte = ext_vref ? ADS7828_CMD_PD1 : ADS7828_CMD_PD3;
+ if (!diff_input)
+ data->cmd_byte |= ADS7828_CMD_SD_SE;
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
data,
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index e01feba909c3..d1542b7d4bc3 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -35,6 +35,7 @@
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/of.h>
+#include <linux/delay.h>
#include <linux/platform_data/ina2xx.h>
@@ -51,7 +52,6 @@
#define INA226_ALERT_LIMIT 0x07
#define INA226_DIE_ID 0xFF
-
/* register count */
#define INA219_REGISTERS 6
#define INA226_REGISTERS 8
@@ -64,6 +64,24 @@
/* worst case is 68.10 ms (~14.6Hz, ina219) */
#define INA2XX_CONVERSION_RATE 15
+#define INA2XX_MAX_DELAY 69 /* worst case delay in ms */
+
+#define INA2XX_RSHUNT_DEFAULT 10000
+
+/* bit mask for reading the averaging setting in the configuration register */
+#define INA226_AVG_RD_MASK 0x0E00
+
+#define INA226_READ_AVG(reg) (((reg) & INA226_AVG_RD_MASK) >> 9)
+#define INA226_SHIFT_AVG(val) ((val) << 9)
+
+/* common attrs, ina226 attrs and NULL */
+#define INA2XX_MAX_ATTRIBUTE_GROUPS 3
+
+/*
+ * Both bus voltage and shunt voltage conversion times for ina226 are set
+ * to 0b0100 on POR, which translates to 2200 microseconds in total.
+ */
+#define INA226_TOTAL_CONV_TIME_DEFAULT 2200
enum ina2xx_ids { ina219, ina226 };
@@ -81,11 +99,16 @@ struct ina2xx_data {
struct i2c_client *client;
const struct ina2xx_config *config;
+ long rshunt;
+ u16 curr_config;
+
struct mutex update_lock;
bool valid;
unsigned long last_updated;
+ int update_interval; /* in jiffies */
int kind;
+ const struct attribute_group *groups[INA2XX_MAX_ATTRIBUTE_GROUPS];
u16 regs[INA2XX_MAX_REGISTERS];
};
@@ -110,34 +133,156 @@ static const struct ina2xx_config ina2xx_config[] = {
},
};
-static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+/*
+ * Available averaging rates for ina226. The indices correspond with
+ * the bit values expected by the chip (according to the ina226 datasheet,
+ * table 3 AVG bit settings, found at
+ * http://www.ti.com/lit/ds/symlink/ina226.pdf.
+ */
+static const int ina226_avg_tab[] = { 1, 4, 16, 64, 128, 256, 512, 1024 };
+
+static int ina226_avg_bits(int avg)
+{
+ int i;
+
+ /* Get the closest average from the tab. */
+ for (i = 0; i < ARRAY_SIZE(ina226_avg_tab) - 1; i++) {
+ if (avg <= (ina226_avg_tab[i] + ina226_avg_tab[i + 1]) / 2)
+ break;
+ }
+
+ return i; /* Return 0b0111 for values greater than 1024. */
+}
+
+static int ina226_reg_to_interval(u16 config)
+{
+ int avg = ina226_avg_tab[INA226_READ_AVG(config)];
+
+ /*
+ * Multiply the total conversion time by the number of averages.
+ * Return the result in milliseconds.
+ */
+ return DIV_ROUND_CLOSEST(avg * INA226_TOTAL_CONV_TIME_DEFAULT, 1000);
+}
+
+static u16 ina226_interval_to_reg(int interval, u16 config)
+{
+ int avg, avg_bits;
+
+ avg = DIV_ROUND_CLOSEST(interval * 1000,
+ INA226_TOTAL_CONV_TIME_DEFAULT);
+ avg_bits = ina226_avg_bits(avg);
+
+ return (config & ~INA226_AVG_RD_MASK) | INA226_SHIFT_AVG(avg_bits);
+}
+
+static void ina226_set_update_interval(struct ina2xx_data *data)
+{
+ int ms;
+
+ ms = ina226_reg_to_interval(data->curr_config);
+ data->update_interval = msecs_to_jiffies(ms);
+}
+
+static int ina2xx_calibrate(struct ina2xx_data *data)
+{
+ u16 val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
+ data->rshunt);
+
+ return i2c_smbus_write_word_swapped(data->client,
+ INA2XX_CALIBRATION, val);
+}
+
+/*
+ * Initialize the configuration and calibration registers.
+ */
+static int ina2xx_init(struct ina2xx_data *data)
{
- struct ina2xx_data *data = dev_get_drvdata(dev);
struct i2c_client *client = data->client;
- struct ina2xx_data *ret = data;
+ int ret;
- mutex_lock(&data->update_lock);
+ /* device configuration */
+ ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+ data->curr_config);
+ if (ret < 0)
+ return ret;
- if (time_after(jiffies, data->last_updated +
- HZ / INA2XX_CONVERSION_RATE) || !data->valid) {
+ /*
+ * Set current LSB to 1mA, shunt is in uOhms
+ * (equation 13 in datasheet).
+ */
+ return ina2xx_calibrate(data);
+}
- int i;
+static int ina2xx_do_update(struct device *dev)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ struct i2c_client *client = data->client;
+ int i, rv, retry;
- dev_dbg(&client->dev, "Starting ina2xx update\n");
+ dev_dbg(&client->dev, "Starting ina2xx update\n");
+ for (retry = 5; retry; retry--) {
/* Read all registers */
for (i = 0; i < data->config->registers; i++) {
- int rv = i2c_smbus_read_word_swapped(client, i);
- if (rv < 0) {
- ret = ERR_PTR(rv);
- goto abort;
- }
+ rv = i2c_smbus_read_word_swapped(client, i);
+ if (rv < 0)
+ return rv;
data->regs[i] = rv;
}
+
+ /*
+ * If the current value in the calibration register is 0, the
+ * power and current registers will also remain at 0. In case
+ * the chip has been reset let's check the calibration
+ * register and reinitialize if needed.
+ */
+ if (data->regs[INA2XX_CALIBRATION] == 0) {
+ dev_warn(dev, "chip not calibrated, reinitializing\n");
+
+ rv = ina2xx_init(data);
+ if (rv < 0)
+ return rv;
+
+ /*
+ * Let's make sure the power and current registers
+ * have been updated before trying again.
+ */
+ msleep(INA2XX_MAX_DELAY);
+ continue;
+ }
+
data->last_updated = jiffies;
data->valid = 1;
+
+ return 0;
}
-abort:
+
+ /*
+ * If we're here then although all write operations succeeded, the
+ * chip still returns 0 in the calibration register. Nothing more we
+ * can do here.
+ */
+ dev_err(dev, "unable to reinitialize the chip\n");
+ return -ENODEV;
+}
+
+static struct ina2xx_data *ina2xx_update_device(struct device *dev)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ struct ina2xx_data *ret = data;
+ unsigned long after;
+ int rv;
+
+ mutex_lock(&data->update_lock);
+
+ after = data->last_updated + data->update_interval;
+ if (time_after(jiffies, after) || !data->valid) {
+ rv = ina2xx_do_update(dev);
+ if (rv < 0)
+ ret = ERR_PTR(rv);
+ }
+
mutex_unlock(&data->update_lock);
return ret;
}
@@ -164,6 +309,10 @@ static int ina2xx_get_value(struct ina2xx_data *data, u8 reg)
/* signed register, LSB=1mA (selected), in mA */
val = (s16)data->regs[reg];
break;
+ case INA2XX_CALIBRATION:
+ val = DIV_ROUND_CLOSEST(data->config->calibration_factor,
+ data->regs[reg]);
+ break;
default:
/* programmer goofed */
WARN_ON_ONCE(1);
@@ -187,6 +336,85 @@ static ssize_t ina2xx_show_value(struct device *dev,
ina2xx_get_value(data, attr->index));
}
+static ssize_t ina2xx_set_shunt(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+ unsigned long val;
+ int status;
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ status = kstrtoul(buf, 10, &val);
+ if (status < 0)
+ return status;
+
+ if (val == 0 ||
+ /* Values greater than the calibration factor make no sense. */
+ val > data->config->calibration_factor)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->rshunt = val;
+ status = ina2xx_calibrate(data);
+ mutex_unlock(&data->update_lock);
+ if (status < 0)
+ return status;
+
+ return count;
+}
+
+static ssize_t ina226_set_interval(struct device *dev,
+ struct device_attribute *da,
+ const char *buf, size_t count)
+{
+ struct ina2xx_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int status;
+
+ status = kstrtoul(buf, 10, &val);
+ if (status < 0)
+ return status;
+
+ if (val > INT_MAX || val == 0)
+ return -EINVAL;
+
+ mutex_lock(&data->update_lock);
+ data->curr_config = ina226_interval_to_reg(val,
+ data->regs[INA2XX_CONFIG]);
+ status = i2c_smbus_write_word_swapped(data->client,
+ INA2XX_CONFIG,
+ data->curr_config);
+
+ ina226_set_update_interval(data);
+ /* Make sure the next access re-reads all registers. */
+ data->valid = 0;
+ mutex_unlock(&data->update_lock);
+ if (status < 0)
+ return status;
+
+ return count;
+}
+
+static ssize_t ina226_show_interval(struct device *dev,
+ struct device_attribute *da, char *buf)
+{
+ struct ina2xx_data *data = ina2xx_update_device(dev);
+
+ if (IS_ERR(data))
+ return PTR_ERR(data);
+
+ /*
+ * We don't use data->update_interval here as we want to display
+ * the actual interval used by the chip and jiffies_to_msecs()
+ * doesn't seem to be accurate enough.
+ */
+ return snprintf(buf, PAGE_SIZE, "%d\n",
+ ina226_reg_to_interval(data->regs[INA2XX_CONFIG]));
+}
+
/* shunt voltage */
static SENSOR_DEVICE_ATTR(in0_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_SHUNT_VOLTAGE);
@@ -203,15 +431,37 @@ static SENSOR_DEVICE_ATTR(curr1_input, S_IRUGO, ina2xx_show_value, NULL,
static SENSOR_DEVICE_ATTR(power1_input, S_IRUGO, ina2xx_show_value, NULL,
INA2XX_POWER);
+/* shunt resistance */
+static SENSOR_DEVICE_ATTR(shunt_resistor, S_IRUGO | S_IWUSR,
+ ina2xx_show_value, ina2xx_set_shunt,
+ INA2XX_CALIBRATION);
+
+/* update interval (ina226 only) */
+static SENSOR_DEVICE_ATTR(update_interval, S_IRUGO | S_IWUSR,
+ ina226_show_interval, ina226_set_interval, 0);
+
/* pointers to created device attributes */
static struct attribute *ina2xx_attrs[] = {
&sensor_dev_attr_in0_input.dev_attr.attr,
&sensor_dev_attr_in1_input.dev_attr.attr,
&sensor_dev_attr_curr1_input.dev_attr.attr,
&sensor_dev_attr_power1_input.dev_attr.attr,
+ &sensor_dev_attr_shunt_resistor.dev_attr.attr,
NULL,
};
-ATTRIBUTE_GROUPS(ina2xx);
+
+static const struct attribute_group ina2xx_group = {
+ .attrs = ina2xx_attrs,
+};
+
+static struct attribute *ina226_attrs[] = {
+ &sensor_dev_attr_update_interval.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group ina226_group = {
+ .attrs = ina226_attrs,
+};
static int ina2xx_probe(struct i2c_client *client,
const struct i2c_device_id *id)
@@ -221,9 +471,8 @@ static int ina2xx_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct ina2xx_data *data;
struct device *hwmon_dev;
- long shunt = 10000; /* default shunt value 10mOhms */
u32 val;
- int ret;
+ int ret, group = 0;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
@@ -234,50 +483,52 @@ static int ina2xx_probe(struct i2c_client *client,
if (dev_get_platdata(dev)) {
pdata = dev_get_platdata(dev);
- shunt = pdata->shunt_uohms;
+ data->rshunt = pdata->shunt_uohms;
} else if (!of_property_read_u32(dev->of_node,
"shunt-resistor", &val)) {
- shunt = val;
+ data->rshunt = val;
+ } else {
+ data->rshunt = INA2XX_RSHUNT_DEFAULT;
}
- if (shunt <= 0)
- return -ENODEV;
-
/* set the device type */
data->kind = id->driver_data;
data->config = &ina2xx_config[data->kind];
-
- /* device configuration */
- 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;
- }
+ data->curr_config = data->config->config_default;
+ data->client = client;
/*
- * Set current LSB to 1mA, shunt is in uOhms
- * (equation 13 in datasheet).
+ * Ina226 has a variable update_interval. For ina219 we
+ * use a constant value.
*/
- ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- data->config->calibration_factor / shunt);
+ if (data->kind == ina226)
+ ina226_set_update_interval(data);
+ else
+ data->update_interval = HZ / INA2XX_CONVERSION_RATE;
+
+ if (data->rshunt <= 0 ||
+ data->rshunt > data->config->calibration_factor)
+ return -ENODEV;
+
+ ret = ina2xx_init(data);
if (ret < 0) {
- dev_err(dev,
- "error writing to the calibration register: %d", ret);
+ dev_err(dev, "error configuring the device: %d\n", ret);
return -ENODEV;
}
- data->client = client;
mutex_init(&data->update_lock);
+ data->groups[group++] = &ina2xx_group;
+ if (data->kind == ina226)
+ data->groups[group++] = &ina226_group;
+
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
- data, ina2xx_groups);
+ data, data->groups);
if (IS_ERR(hwmon_dev))
return PTR_ERR(hwmon_dev);
dev_info(dev, "power monitor %s (Rshunt = %li uOhm)\n",
- id->name, shunt);
+ id->name, data->rshunt);
return 0;
}
@@ -287,6 +538,7 @@ static const struct i2c_device_id ina2xx_id[] = {
{ "ina220", ina219 },
{ "ina226", ina226 },
{ "ina230", ina226 },
+ { "ina231", ina226 },
{ }
};
MODULE_DEVICE_TABLE(i2c, ina2xx_id);
diff --git a/drivers/hwmon/jc42.c b/drivers/hwmon/jc42.c
index 388f8bcd898e..996bdfd5cf25 100644
--- a/drivers/hwmon/jc42.c
+++ b/drivers/hwmon/jc42.c
@@ -201,7 +201,7 @@ struct jc42_data {
#define JC42_TEMP_MIN 0
#define JC42_TEMP_MAX 125000
-static u16 jc42_temp_to_reg(int temp, bool extended)
+static u16 jc42_temp_to_reg(long temp, bool extended)
{
int ntemp = clamp_val(temp,
extended ? JC42_TEMP_MIN_EXTENDED :
@@ -213,11 +213,7 @@ static u16 jc42_temp_to_reg(int temp, bool extended)
static int jc42_temp_from_reg(s16 reg)
{
- reg &= 0x1fff;
-
- /* sign extend register */
- if (reg & 0x1000)
- reg |= 0xf000;
+ reg = sign_extend32(reg, 12);
/* convert from 0.0625 to 0.001 resolution */
return reg * 125 / 2;
@@ -308,15 +304,18 @@ static ssize_t set_temp_crit_hyst(struct device *dev,
const char *buf, size_t count)
{
struct jc42_data *data = dev_get_drvdata(dev);
- unsigned long val;
+ long val;
int diff, hyst;
int err;
int ret = count;
- if (kstrtoul(buf, 10, &val) < 0)
+ if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
+ val = clamp_val(val, (data->extended ? JC42_TEMP_MIN_EXTENDED :
+ JC42_TEMP_MIN) - 6000, JC42_TEMP_MAX);
diff = jc42_temp_from_reg(data->temp[t_crit]) - val;
+
hyst = 0;
if (diff > 0) {
if (diff < 2250)
diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c
index ec5678289e4a..55765790907b 100644
--- a/drivers/hwmon/nct7802.c
+++ b/drivers/hwmon/nct7802.c
@@ -779,7 +779,7 @@ 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 = {
+static const struct regmap_config nct7802_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index a674cd83a4e2..9f7dbd189c97 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -57,7 +57,7 @@ config SENSORS_LTC2978
be called ltc2978.
config SENSORS_LTC2978_REGULATOR
- boolean "Regulator support for LTC2978 and compatibles"
+ bool "Regulator support for LTC2978 and compatibles"
depends on SENSORS_LTC2978 && REGULATOR
help
If you say yes here you get regulator support for Linear
diff --git a/drivers/hwmon/tmp102.c b/drivers/hwmon/tmp102.c
index ba9f478f64ee..9da2735f1424 100644
--- a/drivers/hwmon/tmp102.c
+++ b/drivers/hwmon/tmp102.c
@@ -253,7 +253,7 @@ static int tmp102_remove(struct i2c_client *client)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int tmp102_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -279,17 +279,10 @@ static int tmp102_resume(struct device *dev)
config &= ~TMP102_CONF_SD;
return i2c_smbus_write_word_swapped(client, TMP102_CONF_REG, config);
}
-
-static const struct dev_pm_ops tmp102_dev_pm_ops = {
- .suspend = tmp102_suspend,
- .resume = tmp102_resume,
-};
-
-#define TMP102_DEV_PM_OPS (&tmp102_dev_pm_ops)
-#else
-#define TMP102_DEV_PM_OPS NULL
#endif /* CONFIG_PM */
+static SIMPLE_DEV_PM_OPS(tmp102_dev_pm_ops, tmp102_suspend, tmp102_resume);
+
static const struct i2c_device_id tmp102_id[] = {
{ "tmp102", 0 },
{ }
@@ -298,7 +291,7 @@ MODULE_DEVICE_TABLE(i2c, tmp102_id);
static struct i2c_driver tmp102_driver = {
.driver.name = DRIVER_NAME,
- .driver.pm = TMP102_DEV_PM_OPS,
+ .driver.pm = &tmp102_dev_pm_ops,
.probe = tmp102_probe,
.remove = tmp102_remove,
.id_table = tmp102_id,
diff --git a/drivers/i2c/Kconfig b/drivers/i2c/Kconfig
index 8c9e619f3026..78fbee463628 100644
--- a/drivers/i2c/Kconfig
+++ b/drivers/i2c/Kconfig
@@ -35,11 +35,11 @@ config ACPI_I2C_OPREGION
if I2C
config I2C_BOARDINFO
- boolean
+ bool
default y
config I2C_COMPAT
- boolean "Enable compatibility bits for old user-space"
+ bool "Enable compatibility bits for old user-space"
default y
help
Say Y here if you intend to run lm-sensors 3.1.1 or older, or any
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 31e8308ba899..22da9c2ffa22 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -79,7 +79,7 @@ config I2C_AMD8111
config I2C_HIX5HD2
tristate "Hix5hd2 high-speed I2C driver"
- depends on ARCH_HIX5HD2
+ depends on ARCH_HIX5HD2 || COMPILE_TEST
help
Say Y here to include support for high-speed I2C controller in the
Hisilicon based hix5hd2 SoCs.
@@ -372,6 +372,16 @@ config I2C_BCM2835
This support is also available as a module. If so, the module
will be called i2c-bcm2835.
+config I2C_BCM_IPROC
+ tristate "Broadcom iProc I2C controller"
+ depends on ARCH_BCM_IPROC || COMPILE_TEST
+ default ARCH_BCM_IPROC
+ help
+ If you say yes to this option, support will be included for the
+ Broadcom iProc I2C controller.
+
+ If you don't know what to do here, say N.
+
config I2C_BCM_KONA
tristate "BCM Kona I2C adapter"
depends on ARCH_BCM_MOBILE
@@ -465,6 +475,16 @@ config I2C_DESIGNWARE_PCI
This driver can also be built as a module. If so, the module
will be called i2c-designware-pci.
+config I2C_DESIGNWARE_BAYTRAIL
+ bool "Intel Baytrail I2C semaphore support"
+ depends on I2C_DESIGNWARE_PLATFORM && IOSF_MBI=y && ACPI
+ help
+ This driver enables managed host access to the PMIC I2C bus on select
+ Intel BayTrail platforms using the X-Powers AXP288 PMIC. It allows
+ the host to request uninterrupted access to the PMIC's I2C bus from
+ the platform firmware controlling it. You should say Y if running on
+ a BayTrail system using the AXP288.
+
config I2C_EFM32
tristate "EFM32 I2C controller"
depends on ARCH_EFM32 || COMPILE_TEST
@@ -881,6 +901,7 @@ config I2C_XLR
config I2C_RCAR
tristate "Renesas R-Car I2C Controller"
depends on ARCH_SHMOBILE || COMPILE_TEST
+ select I2C_SLAVE
help
If you say yes to this option, support will be included for the
R-Car I2C controller.
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 56388f658d2f..3638feb6677e 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -33,6 +33,7 @@ obj-$(CONFIG_I2C_AT91) += i2c-at91.o
obj-$(CONFIG_I2C_AU1550) += i2c-au1550.o
obj-$(CONFIG_I2C_AXXIA) += i2c-axxia.o
obj-$(CONFIG_I2C_BCM2835) += i2c-bcm2835.o
+obj-$(CONFIG_I2C_BCM_IPROC) += i2c-bcm-iproc.o
obj-$(CONFIG_I2C_BLACKFIN_TWI) += i2c-bfin-twi.o
obj-$(CONFIG_I2C_CADENCE) += i2c-cadence.o
obj-$(CONFIG_I2C_CBUS_GPIO) += i2c-cbus-gpio.o
@@ -41,6 +42,7 @@ obj-$(CONFIG_I2C_DAVINCI) += i2c-davinci.o
obj-$(CONFIG_I2C_DESIGNWARE_CORE) += i2c-designware-core.o
obj-$(CONFIG_I2C_DESIGNWARE_PLATFORM) += i2c-designware-platform.o
i2c-designware-platform-objs := i2c-designware-platdrv.o
+i2c-designware-platform-$(CONFIG_I2C_DESIGNWARE_BAYTRAIL) += i2c-designware-baytrail.o
obj-$(CONFIG_I2C_DESIGNWARE_PCI) += i2c-designware-pci.o
i2c-designware-pci-objs := i2c-designware-pcidrv.o
obj-$(CONFIG_I2C_EFM32) += i2c-efm32.o
diff --git a/drivers/i2c/busses/i2c-bcm-iproc.c b/drivers/i2c/busses/i2c-bcm-iproc.c
new file mode 100644
index 000000000000..d3c89157b337
--- /dev/null
+++ b/drivers/i2c/busses/i2c-bcm-iproc.c
@@ -0,0 +1,461 @@
+/*
+ * 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 <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#define CFG_OFFSET 0x00
+#define CFG_RESET_SHIFT 31
+#define CFG_EN_SHIFT 30
+#define CFG_M_RETRY_CNT_SHIFT 16
+#define CFG_M_RETRY_CNT_MASK 0x0f
+
+#define TIM_CFG_OFFSET 0x04
+#define TIM_CFG_MODE_400_SHIFT 31
+
+#define M_FIFO_CTRL_OFFSET 0x0c
+#define M_FIFO_RX_FLUSH_SHIFT 31
+#define M_FIFO_TX_FLUSH_SHIFT 30
+#define M_FIFO_RX_CNT_SHIFT 16
+#define M_FIFO_RX_CNT_MASK 0x7f
+#define M_FIFO_RX_THLD_SHIFT 8
+#define M_FIFO_RX_THLD_MASK 0x3f
+
+#define M_CMD_OFFSET 0x30
+#define M_CMD_START_BUSY_SHIFT 31
+#define M_CMD_STATUS_SHIFT 25
+#define M_CMD_STATUS_MASK 0x07
+#define M_CMD_STATUS_SUCCESS 0x0
+#define M_CMD_STATUS_LOST_ARB 0x1
+#define M_CMD_STATUS_NACK_ADDR 0x2
+#define M_CMD_STATUS_NACK_DATA 0x3
+#define M_CMD_STATUS_TIMEOUT 0x4
+#define M_CMD_PROTOCOL_SHIFT 9
+#define M_CMD_PROTOCOL_MASK 0xf
+#define M_CMD_PROTOCOL_BLK_WR 0x7
+#define M_CMD_PROTOCOL_BLK_RD 0x8
+#define M_CMD_PEC_SHIFT 8
+#define M_CMD_RD_CNT_SHIFT 0
+#define M_CMD_RD_CNT_MASK 0xff
+
+#define IE_OFFSET 0x38
+#define IE_M_RX_FIFO_FULL_SHIFT 31
+#define IE_M_RX_THLD_SHIFT 30
+#define IE_M_START_BUSY_SHIFT 28
+
+#define IS_OFFSET 0x3c
+#define IS_M_RX_FIFO_FULL_SHIFT 31
+#define IS_M_RX_THLD_SHIFT 30
+#define IS_M_START_BUSY_SHIFT 28
+
+#define M_TX_OFFSET 0x40
+#define M_TX_WR_STATUS_SHIFT 31
+#define M_TX_DATA_SHIFT 0
+#define M_TX_DATA_MASK 0xff
+
+#define M_RX_OFFSET 0x44
+#define M_RX_STATUS_SHIFT 30
+#define M_RX_STATUS_MASK 0x03
+#define M_RX_PEC_ERR_SHIFT 29
+#define M_RX_DATA_SHIFT 0
+#define M_RX_DATA_MASK 0xff
+
+#define I2C_TIMEOUT_MESC 100
+#define M_TX_RX_FIFO_SIZE 64
+
+enum bus_speed_index {
+ I2C_SPD_100K = 0,
+ I2C_SPD_400K,
+};
+
+struct bcm_iproc_i2c_dev {
+ struct device *device;
+ int irq;
+
+ void __iomem *base;
+
+ struct i2c_adapter adapter;
+
+ struct completion done;
+ int xfer_is_done;
+};
+
+/*
+ * Can be expanded in the future if more interrupt status bits are utilized
+ */
+#define ISR_MASK (1 << IS_M_START_BUSY_SHIFT)
+
+static irqreturn_t bcm_iproc_i2c_isr(int irq, void *data)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = data;
+ u32 status = readl(iproc_i2c->base + IS_OFFSET);
+
+ status &= ISR_MASK;
+
+ if (!status)
+ return IRQ_NONE;
+
+ writel(status, iproc_i2c->base + IS_OFFSET);
+ iproc_i2c->xfer_is_done = 1;
+ complete_all(&iproc_i2c->done);
+
+ return IRQ_HANDLED;
+}
+
+static int bcm_iproc_i2c_check_status(struct bcm_iproc_i2c_dev *iproc_i2c,
+ struct i2c_msg *msg)
+{
+ u32 val;
+
+ val = readl(iproc_i2c->base + M_CMD_OFFSET);
+ val = (val >> M_CMD_STATUS_SHIFT) & M_CMD_STATUS_MASK;
+
+ switch (val) {
+ case M_CMD_STATUS_SUCCESS:
+ return 0;
+
+ case M_CMD_STATUS_LOST_ARB:
+ dev_dbg(iproc_i2c->device, "lost bus arbitration\n");
+ return -EAGAIN;
+
+ case M_CMD_STATUS_NACK_ADDR:
+ dev_dbg(iproc_i2c->device, "NAK addr:0x%02x\n", msg->addr);
+ return -ENXIO;
+
+ case M_CMD_STATUS_NACK_DATA:
+ dev_dbg(iproc_i2c->device, "NAK data\n");
+ return -ENXIO;
+
+ case M_CMD_STATUS_TIMEOUT:
+ dev_dbg(iproc_i2c->device, "bus timeout\n");
+ return -ETIMEDOUT;
+
+ default:
+ dev_dbg(iproc_i2c->device, "unknown error code=%d\n", val);
+ return -EIO;
+ }
+}
+
+static int bcm_iproc_i2c_xfer_single_msg(struct bcm_iproc_i2c_dev *iproc_i2c,
+ struct i2c_msg *msg)
+{
+ int ret, i;
+ u8 addr;
+ u32 val;
+ unsigned long time_left = msecs_to_jiffies(I2C_TIMEOUT_MESC);
+
+ /* need to reserve one byte in the FIFO for the slave address */
+ if (msg->len > M_TX_RX_FIFO_SIZE - 1) {
+ dev_err(iproc_i2c->device,
+ "only support data length up to %u bytes\n",
+ M_TX_RX_FIFO_SIZE - 1);
+ return -EOPNOTSUPP;
+ }
+
+ /* check if bus is busy */
+ if (!!(readl(iproc_i2c->base + M_CMD_OFFSET) &
+ BIT(M_CMD_START_BUSY_SHIFT))) {
+ dev_warn(iproc_i2c->device, "bus is busy\n");
+ return -EBUSY;
+ }
+
+ /* format and load slave address into the TX FIFO */
+ addr = msg->addr << 1 | (msg->flags & I2C_M_RD ? 1 : 0);
+ writel(addr, iproc_i2c->base + M_TX_OFFSET);
+
+ /* for a write transaction, load data into the TX FIFO */
+ if (!(msg->flags & I2C_M_RD)) {
+ for (i = 0; i < msg->len; i++) {
+ val = msg->buf[i];
+
+ /* mark the last byte */
+ if (i == msg->len - 1)
+ val |= 1 << M_TX_WR_STATUS_SHIFT;
+
+ writel(val, iproc_i2c->base + M_TX_OFFSET);
+ }
+ }
+
+ /* mark as incomplete before starting the transaction */
+ reinit_completion(&iproc_i2c->done);
+ iproc_i2c->xfer_is_done = 0;
+
+ /*
+ * Enable the "start busy" interrupt, which will be triggered after the
+ * transaction is done, i.e., the internal start_busy bit, transitions
+ * from 1 to 0.
+ */
+ writel(1 << IE_M_START_BUSY_SHIFT, iproc_i2c->base + IE_OFFSET);
+
+ /*
+ * Now we can activate the transfer. For a read operation, specify the
+ * number of bytes to read
+ */
+ val = 1 << M_CMD_START_BUSY_SHIFT;
+ if (msg->flags & I2C_M_RD) {
+ val |= (M_CMD_PROTOCOL_BLK_RD << M_CMD_PROTOCOL_SHIFT) |
+ (msg->len << M_CMD_RD_CNT_SHIFT);
+ } else {
+ val |= (M_CMD_PROTOCOL_BLK_WR << M_CMD_PROTOCOL_SHIFT);
+ }
+ writel(val, iproc_i2c->base + M_CMD_OFFSET);
+
+ time_left = wait_for_completion_timeout(&iproc_i2c->done, time_left);
+
+ /* disable all interrupts */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ /* read it back to flush the write */
+ readl(iproc_i2c->base + IE_OFFSET);
+
+ /* make sure the interrupt handler isn't running */
+ synchronize_irq(iproc_i2c->irq);
+
+ if (!time_left && !iproc_i2c->xfer_is_done) {
+ dev_err(iproc_i2c->device, "transaction timed out\n");
+
+ /* flush FIFOs */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+ (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ return -ETIMEDOUT;
+ }
+
+ ret = bcm_iproc_i2c_check_status(iproc_i2c, msg);
+ if (ret) {
+ /* flush both TX/RX FIFOs */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) |
+ (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+ return ret;
+ }
+
+ /*
+ * For a read operation, we now need to load the data from FIFO
+ * into the memory buffer
+ */
+ if (msg->flags & I2C_M_RD) {
+ for (i = 0; i < msg->len; i++) {
+ msg->buf[i] = (readl(iproc_i2c->base + M_RX_OFFSET) >>
+ M_RX_DATA_SHIFT) & M_RX_DATA_MASK;
+ }
+ }
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg msgs[], int num)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = i2c_get_adapdata(adapter);
+ int ret, i;
+
+ /* go through all messages */
+ for (i = 0; i < num; i++) {
+ ret = bcm_iproc_i2c_xfer_single_msg(iproc_i2c, &msgs[i]);
+ if (ret) {
+ dev_dbg(iproc_i2c->device, "xfer failed\n");
+ return ret;
+ }
+ }
+
+ return num;
+}
+
+static uint32_t bcm_iproc_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm bcm_iproc_algo = {
+ .master_xfer = bcm_iproc_i2c_xfer,
+ .functionality = bcm_iproc_i2c_functionality,
+};
+
+static int bcm_iproc_i2c_cfg_speed(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+ unsigned int bus_speed;
+ u32 val;
+ int ret = of_property_read_u32(iproc_i2c->device->of_node,
+ "clock-frequency", &bus_speed);
+ if (ret < 0) {
+ dev_info(iproc_i2c->device,
+ "unable to interpret clock-frequency DT property\n");
+ bus_speed = 100000;
+ }
+
+ if (bus_speed < 100000) {
+ dev_err(iproc_i2c->device, "%d Hz bus speed not supported\n",
+ bus_speed);
+ dev_err(iproc_i2c->device,
+ "valid speeds are 100khz and 400khz\n");
+ return -EINVAL;
+ } else if (bus_speed < 400000) {
+ bus_speed = 100000;
+ } else {
+ bus_speed = 400000;
+ }
+
+ val = readl(iproc_i2c->base + TIM_CFG_OFFSET);
+ val &= ~(1 << TIM_CFG_MODE_400_SHIFT);
+ val |= (bus_speed == 400000) << TIM_CFG_MODE_400_SHIFT;
+ writel(val, iproc_i2c->base + TIM_CFG_OFFSET);
+
+ dev_info(iproc_i2c->device, "bus set to %u Hz\n", bus_speed);
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_init(struct bcm_iproc_i2c_dev *iproc_i2c)
+{
+ u32 val;
+
+ /* put controller in reset */
+ val = readl(iproc_i2c->base + CFG_OFFSET);
+ val |= 1 << CFG_RESET_SHIFT;
+ val &= ~(1 << CFG_EN_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+
+ /* wait 100 usec per spec */
+ udelay(100);
+
+ /* bring controller out of reset */
+ val &= ~(1 << CFG_RESET_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+
+ /* flush TX/RX FIFOs and set RX FIFO threshold to zero */
+ val = (1 << M_FIFO_RX_FLUSH_SHIFT) | (1 << M_FIFO_TX_FLUSH_SHIFT);
+ writel(val, iproc_i2c->base + M_FIFO_CTRL_OFFSET);
+
+ /* disable all interrupts */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+
+ /* clear all pending interrupts */
+ writel(0xffffffff, iproc_i2c->base + IS_OFFSET);
+
+ return 0;
+}
+
+static void bcm_iproc_i2c_enable_disable(struct bcm_iproc_i2c_dev *iproc_i2c,
+ bool enable)
+{
+ u32 val;
+
+ val = readl(iproc_i2c->base + CFG_OFFSET);
+ if (enable)
+ val |= BIT(CFG_EN_SHIFT);
+ else
+ val &= ~BIT(CFG_EN_SHIFT);
+ writel(val, iproc_i2c->base + CFG_OFFSET);
+}
+
+static int bcm_iproc_i2c_probe(struct platform_device *pdev)
+{
+ int irq, ret = 0;
+ struct bcm_iproc_i2c_dev *iproc_i2c;
+ struct i2c_adapter *adap;
+ struct resource *res;
+
+ iproc_i2c = devm_kzalloc(&pdev->dev, sizeof(*iproc_i2c),
+ GFP_KERNEL);
+ if (!iproc_i2c)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, iproc_i2c);
+ iproc_i2c->device = &pdev->dev;
+ init_completion(&iproc_i2c->done);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ iproc_i2c->base = devm_ioremap_resource(iproc_i2c->device, res);
+ if (IS_ERR(iproc_i2c->base))
+ return PTR_ERR(iproc_i2c->base);
+
+ ret = bcm_iproc_i2c_init(iproc_i2c);
+ if (ret)
+ return ret;
+
+ ret = bcm_iproc_i2c_cfg_speed(iproc_i2c);
+ if (ret)
+ return ret;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ dev_err(iproc_i2c->device, "no irq resource\n");
+ return irq;
+ }
+ iproc_i2c->irq = irq;
+
+ ret = devm_request_irq(iproc_i2c->device, irq, bcm_iproc_i2c_isr, 0,
+ pdev->name, iproc_i2c);
+ if (ret < 0) {
+ dev_err(iproc_i2c->device, "unable to request irq %i\n", irq);
+ return ret;
+ }
+
+ bcm_iproc_i2c_enable_disable(iproc_i2c, true);
+
+ adap = &iproc_i2c->adapter;
+ i2c_set_adapdata(adap, iproc_i2c);
+ strlcpy(adap->name, "Broadcom iProc I2C adapter", sizeof(adap->name));
+ adap->algo = &bcm_iproc_algo;
+ adap->dev.parent = &pdev->dev;
+ adap->dev.of_node = pdev->dev.of_node;
+
+ ret = i2c_add_adapter(adap);
+ if (ret) {
+ dev_err(iproc_i2c->device, "failed to add adapter\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int bcm_iproc_i2c_remove(struct platform_device *pdev)
+{
+ struct bcm_iproc_i2c_dev *iproc_i2c = platform_get_drvdata(pdev);
+
+ /* make sure there's no pending interrupt when we remove the adapter */
+ writel(0, iproc_i2c->base + IE_OFFSET);
+ readl(iproc_i2c->base + IE_OFFSET);
+ synchronize_irq(iproc_i2c->irq);
+
+ i2c_del_adapter(&iproc_i2c->adapter);
+ bcm_iproc_i2c_enable_disable(iproc_i2c, false);
+
+ return 0;
+}
+
+static const struct of_device_id bcm_iproc_i2c_of_match[] = {
+ { .compatible = "brcm,iproc-i2c" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, bcm_iproc_i2c_of_match);
+
+static struct platform_driver bcm_iproc_i2c_driver = {
+ .driver = {
+ .name = "bcm-iproc-i2c",
+ .of_match_table = bcm_iproc_i2c_of_match,
+ },
+ .probe = bcm_iproc_i2c_probe,
+ .remove = bcm_iproc_i2c_remove,
+};
+module_platform_driver(bcm_iproc_i2c_driver);
+
+MODULE_AUTHOR("Ray Jui <rjui@broadcom.com>");
+MODULE_DESCRIPTION("Broadcom iProc I2C Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 626f74ecd4be..7d7a14cdadfb 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -128,6 +128,7 @@
* @suspended: Flag holding the device's PM status
* @send_count: Number of bytes still expected to send
* @recv_count: Number of bytes still expected to receive
+ * @curr_recv_count: Number of bytes to be received in current transfer
* @irq: IRQ number
* @input_clk: Input clock to I2C controller
* @i2c_clk: Maximum I2C clock speed
@@ -146,6 +147,7 @@ struct cdns_i2c {
u8 suspended;
unsigned int send_count;
unsigned int recv_count;
+ unsigned int curr_recv_count;
int irq;
unsigned long input_clk;
unsigned int i2c_clk;
@@ -182,14 +184,15 @@ static void cdns_i2c_clear_bus_hold(struct cdns_i2c *id)
*/
static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
{
- unsigned int isr_status, avail_bytes;
- unsigned int bytes_to_recv, bytes_to_send;
+ unsigned int isr_status, avail_bytes, updatetx;
+ unsigned int bytes_to_send;
struct cdns_i2c *id = ptr;
/* Signal completion only after everything is updated */
int done_flag = 0;
irqreturn_t status = IRQ_NONE;
isr_status = cdns_i2c_readreg(CDNS_I2C_ISR_OFFSET);
+ cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
/* Handling nack and arbitration lost interrupt */
if (isr_status & (CDNS_I2C_IXR_NACK | CDNS_I2C_IXR_ARB_LOST)) {
@@ -197,89 +200,112 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
status = IRQ_HANDLED;
}
- /* Handling Data interrupt */
- if ((isr_status & CDNS_I2C_IXR_DATA) &&
- (id->recv_count >= CDNS_I2C_DATA_INTR_DEPTH)) {
- /* Always read data interrupt threshold bytes */
- bytes_to_recv = CDNS_I2C_DATA_INTR_DEPTH;
- id->recv_count -= CDNS_I2C_DATA_INTR_DEPTH;
- avail_bytes = cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
-
- /*
- * if the tranfer size register value is zero, then
- * check for the remaining bytes and update the
- * transfer size register.
- */
- if (!avail_bytes) {
- if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
- cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
- CDNS_I2C_XFER_SIZE_OFFSET);
- else
- cdns_i2c_writereg(id->recv_count,
- CDNS_I2C_XFER_SIZE_OFFSET);
- }
+ /*
+ * Check if transfer size register needs to be updated again for a
+ * large data receive operation.
+ */
+ updatetx = 0;
+ if (id->recv_count > id->curr_recv_count)
+ updatetx = 1;
+
+ /* When receiving, handle data interrupt and completion interrupt */
+ if (id->p_recv_buf &&
+ ((isr_status & CDNS_I2C_IXR_COMP) ||
+ (isr_status & CDNS_I2C_IXR_DATA))) {
+ /* Read data if receive data valid is set */
+ while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
+ CDNS_I2C_SR_RXDV) {
+ /*
+ * Clear hold bit that was set for FIFO control if
+ * RX data left is less than FIFO depth, unless
+ * repeated start is selected.
+ */
+ if ((id->recv_count < CDNS_I2C_FIFO_DEPTH) &&
+ !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
- /* Process the data received */
- while (bytes_to_recv--)
*(id->p_recv_buf)++ =
cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
+ id->recv_count--;
+ id->curr_recv_count--;
- if (!id->bus_hold_flag &&
- (id->recv_count <= CDNS_I2C_FIFO_DEPTH))
- cdns_i2c_clear_bus_hold(id);
+ if (updatetx &&
+ (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1))
+ break;
+ }
- status = IRQ_HANDLED;
- }
+ /*
+ * The controller sends NACK to the slave when transfer size
+ * register reaches zero without considering the HOLD bit.
+ * This workaround is implemented for large data transfers to
+ * maintain transfer size non-zero while performing a large
+ * receive operation.
+ */
+ if (updatetx &&
+ (id->curr_recv_count == CDNS_I2C_FIFO_DEPTH + 1)) {
+ /* wait while fifo is full */
+ while (cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET) !=
+ (id->curr_recv_count - CDNS_I2C_FIFO_DEPTH))
+ ;
- /* Handling Transfer Complete interrupt */
- if (isr_status & CDNS_I2C_IXR_COMP) {
- if (!id->p_recv_buf) {
/*
- * If the device is sending data If there is further
- * data to be sent. Calculate the available space
- * in FIFO and fill the FIFO with that many bytes.
+ * Check number of bytes to be received against maximum
+ * transfer size and update register accordingly.
*/
- if (id->send_count) {
- avail_bytes = CDNS_I2C_FIFO_DEPTH -
- cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
- if (id->send_count > avail_bytes)
- bytes_to_send = avail_bytes;
- else
- bytes_to_send = id->send_count;
-
- while (bytes_to_send--) {
- cdns_i2c_writereg(
- (*(id->p_send_buf)++),
- CDNS_I2C_DATA_OFFSET);
- id->send_count--;
- }
+ if (((int)(id->recv_count) - CDNS_I2C_FIFO_DEPTH) >
+ CDNS_I2C_TRANSFER_SIZE) {
+ cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE +
+ CDNS_I2C_FIFO_DEPTH;
} else {
- /*
- * Signal the completion of transaction and
- * clear the hold bus bit if there are no
- * further messages to be processed.
- */
- done_flag = 1;
+ cdns_i2c_writereg(id->recv_count -
+ CDNS_I2C_FIFO_DEPTH,
+ CDNS_I2C_XFER_SIZE_OFFSET);
+ id->curr_recv_count = id->recv_count;
}
- if (!id->send_count && !id->bus_hold_flag)
- cdns_i2c_clear_bus_hold(id);
- } else {
+ }
+
+ /* Clear hold (if not repeated start) and signal completion */
+ if ((isr_status & CDNS_I2C_IXR_COMP) && !id->recv_count) {
if (!id->bus_hold_flag)
cdns_i2c_clear_bus_hold(id);
+ done_flag = 1;
+ }
+
+ status = IRQ_HANDLED;
+ }
+
+ /* When sending, handle transfer complete interrupt */
+ if ((isr_status & CDNS_I2C_IXR_COMP) && !id->p_recv_buf) {
+ /*
+ * If there is more data to be sent, calculate the
+ * space available in FIFO and fill with that many bytes.
+ */
+ if (id->send_count) {
+ avail_bytes = CDNS_I2C_FIFO_DEPTH -
+ cdns_i2c_readreg(CDNS_I2C_XFER_SIZE_OFFSET);
+ if (id->send_count > avail_bytes)
+ bytes_to_send = avail_bytes;
+ else
+ bytes_to_send = id->send_count;
+
+ while (bytes_to_send--) {
+ cdns_i2c_writereg(
+ (*(id->p_send_buf)++),
+ CDNS_I2C_DATA_OFFSET);
+ id->send_count--;
+ }
+ } else {
/*
- * If the device is receiving data, then signal
- * the completion of transaction and read the data
- * present in the FIFO. Signal the completion of
- * transaction.
+ * Signal the completion of transaction and
+ * clear the hold bus bit if there are no
+ * further messages to be processed.
*/
- while (cdns_i2c_readreg(CDNS_I2C_SR_OFFSET) &
- CDNS_I2C_SR_RXDV) {
- *(id->p_recv_buf)++ =
- cdns_i2c_readreg(CDNS_I2C_DATA_OFFSET);
- id->recv_count--;
- }
done_flag = 1;
}
+ if (!id->send_count && !id->bus_hold_flag)
+ cdns_i2c_clear_bus_hold(id);
status = IRQ_HANDLED;
}
@@ -289,8 +315,6 @@ static irqreturn_t cdns_i2c_isr(int irq, void *ptr)
if (id->err_status)
status = IRQ_HANDLED;
- cdns_i2c_writereg(isr_status, CDNS_I2C_ISR_OFFSET);
-
if (done_flag)
complete(&id->xfer_done);
@@ -316,6 +340,8 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
if (id->p_msg->flags & I2C_M_RECV_LEN)
id->recv_count = I2C_SMBUS_BLOCK_MAX + 1;
+ id->curr_recv_count = id->recv_count;
+
/*
* Check for the message size against FIFO depth and set the
* 'hold bus' bit if it is greater than FIFO depth.
@@ -335,11 +361,14 @@ static void cdns_i2c_mrecv(struct cdns_i2c *id)
* receive if it is less than transfer size and transfer size if
* it is more. Enable the interrupts.
*/
- if (id->recv_count > CDNS_I2C_TRANSFER_SIZE)
+ if (id->recv_count > CDNS_I2C_TRANSFER_SIZE) {
cdns_i2c_writereg(CDNS_I2C_TRANSFER_SIZE,
CDNS_I2C_XFER_SIZE_OFFSET);
- else
+ id->curr_recv_count = CDNS_I2C_TRANSFER_SIZE;
+ } else {
cdns_i2c_writereg(id->recv_count, CDNS_I2C_XFER_SIZE_OFFSET);
+ }
+
/* Clear the bus hold flag if bytes to receive is less than FIFO size */
if (!id->bus_hold_flag &&
((id->p_msg->flags & I2C_M_RECV_LEN) != I2C_M_RECV_LEN) &&
@@ -516,6 +545,20 @@ static int cdns_i2c_master_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
* processed with a repeated start.
*/
if (num > 1) {
+ /*
+ * This controller does not give completion interrupt after a
+ * master receive message if HOLD bit is set (repeated start),
+ * resulting in SW timeout. Hence, if a receive message is
+ * followed by any other message, an error is returned
+ * indicating that this sequence is not supported.
+ */
+ for (count = 0; count < num - 1; count++) {
+ if (msgs[count].flags & I2C_M_RD) {
+ dev_warn(adap->dev.parent,
+ "Can't do repeated start after a receive message\n");
+ return -EOPNOTSUPP;
+ }
+ }
id->bus_hold_flag = 1;
reg = cdns_i2c_readreg(CDNS_I2C_CR_OFFSET);
reg |= CDNS_I2C_CR_HOLD;
diff --git a/drivers/i2c/busses/i2c-designware-baytrail.c b/drivers/i2c/busses/i2c-designware-baytrail.c
new file mode 100644
index 000000000000..5f1ff4cc5c34
--- /dev/null
+++ b/drivers/i2c/busses/i2c-designware-baytrail.c
@@ -0,0 +1,160 @@
+/*
+ * Intel BayTrail PMIC I2C bus semaphore implementaion
+ * 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/module.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/acpi.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <asm/iosf_mbi.h>
+#include "i2c-designware-core.h"
+
+#define SEMAPHORE_TIMEOUT 100
+#define PUNIT_SEMAPHORE 0x7
+
+static unsigned long acquired;
+
+static int get_sem(struct device *dev, u32 *sem)
+{
+ u32 reg_val;
+ int ret;
+
+ ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ, PUNIT_SEMAPHORE,
+ &reg_val);
+ if (ret) {
+ dev_err(dev, "iosf failed to read punit semaphore\n");
+ return ret;
+ }
+
+ *sem = reg_val & 0x1;
+
+ return 0;
+}
+
+static void reset_semaphore(struct device *dev)
+{
+ u32 data;
+
+ if (iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
+ PUNIT_SEMAPHORE, &data)) {
+ dev_err(dev, "iosf failed to reset punit semaphore during read\n");
+ return;
+ }
+
+ data = data & 0xfffffffe;
+ if (iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
+ PUNIT_SEMAPHORE, data))
+ dev_err(dev, "iosf failed to reset punit semaphore during write\n");
+}
+
+int baytrail_i2c_acquire(struct dw_i2c_dev *dev)
+{
+ u32 sem = 0;
+ int ret;
+ unsigned long start, end;
+
+ if (!dev || !dev->dev)
+ return -ENODEV;
+
+ if (!dev->acquire_lock)
+ return 0;
+
+ /* host driver writes 0x2 to side band semaphore register */
+ ret = iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_WRITE,
+ PUNIT_SEMAPHORE, 0x2);
+ if (ret) {
+ dev_err(dev->dev, "iosf punit semaphore request failed\n");
+ return ret;
+ }
+
+ /* host driver waits for bit 0 to be set in semaphore register */
+ start = jiffies;
+ end = start + msecs_to_jiffies(SEMAPHORE_TIMEOUT);
+ while (!time_after(jiffies, end)) {
+ ret = get_sem(dev->dev, &sem);
+ if (!ret && sem) {
+ acquired = jiffies;
+ dev_dbg(dev->dev, "punit semaphore acquired after %ums\n",
+ jiffies_to_msecs(jiffies - start));
+ return 0;
+ }
+
+ usleep_range(1000, 2000);
+ }
+
+ dev_err(dev->dev, "punit semaphore timed out, resetting\n");
+ reset_semaphore(dev->dev);
+
+ ret = iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_BUNIT_READ,
+ PUNIT_SEMAPHORE, &sem);
+ if (!ret)
+ dev_err(dev->dev, "iosf failed to read punit semaphore\n");
+ else
+ dev_err(dev->dev, "PUNIT SEM: %d\n", sem);
+
+ WARN_ON(1);
+
+ return -ETIMEDOUT;
+}
+EXPORT_SYMBOL(baytrail_i2c_acquire);
+
+void baytrail_i2c_release(struct dw_i2c_dev *dev)
+{
+ if (!dev || !dev->dev)
+ return;
+
+ if (!dev->acquire_lock)
+ return;
+
+ reset_semaphore(dev->dev);
+ dev_dbg(dev->dev, "punit semaphore held for %ums\n",
+ jiffies_to_msecs(jiffies - acquired));
+}
+EXPORT_SYMBOL(baytrail_i2c_release);
+
+int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev)
+{
+ acpi_status status;
+ unsigned long long shared_host = 0;
+ acpi_handle handle;
+
+ if (!dev || !dev->dev)
+ return 0;
+
+ handle = ACPI_HANDLE(dev->dev);
+ if (!handle)
+ return 0;
+
+ status = acpi_evaluate_integer(handle, "_SEM", NULL, &shared_host);
+
+ if (ACPI_FAILURE(status))
+ return 0;
+
+ if (shared_host) {
+ dev_info(dev->dev, "I2C bus managed by PUNIT\n");
+ dev->acquire_lock = baytrail_i2c_acquire;
+ dev->release_lock = baytrail_i2c_release;
+ dev->pm_runtime_disabled = true;
+ }
+
+ if (!iosf_mbi_available())
+ return -EPROBE_DEFER;
+
+ return 0;
+}
+EXPORT_SYMBOL(i2c_dw_eval_lock_support);
+
+MODULE_AUTHOR("David E. Box <david.e.box@linux.intel.com>");
+MODULE_DESCRIPTION("Baytrail I2C Semaphore driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/i2c/busses/i2c-designware-core.c b/drivers/i2c/busses/i2c-designware-core.c
index 23628b7bfb8d..6e25c010e690 100644
--- a/drivers/i2c/busses/i2c-designware-core.c
+++ b/drivers/i2c/busses/i2c-designware-core.c
@@ -170,10 +170,10 @@ u32 dw_readl(struct dw_i2c_dev *dev, int offset)
u32 value;
if (dev->accessor_flags & ACCESS_16BIT)
- value = readw(dev->base + offset) |
- (readw(dev->base + offset + 2) << 16);
+ value = readw_relaxed(dev->base + offset) |
+ (readw_relaxed(dev->base + offset + 2) << 16);
else
- value = readl(dev->base + offset);
+ value = readl_relaxed(dev->base + offset);
if (dev->accessor_flags & ACCESS_SWAP)
return swab32(value);
@@ -187,10 +187,10 @@ void dw_writel(struct dw_i2c_dev *dev, u32 b, int offset)
b = swab32(b);
if (dev->accessor_flags & ACCESS_16BIT) {
- writew((u16)b, dev->base + offset);
- writew((u16)(b >> 16), dev->base + offset + 2);
+ writew_relaxed((u16)b, dev->base + offset);
+ writew_relaxed((u16)(b >> 16), dev->base + offset + 2);
} else {
- writel(b, dev->base + offset);
+ writel_relaxed(b, dev->base + offset);
}
}
@@ -285,6 +285,15 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
u32 hcnt, lcnt;
u32 reg;
u32 sda_falling_time, scl_falling_time;
+ int ret;
+
+ if (dev->acquire_lock) {
+ ret = dev->acquire_lock(dev);
+ if (ret) {
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+ return ret;
+ }
+ }
input_clock_khz = dev->get_clk_rate_khz(dev);
@@ -298,6 +307,8 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
} else if (reg != DW_IC_COMP_TYPE_VALUE) {
dev_err(dev->dev, "Unknown Synopsys component type: "
"0x%08x\n", reg);
+ if (dev->release_lock)
+ dev->release_lock(dev);
return -ENODEV;
}
@@ -309,40 +320,39 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
sda_falling_time = dev->sda_falling_time ?: 300; /* ns */
scl_falling_time = dev->scl_falling_time ?: 300; /* ns */
- /* Standard-mode */
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 4000, /* tHD;STA = tHIGH = 4.0 us */
- sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 4700, /* tLOW = 4.7 us */
- scl_falling_time,
- 0); /* No offset */
-
- /* Allow platforms to specify the ideal HCNT and LCNT values */
+ /* Set SCL timing parameters for standard-mode */
if (dev->ss_hcnt && dev->ss_lcnt) {
hcnt = dev->ss_hcnt;
lcnt = dev->ss_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 4000, /* tHD;STA = tHIGH = 4.0 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 4700, /* tLOW = 4.7 us */
+ scl_falling_time,
+ 0); /* No offset */
}
dw_writel(dev, hcnt, DW_IC_SS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_SS_SCL_LCNT);
dev_dbg(dev->dev, "Standard-mode HCNT:LCNT = %d:%d\n", hcnt, lcnt);
- /* Fast-mode */
- hcnt = i2c_dw_scl_hcnt(input_clock_khz,
- 600, /* tHD;STA = tHIGH = 0.6 us */
- sda_falling_time,
- 0, /* 0: DW default, 1: Ideal */
- 0); /* No offset */
- lcnt = i2c_dw_scl_lcnt(input_clock_khz,
- 1300, /* tLOW = 1.3 us */
- scl_falling_time,
- 0); /* No offset */
-
+ /* Set SCL timing parameters for fast-mode */
if (dev->fs_hcnt && dev->fs_lcnt) {
hcnt = dev->fs_hcnt;
lcnt = dev->fs_lcnt;
+ } else {
+ hcnt = i2c_dw_scl_hcnt(input_clock_khz,
+ 600, /* tHD;STA = tHIGH = 0.6 us */
+ sda_falling_time,
+ 0, /* 0: DW default, 1: Ideal */
+ 0); /* No offset */
+ lcnt = i2c_dw_scl_lcnt(input_clock_khz,
+ 1300, /* tLOW = 1.3 us */
+ scl_falling_time,
+ 0); /* No offset */
}
dw_writel(dev, hcnt, DW_IC_FS_SCL_HCNT);
dw_writel(dev, lcnt, DW_IC_FS_SCL_LCNT);
@@ -364,6 +374,9 @@ int i2c_dw_init(struct dw_i2c_dev *dev)
/* configure the i2c master */
dw_writel(dev, dev->master_cfg , DW_IC_CON);
+
+ if (dev->release_lock)
+ dev->release_lock(dev);
return 0;
}
EXPORT_SYMBOL_GPL(i2c_dw_init);
@@ -627,6 +640,14 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
dev->abort_source = 0;
dev->rx_outstanding = 0;
+ if (dev->acquire_lock) {
+ ret = dev->acquire_lock(dev);
+ if (ret) {
+ dev_err(dev->dev, "couldn't acquire bus ownership\n");
+ goto done_nolock;
+ }
+ }
+
ret = i2c_dw_wait_bus_not_busy(dev);
if (ret < 0)
goto done;
@@ -672,6 +693,10 @@ i2c_dw_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
ret = -EIO;
done:
+ if (dev->release_lock)
+ dev->release_lock(dev);
+
+done_nolock:
pm_runtime_mark_last_busy(dev->dev);
pm_runtime_put_autosuspend(dev->dev);
mutex_unlock(&dev->lock);
diff --git a/drivers/i2c/busses/i2c-designware-core.h b/drivers/i2c/busses/i2c-designware-core.h
index 5a410ef17abd..9630222abf32 100644
--- a/drivers/i2c/busses/i2c-designware-core.h
+++ b/drivers/i2c/busses/i2c-designware-core.h
@@ -61,6 +61,9 @@
* @ss_lcnt: standard speed LCNT value
* @fs_hcnt: fast speed HCNT value
* @fs_lcnt: fast speed LCNT value
+ * @acquire_lock: function to acquire a hardware lock on the bus
+ * @release_lock: function to release a hardware lock on the bus
+ * @pm_runtime_disabled: true if pm runtime is disabled
*
* HCNT and LCNT parameters can be used if the platform knows more accurate
* values than the one computed based only on the input clock frequency.
@@ -101,6 +104,9 @@ struct dw_i2c_dev {
u16 ss_lcnt;
u16 fs_hcnt;
u16 fs_lcnt;
+ int (*acquire_lock)(struct dw_i2c_dev *dev);
+ void (*release_lock)(struct dw_i2c_dev *dev);
+ bool pm_runtime_disabled;
};
#define ACCESS_SWAP 0x00000001
@@ -119,3 +125,9 @@ extern void i2c_dw_disable(struct dw_i2c_dev *dev);
extern void i2c_dw_clear_int(struct dw_i2c_dev *dev);
extern void i2c_dw_disable_int(struct dw_i2c_dev *dev);
extern u32 i2c_dw_read_comp_param(struct dw_i2c_dev *dev);
+
+#if IS_ENABLED(CONFIG_I2C_DESIGNWARE_BAYTRAIL)
+extern int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev);
+#else
+static inline int i2c_dw_eval_lock_support(struct dw_i2c_dev *dev) { return 0; }
+#endif
diff --git a/drivers/i2c/busses/i2c-designware-pcidrv.c b/drivers/i2c/busses/i2c-designware-pcidrv.c
index acb40f95db78..6643d2dc0b25 100644
--- a/drivers/i2c/busses/i2c-designware-pcidrv.c
+++ b/drivers/i2c/busses/i2c-designware-pcidrv.c
@@ -6,7 +6,7 @@
* Copyright (C) 2006 Texas Instruments.
* Copyright (C) 2007 MontaVista Software Inc.
* Copyright (C) 2009 Provigent Ltd.
- * Copyright (C) 2011 Intel corporation.
+ * Copyright (C) 2011, 2015 Intel Corporation.
*
* ----------------------------------------------------------------------------
*
@@ -40,10 +40,6 @@
#define DRIVER_NAME "i2c-designware-pci"
enum dw_pci_ctl_id_t {
- moorestown_0,
- moorestown_1,
- moorestown_2,
-
medfield_0,
medfield_1,
medfield_2,
@@ -101,28 +97,7 @@ static struct dw_scl_sda_cfg hsw_config = {
.sda_hold = 0x9,
};
-static struct dw_pci_controller dw_pci_controllers[] = {
- [moorestown_0] = {
- .bus_num = 0,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [moorestown_1] = {
- .bus_num = 1,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
- [moorestown_2] = {
- .bus_num = 2,
- .bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
- .tx_fifo_depth = 32,
- .rx_fifo_depth = 32,
- .clk_khz = 25000,
- },
+static struct dw_pci_controller dw_pci_controllers[] = {
[medfield_0] = {
.bus_num = 0,
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
@@ -170,7 +145,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
- .clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &byt_config,
},
@@ -179,7 +153,6 @@ static struct dw_pci_controller dw_pci_controllers[] = {
.bus_cfg = INTEL_MID_STD_CFG | DW_IC_CON_SPEED_FAST,
.tx_fifo_depth = 32,
.rx_fifo_depth = 32,
- .clk_khz = 100000,
.functionality = I2C_FUNC_10BIT_ADDR,
.scl_sda_cfg = &hsw_config,
},
@@ -259,7 +232,7 @@ static int i2c_dw_pci_probe(struct pci_dev *pdev,
dev->functionality = controller->functionality |
DW_DEFAULT_FUNCTIONALITY;
- dev->master_cfg = controller->bus_cfg;
+ dev->master_cfg = controller->bus_cfg;
if (controller->scl_sda_cfg) {
cfg = controller->scl_sda_cfg;
dev->ss_hcnt = cfg->ss_hcnt;
@@ -325,12 +298,8 @@ static void i2c_dw_pci_remove(struct pci_dev *pdev)
MODULE_ALIAS("i2c_designware-pci");
static const struct pci_device_id i2_designware_pci_ids[] = {
- /* Moorestown */
- { PCI_VDEVICE(INTEL, 0x0802), moorestown_0 },
- { PCI_VDEVICE(INTEL, 0x0803), moorestown_1 },
- { PCI_VDEVICE(INTEL, 0x0804), moorestown_2 },
/* Medfield */
- { PCI_VDEVICE(INTEL, 0x0817), medfield_3,},
+ { PCI_VDEVICE(INTEL, 0x0817), medfield_3 },
{ PCI_VDEVICE(INTEL, 0x0818), medfield_4 },
{ PCI_VDEVICE(INTEL, 0x0819), medfield_5 },
{ PCI_VDEVICE(INTEL, 0x082C), medfield_0 },
@@ -348,7 +317,7 @@ static const struct pci_device_id i2_designware_pci_ids[] = {
{ PCI_VDEVICE(INTEL, 0x9c61), haswell },
{ PCI_VDEVICE(INTEL, 0x9c62), haswell },
/* Braswell / Cherrytrail */
- { PCI_VDEVICE(INTEL, 0x22C1), baytrail,},
+ { PCI_VDEVICE(INTEL, 0x22C1), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C2), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C3), baytrail },
{ PCI_VDEVICE(INTEL, 0x22C4), baytrail },
diff --git a/drivers/i2c/busses/i2c-designware-platdrv.c b/drivers/i2c/busses/i2c-designware-platdrv.c
index 2b463c313e4e..c270f5f9a8f9 100644
--- a/drivers/i2c/busses/i2c-designware-platdrv.c
+++ b/drivers/i2c/busses/i2c-designware-platdrv.c
@@ -195,6 +195,10 @@ static int dw_i2c_probe(struct platform_device *pdev)
clk_freq = pdata->i2c_scl_freq;
}
+ r = i2c_dw_eval_lock_support(dev);
+ if (r)
+ return r;
+
dev->functionality =
I2C_FUNC_I2C |
I2C_FUNC_10BIT_ADDR |
@@ -257,10 +261,14 @@ static int dw_i2c_probe(struct platform_device *pdev)
return r;
}
- pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
+ if (dev->pm_runtime_disabled) {
+ pm_runtime_forbid(&pdev->dev);
+ } else {
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 1000);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ }
return 0;
}
@@ -310,7 +318,9 @@ static int dw_i2c_resume(struct device *dev)
struct dw_i2c_dev *i_dev = platform_get_drvdata(pdev);
clk_prepare_enable(i_dev->clk);
- i2c_dw_init(i_dev);
+
+ if (!i_dev->pm_runtime_disabled)
+ i2c_dw_init(i_dev);
return 0;
}
diff --git a/drivers/i2c/busses/i2c-imx.c b/drivers/i2c/busses/i2c-imx.c
index 7f3a9fe9bf4e..d7b26fc6f432 100644
--- a/drivers/i2c/busses/i2c-imx.c
+++ b/drivers/i2c/busses/i2c-imx.c
@@ -201,7 +201,7 @@ struct imx_i2c_struct {
void __iomem *base;
wait_queue_head_t queue;
unsigned long i2csr;
- unsigned int disable_delay;
+ unsigned int disable_delay;
int stopped;
unsigned int ifdr; /* IMX_I2C_IFDR */
unsigned int cur_clk;
@@ -295,7 +295,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma->chan_tx = dma_request_slave_channel(dev, "tx");
if (!dma->chan_tx) {
dev_dbg(dev, "can't request DMA tx channel\n");
- ret = -ENODEV;
goto fail_al;
}
@@ -313,7 +312,6 @@ static void i2c_imx_dma_request(struct imx_i2c_struct *i2c_imx,
dma->chan_rx = dma_request_slave_channel(dev, "rx");
if (!dma->chan_rx) {
dev_dbg(dev, "can't request DMA rx channel\n");
- ret = -ENODEV;
goto fail_tx;
}
@@ -481,8 +479,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
i2c_clk_rate = clk_get_rate(i2c_imx->clk);
if (i2c_imx->cur_clk == i2c_clk_rate)
return;
- else
- i2c_imx->cur_clk = i2c_clk_rate;
+
+ i2c_imx->cur_clk = i2c_clk_rate;
div = (i2c_clk_rate + i2c_imx->bitrate - 1) / i2c_imx->bitrate;
if (div < i2c_clk_div[0].div)
@@ -490,7 +488,8 @@ static void i2c_imx_set_clk(struct imx_i2c_struct *i2c_imx)
else if (div > i2c_clk_div[i2c_imx->hwdata->ndivs - 1].div)
i = i2c_imx->hwdata->ndivs - 1;
else
- for (i = 0; i2c_clk_div[i].div < div; i++);
+ for (i = 0; i2c_clk_div[i].div < div; i++)
+ ;
/* Store divider value */
i2c_imx->ifdr = i2c_clk_div[i].val;
@@ -628,9 +627,9 @@ static int i2c_imx_dma_write(struct imx_i2c_struct *i2c_imx,
result = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
- if (result <= 0) {
+ if (result == 0) {
dmaengine_terminate_all(dma->chan_using);
- return result ?: -ETIMEDOUT;
+ return -ETIMEDOUT;
}
/* Waiting for transfer complete. */
@@ -686,9 +685,9 @@ static int i2c_imx_dma_read(struct imx_i2c_struct *i2c_imx,
result = wait_for_completion_timeout(
&i2c_imx->dma->cmd_complete,
msecs_to_jiffies(DMA_TIMEOUT));
- if (result <= 0) {
+ if (result == 0) {
dmaengine_terminate_all(dma->chan_using);
- return result ?: -ETIMEDOUT;
+ return -ETIMEDOUT;
}
/* waiting for transfer complete. */
@@ -822,6 +821,7 @@ static int i2c_imx_read(struct imx_i2c_struct *i2c_imx, struct i2c_msg *msgs, bo
/* read data */
for (i = 0; i < msgs->len; i++) {
u8 len = 0;
+
result = i2c_imx_trx_complete(i2c_imx);
if (result)
return result;
@@ -917,15 +917,16 @@ static int i2c_imx_xfer(struct i2c_adapter *adapter,
/* write/read data */
#ifdef CONFIG_I2C_DEBUG_BUS
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2CR);
- dev_dbg(&i2c_imx->adapter.dev, "<%s> CONTROL: IEN=%d, IIEN=%d, "
- "MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n", __func__,
+ dev_dbg(&i2c_imx->adapter.dev,
+ "<%s> CONTROL: IEN=%d, IIEN=%d, MSTA=%d, MTX=%d, TXAK=%d, RSTA=%d\n",
+ __func__,
(temp & I2CR_IEN ? 1 : 0), (temp & I2CR_IIEN ? 1 : 0),
(temp & I2CR_MSTA ? 1 : 0), (temp & I2CR_MTX ? 1 : 0),
(temp & I2CR_TXAK ? 1 : 0), (temp & I2CR_RSTA ? 1 : 0));
temp = imx_i2c_read_reg(i2c_imx, IMX_I2C_I2SR);
dev_dbg(&i2c_imx->adapter.dev,
- "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, "
- "IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n", __func__,
+ "<%s> STATUS: ICF=%d, IAAS=%d, IBB=%d, IAL=%d, SRW=%d, IIF=%d, RXAK=%d\n",
+ __func__,
(temp & I2SR_ICF ? 1 : 0), (temp & I2SR_IAAS ? 1 : 0),
(temp & I2SR_IBB ? 1 : 0), (temp & I2SR_IAL ? 1 : 0),
(temp & I2SR_SRW ? 1 : 0), (temp & I2SR_IIF ? 1 : 0),
@@ -1004,7 +1005,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.owner = THIS_MODULE;
i2c_imx->adapter.algo = &i2c_imx_algo;
i2c_imx->adapter.dev.parent = &pdev->dev;
- i2c_imx->adapter.nr = pdev->id;
+ i2c_imx->adapter.nr = pdev->id;
i2c_imx->adapter.dev.of_node = pdev->dev.of_node;
i2c_imx->base = base;
@@ -1063,7 +1064,7 @@ static int i2c_imx_probe(struct platform_device *pdev)
i2c_imx->adapter.name);
dev_info(&i2c_imx->adapter.dev, "IMX I2C adapter registered\n");
- /* Init DMA config if support*/
+ /* Init DMA config if supported */
i2c_imx_dma_request(i2c_imx, phy_addr);
return 0; /* Return OK */
diff --git a/drivers/i2c/busses/i2c-ocores.c b/drivers/i2c/busses/i2c-ocores.c
index 7249b5b1e5d0..abf5db7e441e 100644
--- a/drivers/i2c/busses/i2c-ocores.c
+++ b/drivers/i2c/busses/i2c-ocores.c
@@ -12,6 +12,7 @@
* kind, whether express or implied.
*/
+#include <linux/clk.h>
#include <linux/err.h>
#include <linux/kernel.h>
#include <linux/module.h>
@@ -35,7 +36,9 @@ struct ocores_i2c {
int pos;
int nmsgs;
int state; /* see STATE_ */
- int clock_khz;
+ struct clk *clk;
+ int ip_clock_khz;
+ int bus_clock_khz;
void (*setreg)(struct ocores_i2c *i2c, int reg, u8 value);
u8 (*getreg)(struct ocores_i2c *i2c, int reg);
};
@@ -215,21 +218,34 @@ static int ocores_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
return -ETIMEDOUT;
}
-static void ocores_init(struct ocores_i2c *i2c)
+static int ocores_init(struct device *dev, struct ocores_i2c *i2c)
{
int prescale;
+ int diff;
u8 ctrl = oc_getreg(i2c, OCI2C_CONTROL);
/* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
- prescale = (i2c->clock_khz / (5*100)) - 1;
+ prescale = (i2c->ip_clock_khz / (5 * i2c->bus_clock_khz)) - 1;
+ prescale = clamp(prescale, 0, 0xffff);
+
+ diff = i2c->ip_clock_khz / (5 * (prescale + 1)) - i2c->bus_clock_khz;
+ if (abs(diff) > i2c->bus_clock_khz / 10) {
+ dev_err(dev,
+ "Unsupported clock settings: core: %d KHz, bus: %d KHz\n",
+ i2c->ip_clock_khz, i2c->bus_clock_khz);
+ return -EINVAL;
+ }
+
oc_setreg(i2c, OCI2C_PRELOW, prescale & 0xff);
oc_setreg(i2c, OCI2C_PREHIGH, prescale >> 8);
/* Init the device */
oc_setreg(i2c, OCI2C_CMD, OCI2C_CMD_IACK);
oc_setreg(i2c, OCI2C_CONTROL, ctrl | OCI2C_CTRL_IEN | OCI2C_CTRL_EN);
+
+ return 0;
}
@@ -304,6 +320,8 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
struct device_node *np = pdev->dev.of_node;
const struct of_device_id *match;
u32 val;
+ u32 clock_frequency;
+ bool clock_frequency_present;
if (of_property_read_u32(np, "reg-shift", &i2c->reg_shift)) {
/* no 'reg-shift', check for deprecated 'regstep' */
@@ -319,12 +337,42 @@ static int ocores_i2c_of_probe(struct platform_device *pdev,
}
}
- if (of_property_read_u32(np, "clock-frequency", &val)) {
- dev_err(&pdev->dev,
- "Missing required parameter 'clock-frequency'\n");
- return -ENODEV;
+ clock_frequency_present = !of_property_read_u32(np, "clock-frequency",
+ &clock_frequency);
+ i2c->bus_clock_khz = 100;
+
+ i2c->clk = devm_clk_get(&pdev->dev, NULL);
+
+ if (!IS_ERR(i2c->clk)) {
+ int ret = clk_prepare_enable(i2c->clk);
+
+ if (ret) {
+ dev_err(&pdev->dev,
+ "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+ i2c->ip_clock_khz = clk_get_rate(i2c->clk) / 1000;
+ if (clock_frequency_present)
+ i2c->bus_clock_khz = clock_frequency / 1000;
+ }
+
+ if (i2c->ip_clock_khz == 0) {
+ if (of_property_read_u32(np, "opencores,ip-clock-frequency",
+ &val)) {
+ if (!clock_frequency_present) {
+ dev_err(&pdev->dev,
+ "Missing required parameter 'opencores,ip-clock-frequency'\n");
+ return -ENODEV;
+ }
+ i2c->ip_clock_khz = clock_frequency / 1000;
+ dev_warn(&pdev->dev,
+ "Deprecated usage of the 'clock-frequency' property, please update to 'opencores,ip-clock-frequency'\n");
+ } else {
+ i2c->ip_clock_khz = val / 1000;
+ if (clock_frequency_present)
+ i2c->bus_clock_khz = clock_frequency / 1000;
+ }
}
- i2c->clock_khz = val / 1000;
of_property_read_u32(pdev->dev.of_node, "reg-io-width",
&i2c->reg_io_width);
@@ -368,7 +416,8 @@ static int ocores_i2c_probe(struct platform_device *pdev)
if (pdata) {
i2c->reg_shift = pdata->reg_shift;
i2c->reg_io_width = pdata->reg_io_width;
- i2c->clock_khz = pdata->clock_khz;
+ i2c->ip_clock_khz = pdata->clock_khz;
+ i2c->bus_clock_khz = 100;
} else {
ret = ocores_i2c_of_probe(pdev, i2c);
if (ret)
@@ -402,7 +451,9 @@ static int ocores_i2c_probe(struct platform_device *pdev)
}
}
- ocores_init(i2c);
+ ret = ocores_init(&pdev->dev, i2c);
+ if (ret)
+ return ret;
init_waitqueue_head(&i2c->wait);
ret = devm_request_irq(&pdev->dev, irq, ocores_isr, 0,
@@ -446,6 +497,9 @@ static int ocores_i2c_remove(struct platform_device *pdev)
/* remove adapter & data */
i2c_del_adapter(&i2c->adap);
+ if (!IS_ERR(i2c->clk))
+ clk_disable_unprepare(i2c->clk);
+
return 0;
}
@@ -458,6 +512,8 @@ static int ocores_i2c_suspend(struct device *dev)
/* make sure the device is disabled */
oc_setreg(i2c, OCI2C_CONTROL, ctrl & ~(OCI2C_CTRL_EN|OCI2C_CTRL_IEN));
+ if (!IS_ERR(i2c->clk))
+ clk_disable_unprepare(i2c->clk);
return 0;
}
@@ -465,9 +521,20 @@ static int ocores_i2c_resume(struct device *dev)
{
struct ocores_i2c *i2c = dev_get_drvdata(dev);
- ocores_init(i2c);
+ if (!IS_ERR(i2c->clk)) {
+ unsigned long rate;
+ int ret = clk_prepare_enable(i2c->clk);
- return 0;
+ if (ret) {
+ dev_err(dev,
+ "clk_prepare_enable failed: %d\n", ret);
+ return ret;
+ }
+ rate = clk_get_rate(i2c->clk) / 1000;
+ if (rate)
+ i2c->ip_clock_khz = rate;
+ }
+ return ocores_init(dev, i2c);
}
static SIMPLE_DEV_PM_OPS(ocores_i2c_pm, ocores_i2c_suspend, ocores_i2c_resume);
diff --git a/drivers/i2c/busses/i2c-pmcmsp.c b/drivers/i2c/busses/i2c-pmcmsp.c
index 44f03eed00dd..d37d9db6681e 100644
--- a/drivers/i2c/busses/i2c-pmcmsp.c
+++ b/drivers/i2c/busses/i2c-pmcmsp.c
@@ -148,13 +148,6 @@ static inline u32 pmcmsptwi_clock_to_reg(
return ((clock->filter & 0xf) << 12) | (clock->clock & 0x03ff);
}
-static inline void pmcmsptwi_reg_to_clock(
- u32 reg, struct pmcmsptwi_clock *clock)
-{
- clock->filter = (reg >> 12) & 0xf;
- clock->clock = reg & 0x03ff;
-}
-
static inline u32 pmcmsptwi_cfg_to_reg(const struct pmcmsptwi_cfg *cfg)
{
return ((cfg->arbf & 0xf) << 12) |
diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 92462843db66..5f96b1b3e3a5 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -102,6 +102,9 @@ struct rk3x_i2c {
/* Settings */
unsigned int scl_frequency;
+ unsigned int scl_rise_ns;
+ unsigned int scl_fall_ns;
+ unsigned int sda_fall_ns;
/* Synchronization & notification */
spinlock_t lock;
@@ -435,6 +438,9 @@ out:
*
* @clk_rate: I2C input clock rate
* @scl_rate: Desired SCL rate
+ * @scl_rise_ns: How many ns it takes for SCL to rise.
+ * @scl_fall_ns: How many ns it takes for SCL to fall.
+ * @sda_fall_ns: How many ns it takes for SDA to fall.
* @div_low: Divider output for low
* @div_high: Divider output for high
*
@@ -443,11 +449,16 @@ out:
* too high, we silently use the highest possible rate.
*/
static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
+ unsigned long scl_rise_ns,
+ unsigned long scl_fall_ns,
+ unsigned long sda_fall_ns,
unsigned long *div_low, unsigned long *div_high)
{
- unsigned long min_low_ns, min_high_ns;
- unsigned long max_data_hold_ns;
+ unsigned long spec_min_low_ns, spec_min_high_ns;
+ unsigned long spec_setup_start, spec_max_data_hold_ns;
unsigned long data_hold_buffer_ns;
+
+ unsigned long min_low_ns, min_high_ns;
unsigned long max_low_ns, min_total_ns;
unsigned long clk_rate_khz, scl_rate_khz;
@@ -469,29 +480,50 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
scl_rate = 1000;
/*
- * min_low_ns: The minimum number of ns we need to hold low
- * to meet i2c spec
- * min_high_ns: The minimum number of ns we need to hold high
- * to meet i2c spec
- * max_low_ns: The maximum number of ns we can hold low
- * to meet i2c spec
+ * min_low_ns: The minimum number of ns we need to hold low to
+ * meet I2C specification, should include fall time.
+ * min_high_ns: The minimum number of ns we need to hold high to
+ * meet I2C specification, should include rise time.
+ * max_low_ns: The maximum number of ns we can hold low to meet
+ * I2C specification.
*
- * Note: max_low_ns should be (max data hold time * 2 - buffer)
+ * Note: max_low_ns should be (maximum data hold time * 2 - buffer)
* This is because the i2c host on Rockchip holds the data line
* for half the low time.
*/
if (scl_rate <= 100000) {
- min_low_ns = 4700;
- min_high_ns = 4000;
- max_data_hold_ns = 3450;
+ /* Standard-mode */
+ spec_min_low_ns = 4700;
+ spec_setup_start = 4700;
+ spec_min_high_ns = 4000;
+ spec_max_data_hold_ns = 3450;
data_hold_buffer_ns = 50;
} else {
- min_low_ns = 1300;
- min_high_ns = 600;
- max_data_hold_ns = 900;
+ /* Fast-mode */
+ spec_min_low_ns = 1300;
+ spec_setup_start = 600;
+ spec_min_high_ns = 600;
+ spec_max_data_hold_ns = 900;
data_hold_buffer_ns = 50;
}
- max_low_ns = max_data_hold_ns * 2 - data_hold_buffer_ns;
+ min_high_ns = scl_rise_ns + spec_min_high_ns;
+
+ /*
+ * Timings for repeated start:
+ * - controller appears to drop SDA at .875x (7/8) programmed clk high.
+ * - controller appears to keep SCL high for 2x programmed clk high.
+ *
+ * We need to account for those rules in picking our "high" time so
+ * we meet tSU;STA and tHD;STA times.
+ */
+ min_high_ns = max(min_high_ns,
+ DIV_ROUND_UP((scl_rise_ns + spec_setup_start) * 1000, 875));
+ min_high_ns = max(min_high_ns,
+ DIV_ROUND_UP((scl_rise_ns + spec_setup_start +
+ sda_fall_ns + spec_min_high_ns), 2));
+
+ min_low_ns = scl_fall_ns + spec_min_low_ns;
+ max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
min_total_ns = min_low_ns + min_high_ns;
/* Adjust to avoid overflow */
@@ -510,8 +542,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
min_div_for_hold = (min_low_div + min_high_div);
/*
- * This is the maximum divider so we don't go over the max.
- * We don't round up here (we round down) since this is a max.
+ * This is the maximum divider so we don't go over the maximum.
+ * We don't round up here (we round down) since this is a maximum.
*/
max_low_div = clk_rate_khz * max_low_ns / (8 * 1000000);
@@ -544,7 +576,7 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate, unsigned long scl_rate,
ideal_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns,
scl_rate_khz * 8 * min_total_ns);
- /* Don't allow it to go over the max */
+ /* Don't allow it to go over the maximum */
if (ideal_low_div > max_low_div)
ideal_low_div = max_low_div;
@@ -588,9 +620,9 @@ static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
u64 t_low_ns, t_high_ns;
int ret;
- ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, &div_low,
- &div_high);
-
+ ret = rk3x_i2c_calc_divs(clk_rate, i2c->scl_frequency, i2c->scl_rise_ns,
+ i2c->scl_fall_ns, i2c->sda_fall_ns,
+ &div_low, &div_high);
WARN_ONCE(ret != 0, "Could not reach SCL freq %u", i2c->scl_frequency);
clk_enable(i2c->clk);
@@ -633,9 +665,10 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
switch (event) {
case PRE_RATE_CHANGE:
if (rk3x_i2c_calc_divs(ndata->new_rate, i2c->scl_frequency,
- &div_low, &div_high) != 0) {
+ i2c->scl_rise_ns, i2c->scl_fall_ns,
+ i2c->sda_fall_ns,
+ &div_low, &div_high) != 0)
return NOTIFY_STOP;
- }
/* scale up */
if (ndata->new_rate > ndata->old_rate)
@@ -859,6 +892,24 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
i2c->scl_frequency = DEFAULT_SCL_RATE;
}
+ /*
+ * Read rise and fall time from device tree. If not available use
+ * the default maximum timing from the specification.
+ */
+ if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-rising-time-ns",
+ &i2c->scl_rise_ns)) {
+ if (i2c->scl_frequency <= 100000)
+ i2c->scl_rise_ns = 1000;
+ else
+ i2c->scl_rise_ns = 300;
+ }
+ if (of_property_read_u32(pdev->dev.of_node, "i2c-scl-falling-time-ns",
+ &i2c->scl_fall_ns))
+ i2c->scl_fall_ns = 300;
+ if (of_property_read_u32(pdev->dev.of_node, "i2c-sda-falling-time-ns",
+ &i2c->scl_fall_ns))
+ i2c->sda_fall_ns = i2c->scl_fall_ns;
+
strlcpy(i2c->adap.name, "rk3x-i2c", sizeof(i2c->adap.name));
i2c->adap.owner = THIS_MODULE;
i2c->adap.algo = &rk3x_i2c_algorithm;
diff --git a/drivers/i2c/busses/i2c-s3c2410.c b/drivers/i2c/busses/i2c-s3c2410.c
index bff20a589621..958c8db4ec30 100644
--- a/drivers/i2c/busses/i2c-s3c2410.c
+++ b/drivers/i2c/busses/i2c-s3c2410.c
@@ -785,14 +785,16 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
int ret;
pm_runtime_get_sync(&adap->dev);
- clk_prepare_enable(i2c->clk);
+ ret = clk_enable(i2c->clk);
+ if (ret)
+ return ret;
for (retry = 0; retry < adap->retries; retry++) {
ret = s3c24xx_i2c_doxfer(i2c, msgs, num);
if (ret != -EAGAIN) {
- clk_disable_unprepare(i2c->clk);
+ clk_disable(i2c->clk);
pm_runtime_put(&adap->dev);
return ret;
}
@@ -802,7 +804,7 @@ static int s3c24xx_i2c_xfer(struct i2c_adapter *adap,
udelay(100);
}
- clk_disable_unprepare(i2c->clk);
+ clk_disable(i2c->clk);
pm_runtime_put(&adap->dev);
return -EREMOTEIO;
}
@@ -1197,7 +1199,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
clk_prepare_enable(i2c->clk);
ret = s3c24xx_i2c_init(i2c);
- clk_disable_unprepare(i2c->clk);
+ clk_disable(i2c->clk);
if (ret != 0) {
dev_err(&pdev->dev, "I2C controller init failed\n");
return ret;
@@ -1210,6 +1212,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
i2c->irq = ret = platform_get_irq(pdev, 0);
if (ret <= 0) {
dev_err(&pdev->dev, "cannot find IRQ\n");
+ clk_unprepare(i2c->clk);
return ret;
}
@@ -1218,6 +1221,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (ret != 0) {
dev_err(&pdev->dev, "cannot claim IRQ %d\n", i2c->irq);
+ clk_unprepare(i2c->clk);
return ret;
}
}
@@ -1225,6 +1229,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
ret = s3c24xx_i2c_register_cpufreq(i2c);
if (ret < 0) {
dev_err(&pdev->dev, "failed to register cpufreq notifier\n");
+ clk_unprepare(i2c->clk);
return ret;
}
@@ -1241,6 +1246,7 @@ static int s3c24xx_i2c_probe(struct platform_device *pdev)
if (ret < 0) {
dev_err(&pdev->dev, "failed to add bus to i2c core\n");
s3c24xx_i2c_deregister_cpufreq(i2c);
+ clk_unprepare(i2c->clk);
return ret;
}
@@ -1262,6 +1268,8 @@ static int s3c24xx_i2c_remove(struct platform_device *pdev)
{
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+ clk_unprepare(i2c->clk);
+
pm_runtime_disable(&i2c->adap.dev);
pm_runtime_disable(&pdev->dev);
@@ -1293,13 +1301,16 @@ static int s3c24xx_i2c_resume_noirq(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct s3c24xx_i2c *i2c = platform_get_drvdata(pdev);
+ int ret;
if (!IS_ERR(i2c->sysreg))
regmap_write(i2c->sysreg, EXYNOS5_SYS_I2C_CFG, i2c->sys_i2c_cfg);
- clk_prepare_enable(i2c->clk);
+ ret = clk_enable(i2c->clk);
+ if (ret)
+ return ret;
s3c24xx_i2c_init(i2c);
- clk_disable_unprepare(i2c->clk);
+ clk_disable(i2c->clk);
i2c->suspended = 0;
return 0;
diff --git a/drivers/i2c/busses/i2c-sh_mobile.c b/drivers/i2c/busses/i2c-sh_mobile.c
index 440d5dbc8b5f..007818b3e174 100644
--- a/drivers/i2c/busses/i2c-sh_mobile.c
+++ b/drivers/i2c/busses/i2c-sh_mobile.c
@@ -139,6 +139,7 @@ struct sh_mobile_i2c_data {
int pos;
int sr;
bool send_stop;
+ bool stop_after_dma;
struct resource *res;
struct dma_chan *dma_tx;
@@ -407,7 +408,7 @@ static int sh_mobile_i2c_isr_tx(struct sh_mobile_i2c_data *pd)
if (pd->pos == pd->msg->len) {
/* Send stop if we haven't yet (DMA case) */
- if (pd->send_stop && (iic_rd(pd, ICCR) & ICCR_BBSY))
+ if (pd->send_stop && pd->stop_after_dma)
i2c_op(pd, OP_TX_STOP, 0);
return 1;
}
@@ -449,6 +450,13 @@ static int sh_mobile_i2c_isr_rx(struct sh_mobile_i2c_data *pd)
real_pos = pd->pos - 2;
if (pd->pos == pd->msg->len) {
+ if (pd->stop_after_dma) {
+ /* Simulate PIO end condition after DMA transfer */
+ i2c_op(pd, OP_RX_STOP, 0);
+ pd->pos++;
+ break;
+ }
+
if (real_pos < 0) {
i2c_op(pd, OP_RX_STOP, 0);
break;
@@ -536,6 +544,7 @@ static void sh_mobile_i2c_dma_callback(void *data)
sh_mobile_i2c_dma_unmap(pd);
pd->pos = pd->msg->len;
+ pd->stop_after_dma = true;
iic_set_clr(pd, ICIC, 0, ICIC_TDMAE | ICIC_RDMAE);
}
@@ -726,6 +735,7 @@ static int sh_mobile_i2c_xfer(struct i2c_adapter *adapter,
bool do_start = pd->send_stop || !i;
msg = &msgs[i];
pd->send_stop = i == num - 1 || msg->flags & I2C_M_STOP;
+ pd->stop_after_dma = false;
err = start_ch(pd, msg, do_start);
if (err)
diff --git a/drivers/i2c/busses/i2c-tegra.c b/drivers/i2c/busses/i2c-tegra.c
index 28b87e683503..29f14331dd9d 100644
--- a/drivers/i2c/busses/i2c-tegra.c
+++ b/drivers/i2c/busses/i2c-tegra.c
@@ -286,6 +286,7 @@ static int tegra_i2c_empty_rx_fifo(struct tegra_i2c_dev *i2c_dev)
if (rx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
val = i2c_readl(i2c_dev, I2C_RX_FIFO);
+ val = cpu_to_le32(val);
memcpy(buf, &val, buf_remaining);
buf_remaining = 0;
rx_fifo_avail--;
@@ -344,6 +345,7 @@ static int tegra_i2c_fill_tx_fifo(struct tegra_i2c_dev *i2c_dev)
if (tx_fifo_avail > 0 && buf_remaining > 0) {
BUG_ON(buf_remaining > 3);
memcpy(&val, buf, buf_remaining);
+ val = le32_to_cpu(val);
/* Again update before writing to FIFO to make sure isr sees. */
i2c_dev->msg_buf_remaining = 0;
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index 39d25a8cb1ad..210cf4874cb7 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -102,7 +102,7 @@ static int acpi_i2c_add_resource(struct acpi_resource *ares, void *data)
struct acpi_resource_i2c_serialbus *sb;
sb = &ares->data.i2c_serial_bus;
- if (sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
+ if (!info->addr && sb->type == ACPI_RESOURCE_SERIAL_TYPE_I2C) {
info->addr = sb->slave_address;
if (sb->access_mode == ACPI_I2C_10BIT_MODE)
info->flags |= I2C_CLIENT_TEN;
@@ -698,101 +698,6 @@ static void i2c_device_shutdown(struct device *dev)
driver->shutdown(client);
}
-#ifdef CONFIG_PM_SLEEP
-static int i2c_legacy_suspend(struct device *dev, pm_message_t mesg)
-{
- struct i2c_client *client = i2c_verify_client(dev);
- struct i2c_driver *driver;
-
- if (!client || !dev->driver)
- return 0;
- driver = to_i2c_driver(dev->driver);
- if (!driver->suspend)
- return 0;
- return driver->suspend(client, mesg);
-}
-
-static int i2c_legacy_resume(struct device *dev)
-{
- struct i2c_client *client = i2c_verify_client(dev);
- struct i2c_driver *driver;
-
- if (!client || !dev->driver)
- return 0;
- driver = to_i2c_driver(dev->driver);
- if (!driver->resume)
- return 0;
- return driver->resume(client);
-}
-
-static int i2c_device_pm_suspend(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_suspend(dev);
- else
- return i2c_legacy_suspend(dev, PMSG_SUSPEND);
-}
-
-static int i2c_device_pm_resume(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_resume(dev);
- else
- return i2c_legacy_resume(dev);
-}
-
-static int i2c_device_pm_freeze(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_freeze(dev);
- else
- return i2c_legacy_suspend(dev, PMSG_FREEZE);
-}
-
-static int i2c_device_pm_thaw(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_thaw(dev);
- else
- return i2c_legacy_resume(dev);
-}
-
-static int i2c_device_pm_poweroff(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_poweroff(dev);
- else
- return i2c_legacy_suspend(dev, PMSG_HIBERNATE);
-}
-
-static int i2c_device_pm_restore(struct device *dev)
-{
- const struct dev_pm_ops *pm = dev->driver ? dev->driver->pm : NULL;
-
- if (pm)
- return pm_generic_restore(dev);
- else
- return i2c_legacy_resume(dev);
-}
-#else /* !CONFIG_PM_SLEEP */
-#define i2c_device_pm_suspend NULL
-#define i2c_device_pm_resume NULL
-#define i2c_device_pm_freeze NULL
-#define i2c_device_pm_thaw NULL
-#define i2c_device_pm_poweroff NULL
-#define i2c_device_pm_restore NULL
-#endif /* !CONFIG_PM_SLEEP */
-
static void i2c_client_dev_release(struct device *dev)
{
kfree(to_i2c_client(dev));
@@ -804,6 +709,7 @@ show_name(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s\n", dev->type == &i2c_client_type ?
to_i2c_client(dev)->name : to_i2c_adapter(dev)->name);
}
+static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static ssize_t
show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
@@ -817,8 +723,6 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf)
return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name);
}
-
-static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL);
static struct attribute *i2c_dev_attrs[] = {
@@ -827,29 +731,7 @@ static struct attribute *i2c_dev_attrs[] = {
&dev_attr_modalias.attr,
NULL
};
-
-static struct attribute_group i2c_dev_attr_group = {
- .attrs = i2c_dev_attrs,
-};
-
-static const struct attribute_group *i2c_dev_attr_groups[] = {
- &i2c_dev_attr_group,
- NULL
-};
-
-static const struct dev_pm_ops i2c_device_pm_ops = {
- .suspend = i2c_device_pm_suspend,
- .resume = i2c_device_pm_resume,
- .freeze = i2c_device_pm_freeze,
- .thaw = i2c_device_pm_thaw,
- .poweroff = i2c_device_pm_poweroff,
- .restore = i2c_device_pm_restore,
- SET_RUNTIME_PM_OPS(
- pm_generic_runtime_suspend,
- pm_generic_runtime_resume,
- NULL
- )
-};
+ATTRIBUTE_GROUPS(i2c_dev);
struct bus_type i2c_bus_type = {
.name = "i2c",
@@ -857,12 +739,11 @@ struct bus_type i2c_bus_type = {
.probe = i2c_device_probe,
.remove = i2c_device_remove,
.shutdown = i2c_device_shutdown,
- .pm = &i2c_device_pm_ops,
};
EXPORT_SYMBOL_GPL(i2c_bus_type);
static struct device_type i2c_client_type = {
- .groups = i2c_dev_attr_groups,
+ .groups = i2c_dev_groups,
.uevent = i2c_device_uevent,
.release = i2c_client_dev_release,
};
@@ -1261,6 +1142,7 @@ i2c_sysfs_new_device(struct device *dev, struct device_attribute *attr,
return count;
}
+static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
/*
* And of course let the users delete the devices they instantiated, if
@@ -1315,8 +1197,6 @@ i2c_sysfs_delete_device(struct device *dev, struct device_attribute *attr,
"delete_device");
return res;
}
-
-static DEVICE_ATTR(new_device, S_IWUSR, NULL, i2c_sysfs_new_device);
static DEVICE_ATTR_IGNORE_LOCKDEP(delete_device, S_IWUSR, NULL,
i2c_sysfs_delete_device);
@@ -1326,18 +1206,10 @@ static struct attribute *i2c_adapter_attrs[] = {
&dev_attr_delete_device.attr,
NULL
};
-
-static struct attribute_group i2c_adapter_attr_group = {
- .attrs = i2c_adapter_attrs,
-};
-
-static const struct attribute_group *i2c_adapter_attr_groups[] = {
- &i2c_adapter_attr_group,
- NULL
-};
+ATTRIBUTE_GROUPS(i2c_adapter);
struct device_type i2c_adapter_type = {
- .groups = i2c_adapter_attr_groups,
+ .groups = i2c_adapter_groups,
.release = i2c_adapter_dev_release,
};
EXPORT_SYMBOL_GPL(i2c_adapter_type);
@@ -1419,8 +1291,6 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
if (of_get_property(node, "wakeup-source", NULL))
info.flags |= I2C_CLIENT_WAKE;
- 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",
@@ -1796,11 +1666,15 @@ void i2c_del_adapter(struct i2c_adapter *adap)
/* device name is gone after device_unregister */
dev_dbg(&adap->dev, "adapter [%s] unregistered\n", adap->name);
- /* clean up the sysfs representation */
+ /* wait until all references to the device are gone
+ *
+ * FIXME: This is old code and should ideally be replaced by an
+ * alternative which results in decoupling the lifetime of the struct
+ * device from the i2c_adapter, like spi or netdev do. Any solution
+ * should be throughly tested with DEBUG_KOBJECT_RELEASE enabled!
+ */
init_completion(&adap->dev_released);
device_unregister(&adap->dev);
-
- /* wait for sysfs to drop all references */
wait_for_completion(&adap->dev_released);
/* free bus id */
@@ -1859,14 +1733,6 @@ int i2c_register_driver(struct module *owner, struct i2c_driver *driver)
if (res)
return res;
- /* Drivers should switch to dev_pm_ops instead. */
- if (driver->suspend)
- pr_warn("i2c-core: driver [%s] using legacy suspend method\n",
- driver->driver.name);
- if (driver->resume)
- pr_warn("i2c-core: driver [%s] using legacy resume method\n",
- driver->driver.name);
-
pr_debug("i2c-core: driver [%s] registered\n", driver->driver.name);
INIT_LIST_HEAD(&driver->clients);
@@ -2972,6 +2838,7 @@ trace:
}
EXPORT_SYMBOL(i2c_smbus_xfer);
+#if IS_ENABLED(CONFIG_I2C_SLAVE)
int i2c_slave_register(struct i2c_client *client, i2c_slave_cb_t slave_cb)
{
int ret;
@@ -3019,6 +2886,7 @@ int i2c_slave_unregister(struct i2c_client *client)
return ret;
}
EXPORT_SYMBOL_GPL(i2c_slave_unregister);
+#endif
MODULE_AUTHOR("Simon G. Vogl <simon@tk.uni-linz.ac.at>");
MODULE_DESCRIPTION("I2C-Bus main module");
diff --git a/drivers/i2c/i2c-slave-eeprom.c b/drivers/i2c/i2c-slave-eeprom.c
index 6631400b5f02..cf9b09db092f 100644
--- a/drivers/i2c/i2c-slave-eeprom.c
+++ b/drivers/i2c/i2c-slave-eeprom.c
@@ -74,7 +74,7 @@ static ssize_t i2c_slave_eeprom_bin_read(struct file *filp, struct kobject *kobj
struct eeprom_data *eeprom;
unsigned long flags;
- if (off + count >= attr->size)
+ if (off + count > attr->size)
return -EFBIG;
eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
@@ -92,7 +92,7 @@ static ssize_t i2c_slave_eeprom_bin_write(struct file *filp, struct kobject *kob
struct eeprom_data *eeprom;
unsigned long flags;
- if (off + count >= attr->size)
+ if (off + count > attr->size)
return -EFBIG;
eeprom = dev_get_drvdata(container_of(kobj, struct device, kobj));
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index ec11b404b433..3d8f4fe2e47e 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -41,6 +41,7 @@
#include <linux/i2c-mux.h>
#include <linux/i2c/pca954x.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -186,6 +187,8 @@ static int pca954x_probe(struct i2c_client *client,
{
struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
+ struct device_node *of_node = client->dev.of_node;
+ bool idle_disconnect_dt;
struct gpio_desc *gpio;
int num, force, class;
struct pca954x *data;
@@ -217,8 +220,13 @@ static int pca954x_probe(struct i2c_client *client,
data->type = id->driver_data;
data->last_chan = 0; /* force the first selection */
+ idle_disconnect_dt = of_node &&
+ of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
+
/* Now create an adapter for each channel */
for (num = 0; num < chips[data->type].nchans; num++) {
+ bool idle_disconnect_pd = false;
+
force = 0; /* dynamic adap number */
class = 0; /* no class by default */
if (pdata) {
@@ -229,12 +237,13 @@ static int pca954x_probe(struct i2c_client *client,
} else
/* discard unconfigured channels */
break;
+ idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
}
data->virt_adaps[num] =
i2c_add_mux_adapter(adap, &client->dev, client,
force, num, class, pca954x_select_chan,
- (pdata && pdata->modes[num].deselect_on_exit)
+ (idle_disconnect_pd || idle_disconnect_dt)
? pca954x_deselect_mux : NULL);
if (data->virt_adaps[num] == NULL) {
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 9cceacb92f9d..b0e58522780d 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -97,6 +97,8 @@ static const struct idle_cpu *icpu;
static struct cpuidle_device __percpu *intel_idle_cpuidle_devices;
static int intel_idle(struct cpuidle_device *dev,
struct cpuidle_driver *drv, int index);
+static void intel_idle_freeze(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index);
static int intel_idle_cpu_init(int cpu);
static struct cpuidle_state *cpuidle_state_table;
@@ -131,28 +133,32 @@ static struct cpuidle_state nehalem_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 3,
.target_residency = 6,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-NHM",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-NHM",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
.target_residency = 80,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-NHM",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
.target_residency = 800,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -164,35 +170,40 @@ static struct cpuidle_state snb_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-SNB",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-SNB",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 211,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-SNB",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
.target_residency = 345,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C7-SNB",
.desc = "MWAIT 0x30",
.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
.target_residency = 345,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -204,42 +215,48 @@ static struct cpuidle_state byt_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-BYT",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 15,
.target_residency = 30,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6N-BYT",
.desc = "MWAIT 0x58",
.flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 40,
.target_residency = 275,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6S-BYT",
.desc = "MWAIT 0x52",
.flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
.target_residency = 560,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C7-BYT",
.desc = "MWAIT 0x60",
.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 1200,
.target_residency = 1500,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C7S-BYT",
.desc = "MWAIT 0x64",
.flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 10000,
.target_residency = 20000,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -251,35 +268,40 @@ static struct cpuidle_state ivb_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-IVB",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-IVB",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 156,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-IVB",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 300,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C7-IVB",
.desc = "MWAIT 0x30",
.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 87,
.target_residency = 300,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -291,28 +313,32 @@ static struct cpuidle_state ivt_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-IVT",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 80,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-IVT",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 156,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-IVT",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 82,
.target_residency = 300,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -324,28 +350,32 @@ static struct cpuidle_state ivt_cstates_4s[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-IVT-4S",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 250,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-IVT-4S",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 300,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-IVT-4S",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 84,
.target_residency = 400,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -357,28 +387,32 @@ static struct cpuidle_state ivt_cstates_8s[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-IVT-8S",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 500,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-IVT-8S",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 600,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-IVT-8S",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 88,
.target_residency = 700,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -390,56 +424,64 @@ static struct cpuidle_state hsw_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-HSW",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-HSW",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 33,
.target_residency = 100,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-HSW",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 133,
.target_residency = 400,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C7s-HSW",
.desc = "MWAIT 0x32",
.flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 166,
.target_residency = 500,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C8-HSW",
.desc = "MWAIT 0x40",
.flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 300,
.target_residency = 900,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C9-HSW",
.desc = "MWAIT 0x50",
.flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 600,
.target_residency = 1800,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C10-HSW",
.desc = "MWAIT 0x60",
.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 2600,
.target_residency = 7700,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -450,56 +492,64 @@ static struct cpuidle_state bdw_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C1E-BDW",
.desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C3-BDW",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 40,
.target_residency = 100,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-BDW",
.desc = "MWAIT 0x20",
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 133,
.target_residency = 400,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C7s-BDW",
.desc = "MWAIT 0x32",
.flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 166,
.target_residency = 500,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C8-BDW",
.desc = "MWAIT 0x40",
.flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 300,
.target_residency = 900,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C9-BDW",
.desc = "MWAIT 0x50",
.flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 600,
.target_residency = 1800,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C10-BDW",
.desc = "MWAIT 0x60",
.flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 2600,
.target_residency = 7700,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -511,28 +561,32 @@ static struct cpuidle_state atom_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 10,
.target_residency = 20,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C2-ATM",
.desc = "MWAIT 0x10",
.flags = MWAIT2flg(0x10),
.exit_latency = 20,
.target_residency = 80,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C4-ATM",
.desc = "MWAIT 0x30",
.flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.target_residency = 400,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-ATM",
.desc = "MWAIT 0x52",
.flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
.target_residency = 560,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -543,14 +597,16 @@ static struct cpuidle_state avn_cstates[] = {
.flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.name = "C6-AVN",
.desc = "MWAIT 0x51",
.flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 15,
.target_residency = 45,
- .enter = &intel_idle },
+ .enter = &intel_idle,
+ .enter_freeze = intel_idle_freeze, },
{
.enter = NULL }
};
@@ -592,6 +648,21 @@ static int intel_idle(struct cpuidle_device *dev,
return index;
}
+/**
+ * intel_idle_freeze - simplified "enter" callback routine for suspend-to-idle
+ * @dev: cpuidle_device
+ * @drv: cpuidle driver
+ * @index: state index
+ */
+static void intel_idle_freeze(struct cpuidle_device *dev,
+ struct cpuidle_driver *drv, int index)
+{
+ unsigned long ecx = 1; /* break on interrupt flag */
+ unsigned long eax = flg2MWAIT(drv->states[index].flags);
+
+ mwait_idle_with_hints(eax, ecx);
+}
+
static void __setup_broadcast_timer(void *arg)
{
unsigned long reason = (unsigned long)arg;
@@ -727,6 +798,7 @@ static const struct x86_cpu_id intel_idle_ids[] = {
ICPU(0x46, idle_cpu_hsw),
ICPU(0x4d, idle_cpu_avn),
ICPU(0x3d, idle_cpu_bdw),
+ ICPU(0x47, idle_cpu_bdw),
ICPU(0x4f, idle_cpu_bdw),
ICPU(0x56, idle_cpu_bdw),
{}
diff --git a/drivers/iio/Kconfig b/drivers/iio/Kconfig
index 345395e9dc6e..4011effe4c05 100644
--- a/drivers/iio/Kconfig
+++ b/drivers/iio/Kconfig
@@ -21,13 +21,12 @@ config IIO_BUFFER
if IIO_BUFFER
config IIO_BUFFER_CB
-boolean "IIO callback buffer used for push in-kernel interfaces"
+ bool "IIO callback buffer used for push in-kernel interfaces"
help
Should be selected by any drivers that do in-kernel push
usage. That is, those where the data is pushed to the consumer.
config IIO_KFIFO_BUF
- select IIO_TRIGGER
tristate "Industrial I/O buffering based on kfifo"
help
A simple fifo based on kfifo. Note that this currently provides
@@ -44,7 +43,7 @@ config IIO_TRIGGERED_BUFFER
endif # IIO_BUFFER
config IIO_TRIGGER
- boolean "Enable triggered sampling support"
+ bool "Enable triggered sampling support"
help
Provides IIO core support for triggers. Currently these
are used to initialize capture of samples to push into
diff --git a/drivers/iio/accel/Kconfig b/drivers/iio/accel/Kconfig
index 9b9be8725e9d..7c9a9a94a8ce 100644
--- a/drivers/iio/accel/Kconfig
+++ b/drivers/iio/accel/Kconfig
@@ -43,6 +43,9 @@ config HID_SENSOR_ACCEL_3D
Say yes here to build support for the HID SENSOR
accelerometers 3D.
+ To compile this driver as a module, choose M here: the
+ module will be called hid-sensor-accel-3d.
+
config IIO_ST_ACCEL_3AXIS
tristate "STMicroelectronics accelerometers 3-Axis Driver"
depends on (I2C || SPI_MASTER) && SYSFS
@@ -80,6 +83,9 @@ config KXSD9
Say yes here to build support for the Kionix KXSD9 accelerometer.
Currently this only supports the device via an SPI interface.
+ To compile this driver as a module, choose M here: the module
+ will be called kxsd9.
+
config MMA8452
tristate "Freescale MMA8452Q Accelerometer Driver"
depends on I2C
@@ -105,4 +111,29 @@ config KXCJK1013
To compile this driver as a module, choose M here: the module will
be called kxcjk-1013.
+config MMA9551_CORE
+ tristate
+
+config MMA9551
+ tristate "Freescale MMA9551L Intelligent Motion-Sensing Platform Driver"
+ depends on I2C
+ select MMA9551_CORE
+
+ help
+ Say yes here to build support for the Freescale MMA9551L
+ Intelligent Motion-Sensing Platform Driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mma9551.
+
+config MMA9553
+ tristate "Freescale MMA9553L Intelligent Pedometer Platform Driver"
+ depends on I2C
+ select MMA9551_CORE
+ help
+ Say yes here to build support for the Freescale MMA9553L
+ Intelligent Pedometer Platform Driver.
+
+ To compile this driver as a module, choose M here: the module
+ will be called mma9553.
endmenu
diff --git a/drivers/iio/accel/Makefile b/drivers/iio/accel/Makefile
index a593996c6539..99d89e46cad1 100644
--- a/drivers/iio/accel/Makefile
+++ b/drivers/iio/accel/Makefile
@@ -10,6 +10,12 @@ obj-$(CONFIG_KXCJK1013) += kxcjk-1013.o
obj-$(CONFIG_KXSD9) += kxsd9.o
obj-$(CONFIG_MMA8452) += mma8452.o
+obj-$(CONFIG_MMA9551_CORE) += mma9551_core.o
+obj-$(CONFIG_MMA9551) += mma9551.o
+obj-$(CONFIG_MMA9553) += mma9553.o
+
+obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_accel_sensor.o
+
obj-$(CONFIG_IIO_ST_ACCEL_3AXIS) += st_accel.o
st_accel-y := st_accel_core.o
st_accel-$(CONFIG_IIO_BUFFER) += st_accel_buffer.o
diff --git a/drivers/iio/accel/hid-sensor-accel-3d.c b/drivers/iio/accel/hid-sensor-accel-3d.c
index d5d95317003a..df6a593bd4bd 100644
--- a/drivers/iio/accel/hid-sensor-accel-3d.c
+++ b/drivers/iio/accel/hid-sensor-accel-3d.c
@@ -111,19 +111,12 @@ static int accel_3d_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
switch (mask) {
case 0:
- poll_value = hid_sensor_read_poll_value(
- &accel_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
-
hid_sensor_power_state(&accel_state->common_attributes, true);
- msleep_interruptible(poll_value * 2);
report_id = accel_state->accel[chan->scan_index].report_id;
address = accel_3d_addresses[chan->scan_index];
if (report_id >= 0)
@@ -419,6 +412,7 @@ static struct platform_driver hid_accel_3d_platform_driver = {
.id_table = hid_accel_3d_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_accel_3d_probe,
.remove = hid_accel_3d_remove,
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index da2fe93739a2..567de269cc00 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -108,6 +108,7 @@ struct kxcjk1013_data {
bool motion_trigger_on;
int64_t timestamp;
enum kx_chipset chipset;
+ bool is_smo8500_device;
};
enum kxcjk1013_axis {
@@ -377,6 +378,7 @@ static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
{
+#ifdef CONFIG_PM
int ret;
if (on)
@@ -388,8 +390,11 @@ static int kxcjk1013_set_power_state(struct kxcjk1013_data *data, bool on)
if (ret < 0) {
dev_err(&data->client->dev,
"Failed: kxcjk1013_set_power_state for %d\n", on);
+ if (on)
+ pm_runtime_put_noidle(&data->client->dev);
return ret;
}
+#endif
return 0;
}
@@ -858,6 +863,8 @@ static int kxcjk1013_write_event_config(struct iio_dev *indio_dev,
ret = kxcjk1013_setup_any_motion_interrupt(data, state);
if (ret < 0) {
+ kxcjk1013_set_power_state(data, false);
+ data->ev_enable_state = 0;
mutex_unlock(&data->mutex);
return ret;
}
@@ -1008,6 +1015,7 @@ static int kxcjk1013_data_rdy_trigger_set_state(struct iio_trigger *trig,
else
ret = kxcjk1013_setup_new_data_interrupt(data, state);
if (ret < 0) {
+ kxcjk1013_set_power_state(data, false);
mutex_unlock(&data->mutex);
return ret;
}
@@ -1131,12 +1139,16 @@ static irqreturn_t kxcjk1013_data_rdy_trig_poll(int irq, void *private)
}
static const char *kxcjk1013_match_acpi_device(struct device *dev,
- enum kx_chipset *chipset)
+ enum kx_chipset *chipset,
+ bool *is_smo8500_device)
{
const struct acpi_device_id *id;
+
id = acpi_match_device(dev->driver->acpi_match_table, dev);
if (!id)
return NULL;
+ if (strcmp(id->id, "SMO8500") == 0)
+ *is_smo8500_device = true;
*chipset = (enum kx_chipset)id->driver_data;
return dev_name(dev);
@@ -1151,6 +1163,8 @@ static int kxcjk1013_gpio_probe(struct i2c_client *client,
if (!client)
return -EINVAL;
+ if (data->is_smo8500_device)
+ return -ENOTSUPP;
dev = &client->dev;
@@ -1200,7 +1214,8 @@ static int kxcjk1013_probe(struct i2c_client *client,
name = id->name;
} else if (ACPI_HANDLE(&client->dev)) {
name = kxcjk1013_match_acpi_device(&client->dev,
- &data->chipset);
+ &data->chipset,
+ &data->is_smo8500_device);
} else
return -ENODEV;
@@ -1228,21 +1243,25 @@ static int kxcjk1013_probe(struct i2c_client *client,
KXCJK1013_IRQ_NAME,
indio_dev);
if (ret)
- return ret;
+ goto err_poweroff;
data->dready_trig = devm_iio_trigger_alloc(&client->dev,
"%s-dev%d",
indio_dev->name,
indio_dev->id);
- if (!data->dready_trig)
- return -ENOMEM;
+ if (!data->dready_trig) {
+ ret = -ENOMEM;
+ goto err_poweroff;
+ }
data->motion_trig = devm_iio_trigger_alloc(&client->dev,
"%s-any-motion-dev%d",
indio_dev->name,
indio_dev->id);
- if (!data->motion_trig)
- return -ENOMEM;
+ if (!data->motion_trig) {
+ ret = -ENOMEM;
+ goto err_poweroff;
+ }
data->dready_trig->dev.parent = &client->dev;
data->dready_trig->ops = &kxcjk1013_trigger_ops;
@@ -1251,7 +1270,7 @@ static int kxcjk1013_probe(struct i2c_client *client,
iio_trigger_get(indio_dev->trig);
ret = iio_trigger_register(data->dready_trig);
if (ret)
- return ret;
+ goto err_poweroff;
data->motion_trig->dev.parent = &client->dev;
data->motion_trig->ops = &kxcjk1013_trigger_ops;
@@ -1300,6 +1319,8 @@ err_trigger_unregister:
iio_trigger_unregister(data->dready_trig);
if (data->motion_trig)
iio_trigger_unregister(data->motion_trig);
+err_poweroff:
+ kxcjk1013_set_mode(data, STANDBY);
return ret;
}
@@ -1349,10 +1370,7 @@ static int kxcjk1013_resume(struct device *dev)
int ret = 0;
mutex_lock(&data->mutex);
- /* Check, if the suspend occured while active */
- if (data->dready_trigger_on || data->motion_trigger_on ||
- data->ev_enable_state)
- ret = kxcjk1013_set_mode(data, OPERATION);
+ ret = kxcjk1013_set_mode(data, OPERATION);
mutex_unlock(&data->mutex);
return ret;
@@ -1364,8 +1382,14 @@ static int kxcjk1013_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
struct kxcjk1013_data *data = iio_priv(indio_dev);
+ int ret;
- return kxcjk1013_set_mode(data, STANDBY);
+ ret = kxcjk1013_set_mode(data, STANDBY);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "powering off device failed\n");
+ return -EAGAIN;
+ }
+ return 0;
}
static int kxcjk1013_runtime_resume(struct device *dev)
@@ -1399,6 +1423,7 @@ static const struct acpi_device_id kx_acpi_match[] = {
{"KXCJ1013", KXCJK1013},
{"KXCJ1008", KXCJ91008},
{"KXTJ1009", KXTJ21009},
+ {"SMO8500", KXCJ91008},
{ },
};
MODULE_DEVICE_TABLE(acpi, kx_acpi_match);
@@ -1407,6 +1432,7 @@ static const struct i2c_device_id kxcjk1013_id[] = {
{"kxcjk1013", KXCJK1013},
{"kxcj91008", KXCJ91008},
{"kxtj21009", KXTJ21009},
+ {"SMO8500", KXCJ91008},
{}
};
diff --git a/drivers/iio/accel/mma8452.c b/drivers/iio/accel/mma8452.c
index 3c12d4966376..5b80657883bb 100644
--- a/drivers/iio/accel/mma8452.c
+++ b/drivers/iio/accel/mma8452.c
@@ -111,7 +111,7 @@ static const int mma8452_samp_freq[8][2] = {
{6, 250000}, {1, 560000}
};
-/*
+/*
* Hardware has fullscale of -2G, -4G, -8G corresponding to raw value -2048
* The userspace interface uses m/s^2 and we declare micro units
* So scale factor is given by:
diff --git a/drivers/iio/accel/mma9551.c b/drivers/iio/accel/mma9551.c
new file mode 100644
index 000000000000..46c38351c6a3
--- /dev/null
+++ b/drivers/iio/accel/mma9551.c
@@ -0,0 +1,637 @@
+/*
+ * Freescale MMA9551L Intelligent Motion-Sensing Platform driver
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+#define MMA9551_DRV_NAME "mma9551"
+#define MMA9551_IRQ_NAME "mma9551_event"
+#define MMA9551_GPIO_NAME "mma9551_int"
+#define MMA9551_GPIO_COUNT 4
+
+/* Tilt application (inclination in IIO terms). */
+#define MMA9551_TILT_XZ_ANG_REG 0x00
+#define MMA9551_TILT_YZ_ANG_REG 0x01
+#define MMA9551_TILT_XY_ANG_REG 0x02
+#define MMA9551_TILT_ANGFLG BIT(7)
+#define MMA9551_TILT_QUAD_REG 0x03
+#define MMA9551_TILT_XY_QUAD_SHIFT 0
+#define MMA9551_TILT_YZ_QUAD_SHIFT 2
+#define MMA9551_TILT_XZ_QUAD_SHIFT 4
+#define MMA9551_TILT_CFG_REG 0x01
+#define MMA9551_TILT_ANG_THRESH_MASK GENMASK(3, 0)
+
+#define MMA9551_DEFAULT_SAMPLE_RATE 122 /* Hz */
+
+/* Tilt events are mapped to the first three GPIO pins. */
+enum mma9551_tilt_axis {
+ mma9551_x = 0,
+ mma9551_y,
+ mma9551_z,
+};
+
+struct mma9551_data {
+ struct i2c_client *client;
+ struct mutex mutex;
+ int event_enabled[3];
+ int irqs[MMA9551_GPIO_COUNT];
+};
+
+static int mma9551_read_incli_chan(struct i2c_client *client,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ u8 quad_shift, angle, quadrant;
+ u16 reg_addr;
+ int ret;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ reg_addr = MMA9551_TILT_YZ_ANG_REG;
+ quad_shift = MMA9551_TILT_YZ_QUAD_SHIFT;
+ break;
+ case IIO_MOD_Y:
+ reg_addr = MMA9551_TILT_XZ_ANG_REG;
+ quad_shift = MMA9551_TILT_XZ_QUAD_SHIFT;
+ break;
+ case IIO_MOD_Z:
+ reg_addr = MMA9551_TILT_XY_ANG_REG;
+ quad_shift = MMA9551_TILT_XY_QUAD_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = mma9551_set_power_state(client, true);
+ if (ret < 0)
+ return ret;
+
+ ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
+ reg_addr, &angle);
+ if (ret < 0)
+ goto out_poweroff;
+
+ ret = mma9551_read_status_byte(client, MMA9551_APPID_TILT,
+ MMA9551_TILT_QUAD_REG, &quadrant);
+ if (ret < 0)
+ goto out_poweroff;
+
+ angle &= ~MMA9551_TILT_ANGFLG;
+ quadrant = (quadrant >> quad_shift) & 0x03;
+
+ if (quadrant == 1 || quadrant == 3)
+ *val = 90 * (quadrant + 1) - angle;
+ else
+ *val = angle + 90 * quadrant;
+
+ ret = IIO_VAL_INT;
+
+out_poweroff:
+ mma9551_set_power_state(client, false);
+ return ret;
+}
+
+static int mma9551_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_INCLI:
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_incli_chan(data->client, chan, val);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_accel_chan(data->client,
+ chan, val, val2);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ return mma9551_read_accel_scale(val, val2);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9551_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct mma9551_data *data = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_INCLI:
+ /* IIO counts axes from 1, because IIO_NO_MOD is 0. */
+ return data->event_enabled[chan->channel2 - 1];
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9551_config_incli_event(struct iio_dev *indio_dev,
+ enum iio_modifier axis,
+ int state)
+{
+ struct mma9551_data *data = iio_priv(indio_dev);
+ enum mma9551_tilt_axis mma_axis;
+ int ret;
+
+ /* IIO counts axes from 1, because IIO_NO_MOD is 0. */
+ mma_axis = axis - 1;
+
+ if (data->event_enabled[mma_axis] == state)
+ return 0;
+
+ if (state == 0) {
+ ret = mma9551_gpio_config(data->client,
+ (enum mma9551_gpio_pin)mma_axis,
+ MMA9551_APPID_NONE, 0, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = mma9551_set_power_state(data->client, false);
+ if (ret < 0)
+ return ret;
+ } else {
+ int bitnum;
+
+ /* Bit 7 of each angle register holds the angle flag. */
+ switch (axis) {
+ case IIO_MOD_X:
+ bitnum = 7 + 8 * MMA9551_TILT_YZ_ANG_REG;
+ break;
+ case IIO_MOD_Y:
+ bitnum = 7 + 8 * MMA9551_TILT_XZ_ANG_REG;
+ break;
+ case IIO_MOD_Z:
+ bitnum = 7 + 8 * MMA9551_TILT_XY_ANG_REG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ ret = mma9551_set_power_state(data->client, true);
+ if (ret < 0)
+ return ret;
+
+ ret = mma9551_gpio_config(data->client,
+ (enum mma9551_gpio_pin)mma_axis,
+ MMA9551_APPID_TILT, bitnum, 0);
+ if (ret < 0) {
+ mma9551_set_power_state(data->client, false);
+ return ret;
+ }
+ }
+
+ data->event_enabled[mma_axis] = state;
+
+ return ret;
+}
+
+static int mma9551_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (chan->type) {
+ case IIO_INCLI:
+ mutex_lock(&data->mutex);
+ ret = mma9551_config_incli_event(indio_dev,
+ chan->channel2, state);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9551_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (chan->type) {
+ case IIO_INCLI:
+ if (val2 != 0 || val < 1 || val > 10)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = mma9551_update_config_bits(data->client,
+ MMA9551_APPID_TILT,
+ MMA9551_TILT_CFG_REG,
+ MMA9551_TILT_ANG_THRESH_MASK,
+ val);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9551_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+ u8 tmp;
+
+ switch (chan->type) {
+ case IIO_INCLI:
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_config_byte(data->client,
+ MMA9551_APPID_TILT,
+ MMA9551_TILT_CFG_REG, &tmp);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+ *val = tmp & MMA9551_TILT_ANG_THRESH_MASK;
+ *val2 = 0;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct iio_event_spec mma9551_incli_event = {
+ .type = IIO_EV_TYPE_ROC,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ .mask_shared_by_type = BIT(IIO_EV_INFO_VALUE),
+};
+
+#define MMA9551_INCLI_CHANNEL(axis) { \
+ .type = IIO_INCLI, \
+ .modified = 1, \
+ .channel2 = axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+ .event_spec = &mma9551_incli_event, \
+ .num_event_specs = 1, \
+}
+
+static const struct iio_chan_spec mma9551_channels[] = {
+ MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
+ MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
+ MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
+
+ MMA9551_INCLI_CHANNEL(IIO_MOD_X),
+ MMA9551_INCLI_CHANNEL(IIO_MOD_Y),
+ MMA9551_INCLI_CHANNEL(IIO_MOD_Z),
+};
+
+static const struct iio_info mma9551_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = mma9551_read_raw,
+ .read_event_config = mma9551_read_event_config,
+ .write_event_config = mma9551_write_event_config,
+ .read_event_value = mma9551_read_event_value,
+ .write_event_value = mma9551_write_event_value,
+};
+
+static irqreturn_t mma9551_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int i, ret, mma_axis = -1;
+ u16 reg;
+ u8 val;
+
+ mutex_lock(&data->mutex);
+
+ for (i = 0; i < 3; i++)
+ if (irq == data->irqs[i]) {
+ mma_axis = i;
+ break;
+ }
+
+ if (mma_axis == -1) {
+ /* IRQ was triggered on 4th line, which we don't use. */
+ dev_warn(&data->client->dev,
+ "irq triggered on unused line %d\n", data->irqs[3]);
+ goto out;
+ }
+
+ switch (mma_axis) {
+ case mma9551_x:
+ reg = MMA9551_TILT_YZ_ANG_REG;
+ break;
+ case mma9551_y:
+ reg = MMA9551_TILT_XZ_ANG_REG;
+ break;
+ case mma9551_z:
+ reg = MMA9551_TILT_XY_ANG_REG;
+ break;
+ }
+
+ /*
+ * Read the angle even though we don't use it, otherwise we
+ * won't get any further interrupts.
+ */
+ ret = mma9551_read_status_byte(data->client, MMA9551_APPID_TILT,
+ reg, &val);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "error %d reading tilt register in IRQ\n", ret);
+ goto out;
+ }
+
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_INCLI, 0, (mma_axis + 1),
+ IIO_EV_TYPE_ROC, IIO_EV_DIR_RISING),
+ iio_get_time_ns());
+
+out:
+ mutex_unlock(&data->mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int mma9551_init(struct mma9551_data *data)
+{
+ int ret;
+
+ ret = mma9551_read_version(data->client);
+ if (ret)
+ return ret;
+
+ return mma9551_set_device_state(data->client, true);
+}
+
+static int mma9551_gpio_probe(struct iio_dev *indio_dev)
+{
+ struct gpio_desc *gpio;
+ int i, ret;
+ struct mma9551_data *data = iio_priv(indio_dev);
+ struct device *dev = &data->client->dev;
+
+ for (i = 0; i < MMA9551_GPIO_COUNT; i++) {
+ gpio = devm_gpiod_get_index(dev, MMA9551_GPIO_NAME, i);
+ if (IS_ERR(gpio)) {
+ dev_err(dev, "acpi gpio get index failed\n");
+ return PTR_ERR(gpio);
+ }
+
+ ret = gpiod_direction_input(gpio);
+ if (ret)
+ return ret;
+
+ data->irqs[i] = gpiod_to_irq(gpio);
+ ret = devm_request_threaded_irq(dev, data->irqs[i],
+ NULL, mma9551_event_handler,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ MMA9551_IRQ_NAME, indio_dev);
+ if (ret < 0) {
+ dev_err(dev, "request irq %d failed\n", data->irqs[i]);
+ return ret;
+ }
+
+ dev_dbg(dev, "gpio resource, no:%d irq:%d\n",
+ desc_to_gpio(gpio), data->irqs[i]);
+ }
+
+ return 0;
+}
+
+static const char *mma9551_match_acpi_device(struct device *dev)
+{
+ const struct acpi_device_id *id;
+
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return NULL;
+
+ return dev_name(dev);
+}
+
+static int mma9551_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mma9551_data *data;
+ struct iio_dev *indio_dev;
+ const char *name = NULL;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ if (id)
+ name = id->name;
+ else if (ACPI_HANDLE(&client->dev))
+ name = mma9551_match_acpi_device(&client->dev);
+
+ ret = mma9551_init(data);
+ if (ret < 0)
+ return ret;
+
+ mutex_init(&data->mutex);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = mma9551_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mma9551_channels);
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mma9551_info;
+
+ ret = mma9551_gpio_probe(indio_dev);
+ if (ret < 0)
+ goto out_poweroff;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto out_poweroff;
+ }
+
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret < 0)
+ goto out_iio_unregister;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev,
+ MMA9551_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ return 0;
+
+out_iio_unregister:
+ iio_device_unregister(indio_dev);
+out_poweroff:
+ mma9551_set_device_state(client, false);
+
+ return ret;
+}
+
+static int mma9551_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct mma9551_data *data = iio_priv(indio_dev);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
+ iio_device_unregister(indio_dev);
+ mutex_lock(&data->mutex);
+ mma9551_set_device_state(data->client, false);
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mma9551_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_device_state(data->client, false);
+ mutex_unlock(&data->mutex);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "powering off device failed\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int mma9551_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = mma9551_set_device_state(data->client, true);
+ if (ret < 0)
+ return ret;
+
+ mma9551_sleep(MMA9551_DEFAULT_SAMPLE_RATE);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int mma9551_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_device_state(data->client, false);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int mma9551_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9551_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_device_state(data->client, true);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops mma9551_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mma9551_suspend, mma9551_resume)
+ SET_RUNTIME_PM_OPS(mma9551_runtime_suspend,
+ mma9551_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id mma9551_acpi_match[] = {
+ {"MMA9551", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, mma9551_acpi_match);
+
+static const struct i2c_device_id mma9551_id[] = {
+ {"mma9551", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, mma9551_id);
+
+static struct i2c_driver mma9551_driver = {
+ .driver = {
+ .name = MMA9551_DRV_NAME,
+ .acpi_match_table = ACPI_PTR(mma9551_acpi_match),
+ .pm = &mma9551_pm_ops,
+ },
+ .probe = mma9551_probe,
+ .remove = mma9551_remove,
+ .id_table = mma9551_id,
+};
+
+module_i2c_driver(mma9551_driver);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA9551L motion-sensing platform driver");
diff --git a/drivers/iio/accel/mma9551_core.c b/drivers/iio/accel/mma9551_core.c
new file mode 100644
index 000000000000..7f55a6d7cd03
--- /dev/null
+++ b/drivers/iio/accel/mma9551_core.c
@@ -0,0 +1,798 @@
+/*
+ * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/iio/iio.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+/* Command masks for mailbox write command */
+#define MMA9551_CMD_READ_VERSION_INFO 0x00
+#define MMA9551_CMD_READ_CONFIG 0x10
+#define MMA9551_CMD_WRITE_CONFIG 0x20
+#define MMA9551_CMD_READ_STATUS 0x30
+
+/* Mailbox read command */
+#define MMA9551_RESPONSE_COCO BIT(7)
+
+/* Error-Status codes returned in mailbox read command */
+#define MMA9551_MCI_ERROR_NONE 0x00
+#define MMA9551_MCI_ERROR_PARAM 0x04
+#define MMA9551_MCI_INVALID_COUNT 0x19
+#define MMA9551_MCI_ERROR_COMMAND 0x1C
+#define MMA9551_MCI_ERROR_INVALID_LENGTH 0x21
+#define MMA9551_MCI_ERROR_FIFO_BUSY 0x22
+#define MMA9551_MCI_ERROR_FIFO_ALLOCATED 0x23
+#define MMA9551_MCI_ERROR_FIFO_OVERSIZE 0x24
+
+/* GPIO Application */
+#define MMA9551_GPIO_POL_MSB 0x08
+#define MMA9551_GPIO_POL_LSB 0x09
+
+/* Sleep/Wake application */
+#define MMA9551_SLEEP_CFG 0x06
+#define MMA9551_SLEEP_CFG_SNCEN BIT(0)
+#define MMA9551_SLEEP_CFG_FLEEN BIT(1)
+#define MMA9551_SLEEP_CFG_SCHEN BIT(2)
+
+/* AFE application */
+#define MMA9551_AFE_X_ACCEL_REG 0x00
+#define MMA9551_AFE_Y_ACCEL_REG 0x02
+#define MMA9551_AFE_Z_ACCEL_REG 0x04
+
+/* Reset/Suspend/Clear application */
+#define MMA9551_RSC_RESET 0x00
+#define MMA9551_RSC_OFFSET(mask) (3 - (ffs(mask) - 1) / 8)
+#define MMA9551_RSC_VAL(mask) (mask >> (((ffs(mask) - 1) / 8) * 8))
+
+/*
+ * A response is composed of:
+ * - control registers: MB0-3
+ * - data registers: MB4-31
+ *
+ * A request is composed of:
+ * - mbox to write to (always 0)
+ * - control registers: MB1-4
+ * - data registers: MB5-31
+ */
+#define MMA9551_MAILBOX_CTRL_REGS 4
+#define MMA9551_MAX_MAILBOX_DATA_REGS 28
+#define MMA9551_MAILBOX_REGS 32
+
+#define MMA9551_I2C_READ_RETRIES 5
+#define MMA9551_I2C_READ_DELAY 50 /* us */
+
+struct mma9551_mbox_request {
+ u8 start_mbox; /* Always 0. */
+ u8 app_id;
+ /*
+ * See Section 5.3.1 of the MMA955xL Software Reference Manual.
+ *
+ * Bit 7: reserved, always 0
+ * Bits 6-4: command
+ * Bits 3-0: upper bits of register offset
+ */
+ u8 cmd_off;
+ u8 lower_off;
+ u8 nbytes;
+ u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS - 1];
+} __packed;
+
+struct mma9551_mbox_response {
+ u8 app_id;
+ /*
+ * See Section 5.3.3 of the MMA955xL Software Reference Manual.
+ *
+ * Bit 7: COCO
+ * Bits 6-0: Error code.
+ */
+ u8 coco_err;
+ u8 nbytes;
+ u8 req_bytes;
+ u8 buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+} __packed;
+
+struct mma9551_version_info {
+ __be32 device_id;
+ u8 rom_version[2];
+ u8 fw_version[2];
+ u8 hw_version[2];
+ u8 fw_build[2];
+};
+
+static int mma9551_transfer(struct i2c_client *client,
+ u8 app_id, u8 command, u16 offset,
+ u8 *inbytes, int num_inbytes,
+ u8 *outbytes, int num_outbytes)
+{
+ struct mma9551_mbox_request req;
+ struct mma9551_mbox_response rsp;
+ struct i2c_msg in, out;
+ u8 req_len, err_code;
+ int ret, retries;
+
+ if (offset >= 1 << 12) {
+ dev_err(&client->dev, "register offset too large\n");
+ return -EINVAL;
+ }
+
+ req_len = 1 + MMA9551_MAILBOX_CTRL_REGS + num_inbytes;
+ req.start_mbox = 0;
+ req.app_id = app_id;
+ req.cmd_off = command | (offset >> 8);
+ req.lower_off = offset;
+
+ if (command == MMA9551_CMD_WRITE_CONFIG)
+ req.nbytes = num_inbytes;
+ else
+ req.nbytes = num_outbytes;
+ if (num_inbytes)
+ memcpy(req.buf, inbytes, num_inbytes);
+
+ out.addr = client->addr;
+ out.flags = 0;
+ out.len = req_len;
+ out.buf = (u8 *)&req;
+
+ ret = i2c_transfer(client->adapter, &out, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c write failed\n");
+ return ret;
+ }
+
+ retries = MMA9551_I2C_READ_RETRIES;
+ do {
+ udelay(MMA9551_I2C_READ_DELAY);
+
+ in.addr = client->addr;
+ in.flags = I2C_M_RD;
+ in.len = sizeof(rsp);
+ in.buf = (u8 *)&rsp;
+
+ ret = i2c_transfer(client->adapter, &in, 1);
+ if (ret < 0) {
+ dev_err(&client->dev, "i2c read failed\n");
+ return ret;
+ }
+
+ if (rsp.coco_err & MMA9551_RESPONSE_COCO)
+ break;
+ } while (--retries > 0);
+
+ if (retries == 0) {
+ dev_err(&client->dev,
+ "timed out while waiting for command response\n");
+ return -ETIMEDOUT;
+ }
+
+ if (rsp.app_id != app_id) {
+ dev_err(&client->dev,
+ "app_id mismatch in response got %02x expected %02x\n",
+ rsp.app_id, app_id);
+ return -EINVAL;
+ }
+
+ err_code = rsp.coco_err & ~MMA9551_RESPONSE_COCO;
+ if (err_code != MMA9551_MCI_ERROR_NONE) {
+ dev_err(&client->dev, "read returned error %x\n", err_code);
+ return -EINVAL;
+ }
+
+ if (rsp.nbytes != rsp.req_bytes) {
+ dev_err(&client->dev,
+ "output length mismatch got %d expected %d\n",
+ rsp.nbytes, rsp.req_bytes);
+ return -EINVAL;
+ }
+
+ if (num_outbytes)
+ memcpy(outbytes, rsp.buf, num_outbytes);
+
+ return 0;
+}
+
+/**
+ * mma9551_read_config_byte() - read 1 configuration byte
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @val: Pointer to store value read
+ *
+ * Read one configuration byte from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed
+ * by one or more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 *val)
+{
+ return mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+ reg, NULL, 0, val, 1);
+}
+EXPORT_SYMBOL(mma9551_read_config_byte);
+
+/**
+ * mma9551_write_config_byte() - write 1 configuration byte
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @val: Value to write
+ *
+ * Write one configuration byte from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 val)
+{
+ return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
+ &val, 1, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_byte);
+
+/**
+ * mma9551_read_status_byte() - read 1 status byte
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @val: Pointer to store value read
+ *
+ * Read one status byte from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 *val)
+{
+ return mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+ reg, NULL, 0, val, 1);
+}
+EXPORT_SYMBOL(mma9551_read_status_byte);
+
+/**
+ * mma9551_read_config_word() - read 1 config word
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @val: Pointer to store value read
+ *
+ * Read one configuration word from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
+ u16 reg, u16 *val)
+{
+ int ret;
+ __be16 v;
+
+ ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+ reg, NULL, 0, (u8 *)&v, 2);
+ *val = be16_to_cpu(v);
+
+ return ret;
+}
+EXPORT_SYMBOL(mma9551_read_config_word);
+
+/**
+ * mma9551_write_config_word() - write 1 config word
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @val: Value to write
+ *
+ * Write one configuration word from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
+ u16 reg, u16 val)
+{
+ __be16 v = cpu_to_be16(val);
+
+ return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG, reg,
+ (u8 *) &v, 2, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_word);
+
+/**
+ * mma9551_read_status_word() - read 1 status word
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @val: Pointer to store value read
+ *
+ * Read one status word from the device using MMA955xL command format.
+ * Commands to the MMA955xL platform consist of a write followed by one or
+ * more reads.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
+ u16 reg, u16 *val)
+{
+ int ret;
+ __be16 v;
+
+ ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+ reg, NULL, 0, (u8 *)&v, 2);
+ *val = be16_to_cpu(v);
+
+ return ret;
+}
+EXPORT_SYMBOL(mma9551_read_status_word);
+
+/**
+ * mma9551_read_config_words() - read multiple config words
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @len: Length of array to read in bytes
+ * @val: Array of words to read
+ *
+ * Read multiple configuration registers (word-sized registers).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 len, u16 *buf)
+{
+ int ret, i;
+ int len_words = len / sizeof(u16);
+ __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+ ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_CONFIG,
+ reg, NULL, 0, (u8 *) be_buf, len);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < len_words; i++)
+ buf[i] = be16_to_cpu(be_buf[i]);
+
+ return 0;
+}
+EXPORT_SYMBOL(mma9551_read_config_words);
+
+/**
+ * mma9551_read_status_words() - read multiple status words
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @len: Length of array to read in bytes
+ * @val: Array of words to read
+ *
+ * Read multiple status registers (word-sized registers).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 len, u16 *buf)
+{
+ int ret, i;
+ int len_words = len / sizeof(u16);
+ __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+ ret = mma9551_transfer(client, app_id, MMA9551_CMD_READ_STATUS,
+ reg, NULL, 0, (u8 *) be_buf, len);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < len_words; i++)
+ buf[i] = be16_to_cpu(be_buf[i]);
+
+ return 0;
+}
+EXPORT_SYMBOL(mma9551_read_status_words);
+
+/**
+ * mma9551_write_config_words() - write multiple config words
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @len: Length of array to write in bytes
+ * @val: Array of words to write
+ *
+ * Write multiple configuration registers (word-sized registers).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 len, u16 *buf)
+{
+ int i;
+ int len_words = len / sizeof(u16);
+ __be16 be_buf[MMA9551_MAX_MAILBOX_DATA_REGS];
+
+ for (i = 0; i < len_words; i++)
+ be_buf[i] = cpu_to_be16(buf[i]);
+
+ return mma9551_transfer(client, app_id, MMA9551_CMD_WRITE_CONFIG,
+ reg, (u8 *) be_buf, len, NULL, 0);
+}
+EXPORT_SYMBOL(mma9551_write_config_words);
+
+/**
+ * mma9551_update_config_bits() - update bits in register
+ * @client: I2C client
+ * @app_id: Application ID
+ * @reg: Application register
+ * @mask: Mask for the bits to update
+ * @val: Value of the bits to update
+ *
+ * Update bits in the given register using a bit mask.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 mask, u8 val)
+{
+ int ret;
+ u8 tmp, orig;
+
+ ret = mma9551_read_config_byte(client, app_id, reg, &orig);
+ if (ret < 0)
+ return ret;
+
+ tmp = orig & ~mask;
+ tmp |= val & mask;
+
+ if (tmp == orig)
+ return 0;
+
+ return mma9551_write_config_byte(client, app_id, reg, tmp);
+}
+EXPORT_SYMBOL(mma9551_update_config_bits);
+
+/**
+ * mma9551_gpio_config() - configure gpio
+ * @client: I2C client
+ * @pin: GPIO pin to configure
+ * @app_id: Application ID
+ * @bitnum: Bit number of status register being assigned to the GPIO pin.
+ * @polarity: The polarity parameter is described in section 6.2.2, page 66,
+ * of the Software Reference Manual. Basically, polarity=0 means
+ * the interrupt line has the same value as the selected bit,
+ * while polarity=1 means the line is inverted.
+ *
+ * Assign a bit from an application’s status register to a specific GPIO pin.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
+ u8 app_id, u8 bitnum, int polarity)
+{
+ u8 reg, pol_mask, pol_val;
+ int ret;
+
+ if (pin > mma9551_gpio_max) {
+ dev_err(&client->dev, "bad GPIO pin\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Pin 6 is configured by regs 0x00 and 0x01, pin 7 by 0x02 and
+ * 0x03, and so on.
+ */
+ reg = pin * 2;
+
+ ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
+ reg, app_id);
+ if (ret < 0) {
+ dev_err(&client->dev, "error setting GPIO app_id\n");
+ return ret;
+ }
+
+ ret = mma9551_write_config_byte(client, MMA9551_APPID_GPIO,
+ reg + 1, bitnum);
+ if (ret < 0) {
+ dev_err(&client->dev, "error setting GPIO bit number\n");
+ return ret;
+ }
+
+ switch (pin) {
+ case mma9551_gpio6:
+ reg = MMA9551_GPIO_POL_LSB;
+ pol_mask = 1 << 6;
+ break;
+ case mma9551_gpio7:
+ reg = MMA9551_GPIO_POL_LSB;
+ pol_mask = 1 << 7;
+ break;
+ case mma9551_gpio8:
+ reg = MMA9551_GPIO_POL_MSB;
+ pol_mask = 1 << 0;
+ break;
+ case mma9551_gpio9:
+ reg = MMA9551_GPIO_POL_MSB;
+ pol_mask = 1 << 1;
+ break;
+ }
+ pol_val = polarity ? pol_mask : 0;
+
+ ret = mma9551_update_config_bits(client, MMA9551_APPID_GPIO, reg,
+ pol_mask, pol_val);
+ if (ret < 0)
+ dev_err(&client->dev, "error setting GPIO polarity\n");
+
+ return ret;
+}
+EXPORT_SYMBOL(mma9551_gpio_config);
+
+/**
+ * mma9551_read_version() - read device version information
+ * @client: I2C client
+ *
+ * Read version information and print device id and firmware version.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_read_version(struct i2c_client *client)
+{
+ struct mma9551_version_info info;
+ int ret;
+
+ ret = mma9551_transfer(client, MMA9551_APPID_VERSION, 0x00, 0x00,
+ NULL, 0, (u8 *)&info, sizeof(info));
+ if (ret < 0)
+ return ret;
+
+ dev_info(&client->dev, "device ID 0x%x, firmware version %02x.%02x\n",
+ be32_to_cpu(info.device_id), info.fw_version[0],
+ info.fw_version[1]);
+
+ return 0;
+}
+EXPORT_SYMBOL(mma9551_read_version);
+
+/**
+ * mma9551_set_device_state() - sets HW power mode
+ * @client: I2C client
+ * @enable: Use true to power on device, false to cause the device
+ * to enter sleep.
+ *
+ * Set power on/off for device using the Sleep/Wake Application.
+ * When enable is true, power on chip and enable doze mode.
+ * When enable is false, enter sleep mode (device remains in the
+ * lowest-power mode).
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_set_device_state(struct i2c_client *client, bool enable)
+{
+ return mma9551_update_config_bits(client, MMA9551_APPID_SLEEP_WAKE,
+ MMA9551_SLEEP_CFG,
+ MMA9551_SLEEP_CFG_SNCEN |
+ MMA9551_SLEEP_CFG_FLEEN |
+ MMA9551_SLEEP_CFG_SCHEN,
+ enable ? MMA9551_SLEEP_CFG_SCHEN |
+ MMA9551_SLEEP_CFG_FLEEN :
+ MMA9551_SLEEP_CFG_SNCEN);
+}
+EXPORT_SYMBOL(mma9551_set_device_state);
+
+/**
+ * mma9551_set_power_state() - sets runtime PM state
+ * @client: I2C client
+ * @on: Use true to power on device, false to power off
+ *
+ * Resume or suspend the device using Runtime PM.
+ * The device will suspend after the autosuspend delay.
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_set_power_state(struct i2c_client *client, bool on)
+{
+#ifdef CONFIG_PM
+ int ret;
+
+ if (on)
+ ret = pm_runtime_get_sync(&client->dev);
+ else {
+ pm_runtime_mark_last_busy(&client->dev);
+ ret = pm_runtime_put_autosuspend(&client->dev);
+ }
+
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "failed to change power state to %d\n", on);
+ if (on)
+ pm_runtime_put_noidle(&client->dev);
+
+ return ret;
+ }
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL(mma9551_set_power_state);
+
+/**
+ * mma9551_sleep() - sleep
+ * @freq: Application frequency
+ *
+ * Firmware applications run at a certain frequency on the
+ * device. Sleep for one application cycle to make sure the
+ * application had time to run once and initialize set values.
+ */
+void mma9551_sleep(int freq)
+{
+ int sleep_val = 1000 / freq;
+
+ if (sleep_val < 20)
+ usleep_range(sleep_val * 1000, 20000);
+ else
+ msleep_interruptible(sleep_val);
+}
+EXPORT_SYMBOL(mma9551_sleep);
+
+/**
+ * mma9551_read_accel_chan() - read accelerometer channel
+ * @client: I2C client
+ * @chan: IIO channel
+ * @val: Pointer to the accelerometer value read
+ * @val2: Unused
+ *
+ * Read accelerometer value for the specified channel.
+ *
+ * Locking note: This function must be called with the device lock held.
+ * Locking is not handled inside the function. Callers should ensure they
+ * serialize access to the HW.
+ *
+ * Returns: IIO_VAL_INT on success, negative value on failure.
+ */
+int mma9551_read_accel_chan(struct i2c_client *client,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2)
+{
+ u16 reg_addr;
+ s16 raw_accel;
+ int ret;
+
+ switch (chan->channel2) {
+ case IIO_MOD_X:
+ reg_addr = MMA9551_AFE_X_ACCEL_REG;
+ break;
+ case IIO_MOD_Y:
+ reg_addr = MMA9551_AFE_Y_ACCEL_REG;
+ break;
+ case IIO_MOD_Z:
+ reg_addr = MMA9551_AFE_Z_ACCEL_REG;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = mma9551_set_power_state(client, true);
+ if (ret < 0)
+ return ret;
+
+ ret = mma9551_read_status_word(client, MMA9551_APPID_AFE,
+ reg_addr, &raw_accel);
+ if (ret < 0)
+ goto out_poweroff;
+
+ *val = raw_accel;
+
+ ret = IIO_VAL_INT;
+
+out_poweroff:
+ mma9551_set_power_state(client, false);
+ return ret;
+}
+EXPORT_SYMBOL(mma9551_read_accel_chan);
+
+/**
+ * mma9551_read_accel_scale() - read accelerometer scale
+ * @val: Pointer to the accelerometer scale (int value)
+ * @val2: Pointer to the accelerometer scale (micro value)
+ *
+ * Read accelerometer scale.
+ *
+ * Returns: IIO_VAL_INT_PLUS_MICRO.
+ */
+int mma9551_read_accel_scale(int *val, int *val2)
+{
+ *val = 0;
+ *val2 = 2440;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+EXPORT_SYMBOL(mma9551_read_accel_scale);
+
+/**
+ * mma9551_app_reset() - reset application
+ * @client: I2C client
+ * @app_mask: Application to reset
+ *
+ * Reset the given application (using the Reset/Suspend/Clear
+ * Control Application)
+ *
+ * Returns: 0 on success, negative value on failure.
+ */
+int mma9551_app_reset(struct i2c_client *client, u32 app_mask)
+{
+ return mma9551_write_config_byte(client, MMA9551_APPID_RCS,
+ MMA9551_RSC_RESET +
+ MMA9551_RSC_OFFSET(app_mask),
+ MMA9551_RSC_VAL(app_mask));
+}
+EXPORT_SYMBOL(mma9551_app_reset);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA955xL sensors core");
diff --git a/drivers/iio/accel/mma9551_core.h b/drivers/iio/accel/mma9551_core.h
new file mode 100644
index 000000000000..edaa56b1078e
--- /dev/null
+++ b/drivers/iio/accel/mma9551_core.h
@@ -0,0 +1,81 @@
+/*
+ * Common code for Freescale MMA955x Intelligent Sensor Platform drivers
+ * 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 _MMA9551_CORE_H_
+#define _MMA9551_CORE_H_
+
+/* Applications IDs */
+#define MMA9551_APPID_VERSION 0x00
+#define MMA9551_APPID_GPIO 0x03
+#define MMA9551_APPID_AFE 0x06
+#define MMA9551_APPID_TILT 0x0B
+#define MMA9551_APPID_SLEEP_WAKE 0x12
+#define MMA9551_APPID_PEDOMETER 0x15
+#define MMA9551_APPID_RCS 0x17
+#define MMA9551_APPID_NONE 0xff
+
+/* Reset/Suspend/Clear application app masks */
+#define MMA9551_RSC_PED BIT(21)
+
+#define MMA9551_AUTO_SUSPEND_DELAY_MS 2000
+
+enum mma9551_gpio_pin {
+ mma9551_gpio6 = 0,
+ mma9551_gpio7,
+ mma9551_gpio8,
+ mma9551_gpio9,
+ mma9551_gpio_max = mma9551_gpio9,
+};
+
+#define MMA9551_ACCEL_CHANNEL(axis) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE), \
+}
+
+int mma9551_read_config_byte(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 *val);
+int mma9551_write_config_byte(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 val);
+int mma9551_read_status_byte(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 *val);
+int mma9551_read_config_word(struct i2c_client *client, u8 app_id,
+ u16 reg, u16 *val);
+int mma9551_write_config_word(struct i2c_client *client, u8 app_id,
+ u16 reg, u16 val);
+int mma9551_read_status_word(struct i2c_client *client, u8 app_id,
+ u16 reg, u16 *val);
+int mma9551_read_config_words(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 len, u16 *buf);
+int mma9551_read_status_words(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 len, u16 *buf);
+int mma9551_write_config_words(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 len, u16 *buf);
+int mma9551_update_config_bits(struct i2c_client *client, u8 app_id,
+ u16 reg, u8 mask, u8 val);
+int mma9551_gpio_config(struct i2c_client *client, enum mma9551_gpio_pin pin,
+ u8 app_id, u8 bitnum, int polarity);
+int mma9551_read_version(struct i2c_client *client);
+int mma9551_set_device_state(struct i2c_client *client, bool enable);
+int mma9551_set_power_state(struct i2c_client *client, bool on);
+void mma9551_sleep(int freq);
+int mma9551_read_accel_chan(struct i2c_client *client,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2);
+int mma9551_read_accel_scale(int *val, int *val2);
+int mma9551_app_reset(struct i2c_client *client, u32 app_mask);
+
+#endif /* _MMA9551_CORE_H_ */
diff --git a/drivers/iio/accel/mma9553.c b/drivers/iio/accel/mma9553.c
new file mode 100644
index 000000000000..d23ebf192f63
--- /dev/null
+++ b/drivers/iio/accel/mma9553.c
@@ -0,0 +1,1334 @@
+/*
+ * Freescale MMA9553L Intelligent Pedometer driver
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/pm_runtime.h>
+#include "mma9551_core.h"
+
+#define MMA9553_DRV_NAME "mma9553"
+#define MMA9553_IRQ_NAME "mma9553_event"
+#define MMA9553_GPIO_NAME "mma9553_int"
+
+/* Pedometer configuration registers (R/W) */
+#define MMA9553_REG_CONF_SLEEPMIN 0x00
+#define MMA9553_REG_CONF_SLEEPMAX 0x02
+#define MMA9553_REG_CONF_SLEEPTHD 0x04
+#define MMA9553_MASK_CONF_WORD GENMASK(15, 0)
+
+#define MMA9553_REG_CONF_CONF_STEPLEN 0x06
+#define MMA9553_MASK_CONF_CONFIG BIT(15)
+#define MMA9553_MASK_CONF_ACT_DBCNTM BIT(14)
+#define MMA9553_MASK_CONF_SLP_DBCNTM BIT(13)
+#define MMA9553_MASK_CONF_STEPLEN GENMASK(7, 0)
+
+#define MMA9553_REG_CONF_HEIGHT_WEIGHT 0x08
+#define MMA9553_MASK_CONF_HEIGHT GENMASK(15, 8)
+#define MMA9553_MASK_CONF_WEIGHT GENMASK(7, 0)
+
+#define MMA9553_REG_CONF_FILTER 0x0A
+#define MMA9553_MASK_CONF_FILTSTEP GENMASK(15, 8)
+#define MMA9553_MASK_CONF_MALE BIT(7)
+#define MMA9553_MASK_CONF_FILTTIME GENMASK(6, 0)
+
+#define MMA9553_REG_CONF_SPEED_STEP 0x0C
+#define MMA9553_MASK_CONF_SPDPRD GENMASK(15, 8)
+#define MMA9553_MASK_CONF_STEPCOALESCE GENMASK(7, 0)
+
+#define MMA9553_REG_CONF_ACTTHD 0x0E
+
+/* Pedometer status registers (R-only) */
+#define MMA9553_REG_STATUS 0x00
+#define MMA9553_MASK_STATUS_MRGFL BIT(15)
+#define MMA9553_MASK_STATUS_SUSPCHG BIT(14)
+#define MMA9553_MASK_STATUS_STEPCHG BIT(13)
+#define MMA9553_MASK_STATUS_ACTCHG BIT(12)
+#define MMA9553_MASK_STATUS_SUSP BIT(11)
+#define MMA9553_MASK_STATUS_ACTIVITY (BIT(10) | BIT(9) | BIT(8))
+#define MMA9553_MASK_STATUS_VERSION 0x00FF
+
+#define MMA9553_REG_STEPCNT 0x02
+#define MMA9553_REG_DISTANCE 0x04
+#define MMA9553_REG_SPEED 0x06
+#define MMA9553_REG_CALORIES 0x08
+#define MMA9553_REG_SLEEPCNT 0x0A
+
+/* Pedometer events are always mapped to this pin. */
+#define MMA9553_DEFAULT_GPIO_PIN mma9551_gpio6
+#define MMA9553_DEFAULT_GPIO_POLARITY 0
+
+/* Bitnum used for gpio configuration = bit number in high status byte */
+#define STATUS_TO_BITNUM(bit) (ffs(bit) - 9)
+
+#define MMA9553_DEFAULT_SAMPLE_RATE 30 /* Hz */
+
+/*
+ * The internal activity level must be stable for ACTTHD samples before
+ * ACTIVITY is updated.The ACTIVITY variable contains the current activity
+ * level and is updated every time a step is detected or once a second
+ * if there are no steps.
+ */
+#define MMA9553_ACTIVITY_THD_TO_SEC(thd) ((thd) / MMA9553_DEFAULT_SAMPLE_RATE)
+#define MMA9553_ACTIVITY_SEC_TO_THD(sec) ((sec) * MMA9553_DEFAULT_SAMPLE_RATE)
+
+/*
+ * Autonomously suspend pedometer if acceleration vector magnitude
+ * is near 1g (4096 at 0.244 mg/LSB resolution) for 30 seconds.
+ */
+#define MMA9553_DEFAULT_SLEEPMIN 3688 /* 0,9 g */
+#define MMA9553_DEFAULT_SLEEPMAX 4508 /* 1,1 g */
+#define MMA9553_DEFAULT_SLEEPTHD (MMA9553_DEFAULT_SAMPLE_RATE * 30)
+
+#define MMA9553_CONFIG_RETRIES 2
+
+/* Status register - activity field */
+enum activity_level {
+ ACTIVITY_UNKNOWN,
+ ACTIVITY_REST,
+ ACTIVITY_WALKING,
+ ACTIVITY_JOGGING,
+ ACTIVITY_RUNNING,
+};
+
+static struct mma9553_event_info {
+ enum iio_chan_type type;
+ enum iio_modifier mod;
+ enum iio_event_direction dir;
+} mma9553_events_info[] = {
+ {
+ .type = IIO_STEPS,
+ .mod = IIO_NO_MOD,
+ .dir = IIO_EV_DIR_NONE,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_STILL,
+ .dir = IIO_EV_DIR_RISING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_STILL,
+ .dir = IIO_EV_DIR_FALLING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_WALKING,
+ .dir = IIO_EV_DIR_RISING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_WALKING,
+ .dir = IIO_EV_DIR_FALLING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_JOGGING,
+ .dir = IIO_EV_DIR_RISING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_JOGGING,
+ .dir = IIO_EV_DIR_FALLING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_RUNNING,
+ .dir = IIO_EV_DIR_RISING,
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .mod = IIO_MOD_RUNNING,
+ .dir = IIO_EV_DIR_FALLING,
+ },
+};
+
+#define MMA9553_EVENTS_INFO_SIZE ARRAY_SIZE(mma9553_events_info)
+
+struct mma9553_event {
+ struct mma9553_event_info *info;
+ bool enabled;
+};
+
+struct mma9553_conf_regs {
+ u16 sleepmin;
+ u16 sleepmax;
+ u16 sleepthd;
+ u16 config;
+ u16 height_weight;
+ u16 filter;
+ u16 speed_step;
+ u16 actthd;
+} __packed;
+
+struct mma9553_data {
+ struct i2c_client *client;
+ struct mutex mutex;
+ struct mma9553_conf_regs conf;
+ struct mma9553_event events[MMA9553_EVENTS_INFO_SIZE];
+ int num_events;
+ u8 gpio_bitnum;
+ /*
+ * This is used for all features that depend on step count:
+ * step count, distance, speed, calories.
+ */
+ bool stepcnt_enabled;
+ u16 stepcnt;
+ u8 activity;
+ s64 timestamp;
+};
+
+static u8 mma9553_get_bits(u16 val, u16 mask)
+{
+ return (val & mask) >> (ffs(mask) - 1);
+}
+
+static u16 mma9553_set_bits(u16 current_val, u16 val, u16 mask)
+{
+ return (current_val & ~mask) | (val << (ffs(mask) - 1));
+}
+
+static enum iio_modifier mma9553_activity_to_mod(enum activity_level activity)
+{
+ switch (activity) {
+ case ACTIVITY_RUNNING:
+ return IIO_MOD_RUNNING;
+ case ACTIVITY_JOGGING:
+ return IIO_MOD_JOGGING;
+ case ACTIVITY_WALKING:
+ return IIO_MOD_WALKING;
+ case ACTIVITY_REST:
+ return IIO_MOD_STILL;
+ case ACTIVITY_UNKNOWN:
+ default:
+ return IIO_NO_MOD;
+ }
+}
+
+static void mma9553_init_events(struct mma9553_data *data)
+{
+ int i;
+
+ data->num_events = MMA9553_EVENTS_INFO_SIZE;
+ for (i = 0; i < data->num_events; i++) {
+ data->events[i].info = &mma9553_events_info[i];
+ data->events[i].enabled = false;
+ }
+}
+
+static struct mma9553_event *mma9553_get_event(struct mma9553_data *data,
+ enum iio_chan_type type,
+ enum iio_modifier mod,
+ enum iio_event_direction dir)
+{
+ int i;
+
+ for (i = 0; i < data->num_events; i++)
+ if (data->events[i].info->type == type &&
+ data->events[i].info->mod == mod &&
+ data->events[i].info->dir == dir)
+ return &data->events[i];
+
+ return NULL;
+}
+
+static bool mma9553_is_any_event_enabled(struct mma9553_data *data,
+ bool check_type,
+ enum iio_chan_type type)
+{
+ int i;
+
+ for (i = 0; i < data->num_events; i++)
+ if ((check_type && data->events[i].info->type == type &&
+ data->events[i].enabled) ||
+ (!check_type && data->events[i].enabled))
+ return true;
+
+ return false;
+}
+
+static int mma9553_set_config(struct mma9553_data *data, u16 reg,
+ u16 *p_reg_val, u16 val, u16 mask)
+{
+ int ret, retries;
+ u16 reg_val, config;
+
+ reg_val = *p_reg_val;
+ if (val == mma9553_get_bits(reg_val, mask))
+ return 0;
+
+ reg_val = mma9553_set_bits(reg_val, val, mask);
+ ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
+ reg, reg_val);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "error writing config register 0x%x\n", reg);
+ return ret;
+ }
+
+ *p_reg_val = reg_val;
+
+ /* Reinitializes the pedometer with current configuration values */
+ config = mma9553_set_bits(data->conf.config, 1,
+ MMA9553_MASK_CONF_CONFIG);
+
+ ret = mma9551_write_config_word(data->client, MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_CONF_CONF_STEPLEN, config);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "error writing config register 0x%x\n",
+ MMA9553_REG_CONF_CONF_STEPLEN);
+ return ret;
+ }
+
+ retries = MMA9553_CONFIG_RETRIES;
+ do {
+ mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
+ ret = mma9551_read_config_word(data->client,
+ MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_CONF_CONF_STEPLEN,
+ &config);
+ if (ret < 0)
+ return ret;
+ } while (mma9553_get_bits(config, MMA9553_MASK_CONF_CONFIG) &&
+ --retries > 0);
+
+ return 0;
+}
+
+static int mma9553_read_activity_stepcnt(struct mma9553_data *data,
+ u8 *activity, u16 *stepcnt)
+{
+ u32 status_stepcnt;
+ u16 status;
+ int ret;
+
+ ret = mma9551_read_status_words(data->client, MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_STATUS, sizeof(u32),
+ (u16 *) &status_stepcnt);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "error reading status and stepcnt\n");
+ return ret;
+ }
+
+ status = status_stepcnt & MMA9553_MASK_CONF_WORD;
+ *activity = mma9553_get_bits(status, MMA9553_MASK_STATUS_ACTIVITY);
+ *stepcnt = status_stepcnt >> 16;
+
+ return 0;
+}
+
+static int mma9553_conf_gpio(struct mma9553_data *data)
+{
+ u8 bitnum = 0, appid = MMA9551_APPID_PEDOMETER;
+ int ret;
+ struct mma9553_event *ev_step_detect;
+ bool activity_enabled;
+
+ activity_enabled =
+ mma9553_is_any_event_enabled(data, true, IIO_ACTIVITY);
+ ev_step_detect =
+ mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
+
+ /*
+ * If both step detector and activity are enabled, use the MRGFL bit.
+ * This bit is the logical OR of the SUSPCHG, STEPCHG, and ACTCHG flags.
+ */
+ if (activity_enabled && ev_step_detect->enabled)
+ bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_MRGFL);
+ else if (ev_step_detect->enabled)
+ bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_STEPCHG);
+ else if (activity_enabled)
+ bitnum = STATUS_TO_BITNUM(MMA9553_MASK_STATUS_ACTCHG);
+ else /* Reset */
+ appid = MMA9551_APPID_NONE;
+
+ if (data->gpio_bitnum == bitnum)
+ return 0;
+
+ /* Save initial values for activity and stepcnt */
+ if (activity_enabled || ev_step_detect->enabled)
+ mma9553_read_activity_stepcnt(data, &data->activity,
+ &data->stepcnt);
+
+ ret = mma9551_gpio_config(data->client,
+ MMA9553_DEFAULT_GPIO_PIN,
+ appid, bitnum, MMA9553_DEFAULT_GPIO_POLARITY);
+ if (ret < 0)
+ return ret;
+ data->gpio_bitnum = bitnum;
+
+ return 0;
+}
+
+static int mma9553_init(struct mma9553_data *data)
+{
+ int ret;
+
+ ret = mma9551_read_version(data->client);
+ if (ret)
+ return ret;
+
+ /*
+ * Read all the pedometer configuration registers. This is used as
+ * a device identification command to differentiate the MMA9553L
+ * from the MMA9550L.
+ */
+ ret =
+ mma9551_read_config_words(data->client, MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_CONF_SLEEPMIN,
+ sizeof(data->conf), (u16 *) &data->conf);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "device is not MMA9553L: failed to read cfg regs\n");
+ return ret;
+ }
+
+
+ /* Reset gpio */
+ data->gpio_bitnum = -1;
+ ret = mma9553_conf_gpio(data);
+ if (ret < 0)
+ return ret;
+
+ ret = mma9551_app_reset(data->client, MMA9551_RSC_PED);
+ if (ret < 0)
+ return ret;
+
+ /* Init config registers */
+ data->conf.sleepmin = MMA9553_DEFAULT_SLEEPMIN;
+ data->conf.sleepmax = MMA9553_DEFAULT_SLEEPMAX;
+ data->conf.sleepthd = MMA9553_DEFAULT_SLEEPTHD;
+ data->conf.config =
+ mma9553_set_bits(data->conf.config, 1, MMA9553_MASK_CONF_CONFIG);
+ /*
+ * Clear the activity debounce counter when the activity level changes,
+ * so that the confidence level applies for any activity level.
+ */
+ data->conf.config = mma9553_set_bits(data->conf.config, 1,
+ MMA9553_MASK_CONF_ACT_DBCNTM);
+ ret =
+ mma9551_write_config_words(data->client, MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_CONF_SLEEPMIN,
+ sizeof(data->conf), (u16 *) &data->conf);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "failed to write configuration registers\n");
+ return ret;
+ }
+
+ return mma9551_set_device_state(data->client, true);
+}
+
+static int mma9553_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret;
+ u16 tmp;
+ u8 activity;
+ bool powered_on;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_STEPS:
+ /*
+ * The HW only counts steps and other dependent
+ * parameters (speed, distance, calories, activity)
+ * if power is on (from enabling an event or the
+ * step counter */
+ powered_on =
+ mma9553_is_any_event_enabled(data, false, 0) ||
+ data->stepcnt_enabled;
+ if (!powered_on) {
+ dev_err(&data->client->dev,
+ "No channels enabled\n");
+ return -EINVAL;
+ }
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_status_word(data->client,
+ MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_STEPCNT,
+ &tmp);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+ *val = tmp;
+ return IIO_VAL_INT;
+ case IIO_DISTANCE:
+ powered_on =
+ mma9553_is_any_event_enabled(data, false, 0) ||
+ data->stepcnt_enabled;
+ if (!powered_on) {
+ dev_err(&data->client->dev,
+ "No channels enabled\n");
+ return -EINVAL;
+ }
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_status_word(data->client,
+ MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_DISTANCE,
+ &tmp);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+ *val = tmp;
+ return IIO_VAL_INT;
+ case IIO_ACTIVITY:
+ powered_on =
+ mma9553_is_any_event_enabled(data, false, 0) ||
+ data->stepcnt_enabled;
+ if (!powered_on) {
+ dev_err(&data->client->dev,
+ "No channels enabled\n");
+ return -EINVAL;
+ }
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_status_word(data->client,
+ MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_STATUS,
+ &tmp);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+
+ activity =
+ mma9553_get_bits(tmp, MMA9553_MASK_STATUS_ACTIVITY);
+
+ /*
+ * The device does not support confidence value levels,
+ * so we will always have 100% for current activity and
+ * 0% for the others.
+ */
+ if (chan->channel2 == mma9553_activity_to_mod(activity))
+ *val = 100;
+ else
+ *val = 0;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_VELOCITY: /* m/h */
+ if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+ return -EINVAL;
+ powered_on =
+ mma9553_is_any_event_enabled(data, false, 0) ||
+ data->stepcnt_enabled;
+ if (!powered_on) {
+ dev_err(&data->client->dev,
+ "No channels enabled\n");
+ return -EINVAL;
+ }
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_status_word(data->client,
+ MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_SPEED, &tmp);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+ *val = tmp;
+ return IIO_VAL_INT;
+ case IIO_ENERGY: /* Cal or kcal */
+ powered_on =
+ mma9553_is_any_event_enabled(data, false, 0) ||
+ data->stepcnt_enabled;
+ if (!powered_on) {
+ dev_err(&data->client->dev,
+ "No channels enabled\n");
+ return -EINVAL;
+ }
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_status_word(data->client,
+ MMA9551_APPID_PEDOMETER,
+ MMA9553_REG_CALORIES,
+ &tmp);
+ mutex_unlock(&data->mutex);
+ if (ret < 0)
+ return ret;
+ *val = tmp;
+ return IIO_VAL_INT;
+ case IIO_ACCEL:
+ mutex_lock(&data->mutex);
+ ret = mma9551_read_accel_chan(data->client,
+ chan, val, val2);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_VELOCITY: /* m/h to m/s */
+ if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+ return -EINVAL;
+ *val = 0;
+ *val2 = 277; /* 0.000277 */
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_ENERGY: /* Cal or kcal to J */
+ *val = 4184;
+ return IIO_VAL_INT;
+ case IIO_ACCEL:
+ return mma9551_read_accel_scale(val, val2);
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_ENABLE:
+ *val = data->stepcnt_enabled;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBHEIGHT:
+ tmp = mma9553_get_bits(data->conf.height_weight,
+ MMA9553_MASK_CONF_HEIGHT);
+ *val = tmp / 100; /* cm to m */
+ *val2 = (tmp % 100) * 10000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_CHAN_INFO_CALIBWEIGHT:
+ *val = mma9553_get_bits(data->conf.height_weight,
+ MMA9553_MASK_CONF_WEIGHT);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_DEBOUNCE_COUNT:
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = mma9553_get_bits(data->conf.filter,
+ MMA9553_MASK_CONF_FILTSTEP);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_DEBOUNCE_TIME:
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = mma9553_get_bits(data->conf.filter,
+ MMA9553_MASK_CONF_FILTTIME);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_INT_TIME:
+ switch (chan->type) {
+ case IIO_VELOCITY:
+ if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+ return -EINVAL;
+ *val = mma9553_get_bits(data->conf.speed_step,
+ MMA9553_MASK_CONF_SPDPRD);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9553_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret, tmp;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_ENABLE:
+ if (data->stepcnt_enabled == !!val)
+ return 0;
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_power_state(data->client, val);
+ if (ret < 0) {
+ mutex_unlock(&data->mutex);
+ return ret;
+ }
+ data->stepcnt_enabled = val;
+ mutex_unlock(&data->mutex);
+ return 0;
+ case IIO_CHAN_INFO_CALIBHEIGHT:
+ /* m to cm */
+ tmp = val * 100 + val2 / 10000;
+ if (tmp < 0 || tmp > 255)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data,
+ MMA9553_REG_CONF_HEIGHT_WEIGHT,
+ &data->conf.height_weight,
+ tmp, MMA9553_MASK_CONF_HEIGHT);
+ mutex_unlock(&data->mutex);
+ return ret;
+ case IIO_CHAN_INFO_CALIBWEIGHT:
+ if (val < 0 || val > 255)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data,
+ MMA9553_REG_CONF_HEIGHT_WEIGHT,
+ &data->conf.height_weight,
+ val, MMA9553_MASK_CONF_WEIGHT);
+ mutex_unlock(&data->mutex);
+ return ret;
+ case IIO_CHAN_INFO_DEBOUNCE_COUNT:
+ switch (chan->type) {
+ case IIO_STEPS:
+ /*
+ * Set to 0 to disable step filtering. If the value
+ * specified is greater than 6, then 6 will be used.
+ */
+ if (val < 0)
+ return -EINVAL;
+ if (val > 6)
+ val = 6;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER,
+ &data->conf.filter, val,
+ MMA9553_MASK_CONF_FILTSTEP);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_DEBOUNCE_TIME:
+ switch (chan->type) {
+ case IIO_STEPS:
+ if (val < 0 || val > 127)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER,
+ &data->conf.filter, val,
+ MMA9553_MASK_CONF_FILTTIME);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_INT_TIME:
+ switch (chan->type) {
+ case IIO_VELOCITY:
+ if (chan->channel2 != IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z)
+ return -EINVAL;
+ /*
+ * If set to a value greater than 5, then 5 will be
+ * used. Warning: Do not set SPDPRD to 0 or 1 as
+ * this may cause undesirable behavior.
+ */
+ if (val < 2)
+ return -EINVAL;
+ if (val > 5)
+ val = 5;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data,
+ MMA9553_REG_CONF_SPEED_STEP,
+ &data->conf.speed_step, val,
+ MMA9553_MASK_CONF_SPDPRD);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9553_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+
+ struct mma9553_data *data = iio_priv(indio_dev);
+ struct mma9553_event *event;
+
+ event = mma9553_get_event(data, chan->type, chan->channel2, dir);
+ if (!event)
+ return -EINVAL;
+
+ return event->enabled;
+}
+
+static int mma9553_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir, int state)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+ struct mma9553_event *event;
+ int ret;
+
+ event = mma9553_get_event(data, chan->type, chan->channel2, dir);
+ if (!event)
+ return -EINVAL;
+
+ if (event->enabled == state)
+ return 0;
+
+ mutex_lock(&data->mutex);
+
+ ret = mma9551_set_power_state(data->client, state);
+ if (ret < 0)
+ goto err_out;
+ event->enabled = state;
+
+ ret = mma9553_conf_gpio(data);
+ if (ret < 0)
+ goto err_conf_gpio;
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+
+err_conf_gpio:
+ if (state) {
+ event->enabled = false;
+ mma9551_set_power_state(data->client, false);
+ }
+err_out:
+ mutex_unlock(&data->mutex);
+ return ret;
+}
+
+static int mma9553_read_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+
+ *val2 = 0;
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = mma9553_get_bits(data->conf.speed_step,
+ MMA9553_MASK_CONF_STEPCOALESCE);
+ return IIO_VAL_INT;
+ case IIO_ACTIVITY:
+ /*
+ * The device does not support confidence value levels.
+ * We set an average of 50%.
+ */
+ *val = 50;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_PERIOD:
+ switch (chan->type) {
+ case IIO_ACTIVITY:
+ *val = MMA9553_ACTIVITY_THD_TO_SEC(data->conf.actthd);
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9553_write_event_value(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ switch (chan->type) {
+ case IIO_STEPS:
+ if (val < 0 || val > 255)
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data,
+ MMA9553_REG_CONF_SPEED_STEP,
+ &data->conf.speed_step, val,
+ MMA9553_MASK_CONF_STEPCOALESCE);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ case IIO_EV_INFO_PERIOD:
+ switch (chan->type) {
+ case IIO_ACTIVITY:
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data, MMA9553_REG_CONF_ACTTHD,
+ &data->conf.actthd,
+ MMA9553_ACTIVITY_SEC_TO_THD
+ (val), MMA9553_MASK_CONF_WORD);
+ mutex_unlock(&data->mutex);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mma9553_get_calibgender_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+ u8 gender;
+
+ gender = mma9553_get_bits(data->conf.filter, MMA9553_MASK_CONF_MALE);
+ /*
+ * HW expects 0 for female and 1 for male,
+ * while iio index is 0 for male and 1 for female
+ */
+ return !gender;
+}
+
+static int mma9553_set_calibgender_mode(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ unsigned int mode)
+{
+ struct mma9553_data *data = iio_priv(indio_dev);
+ u8 gender = !mode;
+ int ret;
+
+ if ((mode != 0) && (mode != 1))
+ return -EINVAL;
+ mutex_lock(&data->mutex);
+ ret = mma9553_set_config(data, MMA9553_REG_CONF_FILTER,
+ &data->conf.filter, gender,
+ MMA9553_MASK_CONF_MALE);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_event_spec mma9553_step_event = {
+ .type = IIO_EV_TYPE_CHANGE,
+ .dir = IIO_EV_DIR_NONE,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) | BIT(IIO_EV_INFO_VALUE),
+};
+
+static const struct iio_event_spec mma9553_activity_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD),
+ },
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_PERIOD),
+ },
+};
+
+static const char * const calibgender_modes[] = { "male", "female" };
+
+static const struct iio_enum mma9553_calibgender_enum = {
+ .items = calibgender_modes,
+ .num_items = ARRAY_SIZE(calibgender_modes),
+ .get = mma9553_get_calibgender_mode,
+ .set = mma9553_set_calibgender_mode,
+};
+
+static const struct iio_chan_spec_ext_info mma9553_ext_info[] = {
+ IIO_ENUM("calibgender", IIO_SHARED_BY_TYPE, &mma9553_calibgender_enum),
+ IIO_ENUM_AVAILABLE("calibgender", &mma9553_calibgender_enum),
+ {},
+};
+
+#define MMA9553_PEDOMETER_CHANNEL(_type, _mask) { \
+ .type = _type, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_ENABLE) | \
+ BIT(IIO_CHAN_INFO_CALIBHEIGHT) | \
+ _mask, \
+ .ext_info = mma9553_ext_info, \
+}
+
+#define MMA9553_ACTIVITY_CHANNEL(_chan2) { \
+ .type = IIO_ACTIVITY, \
+ .modified = 1, \
+ .channel2 = _chan2, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT), \
+ .event_spec = mma9553_activity_events, \
+ .num_event_specs = ARRAY_SIZE(mma9553_activity_events), \
+ .ext_info = mma9553_ext_info, \
+}
+
+static const struct iio_chan_spec mma9553_channels[] = {
+ MMA9551_ACCEL_CHANNEL(IIO_MOD_X),
+ MMA9551_ACCEL_CHANNEL(IIO_MOD_Y),
+ MMA9551_ACCEL_CHANNEL(IIO_MOD_Z),
+
+ {
+ .type = IIO_STEPS,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_ENABLE) |
+ BIT(IIO_CHAN_INFO_DEBOUNCE_COUNT) |
+ BIT(IIO_CHAN_INFO_DEBOUNCE_TIME),
+ .event_spec = &mma9553_step_event,
+ .num_event_specs = 1,
+ },
+
+ MMA9553_PEDOMETER_CHANNEL(IIO_DISTANCE, BIT(IIO_CHAN_INFO_PROCESSED)),
+ {
+ .type = IIO_VELOCITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME) |
+ BIT(IIO_CHAN_INFO_ENABLE),
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_CALIBHEIGHT),
+ .ext_info = mma9553_ext_info,
+ },
+ MMA9553_PEDOMETER_CHANNEL(IIO_ENERGY, BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE) |
+ BIT(IIO_CHAN_INFO_CALIBWEIGHT)),
+
+ MMA9553_ACTIVITY_CHANNEL(IIO_MOD_RUNNING),
+ MMA9553_ACTIVITY_CHANNEL(IIO_MOD_JOGGING),
+ MMA9553_ACTIVITY_CHANNEL(IIO_MOD_WALKING),
+ MMA9553_ACTIVITY_CHANNEL(IIO_MOD_STILL),
+};
+
+static const struct iio_info mma9553_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = mma9553_read_raw,
+ .write_raw = mma9553_write_raw,
+ .read_event_config = mma9553_read_event_config,
+ .write_event_config = mma9553_write_event_config,
+ .read_event_value = mma9553_read_event_value,
+ .write_event_value = mma9553_write_event_value,
+};
+
+static irqreturn_t mma9553_irq_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct mma9553_data *data = iio_priv(indio_dev);
+
+ data->timestamp = iio_get_time_ns();
+ /*
+ * Since we only configure the interrupt pin when an
+ * event is enabled, we are sure we have at least
+ * one event enabled at this point.
+ */
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t mma9553_event_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct mma9553_data *data = iio_priv(indio_dev);
+ u16 stepcnt;
+ u8 activity;
+ struct mma9553_event *ev_activity, *ev_prev_activity, *ev_step_detect;
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9553_read_activity_stepcnt(data, &activity, &stepcnt);
+ if (ret < 0) {
+ mutex_unlock(&data->mutex);
+ return IRQ_HANDLED;
+ }
+
+ ev_prev_activity =
+ mma9553_get_event(data, IIO_ACTIVITY,
+ mma9553_activity_to_mod(data->activity),
+ IIO_EV_DIR_FALLING);
+ ev_activity =
+ mma9553_get_event(data, IIO_ACTIVITY,
+ mma9553_activity_to_mod(activity),
+ IIO_EV_DIR_RISING);
+ ev_step_detect =
+ mma9553_get_event(data, IIO_STEPS, IIO_NO_MOD, IIO_EV_DIR_NONE);
+
+ if (ev_step_detect->enabled && (stepcnt != data->stepcnt)) {
+ data->stepcnt = stepcnt;
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
+ IIO_EV_DIR_NONE, IIO_EV_TYPE_CHANGE, 0, 0, 0),
+ data->timestamp);
+ }
+
+ if (activity != data->activity) {
+ data->activity = activity;
+ /* ev_activity can be NULL if activity == ACTIVITY_UNKNOWN */
+ if (ev_prev_activity && ev_prev_activity->enabled)
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+ ev_prev_activity->info->mod,
+ IIO_EV_DIR_FALLING,
+ IIO_EV_TYPE_THRESH, 0, 0, 0),
+ data->timestamp);
+
+ if (ev_activity && ev_activity->enabled)
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+ ev_activity->info->mod,
+ IIO_EV_DIR_RISING,
+ IIO_EV_TYPE_THRESH, 0, 0, 0),
+ data->timestamp);
+ }
+ mutex_unlock(&data->mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int mma9553_gpio_probe(struct i2c_client *client)
+{
+ struct device *dev;
+ struct gpio_desc *gpio;
+ int ret;
+
+ if (!client)
+ return -EINVAL;
+
+ dev = &client->dev;
+
+ /* data ready gpio interrupt pin */
+ gpio = devm_gpiod_get_index(dev, MMA9553_GPIO_NAME, 0);
+ if (IS_ERR(gpio)) {
+ dev_err(dev, "acpi gpio get index failed\n");
+ return PTR_ERR(gpio);
+ }
+
+ ret = gpiod_direction_input(gpio);
+ if (ret)
+ return ret;
+
+ ret = gpiod_to_irq(gpio);
+
+ dev_dbg(dev, "gpio resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+ return ret;
+}
+
+static const char *mma9553_match_acpi_device(struct device *dev)
+{
+ const struct acpi_device_id *id;
+
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return NULL;
+
+ return dev_name(dev);
+}
+
+static int mma9553_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mma9553_data *data;
+ struct iio_dev *indio_dev;
+ const char *name = NULL;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+
+ if (id)
+ name = id->name;
+ else if (ACPI_HANDLE(&client->dev))
+ name = mma9553_match_acpi_device(&client->dev);
+ else
+ return -ENOSYS;
+
+ mutex_init(&data->mutex);
+ mma9553_init_events(data);
+
+ ret = mma9553_init(data);
+ if (ret < 0)
+ return ret;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = mma9553_channels;
+ indio_dev->num_channels = ARRAY_SIZE(mma9553_channels);
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &mma9553_info;
+
+ if (client->irq < 0)
+ client->irq = mma9553_gpio_probe(client);
+
+ if (client->irq >= 0) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ mma9553_irq_handler,
+ mma9553_event_handler,
+ IRQF_TRIGGER_RISING,
+ MMA9553_IRQ_NAME, indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "request irq %d failed\n",
+ client->irq);
+ goto out_poweroff;
+ }
+
+ }
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "unable to register iio device\n");
+ goto out_poweroff;
+ }
+
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret < 0)
+ goto out_iio_unregister;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev,
+ MMA9551_AUTO_SUSPEND_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ dev_dbg(&indio_dev->dev, "Registered device %s\n", name);
+
+ return 0;
+
+out_iio_unregister:
+ iio_device_unregister(indio_dev);
+out_poweroff:
+ mma9551_set_device_state(client, false);
+ return ret;
+}
+
+static int mma9553_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct mma9553_data *data = iio_priv(indio_dev);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
+ iio_device_unregister(indio_dev);
+ mutex_lock(&data->mutex);
+ mma9551_set_device_state(data->client, false);
+ mutex_unlock(&data->mutex);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mma9553_runtime_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_device_state(data->client, false);
+ mutex_unlock(&data->mutex);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "powering off device failed\n");
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static int mma9553_runtime_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret;
+
+ ret = mma9551_set_device_state(data->client, true);
+ if (ret < 0)
+ return ret;
+
+ mma9551_sleep(MMA9553_DEFAULT_SAMPLE_RATE);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int mma9553_suspend(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_device_state(data->client, false);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int mma9553_resume(struct device *dev)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
+ struct mma9553_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+ ret = mma9551_set_device_state(data->client, true);
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops mma9553_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mma9553_suspend, mma9553_resume)
+ SET_RUNTIME_PM_OPS(mma9553_runtime_suspend,
+ mma9553_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id mma9553_acpi_match[] = {
+ {"MMA9553", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, mma9553_acpi_match);
+
+static const struct i2c_device_id mma9553_id[] = {
+ {"mma9553", 0},
+ {},
+};
+
+MODULE_DEVICE_TABLE(i2c, mma9553_id);
+
+static struct i2c_driver mma9553_driver = {
+ .driver = {
+ .name = MMA9553_DRV_NAME,
+ .acpi_match_table = ACPI_PTR(mma9553_acpi_match),
+ .pm = &mma9553_pm_ops,
+ },
+ .probe = mma9553_probe,
+ .remove = mma9553_remove,
+ .id_table = mma9553_id,
+};
+
+module_i2c_driver(mma9553_driver);
+
+MODULE_AUTHOR("Irina Tirdea <irina.tirdea@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("MMA9553L pedometer platform driver");
diff --git a/drivers/iio/accel/ssp_accel_sensor.c b/drivers/iio/accel/ssp_accel_sensor.c
new file mode 100644
index 000000000000..4ae05fce9f24
--- /dev/null
+++ b/drivers/iio/accel/ssp_accel_sensor.c
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2014, Samsung Electronics Co. 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. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/iio/common/ssp_sensors.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "../common/ssp_sensors/ssp_iio_sensor.h"
+
+#define SSP_CHANNEL_COUNT 3
+
+#define SSP_ACCEL_NAME "ssp-accelerometer"
+static const char ssp_accel_device_name[] = SSP_ACCEL_NAME;
+
+enum ssp_accel_3d_channel {
+ SSP_CHANNEL_SCAN_INDEX_X,
+ SSP_CHANNEL_SCAN_INDEX_Y,
+ SSP_CHANNEL_SCAN_INDEX_Z,
+ SSP_CHANNEL_SCAN_INDEX_TIME,
+};
+
+static int ssp_accel_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ u32 t;
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ t = ssp_get_sensor_delay(data, SSP_ACCELEROMETER_SENSOR);
+ ssp_convert_to_freq(t, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int ssp_accel_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int ret;
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = ssp_convert_to_time(val, val2);
+ ret = ssp_change_delay(data, SSP_ACCELEROMETER_SENSOR, ret);
+ if (ret < 0)
+ dev_err(&indio_dev->dev, "accel sensor enable fail\n");
+
+ return ret;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static struct iio_info ssp_accel_iio_info = {
+ .read_raw = &ssp_accel_read_raw,
+ .write_raw = &ssp_accel_write_raw,
+};
+
+static const unsigned long ssp_accel_scan_mask[] = { 0x7, 0, };
+
+static const struct iio_chan_spec ssp_acc_channels[] = {
+ SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
+ SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
+ SSP_CHANNEL_AG(IIO_ACCEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
+ SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
+};
+
+static int ssp_process_accel_data(struct iio_dev *indio_dev, void *buf,
+ int64_t timestamp)
+{
+ return ssp_common_process_data(indio_dev, buf, SSP_ACCELEROMETER_SIZE,
+ timestamp);
+}
+
+static const struct iio_buffer_setup_ops ssp_accel_buffer_ops = {
+ .postenable = &ssp_common_buffer_postenable,
+ .postdisable = &ssp_common_buffer_postdisable,
+};
+
+static int ssp_accel_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct ssp_sensor_data *spd;
+ struct iio_buffer *buffer;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ spd = iio_priv(indio_dev);
+
+ spd->process_data = ssp_process_accel_data;
+ spd->type = SSP_ACCELEROMETER_SENSOR;
+
+ indio_dev->name = ssp_accel_device_name;
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->dev.of_node = pdev->dev.of_node;
+ indio_dev->info = &ssp_accel_iio_info;
+ indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+ indio_dev->channels = ssp_acc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ssp_acc_channels);
+ indio_dev->available_scan_masks = ssp_accel_scan_mask;
+
+ buffer = devm_iio_kfifo_allocate(&pdev->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(indio_dev, buffer);
+
+ indio_dev->setup_ops = &ssp_accel_buffer_ops;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ /* ssp registering should be done after all iio setup */
+ ssp_register_consumer(indio_dev, SSP_ACCELEROMETER_SENSOR);
+
+ return 0;
+}
+
+static int ssp_accel_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ iio_device_unregister(indio_dev);
+
+ return 0;
+}
+
+static struct platform_driver ssp_accel_driver = {
+ .driver = {
+ .name = SSP_ACCEL_NAME,
+ },
+ .probe = ssp_accel_probe,
+ .remove = ssp_accel_remove,
+};
+
+module_platform_driver(ssp_accel_driver);
+
+MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
+MODULE_DESCRIPTION("Samsung sensorhub accelerometers driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 0f79e4725763..202daf889be2 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -135,6 +135,17 @@ config AXP288_ADC
device. Depending on platform configuration, this general purpose ADC can
be used for sampling sensors such as thermal resistors.
+config CC10001_ADC
+ tristate "Cosmic Circuits 10001 ADC driver"
+ depends on HAS_IOMEM || HAVE_CLK || REGULATOR
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say yes here to build support for Cosmic Circuits 10001 ADC.
+
+ This driver can also be built as a module. If so, the module will be
+ called cc10001_adc.
+
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
@@ -228,6 +239,20 @@ config QCOM_SPMI_IADC
To compile this driver as a module, choose M here: the module will
be called qcom-spmi-iadc.
+config QCOM_SPMI_VADC
+ tristate "Qualcomm SPMI PMIC voltage ADC"
+ depends on SPMI
+ select REGMAP_SPMI
+ help
+ This is the IIO Voltage ADC driver for Qualcomm QPNP VADC Chip.
+
+ The driver supports multiple channels read. The VADC is a 15-bit
+ sigma-delta ADC. Some of the channels are internally used for
+ calibration.
+
+ To compile this driver as a module, choose M here: the module will
+ be called qcom-spmi-vadc.
+
config ROCKCHIP_SARADC
tristate "Rockchip SARADC driver"
depends on ARCH_ROCKCHIP || (ARM && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index 701fdb7c96aa..0315af640866 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -15,6 +15,7 @@ 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_CC10001_ADC) += cc10001_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
@@ -24,6 +25,7 @@ obj-$(CONFIG_MCP3422) += mcp3422.o
obj-$(CONFIG_MEN_Z188_ADC) += men_z188_adc.o
obj-$(CONFIG_NAU7802) += nau7802.o
obj-$(CONFIG_QCOM_SPMI_IADC) += qcom-spmi-iadc.o
+obj-$(CONFIG_QCOM_SPMI_VADC) += qcom-spmi-vadc.o
obj-$(CONFIG_ROCKCHIP_SARADC) += rockchip_saradc.o
obj-$(CONFIG_TI_ADC081C) += ti-adc081c.o
obj-$(CONFIG_TI_ADC128S052) += ti-adc128s052.o
diff --git a/drivers/iio/adc/cc10001_adc.c b/drivers/iio/adc/cc10001_adc.c
new file mode 100644
index 000000000000..51e2a83c9404
--- /dev/null
+++ b/drivers/iio/adc/cc10001_adc.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2014-2015 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#include <linux/iio/buffer.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/trigger_consumer.h>
+#include <linux/iio/triggered_buffer.h>
+
+/* Registers */
+#define CC10001_ADC_CONFIG 0x00
+#define CC10001_ADC_START_CONV BIT(4)
+#define CC10001_ADC_MODE_SINGLE_CONV BIT(5)
+
+#define CC10001_ADC_DDATA_OUT 0x04
+#define CC10001_ADC_EOC 0x08
+#define CC10001_ADC_EOC_SET BIT(0)
+
+#define CC10001_ADC_CHSEL_SAMPLED 0x0c
+#define CC10001_ADC_POWER_UP 0x10
+#define CC10001_ADC_POWER_UP_SET BIT(0)
+#define CC10001_ADC_DEBUG 0x14
+#define CC10001_ADC_DATA_COUNT 0x20
+
+#define CC10001_ADC_DATA_MASK GENMASK(9, 0)
+#define CC10001_ADC_NUM_CHANNELS 8
+#define CC10001_ADC_CH_MASK GENMASK(2, 0)
+
+#define CC10001_INVALID_SAMPLED 0xffff
+#define CC10001_MAX_POLL_COUNT 20
+
+/*
+ * As per device specification, wait six clock cycles after power-up to
+ * activate START. Since adding two more clock cycles delay does not
+ * impact the performance too much, we are adding two additional cycles delay
+ * intentionally here.
+ */
+#define CC10001_WAIT_CYCLES 8
+
+struct cc10001_adc_device {
+ void __iomem *reg_base;
+ struct clk *adc_clk;
+ struct regulator *reg;
+ u16 *buf;
+
+ struct mutex lock;
+ unsigned long channel_map;
+ unsigned int start_delay_ns;
+ unsigned int eoc_delay_ns;
+};
+
+static inline void cc10001_adc_write_reg(struct cc10001_adc_device *adc_dev,
+ u32 reg, u32 val)
+{
+ writel(val, adc_dev->reg_base + reg);
+}
+
+static inline u32 cc10001_adc_read_reg(struct cc10001_adc_device *adc_dev,
+ u32 reg)
+{
+ return readl(adc_dev->reg_base + reg);
+}
+
+static void cc10001_adc_start(struct cc10001_adc_device *adc_dev,
+ unsigned int channel)
+{
+ u32 val;
+
+ /* Channel selection and mode of operation */
+ val = (channel & CC10001_ADC_CH_MASK) | CC10001_ADC_MODE_SINGLE_CONV;
+ cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val);
+
+ val = cc10001_adc_read_reg(adc_dev, CC10001_ADC_CONFIG);
+ val = val | CC10001_ADC_START_CONV;
+ cc10001_adc_write_reg(adc_dev, CC10001_ADC_CONFIG, val);
+}
+
+static u16 cc10001_adc_poll_done(struct iio_dev *indio_dev,
+ unsigned int channel,
+ unsigned int delay)
+{
+ struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+ unsigned int poll_count = 0;
+
+ while (!(cc10001_adc_read_reg(adc_dev, CC10001_ADC_EOC) &
+ CC10001_ADC_EOC_SET)) {
+
+ ndelay(delay);
+ if (poll_count++ == CC10001_MAX_POLL_COUNT)
+ return CC10001_INVALID_SAMPLED;
+ }
+
+ poll_count = 0;
+ while ((cc10001_adc_read_reg(adc_dev, CC10001_ADC_CHSEL_SAMPLED) &
+ CC10001_ADC_CH_MASK) != channel) {
+
+ ndelay(delay);
+ if (poll_count++ == CC10001_MAX_POLL_COUNT)
+ return CC10001_INVALID_SAMPLED;
+ }
+
+ /* Read the 10 bit output register */
+ return cc10001_adc_read_reg(adc_dev, CC10001_ADC_DDATA_OUT) &
+ CC10001_ADC_DATA_MASK;
+}
+
+static irqreturn_t cc10001_adc_trigger_h(int irq, void *p)
+{
+ struct cc10001_adc_device *adc_dev;
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev;
+ unsigned int delay_ns;
+ unsigned int channel;
+ bool sample_invalid;
+ u16 *data;
+ int i;
+
+ indio_dev = pf->indio_dev;
+ adc_dev = iio_priv(indio_dev);
+ data = adc_dev->buf;
+
+ mutex_lock(&adc_dev->lock);
+
+ cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP,
+ CC10001_ADC_POWER_UP_SET);
+
+ /* Wait for 8 (6+2) clock cycles before activating START */
+ ndelay(adc_dev->start_delay_ns);
+
+ /* Calculate delay step for eoc and sampled data */
+ delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
+
+ i = 0;
+ sample_invalid = false;
+ for_each_set_bit(channel, indio_dev->active_scan_mask,
+ indio_dev->masklength) {
+
+ cc10001_adc_start(adc_dev, channel);
+
+ data[i] = cc10001_adc_poll_done(indio_dev, channel, delay_ns);
+ if (data[i] == CC10001_INVALID_SAMPLED) {
+ dev_warn(&indio_dev->dev,
+ "invalid sample on channel %d\n", channel);
+ sample_invalid = true;
+ goto done;
+ }
+ i++;
+ }
+
+done:
+ cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0);
+
+ mutex_unlock(&adc_dev->lock);
+
+ if (!sample_invalid)
+ iio_push_to_buffers_with_timestamp(indio_dev, data,
+ iio_get_time_ns());
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static u16 cc10001_adc_read_raw_voltage(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan)
+{
+ struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+ unsigned int delay_ns;
+ u16 val;
+
+ cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP,
+ CC10001_ADC_POWER_UP_SET);
+
+ /* Wait for 8 (6+2) clock cycles before activating START */
+ ndelay(adc_dev->start_delay_ns);
+
+ /* Calculate delay step for eoc and sampled data */
+ delay_ns = adc_dev->eoc_delay_ns / CC10001_MAX_POLL_COUNT;
+
+ cc10001_adc_start(adc_dev, chan->channel);
+
+ val = cc10001_adc_poll_done(indio_dev, chan->channel, delay_ns);
+
+ cc10001_adc_write_reg(adc_dev, CC10001_ADC_POWER_UP, 0);
+
+ return val;
+}
+
+static int cc10001_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+ mutex_lock(&adc_dev->lock);
+ *val = cc10001_adc_read_raw_voltage(indio_dev, chan);
+ mutex_unlock(&adc_dev->lock);
+
+ if (*val == CC10001_INVALID_SAMPLED)
+ return -EIO;
+ return IIO_VAL_INT;
+
+ case IIO_CHAN_INFO_SCALE:
+ ret = regulator_get_voltage(adc_dev->reg);
+ if (ret)
+ return ret;
+
+ *val = ret / 1000;
+ *val2 = chan->scan_type.realbits;
+ return IIO_VAL_FRACTIONAL_LOG2;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cc10001_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+
+ kfree(adc_dev->buf);
+ adc_dev->buf = kmalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ if (!adc_dev->buf)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static const struct iio_info cc10001_adc_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &cc10001_adc_read_raw,
+ .update_scan_mode = &cc10001_update_scan_mode,
+};
+
+static int cc10001_adc_channel_init(struct iio_dev *indio_dev)
+{
+ struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+ struct iio_chan_spec *chan_array, *timestamp;
+ unsigned int bit, idx = 0;
+
+ indio_dev->num_channels = bitmap_weight(&adc_dev->channel_map,
+ CC10001_ADC_NUM_CHANNELS);
+
+ chan_array = devm_kcalloc(&indio_dev->dev, indio_dev->num_channels + 1,
+ sizeof(struct iio_chan_spec),
+ GFP_KERNEL);
+ if (!chan_array)
+ return -ENOMEM;
+
+ for_each_set_bit(bit, &adc_dev->channel_map, CC10001_ADC_NUM_CHANNELS) {
+ struct iio_chan_spec *chan = &chan_array[idx];
+
+ chan->type = IIO_VOLTAGE;
+ chan->indexed = 1;
+ chan->channel = bit;
+ chan->scan_index = idx;
+ chan->scan_type.sign = 'u';
+ chan->scan_type.realbits = 10;
+ chan->scan_type.storagebits = 16;
+ chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
+ chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
+ idx++;
+ }
+
+ timestamp = &chan_array[idx];
+ timestamp->type = IIO_TIMESTAMP;
+ timestamp->channel = -1;
+ timestamp->scan_index = idx;
+ timestamp->scan_type.sign = 's';
+ timestamp->scan_type.realbits = 64;
+ timestamp->scan_type.storagebits = 64;
+
+ indio_dev->channels = chan_array;
+
+ return 0;
+}
+
+static int cc10001_adc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct cc10001_adc_device *adc_dev;
+ unsigned long adc_clk_rate;
+ struct resource *res;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*adc_dev));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ adc_dev = iio_priv(indio_dev);
+
+ adc_dev->channel_map = GENMASK(CC10001_ADC_NUM_CHANNELS - 1, 0);
+ if (!of_property_read_u32(node, "adc-reserved-channels", &ret))
+ adc_dev->channel_map &= ~ret;
+
+ adc_dev->reg = devm_regulator_get(&pdev->dev, "vref");
+ if (IS_ERR(adc_dev->reg))
+ return PTR_ERR(adc_dev->reg);
+
+ ret = regulator_enable(adc_dev->reg);
+ if (ret)
+ return ret;
+
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->name = dev_name(&pdev->dev);
+ indio_dev->info = &cc10001_adc_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ adc_dev->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(adc_dev->reg_base)) {
+ ret = PTR_ERR(adc_dev->reg_base);
+ goto err_disable_reg;
+ }
+
+ adc_dev->adc_clk = devm_clk_get(&pdev->dev, "adc");
+ if (IS_ERR(adc_dev->adc_clk)) {
+ dev_err(&pdev->dev, "failed to get the clock\n");
+ ret = PTR_ERR(adc_dev->adc_clk);
+ goto err_disable_reg;
+ }
+
+ ret = clk_prepare_enable(adc_dev->adc_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable the clock\n");
+ goto err_disable_reg;
+ }
+
+ adc_clk_rate = clk_get_rate(adc_dev->adc_clk);
+ if (!adc_clk_rate) {
+ ret = -EINVAL;
+ dev_err(&pdev->dev, "null clock rate!\n");
+ goto err_disable_clk;
+ }
+
+ adc_dev->eoc_delay_ns = NSEC_PER_SEC / adc_clk_rate;
+ adc_dev->start_delay_ns = adc_dev->eoc_delay_ns * CC10001_WAIT_CYCLES;
+
+ /* Setup the ADC channels available on the device */
+ ret = cc10001_adc_channel_init(indio_dev);
+ if (ret < 0)
+ goto err_disable_clk;
+
+ mutex_init(&adc_dev->lock);
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ &cc10001_adc_trigger_h, NULL);
+ if (ret < 0)
+ goto err_disable_clk;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto err_cleanup_buffer;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ return 0;
+
+err_cleanup_buffer:
+ iio_triggered_buffer_cleanup(indio_dev);
+err_disable_clk:
+ clk_disable_unprepare(adc_dev->adc_clk);
+err_disable_reg:
+ regulator_disable(adc_dev->reg);
+ return ret;
+}
+
+static int cc10001_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct cc10001_adc_device *adc_dev = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ clk_disable_unprepare(adc_dev->adc_clk);
+ regulator_disable(adc_dev->reg);
+
+ return 0;
+}
+
+static const struct of_device_id cc10001_adc_dt_ids[] = {
+ { .compatible = "cosmic,10001-adc", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, cc10001_adc_dt_ids);
+
+static struct platform_driver cc10001_adc_driver = {
+ .driver = {
+ .name = "cc10001-adc",
+ .of_match_table = cc10001_adc_dt_ids,
+ },
+ .probe = cc10001_adc_probe,
+ .remove = cc10001_adc_remove,
+};
+module_platform_driver(cc10001_adc_driver);
+
+MODULE_AUTHOR("Phani Movva <Phani.Movva@imgtec.com>");
+MODULE_DESCRIPTION("Cosmic Circuits ADC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/adc/qcom-spmi-vadc.c b/drivers/iio/adc/qcom-spmi-vadc.c
new file mode 100644
index 000000000000..3211729bcb0b
--- /dev/null
+++ b/drivers/iio/adc/qcom-spmi-vadc.c
@@ -0,0 +1,1016 @@
+/*
+ * 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/bitops.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/log2.h>
+
+#include <dt-bindings/iio/qcom,spmi-vadc.h>
+
+/* VADC register and bit definitions */
+#define VADC_REVISION2 0x1
+#define VADC_REVISION2_SUPPORTED_VADC 1
+
+#define VADC_PERPH_TYPE 0x4
+#define VADC_PERPH_TYPE_ADC 8
+
+#define VADC_PERPH_SUBTYPE 0x5
+#define VADC_PERPH_SUBTYPE_VADC 1
+
+#define VADC_STATUS1 0x8
+#define VADC_STATUS1_OP_MODE 4
+#define VADC_STATUS1_REQ_STS BIT(1)
+#define VADC_STATUS1_EOC BIT(0)
+#define VADC_STATUS1_REQ_STS_EOC_MASK 0x3
+
+#define VADC_MODE_CTL 0x40
+#define VADC_OP_MODE_SHIFT 3
+#define VADC_OP_MODE_NORMAL 0
+#define VADC_AMUX_TRIM_EN BIT(1)
+#define VADC_ADC_TRIM_EN BIT(0)
+
+#define VADC_EN_CTL1 0x46
+#define VADC_EN_CTL1_SET BIT(7)
+
+#define VADC_ADC_CH_SEL_CTL 0x48
+
+#define VADC_ADC_DIG_PARAM 0x50
+#define VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT 2
+
+#define VADC_HW_SETTLE_DELAY 0x51
+
+#define VADC_CONV_REQ 0x52
+#define VADC_CONV_REQ_SET BIT(7)
+
+#define VADC_FAST_AVG_CTL 0x5a
+#define VADC_FAST_AVG_EN 0x5b
+#define VADC_FAST_AVG_EN_SET BIT(7)
+
+#define VADC_ACCESS 0xd0
+#define VADC_ACCESS_DATA 0xa5
+
+#define VADC_PERH_RESET_CTL3 0xda
+#define VADC_FOLLOW_WARM_RB BIT(2)
+
+#define VADC_DATA 0x60 /* 16 bits */
+
+#define VADC_CONV_TIME_MIN_US 2000
+#define VADC_CONV_TIME_MAX_US 2100
+
+/* Min ADC code represents 0V */
+#define VADC_MIN_ADC_CODE 0x6000
+/* Max ADC code represents full-scale range of 1.8V */
+#define VADC_MAX_ADC_CODE 0xa800
+
+#define VADC_ABSOLUTE_RANGE_UV 625000
+#define VADC_RATIOMETRIC_RANGE_UV 1800000
+
+#define VADC_DEF_PRESCALING 0 /* 1:1 */
+#define VADC_DEF_DECIMATION 0 /* 512 */
+#define VADC_DEF_HW_SETTLE_TIME 0 /* 0 us */
+#define VADC_DEF_AVG_SAMPLES 0 /* 1 sample */
+#define VADC_DEF_CALIB_TYPE VADC_CALIB_ABSOLUTE
+
+#define VADC_DECIMATION_MIN 512
+#define VADC_DECIMATION_MAX 4096
+
+#define VADC_HW_SETTLE_DELAY_MAX 10000
+#define VADC_AVG_SAMPLES_MAX 512
+
+#define KELVINMIL_CELSIUSMIL 273150
+
+#define VADC_CHAN_MIN VADC_USBIN
+#define VADC_CHAN_MAX VADC_LR_MUX3_BUF_PU1_PU2_XO_THERM
+
+/*
+ * VADC_CALIB_ABSOLUTE: uses the 625mV and 1.25V as reference channels.
+ * VADC_CALIB_RATIOMETRIC: uses the reference voltage (1.8V) and GND for
+ * calibration.
+ */
+enum vadc_calibration {
+ VADC_CALIB_ABSOLUTE = 0,
+ VADC_CALIB_RATIOMETRIC
+};
+
+/**
+ * struct vadc_linear_graph - Represent ADC characteristics.
+ * @dy: numerator slope to calculate the gain.
+ * @dx: denominator slope to calculate the gain.
+ * @gnd: A/D word of the ground reference used for the channel.
+ *
+ * Each ADC device has different offset and gain parameters which are
+ * computed to calibrate the device.
+ */
+struct vadc_linear_graph {
+ s32 dy;
+ s32 dx;
+ s32 gnd;
+};
+
+/**
+ * struct vadc_prescale_ratio - Represent scaling ratio for ADC input.
+ * @num: the inverse numerator of the gain applied to the input channel.
+ * @den: the inverse denominator of the gain applied to the input channel.
+ */
+struct vadc_prescale_ratio {
+ u32 num;
+ u32 den;
+};
+
+/**
+ * struct vadc_channel_prop - VADC channel property.
+ * @channel: channel number, refer to the channel list.
+ * @calibration: calibration type.
+ * @decimation: sampling rate supported for the channel.
+ * @prescale: channel scaling performed on the input signal.
+ * @hw_settle_time: the time between AMUX being configured and the
+ * start of conversion.
+ * @avg_samples: ability to provide single result from the ADC
+ * that is an average of multiple measurements.
+ */
+struct vadc_channel_prop {
+ unsigned int channel;
+ enum vadc_calibration calibration;
+ unsigned int decimation;
+ unsigned int prescale;
+ unsigned int hw_settle_time;
+ unsigned int avg_samples;
+};
+
+/**
+ * struct vadc_priv - VADC private structure.
+ * @regmap: pointer to struct regmap.
+ * @dev: pointer to struct device.
+ * @base: base address for the ADC peripheral.
+ * @nchannels: number of VADC channels.
+ * @chan_props: array of VADC channel properties.
+ * @iio_chans: array of IIO channels specification.
+ * @are_ref_measured: are reference points measured.
+ * @poll_eoc: use polling instead of interrupt.
+ * @complete: VADC result notification after interrupt is received.
+ * @graph: store parameters for calibration.
+ * @lock: ADC lock for access to the peripheral.
+ */
+struct vadc_priv {
+ struct regmap *regmap;
+ struct device *dev;
+ u16 base;
+ unsigned int nchannels;
+ struct vadc_channel_prop *chan_props;
+ struct iio_chan_spec *iio_chans;
+ bool are_ref_measured;
+ bool poll_eoc;
+ struct completion complete;
+ struct vadc_linear_graph graph[2];
+ struct mutex lock;
+};
+
+static const struct vadc_prescale_ratio vadc_prescale_ratios[] = {
+ {.num = 1, .den = 1},
+ {.num = 1, .den = 3},
+ {.num = 1, .den = 4},
+ {.num = 1, .den = 6},
+ {.num = 1, .den = 20},
+ {.num = 1, .den = 8},
+ {.num = 10, .den = 81},
+ {.num = 1, .den = 10}
+};
+
+static int vadc_read(struct vadc_priv *vadc, u16 offset, u8 *data)
+{
+ return regmap_bulk_read(vadc->regmap, vadc->base + offset, data, 1);
+}
+
+static int vadc_write(struct vadc_priv *vadc, u16 offset, u8 data)
+{
+ return regmap_write(vadc->regmap, vadc->base + offset, data);
+}
+
+static int vadc_reset(struct vadc_priv *vadc)
+{
+ u8 data;
+ int ret;
+
+ ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA);
+ if (ret)
+ return ret;
+
+ ret = vadc_read(vadc, VADC_PERH_RESET_CTL3, &data);
+ if (ret)
+ return ret;
+
+ ret = vadc_write(vadc, VADC_ACCESS, VADC_ACCESS_DATA);
+ if (ret)
+ return ret;
+
+ data |= VADC_FOLLOW_WARM_RB;
+
+ return vadc_write(vadc, VADC_PERH_RESET_CTL3, data);
+}
+
+static int vadc_set_state(struct vadc_priv *vadc, bool state)
+{
+ return vadc_write(vadc, VADC_EN_CTL1, state ? VADC_EN_CTL1_SET : 0);
+}
+
+static void vadc_show_status(struct vadc_priv *vadc)
+{
+ u8 mode, sta1, chan, dig, en, req;
+ int ret;
+
+ ret = vadc_read(vadc, VADC_MODE_CTL, &mode);
+ if (ret)
+ return;
+
+ ret = vadc_read(vadc, VADC_ADC_DIG_PARAM, &dig);
+ if (ret)
+ return;
+
+ ret = vadc_read(vadc, VADC_ADC_CH_SEL_CTL, &chan);
+ if (ret)
+ return;
+
+ ret = vadc_read(vadc, VADC_CONV_REQ, &req);
+ if (ret)
+ return;
+
+ ret = vadc_read(vadc, VADC_STATUS1, &sta1);
+ if (ret)
+ return;
+
+ ret = vadc_read(vadc, VADC_EN_CTL1, &en);
+ if (ret)
+ return;
+
+ dev_err(vadc->dev,
+ "mode:%02x en:%02x chan:%02x dig:%02x req:%02x sta1:%02x\n",
+ mode, en, chan, dig, req, sta1);
+}
+
+static int vadc_configure(struct vadc_priv *vadc,
+ struct vadc_channel_prop *prop)
+{
+ u8 decimation, mode_ctrl;
+ int ret;
+
+ /* Mode selection */
+ mode_ctrl = (VADC_OP_MODE_NORMAL << VADC_OP_MODE_SHIFT) |
+ VADC_ADC_TRIM_EN | VADC_AMUX_TRIM_EN;
+ ret = vadc_write(vadc, VADC_MODE_CTL, mode_ctrl);
+ if (ret)
+ return ret;
+
+ /* Channel selection */
+ ret = vadc_write(vadc, VADC_ADC_CH_SEL_CTL, prop->channel);
+ if (ret)
+ return ret;
+
+ /* Digital parameter setup */
+ decimation = prop->decimation << VADC_ADC_DIG_DEC_RATIO_SEL_SHIFT;
+ ret = vadc_write(vadc, VADC_ADC_DIG_PARAM, decimation);
+ if (ret)
+ return ret;
+
+ /* HW settle time delay */
+ ret = vadc_write(vadc, VADC_HW_SETTLE_DELAY, prop->hw_settle_time);
+ if (ret)
+ return ret;
+
+ ret = vadc_write(vadc, VADC_FAST_AVG_CTL, prop->avg_samples);
+ if (ret)
+ return ret;
+
+ if (prop->avg_samples)
+ ret = vadc_write(vadc, VADC_FAST_AVG_EN, VADC_FAST_AVG_EN_SET);
+ else
+ ret = vadc_write(vadc, VADC_FAST_AVG_EN, 0);
+
+ return ret;
+}
+
+static int vadc_poll_wait_eoc(struct vadc_priv *vadc, unsigned int interval_us)
+{
+ unsigned int count, retry;
+ u8 sta1;
+ int ret;
+
+ retry = interval_us / VADC_CONV_TIME_MIN_US;
+
+ for (count = 0; count < retry; count++) {
+ ret = vadc_read(vadc, VADC_STATUS1, &sta1);
+ if (ret)
+ return ret;
+
+ sta1 &= VADC_STATUS1_REQ_STS_EOC_MASK;
+ if (sta1 == VADC_STATUS1_EOC)
+ return 0;
+
+ usleep_range(VADC_CONV_TIME_MIN_US, VADC_CONV_TIME_MAX_US);
+ }
+
+ vadc_show_status(vadc);
+
+ return -ETIMEDOUT;
+}
+
+static int vadc_read_result(struct vadc_priv *vadc, u16 *data)
+{
+ int ret;
+
+ ret = regmap_bulk_read(vadc->regmap, vadc->base + VADC_DATA, data, 2);
+ if (ret)
+ return ret;
+
+ *data = clamp_t(u16, *data, VADC_MIN_ADC_CODE, VADC_MAX_ADC_CODE);
+
+ return 0;
+}
+
+static struct vadc_channel_prop *vadc_get_channel(struct vadc_priv *vadc,
+ unsigned int num)
+{
+ unsigned int i;
+
+ for (i = 0; i < vadc->nchannels; i++)
+ if (vadc->chan_props[i].channel == num)
+ return &vadc->chan_props[i];
+
+ dev_dbg(vadc->dev, "no such channel %02x\n", num);
+
+ return NULL;
+}
+
+static int vadc_do_conversion(struct vadc_priv *vadc,
+ struct vadc_channel_prop *prop, u16 *data)
+{
+ unsigned int timeout;
+ int ret;
+
+ mutex_lock(&vadc->lock);
+
+ ret = vadc_configure(vadc, prop);
+ if (ret)
+ goto unlock;
+
+ if (!vadc->poll_eoc)
+ reinit_completion(&vadc->complete);
+
+ ret = vadc_set_state(vadc, true);
+ if (ret)
+ goto unlock;
+
+ ret = vadc_write(vadc, VADC_CONV_REQ, VADC_CONV_REQ_SET);
+ if (ret)
+ goto err_disable;
+
+ timeout = BIT(prop->avg_samples) * VADC_CONV_TIME_MIN_US * 2;
+
+ if (vadc->poll_eoc) {
+ ret = vadc_poll_wait_eoc(vadc, timeout);
+ } else {
+ ret = wait_for_completion_timeout(&vadc->complete, timeout);
+ if (!ret) {
+ ret = -ETIMEDOUT;
+ goto err_disable;
+ }
+
+ /* Double check conversion status */
+ ret = vadc_poll_wait_eoc(vadc, VADC_CONV_TIME_MIN_US);
+ if (ret)
+ goto err_disable;
+ }
+
+ ret = vadc_read_result(vadc, data);
+
+err_disable:
+ vadc_set_state(vadc, false);
+ if (ret)
+ dev_err(vadc->dev, "conversion failed\n");
+unlock:
+ mutex_unlock(&vadc->lock);
+ return ret;
+}
+
+static int vadc_measure_ref_points(struct vadc_priv *vadc)
+{
+ struct vadc_channel_prop *prop;
+ u16 read_1, read_2;
+ int ret;
+
+ vadc->graph[VADC_CALIB_RATIOMETRIC].dx = VADC_RATIOMETRIC_RANGE_UV;
+ vadc->graph[VADC_CALIB_ABSOLUTE].dx = VADC_ABSOLUTE_RANGE_UV;
+
+ prop = vadc_get_channel(vadc, VADC_REF_1250MV);
+ ret = vadc_do_conversion(vadc, prop, &read_1);
+ if (ret)
+ goto err;
+
+ /* Try with buffered 625mV channel first */
+ prop = vadc_get_channel(vadc, VADC_SPARE1);
+ if (!prop)
+ prop = vadc_get_channel(vadc, VADC_REF_625MV);
+
+ ret = vadc_do_conversion(vadc, prop, &read_2);
+ if (ret)
+ goto err;
+
+ if (read_1 == read_2) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ vadc->graph[VADC_CALIB_ABSOLUTE].dy = read_1 - read_2;
+ vadc->graph[VADC_CALIB_ABSOLUTE].gnd = read_2;
+
+ /* Ratiometric calibration */
+ prop = vadc_get_channel(vadc, VADC_VDD_VADC);
+ ret = vadc_do_conversion(vadc, prop, &read_1);
+ if (ret)
+ goto err;
+
+ prop = vadc_get_channel(vadc, VADC_GND_REF);
+ ret = vadc_do_conversion(vadc, prop, &read_2);
+ if (ret)
+ goto err;
+
+ if (read_1 == read_2) {
+ ret = -EINVAL;
+ goto err;
+ }
+
+ vadc->graph[VADC_CALIB_RATIOMETRIC].dy = read_1 - read_2;
+ vadc->graph[VADC_CALIB_RATIOMETRIC].gnd = read_2;
+err:
+ if (ret)
+ dev_err(vadc->dev, "measure reference points failed\n");
+
+ return ret;
+}
+
+static s32 vadc_calibrate(struct vadc_priv *vadc,
+ const struct vadc_channel_prop *prop, u16 adc_code)
+{
+ const struct vadc_prescale_ratio *prescale;
+ s32 voltage;
+
+ voltage = adc_code - vadc->graph[prop->calibration].gnd;
+ voltage *= vadc->graph[prop->calibration].dx;
+ voltage = voltage / vadc->graph[prop->calibration].dy;
+
+ if (prop->calibration == VADC_CALIB_ABSOLUTE)
+ voltage += vadc->graph[prop->calibration].dx;
+
+ if (voltage < 0)
+ voltage = 0;
+
+ prescale = &vadc_prescale_ratios[prop->prescale];
+
+ voltage = voltage * prescale->den;
+
+ return voltage / prescale->num;
+}
+
+static int vadc_decimation_from_dt(u32 value)
+{
+ if (!is_power_of_2(value) || value < VADC_DECIMATION_MIN ||
+ value > VADC_DECIMATION_MAX)
+ return -EINVAL;
+
+ return __ffs64(value / VADC_DECIMATION_MIN);
+}
+
+static int vadc_prescaling_from_dt(u32 num, u32 den)
+{
+ unsigned int pre;
+
+ for (pre = 0; pre < ARRAY_SIZE(vadc_prescale_ratios); pre++)
+ if (vadc_prescale_ratios[pre].num == num &&
+ vadc_prescale_ratios[pre].den == den)
+ break;
+
+ if (pre == ARRAY_SIZE(vadc_prescale_ratios))
+ return -EINVAL;
+
+ return pre;
+}
+
+static int vadc_hw_settle_time_from_dt(u32 value)
+{
+ if ((value <= 1000 && value % 100) || (value > 1000 && value % 2000))
+ return -EINVAL;
+
+ if (value <= 1000)
+ value /= 100;
+ else
+ value = value / 2000 + 10;
+
+ return value;
+}
+
+static int vadc_avg_samples_from_dt(u32 value)
+{
+ if (!is_power_of_2(value) || value > VADC_AVG_SAMPLES_MAX)
+ return -EINVAL;
+
+ return __ffs64(value);
+}
+
+static int vadc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val, int *val2,
+ long mask)
+{
+ struct vadc_priv *vadc = iio_priv(indio_dev);
+ struct vadc_channel_prop *prop;
+ u16 adc_code;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ prop = &vadc->chan_props[chan->address];
+ ret = vadc_do_conversion(vadc, prop, &adc_code);
+ if (ret)
+ break;
+
+ *val = vadc_calibrate(vadc, prop, adc_code);
+
+ /* 2mV/K, return milli Celsius */
+ *val /= 2;
+ *val -= KELVINMIL_CELSIUSMIL;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_RAW:
+ prop = &vadc->chan_props[chan->address];
+ ret = vadc_do_conversion(vadc, prop, &adc_code);
+ if (ret)
+ break;
+
+ *val = vadc_calibrate(vadc, prop, adc_code);
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 0;
+ *val2 = 1000;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static int vadc_of_xlate(struct iio_dev *indio_dev,
+ const struct of_phandle_args *iiospec)
+{
+ struct vadc_priv *vadc = iio_priv(indio_dev);
+ unsigned int i;
+
+ for (i = 0; i < vadc->nchannels; i++)
+ if (vadc->iio_chans[i].channel == iiospec->args[0])
+ return i;
+
+ return -EINVAL;
+}
+
+static const struct iio_info vadc_info = {
+ .read_raw = vadc_read_raw,
+ .of_xlate = vadc_of_xlate,
+ .driver_module = THIS_MODULE,
+};
+
+struct vadc_channels {
+ const char *datasheet_name;
+ unsigned int prescale_index;
+ enum iio_chan_type type;
+ long info_mask;
+};
+
+#define VADC_CHAN(_dname, _type, _mask, _pre) \
+ [VADC_##_dname] = { \
+ .datasheet_name = __stringify(_dname), \
+ .prescale_index = _pre, \
+ .type = _type, \
+ .info_mask = _mask \
+ }, \
+
+#define VADC_CHAN_TEMP(_dname, _pre) \
+ VADC_CHAN(_dname, IIO_TEMP, BIT(IIO_CHAN_INFO_PROCESSED), _pre) \
+
+#define VADC_CHAN_VOLT(_dname, _pre) \
+ VADC_CHAN(_dname, IIO_VOLTAGE, \
+ BIT(IIO_CHAN_INFO_RAW) | BIT(IIO_CHAN_INFO_SCALE), \
+ _pre) \
+
+/*
+ * The array represents all possible ADC channels found in the supported PMICs.
+ * Every index in the array is equal to the channel number per datasheet. The
+ * gaps in the array should be treated as reserved channels.
+ */
+static const struct vadc_channels vadc_chans[] = {
+ VADC_CHAN_VOLT(USBIN, 4)
+ VADC_CHAN_VOLT(DCIN, 4)
+ VADC_CHAN_VOLT(VCHG_SNS, 3)
+ VADC_CHAN_VOLT(SPARE1_03, 1)
+ VADC_CHAN_VOLT(USB_ID_MV, 1)
+ VADC_CHAN_VOLT(VCOIN, 1)
+ VADC_CHAN_VOLT(VBAT_SNS, 1)
+ VADC_CHAN_VOLT(VSYS, 1)
+ VADC_CHAN_TEMP(DIE_TEMP, 0)
+ VADC_CHAN_VOLT(REF_625MV, 0)
+ VADC_CHAN_VOLT(REF_1250MV, 0)
+ VADC_CHAN_VOLT(CHG_TEMP, 0)
+ VADC_CHAN_VOLT(SPARE1, 0)
+ VADC_CHAN_VOLT(SPARE2, 0)
+ VADC_CHAN_VOLT(GND_REF, 0)
+ VADC_CHAN_VOLT(VDD_VADC, 0)
+
+ VADC_CHAN_VOLT(P_MUX1_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX2_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX3_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX4_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX5_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX6_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX7_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX8_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX9_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX10_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX11_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX12_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX13_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX14_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX15_1_1, 0)
+ VADC_CHAN_VOLT(P_MUX16_1_1, 0)
+
+ VADC_CHAN_VOLT(P_MUX1_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX2_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX3_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX4_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX5_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX6_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX7_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX8_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX9_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX10_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX11_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX12_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX13_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX14_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX15_1_3, 1)
+ VADC_CHAN_VOLT(P_MUX16_1_3, 1)
+
+ VADC_CHAN_VOLT(LR_MUX1_BAT_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX2_BAT_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_XO_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX4_AMUX_THM1, 0)
+ VADC_CHAN_VOLT(LR_MUX5_AMUX_THM2, 0)
+ VADC_CHAN_VOLT(LR_MUX6_AMUX_THM3, 0)
+ VADC_CHAN_VOLT(LR_MUX7_HW_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX8_AMUX_THM4, 0)
+ VADC_CHAN_VOLT(LR_MUX9_AMUX_THM5, 0)
+ VADC_CHAN_VOLT(LR_MUX10_USB_ID, 0)
+ VADC_CHAN_VOLT(AMUX_PU1, 0)
+ VADC_CHAN_VOLT(AMUX_PU2, 0)
+ VADC_CHAN_VOLT(LR_MUX3_BUF_XO_THERM, 0)
+
+ VADC_CHAN_VOLT(LR_MUX1_PU1_BAT_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX2_PU1_BAT_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_PU1_XO_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX4_PU1_AMUX_THM1, 0)
+ VADC_CHAN_VOLT(LR_MUX5_PU1_AMUX_THM2, 0)
+ VADC_CHAN_VOLT(LR_MUX6_PU1_AMUX_THM3, 0)
+ VADC_CHAN_VOLT(LR_MUX7_PU1_AMUX_HW_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX8_PU1_AMUX_THM4, 0)
+ VADC_CHAN_VOLT(LR_MUX9_PU1_AMUX_THM5, 0)
+ VADC_CHAN_VOLT(LR_MUX10_PU1_AMUX_USB_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_XO_THERM, 0)
+
+ VADC_CHAN_VOLT(LR_MUX1_PU2_BAT_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX2_PU2_BAT_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_PU2_XO_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX4_PU2_AMUX_THM1, 0)
+ VADC_CHAN_VOLT(LR_MUX5_PU2_AMUX_THM2, 0)
+ VADC_CHAN_VOLT(LR_MUX6_PU2_AMUX_THM3, 0)
+ VADC_CHAN_VOLT(LR_MUX7_PU2_AMUX_HW_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX8_PU2_AMUX_THM4, 0)
+ VADC_CHAN_VOLT(LR_MUX9_PU2_AMUX_THM5, 0)
+ VADC_CHAN_VOLT(LR_MUX10_PU2_AMUX_USB_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_BUF_PU2_XO_THERM, 0)
+
+ VADC_CHAN_VOLT(LR_MUX1_PU1_PU2_BAT_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX2_PU1_PU2_BAT_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_PU1_PU2_XO_THERM, 0)
+ VADC_CHAN_VOLT(LR_MUX4_PU1_PU2_AMUX_THM1, 0)
+ VADC_CHAN_VOLT(LR_MUX5_PU1_PU2_AMUX_THM2, 0)
+ VADC_CHAN_VOLT(LR_MUX6_PU1_PU2_AMUX_THM3, 0)
+ VADC_CHAN_VOLT(LR_MUX7_PU1_PU2_AMUX_HW_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX8_PU1_PU2_AMUX_THM4, 0)
+ VADC_CHAN_VOLT(LR_MUX9_PU1_PU2_AMUX_THM5, 0)
+ VADC_CHAN_VOLT(LR_MUX10_PU1_PU2_AMUX_USB_ID, 0)
+ VADC_CHAN_VOLT(LR_MUX3_BUF_PU1_PU2_XO_THERM, 0)
+};
+
+static int vadc_get_dt_channel_data(struct device *dev,
+ struct vadc_channel_prop *prop,
+ struct device_node *node)
+{
+ const char *name = node->name;
+ u32 chan, value, varr[2];
+ int ret;
+
+ ret = of_property_read_u32(node, "reg", &chan);
+ if (ret) {
+ dev_err(dev, "invalid channel number %s\n", name);
+ return ret;
+ }
+
+ if (chan > VADC_CHAN_MAX || chan < VADC_CHAN_MIN) {
+ dev_err(dev, "%s invalid channel number %d\n", name, chan);
+ return -EINVAL;
+ }
+
+ /* the channel has DT description */
+ prop->channel = chan;
+
+ ret = of_property_read_u32(node, "qcom,decimation", &value);
+ if (!ret) {
+ ret = vadc_decimation_from_dt(value);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid decimation %d\n",
+ chan, value);
+ return ret;
+ }
+ prop->decimation = ret;
+ } else {
+ prop->decimation = VADC_DEF_DECIMATION;
+ }
+
+ ret = of_property_read_u32_array(node, "qcom,pre-scaling", varr, 2);
+ if (!ret) {
+ ret = vadc_prescaling_from_dt(varr[0], varr[1]);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid pre-scaling <%d %d>\n",
+ chan, varr[0], varr[1]);
+ return ret;
+ }
+ prop->prescale = ret;
+ } else {
+ prop->prescale = vadc_chans[prop->channel].prescale_index;
+ }
+
+ ret = of_property_read_u32(node, "qcom,hw-settle-time", &value);
+ if (!ret) {
+ ret = vadc_hw_settle_time_from_dt(value);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid hw-settle-time %d us\n",
+ chan, value);
+ return ret;
+ }
+ prop->hw_settle_time = ret;
+ } else {
+ prop->hw_settle_time = VADC_DEF_HW_SETTLE_TIME;
+ }
+
+ ret = of_property_read_u32(node, "qcom,avg-samples", &value);
+ if (!ret) {
+ ret = vadc_avg_samples_from_dt(value);
+ if (ret < 0) {
+ dev_err(dev, "%02x invalid avg-samples %d\n",
+ chan, value);
+ return ret;
+ }
+ prop->avg_samples = ret;
+ } else {
+ prop->avg_samples = VADC_DEF_AVG_SAMPLES;
+ }
+
+ if (of_property_read_bool(node, "qcom,ratiometric"))
+ prop->calibration = VADC_CALIB_RATIOMETRIC;
+ else
+ prop->calibration = VADC_CALIB_ABSOLUTE;
+
+ dev_dbg(dev, "%02x name %s\n", chan, name);
+
+ return 0;
+}
+
+static int vadc_get_dt_data(struct vadc_priv *vadc, struct device_node *node)
+{
+ const struct vadc_channels *vadc_chan;
+ struct iio_chan_spec *iio_chan;
+ struct vadc_channel_prop prop;
+ struct device_node *child;
+ unsigned int index = 0;
+ int ret;
+
+ vadc->nchannels = of_get_available_child_count(node);
+ if (!vadc->nchannels)
+ return -EINVAL;
+
+ vadc->iio_chans = devm_kcalloc(vadc->dev, vadc->nchannels,
+ sizeof(*vadc->iio_chans), GFP_KERNEL);
+ if (!vadc->iio_chans)
+ return -ENOMEM;
+
+ vadc->chan_props = devm_kcalloc(vadc->dev, vadc->nchannels,
+ sizeof(*vadc->chan_props), GFP_KERNEL);
+ if (!vadc->chan_props)
+ return -ENOMEM;
+
+ iio_chan = vadc->iio_chans;
+
+ for_each_available_child_of_node(node, child) {
+ ret = vadc_get_dt_channel_data(vadc->dev, &prop, child);
+ if (ret)
+ return ret;
+
+ vadc->chan_props[index] = prop;
+
+ vadc_chan = &vadc_chans[prop.channel];
+
+ iio_chan->channel = prop.channel;
+ iio_chan->datasheet_name = vadc_chan->datasheet_name;
+ iio_chan->info_mask_separate = vadc_chan->info_mask;
+ iio_chan->type = vadc_chan->type;
+ iio_chan->indexed = 1;
+ iio_chan->address = index++;
+
+ iio_chan++;
+ }
+
+ /* These channels are mandatory, they are used as reference points */
+ if (!vadc_get_channel(vadc, VADC_REF_1250MV)) {
+ dev_err(vadc->dev, "Please define 1.25V channel\n");
+ return -ENODEV;
+ }
+
+ if (!vadc_get_channel(vadc, VADC_REF_625MV)) {
+ dev_err(vadc->dev, "Please define 0.625V channel\n");
+ return -ENODEV;
+ }
+
+ if (!vadc_get_channel(vadc, VADC_VDD_VADC)) {
+ dev_err(vadc->dev, "Please define VDD channel\n");
+ return -ENODEV;
+ }
+
+ if (!vadc_get_channel(vadc, VADC_GND_REF)) {
+ dev_err(vadc->dev, "Please define GND channel\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static irqreturn_t vadc_isr(int irq, void *dev_id)
+{
+ struct vadc_priv *vadc = dev_id;
+
+ complete(&vadc->complete);
+
+ return IRQ_HANDLED;
+}
+
+static int vadc_check_revision(struct vadc_priv *vadc)
+{
+ u8 val;
+ int ret;
+
+ ret = vadc_read(vadc, VADC_PERPH_TYPE, &val);
+ if (ret)
+ return ret;
+
+ if (val < VADC_PERPH_TYPE_ADC) {
+ dev_err(vadc->dev, "%d is not ADC\n", val);
+ return -ENODEV;
+ }
+
+ ret = vadc_read(vadc, VADC_PERPH_SUBTYPE, &val);
+ if (ret)
+ return ret;
+
+ if (val < VADC_PERPH_SUBTYPE_VADC) {
+ dev_err(vadc->dev, "%d is not VADC\n", val);
+ return -ENODEV;
+ }
+
+ ret = vadc_read(vadc, VADC_REVISION2, &val);
+ if (ret)
+ return ret;
+
+ if (val < VADC_REVISION2_SUPPORTED_VADC) {
+ dev_err(vadc->dev, "revision %d not supported\n", val);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int vadc_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct device *dev = &pdev->dev;
+ struct iio_dev *indio_dev;
+ struct vadc_priv *vadc;
+ struct regmap *regmap;
+ int ret, irq_eoc;
+ u32 reg;
+
+ regmap = dev_get_regmap(dev->parent, NULL);
+ if (!regmap)
+ return -ENODEV;
+
+ ret = of_property_read_u32(node, "reg", &reg);
+ if (ret < 0)
+ return ret;
+
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*vadc));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ vadc = iio_priv(indio_dev);
+ vadc->regmap = regmap;
+ vadc->dev = dev;
+ vadc->base = reg;
+ vadc->are_ref_measured = false;
+ init_completion(&vadc->complete);
+ mutex_init(&vadc->lock);
+
+ ret = vadc_check_revision(vadc);
+ if (ret)
+ return ret;
+
+ ret = vadc_get_dt_data(vadc, node);
+ if (ret)
+ return ret;
+
+ irq_eoc = platform_get_irq(pdev, 0);
+ if (irq_eoc < 0) {
+ if (irq_eoc == -EPROBE_DEFER || irq_eoc == -EINVAL)
+ return irq_eoc;
+ vadc->poll_eoc = true;
+ } else {
+ ret = devm_request_irq(dev, irq_eoc, vadc_isr, 0,
+ "spmi-vadc", vadc);
+ if (ret)
+ return ret;
+ }
+
+ ret = vadc_reset(vadc);
+ if (ret) {
+ dev_err(dev, "reset failed\n");
+ return ret;
+ }
+
+ ret = vadc_measure_ref_points(vadc);
+ if (ret)
+ return ret;
+
+ indio_dev->dev.parent = dev;
+ indio_dev->dev.of_node = node;
+ indio_dev->name = pdev->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = &vadc_info;
+ indio_dev->channels = vadc->iio_chans;
+ indio_dev->num_channels = vadc->nchannels;
+
+ return devm_iio_device_register(dev, indio_dev);
+}
+
+static const struct of_device_id vadc_match_table[] = {
+ { .compatible = "qcom,spmi-vadc" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, vadc_match_table);
+
+static struct platform_driver vadc_driver = {
+ .driver = {
+ .name = "qcom-spmi-vadc",
+ .of_match_table = vadc_match_table,
+ },
+ .probe = vadc_probe,
+};
+module_platform_driver(vadc_driver);
+
+MODULE_ALIAS("platform:qcom-spmi-vadc");
+MODULE_DESCRIPTION("Qualcomm SPMI PMIC voltage ADC driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Stanimir Varbanov <svarbanov@mm-sol.com>");
+MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
diff --git a/drivers/iio/adc/ti_am335x_adc.c b/drivers/iio/adc/ti_am335x_adc.c
index b730864731e8..2e5cc4409f78 100644
--- a/drivers/iio/adc/ti_am335x_adc.c
+++ b/drivers/iio/adc/ti_am335x_adc.c
@@ -86,19 +86,18 @@ static void tiadc_step_config(struct iio_dev *indio_dev)
{
struct tiadc_device *adc_dev = iio_priv(indio_dev);
unsigned int stepconfig;
- int i, steps;
+ int i, steps = 0;
/*
* There are 16 configurable steps and 8 analog input
* lines available which are shared between Touchscreen and ADC.
*
- * Steps backwards i.e. from 16 towards 0 are used by ADC
+ * Steps forwards i.e. from 0 towards 16 are used by ADC
* depending on number of input lines needed.
* Channel would represent which analog input
* needs to be given to ADC to digitalize data.
*/
- steps = TOTAL_STEPS - adc_dev->channels;
if (iio_buffer_enabled(indio_dev))
stepconfig = STEPCONFIG_AVG_16 | STEPCONFIG_FIFO1
| STEPCONFIG_MODE_SWCNT;
@@ -250,7 +249,7 @@ static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
struct iio_buffer *buffer;
int ret;
- buffer = iio_kfifo_allocate(indio_dev);
+ buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
@@ -264,16 +263,8 @@ static int tiadc_iio_buffered_hardware_setup(struct iio_dev *indio_dev,
indio_dev->setup_ops = setup_ops;
indio_dev->modes |= INDIO_BUFFER_HARDWARE;
- ret = iio_buffer_register(indio_dev,
- indio_dev->channels,
- indio_dev->num_channels);
- if (ret)
- goto error_free_irq;
-
return 0;
-error_free_irq:
- free_irq(irq, indio_dev);
error_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
@@ -285,7 +276,6 @@ static void tiadc_iio_buffered_hardware_remove(struct iio_dev *indio_dev)
free_irq(adc_dev->mfd_tscadc->irq, indio_dev);
iio_kfifo_free(indio_dev->buffer);
- iio_buffer_unregister(indio_dev);
}
diff --git a/drivers/iio/amplifiers/ad8366.c b/drivers/iio/amplifiers/ad8366.c
index ba6f6a91dfff..c0d364ebaea8 100644
--- a/drivers/iio/amplifiers/ad8366.c
+++ b/drivers/iio/amplifiers/ad8366.c
@@ -31,7 +31,7 @@ struct ad8366_state {
};
static int ad8366_write(struct iio_dev *indio_dev,
- unsigned char ch_a, char unsigned ch_b)
+ unsigned char ch_a, unsigned char ch_b)
{
struct ad8366_state *st = iio_priv(indio_dev);
int ret;
@@ -166,7 +166,7 @@ static int ad8366_probe(struct spi_device *spi)
if (ret)
goto error_disable_reg;
- ad8366_write(indio_dev, 0 , 0);
+ ad8366_write(indio_dev, 0, 0);
return 0;
diff --git a/drivers/iio/common/Kconfig b/drivers/iio/common/Kconfig
index 0b6e97d18fa0..790f106d719c 100644
--- a/drivers/iio/common/Kconfig
+++ b/drivers/iio/common/Kconfig
@@ -3,4 +3,5 @@
#
source "drivers/iio/common/hid-sensors/Kconfig"
+source "drivers/iio/common/ssp_sensors/Kconfig"
source "drivers/iio/common/st_sensors/Kconfig"
diff --git a/drivers/iio/common/Makefile b/drivers/iio/common/Makefile
index 3112df0060e9..b1e4d9c9591c 100644
--- a/drivers/iio/common/Makefile
+++ b/drivers/iio/common/Makefile
@@ -8,4 +8,5 @@
# When adding new entries keep the list in alphabetical order
obj-y += hid-sensors/
+obj-y += ssp_sensors/
obj-y += st_sensors/
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
index 92068cdbf8c7..2f1d535b94c4 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.c
@@ -22,16 +22,18 @@
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/slab.h>
+#include <linux/delay.h>
#include <linux/hid-sensor-hub.h>
#include <linux/iio/iio.h>
#include <linux/iio/trigger.h>
#include <linux/iio/sysfs.h>
#include "hid-sensor-trigger.h"
-int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
+static int _hid_sensor_power_state(struct hid_sensor_common *st, bool state)
{
int state_val;
int report_val;
+ s32 poll_value = 0;
if (state) {
if (sensor_hub_device_open(st->hsdev))
@@ -47,6 +49,8 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
st->report_state.report_id,
st->report_state.index,
HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM);
+
+ poll_value = hid_sensor_read_poll_value(st);
} else {
if (!atomic_dec_and_test(&st->data_ready))
return 0;
@@ -78,10 +82,36 @@ int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
sensor_hub_get_feature(st->hsdev, st->power_state.report_id,
st->power_state.index,
&state_val);
+ if (state && poll_value)
+ msleep_interruptible(poll_value * 2);
+
return 0;
}
EXPORT_SYMBOL(hid_sensor_power_state);
+int hid_sensor_power_state(struct hid_sensor_common *st, bool state)
+{
+#ifdef CONFIG_PM
+ int ret;
+
+ if (state)
+ ret = pm_runtime_get_sync(&st->pdev->dev);
+ else {
+ pm_runtime_mark_last_busy(&st->pdev->dev);
+ ret = pm_runtime_put_autosuspend(&st->pdev->dev);
+ }
+ if (ret < 0) {
+ if (state)
+ pm_runtime_put_noidle(&st->pdev->dev);
+ return ret;
+ }
+
+ return 0;
+#else
+ return _hid_sensor_power_state(st, state);
+#endif
+}
+
static int hid_sensor_data_rdy_trigger_set_state(struct iio_trigger *trig,
bool state)
{
@@ -125,8 +155,21 @@ int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
attrb->trigger = trig;
indio_dev->trig = iio_trigger_get(trig);
- return ret;
+ ret = pm_runtime_set_active(&indio_dev->dev);
+ if (ret)
+ goto error_unreg_trigger;
+ iio_device_set_drvdata(indio_dev, attrb);
+ pm_suspend_ignore_children(&attrb->pdev->dev, true);
+ pm_runtime_enable(&attrb->pdev->dev);
+ /* Default to 3 seconds, but can be changed from sysfs */
+ pm_runtime_set_autosuspend_delay(&attrb->pdev->dev,
+ 3000);
+ pm_runtime_use_autosuspend(&attrb->pdev->dev);
+
+ return ret;
+error_unreg_trigger:
+ iio_trigger_unregister(trig);
error_free_trig:
iio_trigger_free(trig);
error_ret:
@@ -134,6 +177,34 @@ error_ret:
}
EXPORT_SYMBOL(hid_sensor_setup_trigger);
+#ifdef CONFIG_PM
+static int hid_sensor_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
+ return _hid_sensor_power_state(attrb, false);
+}
+
+static int hid_sensor_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+ struct hid_sensor_common *attrb = iio_device_get_drvdata(indio_dev);
+
+ return _hid_sensor_power_state(attrb, true);
+}
+
+#endif
+
+const struct dev_pm_ops hid_sensor_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(hid_sensor_suspend, hid_sensor_resume)
+ SET_RUNTIME_PM_OPS(hid_sensor_suspend,
+ hid_sensor_resume, NULL)
+};
+EXPORT_SYMBOL(hid_sensor_pm_ops);
+
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@intel.com>");
MODULE_DESCRIPTION("HID Sensor trigger processing");
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
index 0f8e78c249d3..9f4713f42ecb 100644
--- a/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
+++ b/drivers/iio/common/hid-sensors/hid-sensor-trigger.h
@@ -19,6 +19,11 @@
#ifndef _HID_SENSOR_TRIGGER_H
#define _HID_SENSOR_TRIGGER_H
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+
+extern const struct dev_pm_ops hid_sensor_pm_ops;
+
int hid_sensor_setup_trigger(struct iio_dev *indio_dev, const char *name,
struct hid_sensor_common *attrb);
void hid_sensor_remove_trigger(struct hid_sensor_common *attrb);
diff --git a/drivers/iio/common/ssp_sensors/Kconfig b/drivers/iio/common/ssp_sensors/Kconfig
new file mode 100644
index 000000000000..0ea4faf016d8
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/Kconfig
@@ -0,0 +1,26 @@
+#
+# SSP sensor drivers and commons configuration
+#
+menu "SSP Sensor Common"
+
+config IIO_SSP_SENSORS_COMMONS
+ tristate "Commons for all SSP Sensor IIO drivers"
+ depends on IIO_SSP_SENSORHUB
+ select IIO_BUFFER
+ select IIO_KFIFO_BUF
+ help
+ Say yes here to build commons for SSP sensors.
+ To compile this as a module, choose M here: the module
+ will be called ssp_iio.
+
+config IIO_SSP_SENSORHUB
+ tristate "Samsung Sensorhub driver"
+ depends on SPI
+ select MFD_CORE
+ help
+ SSP driver for sensorhub.
+ If you say yes here you get ssp support for sensorhub.
+ To compile this driver as a module, choose M here: the
+ module will be called sensorhub.
+
+endmenu
diff --git a/drivers/iio/common/ssp_sensors/Makefile b/drivers/iio/common/ssp_sensors/Makefile
new file mode 100644
index 000000000000..1e0389eb0905
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for SSP sensor drivers and commons.
+#
+
+sensorhub-objs := ssp_dev.o ssp_spi.o
+obj-$(CONFIG_IIO_SSP_SENSORHUB) += sensorhub.o
+
+obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_iio.o
diff --git a/drivers/iio/common/ssp_sensors/ssp.h b/drivers/iio/common/ssp_sensors/ssp.h
new file mode 100644
index 000000000000..b910e91d7c0d
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp.h
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2014, Samsung Electronics Co. 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. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __SSP_SENSORHUB_H__
+#define __SSP_SENSORHUB_H__
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/iio/common/ssp_sensors.h>
+#include <linux/iio/iio.h>
+#include <linux/spi/spi.h>
+
+#define SSP_DEVICE_ID 0x55
+
+#ifdef SSP_DBG
+#define ssp_dbg(format, ...) pr_info("[SSP] "format, ##__VA_ARGS__)
+#else
+#define ssp_dbg(format, ...)
+#endif
+
+#define SSP_SW_RESET_TIME 3000
+/* Sensor polling in ms */
+#define SSP_DEFAULT_POLLING_DELAY 200
+#define SSP_DEFAULT_RETRIES 3
+#define SSP_DATA_PACKET_SIZE 960
+#define SSP_HEADER_BUFFER_SIZE 4
+
+enum {
+ SSP_KERNEL_BINARY = 0,
+ SSP_KERNEL_CRASHED_BINARY,
+};
+
+enum {
+ SSP_INITIALIZATION_STATE = 0,
+ SSP_NO_SENSOR_STATE,
+ SSP_ADD_SENSOR_STATE,
+ SSP_RUNNING_SENSOR_STATE,
+};
+
+/* Firmware download STATE */
+enum {
+ SSP_FW_DL_STATE_FAIL = -1,
+ SSP_FW_DL_STATE_NONE = 0,
+ SSP_FW_DL_STATE_NEED_TO_SCHEDULE,
+ SSP_FW_DL_STATE_SCHEDULED,
+ SSP_FW_DL_STATE_DOWNLOADING,
+ SSP_FW_DL_STATE_SYNC,
+ SSP_FW_DL_STATE_DONE,
+};
+
+#define SSP_INVALID_REVISION 99999
+#define SSP_INVALID_REVISION2 0xffffff
+
+/* AP -> SSP Instruction */
+#define SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD 0xa1
+#define SSP_MSG2SSP_INST_BYPASS_SENSOR_RM 0xa2
+#define SSP_MSG2SSP_INST_REMOVE_ALL 0xa3
+#define SSP_MSG2SSP_INST_CHANGE_DELAY 0xa4
+#define SSP_MSG2SSP_INST_LIBRARY_ADD 0xb1
+#define SSP_MSG2SSP_INST_LIBRARY_REMOVE 0xb2
+#define SSP_MSG2SSP_INST_LIB_NOTI 0xb4
+#define SSP_MSG2SSP_INST_LIB_DATA 0xc1
+
+#define SSP_MSG2SSP_AP_MCU_SET_GYRO_CAL 0xcd
+#define SSP_MSG2SSP_AP_MCU_SET_ACCEL_CAL 0xce
+#define SSP_MSG2SSP_AP_STATUS_SHUTDOWN 0xd0
+#define SSP_MSG2SSP_AP_STATUS_WAKEUP 0xd1
+#define SSP_MSG2SSP_AP_STATUS_SLEEP 0xd2
+#define SSP_MSG2SSP_AP_STATUS_RESUME 0xd3
+#define SSP_MSG2SSP_AP_STATUS_SUSPEND 0xd4
+#define SSP_MSG2SSP_AP_STATUS_RESET 0xd5
+#define SSP_MSG2SSP_AP_STATUS_POW_CONNECTED 0xd6
+#define SSP_MSG2SSP_AP_STATUS_POW_DISCONNECTED 0xd7
+#define SSP_MSG2SSP_AP_TEMPHUMIDITY_CAL_DONE 0xda
+#define SSP_MSG2SSP_AP_MCU_SET_DUMPMODE 0xdb
+#define SSP_MSG2SSP_AP_MCU_DUMP_CHECK 0xdc
+#define SSP_MSG2SSP_AP_MCU_BATCH_FLUSH 0xdd
+#define SSP_MSG2SSP_AP_MCU_BATCH_COUNT 0xdf
+
+#define SSP_MSG2SSP_AP_WHOAMI 0x0f
+#define SSP_MSG2SSP_AP_FIRMWARE_REV 0xf0
+#define SSP_MSG2SSP_AP_SENSOR_FORMATION 0xf1
+#define SSP_MSG2SSP_AP_SENSOR_PROXTHRESHOLD 0xf2
+#define SSP_MSG2SSP_AP_SENSOR_BARCODE_EMUL 0xf3
+#define SSP_MSG2SSP_AP_SENSOR_SCANNING 0xf4
+#define SSP_MSG2SSP_AP_SET_MAGNETIC_HWOFFSET 0xf5
+#define SSP_MSG2SSP_AP_GET_MAGNETIC_HWOFFSET 0xf6
+#define SSP_MSG2SSP_AP_SENSOR_GESTURE_CURRENT 0xf7
+#define SSP_MSG2SSP_AP_GET_THERM 0xf8
+#define SSP_MSG2SSP_AP_GET_BIG_DATA 0xf9
+#define SSP_MSG2SSP_AP_SET_BIG_DATA 0xfa
+#define SSP_MSG2SSP_AP_START_BIG_DATA 0xfb
+#define SSP_MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX 0xfd
+#define SSP_MSG2SSP_AP_SENSOR_TILT 0xea
+#define SSP_MSG2SSP_AP_MCU_SET_TIME 0xfe
+#define SSP_MSG2SSP_AP_MCU_GET_TIME 0xff
+
+#define SSP_MSG2SSP_AP_FUSEROM 0x01
+
+/* voice data */
+#define SSP_TYPE_WAKE_UP_VOICE_SERVICE 0x01
+#define SSP_TYPE_WAKE_UP_VOICE_SOUND_SOURCE_AM 0x01
+#define SSP_TYPE_WAKE_UP_VOICE_SOUND_SOURCE_GRAMMER 0x02
+
+/* Factory Test */
+#define SSP_ACCELEROMETER_FACTORY 0x80
+#define SSP_GYROSCOPE_FACTORY 0x81
+#define SSP_GEOMAGNETIC_FACTORY 0x82
+#define SSP_PRESSURE_FACTORY 0x85
+#define SSP_GESTURE_FACTORY 0x86
+#define SSP_TEMPHUMIDITY_CRC_FACTORY 0x88
+#define SSP_GYROSCOPE_TEMP_FACTORY 0x8a
+#define SSP_GYROSCOPE_DPS_FACTORY 0x8b
+#define SSP_MCU_FACTORY 0x8c
+#define SSP_MCU_SLEEP_FACTORY 0x8d
+
+/* SSP -> AP ACK about write CMD */
+#define SSP_MSG_ACK 0x80 /* ACK from SSP to AP */
+#define SSP_MSG_NAK 0x70 /* NAK from SSP to AP */
+
+struct ssp_sensorhub_info {
+ char *fw_name;
+ char *fw_crashed_name;
+ unsigned int fw_rev;
+ const u8 * const mag_table;
+ const unsigned int mag_length;
+};
+
+/* ssp_msg options bit */
+#define SSP_RW 0
+#define SSP_INDEX 3
+
+#define SSP_AP2HUB_READ 0
+#define SSP_AP2HUB_WRITE 1
+#define SSP_HUB2AP_WRITE 2
+#define SSP_AP2HUB_READY 3
+#define SSP_AP2HUB_RETURN 4
+
+/**
+ * struct ssp_data - ssp platformdata structure
+ * @spi: spi device
+ * @sensorhub_info: info about sensorhub board specific features
+ * @wdt_timer: watchdog timer
+ * @work_wdt: watchdog work
+ * @work_firmware: firmware upgrade work queue
+ * @work_refresh: refresh work queue for reset request from MCU
+ * @shut_down: shut down flag
+ * @mcu_dump_mode: mcu dump mode for debug
+ * @time_syncing: time syncing indication flag
+ * @timestamp: previous time in ns calculated for time syncing
+ * @check_status: status table for each sensor
+ * @com_fail_cnt: communication fail count
+ * @reset_cnt: reset count
+ * @timeout_cnt: timeout count
+ * @available_sensors: available sensors seen by sensorhub (bit array)
+ * @cur_firm_rev: cached current firmware revision
+ * @last_resume_state: last AP resume/suspend state used to handle the PM
+ * state of ssp
+ * @last_ap_state: (obsolete) sleep notification for MCU
+ * @sensor_enable: sensor enable mask
+ * @delay_buf: data acquisition intervals table
+ * @batch_latency_buf: yet unknown but existing in communication protocol
+ * @batch_opt_buf: yet unknown but existing in communication protocol
+ * @accel_position: yet unknown but existing in communication protocol
+ * @mag_position: yet unknown but existing in communication protocol
+ * @fw_dl_state: firmware download state
+ * @comm_lock: lock protecting the handshake
+ * @pending_lock: lock protecting pending list and completion
+ * @mcu_reset_gpio: mcu reset line
+ * @ap_mcu_gpio: ap to mcu gpio line
+ * @mcu_ap_gpio: mcu to ap gpio line
+ * @pending_list: pending list for messages queued to be sent/read
+ * @sensor_devs: registered IIO devices table
+ * @enable_refcount: enable reference count for wdt (watchdog timer)
+ * @header_buffer: cache aligned buffer for packet header
+ */
+struct ssp_data {
+ struct spi_device *spi;
+ struct ssp_sensorhub_info *sensorhub_info;
+ struct timer_list wdt_timer;
+ struct work_struct work_wdt;
+ struct delayed_work work_refresh;
+
+ bool shut_down;
+ bool mcu_dump_mode;
+ bool time_syncing;
+ int64_t timestamp;
+
+ int check_status[SSP_SENSOR_MAX];
+
+ unsigned int com_fail_cnt;
+ unsigned int reset_cnt;
+ unsigned int timeout_cnt;
+
+ unsigned int available_sensors;
+ unsigned int cur_firm_rev;
+
+ char last_resume_state;
+ char last_ap_state;
+
+ unsigned int sensor_enable;
+ u32 delay_buf[SSP_SENSOR_MAX];
+ s32 batch_latency_buf[SSP_SENSOR_MAX];
+ s8 batch_opt_buf[SSP_SENSOR_MAX];
+
+ int accel_position;
+ int mag_position;
+ int fw_dl_state;
+
+ struct mutex comm_lock;
+ struct mutex pending_lock;
+
+ int mcu_reset_gpio;
+ int ap_mcu_gpio;
+ int mcu_ap_gpio;
+
+ struct list_head pending_list;
+
+ struct iio_dev *sensor_devs[SSP_SENSOR_MAX];
+ atomic_t enable_refcount;
+
+ __le16 header_buffer[SSP_HEADER_BUFFER_SIZE / sizeof(__le16)]
+ ____cacheline_aligned;
+};
+
+void ssp_clean_pending_list(struct ssp_data *data);
+
+int ssp_command(struct ssp_data *data, char command, int arg);
+
+int ssp_send_instruction(struct ssp_data *data, u8 inst, u8 sensor_type,
+ u8 *send_buf, u8 length);
+
+int ssp_irq_msg(struct ssp_data *data);
+
+int ssp_get_chipid(struct ssp_data *data);
+
+int ssp_set_magnetic_matrix(struct ssp_data *data);
+
+unsigned int ssp_get_sensor_scanning_info(struct ssp_data *data);
+
+unsigned int ssp_get_firmware_rev(struct ssp_data *data);
+
+int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay);
+
+#endif /* __SSP_SENSORHUB_H__ */
diff --git a/drivers/iio/common/ssp_sensors/ssp_dev.c b/drivers/iio/common/ssp_sensors/ssp_dev.c
new file mode 100644
index 000000000000..52d70435f5a1
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_dev.c
@@ -0,0 +1,712 @@
+/*
+ * Copyright (C) 2014, Samsung Electronics Co. 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. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/iio/iio.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include "ssp.h"
+
+#define SSP_WDT_TIME 10000
+#define SSP_LIMIT_RESET_CNT 20
+#define SSP_LIMIT_TIMEOUT_CNT 3
+
+/* It is possible that it is max clk rate for version 1.0 of bootcode */
+#define SSP_BOOT_SPI_HZ 400000
+
+/*
+ * These fields can look enigmatic but this structure is used mainly to flat
+ * some values and depends on command type.
+ */
+struct ssp_instruction {
+ __le32 a;
+ __le32 b;
+ u8 c;
+} __attribute__((__packed__));
+
+static const u8 ssp_magnitude_table[] = {110, 85, 171, 71, 203, 195, 0, 67,
+ 208, 56, 175, 244, 206, 213, 0, 92, 250, 0, 55, 48, 189, 252, 171,
+ 243, 13, 45, 250};
+
+static const struct ssp_sensorhub_info ssp_rinato_info = {
+ .fw_name = "ssp_B2.fw",
+ .fw_crashed_name = "ssp_crashed.fw",
+ .fw_rev = 14052300,
+ .mag_table = ssp_magnitude_table,
+ .mag_length = ARRAY_SIZE(ssp_magnitude_table),
+};
+
+static const struct ssp_sensorhub_info ssp_thermostat_info = {
+ .fw_name = "thermostat_B2.fw",
+ .fw_crashed_name = "ssp_crashed.fw",
+ .fw_rev = 14080600,
+ .mag_table = ssp_magnitude_table,
+ .mag_length = ARRAY_SIZE(ssp_magnitude_table),
+};
+
+static const struct mfd_cell sensorhub_sensor_devs[] = {
+ {
+ .name = "ssp-accelerometer",
+ },
+ {
+ .name = "ssp-gyroscope",
+ },
+};
+
+static void ssp_toggle_mcu_reset_gpio(struct ssp_data *data)
+{
+ gpio_set_value(data->mcu_reset_gpio, 0);
+ usleep_range(1000, 1200);
+ gpio_set_value(data->mcu_reset_gpio, 1);
+ msleep(50);
+}
+
+static void ssp_sync_available_sensors(struct ssp_data *data)
+{
+ int i, ret;
+
+ for (i = 0; i < SSP_SENSOR_MAX; ++i) {
+ if (data->available_sensors & BIT(i)) {
+ ret = ssp_enable_sensor(data, i, data->delay_buf[i]);
+ if (ret < 0) {
+ dev_err(&data->spi->dev,
+ "Sync sensor nr: %d fail\n", i);
+ continue;
+ }
+ }
+ }
+
+ ret = ssp_command(data, SSP_MSG2SSP_AP_MCU_SET_DUMPMODE,
+ data->mcu_dump_mode);
+ if (ret < 0)
+ dev_err(&data->spi->dev,
+ "SSP_MSG2SSP_AP_MCU_SET_DUMPMODE failed\n");
+}
+
+static void ssp_enable_mcu(struct ssp_data *data, bool enable)
+{
+ dev_info(&data->spi->dev, "current shutdown = %d, old = %d\n", enable,
+ data->shut_down);
+
+ if (enable && data->shut_down) {
+ data->shut_down = false;
+ enable_irq(data->spi->irq);
+ enable_irq_wake(data->spi->irq);
+ } else if (!enable && !data->shut_down) {
+ data->shut_down = true;
+ disable_irq(data->spi->irq);
+ disable_irq_wake(data->spi->irq);
+ } else {
+ dev_warn(&data->spi->dev, "current shutdown = %d, old = %d\n",
+ enable, data->shut_down);
+ }
+}
+
+/*
+ * This function is the first one which communicates with the mcu so it is
+ * possible that the first attempt will fail
+ */
+static int ssp_check_fwbl(struct ssp_data *data)
+{
+ int retries = 0;
+
+ while (retries++ < 5) {
+ data->cur_firm_rev = ssp_get_firmware_rev(data);
+ if (data->cur_firm_rev == SSP_INVALID_REVISION ||
+ data->cur_firm_rev == SSP_INVALID_REVISION2) {
+ dev_warn(&data->spi->dev,
+ "Invalid revision, trying %d time\n", retries);
+ } else {
+ break;
+ }
+ }
+
+ if (data->cur_firm_rev == SSP_INVALID_REVISION ||
+ data->cur_firm_rev == SSP_INVALID_REVISION2) {
+ dev_err(&data->spi->dev, "SSP_INVALID_REVISION\n");
+ return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
+ }
+
+ dev_info(&data->spi->dev,
+ "MCU Firm Rev : Old = %8u, New = %8u\n",
+ data->cur_firm_rev,
+ data->sensorhub_info->fw_rev);
+
+ if (data->cur_firm_rev != data->sensorhub_info->fw_rev)
+ return SSP_FW_DL_STATE_NEED_TO_SCHEDULE;
+
+ return SSP_FW_DL_STATE_NONE;
+}
+
+static void ssp_reset_mcu(struct ssp_data *data)
+{
+ ssp_enable_mcu(data, false);
+ ssp_clean_pending_list(data);
+ ssp_toggle_mcu_reset_gpio(data);
+ ssp_enable_mcu(data, true);
+}
+
+static void ssp_wdt_work_func(struct work_struct *work)
+{
+ struct ssp_data *data = container_of(work, struct ssp_data, work_wdt);
+
+ dev_err(&data->spi->dev, "%s - Sensor state: 0x%x, RC: %u, CC: %u\n",
+ __func__, data->available_sensors, data->reset_cnt,
+ data->com_fail_cnt);
+
+ ssp_reset_mcu(data);
+ data->com_fail_cnt = 0;
+ data->timeout_cnt = 0;
+}
+
+static void ssp_wdt_timer_func(unsigned long ptr)
+{
+ struct ssp_data *data = (struct ssp_data *)ptr;
+
+ switch (data->fw_dl_state) {
+ case SSP_FW_DL_STATE_FAIL:
+ case SSP_FW_DL_STATE_DOWNLOADING:
+ case SSP_FW_DL_STATE_SYNC:
+ goto _mod;
+ }
+
+ if (data->timeout_cnt > SSP_LIMIT_TIMEOUT_CNT ||
+ data->com_fail_cnt > SSP_LIMIT_RESET_CNT)
+ queue_work(system_power_efficient_wq, &data->work_wdt);
+_mod:
+ mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
+}
+
+static void ssp_enable_wdt_timer(struct ssp_data *data)
+{
+ mod_timer(&data->wdt_timer, jiffies + msecs_to_jiffies(SSP_WDT_TIME));
+}
+
+static void ssp_disable_wdt_timer(struct ssp_data *data)
+{
+ del_timer_sync(&data->wdt_timer);
+ cancel_work_sync(&data->work_wdt);
+}
+
+/**
+ * ssp_get_sensor_delay() - gets sensor data acquisition period
+ * @data: sensorhub structure
+ * @type: SSP sensor type
+ *
+ * Returns acquisition period in ms
+ */
+u32 ssp_get_sensor_delay(struct ssp_data *data, enum ssp_sensor_type type)
+{
+ return data->delay_buf[type];
+}
+EXPORT_SYMBOL(ssp_get_sensor_delay);
+
+/**
+ * ssp_enable_sensor() - enables data acquisition for sensor
+ * @data: sensorhub structure
+ * @type: SSP sensor type
+ * @delay: delay in ms
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_enable_sensor(struct ssp_data *data, enum ssp_sensor_type type,
+ u32 delay)
+{
+ int ret;
+ struct ssp_instruction to_send;
+
+ to_send.a = cpu_to_le32(delay);
+ to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
+ to_send.c = data->batch_opt_buf[type];
+
+ switch (data->check_status[type]) {
+ case SSP_INITIALIZATION_STATE:
+ /* do calibration step, now just enable */
+ case SSP_ADD_SENSOR_STATE:
+ ret = ssp_send_instruction(data,
+ SSP_MSG2SSP_INST_BYPASS_SENSOR_ADD,
+ type,
+ (u8 *)&to_send, sizeof(to_send));
+ if (ret < 0) {
+ dev_err(&data->spi->dev, "Enabling sensor failed\n");
+ data->check_status[type] = SSP_NO_SENSOR_STATE;
+ goto derror;
+ }
+
+ data->sensor_enable |= BIT(type);
+ data->check_status[type] = SSP_RUNNING_SENSOR_STATE;
+ break;
+ case SSP_RUNNING_SENSOR_STATE:
+ ret = ssp_send_instruction(data,
+ SSP_MSG2SSP_INST_CHANGE_DELAY, type,
+ (u8 *)&to_send, sizeof(to_send));
+ if (ret < 0) {
+ dev_err(&data->spi->dev,
+ "Changing sensor delay failed\n");
+ goto derror;
+ }
+ break;
+ default:
+ data->check_status[type] = SSP_ADD_SENSOR_STATE;
+ break;
+ }
+
+ data->delay_buf[type] = delay;
+
+ if (atomic_inc_return(&data->enable_refcount) == 1)
+ ssp_enable_wdt_timer(data);
+
+ return 0;
+
+derror:
+ return ret;
+}
+EXPORT_SYMBOL(ssp_enable_sensor);
+
+/**
+ * ssp_change_delay() - changes data acquisition for sensor
+ * @data: sensorhub structure
+ * @type: SSP sensor type
+ * @delay: delay in ms
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_change_delay(struct ssp_data *data, enum ssp_sensor_type type,
+ u32 delay)
+{
+ int ret;
+ struct ssp_instruction to_send;
+
+ to_send.a = cpu_to_le32(delay);
+ to_send.b = cpu_to_le32(data->batch_latency_buf[type]);
+ to_send.c = data->batch_opt_buf[type];
+
+ ret = ssp_send_instruction(data, SSP_MSG2SSP_INST_CHANGE_DELAY, type,
+ (u8 *)&to_send, sizeof(to_send));
+ if (ret < 0) {
+ dev_err(&data->spi->dev, "Changing sensor delay failed\n");
+ return ret;
+ }
+
+ data->delay_buf[type] = delay;
+
+ return 0;
+}
+EXPORT_SYMBOL(ssp_change_delay);
+
+/**
+ * ssp_disable_sensor() - disables sensor
+ *
+ * @data: sensorhub structure
+ * @type: SSP sensor type
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_disable_sensor(struct ssp_data *data, enum ssp_sensor_type type)
+{
+ int ret;
+ __le32 command;
+
+ if (data->sensor_enable & BIT(type)) {
+ command = cpu_to_le32(data->delay_buf[type]);
+
+ ret = ssp_send_instruction(data,
+ SSP_MSG2SSP_INST_BYPASS_SENSOR_RM,
+ type, (u8 *)&command,
+ sizeof(command));
+ if (ret < 0) {
+ dev_err(&data->spi->dev, "Remove sensor fail\n");
+ return ret;
+ }
+
+ data->sensor_enable &= ~BIT(type);
+ }
+
+ data->check_status[type] = SSP_ADD_SENSOR_STATE;
+
+ if (atomic_dec_and_test(&data->enable_refcount))
+ ssp_disable_wdt_timer(data);
+
+ return 0;
+}
+EXPORT_SYMBOL(ssp_disable_sensor);
+
+static irqreturn_t ssp_irq_thread_fn(int irq, void *dev_id)
+{
+ struct ssp_data *data = dev_id;
+
+ /*
+ * This wrapper is done to preserve error path for ssp_irq_msg, also
+ * it is defined in different file.
+ */
+ ssp_irq_msg(data);
+
+ return IRQ_HANDLED;
+}
+
+static int ssp_initialize_mcu(struct ssp_data *data)
+{
+ int ret;
+
+ ssp_clean_pending_list(data);
+
+ ret = ssp_get_chipid(data);
+ if (ret != SSP_DEVICE_ID) {
+ dev_err(&data->spi->dev, "%s - MCU %s ret = %d\n", __func__,
+ ret < 0 ? "is not working" : "identification failed",
+ ret);
+ return ret < 0 ? ret : -ENODEV;
+ }
+
+ dev_info(&data->spi->dev, "MCU device ID = %d\n", ret);
+
+ /*
+ * needs clarification, for now do not want to export all transfer
+ * methods to sensors' drivers
+ */
+ ret = ssp_set_magnetic_matrix(data);
+ if (ret < 0) {
+ dev_err(&data->spi->dev,
+ "%s - ssp_set_magnetic_matrix failed\n", __func__);
+ return ret;
+ }
+
+ data->available_sensors = ssp_get_sensor_scanning_info(data);
+ if (data->available_sensors == 0) {
+ dev_err(&data->spi->dev,
+ "%s - ssp_get_sensor_scanning_info failed\n", __func__);
+ return -EIO;
+ }
+
+ data->cur_firm_rev = ssp_get_firmware_rev(data);
+ dev_info(&data->spi->dev, "MCU Firm Rev : New = %8u\n",
+ data->cur_firm_rev);
+
+ return ssp_command(data, SSP_MSG2SSP_AP_MCU_DUMP_CHECK, 0);
+}
+
+/*
+ * sensorhub can request its reinitialization as some brutal and rare error
+ * handling. It can be requested from the MCU.
+ */
+static void ssp_refresh_task(struct work_struct *work)
+{
+ struct ssp_data *data = container_of((struct delayed_work *)work,
+ struct ssp_data, work_refresh);
+
+ dev_info(&data->spi->dev, "refreshing\n");
+
+ data->reset_cnt++;
+
+ if (ssp_initialize_mcu(data) >= 0) {
+ ssp_sync_available_sensors(data);
+ if (data->last_ap_state != 0)
+ ssp_command(data, data->last_ap_state, 0);
+
+ if (data->last_resume_state != 0)
+ ssp_command(data, data->last_resume_state, 0);
+
+ data->timeout_cnt = 0;
+ data->com_fail_cnt = 0;
+ }
+}
+
+int ssp_queue_ssp_refresh_task(struct ssp_data *data, unsigned int delay)
+{
+ cancel_delayed_work_sync(&data->work_refresh);
+
+ return queue_delayed_work(system_power_efficient_wq,
+ &data->work_refresh,
+ msecs_to_jiffies(delay));
+}
+
+#ifdef CONFIG_OF
+static struct of_device_id ssp_of_match[] = {
+ {
+ .compatible = "samsung,sensorhub-rinato",
+ .data = &ssp_rinato_info,
+ }, {
+ .compatible = "samsung,sensorhub-thermostat",
+ .data = &ssp_thermostat_info,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, ssp_of_match);
+
+static struct ssp_data *ssp_parse_dt(struct device *dev)
+{
+ int ret;
+ struct ssp_data *data;
+ struct device_node *node = dev->of_node;
+ const struct of_device_id *match;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ data->mcu_ap_gpio = of_get_named_gpio(node, "mcu-ap-gpios", 0);
+ if (data->mcu_ap_gpio < 0)
+ goto err_free_pd;
+
+ data->ap_mcu_gpio = of_get_named_gpio(node, "ap-mcu-gpios", 0);
+ if (data->ap_mcu_gpio < 0)
+ goto err_free_pd;
+
+ data->mcu_reset_gpio = of_get_named_gpio(node, "mcu-reset-gpios", 0);
+ if (data->mcu_reset_gpio < 0)
+ goto err_free_pd;
+
+ ret = devm_gpio_request_one(dev, data->ap_mcu_gpio, GPIOF_OUT_INIT_HIGH,
+ "ap-mcu-gpios");
+ if (ret)
+ goto err_free_pd;
+
+ ret = devm_gpio_request_one(dev, data->mcu_reset_gpio,
+ GPIOF_OUT_INIT_HIGH, "mcu-reset-gpios");
+ if (ret)
+ goto err_ap_mcu;
+
+ match = of_match_node(ssp_of_match, node);
+ if (!match)
+ goto err_mcu_reset_gpio;
+
+ data->sensorhub_info = (struct ssp_sensorhub_info *)match->data;
+
+ dev_set_drvdata(dev, data);
+
+ return data;
+
+err_mcu_reset_gpio:
+ devm_gpio_free(dev, data->mcu_reset_gpio);
+err_ap_mcu:
+ devm_gpio_free(dev, data->ap_mcu_gpio);
+err_free_pd:
+ devm_kfree(dev, data);
+ return NULL;
+}
+#else
+static struct ssp_data *ssp_parse_dt(struct device *pdev)
+{
+ return NULL;
+}
+#endif
+
+/**
+ * ssp_register_consumer() - registers iio consumer in ssp framework
+ *
+ * @indio_dev: consumer iio device
+ * @type: ssp sensor type
+ */
+void ssp_register_consumer(struct iio_dev *indio_dev, enum ssp_sensor_type type)
+{
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ data->sensor_devs[type] = indio_dev;
+}
+EXPORT_SYMBOL(ssp_register_consumer);
+
+static int ssp_probe(struct spi_device *spi)
+{
+ int ret, i;
+ struct ssp_data *data;
+
+ data = ssp_parse_dt(&spi->dev);
+ if (!data) {
+ dev_err(&spi->dev, "Failed to find platform data\n");
+ return -ENODEV;
+ }
+
+ ret = mfd_add_devices(&spi->dev, -1, sensorhub_sensor_devs,
+ ARRAY_SIZE(sensorhub_sensor_devs), NULL, 0, NULL);
+ if (ret < 0) {
+ dev_err(&spi->dev, "mfd add devices fail\n");
+ return ret;
+ }
+
+ spi->mode = SPI_MODE_1;
+ ret = spi_setup(spi);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Failed to setup spi\n");
+ return ret;
+ }
+
+ data->fw_dl_state = SSP_FW_DL_STATE_NONE;
+ data->spi = spi;
+ spi_set_drvdata(spi, data);
+
+ mutex_init(&data->comm_lock);
+
+ for (i = 0; i < SSP_SENSOR_MAX; ++i) {
+ data->delay_buf[i] = SSP_DEFAULT_POLLING_DELAY;
+ data->batch_latency_buf[i] = 0;
+ data->batch_opt_buf[i] = 0;
+ data->check_status[i] = SSP_INITIALIZATION_STATE;
+ }
+
+ data->delay_buf[SSP_BIO_HRM_LIB] = 100;
+
+ data->time_syncing = true;
+
+ mutex_init(&data->pending_lock);
+ INIT_LIST_HEAD(&data->pending_list);
+
+ atomic_set(&data->enable_refcount, 0);
+
+ INIT_WORK(&data->work_wdt, ssp_wdt_work_func);
+ INIT_DELAYED_WORK(&data->work_refresh, ssp_refresh_task);
+
+ setup_timer(&data->wdt_timer, ssp_wdt_timer_func, (unsigned long)data);
+
+ ret = request_threaded_irq(data->spi->irq, NULL,
+ ssp_irq_thread_fn,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ "SSP_Int", data);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Irq request fail\n");
+ goto err_setup_irq;
+ }
+
+ /* Let's start with enabled one so irq balance could be ok */
+ data->shut_down = false;
+
+ /* just to avoid unbalanced irq set wake up */
+ enable_irq_wake(data->spi->irq);
+
+ data->fw_dl_state = ssp_check_fwbl(data);
+ if (data->fw_dl_state == SSP_FW_DL_STATE_NONE) {
+ ret = ssp_initialize_mcu(data);
+ if (ret < 0) {
+ dev_err(&spi->dev, "Initialize_mcu failed\n");
+ goto err_read_reg;
+ }
+ } else {
+ dev_err(&spi->dev, "Firmware version not supported\n");
+ ret = -EPERM;
+ goto err_read_reg;
+ }
+
+ return 0;
+
+err_read_reg:
+ free_irq(data->spi->irq, data);
+err_setup_irq:
+ mutex_destroy(&data->pending_lock);
+ mutex_destroy(&data->comm_lock);
+
+ dev_err(&spi->dev, "Probe failed!\n");
+
+ return ret;
+}
+
+static int ssp_remove(struct spi_device *spi)
+{
+ struct ssp_data *data = spi_get_drvdata(spi);
+
+ if (ssp_command(data, SSP_MSG2SSP_AP_STATUS_SHUTDOWN, 0) < 0)
+ dev_err(&data->spi->dev,
+ "SSP_MSG2SSP_AP_STATUS_SHUTDOWN failed\n");
+
+ ssp_enable_mcu(data, false);
+ ssp_disable_wdt_timer(data);
+
+ ssp_clean_pending_list(data);
+
+ free_irq(data->spi->irq, data);
+
+ del_timer_sync(&data->wdt_timer);
+ cancel_work_sync(&data->work_wdt);
+
+ mutex_destroy(&data->comm_lock);
+ mutex_destroy(&data->pending_lock);
+
+ mfd_remove_devices(&spi->dev);
+
+ return 0;
+}
+
+static int ssp_suspend(struct device *dev)
+{
+ int ret;
+ struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
+
+ data->last_resume_state = SSP_MSG2SSP_AP_STATUS_SUSPEND;
+
+ if (atomic_read(&data->enable_refcount) > 0)
+ ssp_disable_wdt_timer(data);
+
+ ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_SUSPEND, 0);
+ if (ret < 0) {
+ dev_err(&data->spi->dev,
+ "%s SSP_MSG2SSP_AP_STATUS_SUSPEND failed\n", __func__);
+
+ ssp_enable_wdt_timer(data);
+ return ret;
+ }
+
+ data->time_syncing = false;
+ disable_irq(data->spi->irq);
+
+ return 0;
+}
+
+static int ssp_resume(struct device *dev)
+{
+ int ret;
+ struct ssp_data *data = spi_get_drvdata(to_spi_device(dev));
+
+ enable_irq(data->spi->irq);
+
+ if (atomic_read(&data->enable_refcount) > 0)
+ ssp_enable_wdt_timer(data);
+
+ ret = ssp_command(data, SSP_MSG2SSP_AP_STATUS_RESUME, 0);
+ if (ret < 0) {
+ dev_err(&data->spi->dev,
+ "%s SSP_MSG2SSP_AP_STATUS_RESUME failed\n", __func__);
+ ssp_disable_wdt_timer(data);
+ return ret;
+ }
+
+ /* timesyncing is set by MCU */
+ data->last_resume_state = SSP_MSG2SSP_AP_STATUS_RESUME;
+
+ return 0;
+}
+
+static const struct dev_pm_ops ssp_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(ssp_suspend, ssp_resume)
+};
+
+static struct spi_driver ssp_driver = {
+ .probe = ssp_probe,
+ .remove = ssp_remove,
+ .driver = {
+ .pm = &ssp_pm_ops,
+ .bus = &spi_bus_type,
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ssp_of_match),
+ .name = "sensorhub"
+ },
+};
+
+module_spi_driver(ssp_driver);
+
+MODULE_DESCRIPTION("ssp sensorhub driver");
+MODULE_AUTHOR("Samsung Electronics");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/ssp_sensors/ssp_iio.c b/drivers/iio/common/ssp_sensors/ssp_iio.c
new file mode 100644
index 000000000000..a3ae165f8d9f
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_iio.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014, Samsung Electronics Co. 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. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/iio/common/ssp_sensors.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "ssp_iio_sensor.h"
+
+/**
+ * ssp_common_buffer_postenable() - generic postenable callback for ssp buffer
+ *
+ * @indio_dev: iio device
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_common_buffer_postenable(struct iio_dev *indio_dev)
+{
+ struct ssp_sensor_data *spd = iio_priv(indio_dev);
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ /* the allocation is made in post because scan size is known in this
+ * moment
+ * */
+ spd->buffer = kmalloc(indio_dev->scan_bytes, GFP_KERNEL | GFP_DMA);
+ if (!spd->buffer)
+ return -ENOMEM;
+
+ return ssp_enable_sensor(data, spd->type,
+ ssp_get_sensor_delay(data, spd->type));
+}
+EXPORT_SYMBOL(ssp_common_buffer_postenable);
+
+/**
+ * ssp_common_buffer_postdisable() - generic postdisable callback for ssp buffer
+ *
+ * @indio_dev: iio device
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_common_buffer_postdisable(struct iio_dev *indio_dev)
+{
+ int ret;
+ struct ssp_sensor_data *spd = iio_priv(indio_dev);
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ ret = ssp_disable_sensor(data, spd->type);
+ if (ret < 0)
+ return ret;
+
+ kfree(spd->buffer);
+
+ return ret;
+}
+EXPORT_SYMBOL(ssp_common_buffer_postdisable);
+
+/**
+ * ssp_common_process_data() - Common process data callback for ssp sensors
+ *
+ * @indio_dev: iio device
+ * @buf: source buffer
+ * @len: sensor data length
+ * @timestamp: system timestamp
+ *
+ * Returns 0 or negative value in case of error
+ */
+int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
+ unsigned int len, int64_t timestamp)
+{
+ __le32 time;
+ int64_t calculated_time;
+ struct ssp_sensor_data *spd = iio_priv(indio_dev);
+
+ if (indio_dev->scan_bytes == 0)
+ return 0;
+
+ /*
+ * it always sends full set of samples, remember about available masks
+ */
+ memcpy(spd->buffer, buf, len);
+
+ if (indio_dev->scan_timestamp) {
+ memcpy(&time, &((char *)buf)[len], SSP_TIME_SIZE);
+ calculated_time =
+ timestamp + (int64_t)le32_to_cpu(time) * 1000000;
+ }
+
+ return iio_push_to_buffers_with_timestamp(indio_dev, spd->buffer,
+ calculated_time);
+}
+EXPORT_SYMBOL(ssp_common_process_data);
+
+MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
+MODULE_DESCRIPTION("Samsung sensorhub commons");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
new file mode 100644
index 000000000000..541c6590d69c
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_iio_sensor.h
@@ -0,0 +1,71 @@
+#ifndef __SSP_IIO_SENSOR_H__
+#define __SSP_IIO_SENSOR_H__
+
+#define SSP_CHANNEL_AG(_type, _mod, _index) \
+{ \
+ .type = _type,\
+ .modified = 1,\
+ .channel2 = _mod,\
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SAMP_FREQ),\
+ .scan_index = _index,\
+ .scan_type = {\
+ .sign = 's',\
+ .realbits = 16,\
+ .storagebits = 16,\
+ .shift = 0,\
+ .endianness = IIO_LE,\
+ },\
+}
+
+/* It is defined here as it is a mixed timestamp */
+#define SSP_CHAN_TIMESTAMP(_si) { \
+ .type = IIO_TIMESTAMP, \
+ .channel = -1, \
+ .scan_index = _si, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 64, \
+ .storagebits = 64, \
+ }, \
+}
+
+#define SSP_MS_PER_S 1000
+#define SSP_INVERTED_SCALING_FACTOR 1000000U
+
+#define SSP_FACTOR_WITH_MS \
+ (SSP_INVERTED_SCALING_FACTOR * SSP_MS_PER_S)
+
+int ssp_common_buffer_postenable(struct iio_dev *indio_dev);
+
+int ssp_common_buffer_postdisable(struct iio_dev *indio_dev);
+
+int ssp_common_process_data(struct iio_dev *indio_dev, void *buf,
+ unsigned int len, int64_t timestamp);
+
+/* Converts time in ms to frequency */
+static inline void ssp_convert_to_freq(u32 time, int *integer_part,
+ int *fractional)
+{
+ if (time == 0) {
+ *fractional = 0;
+ *integer_part = 0;
+ return;
+ }
+
+ *integer_part = SSP_FACTOR_WITH_MS / time;
+ *fractional = *integer_part % SSP_INVERTED_SCALING_FACTOR;
+ *integer_part = *integer_part / SSP_INVERTED_SCALING_FACTOR;
+}
+
+/* Converts frequency to time in ms */
+static inline int ssp_convert_to_time(int integer_part, int fractional)
+{
+ u64 value;
+
+ value = (u64)integer_part * SSP_INVERTED_SCALING_FACTOR + fractional;
+ if (value == 0)
+ return 0;
+
+ return div64_u64((u64)SSP_FACTOR_WITH_MS, value);
+}
+#endif /* __SSP_IIO_SENSOR_H__ */
diff --git a/drivers/iio/common/ssp_sensors/ssp_spi.c b/drivers/iio/common/ssp_sensors/ssp_spi.c
new file mode 100644
index 000000000000..704284a475ae
--- /dev/null
+++ b/drivers/iio/common/ssp_sensors/ssp_spi.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (C) 2014, Samsung Electronics Co. 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. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include "ssp.h"
+
+#define SSP_DEV (&data->spi->dev)
+#define SSP_GET_MESSAGE_TYPE(data) (data & (3 << SSP_RW))
+
+/*
+ * SSP -> AP Instruction
+ * They tell what packet type can be expected. In the future there will
+ * be less of them. BYPASS means common sensor packets with accel, gyro,
+ * hrm etc. data. LIBRARY and META are mock-up's for now.
+ */
+#define SSP_MSG2AP_INST_BYPASS_DATA 0x37
+#define SSP_MSG2AP_INST_LIBRARY_DATA 0x01
+#define SSP_MSG2AP_INST_DEBUG_DATA 0x03
+#define SSP_MSG2AP_INST_BIG_DATA 0x04
+#define SSP_MSG2AP_INST_META_DATA 0x05
+#define SSP_MSG2AP_INST_TIME_SYNC 0x06
+#define SSP_MSG2AP_INST_RESET 0x07
+
+#define SSP_UNIMPLEMENTED -1
+
+struct ssp_msg_header {
+ u8 cmd;
+ __le16 length;
+ __le16 options;
+ __le32 data;
+} __attribute__((__packed__));
+
+struct ssp_msg {
+ u16 length;
+ u16 options;
+ struct list_head list;
+ struct completion *done;
+ struct ssp_msg_header *h;
+ char *buffer;
+};
+
+static const int ssp_offset_map[SSP_SENSOR_MAX] = {
+ [SSP_ACCELEROMETER_SENSOR] = SSP_ACCELEROMETER_SIZE +
+ SSP_TIME_SIZE,
+ [SSP_GYROSCOPE_SENSOR] = SSP_GYROSCOPE_SIZE +
+ SSP_TIME_SIZE,
+ [SSP_GEOMAGNETIC_UNCALIB_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_GEOMAGNETIC_RAW] = SSP_UNIMPLEMENTED,
+ [SSP_GEOMAGNETIC_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_PRESSURE_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_GESTURE_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_PROXIMITY_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_TEMPERATURE_HUMIDITY_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_LIGHT_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_PROXIMITY_RAW] = SSP_UNIMPLEMENTED,
+ [SSP_ORIENTATION_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_STEP_DETECTOR] = SSP_UNIMPLEMENTED,
+ [SSP_SIG_MOTION_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_GYRO_UNCALIB_SENSOR] = SSP_UNIMPLEMENTED,
+ [SSP_GAME_ROTATION_VECTOR] = SSP_UNIMPLEMENTED,
+ [SSP_ROTATION_VECTOR] = SSP_UNIMPLEMENTED,
+ [SSP_STEP_COUNTER] = SSP_UNIMPLEMENTED,
+ [SSP_BIO_HRM_RAW] = SSP_BIO_HRM_RAW_SIZE +
+ SSP_TIME_SIZE,
+ [SSP_BIO_HRM_RAW_FAC] = SSP_BIO_HRM_RAW_FAC_SIZE +
+ SSP_TIME_SIZE,
+ [SSP_BIO_HRM_LIB] = SSP_BIO_HRM_LIB_SIZE +
+ SSP_TIME_SIZE,
+};
+
+#define SSP_HEADER_SIZE (sizeof(struct ssp_msg_header))
+#define SSP_HEADER_SIZE_ALIGNED (ALIGN(SSP_HEADER_SIZE, 4))
+
+static struct ssp_msg *ssp_create_msg(u8 cmd, u16 len, u16 opt, u32 data)
+{
+ struct ssp_msg_header h;
+ struct ssp_msg *msg;
+
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return NULL;
+
+ h.cmd = cmd;
+ h.length = cpu_to_le16(len);
+ h.options = cpu_to_le16(opt);
+ h.data = cpu_to_le32(data);
+
+ msg->buffer = kzalloc(SSP_HEADER_SIZE_ALIGNED + len,
+ GFP_KERNEL | GFP_DMA);
+ if (!msg->buffer) {
+ kfree(msg);
+ return NULL;
+ }
+
+ msg->length = len;
+ msg->options = opt;
+
+ memcpy(msg->buffer, &h, SSP_HEADER_SIZE);
+
+ return msg;
+}
+
+/*
+ * It is a bit heavy to do it this way but often the function is used to compose
+ * the message from smaller chunks which are placed on the stack. Often the
+ * chunks are small so memcpy should be optimalized.
+ */
+static inline void ssp_fill_buffer(struct ssp_msg *m, unsigned int offset,
+ const void *src, unsigned int len)
+{
+ memcpy(&m->buffer[SSP_HEADER_SIZE_ALIGNED + offset], src, len);
+}
+
+static inline void ssp_get_buffer(struct ssp_msg *m, unsigned int offset,
+ void *dest, unsigned int len)
+{
+ memcpy(dest, &m->buffer[SSP_HEADER_SIZE_ALIGNED + offset], len);
+}
+
+#define SSP_GET_BUFFER_AT_INDEX(m, index) \
+ (m->buffer[SSP_HEADER_SIZE_ALIGNED + index])
+#define SSP_SET_BUFFER_AT_INDEX(m, index, val) \
+ (m->buffer[SSP_HEADER_SIZE_ALIGNED + index] = val)
+
+static void ssp_clean_msg(struct ssp_msg *m)
+{
+ kfree(m->buffer);
+ kfree(m);
+}
+
+static int ssp_print_mcu_debug(char *data_frame, int *data_index,
+ int received_len)
+{
+ int length = data_frame[(*data_index)++];
+
+ if (length > received_len - *data_index || length <= 0) {
+ ssp_dbg("[SSP]: MSG From MCU-invalid debug length(%d/%d)\n",
+ length, received_len);
+ return length ? length : -EPROTO;
+ }
+
+ ssp_dbg("[SSP]: MSG From MCU - %s\n", &data_frame[*data_index]);
+
+ *data_index += length;
+
+ return 0;
+}
+
+/*
+ * It was designed that way - additional lines to some kind of handshake,
+ * please do not ask why - only the firmware guy can know it.
+ */
+static int ssp_check_lines(struct ssp_data *data, bool state)
+{
+ int delay_cnt = 0;
+
+ gpio_set_value_cansleep(data->ap_mcu_gpio, state);
+
+ while (gpio_get_value_cansleep(data->mcu_ap_gpio) != state) {
+ usleep_range(3000, 3500);
+
+ if (data->shut_down || delay_cnt++ > 500) {
+ dev_err(SSP_DEV, "%s:timeout, hw ack wait fail %d\n",
+ __func__, state);
+
+ if (!state)
+ gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
+
+ return -ETIMEDOUT;
+ }
+ }
+
+ return 0;
+}
+
+static int ssp_do_transfer(struct ssp_data *data, struct ssp_msg *msg,
+ struct completion *done, int timeout)
+{
+ int status;
+ /*
+ * check if this is a short one way message or the whole transfer has
+ * second part after an interrupt
+ */
+ const bool use_no_irq = msg->length == 0;
+
+ if (data->shut_down)
+ return -EPERM;
+
+ msg->done = done;
+
+ mutex_lock(&data->comm_lock);
+
+ status = ssp_check_lines(data, false);
+ if (status < 0)
+ goto _error_locked;
+
+ status = spi_write(data->spi, msg->buffer, SSP_HEADER_SIZE);
+ if (status < 0) {
+ gpio_set_value_cansleep(data->ap_mcu_gpio, 1);
+ dev_err(SSP_DEV, "%s spi_write fail\n", __func__);
+ goto _error_locked;
+ }
+
+ if (!use_no_irq) {
+ mutex_lock(&data->pending_lock);
+ list_add_tail(&msg->list, &data->pending_list);
+ mutex_unlock(&data->pending_lock);
+ }
+
+ status = ssp_check_lines(data, true);
+ if (status < 0) {
+ if (!use_no_irq) {
+ mutex_lock(&data->pending_lock);
+ list_del(&msg->list);
+ mutex_unlock(&data->pending_lock);
+ }
+ goto _error_locked;
+ }
+
+ mutex_unlock(&data->comm_lock);
+
+ if (!use_no_irq && done)
+ if (wait_for_completion_timeout(done,
+ msecs_to_jiffies(timeout)) ==
+ 0) {
+ mutex_lock(&data->pending_lock);
+ list_del(&msg->list);
+ mutex_unlock(&data->pending_lock);
+
+ data->timeout_cnt++;
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+
+_error_locked:
+ mutex_unlock(&data->comm_lock);
+ data->timeout_cnt++;
+ return status;
+}
+
+static inline int ssp_spi_sync_command(struct ssp_data *data,
+ struct ssp_msg *msg)
+{
+ return ssp_do_transfer(data, msg, NULL, 0);
+}
+
+static int ssp_spi_sync(struct ssp_data *data, struct ssp_msg *msg,
+ int timeout)
+{
+ DECLARE_COMPLETION_ONSTACK(done);
+
+ if (WARN_ON(!msg->length))
+ return -EPERM;
+
+ return ssp_do_transfer(data, msg, &done, timeout);
+}
+
+static int ssp_handle_big_data(struct ssp_data *data, char *dataframe, int *idx)
+{
+ /* mock-up, it will be changed with adding another sensor types */
+ *idx += 8;
+ return 0;
+}
+
+static int ssp_parse_dataframe(struct ssp_data *data, char *dataframe, int len)
+{
+ int idx, sd;
+ struct timespec ts;
+ struct ssp_sensor_data *spd;
+ struct iio_dev **indio_devs = data->sensor_devs;
+
+ getnstimeofday(&ts);
+
+ for (idx = 0; idx < len;) {
+ switch (dataframe[idx++]) {
+ case SSP_MSG2AP_INST_BYPASS_DATA:
+ sd = dataframe[idx++];
+ if (sd < 0 || sd >= SSP_SENSOR_MAX) {
+ dev_err(SSP_DEV,
+ "Mcu data frame1 error %d\n", sd);
+ return -EPROTO;
+ }
+
+ if (indio_devs[sd]) {
+ spd = iio_priv(indio_devs[sd]);
+ if (spd->process_data)
+ spd->process_data(indio_devs[sd],
+ &dataframe[idx],
+ data->timestamp);
+ } else {
+ dev_err(SSP_DEV, "no client for frame\n");
+ }
+
+ idx += ssp_offset_map[sd];
+ break;
+ case SSP_MSG2AP_INST_DEBUG_DATA:
+ sd = ssp_print_mcu_debug(dataframe, &idx, len);
+ if (sd) {
+ dev_err(SSP_DEV,
+ "Mcu data frame3 error %d\n", sd);
+ return sd;
+ }
+ break;
+ case SSP_MSG2AP_INST_LIBRARY_DATA:
+ idx += len;
+ break;
+ case SSP_MSG2AP_INST_BIG_DATA:
+ ssp_handle_big_data(data, dataframe, &idx);
+ break;
+ case SSP_MSG2AP_INST_TIME_SYNC:
+ data->time_syncing = true;
+ break;
+ case SSP_MSG2AP_INST_RESET:
+ ssp_queue_ssp_refresh_task(data, 0);
+ break;
+ }
+ }
+
+ if (data->time_syncing)
+ data->timestamp = ts.tv_sec * 1000000000ULL + ts.tv_nsec;
+
+ return 0;
+}
+
+/* threaded irq */
+int ssp_irq_msg(struct ssp_data *data)
+{
+ bool found = false;
+ char *buffer;
+ u8 msg_type;
+ int ret;
+ u16 length, msg_options;
+ struct ssp_msg *msg, *n;
+
+ ret = spi_read(data->spi, data->header_buffer, SSP_HEADER_BUFFER_SIZE);
+ if (ret < 0) {
+ dev_err(SSP_DEV, "header read fail\n");
+ return ret;
+ }
+
+ length = le16_to_cpu(data->header_buffer[1]);
+ msg_options = le16_to_cpu(data->header_buffer[0]);
+
+ if (length == 0) {
+ dev_err(SSP_DEV, "length received from mcu is 0\n");
+ return -EINVAL;
+ }
+
+ msg_type = SSP_GET_MESSAGE_TYPE(msg_options);
+
+ switch (msg_type) {
+ case SSP_AP2HUB_READ:
+ case SSP_AP2HUB_WRITE:
+ /*
+ * this is a small list, a few elements - the packets can be
+ * received with no order
+ */
+ mutex_lock(&data->pending_lock);
+ list_for_each_entry_safe(msg, n, &data->pending_list, list) {
+ if (msg->options == msg_options) {
+ list_del(&msg->list);
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ /*
+ * here can be implemented dead messages handling
+ * but the slave should not send such ones - it is to
+ * check but let's handle this
+ */
+ buffer = kmalloc(length, GFP_KERNEL | GFP_DMA);
+ if (!buffer) {
+ ret = -ENOMEM;
+ goto _unlock;
+ }
+
+ /* got dead packet so it is always an error */
+ ret = spi_read(data->spi, buffer, length);
+ if (ret >= 0)
+ ret = -EPROTO;
+
+ kfree(buffer);
+
+ dev_err(SSP_DEV, "No match error %x\n",
+ msg_options);
+
+ goto _unlock;
+ }
+
+ if (msg_type == SSP_AP2HUB_READ)
+ ret = spi_read(data->spi,
+ &msg->buffer[SSP_HEADER_SIZE_ALIGNED],
+ msg->length);
+
+ if (msg_type == SSP_AP2HUB_WRITE) {
+ ret = spi_write(data->spi,
+ &msg->buffer[SSP_HEADER_SIZE_ALIGNED],
+ msg->length);
+ if (msg_options & SSP_AP2HUB_RETURN) {
+ msg->options =
+ SSP_AP2HUB_READ | SSP_AP2HUB_RETURN;
+ msg->length = 1;
+
+ list_add_tail(&msg->list, &data->pending_list);
+ goto _unlock;
+ }
+ }
+
+ if (msg->done)
+ if (!completion_done(msg->done))
+ complete(msg->done);
+_unlock:
+ mutex_unlock(&data->pending_lock);
+ break;
+ case SSP_HUB2AP_WRITE:
+ buffer = kzalloc(length, GFP_KERNEL | GFP_DMA);
+ if (!buffer)
+ return -ENOMEM;
+
+ ret = spi_read(data->spi, buffer, length);
+ if (ret < 0) {
+ dev_err(SSP_DEV, "spi read fail\n");
+ kfree(buffer);
+ break;
+ }
+
+ ret = ssp_parse_dataframe(data, buffer, length);
+
+ kfree(buffer);
+ break;
+
+ default:
+ dev_err(SSP_DEV, "unknown msg type\n");
+ return -EPROTO;
+ }
+
+ return ret;
+}
+
+void ssp_clean_pending_list(struct ssp_data *data)
+{
+ struct ssp_msg *msg, *n;
+
+ mutex_lock(&data->pending_lock);
+ list_for_each_entry_safe(msg, n, &data->pending_list, list) {
+ list_del(&msg->list);
+
+ if (msg->done)
+ if (!completion_done(msg->done))
+ complete(msg->done);
+ }
+ mutex_unlock(&data->pending_lock);
+}
+
+int ssp_command(struct ssp_data *data, char command, int arg)
+{
+ int ret;
+ struct ssp_msg *msg;
+
+ msg = ssp_create_msg(command, 0, SSP_AP2HUB_WRITE, arg);
+ if (!msg)
+ return -ENOMEM;
+
+ ssp_dbg("%s - command 0x%x %d\n", __func__, command, arg);
+
+ ret = ssp_spi_sync_command(data, msg);
+ ssp_clean_msg(msg);
+
+ return ret;
+}
+
+int ssp_send_instruction(struct ssp_data *data, u8 inst, u8 sensor_type,
+ u8 *send_buf, u8 length)
+{
+ int ret;
+ struct ssp_msg *msg;
+
+ if (data->fw_dl_state == SSP_FW_DL_STATE_DOWNLOADING) {
+ dev_err(SSP_DEV, "%s - Skip Inst! DL state = %d\n",
+ __func__, data->fw_dl_state);
+ return -EBUSY;
+ } else if (!(data->available_sensors & BIT(sensor_type)) &&
+ (inst <= SSP_MSG2SSP_INST_CHANGE_DELAY)) {
+ dev_err(SSP_DEV, "%s - Bypass Inst Skip! - %u\n",
+ __func__, sensor_type);
+ return -EIO; /* just fail */
+ }
+
+ msg = ssp_create_msg(inst, length + 2, SSP_AP2HUB_WRITE, 0);
+ if (!msg)
+ return -ENOMEM;
+
+ ssp_fill_buffer(msg, 0, &sensor_type, 1);
+ ssp_fill_buffer(msg, 1, send_buf, length);
+
+ ssp_dbg("%s - Inst = 0x%x, Sensor Type = 0x%x, data = %u\n",
+ __func__, inst, sensor_type, send_buf[1]);
+
+ ret = ssp_spi_sync(data, msg, 1000);
+ ssp_clean_msg(msg);
+
+ return ret;
+}
+
+int ssp_get_chipid(struct ssp_data *data)
+{
+ int ret;
+ char buffer;
+ struct ssp_msg *msg;
+
+ msg = ssp_create_msg(SSP_MSG2SSP_AP_WHOAMI, 1, SSP_AP2HUB_READ, 0);
+ if (!msg)
+ return -ENOMEM;
+
+ ret = ssp_spi_sync(data, msg, 1000);
+
+ buffer = SSP_GET_BUFFER_AT_INDEX(msg, 0);
+
+ ssp_clean_msg(msg);
+
+ return ret < 0 ? ret : buffer;
+}
+
+int ssp_set_magnetic_matrix(struct ssp_data *data)
+{
+ int ret;
+ struct ssp_msg *msg;
+
+ msg = ssp_create_msg(SSP_MSG2SSP_AP_SET_MAGNETIC_STATIC_MATRIX,
+ data->sensorhub_info->mag_length, SSP_AP2HUB_WRITE,
+ 0);
+ if (!msg)
+ return -ENOMEM;
+
+ ssp_fill_buffer(msg, 0, data->sensorhub_info->mag_table,
+ data->sensorhub_info->mag_length);
+
+ ret = ssp_spi_sync(data, msg, 1000);
+ ssp_clean_msg(msg);
+
+ return ret;
+}
+
+unsigned int ssp_get_sensor_scanning_info(struct ssp_data *data)
+{
+ int ret;
+ __le32 result;
+ u32 cpu_result = 0;
+
+ struct ssp_msg *msg = ssp_create_msg(SSP_MSG2SSP_AP_SENSOR_SCANNING, 4,
+ SSP_AP2HUB_READ, 0);
+ if (!msg)
+ return 0;
+
+ ret = ssp_spi_sync(data, msg, 1000);
+ if (ret < 0) {
+ dev_err(SSP_DEV, "%s - spi read fail %d\n", __func__, ret);
+ goto _exit;
+ }
+
+ ssp_get_buffer(msg, 0, &result, 4);
+ cpu_result = le32_to_cpu(result);
+
+ dev_info(SSP_DEV, "%s state: 0x%08x\n", __func__, cpu_result);
+
+_exit:
+ ssp_clean_msg(msg);
+ return cpu_result;
+}
+
+unsigned int ssp_get_firmware_rev(struct ssp_data *data)
+{
+ int ret;
+ __le32 result;
+
+ struct ssp_msg *msg = ssp_create_msg(SSP_MSG2SSP_AP_FIRMWARE_REV, 4,
+ SSP_AP2HUB_READ, 0);
+ if (!msg)
+ return SSP_INVALID_REVISION;
+
+ ret = ssp_spi_sync(data, msg, 1000);
+ if (ret < 0) {
+ dev_err(SSP_DEV, "%s - transfer fail %d\n", __func__, ret);
+ ret = SSP_INVALID_REVISION;
+ goto _exit;
+ }
+
+ ssp_get_buffer(msg, 0, &result, 4);
+ ret = le32_to_cpu(result);
+
+_exit:
+ ssp_clean_msg(msg);
+ return ret;
+}
diff --git a/drivers/iio/common/st_sensors/st_sensors_spi.c b/drivers/iio/common/st_sensors/st_sensors_spi.c
index 78a6a1ab3ece..5b377373f48d 100644
--- a/drivers/iio/common/st_sensors/st_sensors_spi.c
+++ b/drivers/iio/common/st_sensors/st_sensors_spi.c
@@ -54,7 +54,7 @@ static int st_sensors_spi_read(struct st_sensor_transfer_buffer *tb,
if (err)
goto acc_spi_read_error;
- memcpy(data, tb->rx_buf, len*sizeof(u8));
+ memcpy(data, tb->rx_buf, len);
mutex_unlock(&tb->buf_lock);
return len;
diff --git a/drivers/iio/frequency/ad9523.c b/drivers/iio/frequency/ad9523.c
index 7c5245d9f99c..50ed8d1ca45a 100644
--- a/drivers/iio/frequency/ad9523.c
+++ b/drivers/iio/frequency/ad9523.c
@@ -445,7 +445,7 @@ static int ad9523_store_eeprom(struct iio_dev *indio_dev)
tmp = 4;
do {
- msleep(16);
+ msleep(20);
ret = ad9523_read(indio_dev,
AD9523_EEPROM_DATA_XFER_STATUS);
if (ret < 0)
diff --git a/drivers/iio/frequency/adf4350.c b/drivers/iio/frequency/adf4350.c
index 63a25d9e1204..10a0dfc3b01f 100644
--- a/drivers/iio/frequency/adf4350.c
+++ b/drivers/iio/frequency/adf4350.c
@@ -387,10 +387,8 @@ static struct adf4350_platform_data *adf4350_parse_dt(struct device *dev)
int ret;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "could not allocate memory for platform data\n");
+ if (!pdata)
return NULL;
- }
strncpy(&pdata->name[0], np->name, SPI_NAME_SIZE - 1);
@@ -613,9 +611,8 @@ static int adf4350_remove(struct spi_device *spi)
if (st->clk)
clk_disable_unprepare(st->clk);
- if (!IS_ERR(reg)) {
+ if (!IS_ERR(reg))
regulator_disable(reg);
- }
return 0;
}
diff --git a/drivers/iio/gyro/Makefile b/drivers/iio/gyro/Makefile
index 36a38776f739..f46341b39139 100644
--- a/drivers/iio/gyro/Makefile
+++ b/drivers/iio/gyro/Makefile
@@ -16,6 +16,8 @@ itg3200-y := itg3200_core.o
itg3200-$(CONFIG_IIO_BUFFER) += itg3200_buffer.o
obj-$(CONFIG_ITG3200) += itg3200.o
+obj-$(CONFIG_IIO_SSP_SENSORS_COMMONS) += ssp_gyro_sensor.o
+
obj-$(CONFIG_IIO_ST_GYRO_3AXIS) += st_gyro.o
st_gyro-y := st_gyro_core.o
st_gyro-$(CONFIG_IIO_BUFFER) += st_gyro_buffer.o
diff --git a/drivers/iio/gyro/hid-sensor-gyro-3d.c b/drivers/iio/gyro/hid-sensor-gyro-3d.c
index a3ea1e8785d7..a3c3e19de527 100644
--- a/drivers/iio/gyro/hid-sensor-gyro-3d.c
+++ b/drivers/iio/gyro/hid-sensor-gyro-3d.c
@@ -111,19 +111,12 @@ static int gyro_3d_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
switch (mask) {
case 0:
- poll_value = hid_sensor_read_poll_value(
- &gyro_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
-
hid_sensor_power_state(&gyro_state->common_attributes, true);
- msleep_interruptible(poll_value * 2);
report_id = gyro_state->gyro[chan->scan_index].report_id;
address = gyro_3d_addresses[chan->scan_index];
if (report_id >= 0)
@@ -416,6 +409,7 @@ static struct platform_driver hid_gyro_3d_platform_driver = {
.id_table = hid_gyro_3d_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_gyro_3d_probe,
.remove = hid_gyro_3d_remove,
diff --git a/drivers/iio/gyro/ssp_gyro_sensor.c b/drivers/iio/gyro/ssp_gyro_sensor.c
new file mode 100644
index 000000000000..0a8afdd21728
--- /dev/null
+++ b/drivers/iio/gyro/ssp_gyro_sensor.c
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2014, Samsung Electronics Co. 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. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/iio/common/ssp_sensors.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/kfifo_buf.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include "../common/ssp_sensors/ssp_iio_sensor.h"
+
+#define SSP_CHANNEL_COUNT 3
+
+#define SSP_GYROSCOPE_NAME "ssp-gyroscope"
+static const char ssp_gyro_name[] = SSP_GYROSCOPE_NAME;
+
+enum ssp_gyro_3d_channel {
+ SSP_CHANNEL_SCAN_INDEX_X,
+ SSP_CHANNEL_SCAN_INDEX_Y,
+ SSP_CHANNEL_SCAN_INDEX_Z,
+ SSP_CHANNEL_SCAN_INDEX_TIME,
+};
+
+static int ssp_gyro_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ u32 t;
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ t = ssp_get_sensor_delay(data, SSP_GYROSCOPE_SENSOR);
+ ssp_convert_to_freq(t, val, val2);
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int ssp_gyro_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int ret;
+ struct ssp_data *data = dev_get_drvdata(indio_dev->dev.parent->parent);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ ret = ssp_convert_to_time(val, val2);
+ ret = ssp_change_delay(data, SSP_GYROSCOPE_SENSOR, ret);
+ if (ret < 0)
+ dev_err(&indio_dev->dev, "gyro sensor enable fail\n");
+
+ return ret;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static struct iio_info ssp_gyro_iio_info = {
+ .read_raw = &ssp_gyro_read_raw,
+ .write_raw = &ssp_gyro_write_raw,
+};
+
+static const unsigned long ssp_gyro_scan_mask[] = { 0x07, 0, };
+
+static const struct iio_chan_spec ssp_gyro_channels[] = {
+ SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_X, SSP_CHANNEL_SCAN_INDEX_X),
+ SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Y, SSP_CHANNEL_SCAN_INDEX_Y),
+ SSP_CHANNEL_AG(IIO_ANGL_VEL, IIO_MOD_Z, SSP_CHANNEL_SCAN_INDEX_Z),
+ SSP_CHAN_TIMESTAMP(SSP_CHANNEL_SCAN_INDEX_TIME),
+};
+
+static int ssp_process_gyro_data(struct iio_dev *indio_dev, void *buf,
+ int64_t timestamp)
+{
+ return ssp_common_process_data(indio_dev, buf, SSP_GYROSCOPE_SIZE,
+ timestamp);
+}
+
+static const struct iio_buffer_setup_ops ssp_gyro_buffer_ops = {
+ .postenable = &ssp_common_buffer_postenable,
+ .postdisable = &ssp_common_buffer_postdisable,
+};
+
+static int ssp_gyro_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct ssp_sensor_data *spd;
+ struct iio_buffer *buffer;
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*spd));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ spd = iio_priv(indio_dev);
+
+ spd->process_data = ssp_process_gyro_data;
+ spd->type = SSP_GYROSCOPE_SENSOR;
+
+ indio_dev->name = ssp_gyro_name;
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->info = &ssp_gyro_iio_info;
+ indio_dev->modes = INDIO_BUFFER_SOFTWARE;
+ indio_dev->channels = ssp_gyro_channels;
+ indio_dev->num_channels = ARRAY_SIZE(ssp_gyro_channels);
+ indio_dev->available_scan_masks = ssp_gyro_scan_mask;
+
+ buffer = devm_iio_kfifo_allocate(&pdev->dev);
+ if (!buffer)
+ return -ENOMEM;
+
+ iio_device_attach_buffer(indio_dev, buffer);
+
+ indio_dev->setup_ops = &ssp_gyro_buffer_ops;
+
+ platform_set_drvdata(pdev, indio_dev);
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ return ret;
+
+ /* ssp registering should be done after all iio setup */
+ ssp_register_consumer(indio_dev, SSP_GYROSCOPE_SENSOR);
+
+ return 0;
+}
+
+static int ssp_gyro_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ iio_device_unregister(indio_dev);
+
+ return 0;
+}
+
+static struct platform_driver ssp_gyro_driver = {
+ .driver = {
+ .name = SSP_GYROSCOPE_NAME,
+ },
+ .probe = ssp_gyro_probe,
+ .remove = ssp_gyro_remove,
+};
+
+module_platform_driver(ssp_gyro_driver);
+
+MODULE_AUTHOR("Karol Wrona <k.wrona@samsung.com>");
+MODULE_DESCRIPTION("Samsung sensorhub gyroscopes driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/iio_core.h b/drivers/iio/iio_core.h
index 5f0ea77fe717..359883525ab7 100644
--- a/drivers/iio/iio_core.h
+++ b/drivers/iio/iio_core.h
@@ -48,6 +48,8 @@ unsigned int iio_buffer_poll(struct file *filp,
ssize_t iio_buffer_read_first_n_outer(struct file *filp, char __user *buf,
size_t n, loff_t *f_ps);
+int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev);
+void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev);
#define iio_buffer_poll_addr (&iio_buffer_poll)
#define iio_buffer_read_first_n_outer_addr (&iio_buffer_read_first_n_outer)
@@ -60,6 +62,13 @@ void iio_buffer_wakeup_poll(struct iio_dev *indio_dev);
#define iio_buffer_poll_addr NULL
#define iio_buffer_read_first_n_outer_addr NULL
+static inline int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
+{
+ return 0;
+}
+
+static inline void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev) {}
+
static inline void iio_disable_all_buffers(struct iio_dev *indio_dev) {}
static inline void iio_buffer_wakeup_poll(struct iio_dev *indio_dev) {}
diff --git a/drivers/iio/imu/Kconfig b/drivers/iio/imu/Kconfig
index 2b0e45133e9d..5e610f7de5aa 100644
--- a/drivers/iio/imu/Kconfig
+++ b/drivers/iio/imu/Kconfig
@@ -25,6 +25,17 @@ config ADIS16480
Say yes here to build support for Analog Devices ADIS16375, ADIS16480,
ADIS16485, ADIS16488 inertial sensors.
+config KMX61
+ tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
+ depends on I2C
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ help
+ Say Y here if you want to build a driver for Kionix KMX61 6-axis
+ accelerometer and magnetometer.
+ To compile this driver as module, choose M here: the module will
+ be called kmx61.
+
source "drivers/iio/imu/inv_mpu6050/Kconfig"
endmenu
diff --git a/drivers/iio/imu/Makefile b/drivers/iio/imu/Makefile
index 114d2c17cbe2..e1e6e3d70e26 100644
--- a/drivers/iio/imu/Makefile
+++ b/drivers/iio/imu/Makefile
@@ -14,3 +14,5 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) += adis_buffer.o
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
obj-y += inv_mpu6050/
+
+obj-$(CONFIG_KMX61) += kmx61.o
diff --git a/drivers/iio/imu/inv_mpu6050/Kconfig b/drivers/iio/imu/inv_mpu6050/Kconfig
index 2d0608ba88d7..48fbc0bc7e2a 100644
--- a/drivers/iio/imu/inv_mpu6050/Kconfig
+++ b/drivers/iio/imu/inv_mpu6050/Kconfig
@@ -7,6 +7,7 @@ config INV_MPU6050_IIO
depends on I2C && SYSFS
select IIO_BUFFER
select IIO_TRIGGERED_BUFFER
+ select I2C_MUX
help
This driver supports the Invensense MPU6050 devices.
This driver can also support MPU6500 in MPU6050 compatibility mode
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
index b75519deac1a..f73e60b7a796 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_core.c
@@ -23,6 +23,8 @@
#include <linux/kfifo.h>
#include <linux/spinlock.h>
#include <linux/iio/iio.h>
+#include <linux/i2c-mux.h>
+#include <linux/acpi.h>
#include "inv_mpu_iio.h"
/*
@@ -52,6 +54,7 @@ static const struct inv_mpu6050_reg_map reg_set_6050 = {
.int_enable = INV_MPU6050_REG_INT_ENABLE,
.pwr_mgmt_1 = INV_MPU6050_REG_PWR_MGMT_1,
.pwr_mgmt_2 = INV_MPU6050_REG_PWR_MGMT_2,
+ .int_pin_cfg = INV_MPU6050_REG_INT_PIN_CFG,
};
static const struct inv_mpu6050_chip_config chip_config_6050 = {
@@ -77,6 +80,83 @@ int inv_mpu6050_write_reg(struct inv_mpu6050_state *st, int reg, u8 d)
return i2c_smbus_write_i2c_block_data(st->client, reg, 1, &d);
}
+/*
+ * The i2c read/write needs to happen in unlocked mode. As the parent
+ * adapter is common. If we use locked versions, it will fail as
+ * the mux adapter will lock the parent i2c adapter, while calling
+ * select/deselect functions.
+ */
+static int inv_mpu6050_write_reg_unlocked(struct inv_mpu6050_state *st,
+ u8 reg, u8 d)
+{
+ int ret;
+ u8 buf[2];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = st->client->addr,
+ .flags = 0,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ buf[0] = reg;
+ buf[1] = d;
+ ret = __i2c_transfer(st->client->adapter, msg, 1);
+ if (ret != 1)
+ return ret;
+
+ return 0;
+}
+
+static int inv_mpu6050_select_bypass(struct i2c_adapter *adap, void *mux_priv,
+ u32 chan_id)
+{
+ struct iio_dev *indio_dev = mux_priv;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ int ret = 0;
+
+ /* Use the same mutex which was used everywhere to protect power-op */
+ mutex_lock(&indio_dev->mlock);
+ if (!st->powerup_count) {
+ ret = inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1,
+ 0);
+ if (ret)
+ goto write_error;
+
+ msleep(INV_MPU6050_REG_UP_TIME);
+ }
+ if (!ret) {
+ st->powerup_count++;
+ ret = inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg,
+ st->client->irq |
+ INV_MPU6050_BIT_BYPASS_EN);
+ }
+write_error:
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static int inv_mpu6050_deselect_bypass(struct i2c_adapter *adap,
+ void *mux_priv, u32 chan_id)
+{
+ struct iio_dev *indio_dev = mux_priv;
+ struct inv_mpu6050_state *st = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ /* It doesn't really mattter, if any of the calls fails */
+ inv_mpu6050_write_reg_unlocked(st, st->reg->int_pin_cfg,
+ st->client->irq);
+ st->powerup_count--;
+ if (!st->powerup_count)
+ inv_mpu6050_write_reg_unlocked(st, st->reg->pwr_mgmt_1,
+ INV_MPU6050_BIT_SLEEP);
+ mutex_unlock(&indio_dev->mlock);
+
+ return 0;
+}
+
int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
{
u8 d, mgmt_1;
@@ -133,13 +213,22 @@ int inv_mpu6050_switch_engine(struct inv_mpu6050_state *st, bool en, u32 mask)
int inv_mpu6050_set_power_itg(struct inv_mpu6050_state *st, bool power_on)
{
- int result;
+ int result = 0;
+
+ if (power_on) {
+ /* Already under indio-dev->mlock mutex */
+ if (!st->powerup_count)
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
+ 0);
+ if (!result)
+ st->powerup_count++;
+ } else {
+ st->powerup_count--;
+ if (!st->powerup_count)
+ result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
+ INV_MPU6050_BIT_SLEEP);
+ }
- if (power_on)
- result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1, 0);
- else
- result = inv_mpu6050_write_reg(st, st->reg->pwr_mgmt_1,
- INV_MPU6050_BIT_SLEEP);
if (result)
return result;
@@ -673,6 +762,7 @@ static int inv_mpu_probe(struct i2c_client *client,
st = iio_priv(indio_dev);
st->client = client;
+ st->powerup_count = 0;
pdata = dev_get_platdata(&client->dev);
if (pdata)
st->plat_data = *pdata;
@@ -720,8 +810,21 @@ static int inv_mpu_probe(struct i2c_client *client,
goto out_remove_trigger;
}
+ st->mux_adapter = i2c_add_mux_adapter(client->adapter,
+ &client->dev,
+ indio_dev,
+ 0, 0, 0,
+ inv_mpu6050_select_bypass,
+ inv_mpu6050_deselect_bypass);
+ if (!st->mux_adapter) {
+ result = -ENODEV;
+ goto out_unreg_device;
+ }
+
return 0;
+out_unreg_device:
+ iio_device_unregister(indio_dev);
out_remove_trigger:
inv_mpu6050_remove_trigger(st);
out_unreg_ring:
@@ -734,6 +837,7 @@ static int inv_mpu_remove(struct i2c_client *client)
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct inv_mpu6050_state *st = iio_priv(indio_dev);
+ i2c_del_mux_adapter(st->mux_adapter);
iio_device_unregister(indio_dev);
inv_mpu6050_remove_trigger(st);
iio_triggered_buffer_cleanup(indio_dev);
@@ -772,6 +876,13 @@ static const struct i2c_device_id inv_mpu_id[] = {
MODULE_DEVICE_TABLE(i2c, inv_mpu_id);
+static const struct acpi_device_id inv_acpi_match[] = {
+ {"INVN6500", 0},
+ { },
+};
+
+MODULE_DEVICE_TABLE(acpi, inv_acpi_match);
+
static struct i2c_driver inv_mpu_driver = {
.probe = inv_mpu_probe,
.remove = inv_mpu_remove,
@@ -780,6 +891,7 @@ static struct i2c_driver inv_mpu_driver = {
.owner = THIS_MODULE,
.name = "inv-mpu6050",
.pm = INV_MPU6050_PMOPS,
+ .acpi_match_table = ACPI_PTR(inv_acpi_match),
},
};
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
index e7799315d4dc..aa837de57079 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_iio.h
@@ -54,6 +54,7 @@ struct inv_mpu6050_reg_map {
u8 int_enable;
u8 pwr_mgmt_1;
u8 pwr_mgmt_2;
+ u8 int_pin_cfg;
};
/*device enum */
@@ -119,6 +120,8 @@ struct inv_mpu6050_state {
enum inv_devices chip_type;
spinlock_t time_stamp_lock;
struct i2c_client *client;
+ struct i2c_adapter *mux_adapter;
+ unsigned int powerup_count;
struct inv_mpu6050_platform_data plat_data;
DECLARE_KFIFO(timestamps, long long, TIMESTAMP_FIFO_SIZE);
};
@@ -179,6 +182,9 @@ struct inv_mpu6050_state {
/* 6 + 6 round up and plus 8 */
#define INV_MPU6050_OUTPUT_DATA_SIZE 24
+#define INV_MPU6050_REG_INT_PIN_CFG 0x37
+#define INV_MPU6050_BIT_BYPASS_EN 0x2
+
/* init parameters */
#define INV_MPU6050_INIT_FIFO_RATE 50
#define INV_MPU6050_TIME_STAMP_TOR 5
diff --git a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
index 926fccea8de0..844610c3a3a9 100644
--- a/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
+++ b/drivers/iio/imu/inv_mpu6050/inv_mpu_trigger.c
@@ -116,40 +116,35 @@ int inv_mpu6050_probe_trigger(struct iio_dev *indio_dev)
int ret;
struct inv_mpu6050_state *st = iio_priv(indio_dev);
- st->trig = iio_trigger_alloc("%s-dev%d",
- indio_dev->name,
- indio_dev->id);
- if (st->trig == NULL) {
- ret = -ENOMEM;
- goto error_ret;
- }
- ret = request_irq(st->client->irq, &iio_trigger_generic_data_rdy_poll,
- IRQF_TRIGGER_RISING,
- "inv_mpu",
- st->trig);
+ st->trig = devm_iio_trigger_alloc(&indio_dev->dev,
+ "%s-dev%d",
+ indio_dev->name,
+ indio_dev->id);
+ if (!st->trig)
+ return -ENOMEM;
+
+ ret = devm_request_irq(&indio_dev->dev, st->client->irq,
+ &iio_trigger_generic_data_rdy_poll,
+ IRQF_TRIGGER_RISING,
+ "inv_mpu",
+ st->trig);
if (ret)
- goto error_free_trig;
+ return ret;
+
st->trig->dev.parent = &st->client->dev;
st->trig->ops = &inv_mpu_trigger_ops;
iio_trigger_set_drvdata(st->trig, indio_dev);
+
ret = iio_trigger_register(st->trig);
if (ret)
- goto error_free_irq;
+ return ret;
+
indio_dev->trig = iio_trigger_get(st->trig);
return 0;
-
-error_free_irq:
- free_irq(st->client->irq, st->trig);
-error_free_trig:
- iio_trigger_free(st->trig);
-error_ret:
- return ret;
}
void inv_mpu6050_remove_trigger(struct inv_mpu6050_state *st)
{
iio_trigger_unregister(st->trig);
- free_irq(st->client->irq, st->trig);
- iio_trigger_free(st->trig);
}
diff --git a/drivers/iio/imu/kmx61.c b/drivers/iio/imu/kmx61.c
new file mode 100644
index 000000000000..5cc3692acf37
--- /dev/null
+++ b/drivers/iio/imu/kmx61.c
@@ -0,0 +1,1595 @@
+/*
+ * KMX61 - Kionix 6-axis Accelerometer/Magnetometer
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This file is subject to the terms and conditions of version 2 of
+ * the GNU General Public License. See the file COPYING in the main
+ * directory of this archive for more details.
+ *
+ * IIO driver for KMX61 (7-bit I2C slave address 0x0E or 0x0F).
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define KMX61_DRV_NAME "kmx61"
+#define KMX61_GPIO_NAME "kmx61_int"
+#define KMX61_IRQ_NAME "kmx61_event"
+
+#define KMX61_REG_WHO_AM_I 0x00
+#define KMX61_REG_INS1 0x01
+#define KMX61_REG_INS2 0x02
+
+/*
+ * three 16-bit accelerometer output registers for X/Y/Z axis
+ * we use only XOUT_L as a base register, all other addresses
+ * can be obtained by applying an offset and are provided here
+ * only for clarity.
+ */
+#define KMX61_ACC_XOUT_L 0x0A
+#define KMX61_ACC_XOUT_H 0x0B
+#define KMX61_ACC_YOUT_L 0x0C
+#define KMX61_ACC_YOUT_H 0x0D
+#define KMX61_ACC_ZOUT_L 0x0E
+#define KMX61_ACC_ZOUT_H 0x0F
+
+/*
+ * one 16-bit temperature output register
+ */
+#define KMX61_TEMP_L 0x10
+#define KMX61_TEMP_H 0x11
+
+/*
+ * three 16-bit magnetometer output registers for X/Y/Z axis
+ */
+#define KMX61_MAG_XOUT_L 0x12
+#define KMX61_MAG_XOUT_H 0x13
+#define KMX61_MAG_YOUT_L 0x14
+#define KMX61_MAG_YOUT_H 0x15
+#define KMX61_MAG_ZOUT_L 0x16
+#define KMX61_MAG_ZOUT_H 0x17
+
+#define KMX61_REG_INL 0x28
+#define KMX61_REG_STBY 0x29
+#define KMX61_REG_CTRL1 0x2A
+#define KMX61_REG_CTRL2 0x2B
+#define KMX61_REG_ODCNTL 0x2C
+#define KMX61_REG_INC1 0x2D
+
+#define KMX61_REG_WUF_THRESH 0x3D
+#define KMX61_REG_WUF_TIMER 0x3E
+
+#define KMX61_ACC_STBY_BIT BIT(0)
+#define KMX61_MAG_STBY_BIT BIT(1)
+#define KMX61_ACT_STBY_BIT BIT(7)
+
+#define KMX61_ALL_STBY (KMX61_ACC_STBY_BIT | KMX61_MAG_STBY_BIT)
+
+#define KMX61_REG_INS1_BIT_WUFS BIT(1)
+
+#define KMX61_REG_INS2_BIT_ZP BIT(0)
+#define KMX61_REG_INS2_BIT_ZN BIT(1)
+#define KMX61_REG_INS2_BIT_YP BIT(2)
+#define KMX61_REG_INS2_BIT_YN BIT(3)
+#define KMX61_REG_INS2_BIT_XP BIT(4)
+#define KMX61_REG_INS2_BIT_XN BIT(5)
+
+#define KMX61_REG_CTRL1_GSEL_MASK 0x03
+
+#define KMX61_REG_CTRL1_BIT_RES BIT(4)
+#define KMX61_REG_CTRL1_BIT_DRDYE BIT(5)
+#define KMX61_REG_CTRL1_BIT_WUFE BIT(6)
+#define KMX61_REG_CTRL1_BIT_BTSE BIT(7)
+
+#define KMX61_REG_INC1_BIT_WUFS BIT(0)
+#define KMX61_REG_INC1_BIT_DRDYM BIT(1)
+#define KMX61_REG_INC1_BIT_DRDYA BIT(2)
+#define KMX61_REG_INC1_BIT_IEN BIT(5)
+
+#define KMX61_ACC_ODR_SHIFT 0
+#define KMX61_MAG_ODR_SHIFT 4
+#define KMX61_ACC_ODR_MASK 0x0F
+#define KMX61_MAG_ODR_MASK 0xF0
+
+#define KMX61_OWUF_MASK 0x7
+
+#define KMX61_DEFAULT_WAKE_THRESH 1
+#define KMX61_DEFAULT_WAKE_DURATION 1
+
+#define KMX61_SLEEP_DELAY_MS 2000
+
+#define KMX61_CHIP_ID 0x12
+
+/* KMX61 devices */
+#define KMX61_ACC 0x01
+#define KMX61_MAG 0x02
+
+struct kmx61_data {
+ struct i2c_client *client;
+
+ /* serialize access to non-atomic ops, e.g set_mode */
+ struct mutex lock;
+
+ /* standby state */
+ bool acc_stby;
+ bool mag_stby;
+
+ /* power state */
+ bool acc_ps;
+ bool mag_ps;
+
+ /* config bits */
+ u8 range;
+ u8 odr_bits;
+ u8 wake_thresh;
+ u8 wake_duration;
+
+ /* accelerometer specific data */
+ struct iio_dev *acc_indio_dev;
+ struct iio_trigger *acc_dready_trig;
+ struct iio_trigger *motion_trig;
+ bool acc_dready_trig_on;
+ bool motion_trig_on;
+ bool ev_enable_state;
+
+ /* magnetometer specific data */
+ struct iio_dev *mag_indio_dev;
+ struct iio_trigger *mag_dready_trig;
+ bool mag_dready_trig_on;
+};
+
+enum kmx61_range {
+ KMX61_RANGE_2G,
+ KMX61_RANGE_4G,
+ KMX61_RANGE_8G,
+};
+
+enum kmx61_axis {
+ KMX61_AXIS_X,
+ KMX61_AXIS_Y,
+ KMX61_AXIS_Z,
+};
+
+static const u16 kmx61_uscale_table[] = {9582, 19163, 38326};
+
+static const struct {
+ int val;
+ int val2;
+ u8 odr_bits;
+} kmx61_samp_freq_table[] = { {12, 500000, 0x00},
+ {25, 0, 0x01},
+ {50, 0, 0x02},
+ {100, 0, 0x03},
+ {200, 0, 0x04},
+ {400, 0, 0x05},
+ {800, 0, 0x06},
+ {1600, 0, 0x07},
+ {0, 781000, 0x08},
+ {1, 563000, 0x09},
+ {3, 125000, 0x0A},
+ {6, 250000, 0x0B} };
+
+static const struct {
+ int val;
+ int val2;
+ int odr_bits;
+} kmx61_wake_up_odr_table[] = { {0, 781000, 0x00},
+ {1, 563000, 0x01},
+ {3, 125000, 0x02},
+ {6, 250000, 0x03},
+ {12, 500000, 0x04},
+ {25, 0, 0x05},
+ {50, 0, 0x06},
+ {100, 0, 0x06},
+ {200, 0, 0x06},
+ {400, 0, 0x06},
+ {800, 0, 0x06},
+ {1600, 0, 0x06} };
+
+static IIO_CONST_ATTR(accel_scale_available, "0.009582 0.019163 0.038326");
+static IIO_CONST_ATTR(magn_scale_available, "0.001465");
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+ "0.781000 1.563000 3.125000 6.250000 12.500000 25 50 100 200 400 800");
+
+static struct attribute *kmx61_acc_attributes[] = {
+ &iio_const_attr_accel_scale_available.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static struct attribute *kmx61_mag_attributes[] = {
+ &iio_const_attr_magn_scale_available.dev_attr.attr,
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group kmx61_acc_attribute_group = {
+ .attrs = kmx61_acc_attributes,
+};
+
+static const struct attribute_group kmx61_mag_attribute_group = {
+ .attrs = kmx61_mag_attributes,
+};
+
+static const struct iio_event_spec kmx61_event = {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) |
+ BIT(IIO_EV_INFO_ENABLE) |
+ BIT(IIO_EV_INFO_PERIOD),
+};
+
+#define KMX61_ACC_CHAN(_axis) { \
+ .type = IIO_ACCEL, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _axis, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .address = KMX61_ACC, \
+ .scan_index = KMX61_AXIS_ ## _axis, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 12, \
+ .storagebits = 16, \
+ .shift = 4, \
+ .endianness = IIO_LE, \
+ }, \
+ .event_spec = &kmx61_event, \
+ .num_event_specs = 1 \
+}
+
+#define KMX61_MAG_CHAN(_axis) { \
+ .type = IIO_MAGN, \
+ .modified = 1, \
+ .channel2 = IIO_MOD_ ## _axis, \
+ .address = KMX61_MAG, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .scan_index = KMX61_AXIS_ ## _axis, \
+ .scan_type = { \
+ .sign = 's', \
+ .realbits = 14, \
+ .storagebits = 16, \
+ .shift = 2, \
+ .endianness = IIO_LE, \
+ }, \
+}
+
+static const struct iio_chan_spec kmx61_acc_channels[] = {
+ KMX61_ACC_CHAN(X),
+ KMX61_ACC_CHAN(Y),
+ KMX61_ACC_CHAN(Z),
+};
+
+static const struct iio_chan_spec kmx61_mag_channels[] = {
+ KMX61_MAG_CHAN(X),
+ KMX61_MAG_CHAN(Y),
+ KMX61_MAG_CHAN(Z),
+};
+
+static void kmx61_set_data(struct iio_dev *indio_dev, struct kmx61_data *data)
+{
+ struct kmx61_data **priv = iio_priv(indio_dev);
+
+ *priv = data;
+}
+
+static struct kmx61_data *kmx61_get_data(struct iio_dev *indio_dev)
+{
+ return *(struct kmx61_data **)iio_priv(indio_dev);
+}
+
+static int kmx61_convert_freq_to_bit(int val, int val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
+ if (val == kmx61_samp_freq_table[i].val &&
+ val2 == kmx61_samp_freq_table[i].val2)
+ return kmx61_samp_freq_table[i].odr_bits;
+ return -EINVAL;
+}
+
+static int kmx61_convert_bit_to_freq(u8 odr_bits, int *val, int *val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
+ if (odr_bits == kmx61_samp_freq_table[i].odr_bits) {
+ *val = kmx61_samp_freq_table[i].val;
+ *val2 = kmx61_samp_freq_table[i].val2;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static int kmx61_convert_wake_up_odr_to_bit(int val, int val2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(kmx61_wake_up_odr_table); ++i)
+ if (kmx61_wake_up_odr_table[i].val == val &&
+ kmx61_wake_up_odr_table[i].val2 == val2)
+ return kmx61_wake_up_odr_table[i].odr_bits;
+ return -EINVAL;
+}
+
+/**
+ * kmx61_set_mode() - set KMX61 device operating mode
+ * @data - kmx61 device private data pointer
+ * @mode - bitmask, indicating operating mode for @device
+ * @device - bitmask, indicating device for which @mode needs to be set
+ * @update - update stby bits stored in device's private @data
+ *
+ * For each sensor (accelerometer/magnetometer) there are two operating modes
+ * STANDBY and OPERATION. Neither accel nor magn can be disabled independently
+ * if they are both enabled. Internal sensors state is saved in acc_stby and
+ * mag_stby members of driver's private @data.
+ */
+static int kmx61_set_mode(struct kmx61_data *data, u8 mode, u8 device,
+ bool update)
+{
+ int ret;
+ int acc_stby = -1, mag_stby = -1;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_stby\n");
+ return ret;
+ }
+ if (device & KMX61_ACC) {
+ if (mode & KMX61_ACC_STBY_BIT) {
+ ret |= KMX61_ACC_STBY_BIT;
+ acc_stby = 1;
+ } else {
+ ret &= ~KMX61_ACC_STBY_BIT;
+ acc_stby = 0;
+ }
+ }
+
+ if (device & KMX61_MAG) {
+ if (mode & KMX61_MAG_STBY_BIT) {
+ ret |= KMX61_MAG_STBY_BIT;
+ mag_stby = 1;
+ } else {
+ ret &= ~KMX61_MAG_STBY_BIT;
+ mag_stby = 0;
+ }
+ }
+
+ if (mode & KMX61_ACT_STBY_BIT)
+ ret |= KMX61_ACT_STBY_BIT;
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_STBY, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_stby\n");
+ return ret;
+ }
+
+ if (acc_stby != -1 && update)
+ data->acc_stby = acc_stby;
+ if (mag_stby != -1 && update)
+ data->mag_stby = mag_stby;
+
+ return 0;
+}
+
+static int kmx61_get_mode(struct kmx61_data *data, u8 *mode, u8 device)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_STBY);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_stby\n");
+ return ret;
+ }
+ *mode = 0;
+
+ if (device & KMX61_ACC) {
+ if (ret & KMX61_ACC_STBY_BIT)
+ *mode |= KMX61_ACC_STBY_BIT;
+ else
+ *mode &= ~KMX61_ACC_STBY_BIT;
+ }
+
+ if (device & KMX61_MAG) {
+ if (ret & KMX61_MAG_STBY_BIT)
+ *mode |= KMX61_MAG_STBY_BIT;
+ else
+ *mode &= ~KMX61_MAG_STBY_BIT;
+ }
+
+ return 0;
+}
+
+static int kmx61_set_wake_up_odr(struct kmx61_data *data, int val, int val2)
+{
+ int ret, odr_bits;
+
+ odr_bits = kmx61_convert_wake_up_odr_to_bit(val, val2);
+ if (odr_bits < 0)
+ return odr_bits;
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL2,
+ odr_bits);
+ if (ret < 0)
+ dev_err(&data->client->dev, "Error writing reg_ctrl2\n");
+ return ret;
+}
+
+static int kmx61_set_odr(struct kmx61_data *data, int val, int val2, u8 device)
+{
+ int ret;
+ u8 mode;
+ int lodr_bits, odr_bits;
+
+ ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
+ if (ret < 0)
+ return ret;
+
+ lodr_bits = kmx61_convert_freq_to_bit(val, val2);
+ if (lodr_bits < 0)
+ return lodr_bits;
+
+ /* To change ODR, accel and magn must be in STDBY */
+ ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
+ true);
+ if (ret < 0)
+ return ret;
+
+ odr_bits = 0;
+ if (device & KMX61_ACC)
+ odr_bits |= lodr_bits << KMX61_ACC_ODR_SHIFT;
+ if (device & KMX61_MAG)
+ odr_bits |= lodr_bits << KMX61_MAG_ODR_SHIFT;
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_ODCNTL,
+ odr_bits);
+ if (ret < 0)
+ return ret;
+
+ data->odr_bits = odr_bits;
+
+ if (device & KMX61_ACC) {
+ ret = kmx61_set_wake_up_odr(data, val, val2);
+ if (ret)
+ return ret;
+ }
+
+ return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
+}
+
+static int kmx61_get_odr(struct kmx61_data *data, int *val, int *val2,
+ u8 device)
+{ int i;
+ u8 lodr_bits;
+
+ if (device & KMX61_ACC)
+ lodr_bits = (data->odr_bits >> KMX61_ACC_ODR_SHIFT) &
+ KMX61_ACC_ODR_MASK;
+ else if (device & KMX61_MAG)
+ lodr_bits = (data->odr_bits >> KMX61_MAG_ODR_SHIFT) &
+ KMX61_MAG_ODR_MASK;
+ else
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(kmx61_samp_freq_table); i++)
+ if (lodr_bits == kmx61_samp_freq_table[i].odr_bits) {
+ *val = kmx61_samp_freq_table[i].val;
+ *val2 = kmx61_samp_freq_table[i].val2;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int kmx61_set_range(struct kmx61_data *data, u8 range)
+{
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+ return ret;
+ }
+
+ ret &= ~KMX61_REG_CTRL1_GSEL_MASK;
+ ret |= range & KMX61_REG_CTRL1_GSEL_MASK;
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+ return ret;
+ }
+
+ data->range = range;
+
+ return 0;
+}
+
+static int kmx61_set_scale(struct kmx61_data *data, u16 uscale)
+{
+ int ret, i;
+ u8 mode;
+
+ for (i = 0; i < ARRAY_SIZE(kmx61_uscale_table); i++) {
+ if (kmx61_uscale_table[i] == uscale) {
+ ret = kmx61_get_mode(data, &mode,
+ KMX61_ACC | KMX61_MAG);
+ if (ret < 0)
+ return ret;
+
+ ret = kmx61_set_mode(data, KMX61_ALL_STBY,
+ KMX61_ACC | KMX61_MAG, true);
+ if (ret < 0)
+ return ret;
+
+ ret = kmx61_set_range(data, i);
+ if (ret < 0)
+ return ret;
+
+ return kmx61_set_mode(data, mode,
+ KMX61_ACC | KMX61_MAG, true);
+ }
+ }
+ return -EINVAL;
+}
+
+static int kmx61_chip_init(struct kmx61_data *data)
+{
+ int ret, val, val2;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_WHO_AM_I);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading who_am_i\n");
+ return ret;
+ }
+
+ if (ret != KMX61_CHIP_ID) {
+ dev_err(&data->client->dev,
+ "Wrong chip id, got %x expected %x\n",
+ ret, KMX61_CHIP_ID);
+ return -EINVAL;
+ }
+
+ /* set accel 12bit, 4g range */
+ ret = kmx61_set_range(data, KMX61_RANGE_4G);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_ODCNTL);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_odcntl\n");
+ return ret;
+ }
+ data->odr_bits = ret;
+
+ /* set output data rate for wake up (motion detection) function */
+ ret = kmx61_convert_bit_to_freq(data->odr_bits, &val, &val2);
+ if (ret < 0)
+ return ret;
+
+ ret = kmx61_set_wake_up_odr(data, val, val2);
+ if (ret < 0)
+ return ret;
+
+ /* set acc/magn to OPERATION mode */
+ ret = kmx61_set_mode(data, 0, KMX61_ACC | KMX61_MAG, true);
+ if (ret < 0)
+ return ret;
+
+ data->wake_thresh = KMX61_DEFAULT_WAKE_THRESH;
+ data->wake_duration = KMX61_DEFAULT_WAKE_DURATION;
+
+ return 0;
+}
+
+static int kmx61_setup_new_data_interrupt(struct kmx61_data *data,
+ bool status, u8 device)
+{
+ u8 mode;
+ int ret;
+
+ ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
+ if (ret < 0)
+ return ret;
+
+ ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INC1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+ return ret;
+ }
+
+ if (status) {
+ ret |= KMX61_REG_INC1_BIT_IEN;
+ if (device & KMX61_ACC)
+ ret |= KMX61_REG_INC1_BIT_DRDYA;
+ if (device & KMX61_MAG)
+ ret |= KMX61_REG_INC1_BIT_DRDYM;
+ } else {
+ ret &= ~KMX61_REG_INC1_BIT_IEN;
+ if (device & KMX61_ACC)
+ ret &= ~KMX61_REG_INC1_BIT_DRDYA;
+ if (device & KMX61_MAG)
+ ret &= ~KMX61_REG_INC1_BIT_DRDYM;
+ }
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_INC1, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_int_ctrl1\n");
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+ return ret;
+ }
+
+ if (status)
+ ret |= KMX61_REG_CTRL1_BIT_DRDYE;
+ else
+ ret &= ~KMX61_REG_CTRL1_BIT_DRDYE;
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+ return ret;
+ }
+
+ return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
+}
+
+static int kmx61_chip_update_thresholds(struct kmx61_data *data)
+{
+ int ret;
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ KMX61_REG_WUF_TIMER,
+ data->wake_duration);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Errow writing reg_wuf_timer\n");
+ return ret;
+ }
+
+ ret = i2c_smbus_write_byte_data(data->client,
+ KMX61_REG_WUF_THRESH,
+ data->wake_thresh);
+ if (ret < 0)
+ dev_err(&data->client->dev, "Error writing reg_wuf_thresh\n");
+
+ return ret;
+}
+
+static int kmx61_setup_any_motion_interrupt(struct kmx61_data *data,
+ bool status)
+{
+ u8 mode;
+ int ret;
+
+ ret = kmx61_get_mode(data, &mode, KMX61_ACC | KMX61_MAG);
+ if (ret < 0)
+ return ret;
+
+ ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+ if (ret < 0)
+ return ret;
+
+ ret = kmx61_chip_update_thresholds(data);
+ if (ret < 0)
+ return ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INC1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_inc1\n");
+ return ret;
+ }
+ if (status)
+ ret |= (KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS);
+ else
+ ret &= ~(KMX61_REG_INC1_BIT_IEN | KMX61_REG_INC1_BIT_WUFS);
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_INC1, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_inc1\n");
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+ return ret;
+ }
+
+ if (status)
+ ret |= KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE;
+ else
+ ret &= ~(KMX61_REG_CTRL1_BIT_WUFE | KMX61_REG_CTRL1_BIT_BTSE);
+
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+ return ret;
+ }
+ mode |= KMX61_ACT_STBY_BIT;
+ return kmx61_set_mode(data, mode, KMX61_ACC | KMX61_MAG, true);
+}
+
+/**
+ * kmx61_set_power_state() - set power state for kmx61 @device
+ * @data - kmx61 device private pointer
+ * @on - power state to be set for @device
+ * @device - bitmask indicating device for which @on state needs to be set
+ *
+ * Notice that when ACC power state needs to be set to ON and MAG is in
+ * OPERATION then we know that kmx61_runtime_resume was already called
+ * so we must set ACC OPERATION mode here. The same happens when MAG power
+ * state needs to be set to ON and ACC is in OPERATION.
+ */
+static int kmx61_set_power_state(struct kmx61_data *data, bool on, u8 device)
+{
+#ifdef CONFIG_PM
+ int ret;
+
+ if (device & KMX61_ACC) {
+ if (on && !data->acc_ps && !data->mag_stby) {
+ ret = kmx61_set_mode(data, 0, KMX61_ACC, true);
+ if (ret < 0)
+ return ret;
+ }
+ data->acc_ps = on;
+ }
+ if (device & KMX61_MAG) {
+ if (on && !data->mag_ps && !data->acc_stby) {
+ ret = kmx61_set_mode(data, 0, KMX61_MAG, true);
+ if (ret < 0)
+ return ret;
+ }
+ data->mag_ps = on;
+ }
+
+ if (on) {
+ ret = pm_runtime_get_sync(&data->client->dev);
+ } else {
+ pm_runtime_mark_last_busy(&data->client->dev);
+ ret = pm_runtime_put_autosuspend(&data->client->dev);
+ }
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed: kmx61_set_power_state for %d, ret %d\n",
+ on, ret);
+ if (on)
+ pm_runtime_put_noidle(&data->client->dev);
+
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+static int kmx61_read_measurement(struct kmx61_data *data, u8 base, u8 offset)
+{
+ int ret;
+ u8 reg = base + offset * 2;
+
+ ret = i2c_smbus_read_word_data(data->client, reg);
+ if (ret < 0)
+ dev_err(&data->client->dev, "failed to read reg at %x\n", reg);
+
+ return ret;
+}
+
+static int kmx61_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int *val,
+ int *val2, long mask)
+{
+ int ret;
+ u8 base_reg;
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ base_reg = KMX61_ACC_XOUT_L;
+ break;
+ case IIO_MAGN:
+ base_reg = KMX61_MAG_XOUT_L;
+ break;
+ default:
+ return -EINVAL;
+ }
+ mutex_lock(&data->lock);
+
+ ret = kmx61_set_power_state(data, true, chan->address);
+ if (ret) {
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+
+ ret = kmx61_read_measurement(data, base_reg, chan->scan_index);
+ if (ret < 0) {
+ kmx61_set_power_state(data, false, chan->address);
+ mutex_unlock(&data->lock);
+ return ret;
+ }
+ *val = sign_extend32(ret >> chan->scan_type.shift,
+ chan->scan_type.realbits - 1);
+ ret = kmx61_set_power_state(data, false, chan->address);
+
+ mutex_unlock(&data->lock);
+ if (ret)
+ return ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ *val = 0;
+ *val2 = kmx61_uscale_table[data->range];
+ return IIO_VAL_INT_PLUS_MICRO;
+ case IIO_MAGN:
+ /* 14 bits res, 1465 microGauss per magn count */
+ *val = 0;
+ *val2 = 1465;
+ return IIO_VAL_INT_PLUS_MICRO;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ ret = kmx61_get_odr(data, val, val2, chan->address);
+ mutex_unlock(&data->lock);
+ if (ret)
+ return -EINVAL;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ return -EINVAL;
+}
+
+static int kmx61_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan, int val,
+ int val2, long mask)
+{
+ int ret;
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ if (chan->type != IIO_ACCEL && chan->type != IIO_MAGN)
+ return -EINVAL;
+
+ mutex_lock(&data->lock);
+ ret = kmx61_set_odr(data, val, val2, chan->address);
+ mutex_unlock(&data->lock);
+ return ret;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_ACCEL:
+ if (val != 0)
+ return -EINVAL;
+ mutex_lock(&data->lock);
+ ret = kmx61_set_scale(data, val2);
+ mutex_unlock(&data->lock);
+ return ret;
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int kmx61_read_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int *val, int *val2)
+{
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ *val2 = 0;
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ *val = data->wake_thresh;
+ return IIO_VAL_INT;
+ case IIO_EV_INFO_PERIOD:
+ *val = data->wake_duration;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int kmx61_write_event(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ enum iio_event_info info,
+ int val, int val2)
+{
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ if (data->ev_enable_state)
+ return -EBUSY;
+
+ switch (info) {
+ case IIO_EV_INFO_VALUE:
+ data->wake_thresh = val;
+ return IIO_VAL_INT;
+ case IIO_EV_INFO_PERIOD:
+ data->wake_duration = val;
+ return IIO_VAL_INT;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int kmx61_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ return data->ev_enable_state;
+}
+
+static int kmx61_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+ int ret = 0;
+
+ if (state && data->ev_enable_state)
+ return 0;
+
+ mutex_lock(&data->lock);
+
+ if (!state && data->motion_trig_on) {
+ data->ev_enable_state = false;
+ goto err_unlock;
+ }
+
+ ret = kmx61_set_power_state(data, state, KMX61_ACC);
+ if (ret < 0)
+ goto err_unlock;
+
+ ret = kmx61_setup_any_motion_interrupt(data, state);
+ if (ret < 0) {
+ kmx61_set_power_state(data, false, KMX61_ACC);
+ goto err_unlock;
+ }
+
+ data->ev_enable_state = state;
+
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int kmx61_acc_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ if (data->acc_dready_trig != trig && data->motion_trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int kmx61_mag_validate_trigger(struct iio_dev *indio_dev,
+ struct iio_trigger *trig)
+{
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ if (data->mag_dready_trig != trig)
+ return -EINVAL;
+
+ return 0;
+}
+
+static const struct iio_info kmx61_acc_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = kmx61_read_raw,
+ .write_raw = kmx61_write_raw,
+ .attrs = &kmx61_acc_attribute_group,
+ .read_event_value = kmx61_read_event,
+ .write_event_value = kmx61_write_event,
+ .read_event_config = kmx61_read_event_config,
+ .write_event_config = kmx61_write_event_config,
+ .validate_trigger = kmx61_acc_validate_trigger,
+};
+
+static const struct iio_info kmx61_mag_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = kmx61_read_raw,
+ .write_raw = kmx61_write_raw,
+ .attrs = &kmx61_mag_attribute_group,
+ .validate_trigger = kmx61_mag_validate_trigger,
+};
+
+
+static int kmx61_data_rdy_trigger_set_state(struct iio_trigger *trig,
+ bool state)
+{
+ int ret = 0;
+ u8 device;
+
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+
+ mutex_lock(&data->lock);
+
+ if (!state && data->ev_enable_state && data->motion_trig_on) {
+ data->motion_trig_on = false;
+ goto err_unlock;
+ }
+
+ if (data->acc_dready_trig == trig || data->motion_trig == trig)
+ device = KMX61_ACC;
+ else
+ device = KMX61_MAG;
+
+ ret = kmx61_set_power_state(data, state, device);
+ if (ret < 0)
+ goto err_unlock;
+
+ if (data->acc_dready_trig == trig || data->mag_dready_trig == trig)
+ ret = kmx61_setup_new_data_interrupt(data, state, device);
+ else
+ ret = kmx61_setup_any_motion_interrupt(data, state);
+ if (ret < 0) {
+ kmx61_set_power_state(data, false, device);
+ goto err_unlock;
+ }
+
+ if (data->acc_dready_trig == trig)
+ data->acc_dready_trig_on = state;
+ else if (data->mag_dready_trig == trig)
+ data->mag_dready_trig_on = state;
+ else
+ data->motion_trig_on = state;
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int kmx61_trig_try_reenable(struct iio_trigger *trig)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_inl\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct iio_trigger_ops kmx61_trigger_ops = {
+ .set_trigger_state = kmx61_data_rdy_trigger_set_state,
+ .try_reenable = kmx61_trig_try_reenable,
+ .owner = THIS_MODULE,
+};
+
+static irqreturn_t kmx61_event_handler(int irq, void *private)
+{
+ struct kmx61_data *data = private;
+ struct iio_dev *indio_dev = data->acc_indio_dev;
+ int ret;
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INS1);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_ins1\n");
+ goto ack_intr;
+ }
+
+ if (ret & KMX61_REG_INS1_BIT_WUFS) {
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INS2);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "Error reading reg_ins2\n");
+ goto ack_intr;
+ }
+
+ if (ret & KMX61_REG_INS2_BIT_XN)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_X,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ 0);
+
+ if (ret & KMX61_REG_INS2_BIT_XP)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_X,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ 0);
+
+ if (ret & KMX61_REG_INS2_BIT_YN)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_Y,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ 0);
+
+ if (ret & KMX61_REG_INS2_BIT_YP)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_Y,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ 0);
+
+ if (ret & KMX61_REG_INS2_BIT_ZN)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_Z,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_FALLING),
+ 0);
+
+ if (ret & KMX61_REG_INS2_BIT_ZP)
+ iio_push_event(indio_dev,
+ IIO_MOD_EVENT_CODE(IIO_ACCEL,
+ 0,
+ IIO_MOD_Z,
+ IIO_EV_TYPE_THRESH,
+ IIO_EV_DIR_RISING),
+ 0);
+ }
+
+ack_intr:
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_CTRL1);
+ if (ret < 0)
+ dev_err(&data->client->dev, "Error reading reg_ctrl1\n");
+
+ ret |= KMX61_REG_CTRL1_BIT_RES;
+ ret = i2c_smbus_write_byte_data(data->client, KMX61_REG_CTRL1, ret);
+ if (ret < 0)
+ dev_err(&data->client->dev, "Error writing reg_ctrl1\n");
+
+ ret = i2c_smbus_read_byte_data(data->client, KMX61_REG_INL);
+ if (ret < 0)
+ dev_err(&data->client->dev, "Error reading reg_inl\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t kmx61_data_rdy_trig_poll(int irq, void *private)
+{
+ struct kmx61_data *data = private;
+
+ if (data->acc_dready_trig_on)
+ iio_trigger_poll(data->acc_dready_trig);
+ if (data->mag_dready_trig_on)
+ iio_trigger_poll(data->mag_dready_trig);
+
+ if (data->motion_trig_on)
+ iio_trigger_poll(data->motion_trig);
+
+ if (data->ev_enable_state)
+ return IRQ_WAKE_THREAD;
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t kmx61_trigger_handler(int irq, void *p)
+{
+ struct iio_poll_func *pf = p;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct kmx61_data *data = kmx61_get_data(indio_dev);
+ int bit, ret, i = 0;
+ u8 base;
+ s16 buffer[8];
+
+ if (indio_dev == data->acc_indio_dev)
+ base = KMX61_ACC_XOUT_L;
+ else
+ base = KMX61_MAG_XOUT_L;
+
+ mutex_lock(&data->lock);
+ for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+ indio_dev->masklength) {
+ ret = kmx61_read_measurement(data, base, bit);
+ if (ret < 0) {
+ mutex_unlock(&data->lock);
+ goto err;
+ }
+ buffer[i++] = ret;
+ }
+ mutex_unlock(&data->lock);
+
+ iio_push_to_buffers(indio_dev, buffer);
+err:
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+static const char *kmx61_match_acpi_device(struct device *dev)
+{
+ const struct acpi_device_id *id;
+
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return NULL;
+ return dev_name(dev);
+}
+
+static int kmx61_gpio_probe(struct i2c_client *client, struct kmx61_data *data)
+{
+ struct device *dev;
+ struct gpio_desc *gpio;
+ int ret;
+
+ if (!client)
+ return -EINVAL;
+
+ dev = &client->dev;
+
+ /* data ready gpio interrupt pin */
+ gpio = devm_gpiod_get_index(dev, KMX61_GPIO_NAME, 0);
+ if (IS_ERR(gpio)) {
+ dev_err(dev, "acpi gpio get index failed\n");
+ return PTR_ERR(gpio);
+ }
+
+ ret = gpiod_direction_input(gpio);
+ if (ret)
+ return ret;
+
+ ret = gpiod_to_irq(gpio);
+
+ dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+ return ret;
+}
+
+static struct iio_dev *kmx61_indiodev_setup(struct kmx61_data *data,
+ const struct iio_info *info,
+ const struct iio_chan_spec *chan,
+ int num_channels,
+ const char *name)
+{
+ struct iio_dev *indio_dev;
+
+ indio_dev = devm_iio_device_alloc(&data->client->dev, sizeof(data));
+ if (!indio_dev)
+ return ERR_PTR(-ENOMEM);
+
+ kmx61_set_data(indio_dev, data);
+
+ indio_dev->dev.parent = &data->client->dev;
+ indio_dev->channels = chan;
+ indio_dev->num_channels = num_channels;
+ indio_dev->name = name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ indio_dev->info = info;
+
+ return indio_dev;
+}
+
+static struct iio_trigger *kmx61_trigger_setup(struct kmx61_data *data,
+ struct iio_dev *indio_dev,
+ const char *tag)
+{
+ struct iio_trigger *trig;
+ int ret;
+
+ trig = devm_iio_trigger_alloc(&data->client->dev,
+ "%s-%s-dev%d",
+ indio_dev->name,
+ tag,
+ indio_dev->id);
+ if (!trig)
+ return ERR_PTR(-ENOMEM);
+
+ trig->dev.parent = &data->client->dev;
+ trig->ops = &kmx61_trigger_ops;
+ iio_trigger_set_drvdata(trig, indio_dev);
+
+ ret = iio_trigger_register(trig);
+ if (ret)
+ return ERR_PTR(ret);
+
+ return trig;
+}
+
+static int kmx61_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct kmx61_data *data;
+ const char *name = NULL;
+
+ data = devm_kzalloc(&client->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ i2c_set_clientdata(client, data);
+ data->client = client;
+
+ mutex_init(&data->lock);
+
+ if (id)
+ name = id->name;
+ else if (ACPI_HANDLE(&client->dev))
+ name = kmx61_match_acpi_device(&client->dev);
+ else
+ return -ENODEV;
+
+ data->acc_indio_dev =
+ kmx61_indiodev_setup(data, &kmx61_acc_info,
+ kmx61_acc_channels,
+ ARRAY_SIZE(kmx61_acc_channels),
+ name);
+ if (IS_ERR(data->acc_indio_dev))
+ return PTR_ERR(data->acc_indio_dev);
+
+ data->mag_indio_dev =
+ kmx61_indiodev_setup(data, &kmx61_mag_info,
+ kmx61_mag_channels,
+ ARRAY_SIZE(kmx61_mag_channels),
+ name);
+ if (IS_ERR(data->mag_indio_dev))
+ return PTR_ERR(data->mag_indio_dev);
+
+ ret = kmx61_chip_init(data);
+ if (ret < 0)
+ return ret;
+
+ if (client->irq < 0)
+ client->irq = kmx61_gpio_probe(client, data);
+
+ if (client->irq >= 0) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ kmx61_data_rdy_trig_poll,
+ kmx61_event_handler,
+ IRQF_TRIGGER_RISING,
+ KMX61_IRQ_NAME,
+ data);
+ if (ret)
+ goto err_chip_uninit;
+
+ data->acc_dready_trig =
+ kmx61_trigger_setup(data, data->acc_indio_dev,
+ "dready");
+ if (IS_ERR(data->acc_dready_trig)) {
+ ret = PTR_ERR(data->acc_dready_trig);
+ goto err_chip_uninit;
+ }
+
+ data->mag_dready_trig =
+ kmx61_trigger_setup(data, data->mag_indio_dev,
+ "dready");
+ if (IS_ERR(data->mag_dready_trig)) {
+ ret = PTR_ERR(data->mag_dready_trig);
+ goto err_trigger_unregister_acc_dready;
+ }
+
+ data->motion_trig =
+ kmx61_trigger_setup(data, data->acc_indio_dev,
+ "any-motion");
+ if (IS_ERR(data->motion_trig)) {
+ ret = PTR_ERR(data->motion_trig);
+ goto err_trigger_unregister_mag_dready;
+ }
+
+ ret = iio_triggered_buffer_setup(data->acc_indio_dev,
+ &iio_pollfunc_store_time,
+ kmx61_trigger_handler,
+ NULL);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to setup acc triggered buffer\n");
+ goto err_trigger_unregister_motion;
+ }
+
+ ret = iio_triggered_buffer_setup(data->mag_indio_dev,
+ &iio_pollfunc_store_time,
+ kmx61_trigger_handler,
+ NULL);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "Failed to setup mag triggered buffer\n");
+ goto err_buffer_cleanup_acc;
+ }
+ }
+
+ ret = iio_device_register(data->acc_indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to register acc iio device\n");
+ goto err_buffer_cleanup_mag;
+ }
+
+ ret = iio_device_register(data->mag_indio_dev);
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed to register mag iio device\n");
+ goto err_iio_unregister_acc;
+ }
+
+ ret = pm_runtime_set_active(&client->dev);
+ if (ret < 0)
+ goto err_iio_unregister_mag;
+
+ pm_runtime_enable(&client->dev);
+ pm_runtime_set_autosuspend_delay(&client->dev, KMX61_SLEEP_DELAY_MS);
+ pm_runtime_use_autosuspend(&client->dev);
+
+ return 0;
+
+err_iio_unregister_mag:
+ iio_device_unregister(data->mag_indio_dev);
+err_iio_unregister_acc:
+ iio_device_unregister(data->acc_indio_dev);
+err_buffer_cleanup_mag:
+ if (client->irq >= 0)
+ iio_triggered_buffer_cleanup(data->mag_indio_dev);
+err_buffer_cleanup_acc:
+ if (client->irq >= 0)
+ iio_triggered_buffer_cleanup(data->acc_indio_dev);
+err_trigger_unregister_motion:
+ iio_trigger_unregister(data->motion_trig);
+err_trigger_unregister_mag_dready:
+ iio_trigger_unregister(data->mag_dready_trig);
+err_trigger_unregister_acc_dready:
+ iio_trigger_unregister(data->acc_dready_trig);
+err_chip_uninit:
+ kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+ return ret;
+}
+
+static int kmx61_remove(struct i2c_client *client)
+{
+ struct kmx61_data *data = i2c_get_clientdata(client);
+
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+ pm_runtime_put_noidle(&client->dev);
+
+ iio_device_unregister(data->acc_indio_dev);
+ iio_device_unregister(data->mag_indio_dev);
+
+ if (client->irq >= 0) {
+ iio_triggered_buffer_cleanup(data->acc_indio_dev);
+ iio_triggered_buffer_cleanup(data->mag_indio_dev);
+ iio_trigger_unregister(data->acc_dready_trig);
+ iio_trigger_unregister(data->mag_dready_trig);
+ iio_trigger_unregister(data->motion_trig);
+ }
+
+ mutex_lock(&data->lock);
+ kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+ mutex_unlock(&data->lock);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int kmx61_suspend(struct device *dev)
+{
+ int ret;
+ struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+ mutex_lock(&data->lock);
+ ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG,
+ false);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int kmx61_resume(struct device *dev)
+{
+ u8 stby = 0;
+ struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+
+ if (data->acc_stby)
+ stby |= KMX61_ACC_STBY_BIT;
+ if (data->mag_stby)
+ stby |= KMX61_MAG_STBY_BIT;
+
+ return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
+}
+#endif
+
+#ifdef CONFIG_PM
+static int kmx61_runtime_suspend(struct device *dev)
+{
+ struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+ int ret;
+
+ mutex_lock(&data->lock);
+ ret = kmx61_set_mode(data, KMX61_ALL_STBY, KMX61_ACC | KMX61_MAG, true);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int kmx61_runtime_resume(struct device *dev)
+{
+ struct kmx61_data *data = i2c_get_clientdata(to_i2c_client(dev));
+ u8 stby = 0;
+
+ if (!data->acc_ps)
+ stby |= KMX61_ACC_STBY_BIT;
+ if (!data->mag_ps)
+ stby |= KMX61_MAG_STBY_BIT;
+
+ return kmx61_set_mode(data, stby, KMX61_ACC | KMX61_MAG, true);
+}
+#endif
+
+static const struct dev_pm_ops kmx61_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(kmx61_suspend, kmx61_resume)
+ SET_RUNTIME_PM_OPS(kmx61_runtime_suspend, kmx61_runtime_resume, NULL)
+};
+
+static const struct acpi_device_id kmx61_acpi_match[] = {
+ {"KMX61021", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, kmx61_acpi_match);
+
+static const struct i2c_device_id kmx61_id[] = {
+ {"kmx611021", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, kmx61_id);
+
+static struct i2c_driver kmx61_driver = {
+ .driver = {
+ .name = KMX61_DRV_NAME,
+ .acpi_match_table = ACPI_PTR(kmx61_acpi_match),
+ .pm = &kmx61_pm_ops,
+ },
+ .probe = kmx61_probe,
+ .remove = kmx61_remove,
+ .id_table = kmx61_id,
+};
+
+module_i2c_driver(kmx61_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com>");
+MODULE_DESCRIPTION("KMX61 accelerometer/magnetometer driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c
index f971f79103ec..71333140d42c 100644
--- a/drivers/iio/industrialio-buffer.c
+++ b/drivers/iio/industrialio-buffer.c
@@ -178,6 +178,80 @@ static ssize_t iio_scan_el_show(struct device *dev,
return sprintf(buf, "%d\n", ret);
}
+/* Note NULL used as error indicator as it doesn't make sense. */
+static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
+ unsigned int masklength,
+ const unsigned long *mask)
+{
+ if (bitmap_empty(mask, masklength))
+ return NULL;
+ while (*av_masks) {
+ if (bitmap_subset(mask, av_masks, masklength))
+ return av_masks;
+ av_masks += BITS_TO_LONGS(masklength);
+ }
+ return NULL;
+}
+
+static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
+ const unsigned long *mask)
+{
+ if (!indio_dev->setup_ops->validate_scan_mask)
+ return true;
+
+ return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
+}
+
+/**
+ * iio_scan_mask_set() - set particular bit in the scan mask
+ * @indio_dev: the iio device
+ * @buffer: the buffer whose scan mask we are interested in
+ * @bit: the bit to be set.
+ *
+ * Note that at this point we have no way of knowing what other
+ * buffers might request, hence this code only verifies that the
+ * individual buffers request is plausible.
+ */
+static int iio_scan_mask_set(struct iio_dev *indio_dev,
+ struct iio_buffer *buffer, int bit)
+{
+ const unsigned long *mask;
+ unsigned long *trialmask;
+
+ trialmask = kmalloc(sizeof(*trialmask)*
+ BITS_TO_LONGS(indio_dev->masklength),
+ GFP_KERNEL);
+
+ if (trialmask == NULL)
+ return -ENOMEM;
+ if (!indio_dev->masklength) {
+ WARN_ON("Trying to set scanmask prior to registering buffer\n");
+ goto err_invalid_mask;
+ }
+ bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
+ set_bit(bit, trialmask);
+
+ if (!iio_validate_scan_mask(indio_dev, trialmask))
+ goto err_invalid_mask;
+
+ if (indio_dev->available_scan_masks) {
+ mask = iio_scan_mask_match(indio_dev->available_scan_masks,
+ indio_dev->masklength,
+ trialmask);
+ if (!mask)
+ goto err_invalid_mask;
+ }
+ bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
+
+ kfree(trialmask);
+
+ return 0;
+
+err_invalid_mask:
+ kfree(trialmask);
+ return -EINVAL;
+}
+
static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit)
{
clear_bit(bit, buffer->scan_mask);
@@ -309,115 +383,19 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
return ret;
}
-static const char * const iio_scan_elements_group_name = "scan_elements";
-
-int iio_buffer_register(struct iio_dev *indio_dev,
- const struct iio_chan_spec *channels,
- int num_channels)
-{
- struct iio_dev_attr *p;
- struct attribute **attr;
- struct iio_buffer *buffer = indio_dev->buffer;
- int ret, i, attrn, attrcount, attrcount_orig = 0;
-
- if (buffer->attrs)
- indio_dev->groups[indio_dev->groupcounter++] = buffer->attrs;
-
- if (buffer->scan_el_attrs != NULL) {
- attr = buffer->scan_el_attrs->attrs;
- while (*attr++ != NULL)
- attrcount_orig++;
- }
- attrcount = attrcount_orig;
- INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
- if (channels) {
- /* new magic */
- for (i = 0; i < num_channels; i++) {
- if (channels[i].scan_index < 0)
- continue;
-
- /* Establish necessary mask length */
- if (channels[i].scan_index >
- (int)indio_dev->masklength - 1)
- indio_dev->masklength
- = channels[i].scan_index + 1;
-
- ret = iio_buffer_add_channel_sysfs(indio_dev,
- &channels[i]);
- if (ret < 0)
- goto error_cleanup_dynamic;
- attrcount += ret;
- if (channels[i].type == IIO_TIMESTAMP)
- indio_dev->scan_index_timestamp =
- channels[i].scan_index;
- }
- if (indio_dev->masklength && buffer->scan_mask == NULL) {
- buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
- sizeof(*buffer->scan_mask),
- GFP_KERNEL);
- if (buffer->scan_mask == NULL) {
- ret = -ENOMEM;
- goto error_cleanup_dynamic;
- }
- }
- }
-
- buffer->scan_el_group.name = iio_scan_elements_group_name;
-
- buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
- sizeof(buffer->scan_el_group.attrs[0]),
- GFP_KERNEL);
- if (buffer->scan_el_group.attrs == NULL) {
- ret = -ENOMEM;
- goto error_free_scan_mask;
- }
- if (buffer->scan_el_attrs)
- memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
- sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
- attrn = attrcount_orig;
-
- list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
- buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
- indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
-
- return 0;
-
-error_free_scan_mask:
- kfree(buffer->scan_mask);
-error_cleanup_dynamic:
- iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
-
- return ret;
-}
-EXPORT_SYMBOL(iio_buffer_register);
-
-void iio_buffer_unregister(struct iio_dev *indio_dev)
-{
- kfree(indio_dev->buffer->scan_mask);
- kfree(indio_dev->buffer->scan_el_group.attrs);
- iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
-}
-EXPORT_SYMBOL(iio_buffer_unregister);
-
-ssize_t iio_buffer_read_length(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t iio_buffer_read_length(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
- if (buffer->access->get_length)
- return sprintf(buf, "%d\n",
- buffer->access->get_length(buffer));
-
- return 0;
+ return sprintf(buf, "%d\n", buffer->length);
}
-EXPORT_SYMBOL(iio_buffer_read_length);
-ssize_t iio_buffer_write_length(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+static ssize_t iio_buffer_write_length(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
struct iio_buffer *buffer = indio_dev->buffer;
@@ -428,47 +406,28 @@ ssize_t iio_buffer_write_length(struct device *dev,
if (ret)
return ret;
- if (buffer->access->get_length)
- if (val == buffer->access->get_length(buffer))
- return len;
+ if (val == buffer->length)
+ return len;
mutex_lock(&indio_dev->mlock);
if (iio_buffer_is_active(indio_dev->buffer)) {
ret = -EBUSY;
} else {
- if (buffer->access->set_length)
- buffer->access->set_length(buffer, val);
+ buffer->access->set_length(buffer, val);
ret = 0;
}
mutex_unlock(&indio_dev->mlock);
return ret ? ret : len;
}
-EXPORT_SYMBOL(iio_buffer_write_length);
-ssize_t iio_buffer_show_enable(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t iio_buffer_show_enable(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct iio_dev *indio_dev = dev_to_iio_dev(dev);
return sprintf(buf, "%d\n", iio_buffer_is_active(indio_dev->buffer));
}
-EXPORT_SYMBOL(iio_buffer_show_enable);
-
-/* Note NULL used as error indicator as it doesn't make sense. */
-static const unsigned long *iio_scan_mask_match(const unsigned long *av_masks,
- unsigned int masklength,
- const unsigned long *mask)
-{
- if (bitmap_empty(mask, masklength))
- return NULL;
- while (*av_masks) {
- if (bitmap_subset(mask, av_masks, masklength))
- return av_masks;
- av_masks += BITS_TO_LONGS(masklength);
- }
- return NULL;
-}
static int iio_compute_scan_bytes(struct iio_dev *indio_dev,
const unsigned long *mask, bool timestamp)
@@ -680,6 +639,8 @@ static int __iio_update_buffers(struct iio_dev *indio_dev,
indio_dev->currentmode = INDIO_BUFFER_TRIGGERED;
} else if (indio_dev->modes & INDIO_BUFFER_HARDWARE) {
indio_dev->currentmode = INDIO_BUFFER_HARDWARE;
+ } else if (indio_dev->modes & INDIO_BUFFER_SOFTWARE) {
+ indio_dev->currentmode = INDIO_BUFFER_SOFTWARE;
} else { /* Should never be reached */
ret = -EINVAL;
goto error_run_postdisable;
@@ -755,10 +716,10 @@ out_unlock:
}
EXPORT_SYMBOL_GPL(iio_update_buffers);
-ssize_t iio_buffer_store_enable(struct device *dev,
- struct device_attribute *attr,
- const char *buf,
- size_t len)
+static ssize_t iio_buffer_store_enable(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf,
+ size_t len)
{
int ret;
bool requested_state;
@@ -790,83 +751,146 @@ done:
mutex_unlock(&indio_dev->mlock);
return (ret < 0) ? ret : len;
}
-EXPORT_SYMBOL(iio_buffer_store_enable);
-/**
- * iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected
- * @indio_dev: the iio device
- * @mask: scan mask to be checked
- *
- * Return true if exactly one bit is set in the scan mask, false otherwise. It
- * can be used for devices where only one channel can be active for sampling at
- * a time.
- */
-bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
- const unsigned long *mask)
-{
- return bitmap_weight(mask, indio_dev->masklength) == 1;
-}
-EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot);
-
-static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
- const unsigned long *mask)
-{
- if (!indio_dev->setup_ops->validate_scan_mask)
- return true;
+static const char * const iio_scan_elements_group_name = "scan_elements";
- return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask);
-}
+static DEVICE_ATTR(length, S_IRUGO | S_IWUSR, iio_buffer_read_length,
+ iio_buffer_write_length);
+static struct device_attribute dev_attr_length_ro = __ATTR(length,
+ S_IRUGO, iio_buffer_read_length, NULL);
+static DEVICE_ATTR(enable, S_IRUGO | S_IWUSR,
+ iio_buffer_show_enable, iio_buffer_store_enable);
-/**
- * iio_scan_mask_set() - set particular bit in the scan mask
- * @indio_dev: the iio device
- * @buffer: the buffer whose scan mask we are interested in
- * @bit: the bit to be set.
- *
- * Note that at this point we have no way of knowing what other
- * buffers might request, hence this code only verifies that the
- * individual buffers request is plausible.
- */
-int iio_scan_mask_set(struct iio_dev *indio_dev,
- struct iio_buffer *buffer, int bit)
+int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
{
- const unsigned long *mask;
- unsigned long *trialmask;
+ struct iio_dev_attr *p;
+ struct attribute **attr;
+ struct iio_buffer *buffer = indio_dev->buffer;
+ int ret, i, attrn, attrcount, attrcount_orig = 0;
+ const struct iio_chan_spec *channels;
- trialmask = kmalloc(sizeof(*trialmask)*
- BITS_TO_LONGS(indio_dev->masklength),
- GFP_KERNEL);
+ if (!buffer)
+ return 0;
- if (trialmask == NULL)
+ attrcount = 0;
+ if (buffer->attrs) {
+ while (buffer->attrs[attrcount] != NULL)
+ attrcount++;
+ }
+
+ buffer->buffer_group.name = "buffer";
+ buffer->buffer_group.attrs = kcalloc(attrcount + 3,
+ sizeof(*buffer->buffer_group.attrs), GFP_KERNEL);
+ if (!buffer->buffer_group.attrs)
return -ENOMEM;
- if (!indio_dev->masklength) {
- WARN_ON("Trying to set scanmask prior to registering buffer\n");
- goto err_invalid_mask;
+
+ if (buffer->access->set_length)
+ buffer->buffer_group.attrs[0] = &dev_attr_length.attr;
+ else
+ buffer->buffer_group.attrs[0] = &dev_attr_length_ro.attr;
+ buffer->buffer_group.attrs[1] = &dev_attr_enable.attr;
+ if (buffer->attrs)
+ memcpy(&buffer->buffer_group.attrs[2], buffer->attrs,
+ sizeof(*&buffer->buffer_group.attrs) * attrcount);
+ buffer->buffer_group.attrs[attrcount+2] = NULL;
+
+ indio_dev->groups[indio_dev->groupcounter++] = &buffer->buffer_group;
+
+ if (buffer->scan_el_attrs != NULL) {
+ attr = buffer->scan_el_attrs->attrs;
+ while (*attr++ != NULL)
+ attrcount_orig++;
}
- bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
- set_bit(bit, trialmask);
+ attrcount = attrcount_orig;
+ INIT_LIST_HEAD(&buffer->scan_el_dev_attr_list);
+ channels = indio_dev->channels;
+ if (channels) {
+ /* new magic */
+ for (i = 0; i < indio_dev->num_channels; i++) {
+ if (channels[i].scan_index < 0)
+ continue;
- if (!iio_validate_scan_mask(indio_dev, trialmask))
- goto err_invalid_mask;
+ /* Establish necessary mask length */
+ if (channels[i].scan_index >
+ (int)indio_dev->masklength - 1)
+ indio_dev->masklength
+ = channels[i].scan_index + 1;
- if (indio_dev->available_scan_masks) {
- mask = iio_scan_mask_match(indio_dev->available_scan_masks,
- indio_dev->masklength,
- trialmask);
- if (!mask)
- goto err_invalid_mask;
+ ret = iio_buffer_add_channel_sysfs(indio_dev,
+ &channels[i]);
+ if (ret < 0)
+ goto error_cleanup_dynamic;
+ attrcount += ret;
+ if (channels[i].type == IIO_TIMESTAMP)
+ indio_dev->scan_index_timestamp =
+ channels[i].scan_index;
+ }
+ if (indio_dev->masklength && buffer->scan_mask == NULL) {
+ buffer->scan_mask = kcalloc(BITS_TO_LONGS(indio_dev->masklength),
+ sizeof(*buffer->scan_mask),
+ GFP_KERNEL);
+ if (buffer->scan_mask == NULL) {
+ ret = -ENOMEM;
+ goto error_cleanup_dynamic;
+ }
+ }
}
- bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength);
- kfree(trialmask);
+ buffer->scan_el_group.name = iio_scan_elements_group_name;
+
+ buffer->scan_el_group.attrs = kcalloc(attrcount + 1,
+ sizeof(buffer->scan_el_group.attrs[0]),
+ GFP_KERNEL);
+ if (buffer->scan_el_group.attrs == NULL) {
+ ret = -ENOMEM;
+ goto error_free_scan_mask;
+ }
+ if (buffer->scan_el_attrs)
+ memcpy(buffer->scan_el_group.attrs, buffer->scan_el_attrs,
+ sizeof(buffer->scan_el_group.attrs[0])*attrcount_orig);
+ attrn = attrcount_orig;
+
+ list_for_each_entry(p, &buffer->scan_el_dev_attr_list, l)
+ buffer->scan_el_group.attrs[attrn++] = &p->dev_attr.attr;
+ indio_dev->groups[indio_dev->groupcounter++] = &buffer->scan_el_group;
return 0;
-err_invalid_mask:
- kfree(trialmask);
- return -EINVAL;
+error_free_scan_mask:
+ kfree(buffer->scan_mask);
+error_cleanup_dynamic:
+ iio_free_chan_devattr_list(&buffer->scan_el_dev_attr_list);
+ kfree(indio_dev->buffer->buffer_group.attrs);
+
+ return ret;
+}
+
+void iio_buffer_free_sysfs_and_mask(struct iio_dev *indio_dev)
+{
+ if (!indio_dev->buffer)
+ return;
+
+ kfree(indio_dev->buffer->scan_mask);
+ kfree(indio_dev->buffer->buffer_group.attrs);
+ kfree(indio_dev->buffer->scan_el_group.attrs);
+ iio_free_chan_devattr_list(&indio_dev->buffer->scan_el_dev_attr_list);
+}
+
+/**
+ * iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected
+ * @indio_dev: the iio device
+ * @mask: scan mask to be checked
+ *
+ * Return true if exactly one bit is set in the scan mask, false otherwise. It
+ * can be used for devices where only one channel can be active for sampling at
+ * a time.
+ */
+bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev,
+ const unsigned long *mask)
+{
+ return bitmap_weight(mask, indio_dev->masklength) == 1;
}
-EXPORT_SYMBOL_GPL(iio_scan_mask_set);
+EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot);
int iio_scan_mask_query(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
diff --git a/drivers/iio/industrialio-core.c b/drivers/iio/industrialio-core.c
index af3e76d652ba..aaba9d3d980e 100644
--- a/drivers/iio/industrialio-core.c
+++ b/drivers/iio/industrialio-core.c
@@ -70,6 +70,11 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CCT] = "cct",
[IIO_PRESSURE] = "pressure",
[IIO_HUMIDITYRELATIVE] = "humidityrelative",
+ [IIO_ACTIVITY] = "activity",
+ [IIO_STEPS] = "steps",
+ [IIO_ENERGY] = "energy",
+ [IIO_DISTANCE] = "distance",
+ [IIO_VELOCITY] = "velocity",
};
static const char * const iio_modifier_names[] = {
@@ -91,6 +96,11 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_NORTH_TRUE] = "from_north_true",
[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
+ [IIO_MOD_RUNNING] = "running",
+ [IIO_MOD_JOGGING] = "jogging",
+ [IIO_MOD_WALKING] = "walking",
+ [IIO_MOD_STILL] = "still",
+ [IIO_MOD_ROOT_SUM_SQUARED_X_Y_Z] = "sqrt(x^2+y^2+z^2)",
};
/* relies on pairs of these shared then separate */
@@ -113,6 +123,11 @@ static const char * const iio_chan_info_postfix[] = {
[IIO_CHAN_INFO_HARDWAREGAIN] = "hardwaregain",
[IIO_CHAN_INFO_HYSTERESIS] = "hysteresis",
[IIO_CHAN_INFO_INT_TIME] = "integration_time",
+ [IIO_CHAN_INFO_ENABLE] = "en",
+ [IIO_CHAN_INFO_CALIBHEIGHT] = "calibheight",
+ [IIO_CHAN_INFO_CALIBWEIGHT] = "calibweight",
+ [IIO_CHAN_INFO_DEBOUNCE_COUNT] = "debounce_count",
+ [IIO_CHAN_INFO_DEBOUNCE_TIME] = "debounce_time",
};
/**
@@ -1035,7 +1050,6 @@ struct iio_dev *devm_iio_device_alloc(struct device *dev, int sizeof_priv)
if (!ptr)
return NULL;
- /* use raw alloc_dr for kmalloc caller tracing */
iio_dev = iio_device_alloc(sizeof_priv);
if (iio_dev) {
*ptr = iio_dev;
@@ -1127,6 +1141,29 @@ static const struct file_operations iio_buffer_fileops = {
.compat_ioctl = iio_ioctl,
};
+static int iio_check_unique_scan_index(struct iio_dev *indio_dev)
+{
+ int i, j;
+ const struct iio_chan_spec *channels = indio_dev->channels;
+
+ if (!(indio_dev->modes & INDIO_ALL_BUFFER_MODES))
+ return 0;
+
+ for (i = 0; i < indio_dev->num_channels - 1; i++) {
+ if (channels[i].scan_index < 0)
+ continue;
+ for (j = i + 1; j < indio_dev->num_channels; j++)
+ if (channels[i].scan_index == channels[j].scan_index) {
+ dev_err(&indio_dev->dev,
+ "Duplicate scan index %d\n",
+ channels[i].scan_index);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
static const struct iio_buffer_setup_ops noop_ring_setup_ops;
/**
@@ -1141,6 +1178,10 @@ int iio_device_register(struct iio_dev *indio_dev)
if (!indio_dev->dev.of_node && indio_dev->dev.parent)
indio_dev->dev.of_node = indio_dev->dev.parent->of_node;
+ ret = iio_check_unique_scan_index(indio_dev);
+ if (ret < 0)
+ return ret;
+
/* configure elements for the chrdev */
indio_dev->dev.devt = MKDEV(MAJOR(iio_devt), indio_dev->id);
@@ -1150,11 +1191,19 @@ int iio_device_register(struct iio_dev *indio_dev)
"Failed to register debugfs interfaces\n");
return ret;
}
+
+ ret = iio_buffer_alloc_sysfs_and_mask(indio_dev);
+ if (ret) {
+ dev_err(indio_dev->dev.parent,
+ "Failed to create buffer sysfs interfaces\n");
+ goto error_unreg_debugfs;
+ }
+
ret = iio_device_register_sysfs(indio_dev);
if (ret) {
dev_err(indio_dev->dev.parent,
"Failed to register sysfs interfaces\n");
- goto error_unreg_debugfs;
+ goto error_buffer_free_sysfs;
}
ret = iio_device_register_eventset(indio_dev);
if (ret) {
@@ -1187,6 +1236,8 @@ error_unreg_eventset:
iio_device_unregister_eventset(indio_dev);
error_free_sysfs:
iio_device_unregister_sysfs(indio_dev);
+error_buffer_free_sysfs:
+ iio_buffer_free_sysfs_and_mask(indio_dev);
error_unreg_debugfs:
iio_device_unregister_debugfs(indio_dev);
return ret;
@@ -1215,6 +1266,8 @@ void iio_device_unregister(struct iio_dev *indio_dev)
iio_buffer_wakeup_poll(indio_dev);
mutex_unlock(&indio_dev->info_exist_lock);
+
+ iio_buffer_free_sysfs_and_mask(indio_dev);
}
EXPORT_SYMBOL(iio_device_unregister);
diff --git a/drivers/iio/industrialio-event.c b/drivers/iio/industrialio-event.c
index 0c1e37e3120a..a4b397048f71 100644
--- a/drivers/iio/industrialio-event.c
+++ b/drivers/iio/industrialio-event.c
@@ -197,6 +197,7 @@ static const char * const iio_ev_type_text[] = {
[IIO_EV_TYPE_ROC] = "roc",
[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+ [IIO_EV_TYPE_CHANGE] = "change",
};
static const char * const iio_ev_dir_text[] = {
@@ -327,9 +328,15 @@ static int iio_device_add_event(struct iio_dev *indio_dev,
for_each_set_bit(i, mask, sizeof(*mask)*8) {
if (i >= ARRAY_SIZE(iio_ev_info_text))
return -EINVAL;
- postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
- iio_ev_type_text[type], iio_ev_dir_text[dir],
- iio_ev_info_text[i]);
+ if (dir != IIO_EV_DIR_NONE)
+ postfix = kasprintf(GFP_KERNEL, "%s_%s_%s",
+ iio_ev_type_text[type],
+ iio_ev_dir_text[dir],
+ iio_ev_info_text[i]);
+ else
+ postfix = kasprintf(GFP_KERNEL, "%s_%s",
+ iio_ev_type_text[type],
+ iio_ev_info_text[i]);
if (postfix == NULL)
return -ENOMEM;
@@ -404,7 +411,7 @@ static inline int __iio_add_event_config_attrs(struct iio_dev *indio_dev)
{
int j, ret, attrcount = 0;
- /* Dynically created from the channels array */
+ /* Dynamically created from the channels array */
for (j = 0; j < indio_dev->num_channels; j++) {
ret = iio_device_add_event_sysfs(indio_dev,
&indio_dev->channels[j]);
diff --git a/drivers/iio/industrialio-triggered-buffer.c b/drivers/iio/industrialio-triggered-buffer.c
index d6f54930b34a..15a5341b5e7b 100644
--- a/drivers/iio/industrialio-triggered-buffer.c
+++ b/drivers/iio/industrialio-triggered-buffer.c
@@ -32,7 +32,7 @@ static const struct iio_buffer_setup_ops iio_triggered_buffer_setup_ops = {
*
* This function combines some common tasks which will normally be performed
* when setting up a triggered buffer. It will allocate the buffer and the
- * pollfunc, as well as register the buffer with the IIO core.
+ * pollfunc.
*
* Before calling this function the indio_dev structure should already be
* completely initialized, but not yet registered. In practice this means that
@@ -49,7 +49,7 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
struct iio_buffer *buffer;
int ret;
- buffer = iio_kfifo_allocate(indio_dev);
+ buffer = iio_kfifo_allocate();
if (!buffer) {
ret = -ENOMEM;
goto error_ret;
@@ -78,16 +78,8 @@ int iio_triggered_buffer_setup(struct iio_dev *indio_dev,
/* Flag that polled ring buffering is possible */
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
- ret = iio_buffer_register(indio_dev,
- indio_dev->channels,
- indio_dev->num_channels);
- if (ret)
- goto error_dealloc_pollfunc;
-
return 0;
-error_dealloc_pollfunc:
- iio_dealloc_pollfunc(indio_dev->pollfunc);
error_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
error_ret:
@@ -101,7 +93,6 @@ EXPORT_SYMBOL(iio_triggered_buffer_setup);
*/
void iio_triggered_buffer_cleanup(struct iio_dev *indio_dev)
{
- iio_buffer_unregister(indio_dev);
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
index 90c8cb727cc7..c8bad3cf891d 100644
--- a/drivers/iio/inkern.c
+++ b/drivers/iio/inkern.c
@@ -116,8 +116,11 @@ static int __of_iio_simple_xlate(struct iio_dev *indio_dev,
if (!iiospec->args_count)
return 0;
- if (iiospec->args[0] >= indio_dev->num_channels)
+ if (iiospec->args[0] >= indio_dev->num_channels) {
+ dev_err(&indio_dev->dev, "invalid channel index %u\n",
+ iiospec->args[0]);
return -EINVAL;
+ }
return iiospec->args[0];
}
@@ -634,3 +637,28 @@ err_unlock:
return ret;
}
EXPORT_SYMBOL_GPL(iio_get_channel_type);
+
+static int iio_channel_write(struct iio_channel *chan, int val, int val2,
+ enum iio_chan_info_enum info)
+{
+ return chan->indio_dev->info->write_raw(chan->indio_dev,
+ chan->channel, val, val2, info);
+}
+
+int iio_write_channel_raw(struct iio_channel *chan, int val)
+{
+ int ret;
+
+ mutex_lock(&chan->indio_dev->info_exist_lock);
+ if (chan->indio_dev->info == NULL) {
+ ret = -ENODEV;
+ goto err_unlock;
+ }
+
+ ret = iio_channel_write(chan, val, 0, IIO_CHAN_INFO_RAW);
+err_unlock:
+ mutex_unlock(&chan->indio_dev->info_exist_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(iio_write_channel_raw);
diff --git a/drivers/iio/kfifo_buf.c b/drivers/iio/kfifo_buf.c
index 7134e8ada09a..b2beea01c49b 100644
--- a/drivers/iio/kfifo_buf.c
+++ b/drivers/iio/kfifo_buf.c
@@ -47,30 +47,6 @@ static int iio_request_update_kfifo(struct iio_buffer *r)
return ret;
}
-static int iio_get_length_kfifo(struct iio_buffer *r)
-{
- return r->length;
-}
-
-static IIO_BUFFER_ENABLE_ATTR;
-static IIO_BUFFER_LENGTH_ATTR;
-
-static struct attribute *iio_kfifo_attributes[] = {
- &dev_attr_length.attr,
- &dev_attr_enable.attr,
- NULL,
-};
-
-static struct attribute_group iio_kfifo_attribute_group = {
- .attrs = iio_kfifo_attributes,
- .name = "buffer",
-};
-
-static int iio_get_bytes_per_datum_kfifo(struct iio_buffer *r)
-{
- return r->bytes_per_datum;
-}
-
static int iio_mark_update_needed_kfifo(struct iio_buffer *r)
{
struct iio_kfifo *kf = iio_to_kfifo(r);
@@ -159,26 +135,25 @@ static const struct iio_buffer_access_funcs kfifo_access_funcs = {
.read_first_n = &iio_read_first_n_kfifo,
.data_available = iio_kfifo_buf_data_available,
.request_update = &iio_request_update_kfifo,
- .get_bytes_per_datum = &iio_get_bytes_per_datum_kfifo,
.set_bytes_per_datum = &iio_set_bytes_per_datum_kfifo,
- .get_length = &iio_get_length_kfifo,
.set_length = &iio_set_length_kfifo,
.release = &iio_kfifo_buffer_release,
};
-struct iio_buffer *iio_kfifo_allocate(struct iio_dev *indio_dev)
+struct iio_buffer *iio_kfifo_allocate(void)
{
struct iio_kfifo *kf;
- kf = kzalloc(sizeof *kf, GFP_KERNEL);
+ kf = kzalloc(sizeof(*kf), GFP_KERNEL);
if (!kf)
return NULL;
+
kf->update_needed = true;
iio_buffer_init(&kf->buffer);
- kf->buffer.attrs = &iio_kfifo_attribute_group;
kf->buffer.access = &kfifo_access_funcs;
kf->buffer.length = 2;
mutex_init(&kf->user_lock);
+
return &kf->buffer;
}
EXPORT_SYMBOL(iio_kfifo_allocate);
@@ -189,4 +164,58 @@ void iio_kfifo_free(struct iio_buffer *r)
}
EXPORT_SYMBOL(iio_kfifo_free);
+static void devm_iio_kfifo_release(struct device *dev, void *res)
+{
+ iio_kfifo_free(*(struct iio_buffer **)res);
+}
+
+static int devm_iio_kfifo_match(struct device *dev, void *res, void *data)
+{
+ struct iio_buffer **r = res;
+
+ if (WARN_ON(!r || !*r))
+ return 0;
+
+ return *r == data;
+}
+
+/**
+ * devm_iio_fifo_allocate - Resource-managed iio_kfifo_allocate()
+ * @dev: Device to allocate kfifo buffer for
+ *
+ * RETURNS:
+ * Pointer to allocated iio_buffer on success, NULL on failure.
+ */
+struct iio_buffer *devm_iio_kfifo_allocate(struct device *dev)
+{
+ struct iio_buffer **ptr, *r;
+
+ ptr = devres_alloc(devm_iio_kfifo_release, sizeof(*ptr), GFP_KERNEL);
+ if (!ptr)
+ return NULL;
+
+ r = iio_kfifo_allocate();
+ if (r) {
+ *ptr = r;
+ devres_add(dev, ptr);
+ } else {
+ devres_free(ptr);
+ }
+
+ return r;
+}
+EXPORT_SYMBOL(devm_iio_kfifo_allocate);
+
+/**
+ * devm_iio_fifo_free - Resource-managed iio_kfifo_free()
+ * @dev: Device the buffer belongs to
+ * @r: The buffer associated with the device
+ */
+void devm_iio_kfifo_free(struct device *dev, struct iio_buffer *r)
+{
+ WARN_ON(devres_release(dev, devm_iio_kfifo_release,
+ devm_iio_kfifo_match, r));
+}
+EXPORT_SYMBOL(devm_iio_kfifo_free);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/Kconfig b/drivers/iio/light/Kconfig
index 5bea821adcae..ae68c64bdad3 100644
--- a/drivers/iio/light/Kconfig
+++ b/drivers/iio/light/Kconfig
@@ -48,6 +48,17 @@ config CM32181
To compile this driver as a module, choose M here:
the module will be called cm32181.
+config CM3232
+ depends on I2C
+ tristate "CM3232 ambient light sensor"
+ help
+ Say Y here if you use cm3232.
+ This option enables ambient light sensor using
+ Capella Microsystems cm3232 device driver.
+
+ To compile this driver as a module, choose M here:
+ the module will be called cm3232.
+
config CM36651
depends on I2C
tristate "CM36651 driver"
@@ -95,6 +106,9 @@ config HID_SENSOR_ALS
Say yes here to build support for the HID SENSOR
Ambient light sensor.
+ To compile this driver as a module, choose M here: the
+ module will be called hid-sensor-als.
+
config HID_SENSOR_PROX
depends on HID_SENSOR_HUB
select IIO_BUFFER
@@ -109,6 +123,16 @@ config HID_SENSOR_PROX
To compile this driver as a module, choose M here: the
module will be called hid-sensor-prox.
+config JSA1212
+ tristate "JSA1212 ALS and proximity sensor driver"
+ depends on I2C
+ help
+ Say Y here if you want to build a IIO driver for JSA1212
+ proximity & ALS sensor device.
+
+ To compile this driver as a module, choose M here:
+ the module will be called jsa1212.
+
config SENSORS_LM3533
tristate "LM3533 ambient light sensor"
depends on MFD_LM3533
diff --git a/drivers/iio/light/Makefile b/drivers/iio/light/Makefile
index 47877a36cc12..b12a5160d9e0 100644
--- a/drivers/iio/light/Makefile
+++ b/drivers/iio/light/Makefile
@@ -7,11 +7,13 @@ obj-$(CONFIG_ADJD_S311) += adjd_s311.o
obj-$(CONFIG_AL3320A) += al3320a.o
obj-$(CONFIG_APDS9300) += apds9300.o
obj-$(CONFIG_CM32181) += cm32181.o
+obj-$(CONFIG_CM3232) += cm3232.o
obj-$(CONFIG_CM36651) += cm36651.o
obj-$(CONFIG_GP2AP020A00F) += gp2ap020a00f.o
obj-$(CONFIG_HID_SENSOR_ALS) += hid-sensor-als.o
obj-$(CONFIG_HID_SENSOR_PROX) += hid-sensor-prox.o
obj-$(CONFIG_ISL29125) += isl29125.o
+obj-$(CONFIG_JSA1212) += jsa1212.o
obj-$(CONFIG_SENSORS_LM3533) += lm3533-als.o
obj-$(CONFIG_LTR501) += ltr501.o
obj-$(CONFIG_SENSORS_TSL2563) += tsl2563.o
diff --git a/drivers/iio/light/cm32181.c b/drivers/iio/light/cm32181.c
index ad36b294e4d5..5d12ae54d088 100644
--- a/drivers/iio/light/cm32181.c
+++ b/drivers/iio/light/cm32181.c
@@ -169,7 +169,7 @@ static int cm32181_write_als_it(struct cm32181_chip *cm32181, int val)
* @cm32181: pointer of struct cm32181.
*
* Convert sensor raw data to lux. It depends on integration
- * time and claibscale variable.
+ * time and calibscale variable.
*
* Return: Positive value is lux, otherwise is error code.
*/
diff --git a/drivers/iio/light/cm3232.c b/drivers/iio/light/cm3232.c
new file mode 100644
index 000000000000..90e3519a91de
--- /dev/null
+++ b/drivers/iio/light/cm3232.c
@@ -0,0 +1,403 @@
+/*
+ * CM3232 Ambient Light Sensor
+ *
+ * Copyright (C) 2014-2015 Capella Microsystems Inc.
+ * Author: Kevin Tsai <ktsai@capellamicro.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.
+ *
+ * IIO driver for CM3232 (7-bit I2C slave address 0x10).
+ */
+
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+#include <linux/init.h>
+
+/* Registers Address */
+#define CM3232_REG_ADDR_CMD 0x00
+#define CM3232_REG_ADDR_ALS 0x50
+#define CM3232_REG_ADDR_ID 0x53
+
+#define CM3232_CMD_ALS_DISABLE BIT(0)
+
+#define CM3232_CMD_ALS_IT_SHIFT 2
+#define CM3232_CMD_ALS_IT_MASK (BIT(2) | BIT(3) | BIT(4))
+#define CM3232_CMD_ALS_IT_DEFAULT (0x01 << CM3232_CMD_ALS_IT_SHIFT)
+
+#define CM3232_CMD_ALS_RESET BIT(6)
+
+#define CM3232_CMD_DEFAULT CM3232_CMD_ALS_IT_DEFAULT
+
+#define CM3232_HW_ID 0x32
+#define CM3232_CALIBSCALE_DEFAULT 100000
+#define CM3232_CALIBSCALE_RESOLUTION 100000
+#define CM3232_MLUX_PER_LUX 1000
+
+#define CM3232_MLUX_PER_BIT_DEFAULT 64
+#define CM3232_MLUX_PER_BIT_BASE_IT 100000
+
+static const struct {
+ int val;
+ int val2;
+ u8 it;
+} cm3232_als_it_scales[] = {
+ {0, 100000, 0}, /* 0.100000 */
+ {0, 200000, 1}, /* 0.200000 */
+ {0, 400000, 2}, /* 0.400000 */
+ {0, 800000, 3}, /* 0.800000 */
+ {1, 600000, 4}, /* 1.600000 */
+ {3, 200000, 5}, /* 3.200000 */
+};
+
+struct cm3232_als_info {
+ u8 regs_cmd_default;
+ u8 hw_id;
+ int calibscale;
+ int mlux_per_bit;
+ int mlux_per_bit_base_it;
+};
+
+static struct cm3232_als_info cm3232_als_info_default = {
+ .regs_cmd_default = CM3232_CMD_DEFAULT,
+ .hw_id = CM3232_HW_ID,
+ .calibscale = CM3232_CALIBSCALE_DEFAULT,
+ .mlux_per_bit = CM3232_MLUX_PER_BIT_DEFAULT,
+ .mlux_per_bit_base_it = CM3232_MLUX_PER_BIT_BASE_IT,
+};
+
+struct cm3232_chip {
+ struct i2c_client *client;
+ struct cm3232_als_info *als_info;
+ u8 regs_cmd;
+ u16 regs_als;
+};
+
+/**
+ * cm3232_reg_init() - Initialize CM3232
+ * @chip: pointer of struct cm3232_chip.
+ *
+ * Check and initialize CM3232 ambient light sensor.
+ *
+ * Return: 0 for success; otherwise for error code.
+ */
+static int cm3232_reg_init(struct cm3232_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ s32 ret;
+
+ chip->als_info = &cm3232_als_info_default;
+
+ /* Identify device */
+ ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ID);
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "Error reading addr_id\n");
+ return ret;
+ }
+
+ if ((ret & 0xFF) != chip->als_info->hw_id)
+ return -ENODEV;
+
+ /* Disable and reset device */
+ chip->regs_cmd = CM3232_CMD_ALS_DISABLE | CM3232_CMD_ALS_RESET;
+ ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+ chip->regs_cmd);
+ if (ret < 0) {
+ dev_err(&chip->client->dev, "Error writing reg_cmd\n");
+ return ret;
+ }
+
+ /* Register default value */
+ chip->regs_cmd = chip->als_info->regs_cmd_default;
+
+ /* Configure register */
+ ret = i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+ chip->regs_cmd);
+ if (ret < 0)
+ dev_err(&chip->client->dev, "Error writing reg_cmd\n");
+
+ return 0;
+}
+
+/**
+ * cm3232_read_als_it() - Get sensor integration time
+ * @chip: pointer of struct cm3232_chip
+ * @val: pointer of int to load the integration (sec).
+ * @val2: pointer of int to load the integration time (microsecond).
+ *
+ * Report the current integration time.
+ *
+ * Return: IIO_VAL_INT_PLUS_MICRO for success, otherwise -EINVAL.
+ */
+static int cm3232_read_als_it(struct cm3232_chip *chip, int *val, int *val2)
+{
+ u16 als_it;
+ int i;
+
+ als_it = chip->regs_cmd;
+ als_it &= CM3232_CMD_ALS_IT_MASK;
+ als_it >>= CM3232_CMD_ALS_IT_SHIFT;
+ for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
+ if (als_it == cm3232_als_it_scales[i].it) {
+ *val = cm3232_als_it_scales[i].val;
+ *val2 = cm3232_als_it_scales[i].val2;
+ return IIO_VAL_INT_PLUS_MICRO;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * cm3232_write_als_it() - Write sensor integration time
+ * @chip: pointer of struct cm3232_chip.
+ * @val: integration time in second.
+ * @val2: integration time in microsecond.
+ *
+ * Convert integration time to sensor value.
+ *
+ * Return: i2c_smbus_write_byte_data command return value.
+ */
+static int cm3232_write_als_it(struct cm3232_chip *chip, int val, int val2)
+{
+ struct i2c_client *client = chip->client;
+ u16 als_it, cmd;
+ int i;
+ s32 ret;
+
+ for (i = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++) {
+ if (val == cm3232_als_it_scales[i].val &&
+ val2 == cm3232_als_it_scales[i].val2) {
+
+ als_it = cm3232_als_it_scales[i].it;
+ als_it <<= CM3232_CMD_ALS_IT_SHIFT;
+
+ cmd = chip->regs_cmd & ~CM3232_CMD_ALS_IT_MASK;
+ cmd |= als_it;
+ ret = i2c_smbus_write_byte_data(client,
+ CM3232_REG_ADDR_CMD,
+ cmd);
+ if (ret < 0)
+ return ret;
+ chip->regs_cmd = cmd;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+/**
+ * cm3232_get_lux() - report current lux value
+ * @chip: pointer of struct cm3232_chip.
+ *
+ * Convert sensor data to lux. It depends on integration
+ * time and calibscale variable.
+ *
+ * Return: Zero or positive value is lux, otherwise error code.
+ */
+static int cm3232_get_lux(struct cm3232_chip *chip)
+{
+ struct i2c_client *client = chip->client;
+ struct cm3232_als_info *als_info = chip->als_info;
+ int ret;
+ int val, val2;
+ int als_it;
+ u64 lux;
+
+ /* Calculate mlux per bit based on als_it */
+ ret = cm3232_read_als_it(chip, &val, &val2);
+ if (ret < 0)
+ return -EINVAL;
+ als_it = val * 1000000 + val2;
+ lux = (__force u64)als_info->mlux_per_bit;
+ lux *= als_info->mlux_per_bit_base_it;
+ lux = div_u64(lux, als_it);
+
+ ret = i2c_smbus_read_word_data(client, CM3232_REG_ADDR_ALS);
+ if (ret < 0) {
+ dev_err(&client->dev, "Error reading reg_addr_als\n");
+ return ret;
+ }
+
+ chip->regs_als = (u16)ret;
+ lux *= chip->regs_als;
+ lux *= als_info->calibscale;
+ lux = div_u64(lux, CM3232_CALIBSCALE_RESOLUTION);
+ lux = div_u64(lux, CM3232_MLUX_PER_LUX);
+
+ if (lux > 0xFFFF)
+ lux = 0xFFFF;
+
+ return (int)lux;
+}
+
+static int cm3232_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ struct cm3232_chip *chip = iio_priv(indio_dev);
+ struct cm3232_als_info *als_info = chip->als_info;
+ int ret;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = cm3232_get_lux(chip);
+ if (ret < 0)
+ return ret;
+ *val = ret;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_CALIBSCALE:
+ *val = als_info->calibscale;
+ return IIO_VAL_INT;
+ case IIO_CHAN_INFO_INT_TIME:
+ return cm3232_read_als_it(chip, val, val2);
+ }
+
+ return -EINVAL;
+}
+
+static int cm3232_write_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int val, int val2, long mask)
+{
+ struct cm3232_chip *chip = iio_priv(indio_dev);
+ struct cm3232_als_info *als_info = chip->als_info;
+
+ switch (mask) {
+ case IIO_CHAN_INFO_CALIBSCALE:
+ als_info->calibscale = val;
+ return 0;
+ case IIO_CHAN_INFO_INT_TIME:
+ return cm3232_write_als_it(chip, val, val2);
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * cm3232_get_it_available() - Get available ALS IT value
+ * @dev: pointer of struct device.
+ * @attr: pointer of struct device_attribute.
+ * @buf: pointer of return string buffer.
+ *
+ * Display the available integration time in second.
+ *
+ * Return: string length.
+ */
+static ssize_t cm3232_get_it_available(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ int i, len;
+
+ for (i = 0, len = 0; i < ARRAY_SIZE(cm3232_als_it_scales); i++)
+ len += scnprintf(buf + len, PAGE_SIZE - len, "%u.%06u ",
+ cm3232_als_it_scales[i].val,
+ cm3232_als_it_scales[i].val2);
+ return len + scnprintf(buf + len, PAGE_SIZE - len, "\n");
+}
+
+static const struct iio_chan_spec cm3232_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate =
+ BIT(IIO_CHAN_INFO_PROCESSED) |
+ BIT(IIO_CHAN_INFO_CALIBSCALE) |
+ BIT(IIO_CHAN_INFO_INT_TIME),
+ }
+};
+
+static IIO_DEVICE_ATTR(in_illuminance_integration_time_available,
+ S_IRUGO, cm3232_get_it_available, NULL, 0);
+
+static struct attribute *cm3232_attributes[] = {
+ &iio_dev_attr_in_illuminance_integration_time_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group cm3232_attribute_group = {
+ .attrs = cm3232_attributes
+};
+
+static const struct iio_info cm3232_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &cm3232_read_raw,
+ .write_raw = &cm3232_write_raw,
+ .attrs = &cm3232_attribute_group,
+};
+
+static int cm3232_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct cm3232_chip *chip;
+ struct iio_dev *indio_dev;
+ int ret;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*chip));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ chip = iio_priv(indio_dev);
+ i2c_set_clientdata(client, indio_dev);
+ chip->client = client;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = cm3232_channels;
+ indio_dev->num_channels = ARRAY_SIZE(cm3232_channels);
+ indio_dev->info = &cm3232_info;
+ indio_dev->name = id->name;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ ret = cm3232_reg_init(chip);
+ if (ret) {
+ dev_err(&client->dev,
+ "%s: register init failed\n",
+ __func__);
+ return ret;
+ }
+
+ return iio_device_register(indio_dev);
+}
+
+static int cm3232_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+
+ i2c_smbus_write_byte_data(client, CM3232_REG_ADDR_CMD,
+ CM3232_CMD_ALS_DISABLE);
+
+ iio_device_unregister(indio_dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id cm3232_id[] = {
+ {"cm3232", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(i2c, cm3232_id);
+
+static const struct of_device_id cm3232_of_match[] = {
+ {.compatible = "capella,cm3232"},
+ {}
+};
+
+static struct i2c_driver cm3232_driver = {
+ .driver = {
+ .name = "cm3232",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cm3232_of_match),
+ },
+ .id_table = cm3232_id,
+ .probe = cm3232_probe,
+ .remove = cm3232_remove,
+};
+
+module_i2c_driver(cm3232_driver);
+
+MODULE_AUTHOR("Kevin Tsai <ktsai@capellamicro.com>");
+MODULE_DESCRIPTION("CM3232 ambient light sensor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/light/hid-sensor-als.c b/drivers/iio/light/hid-sensor-als.c
index a5283d75c096..948acfc38b8c 100644
--- a/drivers/iio/light/hid-sensor-als.c
+++ b/drivers/iio/light/hid-sensor-als.c
@@ -80,7 +80,6 @@ static int als_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
@@ -97,15 +96,8 @@ static int als_read_raw(struct iio_dev *indio_dev,
break;
}
if (report_id >= 0) {
- poll_value = hid_sensor_read_poll_value(
- &als_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
-
hid_sensor_power_state(&als_state->common_attributes,
true);
- msleep_interruptible(poll_value * 2);
-
*val = sensor_hub_input_attr_get_raw_value(
als_state->common_attributes.hsdev,
HID_USAGE_SENSOR_ALS, address,
@@ -381,6 +373,7 @@ static struct platform_driver hid_als_platform_driver = {
.id_table = hid_als_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_als_probe,
.remove = hid_als_remove,
diff --git a/drivers/iio/light/hid-sensor-prox.c b/drivers/iio/light/hid-sensor-prox.c
index f5a514698fd8..3ecf79ed08ac 100644
--- a/drivers/iio/light/hid-sensor-prox.c
+++ b/drivers/iio/light/hid-sensor-prox.c
@@ -75,7 +75,6 @@ static int prox_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
@@ -92,16 +91,8 @@ static int prox_read_raw(struct iio_dev *indio_dev,
break;
}
if (report_id >= 0) {
- poll_value = hid_sensor_read_poll_value(
- &prox_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
-
hid_sensor_power_state(&prox_state->common_attributes,
true);
-
- msleep_interruptible(poll_value * 2);
-
*val = sensor_hub_input_attr_get_raw_value(
prox_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PROX, address,
@@ -373,6 +364,7 @@ static struct platform_driver hid_prox_platform_driver = {
.id_table = hid_prox_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_prox_probe,
.remove = hid_prox_remove,
diff --git a/drivers/iio/light/jsa1212.c b/drivers/iio/light/jsa1212.c
new file mode 100644
index 000000000000..29de7e7d9562
--- /dev/null
+++ b/drivers/iio/light/jsa1212.c
@@ -0,0 +1,471 @@
+/*
+ * JSA1212 Ambient Light & Proximity Sensor Driver
+ *
+ * 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.
+ *
+ * JSA1212 I2C slave address: 0x44(ADDR tied to GND), 0x45(ADDR tied to VDD)
+ *
+ * TODO: Interrupt support, thresholds, range support.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include <linux/iio/iio.h>
+#include <linux/iio/sysfs.h>
+
+/* JSA1212 reg address */
+#define JSA1212_CONF_REG 0x01
+#define JSA1212_INT_REG 0x02
+#define JSA1212_PXS_LT_REG 0x03
+#define JSA1212_PXS_HT_REG 0x04
+#define JSA1212_ALS_TH1_REG 0x05
+#define JSA1212_ALS_TH2_REG 0x06
+#define JSA1212_ALS_TH3_REG 0x07
+#define JSA1212_PXS_DATA_REG 0x08
+#define JSA1212_ALS_DT1_REG 0x09
+#define JSA1212_ALS_DT2_REG 0x0A
+#define JSA1212_ALS_RNG_REG 0x0B
+#define JSA1212_MAX_REG 0x0C
+
+/* JSA1212 reg masks */
+#define JSA1212_CONF_MASK 0xFF
+#define JSA1212_INT_MASK 0xFF
+#define JSA1212_PXS_LT_MASK 0xFF
+#define JSA1212_PXS_HT_MASK 0xFF
+#define JSA1212_ALS_TH1_MASK 0xFF
+#define JSA1212_ALS_TH2_LT_MASK 0x0F
+#define JSA1212_ALS_TH2_HT_MASK 0xF0
+#define JSA1212_ALS_TH3_MASK 0xFF
+#define JSA1212_PXS_DATA_MASK 0xFF
+#define JSA1212_ALS_DATA_MASK 0x0FFF
+#define JSA1212_ALS_DT1_MASK 0xFF
+#define JSA1212_ALS_DT2_MASK 0x0F
+#define JSA1212_ALS_RNG_MASK 0x07
+
+/* JSA1212 CONF REG bits */
+#define JSA1212_CONF_PXS_MASK 0x80
+#define JSA1212_CONF_PXS_ENABLE 0x80
+#define JSA1212_CONF_PXS_DISABLE 0x00
+#define JSA1212_CONF_ALS_MASK 0x04
+#define JSA1212_CONF_ALS_ENABLE 0x04
+#define JSA1212_CONF_ALS_DISABLE 0x00
+#define JSA1212_CONF_IRDR_MASK 0x08
+/* Proxmity sensing IRDR current sink settings */
+#define JSA1212_CONF_IRDR_200MA 0x08
+#define JSA1212_CONF_IRDR_100MA 0x00
+#define JSA1212_CONF_PXS_SLP_MASK 0x70
+#define JSA1212_CONF_PXS_SLP_0MS 0x70
+#define JSA1212_CONF_PXS_SLP_12MS 0x60
+#define JSA1212_CONF_PXS_SLP_50MS 0x50
+#define JSA1212_CONF_PXS_SLP_75MS 0x40
+#define JSA1212_CONF_PXS_SLP_100MS 0x30
+#define JSA1212_CONF_PXS_SLP_200MS 0x20
+#define JSA1212_CONF_PXS_SLP_400MS 0x10
+#define JSA1212_CONF_PXS_SLP_800MS 0x00
+
+/* JSA1212 INT REG bits */
+#define JSA1212_INT_CTRL_MASK 0x01
+#define JSA1212_INT_CTRL_EITHER 0x00
+#define JSA1212_INT_CTRL_BOTH 0x01
+#define JSA1212_INT_ALS_PRST_MASK 0x06
+#define JSA1212_INT_ALS_PRST_1CONV 0x00
+#define JSA1212_INT_ALS_PRST_4CONV 0x02
+#define JSA1212_INT_ALS_PRST_8CONV 0x04
+#define JSA1212_INT_ALS_PRST_16CONV 0x06
+#define JSA1212_INT_ALS_FLAG_MASK 0x08
+#define JSA1212_INT_ALS_FLAG_CLR 0x00
+#define JSA1212_INT_PXS_PRST_MASK 0x60
+#define JSA1212_INT_PXS_PRST_1CONV 0x00
+#define JSA1212_INT_PXS_PRST_4CONV 0x20
+#define JSA1212_INT_PXS_PRST_8CONV 0x40
+#define JSA1212_INT_PXS_PRST_16CONV 0x60
+#define JSA1212_INT_PXS_FLAG_MASK 0x80
+#define JSA1212_INT_PXS_FLAG_CLR 0x00
+
+/* JSA1212 ALS RNG REG bits */
+#define JSA1212_ALS_RNG_0_2048 0x00
+#define JSA1212_ALS_RNG_0_1024 0x01
+#define JSA1212_ALS_RNG_0_512 0x02
+#define JSA1212_ALS_RNG_0_256 0x03
+#define JSA1212_ALS_RNG_0_128 0x04
+
+/* JSA1212 INT threshold range */
+#define JSA1212_ALS_TH_MIN 0x0000
+#define JSA1212_ALS_TH_MAX 0x0FFF
+#define JSA1212_PXS_TH_MIN 0x00
+#define JSA1212_PXS_TH_MAX 0xFF
+
+#define JSA1212_ALS_DELAY_MS 200
+#define JSA1212_PXS_DELAY_MS 100
+
+#define JSA1212_DRIVER_NAME "jsa1212"
+#define JSA1212_REGMAP_NAME "jsa1212_regmap"
+
+enum jsa1212_op_mode {
+ JSA1212_OPMODE_ALS_EN,
+ JSA1212_OPMODE_PXS_EN,
+};
+
+struct jsa1212_data {
+ struct i2c_client *client;
+ struct mutex lock;
+ u8 als_rng_idx;
+ bool als_en; /* ALS enable status */
+ bool pxs_en; /* proximity enable status */
+ struct regmap *regmap;
+};
+
+/* ALS range idx to val mapping */
+static const int jsa1212_als_range_val[] = {2048, 1024, 512, 256, 128,
+ 128, 128, 128};
+
+/* Enables or disables ALS function based on status */
+static int jsa1212_als_enable(struct jsa1212_data *data, u8 status)
+{
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
+ JSA1212_CONF_ALS_MASK,
+ status);
+ if (ret < 0)
+ return ret;
+
+ data->als_en = !!status;
+
+ return 0;
+}
+
+/* Enables or disables PXS function based on status */
+static int jsa1212_pxs_enable(struct jsa1212_data *data, u8 status)
+{
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
+ JSA1212_CONF_PXS_MASK,
+ status);
+ if (ret < 0)
+ return ret;
+
+ data->pxs_en = !!status;
+
+ return 0;
+}
+
+static int jsa1212_read_als_data(struct jsa1212_data *data,
+ unsigned int *val)
+{
+ int ret;
+ __le16 als_data;
+
+ ret = jsa1212_als_enable(data, JSA1212_CONF_ALS_ENABLE);
+ if (ret < 0)
+ return ret;
+
+ /* Delay for data output */
+ msleep(JSA1212_ALS_DELAY_MS);
+
+ /* Read 12 bit data */
+ ret = regmap_bulk_read(data->regmap, JSA1212_ALS_DT1_REG, &als_data, 2);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "als data read err\n");
+ goto als_data_read_err;
+ }
+
+ *val = le16_to_cpu(als_data);
+
+als_data_read_err:
+ return jsa1212_als_enable(data, JSA1212_CONF_ALS_DISABLE);
+}
+
+static int jsa1212_read_pxs_data(struct jsa1212_data *data,
+ unsigned int *val)
+{
+ int ret;
+ unsigned int pxs_data;
+
+ ret = jsa1212_pxs_enable(data, JSA1212_CONF_PXS_ENABLE);
+ if (ret < 0)
+ return ret;
+
+ /* Delay for data output */
+ msleep(JSA1212_PXS_DELAY_MS);
+
+ /* Read out all data */
+ ret = regmap_read(data->regmap, JSA1212_PXS_DATA_REG, &pxs_data);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "pxs data read err\n");
+ goto pxs_data_read_err;
+ }
+
+ *val = pxs_data & JSA1212_PXS_DATA_MASK;
+
+pxs_data_read_err:
+ return jsa1212_pxs_enable(data, JSA1212_CONF_PXS_DISABLE);
+}
+
+static int jsa1212_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+ struct jsa1212_data *data = iio_priv(indio_dev);
+
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ mutex_lock(&data->lock);
+ switch (chan->type) {
+ case IIO_LIGHT:
+ ret = jsa1212_read_als_data(data, val);
+ break;
+ case IIO_PROXIMITY:
+ ret = jsa1212_read_pxs_data(data, val);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ mutex_unlock(&data->lock);
+ return ret < 0 ? ret : IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ switch (chan->type) {
+ case IIO_LIGHT:
+ *val = jsa1212_als_range_val[data->als_rng_idx];
+ *val2 = BIT(12); /* Max 12 bit value */
+ return IIO_VAL_FRACTIONAL;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static const struct iio_chan_spec jsa1212_channels[] = {
+ {
+ .type = IIO_LIGHT,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
+ },
+ {
+ .type = IIO_PROXIMITY,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ }
+};
+
+static const struct iio_info jsa1212_info = {
+ .driver_module = THIS_MODULE,
+ .read_raw = &jsa1212_read_raw,
+};
+
+static int jsa1212_chip_init(struct jsa1212_data *data)
+{
+ int ret;
+
+ ret = regmap_write(data->regmap, JSA1212_CONF_REG,
+ (JSA1212_CONF_PXS_SLP_50MS |
+ JSA1212_CONF_IRDR_200MA));
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(data->regmap, JSA1212_INT_REG,
+ JSA1212_INT_ALS_PRST_4CONV);
+ if (ret < 0)
+ return ret;
+
+ data->als_rng_idx = JSA1212_ALS_RNG_0_2048;
+
+ return 0;
+}
+
+static bool jsa1212_is_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case JSA1212_PXS_DATA_REG:
+ case JSA1212_ALS_DT1_REG:
+ case JSA1212_ALS_DT2_REG:
+ case JSA1212_INT_REG:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static struct regmap_config jsa1212_regmap_config = {
+ .name = JSA1212_REGMAP_NAME,
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = JSA1212_MAX_REG,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = jsa1212_is_volatile_reg,
+};
+
+static int jsa1212_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct jsa1212_data *data;
+ struct iio_dev *indio_dev;
+ struct regmap *regmap;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -ENODEV;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ regmap = devm_regmap_init_i2c(client, &jsa1212_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(&client->dev, "Regmap initialization failed.\n");
+ return PTR_ERR(regmap);
+ }
+
+ data = iio_priv(indio_dev);
+
+ i2c_set_clientdata(client, indio_dev);
+ data->client = client;
+ data->regmap = regmap;
+
+ mutex_init(&data->lock);
+
+ ret = jsa1212_chip_init(data);
+ if (ret < 0)
+ return ret;
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->channels = jsa1212_channels;
+ indio_dev->num_channels = ARRAY_SIZE(jsa1212_channels);
+ indio_dev->name = JSA1212_DRIVER_NAME;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+
+ indio_dev->info = &jsa1212_info;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ dev_err(&client->dev, "%s: register device failed\n", __func__);
+
+ return ret;
+}
+
+ /* power off the device */
+static int jsa1212_power_off(struct jsa1212_data *data)
+{
+ int ret;
+
+ mutex_lock(&data->lock);
+
+ ret = regmap_update_bits(data->regmap, JSA1212_CONF_REG,
+ JSA1212_CONF_ALS_MASK |
+ JSA1212_CONF_PXS_MASK,
+ JSA1212_CONF_ALS_DISABLE |
+ JSA1212_CONF_PXS_DISABLE);
+
+ if (ret < 0)
+ dev_err(&data->client->dev, "power off cmd failed\n");
+
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int jsa1212_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct jsa1212_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+
+ return jsa1212_power_off(data);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int jsa1212_suspend(struct device *dev)
+{
+ struct jsa1212_data *data;
+
+ data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+ return jsa1212_power_off(data);
+}
+
+static int jsa1212_resume(struct device *dev)
+{
+ int ret = 0;
+ struct jsa1212_data *data;
+
+ data = iio_priv(i2c_get_clientdata(to_i2c_client(dev)));
+
+ mutex_lock(&data->lock);
+
+ if (data->als_en) {
+ ret = jsa1212_als_enable(data, JSA1212_CONF_ALS_ENABLE);
+ if (ret < 0) {
+ dev_err(dev, "als resume failed\n");
+ goto unlock_and_ret;
+ }
+ }
+
+ if (data->pxs_en) {
+ ret = jsa1212_pxs_enable(data, JSA1212_CONF_PXS_ENABLE);
+ if (ret < 0)
+ dev_err(dev, "pxs resume failed\n");
+ }
+
+unlock_and_ret:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
+static SIMPLE_DEV_PM_OPS(jsa1212_pm_ops, jsa1212_suspend, jsa1212_resume);
+
+#define JSA1212_PM_OPS (&jsa1212_pm_ops)
+#else
+#define JSA1212_PM_OPS NULL
+#endif
+
+static const struct acpi_device_id jsa1212_acpi_match[] = {
+ {"JSA1212", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, jsa1212_acpi_match);
+
+static const struct i2c_device_id jsa1212_id[] = {
+ { JSA1212_DRIVER_NAME, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, jsa1212_id);
+
+static struct i2c_driver jsa1212_driver = {
+ .driver = {
+ .name = JSA1212_DRIVER_NAME,
+ .pm = JSA1212_PM_OPS,
+ .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(jsa1212_acpi_match),
+ },
+ .probe = jsa1212_probe,
+ .remove = jsa1212_remove,
+ .id_table = jsa1212_id,
+};
+module_i2c_driver(jsa1212_driver);
+
+MODULE_AUTHOR("Sathya Kuppuswamy <sathyanarayanan.kuppuswamy@linux.intel.com>");
+MODULE_DESCRIPTION("JSA1212 proximity/ambient light sensor driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/light/lm3533-als.c b/drivers/iio/light/lm3533-als.c
index ae3c71bdd6c6..076bc46fad03 100644
--- a/drivers/iio/light/lm3533-als.c
+++ b/drivers/iio/light/lm3533-als.c
@@ -657,7 +657,7 @@ static ALS_HYSTERESIS_ATTR_RO(3);
#define ILLUMINANCE_ATTR_RO(_name) \
DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO, show_##_name, NULL)
#define ILLUMINANCE_ATTR_RW(_name) \
- DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR , \
+ DEVICE_ATTR(in_illuminance0_##_name, S_IRUGO | S_IWUSR, \
show_##_name, store_##_name)
/*
* ALS Zone threshold-event enable
diff --git a/drivers/iio/light/tcs3414.c b/drivers/iio/light/tcs3414.c
index a9e449b0be0c..71c2bde275aa 100644
--- a/drivers/iio/light/tcs3414.c
+++ b/drivers/iio/light/tcs3414.c
@@ -149,8 +149,8 @@ static int tcs3414_read_raw(struct iio_dev *indio_dev,
*val = ret;
return IIO_VAL_INT;
case IIO_CHAN_INFO_SCALE:
- i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
- *val = tcs3414_scales[i][0];
+ i = (data->gain & TCS3414_GAIN_MASK) >> TCS3414_GAIN_SHIFT;
+ *val = tcs3414_scales[i][0];
*val2 = tcs3414_scales[i][1];
return IIO_VAL_INT_PLUS_MICRO;
case IIO_CHAN_INFO_INT_TIME:
diff --git a/drivers/iio/magnetometer/Kconfig b/drivers/iio/magnetometer/Kconfig
index b2dba9e506ab..4c7a4c52dd06 100644
--- a/drivers/iio/magnetometer/Kconfig
+++ b/drivers/iio/magnetometer/Kconfig
@@ -6,26 +6,21 @@
menu "Magnetometer sensors"
config AK8975
- tristate "Asahi Kasei AK8975 3-Axis Magnetometer"
+ tristate "Asahi Kasei AK 3-Axis Magnetometer"
depends on I2C
depends on GPIOLIB
help
- Say yes here to build support for Asahi Kasei AK8975 3-Axis
- Magnetometer. This driver can also support AK8963, if i2c
- device name is identified as ak8963.
+ Say yes here to build support for Asahi Kasei AK8975, AK8963,
+ AK09911 or AK09912 3-Axis Magnetometer.
To compile this driver as a module, choose M here: the module
will be called ak8975.
config AK09911
tristate "Asahi Kasei AK09911 3-axis Compass"
- depends on I2C
+ select AK8975
help
- Say yes here to build support for Asahi Kasei AK09911 3-Axis
- Magnetometer.
-
- To compile this driver as a module, choose M here: the module
- will be called ak09911.
+ Deprecated: AK09911 is now supported by AK8975 driver.
config MAG3110
tristate "Freescale MAG3110 3-Axis Magnetometer"
diff --git a/drivers/iio/magnetometer/Makefile b/drivers/iio/magnetometer/Makefile
index b91315e0b826..0f5d3c985799 100644
--- a/drivers/iio/magnetometer/Makefile
+++ b/drivers/iio/magnetometer/Makefile
@@ -3,7 +3,6 @@
#
# When adding new entries keep the list in alphabetical order
-obj-$(CONFIG_AK09911) += ak09911.o
obj-$(CONFIG_AK8975) += ak8975.o
obj-$(CONFIG_MAG3110) += mag3110.o
obj-$(CONFIG_HID_SENSOR_MAGNETOMETER_3D) += hid-sensor-magn-3d.o
diff --git a/drivers/iio/magnetometer/ak09911.c b/drivers/iio/magnetometer/ak09911.c
deleted file mode 100644
index b2bc942ff6b8..000000000000
--- a/drivers/iio/magnetometer/ak09911.c
+++ /dev/null
@@ -1,326 +0,0 @@
-/*
- * AK09911 3-axis compass driver
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <linux/acpi.h>
-#include <linux/iio/iio.h>
-
-#define AK09911_REG_WIA1 0x00
-#define AK09911_REG_WIA2 0x01
-#define AK09911_WIA1_VALUE 0x48
-#define AK09911_WIA2_VALUE 0x05
-
-#define AK09911_REG_ST1 0x10
-#define AK09911_REG_HXL 0x11
-#define AK09911_REG_HXH 0x12
-#define AK09911_REG_HYL 0x13
-#define AK09911_REG_HYH 0x14
-#define AK09911_REG_HZL 0x15
-#define AK09911_REG_HZH 0x16
-
-#define AK09911_REG_ASAX 0x60
-#define AK09911_REG_ASAY 0x61
-#define AK09911_REG_ASAZ 0x62
-
-#define AK09911_REG_CNTL1 0x30
-#define AK09911_REG_CNTL2 0x31
-#define AK09911_REG_CNTL3 0x32
-
-#define AK09911_MODE_SNG_MEASURE 0x01
-#define AK09911_MODE_SELF_TEST 0x10
-#define AK09911_MODE_FUSE_ACCESS 0x1F
-#define AK09911_MODE_POWERDOWN 0x00
-#define AK09911_RESET_DATA 0x01
-
-#define AK09911_REG_CNTL1 0x30
-#define AK09911_REG_CNTL2 0x31
-#define AK09911_REG_CNTL3 0x32
-
-#define AK09911_RAW_TO_GAUSS(asa) ((((asa) + 128) * 6000) / 256)
-
-#define AK09911_MAX_CONVERSION_TIMEOUT_MS 500
-#define AK09911_CONVERSION_DONE_POLL_TIME_MS 10
-
-struct ak09911_data {
- struct i2c_client *client;
- struct mutex lock;
- u8 asa[3];
- long raw_to_gauss[3];
-};
-
-static const int ak09911_index_to_reg[] = {
- AK09911_REG_HXL, AK09911_REG_HYL, AK09911_REG_HZL,
-};
-
-static int ak09911_set_mode(struct i2c_client *client, u8 mode)
-{
- int ret;
-
- switch (mode) {
- case AK09911_MODE_SNG_MEASURE:
- case AK09911_MODE_SELF_TEST:
- case AK09911_MODE_FUSE_ACCESS:
- case AK09911_MODE_POWERDOWN:
- ret = i2c_smbus_write_byte_data(client,
- AK09911_REG_CNTL2, mode);
- if (ret < 0) {
- dev_err(&client->dev, "set_mode error\n");
- return ret;
- }
- /* After mode change wait atleast 100us */
- usleep_range(100, 500);
- break;
- default:
- dev_err(&client->dev,
- "%s: Unknown mode(%d).", __func__, mode);
- return -EINVAL;
- }
-
- return ret;
-}
-
-/* Get Sensitivity Adjustment value */
-static int ak09911_get_asa(struct i2c_client *client)
-{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ak09911_data *data = iio_priv(indio_dev);
- int ret;
-
- ret = ak09911_set_mode(client, AK09911_MODE_FUSE_ACCESS);
- if (ret < 0)
- return ret;
-
- /* Get asa data and store in the device data. */
- ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_ASAX,
- 3, data->asa);
- if (ret < 0) {
- dev_err(&client->dev, "Not able to read asa data\n");
- return ret;
- }
-
- ret = ak09911_set_mode(client, AK09911_MODE_POWERDOWN);
- if (ret < 0)
- return ret;
-
- data->raw_to_gauss[0] = AK09911_RAW_TO_GAUSS(data->asa[0]);
- data->raw_to_gauss[1] = AK09911_RAW_TO_GAUSS(data->asa[1]);
- data->raw_to_gauss[2] = AK09911_RAW_TO_GAUSS(data->asa[2]);
-
- return 0;
-}
-
-static int ak09911_verify_chip_id(struct i2c_client *client)
-{
- u8 wia_val[2];
- int ret;
-
- ret = i2c_smbus_read_i2c_block_data(client, AK09911_REG_WIA1,
- 2, wia_val);
- if (ret < 0) {
- dev_err(&client->dev, "Error reading WIA\n");
- return ret;
- }
-
- dev_dbg(&client->dev, "WIA %02x %02x\n", wia_val[0], wia_val[1]);
-
- if (wia_val[0] != AK09911_WIA1_VALUE ||
- wia_val[1] != AK09911_WIA2_VALUE) {
- dev_err(&client->dev, "Device ak09911 not found\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int wait_conversion_complete_polled(struct ak09911_data *data)
-{
- struct i2c_client *client = data->client;
- u8 read_status;
- u32 timeout_ms = AK09911_MAX_CONVERSION_TIMEOUT_MS;
- int ret;
-
- /* Wait for the conversion to complete. */
- while (timeout_ms) {
- msleep_interruptible(AK09911_CONVERSION_DONE_POLL_TIME_MS);
- ret = i2c_smbus_read_byte_data(client, AK09911_REG_ST1);
- if (ret < 0) {
- dev_err(&client->dev, "Error in reading ST1\n");
- return ret;
- }
- read_status = ret & 0x01;
- if (read_status)
- break;
- timeout_ms -= AK09911_CONVERSION_DONE_POLL_TIME_MS;
- }
- if (!timeout_ms) {
- dev_err(&client->dev, "Conversion timeout happened\n");
- return -EIO;
- }
-
- return read_status;
-}
-
-static int ak09911_read_axis(struct iio_dev *indio_dev, int index, int *val)
-{
- struct ak09911_data *data = iio_priv(indio_dev);
- struct i2c_client *client = data->client;
- int ret;
-
- mutex_lock(&data->lock);
-
- ret = ak09911_set_mode(client, AK09911_MODE_SNG_MEASURE);
- if (ret < 0)
- goto fn_exit;
-
- ret = wait_conversion_complete_polled(data);
- if (ret < 0)
- goto fn_exit;
-
- /* Read data */
- ret = i2c_smbus_read_word_data(client, ak09911_index_to_reg[index]);
- if (ret < 0) {
- dev_err(&client->dev, "Read axis data fails\n");
- goto fn_exit;
- }
-
- mutex_unlock(&data->lock);
-
- /* Clamp to valid range. */
- *val = sign_extend32(clamp_t(s16, ret, -8192, 8191), 13);
-
- return IIO_VAL_INT;
-
-fn_exit:
- mutex_unlock(&data->lock);
-
- return ret;
-}
-
-static int ak09911_read_raw(struct iio_dev *indio_dev,
- struct iio_chan_spec const *chan,
- int *val, int *val2,
- long mask)
-{
- struct ak09911_data *data = iio_priv(indio_dev);
-
- switch (mask) {
- case IIO_CHAN_INFO_RAW:
- return ak09911_read_axis(indio_dev, chan->address, val);
- case IIO_CHAN_INFO_SCALE:
- *val = 0;
- *val2 = data->raw_to_gauss[chan->address];
- return IIO_VAL_INT_PLUS_MICRO;
- }
-
- return -EINVAL;
-}
-
-#define AK09911_CHANNEL(axis, index) \
- { \
- .type = IIO_MAGN, \
- .modified = 1, \
- .channel2 = IIO_MOD_##axis, \
- .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) | \
- BIT(IIO_CHAN_INFO_SCALE), \
- .address = index, \
- }
-
-static const struct iio_chan_spec ak09911_channels[] = {
- AK09911_CHANNEL(X, 0), AK09911_CHANNEL(Y, 1), AK09911_CHANNEL(Z, 2),
-};
-
-static const struct iio_info ak09911_info = {
- .read_raw = &ak09911_read_raw,
- .driver_module = THIS_MODULE,
-};
-
-static const struct acpi_device_id ak_acpi_match[] = {
- {"AK009911", 0},
- { },
-};
-MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
-
-static int ak09911_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct iio_dev *indio_dev;
- struct ak09911_data *data;
- const char *name;
- int ret;
-
- ret = ak09911_verify_chip_id(client);
- if (ret) {
- dev_err(&client->dev, "AK00911 not detected\n");
- return -ENODEV;
- }
-
- indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
- if (indio_dev == NULL)
- return -ENOMEM;
-
- data = iio_priv(indio_dev);
- i2c_set_clientdata(client, indio_dev);
-
- data->client = client;
- mutex_init(&data->lock);
-
- ret = ak09911_get_asa(client);
- if (ret)
- return ret;
-
- if (id)
- name = id->name;
- else if (ACPI_HANDLE(&client->dev))
- name = dev_name(&client->dev);
- else
- return -ENODEV;
-
- dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
-
- indio_dev->dev.parent = &client->dev;
- indio_dev->channels = ak09911_channels;
- indio_dev->num_channels = ARRAY_SIZE(ak09911_channels);
- indio_dev->info = &ak09911_info;
- indio_dev->modes = INDIO_DIRECT_MODE;
- indio_dev->name = name;
-
- return devm_iio_device_register(&client->dev, indio_dev);
-}
-
-static const struct i2c_device_id ak09911_id[] = {
- {"ak09911", 0},
- {}
-};
-
-MODULE_DEVICE_TABLE(i2c, ak09911_id);
-
-static struct i2c_driver ak09911_driver = {
- .driver = {
- .name = "ak09911",
- .acpi_match_table = ACPI_PTR(ak_acpi_match),
- },
- .probe = ak09911_probe,
- .id_table = ak09911_id,
-};
-module_i2c_driver(ak09911_driver);
-
-MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_DESCRIPTION("AK09911 Compass driver");
diff --git a/drivers/iio/magnetometer/ak8975.c b/drivers/iio/magnetometer/ak8975.c
index bf5ef077e791..b13936dacc78 100644
--- a/drivers/iio/magnetometer/ak8975.c
+++ b/drivers/iio/magnetometer/ak8975.c
@@ -64,10 +64,10 @@
#define AK8975_REG_CNTL 0x0A
#define AK8975_REG_CNTL_MODE_SHIFT 0
#define AK8975_REG_CNTL_MODE_MASK (0xF << AK8975_REG_CNTL_MODE_SHIFT)
-#define AK8975_REG_CNTL_MODE_POWER_DOWN 0
-#define AK8975_REG_CNTL_MODE_ONCE 1
-#define AK8975_REG_CNTL_MODE_SELF_TEST 8
-#define AK8975_REG_CNTL_MODE_FUSE_ROM 0xF
+#define AK8975_REG_CNTL_MODE_POWER_DOWN 0x00
+#define AK8975_REG_CNTL_MODE_ONCE 0x01
+#define AK8975_REG_CNTL_MODE_SELF_TEST 0x08
+#define AK8975_REG_CNTL_MODE_FUSE_ROM 0x0F
#define AK8975_REG_RSVC 0x0B
#define AK8975_REG_ASTC 0x0C
@@ -81,18 +81,278 @@
#define AK8975_MAX_REGS AK8975_REG_ASAZ
/*
+ * AK09912 Register definitions
+ */
+#define AK09912_REG_WIA1 0x00
+#define AK09912_REG_WIA2 0x01
+#define AK09912_DEVICE_ID 0x04
+#define AK09911_DEVICE_ID 0x05
+
+#define AK09911_REG_INFO1 0x02
+#define AK09911_REG_INFO2 0x03
+
+#define AK09912_REG_ST1 0x10
+
+#define AK09912_REG_ST1_DRDY_SHIFT 0
+#define AK09912_REG_ST1_DRDY_MASK (1 << AK09912_REG_ST1_DRDY_SHIFT)
+
+#define AK09912_REG_HXL 0x11
+#define AK09912_REG_HXH 0x12
+#define AK09912_REG_HYL 0x13
+#define AK09912_REG_HYH 0x14
+#define AK09912_REG_HZL 0x15
+#define AK09912_REG_HZH 0x16
+#define AK09912_REG_TMPS 0x17
+
+#define AK09912_REG_ST2 0x18
+#define AK09912_REG_ST2_HOFL_SHIFT 3
+#define AK09912_REG_ST2_HOFL_MASK (1 << AK09912_REG_ST2_HOFL_SHIFT)
+
+#define AK09912_REG_CNTL1 0x30
+
+#define AK09912_REG_CNTL2 0x31
+#define AK09912_REG_CNTL_MODE_POWER_DOWN 0x00
+#define AK09912_REG_CNTL_MODE_ONCE 0x01
+#define AK09912_REG_CNTL_MODE_SELF_TEST 0x10
+#define AK09912_REG_CNTL_MODE_FUSE_ROM 0x1F
+#define AK09912_REG_CNTL2_MODE_SHIFT 0
+#define AK09912_REG_CNTL2_MODE_MASK (0x1F << AK09912_REG_CNTL2_MODE_SHIFT)
+
+#define AK09912_REG_CNTL3 0x32
+
+#define AK09912_REG_TS1 0x33
+#define AK09912_REG_TS2 0x34
+#define AK09912_REG_TS3 0x35
+#define AK09912_REG_I2CDIS 0x36
+#define AK09912_REG_TS4 0x37
+
+#define AK09912_REG_ASAX 0x60
+#define AK09912_REG_ASAY 0x61
+#define AK09912_REG_ASAZ 0x62
+
+#define AK09912_MAX_REGS AK09912_REG_ASAZ
+
+/*
* Miscellaneous values.
*/
#define AK8975_MAX_CONVERSION_TIMEOUT 500
#define AK8975_CONVERSION_DONE_POLL_TIME 10
#define AK8975_DATA_READY_TIMEOUT ((100*HZ)/1000)
-#define RAW_TO_GAUSS_8975(asa) ((((asa) + 128) * 3000) / 256)
-#define RAW_TO_GAUSS_8963(asa) ((((asa) + 128) * 6000) / 256)
+
+/*
+ * Precalculate scale factor (in Gauss units) for each axis and
+ * store in the device data.
+ *
+ * This scale factor is axis-dependent, and is derived from 3 calibration
+ * factors ASA(x), ASA(y), and ASA(z).
+ *
+ * These ASA values are read from the sensor device at start of day, and
+ * cached in the device context struct.
+ *
+ * Adjusting the flux value with the sensitivity adjustment value should be
+ * done via the following formula:
+ *
+ * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
+ * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
+ * is the resultant adjusted value.
+ *
+ * We reduce the formula to:
+ *
+ * Hadj = H * (ASA + 128) / 256
+ *
+ * H is in the range of -4096 to 4095. The magnetometer has a range of
+ * +-1229uT. To go from the raw value to uT is:
+ *
+ * HuT = H * 1229/4096, or roughly, 3/10.
+ *
+ * Since 1uT = 0.01 gauss, our final scale factor becomes:
+ *
+ * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
+ * Hadj = H * ((ASA + 128) * 0.003) / 256
+ *
+ * Since ASA doesn't change, we cache the resultant scale factor into the
+ * device context in ak8975_setup().
+ *
+ * Given we use IIO_VAL_INT_PLUS_MICRO bit when displaying the scale, we
+ * multiply the stored scale value by 1e6.
+ */
+static long ak8975_raw_to_gauss(u16 data)
+{
+ return (((long)data + 128) * 3000) / 256;
+}
+
+/*
+ * For AK8963 and AK09911, same calculation, but the device is less sensitive:
+ *
+ * H is in the range of +-8190. The magnetometer has a range of
+ * +-4912uT. To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/8190, or roughly, 6/10, instead of 3/10.
+ */
+
+static long ak8963_09911_raw_to_gauss(u16 data)
+{
+ return (((long)data + 128) * 6000) / 256;
+}
+
+/*
+ * For AK09912, same calculation, except the device is more sensitive:
+ *
+ * H is in the range of -32752 to 32752. The magnetometer has a range of
+ * +-4912uT. To go from the raw value to uT is:
+ *
+ * HuT = H * 4912/32752, or roughly, 3/20, instead of 3/10.
+ */
+static long ak09912_raw_to_gauss(u16 data)
+{
+ return (((long)data + 128) * 1500) / 256;
+}
/* Compatible Asahi Kasei Compass parts */
enum asahi_compass_chipset {
AK8975,
AK8963,
+ AK09911,
+ AK09912,
+ AK_MAX_TYPE
+};
+
+enum ak_ctrl_reg_addr {
+ ST1,
+ ST2,
+ CNTL,
+ ASA_BASE,
+ MAX_REGS,
+ REGS_END,
+};
+
+enum ak_ctrl_reg_mask {
+ ST1_DRDY,
+ ST2_HOFL,
+ ST2_DERR,
+ CNTL_MODE,
+ MASK_END,
+};
+
+enum ak_ctrl_mode {
+ POWER_DOWN,
+ MODE_ONCE,
+ SELF_TEST,
+ FUSE_ROM,
+ MODE_END,
+};
+
+struct ak_def {
+ enum asahi_compass_chipset type;
+ long (*raw_to_gauss)(u16 data);
+ u16 range;
+ u8 ctrl_regs[REGS_END];
+ u8 ctrl_masks[MASK_END];
+ u8 ctrl_modes[MODE_END];
+ u8 data_regs[3];
+};
+
+static struct ak_def ak_def_array[AK_MAX_TYPE] = {
+ {
+ .type = AK8975,
+ .raw_to_gauss = ak8975_raw_to_gauss,
+ .range = 4096,
+ .ctrl_regs = {
+ AK8975_REG_ST1,
+ AK8975_REG_ST2,
+ AK8975_REG_CNTL,
+ AK8975_REG_ASAX,
+ AK8975_MAX_REGS},
+ .ctrl_masks = {
+ AK8975_REG_ST1_DRDY_MASK,
+ AK8975_REG_ST2_HOFL_MASK,
+ AK8975_REG_ST2_DERR_MASK,
+ AK8975_REG_CNTL_MODE_MASK},
+ .ctrl_modes = {
+ AK8975_REG_CNTL_MODE_POWER_DOWN,
+ AK8975_REG_CNTL_MODE_ONCE,
+ AK8975_REG_CNTL_MODE_SELF_TEST,
+ AK8975_REG_CNTL_MODE_FUSE_ROM},
+ .data_regs = {
+ AK8975_REG_HXL,
+ AK8975_REG_HYL,
+ AK8975_REG_HZL},
+ },
+ {
+ .type = AK8963,
+ .raw_to_gauss = ak8963_09911_raw_to_gauss,
+ .range = 8190,
+ .ctrl_regs = {
+ AK8975_REG_ST1,
+ AK8975_REG_ST2,
+ AK8975_REG_CNTL,
+ AK8975_REG_ASAX,
+ AK8975_MAX_REGS},
+ .ctrl_masks = {
+ AK8975_REG_ST1_DRDY_MASK,
+ AK8975_REG_ST2_HOFL_MASK,
+ 0,
+ AK8975_REG_CNTL_MODE_MASK},
+ .ctrl_modes = {
+ AK8975_REG_CNTL_MODE_POWER_DOWN,
+ AK8975_REG_CNTL_MODE_ONCE,
+ AK8975_REG_CNTL_MODE_SELF_TEST,
+ AK8975_REG_CNTL_MODE_FUSE_ROM},
+ .data_regs = {
+ AK8975_REG_HXL,
+ AK8975_REG_HYL,
+ AK8975_REG_HZL},
+ },
+ {
+ .type = AK09911,
+ .raw_to_gauss = ak8963_09911_raw_to_gauss,
+ .range = 8192,
+ .ctrl_regs = {
+ AK09912_REG_ST1,
+ AK09912_REG_ST2,
+ AK09912_REG_CNTL2,
+ AK09912_REG_ASAX,
+ AK09912_MAX_REGS},
+ .ctrl_masks = {
+ AK09912_REG_ST1_DRDY_MASK,
+ AK09912_REG_ST2_HOFL_MASK,
+ 0,
+ AK09912_REG_CNTL2_MODE_MASK},
+ .ctrl_modes = {
+ AK09912_REG_CNTL_MODE_POWER_DOWN,
+ AK09912_REG_CNTL_MODE_ONCE,
+ AK09912_REG_CNTL_MODE_SELF_TEST,
+ AK09912_REG_CNTL_MODE_FUSE_ROM},
+ .data_regs = {
+ AK09912_REG_HXL,
+ AK09912_REG_HYL,
+ AK09912_REG_HZL},
+ },
+ {
+ .type = AK09912,
+ .raw_to_gauss = ak09912_raw_to_gauss,
+ .range = 32752,
+ .ctrl_regs = {
+ AK09912_REG_ST1,
+ AK09912_REG_ST2,
+ AK09912_REG_CNTL2,
+ AK09912_REG_ASAX,
+ AK09912_MAX_REGS},
+ .ctrl_masks = {
+ AK09912_REG_ST1_DRDY_MASK,
+ AK09912_REG_ST2_HOFL_MASK,
+ 0,
+ AK09912_REG_CNTL2_MODE_MASK},
+ .ctrl_modes = {
+ AK09912_REG_CNTL_MODE_POWER_DOWN,
+ AK09912_REG_CNTL_MODE_ONCE,
+ AK09912_REG_CNTL_MODE_SELF_TEST,
+ AK09912_REG_CNTL_MODE_FUSE_ROM},
+ .data_regs = {
+ AK09912_REG_HXL,
+ AK09912_REG_HYL,
+ AK09912_REG_HZL},
+ }
};
/*
@@ -100,40 +360,82 @@ enum asahi_compass_chipset {
*/
struct ak8975_data {
struct i2c_client *client;
+ struct ak_def *def;
struct attribute_group attrs;
struct mutex lock;
u8 asa[3];
long raw_to_gauss[3];
- u8 reg_cache[AK8975_MAX_REGS];
int eoc_gpio;
int eoc_irq;
wait_queue_head_t data_ready_queue;
unsigned long flags;
- enum asahi_compass_chipset chipset;
+ u8 cntl_cache;
};
-static const int ak8975_index_to_reg[] = {
- AK8975_REG_HXL, AK8975_REG_HYL, AK8975_REG_HZL,
-};
+/*
+ * Return 0 if the i2c device is the one we expect.
+ * return a negative error number otherwise
+ */
+static int ak8975_who_i_am(struct i2c_client *client,
+ enum asahi_compass_chipset type)
+{
+ u8 wia_val[2];
+ int ret;
+
+ /*
+ * Signature for each device:
+ * Device | WIA1 | WIA2
+ * AK09912 | DEVICE_ID | AK09912_DEVICE_ID
+ * AK09911 | DEVICE_ID | AK09911_DEVICE_ID
+ * AK8975 | DEVICE_ID | NA
+ * AK8963 | DEVICE_ID | NA
+ */
+ ret = i2c_smbus_read_i2c_block_data(client, AK09912_REG_WIA1,
+ 2, wia_val);
+ if (ret < 0) {
+ dev_err(&client->dev, "Error reading WIA\n");
+ return ret;
+ }
+
+ if (wia_val[0] != AK8975_DEVICE_ID)
+ return -ENODEV;
+
+ switch (type) {
+ case AK8975:
+ case AK8963:
+ return 0;
+ case AK09911:
+ if (wia_val[1] == AK09911_DEVICE_ID)
+ return 0;
+ break;
+ case AK09912:
+ if (wia_val[1] == AK09912_DEVICE_ID)
+ return 0;
+ break;
+ default:
+ dev_err(&client->dev, "Type %d unknown\n", type);
+ }
+ return -ENODEV;
+}
/*
- * Helper function to write to the I2C device's registers.
+ * Helper function to write to CNTL register.
*/
-static int ak8975_write_data(struct i2c_client *client,
- u8 reg, u8 val, u8 mask, u8 shift)
+static int ak8975_set_mode(struct ak8975_data *data, enum ak_ctrl_mode mode)
{
- struct iio_dev *indio_dev = i2c_get_clientdata(client);
- struct ak8975_data *data = iio_priv(indio_dev);
u8 regval;
int ret;
- regval = (data->reg_cache[reg] & ~mask) | (val << shift);
- ret = i2c_smbus_write_byte_data(client, reg, regval);
+ regval = (data->cntl_cache & ~data->def->ctrl_masks[CNTL_MODE]) |
+ data->def->ctrl_modes[mode];
+ ret = i2c_smbus_write_byte_data(data->client,
+ data->def->ctrl_regs[CNTL], regval);
if (ret < 0) {
- dev_err(&client->dev, "Write to device fails status %x\n", ret);
return ret;
}
- data->reg_cache[reg] = regval;
+ data->cntl_cache = regval;
+ /* After mode change wait atleast 100us */
+ usleep_range(100, 500);
return 0;
}
@@ -166,8 +468,8 @@ static int ak8975_setup_irq(struct ak8975_data *data)
irq = gpio_to_irq(data->eoc_gpio);
rc = devm_request_irq(&client->dev, irq, ak8975_irq_handler,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- dev_name(&client->dev), data);
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ dev_name(&client->dev), data);
if (rc < 0) {
dev_err(&client->dev,
"irq %d request failed, (gpio %d): %d\n",
@@ -191,34 +493,18 @@ static int ak8975_setup(struct i2c_client *client)
{
struct iio_dev *indio_dev = i2c_get_clientdata(client);
struct ak8975_data *data = iio_priv(indio_dev);
- u8 device_id;
int ret;
- /* Confirm that the device we're talking to is really an AK8975. */
- ret = i2c_smbus_read_byte_data(client, AK8975_REG_WIA);
- if (ret < 0) {
- dev_err(&client->dev, "Error reading WIA\n");
- return ret;
- }
- device_id = ret;
- if (device_id != AK8975_DEVICE_ID) {
- dev_err(&client->dev, "Device ak8975 not found\n");
- return -ENODEV;
- }
-
/* Write the fused rom access mode. */
- ret = ak8975_write_data(client,
- AK8975_REG_CNTL,
- AK8975_REG_CNTL_MODE_FUSE_ROM,
- AK8975_REG_CNTL_MODE_MASK,
- AK8975_REG_CNTL_MODE_SHIFT);
+ ret = ak8975_set_mode(data, FUSE_ROM);
if (ret < 0) {
dev_err(&client->dev, "Error in setting fuse access mode\n");
return ret;
}
/* Get asa data and store in the device data. */
- ret = i2c_smbus_read_i2c_block_data(client, AK8975_REG_ASAX,
+ ret = i2c_smbus_read_i2c_block_data(client,
+ data->def->ctrl_regs[ASA_BASE],
3, data->asa);
if (ret < 0) {
dev_err(&client->dev, "Not able to read asa data\n");
@@ -226,13 +512,13 @@ static int ak8975_setup(struct i2c_client *client)
}
/* After reading fuse ROM data set power-down mode */
- ret = ak8975_write_data(client,
- AK8975_REG_CNTL,
- AK8975_REG_CNTL_MODE_POWER_DOWN,
- AK8975_REG_CNTL_MODE_MASK,
- AK8975_REG_CNTL_MODE_SHIFT);
+ ret = ak8975_set_mode(data, POWER_DOWN);
+ if (ret < 0) {
+ dev_err(&client->dev, "Error in setting power-down mode\n");
+ return ret;
+ }
- if (data->eoc_gpio > 0 || client->irq) {
+ if (data->eoc_gpio > 0 || client->irq > 0) {
ret = ak8975_setup_irq(data);
if (ret < 0) {
dev_err(&client->dev,
@@ -241,61 +527,9 @@ static int ak8975_setup(struct i2c_client *client)
}
}
- if (ret < 0) {
- dev_err(&client->dev, "Error in setting power-down mode\n");
- return ret;
- }
-
-/*
- * Precalculate scale factor (in Gauss units) for each axis and
- * store in the device data.
- *
- * This scale factor is axis-dependent, and is derived from 3 calibration
- * factors ASA(x), ASA(y), and ASA(z).
- *
- * These ASA values are read from the sensor device at start of day, and
- * cached in the device context struct.
- *
- * Adjusting the flux value with the sensitivity adjustment value should be
- * done via the following formula:
- *
- * Hadj = H * ( ( ( (ASA-128)*0.5 ) / 128 ) + 1 )
- *
- * where H is the raw value, ASA is the sensitivity adjustment, and Hadj
- * is the resultant adjusted value.
- *
- * We reduce the formula to:
- *
- * Hadj = H * (ASA + 128) / 256
- *
- * H is in the range of -4096 to 4095. The magnetometer has a range of
- * +-1229uT. To go from the raw value to uT is:
- *
- * HuT = H * 1229/4096, or roughly, 3/10.
- *
- * Since 1uT = 0.01 gauss, our final scale factor becomes:
- *
- * Hadj = H * ((ASA + 128) / 256) * 3/10 * 1/100
- * Hadj = H * ((ASA + 128) * 0.003) / 256
- *
- * Since ASA doesn't change, we cache the resultant scale factor into the
- * device context in ak8975_setup().
- */
- if (data->chipset == AK8963) {
- /*
- * H range is +-8190 and magnetometer range is +-4912.
- * So HuT using the above explanation for 8975,
- * 4912/8190 = ~ 6/10.
- * So the Hadj should use 6/10 instead of 3/10.
- */
- data->raw_to_gauss[0] = RAW_TO_GAUSS_8963(data->asa[0]);
- data->raw_to_gauss[1] = RAW_TO_GAUSS_8963(data->asa[1]);
- data->raw_to_gauss[2] = RAW_TO_GAUSS_8963(data->asa[2]);
- } else {
- data->raw_to_gauss[0] = RAW_TO_GAUSS_8975(data->asa[0]);
- data->raw_to_gauss[1] = RAW_TO_GAUSS_8975(data->asa[1]);
- data->raw_to_gauss[2] = RAW_TO_GAUSS_8975(data->asa[2]);
- }
+ data->raw_to_gauss[0] = data->def->raw_to_gauss(data->asa[0]);
+ data->raw_to_gauss[1] = data->def->raw_to_gauss(data->asa[1]);
+ data->raw_to_gauss[2] = data->def->raw_to_gauss(data->asa[2]);
return 0;
}
@@ -318,7 +552,7 @@ static int wait_conversion_complete_gpio(struct ak8975_data *data)
return -EINVAL;
}
- ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+ ret = i2c_smbus_read_byte_data(client, data->def->ctrl_regs[ST1]);
if (ret < 0)
dev_err(&client->dev, "Error in reading ST1\n");
@@ -335,7 +569,8 @@ static int wait_conversion_complete_polled(struct ak8975_data *data)
/* Wait for the conversion to complete. */
while (timeout_ms) {
msleep(AK8975_CONVERSION_DONE_POLL_TIME);
- ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST1);
+ ret = i2c_smbus_read_byte_data(client,
+ data->def->ctrl_regs[ST1]);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST1\n");
return ret;
@@ -378,11 +613,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
mutex_lock(&data->lock);
/* Set up the device for taking a sample. */
- ret = ak8975_write_data(client,
- AK8975_REG_CNTL,
- AK8975_REG_CNTL_MODE_ONCE,
- AK8975_REG_CNTL_MODE_MASK,
- AK8975_REG_CNTL_MODE_SHIFT);
+ ret = ak8975_set_mode(data, MODE_ONCE);
if (ret < 0) {
dev_err(&client->dev, "Error in setting operating mode\n");
goto exit;
@@ -399,14 +630,15 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
goto exit;
/* This will be executed only for non-interrupt based waiting case */
- if (ret & AK8975_REG_ST1_DRDY_MASK) {
- ret = i2c_smbus_read_byte_data(client, AK8975_REG_ST2);
+ if (ret & data->def->ctrl_masks[ST1_DRDY]) {
+ ret = i2c_smbus_read_byte_data(client,
+ data->def->ctrl_regs[ST2]);
if (ret < 0) {
dev_err(&client->dev, "Error in reading ST2\n");
goto exit;
}
- if (ret & (AK8975_REG_ST2_DERR_MASK |
- AK8975_REG_ST2_HOFL_MASK)) {
+ if (ret & (data->def->ctrl_masks[ST2_DERR] |
+ data->def->ctrl_masks[ST2_HOFL])) {
dev_err(&client->dev, "ST2 status error 0x%x\n", ret);
ret = -EINVAL;
goto exit;
@@ -415,7 +647,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
/* Read the flux value from the appropriate register
(the register is specified in the iio device attributes). */
- ret = i2c_smbus_read_word_data(client, ak8975_index_to_reg[index]);
+ ret = i2c_smbus_read_word_data(client, data->def->data_regs[index]);
if (ret < 0) {
dev_err(&client->dev, "Read axis data fails\n");
goto exit;
@@ -424,7 +656,7 @@ static int ak8975_read_axis(struct iio_dev *indio_dev, int index, int *val)
mutex_unlock(&data->lock);
/* Clamp to valid range. */
- *val = clamp_t(s16, ret, -4096, 4095);
+ *val = clamp_t(s16, ret, -data->def->range, data->def->range);
return IIO_VAL_INT;
exit:
@@ -473,6 +705,8 @@ static const struct acpi_device_id ak_acpi_match[] = {
{"AK8975", AK8975},
{"AK8963", AK8963},
{"INVN6500", AK8963},
+ {"AK09911", AK09911},
+ {"AK09912", AK09912},
{ },
};
MODULE_DEVICE_TABLE(acpi, ak_acpi_match);
@@ -498,6 +732,7 @@ static int ak8975_probe(struct i2c_client *client,
int eoc_gpio;
int err;
const char *name = NULL;
+ enum asahi_compass_chipset chipset;
/* Grab and set up the supplied GPIO. */
if (client->dev.platform_data)
@@ -537,42 +772,50 @@ static int ak8975_probe(struct i2c_client *client,
/* id will be NULL when enumerated via ACPI */
if (id) {
- data->chipset =
- (enum asahi_compass_chipset)(id->driver_data);
+ chipset = (enum asahi_compass_chipset)(id->driver_data);
name = id->name;
} else if (ACPI_HANDLE(&client->dev))
- name = ak8975_match_acpi_device(&client->dev, &data->chipset);
+ name = ak8975_match_acpi_device(&client->dev, &chipset);
else
return -ENOSYS;
+ if (chipset >= AK_MAX_TYPE) {
+ dev_err(&client->dev, "AKM device type unsupported: %d\n",
+ chipset);
+ return -ENODEV;
+ }
+
+ data->def = &ak_def_array[chipset];
+ err = ak8975_who_i_am(client, data->def->type);
+ if (err < 0) {
+ dev_err(&client->dev, "Unexpected device\n");
+ return err;
+ }
dev_dbg(&client->dev, "Asahi compass chip %s\n", name);
/* Perform some basic start-of-day setup of the device. */
err = ak8975_setup(client);
if (err < 0) {
- dev_err(&client->dev, "AK8975 initialization fails\n");
+ dev_err(&client->dev, "%s initialization fails\n", name);
return err;
}
- data->client = client;
mutex_init(&data->lock);
- data->eoc_gpio = eoc_gpio;
indio_dev->dev.parent = &client->dev;
indio_dev->channels = ak8975_channels;
indio_dev->num_channels = ARRAY_SIZE(ak8975_channels);
indio_dev->info = &ak8975_info;
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->name = name;
- err = devm_iio_device_register(&client->dev, indio_dev);
- if (err < 0)
- return err;
-
- return 0;
+ return devm_iio_device_register(&client->dev, indio_dev);
}
static const struct i2c_device_id ak8975_id[] = {
{"ak8975", AK8975},
{"ak8963", AK8963},
+ {"AK8963", AK8963},
+ {"ak09911", AK09911},
+ {"ak09912", AK09912},
{}
};
@@ -581,14 +824,20 @@ MODULE_DEVICE_TABLE(i2c, ak8975_id);
static const struct of_device_id ak8975_of_match[] = {
{ .compatible = "asahi-kasei,ak8975", },
{ .compatible = "ak8975", },
- { }
+ { .compatible = "asahi-kasei,ak8963", },
+ { .compatible = "ak8963", },
+ { .compatible = "asahi-kasei,ak09911", },
+ { .compatible = "ak09911", },
+ { .compatible = "asahi-kasei,ak09912", },
+ { .compatible = "ak09912", },
+ {}
};
MODULE_DEVICE_TABLE(of, ak8975_of_match);
static struct i2c_driver ak8975_driver = {
.driver = {
.name = "ak8975",
- .of_match_table = ak8975_of_match,
+ .of_match_table = of_match_ptr(ak8975_of_match),
.acpi_match_table = ACPI_PTR(ak_acpi_match),
},
.probe = ak8975_probe,
diff --git a/drivers/iio/magnetometer/hid-sensor-magn-3d.c b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
index 6294575d2777..d22993b4066a 100644
--- a/drivers/iio/magnetometer/hid-sensor-magn-3d.c
+++ b/drivers/iio/magnetometer/hid-sensor-magn-3d.c
@@ -157,20 +157,12 @@ static int magn_3d_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
switch (mask) {
case 0:
- poll_value = hid_sensor_read_poll_value(
- &magn_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
-
hid_sensor_power_state(&magn_state->common_attributes, true);
- msleep_interruptible(poll_value * 2);
-
report_id =
magn_state->magn[chan->address].report_id;
address = magn_3d_addresses[chan->address];
@@ -530,6 +522,7 @@ static struct platform_driver hid_magn_3d_platform_driver = {
.id_table = hid_magn_3d_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_magn_3d_probe,
.remove = hid_magn_3d_remove,
diff --git a/drivers/iio/orientation/hid-sensor-incl-3d.c b/drivers/iio/orientation/hid-sensor-incl-3d.c
index 1ff181bbbcef..73854460bb2c 100644
--- a/drivers/iio/orientation/hid-sensor-incl-3d.c
+++ b/drivers/iio/orientation/hid-sensor-incl-3d.c
@@ -111,20 +111,12 @@ static int incl_3d_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
switch (mask) {
case IIO_CHAN_INFO_RAW:
- poll_value = hid_sensor_read_poll_value(
- &incl_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
-
hid_sensor_power_state(&incl_state->common_attributes, true);
- msleep_interruptible(poll_value * 2);
-
report_id =
incl_state->incl[chan->scan_index].report_id;
address = incl_3d_addresses[chan->scan_index];
@@ -437,6 +429,7 @@ static struct platform_driver hid_incl_3d_platform_driver = {
.id_table = hid_incl_3d_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_incl_3d_probe,
.remove = hid_incl_3d_remove,
diff --git a/drivers/iio/pressure/bmp280.c b/drivers/iio/pressure/bmp280.c
index 75038dacfff1..7c623e2bd633 100644
--- a/drivers/iio/pressure/bmp280.c
+++ b/drivers/iio/pressure/bmp280.c
@@ -80,16 +80,12 @@ struct bmp280_data {
s32 t_fine;
};
-/* Compensation parameters. */
-struct bmp280_comp_temp {
- u16 dig_t1;
- s16 dig_t2, dig_t3;
-};
-
-struct bmp280_comp_press {
- u16 dig_p1;
- s16 dig_p2, dig_p3, dig_p4, dig_p5, dig_p6, dig_p7, dig_p8, dig_p9;
-};
+/*
+ * These enums are used for indexing into the array of compensation
+ * parameters.
+ */
+enum { T1, T2, T3 };
+enum { P1, P2, P3, P4, P5, P6, P7, P8, P9 };
static const struct iio_chan_spec bmp280_channels[] = {
{
@@ -141,54 +137,6 @@ static const struct regmap_config bmp280_regmap_config = {
.volatile_reg = bmp280_is_volatile_reg,
};
-static int bmp280_read_compensation_temp(struct bmp280_data *data,
- struct bmp280_comp_temp *comp)
-{
- int ret;
- __le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
-
- ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
- buf, BMP280_COMP_TEMP_REG_COUNT);
- if (ret < 0) {
- dev_err(&data->client->dev,
- "failed to read temperature calibration parameters\n");
- return ret;
- }
-
- comp->dig_t1 = (u16) le16_to_cpu(buf[0]);
- comp->dig_t2 = (s16) le16_to_cpu(buf[1]);
- comp->dig_t3 = (s16) le16_to_cpu(buf[2]);
-
- return 0;
-}
-
-static int bmp280_read_compensation_press(struct bmp280_data *data,
- struct bmp280_comp_press *comp)
-{
- int ret;
- __le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
-
- ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
- buf, BMP280_COMP_PRESS_REG_COUNT);
- if (ret < 0) {
- dev_err(&data->client->dev,
- "failed to read pressure calibration parameters\n");
- return ret;
- }
-
- comp->dig_p1 = (u16) le16_to_cpu(buf[0]);
- comp->dig_p2 = (s16) le16_to_cpu(buf[1]);
- comp->dig_p3 = (s16) le16_to_cpu(buf[2]);
- comp->dig_p4 = (s16) le16_to_cpu(buf[3]);
- comp->dig_p5 = (s16) le16_to_cpu(buf[4]);
- comp->dig_p6 = (s16) le16_to_cpu(buf[5]);
- comp->dig_p7 = (s16) le16_to_cpu(buf[6]);
- comp->dig_p8 = (s16) le16_to_cpu(buf[7]);
- comp->dig_p9 = (s16) le16_to_cpu(buf[8]);
-
- return 0;
-}
-
/*
* Returns temperature in DegC, resolution is 0.01 DegC. Output value of
* "5123" equals 51.23 DegC. t_fine carries fine temperature as global
@@ -197,21 +145,35 @@ static int bmp280_read_compensation_press(struct bmp280_data *data,
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static s32 bmp280_compensate_temp(struct bmp280_data *data,
- struct bmp280_comp_temp *comp,
s32 adc_temp)
{
- s32 var1, var2, t;
+ int ret;
+ s32 var1, var2;
+ __le16 buf[BMP280_COMP_TEMP_REG_COUNT / 2];
- var1 = (((adc_temp >> 3) - ((s32) comp->dig_t1 << 1)) *
- ((s32) comp->dig_t2)) >> 11;
- var2 = (((((adc_temp >> 4) - ((s32) comp->dig_t1)) *
- ((adc_temp >> 4) - ((s32) comp->dig_t1))) >> 12) *
- ((s32) comp->dig_t3)) >> 14;
+ ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_TEMP_START,
+ buf, BMP280_COMP_TEMP_REG_COUNT);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "failed to read temperature calibration parameters\n");
+ return ret;
+ }
- data->t_fine = var1 + var2;
- t = (data->t_fine * 5 + 128) >> 8;
+ /*
+ * The double casts are necessary because le16_to_cpu returns an
+ * unsigned 16-bit value. Casting that value directly to a
+ * signed 32-bit will not do proper sign extension.
+ *
+ * Conversely, T1 and P1 are unsigned values, so they can be
+ * cast straight to the larger type.
+ */
+ var1 = (((adc_temp >> 3) - ((s32)le16_to_cpu(buf[T1]) << 1)) *
+ ((s32)(s16)le16_to_cpu(buf[T2]))) >> 11;
+ var2 = (((((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1]))) *
+ ((adc_temp >> 4) - ((s32)le16_to_cpu(buf[T1])))) >> 12) *
+ ((s32)(s16)le16_to_cpu(buf[T3]))) >> 14;
- return t;
+ return (data->t_fine * 5 + 128) >> 8;
}
/*
@@ -222,29 +184,38 @@ static s32 bmp280_compensate_temp(struct bmp280_data *data,
* Taken from datasheet, Section 3.11.3, "Compensation formula".
*/
static u32 bmp280_compensate_press(struct bmp280_data *data,
- struct bmp280_comp_press *comp,
s32 adc_press)
{
+ int ret;
s64 var1, var2, p;
+ __le16 buf[BMP280_COMP_PRESS_REG_COUNT / 2];
+
+ ret = regmap_bulk_read(data->regmap, BMP280_REG_COMP_PRESS_START,
+ buf, BMP280_COMP_PRESS_REG_COUNT);
+ if (ret < 0) {
+ dev_err(&data->client->dev,
+ "failed to read pressure calibration parameters\n");
+ return ret;
+ }
- var1 = ((s64) data->t_fine) - 128000;
- var2 = var1 * var1 * (s64) comp->dig_p6;
- var2 = var2 + ((var1 * (s64) comp->dig_p5) << 17);
- var2 = var2 + (((s64) comp->dig_p4) << 35);
- var1 = ((var1 * var1 * (s64) comp->dig_p3) >> 8) +
- ((var1 * (s64) comp->dig_p2) << 12);
- var1 = (((((s64) 1) << 47) + var1)) * ((s64) comp->dig_p1) >> 33;
+ var1 = ((s64)data->t_fine) - 128000;
+ var2 = var1 * var1 * (s64)(s16)le16_to_cpu(buf[P6]);
+ var2 += (var1 * (s64)(s16)le16_to_cpu(buf[P5])) << 17;
+ var2 += ((s64)(s16)le16_to_cpu(buf[P4])) << 35;
+ var1 = ((var1 * var1 * (s64)(s16)le16_to_cpu(buf[P3])) >> 8) +
+ ((var1 * (s64)(s16)le16_to_cpu(buf[P2])) << 12);
+ var1 = ((((s64)1) << 47) + var1) * ((s64)le16_to_cpu(buf[P1])) >> 33;
if (var1 == 0)
return 0;
- p = ((((s64) 1048576 - adc_press) << 31) - var2) * 3125;
+ p = ((((s64)1048576 - adc_press) << 31) - var2) * 3125;
p = div64_s64(p, var1);
- var1 = (((s64) comp->dig_p9) * (p >> 13) * (p >> 13)) >> 25;
- var2 = (((s64) comp->dig_p8) * p) >> 19;
- p = ((p + var1 + var2) >> 8) + (((s64) comp->dig_p7) << 4);
+ var1 = (((s64)(s16)le16_to_cpu(buf[P9])) * (p >> 13) * (p >> 13)) >> 25;
+ var2 = (((s64)(s16)le16_to_cpu(buf[P8])) * p) >> 19;
+ p = ((p + var1 + var2) >> 8) + (((s64)(s16)le16_to_cpu(buf[P7])) << 4);
- return (u32) p;
+ return (u32)p;
}
static int bmp280_read_temp(struct bmp280_data *data,
@@ -253,11 +224,6 @@ static int bmp280_read_temp(struct bmp280_data *data,
int ret;
__be32 tmp = 0;
s32 adc_temp, comp_temp;
- struct bmp280_comp_temp comp;
-
- ret = bmp280_read_compensation_temp(data, &comp);
- if (ret < 0)
- return ret;
ret = regmap_bulk_read(data->regmap, BMP280_REG_TEMP_MSB,
(u8 *) &tmp, 3);
@@ -267,7 +233,7 @@ static int bmp280_read_temp(struct bmp280_data *data,
}
adc_temp = be32_to_cpu(tmp) >> 12;
- comp_temp = bmp280_compensate_temp(data, &comp, adc_temp);
+ comp_temp = bmp280_compensate_temp(data, adc_temp);
/*
* val might be NULL if we're called by the read_press routine,
@@ -288,11 +254,6 @@ static int bmp280_read_press(struct bmp280_data *data,
__be32 tmp = 0;
s32 adc_press;
u32 comp_press;
- struct bmp280_comp_press comp;
-
- ret = bmp280_read_compensation_press(data, &comp);
- if (ret < 0)
- return ret;
/* Read and compensate temperature so we get a reading of t_fine. */
ret = bmp280_read_temp(data, NULL);
@@ -307,7 +268,7 @@ static int bmp280_read_press(struct bmp280_data *data,
}
adc_press = be32_to_cpu(tmp) >> 12;
- comp_press = bmp280_compensate_press(data, &comp, adc_press);
+ comp_press = bmp280_compensate_press(data, adc_press);
*val = comp_press;
*val2 = 256000;
@@ -366,7 +327,7 @@ static int bmp280_chip_init(struct bmp280_data *data)
BMP280_MODE_NORMAL);
if (ret < 0) {
dev_err(&data->client->dev,
- "failed to write config register\n");
+ "failed to write ctrl_meas register\n");
return ret;
}
@@ -394,7 +355,6 @@ static int bmp280_probe(struct i2c_client *client,
if (!indio_dev)
return -ENOMEM;
- i2c_set_clientdata(client, indio_dev);
data = iio_priv(indio_dev);
mutex_init(&data->lock);
data->client = client;
diff --git a/drivers/iio/pressure/hid-sensor-press.c b/drivers/iio/pressure/hid-sensor-press.c
index 764928682df2..1af314926ebd 100644
--- a/drivers/iio/pressure/hid-sensor-press.c
+++ b/drivers/iio/pressure/hid-sensor-press.c
@@ -79,7 +79,6 @@ static int press_read_raw(struct iio_dev *indio_dev,
int report_id = -1;
u32 address;
int ret_type;
- s32 poll_value;
*val = 0;
*val2 = 0;
@@ -96,15 +95,8 @@ static int press_read_raw(struct iio_dev *indio_dev,
break;
}
if (report_id >= 0) {
- poll_value = hid_sensor_read_poll_value(
- &press_state->common_attributes);
- if (poll_value < 0)
- return -EINVAL;
hid_sensor_power_state(&press_state->common_attributes,
true);
-
- msleep_interruptible(poll_value * 2);
-
*val = sensor_hub_input_attr_get_raw_value(
press_state->common_attributes.hsdev,
HID_USAGE_SENSOR_PRESSURE, address,
@@ -382,6 +374,7 @@ static struct platform_driver hid_press_platform_driver = {
.id_table = hid_press_ids,
.driver = {
.name = KBUILD_MODNAME,
+ .pm = &hid_sensor_pm_ops,
},
.probe = hid_press_probe,
.remove = hid_press_remove,
diff --git a/drivers/iio/proximity/Kconfig b/drivers/iio/proximity/Kconfig
index 0c8cdf58f6a1..41a8d8ffa0de 100644
--- a/drivers/iio/proximity/Kconfig
+++ b/drivers/iio/proximity/Kconfig
@@ -17,3 +17,20 @@ config AS3935
module will be called as3935
endmenu
+
+menu "Proximity sensors"
+
+config SX9500
+ tristate "SX9500 Semtech proximity sensor"
+ select IIO_BUFFER
+ select IIO_TRIGGERED_BUFFER
+ select REGMAP_I2C
+ depends on I2C
+ help
+ Say Y here to build a driver for Semtech's SX9500 capacitive
+ proximity/button sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sx9500.
+
+endmenu
diff --git a/drivers/iio/proximity/Makefile b/drivers/iio/proximity/Makefile
index 743adee1c8bf..9818dc562abd 100644
--- a/drivers/iio/proximity/Makefile
+++ b/drivers/iio/proximity/Makefile
@@ -4,3 +4,4 @@
# When adding new entries keep the list in alphabetical order
obj-$(CONFIG_AS3935) += as3935.o
+obj-$(CONFIG_SX9500) += sx9500.o
diff --git a/drivers/iio/proximity/as3935.c b/drivers/iio/proximity/as3935.c
index 466aa4314667..bc0d68efd455 100644
--- a/drivers/iio/proximity/as3935.c
+++ b/drivers/iio/proximity/as3935.c
@@ -273,9 +273,9 @@ static void calibrate_as3935(struct as3935_state *st)
}
#ifdef CONFIG_PM_SLEEP
-static int as3935_suspend(struct spi_device *spi, pm_message_t msg)
+static int as3935_suspend(struct device *dev)
{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct as3935_state *st = iio_priv(indio_dev);
int val, ret;
@@ -293,9 +293,9 @@ err_suspend:
return ret;
}
-static int as3935_resume(struct spi_device *spi)
+static int as3935_resume(struct device *dev)
{
- struct iio_dev *indio_dev = spi_get_drvdata(spi);
+ struct iio_dev *indio_dev = dev_get_drvdata(dev);
struct as3935_state *st = iio_priv(indio_dev);
int val, ret;
@@ -311,9 +311,12 @@ err_resume:
return ret;
}
+
+static SIMPLE_DEV_PM_OPS(as3935_pm_ops, as3935_suspend, as3935_resume);
+#define AS3935_PM_OPS (&as3935_pm_ops)
+
#else
-#define as3935_suspend NULL
-#define as3935_resume NULL
+#define AS3935_PM_OPS NULL
#endif
static int as3935_probe(struct spi_device *spi)
@@ -441,12 +444,11 @@ static struct spi_driver as3935_driver = {
.driver = {
.name = "as3935",
.owner = THIS_MODULE,
+ .pm = AS3935_PM_OPS,
},
.probe = as3935_probe,
.remove = as3935_remove,
.id_table = as3935_id,
- .suspend = as3935_suspend,
- .resume = as3935_resume,
};
module_spi_driver(as3935_driver);
diff --git a/drivers/iio/proximity/sx9500.c b/drivers/iio/proximity/sx9500.c
new file mode 100644
index 000000000000..74dff4e4a11a
--- /dev/null
+++ b/drivers/iio/proximity/sx9500.c
@@ -0,0 +1,752 @@
+/*
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Driver for Semtech's SX9500 capacitive proximity/button solution.
+ * Datasheet available at
+ * <http://www.semtech.com/images/datasheet/sx9500.pdf>.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/irq.h>
+#include <linux/acpi.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regmap.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/buffer.h>
+#include <linux/iio/sysfs.h>
+#include <linux/iio/events.h>
+#include <linux/iio/trigger.h>
+#include <linux/iio/triggered_buffer.h>
+#include <linux/iio/trigger_consumer.h>
+
+#define SX9500_DRIVER_NAME "sx9500"
+#define SX9500_IRQ_NAME "sx9500_event"
+#define SX9500_GPIO_NAME "sx9500_gpio"
+
+/* Register definitions. */
+#define SX9500_REG_IRQ_SRC 0x00
+#define SX9500_REG_STAT 0x01
+#define SX9500_REG_IRQ_MSK 0x03
+
+#define SX9500_REG_PROX_CTRL0 0x06
+#define SX9500_REG_PROX_CTRL1 0x07
+#define SX9500_REG_PROX_CTRL2 0x08
+#define SX9500_REG_PROX_CTRL3 0x09
+#define SX9500_REG_PROX_CTRL4 0x0a
+#define SX9500_REG_PROX_CTRL5 0x0b
+#define SX9500_REG_PROX_CTRL6 0x0c
+#define SX9500_REG_PROX_CTRL7 0x0d
+#define SX9500_REG_PROX_CTRL8 0x0e
+
+#define SX9500_REG_SENSOR_SEL 0x20
+#define SX9500_REG_USE_MSB 0x21
+#define SX9500_REG_USE_LSB 0x22
+#define SX9500_REG_AVG_MSB 0x23
+#define SX9500_REG_AVG_LSB 0x24
+#define SX9500_REG_DIFF_MSB 0x25
+#define SX9500_REG_DIFF_LSB 0x26
+#define SX9500_REG_OFFSET_MSB 0x27
+#define SX9500_REG_OFFSET_LSB 0x28
+
+#define SX9500_REG_RESET 0x7f
+
+/* Write this to REG_RESET to do a soft reset. */
+#define SX9500_SOFT_RESET 0xde
+
+#define SX9500_SCAN_PERIOD_MASK GENMASK(6, 4)
+#define SX9500_SCAN_PERIOD_SHIFT 4
+
+/*
+ * These serve for identifying IRQ source in the IRQ_SRC register, and
+ * also for masking the IRQs in the IRQ_MSK register.
+ */
+#define SX9500_CLOSE_IRQ BIT(6)
+#define SX9500_FAR_IRQ BIT(5)
+#define SX9500_CONVDONE_IRQ BIT(3)
+
+#define SX9500_PROXSTAT_SHIFT 4
+
+#define SX9500_NUM_CHANNELS 4
+
+struct sx9500_data {
+ struct mutex mutex;
+ struct i2c_client *client;
+ struct iio_trigger *trig;
+ struct regmap *regmap;
+ /*
+ * Last reading of the proximity status for each channel. We
+ * only send an event to user space when this changes.
+ */
+ bool prox_stat[SX9500_NUM_CHANNELS];
+ bool event_enabled[SX9500_NUM_CHANNELS];
+ bool trigger_enabled;
+ u16 *buffer;
+};
+
+static const struct iio_event_spec sx9500_events[] = {
+ {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_EITHER,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+ },
+};
+
+#define SX9500_CHANNEL(idx) \
+ { \
+ .type = IIO_PROXIMITY, \
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
+ .info_mask_shared_by_all = BIT(IIO_CHAN_INFO_SAMP_FREQ), \
+ .indexed = 1, \
+ .channel = idx, \
+ .event_spec = sx9500_events, \
+ .num_event_specs = ARRAY_SIZE(sx9500_events), \
+ .scan_index = idx, \
+ .scan_type = { \
+ .sign = 'u', \
+ .realbits = 16, \
+ .storagebits = 16, \
+ .shift = 0, \
+ }, \
+ }
+
+static const struct iio_chan_spec sx9500_channels[] = {
+ SX9500_CHANNEL(0),
+ SX9500_CHANNEL(1),
+ SX9500_CHANNEL(2),
+ SX9500_CHANNEL(3),
+ IIO_CHAN_SOFT_TIMESTAMP(4),
+};
+
+static const struct {
+ int val;
+ int val2;
+} sx9500_samp_freq_table[] = {
+ {33, 333333},
+ {16, 666666},
+ {11, 111111},
+ {8, 333333},
+ {6, 666666},
+ {5, 0},
+ {3, 333333},
+ {2, 500000},
+};
+
+static const struct regmap_range sx9500_writable_reg_ranges[] = {
+ regmap_reg_range(SX9500_REG_IRQ_MSK, SX9500_REG_IRQ_MSK),
+ regmap_reg_range(SX9500_REG_PROX_CTRL0, SX9500_REG_PROX_CTRL8),
+ regmap_reg_range(SX9500_REG_SENSOR_SEL, SX9500_REG_SENSOR_SEL),
+ regmap_reg_range(SX9500_REG_OFFSET_MSB, SX9500_REG_OFFSET_LSB),
+ regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET),
+};
+
+static const struct regmap_access_table sx9500_writeable_regs = {
+ .yes_ranges = sx9500_writable_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sx9500_writable_reg_ranges),
+};
+
+/*
+ * All allocated registers are readable, so we just list unallocated
+ * ones.
+ */
+static const struct regmap_range sx9500_non_readable_reg_ranges[] = {
+ regmap_reg_range(SX9500_REG_STAT + 1, SX9500_REG_STAT + 1),
+ regmap_reg_range(SX9500_REG_IRQ_MSK + 1, SX9500_REG_PROX_CTRL0 - 1),
+ regmap_reg_range(SX9500_REG_PROX_CTRL8 + 1, SX9500_REG_SENSOR_SEL - 1),
+ regmap_reg_range(SX9500_REG_OFFSET_LSB + 1, SX9500_REG_RESET - 1),
+};
+
+static const struct regmap_access_table sx9500_readable_regs = {
+ .no_ranges = sx9500_non_readable_reg_ranges,
+ .n_no_ranges = ARRAY_SIZE(sx9500_non_readable_reg_ranges),
+};
+
+static const struct regmap_range sx9500_volatile_reg_ranges[] = {
+ regmap_reg_range(SX9500_REG_IRQ_SRC, SX9500_REG_STAT),
+ regmap_reg_range(SX9500_REG_USE_MSB, SX9500_REG_OFFSET_LSB),
+ regmap_reg_range(SX9500_REG_RESET, SX9500_REG_RESET),
+};
+
+static const struct regmap_access_table sx9500_volatile_regs = {
+ .yes_ranges = sx9500_volatile_reg_ranges,
+ .n_yes_ranges = ARRAY_SIZE(sx9500_volatile_reg_ranges),
+};
+
+static const struct regmap_config sx9500_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = SX9500_REG_RESET,
+ .cache_type = REGCACHE_RBTREE,
+
+ .wr_table = &sx9500_writeable_regs,
+ .rd_table = &sx9500_readable_regs,
+ .volatile_table = &sx9500_volatile_regs,
+};
+
+static int sx9500_read_proximity(struct sx9500_data *data,
+ const struct iio_chan_spec *chan,
+ int *val)
+{
+ int ret;
+ __be16 regval;
+
+ ret = regmap_write(data->regmap, SX9500_REG_SENSOR_SEL, chan->channel);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_bulk_read(data->regmap, SX9500_REG_USE_MSB, &regval, 2);
+ if (ret < 0)
+ return ret;
+
+ *val = 32767 - (s16)be16_to_cpu(regval);
+
+ return IIO_VAL_INT;
+}
+
+static int sx9500_read_samp_freq(struct sx9500_data *data,
+ int *val, int *val2)
+{
+ int ret;
+ unsigned int regval;
+
+ mutex_lock(&data->mutex);
+ ret = regmap_read(data->regmap, SX9500_REG_PROX_CTRL0, &regval);
+ mutex_unlock(&data->mutex);
+
+ if (ret < 0)
+ return ret;
+
+ regval = (regval & SX9500_SCAN_PERIOD_MASK) >> SX9500_SCAN_PERIOD_SHIFT;
+ *val = sx9500_samp_freq_table[regval].val;
+ *val2 = sx9500_samp_freq_table[regval].val2;
+
+ return IIO_VAL_INT_PLUS_MICRO;
+}
+
+static int sx9500_read_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int *val, int *val2, long mask)
+{
+ struct sx9500_data *data = iio_priv(indio_dev);
+ int ret;
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (iio_buffer_enabled(indio_dev))
+ return -EBUSY;
+ mutex_lock(&data->mutex);
+ ret = sx9500_read_proximity(data, chan, val);
+ mutex_unlock(&data->mutex);
+ return ret;
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return sx9500_read_samp_freq(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sx9500_set_samp_freq(struct sx9500_data *data,
+ int val, int val2)
+{
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(sx9500_samp_freq_table); i++)
+ if (val == sx9500_samp_freq_table[i].val &&
+ val2 == sx9500_samp_freq_table[i].val2)
+ break;
+
+ if (i == ARRAY_SIZE(sx9500_samp_freq_table))
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, SX9500_REG_PROX_CTRL0,
+ SX9500_SCAN_PERIOD_MASK,
+ i << SX9500_SCAN_PERIOD_SHIFT);
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9500_write_raw(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ int val, int val2, long mask)
+{
+ struct sx9500_data *data = iio_priv(indio_dev);
+
+ switch (chan->type) {
+ case IIO_PROXIMITY:
+ switch (mask) {
+ case IIO_CHAN_INFO_SAMP_FREQ:
+ return sx9500_set_samp_freq(data, val, val2);
+ default:
+ return -EINVAL;
+ }
+ default:
+ return -EINVAL;
+ }
+}
+
+static irqreturn_t sx9500_irq_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct sx9500_data *data = iio_priv(indio_dev);
+
+ if (data->trigger_enabled)
+ iio_trigger_poll(data->trig);
+
+ /*
+ * Even if no event is enabled, we need to wake the thread to
+ * clear the interrupt state by reading SX9500_REG_IRQ_SRC. It
+ * is not possible to do that here because regmap_read takes a
+ * mutex.
+ */
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t sx9500_irq_thread_handler(int irq, void *private)
+{
+ struct iio_dev *indio_dev = private;
+ struct sx9500_data *data = iio_priv(indio_dev);
+ int ret;
+ unsigned int val, chan;
+
+ mutex_lock(&data->mutex);
+
+ ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
+ goto out;
+ }
+
+ if (!(val & (SX9500_CLOSE_IRQ | SX9500_FAR_IRQ)))
+ goto out;
+
+ ret = regmap_read(data->regmap, SX9500_REG_STAT, &val);
+ if (ret < 0) {
+ dev_err(&data->client->dev, "i2c transfer error in irq\n");
+ goto out;
+ }
+
+ val >>= SX9500_PROXSTAT_SHIFT;
+ for (chan = 0; chan < SX9500_NUM_CHANNELS; chan++) {
+ int dir;
+ u64 ev;
+ bool new_prox = val & BIT(chan);
+
+ if (!data->event_enabled[chan])
+ continue;
+ if (new_prox == data->prox_stat[chan])
+ /* No change on this channel. */
+ continue;
+
+ dir = new_prox ? IIO_EV_DIR_FALLING :
+ IIO_EV_DIR_RISING;
+ ev = IIO_UNMOD_EVENT_CODE(IIO_PROXIMITY,
+ chan,
+ IIO_EV_TYPE_THRESH,
+ dir);
+ iio_push_event(indio_dev, ev, iio_get_time_ns());
+ data->prox_stat[chan] = new_prox;
+ }
+
+out:
+ mutex_unlock(&data->mutex);
+
+ return IRQ_HANDLED;
+}
+
+static int sx9500_read_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir)
+{
+ struct sx9500_data *data = iio_priv(indio_dev);
+
+ if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
+ dir != IIO_EV_DIR_EITHER)
+ return -EINVAL;
+
+ return data->event_enabled[chan->channel];
+}
+
+static int sx9500_write_event_config(struct iio_dev *indio_dev,
+ const struct iio_chan_spec *chan,
+ enum iio_event_type type,
+ enum iio_event_direction dir,
+ int state)
+{
+ struct sx9500_data *data = iio_priv(indio_dev);
+ int ret, i;
+ bool any_active = false;
+ unsigned int irqmask;
+
+ if (chan->type != IIO_PROXIMITY || type != IIO_EV_TYPE_THRESH ||
+ dir != IIO_EV_DIR_EITHER)
+ return -EINVAL;
+
+ mutex_lock(&data->mutex);
+
+ data->event_enabled[chan->channel] = state;
+
+ for (i = 0; i < SX9500_NUM_CHANNELS; i++)
+ if (data->event_enabled[i]) {
+ any_active = true;
+ break;
+ }
+
+ irqmask = SX9500_CLOSE_IRQ | SX9500_FAR_IRQ;
+ if (any_active)
+ ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
+ irqmask, irqmask);
+ else
+ ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
+ irqmask, 0);
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static int sx9500_update_scan_mode(struct iio_dev *indio_dev,
+ const unsigned long *scan_mask)
+{
+ struct sx9500_data *data = iio_priv(indio_dev);
+
+ mutex_lock(&data->mutex);
+ kfree(data->buffer);
+ data->buffer = kzalloc(indio_dev->scan_bytes, GFP_KERNEL);
+ mutex_unlock(&data->mutex);
+
+ if (data->buffer == NULL)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static IIO_CONST_ATTR_SAMP_FREQ_AVAIL(
+ "2.500000 3.333333 5 6.666666 8.333333 11.111111 16.666666 33.333333");
+
+static struct attribute *sx9500_attributes[] = {
+ &iio_const_attr_sampling_frequency_available.dev_attr.attr,
+ NULL,
+};
+
+static const struct attribute_group sx9500_attribute_group = {
+ .attrs = sx9500_attributes,
+};
+
+static const struct iio_info sx9500_info = {
+ .driver_module = THIS_MODULE,
+ .attrs = &sx9500_attribute_group,
+ .read_raw = &sx9500_read_raw,
+ .write_raw = &sx9500_write_raw,
+ .read_event_config = &sx9500_read_event_config,
+ .write_event_config = &sx9500_write_event_config,
+ .update_scan_mode = &sx9500_update_scan_mode,
+};
+
+static int sx9500_set_trigger_state(struct iio_trigger *trig,
+ bool state)
+{
+ struct iio_dev *indio_dev = iio_trigger_get_drvdata(trig);
+ struct sx9500_data *data = iio_priv(indio_dev);
+ int ret;
+
+ mutex_lock(&data->mutex);
+
+ ret = regmap_update_bits(data->regmap, SX9500_REG_IRQ_MSK,
+ SX9500_CONVDONE_IRQ,
+ state ? SX9500_CONVDONE_IRQ : 0);
+ if (ret == 0)
+ data->trigger_enabled = state;
+
+ mutex_unlock(&data->mutex);
+
+ return ret;
+}
+
+static const struct iio_trigger_ops sx9500_trigger_ops = {
+ .set_trigger_state = sx9500_set_trigger_state,
+ .owner = THIS_MODULE,
+};
+
+static irqreturn_t sx9500_trigger_handler(int irq, void *private)
+{
+ struct iio_poll_func *pf = private;
+ struct iio_dev *indio_dev = pf->indio_dev;
+ struct sx9500_data *data = iio_priv(indio_dev);
+ int val, bit, ret, i = 0;
+
+ mutex_lock(&data->mutex);
+
+ for_each_set_bit(bit, indio_dev->buffer->scan_mask,
+ indio_dev->masklength) {
+ ret = sx9500_read_proximity(data, &indio_dev->channels[bit],
+ &val);
+ if (ret < 0)
+ goto out;
+
+ data->buffer[i++] = val;
+ }
+
+ iio_push_to_buffers_with_timestamp(indio_dev, data->buffer,
+ iio_get_time_ns());
+
+out:
+ mutex_unlock(&data->mutex);
+
+ iio_trigger_notify_done(indio_dev->trig);
+
+ return IRQ_HANDLED;
+}
+
+struct sx9500_reg_default {
+ u8 reg;
+ u8 def;
+};
+
+static const struct sx9500_reg_default sx9500_default_regs[] = {
+ {
+ .reg = SX9500_REG_PROX_CTRL1,
+ /* Shield enabled, small range. */
+ .def = 0x43,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL2,
+ /* x8 gain, 167kHz frequency, finest resolution. */
+ .def = 0x77,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL3,
+ /* Doze enabled, 2x scan period doze, no raw filter. */
+ .def = 0x40,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL4,
+ /* Average threshold. */
+ .def = 0x30,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL5,
+ /*
+ * Debouncer off, lowest average negative filter,
+ * highest average postive filter.
+ */
+ .def = 0x0f,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL6,
+ /* Proximity detection threshold: 280 */
+ .def = 0x0e,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL7,
+ /*
+ * No automatic compensation, compensate each pin
+ * independently, proximity hysteresis: 32, close
+ * debouncer off, far debouncer off.
+ */
+ .def = 0x00,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL8,
+ /* No stuck timeout, no periodic compensation. */
+ .def = 0x00,
+ },
+ {
+ .reg = SX9500_REG_PROX_CTRL0,
+ /* Scan period: 30ms, all sensors enabled. */
+ .def = 0x0f,
+ },
+};
+
+static int sx9500_init_device(struct iio_dev *indio_dev)
+{
+ struct sx9500_data *data = iio_priv(indio_dev);
+ int ret, i;
+ unsigned int val;
+
+ ret = regmap_write(data->regmap, SX9500_REG_IRQ_MSK, 0);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_write(data->regmap, SX9500_REG_RESET,
+ SX9500_SOFT_RESET);
+ if (ret < 0)
+ return ret;
+
+ ret = regmap_read(data->regmap, SX9500_REG_IRQ_SRC, &val);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < ARRAY_SIZE(sx9500_default_regs); i++) {
+ ret = regmap_write(data->regmap,
+ sx9500_default_regs[i].reg,
+ sx9500_default_regs[i].def);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sx9500_gpio_probe(struct i2c_client *client,
+ struct sx9500_data *data)
+{
+ struct device *dev;
+ struct gpio_desc *gpio;
+ int ret;
+
+ if (!client)
+ return -EINVAL;
+
+ dev = &client->dev;
+
+ /* data ready gpio interrupt pin */
+ gpio = devm_gpiod_get_index(dev, SX9500_GPIO_NAME, 0);
+ if (IS_ERR(gpio)) {
+ dev_err(dev, "acpi gpio get index failed\n");
+ return PTR_ERR(gpio);
+ }
+
+ ret = gpiod_direction_input(gpio);
+ if (ret)
+ return ret;
+
+ ret = gpiod_to_irq(gpio);
+
+ dev_dbg(dev, "GPIO resource, no:%d irq:%d\n", desc_to_gpio(gpio), ret);
+
+ return ret;
+}
+
+static int sx9500_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret;
+ struct iio_dev *indio_dev;
+ struct sx9500_data *data;
+
+ indio_dev = devm_iio_device_alloc(&client->dev, sizeof(*data));
+ if (indio_dev == NULL)
+ return -ENOMEM;
+
+ data = iio_priv(indio_dev);
+ data->client = client;
+ mutex_init(&data->mutex);
+ data->trigger_enabled = false;
+
+ data->regmap = devm_regmap_init_i2c(client, &sx9500_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ sx9500_init_device(indio_dev);
+
+ indio_dev->dev.parent = &client->dev;
+ indio_dev->name = SX9500_DRIVER_NAME;
+ indio_dev->channels = sx9500_channels;
+ indio_dev->num_channels = ARRAY_SIZE(sx9500_channels);
+ indio_dev->info = &sx9500_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ i2c_set_clientdata(client, indio_dev);
+
+ if (client->irq <= 0)
+ client->irq = sx9500_gpio_probe(client, data);
+
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(&client->dev, client->irq,
+ sx9500_irq_handler, sx9500_irq_thread_handler,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ SX9500_IRQ_NAME, indio_dev);
+ if (ret < 0)
+ return ret;
+
+ data->trig = devm_iio_trigger_alloc(&client->dev,
+ "%s-dev%d", indio_dev->name, indio_dev->id);
+ if (!data->trig)
+ return -ENOMEM;
+
+ data->trig->dev.parent = &client->dev;
+ data->trig->ops = &sx9500_trigger_ops;
+ iio_trigger_set_drvdata(data->trig, indio_dev);
+
+ ret = iio_trigger_register(data->trig);
+ if (ret)
+ return ret;
+ }
+
+ ret = iio_triggered_buffer_setup(indio_dev, NULL,
+ sx9500_trigger_handler, NULL);
+ if (ret < 0)
+ goto out_trigger_unregister;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0)
+ goto out_buffer_cleanup;
+
+ return 0;
+
+out_buffer_cleanup:
+ iio_triggered_buffer_cleanup(indio_dev);
+out_trigger_unregister:
+ if (client->irq > 0)
+ iio_trigger_unregister(data->trig);
+
+ return ret;
+}
+
+static int sx9500_remove(struct i2c_client *client)
+{
+ struct iio_dev *indio_dev = i2c_get_clientdata(client);
+ struct sx9500_data *data = iio_priv(indio_dev);
+
+ iio_device_unregister(indio_dev);
+ iio_triggered_buffer_cleanup(indio_dev);
+ if (client->irq > 0)
+ iio_trigger_unregister(data->trig);
+ kfree(data->buffer);
+
+ return 0;
+}
+
+static const struct acpi_device_id sx9500_acpi_match[] = {
+ {"SSX9500", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, sx9500_acpi_match);
+
+static const struct i2c_device_id sx9500_id[] = {
+ {"sx9500", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, sx9500_id);
+
+static struct i2c_driver sx9500_driver = {
+ .driver = {
+ .name = SX9500_DRIVER_NAME,
+ .acpi_match_table = ACPI_PTR(sx9500_acpi_match),
+ },
+ .probe = sx9500_probe,
+ .remove = sx9500_remove,
+ .id_table = sx9500_id,
+};
+module_i2c_driver(sx9500_driver);
+
+MODULE_AUTHOR("Vlad Dogaru <vlad.dogaru@intel.com>");
+MODULE_DESCRIPTION("Driver for Semtech SX9500 proximity sensor");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/iio/trigger/iio-trig-sysfs.c b/drivers/iio/trigger/iio-trig-sysfs.c
index 254c7e906127..3dfab2bc6d69 100644
--- a/drivers/iio/trigger/iio-trig-sysfs.c
+++ b/drivers/iio/trigger/iio-trig-sysfs.c
@@ -135,6 +135,7 @@ static int iio_sysfs_trigger_probe(int id)
struct iio_sysfs_trig *t;
int ret;
bool foundit = false;
+
mutex_lock(&iio_sysfs_trig_list_mut);
list_for_each_entry(t, &iio_sysfs_trig_list, l)
if (id == t->id) {
@@ -185,6 +186,7 @@ static int iio_sysfs_trigger_remove(int id)
{
bool foundit = false;
struct iio_sysfs_trig *t;
+
mutex_lock(&iio_sysfs_trig_list_mut);
list_for_each_entry(t, &iio_sysfs_trig_list, l)
if (id == t->id) {
diff --git a/drivers/infiniband/core/ucma.c b/drivers/infiniband/core/ucma.c
index 56a4b7ca7ee3..45d67e9228d7 100644
--- a/drivers/infiniband/core/ucma.c
+++ b/drivers/infiniband/core/ucma.c
@@ -1124,6 +1124,9 @@ static int ucma_set_ib_path(struct ucma_context *ctx,
if (!optlen)
return -EINVAL;
+ memset(&sa_path, 0, sizeof(sa_path));
+ sa_path.vlan_id = 0xffff;
+
ib_sa_unpack_path(path_data->path_rec, &sa_path);
ret = rdma_set_ib_paths(ctx->cm_id, &sa_path, 1);
if (ret)
diff --git a/drivers/infiniband/core/umem_odp.c b/drivers/infiniband/core/umem_odp.c
index 6095872549e7..8b8cc6fa0ab0 100644
--- a/drivers/infiniband/core/umem_odp.c
+++ b/drivers/infiniband/core/umem_odp.c
@@ -294,7 +294,8 @@ int ib_umem_odp_get(struct ib_ucontext *context, struct ib_umem *umem)
if (likely(ib_umem_start(umem) != ib_umem_end(umem)))
rbt_ib_umem_insert(&umem->odp_data->interval_tree,
&context->umem_tree);
- if (likely(!atomic_read(&context->notifier_count)))
+ if (likely(!atomic_read(&context->notifier_count)) ||
+ context->odp_mrs_count == 1)
umem->odp_data->mn_counters_active = true;
else
list_add(&umem->odp_data->no_private_counters,
diff --git a/drivers/infiniband/core/uverbs_cmd.c b/drivers/infiniband/core/uverbs_cmd.c
index 532d8eba8b02..a9f048990dfc 100644
--- a/drivers/infiniband/core/uverbs_cmd.c
+++ b/drivers/infiniband/core/uverbs_cmd.c
@@ -2097,20 +2097,21 @@ ssize_t ib_uverbs_modify_qp(struct ib_uverbs_file *file,
if (qp->real_qp == qp) {
ret = ib_resolve_eth_l2_attrs(qp, attr, &cmd.attr_mask);
if (ret)
- goto out;
+ goto release_qp;
ret = qp->device->modify_qp(qp, attr,
modify_qp_mask(qp->qp_type, cmd.attr_mask), &udata);
} else {
ret = ib_modify_qp(qp, attr, modify_qp_mask(qp->qp_type, cmd.attr_mask));
}
- put_qp_read(qp);
-
if (ret)
- goto out;
+ goto release_qp;
ret = in_len;
+release_qp:
+ put_qp_read(qp);
+
out:
kfree(attr);
@@ -3312,31 +3313,43 @@ int ib_uverbs_ex_query_device(struct ib_uverbs_file *file,
if (err)
return err;
+ if (cmd.comp_mask)
+ return -EINVAL;
+
if (cmd.reserved)
return -EINVAL;
+ resp.response_length = offsetof(typeof(resp), odp_caps);
+
+ if (ucore->outlen < resp.response_length)
+ return -ENOSPC;
+
err = device->query_device(device, &attr);
if (err)
return err;
- memset(&resp, 0, sizeof(resp));
copy_query_dev_fields(file, &resp.base, &attr);
resp.comp_mask = 0;
+ if (ucore->outlen < resp.response_length + sizeof(resp.odp_caps))
+ goto end;
+
#ifdef CONFIG_INFINIBAND_ON_DEMAND_PAGING
- if (cmd.comp_mask & IB_USER_VERBS_EX_QUERY_DEVICE_ODP) {
- resp.odp_caps.general_caps = attr.odp_caps.general_caps;
- resp.odp_caps.per_transport_caps.rc_odp_caps =
- attr.odp_caps.per_transport_caps.rc_odp_caps;
- resp.odp_caps.per_transport_caps.uc_odp_caps =
- attr.odp_caps.per_transport_caps.uc_odp_caps;
- resp.odp_caps.per_transport_caps.ud_odp_caps =
- attr.odp_caps.per_transport_caps.ud_odp_caps;
- resp.comp_mask |= IB_USER_VERBS_EX_QUERY_DEVICE_ODP;
- }
+ resp.odp_caps.general_caps = attr.odp_caps.general_caps;
+ resp.odp_caps.per_transport_caps.rc_odp_caps =
+ attr.odp_caps.per_transport_caps.rc_odp_caps;
+ resp.odp_caps.per_transport_caps.uc_odp_caps =
+ attr.odp_caps.per_transport_caps.uc_odp_caps;
+ resp.odp_caps.per_transport_caps.ud_odp_caps =
+ attr.odp_caps.per_transport_caps.ud_odp_caps;
+ resp.odp_caps.reserved = 0;
+#else
+ memset(&resp.odp_caps, 0, sizeof(resp.odp_caps));
#endif
+ resp.response_length += sizeof(resp.odp_caps);
- err = ib_copy_to_udata(ucore, &resp, sizeof(resp));
+end:
+ err = ib_copy_to_udata(ucore, &resp, resp.response_length);
if (err)
return err;
diff --git a/drivers/infiniband/core/uverbs_main.c b/drivers/infiniband/core/uverbs_main.c
index e6c23b9eab33..259dcc7779f5 100644
--- a/drivers/infiniband/core/uverbs_main.c
+++ b/drivers/infiniband/core/uverbs_main.c
@@ -123,7 +123,7 @@ static int (*uverbs_ex_cmd_table[])(struct ib_uverbs_file *file,
struct ib_udata *uhw) = {
[IB_USER_VERBS_EX_CMD_CREATE_FLOW] = ib_uverbs_ex_create_flow,
[IB_USER_VERBS_EX_CMD_DESTROY_FLOW] = ib_uverbs_ex_destroy_flow,
- [IB_USER_VERBS_EX_CMD_QUERY_DEVICE] = ib_uverbs_ex_query_device
+ [IB_USER_VERBS_EX_CMD_QUERY_DEVICE] = ib_uverbs_ex_query_device,
};
static void ib_uverbs_add_one(struct ib_device *device);
diff --git a/drivers/infiniband/hw/cxgb4/cm.c b/drivers/infiniband/hw/cxgb4/cm.c
index 9edc200b311d..57176ddd4c50 100644
--- a/drivers/infiniband/hw/cxgb4/cm.c
+++ b/drivers/infiniband/hw/cxgb4/cm.c
@@ -235,19 +235,19 @@ static void release_tid(struct c4iw_rdev *rdev, u32 hwtid, struct sk_buff *skb)
static void set_emss(struct c4iw_ep *ep, u16 opt)
{
- ep->emss = ep->com.dev->rdev.lldi.mtus[GET_TCPOPT_MSS(opt)] -
+ ep->emss = ep->com.dev->rdev.lldi.mtus[TCPOPT_MSS_G(opt)] -
((AF_INET == ep->com.remote_addr.ss_family) ?
sizeof(struct iphdr) : sizeof(struct ipv6hdr)) -
sizeof(struct tcphdr);
ep->mss = ep->emss;
- if (GET_TCPOPT_TSTAMP(opt))
+ if (TCPOPT_TSTAMP_G(opt))
ep->emss -= round_up(TCPOLEN_TIMESTAMP, 4);
if (ep->emss < 128)
ep->emss = 128;
if (ep->emss & 7)
PDBG("Warning: misaligned mtu idx %u mss %u emss=%u\n",
- GET_TCPOPT_MSS(opt), ep->mss, ep->emss);
- PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, GET_TCPOPT_MSS(opt),
+ TCPOPT_MSS_G(opt), ep->mss, ep->emss);
+ PDBG("%s mss_idx %u mss %u emss=%u\n", __func__, TCPOPT_MSS_G(opt),
ep->mss, ep->emss);
}
@@ -652,29 +652,29 @@ static int send_connect(struct c4iw_ep *ep)
if (win > RCV_BUFSIZ_M)
win = RCV_BUFSIZ_M;
- opt0 = (nocong ? NO_CONG(1) : 0) |
+ opt0 = (nocong ? NO_CONG_F : 0) |
KEEP_ALIVE_F |
- DELACK(1) |
+ DELACK_F |
WND_SCALE_V(wscale) |
MSS_IDX_V(mtu_idx) |
L2T_IDX_V(ep->l2t->idx) |
TX_CHAN_V(ep->tx_chan) |
SMAC_SEL_V(ep->smac_idx) |
- DSCP(ep->tos) |
+ DSCP_V(ep->tos) |
ULP_MODE_V(ULP_MODE_TCPDDP) |
RCV_BUFSIZ_V(win);
opt2 = RX_CHANNEL_V(0) |
- CCTRL_ECN(enable_ecn) |
+ CCTRL_ECN_V(enable_ecn) |
RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
if (enable_tcp_timestamps)
- opt2 |= TSTAMPS_EN(1);
+ opt2 |= TSTAMPS_EN_F;
if (enable_tcp_sack)
- opt2 |= SACK_EN(1);
+ opt2 |= SACK_EN_F;
if (wscale && enable_tcp_window_scaling)
opt2 |= WND_SCALE_EN_F;
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
opt2 |= T5_OPT_2_VALID_F;
- opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
+ opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
}
t4_set_arp_err_handler(skb, ep, act_open_req_arp_failure);
@@ -1042,7 +1042,7 @@ static int act_establish(struct c4iw_dev *dev, struct sk_buff *skb)
struct c4iw_ep *ep;
struct cpl_act_establish *req = cplhdr(skb);
unsigned int tid = GET_TID(req);
- unsigned int atid = GET_TID_TID(ntohl(req->tos_atid));
+ unsigned int atid = TID_TID_G(ntohl(req->tos_atid));
struct tid_info *t = dev->rdev.lldi.tids;
ep = lookup_atid(t, atid);
@@ -1258,8 +1258,8 @@ static int update_rx_credits(struct c4iw_ep *ep, u32 credits)
OPCODE_TID(req) = cpu_to_be32(MK_OPCODE_TID(CPL_RX_DATA_ACK,
ep->hwtid));
req->credit_dack = cpu_to_be32(credits | RX_FORCE_ACK_F |
- F_RX_DACK_CHANGE |
- V_RX_DACK_MODE(dack_mode));
+ RX_DACK_CHANGE_F |
+ RX_DACK_MODE_V(dack_mode));
set_wr_txq(skb, CPL_PRIORITY_ACK, ep->ctrlq_idx);
c4iw_ofld_send(&ep->com.dev->rdev, skb);
return credits;
@@ -1751,7 +1751,7 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
skb = get_skb(NULL, sizeof(*req), GFP_KERNEL);
req = (struct fw_ofld_connection_wr *)__skb_put(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
- req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR));
+ req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR));
req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
req->le.filter = cpu_to_be32(cxgb4_select_ntuple(
ep->com.dev->rdev.lldi.ports[0],
@@ -1782,27 +1782,27 @@ static void send_fw_act_open_req(struct c4iw_ep *ep, unsigned int atid)
if (win > RCV_BUFSIZ_M)
win = RCV_BUFSIZ_M;
- req->tcb.opt0 = (__force __be64) (TCAM_BYPASS(1) |
- (nocong ? NO_CONG(1) : 0) |
+ req->tcb.opt0 = (__force __be64) (TCAM_BYPASS_F |
+ (nocong ? NO_CONG_F : 0) |
KEEP_ALIVE_F |
- DELACK(1) |
+ DELACK_F |
WND_SCALE_V(wscale) |
MSS_IDX_V(mtu_idx) |
L2T_IDX_V(ep->l2t->idx) |
TX_CHAN_V(ep->tx_chan) |
SMAC_SEL_V(ep->smac_idx) |
- DSCP(ep->tos) |
+ DSCP_V(ep->tos) |
ULP_MODE_V(ULP_MODE_TCPDDP) |
RCV_BUFSIZ_V(win));
- req->tcb.opt2 = (__force __be32) (PACE(1) |
- TX_QUEUE(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
+ req->tcb.opt2 = (__force __be32) (PACE_V(1) |
+ TX_QUEUE_V(ep->com.dev->rdev.lldi.tx_modq[ep->tx_chan]) |
RX_CHANNEL_V(0) |
- CCTRL_ECN(enable_ecn) |
+ CCTRL_ECN_V(enable_ecn) |
RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid));
if (enable_tcp_timestamps)
- req->tcb.opt2 |= (__force __be32)TSTAMPS_EN(1);
+ req->tcb.opt2 |= (__force __be32)TSTAMPS_EN_F;
if (enable_tcp_sack)
- req->tcb.opt2 |= (__force __be32)SACK_EN(1);
+ req->tcb.opt2 |= (__force __be32)SACK_EN_F;
if (wscale && enable_tcp_window_scaling)
req->tcb.opt2 |= (__force __be32)WND_SCALE_EN_F;
req->tcb.opt0 = cpu_to_be64((__force u64)req->tcb.opt0);
@@ -2023,10 +2023,10 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
{
struct c4iw_ep *ep;
struct cpl_act_open_rpl *rpl = cplhdr(skb);
- unsigned int atid = GET_TID_TID(GET_AOPEN_ATID(
- ntohl(rpl->atid_status)));
+ unsigned int atid = TID_TID_G(AOPEN_ATID_G(
+ ntohl(rpl->atid_status)));
struct tid_info *t = dev->rdev.lldi.tids;
- int status = GET_AOPEN_STATUS(ntohl(rpl->atid_status));
+ int status = AOPEN_STATUS_G(ntohl(rpl->atid_status));
struct sockaddr_in *la;
struct sockaddr_in *ra;
struct sockaddr_in6 *la6;
@@ -2064,7 +2064,7 @@ static int act_open_rpl(struct c4iw_dev *dev, struct sk_buff *skb)
if (ep->com.local_addr.ss_family == AF_INET &&
dev->rdev.lldi.enable_fw_ofld_conn) {
send_fw_act_open_req(ep,
- GET_TID_TID(GET_AOPEN_ATID(
+ TID_TID_G(AOPEN_ATID_G(
ntohl(rpl->atid_status))));
return 0;
}
@@ -2181,39 +2181,39 @@ static void accept_cr(struct c4iw_ep *ep, struct sk_buff *skb,
win = ep->rcv_win >> 10;
if (win > RCV_BUFSIZ_M)
win = RCV_BUFSIZ_M;
- opt0 = (nocong ? NO_CONG(1) : 0) |
+ opt0 = (nocong ? NO_CONG_F : 0) |
KEEP_ALIVE_F |
- DELACK(1) |
+ DELACK_F |
WND_SCALE_V(wscale) |
MSS_IDX_V(mtu_idx) |
L2T_IDX_V(ep->l2t->idx) |
TX_CHAN_V(ep->tx_chan) |
SMAC_SEL_V(ep->smac_idx) |
- DSCP(ep->tos >> 2) |
+ DSCP_V(ep->tos >> 2) |
ULP_MODE_V(ULP_MODE_TCPDDP) |
RCV_BUFSIZ_V(win);
opt2 = RX_CHANNEL_V(0) |
RSS_QUEUE_VALID_F | RSS_QUEUE_V(ep->rss_qid);
if (enable_tcp_timestamps && req->tcpopt.tstamp)
- opt2 |= TSTAMPS_EN(1);
+ opt2 |= TSTAMPS_EN_F;
if (enable_tcp_sack && req->tcpopt.sack)
- opt2 |= SACK_EN(1);
+ opt2 |= SACK_EN_F;
if (wscale && enable_tcp_window_scaling)
opt2 |= WND_SCALE_EN_F;
if (enable_ecn) {
const struct tcphdr *tcph;
u32 hlen = ntohl(req->hdr_len);
- tcph = (const void *)(req + 1) + G_ETH_HDR_LEN(hlen) +
- G_IP_HDR_LEN(hlen);
+ tcph = (const void *)(req + 1) + ETH_HDR_LEN_G(hlen) +
+ IP_HDR_LEN_G(hlen);
if (tcph->ece && tcph->cwr)
- opt2 |= CCTRL_ECN(1);
+ opt2 |= CCTRL_ECN_V(1);
}
if (is_t5(ep->com.dev->rdev.lldi.adapter_type)) {
u32 isn = (prandom_u32() & ~7UL) - 1;
opt2 |= T5_OPT_2_VALID_F;
- opt2 |= V_CONG_CNTRL(CONG_ALG_TAHOE);
+ opt2 |= CONG_CNTRL_V(CONG_ALG_TAHOE);
opt2 |= CONG_CNTRL_VALID; /* OPT_2_ISS for T5 */
rpl5 = (void *)rpl;
memset(&rpl5->iss, 0, roundup(sizeof(*rpl5)-sizeof(*rpl), 16));
@@ -2245,8 +2245,8 @@ static void get_4tuple(struct cpl_pass_accept_req *req, int *iptype,
__u8 *local_ip, __u8 *peer_ip,
__be16 *local_port, __be16 *peer_port)
{
- int eth_len = G_ETH_HDR_LEN(be32_to_cpu(req->hdr_len));
- int ip_len = G_IP_HDR_LEN(be32_to_cpu(req->hdr_len));
+ int eth_len = ETH_HDR_LEN_G(be32_to_cpu(req->hdr_len));
+ int ip_len = IP_HDR_LEN_G(be32_to_cpu(req->hdr_len));
struct iphdr *ip = (struct iphdr *)((u8 *)(req + 1) + eth_len);
struct ipv6hdr *ip6 = (struct ipv6hdr *)((u8 *)(req + 1) + eth_len);
struct tcphdr *tcp = (struct tcphdr *)
@@ -2277,7 +2277,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
{
struct c4iw_ep *child_ep = NULL, *parent_ep;
struct cpl_pass_accept_req *req = cplhdr(skb);
- unsigned int stid = GET_POPEN_TID(ntohl(req->tos_stid));
+ unsigned int stid = PASS_OPEN_TID_G(ntohl(req->tos_stid));
struct tid_info *t = dev->rdev.lldi.tids;
unsigned int hwtid = GET_TID(req);
struct dst_entry *dst;
@@ -2310,14 +2310,14 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
ntohs(peer_port), peer_mss);
dst = find_route(dev, *(__be32 *)local_ip, *(__be32 *)peer_ip,
local_port, peer_port,
- GET_POPEN_TOS(ntohl(req->tos_stid)));
+ PASS_OPEN_TOS_G(ntohl(req->tos_stid)));
} else {
PDBG("%s parent ep %p hwtid %u laddr %pI6 raddr %pI6 lport %d rport %d peer_mss %d\n"
, __func__, parent_ep, hwtid,
local_ip, peer_ip, ntohs(local_port),
ntohs(peer_port), peer_mss);
dst = find_route6(dev, local_ip, peer_ip, local_port, peer_port,
- PASS_OPEN_TOS(ntohl(req->tos_stid)),
+ PASS_OPEN_TOS_G(ntohl(req->tos_stid)),
((struct sockaddr_in6 *)
&parent_ep->com.local_addr)->sin6_scope_id);
}
@@ -2375,7 +2375,7 @@ static int pass_accept_req(struct c4iw_dev *dev, struct sk_buff *skb)
}
c4iw_get_ep(&parent_ep->com);
child_ep->parent_ep = parent_ep;
- child_ep->tos = GET_POPEN_TOS(ntohl(req->tos_stid));
+ child_ep->tos = PASS_OPEN_TOS_G(ntohl(req->tos_stid));
child_ep->dst = dst;
child_ep->hwtid = hwtid;
@@ -3500,24 +3500,24 @@ static void build_cpl_pass_accept_req(struct sk_buff *skb, int stid , u8 tos)
req = (struct cpl_pass_accept_req *)__skb_push(skb, sizeof(*req));
memset(req, 0, sizeof(*req));
- req->l2info = cpu_to_be16(V_SYN_INTF(intf) |
- V_SYN_MAC_IDX(G_RX_MACIDX(
+ req->l2info = cpu_to_be16(SYN_INTF_V(intf) |
+ SYN_MAC_IDX_V(RX_MACIDX_G(
(__force int) htonl(l2info))) |
- F_SYN_XACT_MATCH);
+ SYN_XACT_MATCH_F);
eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ?
- G_RX_ETHHDR_LEN((__force int) htonl(l2info)) :
- G_RX_T5_ETHHDR_LEN((__force int) htonl(l2info));
- req->hdr_len = cpu_to_be32(V_SYN_RX_CHAN(G_RX_CHAN(
+ RX_ETHHDR_LEN_G((__force int)htonl(l2info)) :
+ RX_T5_ETHHDR_LEN_G((__force int)htonl(l2info));
+ req->hdr_len = cpu_to_be32(SYN_RX_CHAN_V(RX_CHAN_G(
(__force int) htonl(l2info))) |
- V_TCP_HDR_LEN(G_RX_TCPHDR_LEN(
+ TCP_HDR_LEN_V(RX_TCPHDR_LEN_G(
(__force int) htons(hdr_len))) |
- V_IP_HDR_LEN(G_RX_IPHDR_LEN(
+ IP_HDR_LEN_V(RX_IPHDR_LEN_G(
(__force int) htons(hdr_len))) |
- V_ETH_HDR_LEN(G_RX_ETHHDR_LEN(eth_hdr_len)));
+ ETH_HDR_LEN_V(RX_ETHHDR_LEN_G(eth_hdr_len)));
req->vlan = (__force __be16) vlantag;
req->len = (__force __be16) len;
- req->tos_stid = cpu_to_be32(PASS_OPEN_TID(stid) |
- PASS_OPEN_TOS(tos));
+ req->tos_stid = cpu_to_be32(PASS_OPEN_TID_V(stid) |
+ PASS_OPEN_TOS_V(tos));
req->tcpopt.mss = htons(tmp_opt.mss_clamp);
if (tmp_opt.wscale_ok)
req->tcpopt.wsf = tmp_opt.snd_wscale;
@@ -3542,7 +3542,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
req_skb = alloc_skb(sizeof(struct fw_ofld_connection_wr), GFP_KERNEL);
req = (struct fw_ofld_connection_wr *)__skb_put(req_skb, sizeof(*req));
memset(req, 0, sizeof(*req));
- req->op_compl = htonl(V_WR_OP(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F);
+ req->op_compl = htonl(WR_OP_V(FW_OFLD_CONNECTION_WR) | FW_WR_COMPL_F);
req->len16_pkd = htonl(FW_WR_LEN16_V(DIV_ROUND_UP(sizeof(*req), 16)));
req->le.version_cpl = htonl(FW_OFLD_CONNECTION_WR_CPL_F);
req->le.filter = (__force __be32) filter;
@@ -3556,7 +3556,7 @@ static void send_fw_pass_open_req(struct c4iw_dev *dev, struct sk_buff *skb,
htonl(FW_OFLD_CONNECTION_WR_T_STATE_V(TCP_SYN_RECV) |
FW_OFLD_CONNECTION_WR_RCV_SCALE_V(cpl->tcpopt.wsf) |
FW_OFLD_CONNECTION_WR_ASTID_V(
- GET_PASS_OPEN_TID(ntohl(cpl->tos_stid))));
+ PASS_OPEN_TID_G(ntohl(cpl->tos_stid))));
/*
* We store the qid in opt2 which will be used by the firmware
@@ -3613,7 +3613,7 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
struct neighbour *neigh;
/* Drop all non-SYN packets */
- if (!(cpl->l2info & cpu_to_be32(F_RXF_SYN)))
+ if (!(cpl->l2info & cpu_to_be32(RXF_SYN_F)))
goto reject;
/*
@@ -3635,8 +3635,8 @@ static int rx_pkt(struct c4iw_dev *dev, struct sk_buff *skb)
}
eth_hdr_len = is_t4(dev->rdev.lldi.adapter_type) ?
- G_RX_ETHHDR_LEN(htonl(cpl->l2info)) :
- G_RX_T5_ETHHDR_LEN(htonl(cpl->l2info));
+ RX_ETHHDR_LEN_G(htonl(cpl->l2info)) :
+ RX_T5_ETHHDR_LEN_G(htonl(cpl->l2info));
if (eth_hdr_len == ETH_HLEN) {
eh = (struct ethhdr *)(req + 1);
iph = (struct iphdr *)(eh + 1);
diff --git a/drivers/infiniband/hw/cxgb4/cq.c b/drivers/infiniband/hw/cxgb4/cq.c
index e9fd3a029296..ab7692ac2044 100644
--- a/drivers/infiniband/hw/cxgb4/cq.c
+++ b/drivers/infiniband/hw/cxgb4/cq.c
@@ -52,7 +52,7 @@ static int destroy_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
memset(res_wr, 0, wr_len);
res_wr->op_nres = cpu_to_be32(
FW_WR_OP_V(FW_RI_RES_WR) |
- V_FW_RI_RES_WR_NRES(1) |
+ FW_RI_RES_WR_NRES_V(1) |
FW_WR_COMPL_F);
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
res_wr->cookie = (unsigned long) &wr_wait;
@@ -122,7 +122,7 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
memset(res_wr, 0, wr_len);
res_wr->op_nres = cpu_to_be32(
FW_WR_OP_V(FW_RI_RES_WR) |
- V_FW_RI_RES_WR_NRES(1) |
+ FW_RI_RES_WR_NRES_V(1) |
FW_WR_COMPL_F);
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
res_wr->cookie = (unsigned long) &wr_wait;
@@ -131,17 +131,17 @@ static int create_cq(struct c4iw_rdev *rdev, struct t4_cq *cq,
res->u.cq.op = FW_RI_RES_OP_WRITE;
res->u.cq.iqid = cpu_to_be32(cq->cqid);
res->u.cq.iqandst_to_iqandstindex = cpu_to_be32(
- V_FW_RI_RES_WR_IQANUS(0) |
- V_FW_RI_RES_WR_IQANUD(1) |
- F_FW_RI_RES_WR_IQANDST |
- V_FW_RI_RES_WR_IQANDSTINDEX(
+ FW_RI_RES_WR_IQANUS_V(0) |
+ FW_RI_RES_WR_IQANUD_V(1) |
+ FW_RI_RES_WR_IQANDST_F |
+ FW_RI_RES_WR_IQANDSTINDEX_V(
rdev->lldi.ciq_ids[cq->vector]));
res->u.cq.iqdroprss_to_iqesize = cpu_to_be16(
- F_FW_RI_RES_WR_IQDROPRSS |
- V_FW_RI_RES_WR_IQPCIECH(2) |
- V_FW_RI_RES_WR_IQINTCNTTHRESH(0) |
- F_FW_RI_RES_WR_IQO |
- V_FW_RI_RES_WR_IQESIZE(1));
+ FW_RI_RES_WR_IQDROPRSS_F |
+ FW_RI_RES_WR_IQPCIECH_V(2) |
+ FW_RI_RES_WR_IQINTCNTTHRESH_V(0) |
+ FW_RI_RES_WR_IQO_F |
+ FW_RI_RES_WR_IQESIZE_V(1));
res->u.cq.iqsize = cpu_to_be16(cq->size);
res->u.cq.iqaddr = cpu_to_be64(cq->dma_addr);
@@ -182,12 +182,12 @@ static void insert_recv_cqe(struct t4_wq *wq, struct t4_cq *cq)
PDBG("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__,
wq, cq, cq->sw_cidx, cq->sw_pidx);
memset(&cqe, 0, sizeof(cqe));
- cqe.header = cpu_to_be32(V_CQE_STATUS(T4_ERR_SWFLUSH) |
- V_CQE_OPCODE(FW_RI_SEND) |
- V_CQE_TYPE(0) |
- V_CQE_SWCQE(1) |
- V_CQE_QPID(wq->sq.qid));
- cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen));
+ cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
+ CQE_OPCODE_V(FW_RI_SEND) |
+ CQE_TYPE_V(0) |
+ CQE_SWCQE_V(1) |
+ CQE_QPID_V(wq->sq.qid));
+ cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
cq->sw_queue[cq->sw_pidx] = cqe;
t4_swcq_produce(cq);
}
@@ -215,13 +215,13 @@ static void insert_sq_cqe(struct t4_wq *wq, struct t4_cq *cq,
PDBG("%s wq %p cq %p sw_cidx %u sw_pidx %u\n", __func__,
wq, cq, cq->sw_cidx, cq->sw_pidx);
memset(&cqe, 0, sizeof(cqe));
- cqe.header = cpu_to_be32(V_CQE_STATUS(T4_ERR_SWFLUSH) |
- V_CQE_OPCODE(swcqe->opcode) |
- V_CQE_TYPE(1) |
- V_CQE_SWCQE(1) |
- V_CQE_QPID(wq->sq.qid));
+ cqe.header = cpu_to_be32(CQE_STATUS_V(T4_ERR_SWFLUSH) |
+ CQE_OPCODE_V(swcqe->opcode) |
+ CQE_TYPE_V(1) |
+ CQE_SWCQE_V(1) |
+ CQE_QPID_V(wq->sq.qid));
CQE_WRID_SQ_IDX(&cqe) = swcqe->idx;
- cqe.bits_type_ts = cpu_to_be64(V_CQE_GENBIT((u64)cq->gen));
+ cqe.bits_type_ts = cpu_to_be64(CQE_GENBIT_V((u64)cq->gen));
cq->sw_queue[cq->sw_pidx] = cqe;
t4_swcq_produce(cq);
}
@@ -284,7 +284,7 @@ static void flush_completed_wrs(struct t4_wq *wq, struct t4_cq *cq)
*/
PDBG("%s moving cqe into swcq sq idx %u cq idx %u\n",
__func__, cidx, cq->sw_pidx);
- swsqe->cqe.header |= htonl(V_CQE_SWCQE(1));
+ swsqe->cqe.header |= htonl(CQE_SWCQE_V(1));
cq->sw_queue[cq->sw_pidx] = swsqe->cqe;
t4_swcq_produce(cq);
swsqe->flushed = 1;
@@ -301,10 +301,10 @@ static void create_read_req_cqe(struct t4_wq *wq, struct t4_cqe *hw_cqe,
{
read_cqe->u.scqe.cidx = wq->sq.oldest_read->idx;
read_cqe->len = htonl(wq->sq.oldest_read->read_len);
- read_cqe->header = htonl(V_CQE_QPID(CQE_QPID(hw_cqe)) |
- V_CQE_SWCQE(SW_CQE(hw_cqe)) |
- V_CQE_OPCODE(FW_RI_READ_REQ) |
- V_CQE_TYPE(1));
+ read_cqe->header = htonl(CQE_QPID_V(CQE_QPID(hw_cqe)) |
+ CQE_SWCQE_V(SW_CQE(hw_cqe)) |
+ CQE_OPCODE_V(FW_RI_READ_REQ) |
+ CQE_TYPE_V(1));
read_cqe->bits_type_ts = hw_cqe->bits_type_ts;
}
@@ -400,7 +400,7 @@ void c4iw_flush_hw_cq(struct c4iw_cq *chp)
} else {
swcqe = &chp->cq.sw_queue[chp->cq.sw_pidx];
*swcqe = *hw_cqe;
- swcqe->header |= cpu_to_be32(V_CQE_SWCQE(1));
+ swcqe->header |= cpu_to_be32(CQE_SWCQE_V(1));
t4_swcq_produce(&chp->cq);
}
next_cqe:
@@ -576,7 +576,7 @@ static int poll_cq(struct t4_wq *wq, struct t4_cq *cq, struct t4_cqe *cqe,
}
if (unlikely((CQE_WRID_MSN(hw_cqe) != (wq->rq.msn)))) {
t4_set_wq_in_error(wq);
- hw_cqe->header |= htonl(V_CQE_STATUS(T4_ERR_MSN));
+ hw_cqe->header |= htonl(CQE_STATUS_V(T4_ERR_MSN));
goto proc_cqe;
}
goto proc_cqe;
diff --git a/drivers/infiniband/hw/cxgb4/device.c b/drivers/infiniband/hw/cxgb4/device.c
index eb5df4e62703..8fb295e4a9ab 100644
--- a/drivers/infiniband/hw/cxgb4/device.c
+++ b/drivers/infiniband/hw/cxgb4/device.c
@@ -380,12 +380,12 @@ static int dump_stag(int id, void *p, void *data)
"stag: idx 0x%x valid %d key 0x%x state %d pdid %d "
"perm 0x%x ps %d len 0x%llx va 0x%llx\n",
(u32)id<<8,
- G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)),
- G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)),
+ FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_STAGKEY_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid)),
+ FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid)),
((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo),
((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo));
if (cc < space)
@@ -700,37 +700,24 @@ static const struct file_operations ep_debugfs_fops = {
static int setup_debugfs(struct c4iw_dev *devp)
{
- struct dentry *de;
-
if (!devp->debugfs_root)
return -1;
- de = debugfs_create_file("qps", S_IWUSR, devp->debugfs_root,
- (void *)devp, &qp_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = 4096;
+ debugfs_create_file_size("qps", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &qp_debugfs_fops, 4096);
- de = debugfs_create_file("stags", S_IWUSR, devp->debugfs_root,
- (void *)devp, &stag_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = 4096;
+ debugfs_create_file_size("stags", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &stag_debugfs_fops, 4096);
- de = debugfs_create_file("stats", S_IWUSR, devp->debugfs_root,
- (void *)devp, &stats_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = 4096;
+ debugfs_create_file_size("stats", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &stats_debugfs_fops, 4096);
- de = debugfs_create_file("eps", S_IWUSR, devp->debugfs_root,
- (void *)devp, &ep_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = 4096;
+ debugfs_create_file_size("eps", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &ep_debugfs_fops, 4096);
- if (c4iw_wr_log) {
- de = debugfs_create_file("wr_log", S_IWUSR, devp->debugfs_root,
- (void *)devp, &wr_log_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = 4096;
- }
+ if (c4iw_wr_log)
+ debugfs_create_file_size("wr_log", S_IWUSR, devp->debugfs_root,
+ (void *)devp, &wr_log_debugfs_fops, 4096);
return 0;
}
diff --git a/drivers/infiniband/hw/cxgb4/ev.c b/drivers/infiniband/hw/cxgb4/ev.c
index c9df0549f51d..bdfac2ccb704 100644
--- a/drivers/infiniband/hw/cxgb4/ev.c
+++ b/drivers/infiniband/hw/cxgb4/ev.c
@@ -50,12 +50,12 @@ static void print_tpte(struct c4iw_dev *dev, u32 stag)
PDBG("stag idx 0x%x valid %d key 0x%x state %d pdid %d "
"perm 0x%x ps %d len 0x%llx va 0x%llx\n",
stag & 0xffffff00,
- G_FW_RI_TPTE_VALID(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_STAGKEY(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_STAGSTATE(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_PDID(ntohl(tpte.valid_to_pdid)),
- G_FW_RI_TPTE_PERM(ntohl(tpte.locread_to_qpid)),
- G_FW_RI_TPTE_PS(ntohl(tpte.locread_to_qpid)),
+ FW_RI_TPTE_VALID_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_STAGKEY_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_STAGSTATE_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_PDID_G(ntohl(tpte.valid_to_pdid)),
+ FW_RI_TPTE_PERM_G(ntohl(tpte.locread_to_qpid)),
+ FW_RI_TPTE_PS_G(ntohl(tpte.locread_to_qpid)),
((u64)ntohl(tpte.len_hi) << 32) | ntohl(tpte.len_lo),
((u64)ntohl(tpte.va_hi) << 32) | ntohl(tpte.va_lo_fbo));
}
@@ -225,13 +225,20 @@ int c4iw_ev_handler(struct c4iw_dev *dev, u32 qid)
struct c4iw_cq *chp;
unsigned long flag;
+ spin_lock_irqsave(&dev->lock, flag);
chp = get_chp(dev, qid);
if (chp) {
+ atomic_inc(&chp->refcnt);
+ spin_unlock_irqrestore(&dev->lock, flag);
t4_clear_cq_armed(&chp->cq);
spin_lock_irqsave(&chp->comp_handler_lock, flag);
(*chp->ibcq.comp_handler)(&chp->ibcq, chp->ibcq.cq_context);
spin_unlock_irqrestore(&chp->comp_handler_lock, flag);
- } else
+ if (atomic_dec_and_test(&chp->refcnt))
+ wake_up(&chp->wait);
+ } else {
PDBG("%s unknown cqid 0x%x\n", __func__, qid);
+ spin_unlock_irqrestore(&dev->lock, flag);
+ }
return 0;
}
diff --git a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
index b5678ac97393..d87e1650f643 100644
--- a/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
+++ b/drivers/infiniband/hw/cxgb4/iw_cxgb4.h
@@ -196,7 +196,7 @@ static inline int c4iw_num_stags(struct c4iw_rdev *rdev)
return (int)(rdev->lldi.vr->stag.size >> 5);
}
-#define C4IW_WR_TO (30*HZ)
+#define C4IW_WR_TO (60*HZ)
struct c4iw_wr_wait {
struct completion completion;
@@ -220,22 +220,21 @@ static inline int c4iw_wait_for_reply(struct c4iw_rdev *rdev,
u32 hwtid, u32 qpid,
const char *func)
{
- unsigned to = C4IW_WR_TO;
int ret;
- do {
- ret = wait_for_completion_timeout(&wr_waitp->completion, to);
- if (!ret) {
- printk(KERN_ERR MOD "%s - Device %s not responding - "
- "tid %u qpid %u\n", func,
- pci_name(rdev->lldi.pdev), hwtid, qpid);
- if (c4iw_fatal_error(rdev)) {
- wr_waitp->ret = -EIO;
- break;
- }
- to = to << 2;
- }
- } while (!ret);
+ if (c4iw_fatal_error(rdev)) {
+ wr_waitp->ret = -EIO;
+ goto out;
+ }
+
+ ret = wait_for_completion_timeout(&wr_waitp->completion, C4IW_WR_TO);
+ if (!ret) {
+ PDBG("%s - Device %s not responding (disabling device) - tid %u qpid %u\n",
+ func, pci_name(rdev->lldi.pdev), hwtid, qpid);
+ rdev->flags |= T4_FATAL_ERROR;
+ wr_waitp->ret = -EIO;
+ }
+out:
if (wr_waitp->ret)
PDBG("%s: FW reply %d tid %u qpid %u\n",
pci_name(rdev->lldi.pdev), wr_waitp->ret, hwtid, qpid);
diff --git a/drivers/infiniband/hw/cxgb4/mem.c b/drivers/infiniband/hw/cxgb4/mem.c
index cb43c2299ac0..6791fd16272c 100644
--- a/drivers/infiniband/hw/cxgb4/mem.c
+++ b/drivers/infiniband/hw/cxgb4/mem.c
@@ -86,14 +86,14 @@ static int _c4iw_write_mem_dma_aligned(struct c4iw_rdev *rdev, u32 addr,
req->wr.wr_lo = wait ? (__force __be64)(unsigned long) &wr_wait : 0L;
req->wr.wr_mid = cpu_to_be32(FW_WR_LEN16_V(DIV_ROUND_UP(wr_len, 16)));
req->cmd = cpu_to_be32(ULPTX_CMD_V(ULP_TX_MEM_WRITE));
- req->cmd |= cpu_to_be32(V_T5_ULP_MEMIO_ORDER(1));
+ req->cmd |= cpu_to_be32(T5_ULP_MEMIO_ORDER_V(1));
req->dlen = cpu_to_be32(ULP_MEMIO_DATA_LEN_V(len>>5));
req->len16 = cpu_to_be32(DIV_ROUND_UP(wr_len-sizeof(req->wr), 16));
req->lock_addr = cpu_to_be32(ULP_MEMIO_ADDR_V(addr));
sgl = (struct ulptx_sgl *)(req + 1);
sgl->cmd_nsge = cpu_to_be32(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
- ULPTX_NSGE(1));
+ ULPTX_NSGE_V(1));
sgl->len0 = cpu_to_be32(len);
sgl->addr0 = cpu_to_be64(data);
@@ -286,17 +286,17 @@ static int write_tpt_entry(struct c4iw_rdev *rdev, u32 reset_tpt_entry,
if (reset_tpt_entry)
memset(&tpt, 0, sizeof(tpt));
else {
- tpt.valid_to_pdid = cpu_to_be32(F_FW_RI_TPTE_VALID |
- V_FW_RI_TPTE_STAGKEY((*stag & M_FW_RI_TPTE_STAGKEY)) |
- V_FW_RI_TPTE_STAGSTATE(stag_state) |
- V_FW_RI_TPTE_STAGTYPE(type) | V_FW_RI_TPTE_PDID(pdid));
- tpt.locread_to_qpid = cpu_to_be32(V_FW_RI_TPTE_PERM(perm) |
- (bind_enabled ? F_FW_RI_TPTE_MWBINDEN : 0) |
- V_FW_RI_TPTE_ADDRTYPE((zbva ? FW_RI_ZERO_BASED_TO :
+ tpt.valid_to_pdid = cpu_to_be32(FW_RI_TPTE_VALID_F |
+ FW_RI_TPTE_STAGKEY_V((*stag & FW_RI_TPTE_STAGKEY_M)) |
+ FW_RI_TPTE_STAGSTATE_V(stag_state) |
+ FW_RI_TPTE_STAGTYPE_V(type) | FW_RI_TPTE_PDID_V(pdid));
+ tpt.locread_to_qpid = cpu_to_be32(FW_RI_TPTE_PERM_V(perm) |
+ (bind_enabled ? FW_RI_TPTE_MWBINDEN_F : 0) |
+ FW_RI_TPTE_ADDRTYPE_V((zbva ? FW_RI_ZERO_BASED_TO :
FW_RI_VA_BASED_TO))|
- V_FW_RI_TPTE_PS(page_size));
+ FW_RI_TPTE_PS_V(page_size));
tpt.nosnoop_pbladdr = !pbl_size ? 0 : cpu_to_be32(
- V_FW_RI_TPTE_PBLADDR(PBL_OFF(rdev, pbl_addr)>>3));
+ FW_RI_TPTE_PBLADDR_V(PBL_OFF(rdev, pbl_addr)>>3));
tpt.len_lo = cpu_to_be32((u32)(len & 0xffffffffUL));
tpt.va_hi = cpu_to_be32((u32)(to >> 32));
tpt.va_lo_fbo = cpu_to_be32((u32)(to & 0xffffffffUL));
diff --git a/drivers/infiniband/hw/cxgb4/qp.c b/drivers/infiniband/hw/cxgb4/qp.c
index bb85d479e66e..15cae5a31018 100644
--- a/drivers/infiniband/hw/cxgb4/qp.c
+++ b/drivers/infiniband/hw/cxgb4/qp.c
@@ -272,7 +272,7 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
memset(res_wr, 0, wr_len);
res_wr->op_nres = cpu_to_be32(
FW_WR_OP_V(FW_RI_RES_WR) |
- V_FW_RI_RES_WR_NRES(2) |
+ FW_RI_RES_WR_NRES_V(2) |
FW_WR_COMPL_F);
res_wr->len16_pkd = cpu_to_be32(DIV_ROUND_UP(wr_len, 16));
res_wr->cookie = (unsigned long) &wr_wait;
@@ -287,19 +287,19 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
rdev->hw_queue.t4_eq_status_entries;
res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
- V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */
- V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */
- V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */
- (t4_sq_onchip(&wq->sq) ? F_FW_RI_RES_WR_ONCHIP : 0) |
- V_FW_RI_RES_WR_IQID(scq->cqid));
+ FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */
+ FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */
+ FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */
+ (t4_sq_onchip(&wq->sq) ? FW_RI_RES_WR_ONCHIP_F : 0) |
+ FW_RI_RES_WR_IQID_V(scq->cqid));
res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
- V_FW_RI_RES_WR_DCAEN(0) |
- V_FW_RI_RES_WR_DCACPU(0) |
- V_FW_RI_RES_WR_FBMIN(2) |
- V_FW_RI_RES_WR_FBMAX(2) |
- V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
- V_FW_RI_RES_WR_CIDXFTHRESH(0) |
- V_FW_RI_RES_WR_EQSIZE(eqsize));
+ FW_RI_RES_WR_DCAEN_V(0) |
+ FW_RI_RES_WR_DCACPU_V(0) |
+ FW_RI_RES_WR_FBMIN_V(2) |
+ FW_RI_RES_WR_FBMAX_V(2) |
+ FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
+ FW_RI_RES_WR_CIDXFTHRESH_V(0) |
+ FW_RI_RES_WR_EQSIZE_V(eqsize));
res->u.sqrq.eqid = cpu_to_be32(wq->sq.qid);
res->u.sqrq.eqaddr = cpu_to_be64(wq->sq.dma_addr);
res++;
@@ -312,18 +312,18 @@ static int create_qp(struct c4iw_rdev *rdev, struct t4_wq *wq,
eqsize = wq->rq.size * T4_RQ_NUM_SLOTS +
rdev->hw_queue.t4_eq_status_entries;
res->u.sqrq.fetchszm_to_iqid = cpu_to_be32(
- V_FW_RI_RES_WR_HOSTFCMODE(0) | /* no host cidx updates */
- V_FW_RI_RES_WR_CPRIO(0) | /* don't keep in chip cache */
- V_FW_RI_RES_WR_PCIECHN(0) | /* set by uP at ri_init time */
- V_FW_RI_RES_WR_IQID(rcq->cqid));
+ FW_RI_RES_WR_HOSTFCMODE_V(0) | /* no host cidx updates */
+ FW_RI_RES_WR_CPRIO_V(0) | /* don't keep in chip cache */
+ FW_RI_RES_WR_PCIECHN_V(0) | /* set by uP at ri_init time */
+ FW_RI_RES_WR_IQID_V(rcq->cqid));
res->u.sqrq.dcaen_to_eqsize = cpu_to_be32(
- V_FW_RI_RES_WR_DCAEN(0) |
- V_FW_RI_RES_WR_DCACPU(0) |
- V_FW_RI_RES_WR_FBMIN(2) |
- V_FW_RI_RES_WR_FBMAX(2) |
- V_FW_RI_RES_WR_CIDXFTHRESHO(0) |
- V_FW_RI_RES_WR_CIDXFTHRESH(0) |
- V_FW_RI_RES_WR_EQSIZE(eqsize));
+ FW_RI_RES_WR_DCAEN_V(0) |
+ FW_RI_RES_WR_DCACPU_V(0) |
+ FW_RI_RES_WR_FBMIN_V(2) |
+ FW_RI_RES_WR_FBMAX_V(2) |
+ FW_RI_RES_WR_CIDXFTHRESHO_V(0) |
+ FW_RI_RES_WR_CIDXFTHRESH_V(0) |
+ FW_RI_RES_WR_EQSIZE_V(eqsize));
res->u.sqrq.eqid = cpu_to_be32(wq->rq.qid);
res->u.sqrq.eqaddr = cpu_to_be64(wq->rq.dma_addr);
@@ -444,19 +444,19 @@ static int build_rdma_send(struct t4_sq *sq, union t4_wr *wqe,
case IB_WR_SEND:
if (wr->send_flags & IB_SEND_SOLICITED)
wqe->send.sendop_pkd = cpu_to_be32(
- V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_SE));
+ FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE));
else
wqe->send.sendop_pkd = cpu_to_be32(
- V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND));
+ FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND));
wqe->send.stag_inv = 0;
break;
case IB_WR_SEND_WITH_INV:
if (wr->send_flags & IB_SEND_SOLICITED)
wqe->send.sendop_pkd = cpu_to_be32(
- V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_SE_INV));
+ FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_SE_INV));
else
wqe->send.sendop_pkd = cpu_to_be32(
- V_FW_RI_SEND_WR_SENDOP(FW_RI_SEND_WITH_INV));
+ FW_RI_SEND_WR_SENDOP_V(FW_RI_SEND_WITH_INV));
wqe->send.stag_inv = cpu_to_be32(wr->ex.invalidate_rkey);
break;
@@ -1283,8 +1283,8 @@ static int rdma_init(struct c4iw_dev *rhp, struct c4iw_qp *qhp)
wqe->u.init.type = FW_RI_TYPE_INIT;
wqe->u.init.mpareqbit_p2ptype =
- V_FW_RI_WR_MPAREQBIT(qhp->attr.mpa_attr.initiator) |
- V_FW_RI_WR_P2PTYPE(qhp->attr.mpa_attr.p2p_type);
+ FW_RI_WR_MPAREQBIT_V(qhp->attr.mpa_attr.initiator) |
+ FW_RI_WR_P2PTYPE_V(qhp->attr.mpa_attr.p2p_type);
wqe->u.init.mpa_attrs = FW_RI_MPA_IETF_ENABLE;
if (qhp->attr.mpa_attr.recv_marker_enabled)
wqe->u.init.mpa_attrs |= FW_RI_MPA_RX_MARKER_ENABLE;
@@ -1776,7 +1776,7 @@ struct ib_qp *c4iw_create_qp(struct ib_pd *pd, struct ib_qp_init_attr *attrs,
if (mm5) {
mm5->key = uresp.ma_sync_key;
mm5->addr = (pci_resource_start(rhp->rdev.lldi.pdev, 0)
- + A_PCIE_MA_SYNC) & PAGE_MASK;
+ + PCIE_MA_SYNC_A) & PAGE_MASK;
mm5->len = PAGE_SIZE;
insert_mmap(ucontext, mm5);
}
diff --git a/drivers/infiniband/hw/cxgb4/t4.h b/drivers/infiniband/hw/cxgb4/t4.h
index c04e5134b30c..871cdcac7be2 100644
--- a/drivers/infiniband/hw/cxgb4/t4.h
+++ b/drivers/infiniband/hw/cxgb4/t4.h
@@ -41,7 +41,7 @@
#define T4_PAGESIZE_MASK 0xffff000 /* 4KB-128MB */
#define T4_STAG_UNSET 0xffffffff
#define T4_FW_MAJ 0
-#define A_PCIE_MA_SYNC 0x30b4
+#define PCIE_MA_SYNC_A 0x30b4
struct t4_status_page {
__be32 rsvd1; /* flit 0 - hw owns */
@@ -184,44 +184,44 @@ struct t4_cqe {
/* macros for flit 0 of the cqe */
-#define S_CQE_QPID 12
-#define M_CQE_QPID 0xFFFFF
-#define G_CQE_QPID(x) ((((x) >> S_CQE_QPID)) & M_CQE_QPID)
-#define V_CQE_QPID(x) ((x)<<S_CQE_QPID)
-
-#define S_CQE_SWCQE 11
-#define M_CQE_SWCQE 0x1
-#define G_CQE_SWCQE(x) ((((x) >> S_CQE_SWCQE)) & M_CQE_SWCQE)
-#define V_CQE_SWCQE(x) ((x)<<S_CQE_SWCQE)
-
-#define S_CQE_STATUS 5
-#define M_CQE_STATUS 0x1F
-#define G_CQE_STATUS(x) ((((x) >> S_CQE_STATUS)) & M_CQE_STATUS)
-#define V_CQE_STATUS(x) ((x)<<S_CQE_STATUS)
-
-#define S_CQE_TYPE 4
-#define M_CQE_TYPE 0x1
-#define G_CQE_TYPE(x) ((((x) >> S_CQE_TYPE)) & M_CQE_TYPE)
-#define V_CQE_TYPE(x) ((x)<<S_CQE_TYPE)
-
-#define S_CQE_OPCODE 0
-#define M_CQE_OPCODE 0xF
-#define G_CQE_OPCODE(x) ((((x) >> S_CQE_OPCODE)) & M_CQE_OPCODE)
-#define V_CQE_OPCODE(x) ((x)<<S_CQE_OPCODE)
-
-#define SW_CQE(x) (G_CQE_SWCQE(be32_to_cpu((x)->header)))
-#define CQE_QPID(x) (G_CQE_QPID(be32_to_cpu((x)->header)))
-#define CQE_TYPE(x) (G_CQE_TYPE(be32_to_cpu((x)->header)))
+#define CQE_QPID_S 12
+#define CQE_QPID_M 0xFFFFF
+#define CQE_QPID_G(x) ((((x) >> CQE_QPID_S)) & CQE_QPID_M)
+#define CQE_QPID_V(x) ((x)<<CQE_QPID_S)
+
+#define CQE_SWCQE_S 11
+#define CQE_SWCQE_M 0x1
+#define CQE_SWCQE_G(x) ((((x) >> CQE_SWCQE_S)) & CQE_SWCQE_M)
+#define CQE_SWCQE_V(x) ((x)<<CQE_SWCQE_S)
+
+#define CQE_STATUS_S 5
+#define CQE_STATUS_M 0x1F
+#define CQE_STATUS_G(x) ((((x) >> CQE_STATUS_S)) & CQE_STATUS_M)
+#define CQE_STATUS_V(x) ((x)<<CQE_STATUS_S)
+
+#define CQE_TYPE_S 4
+#define CQE_TYPE_M 0x1
+#define CQE_TYPE_G(x) ((((x) >> CQE_TYPE_S)) & CQE_TYPE_M)
+#define CQE_TYPE_V(x) ((x)<<CQE_TYPE_S)
+
+#define CQE_OPCODE_S 0
+#define CQE_OPCODE_M 0xF
+#define CQE_OPCODE_G(x) ((((x) >> CQE_OPCODE_S)) & CQE_OPCODE_M)
+#define CQE_OPCODE_V(x) ((x)<<CQE_OPCODE_S)
+
+#define SW_CQE(x) (CQE_SWCQE_G(be32_to_cpu((x)->header)))
+#define CQE_QPID(x) (CQE_QPID_G(be32_to_cpu((x)->header)))
+#define CQE_TYPE(x) (CQE_TYPE_G(be32_to_cpu((x)->header)))
#define SQ_TYPE(x) (CQE_TYPE((x)))
#define RQ_TYPE(x) (!CQE_TYPE((x)))
-#define CQE_STATUS(x) (G_CQE_STATUS(be32_to_cpu((x)->header)))
-#define CQE_OPCODE(x) (G_CQE_OPCODE(be32_to_cpu((x)->header)))
+#define CQE_STATUS(x) (CQE_STATUS_G(be32_to_cpu((x)->header)))
+#define CQE_OPCODE(x) (CQE_OPCODE_G(be32_to_cpu((x)->header)))
#define CQE_SEND_OPCODE(x)( \
- (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND) || \
- (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE) || \
- (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_INV) || \
- (G_CQE_OPCODE(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE_INV))
+ (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND) || \
+ (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE) || \
+ (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_INV) || \
+ (CQE_OPCODE_G(be32_to_cpu((x)->header)) == FW_RI_SEND_WITH_SE_INV))
#define CQE_LEN(x) (be32_to_cpu((x)->len))
@@ -237,25 +237,25 @@ struct t4_cqe {
#define CQE_WRID_LOW(x) (be32_to_cpu((x)->u.gen.wrid_low))
/* macros for flit 3 of the cqe */
-#define S_CQE_GENBIT 63
-#define M_CQE_GENBIT 0x1
-#define G_CQE_GENBIT(x) (((x) >> S_CQE_GENBIT) & M_CQE_GENBIT)
-#define V_CQE_GENBIT(x) ((x)<<S_CQE_GENBIT)
+#define CQE_GENBIT_S 63
+#define CQE_GENBIT_M 0x1
+#define CQE_GENBIT_G(x) (((x) >> CQE_GENBIT_S) & CQE_GENBIT_M)
+#define CQE_GENBIT_V(x) ((x)<<CQE_GENBIT_S)
-#define S_CQE_OVFBIT 62
-#define M_CQE_OVFBIT 0x1
-#define G_CQE_OVFBIT(x) ((((x) >> S_CQE_OVFBIT)) & M_CQE_OVFBIT)
+#define CQE_OVFBIT_S 62
+#define CQE_OVFBIT_M 0x1
+#define CQE_OVFBIT_G(x) ((((x) >> CQE_OVFBIT_S)) & CQE_OVFBIT_M)
-#define S_CQE_IQTYPE 60
-#define M_CQE_IQTYPE 0x3
-#define G_CQE_IQTYPE(x) ((((x) >> S_CQE_IQTYPE)) & M_CQE_IQTYPE)
+#define CQE_IQTYPE_S 60
+#define CQE_IQTYPE_M 0x3
+#define CQE_IQTYPE_G(x) ((((x) >> CQE_IQTYPE_S)) & CQE_IQTYPE_M)
-#define M_CQE_TS 0x0fffffffffffffffULL
-#define G_CQE_TS(x) ((x) & M_CQE_TS)
+#define CQE_TS_M 0x0fffffffffffffffULL
+#define CQE_TS_G(x) ((x) & CQE_TS_M)
-#define CQE_OVFBIT(x) ((unsigned)G_CQE_OVFBIT(be64_to_cpu((x)->bits_type_ts)))
-#define CQE_GENBIT(x) ((unsigned)G_CQE_GENBIT(be64_to_cpu((x)->bits_type_ts)))
-#define CQE_TS(x) (G_CQE_TS(be64_to_cpu((x)->bits_type_ts)))
+#define CQE_OVFBIT(x) ((unsigned)CQE_OVFBIT_G(be64_to_cpu((x)->bits_type_ts)))
+#define CQE_GENBIT(x) ((unsigned)CQE_GENBIT_G(be64_to_cpu((x)->bits_type_ts)))
+#define CQE_TS(x) (CQE_TS_G(be64_to_cpu((x)->bits_type_ts)))
struct t4_swsqe {
u64 wr_id;
@@ -465,14 +465,14 @@ static inline void t4_ring_sq_db(struct t4_wq *wq, u16 inc, u8 t5,
} else {
PDBG("%s: DB wq->sq.pidx = %d\n",
__func__, wq->sq.pidx);
- writel(PIDX_T5(inc), wq->sq.udb);
+ writel(PIDX_T5_V(inc), wq->sq.udb);
}
/* Flush user doorbell area writes. */
wmb();
return;
}
- writel(QID(wq->sq.qid) | PIDX(inc), wq->db);
+ writel(QID_V(wq->sq.qid) | PIDX_V(inc), wq->db);
}
static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5,
@@ -489,14 +489,14 @@ static inline void t4_ring_rq_db(struct t4_wq *wq, u16 inc, u8 t5,
} else {
PDBG("%s: DB wq->rq.pidx = %d\n",
__func__, wq->rq.pidx);
- writel(PIDX_T5(inc), wq->rq.udb);
+ writel(PIDX_T5_V(inc), wq->rq.udb);
}
/* Flush user doorbell area writes. */
wmb();
return;
}
- writel(QID(wq->rq.qid) | PIDX(inc), wq->db);
+ writel(QID_V(wq->rq.qid) | PIDX_V(inc), wq->db);
}
static inline int t4_wq_in_error(struct t4_wq *wq)
@@ -561,14 +561,14 @@ static inline int t4_arm_cq(struct t4_cq *cq, int se)
u32 val;
set_bit(CQ_ARMED, &cq->flags);
- while (cq->cidx_inc > CIDXINC_MASK) {
- val = SEINTARM(0) | CIDXINC(CIDXINC_MASK) | TIMERREG(7) |
- INGRESSQID(cq->cqid);
+ while (cq->cidx_inc > CIDXINC_M) {
+ val = SEINTARM_V(0) | CIDXINC_V(CIDXINC_M) | TIMERREG_V(7) |
+ INGRESSQID_V(cq->cqid);
writel(val, cq->gts);
- cq->cidx_inc -= CIDXINC_MASK;
+ cq->cidx_inc -= CIDXINC_M;
}
- val = SEINTARM(se) | CIDXINC(cq->cidx_inc) | TIMERREG(6) |
- INGRESSQID(cq->cqid);
+ val = SEINTARM_V(se) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(6) |
+ INGRESSQID_V(cq->cqid);
writel(val, cq->gts);
cq->cidx_inc = 0;
return 0;
@@ -597,11 +597,11 @@ static inline void t4_swcq_consume(struct t4_cq *cq)
static inline void t4_hwcq_consume(struct t4_cq *cq)
{
cq->bits_type_ts = cq->queue[cq->cidx].bits_type_ts;
- if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == CIDXINC_MASK) {
+ if (++cq->cidx_inc == (cq->size >> 4) || cq->cidx_inc == CIDXINC_M) {
u32 val;
- val = SEINTARM(0) | CIDXINC(cq->cidx_inc) | TIMERREG(7) |
- INGRESSQID(cq->cqid);
+ val = SEINTARM_V(0) | CIDXINC_V(cq->cidx_inc) | TIMERREG_V(7) |
+ INGRESSQID_V(cq->cqid);
writel(val, cq->gts);
cq->cidx_inc = 0;
}
diff --git a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
index 5709e77faf7c..5e53327fc647 100644
--- a/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
+++ b/drivers/infiniband/hw/cxgb4/t4fw_ri_api.h
@@ -162,102 +162,102 @@ struct fw_ri_tpte {
__be32 len_hi;
};
-#define S_FW_RI_TPTE_VALID 31
-#define M_FW_RI_TPTE_VALID 0x1
-#define V_FW_RI_TPTE_VALID(x) ((x) << S_FW_RI_TPTE_VALID)
-#define G_FW_RI_TPTE_VALID(x) \
- (((x) >> S_FW_RI_TPTE_VALID) & M_FW_RI_TPTE_VALID)
-#define F_FW_RI_TPTE_VALID V_FW_RI_TPTE_VALID(1U)
-
-#define S_FW_RI_TPTE_STAGKEY 23
-#define M_FW_RI_TPTE_STAGKEY 0xff
-#define V_FW_RI_TPTE_STAGKEY(x) ((x) << S_FW_RI_TPTE_STAGKEY)
-#define G_FW_RI_TPTE_STAGKEY(x) \
- (((x) >> S_FW_RI_TPTE_STAGKEY) & M_FW_RI_TPTE_STAGKEY)
-
-#define S_FW_RI_TPTE_STAGSTATE 22
-#define M_FW_RI_TPTE_STAGSTATE 0x1
-#define V_FW_RI_TPTE_STAGSTATE(x) ((x) << S_FW_RI_TPTE_STAGSTATE)
-#define G_FW_RI_TPTE_STAGSTATE(x) \
- (((x) >> S_FW_RI_TPTE_STAGSTATE) & M_FW_RI_TPTE_STAGSTATE)
-#define F_FW_RI_TPTE_STAGSTATE V_FW_RI_TPTE_STAGSTATE(1U)
-
-#define S_FW_RI_TPTE_STAGTYPE 20
-#define M_FW_RI_TPTE_STAGTYPE 0x3
-#define V_FW_RI_TPTE_STAGTYPE(x) ((x) << S_FW_RI_TPTE_STAGTYPE)
-#define G_FW_RI_TPTE_STAGTYPE(x) \
- (((x) >> S_FW_RI_TPTE_STAGTYPE) & M_FW_RI_TPTE_STAGTYPE)
-
-#define S_FW_RI_TPTE_PDID 0
-#define M_FW_RI_TPTE_PDID 0xfffff
-#define V_FW_RI_TPTE_PDID(x) ((x) << S_FW_RI_TPTE_PDID)
-#define G_FW_RI_TPTE_PDID(x) \
- (((x) >> S_FW_RI_TPTE_PDID) & M_FW_RI_TPTE_PDID)
-
-#define S_FW_RI_TPTE_PERM 28
-#define M_FW_RI_TPTE_PERM 0xf
-#define V_FW_RI_TPTE_PERM(x) ((x) << S_FW_RI_TPTE_PERM)
-#define G_FW_RI_TPTE_PERM(x) \
- (((x) >> S_FW_RI_TPTE_PERM) & M_FW_RI_TPTE_PERM)
-
-#define S_FW_RI_TPTE_REMINVDIS 27
-#define M_FW_RI_TPTE_REMINVDIS 0x1
-#define V_FW_RI_TPTE_REMINVDIS(x) ((x) << S_FW_RI_TPTE_REMINVDIS)
-#define G_FW_RI_TPTE_REMINVDIS(x) \
- (((x) >> S_FW_RI_TPTE_REMINVDIS) & M_FW_RI_TPTE_REMINVDIS)
-#define F_FW_RI_TPTE_REMINVDIS V_FW_RI_TPTE_REMINVDIS(1U)
-
-#define S_FW_RI_TPTE_ADDRTYPE 26
-#define M_FW_RI_TPTE_ADDRTYPE 1
-#define V_FW_RI_TPTE_ADDRTYPE(x) ((x) << S_FW_RI_TPTE_ADDRTYPE)
-#define G_FW_RI_TPTE_ADDRTYPE(x) \
- (((x) >> S_FW_RI_TPTE_ADDRTYPE) & M_FW_RI_TPTE_ADDRTYPE)
-#define F_FW_RI_TPTE_ADDRTYPE V_FW_RI_TPTE_ADDRTYPE(1U)
-
-#define S_FW_RI_TPTE_MWBINDEN 25
-#define M_FW_RI_TPTE_MWBINDEN 0x1
-#define V_FW_RI_TPTE_MWBINDEN(x) ((x) << S_FW_RI_TPTE_MWBINDEN)
-#define G_FW_RI_TPTE_MWBINDEN(x) \
- (((x) >> S_FW_RI_TPTE_MWBINDEN) & M_FW_RI_TPTE_MWBINDEN)
-#define F_FW_RI_TPTE_MWBINDEN V_FW_RI_TPTE_MWBINDEN(1U)
-
-#define S_FW_RI_TPTE_PS 20
-#define M_FW_RI_TPTE_PS 0x1f
-#define V_FW_RI_TPTE_PS(x) ((x) << S_FW_RI_TPTE_PS)
-#define G_FW_RI_TPTE_PS(x) \
- (((x) >> S_FW_RI_TPTE_PS) & M_FW_RI_TPTE_PS)
-
-#define S_FW_RI_TPTE_QPID 0
-#define M_FW_RI_TPTE_QPID 0xfffff
-#define V_FW_RI_TPTE_QPID(x) ((x) << S_FW_RI_TPTE_QPID)
-#define G_FW_RI_TPTE_QPID(x) \
- (((x) >> S_FW_RI_TPTE_QPID) & M_FW_RI_TPTE_QPID)
-
-#define S_FW_RI_TPTE_NOSNOOP 30
-#define M_FW_RI_TPTE_NOSNOOP 0x1
-#define V_FW_RI_TPTE_NOSNOOP(x) ((x) << S_FW_RI_TPTE_NOSNOOP)
-#define G_FW_RI_TPTE_NOSNOOP(x) \
- (((x) >> S_FW_RI_TPTE_NOSNOOP) & M_FW_RI_TPTE_NOSNOOP)
-#define F_FW_RI_TPTE_NOSNOOP V_FW_RI_TPTE_NOSNOOP(1U)
-
-#define S_FW_RI_TPTE_PBLADDR 0
-#define M_FW_RI_TPTE_PBLADDR 0x1fffffff
-#define V_FW_RI_TPTE_PBLADDR(x) ((x) << S_FW_RI_TPTE_PBLADDR)
-#define G_FW_RI_TPTE_PBLADDR(x) \
- (((x) >> S_FW_RI_TPTE_PBLADDR) & M_FW_RI_TPTE_PBLADDR)
-
-#define S_FW_RI_TPTE_DCA 24
-#define M_FW_RI_TPTE_DCA 0x1f
-#define V_FW_RI_TPTE_DCA(x) ((x) << S_FW_RI_TPTE_DCA)
-#define G_FW_RI_TPTE_DCA(x) \
- (((x) >> S_FW_RI_TPTE_DCA) & M_FW_RI_TPTE_DCA)
-
-#define S_FW_RI_TPTE_MWBCNT_PSTAG 0
-#define M_FW_RI_TPTE_MWBCNT_PSTAG 0xffffff
-#define V_FW_RI_TPTE_MWBCNT_PSTAT(x) \
- ((x) << S_FW_RI_TPTE_MWBCNT_PSTAG)
-#define G_FW_RI_TPTE_MWBCNT_PSTAG(x) \
- (((x) >> S_FW_RI_TPTE_MWBCNT_PSTAG) & M_FW_RI_TPTE_MWBCNT_PSTAG)
+#define FW_RI_TPTE_VALID_S 31
+#define FW_RI_TPTE_VALID_M 0x1
+#define FW_RI_TPTE_VALID_V(x) ((x) << FW_RI_TPTE_VALID_S)
+#define FW_RI_TPTE_VALID_G(x) \
+ (((x) >> FW_RI_TPTE_VALID_S) & FW_RI_TPTE_VALID_M)
+#define FW_RI_TPTE_VALID_F FW_RI_TPTE_VALID_V(1U)
+
+#define FW_RI_TPTE_STAGKEY_S 23
+#define FW_RI_TPTE_STAGKEY_M 0xff
+#define FW_RI_TPTE_STAGKEY_V(x) ((x) << FW_RI_TPTE_STAGKEY_S)
+#define FW_RI_TPTE_STAGKEY_G(x) \
+ (((x) >> FW_RI_TPTE_STAGKEY_S) & FW_RI_TPTE_STAGKEY_M)
+
+#define FW_RI_TPTE_STAGSTATE_S 22
+#define FW_RI_TPTE_STAGSTATE_M 0x1
+#define FW_RI_TPTE_STAGSTATE_V(x) ((x) << FW_RI_TPTE_STAGSTATE_S)
+#define FW_RI_TPTE_STAGSTATE_G(x) \
+ (((x) >> FW_RI_TPTE_STAGSTATE_S) & FW_RI_TPTE_STAGSTATE_M)
+#define FW_RI_TPTE_STAGSTATE_F FW_RI_TPTE_STAGSTATE_V(1U)
+
+#define FW_RI_TPTE_STAGTYPE_S 20
+#define FW_RI_TPTE_STAGTYPE_M 0x3
+#define FW_RI_TPTE_STAGTYPE_V(x) ((x) << FW_RI_TPTE_STAGTYPE_S)
+#define FW_RI_TPTE_STAGTYPE_G(x) \
+ (((x) >> FW_RI_TPTE_STAGTYPE_S) & FW_RI_TPTE_STAGTYPE_M)
+
+#define FW_RI_TPTE_PDID_S 0
+#define FW_RI_TPTE_PDID_M 0xfffff
+#define FW_RI_TPTE_PDID_V(x) ((x) << FW_RI_TPTE_PDID_S)
+#define FW_RI_TPTE_PDID_G(x) \
+ (((x) >> FW_RI_TPTE_PDID_S) & FW_RI_TPTE_PDID_M)
+
+#define FW_RI_TPTE_PERM_S 28
+#define FW_RI_TPTE_PERM_M 0xf
+#define FW_RI_TPTE_PERM_V(x) ((x) << FW_RI_TPTE_PERM_S)
+#define FW_RI_TPTE_PERM_G(x) \
+ (((x) >> FW_RI_TPTE_PERM_S) & FW_RI_TPTE_PERM_M)
+
+#define FW_RI_TPTE_REMINVDIS_S 27
+#define FW_RI_TPTE_REMINVDIS_M 0x1
+#define FW_RI_TPTE_REMINVDIS_V(x) ((x) << FW_RI_TPTE_REMINVDIS_S)
+#define FW_RI_TPTE_REMINVDIS_G(x) \
+ (((x) >> FW_RI_TPTE_REMINVDIS_S) & FW_RI_TPTE_REMINVDIS_M)
+#define FW_RI_TPTE_REMINVDIS_F FW_RI_TPTE_REMINVDIS_V(1U)
+
+#define FW_RI_TPTE_ADDRTYPE_S 26
+#define FW_RI_TPTE_ADDRTYPE_M 1
+#define FW_RI_TPTE_ADDRTYPE_V(x) ((x) << FW_RI_TPTE_ADDRTYPE_S)
+#define FW_RI_TPTE_ADDRTYPE_G(x) \
+ (((x) >> FW_RI_TPTE_ADDRTYPE_S) & FW_RI_TPTE_ADDRTYPE_M)
+#define FW_RI_TPTE_ADDRTYPE_F FW_RI_TPTE_ADDRTYPE_V(1U)
+
+#define FW_RI_TPTE_MWBINDEN_S 25
+#define FW_RI_TPTE_MWBINDEN_M 0x1
+#define FW_RI_TPTE_MWBINDEN_V(x) ((x) << FW_RI_TPTE_MWBINDEN_S)
+#define FW_RI_TPTE_MWBINDEN_G(x) \
+ (((x) >> FW_RI_TPTE_MWBINDEN_S) & FW_RI_TPTE_MWBINDEN_M)
+#define FW_RI_TPTE_MWBINDEN_F FW_RI_TPTE_MWBINDEN_V(1U)
+
+#define FW_RI_TPTE_PS_S 20
+#define FW_RI_TPTE_PS_M 0x1f
+#define FW_RI_TPTE_PS_V(x) ((x) << FW_RI_TPTE_PS_S)
+#define FW_RI_TPTE_PS_G(x) \
+ (((x) >> FW_RI_TPTE_PS_S) & FW_RI_TPTE_PS_M)
+
+#define FW_RI_TPTE_QPID_S 0
+#define FW_RI_TPTE_QPID_M 0xfffff
+#define FW_RI_TPTE_QPID_V(x) ((x) << FW_RI_TPTE_QPID_S)
+#define FW_RI_TPTE_QPID_G(x) \
+ (((x) >> FW_RI_TPTE_QPID_S) & FW_RI_TPTE_QPID_M)
+
+#define FW_RI_TPTE_NOSNOOP_S 30
+#define FW_RI_TPTE_NOSNOOP_M 0x1
+#define FW_RI_TPTE_NOSNOOP_V(x) ((x) << FW_RI_TPTE_NOSNOOP_S)
+#define FW_RI_TPTE_NOSNOOP_G(x) \
+ (((x) >> FW_RI_TPTE_NOSNOOP_S) & FW_RI_TPTE_NOSNOOP_M)
+#define FW_RI_TPTE_NOSNOOP_F FW_RI_TPTE_NOSNOOP_V(1U)
+
+#define FW_RI_TPTE_PBLADDR_S 0
+#define FW_RI_TPTE_PBLADDR_M 0x1fffffff
+#define FW_RI_TPTE_PBLADDR_V(x) ((x) << FW_RI_TPTE_PBLADDR_S)
+#define FW_RI_TPTE_PBLADDR_G(x) \
+ (((x) >> FW_RI_TPTE_PBLADDR_S) & FW_RI_TPTE_PBLADDR_M)
+
+#define FW_RI_TPTE_DCA_S 24
+#define FW_RI_TPTE_DCA_M 0x1f
+#define FW_RI_TPTE_DCA_V(x) ((x) << FW_RI_TPTE_DCA_S)
+#define FW_RI_TPTE_DCA_G(x) \
+ (((x) >> FW_RI_TPTE_DCA_S) & FW_RI_TPTE_DCA_M)
+
+#define FW_RI_TPTE_MWBCNT_PSTAG_S 0
+#define FW_RI_TPTE_MWBCNT_PSTAG_M 0xffffff
+#define FW_RI_TPTE_MWBCNT_PSTAT_V(x) \
+ ((x) << FW_RI_TPTE_MWBCNT_PSTAG_S)
+#define FW_RI_TPTE_MWBCNT_PSTAG_G(x) \
+ (((x) >> FW_RI_TPTE_MWBCNT_PSTAG_S) & FW_RI_TPTE_MWBCNT_PSTAG_M)
enum fw_ri_res_type {
FW_RI_RES_TYPE_SQ,
@@ -308,222 +308,222 @@ struct fw_ri_res_wr {
#endif
};
-#define S_FW_RI_RES_WR_NRES 0
-#define M_FW_RI_RES_WR_NRES 0xff
-#define V_FW_RI_RES_WR_NRES(x) ((x) << S_FW_RI_RES_WR_NRES)
-#define G_FW_RI_RES_WR_NRES(x) \
- (((x) >> S_FW_RI_RES_WR_NRES) & M_FW_RI_RES_WR_NRES)
-
-#define S_FW_RI_RES_WR_FETCHSZM 26
-#define M_FW_RI_RES_WR_FETCHSZM 0x1
-#define V_FW_RI_RES_WR_FETCHSZM(x) ((x) << S_FW_RI_RES_WR_FETCHSZM)
-#define G_FW_RI_RES_WR_FETCHSZM(x) \
- (((x) >> S_FW_RI_RES_WR_FETCHSZM) & M_FW_RI_RES_WR_FETCHSZM)
-#define F_FW_RI_RES_WR_FETCHSZM V_FW_RI_RES_WR_FETCHSZM(1U)
-
-#define S_FW_RI_RES_WR_STATUSPGNS 25
-#define M_FW_RI_RES_WR_STATUSPGNS 0x1
-#define V_FW_RI_RES_WR_STATUSPGNS(x) ((x) << S_FW_RI_RES_WR_STATUSPGNS)
-#define G_FW_RI_RES_WR_STATUSPGNS(x) \
- (((x) >> S_FW_RI_RES_WR_STATUSPGNS) & M_FW_RI_RES_WR_STATUSPGNS)
-#define F_FW_RI_RES_WR_STATUSPGNS V_FW_RI_RES_WR_STATUSPGNS(1U)
-
-#define S_FW_RI_RES_WR_STATUSPGRO 24
-#define M_FW_RI_RES_WR_STATUSPGRO 0x1
-#define V_FW_RI_RES_WR_STATUSPGRO(x) ((x) << S_FW_RI_RES_WR_STATUSPGRO)
-#define G_FW_RI_RES_WR_STATUSPGRO(x) \
- (((x) >> S_FW_RI_RES_WR_STATUSPGRO) & M_FW_RI_RES_WR_STATUSPGRO)
-#define F_FW_RI_RES_WR_STATUSPGRO V_FW_RI_RES_WR_STATUSPGRO(1U)
-
-#define S_FW_RI_RES_WR_FETCHNS 23
-#define M_FW_RI_RES_WR_FETCHNS 0x1
-#define V_FW_RI_RES_WR_FETCHNS(x) ((x) << S_FW_RI_RES_WR_FETCHNS)
-#define G_FW_RI_RES_WR_FETCHNS(x) \
- (((x) >> S_FW_RI_RES_WR_FETCHNS) & M_FW_RI_RES_WR_FETCHNS)
-#define F_FW_RI_RES_WR_FETCHNS V_FW_RI_RES_WR_FETCHNS(1U)
-
-#define S_FW_RI_RES_WR_FETCHRO 22
-#define M_FW_RI_RES_WR_FETCHRO 0x1
-#define V_FW_RI_RES_WR_FETCHRO(x) ((x) << S_FW_RI_RES_WR_FETCHRO)
-#define G_FW_RI_RES_WR_FETCHRO(x) \
- (((x) >> S_FW_RI_RES_WR_FETCHRO) & M_FW_RI_RES_WR_FETCHRO)
-#define F_FW_RI_RES_WR_FETCHRO V_FW_RI_RES_WR_FETCHRO(1U)
-
-#define S_FW_RI_RES_WR_HOSTFCMODE 20
-#define M_FW_RI_RES_WR_HOSTFCMODE 0x3
-#define V_FW_RI_RES_WR_HOSTFCMODE(x) ((x) << S_FW_RI_RES_WR_HOSTFCMODE)
-#define G_FW_RI_RES_WR_HOSTFCMODE(x) \
- (((x) >> S_FW_RI_RES_WR_HOSTFCMODE) & M_FW_RI_RES_WR_HOSTFCMODE)
-
-#define S_FW_RI_RES_WR_CPRIO 19
-#define M_FW_RI_RES_WR_CPRIO 0x1
-#define V_FW_RI_RES_WR_CPRIO(x) ((x) << S_FW_RI_RES_WR_CPRIO)
-#define G_FW_RI_RES_WR_CPRIO(x) \
- (((x) >> S_FW_RI_RES_WR_CPRIO) & M_FW_RI_RES_WR_CPRIO)
-#define F_FW_RI_RES_WR_CPRIO V_FW_RI_RES_WR_CPRIO(1U)
-
-#define S_FW_RI_RES_WR_ONCHIP 18
-#define M_FW_RI_RES_WR_ONCHIP 0x1
-#define V_FW_RI_RES_WR_ONCHIP(x) ((x) << S_FW_RI_RES_WR_ONCHIP)
-#define G_FW_RI_RES_WR_ONCHIP(x) \
- (((x) >> S_FW_RI_RES_WR_ONCHIP) & M_FW_RI_RES_WR_ONCHIP)
-#define F_FW_RI_RES_WR_ONCHIP V_FW_RI_RES_WR_ONCHIP(1U)
-
-#define S_FW_RI_RES_WR_PCIECHN 16
-#define M_FW_RI_RES_WR_PCIECHN 0x3
-#define V_FW_RI_RES_WR_PCIECHN(x) ((x) << S_FW_RI_RES_WR_PCIECHN)
-#define G_FW_RI_RES_WR_PCIECHN(x) \
- (((x) >> S_FW_RI_RES_WR_PCIECHN) & M_FW_RI_RES_WR_PCIECHN)
-
-#define S_FW_RI_RES_WR_IQID 0
-#define M_FW_RI_RES_WR_IQID 0xffff
-#define V_FW_RI_RES_WR_IQID(x) ((x) << S_FW_RI_RES_WR_IQID)
-#define G_FW_RI_RES_WR_IQID(x) \
- (((x) >> S_FW_RI_RES_WR_IQID) & M_FW_RI_RES_WR_IQID)
-
-#define S_FW_RI_RES_WR_DCAEN 31
-#define M_FW_RI_RES_WR_DCAEN 0x1
-#define V_FW_RI_RES_WR_DCAEN(x) ((x) << S_FW_RI_RES_WR_DCAEN)
-#define G_FW_RI_RES_WR_DCAEN(x) \
- (((x) >> S_FW_RI_RES_WR_DCAEN) & M_FW_RI_RES_WR_DCAEN)
-#define F_FW_RI_RES_WR_DCAEN V_FW_RI_RES_WR_DCAEN(1U)
-
-#define S_FW_RI_RES_WR_DCACPU 26
-#define M_FW_RI_RES_WR_DCACPU 0x1f
-#define V_FW_RI_RES_WR_DCACPU(x) ((x) << S_FW_RI_RES_WR_DCACPU)
-#define G_FW_RI_RES_WR_DCACPU(x) \
- (((x) >> S_FW_RI_RES_WR_DCACPU) & M_FW_RI_RES_WR_DCACPU)
-
-#define S_FW_RI_RES_WR_FBMIN 23
-#define M_FW_RI_RES_WR_FBMIN 0x7
-#define V_FW_RI_RES_WR_FBMIN(x) ((x) << S_FW_RI_RES_WR_FBMIN)
-#define G_FW_RI_RES_WR_FBMIN(x) \
- (((x) >> S_FW_RI_RES_WR_FBMIN) & M_FW_RI_RES_WR_FBMIN)
-
-#define S_FW_RI_RES_WR_FBMAX 20
-#define M_FW_RI_RES_WR_FBMAX 0x7
-#define V_FW_RI_RES_WR_FBMAX(x) ((x) << S_FW_RI_RES_WR_FBMAX)
-#define G_FW_RI_RES_WR_FBMAX(x) \
- (((x) >> S_FW_RI_RES_WR_FBMAX) & M_FW_RI_RES_WR_FBMAX)
-
-#define S_FW_RI_RES_WR_CIDXFTHRESHO 19
-#define M_FW_RI_RES_WR_CIDXFTHRESHO 0x1
-#define V_FW_RI_RES_WR_CIDXFTHRESHO(x) ((x) << S_FW_RI_RES_WR_CIDXFTHRESHO)
-#define G_FW_RI_RES_WR_CIDXFTHRESHO(x) \
- (((x) >> S_FW_RI_RES_WR_CIDXFTHRESHO) & M_FW_RI_RES_WR_CIDXFTHRESHO)
-#define F_FW_RI_RES_WR_CIDXFTHRESHO V_FW_RI_RES_WR_CIDXFTHRESHO(1U)
-
-#define S_FW_RI_RES_WR_CIDXFTHRESH 16
-#define M_FW_RI_RES_WR_CIDXFTHRESH 0x7
-#define V_FW_RI_RES_WR_CIDXFTHRESH(x) ((x) << S_FW_RI_RES_WR_CIDXFTHRESH)
-#define G_FW_RI_RES_WR_CIDXFTHRESH(x) \
- (((x) >> S_FW_RI_RES_WR_CIDXFTHRESH) & M_FW_RI_RES_WR_CIDXFTHRESH)
-
-#define S_FW_RI_RES_WR_EQSIZE 0
-#define M_FW_RI_RES_WR_EQSIZE 0xffff
-#define V_FW_RI_RES_WR_EQSIZE(x) ((x) << S_FW_RI_RES_WR_EQSIZE)
-#define G_FW_RI_RES_WR_EQSIZE(x) \
- (((x) >> S_FW_RI_RES_WR_EQSIZE) & M_FW_RI_RES_WR_EQSIZE)
-
-#define S_FW_RI_RES_WR_IQANDST 15
-#define M_FW_RI_RES_WR_IQANDST 0x1
-#define V_FW_RI_RES_WR_IQANDST(x) ((x) << S_FW_RI_RES_WR_IQANDST)
-#define G_FW_RI_RES_WR_IQANDST(x) \
- (((x) >> S_FW_RI_RES_WR_IQANDST) & M_FW_RI_RES_WR_IQANDST)
-#define F_FW_RI_RES_WR_IQANDST V_FW_RI_RES_WR_IQANDST(1U)
-
-#define S_FW_RI_RES_WR_IQANUS 14
-#define M_FW_RI_RES_WR_IQANUS 0x1
-#define V_FW_RI_RES_WR_IQANUS(x) ((x) << S_FW_RI_RES_WR_IQANUS)
-#define G_FW_RI_RES_WR_IQANUS(x) \
- (((x) >> S_FW_RI_RES_WR_IQANUS) & M_FW_RI_RES_WR_IQANUS)
-#define F_FW_RI_RES_WR_IQANUS V_FW_RI_RES_WR_IQANUS(1U)
-
-#define S_FW_RI_RES_WR_IQANUD 12
-#define M_FW_RI_RES_WR_IQANUD 0x3
-#define V_FW_RI_RES_WR_IQANUD(x) ((x) << S_FW_RI_RES_WR_IQANUD)
-#define G_FW_RI_RES_WR_IQANUD(x) \
- (((x) >> S_FW_RI_RES_WR_IQANUD) & M_FW_RI_RES_WR_IQANUD)
-
-#define S_FW_RI_RES_WR_IQANDSTINDEX 0
-#define M_FW_RI_RES_WR_IQANDSTINDEX 0xfff
-#define V_FW_RI_RES_WR_IQANDSTINDEX(x) ((x) << S_FW_RI_RES_WR_IQANDSTINDEX)
-#define G_FW_RI_RES_WR_IQANDSTINDEX(x) \
- (((x) >> S_FW_RI_RES_WR_IQANDSTINDEX) & M_FW_RI_RES_WR_IQANDSTINDEX)
-
-#define S_FW_RI_RES_WR_IQDROPRSS 15
-#define M_FW_RI_RES_WR_IQDROPRSS 0x1
-#define V_FW_RI_RES_WR_IQDROPRSS(x) ((x) << S_FW_RI_RES_WR_IQDROPRSS)
-#define G_FW_RI_RES_WR_IQDROPRSS(x) \
- (((x) >> S_FW_RI_RES_WR_IQDROPRSS) & M_FW_RI_RES_WR_IQDROPRSS)
-#define F_FW_RI_RES_WR_IQDROPRSS V_FW_RI_RES_WR_IQDROPRSS(1U)
-
-#define S_FW_RI_RES_WR_IQGTSMODE 14
-#define M_FW_RI_RES_WR_IQGTSMODE 0x1
-#define V_FW_RI_RES_WR_IQGTSMODE(x) ((x) << S_FW_RI_RES_WR_IQGTSMODE)
-#define G_FW_RI_RES_WR_IQGTSMODE(x) \
- (((x) >> S_FW_RI_RES_WR_IQGTSMODE) & M_FW_RI_RES_WR_IQGTSMODE)
-#define F_FW_RI_RES_WR_IQGTSMODE V_FW_RI_RES_WR_IQGTSMODE(1U)
-
-#define S_FW_RI_RES_WR_IQPCIECH 12
-#define M_FW_RI_RES_WR_IQPCIECH 0x3
-#define V_FW_RI_RES_WR_IQPCIECH(x) ((x) << S_FW_RI_RES_WR_IQPCIECH)
-#define G_FW_RI_RES_WR_IQPCIECH(x) \
- (((x) >> S_FW_RI_RES_WR_IQPCIECH) & M_FW_RI_RES_WR_IQPCIECH)
-
-#define S_FW_RI_RES_WR_IQDCAEN 11
-#define M_FW_RI_RES_WR_IQDCAEN 0x1
-#define V_FW_RI_RES_WR_IQDCAEN(x) ((x) << S_FW_RI_RES_WR_IQDCAEN)
-#define G_FW_RI_RES_WR_IQDCAEN(x) \
- (((x) >> S_FW_RI_RES_WR_IQDCAEN) & M_FW_RI_RES_WR_IQDCAEN)
-#define F_FW_RI_RES_WR_IQDCAEN V_FW_RI_RES_WR_IQDCAEN(1U)
-
-#define S_FW_RI_RES_WR_IQDCACPU 6
-#define M_FW_RI_RES_WR_IQDCACPU 0x1f
-#define V_FW_RI_RES_WR_IQDCACPU(x) ((x) << S_FW_RI_RES_WR_IQDCACPU)
-#define G_FW_RI_RES_WR_IQDCACPU(x) \
- (((x) >> S_FW_RI_RES_WR_IQDCACPU) & M_FW_RI_RES_WR_IQDCACPU)
-
-#define S_FW_RI_RES_WR_IQINTCNTTHRESH 4
-#define M_FW_RI_RES_WR_IQINTCNTTHRESH 0x3
-#define V_FW_RI_RES_WR_IQINTCNTTHRESH(x) \
- ((x) << S_FW_RI_RES_WR_IQINTCNTTHRESH)
-#define G_FW_RI_RES_WR_IQINTCNTTHRESH(x) \
- (((x) >> S_FW_RI_RES_WR_IQINTCNTTHRESH) & M_FW_RI_RES_WR_IQINTCNTTHRESH)
-
-#define S_FW_RI_RES_WR_IQO 3
-#define M_FW_RI_RES_WR_IQO 0x1
-#define V_FW_RI_RES_WR_IQO(x) ((x) << S_FW_RI_RES_WR_IQO)
-#define G_FW_RI_RES_WR_IQO(x) \
- (((x) >> S_FW_RI_RES_WR_IQO) & M_FW_RI_RES_WR_IQO)
-#define F_FW_RI_RES_WR_IQO V_FW_RI_RES_WR_IQO(1U)
-
-#define S_FW_RI_RES_WR_IQCPRIO 2
-#define M_FW_RI_RES_WR_IQCPRIO 0x1
-#define V_FW_RI_RES_WR_IQCPRIO(x) ((x) << S_FW_RI_RES_WR_IQCPRIO)
-#define G_FW_RI_RES_WR_IQCPRIO(x) \
- (((x) >> S_FW_RI_RES_WR_IQCPRIO) & M_FW_RI_RES_WR_IQCPRIO)
-#define F_FW_RI_RES_WR_IQCPRIO V_FW_RI_RES_WR_IQCPRIO(1U)
-
-#define S_FW_RI_RES_WR_IQESIZE 0
-#define M_FW_RI_RES_WR_IQESIZE 0x3
-#define V_FW_RI_RES_WR_IQESIZE(x) ((x) << S_FW_RI_RES_WR_IQESIZE)
-#define G_FW_RI_RES_WR_IQESIZE(x) \
- (((x) >> S_FW_RI_RES_WR_IQESIZE) & M_FW_RI_RES_WR_IQESIZE)
-
-#define S_FW_RI_RES_WR_IQNS 31
-#define M_FW_RI_RES_WR_IQNS 0x1
-#define V_FW_RI_RES_WR_IQNS(x) ((x) << S_FW_RI_RES_WR_IQNS)
-#define G_FW_RI_RES_WR_IQNS(x) \
- (((x) >> S_FW_RI_RES_WR_IQNS) & M_FW_RI_RES_WR_IQNS)
-#define F_FW_RI_RES_WR_IQNS V_FW_RI_RES_WR_IQNS(1U)
-
-#define S_FW_RI_RES_WR_IQRO 30
-#define M_FW_RI_RES_WR_IQRO 0x1
-#define V_FW_RI_RES_WR_IQRO(x) ((x) << S_FW_RI_RES_WR_IQRO)
-#define G_FW_RI_RES_WR_IQRO(x) \
- (((x) >> S_FW_RI_RES_WR_IQRO) & M_FW_RI_RES_WR_IQRO)
-#define F_FW_RI_RES_WR_IQRO V_FW_RI_RES_WR_IQRO(1U)
+#define FW_RI_RES_WR_NRES_S 0
+#define FW_RI_RES_WR_NRES_M 0xff
+#define FW_RI_RES_WR_NRES_V(x) ((x) << FW_RI_RES_WR_NRES_S)
+#define FW_RI_RES_WR_NRES_G(x) \
+ (((x) >> FW_RI_RES_WR_NRES_S) & FW_RI_RES_WR_NRES_M)
+
+#define FW_RI_RES_WR_FETCHSZM_S 26
+#define FW_RI_RES_WR_FETCHSZM_M 0x1
+#define FW_RI_RES_WR_FETCHSZM_V(x) ((x) << FW_RI_RES_WR_FETCHSZM_S)
+#define FW_RI_RES_WR_FETCHSZM_G(x) \
+ (((x) >> FW_RI_RES_WR_FETCHSZM_S) & FW_RI_RES_WR_FETCHSZM_M)
+#define FW_RI_RES_WR_FETCHSZM_F FW_RI_RES_WR_FETCHSZM_V(1U)
+
+#define FW_RI_RES_WR_STATUSPGNS_S 25
+#define FW_RI_RES_WR_STATUSPGNS_M 0x1
+#define FW_RI_RES_WR_STATUSPGNS_V(x) ((x) << FW_RI_RES_WR_STATUSPGNS_S)
+#define FW_RI_RES_WR_STATUSPGNS_G(x) \
+ (((x) >> FW_RI_RES_WR_STATUSPGNS_S) & FW_RI_RES_WR_STATUSPGNS_M)
+#define FW_RI_RES_WR_STATUSPGNS_F FW_RI_RES_WR_STATUSPGNS_V(1U)
+
+#define FW_RI_RES_WR_STATUSPGRO_S 24
+#define FW_RI_RES_WR_STATUSPGRO_M 0x1
+#define FW_RI_RES_WR_STATUSPGRO_V(x) ((x) << FW_RI_RES_WR_STATUSPGRO_S)
+#define FW_RI_RES_WR_STATUSPGRO_G(x) \
+ (((x) >> FW_RI_RES_WR_STATUSPGRO_S) & FW_RI_RES_WR_STATUSPGRO_M)
+#define FW_RI_RES_WR_STATUSPGRO_F FW_RI_RES_WR_STATUSPGRO_V(1U)
+
+#define FW_RI_RES_WR_FETCHNS_S 23
+#define FW_RI_RES_WR_FETCHNS_M 0x1
+#define FW_RI_RES_WR_FETCHNS_V(x) ((x) << FW_RI_RES_WR_FETCHNS_S)
+#define FW_RI_RES_WR_FETCHNS_G(x) \
+ (((x) >> FW_RI_RES_WR_FETCHNS_S) & FW_RI_RES_WR_FETCHNS_M)
+#define FW_RI_RES_WR_FETCHNS_F FW_RI_RES_WR_FETCHNS_V(1U)
+
+#define FW_RI_RES_WR_FETCHRO_S 22
+#define FW_RI_RES_WR_FETCHRO_M 0x1
+#define FW_RI_RES_WR_FETCHRO_V(x) ((x) << FW_RI_RES_WR_FETCHRO_S)
+#define FW_RI_RES_WR_FETCHRO_G(x) \
+ (((x) >> FW_RI_RES_WR_FETCHRO_S) & FW_RI_RES_WR_FETCHRO_M)
+#define FW_RI_RES_WR_FETCHRO_F FW_RI_RES_WR_FETCHRO_V(1U)
+
+#define FW_RI_RES_WR_HOSTFCMODE_S 20
+#define FW_RI_RES_WR_HOSTFCMODE_M 0x3
+#define FW_RI_RES_WR_HOSTFCMODE_V(x) ((x) << FW_RI_RES_WR_HOSTFCMODE_S)
+#define FW_RI_RES_WR_HOSTFCMODE_G(x) \
+ (((x) >> FW_RI_RES_WR_HOSTFCMODE_S) & FW_RI_RES_WR_HOSTFCMODE_M)
+
+#define FW_RI_RES_WR_CPRIO_S 19
+#define FW_RI_RES_WR_CPRIO_M 0x1
+#define FW_RI_RES_WR_CPRIO_V(x) ((x) << FW_RI_RES_WR_CPRIO_S)
+#define FW_RI_RES_WR_CPRIO_G(x) \
+ (((x) >> FW_RI_RES_WR_CPRIO_S) & FW_RI_RES_WR_CPRIO_M)
+#define FW_RI_RES_WR_CPRIO_F FW_RI_RES_WR_CPRIO_V(1U)
+
+#define FW_RI_RES_WR_ONCHIP_S 18
+#define FW_RI_RES_WR_ONCHIP_M 0x1
+#define FW_RI_RES_WR_ONCHIP_V(x) ((x) << FW_RI_RES_WR_ONCHIP_S)
+#define FW_RI_RES_WR_ONCHIP_G(x) \
+ (((x) >> FW_RI_RES_WR_ONCHIP_S) & FW_RI_RES_WR_ONCHIP_M)
+#define FW_RI_RES_WR_ONCHIP_F FW_RI_RES_WR_ONCHIP_V(1U)
+
+#define FW_RI_RES_WR_PCIECHN_S 16
+#define FW_RI_RES_WR_PCIECHN_M 0x3
+#define FW_RI_RES_WR_PCIECHN_V(x) ((x) << FW_RI_RES_WR_PCIECHN_S)
+#define FW_RI_RES_WR_PCIECHN_G(x) \
+ (((x) >> FW_RI_RES_WR_PCIECHN_S) & FW_RI_RES_WR_PCIECHN_M)
+
+#define FW_RI_RES_WR_IQID_S 0
+#define FW_RI_RES_WR_IQID_M 0xffff
+#define FW_RI_RES_WR_IQID_V(x) ((x) << FW_RI_RES_WR_IQID_S)
+#define FW_RI_RES_WR_IQID_G(x) \
+ (((x) >> FW_RI_RES_WR_IQID_S) & FW_RI_RES_WR_IQID_M)
+
+#define FW_RI_RES_WR_DCAEN_S 31
+#define FW_RI_RES_WR_DCAEN_M 0x1
+#define FW_RI_RES_WR_DCAEN_V(x) ((x) << FW_RI_RES_WR_DCAEN_S)
+#define FW_RI_RES_WR_DCAEN_G(x) \
+ (((x) >> FW_RI_RES_WR_DCAEN_S) & FW_RI_RES_WR_DCAEN_M)
+#define FW_RI_RES_WR_DCAEN_F FW_RI_RES_WR_DCAEN_V(1U)
+
+#define FW_RI_RES_WR_DCACPU_S 26
+#define FW_RI_RES_WR_DCACPU_M 0x1f
+#define FW_RI_RES_WR_DCACPU_V(x) ((x) << FW_RI_RES_WR_DCACPU_S)
+#define FW_RI_RES_WR_DCACPU_G(x) \
+ (((x) >> FW_RI_RES_WR_DCACPU_S) & FW_RI_RES_WR_DCACPU_M)
+
+#define FW_RI_RES_WR_FBMIN_S 23
+#define FW_RI_RES_WR_FBMIN_M 0x7
+#define FW_RI_RES_WR_FBMIN_V(x) ((x) << FW_RI_RES_WR_FBMIN_S)
+#define FW_RI_RES_WR_FBMIN_G(x) \
+ (((x) >> FW_RI_RES_WR_FBMIN_S) & FW_RI_RES_WR_FBMIN_M)
+
+#define FW_RI_RES_WR_FBMAX_S 20
+#define FW_RI_RES_WR_FBMAX_M 0x7
+#define FW_RI_RES_WR_FBMAX_V(x) ((x) << FW_RI_RES_WR_FBMAX_S)
+#define FW_RI_RES_WR_FBMAX_G(x) \
+ (((x) >> FW_RI_RES_WR_FBMAX_S) & FW_RI_RES_WR_FBMAX_M)
+
+#define FW_RI_RES_WR_CIDXFTHRESHO_S 19
+#define FW_RI_RES_WR_CIDXFTHRESHO_M 0x1
+#define FW_RI_RES_WR_CIDXFTHRESHO_V(x) ((x) << FW_RI_RES_WR_CIDXFTHRESHO_S)
+#define FW_RI_RES_WR_CIDXFTHRESHO_G(x) \
+ (((x) >> FW_RI_RES_WR_CIDXFTHRESHO_S) & FW_RI_RES_WR_CIDXFTHRESHO_M)
+#define FW_RI_RES_WR_CIDXFTHRESHO_F FW_RI_RES_WR_CIDXFTHRESHO_V(1U)
+
+#define FW_RI_RES_WR_CIDXFTHRESH_S 16
+#define FW_RI_RES_WR_CIDXFTHRESH_M 0x7
+#define FW_RI_RES_WR_CIDXFTHRESH_V(x) ((x) << FW_RI_RES_WR_CIDXFTHRESH_S)
+#define FW_RI_RES_WR_CIDXFTHRESH_G(x) \
+ (((x) >> FW_RI_RES_WR_CIDXFTHRESH_S) & FW_RI_RES_WR_CIDXFTHRESH_M)
+
+#define FW_RI_RES_WR_EQSIZE_S 0
+#define FW_RI_RES_WR_EQSIZE_M 0xffff
+#define FW_RI_RES_WR_EQSIZE_V(x) ((x) << FW_RI_RES_WR_EQSIZE_S)
+#define FW_RI_RES_WR_EQSIZE_G(x) \
+ (((x) >> FW_RI_RES_WR_EQSIZE_S) & FW_RI_RES_WR_EQSIZE_M)
+
+#define FW_RI_RES_WR_IQANDST_S 15
+#define FW_RI_RES_WR_IQANDST_M 0x1
+#define FW_RI_RES_WR_IQANDST_V(x) ((x) << FW_RI_RES_WR_IQANDST_S)
+#define FW_RI_RES_WR_IQANDST_G(x) \
+ (((x) >> FW_RI_RES_WR_IQANDST_S) & FW_RI_RES_WR_IQANDST_M)
+#define FW_RI_RES_WR_IQANDST_F FW_RI_RES_WR_IQANDST_V(1U)
+
+#define FW_RI_RES_WR_IQANUS_S 14
+#define FW_RI_RES_WR_IQANUS_M 0x1
+#define FW_RI_RES_WR_IQANUS_V(x) ((x) << FW_RI_RES_WR_IQANUS_S)
+#define FW_RI_RES_WR_IQANUS_G(x) \
+ (((x) >> FW_RI_RES_WR_IQANUS_S) & FW_RI_RES_WR_IQANUS_M)
+#define FW_RI_RES_WR_IQANUS_F FW_RI_RES_WR_IQANUS_V(1U)
+
+#define FW_RI_RES_WR_IQANUD_S 12
+#define FW_RI_RES_WR_IQANUD_M 0x3
+#define FW_RI_RES_WR_IQANUD_V(x) ((x) << FW_RI_RES_WR_IQANUD_S)
+#define FW_RI_RES_WR_IQANUD_G(x) \
+ (((x) >> FW_RI_RES_WR_IQANUD_S) & FW_RI_RES_WR_IQANUD_M)
+
+#define FW_RI_RES_WR_IQANDSTINDEX_S 0
+#define FW_RI_RES_WR_IQANDSTINDEX_M 0xfff
+#define FW_RI_RES_WR_IQANDSTINDEX_V(x) ((x) << FW_RI_RES_WR_IQANDSTINDEX_S)
+#define FW_RI_RES_WR_IQANDSTINDEX_G(x) \
+ (((x) >> FW_RI_RES_WR_IQANDSTINDEX_S) & FW_RI_RES_WR_IQANDSTINDEX_M)
+
+#define FW_RI_RES_WR_IQDROPRSS_S 15
+#define FW_RI_RES_WR_IQDROPRSS_M 0x1
+#define FW_RI_RES_WR_IQDROPRSS_V(x) ((x) << FW_RI_RES_WR_IQDROPRSS_S)
+#define FW_RI_RES_WR_IQDROPRSS_G(x) \
+ (((x) >> FW_RI_RES_WR_IQDROPRSS_S) & FW_RI_RES_WR_IQDROPRSS_M)
+#define FW_RI_RES_WR_IQDROPRSS_F FW_RI_RES_WR_IQDROPRSS_V(1U)
+
+#define FW_RI_RES_WR_IQGTSMODE_S 14
+#define FW_RI_RES_WR_IQGTSMODE_M 0x1
+#define FW_RI_RES_WR_IQGTSMODE_V(x) ((x) << FW_RI_RES_WR_IQGTSMODE_S)
+#define FW_RI_RES_WR_IQGTSMODE_G(x) \
+ (((x) >> FW_RI_RES_WR_IQGTSMODE_S) & FW_RI_RES_WR_IQGTSMODE_M)
+#define FW_RI_RES_WR_IQGTSMODE_F FW_RI_RES_WR_IQGTSMODE_V(1U)
+
+#define FW_RI_RES_WR_IQPCIECH_S 12
+#define FW_RI_RES_WR_IQPCIECH_M 0x3
+#define FW_RI_RES_WR_IQPCIECH_V(x) ((x) << FW_RI_RES_WR_IQPCIECH_S)
+#define FW_RI_RES_WR_IQPCIECH_G(x) \
+ (((x) >> FW_RI_RES_WR_IQPCIECH_S) & FW_RI_RES_WR_IQPCIECH_M)
+
+#define FW_RI_RES_WR_IQDCAEN_S 11
+#define FW_RI_RES_WR_IQDCAEN_M 0x1
+#define FW_RI_RES_WR_IQDCAEN_V(x) ((x) << FW_RI_RES_WR_IQDCAEN_S)
+#define FW_RI_RES_WR_IQDCAEN_G(x) \
+ (((x) >> FW_RI_RES_WR_IQDCAEN_S) & FW_RI_RES_WR_IQDCAEN_M)
+#define FW_RI_RES_WR_IQDCAEN_F FW_RI_RES_WR_IQDCAEN_V(1U)
+
+#define FW_RI_RES_WR_IQDCACPU_S 6
+#define FW_RI_RES_WR_IQDCACPU_M 0x1f
+#define FW_RI_RES_WR_IQDCACPU_V(x) ((x) << FW_RI_RES_WR_IQDCACPU_S)
+#define FW_RI_RES_WR_IQDCACPU_G(x) \
+ (((x) >> FW_RI_RES_WR_IQDCACPU_S) & FW_RI_RES_WR_IQDCACPU_M)
+
+#define FW_RI_RES_WR_IQINTCNTTHRESH_S 4
+#define FW_RI_RES_WR_IQINTCNTTHRESH_M 0x3
+#define FW_RI_RES_WR_IQINTCNTTHRESH_V(x) \
+ ((x) << FW_RI_RES_WR_IQINTCNTTHRESH_S)
+#define FW_RI_RES_WR_IQINTCNTTHRESH_G(x) \
+ (((x) >> FW_RI_RES_WR_IQINTCNTTHRESH_S) & FW_RI_RES_WR_IQINTCNTTHRESH_M)
+
+#define FW_RI_RES_WR_IQO_S 3
+#define FW_RI_RES_WR_IQO_M 0x1
+#define FW_RI_RES_WR_IQO_V(x) ((x) << FW_RI_RES_WR_IQO_S)
+#define FW_RI_RES_WR_IQO_G(x) \
+ (((x) >> FW_RI_RES_WR_IQO_S) & FW_RI_RES_WR_IQO_M)
+#define FW_RI_RES_WR_IQO_F FW_RI_RES_WR_IQO_V(1U)
+
+#define FW_RI_RES_WR_IQCPRIO_S 2
+#define FW_RI_RES_WR_IQCPRIO_M 0x1
+#define FW_RI_RES_WR_IQCPRIO_V(x) ((x) << FW_RI_RES_WR_IQCPRIO_S)
+#define FW_RI_RES_WR_IQCPRIO_G(x) \
+ (((x) >> FW_RI_RES_WR_IQCPRIO_S) & FW_RI_RES_WR_IQCPRIO_M)
+#define FW_RI_RES_WR_IQCPRIO_F FW_RI_RES_WR_IQCPRIO_V(1U)
+
+#define FW_RI_RES_WR_IQESIZE_S 0
+#define FW_RI_RES_WR_IQESIZE_M 0x3
+#define FW_RI_RES_WR_IQESIZE_V(x) ((x) << FW_RI_RES_WR_IQESIZE_S)
+#define FW_RI_RES_WR_IQESIZE_G(x) \
+ (((x) >> FW_RI_RES_WR_IQESIZE_S) & FW_RI_RES_WR_IQESIZE_M)
+
+#define FW_RI_RES_WR_IQNS_S 31
+#define FW_RI_RES_WR_IQNS_M 0x1
+#define FW_RI_RES_WR_IQNS_V(x) ((x) << FW_RI_RES_WR_IQNS_S)
+#define FW_RI_RES_WR_IQNS_G(x) \
+ (((x) >> FW_RI_RES_WR_IQNS_S) & FW_RI_RES_WR_IQNS_M)
+#define FW_RI_RES_WR_IQNS_F FW_RI_RES_WR_IQNS_V(1U)
+
+#define FW_RI_RES_WR_IQRO_S 30
+#define FW_RI_RES_WR_IQRO_M 0x1
+#define FW_RI_RES_WR_IQRO_V(x) ((x) << FW_RI_RES_WR_IQRO_S)
+#define FW_RI_RES_WR_IQRO_G(x) \
+ (((x) >> FW_RI_RES_WR_IQRO_S) & FW_RI_RES_WR_IQRO_M)
+#define FW_RI_RES_WR_IQRO_F FW_RI_RES_WR_IQRO_V(1U)
struct fw_ri_rdma_write_wr {
__u8 opcode;
@@ -562,11 +562,11 @@ struct fw_ri_send_wr {
#endif
};
-#define S_FW_RI_SEND_WR_SENDOP 0
-#define M_FW_RI_SEND_WR_SENDOP 0xf
-#define V_FW_RI_SEND_WR_SENDOP(x) ((x) << S_FW_RI_SEND_WR_SENDOP)
-#define G_FW_RI_SEND_WR_SENDOP(x) \
- (((x) >> S_FW_RI_SEND_WR_SENDOP) & M_FW_RI_SEND_WR_SENDOP)
+#define FW_RI_SEND_WR_SENDOP_S 0
+#define FW_RI_SEND_WR_SENDOP_M 0xf
+#define FW_RI_SEND_WR_SENDOP_V(x) ((x) << FW_RI_SEND_WR_SENDOP_S)
+#define FW_RI_SEND_WR_SENDOP_G(x) \
+ (((x) >> FW_RI_SEND_WR_SENDOP_S) & FW_RI_SEND_WR_SENDOP_M)
struct fw_ri_rdma_read_wr {
__u8 opcode;
@@ -612,25 +612,25 @@ struct fw_ri_bind_mw_wr {
__be64 r4;
};
-#define S_FW_RI_BIND_MW_WR_QPBINDE 6
-#define M_FW_RI_BIND_MW_WR_QPBINDE 0x1
-#define V_FW_RI_BIND_MW_WR_QPBINDE(x) ((x) << S_FW_RI_BIND_MW_WR_QPBINDE)
-#define G_FW_RI_BIND_MW_WR_QPBINDE(x) \
- (((x) >> S_FW_RI_BIND_MW_WR_QPBINDE) & M_FW_RI_BIND_MW_WR_QPBINDE)
-#define F_FW_RI_BIND_MW_WR_QPBINDE V_FW_RI_BIND_MW_WR_QPBINDE(1U)
+#define FW_RI_BIND_MW_WR_QPBINDE_S 6
+#define FW_RI_BIND_MW_WR_QPBINDE_M 0x1
+#define FW_RI_BIND_MW_WR_QPBINDE_V(x) ((x) << FW_RI_BIND_MW_WR_QPBINDE_S)
+#define FW_RI_BIND_MW_WR_QPBINDE_G(x) \
+ (((x) >> FW_RI_BIND_MW_WR_QPBINDE_S) & FW_RI_BIND_MW_WR_QPBINDE_M)
+#define FW_RI_BIND_MW_WR_QPBINDE_F FW_RI_BIND_MW_WR_QPBINDE_V(1U)
-#define S_FW_RI_BIND_MW_WR_NS 5
-#define M_FW_RI_BIND_MW_WR_NS 0x1
-#define V_FW_RI_BIND_MW_WR_NS(x) ((x) << S_FW_RI_BIND_MW_WR_NS)
-#define G_FW_RI_BIND_MW_WR_NS(x) \
- (((x) >> S_FW_RI_BIND_MW_WR_NS) & M_FW_RI_BIND_MW_WR_NS)
-#define F_FW_RI_BIND_MW_WR_NS V_FW_RI_BIND_MW_WR_NS(1U)
+#define FW_RI_BIND_MW_WR_NS_S 5
+#define FW_RI_BIND_MW_WR_NS_M 0x1
+#define FW_RI_BIND_MW_WR_NS_V(x) ((x) << FW_RI_BIND_MW_WR_NS_S)
+#define FW_RI_BIND_MW_WR_NS_G(x) \
+ (((x) >> FW_RI_BIND_MW_WR_NS_S) & FW_RI_BIND_MW_WR_NS_M)
+#define FW_RI_BIND_MW_WR_NS_F FW_RI_BIND_MW_WR_NS_V(1U)
-#define S_FW_RI_BIND_MW_WR_DCACPU 0
-#define M_FW_RI_BIND_MW_WR_DCACPU 0x1f
-#define V_FW_RI_BIND_MW_WR_DCACPU(x) ((x) << S_FW_RI_BIND_MW_WR_DCACPU)
-#define G_FW_RI_BIND_MW_WR_DCACPU(x) \
- (((x) >> S_FW_RI_BIND_MW_WR_DCACPU) & M_FW_RI_BIND_MW_WR_DCACPU)
+#define FW_RI_BIND_MW_WR_DCACPU_S 0
+#define FW_RI_BIND_MW_WR_DCACPU_M 0x1f
+#define FW_RI_BIND_MW_WR_DCACPU_V(x) ((x) << FW_RI_BIND_MW_WR_DCACPU_S)
+#define FW_RI_BIND_MW_WR_DCACPU_G(x) \
+ (((x) >> FW_RI_BIND_MW_WR_DCACPU_S) & FW_RI_BIND_MW_WR_DCACPU_M)
struct fw_ri_fr_nsmr_wr {
__u8 opcode;
@@ -649,25 +649,25 @@ struct fw_ri_fr_nsmr_wr {
__be32 va_lo_fbo;
};
-#define S_FW_RI_FR_NSMR_WR_QPBINDE 6
-#define M_FW_RI_FR_NSMR_WR_QPBINDE 0x1
-#define V_FW_RI_FR_NSMR_WR_QPBINDE(x) ((x) << S_FW_RI_FR_NSMR_WR_QPBINDE)
-#define G_FW_RI_FR_NSMR_WR_QPBINDE(x) \
- (((x) >> S_FW_RI_FR_NSMR_WR_QPBINDE) & M_FW_RI_FR_NSMR_WR_QPBINDE)
-#define F_FW_RI_FR_NSMR_WR_QPBINDE V_FW_RI_FR_NSMR_WR_QPBINDE(1U)
+#define FW_RI_FR_NSMR_WR_QPBINDE_S 6
+#define FW_RI_FR_NSMR_WR_QPBINDE_M 0x1
+#define FW_RI_FR_NSMR_WR_QPBINDE_V(x) ((x) << FW_RI_FR_NSMR_WR_QPBINDE_S)
+#define FW_RI_FR_NSMR_WR_QPBINDE_G(x) \
+ (((x) >> FW_RI_FR_NSMR_WR_QPBINDE_S) & FW_RI_FR_NSMR_WR_QPBINDE_M)
+#define FW_RI_FR_NSMR_WR_QPBINDE_F FW_RI_FR_NSMR_WR_QPBINDE_V(1U)
-#define S_FW_RI_FR_NSMR_WR_NS 5
-#define M_FW_RI_FR_NSMR_WR_NS 0x1
-#define V_FW_RI_FR_NSMR_WR_NS(x) ((x) << S_FW_RI_FR_NSMR_WR_NS)
-#define G_FW_RI_FR_NSMR_WR_NS(x) \
- (((x) >> S_FW_RI_FR_NSMR_WR_NS) & M_FW_RI_FR_NSMR_WR_NS)
-#define F_FW_RI_FR_NSMR_WR_NS V_FW_RI_FR_NSMR_WR_NS(1U)
+#define FW_RI_FR_NSMR_WR_NS_S 5
+#define FW_RI_FR_NSMR_WR_NS_M 0x1
+#define FW_RI_FR_NSMR_WR_NS_V(x) ((x) << FW_RI_FR_NSMR_WR_NS_S)
+#define FW_RI_FR_NSMR_WR_NS_G(x) \
+ (((x) >> FW_RI_FR_NSMR_WR_NS_S) & FW_RI_FR_NSMR_WR_NS_M)
+#define FW_RI_FR_NSMR_WR_NS_F FW_RI_FR_NSMR_WR_NS_V(1U)
-#define S_FW_RI_FR_NSMR_WR_DCACPU 0
-#define M_FW_RI_FR_NSMR_WR_DCACPU 0x1f
-#define V_FW_RI_FR_NSMR_WR_DCACPU(x) ((x) << S_FW_RI_FR_NSMR_WR_DCACPU)
-#define G_FW_RI_FR_NSMR_WR_DCACPU(x) \
- (((x) >> S_FW_RI_FR_NSMR_WR_DCACPU) & M_FW_RI_FR_NSMR_WR_DCACPU)
+#define FW_RI_FR_NSMR_WR_DCACPU_S 0
+#define FW_RI_FR_NSMR_WR_DCACPU_M 0x1f
+#define FW_RI_FR_NSMR_WR_DCACPU_V(x) ((x) << FW_RI_FR_NSMR_WR_DCACPU_S)
+#define FW_RI_FR_NSMR_WR_DCACPU_G(x) \
+ (((x) >> FW_RI_FR_NSMR_WR_DCACPU_S) & FW_RI_FR_NSMR_WR_DCACPU_M)
struct fw_ri_inv_lstag_wr {
__u8 opcode;
@@ -740,18 +740,18 @@ struct fw_ri_wr {
} u;
};
-#define S_FW_RI_WR_MPAREQBIT 7
-#define M_FW_RI_WR_MPAREQBIT 0x1
-#define V_FW_RI_WR_MPAREQBIT(x) ((x) << S_FW_RI_WR_MPAREQBIT)
-#define G_FW_RI_WR_MPAREQBIT(x) \
- (((x) >> S_FW_RI_WR_MPAREQBIT) & M_FW_RI_WR_MPAREQBIT)
-#define F_FW_RI_WR_MPAREQBIT V_FW_RI_WR_MPAREQBIT(1U)
+#define FW_RI_WR_MPAREQBIT_S 7
+#define FW_RI_WR_MPAREQBIT_M 0x1
+#define FW_RI_WR_MPAREQBIT_V(x) ((x) << FW_RI_WR_MPAREQBIT_S)
+#define FW_RI_WR_MPAREQBIT_G(x) \
+ (((x) >> FW_RI_WR_MPAREQBIT_S) & FW_RI_WR_MPAREQBIT_M)
+#define FW_RI_WR_MPAREQBIT_F FW_RI_WR_MPAREQBIT_V(1U)
-#define S_FW_RI_WR_P2PTYPE 0
-#define M_FW_RI_WR_P2PTYPE 0xf
-#define V_FW_RI_WR_P2PTYPE(x) ((x) << S_FW_RI_WR_P2PTYPE)
-#define G_FW_RI_WR_P2PTYPE(x) \
- (((x) >> S_FW_RI_WR_P2PTYPE) & M_FW_RI_WR_P2PTYPE)
+#define FW_RI_WR_P2PTYPE_S 0
+#define FW_RI_WR_P2PTYPE_M 0xf
+#define FW_RI_WR_P2PTYPE_V(x) ((x) << FW_RI_WR_P2PTYPE_S)
+#define FW_RI_WR_P2PTYPE_G(x) \
+ (((x) >> FW_RI_WR_P2PTYPE_S) & FW_RI_WR_P2PTYPE_M)
struct tcp_options {
__be16 mss;
@@ -783,58 +783,58 @@ struct cpl_pass_accept_req {
};
/* cpl_pass_accept_req.hdr_len fields */
-#define S_SYN_RX_CHAN 0
-#define M_SYN_RX_CHAN 0xF
-#define V_SYN_RX_CHAN(x) ((x) << S_SYN_RX_CHAN)
-#define G_SYN_RX_CHAN(x) (((x) >> S_SYN_RX_CHAN) & M_SYN_RX_CHAN)
-
-#define S_TCP_HDR_LEN 10
-#define M_TCP_HDR_LEN 0x3F
-#define V_TCP_HDR_LEN(x) ((x) << S_TCP_HDR_LEN)
-#define G_TCP_HDR_LEN(x) (((x) >> S_TCP_HDR_LEN) & M_TCP_HDR_LEN)
-
-#define S_IP_HDR_LEN 16
-#define M_IP_HDR_LEN 0x3FF
-#define V_IP_HDR_LEN(x) ((x) << S_IP_HDR_LEN)
-#define G_IP_HDR_LEN(x) (((x) >> S_IP_HDR_LEN) & M_IP_HDR_LEN)
-
-#define S_ETH_HDR_LEN 26
-#define M_ETH_HDR_LEN 0x1F
-#define V_ETH_HDR_LEN(x) ((x) << S_ETH_HDR_LEN)
-#define G_ETH_HDR_LEN(x) (((x) >> S_ETH_HDR_LEN) & M_ETH_HDR_LEN)
+#define SYN_RX_CHAN_S 0
+#define SYN_RX_CHAN_M 0xF
+#define SYN_RX_CHAN_V(x) ((x) << SYN_RX_CHAN_S)
+#define SYN_RX_CHAN_G(x) (((x) >> SYN_RX_CHAN_S) & SYN_RX_CHAN_M)
+
+#define TCP_HDR_LEN_S 10
+#define TCP_HDR_LEN_M 0x3F
+#define TCP_HDR_LEN_V(x) ((x) << TCP_HDR_LEN_S)
+#define TCP_HDR_LEN_G(x) (((x) >> TCP_HDR_LEN_S) & TCP_HDR_LEN_M)
+
+#define IP_HDR_LEN_S 16
+#define IP_HDR_LEN_M 0x3FF
+#define IP_HDR_LEN_V(x) ((x) << IP_HDR_LEN_S)
+#define IP_HDR_LEN_G(x) (((x) >> IP_HDR_LEN_S) & IP_HDR_LEN_M)
+
+#define ETH_HDR_LEN_S 26
+#define ETH_HDR_LEN_M 0x1F
+#define ETH_HDR_LEN_V(x) ((x) << ETH_HDR_LEN_S)
+#define ETH_HDR_LEN_G(x) (((x) >> ETH_HDR_LEN_S) & ETH_HDR_LEN_M)
/* cpl_pass_accept_req.l2info fields */
-#define S_SYN_MAC_IDX 0
-#define M_SYN_MAC_IDX 0x1FF
-#define V_SYN_MAC_IDX(x) ((x) << S_SYN_MAC_IDX)
-#define G_SYN_MAC_IDX(x) (((x) >> S_SYN_MAC_IDX) & M_SYN_MAC_IDX)
+#define SYN_MAC_IDX_S 0
+#define SYN_MAC_IDX_M 0x1FF
+#define SYN_MAC_IDX_V(x) ((x) << SYN_MAC_IDX_S)
+#define SYN_MAC_IDX_G(x) (((x) >> SYN_MAC_IDX_S) & SYN_MAC_IDX_M)
-#define S_SYN_XACT_MATCH 9
-#define V_SYN_XACT_MATCH(x) ((x) << S_SYN_XACT_MATCH)
-#define F_SYN_XACT_MATCH V_SYN_XACT_MATCH(1U)
+#define SYN_XACT_MATCH_S 9
+#define SYN_XACT_MATCH_V(x) ((x) << SYN_XACT_MATCH_S)
+#define SYN_XACT_MATCH_F SYN_XACT_MATCH_V(1U)
-#define S_SYN_INTF 12
-#define M_SYN_INTF 0xF
-#define V_SYN_INTF(x) ((x) << S_SYN_INTF)
-#define G_SYN_INTF(x) (((x) >> S_SYN_INTF) & M_SYN_INTF)
+#define SYN_INTF_S 12
+#define SYN_INTF_M 0xF
+#define SYN_INTF_V(x) ((x) << SYN_INTF_S)
+#define SYN_INTF_G(x) (((x) >> SYN_INTF_S) & SYN_INTF_M)
struct ulptx_idata {
__be32 cmd_more;
__be32 len;
};
-#define S_ULPTX_NSGE 0
-#define M_ULPTX_NSGE 0xFFFF
-#define V_ULPTX_NSGE(x) ((x) << S_ULPTX_NSGE)
+#define ULPTX_NSGE_S 0
+#define ULPTX_NSGE_M 0xFFFF
+#define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S)
-#define S_RX_DACK_MODE 29
-#define M_RX_DACK_MODE 0x3
-#define V_RX_DACK_MODE(x) ((x) << S_RX_DACK_MODE)
-#define G_RX_DACK_MODE(x) (((x) >> S_RX_DACK_MODE) & M_RX_DACK_MODE)
+#define RX_DACK_MODE_S 29
+#define RX_DACK_MODE_M 0x3
+#define RX_DACK_MODE_V(x) ((x) << RX_DACK_MODE_S)
+#define RX_DACK_MODE_G(x) (((x) >> RX_DACK_MODE_S) & RX_DACK_MODE_M)
-#define S_RX_DACK_CHANGE 31
-#define V_RX_DACK_CHANGE(x) ((x) << S_RX_DACK_CHANGE)
-#define F_RX_DACK_CHANGE V_RX_DACK_CHANGE(1U)
+#define RX_DACK_CHANGE_S 31
+#define RX_DACK_CHANGE_V(x) ((x) << RX_DACK_CHANGE_S)
+#define RX_DACK_CHANGE_F RX_DACK_CHANGE_V(1U)
enum { /* TCP congestion control algorithms */
CONG_ALG_RENO,
@@ -843,10 +843,10 @@ enum { /* TCP congestion control algorithms */
CONG_ALG_HIGHSPEED
};
-#define S_CONG_CNTRL 14
-#define M_CONG_CNTRL 0x3
-#define V_CONG_CNTRL(x) ((x) << S_CONG_CNTRL)
-#define G_CONG_CNTRL(x) (((x) >> S_CONG_CNTRL) & M_CONG_CNTRL)
+#define CONG_CNTRL_S 14
+#define CONG_CNTRL_M 0x3
+#define CONG_CNTRL_V(x) ((x) << CONG_CNTRL_S)
+#define CONG_CNTRL_G(x) (((x) >> CONG_CNTRL_S) & CONG_CNTRL_M)
#define CONG_CNTRL_VALID (1 << 18)
diff --git a/drivers/infiniband/hw/ipath/ipath_fs.c b/drivers/infiniband/hw/ipath/ipath_fs.c
index 4977082e081f..33c45dfcbd88 100644
--- a/drivers/infiniband/hw/ipath/ipath_fs.c
+++ b/drivers/infiniband/hw/ipath/ipath_fs.c
@@ -277,7 +277,7 @@ static int remove_file(struct dentry *parent, char *name)
}
spin_lock(&tmp->d_lock);
- if (!(d_unhashed(tmp) && tmp->d_inode)) {
+ if (!d_unhashed(tmp) && tmp->d_inode) {
dget_dlock(tmp);
__d_drop(tmp);
spin_unlock(&tmp->d_lock);
diff --git a/drivers/infiniband/hw/ipath/ipath_kernel.h b/drivers/infiniband/hw/ipath/ipath_kernel.h
index 6559af60bffd..e08db7020cd4 100644
--- a/drivers/infiniband/hw/ipath/ipath_kernel.h
+++ b/drivers/infiniband/hw/ipath/ipath_kernel.h
@@ -908,9 +908,6 @@ void ipath_chip_cleanup(struct ipath_devdata *);
/* clean up any chip type-specific stuff */
void ipath_chip_done(void);
-/* check to see if we have to force ordering for write combining */
-int ipath_unordered_wc(void);
-
void ipath_disarm_piobufs(struct ipath_devdata *, unsigned first,
unsigned cnt);
void ipath_cancel_sends(struct ipath_devdata *, int);
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
index 1d7bd82a1fb1..1a7e20a75149 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_ppc64.c
@@ -47,16 +47,3 @@ int ipath_enable_wc(struct ipath_devdata *dd)
{
return 0;
}
-
-/**
- * ipath_unordered_wc - indicate whether write combining is unordered
- *
- * Because our performance depends on our ability to do write
- * combining mmio writes in the most efficient way, we need to
- * know if we are on a processor that may reorder stores when
- * write combining.
- */
-int ipath_unordered_wc(void)
-{
- return 1;
-}
diff --git a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
index 3428acb0868c..4ad0b932df1f 100644
--- a/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
+++ b/drivers/infiniband/hw/ipath/ipath_wc_x86_64.c
@@ -167,18 +167,3 @@ void ipath_disable_wc(struct ipath_devdata *dd)
dd->ipath_wc_cookie = 0; /* even on failure */
}
}
-
-/**
- * ipath_unordered_wc - indicate whether write combining is ordered
- *
- * Because our performance depends on our ability to do write combining mmio
- * writes in the most efficient way, we need to know if we are on an Intel
- * or AMD x86_64 processor. AMD x86_64 processors flush WC buffers out in
- * the order completed, and so no special flushing is required to get
- * correct ordering. Intel processors, however, will flush write buffers
- * out in "random" orders, and so explicit ordering is needed at times.
- */
-int ipath_unordered_wc(void)
-{
- return boot_cpu_data.x86_vendor != X86_VENDOR_AMD;
-}
diff --git a/drivers/infiniband/hw/mlx4/ah.c b/drivers/infiniband/hw/mlx4/ah.c
index 2d8c3397774f..f50a546224ad 100644
--- a/drivers/infiniband/hw/mlx4/ah.c
+++ b/drivers/infiniband/hw/mlx4/ah.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <linux/inet.h>
#include <linux/string.h>
+#include <linux/mlx4/driver.h>
#include "mlx4_ib.h"
diff --git a/drivers/infiniband/hw/mlx4/alias_GUID.c b/drivers/infiniband/hw/mlx4/alias_GUID.c
index 0eb141c41416..a31e031afd87 100644
--- a/drivers/infiniband/hw/mlx4/alias_GUID.c
+++ b/drivers/infiniband/hw/mlx4/alias_GUID.c
@@ -154,7 +154,7 @@ void mlx4_ib_notify_slaves_on_guid_change(struct mlx4_ib_dev *dev,
continue;
slave_id = (block_num * NUM_ALIAS_GUID_IN_REC) + i ;
- if (slave_id >= dev->dev->num_vfs + 1)
+ if (slave_id >= dev->dev->persist->num_vfs + 1)
return;
tmp_cur_ag = *(__be64 *)&p_data[i * GUID_REC_SIZE];
form_cache_ag = get_cached_alias_guid(dev, port_num,
diff --git a/drivers/infiniband/hw/mlx4/cm.c b/drivers/infiniband/hw/mlx4/cm.c
index 56a593e0ae5d..39a488889fc7 100644
--- a/drivers/infiniband/hw/mlx4/cm.c
+++ b/drivers/infiniband/hw/mlx4/cm.c
@@ -372,7 +372,7 @@ int mlx4_ib_demux_cm_handler(struct ib_device *ibdev, int port, int *slave,
*slave = mlx4_ib_find_real_gid(ibdev, port, gid.global.interface_id);
if (*slave < 0) {
mlx4_ib_warn(ibdev, "failed matching slave_id by gid (0x%llx)\n",
- gid.global.interface_id);
+ be64_to_cpu(gid.global.interface_id));
return -ENOENT;
}
return 0;
diff --git a/drivers/infiniband/hw/mlx4/cq.c b/drivers/infiniband/hw/mlx4/cq.c
index a3b70f6c4035..0176caa5792c 100644
--- a/drivers/infiniband/hw/mlx4/cq.c
+++ b/drivers/infiniband/hw/mlx4/cq.c
@@ -188,6 +188,8 @@ struct ib_cq *mlx4_ib_create_cq(struct ib_device *ibdev, int entries, int vector
spin_lock_init(&cq->lock);
cq->resize_buf = NULL;
cq->resize_umem = NULL;
+ INIT_LIST_HEAD(&cq->send_qp_list);
+ INIT_LIST_HEAD(&cq->recv_qp_list);
if (context) {
struct mlx4_ib_create_cq ucmd;
@@ -367,8 +369,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
int err;
mutex_lock(&cq->resize_mutex);
-
- if (entries < 1) {
+ if (entries < 1 || entries > dev->dev->caps.max_cqes) {
err = -EINVAL;
goto out;
}
@@ -379,7 +380,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
goto out;
}
- if (entries > dev->dev->caps.max_cqes) {
+ if (entries > dev->dev->caps.max_cqes + 1) {
err = -EINVAL;
goto out;
}
@@ -392,7 +393,7 @@ int mlx4_ib_resize_cq(struct ib_cq *ibcq, int entries, struct ib_udata *udata)
/* Can't be smaller than the number of outstanding CQEs */
outst_cqe = mlx4_ib_get_outstanding_cqes(cq);
if (entries < outst_cqe + 1) {
- err = 0;
+ err = -EINVAL;
goto out;
}
@@ -594,6 +595,55 @@ static int use_tunnel_data(struct mlx4_ib_qp *qp, struct mlx4_ib_cq *cq, struct
return 0;
}
+static void mlx4_ib_qp_sw_comp(struct mlx4_ib_qp *qp, int num_entries,
+ struct ib_wc *wc, int *npolled, int is_send)
+{
+ struct mlx4_ib_wq *wq;
+ unsigned cur;
+ int i;
+
+ wq = is_send ? &qp->sq : &qp->rq;
+ cur = wq->head - wq->tail;
+
+ if (cur == 0)
+ return;
+
+ for (i = 0; i < cur && *npolled < num_entries; i++) {
+ wc->wr_id = wq->wrid[wq->tail & (wq->wqe_cnt - 1)];
+ wc->status = IB_WC_WR_FLUSH_ERR;
+ wc->vendor_err = MLX4_CQE_SYNDROME_WR_FLUSH_ERR;
+ wq->tail++;
+ (*npolled)++;
+ wc->qp = &qp->ibqp;
+ wc++;
+ }
+}
+
+static void mlx4_ib_poll_sw_comp(struct mlx4_ib_cq *cq, int num_entries,
+ struct ib_wc *wc, int *npolled)
+{
+ struct mlx4_ib_qp *qp;
+
+ *npolled = 0;
+ /* Find uncompleted WQEs belonging to that cq and retrun
+ * simulated FLUSH_ERR completions
+ */
+ list_for_each_entry(qp, &cq->send_qp_list, cq_send_list) {
+ mlx4_ib_qp_sw_comp(qp, num_entries, wc, npolled, 1);
+ if (*npolled >= num_entries)
+ goto out;
+ }
+
+ list_for_each_entry(qp, &cq->recv_qp_list, cq_recv_list) {
+ mlx4_ib_qp_sw_comp(qp, num_entries, wc + *npolled, npolled, 0);
+ if (*npolled >= num_entries)
+ goto out;
+ }
+
+out:
+ return;
+}
+
static int mlx4_ib_poll_one(struct mlx4_ib_cq *cq,
struct mlx4_ib_qp **cur_qp,
struct ib_wc *wc)
@@ -836,8 +886,13 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
unsigned long flags;
int npolled;
int err = 0;
+ struct mlx4_ib_dev *mdev = to_mdev(cq->ibcq.device);
spin_lock_irqsave(&cq->lock, flags);
+ if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ mlx4_ib_poll_sw_comp(cq, num_entries, wc, &npolled);
+ goto out;
+ }
for (npolled = 0; npolled < num_entries; ++npolled) {
err = mlx4_ib_poll_one(cq, &cur_qp, wc + npolled);
@@ -847,6 +902,7 @@ int mlx4_ib_poll_cq(struct ib_cq *ibcq, int num_entries, struct ib_wc *wc)
mlx4_cq_set_ci(&cq->mcq);
+out:
spin_unlock_irqrestore(&cq->lock, flags);
if (err == 0 || err == -EAGAIN)
diff --git a/drivers/infiniband/hw/mlx4/mad.c b/drivers/infiniband/hw/mlx4/mad.c
index 82a7dd87089b..c7619716c31d 100644
--- a/drivers/infiniband/hw/mlx4/mad.c
+++ b/drivers/infiniband/hw/mlx4/mad.c
@@ -1951,7 +1951,8 @@ static int mlx4_ib_alloc_demux_ctx(struct mlx4_ib_dev *dev,
ctx->ib_dev = &dev->ib_dev;
for (i = 0;
- i < min(dev->dev->caps.sqp_demux, (u16)(dev->dev->num_vfs + 1));
+ i < min(dev->dev->caps.sqp_demux,
+ (u16)(dev->dev->persist->num_vfs + 1));
i++) {
struct mlx4_active_ports actv_ports =
mlx4_get_active_ports(dev->dev, i);
diff --git a/drivers/infiniband/hw/mlx4/main.c b/drivers/infiniband/hw/mlx4/main.c
index 9117b7a2d5f8..ac6e2b710ea6 100644
--- a/drivers/infiniband/hw/mlx4/main.c
+++ b/drivers/infiniband/hw/mlx4/main.c
@@ -198,7 +198,7 @@ static int mlx4_ib_query_device(struct ib_device *ibdev,
props->vendor_id = be32_to_cpup((__be32 *) (out_mad->data + 36)) &
0xffffff;
- props->vendor_part_id = dev->dev->pdev->device;
+ props->vendor_part_id = dev->dev->persist->pdev->device;
props->hw_ver = be32_to_cpup((__be32 *) (out_mad->data + 32));
memcpy(&props->sys_image_guid, out_mad->data + 4, 8);
@@ -351,6 +351,7 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
enum ib_mtu tmp;
struct mlx4_cmd_mailbox *mailbox;
int err = 0;
+ int is_bonded = mlx4_is_bonded(mdev->dev);
mailbox = mlx4_alloc_cmd_mailbox(mdev->dev);
if (IS_ERR(mailbox))
@@ -374,8 +375,12 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
props->state = IB_PORT_DOWN;
props->phys_state = state_to_phys_state(props->state);
props->active_mtu = IB_MTU_256;
+ if (is_bonded)
+ rtnl_lock(); /* required to get upper dev */
spin_lock_bh(&iboe->lock);
ndev = iboe->netdevs[port - 1];
+ if (ndev && is_bonded)
+ ndev = netdev_master_upper_dev_get(ndev);
if (!ndev)
goto out_unlock;
@@ -387,6 +392,8 @@ static int eth_link_query_port(struct ib_device *ibdev, u8 port,
props->phys_state = state_to_phys_state(props->state);
out_unlock:
spin_unlock_bh(&iboe->lock);
+ if (is_bonded)
+ rtnl_unlock();
out:
mlx4_free_cmd_mailbox(mdev->dev, mailbox);
return err;
@@ -844,7 +851,7 @@ int mlx4_ib_add_mc(struct mlx4_ib_dev *mdev, struct mlx4_ib_qp *mqp,
struct mlx4_ib_steering {
struct list_head list;
- u64 reg_id;
+ struct mlx4_flow_reg_id reg_id;
union ib_gid gid;
};
@@ -1135,9 +1142,11 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
struct ib_flow_attr *flow_attr,
int domain)
{
- int err = 0, i = 0;
+ int err = 0, i = 0, j = 0;
struct mlx4_ib_flow *mflow;
enum mlx4_net_trans_promisc_mode type[2];
+ struct mlx4_dev *dev = (to_mdev(qp->device))->dev;
+ int is_bonded = mlx4_is_bonded(dev);
memset(type, 0, sizeof(type));
@@ -1172,26 +1181,58 @@ static struct ib_flow *mlx4_ib_create_flow(struct ib_qp *qp,
while (i < ARRAY_SIZE(type) && type[i]) {
err = __mlx4_ib_create_flow(qp, flow_attr, domain, type[i],
- &mflow->reg_id[i]);
+ &mflow->reg_id[i].id);
if (err)
goto err_create_flow;
i++;
+ if (is_bonded) {
+ /* Application always sees one port so the mirror rule
+ * must be on port #2
+ */
+ flow_attr->port = 2;
+ err = __mlx4_ib_create_flow(qp, flow_attr,
+ domain, type[j],
+ &mflow->reg_id[j].mirror);
+ flow_attr->port = 1;
+ if (err)
+ goto err_create_flow;
+ j++;
+ }
+
}
if (i < ARRAY_SIZE(type) && flow_attr->type == IB_FLOW_ATTR_NORMAL) {
- err = mlx4_ib_tunnel_steer_add(qp, flow_attr, &mflow->reg_id[i]);
+ err = mlx4_ib_tunnel_steer_add(qp, flow_attr,
+ &mflow->reg_id[i].id);
if (err)
goto err_create_flow;
i++;
+ if (is_bonded) {
+ flow_attr->port = 2;
+ err = mlx4_ib_tunnel_steer_add(qp, flow_attr,
+ &mflow->reg_id[j].mirror);
+ flow_attr->port = 1;
+ if (err)
+ goto err_create_flow;
+ j++;
+ }
+ /* function to create mirror rule */
}
return &mflow->ibflow;
err_create_flow:
while (i) {
- (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev, mflow->reg_id[i]);
+ (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev,
+ mflow->reg_id[i].id);
i--;
}
+
+ while (j) {
+ (void)__mlx4_ib_destroy_flow(to_mdev(qp->device)->dev,
+ mflow->reg_id[j].mirror);
+ j--;
+ }
err_free:
kfree(mflow);
return ERR_PTR(err);
@@ -1204,10 +1245,16 @@ static int mlx4_ib_destroy_flow(struct ib_flow *flow_id)
struct mlx4_ib_dev *mdev = to_mdev(flow_id->qp->device);
struct mlx4_ib_flow *mflow = to_mflow(flow_id);
- while (i < ARRAY_SIZE(mflow->reg_id) && mflow->reg_id[i]) {
- err = __mlx4_ib_destroy_flow(mdev->dev, mflow->reg_id[i]);
+ while (i < ARRAY_SIZE(mflow->reg_id) && mflow->reg_id[i].id) {
+ err = __mlx4_ib_destroy_flow(mdev->dev, mflow->reg_id[i].id);
if (err)
ret = err;
+ if (mflow->reg_id[i].mirror) {
+ err = __mlx4_ib_destroy_flow(mdev->dev,
+ mflow->reg_id[i].mirror);
+ if (err)
+ ret = err;
+ }
i++;
}
@@ -1219,11 +1266,11 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
int err;
struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+ struct mlx4_dev *dev = mdev->dev;
struct mlx4_ib_qp *mqp = to_mqp(ibqp);
- u64 reg_id;
struct mlx4_ib_steering *ib_steering = NULL;
- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ?
- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6;
+ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
+ struct mlx4_flow_reg_id reg_id;
if (mdev->dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED) {
@@ -1235,9 +1282,22 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw, mqp->port,
!!(mqp->flags &
MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
- prot, &reg_id);
- if (err)
+ prot, &reg_id.id);
+ if (err) {
+ pr_err("multicast attach op failed, err %d\n", err);
goto err_malloc;
+ }
+
+ reg_id.mirror = 0;
+ if (mlx4_is_bonded(dev)) {
+ err = mlx4_multicast_attach(mdev->dev, &mqp->mqp, gid->raw,
+ (mqp->port == 1) ? 2 : 1,
+ !!(mqp->flags &
+ MLX4_IB_QP_BLOCK_MULTICAST_LOOPBACK),
+ prot, &reg_id.mirror);
+ if (err)
+ goto err_add;
+ }
err = add_gid_entry(ibqp, gid);
if (err)
@@ -1254,7 +1314,10 @@ static int mlx4_ib_mcg_attach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
err_add:
mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
- prot, reg_id);
+ prot, reg_id.id);
+ if (reg_id.mirror)
+ mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
+ prot, reg_id.mirror);
err_malloc:
kfree(ib_steering);
@@ -1281,12 +1344,12 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
{
int err;
struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
+ struct mlx4_dev *dev = mdev->dev;
struct mlx4_ib_qp *mqp = to_mqp(ibqp);
struct net_device *ndev;
struct mlx4_ib_gid_entry *ge;
- u64 reg_id = 0;
- enum mlx4_protocol prot = (gid->raw[1] == 0x0e) ?
- MLX4_PROT_IB_IPV4 : MLX4_PROT_IB_IPV6;
+ struct mlx4_flow_reg_id reg_id = {0, 0};
+ enum mlx4_protocol prot = MLX4_PROT_IB_IPV6;
if (mdev->dev->caps.steering_mode ==
MLX4_STEERING_MODE_DEVICE_MANAGED) {
@@ -1309,10 +1372,17 @@ static int mlx4_ib_mcg_detach(struct ib_qp *ibqp, union ib_gid *gid, u16 lid)
}
err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
- prot, reg_id);
+ prot, reg_id.id);
if (err)
return err;
+ if (mlx4_is_bonded(dev)) {
+ err = mlx4_multicast_detach(mdev->dev, &mqp->mqp, gid->raw,
+ prot, reg_id.mirror);
+ if (err)
+ return err;
+ }
+
mutex_lock(&mqp->mutex);
ge = find_gid_entry(mqp, gid->raw);
if (ge) {
@@ -1376,7 +1446,7 @@ static ssize_t show_hca(struct device *device, struct device_attribute *attr,
{
struct mlx4_ib_dev *dev =
container_of(device, struct mlx4_ib_dev, ib_dev.dev);
- return sprintf(buf, "MT%d\n", dev->dev->pdev->device);
+ return sprintf(buf, "MT%d\n", dev->dev->persist->pdev->device);
}
static ssize_t show_fw_ver(struct device *device, struct device_attribute *attr,
@@ -1440,6 +1510,7 @@ static void update_gids_task(struct work_struct *work)
union ib_gid *gids;
int err;
struct mlx4_dev *dev = gw->dev->dev;
+ int is_bonded = mlx4_is_bonded(dev);
if (!gw->dev->ib_active)
return;
@@ -1459,7 +1530,10 @@ static void update_gids_task(struct work_struct *work)
if (err)
pr_warn("set port command failed\n");
else
- mlx4_ib_dispatch_event(gw->dev, gw->port, IB_EVENT_GID_CHANGE);
+ if ((gw->port == 1) || !is_bonded)
+ mlx4_ib_dispatch_event(gw->dev,
+ is_bonded ? 1 : gw->port,
+ IB_EVENT_GID_CHANGE);
mlx4_free_cmd_mailbox(dev, mailbox);
kfree(gw);
@@ -1875,7 +1949,8 @@ static void mlx4_ib_scan_netdevs(struct mlx4_ib_dev *ibdev,
* don't want the bond IP based gids in the table since
* flows that select port by gid may get the down port.
*/
- if (port_state == IB_PORT_DOWN) {
+ if (port_state == IB_PORT_DOWN &&
+ !mlx4_is_bonded(ibdev->dev)) {
reset_gid_table(ibdev, port);
mlx4_ib_set_default_gid(ibdev,
curr_netdev,
@@ -1938,7 +2013,8 @@ static void init_pkeys(struct mlx4_ib_dev *ibdev)
int i;
if (mlx4_is_master(ibdev->dev)) {
- for (slave = 0; slave <= ibdev->dev->num_vfs; ++slave) {
+ for (slave = 0; slave <= ibdev->dev->persist->num_vfs;
+ ++slave) {
for (port = 1; port <= ibdev->dev->caps.num_ports; ++port) {
for (i = 0;
i < ibdev->dev->phys_caps.pkey_phys_table_len[port];
@@ -1995,7 +2071,7 @@ static void mlx4_ib_alloc_eqs(struct mlx4_dev *dev, struct mlx4_ib_dev *ibdev)
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB) {
for (j = 0; j < eq_per_port; j++) {
snprintf(name, sizeof(name), "mlx4-ib-%d-%d@%s",
- i, j, dev->pdev->bus->name);
+ i, j, dev->persist->pdev->bus->name);
/* Set IRQ for specific name (per ring) */
if (mlx4_assign_eq(dev, name, NULL,
&ibdev->eq_table[eq])) {
@@ -2046,6 +2122,7 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
int err;
struct mlx4_ib_iboe *iboe;
int ib_num_ports = 0;
+ int num_req_counters;
pr_info_once("%s", mlx4_ib_version);
@@ -2059,7 +2136,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev = (struct mlx4_ib_dev *) ib_alloc_device(sizeof *ibdev);
if (!ibdev) {
- dev_err(&dev->pdev->dev, "Device struct alloc failed\n");
+ dev_err(&dev->persist->pdev->dev,
+ "Device struct alloc failed\n");
return NULL;
}
@@ -2078,15 +2156,17 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
MLX4_INIT_DOORBELL_LOCK(&ibdev->uar_lock);
ibdev->dev = dev;
+ ibdev->bond_next_port = 0;
strlcpy(ibdev->ib_dev.name, "mlx4_%d", IB_DEVICE_NAME_MAX);
ibdev->ib_dev.owner = THIS_MODULE;
ibdev->ib_dev.node_type = RDMA_NODE_IB_CA;
ibdev->ib_dev.local_dma_lkey = dev->caps.reserved_lkey;
ibdev->num_ports = num_ports;
- ibdev->ib_dev.phys_port_cnt = ibdev->num_ports;
+ ibdev->ib_dev.phys_port_cnt = mlx4_is_bonded(dev) ?
+ 1 : ibdev->num_ports;
ibdev->ib_dev.num_comp_vectors = dev->caps.num_comp_vectors;
- ibdev->ib_dev.dma_device = &dev->pdev->dev;
+ ibdev->ib_dev.dma_device = &dev->persist->pdev->dev;
if (dev->caps.userspace_caps)
ibdev->ib_dev.uverbs_abi_ver = MLX4_IB_UVERBS_ABI_VERSION;
@@ -2205,7 +2285,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
if (init_node_data(ibdev))
goto err_map;
- for (i = 0; i < ibdev->num_ports; ++i) {
+ num_req_counters = mlx4_is_bonded(dev) ? 1 : ibdev->num_ports;
+ for (i = 0; i < num_req_counters; ++i) {
mutex_init(&ibdev->qp1_proxy_lock[i]);
if (mlx4_ib_port_link_layer(&ibdev->ib_dev, i + 1) ==
IB_LINK_LAYER_ETHERNET) {
@@ -2216,12 +2297,18 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
ibdev->counters[i] = -1;
}
}
+ if (mlx4_is_bonded(dev))
+ for (i = 1; i < ibdev->num_ports ; ++i)
+ ibdev->counters[i] = ibdev->counters[0];
+
mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_IB)
ib_num_ports++;
spin_lock_init(&ibdev->sm_lock);
mutex_init(&ibdev->cap_mask_mutex);
+ INIT_LIST_HEAD(&ibdev->qp_list);
+ spin_lock_init(&ibdev->reset_flow_resource_lock);
if (ibdev->steering_support == MLX4_STEERING_MODE_DEVICE_MANAGED &&
ib_num_ports) {
@@ -2237,7 +2324,8 @@ static void *mlx4_ib_add(struct mlx4_dev *dev)
sizeof(long),
GFP_KERNEL);
if (!ibdev->ib_uc_qpns_bitmap) {
- dev_err(&dev->pdev->dev, "bit map alloc failed\n");
+ dev_err(&dev->persist->pdev->dev,
+ "bit map alloc failed\n");
goto err_steer_qp_release;
}
@@ -2535,6 +2623,99 @@ out:
return;
}
+static void mlx4_ib_handle_catas_error(struct mlx4_ib_dev *ibdev)
+{
+ struct mlx4_ib_qp *mqp;
+ unsigned long flags_qp;
+ unsigned long flags_cq;
+ struct mlx4_ib_cq *send_mcq, *recv_mcq;
+ struct list_head cq_notify_list;
+ struct mlx4_cq *mcq;
+ unsigned long flags;
+
+ pr_warn("mlx4_ib_handle_catas_error was started\n");
+ INIT_LIST_HEAD(&cq_notify_list);
+
+ /* Go over qp list reside on that ibdev, sync with create/destroy qp.*/
+ spin_lock_irqsave(&ibdev->reset_flow_resource_lock, flags);
+
+ list_for_each_entry(mqp, &ibdev->qp_list, qps_list) {
+ spin_lock_irqsave(&mqp->sq.lock, flags_qp);
+ if (mqp->sq.tail != mqp->sq.head) {
+ send_mcq = to_mcq(mqp->ibqp.send_cq);
+ spin_lock_irqsave(&send_mcq->lock, flags_cq);
+ if (send_mcq->mcq.comp &&
+ mqp->ibqp.send_cq->comp_handler) {
+ if (!send_mcq->mcq.reset_notify_added) {
+ send_mcq->mcq.reset_notify_added = 1;
+ list_add_tail(&send_mcq->mcq.reset_notify,
+ &cq_notify_list);
+ }
+ }
+ spin_unlock_irqrestore(&send_mcq->lock, flags_cq);
+ }
+ spin_unlock_irqrestore(&mqp->sq.lock, flags_qp);
+ /* Now, handle the QP's receive queue */
+ spin_lock_irqsave(&mqp->rq.lock, flags_qp);
+ /* no handling is needed for SRQ */
+ if (!mqp->ibqp.srq) {
+ if (mqp->rq.tail != mqp->rq.head) {
+ recv_mcq = to_mcq(mqp->ibqp.recv_cq);
+ spin_lock_irqsave(&recv_mcq->lock, flags_cq);
+ if (recv_mcq->mcq.comp &&
+ mqp->ibqp.recv_cq->comp_handler) {
+ if (!recv_mcq->mcq.reset_notify_added) {
+ recv_mcq->mcq.reset_notify_added = 1;
+ list_add_tail(&recv_mcq->mcq.reset_notify,
+ &cq_notify_list);
+ }
+ }
+ spin_unlock_irqrestore(&recv_mcq->lock,
+ flags_cq);
+ }
+ }
+ spin_unlock_irqrestore(&mqp->rq.lock, flags_qp);
+ }
+
+ list_for_each_entry(mcq, &cq_notify_list, reset_notify) {
+ mcq->comp(mcq);
+ }
+ spin_unlock_irqrestore(&ibdev->reset_flow_resource_lock, flags);
+ pr_warn("mlx4_ib_handle_catas_error ended\n");
+}
+
+static void handle_bonded_port_state_event(struct work_struct *work)
+{
+ struct ib_event_work *ew =
+ container_of(work, struct ib_event_work, work);
+ struct mlx4_ib_dev *ibdev = ew->ib_dev;
+ enum ib_port_state bonded_port_state = IB_PORT_NOP;
+ int i;
+ struct ib_event ibev;
+
+ kfree(ew);
+ spin_lock_bh(&ibdev->iboe.lock);
+ for (i = 0; i < MLX4_MAX_PORTS; ++i) {
+ struct net_device *curr_netdev = ibdev->iboe.netdevs[i];
+
+ enum ib_port_state curr_port_state =
+ (netif_running(curr_netdev) &&
+ netif_carrier_ok(curr_netdev)) ?
+ IB_PORT_ACTIVE : IB_PORT_DOWN;
+
+ bonded_port_state = (bonded_port_state != IB_PORT_ACTIVE) ?
+ curr_port_state : IB_PORT_ACTIVE;
+ }
+ spin_unlock_bh(&ibdev->iboe.lock);
+
+ ibev.device = &ibdev->ib_dev;
+ ibev.element.port_num = 1;
+ ibev.event = (bonded_port_state == IB_PORT_ACTIVE) ?
+ IB_EVENT_PORT_ACTIVE : IB_EVENT_PORT_ERR;
+
+ ib_dispatch_event(&ibev);
+}
+
static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
enum mlx4_dev_event event, unsigned long param)
{
@@ -2544,6 +2725,18 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
struct ib_event_work *ew;
int p = 0;
+ if (mlx4_is_bonded(dev) &&
+ ((event == MLX4_DEV_EVENT_PORT_UP) ||
+ (event == MLX4_DEV_EVENT_PORT_DOWN))) {
+ ew = kmalloc(sizeof(*ew), GFP_ATOMIC);
+ if (!ew)
+ return;
+ INIT_WORK(&ew->work, handle_bonded_port_state_event);
+ ew->ib_dev = ibdev;
+ queue_work(wq, &ew->work);
+ return;
+ }
+
if (event == MLX4_DEV_EVENT_PORT_MGMT_CHANGE)
eqe = (struct mlx4_eqe *)param;
else
@@ -2570,6 +2763,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
case MLX4_DEV_EVENT_CATASTROPHIC_ERROR:
ibdev->ib_active = false;
ibev.event = IB_EVENT_DEVICE_FATAL;
+ mlx4_ib_handle_catas_error(ibdev);
break;
case MLX4_DEV_EVENT_PORT_MGMT_CHANGE:
@@ -2604,7 +2798,7 @@ static void mlx4_ib_event(struct mlx4_dev *dev, void *ibdev_ptr,
}
ibev.device = ibdev_ptr;
- ibev.element.port_num = (u8) p;
+ ibev.element.port_num = mlx4_is_bonded(ibdev->dev) ? 1 : (u8)p;
ib_dispatch_event(&ibev);
}
@@ -2613,7 +2807,8 @@ static struct mlx4_interface mlx4_ib_interface = {
.add = mlx4_ib_add,
.remove = mlx4_ib_remove,
.event = mlx4_ib_event,
- .protocol = MLX4_PROT_IB_IPV6
+ .protocol = MLX4_PROT_IB_IPV6,
+ .flags = MLX4_INTFF_BONDING
};
static int __init mlx4_ib_init(void)
diff --git a/drivers/infiniband/hw/mlx4/mlx4_ib.h b/drivers/infiniband/hw/mlx4/mlx4_ib.h
index 6eb743f65f6f..f829fd935b79 100644
--- a/drivers/infiniband/hw/mlx4/mlx4_ib.h
+++ b/drivers/infiniband/hw/mlx4/mlx4_ib.h
@@ -110,6 +110,9 @@ struct mlx4_ib_cq {
struct mutex resize_mutex;
struct ib_umem *umem;
struct ib_umem *resize_umem;
+ /* List of qps that it serves.*/
+ struct list_head send_qp_list;
+ struct list_head recv_qp_list;
};
struct mlx4_ib_mr {
@@ -134,10 +137,17 @@ struct mlx4_ib_fmr {
struct mlx4_fmr mfmr;
};
+#define MAX_REGS_PER_FLOW 2
+
+struct mlx4_flow_reg_id {
+ u64 id;
+ u64 mirror;
+};
+
struct mlx4_ib_flow {
struct ib_flow ibflow;
/* translating DMFS verbs sniffer rule to FW API requires two reg IDs */
- u64 reg_id[2];
+ struct mlx4_flow_reg_id reg_id[MAX_REGS_PER_FLOW];
};
struct mlx4_ib_wq {
@@ -293,6 +303,9 @@ struct mlx4_ib_qp {
struct mlx4_roce_smac_vlan_info pri;
struct mlx4_roce_smac_vlan_info alt;
u64 reg_id;
+ struct list_head qps_list;
+ struct list_head cq_recv_list;
+ struct list_head cq_send_list;
};
struct mlx4_ib_srq {
@@ -527,6 +540,10 @@ struct mlx4_ib_dev {
struct mlx4_ib_qp *qp1_proxy[MLX4_MAX_PORTS];
/* lock when destroying qp1_proxy and getting netdev events */
struct mutex qp1_proxy_lock[MLX4_MAX_PORTS];
+ u8 bond_next_port;
+ /* protect resources needed as part of reset flow */
+ spinlock_t reset_flow_resource_lock;
+ struct list_head qp_list;
};
struct ib_event_work {
@@ -622,6 +639,13 @@ static inline struct mlx4_ib_ah *to_mah(struct ib_ah *ibah)
return container_of(ibah, struct mlx4_ib_ah, ibah);
}
+static inline u8 mlx4_ib_bond_next_port(struct mlx4_ib_dev *dev)
+{
+ dev->bond_next_port = (dev->bond_next_port + 1) % dev->num_ports;
+
+ return dev->bond_next_port + 1;
+}
+
int mlx4_ib_init_sriov(struct mlx4_ib_dev *dev);
void mlx4_ib_close_sriov(struct mlx4_ib_dev *dev);
diff --git a/drivers/infiniband/hw/mlx4/mr.c b/drivers/infiniband/hw/mlx4/mr.c
index c36ccbd9a644..e0d271782d0a 100644
--- a/drivers/infiniband/hw/mlx4/mr.c
+++ b/drivers/infiniband/hw/mlx4/mr.c
@@ -401,7 +401,8 @@ struct ib_fast_reg_page_list *mlx4_ib_alloc_fast_reg_page_list(struct ib_device
if (!mfrpl->ibfrpl.page_list)
goto err_free;
- mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->pdev->dev,
+ mfrpl->mapped_page_list = dma_alloc_coherent(&dev->dev->persist->
+ pdev->dev,
size, &mfrpl->map,
GFP_KERNEL);
if (!mfrpl->mapped_page_list)
@@ -423,7 +424,8 @@ void mlx4_ib_free_fast_reg_page_list(struct ib_fast_reg_page_list *page_list)
struct mlx4_ib_fast_reg_page_list *mfrpl = to_mfrpl(page_list);
int size = page_list->max_page_list_len * sizeof (u64);
- dma_free_coherent(&dev->dev->pdev->dev, size, mfrpl->mapped_page_list,
+ dma_free_coherent(&dev->dev->persist->pdev->dev, size,
+ mfrpl->mapped_page_list,
mfrpl->map);
kfree(mfrpl->ibfrpl.page_list);
kfree(mfrpl);
diff --git a/drivers/infiniband/hw/mlx4/qp.c b/drivers/infiniband/hw/mlx4/qp.c
index cf000b7ad64f..ed2bd6701f9b 100644
--- a/drivers/infiniband/hw/mlx4/qp.c
+++ b/drivers/infiniband/hw/mlx4/qp.c
@@ -40,11 +40,17 @@
#include <rdma/ib_addr.h>
#include <rdma/ib_mad.h>
+#include <linux/mlx4/driver.h>
#include <linux/mlx4/qp.h>
#include "mlx4_ib.h"
#include "user.h"
+static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq,
+ struct mlx4_ib_cq *recv_cq);
+static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq,
+ struct mlx4_ib_cq *recv_cq);
+
enum {
MLX4_IB_ACK_REQ_FREQ = 8,
};
@@ -93,17 +99,6 @@ enum {
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
-static inline u64 mlx4_mac_to_u64(u8 *addr)
-{
- u64 mac = 0;
- int i;
-
- for (i = 0; i < ETH_ALEN; i++) {
- mac <<= 8;
- mac |= addr[i];
- }
- return mac;
-}
static const __be32 mlx4_ib_opcode[] = {
[IB_WR_SEND] = cpu_to_be32(MLX4_OPCODE_SEND),
@@ -628,6 +623,8 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
struct mlx4_ib_sqp *sqp;
struct mlx4_ib_qp *qp;
enum mlx4_ib_qp_type qp_type = (enum mlx4_ib_qp_type) init_attr->qp_type;
+ struct mlx4_ib_cq *mcq;
+ unsigned long flags;
/* When tunneling special qps, we use a plain UD qp */
if (sqpn) {
@@ -838,6 +835,24 @@ static int create_qp_common(struct mlx4_ib_dev *dev, struct ib_pd *pd,
qp->mqp.event = mlx4_ib_qp_event;
if (!*caller_qp)
*caller_qp = qp;
+
+ spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
+ mlx4_ib_lock_cqs(to_mcq(init_attr->send_cq),
+ to_mcq(init_attr->recv_cq));
+ /* Maintain device to QPs access, needed for further handling
+ * via reset flow
+ */
+ list_add_tail(&qp->qps_list, &dev->qp_list);
+ /* Maintain CQ to QPs access, needed for further handling
+ * via reset flow
+ */
+ mcq = to_mcq(init_attr->send_cq);
+ list_add_tail(&qp->cq_send_list, &mcq->send_qp_list);
+ mcq = to_mcq(init_attr->recv_cq);
+ list_add_tail(&qp->cq_recv_list, &mcq->recv_qp_list);
+ mlx4_ib_unlock_cqs(to_mcq(init_attr->send_cq),
+ to_mcq(init_attr->recv_cq));
+ spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
return 0;
err_qpn:
@@ -896,13 +911,13 @@ static void mlx4_ib_lock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *recv
__acquires(&send_cq->lock) __acquires(&recv_cq->lock)
{
if (send_cq == recv_cq) {
- spin_lock_irq(&send_cq->lock);
+ spin_lock(&send_cq->lock);
__acquire(&recv_cq->lock);
} else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
- spin_lock_irq(&send_cq->lock);
+ spin_lock(&send_cq->lock);
spin_lock_nested(&recv_cq->lock, SINGLE_DEPTH_NESTING);
} else {
- spin_lock_irq(&recv_cq->lock);
+ spin_lock(&recv_cq->lock);
spin_lock_nested(&send_cq->lock, SINGLE_DEPTH_NESTING);
}
}
@@ -912,13 +927,13 @@ static void mlx4_ib_unlock_cqs(struct mlx4_ib_cq *send_cq, struct mlx4_ib_cq *re
{
if (send_cq == recv_cq) {
__release(&recv_cq->lock);
- spin_unlock_irq(&send_cq->lock);
+ spin_unlock(&send_cq->lock);
} else if (send_cq->mcq.cqn < recv_cq->mcq.cqn) {
spin_unlock(&recv_cq->lock);
- spin_unlock_irq(&send_cq->lock);
+ spin_unlock(&send_cq->lock);
} else {
spin_unlock(&send_cq->lock);
- spin_unlock_irq(&recv_cq->lock);
+ spin_unlock(&recv_cq->lock);
}
}
@@ -963,6 +978,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
int is_user)
{
struct mlx4_ib_cq *send_cq, *recv_cq;
+ unsigned long flags;
if (qp->state != IB_QPS_RESET) {
if (mlx4_qp_modify(dev->dev, NULL, to_mlx4_state(qp->state),
@@ -994,8 +1010,13 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
get_cqs(qp, &send_cq, &recv_cq);
+ spin_lock_irqsave(&dev->reset_flow_resource_lock, flags);
mlx4_ib_lock_cqs(send_cq, recv_cq);
+ /* del from lists under both locks above to protect reset flow paths */
+ list_del(&qp->qps_list);
+ list_del(&qp->cq_send_list);
+ list_del(&qp->cq_recv_list);
if (!is_user) {
__mlx4_ib_cq_clean(recv_cq, qp->mqp.qpn,
qp->ibqp.srq ? to_msrq(qp->ibqp.srq): NULL);
@@ -1006,6 +1027,7 @@ static void destroy_qp_common(struct mlx4_ib_dev *dev, struct mlx4_ib_qp *qp,
mlx4_qp_remove(dev->dev, &qp->mqp);
mlx4_ib_unlock_cqs(send_cq, recv_cq);
+ spin_unlock_irqrestore(&dev->reset_flow_resource_lock, flags);
mlx4_qp_free(dev->dev, &qp->mqp);
@@ -1674,8 +1696,10 @@ static int __mlx4_ib_modify_qp(struct ib_qp *ibqp,
qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI ||
qp->mlx4_ib_qp_type == MLX4_IB_QPT_TUN_GSI) {
err = handle_eth_ud_smac_index(dev, qp, (u8 *)attr->smac, context);
- if (err)
- return -EINVAL;
+ if (err) {
+ err = -EINVAL;
+ goto out;
+ }
if (qp->mlx4_ib_qp_type == MLX4_IB_QPT_PROXY_GSI)
dev->qp1_proxy[qp->port - 1] = qp;
}
@@ -1915,6 +1939,22 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
goto out;
}
+ if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT)) {
+ if ((cur_state == IB_QPS_RESET) && (new_state == IB_QPS_INIT)) {
+ if ((ibqp->qp_type == IB_QPT_RC) ||
+ (ibqp->qp_type == IB_QPT_UD) ||
+ (ibqp->qp_type == IB_QPT_UC) ||
+ (ibqp->qp_type == IB_QPT_RAW_PACKET) ||
+ (ibqp->qp_type == IB_QPT_XRC_INI)) {
+ attr->port_num = mlx4_ib_bond_next_port(dev);
+ }
+ } else {
+ /* no sense in changing port_num
+ * when ports are bonded */
+ attr_mask &= ~IB_QP_PORT;
+ }
+ }
+
if ((attr_mask & IB_QP_PORT) &&
(attr->port_num == 0 || attr->port_num > dev->num_ports)) {
pr_debug("qpn 0x%x: invalid port number (%d) specified "
@@ -1965,6 +2005,9 @@ int mlx4_ib_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
err = __mlx4_ib_modify_qp(ibqp, attr, attr_mask, cur_state, new_state);
+ if (mlx4_is_bonded(dev->dev) && (attr_mask & IB_QP_PORT))
+ attr->port_num = 1;
+
out:
mutex_unlock(&qp->mutex);
return err;
@@ -2609,8 +2652,15 @@ int mlx4_ib_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
__be32 uninitialized_var(lso_hdr_sz);
__be32 blh;
int i;
+ struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
spin_lock_irqsave(&qp->sq.lock, flags);
+ if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ err = -EIO;
+ *bad_wr = wr;
+ nreq = 0;
+ goto out;
+ }
ind = qp->sq_next_wqe;
@@ -2908,10 +2958,18 @@ int mlx4_ib_post_recv(struct ib_qp *ibqp, struct ib_recv_wr *wr,
int ind;
int max_gs;
int i;
+ struct mlx4_ib_dev *mdev = to_mdev(ibqp->device);
max_gs = qp->rq.max_gs;
spin_lock_irqsave(&qp->rq.lock, flags);
+ if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ err = -EIO;
+ *bad_wr = wr;
+ nreq = 0;
+ goto out;
+ }
+
ind = qp->rq.head & (qp->rq.wqe_cnt - 1);
for (nreq = 0; wr; ++nreq, wr = wr->next) {
diff --git a/drivers/infiniband/hw/mlx4/srq.c b/drivers/infiniband/hw/mlx4/srq.c
index 62d9285300af..dce5dfe3a70e 100644
--- a/drivers/infiniband/hw/mlx4/srq.c
+++ b/drivers/infiniband/hw/mlx4/srq.c
@@ -316,8 +316,15 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
int err = 0;
int nreq;
int i;
+ struct mlx4_ib_dev *mdev = to_mdev(ibsrq->device);
spin_lock_irqsave(&srq->lock, flags);
+ if (mdev->dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ err = -EIO;
+ *bad_wr = wr;
+ nreq = 0;
+ goto out;
+ }
for (nreq = 0; wr; ++nreq, wr = wr->next) {
if (unlikely(wr->num_sge > srq->msrq.max_gs)) {
@@ -362,6 +369,7 @@ int mlx4_ib_post_srq_recv(struct ib_srq *ibsrq, struct ib_recv_wr *wr,
*srq->db.db = cpu_to_be32(srq->wqe_ctr);
}
+out:
spin_unlock_irqrestore(&srq->lock, flags);
diff --git a/drivers/infiniband/hw/mlx4/sysfs.c b/drivers/infiniband/hw/mlx4/sysfs.c
index cb4c66e723b5..d10c2b8a5dad 100644
--- a/drivers/infiniband/hw/mlx4/sysfs.c
+++ b/drivers/infiniband/hw/mlx4/sysfs.c
@@ -375,7 +375,7 @@ static void get_name(struct mlx4_ib_dev *dev, char *name, int i, int max)
char base_name[9];
/* pci_name format is: bus:dev:func -> xxxx:yy:zz.n */
- strlcpy(name, pci_name(dev->dev->pdev), max);
+ strlcpy(name, pci_name(dev->dev->persist->pdev), max);
strncpy(base_name, name, 8); /*till xxxx:yy:*/
base_name[8] = '\0';
/* with no ARI only 3 last bits are used so when the fn is higher than 8
@@ -792,7 +792,7 @@ static int register_pkey_tree(struct mlx4_ib_dev *device)
if (!mlx4_is_master(device->dev))
return 0;
- for (i = 0; i <= device->dev->num_vfs; ++i)
+ for (i = 0; i <= device->dev->persist->num_vfs; ++i)
register_one_pkey_tree(device, i);
return 0;
@@ -807,7 +807,7 @@ static void unregister_pkey_tree(struct mlx4_ib_dev *device)
if (!mlx4_is_master(device->dev))
return;
- for (slave = device->dev->num_vfs; slave >= 0; --slave) {
+ for (slave = device->dev->persist->num_vfs; slave >= 0; --slave) {
list_for_each_entry_safe(p, t,
&device->pkeys.pkey_port_list[slave],
entry) {
diff --git a/drivers/infiniband/hw/mlx5/main.c b/drivers/infiniband/hw/mlx5/main.c
index 8a87404e9c76..cc4ac1e583b2 100644
--- a/drivers/infiniband/hw/mlx5/main.c
+++ b/drivers/infiniband/hw/mlx5/main.c
@@ -997,7 +997,7 @@ static int get_port_caps(struct mlx5_ib_dev *dev)
struct ib_device_attr *dprops = NULL;
struct ib_port_attr *pprops = NULL;
struct mlx5_general_caps *gen;
- int err = 0;
+ int err = -ENOMEM;
int port;
gen = &dev->mdev->caps.gen;
diff --git a/drivers/infiniband/hw/mlx5/mem.c b/drivers/infiniband/hw/mlx5/mem.c
index b56e4c5593ee..611a9fdf2f38 100644
--- a/drivers/infiniband/hw/mlx5/mem.c
+++ b/drivers/infiniband/hw/mlx5/mem.c
@@ -81,7 +81,7 @@ void mlx5_ib_cont_pages(struct ib_umem *umem, u64 addr, int *count, int *shift,
for (k = 0; k < len; k++) {
if (!(i & mask)) {
tmp = (unsigned long)pfn;
- m = min(m, find_first_bit(&tmp, sizeof(tmp)));
+ m = min_t(unsigned long, m, find_first_bit(&tmp, sizeof(tmp)));
skip = 1 << m;
mask = skip - 1;
base = pfn;
diff --git a/drivers/infiniband/hw/mlx5/mr.c b/drivers/infiniband/hw/mlx5/mr.c
index 32a28bd50b20..cd9822eeacae 100644
--- a/drivers/infiniband/hw/mlx5/mr.c
+++ b/drivers/infiniband/hw/mlx5/mr.c
@@ -1012,6 +1012,7 @@ static struct mlx5_ib_mr *reg_create(struct ib_pd *pd, u64 virt_addr,
goto err_2;
}
mr->umem = umem;
+ mr->dev = dev;
mr->live = 1;
kvfree(in);
diff --git a/drivers/infiniband/hw/nes/nes_nic.c b/drivers/infiniband/hw/nes/nes_nic.c
index 49eb5111d2cd..70acda91eb2a 100644
--- a/drivers/infiniband/hw/nes/nes_nic.c
+++ b/drivers/infiniband/hw/nes/nes_nic.c
@@ -373,11 +373,11 @@ static int nes_nic_send(struct sk_buff *skb, struct net_device *netdev)
wqe_fragment_length = (__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
/* setup the VLAN tag if present */
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
- netdev->name, vlan_tx_tag_get(skb));
+ netdev->name, skb_vlan_tag_get(skb));
wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
- wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb);
+ wqe_fragment_length[0] = (__force __le16) skb_vlan_tag_get(skb);
} else
wqe_misc = 0;
@@ -576,11 +576,12 @@ tso_sq_no_longer_full:
wqe_fragment_length =
(__le16 *)&nic_sqe->wqe_words[NES_NIC_SQ_WQE_LENGTH_0_TAG_IDX];
/* setup the VLAN tag if present */
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
nes_debug(NES_DBG_NIC_TX, "%s: VLAN packet to send... VLAN = %08X\n",
- netdev->name, vlan_tx_tag_get(skb) );
+ netdev->name,
+ skb_vlan_tag_get(skb));
wqe_misc = NES_NIC_SQ_WQE_TAGVALUE_ENABLE;
- wqe_fragment_length[0] = (__force __le16) vlan_tx_tag_get(skb);
+ wqe_fragment_length[0] = (__force __le16) skb_vlan_tag_get(skb);
} else
wqe_misc = 0;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma.h b/drivers/infiniband/hw/ocrdma/ocrdma.h
index b43456ae124b..c9780d919769 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma.h
@@ -40,7 +40,7 @@
#include <be_roce.h>
#include "ocrdma_sli.h"
-#define OCRDMA_ROCE_DRV_VERSION "10.2.287.0u"
+#define OCRDMA_ROCE_DRV_VERSION "10.4.205.0u"
#define OCRDMA_ROCE_DRV_DESC "Emulex OneConnect RoCE Driver"
#define OCRDMA_NODE_DESC "Emulex OneConnect RoCE HCA"
@@ -55,12 +55,19 @@
#define OCRDMA_UVERBS(CMD_NAME) (1ull << IB_USER_VERBS_CMD_##CMD_NAME)
#define convert_to_64bit(lo, hi) ((u64)hi << 32 | (u64)lo)
+#define EQ_INTR_PER_SEC_THRSH_HI 150000
+#define EQ_INTR_PER_SEC_THRSH_LOW 100000
+#define EQ_AIC_MAX_EQD 20
+#define EQ_AIC_MIN_EQD 0
+
+void ocrdma_eqd_set_task(struct work_struct *work);
struct ocrdma_dev_attr {
u8 fw_ver[32];
u32 vendor_id;
u32 device_id;
u16 max_pd;
+ u16 max_dpp_pds;
u16 max_cq;
u16 max_cqe;
u16 max_qp;
@@ -116,12 +123,19 @@ struct ocrdma_queue_info {
bool created;
};
+struct ocrdma_aic_obj { /* Adaptive interrupt coalescing (AIC) info */
+ u32 prev_eqd;
+ u64 eq_intr_cnt;
+ u64 prev_eq_intr_cnt;
+};
+
struct ocrdma_eq {
struct ocrdma_queue_info q;
u32 vector;
int cq_cnt;
struct ocrdma_dev *dev;
char irq_name[32];
+ struct ocrdma_aic_obj aic_obj;
};
struct ocrdma_mq {
@@ -171,6 +185,21 @@ struct ocrdma_stats {
struct ocrdma_dev *dev;
};
+struct ocrdma_pd_resource_mgr {
+ u32 pd_norm_start;
+ u16 pd_norm_count;
+ u16 pd_norm_thrsh;
+ u16 max_normal_pd;
+ u32 pd_dpp_start;
+ u16 pd_dpp_count;
+ u16 pd_dpp_thrsh;
+ u16 max_dpp_pd;
+ u16 dpp_page_index;
+ unsigned long *pd_norm_bitmap;
+ unsigned long *pd_dpp_bitmap;
+ bool pd_prealloc_valid;
+};
+
struct stats_mem {
struct ocrdma_mqe mqe;
void *va;
@@ -198,6 +227,7 @@ struct ocrdma_dev {
struct ocrdma_eq *eq_tbl;
int eq_cnt;
+ struct delayed_work eqd_work;
u16 base_eqid;
u16 max_eq;
@@ -255,7 +285,12 @@ struct ocrdma_dev {
struct ocrdma_stats rx_qp_err_stats;
struct ocrdma_stats tx_dbg_stats;
struct ocrdma_stats rx_dbg_stats;
+ struct ocrdma_stats driver_stats;
+ struct ocrdma_stats reset_stats;
struct dentry *dir;
+ atomic_t async_err_stats[OCRDMA_MAX_ASYNC_ERRORS];
+ atomic_t cqe_err_stats[OCRDMA_MAX_CQE_ERR];
+ struct ocrdma_pd_resource_mgr *pd_mgr;
};
struct ocrdma_cq {
@@ -335,7 +370,6 @@ struct ocrdma_srq {
struct ocrdma_qp {
struct ib_qp ibqp;
- struct ocrdma_dev *dev;
u8 __iomem *sq_db;
struct ocrdma_qp_hwq_info sq;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
index f3cc8c9e65ae..d812904f3984 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.c
@@ -29,19 +29,22 @@
#include <net/netevent.h>
#include <rdma/ib_addr.h>
+#include <rdma/ib_mad.h>
#include "ocrdma.h"
#include "ocrdma_verbs.h"
#include "ocrdma_ah.h"
#include "ocrdma_hw.h"
+#include "ocrdma_stats.h"
#define OCRDMA_VID_PCP_SHIFT 0xD
static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
- struct ib_ah_attr *attr, union ib_gid *sgid, int pdid)
+ struct ib_ah_attr *attr, union ib_gid *sgid,
+ int pdid, bool *isvlan)
{
int status = 0;
- u16 vlan_tag; bool vlan_enabled = false;
+ u16 vlan_tag;
struct ocrdma_eth_vlan eth;
struct ocrdma_grh grh;
int eth_sz;
@@ -59,7 +62,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
vlan_tag |= (dev->sl & 0x07) << OCRDMA_VID_PCP_SHIFT;
eth.vlan_tag = cpu_to_be16(vlan_tag);
eth_sz = sizeof(struct ocrdma_eth_vlan);
- vlan_enabled = true;
+ *isvlan = true;
} else {
eth.eth_type = cpu_to_be16(OCRDMA_ROCE_ETH_TYPE);
eth_sz = sizeof(struct ocrdma_eth_basic);
@@ -82,7 +85,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
/* Eth HDR */
memcpy(&ah->av->eth_hdr, &eth, eth_sz);
memcpy((u8 *)ah->av + eth_sz, &grh, sizeof(struct ocrdma_grh));
- if (vlan_enabled)
+ if (*isvlan)
ah->av->valid |= OCRDMA_AV_VLAN_VALID;
ah->av->valid = cpu_to_le32(ah->av->valid);
return status;
@@ -91,6 +94,7 @@ static inline int set_av_attr(struct ocrdma_dev *dev, struct ocrdma_ah *ah,
struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
{
u32 *ahid_addr;
+ bool isvlan = false;
int status;
struct ocrdma_ah *ah;
struct ocrdma_pd *pd = get_ocrdma_pd(ibpd);
@@ -127,15 +131,20 @@ struct ib_ah *ocrdma_create_ah(struct ib_pd *ibpd, struct ib_ah_attr *attr)
}
}
- status = set_av_attr(dev, ah, attr, &sgid, pd->id);
+ status = set_av_attr(dev, ah, attr, &sgid, pd->id, &isvlan);
if (status)
goto av_conf_err;
/* if pd is for the user process, pass the ah_id to user space */
if ((pd->uctx) && (pd->uctx->ah_tbl.va)) {
ahid_addr = pd->uctx->ah_tbl.va + attr->dlid;
- *ahid_addr = ah->id;
+ *ahid_addr = 0;
+ *ahid_addr |= ah->id & OCRDMA_AH_ID_MASK;
+ if (isvlan)
+ *ahid_addr |= (OCRDMA_AH_VLAN_VALID_MASK <<
+ OCRDMA_AH_VLAN_VALID_SHIFT);
}
+
return &ah->ibah;
av_conf_err:
@@ -191,5 +200,20 @@ int ocrdma_process_mad(struct ib_device *ibdev,
struct ib_grh *in_grh,
struct ib_mad *in_mad, struct ib_mad *out_mad)
{
- return IB_MAD_RESULT_SUCCESS;
+ int status;
+ struct ocrdma_dev *dev;
+
+ switch (in_mad->mad_hdr.mgmt_class) {
+ case IB_MGMT_CLASS_PERF_MGMT:
+ dev = get_ocrdma_dev(ibdev);
+ if (!ocrdma_pma_counters(dev, out_mad))
+ status = IB_MAD_RESULT_SUCCESS | IB_MAD_RESULT_REPLY;
+ else
+ status = IB_MAD_RESULT_SUCCESS;
+ break;
+ default:
+ status = IB_MAD_RESULT_SUCCESS;
+ break;
+ }
+ return status;
}
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
index 8ac49e7f96d1..726a87cf22dc 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_ah.h
@@ -28,6 +28,12 @@
#ifndef __OCRDMA_AH_H__
#define __OCRDMA_AH_H__
+enum {
+ OCRDMA_AH_ID_MASK = 0x3FF,
+ OCRDMA_AH_VLAN_VALID_MASK = 0x01,
+ OCRDMA_AH_VLAN_VALID_SHIFT = 0x1F
+};
+
struct ib_ah *ocrdma_create_ah(struct ib_pd *, struct ib_ah_attr *);
int ocrdma_destroy_ah(struct ib_ah *);
int ocrdma_query_ah(struct ib_ah *, struct ib_ah_attr *);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
index 638bff1ffc6c..0c9e95909a64 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.c
@@ -734,6 +734,9 @@ static void ocrdma_dispatch_ibevent(struct ocrdma_dev *dev,
break;
}
+ if (type < OCRDMA_MAX_ASYNC_ERRORS)
+ atomic_inc(&dev->async_err_stats[type]);
+
if (qp_event) {
if (qp->ibqp.event_handler)
qp->ibqp.event_handler(&ib_evt, qp->ibqp.qp_context);
@@ -831,20 +834,20 @@ static int ocrdma_mq_cq_handler(struct ocrdma_dev *dev, u16 cq_id)
return 0;
}
-static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
- struct ocrdma_cq *cq)
+static struct ocrdma_cq *_ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq, bool sq)
{
- unsigned long flags;
struct ocrdma_qp *qp;
- bool buddy_cq_found = false;
- /* Go through list of QPs in error state which are using this CQ
- * and invoke its callback handler to trigger CQE processing for
- * error/flushed CQE. It is rare to find more than few entries in
- * this list as most consumers stops after getting error CQE.
- * List is traversed only once when a matching buddy cq found for a QP.
- */
- spin_lock_irqsave(&dev->flush_q_lock, flags);
- list_for_each_entry(qp, &cq->sq_head, sq_entry) {
+ struct list_head *cur;
+ struct ocrdma_cq *bcq = NULL;
+ struct list_head *head = sq?(&cq->sq_head):(&cq->rq_head);
+
+ list_for_each(cur, head) {
+ if (sq)
+ qp = list_entry(cur, struct ocrdma_qp, sq_entry);
+ else
+ qp = list_entry(cur, struct ocrdma_qp, rq_entry);
+
if (qp->srq)
continue;
/* if wq and rq share the same cq, than comp_handler
@@ -856,19 +859,41 @@ static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
* if completion came on rq, sq's cq is buddy cq.
*/
if (qp->sq_cq == cq)
- cq = qp->rq_cq;
+ bcq = qp->rq_cq;
else
- cq = qp->sq_cq;
- buddy_cq_found = true;
- break;
+ bcq = qp->sq_cq;
+ return bcq;
}
+ return NULL;
+}
+
+static void ocrdma_qp_buddy_cq_handler(struct ocrdma_dev *dev,
+ struct ocrdma_cq *cq)
+{
+ unsigned long flags;
+ struct ocrdma_cq *bcq = NULL;
+
+ /* Go through list of QPs in error state which are using this CQ
+ * and invoke its callback handler to trigger CQE processing for
+ * error/flushed CQE. It is rare to find more than few entries in
+ * this list as most consumers stops after getting error CQE.
+ * List is traversed only once when a matching buddy cq found for a QP.
+ */
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
+ /* Check if buddy CQ is present.
+ * true - Check for SQ CQ
+ * false - Check for RQ CQ
+ */
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, true);
+ if (bcq == NULL)
+ bcq = _ocrdma_qp_buddy_cq_handler(dev, cq, false);
spin_unlock_irqrestore(&dev->flush_q_lock, flags);
- if (buddy_cq_found == false)
- return;
- if (cq->ibcq.comp_handler) {
- spin_lock_irqsave(&cq->comp_handler_lock, flags);
- (*cq->ibcq.comp_handler) (&cq->ibcq, cq->ibcq.cq_context);
- spin_unlock_irqrestore(&cq->comp_handler_lock, flags);
+
+ /* if there is valid buddy cq, look for its completion handler */
+ if (bcq && bcq->ibcq.comp_handler) {
+ spin_lock_irqsave(&bcq->comp_handler_lock, flags);
+ (*bcq->ibcq.comp_handler) (&bcq->ibcq, bcq->ibcq.cq_context);
+ spin_unlock_irqrestore(&bcq->comp_handler_lock, flags);
}
}
@@ -935,6 +960,7 @@ static irqreturn_t ocrdma_irq_handler(int irq, void *handle)
} while (budget);
+ eq->aic_obj.eq_intr_cnt++;
ocrdma_ring_eq_db(dev, eq->q.id, true, true, 0);
return IRQ_HANDLED;
}
@@ -1050,6 +1076,9 @@ static void ocrdma_get_attr(struct ocrdma_dev *dev,
attr->max_pd =
(rsp->max_pd_ca_ack_delay & OCRDMA_MBX_QUERY_CFG_MAX_PD_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_PD_SHIFT;
+ attr->max_dpp_pds =
+ (rsp->max_dpp_pds_credits & OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_MASK) >>
+ OCRDMA_MBX_QUERY_CFG_MAX_DPP_PDS_OFFSET;
attr->max_qp =
(rsp->qp_srq_cq_ird_ord & OCRDMA_MBX_QUERY_CFG_MAX_QP_MASK) >>
OCRDMA_MBX_QUERY_CFG_MAX_QP_SHIFT;
@@ -1396,6 +1425,122 @@ int ocrdma_mbx_dealloc_pd(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
return status;
}
+
+static int ocrdma_mbx_alloc_pd_range(struct ocrdma_dev *dev)
+{
+ int status = -ENOMEM;
+ size_t pd_bitmap_size;
+ struct ocrdma_alloc_pd_range *cmd;
+ struct ocrdma_alloc_pd_range_rsp *rsp;
+
+ /* Pre allocate the DPP PDs */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+ cmd->pd_count = dev->attr.max_dpp_pds;
+ cmd->enable_dpp_rsvd |= OCRDMA_ALLOC_PD_ENABLE_DPP;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+
+ if ((rsp->dpp_page_pdid & OCRDMA_ALLOC_PD_RSP_DPP) && rsp->pd_count) {
+ dev->pd_mgr->dpp_page_index = rsp->dpp_page_pdid >>
+ OCRDMA_ALLOC_PD_RSP_DPP_PAGE_SHIFT;
+ dev->pd_mgr->pd_dpp_start = rsp->dpp_page_pdid &
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+ dev->pd_mgr->max_dpp_pd = rsp->pd_count;
+ pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+ dev->pd_mgr->pd_dpp_bitmap = kzalloc(pd_bitmap_size,
+ GFP_KERNEL);
+ }
+ kfree(cmd);
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_ALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->pd_count = dev->attr.max_pd - dev->attr.max_dpp_pds;
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+ rsp = (struct ocrdma_alloc_pd_range_rsp *)cmd;
+ if (rsp->pd_count) {
+ dev->pd_mgr->pd_norm_start = rsp->dpp_page_pdid &
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK;
+ dev->pd_mgr->max_normal_pd = rsp->pd_count;
+ pd_bitmap_size = BITS_TO_LONGS(rsp->pd_count) * sizeof(long);
+ dev->pd_mgr->pd_norm_bitmap = kzalloc(pd_bitmap_size,
+ GFP_KERNEL);
+ }
+
+ if (dev->pd_mgr->pd_norm_bitmap || dev->pd_mgr->pd_dpp_bitmap) {
+ /* Enable PD resource manager */
+ dev->pd_mgr->pd_prealloc_valid = true;
+ } else {
+ return -ENOMEM;
+ }
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static void ocrdma_mbx_dealloc_pd_range(struct ocrdma_dev *dev)
+{
+ struct ocrdma_dealloc_pd_range *cmd;
+
+ /* return normal PDs to firmware */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE, sizeof(*cmd));
+ if (!cmd)
+ goto mbx_err;
+
+ if (dev->pd_mgr->max_normal_pd) {
+ cmd->start_pd_id = dev->pd_mgr->pd_norm_start;
+ cmd->pd_count = dev->pd_mgr->max_normal_pd;
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ }
+
+ if (dev->pd_mgr->max_dpp_pd) {
+ kfree(cmd);
+ /* return DPP PDs to firmware */
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_DEALLOC_PD_RANGE,
+ sizeof(*cmd));
+ if (!cmd)
+ goto mbx_err;
+
+ cmd->start_pd_id = dev->pd_mgr->pd_dpp_start;
+ cmd->pd_count = dev->pd_mgr->max_dpp_pd;
+ ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ }
+mbx_err:
+ kfree(cmd);
+}
+
+void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev)
+{
+ int status;
+
+ dev->pd_mgr = kzalloc(sizeof(struct ocrdma_pd_resource_mgr),
+ GFP_KERNEL);
+ if (!dev->pd_mgr) {
+ pr_err("%s(%d)Memory allocation failure.\n", __func__, dev->id);
+ return;
+ }
+ status = ocrdma_mbx_alloc_pd_range(dev);
+ if (status) {
+ pr_err("%s(%d) Unable to initialize PD pool, using default.\n",
+ __func__, dev->id);
+ }
+}
+
+static void ocrdma_free_pd_pool(struct ocrdma_dev *dev)
+{
+ ocrdma_mbx_dealloc_pd_range(dev);
+ kfree(dev->pd_mgr->pd_norm_bitmap);
+ kfree(dev->pd_mgr->pd_dpp_bitmap);
+ kfree(dev->pd_mgr);
+}
+
static int ocrdma_build_q_conf(u32 *num_entries, int entry_size,
int *num_pages, int *page_size)
{
@@ -1896,8 +2041,9 @@ void ocrdma_flush_qp(struct ocrdma_qp *qp)
{
bool found;
unsigned long flags;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
- spin_lock_irqsave(&qp->dev->flush_q_lock, flags);
+ spin_lock_irqsave(&dev->flush_q_lock, flags);
found = ocrdma_is_qp_in_sq_flushlist(qp->sq_cq, qp);
if (!found)
list_add_tail(&qp->sq_entry, &qp->sq_cq->sq_head);
@@ -1906,7 +2052,7 @@ void ocrdma_flush_qp(struct ocrdma_qp *qp)
if (!found)
list_add_tail(&qp->rq_entry, &qp->rq_cq->rq_head);
}
- spin_unlock_irqrestore(&qp->dev->flush_q_lock, flags);
+ spin_unlock_irqrestore(&dev->flush_q_lock, flags);
}
static void ocrdma_init_hwq_ptr(struct ocrdma_qp *qp)
@@ -1972,7 +2118,8 @@ static int ocrdma_set_create_qp_sq_cmd(struct ocrdma_create_qp_req *cmd,
int status;
u32 len, hw_pages, hw_page_size;
dma_addr_t pa;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
u32 max_wqe_allocated;
u32 max_sges = attrs->cap.max_send_sge;
@@ -2027,7 +2174,8 @@ static int ocrdma_set_create_qp_rq_cmd(struct ocrdma_create_qp_req *cmd,
int status;
u32 len, hw_pages, hw_page_size;
dma_addr_t pa = 0;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
u32 max_rqe_allocated = attrs->cap.max_recv_wr + 1;
@@ -2086,7 +2234,8 @@ static void ocrdma_set_create_qp_dpp_cmd(struct ocrdma_create_qp_req *cmd,
static int ocrdma_set_create_qp_ird_cmd(struct ocrdma_create_qp_req *cmd,
struct ocrdma_qp *qp)
{
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
dma_addr_t pa = 0;
int ird_page_size = dev->attr.ird_page_size;
@@ -2157,8 +2306,8 @@ int ocrdma_mbx_create_qp(struct ocrdma_qp *qp, struct ib_qp_init_attr *attrs,
{
int status = -ENOMEM;
u32 flags = 0;
- struct ocrdma_dev *dev = qp->dev;
struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
struct pci_dev *pdev = dev->nic_info.pdev;
struct ocrdma_cq *cq;
struct ocrdma_create_qp_req *cmd;
@@ -2281,11 +2430,12 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
union ib_gid sgid, zgid;
u32 vlan_id;
u8 mac_addr[6];
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
if ((ah_attr->ah_flags & IB_AH_GRH) == 0)
return -EINVAL;
- if (atomic_cmpxchg(&qp->dev->update_sl, 1, 0))
- ocrdma_init_service_level(qp->dev);
+ if (atomic_cmpxchg(&dev->update_sl, 1, 0))
+ ocrdma_init_service_level(dev);
cmd->params.tclass_sq_psn |=
(ah_attr->grh.traffic_class << OCRDMA_QP_PARAMS_TCLASS_SHIFT);
cmd->params.rnt_rc_sl_fl |=
@@ -2296,7 +2446,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
cmd->flags |= OCRDMA_QP_PARA_FLOW_LBL_VALID;
memcpy(&cmd->params.dgid[0], &ah_attr->grh.dgid.raw[0],
sizeof(cmd->params.dgid));
- status = ocrdma_query_gid(&qp->dev->ibdev, 1,
+ status = ocrdma_query_gid(&dev->ibdev, 1,
ah_attr->grh.sgid_index, &sgid);
if (status)
return status;
@@ -2307,7 +2457,9 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
qp->sgid_idx = ah_attr->grh.sgid_index;
memcpy(&cmd->params.sgid[0], &sgid.raw[0], sizeof(cmd->params.sgid));
- ocrdma_resolve_dmac(qp->dev, ah_attr, &mac_addr[0]);
+ status = ocrdma_resolve_dmac(dev, ah_attr, &mac_addr[0]);
+ if (status)
+ return status;
cmd->params.dmac_b0_to_b3 = mac_addr[0] | (mac_addr[1] << 8) |
(mac_addr[2] << 16) | (mac_addr[3] << 24);
/* convert them to LE format. */
@@ -2320,7 +2472,7 @@ static int ocrdma_set_av_params(struct ocrdma_qp *qp,
vlan_id << OCRDMA_QP_PARAMS_VLAN_SHIFT;
cmd->flags |= OCRDMA_QP_PARA_VLAN_EN_VALID;
cmd->params.rnt_rc_sl_fl |=
- (qp->dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
+ (dev->sl & 0x07) << OCRDMA_QP_PARAMS_SL_SHIFT;
}
return 0;
}
@@ -2330,6 +2482,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
struct ib_qp_attr *attrs, int attr_mask)
{
int status = 0;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
if (attr_mask & IB_QP_PKEY_INDEX) {
cmd->params.path_mtu_pkey_indx |= (attrs->pkey_index &
@@ -2347,12 +2500,12 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
return status;
} else if (qp->qp_type == IB_QPT_GSI || qp->qp_type == IB_QPT_UD) {
/* set the default mac address for UD, GSI QPs */
- cmd->params.dmac_b0_to_b3 = qp->dev->nic_info.mac_addr[0] |
- (qp->dev->nic_info.mac_addr[1] << 8) |
- (qp->dev->nic_info.mac_addr[2] << 16) |
- (qp->dev->nic_info.mac_addr[3] << 24);
- cmd->params.vlan_dmac_b4_to_b5 = qp->dev->nic_info.mac_addr[4] |
- (qp->dev->nic_info.mac_addr[5] << 8);
+ cmd->params.dmac_b0_to_b3 = dev->nic_info.mac_addr[0] |
+ (dev->nic_info.mac_addr[1] << 8) |
+ (dev->nic_info.mac_addr[2] << 16) |
+ (dev->nic_info.mac_addr[3] << 24);
+ cmd->params.vlan_dmac_b4_to_b5 = dev->nic_info.mac_addr[4] |
+ (dev->nic_info.mac_addr[5] << 8);
}
if ((attr_mask & IB_QP_EN_SQD_ASYNC_NOTIFY) &&
attrs->en_sqd_async_notify) {
@@ -2409,7 +2562,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
cmd->flags |= OCRDMA_QP_PARA_RQPSN_VALID;
}
if (attr_mask & IB_QP_MAX_QP_RD_ATOMIC) {
- if (attrs->max_rd_atomic > qp->dev->attr.max_ord_per_qp) {
+ if (attrs->max_rd_atomic > dev->attr.max_ord_per_qp) {
status = -EINVAL;
goto pmtu_err;
}
@@ -2417,7 +2570,7 @@ static int ocrdma_set_qp_params(struct ocrdma_qp *qp,
cmd->flags |= OCRDMA_QP_PARA_MAX_ORD_VALID;
}
if (attr_mask & IB_QP_MAX_DEST_RD_ATOMIC) {
- if (attrs->max_dest_rd_atomic > qp->dev->attr.max_ird_per_qp) {
+ if (attrs->max_dest_rd_atomic > dev->attr.max_ird_per_qp) {
status = -EINVAL;
goto pmtu_err;
}
@@ -2870,6 +3023,82 @@ done:
return status;
}
+static int ocrdma_mbx_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
+ int num)
+{
+ int i, status = -ENOMEM;
+ struct ocrdma_modify_eqd_req *cmd;
+
+ cmd = ocrdma_init_emb_mqe(OCRDMA_CMD_MODIFY_EQ_DELAY, sizeof(*cmd));
+ if (!cmd)
+ return status;
+
+ ocrdma_init_mch(&cmd->cmd.req, OCRDMA_CMD_MODIFY_EQ_DELAY,
+ OCRDMA_SUBSYS_COMMON, sizeof(*cmd));
+
+ cmd->cmd.num_eq = num;
+ for (i = 0; i < num; i++) {
+ cmd->cmd.set_eqd[i].eq_id = eq[i].q.id;
+ cmd->cmd.set_eqd[i].phase = 0;
+ cmd->cmd.set_eqd[i].delay_multiplier =
+ (eq[i].aic_obj.prev_eqd * 65)/100;
+ }
+ status = ocrdma_mbx_cmd(dev, (struct ocrdma_mqe *)cmd);
+ if (status)
+ goto mbx_err;
+mbx_err:
+ kfree(cmd);
+ return status;
+}
+
+static int ocrdma_modify_eqd(struct ocrdma_dev *dev, struct ocrdma_eq *eq,
+ int num)
+{
+ int num_eqs, i = 0;
+ if (num > 8) {
+ while (num) {
+ num_eqs = min(num, 8);
+ ocrdma_mbx_modify_eqd(dev, &eq[i], num_eqs);
+ i += num_eqs;
+ num -= num_eqs;
+ }
+ } else {
+ ocrdma_mbx_modify_eqd(dev, eq, num);
+ }
+ return 0;
+}
+
+void ocrdma_eqd_set_task(struct work_struct *work)
+{
+ struct ocrdma_dev *dev =
+ container_of(work, struct ocrdma_dev, eqd_work.work);
+ struct ocrdma_eq *eq = 0;
+ int i, num = 0, status = -EINVAL;
+ u64 eq_intr;
+
+ for (i = 0; i < dev->eq_cnt; i++) {
+ eq = &dev->eq_tbl[i];
+ if (eq->aic_obj.eq_intr_cnt > eq->aic_obj.prev_eq_intr_cnt) {
+ eq_intr = eq->aic_obj.eq_intr_cnt -
+ eq->aic_obj.prev_eq_intr_cnt;
+ if ((eq_intr > EQ_INTR_PER_SEC_THRSH_HI) &&
+ (eq->aic_obj.prev_eqd == EQ_AIC_MIN_EQD)) {
+ eq->aic_obj.prev_eqd = EQ_AIC_MAX_EQD;
+ num++;
+ } else if ((eq_intr < EQ_INTR_PER_SEC_THRSH_LOW) &&
+ (eq->aic_obj.prev_eqd == EQ_AIC_MAX_EQD)) {
+ eq->aic_obj.prev_eqd = EQ_AIC_MIN_EQD;
+ num++;
+ }
+ }
+ eq->aic_obj.prev_eq_intr_cnt = eq->aic_obj.eq_intr_cnt;
+ }
+
+ if (num)
+ status = ocrdma_modify_eqd(dev, &dev->eq_tbl[0], num);
+ schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
+}
+
int ocrdma_init_hw(struct ocrdma_dev *dev)
{
int status;
@@ -2915,6 +3144,7 @@ qpeq_err:
void ocrdma_cleanup_hw(struct ocrdma_dev *dev)
{
+ ocrdma_free_pd_pool(dev);
ocrdma_mbx_delete_ah_tbl(dev);
/* cleanup the eqs */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
index 6eed8f191322..e905972fceb7 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_hw.h
@@ -136,5 +136,7 @@ int ocrdma_get_irq(struct ocrdma_dev *dev, struct ocrdma_eq *eq);
int ocrdma_mbx_rdma_stats(struct ocrdma_dev *, bool reset);
char *port_speed_string(struct ocrdma_dev *dev);
void ocrdma_init_service_level(struct ocrdma_dev *);
+void ocrdma_alloc_pd_pool(struct ocrdma_dev *dev);
+void ocrdma_free_pd_range(struct ocrdma_dev *dev);
#endif /* __OCRDMA_HW_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_main.c b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
index b0b2257b8e04..7a2b59aca004 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_main.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_main.c
@@ -239,7 +239,7 @@ static int ocrdma_register_device(struct ocrdma_dev *dev)
dev->ibdev.node_type = RDMA_NODE_IB_CA;
dev->ibdev.phys_port_cnt = 1;
- dev->ibdev.num_comp_vectors = 1;
+ dev->ibdev.num_comp_vectors = dev->eq_cnt;
/* mandatory verbs. */
dev->ibdev.query_device = ocrdma_query_device;
@@ -329,6 +329,8 @@ static int ocrdma_alloc_resources(struct ocrdma_dev *dev)
if (dev->stag_arr == NULL)
goto alloc_err;
+ ocrdma_alloc_pd_pool(dev);
+
spin_lock_init(&dev->av_tbl.lock);
spin_lock_init(&dev->flush_q_lock);
return 0;
@@ -491,6 +493,9 @@ static struct ocrdma_dev *ocrdma_add(struct be_dev_info *dev_info)
spin_unlock(&ocrdma_devlist_lock);
/* Init stats */
ocrdma_add_port_stats(dev);
+ /* Interrupt Moderation */
+ INIT_DELAYED_WORK(&dev->eqd_work, ocrdma_eqd_set_task);
+ schedule_delayed_work(&dev->eqd_work, msecs_to_jiffies(1000));
pr_info("%s %s: %s \"%s\" port %d\n",
dev_name(&dev->nic_info.pdev->dev), hca_name(dev),
@@ -528,11 +533,12 @@ static void ocrdma_remove(struct ocrdma_dev *dev)
/* first unregister with stack to stop all the active traffic
* of the registered clients.
*/
- ocrdma_rem_port_stats(dev);
+ cancel_delayed_work_sync(&dev->eqd_work);
ocrdma_remove_sysfiles(dev);
-
ib_unregister_device(&dev->ibdev);
+ ocrdma_rem_port_stats(dev);
+
spin_lock(&ocrdma_devlist_lock);
list_del_rcu(&dev->entry);
spin_unlock(&ocrdma_devlist_lock);
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
index 4e036480c1a8..243c87c8bd65 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_sli.h
@@ -75,6 +75,8 @@ enum {
OCRDMA_CMD_DESTROY_RBQ = 26,
OCRDMA_CMD_GET_RDMA_STATS = 27,
+ OCRDMA_CMD_ALLOC_PD_RANGE = 28,
+ OCRDMA_CMD_DEALLOC_PD_RANGE = 29,
OCRDMA_CMD_MAX
};
@@ -87,6 +89,7 @@ enum {
OCRDMA_CMD_CREATE_MQ = 21,
OCRDMA_CMD_GET_CTRL_ATTRIBUTES = 32,
OCRDMA_CMD_GET_FW_VER = 35,
+ OCRDMA_CMD_MODIFY_EQ_DELAY = 41,
OCRDMA_CMD_DELETE_MQ = 53,
OCRDMA_CMD_DELETE_CQ = 54,
OCRDMA_CMD_DELETE_EQ = 55,
@@ -101,7 +104,7 @@ enum {
QTYPE_MCCQ = 3
};
-#define OCRDMA_MAX_SGID 8
+#define OCRDMA_MAX_SGID 16
#define OCRDMA_MAX_QP 2048
#define OCRDMA_MAX_CQ 2048
@@ -314,6 +317,29 @@ struct ocrdma_create_eq_rsp {
#define OCRDMA_EQ_MINOR_OTHER 0x1
+struct ocrmda_set_eqd {
+ u32 eq_id;
+ u32 phase;
+ u32 delay_multiplier;
+};
+
+struct ocrdma_modify_eqd_cmd {
+ struct ocrdma_mbx_hdr req;
+ u32 num_eq;
+ struct ocrmda_set_eqd set_eqd[8];
+} __packed;
+
+struct ocrdma_modify_eqd_req {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_modify_eqd_cmd cmd;
+};
+
+
+struct ocrdma_modify_eq_delay_rsp {
+ struct ocrdma_mbx_rsp hdr;
+ u32 rsvd0;
+} __packed;
+
enum {
OCRDMA_MCQE_STATUS_SHIFT = 0,
OCRDMA_MCQE_STATUS_MASK = 0xFFFF,
@@ -441,7 +467,9 @@ enum OCRDMA_ASYNC_EVENT_TYPE {
OCRDMA_DEVICE_FATAL_EVENT = 0x08,
OCRDMA_SRQCAT_ERROR = 0x0E,
OCRDMA_SRQ_LIMIT_EVENT = 0x0F,
- OCRDMA_QP_LAST_WQE_EVENT = 0x10
+ OCRDMA_QP_LAST_WQE_EVENT = 0x10,
+
+ OCRDMA_MAX_ASYNC_ERRORS
};
/* mailbox command request and responses */
@@ -1297,6 +1325,37 @@ struct ocrdma_dealloc_pd_rsp {
struct ocrdma_mbx_rsp rsp;
};
+struct ocrdma_alloc_pd_range {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 enable_dpp_rsvd;
+ u32 pd_count;
+};
+
+struct ocrdma_alloc_pd_range_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_rsp rsp;
+ u32 dpp_page_pdid;
+ u32 pd_count;
+};
+
+enum {
+ OCRDMA_ALLOC_PD_RNG_RSP_START_PDID_MASK = 0xFFFF,
+};
+
+struct ocrdma_dealloc_pd_range {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 start_pd_id;
+ u32 pd_count;
+};
+
+struct ocrdma_dealloc_pd_range_rsp {
+ struct ocrdma_mqe_hdr hdr;
+ struct ocrdma_mbx_hdr req;
+ u32 rsvd;
+};
+
enum {
OCRDMA_ADDR_CHECK_ENABLE = 1,
OCRDMA_ADDR_CHECK_DISABLE = 0
@@ -1597,7 +1656,9 @@ enum OCRDMA_CQE_STATUS {
OCRDMA_CQE_INV_EEC_STATE_ERR,
OCRDMA_CQE_FATAL_ERR,
OCRDMA_CQE_RESP_TIMEOUT_ERR,
- OCRDMA_CQE_GENERAL_ERR
+ OCRDMA_CQE_GENERAL_ERR,
+
+ OCRDMA_MAX_CQE_ERR
};
enum {
@@ -1673,6 +1734,7 @@ enum {
OCRDMA_FLAG_FENCE_R = 0x8,
OCRDMA_FLAG_SOLICIT = 0x10,
OCRDMA_FLAG_IMM = 0x20,
+ OCRDMA_FLAG_AH_VLAN_PR = 0x40,
/* Stag flags */
OCRDMA_LKEY_FLAG_LOCAL_WR = 0x1,
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
index 41a9aec9998d..48d7ef51aa0c 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.c
@@ -26,6 +26,7 @@
*******************************************************************/
#include <rdma/ib_addr.h>
+#include <rdma/ib_pma.h>
#include "ocrdma_stats.h"
static struct dentry *ocrdma_dbgfs_dir;
@@ -249,6 +250,27 @@ static char *ocrdma_rx_stats(struct ocrdma_dev *dev)
return stats;
}
+static u64 ocrdma_sysfs_rcv_pkts(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ return convert_to_64bit(rx_stats->roce_frames_lo,
+ rx_stats->roce_frames_hi) + (u64)rx_stats->roce_frame_icrc_drops
+ + (u64)rx_stats->roce_frame_payload_len_drops;
+}
+
+static u64 ocrdma_sysfs_rcv_data(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rx_stats *rx_stats = &rdma_stats->rx_stats;
+
+ return (convert_to_64bit(rx_stats->roce_frame_bytes_lo,
+ rx_stats->roce_frame_bytes_hi))/4;
+}
+
static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
{
char *stats = dev->stats_mem.debugfs_mem, *pcur;
@@ -292,6 +314,37 @@ static char *ocrdma_tx_stats(struct ocrdma_dev *dev)
return stats;
}
+static u64 ocrdma_sysfs_xmit_pkts(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ return (convert_to_64bit(tx_stats->send_pkts_lo,
+ tx_stats->send_pkts_hi) +
+ convert_to_64bit(tx_stats->write_pkts_lo, tx_stats->write_pkts_hi) +
+ convert_to_64bit(tx_stats->read_pkts_lo, tx_stats->read_pkts_hi) +
+ convert_to_64bit(tx_stats->read_rsp_pkts_lo,
+ tx_stats->read_rsp_pkts_hi) +
+ convert_to_64bit(tx_stats->ack_pkts_lo, tx_stats->ack_pkts_hi));
+}
+
+static u64 ocrdma_sysfs_xmit_data(struct ocrdma_dev *dev)
+{
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_tx_stats *tx_stats = &rdma_stats->tx_stats;
+
+ return (convert_to_64bit(tx_stats->send_bytes_lo,
+ tx_stats->send_bytes_hi) +
+ convert_to_64bit(tx_stats->write_bytes_lo,
+ tx_stats->write_bytes_hi) +
+ convert_to_64bit(tx_stats->read_req_bytes_lo,
+ tx_stats->read_req_bytes_hi) +
+ convert_to_64bit(tx_stats->read_rsp_bytes_lo,
+ tx_stats->read_rsp_bytes_hi))/4;
+}
+
static char *ocrdma_wqe_stats(struct ocrdma_dev *dev)
{
char *stats = dev->stats_mem.debugfs_mem, *pcur;
@@ -432,10 +485,118 @@ static char *ocrdma_rx_dbg_stats(struct ocrdma_dev *dev)
return dev->stats_mem.debugfs_mem;
}
+static char *ocrdma_driver_dbg_stats(struct ocrdma_dev *dev)
+{
+ char *stats = dev->stats_mem.debugfs_mem, *pcur;
+
+
+ memset(stats, 0, (OCRDMA_MAX_DBGFS_MEM));
+
+ pcur = stats;
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_err",
+ (u64)(dev->async_err_stats
+ [OCRDMA_CQ_ERROR].counter));
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_overrun_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_CQ_OVERRUN_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_cq_qpcat_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_CQ_QPCAT_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_access_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_ACCESS_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_commm_est_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_COMM_EST_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_sq_drained_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_SQ_DRAINED_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_dev_fatal_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_DEVICE_FATAL_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_srqcat_err",
+ (u64)dev->async_err_stats
+ [OCRDMA_SRQCAT_ERROR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_srq_limit_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_SRQ_LIMIT_EVENT].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "async_qp_last_wqe_evt",
+ (u64)dev->async_err_stats
+ [OCRDMA_QP_LAST_WQE_EVENT].counter);
+
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_len_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_LEN_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_qp_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_QP_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_eec_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_EEC_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_prot_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_PROT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_wr_flush_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_WR_FLUSH_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_mw_bind_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_MW_BIND_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_bad_resp_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_BAD_RESP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_access_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_ACCESS_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_req_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_INV_REQ_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_access_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_ACCESS_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_op_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_OP_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_retry_exc_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RETRY_EXC_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rnr_retry_exc_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RNR_RETRY_EXC_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_loc_rdd_viol_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_LOC_RDD_VIOL_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_inv_rd_req_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_INV_RD_REQ_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_rem_abort_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_REM_ABORT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eecn_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_INV_EECN_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_inv_eec_state_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_INV_EEC_STATE_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_fatal_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_FATAL_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_resp_timeout_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_RESP_TIMEOUT_ERR].counter);
+ pcur += ocrdma_add_stat(stats, pcur, "cqe_general_err",
+ (u64)dev->cqe_err_stats
+ [OCRDMA_CQE_GENERAL_ERR].counter);
+ return stats;
+}
+
static void ocrdma_update_stats(struct ocrdma_dev *dev)
{
ulong now = jiffies, secs;
int status = 0;
+ struct ocrdma_rdma_stats_resp *rdma_stats =
+ (struct ocrdma_rdma_stats_resp *)dev->stats_mem.va;
+ struct ocrdma_rsrc_stats *rsrc_stats = &rdma_stats->act_rsrc_stats;
secs = jiffies_to_msecs(now - dev->last_stats_time) / 1000U;
if (secs) {
@@ -444,10 +605,74 @@ static void ocrdma_update_stats(struct ocrdma_dev *dev)
if (status)
pr_err("%s: stats mbox failed with status = %d\n",
__func__, status);
+ /* Update PD counters from PD resource manager */
+ if (dev->pd_mgr->pd_prealloc_valid) {
+ rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_count;
+ rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_count;
+ /* Threshold stata*/
+ rsrc_stats = &rdma_stats->th_rsrc_stats;
+ rsrc_stats->dpp_pds = dev->pd_mgr->pd_dpp_thrsh;
+ rsrc_stats->non_dpp_pds = dev->pd_mgr->pd_norm_thrsh;
+ }
dev->last_stats_time = jiffies;
}
}
+static ssize_t ocrdma_dbgfs_ops_write(struct file *filp,
+ const char __user *buffer,
+ size_t count, loff_t *ppos)
+{
+ char tmp_str[32];
+ long reset;
+ int status = 0;
+ struct ocrdma_stats *pstats = filp->private_data;
+ struct ocrdma_dev *dev = pstats->dev;
+
+ if (count > 32)
+ goto err;
+
+ if (copy_from_user(tmp_str, buffer, count))
+ goto err;
+
+ tmp_str[count-1] = '\0';
+ if (kstrtol(tmp_str, 10, &reset))
+ goto err;
+
+ switch (pstats->type) {
+ case OCRDMA_RESET_STATS:
+ if (reset) {
+ status = ocrdma_mbx_rdma_stats(dev, true);
+ if (status) {
+ pr_err("Failed to reset stats = %d", status);
+ goto err;
+ }
+ }
+ break;
+ default:
+ goto err;
+ }
+
+ return count;
+err:
+ return -EFAULT;
+}
+
+int ocrdma_pma_counters(struct ocrdma_dev *dev,
+ struct ib_mad *out_mad)
+{
+ struct ib_pma_portcounters *pma_cnt;
+
+ memset(out_mad->data, 0, sizeof out_mad->data);
+ pma_cnt = (void *)(out_mad->data + 40);
+ ocrdma_update_stats(dev);
+
+ pma_cnt->port_xmit_data = cpu_to_be32(ocrdma_sysfs_xmit_data(dev));
+ pma_cnt->port_rcv_data = cpu_to_be32(ocrdma_sysfs_rcv_data(dev));
+ pma_cnt->port_xmit_packets = cpu_to_be32(ocrdma_sysfs_xmit_pkts(dev));
+ pma_cnt->port_rcv_packets = cpu_to_be32(ocrdma_sysfs_rcv_pkts(dev));
+ return 0;
+}
+
static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
size_t usr_buf_len, loff_t *ppos)
{
@@ -492,6 +717,9 @@ static ssize_t ocrdma_dbgfs_ops_read(struct file *filp, char __user *buffer,
case OCRDMA_RX_DBG_STATS:
data = ocrdma_rx_dbg_stats(dev);
break;
+ case OCRDMA_DRV_STATS:
+ data = ocrdma_driver_dbg_stats(dev);
+ break;
default:
status = -EFAULT;
@@ -514,6 +742,7 @@ static const struct file_operations ocrdma_dbg_ops = {
.owner = THIS_MODULE,
.open = simple_open,
.read = ocrdma_dbgfs_ops_read,
+ .write = ocrdma_dbgfs_ops_write,
};
void ocrdma_add_port_stats(struct ocrdma_dev *dev)
@@ -582,6 +811,18 @@ void ocrdma_add_port_stats(struct ocrdma_dev *dev)
&dev->rx_dbg_stats, &ocrdma_dbg_ops))
goto err;
+ dev->driver_stats.type = OCRDMA_DRV_STATS;
+ dev->driver_stats.dev = dev;
+ if (!debugfs_create_file("driver_dbg_stats", S_IRUSR, dev->dir,
+ &dev->driver_stats, &ocrdma_dbg_ops))
+ goto err;
+
+ dev->reset_stats.type = OCRDMA_RESET_STATS;
+ dev->reset_stats.dev = dev;
+ if (!debugfs_create_file("reset_stats", S_IRUSR, dev->dir,
+ &dev->reset_stats, &ocrdma_dbg_ops))
+ goto err;
+
/* Now create dma_mem for stats mbx command */
if (!ocrdma_alloc_stats_mem(dev))
goto err;
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
index 5f5e20c46d7c..091edd68a8a3 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_stats.h
@@ -43,12 +43,16 @@ enum OCRDMA_STATS_TYPE {
OCRDMA_RXQP_ERRSTATS,
OCRDMA_TXQP_ERRSTATS,
OCRDMA_TX_DBG_STATS,
- OCRDMA_RX_DBG_STATS
+ OCRDMA_RX_DBG_STATS,
+ OCRDMA_DRV_STATS,
+ OCRDMA_RESET_STATS
};
void ocrdma_rem_debugfs(void);
void ocrdma_init_debugfs(void);
void ocrdma_rem_port_stats(struct ocrdma_dev *dev);
void ocrdma_add_port_stats(struct ocrdma_dev *dev);
+int ocrdma_pma_counters(struct ocrdma_dev *dev,
+ struct ib_mad *out_mad);
#endif /* __OCRDMA_STATS_H__ */
diff --git a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
index fb8d8c4dfbb9..877175563634 100644
--- a/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
+++ b/drivers/infiniband/hw/ocrdma/ocrdma_verbs.c
@@ -53,7 +53,7 @@ int ocrdma_query_gid(struct ib_device *ibdev, u8 port,
dev = get_ocrdma_dev(ibdev);
memset(sgid, 0, sizeof(*sgid));
- if (index > OCRDMA_MAX_SGID)
+ if (index >= OCRDMA_MAX_SGID)
return -EINVAL;
memcpy(sgid, &dev->sgid_tbl[index], sizeof(*sgid));
@@ -253,6 +253,107 @@ static bool ocrdma_search_mmap(struct ocrdma_ucontext *uctx, u64 phy_addr,
return found;
}
+
+static u16 _ocrdma_pd_mgr_get_bitmap(struct ocrdma_dev *dev, bool dpp_pool)
+{
+ u16 pd_bitmap_idx = 0;
+ const unsigned long *pd_bitmap;
+
+ if (dpp_pool) {
+ pd_bitmap = dev->pd_mgr->pd_dpp_bitmap;
+ pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
+ dev->pd_mgr->max_dpp_pd);
+ __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_dpp_bitmap);
+ dev->pd_mgr->pd_dpp_count++;
+ if (dev->pd_mgr->pd_dpp_count > dev->pd_mgr->pd_dpp_thrsh)
+ dev->pd_mgr->pd_dpp_thrsh = dev->pd_mgr->pd_dpp_count;
+ } else {
+ pd_bitmap = dev->pd_mgr->pd_norm_bitmap;
+ pd_bitmap_idx = find_first_zero_bit(pd_bitmap,
+ dev->pd_mgr->max_normal_pd);
+ __set_bit(pd_bitmap_idx, dev->pd_mgr->pd_norm_bitmap);
+ dev->pd_mgr->pd_norm_count++;
+ if (dev->pd_mgr->pd_norm_count > dev->pd_mgr->pd_norm_thrsh)
+ dev->pd_mgr->pd_norm_thrsh = dev->pd_mgr->pd_norm_count;
+ }
+ return pd_bitmap_idx;
+}
+
+static int _ocrdma_pd_mgr_put_bitmap(struct ocrdma_dev *dev, u16 pd_id,
+ bool dpp_pool)
+{
+ u16 pd_count;
+ u16 pd_bit_index;
+
+ pd_count = dpp_pool ? dev->pd_mgr->pd_dpp_count :
+ dev->pd_mgr->pd_norm_count;
+ if (pd_count == 0)
+ return -EINVAL;
+
+ if (dpp_pool) {
+ pd_bit_index = pd_id - dev->pd_mgr->pd_dpp_start;
+ if (pd_bit_index >= dev->pd_mgr->max_dpp_pd) {
+ return -EINVAL;
+ } else {
+ __clear_bit(pd_bit_index, dev->pd_mgr->pd_dpp_bitmap);
+ dev->pd_mgr->pd_dpp_count--;
+ }
+ } else {
+ pd_bit_index = pd_id - dev->pd_mgr->pd_norm_start;
+ if (pd_bit_index >= dev->pd_mgr->max_normal_pd) {
+ return -EINVAL;
+ } else {
+ __clear_bit(pd_bit_index, dev->pd_mgr->pd_norm_bitmap);
+ dev->pd_mgr->pd_norm_count--;
+ }
+ }
+
+ return 0;
+}
+
+static u8 ocrdma_put_pd_num(struct ocrdma_dev *dev, u16 pd_id,
+ bool dpp_pool)
+{
+ int status;
+
+ mutex_lock(&dev->dev_lock);
+ status = _ocrdma_pd_mgr_put_bitmap(dev, pd_id, dpp_pool);
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
+static int ocrdma_get_pd_num(struct ocrdma_dev *dev, struct ocrdma_pd *pd)
+{
+ u16 pd_idx = 0;
+ int status = 0;
+
+ mutex_lock(&dev->dev_lock);
+ if (pd->dpp_enabled) {
+ /* try allocating DPP PD, if not available then normal PD */
+ if (dev->pd_mgr->pd_dpp_count < dev->pd_mgr->max_dpp_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, true);
+ pd->id = dev->pd_mgr->pd_dpp_start + pd_idx;
+ pd->dpp_page = dev->pd_mgr->dpp_page_index + pd_idx;
+ } else if (dev->pd_mgr->pd_norm_count <
+ dev->pd_mgr->max_normal_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
+ pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
+ pd->dpp_enabled = false;
+ } else {
+ status = -EINVAL;
+ }
+ } else {
+ if (dev->pd_mgr->pd_norm_count < dev->pd_mgr->max_normal_pd) {
+ pd_idx = _ocrdma_pd_mgr_get_bitmap(dev, false);
+ pd->id = dev->pd_mgr->pd_norm_start + pd_idx;
+ } else {
+ status = -EINVAL;
+ }
+ }
+ mutex_unlock(&dev->dev_lock);
+ return status;
+}
+
static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
struct ocrdma_ucontext *uctx,
struct ib_udata *udata)
@@ -272,6 +373,11 @@ static struct ocrdma_pd *_ocrdma_alloc_pd(struct ocrdma_dev *dev,
dev->attr.wqe_size) : 0;
}
+ if (dev->pd_mgr->pd_prealloc_valid) {
+ status = ocrdma_get_pd_num(dev, pd);
+ return (status == 0) ? pd : ERR_PTR(status);
+ }
+
retry:
status = ocrdma_mbx_alloc_pd(dev, pd);
if (status) {
@@ -299,7 +405,11 @@ static int _ocrdma_dealloc_pd(struct ocrdma_dev *dev,
{
int status = 0;
- status = ocrdma_mbx_dealloc_pd(dev, pd);
+ if (dev->pd_mgr->pd_prealloc_valid)
+ status = ocrdma_put_pd_num(dev, pd->id, pd->dpp_enabled);
+ else
+ status = ocrdma_mbx_dealloc_pd(dev, pd);
+
kfree(pd);
return status;
}
@@ -325,7 +435,6 @@ err:
static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
{
- int status = 0;
struct ocrdma_pd *pd = uctx->cntxt_pd;
struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
@@ -334,8 +443,8 @@ static int ocrdma_dealloc_ucontext_pd(struct ocrdma_ucontext *uctx)
__func__, dev->id, pd->id);
}
uctx->cntxt_pd = NULL;
- status = _ocrdma_dealloc_pd(dev, pd);
- return status;
+ (void)_ocrdma_dealloc_pd(dev, pd);
+ return 0;
}
static struct ocrdma_pd *ocrdma_get_ucontext_pd(struct ocrdma_ucontext *uctx)
@@ -569,7 +678,7 @@ err:
if (is_uctx_pd) {
ocrdma_release_ucontext_pd(uctx);
} else {
- status = ocrdma_mbx_dealloc_pd(dev, pd);
+ status = _ocrdma_dealloc_pd(dev, pd);
kfree(pd);
}
exit:
@@ -837,9 +946,8 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
{
struct ocrdma_mr *mr = get_ocrdma_mr(ib_mr);
struct ocrdma_dev *dev = get_ocrdma_dev(ib_mr->device);
- int status;
- status = ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
+ (void) ocrdma_mbx_dealloc_lkey(dev, mr->hwmr.fr_mr, mr->hwmr.lkey);
ocrdma_free_mr_pbl_tbl(dev, &mr->hwmr);
@@ -850,11 +958,10 @@ int ocrdma_dereg_mr(struct ib_mr *ib_mr)
/* Don't stop cleanup, in case FW is unresponsive */
if (dev->mqe_ctx.fw_error_state) {
- status = 0;
pr_err("%s(%d) fw not responding.\n",
__func__, dev->id);
}
- return status;
+ return 0;
}
static int ocrdma_copy_cq_uresp(struct ocrdma_dev *dev, struct ocrdma_cq *cq,
@@ -986,7 +1093,6 @@ static void ocrdma_flush_cq(struct ocrdma_cq *cq)
int ocrdma_destroy_cq(struct ib_cq *ibcq)
{
- int status;
struct ocrdma_cq *cq = get_ocrdma_cq(ibcq);
struct ocrdma_eq *eq = NULL;
struct ocrdma_dev *dev = get_ocrdma_dev(ibcq->device);
@@ -1003,7 +1109,7 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
synchronize_irq(irq);
ocrdma_flush_cq(cq);
- status = ocrdma_mbx_destroy_cq(dev, cq);
+ (void)ocrdma_mbx_destroy_cq(dev, cq);
if (cq->ucontext) {
pdid = cq->ucontext->cntxt_pd->id;
ocrdma_del_mmap(cq->ucontext, (u64) cq->pa,
@@ -1014,7 +1120,7 @@ int ocrdma_destroy_cq(struct ib_cq *ibcq)
}
kfree(cq);
- return status;
+ return 0;
}
static int ocrdma_add_qpn_map(struct ocrdma_dev *dev, struct ocrdma_qp *qp)
@@ -1113,8 +1219,8 @@ static int ocrdma_copy_qp_uresp(struct ocrdma_qp *qp,
int status = 0;
u64 usr_db;
struct ocrdma_create_qp_uresp uresp;
- struct ocrdma_dev *dev = qp->dev;
struct ocrdma_pd *pd = qp->pd;
+ struct ocrdma_dev *dev = get_ocrdma_dev(pd->ibpd.device);
memset(&uresp, 0, sizeof(uresp));
usr_db = dev->nic_info.unmapped_db +
@@ -1253,7 +1359,6 @@ struct ib_qp *ocrdma_create_qp(struct ib_pd *ibpd,
status = -ENOMEM;
goto gen_err;
}
- qp->dev = dev;
ocrdma_set_qp_init_params(qp, pd, attrs);
if (udata == NULL)
qp->cap_flags |= (OCRDMA_QP_MW_BIND | OCRDMA_QP_LKEY0 |
@@ -1312,7 +1417,7 @@ int _ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
enum ib_qp_state old_qps;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
if (attr_mask & IB_QP_STATE)
status = ocrdma_qp_state_change(qp, attr->qp_state, &old_qps);
/* if new and previous states are same hw doesn't need to
@@ -1335,7 +1440,7 @@ int ocrdma_modify_qp(struct ib_qp *ibqp, struct ib_qp_attr *attr,
enum ib_qp_state old_qps, new_qps;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
/* syncronize with multiple context trying to change, retrive qps */
mutex_lock(&dev->dev_lock);
@@ -1402,7 +1507,7 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
u32 qp_state;
struct ocrdma_qp_params params;
struct ocrdma_qp *qp = get_ocrdma_qp(ibqp);
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_dev *dev = get_ocrdma_dev(ibqp->device);
memset(&params, 0, sizeof(params));
mutex_lock(&dev->dev_lock);
@@ -1412,8 +1517,6 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
goto mbx_err;
if (qp->qp_type == IB_QPT_UD)
qp_attr->qkey = params.qkey;
- qp_attr->qp_state = get_ibqp_state(IB_QPS_INIT);
- qp_attr->cur_qp_state = get_ibqp_state(IB_QPS_INIT);
qp_attr->path_mtu =
ocrdma_mtu_int_to_enum(params.path_mtu_pkey_indx &
OCRDMA_QP_PARAMS_PATH_MTU_MASK) >>
@@ -1468,6 +1571,8 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
memset(&qp_attr->alt_ah_attr, 0, sizeof(qp_attr->alt_ah_attr));
qp_state = (params.max_sge_recv_flags & OCRDMA_QP_PARAMS_STATE_MASK) >>
OCRDMA_QP_PARAMS_STATE_SHIFT;
+ qp_attr->qp_state = get_ibqp_state(qp_state);
+ qp_attr->cur_qp_state = qp_attr->qp_state;
qp_attr->sq_draining = (qp_state == OCRDMA_QPS_SQ_DRAINING) ? 1 : 0;
qp_attr->max_dest_rd_atomic =
params.max_ord_ird >> OCRDMA_QP_PARAMS_MAX_ORD_SHIFT;
@@ -1475,19 +1580,18 @@ int ocrdma_query_qp(struct ib_qp *ibqp,
params.max_ord_ird & OCRDMA_QP_PARAMS_MAX_IRD_MASK;
qp_attr->en_sqd_async_notify = (params.max_sge_recv_flags &
OCRDMA_QP_PARAMS_FLAGS_SQD_ASYNC) ? 1 : 0;
+ /* Sync driver QP state with FW */
+ ocrdma_qp_state_change(qp, qp_attr->qp_state, NULL);
mbx_err:
return status;
}
-static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, int idx)
+static void ocrdma_srq_toggle_bit(struct ocrdma_srq *srq, unsigned int idx)
{
- int i = idx / 32;
- unsigned int mask = (1 << (idx % 32));
+ unsigned int i = idx / 32;
+ u32 mask = (1U << (idx % 32));
- if (srq->idx_bit_fields[i] & mask)
- srq->idx_bit_fields[i] &= ~mask;
- else
- srq->idx_bit_fields[i] |= mask;
+ srq->idx_bit_fields[i] ^= mask;
}
static int ocrdma_hwq_free_cnt(struct ocrdma_qp_hwq_info *q)
@@ -1596,7 +1700,7 @@ void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
{
int found = false;
unsigned long flags;
- struct ocrdma_dev *dev = qp->dev;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
/* sync with any active CQ poll */
spin_lock_irqsave(&dev->flush_q_lock, flags);
@@ -1613,7 +1717,6 @@ void ocrdma_del_flush_qp(struct ocrdma_qp *qp)
int ocrdma_destroy_qp(struct ib_qp *ibqp)
{
- int status;
struct ocrdma_pd *pd;
struct ocrdma_qp *qp;
struct ocrdma_dev *dev;
@@ -1622,7 +1725,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
unsigned long flags;
qp = get_ocrdma_qp(ibqp);
- dev = qp->dev;
+ dev = get_ocrdma_dev(ibqp->device);
attrs.qp_state = IB_QPS_ERR;
pd = qp->pd;
@@ -1635,7 +1738,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
* discarded until the old CQEs are discarded.
*/
mutex_lock(&dev->dev_lock);
- status = ocrdma_mbx_destroy_qp(dev, qp);
+ (void) ocrdma_mbx_destroy_qp(dev, qp);
/*
* acquire CQ lock while destroy is in progress, in order to
@@ -1670,7 +1773,7 @@ int ocrdma_destroy_qp(struct ib_qp *ibqp)
kfree(qp->wqe_wr_id_tbl);
kfree(qp->rqe_wr_id_tbl);
kfree(qp);
- return status;
+ return 0;
}
static int ocrdma_copy_srq_uresp(struct ocrdma_dev *dev, struct ocrdma_srq *srq,
@@ -1831,6 +1934,8 @@ static void ocrdma_build_ud_hdr(struct ocrdma_qp *qp,
else
ud_hdr->qkey = wr->wr.ud.remote_qkey;
ud_hdr->rsvd_ahid = ah->id;
+ if (ah->av->valid & OCRDMA_AV_VLAN_VALID)
+ hdr->cw |= (OCRDMA_FLAG_AH_VLAN_PR << OCRDMA_WQE_FLAGS_SHIFT);
}
static void ocrdma_build_sges(struct ocrdma_hdr_wqe *hdr,
@@ -2007,11 +2112,12 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
u64 fbo;
struct ocrdma_ewqe_fr *fast_reg = (struct ocrdma_ewqe_fr *)(hdr + 1);
struct ocrdma_mr *mr;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
u32 wqe_size = sizeof(*fast_reg) + sizeof(*hdr);
wqe_size = roundup(wqe_size, OCRDMA_WQE_ALIGN_BYTES);
- if (wr->wr.fast_reg.page_list_len > qp->dev->attr.max_pages_per_frmr)
+ if (wr->wr.fast_reg.page_list_len > dev->attr.max_pages_per_frmr)
return -EINVAL;
hdr->cw |= (OCRDMA_FR_MR << OCRDMA_WQE_OPCODE_SHIFT);
@@ -2039,7 +2145,7 @@ static int ocrdma_build_fr(struct ocrdma_qp *qp, struct ocrdma_hdr_wqe *hdr,
fast_reg->size_sge =
get_encoded_page_size(1 << wr->wr.fast_reg.page_shift);
mr = (struct ocrdma_mr *) (unsigned long)
- qp->dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
+ dev->stag_arr[(hdr->lkey >> 8) & (OCRDMA_MAX_STAG - 1)];
build_frmr_pbes(wr, mr->hwmr.pbl_table, &mr->hwmr);
return 0;
}
@@ -2112,8 +2218,6 @@ int ocrdma_post_send(struct ib_qp *ibqp, struct ib_send_wr *wr,
hdr->cw |= (OCRDMA_WRITE << OCRDMA_WQE_OPCODE_SHIFT);
status = ocrdma_build_write(qp, hdr, wr);
break;
- case IB_WR_RDMA_READ_WITH_INV:
- hdr->cw |= (OCRDMA_FLAG_INV << OCRDMA_WQE_FLAGS_SHIFT);
case IB_WR_RDMA_READ:
ocrdma_build_read(qp, hdr, wr);
break;
@@ -2484,8 +2588,11 @@ static bool ocrdma_poll_err_scqe(struct ocrdma_qp *qp,
bool *polled, bool *stop)
{
bool expand;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
int status = (le32_to_cpu(cqe->flags_status_srcqpn) &
OCRDMA_CQE_STATUS_MASK) >> OCRDMA_CQE_STATUS_SHIFT;
+ if (status < OCRDMA_MAX_CQE_ERR)
+ atomic_inc(&dev->cqe_err_stats[status]);
/* when hw sq is empty, but rq is not empty, so we continue
* to keep the cqe in order to get the cq event again.
@@ -2604,6 +2711,10 @@ static bool ocrdma_poll_err_rcqe(struct ocrdma_qp *qp, struct ocrdma_cqe *cqe,
int status)
{
bool expand;
+ struct ocrdma_dev *dev = get_ocrdma_dev(qp->ibqp.device);
+
+ if (status < OCRDMA_MAX_CQE_ERR)
+ atomic_inc(&dev->cqe_err_stats[status]);
/* when hw_rq is empty, but wq is not empty, so continue
* to keep the cqe to get the cq event again.
diff --git a/drivers/infiniband/hw/qib/qib.h b/drivers/infiniband/hw/qib/qib.h
index c00ae093b6f8..ffd48bfc4923 100644
--- a/drivers/infiniband/hw/qib/qib.h
+++ b/drivers/infiniband/hw/qib/qib.h
@@ -1082,12 +1082,6 @@ struct qib_devdata {
/* control high-level access to EEPROM */
struct mutex eep_lock;
uint64_t traffic_wds;
- /* active time is kept in seconds, but logged in hours */
- atomic_t active_time;
- /* Below are nominal shadow of EEPROM, new since last EEPROM update */
- uint8_t eep_st_errs[QIB_EEP_LOG_CNT];
- uint8_t eep_st_new_errs[QIB_EEP_LOG_CNT];
- uint16_t eep_hrs;
/*
* masks for which bits of errs, hwerrs that cause
* each of the counters to increment.
@@ -1309,8 +1303,7 @@ int qib_twsi_blk_rd(struct qib_devdata *dd, int dev, int addr, void *buffer,
int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr,
const void *buffer, int len);
void qib_get_eeprom_info(struct qib_devdata *);
-int qib_update_eeprom_log(struct qib_devdata *dd);
-void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr);
+#define qib_inc_eeprom_err(dd, eidx, incr)
void qib_dump_lookup_output_queue(struct qib_devdata *);
void qib_force_pio_avail_update(struct qib_devdata *);
void qib_clear_symerror_on_linkup(unsigned long opaque);
@@ -1467,11 +1460,14 @@ const char *qib_get_unit_name(int unit);
* Flush write combining store buffers (if present) and perform a write
* barrier.
*/
+static inline void qib_flush_wc(void)
+{
#if defined(CONFIG_X86_64)
-#define qib_flush_wc() asm volatile("sfence" : : : "memory")
+ asm volatile("sfence" : : : "memory");
#else
-#define qib_flush_wc() wmb() /* no reorder around wc flush */
+ wmb(); /* no reorder around wc flush */
#endif
+}
/* global module parameter variables */
extern unsigned qib_ibmtu;
diff --git a/drivers/infiniband/hw/qib/qib_common.h b/drivers/infiniband/hw/qib/qib_common.h
index 5670ace27c63..4fb78abd8ba1 100644
--- a/drivers/infiniband/hw/qib/qib_common.h
+++ b/drivers/infiniband/hw/qib/qib_common.h
@@ -257,7 +257,7 @@ struct qib_base_info {
/* shared memory page for send buffer disarm status */
__u64 spi_sendbuf_status;
-} __attribute__ ((aligned(8)));
+} __aligned(8);
/*
* This version number is given to the driver by the user code during
@@ -361,7 +361,7 @@ struct qib_user_info {
*/
__u64 spu_base_info;
-} __attribute__ ((aligned(8)));
+} __aligned(8);
/* User commands. */
diff --git a/drivers/infiniband/hw/qib/qib_debugfs.c b/drivers/infiniband/hw/qib/qib_debugfs.c
index 6abd3ed3cd51..5e75b43c596b 100644
--- a/drivers/infiniband/hw/qib/qib_debugfs.c
+++ b/drivers/infiniband/hw/qib/qib_debugfs.c
@@ -255,7 +255,6 @@ void qib_dbg_ibdev_init(struct qib_ibdev *ibd)
DEBUGFS_FILE_CREATE(opcode_stats);
DEBUGFS_FILE_CREATE(ctx_stats);
DEBUGFS_FILE_CREATE(qp_stats);
- return;
}
void qib_dbg_ibdev_exit(struct qib_ibdev *ibd)
diff --git a/drivers/infiniband/hw/qib/qib_diag.c b/drivers/infiniband/hw/qib/qib_diag.c
index 5dfda4c5cc9c..8c34b23e5bf6 100644
--- a/drivers/infiniband/hw/qib/qib_diag.c
+++ b/drivers/infiniband/hw/qib/qib_diag.c
@@ -85,7 +85,7 @@ static struct qib_diag_client *get_client(struct qib_devdata *dd)
client_pool = dc->next;
else
/* None in pool, alloc and init */
- dc = kmalloc(sizeof *dc, GFP_KERNEL);
+ dc = kmalloc(sizeof(*dc), GFP_KERNEL);
if (dc) {
dc->next = NULL;
@@ -257,6 +257,7 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
if (dd->userbase) {
/* If user regs mapped, they are after send, so set limit. */
u32 ulim = (dd->cfgctxts * dd->ureg_align) + dd->uregbase;
+
if (!dd->piovl15base)
snd_lim = dd->uregbase;
krb32 = (u32 __iomem *)dd->userbase;
@@ -280,6 +281,7 @@ static u32 __iomem *qib_remap_ioaddr32(struct qib_devdata *dd, u32 offset,
snd_bottom = dd->pio2k_bufbase;
if (snd_lim == 0) {
u32 tot2k = dd->piobcnt2k * ALIGN(dd->piosize2k, dd->palign);
+
snd_lim = snd_bottom + tot2k;
}
/* If 4k buffers exist, account for them by bumping
@@ -398,6 +400,7 @@ static int qib_write_umem64(struct qib_devdata *dd, u32 regoffs,
/* not very efficient, but it works for now */
while (reg_addr < reg_end) {
u64 data;
+
if (copy_from_user(&data, uaddr, sizeof(data))) {
ret = -EFAULT;
goto bail;
@@ -698,7 +701,7 @@ int qib_register_observer(struct qib_devdata *dd,
if (!dd || !op)
return -EINVAL;
- olp = vmalloc(sizeof *olp);
+ olp = vmalloc(sizeof(*olp));
if (!olp) {
pr_err("vmalloc for observer failed\n");
return -ENOMEM;
@@ -796,6 +799,7 @@ static ssize_t qib_diag_read(struct file *fp, char __user *data,
op = diag_get_observer(dd, *off);
if (op) {
u32 offset = *off;
+
ret = op->hook(dd, op, offset, &data64, 0, use_32);
}
/*
@@ -873,6 +877,7 @@ static ssize_t qib_diag_write(struct file *fp, const char __user *data,
if (count == 4 || count == 8) {
u64 data64;
u32 offset = *off;
+
ret = copy_from_user(&data64, data, count);
if (ret) {
ret = -EFAULT;
diff --git a/drivers/infiniband/hw/qib/qib_driver.c b/drivers/infiniband/hw/qib/qib_driver.c
index 5bee08f16d74..f58fdc3d25a2 100644
--- a/drivers/infiniband/hw/qib/qib_driver.c
+++ b/drivers/infiniband/hw/qib/qib_driver.c
@@ -86,7 +86,7 @@ const char *qib_get_unit_name(int unit)
{
static char iname[16];
- snprintf(iname, sizeof iname, "infinipath%u", unit);
+ snprintf(iname, sizeof(iname), "infinipath%u", unit);
return iname;
}
@@ -349,6 +349,7 @@ static u32 qib_rcv_hdrerr(struct qib_ctxtdata *rcd, struct qib_pportdata *ppd,
qp_num = be32_to_cpu(ohdr->bth[1]) & QIB_QPN_MASK;
if (qp_num != QIB_MULTICAST_QPN) {
int ruc_res;
+
qp = qib_lookup_qpn(ibp, qp_num);
if (!qp)
goto drop;
@@ -461,6 +462,7 @@ u32 qib_kreceive(struct qib_ctxtdata *rcd, u32 *llic, u32 *npkts)
rhf_addr = (__le32 *) rcd->rcvhdrq + l + dd->rhf_offset;
if (dd->flags & QIB_NODMA_RTAIL) {
u32 seq = qib_hdrget_seq(rhf_addr);
+
if (seq != rcd->seq_cnt)
goto bail;
hdrqtail = 0;
@@ -651,6 +653,7 @@ bail:
int qib_set_lid(struct qib_pportdata *ppd, u32 lid, u8 lmc)
{
struct qib_devdata *dd = ppd->dd;
+
ppd->lid = lid;
ppd->lmc = lmc;
diff --git a/drivers/infiniband/hw/qib/qib_eeprom.c b/drivers/infiniband/hw/qib/qib_eeprom.c
index 4d5d71aaa2b4..311ee6c3dd5e 100644
--- a/drivers/infiniband/hw/qib/qib_eeprom.c
+++ b/drivers/infiniband/hw/qib/qib_eeprom.c
@@ -153,6 +153,7 @@ void qib_get_eeprom_info(struct qib_devdata *dd)
if (t && dd0->nguid > 1 && t <= dd0->nguid) {
u8 oguid;
+
dd->base_guid = dd0->base_guid;
bguid = (u8 *) &dd->base_guid;
@@ -251,206 +252,25 @@ void qib_get_eeprom_info(struct qib_devdata *dd)
* This board has a Serial-prefix, which is stored
* elsewhere for backward-compatibility.
*/
- memcpy(snp, ifp->if_sprefix, sizeof ifp->if_sprefix);
- snp[sizeof ifp->if_sprefix] = '\0';
+ memcpy(snp, ifp->if_sprefix, sizeof(ifp->if_sprefix));
+ snp[sizeof(ifp->if_sprefix)] = '\0';
len = strlen(snp);
snp += len;
- len = (sizeof dd->serial) - len;
- if (len > sizeof ifp->if_serial)
- len = sizeof ifp->if_serial;
+ len = sizeof(dd->serial) - len;
+ if (len > sizeof(ifp->if_serial))
+ len = sizeof(ifp->if_serial);
memcpy(snp, ifp->if_serial, len);
- } else
- memcpy(dd->serial, ifp->if_serial,
- sizeof ifp->if_serial);
+ } else {
+ memcpy(dd->serial, ifp->if_serial, sizeof(ifp->if_serial));
+ }
if (!strstr(ifp->if_comment, "Tested successfully"))
qib_dev_err(dd,
"Board SN %s did not pass functional test: %s\n",
dd->serial, ifp->if_comment);
- memcpy(&dd->eep_st_errs, &ifp->if_errcntp, QIB_EEP_LOG_CNT);
- /*
- * Power-on (actually "active") hours are kept as little-endian value
- * in EEPROM, but as seconds in a (possibly as small as 24-bit)
- * atomic_t while running.
- */
- atomic_set(&dd->active_time, 0);
- dd->eep_hrs = ifp->if_powerhour[0] | (ifp->if_powerhour[1] << 8);
-
done:
vfree(buf);
bail:;
}
-/**
- * qib_update_eeprom_log - copy active-time and error counters to eeprom
- * @dd: the qlogic_ib device
- *
- * Although the time is kept as seconds in the qib_devdata struct, it is
- * rounded to hours for re-write, as we have only 16 bits in EEPROM.
- * First-cut code reads whole (expected) struct qib_flash, modifies,
- * re-writes. Future direction: read/write only what we need, assuming
- * that the EEPROM had to have been "good enough" for driver init, and
- * if not, we aren't making it worse.
- *
- */
-int qib_update_eeprom_log(struct qib_devdata *dd)
-{
- void *buf;
- struct qib_flash *ifp;
- int len, hi_water;
- uint32_t new_time, new_hrs;
- u8 csum;
- int ret, idx;
- unsigned long flags;
-
- /* first, check if we actually need to do anything. */
- ret = 0;
- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
- if (dd->eep_st_new_errs[idx]) {
- ret = 1;
- break;
- }
- }
- new_time = atomic_read(&dd->active_time);
-
- if (ret == 0 && new_time < 3600)
- goto bail;
-
- /*
- * The quick-check above determined that there is something worthy
- * of logging, so get current contents and do a more detailed idea.
- * read full flash, not just currently used part, since it may have
- * been written with a newer definition
- */
- len = sizeof(struct qib_flash);
- buf = vmalloc(len);
- ret = 1;
- if (!buf) {
- qib_dev_err(dd,
- "Couldn't allocate memory to read %u bytes from eeprom for logging\n",
- len);
- goto bail;
- }
-
- /* Grab semaphore and read current EEPROM. If we get an
- * error, let go, but if not, keep it until we finish write.
- */
- ret = mutex_lock_interruptible(&dd->eep_lock);
- if (ret) {
- qib_dev_err(dd, "Unable to acquire EEPROM for logging\n");
- goto free_bail;
- }
- ret = qib_twsi_blk_rd(dd, dd->twsi_eeprom_dev, 0, buf, len);
- if (ret) {
- mutex_unlock(&dd->eep_lock);
- qib_dev_err(dd, "Unable read EEPROM for logging\n");
- goto free_bail;
- }
- ifp = (struct qib_flash *)buf;
-
- csum = flash_csum(ifp, 0);
- if (csum != ifp->if_csum) {
- mutex_unlock(&dd->eep_lock);
- qib_dev_err(dd, "EEPROM cks err (0x%02X, S/B 0x%02X)\n",
- csum, ifp->if_csum);
- ret = 1;
- goto free_bail;
- }
- hi_water = 0;
- spin_lock_irqsave(&dd->eep_st_lock, flags);
- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
- int new_val = dd->eep_st_new_errs[idx];
- if (new_val) {
- /*
- * If we have seen any errors, add to EEPROM values
- * We need to saturate at 0xFF (255) and we also
- * would need to adjust the checksum if we were
- * trying to minimize EEPROM traffic
- * Note that we add to actual current count in EEPROM,
- * in case it was altered while we were running.
- */
- new_val += ifp->if_errcntp[idx];
- if (new_val > 0xFF)
- new_val = 0xFF;
- if (ifp->if_errcntp[idx] != new_val) {
- ifp->if_errcntp[idx] = new_val;
- hi_water = offsetof(struct qib_flash,
- if_errcntp) + idx;
- }
- /*
- * update our shadow (used to minimize EEPROM
- * traffic), to match what we are about to write.
- */
- dd->eep_st_errs[idx] = new_val;
- dd->eep_st_new_errs[idx] = 0;
- }
- }
- /*
- * Now update active-time. We would like to round to the nearest hour
- * but unless atomic_t are sure to be proper signed ints we cannot,
- * because we need to account for what we "transfer" to EEPROM and
- * if we log an hour at 31 minutes, then we would need to set
- * active_time to -29 to accurately count the _next_ hour.
- */
- if (new_time >= 3600) {
- new_hrs = new_time / 3600;
- atomic_sub((new_hrs * 3600), &dd->active_time);
- new_hrs += dd->eep_hrs;
- if (new_hrs > 0xFFFF)
- new_hrs = 0xFFFF;
- dd->eep_hrs = new_hrs;
- if ((new_hrs & 0xFF) != ifp->if_powerhour[0]) {
- ifp->if_powerhour[0] = new_hrs & 0xFF;
- hi_water = offsetof(struct qib_flash, if_powerhour);
- }
- if ((new_hrs >> 8) != ifp->if_powerhour[1]) {
- ifp->if_powerhour[1] = new_hrs >> 8;
- hi_water = offsetof(struct qib_flash, if_powerhour) + 1;
- }
- }
- /*
- * There is a tiny possibility that we could somehow fail to write
- * the EEPROM after updating our shadows, but problems from holding
- * the spinlock too long are a much bigger issue.
- */
- spin_unlock_irqrestore(&dd->eep_st_lock, flags);
- if (hi_water) {
- /* we made some change to the data, uopdate cksum and write */
- csum = flash_csum(ifp, 1);
- ret = eeprom_write_with_enable(dd, 0, buf, hi_water + 1);
- }
- mutex_unlock(&dd->eep_lock);
- if (ret)
- qib_dev_err(dd, "Failed updating EEPROM\n");
-
-free_bail:
- vfree(buf);
-bail:
- return ret;
-}
-
-/**
- * qib_inc_eeprom_err - increment one of the four error counters
- * that are logged to EEPROM.
- * @dd: the qlogic_ib device
- * @eidx: 0..3, the counter to increment
- * @incr: how much to add
- *
- * Each counter is 8-bits, and saturates at 255 (0xFF). They
- * are copied to the EEPROM (aka flash) whenever qib_update_eeprom_log()
- * is called, but it can only be called in a context that allows sleep.
- * This function can be called even at interrupt level.
- */
-void qib_inc_eeprom_err(struct qib_devdata *dd, u32 eidx, u32 incr)
-{
- uint new_val;
- unsigned long flags;
-
- spin_lock_irqsave(&dd->eep_st_lock, flags);
- new_val = dd->eep_st_new_errs[eidx] + incr;
- if (new_val > 255)
- new_val = 255;
- dd->eep_st_new_errs[eidx] = new_val;
- spin_unlock_irqrestore(&dd->eep_st_lock, flags);
-}
diff --git a/drivers/infiniband/hw/qib/qib_file_ops.c b/drivers/infiniband/hw/qib/qib_file_ops.c
index b15e34eeef68..41937c6f888a 100644
--- a/drivers/infiniband/hw/qib/qib_file_ops.c
+++ b/drivers/infiniband/hw/qib/qib_file_ops.c
@@ -351,9 +351,10 @@ static int qib_tid_update(struct qib_ctxtdata *rcd, struct file *fp,
* unless perhaps the user has mpin'ed the pages
* themselves.
*/
- qib_devinfo(dd->pcidev,
- "Failed to lock addr %p, %u pages: "
- "errno %d\n", (void *) vaddr, cnt, -ret);
+ qib_devinfo(
+ dd->pcidev,
+ "Failed to lock addr %p, %u pages: errno %d\n",
+ (void *) vaddr, cnt, -ret);
goto done;
}
for (i = 0; i < cnt; i++, vaddr += PAGE_SIZE) {
@@ -437,7 +438,7 @@ cleanup:
goto cleanup;
}
if (copy_to_user((void __user *) (unsigned long) ti->tidmap,
- tidmap, sizeof tidmap)) {
+ tidmap, sizeof(tidmap))) {
ret = -EFAULT;
goto cleanup;
}
@@ -484,7 +485,7 @@ static int qib_tid_free(struct qib_ctxtdata *rcd, unsigned subctxt,
}
if (copy_from_user(tidmap, (void __user *)(unsigned long)ti->tidmap,
- sizeof tidmap)) {
+ sizeof(tidmap))) {
ret = -EFAULT;
goto done;
}
@@ -951,8 +952,8 @@ static int mmap_kvaddr(struct vm_area_struct *vma, u64 pgaddr,
/* rcvegrbufs are read-only on the slave */
if (vma->vm_flags & VM_WRITE) {
qib_devinfo(dd->pcidev,
- "Can't map eager buffers as "
- "writable (flags=%lx)\n", vma->vm_flags);
+ "Can't map eager buffers as writable (flags=%lx)\n",
+ vma->vm_flags);
ret = -EPERM;
goto bail;
}
@@ -1185,6 +1186,7 @@ static void assign_ctxt_affinity(struct file *fp, struct qib_devdata *dd)
*/
if (weight >= qib_cpulist_count) {
int cpu;
+
cpu = find_first_zero_bit(qib_cpulist,
qib_cpulist_count);
if (cpu == qib_cpulist_count)
@@ -1247,10 +1249,7 @@ static int init_subctxts(struct qib_devdata *dd,
if (!qib_compatible_subctxts(uinfo->spu_userversion >> 16,
uinfo->spu_userversion & 0xffff)) {
qib_devinfo(dd->pcidev,
- "Mismatched user version (%d.%d) and driver "
- "version (%d.%d) while context sharing. Ensure "
- "that driver and library are from the same "
- "release.\n",
+ "Mismatched user version (%d.%d) and driver version (%d.%d) while context sharing. Ensure that driver and library are from the same release.\n",
(int) (uinfo->spu_userversion >> 16),
(int) (uinfo->spu_userversion & 0xffff),
QIB_USER_SWMAJOR, QIB_USER_SWMINOR);
@@ -1391,6 +1390,7 @@ static int choose_port_ctxt(struct file *fp, struct qib_devdata *dd, u32 port,
}
if (!ppd) {
u32 pidx = ctxt % dd->num_pports;
+
if (usable(dd->pport + pidx))
ppd = dd->pport + pidx;
else {
@@ -1438,10 +1438,12 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
if (alg == QIB_PORT_ALG_ACROSS) {
unsigned inuse = ~0U;
+
/* find device (with ACTIVE ports) with fewest ctxts in use */
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
unsigned cused = 0, cfree = 0, pusable = 0;
+
if (!dd)
continue;
if (port && port <= dd->num_pports &&
@@ -1471,6 +1473,7 @@ static int get_a_ctxt(struct file *fp, const struct qib_user_info *uinfo,
} else {
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
+
if (dd) {
ret = choose_port_ctxt(fp, dd, port, uinfo);
if (!ret)
@@ -1556,6 +1559,7 @@ static int find_hca(unsigned int cpu, int *unit)
}
for (ndev = 0; ndev < devmax; ndev++) {
struct qib_devdata *dd = qib_lookup(ndev);
+
if (dd) {
if (pcibus_to_node(dd->pcidev->bus) < 0) {
ret = -EINVAL;
diff --git a/drivers/infiniband/hw/qib/qib_fs.c b/drivers/infiniband/hw/qib/qib_fs.c
index 81854586c081..650897a8591e 100644
--- a/drivers/infiniband/hw/qib/qib_fs.c
+++ b/drivers/infiniband/hw/qib/qib_fs.c
@@ -106,7 +106,7 @@ static ssize_t driver_stats_read(struct file *file, char __user *buf,
{
qib_stats.sps_ints = qib_sps_ints();
return simple_read_from_buffer(buf, count, ppos, &qib_stats,
- sizeof qib_stats);
+ sizeof(qib_stats));
}
/*
@@ -133,7 +133,7 @@ static ssize_t driver_names_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
return simple_read_from_buffer(buf, count, ppos, qib_statnames,
- sizeof qib_statnames - 1); /* no null */
+ sizeof(qib_statnames) - 1); /* no null */
}
static const struct file_operations driver_ops[] = {
@@ -379,7 +379,7 @@ static int add_cntr_files(struct super_block *sb, struct qib_devdata *dd)
int ret, i;
/* create the per-unit directory */
- snprintf(unit, sizeof unit, "%u", dd->unit);
+ snprintf(unit, sizeof(unit), "%u", dd->unit);
ret = create_file(unit, S_IFDIR|S_IRUGO|S_IXUGO, sb->s_root, &dir,
&simple_dir_operations, dd);
if (ret) {
@@ -455,7 +455,7 @@ static int remove_file(struct dentry *parent, char *name)
}
spin_lock(&tmp->d_lock);
- if (!(d_unhashed(tmp) && tmp->d_inode)) {
+ if (!d_unhashed(tmp) && tmp->d_inode) {
__d_drop(tmp);
spin_unlock(&tmp->d_lock);
simple_unlink(parent->d_inode, tmp);
@@ -482,7 +482,7 @@ static int remove_device_files(struct super_block *sb,
root = dget(sb->s_root);
mutex_lock(&root->d_inode->i_mutex);
- snprintf(unit, sizeof unit, "%u", dd->unit);
+ snprintf(unit, sizeof(unit), "%u", dd->unit);
dir = lookup_one_len(unit, root, strlen(unit));
if (IS_ERR(dir)) {
@@ -560,6 +560,7 @@ static struct dentry *qibfs_mount(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data)
{
struct dentry *ret;
+
ret = mount_single(fs_type, flags, data, qibfs_fill_super);
if (!IS_ERR(ret))
qib_super = ret->d_sb;
diff --git a/drivers/infiniband/hw/qib/qib_iba6120.c b/drivers/infiniband/hw/qib/qib_iba6120.c
index d68266ac7619..0d2ba59af30a 100644
--- a/drivers/infiniband/hw/qib/qib_iba6120.c
+++ b/drivers/infiniband/hw/qib/qib_iba6120.c
@@ -333,6 +333,7 @@ static inline void qib_write_ureg(const struct qib_devdata *dd,
enum qib_ureg regno, u64 value, int ctxt)
{
u64 __iomem *ubase;
+
if (dd->userbase)
ubase = (u64 __iomem *)
((char __iomem *) dd->userbase +
@@ -834,14 +835,14 @@ static void qib_handle_6120_hwerrors(struct qib_devdata *dd, char *msg,
bits = (u32) ((hwerrs >>
QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
if (hwerrs & _QIB_PLL_FAIL) {
isfatal = 1;
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PLL failed (%llx), InfiniPath hardware unusable]",
(unsigned long long) hwerrs & _QIB_PLL_FAIL);
strlcat(msg, bitsmsg, msgl);
@@ -1014,7 +1015,7 @@ static void handle_6120_errors(struct qib_devdata *dd, u64 errs)
/* do these first, they are most important */
if (errs & ERR_MASK(HardwareErr))
- qib_handle_6120_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+ qib_handle_6120_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
else
for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
if (errs & dd->eep_st_masks[log_idx].errs_to_log)
@@ -1062,7 +1063,7 @@ static void handle_6120_errors(struct qib_devdata *dd, u64 errs)
*/
mask = ERR_MASK(IBStatusChanged) | ERR_MASK(RcvEgrFullErr) |
ERR_MASK(RcvHdrFullErr) | ERR_MASK(HardwareErr);
- qib_decode_6120_err(dd, msg, sizeof dd->cspec->emsgbuf, errs & ~mask);
+ qib_decode_6120_err(dd, msg, sizeof(dd->cspec->emsgbuf), errs & ~mask);
if (errs & E_SUM_PKTERRS)
qib_stats.sps_rcverrs++;
@@ -1670,6 +1671,7 @@ static irqreturn_t qib_6120intr(int irq, void *data)
}
if (crcs) {
u32 cntr = dd->cspec->lli_counter;
+
cntr += crcs;
if (cntr) {
if (cntr > dd->cspec->lli_thresh) {
@@ -1722,6 +1724,7 @@ static void qib_setup_6120_interrupt(struct qib_devdata *dd)
"irq is 0, BIOS error? Interrupts won't work\n");
else {
int ret;
+
ret = request_irq(dd->cspec->irq, qib_6120intr, 0,
QIB_DRV_NAME, dd);
if (ret)
@@ -2681,8 +2684,6 @@ static void qib_get_6120_faststats(unsigned long opaque)
spin_lock_irqsave(&dd->eep_st_lock, flags);
traffic_wds -= dd->traffic_wds;
dd->traffic_wds += traffic_wds;
- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
- atomic_add(5, &dd->active_time); /* S/B #define */
spin_unlock_irqrestore(&dd->eep_st_lock, flags);
qib_chk_6120_errormask(dd);
@@ -2929,6 +2930,7 @@ bail:
static int qib_6120_set_loopback(struct qib_pportdata *ppd, const char *what)
{
int ret = 0;
+
if (!strncmp(what, "ibc", 3)) {
ppd->dd->cspec->ibcctrl |= SYM_MASK(IBCCtrl, Loopback);
qib_devinfo(ppd->dd->pcidev, "Enabling IB%u:%u IBC loopback\n",
@@ -3170,6 +3172,7 @@ static void get_6120_chip_params(struct qib_devdata *dd)
static void set_6120_baseaddrs(struct qib_devdata *dd)
{
u32 cregbase;
+
cregbase = qib_read_kreg32(dd, kr_counterregbase);
dd->cspec->cregbase = (u64 __iomem *)
((char __iomem *) dd->kregbase + cregbase);
diff --git a/drivers/infiniband/hw/qib/qib_iba7220.c b/drivers/infiniband/hw/qib/qib_iba7220.c
index 7dec89fdc124..22affda8af88 100644
--- a/drivers/infiniband/hw/qib/qib_iba7220.c
+++ b/drivers/infiniband/hw/qib/qib_iba7220.c
@@ -902,7 +902,8 @@ static void sdma_7220_errors(struct qib_pportdata *ppd, u64 errs)
errs &= QLOGIC_IB_E_SDMAERRS;
msg = dd->cspec->sdmamsgbuf;
- qib_decode_7220_sdma_errs(ppd, errs, msg, sizeof dd->cspec->sdmamsgbuf);
+ qib_decode_7220_sdma_errs(ppd, errs, msg,
+ sizeof(dd->cspec->sdmamsgbuf));
spin_lock_irqsave(&ppd->sdma_lock, flags);
if (errs & ERR_MASK(SendBufMisuseErr)) {
@@ -1043,6 +1044,7 @@ done:
static void reenable_7220_chase(unsigned long opaque)
{
struct qib_pportdata *ppd = (struct qib_pportdata *)opaque;
+
ppd->cpspec->chase_timer.expires = 0;
qib_set_ib_7220_lstate(ppd, QLOGIC_IB_IBCC_LINKCMD_DOWN,
QLOGIC_IB_IBCC_LINKINITCMD_POLL);
@@ -1101,7 +1103,7 @@ static void handle_7220_errors(struct qib_devdata *dd, u64 errs)
/* do these first, they are most important */
if (errs & ERR_MASK(HardwareErr))
- qib_7220_handle_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+ qib_7220_handle_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
else
for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
if (errs & dd->eep_st_masks[log_idx].errs_to_log)
@@ -1155,7 +1157,7 @@ static void handle_7220_errors(struct qib_devdata *dd, u64 errs)
ERR_MASK(RcvEgrFullErr) | ERR_MASK(RcvHdrFullErr) |
ERR_MASK(HardwareErr) | ERR_MASK(SDmaDisabledErr);
- qib_decode_7220_err(dd, msg, sizeof dd->cspec->emsgbuf, errs & ~mask);
+ qib_decode_7220_err(dd, msg, sizeof(dd->cspec->emsgbuf), errs & ~mask);
if (errs & E_SUM_PKTERRS)
qib_stats.sps_rcverrs++;
@@ -1380,7 +1382,7 @@ static void qib_7220_handle_hwerrors(struct qib_devdata *dd, char *msg,
bits = (u32) ((hwerrs >>
QLOGIC_IB_HWE_PCIEMEMPARITYERR_SHIFT) &
QLOGIC_IB_HWE_PCIEMEMPARITYERR_MASK);
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PCIe Mem Parity Errs %x] ", bits);
strlcat(msg, bitsmsg, msgl);
}
@@ -1390,7 +1392,7 @@ static void qib_7220_handle_hwerrors(struct qib_devdata *dd, char *msg,
if (hwerrs & _QIB_PLL_FAIL) {
isfatal = 1;
- snprintf(bitsmsg, sizeof dd->cspec->bitsmsgbuf,
+ snprintf(bitsmsg, sizeof(dd->cspec->bitsmsgbuf),
"[PLL failed (%llx), InfiniPath hardware unusable]",
(unsigned long long) hwerrs & _QIB_PLL_FAIL);
strlcat(msg, bitsmsg, msgl);
@@ -3297,8 +3299,6 @@ static void qib_get_7220_faststats(unsigned long opaque)
spin_lock_irqsave(&dd->eep_st_lock, flags);
traffic_wds -= dd->traffic_wds;
dd->traffic_wds += traffic_wds;
- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
- atomic_add(5, &dd->active_time); /* S/B #define */
spin_unlock_irqrestore(&dd->eep_st_lock, flags);
done:
mod_timer(&dd->stats_timer, jiffies + HZ * ACTIVITY_TIMER);
diff --git a/drivers/infiniband/hw/qib/qib_iba7322.c b/drivers/infiniband/hw/qib/qib_iba7322.c
index a7eb32517a04..ef97b71c8f7d 100644
--- a/drivers/infiniband/hw/qib/qib_iba7322.c
+++ b/drivers/infiniband/hw/qib/qib_iba7322.c
@@ -117,7 +117,7 @@ MODULE_PARM_DESC(chase, "Enable state chase handling");
static ushort qib_long_atten = 10; /* 10 dB ~= 5m length */
module_param_named(long_attenuation, qib_long_atten, ushort, S_IRUGO);
-MODULE_PARM_DESC(long_attenuation, \
+MODULE_PARM_DESC(long_attenuation,
"attenuation cutoff (dB) for long copper cable setup");
static ushort qib_singleport;
@@ -153,11 +153,12 @@ static struct kparam_string kp_txselect = {
static int setup_txselect(const char *, struct kernel_param *);
module_param_call(txselect, setup_txselect, param_get_string,
&kp_txselect, S_IWUSR | S_IRUGO);
-MODULE_PARM_DESC(txselect, \
+MODULE_PARM_DESC(txselect,
"Tx serdes indices (for no QSFP or invalid QSFP data)");
#define BOARD_QME7342 5
#define BOARD_QMH7342 6
+#define BOARD_QMH7360 9
#define IS_QMH(dd) (SYM_FIELD((dd)->revision, Revision, BoardID) == \
BOARD_QMH7342)
#define IS_QME(dd) (SYM_FIELD((dd)->revision, Revision, BoardID) == \
@@ -817,6 +818,7 @@ static inline void qib_write_ureg(const struct qib_devdata *dd,
enum qib_ureg regno, u64 value, int ctxt)
{
u64 __iomem *ubase;
+
if (dd->userbase)
ubase = (u64 __iomem *)
((char __iomem *) dd->userbase +
@@ -1677,7 +1679,7 @@ static noinline void handle_7322_errors(struct qib_devdata *dd)
/* do these first, they are most important */
if (errs & QIB_E_HARDWARE) {
*msg = '\0';
- qib_7322_handle_hwerrors(dd, msg, sizeof dd->cspec->emsgbuf);
+ qib_7322_handle_hwerrors(dd, msg, sizeof(dd->cspec->emsgbuf));
} else
for (log_idx = 0; log_idx < QIB_EEP_LOG_CNT; ++log_idx)
if (errs & dd->eep_st_masks[log_idx].errs_to_log)
@@ -1702,7 +1704,7 @@ static noinline void handle_7322_errors(struct qib_devdata *dd)
mask = QIB_E_HARDWARE;
*msg = '\0';
- err_decode(msg, sizeof dd->cspec->emsgbuf, errs & ~mask,
+ err_decode(msg, sizeof(dd->cspec->emsgbuf), errs & ~mask,
qib_7322error_msgs);
/*
@@ -1889,10 +1891,10 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
*msg = '\0';
if (errs & ~QIB_E_P_BITSEXTANT) {
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf),
errs & ~QIB_E_P_BITSEXTANT, qib_7322p_error_msgs);
if (!*msg)
- snprintf(msg, sizeof ppd->cpspec->epmsgbuf,
+ snprintf(msg, sizeof(ppd->cpspec->epmsgbuf),
"no others");
qib_dev_porterr(dd, ppd->port,
"error interrupt with unknown errors 0x%016Lx set (and %s)\n",
@@ -1906,7 +1908,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
/* determine cause, then write to clear */
symptom = qib_read_kreg_port(ppd, krp_sendhdrsymptom);
qib_write_kreg_port(ppd, krp_sendhdrsymptom, 0);
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf, symptom,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf), symptom,
hdrchk_msgs);
*msg = '\0';
/* senderrbuf cleared in SPKTERRS below */
@@ -1922,7 +1924,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
* isn't valid. We don't want to confuse people, so
* we just don't print them, except at debug
*/
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf),
(errs & QIB_E_P_LINK_PKTERRS),
qib_7322p_error_msgs);
*msg = '\0';
@@ -1938,7 +1940,7 @@ static noinline void handle_7322_p_errors(struct qib_pportdata *ppd)
* valid. We don't want to confuse people, so we just
* don't print them, except at debug
*/
- err_decode(msg, sizeof ppd->cpspec->epmsgbuf, errs,
+ err_decode(msg, sizeof(ppd->cpspec->epmsgbuf), errs,
qib_7322p_error_msgs);
ignore_this_time = errs & QIB_E_P_LINK_PKTERRS;
*msg = '\0';
@@ -2031,6 +2033,7 @@ static void qib_7322_set_intr_state(struct qib_devdata *dd, u32 enable)
if (dd->cspec->num_msix_entries) {
/* and same for MSIx */
u64 val = qib_read_kreg64(dd, kr_intgranted);
+
if (val)
qib_write_kreg(dd, kr_intgranted, val);
}
@@ -2176,6 +2179,7 @@ static void qib_7322_handle_hwerrors(struct qib_devdata *dd, char *msg,
int err;
unsigned long flags;
struct qib_pportdata *ppd = dd->pport;
+
for (; pidx < dd->num_pports; ++pidx, ppd++) {
err = 0;
if (pidx == 0 && (hwerrs &
@@ -2801,9 +2805,11 @@ static void qib_irq_notifier_notify(struct irq_affinity_notify *notify,
if (n->rcv) {
struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+
qib_update_rhdrq_dca(rcd, cpu);
} else {
struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+
qib_update_sdma_dca(ppd, cpu);
}
}
@@ -2816,9 +2822,11 @@ static void qib_irq_notifier_release(struct kref *ref)
if (n->rcv) {
struct qib_ctxtdata *rcd = (struct qib_ctxtdata *)n->arg;
+
dd = rcd->dd;
} else {
struct qib_pportdata *ppd = (struct qib_pportdata *)n->arg;
+
dd = ppd->dd;
}
qib_devinfo(dd->pcidev,
@@ -2994,6 +3002,7 @@ static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd)
struct qib_pportdata *ppd;
struct qib_qsfp_data *qd;
u32 mask;
+
if (!dd->pport[pidx].link_speed_supported)
continue;
mask = QSFP_GPIO_MOD_PRS_N;
@@ -3001,6 +3010,7 @@ static noinline void unknown_7322_gpio_intr(struct qib_devdata *dd)
mask <<= (QSFP_GPIO_PORT2_SHIFT * ppd->hw_pidx);
if (gpiostatus & dd->cspec->gpio_mask & mask) {
u64 pins;
+
qd = &ppd->cpspec->qsfp_data;
gpiostatus &= ~mask;
pins = qib_read_kreg64(dd, kr_extstatus);
@@ -3442,7 +3452,7 @@ try_intx:
}
/* Try to get MSIx interrupts */
- memset(redirect, 0, sizeof redirect);
+ memset(redirect, 0, sizeof(redirect));
mask = ~0ULL;
msixnum = 0;
local_mask = cpumask_of_pcibus(dd->pcidev->bus);
@@ -3617,6 +3627,10 @@ static unsigned qib_7322_boardname(struct qib_devdata *dd)
n = "InfiniPath_QME7362";
dd->flags |= QIB_HAS_QSFP;
break;
+ case BOARD_QMH7360:
+ n = "Intel IB QDR 1P FLR-QSFP Adptr";
+ dd->flags |= QIB_HAS_QSFP;
+ break;
case 15:
n = "InfiniPath_QLE7342_TEST";
dd->flags |= QIB_HAS_QSFP;
@@ -3694,6 +3708,7 @@ static int qib_do_7322_reset(struct qib_devdata *dd)
*/
for (i = 0; i < msix_entries; i++) {
u64 vecaddr, vecdata;
+
vecaddr = qib_read_kreg64(dd, 2 * i +
(QIB_7322_MsixTable_OFFS / sizeof(u64)));
vecdata = qib_read_kreg64(dd, 1 + 2 * i +
@@ -5178,8 +5193,6 @@ static void qib_get_7322_faststats(unsigned long opaque)
spin_lock_irqsave(&ppd->dd->eep_st_lock, flags);
traffic_wds -= ppd->dd->traffic_wds;
ppd->dd->traffic_wds += traffic_wds;
- if (traffic_wds >= QIB_TRAFFIC_ACTIVE_THRESHOLD)
- atomic_add(ACTIVITY_TIMER, &ppd->dd->active_time);
spin_unlock_irqrestore(&ppd->dd->eep_st_lock, flags);
if (ppd->cpspec->qdr_dfe_on && (ppd->link_speed_active &
QIB_IB_QDR) &&
@@ -5357,6 +5370,7 @@ static void qib_autoneg_7322_send(struct qib_pportdata *ppd, int which)
static void set_7322_ibspeed_fast(struct qib_pportdata *ppd, u32 speed)
{
u64 newctrlb;
+
newctrlb = ppd->cpspec->ibcctrl_b & ~(IBA7322_IBC_SPEED_MASK |
IBA7322_IBC_IBTA_1_2_MASK |
IBA7322_IBC_MAX_SPEED_MASK);
@@ -5843,6 +5857,7 @@ static void get_7322_chip_params(struct qib_devdata *dd)
static void qib_7322_set_baseaddrs(struct qib_devdata *dd)
{
u32 cregbase;
+
cregbase = qib_read_kreg32(dd, kr_counterregbase);
dd->cspec->cregbase = (u64 __iomem *)(cregbase +
@@ -6183,6 +6198,7 @@ static int setup_txselect(const char *str, struct kernel_param *kp)
struct qib_devdata *dd;
unsigned long val;
char *n;
+
if (strlen(str) >= MAX_ATTEN_LEN) {
pr_info("txselect_values string too long\n");
return -ENOSPC;
@@ -6393,6 +6409,7 @@ static void write_7322_initregs(struct qib_devdata *dd)
val = TIDFLOW_ERRBITS; /* these are W1C */
for (i = 0; i < dd->cfgctxts; i++) {
int flow;
+
for (flow = 0; flow < NUM_TIDFLOWS_CTXT; flow++)
qib_write_ureg(dd, ur_rcvflowtable+flow, val, i);
}
@@ -6503,6 +6520,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
for (pidx = 0; pidx < NUM_IB_PORTS; ++pidx) {
struct qib_chippport_specific *cp = ppd->cpspec;
+
ppd->link_speed_supported = features & PORT_SPD_CAP;
features >>= PORT_SPD_CAP_SHIFT;
if (!ppd->link_speed_supported) {
@@ -6581,8 +6599,7 @@ static int qib_init_7322_variables(struct qib_devdata *dd)
ppd->vls_supported = IB_VL_VL0_7;
else {
qib_devinfo(dd->pcidev,
- "Invalid num_vls %u for MTU %d "
- ", using 4 VLs\n",
+ "Invalid num_vls %u for MTU %d , using 4 VLs\n",
qib_num_cfg_vls, mtu);
ppd->vls_supported = IB_VL_VL0_3;
qib_num_cfg_vls = 4;
@@ -7890,6 +7907,7 @@ static void serdes_7322_los_enable(struct qib_pportdata *ppd, int enable)
static int serdes_7322_init(struct qib_pportdata *ppd)
{
int ret = 0;
+
if (ppd->dd->cspec->r1)
ret = serdes_7322_init_old(ppd);
else
@@ -8305,8 +8323,8 @@ static void force_h1(struct qib_pportdata *ppd)
static int qib_r_grab(struct qib_devdata *dd)
{
- u64 val;
- val = SJA_EN;
+ u64 val = SJA_EN;
+
qib_write_kreg(dd, kr_r_access, val);
qib_read_kreg32(dd, kr_scratch);
return 0;
@@ -8319,6 +8337,7 @@ static int qib_r_wait_for_rdy(struct qib_devdata *dd)
{
u64 val;
int timeout;
+
for (timeout = 0; timeout < 100 ; ++timeout) {
val = qib_read_kreg32(dd, kr_r_access);
if (val & R_RDY)
@@ -8346,6 +8365,7 @@ static int qib_r_shift(struct qib_devdata *dd, int bisten,
}
if (inp) {
int tdi = inp[pos >> 3] >> (pos & 7);
+
val |= ((tdi & 1) << R_TDI_LSB);
}
qib_write_kreg(dd, kr_r_access, val);
diff --git a/drivers/infiniband/hw/qib/qib_init.c b/drivers/infiniband/hw/qib/qib_init.c
index 729da39c49ed..2ee36953e234 100644
--- a/drivers/infiniband/hw/qib/qib_init.c
+++ b/drivers/infiniband/hw/qib/qib_init.c
@@ -140,7 +140,7 @@ int qib_create_ctxts(struct qib_devdata *dd)
* Allocate full ctxtcnt array, rather than just cfgctxts, because
* cleanup iterates across all possible ctxts.
*/
- dd->rcd = kzalloc(sizeof(*dd->rcd) * dd->ctxtcnt, GFP_KERNEL);
+ dd->rcd = kcalloc(dd->ctxtcnt, sizeof(*dd->rcd), GFP_KERNEL);
if (!dd->rcd) {
qib_dev_err(dd,
"Unable to allocate ctxtdata array, failing\n");
@@ -234,6 +234,7 @@ int qib_init_pportdata(struct qib_pportdata *ppd, struct qib_devdata *dd,
u8 hw_pidx, u8 port)
{
int size;
+
ppd->dd = dd;
ppd->hw_pidx = hw_pidx;
ppd->port = port; /* IB port number, not index */
@@ -613,6 +614,7 @@ static int qib_create_workqueues(struct qib_devdata *dd)
ppd = dd->pport + pidx;
if (!ppd->qib_wq) {
char wq_name[8]; /* 3 + 2 + 1 + 1 + 1 */
+
snprintf(wq_name, sizeof(wq_name), "qib%d_%d",
dd->unit, pidx);
ppd->qib_wq =
@@ -714,6 +716,7 @@ int qib_init(struct qib_devdata *dd, int reinit)
for (pidx = 0; pidx < dd->num_pports; ++pidx) {
int mtu;
+
if (lastfail)
ret = lastfail;
ppd = dd->pport + pidx;
@@ -931,7 +934,6 @@ static void qib_shutdown_device(struct qib_devdata *dd)
qib_free_pportdata(ppd);
}
- qib_update_eeprom_log(dd);
}
/**
@@ -1026,8 +1028,7 @@ static void qib_verify_pioperf(struct qib_devdata *dd)
addr = vmalloc(cnt);
if (!addr) {
qib_devinfo(dd->pcidev,
- "Couldn't get memory for checking PIO perf,"
- " skipping\n");
+ "Couldn't get memory for checking PIO perf, skipping\n");
goto done;
}
@@ -1163,6 +1164,7 @@ struct qib_devdata *qib_alloc_devdata(struct pci_dev *pdev, size_t extra)
if (!qib_cpulist_count) {
u32 count = num_online_cpus();
+
qib_cpulist = kzalloc(BITS_TO_LONGS(count) *
sizeof(long), GFP_KERNEL);
if (qib_cpulist)
@@ -1179,7 +1181,7 @@ bail:
if (!list_empty(&dd->list))
list_del_init(&dd->list);
ib_dealloc_device(&dd->verbs_dev.ibdev);
- return ERR_PTR(ret);;
+ return ERR_PTR(ret);
}
/*
diff --git a/drivers/infiniband/hw/qib/qib_intr.c b/drivers/infiniband/hw/qib/qib_intr.c
index f4918f2165ec..086616d071b9 100644
--- a/drivers/infiniband/hw/qib/qib_intr.c
+++ b/drivers/infiniband/hw/qib/qib_intr.c
@@ -168,7 +168,6 @@ skip_ibchange:
ppd->lastibcstat = ibcs;
if (ev)
signal_ib_event(ppd, ev);
- return;
}
void qib_clear_symerror_on_linkup(unsigned long opaque)
diff --git a/drivers/infiniband/hw/qib/qib_keys.c b/drivers/infiniband/hw/qib/qib_keys.c
index 3b9afccaaade..ad843c786e72 100644
--- a/drivers/infiniband/hw/qib/qib_keys.c
+++ b/drivers/infiniband/hw/qib/qib_keys.c
@@ -122,10 +122,10 @@ void qib_free_lkey(struct qib_mregion *mr)
if (!mr->lkey_published)
goto out;
if (lkey == 0)
- rcu_assign_pointer(dev->dma_mr, NULL);
+ RCU_INIT_POINTER(dev->dma_mr, NULL);
else {
r = lkey >> (32 - ib_qib_lkey_table_size);
- rcu_assign_pointer(rkt->table[r], NULL);
+ RCU_INIT_POINTER(rkt->table[r], NULL);
}
qib_put_mr(mr);
mr->lkey_published = 0;
diff --git a/drivers/infiniband/hw/qib/qib_mad.c b/drivers/infiniband/hw/qib/qib_mad.c
index 636be117b578..395f4046dba2 100644
--- a/drivers/infiniband/hw/qib/qib_mad.c
+++ b/drivers/infiniband/hw/qib/qib_mad.c
@@ -152,14 +152,14 @@ void qib_bad_pqkey(struct qib_ibport *ibp, __be16 trap_num, u32 key, u32 sl,
data.trap_num = trap_num;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_257_258.lid1 = lid1;
data.details.ntc_257_258.lid2 = lid2;
data.details.ntc_257_258.key = cpu_to_be32(key);
data.details.ntc_257_258.sl_qp1 = cpu_to_be32((sl << 28) | qp1);
data.details.ntc_257_258.qp2 = cpu_to_be32(qp2);
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -176,7 +176,7 @@ static void qib_bad_mkey(struct qib_ibport *ibp, struct ib_smp *smp)
data.trap_num = IB_NOTICE_TRAP_BAD_MKEY;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_256.lid = data.issuer_lid;
data.details.ntc_256.method = smp->method;
data.details.ntc_256.attr_id = smp->attr_id;
@@ -198,7 +198,7 @@ static void qib_bad_mkey(struct qib_ibport *ibp, struct ib_smp *smp)
hop_cnt);
}
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -214,11 +214,11 @@ void qib_cap_mask_chg(struct qib_ibport *ibp)
data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_144.lid = data.issuer_lid;
data.details.ntc_144.new_cap_mask = cpu_to_be32(ibp->port_cap_flags);
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -234,11 +234,11 @@ void qib_sys_guid_chg(struct qib_ibport *ibp)
data.trap_num = IB_NOTICE_TRAP_SYS_GUID_CHG;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_145.lid = data.issuer_lid;
data.details.ntc_145.new_sys_guid = ib_qib_sys_image_guid;
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
/*
@@ -254,12 +254,12 @@ void qib_node_desc_chg(struct qib_ibport *ibp)
data.trap_num = IB_NOTICE_TRAP_CAP_MASK_CHG;
data.issuer_lid = cpu_to_be16(ppd_from_ibp(ibp)->lid);
data.toggle_count = 0;
- memset(&data.details, 0, sizeof data.details);
+ memset(&data.details, 0, sizeof(data.details));
data.details.ntc_144.lid = data.issuer_lid;
data.details.ntc_144.local_changes = 1;
data.details.ntc_144.change_flags = IB_NOTICE_TRAP_NODE_DESC_CHG;
- qib_send_trap(ibp, &data, sizeof data);
+ qib_send_trap(ibp, &data, sizeof(data));
}
static int subn_get_nodedescription(struct ib_smp *smp,
diff --git a/drivers/infiniband/hw/qib/qib_mmap.c b/drivers/infiniband/hw/qib/qib_mmap.c
index 8b73a11d571c..146cf29a2e1d 100644
--- a/drivers/infiniband/hw/qib/qib_mmap.c
+++ b/drivers/infiniband/hw/qib/qib_mmap.c
@@ -134,7 +134,7 @@ struct qib_mmap_info *qib_create_mmap_info(struct qib_ibdev *dev,
void *obj) {
struct qib_mmap_info *ip;
- ip = kmalloc(sizeof *ip, GFP_KERNEL);
+ ip = kmalloc(sizeof(*ip), GFP_KERNEL);
if (!ip)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_mr.c b/drivers/infiniband/hw/qib/qib_mr.c
index a77fb4fb14e4..c4473db46699 100644
--- a/drivers/infiniband/hw/qib/qib_mr.c
+++ b/drivers/infiniband/hw/qib/qib_mr.c
@@ -55,7 +55,7 @@ static int init_qib_mregion(struct qib_mregion *mr, struct ib_pd *pd,
m = (count + QIB_SEGSZ - 1) / QIB_SEGSZ;
for (; i < m; i++) {
- mr->map[i] = kzalloc(sizeof *mr->map[0], GFP_KERNEL);
+ mr->map[i] = kzalloc(sizeof(*mr->map[0]), GFP_KERNEL);
if (!mr->map[i])
goto bail;
}
@@ -104,7 +104,7 @@ struct ib_mr *qib_get_dma_mr(struct ib_pd *pd, int acc)
goto bail;
}
- mr = kzalloc(sizeof *mr, GFP_KERNEL);
+ mr = kzalloc(sizeof(*mr), GFP_KERNEL);
if (!mr) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -143,7 +143,7 @@ static struct qib_mr *alloc_mr(int count, struct ib_pd *pd)
/* Allocate struct plus pointers to first level page tables. */
m = (count + QIB_SEGSZ - 1) / QIB_SEGSZ;
- mr = kzalloc(sizeof *mr + m * sizeof mr->mr.map[0], GFP_KERNEL);
+ mr = kzalloc(sizeof(*mr) + m * sizeof(mr->mr.map[0]), GFP_KERNEL);
if (!mr)
goto bail;
@@ -347,7 +347,7 @@ qib_alloc_fast_reg_page_list(struct ib_device *ibdev, int page_list_len)
if (size > PAGE_SIZE)
return ERR_PTR(-EINVAL);
- pl = kzalloc(sizeof *pl, GFP_KERNEL);
+ pl = kzalloc(sizeof(*pl), GFP_KERNEL);
if (!pl)
return ERR_PTR(-ENOMEM);
@@ -386,7 +386,7 @@ struct ib_fmr *qib_alloc_fmr(struct ib_pd *pd, int mr_access_flags,
/* Allocate struct plus pointers to first level page tables. */
m = (fmr_attr->max_pages + QIB_SEGSZ - 1) / QIB_SEGSZ;
- fmr = kzalloc(sizeof *fmr + m * sizeof fmr->mr.map[0], GFP_KERNEL);
+ fmr = kzalloc(sizeof(*fmr) + m * sizeof(fmr->mr.map[0]), GFP_KERNEL);
if (!fmr)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_pcie.c b/drivers/infiniband/hw/qib/qib_pcie.c
index 61a0046efb76..4758a3801ae8 100644
--- a/drivers/infiniband/hw/qib/qib_pcie.c
+++ b/drivers/infiniband/hw/qib/qib_pcie.c
@@ -210,7 +210,7 @@ static void qib_msix_setup(struct qib_devdata *dd, int pos, u32 *msixcnt,
/* We can't pass qib_msix_entry array to qib_msix_setup
* so use a dummy msix_entry array and copy the allocated
* irq back to the qib_msix_entry array. */
- msix_entry = kmalloc(nvec * sizeof(*msix_entry), GFP_KERNEL);
+ msix_entry = kcalloc(nvec, sizeof(*msix_entry), GFP_KERNEL);
if (!msix_entry)
goto do_intx;
@@ -234,8 +234,10 @@ free_msix_entry:
kfree(msix_entry);
do_intx:
- qib_dev_err(dd, "pci_enable_msix_range %d vectors failed: %d, "
- "falling back to INTx\n", nvec, ret);
+ qib_dev_err(
+ dd,
+ "pci_enable_msix_range %d vectors failed: %d, falling back to INTx\n",
+ nvec, ret);
*msixcnt = 0;
qib_enable_intx(dd->pcidev);
}
@@ -459,6 +461,7 @@ void qib_pcie_getcmd(struct qib_devdata *dd, u16 *cmd, u8 *iline, u8 *cline)
void qib_pcie_reenable(struct qib_devdata *dd, u16 cmd, u8 iline, u8 cline)
{
int r;
+
r = pci_write_config_dword(dd->pcidev, PCI_BASE_ADDRESS_0,
dd->pcibar0);
if (r)
@@ -696,6 +699,7 @@ static void
qib_pci_resume(struct pci_dev *pdev)
{
struct qib_devdata *dd = pci_get_drvdata(pdev);
+
qib_devinfo(pdev, "QIB resume function called\n");
pci_cleanup_aer_uncorrect_error_status(pdev);
/*
diff --git a/drivers/infiniband/hw/qib/qib_qp.c b/drivers/infiniband/hw/qib/qib_qp.c
index 6ddc0264aad2..4fa88ba2963e 100644
--- a/drivers/infiniband/hw/qib/qib_qp.c
+++ b/drivers/infiniband/hw/qib/qib_qp.c
@@ -255,10 +255,10 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
if (rcu_dereference_protected(ibp->qp0,
lockdep_is_held(&dev->qpt_lock)) == qp) {
- rcu_assign_pointer(ibp->qp0, NULL);
+ RCU_INIT_POINTER(ibp->qp0, NULL);
} else if (rcu_dereference_protected(ibp->qp1,
lockdep_is_held(&dev->qpt_lock)) == qp) {
- rcu_assign_pointer(ibp->qp1, NULL);
+ RCU_INIT_POINTER(ibp->qp1, NULL);
} else {
struct qib_qp *q;
struct qib_qp __rcu **qpp;
@@ -269,7 +269,7 @@ static void remove_qp(struct qib_ibdev *dev, struct qib_qp *qp)
lockdep_is_held(&dev->qpt_lock))) != NULL;
qpp = &q->next)
if (q == qp) {
- rcu_assign_pointer(*qpp,
+ RCU_INIT_POINTER(*qpp,
rcu_dereference_protected(qp->next,
lockdep_is_held(&dev->qpt_lock)));
removed = 1;
@@ -315,7 +315,7 @@ unsigned qib_free_all_qps(struct qib_devdata *dd)
for (n = 0; n < dev->qp_table_size; n++) {
qp = rcu_dereference_protected(dev->qp_table[n],
lockdep_is_held(&dev->qpt_lock));
- rcu_assign_pointer(dev->qp_table[n], NULL);
+ RCU_INIT_POINTER(dev->qp_table[n], NULL);
for (; qp; qp = rcu_dereference_protected(qp->next,
lockdep_is_held(&dev->qpt_lock)))
diff --git a/drivers/infiniband/hw/qib/qib_qsfp.c b/drivers/infiniband/hw/qib/qib_qsfp.c
index fa71b1e666c5..5e27f76805e2 100644
--- a/drivers/infiniband/hw/qib/qib_qsfp.c
+++ b/drivers/infiniband/hw/qib/qib_qsfp.c
@@ -81,7 +81,7 @@ static int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len)
* Module could take up to 2 Msec to respond to MOD_SEL, and there
* is no way to tell if it is ready, so we must wait.
*/
- msleep(2);
+ msleep(20);
/* Make sure TWSI bus is in sane state. */
ret = qib_twsi_reset(dd);
@@ -99,6 +99,7 @@ static int qsfp_read(struct qib_pportdata *ppd, int addr, void *bp, int len)
while (cnt < len) {
unsigned in_page;
int wlen = len - cnt;
+
in_page = addr % QSFP_PAGESIZE;
if ((in_page + wlen) > QSFP_PAGESIZE)
wlen = QSFP_PAGESIZE - in_page;
@@ -139,7 +140,7 @@ deselect:
else if (pass)
qib_dev_porterr(dd, ppd->port, "QSFP retries: %d\n", pass);
- msleep(2);
+ msleep(20);
bail:
mutex_unlock(&dd->eep_lock);
@@ -189,7 +190,7 @@ static int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp,
* Module could take up to 2 Msec to respond to MOD_SEL,
* and there is no way to tell if it is ready, so we must wait.
*/
- msleep(2);
+ msleep(20);
/* Make sure TWSI bus is in sane state. */
ret = qib_twsi_reset(dd);
@@ -206,6 +207,7 @@ static int qib_qsfp_write(struct qib_pportdata *ppd, int addr, void *bp,
while (cnt < len) {
unsigned in_page;
int wlen = len - cnt;
+
in_page = addr % QSFP_PAGESIZE;
if ((in_page + wlen) > QSFP_PAGESIZE)
wlen = QSFP_PAGESIZE - in_page;
@@ -234,7 +236,7 @@ deselect:
* going away, and there is no way to tell if it is ready.
* so we must wait.
*/
- msleep(2);
+ msleep(20);
bail:
mutex_unlock(&dd->eep_lock);
@@ -296,6 +298,7 @@ int qib_refresh_qsfp_cache(struct qib_pportdata *ppd, struct qib_qsfp_cache *cp)
* set the page to zero, Even if it already appears to be zero.
*/
u8 poke = 0;
+
ret = qib_qsfp_write(ppd, 127, &poke, 1);
udelay(50);
if (ret != 1) {
@@ -480,7 +483,6 @@ void qib_qsfp_init(struct qib_qsfp_data *qd,
udelay(20); /* Generous RST dwell */
dd->f_gpio_mod(dd, mask, mask, mask);
- return;
}
void qib_qsfp_deinit(struct qib_qsfp_data *qd)
@@ -540,6 +542,7 @@ int qib_qsfp_dump(struct qib_pportdata *ppd, char *buf, int len)
while (bidx < QSFP_DEFAULT_HDR_CNT) {
int iidx;
+
ret = qsfp_read(ppd, bidx, bin_buff, QSFP_DUMP_CHUNK);
if (ret < 0)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_rc.c b/drivers/infiniband/hw/qib/qib_rc.c
index 2f2501890c4e..4544d6f88ad7 100644
--- a/drivers/infiniband/hw/qib/qib_rc.c
+++ b/drivers/infiniband/hw/qib/qib_rc.c
@@ -1017,7 +1017,7 @@ void qib_rc_send_complete(struct qib_qp *qp, struct qib_ib_header *hdr)
/* Post a send completion queue entry if requested. */
if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr.wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
@@ -1073,7 +1073,7 @@ static struct qib_swqe *do_rc_completion(struct qib_qp *qp,
/* Post a send completion queue entry if requested. */
if (!(qp->s_flags & QIB_S_SIGNAL_REQ_WR) ||
(wqe->wr.send_flags & IB_SEND_SIGNALED)) {
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr.wr_id;
wc.status = IB_WC_SUCCESS;
wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
diff --git a/drivers/infiniband/hw/qib/qib_ruc.c b/drivers/infiniband/hw/qib/qib_ruc.c
index 4c07a8b34ffe..f42bd0f47577 100644
--- a/drivers/infiniband/hw/qib/qib_ruc.c
+++ b/drivers/infiniband/hw/qib/qib_ruc.c
@@ -247,8 +247,8 @@ static __be64 get_sguid(struct qib_ibport *ibp, unsigned index)
struct qib_pportdata *ppd = ppd_from_ibp(ibp);
return ppd->guid;
- } else
- return ibp->guids[index - 1];
+ }
+ return ibp->guids[index - 1];
}
static int gid_ok(union ib_gid *gid, __be64 gid_prefix, __be64 id)
@@ -420,7 +420,7 @@ again:
goto serr;
}
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
send_status = IB_WC_SUCCESS;
release = 1;
@@ -792,7 +792,7 @@ void qib_send_complete(struct qib_qp *qp, struct qib_swqe *wqe,
status != IB_WC_SUCCESS) {
struct ib_wc wc;
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.wr_id = wqe->wr.wr_id;
wc.status = status;
wc.opcode = ib_qib_wc_opcode[wqe->wr.opcode];
diff --git a/drivers/infiniband/hw/qib/qib_sd7220.c b/drivers/infiniband/hw/qib/qib_sd7220.c
index 911205d3d5a0..c72775f27212 100644
--- a/drivers/infiniband/hw/qib/qib_sd7220.c
+++ b/drivers/infiniband/hw/qib/qib_sd7220.c
@@ -259,6 +259,7 @@ static int qib_ibsd_reset(struct qib_devdata *dd, int assert_rst)
* it again during startup.
*/
u64 val;
+
rst_val &= ~(1ULL);
qib_write_kreg(dd, kr_hwerrmask,
dd->cspec->hwerrmask &
@@ -590,6 +591,7 @@ static int epb_access(struct qib_devdata *dd, int sdnum, int claim)
* Both should be clear
*/
u64 newval = 0;
+
qib_write_kreg(dd, acc, newval);
/* First read after write is not trustworthy */
pollval = qib_read_kreg32(dd, acc);
@@ -601,6 +603,7 @@ static int epb_access(struct qib_devdata *dd, int sdnum, int claim)
/* Need to claim */
u64 pollval;
u64 newval = EPB_ACC_REQ | oct_sel;
+
qib_write_kreg(dd, acc, newval);
/* First read after write is not trustworthy */
pollval = qib_read_kreg32(dd, acc);
@@ -812,6 +815,7 @@ static int qib_sd7220_ram_xfer(struct qib_devdata *dd, int sdnum, u32 loc,
if (!sofar) {
/* Only set address at start of chunk */
int addrbyte = (addr + sofar) >> 8;
+
transval = csbit | EPB_MADDRH | addrbyte;
tries = epb_trans(dd, trans, transval,
&transval);
@@ -922,7 +926,7 @@ qib_sd7220_ib_vfy(struct qib_devdata *dd, const struct firmware *fw)
* IRQ not set up at this point in init, so we poll.
*/
#define IB_SERDES_TRIM_DONE (1ULL << 11)
-#define TRIM_TMO (30)
+#define TRIM_TMO (15)
static int qib_sd_trimdone_poll(struct qib_devdata *dd)
{
@@ -940,7 +944,7 @@ static int qib_sd_trimdone_poll(struct qib_devdata *dd)
ret = 1;
break;
}
- msleep(10);
+ msleep(20);
}
if (trim_tmo >= TRIM_TMO) {
qib_dev_err(dd, "No TRIMDONE in %d tries\n", trim_tmo);
@@ -1071,6 +1075,7 @@ static int qib_sd_setvals(struct qib_devdata *dd)
dds_reg_map >>= 4;
for (midx = 0; midx < DDS_ROWS; ++midx) {
u64 __iomem *daddr = taddr + ((midx << 4) + idx);
+
data = dds_init_vals[midx].reg_vals[idx];
writeq(data, daddr);
mmiowb();
diff --git a/drivers/infiniband/hw/qib/qib_sysfs.c b/drivers/infiniband/hw/qib/qib_sysfs.c
index 3c8e4e3caca6..81f56cdff2bc 100644
--- a/drivers/infiniband/hw/qib/qib_sysfs.c
+++ b/drivers/infiniband/hw/qib/qib_sysfs.c
@@ -586,8 +586,8 @@ static ssize_t show_serial(struct device *device,
container_of(device, struct qib_ibdev, ibdev.dev);
struct qib_devdata *dd = dd_from_dev(dev);
- buf[sizeof dd->serial] = '\0';
- memcpy(buf, dd->serial, sizeof dd->serial);
+ buf[sizeof(dd->serial)] = '\0';
+ memcpy(buf, dd->serial, sizeof(dd->serial));
strcat(buf, "\n");
return strlen(buf);
}
@@ -611,28 +611,6 @@ bail:
return ret < 0 ? ret : count;
}
-static ssize_t show_logged_errs(struct device *device,
- struct device_attribute *attr, char *buf)
-{
- struct qib_ibdev *dev =
- container_of(device, struct qib_ibdev, ibdev.dev);
- struct qib_devdata *dd = dd_from_dev(dev);
- int idx, count;
-
- /* force consistency with actual EEPROM */
- if (qib_update_eeprom_log(dd) != 0)
- return -ENXIO;
-
- count = 0;
- for (idx = 0; idx < QIB_EEP_LOG_CNT; ++idx) {
- count += scnprintf(buf + count, PAGE_SIZE - count, "%d%c",
- dd->eep_st_errs[idx],
- idx == (QIB_EEP_LOG_CNT - 1) ? '\n' : ' ');
- }
-
- return count;
-}
-
/*
* Dump tempsense regs. in decimal, to ease shell-scripts.
*/
@@ -679,7 +657,6 @@ static DEVICE_ATTR(nctxts, S_IRUGO, show_nctxts, NULL);
static DEVICE_ATTR(nfreectxts, S_IRUGO, show_nfreectxts, NULL);
static DEVICE_ATTR(serial, S_IRUGO, show_serial, NULL);
static DEVICE_ATTR(boardversion, S_IRUGO, show_boardversion, NULL);
-static DEVICE_ATTR(logged_errors, S_IRUGO, show_logged_errs, NULL);
static DEVICE_ATTR(tempsense, S_IRUGO, show_tempsense, NULL);
static DEVICE_ATTR(localbus_info, S_IRUGO, show_localbus_info, NULL);
static DEVICE_ATTR(chip_reset, S_IWUSR, NULL, store_chip_reset);
@@ -693,7 +670,6 @@ static struct device_attribute *qib_attributes[] = {
&dev_attr_nfreectxts,
&dev_attr_serial,
&dev_attr_boardversion,
- &dev_attr_logged_errors,
&dev_attr_tempsense,
&dev_attr_localbus_info,
&dev_attr_chip_reset,
diff --git a/drivers/infiniband/hw/qib/qib_twsi.c b/drivers/infiniband/hw/qib/qib_twsi.c
index 647f7beb1b0a..f5698664419b 100644
--- a/drivers/infiniband/hw/qib/qib_twsi.c
+++ b/drivers/infiniband/hw/qib/qib_twsi.c
@@ -105,6 +105,7 @@ static void scl_out(struct qib_devdata *dd, u8 bit)
udelay(2);
else {
int rise_usec;
+
for (rise_usec = SCL_WAIT_USEC; rise_usec > 0; rise_usec -= 2) {
if (mask & dd->f_gpio_mod(dd, 0, 0, 0))
break;
@@ -326,6 +327,7 @@ int qib_twsi_reset(struct qib_devdata *dd)
static int qib_twsi_wr(struct qib_devdata *dd, int data, int flags)
{
int ret = 1;
+
if (flags & QIB_TWSI_START)
start_seq(dd);
@@ -435,8 +437,7 @@ int qib_twsi_blk_wr(struct qib_devdata *dd, int dev, int addr,
int sub_len;
const u8 *bp = buffer;
int max_wait_time, i;
- int ret;
- ret = 1;
+ int ret = 1;
while (len > 0) {
if (dev == QIB_TWSI_NO_DEV) {
diff --git a/drivers/infiniband/hw/qib/qib_tx.c b/drivers/infiniband/hw/qib/qib_tx.c
index 31d3561400a4..eface3b3dacf 100644
--- a/drivers/infiniband/hw/qib/qib_tx.c
+++ b/drivers/infiniband/hw/qib/qib_tx.c
@@ -180,6 +180,7 @@ void qib_disarm_piobufs_set(struct qib_devdata *dd, unsigned long *mask,
for (i = 0; i < cnt; i++) {
int which;
+
if (!test_bit(i, mask))
continue;
/*
diff --git a/drivers/infiniband/hw/qib/qib_ud.c b/drivers/infiniband/hw/qib/qib_ud.c
index aaf7039f8ed2..26243b722b5e 100644
--- a/drivers/infiniband/hw/qib/qib_ud.c
+++ b/drivers/infiniband/hw/qib/qib_ud.c
@@ -127,7 +127,7 @@ static void qib_ud_loopback(struct qib_qp *sqp, struct qib_swqe *swqe)
* present on the wire.
*/
length = swqe->length;
- memset(&wc, 0, sizeof wc);
+ memset(&wc, 0, sizeof(wc));
wc.byte_len = length + sizeof(struct ib_grh);
if (swqe->wr.opcode == IB_WR_SEND_WITH_IMM) {
diff --git a/drivers/infiniband/hw/qib/qib_user_sdma.c b/drivers/infiniband/hw/qib/qib_user_sdma.c
index d2806cae234c..3e0677c51276 100644
--- a/drivers/infiniband/hw/qib/qib_user_sdma.c
+++ b/drivers/infiniband/hw/qib/qib_user_sdma.c
@@ -50,7 +50,7 @@
/* expected size of headers (for dma_pool) */
#define QIB_USER_SDMA_EXP_HEADER_LENGTH 64
/* attempt to drain the queue for 5secs */
-#define QIB_USER_SDMA_DRAIN_TIMEOUT 500
+#define QIB_USER_SDMA_DRAIN_TIMEOUT 250
/*
* track how many times a process open this driver.
@@ -226,6 +226,7 @@ qib_user_sdma_queue_create(struct device *dev, int unit, int ctxt, int sctxt)
sdma_rb_node->refcount++;
} else {
int ret;
+
sdma_rb_node = kmalloc(sizeof(
struct qib_user_sdma_rb_node), GFP_KERNEL);
if (!sdma_rb_node)
@@ -936,6 +937,7 @@ static int qib_user_sdma_queue_pkts(const struct qib_devdata *dd,
if (tiddma) {
char *tidsm = (char *)pkt + pktsize;
+
cfur = copy_from_user(tidsm,
iov[idx].iov_base, tidsmsize);
if (cfur) {
@@ -1142,7 +1144,7 @@ void qib_user_sdma_queue_drain(struct qib_pportdata *ppd,
qib_user_sdma_hwqueue_clean(ppd);
qib_user_sdma_queue_clean(ppd, pq);
mutex_unlock(&pq->lock);
- msleep(10);
+ msleep(20);
}
if (pq->num_pending || pq->num_sending) {
@@ -1316,8 +1318,6 @@ retry:
if (nfree && !list_empty(pktlist))
goto retry;
-
- return;
}
/* pq->lock must be held, get packets on the wire... */
diff --git a/drivers/infiniband/hw/qib/qib_verbs.c b/drivers/infiniband/hw/qib/qib_verbs.c
index 9bcfbd842980..4a3599890ea5 100644
--- a/drivers/infiniband/hw/qib/qib_verbs.c
+++ b/drivers/infiniband/hw/qib/qib_verbs.c
@@ -1342,6 +1342,7 @@ static int qib_verbs_send_pio(struct qib_qp *qp, struct qib_ib_header *ibhdr,
done:
if (dd->flags & QIB_USE_SPCL_TRIG) {
u32 spcl_off = (pbufn >= dd->piobcnt2k) ? 2047 : 1023;
+
qib_flush_wc();
__raw_writel(0xaebecede, piobuf_orig + spcl_off);
}
@@ -1744,7 +1745,7 @@ static struct ib_pd *qib_alloc_pd(struct ib_device *ibdev,
* we allow allocations of more than we report for this value.
*/
- pd = kmalloc(sizeof *pd, GFP_KERNEL);
+ pd = kmalloc(sizeof(*pd), GFP_KERNEL);
if (!pd) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -1829,7 +1830,7 @@ static struct ib_ah *qib_create_ah(struct ib_pd *pd,
goto bail;
}
- ah = kmalloc(sizeof *ah, GFP_ATOMIC);
+ ah = kmalloc(sizeof(*ah), GFP_ATOMIC);
if (!ah) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -1862,7 +1863,7 @@ struct ib_ah *qib_create_qp0_ah(struct qib_ibport *ibp, u16 dlid)
struct ib_ah *ah = ERR_PTR(-EINVAL);
struct qib_qp *qp0;
- memset(&attr, 0, sizeof attr);
+ memset(&attr, 0, sizeof(attr));
attr.dlid = dlid;
attr.port_num = ppd_from_ibp(ibp)->port;
rcu_read_lock();
@@ -1977,7 +1978,7 @@ static struct ib_ucontext *qib_alloc_ucontext(struct ib_device *ibdev,
struct qib_ucontext *context;
struct ib_ucontext *ret;
- context = kmalloc(sizeof *context, GFP_KERNEL);
+ context = kmalloc(sizeof(*context), GFP_KERNEL);
if (!context) {
ret = ERR_PTR(-ENOMEM);
goto bail;
@@ -2054,7 +2055,9 @@ int qib_register_ib_device(struct qib_devdata *dd)
dev->qp_table_size = ib_qib_qp_table_size;
get_random_bytes(&dev->qp_rnd, sizeof(dev->qp_rnd));
- dev->qp_table = kmalloc(dev->qp_table_size * sizeof *dev->qp_table,
+ dev->qp_table = kmalloc_array(
+ dev->qp_table_size,
+ sizeof(*dev->qp_table),
GFP_KERNEL);
if (!dev->qp_table) {
ret = -ENOMEM;
@@ -2122,7 +2125,7 @@ int qib_register_ib_device(struct qib_devdata *dd)
for (i = 0; i < ppd->sdma_descq_cnt; i++) {
struct qib_verbs_txreq *tx;
- tx = kzalloc(sizeof *tx, GFP_KERNEL);
+ tx = kzalloc(sizeof(*tx), GFP_KERNEL);
if (!tx) {
ret = -ENOMEM;
goto err_tx;
diff --git a/drivers/infiniband/hw/qib/qib_verbs_mcast.c b/drivers/infiniband/hw/qib/qib_verbs_mcast.c
index dabb697b1c2a..f8ea069a3eaf 100644
--- a/drivers/infiniband/hw/qib/qib_verbs_mcast.c
+++ b/drivers/infiniband/hw/qib/qib_verbs_mcast.c
@@ -43,7 +43,7 @@ static struct qib_mcast_qp *qib_mcast_qp_alloc(struct qib_qp *qp)
{
struct qib_mcast_qp *mqp;
- mqp = kmalloc(sizeof *mqp, GFP_KERNEL);
+ mqp = kmalloc(sizeof(*mqp), GFP_KERNEL);
if (!mqp)
goto bail;
@@ -75,7 +75,7 @@ static struct qib_mcast *qib_mcast_alloc(union ib_gid *mgid)
{
struct qib_mcast *mcast;
- mcast = kmalloc(sizeof *mcast, GFP_KERNEL);
+ mcast = kmalloc(sizeof(*mcast), GFP_KERNEL);
if (!mcast)
goto bail;
diff --git a/drivers/infiniband/hw/qib/qib_wc_x86_64.c b/drivers/infiniband/hw/qib/qib_wc_x86_64.c
index 1d7281c5a02e..81b225f2300a 100644
--- a/drivers/infiniband/hw/qib/qib_wc_x86_64.c
+++ b/drivers/infiniband/hw/qib/qib_wc_x86_64.c
@@ -72,6 +72,7 @@ int qib_enable_wc(struct qib_devdata *dd)
if (dd->piobcnt2k && dd->piobcnt4k) {
/* 2 sizes for chip */
unsigned long pio2kbase, pio4kbase;
+
pio2kbase = dd->piobufbase & 0xffffffffUL;
pio4kbase = (dd->piobufbase >> 32) & 0xffffffffUL;
if (pio2kbase < pio4kbase) {
@@ -91,7 +92,7 @@ int qib_enable_wc(struct qib_devdata *dd)
}
for (bits = 0; !(piolen & (1ULL << bits)); bits++)
- /* do nothing */ ;
+ ; /* do nothing */
if (piolen != (1ULL << bits)) {
piolen >>= bits;
@@ -100,8 +101,8 @@ int qib_enable_wc(struct qib_devdata *dd)
piolen = 1ULL << (bits + 1);
}
if (pioaddr & (piolen - 1)) {
- u64 atmp;
- atmp = pioaddr & ~(piolen - 1);
+ u64 atmp = pioaddr & ~(piolen - 1);
+
if (atmp < addr || (atmp + piolen) > (addr + len)) {
qib_dev_err(dd,
"No way to align address/size (%llx/%llx), no WC mtrr\n",
diff --git a/drivers/infiniband/ulp/ipoib/ipoib.h b/drivers/infiniband/ulp/ipoib/ipoib.h
index 8ba80a6d3a46..d7562beb5423 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib.h
+++ b/drivers/infiniband/ulp/ipoib/ipoib.h
@@ -98,15 +98,9 @@ enum {
IPOIB_MCAST_FLAG_FOUND = 0, /* used in set_multicast_list */
IPOIB_MCAST_FLAG_SENDONLY = 1,
- /*
- * For IPOIB_MCAST_FLAG_BUSY
- * When set, in flight join and mcast->mc is unreliable
- * When clear and mcast->mc IS_ERR_OR_NULL, need to restart or
- * haven't started yet
- * When clear and mcast->mc is valid pointer, join was successful
- */
- IPOIB_MCAST_FLAG_BUSY = 2,
+ IPOIB_MCAST_FLAG_BUSY = 2, /* joining or already joined */
IPOIB_MCAST_FLAG_ATTACHED = 3,
+ IPOIB_MCAST_JOIN_STARTED = 4,
MAX_SEND_CQE = 16,
IPOIB_CM_COPYBREAK = 256,
@@ -323,7 +317,6 @@ struct ipoib_dev_priv {
struct list_head multicast_list;
struct rb_root multicast_tree;
- struct workqueue_struct *wq;
struct delayed_work mcast_task;
struct work_struct carrier_on_task;
struct work_struct flush_light;
@@ -484,10 +477,10 @@ void ipoib_ib_dev_flush_heavy(struct work_struct *work);
void ipoib_pkey_event(struct work_struct *work);
void ipoib_ib_dev_cleanup(struct net_device *dev);
-int ipoib_ib_dev_open(struct net_device *dev);
+int ipoib_ib_dev_open(struct net_device *dev, int flush);
int ipoib_ib_dev_up(struct net_device *dev);
-int ipoib_ib_dev_down(struct net_device *dev);
-int ipoib_ib_dev_stop(struct net_device *dev);
+int ipoib_ib_dev_down(struct net_device *dev, int flush);
+int ipoib_ib_dev_stop(struct net_device *dev, int flush);
void ipoib_pkey_dev_check_presence(struct net_device *dev);
int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port);
@@ -499,7 +492,7 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb);
void ipoib_mcast_restart_task(struct work_struct *work);
int ipoib_mcast_start_thread(struct net_device *dev);
-int ipoib_mcast_stop_thread(struct net_device *dev);
+int ipoib_mcast_stop_thread(struct net_device *dev, int flush);
void ipoib_mcast_dev_down(struct net_device *dev);
void ipoib_mcast_dev_flush(struct net_device *dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_cm.c b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
index 56959adb6c7d..933efcea0d03 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_cm.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_cm.c
@@ -474,7 +474,7 @@ static int ipoib_cm_req_handler(struct ib_cm_id *cm_id, struct ib_cm_event *even
}
spin_lock_irq(&priv->lock);
- queue_delayed_work(priv->wq,
+ queue_delayed_work(ipoib_workqueue,
&priv->cm.stale_task, IPOIB_CM_RX_DELAY);
/* Add this entry to passive ids list head, but do not re-add it
* if IB_EVENT_QP_LAST_WQE_REACHED has moved it to flush list. */
@@ -576,7 +576,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
spin_lock_irqsave(&priv->lock, flags);
list_splice_init(&priv->cm.rx_drain_list, &priv->cm.rx_reap_list);
ipoib_cm_start_rx_drain(priv);
- queue_work(priv->wq, &priv->cm.rx_reap_task);
+ queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
spin_unlock_irqrestore(&priv->lock, flags);
} else
ipoib_warn(priv, "cm recv completion event with wrid %d (> %d)\n",
@@ -603,7 +603,7 @@ void ipoib_cm_handle_rx_wc(struct net_device *dev, struct ib_wc *wc)
spin_lock_irqsave(&priv->lock, flags);
list_move(&p->list, &priv->cm.rx_reap_list);
spin_unlock_irqrestore(&priv->lock, flags);
- queue_work(priv->wq, &priv->cm.rx_reap_task);
+ queue_work(ipoib_workqueue, &priv->cm.rx_reap_task);
}
return;
}
@@ -827,7 +827,7 @@ void ipoib_cm_handle_tx_wc(struct net_device *dev, struct ib_wc *wc)
if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
list_move(&tx->list, &priv->cm.reap_list);
- queue_work(priv->wq, &priv->cm.reap_task);
+ queue_work(ipoib_workqueue, &priv->cm.reap_task);
}
clear_bit(IPOIB_FLAG_OPER_UP, &tx->flags);
@@ -1255,7 +1255,7 @@ static int ipoib_cm_tx_handler(struct ib_cm_id *cm_id,
if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
list_move(&tx->list, &priv->cm.reap_list);
- queue_work(priv->wq, &priv->cm.reap_task);
+ queue_work(ipoib_workqueue, &priv->cm.reap_task);
}
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1284,7 +1284,7 @@ struct ipoib_cm_tx *ipoib_cm_create_tx(struct net_device *dev, struct ipoib_path
tx->dev = dev;
list_add(&tx->list, &priv->cm.start_list);
set_bit(IPOIB_FLAG_INITIALIZED, &tx->flags);
- queue_work(priv->wq, &priv->cm.start_task);
+ queue_work(ipoib_workqueue, &priv->cm.start_task);
return tx;
}
@@ -1295,7 +1295,7 @@ void ipoib_cm_destroy_tx(struct ipoib_cm_tx *tx)
if (test_and_clear_bit(IPOIB_FLAG_INITIALIZED, &tx->flags)) {
spin_lock_irqsave(&priv->lock, flags);
list_move(&tx->list, &priv->cm.reap_list);
- queue_work(priv->wq, &priv->cm.reap_task);
+ queue_work(ipoib_workqueue, &priv->cm.reap_task);
ipoib_dbg(priv, "Reap connection for gid %pI6\n",
tx->neigh->daddr + 4);
tx->neigh = NULL;
@@ -1417,7 +1417,7 @@ void ipoib_cm_skb_too_long(struct net_device *dev, struct sk_buff *skb,
skb_queue_tail(&priv->cm.skb_queue, skb);
if (e)
- queue_work(priv->wq, &priv->cm.skb_task);
+ queue_work(ipoib_workqueue, &priv->cm.skb_task);
}
static void ipoib_cm_rx_reap(struct work_struct *work)
@@ -1450,7 +1450,7 @@ static void ipoib_cm_stale_task(struct work_struct *work)
}
if (!list_empty(&priv->cm.passive_ids))
- queue_delayed_work(priv->wq,
+ queue_delayed_work(ipoib_workqueue,
&priv->cm.stale_task, IPOIB_CM_RX_DELAY);
spin_unlock_irq(&priv->lock);
}
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_ib.c b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
index fe65abb5150c..72626c348174 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_ib.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_ib.c
@@ -655,7 +655,7 @@ void ipoib_reap_ah(struct work_struct *work)
__ipoib_reap_ah(dev);
if (!test_bit(IPOIB_STOP_REAPER, &priv->flags))
- queue_delayed_work(priv->wq, &priv->ah_reap_task,
+ queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
round_jiffies_relative(HZ));
}
@@ -664,7 +664,7 @@ static void ipoib_ib_tx_timer_func(unsigned long ctx)
drain_tx_cq((struct net_device *)ctx);
}
-int ipoib_ib_dev_open(struct net_device *dev)
+int ipoib_ib_dev_open(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
int ret;
@@ -696,7 +696,7 @@ int ipoib_ib_dev_open(struct net_device *dev)
}
clear_bit(IPOIB_STOP_REAPER, &priv->flags);
- queue_delayed_work(priv->wq, &priv->ah_reap_task,
+ queue_delayed_work(ipoib_workqueue, &priv->ah_reap_task,
round_jiffies_relative(HZ));
if (!test_and_set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
@@ -706,7 +706,7 @@ int ipoib_ib_dev_open(struct net_device *dev)
dev_stop:
if (!test_and_set_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
napi_enable(&priv->napi);
- ipoib_ib_dev_stop(dev);
+ ipoib_ib_dev_stop(dev, flush);
return -1;
}
@@ -738,7 +738,7 @@ int ipoib_ib_dev_up(struct net_device *dev)
return ipoib_mcast_start_thread(dev);
}
-int ipoib_ib_dev_down(struct net_device *dev)
+int ipoib_ib_dev_down(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -747,7 +747,7 @@ int ipoib_ib_dev_down(struct net_device *dev)
clear_bit(IPOIB_FLAG_OPER_UP, &priv->flags);
netif_carrier_off(dev);
- ipoib_mcast_stop_thread(dev);
+ ipoib_mcast_stop_thread(dev, flush);
ipoib_mcast_dev_flush(dev);
ipoib_flush_paths(dev);
@@ -807,7 +807,7 @@ void ipoib_drain_cq(struct net_device *dev)
local_bh_enable();
}
-int ipoib_ib_dev_stop(struct net_device *dev)
+int ipoib_ib_dev_stop(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
struct ib_qp_attr qp_attr;
@@ -880,7 +880,8 @@ timeout:
/* Wait for all AHs to be reaped */
set_bit(IPOIB_STOP_REAPER, &priv->flags);
cancel_delayed_work(&priv->ah_reap_task);
- flush_workqueue(priv->wq);
+ if (flush)
+ flush_workqueue(ipoib_workqueue);
begin = jiffies;
@@ -917,7 +918,7 @@ int ipoib_ib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
(unsigned long) dev);
if (dev->flags & IFF_UP) {
- if (ipoib_ib_dev_open(dev)) {
+ if (ipoib_ib_dev_open(dev, 1)) {
ipoib_transport_dev_cleanup(dev);
return -ENODEV;
}
@@ -1039,12 +1040,12 @@ static void __ipoib_ib_dev_flush(struct ipoib_dev_priv *priv,
}
if (level >= IPOIB_FLUSH_NORMAL)
- ipoib_ib_dev_down(dev);
+ ipoib_ib_dev_down(dev, 0);
if (level == IPOIB_FLUSH_HEAVY) {
if (test_bit(IPOIB_FLAG_INITIALIZED, &priv->flags))
- ipoib_ib_dev_stop(dev);
- if (ipoib_ib_dev_open(dev) != 0)
+ ipoib_ib_dev_stop(dev, 0);
+ if (ipoib_ib_dev_open(dev, 0) != 0)
return;
if (netif_queue_stopped(dev))
netif_start_queue(dev);
@@ -1096,7 +1097,7 @@ void ipoib_ib_dev_cleanup(struct net_device *dev)
*/
ipoib_flush_paths(dev);
- ipoib_mcast_stop_thread(dev);
+ ipoib_mcast_stop_thread(dev, 1);
ipoib_mcast_dev_flush(dev);
ipoib_transport_dev_cleanup(dev);
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_main.c b/drivers/infiniband/ulp/ipoib/ipoib_main.c
index 6bad17d4d588..58b5aa3b6f2d 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_main.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_main.c
@@ -108,7 +108,7 @@ int ipoib_open(struct net_device *dev)
set_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
- if (ipoib_ib_dev_open(dev)) {
+ if (ipoib_ib_dev_open(dev, 1)) {
if (!test_bit(IPOIB_PKEY_ASSIGNED, &priv->flags))
return 0;
goto err_disable;
@@ -139,7 +139,7 @@ int ipoib_open(struct net_device *dev)
return 0;
err_stop:
- ipoib_ib_dev_stop(dev);
+ ipoib_ib_dev_stop(dev, 1);
err_disable:
clear_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags);
@@ -157,8 +157,8 @@ static int ipoib_stop(struct net_device *dev)
netif_stop_queue(dev);
- ipoib_ib_dev_down(dev);
- ipoib_ib_dev_stop(dev);
+ ipoib_ib_dev_down(dev, 1);
+ ipoib_ib_dev_stop(dev, 0);
if (!test_bit(IPOIB_FLAG_SUBINTERFACE, &priv->flags)) {
struct ipoib_dev_priv *cpriv;
@@ -839,7 +839,7 @@ static void ipoib_set_mcast_list(struct net_device *dev)
return;
}
- queue_work(priv->wq, &priv->restart_task);
+ queue_work(ipoib_workqueue, &priv->restart_task);
}
static u32 ipoib_addr_hash(struct ipoib_neigh_hash *htbl, u8 *daddr)
@@ -954,7 +954,7 @@ static void ipoib_reap_neigh(struct work_struct *work)
__ipoib_reap_neigh(priv);
if (!test_bit(IPOIB_STOP_NEIGH_GC, &priv->flags))
- queue_delayed_work(priv->wq, &priv->neigh_reap_task,
+ queue_delayed_work(ipoib_workqueue, &priv->neigh_reap_task,
arp_tbl.gc_interval);
}
@@ -1133,7 +1133,7 @@ static int ipoib_neigh_hash_init(struct ipoib_dev_priv *priv)
/* start garbage collection */
clear_bit(IPOIB_STOP_NEIGH_GC, &priv->flags);
- queue_delayed_work(priv->wq, &priv->neigh_reap_task,
+ queue_delayed_work(ipoib_workqueue, &priv->neigh_reap_task,
arp_tbl.gc_interval);
return 0;
@@ -1262,13 +1262,15 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
+ if (ipoib_neigh_hash_init(priv) < 0)
+ goto out;
/* Allocate RX/TX "rings" to hold queued skbs */
priv->rx_ring = kzalloc(ipoib_recvq_size * sizeof *priv->rx_ring,
GFP_KERNEL);
if (!priv->rx_ring) {
printk(KERN_WARNING "%s: failed to allocate RX ring (%d entries)\n",
ca->name, ipoib_recvq_size);
- goto out;
+ goto out_neigh_hash_cleanup;
}
priv->tx_ring = vzalloc(ipoib_sendq_size * sizeof *priv->tx_ring);
@@ -1283,24 +1285,16 @@ int ipoib_dev_init(struct net_device *dev, struct ib_device *ca, int port)
if (ipoib_ib_dev_init(dev, ca, port))
goto out_tx_ring_cleanup;
- /*
- * Must be after ipoib_ib_dev_init so we can allocate a per
- * device wq there and use it here
- */
- if (ipoib_neigh_hash_init(priv) < 0)
- goto out_dev_uninit;
-
return 0;
-out_dev_uninit:
- ipoib_ib_dev_cleanup(dev);
-
out_tx_ring_cleanup:
vfree(priv->tx_ring);
out_rx_ring_cleanup:
kfree(priv->rx_ring);
+out_neigh_hash_cleanup:
+ ipoib_neigh_hash_uninit(dev);
out:
return -ENOMEM;
}
@@ -1323,12 +1317,6 @@ void ipoib_dev_cleanup(struct net_device *dev)
}
unregister_netdevice_many(&head);
- /*
- * Must be before ipoib_ib_dev_cleanup or we delete an in use
- * work queue
- */
- ipoib_neigh_hash_uninit(dev);
-
ipoib_ib_dev_cleanup(dev);
kfree(priv->rx_ring);
@@ -1336,6 +1324,8 @@ void ipoib_dev_cleanup(struct net_device *dev)
priv->rx_ring = NULL;
priv->tx_ring = NULL;
+
+ ipoib_neigh_hash_uninit(dev);
}
static const struct header_ops ipoib_header_ops = {
@@ -1646,7 +1636,7 @@ register_failed:
/* Stop GC if started before flush */
set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags);
cancel_delayed_work(&priv->neigh_reap_task);
- flush_workqueue(priv->wq);
+ flush_workqueue(ipoib_workqueue);
event_failed:
ipoib_dev_cleanup(priv->dev);
@@ -1717,7 +1707,7 @@ static void ipoib_remove_one(struct ib_device *device)
/* Stop GC */
set_bit(IPOIB_STOP_NEIGH_GC, &priv->flags);
cancel_delayed_work(&priv->neigh_reap_task);
- flush_workqueue(priv->wq);
+ flush_workqueue(ipoib_workqueue);
unregister_netdev(priv->dev);
free_netdev(priv->dev);
@@ -1758,13 +1748,8 @@ static int __init ipoib_init_module(void)
* unregister_netdev() and linkwatch_event take the rtnl lock,
* so flush_scheduled_work() can deadlock during device
* removal.
- *
- * In addition, bringing one device up and another down at the
- * same time can deadlock a single workqueue, so we have this
- * global fallback workqueue, but we also attempt to open a
- * per device workqueue each time we bring an interface up
*/
- ipoib_workqueue = create_singlethread_workqueue("ipoib_flush");
+ ipoib_workqueue = create_singlethread_workqueue("ipoib");
if (!ipoib_workqueue) {
ret = -ENOMEM;
goto err_fs;
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
index bc50dd0d0e4d..ffb83b5f7e80 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_multicast.c
@@ -190,6 +190,12 @@ static int ipoib_mcast_join_finish(struct ipoib_mcast *mcast,
spin_unlock_irq(&priv->lock);
priv->tx_wr.wr.ud.remote_qkey = priv->qkey;
set_qkey = 1;
+
+ if (!ipoib_cm_admin_enabled(dev)) {
+ rtnl_lock();
+ dev_set_mtu(dev, min(priv->mcast_mtu, priv->admin_mtu));
+ rtnl_unlock();
+ }
}
if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)) {
@@ -271,27 +277,16 @@ ipoib_mcast_sendonly_join_complete(int status,
struct ipoib_mcast *mcast = multicast->context;
struct net_device *dev = mcast->dev;
- /*
- * We have to take the mutex to force mcast_sendonly_join to
- * return from ib_sa_multicast_join and set mcast->mc to a
- * valid value. Otherwise we were racing with ourselves in
- * that we might fail here, but get a valid return from
- * ib_sa_multicast_join after we had cleared mcast->mc here,
- * resulting in mis-matched joins and leaves and a deadlock
- */
- mutex_lock(&mcast_mutex);
-
/* We trap for port events ourselves. */
if (status == -ENETRESET)
- goto out;
+ return 0;
if (!status)
status = ipoib_mcast_join_finish(mcast, &multicast->rec);
if (status) {
if (mcast->logcount++ < 20)
- ipoib_dbg_mcast(netdev_priv(dev), "sendonly multicast "
- "join failed for %pI6, status %d\n",
+ ipoib_dbg_mcast(netdev_priv(dev), "multicast join failed for %pI6, status %d\n",
mcast->mcmember.mgid.raw, status);
/* Flush out any queued packets */
@@ -301,15 +296,11 @@ ipoib_mcast_sendonly_join_complete(int status,
dev_kfree_skb_any(skb_dequeue(&mcast->pkt_queue));
}
netif_tx_unlock_bh(dev);
+
+ /* Clear the busy flag so we try again */
+ status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY,
+ &mcast->flags);
}
-out:
- clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
- if (status)
- mcast->mc = NULL;
- complete(&mcast->done);
- if (status == -ENETRESET)
- status = 0;
- mutex_unlock(&mcast_mutex);
return status;
}
@@ -327,14 +318,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
int ret = 0;
if (!test_bit(IPOIB_FLAG_OPER_UP, &priv->flags)) {
- ipoib_dbg_mcast(priv, "device shutting down, no sendonly "
- "multicast joins\n");
+ ipoib_dbg_mcast(priv, "device shutting down, no multicast joins\n");
return -ENODEV;
}
- if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) {
- ipoib_dbg_mcast(priv, "multicast entry busy, skipping "
- "sendonly join\n");
+ if (test_and_set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)) {
+ ipoib_dbg_mcast(priv, "multicast entry busy, skipping\n");
return -EBUSY;
}
@@ -342,9 +331,6 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
rec.port_gid = priv->local_gid;
rec.pkey = cpu_to_be16(priv->pkey);
- mutex_lock(&mcast_mutex);
- init_completion(&mcast->done);
- set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca,
priv->port, &rec,
IB_SA_MCMEMBER_REC_MGID |
@@ -357,14 +343,12 @@ static int ipoib_mcast_sendonly_join(struct ipoib_mcast *mcast)
if (IS_ERR(mcast->mc)) {
ret = PTR_ERR(mcast->mc);
clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
- complete(&mcast->done);
- ipoib_warn(priv, "ib_sa_join_multicast for sendonly join "
- "failed (ret = %d)\n", ret);
+ ipoib_warn(priv, "ib_sa_join_multicast failed (ret = %d)\n",
+ ret);
} else {
- ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting "
- "sendonly join\n", mcast->mcmember.mgid.raw);
+ ipoib_dbg_mcast(priv, "no multicast record for %pI6, starting join\n",
+ mcast->mcmember.mgid.raw);
}
- mutex_unlock(&mcast_mutex);
return ret;
}
@@ -375,29 +359,18 @@ void ipoib_mcast_carrier_on_task(struct work_struct *work)
carrier_on_task);
struct ib_port_attr attr;
+ /*
+ * Take rtnl_lock to avoid racing with ipoib_stop() and
+ * turning the carrier back on while a device is being
+ * removed.
+ */
if (ib_query_port(priv->ca, priv->port, &attr) ||
attr.state != IB_PORT_ACTIVE) {
ipoib_dbg(priv, "Keeping carrier off until IB port is active\n");
return;
}
- /*
- * Take rtnl_lock to avoid racing with ipoib_stop() and
- * turning the carrier back on while a device is being
- * removed. However, ipoib_stop() will attempt to flush
- * the workqueue while holding the rtnl lock, so loop
- * on trylock until either we get the lock or we see
- * FLAG_ADMIN_UP go away as that signals that we are bailing
- * and can safely ignore the carrier on work.
- */
- while (!rtnl_trylock()) {
- if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
- return;
- else
- msleep(20);
- }
- if (!ipoib_cm_admin_enabled(priv->dev))
- dev_set_mtu(priv->dev, min(priv->mcast_mtu, priv->admin_mtu));
+ rtnl_lock();
netif_carrier_on(priv->dev);
rtnl_unlock();
}
@@ -412,63 +385,60 @@ static int ipoib_mcast_join_complete(int status,
ipoib_dbg_mcast(priv, "join completion for %pI6 (status %d)\n",
mcast->mcmember.mgid.raw, status);
- /*
- * We have to take the mutex to force mcast_join to
- * return from ib_sa_multicast_join and set mcast->mc to a
- * valid value. Otherwise we were racing with ourselves in
- * that we might fail here, but get a valid return from
- * ib_sa_multicast_join after we had cleared mcast->mc here,
- * resulting in mis-matched joins and leaves and a deadlock
- */
- mutex_lock(&mcast_mutex);
-
/* We trap for port events ourselves. */
- if (status == -ENETRESET)
+ if (status == -ENETRESET) {
+ status = 0;
goto out;
+ }
if (!status)
status = ipoib_mcast_join_finish(mcast, &multicast->rec);
if (!status) {
mcast->backoff = 1;
+ mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
- queue_delayed_work(priv->wq, &priv->mcast_task, 0);
+ queue_delayed_work(ipoib_workqueue,
+ &priv->mcast_task, 0);
+ mutex_unlock(&mcast_mutex);
/*
- * Defer carrier on work to priv->wq to avoid a
+ * Defer carrier on work to ipoib_workqueue to avoid a
* deadlock on rtnl_lock here.
*/
if (mcast == priv->broadcast)
- queue_work(priv->wq, &priv->carrier_on_task);
- } else {
- if (mcast->logcount++ < 20) {
- if (status == -ETIMEDOUT || status == -EAGAIN) {
- ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n",
- mcast->mcmember.mgid.raw, status);
- } else {
- ipoib_warn(priv, "multicast join failed for %pI6, status %d\n",
- mcast->mcmember.mgid.raw, status);
- }
- }
+ queue_work(ipoib_workqueue, &priv->carrier_on_task);
- mcast->backoff *= 2;
- if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
- mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
+ status = 0;
+ goto out;
}
-out:
+
+ if (mcast->logcount++ < 20) {
+ if (status == -ETIMEDOUT || status == -EAGAIN) {
+ ipoib_dbg_mcast(priv, "multicast join failed for %pI6, status %d\n",
+ mcast->mcmember.mgid.raw, status);
+ } else {
+ ipoib_warn(priv, "multicast join failed for %pI6, status %d\n",
+ mcast->mcmember.mgid.raw, status);
+ }
+ }
+
+ mcast->backoff *= 2;
+ if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
+ mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
+
+ /* Clear the busy flag so we try again */
+ status = test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+
+ mutex_lock(&mcast_mutex);
spin_lock_irq(&priv->lock);
- clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
- if (status)
- mcast->mc = NULL;
- complete(&mcast->done);
- if (status == -ENETRESET)
- status = 0;
- if (status && test_bit(IPOIB_MCAST_RUN, &priv->flags))
- queue_delayed_work(priv->wq, &priv->mcast_task,
+ if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
+ queue_delayed_work(ipoib_workqueue, &priv->mcast_task,
mcast->backoff * HZ);
spin_unlock_irq(&priv->lock);
mutex_unlock(&mcast_mutex);
-
+out:
+ complete(&mcast->done);
return status;
}
@@ -517,9 +487,10 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
rec.hop_limit = priv->broadcast->mcmember.hop_limit;
}
- mutex_lock(&mcast_mutex);
- init_completion(&mcast->done);
set_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags);
+ init_completion(&mcast->done);
+ set_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags);
+
mcast->mc = ib_sa_join_multicast(&ipoib_sa_client, priv->ca, priv->port,
&rec, comp_mask, GFP_KERNEL,
ipoib_mcast_join_complete, mcast);
@@ -533,11 +504,13 @@ static void ipoib_mcast_join(struct net_device *dev, struct ipoib_mcast *mcast,
if (mcast->backoff > IPOIB_MAX_BACKOFF_SECONDS)
mcast->backoff = IPOIB_MAX_BACKOFF_SECONDS;
+ mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
- queue_delayed_work(priv->wq, &priv->mcast_task,
+ queue_delayed_work(ipoib_workqueue,
+ &priv->mcast_task,
mcast->backoff * HZ);
+ mutex_unlock(&mcast_mutex);
}
- mutex_unlock(&mcast_mutex);
}
void ipoib_mcast_join_task(struct work_struct *work)
@@ -574,8 +547,8 @@ void ipoib_mcast_join_task(struct work_struct *work)
ipoib_warn(priv, "failed to allocate broadcast group\n");
mutex_lock(&mcast_mutex);
if (test_bit(IPOIB_MCAST_RUN, &priv->flags))
- queue_delayed_work(priv->wq, &priv->mcast_task,
- HZ);
+ queue_delayed_work(ipoib_workqueue,
+ &priv->mcast_task, HZ);
mutex_unlock(&mcast_mutex);
return;
}
@@ -590,8 +563,7 @@ void ipoib_mcast_join_task(struct work_struct *work)
}
if (!test_bit(IPOIB_MCAST_FLAG_ATTACHED, &priv->broadcast->flags)) {
- if (IS_ERR_OR_NULL(priv->broadcast->mc) &&
- !test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags))
+ if (!test_bit(IPOIB_MCAST_FLAG_BUSY, &priv->broadcast->flags))
ipoib_mcast_join(dev, priv->broadcast, 0);
return;
}
@@ -599,33 +571,23 @@ void ipoib_mcast_join_task(struct work_struct *work)
while (1) {
struct ipoib_mcast *mcast = NULL;
- /*
- * Need the mutex so our flags are consistent, need the
- * priv->lock so we don't race with list removals in either
- * mcast_dev_flush or mcast_restart_task
- */
- mutex_lock(&mcast_mutex);
spin_lock_irq(&priv->lock);
list_for_each_entry(mcast, &priv->multicast_list, list) {
- if (IS_ERR_OR_NULL(mcast->mc) &&
- !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags) &&
- !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
+ if (!test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags)
+ && !test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags)
+ && !test_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
/* Found the next unjoined group */
break;
}
}
spin_unlock_irq(&priv->lock);
- mutex_unlock(&mcast_mutex);
if (&mcast->list == &priv->multicast_list) {
/* All done */
break;
}
- if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
- ipoib_mcast_sendonly_join(mcast);
- else
- ipoib_mcast_join(dev, mcast, 1);
+ ipoib_mcast_join(dev, mcast, 1);
return;
}
@@ -642,13 +604,13 @@ int ipoib_mcast_start_thread(struct net_device *dev)
mutex_lock(&mcast_mutex);
if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags))
- queue_delayed_work(priv->wq, &priv->mcast_task, 0);
+ queue_delayed_work(ipoib_workqueue, &priv->mcast_task, 0);
mutex_unlock(&mcast_mutex);
return 0;
}
-int ipoib_mcast_stop_thread(struct net_device *dev)
+int ipoib_mcast_stop_thread(struct net_device *dev, int flush)
{
struct ipoib_dev_priv *priv = netdev_priv(dev);
@@ -659,7 +621,8 @@ int ipoib_mcast_stop_thread(struct net_device *dev)
cancel_delayed_work(&priv->mcast_task);
mutex_unlock(&mcast_mutex);
- flush_workqueue(priv->wq);
+ if (flush)
+ flush_workqueue(ipoib_workqueue);
return 0;
}
@@ -670,9 +633,6 @@ static int ipoib_mcast_leave(struct net_device *dev, struct ipoib_mcast *mcast)
int ret = 0;
if (test_and_clear_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
- ipoib_warn(priv, "ipoib_mcast_leave on an in-flight join\n");
-
- if (!IS_ERR_OR_NULL(mcast->mc))
ib_sa_free_multicast(mcast->mc);
if (test_and_clear_bit(IPOIB_MCAST_FLAG_ATTACHED, &mcast->flags)) {
@@ -725,8 +685,6 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
memcpy(mcast->mcmember.mgid.raw, mgid, sizeof (union ib_gid));
__ipoib_mcast_add(dev, mcast);
list_add_tail(&mcast->list, &priv->multicast_list);
- if (!test_and_set_bit(IPOIB_MCAST_RUN, &priv->flags))
- queue_delayed_work(priv->wq, &priv->mcast_task, 0);
}
if (!mcast->ah) {
@@ -740,6 +698,8 @@ void ipoib_mcast_send(struct net_device *dev, u8 *daddr, struct sk_buff *skb)
if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
ipoib_dbg_mcast(priv, "no address vector, "
"but multicast join already started\n");
+ else if (test_bit(IPOIB_MCAST_FLAG_SENDONLY, &mcast->flags))
+ ipoib_mcast_sendonly_join(mcast);
/*
* If lookup completes between here and out:, don't
@@ -799,12 +759,9 @@ void ipoib_mcast_dev_flush(struct net_device *dev)
spin_unlock_irqrestore(&priv->lock, flags);
- /*
- * make sure the in-flight joins have finished before we attempt
- * to leave
- */
+ /* seperate between the wait to the leave*/
list_for_each_entry_safe(mcast, tmcast, &remove_list, list)
- if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
+ if (test_bit(IPOIB_MCAST_JOIN_STARTED, &mcast->flags))
wait_for_completion(&mcast->done);
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
@@ -837,6 +794,8 @@ void ipoib_mcast_restart_task(struct work_struct *work)
ipoib_dbg_mcast(priv, "restarting multicast task\n");
+ ipoib_mcast_stop_thread(dev, 0);
+
local_irq_save(flags);
netif_addr_lock(dev);
spin_lock(&priv->lock);
@@ -921,38 +880,14 @@ void ipoib_mcast_restart_task(struct work_struct *work)
netif_addr_unlock(dev);
local_irq_restore(flags);
- /*
- * make sure the in-flight joins have finished before we attempt
- * to leave
- */
- list_for_each_entry_safe(mcast, tmcast, &remove_list, list)
- if (test_bit(IPOIB_MCAST_FLAG_BUSY, &mcast->flags))
- wait_for_completion(&mcast->done);
-
- /*
- * We have to cancel outside of the spinlock, but we have to
- * take the rtnl lock or else we race with the removal of
- * entries from the remove list in mcast_dev_flush as part
- * of ipoib_stop(). We detect the drop of the ADMIN_UP flag
- * to signal that we have hit this particular race, and we
- * return since we know we don't need to do anything else
- * anyway.
- */
- while (!rtnl_trylock()) {
- if (!test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
- return;
- else
- msleep(20);
- }
+ /* We have to cancel outside of the spinlock */
list_for_each_entry_safe(mcast, tmcast, &remove_list, list) {
ipoib_mcast_leave(mcast->dev, mcast);
ipoib_mcast_free(mcast);
}
- /*
- * Restart our join task if needed
- */
- ipoib_mcast_start_thread(dev);
- rtnl_unlock();
+
+ if (test_bit(IPOIB_FLAG_ADMIN_UP, &priv->flags))
+ ipoib_mcast_start_thread(dev);
}
#ifdef CONFIG_INFINIBAND_IPOIB_DEBUG
diff --git a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
index b72a753eb41d..c56d5d44c53b 100644
--- a/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
+++ b/drivers/infiniband/ulp/ipoib/ipoib_verbs.c
@@ -145,20 +145,10 @@ int ipoib_transport_dev_init(struct net_device *dev, struct ib_device *ca)
int ret, size;
int i;
- /*
- * the various IPoIB tasks assume they will never race against
- * themselves, so always use a single thread workqueue
- */
- priv->wq = create_singlethread_workqueue("ipoib_wq");
- if (!priv->wq) {
- printk(KERN_WARNING "ipoib: failed to allocate device WQ\n");
- return -ENODEV;
- }
-
priv->pd = ib_alloc_pd(priv->ca);
if (IS_ERR(priv->pd)) {
printk(KERN_WARNING "%s: failed to allocate PD\n", ca->name);
- goto out_free_wq;
+ return -ENODEV;
}
priv->mr = ib_get_dma_mr(priv->pd, IB_ACCESS_LOCAL_WRITE);
@@ -252,10 +242,6 @@ out_free_mr:
out_free_pd:
ib_dealloc_pd(priv->pd);
-
-out_free_wq:
- destroy_workqueue(priv->wq);
- priv->wq = NULL;
return -ENODEV;
}
@@ -284,12 +270,6 @@ void ipoib_transport_dev_cleanup(struct net_device *dev)
if (ib_dealloc_pd(priv->pd))
ipoib_warn(priv, "ib_dealloc_pd failed\n");
-
- if (priv->wq) {
- flush_workqueue(priv->wq);
- destroy_workqueue(priv->wq);
- priv->wq = NULL;
- }
}
void ipoib_event(struct ib_event_handler *handler,
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.h b/drivers/infiniband/ulp/iser/iscsi_iser.h
index 5ce26817e7e1..b47aea1094b2 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.h
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.h
@@ -654,7 +654,9 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
enum dma_data_direction dma_dir);
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
- struct iser_data_buf *data);
+ struct iser_data_buf *data,
+ enum dma_data_direction dir);
+
int iser_initialize_task_headers(struct iscsi_task *task,
struct iser_tx_desc *tx_desc);
int iser_alloc_rx_descriptors(struct iser_conn *iser_conn,
diff --git a/drivers/infiniband/ulp/iser/iser_initiator.c b/drivers/infiniband/ulp/iser/iser_initiator.c
index 3821633f1065..20e859a6f1a6 100644
--- a/drivers/infiniband/ulp/iser/iser_initiator.c
+++ b/drivers/infiniband/ulp/iser/iser_initiator.c
@@ -320,9 +320,6 @@ void iser_free_rx_descriptors(struct iser_conn *iser_conn)
struct ib_conn *ib_conn = &iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
- if (!iser_conn->rx_descs)
- goto free_login_buf;
-
if (device->iser_free_rdma_reg_res)
device->iser_free_rdma_reg_res(ib_conn);
@@ -334,7 +331,6 @@ void iser_free_rx_descriptors(struct iser_conn *iser_conn)
/* make sure we never redo any unmapping */
iser_conn->rx_descs = NULL;
-free_login_buf:
iser_free_login_buf(iser_conn);
}
@@ -714,19 +710,23 @@ void iser_task_rdma_finalize(struct iscsi_iser_task *iser_task)
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_IN);
if (is_rdma_data_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->data[ISER_DIR_IN]);
+ &iser_task->data[ISER_DIR_IN],
+ DMA_FROM_DEVICE);
if (prot_count && is_rdma_prot_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->prot[ISER_DIR_IN]);
+ &iser_task->prot[ISER_DIR_IN],
+ DMA_FROM_DEVICE);
}
if (iser_task->dir[ISER_DIR_OUT]) {
device->iser_unreg_rdma_mem(iser_task, ISER_DIR_OUT);
if (is_rdma_data_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->data[ISER_DIR_OUT]);
+ &iser_task->data[ISER_DIR_OUT],
+ DMA_TO_DEVICE);
if (prot_count && is_rdma_prot_aligned)
iser_dma_unmap_task_data(iser_task,
- &iser_task->prot[ISER_DIR_OUT]);
+ &iser_task->prot[ISER_DIR_OUT],
+ DMA_TO_DEVICE);
}
}
diff --git a/drivers/infiniband/ulp/iser/iser_memory.c b/drivers/infiniband/ulp/iser/iser_memory.c
index abce9339333f..341040bf0984 100644
--- a/drivers/infiniband/ulp/iser/iser_memory.c
+++ b/drivers/infiniband/ulp/iser/iser_memory.c
@@ -332,12 +332,13 @@ int iser_dma_map_task_data(struct iscsi_iser_task *iser_task,
}
void iser_dma_unmap_task_data(struct iscsi_iser_task *iser_task,
- struct iser_data_buf *data)
+ struct iser_data_buf *data,
+ enum dma_data_direction dir)
{
struct ib_device *dev;
dev = iser_task->iser_conn->ib_conn.device->ib_device;
- ib_dma_unmap_sg(dev, data->buf, data->size, DMA_FROM_DEVICE);
+ ib_dma_unmap_sg(dev, data->buf, data->size, dir);
}
static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
@@ -357,7 +358,9 @@ static int fall_to_bounce_buf(struct iscsi_iser_task *iser_task,
iser_data_buf_dump(mem, ibdev);
/* unmap the command data before accessing it */
- iser_dma_unmap_task_data(iser_task, mem);
+ iser_dma_unmap_task_data(iser_task, mem,
+ (cmd_dir == ISER_DIR_OUT) ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
/* allocate copy buf, if we are writing, copy the */
/* unaligned scatterlist, dma map the copy */
diff --git a/drivers/infiniband/ulp/iser/iser_verbs.c b/drivers/infiniband/ulp/iser/iser_verbs.c
index 695a2704bd43..4065abe28829 100644
--- a/drivers/infiniband/ulp/iser/iser_verbs.c
+++ b/drivers/infiniband/ulp/iser/iser_verbs.c
@@ -600,16 +600,16 @@ void iser_release_work(struct work_struct *work)
/**
* iser_free_ib_conn_res - release IB related resources
* @iser_conn: iser connection struct
- * @destroy_device: indicator if we need to try to release
- * the iser device (only iscsi shutdown and DEVICE_REMOVAL
- * will use this.
+ * @destroy: indicator if we need to try to release the
+ * iser device and memory regoins pool (only iscsi
+ * shutdown and DEVICE_REMOVAL will use this).
*
* This routine is called with the iser state mutex held
* so the cm_id removal is out of here. It is Safe to
* be invoked multiple times.
*/
static void iser_free_ib_conn_res(struct iser_conn *iser_conn,
- bool destroy_device)
+ bool destroy)
{
struct ib_conn *ib_conn = &iser_conn->ib_conn;
struct iser_device *device = ib_conn->device;
@@ -617,17 +617,20 @@ static void iser_free_ib_conn_res(struct iser_conn *iser_conn,
iser_info("freeing conn %p cma_id %p qp %p\n",
iser_conn, ib_conn->cma_id, ib_conn->qp);
- iser_free_rx_descriptors(iser_conn);
-
if (ib_conn->qp != NULL) {
ib_conn->comp->active_qps--;
rdma_destroy_qp(ib_conn->cma_id);
ib_conn->qp = NULL;
}
- if (destroy_device && device != NULL) {
- iser_device_try_release(device);
- ib_conn->device = NULL;
+ if (destroy) {
+ if (iser_conn->rx_descs)
+ iser_free_rx_descriptors(iser_conn);
+
+ if (device != NULL) {
+ iser_device_try_release(device);
+ ib_conn->device = NULL;
+ }
}
}
@@ -643,9 +646,11 @@ void iser_conn_release(struct iser_conn *iser_conn)
mutex_unlock(&ig.connlist_mutex);
mutex_lock(&iser_conn->state_mutex);
+ /* In case we endup here without ep_disconnect being invoked. */
if (iser_conn->state != ISER_CONN_DOWN) {
iser_warn("iser conn %p state %d, expected state down.\n",
iser_conn, iser_conn->state);
+ iscsi_destroy_endpoint(iser_conn->ep);
iser_conn->state = ISER_CONN_DOWN;
}
/*
@@ -840,7 +845,7 @@ static void iser_disconnected_handler(struct rdma_cm_id *cma_id)
}
static void iser_cleanup_handler(struct rdma_cm_id *cma_id,
- bool destroy_device)
+ bool destroy)
{
struct iser_conn *iser_conn = (struct iser_conn *)cma_id->context;
@@ -850,7 +855,7 @@ static void iser_cleanup_handler(struct rdma_cm_id *cma_id,
* and flush errors.
*/
iser_disconnected_handler(cma_id);
- iser_free_ib_conn_res(iser_conn, destroy_device);
+ iser_free_ib_conn_res(iser_conn, destroy);
complete(&iser_conn->ib_completion);
};
diff --git a/drivers/infiniband/ulp/isert/ib_isert.c b/drivers/infiniband/ulp/isert/ib_isert.c
index dafb3c531f96..075b19cc78e8 100644
--- a/drivers/infiniband/ulp/isert/ib_isert.c
+++ b/drivers/infiniband/ulp/isert/ib_isert.c
@@ -38,7 +38,7 @@
#define ISER_MAX_CQ_LEN (ISER_MAX_RX_CQ_LEN + ISER_MAX_TX_CQ_LEN + \
ISERT_MAX_CONN)
-int isert_debug_level = 0;
+static int isert_debug_level;
module_param_named(debug_level, isert_debug_level, int, 0644);
MODULE_PARM_DESC(debug_level, "Enable debug tracing if > 0 (default:0)");
@@ -949,7 +949,7 @@ isert_post_recv(struct isert_conn *isert_conn, u32 count)
isert_err("ib_post_recv() failed with ret: %d\n", ret);
isert_conn->post_recv_buf_count -= count;
} else {
- isert_dbg("isert_post_recv(): Posted %d RX buffers\n", count);
+ isert_dbg("Posted %d RX buffers\n", count);
isert_conn->conn_rx_desc_head = rx_head;
}
return ret;
@@ -1351,17 +1351,19 @@ isert_handle_text_cmd(struct isert_conn *isert_conn, struct isert_cmd *isert_cmd
struct iscsi_conn *conn = isert_conn->conn;
u32 payload_length = ntoh24(hdr->dlength);
int rc;
- unsigned char *text_in;
+ unsigned char *text_in = NULL;
rc = iscsit_setup_text_cmd(conn, cmd, hdr);
if (rc < 0)
return rc;
- text_in = kzalloc(payload_length, GFP_KERNEL);
- if (!text_in) {
- isert_err("Unable to allocate text_in of payload_length: %u\n",
- payload_length);
- return -ENOMEM;
+ if (payload_length) {
+ text_in = kzalloc(payload_length, GFP_KERNEL);
+ if (!text_in) {
+ isert_err("Unable to allocate text_in of payload_length: %u\n",
+ payload_length);
+ return -ENOMEM;
+ }
}
cmd->text_in_ptr = text_in;
@@ -1434,9 +1436,15 @@ isert_rx_opcode(struct isert_conn *isert_conn, struct iser_rx_desc *rx_desc,
ret = iscsit_handle_logout_cmd(conn, cmd, (unsigned char *)hdr);
break;
case ISCSI_OP_TEXT:
- cmd = isert_allocate_cmd(conn);
- if (!cmd)
- break;
+ if (be32_to_cpu(hdr->ttt) != 0xFFFFFFFF) {
+ cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
+ if (!cmd)
+ break;
+ } else {
+ cmd = isert_allocate_cmd(conn);
+ if (!cmd)
+ break;
+ }
isert_cmd = iscsit_priv_cmd(cmd);
ret = isert_handle_text_cmd(isert_conn, isert_cmd, cmd,
@@ -1658,6 +1666,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
struct isert_conn *isert_conn = isert_cmd->conn;
struct iscsi_conn *conn = isert_conn->conn;
struct isert_device *device = isert_conn->conn_device;
+ struct iscsi_text_rsp *hdr;
isert_dbg("Cmd %p\n", isert_cmd);
@@ -1698,6 +1707,11 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
case ISCSI_OP_REJECT:
case ISCSI_OP_NOOP_OUT:
case ISCSI_OP_TEXT:
+ hdr = (struct iscsi_text_rsp *)&isert_cmd->tx_desc.iscsi_header;
+ /* If the continue bit is on, keep the command alive */
+ if (hdr->flags & ISCSI_FLAG_TEXT_CONTINUE)
+ break;
+
spin_lock_bh(&conn->cmd_lock);
if (!list_empty(&cmd->i_conn_node))
list_del_init(&cmd->i_conn_node);
@@ -1709,8 +1723,7 @@ isert_put_cmd(struct isert_cmd *isert_cmd, bool comp_err)
* associated cmd->se_cmd needs to be released.
*/
if (cmd->se_cmd.se_tfo != NULL) {
- isert_dbg("Calling transport_generic_free_cmd from"
- " isert_put_cmd for 0x%02x\n",
+ isert_dbg("Calling transport_generic_free_cmd for 0x%02x\n",
cmd->iscsi_opcode);
transport_generic_free_cmd(&cmd->se_cmd, 0);
break;
@@ -2275,7 +2288,7 @@ isert_put_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn)
}
isert_init_send_wr(isert_conn, isert_cmd, send_wr);
- isert_dbg("conn %p Text Reject\n", isert_conn);
+ isert_dbg("conn %p Text Response\n", isert_conn);
return isert_post_response(isert_conn, isert_cmd);
}
@@ -3136,7 +3149,7 @@ accept_wait:
spin_lock_bh(&np->np_thread_lock);
if (np->np_thread_state >= ISCSI_NP_THREAD_RESET) {
spin_unlock_bh(&np->np_thread_lock);
- isert_dbg("np_thread_state %d for isert_accept_np\n",
+ isert_dbg("np_thread_state %d\n",
np->np_thread_state);
/**
* No point in stalling here when np_thread
@@ -3320,7 +3333,8 @@ static int __init isert_init(void)
{
int ret;
- isert_comp_wq = alloc_workqueue("isert_comp_wq", 0, 0);
+ isert_comp_wq = alloc_workqueue("isert_comp_wq",
+ WQ_UNBOUND | WQ_HIGHPRI, 0);
if (!isert_comp_wq) {
isert_err("Unable to allocate isert_comp_wq\n");
ret = -ENOMEM;
diff --git a/drivers/infiniband/ulp/srpt/ib_srpt.c b/drivers/infiniband/ulp/srpt/ib_srpt.c
index eb694ddad79f..6e0a477681e9 100644
--- a/drivers/infiniband/ulp/srpt/ib_srpt.c
+++ b/drivers/infiniband/ulp/srpt/ib_srpt.c
@@ -3518,7 +3518,7 @@ static void srpt_close_session(struct se_session *se_sess)
DECLARE_COMPLETION_ONSTACK(release_done);
struct srpt_rdma_ch *ch;
struct srpt_device *sdev;
- int res;
+ unsigned long res;
ch = se_sess->fabric_sess_ptr;
WARN_ON(ch->sess != se_sess);
@@ -3533,7 +3533,7 @@ static void srpt_close_session(struct se_session *se_sess)
spin_unlock_irq(&sdev->spinlock);
res = wait_for_completion_timeout(&release_done, 60 * HZ);
- WARN_ON(res <= 0);
+ WARN_ON(res == 0);
}
/**
diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c
index 18d4b2c8fe55..a18f41b89b6a 100644
--- a/drivers/input/evdev.c
+++ b/drivers/input/evdev.c
@@ -62,26 +62,6 @@ struct evdev_client {
struct input_event buffer[];
};
-static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
-{
- switch (clkid) {
-
- case CLOCK_REALTIME:
- client->clk_type = EV_CLK_REAL;
- break;
- case CLOCK_MONOTONIC:
- client->clk_type = EV_CLK_MONO;
- break;
- case CLOCK_BOOTTIME:
- client->clk_type = EV_CLK_BOOT;
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
/* flush queued events of type @type, caller must hold client->buffer_lock */
static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
{
@@ -128,10 +108,8 @@ static void __evdev_flush_queue(struct evdev_client *client, unsigned int type)
client->head = head;
}
-/* queue SYN_DROPPED event */
-static void evdev_queue_syn_dropped(struct evdev_client *client)
+static void __evdev_queue_syn_dropped(struct evdev_client *client)
{
- unsigned long flags;
struct input_event ev;
ktime_t time;
@@ -146,8 +124,6 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
ev.code = SYN_DROPPED;
ev.value = 0;
- spin_lock_irqsave(&client->buffer_lock, flags);
-
client->buffer[client->head++] = ev;
client->head &= client->bufsize - 1;
@@ -156,8 +132,53 @@ static void evdev_queue_syn_dropped(struct evdev_client *client)
client->tail = (client->head - 1) & (client->bufsize - 1);
client->packet_head = client->tail;
}
+}
+
+static void evdev_queue_syn_dropped(struct evdev_client *client)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&client->buffer_lock, flags);
+ __evdev_queue_syn_dropped(client);
+ spin_unlock_irqrestore(&client->buffer_lock, flags);
+}
+
+static int evdev_set_clk_type(struct evdev_client *client, unsigned int clkid)
+{
+ unsigned long flags;
+
+ if (client->clk_type == clkid)
+ return 0;
+
+ switch (clkid) {
+
+ case CLOCK_REALTIME:
+ client->clk_type = EV_CLK_REAL;
+ break;
+ case CLOCK_MONOTONIC:
+ client->clk_type = EV_CLK_MONO;
+ break;
+ case CLOCK_BOOTTIME:
+ client->clk_type = EV_CLK_BOOT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Flush pending events and queue SYN_DROPPED event,
+ * but only if the queue is not empty.
+ */
+ spin_lock_irqsave(&client->buffer_lock, flags);
+
+ if (client->head != client->tail) {
+ client->packet_head = client->head = client->tail;
+ __evdev_queue_syn_dropped(client);
+ }
spin_unlock_irqrestore(&client->buffer_lock, flags);
+
+ return 0;
}
static void __pass_event(struct evdev_client *client,
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
index fbe29fcb15c5..cb150a1dbaff 100644
--- a/drivers/input/input-mt.c
+++ b/drivers/input/input-mt.c
@@ -293,7 +293,7 @@ void input_mt_sync_frame(struct input_dev *dev)
}
EXPORT_SYMBOL(input_mt_sync_frame);
-static int adjust_dual(int *begin, int step, int *end, int eq)
+static int adjust_dual(int *begin, int step, int *end, int eq, int mu)
{
int f, *p, s, c;
@@ -311,9 +311,10 @@ static int adjust_dual(int *begin, int step, int *end, int eq)
s = *p;
c = (f + s + 1) / 2;
- if (c == 0 || (c > 0 && !eq))
+ if (c == 0 || (c > mu && (!eq || mu > 0)))
return 0;
- if (s < 0)
+ /* Improve convergence for positive matrices by penalizing overcovers */
+ if (s < 0 && mu <= 0)
c *= 2;
for (p = begin; p != end; p += step)
@@ -322,23 +323,24 @@ static int adjust_dual(int *begin, int step, int *end, int eq)
return (c < s && s <= 0) || (f >= 0 && f < c);
}
-static void find_reduced_matrix(int *w, int nr, int nc, int nrc)
+static void find_reduced_matrix(int *w, int nr, int nc, int nrc, int mu)
{
int i, k, sum;
for (k = 0; k < nrc; k++) {
for (i = 0; i < nr; i++)
- adjust_dual(w + i, nr, w + i + nrc, nr <= nc);
+ adjust_dual(w + i, nr, w + i + nrc, nr <= nc, mu);
sum = 0;
for (i = 0; i < nrc; i += nr)
- sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr);
+ sum += adjust_dual(w + i, 1, w + i + nr, nc <= nr, mu);
if (!sum)
break;
}
}
static int input_mt_set_matrix(struct input_mt *mt,
- const struct input_mt_pos *pos, int num_pos)
+ const struct input_mt_pos *pos, int num_pos,
+ int mu)
{
const struct input_mt_pos *p;
struct input_mt_slot *s;
@@ -352,7 +354,7 @@ static int input_mt_set_matrix(struct input_mt *mt,
y = input_mt_get_value(s, ABS_MT_POSITION_Y);
for (p = pos; p != pos + num_pos; p++) {
int dx = x - p->x, dy = y - p->y;
- *w++ = dx * dx + dy * dy;
+ *w++ = dx * dx + dy * dy - mu;
}
}
@@ -393,17 +395,24 @@ static void input_mt_set_slots(struct input_mt *mt,
* @slots: the slot assignment to be filled
* @pos: the position array to match
* @num_pos: number of positions
+ * @dmax: maximum ABS_MT_POSITION displacement (zero for infinite)
*
* Performs a best match against the current contacts and returns
* the slot assignment list. New contacts are assigned to unused
* slots.
*
+ * The assignments are balanced so that all coordinate displacements are
+ * below the euclidian distance dmax. If no such assignment can be found,
+ * some contacts are assigned to unused slots.
+ *
* Returns zero on success, or negative error in case of failure.
*/
int input_mt_assign_slots(struct input_dev *dev, int *slots,
- const struct input_mt_pos *pos, int num_pos)
+ const struct input_mt_pos *pos, int num_pos,
+ int dmax)
{
struct input_mt *mt = dev->mt;
+ int mu = 2 * dmax * dmax;
int nrc;
if (!mt || !mt->red)
@@ -413,8 +422,8 @@ int input_mt_assign_slots(struct input_dev *dev, int *slots,
if (num_pos < 1)
return 0;
- nrc = input_mt_set_matrix(mt, pos, num_pos);
- find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc);
+ nrc = input_mt_set_matrix(mt, pos, num_pos, mu);
+ find_reduced_matrix(mt->red, num_pos, nrc / num_pos, nrc, mu);
input_mt_set_slots(mt, slots, num_pos);
return 0;
diff --git a/drivers/input/input.c b/drivers/input/input.c
index 213e3a1903ee..cc357f1516a7 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -100,23 +100,24 @@ static unsigned int input_to_handler(struct input_handle *handle,
struct input_value *end = vals;
struct input_value *v;
- for (v = vals; v != vals + count; v++) {
- if (handler->filter &&
- handler->filter(handle, v->type, v->code, v->value))
- continue;
- if (end != v)
- *end = *v;
- end++;
+ if (handler->filter) {
+ for (v = vals; v != vals + count; v++) {
+ if (handler->filter(handle, v->type, v->code, v->value))
+ continue;
+ if (end != v)
+ *end = *v;
+ end++;
+ }
+ count = end - vals;
}
- count = end - vals;
if (!count)
return 0;
if (handler->events)
handler->events(handle, vals, count);
else if (handler->event)
- for (v = vals; v != end; v++)
+ for (v = vals; v != vals + count; v++)
handler->event(handle, v->type, v->code, v->value);
return count;
@@ -143,8 +144,11 @@ static void input_pass_values(struct input_dev *dev,
count = input_to_handler(handle, vals, count);
} else {
list_for_each_entry_rcu(handle, &dev->h_list, d_node)
- if (handle->open)
+ if (handle->open) {
count = input_to_handler(handle, vals, count);
+ if (!count)
+ break;
+ }
}
rcu_read_unlock();
@@ -152,12 +156,14 @@ static void input_pass_values(struct input_dev *dev,
add_input_randomness(vals->type, vals->code, vals->value);
/* trigger auto repeat for key events */
- for (v = vals; v != vals + count; v++) {
- if (v->type == EV_KEY && v->value != 2) {
- if (v->value)
- input_start_autorepeat(dev, v->code);
- else
- input_stop_autorepeat(dev);
+ if (test_bit(EV_REP, dev->evbit) && test_bit(EV_KEY, dev->evbit)) {
+ for (v = vals; v != vals + count; v++) {
+ if (v->type == EV_KEY && v->value != 2) {
+ if (v->value)
+ input_start_autorepeat(dev, v->code);
+ else
+ input_stop_autorepeat(dev);
+ }
}
}
}
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
index b78425765d3e..d09cefa37931 100644
--- a/drivers/input/joystick/adi.c
+++ b/drivers/input/joystick/adi.c
@@ -535,8 +535,7 @@ static int adi_connect(struct gameport *gameport, struct gameport_driver *drv)
}
}
fail2: for (i = 0; i < 2; i++)
- if (port->adi[i].dev)
- input_free_device(port->adi[i].dev);
+ input_free_device(port->adi[i].dev);
gameport_close(gameport);
fail1: gameport_set_drvdata(gameport, NULL);
kfree(port);
diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
index a5d9b3f3c871..a89ba7cb96f1 100644
--- a/drivers/input/keyboard/Kconfig
+++ b/drivers/input/keyboard/Kconfig
@@ -568,6 +568,16 @@ config KEYBOARD_STMPE
To compile this driver as a module, choose M here: the module will be
called stmpe-keypad.
+config KEYBOARD_SUN4I_LRADC
+ tristate "Allwinner sun4i low res adc attached tablet keys support"
+ depends on ARCH_SUNXI
+ help
+ This selects support for the Allwinner low res adc attached tablet
+ keys found on Allwinner sunxi SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sun4i-lradc-keys.
+
config KEYBOARD_DAVINCI
tristate "TI DaVinci Key Scan"
depends on ARCH_DAVINCI_DM365
diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
index febafa527eb6..470767884bd8 100644
--- a/drivers/input/keyboard/Makefile
+++ b/drivers/input/keyboard/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_KEYBOARD_SPEAR) += spear-keyboard.o
obj-$(CONFIG_KEYBOARD_STMPE) += stmpe-keypad.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_ST_KEYSCAN) += st-keyscan.o
+obj-$(CONFIG_KEYBOARD_SUN4I_LRADC) += sun4i-lradc-keys.o
obj-$(CONFIG_KEYBOARD_SUNKBD) += sunkbd.o
obj-$(CONFIG_KEYBOARD_TC3589X) += tc3589x-keypad.o
obj-$(CONFIG_KEYBOARD_TEGRA) += tegra-kbc.o
diff --git a/drivers/input/keyboard/atakbd.c b/drivers/input/keyboard/atakbd.c
index 10bcd4ae5402..f1235831283d 100644
--- a/drivers/input/keyboard/atakbd.c
+++ b/drivers/input/keyboard/atakbd.c
@@ -170,7 +170,7 @@ static unsigned char atakbd_keycode[0x72] = { /* American layout */
[93] = KEY_KPASTERISK,
[94] = KEY_KPPLUS,
[95] = KEY_HELP,
- [96] = KEY_BACKSLASH, /* FIXME: '<' */
+ [96] = KEY_102ND,
[97] = KEY_KPASTERISK, /* FIXME */
[98] = KEY_KPSLASH,
[99] = KEY_KPLEFTPAREN,
diff --git a/drivers/input/keyboard/atkbd.c b/drivers/input/keyboard/atkbd.c
index e27a25892db4..387c51f4b4e4 100644
--- a/drivers/input/keyboard/atkbd.c
+++ b/drivers/input/keyboard/atkbd.c
@@ -1399,8 +1399,8 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
static ssize_t atkbd_show_force_release(struct atkbd *atkbd, char *buf)
{
- size_t len = bitmap_scnlistprintf(buf, PAGE_SIZE - 2,
- atkbd->force_release_mask, ATKBD_KEYMAP_SIZE);
+ size_t len = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+ ATKBD_KEYMAP_SIZE, atkbd->force_release_mask);
buf[len++] = '\n';
buf[len] = '\0';
diff --git a/drivers/input/keyboard/cap11xx.c b/drivers/input/keyboard/cap11xx.c
index 4f59f0bab28f..f07461a64d85 100644
--- a/drivers/input/keyboard/cap11xx.c
+++ b/drivers/input/keyboard/cap11xx.c
@@ -370,7 +370,6 @@ static struct i2c_driver cap11xx_i2c_driver = {
module_i2c_driver(cap11xx_i2c_driver);
-MODULE_ALIAS("platform:cap11xx");
MODULE_DESCRIPTION("Microchip CAP11XX driver");
MODULE_AUTHOR("Daniel Mack <linux@zonque.org>");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index 883d6aed5b9a..ddf4045de084 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -190,7 +190,7 @@ static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
__set_bit(bdata->button->code, bits);
}
- ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
+ ret = scnprintf(buf, PAGE_SIZE - 1, "%*pbl", n_events, bits);
buf[ret++] = '\n';
buf[ret] = '\0';
diff --git a/drivers/input/keyboard/imx_keypad.c b/drivers/input/keyboard/imx_keypad.c
index e53f232eda0e..2e855e6f3565 100644
--- a/drivers/input/keyboard/imx_keypad.c
+++ b/drivers/input/keyboard/imx_keypad.c
@@ -448,8 +448,7 @@ static int imx_keypad_probe(struct platform_device *pdev)
return -ENOMEM;
}
- keypad = devm_kzalloc(&pdev->dev, sizeof(struct imx_keypad),
- GFP_KERNEL);
+ keypad = devm_kzalloc(&pdev->dev, sizeof(*keypad), GFP_KERNEL);
if (!keypad) {
dev_err(&pdev->dev, "not enough memory for driver data\n");
return -ENOMEM;
diff --git a/drivers/input/keyboard/pxa27x_keypad.c b/drivers/input/keyboard/pxa27x_keypad.c
index a90d6bdc499e..fcef5d1365e2 100644
--- a/drivers/input/keyboard/pxa27x_keypad.c
+++ b/drivers/input/keyboard/pxa27x_keypad.c
@@ -20,6 +20,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/input.h>
+#include <linux/io.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
@@ -28,10 +29,6 @@
#include <linux/slab.h>
#include <linux/of.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/hardware.h>
#include <linux/platform_data/keypad-pxa27x.h>
/*
* Keypad Controller registers
@@ -348,13 +345,11 @@ static int pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
{
const struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
- const struct matrix_keymap_data *keymap_data =
- pdata ? pdata->matrix_keymap_data : NULL;
unsigned short keycode;
int i;
int error;
- error = matrix_keypad_build_keymap(keymap_data, NULL,
+ error = matrix_keypad_build_keymap(pdata->matrix_keymap_data, NULL,
pdata->matrix_key_rows,
pdata->matrix_key_cols,
keypad->keycodes, input_dev);
diff --git a/drivers/input/keyboard/sun4i-lradc-keys.c b/drivers/input/keyboard/sun4i-lradc-keys.c
new file mode 100644
index 000000000000..cc8f7ddcee53
--- /dev/null
+++ b/drivers/input/keyboard/sun4i-lradc-keys.c
@@ -0,0 +1,286 @@
+/*
+ * Allwinner sun4i low res adc attached tablet keys driver
+ *
+ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.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.
+ */
+
+/*
+ * Allwinnner sunxi SoCs have a lradc which is specifically designed to have
+ * various (tablet) keys (ie home, back, search, etc). attached to it using
+ * a resistor network. This driver is for the keys on such boards.
+ *
+ * There are 2 channels, currently this driver only supports channel 0 since
+ * there are no boards known to use channel 1.
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/input.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/regulator/consumer.h>
+#include <linux/slab.h>
+
+#define LRADC_CTRL 0x00
+#define LRADC_INTC 0x04
+#define LRADC_INTS 0x08
+#define LRADC_DATA0 0x0c
+#define LRADC_DATA1 0x10
+
+/* LRADC_CTRL bits */
+#define FIRST_CONVERT_DLY(x) ((x) << 24) /* 8 bits */
+#define CHAN_SELECT(x) ((x) << 22) /* 2 bits */
+#define CONTINUE_TIME_SEL(x) ((x) << 16) /* 4 bits */
+#define KEY_MODE_SEL(x) ((x) << 12) /* 2 bits */
+#define LEVELA_B_CNT(x) ((x) << 8) /* 4 bits */
+#define HOLD_EN(x) ((x) << 6)
+#define LEVELB_VOL(x) ((x) << 4) /* 2 bits */
+#define SAMPLE_RATE(x) ((x) << 2) /* 2 bits */
+#define ENABLE(x) ((x) << 0)
+
+/* LRADC_INTC and LRADC_INTS bits */
+#define CHAN1_KEYUP_IRQ BIT(12)
+#define CHAN1_ALRDY_HOLD_IRQ BIT(11)
+#define CHAN1_HOLD_IRQ BIT(10)
+#define CHAN1_KEYDOWN_IRQ BIT(9)
+#define CHAN1_DATA_IRQ BIT(8)
+#define CHAN0_KEYUP_IRQ BIT(4)
+#define CHAN0_ALRDY_HOLD_IRQ BIT(3)
+#define CHAN0_HOLD_IRQ BIT(2)
+#define CHAN0_KEYDOWN_IRQ BIT(1)
+#define CHAN0_DATA_IRQ BIT(0)
+
+struct sun4i_lradc_keymap {
+ u32 voltage;
+ u32 keycode;
+};
+
+struct sun4i_lradc_data {
+ struct device *dev;
+ struct input_dev *input;
+ void __iomem *base;
+ struct regulator *vref_supply;
+ struct sun4i_lradc_keymap *chan0_map;
+ u32 chan0_map_count;
+ u32 chan0_keycode;
+ u32 vref;
+};
+
+static irqreturn_t sun4i_lradc_irq(int irq, void *dev_id)
+{
+ struct sun4i_lradc_data *lradc = dev_id;
+ u32 i, ints, val, voltage, diff, keycode = 0, closest = 0xffffffff;
+
+ ints = readl(lradc->base + LRADC_INTS);
+
+ /*
+ * lradc supports only one keypress at a time, release does not give
+ * any info as to which key was released, so we cache the keycode.
+ */
+
+ if (ints & CHAN0_KEYUP_IRQ) {
+ input_report_key(lradc->input, lradc->chan0_keycode, 0);
+ lradc->chan0_keycode = 0;
+ }
+
+ if ((ints & CHAN0_KEYDOWN_IRQ) && lradc->chan0_keycode == 0) {
+ val = readl(lradc->base + LRADC_DATA0) & 0x3f;
+ voltage = val * lradc->vref / 63;
+
+ for (i = 0; i < lradc->chan0_map_count; i++) {
+ diff = abs(lradc->chan0_map[i].voltage - voltage);
+ if (diff < closest) {
+ closest = diff;
+ keycode = lradc->chan0_map[i].keycode;
+ }
+ }
+
+ lradc->chan0_keycode = keycode;
+ input_report_key(lradc->input, lradc->chan0_keycode, 1);
+ }
+
+ input_sync(lradc->input);
+
+ writel(ints, lradc->base + LRADC_INTS);
+
+ return IRQ_HANDLED;
+}
+
+static int sun4i_lradc_open(struct input_dev *dev)
+{
+ struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
+ int error;
+
+ error = regulator_enable(lradc->vref_supply);
+ if (error)
+ return error;
+
+ /* lradc Vref internally is divided by 2/3 */
+ lradc->vref = regulator_get_voltage(lradc->vref_supply) * 2 / 3;
+
+ /*
+ * Set sample time to 4 ms / 250 Hz. Wait 2 * 4 ms for key to
+ * stabilize on press, wait (1 + 1) * 4 ms for key release
+ */
+ writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
+ SAMPLE_RATE(0) | ENABLE(1), lradc->base + LRADC_CTRL);
+
+ writel(CHAN0_KEYUP_IRQ | CHAN0_KEYDOWN_IRQ, lradc->base + LRADC_INTC);
+
+ return 0;
+}
+
+static void sun4i_lradc_close(struct input_dev *dev)
+{
+ struct sun4i_lradc_data *lradc = input_get_drvdata(dev);
+
+ /* Disable lradc, leave other settings unchanged */
+ writel(FIRST_CONVERT_DLY(2) | LEVELA_B_CNT(1) | HOLD_EN(1) |
+ SAMPLE_RATE(2), lradc->base + LRADC_CTRL);
+ writel(0, lradc->base + LRADC_INTC);
+
+ regulator_disable(lradc->vref_supply);
+}
+
+static int sun4i_lradc_load_dt_keymap(struct device *dev,
+ struct sun4i_lradc_data *lradc)
+{
+ struct device_node *np, *pp;
+ int i;
+ int error;
+
+ np = dev->of_node;
+ if (!np)
+ return -EINVAL;
+
+ lradc->chan0_map_count = of_get_child_count(np);
+ if (lradc->chan0_map_count == 0) {
+ dev_err(dev, "keymap is missing in device tree\n");
+ return -EINVAL;
+ }
+
+ lradc->chan0_map = devm_kmalloc_array(dev, lradc->chan0_map_count,
+ sizeof(struct sun4i_lradc_keymap),
+ GFP_KERNEL);
+ if (!lradc->chan0_map)
+ return -ENOMEM;
+
+ i = 0;
+ for_each_child_of_node(np, pp) {
+ struct sun4i_lradc_keymap *map = &lradc->chan0_map[i];
+ u32 channel;
+
+ error = of_property_read_u32(pp, "channel", &channel);
+ if (error || channel != 0) {
+ dev_err(dev, "%s: Inval channel prop\n", pp->name);
+ return -EINVAL;
+ }
+
+ error = of_property_read_u32(pp, "voltage", &map->voltage);
+ if (error) {
+ dev_err(dev, "%s: Inval voltage prop\n", pp->name);
+ return -EINVAL;
+ }
+
+ error = of_property_read_u32(pp, "linux,code", &map->keycode);
+ if (error) {
+ dev_err(dev, "%s: Inval linux,code prop\n", pp->name);
+ return -EINVAL;
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+static int sun4i_lradc_probe(struct platform_device *pdev)
+{
+ struct sun4i_lradc_data *lradc;
+ struct device *dev = &pdev->dev;
+ int i;
+ int error;
+
+ lradc = devm_kzalloc(dev, sizeof(struct sun4i_lradc_data), GFP_KERNEL);
+ if (!lradc)
+ return -ENOMEM;
+
+ error = sun4i_lradc_load_dt_keymap(dev, lradc);
+ if (error)
+ return error;
+
+ lradc->vref_supply = devm_regulator_get(dev, "vref");
+ if (IS_ERR(lradc->vref_supply))
+ return PTR_ERR(lradc->vref_supply);
+
+ lradc->dev = dev;
+ lradc->input = devm_input_allocate_device(dev);
+ if (!lradc->input)
+ return -ENOMEM;
+
+ lradc->input->name = pdev->name;
+ lradc->input->phys = "sun4i_lradc/input0";
+ lradc->input->open = sun4i_lradc_open;
+ lradc->input->close = sun4i_lradc_close;
+ lradc->input->id.bustype = BUS_HOST;
+ lradc->input->id.vendor = 0x0001;
+ lradc->input->id.product = 0x0001;
+ lradc->input->id.version = 0x0100;
+
+ __set_bit(EV_KEY, lradc->input->evbit);
+ for (i = 0; i < lradc->chan0_map_count; i++)
+ __set_bit(lradc->chan0_map[i].keycode, lradc->input->keybit);
+
+ input_set_drvdata(lradc->input, lradc);
+
+ lradc->base = devm_ioremap_resource(dev,
+ platform_get_resource(pdev, IORESOURCE_MEM, 0));
+ if (IS_ERR(lradc->base))
+ return PTR_ERR(lradc->base);
+
+ error = devm_request_irq(dev, platform_get_irq(pdev, 0),
+ sun4i_lradc_irq, 0,
+ "sun4i-a10-lradc-keys", lradc);
+ if (error)
+ return error;
+
+ error = input_register_device(lradc->input);
+ if (error)
+ return error;
+
+ platform_set_drvdata(pdev, lradc);
+ return 0;
+}
+
+static const struct of_device_id sun4i_lradc_of_match[] = {
+ { .compatible = "allwinner,sun4i-a10-lradc-keys", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, sun4i_lradc_of_match);
+
+static struct platform_driver sun4i_lradc_driver = {
+ .driver = {
+ .name = "sun4i-a10-lradc-keys",
+ .of_match_table = of_match_ptr(sun4i_lradc_of_match),
+ },
+ .probe = sun4i_lradc_probe,
+};
+
+module_platform_driver(sun4i_lradc_driver);
+
+MODULE_DESCRIPTION("Allwinner sun4i low res adc attached tablet keys driver");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/Kconfig b/drivers/input/misc/Kconfig
index 23297ab6163f..6deb8dae3205 100644
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -93,6 +93,16 @@ config INPUT_BMA150
To compile this driver as a module, choose M here: the
module will be called bma150.
+config INPUT_E3X0_BUTTON
+ tristate "NI Ettus Research USRP E3x0 Button support."
+ default n
+ help
+ Say Y here to enable support for the NI Ettus Research
+ USRP E3x0 Button.
+
+ To compile this driver as a module, choose M here: the
+ module will be called e3x0_button.
+
config INPUT_PCSPKR
tristate "PC Speaker support"
depends on PCSPKR_PLATFORM
@@ -394,6 +404,18 @@ config INPUT_CM109
To compile this driver as a module, choose M here: the module will be
called cm109.
+config INPUT_REGULATOR_HAPTIC
+ tristate "Regulator haptics support"
+ depends on REGULATOR
+ select INPUT_FF_MEMLESS
+ help
+ This option enables device driver support for the haptic controlled
+ by a regulator. This driver supports ff-memless interface
+ from input framework.
+
+ To compile this driver as a module, choose M here: the
+ module will be called regulator-haptic.
+
config INPUT_RETU_PWRBUTTON
tristate "Retu Power button Driver"
depends on MFD_RETU
@@ -404,6 +426,27 @@ config INPUT_RETU_PWRBUTTON
To compile this driver as a module, choose M here. The module will
be called retu-pwrbutton.
+config INPUT_TPS65218_PWRBUTTON
+ tristate "TPS65218 Power button driver"
+ depends on MFD_TPS65218
+ help
+ Say Y here if you want to enable power buttong reporting for
+ the TPS65218 Power Management IC device.
+
+ To compile this driver as a module, choose M here. The module will
+ be called tps65218-pwrbutton.
+
+config INPUT_AXP20X_PEK
+ tristate "X-Powers AXP20X power button driver"
+ depends on MFD_AXP20X
+ help
+ Say Y here if you want to enable power key reporting via the
+ AXP20X PMIC.
+
+ To compile this driver as a module, choose M here. The module will
+ be called axp20x-pek.
+
+
config INPUT_TWL4030_PWRBUTTON
tristate "TWL4030 Power button Driver"
depends on TWL4030_CORE
diff --git a/drivers/input/misc/Makefile b/drivers/input/misc/Makefile
index 19c760361f80..403a1a54a76c 100644
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_INPUT_COBALT_BTNS) += cobalt_btns.o
obj-$(CONFIG_INPUT_DA9052_ONKEY) += da9052_onkey.o
obj-$(CONFIG_INPUT_DA9055_ONKEY) += da9055_onkey.o
obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o
+obj-$(CONFIG_INPUT_E3X0_BUTTON) += e3x0-button.o
obj-$(CONFIG_INPUT_DRV260X_HAPTICS) += drv260x.o
obj-$(CONFIG_INPUT_DRV2667_HAPTICS) += drv2667.o
obj-$(CONFIG_INPUT_GP2A) += gp2ap002a00f.o
@@ -53,12 +54,15 @@ obj-$(CONFIG_INPUT_PMIC8XXX_PWRKEY) += pmic8xxx-pwrkey.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_PWM_BEEPER) += pwm-beeper.o
obj-$(CONFIG_INPUT_RB532_BUTTON) += rb532_button.o
+obj-$(CONFIG_INPUT_REGULATOR_HAPTIC) += regulator-haptic.o
obj-$(CONFIG_INPUT_RETU_PWRBUTTON) += retu-pwrbutton.o
+obj-$(CONFIG_INPUT_AXP20X_PEK) += axp20x-pek.o
obj-$(CONFIG_INPUT_GPIO_ROTARY_ENCODER) += rotary_encoder.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
obj-$(CONFIG_INPUT_SIRFSOC_ONKEY) += sirfsoc-onkey.o
obj-$(CONFIG_INPUT_SOC_BUTTON_ARRAY) += soc_button_array.o
obj-$(CONFIG_INPUT_SPARCSPKR) += sparcspkr.o
+obj-$(CONFIG_INPUT_TPS65218_PWRBUTTON) += tps65218-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_PWRBUTTON) += twl4030-pwrbutton.o
obj-$(CONFIG_INPUT_TWL4030_VIBRA) += twl4030-vibra.o
obj-$(CONFIG_INPUT_TWL6040_VIBRA) += twl6040-vibra.o
diff --git a/drivers/input/misc/axp20x-pek.c b/drivers/input/misc/axp20x-pek.c
new file mode 100644
index 000000000000..f1c844739cd7
--- /dev/null
+++ b/drivers/input/misc/axp20x-pek.c
@@ -0,0 +1,290 @@
+/*
+ * axp20x power button driver.
+ *
+ * Copyright (C) 2013 Carlo Caione <carlo@caione.org>
+ *
+ * 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/errno.h>
+#include <linux/irq.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define AXP20X_PEK_STARTUP_MASK (0xc0)
+#define AXP20X_PEK_SHUTDOWN_MASK (0x03)
+
+struct axp20x_pek {
+ struct axp20x_dev *axp20x;
+ struct input_dev *input;
+ int irq_dbr;
+ int irq_dbf;
+};
+
+struct axp20x_time {
+ unsigned int time;
+ unsigned int idx;
+};
+
+static const struct axp20x_time startup_time[] = {
+ { .time = 128, .idx = 0 },
+ { .time = 1000, .idx = 2 },
+ { .time = 3000, .idx = 1 },
+ { .time = 2000, .idx = 3 },
+};
+
+static const struct axp20x_time shutdown_time[] = {
+ { .time = 4000, .idx = 0 },
+ { .time = 6000, .idx = 1 },
+ { .time = 8000, .idx = 2 },
+ { .time = 10000, .idx = 3 },
+};
+
+struct axp20x_pek_ext_attr {
+ const struct axp20x_time *p_time;
+ unsigned int mask;
+};
+
+static struct axp20x_pek_ext_attr axp20x_pek_startup_ext_attr = {
+ .p_time = startup_time,
+ .mask = AXP20X_PEK_STARTUP_MASK,
+};
+
+static struct axp20x_pek_ext_attr axp20x_pek_shutdown_ext_attr = {
+ .p_time = shutdown_time,
+ .mask = AXP20X_PEK_SHUTDOWN_MASK,
+};
+
+static struct axp20x_pek_ext_attr *get_axp_ext_attr(struct device_attribute *attr)
+{
+ return container_of(attr, struct dev_ext_attribute, attr)->var;
+}
+
+static ssize_t axp20x_show_ext_attr(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
+ struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
+ unsigned int val;
+ int ret, i;
+
+ ret = regmap_read(axp20x_pek->axp20x->regmap, AXP20X_PEK_KEY, &val);
+ if (ret != 0)
+ return ret;
+
+ val &= axp20x_ea->mask;
+ val >>= ffs(axp20x_ea->mask) - 1;
+
+ for (i = 0; i < 4; i++)
+ if (val == axp20x_ea->p_time[i].idx)
+ val = axp20x_ea->p_time[i].time;
+
+ return sprintf(buf, "%u\n", val);
+}
+
+static ssize_t axp20x_store_ext_attr(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct axp20x_pek *axp20x_pek = dev_get_drvdata(dev);
+ struct axp20x_pek_ext_attr *axp20x_ea = get_axp_ext_attr(attr);
+ char val_str[20];
+ size_t len;
+ int ret, i;
+ unsigned int val, idx = 0;
+ unsigned int best_err = UINT_MAX;
+
+ val_str[sizeof(val_str) - 1] = '\0';
+ strncpy(val_str, buf, sizeof(val_str) - 1);
+ len = strlen(val_str);
+
+ if (len && val_str[len - 1] == '\n')
+ val_str[len - 1] = '\0';
+
+ ret = kstrtouint(val_str, 10, &val);
+ if (ret)
+ return ret;
+
+ for (i = 3; i >= 0; i--) {
+ unsigned int err;
+
+ err = abs(axp20x_ea->p_time[i].time - val);
+ if (err < best_err) {
+ best_err = err;
+ idx = axp20x_ea->p_time[i].idx;
+ }
+
+ if (!err)
+ break;
+ }
+
+ idx <<= ffs(axp20x_ea->mask) - 1;
+ ret = regmap_update_bits(axp20x_pek->axp20x->regmap,
+ AXP20X_PEK_KEY,
+ axp20x_ea->mask, idx);
+ if (ret != 0)
+ return -EINVAL;
+
+ return count;
+}
+
+static struct dev_ext_attribute axp20x_dev_attr_startup = {
+ .attr = __ATTR(startup, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
+ .var = &axp20x_pek_startup_ext_attr,
+};
+
+static struct dev_ext_attribute axp20x_dev_attr_shutdown = {
+ .attr = __ATTR(shutdown, 0644, axp20x_show_ext_attr, axp20x_store_ext_attr),
+ .var = &axp20x_pek_shutdown_ext_attr,
+};
+
+static struct attribute *axp20x_attributes[] = {
+ &axp20x_dev_attr_startup.attr.attr,
+ &axp20x_dev_attr_shutdown.attr.attr,
+ NULL,
+};
+
+static const struct attribute_group axp20x_attribute_group = {
+ .attrs = axp20x_attributes,
+};
+
+static irqreturn_t axp20x_pek_irq(int irq, void *pwr)
+{
+ struct input_dev *idev = pwr;
+ struct axp20x_pek *axp20x_pek = input_get_drvdata(idev);
+
+ if (irq == axp20x_pek->irq_dbr)
+ input_report_key(idev, KEY_POWER, true);
+ else if (irq == axp20x_pek->irq_dbf)
+ input_report_key(idev, KEY_POWER, false);
+
+ input_sync(idev);
+
+ return IRQ_HANDLED;
+}
+
+static void axp20x_remove_sysfs_group(void *_data)
+{
+ struct device *dev = _data;
+
+ sysfs_remove_group(&dev->kobj, &axp20x_attribute_group);
+}
+
+static int axp20x_pek_probe(struct platform_device *pdev)
+{
+ struct axp20x_pek *axp20x_pek;
+ struct axp20x_dev *axp20x;
+ struct input_dev *idev;
+ int error;
+
+ axp20x_pek = devm_kzalloc(&pdev->dev, sizeof(struct axp20x_pek),
+ GFP_KERNEL);
+ if (!axp20x_pek)
+ return -ENOMEM;
+
+ axp20x_pek->axp20x = dev_get_drvdata(pdev->dev.parent);
+ axp20x = axp20x_pek->axp20x;
+
+ axp20x_pek->irq_dbr = platform_get_irq_byname(pdev, "PEK_DBR");
+ if (axp20x_pek->irq_dbr < 0) {
+ dev_err(&pdev->dev, "No IRQ for PEK_DBR, error=%d\n",
+ axp20x_pek->irq_dbr);
+ return axp20x_pek->irq_dbr;
+ }
+ axp20x_pek->irq_dbr = regmap_irq_get_virq(axp20x->regmap_irqc,
+ axp20x_pek->irq_dbr);
+
+ axp20x_pek->irq_dbf = platform_get_irq_byname(pdev, "PEK_DBF");
+ if (axp20x_pek->irq_dbf < 0) {
+ dev_err(&pdev->dev, "No IRQ for PEK_DBF, error=%d\n",
+ axp20x_pek->irq_dbf);
+ return axp20x_pek->irq_dbf;
+ }
+ axp20x_pek->irq_dbf = regmap_irq_get_virq(axp20x->regmap_irqc,
+ axp20x_pek->irq_dbf);
+
+ axp20x_pek->input = devm_input_allocate_device(&pdev->dev);
+ if (!axp20x_pek->input)
+ return -ENOMEM;
+
+ idev = axp20x_pek->input;
+
+ idev->name = "axp20x-pek";
+ idev->phys = "m1kbd/input2";
+ idev->dev.parent = &pdev->dev;
+
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ input_set_drvdata(idev, axp20x_pek);
+
+ error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbr,
+ axp20x_pek_irq, 0,
+ "axp20x-pek-dbr", idev);
+ if (error < 0) {
+ dev_err(axp20x->dev, "Failed to request dbr IRQ#%d: %d\n",
+ axp20x_pek->irq_dbr, error);
+ return error;
+ }
+
+ error = devm_request_any_context_irq(&pdev->dev, axp20x_pek->irq_dbf,
+ axp20x_pek_irq, 0,
+ "axp20x-pek-dbf", idev);
+ if (error < 0) {
+ dev_err(axp20x->dev, "Failed to request dbf IRQ#%d: %d\n",
+ axp20x_pek->irq_dbf, error);
+ return error;
+ }
+
+ error = sysfs_create_group(&pdev->dev.kobj, &axp20x_attribute_group);
+ if (error) {
+ dev_err(axp20x->dev, "Failed to create sysfs attributes: %d\n",
+ error);
+ return error;
+ }
+
+ error = devm_add_action(&pdev->dev,
+ axp20x_remove_sysfs_group, &pdev->dev);
+ if (error) {
+ axp20x_remove_sysfs_group(&pdev->dev);
+ dev_err(&pdev->dev, "Failed to add sysfs cleanup action: %d\n",
+ error);
+ return error;
+ }
+
+ error = input_register_device(idev);
+ if (error) {
+ dev_err(axp20x->dev, "Can't register input device: %d\n",
+ error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, axp20x_pek);
+
+ return 0;
+}
+
+static struct platform_driver axp20x_pek_driver = {
+ .probe = axp20x_pek_probe,
+ .driver = {
+ .name = "axp20x-pek",
+ },
+};
+module_platform_driver(axp20x_pek_driver);
+
+MODULE_DESCRIPTION("axp20x Power Button");
+MODULE_AUTHOR("Carlo Caione <carlo@caione.org>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/bfin_rotary.c b/drivers/input/misc/bfin_rotary.c
index 3f4351579372..a0fc18fdfc0c 100644
--- a/drivers/input/misc/bfin_rotary.c
+++ b/drivers/input/misc/bfin_rotary.c
@@ -7,29 +7,37 @@
#include <linux/module.h>
#include <linux/interrupt.h>
+#include <linux/io.h>
#include <linux/irq.h>
#include <linux/pm.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/slab.h>
+#include <linux/platform_data/bfin_rotary.h>
#include <asm/portmux.h>
-#include <asm/bfin_rotary.h>
-static const u16 per_cnt[] = {
- P_CNT_CUD,
- P_CNT_CDG,
- P_CNT_CZM,
- 0
-};
+#define CNT_CONFIG_OFF 0 /* CNT Config Offset */
+#define CNT_IMASK_OFF 4 /* CNT Interrupt Mask Offset */
+#define CNT_STATUS_OFF 8 /* CNT Status Offset */
+#define CNT_COMMAND_OFF 12 /* CNT Command Offset */
+#define CNT_DEBOUNCE_OFF 16 /* CNT Debounce Offset */
+#define CNT_COUNTER_OFF 20 /* CNT Counter Offset */
+#define CNT_MAX_OFF 24 /* CNT Maximum Count Offset */
+#define CNT_MIN_OFF 28 /* CNT Minimum Count Offset */
struct bfin_rot {
struct input_dev *input;
+ void __iomem *base;
int irq;
unsigned int up_key;
unsigned int down_key;
unsigned int button_key;
unsigned int rel_code;
+
+ unsigned short mode;
+ unsigned short debounce;
+
unsigned short cnt_config;
unsigned short cnt_imask;
unsigned short cnt_debounce;
@@ -59,18 +67,17 @@ static void report_rotary_event(struct bfin_rot *rotary, int delta)
static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
{
- struct platform_device *pdev = dev_id;
- struct bfin_rot *rotary = platform_get_drvdata(pdev);
+ struct bfin_rot *rotary = dev_id;
int delta;
- switch (bfin_read_CNT_STATUS()) {
+ switch (readw(rotary->base + CNT_STATUS_OFF)) {
case ICII:
break;
case UCII:
case DCII:
- delta = bfin_read_CNT_COUNTER();
+ delta = readl(rotary->base + CNT_COUNTER_OFF);
if (delta)
report_rotary_event(rotary, delta);
break;
@@ -83,16 +90,52 @@ static irqreturn_t bfin_rotary_isr(int irq, void *dev_id)
break;
}
- bfin_write_CNT_COMMAND(W1LCNT_ZERO); /* Clear COUNTER */
- bfin_write_CNT_STATUS(-1); /* Clear STATUS */
+ writew(W1LCNT_ZERO, rotary->base + CNT_COMMAND_OFF); /* Clear COUNTER */
+ writew(-1, rotary->base + CNT_STATUS_OFF); /* Clear STATUS */
return IRQ_HANDLED;
}
+static int bfin_rotary_open(struct input_dev *input)
+{
+ struct bfin_rot *rotary = input_get_drvdata(input);
+ unsigned short val;
+
+ if (rotary->mode & ROT_DEBE)
+ writew(rotary->debounce & DPRESCALE,
+ rotary->base + CNT_DEBOUNCE_OFF);
+
+ writew(rotary->mode & ~CNTE, rotary->base + CNT_CONFIG_OFF);
+
+ val = UCIE | DCIE;
+ if (rotary->button_key)
+ val |= CZMIE;
+ writew(val, rotary->base + CNT_IMASK_OFF);
+
+ writew(rotary->mode | CNTE, rotary->base + CNT_CONFIG_OFF);
+
+ return 0;
+}
+
+static void bfin_rotary_close(struct input_dev *input)
+{
+ struct bfin_rot *rotary = input_get_drvdata(input);
+
+ writew(0, rotary->base + CNT_CONFIG_OFF);
+ writew(0, rotary->base + CNT_IMASK_OFF);
+}
+
+static void bfin_rotary_free_action(void *data)
+{
+ peripheral_free_list(data);
+}
+
static int bfin_rotary_probe(struct platform_device *pdev)
{
- struct bfin_rotary_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ struct device *dev = &pdev->dev;
+ const struct bfin_rotary_platform_data *pdata = dev_get_platdata(dev);
struct bfin_rot *rotary;
+ struct resource *res;
struct input_dev *input;
int error;
@@ -102,18 +145,37 @@ static int bfin_rotary_probe(struct platform_device *pdev)
return -EINVAL;
}
- error = peripheral_request_list(per_cnt, dev_name(&pdev->dev));
- if (error) {
- dev_err(&pdev->dev, "requesting peripherals failed\n");
- return error;
+ if (pdata->pin_list) {
+ error = peripheral_request_list(pdata->pin_list,
+ dev_name(&pdev->dev));
+ if (error) {
+ dev_err(dev, "requesting peripherals failed: %d\n",
+ error);
+ return error;
+ }
+
+ error = devm_add_action(dev, bfin_rotary_free_action,
+ pdata->pin_list);
+ if (error) {
+ dev_err(dev, "setting cleanup action failed: %d\n",
+ error);
+ peripheral_free_list(pdata->pin_list);
+ return error;
+ }
}
- rotary = kzalloc(sizeof(struct bfin_rot), GFP_KERNEL);
- input = input_allocate_device();
- if (!rotary || !input) {
- error = -ENOMEM;
- goto out1;
- }
+ rotary = devm_kzalloc(dev, sizeof(struct bfin_rot), GFP_KERNEL);
+ if (!rotary)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rotary->base = devm_ioremap_resource(dev, res);
+ if (IS_ERR(rotary->base))
+ return PTR_ERR(rotary->base);
+
+ input = devm_input_allocate_device(dev);
+ if (!input)
+ return -ENOMEM;
rotary->input = input;
@@ -122,9 +184,8 @@ static int bfin_rotary_probe(struct platform_device *pdev)
rotary->button_key = pdata->rotary_button_key;
rotary->rel_code = pdata->rotary_rel_code;
- error = rotary->irq = platform_get_irq(pdev, 0);
- if (error < 0)
- goto out1;
+ rotary->mode = pdata->mode;
+ rotary->debounce = pdata->debounce;
input->name = pdev->name;
input->phys = "bfin-rotary/input0";
@@ -137,6 +198,9 @@ static int bfin_rotary_probe(struct platform_device *pdev)
input->id.product = 0x0001;
input->id.version = 0x0100;
+ input->open = bfin_rotary_open;
+ input->close = bfin_rotary_close;
+
if (rotary->up_key) {
__set_bit(EV_KEY, input->evbit);
__set_bit(rotary->up_key, input->keybit);
@@ -151,75 +215,43 @@ static int bfin_rotary_probe(struct platform_device *pdev)
__set_bit(rotary->button_key, input->keybit);
}
- error = request_irq(rotary->irq, bfin_rotary_isr,
- 0, dev_name(&pdev->dev), pdev);
+ /* Quiesce the device before requesting irq */
+ bfin_rotary_close(input);
+
+ rotary->irq = platform_get_irq(pdev, 0);
+ if (rotary->irq < 0) {
+ dev_err(dev, "No rotary IRQ specified\n");
+ return -ENOENT;
+ }
+
+ error = devm_request_irq(dev, rotary->irq, bfin_rotary_isr,
+ 0, dev_name(dev), rotary);
if (error) {
- dev_err(&pdev->dev,
- "unable to claim irq %d; error %d\n",
+ dev_err(dev, "unable to claim irq %d; error %d\n",
rotary->irq, error);
- goto out1;
+ return error;
}
error = input_register_device(input);
if (error) {
- dev_err(&pdev->dev,
- "unable to register input device (%d)\n", error);
- goto out2;
+ dev_err(dev, "unable to register input device (%d)\n", error);
+ return error;
}
- if (pdata->rotary_button_key)
- bfin_write_CNT_IMASK(CZMIE);
-
- if (pdata->mode & ROT_DEBE)
- bfin_write_CNT_DEBOUNCE(pdata->debounce & DPRESCALE);
-
- if (pdata->mode)
- bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() |
- (pdata->mode & ~CNTE));
-
- bfin_write_CNT_IMASK(bfin_read_CNT_IMASK() | UCIE | DCIE);
- bfin_write_CNT_CONFIG(bfin_read_CNT_CONFIG() | CNTE);
-
platform_set_drvdata(pdev, rotary);
device_init_wakeup(&pdev->dev, 1);
return 0;
-
-out2:
- free_irq(rotary->irq, pdev);
-out1:
- input_free_device(input);
- kfree(rotary);
- peripheral_free_list(per_cnt);
-
- return error;
}
-static int bfin_rotary_remove(struct platform_device *pdev)
-{
- struct bfin_rot *rotary = platform_get_drvdata(pdev);
-
- bfin_write_CNT_CONFIG(0);
- bfin_write_CNT_IMASK(0);
-
- free_irq(rotary->irq, pdev);
- input_unregister_device(rotary->input);
- peripheral_free_list(per_cnt);
-
- kfree(rotary);
-
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int bfin_rotary_suspend(struct device *dev)
+static int __maybe_unused bfin_rotary_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct bfin_rot *rotary = platform_get_drvdata(pdev);
- rotary->cnt_config = bfin_read_CNT_CONFIG();
- rotary->cnt_imask = bfin_read_CNT_IMASK();
- rotary->cnt_debounce = bfin_read_CNT_DEBOUNCE();
+ rotary->cnt_config = readw(rotary->base + CNT_CONFIG_OFF);
+ rotary->cnt_imask = readw(rotary->base + CNT_IMASK_OFF);
+ rotary->cnt_debounce = readw(rotary->base + CNT_DEBOUNCE_OFF);
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(rotary->irq);
@@ -227,38 +259,32 @@ static int bfin_rotary_suspend(struct device *dev)
return 0;
}
-static int bfin_rotary_resume(struct device *dev)
+static int __maybe_unused bfin_rotary_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct bfin_rot *rotary = platform_get_drvdata(pdev);
- bfin_write_CNT_DEBOUNCE(rotary->cnt_debounce);
- bfin_write_CNT_IMASK(rotary->cnt_imask);
- bfin_write_CNT_CONFIG(rotary->cnt_config & ~CNTE);
+ writew(rotary->cnt_debounce, rotary->base + CNT_DEBOUNCE_OFF);
+ writew(rotary->cnt_imask, rotary->base + CNT_IMASK_OFF);
+ writew(rotary->cnt_config & ~CNTE, rotary->base + CNT_CONFIG_OFF);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(rotary->irq);
if (rotary->cnt_config & CNTE)
- bfin_write_CNT_CONFIG(rotary->cnt_config);
+ writew(rotary->cnt_config, rotary->base + CNT_CONFIG_OFF);
return 0;
}
-static const struct dev_pm_ops bfin_rotary_pm_ops = {
- .suspend = bfin_rotary_suspend,
- .resume = bfin_rotary_resume,
-};
-#endif
+static SIMPLE_DEV_PM_OPS(bfin_rotary_pm_ops,
+ bfin_rotary_suspend, bfin_rotary_resume);
static struct platform_driver bfin_rotary_device_driver = {
.probe = bfin_rotary_probe,
- .remove = bfin_rotary_remove,
.driver = {
.name = "bfin-rotary",
-#ifdef CONFIG_PM
.pm = &bfin_rotary_pm_ops,
-#endif
},
};
module_platform_driver(bfin_rotary_device_driver);
diff --git a/drivers/input/misc/drv260x.c b/drivers/input/misc/drv260x.c
index a364e109ca7c..599578042ea0 100644
--- a/drivers/input/misc/drv260x.c
+++ b/drivers/input/misc/drv260x.c
@@ -733,7 +733,6 @@ static struct i2c_driver drv260x_driver = {
};
module_i2c_driver(drv260x_driver);
-MODULE_ALIAS("platform:drv260x-haptics");
MODULE_DESCRIPTION("TI DRV260x haptics driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
diff --git a/drivers/input/misc/drv2667.c b/drivers/input/misc/drv2667.c
index a021744e608c..fc0fddf0896a 100644
--- a/drivers/input/misc/drv2667.c
+++ b/drivers/input/misc/drv2667.c
@@ -492,7 +492,6 @@ static struct i2c_driver drv2667_driver = {
};
module_i2c_driver(drv2667_driver);
-MODULE_ALIAS("platform:drv2667-haptics");
MODULE_DESCRIPTION("TI DRV2667 haptics driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Dan Murphy <dmurphy@ti.com>");
diff --git a/drivers/input/misc/e3x0-button.c b/drivers/input/misc/e3x0-button.c
new file mode 100644
index 000000000000..13bfca8a7b16
--- /dev/null
+++ b/drivers/input/misc/e3x0-button.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2014, National Instruments Corp. All rights reserved.
+ *
+ * Driver for NI Ettus Research USRP E3x0 Button Driver
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; 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/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+#include <linux/slab.h>
+
+static irqreturn_t e3x0_button_release_handler(int irq, void *data)
+{
+ struct input_dev *idev = data;
+
+ input_report_key(idev, KEY_POWER, 0);
+ input_sync(idev);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t e3x0_button_press_handler(int irq, void *data)
+{
+ struct input_dev *idev = data;
+
+ input_report_key(idev, KEY_POWER, 1);
+ pm_wakeup_event(idev->dev.parent, 0);
+ input_sync(idev);
+
+ return IRQ_HANDLED;
+}
+
+static int __maybe_unused e3x0_button_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (device_may_wakeup(dev))
+ enable_irq_wake(platform_get_irq_byname(pdev, "press"));
+
+ return 0;
+}
+
+static int __maybe_unused e3x0_button_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+
+ if (device_may_wakeup(dev))
+ disable_irq_wake(platform_get_irq_byname(pdev, "press"));
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(e3x0_button_pm_ops,
+ e3x0_button_suspend, e3x0_button_resume);
+
+static int e3x0_button_probe(struct platform_device *pdev)
+{
+ struct input_dev *input;
+ int irq_press, irq_release;
+ int error;
+
+ irq_press = platform_get_irq_byname(pdev, "press");
+ if (irq_press < 0) {
+ dev_err(&pdev->dev, "No IRQ for 'press', error=%d\n",
+ irq_press);
+ return irq_press;
+ }
+
+ irq_release = platform_get_irq_byname(pdev, "release");
+ if (irq_release < 0) {
+ dev_err(&pdev->dev, "No IRQ for 'release', error=%d\n",
+ irq_release);
+ return irq_release;
+ }
+
+ input = devm_input_allocate_device(&pdev->dev);
+ if (!input)
+ return -ENOMEM;
+
+ input->name = "NI Ettus Research USRP E3x0 Button Driver";
+ input->phys = "e3x0_button/input0";
+ input->dev.parent = &pdev->dev;
+
+ input_set_capability(input, EV_KEY, KEY_POWER);
+
+ error = devm_request_irq(&pdev->dev, irq_press,
+ e3x0_button_press_handler, 0,
+ "e3x0-button", input);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to request 'press' IRQ#%d: %d\n",
+ irq_press, error);
+ return error;
+ }
+
+ error = devm_request_irq(&pdev->dev, irq_release,
+ e3x0_button_release_handler, 0,
+ "e3x0-button", input);
+ if (error) {
+ dev_err(&pdev->dev, "Failed to request 'release' IRQ#%d: %d\n",
+ irq_release, error);
+ return error;
+ }
+
+ error = input_register_device(input);
+ if (error) {
+ dev_err(&pdev->dev, "Can't register input device: %d\n", error);
+ return error;
+ }
+
+ platform_set_drvdata(pdev, input);
+ device_init_wakeup(&pdev->dev, 1);
+ return 0;
+}
+
+static int e3x0_button_remove(struct platform_device *pdev)
+{
+ device_init_wakeup(&pdev->dev, 0);
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id e3x0_button_match[] = {
+ { .compatible = "ettus,e3x0-button", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, e3x0_button_match);
+#endif
+
+static struct platform_driver e3x0_button_driver = {
+ .driver = {
+ .name = "e3x0-button",
+ .of_match_table = of_match_ptr(e3x0_button_match),
+ .pm = &e3x0_button_pm_ops,
+ },
+ .probe = e3x0_button_probe,
+ .remove = e3x0_button_remove,
+};
+
+module_platform_driver(e3x0_button_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Moritz Fischer <moritz.fischer@ettus.com>");
+MODULE_DESCRIPTION("NI Ettus Research USRP E3x0 Button driver");
+MODULE_ALIAS("platform:e3x0-button");
diff --git a/drivers/input/misc/regulator-haptic.c b/drivers/input/misc/regulator-haptic.c
new file mode 100644
index 000000000000..132eb914ea3e
--- /dev/null
+++ b/drivers/input/misc/regulator-haptic.c
@@ -0,0 +1,266 @@
+/*
+ * Regulator haptic driver
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ * Author: Hyunhee Kim <hyunhee.kim@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_data/regulator-haptic.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+
+#define MAX_MAGNITUDE_SHIFT 16
+
+struct regulator_haptic {
+ struct device *dev;
+ struct input_dev *input_dev;
+ struct regulator *regulator;
+
+ struct work_struct work;
+ struct mutex mutex;
+
+ bool active;
+ bool suspended;
+
+ unsigned int max_volt;
+ unsigned int min_volt;
+ unsigned int magnitude;
+};
+
+static int regulator_haptic_toggle(struct regulator_haptic *haptic, bool on)
+{
+ int error;
+
+ if (haptic->active != on) {
+
+ error = on ? regulator_enable(haptic->regulator) :
+ regulator_disable(haptic->regulator);
+ if (error) {
+ dev_err(haptic->dev,
+ "failed to switch regulator %s: %d\n",
+ on ? "on" : "off", error);
+ return error;
+ }
+
+ haptic->active = on;
+ }
+
+ return 0;
+}
+
+static int regulator_haptic_set_voltage(struct regulator_haptic *haptic,
+ unsigned int magnitude)
+{
+ u64 volt_mag_multi;
+ unsigned int intensity;
+ int error;
+
+ volt_mag_multi = (u64)(haptic->max_volt - haptic->min_volt) * magnitude;
+ intensity = (unsigned int)(volt_mag_multi >> MAX_MAGNITUDE_SHIFT);
+
+ error = regulator_set_voltage(haptic->regulator,
+ intensity + haptic->min_volt,
+ haptic->max_volt);
+ if (error) {
+ dev_err(haptic->dev, "cannot set regulator voltage to %d: %d\n",
+ intensity + haptic->min_volt, error);
+ return error;
+ }
+
+ regulator_haptic_toggle(haptic, !!magnitude);
+
+ return 0;
+}
+
+static void regulator_haptic_work(struct work_struct *work)
+{
+ struct regulator_haptic *haptic = container_of(work,
+ struct regulator_haptic, work);
+
+ mutex_lock(&haptic->mutex);
+
+ if (!haptic->suspended)
+ regulator_haptic_set_voltage(haptic, haptic->magnitude);
+
+ mutex_unlock(&haptic->mutex);
+}
+
+static int regulator_haptic_play_effect(struct input_dev *input, void *data,
+ struct ff_effect *effect)
+{
+ struct regulator_haptic *haptic = input_get_drvdata(input);
+
+ haptic->magnitude = effect->u.rumble.strong_magnitude;
+ if (!haptic->magnitude)
+ haptic->magnitude = effect->u.rumble.weak_magnitude;
+
+ schedule_work(&haptic->work);
+
+ return 0;
+}
+
+static void regulator_haptic_close(struct input_dev *input)
+{
+ struct regulator_haptic *haptic = input_get_drvdata(input);
+
+ cancel_work_sync(&haptic->work);
+ regulator_haptic_set_voltage(haptic, 0);
+}
+
+static int __maybe_unused
+regulator_haptic_parse_dt(struct device *dev, struct regulator_haptic *haptic)
+{
+ struct device_node *node;
+ int error;
+
+ node = dev->of_node;
+ if(!node) {
+ dev_err(dev, "Missing dveice tree data\n");
+ return -EINVAL;
+ }
+
+ error = of_property_read_u32(node, "max-microvolt", &haptic->max_volt);
+ if (error) {
+ dev_err(dev, "cannot parse max-microvolt\n");
+ return error;
+ }
+
+ error = of_property_read_u32(node, "min-microvolt", &haptic->min_volt);
+ if (error) {
+ dev_err(dev, "cannot parse min-microvolt\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int regulator_haptic_probe(struct platform_device *pdev)
+{
+ const struct regulator_haptic_data *pdata = dev_get_platdata(&pdev->dev);
+ struct regulator_haptic *haptic;
+ struct input_dev *input_dev;
+ int error;
+
+ haptic = devm_kzalloc(&pdev->dev, sizeof(*haptic), GFP_KERNEL);
+ if (!haptic)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, haptic);
+ haptic->dev = &pdev->dev;
+ mutex_init(&haptic->mutex);
+ INIT_WORK(&haptic->work, regulator_haptic_work);
+
+ if (pdata) {
+ haptic->max_volt = pdata->max_volt;
+ haptic->min_volt = pdata->min_volt;
+ } else if (IS_ENABLED(CONFIG_OF)) {
+ error = regulator_haptic_parse_dt(&pdev->dev, haptic);
+ if (error)
+ return error;
+ } else {
+ dev_err(&pdev->dev, "Missing platform data\n");
+ return -EINVAL;
+ }
+
+ haptic->regulator = devm_regulator_get_exclusive(&pdev->dev, "haptic");
+ if (IS_ERR(haptic->regulator)) {
+ dev_err(&pdev->dev, "failed to get regulator\n");
+ return PTR_ERR(haptic->regulator);
+ }
+
+ input_dev = devm_input_allocate_device(&pdev->dev);
+ if (!input_dev)
+ return -ENOMEM;
+
+ haptic->input_dev = input_dev;
+ haptic->input_dev->name = "regulator-haptic";
+ haptic->input_dev->dev.parent = &pdev->dev;
+ haptic->input_dev->close = regulator_haptic_close;
+ input_set_drvdata(haptic->input_dev, haptic);
+ input_set_capability(haptic->input_dev, EV_FF, FF_RUMBLE);
+
+ error = input_ff_create_memless(input_dev, NULL,
+ regulator_haptic_play_effect);
+ if (error) {
+ dev_err(&pdev->dev, "failed to create force-feedback\n");
+ return error;
+ }
+
+ error = input_register_device(haptic->input_dev);
+ if (error) {
+ dev_err(&pdev->dev, "failed to register input device\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static int __maybe_unused regulator_haptic_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct regulator_haptic *haptic = platform_get_drvdata(pdev);
+ int error;
+
+ error = mutex_lock_interruptible(&haptic->mutex);
+ if (error)
+ return error;
+
+ regulator_haptic_set_voltage(haptic, 0);
+
+ haptic->suspended = true;
+
+ mutex_unlock(&haptic->mutex);
+
+ return 0;
+}
+
+static int __maybe_unused regulator_haptic_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct regulator_haptic *haptic = platform_get_drvdata(pdev);
+ unsigned int magnitude;
+
+ mutex_lock(&haptic->mutex);
+
+ haptic->suspended = false;
+
+ magnitude = ACCESS_ONCE(haptic->magnitude);
+ if (magnitude)
+ regulator_haptic_set_voltage(haptic, magnitude);
+
+ mutex_unlock(&haptic->mutex);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(regulator_haptic_pm_ops,
+ regulator_haptic_suspend, regulator_haptic_resume);
+
+static struct of_device_id regulator_haptic_dt_match[] = {
+ { .compatible = "regulator-haptic" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver regulator_haptic_driver = {
+ .probe = regulator_haptic_probe,
+ .driver = {
+ .name = "regulator-haptic",
+ .of_match_table = regulator_haptic_dt_match,
+ .pm = &regulator_haptic_pm_ops,
+ },
+};
+module_platform_driver(regulator_haptic_driver);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_AUTHOR("Hyunhee Kim <hyunhee.kim@samsung.com>");
+MODULE_DESCRIPTION("Regulator haptic driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/input/misc/soc_button_array.c b/drivers/input/misc/soc_button_array.c
index 79cc0f79896f..e8e010a85484 100644
--- a/drivers/input/misc/soc_button_array.c
+++ b/drivers/input/misc/soc_button_array.c
@@ -195,7 +195,7 @@ static int soc_button_probe(struct platform_device *pdev)
static struct soc_button_info soc_button_PNP0C40[] = {
{ "power", 0, EV_KEY, KEY_POWER, false, true },
- { "home", 1, EV_KEY, KEY_HOME, false, true },
+ { "home", 1, EV_KEY, KEY_LEFTMETA, false, true },
{ "volume_up", 2, EV_KEY, KEY_VOLUMEUP, true, false },
{ "volume_down", 3, EV_KEY, KEY_VOLUMEDOWN, true, false },
{ "rotation_lock", 4, EV_SW, SW_ROTATE_LOCK, false, false },
diff --git a/drivers/input/misc/tps65218-pwrbutton.c b/drivers/input/misc/tps65218-pwrbutton.c
new file mode 100644
index 000000000000..54508dec4eb3
--- /dev/null
+++ b/drivers/input/misc/tps65218-pwrbutton.c
@@ -0,0 +1,126 @@
+/*
+ * Texas Instruments' TPS65218 Power Button Input Driver
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ * Author: Felipe Balbi <balbi@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tps65218.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+struct tps65218_pwrbutton {
+ struct device *dev;
+ struct tps65218 *tps;
+ struct input_dev *idev;
+};
+
+static irqreturn_t tps65218_pwr_irq(int irq, void *_pwr)
+{
+ struct tps65218_pwrbutton *pwr = _pwr;
+ unsigned int reg;
+ int error;
+
+ error = tps65218_reg_read(pwr->tps, TPS65218_REG_STATUS, &reg);
+ if (error) {
+ dev_err(pwr->dev, "can't read register: %d\n", error);
+ goto out;
+ }
+
+ if (reg & TPS65218_STATUS_PB_STATE) {
+ input_report_key(pwr->idev, KEY_POWER, 1);
+ pm_wakeup_event(pwr->dev, 0);
+ } else {
+ input_report_key(pwr->idev, KEY_POWER, 0);
+ }
+
+ input_sync(pwr->idev);
+
+out:
+ return IRQ_HANDLED;
+}
+
+static int tps65218_pwron_probe(struct platform_device *pdev)
+{
+ struct tps65218 *tps = dev_get_drvdata(pdev->dev.parent);
+ struct device *dev = &pdev->dev;
+ struct tps65218_pwrbutton *pwr;
+ struct input_dev *idev;
+ int error;
+ int irq;
+
+ pwr = devm_kzalloc(dev, sizeof(*pwr), GFP_KERNEL);
+ if (!pwr)
+ return -ENOMEM;
+
+ idev = devm_input_allocate_device(dev);
+ if (!idev)
+ return -ENOMEM;
+
+ idev->name = "tps65218_pwrbutton";
+ idev->phys = "tps65218_pwrbutton/input0";
+ idev->dev.parent = dev;
+ idev->id.bustype = BUS_I2C;
+
+ input_set_capability(idev, EV_KEY, KEY_POWER);
+
+ pwr->tps = tps;
+ pwr->dev = dev;
+ pwr->idev = idev;
+ platform_set_drvdata(pdev, pwr);
+ device_init_wakeup(dev, true);
+
+ irq = platform_get_irq(pdev, 0);
+ error = devm_request_threaded_irq(dev, irq, NULL, tps65218_pwr_irq,
+ IRQF_TRIGGER_RISING |
+ IRQF_TRIGGER_FALLING |
+ IRQF_ONESHOT,
+ "tps65218-pwrbutton", pwr);
+ if (error) {
+ dev_err(dev, "failed to request IRQ #%d: %d\n",
+ irq, error);
+ return error;
+ }
+
+ error= input_register_device(idev);
+ if (error) {
+ dev_err(dev, "Can't register power button: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static struct of_device_id of_tps65218_pwr_match[] = {
+ { .compatible = "ti,tps65218-pwrbutton" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, of_tps65218_pwr_match);
+
+static struct platform_driver tps65218_pwron_driver = {
+ .probe = tps65218_pwron_probe,
+ .driver = {
+ .name = "tps65218_pwrbutton",
+ .of_match_table = of_tps65218_pwr_match,
+ },
+};
+module_platform_driver(tps65218_pwron_driver);
+
+MODULE_DESCRIPTION("TPS65218 Power Button");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/input/mouse/Kconfig b/drivers/input/mouse/Kconfig
index d8b46b0f2dbe..4658b5d41dd7 100644
--- a/drivers/input/mouse/Kconfig
+++ b/drivers/input/mouse/Kconfig
@@ -105,19 +105,12 @@ config MOUSE_PS2_ELANTECH
Say Y here if you have an Elantech PS/2 touchpad connected
to your system.
- Note that if you enable this driver you will need an updated
- X.org Synaptics driver that does not require ABS_PRESSURE
- reports from the touchpad (i.e. post 1.5.0 version). You can
- grab a patch for the driver here:
-
- http://userweb.kernel.org/~dtor/synaptics-no-abspressure.patch
-
- If unsure, say N.
-
This driver exposes some configuration registers via sysfs
entries. For further information,
see <file:Documentation/input/elantech.txt>.
+ If unsure, say N.
+
config MOUSE_PS2_SENTELIC
bool "Sentelic Finger Sensing Pad PS/2 protocol extension"
depends on MOUSE_PS2
@@ -146,6 +139,16 @@ config MOUSE_PS2_OLPC
If unsure, say N.
+config MOUSE_PS2_FOCALTECH
+ bool "FocalTech PS/2 mouse protocol extension" if EXPERT
+ default y
+ depends on MOUSE_PS2
+ help
+ Say Y here if you have a FocalTech PS/2 TouchPad connected to
+ your system.
+
+ If unsure, say Y.
+
config MOUSE_SERIAL
tristate "Serial mouse"
select SERIO
@@ -206,6 +209,7 @@ config MOUSE_BCM5974
config MOUSE_CYAPA
tristate "Cypress APA I2C Trackpad support"
depends on I2C
+ select CRC_ITU_T
help
This driver adds support for Cypress All Points Addressable (APA)
I2C Trackpads, including the ones used in 2012 Samsung Chromebooks.
diff --git a/drivers/input/mouse/Makefile b/drivers/input/mouse/Makefile
index 560003dcac37..8a9c98e76d9c 100644
--- a/drivers/input/mouse/Makefile
+++ b/drivers/input/mouse/Makefile
@@ -8,7 +8,7 @@ obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o
-obj-$(CONFIG_MOUSE_CYAPA) += cyapa.o
+obj-$(CONFIG_MOUSE_CYAPA) += cyapatp.o
obj-$(CONFIG_MOUSE_ELAN_I2C) += elan_i2c.o
obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o
@@ -24,6 +24,7 @@ obj-$(CONFIG_MOUSE_SYNAPTICS_I2C) += synaptics_i2c.o
obj-$(CONFIG_MOUSE_SYNAPTICS_USB) += synaptics_usb.o
obj-$(CONFIG_MOUSE_VSXXXAA) += vsxxxaa.o
+cyapatp-objs := cyapa.o cyapa_gen3.o cyapa_gen5.o
psmouse-objs := psmouse-base.o synaptics.o focaltech.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
diff --git a/drivers/input/mouse/alps.c b/drivers/input/mouse/alps.c
index d88d73d83552..d28726a0ef85 100644
--- a/drivers/input/mouse/alps.c
+++ b/drivers/input/mouse/alps.c
@@ -99,36 +99,58 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
#define ALPS_FOUR_BUTTONS 0x40 /* 4 direction button present */
#define ALPS_PS2_INTERLEAVED 0x80 /* 3-byte PS/2 packet interleaved with
6-byte ALPS packet */
-#define ALPS_IS_RUSHMORE 0x100 /* device is a rushmore */
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
static const struct alps_model_info alps_model_data[] = {
- { { 0x32, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Toshiba Salellite Pro M10 */
- { { 0x33, 0x02, 0x0a }, 0x00, ALPS_PROTO_V1, 0x88, 0xf8, 0 }, /* UMAX-530T */
- { { 0x53, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x53, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x60, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 }, /* HP ze1115 */
- { { 0x63, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x02, 0x28 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Fujitsu Siemens S6010 */
- { { 0x63, 0x02, 0x3c }, 0x00, ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL }, /* Toshiba Satellite S2400-103 */
- { { 0x63, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 }, /* NEC Versa L320 */
- { { 0x63, 0x02, 0x64 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x63, 0x03, 0xc8 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D800 */
- { { 0x73, 0x00, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT }, /* ThinkPad R61 8918-5QG */
- { { 0x73, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, 0 },
- { { 0x73, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 }, /* Ahtec Laptop */
- { { 0x20, 0x02, 0x0e }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
- { { 0x22, 0x02, 0x0a }, 0x00, ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
- { { 0x22, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
+ { { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */
+ { { 0x33, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V1, 0x88, 0xf8, 0 } }, /* UMAX-530T */
+ { { 0x53, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x53, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x60, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } }, /* HP ze1115 */
+ { { 0x63, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x63, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x63, 0x02, 0x28 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Fujitsu Siemens S6010 */
+ { { 0x63, 0x02, 0x3c }, 0x00, { ALPS_PROTO_V2, 0x8f, 0x8f, ALPS_WHEEL } }, /* Toshiba Satellite S2400-103 */
+ { { 0x63, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xef, 0xef, ALPS_FW_BK_1 } }, /* NEC Versa L320 */
+ { { 0x63, 0x02, 0x64 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x63, 0x03, 0xc8 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D800 */
+ { { 0x73, 0x00, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_DUALPOINT } }, /* ThinkPad R61 8918-5QG */
+ { { 0x73, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, 0 } },
+ { { 0x73, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_FW_BK_2 } }, /* Ahtec Laptop */
+
+ /*
+ * XXX This entry is suspicious. First byte has zero lower nibble,
+ * which is what a normal mouse would report. Also, the value 0x0e
+ * isn't valid per PS/2 spec.
+ */
+ { { 0x20, 0x02, 0x0e }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },
+
+ { { 0x22, 0x02, 0x0a }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } },
+ { { 0x22, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT } }, /* Dell Latitude D600 */
/* Dell Latitude E5500, E6400, E6500, Precision M4400 */
- { { 0x62, 0x02, 0x14 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED },
- { { 0x73, 0x00, 0x14 }, 0x00, ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT }, /* Dell XT2 */
- { { 0x73, 0x02, 0x50 }, 0x00, ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS }, /* Dell Vostro 1400 */
- { { 0x52, 0x01, 0x14 }, 0x00, ALPS_PROTO_V2, 0xff, 0xff,
- ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED }, /* Toshiba Tecra A11-11L */
- { { 0x73, 0x02, 0x64 }, 0x8a, ALPS_PROTO_V4, 0x8f, 0x8f, 0 },
+ { { 0x62, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } },
+ { { 0x73, 0x00, 0x14 }, 0x00, { ALPS_PROTO_V6, 0xff, 0xff, ALPS_DUALPOINT } }, /* Dell XT2 */
+ { { 0x73, 0x02, 0x50 }, 0x00, { ALPS_PROTO_V2, 0xcf, 0xcf, ALPS_FOUR_BUTTONS } }, /* Dell Vostro 1400 */
+ { { 0x52, 0x01, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xff, 0xff,
+ ALPS_PASS | ALPS_DUALPOINT | ALPS_PS2_INTERLEAVED } }, /* Toshiba Tecra A11-11L */
+ { { 0x73, 0x02, 0x64 }, 0x8a, { ALPS_PROTO_V4, 0x8f, 0x8f, 0 } },
+};
+
+static const struct alps_protocol_info alps_v3_protocol_data = {
+ ALPS_PROTO_V3, 0x8f, 0x8f, ALPS_DUALPOINT
+};
+
+static const struct alps_protocol_info alps_v3_rushmore_data = {
+ ALPS_PROTO_V3_RUSHMORE, 0x8f, 0x8f, ALPS_DUALPOINT
+};
+
+static const struct alps_protocol_info alps_v5_protocol_data = {
+ ALPS_PROTO_V5, 0xc8, 0xd8, 0
+};
+
+static const struct alps_protocol_info alps_v7_protocol_data = {
+ ALPS_PROTO_V7, 0x48, 0x48, ALPS_DUALPOINT
};
static void alps_set_abs_params_st(struct alps_data *priv,
@@ -136,12 +158,6 @@ static void alps_set_abs_params_st(struct alps_data *priv,
static void alps_set_abs_params_mt(struct alps_data *priv,
struct input_dev *dev1);
-/*
- * XXX - this entry is suspicious. First byte has zero lower nibble,
- * which is what a normal mouse would report. Also, the value 0x0e
- * isn't valid per PS/2 spec.
- */
-
/* Packet formats are described in Documentation/input/alps.txt */
static bool alps_is_valid_first_byte(struct alps_data *priv,
@@ -150,8 +166,7 @@ static bool alps_is_valid_first_byte(struct alps_data *priv,
return (data & priv->mask0) == priv->byte0;
}
-static void alps_report_buttons(struct psmouse *psmouse,
- struct input_dev *dev1, struct input_dev *dev2,
+static void alps_report_buttons(struct input_dev *dev1, struct input_dev *dev2,
int left, int right, int middle)
{
struct input_dev *dev;
@@ -161,20 +176,21 @@ static void alps_report_buttons(struct psmouse *psmouse,
* other device (dev2) then this event should be also
* sent through that device.
*/
- dev = test_bit(BTN_LEFT, dev2->key) ? dev2 : dev1;
+ dev = (dev2 && test_bit(BTN_LEFT, dev2->key)) ? dev2 : dev1;
input_report_key(dev, BTN_LEFT, left);
- dev = test_bit(BTN_RIGHT, dev2->key) ? dev2 : dev1;
+ dev = (dev2 && test_bit(BTN_RIGHT, dev2->key)) ? dev2 : dev1;
input_report_key(dev, BTN_RIGHT, right);
- dev = test_bit(BTN_MIDDLE, dev2->key) ? dev2 : dev1;
+ dev = (dev2 && test_bit(BTN_MIDDLE, dev2->key)) ? dev2 : dev1;
input_report_key(dev, BTN_MIDDLE, middle);
/*
* Sync the _other_ device now, we'll do the first
* device later once we report the rest of the events.
*/
- input_sync(dev2);
+ if (dev2)
+ input_sync(dev2);
}
static void alps_process_packet_v1_v2(struct psmouse *psmouse)
@@ -221,13 +237,13 @@ static void alps_process_packet_v1_v2(struct psmouse *psmouse)
input_report_rel(dev2, REL_X, (x > 383 ? (x - 768) : x));
input_report_rel(dev2, REL_Y, -(y > 255 ? (y - 512) : y));
- alps_report_buttons(psmouse, dev2, dev, left, right, middle);
+ alps_report_buttons(dev2, dev, left, right, middle);
input_sync(dev2);
return;
}
- alps_report_buttons(psmouse, dev, dev2, left, right, middle);
+ alps_report_buttons(dev, dev2, left, right, middle);
/* Convert hardware tap to a reasonable Z value */
if (ges && !fin)
@@ -412,7 +428,7 @@ static int alps_process_bitmap(struct alps_data *priv,
(2 * (priv->y_bits - 1));
/* y-bitmap order is reversed, except on rushmore */
- if (!(priv->flags & ALPS_IS_RUSHMORE)) {
+ if (priv->proto_version != ALPS_PROTO_V3_RUSHMORE) {
fields->mt[0].y = priv->y_max - fields->mt[0].y;
fields->mt[1].y = priv->y_max - fields->mt[1].y;
}
@@ -435,7 +451,7 @@ static void alps_report_mt_data(struct psmouse *psmouse, int n)
struct alps_fields *f = &priv->f;
int i, slot[MAX_TOUCHES];
- input_mt_assign_slots(dev, slot, f->mt, n);
+ input_mt_assign_slots(dev, slot, f->mt, n, 0);
for (i = 0; i < n; i++)
alps_set_slot(dev, slot[i], f->mt[i].x, f->mt[i].y);
@@ -475,6 +491,13 @@ static void alps_process_trackstick_packet_v3(struct psmouse *psmouse)
struct input_dev *dev = priv->dev2;
int x, y, z, left, right, middle;
+ /* It should be a DualPoint when received trackstick packet */
+ if (!(priv->flags & ALPS_DUALPOINT)) {
+ psmouse_warn(psmouse,
+ "Rejected trackstick packet from non DualPoint device");
+ return;
+ }
+
/* Sanity check packet */
if (!(packet[0] & 0x40)) {
psmouse_dbg(psmouse, "Bad trackstick packet, discarding\n");
@@ -641,7 +664,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
*/
if (f->is_mp) {
fingers = f->fingers;
- if (priv->proto_version == ALPS_PROTO_V3) {
+ if (priv->proto_version == ALPS_PROTO_V3 ||
+ priv->proto_version == ALPS_PROTO_V3_RUSHMORE) {
if (alps_process_bitmap(priv, f) == 0)
fingers = 0; /* Use st data */
@@ -699,7 +723,8 @@ static void alps_process_touchpad_packet_v3_v5(struct psmouse *psmouse)
alps_report_semi_mt_data(psmouse, fingers);
- if (!(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
+ if ((priv->flags & ALPS_DUALPOINT) &&
+ !(priv->quirks & ALPS_QUIRK_TRACKSTICK_BUTTONS)) {
input_report_key(dev2, BTN_LEFT, f->ts_left);
input_report_key(dev2, BTN_RIGHT, f->ts_right);
input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
@@ -743,8 +768,11 @@ static void alps_process_packet_v6(struct psmouse *psmouse)
*/
if (packet[5] == 0x7F) {
/* It should be a DualPoint when received Trackpoint packet */
- if (!(priv->flags & ALPS_DUALPOINT))
+ if (!(priv->flags & ALPS_DUALPOINT)) {
+ psmouse_warn(psmouse,
+ "Rejected trackstick packet from non DualPoint device");
return;
+ }
/* Trackpoint packet */
x = packet[1] | ((packet[3] & 0x20) << 2);
@@ -881,34 +909,6 @@ static void alps_get_finger_coordinate_v7(struct input_mt_pos *mt,
unsigned char *pkt,
unsigned char pkt_id)
{
- /*
- * packet-fmt b7 b6 b5 b4 b3 b2 b1 b0
- * Byte0 TWO & MULTI L 1 R M 1 Y0-2 Y0-1 Y0-0
- * Byte0 NEW L 1 X1-5 1 1 Y0-2 Y0-1 Y0-0
- * Byte1 Y0-10 Y0-9 Y0-8 Y0-7 Y0-6 Y0-5 Y0-4 Y0-3
- * Byte2 X0-11 1 X0-10 X0-9 X0-8 X0-7 X0-6 X0-5
- * Byte3 X1-11 1 X0-4 X0-3 1 X0-2 X0-1 X0-0
- * Byte4 TWO X1-10 TWO X1-9 X1-8 X1-7 X1-6 X1-5 X1-4
- * Byte4 MULTI X1-10 TWO X1-9 X1-8 X1-7 X1-6 Y1-5 1
- * Byte4 NEW X1-10 TWO X1-9 X1-8 X1-7 X1-6 0 0
- * Byte5 TWO & NEW Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 Y1-5 Y1-4
- * Byte5 MULTI Y1-10 0 Y1-9 Y1-8 Y1-7 Y1-6 F-1 F-0
- * L: Left button
- * R / M: Non-clickpads: Right / Middle button
- * Clickpads: When > 2 fingers are down, and some fingers
- * are in the button area, then the 2 coordinates reported
- * are for fingers outside the button area and these report
- * extra fingers being present in the right / left button
- * area. Note these fingers are not added to the F field!
- * so if a TWO packet is received and R = 1 then there are
- * 3 fingers down, etc.
- * TWO: 1: Two touches present, byte 0/4/5 are in TWO fmt
- * 0: If byte 4 bit 0 is 1, then byte 0/4/5 are in MULTI fmt
- * otherwise byte 0 bit 4 must be set and byte 0/4/5 are
- * in NEW fmt
- * F: Number of fingers - 3, 0 means 3 fingers, 1 means 4 ...
- */
-
mt[0].x = ((pkt[2] & 0x80) << 4);
mt[0].x |= ((pkt[2] & 0x3F) << 5);
mt[0].x |= ((pkt[3] & 0x30) >> 1);
@@ -1026,16 +1026,12 @@ static void alps_process_trackstick_packet_v7(struct psmouse *psmouse)
struct input_dev *dev2 = priv->dev2;
int x, y, z, left, right, middle;
- /*
- * b7 b6 b5 b4 b3 b2 b1 b0
- * Byte0 0 1 0 0 1 0 0 0
- * Byte1 1 1 * * 1 M R L
- * Byte2 X7 1 X5 X4 X3 X2 X1 X0
- * Byte3 Z6 1 Y6 X6 1 Y2 Y1 Y0
- * Byte4 Y7 0 Y5 Y4 Y3 1 1 0
- * Byte5 T&P 0 Z5 Z4 Z3 Z2 Z1 Z0
- * M / R / L: Middle / Right / Left button
- */
+ /* It should be a DualPoint when received trackstick packet */
+ if (!(priv->flags & ALPS_DUALPOINT)) {
+ psmouse_warn(psmouse,
+ "Rejected trackstick packet from non DualPoint device");
+ return;
+ }
x = ((packet[2] & 0xbf)) | ((packet[3] & 0x10) << 2);
y = (packet[3] & 0x07) | (packet[4] & 0xb8) |
@@ -1089,23 +1085,89 @@ static void alps_process_packet_v7(struct psmouse *psmouse)
alps_process_touchpad_packet_v7(psmouse);
}
-static void alps_report_bare_ps2_packet(struct psmouse *psmouse,
+static DEFINE_MUTEX(alps_mutex);
+
+static void alps_register_bare_ps2_mouse(struct work_struct *work)
+{
+ struct alps_data *priv =
+ container_of(work, struct alps_data, dev3_register_work.work);
+ struct psmouse *psmouse = priv->psmouse;
+ struct input_dev *dev3;
+ int error = 0;
+
+ mutex_lock(&alps_mutex);
+
+ if (priv->dev3)
+ goto out;
+
+ dev3 = input_allocate_device();
+ if (!dev3) {
+ psmouse_err(psmouse, "failed to allocate secondary device\n");
+ error = -ENOMEM;
+ goto out;
+ }
+
+ snprintf(priv->phys3, sizeof(priv->phys3), "%s/%s",
+ psmouse->ps2dev.serio->phys,
+ (priv->dev2 ? "input2" : "input1"));
+ dev3->phys = priv->phys3;
+
+ /*
+ * format of input device name is: "protocol vendor name"
+ * see function psmouse_switch_protocol() in psmouse-base.c
+ */
+ dev3->name = "PS/2 ALPS Mouse";
+
+ dev3->id.bustype = BUS_I8042;
+ dev3->id.vendor = 0x0002;
+ dev3->id.product = PSMOUSE_PS2;
+ dev3->id.version = 0x0000;
+ dev3->dev.parent = &psmouse->ps2dev.serio->dev;
+
+ input_set_capability(dev3, EV_REL, REL_X);
+ input_set_capability(dev3, EV_REL, REL_Y);
+ input_set_capability(dev3, EV_KEY, BTN_LEFT);
+ input_set_capability(dev3, EV_KEY, BTN_RIGHT);
+ input_set_capability(dev3, EV_KEY, BTN_MIDDLE);
+
+ __set_bit(INPUT_PROP_POINTER, dev3->propbit);
+
+ error = input_register_device(dev3);
+ if (error) {
+ psmouse_err(psmouse,
+ "failed to register secondary device: %d\n",
+ error);
+ input_free_device(dev3);
+ goto out;
+ }
+
+ priv->dev3 = dev3;
+
+out:
+ /*
+ * Save the error code so that we can detect that we
+ * already tried to create the device.
+ */
+ if (error)
+ priv->dev3 = ERR_PTR(error);
+
+ mutex_unlock(&alps_mutex);
+}
+
+static void alps_report_bare_ps2_packet(struct input_dev *dev,
unsigned char packet[],
bool report_buttons)
{
- struct alps_data *priv = psmouse->private;
- struct input_dev *dev2 = priv->dev2;
-
if (report_buttons)
- alps_report_buttons(psmouse, dev2, psmouse->dev,
+ alps_report_buttons(dev, NULL,
packet[0] & 1, packet[0] & 2, packet[0] & 4);
- input_report_rel(dev2, REL_X,
+ input_report_rel(dev, REL_X,
packet[1] ? packet[1] - ((packet[0] << 4) & 0x100) : 0);
- input_report_rel(dev2, REL_Y,
+ input_report_rel(dev, REL_Y,
packet[2] ? ((packet[0] << 3) & 0x100) - packet[2] : 0);
- input_sync(dev2);
+ input_sync(dev);
}
static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
@@ -1170,8 +1232,8 @@ static psmouse_ret_t alps_handle_interleaved_ps2(struct psmouse *psmouse)
* de-synchronization.
*/
- alps_report_bare_ps2_packet(psmouse, &psmouse->packet[3],
- false);
+ alps_report_bare_ps2_packet(priv->dev2,
+ &psmouse->packet[3], false);
/*
* Continue with the standard ALPS protocol handling,
@@ -1227,9 +1289,18 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
* properly we only do this if the device is fully synchronized.
*/
if (!psmouse->out_of_sync_cnt && (psmouse->packet[0] & 0xc8) == 0x08) {
+
+ /* Register dev3 mouse if we received PS/2 packet first time */
+ if (unlikely(!priv->dev3))
+ psmouse_queue_work(psmouse,
+ &priv->dev3_register_work, 0);
+
if (psmouse->pktcnt == 3) {
- alps_report_bare_ps2_packet(psmouse, psmouse->packet,
- true);
+ /* Once dev3 mouse device is registered report data */
+ if (likely(!IS_ERR_OR_NULL(priv->dev3)))
+ alps_report_bare_ps2_packet(priv->dev3,
+ psmouse->packet,
+ true);
return PSMOUSE_FULL_PACKET;
}
return PSMOUSE_GOOD_DATA;
@@ -1257,7 +1328,7 @@ static psmouse_ret_t alps_process_byte(struct psmouse *psmouse)
psmouse->pktcnt - 1,
psmouse->packet[psmouse->pktcnt - 1]);
- if (priv->proto_version == ALPS_PROTO_V3 &&
+ if (priv->proto_version == ALPS_PROTO_V3_RUSHMORE &&
psmouse->pktcnt == psmouse->pktsize) {
/*
* Some Dell boxes, such as Latitude E6440 or E7440
@@ -1762,7 +1833,7 @@ static int alps_setup_trackstick_v3(struct psmouse *psmouse, int reg_base)
* all.
*/
if (alps_rpt_cmd(psmouse, 0, PSMOUSE_CMD_SETSCALE21, param)) {
- psmouse_warn(psmouse, "trackstick E7 report failed\n");
+ psmouse_warn(psmouse, "Failed to initialize trackstick (E7 report failed)\n");
ret = -ENODEV;
} else {
psmouse_dbg(psmouse, "trackstick E7 report: %3ph\n", param);
@@ -1927,8 +1998,6 @@ static int alps_hw_init_rushmore_v3(struct psmouse *psmouse)
ALPS_REG_BASE_RUSHMORE);
if (reg_val == -EIO)
goto error;
- if (reg_val == -ENODEV)
- priv->flags &= ~ALPS_DUALPOINT;
}
if (alps_enter_command_mode(psmouse) ||
@@ -2144,11 +2213,18 @@ error:
return ret;
}
-static void alps_set_defaults(struct alps_data *priv)
+static int alps_set_protocol(struct psmouse *psmouse,
+ struct alps_data *priv,
+ const struct alps_protocol_info *protocol)
{
- priv->byte0 = 0x8f;
- priv->mask0 = 0x8f;
- priv->flags = ALPS_DUALPOINT;
+ psmouse->private = priv;
+
+ setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
+
+ priv->proto_version = protocol->version;
+ priv->byte0 = protocol->byte0;
+ priv->mask0 = protocol->mask0;
+ priv->flags = protocol->flags;
priv->x_max = 2000;
priv->y_max = 1400;
@@ -2164,6 +2240,7 @@ static void alps_set_defaults(struct alps_data *priv)
priv->x_max = 1023;
priv->y_max = 767;
break;
+
case ALPS_PROTO_V3:
priv->hw_init = alps_hw_init_v3;
priv->process_packet = alps_process_packet_v3;
@@ -2172,6 +2249,23 @@ static void alps_set_defaults(struct alps_data *priv)
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
break;
+
+ case ALPS_PROTO_V3_RUSHMORE:
+ priv->hw_init = alps_hw_init_rushmore_v3;
+ priv->process_packet = alps_process_packet_v3;
+ priv->set_abs_params = alps_set_abs_params_mt;
+ priv->decode_fields = alps_decode_rushmore;
+ priv->nibble_commands = alps_v3_nibble_commands;
+ priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
+ priv->x_bits = 16;
+ priv->y_bits = 12;
+
+ if (alps_probe_trackstick_v3(psmouse,
+ ALPS_REG_BASE_RUSHMORE) < 0)
+ priv->flags &= ~ALPS_DUALPOINT;
+
+ break;
+
case ALPS_PROTO_V4:
priv->hw_init = alps_hw_init_v4;
priv->process_packet = alps_process_packet_v4;
@@ -2179,6 +2273,7 @@ static void alps_set_defaults(struct alps_data *priv)
priv->nibble_commands = alps_v4_nibble_commands;
priv->addr_command = PSMOUSE_CMD_DISABLE;
break;
+
case ALPS_PROTO_V5:
priv->hw_init = alps_hw_init_dolphin_v1;
priv->process_packet = alps_process_touchpad_packet_v3_v5;
@@ -2186,14 +2281,12 @@ static void alps_set_defaults(struct alps_data *priv)
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
- priv->byte0 = 0xc8;
- priv->mask0 = 0xd8;
- priv->flags = 0;
priv->x_max = 1360;
priv->y_max = 660;
priv->x_bits = 23;
priv->y_bits = 12;
break;
+
case ALPS_PROTO_V6:
priv->hw_init = alps_hw_init_v6;
priv->process_packet = alps_process_packet_v6;
@@ -2202,6 +2295,7 @@ static void alps_set_defaults(struct alps_data *priv)
priv->x_max = 2047;
priv->y_max = 1535;
break;
+
case ALPS_PROTO_V7:
priv->hw_init = alps_hw_init_v7;
priv->process_packet = alps_process_packet_v7;
@@ -2209,19 +2303,21 @@ static void alps_set_defaults(struct alps_data *priv)
priv->set_abs_params = alps_set_abs_params_mt;
priv->nibble_commands = alps_v3_nibble_commands;
priv->addr_command = PSMOUSE_CMD_RESET_WRAP;
- priv->x_max = 0xfff;
- priv->y_max = 0x7ff;
- priv->byte0 = 0x48;
- priv->mask0 = 0x48;
+
+ if (alps_dolphin_get_device_area(psmouse, priv))
+ return -EIO;
if (priv->fw_ver[1] != 0xba)
priv->flags |= ALPS_BUTTONPAD;
+
break;
}
+
+ return 0;
}
-static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
- unsigned char *e7, unsigned char *ec)
+static const struct alps_protocol_info *alps_match_table(unsigned char *e7,
+ unsigned char *ec)
{
const struct alps_model_info *model;
int i;
@@ -2233,23 +2329,18 @@ static int alps_match_table(struct psmouse *psmouse, struct alps_data *priv,
(!model->command_mode_resp ||
model->command_mode_resp == ec[2])) {
- priv->proto_version = model->proto_version;
- alps_set_defaults(priv);
-
- priv->flags = model->flags;
- priv->byte0 = model->byte0;
- priv->mask0 = model->mask0;
-
- return 0;
+ return &model->protocol_info;
}
}
- return -EINVAL;
+ return NULL;
}
static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
{
+ const struct alps_protocol_info *protocol;
unsigned char e6[4], e7[4], ec[4];
+ int error;
/*
* First try "E6 report".
@@ -2275,54 +2366,35 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
alps_exit_command_mode(psmouse))
return -EIO;
- /* Save the Firmware version */
- memcpy(priv->fw_ver, ec, 3);
-
- if (alps_match_table(psmouse, priv, e7, ec) == 0) {
- return 0;
- } else if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
- ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
- priv->proto_version = ALPS_PROTO_V5;
- alps_set_defaults(priv);
- if (alps_dolphin_get_device_area(psmouse, priv))
- return -EIO;
- else
- return 0;
- } else if (ec[0] == 0x88 &&
- ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
- priv->proto_version = ALPS_PROTO_V7;
- alps_set_defaults(priv);
-
- return 0;
- } else if (ec[0] == 0x88 && ec[1] == 0x08) {
- priv->proto_version = ALPS_PROTO_V3;
- alps_set_defaults(priv);
-
- priv->hw_init = alps_hw_init_rushmore_v3;
- priv->decode_fields = alps_decode_rushmore;
- priv->x_bits = 16;
- priv->y_bits = 12;
- priv->flags |= ALPS_IS_RUSHMORE;
-
- /* hack to make addr_command, nibble_command available */
- psmouse->private = priv;
-
- if (alps_probe_trackstick_v3(psmouse, ALPS_REG_BASE_RUSHMORE))
- priv->flags &= ~ALPS_DUALPOINT;
-
- return 0;
- } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
- ec[2] >= 0x90 && ec[2] <= 0x9d) {
- priv->proto_version = ALPS_PROTO_V3;
- alps_set_defaults(priv);
-
- return 0;
+ protocol = alps_match_table(e7, ec);
+ if (!protocol) {
+ if (e7[0] == 0x73 && e7[1] == 0x03 && e7[2] == 0x50 &&
+ ec[0] == 0x73 && (ec[1] == 0x01 || ec[1] == 0x02)) {
+ protocol = &alps_v5_protocol_data;
+ } else if (ec[0] == 0x88 &&
+ ((ec[1] & 0xf0) == 0xb0 || (ec[1] & 0xf0) == 0xc0)) {
+ protocol = &alps_v7_protocol_data;
+ } else if (ec[0] == 0x88 && ec[1] == 0x08) {
+ protocol = &alps_v3_rushmore_data;
+ } else if (ec[0] == 0x88 && ec[1] == 0x07 &&
+ ec[2] >= 0x90 && ec[2] <= 0x9d) {
+ protocol = &alps_v3_protocol_data;
+ } else {
+ psmouse_dbg(psmouse,
+ "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
+ return -EINVAL;
+ }
}
- psmouse_dbg(psmouse,
- "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
+ if (priv) {
+ /* Save the Firmware version */
+ memcpy(priv->fw_ver, ec, 3);
+ error = alps_set_protocol(psmouse, priv, protocol);
+ if (error)
+ return error;
+ }
- return -EINVAL;
+ return 0;
}
static int alps_reconnect(struct psmouse *psmouse)
@@ -2343,7 +2415,10 @@ static void alps_disconnect(struct psmouse *psmouse)
psmouse_reset(psmouse);
del_timer_sync(&priv->timer);
- input_unregister_device(priv->dev2);
+ if (priv->dev2)
+ input_unregister_device(priv->dev2);
+ if (!IS_ERR_OR_NULL(priv->dev3))
+ input_unregister_device(priv->dev3);
kfree(priv);
}
@@ -2376,25 +2451,12 @@ static void alps_set_abs_params_mt(struct alps_data *priv,
int alps_init(struct psmouse *psmouse)
{
- struct alps_data *priv;
- struct input_dev *dev1 = psmouse->dev, *dev2;
-
- priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
- dev2 = input_allocate_device();
- if (!priv || !dev2)
- goto init_fail;
-
- priv->dev2 = dev2;
- setup_timer(&priv->timer, alps_flush_packet, (unsigned long)psmouse);
-
- psmouse->private = priv;
-
- psmouse_reset(psmouse);
-
- if (alps_identify(psmouse, priv) < 0)
- goto init_fail;
+ struct alps_data *priv = psmouse->private;
+ struct input_dev *dev1 = psmouse->dev;
+ int error;
- if (priv->hw_init(psmouse))
+ error = priv->hw_init(psmouse);
+ if (error)
goto init_fail;
/*
@@ -2443,27 +2505,58 @@ int alps_init(struct psmouse *psmouse)
dev1->keybit[BIT_WORD(BTN_MIDDLE)] |= BIT_MASK(BTN_MIDDLE);
}
- snprintf(priv->phys, sizeof(priv->phys), "%s/input1", psmouse->ps2dev.serio->phys);
- dev2->phys = priv->phys;
- dev2->name = (priv->flags & ALPS_DUALPOINT) ?
- "DualPoint Stick" : "ALPS PS/2 Device";
- dev2->id.bustype = BUS_I8042;
- dev2->id.vendor = 0x0002;
- dev2->id.product = PSMOUSE_ALPS;
- dev2->id.version = 0x0000;
- dev2->dev.parent = &psmouse->ps2dev.serio->dev;
+ if (priv->flags & ALPS_DUALPOINT) {
+ struct input_dev *dev2;
+
+ dev2 = input_allocate_device();
+ if (!dev2) {
+ psmouse_err(psmouse,
+ "failed to allocate trackstick device\n");
+ error = -ENOMEM;
+ goto init_fail;
+ }
+
+ snprintf(priv->phys2, sizeof(priv->phys2), "%s/input1",
+ psmouse->ps2dev.serio->phys);
+ dev2->phys = priv->phys2;
+
+ /*
+ * format of input device name is: "protocol vendor name"
+ * see function psmouse_switch_protocol() in psmouse-base.c
+ */
+ dev2->name = "AlpsPS/2 ALPS DualPoint Stick";
+
+ dev2->id.bustype = BUS_I8042;
+ dev2->id.vendor = 0x0002;
+ dev2->id.product = PSMOUSE_ALPS;
+ dev2->id.version = priv->proto_version;
+ dev2->dev.parent = &psmouse->ps2dev.serio->dev;
- dev2->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
- dev2->relbit[BIT_WORD(REL_X)] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
- dev2->keybit[BIT_WORD(BTN_LEFT)] =
- BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) | BIT_MASK(BTN_RIGHT);
+ input_set_capability(dev2, EV_REL, REL_X);
+ input_set_capability(dev2, EV_REL, REL_Y);
+ input_set_capability(dev2, EV_KEY, BTN_LEFT);
+ input_set_capability(dev2, EV_KEY, BTN_RIGHT);
+ input_set_capability(dev2, EV_KEY, BTN_MIDDLE);
- __set_bit(INPUT_PROP_POINTER, dev2->propbit);
- if (priv->flags & ALPS_DUALPOINT)
+ __set_bit(INPUT_PROP_POINTER, dev2->propbit);
__set_bit(INPUT_PROP_POINTING_STICK, dev2->propbit);
- if (input_register_device(priv->dev2))
- goto init_fail;
+ error = input_register_device(dev2);
+ if (error) {
+ psmouse_err(psmouse,
+ "failed to register trackstick device: %d\n",
+ error);
+ input_free_device(dev2);
+ goto init_fail;
+ }
+
+ priv->dev2 = dev2;
+ }
+
+ priv->psmouse = psmouse;
+
+ INIT_DELAYED_WORK(&priv->dev3_register_work,
+ alps_register_bare_ps2_mouse);
psmouse->protocol_handler = alps_process_byte;
psmouse->poll = alps_poll;
@@ -2481,25 +2574,56 @@ int alps_init(struct psmouse *psmouse)
init_fail:
psmouse_reset(psmouse);
- input_free_device(dev2);
- kfree(priv);
+ /*
+ * Even though we did not allocate psmouse->private we do free
+ * it here.
+ */
+ kfree(psmouse->private);
psmouse->private = NULL;
- return -1;
+ return error;
}
int alps_detect(struct psmouse *psmouse, bool set_properties)
{
- struct alps_data dummy;
+ struct alps_data *priv;
+ int error;
- if (alps_identify(psmouse, &dummy) < 0)
- return -1;
+ error = alps_identify(psmouse, NULL);
+ if (error)
+ return error;
+
+ /*
+ * Reset the device to make sure it is fully operational:
+ * on some laptops, like certain Dell Latitudes, we may
+ * fail to properly detect presence of trackstick if device
+ * has not been reset.
+ */
+ psmouse_reset(psmouse);
+
+ priv = kzalloc(sizeof(struct alps_data), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ error = alps_identify(psmouse, priv);
+ if (error)
+ return error;
if (set_properties) {
psmouse->vendor = "ALPS";
- psmouse->name = dummy.flags & ALPS_DUALPOINT ?
+ psmouse->name = priv->flags & ALPS_DUALPOINT ?
"DualPoint TouchPad" : "GlidePoint";
- psmouse->model = dummy.proto_version << 8;
+ psmouse->model = priv->proto_version;
+ } else {
+ /*
+ * Destroy alps_data structure we allocated earlier since
+ * this was just a "trial run". Otherwise we'll keep it
+ * to be used by alps_init() which has to be called if
+ * we succeed and set_properties is true.
+ */
+ kfree(priv);
+ psmouse->private = NULL;
}
+
return 0;
}
diff --git a/drivers/input/mouse/alps.h b/drivers/input/mouse/alps.h
index 66240b47819a..02513c0502fc 100644
--- a/drivers/input/mouse/alps.h
+++ b/drivers/input/mouse/alps.h
@@ -14,13 +14,14 @@
#include <linux/input/mt.h>
-#define ALPS_PROTO_V1 1
-#define ALPS_PROTO_V2 2
-#define ALPS_PROTO_V3 3
-#define ALPS_PROTO_V4 4
-#define ALPS_PROTO_V5 5
-#define ALPS_PROTO_V6 6
-#define ALPS_PROTO_V7 7 /* t3btl t4s */
+#define ALPS_PROTO_V1 0x100
+#define ALPS_PROTO_V2 0x200
+#define ALPS_PROTO_V3 0x300
+#define ALPS_PROTO_V3_RUSHMORE 0x310
+#define ALPS_PROTO_V4 0x400
+#define ALPS_PROTO_V5 0x500
+#define ALPS_PROTO_V6 0x600
+#define ALPS_PROTO_V7 0x700 /* t3btl t4s */
#define MAX_TOUCHES 2
@@ -46,29 +47,37 @@ enum V7_PACKET_ID {
};
/**
+ * struct alps_protocol_info - information about protocol used by a device
+ * @version: Indicates V1/V2/V3/...
+ * @byte0: Helps figure out whether a position report packet matches the
+ * known format for this model. The first byte of the report, ANDed with
+ * mask0, should match byte0.
+ * @mask0: The mask used to check the first byte of the report.
+ * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ */
+struct alps_protocol_info {
+ u16 version;
+ u8 byte0, mask0;
+ unsigned int flags;
+};
+
+/**
* struct alps_model_info - touchpad ID table
* @signature: E7 response string to match.
* @command_mode_resp: For V3/V4 touchpads, the final byte of the EC response
* (aka command mode response) identifies the firmware minor version. This
* can be used to distinguish different hardware models which are not
* uniquely identifiable through their E7 responses.
- * @proto_version: Indicates V1/V2/V3/...
- * @byte0: Helps figure out whether a position report packet matches the
- * known format for this model. The first byte of the report, ANDed with
- * mask0, should match byte0.
- * @mask0: The mask used to check the first byte of the report.
- * @flags: Additional device capabilities (passthrough port, trackstick, etc.).
+ * @protocol_info: information about protcol used by the device.
*
* Many (but not all) ALPS touchpads can be identified by looking at the
* values returned in the "E7 report" and/or the "EC report." This table
* lists a number of such touchpads.
*/
struct alps_model_info {
- unsigned char signature[3];
- unsigned char command_mode_resp;
- unsigned char proto_version;
- unsigned char byte0, mask0;
- int flags;
+ u8 signature[3];
+ u8 command_mode_resp;
+ struct alps_protocol_info protocol_info;
};
/**
@@ -132,8 +141,12 @@ struct alps_fields {
/**
* struct alps_data - private data structure for the ALPS driver
- * @dev2: "Relative" device used to report trackstick or mouse activity.
- * @phys: Physical path for the relative device.
+ * @psmouse: Pointer to parent psmouse device
+ * @dev2: Trackstick device (can be NULL).
+ * @dev3: Generic PS/2 mouse (can be NULL, delayed registering).
+ * @phys2: Physical path for the trackstick device.
+ * @phys3: Physical path for the generic PS/2 mouse.
+ * @dev3_register_work: Delayed work for registering PS/2 mouse.
* @nibble_commands: Command mapping used for touchpad register accesses.
* @addr_command: Command used to tell the touchpad that a register address
* follows.
@@ -160,15 +173,19 @@ struct alps_fields {
* @timer: Timer for flushing out the final report packet in the stream.
*/
struct alps_data {
+ struct psmouse *psmouse;
struct input_dev *dev2;
- char phys[32];
+ struct input_dev *dev3;
+ char phys2[32];
+ char phys3[32];
+ struct delayed_work dev3_register_work;
/* these are autodetected when the device is identified */
const struct alps_nibble_commands *nibble_commands;
int addr_command;
- unsigned char proto_version;
- unsigned char byte0, mask0;
- unsigned char fw_ver[3];
+ u16 proto_version;
+ u8 byte0, mask0;
+ u8 fw_ver[3];
int flags;
int x_max;
int y_max;
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index c329cdb0b91a..b10709f04615 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -564,7 +564,7 @@ static int report_tp_state(struct bcm5974 *dev, int size)
dev->index[n++] = &f[i];
}
- input_mt_assign_slots(input, dev->slots, dev->pos, n);
+ input_mt_assign_slots(input, dev->slots, dev->pos, n, 0);
for (i = 0; i < n; i++)
report_finger_data(input, dev->slots[i],
diff --git a/drivers/input/mouse/cyapa.c b/drivers/input/mouse/cyapa.c
index 1bece8cad46f..58f4f6fa4857 100644
--- a/drivers/input/mouse/cyapa.c
+++ b/drivers/input/mouse/cyapa.c
@@ -20,408 +20,131 @@
#include <linux/input/mt.h>
#include <linux/interrupt.h>
#include <linux/module.h>
+#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/pm_runtime.h>
+#include <linux/acpi.h>
+#include "cyapa.h"
-/* APA trackpad firmware generation */
-#define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */
-
-#define CYAPA_NAME "Cypress APA Trackpad (cyapa)"
-
-/* commands for read/write registers of Cypress trackpad */
-#define CYAPA_CMD_SOFT_RESET 0x00
-#define CYAPA_CMD_POWER_MODE 0x01
-#define CYAPA_CMD_DEV_STATUS 0x02
-#define CYAPA_CMD_GROUP_DATA 0x03
-#define CYAPA_CMD_GROUP_CMD 0x04
-#define CYAPA_CMD_GROUP_QUERY 0x05
-#define CYAPA_CMD_BL_STATUS 0x06
-#define CYAPA_CMD_BL_HEAD 0x07
-#define CYAPA_CMD_BL_CMD 0x08
-#define CYAPA_CMD_BL_DATA 0x09
-#define CYAPA_CMD_BL_ALL 0x0a
-#define CYAPA_CMD_BLK_PRODUCT_ID 0x0b
-#define CYAPA_CMD_BLK_HEAD 0x0c
-
-/* report data start reg offset address. */
-#define DATA_REG_START_OFFSET 0x0000
-
-#define BL_HEAD_OFFSET 0x00
-#define BL_DATA_OFFSET 0x10
-
-/*
- * Operational Device Status Register
- *
- * bit 7: Valid interrupt source
- * bit 6 - 4: Reserved
- * bit 3 - 2: Power status
- * bit 1 - 0: Device status
- */
-#define REG_OP_STATUS 0x00
-#define OP_STATUS_SRC 0x80
-#define OP_STATUS_POWER 0x0c
-#define OP_STATUS_DEV 0x03
-#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
-
-/*
- * Operational Finger Count/Button Flags Register
- *
- * bit 7 - 4: Number of touched finger
- * bit 3: Valid data
- * bit 2: Middle Physical Button
- * bit 1: Right Physical Button
- * bit 0: Left physical Button
- */
-#define REG_OP_DATA1 0x01
-#define OP_DATA_VALID 0x08
-#define OP_DATA_MIDDLE_BTN 0x04
-#define OP_DATA_RIGHT_BTN 0x02
-#define OP_DATA_LEFT_BTN 0x01
-#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
- OP_DATA_LEFT_BTN)
-
-/*
- * Bootloader Status Register
- *
- * bit 7: Busy
- * bit 6 - 5: Reserved
- * bit 4: Bootloader running
- * bit 3 - 1: Reserved
- * bit 0: Checksum valid
- */
-#define REG_BL_STATUS 0x01
-#define BL_STATUS_BUSY 0x80
-#define BL_STATUS_RUNNING 0x10
-#define BL_STATUS_DATA_VALID 0x08
-#define BL_STATUS_CSUM_VALID 0x01
-
-/*
- * Bootloader Error Register
- *
- * bit 7: Invalid
- * bit 6: Invalid security key
- * bit 5: Bootloading
- * bit 4: Command checksum
- * bit 3: Flash protection error
- * bit 2: Flash checksum error
- * bit 1 - 0: Reserved
- */
-#define REG_BL_ERROR 0x02
-#define BL_ERROR_INVALID 0x80
-#define BL_ERROR_INVALID_KEY 0x40
-#define BL_ERROR_BOOTLOADING 0x20
-#define BL_ERROR_CMD_CSUM 0x10
-#define BL_ERROR_FLASH_PROT 0x08
-#define BL_ERROR_FLASH_CSUM 0x04
-
-#define BL_STATUS_SIZE 3 /* length of bootloader status registers */
-#define BLK_HEAD_BYTES 32
-
-#define PRODUCT_ID_SIZE 16
-#define QUERY_DATA_SIZE 27
-#define REG_PROTOCOL_GEN_QUERY_OFFSET 20
-
-#define REG_OFFSET_DATA_BASE 0x0000
-#define REG_OFFSET_COMMAND_BASE 0x0028
-#define REG_OFFSET_QUERY_BASE 0x002a
-
-#define CAPABILITY_LEFT_BTN_MASK (0x01 << 3)
-#define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4)
-#define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5)
-#define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \
- CAPABILITY_RIGHT_BTN_MASK | \
- CAPABILITY_MIDDLE_BTN_MASK)
-
-#define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE
-
-#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1)
-
-#define PWR_MODE_MASK 0xfc
-#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
-#define PWR_MODE_IDLE (0x05 << 2) /* default sleep time is 50 ms. */
-#define PWR_MODE_OFF (0x00 << 2)
-
-#define PWR_STATUS_MASK 0x0c
-#define PWR_STATUS_ACTIVE (0x03 << 2)
-#define PWR_STATUS_IDLE (0x02 << 2)
-#define PWR_STATUS_OFF (0x00 << 2)
-
-/*
- * CYAPA trackpad device states.
- * Used in register 0x00, bit1-0, DeviceStatus field.
- * Other values indicate device is in an abnormal state and must be reset.
- */
-#define CYAPA_DEV_NORMAL 0x03
-#define CYAPA_DEV_BUSY 0x01
-
-enum cyapa_state {
- CYAPA_STATE_OP,
- CYAPA_STATE_BL_IDLE,
- CYAPA_STATE_BL_ACTIVE,
- CYAPA_STATE_BL_BUSY,
- CYAPA_STATE_NO_DEVICE,
-};
-
-
-struct cyapa_touch {
- /*
- * high bits or x/y position value
- * bit 7 - 4: high 4 bits of x position value
- * bit 3 - 0: high 4 bits of y position value
- */
- u8 xy_hi;
- u8 x_lo; /* low 8 bits of x position value. */
- u8 y_lo; /* low 8 bits of y position value. */
- u8 pressure;
- /* id range is 1 - 15. It is incremented with every new touch. */
- u8 id;
-} __packed;
-
-/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
-#define CYAPA_MAX_MT_SLOTS 15
-
-struct cyapa_reg_data {
- /*
- * bit 0 - 1: device status
- * bit 3 - 2: power mode
- * bit 6 - 4: reserved
- * bit 7: interrupt valid bit
- */
- u8 device_status;
- /*
- * bit 7 - 4: number of fingers currently touching pad
- * bit 3: valid data check bit
- * bit 2: middle mechanism button state if exists
- * bit 1: right mechanism button state if exists
- * bit 0: left mechanism button state if exists
- */
- u8 finger_btn;
- /* CYAPA reports up to 5 touches per packet. */
- struct cyapa_touch touches[5];
-} __packed;
-
-/* The main device structure */
-struct cyapa {
- enum cyapa_state state;
-
- struct i2c_client *client;
- struct input_dev *input;
- char phys[32]; /* device physical location */
- bool irq_wake; /* irq wake is enabled */
- bool smbus;
-
- /* read from query data region. */
- char product_id[16];
- u8 btn_capability;
- u8 gen;
- int max_abs_x;
- int max_abs_y;
- int physical_size_x;
- int physical_size_y;
-};
-
-static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03,
- 0x04, 0x05, 0x06, 0x07 };
-static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
- 0x05, 0x06, 0x07 };
-
-struct cyapa_cmd_len {
- u8 cmd;
- u8 len;
-};
#define CYAPA_ADAPTER_FUNC_NONE 0
#define CYAPA_ADAPTER_FUNC_I2C 1
#define CYAPA_ADAPTER_FUNC_SMBUS 2
#define CYAPA_ADAPTER_FUNC_BOTH 3
-/*
- * macros for SMBus communication
- */
-#define SMBUS_READ 0x01
-#define SMBUS_WRITE 0x00
-#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
-#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
-#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
-#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
-
- /* for byte read/write command */
-#define CMD_RESET 0
-#define CMD_POWER_MODE 1
-#define CMD_DEV_STATUS 2
-#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
-#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
-#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
-#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
-
- /* for group registers read/write command */
-#define REG_GROUP_DATA 0
-#define REG_GROUP_CMD 2
-#define REG_GROUP_QUERY 3
-#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
-#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
-#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
-#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
-
- /* for register block read/write command */
-#define CMD_BL_STATUS 0
-#define CMD_BL_HEAD 1
-#define CMD_BL_CMD 2
-#define CMD_BL_DATA 3
-#define CMD_BL_ALL 4
-#define CMD_BLK_PRODUCT_ID 5
-#define CMD_BLK_HEAD 6
-#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
-
-/* register block read/write command in bootloader mode */
-#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
-#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
-#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
-#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
-#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
-
-/* register block read/write command in operational mode */
-#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
-#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
-
-static const struct cyapa_cmd_len cyapa_i2c_cmds[] = {
- { CYAPA_OFFSET_SOFT_RESET, 1 },
- { REG_OFFSET_COMMAND_BASE + 1, 1 },
- { REG_OFFSET_DATA_BASE, 1 },
- { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) },
- { REG_OFFSET_COMMAND_BASE, 0 },
- { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE },
- { BL_HEAD_OFFSET, 3 },
- { BL_HEAD_OFFSET, 16 },
- { BL_HEAD_OFFSET, 16 },
- { BL_DATA_OFFSET, 16 },
- { BL_HEAD_OFFSET, 32 },
- { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE },
- { REG_OFFSET_DATA_BASE, 32 }
-};
+#define CYAPA_FW_NAME "cyapa.bin"
-static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
- { CYAPA_SMBUS_RESET, 1 },
- { CYAPA_SMBUS_POWER_MODE, 1 },
- { CYAPA_SMBUS_DEV_STATUS, 1 },
- { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) },
- { CYAPA_SMBUS_GROUP_CMD, 2 },
- { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE },
- { CYAPA_SMBUS_BL_STATUS, 3 },
- { CYAPA_SMBUS_BL_HEAD, 16 },
- { CYAPA_SMBUS_BL_CMD, 16 },
- { CYAPA_SMBUS_BL_DATA, 16 },
- { CYAPA_SMBUS_BL_ALL, 32 },
- { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE },
- { CYAPA_SMBUS_BLK_HEAD, 16 },
-};
+const char product_id[] = "CYTRA";
-static ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
- u8 *values)
+static int cyapa_reinitialize(struct cyapa *cyapa);
+
+static inline bool cyapa_is_bootloader_mode(struct cyapa *cyapa)
{
- return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values);
+ if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_BL)
+ return true;
+
+ if (cyapa->gen == CYAPA_GEN3 &&
+ cyapa->state >= CYAPA_STATE_BL_BUSY &&
+ cyapa->state <= CYAPA_STATE_BL_ACTIVE)
+ return true;
+
+ return false;
}
-static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
- size_t len, const u8 *values)
+static inline bool cyapa_is_operational_mode(struct cyapa *cyapa)
{
- return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values);
+ if (cyapa->gen == CYAPA_GEN5 && cyapa->state == CYAPA_STATE_GEN5_APP)
+ return true;
+
+ if (cyapa->gen == CYAPA_GEN3 && cyapa->state == CYAPA_STATE_OP)
+ return true;
+
+ return false;
}
-/*
- * cyapa_smbus_read_block - perform smbus block read command
- * @cyapa - private data structure of the driver
- * @cmd - the properly encoded smbus command
- * @len - expected length of smbus command result
- * @values - buffer to store smbus command result
- *
- * Returns negative errno, else the number of bytes written.
- *
- * Note:
- * In trackpad device, the memory block allocated for I2C register map
- * is 256 bytes, so the max read block for I2C bus is 256 bytes.
- */
-static ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
- u8 *values)
+/* Returns 0 on success, else negative errno on failure. */
+static ssize_t cyapa_i2c_read(struct cyapa *cyapa, u8 reg, size_t len,
+ u8 *values)
{
- ssize_t ret;
- u8 index;
- u8 smbus_cmd;
- u8 *buf;
struct i2c_client *client = cyapa->client;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &reg,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = len,
+ .buf = values,
+ },
+ };
+ int ret;
- if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd))
- return -EINVAL;
-
- if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) {
- /* read specific block registers command. */
- smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
- ret = i2c_smbus_read_block_data(client, smbus_cmd, values);
- goto out;
- }
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- ret = 0;
- for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
- smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
- smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
- buf = values + I2C_SMBUS_BLOCK_MAX * index;
- ret = i2c_smbus_read_block_data(client, smbus_cmd, buf);
- if (ret < 0)
- goto out;
- }
+ if (ret != ARRAY_SIZE(msgs))
+ return ret < 0 ? ret : -EIO;
-out:
- return ret > 0 ? len : ret;
+ return 0;
}
-static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx)
+/**
+ * cyapa_i2c_write - Execute i2c block data write operation
+ * @cyapa: Handle to this driver
+ * @ret: Offset of the data to written in the register map
+ * @len: number of bytes to write
+ * @values: Data to be written
+ *
+ * Return negative errno code on error; return zero when success.
+ */
+static int cyapa_i2c_write(struct cyapa *cyapa, u8 reg,
+ size_t len, const void *values)
{
- u8 cmd;
+ struct i2c_client *client = cyapa->client;
+ char buf[32];
+ int ret;
- if (cyapa->smbus) {
- cmd = cyapa_smbus_cmds[cmd_idx].cmd;
- cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
- } else {
- cmd = cyapa_i2c_cmds[cmd_idx].cmd;
- }
- return i2c_smbus_read_byte_data(cyapa->client, cmd);
-}
+ if (len > sizeof(buf) - 1)
+ return -ENOMEM;
-static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value)
-{
- u8 cmd;
+ buf[0] = reg;
+ memcpy(&buf[1], values, len);
- if (cyapa->smbus) {
- cmd = cyapa_smbus_cmds[cmd_idx].cmd;
- cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE);
- } else {
- cmd = cyapa_i2c_cmds[cmd_idx].cmd;
- }
- return i2c_smbus_write_byte_data(cyapa->client, cmd, value);
+ ret = i2c_master_send(client, buf, len + 1);
+ if (ret != len + 1)
+ return ret < 0 ? ret : -EIO;
+
+ return 0;
}
-static ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
+static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
{
- u8 cmd;
- size_t len;
+ u8 ret = CYAPA_ADAPTER_FUNC_NONE;
- if (cyapa->smbus) {
- cmd = cyapa_smbus_cmds[cmd_idx].cmd;
- len = cyapa_smbus_cmds[cmd_idx].len;
- return cyapa_smbus_read_block(cyapa, cmd, len, values);
- } else {
- cmd = cyapa_i2c_cmds[cmd_idx].cmd;
- len = cyapa_i2c_cmds[cmd_idx].len;
- return cyapa_i2c_reg_read_block(cyapa, cmd, len, values);
- }
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
+ ret |= CYAPA_ADAPTER_FUNC_I2C;
+ if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_BLOCK_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK))
+ ret |= CYAPA_ADAPTER_FUNC_SMBUS;
+ return ret;
}
/*
* Query device for its current operating state.
- *
*/
static int cyapa_get_state(struct cyapa *cyapa)
{
u8 status[BL_STATUS_SIZE];
+ u8 cmd[32];
+ /* The i2c address of gen4 and gen5 trackpad device must be even. */
+ bool even_addr = ((cyapa->client->addr & 0x0001) == 0);
+ bool smbus = false;
+ int retries = 2;
int error;
cyapa->state = CYAPA_STATE_NO_DEVICE;
@@ -433,39 +156,74 @@ static int cyapa_get_state(struct cyapa *cyapa)
*
*/
error = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET, BL_STATUS_SIZE,
- status);
+ status);
/*
* On smbus systems in OP mode, the i2c_reg_read will fail with
* -ETIMEDOUT. In this case, try again using the smbus equivalent
* command. This should return a BL_HEAD indicating CYAPA_STATE_OP.
*/
- if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO))
- error = cyapa_read_block(cyapa, CYAPA_CMD_BL_STATUS, status);
+ if (cyapa->smbus && (error == -ETIMEDOUT || error == -ENXIO)) {
+ if (!even_addr)
+ error = cyapa_read_block(cyapa,
+ CYAPA_CMD_BL_STATUS, status);
+ smbus = true;
+ }
if (error != BL_STATUS_SIZE)
goto error;
- if ((status[REG_OP_STATUS] & OP_STATUS_SRC) == OP_STATUS_SRC) {
- switch (status[REG_OP_STATUS] & OP_STATUS_DEV) {
- case CYAPA_DEV_NORMAL:
- case CYAPA_DEV_BUSY:
- cyapa->state = CYAPA_STATE_OP;
- break;
- default:
- error = -EAGAIN;
- goto error;
+ /*
+ * Detect trackpad protocol based on characteristic registers and bits.
+ */
+ do {
+ cyapa->status[REG_OP_STATUS] = status[REG_OP_STATUS];
+ cyapa->status[REG_BL_STATUS] = status[REG_BL_STATUS];
+ cyapa->status[REG_BL_ERROR] = status[REG_BL_ERROR];
+
+ if (cyapa->gen == CYAPA_GEN_UNKNOWN ||
+ cyapa->gen == CYAPA_GEN3) {
+ error = cyapa_gen3_ops.state_parse(cyapa,
+ status, BL_STATUS_SIZE);
+ if (!error)
+ goto out_detected;
}
- } else {
- if (status[REG_BL_STATUS] & BL_STATUS_BUSY)
- cyapa->state = CYAPA_STATE_BL_BUSY;
- else if (status[REG_BL_ERROR] & BL_ERROR_BOOTLOADING)
- cyapa->state = CYAPA_STATE_BL_ACTIVE;
- else
- cyapa->state = CYAPA_STATE_BL_IDLE;
- }
+ if ((cyapa->gen == CYAPA_GEN_UNKNOWN ||
+ cyapa->gen == CYAPA_GEN5) &&
+ !smbus && even_addr) {
+ error = cyapa_gen5_ops.state_parse(cyapa,
+ status, BL_STATUS_SIZE);
+ if (!error)
+ goto out_detected;
+ }
+
+ /*
+ * Write 0x00 0x00 to trackpad device to force update its
+ * status, then redo the detection again.
+ */
+ if (!smbus) {
+ cmd[0] = 0x00;
+ cmd[1] = 0x00;
+ error = cyapa_i2c_write(cyapa, 0, 2, cmd);
+ if (error)
+ goto error;
+
+ msleep(50);
+
+ error = cyapa_i2c_read(cyapa, BL_HEAD_OFFSET,
+ BL_STATUS_SIZE, status);
+ if (error)
+ goto error;
+ }
+ } while (--retries > 0 && !smbus);
+
+ goto error;
+out_detected:
+ if (cyapa->state <= CYAPA_STATE_BL_BUSY)
+ return -EAGAIN;
return 0;
+
error:
return (error < 0) ? error : -EAGAIN;
}
@@ -482,364 +240,939 @@ error:
* Returns:
* 0 when the device eventually responds with a valid non-busy state.
* -ETIMEDOUT if device never responds (too many -EAGAIN)
- * < 0 other errors
+ * -EAGAIN if bootload is busy, or unknown state.
+ * < 0 other errors
*/
-static int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
+int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout)
{
int error;
int tries = timeout / 100;
- error = cyapa_get_state(cyapa);
- while ((error || cyapa->state >= CYAPA_STATE_BL_BUSY) && tries--) {
- msleep(100);
+ do {
error = cyapa_get_state(cyapa);
- }
- return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error;
-}
+ if (!error && cyapa->state > CYAPA_STATE_BL_BUSY)
+ return 0;
-static int cyapa_bl_deactivate(struct cyapa *cyapa)
-{
- int error;
-
- error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
- bl_deactivate);
- if (error)
- return error;
+ msleep(100);
+ } while (tries--);
- /* wait for bootloader to switch to idle state; should take < 100ms */
- msleep(100);
- error = cyapa_poll_state(cyapa, 500);
- if (error)
- return error;
- if (cyapa->state != CYAPA_STATE_BL_IDLE)
- return -EAGAIN;
- return 0;
+ return (error == -EAGAIN || error == -ETIMEDOUT) ? -ETIMEDOUT : error;
}
/*
- * Exit bootloader
+ * Check if device is operational.
*
- * Send bl_exit command, then wait 50 - 100 ms to let device transition to
- * operational mode. If this is the first time the device's firmware is
- * running, it can take up to 2 seconds to calibrate its sensors. So, poll
- * the device's new state for up to 2 seconds.
+ * An operational device is responding, has exited bootloader, and has
+ * firmware supported by this driver.
*
* Returns:
+ * -ENODEV no device
+ * -EBUSY no device or in bootloader
* -EIO failure while reading from device
- * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware
- * 0 device is supported and in operational mode
+ * -ETIMEDOUT timeout failure for bus idle or bus no response
+ * -EAGAIN device is still in bootloader
+ * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
+ * -EINVAL device is in operational mode, but not supported by this driver
+ * 0 device is supported
*/
-static int cyapa_bl_exit(struct cyapa *cyapa)
+static int cyapa_check_is_operational(struct cyapa *cyapa)
{
int error;
- error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
+ error = cyapa_poll_state(cyapa, 4000);
if (error)
return error;
- /*
- * Wait for bootloader to exit, and operation mode to start.
- * Normally, this takes at least 50 ms.
- */
- usleep_range(50000, 100000);
- /*
- * In addition, when a device boots for the first time after being
- * updated to new firmware, it must first calibrate its sensors, which
- * can take up to an additional 2 seconds.
- */
- error = cyapa_poll_state(cyapa, 2000);
- if (error < 0)
- return error;
- if (cyapa->state != CYAPA_STATE_OP)
- return -EAGAIN;
+ switch (cyapa->gen) {
+ case CYAPA_GEN5:
+ cyapa->ops = &cyapa_gen5_ops;
+ break;
+ case CYAPA_GEN3:
+ cyapa->ops = &cyapa_gen3_ops;
+ break;
+ default:
+ return -ENODEV;
+ }
- return 0;
+ error = cyapa->ops->operational_check(cyapa);
+ if (!error && cyapa_is_operational_mode(cyapa))
+ cyapa->operational = true;
+ else
+ cyapa->operational = false;
+
+ return error;
}
+
/*
- * Set device power mode
- *
+ * Returns 0 on device detected, negative errno on no device detected.
+ * And when the device is detected and opertaional, it will be reset to
+ * full power active mode automatically.
*/
-static int cyapa_set_power_mode(struct cyapa *cyapa, u8 power_mode)
+static int cyapa_detect(struct cyapa *cyapa)
{
struct device *dev = &cyapa->client->dev;
- int ret;
- u8 power;
-
- if (cyapa->state != CYAPA_STATE_OP)
- return 0;
+ int error;
- ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE);
- if (ret < 0)
- return ret;
+ error = cyapa_check_is_operational(cyapa);
+ if (error) {
+ if (error != -ETIMEDOUT && error != -ENODEV &&
+ cyapa_is_bootloader_mode(cyapa)) {
+ dev_warn(dev, "device detected but not operational\n");
+ return 0;
+ }
- power = ret & ~PWR_MODE_MASK;
- power |= power_mode & PWR_MODE_MASK;
- ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
- if (ret < 0) {
- dev_err(dev, "failed to set power_mode 0x%02x err = %d\n",
- power_mode, ret);
- return ret;
+ dev_err(dev, "no device detected: %d\n", error);
+ return error;
}
return 0;
}
-static int cyapa_get_query_data(struct cyapa *cyapa)
+static int cyapa_open(struct input_dev *input)
{
- u8 query_data[QUERY_DATA_SIZE];
- int ret;
+ struct cyapa *cyapa = input_get_drvdata(input);
+ struct i2c_client *client = cyapa->client;
+ int error;
- if (cyapa->state != CYAPA_STATE_OP)
- return -EBUSY;
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
- ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data);
- if (ret < 0)
- return ret;
- if (ret != QUERY_DATA_SIZE)
- return -EIO;
+ if (cyapa->operational) {
+ /*
+ * though failed to set active power mode,
+ * but still may be able to work in lower scan rate
+ * when in operational mode.
+ */
+ error = cyapa->ops->set_power_mode(cyapa,
+ PWR_MODE_FULL_ACTIVE, 0);
+ if (error) {
+ dev_warn(&client->dev,
+ "set active power failed: %d\n", error);
+ goto out;
+ }
+ } else {
+ error = cyapa_reinitialize(cyapa);
+ if (error || !cyapa->operational) {
+ error = error ? error : -EAGAIN;
+ goto out;
+ }
+ }
+
+ enable_irq(client->irq);
+ if (!pm_runtime_enabled(&client->dev)) {
+ pm_runtime_set_active(&client->dev);
+ pm_runtime_enable(&client->dev);
+ }
+out:
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error;
+}
+
+static void cyapa_close(struct input_dev *input)
+{
+ struct cyapa *cyapa = input_get_drvdata(input);
+ struct i2c_client *client = cyapa->client;
+
+ mutex_lock(&cyapa->state_sync_lock);
+
+ disable_irq(client->irq);
+ if (pm_runtime_enabled(&client->dev))
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
+
+ if (cyapa->operational)
+ cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
- memcpy(&cyapa->product_id[0], &query_data[0], 5);
- cyapa->product_id[5] = '-';
- memcpy(&cyapa->product_id[6], &query_data[5], 6);
- cyapa->product_id[12] = '-';
- memcpy(&cyapa->product_id[13], &query_data[11], 2);
- cyapa->product_id[15] = '\0';
+ mutex_unlock(&cyapa->state_sync_lock);
+}
- cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK;
+static int cyapa_create_input_dev(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ struct input_dev *input;
+ int error;
- cyapa->gen = query_data[20] & 0x0f;
+ if (!cyapa->physical_size_x || !cyapa->physical_size_y)
+ return -EINVAL;
- cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22];
- cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23];
+ input = devm_input_allocate_device(dev);
+ if (!input) {
+ dev_err(dev, "failed to allocate memory for input device.\n");
+ return -ENOMEM;
+ }
+
+ input->name = CYAPA_NAME;
+ input->phys = cyapa->phys;
+ input->id.bustype = BUS_I2C;
+ input->id.version = 1;
+ input->id.product = 0; /* Means any product in eventcomm. */
+ input->dev.parent = &cyapa->client->dev;
+
+ input->open = cyapa_open;
+ input->close = cyapa_close;
+
+ input_set_drvdata(input, cyapa);
+
+ __set_bit(EV_ABS, input->evbit);
+
+ /* Finger position */
+ input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
+ 0);
+ input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
+ 0);
+ input_set_abs_params(input, ABS_MT_PRESSURE, 0, cyapa->max_z, 0, 0);
+ if (cyapa->gen > CYAPA_GEN3) {
+ input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
+ /*
+ * Orientation is the angle between the vertical axis and
+ * the major axis of the contact ellipse.
+ * The range is -127 to 127.
+ * the positive direction is clockwise form the vertical axis.
+ * If the ellipse of contact degenerates into a circle,
+ * orientation is reported as 0.
+ *
+ * Also, for Gen5 trackpad the accurate of this orientation
+ * value is value + (-30 ~ 30).
+ */
+ input_set_abs_params(input, ABS_MT_ORIENTATION,
+ -127, 127, 0, 0);
+ }
+ if (cyapa->gen >= CYAPA_GEN5) {
+ input_set_abs_params(input, ABS_MT_WIDTH_MAJOR, 0, 255, 0, 0);
+ input_set_abs_params(input, ABS_MT_WIDTH_MINOR, 0, 255, 0, 0);
+ }
+
+ input_abs_set_res(input, ABS_MT_POSITION_X,
+ cyapa->max_abs_x / cyapa->physical_size_x);
+ input_abs_set_res(input, ABS_MT_POSITION_Y,
+ cyapa->max_abs_y / cyapa->physical_size_y);
+
+ if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
+ __set_bit(BTN_LEFT, input->keybit);
+ if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
+ __set_bit(BTN_MIDDLE, input->keybit);
+ if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
+ __set_bit(BTN_RIGHT, input->keybit);
+
+ if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
+ __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+
+ /* Handle pointer emulation and unused slots in core */
+ error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
+ INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
+ if (error) {
+ dev_err(dev, "failed to initialize MT slots: %d\n", error);
+ return error;
+ }
- cyapa->physical_size_x =
- ((query_data[24] & 0xf0) << 4) | query_data[25];
- cyapa->physical_size_y =
- ((query_data[24] & 0x0f) << 8) | query_data[26];
+ /* Register the device in input subsystem */
+ error = input_register_device(input);
+ if (error) {
+ dev_err(dev, "failed to register input device: %d\n", error);
+ return error;
+ }
+ cyapa->input = input;
return 0;
}
+static void cyapa_enable_irq_for_cmd(struct cyapa *cyapa)
+{
+ struct input_dev *input = cyapa->input;
+
+ if (!input || !input->users) {
+ /*
+ * When input is NULL, TP must be in deep sleep mode.
+ * In this mode, later non-power I2C command will always failed
+ * if not bring it out of deep sleep mode firstly,
+ * so must command TP to active mode here.
+ */
+ if (!input || cyapa->operational)
+ cyapa->ops->set_power_mode(cyapa,
+ PWR_MODE_FULL_ACTIVE, 0);
+ /* Gen3 always using polling mode for command. */
+ if (cyapa->gen >= CYAPA_GEN5)
+ enable_irq(cyapa->client->irq);
+ }
+}
+
+static void cyapa_disable_irq_for_cmd(struct cyapa *cyapa)
+{
+ struct input_dev *input = cyapa->input;
+
+ if (!input || !input->users) {
+ if (cyapa->gen >= CYAPA_GEN5)
+ disable_irq(cyapa->client->irq);
+ if (!input || cyapa->operational)
+ cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
+ }
+}
+
/*
- * Check if device is operational.
+ * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time
*
- * An operational device is responding, has exited bootloader, and has
- * firmware supported by this driver.
+ * These are helper functions that convert to and from integer idle
+ * times and register settings to write to the PowerMode register.
+ * The trackpad supports between 20ms to 1000ms scan intervals.
+ * The time will be increased in increments of 10ms from 20ms to 100ms.
+ * From 100ms to 1000ms, time will be increased in increments of 20ms.
*
- * Returns:
- * -EBUSY no device or in bootloader
- * -EIO failure while reading from device
- * -EAGAIN device is still in bootloader
- * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
- * -EINVAL device is in operational mode, but not supported by this driver
- * 0 device is supported
+ * When Idle_Time < 100, the format to convert Idle_Time to Idle_Command is:
+ * Idle_Command = Idle Time / 10;
+ * When Idle_Time >= 100, the format to convert Idle_Time to Idle_Command is:
+ * Idle_Command = Idle Time / 20 + 5;
*/
-static int cyapa_check_is_operational(struct cyapa *cyapa)
+u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time)
{
- struct device *dev = &cyapa->client->dev;
- static const char unique_str[] = "CYTRA";
- int error;
+ u16 encoded_time;
- error = cyapa_poll_state(cyapa, 2000);
+ sleep_time = clamp_val(sleep_time, 20, 1000);
+ encoded_time = sleep_time < 100 ? sleep_time / 10 : sleep_time / 20 + 5;
+ return (encoded_time << 2) & PWR_MODE_MASK;
+}
+
+u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode)
+{
+ u8 encoded_time = pwr_mode >> 2;
+
+ return (encoded_time < 10) ? encoded_time * 10
+ : (encoded_time - 5) * 20;
+}
+
+/* 0 on driver initialize and detected successfully, negative on failure. */
+static int cyapa_initialize(struct cyapa *cyapa)
+{
+ int error = 0;
+
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+ cyapa->gen = CYAPA_GEN_UNKNOWN;
+ mutex_init(&cyapa->state_sync_lock);
+
+ /*
+ * Set to hard code default, they will be updated with trackpad set
+ * default values after probe and initialized.
+ */
+ cyapa->suspend_power_mode = PWR_MODE_SLEEP;
+ cyapa->suspend_sleep_time =
+ cyapa_pwr_cmd_to_sleep_time(cyapa->suspend_power_mode);
+
+ /* ops.initialize() is aimed to prepare for module communications. */
+ error = cyapa_gen3_ops.initialize(cyapa);
+ if (!error)
+ error = cyapa_gen5_ops.initialize(cyapa);
if (error)
return error;
- switch (cyapa->state) {
- case CYAPA_STATE_BL_ACTIVE:
- error = cyapa_bl_deactivate(cyapa);
- if (error)
- return error;
- /* Fallthrough state */
- case CYAPA_STATE_BL_IDLE:
- error = cyapa_bl_exit(cyapa);
- if (error)
- return error;
+ error = cyapa_detect(cyapa);
+ if (error)
+ return error;
- /* Fallthrough state */
- case CYAPA_STATE_OP:
- error = cyapa_get_query_data(cyapa);
- if (error)
- return error;
+ /* Power down the device until we need it. */
+ if (cyapa->operational)
+ cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
- /* only support firmware protocol gen3 */
- if (cyapa->gen != CYAPA_GEN3) {
- dev_err(dev, "unsupported protocol version (%d)",
- cyapa->gen);
- return -EINVAL;
- }
+ return 0;
+}
+
+static int cyapa_reinitialize(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ struct input_dev *input = cyapa->input;
+ int error;
+
+ if (pm_runtime_enabled(dev))
+ pm_runtime_disable(dev);
- /* only support product ID starting with CYTRA */
- if (memcmp(cyapa->product_id, unique_str,
- sizeof(unique_str) - 1) != 0) {
- dev_err(dev, "unsupported product ID (%s)\n",
- cyapa->product_id);
- return -EINVAL;
+ /* Avoid command failures when TP was in OFF state. */
+ if (cyapa->operational)
+ cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0);
+
+ error = cyapa_detect(cyapa);
+ if (error)
+ goto out;
+
+ if (!input && cyapa->operational) {
+ error = cyapa_create_input_dev(cyapa);
+ if (error) {
+ dev_err(dev, "create input_dev instance failed: %d\n",
+ error);
+ goto out;
}
- return 0;
+ }
- default:
- return -EIO;
+out:
+ if (!input || !input->users) {
+ /* Reset to power OFF state to save power when no user open. */
+ if (cyapa->operational)
+ cyapa->ops->set_power_mode(cyapa, PWR_MODE_OFF, 0);
+ } else if (!error && cyapa->operational) {
+ /*
+ * Make sure only enable runtime PM when device is
+ * in operational mode and input->users > 0.
+ */
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
}
- return 0;
+
+ return error;
}
static irqreturn_t cyapa_irq(int irq, void *dev_id)
{
struct cyapa *cyapa = dev_id;
struct device *dev = &cyapa->client->dev;
- struct input_dev *input = cyapa->input;
- struct cyapa_reg_data data;
- int i;
- int ret;
- int num_fingers;
+ pm_runtime_get_sync(dev);
if (device_may_wakeup(dev))
pm_wakeup_event(dev, 0);
- ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
- if (ret != sizeof(data))
- goto out;
+ /* Interrupt event maybe cuased by host command to trackpad device. */
+ if (cyapa->ops->irq_cmd_handler(cyapa)) {
+ /*
+ * Interrupt event maybe from trackpad device input reporting.
+ */
+ if (!cyapa->input) {
+ /*
+ * Still in probling or in firware image
+ * udpating or reading.
+ */
+ cyapa->ops->sort_empty_output_data(cyapa,
+ NULL, NULL, NULL);
+ goto out;
+ }
- if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
- (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
- (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
- goto out;
+ if (!cyapa->operational || cyapa->ops->irq_handler(cyapa)) {
+ if (!mutex_trylock(&cyapa->state_sync_lock)) {
+ cyapa->ops->sort_empty_output_data(cyapa,
+ NULL, NULL, NULL);
+ goto out;
+ }
+ cyapa_reinitialize(cyapa);
+ mutex_unlock(&cyapa->state_sync_lock);
+ }
}
- num_fingers = (data.finger_btn >> 4) & 0x0f;
- for (i = 0; i < num_fingers; i++) {
- const struct cyapa_touch *touch = &data.touches[i];
- /* Note: touch->id range is 1 to 15; slots are 0 to 14. */
- int slot = touch->id - 1;
+out:
+ pm_runtime_mark_last_busy(dev);
+ pm_runtime_put_sync_autosuspend(dev);
+ return IRQ_HANDLED;
+}
+
+/*
+ **************************************************************
+ * sysfs interface
+ **************************************************************
+*/
+#ifdef CONFIG_PM_SLEEP
+static ssize_t cyapa_show_suspend_scanrate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ u8 pwr_cmd = cyapa->suspend_power_mode;
+ u16 sleep_time;
+ int len;
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ pwr_cmd = cyapa->suspend_power_mode;
+ sleep_time = cyapa->suspend_sleep_time;
+
+ mutex_unlock(&cyapa->state_sync_lock);
+
+ switch (pwr_cmd) {
+ case PWR_MODE_BTN_ONLY:
+ len = scnprintf(buf, PAGE_SIZE, "%s\n", BTN_ONLY_MODE_NAME);
+ break;
- input_mt_slot(input, slot);
- input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
- input_report_abs(input, ABS_MT_POSITION_X,
- ((touch->xy_hi & 0xf0) << 4) | touch->x_lo);
- input_report_abs(input, ABS_MT_POSITION_Y,
- ((touch->xy_hi & 0x0f) << 8) | touch->y_lo);
- input_report_abs(input, ABS_MT_PRESSURE, touch->pressure);
+ case PWR_MODE_OFF:
+ len = scnprintf(buf, PAGE_SIZE, "%s\n", OFF_MODE_NAME);
+ break;
+
+ default:
+ len = scnprintf(buf, PAGE_SIZE, "%u\n",
+ cyapa->gen == CYAPA_GEN3 ?
+ cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
+ sleep_time);
+ break;
}
- input_mt_sync_frame(input);
+ return len;
+}
- if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
- input_report_key(input, BTN_LEFT,
- data.finger_btn & OP_DATA_LEFT_BTN);
+static ssize_t cyapa_update_suspend_scanrate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ u16 sleep_time;
+ int error;
- if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
- input_report_key(input, BTN_MIDDLE,
- data.finger_btn & OP_DATA_MIDDLE_BTN);
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
- if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
- input_report_key(input, BTN_RIGHT,
- data.finger_btn & OP_DATA_RIGHT_BTN);
+ if (sysfs_streq(buf, BTN_ONLY_MODE_NAME)) {
+ cyapa->suspend_power_mode = PWR_MODE_BTN_ONLY;
+ } else if (sysfs_streq(buf, OFF_MODE_NAME)) {
+ cyapa->suspend_power_mode = PWR_MODE_OFF;
+ } else if (!kstrtou16(buf, 10, &sleep_time)) {
+ cyapa->suspend_sleep_time = max_t(u16, sleep_time, 1000);
+ cyapa->suspend_power_mode =
+ cyapa_sleep_time_to_pwr_cmd(cyapa->suspend_sleep_time);
+ } else {
+ count = -EINVAL;
+ }
- input_sync(input);
+ mutex_unlock(&cyapa->state_sync_lock);
-out:
- return IRQ_HANDLED;
+ return count;
}
-static u8 cyapa_check_adapter_functionality(struct i2c_client *client)
+static DEVICE_ATTR(suspend_scanrate_ms, S_IRUGO|S_IWUSR,
+ cyapa_show_suspend_scanrate,
+ cyapa_update_suspend_scanrate);
+
+static struct attribute *cyapa_power_wakeup_entries[] = {
+ &dev_attr_suspend_scanrate_ms.attr,
+ NULL,
+};
+
+static const struct attribute_group cyapa_power_wakeup_group = {
+ .name = power_group_name,
+ .attrs = cyapa_power_wakeup_entries,
+};
+
+static void cyapa_remove_power_wakeup_group(void *data)
{
- u8 ret = CYAPA_ADAPTER_FUNC_NONE;
+ struct cyapa *cyapa = data;
- if (i2c_check_functionality(client->adapter, I2C_FUNC_I2C))
- ret |= CYAPA_ADAPTER_FUNC_I2C;
- if (i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA |
- I2C_FUNC_SMBUS_BLOCK_DATA |
- I2C_FUNC_SMBUS_I2C_BLOCK))
- ret |= CYAPA_ADAPTER_FUNC_SMBUS;
- return ret;
+ sysfs_unmerge_group(&cyapa->client->dev.kobj,
+ &cyapa_power_wakeup_group);
}
-static int cyapa_open(struct input_dev *input)
+static int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
{
- struct cyapa *cyapa = input_get_drvdata(input);
struct i2c_client *client = cyapa->client;
+ struct device *dev = &client->dev;
+ int error;
+
+ if (device_can_wakeup(dev)) {
+ error = sysfs_merge_group(&client->dev.kobj,
+ &cyapa_power_wakeup_group);
+ if (error) {
+ dev_err(dev, "failed to add power wakeup group: %d\n",
+ error);
+ return error;
+ }
+
+ error = devm_add_action(dev,
+ cyapa_remove_power_wakeup_group, cyapa);
+ if (error) {
+ cyapa_remove_power_wakeup_group(cyapa);
+ dev_err(dev, "failed to add power cleanup action: %d\n",
+ error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+#else
+static inline int cyapa_prepare_wakeup_controls(struct cyapa *cyapa)
+{
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static ssize_t cyapa_show_rt_suspend_scanrate(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ u8 pwr_cmd;
+ u16 sleep_time;
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ pwr_cmd = cyapa->runtime_suspend_power_mode;
+ sleep_time = cyapa->runtime_suspend_sleep_time;
+
+ mutex_unlock(&cyapa->state_sync_lock);
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n",
+ cyapa->gen == CYAPA_GEN3 ?
+ cyapa_pwr_cmd_to_sleep_time(pwr_cmd) :
+ sleep_time);
+}
+
+static ssize_t cyapa_update_rt_suspend_scanrate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ u16 time;
+ int error;
+
+ if (buf == NULL || count == 0 || kstrtou16(buf, 10, &time)) {
+ dev_err(dev, "invalid runtime suspend scanrate ms parameter\n");
+ return -EINVAL;
+ }
+
+ /*
+ * When the suspend scanrate is changed, pm_runtime_get to resume
+ * a potentially suspended device, update to the new pwr_cmd
+ * and then pm_runtime_put to suspend into the new power mode.
+ */
+ pm_runtime_get_sync(dev);
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ cyapa->runtime_suspend_sleep_time = max_t(u16, time, 1000);
+ cyapa->runtime_suspend_power_mode =
+ cyapa_sleep_time_to_pwr_cmd(cyapa->runtime_suspend_sleep_time);
+
+ mutex_unlock(&cyapa->state_sync_lock);
+
+ pm_runtime_put_sync_autosuspend(dev);
+
+ return count;
+}
+
+static DEVICE_ATTR(runtime_suspend_scanrate_ms, S_IRUGO|S_IWUSR,
+ cyapa_show_rt_suspend_scanrate,
+ cyapa_update_rt_suspend_scanrate);
+
+static struct attribute *cyapa_power_runtime_entries[] = {
+ &dev_attr_runtime_suspend_scanrate_ms.attr,
+ NULL,
+};
+
+static const struct attribute_group cyapa_power_runtime_group = {
+ .name = power_group_name,
+ .attrs = cyapa_power_runtime_entries,
+};
+
+static void cyapa_remove_power_runtime_group(void *data)
+{
+ struct cyapa *cyapa = data;
+
+ sysfs_unmerge_group(&cyapa->client->dev.kobj,
+ &cyapa_power_runtime_group);
+}
+
+static int cyapa_start_runtime(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
int error;
- error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
+ cyapa->runtime_suspend_power_mode = PWR_MODE_IDLE;
+ cyapa->runtime_suspend_sleep_time =
+ cyapa_pwr_cmd_to_sleep_time(cyapa->runtime_suspend_power_mode);
+
+ error = sysfs_merge_group(&dev->kobj, &cyapa_power_runtime_group);
if (error) {
- dev_err(&client->dev, "set active power failed: %d\n", error);
+ dev_err(dev,
+ "failed to create power runtime group: %d\n", error);
return error;
}
- enable_irq(client->irq);
+ error = devm_add_action(dev, cyapa_remove_power_runtime_group, cyapa);
+ if (error) {
+ cyapa_remove_power_runtime_group(cyapa);
+ dev_err(dev,
+ "failed to add power runtime cleanup action: %d\n",
+ error);
+ return error;
+ }
+
+ /* runtime is enabled until device is operational and opened. */
+ pm_runtime_set_suspended(dev);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_autosuspend_delay(dev, AUTOSUSPEND_DELAY);
+
return 0;
}
+#else
+static inline int cyapa_start_runtime(struct cyapa *cyapa)
+{
+ return 0;
+}
+#endif /* CONFIG_PM */
-static void cyapa_close(struct input_dev *input)
+static ssize_t cyapa_show_fm_ver(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- struct cyapa *cyapa = input_get_drvdata(input);
+ int error;
+ struct cyapa *cyapa = dev_get_drvdata(dev);
- disable_irq(cyapa->client->irq);
- cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+ error = scnprintf(buf, PAGE_SIZE, "%d.%d\n", cyapa->fw_maj_ver,
+ cyapa->fw_min_ver);
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error;
}
-static int cyapa_create_input_dev(struct cyapa *cyapa)
+static ssize_t cyapa_show_product_id(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int size;
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+ size = scnprintf(buf, PAGE_SIZE, "%s\n", cyapa->product_id);
+ mutex_unlock(&cyapa->state_sync_lock);
+ return size;
+}
+
+static int cyapa_firmware(struct cyapa *cyapa, const char *fw_name)
{
struct device *dev = &cyapa->client->dev;
- struct input_dev *input;
+ const struct firmware *fw;
int error;
- if (!cyapa->physical_size_x || !cyapa->physical_size_y)
- return -EINVAL;
+ error = request_firmware(&fw, fw_name, dev);
+ if (error) {
+ dev_err(dev, "Could not load firmware from %s: %d\n",
+ fw_name, error);
+ return error;
+ }
- input = devm_input_allocate_device(dev);
- if (!input) {
- dev_err(dev, "failed to allocate memory for input device.\n");
- return -ENOMEM;
+ error = cyapa->ops->check_fw(cyapa, fw);
+ if (error) {
+ dev_err(dev, "Invalid CYAPA firmware image: %s\n",
+ fw_name);
+ goto done;
}
- input->name = CYAPA_NAME;
- input->phys = cyapa->phys;
- input->id.bustype = BUS_I2C;
- input->id.version = 1;
- input->id.product = 0; /* Means any product in eventcomm. */
- input->dev.parent = &cyapa->client->dev;
+ /*
+ * Resume the potentially suspended device because doing FW
+ * update on a device not in the FULL mode has a chance to
+ * fail.
+ */
+ pm_runtime_get_sync(dev);
- input->open = cyapa_open;
- input->close = cyapa_close;
+ /* Require IRQ support for firmware update commands. */
+ cyapa_enable_irq_for_cmd(cyapa);
- input_set_drvdata(input, cyapa);
+ error = cyapa->ops->bl_enter(cyapa);
+ if (error) {
+ dev_err(dev, "bl_enter failed, %d\n", error);
+ goto err_detect;
+ }
- __set_bit(EV_ABS, input->evbit);
+ error = cyapa->ops->bl_activate(cyapa);
+ if (error) {
+ dev_err(dev, "bl_activate failed, %d\n", error);
+ goto err_detect;
+ }
- /* Finger position */
- input_set_abs_params(input, ABS_MT_POSITION_X, 0, cyapa->max_abs_x, 0,
- 0);
- input_set_abs_params(input, ABS_MT_POSITION_Y, 0, cyapa->max_abs_y, 0,
- 0);
- input_set_abs_params(input, ABS_MT_PRESSURE, 0, 255, 0, 0);
+ error = cyapa->ops->bl_initiate(cyapa, fw);
+ if (error) {
+ dev_err(dev, "bl_initiate failed, %d\n", error);
+ goto err_detect;
+ }
- input_abs_set_res(input, ABS_MT_POSITION_X,
- cyapa->max_abs_x / cyapa->physical_size_x);
- input_abs_set_res(input, ABS_MT_POSITION_Y,
- cyapa->max_abs_y / cyapa->physical_size_y);
+ error = cyapa->ops->update_fw(cyapa, fw);
+ if (error) {
+ dev_err(dev, "update_fw failed, %d\n", error);
+ goto err_detect;
+ }
- if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
- __set_bit(BTN_LEFT, input->keybit);
- if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
- __set_bit(BTN_MIDDLE, input->keybit);
- if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
- __set_bit(BTN_RIGHT, input->keybit);
+err_detect:
+ cyapa_disable_irq_for_cmd(cyapa);
+ pm_runtime_put_noidle(dev);
- if (cyapa->btn_capability == CAPABILITY_LEFT_BTN_MASK)
- __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
+done:
+ release_firmware(fw);
+ return error;
+}
- /* Handle pointer emulation and unused slots in core */
- error = input_mt_init_slots(input, CYAPA_MAX_MT_SLOTS,
- INPUT_MT_POINTER | INPUT_MT_DROP_UNUSED);
+static ssize_t cyapa_update_fw_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ char fw_name[NAME_MAX];
+ int ret, error;
+
+ if (count >= NAME_MAX) {
+ dev_err(dev, "File name too long\n");
+ return -EINVAL;
+ }
+
+ memcpy(fw_name, buf, count);
+ if (fw_name[count - 1] == '\n')
+ fw_name[count - 1] = '\0';
+ else
+ fw_name[count] = '\0';
+
+ if (cyapa->input) {
+ /*
+ * Force the input device to be registered after the firmware
+ * image is updated, so if the corresponding parameters updated
+ * in the new firmware image can taken effect immediately.
+ */
+ input_unregister_device(cyapa->input);
+ cyapa->input = NULL;
+ }
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
if (error) {
- dev_err(dev, "failed to initialize MT slots: %d\n", error);
+ /*
+ * Whatever, do reinitialize to try to recover TP state to
+ * previous state just as it entered fw update entrance.
+ */
+ cyapa_reinitialize(cyapa);
return error;
}
- cyapa->input = input;
- return 0;
+ error = cyapa_firmware(cyapa, fw_name);
+ if (error)
+ dev_err(dev, "firmware update failed: %d\n", error);
+ else
+ dev_dbg(dev, "firmware update successfully done.\n");
+
+ /*
+ * Redetect trackpad device states because firmware update process
+ * will reset trackpad device into bootloader mode.
+ */
+ ret = cyapa_reinitialize(cyapa);
+ if (ret) {
+ dev_err(dev, "failed to redetect after updated: %d\n", ret);
+ error = error ? error : ret;
+ }
+
+ mutex_unlock(&cyapa->state_sync_lock);
+
+ return error ? error : count;
+}
+
+static ssize_t cyapa_calibrate_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ if (cyapa->operational) {
+ cyapa_enable_irq_for_cmd(cyapa);
+ error = cyapa->ops->calibrate_store(dev, attr, buf, count);
+ cyapa_disable_irq_for_cmd(cyapa);
+ } else {
+ error = -EBUSY; /* Still running in bootloader mode. */
+ }
+
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error < 0 ? error : count;
+}
+
+static ssize_t cyapa_show_baseline(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ ssize_t error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ if (cyapa->operational) {
+ cyapa_enable_irq_for_cmd(cyapa);
+ error = cyapa->ops->show_baseline(dev, attr, buf);
+ cyapa_disable_irq_for_cmd(cyapa);
+ } else {
+ error = -EBUSY; /* Still running in bootloader mode. */
+ }
+
+ mutex_unlock(&cyapa->state_sync_lock);
+ return error;
+}
+
+static char *cyapa_state_to_string(struct cyapa *cyapa)
+{
+ switch (cyapa->state) {
+ case CYAPA_STATE_BL_BUSY:
+ return "bootloader busy";
+ case CYAPA_STATE_BL_IDLE:
+ return "bootloader idle";
+ case CYAPA_STATE_BL_ACTIVE:
+ return "bootloader active";
+ case CYAPA_STATE_GEN5_BL:
+ return "bootloader";
+ case CYAPA_STATE_OP:
+ case CYAPA_STATE_GEN5_APP:
+ return "operational"; /* Normal valid state. */
+ default:
+ return "invalid mode";
+ }
+}
+
+static ssize_t cyapa_show_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int size;
+ int error;
+
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
+ if (error)
+ return error;
+
+ size = scnprintf(buf, PAGE_SIZE, "gen%d %s\n",
+ cyapa->gen, cyapa_state_to_string(cyapa));
+
+ mutex_unlock(&cyapa->state_sync_lock);
+ return size;
+}
+
+static DEVICE_ATTR(firmware_version, S_IRUGO, cyapa_show_fm_ver, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, cyapa_show_product_id, NULL);
+static DEVICE_ATTR(update_fw, S_IWUSR, NULL, cyapa_update_fw_store);
+static DEVICE_ATTR(baseline, S_IRUGO, cyapa_show_baseline, NULL);
+static DEVICE_ATTR(calibrate, S_IWUSR, NULL, cyapa_calibrate_store);
+static DEVICE_ATTR(mode, S_IRUGO, cyapa_show_mode, NULL);
+
+static struct attribute *cyapa_sysfs_entries[] = {
+ &dev_attr_firmware_version.attr,
+ &dev_attr_product_id.attr,
+ &dev_attr_update_fw.attr,
+ &dev_attr_baseline.attr,
+ &dev_attr_calibrate.attr,
+ &dev_attr_mode.attr,
+ NULL,
+};
+
+static const struct attribute_group cyapa_sysfs_group = {
+ .attrs = cyapa_sysfs_entries,
+};
+
+static void cyapa_remove_sysfs_group(void *data)
+{
+ struct cyapa *cyapa = data;
+
+ sysfs_remove_group(&cyapa->client->dev.kobj, &cyapa_sysfs_group);
}
static int cyapa_probe(struct i2c_client *client,
@@ -848,6 +1181,7 @@ static int cyapa_probe(struct i2c_client *client,
struct device *dev = &client->dev;
struct cyapa *cyapa;
u8 adapter_func;
+ union i2c_smbus_data dummy;
int error;
adapter_func = cyapa_check_adapter_functionality(client);
@@ -856,38 +1190,54 @@ static int cyapa_probe(struct i2c_client *client,
return -EIO;
}
+ /* Make sure there is something at this address */
+ if (i2c_smbus_xfer(client->adapter, client->addr, 0,
+ I2C_SMBUS_READ, 0, I2C_SMBUS_BYTE, &dummy) < 0)
+ return -ENODEV;
+
cyapa = devm_kzalloc(dev, sizeof(struct cyapa), GFP_KERNEL);
if (!cyapa)
return -ENOMEM;
- cyapa->gen = CYAPA_GEN3;
+ /* i2c isn't supported, use smbus */
+ if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
+ cyapa->smbus = true;
+
cyapa->client = client;
i2c_set_clientdata(client, cyapa);
sprintf(cyapa->phys, "i2c-%d-%04x/input0", client->adapter->nr,
client->addr);
- /* i2c isn't supported, use smbus */
- if (adapter_func == CYAPA_ADAPTER_FUNC_SMBUS)
- cyapa->smbus = true;
+ error = cyapa_initialize(cyapa);
+ if (error) {
+ dev_err(dev, "failed to detect and initialize tp device.\n");
+ return error;
+ }
- cyapa->state = CYAPA_STATE_NO_DEVICE;
+ error = sysfs_create_group(&client->dev.kobj, &cyapa_sysfs_group);
+ if (error) {
+ dev_err(dev, "failed to create sysfs entries: %d\n", error);
+ return error;
+ }
- error = cyapa_check_is_operational(cyapa);
+ error = devm_add_action(dev, cyapa_remove_sysfs_group, cyapa);
if (error) {
- dev_err(dev, "device not operational, %d\n", error);
+ cyapa_remove_sysfs_group(cyapa);
+ dev_err(dev, "failed to add sysfs cleanup action: %d\n", error);
return error;
}
- /* Power down the device until we need it */
- error = cyapa_set_power_mode(cyapa, PWR_MODE_OFF);
+ error = cyapa_prepare_wakeup_controls(cyapa);
if (error) {
- dev_err(dev, "failed to quiesce the device: %d\n", error);
+ dev_err(dev, "failed to prepare wakeup controls: %d\n", error);
return error;
}
- error = cyapa_create_input_dev(cyapa);
- if (error)
+ error = cyapa_start_runtime(cyapa);
+ if (error) {
+ dev_err(dev, "failed to start pm_runtime: %d\n", error);
return error;
+ }
error = devm_request_threaded_irq(dev, client->irq,
NULL, cyapa_irq,
@@ -901,11 +1251,18 @@ static int cyapa_probe(struct i2c_client *client,
/* Disable IRQ until the device is opened */
disable_irq(client->irq);
- /* Register the device in input subsystem */
- error = input_register_device(cyapa->input);
- if (error) {
- dev_err(dev, "failed to register input device: %d\n", error);
- return error;
+ /*
+ * Register the device in the input subsystem when it's operational.
+ * Otherwise, keep in this driver, so it can be be recovered or updated
+ * through the sysfs mode and update_fw interfaces by user or apps.
+ */
+ if (cyapa->operational) {
+ error = cyapa_create_input_dev(cyapa);
+ if (error) {
+ dev_err(dev, "create input_dev instance failed: %d\n",
+ error);
+ return error;
+ }
}
return 0;
@@ -915,32 +1272,40 @@ static int __maybe_unused cyapa_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cyapa *cyapa = i2c_get_clientdata(client);
- struct input_dev *input = cyapa->input;
u8 power_mode;
int error;
- error = mutex_lock_interruptible(&input->mutex);
+ error = mutex_lock_interruptible(&cyapa->state_sync_lock);
if (error)
return error;
+ /*
+ * Runtime PM is enable only when device is in operational mode and
+ * users in use, so need check it before disable it to
+ * avoid unbalance warning.
+ */
+ if (pm_runtime_enabled(dev))
+ pm_runtime_disable(dev);
disable_irq(client->irq);
/*
* Set trackpad device to idle mode if wakeup is allowed,
* otherwise turn off.
*/
- power_mode = device_may_wakeup(dev) ? PWR_MODE_IDLE
- : PWR_MODE_OFF;
- error = cyapa_set_power_mode(cyapa, power_mode);
- if (error)
- dev_err(dev, "resume: set power mode to %d failed: %d\n",
- power_mode, error);
+ if (cyapa->operational) {
+ power_mode = device_may_wakeup(dev) ? cyapa->suspend_power_mode
+ : PWR_MODE_OFF;
+ error = cyapa->ops->set_power_mode(cyapa, power_mode,
+ cyapa->suspend_sleep_time);
+ if (error)
+ dev_err(dev, "suspend set power mode failed: %d\n",
+ error);
+ }
if (device_may_wakeup(dev))
cyapa->irq_wake = (enable_irq_wake(client->irq) == 0);
- mutex_unlock(&input->mutex);
-
+ mutex_unlock(&cyapa->state_sync_lock);
return 0;
}
@@ -948,29 +1313,56 @@ static int __maybe_unused cyapa_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct cyapa *cyapa = i2c_get_clientdata(client);
- struct input_dev *input = cyapa->input;
- u8 power_mode;
int error;
- mutex_lock(&input->mutex);
+ mutex_lock(&cyapa->state_sync_lock);
- if (device_may_wakeup(dev) && cyapa->irq_wake)
+ if (device_may_wakeup(dev) && cyapa->irq_wake) {
disable_irq_wake(client->irq);
+ cyapa->irq_wake = false;
+ }
- power_mode = input->users ? PWR_MODE_FULL_ACTIVE : PWR_MODE_OFF;
- error = cyapa_set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE);
+ /* Update device states and runtime PM states. */
+ error = cyapa_reinitialize(cyapa);
if (error)
- dev_warn(dev, "resume: set power mode to %d failed: %d\n",
- power_mode, error);
+ dev_warn(dev, "failed to reinitialize TP device: %d\n", error);
enable_irq(client->irq);
- mutex_unlock(&input->mutex);
+ mutex_unlock(&cyapa->state_sync_lock);
+ return 0;
+}
+
+static int __maybe_unused cyapa_runtime_suspend(struct device *dev)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error;
+
+ error = cyapa->ops->set_power_mode(cyapa,
+ cyapa->runtime_suspend_power_mode,
+ cyapa->runtime_suspend_sleep_time);
+ if (error)
+ dev_warn(dev, "runtime suspend failed: %d\n", error);
+
+ return 0;
+}
+
+static int __maybe_unused cyapa_runtime_resume(struct device *dev)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error;
+
+ error = cyapa->ops->set_power_mode(cyapa, PWR_MODE_FULL_ACTIVE, 0);
+ if (error)
+ dev_warn(dev, "runtime resume failed: %d\n", error);
return 0;
}
-static SIMPLE_DEV_PM_OPS(cyapa_pm_ops, cyapa_suspend, cyapa_resume);
+static const struct dev_pm_ops cyapa_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(cyapa_suspend, cyapa_resume)
+ SET_RUNTIME_PM_OPS(cyapa_runtime_suspend, cyapa_runtime_resume, NULL)
+};
static const struct i2c_device_id cyapa_id_table[] = {
{ "cyapa", 0 },
@@ -978,11 +1370,21 @@ static const struct i2c_device_id cyapa_id_table[] = {
};
MODULE_DEVICE_TABLE(i2c, cyapa_id_table);
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id cyapa_acpi_id[] = {
+ { "CYAP0000", 0 }, /* Gen3 trackpad with 0x67 I2C address. */
+ { "CYAP0001", 0 }, /* Gen5 trackpad with 0x24 I2C address. */
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, cyapa_acpi_id);
+#endif
+
static struct i2c_driver cyapa_driver = {
.driver = {
.name = "cyapa",
.owner = THIS_MODULE,
.pm = &cyapa_pm_ops,
+ .acpi_match_table = ACPI_PTR(cyapa_acpi_id),
},
.probe = cyapa_probe,
diff --git a/drivers/input/mouse/cyapa.h b/drivers/input/mouse/cyapa.h
new file mode 100644
index 000000000000..adc9ed5dcb0e
--- /dev/null
+++ b/drivers/input/mouse/cyapa.h
@@ -0,0 +1,301 @@
+/*
+ * Cypress APA trackpad with I2C interface
+ *
+ * Author: Dudley Du <dudl@cypress.com>
+ *
+ * Copyright (C) 2014 Cypress Semiconductor, 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 _CYAPA_H
+#define _CYAPA_H
+
+#include <linux/firmware.h>
+
+/* APA trackpad firmware generation number. */
+#define CYAPA_GEN_UNKNOWN 0x00 /* unknown protocol. */
+#define CYAPA_GEN3 0x03 /* support MT-protocol B with tracking ID. */
+#define CYAPA_GEN5 0x05 /* support TrueTouch GEN5 trackpad device. */
+
+#define CYAPA_NAME "Cypress APA Trackpad (cyapa)"
+
+/*
+ * Macros for SMBus communication
+ */
+#define SMBUS_READ 0x01
+#define SMBUS_WRITE 0x00
+#define SMBUS_ENCODE_IDX(cmd, idx) ((cmd) | (((idx) & 0x03) << 1))
+#define SMBUS_ENCODE_RW(cmd, rw) ((cmd) | ((rw) & 0x01))
+#define SMBUS_BYTE_BLOCK_CMD_MASK 0x80
+#define SMBUS_GROUP_BLOCK_CMD_MASK 0x40
+
+/* Commands for read/write registers of Cypress trackpad */
+#define CYAPA_CMD_SOFT_RESET 0x00
+#define CYAPA_CMD_POWER_MODE 0x01
+#define CYAPA_CMD_DEV_STATUS 0x02
+#define CYAPA_CMD_GROUP_DATA 0x03
+#define CYAPA_CMD_GROUP_CMD 0x04
+#define CYAPA_CMD_GROUP_QUERY 0x05
+#define CYAPA_CMD_BL_STATUS 0x06
+#define CYAPA_CMD_BL_HEAD 0x07
+#define CYAPA_CMD_BL_CMD 0x08
+#define CYAPA_CMD_BL_DATA 0x09
+#define CYAPA_CMD_BL_ALL 0x0a
+#define CYAPA_CMD_BLK_PRODUCT_ID 0x0b
+#define CYAPA_CMD_BLK_HEAD 0x0c
+#define CYAPA_CMD_MAX_BASELINE 0x0d
+#define CYAPA_CMD_MIN_BASELINE 0x0e
+
+#define BL_HEAD_OFFSET 0x00
+#define BL_DATA_OFFSET 0x10
+
+#define BL_STATUS_SIZE 3 /* Length of gen3 bootloader status registers */
+#define CYAPA_REG_MAP_SIZE 256
+
+/*
+ * Gen3 Operational Device Status Register
+ *
+ * bit 7: Valid interrupt source
+ * bit 6 - 4: Reserved
+ * bit 3 - 2: Power status
+ * bit 1 - 0: Device status
+ */
+#define REG_OP_STATUS 0x00
+#define OP_STATUS_SRC 0x80
+#define OP_STATUS_POWER 0x0c
+#define OP_STATUS_DEV 0x03
+#define OP_STATUS_MASK (OP_STATUS_SRC | OP_STATUS_POWER | OP_STATUS_DEV)
+
+/*
+ * Operational Finger Count/Button Flags Register
+ *
+ * bit 7 - 4: Number of touched finger
+ * bit 3: Valid data
+ * bit 2: Middle Physical Button
+ * bit 1: Right Physical Button
+ * bit 0: Left physical Button
+ */
+#define REG_OP_DATA1 0x01
+#define OP_DATA_VALID 0x08
+#define OP_DATA_MIDDLE_BTN 0x04
+#define OP_DATA_RIGHT_BTN 0x02
+#define OP_DATA_LEFT_BTN 0x01
+#define OP_DATA_BTN_MASK (OP_DATA_MIDDLE_BTN | OP_DATA_RIGHT_BTN | \
+ OP_DATA_LEFT_BTN)
+
+/*
+ * Write-only command file register used to issue commands and
+ * parameters to the bootloader.
+ * The default value read from it is always 0x00.
+ */
+#define REG_BL_FILE 0x00
+#define BL_FILE 0x00
+
+/*
+ * Bootloader Status Register
+ *
+ * bit 7: Busy
+ * bit 6 - 5: Reserved
+ * bit 4: Bootloader running
+ * bit 3 - 2: Reserved
+ * bit 1: Watchdog Reset
+ * bit 0: Checksum valid
+ */
+#define REG_BL_STATUS 0x01
+#define BL_STATUS_REV_6_5 0x60
+#define BL_STATUS_BUSY 0x80
+#define BL_STATUS_RUNNING 0x10
+#define BL_STATUS_REV_3_2 0x0c
+#define BL_STATUS_WATCHDOG 0x02
+#define BL_STATUS_CSUM_VALID 0x01
+#define BL_STATUS_REV_MASK (BL_STATUS_WATCHDOG | BL_STATUS_REV_3_2 | \
+ BL_STATUS_REV_6_5)
+
+/*
+ * Bootloader Error Register
+ *
+ * bit 7: Invalid
+ * bit 6: Invalid security key
+ * bit 5: Bootloading
+ * bit 4: Command checksum
+ * bit 3: Flash protection error
+ * bit 2: Flash checksum error
+ * bit 1 - 0: Reserved
+ */
+#define REG_BL_ERROR 0x02
+#define BL_ERROR_INVALID 0x80
+#define BL_ERROR_INVALID_KEY 0x40
+#define BL_ERROR_BOOTLOADING 0x20
+#define BL_ERROR_CMD_CSUM 0x10
+#define BL_ERROR_FLASH_PROT 0x08
+#define BL_ERROR_FLASH_CSUM 0x04
+#define BL_ERROR_RESERVED 0x03
+#define BL_ERROR_NO_ERR_IDLE 0x00
+#define BL_ERROR_NO_ERR_ACTIVE (BL_ERROR_BOOTLOADING)
+
+#define CAPABILITY_BTN_SHIFT 3
+#define CAPABILITY_LEFT_BTN_MASK (0x01 << 3)
+#define CAPABILITY_RIGHT_BTN_MASK (0x01 << 4)
+#define CAPABILITY_MIDDLE_BTN_MASK (0x01 << 5)
+#define CAPABILITY_BTN_MASK (CAPABILITY_LEFT_BTN_MASK | \
+ CAPABILITY_RIGHT_BTN_MASK | \
+ CAPABILITY_MIDDLE_BTN_MASK)
+
+#define PWR_MODE_MASK 0xfc
+#define PWR_MODE_FULL_ACTIVE (0x3f << 2)
+#define PWR_MODE_IDLE (0x03 << 2) /* Default rt suspend scanrate: 30ms */
+#define PWR_MODE_SLEEP (0x05 << 2) /* Default suspend scanrate: 50ms */
+#define PWR_MODE_BTN_ONLY (0x01 << 2)
+#define PWR_MODE_OFF (0x00 << 2)
+
+#define PWR_STATUS_MASK 0x0c
+#define PWR_STATUS_ACTIVE (0x03 << 2)
+#define PWR_STATUS_IDLE (0x02 << 2)
+#define PWR_STATUS_BTN_ONLY (0x01 << 2)
+#define PWR_STATUS_OFF (0x00 << 2)
+
+#define AUTOSUSPEND_DELAY 2000 /* unit : ms */
+
+#define UNINIT_SLEEP_TIME 0xFFFF
+#define UNINIT_PWR_MODE 0xFF
+
+#define BTN_ONLY_MODE_NAME "buttononly"
+#define OFF_MODE_NAME "off"
+
+/* The touch.id is used as the MT slot id, thus max MT slot is 15 */
+#define CYAPA_MAX_MT_SLOTS 15
+
+struct cyapa;
+
+typedef bool (*cb_sort)(struct cyapa *, u8 *, int);
+
+struct cyapa_dev_ops {
+ int (*check_fw)(struct cyapa *, const struct firmware *);
+ int (*bl_enter)(struct cyapa *);
+ int (*bl_activate)(struct cyapa *);
+ int (*bl_initiate)(struct cyapa *, const struct firmware *);
+ int (*update_fw)(struct cyapa *, const struct firmware *);
+ int (*bl_deactivate)(struct cyapa *);
+
+ ssize_t (*show_baseline)(struct device *,
+ struct device_attribute *, char *);
+ ssize_t (*calibrate_store)(struct device *,
+ struct device_attribute *, const char *, size_t);
+
+ int (*initialize)(struct cyapa *cyapa);
+
+ int (*state_parse)(struct cyapa *cyapa, u8 *reg_status, int len);
+ int (*operational_check)(struct cyapa *cyapa);
+
+ int (*irq_handler)(struct cyapa *);
+ bool (*irq_cmd_handler)(struct cyapa *);
+ int (*sort_empty_output_data)(struct cyapa *,
+ u8 *, int *, cb_sort);
+
+ int (*set_power_mode)(struct cyapa *, u8, u16);
+};
+
+struct cyapa_gen5_cmd_states {
+ struct mutex cmd_lock;
+ struct completion cmd_ready;
+ atomic_t cmd_issued;
+ u8 in_progress_cmd;
+ bool is_irq_mode;
+
+ cb_sort resp_sort_func;
+ u8 *resp_data;
+ int *resp_len;
+
+ u8 irq_cmd_buf[CYAPA_REG_MAP_SIZE];
+ u8 empty_buf[CYAPA_REG_MAP_SIZE];
+};
+
+union cyapa_cmd_states {
+ struct cyapa_gen5_cmd_states gen5;
+};
+
+enum cyapa_state {
+ CYAPA_STATE_NO_DEVICE,
+ CYAPA_STATE_BL_BUSY,
+ CYAPA_STATE_BL_IDLE,
+ CYAPA_STATE_BL_ACTIVE,
+ CYAPA_STATE_OP,
+ CYAPA_STATE_GEN5_BL,
+ CYAPA_STATE_GEN5_APP,
+};
+
+/* The main device structure */
+struct cyapa {
+ enum cyapa_state state;
+ u8 status[BL_STATUS_SIZE];
+ bool operational; /* true: ready for data reporting; false: not. */
+
+ struct i2c_client *client;
+ struct input_dev *input;
+ char phys[32]; /* Device physical location */
+ bool irq_wake; /* Irq wake is enabled */
+ bool smbus;
+
+ /* power mode settings */
+ u8 suspend_power_mode;
+ u16 suspend_sleep_time;
+ u8 runtime_suspend_power_mode;
+ u16 runtime_suspend_sleep_time;
+ u8 dev_pwr_mode;
+ u16 dev_sleep_time;
+
+ /* Read from query data region. */
+ char product_id[16];
+ u8 fw_maj_ver; /* Firmware major version. */
+ u8 fw_min_ver; /* Firmware minor version. */
+ u8 btn_capability;
+ u8 gen;
+ int max_abs_x;
+ int max_abs_y;
+ int physical_size_x;
+ int physical_size_y;
+
+ /* Used in ttsp and truetouch based trackpad devices. */
+ u8 x_origin; /* X Axis Origin: 0 = left side; 1 = rigth side. */
+ u8 y_origin; /* Y Axis Origin: 0 = top; 1 = bottom. */
+ int electrodes_x; /* Number of electrodes on the X Axis*/
+ int electrodes_y; /* Number of electrodes on the Y Axis*/
+ int electrodes_rx; /* Number of Rx electrodes */
+ int aligned_electrodes_rx; /* 4 aligned */
+ int max_z;
+
+ /*
+ * Used to synchronize the access or update the device state.
+ * And since update firmware and read firmware image process will take
+ * quite long time, maybe more than 10 seconds, so use mutex_lock
+ * to sync and wait other interface and detecting are done or ready.
+ */
+ struct mutex state_sync_lock;
+
+ const struct cyapa_dev_ops *ops;
+
+ union cyapa_cmd_states cmd_states;
+};
+
+
+ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
+ u8 *values);
+ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
+ u8 *values);
+
+ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values);
+
+int cyapa_poll_state(struct cyapa *cyapa, unsigned int timeout);
+
+u8 cyapa_sleep_time_to_pwr_cmd(u16 sleep_time);
+u16 cyapa_pwr_cmd_to_sleep_time(u8 pwr_mode);
+
+
+extern const char product_id[];
+extern const struct cyapa_dev_ops cyapa_gen3_ops;
+extern const struct cyapa_dev_ops cyapa_gen5_ops;
+
+#endif
diff --git a/drivers/input/mouse/cyapa_gen3.c b/drivers/input/mouse/cyapa_gen3.c
new file mode 100644
index 000000000000..77e9d70a986b
--- /dev/null
+++ b/drivers/input/mouse/cyapa_gen3.c
@@ -0,0 +1,1247 @@
+/*
+ * Cypress APA trackpad with I2C interface
+ *
+ * Author: Dudley Du <dudl@cypress.com>
+ * Further cleanup and restructuring by:
+ * Daniel Kurtz <djkurtz@chromium.org>
+ * Benson Leung <bleung@chromium.org>
+ *
+ * Copyright (C) 2011-2014 Cypress Semiconductor, Inc.
+ * Copyright (C) 2011-2012 Google, 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/unaligned/access_ok.h>
+#include "cyapa.h"
+
+
+#define GEN3_MAX_FINGERS 5
+#define GEN3_FINGER_NUM(x) (((x) >> 4) & 0x07)
+
+#define BLK_HEAD_BYTES 32
+
+/* Macro for register map group offset. */
+#define PRODUCT_ID_SIZE 16
+#define QUERY_DATA_SIZE 27
+#define REG_PROTOCOL_GEN_QUERY_OFFSET 20
+
+#define REG_OFFSET_DATA_BASE 0x0000
+#define REG_OFFSET_COMMAND_BASE 0x0028
+#define REG_OFFSET_QUERY_BASE 0x002a
+
+#define CYAPA_OFFSET_SOFT_RESET REG_OFFSET_COMMAND_BASE
+#define OP_RECALIBRATION_MASK 0x80
+#define OP_REPORT_BASELINE_MASK 0x40
+#define REG_OFFSET_MAX_BASELINE 0x0026
+#define REG_OFFSET_MIN_BASELINE 0x0027
+
+#define REG_OFFSET_POWER_MODE (REG_OFFSET_COMMAND_BASE + 1)
+#define SET_POWER_MODE_DELAY 10000 /* Unit: us */
+#define SET_POWER_MODE_TRIES 5
+
+#define GEN3_BL_CMD_CHECKSUM_SEED 0xff
+#define GEN3_BL_CMD_INITIATE_BL 0x38
+#define GEN3_BL_CMD_WRITE_BLOCK 0x39
+#define GEN3_BL_CMD_VERIFY_BLOCK 0x3a
+#define GEN3_BL_CMD_TERMINATE_BL 0x3b
+#define GEN3_BL_CMD_LAUNCH_APP 0xa5
+
+/*
+ * CYAPA trackpad device states.
+ * Used in register 0x00, bit1-0, DeviceStatus field.
+ * Other values indicate device is in an abnormal state and must be reset.
+ */
+#define CYAPA_DEV_NORMAL 0x03
+#define CYAPA_DEV_BUSY 0x01
+
+#define CYAPA_FW_BLOCK_SIZE 64
+#define CYAPA_FW_READ_SIZE 16
+#define CYAPA_FW_HDR_START 0x0780
+#define CYAPA_FW_HDR_BLOCK_COUNT 2
+#define CYAPA_FW_HDR_BLOCK_START (CYAPA_FW_HDR_START / CYAPA_FW_BLOCK_SIZE)
+#define CYAPA_FW_HDR_SIZE (CYAPA_FW_HDR_BLOCK_COUNT * \
+ CYAPA_FW_BLOCK_SIZE)
+#define CYAPA_FW_DATA_START 0x0800
+#define CYAPA_FW_DATA_BLOCK_COUNT 480
+#define CYAPA_FW_DATA_BLOCK_START (CYAPA_FW_DATA_START / CYAPA_FW_BLOCK_SIZE)
+#define CYAPA_FW_DATA_SIZE (CYAPA_FW_DATA_BLOCK_COUNT * \
+ CYAPA_FW_BLOCK_SIZE)
+#define CYAPA_FW_SIZE (CYAPA_FW_HDR_SIZE + CYAPA_FW_DATA_SIZE)
+#define CYAPA_CMD_LEN 16
+
+#define GEN3_BL_IDLE_FW_MAJ_VER_OFFSET 0x0b
+#define GEN3_BL_IDLE_FW_MIN_VER_OFFSET (GEN3_BL_IDLE_FW_MAJ_VER_OFFSET + 1)
+
+
+struct cyapa_touch {
+ /*
+ * high bits or x/y position value
+ * bit 7 - 4: high 4 bits of x position value
+ * bit 3 - 0: high 4 bits of y position value
+ */
+ u8 xy_hi;
+ u8 x_lo; /* low 8 bits of x position value. */
+ u8 y_lo; /* low 8 bits of y position value. */
+ u8 pressure;
+ /* id range is 1 - 15. It is incremented with every new touch. */
+ u8 id;
+} __packed;
+
+struct cyapa_reg_data {
+ /*
+ * bit 0 - 1: device status
+ * bit 3 - 2: power mode
+ * bit 6 - 4: reserved
+ * bit 7: interrupt valid bit
+ */
+ u8 device_status;
+ /*
+ * bit 7 - 4: number of fingers currently touching pad
+ * bit 3: valid data check bit
+ * bit 2: middle mechanism button state if exists
+ * bit 1: right mechanism button state if exists
+ * bit 0: left mechanism button state if exists
+ */
+ u8 finger_btn;
+ /* CYAPA reports up to 5 touches per packet. */
+ struct cyapa_touch touches[5];
+} __packed;
+
+struct gen3_write_block_cmd {
+ u8 checksum_seed; /* Always be 0xff */
+ u8 cmd_code; /* command code: 0x39 */
+ u8 key[8]; /* 8-byte security key */
+ __be16 block_num;
+ u8 block_data[CYAPA_FW_BLOCK_SIZE];
+ u8 block_checksum; /* Calculated using bytes 12 - 75 */
+ u8 cmd_checksum; /* Calculated using bytes 0-76 */
+} __packed;
+
+static const u8 security_key[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
+static const u8 bl_activate[] = { 0x00, 0xff, 0x38, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07 };
+static const u8 bl_deactivate[] = { 0x00, 0xff, 0x3b, 0x00, 0x01, 0x02, 0x03,
+ 0x04, 0x05, 0x06, 0x07 };
+static const u8 bl_exit[] = { 0x00, 0xff, 0xa5, 0x00, 0x01, 0x02, 0x03, 0x04,
+ 0x05, 0x06, 0x07 };
+
+
+ /* for byte read/write command */
+#define CMD_RESET 0
+#define CMD_POWER_MODE 1
+#define CMD_DEV_STATUS 2
+#define CMD_REPORT_MAX_BASELINE 3
+#define CMD_REPORT_MIN_BASELINE 4
+#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
+#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
+#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
+#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
+#define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE)
+#define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE)
+
+ /* for group registers read/write command */
+#define REG_GROUP_DATA 0
+#define REG_GROUP_CMD 2
+#define REG_GROUP_QUERY 3
+#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
+#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
+#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
+#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
+
+ /* for register block read/write command */
+#define CMD_BL_STATUS 0
+#define CMD_BL_HEAD 1
+#define CMD_BL_CMD 2
+#define CMD_BL_DATA 3
+#define CMD_BL_ALL 4
+#define CMD_BLK_PRODUCT_ID 5
+#define CMD_BLK_HEAD 6
+#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
+
+/* register block read/write command in bootloader mode */
+#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
+#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
+#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
+#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
+#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
+
+/* register block read/write command in operational mode */
+#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
+#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
+
+ /* for byte read/write command */
+#define CMD_RESET 0
+#define CMD_POWER_MODE 1
+#define CMD_DEV_STATUS 2
+#define CMD_REPORT_MAX_BASELINE 3
+#define CMD_REPORT_MIN_BASELINE 4
+#define SMBUS_BYTE_CMD(cmd) (((cmd) & 0x3f) << 1)
+#define CYAPA_SMBUS_RESET SMBUS_BYTE_CMD(CMD_RESET)
+#define CYAPA_SMBUS_POWER_MODE SMBUS_BYTE_CMD(CMD_POWER_MODE)
+#define CYAPA_SMBUS_DEV_STATUS SMBUS_BYTE_CMD(CMD_DEV_STATUS)
+#define CYAPA_SMBUS_MAX_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MAX_BASELINE)
+#define CYAPA_SMBUS_MIN_BASELINE SMBUS_BYTE_CMD(CMD_REPORT_MIN_BASELINE)
+
+ /* for group registers read/write command */
+#define REG_GROUP_DATA 0
+#define REG_GROUP_CMD 2
+#define REG_GROUP_QUERY 3
+#define SMBUS_GROUP_CMD(grp) (0x80 | (((grp) & 0x07) << 3))
+#define CYAPA_SMBUS_GROUP_DATA SMBUS_GROUP_CMD(REG_GROUP_DATA)
+#define CYAPA_SMBUS_GROUP_CMD SMBUS_GROUP_CMD(REG_GROUP_CMD)
+#define CYAPA_SMBUS_GROUP_QUERY SMBUS_GROUP_CMD(REG_GROUP_QUERY)
+
+ /* for register block read/write command */
+#define CMD_BL_STATUS 0
+#define CMD_BL_HEAD 1
+#define CMD_BL_CMD 2
+#define CMD_BL_DATA 3
+#define CMD_BL_ALL 4
+#define CMD_BLK_PRODUCT_ID 5
+#define CMD_BLK_HEAD 6
+#define SMBUS_BLOCK_CMD(cmd) (0xc0 | (((cmd) & 0x1f) << 1))
+
+/* register block read/write command in bootloader mode */
+#define CYAPA_SMBUS_BL_STATUS SMBUS_BLOCK_CMD(CMD_BL_STATUS)
+#define CYAPA_SMBUS_BL_HEAD SMBUS_BLOCK_CMD(CMD_BL_HEAD)
+#define CYAPA_SMBUS_BL_CMD SMBUS_BLOCK_CMD(CMD_BL_CMD)
+#define CYAPA_SMBUS_BL_DATA SMBUS_BLOCK_CMD(CMD_BL_DATA)
+#define CYAPA_SMBUS_BL_ALL SMBUS_BLOCK_CMD(CMD_BL_ALL)
+
+/* register block read/write command in operational mode */
+#define CYAPA_SMBUS_BLK_PRODUCT_ID SMBUS_BLOCK_CMD(CMD_BLK_PRODUCT_ID)
+#define CYAPA_SMBUS_BLK_HEAD SMBUS_BLOCK_CMD(CMD_BLK_HEAD)
+
+struct cyapa_cmd_len {
+ u8 cmd;
+ u8 len;
+};
+
+/* maps generic CYAPA_CMD_* code to the I2C equivalent */
+static const struct cyapa_cmd_len cyapa_i2c_cmds[] = {
+ { CYAPA_OFFSET_SOFT_RESET, 1 }, /* CYAPA_CMD_SOFT_RESET */
+ { REG_OFFSET_COMMAND_BASE + 1, 1 }, /* CYAPA_CMD_POWER_MODE */
+ { REG_OFFSET_DATA_BASE, 1 }, /* CYAPA_CMD_DEV_STATUS */
+ { REG_OFFSET_DATA_BASE, sizeof(struct cyapa_reg_data) },
+ /* CYAPA_CMD_GROUP_DATA */
+ { REG_OFFSET_COMMAND_BASE, 0 }, /* CYAPA_CMD_GROUP_CMD */
+ { REG_OFFSET_QUERY_BASE, QUERY_DATA_SIZE }, /* CYAPA_CMD_GROUP_QUERY */
+ { BL_HEAD_OFFSET, 3 }, /* CYAPA_CMD_BL_STATUS */
+ { BL_HEAD_OFFSET, 16 }, /* CYAPA_CMD_BL_HEAD */
+ { BL_HEAD_OFFSET, 16 }, /* CYAPA_CMD_BL_CMD */
+ { BL_DATA_OFFSET, 16 }, /* CYAPA_CMD_BL_DATA */
+ { BL_HEAD_OFFSET, 32 }, /* CYAPA_CMD_BL_ALL */
+ { REG_OFFSET_QUERY_BASE, PRODUCT_ID_SIZE },
+ /* CYAPA_CMD_BLK_PRODUCT_ID */
+ { REG_OFFSET_DATA_BASE, 32 }, /* CYAPA_CMD_BLK_HEAD */
+ { REG_OFFSET_MAX_BASELINE, 1 }, /* CYAPA_CMD_MAX_BASELINE */
+ { REG_OFFSET_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */
+};
+
+static const struct cyapa_cmd_len cyapa_smbus_cmds[] = {
+ { CYAPA_SMBUS_RESET, 1 }, /* CYAPA_CMD_SOFT_RESET */
+ { CYAPA_SMBUS_POWER_MODE, 1 }, /* CYAPA_CMD_POWER_MODE */
+ { CYAPA_SMBUS_DEV_STATUS, 1 }, /* CYAPA_CMD_DEV_STATUS */
+ { CYAPA_SMBUS_GROUP_DATA, sizeof(struct cyapa_reg_data) },
+ /* CYAPA_CMD_GROUP_DATA */
+ { CYAPA_SMBUS_GROUP_CMD, 2 }, /* CYAPA_CMD_GROUP_CMD */
+ { CYAPA_SMBUS_GROUP_QUERY, QUERY_DATA_SIZE },
+ /* CYAPA_CMD_GROUP_QUERY */
+ { CYAPA_SMBUS_BL_STATUS, 3 }, /* CYAPA_CMD_BL_STATUS */
+ { CYAPA_SMBUS_BL_HEAD, 16 }, /* CYAPA_CMD_BL_HEAD */
+ { CYAPA_SMBUS_BL_CMD, 16 }, /* CYAPA_CMD_BL_CMD */
+ { CYAPA_SMBUS_BL_DATA, 16 }, /* CYAPA_CMD_BL_DATA */
+ { CYAPA_SMBUS_BL_ALL, 32 }, /* CYAPA_CMD_BL_ALL */
+ { CYAPA_SMBUS_BLK_PRODUCT_ID, PRODUCT_ID_SIZE },
+ /* CYAPA_CMD_BLK_PRODUCT_ID */
+ { CYAPA_SMBUS_BLK_HEAD, 16 }, /* CYAPA_CMD_BLK_HEAD */
+ { CYAPA_SMBUS_MAX_BASELINE, 1 }, /* CYAPA_CMD_MAX_BASELINE */
+ { CYAPA_SMBUS_MIN_BASELINE, 1 }, /* CYAPA_CMD_MIN_BASELINE */
+};
+
+
+/*
+ * cyapa_smbus_read_block - perform smbus block read command
+ * @cyapa - private data structure of the driver
+ * @cmd - the properly encoded smbus command
+ * @len - expected length of smbus command result
+ * @values - buffer to store smbus command result
+ *
+ * Returns negative errno, else the number of bytes written.
+ *
+ * Note:
+ * In trackpad device, the memory block allocated for I2C register map
+ * is 256 bytes, so the max read block for I2C bus is 256 bytes.
+ */
+ssize_t cyapa_smbus_read_block(struct cyapa *cyapa, u8 cmd, size_t len,
+ u8 *values)
+{
+ ssize_t ret;
+ u8 index;
+ u8 smbus_cmd;
+ u8 *buf;
+ struct i2c_client *client = cyapa->client;
+
+ if (!(SMBUS_BYTE_BLOCK_CMD_MASK & cmd))
+ return -EINVAL;
+
+ if (SMBUS_GROUP_BLOCK_CMD_MASK & cmd) {
+ /* read specific block registers command. */
+ smbus_cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
+ ret = i2c_smbus_read_block_data(client, smbus_cmd, values);
+ goto out;
+ }
+
+ ret = 0;
+ for (index = 0; index * I2C_SMBUS_BLOCK_MAX < len; index++) {
+ smbus_cmd = SMBUS_ENCODE_IDX(cmd, index);
+ smbus_cmd = SMBUS_ENCODE_RW(smbus_cmd, SMBUS_READ);
+ buf = values + I2C_SMBUS_BLOCK_MAX * index;
+ ret = i2c_smbus_read_block_data(client, smbus_cmd, buf);
+ if (ret < 0)
+ goto out;
+ }
+
+out:
+ return ret > 0 ? len : ret;
+}
+
+static s32 cyapa_read_byte(struct cyapa *cyapa, u8 cmd_idx)
+{
+ u8 cmd;
+
+ if (cyapa->smbus) {
+ cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+ cmd = SMBUS_ENCODE_RW(cmd, SMBUS_READ);
+ } else {
+ cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+ }
+ return i2c_smbus_read_byte_data(cyapa->client, cmd);
+}
+
+static s32 cyapa_write_byte(struct cyapa *cyapa, u8 cmd_idx, u8 value)
+{
+ u8 cmd;
+
+ if (cyapa->smbus) {
+ cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+ cmd = SMBUS_ENCODE_RW(cmd, SMBUS_WRITE);
+ } else {
+ cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+ }
+ return i2c_smbus_write_byte_data(cyapa->client, cmd, value);
+}
+
+ssize_t cyapa_i2c_reg_read_block(struct cyapa *cyapa, u8 reg, size_t len,
+ u8 *values)
+{
+ return i2c_smbus_read_i2c_block_data(cyapa->client, reg, len, values);
+}
+
+static ssize_t cyapa_i2c_reg_write_block(struct cyapa *cyapa, u8 reg,
+ size_t len, const u8 *values)
+{
+ return i2c_smbus_write_i2c_block_data(cyapa->client, reg, len, values);
+}
+
+ssize_t cyapa_read_block(struct cyapa *cyapa, u8 cmd_idx, u8 *values)
+{
+ u8 cmd;
+ size_t len;
+
+ if (cyapa->smbus) {
+ cmd = cyapa_smbus_cmds[cmd_idx].cmd;
+ len = cyapa_smbus_cmds[cmd_idx].len;
+ return cyapa_smbus_read_block(cyapa, cmd, len, values);
+ }
+ cmd = cyapa_i2c_cmds[cmd_idx].cmd;
+ len = cyapa_i2c_cmds[cmd_idx].len;
+ return cyapa_i2c_reg_read_block(cyapa, cmd, len, values);
+}
+
+/*
+ * Determine the Gen3 trackpad device's current operating state.
+ *
+ */
+static int cyapa_gen3_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
+{
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+
+ /* Parse based on Gen3 characteristic registers and bits */
+ if (reg_data[REG_BL_FILE] == BL_FILE &&
+ reg_data[REG_BL_ERROR] == BL_ERROR_NO_ERR_IDLE &&
+ (reg_data[REG_BL_STATUS] ==
+ (BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID) ||
+ reg_data[REG_BL_STATUS] == BL_STATUS_RUNNING)) {
+ /*
+ * Normal state after power on or reset,
+ * REG_BL_STATUS == 0x11, firmware image checksum is valid.
+ * REG_BL_STATUS == 0x10, firmware image checksum is invalid.
+ */
+ cyapa->gen = CYAPA_GEN3;
+ cyapa->state = CYAPA_STATE_BL_IDLE;
+ } else if (reg_data[REG_BL_FILE] == BL_FILE &&
+ (reg_data[REG_BL_STATUS] & BL_STATUS_RUNNING) ==
+ BL_STATUS_RUNNING) {
+ cyapa->gen = CYAPA_GEN3;
+ if (reg_data[REG_BL_STATUS] & BL_STATUS_BUSY) {
+ cyapa->state = CYAPA_STATE_BL_BUSY;
+ } else {
+ if ((reg_data[REG_BL_ERROR] & BL_ERROR_BOOTLOADING) ==
+ BL_ERROR_BOOTLOADING)
+ cyapa->state = CYAPA_STATE_BL_ACTIVE;
+ else
+ cyapa->state = CYAPA_STATE_BL_IDLE;
+ }
+ } else if ((reg_data[REG_OP_STATUS] & OP_STATUS_SRC) &&
+ (reg_data[REG_OP_DATA1] & OP_DATA_VALID)) {
+ /*
+ * Normal state when running in operational mode,
+ * may also not in full power state or
+ * busying in command process.
+ */
+ if (GEN3_FINGER_NUM(reg_data[REG_OP_DATA1]) <=
+ GEN3_MAX_FINGERS) {
+ /* Finger number data is valid. */
+ cyapa->gen = CYAPA_GEN3;
+ cyapa->state = CYAPA_STATE_OP;
+ }
+ } else if (reg_data[REG_OP_STATUS] == 0x0C &&
+ reg_data[REG_OP_DATA1] == 0x08) {
+ /* Op state when first two registers overwritten with 0x00 */
+ cyapa->gen = CYAPA_GEN3;
+ cyapa->state = CYAPA_STATE_OP;
+ } else if (reg_data[REG_BL_STATUS] &
+ (BL_STATUS_RUNNING | BL_STATUS_BUSY)) {
+ cyapa->gen = CYAPA_GEN3;
+ cyapa->state = CYAPA_STATE_BL_BUSY;
+ }
+
+ if (cyapa->gen == CYAPA_GEN3 && (cyapa->state == CYAPA_STATE_OP ||
+ cyapa->state == CYAPA_STATE_BL_IDLE ||
+ cyapa->state == CYAPA_STATE_BL_ACTIVE ||
+ cyapa->state == CYAPA_STATE_BL_BUSY))
+ return 0;
+
+ return -EAGAIN;
+}
+
+/*
+ * Enter bootloader by soft resetting the device.
+ *
+ * If device is already in the bootloader, the function just returns.
+ * Otherwise, reset the device; after reset, device enters bootloader idle
+ * state immediately.
+ *
+ * Returns:
+ * 0 on success
+ * -EAGAIN device was reset, but is not now in bootloader idle state
+ * < 0 if the device never responds within the timeout
+ */
+static int cyapa_gen3_bl_enter(struct cyapa *cyapa)
+{
+ int error;
+ int waiting_time;
+
+ error = cyapa_poll_state(cyapa, 500);
+ if (error)
+ return error;
+ if (cyapa->state == CYAPA_STATE_BL_IDLE) {
+ /* Already in BL_IDLE. Skipping reset. */
+ return 0;
+ }
+
+ if (cyapa->state != CYAPA_STATE_OP)
+ return -EAGAIN;
+
+ cyapa->operational = false;
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+ error = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET, 0x01);
+ if (error)
+ return -EIO;
+
+ usleep_range(25000, 50000);
+ waiting_time = 2000; /* For some shipset, max waiting time is 1~2s. */
+ do {
+ error = cyapa_poll_state(cyapa, 500);
+ if (error) {
+ if (error == -ETIMEDOUT) {
+ waiting_time -= 500;
+ continue;
+ }
+ return error;
+ }
+
+ if ((cyapa->state == CYAPA_STATE_BL_IDLE) &&
+ !(cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG))
+ break;
+
+ msleep(100);
+ waiting_time -= 100;
+ } while (waiting_time > 0);
+
+ if ((cyapa->state != CYAPA_STATE_BL_IDLE) ||
+ (cyapa->status[REG_BL_STATUS] & BL_STATUS_WATCHDOG))
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen3_bl_activate(struct cyapa *cyapa)
+{
+ int error;
+
+ error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_activate),
+ bl_activate);
+ if (error)
+ return error;
+
+ /* Wait for bootloader to activate; takes between 2 and 12 seconds */
+ msleep(2000);
+ error = cyapa_poll_state(cyapa, 11000);
+ if (error)
+ return error;
+ if (cyapa->state != CYAPA_STATE_BL_ACTIVE)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen3_bl_deactivate(struct cyapa *cyapa)
+{
+ int error;
+
+ error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_deactivate),
+ bl_deactivate);
+ if (error)
+ return error;
+
+ /* Wait for bootloader to switch to idle state; should take < 100ms */
+ msleep(100);
+ error = cyapa_poll_state(cyapa, 500);
+ if (error)
+ return error;
+ if (cyapa->state != CYAPA_STATE_BL_IDLE)
+ return -EAGAIN;
+ return 0;
+}
+
+/*
+ * Exit bootloader
+ *
+ * Send bl_exit command, then wait 50 - 100 ms to let device transition to
+ * operational mode. If this is the first time the device's firmware is
+ * running, it can take up to 2 seconds to calibrate its sensors. So, poll
+ * the device's new state for up to 2 seconds.
+ *
+ * Returns:
+ * -EIO failure while reading from device
+ * -EAGAIN device is stuck in bootloader, b/c it has invalid firmware
+ * 0 device is supported and in operational mode
+ */
+static int cyapa_gen3_bl_exit(struct cyapa *cyapa)
+{
+ int error;
+
+ error = cyapa_i2c_reg_write_block(cyapa, 0, sizeof(bl_exit), bl_exit);
+ if (error)
+ return error;
+
+ /*
+ * Wait for bootloader to exit, and operation mode to start.
+ * Normally, this takes at least 50 ms.
+ */
+ usleep_range(50000, 100000);
+ /*
+ * In addition, when a device boots for the first time after being
+ * updated to new firmware, it must first calibrate its sensors, which
+ * can take up to an additional 2 seconds. If the device power is
+ * running low, this may take even longer.
+ */
+ error = cyapa_poll_state(cyapa, 4000);
+ if (error < 0)
+ return error;
+ if (cyapa->state != CYAPA_STATE_OP)
+ return -EAGAIN;
+
+ return 0;
+}
+
+static u16 cyapa_gen3_csum(const u8 *buf, size_t count)
+{
+ int i;
+ u16 csum = 0;
+
+ for (i = 0; i < count; i++)
+ csum += buf[i];
+
+ return csum;
+}
+
+/*
+ * Verify the integrity of a CYAPA firmware image file.
+ *
+ * The firmware image file is 30848 bytes, composed of 482 64-byte blocks.
+ *
+ * The first 2 blocks are the firmware header.
+ * The next 480 blocks are the firmware image.
+ *
+ * The first two bytes of the header hold the header checksum, computed by
+ * summing the other 126 bytes of the header.
+ * The last two bytes of the header hold the firmware image checksum, computed
+ * by summing the 30720 bytes of the image modulo 0xffff.
+ *
+ * Both checksums are stored little-endian.
+ */
+static int cyapa_gen3_check_fw(struct cyapa *cyapa, const struct firmware *fw)
+{
+ struct device *dev = &cyapa->client->dev;
+ u16 csum;
+ u16 csum_expected;
+
+ /* Firmware must match exact 30848 bytes = 482 64-byte blocks. */
+ if (fw->size != CYAPA_FW_SIZE) {
+ dev_err(dev, "invalid firmware size = %zu, expected %u.\n",
+ fw->size, CYAPA_FW_SIZE);
+ return -EINVAL;
+ }
+
+ /* Verify header block */
+ csum_expected = (fw->data[0] << 8) | fw->data[1];
+ csum = cyapa_gen3_csum(&fw->data[2], CYAPA_FW_HDR_SIZE - 2);
+ if (csum != csum_expected) {
+ dev_err(dev, "%s %04x, expected: %04x\n",
+ "invalid firmware header checksum = ",
+ csum, csum_expected);
+ return -EINVAL;
+ }
+
+ /* Verify firmware image */
+ csum_expected = (fw->data[CYAPA_FW_HDR_SIZE - 2] << 8) |
+ fw->data[CYAPA_FW_HDR_SIZE - 1];
+ csum = cyapa_gen3_csum(&fw->data[CYAPA_FW_HDR_SIZE],
+ CYAPA_FW_DATA_SIZE);
+ if (csum != csum_expected) {
+ dev_err(dev, "%s %04x, expected: %04x\n",
+ "invalid firmware header checksum = ",
+ csum, csum_expected);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+/*
+ * Write a |len| byte long buffer |buf| to the device, by chopping it up into a
+ * sequence of smaller |CYAPA_CMD_LEN|-length write commands.
+ *
+ * The data bytes for a write command are prepended with the 1-byte offset
+ * of the data relative to the start of |buf|.
+ */
+static int cyapa_gen3_write_buffer(struct cyapa *cyapa,
+ const u8 *buf, size_t len)
+{
+ int error;
+ size_t i;
+ unsigned char cmd[CYAPA_CMD_LEN + 1];
+ size_t cmd_len;
+
+ for (i = 0; i < len; i += CYAPA_CMD_LEN) {
+ const u8 *payload = &buf[i];
+
+ cmd_len = (len - i >= CYAPA_CMD_LEN) ? CYAPA_CMD_LEN : len - i;
+ cmd[0] = i;
+ memcpy(&cmd[1], payload, cmd_len);
+
+ error = cyapa_i2c_reg_write_block(cyapa, 0, cmd_len + 1, cmd);
+ if (error)
+ return error;
+ }
+ return 0;
+}
+
+/*
+ * A firmware block write command writes 64 bytes of data to a single flash
+ * page in the device. The 78-byte block write command has the format:
+ * <0xff> <CMD> <Key> <Start> <Data> <Data-Checksum> <CMD Checksum>
+ *
+ * <0xff> - every command starts with 0xff
+ * <CMD> - the write command value is 0x39
+ * <Key> - write commands include an 8-byte key: { 00 01 02 03 04 05 06 07 }
+ * <Block> - Memory Block number (address / 64) (16-bit, big-endian)
+ * <Data> - 64 bytes of firmware image data
+ * <Data Checksum> - sum of 64 <Data> bytes, modulo 0xff
+ * <CMD Checksum> - sum of 77 bytes, from 0xff to <Data Checksum>
+ *
+ * Each write command is split into 5 i2c write transactions of up to 16 bytes.
+ * Each transaction starts with an i2c register offset: (00, 10, 20, 30, 40).
+ */
+static int cyapa_gen3_write_fw_block(struct cyapa *cyapa,
+ u16 block, const u8 *data)
+{
+ int ret;
+ struct gen3_write_block_cmd write_block_cmd;
+ u8 status[BL_STATUS_SIZE];
+ int tries;
+ u8 bl_status, bl_error;
+
+ /* Set write command and security key bytes. */
+ write_block_cmd.checksum_seed = GEN3_BL_CMD_CHECKSUM_SEED;
+ write_block_cmd.cmd_code = GEN3_BL_CMD_WRITE_BLOCK;
+ memcpy(write_block_cmd.key, security_key, sizeof(security_key));
+ put_unaligned_be16(block, &write_block_cmd.block_num);
+ memcpy(write_block_cmd.block_data, data, CYAPA_FW_BLOCK_SIZE);
+ write_block_cmd.block_checksum = cyapa_gen3_csum(
+ write_block_cmd.block_data, CYAPA_FW_BLOCK_SIZE);
+ write_block_cmd.cmd_checksum = cyapa_gen3_csum((u8 *)&write_block_cmd,
+ sizeof(write_block_cmd) - 1);
+
+ ret = cyapa_gen3_write_buffer(cyapa, (u8 *)&write_block_cmd,
+ sizeof(write_block_cmd));
+ if (ret)
+ return ret;
+
+ /* Wait for write to finish */
+ tries = 11; /* Programming for one block can take about 100ms. */
+ do {
+ usleep_range(10000, 20000);
+
+ /* Check block write command result status. */
+ ret = cyapa_i2c_reg_read_block(cyapa, BL_HEAD_OFFSET,
+ BL_STATUS_SIZE, status);
+ if (ret != BL_STATUS_SIZE)
+ return (ret < 0) ? ret : -EIO;
+ } while ((status[REG_BL_STATUS] & BL_STATUS_BUSY) && --tries);
+
+ /* Ignore WATCHDOG bit and reserved bits. */
+ bl_status = status[REG_BL_STATUS] & ~BL_STATUS_REV_MASK;
+ bl_error = status[REG_BL_ERROR] & ~BL_ERROR_RESERVED;
+
+ if (bl_status & BL_STATUS_BUSY)
+ ret = -ETIMEDOUT;
+ else if (bl_status != BL_STATUS_RUNNING ||
+ bl_error != BL_ERROR_BOOTLOADING)
+ ret = -EIO;
+ else
+ ret = 0;
+
+ return ret;
+}
+
+static int cyapa_gen3_write_blocks(struct cyapa *cyapa,
+ size_t start_block, size_t block_count,
+ const u8 *image_data)
+{
+ int error;
+ int i;
+
+ for (i = 0; i < block_count; i++) {
+ size_t block = start_block + i;
+ size_t addr = i * CYAPA_FW_BLOCK_SIZE;
+ const u8 *data = &image_data[addr];
+
+ error = cyapa_gen3_write_fw_block(cyapa, block, data);
+ if (error)
+ return error;
+ }
+ return 0;
+}
+
+static int cyapa_gen3_do_fw_update(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ struct device *dev = &cyapa->client->dev;
+ int error;
+
+ /* First write data, starting at byte 128 of fw->data */
+ error = cyapa_gen3_write_blocks(cyapa,
+ CYAPA_FW_DATA_BLOCK_START, CYAPA_FW_DATA_BLOCK_COUNT,
+ &fw->data[CYAPA_FW_HDR_BLOCK_COUNT * CYAPA_FW_BLOCK_SIZE]);
+ if (error) {
+ dev_err(dev, "FW update aborted, write image: %d\n", error);
+ return error;
+ }
+
+ /* Then write checksum */
+ error = cyapa_gen3_write_blocks(cyapa,
+ CYAPA_FW_HDR_BLOCK_START, CYAPA_FW_HDR_BLOCK_COUNT,
+ &fw->data[0]);
+ if (error) {
+ dev_err(dev, "FW update aborted, write checksum: %d\n", error);
+ return error;
+ }
+
+ return 0;
+}
+
+static ssize_t cyapa_gen3_do_calibrate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int tries;
+ int ret;
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
+ if (ret < 0) {
+ dev_err(dev, "Error reading dev status: %d\n", ret);
+ goto out;
+ }
+ if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) {
+ dev_warn(dev, "Trackpad device is busy, device state: 0x%02x\n",
+ ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET,
+ OP_RECALIBRATION_MASK);
+ if (ret < 0) {
+ dev_err(dev, "Failed to send calibrate command: %d\n",
+ ret);
+ goto out;
+ }
+
+ tries = 20; /* max recalibration timeout 2s. */
+ do {
+ /*
+ * For this recalibration, the max time will not exceed 2s.
+ * The average time is approximately 500 - 700 ms, and we
+ * will check the status every 100 - 200ms.
+ */
+ usleep_range(100000, 200000);
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
+ if (ret < 0) {
+ dev_err(dev, "Error reading dev status: %d\n",
+ ret);
+ goto out;
+ }
+ if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL)
+ break;
+ } while (--tries);
+
+ if (tries == 0) {
+ dev_err(dev, "Failed to calibrate. Timeout.\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+ dev_dbg(dev, "Calibration successful.\n");
+
+out:
+ return ret < 0 ? ret : count;
+}
+
+static ssize_t cyapa_gen3_show_baseline(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int max_baseline, min_baseline;
+ int tries;
+ int ret;
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
+ if (ret < 0) {
+ dev_err(dev, "Error reading dev status. err = %d\n", ret);
+ goto out;
+ }
+ if ((ret & CYAPA_DEV_NORMAL) != CYAPA_DEV_NORMAL) {
+ dev_warn(dev, "Trackpad device is busy. device state = 0x%x\n",
+ ret);
+ ret = -EAGAIN;
+ goto out;
+ }
+
+ ret = cyapa_write_byte(cyapa, CYAPA_CMD_SOFT_RESET,
+ OP_REPORT_BASELINE_MASK);
+ if (ret < 0) {
+ dev_err(dev, "Failed to send report baseline command. %d\n",
+ ret);
+ goto out;
+ }
+
+ tries = 3; /* Try for 30 to 60 ms */
+ do {
+ usleep_range(10000, 20000);
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_DEV_STATUS);
+ if (ret < 0) {
+ dev_err(dev, "Error reading dev status. err = %d\n",
+ ret);
+ goto out;
+ }
+ if ((ret & CYAPA_DEV_NORMAL) == CYAPA_DEV_NORMAL)
+ break;
+ } while (--tries);
+
+ if (tries == 0) {
+ dev_err(dev, "Device timed out going to Normal state.\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_MAX_BASELINE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read max baseline. err = %d\n", ret);
+ goto out;
+ }
+ max_baseline = ret;
+
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_MIN_BASELINE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to read min baseline. err = %d\n", ret);
+ goto out;
+ }
+ min_baseline = ret;
+
+ dev_dbg(dev, "Baseline report successful. Max: %d Min: %d\n",
+ max_baseline, min_baseline);
+ ret = scnprintf(buf, PAGE_SIZE, "%d %d\n", max_baseline, min_baseline);
+
+out:
+ return ret;
+}
+
+/*
+ * cyapa_get_wait_time_for_pwr_cmd
+ *
+ * Compute the amount of time we need to wait after updating the touchpad
+ * power mode. The touchpad needs to consume the incoming power mode set
+ * command at the current clock rate.
+ */
+
+static u16 cyapa_get_wait_time_for_pwr_cmd(u8 pwr_mode)
+{
+ switch (pwr_mode) {
+ case PWR_MODE_FULL_ACTIVE: return 20;
+ case PWR_MODE_BTN_ONLY: return 20;
+ case PWR_MODE_OFF: return 20;
+ default: return cyapa_pwr_cmd_to_sleep_time(pwr_mode) + 50;
+ }
+}
+
+/*
+ * Set device power mode
+ *
+ * Write to the field to configure power state. Power states include :
+ * Full : Max scans and report rate.
+ * Idle : Report rate set by user specified time.
+ * ButtonOnly : No scans for fingers. When the button is triggered,
+ * a slave interrupt is asserted to notify host to wake up.
+ * Off : Only awake for i2c commands from host. No function for button
+ * or touch sensors.
+ *
+ * The power_mode command should conform to the following :
+ * Full : 0x3f
+ * Idle : Configurable from 20 to 1000ms. See note below for
+ * cyapa_sleep_time_to_pwr_cmd and cyapa_pwr_cmd_to_sleep_time
+ * ButtonOnly : 0x01
+ * Off : 0x00
+ *
+ * Device power mode can only be set when device is in operational mode.
+ */
+static int cyapa_gen3_set_power_mode(struct cyapa *cyapa, u8 power_mode,
+ u16 always_unused)
+{
+ int ret;
+ u8 power;
+ int tries;
+ u16 sleep_time;
+
+ always_unused = 0;
+ if (cyapa->state != CYAPA_STATE_OP)
+ return 0;
+
+ tries = SET_POWER_MODE_TRIES;
+ while (tries--) {
+ ret = cyapa_read_byte(cyapa, CYAPA_CMD_POWER_MODE);
+ if (ret >= 0)
+ break;
+ usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY);
+ }
+ if (ret < 0)
+ return ret;
+
+ /*
+ * Return early if the power mode to set is the same as the current
+ * one.
+ */
+ if ((ret & PWR_MODE_MASK) == power_mode)
+ return 0;
+
+ sleep_time = cyapa_get_wait_time_for_pwr_cmd(ret & PWR_MODE_MASK);
+ power = ret;
+ power &= ~PWR_MODE_MASK;
+ power |= power_mode & PWR_MODE_MASK;
+ tries = SET_POWER_MODE_TRIES;
+ while (tries--) {
+ ret = cyapa_write_byte(cyapa, CYAPA_CMD_POWER_MODE, power);
+ if (!ret)
+ break;
+ usleep_range(SET_POWER_MODE_DELAY, 2 * SET_POWER_MODE_DELAY);
+ }
+
+ /*
+ * Wait for the newly set power command to go in at the previous
+ * clock speed (scanrate) used by the touchpad firmware. Not
+ * doing so before issuing the next command may result in errors
+ * depending on the command's content.
+ */
+ msleep(sleep_time);
+ return ret;
+}
+
+static int cyapa_gen3_get_query_data(struct cyapa *cyapa)
+{
+ u8 query_data[QUERY_DATA_SIZE];
+ int ret;
+
+ if (cyapa->state != CYAPA_STATE_OP)
+ return -EBUSY;
+
+ ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_QUERY, query_data);
+ if (ret != QUERY_DATA_SIZE)
+ return (ret < 0) ? ret : -EIO;
+
+ memcpy(&cyapa->product_id[0], &query_data[0], 5);
+ cyapa->product_id[5] = '-';
+ memcpy(&cyapa->product_id[6], &query_data[5], 6);
+ cyapa->product_id[12] = '-';
+ memcpy(&cyapa->product_id[13], &query_data[11], 2);
+ cyapa->product_id[15] = '\0';
+
+ cyapa->fw_maj_ver = query_data[15];
+ cyapa->fw_min_ver = query_data[16];
+
+ cyapa->btn_capability = query_data[19] & CAPABILITY_BTN_MASK;
+
+ cyapa->gen = query_data[20] & 0x0f;
+
+ cyapa->max_abs_x = ((query_data[21] & 0xf0) << 4) | query_data[22];
+ cyapa->max_abs_y = ((query_data[21] & 0x0f) << 8) | query_data[23];
+
+ cyapa->physical_size_x =
+ ((query_data[24] & 0xf0) << 4) | query_data[25];
+ cyapa->physical_size_y =
+ ((query_data[24] & 0x0f) << 8) | query_data[26];
+
+ cyapa->max_z = 255;
+
+ return 0;
+}
+
+static int cyapa_gen3_bl_query_data(struct cyapa *cyapa)
+{
+ u8 bl_data[CYAPA_CMD_LEN];
+ int ret;
+
+ ret = cyapa_i2c_reg_read_block(cyapa, 0, CYAPA_CMD_LEN, bl_data);
+ if (ret != CYAPA_CMD_LEN)
+ return (ret < 0) ? ret : -EIO;
+
+ /*
+ * This value will be updated again when entered application mode.
+ * If TP failed to enter application mode, this fw version values
+ * can be used as a reference.
+ * This firmware version valid when fw image checksum is valid.
+ */
+ if (bl_data[REG_BL_STATUS] ==
+ (BL_STATUS_RUNNING | BL_STATUS_CSUM_VALID)) {
+ cyapa->fw_maj_ver = bl_data[GEN3_BL_IDLE_FW_MAJ_VER_OFFSET];
+ cyapa->fw_min_ver = bl_data[GEN3_BL_IDLE_FW_MIN_VER_OFFSET];
+ }
+
+ return 0;
+}
+
+/*
+ * Check if device is operational.
+ *
+ * An operational device is responding, has exited bootloader, and has
+ * firmware supported by this driver.
+ *
+ * Returns:
+ * -EBUSY no device or in bootloader
+ * -EIO failure while reading from device
+ * -EAGAIN device is still in bootloader
+ * if ->state = CYAPA_STATE_BL_IDLE, device has invalid firmware
+ * -EINVAL device is in operational mode, but not supported by this driver
+ * 0 device is supported
+ */
+static int cyapa_gen3_do_operational_check(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ int error;
+
+ switch (cyapa->state) {
+ case CYAPA_STATE_BL_ACTIVE:
+ error = cyapa_gen3_bl_deactivate(cyapa);
+ if (error) {
+ dev_err(dev, "failed to bl_deactivate: %d\n", error);
+ return error;
+ }
+
+ /* Fallthrough state */
+ case CYAPA_STATE_BL_IDLE:
+ /* Try to get firmware version in bootloader mode. */
+ cyapa_gen3_bl_query_data(cyapa);
+
+ error = cyapa_gen3_bl_exit(cyapa);
+ if (error) {
+ dev_err(dev, "failed to bl_exit: %d\n", error);
+ return error;
+ }
+
+ /* Fallthrough state */
+ case CYAPA_STATE_OP:
+ /*
+ * Reading query data before going back to the full mode
+ * may cause problems, so we set the power mode first here.
+ */
+ error = cyapa_gen3_set_power_mode(cyapa,
+ PWR_MODE_FULL_ACTIVE, 0);
+ if (error)
+ dev_err(dev, "%s: set full power mode failed: %d\n",
+ __func__, error);
+ error = cyapa_gen3_get_query_data(cyapa);
+ if (error < 0)
+ return error;
+
+ /* Only support firmware protocol gen3 */
+ if (cyapa->gen != CYAPA_GEN3) {
+ dev_err(dev, "unsupported protocol version (%d)",
+ cyapa->gen);
+ return -EINVAL;
+ }
+
+ /* Only support product ID starting with CYTRA */
+ if (memcmp(cyapa->product_id, product_id,
+ strlen(product_id)) != 0) {
+ dev_err(dev, "unsupported product ID (%s)\n",
+ cyapa->product_id);
+ return -EINVAL;
+ }
+
+ return 0;
+
+ default:
+ return -EIO;
+ }
+ return 0;
+}
+
+/*
+ * Return false, do not continue process
+ * Return true, continue process.
+ */
+static bool cyapa_gen3_irq_cmd_handler(struct cyapa *cyapa)
+{
+ /* Not gen3 irq command response, skip for continue. */
+ if (cyapa->gen != CYAPA_GEN3)
+ return true;
+
+ if (cyapa->operational)
+ return true;
+
+ /*
+ * Driver in detecting or other interface function processing,
+ * so, stop cyapa_gen3_irq_handler to continue process to
+ * avoid unwanted to error detecting and processing.
+ *
+ * And also, avoid the periodicly accerted interrupts to be processed
+ * as touch inputs when gen3 failed to launch into application mode,
+ * which will cause gen3 stays in bootloader mode.
+ */
+ return false;
+}
+
+static int cyapa_gen3_irq_handler(struct cyapa *cyapa)
+{
+ struct input_dev *input = cyapa->input;
+ struct device *dev = &cyapa->client->dev;
+ struct cyapa_reg_data data;
+ int num_fingers;
+ int ret;
+ int i;
+
+ ret = cyapa_read_block(cyapa, CYAPA_CMD_GROUP_DATA, (u8 *)&data);
+ if (ret != sizeof(data)) {
+ dev_err(dev, "failed to read report data, (%d)\n", ret);
+ return -EINVAL;
+ }
+
+ if ((data.device_status & OP_STATUS_SRC) != OP_STATUS_SRC ||
+ (data.device_status & OP_STATUS_DEV) != CYAPA_DEV_NORMAL ||
+ (data.finger_btn & OP_DATA_VALID) != OP_DATA_VALID) {
+ dev_err(dev, "invalid device state bytes, %02x %02x\n",
+ data.device_status, data.finger_btn);
+ return -EINVAL;
+ }
+
+ num_fingers = (data.finger_btn >> 4) & 0x0f;
+ for (i = 0; i < num_fingers; i++) {
+ const struct cyapa_touch *touch = &data.touches[i];
+ /* Note: touch->id range is 1 to 15; slots are 0 to 14. */
+ int slot = touch->id - 1;
+
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+ input_report_abs(input, ABS_MT_POSITION_X,
+ ((touch->xy_hi & 0xf0) << 4) | touch->x_lo);
+ input_report_abs(input, ABS_MT_POSITION_Y,
+ ((touch->xy_hi & 0x0f) << 8) | touch->y_lo);
+ input_report_abs(input, ABS_MT_PRESSURE, touch->pressure);
+ }
+
+ input_mt_sync_frame(input);
+
+ if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK)
+ input_report_key(input, BTN_LEFT,
+ !!(data.finger_btn & OP_DATA_LEFT_BTN));
+ if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK)
+ input_report_key(input, BTN_MIDDLE,
+ !!(data.finger_btn & OP_DATA_MIDDLE_BTN));
+ if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK)
+ input_report_key(input, BTN_RIGHT,
+ !!(data.finger_btn & OP_DATA_RIGHT_BTN));
+ input_sync(input);
+
+ return 0;
+}
+
+static int cyapa_gen3_initialize(struct cyapa *cyapa) { return 0; }
+static int cyapa_gen3_bl_initiate(struct cyapa *cyapa,
+ const struct firmware *fw) { return 0; }
+static int cyapa_gen3_empty_output_data(struct cyapa *cyapa,
+ u8 *buf, int *len, cb_sort func) { return 0; }
+
+const struct cyapa_dev_ops cyapa_gen3_ops = {
+ .check_fw = cyapa_gen3_check_fw,
+ .bl_enter = cyapa_gen3_bl_enter,
+ .bl_activate = cyapa_gen3_bl_activate,
+ .update_fw = cyapa_gen3_do_fw_update,
+ .bl_deactivate = cyapa_gen3_bl_deactivate,
+ .bl_initiate = cyapa_gen3_bl_initiate,
+
+ .show_baseline = cyapa_gen3_show_baseline,
+ .calibrate_store = cyapa_gen3_do_calibrate,
+
+ .initialize = cyapa_gen3_initialize,
+
+ .state_parse = cyapa_gen3_state_parse,
+ .operational_check = cyapa_gen3_do_operational_check,
+
+ .irq_handler = cyapa_gen3_irq_handler,
+ .irq_cmd_handler = cyapa_gen3_irq_cmd_handler,
+ .sort_empty_output_data = cyapa_gen3_empty_output_data,
+ .set_power_mode = cyapa_gen3_set_power_mode,
+};
diff --git a/drivers/input/mouse/cyapa_gen5.c b/drivers/input/mouse/cyapa_gen5.c
new file mode 100644
index 000000000000..ddf5393a1180
--- /dev/null
+++ b/drivers/input/mouse/cyapa_gen5.c
@@ -0,0 +1,2777 @@
+/*
+ * Cypress APA trackpad with I2C interface
+ *
+ * Author: Dudley Du <dudl@cypress.com>
+ *
+ * Copyright (C) 2014 Cypress Semiconductor, 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/delay.h>
+#include <linux/i2c.h>
+#include <linux/input.h>
+#include <linux/input/mt.h>
+#include <linux/mutex.h>
+#include <linux/completion.h>
+#include <linux/slab.h>
+#include <linux/unaligned/access_ok.h>
+#include <linux/crc-itu-t.h>
+#include "cyapa.h"
+
+
+/* Macro of Gen5 */
+#define RECORD_EVENT_NONE 0
+#define RECORD_EVENT_TOUCHDOWN 1
+#define RECORD_EVENT_DISPLACE 2
+#define RECORD_EVENT_LIFTOFF 3
+
+#define CYAPA_TSG_FLASH_MAP_BLOCK_SIZE 0x80
+#define CYAPA_TSG_IMG_FW_HDR_SIZE 13
+#define CYAPA_TSG_FW_ROW_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE)
+#define CYAPA_TSG_IMG_START_ROW_NUM 0x002e
+#define CYAPA_TSG_IMG_END_ROW_NUM 0x01fe
+#define CYAPA_TSG_IMG_APP_INTEGRITY_ROW_NUM 0x01ff
+#define CYAPA_TSG_IMG_MAX_RECORDS (CYAPA_TSG_IMG_END_ROW_NUM - \
+ CYAPA_TSG_IMG_START_ROW_NUM + 1 + 1)
+#define CYAPA_TSG_IMG_READ_SIZE (CYAPA_TSG_FLASH_MAP_BLOCK_SIZE / 2)
+#define CYAPA_TSG_START_OF_APPLICATION 0x1700
+#define CYAPA_TSG_APP_INTEGRITY_SIZE 60
+#define CYAPA_TSG_FLASH_MAP_METADATA_SIZE 60
+#define CYAPA_TSG_BL_KEY_SIZE 8
+
+#define CYAPA_TSG_MAX_CMD_SIZE 256
+
+#define GEN5_BL_CMD_VERIFY_APP_INTEGRITY 0x31
+#define GEN5_BL_CMD_GET_BL_INFO 0x38
+#define GEN5_BL_CMD_PROGRAM_VERIFY_ROW 0x39
+#define GEN5_BL_CMD_LAUNCH_APP 0x3b
+#define GEN5_BL_CMD_INITIATE_BL 0x48
+
+#define GEN5_HID_DESCRIPTOR_ADDR 0x0001
+#define GEN5_REPORT_DESCRIPTOR_ADDR 0x0002
+#define GEN5_INPUT_REPORT_ADDR 0x0003
+#define GEN5_OUTPUT_REPORT_ADDR 0x0004
+#define GEN5_CMD_DATA_ADDR 0x0006
+
+#define GEN5_TOUCH_REPORT_HEAD_SIZE 7
+#define GEN5_TOUCH_REPORT_MAX_SIZE 127
+#define GEN5_BTN_REPORT_HEAD_SIZE 6
+#define GEN5_BTN_REPORT_MAX_SIZE 14
+#define GEN5_WAKEUP_EVENT_SIZE 4
+#define GEN5_RAW_DATA_HEAD_SIZE 24
+
+#define GEN5_BL_CMD_REPORT_ID 0x40
+#define GEN5_BL_RESP_REPORT_ID 0x30
+#define GEN5_APP_CMD_REPORT_ID 0x2f
+#define GEN5_APP_RESP_REPORT_ID 0x1f
+
+#define GEN5_APP_DEEP_SLEEP_REPORT_ID 0xf0
+#define GEN5_DEEP_SLEEP_RESP_LENGTH 5
+
+#define GEN5_CMD_GET_PARAMETER 0x05
+#define GEN5_CMD_SET_PARAMETER 0x06
+#define GEN5_PARAMETER_ACT_INTERVL_ID 0x4d
+#define GEN5_PARAMETER_ACT_INTERVL_SIZE 1
+#define GEN5_PARAMETER_ACT_LFT_INTERVL_ID 0x4f
+#define GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE 2
+#define GEN5_PARAMETER_LP_INTRVL_ID 0x4c
+#define GEN5_PARAMETER_LP_INTRVL_SIZE 2
+
+#define GEN5_PARAMETER_DISABLE_PIP_REPORT 0x08
+
+#define GEN5_POWER_STATE_ACTIVE 0x01
+#define GEN5_POWER_STATE_LOOK_FOR_TOUCH 0x02
+#define GEN5_POWER_STATE_READY 0x03
+#define GEN5_POWER_STATE_IDLE 0x04
+#define GEN5_POWER_STATE_BTN_ONLY 0x05
+#define GEN5_POWER_STATE_OFF 0x06
+
+#define GEN5_DEEP_SLEEP_STATE_MASK 0x03
+#define GEN5_DEEP_SLEEP_STATE_ON 0x00
+#define GEN5_DEEP_SLEEP_STATE_OFF 0x01
+
+#define GEN5_DEEP_SLEEP_OPCODE 0x08
+#define GEN5_DEEP_SLEEP_OPCODE_MASK 0x0f
+
+#define GEN5_POWER_READY_MAX_INTRVL_TIME 50 /* Unit: ms */
+#define GEN5_POWER_IDLE_MAX_INTRVL_TIME 250 /* Unit: ms */
+
+#define GEN5_CMD_REPORT_ID_OFFSET 4
+
+#define GEN5_RESP_REPORT_ID_OFFSET 2
+#define GEN5_RESP_RSVD_OFFSET 3
+#define GEN5_RESP_RSVD_KEY 0x00
+#define GEN5_RESP_BL_SOP_OFFSET 4
+#define GEN5_SOP_KEY 0x01 /* Start of Packet */
+#define GEN5_EOP_KEY 0x17 /* End of Packet */
+#define GEN5_RESP_APP_CMD_OFFSET 4
+#define GET_GEN5_CMD_CODE(reg) ((reg) & 0x7f)
+
+#define VALID_CMD_RESP_HEADER(resp, cmd) \
+ (((resp)[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID) && \
+ ((resp)[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) && \
+ (GET_GEN5_CMD_CODE((resp)[GEN5_RESP_APP_CMD_OFFSET]) == (cmd)))
+
+#define GEN5_MIN_BL_CMD_LENGTH 13
+#define GEN5_MIN_BL_RESP_LENGTH 11
+#define GEN5_MIN_APP_CMD_LENGTH 7
+#define GEN5_MIN_APP_RESP_LENGTH 5
+#define GEN5_UNSUPPORTED_CMD_RESP_LENGTH 6
+
+#define GEN5_RESP_LENGTH_OFFSET 0x00
+#define GEN5_RESP_LENGTH_SIZE 2
+
+#define GEN5_HID_DESCRIPTOR_SIZE 32
+#define GEN5_BL_HID_REPORT_ID 0xff
+#define GEN5_APP_HID_REPORT_ID 0xf7
+#define GEN5_BL_MAX_OUTPUT_LENGTH 0x0100
+#define GEN5_APP_MAX_OUTPUT_LENGTH 0x00fe
+
+#define GEN5_BL_REPORT_DESCRIPTOR_SIZE 0x1d
+#define GEN5_BL_REPORT_DESCRIPTOR_ID 0xfe
+#define GEN5_APP_REPORT_DESCRIPTOR_SIZE 0xee
+#define GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE 0xfa
+#define GEN5_APP_REPORT_DESCRIPTOR_ID 0xf6
+
+#define GEN5_TOUCH_REPORT_ID 0x01
+#define GEN5_BTN_REPORT_ID 0x03
+#define GEN5_WAKEUP_EVENT_REPORT_ID 0x04
+#define GEN5_OLD_PUSH_BTN_REPORT_ID 0x05
+#define GEN5_PUSH_BTN_REPORT_ID 0x06
+
+#define GEN5_CMD_COMPLETE_SUCCESS(status) ((status) == 0x00)
+
+#define GEN5_BL_INITIATE_RESP_LEN 11
+#define GEN5_BL_FAIL_EXIT_RESP_LEN 11
+#define GEN5_BL_FAIL_EXIT_STATUS_CODE 0x0c
+#define GEN5_BL_VERIFY_INTEGRITY_RESP_LEN 12
+#define GEN5_BL_INTEGRITY_CHEKC_PASS 0x00
+#define GEN5_BL_BLOCK_WRITE_RESP_LEN 11
+#define GEN5_BL_READ_APP_INFO_RESP_LEN 31
+#define GEN5_CMD_CALIBRATE 0x28
+#define CYAPA_SENSING_MODE_MUTUAL_CAP_FINE 0x00
+#define CYAPA_SENSING_MODE_SELF_CAP 0x02
+
+#define GEN5_CMD_RETRIEVE_DATA_STRUCTURE 0x24
+#define GEN5_RETRIEVE_MUTUAL_PWC_DATA 0x00
+#define GEN5_RETRIEVE_SELF_CAP_PWC_DATA 0x01
+
+#define GEN5_RETRIEVE_DATA_ELEMENT_SIZE_MASK 0x07
+
+#define GEN5_CMD_EXECUTE_PANEL_SCAN 0x2a
+#define GEN5_CMD_RETRIEVE_PANEL_SCAN 0x2b
+#define GEN5_PANEL_SCAN_MUTUAL_RAW_DATA 0x00
+#define GEN5_PANEL_SCAN_MUTUAL_BASELINE 0x01
+#define GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT 0x02
+#define GEN5_PANEL_SCAN_SELF_RAW_DATA 0x03
+#define GEN5_PANEL_SCAN_SELF_BASELINE 0x04
+#define GEN5_PANEL_SCAN_SELF_DIFFCOUNT 0x05
+
+/* The offset only valid for reterive PWC and panel scan commands */
+#define GEN5_RESP_DATA_STRUCTURE_OFFSET 10
+#define GEN5_PWC_DATA_ELEMENT_SIZE_MASK 0x07
+
+#define GEN5_NUMBER_OF_TOUCH_OFFSET 5
+#define GEN5_NUMBER_OF_TOUCH_MASK 0x1f
+#define GEN5_BUTTONS_OFFSET 5
+#define GEN5_BUTTONS_MASK 0x0f
+#define GEN5_GET_EVENT_ID(reg) (((reg) >> 5) & 0x03)
+#define GEN5_GET_TOUCH_ID(reg) ((reg) & 0x1f)
+
+#define GEN5_PRODUCT_FAMILY_MASK 0xf000
+#define GEN5_PRODUCT_FAMILY_TRACKPAD 0x1000
+
+#define TSG_INVALID_CMD 0xff
+
+struct cyapa_gen5_touch_record {
+ /*
+ * Bit 7 - 3: reserved
+ * Bit 2 - 0: touch type;
+ * 0 : standard finger;
+ * 1 - 15 : reserved.
+ */
+ u8 touch_type;
+
+ /*
+ * Bit 7: indicates touch liftoff status.
+ * 0 : touch is currently on the panel.
+ * 1 : touch record indicates a liftoff.
+ * Bit 6 - 5: indicates an event associated with this touch instance
+ * 0 : no event
+ * 1 : touchdown
+ * 2 : significant displacement (> active distance)
+ * 3 : liftoff (record reports last known coordinates)
+ * Bit 4 - 0: An arbitrary ID tag associated with a finger
+ * to allow tracking a touch as it moves around the panel.
+ */
+ u8 touch_tip_event_id;
+
+ /* Bit 7 - 0 of X-axis coordinate of the touch in pixel. */
+ u8 x_lo;
+
+ /* Bit 15 - 8 of X-axis coordinate of the touch in pixel. */
+ u8 x_hi;
+
+ /* Bit 7 - 0 of Y-axis coordinate of the touch in pixel. */
+ u8 y_lo;
+
+ /* Bit 15 - 8 of Y-axis coordinate of the touch in pixel. */
+ u8 y_hi;
+
+ /* Touch intensity in counts, pressure value. */
+ u8 z;
+
+ /*
+ * The length of the major axis of the ellipse of contact between
+ * the finger and the panel (ABS_MT_TOUCH_MAJOR).
+ */
+ u8 major_axis_len;
+
+ /*
+ * The length of the minor axis of the ellipse of contact between
+ * the finger and the panel (ABS_MT_TOUCH_MINOR).
+ */
+ u8 minor_axis_len;
+
+ /*
+ * The length of the major axis of the approaching tool.
+ * (ABS_MT_WIDTH_MAJOR)
+ */
+ u8 major_tool_len;
+
+ /*
+ * The length of the minor axis of the approaching tool.
+ * (ABS_MT_WIDTH_MINOR)
+ */
+ u8 minor_tool_len;
+
+ /*
+ * The angle between the panel vertical axis and
+ * the major axis of the contact ellipse. This value is an 8-bit
+ * signed integer. The range is -127 to +127 (corresponding to
+ * -90 degree and +90 degree respectively).
+ * The positive direction is clockwise from the vertical axis.
+ * If the ellipse of contact degenerates into a circle,
+ * orientation is reported as 0.
+ */
+ u8 orientation;
+} __packed;
+
+struct cyapa_gen5_report_data {
+ u8 report_head[GEN5_TOUCH_REPORT_HEAD_SIZE];
+ struct cyapa_gen5_touch_record touch_records[10];
+} __packed;
+
+struct cyapa_tsg_bin_image_head {
+ u8 head_size; /* Unit: bytes, including itself. */
+ u8 ttda_driver_major_version; /* Reserved as 0. */
+ u8 ttda_driver_minor_version; /* Reserved as 0. */
+ u8 fw_major_version;
+ u8 fw_minor_version;
+ u8 fw_revision_control_number[8];
+} __packed;
+
+struct cyapa_tsg_bin_image_data_record {
+ u8 flash_array_id;
+ __be16 row_number;
+ /* The number of bytes of flash data contained in this record. */
+ __be16 record_len;
+ /* The flash program data. */
+ u8 record_data[CYAPA_TSG_FW_ROW_SIZE];
+} __packed;
+
+struct cyapa_tsg_bin_image {
+ struct cyapa_tsg_bin_image_head image_head;
+ struct cyapa_tsg_bin_image_data_record records[0];
+} __packed;
+
+struct gen5_bl_packet_start {
+ u8 sop; /* Start of packet, must be 01h */
+ u8 cmd_code;
+ __le16 data_length; /* Size of data parameter start from data[0] */
+} __packed;
+
+struct gen5_bl_packet_end {
+ __le16 crc;
+ u8 eop; /* End of packet, must be 17h */
+} __packed;
+
+struct gen5_bl_cmd_head {
+ __le16 addr; /* Output report register address, must be 0004h */
+ /* Size of packet not including output report register address */
+ __le16 length;
+ u8 report_id; /* Bootloader output report id, must be 40h */
+ u8 rsvd; /* Reserved, must be 0 */
+ struct gen5_bl_packet_start packet_start;
+ u8 data[0]; /* Command data variable based on commands */
+} __packed;
+
+/* Initiate bootload command data structure. */
+struct gen5_bl_initiate_cmd_data {
+ /* Key must be "A5h 01h 02h 03h FFh FEh FDh 5Ah" */
+ u8 key[CYAPA_TSG_BL_KEY_SIZE];
+ u8 metadata_raw_parameter[CYAPA_TSG_FLASH_MAP_METADATA_SIZE];
+ __le16 metadata_crc;
+} __packed;
+
+struct gen5_bl_metadata_row_params {
+ __le16 size;
+ __le16 maximum_size;
+ __le32 app_start;
+ __le16 app_len;
+ __le16 app_crc;
+ __le32 app_entry;
+ __le32 upgrade_start;
+ __le16 upgrade_len;
+ __le16 entry_row_crc;
+ u8 padding[36]; /* Padding data must be 0 */
+ __le16 metadata_crc; /* CRC starts at offset of 60 */
+} __packed;
+
+/* Bootload program and verify row command data structure */
+struct gen5_bl_flash_row_head {
+ u8 flash_array_id;
+ __le16 flash_row_id;
+ u8 flash_data[0];
+} __packed;
+
+struct gen5_app_cmd_head {
+ __le16 addr; /* Output report register address, must be 0004h */
+ /* Size of packet not including output report register address */
+ __le16 length;
+ u8 report_id; /* Application output report id, must be 2Fh */
+ u8 rsvd; /* Reserved, must be 0 */
+ /*
+ * Bit 7: reserved, must be 0.
+ * Bit 6-0: command code.
+ */
+ u8 cmd_code;
+ u8 parameter_data[0]; /* Parameter data variable based on cmd_code */
+} __packed;
+
+/* Applicaton get/set parameter command data structure */
+struct gen5_app_set_parameter_data {
+ u8 parameter_id;
+ u8 parameter_size;
+ __le32 value;
+} __packed;
+
+struct gen5_app_get_parameter_data {
+ u8 parameter_id;
+} __packed;
+
+struct gen5_retrieve_panel_scan_data {
+ __le16 read_offset;
+ __le16 read_elements;
+ u8 data_id;
+} __packed;
+
+/* Variables to record latest gen5 trackpad power states. */
+#define GEN5_DEV_SET_PWR_STATE(cyapa, s) ((cyapa)->dev_pwr_mode = (s))
+#define GEN5_DEV_GET_PWR_STATE(cyapa) ((cyapa)->dev_pwr_mode)
+#define GEN5_DEV_SET_SLEEP_TIME(cyapa, t) ((cyapa)->dev_sleep_time = (t))
+#define GEN5_DEV_GET_SLEEP_TIME(cyapa) ((cyapa)->dev_sleep_time)
+#define GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) \
+ (((cyapa)->dev_sleep_time) == UNINIT_SLEEP_TIME)
+
+
+static u8 cyapa_gen5_bl_cmd_key[] = { 0xa5, 0x01, 0x02, 0x03,
+ 0xff, 0xfe, 0xfd, 0x5a };
+
+static int cyapa_gen5_initialize(struct cyapa *cyapa)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+
+ init_completion(&gen5_pip->cmd_ready);
+ atomic_set(&gen5_pip->cmd_issued, 0);
+ mutex_init(&gen5_pip->cmd_lock);
+
+ gen5_pip->resp_sort_func = NULL;
+ gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
+ gen5_pip->resp_data = NULL;
+ gen5_pip->resp_len = NULL;
+
+ cyapa->dev_pwr_mode = UNINIT_PWR_MODE;
+ cyapa->dev_sleep_time = UNINIT_SLEEP_TIME;
+
+ return 0;
+}
+
+/* Return negative errno, or else the number of bytes read. */
+static ssize_t cyapa_i2c_pip_read(struct cyapa *cyapa, u8 *buf, size_t size)
+{
+ int ret;
+
+ if (size == 0)
+ return 0;
+
+ if (!buf || size > CYAPA_REG_MAP_SIZE)
+ return -EINVAL;
+
+ ret = i2c_master_recv(cyapa->client, buf, size);
+
+ if (ret != size)
+ return (ret < 0) ? ret : -EIO;
+
+ return size;
+}
+
+/**
+ * Return a negative errno code else zero on success.
+ */
+static ssize_t cyapa_i2c_pip_write(struct cyapa *cyapa, u8 *buf, size_t size)
+{
+ int ret;
+
+ if (!buf || !size)
+ return -EINVAL;
+
+ ret = i2c_master_send(cyapa->client, buf, size);
+
+ if (ret != size)
+ return (ret < 0) ? ret : -EIO;
+
+ return 0;
+}
+
+/**
+ * This function is aimed to dump all not read data in Gen5 trackpad
+ * before send any command, otherwise, the interrupt line will be blocked.
+ */
+static int cyapa_empty_pip_output_data(struct cyapa *cyapa,
+ u8 *buf, int *len, cb_sort func)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int length;
+ int report_count;
+ int empty_count;
+ int buf_len;
+ int error;
+
+ buf_len = 0;
+ if (len) {
+ buf_len = (*len < CYAPA_REG_MAP_SIZE) ?
+ *len : CYAPA_REG_MAP_SIZE;
+ *len = 0;
+ }
+
+ report_count = 8; /* max 7 pending data before command response data */
+ empty_count = 0;
+ do {
+ /*
+ * Depending on testing in cyapa driver, there are max 5 "02 00"
+ * packets between two valid buffered data report in firmware.
+ * So in order to dump all buffered data out and
+ * make interrupt line release for reassert again,
+ * we must set the empty_count check value bigger than 5 to
+ * make it work. Otherwise, in some situation,
+ * the interrupt line may unable to reactive again,
+ * which will cause trackpad device unable to
+ * report data any more.
+ * for example, it may happen in EFT and ESD testing.
+ */
+ if (empty_count > 5)
+ return 0;
+
+ error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf,
+ GEN5_RESP_LENGTH_SIZE);
+ if (error < 0)
+ return error;
+
+ length = get_unaligned_le16(gen5_pip->empty_buf);
+ if (length == GEN5_RESP_LENGTH_SIZE) {
+ empty_count++;
+ continue;
+ } else if (length > CYAPA_REG_MAP_SIZE) {
+ /* Should not happen */
+ return -EINVAL;
+ } else if (length == 0) {
+ /* Application or bootloader launch data polled out. */
+ length = GEN5_RESP_LENGTH_SIZE;
+ if (buf && buf_len && func &&
+ func(cyapa, gen5_pip->empty_buf, length)) {
+ length = min(buf_len, length);
+ memcpy(buf, gen5_pip->empty_buf, length);
+ *len = length;
+ /* Response found, success. */
+ return 0;
+ }
+ continue;
+ }
+
+ error = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
+ if (error < 0)
+ return error;
+
+ report_count--;
+ empty_count = 0;
+ length = get_unaligned_le16(gen5_pip->empty_buf);
+ if (length <= GEN5_RESP_LENGTH_SIZE) {
+ empty_count++;
+ } else if (buf && buf_len && func &&
+ func(cyapa, gen5_pip->empty_buf, length)) {
+ length = min(buf_len, length);
+ memcpy(buf, gen5_pip->empty_buf, length);
+ *len = length;
+ /* Response found, success. */
+ return 0;
+ }
+
+ error = -EINVAL;
+ } while (report_count);
+
+ return error;
+}
+
+static int cyapa_do_i2c_pip_cmd_irq_sync(
+ struct cyapa *cyapa,
+ u8 *cmd, size_t cmd_len,
+ unsigned long timeout)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int error;
+
+ /* Wait for interrupt to set ready completion */
+ init_completion(&gen5_pip->cmd_ready);
+
+ atomic_inc(&gen5_pip->cmd_issued);
+ error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
+ if (error) {
+ atomic_dec(&gen5_pip->cmd_issued);
+ return (error < 0) ? error : -EIO;
+ }
+
+ /* Wait for interrupt to indicate command is completed. */
+ timeout = wait_for_completion_timeout(&gen5_pip->cmd_ready,
+ msecs_to_jiffies(timeout));
+ if (timeout == 0) {
+ atomic_dec(&gen5_pip->cmd_issued);
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int cyapa_do_i2c_pip_cmd_polling(
+ struct cyapa *cyapa,
+ u8 *cmd, size_t cmd_len,
+ u8 *resp_data, int *resp_len,
+ unsigned long timeout,
+ cb_sort func)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int tries;
+ int length;
+ int error;
+
+ atomic_inc(&gen5_pip->cmd_issued);
+ error = cyapa_i2c_pip_write(cyapa, cmd, cmd_len);
+ if (error) {
+ atomic_dec(&gen5_pip->cmd_issued);
+ return error < 0 ? error : -EIO;
+ }
+
+ length = resp_len ? *resp_len : 0;
+ if (resp_data && resp_len && length != 0 && func) {
+ tries = timeout / 5;
+ do {
+ usleep_range(3000, 5000);
+ *resp_len = length;
+ error = cyapa_empty_pip_output_data(cyapa,
+ resp_data, resp_len, func);
+ if (error || *resp_len == 0)
+ continue;
+ else
+ break;
+ } while (--tries > 0);
+ if ((error || *resp_len == 0) || tries <= 0)
+ error = error ? error : -ETIMEDOUT;
+ }
+
+ atomic_dec(&gen5_pip->cmd_issued);
+ return error;
+}
+
+static int cyapa_i2c_pip_cmd_irq_sync(
+ struct cyapa *cyapa,
+ u8 *cmd, int cmd_len,
+ u8 *resp_data, int *resp_len,
+ unsigned long timeout,
+ cb_sort func,
+ bool irq_mode)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int error;
+
+ if (!cmd || !cmd_len)
+ return -EINVAL;
+
+ /* Commands must be serialized. */
+ error = mutex_lock_interruptible(&gen5_pip->cmd_lock);
+ if (error)
+ return error;
+
+ gen5_pip->resp_sort_func = func;
+ gen5_pip->resp_data = resp_data;
+ gen5_pip->resp_len = resp_len;
+
+ if (cmd_len >= GEN5_MIN_APP_CMD_LENGTH &&
+ cmd[4] == GEN5_APP_CMD_REPORT_ID) {
+ /* Application command */
+ gen5_pip->in_progress_cmd = cmd[6] & 0x7f;
+ } else if (cmd_len >= GEN5_MIN_BL_CMD_LENGTH &&
+ cmd[4] == GEN5_BL_CMD_REPORT_ID) {
+ /* Bootloader command */
+ gen5_pip->in_progress_cmd = cmd[7];
+ }
+
+ /* Send command data, wait and read output response data's length. */
+ if (irq_mode) {
+ gen5_pip->is_irq_mode = true;
+ error = cyapa_do_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
+ timeout);
+ if (error == -ETIMEDOUT && resp_data &&
+ resp_len && *resp_len != 0 && func) {
+ /*
+ * For some old version, there was no interrupt for
+ * the command response data, so need to poll here
+ * to try to get the response data.
+ */
+ error = cyapa_empty_pip_output_data(cyapa,
+ resp_data, resp_len, func);
+ if (error || *resp_len == 0)
+ error = error ? error : -ETIMEDOUT;
+ }
+ } else {
+ gen5_pip->is_irq_mode = false;
+ error = cyapa_do_i2c_pip_cmd_polling(cyapa, cmd, cmd_len,
+ resp_data, resp_len, timeout, func);
+ }
+
+ gen5_pip->resp_sort_func = NULL;
+ gen5_pip->resp_data = NULL;
+ gen5_pip->resp_len = NULL;
+ gen5_pip->in_progress_cmd = TSG_INVALID_CMD;
+
+ mutex_unlock(&gen5_pip->cmd_lock);
+ return error;
+}
+
+static bool cyapa_gen5_sort_tsg_pip_bl_resp_data(struct cyapa *cyapa,
+ u8 *data, int len)
+{
+ if (!data || len < GEN5_MIN_BL_RESP_LENGTH)
+ return false;
+
+ /* Bootloader input report id 30h */
+ if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_RESP_REPORT_ID &&
+ data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
+ data[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY)
+ return true;
+
+ return false;
+}
+
+static bool cyapa_gen5_sort_tsg_pip_app_resp_data(struct cyapa *cyapa,
+ u8 *data, int len)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int resp_len;
+
+ if (!data || len < GEN5_MIN_APP_RESP_LENGTH)
+ return false;
+
+ if (data[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_APP_RESP_REPORT_ID &&
+ data[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY) {
+ resp_len = get_unaligned_le16(&data[GEN5_RESP_LENGTH_OFFSET]);
+ if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) == 0x00 &&
+ resp_len == GEN5_UNSUPPORTED_CMD_RESP_LENGTH &&
+ data[5] == gen5_pip->in_progress_cmd) {
+ /* Unsupported command code */
+ return false;
+ } else if (GET_GEN5_CMD_CODE(data[GEN5_RESP_APP_CMD_OFFSET]) ==
+ gen5_pip->in_progress_cmd) {
+ /* Correct command response received */
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool cyapa_gen5_sort_application_launch_data(struct cyapa *cyapa,
+ u8 *buf, int len)
+{
+ if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
+ return false;
+
+ /*
+ * After reset or power on, trackpad device always sets to 0x00 0x00
+ * to indicate a reset or power on event.
+ */
+ if (buf[0] == 0 && buf[1] == 0)
+ return true;
+
+ return false;
+}
+
+static bool cyapa_gen5_sort_hid_descriptor_data(struct cyapa *cyapa,
+ u8 *buf, int len)
+{
+ int resp_len;
+ int max_output_len;
+
+ /* Check hid descriptor. */
+ if (len != GEN5_HID_DESCRIPTOR_SIZE)
+ return false;
+
+ resp_len = get_unaligned_le16(&buf[GEN5_RESP_LENGTH_OFFSET]);
+ max_output_len = get_unaligned_le16(&buf[16]);
+ if (resp_len == GEN5_HID_DESCRIPTOR_SIZE) {
+ if (buf[GEN5_RESP_REPORT_ID_OFFSET] == GEN5_BL_HID_REPORT_ID &&
+ max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
+ /* BL mode HID Descriptor */
+ return true;
+ } else if ((buf[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_APP_HID_REPORT_ID) &&
+ max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
+ /* APP mode HID Descriptor */
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool cyapa_gen5_sort_deep_sleep_data(struct cyapa *cyapa,
+ u8 *buf, int len)
+{
+ if (len == GEN5_DEEP_SLEEP_RESP_LENGTH &&
+ buf[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_APP_DEEP_SLEEP_REPORT_ID &&
+ (buf[4] & GEN5_DEEP_SLEEP_OPCODE_MASK) ==
+ GEN5_DEEP_SLEEP_OPCODE)
+ return true;
+ return false;
+}
+
+static int gen5_idle_state_parse(struct cyapa *cyapa)
+{
+ u8 resp_data[GEN5_HID_DESCRIPTOR_SIZE];
+ int max_output_len;
+ int length;
+ u8 cmd[2];
+ int ret;
+ int error;
+
+ /*
+ * Dump all buffered data firstly for the situation
+ * when the trackpad is just power on the cyapa go here.
+ */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ memset(resp_data, 0, sizeof(resp_data));
+ ret = cyapa_i2c_pip_read(cyapa, resp_data, 3);
+ if (ret != 3)
+ return ret < 0 ? ret : -EIO;
+
+ length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
+ if (length == GEN5_RESP_LENGTH_SIZE) {
+ /* Normal state of Gen5 with no data to respose */
+ cyapa->gen = CYAPA_GEN5;
+
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ /* Read description from trackpad device */
+ cmd[0] = 0x01;
+ cmd[1] = 0x00;
+ length = GEN5_HID_DESCRIPTOR_SIZE;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, GEN5_RESP_LENGTH_SIZE,
+ resp_data, &length,
+ 300,
+ cyapa_gen5_sort_hid_descriptor_data,
+ false);
+ if (error)
+ return error;
+
+ length = get_unaligned_le16(
+ &resp_data[GEN5_RESP_LENGTH_OFFSET]);
+ max_output_len = get_unaligned_le16(&resp_data[16]);
+ if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
+ length == GEN5_RESP_LENGTH_SIZE) &&
+ (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_BL_HID_REPORT_ID) &&
+ max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
+ /* BL mode HID Description read */
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ } else if ((length == GEN5_HID_DESCRIPTOR_SIZE ||
+ length == GEN5_RESP_LENGTH_SIZE) &&
+ (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_APP_HID_REPORT_ID) &&
+ max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
+ /* APP mode HID Description read */
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ } else {
+ /* Should not happen!!! */
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+ }
+ }
+
+ return 0;
+}
+
+static int gen5_hid_description_header_parse(struct cyapa *cyapa, u8 *reg_data)
+{
+ int length;
+ u8 resp_data[32];
+ int max_output_len;
+ int ret;
+
+ /* 0x20 0x00 0xF7 is Gen5 Application HID Description Header;
+ * 0x20 0x00 0xFF is Gen5 Booloader HID Description Header.
+ *
+ * Must read HID Description content through out,
+ * otherwise Gen5 trackpad cannot response next command
+ * or report any touch or button data.
+ */
+ ret = cyapa_i2c_pip_read(cyapa, resp_data,
+ GEN5_HID_DESCRIPTOR_SIZE);
+ if (ret != GEN5_HID_DESCRIPTOR_SIZE)
+ return ret < 0 ? ret : -EIO;
+ length = get_unaligned_le16(&resp_data[GEN5_RESP_LENGTH_OFFSET]);
+ max_output_len = get_unaligned_le16(&resp_data[16]);
+ if (length == GEN5_RESP_LENGTH_SIZE) {
+ if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_BL_HID_REPORT_ID) {
+ /*
+ * BL mode HID Description has been previously
+ * read out.
+ */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ } else {
+ /*
+ * APP mode HID Description has been previously
+ * read out.
+ */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ }
+ } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
+ resp_data[2] == GEN5_BL_HID_REPORT_ID &&
+ max_output_len == GEN5_BL_MAX_OUTPUT_LENGTH) {
+ /* BL mode HID Description read. */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
+ (resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_APP_HID_REPORT_ID) &&
+ max_output_len == GEN5_APP_MAX_OUTPUT_LENGTH) {
+ /* APP mode HID Description read. */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ } else {
+ /* Should not happen!!! */
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+ }
+
+ return 0;
+}
+
+static int gen5_report_data_header_parse(struct cyapa *cyapa, u8 *reg_data)
+{
+ int length;
+
+ length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
+ switch (reg_data[GEN5_RESP_REPORT_ID_OFFSET]) {
+ case GEN5_TOUCH_REPORT_ID:
+ if (length < GEN5_TOUCH_REPORT_HEAD_SIZE ||
+ length > GEN5_TOUCH_REPORT_MAX_SIZE)
+ return -EINVAL;
+ break;
+ case GEN5_BTN_REPORT_ID:
+ case GEN5_OLD_PUSH_BTN_REPORT_ID:
+ case GEN5_PUSH_BTN_REPORT_ID:
+ if (length < GEN5_BTN_REPORT_HEAD_SIZE ||
+ length > GEN5_BTN_REPORT_MAX_SIZE)
+ return -EINVAL;
+ break;
+ case GEN5_WAKEUP_EVENT_REPORT_ID:
+ if (length != GEN5_WAKEUP_EVENT_SIZE)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ return 0;
+}
+
+static int gen5_cmd_resp_header_parse(struct cyapa *cyapa, u8 *reg_data)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int length;
+ int ret;
+
+ /*
+ * Must read report data through out,
+ * otherwise Gen5 trackpad cannot response next command
+ * or report any touch or button data.
+ */
+ length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
+ ret = cyapa_i2c_pip_read(cyapa, gen5_pip->empty_buf, length);
+ if (ret != length)
+ return ret < 0 ? ret : -EIO;
+
+ if (length == GEN5_RESP_LENGTH_SIZE) {
+ /* Previous command has read the data through out. */
+ if (reg_data[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_BL_RESP_REPORT_ID) {
+ /* Gen5 BL command response data detected */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ } else {
+ /* Gen5 APP command response data detected */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ }
+ } else if ((gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_BL_RESP_REPORT_ID) &&
+ (gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
+ GEN5_RESP_RSVD_KEY) &&
+ (gen5_pip->empty_buf[GEN5_RESP_BL_SOP_OFFSET] ==
+ GEN5_SOP_KEY) &&
+ (gen5_pip->empty_buf[length - 1] ==
+ GEN5_EOP_KEY)) {
+ /* Gen5 BL command response data detected */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ } else if (gen5_pip->empty_buf[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_APP_RESP_REPORT_ID &&
+ gen5_pip->empty_buf[GEN5_RESP_RSVD_OFFSET] ==
+ GEN5_RESP_RSVD_KEY) {
+ /* Gen5 APP command response data detected */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ } else {
+ /* Should not happen!!! */
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_state_parse(struct cyapa *cyapa, u8 *reg_data, int len)
+{
+ int length;
+
+ if (!reg_data || len < 3)
+ return -EINVAL;
+
+ cyapa->state = CYAPA_STATE_NO_DEVICE;
+
+ /* Parse based on Gen5 characteristic registers and bits */
+ length = get_unaligned_le16(&reg_data[GEN5_RESP_LENGTH_OFFSET]);
+ if (length == 0 || length == GEN5_RESP_LENGTH_SIZE) {
+ gen5_idle_state_parse(cyapa);
+ } else if (length == GEN5_HID_DESCRIPTOR_SIZE &&
+ (reg_data[2] == GEN5_BL_HID_REPORT_ID ||
+ reg_data[2] == GEN5_APP_HID_REPORT_ID)) {
+ gen5_hid_description_header_parse(cyapa, reg_data);
+ } else if ((length == GEN5_APP_REPORT_DESCRIPTOR_SIZE ||
+ length == GEN5_APP_CONTRACT_REPORT_DESCRIPTOR_SIZE) &&
+ reg_data[2] == GEN5_APP_REPORT_DESCRIPTOR_ID) {
+ /* 0xEE 0x00 0xF6 is Gen5 APP report description header. */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+ } else if (length == GEN5_BL_REPORT_DESCRIPTOR_SIZE &&
+ reg_data[2] == GEN5_BL_REPORT_DESCRIPTOR_ID) {
+ /* 0x1D 0x00 0xFE is Gen5 BL report descriptior header. */
+ cyapa->gen = CYAPA_GEN5;
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ } else if (reg_data[2] == GEN5_TOUCH_REPORT_ID ||
+ reg_data[2] == GEN5_BTN_REPORT_ID ||
+ reg_data[2] == GEN5_OLD_PUSH_BTN_REPORT_ID ||
+ reg_data[2] == GEN5_PUSH_BTN_REPORT_ID ||
+ reg_data[2] == GEN5_WAKEUP_EVENT_REPORT_ID) {
+ gen5_report_data_header_parse(cyapa, reg_data);
+ } else if (reg_data[2] == GEN5_BL_RESP_REPORT_ID ||
+ reg_data[2] == GEN5_APP_RESP_REPORT_ID) {
+ gen5_cmd_resp_header_parse(cyapa, reg_data);
+ }
+
+ if (cyapa->gen == CYAPA_GEN5) {
+ /*
+ * Must read the content (e.g.: report description and so on)
+ * from trackpad device throughout. Otherwise,
+ * Gen5 trackpad cannot response to next command or
+ * report any touch or button data later.
+ */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ if (cyapa->state == CYAPA_STATE_GEN5_APP ||
+ cyapa->state == CYAPA_STATE_GEN5_BL)
+ return 0;
+ }
+
+ return -EAGAIN;
+}
+
+static int cyapa_gen5_bl_initiate(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ struct cyapa_tsg_bin_image *image;
+ struct gen5_bl_cmd_head *bl_cmd_head;
+ struct gen5_bl_packet_start *bl_packet_start;
+ struct gen5_bl_initiate_cmd_data *cmd_data;
+ struct gen5_bl_packet_end *bl_packet_end;
+ u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
+ int cmd_len;
+ u16 cmd_data_len;
+ u16 cmd_crc = 0;
+ u16 meta_data_crc = 0;
+ u8 resp_data[11];
+ int resp_len;
+ int records_num;
+ u8 *data;
+ int error;
+
+ /* Try to dump all buffered report data before any send command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
+ bl_cmd_head = (struct gen5_bl_cmd_head *)cmd;
+ cmd_data_len = CYAPA_TSG_BL_KEY_SIZE + CYAPA_TSG_FLASH_MAP_BLOCK_SIZE;
+ cmd_len = sizeof(struct gen5_bl_cmd_head) + cmd_data_len +
+ sizeof(struct gen5_bl_packet_end);
+
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
+ put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
+ bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID;
+
+ bl_packet_start = &bl_cmd_head->packet_start;
+ bl_packet_start->sop = GEN5_SOP_KEY;
+ bl_packet_start->cmd_code = GEN5_BL_CMD_INITIATE_BL;
+ /* 8 key bytes and 128 bytes block size */
+ put_unaligned_le16(cmd_data_len, &bl_packet_start->data_length);
+
+ cmd_data = (struct gen5_bl_initiate_cmd_data *)bl_cmd_head->data;
+ memcpy(cmd_data->key, cyapa_gen5_bl_cmd_key, CYAPA_TSG_BL_KEY_SIZE);
+
+ /* Copy 60 bytes Meta Data Row Parameters */
+ image = (struct cyapa_tsg_bin_image *)fw->data;
+ records_num = (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+ /* APP_INTEGRITY row is always the last row block */
+ data = image->records[records_num - 1].record_data;
+ memcpy(cmd_data->metadata_raw_parameter, data,
+ CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
+
+ meta_data_crc = crc_itu_t(0xffff, cmd_data->metadata_raw_parameter,
+ CYAPA_TSG_FLASH_MAP_METADATA_SIZE);
+ put_unaligned_le16(meta_data_crc, &cmd_data->metadata_crc);
+
+ bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data +
+ cmd_data_len);
+ cmd_crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
+ sizeof(struct gen5_bl_packet_start) + cmd_data_len);
+ put_unaligned_le16(cmd_crc, &bl_packet_end->crc);
+ bl_packet_end->eop = GEN5_EOP_KEY;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, cmd_len,
+ resp_data, &resp_len, 12000,
+ cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (error || resp_len != GEN5_BL_INITIATE_RESP_LEN ||
+ resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ return 0;
+}
+
+static bool cyapa_gen5_sort_bl_exit_data(struct cyapa *cyapa, u8 *buf, int len)
+{
+ if (buf == NULL || len < GEN5_RESP_LENGTH_SIZE)
+ return false;
+
+ if (buf[0] == 0 && buf[1] == 0)
+ return true;
+
+ /* Exit bootloader failed for some reason. */
+ if (len == GEN5_BL_FAIL_EXIT_RESP_LEN &&
+ buf[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_BL_RESP_REPORT_ID &&
+ buf[GEN5_RESP_RSVD_OFFSET] == GEN5_RESP_RSVD_KEY &&
+ buf[GEN5_RESP_BL_SOP_OFFSET] == GEN5_SOP_KEY &&
+ buf[10] == GEN5_EOP_KEY)
+ return true;
+
+ return false;
+}
+
+static int cyapa_gen5_bl_exit(struct cyapa *cyapa)
+{
+
+ u8 bl_gen5_bl_exit[] = { 0x04, 0x00,
+ 0x0B, 0x00, 0x40, 0x00, 0x01, 0x3b, 0x00, 0x00,
+ 0x20, 0xc7, 0x17
+ };
+ u8 resp_data[11];
+ int resp_len;
+ int error;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ bl_gen5_bl_exit, sizeof(bl_gen5_bl_exit),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_bl_exit_data, false);
+ if (error)
+ return error;
+
+ if (resp_len == GEN5_BL_FAIL_EXIT_RESP_LEN ||
+ resp_data[GEN5_RESP_REPORT_ID_OFFSET] ==
+ GEN5_BL_RESP_REPORT_ID)
+ return -EAGAIN;
+
+ if (resp_data[0] == 0x00 && resp_data[1] == 0x00)
+ return 0;
+
+ return -ENODEV;
+}
+
+static int cyapa_gen5_bl_enter(struct cyapa *cyapa)
+{
+ u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2F, 0x00, 0x01 };
+ u8 resp_data[2];
+ int resp_len;
+ int error;
+
+ error = cyapa_poll_state(cyapa, 500);
+ if (error < 0)
+ return error;
+ if (cyapa->gen != CYAPA_GEN5)
+ return -EINVAL;
+
+ /* Already in Gen5 BL. Skipping exit. */
+ if (cyapa->state == CYAPA_STATE_GEN5_BL)
+ return 0;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return -EAGAIN;
+
+ /* Try to dump all buffered report data before any send command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ /*
+ * Send bootloader enter command to trackpad device,
+ * after enter bootloader, the response data is two bytes of 0x00 0x00.
+ */
+ resp_len = sizeof(resp_data);
+ memset(resp_data, 0, resp_len);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_application_launch_data,
+ true);
+ if (error || resp_data[0] != 0x00 || resp_data[1] != 0x00)
+ return error < 0 ? error : -EAGAIN;
+
+ cyapa->operational = false;
+ cyapa->state = CYAPA_STATE_GEN5_BL;
+ return 0;
+}
+
+static int cyapa_gen5_check_fw(struct cyapa *cyapa, const struct firmware *fw)
+{
+ struct device *dev = &cyapa->client->dev;
+ const struct cyapa_tsg_bin_image *image = (const void *)fw->data;
+ const struct cyapa_tsg_bin_image_data_record *app_integrity;
+ const struct gen5_bl_metadata_row_params *metadata;
+ size_t flash_records_count;
+ u32 fw_app_start, fw_upgrade_start;
+ u16 fw_app_len, fw_upgrade_len;
+ u16 app_crc;
+ u16 app_integrity_crc;
+ int record_index;
+ int i;
+
+ flash_records_count = (fw->size -
+ sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+
+ /*
+ * APP_INTEGRITY row is always the last row block,
+ * and the row id must be 0x01ff.
+ */
+ app_integrity = &image->records[flash_records_count - 1];
+
+ if (app_integrity->flash_array_id != 0x00 ||
+ get_unaligned_be16(&app_integrity->row_number) != 0x01ff) {
+ dev_err(dev, "%s: invalid app_integrity data.\n", __func__);
+ return -EINVAL;
+ }
+
+ metadata = (const void *)app_integrity->record_data;
+
+ /* Verify app_integrity crc */
+ app_integrity_crc = crc_itu_t(0xffff, app_integrity->record_data,
+ CYAPA_TSG_APP_INTEGRITY_SIZE);
+ if (app_integrity_crc != get_unaligned_le16(&metadata->metadata_crc)) {
+ dev_err(dev, "%s: invalid app_integrity crc.\n", __func__);
+ return -EINVAL;
+ }
+
+ fw_app_start = get_unaligned_le32(&metadata->app_start);
+ fw_app_len = get_unaligned_le16(&metadata->app_len);
+ fw_upgrade_start = get_unaligned_le32(&metadata->upgrade_start);
+ fw_upgrade_len = get_unaligned_le16(&metadata->upgrade_len);
+
+ if (fw_app_start % CYAPA_TSG_FW_ROW_SIZE ||
+ fw_app_len % CYAPA_TSG_FW_ROW_SIZE ||
+ fw_upgrade_start % CYAPA_TSG_FW_ROW_SIZE ||
+ fw_upgrade_len % CYAPA_TSG_FW_ROW_SIZE) {
+ dev_err(dev, "%s: invalid image alignment.\n", __func__);
+ return -EINVAL;
+ }
+
+ /*
+ * Verify application image CRC
+ */
+ record_index = fw_app_start / CYAPA_TSG_FW_ROW_SIZE -
+ CYAPA_TSG_IMG_START_ROW_NUM;
+ app_crc = 0xffffU;
+ for (i = 0; i < fw_app_len / CYAPA_TSG_FW_ROW_SIZE; i++) {
+ const u8 *data = image->records[record_index + i].record_data;
+ app_crc = crc_itu_t(app_crc, data, CYAPA_TSG_FW_ROW_SIZE);
+ }
+
+ if (app_crc != get_unaligned_le16(&metadata->app_crc)) {
+ dev_err(dev, "%s: invalid firmware app crc check.\n", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_write_fw_block(struct cyapa *cyapa,
+ struct cyapa_tsg_bin_image_data_record *flash_record)
+{
+ struct gen5_bl_cmd_head *bl_cmd_head;
+ struct gen5_bl_packet_start *bl_packet_start;
+ struct gen5_bl_flash_row_head *flash_row_head;
+ struct gen5_bl_packet_end *bl_packet_end;
+ u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
+ u16 cmd_len;
+ u8 flash_array_id;
+ u16 flash_row_id;
+ u16 record_len;
+ u8 *record_data;
+ u16 data_len;
+ u16 crc;
+ u8 resp_data[11];
+ int resp_len;
+ int error;
+
+ flash_array_id = flash_record->flash_array_id;
+ flash_row_id = get_unaligned_be16(&flash_record->row_number);
+ record_len = get_unaligned_be16(&flash_record->record_len);
+ record_data = flash_record->record_data;
+
+ memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
+ bl_cmd_head = (struct gen5_bl_cmd_head *)cmd;
+ bl_packet_start = &bl_cmd_head->packet_start;
+ cmd_len = sizeof(struct gen5_bl_cmd_head) +
+ sizeof(struct gen5_bl_flash_row_head) +
+ CYAPA_TSG_FLASH_MAP_BLOCK_SIZE +
+ sizeof(struct gen5_bl_packet_end);
+
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &bl_cmd_head->addr);
+ /* Don't include 2 bytes register address */
+ put_unaligned_le16(cmd_len - 2, &bl_cmd_head->length);
+ bl_cmd_head->report_id = GEN5_BL_CMD_REPORT_ID;
+ bl_packet_start->sop = GEN5_SOP_KEY;
+ bl_packet_start->cmd_code = GEN5_BL_CMD_PROGRAM_VERIFY_ROW;
+
+ /* 1 (Flash Array ID) + 2 (Flash Row ID) + 128 (flash data) */
+ data_len = sizeof(struct gen5_bl_flash_row_head) + record_len;
+ put_unaligned_le16(data_len, &bl_packet_start->data_length);
+
+ flash_row_head = (struct gen5_bl_flash_row_head *)bl_cmd_head->data;
+ flash_row_head->flash_array_id = flash_array_id;
+ put_unaligned_le16(flash_row_id, &flash_row_head->flash_row_id);
+ memcpy(flash_row_head->flash_data, record_data, record_len);
+
+ bl_packet_end = (struct gen5_bl_packet_end *)(bl_cmd_head->data +
+ data_len);
+ crc = crc_itu_t(0xffff, (u8 *)bl_packet_start,
+ sizeof(struct gen5_bl_packet_start) + data_len);
+ put_unaligned_le16(crc, &bl_packet_end->crc);
+ bl_packet_end->eop = GEN5_EOP_KEY;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, true);
+ if (error || resp_len != GEN5_BL_BLOCK_WRITE_RESP_LEN ||
+ resp_data[2] != GEN5_BL_RESP_REPORT_ID ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen5_do_fw_update(struct cyapa *cyapa,
+ const struct firmware *fw)
+{
+ struct device *dev = &cyapa->client->dev;
+ struct cyapa_tsg_bin_image_data_record *flash_record;
+ struct cyapa_tsg_bin_image *image =
+ (struct cyapa_tsg_bin_image *)fw->data;
+ int flash_records_count;
+ int i;
+ int error;
+
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ flash_records_count =
+ (fw->size - sizeof(struct cyapa_tsg_bin_image_head)) /
+ sizeof(struct cyapa_tsg_bin_image_data_record);
+ /*
+ * The last flash row 0x01ff has been written through bl_initiate
+ * command, so DO NOT write flash 0x01ff to trackpad device.
+ */
+ for (i = 0; i < (flash_records_count - 1); i++) {
+ flash_record = &image->records[i];
+ error = cyapa_gen5_write_fw_block(cyapa, flash_record);
+ if (error) {
+ dev_err(dev, "%s: Gen5 FW update aborted: %d\n",
+ __func__, error);
+ return error;
+ }
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_change_power_state(struct cyapa *cyapa, u8 power_state)
+{
+ u8 cmd[8] = { 0x04, 0x00, 0x06, 0x00, 0x2f, 0x00, 0x08, 0x01 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ cmd[7] = power_state;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x08) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EINVAL;
+
+ return 0;
+}
+
+static int cyapa_gen5_set_interval_time(struct cyapa *cyapa,
+ u8 parameter_id, u16 interval_time)
+{
+ struct gen5_app_cmd_head *app_cmd_head;
+ struct gen5_app_set_parameter_data *parameter_data;
+ u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
+ int cmd_len;
+ u8 resp_data[7];
+ int resp_len;
+ u8 parameter_size;
+ int error;
+
+ memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
+ app_cmd_head = (struct gen5_app_cmd_head *)cmd;
+ parameter_data = (struct gen5_app_set_parameter_data *)
+ app_cmd_head->parameter_data;
+ cmd_len = sizeof(struct gen5_app_cmd_head) +
+ sizeof(struct gen5_app_set_parameter_data);
+
+ switch (parameter_id) {
+ case GEN5_PARAMETER_ACT_INTERVL_ID:
+ parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
+ break;
+ case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
+ parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
+ break;
+ case GEN5_PARAMETER_LP_INTRVL_ID:
+ parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
+ /*
+ * Don't include unused parameter value bytes and
+ * 2 bytes register address.
+ */
+ put_unaligned_le16(cmd_len - (4 - parameter_size) - 2,
+ &app_cmd_head->length);
+ app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
+ parameter_data->parameter_id = parameter_id;
+ parameter_data->parameter_size = parameter_size;
+ put_unaligned_le32((u32)interval_time, &parameter_data->value);
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
+ if (error || resp_data[5] != parameter_id ||
+ resp_data[6] != parameter_size ||
+ !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER))
+ return error < 0 ? error : -EINVAL;
+
+ return 0;
+}
+
+static int cyapa_gen5_get_interval_time(struct cyapa *cyapa,
+ u8 parameter_id, u16 *interval_time)
+{
+ struct gen5_app_cmd_head *app_cmd_head;
+ struct gen5_app_get_parameter_data *parameter_data;
+ u8 cmd[CYAPA_TSG_MAX_CMD_SIZE];
+ int cmd_len;
+ u8 resp_data[11];
+ int resp_len;
+ u8 parameter_size;
+ u16 mask, i;
+ int error;
+
+ memset(cmd, 0, CYAPA_TSG_MAX_CMD_SIZE);
+ app_cmd_head = (struct gen5_app_cmd_head *)cmd;
+ parameter_data = (struct gen5_app_get_parameter_data *)
+ app_cmd_head->parameter_data;
+ cmd_len = sizeof(struct gen5_app_cmd_head) +
+ sizeof(struct gen5_app_get_parameter_data);
+
+ *interval_time = 0;
+ switch (parameter_id) {
+ case GEN5_PARAMETER_ACT_INTERVL_ID:
+ parameter_size = GEN5_PARAMETER_ACT_INTERVL_SIZE;
+ break;
+ case GEN5_PARAMETER_ACT_LFT_INTERVL_ID:
+ parameter_size = GEN5_PARAMETER_ACT_LFT_INTERVL_SIZE;
+ break;
+ case GEN5_PARAMETER_LP_INTRVL_ID:
+ parameter_size = GEN5_PARAMETER_LP_INTRVL_SIZE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
+ /* Don't include 2 bytes register address */
+ put_unaligned_le16(cmd_len - 2, &app_cmd_head->length);
+ app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ app_cmd_head->cmd_code = GEN5_CMD_GET_PARAMETER;
+ parameter_data->parameter_id = parameter_id;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, cmd_len,
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
+ if (error || resp_data[5] != parameter_id || resp_data[6] == 0 ||
+ !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_GET_PARAMETER))
+ return error < 0 ? error : -EINVAL;
+
+ mask = 0;
+ for (i = 0; i < parameter_size; i++)
+ mask |= (0xff << (i * 8));
+ *interval_time = get_unaligned_le16(&resp_data[7]) & mask;
+
+ return 0;
+}
+
+static int cyapa_gen5_disable_pip_report(struct cyapa *cyapa)
+{
+ struct gen5_app_cmd_head *app_cmd_head;
+ u8 cmd[10];
+ u8 resp_data[7];
+ int resp_len;
+ int error;
+
+ memset(cmd, 0, sizeof(cmd));
+ app_cmd_head = (struct gen5_app_cmd_head *)cmd;
+
+ put_unaligned_le16(GEN5_HID_DESCRIPTOR_ADDR, &app_cmd_head->addr);
+ put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
+ app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ app_cmd_head->cmd_code = GEN5_CMD_SET_PARAMETER;
+ app_cmd_head->parameter_data[0] = GEN5_PARAMETER_DISABLE_PIP_REPORT;
+ app_cmd_head->parameter_data[1] = 0x01;
+ app_cmd_head->parameter_data[2] = 0x01;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, false);
+ if (error || resp_data[5] != GEN5_PARAMETER_DISABLE_PIP_REPORT ||
+ !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_SET_PARAMETER) ||
+ resp_data[6] != 0x01)
+ return error < 0 ? error : -EINVAL;
+
+ return 0;
+}
+
+static int cyapa_gen5_deep_sleep(struct cyapa *cyapa, u8 state)
+{
+ u8 cmd[] = { 0x05, 0x00, 0x00, 0x08};
+ u8 resp_data[5];
+ int resp_len;
+ int error;
+
+ cmd[2] = state & GEN5_DEEP_SLEEP_STATE_MASK;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa, cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_deep_sleep_data, false);
+ if (error || ((resp_data[3] & GEN5_DEEP_SLEEP_STATE_MASK) != state))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int cyapa_gen5_set_power_mode(struct cyapa *cyapa,
+ u8 power_mode, u16 sleep_time)
+{
+ struct device *dev = &cyapa->client->dev;
+ u8 power_state;
+ int error;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return 0;
+
+ /* Dump all the report data before do power mode commmands. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ if (GEN5_DEV_GET_PWR_STATE(cyapa) == UNINIT_PWR_MODE) {
+ /*
+ * Assume TP in deep sleep mode when driver is loaded,
+ * avoid driver unload and reload command IO issue caused by TP
+ * has been set into deep sleep mode when unloading.
+ */
+ GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
+ }
+
+ if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) &&
+ GEN5_DEV_GET_PWR_STATE(cyapa) != PWR_MODE_OFF)
+ if (cyapa_gen5_get_interval_time(cyapa,
+ GEN5_PARAMETER_LP_INTRVL_ID,
+ &cyapa->dev_sleep_time) != 0)
+ GEN5_DEV_SET_SLEEP_TIME(cyapa, UNINIT_SLEEP_TIME);
+
+ if (GEN5_DEV_GET_PWR_STATE(cyapa) == power_mode) {
+ if (power_mode == PWR_MODE_OFF ||
+ power_mode == PWR_MODE_FULL_ACTIVE ||
+ power_mode == PWR_MODE_BTN_ONLY ||
+ GEN5_DEV_GET_SLEEP_TIME(cyapa) == sleep_time) {
+ /* Has in correct power mode state, early return. */
+ return 0;
+ }
+ }
+
+ if (power_mode == PWR_MODE_OFF) {
+ error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_OFF);
+ if (error) {
+ dev_err(dev, "enter deep sleep fail: %d\n", error);
+ return error;
+ }
+
+ GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_OFF);
+ return 0;
+ }
+
+ /*
+ * When trackpad in power off mode, it cannot change to other power
+ * state directly, must be wake up from sleep firstly, then
+ * continue to do next power sate change.
+ */
+ if (GEN5_DEV_GET_PWR_STATE(cyapa) == PWR_MODE_OFF) {
+ error = cyapa_gen5_deep_sleep(cyapa, GEN5_DEEP_SLEEP_STATE_ON);
+ if (error) {
+ dev_err(dev, "deep sleep wake fail: %d\n", error);
+ return error;
+ }
+ }
+
+ if (power_mode == PWR_MODE_FULL_ACTIVE) {
+ error = cyapa_gen5_change_power_state(cyapa,
+ GEN5_POWER_STATE_ACTIVE);
+ if (error) {
+ dev_err(dev, "change to active fail: %d\n", error);
+ return error;
+ }
+
+ GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_FULL_ACTIVE);
+ } else if (power_mode == PWR_MODE_BTN_ONLY) {
+ error = cyapa_gen5_change_power_state(cyapa,
+ GEN5_POWER_STATE_BTN_ONLY);
+ if (error) {
+ dev_err(dev, "fail to button only mode: %d\n", error);
+ return error;
+ }
+
+ GEN5_DEV_SET_PWR_STATE(cyapa, PWR_MODE_BTN_ONLY);
+ } else {
+ /*
+ * Continue to change power mode even failed to set
+ * interval time, it won't affect the power mode change.
+ * except the sleep interval time is not correct.
+ */
+ if (GEN5_DEV_UNINIT_SLEEP_TIME(cyapa) ||
+ sleep_time != GEN5_DEV_GET_SLEEP_TIME(cyapa))
+ if (cyapa_gen5_set_interval_time(cyapa,
+ GEN5_PARAMETER_LP_INTRVL_ID,
+ sleep_time) == 0)
+ GEN5_DEV_SET_SLEEP_TIME(cyapa, sleep_time);
+
+ if (sleep_time <= GEN5_POWER_READY_MAX_INTRVL_TIME)
+ power_state = GEN5_POWER_STATE_READY;
+ else
+ power_state = GEN5_POWER_STATE_IDLE;
+ error = cyapa_gen5_change_power_state(cyapa, power_state);
+ if (error) {
+ dev_err(dev, "set power state to 0x%02x failed: %d\n",
+ power_state, error);
+ return error;
+ }
+
+ /*
+ * Disable pip report for a little time, firmware will
+ * re-enable it automatically. It's used to fix the issue
+ * that trackpad unable to report signal to wake system up
+ * in the special situation that system is in suspending, and
+ * at the same time, user touch trackpad to wake system up.
+ * This function can avoid the data to be buffured when system
+ * is suspending which may cause interrput line unable to be
+ * asserted again.
+ */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+ cyapa_gen5_disable_pip_report(cyapa);
+
+ GEN5_DEV_SET_PWR_STATE(cyapa,
+ cyapa_sleep_time_to_pwr_cmd(sleep_time));
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_resume_scanning(struct cyapa *cyapa)
+{
+ u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x04 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all buffered data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x04))
+ return -EINVAL;
+
+ /* Try to dump all buffered data when resuming scanning. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int cyapa_gen5_suspend_scanning(struct cyapa *cyapa)
+{
+ u8 cmd[] = { 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x03 };
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all buffered data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, 0x03))
+ return -EINVAL;
+
+ /* Try to dump all buffered data when suspending scanning. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ return 0;
+}
+
+static int cyapa_gen5_calibrate_pwcs(struct cyapa *cyapa,
+ u8 calibrate_sensing_mode_type)
+{
+ struct gen5_app_cmd_head *app_cmd_head;
+ u8 cmd[8];
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ /* Try to dump all buffered data before doing command. */
+ cyapa_empty_pip_output_data(cyapa, NULL, NULL, NULL);
+
+ memset(cmd, 0, sizeof(cmd));
+ app_cmd_head = (struct gen5_app_cmd_head *)cmd;
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
+ put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
+ app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ app_cmd_head->cmd_code = GEN5_CMD_CALIBRATE;
+ app_cmd_head->parameter_data[0] = calibrate_sensing_mode_type;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 5000, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || !VALID_CMD_RESP_HEADER(resp_data, GEN5_CMD_CALIBRATE) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error < 0 ? error : -EAGAIN;
+
+ return 0;
+}
+
+static ssize_t cyapa_gen5_do_calibrate(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int error, calibrate_error;
+
+ /* 1. Suspend Scanning*/
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Do mutual capacitance fine calibrate. */
+ calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
+ CYAPA_SENSING_MODE_MUTUAL_CAP_FINE);
+ if (calibrate_error)
+ goto resume_scanning;
+
+ /* 3. Do self capacitance calibrate. */
+ calibrate_error = cyapa_gen5_calibrate_pwcs(cyapa,
+ CYAPA_SENSING_MODE_SELF_CAP);
+ if (calibrate_error)
+ goto resume_scanning;
+
+resume_scanning:
+ /* 4. Resume Scanning*/
+ error = cyapa_gen5_resume_scanning(cyapa);
+ if (error || calibrate_error)
+ return error ? error : calibrate_error;
+
+ return count;
+}
+
+static s32 twos_complement_to_s32(s32 value, int num_bits)
+{
+ if (value >> (num_bits - 1))
+ value |= -1 << num_bits;
+ return value;
+}
+
+static s32 cyapa_parse_structure_data(u8 data_format, u8 *buf, int buf_len)
+{
+ int data_size;
+ bool big_endian;
+ bool unsigned_type;
+ s32 value;
+
+ data_size = (data_format & 0x07);
+ big_endian = ((data_format & 0x10) == 0x00);
+ unsigned_type = ((data_format & 0x20) == 0x00);
+
+ if (buf_len < data_size)
+ return 0;
+
+ switch (data_size) {
+ case 1:
+ value = buf[0];
+ break;
+ case 2:
+ if (big_endian)
+ value = get_unaligned_be16(buf);
+ else
+ value = get_unaligned_le16(buf);
+ break;
+ case 4:
+ if (big_endian)
+ value = get_unaligned_be32(buf);
+ else
+ value = get_unaligned_le32(buf);
+ break;
+ default:
+ /* Should not happen, just as default case here. */
+ value = 0;
+ break;
+ }
+
+ if (!unsigned_type)
+ value = twos_complement_to_s32(value, data_size * 8);
+
+ return value;
+}
+
+static void cyapa_gen5_guess_electrodes(struct cyapa *cyapa,
+ int *electrodes_rx, int *electrodes_tx)
+{
+ if (cyapa->electrodes_rx != 0) {
+ *electrodes_rx = cyapa->electrodes_rx;
+ *electrodes_tx = (cyapa->electrodes_x == *electrodes_rx) ?
+ cyapa->electrodes_y : cyapa->electrodes_x;
+ } else {
+ *electrodes_tx = min(cyapa->electrodes_x, cyapa->electrodes_y);
+ *electrodes_rx = max(cyapa->electrodes_x, cyapa->electrodes_y);
+ }
+}
+
+/*
+ * Read all the global mutual or self idac data or mutual or self local PWC
+ * data based on the @idac_data_type.
+ * If the input value of @data_size is 0, then means read global mutual or
+ * self idac data. For read global mutual idac data, @idac_max, @idac_min and
+ * @idac_ave are in order used to return the max value of global mutual idac
+ * data, the min value of global mutual idac and the average value of the
+ * global mutual idac data. For read global self idac data, @idac_max is used
+ * to return the global self cap idac data in Rx direction, @idac_min is used
+ * to return the global self cap idac data in Tx direction. @idac_ave is not
+ * used.
+ * If the input value of @data_size is not 0, than means read the mutual or
+ * self local PWC data. The @idac_max, @idac_min and @idac_ave are used to
+ * return the max, min and average value of the mutual or self local PWC data.
+ * Note, in order to raed mutual local PWC data, must read invoke this function
+ * to read the mutual global idac data firstly to set the correct Rx number
+ * value, otherwise, the read mutual idac and PWC data may not correct.
+ */
+static int cyapa_gen5_read_idac_data(struct cyapa *cyapa,
+ u8 cmd_code, u8 idac_data_type, int *data_size,
+ int *idac_max, int *idac_min, int *idac_ave)
+{
+ struct gen5_app_cmd_head *cmd_head;
+ u8 cmd[12];
+ u8 resp_data[256];
+ int resp_len;
+ int read_len;
+ int value;
+ u16 offset;
+ int read_elements;
+ bool read_global_idac;
+ int sum, count, max_element_cnt;
+ int tmp_max, tmp_min, tmp_ave, tmp_sum, tmp_count;
+ int electrodes_rx, electrodes_tx;
+ int i;
+ int error;
+
+ if (cmd_code != GEN5_CMD_RETRIEVE_DATA_STRUCTURE ||
+ (idac_data_type != GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
+ idac_data_type != GEN5_RETRIEVE_SELF_CAP_PWC_DATA) ||
+ !data_size || !idac_max || !idac_min || !idac_ave)
+ return -EINVAL;
+
+ *idac_max = INT_MIN;
+ *idac_min = INT_MAX;
+ sum = count = tmp_count = 0;
+ electrodes_rx = electrodes_tx = 0;
+ if (*data_size == 0) {
+ /*
+ * Read global idac values firstly.
+ * Currently, no idac data exceed 4 bytes.
+ */
+ read_global_idac = true;
+ offset = 0;
+ *data_size = 4;
+ tmp_max = INT_MIN;
+ tmp_min = INT_MAX;
+ tmp_ave = tmp_sum = tmp_count = 0;
+
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ if (cyapa->aligned_electrodes_rx == 0) {
+ cyapa_gen5_guess_electrodes(cyapa,
+ &electrodes_rx, &electrodes_tx);
+ cyapa->aligned_electrodes_rx =
+ (electrodes_rx + 3) & ~3u;
+ }
+ max_element_cnt =
+ (cyapa->aligned_electrodes_rx + 7) & ~7u;
+ } else {
+ max_element_cnt = 2;
+ }
+ } else {
+ read_global_idac = false;
+ if (*data_size > 4)
+ *data_size = 4;
+ /* Calculate the start offset in bytes of local PWC data. */
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ offset = cyapa->aligned_electrodes_rx * (*data_size);
+ if (cyapa->electrodes_rx == cyapa->electrodes_x)
+ electrodes_tx = cyapa->electrodes_y;
+ else
+ electrodes_tx = cyapa->electrodes_x;
+ max_element_cnt = ((cyapa->aligned_electrodes_rx + 7) &
+ ~7u) * electrodes_tx;
+ } else if (idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+ offset = 2;
+ max_element_cnt = cyapa->electrodes_x +
+ cyapa->electrodes_y;
+ max_element_cnt = (max_element_cnt + 3) & ~3u;
+ }
+ }
+
+ memset(cmd, 0, sizeof(cmd));
+ cmd_head = (struct gen5_app_cmd_head *)cmd;
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &cmd_head->addr);
+ put_unaligned_le16(sizeof(cmd) - 2, &cmd_head->length);
+ cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ cmd_head->cmd_code = cmd_code;
+ do {
+ read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) /
+ (*data_size);
+ read_elements = min(read_elements, max_element_cnt - count);
+ read_len = read_elements * (*data_size);
+
+ put_unaligned_le16(offset, &cmd_head->parameter_data[0]);
+ put_unaligned_le16(read_len, &cmd_head->parameter_data[2]);
+ cmd_head->parameter_data[4] = idac_data_type;
+ resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data,
+ true);
+ if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
+ !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
+ resp_data[6] != idac_data_type)
+ return (error < 0) ? error : -EAGAIN;
+ read_len = get_unaligned_le16(&resp_data[7]);
+ if (read_len == 0)
+ break;
+
+ *data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
+ if (read_len < *data_size)
+ return -EINVAL;
+
+ if (read_global_idac &&
+ idac_data_type == GEN5_RETRIEVE_SELF_CAP_PWC_DATA) {
+ /* Rx's self global idac data. */
+ *idac_max = cyapa_parse_structure_data(
+ resp_data[9],
+ &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET],
+ *data_size);
+ /* Tx's self global idac data. */
+ *idac_min = cyapa_parse_structure_data(
+ resp_data[9],
+ &resp_data[GEN5_RESP_DATA_STRUCTURE_OFFSET +
+ *data_size],
+ *data_size);
+ break;
+ }
+
+ /* Read mutual global idac or local mutual/self PWC data. */
+ offset += read_len;
+ for (i = 10; i < (read_len + GEN5_RESP_DATA_STRUCTURE_OFFSET);
+ i += *data_size) {
+ value = cyapa_parse_structure_data(resp_data[9],
+ &resp_data[i], *data_size);
+ *idac_min = min(value, *idac_min);
+ *idac_max = max(value, *idac_max);
+
+ if (idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA &&
+ tmp_count < cyapa->aligned_electrodes_rx &&
+ read_global_idac) {
+ /*
+ * The value gap betwen global and local mutual
+ * idac data must bigger than 50%.
+ * Normally, global value bigger than 50,
+ * local values less than 10.
+ */
+ if (!tmp_ave || value > tmp_ave / 2) {
+ tmp_min = min(value, tmp_min);
+ tmp_max = max(value, tmp_max);
+ tmp_sum += value;
+ tmp_count++;
+
+ tmp_ave = tmp_sum / tmp_count;
+ }
+ }
+
+ sum += value;
+ count++;
+
+ if (count >= max_element_cnt)
+ goto out;
+ }
+ } while (true);
+
+out:
+ *idac_ave = count ? (sum / count) : 0;
+
+ if (read_global_idac &&
+ idac_data_type == GEN5_RETRIEVE_MUTUAL_PWC_DATA) {
+ if (tmp_count == 0)
+ return 0;
+
+ if (tmp_count == cyapa->aligned_electrodes_rx) {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_rx;
+ } else if (tmp_count == electrodes_rx) {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_rx;
+ cyapa->aligned_electrodes_rx = electrodes_rx;
+ } else {
+ cyapa->electrodes_rx = cyapa->electrodes_rx ?
+ cyapa->electrodes_rx : electrodes_tx;
+ cyapa->aligned_electrodes_rx = tmp_count;
+ }
+
+ *idac_min = tmp_min;
+ *idac_max = tmp_max;
+ *idac_ave = tmp_ave;
+ }
+
+ return 0;
+}
+
+static int cyapa_gen5_read_mutual_idac_data(struct cyapa *cyapa,
+ int *gidac_mutual_max, int *gidac_mutual_min, int *gidac_mutual_ave,
+ int *lidac_mutual_max, int *lidac_mutual_min, int *lidac_mutual_ave)
+{
+ int data_size;
+ int error;
+
+ *gidac_mutual_max = *gidac_mutual_min = *gidac_mutual_ave = 0;
+ *lidac_mutual_max = *lidac_mutual_min = *lidac_mutual_ave = 0;
+
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size,
+ gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave);
+ if (error)
+ return error;
+
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_MUTUAL_PWC_DATA,
+ &data_size,
+ lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave);
+ return error;
+}
+
+static int cyapa_gen5_read_self_idac_data(struct cyapa *cyapa,
+ int *gidac_self_rx, int *gidac_self_tx,
+ int *lidac_self_max, int *lidac_self_min, int *lidac_self_ave)
+{
+ int data_size;
+ int error;
+
+ *gidac_self_rx = *gidac_self_tx = 0;
+ *lidac_self_max = *lidac_self_min = *lidac_self_ave = 0;
+
+ data_size = 0;
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
+ &data_size,
+ lidac_self_max, lidac_self_min, lidac_self_ave);
+ if (error)
+ return error;
+ *gidac_self_rx = *lidac_self_max;
+ *gidac_self_tx = *lidac_self_min;
+
+ error = cyapa_gen5_read_idac_data(cyapa,
+ GEN5_CMD_RETRIEVE_DATA_STRUCTURE,
+ GEN5_RETRIEVE_SELF_CAP_PWC_DATA,
+ &data_size,
+ lidac_self_max, lidac_self_min, lidac_self_ave);
+ return error;
+}
+
+static ssize_t cyapa_gen5_execute_panel_scan(struct cyapa *cyapa)
+{
+ struct gen5_app_cmd_head *app_cmd_head;
+ u8 cmd[7];
+ u8 resp_data[6];
+ int resp_len;
+ int error;
+
+ memset(cmd, 0, sizeof(cmd));
+ app_cmd_head = (struct gen5_app_cmd_head *)cmd;
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
+ put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
+ app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ app_cmd_head->cmd_code = GEN5_CMD_EXECUTE_PANEL_SCAN;
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || resp_len != sizeof(resp_data) ||
+ !VALID_CMD_RESP_HEADER(resp_data,
+ GEN5_CMD_EXECUTE_PANEL_SCAN) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EAGAIN;
+
+ return 0;
+}
+
+static int cyapa_gen5_read_panel_scan_raw_data(struct cyapa *cyapa,
+ u8 cmd_code, u8 raw_data_type, int raw_data_max_num,
+ int *raw_data_max, int *raw_data_min, int *raw_data_ave,
+ u8 *buffer)
+{
+ struct gen5_app_cmd_head *app_cmd_head;
+ struct gen5_retrieve_panel_scan_data *panel_sacn_data;
+ u8 cmd[12];
+ u8 resp_data[256]; /* Max bytes can transfer one time. */
+ int resp_len;
+ int read_elements;
+ int read_len;
+ u16 offset;
+ s32 value;
+ int sum, count;
+ int data_size;
+ s32 *intp;
+ int i;
+ int error;
+
+ if (cmd_code != GEN5_CMD_RETRIEVE_PANEL_SCAN ||
+ (raw_data_type > GEN5_PANEL_SCAN_SELF_DIFFCOUNT) ||
+ !raw_data_max || !raw_data_min || !raw_data_ave)
+ return -EINVAL;
+
+ intp = (s32 *)buffer;
+ *raw_data_max = INT_MIN;
+ *raw_data_min = INT_MAX;
+ sum = count = 0;
+ offset = 0;
+ /* Assume max element size is 4 currently. */
+ read_elements = (256 - GEN5_RESP_DATA_STRUCTURE_OFFSET) / 4;
+ read_len = read_elements * 4;
+ app_cmd_head = (struct gen5_app_cmd_head *)cmd;
+ put_unaligned_le16(GEN5_OUTPUT_REPORT_ADDR, &app_cmd_head->addr);
+ put_unaligned_le16(sizeof(cmd) - 2, &app_cmd_head->length);
+ app_cmd_head->report_id = GEN5_APP_CMD_REPORT_ID;
+ app_cmd_head->cmd_code = cmd_code;
+ panel_sacn_data = (struct gen5_retrieve_panel_scan_data *)
+ app_cmd_head->parameter_data;
+ do {
+ put_unaligned_le16(offset, &panel_sacn_data->read_offset);
+ put_unaligned_le16(read_elements,
+ &panel_sacn_data->read_elements);
+ panel_sacn_data->data_id = raw_data_type;
+
+ resp_len = GEN5_RESP_DATA_STRUCTURE_OFFSET + read_len;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ cmd, sizeof(cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_app_resp_data, true);
+ if (error || resp_len < GEN5_RESP_DATA_STRUCTURE_OFFSET ||
+ !VALID_CMD_RESP_HEADER(resp_data, cmd_code) ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]) ||
+ resp_data[6] != raw_data_type)
+ return error ? error : -EAGAIN;
+
+ read_elements = get_unaligned_le16(&resp_data[7]);
+ if (read_elements == 0)
+ break;
+
+ data_size = (resp_data[9] & GEN5_PWC_DATA_ELEMENT_SIZE_MASK);
+ offset += read_elements;
+ if (read_elements) {
+ for (i = GEN5_RESP_DATA_STRUCTURE_OFFSET;
+ i < (read_elements * data_size +
+ GEN5_RESP_DATA_STRUCTURE_OFFSET);
+ i += data_size) {
+ value = cyapa_parse_structure_data(resp_data[9],
+ &resp_data[i], data_size);
+ *raw_data_min = min(value, *raw_data_min);
+ *raw_data_max = max(value, *raw_data_max);
+
+ if (intp)
+ put_unaligned_le32(value, &intp[count]);
+
+ sum += value;
+ count++;
+
+ }
+ }
+
+ if (count >= raw_data_max_num)
+ break;
+
+ read_elements = (sizeof(resp_data) -
+ GEN5_RESP_DATA_STRUCTURE_OFFSET) / data_size;
+ read_len = read_elements * data_size;
+ } while (true);
+
+ *raw_data_ave = count ? (sum / count) : 0;
+
+ return 0;
+}
+
+static ssize_t cyapa_gen5_show_baseline(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct cyapa *cyapa = dev_get_drvdata(dev);
+ int gidac_mutual_max, gidac_mutual_min, gidac_mutual_ave;
+ int lidac_mutual_max, lidac_mutual_min, lidac_mutual_ave;
+ int gidac_self_rx, gidac_self_tx;
+ int lidac_self_max, lidac_self_min, lidac_self_ave;
+ int raw_cap_mutual_max, raw_cap_mutual_min, raw_cap_mutual_ave;
+ int raw_cap_self_max, raw_cap_self_min, raw_cap_self_ave;
+ int mutual_diffdata_max, mutual_diffdata_min, mutual_diffdata_ave;
+ int self_diffdata_max, self_diffdata_min, self_diffdata_ave;
+ int mutual_baseline_max, mutual_baseline_min, mutual_baseline_ave;
+ int self_baseline_max, self_baseline_min, self_baseline_ave;
+ int error, resume_error;
+ int size;
+
+ if (cyapa->state != CYAPA_STATE_GEN5_APP)
+ return -EBUSY;
+
+ /* 1. Suspend Scanning*/
+ error = cyapa_gen5_suspend_scanning(cyapa);
+ if (error)
+ return error;
+
+ /* 2. Read global and local mutual IDAC data. */
+ gidac_self_rx = gidac_self_tx = 0;
+ error = cyapa_gen5_read_mutual_idac_data(cyapa,
+ &gidac_mutual_max, &gidac_mutual_min,
+ &gidac_mutual_ave, &lidac_mutual_max,
+ &lidac_mutual_min, &lidac_mutual_ave);
+ if (error)
+ goto resume_scanning;
+
+ /* 3. Read global and local self IDAC data. */
+ error = cyapa_gen5_read_self_idac_data(cyapa,
+ &gidac_self_rx, &gidac_self_tx,
+ &lidac_self_max, &lidac_self_min,
+ &lidac_self_ave);
+ if (error)
+ goto resume_scanning;
+
+ /* 4. Execuate panel scan. It must be executed before read data. */
+ error = cyapa_gen5_execute_panel_scan(cyapa);
+ if (error)
+ goto resume_scanning;
+
+ /* 5. Retrieve panel scan, mutual cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_RAW_DATA,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &raw_cap_mutual_max, &raw_cap_mutual_min,
+ &raw_cap_mutual_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 6. Retrieve panel scan, self cap raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_RAW_DATA,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &raw_cap_self_max, &raw_cap_self_min,
+ &raw_cap_self_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 7. Retrieve panel scan, mutual cap diffcount raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_DIFFCOUNT,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &mutual_diffdata_max, &mutual_diffdata_min,
+ &mutual_diffdata_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 8. Retrieve panel scan, self cap diffcount raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_DIFFCOUNT,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &self_diffdata_max, &self_diffdata_min,
+ &self_diffdata_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 9. Retrieve panel scan, mutual cap baseline raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_MUTUAL_BASELINE,
+ cyapa->electrodes_x * cyapa->electrodes_y,
+ &mutual_baseline_max, &mutual_baseline_min,
+ &mutual_baseline_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+ /* 10. Retrieve panel scan, self cap baseline raw data. */
+ error = cyapa_gen5_read_panel_scan_raw_data(cyapa,
+ GEN5_CMD_RETRIEVE_PANEL_SCAN,
+ GEN5_PANEL_SCAN_SELF_BASELINE,
+ cyapa->electrodes_x + cyapa->electrodes_y,
+ &self_baseline_max, &self_baseline_min,
+ &self_baseline_ave,
+ NULL);
+ if (error)
+ goto resume_scanning;
+
+resume_scanning:
+ /* 11. Resume Scanning*/
+ resume_error = cyapa_gen5_resume_scanning(cyapa);
+ if (resume_error || error)
+ return resume_error ? resume_error : error;
+
+ /* 12. Output data strings */
+ size = scnprintf(buf, PAGE_SIZE, "%d %d %d %d %d %d %d %d %d %d %d ",
+ gidac_mutual_min, gidac_mutual_max, gidac_mutual_ave,
+ lidac_mutual_min, lidac_mutual_max, lidac_mutual_ave,
+ gidac_self_rx, gidac_self_tx,
+ lidac_self_min, lidac_self_max, lidac_self_ave);
+ size += scnprintf(buf + size, PAGE_SIZE - size,
+ "%d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d\n",
+ raw_cap_mutual_min, raw_cap_mutual_max, raw_cap_mutual_ave,
+ raw_cap_self_min, raw_cap_self_max, raw_cap_self_ave,
+ mutual_diffdata_min, mutual_diffdata_max, mutual_diffdata_ave,
+ self_diffdata_min, self_diffdata_max, self_diffdata_ave,
+ mutual_baseline_min, mutual_baseline_max, mutual_baseline_ave,
+ self_baseline_min, self_baseline_max, self_baseline_ave);
+ return size;
+}
+
+static bool cyapa_gen5_sort_system_info_data(struct cyapa *cyapa,
+ u8 *buf, int len)
+{
+ /* Check the report id and command code */
+ if (VALID_CMD_RESP_HEADER(buf, 0x02))
+ return true;
+
+ return false;
+}
+
+static int cyapa_gen5_bl_query_data(struct cyapa *cyapa)
+{
+ u8 bl_query_data_cmd[] = { 0x04, 0x00, 0x0b, 0x00, 0x40, 0x00,
+ 0x01, 0x3c, 0x00, 0x00, 0xb0, 0x42, 0x17
+ };
+ u8 resp_data[GEN5_BL_READ_APP_INFO_RESP_LEN];
+ int resp_len;
+ int error;
+
+ resp_len = GEN5_BL_READ_APP_INFO_RESP_LEN;
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ bl_query_data_cmd, sizeof(bl_query_data_cmd),
+ resp_data, &resp_len,
+ 500, cyapa_gen5_sort_tsg_pip_bl_resp_data, false);
+ if (error || resp_len != GEN5_BL_READ_APP_INFO_RESP_LEN ||
+ !GEN5_CMD_COMPLETE_SUCCESS(resp_data[5]))
+ return error ? error : -EIO;
+
+ memcpy(&cyapa->product_id[0], &resp_data[8], 5);
+ cyapa->product_id[5] = '-';
+ memcpy(&cyapa->product_id[6], &resp_data[13], 6);
+ cyapa->product_id[12] = '-';
+ memcpy(&cyapa->product_id[13], &resp_data[19], 2);
+ cyapa->product_id[15] = '\0';
+
+ cyapa->fw_maj_ver = resp_data[22];
+ cyapa->fw_min_ver = resp_data[23];
+
+ return 0;
+}
+
+static int cyapa_gen5_get_query_data(struct cyapa *cyapa)
+{
+ u8 get_system_information[] = {
+ 0x04, 0x00, 0x05, 0x00, 0x2f, 0x00, 0x02
+ };
+ u8 resp_data[71];
+ int resp_len;
+ u16 product_family;
+ int error;
+
+ resp_len = sizeof(resp_data);
+ error = cyapa_i2c_pip_cmd_irq_sync(cyapa,
+ get_system_information, sizeof(get_system_information),
+ resp_data, &resp_len,
+ 2000, cyapa_gen5_sort_system_info_data, false);
+ if (error || resp_len < sizeof(resp_data))
+ return error ? error : -EIO;
+
+ product_family = get_unaligned_le16(&resp_data[7]);
+ if ((product_family & GEN5_PRODUCT_FAMILY_MASK) !=
+ GEN5_PRODUCT_FAMILY_TRACKPAD)
+ return -EINVAL;
+
+ cyapa->fw_maj_ver = resp_data[15];
+ cyapa->fw_min_ver = resp_data[16];
+
+ cyapa->electrodes_x = resp_data[52];
+ cyapa->electrodes_y = resp_data[53];
+
+ cyapa->physical_size_x = get_unaligned_le16(&resp_data[54]) / 100;
+ cyapa->physical_size_y = get_unaligned_le16(&resp_data[56]) / 100;
+
+ cyapa->max_abs_x = get_unaligned_le16(&resp_data[58]);
+ cyapa->max_abs_y = get_unaligned_le16(&resp_data[60]);
+
+ cyapa->max_z = get_unaligned_le16(&resp_data[62]);
+
+ cyapa->x_origin = resp_data[64] & 0x01;
+ cyapa->y_origin = resp_data[65] & 0x01;
+
+ cyapa->btn_capability = (resp_data[70] << 3) & CAPABILITY_BTN_MASK;
+
+ memcpy(&cyapa->product_id[0], &resp_data[33], 5);
+ cyapa->product_id[5] = '-';
+ memcpy(&cyapa->product_id[6], &resp_data[38], 6);
+ cyapa->product_id[12] = '-';
+ memcpy(&cyapa->product_id[13], &resp_data[44], 2);
+ cyapa->product_id[15] = '\0';
+
+ if (!cyapa->electrodes_x || !cyapa->electrodes_y ||
+ !cyapa->physical_size_x || !cyapa->physical_size_y ||
+ !cyapa->max_abs_x || !cyapa->max_abs_y || !cyapa->max_z)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int cyapa_gen5_do_operational_check(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ int error;
+
+ if (cyapa->gen != CYAPA_GEN5)
+ return -ENODEV;
+
+ switch (cyapa->state) {
+ case CYAPA_STATE_GEN5_BL:
+ error = cyapa_gen5_bl_exit(cyapa);
+ if (error) {
+ /* Rry to update trackpad product information. */
+ cyapa_gen5_bl_query_data(cyapa);
+ goto out;
+ }
+
+ cyapa->state = CYAPA_STATE_GEN5_APP;
+
+ case CYAPA_STATE_GEN5_APP:
+ /*
+ * If trackpad device in deep sleep mode,
+ * the app command will fail.
+ * So always try to reset trackpad device to full active when
+ * the device state is requeried.
+ */
+ error = cyapa_gen5_set_power_mode(cyapa,
+ PWR_MODE_FULL_ACTIVE, 0);
+ if (error)
+ dev_warn(dev, "%s: failed to set power active mode.\n",
+ __func__);
+
+ /* Get trackpad product information. */
+ error = cyapa_gen5_get_query_data(cyapa);
+ if (error)
+ goto out;
+ /* Only support product ID starting with CYTRA */
+ if (memcmp(cyapa->product_id, product_id,
+ strlen(product_id)) != 0) {
+ dev_err(dev, "%s: unknown product ID (%s)\n",
+ __func__, cyapa->product_id);
+ error = -EINVAL;
+ }
+ break;
+ default:
+ error = -EINVAL;
+ }
+
+out:
+ return error;
+}
+
+/*
+ * Return false, do not continue process
+ * Return true, continue process.
+ */
+static bool cyapa_gen5_irq_cmd_handler(struct cyapa *cyapa)
+{
+ struct cyapa_gen5_cmd_states *gen5_pip = &cyapa->cmd_states.gen5;
+ int length;
+
+ if (atomic_read(&gen5_pip->cmd_issued)) {
+ /* Polling command response data. */
+ if (gen5_pip->is_irq_mode == false)
+ return false;
+
+ /*
+ * Read out all none command response data.
+ * these output data may caused by user put finger on
+ * trackpad when host waiting the command response.
+ */
+ cyapa_i2c_pip_read(cyapa, gen5_pip->irq_cmd_buf,
+ GEN5_RESP_LENGTH_SIZE);
+ length = get_unaligned_le16(gen5_pip->irq_cmd_buf);
+ length = (length <= GEN5_RESP_LENGTH_SIZE) ?
+ GEN5_RESP_LENGTH_SIZE : length;
+ if (length > GEN5_RESP_LENGTH_SIZE)
+ cyapa_i2c_pip_read(cyapa,
+ gen5_pip->irq_cmd_buf, length);
+
+ if (!(gen5_pip->resp_sort_func &&
+ gen5_pip->resp_sort_func(cyapa,
+ gen5_pip->irq_cmd_buf, length))) {
+ /*
+ * Cover the Gen5 V1 firmware issue.
+ * The issue is there is no interrut will be
+ * asserted to notityf host to read a command
+ * data out when always has finger touch on
+ * trackpad during the command is issued to
+ * trackad device.
+ * This issue has the scenario is that,
+ * user always has his fingers touched on
+ * trackpad device when booting/rebooting
+ * their chrome book.
+ */
+ length = 0;
+ if (gen5_pip->resp_len)
+ length = *gen5_pip->resp_len;
+ cyapa_empty_pip_output_data(cyapa,
+ gen5_pip->resp_data,
+ &length,
+ gen5_pip->resp_sort_func);
+ if (gen5_pip->resp_len && length != 0) {
+ *gen5_pip->resp_len = length;
+ atomic_dec(&gen5_pip->cmd_issued);
+ complete(&gen5_pip->cmd_ready);
+ }
+ return false;
+ }
+
+ if (gen5_pip->resp_data && gen5_pip->resp_len) {
+ *gen5_pip->resp_len = (*gen5_pip->resp_len < length) ?
+ *gen5_pip->resp_len : length;
+ memcpy(gen5_pip->resp_data, gen5_pip->irq_cmd_buf,
+ *gen5_pip->resp_len);
+ }
+ atomic_dec(&gen5_pip->cmd_issued);
+ complete(&gen5_pip->cmd_ready);
+ return false;
+ }
+
+ return true;
+}
+
+static void cyapa_gen5_report_buttons(struct cyapa *cyapa,
+ const struct cyapa_gen5_report_data *report_data)
+{
+ struct input_dev *input = cyapa->input;
+ u8 buttons = report_data->report_head[GEN5_BUTTONS_OFFSET];
+
+ buttons = (buttons << CAPABILITY_BTN_SHIFT) & CAPABILITY_BTN_MASK;
+
+ if (cyapa->btn_capability & CAPABILITY_LEFT_BTN_MASK) {
+ input_report_key(input, BTN_LEFT,
+ !!(buttons & CAPABILITY_LEFT_BTN_MASK));
+ }
+ if (cyapa->btn_capability & CAPABILITY_MIDDLE_BTN_MASK) {
+ input_report_key(input, BTN_MIDDLE,
+ !!(buttons & CAPABILITY_MIDDLE_BTN_MASK));
+ }
+ if (cyapa->btn_capability & CAPABILITY_RIGHT_BTN_MASK) {
+ input_report_key(input, BTN_RIGHT,
+ !!(buttons & CAPABILITY_RIGHT_BTN_MASK));
+ }
+
+ input_sync(input);
+}
+
+static void cyapa_gen5_report_slot_data(struct cyapa *cyapa,
+ const struct cyapa_gen5_touch_record *touch)
+{
+ struct input_dev *input = cyapa->input;
+ u8 event_id = GEN5_GET_EVENT_ID(touch->touch_tip_event_id);
+ int slot = GEN5_GET_TOUCH_ID(touch->touch_tip_event_id);
+ int x, y;
+
+ if (event_id == RECORD_EVENT_LIFTOFF)
+ return;
+
+ input_mt_slot(input, slot);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, true);
+ x = (touch->x_hi << 8) | touch->x_lo;
+ if (cyapa->x_origin)
+ x = cyapa->max_abs_x - x;
+ input_report_abs(input, ABS_MT_POSITION_X, x);
+ y = (touch->y_hi << 8) | touch->y_lo;
+ if (cyapa->y_origin)
+ y = cyapa->max_abs_y - y;
+ input_report_abs(input, ABS_MT_POSITION_Y, y);
+ input_report_abs(input, ABS_MT_PRESSURE,
+ touch->z);
+ input_report_abs(input, ABS_MT_TOUCH_MAJOR,
+ touch->major_axis_len);
+ input_report_abs(input, ABS_MT_TOUCH_MINOR,
+ touch->minor_axis_len);
+
+ input_report_abs(input, ABS_MT_WIDTH_MAJOR,
+ touch->major_tool_len);
+ input_report_abs(input, ABS_MT_WIDTH_MINOR,
+ touch->minor_tool_len);
+
+ input_report_abs(input, ABS_MT_ORIENTATION,
+ touch->orientation);
+}
+
+static void cyapa_gen5_report_touches(struct cyapa *cyapa,
+ const struct cyapa_gen5_report_data *report_data)
+{
+ struct input_dev *input = cyapa->input;
+ unsigned int touch_num;
+ int i;
+
+ touch_num = report_data->report_head[GEN5_NUMBER_OF_TOUCH_OFFSET] &
+ GEN5_NUMBER_OF_TOUCH_MASK;
+
+ for (i = 0; i < touch_num; i++)
+ cyapa_gen5_report_slot_data(cyapa,
+ &report_data->touch_records[i]);
+
+ input_mt_sync_frame(input);
+ input_sync(input);
+}
+
+static int cyapa_gen5_irq_handler(struct cyapa *cyapa)
+{
+ struct device *dev = &cyapa->client->dev;
+ struct cyapa_gen5_report_data report_data;
+ int ret;
+ u8 report_id;
+ unsigned int report_len;
+
+ if (cyapa->gen != CYAPA_GEN5 ||
+ cyapa->state != CYAPA_STATE_GEN5_APP) {
+ dev_err(dev, "invalid device state, gen=%d, state=0x%02x\n",
+ cyapa->gen, cyapa->state);
+ return -EINVAL;
+ }
+
+ ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data,
+ GEN5_RESP_LENGTH_SIZE);
+ if (ret != GEN5_RESP_LENGTH_SIZE) {
+ dev_err(dev, "failed to read length bytes, (%d)\n", ret);
+ return -EINVAL;
+ }
+
+ report_len = get_unaligned_le16(
+ &report_data.report_head[GEN5_RESP_LENGTH_OFFSET]);
+ if (report_len < GEN5_RESP_LENGTH_SIZE) {
+ /* Invliad length or internal reset happened. */
+ dev_err(dev, "invalid report_len=%d. bytes: %02x %02x\n",
+ report_len, report_data.report_head[0],
+ report_data.report_head[1]);
+ return -EINVAL;
+ }
+
+ /* Idle, no data for report. */
+ if (report_len == GEN5_RESP_LENGTH_SIZE)
+ return 0;
+
+ ret = cyapa_i2c_pip_read(cyapa, (u8 *)&report_data, report_len);
+ if (ret != report_len) {
+ dev_err(dev, "failed to read %d bytes report data, (%d)\n",
+ report_len, ret);
+ return -EINVAL;
+ }
+
+ report_id = report_data.report_head[GEN5_RESP_REPORT_ID_OFFSET];
+ if (report_id == GEN5_WAKEUP_EVENT_REPORT_ID &&
+ report_len == GEN5_WAKEUP_EVENT_SIZE) {
+ /*
+ * Device wake event from deep sleep mode for touch.
+ * This interrupt event is used to wake system up.
+ */
+ return 0;
+ } else if (report_id != GEN5_TOUCH_REPORT_ID &&
+ report_id != GEN5_BTN_REPORT_ID &&
+ report_id != GEN5_OLD_PUSH_BTN_REPORT_ID &&
+ report_id != GEN5_PUSH_BTN_REPORT_ID) {
+ /* Running in BL mode or unknown response data read. */
+ dev_err(dev, "invalid report_id=0x%02x\n", report_id);
+ return -EINVAL;
+ }
+
+ if (report_id == GEN5_TOUCH_REPORT_ID &&
+ (report_len < GEN5_TOUCH_REPORT_HEAD_SIZE ||
+ report_len > GEN5_TOUCH_REPORT_MAX_SIZE)) {
+ /* Invalid report data length for finger packet. */
+ dev_err(dev, "invalid touch packet length=%d\n", report_len);
+ return 0;
+ }
+
+ if ((report_id == GEN5_BTN_REPORT_ID ||
+ report_id == GEN5_OLD_PUSH_BTN_REPORT_ID ||
+ report_id == GEN5_PUSH_BTN_REPORT_ID) &&
+ (report_len < GEN5_BTN_REPORT_HEAD_SIZE ||
+ report_len > GEN5_BTN_REPORT_MAX_SIZE)) {
+ /* Invalid report data length of button packet. */
+ dev_err(dev, "invalid button packet length=%d\n", report_len);
+ return 0;
+ }
+
+ if (report_id == GEN5_TOUCH_REPORT_ID)
+ cyapa_gen5_report_touches(cyapa, &report_data);
+ else
+ cyapa_gen5_report_buttons(cyapa, &report_data);
+
+ return 0;
+}
+
+static int cyapa_gen5_bl_activate(struct cyapa *cyapa) { return 0; }
+static int cyapa_gen5_bl_deactivate(struct cyapa *cyapa) { return 0; }
+
+const struct cyapa_dev_ops cyapa_gen5_ops = {
+ .check_fw = cyapa_gen5_check_fw,
+ .bl_enter = cyapa_gen5_bl_enter,
+ .bl_initiate = cyapa_gen5_bl_initiate,
+ .update_fw = cyapa_gen5_do_fw_update,
+ .bl_activate = cyapa_gen5_bl_activate,
+ .bl_deactivate = cyapa_gen5_bl_deactivate,
+
+ .show_baseline = cyapa_gen5_show_baseline,
+ .calibrate_store = cyapa_gen5_do_calibrate,
+
+ .initialize = cyapa_gen5_initialize,
+
+ .state_parse = cyapa_gen5_state_parse,
+ .operational_check = cyapa_gen5_do_operational_check,
+
+ .irq_handler = cyapa_gen5_irq_handler,
+ .irq_cmd_handler = cyapa_gen5_irq_cmd_handler,
+ .sort_empty_output_data = cyapa_empty_pip_output_data,
+ .set_power_mode = cyapa_gen5_set_power_mode,
+};
diff --git a/drivers/input/mouse/cypress_ps2.c b/drivers/input/mouse/cypress_ps2.c
index 8af34ffe208b..28dcfc822bf6 100644
--- a/drivers/input/mouse/cypress_ps2.c
+++ b/drivers/input/mouse/cypress_ps2.c
@@ -538,7 +538,7 @@ static void cypress_process_packet(struct psmouse *psmouse, bool zero_pkt)
pos[i].y = contact->y;
}
- input_mt_assign_slots(input, slots, pos, n);
+ input_mt_assign_slots(input, slots, pos, n, 0);
for (i = 0; i < n; i++) {
contact = &report_data.contacts[i];
@@ -710,8 +710,3 @@ err_exit:
return -1;
}
-
-bool cypress_supported(void)
-{
- return true;
-}
diff --git a/drivers/input/mouse/cypress_ps2.h b/drivers/input/mouse/cypress_ps2.h
index 4720f21d2d70..81f68aaed7c8 100644
--- a/drivers/input/mouse/cypress_ps2.h
+++ b/drivers/input/mouse/cypress_ps2.h
@@ -172,7 +172,6 @@ struct cytp_data {
#ifdef CONFIG_MOUSE_PS2_CYPRESS
int cypress_detect(struct psmouse *psmouse, bool set_properties);
int cypress_init(struct psmouse *psmouse);
-bool cypress_supported(void);
#else
inline int cypress_detect(struct psmouse *psmouse, bool set_properties)
{
@@ -182,10 +181,6 @@ inline int cypress_init(struct psmouse *psmouse)
{
return -ENOSYS;
}
-inline bool cypress_supported(void)
-{
- return 0;
-}
#endif /* CONFIG_MOUSE_PS2_CYPRESS */
#endif /* _CYPRESS_PS2_H */
diff --git a/drivers/input/mouse/elan_i2c.h b/drivers/input/mouse/elan_i2c.h
index 2e838626205f..e100c1b31597 100644
--- a/drivers/input/mouse/elan_i2c.h
+++ b/drivers/input/mouse/elan_i2c.h
@@ -4,7 +4,6 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.5
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -33,8 +32,9 @@
#define ETP_FW_IAP_PAGE_ERR (1 << 5)
#define ETP_FW_IAP_INTF_ERR (1 << 4)
#define ETP_FW_PAGE_SIZE 64
-#define ETP_FW_PAGE_COUNT 768
-#define ETP_FW_SIZE (ETP_FW_PAGE_SIZE * ETP_FW_PAGE_COUNT)
+#define ETP_FW_VAILDPAGE_COUNT 768
+#define ETP_FW_SIGNATURE_SIZE 6
+#define ETP_FW_SIGNATURE_ADDRESS 0xBFFA
struct i2c_client;
struct completion;
diff --git a/drivers/input/mouse/elan_i2c_core.c b/drivers/input/mouse/elan_i2c_core.c
index 0cb2be48d537..7ce8bfe22d7e 100644
--- a/drivers/input/mouse/elan_i2c_core.c
+++ b/drivers/input/mouse/elan_i2c_core.c
@@ -4,7 +4,7 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.5
+ * Version: 1.5.6
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -40,7 +40,7 @@
#include "elan_i2c.h"
#define DRIVER_NAME "elan_i2c"
-#define ELAN_DRIVER_VERSION "1.5.5"
+#define ELAN_DRIVER_VERSION "1.5.6"
#define ETP_PRESSURE_OFFSET 25
#define ETP_MAX_PRESSURE 255
#define ETP_FWIDTH_REDUCE 90
@@ -312,7 +312,7 @@ static int __elan_update_firmware(struct elan_tp_data *data,
iap_start_addr = get_unaligned_le16(&fw->data[ETP_IAP_START_ADDR * 2]);
boot_page_count = (iap_start_addr * 2) / ETP_FW_PAGE_SIZE;
- for (i = boot_page_count; i < ETP_FW_PAGE_COUNT; i++) {
+ for (i = boot_page_count; i < ETP_FW_VAILDPAGE_COUNT; i++) {
u16 checksum = 0;
const u8 *page = &fw->data[i * ETP_FW_PAGE_SIZE];
@@ -434,10 +434,11 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- struct i2c_client *client = to_i2c_client(dev);
- struct elan_tp_data *data = i2c_get_clientdata(client);
+ struct elan_tp_data *data = dev_get_drvdata(dev);
const struct firmware *fw;
int error;
+ const u8 *fw_signature;
+ static const u8 signature[] = {0xAA, 0x55, 0xCC, 0x33, 0xFF, 0xFF};
error = request_firmware(&fw, ETP_FW_NAME, dev);
if (error) {
@@ -446,10 +447,12 @@ static ssize_t elan_sysfs_update_fw(struct device *dev,
return error;
}
- /* Firmware must be exactly PAGE_NUM * PAGE_SIZE bytes */
- if (fw->size != ETP_FW_SIZE) {
- dev_err(dev, "invalid firmware size = %zu, expected %d.\n",
- fw->size, ETP_FW_SIZE);
+ /* Firmware file must match signature data */
+ fw_signature = &fw->data[ETP_FW_SIGNATURE_ADDRESS];
+ if (memcmp(fw_signature, signature, sizeof(signature)) != 0) {
+ dev_err(dev, "signature mismatch (expected %*ph, got %*ph)\n",
+ (int)sizeof(signature), signature,
+ (int)sizeof(signature), fw_signature);
error = -EBADF;
goto out_release_fw;
}
diff --git a/drivers/input/mouse/elan_i2c_i2c.c b/drivers/input/mouse/elan_i2c_i2c.c
index 97d4937fc244..029941f861af 100644
--- a/drivers/input/mouse/elan_i2c_i2c.c
+++ b/drivers/input/mouse/elan_i2c_i2c.c
@@ -4,7 +4,6 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.5
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
diff --git a/drivers/input/mouse/elan_i2c_smbus.c b/drivers/input/mouse/elan_i2c_smbus.c
index 359bf8583d54..06a2bcd1cda2 100644
--- a/drivers/input/mouse/elan_i2c_smbus.c
+++ b/drivers/input/mouse/elan_i2c_smbus.c
@@ -4,7 +4,6 @@
* Copyright (c) 2013 ELAN Microelectronics Corp.
*
* Author: 林政維 (Duson Lin) <dusonlin@emc.com.tw>
- * Version: 1.5.5
*
* Based on cyapa driver:
* copyright (c) 2011-2012 Cypress Semiconductor, Inc.
@@ -71,7 +70,7 @@ static int elan_smbus_initialize(struct i2c_client *client)
/* compare hello packet */
if (memcmp(values, check, ETP_SMBUS_HELLOPACKET_LEN)) {
- dev_err(&client->dev, "hello packet fail [%*px]\n",
+ dev_err(&client->dev, "hello packet fail [%*ph]\n",
ETP_SMBUS_HELLOPACKET_LEN, values);
return -ENXIO;
}
diff --git a/drivers/input/mouse/elantech.c b/drivers/input/mouse/elantech.c
index 77ecf6d32237..6e22682c8255 100644
--- a/drivers/input/mouse/elantech.c
+++ b/drivers/input/mouse/elantech.c
@@ -1097,6 +1097,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Asus UX31 0x361f00 20, 15, 0e clickpad
* Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad
+ * Fujitsu LIFEBOOK E544 0x470f00 d0, 12, 09 2 hw buttons
+ * Fujitsu LIFEBOOK E554 0x570f01 40, 14, 0c 2 hw buttons
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
* Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
* Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
@@ -1475,6 +1477,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"),
},
},
+ {
+ /* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
+ },
+ },
+ {
+ /* Fujitsu LIFEBOOK E544 does not work with crc_enabled == 0 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"),
+ },
+ },
#endif
{ }
};
diff --git a/drivers/input/mouse/focaltech.c b/drivers/input/mouse/focaltech.c
index f4d657ee1cc0..757f78a94aec 100644
--- a/drivers/input/mouse/focaltech.c
+++ b/drivers/input/mouse/focaltech.c
@@ -2,6 +2,7 @@
* Focaltech TouchPad PS/2 mouse driver
*
* Copyright (c) 2014 Red Hat Inc.
+ * Copyright (c) 2014 Mathias Gottschlag <mgottschlag@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
@@ -13,15 +14,14 @@
* Hans de Goede <hdegoede@redhat.com>
*/
-/*
- * The Focaltech PS/2 touchpad protocol is unknown. This drivers deals with
- * detection only, to avoid further detection attempts confusing the touchpad
- * this way it at least works in PS/2 mouse compatibility mode.
- */
#include <linux/device.h>
#include <linux/libps2.h>
+#include <linux/input/mt.h>
+#include <linux/serio.h>
+#include <linux/slab.h>
#include "psmouse.h"
+#include "focaltech.h"
static const char * const focaltech_pnp_ids[] = {
"FLT0101",
@@ -30,6 +30,12 @@ static const char * const focaltech_pnp_ids[] = {
NULL
};
+/*
+ * Even if the kernel is built without support for Focaltech PS/2 touchpads (or
+ * when the real driver fails to recognize the device), we still have to detect
+ * them in order to avoid further detection attempts confusing the touchpad.
+ * This way it at least works in PS/2 mouse compatibility mode.
+ */
int focaltech_detect(struct psmouse *psmouse, bool set_properties)
{
if (!psmouse_matches_pnp_id(psmouse, focaltech_pnp_ids))
@@ -37,16 +43,394 @@ int focaltech_detect(struct psmouse *psmouse, bool set_properties)
if (set_properties) {
psmouse->vendor = "FocalTech";
- psmouse->name = "FocalTech Touchpad in mouse emulation mode";
+ psmouse->name = "FocalTech Touchpad";
}
return 0;
}
-int focaltech_init(struct psmouse *psmouse)
+static void focaltech_reset(struct psmouse *psmouse)
{
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_RESET_DIS);
psmouse_reset(psmouse);
+}
+
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH
+
+/*
+ * Packet types - the numbers are not consecutive, so we might be missing
+ * something here.
+ */
+#define FOC_TOUCH 0x3 /* bitmap of active fingers */
+#define FOC_ABS 0x6 /* absolute position of one finger */
+#define FOC_REL 0x9 /* relative position of 1-2 fingers */
+
+#define FOC_MAX_FINGERS 5
+
+#define FOC_MAX_X 2431
+#define FOC_MAX_Y 1663
+
+/*
+ * Current state of a single finger on the touchpad.
+ */
+struct focaltech_finger_state {
+ /* The touchpad has generated a touch event for the finger */
+ bool active;
+
+ /*
+ * The touchpad has sent position data for the finger. The
+ * flag is 0 when the finger is not active, and there is a
+ * time between the first touch event for the finger and the
+ * following absolute position packet for the finger where the
+ * touchpad has declared the finger to be valid, but we do not
+ * have any valid position yet.
+ */
+ bool valid;
+
+ /*
+ * Absolute position (from the bottom left corner) of the
+ * finger.
+ */
+ unsigned int x;
+ unsigned int y;
+};
+
+/*
+ * Description of the current state of the touchpad hardware.
+ */
+struct focaltech_hw_state {
+ /*
+ * The touchpad tracks the positions of the fingers for us,
+ * the array indices correspond to the finger indices returned
+ * in the report packages.
+ */
+ struct focaltech_finger_state fingers[FOC_MAX_FINGERS];
+
+ /* True if the clickpad has been pressed. */
+ bool pressed;
+};
+
+struct focaltech_data {
+ unsigned int x_max, y_max;
+ struct focaltech_hw_state state;
+};
+
+static void focaltech_report_state(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ struct input_dev *dev = psmouse->dev;
+ int i;
+
+ for (i = 0; i < FOC_MAX_FINGERS; i++) {
+ struct focaltech_finger_state *finger = &state->fingers[i];
+ bool active = finger->active && finger->valid;
+
+ input_mt_slot(dev, i);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, active);
+ if (active) {
+ input_report_abs(dev, ABS_MT_POSITION_X, finger->x);
+ input_report_abs(dev, ABS_MT_POSITION_Y,
+ FOC_MAX_Y - finger->y);
+ }
+ }
+ input_mt_report_pointer_emulation(dev, true);
+
+ input_report_key(psmouse->dev, BTN_LEFT, state->pressed);
+ input_sync(psmouse->dev);
+}
+
+static void focaltech_process_touch_packet(struct psmouse *psmouse,
+ unsigned char *packet)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ unsigned char fingers = packet[1];
+ int i;
+
+ state->pressed = (packet[0] >> 4) & 1;
+
+ /* the second byte contains a bitmap of all fingers touching the pad */
+ for (i = 0; i < FOC_MAX_FINGERS; i++) {
+ state->fingers[i].active = fingers & 0x1;
+ if (!state->fingers[i].active) {
+ /*
+ * Even when the finger becomes active again, we still
+ * will have to wait for the first valid position.
+ */
+ state->fingers[i].valid = false;
+ }
+ fingers >>= 1;
+ }
+}
+
+static void focaltech_process_abs_packet(struct psmouse *psmouse,
+ unsigned char *packet)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ unsigned int finger;
+
+ finger = (packet[1] >> 4) - 1;
+ if (finger >= FOC_MAX_FINGERS) {
+ psmouse_err(psmouse, "Invalid finger in abs packet: %d\n",
+ finger);
+ return;
+ }
+
+ state->pressed = (packet[0] >> 4) & 1;
+
+ /*
+ * packet[5] contains some kind of tool size in the most
+ * significant nibble. 0xff is a special value (latching) that
+ * signals a large contact area.
+ */
+ if (packet[5] == 0xff) {
+ state->fingers[finger].valid = false;
+ return;
+ }
+
+ state->fingers[finger].x = ((packet[1] & 0xf) << 8) | packet[2];
+ state->fingers[finger].y = (packet[3] << 8) | packet[4];
+ state->fingers[finger].valid = true;
+}
+
+static void focaltech_process_rel_packet(struct psmouse *psmouse,
+ unsigned char *packet)
+{
+ struct focaltech_data *priv = psmouse->private;
+ struct focaltech_hw_state *state = &priv->state;
+ int finger1, finger2;
+
+ state->pressed = packet[0] >> 7;
+ finger1 = ((packet[0] >> 4) & 0x7) - 1;
+ if (finger1 < FOC_MAX_FINGERS) {
+ state->fingers[finger1].x += (char)packet[1];
+ state->fingers[finger1].y += (char)packet[2];
+ } else {
+ psmouse_err(psmouse, "First finger in rel packet invalid: %d\n",
+ finger1);
+ }
+
+ /*
+ * If there is an odd number of fingers, the last relative
+ * packet only contains one finger. In this case, the second
+ * finger index in the packet is 0 (we subtract 1 in the lines
+ * above to create array indices, so the finger will overflow
+ * and be above FOC_MAX_FINGERS).
+ */
+ finger2 = ((packet[3] >> 4) & 0x7) - 1;
+ if (finger2 < FOC_MAX_FINGERS) {
+ state->fingers[finger2].x += (char)packet[4];
+ state->fingers[finger2].y += (char)packet[5];
+ }
+}
+
+static void focaltech_process_packet(struct psmouse *psmouse)
+{
+ unsigned char *packet = psmouse->packet;
+
+ switch (packet[0] & 0xf) {
+ case FOC_TOUCH:
+ focaltech_process_touch_packet(psmouse, packet);
+ break;
+
+ case FOC_ABS:
+ focaltech_process_abs_packet(psmouse, packet);
+ break;
+
+ case FOC_REL:
+ focaltech_process_rel_packet(psmouse, packet);
+ break;
+
+ default:
+ psmouse_err(psmouse, "Unknown packet type: %02x\n", packet[0]);
+ break;
+ }
+
+ focaltech_report_state(psmouse);
+}
+
+static psmouse_ret_t focaltech_process_byte(struct psmouse *psmouse)
+{
+ if (psmouse->pktcnt >= 6) { /* Full packet received */
+ focaltech_process_packet(psmouse);
+ return PSMOUSE_FULL_PACKET;
+ }
+
+ /*
+ * We might want to do some validation of the data here, but
+ * we do not know the protocol well enough
+ */
+ return PSMOUSE_GOOD_DATA;
+}
+
+static int focaltech_switch_protocol(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ unsigned char param[3];
+
+ param[0] = 0;
+ if (ps2_command(ps2dev, param, 0x10f8))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, 0x10f8))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, 0x10f8))
+ return -EIO;
+
+ param[0] = 1;
+ if (ps2_command(ps2dev, param, 0x10f8))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_ENABLE))
+ return -EIO;
return 0;
}
+
+static void focaltech_disconnect(struct psmouse *psmouse)
+{
+ focaltech_reset(psmouse);
+ kfree(psmouse->private);
+ psmouse->private = NULL;
+}
+
+static int focaltech_reconnect(struct psmouse *psmouse)
+{
+ int error;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ return error;
+ }
+
+ return 0;
+}
+
+static void focaltech_set_input_params(struct psmouse *psmouse)
+{
+ struct input_dev *dev = psmouse->dev;
+ struct focaltech_data *priv = psmouse->private;
+
+ /*
+ * Undo part of setup done for us by psmouse core since touchpad
+ * is not a relative device.
+ */
+ __clear_bit(EV_REL, dev->evbit);
+ __clear_bit(REL_X, dev->relbit);
+ __clear_bit(REL_Y, dev->relbit);
+ __clear_bit(BTN_RIGHT, dev->keybit);
+ __clear_bit(BTN_MIDDLE, dev->keybit);
+
+ /*
+ * Now set up our capabilities.
+ */
+ __set_bit(EV_ABS, dev->evbit);
+ input_set_abs_params(dev, ABS_MT_POSITION_X, 0, priv->x_max, 0, 0);
+ input_set_abs_params(dev, ABS_MT_POSITION_Y, 0, priv->y_max, 0, 0);
+ input_mt_init_slots(dev, 5, INPUT_MT_POINTER);
+ __set_bit(INPUT_PROP_BUTTONPAD, dev->propbit);
+}
+
+static int focaltech_read_register(struct ps2dev *ps2dev, int reg,
+ unsigned char *param)
+{
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETSCALE11))
+ return -EIO;
+
+ param[0] = 0;
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+ return -EIO;
+
+ param[0] = reg;
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_SETRES))
+ return -EIO;
+
+ if (ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO))
+ return -EIO;
+
+ return 0;
+}
+
+static int focaltech_read_size(struct psmouse *psmouse)
+{
+ struct ps2dev *ps2dev = &psmouse->ps2dev;
+ struct focaltech_data *priv = psmouse->private;
+ char param[3];
+
+ if (focaltech_read_register(ps2dev, 2, param))
+ return -EIO;
+
+ /* not sure whether this is 100% correct */
+ priv->x_max = (unsigned char)param[1] * 128;
+ priv->y_max = (unsigned char)param[2] * 128;
+
+ return 0;
+}
+int focaltech_init(struct psmouse *psmouse)
+{
+ struct focaltech_data *priv;
+ int error;
+
+ psmouse->private = priv = kzalloc(sizeof(struct focaltech_data),
+ GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ focaltech_reset(psmouse);
+
+ error = focaltech_read_size(psmouse);
+ if (error) {
+ psmouse_err(psmouse,
+ "Unable to read the size of the touchpad\n");
+ goto fail;
+ }
+
+ error = focaltech_switch_protocol(psmouse);
+ if (error) {
+ psmouse_err(psmouse, "Unable to initialize the device\n");
+ goto fail;
+ }
+
+ focaltech_set_input_params(psmouse);
+
+ psmouse->protocol_handler = focaltech_process_byte;
+ psmouse->pktsize = 6;
+ psmouse->disconnect = focaltech_disconnect;
+ psmouse->reconnect = focaltech_reconnect;
+ psmouse->cleanup = focaltech_reset;
+ /* resync is not supported yet */
+ psmouse->resync_time = 0;
+
+ return 0;
+
+fail:
+ focaltech_reset(psmouse);
+ kfree(priv);
+ return error;
+}
+
+#else /* CONFIG_MOUSE_PS2_FOCALTECH */
+
+int focaltech_init(struct psmouse *psmouse)
+{
+ focaltech_reset(psmouse);
+
+ return 0;
+}
+
+#endif /* CONFIG_MOUSE_PS2_FOCALTECH */
diff --git a/drivers/input/mouse/focaltech.h b/drivers/input/mouse/focaltech.h
index 498650c61e28..ca61ebff373e 100644
--- a/drivers/input/mouse/focaltech.h
+++ b/drivers/input/mouse/focaltech.h
@@ -2,6 +2,7 @@
* Focaltech TouchPad PS/2 mouse driver
*
* Copyright (c) 2014 Red Hat Inc.
+ * Copyright (c) 2014 Mathias Gottschlag <mgottschlag@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
diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c
index 95a3a6e2faf6..4ccd01d7a48d 100644
--- a/drivers/input/mouse/psmouse-base.c
+++ b/drivers/input/mouse/psmouse-base.c
@@ -725,16 +725,19 @@ static int psmouse_extensions(struct psmouse *psmouse,
/* Always check for focaltech, this is safe as it uses pnp-id matching */
if (psmouse_do_detect(focaltech_detect, psmouse, set_properties) == 0) {
- if (!set_properties || focaltech_init(psmouse) == 0) {
- /*
- * Not supported yet, use bare protocol.
- * Note that we need to also restrict
- * psmouse_max_proto so that psmouse_initialize()
- * does not try to reset rate and resolution,
- * because even that upsets the device.
- */
- psmouse_max_proto = PSMOUSE_PS2;
- return PSMOUSE_PS2;
+ if (max_proto > PSMOUSE_IMEX) {
+ if (!set_properties || focaltech_init(psmouse) == 0) {
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_FOCALTECH))
+ return PSMOUSE_FOCALTECH;
+ /*
+ * Note that we need to also restrict
+ * psmouse_max_proto so that psmouse_initialize()
+ * does not try to reset rate and resolution,
+ * because even that upsets the device.
+ */
+ psmouse_max_proto = PSMOUSE_PS2;
+ return PSMOUSE_PS2;
+ }
}
}
@@ -773,7 +776,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
* Try activating protocol, but check if support is enabled first, since
* we try detecting Synaptics even when protocol is disabled.
*/
- if (synaptics_supported() &&
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_SYNAPTICS) &&
(!set_properties || synaptics_init(psmouse) == 0)) {
return PSMOUSE_SYNAPTICS;
}
@@ -798,7 +801,7 @@ static int psmouse_extensions(struct psmouse *psmouse,
*/
if (max_proto > PSMOUSE_IMEX &&
cypress_detect(psmouse, set_properties) == 0) {
- if (cypress_supported()) {
+ if (IS_ENABLED(CONFIG_MOUSE_PS2_CYPRESS)) {
if (cypress_init(psmouse) == 0)
return PSMOUSE_CYPRESS;
@@ -1063,6 +1066,15 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.alias = "cortps",
.detect = cortron_detect,
},
+#ifdef CONFIG_MOUSE_PS2_FOCALTECH
+ {
+ .type = PSMOUSE_FOCALTECH,
+ .name = "FocalTechPS/2",
+ .alias = "focaltech",
+ .detect = focaltech_detect,
+ .init = focaltech_init,
+ },
+#endif
{
.type = PSMOUSE_AUTO,
.name = "auto",
diff --git a/drivers/input/mouse/psmouse.h b/drivers/input/mouse/psmouse.h
index f4cf664c7db3..c2ff137ecbdb 100644
--- a/drivers/input/mouse/psmouse.h
+++ b/drivers/input/mouse/psmouse.h
@@ -96,6 +96,7 @@ enum psmouse_type {
PSMOUSE_FSP,
PSMOUSE_SYNAPTICS_RELATIVE,
PSMOUSE_CYPRESS,
+ PSMOUSE_FOCALTECH,
PSMOUSE_AUTO /* This one should always be last */
};
diff --git a/drivers/input/mouse/synaptics.c b/drivers/input/mouse/synaptics.c
index f9472920d986..f2cceb6493a0 100644
--- a/drivers/input/mouse/synaptics.c
+++ b/drivers/input/mouse/synaptics.c
@@ -67,6 +67,9 @@
#define X_MAX_POSITIVE 8176
#define Y_MAX_POSITIVE 8176
+/* maximum ABS_MT_POSITION displacement (in mm) */
+#define DMAX 10
+
/*****************************************************************************
* Stuff we need even when we do not want native Synaptics support
****************************************************************************/
@@ -135,8 +138,9 @@ static const struct min_max_quirk min_max_pnpid_table[] = {
1232, 5710, 1156, 4696
},
{
- (const char * const []){"LEN0034", "LEN0036", "LEN0039",
- "LEN2002", "LEN2004", NULL},
+ (const char * const []){"LEN0034", "LEN0036", "LEN0037",
+ "LEN0039", "LEN2002", "LEN2004",
+ NULL},
1024, 5112, 2024, 4832
},
{
@@ -165,7 +169,7 @@ static const char * const topbuttonpad_pnp_ids[] = {
"LEN0034", /* T431s, L440, L540, T540, W540, X1 Carbon 2nd */
"LEN0035", /* X240 */
"LEN0036", /* T440 */
- "LEN0037",
+ "LEN0037", /* X1 Carbon 2nd */
"LEN0038",
"LEN0039", /* T440s */
"LEN0041",
@@ -574,14 +578,6 @@ static void synaptics_pt_create(struct psmouse *psmouse)
* Functions to interpret the absolute mode packets
****************************************************************************/
-static void synaptics_mt_state_set(struct synaptics_mt_state *state, int count,
- int sgm, int agm)
-{
- state->count = count;
- state->sgm = sgm;
- state->agm = agm;
-}
-
static void synaptics_parse_agm(const unsigned char buf[],
struct synaptics_data *priv,
struct synaptics_hw_state *hw)
@@ -600,16 +596,13 @@ static void synaptics_parse_agm(const unsigned char buf[],
break;
case 2:
- /* AGM-CONTACT packet: (count, sgm, agm) */
- synaptics_mt_state_set(&agm->mt_state, buf[1], buf[2], buf[4]);
+ /* AGM-CONTACT packet: we are only interested in the count */
+ priv->agm_count = buf[1];
break;
default:
break;
}
-
- /* Record that at least one AGM has been received since last SGM */
- priv->agm_pending = true;
}
static bool is_forcepad;
@@ -803,424 +796,68 @@ static void synaptics_report_buttons(struct psmouse *psmouse,
input_report_key(dev, BTN_0 + i, hw->ext_buttons & (1 << i));
}
-static void synaptics_report_slot(struct input_dev *dev, int slot,
- const struct synaptics_hw_state *hw)
-{
- input_mt_slot(dev, slot);
- input_mt_report_slot_state(dev, MT_TOOL_FINGER, (hw != NULL));
- if (!hw)
- return;
-
- input_report_abs(dev, ABS_MT_POSITION_X, hw->x);
- input_report_abs(dev, ABS_MT_POSITION_Y, synaptics_invert_y(hw->y));
- input_report_abs(dev, ABS_MT_PRESSURE, hw->z);
-}
-
static void synaptics_report_mt_data(struct psmouse *psmouse,
- struct synaptics_mt_state *mt_state,
- const struct synaptics_hw_state *sgm)
+ const struct synaptics_hw_state *sgm,
+ int num_fingers)
{
struct input_dev *dev = psmouse->dev;
struct synaptics_data *priv = psmouse->private;
- struct synaptics_hw_state *agm = &priv->agm;
- struct synaptics_mt_state *old = &priv->mt_state;
+ const struct synaptics_hw_state *hw[2] = { sgm, &priv->agm };
+ struct input_mt_pos pos[2];
+ int slot[2], nsemi, i;
- switch (mt_state->count) {
- case 0:
- synaptics_report_slot(dev, 0, NULL);
- synaptics_report_slot(dev, 1, NULL);
- break;
- case 1:
- if (mt_state->sgm == -1) {
- synaptics_report_slot(dev, 0, NULL);
- synaptics_report_slot(dev, 1, NULL);
- } else if (mt_state->sgm == 0) {
- synaptics_report_slot(dev, 0, sgm);
- synaptics_report_slot(dev, 1, NULL);
- } else {
- synaptics_report_slot(dev, 0, NULL);
- synaptics_report_slot(dev, 1, sgm);
- }
- break;
- default:
- /*
- * If the finger slot contained in SGM is valid, and either
- * hasn't changed, or is new, or the old SGM has now moved to
- * AGM, then report SGM in MTB slot 0.
- * Otherwise, empty MTB slot 0.
- */
- if (mt_state->sgm != -1 &&
- (mt_state->sgm == old->sgm ||
- old->sgm == -1 || mt_state->agm == old->sgm))
- synaptics_report_slot(dev, 0, sgm);
- else
- synaptics_report_slot(dev, 0, NULL);
+ nsemi = clamp_val(num_fingers, 0, 2);
- /*
- * If the finger slot contained in AGM is valid, and either
- * hasn't changed, or is new, then report AGM in MTB slot 1.
- * Otherwise, empty MTB slot 1.
- *
- * However, in the case where the AGM is new, make sure that
- * that it is either the same as the old SGM, or there was no
- * SGM.
- *
- * Otherwise, if the SGM was just 1, and the new AGM is 2, then
- * the new AGM will keep the old SGM's tracking ID, which can
- * cause apparent drumroll. This happens if in the following
- * valid finger sequence:
- *
- * Action SGM AGM (MTB slot:Contact)
- * 1. Touch contact 0 (0:0)
- * 2. Touch contact 1 (0:0, 1:1)
- * 3. Lift contact 0 (1:1)
- * 4. Touch contacts 2,3 (0:2, 1:3)
- *
- * In step 4, contact 3, in AGM must not be given the same
- * tracking ID as contact 1 had in step 3. To avoid this,
- * the first agm with contact 3 is dropped and slot 1 is
- * invalidated (tracking ID = -1).
- */
- if (mt_state->agm != -1 &&
- (mt_state->agm == old->agm ||
- (old->agm == -1 &&
- (old->sgm == -1 || mt_state->agm == old->sgm))))
- synaptics_report_slot(dev, 1, agm);
- else
- synaptics_report_slot(dev, 1, NULL);
- break;
+ for (i = 0; i < nsemi; i++) {
+ pos[i].x = hw[i]->x;
+ pos[i].y = synaptics_invert_y(hw[i]->y);
}
+ input_mt_assign_slots(dev, slot, pos, nsemi, DMAX * priv->x_res);
+
+ for (i = 0; i < nsemi; i++) {
+ input_mt_slot(dev, slot[i]);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
+ input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x);
+ input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y);
+ input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z);
+ }
+
+ input_mt_drop_unused(dev);
+
/* Don't use active slot count to generate BTN_TOOL events. */
input_mt_report_pointer_emulation(dev, false);
/* Send the number of fingers reported by touchpad itself. */
- input_mt_report_finger_count(dev, mt_state->count);
+ input_mt_report_finger_count(dev, num_fingers);
synaptics_report_buttons(psmouse, sgm);
input_sync(dev);
}
-/* Handle case where mt_state->count = 0 */
-static void synaptics_image_sensor_0f(struct synaptics_data *priv,
- struct synaptics_mt_state *mt_state)
-{
- synaptics_mt_state_set(mt_state, 0, -1, -1);
- priv->mt_state_lost = false;
-}
-
-/* Handle case where mt_state->count = 1 */
-static void synaptics_image_sensor_1f(struct synaptics_data *priv,
- struct synaptics_mt_state *mt_state)
-{
- struct synaptics_hw_state *agm = &priv->agm;
- struct synaptics_mt_state *old = &priv->mt_state;
-
- /*
- * If the last AGM was (0,0,0), and there is only one finger left,
- * then we absolutely know that SGM contains slot 0, and all other
- * fingers have been removed.
- */
- if (priv->agm_pending && agm->z == 0) {
- synaptics_mt_state_set(mt_state, 1, 0, -1);
- priv->mt_state_lost = false;
- return;
- }
-
- switch (old->count) {
- case 0:
- synaptics_mt_state_set(mt_state, 1, 0, -1);
- break;
- case 1:
- /*
- * If mt_state_lost, then the previous transition was 3->1,
- * and SGM now contains either slot 0 or 1, but we don't know
- * which. So, we just assume that the SGM now contains slot 1.
- *
- * If pending AGM and either:
- * (a) the previous SGM slot contains slot 0, or
- * (b) there was no SGM slot
- * then, the SGM now contains slot 1
- *
- * Case (a) happens with very rapid "drum roll" gestures, where
- * slot 0 finger is lifted and a new slot 1 finger touches
- * within one reporting interval.
- *
- * Case (b) happens if initially two or more fingers tap
- * briefly, and all but one lift before the end of the first
- * reporting interval.
- *
- * (In both these cases, slot 0 will becomes empty, so SGM
- * contains slot 1 with the new finger)
- *
- * Else, if there was no previous SGM, it now contains slot 0.
- *
- * Otherwise, SGM still contains the same slot.
- */
- if (priv->mt_state_lost ||
- (priv->agm_pending && old->sgm <= 0))
- synaptics_mt_state_set(mt_state, 1, 1, -1);
- else if (old->sgm == -1)
- synaptics_mt_state_set(mt_state, 1, 0, -1);
- break;
- case 2:
- /*
- * If mt_state_lost, we don't know which finger SGM contains.
- *
- * So, report 1 finger, but with both slots empty.
- * We will use slot 1 on subsequent 1->1
- */
- if (priv->mt_state_lost) {
- synaptics_mt_state_set(mt_state, 1, -1, -1);
- break;
- }
- /*
- * Since the last AGM was NOT (0,0,0), it was the finger in
- * slot 0 that has been removed.
- * So, SGM now contains previous AGM's slot, and AGM is now
- * empty.
- */
- synaptics_mt_state_set(mt_state, 1, old->agm, -1);
- break;
- case 3:
- /*
- * Since last AGM was not (0,0,0), we don't know which finger
- * is left.
- *
- * So, report 1 finger, but with both slots empty.
- * We will use slot 1 on subsequent 1->1
- */
- synaptics_mt_state_set(mt_state, 1, -1, -1);
- priv->mt_state_lost = true;
- break;
- case 4:
- case 5:
- /* mt_state was updated by AGM-CONTACT packet */
- break;
- }
-}
-
-/* Handle case where mt_state->count = 2 */
-static void synaptics_image_sensor_2f(struct synaptics_data *priv,
- struct synaptics_mt_state *mt_state)
-{
- struct synaptics_mt_state *old = &priv->mt_state;
-
- switch (old->count) {
- case 0:
- synaptics_mt_state_set(mt_state, 2, 0, 1);
- break;
- case 1:
- /*
- * If previous SGM contained slot 1 or higher, SGM now contains
- * slot 0 (the newly touching finger) and AGM contains SGM's
- * previous slot.
- *
- * Otherwise, SGM still contains slot 0 and AGM now contains
- * slot 1.
- */
- if (old->sgm >= 1)
- synaptics_mt_state_set(mt_state, 2, 0, old->sgm);
- else
- synaptics_mt_state_set(mt_state, 2, 0, 1);
- break;
- case 2:
- /*
- * If mt_state_lost, SGM now contains either finger 1 or 2, but
- * we don't know which.
- * So, we just assume that the SGM contains slot 0 and AGM 1.
- */
- if (priv->mt_state_lost)
- synaptics_mt_state_set(mt_state, 2, 0, 1);
- /*
- * Otherwise, use the same mt_state, since it either hasn't
- * changed, or was updated by a recently received AGM-CONTACT
- * packet.
- */
- break;
- case 3:
- /*
- * 3->2 transitions have two unsolvable problems:
- * 1) no indication is given which finger was removed
- * 2) no way to tell if agm packet was for finger 3
- * before 3->2, or finger 2 after 3->2.
- *
- * So, report 2 fingers, but empty all slots.
- * We will guess slots [0,1] on subsequent 2->2.
- */
- synaptics_mt_state_set(mt_state, 2, -1, -1);
- priv->mt_state_lost = true;
- break;
- case 4:
- case 5:
- /* mt_state was updated by AGM-CONTACT packet */
- break;
- }
-}
-
-/* Handle case where mt_state->count = 3 */
-static void synaptics_image_sensor_3f(struct synaptics_data *priv,
- struct synaptics_mt_state *mt_state)
-{
- struct synaptics_mt_state *old = &priv->mt_state;
-
- switch (old->count) {
- case 0:
- synaptics_mt_state_set(mt_state, 3, 0, 2);
- break;
- case 1:
- /*
- * If previous SGM contained slot 2 or higher, SGM now contains
- * slot 0 (one of the newly touching fingers) and AGM contains
- * SGM's previous slot.
- *
- * Otherwise, SGM now contains slot 0 and AGM contains slot 2.
- */
- if (old->sgm >= 2)
- synaptics_mt_state_set(mt_state, 3, 0, old->sgm);
- else
- synaptics_mt_state_set(mt_state, 3, 0, 2);
- break;
- case 2:
- /*
- * If the AGM previously contained slot 3 or higher, then the
- * newly touching finger is in the lowest available slot.
- *
- * If SGM was previously 1 or higher, then the new SGM is
- * now slot 0 (with a new finger), otherwise, the new finger
- * is now in a hidden slot between 0 and AGM's slot.
- *
- * In all such cases, the SGM now contains slot 0, and the AGM
- * continues to contain the same slot as before.
- */
- if (old->agm >= 3) {
- synaptics_mt_state_set(mt_state, 3, 0, old->agm);
- break;
- }
-
- /*
- * After some 3->1 and all 3->2 transitions, we lose track
- * of which slot is reported by SGM and AGM.
- *
- * For 2->3 in this state, report 3 fingers, but empty all
- * slots, and we will guess (0,2) on a subsequent 0->3.
- *
- * To userspace, the resulting transition will look like:
- * 2:[0,1] -> 3:[-1,-1] -> 3:[0,2]
- */
- if (priv->mt_state_lost) {
- synaptics_mt_state_set(mt_state, 3, -1, -1);
- break;
- }
-
- /*
- * If the (SGM,AGM) really previously contained slots (0, 1),
- * then we cannot know what slot was just reported by the AGM,
- * because the 2->3 transition can occur either before or after
- * the AGM packet. Thus, this most recent AGM could contain
- * either the same old slot 1 or the new slot 2.
- * Subsequent AGMs will be reporting slot 2.
- *
- * To userspace, the resulting transition will look like:
- * 2:[0,1] -> 3:[0,-1] -> 3:[0,2]
- */
- synaptics_mt_state_set(mt_state, 3, 0, -1);
- break;
- case 3:
- /*
- * If, for whatever reason, the previous agm was invalid,
- * Assume SGM now contains slot 0, AGM now contains slot 2.
- */
- if (old->agm <= 2)
- synaptics_mt_state_set(mt_state, 3, 0, 2);
- /*
- * mt_state either hasn't changed, or was updated by a recently
- * received AGM-CONTACT packet.
- */
- break;
-
- case 4:
- case 5:
- /* mt_state was updated by AGM-CONTACT packet */
- break;
- }
-}
-
-/* Handle case where mt_state->count = 4, or = 5 */
-static void synaptics_image_sensor_45f(struct synaptics_data *priv,
- struct synaptics_mt_state *mt_state)
-{
- /* mt_state was updated correctly by AGM-CONTACT packet */
- priv->mt_state_lost = false;
-}
-
static void synaptics_image_sensor_process(struct psmouse *psmouse,
struct synaptics_hw_state *sgm)
{
struct synaptics_data *priv = psmouse->private;
- struct synaptics_hw_state *agm = &priv->agm;
- struct synaptics_mt_state mt_state;
-
- /* Initialize using current mt_state (as updated by last agm) */
- mt_state = agm->mt_state;
+ int num_fingers;
/*
* Update mt_state using the new finger count and current mt_state.
*/
if (sgm->z == 0)
- synaptics_image_sensor_0f(priv, &mt_state);
+ num_fingers = 0;
else if (sgm->w >= 4)
- synaptics_image_sensor_1f(priv, &mt_state);
+ num_fingers = 1;
else if (sgm->w == 0)
- synaptics_image_sensor_2f(priv, &mt_state);
- else if (sgm->w == 1 && mt_state.count <= 3)
- synaptics_image_sensor_3f(priv, &mt_state);
+ num_fingers = 2;
+ else if (sgm->w == 1)
+ num_fingers = priv->agm_count ? priv->agm_count : 3;
else
- synaptics_image_sensor_45f(priv, &mt_state);
+ num_fingers = 4;
/* Send resulting input events to user space */
- synaptics_report_mt_data(psmouse, &mt_state, sgm);
-
- /* Store updated mt_state */
- priv->mt_state = agm->mt_state = mt_state;
- priv->agm_pending = false;
-}
-
-static void synaptics_profile_sensor_process(struct psmouse *psmouse,
- struct synaptics_hw_state *sgm,
- int num_fingers)
-{
- struct input_dev *dev = psmouse->dev;
- struct synaptics_data *priv = psmouse->private;
- struct synaptics_hw_state *hw[2] = { sgm, &priv->agm };
- struct input_mt_pos pos[2];
- int slot[2], nsemi, i;
-
- nsemi = clamp_val(num_fingers, 0, 2);
-
- for (i = 0; i < nsemi; i++) {
- pos[i].x = hw[i]->x;
- pos[i].y = synaptics_invert_y(hw[i]->y);
- }
-
- input_mt_assign_slots(dev, slot, pos, nsemi);
-
- for (i = 0; i < nsemi; i++) {
- input_mt_slot(dev, slot[i]);
- input_mt_report_slot_state(dev, MT_TOOL_FINGER, true);
- input_report_abs(dev, ABS_MT_POSITION_X, pos[i].x);
- input_report_abs(dev, ABS_MT_POSITION_Y, pos[i].y);
- input_report_abs(dev, ABS_MT_PRESSURE, hw[i]->z);
- }
-
- input_mt_drop_unused(dev);
- input_mt_report_pointer_emulation(dev, false);
- input_mt_report_finger_count(dev, num_fingers);
-
- synaptics_report_buttons(psmouse, sgm);
-
- input_sync(dev);
+ synaptics_report_mt_data(psmouse, sgm, num_fingers);
}
/*
@@ -1287,7 +924,7 @@ static void synaptics_process_packet(struct psmouse *psmouse)
}
if (cr48_profile_sensor) {
- synaptics_profile_sensor_process(psmouse, &hw, num_fingers);
+ synaptics_report_mt_data(psmouse, &hw, num_fingers);
return;
}
@@ -1444,7 +1081,7 @@ static void set_input_params(struct psmouse *psmouse,
ABS_MT_POSITION_Y);
/* Image sensors can report per-contact pressure */
input_set_abs_params(dev, ABS_MT_PRESSURE, 0, 255, 0, 0);
- input_mt_init_slots(dev, 2, INPUT_MT_POINTER);
+ input_mt_init_slots(dev, 2, INPUT_MT_POINTER | INPUT_MT_TRACK);
/* Image sensors can signal 4 and 5 finger clicks */
__set_bit(BTN_TOOL_QUADTAP, dev->keybit);
@@ -1817,11 +1454,6 @@ int synaptics_init_relative(struct psmouse *psmouse)
return __synaptics_init(psmouse, false);
}
-bool synaptics_supported(void)
-{
- return true;
-}
-
#else /* CONFIG_MOUSE_PS2_SYNAPTICS */
void __init synaptics_module_init(void)
@@ -1833,9 +1465,4 @@ int synaptics_init(struct psmouse *psmouse)
return -ENOSYS;
}
-bool synaptics_supported(void)
-{
- return false;
-}
-
#endif /* CONFIG_MOUSE_PS2_SYNAPTICS */
diff --git a/drivers/input/mouse/synaptics.h b/drivers/input/mouse/synaptics.h
index 1bd01f21783b..aedc3299b14e 100644
--- a/drivers/input/mouse/synaptics.h
+++ b/drivers/input/mouse/synaptics.h
@@ -119,16 +119,6 @@
#define SYN_REDUCED_FILTER_FUZZ 8
/*
- * A structure to describe which internal touchpad finger slots are being
- * reported in raw packets.
- */
-struct synaptics_mt_state {
- int count; /* num fingers being tracked */
- int sgm; /* which slot is reported by sgm pkt */
- int agm; /* which slot is reported by agm pkt*/
-};
-
-/*
* A structure to describe the state of the touchpad hardware (buttons and pad)
*/
struct synaptics_hw_state {
@@ -143,9 +133,6 @@ struct synaptics_hw_state {
unsigned int down:1;
unsigned char ext_buttons;
signed char scroll;
-
- /* As reported in last AGM-CONTACT packets */
- struct synaptics_mt_state mt_state;
};
struct synaptics_data {
@@ -170,15 +157,12 @@ struct synaptics_data {
struct serio *pt_port; /* Pass-through serio port */
- struct synaptics_mt_state mt_state; /* Current mt finger state */
- bool mt_state_lost; /* mt_state may be incorrect */
-
/*
* Last received Advanced Gesture Mode (AGM) packet. An AGM packet
* contains position data for a second contact, at half resolution.
*/
struct synaptics_hw_state agm;
- bool agm_pending; /* new AGM packet received */
+ unsigned int agm_count; /* finger count reported by agm */
/* ForcePad handling */
unsigned long press_start;
@@ -191,6 +175,5 @@ int synaptics_detect(struct psmouse *psmouse, bool set_properties);
int synaptics_init(struct psmouse *psmouse);
int synaptics_init_relative(struct psmouse *psmouse);
void synaptics_reset(struct psmouse *psmouse);
-bool synaptics_supported(void);
#endif /* _SYNAPTICS_H */
diff --git a/drivers/input/serio/Kconfig b/drivers/input/serio/Kconfig
index bc2d47431bdc..77833d7a004b 100644
--- a/drivers/input/serio/Kconfig
+++ b/drivers/input/serio/Kconfig
@@ -281,4 +281,14 @@ config HYPERV_KEYBOARD
To compile this driver as a module, choose M here: the module will
be called hyperv_keyboard.
+config SERIO_SUN4I_PS2
+ tristate "Allwinner A10 PS/2 controller support"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ help
+ This selects support for the PS/2 Host Controller on
+ Allwinner A10.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sun4i-ps2.
+
endif
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
index 815d874fe724..c600089b7a34 100644
--- a/drivers/input/serio/Makefile
+++ b/drivers/input/serio/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_SERIO_ARC_PS2) += arc_ps2.o
obj-$(CONFIG_SERIO_APBPS2) += apbps2.o
obj-$(CONFIG_SERIO_OLPC_APSP) += olpc_apsp.o
obj-$(CONFIG_HYPERV_KEYBOARD) += hyperv-keyboard.o
+obj-$(CONFIG_SERIO_SUN4I_PS2) += sun4i-ps2.o
diff --git a/drivers/input/serio/gscps2.c b/drivers/input/serio/gscps2.c
index 8d9ba0c3827c..94ab494a6ade 100644
--- a/drivers/input/serio/gscps2.c
+++ b/drivers/input/serio/gscps2.c
@@ -40,7 +40,6 @@
MODULE_AUTHOR("Laurent Canet <canetl@esiee.fr>, Thibaut Varene <varenet@parisc-linux.org>, Helge Deller <deller@gmx.de>");
MODULE_DESCRIPTION("HP GSC PS2 port driver");
MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
#define PFX "gscps2.c: "
@@ -439,6 +438,7 @@ static struct parisc_device_id gscps2_device_tbl[] = {
#endif
{ 0, } /* 0 terminated list */
};
+MODULE_DEVICE_TABLE(parisc, gscps2_device_tbl);
static struct parisc_driver parisc_ps2_driver = {
.name = "gsc_ps2",
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 764857b4e268..c11556563ef0 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -152,6 +152,14 @@ static const struct dmi_system_id __initconst i8042_dmi_noloop_table[] = {
},
},
{
+ /* Medion Akoya E7225 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Medion"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Akoya E7225"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1.0"),
+ },
+ },
+ {
/* Blue FB5601 */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "blue"),
diff --git a/drivers/input/serio/sun4i-ps2.c b/drivers/input/serio/sun4i-ps2.c
new file mode 100644
index 000000000000..04b96fe39339
--- /dev/null
+++ b/drivers/input/serio/sun4i-ps2.c
@@ -0,0 +1,340 @@
+/*
+ * Driver for Allwinner A10 PS2 host controller
+ *
+ * Author: Vishnu Patekar <vishnupatekar0510@gmail.com>
+ * Aaron.maoye <leafy.myeh@newbietech.com>
+ */
+
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <linux/interrupt.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/clk.h>
+#include <linux/mod_devicetable.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "sun4i-ps2"
+
+/* register offset definitions */
+#define PS2_REG_GCTL 0x00 /* PS2 Module Global Control Reg */
+#define PS2_REG_DATA 0x04 /* PS2 Module Data Reg */
+#define PS2_REG_LCTL 0x08 /* PS2 Module Line Control Reg */
+#define PS2_REG_LSTS 0x0C /* PS2 Module Line Status Reg */
+#define PS2_REG_FCTL 0x10 /* PS2 Module FIFO Control Reg */
+#define PS2_REG_FSTS 0x14 /* PS2 Module FIFO Status Reg */
+#define PS2_REG_CLKDR 0x18 /* PS2 Module Clock Divider Reg*/
+
+/* PS2 GLOBAL CONTROL REGISTER PS2_GCTL */
+#define PS2_GCTL_INTFLAG BIT(4)
+#define PS2_GCTL_INTEN BIT(3)
+#define PS2_GCTL_RESET BIT(2)
+#define PS2_GCTL_MASTER BIT(1)
+#define PS2_GCTL_BUSEN BIT(0)
+
+/* PS2 LINE CONTROL REGISTER */
+#define PS2_LCTL_NOACK BIT(18)
+#define PS2_LCTL_TXDTOEN BIT(8)
+#define PS2_LCTL_STOPERREN BIT(3)
+#define PS2_LCTL_ACKERREN BIT(2)
+#define PS2_LCTL_PARERREN BIT(1)
+#define PS2_LCTL_RXDTOEN BIT(0)
+
+/* PS2 LINE STATUS REGISTER */
+#define PS2_LSTS_TXTDO BIT(8)
+#define PS2_LSTS_STOPERR BIT(3)
+#define PS2_LSTS_ACKERR BIT(2)
+#define PS2_LSTS_PARERR BIT(1)
+#define PS2_LSTS_RXTDO BIT(0)
+
+#define PS2_LINE_ERROR_BIT \
+ (PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR | \
+ PS2_LSTS_PARERR | PS2_LSTS_RXTDO)
+
+/* PS2 FIFO CONTROL REGISTER */
+#define PS2_FCTL_TXRST BIT(17)
+#define PS2_FCTL_RXRST BIT(16)
+#define PS2_FCTL_TXUFIEN BIT(10)
+#define PS2_FCTL_TXOFIEN BIT(9)
+#define PS2_FCTL_TXRDYIEN BIT(8)
+#define PS2_FCTL_RXUFIEN BIT(2)
+#define PS2_FCTL_RXOFIEN BIT(1)
+#define PS2_FCTL_RXRDYIEN BIT(0)
+
+/* PS2 FIFO STATUS REGISTER */
+#define PS2_FSTS_TXUF BIT(10)
+#define PS2_FSTS_TXOF BIT(9)
+#define PS2_FSTS_TXRDY BIT(8)
+#define PS2_FSTS_RXUF BIT(2)
+#define PS2_FSTS_RXOF BIT(1)
+#define PS2_FSTS_RXRDY BIT(0)
+
+#define PS2_FIFO_ERROR_BIT \
+ (PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_RXUF | PS2_FSTS_RXOF)
+
+#define PS2_SAMPLE_CLK 1000000
+#define PS2_SCLK 125000
+
+struct sun4i_ps2data {
+ struct serio *serio;
+ struct device *dev;
+
+ /* IO mapping base */
+ void __iomem *reg_base;
+
+ /* clock management */
+ struct clk *clk;
+
+ /* irq */
+ spinlock_t lock;
+ int irq;
+};
+
+static irqreturn_t sun4i_ps2_interrupt(int irq, void *dev_id)
+{
+ struct sun4i_ps2data *drvdata = dev_id;
+ u32 intr_status;
+ u32 fifo_status;
+ unsigned char byte;
+ unsigned int rxflags = 0;
+ u32 rval;
+
+ spin_lock(&drvdata->lock);
+
+ /* Get the PS/2 interrupts and clear them */
+ intr_status = readl(drvdata->reg_base + PS2_REG_LSTS);
+ fifo_status = readl(drvdata->reg_base + PS2_REG_FSTS);
+
+ /* Check line status register */
+ if (intr_status & PS2_LINE_ERROR_BIT) {
+ rxflags = (intr_status & PS2_LINE_ERROR_BIT) ? SERIO_FRAME : 0;
+ rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_PARITY : 0;
+ rxflags |= (intr_status & PS2_LSTS_PARERR) ? SERIO_TIMEOUT : 0;
+
+ rval = PS2_LSTS_TXTDO | PS2_LSTS_STOPERR | PS2_LSTS_ACKERR |
+ PS2_LSTS_PARERR | PS2_LSTS_RXTDO;
+ writel(rval, drvdata->reg_base + PS2_REG_LSTS);
+ }
+
+ /* Check FIFO status register */
+ if (fifo_status & PS2_FIFO_ERROR_BIT) {
+ rval = PS2_FSTS_TXUF | PS2_FSTS_TXOF | PS2_FSTS_TXRDY |
+ PS2_FSTS_RXUF | PS2_FSTS_RXOF | PS2_FSTS_RXRDY;
+ writel(rval, drvdata->reg_base + PS2_REG_FSTS);
+ }
+
+ rval = (fifo_status >> 16) & 0x3;
+ while (rval--) {
+ byte = readl(drvdata->reg_base + PS2_REG_DATA) & 0xff;
+ serio_interrupt(drvdata->serio, byte, rxflags);
+ }
+
+ writel(intr_status, drvdata->reg_base + PS2_REG_LSTS);
+ writel(fifo_status, drvdata->reg_base + PS2_REG_FSTS);
+
+ spin_unlock(&drvdata->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int sun4i_ps2_open(struct serio *serio)
+{
+ struct sun4i_ps2data *drvdata = serio->port_data;
+ u32 src_clk = 0;
+ u32 clk_scdf;
+ u32 clk_pcdf;
+ u32 rval;
+ unsigned long flags;
+
+ /* Set line control and enable interrupt */
+ rval = PS2_LCTL_STOPERREN | PS2_LCTL_ACKERREN
+ | PS2_LCTL_PARERREN | PS2_LCTL_RXDTOEN;
+ writel(rval, drvdata->reg_base + PS2_REG_LCTL);
+
+ /* Reset FIFO */
+ rval = PS2_FCTL_TXRST | PS2_FCTL_RXRST | PS2_FCTL_TXUFIEN
+ | PS2_FCTL_TXOFIEN | PS2_FCTL_RXUFIEN
+ | PS2_FCTL_RXOFIEN | PS2_FCTL_RXRDYIEN;
+
+ writel(rval, drvdata->reg_base + PS2_REG_FCTL);
+
+ src_clk = clk_get_rate(drvdata->clk);
+ /* Set clock divider register */
+ clk_scdf = src_clk / PS2_SAMPLE_CLK - 1;
+ clk_pcdf = PS2_SAMPLE_CLK / PS2_SCLK - 1;
+ rval = (clk_scdf << 8) | clk_pcdf;
+ writel(rval, drvdata->reg_base + PS2_REG_CLKDR);
+
+ /* Set global control register */
+ rval = PS2_GCTL_RESET | PS2_GCTL_INTEN | PS2_GCTL_MASTER
+ | PS2_GCTL_BUSEN;
+
+ spin_lock_irqsave(&drvdata->lock, flags);
+ writel(rval, drvdata->reg_base + PS2_REG_GCTL);
+ spin_unlock_irqrestore(&drvdata->lock, flags);
+
+ return 0;
+}
+
+static void sun4i_ps2_close(struct serio *serio)
+{
+ struct sun4i_ps2data *drvdata = serio->port_data;
+ u32 rval;
+
+ /* Shut off the interrupt */
+ rval = readl(drvdata->reg_base + PS2_REG_GCTL);
+ writel(rval & ~(PS2_GCTL_INTEN), drvdata->reg_base + PS2_REG_GCTL);
+
+ synchronize_irq(drvdata->irq);
+}
+
+static int sun4i_ps2_write(struct serio *serio, unsigned char val)
+{
+ unsigned long expire = jiffies + msecs_to_jiffies(10000);
+ struct sun4i_ps2data *drvdata = serio->port_data;
+
+ do {
+ if (readl(drvdata->reg_base + PS2_REG_FSTS) & PS2_FSTS_TXRDY) {
+ writel(val, drvdata->reg_base + PS2_REG_DATA);
+ return 0;
+ }
+ } while (time_before(jiffies, expire));
+
+ return SERIO_TIMEOUT;
+}
+
+static int sun4i_ps2_probe(struct platform_device *pdev)
+{
+ struct resource *res; /* IO mem resources */
+ struct sun4i_ps2data *drvdata;
+ struct serio *serio;
+ struct device *dev = &pdev->dev;
+ unsigned int irq;
+ int error;
+
+ drvdata = kzalloc(sizeof(struct sun4i_ps2data), GFP_KERNEL);
+ serio = kzalloc(sizeof(struct serio), GFP_KERNEL);
+ if (!drvdata || !serio) {
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ spin_lock_init(&drvdata->lock);
+
+ /* IO */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(dev, "failed to locate registers\n");
+ error = -ENXIO;
+ goto err_free_mem;
+ }
+
+ drvdata->reg_base = ioremap(res->start, resource_size(res));
+ if (!drvdata->reg_base) {
+ dev_err(dev, "failed to map registers\n");
+ error = -ENOMEM;
+ goto err_free_mem;
+ }
+
+ drvdata->clk = clk_get(dev, NULL);
+ if (IS_ERR(drvdata->clk)) {
+ error = PTR_ERR(drvdata->clk);
+ dev_err(dev, "couldn't get clock %d\n", error);
+ goto err_ioremap;
+ }
+
+ error = clk_prepare_enable(drvdata->clk);
+ if (error) {
+ dev_err(dev, "failed to enable clock %d\n", error);
+ goto err_clk;
+ }
+
+ serio->id.type = SERIO_8042;
+ serio->write = sun4i_ps2_write;
+ serio->open = sun4i_ps2_open;
+ serio->close = sun4i_ps2_close;
+ serio->port_data = drvdata;
+ serio->dev.parent = dev;
+ strlcpy(serio->name, dev_name(dev), sizeof(serio->name));
+ strlcpy(serio->phys, dev_name(dev), sizeof(serio->phys));
+
+ /* shutoff interrupt */
+ writel(0, drvdata->reg_base + PS2_REG_GCTL);
+
+ /* Get IRQ for the device */
+ irq = platform_get_irq(pdev, 0);
+ if (!irq) {
+ dev_err(dev, "no IRQ found\n");
+ error = -ENXIO;
+ goto err_disable_clk;
+ }
+
+ drvdata->irq = irq;
+ drvdata->serio = serio;
+ drvdata->dev = dev;
+
+ error = request_irq(drvdata->irq, sun4i_ps2_interrupt, 0,
+ DRIVER_NAME, drvdata);
+ if (error) {
+ dev_err(drvdata->dev, "failed to allocate interrupt %d: %d\n",
+ drvdata->irq, error);
+ goto err_disable_clk;
+ }
+
+ serio_register_port(serio);
+ platform_set_drvdata(pdev, drvdata);
+
+ return 0; /* success */
+
+err_disable_clk:
+ clk_disable_unprepare(drvdata->clk);
+err_clk:
+ clk_put(drvdata->clk);
+err_ioremap:
+ iounmap(drvdata->reg_base);
+err_free_mem:
+ kfree(serio);
+ kfree(drvdata);
+ return error;
+}
+
+static int sun4i_ps2_remove(struct platform_device *pdev)
+{
+ struct sun4i_ps2data *drvdata = platform_get_drvdata(pdev);
+
+ serio_unregister_port(drvdata->serio);
+
+ free_irq(drvdata->irq, drvdata);
+
+ clk_disable_unprepare(drvdata->clk);
+ clk_put(drvdata->clk);
+
+ iounmap(drvdata->reg_base);
+
+ kfree(drvdata);
+
+ return 0;
+}
+
+static const struct of_device_id sun4i_ps2_match[] = {
+ { .compatible = "allwinner,sun4i-a10-ps2", },
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, sun4i_ps2_match);
+
+static struct platform_driver sun4i_ps2_driver = {
+ .probe = sun4i_ps2_probe,
+ .remove = sun4i_ps2_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = sun4i_ps2_match,
+ },
+};
+module_platform_driver(sun4i_ps2_driver);
+
+MODULE_AUTHOR("Vishnu Patekar <vishnupatekar0510@gmail.com>");
+MODULE_AUTHOR("Aaron.maoye <leafy.myeh@newbietech.com>");
+MODULE_DESCRIPTION("Allwinner A10/Sun4i PS/2 driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/input/tablet/gtco.c b/drivers/input/tablet/gtco.c
index 858045694e9d..3a7f3a4a4396 100644
--- a/drivers/input/tablet/gtco.c
+++ b/drivers/input/tablet/gtco.c
@@ -59,7 +59,7 @@ Scott Hill shill@gtcocalcomp.com
#include <asm/uaccess.h>
#include <asm/unaligned.h>
#include <asm/byteorder.h>
-
+#include <linux/bitops.h>
#include <linux/usb/input.h>
@@ -614,7 +614,6 @@ static void gtco_urb_callback(struct urb *urbinfo)
struct input_dev *inputdev;
int rc;
u32 val = 0;
- s8 valsigned = 0;
char le_buffer[2];
inputdev = device->inputdevice;
@@ -665,20 +664,11 @@ static void gtco_urb_callback(struct urb *urbinfo)
/* Fall thru */
case 4:
/* Tilt */
+ input_report_abs(inputdev, ABS_TILT_X,
+ sign_extend32(device->buffer[6], 6));
- /* Sign extend these 7 bit numbers. */
- if (device->buffer[6] & 0x40)
- device->buffer[6] |= 0x80;
-
- if (device->buffer[7] & 0x40)
- device->buffer[7] |= 0x80;
-
-
- valsigned = (device->buffer[6]);
- input_report_abs(inputdev, ABS_TILT_X, (s32)valsigned);
-
- valsigned = (device->buffer[7]);
- input_report_abs(inputdev, ABS_TILT_Y, (s32)valsigned);
+ input_report_abs(inputdev, ABS_TILT_Y,
+ sign_extend32(device->buffer[7], 6));
/* Fall thru */
case 2:
diff --git a/drivers/input/touchscreen/elants_i2c.c b/drivers/input/touchscreen/elants_i2c.c
index a510f7ef9b66..926c58e540c0 100644
--- a/drivers/input/touchscreen/elants_i2c.c
+++ b/drivers/input/touchscreen/elants_i2c.c
@@ -33,10 +33,8 @@
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/buffer_head.h>
-#include <linux/version.h>
#include <linux/slab.h>
#include <linux/firmware.h>
-#include <linux/version.h>
#include <linux/input/mt.h>
#include <linux/acpi.h>
#include <linux/of.h>
diff --git a/drivers/input/touchscreen/pixcir_i2c_ts.c b/drivers/input/touchscreen/pixcir_i2c_ts.c
index 4fb5537fdd42..2c2107147319 100644
--- a/drivers/input/touchscreen/pixcir_i2c_ts.c
+++ b/drivers/input/touchscreen/pixcir_i2c_ts.c
@@ -126,7 +126,7 @@ static void pixcir_ts_report(struct pixcir_i2c_ts_data *ts,
pos[i].y = touch->y;
}
- input_mt_assign_slots(ts->input, slots, pos, n);
+ input_mt_assign_slots(ts->input, slots, pos, n, 0);
}
for (i = 0; i < n; i++) {
diff --git a/drivers/input/touchscreen/sun4i-ts.c b/drivers/input/touchscreen/sun4i-ts.c
index 28a06749ae42..b93a28b955fd 100644
--- a/drivers/input/touchscreen/sun4i-ts.c
+++ b/drivers/input/touchscreen/sun4i-ts.c
@@ -34,6 +34,7 @@
#include <linux/err.h>
#include <linux/hwmon.h>
+#include <linux/thermal.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
@@ -71,6 +72,9 @@
#define TP_ADC_SELECT(x) ((x) << 3)
#define ADC_CHAN_SELECT(x) ((x) << 0) /* 3 bits */
+/* on sun6i, bits 3~6 are left shifted by 1 to 4~7 */
+#define SUN6I_TP_MODE_EN(x) ((x) << 5)
+
/* TP_CTRL2 bits */
#define TP_SENSITIVE_ADJUST(x) ((x) << 28) /* 4 bits */
#define TP_MODE_SELECT(x) ((x) << 26) /* 2 bits */
@@ -107,10 +111,13 @@
struct sun4i_ts_data {
struct device *dev;
struct input_dev *input;
+ struct thermal_zone_device *tz;
void __iomem *base;
unsigned int irq;
bool ignore_fifo_data;
int temp_data;
+ int temp_offset;
+ int temp_step;
};
static void sun4i_ts_irq_handle_input(struct sun4i_ts_data *ts, u32 reg_val)
@@ -180,16 +187,38 @@ static void sun4i_ts_close(struct input_dev *dev)
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
}
+static int sun4i_get_temp(const struct sun4i_ts_data *ts, long *temp)
+{
+ /* No temp_data until the first irq */
+ if (ts->temp_data == -1)
+ return -EAGAIN;
+
+ *temp = (ts->temp_data - ts->temp_offset) * ts->temp_step;
+
+ return 0;
+}
+
+static int sun4i_get_tz_temp(void *data, long *temp)
+{
+ return sun4i_get_temp(data, temp);
+}
+
+static struct thermal_zone_of_device_ops sun4i_ts_tz_ops = {
+ .get_temp = sun4i_get_tz_temp,
+};
+
static ssize_t show_temp(struct device *dev, struct device_attribute *devattr,
char *buf)
{
struct sun4i_ts_data *ts = dev_get_drvdata(dev);
+ long temp;
+ int error;
- /* No temp_data until the first irq */
- if (ts->temp_data == -1)
- return -EAGAIN;
+ error = sun4i_get_temp(ts, &temp);
+ if (error)
+ return error;
- return sprintf(buf, "%d\n", (ts->temp_data - 1447) * 100);
+ return sprintf(buf, "%ld\n", temp);
}
static ssize_t show_temp_label(struct device *dev,
@@ -215,6 +244,7 @@ static int sun4i_ts_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct device *hwmon;
int error;
+ u32 reg;
bool ts_attached;
ts = devm_kzalloc(dev, sizeof(struct sun4i_ts_data), GFP_KERNEL);
@@ -224,6 +254,25 @@ static int sun4i_ts_probe(struct platform_device *pdev)
ts->dev = dev;
ts->ignore_fifo_data = true;
ts->temp_data = -1;
+ if (of_device_is_compatible(np, "allwinner,sun6i-a31-ts")) {
+ /* Allwinner SDK has temperature = -271 + (value / 6) (C) */
+ ts->temp_offset = 1626;
+ ts->temp_step = 167;
+ } else {
+ /*
+ * The user manuals do not contain the formula for calculating
+ * the temperature. The formula used here is from the AXP209,
+ * which is designed by X-Powers, an affiliate of Allwinner:
+ *
+ * temperature = -144.7 + (value * 0.1)
+ *
+ * Allwinner does not have any documentation whatsoever for
+ * this hardware. Moreover, it is claimed that the sensor
+ * is inaccurate and cannot work properly.
+ */
+ ts->temp_offset = 1447;
+ ts->temp_step = 100;
+ }
ts_attached = of_property_read_bool(np, "allwinner,ts-attached");
if (ts_attached) {
@@ -280,20 +329,34 @@ static int sun4i_ts_probe(struct platform_device *pdev)
* Set stylus up debounce to aprox 10 ms, enable debounce, and
* finally enable tp mode.
*/
- writel(STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1) | TP_MODE_EN(1),
- ts->base + TP_CTRL1);
+ reg = STYLUS_UP_DEBOUN(5) | STYLUS_UP_DEBOUN_EN(1);
+ if (of_device_is_compatible(np, "allwinner,sun4i-a10-ts"))
+ reg |= TP_MODE_EN(1);
+ else
+ reg |= SUN6I_TP_MODE_EN(1);
+ writel(reg, ts->base + TP_CTRL1);
+ /*
+ * The thermal core does not register hwmon devices for DT-based
+ * thermal zone sensors, such as this one.
+ */
hwmon = devm_hwmon_device_register_with_groups(ts->dev, "sun4i_ts",
ts, sun4i_ts_groups);
if (IS_ERR(hwmon))
return PTR_ERR(hwmon);
+ ts->tz = thermal_zone_of_sensor_register(ts->dev, 0, ts,
+ &sun4i_ts_tz_ops);
+ if (IS_ERR(ts->tz))
+ ts->tz = NULL;
+
writel(TEMP_IRQ_EN(1), ts->base + TP_INT_FIFOC);
if (ts_attached) {
error = input_register_device(ts->input);
if (error) {
writel(0, ts->base + TP_INT_FIFOC);
+ thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
return error;
}
}
@@ -310,6 +373,8 @@ static int sun4i_ts_remove(struct platform_device *pdev)
if (ts->input)
input_unregister_device(ts->input);
+ thermal_zone_of_sensor_unregister(ts->dev, ts->tz);
+
/* Deactivate all IRQs */
writel(0, ts->base + TP_INT_FIFOC);
@@ -318,6 +383,7 @@ static int sun4i_ts_remove(struct platform_device *pdev)
static const struct of_device_id sun4i_ts_of_match[] = {
{ .compatible = "allwinner,sun4i-a10-ts", },
+ { .compatible = "allwinner,sun6i-a31-ts", },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, sun4i_ts_of_match);
diff --git a/drivers/input/touchscreen/ti_am335x_tsc.c b/drivers/input/touchscreen/ti_am335x_tsc.c
index 004f1346a957..191a1b87895f 100644
--- a/drivers/input/touchscreen/ti_am335x_tsc.c
+++ b/drivers/input/touchscreen/ti_am335x_tsc.c
@@ -26,6 +26,7 @@
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/of_device.h>
+#include <linux/sort.h>
#include <linux/mfd/ti_am335x_tscadc.h>
@@ -52,6 +53,7 @@ struct titsc {
u32 bit_xp, bit_xn, bit_yp, bit_yn;
u32 inp_xp, inp_xn, inp_yp, inp_yn;
u32 step_mask;
+ u32 charge_delay;
};
static unsigned int titsc_readl(struct titsc *ts, unsigned int reg)
@@ -121,7 +123,7 @@ static void titsc_step_config(struct titsc *ts_dev)
{
unsigned int config;
int i;
- int end_step;
+ int end_step, first_step, tsc_steps;
u32 stepenable;
config = STEPCONFIG_MODE_HWSYNC |
@@ -140,9 +142,11 @@ static void titsc_step_config(struct titsc *ts_dev)
break;
}
- /* 1 … coordinate_readouts is for X */
- end_step = ts_dev->coordinate_readouts;
- for (i = 0; i < end_step; i++) {
+ tsc_steps = ts_dev->coordinate_readouts * 2 + 2;
+ first_step = TOTAL_STEPS - tsc_steps;
+ /* Steps 16 to 16-coordinate_readouts is for X */
+ end_step = first_step + tsc_steps;
+ for (i = end_step - ts_dev->coordinate_readouts; i < end_step; i++) {
titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
}
@@ -164,22 +168,20 @@ static void titsc_step_config(struct titsc *ts_dev)
break;
}
- /* coordinate_readouts … coordinate_readouts * 2 is for Y */
- end_step = ts_dev->coordinate_readouts * 2;
- for (i = ts_dev->coordinate_readouts; i < end_step; i++) {
+ /* 1 ... coordinate_readouts is for Y */
+ end_step = first_step + ts_dev->coordinate_readouts;
+ for (i = first_step; i < end_step; i++) {
titsc_writel(ts_dev, REG_STEPCONFIG(i), config);
titsc_writel(ts_dev, REG_STEPDELAY(i), STEPCONFIG_OPENDLY);
}
- /* Charge step configuration */
- config = ts_dev->bit_xp | ts_dev->bit_yn |
- STEPCHARGE_RFP_XPUL | STEPCHARGE_RFM_XNUR |
- STEPCHARGE_INM_AN1 | STEPCHARGE_INP(ts_dev->inp_yp);
+ /* Make CHARGECONFIG same as IDLECONFIG */
+ config = titsc_readl(ts_dev, REG_IDLECONFIG);
titsc_writel(ts_dev, REG_CHARGECONFIG, config);
- titsc_writel(ts_dev, REG_CHARGEDELAY, CHARGEDLY_OPENDLY);
+ titsc_writel(ts_dev, REG_CHARGEDELAY, ts_dev->charge_delay);
- /* coordinate_readouts * 2 … coordinate_readouts * 2 + 2 is for Z */
+ /* coordinate_readouts + 1 ... coordinate_readouts + 2 is for Z */
config = STEPCONFIG_MODE_HWSYNC |
STEPCONFIG_AVG_16 | ts_dev->bit_yp |
ts_dev->bit_xn | STEPCONFIG_INM_ADCREFM |
@@ -194,73 +196,104 @@ static void titsc_step_config(struct titsc *ts_dev)
titsc_writel(ts_dev, REG_STEPDELAY(end_step),
STEPCONFIG_OPENDLY);
- /* The steps1 … end and bit 0 for TS_Charge */
- stepenable = (1 << (end_step + 2)) - 1;
+ /* The steps end ... end - readouts * 2 + 2 and bit 0 for TS_Charge */
+ stepenable = 1;
+ for (i = 0; i < tsc_steps; i++)
+ stepenable |= 1 << (first_step + i + 1);
+
ts_dev->step_mask = stepenable;
am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
}
+static int titsc_cmp_coord(const void *a, const void *b)
+{
+ return *(int *)a - *(int *)b;
+}
+
static void titsc_read_coordinates(struct titsc *ts_dev,
u32 *x, u32 *y, u32 *z1, u32 *z2)
{
- unsigned int fifocount = titsc_readl(ts_dev, REG_FIFO0CNT);
- unsigned int prev_val_x = ~0, prev_val_y = ~0;
- unsigned int prev_diff_x = ~0, prev_diff_y = ~0;
- unsigned int read, diff;
- unsigned int i, channel;
+ unsigned int yvals[7], xvals[7];
+ unsigned int i, xsum = 0, ysum = 0;
unsigned int creads = ts_dev->coordinate_readouts;
- *z1 = *z2 = 0;
- if (fifocount % (creads * 2 + 2))
- fifocount -= fifocount % (creads * 2 + 2);
- /*
- * Delta filter is used to remove large variations in sampled
- * values from ADC. The filter tries to predict where the next
- * coordinate could be. This is done by taking a previous
- * coordinate and subtracting it form current one. Further the
- * algorithm compares the difference with that of a present value,
- * if true the value is reported to the sub system.
- */
- for (i = 0; i < fifocount; i++) {
- read = titsc_readl(ts_dev, REG_FIFO0);
-
- channel = (read & 0xf0000) >> 16;
- read &= 0xfff;
- if (channel < creads) {
- diff = abs(read - prev_val_x);
- if (diff < prev_diff_x) {
- prev_diff_x = diff;
- *x = read;
- }
- prev_val_x = read;
+ for (i = 0; i < creads; i++) {
+ yvals[i] = titsc_readl(ts_dev, REG_FIFO0);
+ yvals[i] &= 0xfff;
+ }
- } else if (channel < creads * 2) {
- diff = abs(read - prev_val_y);
- if (diff < prev_diff_y) {
- prev_diff_y = diff;
- *y = read;
- }
- prev_val_y = read;
+ *z1 = titsc_readl(ts_dev, REG_FIFO0);
+ *z1 &= 0xfff;
+ *z2 = titsc_readl(ts_dev, REG_FIFO0);
+ *z2 &= 0xfff;
- } else if (channel < creads * 2 + 1) {
- *z1 = read;
+ for (i = 0; i < creads; i++) {
+ xvals[i] = titsc_readl(ts_dev, REG_FIFO0);
+ xvals[i] &= 0xfff;
+ }
- } else if (channel < creads * 2 + 2) {
- *z2 = read;
+ /*
+ * If co-ordinates readouts is less than 4 then
+ * report the average. In case of 4 or more
+ * readouts, sort the co-ordinate samples, drop
+ * min and max values and report the average of
+ * remaining values.
+ */
+ if (creads <= 3) {
+ for (i = 0; i < creads; i++) {
+ ysum += yvals[i];
+ xsum += xvals[i];
}
+ ysum /= creads;
+ xsum /= creads;
+ } else {
+ sort(yvals, creads, sizeof(unsigned int),
+ titsc_cmp_coord, NULL);
+ sort(xvals, creads, sizeof(unsigned int),
+ titsc_cmp_coord, NULL);
+ for (i = 1; i < creads - 1; i++) {
+ ysum += yvals[i];
+ xsum += xvals[i];
+ }
+ ysum /= creads - 2;
+ xsum /= creads - 2;
}
+ *y = ysum;
+ *x = xsum;
}
static irqreturn_t titsc_irq(int irq, void *dev)
{
struct titsc *ts_dev = dev;
struct input_dev *input_dev = ts_dev->input;
- unsigned int status, irqclr = 0;
+ unsigned int fsm, status, irqclr = 0;
unsigned int x = 0, y = 0;
unsigned int z1, z2, z;
- unsigned int fsm;
- status = titsc_readl(ts_dev, REG_IRQSTATUS);
+ status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
+ if (status & IRQENB_HW_PEN) {
+ ts_dev->pen_down = true;
+ titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
+ titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
+ irqclr |= IRQENB_HW_PEN;
+ }
+
+ if (status & IRQENB_PENUP) {
+ fsm = titsc_readl(ts_dev, REG_ADCFSM);
+ if (fsm == ADCFSM_STEPID) {
+ ts_dev->pen_down = false;
+ input_report_key(input_dev, BTN_TOUCH, 0);
+ input_report_abs(input_dev, ABS_PRESSURE, 0);
+ input_sync(input_dev);
+ } else {
+ ts_dev->pen_down = true;
+ }
+ irqclr |= IRQENB_PENUP;
+ }
+
+ if (status & IRQENB_EOS)
+ irqclr |= IRQENB_EOS;
+
/*
* ADC and touchscreen share the IRQ line.
* FIFO1 interrupts are used by ADC. Handle FIFO0 IRQs here only
@@ -291,37 +324,11 @@ static irqreturn_t titsc_irq(int irq, void *dev)
}
irqclr |= IRQENB_FIFO0THRES;
}
-
- /*
- * Time for sequencer to settle, to read
- * correct state of the sequencer.
- */
- udelay(SEQ_SETTLE);
-
- status = titsc_readl(ts_dev, REG_RAWIRQSTATUS);
- if (status & IRQENB_PENUP) {
- /* Pen up event */
- fsm = titsc_readl(ts_dev, REG_ADCFSM);
- if (fsm == ADCFSM_STEPID) {
- ts_dev->pen_down = false;
- input_report_key(input_dev, BTN_TOUCH, 0);
- input_report_abs(input_dev, ABS_PRESSURE, 0);
- input_sync(input_dev);
- } else {
- ts_dev->pen_down = true;
- }
- irqclr |= IRQENB_PENUP;
- }
-
- if (status & IRQENB_HW_PEN) {
-
- titsc_writel(ts_dev, REG_IRQWAKEUP, 0x00);
- titsc_writel(ts_dev, REG_IRQCLR, IRQENB_HW_PEN);
- }
-
if (irqclr) {
titsc_writel(ts_dev, REG_IRQSTATUS, irqclr);
- am335x_tsc_se_set_cache(ts_dev->mfd_tscadc, ts_dev->step_mask);
+ if (status & IRQENB_EOS)
+ am335x_tsc_se_set_cache(ts_dev->mfd_tscadc,
+ ts_dev->step_mask);
return IRQ_HANDLED;
}
return IRQ_NONE;
@@ -368,6 +375,23 @@ static int titsc_parse_dt(struct platform_device *pdev,
if (err < 0)
return err;
+ if (ts_dev->coordinate_readouts <= 0) {
+ dev_warn(&pdev->dev,
+ "invalid co-ordinate readouts, resetting it to 5\n");
+ ts_dev->coordinate_readouts = 5;
+ }
+
+ err = of_property_read_u32(node, "ti,charge-delay",
+ &ts_dev->charge_delay);
+ /*
+ * If ti,charge-delay value is not specified, then use
+ * CHARGEDLY_OPENDLY as the default value.
+ */
+ if (err < 0) {
+ ts_dev->charge_delay = CHARGEDLY_OPENDLY;
+ dev_warn(&pdev->dev, "ti,charge-delay not specified\n");
+ }
+
return of_property_read_u32_array(node, "ti,wire-config",
ts_dev->config_inp, ARRAY_SIZE(ts_dev->config_inp));
}
@@ -411,6 +435,7 @@ static int titsc_probe(struct platform_device *pdev)
}
titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_FIFO0THRES);
+ titsc_writel(ts_dev, REG_IRQENABLE, IRQENB_EOS);
err = titsc_config_wires(ts_dev);
if (err) {
dev_err(&pdev->dev, "wrong i/p wire configuration\n");
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index 325188eef1c1..baa0d9786f50 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -4,6 +4,7 @@ config IOMMU_API
menuconfig IOMMU_SUPPORT
bool "IOMMU Hardware Support"
+ depends on MMU
default y
---help---
Say Y here if you want to compile device drivers for IO Memory
@@ -13,13 +14,43 @@ menuconfig IOMMU_SUPPORT
if IOMMU_SUPPORT
+menu "Generic IOMMU Pagetable Support"
+
+# Selected by the actual pagetable implementations
+config IOMMU_IO_PGTABLE
+ bool
+
+config IOMMU_IO_PGTABLE_LPAE
+ bool "ARMv7/v8 Long Descriptor Format"
+ select IOMMU_IO_PGTABLE
+ help
+ Enable support for the ARM long descriptor pagetable format.
+ This allocator supports 4K/2M/1G, 16K/32M and 64K/512M page
+ sizes at both stage-1 and stage-2, as well as address spaces
+ up to 48-bits in size.
+
+config IOMMU_IO_PGTABLE_LPAE_SELFTEST
+ bool "LPAE selftests"
+ depends on IOMMU_IO_PGTABLE_LPAE
+ help
+ Enable self-tests for LPAE page table allocator. This performs
+ a series of page-table consistency checks during boot.
+
+ If unsure, say N here.
+
+endmenu
+
+config IOMMU_IOVA
+ bool
+
config OF_IOMMU
def_bool y
depends on OF && IOMMU_API
config FSL_PAMU
bool "Freescale IOMMU support"
- depends on PPC_E500MC
+ depends on PPC32
+ depends on PPC_E500MC || COMPILE_TEST
select IOMMU_API
select GENERIC_ALLOCATOR
help
@@ -30,7 +61,8 @@ config FSL_PAMU
# MSM IOMMU support
config MSM_IOMMU
bool "MSM IOMMU Support"
- depends on ARCH_MSM8X60 || ARCH_MSM8960
+ depends on ARM
+ depends on ARCH_MSM8X60 || ARCH_MSM8960 || COMPILE_TEST
select IOMMU_API
help
Support for the IOMMUs found on certain Qualcomm SOCs.
@@ -91,6 +123,7 @@ config INTEL_IOMMU
bool "Support for Intel IOMMU using DMA Remapping Devices"
depends on PCI_MSI && ACPI && (X86 || IA64_GENERIC)
select IOMMU_API
+ select IOMMU_IOVA
select DMAR_TABLE
help
DMA remapping (DMAR) devices support enables independent address
@@ -140,7 +173,8 @@ config IRQ_REMAP
# OMAP IOMMU support
config OMAP_IOMMU
bool "OMAP IOMMU Support"
- depends on ARCH_OMAP2PLUS
+ depends on ARM && MMU
+ depends on ARCH_OMAP2PLUS || COMPILE_TEST
select IOMMU_API
config OMAP_IOMMU_DEBUG
@@ -187,7 +221,7 @@ config TEGRA_IOMMU_SMMU
config EXYNOS_IOMMU
bool "Exynos IOMMU Support"
- depends on ARCH_EXYNOS && ARM
+ depends on ARCH_EXYNOS && ARM && MMU
select IOMMU_API
select ARM_DMA_USE_IOMMU
help
@@ -216,7 +250,7 @@ config SHMOBILE_IPMMU_TLB
config SHMOBILE_IOMMU
bool "IOMMU for Renesas IPMMU/IPMMUI"
default n
- depends on ARM
+ depends on ARM && MMU
depends on ARCH_SHMOBILE || COMPILE_TEST
select IOMMU_API
select ARM_DMA_USE_IOMMU
@@ -287,6 +321,7 @@ config IPMMU_VMSA
depends on ARM_LPAE
depends on ARCH_SHMOBILE || COMPILE_TEST
select IOMMU_API
+ select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU
help
Support for the Renesas VMSA-compatible IPMMU Renesas found in the
@@ -304,13 +339,13 @@ config SPAPR_TCE_IOMMU
config ARM_SMMU
bool "ARM Ltd. System MMU (SMMU) Support"
- depends on ARM64 || (ARM_LPAE && OF)
+ depends on (ARM64 || ARM) && MMU
select IOMMU_API
+ select IOMMU_IO_PGTABLE_LPAE
select ARM_DMA_USE_IOMMU if ARM
help
Support for implementations of the ARM System MMU architecture
- versions 1 and 2. The driver supports both v7l and v8l table
- formats with 4k and 64k page sizes.
+ versions 1 and 2.
Say Y here if your SoC includes an IOMMU device implementing
the ARM SMMU architecture.
diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
index 7b976f294a69..080ffab4ed1c 100644
--- a/drivers/iommu/Makefile
+++ b/drivers/iommu/Makefile
@@ -1,13 +1,16 @@
obj-$(CONFIG_IOMMU_API) += iommu.o
obj-$(CONFIG_IOMMU_API) += iommu-traces.o
obj-$(CONFIG_IOMMU_API) += iommu-sysfs.o
+obj-$(CONFIG_IOMMU_IO_PGTABLE) += io-pgtable.o
+obj-$(CONFIG_IOMMU_IO_PGTABLE_LPAE) += io-pgtable-arm.o
+obj-$(CONFIG_IOMMU_IOVA) += iova.o
obj-$(CONFIG_OF_IOMMU) += of_iommu.o
obj-$(CONFIG_MSM_IOMMU) += msm_iommu.o msm_iommu_dev.o
obj-$(CONFIG_AMD_IOMMU) += amd_iommu.o amd_iommu_init.o
obj-$(CONFIG_AMD_IOMMU_V2) += amd_iommu_v2.o
obj-$(CONFIG_ARM_SMMU) += arm-smmu.o
obj-$(CONFIG_DMAR_TABLE) += dmar.o
-obj-$(CONFIG_INTEL_IOMMU) += iova.o intel-iommu.o
+obj-$(CONFIG_INTEL_IOMMU) += intel-iommu.o
obj-$(CONFIG_IPMMU_VMSA) += ipmmu-vmsa.o
obj-$(CONFIG_IRQ_REMAP) += intel_irq_remapping.o irq_remapping.o
obj-$(CONFIG_OMAP_IOMMU) += omap-iommu.o
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 98024856df07..48882c126245 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.de>
* Leo Duran <leo.duran@amd.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -843,10 +843,10 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
size_t size, u16 domid, int pde)
{
u64 pages;
- int s;
+ bool s;
pages = iommu_num_pages(address, size, PAGE_SIZE);
- s = 0;
+ s = false;
if (pages > 1) {
/*
@@ -854,7 +854,7 @@ static void build_inv_iommu_pages(struct iommu_cmd *cmd, u64 address,
* TLB entries for this domain
*/
address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
- s = 1;
+ s = true;
}
address &= PAGE_MASK;
@@ -874,10 +874,10 @@ static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
u64 address, size_t size)
{
u64 pages;
- int s;
+ bool s;
pages = iommu_num_pages(address, size, PAGE_SIZE);
- s = 0;
+ s = false;
if (pages > 1) {
/*
@@ -885,7 +885,7 @@ static void build_inv_iotlb_pages(struct iommu_cmd *cmd, u16 devid, int qdep,
* TLB entries for this domain
*/
address = CMD_INV_IOMMU_ALL_PAGES_ADDRESS;
- s = 1;
+ s = true;
}
address &= PAGE_MASK;
@@ -4284,7 +4284,6 @@ static int alloc_hpet_msi(unsigned int irq, unsigned int id)
}
struct irq_remap_ops amd_iommu_irq_ops = {
- .supported = amd_iommu_supported,
.prepare = amd_iommu_prepare,
.enable = amd_iommu_enable,
.disable = amd_iommu_disable,
diff --git a/drivers/iommu/amd_iommu_init.c b/drivers/iommu/amd_iommu_init.c
index b0522f15730f..450ef5001a65 100644
--- a/drivers/iommu/amd_iommu_init.c
+++ b/drivers/iommu/amd_iommu_init.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.de>
* Leo Duran <leo.duran@amd.com>
*
* This program is free software; you can redistribute it and/or modify it
@@ -2014,9 +2014,6 @@ static bool detect_ivrs(void)
/* Make sure ACS will be enabled during PCI probe */
pci_request_acs();
- if (!disable_irq_remap)
- amd_iommu_irq_remap = true;
-
return true;
}
@@ -2123,12 +2120,14 @@ static int __init iommu_go_to_state(enum iommu_init_state state)
#ifdef CONFIG_IRQ_REMAP
int __init amd_iommu_prepare(void)
{
- return iommu_go_to_state(IOMMU_ACPI_FINISHED);
-}
+ int ret;
-int __init amd_iommu_supported(void)
-{
- return amd_iommu_irq_remap ? 1 : 0;
+ amd_iommu_irq_remap = true;
+
+ ret = iommu_go_to_state(IOMMU_ACPI_FINISHED);
+ if (ret)
+ return ret;
+ return amd_iommu_irq_remap ? 0 : -ENODEV;
}
int __init amd_iommu_enable(void)
diff --git a/drivers/iommu/amd_iommu_proto.h b/drivers/iommu/amd_iommu_proto.h
index 95ed6deae47f..72b0fd455e24 100644
--- a/drivers/iommu/amd_iommu_proto.h
+++ b/drivers/iommu/amd_iommu_proto.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2009-2010 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.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
@@ -33,7 +33,6 @@ extern void amd_iommu_init_notifier(void);
extern void amd_iommu_init_api(void);
/* Needed for interrupt remapping */
-extern int amd_iommu_supported(void);
extern int amd_iommu_prepare(void);
extern int amd_iommu_enable(void);
extern void amd_iommu_disable(void);
diff --git a/drivers/iommu/amd_iommu_types.h b/drivers/iommu/amd_iommu_types.h
index cec51a8ba844..c4fffb710c58 100644
--- a/drivers/iommu/amd_iommu_types.h
+++ b/drivers/iommu/amd_iommu_types.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007-2010 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.de>
* Leo Duran <leo.duran@amd.com>
*
* This program is free software; you can redistribute it and/or modify it
diff --git a/drivers/iommu/amd_iommu_v2.c b/drivers/iommu/amd_iommu_v2.c
index 90f70d0e1141..6d5a5c44453b 100644
--- a/drivers/iommu/amd_iommu_v2.c
+++ b/drivers/iommu/amd_iommu_v2.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010-2012 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.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
@@ -31,7 +31,7 @@
#include "amd_iommu_proto.h"
MODULE_LICENSE("GPL v2");
-MODULE_AUTHOR("Joerg Roedel <joerg.roedel@amd.com>");
+MODULE_AUTHOR("Joerg Roedel <jroedel@suse.de>");
#define MAX_DEVICES 0x10000
#define PRI_QUEUE_SIZE 512
@@ -151,18 +151,6 @@ static void put_device_state(struct device_state *dev_state)
wake_up(&dev_state->wq);
}
-static void put_device_state_wait(struct device_state *dev_state)
-{
- DEFINE_WAIT(wait);
-
- prepare_to_wait(&dev_state->wq, &wait, TASK_UNINTERRUPTIBLE);
- if (!atomic_dec_and_test(&dev_state->count))
- schedule();
- finish_wait(&dev_state->wq, &wait);
-
- free_device_state(dev_state);
-}
-
/* Must be called under dev_state->lock */
static struct pasid_state **__get_pasid_state_ptr(struct device_state *dev_state,
int pasid, bool alloc)
@@ -278,14 +266,7 @@ static void put_pasid_state(struct pasid_state *pasid_state)
static void put_pasid_state_wait(struct pasid_state *pasid_state)
{
- DEFINE_WAIT(wait);
-
- prepare_to_wait(&pasid_state->wq, &wait, TASK_UNINTERRUPTIBLE);
-
- if (!atomic_dec_and_test(&pasid_state->count))
- schedule();
-
- finish_wait(&pasid_state->wq, &wait);
+ wait_event(pasid_state->wq, !atomic_read(&pasid_state->count));
free_pasid_state(pasid_state);
}
@@ -851,7 +832,13 @@ void amd_iommu_free_device(struct pci_dev *pdev)
/* Get rid of any remaining pasid states */
free_pasid_states(dev_state);
- put_device_state_wait(dev_state);
+ put_device_state(dev_state);
+ /*
+ * Wait until the last reference is dropped before freeing
+ * the device state.
+ */
+ wait_event(dev_state->wq, !atomic_read(&dev_state->count));
+ free_device_state(dev_state);
}
EXPORT_SYMBOL(amd_iommu_free_device);
@@ -921,7 +908,7 @@ static int __init amd_iommu_v2_init(void)
{
int ret;
- pr_info("AMD IOMMUv2 driver by Joerg Roedel <joerg.roedel@amd.com>\n");
+ pr_info("AMD IOMMUv2 driver by Joerg Roedel <jroedel@suse.de>\n");
if (!amd_iommu_v2_supported()) {
pr_info("AMD IOMMUv2 functionality not available on this system\n");
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 6cd47b75286f..fc13dd56953e 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -23,8 +23,6 @@
* - Stream-matching and stream-indexing
* - v7/v8 long-descriptor format
* - Non-secure access to the SMMU
- * - 4k and 64k pages, with contiguous pte hints.
- * - Up to 48-bit addressing (dependent on VA_BITS)
* - Context fault reporting
*/
@@ -36,7 +34,7 @@
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/iommu.h>
-#include <linux/mm.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/pci.h>
@@ -46,7 +44,7 @@
#include <linux/amba/bus.h>
-#include <asm/pgalloc.h>
+#include "io-pgtable.h"
/* Maximum number of stream IDs assigned to a single device */
#define MAX_MASTER_STREAMIDS MAX_PHANDLE_ARGS
@@ -71,40 +69,6 @@
((smmu->options & ARM_SMMU_OPT_SECURE_CFG_ACCESS) \
? 0x400 : 0))
-/* Page table bits */
-#define ARM_SMMU_PTE_XN (((pteval_t)3) << 53)
-#define ARM_SMMU_PTE_CONT (((pteval_t)1) << 52)
-#define ARM_SMMU_PTE_AF (((pteval_t)1) << 10)
-#define ARM_SMMU_PTE_SH_NS (((pteval_t)0) << 8)
-#define ARM_SMMU_PTE_SH_OS (((pteval_t)2) << 8)
-#define ARM_SMMU_PTE_SH_IS (((pteval_t)3) << 8)
-#define ARM_SMMU_PTE_PAGE (((pteval_t)3) << 0)
-
-#if PAGE_SIZE == SZ_4K
-#define ARM_SMMU_PTE_CONT_ENTRIES 16
-#elif PAGE_SIZE == SZ_64K
-#define ARM_SMMU_PTE_CONT_ENTRIES 32
-#else
-#define ARM_SMMU_PTE_CONT_ENTRIES 1
-#endif
-
-#define ARM_SMMU_PTE_CONT_SIZE (PAGE_SIZE * ARM_SMMU_PTE_CONT_ENTRIES)
-#define ARM_SMMU_PTE_CONT_MASK (~(ARM_SMMU_PTE_CONT_SIZE - 1))
-
-/* Stage-1 PTE */
-#define ARM_SMMU_PTE_AP_UNPRIV (((pteval_t)1) << 6)
-#define ARM_SMMU_PTE_AP_RDONLY (((pteval_t)2) << 6)
-#define ARM_SMMU_PTE_ATTRINDX_SHIFT 2
-#define ARM_SMMU_PTE_nG (((pteval_t)1) << 11)
-
-/* Stage-2 PTE */
-#define ARM_SMMU_PTE_HAP_FAULT (((pteval_t)0) << 6)
-#define ARM_SMMU_PTE_HAP_READ (((pteval_t)1) << 6)
-#define ARM_SMMU_PTE_HAP_WRITE (((pteval_t)2) << 6)
-#define ARM_SMMU_PTE_MEMATTR_OIWB (((pteval_t)0xf) << 2)
-#define ARM_SMMU_PTE_MEMATTR_NC (((pteval_t)0x5) << 2)
-#define ARM_SMMU_PTE_MEMATTR_DEV (((pteval_t)0x1) << 2)
-
/* Configuration registers */
#define ARM_SMMU_GR0_sCR0 0x0
#define sCR0_CLIENTPD (1 << 0)
@@ -132,17 +96,12 @@
#define ARM_SMMU_GR0_sGFSYNR0 0x50
#define ARM_SMMU_GR0_sGFSYNR1 0x54
#define ARM_SMMU_GR0_sGFSYNR2 0x58
-#define ARM_SMMU_GR0_PIDR0 0xfe0
-#define ARM_SMMU_GR0_PIDR1 0xfe4
-#define ARM_SMMU_GR0_PIDR2 0xfe8
#define ID0_S1TS (1 << 30)
#define ID0_S2TS (1 << 29)
#define ID0_NTS (1 << 28)
#define ID0_SMS (1 << 27)
-#define ID0_PTFS_SHIFT 24
-#define ID0_PTFS_MASK 0x2
-#define ID0_PTFS_V8_ONLY 0x2
+#define ID0_ATOSNS (1 << 26)
#define ID0_CTTW (1 << 14)
#define ID0_NUMIRPT_SHIFT 16
#define ID0_NUMIRPT_MASK 0xff
@@ -169,11 +128,7 @@
#define ID2_PTFS_16K (1 << 13)
#define ID2_PTFS_64K (1 << 14)
-#define PIDR2_ARCH_SHIFT 4
-#define PIDR2_ARCH_MASK 0xf
-
/* Global TLB invalidation */
-#define ARM_SMMU_GR0_STLBIALL 0x60
#define ARM_SMMU_GR0_TLBIVMID 0x64
#define ARM_SMMU_GR0_TLBIALLNSNH 0x68
#define ARM_SMMU_GR0_TLBIALLH 0x6c
@@ -231,13 +186,25 @@
#define ARM_SMMU_CB_TTBCR2 0x10
#define ARM_SMMU_CB_TTBR0_LO 0x20
#define ARM_SMMU_CB_TTBR0_HI 0x24
+#define ARM_SMMU_CB_TTBR1_LO 0x28
+#define ARM_SMMU_CB_TTBR1_HI 0x2c
#define ARM_SMMU_CB_TTBCR 0x30
#define ARM_SMMU_CB_S1_MAIR0 0x38
+#define ARM_SMMU_CB_S1_MAIR1 0x3c
+#define ARM_SMMU_CB_PAR_LO 0x50
+#define ARM_SMMU_CB_PAR_HI 0x54
#define ARM_SMMU_CB_FSR 0x58
#define ARM_SMMU_CB_FAR_LO 0x60
#define ARM_SMMU_CB_FAR_HI 0x64
#define ARM_SMMU_CB_FSYNR0 0x68
+#define ARM_SMMU_CB_S1_TLBIVA 0x600
#define ARM_SMMU_CB_S1_TLBIASID 0x610
+#define ARM_SMMU_CB_S1_TLBIVAL 0x620
+#define ARM_SMMU_CB_S2_TLBIIPAS2 0x630
+#define ARM_SMMU_CB_S2_TLBIIPAS2L 0x638
+#define ARM_SMMU_CB_ATS1PR_LO 0x800
+#define ARM_SMMU_CB_ATS1PR_HI 0x804
+#define ARM_SMMU_CB_ATSR 0x8f0
#define SCTLR_S1_ASIDPNE (1 << 12)
#define SCTLR_CFCFG (1 << 7)
@@ -249,47 +216,16 @@
#define SCTLR_M (1 << 0)
#define SCTLR_EAE_SBOP (SCTLR_AFE | SCTLR_TRE)
-#define RESUME_RETRY (0 << 0)
-#define RESUME_TERMINATE (1 << 0)
-
-#define TTBCR_EAE (1 << 31)
+#define CB_PAR_F (1 << 0)
-#define TTBCR_PASIZE_SHIFT 16
-#define TTBCR_PASIZE_MASK 0x7
+#define ATSR_ACTIVE (1 << 0)
-#define TTBCR_TG0_4K (0 << 14)
-#define TTBCR_TG0_64K (1 << 14)
-
-#define TTBCR_SH0_SHIFT 12
-#define TTBCR_SH0_MASK 0x3
-#define TTBCR_SH_NS 0
-#define TTBCR_SH_OS 2
-#define TTBCR_SH_IS 3
-
-#define TTBCR_ORGN0_SHIFT 10
-#define TTBCR_IRGN0_SHIFT 8
-#define TTBCR_RGN_MASK 0x3
-#define TTBCR_RGN_NC 0
-#define TTBCR_RGN_WBWA 1
-#define TTBCR_RGN_WT 2
-#define TTBCR_RGN_WB 3
-
-#define TTBCR_SL0_SHIFT 6
-#define TTBCR_SL0_MASK 0x3
-#define TTBCR_SL0_LVL_2 0
-#define TTBCR_SL0_LVL_1 1
-
-#define TTBCR_T1SZ_SHIFT 16
-#define TTBCR_T0SZ_SHIFT 0
-#define TTBCR_SZ_MASK 0xf
+#define RESUME_RETRY (0 << 0)
+#define RESUME_TERMINATE (1 << 0)
#define TTBCR2_SEP_SHIFT 15
#define TTBCR2_SEP_MASK 0x7
-#define TTBCR2_PASIZE_SHIFT 0
-#define TTBCR2_PASIZE_MASK 0x7
-
-/* Common definitions for PASize and SEP fields */
#define TTBCR2_ADDR_32 0
#define TTBCR2_ADDR_36 1
#define TTBCR2_ADDR_40 2
@@ -297,16 +233,7 @@
#define TTBCR2_ADDR_44 4
#define TTBCR2_ADDR_48 5
-#define TTBRn_HI_ASID_SHIFT 16
-
-#define MAIR_ATTR_SHIFT(n) ((n) << 3)
-#define MAIR_ATTR_MASK 0xff
-#define MAIR_ATTR_DEVICE 0x04
-#define MAIR_ATTR_NC 0x44
-#define MAIR_ATTR_WBRWA 0xff
-#define MAIR_ATTR_IDX_NC 0
-#define MAIR_ATTR_IDX_CACHE 1
-#define MAIR_ATTR_IDX_DEV 2
+#define TTBRn_HI_ASID_SHIFT 16
#define FSR_MULTI (1 << 31)
#define FSR_SS (1 << 30)
@@ -366,6 +293,7 @@ struct arm_smmu_device {
#define ARM_SMMU_FEAT_TRANS_S1 (1 << 2)
#define ARM_SMMU_FEAT_TRANS_S2 (1 << 3)
#define ARM_SMMU_FEAT_TRANS_NESTED (1 << 4)
+#define ARM_SMMU_FEAT_TRANS_OPS (1 << 5)
u32 features;
#define ARM_SMMU_OPT_SECURE_CFG_ACCESS (1 << 0)
@@ -380,10 +308,9 @@ struct arm_smmu_device {
u32 num_mapping_groups;
DECLARE_BITMAP(smr_map, ARM_SMMU_MAX_SMRS);
- unsigned long s1_input_size;
- unsigned long s1_output_size;
- unsigned long s2_input_size;
- unsigned long s2_output_size;
+ unsigned long va_size;
+ unsigned long ipa_size;
+ unsigned long pa_size;
u32 num_global_irqs;
u32 num_context_irqs;
@@ -397,7 +324,6 @@ struct arm_smmu_cfg {
u8 cbndx;
u8 irptndx;
u32 cbar;
- pgd_t *pgd;
};
#define INVALID_IRPTNDX 0xff
@@ -412,11 +338,15 @@ enum arm_smmu_domain_stage {
struct arm_smmu_domain {
struct arm_smmu_device *smmu;
+ struct io_pgtable_ops *pgtbl_ops;
+ spinlock_t pgtbl_lock;
struct arm_smmu_cfg cfg;
enum arm_smmu_domain_stage stage;
- spinlock_t lock;
+ struct mutex init_mutex; /* Protects smmu pointer */
};
+static struct iommu_ops arm_smmu_ops;
+
static DEFINE_SPINLOCK(arm_smmu_devices_lock);
static LIST_HEAD(arm_smmu_devices);
@@ -597,7 +527,7 @@ static void __arm_smmu_free_bitmap(unsigned long *map, int idx)
}
/* Wait for any pending TLB invalidations to complete */
-static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
+static void __arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
{
int count = 0;
void __iomem *gr0_base = ARM_SMMU_GR0(smmu);
@@ -615,12 +545,19 @@ static void arm_smmu_tlb_sync(struct arm_smmu_device *smmu)
}
}
-static void arm_smmu_tlb_inv_context(struct arm_smmu_domain *smmu_domain)
+static void arm_smmu_tlb_sync(void *cookie)
{
+ struct arm_smmu_domain *smmu_domain = cookie;
+ __arm_smmu_tlb_sync(smmu_domain->smmu);
+}
+
+static void arm_smmu_tlb_inv_context(void *cookie)
+{
+ struct arm_smmu_domain *smmu_domain = cookie;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
struct arm_smmu_device *smmu = smmu_domain->smmu;
- void __iomem *base = ARM_SMMU_GR0(smmu);
bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
+ void __iomem *base;
if (stage1) {
base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
@@ -632,9 +569,76 @@ static void arm_smmu_tlb_inv_context(struct arm_smmu_domain *smmu_domain)
base + ARM_SMMU_GR0_TLBIVMID);
}
- arm_smmu_tlb_sync(smmu);
+ __arm_smmu_tlb_sync(smmu);
+}
+
+static void arm_smmu_tlb_inv_range_nosync(unsigned long iova, size_t size,
+ bool leaf, void *cookie)
+{
+ struct arm_smmu_domain *smmu_domain = cookie;
+ struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ bool stage1 = cfg->cbar != CBAR_TYPE_S2_TRANS;
+ void __iomem *reg;
+
+ if (stage1) {
+ reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ reg += leaf ? ARM_SMMU_CB_S1_TLBIVAL : ARM_SMMU_CB_S1_TLBIVA;
+
+ if (!IS_ENABLED(CONFIG_64BIT) || smmu->version == ARM_SMMU_V1) {
+ iova &= ~12UL;
+ iova |= ARM_SMMU_CB_ASID(cfg);
+ writel_relaxed(iova, reg);
+#ifdef CONFIG_64BIT
+ } else {
+ iova >>= 12;
+ iova |= (u64)ARM_SMMU_CB_ASID(cfg) << 48;
+ writeq_relaxed(iova, reg);
+#endif
+ }
+#ifdef CONFIG_64BIT
+ } else if (smmu->version == ARM_SMMU_V2) {
+ reg = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+ reg += leaf ? ARM_SMMU_CB_S2_TLBIIPAS2L :
+ ARM_SMMU_CB_S2_TLBIIPAS2;
+ writeq_relaxed(iova >> 12, reg);
+#endif
+ } else {
+ reg = ARM_SMMU_GR0(smmu) + ARM_SMMU_GR0_TLBIVMID;
+ writel_relaxed(ARM_SMMU_CB_VMID(cfg), reg);
+ }
+}
+
+static void arm_smmu_flush_pgtable(void *addr, size_t size, void *cookie)
+{
+ struct arm_smmu_domain *smmu_domain = cookie;
+ struct arm_smmu_device *smmu = smmu_domain->smmu;
+ unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+
+
+ /* Ensure new page tables are visible to the hardware walker */
+ if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) {
+ dsb(ishst);
+ } else {
+ /*
+ * If the SMMU can't walk tables in the CPU caches, treat them
+ * like non-coherent DMA since we need to flush the new entries
+ * all the way out to memory. There's no possibility of
+ * recursion here as the SMMU table walker will not be wired
+ * through another SMMU.
+ */
+ dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
+ DMA_TO_DEVICE);
+ }
}
+static struct iommu_gather_ops arm_smmu_gather_ops = {
+ .tlb_flush_all = arm_smmu_tlb_inv_context,
+ .tlb_add_flush = arm_smmu_tlb_inv_range_nosync,
+ .tlb_sync = arm_smmu_tlb_sync,
+ .flush_pgtable = arm_smmu_flush_pgtable,
+};
+
static irqreturn_t arm_smmu_context_fault(int irq, void *dev)
{
int flags, ret;
@@ -712,29 +716,8 @@ static irqreturn_t arm_smmu_global_fault(int irq, void *dev)
return IRQ_HANDLED;
}
-static void arm_smmu_flush_pgtable(struct arm_smmu_device *smmu, void *addr,
- size_t size)
-{
- unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
-
-
- /* Ensure new page tables are visible to the hardware walker */
- if (smmu->features & ARM_SMMU_FEAT_COHERENT_WALK) {
- dsb(ishst);
- } else {
- /*
- * If the SMMU can't walk tables in the CPU caches, treat them
- * like non-coherent DMA since we need to flush the new entries
- * all the way out to memory. There's no possibility of
- * recursion here as the SMMU table walker will not be wired
- * through another SMMU.
- */
- dma_map_page(smmu->dev, virt_to_page(addr), offset, size,
- DMA_TO_DEVICE);
- }
-}
-
-static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
+static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain,
+ struct io_pgtable_cfg *pgtbl_cfg)
{
u32 reg;
bool stage1;
@@ -771,124 +754,68 @@ static void arm_smmu_init_context_bank(struct arm_smmu_domain *smmu_domain)
#else
reg = CBA2R_RW64_32BIT;
#endif
- writel_relaxed(reg,
- gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
-
- /* TTBCR2 */
- switch (smmu->s1_input_size) {
- case 32:
- reg = (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
- break;
- case 36:
- reg = (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT);
- break;
- case 39:
- case 40:
- reg = (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT);
- break;
- case 42:
- reg = (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT);
- break;
- case 44:
- reg = (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT);
- break;
- case 48:
- reg = (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT);
- break;
- }
-
- switch (smmu->s1_output_size) {
- case 32:
- reg |= (TTBCR2_ADDR_32 << TTBCR2_PASIZE_SHIFT);
- break;
- case 36:
- reg |= (TTBCR2_ADDR_36 << TTBCR2_PASIZE_SHIFT);
- break;
- case 39:
- case 40:
- reg |= (TTBCR2_ADDR_40 << TTBCR2_PASIZE_SHIFT);
- break;
- case 42:
- reg |= (TTBCR2_ADDR_42 << TTBCR2_PASIZE_SHIFT);
- break;
- case 44:
- reg |= (TTBCR2_ADDR_44 << TTBCR2_PASIZE_SHIFT);
- break;
- case 48:
- reg |= (TTBCR2_ADDR_48 << TTBCR2_PASIZE_SHIFT);
- break;
- }
-
- if (stage1)
- writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
+ writel_relaxed(reg, gr1_base + ARM_SMMU_GR1_CBA2R(cfg->cbndx));
}
- /* TTBR0 */
- arm_smmu_flush_pgtable(smmu, cfg->pgd,
- PTRS_PER_PGD * sizeof(pgd_t));
- reg = __pa(cfg->pgd);
- writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
- reg = (phys_addr_t)__pa(cfg->pgd) >> 32;
- if (stage1)
+ /* TTBRs */
+ if (stage1) {
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0];
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[0] >> 32;
reg |= ARM_SMMU_CB_ASID(cfg) << TTBRn_HI_ASID_SHIFT;
- writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
-
- /*
- * TTBCR
- * We use long descriptor, with inner-shareable WBWA tables in TTBR0.
- */
- if (smmu->version > ARM_SMMU_V1) {
- if (PAGE_SIZE == SZ_4K)
- reg = TTBCR_TG0_4K;
- else
- reg = TTBCR_TG0_64K;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
- if (!stage1) {
- reg |= (64 - smmu->s2_input_size) << TTBCR_T0SZ_SHIFT;
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1];
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_LO);
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.ttbr[1] >> 32;
+ reg |= ARM_SMMU_CB_ASID(cfg) << TTBRn_HI_ASID_SHIFT;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR1_HI);
+ } else {
+ reg = pgtbl_cfg->arm_lpae_s2_cfg.vttbr;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_LO);
+ reg = pgtbl_cfg->arm_lpae_s2_cfg.vttbr >> 32;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBR0_HI);
+ }
- switch (smmu->s2_output_size) {
+ /* TTBCR */
+ if (stage1) {
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
+ if (smmu->version > ARM_SMMU_V1) {
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.tcr >> 32;
+ switch (smmu->va_size) {
case 32:
- reg |= (TTBCR2_ADDR_32 << TTBCR_PASIZE_SHIFT);
+ reg |= (TTBCR2_ADDR_32 << TTBCR2_SEP_SHIFT);
break;
case 36:
- reg |= (TTBCR2_ADDR_36 << TTBCR_PASIZE_SHIFT);
+ reg |= (TTBCR2_ADDR_36 << TTBCR2_SEP_SHIFT);
break;
case 40:
- reg |= (TTBCR2_ADDR_40 << TTBCR_PASIZE_SHIFT);
+ reg |= (TTBCR2_ADDR_40 << TTBCR2_SEP_SHIFT);
break;
case 42:
- reg |= (TTBCR2_ADDR_42 << TTBCR_PASIZE_SHIFT);
+ reg |= (TTBCR2_ADDR_42 << TTBCR2_SEP_SHIFT);
break;
case 44:
- reg |= (TTBCR2_ADDR_44 << TTBCR_PASIZE_SHIFT);
+ reg |= (TTBCR2_ADDR_44 << TTBCR2_SEP_SHIFT);
break;
case 48:
- reg |= (TTBCR2_ADDR_48 << TTBCR_PASIZE_SHIFT);
+ reg |= (TTBCR2_ADDR_48 << TTBCR2_SEP_SHIFT);
break;
}
- } else {
- reg |= (64 - smmu->s1_input_size) << TTBCR_T0SZ_SHIFT;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR2);
}
} else {
- reg = 0;
+ reg = pgtbl_cfg->arm_lpae_s2_cfg.vtcr;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
}
- reg |= TTBCR_EAE |
- (TTBCR_SH_IS << TTBCR_SH0_SHIFT) |
- (TTBCR_RGN_WBWA << TTBCR_ORGN0_SHIFT) |
- (TTBCR_RGN_WBWA << TTBCR_IRGN0_SHIFT);
-
- if (!stage1)
- reg |= (TTBCR_SL0_LVL_1 << TTBCR_SL0_SHIFT);
-
- writel_relaxed(reg, cb_base + ARM_SMMU_CB_TTBCR);
-
- /* MAIR0 (stage-1 only) */
+ /* MAIRs (stage-1 only) */
if (stage1) {
- reg = (MAIR_ATTR_NC << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_NC)) |
- (MAIR_ATTR_WBRWA << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_CACHE)) |
- (MAIR_ATTR_DEVICE << MAIR_ATTR_SHIFT(MAIR_ATTR_IDX_DEV));
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[0];
writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR0);
+ reg = pgtbl_cfg->arm_lpae_s1_cfg.mair[1];
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_S1_MAIR1);
}
/* SCTLR */
@@ -905,11 +832,14 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
struct arm_smmu_device *smmu)
{
int irq, start, ret = 0;
- unsigned long flags;
+ unsigned long ias, oas;
+ struct io_pgtable_ops *pgtbl_ops;
+ struct io_pgtable_cfg pgtbl_cfg;
+ enum io_pgtable_fmt fmt;
struct arm_smmu_domain *smmu_domain = domain->priv;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- spin_lock_irqsave(&smmu_domain->lock, flags);
+ mutex_lock(&smmu_domain->init_mutex);
if (smmu_domain->smmu)
goto out_unlock;
@@ -940,6 +870,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
case ARM_SMMU_DOMAIN_S1:
cfg->cbar = CBAR_TYPE_S1_TRANS_S2_BYPASS;
start = smmu->num_s2_context_banks;
+ ias = smmu->va_size;
+ oas = smmu->ipa_size;
+ if (IS_ENABLED(CONFIG_64BIT))
+ fmt = ARM_64_LPAE_S1;
+ else
+ fmt = ARM_32_LPAE_S1;
break;
case ARM_SMMU_DOMAIN_NESTED:
/*
@@ -949,6 +885,12 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
case ARM_SMMU_DOMAIN_S2:
cfg->cbar = CBAR_TYPE_S2_TRANS;
start = 0;
+ ias = smmu->ipa_size;
+ oas = smmu->pa_size;
+ if (IS_ENABLED(CONFIG_64BIT))
+ fmt = ARM_64_LPAE_S2;
+ else
+ fmt = ARM_32_LPAE_S2;
break;
default:
ret = -EINVAL;
@@ -968,10 +910,30 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
cfg->irptndx = cfg->cbndx;
}
- ACCESS_ONCE(smmu_domain->smmu) = smmu;
- arm_smmu_init_context_bank(smmu_domain);
- spin_unlock_irqrestore(&smmu_domain->lock, flags);
+ pgtbl_cfg = (struct io_pgtable_cfg) {
+ .pgsize_bitmap = arm_smmu_ops.pgsize_bitmap,
+ .ias = ias,
+ .oas = oas,
+ .tlb = &arm_smmu_gather_ops,
+ };
+
+ smmu_domain->smmu = smmu;
+ pgtbl_ops = alloc_io_pgtable_ops(fmt, &pgtbl_cfg, smmu_domain);
+ if (!pgtbl_ops) {
+ ret = -ENOMEM;
+ goto out_clear_smmu;
+ }
+
+ /* Update our support page sizes to reflect the page table format */
+ arm_smmu_ops.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
+ /* Initialise the context bank with our page table cfg */
+ arm_smmu_init_context_bank(smmu_domain, &pgtbl_cfg);
+
+ /*
+ * Request context fault interrupt. Do this last to avoid the
+ * handler seeing a half-initialised domain state.
+ */
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
ret = request_irq(irq, arm_smmu_context_fault, IRQF_SHARED,
"arm-smmu-context-fault", domain);
@@ -981,10 +943,16 @@ static int arm_smmu_init_domain_context(struct iommu_domain *domain,
cfg->irptndx = INVALID_IRPTNDX;
}
+ mutex_unlock(&smmu_domain->init_mutex);
+
+ /* Publish page table ops for map/unmap */
+ smmu_domain->pgtbl_ops = pgtbl_ops;
return 0;
+out_clear_smmu:
+ smmu_domain->smmu = NULL;
out_unlock:
- spin_unlock_irqrestore(&smmu_domain->lock, flags);
+ mutex_unlock(&smmu_domain->init_mutex);
return ret;
}
@@ -999,23 +967,27 @@ static void arm_smmu_destroy_domain_context(struct iommu_domain *domain)
if (!smmu)
return;
- /* Disable the context bank and nuke the TLB before freeing it. */
+ /*
+ * Disable the context bank and free the page tables before freeing
+ * it.
+ */
cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
writel_relaxed(0, cb_base + ARM_SMMU_CB_SCTLR);
- arm_smmu_tlb_inv_context(smmu_domain);
if (cfg->irptndx != INVALID_IRPTNDX) {
irq = smmu->irqs[smmu->num_global_irqs + cfg->irptndx];
free_irq(irq, domain);
}
+ if (smmu_domain->pgtbl_ops)
+ free_io_pgtable_ops(smmu_domain->pgtbl_ops);
+
__arm_smmu_free_bitmap(smmu->context_map, cfg->cbndx);
}
static int arm_smmu_domain_init(struct iommu_domain *domain)
{
struct arm_smmu_domain *smmu_domain;
- pgd_t *pgd;
/*
* Allocate the domain and initialise some of its data structures.
@@ -1026,81 +998,10 @@ static int arm_smmu_domain_init(struct iommu_domain *domain)
if (!smmu_domain)
return -ENOMEM;
- pgd = kcalloc(PTRS_PER_PGD, sizeof(pgd_t), GFP_KERNEL);
- if (!pgd)
- goto out_free_domain;
- smmu_domain->cfg.pgd = pgd;
-
- spin_lock_init(&smmu_domain->lock);
+ mutex_init(&smmu_domain->init_mutex);
+ spin_lock_init(&smmu_domain->pgtbl_lock);
domain->priv = smmu_domain;
return 0;
-
-out_free_domain:
- kfree(smmu_domain);
- return -ENOMEM;
-}
-
-static void arm_smmu_free_ptes(pmd_t *pmd)
-{
- pgtable_t table = pmd_pgtable(*pmd);
-
- __free_page(table);
-}
-
-static void arm_smmu_free_pmds(pud_t *pud)
-{
- int i;
- pmd_t *pmd, *pmd_base = pmd_offset(pud, 0);
-
- pmd = pmd_base;
- for (i = 0; i < PTRS_PER_PMD; ++i) {
- if (pmd_none(*pmd))
- continue;
-
- arm_smmu_free_ptes(pmd);
- pmd++;
- }
-
- pmd_free(NULL, pmd_base);
-}
-
-static void arm_smmu_free_puds(pgd_t *pgd)
-{
- int i;
- pud_t *pud, *pud_base = pud_offset(pgd, 0);
-
- pud = pud_base;
- for (i = 0; i < PTRS_PER_PUD; ++i) {
- if (pud_none(*pud))
- continue;
-
- arm_smmu_free_pmds(pud);
- pud++;
- }
-
- pud_free(NULL, pud_base);
-}
-
-static void arm_smmu_free_pgtables(struct arm_smmu_domain *smmu_domain)
-{
- int i;
- struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- pgd_t *pgd, *pgd_base = cfg->pgd;
-
- /*
- * Recursively free the page tables for this domain. We don't
- * care about speculative TLB filling because the tables should
- * not be active in any context bank at this point (SCTLR.M is 0).
- */
- pgd = pgd_base;
- for (i = 0; i < PTRS_PER_PGD; ++i) {
- if (pgd_none(*pgd))
- continue;
- arm_smmu_free_puds(pgd);
- pgd++;
- }
-
- kfree(pgd_base);
}
static void arm_smmu_domain_destroy(struct iommu_domain *domain)
@@ -1112,7 +1013,6 @@ static void arm_smmu_domain_destroy(struct iommu_domain *domain)
* already been detached.
*/
arm_smmu_destroy_domain_context(domain);
- arm_smmu_free_pgtables(smmu_domain);
kfree(smmu_domain);
}
@@ -1244,7 +1144,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
{
int ret;
struct arm_smmu_domain *smmu_domain = domain->priv;
- struct arm_smmu_device *smmu, *dom_smmu;
+ struct arm_smmu_device *smmu;
struct arm_smmu_master_cfg *cfg;
smmu = find_smmu_for_device(dev);
@@ -1258,21 +1158,16 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
return -EEXIST;
}
+ /* Ensure that the domain is finalised */
+ ret = arm_smmu_init_domain_context(domain, smmu);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+
/*
* Sanity check the domain. We don't support domains across
* different SMMUs.
*/
- dom_smmu = ACCESS_ONCE(smmu_domain->smmu);
- if (!dom_smmu) {
- /* Now that we have a master, we can finalise the domain */
- ret = arm_smmu_init_domain_context(domain, smmu);
- if (IS_ERR_VALUE(ret))
- return ret;
-
- dom_smmu = smmu_domain->smmu;
- }
-
- if (dom_smmu != smmu) {
+ if (smmu_domain->smmu != smmu) {
dev_err(dev,
"cannot attach to SMMU %s whilst already attached to domain on SMMU %s\n",
dev_name(smmu_domain->smmu->dev), dev_name(smmu->dev));
@@ -1303,293 +1198,103 @@ static void arm_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
arm_smmu_domain_remove_master(smmu_domain, cfg);
}
-static bool arm_smmu_pte_is_contiguous_range(unsigned long addr,
- unsigned long end)
-{
- return !(addr & ~ARM_SMMU_PTE_CONT_MASK) &&
- (addr + ARM_SMMU_PTE_CONT_SIZE <= end);
-}
-
-static int arm_smmu_alloc_init_pte(struct arm_smmu_device *smmu, pmd_t *pmd,
- unsigned long addr, unsigned long end,
- unsigned long pfn, int prot, int stage)
-{
- pte_t *pte, *start;
- pteval_t pteval = ARM_SMMU_PTE_PAGE | ARM_SMMU_PTE_AF;
-
- if (pmd_none(*pmd)) {
- /* Allocate a new set of tables */
- pgtable_t table = alloc_page(GFP_ATOMIC|__GFP_ZERO);
-
- if (!table)
- return -ENOMEM;
-
- arm_smmu_flush_pgtable(smmu, page_address(table), PAGE_SIZE);
- pmd_populate(NULL, pmd, table);
- arm_smmu_flush_pgtable(smmu, pmd, sizeof(*pmd));
- }
-
- if (stage == 1) {
- pteval |= ARM_SMMU_PTE_AP_UNPRIV | ARM_SMMU_PTE_nG;
- if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ))
- pteval |= ARM_SMMU_PTE_AP_RDONLY;
-
- if (prot & IOMMU_CACHE)
- pteval |= (MAIR_ATTR_IDX_CACHE <<
- ARM_SMMU_PTE_ATTRINDX_SHIFT);
- } else {
- pteval |= ARM_SMMU_PTE_HAP_FAULT;
- if (prot & IOMMU_READ)
- pteval |= ARM_SMMU_PTE_HAP_READ;
- if (prot & IOMMU_WRITE)
- pteval |= ARM_SMMU_PTE_HAP_WRITE;
- if (prot & IOMMU_CACHE)
- pteval |= ARM_SMMU_PTE_MEMATTR_OIWB;
- else
- pteval |= ARM_SMMU_PTE_MEMATTR_NC;
- }
-
- if (prot & IOMMU_NOEXEC)
- pteval |= ARM_SMMU_PTE_XN;
-
- /* If no access, create a faulting entry to avoid TLB fills */
- if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
- pteval &= ~ARM_SMMU_PTE_PAGE;
-
- pteval |= ARM_SMMU_PTE_SH_IS;
- start = pmd_page_vaddr(*pmd) + pte_index(addr);
- pte = start;
-
- /*
- * Install the page table entries. This is fairly complicated
- * since we attempt to make use of the contiguous hint in the
- * ptes where possible. The contiguous hint indicates a series
- * of ARM_SMMU_PTE_CONT_ENTRIES ptes mapping a physically
- * contiguous region with the following constraints:
- *
- * - The region start is aligned to ARM_SMMU_PTE_CONT_SIZE
- * - Each pte in the region has the contiguous hint bit set
- *
- * This complicates unmapping (also handled by this code, when
- * neither IOMMU_READ or IOMMU_WRITE are set) because it is
- * possible, yet highly unlikely, that a client may unmap only
- * part of a contiguous range. This requires clearing of the
- * contiguous hint bits in the range before installing the new
- * faulting entries.
- *
- * Note that re-mapping an address range without first unmapping
- * it is not supported, so TLB invalidation is not required here
- * and is instead performed at unmap and domain-init time.
- */
- do {
- int i = 1;
-
- pteval &= ~ARM_SMMU_PTE_CONT;
-
- if (arm_smmu_pte_is_contiguous_range(addr, end)) {
- i = ARM_SMMU_PTE_CONT_ENTRIES;
- pteval |= ARM_SMMU_PTE_CONT;
- } else if (pte_val(*pte) &
- (ARM_SMMU_PTE_CONT | ARM_SMMU_PTE_PAGE)) {
- int j;
- pte_t *cont_start;
- unsigned long idx = pte_index(addr);
-
- idx &= ~(ARM_SMMU_PTE_CONT_ENTRIES - 1);
- cont_start = pmd_page_vaddr(*pmd) + idx;
- for (j = 0; j < ARM_SMMU_PTE_CONT_ENTRIES; ++j)
- pte_val(*(cont_start + j)) &=
- ~ARM_SMMU_PTE_CONT;
-
- arm_smmu_flush_pgtable(smmu, cont_start,
- sizeof(*pte) *
- ARM_SMMU_PTE_CONT_ENTRIES);
- }
-
- do {
- *pte = pfn_pte(pfn, __pgprot(pteval));
- } while (pte++, pfn++, addr += PAGE_SIZE, --i);
- } while (addr != end);
-
- arm_smmu_flush_pgtable(smmu, start, sizeof(*pte) * (pte - start));
- return 0;
-}
-
-static int arm_smmu_alloc_init_pmd(struct arm_smmu_device *smmu, pud_t *pud,
- unsigned long addr, unsigned long end,
- phys_addr_t phys, int prot, int stage)
+static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
{
int ret;
- pmd_t *pmd;
- unsigned long next, pfn = __phys_to_pfn(phys);
-
-#ifndef __PAGETABLE_PMD_FOLDED
- if (pud_none(*pud)) {
- pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
- if (!pmd)
- return -ENOMEM;
-
- arm_smmu_flush_pgtable(smmu, pmd, PAGE_SIZE);
- pud_populate(NULL, pud, pmd);
- arm_smmu_flush_pgtable(smmu, pud, sizeof(*pud));
-
- pmd += pmd_index(addr);
- } else
-#endif
- pmd = pmd_offset(pud, addr);
+ unsigned long flags;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
- do {
- next = pmd_addr_end(addr, end);
- ret = arm_smmu_alloc_init_pte(smmu, pmd, addr, next, pfn,
- prot, stage);
- phys += next - addr;
- pfn = __phys_to_pfn(phys);
- } while (pmd++, addr = next, addr < end);
+ if (!ops)
+ return -ENODEV;
+ spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+ ret = ops->map(ops, iova, paddr, size, prot);
+ spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
return ret;
}
-static int arm_smmu_alloc_init_pud(struct arm_smmu_device *smmu, pgd_t *pgd,
- unsigned long addr, unsigned long end,
- phys_addr_t phys, int prot, int stage)
+static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size)
{
- int ret = 0;
- pud_t *pud;
- unsigned long next;
-
-#ifndef __PAGETABLE_PUD_FOLDED
- if (pgd_none(*pgd)) {
- pud = (pud_t *)get_zeroed_page(GFP_ATOMIC);
- if (!pud)
- return -ENOMEM;
-
- arm_smmu_flush_pgtable(smmu, pud, PAGE_SIZE);
- pgd_populate(NULL, pgd, pud);
- arm_smmu_flush_pgtable(smmu, pgd, sizeof(*pgd));
-
- pud += pud_index(addr);
- } else
-#endif
- pud = pud_offset(pgd, addr);
+ size_t ret;
+ unsigned long flags;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
+ struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
- do {
- next = pud_addr_end(addr, end);
- ret = arm_smmu_alloc_init_pmd(smmu, pud, addr, next, phys,
- prot, stage);
- phys += next - addr;
- } while (pud++, addr = next, addr < end);
+ if (!ops)
+ return 0;
+ spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+ ret = ops->unmap(ops, iova, size);
+ spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
return ret;
}
-static int arm_smmu_handle_mapping(struct arm_smmu_domain *smmu_domain,
- unsigned long iova, phys_addr_t paddr,
- size_t size, int prot)
+static phys_addr_t arm_smmu_iova_to_phys_hard(struct iommu_domain *domain,
+ dma_addr_t iova)
{
- int ret, stage;
- unsigned long end;
- phys_addr_t input_mask, output_mask;
+ struct arm_smmu_domain *smmu_domain = domain->priv;
struct arm_smmu_device *smmu = smmu_domain->smmu;
struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
- pgd_t *pgd = cfg->pgd;
- unsigned long flags;
+ struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
+ struct device *dev = smmu->dev;
+ void __iomem *cb_base;
+ u32 tmp;
+ u64 phys;
- if (cfg->cbar == CBAR_TYPE_S2_TRANS) {
- stage = 2;
- input_mask = (1ULL << smmu->s2_input_size) - 1;
- output_mask = (1ULL << smmu->s2_output_size) - 1;
+ cb_base = ARM_SMMU_CB_BASE(smmu) + ARM_SMMU_CB(smmu, cfg->cbndx);
+
+ if (smmu->version == 1) {
+ u32 reg = iova & ~0xfff;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO);
} else {
- stage = 1;
- input_mask = (1ULL << smmu->s1_input_size) - 1;
- output_mask = (1ULL << smmu->s1_output_size) - 1;
+ u32 reg = iova & ~0xfff;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_LO);
+ reg = ((u64)iova & ~0xfff) >> 32;
+ writel_relaxed(reg, cb_base + ARM_SMMU_CB_ATS1PR_HI);
}
- if (!pgd)
- return -EINVAL;
-
- if (size & ~PAGE_MASK)
- return -EINVAL;
-
- if ((phys_addr_t)iova & ~input_mask)
- return -ERANGE;
-
- if (paddr & ~output_mask)
- return -ERANGE;
-
- spin_lock_irqsave(&smmu_domain->lock, flags);
- pgd += pgd_index(iova);
- end = iova + size;
- do {
- unsigned long next = pgd_addr_end(iova, end);
-
- ret = arm_smmu_alloc_init_pud(smmu, pgd, iova, next, paddr,
- prot, stage);
- if (ret)
- goto out_unlock;
-
- paddr += next - iova;
- iova = next;
- } while (pgd++, iova != end);
-
-out_unlock:
- spin_unlock_irqrestore(&smmu_domain->lock, flags);
-
- return ret;
-}
-
-static int arm_smmu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t paddr, size_t size, int prot)
-{
- struct arm_smmu_domain *smmu_domain = domain->priv;
-
- if (!smmu_domain)
- return -ENODEV;
+ if (readl_poll_timeout_atomic(cb_base + ARM_SMMU_CB_ATSR, tmp,
+ !(tmp & ATSR_ACTIVE), 5, 50)) {
+ dev_err(dev,
+ "iova to phys timed out on 0x%pad. Falling back to software table walk.\n",
+ &iova);
+ return ops->iova_to_phys(ops, iova);
+ }
- return arm_smmu_handle_mapping(smmu_domain, iova, paddr, size, prot);
-}
+ phys = readl_relaxed(cb_base + ARM_SMMU_CB_PAR_LO);
+ phys |= ((u64)readl_relaxed(cb_base + ARM_SMMU_CB_PAR_HI)) << 32;
-static size_t arm_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
- size_t size)
-{
- int ret;
- struct arm_smmu_domain *smmu_domain = domain->priv;
+ if (phys & CB_PAR_F) {
+ dev_err(dev, "translation fault!\n");
+ dev_err(dev, "PAR = 0x%llx\n", phys);
+ return 0;
+ }
- ret = arm_smmu_handle_mapping(smmu_domain, iova, 0, size, 0);
- arm_smmu_tlb_inv_context(smmu_domain);
- return ret ? 0 : size;
+ return (phys & GENMASK_ULL(39, 12)) | (iova & 0xfff);
}
static phys_addr_t arm_smmu_iova_to_phys(struct iommu_domain *domain,
- dma_addr_t iova)
+ dma_addr_t iova)
{
- pgd_t *pgdp, pgd;
- pud_t pud;
- pmd_t pmd;
- pte_t pte;
+ phys_addr_t ret;
+ unsigned long flags;
struct arm_smmu_domain *smmu_domain = domain->priv;
- struct arm_smmu_cfg *cfg = &smmu_domain->cfg;
+ struct io_pgtable_ops *ops= smmu_domain->pgtbl_ops;
- pgdp = cfg->pgd;
- if (!pgdp)
+ if (!ops)
return 0;
- pgd = *(pgdp + pgd_index(iova));
- if (pgd_none(pgd))
- return 0;
-
- pud = *pud_offset(&pgd, iova);
- if (pud_none(pud))
- return 0;
-
- pmd = *pmd_offset(&pud, iova);
- if (pmd_none(pmd))
- return 0;
+ spin_lock_irqsave(&smmu_domain->pgtbl_lock, flags);
+ if (smmu_domain->smmu->features & ARM_SMMU_FEAT_TRANS_OPS)
+ ret = arm_smmu_iova_to_phys_hard(domain, iova);
+ else
+ ret = ops->iova_to_phys(ops, iova);
+ spin_unlock_irqrestore(&smmu_domain->pgtbl_lock, flags);
- pte = *(pmd_page_vaddr(pmd) + pte_index(iova));
- if (pte_none(pte))
- return 0;
-
- return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK);
+ return ret;
}
static bool arm_smmu_capable(enum iommu_cap cap)
@@ -1698,24 +1403,34 @@ static int arm_smmu_domain_get_attr(struct iommu_domain *domain,
static int arm_smmu_domain_set_attr(struct iommu_domain *domain,
enum iommu_attr attr, void *data)
{
+ int ret = 0;
struct arm_smmu_domain *smmu_domain = domain->priv;
+ mutex_lock(&smmu_domain->init_mutex);
+
switch (attr) {
case DOMAIN_ATTR_NESTING:
- if (smmu_domain->smmu)
- return -EPERM;
+ if (smmu_domain->smmu) {
+ ret = -EPERM;
+ goto out_unlock;
+ }
+
if (*(int *)data)
smmu_domain->stage = ARM_SMMU_DOMAIN_NESTED;
else
smmu_domain->stage = ARM_SMMU_DOMAIN_S1;
- return 0;
+ break;
default:
- return -ENODEV;
+ ret = -ENODEV;
}
+
+out_unlock:
+ mutex_unlock(&smmu_domain->init_mutex);
+ return ret;
}
-static const struct iommu_ops arm_smmu_ops = {
+static struct iommu_ops arm_smmu_ops = {
.capable = arm_smmu_capable,
.domain_init = arm_smmu_domain_init,
.domain_destroy = arm_smmu_domain_destroy,
@@ -1729,9 +1444,7 @@ static const struct iommu_ops arm_smmu_ops = {
.remove_device = arm_smmu_remove_device,
.domain_get_attr = arm_smmu_domain_get_attr,
.domain_set_attr = arm_smmu_domain_set_attr,
- .pgsize_bitmap = (SECTION_SIZE |
- ARM_SMMU_PTE_CONT_SIZE |
- PAGE_SIZE),
+ .pgsize_bitmap = -1UL, /* Restricted during device attach */
};
static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
@@ -1760,7 +1473,6 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
}
/* Invalidate the TLB, just in case */
- writel_relaxed(0, gr0_base + ARM_SMMU_GR0_STLBIALL);
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLH);
writel_relaxed(0, gr0_base + ARM_SMMU_GR0_TLBIALLNSNH);
@@ -1782,7 +1494,7 @@ static void arm_smmu_device_reset(struct arm_smmu_device *smmu)
reg &= ~(sCR0_BSU_MASK << sCR0_BSU_SHIFT);
/* Push the button */
- arm_smmu_tlb_sync(smmu);
+ __arm_smmu_tlb_sync(smmu);
writel(reg, ARM_SMMU_GR0_NS(smmu) + ARM_SMMU_GR0_sCR0);
}
@@ -1816,12 +1528,6 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
/* ID0 */
id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID0);
-#ifndef CONFIG_64BIT
- if (((id >> ID0_PTFS_SHIFT) & ID0_PTFS_MASK) == ID0_PTFS_V8_ONLY) {
- dev_err(smmu->dev, "\tno v7 descriptor support!\n");
- return -ENODEV;
- }
-#endif
/* Restrict available stages based on module parameter */
if (force_stage == 1)
@@ -1850,6 +1556,11 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
return -ENODEV;
}
+ if (smmu->version == 1 || (!(id & ID0_ATOSNS) && (id & ID0_S1TS))) {
+ smmu->features |= ARM_SMMU_FEAT_TRANS_OPS;
+ dev_notice(smmu->dev, "\taddress translation ops\n");
+ }
+
if (id & ID0_CTTW) {
smmu->features |= ARM_SMMU_FEAT_COHERENT_WALK;
dev_notice(smmu->dev, "\tcoherent table walk\n");
@@ -1894,16 +1605,14 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
smmu->pgshift = (id & ID1_PAGESIZE) ? 16 : 12;
/* Check for size mismatch of SMMU address space from mapped region */
- size = 1 <<
- (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1);
+ size = 1 << (((id >> ID1_NUMPAGENDXB_SHIFT) & ID1_NUMPAGENDXB_MASK) + 1);
size *= 2 << smmu->pgshift;
if (smmu->size != size)
dev_warn(smmu->dev,
"SMMU address space size (0x%lx) differs from mapped region size (0x%lx)!\n",
size, smmu->size);
- smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) &
- ID1_NUMS2CB_MASK;
+ smmu->num_s2_context_banks = (id >> ID1_NUMS2CB_SHIFT) & ID1_NUMS2CB_MASK;
smmu->num_context_banks = (id >> ID1_NUMCB_SHIFT) & ID1_NUMCB_MASK;
if (smmu->num_s2_context_banks > smmu->num_context_banks) {
dev_err(smmu->dev, "impossible number of S2 context banks!\n");
@@ -1915,46 +1624,40 @@ static int arm_smmu_device_cfg_probe(struct arm_smmu_device *smmu)
/* ID2 */
id = readl_relaxed(gr0_base + ARM_SMMU_GR0_ID2);
size = arm_smmu_id_size_to_bits((id >> ID2_IAS_SHIFT) & ID2_IAS_MASK);
- smmu->s1_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);
-
- /* Stage-2 input size limited due to pgd allocation (PTRS_PER_PGD) */
-#ifdef CONFIG_64BIT
- smmu->s2_input_size = min_t(unsigned long, VA_BITS, size);
-#else
- smmu->s2_input_size = min(32UL, size);
-#endif
+ smmu->ipa_size = size;
- /* The stage-2 output mask is also applied for bypass */
+ /* The output mask is also applied for bypass */
size = arm_smmu_id_size_to_bits((id >> ID2_OAS_SHIFT) & ID2_OAS_MASK);
- smmu->s2_output_size = min_t(unsigned long, PHYS_MASK_SHIFT, size);
+ smmu->pa_size = size;
if (smmu->version == ARM_SMMU_V1) {
- smmu->s1_input_size = 32;
+ smmu->va_size = smmu->ipa_size;
+ size = SZ_4K | SZ_2M | SZ_1G;
} else {
-#ifdef CONFIG_64BIT
size = (id >> ID2_UBS_SHIFT) & ID2_UBS_MASK;
- size = min(VA_BITS, arm_smmu_id_size_to_bits(size));
-#else
- size = 32;
+ smmu->va_size = arm_smmu_id_size_to_bits(size);
+#ifndef CONFIG_64BIT
+ smmu->va_size = min(32UL, smmu->va_size);
#endif
- smmu->s1_input_size = size;
-
- if ((PAGE_SIZE == SZ_4K && !(id & ID2_PTFS_4K)) ||
- (PAGE_SIZE == SZ_64K && !(id & ID2_PTFS_64K)) ||
- (PAGE_SIZE != SZ_4K && PAGE_SIZE != SZ_64K)) {
- dev_err(smmu->dev, "CPU page size 0x%lx unsupported\n",
- PAGE_SIZE);
- return -ENODEV;
- }
+ size = 0;
+ if (id & ID2_PTFS_4K)
+ size |= SZ_4K | SZ_2M | SZ_1G;
+ if (id & ID2_PTFS_16K)
+ size |= SZ_16K | SZ_32M;
+ if (id & ID2_PTFS_64K)
+ size |= SZ_64K | SZ_512M;
}
+ arm_smmu_ops.pgsize_bitmap &= size;
+ dev_notice(smmu->dev, "\tSupported page sizes: 0x%08lx\n", size);
+
if (smmu->features & ARM_SMMU_FEAT_TRANS_S1)
dev_notice(smmu->dev, "\tStage-1: %lu-bit VA -> %lu-bit IPA\n",
- smmu->s1_input_size, smmu->s1_output_size);
+ smmu->va_size, smmu->ipa_size);
if (smmu->features & ARM_SMMU_FEAT_TRANS_S2)
dev_notice(smmu->dev, "\tStage-2: %lu-bit IPA -> %lu-bit PA\n",
- smmu->s2_input_size, smmu->s2_output_size);
+ smmu->ipa_size, smmu->pa_size);
return 0;
}
diff --git a/drivers/iommu/fsl_pamu.c b/drivers/iommu/fsl_pamu.c
index 80ac68d884c5..abeedc9a78c2 100644
--- a/drivers/iommu/fsl_pamu.c
+++ b/drivers/iommu/fsl_pamu.c
@@ -18,22 +18,13 @@
#define pr_fmt(fmt) "fsl-pamu: %s: " fmt, __func__
-#include <linux/init.h>
-#include <linux/iommu.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
+#include "fsl_pamu.h"
+
#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/of_platform.h>
-#include <linux/bootmem.h>
#include <linux/genalloc.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-#include <asm/fsl_guts.h>
-#include "fsl_pamu.h"
+#include <asm/mpc85xx.h>
+#include <asm/fsl_guts.h>
/* define indexes for each operation mapping scenario */
#define OMI_QMAN 0x00
@@ -44,13 +35,13 @@
#define make64(high, low) (((u64)(high) << 32) | (low))
struct pamu_isr_data {
- void __iomem *pamu_reg_base; /* Base address of PAMU regs*/
+ void __iomem *pamu_reg_base; /* Base address of PAMU regs */
unsigned int count; /* The number of PAMUs */
};
static struct paace *ppaact;
static struct paace *spaact;
-static struct ome *omt;
+static struct ome *omt __initdata;
/*
* Table for matching compatible strings, for device tree
@@ -58,14 +49,13 @@ static struct ome *omt;
* "fsl,qoriq-device-config-2.0" corresponds to T4 & B4
* SOCs. For the older SOCs "fsl,qoriq-device-config-1.0"
* string would be used.
-*/
-static const struct of_device_id guts_device_ids[] = {
+ */
+static const struct of_device_id guts_device_ids[] __initconst = {
{ .compatible = "fsl,qoriq-device-config-1.0", },
{ .compatible = "fsl,qoriq-device-config-2.0", },
{}
};
-
/*
* Table for matching compatible strings, for device tree
* L3 cache controller node.
@@ -73,7 +63,7 @@ static const struct of_device_id guts_device_ids[] = {
* "fsl,b4860-l3-cache-controller" corresponds to B4 &
* "fsl,p4080-l3-cache-controller" corresponds to other,
* SOCs.
-*/
+ */
static const struct of_device_id l3_device_ids[] = {
{ .compatible = "fsl,t4240-l3-cache-controller", },
{ .compatible = "fsl,b4860-l3-cache-controller", },
@@ -85,7 +75,7 @@ static const struct of_device_id l3_device_ids[] = {
static u32 max_subwindow_count;
/* Pool for fspi allocation */
-struct gen_pool *spaace_pool;
+static struct gen_pool *spaace_pool;
/**
* pamu_get_max_subwin_cnt() - Return the maximum supported
@@ -170,7 +160,7 @@ int pamu_disable_liodn(int liodn)
static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size)
{
/* Bug if not a power of 2 */
- BUG_ON((addrspace_size & (addrspace_size - 1)));
+ BUG_ON(addrspace_size & (addrspace_size - 1));
/* window size is 2^(WSE+1) bytes */
return fls64(addrspace_size) - 2;
@@ -179,8 +169,8 @@ static unsigned int map_addrspace_size_to_wse(phys_addr_t addrspace_size)
/* Derive the PAACE window count encoding for the subwindow count */
static unsigned int map_subwindow_cnt_to_wce(u32 subwindow_cnt)
{
- /* window count is 2^(WCE+1) bytes */
- return __ffs(subwindow_cnt) - 1;
+ /* window count is 2^(WCE+1) bytes */
+ return __ffs(subwindow_cnt) - 1;
}
/*
@@ -241,7 +231,7 @@ static struct paace *pamu_get_spaace(struct paace *paace, u32 wnum)
* If no SPAACE entry is available or the allocator can not reserve the required
* number of contiguous entries function returns ULONG_MAX indicating a failure.
*
-*/
+ */
static unsigned long pamu_get_fspi_and_allocate(u32 subwin_cnt)
{
unsigned long spaace_addr;
@@ -288,9 +278,8 @@ int pamu_update_paace_stash(int liodn, u32 subwin, u32 value)
}
if (subwin) {
paace = pamu_get_spaace(paace, subwin - 1);
- if (!paace) {
+ if (!paace)
return -ENOENT;
- }
}
set_bf(paace->impl_attr, PAACE_IA_CID, value);
@@ -311,14 +300,12 @@ int pamu_disable_spaace(int liodn, u32 subwin)
}
if (subwin) {
paace = pamu_get_spaace(paace, subwin - 1);
- if (!paace) {
+ if (!paace)
return -ENOENT;
- }
- set_bf(paace->addr_bitfields, PAACE_AF_V,
- PAACE_V_INVALID);
+ set_bf(paace->addr_bitfields, PAACE_AF_V, PAACE_V_INVALID);
} else {
set_bf(paace->addr_bitfields, PAACE_AF_AP,
- PAACE_AP_PERMS_DENIED);
+ PAACE_AP_PERMS_DENIED);
}
mb();
@@ -326,7 +313,6 @@ int pamu_disable_spaace(int liodn, u32 subwin)
return 0;
}
-
/**
* pamu_config_paace() - Sets up PPAACE entry for specified liodn
*
@@ -352,7 +338,8 @@ int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
unsigned long fspi;
if ((win_size & (win_size - 1)) || win_size < PAMU_PAGE_SIZE) {
- pr_debug("window size too small or not a power of two %llx\n", win_size);
+ pr_debug("window size too small or not a power of two %pa\n",
+ &win_size);
return -EINVAL;
}
@@ -362,13 +349,12 @@ int pamu_config_ppaace(int liodn, phys_addr_t win_addr, phys_addr_t win_size,
}
ppaace = pamu_get_ppaace(liodn);
- if (!ppaace) {
+ if (!ppaace)
return -ENOENT;
- }
/* window size is 2^(WSE+1) bytes */
set_bf(ppaace->addr_bitfields, PPAACE_AF_WSE,
- map_addrspace_size_to_wse(win_size));
+ map_addrspace_size_to_wse(win_size));
pamu_init_ppaace(ppaace);
@@ -442,7 +428,6 @@ int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin,
{
struct paace *paace;
-
/* setup sub-windows */
if (!subwin_cnt) {
pr_debug("Invalid subwindow count\n");
@@ -510,11 +495,11 @@ int pamu_config_spaace(int liodn, u32 subwin_cnt, u32 subwin,
}
/**
-* get_ome_index() - Returns the index in the operation mapping table
-* for device.
-* @*omi_index: pointer for storing the index value
-*
-*/
+ * get_ome_index() - Returns the index in the operation mapping table
+ * for device.
+ * @*omi_index: pointer for storing the index value
+ *
+ */
void get_ome_index(u32 *omi_index, struct device *dev)
{
if (of_device_is_compatible(dev->of_node, "fsl,qman-portal"))
@@ -544,9 +529,10 @@ u32 get_stash_id(u32 stash_dest_hint, u32 vcpu)
if (stash_dest_hint == PAMU_ATTR_CACHE_L3) {
node = of_find_matching_node(NULL, l3_device_ids);
if (node) {
- prop = of_get_property(node, "cache-stash-id", 0);
+ prop = of_get_property(node, "cache-stash-id", NULL);
if (!prop) {
- pr_debug("missing cache-stash-id at %s\n", node->full_name);
+ pr_debug("missing cache-stash-id at %s\n",
+ node->full_name);
of_node_put(node);
return ~(u32)0;
}
@@ -570,9 +556,10 @@ found_cpu_node:
/* find the hwnode that represents the cache */
for (cache_level = PAMU_ATTR_CACHE_L1; (cache_level < PAMU_ATTR_CACHE_L3) && found; cache_level++) {
if (stash_dest_hint == cache_level) {
- prop = of_get_property(node, "cache-stash-id", 0);
+ prop = of_get_property(node, "cache-stash-id", NULL);
if (!prop) {
- pr_debug("missing cache-stash-id at %s\n", node->full_name);
+ pr_debug("missing cache-stash-id at %s\n",
+ node->full_name);
of_node_put(node);
return ~(u32)0;
}
@@ -580,10 +567,10 @@ found_cpu_node:
return be32_to_cpup(prop);
}
- prop = of_get_property(node, "next-level-cache", 0);
+ prop = of_get_property(node, "next-level-cache", NULL);
if (!prop) {
pr_debug("can't find next-level-cache at %s\n",
- node->full_name);
+ node->full_name);
of_node_put(node);
return ~(u32)0; /* can't traverse any further */
}
@@ -598,7 +585,7 @@ found_cpu_node:
}
pr_debug("stash dest not found for %d on vcpu %d\n",
- stash_dest_hint, vcpu);
+ stash_dest_hint, vcpu);
return ~(u32)0;
}
@@ -612,7 +599,7 @@ found_cpu_node:
* Memory accesses to QMAN and BMAN private memory need not be coherent, so
* clear the PAACE entry coherency attribute for them.
*/
-static void setup_qbman_paace(struct paace *ppaace, int paace_type)
+static void __init setup_qbman_paace(struct paace *ppaace, int paace_type)
{
switch (paace_type) {
case QMAN_PAACE:
@@ -626,7 +613,7 @@ static void setup_qbman_paace(struct paace *ppaace, int paace_type)
case QMAN_PORTAL_PAACE:
set_bf(ppaace->impl_attr, PAACE_IA_OTM, PAACE_OTM_INDEXED);
ppaace->op_encode.index_ot.omi = OMI_QMAN;
- /*Set DQRR and Frame stashing for the L3 cache */
+ /* Set DQRR and Frame stashing for the L3 cache */
set_bf(ppaace->impl_attr, PAACE_IA_CID, get_stash_id(PAMU_ATTR_CACHE_L3, 0));
break;
case BMAN_PAACE:
@@ -679,7 +666,7 @@ static void __init setup_omt(struct ome *omt)
* Get the maximum number of PAACT table entries
* and subwindows supported by PAMU
*/
-static void get_pamu_cap_values(unsigned long pamu_reg_base)
+static void __init get_pamu_cap_values(unsigned long pamu_reg_base)
{
u32 pc_val;
@@ -689,9 +676,9 @@ static void get_pamu_cap_values(unsigned long pamu_reg_base)
}
/* Setup PAMU registers pointing to PAACT, SPAACT and OMT */
-int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size,
- phys_addr_t ppaact_phys, phys_addr_t spaact_phys,
- phys_addr_t omt_phys)
+static int __init setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size,
+ phys_addr_t ppaact_phys, phys_addr_t spaact_phys,
+ phys_addr_t omt_phys)
{
u32 *pc;
struct pamu_mmap_regs *pamu_regs;
@@ -727,7 +714,7 @@ int setup_one_pamu(unsigned long pamu_reg_base, unsigned long pamu_reg_size,
*/
out_be32((u32 *)(pamu_reg_base + PAMU_PICS),
- PAMU_ACCESS_VIOLATION_ENABLE);
+ PAMU_ACCESS_VIOLATION_ENABLE);
out_be32(pc, PAMU_PC_PE | PAMU_PC_OCE | PAMU_PC_SPCC | PAMU_PC_PPCC);
return 0;
}
@@ -757,9 +744,9 @@ static void __init setup_liodns(void)
ppaace->wbah = 0;
set_bf(ppaace->addr_bitfields, PPAACE_AF_WBAL, 0);
set_bf(ppaace->impl_attr, PAACE_IA_ATM,
- PAACE_ATM_NO_XLATE);
+ PAACE_ATM_NO_XLATE);
set_bf(ppaace->addr_bitfields, PAACE_AF_AP,
- PAACE_AP_PERMS_ALL);
+ PAACE_AP_PERMS_ALL);
if (of_device_is_compatible(node, "fsl,qman-portal"))
setup_qbman_paace(ppaace, QMAN_PORTAL_PAACE);
if (of_device_is_compatible(node, "fsl,qman"))
@@ -772,7 +759,7 @@ static void __init setup_liodns(void)
}
}
-irqreturn_t pamu_av_isr(int irq, void *arg)
+static irqreturn_t pamu_av_isr(int irq, void *arg)
{
struct pamu_isr_data *data = arg;
phys_addr_t phys;
@@ -792,14 +779,16 @@ irqreturn_t pamu_av_isr(int irq, void *arg)
pr_emerg("POES2=%08x\n", in_be32(p + PAMU_POES2));
pr_emerg("AVS1=%08x\n", avs1);
pr_emerg("AVS2=%08x\n", in_be32(p + PAMU_AVS2));
- pr_emerg("AVA=%016llx\n", make64(in_be32(p + PAMU_AVAH),
- in_be32(p + PAMU_AVAL)));
+ pr_emerg("AVA=%016llx\n",
+ make64(in_be32(p + PAMU_AVAH),
+ in_be32(p + PAMU_AVAL)));
pr_emerg("UDAD=%08x\n", in_be32(p + PAMU_UDAD));
- pr_emerg("POEA=%016llx\n", make64(in_be32(p + PAMU_POEAH),
- in_be32(p + PAMU_POEAL)));
+ pr_emerg("POEA=%016llx\n",
+ make64(in_be32(p + PAMU_POEAH),
+ in_be32(p + PAMU_POEAL)));
phys = make64(in_be32(p + PAMU_POEAH),
- in_be32(p + PAMU_POEAL));
+ in_be32(p + PAMU_POEAL));
/* Assume that POEA points to a PAACE */
if (phys) {
@@ -807,11 +796,12 @@ irqreturn_t pamu_av_isr(int irq, void *arg)
/* Only the first four words are relevant */
for (j = 0; j < 4; j++)
- pr_emerg("PAACE[%u]=%08x\n", j, in_be32(paace + j));
+ pr_emerg("PAACE[%u]=%08x\n",
+ j, in_be32(paace + j));
}
/* clear access violation condition */
- out_be32((p + PAMU_AVS1), avs1 & PAMU_AV_MASK);
+ out_be32(p + PAMU_AVS1, avs1 & PAMU_AV_MASK);
paace = pamu_get_ppaace(avs1 >> PAMU_AVS1_LIODN_SHIFT);
BUG_ON(!paace);
/* check if we got a violation for a disabled LIODN */
@@ -827,13 +817,13 @@ irqreturn_t pamu_av_isr(int irq, void *arg)
/* Disable the LIODN */
ret = pamu_disable_liodn(avs1 >> PAMU_AVS1_LIODN_SHIFT);
BUG_ON(ret);
- pr_emerg("Disabling liodn %x\n", avs1 >> PAMU_AVS1_LIODN_SHIFT);
+ pr_emerg("Disabling liodn %x\n",
+ avs1 >> PAMU_AVS1_LIODN_SHIFT);
}
out_be32((p + PAMU_PICS), pics);
}
}
-
return IRQ_HANDLED;
}
@@ -952,7 +942,7 @@ static int __init create_csd(phys_addr_t phys, size_t size, u32 csd_port_id)
}
if (i == 0 || i == num_laws) {
- /* This should never happen*/
+ /* This should never happen */
ret = -ENOENT;
goto error;
}
@@ -998,26 +988,27 @@ error:
static const struct {
u32 svr;
u32 port_id;
-} port_id_map[] = {
- {0x82100010, 0xFF000000}, /* P2040 1.0 */
- {0x82100011, 0xFF000000}, /* P2040 1.1 */
- {0x82100110, 0xFF000000}, /* P2041 1.0 */
- {0x82100111, 0xFF000000}, /* P2041 1.1 */
- {0x82110310, 0xFF000000}, /* P3041 1.0 */
- {0x82110311, 0xFF000000}, /* P3041 1.1 */
- {0x82010020, 0xFFF80000}, /* P4040 2.0 */
- {0x82000020, 0xFFF80000}, /* P4080 2.0 */
- {0x82210010, 0xFC000000}, /* P5010 1.0 */
- {0x82210020, 0xFC000000}, /* P5010 2.0 */
- {0x82200010, 0xFC000000}, /* P5020 1.0 */
- {0x82050010, 0xFF800000}, /* P5021 1.0 */
- {0x82040010, 0xFF800000}, /* P5040 1.0 */
+} port_id_map[] __initconst = {
+ {(SVR_P2040 << 8) | 0x10, 0xFF000000}, /* P2040 1.0 */
+ {(SVR_P2040 << 8) | 0x11, 0xFF000000}, /* P2040 1.1 */
+ {(SVR_P2041 << 8) | 0x10, 0xFF000000}, /* P2041 1.0 */
+ {(SVR_P2041 << 8) | 0x11, 0xFF000000}, /* P2041 1.1 */
+ {(SVR_P3041 << 8) | 0x10, 0xFF000000}, /* P3041 1.0 */
+ {(SVR_P3041 << 8) | 0x11, 0xFF000000}, /* P3041 1.1 */
+ {(SVR_P4040 << 8) | 0x20, 0xFFF80000}, /* P4040 2.0 */
+ {(SVR_P4080 << 8) | 0x20, 0xFFF80000}, /* P4080 2.0 */
+ {(SVR_P5010 << 8) | 0x10, 0xFC000000}, /* P5010 1.0 */
+ {(SVR_P5010 << 8) | 0x20, 0xFC000000}, /* P5010 2.0 */
+ {(SVR_P5020 << 8) | 0x10, 0xFC000000}, /* P5020 1.0 */
+ {(SVR_P5021 << 8) | 0x10, 0xFF800000}, /* P5021 1.0 */
+ {(SVR_P5040 << 8) | 0x10, 0xFF800000}, /* P5040 1.0 */
};
#define SVR_SECURITY 0x80000 /* The Security (E) bit */
static int __init fsl_pamu_probe(struct platform_device *pdev)
{
+ struct device *dev = &pdev->dev;
void __iomem *pamu_regs = NULL;
struct ccsr_guts __iomem *guts_regs = NULL;
u32 pamubypenr, pamu_counter;
@@ -1042,22 +1033,21 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
* NOTE : All PAMUs share the same LIODN tables.
*/
- pamu_regs = of_iomap(pdev->dev.of_node, 0);
+ pamu_regs = of_iomap(dev->of_node, 0);
if (!pamu_regs) {
- dev_err(&pdev->dev, "ioremap of PAMU node failed\n");
+ dev_err(dev, "ioremap of PAMU node failed\n");
return -ENOMEM;
}
- of_get_address(pdev->dev.of_node, 0, &size, NULL);
+ of_get_address(dev->of_node, 0, &size, NULL);
- irq = irq_of_parse_and_map(pdev->dev.of_node, 0);
+ irq = irq_of_parse_and_map(dev->of_node, 0);
if (irq == NO_IRQ) {
- dev_warn(&pdev->dev, "no interrupts listed in PAMU node\n");
+ dev_warn(dev, "no interrupts listed in PAMU node\n");
goto error;
}
- data = kzalloc(sizeof(struct pamu_isr_data), GFP_KERNEL);
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data) {
- dev_err(&pdev->dev, "PAMU isr data memory allocation failed\n");
ret = -ENOMEM;
goto error;
}
@@ -1067,15 +1057,14 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
/* The ISR needs access to the regs, so we won't iounmap them */
ret = request_irq(irq, pamu_av_isr, 0, "pamu", data);
if (ret < 0) {
- dev_err(&pdev->dev, "error %i installing ISR for irq %i\n",
- ret, irq);
+ dev_err(dev, "error %i installing ISR for irq %i\n", ret, irq);
goto error;
}
guts_node = of_find_matching_node(NULL, guts_device_ids);
if (!guts_node) {
- dev_err(&pdev->dev, "could not find GUTS node %s\n",
- pdev->dev.of_node->full_name);
+ dev_err(dev, "could not find GUTS node %s\n",
+ dev->of_node->full_name);
ret = -ENODEV;
goto error;
}
@@ -1083,7 +1072,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
guts_regs = of_iomap(guts_node, 0);
of_node_put(guts_node);
if (!guts_regs) {
- dev_err(&pdev->dev, "ioremap of GUTS node failed\n");
+ dev_err(dev, "ioremap of GUTS node failed\n");
ret = -ENODEV;
goto error;
}
@@ -1103,7 +1092,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
p = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
if (!p) {
- dev_err(&pdev->dev, "unable to allocate PAACT/SPAACT/OMT block\n");
+ dev_err(dev, "unable to allocate PAACT/SPAACT/OMT block\n");
ret = -ENOMEM;
goto error;
}
@@ -1113,7 +1102,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
/* Make sure the memory is naturally aligned */
if (ppaact_phys & ((PAGE_SIZE << order) - 1)) {
- dev_err(&pdev->dev, "PAACT/OMT block is unaligned\n");
+ dev_err(dev, "PAACT/OMT block is unaligned\n");
ret = -ENOMEM;
goto error;
}
@@ -1121,8 +1110,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
spaact = (void *)ppaact + (PAGE_SIZE << get_order(PAACT_SIZE));
omt = (void *)spaact + (PAGE_SIZE << get_order(SPAACT_SIZE));
- dev_dbg(&pdev->dev, "ppaact virt=%p phys=0x%llx\n", ppaact,
- (unsigned long long) ppaact_phys);
+ dev_dbg(dev, "ppaact virt=%p phys=%pa\n", ppaact, &ppaact_phys);
/* Check to see if we need to implement the work-around on this SOC */
@@ -1130,21 +1118,19 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
for (i = 0; i < ARRAY_SIZE(port_id_map); i++) {
if (port_id_map[i].svr == (mfspr(SPRN_SVR) & ~SVR_SECURITY)) {
csd_port_id = port_id_map[i].port_id;
- dev_dbg(&pdev->dev, "found matching SVR %08x\n",
+ dev_dbg(dev, "found matching SVR %08x\n",
port_id_map[i].svr);
break;
}
}
if (csd_port_id) {
- dev_dbg(&pdev->dev, "creating coherency subdomain at address "
- "0x%llx, size %zu, port id 0x%08x", ppaact_phys,
- mem_size, csd_port_id);
+ dev_dbg(dev, "creating coherency subdomain at address %pa, size %zu, port id 0x%08x",
+ &ppaact_phys, mem_size, csd_port_id);
ret = create_csd(ppaact_phys, mem_size, csd_port_id);
if (ret) {
- dev_err(&pdev->dev, "could not create coherence "
- "subdomain\n");
+ dev_err(dev, "could not create coherence subdomain\n");
return ret;
}
}
@@ -1155,7 +1141,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
spaace_pool = gen_pool_create(ilog2(sizeof(struct paace)), -1);
if (!spaace_pool) {
ret = -ENOMEM;
- dev_err(&pdev->dev, "PAMU : failed to allocate spaace gen pool\n");
+ dev_err(dev, "Failed to allocate spaace gen pool\n");
goto error;
}
@@ -1168,9 +1154,9 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
for (pamu_reg_off = 0, pamu_counter = 0x80000000; pamu_reg_off < size;
pamu_reg_off += PAMU_OFFSET, pamu_counter >>= 1) {
- pamu_reg_base = (unsigned long) pamu_regs + pamu_reg_off;
+ pamu_reg_base = (unsigned long)pamu_regs + pamu_reg_off;
setup_one_pamu(pamu_reg_base, pamu_reg_off, ppaact_phys,
- spaact_phys, omt_phys);
+ spaact_phys, omt_phys);
/* Disable PAMU bypass for this PAMU */
pamubypenr &= ~pamu_counter;
}
@@ -1182,7 +1168,7 @@ static int __init fsl_pamu_probe(struct platform_device *pdev)
iounmap(guts_regs);
- /* Enable DMA for the LIODNs in the device tree*/
+ /* Enable DMA for the LIODNs in the device tree */
setup_liodns();
@@ -1214,17 +1200,7 @@ error:
return ret;
}
-static const struct of_device_id fsl_of_pamu_ids[] = {
- {
- .compatible = "fsl,p4080-pamu",
- },
- {
- .compatible = "fsl,pamu",
- },
- {},
-};
-
-static struct platform_driver fsl_of_pamu_driver = {
+static struct platform_driver fsl_of_pamu_driver __initdata = {
.driver = {
.name = "fsl-of-pamu",
},
diff --git a/drivers/iommu/fsl_pamu.h b/drivers/iommu/fsl_pamu.h
index 8fc1a125b16e..aab723f91f12 100644
--- a/drivers/iommu/fsl_pamu.h
+++ b/drivers/iommu/fsl_pamu.h
@@ -19,13 +19,15 @@
#ifndef __FSL_PAMU_H
#define __FSL_PAMU_H
+#include <linux/iommu.h>
+
#include <asm/fsl_pamu_stash.h>
/* Bit Field macros
* v = bit field variable; m = mask, m##_SHIFT = shift, x = value to load
*/
-#define set_bf(v, m, x) (v = ((v) & ~(m)) | (((x) << (m##_SHIFT)) & (m)))
-#define get_bf(v, m) (((v) & (m)) >> (m##_SHIFT))
+#define set_bf(v, m, x) (v = ((v) & ~(m)) | (((x) << m##_SHIFT) & (m)))
+#define get_bf(v, m) (((v) & (m)) >> m##_SHIFT)
/* PAMU CCSR space */
#define PAMU_PGC 0x00000000 /* Allows all peripheral accesses */
@@ -65,7 +67,7 @@ struct pamu_mmap_regs {
#define PAMU_AVS1_GCV 0x2000
#define PAMU_AVS1_PDV 0x4000
#define PAMU_AV_MASK (PAMU_AVS1_AV | PAMU_AVS1_OTV | PAMU_AVS1_APV | PAMU_AVS1_WAV \
- | PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV)
+ | PAMU_AVS1_LAV | PAMU_AVS1_GCV | PAMU_AVS1_PDV)
#define PAMU_AVS1_LIODN_SHIFT 16
#define PAMU_LAV_LIODN_NOT_IN_PPAACT 0x400
@@ -198,8 +200,7 @@ struct pamu_mmap_regs {
#define PAACE_ATM_NO_XLATE 0x00
#define PAACE_ATM_WINDOW_XLATE 0x01
#define PAACE_ATM_PAGE_XLATE 0x02
-#define PAACE_ATM_WIN_PG_XLATE \
- (PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE)
+#define PAACE_ATM_WIN_PG_XLATE (PAACE_ATM_WINDOW_XLATE | PAACE_ATM_PAGE_XLATE)
#define PAACE_OTM_NO_XLATE 0x00
#define PAACE_OTM_IMMEDIATE 0x01
#define PAACE_OTM_INDEXED 0x02
@@ -219,7 +220,7 @@ struct pamu_mmap_regs {
#define PAACE_TCEF_FORMAT0_8B 0x00
#define PAACE_TCEF_FORMAT1_RSVD 0x01
/*
- * Hard coded value for the PAACT size to accomodate
+ * Hard coded value for the PAACT size to accommodate
* maximum LIODN value generated by u-boot.
*/
#define PAACE_NUMBER_ENTRIES 0x500
@@ -332,7 +333,7 @@ struct paace {
#define NUM_MOE 128
struct ome {
u8 moe[NUM_MOE];
-} __attribute__((packed));
+} __packed;
#define PAACT_SIZE (sizeof(struct paace) * PAACE_NUMBER_ENTRIES)
#define SPAACT_SIZE (sizeof(struct paace) * SPAACE_NUMBER_ENTRIES)
diff --git a/drivers/iommu/fsl_pamu_domain.c b/drivers/iommu/fsl_pamu_domain.c
index c828f80d48b0..ceebd287b660 100644
--- a/drivers/iommu/fsl_pamu_domain.c
+++ b/drivers/iommu/fsl_pamu_domain.c
@@ -19,26 +19,10 @@
#define pr_fmt(fmt) "fsl-pamu-domain: %s: " fmt, __func__
-#include <linux/init.h>
-#include <linux/iommu.h>
-#include <linux/notifier.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-#include <linux/interrupt.h>
-#include <linux/device.h>
-#include <linux/of_platform.h>
-#include <linux/bootmem.h>
-#include <linux/err.h>
-#include <asm/io.h>
-#include <asm/bitops.h>
-
-#include <asm/pci-bridge.h>
-#include <sysdev/fsl_pci.h>
-
#include "fsl_pamu_domain.h"
+#include <sysdev/fsl_pci.h>
+
/*
* Global spinlock that needs to be held while
* configuring PAMU.
@@ -51,23 +35,21 @@ static DEFINE_SPINLOCK(device_domain_lock);
static int __init iommu_init_mempool(void)
{
-
fsl_pamu_domain_cache = kmem_cache_create("fsl_pamu_domain",
- sizeof(struct fsl_dma_domain),
- 0,
- SLAB_HWCACHE_ALIGN,
-
- NULL);
+ sizeof(struct fsl_dma_domain),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL);
if (!fsl_pamu_domain_cache) {
pr_debug("Couldn't create fsl iommu_domain cache\n");
return -ENOMEM;
}
iommu_devinfo_cache = kmem_cache_create("iommu_devinfo",
- sizeof(struct device_domain_info),
- 0,
- SLAB_HWCACHE_ALIGN,
- NULL);
+ sizeof(struct device_domain_info),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL);
if (!iommu_devinfo_cache) {
pr_debug("Couldn't create devinfo cache\n");
kmem_cache_destroy(fsl_pamu_domain_cache);
@@ -80,8 +62,7 @@ static int __init iommu_init_mempool(void)
static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t iova)
{
u32 win_cnt = dma_domain->win_cnt;
- struct dma_window *win_ptr =
- &dma_domain->win_arr[0];
+ struct dma_window *win_ptr = &dma_domain->win_arr[0];
struct iommu_domain_geometry *geom;
geom = &dma_domain->iommu_domain->geometry;
@@ -103,22 +84,20 @@ static phys_addr_t get_phys_addr(struct fsl_dma_domain *dma_domain, dma_addr_t i
}
if (win_ptr->valid)
- return (win_ptr->paddr + (iova & (win_ptr->size - 1)));
+ return win_ptr->paddr + (iova & (win_ptr->size - 1));
return 0;
}
static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain)
{
- struct dma_window *sub_win_ptr =
- &dma_domain->win_arr[0];
+ struct dma_window *sub_win_ptr = &dma_domain->win_arr[0];
int i, ret;
unsigned long rpn, flags;
for (i = 0; i < dma_domain->win_cnt; i++) {
if (sub_win_ptr[i].valid) {
- rpn = sub_win_ptr[i].paddr >>
- PAMU_PAGE_SHIFT;
+ rpn = sub_win_ptr[i].paddr >> PAMU_PAGE_SHIFT;
spin_lock_irqsave(&iommu_lock, flags);
ret = pamu_config_spaace(liodn, dma_domain->win_cnt, i,
sub_win_ptr[i].size,
@@ -130,7 +109,7 @@ static int map_subwins(int liodn, struct fsl_dma_domain *dma_domain)
sub_win_ptr[i].prot);
spin_unlock_irqrestore(&iommu_lock, flags);
if (ret) {
- pr_debug("PAMU SPAACE configuration failed for liodn %d\n",
+ pr_debug("SPAACE configuration failed for liodn %d\n",
liodn);
return ret;
}
@@ -156,8 +135,7 @@ static int map_win(int liodn, struct fsl_dma_domain *dma_domain)
0, wnd->prot);
spin_unlock_irqrestore(&iommu_lock, flags);
if (ret)
- pr_debug("PAMU PAACE configuration failed for liodn %d\n",
- liodn);
+ pr_debug("PAACE configuration failed for liodn %d\n", liodn);
return ret;
}
@@ -169,7 +147,6 @@ static int map_liodn(int liodn, struct fsl_dma_domain *dma_domain)
return map_subwins(liodn, dma_domain);
else
return map_win(liodn, dma_domain);
-
}
/* Update window/subwindow mapping for the LIODN */
@@ -190,7 +167,8 @@ static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr
(wnd_nr > 0) ? 1 : 0,
wnd->prot);
if (ret)
- pr_debug("Subwindow reconfiguration failed for liodn %d\n", liodn);
+ pr_debug("Subwindow reconfiguration failed for liodn %d\n",
+ liodn);
} else {
phys_addr_t wnd_addr;
@@ -200,10 +178,11 @@ static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr
wnd->size,
~(u32)0,
wnd->paddr >> PAMU_PAGE_SHIFT,
- dma_domain->snoop_id, dma_domain->stash_id,
- 0, wnd->prot);
+ dma_domain->snoop_id, dma_domain->stash_id,
+ 0, wnd->prot);
if (ret)
- pr_debug("Window reconfiguration failed for liodn %d\n", liodn);
+ pr_debug("Window reconfiguration failed for liodn %d\n",
+ liodn);
}
spin_unlock_irqrestore(&iommu_lock, flags);
@@ -212,14 +191,15 @@ static int update_liodn(int liodn, struct fsl_dma_domain *dma_domain, u32 wnd_nr
}
static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
- u32 val)
+ u32 val)
{
int ret = 0, i;
unsigned long flags;
spin_lock_irqsave(&iommu_lock, flags);
if (!dma_domain->win_arr) {
- pr_debug("Windows not configured, stash destination update failed for liodn %d\n", liodn);
+ pr_debug("Windows not configured, stash destination update failed for liodn %d\n",
+ liodn);
spin_unlock_irqrestore(&iommu_lock, flags);
return -EINVAL;
}
@@ -227,7 +207,8 @@ static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
for (i = 0; i < dma_domain->win_cnt; i++) {
ret = pamu_update_paace_stash(liodn, i, val);
if (ret) {
- pr_debug("Failed to update SPAACE %d field for liodn %d\n ", i, liodn);
+ pr_debug("Failed to update SPAACE %d field for liodn %d\n ",
+ i, liodn);
spin_unlock_irqrestore(&iommu_lock, flags);
return ret;
}
@@ -240,9 +221,9 @@ static int update_liodn_stash(int liodn, struct fsl_dma_domain *dma_domain,
/* Set the geometry parameters for a LIODN */
static int pamu_set_liodn(int liodn, struct device *dev,
- struct fsl_dma_domain *dma_domain,
- struct iommu_domain_geometry *geom_attr,
- u32 win_cnt)
+ struct fsl_dma_domain *dma_domain,
+ struct iommu_domain_geometry *geom_attr,
+ u32 win_cnt)
{
phys_addr_t window_addr, window_size;
phys_addr_t subwin_size;
@@ -268,7 +249,8 @@ static int pamu_set_liodn(int liodn, struct device *dev,
dma_domain->stash_id, win_cnt, 0);
spin_unlock_irqrestore(&iommu_lock, flags);
if (ret) {
- pr_debug("PAMU PAACE configuration failed for liodn %d, win_cnt =%d\n", liodn, win_cnt);
+ pr_debug("PAACE configuration failed for liodn %d, win_cnt =%d\n",
+ liodn, win_cnt);
return ret;
}
@@ -285,7 +267,8 @@ static int pamu_set_liodn(int liodn, struct device *dev,
0, 0);
spin_unlock_irqrestore(&iommu_lock, flags);
if (ret) {
- pr_debug("PAMU SPAACE configuration failed for liodn %d\n", liodn);
+ pr_debug("SPAACE configuration failed for liodn %d\n",
+ liodn);
return ret;
}
}
@@ -301,13 +284,13 @@ static int check_size(u64 size, dma_addr_t iova)
* to PAMU page size.
*/
if ((size & (size - 1)) || size < PAMU_PAGE_SIZE) {
- pr_debug("%s: size too small or not a power of two\n", __func__);
+ pr_debug("Size too small or not a power of two\n");
return -EINVAL;
}
- /* iova must be page size aligned*/
+ /* iova must be page size aligned */
if (iova & (size - 1)) {
- pr_debug("%s: address is not aligned with window size\n", __func__);
+ pr_debug("Address is not aligned with window size\n");
return -EINVAL;
}
@@ -396,16 +379,15 @@ static void attach_device(struct fsl_dma_domain *dma_domain, int liodn, struct d
if (!dev->archdata.iommu_domain)
dev->archdata.iommu_domain = info;
spin_unlock_irqrestore(&device_domain_lock, flags);
-
}
static phys_addr_t fsl_pamu_iova_to_phys(struct iommu_domain *domain,
- dma_addr_t iova)
+ dma_addr_t iova)
{
struct fsl_dma_domain *dma_domain = domain->priv;
- if ((iova < domain->geometry.aperture_start) ||
- iova > (domain->geometry.aperture_end))
+ if (iova < domain->geometry.aperture_start ||
+ iova > domain->geometry.aperture_end)
return 0;
return get_phys_addr(dma_domain, iova);
@@ -460,7 +442,7 @@ static int pamu_set_domain_geometry(struct fsl_dma_domain *dma_domain,
list_for_each_entry(info, &dma_domain->devices, link) {
ret = pamu_set_liodn(info->liodn, info->dev, dma_domain,
- geom_attr, win_cnt);
+ geom_attr, win_cnt);
if (ret)
break;
}
@@ -543,7 +525,6 @@ static void fsl_pamu_window_disable(struct iommu_domain *domain, u32 wnd_nr)
}
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
-
}
static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr,
@@ -576,7 +557,7 @@ static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr,
win_size = dma_domain->geom_size >> ilog2(dma_domain->win_cnt);
if (size > win_size) {
- pr_debug("Invalid window size \n");
+ pr_debug("Invalid window size\n");
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
return -EINVAL;
}
@@ -622,8 +603,8 @@ static int fsl_pamu_window_enable(struct iommu_domain *domain, u32 wnd_nr,
* and window mappings.
*/
static int handle_attach_device(struct fsl_dma_domain *dma_domain,
- struct device *dev, const u32 *liodn,
- int num)
+ struct device *dev, const u32 *liodn,
+ int num)
{
unsigned long flags;
struct iommu_domain *domain = dma_domain->iommu_domain;
@@ -632,11 +613,10 @@ static int handle_attach_device(struct fsl_dma_domain *dma_domain,
spin_lock_irqsave(&dma_domain->domain_lock, flags);
for (i = 0; i < num; i++) {
-
/* Ensure that LIODN value is valid */
if (liodn[i] >= PAACE_NUMBER_ENTRIES) {
pr_debug("Invalid liodn %d, attach device failed for %s\n",
- liodn[i], dev->of_node->full_name);
+ liodn[i], dev->of_node->full_name);
ret = -EINVAL;
break;
}
@@ -649,9 +629,9 @@ static int handle_attach_device(struct fsl_dma_domain *dma_domain,
*/
if (dma_domain->win_arr) {
u32 win_cnt = dma_domain->win_cnt > 1 ? dma_domain->win_cnt : 0;
+
ret = pamu_set_liodn(liodn[i], dev, dma_domain,
- &domain->geometry,
- win_cnt);
+ &domain->geometry, win_cnt);
if (ret)
break;
if (dma_domain->mapped) {
@@ -698,19 +678,18 @@ static int fsl_pamu_attach_device(struct iommu_domain *domain,
liodn = of_get_property(dev->of_node, "fsl,liodn", &len);
if (liodn) {
liodn_cnt = len / sizeof(u32);
- ret = handle_attach_device(dma_domain, dev,
- liodn, liodn_cnt);
+ ret = handle_attach_device(dma_domain, dev, liodn, liodn_cnt);
} else {
pr_debug("missing fsl,liodn property at %s\n",
- dev->of_node->full_name);
- ret = -EINVAL;
+ dev->of_node->full_name);
+ ret = -EINVAL;
}
return ret;
}
static void fsl_pamu_detach_device(struct iommu_domain *domain,
- struct device *dev)
+ struct device *dev)
{
struct fsl_dma_domain *dma_domain = domain->priv;
const u32 *prop;
@@ -738,7 +717,7 @@ static void fsl_pamu_detach_device(struct iommu_domain *domain,
detach_device(dev, dma_domain);
else
pr_debug("missing fsl,liodn property at %s\n",
- dev->of_node->full_name);
+ dev->of_node->full_name);
}
static int configure_domain_geometry(struct iommu_domain *domain, void *data)
@@ -754,10 +733,10 @@ static int configure_domain_geometry(struct iommu_domain *domain, void *data)
* DMA outside of the geometry.
*/
if (check_size(geom_size, geom_attr->aperture_start) ||
- !geom_attr->force_aperture) {
- pr_debug("Invalid PAMU geometry attributes\n");
- return -EINVAL;
- }
+ !geom_attr->force_aperture) {
+ pr_debug("Invalid PAMU geometry attributes\n");
+ return -EINVAL;
+ }
spin_lock_irqsave(&dma_domain->domain_lock, flags);
if (dma_domain->enabled) {
@@ -786,7 +765,7 @@ static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data)
spin_lock_irqsave(&dma_domain->domain_lock, flags);
memcpy(&dma_domain->dma_stash, stash_attr,
- sizeof(struct pamu_stash_attribute));
+ sizeof(struct pamu_stash_attribute));
dma_domain->stash_id = get_stash_id(stash_attr->cache,
stash_attr->cpu);
@@ -803,7 +782,7 @@ static int configure_domain_stash(struct fsl_dma_domain *dma_domain, void *data)
return ret;
}
-/* Configure domain dma state i.e. enable/disable DMA*/
+/* Configure domain dma state i.e. enable/disable DMA */
static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool enable)
{
struct device_domain_info *info;
@@ -819,8 +798,7 @@ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool en
}
dma_domain->enabled = enable;
- list_for_each_entry(info, &dma_domain->devices,
- link) {
+ list_for_each_entry(info, &dma_domain->devices, link) {
ret = (enable) ? pamu_enable_liodn(info->liodn) :
pamu_disable_liodn(info->liodn);
if (ret)
@@ -833,12 +811,11 @@ static int configure_domain_dma_state(struct fsl_dma_domain *dma_domain, bool en
}
static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
- enum iommu_attr attr_type, void *data)
+ enum iommu_attr attr_type, void *data)
{
struct fsl_dma_domain *dma_domain = domain->priv;
int ret = 0;
-
switch (attr_type) {
case DOMAIN_ATTR_GEOMETRY:
ret = configure_domain_geometry(domain, data);
@@ -853,22 +830,21 @@ static int fsl_pamu_set_domain_attr(struct iommu_domain *domain,
pr_debug("Unsupported attribute type\n");
ret = -EINVAL;
break;
- };
+ }
return ret;
}
static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
- enum iommu_attr attr_type, void *data)
+ enum iommu_attr attr_type, void *data)
{
struct fsl_dma_domain *dma_domain = domain->priv;
int ret = 0;
-
switch (attr_type) {
case DOMAIN_ATTR_FSL_PAMU_STASH:
- memcpy((struct pamu_stash_attribute *) data, &dma_domain->dma_stash,
- sizeof(struct pamu_stash_attribute));
+ memcpy(data, &dma_domain->dma_stash,
+ sizeof(struct pamu_stash_attribute));
break;
case DOMAIN_ATTR_FSL_PAMU_ENABLE:
*(int *)data = dma_domain->enabled;
@@ -880,7 +856,7 @@ static int fsl_pamu_get_domain_attr(struct iommu_domain *domain,
pr_debug("Unsupported attribute type\n");
ret = -EINVAL;
break;
- };
+ }
return ret;
}
@@ -903,11 +879,8 @@ static bool check_pci_ctl_endpt_part(struct pci_controller *pci_ctl)
/* Check the PCI controller version number by readding BRR1 register */
version = in_be32(pci_ctl->cfg_addr + (PCI_FSL_BRR1 >> 2));
version &= PCI_FSL_BRR1_VER;
- /* If PCI controller version is >= 0x204 we can partition endpoints*/
- if (version >= 0x204)
- return 1;
-
- return 0;
+ /* If PCI controller version is >= 0x204 we can partition endpoints */
+ return version >= 0x204;
}
/* Get iommu group information from peer devices or devices on the parent bus */
@@ -968,8 +941,9 @@ static struct iommu_group *get_pci_device_group(struct pci_dev *pdev)
if (pci_ctl->parent->iommu_group) {
group = get_device_iommu_group(pci_ctl->parent);
iommu_group_remove_device(pci_ctl->parent);
- } else
+ } else {
group = get_shared_pci_device_group(pdev);
+ }
}
if (!group)
@@ -1055,11 +1029,12 @@ static int fsl_pamu_set_windows(struct iommu_domain *domain, u32 w_count)
}
ret = pamu_set_domain_geometry(dma_domain, &domain->geometry,
- ((w_count > 1) ? w_count : 0));
+ w_count > 1 ? w_count : 0);
if (!ret) {
kfree(dma_domain->win_arr);
- dma_domain->win_arr = kzalloc(sizeof(struct dma_window) *
- w_count, GFP_ATOMIC);
+ dma_domain->win_arr = kcalloc(w_count,
+ sizeof(*dma_domain->win_arr),
+ GFP_ATOMIC);
if (!dma_domain->win_arr) {
spin_unlock_irqrestore(&dma_domain->domain_lock, flags);
return -ENOMEM;
@@ -1095,7 +1070,7 @@ static const struct iommu_ops fsl_pamu_ops = {
.remove_device = fsl_pamu_remove_device,
};
-int pamu_domain_init(void)
+int __init pamu_domain_init(void)
{
int ret = 0;
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index 40dfbc0444c0..ae4c1a854e57 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -71,6 +71,9 @@
__DOMAIN_MAX_PFN(gaw), (unsigned long)-1))
#define DOMAIN_MAX_ADDR(gaw) (((uint64_t)__DOMAIN_MAX_PFN(gaw)) << VTD_PAGE_SHIFT)
+/* IO virtual address start page frame number */
+#define IOVA_START_PFN (1)
+
#define IOVA_PFN(addr) ((addr) >> PAGE_SHIFT)
#define DMA_32BIT_PFN IOVA_PFN(DMA_BIT_MASK(32))
#define DMA_64BIT_PFN IOVA_PFN(DMA_BIT_MASK(64))
@@ -485,7 +488,6 @@ __setup("intel_iommu=", intel_iommu_setup);
static struct kmem_cache *iommu_domain_cache;
static struct kmem_cache *iommu_devinfo_cache;
-static struct kmem_cache *iommu_iova_cache;
static inline void *alloc_pgtable_page(int node)
{
@@ -523,16 +525,6 @@ static inline void free_devinfo_mem(void *vaddr)
kmem_cache_free(iommu_devinfo_cache, vaddr);
}
-struct iova *alloc_iova_mem(void)
-{
- return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
-}
-
-void free_iova_mem(struct iova *iova)
-{
- kmem_cache_free(iommu_iova_cache, iova);
-}
-
static inline int domain_type_is_vm(struct dmar_domain *domain)
{
return domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE;
@@ -1643,7 +1635,8 @@ static int dmar_init_reserved_ranges(void)
struct iova *iova;
int i;
- init_iova_domain(&reserved_iova_list, DMA_32BIT_PFN);
+ init_iova_domain(&reserved_iova_list, VTD_PAGE_SIZE, IOVA_START_PFN,
+ DMA_32BIT_PFN);
lockdep_set_class(&reserved_iova_list.iova_rbtree_lock,
&reserved_rbtree_key);
@@ -1701,7 +1694,8 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
int adjust_width, agaw;
unsigned long sagaw;
- init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
+ init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN,
+ DMA_32BIT_PFN);
domain_reserve_special_ranges(domain);
/* calculate AGAW */
@@ -3427,23 +3421,6 @@ static inline int iommu_devinfo_cache_init(void)
return ret;
}
-static inline int iommu_iova_cache_init(void)
-{
- int ret = 0;
-
- iommu_iova_cache = kmem_cache_create("iommu_iova",
- sizeof(struct iova),
- 0,
- SLAB_HWCACHE_ALIGN,
- NULL);
- if (!iommu_iova_cache) {
- printk(KERN_ERR "Couldn't create iova cache\n");
- ret = -ENOMEM;
- }
-
- return ret;
-}
-
static int __init iommu_init_mempool(void)
{
int ret;
@@ -3461,7 +3438,7 @@ static int __init iommu_init_mempool(void)
kmem_cache_destroy(iommu_domain_cache);
domain_error:
- kmem_cache_destroy(iommu_iova_cache);
+ iommu_iova_cache_destroy();
return -ENOMEM;
}
@@ -3470,8 +3447,7 @@ static void __init iommu_exit_mempool(void)
{
kmem_cache_destroy(iommu_devinfo_cache);
kmem_cache_destroy(iommu_domain_cache);
- kmem_cache_destroy(iommu_iova_cache);
-
+ iommu_iova_cache_destroy();
}
static void quirk_ioat_snb_local_iommu(struct pci_dev *pdev)
@@ -4342,7 +4318,8 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
{
int adjust_width;
- init_iova_domain(&domain->iovad, DMA_32BIT_PFN);
+ init_iova_domain(&domain->iovad, VTD_PAGE_SIZE, IOVA_START_PFN,
+ DMA_32BIT_PFN);
domain_reserve_special_ranges(domain);
/* calculate AGAW */
diff --git a/drivers/iommu/intel_irq_remapping.c b/drivers/iommu/intel_irq_remapping.c
index a55b207b9425..14de1ab223c8 100644
--- a/drivers/iommu/intel_irq_remapping.c
+++ b/drivers/iommu/intel_irq_remapping.c
@@ -32,8 +32,9 @@ struct hpet_scope {
};
#define IR_X2APIC_MODE(mode) (mode ? (1 << 11) : 0)
-#define IRTE_DEST(dest) ((x2apic_mode) ? dest : dest << 8)
+#define IRTE_DEST(dest) ((eim_mode) ? dest : dest << 8)
+static int __read_mostly eim_mode;
static struct ioapic_scope ir_ioapic[MAX_IO_APICS];
static struct hpet_scope ir_hpet[MAX_HPET_TBS];
@@ -481,11 +482,11 @@ static int intel_setup_irq_remapping(struct intel_iommu *iommu)
if (iommu->ir_table)
return 0;
- ir_table = kzalloc(sizeof(struct ir_table), GFP_ATOMIC);
+ ir_table = kzalloc(sizeof(struct ir_table), GFP_KERNEL);
if (!ir_table)
return -ENOMEM;
- pages = alloc_pages_node(iommu->node, GFP_ATOMIC | __GFP_ZERO,
+ pages = alloc_pages_node(iommu->node, GFP_KERNEL | __GFP_ZERO,
INTR_REMAP_PAGE_ORDER);
if (!pages) {
@@ -566,13 +567,27 @@ static int __init dmar_x2apic_optout(void)
return dmar->flags & DMAR_X2APIC_OPT_OUT;
}
-static int __init intel_irq_remapping_supported(void)
+static void __init intel_cleanup_irq_remapping(void)
+{
+ struct dmar_drhd_unit *drhd;
+ struct intel_iommu *iommu;
+
+ for_each_iommu(iommu, drhd) {
+ if (ecap_ir_support(iommu->ecap)) {
+ iommu_disable_irq_remapping(iommu);
+ intel_teardown_irq_remapping(iommu);
+ }
+ }
+
+ if (x2apic_supported())
+ pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
+}
+
+static int __init intel_prepare_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
- if (disable_irq_remap)
- return 0;
if (irq_remap_broken) {
printk(KERN_WARNING
"This system BIOS has enabled interrupt remapping\n"
@@ -581,38 +596,45 @@ static int __init intel_irq_remapping_supported(void)
"interrupt remapping is being disabled. Please\n"
"contact your BIOS vendor for an update\n");
add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
- disable_irq_remap = 1;
- return 0;
+ return -ENODEV;
}
+ if (dmar_table_init() < 0)
+ return -ENODEV;
+
if (!dmar_ir_support())
- return 0;
+ return -ENODEV;
+
+ if (parse_ioapics_under_ir() != 1) {
+ printk(KERN_INFO "Not enabling interrupt remapping\n");
+ goto error;
+ }
+ /* First make sure all IOMMUs support IRQ remapping */
for_each_iommu(iommu, drhd)
if (!ecap_ir_support(iommu->ecap))
- return 0;
+ goto error;
- return 1;
+ /* Do the allocations early */
+ for_each_iommu(iommu, drhd)
+ if (intel_setup_irq_remapping(iommu))
+ goto error;
+
+ return 0;
+
+error:
+ intel_cleanup_irq_remapping();
+ return -ENODEV;
}
static int __init intel_enable_irq_remapping(void)
{
struct dmar_drhd_unit *drhd;
struct intel_iommu *iommu;
- bool x2apic_present;
int setup = 0;
int eim = 0;
- x2apic_present = x2apic_supported();
-
- if (parse_ioapics_under_ir() != 1) {
- printk(KERN_INFO "Not enable interrupt remapping\n");
- goto error;
- }
-
- if (x2apic_present) {
- pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
-
+ if (x2apic_supported()) {
eim = !dmar_x2apic_optout();
if (!eim)
printk(KERN_WARNING
@@ -646,16 +668,15 @@ static int __init intel_enable_irq_remapping(void)
/*
* check for the Interrupt-remapping support
*/
- for_each_iommu(iommu, drhd) {
- if (!ecap_ir_support(iommu->ecap))
- continue;
-
+ for_each_iommu(iommu, drhd)
if (eim && !ecap_eim_support(iommu->ecap)) {
printk(KERN_INFO "DRHD %Lx: EIM not supported by DRHD, "
" ecap %Lx\n", drhd->reg_base_addr, iommu->ecap);
- goto error;
+ eim = 0;
}
- }
+ eim_mode = eim;
+ if (eim)
+ pr_info("Queued invalidation will be enabled to support x2apic and Intr-remapping.\n");
/*
* Enable queued invalidation for all the DRHD's.
@@ -675,12 +696,6 @@ static int __init intel_enable_irq_remapping(void)
* Setup Interrupt-remapping for all the DRHD's now.
*/
for_each_iommu(iommu, drhd) {
- if (!ecap_ir_support(iommu->ecap))
- continue;
-
- if (intel_setup_irq_remapping(iommu))
- goto error;
-
iommu_set_irq_remapping(iommu, eim);
setup = 1;
}
@@ -702,15 +717,7 @@ static int __init intel_enable_irq_remapping(void)
return eim ? IRQ_REMAP_X2APIC_MODE : IRQ_REMAP_XAPIC_MODE;
error:
- for_each_iommu(iommu, drhd)
- if (ecap_ir_support(iommu->ecap)) {
- iommu_disable_irq_remapping(iommu);
- intel_teardown_irq_remapping(iommu);
- }
-
- if (x2apic_present)
- pr_warn("Failed to enable irq remapping. You are vulnerable to irq-injection attacks.\n");
-
+ intel_cleanup_irq_remapping();
return -1;
}
@@ -1199,8 +1206,7 @@ static int intel_alloc_hpet_msi(unsigned int irq, unsigned int id)
}
struct irq_remap_ops intel_irq_remap_ops = {
- .supported = intel_irq_remapping_supported,
- .prepare = dmar_table_init,
+ .prepare = intel_prepare_irq_remapping,
.enable = intel_enable_irq_remapping,
.disable = disable_irq_remapping,
.reenable = reenable_irq_remapping,
diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c
new file mode 100644
index 000000000000..5a500edf00cc
--- /dev/null
+++ b/drivers/iommu/io-pgtable-arm.c
@@ -0,0 +1,986 @@
+/*
+ * CPU-agnostic ARM page table allocator.
+ *
+ * This program is free software; you can 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/>.
+ *
+ * Copyright (C) 2014 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#define pr_fmt(fmt) "arm-lpae io-pgtable: " fmt
+
+#include <linux/iommu.h>
+#include <linux/kernel.h>
+#include <linux/sizes.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "io-pgtable.h"
+
+#define ARM_LPAE_MAX_ADDR_BITS 48
+#define ARM_LPAE_S2_MAX_CONCAT_PAGES 16
+#define ARM_LPAE_MAX_LEVELS 4
+
+/* Struct accessors */
+#define io_pgtable_to_data(x) \
+ container_of((x), struct arm_lpae_io_pgtable, iop)
+
+#define io_pgtable_ops_to_pgtable(x) \
+ container_of((x), struct io_pgtable, ops)
+
+#define io_pgtable_ops_to_data(x) \
+ io_pgtable_to_data(io_pgtable_ops_to_pgtable(x))
+
+/*
+ * For consistency with the architecture, we always consider
+ * ARM_LPAE_MAX_LEVELS levels, with the walk starting at level n >=0
+ */
+#define ARM_LPAE_START_LVL(d) (ARM_LPAE_MAX_LEVELS - (d)->levels)
+
+/*
+ * Calculate the right shift amount to get to the portion describing level l
+ * in a virtual address mapped by the pagetable in d.
+ */
+#define ARM_LPAE_LVL_SHIFT(l,d) \
+ ((((d)->levels - ((l) - ARM_LPAE_START_LVL(d) + 1)) \
+ * (d)->bits_per_level) + (d)->pg_shift)
+
+#define ARM_LPAE_PAGES_PER_PGD(d) ((d)->pgd_size >> (d)->pg_shift)
+
+/*
+ * Calculate the index at level l used to map virtual address a using the
+ * pagetable in d.
+ */
+#define ARM_LPAE_PGD_IDX(l,d) \
+ ((l) == ARM_LPAE_START_LVL(d) ? ilog2(ARM_LPAE_PAGES_PER_PGD(d)) : 0)
+
+#define ARM_LPAE_LVL_IDX(a,l,d) \
+ (((a) >> ARM_LPAE_LVL_SHIFT(l,d)) & \
+ ((1 << ((d)->bits_per_level + ARM_LPAE_PGD_IDX(l,d))) - 1))
+
+/* Calculate the block/page mapping size at level l for pagetable in d. */
+#define ARM_LPAE_BLOCK_SIZE(l,d) \
+ (1 << (ilog2(sizeof(arm_lpae_iopte)) + \
+ ((ARM_LPAE_MAX_LEVELS - (l)) * (d)->bits_per_level)))
+
+/* Page table bits */
+#define ARM_LPAE_PTE_TYPE_SHIFT 0
+#define ARM_LPAE_PTE_TYPE_MASK 0x3
+
+#define ARM_LPAE_PTE_TYPE_BLOCK 1
+#define ARM_LPAE_PTE_TYPE_TABLE 3
+#define ARM_LPAE_PTE_TYPE_PAGE 3
+
+#define ARM_LPAE_PTE_NSTABLE (((arm_lpae_iopte)1) << 63)
+#define ARM_LPAE_PTE_XN (((arm_lpae_iopte)3) << 53)
+#define ARM_LPAE_PTE_AF (((arm_lpae_iopte)1) << 10)
+#define ARM_LPAE_PTE_SH_NS (((arm_lpae_iopte)0) << 8)
+#define ARM_LPAE_PTE_SH_OS (((arm_lpae_iopte)2) << 8)
+#define ARM_LPAE_PTE_SH_IS (((arm_lpae_iopte)3) << 8)
+#define ARM_LPAE_PTE_NS (((arm_lpae_iopte)1) << 5)
+#define ARM_LPAE_PTE_VALID (((arm_lpae_iopte)1) << 0)
+
+#define ARM_LPAE_PTE_ATTR_LO_MASK (((arm_lpae_iopte)0x3ff) << 2)
+/* Ignore the contiguous bit for block splitting */
+#define ARM_LPAE_PTE_ATTR_HI_MASK (((arm_lpae_iopte)6) << 52)
+#define ARM_LPAE_PTE_ATTR_MASK (ARM_LPAE_PTE_ATTR_LO_MASK | \
+ ARM_LPAE_PTE_ATTR_HI_MASK)
+
+/* Stage-1 PTE */
+#define ARM_LPAE_PTE_AP_UNPRIV (((arm_lpae_iopte)1) << 6)
+#define ARM_LPAE_PTE_AP_RDONLY (((arm_lpae_iopte)2) << 6)
+#define ARM_LPAE_PTE_ATTRINDX_SHIFT 2
+#define ARM_LPAE_PTE_nG (((arm_lpae_iopte)1) << 11)
+
+/* Stage-2 PTE */
+#define ARM_LPAE_PTE_HAP_FAULT (((arm_lpae_iopte)0) << 6)
+#define ARM_LPAE_PTE_HAP_READ (((arm_lpae_iopte)1) << 6)
+#define ARM_LPAE_PTE_HAP_WRITE (((arm_lpae_iopte)2) << 6)
+#define ARM_LPAE_PTE_MEMATTR_OIWB (((arm_lpae_iopte)0xf) << 2)
+#define ARM_LPAE_PTE_MEMATTR_NC (((arm_lpae_iopte)0x5) << 2)
+#define ARM_LPAE_PTE_MEMATTR_DEV (((arm_lpae_iopte)0x1) << 2)
+
+/* Register bits */
+#define ARM_32_LPAE_TCR_EAE (1 << 31)
+#define ARM_64_LPAE_S2_TCR_RES1 (1 << 31)
+
+#define ARM_LPAE_TCR_TG0_4K (0 << 14)
+#define ARM_LPAE_TCR_TG0_64K (1 << 14)
+#define ARM_LPAE_TCR_TG0_16K (2 << 14)
+
+#define ARM_LPAE_TCR_SH0_SHIFT 12
+#define ARM_LPAE_TCR_SH0_MASK 0x3
+#define ARM_LPAE_TCR_SH_NS 0
+#define ARM_LPAE_TCR_SH_OS 2
+#define ARM_LPAE_TCR_SH_IS 3
+
+#define ARM_LPAE_TCR_ORGN0_SHIFT 10
+#define ARM_LPAE_TCR_IRGN0_SHIFT 8
+#define ARM_LPAE_TCR_RGN_MASK 0x3
+#define ARM_LPAE_TCR_RGN_NC 0
+#define ARM_LPAE_TCR_RGN_WBWA 1
+#define ARM_LPAE_TCR_RGN_WT 2
+#define ARM_LPAE_TCR_RGN_WB 3
+
+#define ARM_LPAE_TCR_SL0_SHIFT 6
+#define ARM_LPAE_TCR_SL0_MASK 0x3
+
+#define ARM_LPAE_TCR_T0SZ_SHIFT 0
+#define ARM_LPAE_TCR_SZ_MASK 0xf
+
+#define ARM_LPAE_TCR_PS_SHIFT 16
+#define ARM_LPAE_TCR_PS_MASK 0x7
+
+#define ARM_LPAE_TCR_IPS_SHIFT 32
+#define ARM_LPAE_TCR_IPS_MASK 0x7
+
+#define ARM_LPAE_TCR_PS_32_BIT 0x0ULL
+#define ARM_LPAE_TCR_PS_36_BIT 0x1ULL
+#define ARM_LPAE_TCR_PS_40_BIT 0x2ULL
+#define ARM_LPAE_TCR_PS_42_BIT 0x3ULL
+#define ARM_LPAE_TCR_PS_44_BIT 0x4ULL
+#define ARM_LPAE_TCR_PS_48_BIT 0x5ULL
+
+#define ARM_LPAE_MAIR_ATTR_SHIFT(n) ((n) << 3)
+#define ARM_LPAE_MAIR_ATTR_MASK 0xff
+#define ARM_LPAE_MAIR_ATTR_DEVICE 0x04
+#define ARM_LPAE_MAIR_ATTR_NC 0x44
+#define ARM_LPAE_MAIR_ATTR_WBRWA 0xff
+#define ARM_LPAE_MAIR_ATTR_IDX_NC 0
+#define ARM_LPAE_MAIR_ATTR_IDX_CACHE 1
+#define ARM_LPAE_MAIR_ATTR_IDX_DEV 2
+
+/* IOPTE accessors */
+#define iopte_deref(pte,d) \
+ (__va((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1) \
+ & ~((1ULL << (d)->pg_shift) - 1)))
+
+#define iopte_type(pte,l) \
+ (((pte) >> ARM_LPAE_PTE_TYPE_SHIFT) & ARM_LPAE_PTE_TYPE_MASK)
+
+#define iopte_prot(pte) ((pte) & ARM_LPAE_PTE_ATTR_MASK)
+
+#define iopte_leaf(pte,l) \
+ (l == (ARM_LPAE_MAX_LEVELS - 1) ? \
+ (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_PAGE) : \
+ (iopte_type(pte,l) == ARM_LPAE_PTE_TYPE_BLOCK))
+
+#define iopte_to_pfn(pte,d) \
+ (((pte) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1)) >> (d)->pg_shift)
+
+#define pfn_to_iopte(pfn,d) \
+ (((pfn) << (d)->pg_shift) & ((1ULL << ARM_LPAE_MAX_ADDR_BITS) - 1))
+
+struct arm_lpae_io_pgtable {
+ struct io_pgtable iop;
+
+ int levels;
+ size_t pgd_size;
+ unsigned long pg_shift;
+ unsigned long bits_per_level;
+
+ void *pgd;
+};
+
+typedef u64 arm_lpae_iopte;
+
+static bool selftest_running = false;
+
+static int arm_lpae_init_pte(struct arm_lpae_io_pgtable *data,
+ unsigned long iova, phys_addr_t paddr,
+ arm_lpae_iopte prot, int lvl,
+ arm_lpae_iopte *ptep)
+{
+ arm_lpae_iopte pte = prot;
+
+ /* We require an unmap first */
+ if (iopte_leaf(*ptep, lvl)) {
+ WARN_ON(!selftest_running);
+ return -EEXIST;
+ }
+
+ if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS)
+ pte |= ARM_LPAE_PTE_NS;
+
+ if (lvl == ARM_LPAE_MAX_LEVELS - 1)
+ pte |= ARM_LPAE_PTE_TYPE_PAGE;
+ else
+ pte |= ARM_LPAE_PTE_TYPE_BLOCK;
+
+ pte |= ARM_LPAE_PTE_AF | ARM_LPAE_PTE_SH_IS;
+ pte |= pfn_to_iopte(paddr >> data->pg_shift, data);
+
+ *ptep = pte;
+ data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), data->iop.cookie);
+ return 0;
+}
+
+static int __arm_lpae_map(struct arm_lpae_io_pgtable *data, unsigned long iova,
+ phys_addr_t paddr, size_t size, arm_lpae_iopte prot,
+ int lvl, arm_lpae_iopte *ptep)
+{
+ arm_lpae_iopte *cptep, pte;
+ void *cookie = data->iop.cookie;
+ size_t block_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
+
+ /* Find our entry at the current level */
+ ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);
+
+ /* If we can install a leaf entry at this level, then do so */
+ if (size == block_size && (size & data->iop.cfg.pgsize_bitmap))
+ return arm_lpae_init_pte(data, iova, paddr, prot, lvl, ptep);
+
+ /* We can't allocate tables at the final level */
+ if (WARN_ON(lvl >= ARM_LPAE_MAX_LEVELS - 1))
+ return -EINVAL;
+
+ /* Grab a pointer to the next level */
+ pte = *ptep;
+ if (!pte) {
+ cptep = alloc_pages_exact(1UL << data->pg_shift,
+ GFP_ATOMIC | __GFP_ZERO);
+ if (!cptep)
+ return -ENOMEM;
+
+ data->iop.cfg.tlb->flush_pgtable(cptep, 1UL << data->pg_shift,
+ cookie);
+ pte = __pa(cptep) | ARM_LPAE_PTE_TYPE_TABLE;
+ if (data->iop.cfg.quirks & IO_PGTABLE_QUIRK_ARM_NS)
+ pte |= ARM_LPAE_PTE_NSTABLE;
+ *ptep = pte;
+ data->iop.cfg.tlb->flush_pgtable(ptep, sizeof(*ptep), cookie);
+ } else {
+ cptep = iopte_deref(pte, data);
+ }
+
+ /* Rinse, repeat */
+ return __arm_lpae_map(data, iova, paddr, size, prot, lvl + 1, cptep);
+}
+
+static arm_lpae_iopte arm_lpae_prot_to_pte(struct arm_lpae_io_pgtable *data,
+ int prot)
+{
+ arm_lpae_iopte pte;
+
+ if (data->iop.fmt == ARM_64_LPAE_S1 ||
+ data->iop.fmt == ARM_32_LPAE_S1) {
+ pte = ARM_LPAE_PTE_AP_UNPRIV | ARM_LPAE_PTE_nG;
+
+ if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ))
+ pte |= ARM_LPAE_PTE_AP_RDONLY;
+
+ if (prot & IOMMU_CACHE)
+ pte |= (ARM_LPAE_MAIR_ATTR_IDX_CACHE
+ << ARM_LPAE_PTE_ATTRINDX_SHIFT);
+ } else {
+ pte = ARM_LPAE_PTE_HAP_FAULT;
+ if (prot & IOMMU_READ)
+ pte |= ARM_LPAE_PTE_HAP_READ;
+ if (prot & IOMMU_WRITE)
+ pte |= ARM_LPAE_PTE_HAP_WRITE;
+ if (prot & IOMMU_CACHE)
+ pte |= ARM_LPAE_PTE_MEMATTR_OIWB;
+ else
+ pte |= ARM_LPAE_PTE_MEMATTR_NC;
+ }
+
+ if (prot & IOMMU_NOEXEC)
+ pte |= ARM_LPAE_PTE_XN;
+
+ return pte;
+}
+
+static int arm_lpae_map(struct io_pgtable_ops *ops, unsigned long iova,
+ phys_addr_t paddr, size_t size, int iommu_prot)
+{
+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+ arm_lpae_iopte *ptep = data->pgd;
+ int lvl = ARM_LPAE_START_LVL(data);
+ arm_lpae_iopte prot;
+
+ /* If no access, then nothing to do */
+ if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
+ return 0;
+
+ prot = arm_lpae_prot_to_pte(data, iommu_prot);
+ return __arm_lpae_map(data, iova, paddr, size, prot, lvl, ptep);
+}
+
+static void __arm_lpae_free_pgtable(struct arm_lpae_io_pgtable *data, int lvl,
+ arm_lpae_iopte *ptep)
+{
+ arm_lpae_iopte *start, *end;
+ unsigned long table_size;
+
+ /* Only leaf entries at the last level */
+ if (lvl == ARM_LPAE_MAX_LEVELS - 1)
+ return;
+
+ if (lvl == ARM_LPAE_START_LVL(data))
+ table_size = data->pgd_size;
+ else
+ table_size = 1UL << data->pg_shift;
+
+ start = ptep;
+ end = (void *)ptep + table_size;
+
+ while (ptep != end) {
+ arm_lpae_iopte pte = *ptep++;
+
+ if (!pte || iopte_leaf(pte, lvl))
+ continue;
+
+ __arm_lpae_free_pgtable(data, lvl + 1, iopte_deref(pte, data));
+ }
+
+ free_pages_exact(start, table_size);
+}
+
+static void arm_lpae_free_pgtable(struct io_pgtable *iop)
+{
+ struct arm_lpae_io_pgtable *data = io_pgtable_to_data(iop);
+
+ __arm_lpae_free_pgtable(data, ARM_LPAE_START_LVL(data), data->pgd);
+ kfree(data);
+}
+
+static int arm_lpae_split_blk_unmap(struct arm_lpae_io_pgtable *data,
+ unsigned long iova, size_t size,
+ arm_lpae_iopte prot, int lvl,
+ arm_lpae_iopte *ptep, size_t blk_size)
+{
+ unsigned long blk_start, blk_end;
+ phys_addr_t blk_paddr;
+ arm_lpae_iopte table = 0;
+ void *cookie = data->iop.cookie;
+ const struct iommu_gather_ops *tlb = data->iop.cfg.tlb;
+
+ blk_start = iova & ~(blk_size - 1);
+ blk_end = blk_start + blk_size;
+ blk_paddr = iopte_to_pfn(*ptep, data) << data->pg_shift;
+
+ for (; blk_start < blk_end; blk_start += size, blk_paddr += size) {
+ arm_lpae_iopte *tablep;
+
+ /* Unmap! */
+ if (blk_start == iova)
+ continue;
+
+ /* __arm_lpae_map expects a pointer to the start of the table */
+ tablep = &table - ARM_LPAE_LVL_IDX(blk_start, lvl, data);
+ if (__arm_lpae_map(data, blk_start, blk_paddr, size, prot, lvl,
+ tablep) < 0) {
+ if (table) {
+ /* Free the table we allocated */
+ tablep = iopte_deref(table, data);
+ __arm_lpae_free_pgtable(data, lvl + 1, tablep);
+ }
+ return 0; /* Bytes unmapped */
+ }
+ }
+
+ *ptep = table;
+ tlb->flush_pgtable(ptep, sizeof(*ptep), cookie);
+ iova &= ~(blk_size - 1);
+ tlb->tlb_add_flush(iova, blk_size, true, cookie);
+ return size;
+}
+
+static int __arm_lpae_unmap(struct arm_lpae_io_pgtable *data,
+ unsigned long iova, size_t size, int lvl,
+ arm_lpae_iopte *ptep)
+{
+ arm_lpae_iopte pte;
+ const struct iommu_gather_ops *tlb = data->iop.cfg.tlb;
+ void *cookie = data->iop.cookie;
+ size_t blk_size = ARM_LPAE_BLOCK_SIZE(lvl, data);
+
+ ptep += ARM_LPAE_LVL_IDX(iova, lvl, data);
+ pte = *ptep;
+
+ /* Something went horribly wrong and we ran out of page table */
+ if (WARN_ON(!pte || (lvl == ARM_LPAE_MAX_LEVELS)))
+ return 0;
+
+ /* If the size matches this level, we're in the right place */
+ if (size == blk_size) {
+ *ptep = 0;
+ tlb->flush_pgtable(ptep, sizeof(*ptep), cookie);
+
+ if (!iopte_leaf(pte, lvl)) {
+ /* Also flush any partial walks */
+ tlb->tlb_add_flush(iova, size, false, cookie);
+ tlb->tlb_sync(data->iop.cookie);
+ ptep = iopte_deref(pte, data);
+ __arm_lpae_free_pgtable(data, lvl + 1, ptep);
+ } else {
+ tlb->tlb_add_flush(iova, size, true, cookie);
+ }
+
+ return size;
+ } else if (iopte_leaf(pte, lvl)) {
+ /*
+ * Insert a table at the next level to map the old region,
+ * minus the part we want to unmap
+ */
+ return arm_lpae_split_blk_unmap(data, iova, size,
+ iopte_prot(pte), lvl, ptep,
+ blk_size);
+ }
+
+ /* Keep on walkin' */
+ ptep = iopte_deref(pte, data);
+ return __arm_lpae_unmap(data, iova, size, lvl + 1, ptep);
+}
+
+static int arm_lpae_unmap(struct io_pgtable_ops *ops, unsigned long iova,
+ size_t size)
+{
+ size_t unmapped;
+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+ struct io_pgtable *iop = &data->iop;
+ arm_lpae_iopte *ptep = data->pgd;
+ int lvl = ARM_LPAE_START_LVL(data);
+
+ unmapped = __arm_lpae_unmap(data, iova, size, lvl, ptep);
+ if (unmapped)
+ iop->cfg.tlb->tlb_sync(iop->cookie);
+
+ return unmapped;
+}
+
+static phys_addr_t arm_lpae_iova_to_phys(struct io_pgtable_ops *ops,
+ unsigned long iova)
+{
+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+ arm_lpae_iopte pte, *ptep = data->pgd;
+ int lvl = ARM_LPAE_START_LVL(data);
+
+ do {
+ /* Valid IOPTE pointer? */
+ if (!ptep)
+ return 0;
+
+ /* Grab the IOPTE we're interested in */
+ pte = *(ptep + ARM_LPAE_LVL_IDX(iova, lvl, data));
+
+ /* Valid entry? */
+ if (!pte)
+ return 0;
+
+ /* Leaf entry? */
+ if (iopte_leaf(pte,lvl))
+ goto found_translation;
+
+ /* Take it to the next level */
+ ptep = iopte_deref(pte, data);
+ } while (++lvl < ARM_LPAE_MAX_LEVELS);
+
+ /* Ran out of page tables to walk */
+ return 0;
+
+found_translation:
+ iova &= ((1 << data->pg_shift) - 1);
+ return ((phys_addr_t)iopte_to_pfn(pte,data) << data->pg_shift) | iova;
+}
+
+static void arm_lpae_restrict_pgsizes(struct io_pgtable_cfg *cfg)
+{
+ unsigned long granule;
+
+ /*
+ * We need to restrict the supported page sizes to match the
+ * translation regime for a particular granule. Aim to match
+ * the CPU page size if possible, otherwise prefer smaller sizes.
+ * While we're at it, restrict the block sizes to match the
+ * chosen granule.
+ */
+ if (cfg->pgsize_bitmap & PAGE_SIZE)
+ granule = PAGE_SIZE;
+ else if (cfg->pgsize_bitmap & ~PAGE_MASK)
+ granule = 1UL << __fls(cfg->pgsize_bitmap & ~PAGE_MASK);
+ else if (cfg->pgsize_bitmap & PAGE_MASK)
+ granule = 1UL << __ffs(cfg->pgsize_bitmap & PAGE_MASK);
+ else
+ granule = 0;
+
+ switch (granule) {
+ case SZ_4K:
+ cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
+ break;
+ case SZ_16K:
+ cfg->pgsize_bitmap &= (SZ_16K | SZ_32M);
+ break;
+ case SZ_64K:
+ cfg->pgsize_bitmap &= (SZ_64K | SZ_512M);
+ break;
+ default:
+ cfg->pgsize_bitmap = 0;
+ }
+}
+
+static struct arm_lpae_io_pgtable *
+arm_lpae_alloc_pgtable(struct io_pgtable_cfg *cfg)
+{
+ unsigned long va_bits, pgd_bits;
+ struct arm_lpae_io_pgtable *data;
+
+ arm_lpae_restrict_pgsizes(cfg);
+
+ if (!(cfg->pgsize_bitmap & (SZ_4K | SZ_16K | SZ_64K)))
+ return NULL;
+
+ if (cfg->ias > ARM_LPAE_MAX_ADDR_BITS)
+ return NULL;
+
+ if (cfg->oas > ARM_LPAE_MAX_ADDR_BITS)
+ return NULL;
+
+ data = kmalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ return NULL;
+
+ data->pg_shift = __ffs(cfg->pgsize_bitmap);
+ data->bits_per_level = data->pg_shift - ilog2(sizeof(arm_lpae_iopte));
+
+ va_bits = cfg->ias - data->pg_shift;
+ data->levels = DIV_ROUND_UP(va_bits, data->bits_per_level);
+
+ /* Calculate the actual size of our pgd (without concatenation) */
+ pgd_bits = va_bits - (data->bits_per_level * (data->levels - 1));
+ data->pgd_size = 1UL << (pgd_bits + ilog2(sizeof(arm_lpae_iopte)));
+
+ data->iop.ops = (struct io_pgtable_ops) {
+ .map = arm_lpae_map,
+ .unmap = arm_lpae_unmap,
+ .iova_to_phys = arm_lpae_iova_to_phys,
+ };
+
+ return data;
+}
+
+static struct io_pgtable *
+arm_64_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
+{
+ u64 reg;
+ struct arm_lpae_io_pgtable *data = arm_lpae_alloc_pgtable(cfg);
+
+ if (!data)
+ return NULL;
+
+ /* TCR */
+ reg = (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+
+ switch (1 << data->pg_shift) {
+ case SZ_4K:
+ reg |= ARM_LPAE_TCR_TG0_4K;
+ break;
+ case SZ_16K:
+ reg |= ARM_LPAE_TCR_TG0_16K;
+ break;
+ case SZ_64K:
+ reg |= ARM_LPAE_TCR_TG0_64K;
+ break;
+ }
+
+ switch (cfg->oas) {
+ case 32:
+ reg |= (ARM_LPAE_TCR_PS_32_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ break;
+ case 36:
+ reg |= (ARM_LPAE_TCR_PS_36_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ break;
+ case 40:
+ reg |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ break;
+ case 42:
+ reg |= (ARM_LPAE_TCR_PS_42_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ break;
+ case 44:
+ reg |= (ARM_LPAE_TCR_PS_44_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ break;
+ case 48:
+ reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_IPS_SHIFT);
+ break;
+ default:
+ goto out_free_data;
+ }
+
+ reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT;
+ cfg->arm_lpae_s1_cfg.tcr = reg;
+
+ /* MAIRs */
+ reg = (ARM_LPAE_MAIR_ATTR_NC
+ << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_NC)) |
+ (ARM_LPAE_MAIR_ATTR_WBRWA
+ << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_CACHE)) |
+ (ARM_LPAE_MAIR_ATTR_DEVICE
+ << ARM_LPAE_MAIR_ATTR_SHIFT(ARM_LPAE_MAIR_ATTR_IDX_DEV));
+
+ cfg->arm_lpae_s1_cfg.mair[0] = reg;
+ cfg->arm_lpae_s1_cfg.mair[1] = 0;
+
+ /* Looking good; allocate a pgd */
+ data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO);
+ if (!data->pgd)
+ goto out_free_data;
+
+ cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie);
+
+ /* TTBRs */
+ cfg->arm_lpae_s1_cfg.ttbr[0] = virt_to_phys(data->pgd);
+ cfg->arm_lpae_s1_cfg.ttbr[1] = 0;
+ return &data->iop;
+
+out_free_data:
+ kfree(data);
+ return NULL;
+}
+
+static struct io_pgtable *
+arm_64_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
+{
+ u64 reg, sl;
+ struct arm_lpae_io_pgtable *data = arm_lpae_alloc_pgtable(cfg);
+
+ if (!data)
+ return NULL;
+
+ /*
+ * Concatenate PGDs at level 1 if possible in order to reduce
+ * the depth of the stage-2 walk.
+ */
+ if (data->levels == ARM_LPAE_MAX_LEVELS) {
+ unsigned long pgd_pages;
+
+ pgd_pages = data->pgd_size >> ilog2(sizeof(arm_lpae_iopte));
+ if (pgd_pages <= ARM_LPAE_S2_MAX_CONCAT_PAGES) {
+ data->pgd_size = pgd_pages << data->pg_shift;
+ data->levels--;
+ }
+ }
+
+ /* VTCR */
+ reg = ARM_64_LPAE_S2_TCR_RES1 |
+ (ARM_LPAE_TCR_SH_IS << ARM_LPAE_TCR_SH0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_IRGN0_SHIFT) |
+ (ARM_LPAE_TCR_RGN_WBWA << ARM_LPAE_TCR_ORGN0_SHIFT);
+
+ sl = ARM_LPAE_START_LVL(data);
+
+ switch (1 << data->pg_shift) {
+ case SZ_4K:
+ reg |= ARM_LPAE_TCR_TG0_4K;
+ sl++; /* SL0 format is different for 4K granule size */
+ break;
+ case SZ_16K:
+ reg |= ARM_LPAE_TCR_TG0_16K;
+ break;
+ case SZ_64K:
+ reg |= ARM_LPAE_TCR_TG0_64K;
+ break;
+ }
+
+ switch (cfg->oas) {
+ case 32:
+ reg |= (ARM_LPAE_TCR_PS_32_BIT << ARM_LPAE_TCR_PS_SHIFT);
+ break;
+ case 36:
+ reg |= (ARM_LPAE_TCR_PS_36_BIT << ARM_LPAE_TCR_PS_SHIFT);
+ break;
+ case 40:
+ reg |= (ARM_LPAE_TCR_PS_40_BIT << ARM_LPAE_TCR_PS_SHIFT);
+ break;
+ case 42:
+ reg |= (ARM_LPAE_TCR_PS_42_BIT << ARM_LPAE_TCR_PS_SHIFT);
+ break;
+ case 44:
+ reg |= (ARM_LPAE_TCR_PS_44_BIT << ARM_LPAE_TCR_PS_SHIFT);
+ break;
+ case 48:
+ reg |= (ARM_LPAE_TCR_PS_48_BIT << ARM_LPAE_TCR_PS_SHIFT);
+ break;
+ default:
+ goto out_free_data;
+ }
+
+ reg |= (64ULL - cfg->ias) << ARM_LPAE_TCR_T0SZ_SHIFT;
+ reg |= (~sl & ARM_LPAE_TCR_SL0_MASK) << ARM_LPAE_TCR_SL0_SHIFT;
+ cfg->arm_lpae_s2_cfg.vtcr = reg;
+
+ /* Allocate pgd pages */
+ data->pgd = alloc_pages_exact(data->pgd_size, GFP_KERNEL | __GFP_ZERO);
+ if (!data->pgd)
+ goto out_free_data;
+
+ cfg->tlb->flush_pgtable(data->pgd, data->pgd_size, cookie);
+
+ /* VTTBR */
+ cfg->arm_lpae_s2_cfg.vttbr = virt_to_phys(data->pgd);
+ return &data->iop;
+
+out_free_data:
+ kfree(data);
+ return NULL;
+}
+
+static struct io_pgtable *
+arm_32_lpae_alloc_pgtable_s1(struct io_pgtable_cfg *cfg, void *cookie)
+{
+ struct io_pgtable *iop;
+
+ if (cfg->ias > 32 || cfg->oas > 40)
+ return NULL;
+
+ cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
+ iop = arm_64_lpae_alloc_pgtable_s1(cfg, cookie);
+ if (iop) {
+ cfg->arm_lpae_s1_cfg.tcr |= ARM_32_LPAE_TCR_EAE;
+ cfg->arm_lpae_s1_cfg.tcr &= 0xffffffff;
+ }
+
+ return iop;
+}
+
+static struct io_pgtable *
+arm_32_lpae_alloc_pgtable_s2(struct io_pgtable_cfg *cfg, void *cookie)
+{
+ struct io_pgtable *iop;
+
+ if (cfg->ias > 40 || cfg->oas > 40)
+ return NULL;
+
+ cfg->pgsize_bitmap &= (SZ_4K | SZ_2M | SZ_1G);
+ iop = arm_64_lpae_alloc_pgtable_s2(cfg, cookie);
+ if (iop)
+ cfg->arm_lpae_s2_cfg.vtcr &= 0xffffffff;
+
+ return iop;
+}
+
+struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns = {
+ .alloc = arm_64_lpae_alloc_pgtable_s1,
+ .free = arm_lpae_free_pgtable,
+};
+
+struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns = {
+ .alloc = arm_64_lpae_alloc_pgtable_s2,
+ .free = arm_lpae_free_pgtable,
+};
+
+struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns = {
+ .alloc = arm_32_lpae_alloc_pgtable_s1,
+ .free = arm_lpae_free_pgtable,
+};
+
+struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns = {
+ .alloc = arm_32_lpae_alloc_pgtable_s2,
+ .free = arm_lpae_free_pgtable,
+};
+
+#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE_SELFTEST
+
+static struct io_pgtable_cfg *cfg_cookie;
+
+static void dummy_tlb_flush_all(void *cookie)
+{
+ WARN_ON(cookie != cfg_cookie);
+}
+
+static void dummy_tlb_add_flush(unsigned long iova, size_t size, bool leaf,
+ void *cookie)
+{
+ WARN_ON(cookie != cfg_cookie);
+ WARN_ON(!(size & cfg_cookie->pgsize_bitmap));
+}
+
+static void dummy_tlb_sync(void *cookie)
+{
+ WARN_ON(cookie != cfg_cookie);
+}
+
+static void dummy_flush_pgtable(void *ptr, size_t size, void *cookie)
+{
+ WARN_ON(cookie != cfg_cookie);
+}
+
+static struct iommu_gather_ops dummy_tlb_ops __initdata = {
+ .tlb_flush_all = dummy_tlb_flush_all,
+ .tlb_add_flush = dummy_tlb_add_flush,
+ .tlb_sync = dummy_tlb_sync,
+ .flush_pgtable = dummy_flush_pgtable,
+};
+
+static void __init arm_lpae_dump_ops(struct io_pgtable_ops *ops)
+{
+ struct arm_lpae_io_pgtable *data = io_pgtable_ops_to_data(ops);
+ struct io_pgtable_cfg *cfg = &data->iop.cfg;
+
+ pr_err("cfg: pgsize_bitmap 0x%lx, ias %u-bit\n",
+ cfg->pgsize_bitmap, cfg->ias);
+ pr_err("data: %d levels, 0x%zx pgd_size, %lu pg_shift, %lu bits_per_level, pgd @ %p\n",
+ data->levels, data->pgd_size, data->pg_shift,
+ data->bits_per_level, data->pgd);
+}
+
+#define __FAIL(ops, i) ({ \
+ WARN(1, "selftest: test failed for fmt idx %d\n", (i)); \
+ arm_lpae_dump_ops(ops); \
+ selftest_running = false; \
+ -EFAULT; \
+})
+
+static int __init arm_lpae_run_tests(struct io_pgtable_cfg *cfg)
+{
+ static const enum io_pgtable_fmt fmts[] = {
+ ARM_64_LPAE_S1,
+ ARM_64_LPAE_S2,
+ };
+
+ int i, j;
+ unsigned long iova;
+ size_t size;
+ struct io_pgtable_ops *ops;
+
+ selftest_running = true;
+
+ for (i = 0; i < ARRAY_SIZE(fmts); ++i) {
+ cfg_cookie = cfg;
+ ops = alloc_io_pgtable_ops(fmts[i], cfg, cfg);
+ if (!ops) {
+ pr_err("selftest: failed to allocate io pgtable ops\n");
+ return -ENOMEM;
+ }
+
+ /*
+ * Initial sanity checks.
+ * Empty page tables shouldn't provide any translations.
+ */
+ if (ops->iova_to_phys(ops, 42))
+ return __FAIL(ops, i);
+
+ if (ops->iova_to_phys(ops, SZ_1G + 42))
+ return __FAIL(ops, i);
+
+ if (ops->iova_to_phys(ops, SZ_2G + 42))
+ return __FAIL(ops, i);
+
+ /*
+ * Distinct mappings of different granule sizes.
+ */
+ iova = 0;
+ j = find_first_bit(&cfg->pgsize_bitmap, BITS_PER_LONG);
+ while (j != BITS_PER_LONG) {
+ size = 1UL << j;
+
+ if (ops->map(ops, iova, iova, size, IOMMU_READ |
+ IOMMU_WRITE |
+ IOMMU_NOEXEC |
+ IOMMU_CACHE))
+ return __FAIL(ops, i);
+
+ /* Overlapping mappings */
+ if (!ops->map(ops, iova, iova + size, size,
+ IOMMU_READ | IOMMU_NOEXEC))
+ return __FAIL(ops, i);
+
+ if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
+ return __FAIL(ops, i);
+
+ iova += SZ_1G;
+ j++;
+ j = find_next_bit(&cfg->pgsize_bitmap, BITS_PER_LONG, j);
+ }
+
+ /* Partial unmap */
+ size = 1UL << __ffs(cfg->pgsize_bitmap);
+ if (ops->unmap(ops, SZ_1G + size, size) != size)
+ return __FAIL(ops, i);
+
+ /* Remap of partial unmap */
+ if (ops->map(ops, SZ_1G + size, size, size, IOMMU_READ))
+ return __FAIL(ops, i);
+
+ if (ops->iova_to_phys(ops, SZ_1G + size + 42) != (size + 42))
+ return __FAIL(ops, i);
+
+ /* Full unmap */
+ iova = 0;
+ j = find_first_bit(&cfg->pgsize_bitmap, BITS_PER_LONG);
+ while (j != BITS_PER_LONG) {
+ size = 1UL << j;
+
+ if (ops->unmap(ops, iova, size) != size)
+ return __FAIL(ops, i);
+
+ if (ops->iova_to_phys(ops, iova + 42))
+ return __FAIL(ops, i);
+
+ /* Remap full block */
+ if (ops->map(ops, iova, iova, size, IOMMU_WRITE))
+ return __FAIL(ops, i);
+
+ if (ops->iova_to_phys(ops, iova + 42) != (iova + 42))
+ return __FAIL(ops, i);
+
+ iova += SZ_1G;
+ j++;
+ j = find_next_bit(&cfg->pgsize_bitmap, BITS_PER_LONG, j);
+ }
+
+ free_io_pgtable_ops(ops);
+ }
+
+ selftest_running = false;
+ return 0;
+}
+
+static int __init arm_lpae_do_selftests(void)
+{
+ static const unsigned long pgsize[] = {
+ SZ_4K | SZ_2M | SZ_1G,
+ SZ_16K | SZ_32M,
+ SZ_64K | SZ_512M,
+ };
+
+ static const unsigned int ias[] = {
+ 32, 36, 40, 42, 44, 48,
+ };
+
+ int i, j, pass = 0, fail = 0;
+ struct io_pgtable_cfg cfg = {
+ .tlb = &dummy_tlb_ops,
+ .oas = 48,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(pgsize); ++i) {
+ for (j = 0; j < ARRAY_SIZE(ias); ++j) {
+ cfg.pgsize_bitmap = pgsize[i];
+ cfg.ias = ias[j];
+ pr_info("selftest: pgsize_bitmap 0x%08lx, IAS %u\n",
+ pgsize[i], ias[j]);
+ if (arm_lpae_run_tests(&cfg))
+ fail++;
+ else
+ pass++;
+ }
+ }
+
+ pr_info("selftest: completed with %d PASS %d FAIL\n", pass, fail);
+ return fail ? -EFAULT : 0;
+}
+subsys_initcall(arm_lpae_do_selftests);
+#endif
diff --git a/drivers/iommu/io-pgtable.c b/drivers/iommu/io-pgtable.c
new file mode 100644
index 000000000000..6436fe24bc2f
--- /dev/null
+++ b/drivers/iommu/io-pgtable.c
@@ -0,0 +1,82 @@
+/*
+ * Generic page table allocator for IOMMUs.
+ *
+ * This program is free software; you can 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/>.
+ *
+ * Copyright (C) 2014 ARM Limited
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/bug.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+
+#include "io-pgtable.h"
+
+extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s1_init_fns;
+extern struct io_pgtable_init_fns io_pgtable_arm_32_lpae_s2_init_fns;
+extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s1_init_fns;
+extern struct io_pgtable_init_fns io_pgtable_arm_64_lpae_s2_init_fns;
+
+static const struct io_pgtable_init_fns *
+io_pgtable_init_table[IO_PGTABLE_NUM_FMTS] =
+{
+#ifdef CONFIG_IOMMU_IO_PGTABLE_LPAE
+ [ARM_32_LPAE_S1] = &io_pgtable_arm_32_lpae_s1_init_fns,
+ [ARM_32_LPAE_S2] = &io_pgtable_arm_32_lpae_s2_init_fns,
+ [ARM_64_LPAE_S1] = &io_pgtable_arm_64_lpae_s1_init_fns,
+ [ARM_64_LPAE_S2] = &io_pgtable_arm_64_lpae_s2_init_fns,
+#endif
+};
+
+struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
+ struct io_pgtable_cfg *cfg,
+ void *cookie)
+{
+ struct io_pgtable *iop;
+ const struct io_pgtable_init_fns *fns;
+
+ if (fmt >= IO_PGTABLE_NUM_FMTS)
+ return NULL;
+
+ fns = io_pgtable_init_table[fmt];
+ if (!fns)
+ return NULL;
+
+ iop = fns->alloc(cfg, cookie);
+ if (!iop)
+ return NULL;
+
+ iop->fmt = fmt;
+ iop->cookie = cookie;
+ iop->cfg = *cfg;
+
+ return &iop->ops;
+}
+
+/*
+ * It is the IOMMU driver's responsibility to ensure that the page table
+ * is no longer accessible to the walker by this point.
+ */
+void free_io_pgtable_ops(struct io_pgtable_ops *ops)
+{
+ struct io_pgtable *iop;
+
+ if (!ops)
+ return;
+
+ iop = container_of(ops, struct io_pgtable, ops);
+ iop->cfg.tlb->tlb_flush_all(iop->cookie);
+ io_pgtable_init_table[iop->fmt]->free(iop);
+}
diff --git a/drivers/iommu/io-pgtable.h b/drivers/iommu/io-pgtable.h
new file mode 100644
index 000000000000..10e32f69c668
--- /dev/null
+++ b/drivers/iommu/io-pgtable.h
@@ -0,0 +1,143 @@
+#ifndef __IO_PGTABLE_H
+#define __IO_PGTABLE_H
+
+/*
+ * Public API for use by IOMMU drivers
+ */
+enum io_pgtable_fmt {
+ ARM_32_LPAE_S1,
+ ARM_32_LPAE_S2,
+ ARM_64_LPAE_S1,
+ ARM_64_LPAE_S2,
+ IO_PGTABLE_NUM_FMTS,
+};
+
+/**
+ * struct iommu_gather_ops - IOMMU callbacks for TLB and page table management.
+ *
+ * @tlb_flush_all: Synchronously invalidate the entire TLB context.
+ * @tlb_add_flush: Queue up a TLB invalidation for a virtual address range.
+ * @tlb_sync: Ensure any queue TLB invalidation has taken effect.
+ * @flush_pgtable: Ensure page table updates are visible to the IOMMU.
+ *
+ * Note that these can all be called in atomic context and must therefore
+ * not block.
+ */
+struct iommu_gather_ops {
+ void (*tlb_flush_all)(void *cookie);
+ void (*tlb_add_flush)(unsigned long iova, size_t size, bool leaf,
+ void *cookie);
+ void (*tlb_sync)(void *cookie);
+ void (*flush_pgtable)(void *ptr, size_t size, void *cookie);
+};
+
+/**
+ * struct io_pgtable_cfg - Configuration data for a set of page tables.
+ *
+ * @quirks: A bitmap of hardware quirks that require some special
+ * action by the low-level page table allocator.
+ * @pgsize_bitmap: A bitmap of page sizes supported by this set of page
+ * tables.
+ * @ias: Input address (iova) size, in bits.
+ * @oas: Output address (paddr) size, in bits.
+ * @tlb: TLB management callbacks for this set of tables.
+ */
+struct io_pgtable_cfg {
+ #define IO_PGTABLE_QUIRK_ARM_NS (1 << 0) /* Set NS bit in PTEs */
+ int quirks;
+ unsigned long pgsize_bitmap;
+ unsigned int ias;
+ unsigned int oas;
+ const struct iommu_gather_ops *tlb;
+
+ /* Low-level data specific to the table format */
+ union {
+ struct {
+ u64 ttbr[2];
+ u64 tcr;
+ u64 mair[2];
+ } arm_lpae_s1_cfg;
+
+ struct {
+ u64 vttbr;
+ u64 vtcr;
+ } arm_lpae_s2_cfg;
+ };
+};
+
+/**
+ * struct io_pgtable_ops - Page table manipulation API for IOMMU drivers.
+ *
+ * @map: Map a physically contiguous memory region.
+ * @unmap: Unmap a physically contiguous memory region.
+ * @iova_to_phys: Translate iova to physical address.
+ *
+ * These functions map directly onto the iommu_ops member functions with
+ * the same names.
+ */
+struct io_pgtable_ops {
+ int (*map)(struct io_pgtable_ops *ops, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot);
+ int (*unmap)(struct io_pgtable_ops *ops, unsigned long iova,
+ size_t size);
+ phys_addr_t (*iova_to_phys)(struct io_pgtable_ops *ops,
+ unsigned long iova);
+};
+
+/**
+ * alloc_io_pgtable_ops() - Allocate a page table allocator for use by an IOMMU.
+ *
+ * @fmt: The page table format.
+ * @cfg: The page table configuration. This will be modified to represent
+ * the configuration actually provided by the allocator (e.g. the
+ * pgsize_bitmap may be restricted).
+ * @cookie: An opaque token provided by the IOMMU driver and passed back to
+ * the callback routines in cfg->tlb.
+ */
+struct io_pgtable_ops *alloc_io_pgtable_ops(enum io_pgtable_fmt fmt,
+ struct io_pgtable_cfg *cfg,
+ void *cookie);
+
+/**
+ * free_io_pgtable_ops() - Free an io_pgtable_ops structure. The caller
+ * *must* ensure that the page table is no longer
+ * live, but the TLB can be dirty.
+ *
+ * @ops: The ops returned from alloc_io_pgtable_ops.
+ */
+void free_io_pgtable_ops(struct io_pgtable_ops *ops);
+
+
+/*
+ * Internal structures for page table allocator implementations.
+ */
+
+/**
+ * struct io_pgtable - Internal structure describing a set of page tables.
+ *
+ * @fmt: The page table format.
+ * @cookie: An opaque token provided by the IOMMU driver and passed back to
+ * any callback routines.
+ * @cfg: A copy of the page table configuration.
+ * @ops: The page table operations in use for this set of page tables.
+ */
+struct io_pgtable {
+ enum io_pgtable_fmt fmt;
+ void *cookie;
+ struct io_pgtable_cfg cfg;
+ struct io_pgtable_ops ops;
+};
+
+/**
+ * struct io_pgtable_init_fns - Alloc/free a set of page tables for a
+ * particular format.
+ *
+ * @alloc: Allocate a set of page tables described by cfg.
+ * @free: Free the page tables associated with iop.
+ */
+struct io_pgtable_init_fns {
+ struct io_pgtable *(*alloc)(struct io_pgtable_cfg *cfg, void *cookie);
+ void (*free)(struct io_pgtable *iop);
+};
+
+#endif /* __IO_PGTABLE_H */
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index f7718d73e984..72e683df0731 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2007-2008 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.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
@@ -1084,7 +1084,7 @@ int iommu_map(struct iommu_domain *domain, unsigned long iova,
if (ret)
iommu_unmap(domain, orig_iova, orig_size - size);
else
- trace_map(iova, paddr, size);
+ trace_map(orig_iova, paddr, orig_size);
return ret;
}
@@ -1094,6 +1094,7 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
{
size_t unmapped_page, unmapped = 0;
unsigned int min_pagesz;
+ unsigned long orig_iova = iova;
if (unlikely(domain->ops->unmap == NULL ||
domain->ops->pgsize_bitmap == 0UL))
@@ -1133,7 +1134,7 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
unmapped += unmapped_page;
}
- trace_unmap(iova, 0, size);
+ trace_unmap(orig_iova, size, unmapped);
return unmapped;
}
EXPORT_SYMBOL_GPL(iommu_unmap);
diff --git a/drivers/iommu/iova.c b/drivers/iommu/iova.c
index f6b17e6af2fb..9dd8208312c2 100644
--- a/drivers/iommu/iova.c
+++ b/drivers/iommu/iova.c
@@ -18,13 +18,58 @@
*/
#include <linux/iova.h>
+#include <linux/slab.h>
+
+static struct kmem_cache *iommu_iova_cache;
+
+int iommu_iova_cache_init(void)
+{
+ int ret = 0;
+
+ iommu_iova_cache = kmem_cache_create("iommu_iova",
+ sizeof(struct iova),
+ 0,
+ SLAB_HWCACHE_ALIGN,
+ NULL);
+ if (!iommu_iova_cache) {
+ pr_err("Couldn't create iova cache\n");
+ ret = -ENOMEM;
+ }
+
+ return ret;
+}
+
+void iommu_iova_cache_destroy(void)
+{
+ kmem_cache_destroy(iommu_iova_cache);
+}
+
+struct iova *alloc_iova_mem(void)
+{
+ return kmem_cache_alloc(iommu_iova_cache, GFP_ATOMIC);
+}
+
+void free_iova_mem(struct iova *iova)
+{
+ kmem_cache_free(iommu_iova_cache, iova);
+}
void
-init_iova_domain(struct iova_domain *iovad, unsigned long pfn_32bit)
+init_iova_domain(struct iova_domain *iovad, unsigned long granule,
+ unsigned long start_pfn, unsigned long pfn_32bit)
{
+ /*
+ * IOVA granularity will normally be equal to the smallest
+ * supported IOMMU page size; both *must* be capable of
+ * representing individual CPU pages exactly.
+ */
+ BUG_ON((granule > PAGE_SIZE) || !is_power_of_2(granule));
+
spin_lock_init(&iovad->iova_rbtree_lock);
iovad->rbroot = RB_ROOT;
iovad->cached32_node = NULL;
+ iovad->granule = granule;
+ iovad->start_pfn = start_pfn;
iovad->dma_32bit_pfn = pfn_32bit;
}
@@ -127,7 +172,7 @@ move_left:
if (!curr) {
if (size_aligned)
pad_size = iova_get_pad_size(size, limit_pfn);
- if ((IOVA_START_PFN + size + pad_size) > limit_pfn) {
+ if ((iovad->start_pfn + size + pad_size) > limit_pfn) {
spin_unlock_irqrestore(&iovad->iova_rbtree_lock, flags);
return -ENOMEM;
}
@@ -202,8 +247,8 @@ iova_insert_rbtree(struct rb_root *root, struct iova *iova)
* @size: - size of page frames to allocate
* @limit_pfn: - max limit address
* @size_aligned: - set if size_aligned address range is required
- * This function allocates an iova in the range limit_pfn to IOVA_START_PFN
- * looking from limit_pfn instead from IOVA_START_PFN. If the size_aligned
+ * This function allocates an iova in the range iovad->start_pfn to limit_pfn,
+ * searching top-down from limit_pfn to iovad->start_pfn. If the size_aligned
* flag is set then the allocated address iova->pfn_lo will be naturally
* aligned on roundup_power_of_two(size).
*/
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 748693192c20..10186cac7716 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -16,7 +16,7 @@
#include <linux/io.h>
#include <linux/iommu.h>
#include <linux/module.h>
-#include <linux/platform_data/ipmmu-vmsa.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sizes.h>
#include <linux/slab.h>
@@ -24,12 +24,13 @@
#include <asm/dma-iommu.h>
#include <asm/pgalloc.h>
+#include "io-pgtable.h"
+
struct ipmmu_vmsa_device {
struct device *dev;
void __iomem *base;
struct list_head list;
- const struct ipmmu_vmsa_platform_data *pdata;
unsigned int num_utlbs;
struct dma_iommu_mapping *mapping;
@@ -39,14 +40,17 @@ struct ipmmu_vmsa_domain {
struct ipmmu_vmsa_device *mmu;
struct iommu_domain *io_domain;
+ struct io_pgtable_cfg cfg;
+ struct io_pgtable_ops *iop;
+
unsigned int context_id;
spinlock_t lock; /* Protects mappings */
- pgd_t *pgd;
};
struct ipmmu_vmsa_archdata {
struct ipmmu_vmsa_device *mmu;
- unsigned int utlb;
+ unsigned int *utlbs;
+ unsigned int num_utlbs;
};
static DEFINE_SPINLOCK(ipmmu_devices_lock);
@@ -58,6 +62,8 @@ static LIST_HEAD(ipmmu_devices);
* Registers Definition
*/
+#define IM_NS_ALIAS_OFFSET 0x800
+
#define IM_CTX_SIZE 0x40
#define IMCTR 0x0000
@@ -171,52 +177,6 @@ static LIST_HEAD(ipmmu_devices);
#define IMUASID_ASID0_SHIFT 0
/* -----------------------------------------------------------------------------
- * Page Table Bits
- */
-
-/*
- * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory access,
- * Long-descriptor format" that the NStable bit being set in a table descriptor
- * will result in the NStable and NS bits of all child entries being ignored and
- * considered as being set. The IPMMU seems not to comply with this, as it
- * generates a secure access page fault if any of the NStable and NS bits isn't
- * set when running in non-secure mode.
- */
-#ifndef PMD_NSTABLE
-#define PMD_NSTABLE (_AT(pmdval_t, 1) << 63)
-#endif
-
-#define ARM_VMSA_PTE_XN (((pteval_t)3) << 53)
-#define ARM_VMSA_PTE_CONT (((pteval_t)1) << 52)
-#define ARM_VMSA_PTE_AF (((pteval_t)1) << 10)
-#define ARM_VMSA_PTE_SH_NS (((pteval_t)0) << 8)
-#define ARM_VMSA_PTE_SH_OS (((pteval_t)2) << 8)
-#define ARM_VMSA_PTE_SH_IS (((pteval_t)3) << 8)
-#define ARM_VMSA_PTE_SH_MASK (((pteval_t)3) << 8)
-#define ARM_VMSA_PTE_NS (((pteval_t)1) << 5)
-#define ARM_VMSA_PTE_PAGE (((pteval_t)3) << 0)
-
-/* Stage-1 PTE */
-#define ARM_VMSA_PTE_nG (((pteval_t)1) << 11)
-#define ARM_VMSA_PTE_AP_UNPRIV (((pteval_t)1) << 6)
-#define ARM_VMSA_PTE_AP_RDONLY (((pteval_t)2) << 6)
-#define ARM_VMSA_PTE_AP_MASK (((pteval_t)3) << 6)
-#define ARM_VMSA_PTE_ATTRINDX_MASK (((pteval_t)3) << 2)
-#define ARM_VMSA_PTE_ATTRINDX_SHIFT 2
-
-#define ARM_VMSA_PTE_ATTRS_MASK \
- (ARM_VMSA_PTE_XN | ARM_VMSA_PTE_CONT | ARM_VMSA_PTE_nG | \
- ARM_VMSA_PTE_AF | ARM_VMSA_PTE_SH_MASK | ARM_VMSA_PTE_AP_MASK | \
- ARM_VMSA_PTE_NS | ARM_VMSA_PTE_ATTRINDX_MASK)
-
-#define ARM_VMSA_PTE_CONT_ENTRIES 16
-#define ARM_VMSA_PTE_CONT_SIZE (PAGE_SIZE * ARM_VMSA_PTE_CONT_ENTRIES)
-
-#define IPMMU_PTRS_PER_PTE 512
-#define IPMMU_PTRS_PER_PMD 512
-#define IPMMU_PTRS_PER_PGD 4
-
-/* -----------------------------------------------------------------------------
* Read/Write Access
*/
@@ -305,18 +265,39 @@ static void ipmmu_utlb_disable(struct ipmmu_vmsa_domain *domain,
ipmmu_write(mmu, IMUCTR(utlb), 0);
}
-static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr,
- size_t size)
+static void ipmmu_tlb_flush_all(void *cookie)
+{
+ struct ipmmu_vmsa_domain *domain = cookie;
+
+ ipmmu_tlb_invalidate(domain);
+}
+
+static void ipmmu_tlb_add_flush(unsigned long iova, size_t size, bool leaf,
+ void *cookie)
{
- unsigned long offset = (unsigned long)addr & ~PAGE_MASK;
+ /* The hardware doesn't support selective TLB flush. */
+}
+
+static void ipmmu_flush_pgtable(void *ptr, size_t size, void *cookie)
+{
+ unsigned long offset = (unsigned long)ptr & ~PAGE_MASK;
+ struct ipmmu_vmsa_domain *domain = cookie;
/*
* TODO: Add support for coherent walk through CCI with DVM and remove
* cache handling.
*/
- dma_map_page(mmu->dev, virt_to_page(addr), offset, size, DMA_TO_DEVICE);
+ dma_map_page(domain->mmu->dev, virt_to_page(ptr), offset, size,
+ DMA_TO_DEVICE);
}
+static struct iommu_gather_ops ipmmu_gather_ops = {
+ .tlb_flush_all = ipmmu_tlb_flush_all,
+ .tlb_add_flush = ipmmu_tlb_add_flush,
+ .tlb_sync = ipmmu_tlb_flush_all,
+ .flush_pgtable = ipmmu_flush_pgtable,
+};
+
/* -----------------------------------------------------------------------------
* Domain/Context Management
*/
@@ -324,7 +305,28 @@ static void ipmmu_flush_pgtable(struct ipmmu_vmsa_device *mmu, void *addr,
static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
{
phys_addr_t ttbr;
- u32 reg;
+
+ /*
+ * Allocate the page table operations.
+ *
+ * VMSA states in section B3.6.3 "Control of Secure or Non-secure memory
+ * access, Long-descriptor format" that the NStable bit being set in a
+ * table descriptor will result in the NStable and NS bits of all child
+ * entries being ignored and considered as being set. The IPMMU seems
+ * not to comply with this, as it generates a secure access page fault
+ * if any of the NStable and NS bits isn't set when running in
+ * non-secure mode.
+ */
+ domain->cfg.quirks = IO_PGTABLE_QUIRK_ARM_NS;
+ domain->cfg.pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K,
+ domain->cfg.ias = 32;
+ domain->cfg.oas = 40;
+ domain->cfg.tlb = &ipmmu_gather_ops;
+
+ domain->iop = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &domain->cfg,
+ domain);
+ if (!domain->iop)
+ return -EINVAL;
/*
* TODO: When adding support for multiple contexts, find an unused
@@ -333,9 +335,7 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
domain->context_id = 0;
/* TTBR0 */
- ipmmu_flush_pgtable(domain->mmu, domain->pgd,
- IPMMU_PTRS_PER_PGD * sizeof(*domain->pgd));
- ttbr = __pa(domain->pgd);
+ ttbr = domain->cfg.arm_lpae_s1_cfg.ttbr[0];
ipmmu_ctx_write(domain, IMTTLBR0, ttbr);
ipmmu_ctx_write(domain, IMTTUBR0, ttbr >> 32);
@@ -348,15 +348,8 @@ static int ipmmu_domain_init_context(struct ipmmu_vmsa_domain *domain)
IMTTBCR_SH0_INNER_SHAREABLE | IMTTBCR_ORGN0_WB_WA |
IMTTBCR_IRGN0_WB_WA | IMTTBCR_SL0_LVL_1);
- /*
- * MAIR0
- * We need three attributes only, non-cacheable, write-back read/write
- * allocate and device memory.
- */
- reg = (IMMAIR_ATTR_NC << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_NC))
- | (IMMAIR_ATTR_WBRWA << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_WBRWA))
- | (IMMAIR_ATTR_DEVICE << IMMAIR_ATTR_SHIFT(IMMAIR_ATTR_IDX_DEV));
- ipmmu_ctx_write(domain, IMMAIR0, reg);
+ /* MAIR0 */
+ ipmmu_ctx_write(domain, IMMAIR0, domain->cfg.arm_lpae_s1_cfg.mair[0]);
/* IMBUSCR */
ipmmu_ctx_write(domain, IMBUSCR,
@@ -461,396 +454,6 @@ static irqreturn_t ipmmu_irq(int irq, void *dev)
}
/* -----------------------------------------------------------------------------
- * Page Table Management
- */
-
-#define pud_pgtable(pud) pfn_to_page(__phys_to_pfn(pud_val(pud) & PHYS_MASK))
-
-static void ipmmu_free_ptes(pmd_t *pmd)
-{
- pgtable_t table = pmd_pgtable(*pmd);
- __free_page(table);
-}
-
-static void ipmmu_free_pmds(pud_t *pud)
-{
- pmd_t *pmd = pmd_offset(pud, 0);
- pgtable_t table;
- unsigned int i;
-
- for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) {
- if (!pmd_table(*pmd))
- continue;
-
- ipmmu_free_ptes(pmd);
- pmd++;
- }
-
- table = pud_pgtable(*pud);
- __free_page(table);
-}
-
-static void ipmmu_free_pgtables(struct ipmmu_vmsa_domain *domain)
-{
- pgd_t *pgd, *pgd_base = domain->pgd;
- unsigned int i;
-
- /*
- * Recursively free the page tables for this domain. We don't care about
- * speculative TLB filling, because the TLB will be nuked next time this
- * context bank is re-allocated and no devices currently map to these
- * tables.
- */
- pgd = pgd_base;
- for (i = 0; i < IPMMU_PTRS_PER_PGD; ++i) {
- if (pgd_none(*pgd))
- continue;
- ipmmu_free_pmds((pud_t *)pgd);
- pgd++;
- }
-
- kfree(pgd_base);
-}
-
-/*
- * We can't use the (pgd|pud|pmd|pte)_populate or the set_(pgd|pud|pmd|pte)
- * functions as they would flush the CPU TLB.
- */
-
-static pte_t *ipmmu_alloc_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd,
- unsigned long iova)
-{
- pte_t *pte;
-
- if (!pmd_none(*pmd))
- return pte_offset_kernel(pmd, iova);
-
- pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
- if (!pte)
- return NULL;
-
- ipmmu_flush_pgtable(mmu, pte, PAGE_SIZE);
- *pmd = __pmd(__pa(pte) | PMD_NSTABLE | PMD_TYPE_TABLE);
- ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd));
-
- return pte + pte_index(iova);
-}
-
-static pmd_t *ipmmu_alloc_pmd(struct ipmmu_vmsa_device *mmu, pgd_t *pgd,
- unsigned long iova)
-{
- pud_t *pud = (pud_t *)pgd;
- pmd_t *pmd;
-
- if (!pud_none(*pud))
- return pmd_offset(pud, iova);
-
- pmd = (pmd_t *)get_zeroed_page(GFP_ATOMIC);
- if (!pmd)
- return NULL;
-
- ipmmu_flush_pgtable(mmu, pmd, PAGE_SIZE);
- *pud = __pud(__pa(pmd) | PMD_NSTABLE | PMD_TYPE_TABLE);
- ipmmu_flush_pgtable(mmu, pud, sizeof(*pud));
-
- return pmd + pmd_index(iova);
-}
-
-static u64 ipmmu_page_prot(unsigned int prot, u64 type)
-{
- u64 pgprot = ARM_VMSA_PTE_nG | ARM_VMSA_PTE_AF
- | ARM_VMSA_PTE_SH_IS | ARM_VMSA_PTE_AP_UNPRIV
- | ARM_VMSA_PTE_NS | type;
-
- if (!(prot & IOMMU_WRITE) && (prot & IOMMU_READ))
- pgprot |= ARM_VMSA_PTE_AP_RDONLY;
-
- if (prot & IOMMU_CACHE)
- pgprot |= IMMAIR_ATTR_IDX_WBRWA << ARM_VMSA_PTE_ATTRINDX_SHIFT;
-
- if (prot & IOMMU_NOEXEC)
- pgprot |= ARM_VMSA_PTE_XN;
- else if (!(prot & (IOMMU_READ | IOMMU_WRITE)))
- /* If no access create a faulting entry to avoid TLB fills. */
- pgprot &= ~ARM_VMSA_PTE_PAGE;
-
- return pgprot;
-}
-
-static int ipmmu_alloc_init_pte(struct ipmmu_vmsa_device *mmu, pmd_t *pmd,
- unsigned long iova, unsigned long pfn,
- size_t size, int prot)
-{
- pteval_t pteval = ipmmu_page_prot(prot, ARM_VMSA_PTE_PAGE);
- unsigned int num_ptes = 1;
- pte_t *pte, *start;
- unsigned int i;
-
- pte = ipmmu_alloc_pte(mmu, pmd, iova);
- if (!pte)
- return -ENOMEM;
-
- start = pte;
-
- /*
- * Install the page table entries. We can be called both for a single
- * page or for a block of 16 physically contiguous pages. In the latter
- * case set the PTE contiguous hint.
- */
- if (size == SZ_64K) {
- pteval |= ARM_VMSA_PTE_CONT;
- num_ptes = ARM_VMSA_PTE_CONT_ENTRIES;
- }
-
- for (i = num_ptes; i; --i)
- *pte++ = pfn_pte(pfn++, __pgprot(pteval));
-
- ipmmu_flush_pgtable(mmu, start, sizeof(*pte) * num_ptes);
-
- return 0;
-}
-
-static int ipmmu_alloc_init_pmd(struct ipmmu_vmsa_device *mmu, pmd_t *pmd,
- unsigned long iova, unsigned long pfn,
- int prot)
-{
- pmdval_t pmdval = ipmmu_page_prot(prot, PMD_TYPE_SECT);
-
- *pmd = pfn_pmd(pfn, __pgprot(pmdval));
- ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd));
-
- return 0;
-}
-
-static int ipmmu_create_mapping(struct ipmmu_vmsa_domain *domain,
- unsigned long iova, phys_addr_t paddr,
- size_t size, int prot)
-{
- struct ipmmu_vmsa_device *mmu = domain->mmu;
- pgd_t *pgd = domain->pgd;
- unsigned long flags;
- unsigned long pfn;
- pmd_t *pmd;
- int ret;
-
- if (!pgd)
- return -EINVAL;
-
- if (size & ~PAGE_MASK)
- return -EINVAL;
-
- if (paddr & ~((1ULL << 40) - 1))
- return -ERANGE;
-
- pfn = __phys_to_pfn(paddr);
- pgd += pgd_index(iova);
-
- /* Update the page tables. */
- spin_lock_irqsave(&domain->lock, flags);
-
- pmd = ipmmu_alloc_pmd(mmu, pgd, iova);
- if (!pmd) {
- ret = -ENOMEM;
- goto done;
- }
-
- switch (size) {
- case SZ_2M:
- ret = ipmmu_alloc_init_pmd(mmu, pmd, iova, pfn, prot);
- break;
- case SZ_64K:
- case SZ_4K:
- ret = ipmmu_alloc_init_pte(mmu, pmd, iova, pfn, size, prot);
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
-done:
- spin_unlock_irqrestore(&domain->lock, flags);
-
- if (!ret)
- ipmmu_tlb_invalidate(domain);
-
- return ret;
-}
-
-static void ipmmu_clear_pud(struct ipmmu_vmsa_device *mmu, pud_t *pud)
-{
- /* Free the page table. */
- pgtable_t table = pud_pgtable(*pud);
- __free_page(table);
-
- /* Clear the PUD. */
- *pud = __pud(0);
- ipmmu_flush_pgtable(mmu, pud, sizeof(*pud));
-}
-
-static void ipmmu_clear_pmd(struct ipmmu_vmsa_device *mmu, pud_t *pud,
- pmd_t *pmd)
-{
- unsigned int i;
-
- /* Free the page table. */
- if (pmd_table(*pmd)) {
- pgtable_t table = pmd_pgtable(*pmd);
- __free_page(table);
- }
-
- /* Clear the PMD. */
- *pmd = __pmd(0);
- ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd));
-
- /* Check whether the PUD is still needed. */
- pmd = pmd_offset(pud, 0);
- for (i = 0; i < IPMMU_PTRS_PER_PMD; ++i) {
- if (!pmd_none(pmd[i]))
- return;
- }
-
- /* Clear the parent PUD. */
- ipmmu_clear_pud(mmu, pud);
-}
-
-static void ipmmu_clear_pte(struct ipmmu_vmsa_device *mmu, pud_t *pud,
- pmd_t *pmd, pte_t *pte, unsigned int num_ptes)
-{
- unsigned int i;
-
- /* Clear the PTE. */
- for (i = num_ptes; i; --i)
- pte[i-1] = __pte(0);
-
- ipmmu_flush_pgtable(mmu, pte, sizeof(*pte) * num_ptes);
-
- /* Check whether the PMD is still needed. */
- pte = pte_offset_kernel(pmd, 0);
- for (i = 0; i < IPMMU_PTRS_PER_PTE; ++i) {
- if (!pte_none(pte[i]))
- return;
- }
-
- /* Clear the parent PMD. */
- ipmmu_clear_pmd(mmu, pud, pmd);
-}
-
-static int ipmmu_split_pmd(struct ipmmu_vmsa_device *mmu, pmd_t *pmd)
-{
- pte_t *pte, *start;
- pteval_t pteval;
- unsigned long pfn;
- unsigned int i;
-
- pte = (pte_t *)get_zeroed_page(GFP_ATOMIC);
- if (!pte)
- return -ENOMEM;
-
- /* Copy the PMD attributes. */
- pteval = (pmd_val(*pmd) & ARM_VMSA_PTE_ATTRS_MASK)
- | ARM_VMSA_PTE_CONT | ARM_VMSA_PTE_PAGE;
-
- pfn = pmd_pfn(*pmd);
- start = pte;
-
- for (i = IPMMU_PTRS_PER_PTE; i; --i)
- *pte++ = pfn_pte(pfn++, __pgprot(pteval));
-
- ipmmu_flush_pgtable(mmu, start, PAGE_SIZE);
- *pmd = __pmd(__pa(start) | PMD_NSTABLE | PMD_TYPE_TABLE);
- ipmmu_flush_pgtable(mmu, pmd, sizeof(*pmd));
-
- return 0;
-}
-
-static void ipmmu_split_pte(struct ipmmu_vmsa_device *mmu, pte_t *pte)
-{
- unsigned int i;
-
- for (i = ARM_VMSA_PTE_CONT_ENTRIES; i; --i)
- pte[i-1] = __pte(pte_val(*pte) & ~ARM_VMSA_PTE_CONT);
-
- ipmmu_flush_pgtable(mmu, pte, sizeof(*pte) * ARM_VMSA_PTE_CONT_ENTRIES);
-}
-
-static int ipmmu_clear_mapping(struct ipmmu_vmsa_domain *domain,
- unsigned long iova, size_t size)
-{
- struct ipmmu_vmsa_device *mmu = domain->mmu;
- unsigned long flags;
- pgd_t *pgd = domain->pgd;
- pud_t *pud;
- pmd_t *pmd;
- pte_t *pte;
- int ret = 0;
-
- if (!pgd)
- return -EINVAL;
-
- if (size & ~PAGE_MASK)
- return -EINVAL;
-
- pgd += pgd_index(iova);
- pud = (pud_t *)pgd;
-
- spin_lock_irqsave(&domain->lock, flags);
-
- /* If there's no PUD or PMD we're done. */
- if (pud_none(*pud))
- goto done;
-
- pmd = pmd_offset(pud, iova);
- if (pmd_none(*pmd))
- goto done;
-
- /*
- * When freeing a 2MB block just clear the PMD. In the unlikely case the
- * block is mapped as individual pages this will free the corresponding
- * PTE page table.
- */
- if (size == SZ_2M) {
- ipmmu_clear_pmd(mmu, pud, pmd);
- goto done;
- }
-
- /*
- * If the PMD has been mapped as a section remap it as pages to allow
- * freeing individual pages.
- */
- if (pmd_sect(*pmd))
- ipmmu_split_pmd(mmu, pmd);
-
- pte = pte_offset_kernel(pmd, iova);
-
- /*
- * When freeing a 64kB block just clear the PTE entries. We don't have
- * to care about the contiguous hint of the surrounding entries.
- */
- if (size == SZ_64K) {
- ipmmu_clear_pte(mmu, pud, pmd, pte, ARM_VMSA_PTE_CONT_ENTRIES);
- goto done;
- }
-
- /*
- * If the PTE has been mapped with the contiguous hint set remap it and
- * its surrounding PTEs to allow unmapping a single page.
- */
- if (pte_val(*pte) & ARM_VMSA_PTE_CONT)
- ipmmu_split_pte(mmu, pte);
-
- /* Clear the PTE. */
- ipmmu_clear_pte(mmu, pud, pmd, pte, 1);
-
-done:
- spin_unlock_irqrestore(&domain->lock, flags);
-
- if (ret)
- ipmmu_tlb_invalidate(domain);
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
* IOMMU Operations
*/
@@ -864,12 +467,6 @@ static int ipmmu_domain_init(struct iommu_domain *io_domain)
spin_lock_init(&domain->lock);
- domain->pgd = kzalloc(IPMMU_PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
- if (!domain->pgd) {
- kfree(domain);
- return -ENOMEM;
- }
-
io_domain->priv = domain;
domain->io_domain = io_domain;
@@ -885,7 +482,7 @@ static void ipmmu_domain_destroy(struct iommu_domain *io_domain)
* been detached.
*/
ipmmu_domain_destroy_context(domain);
- ipmmu_free_pgtables(domain);
+ free_io_pgtable_ops(domain->iop);
kfree(domain);
}
@@ -896,6 +493,7 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
struct ipmmu_vmsa_device *mmu = archdata->mmu;
struct ipmmu_vmsa_domain *domain = io_domain->priv;
unsigned long flags;
+ unsigned int i;
int ret = 0;
if (!mmu) {
@@ -924,7 +522,8 @@ static int ipmmu_attach_device(struct iommu_domain *io_domain,
if (ret < 0)
return ret;
- ipmmu_utlb_enable(domain, archdata->utlb);
+ for (i = 0; i < archdata->num_utlbs; ++i)
+ ipmmu_utlb_enable(domain, archdata->utlbs[i]);
return 0;
}
@@ -934,8 +533,10 @@ static void ipmmu_detach_device(struct iommu_domain *io_domain,
{
struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
struct ipmmu_vmsa_domain *domain = io_domain->priv;
+ unsigned int i;
- ipmmu_utlb_disable(domain, archdata->utlb);
+ for (i = 0; i < archdata->num_utlbs; ++i)
+ ipmmu_utlb_disable(domain, archdata->utlbs[i]);
/*
* TODO: Optimize by disabling the context when no device is attached.
@@ -950,76 +551,61 @@ static int ipmmu_map(struct iommu_domain *io_domain, unsigned long iova,
if (!domain)
return -ENODEV;
- return ipmmu_create_mapping(domain, iova, paddr, size, prot);
+ return domain->iop->map(domain->iop, iova, paddr, size, prot);
}
static size_t ipmmu_unmap(struct iommu_domain *io_domain, unsigned long iova,
size_t size)
{
struct ipmmu_vmsa_domain *domain = io_domain->priv;
- int ret;
- ret = ipmmu_clear_mapping(domain, iova, size);
- return ret ? 0 : size;
+ return domain->iop->unmap(domain->iop, iova, size);
}
static phys_addr_t ipmmu_iova_to_phys(struct iommu_domain *io_domain,
dma_addr_t iova)
{
struct ipmmu_vmsa_domain *domain = io_domain->priv;
- pgd_t pgd;
- pud_t pud;
- pmd_t pmd;
- pte_t pte;
/* TODO: Is locking needed ? */
- if (!domain->pgd)
- return 0;
-
- pgd = *(domain->pgd + pgd_index(iova));
- if (pgd_none(pgd))
- return 0;
-
- pud = *pud_offset(&pgd, iova);
- if (pud_none(pud))
- return 0;
+ return domain->iop->iova_to_phys(domain->iop, iova);
+}
- pmd = *pmd_offset(&pud, iova);
- if (pmd_none(pmd))
- return 0;
+static int ipmmu_find_utlbs(struct ipmmu_vmsa_device *mmu, struct device *dev,
+ unsigned int *utlbs, unsigned int num_utlbs)
+{
+ unsigned int i;
- if (pmd_sect(pmd))
- return __pfn_to_phys(pmd_pfn(pmd)) | (iova & ~PMD_MASK);
+ for (i = 0; i < num_utlbs; ++i) {
+ struct of_phandle_args args;
+ int ret;
- pte = *(pmd_page_vaddr(pmd) + pte_index(iova));
- if (pte_none(pte))
- return 0;
+ ret = of_parse_phandle_with_args(dev->of_node, "iommus",
+ "#iommu-cells", i, &args);
+ if (ret < 0)
+ return ret;
- return __pfn_to_phys(pte_pfn(pte)) | (iova & ~PAGE_MASK);
-}
+ of_node_put(args.np);
-static int ipmmu_find_utlb(struct ipmmu_vmsa_device *mmu, struct device *dev)
-{
- const struct ipmmu_vmsa_master *master = mmu->pdata->masters;
- const char *devname = dev_name(dev);
- unsigned int i;
+ if (args.np != mmu->dev->of_node || args.args_count != 1)
+ return -EINVAL;
- for (i = 0; i < mmu->pdata->num_masters; ++i, ++master) {
- if (strcmp(master->name, devname) == 0)
- return master->utlb;
+ utlbs[i] = args.args[0];
}
- return -1;
+ return 0;
}
static int ipmmu_add_device(struct device *dev)
{
struct ipmmu_vmsa_archdata *archdata;
struct ipmmu_vmsa_device *mmu;
- struct iommu_group *group;
- int utlb = -1;
- int ret;
+ struct iommu_group *group = NULL;
+ unsigned int *utlbs;
+ unsigned int i;
+ int num_utlbs;
+ int ret = -ENODEV;
if (dev->archdata.iommu) {
dev_warn(dev, "IOMMU driver already assigned to device %s\n",
@@ -1028,11 +614,21 @@ static int ipmmu_add_device(struct device *dev)
}
/* Find the master corresponding to the device. */
+
+ num_utlbs = of_count_phandle_with_args(dev->of_node, "iommus",
+ "#iommu-cells");
+ if (num_utlbs < 0)
+ return -ENODEV;
+
+ utlbs = kcalloc(num_utlbs, sizeof(*utlbs), GFP_KERNEL);
+ if (!utlbs)
+ return -ENOMEM;
+
spin_lock(&ipmmu_devices_lock);
list_for_each_entry(mmu, &ipmmu_devices, list) {
- utlb = ipmmu_find_utlb(mmu, dev);
- if (utlb >= 0) {
+ ret = ipmmu_find_utlbs(mmu, dev, utlbs, num_utlbs);
+ if (!ret) {
/*
* TODO Take a reference to the MMU to protect
* against device removal.
@@ -1043,17 +639,22 @@ static int ipmmu_add_device(struct device *dev)
spin_unlock(&ipmmu_devices_lock);
- if (utlb < 0)
+ if (ret < 0)
return -ENODEV;
- if (utlb >= mmu->num_utlbs)
- return -EINVAL;
+ for (i = 0; i < num_utlbs; ++i) {
+ if (utlbs[i] >= mmu->num_utlbs) {
+ ret = -EINVAL;
+ goto error;
+ }
+ }
/* Create a device group and add the device to it. */
group = iommu_group_alloc();
if (IS_ERR(group)) {
dev_err(dev, "Failed to allocate IOMMU group\n");
- return PTR_ERR(group);
+ ret = PTR_ERR(group);
+ goto error;
}
ret = iommu_group_add_device(group, dev);
@@ -1061,7 +662,8 @@ static int ipmmu_add_device(struct device *dev)
if (ret < 0) {
dev_err(dev, "Failed to add device to IPMMU group\n");
- return ret;
+ group = NULL;
+ goto error;
}
archdata = kzalloc(sizeof(*archdata), GFP_KERNEL);
@@ -1071,7 +673,8 @@ static int ipmmu_add_device(struct device *dev)
}
archdata->mmu = mmu;
- archdata->utlb = utlb;
+ archdata->utlbs = utlbs;
+ archdata->num_utlbs = num_utlbs;
dev->archdata.iommu = archdata;
/*
@@ -1090,7 +693,8 @@ static int ipmmu_add_device(struct device *dev)
SZ_1G, SZ_2G);
if (IS_ERR(mapping)) {
dev_err(mmu->dev, "failed to create ARM IOMMU mapping\n");
- return PTR_ERR(mapping);
+ ret = PTR_ERR(mapping);
+ goto error;
}
mmu->mapping = mapping;
@@ -1106,17 +710,29 @@ static int ipmmu_add_device(struct device *dev)
return 0;
error:
+ arm_iommu_release_mapping(mmu->mapping);
+
kfree(dev->archdata.iommu);
+ kfree(utlbs);
+
dev->archdata.iommu = NULL;
- iommu_group_remove_device(dev);
+
+ if (!IS_ERR_OR_NULL(group))
+ iommu_group_remove_device(dev);
+
return ret;
}
static void ipmmu_remove_device(struct device *dev)
{
+ struct ipmmu_vmsa_archdata *archdata = dev->archdata.iommu;
+
arm_iommu_detach_device(dev);
iommu_group_remove_device(dev);
- kfree(dev->archdata.iommu);
+
+ kfree(archdata->utlbs);
+ kfree(archdata);
+
dev->archdata.iommu = NULL;
}
@@ -1131,7 +747,7 @@ static const struct iommu_ops ipmmu_ops = {
.iova_to_phys = ipmmu_iova_to_phys,
.add_device = ipmmu_add_device,
.remove_device = ipmmu_remove_device,
- .pgsize_bitmap = SZ_2M | SZ_64K | SZ_4K,
+ .pgsize_bitmap = SZ_1G | SZ_2M | SZ_4K,
};
/* -----------------------------------------------------------------------------
@@ -1154,7 +770,7 @@ static int ipmmu_probe(struct platform_device *pdev)
int irq;
int ret;
- if (!pdev->dev.platform_data) {
+ if (!IS_ENABLED(CONFIG_OF) && !pdev->dev.platform_data) {
dev_err(&pdev->dev, "missing platform data\n");
return -EINVAL;
}
@@ -1166,7 +782,6 @@ static int ipmmu_probe(struct platform_device *pdev)
}
mmu->dev = &pdev->dev;
- mmu->pdata = pdev->dev.platform_data;
mmu->num_utlbs = 32;
/* Map I/O memory and request IRQ. */
@@ -1175,6 +790,20 @@ static int ipmmu_probe(struct platform_device *pdev)
if (IS_ERR(mmu->base))
return PTR_ERR(mmu->base);
+ /*
+ * The IPMMU has two register banks, for secure and non-secure modes.
+ * The bank mapped at the beginning of the IPMMU address space
+ * corresponds to the running mode of the CPU. When running in secure
+ * mode the non-secure register bank is also available at an offset.
+ *
+ * Secure mode operation isn't clearly documented and is thus currently
+ * not implemented in the driver. Furthermore, preliminary tests of
+ * non-secure operation with the main register bank were not successful.
+ * Offset the registers base unconditionally to point to the non-secure
+ * alias space for now.
+ */
+ mmu->base += IM_NS_ALIAS_OFFSET;
+
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "no IRQ found\n");
@@ -1220,9 +849,14 @@ static int ipmmu_remove(struct platform_device *pdev)
return 0;
}
+static const struct of_device_id ipmmu_of_ids[] = {
+ { .compatible = "renesas,ipmmu-vmsa", },
+};
+
static struct platform_driver ipmmu_driver = {
.driver = {
.name = "ipmmu-vmsa",
+ .of_match_table = of_match_ptr(ipmmu_of_ids),
},
.probe = ipmmu_probe,
.remove = ipmmu_remove,
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 89c4846683be..390079ee1350 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -17,12 +17,11 @@
#include "irq_remapping.h"
int irq_remapping_enabled;
-
-int disable_irq_remap;
int irq_remap_broken;
int disable_sourceid_checking;
int no_x2apic_optout;
+static int disable_irq_remap;
static struct irq_remap_ops *remap_ops;
static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec);
@@ -194,45 +193,32 @@ static __init int setup_irqremap(char *str)
}
early_param("intremap", setup_irqremap);
-void __init setup_irq_remapping_ops(void)
-{
- remap_ops = &intel_irq_remap_ops;
-
-#ifdef CONFIG_AMD_IOMMU
- if (amd_iommu_irq_ops.prepare() == 0)
- remap_ops = &amd_iommu_irq_ops;
-#endif
-}
-
void set_irq_remapping_broken(void)
{
irq_remap_broken = 1;
}
-int irq_remapping_supported(void)
+int __init irq_remapping_prepare(void)
{
if (disable_irq_remap)
- return 0;
-
- if (!remap_ops || !remap_ops->supported)
- return 0;
-
- return remap_ops->supported();
-}
+ return -ENOSYS;
-int __init irq_remapping_prepare(void)
-{
- if (!remap_ops || !remap_ops->prepare)
- return -ENODEV;
+ if (intel_irq_remap_ops.prepare() == 0)
+ remap_ops = &intel_irq_remap_ops;
+ else if (IS_ENABLED(CONFIG_AMD_IOMMU) &&
+ amd_iommu_irq_ops.prepare() == 0)
+ remap_ops = &amd_iommu_irq_ops;
+ else
+ return -ENOSYS;
- return remap_ops->prepare();
+ return 0;
}
int __init irq_remapping_enable(void)
{
int ret;
- if (!remap_ops || !remap_ops->enable)
+ if (!remap_ops->enable)
return -ENODEV;
ret = remap_ops->enable();
@@ -245,22 +231,16 @@ int __init irq_remapping_enable(void)
void irq_remapping_disable(void)
{
- if (!irq_remapping_enabled ||
- !remap_ops ||
- !remap_ops->disable)
- return;
-
- remap_ops->disable();
+ if (irq_remapping_enabled && remap_ops->disable)
+ remap_ops->disable();
}
int irq_remapping_reenable(int mode)
{
- if (!irq_remapping_enabled ||
- !remap_ops ||
- !remap_ops->reenable)
- return 0;
+ if (irq_remapping_enabled && remap_ops->reenable)
+ return remap_ops->reenable(mode);
- return remap_ops->reenable(mode);
+ return 0;
}
int __init irq_remap_enable_fault_handling(void)
@@ -268,7 +248,7 @@ int __init irq_remap_enable_fault_handling(void)
if (!irq_remapping_enabled)
return 0;
- if (!remap_ops || !remap_ops->enable_faulting)
+ if (!remap_ops->enable_faulting)
return -ENODEV;
return remap_ops->enable_faulting();
@@ -279,7 +259,7 @@ int setup_ioapic_remapped_entry(int irq,
unsigned int destination, int vector,
struct io_apic_irq_attr *attr)
{
- if (!remap_ops || !remap_ops->setup_ioapic_entry)
+ if (!remap_ops->setup_ioapic_entry)
return -ENODEV;
return remap_ops->setup_ioapic_entry(irq, entry, destination,
@@ -289,8 +269,7 @@ int setup_ioapic_remapped_entry(int irq,
static int set_remapped_irq_affinity(struct irq_data *data,
const struct cpumask *mask, bool force)
{
- if (!config_enabled(CONFIG_SMP) || !remap_ops ||
- !remap_ops->set_affinity)
+ if (!config_enabled(CONFIG_SMP) || !remap_ops->set_affinity)
return 0;
return remap_ops->set_affinity(data, mask, force);
@@ -300,10 +279,7 @@ void free_remapped_irq(int irq)
{
struct irq_cfg *cfg = irq_cfg(irq);
- if (!remap_ops || !remap_ops->free_irq)
- return;
-
- if (irq_remapped(cfg))
+ if (irq_remapped(cfg) && remap_ops->free_irq)
remap_ops->free_irq(irq);
}
@@ -315,13 +291,13 @@ void compose_remapped_msi_msg(struct pci_dev *pdev,
if (!irq_remapped(cfg))
native_compose_msi_msg(pdev, irq, dest, msg, hpet_id);
- else if (remap_ops && remap_ops->compose_msi_msg)
+ else if (remap_ops->compose_msi_msg)
remap_ops->compose_msi_msg(pdev, irq, dest, msg, hpet_id);
}
static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
{
- if (!remap_ops || !remap_ops->msi_alloc_irq)
+ if (!remap_ops->msi_alloc_irq)
return -ENODEV;
return remap_ops->msi_alloc_irq(pdev, irq, nvec);
@@ -330,7 +306,7 @@ static int msi_alloc_remapped_irq(struct pci_dev *pdev, int irq, int nvec)
static int msi_setup_remapped_irq(struct pci_dev *pdev, unsigned int irq,
int index, int sub_handle)
{
- if (!remap_ops || !remap_ops->msi_setup_irq)
+ if (!remap_ops->msi_setup_irq)
return -ENODEV;
return remap_ops->msi_setup_irq(pdev, irq, index, sub_handle);
@@ -340,7 +316,7 @@ int setup_hpet_msi_remapped(unsigned int irq, unsigned int id)
{
int ret;
- if (!remap_ops || !remap_ops->alloc_hpet_msi)
+ if (!remap_ops->alloc_hpet_msi)
return -ENODEV;
ret = remap_ops->alloc_hpet_msi(irq, id);
diff --git a/drivers/iommu/irq_remapping.h b/drivers/iommu/irq_remapping.h
index fde250f86e60..7c70cc29ffe6 100644
--- a/drivers/iommu/irq_remapping.h
+++ b/drivers/iommu/irq_remapping.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2012 Advanced Micro Devices, Inc.
- * Author: Joerg Roedel <joerg.roedel@amd.com>
+ * Author: Joerg Roedel <jroedel@suse.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
@@ -31,16 +31,12 @@ struct cpumask;
struct pci_dev;
struct msi_msg;
-extern int disable_irq_remap;
extern int irq_remap_broken;
extern int disable_sourceid_checking;
extern int no_x2apic_optout;
extern int irq_remapping_enabled;
struct irq_remap_ops {
- /* Check whether Interrupt Remapping is supported */
- int (*supported)(void);
-
/* Initializes hardware and makes it ready for remapping interrupts */
int (*prepare)(void);
@@ -89,7 +85,6 @@ extern struct irq_remap_ops amd_iommu_irq_ops;
#else /* CONFIG_IRQ_REMAP */
#define irq_remapping_enabled 0
-#define disable_irq_remap 1
#define irq_remap_broken 0
#endif /* CONFIG_IRQ_REMAP */
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index bbb7dcef02d3..f59f857b702e 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1126,7 +1126,7 @@ static int omap_iommu_map(struct iommu_domain *domain, unsigned long da,
return -EINVAL;
}
- dev_dbg(dev, "mapping da 0x%lx to pa 0x%x size 0x%x\n", da, pa, bytes);
+ dev_dbg(dev, "mapping da 0x%lx to pa %pa size 0x%x\n", da, &pa, bytes);
iotlb_init_entry(&e, da, pa, omap_pgsz);
diff --git a/drivers/iommu/tegra-gart.c b/drivers/iommu/tegra-gart.c
index f722a0c466cf..c48da057dbb1 100644
--- a/drivers/iommu/tegra-gart.c
+++ b/drivers/iommu/tegra-gart.c
@@ -315,6 +315,7 @@ static const struct iommu_ops gart_iommu_ops = {
.attach_dev = gart_iommu_attach_dev,
.detach_dev = gart_iommu_detach_dev,
.map = gart_iommu_map,
+ .map_sg = default_iommu_map_sg,
.unmap = gart_iommu_unmap,
.iova_to_phys = gart_iommu_iova_to_phys,
.pgsize_bitmap = GART_IOMMU_PGSIZES,
@@ -395,7 +396,7 @@ static int tegra_gart_probe(struct platform_device *pdev)
do_gart_setup(gart, NULL);
gart_handle = gart;
- bus_set_iommu(&platform_bus_type, &gart_iommu_ops);
+
return 0;
}
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 9516a324be6d..42965d2476bb 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -42,3 +42,4 @@ obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
obj-$(CONFIG_MIPS_GIC) += irq-mips-gic.o
obj-$(CONFIG_ARCH_MEDIATEK) += irq-mtk-sysirq.o
+obj-$(CONFIG_ARCH_DIGICOLOR) += irq-digicolor.o
diff --git a/drivers/irqchip/irq-digicolor.c b/drivers/irqchip/irq-digicolor.c
new file mode 100644
index 000000000000..930a2a2fac7f
--- /dev/null
+++ b/drivers/irqchip/irq-digicolor.c
@@ -0,0 +1,120 @@
+/*
+ * Conexant Digicolor SoCs IRQ chip driver
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation 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 <linux/io.h>
+#include <linux/irq.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include <asm/exception.h>
+
+#include "irqchip.h"
+
+#define UC_IRQ_CONTROL 0x04
+
+#define IC_FLAG_CLEAR_LO 0x00
+#define IC_FLAG_CLEAR_XLO 0x04
+#define IC_INT0ENABLE_LO 0x10
+#define IC_INT0ENABLE_XLO 0x14
+#define IC_INT0STATUS_LO 0x18
+#define IC_INT0STATUS_XLO 0x1c
+
+static struct irq_domain *digicolor_irq_domain;
+
+static void __exception_irq_entry digicolor_handle_irq(struct pt_regs *regs)
+{
+ struct irq_domain_chip_generic *dgc = digicolor_irq_domain->gc;
+ struct irq_chip_generic *gc = dgc->gc[0];
+ u32 status, hwirq;
+
+ do {
+ status = irq_reg_readl(gc, IC_INT0STATUS_LO);
+ if (status) {
+ hwirq = ffs(status) - 1;
+ } else {
+ status = irq_reg_readl(gc, IC_INT0STATUS_XLO);
+ if (status)
+ hwirq = ffs(status) - 1 + 32;
+ else
+ return;
+ }
+
+ handle_domain_irq(digicolor_irq_domain, hwirq, regs);
+ } while (1);
+}
+
+static void digicolor_set_gc(void __iomem *reg_base, unsigned irq_base,
+ unsigned en_reg, unsigned ack_reg)
+{
+ struct irq_chip_generic *gc;
+
+ gc = irq_get_domain_generic_chip(digicolor_irq_domain, irq_base);
+ gc->reg_base = reg_base;
+ gc->chip_types[0].regs.ack = ack_reg;
+ gc->chip_types[0].regs.mask = en_reg;
+ gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
+ gc->chip_types[0].chip.irq_mask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
+}
+
+static int __init digicolor_of_init(struct device_node *node,
+ struct device_node *parent)
+{
+ static void __iomem *reg_base;
+ unsigned int clr = IRQ_NOREQUEST | IRQ_NOPROBE | IRQ_NOAUTOEN;
+ struct regmap *ucregs;
+ int ret;
+
+ reg_base = of_iomap(node, 0);
+ if (!reg_base) {
+ pr_err("%s: unable to map IC registers\n", node->full_name);
+ return -ENXIO;
+ }
+
+ /* disable all interrupts */
+ writel(0, reg_base + IC_INT0ENABLE_LO);
+ writel(0, reg_base + IC_INT0ENABLE_XLO);
+
+ ucregs = syscon_regmap_lookup_by_phandle(node, "syscon");
+ if (IS_ERR(ucregs)) {
+ pr_err("%s: unable to map UC registers\n", node->full_name);
+ return PTR_ERR(ucregs);
+ }
+ /* channel 1, regular IRQs */
+ regmap_write(ucregs, UC_IRQ_CONTROL, 1);
+
+ digicolor_irq_domain =
+ irq_domain_add_linear(node, 64, &irq_generic_chip_ops, NULL);
+ if (!digicolor_irq_domain) {
+ pr_err("%s: unable to create IRQ domain\n", node->full_name);
+ return -ENOMEM;
+ }
+
+ ret = irq_alloc_domain_generic_chips(digicolor_irq_domain, 32, 1,
+ "digicolor_irq", handle_level_irq,
+ clr, 0, 0);
+ if (ret) {
+ pr_err("%s: unable to allocate IRQ gc\n", node->full_name);
+ return ret;
+ }
+
+ digicolor_set_gc(reg_base, 0, IC_INT0ENABLE_LO, IC_FLAG_CLEAR_LO);
+ digicolor_set_gc(reg_base, 32, IC_INT0ENABLE_XLO, IC_FLAG_CLEAR_XLO);
+
+ set_handle_irq(digicolor_handle_irq);
+
+ return 0;
+}
+IRQCHIP_DECLARE(conexant_digicolor_ic, "cnxt,cx92755-ic", digicolor_of_init);
diff --git a/drivers/irqchip/irq-gic-common.c b/drivers/irqchip/irq-gic-common.c
index 61541ff24397..ad96ebb0c7ab 100644
--- a/drivers/irqchip/irq-gic-common.c
+++ b/drivers/irqchip/irq-gic-common.c
@@ -21,7 +21,7 @@
#include "irq-gic-common.h"
-void gic_configure_irq(unsigned int irq, unsigned int type,
+int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void))
{
u32 enablemask = 1 << (irq % 32);
@@ -29,16 +29,17 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
u32 confmask = 0x2 << ((irq % 16) * 2);
u32 confoff = (irq / 16) * 4;
bool enabled = false;
- u32 val;
+ u32 val, oldval;
+ int ret = 0;
/*
* Read current configuration register, and insert the config
* for "irq", depending on "type".
*/
- val = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
- if (type == IRQ_TYPE_LEVEL_HIGH)
+ val = oldval = readl_relaxed(base + GIC_DIST_CONFIG + confoff);
+ if (type & IRQ_TYPE_LEVEL_MASK)
val &= ~confmask;
- else if (type == IRQ_TYPE_EDGE_RISING)
+ else if (type & IRQ_TYPE_EDGE_BOTH)
val |= confmask;
/*
@@ -54,15 +55,20 @@ void gic_configure_irq(unsigned int irq, unsigned int type,
/*
* Write back the new configuration, and possibly re-enable
- * the interrupt.
+ * the interrupt. If we tried to write a new configuration and failed,
+ * return an error.
*/
writel_relaxed(val, base + GIC_DIST_CONFIG + confoff);
+ if (readl_relaxed(base + GIC_DIST_CONFIG + confoff) != val && val != oldval)
+ ret = -EINVAL;
if (enabled)
writel_relaxed(enablemask, base + GIC_DIST_ENABLE_SET + enableoff);
if (sync_access)
sync_access();
+
+ return ret;
}
void __init gic_dist_config(void __iomem *base, int gic_irqs,
diff --git a/drivers/irqchip/irq-gic-common.h b/drivers/irqchip/irq-gic-common.h
index b41f02481c3a..35a9884778bd 100644
--- a/drivers/irqchip/irq-gic-common.h
+++ b/drivers/irqchip/irq-gic-common.h
@@ -20,7 +20,7 @@
#include <linux/of.h>
#include <linux/irqdomain.h>
-void gic_configure_irq(unsigned int irq, unsigned int type,
+int gic_configure_irq(unsigned int irq, unsigned int type,
void __iomem *base, void (*sync_access)(void));
void gic_dist_config(void __iomem *base, int gic_irqs,
void (*sync_access)(void));
diff --git a/drivers/irqchip/irq-gic-v3.c b/drivers/irqchip/irq-gic-v3.c
index 1a146ccee701..1c6dea2fbc34 100644
--- a/drivers/irqchip/irq-gic-v3.c
+++ b/drivers/irqchip/irq-gic-v3.c
@@ -238,7 +238,9 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (irq < 16)
return -EINVAL;
- if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+ /* SPIs have restrictions on the supported types */
+ if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
+ type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
if (gic_irq_in_rdist(d)) {
@@ -249,9 +251,7 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
rwp_wait = gic_dist_wait_for_rwp;
}
- gic_configure_irq(irq, type, base, rwp_wait);
-
- return 0;
+ return gic_configure_irq(irq, type, base, rwp_wait);
}
static u64 gic_mpidr_to_affinity(u64 mpidr)
@@ -481,15 +481,19 @@ out:
return tlist;
}
+#define MPIDR_TO_SGI_AFFINITY(cluster_id, level) \
+ (MPIDR_AFFINITY_LEVEL(cluster_id, level) \
+ << ICC_SGI1R_AFFINITY_## level ##_SHIFT)
+
static void gic_send_sgi(u64 cluster_id, u16 tlist, unsigned int irq)
{
u64 val;
- val = (MPIDR_AFFINITY_LEVEL(cluster_id, 3) << 48 |
- MPIDR_AFFINITY_LEVEL(cluster_id, 2) << 32 |
- irq << 24 |
- MPIDR_AFFINITY_LEVEL(cluster_id, 1) << 16 |
- tlist);
+ val = (MPIDR_TO_SGI_AFFINITY(cluster_id, 3) |
+ MPIDR_TO_SGI_AFFINITY(cluster_id, 2) |
+ irq << ICC_SGI1R_SGI_ID_SHIFT |
+ MPIDR_TO_SGI_AFFINITY(cluster_id, 1) |
+ tlist << ICC_SGI1R_TARGET_LIST_SHIFT);
pr_debug("CPU%d: ICC_SGI1R_EL1 %llx\n", smp_processor_id(), val);
gic_write_sgi1r(val);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index d617ee5a3d8a..4634cf7d0ec3 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -188,12 +188,15 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = gic_dist_base(d);
unsigned int gicirq = gic_irq(d);
+ int ret;
/* Interrupt configuration for SGIs can't be changed */
if (gicirq < 16)
return -EINVAL;
- if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+ /* SPIs have restrictions on the supported types */
+ if (gicirq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
+ type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
raw_spin_lock(&irq_controller_lock);
@@ -201,11 +204,11 @@ static int gic_set_type(struct irq_data *d, unsigned int type)
if (gic_arch_extn.irq_set_type)
gic_arch_extn.irq_set_type(d, type);
- gic_configure_irq(gicirq, type, base, NULL);
+ ret = gic_configure_irq(gicirq, type, base, NULL);
raw_spin_unlock(&irq_controller_lock);
- return 0;
+ return ret;
}
static int gic_retrigger(struct irq_data *d)
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 6bc2deb73d53..7d6ffb5de84f 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -120,21 +120,24 @@ static int hip04_irq_set_type(struct irq_data *d, unsigned int type)
{
void __iomem *base = hip04_dist_base(d);
unsigned int irq = hip04_irq(d);
+ int ret;
/* Interrupt configuration for SGIs can't be changed */
if (irq < 16)
return -EINVAL;
- if (type != IRQ_TYPE_LEVEL_HIGH && type != IRQ_TYPE_EDGE_RISING)
+ /* SPIs have restrictions on the supported types */
+ if (irq >= 32 && type != IRQ_TYPE_LEVEL_HIGH &&
+ type != IRQ_TYPE_EDGE_RISING)
return -EINVAL;
raw_spin_lock(&irq_controller_lock);
- gic_configure_irq(irq, type, base, NULL);
+ ret = gic_configure_irq(irq, type, base, NULL);
raw_spin_unlock(&irq_controller_lock);
- return 0;
+ return ret;
}
#ifdef CONFIG_SMP
diff --git a/drivers/irqchip/irq-mips-gic.c b/drivers/irqchip/irq-mips-gic.c
index 2b0468e3df6a..9acdc080e7ec 100644
--- a/drivers/irqchip/irq-mips-gic.c
+++ b/drivers/irqchip/irq-mips-gic.c
@@ -37,6 +37,7 @@ static struct irq_domain *gic_irq_domain;
static int gic_shared_intrs;
static int gic_vpes;
static unsigned int gic_cpu_pin;
+static unsigned int timer_cpu_pin;
static struct irq_chip gic_level_irq_controller, gic_edge_irq_controller;
static void __gic_irq_dispatch(void);
@@ -191,14 +192,6 @@ static bool gic_local_irq_is_routable(int intr)
}
}
-unsigned int gic_get_timer_pending(void)
-{
- unsigned int vpe_pending;
-
- vpe_pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
- return vpe_pending & GIC_VPE_PEND_TIMER_MSK;
-}
-
static void gic_bind_eic_interrupt(int irq, int set)
{
/* Convert irq vector # to hw int # */
@@ -234,9 +227,9 @@ int gic_get_c0_perfcount_int(void)
GIC_LOCAL_TO_HWIRQ(GIC_LOCAL_INT_PERFCTR));
}
-static unsigned int gic_get_int(void)
+static void gic_handle_shared_int(void)
{
- unsigned int i;
+ unsigned int i, intr, virq;
unsigned long *pcpu_mask;
unsigned long pending_reg, intrmask_reg;
DECLARE_BITMAP(pending, GIC_MAX_INTRS);
@@ -258,7 +251,16 @@ static unsigned int gic_get_int(void)
bitmap_and(pending, pending, intrmask, gic_shared_intrs);
bitmap_and(pending, pending, pcpu_mask, gic_shared_intrs);
- return find_first_bit(pending, gic_shared_intrs);
+ intr = find_first_bit(pending, gic_shared_intrs);
+ while (intr != gic_shared_intrs) {
+ virq = irq_linear_revmap(gic_irq_domain,
+ GIC_SHARED_TO_HWIRQ(intr));
+ do_IRQ(virq);
+
+ /* go to next pending bit */
+ bitmap_clear(pending, intr, 1);
+ intr = find_first_bit(pending, gic_shared_intrs);
+ }
}
static void gic_mask_irq(struct irq_data *d)
@@ -385,16 +387,26 @@ static struct irq_chip gic_edge_irq_controller = {
#endif
};
-static unsigned int gic_get_local_int(void)
+static void gic_handle_local_int(void)
{
unsigned long pending, masked;
+ unsigned int intr, virq;
pending = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_PEND));
masked = gic_read(GIC_REG(VPE_LOCAL, GIC_VPE_MASK));
bitmap_and(&pending, &pending, &masked, GIC_NUM_LOCAL_INTRS);
- return find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+ intr = find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+ while (intr != GIC_NUM_LOCAL_INTRS) {
+ virq = irq_linear_revmap(gic_irq_domain,
+ GIC_LOCAL_TO_HWIRQ(intr));
+ do_IRQ(virq);
+
+ /* go to next pending bit */
+ bitmap_clear(&pending, intr, 1);
+ intr = find_first_bit(&pending, GIC_NUM_LOCAL_INTRS);
+ }
}
static void gic_mask_local_irq(struct irq_data *d)
@@ -453,19 +465,8 @@ static struct irq_chip gic_all_vpes_local_irq_controller = {
static void __gic_irq_dispatch(void)
{
- unsigned int intr, virq;
-
- while ((intr = gic_get_local_int()) != GIC_NUM_LOCAL_INTRS) {
- virq = irq_linear_revmap(gic_irq_domain,
- GIC_LOCAL_TO_HWIRQ(intr));
- do_IRQ(virq);
- }
-
- while ((intr = gic_get_int()) != gic_shared_intrs) {
- virq = irq_linear_revmap(gic_irq_domain,
- GIC_SHARED_TO_HWIRQ(intr));
- do_IRQ(virq);
- }
+ gic_handle_local_int();
+ gic_handle_shared_int();
}
static void gic_irq_dispatch(unsigned int irq, struct irq_desc *desc)
@@ -616,6 +617,8 @@ static int gic_local_irq_domain_map(struct irq_domain *d, unsigned int virq,
gic_write(GIC_REG(VPE_OTHER, GIC_VPE_COMPARE_MAP), val);
break;
case GIC_LOCAL_INT_TIMER:
+ /* CONFIG_MIPS_CMP workaround (see __gic_init) */
+ val = GIC_MAP_TO_PIN_MSK | timer_cpu_pin;
gic_write(GIC_REG(VPE_OTHER, GIC_VPE_TIMER_MAP), val);
break;
case GIC_LOCAL_INT_PERFCTR:
@@ -713,12 +716,36 @@ static void __init __gic_init(unsigned long gic_base_addr,
if (cpu_has_veic) {
/* Always use vector 1 in EIC mode */
gic_cpu_pin = 0;
+ timer_cpu_pin = gic_cpu_pin;
set_vi_handler(gic_cpu_pin + GIC_PIN_TO_VEC_OFFSET,
__gic_irq_dispatch);
} else {
gic_cpu_pin = cpu_vec - GIC_CPU_PIN_OFFSET;
irq_set_chained_handler(MIPS_CPU_IRQ_BASE + cpu_vec,
gic_irq_dispatch);
+ /*
+ * With the CMP implementation of SMP (deprecated), other CPUs
+ * are started by the bootloader and put into a timer based
+ * waiting poll loop. We must not re-route those CPU's local
+ * timer interrupts as the wait instruction will never finish,
+ * so just handle whatever CPU interrupt it is routed to by
+ * default.
+ *
+ * This workaround should be removed when CMP support is
+ * dropped.
+ */
+ if (IS_ENABLED(CONFIG_MIPS_CMP) &&
+ gic_local_irq_is_routable(GIC_LOCAL_INT_TIMER)) {
+ timer_cpu_pin = gic_read(GIC_REG(VPE_LOCAL,
+ GIC_VPE_TIMER_MAP)) &
+ GIC_MAP_MSK;
+ irq_set_chained_handler(MIPS_CPU_IRQ_BASE +
+ GIC_CPU_PIN_OFFSET +
+ timer_cpu_pin,
+ gic_irq_dispatch);
+ } else {
+ timer_cpu_pin = gic_cpu_pin;
+ }
}
gic_irq_domain = irq_domain_add_simple(node, GIC_NUM_LOCAL_INTRS +
diff --git a/drivers/irqchip/irq-mtk-sysirq.c b/drivers/irqchip/irq-mtk-sysirq.c
index 0b0d2c00a2df..eaf0a710e98a 100644
--- a/drivers/irqchip/irq-mtk-sysirq.c
+++ b/drivers/irqchip/irq-mtk-sysirq.c
@@ -23,8 +23,6 @@
#include "irqchip.h"
-#define MT6577_SYS_INTPOL_NUM (224)
-
struct mtk_sysirq_chip_data {
spinlock_t lock;
void __iomem *intpol_base;
@@ -124,7 +122,8 @@ static int __init mtk_sysirq_of_init(struct device_node *node,
{
struct irq_domain *domain, *domain_parent;
struct mtk_sysirq_chip_data *chip_data;
- int ret = 0;
+ int ret, size, intpol_num;
+ struct resource res;
domain_parent = irq_find_host(parent);
if (!domain_parent) {
@@ -132,19 +131,24 @@ static int __init mtk_sysirq_of_init(struct device_node *node,
return -EINVAL;
}
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret)
+ return ret;
+
chip_data = kzalloc(sizeof(*chip_data), GFP_KERNEL);
if (!chip_data)
return -ENOMEM;
- chip_data->intpol_base = of_io_request_and_map(node, 0, "intpol");
- if (IS_ERR(chip_data->intpol_base)) {
+ size = resource_size(&res);
+ intpol_num = size * 8;
+ chip_data->intpol_base = ioremap(res.start, size);
+ if (!chip_data->intpol_base) {
pr_err("mtk_sysirq: unable to map sysirq register\n");
ret = PTR_ERR(chip_data->intpol_base);
goto out_free;
}
- domain = irq_domain_add_hierarchy(domain_parent, 0,
- MT6577_SYS_INTPOL_NUM, node,
+ domain = irq_domain_add_hierarchy(domain_parent, 0, intpol_num, node,
&sysirq_domain_ops, chip_data);
if (!domain) {
ret = -ENOMEM;
diff --git a/drivers/irqchip/irq-omap-intc.c b/drivers/irqchip/irq-omap-intc.c
index c03f140acbae..a569c6dbd1d1 100644
--- a/drivers/irqchip/irq-omap-intc.c
+++ b/drivers/irqchip/irq-omap-intc.c
@@ -364,14 +364,6 @@ out:
omap_ack_irq(NULL);
}
-void __init omap2_init_irq(void)
-{
- omap_nr_irqs = 96;
- omap_nr_pending = 3;
- omap_init_irq(OMAP24XX_IC_BASE, NULL);
- set_handle_irq(omap_intc_handle_irq);
-}
-
void __init omap3_init_irq(void)
{
omap_nr_irqs = 96;
@@ -380,14 +372,6 @@ void __init omap3_init_irq(void)
set_handle_irq(omap_intc_handle_irq);
}
-void __init ti81xx_init_irq(void)
-{
- omap_nr_irqs = 96;
- omap_nr_pending = 4;
- omap_init_irq(OMAP34XX_IC_BASE, NULL);
- set_handle_irq(omap_intc_handle_irq);
-}
-
static int __init intc_of_init(struct device_node *node,
struct device_node *parent)
{
@@ -399,7 +383,9 @@ static int __init intc_of_init(struct device_node *node,
if (WARN_ON(!node))
return -ENODEV;
- if (of_device_is_compatible(node, "ti,am33xx-intc")) {
+ if (of_device_is_compatible(node, "ti,dm814-intc") ||
+ of_device_is_compatible(node, "ti,dm816-intc") ||
+ of_device_is_compatible(node, "ti,am33xx-intc")) {
omap_nr_irqs = 128;
omap_nr_pending = 4;
}
@@ -415,4 +401,6 @@ static int __init intc_of_init(struct device_node *node,
IRQCHIP_DECLARE(omap2_intc, "ti,omap2-intc", intc_of_init);
IRQCHIP_DECLARE(omap3_intc, "ti,omap3-intc", intc_of_init);
+IRQCHIP_DECLARE(dm814x_intc, "ti,dm814-intc", intc_of_init);
+IRQCHIP_DECLARE(dm816x_intc, "ti,dm816-intc", intc_of_init);
IRQCHIP_DECLARE(am33xx_intc, "ti,am33xx-intc", intc_of_init);
diff --git a/drivers/irqchip/irq-renesas-intc-irqpin.c b/drivers/irqchip/irq-renesas-intc-irqpin.c
index 078cac5e2d08..9a0767b9c89d 100644
--- a/drivers/irqchip/irq-renesas-intc-irqpin.c
+++ b/drivers/irqchip/irq-renesas-intc-irqpin.c
@@ -30,6 +30,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/of_device.h>
#include <linux/platform_data/irq-renesas-intc-irqpin.h>
#include <linux/pm_runtime.h>
@@ -40,7 +41,9 @@
#define INTC_IRQPIN_REG_SOURCE 2 /* INTREQnn */
#define INTC_IRQPIN_REG_MASK 3 /* INTMSKnn */
#define INTC_IRQPIN_REG_CLEAR 4 /* INTMSKCLRnn */
-#define INTC_IRQPIN_REG_NR 5
+#define INTC_IRQPIN_REG_NR_MANDATORY 5
+#define INTC_IRQPIN_REG_IRLM 5 /* ICR0 with IRLM bit (optional) */
+#define INTC_IRQPIN_REG_NR 6
/* INTC external IRQ PIN hardware register access:
*
@@ -82,6 +85,10 @@ struct intc_irqpin_priv {
u8 shared_irq_mask;
};
+struct intc_irqpin_irlm_config {
+ unsigned int irlm_bit;
+};
+
static unsigned long intc_irqpin_read32(void __iomem *iomem)
{
return ioread32(iomem);
@@ -345,10 +352,23 @@ static struct irq_domain_ops intc_irqpin_irq_domain_ops = {
.xlate = irq_domain_xlate_twocell,
};
+static const struct intc_irqpin_irlm_config intc_irqpin_irlm_r8a7779 = {
+ .irlm_bit = 23, /* ICR0.IRLM0 */
+};
+
+static const struct of_device_id intc_irqpin_dt_ids[] = {
+ { .compatible = "renesas,intc-irqpin", },
+ { .compatible = "renesas,intc-irqpin-r8a7779",
+ .data = &intc_irqpin_irlm_r8a7779 },
+ {},
+};
+MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
+
static int intc_irqpin_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct renesas_intc_irqpin_config *pdata = dev->platform_data;
+ const struct of_device_id *of_id;
struct intc_irqpin_priv *p;
struct intc_irqpin_iomem *i;
struct resource *io[INTC_IRQPIN_REG_NR];
@@ -391,10 +411,11 @@ static int intc_irqpin_probe(struct platform_device *pdev)
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
- /* get hold of manadatory IOMEM */
+ /* get hold of register banks */
+ memset(io, 0, sizeof(io));
for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
io[k] = platform_get_resource(pdev, IORESOURCE_MEM, k);
- if (!io[k]) {
+ if (!io[k] && k < INTC_IRQPIN_REG_NR_MANDATORY) {
dev_err(dev, "not enough IOMEM resources\n");
ret = -EINVAL;
goto err0;
@@ -422,6 +443,10 @@ static int intc_irqpin_probe(struct platform_device *pdev)
for (k = 0; k < INTC_IRQPIN_REG_NR; k++) {
i = &p->iomem[k];
+ /* handle optional registers */
+ if (!io[k])
+ continue;
+
switch (resource_size(io[k])) {
case 1:
i->width = 8;
@@ -448,6 +473,19 @@ static int intc_irqpin_probe(struct platform_device *pdev)
}
}
+ /* configure "individual IRQ mode" where needed */
+ of_id = of_match_device(intc_irqpin_dt_ids, dev);
+ if (of_id && of_id->data) {
+ const struct intc_irqpin_irlm_config *irlm_config = of_id->data;
+
+ if (io[INTC_IRQPIN_REG_IRLM])
+ intc_irqpin_read_modify_write(p, INTC_IRQPIN_REG_IRLM,
+ irlm_config->irlm_bit,
+ 1, 1);
+ else
+ dev_warn(dev, "unable to select IRLM mode\n");
+ }
+
/* mask all interrupts using priority */
for (k = 0; k < p->number_of_irqs; k++)
intc_irqpin_mask_unmask_prio(p, k, 1);
@@ -550,12 +588,6 @@ static int intc_irqpin_remove(struct platform_device *pdev)
return 0;
}
-static const struct of_device_id intc_irqpin_dt_ids[] = {
- { .compatible = "renesas,intc-irqpin", },
- {},
-};
-MODULE_DEVICE_TABLE(of, intc_irqpin_dt_ids);
-
static struct platform_driver intc_irqpin_device_driver = {
.probe = intc_irqpin_probe,
.remove = intc_irqpin_remove,
diff --git a/drivers/isdn/hardware/eicon/message.c b/drivers/isdn/hardware/eicon/message.c
index 0b380603a578..d7c286656a25 100644
--- a/drivers/isdn/hardware/eicon/message.c
+++ b/drivers/isdn/hardware/eicon/message.c
@@ -1474,7 +1474,7 @@ static byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
add_ai(plci, &parms[5]);
sig_req(plci, REJECT, 0);
}
- else if (Reject == 1 || Reject > 9)
+ else if (Reject == 1 || Reject >= 9)
{
add_ai(plci, &parms[5]);
sig_req(plci, HANGUP, 0);
diff --git a/drivers/isdn/hardware/mISDN/Kconfig b/drivers/isdn/hardware/mISDN/Kconfig
index b8611e3e5e74..09df54fc1fef 100644
--- a/drivers/isdn/hardware/mISDN/Kconfig
+++ b/drivers/isdn/hardware/mISDN/Kconfig
@@ -24,7 +24,7 @@ config MISDN_HFCMULTI
* HFC-E1 (E1 interface for 2Mbit ISDN)
config MISDN_HFCMULTI_8xx
- boolean "Support for XHFC embedded board in HFC multiport driver"
+ bool "Support for XHFC embedded board in HFC multiport driver"
depends on MISDN
depends on MISDN_HFCMULTI
depends on 8xx
diff --git a/drivers/isdn/hardware/mISDN/mISDNipac.c b/drivers/isdn/hardware/mISDN/mISDNipac.c
index ccd7d851be26..a77eea594b69 100644
--- a/drivers/isdn/hardware/mISDN/mISDNipac.c
+++ b/drivers/isdn/hardware/mISDN/mISDNipac.c
@@ -754,10 +754,10 @@ dbusy_timer_handler(struct isac_hw *isac)
}
static int
-open_dchannel(struct isac_hw *isac, struct channel_req *rq)
+open_dchannel_caller(struct isac_hw *isac, struct channel_req *rq, void *caller)
{
pr_debug("%s: %s dev(%d) open from %p\n", isac->name, __func__,
- isac->dch.dev.id, __builtin_return_address(1));
+ isac->dch.dev.id, caller);
if (rq->protocol != ISDN_P_TE_S0)
return -EINVAL;
if (rq->adr.channel == 1)
@@ -771,6 +771,12 @@ open_dchannel(struct isac_hw *isac, struct channel_req *rq)
return 0;
}
+static int
+open_dchannel(struct isac_hw *isac, struct channel_req *rq)
+{
+ return open_dchannel_caller(isac, rq, __builtin_return_address(0));
+}
+
static const char *ISACVer[] =
{"2086/2186 V1.1", "2085 B1", "2085 B2",
"2085 V2.3"};
@@ -1548,7 +1554,7 @@ ipac_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
case OPEN_CHANNEL:
rq = arg;
if (rq->protocol == ISDN_P_TE_S0)
- err = open_dchannel(isac, rq);
+ err = open_dchannel_caller(isac, rq, __builtin_return_address(0));
else
err = open_bchannel(ipac, rq);
if (err)
diff --git a/drivers/isdn/hardware/mISDN/w6692.c b/drivers/isdn/hardware/mISDN/w6692.c
index de69f6828c76..741675525b53 100644
--- a/drivers/isdn/hardware/mISDN/w6692.c
+++ b/drivers/isdn/hardware/mISDN/w6692.c
@@ -1176,10 +1176,10 @@ w6692_l1callback(struct dchannel *dch, u32 cmd)
}
static int
-open_dchannel(struct w6692_hw *card, struct channel_req *rq)
+open_dchannel(struct w6692_hw *card, struct channel_req *rq, void *caller)
{
pr_debug("%s: %s dev(%d) open from %p\n", card->name, __func__,
- card->dch.dev.id, __builtin_return_address(1));
+ card->dch.dev.id, caller);
if (rq->protocol != ISDN_P_TE_S0)
return -EINVAL;
if (rq->adr.channel == 1)
@@ -1207,7 +1207,7 @@ w6692_dctrl(struct mISDNchannel *ch, u32 cmd, void *arg)
case OPEN_CHANNEL:
rq = arg;
if (rq->protocol == ISDN_P_TE_S0)
- err = open_dchannel(card, rq);
+ err = open_dchannel(card, rq, __builtin_return_address(0));
else
err = open_bchannel(card, rq);
if (err)
diff --git a/drivers/isdn/hisax/hfc4s8s_l1.c b/drivers/isdn/hisax/hfc4s8s_l1.c
index fc9f9d03fa13..0e5d673871c0 100644
--- a/drivers/isdn/hisax/hfc4s8s_l1.c
+++ b/drivers/isdn/hisax/hfc4s8s_l1.c
@@ -225,20 +225,6 @@ fWrite_hfc8(hfc4s8s_hw *a, u_char c)
}
static inline void
-Write_hfc16(hfc4s8s_hw *a, u_char b, u_short c)
-{
- SetRegAddr(a, b);
- outw(c, a->iobase);
-}
-
-static inline void
-Write_hfc32(hfc4s8s_hw *a, u_char b, u_long c)
-{
- SetRegAddr(a, b);
- outl(c, a->iobase);
-}
-
-static inline void
fWrite_hfc32(hfc4s8s_hw *a, u_long c)
{
outl(c, a->iobase);
@@ -266,13 +252,6 @@ Read_hfc16(hfc4s8s_hw *a, u_char b)
}
static inline u_long
-Read_hfc32(hfc4s8s_hw *a, u_char b)
-{
- SetRegAddr(a, b);
- return (inl((volatile u_int) a->iobase));
-}
-
-static inline u_long
fRead_hfc32(hfc4s8s_hw *a)
{
return (inl((volatile u_int) a->iobase));
diff --git a/drivers/isdn/isdnloop/isdnloop.c b/drivers/isdn/isdnloop/isdnloop.c
index 5a4da94aefb0..ef9c8e4f1fa2 100644
--- a/drivers/isdn/isdnloop/isdnloop.c
+++ b/drivers/isdn/isdnloop/isdnloop.c
@@ -59,7 +59,8 @@ isdnloop_bchan_send(isdnloop_card *card, int ch)
isdn_ctrl cmd;
while (card->sndcount[ch]) {
- if ((skb = skb_dequeue(&card->bqueue[ch]))) {
+ skb = skb_dequeue(&card->bqueue[ch]);
+ if (skb) {
len = skb->len;
card->sndcount[ch] -= len;
ack = *(skb->head); /* used as scratch area */
@@ -149,8 +150,7 @@ typedef struct isdnloop_stat {
int action;
} isdnloop_stat;
/* *INDENT-OFF* */
-static isdnloop_stat isdnloop_stat_table[] =
-{
+static isdnloop_stat isdnloop_stat_table[] = {
{"BCON_", ISDN_STAT_BCONN, 1}, /* B-Channel connected */
{"BDIS_", ISDN_STAT_BHUP, 2}, /* B-Channel disconnected */
{"DCON_", ISDN_STAT_DCONN, 0}, /* D-Channel connected */
@@ -317,7 +317,8 @@ isdnloop_polldchan(unsigned long data)
u_char *p;
isdn_ctrl cmd;
- if ((skb = skb_dequeue(&card->dqueue)))
+ skb = skb_dequeue(&card->dqueue);
+ if (skb)
avail = skb->len;
else
avail = 0;
@@ -471,8 +472,8 @@ isdnloop_fake(isdnloop_card *card, char *s, int ch)
{
struct sk_buff *skb;
int len = strlen(s) + ((ch >= 0) ? 3 : 0);
-
- if (!(skb = dev_alloc_skb(len))) {
+ skb = dev_alloc_skb(len);
+ if (!skb) {
printk(KERN_WARNING "isdnloop: Out of memory in isdnloop_fake\n");
return 1;
}
@@ -483,8 +484,7 @@ isdnloop_fake(isdnloop_card *card, char *s, int ch)
return 0;
}
/* *INDENT-OFF* */
-static isdnloop_stat isdnloop_cmd_table[] =
-{
+static isdnloop_stat isdnloop_cmd_table[] = {
{"BCON_R", 0, 1}, /* B-Channel connect */
{"BCON_I", 0, 17}, /* B-Channel connect ind */
{"BDIS_R", 0, 2}, /* B-Channel disconnect */
@@ -525,10 +525,8 @@ isdnloop_fake_err(isdnloop_card *card)
isdnloop_fake(card, "NAK", -1);
}
-static u_char ctable_eu[] =
-{0x00, 0x11, 0x01, 0x12};
-static u_char ctable_1t[] =
-{0x00, 0x3b, 0x01, 0x3a};
+static u_char ctable_eu[] = {0x00, 0x11, 0x01, 0x12};
+static u_char ctable_1t[] = {0x00, 0x3b, 0x01, 0x3a};
/*
* Assemble a simplified cause message depending on the
@@ -554,9 +552,9 @@ isdnloop_unicause(isdnloop_card *card, int loc, int cau)
sprintf(buf, "%02X44", ctable_1t[cau]);
break;
default:
- return ("0000");
+ return "0000";
}
- return (buf);
+ return buf;
}
/*
@@ -647,10 +645,8 @@ isdnloop_kill_ctimer(isdnloop_card *card, int ch)
spin_unlock_irqrestore(&card->isdnloop_lock, flags);
}
-static u_char si2bit[] =
-{0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
-static u_char bit2si[] =
-{1, 5, 7};
+static u_char si2bit[] = {0, 1, 0, 0, 0, 2, 0, 4, 0, 0};
+static u_char bit2si[] = {1, 5, 7};
/*
* Try finding a listener for an outgoing call.
@@ -754,17 +750,17 @@ isdnloop_vstphone(isdnloop_card *card, char *phone, int caller)
if (caller) {
for (i = 0; i < 2; i++)
if (!(strcmp(card->s0num[i], phone)))
- return (phone);
- return (card->s0num[0]);
+ return phone;
+ return card->s0num[0];
}
- return (phone);
+ return phone;
break;
case ISDN_PTYPE_1TR6:
if (caller) {
sprintf(nphone, "%s%c", card->s0num[0], phone[0]);
- return (nphone);
+ return nphone;
} else
- return (&phone[strlen(phone) - 1]);
+ return &phone[strlen(phone) - 1];
break;
}
return "";
@@ -1148,14 +1144,14 @@ isdnloop_command(isdn_ctrl *c, isdnloop_card *card)
case ISDNLOOP_IOCTL_STARTUP:
if (!access_ok(VERIFY_READ, (void *) a, sizeof(isdnloop_sdef)))
return -EFAULT;
- return (isdnloop_start(card, (isdnloop_sdef *) a));
+ return isdnloop_start(card, (isdnloop_sdef *) a);
break;
case ISDNLOOP_IOCTL_ADDCARD:
if (copy_from_user((char *)&cdef,
(char *)a,
sizeof(cdef)))
return -EFAULT;
- return (isdnloop_addcard(cdef.id1));
+ return isdnloop_addcard(cdef.id1);
break;
case ISDNLOOP_IOCTL_LEASEDCFG:
if (a) {
@@ -1377,7 +1373,7 @@ if_command(isdn_ctrl *c)
isdnloop_card *card = isdnloop_findcard(c->driver);
if (card)
- return (isdnloop_command(c, card));
+ return isdnloop_command(c, card);
printk(KERN_ERR
"isdnloop: if_command called with invalid driverId!\n");
return -ENODEV;
@@ -1391,7 +1387,7 @@ if_writecmd(const u_char __user *buf, int len, int id, int channel)
if (card) {
if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
- return (isdnloop_writecmd(buf, len, 1, card));
+ return isdnloop_writecmd(buf, len, 1, card);
}
printk(KERN_ERR
"isdnloop: if_writecmd called with invalid driverId!\n");
@@ -1406,7 +1402,7 @@ if_readstatus(u_char __user *buf, int len, int id, int channel)
if (card) {
if (!(card->flags & ISDNLOOP_FLAGS_RUNNING))
return -ENODEV;
- return (isdnloop_readstatus(buf, len, card));
+ return isdnloop_readstatus(buf, len, card);
}
printk(KERN_ERR
"isdnloop: if_readstatus called with invalid driverId!\n");
@@ -1423,7 +1419,7 @@ if_sendbuf(int id, int channel, int ack, struct sk_buff *skb)
return -ENODEV;
/* ack request stored in skb scratch area */
*(skb->head) = ack;
- return (isdnloop_sendbuf(channel, skb, card));
+ return isdnloop_sendbuf(channel, skb, card);
}
printk(KERN_ERR
"isdnloop: if_sendbuf called with invalid driverId!\n");
@@ -1439,8 +1435,8 @@ isdnloop_initcard(char *id)
{
isdnloop_card *card;
int i;
-
- if (!(card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL))) {
+ card = kzalloc(sizeof(isdnloop_card), GFP_KERNEL);
+ if (!card) {
printk(KERN_WARNING
"isdnloop: (%s) Could not allocate card-struct.\n", id);
return (isdnloop_card *) 0;
@@ -1489,8 +1485,8 @@ static int
isdnloop_addcard(char *id1)
{
isdnloop_card *card;
-
- if (!(card = isdnloop_initcard(id1))) {
+ card = isdnloop_initcard(id1);
+ if (!card) {
return -EIO;
}
printk(KERN_INFO
@@ -1503,7 +1499,7 @@ static int __init
isdnloop_init(void)
{
if (isdnloop_id)
- return (isdnloop_addcard(isdnloop_id));
+ return isdnloop_addcard(isdnloop_id);
return 0;
}
diff --git a/drivers/isdn/sc/init.c b/drivers/isdn/sc/init.c
index d6f19b168e8a..3597ef47b28a 100644
--- a/drivers/isdn/sc/init.c
+++ b/drivers/isdn/sc/init.c
@@ -30,7 +30,7 @@ static const char *boardname[] = { "DataCommute/BRI", "DataCommute/PRI", "TeleCo
static unsigned int io[] = {0, 0, 0, 0};
static unsigned char irq[] = {0, 0, 0, 0};
static unsigned long ram[] = {0, 0, 0, 0};
-static bool do_reset = 0;
+static bool do_reset;
module_param_array(io, int, NULL, 0);
module_param_array(irq, byte, NULL, 0);
@@ -104,13 +104,12 @@ static int __init sc_init(void)
io[b] + 0x400 * EXP_PAGE0);
continue;
}
- }
- else {
+ } else {
/*
* Yes, probe for I/O Base
*/
if (probe_exhasted) {
- pr_debug("All probe addresses exhasted, skipping\n");
+ pr_debug("All probe addresses exhausted, skipping\n");
continue;
}
pr_debug("Probing for I/O...\n");
@@ -169,8 +168,7 @@ static int __init sc_init(void)
model = identify_board(ram[b], io[b]);
release_region(ram[b], SRAM_PAGESIZE);
}
- }
- else {
+ } else {
/*
* Yes, probe for free RAM and look for
* a signature and id the board model
@@ -187,7 +185,7 @@ static int __init sc_init(void)
ram[b] = i;
break;
}
- pr_debug(" Unidentifed or inaccessible\n");
+ pr_debug(" Unidentified or inaccessible\n");
continue;
}
pr_debug(" request failed\n");
@@ -337,8 +335,7 @@ static int __init sc_init(void)
sc_adapter[cinst]->interrupt = irq[b];
if (request_irq(sc_adapter[cinst]->interrupt, interrupt_handler,
0, interface->id,
- (void *)(unsigned long) cinst))
- {
+ (void *)(unsigned long) cinst)) {
kfree(sc_adapter[cinst]->channel);
indicate_status(cinst, ISDN_STAT_UNLOAD, 0, NULL); /* Fix me */
kfree(interface);
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
index a6c3d2f153f3..25b320d64e26 100644
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -22,6 +22,16 @@ config LEDS_CLASS
This option enables the led sysfs class in /sys/class/leds. You'll
need this to do anything useful with LEDs. If unsure, say N.
+config LEDS_CLASS_FLASH
+ tristate "LED Flash Class Support"
+ depends on LEDS_CLASS
+ help
+ This option enables the flash led sysfs class in /sys/class/leds.
+ It wrapps LED Class and adds flash LEDs specific sysfs attributes
+ and kernel internal API to it. You'll need this to provide support
+ for the flash related features of a LED device. It can be built
+ as a module.
+
comment "LED drivers"
config LEDS_88PM860X
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
index 1c65a191d907..cbba921b6f1c 100644
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -2,6 +2,7 @@
# LED Core
obj-$(CONFIG_NEW_LEDS) += led-core.o
obj-$(CONFIG_LEDS_CLASS) += led-class.o
+obj-$(CONFIG_LEDS_CLASS_FLASH) += led-class-flash.o
obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o
# LED Platform Drivers
diff --git a/drivers/leds/led-class-flash.c b/drivers/leds/led-class-flash.c
new file mode 100644
index 000000000000..4a19fd44f93f
--- /dev/null
+++ b/drivers/leds/led-class-flash.c
@@ -0,0 +1,486 @@
+/*
+ * LED Flash class interface
+ *
+ * Copyright (C) 2015 Samsung Electronics Co., Ltd.
+ * Author: Jacek Anaszewski <j.anaszewski@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/led-class-flash.h>
+#include <linux/leds.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "leds.h"
+
+#define has_flash_op(fled_cdev, op) \
+ (fled_cdev && fled_cdev->ops->op)
+
+#define call_flash_op(fled_cdev, op, args...) \
+ ((has_flash_op(fled_cdev, op)) ? \
+ (fled_cdev->ops->op(fled_cdev, args)) : \
+ -EINVAL)
+
+static const char * const led_flash_fault_names[] = {
+ "led-over-voltage",
+ "flash-timeout-exceeded",
+ "controller-over-temperature",
+ "controller-short-circuit",
+ "led-power-supply-over-current",
+ "indicator-led-fault",
+ "led-under-voltage",
+ "controller-under-voltage",
+ "led-over-temperature",
+};
+
+static ssize_t flash_brightness_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ unsigned long state;
+ ssize_t ret;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ goto unlock;
+
+ ret = led_set_flash_brightness(fled_cdev, state);
+ if (ret < 0)
+ goto unlock;
+
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
+}
+
+static ssize_t flash_brightness_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+ /* no lock needed for this */
+ led_update_flash_brightness(fled_cdev);
+
+ return sprintf(buf, "%u\n", fled_cdev->brightness.val);
+}
+static DEVICE_ATTR_RW(flash_brightness);
+
+static ssize_t max_flash_brightness_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+ return sprintf(buf, "%u\n", fled_cdev->brightness.max);
+}
+static DEVICE_ATTR_RO(max_flash_brightness);
+
+static ssize_t flash_strobe_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ unsigned long state;
+ ssize_t ret = -EINVAL;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = kstrtoul(buf, 10, &state);
+ if (ret)
+ goto unlock;
+
+ if (state < 0 || state > 1) {
+ ret = -EINVAL;
+ goto unlock;
+ }
+
+ ret = led_set_flash_strobe(fled_cdev, state);
+ if (ret < 0)
+ goto unlock;
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
+}
+
+static ssize_t flash_strobe_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ bool state;
+ int ret;
+
+ /* no lock needed for this */
+ ret = led_get_flash_strobe(fled_cdev, &state);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%u\n", state);
+}
+static DEVICE_ATTR_RW(flash_strobe);
+
+static ssize_t flash_timeout_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ unsigned long flash_timeout;
+ ssize_t ret;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = kstrtoul(buf, 10, &flash_timeout);
+ if (ret)
+ goto unlock;
+
+ ret = led_set_flash_timeout(fled_cdev, flash_timeout);
+ if (ret < 0)
+ goto unlock;
+
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
+}
+
+static ssize_t flash_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+ return sprintf(buf, "%u\n", fled_cdev->timeout.val);
+}
+static DEVICE_ATTR_RW(flash_timeout);
+
+static ssize_t max_flash_timeout_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+ return sprintf(buf, "%u\n", fled_cdev->timeout.max);
+}
+static DEVICE_ATTR_RO(max_flash_timeout);
+
+static ssize_t flash_fault_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ u32 fault, mask = 0x1;
+ char *pbuf = buf;
+ int i, ret, buf_len;
+
+ ret = led_get_flash_fault(fled_cdev, &fault);
+ if (ret < 0)
+ return -EINVAL;
+
+ *buf = '\0';
+
+ for (i = 0; i < LED_NUM_FLASH_FAULTS; ++i) {
+ if (fault & mask) {
+ buf_len = sprintf(pbuf, "%s ",
+ led_flash_fault_names[i]);
+ pbuf += buf_len;
+ }
+ mask <<= 1;
+ }
+
+ return sprintf(buf, "%s\n", buf);
+}
+static DEVICE_ATTR_RO(flash_fault);
+
+static ssize_t available_sync_leds_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ char *pbuf = buf;
+ int i, buf_len;
+
+ buf_len = sprintf(pbuf, "[0: none] ");
+ pbuf += buf_len;
+
+ for (i = 0; i < fled_cdev->num_sync_leds; ++i) {
+ buf_len = sprintf(pbuf, "[%d: %s] ", i + 1,
+ fled_cdev->sync_leds[i]->led_cdev.name);
+ pbuf += buf_len;
+ }
+
+ return sprintf(buf, "%s\n", buf);
+}
+static DEVICE_ATTR_RO(available_sync_leds);
+
+static ssize_t flash_sync_strobe_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t size)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ unsigned long led_id;
+ ssize_t ret;
+
+ mutex_lock(&led_cdev->led_access);
+
+ if (led_sysfs_is_disabled(led_cdev)) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ ret = kstrtoul(buf, 10, &led_id);
+ if (ret)
+ goto unlock;
+
+ if (led_id > fled_cdev->num_sync_leds) {
+ ret = -ERANGE;
+ goto unlock;
+ }
+
+ fled_cdev->sync_led_id = led_id;
+
+ ret = size;
+unlock:
+ mutex_unlock(&led_cdev->led_access);
+ return ret;
+}
+
+static ssize_t flash_sync_strobe_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+ int sled_id = fled_cdev->sync_led_id;
+ char *sync_led_name = "none";
+
+ if (fled_cdev->sync_led_id > 0)
+ sync_led_name = (char *)
+ fled_cdev->sync_leds[sled_id - 1]->led_cdev.name;
+
+ return sprintf(buf, "[%d: %s]\n", sled_id, sync_led_name);
+}
+static DEVICE_ATTR_RW(flash_sync_strobe);
+
+static struct attribute *led_flash_strobe_attrs[] = {
+ &dev_attr_flash_strobe.attr,
+ NULL,
+};
+
+static struct attribute *led_flash_timeout_attrs[] = {
+ &dev_attr_flash_timeout.attr,
+ &dev_attr_max_flash_timeout.attr,
+ NULL,
+};
+
+static struct attribute *led_flash_brightness_attrs[] = {
+ &dev_attr_flash_brightness.attr,
+ &dev_attr_max_flash_brightness.attr,
+ NULL,
+};
+
+static struct attribute *led_flash_fault_attrs[] = {
+ &dev_attr_flash_fault.attr,
+ NULL,
+};
+
+static struct attribute *led_flash_sync_strobe_attrs[] = {
+ &dev_attr_available_sync_leds.attr,
+ &dev_attr_flash_sync_strobe.attr,
+ NULL,
+};
+
+static const struct attribute_group led_flash_strobe_group = {
+ .attrs = led_flash_strobe_attrs,
+};
+
+static const struct attribute_group led_flash_timeout_group = {
+ .attrs = led_flash_timeout_attrs,
+};
+
+static const struct attribute_group led_flash_brightness_group = {
+ .attrs = led_flash_brightness_attrs,
+};
+
+static const struct attribute_group led_flash_fault_group = {
+ .attrs = led_flash_fault_attrs,
+};
+
+static const struct attribute_group led_flash_sync_strobe_group = {
+ .attrs = led_flash_sync_strobe_attrs,
+};
+
+static void led_flash_resume(struct led_classdev *led_cdev)
+{
+ struct led_classdev_flash *fled_cdev = lcdev_to_flcdev(led_cdev);
+
+ call_flash_op(fled_cdev, flash_brightness_set,
+ fled_cdev->brightness.val);
+ call_flash_op(fled_cdev, timeout_set, fled_cdev->timeout.val);
+}
+
+static void led_flash_init_sysfs_groups(struct led_classdev_flash *fled_cdev)
+{
+ struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ const struct led_flash_ops *ops = fled_cdev->ops;
+ const struct attribute_group **flash_groups = fled_cdev->sysfs_groups;
+
+ int num_sysfs_groups = 0;
+
+ flash_groups[num_sysfs_groups++] = &led_flash_strobe_group;
+
+ if (ops->flash_brightness_set)
+ flash_groups[num_sysfs_groups++] = &led_flash_brightness_group;
+
+ if (ops->timeout_set)
+ flash_groups[num_sysfs_groups++] = &led_flash_timeout_group;
+
+ if (ops->fault_get)
+ flash_groups[num_sysfs_groups++] = &led_flash_fault_group;
+
+ if (led_cdev->flags & LED_DEV_CAP_SYNC_STROBE)
+ flash_groups[num_sysfs_groups++] = &led_flash_sync_strobe_group;
+
+ led_cdev->groups = flash_groups;
+}
+
+int led_classdev_flash_register(struct device *parent,
+ struct led_classdev_flash *fled_cdev)
+{
+ struct led_classdev *led_cdev;
+ const struct led_flash_ops *ops;
+ int ret;
+
+ if (!fled_cdev)
+ return -EINVAL;
+
+ led_cdev = &fled_cdev->led_cdev;
+
+ if (led_cdev->flags & LED_DEV_CAP_FLASH) {
+ if (!led_cdev->brightness_set_sync)
+ return -EINVAL;
+
+ ops = fled_cdev->ops;
+ if (!ops || !ops->strobe_set)
+ return -EINVAL;
+
+ led_cdev->flash_resume = led_flash_resume;
+
+ /* Select the sysfs attributes to be created for the device */
+ led_flash_init_sysfs_groups(fled_cdev);
+ }
+
+ /* Register led class device */
+ ret = led_classdev_register(parent, led_cdev);
+ if (ret < 0)
+ return ret;
+
+ /* Setting a torch brightness needs to have immediate effect */
+ led_cdev->flags &= ~SET_BRIGHTNESS_ASYNC;
+ led_cdev->flags |= SET_BRIGHTNESS_SYNC;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(led_classdev_flash_register);
+
+void led_classdev_flash_unregister(struct led_classdev_flash *fled_cdev)
+{
+ if (!fled_cdev)
+ return;
+
+ led_classdev_unregister(&fled_cdev->led_cdev);
+}
+EXPORT_SYMBOL_GPL(led_classdev_flash_unregister);
+
+static void led_clamp_align(struct led_flash_setting *s)
+{
+ u32 v, offset;
+
+ v = s->val + s->step / 2;
+ v = clamp(v, s->min, s->max);
+ offset = v - s->min;
+ offset = s->step * (offset / s->step);
+ s->val = s->min + offset;
+}
+
+int led_set_flash_timeout(struct led_classdev_flash *fled_cdev, u32 timeout)
+{
+ struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ struct led_flash_setting *s = &fled_cdev->timeout;
+
+ s->val = timeout;
+ led_clamp_align(s);
+
+ if (!(led_cdev->flags & LED_SUSPENDED))
+ return call_flash_op(fled_cdev, timeout_set, s->val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(led_set_flash_timeout);
+
+int led_get_flash_fault(struct led_classdev_flash *fled_cdev, u32 *fault)
+{
+ return call_flash_op(fled_cdev, fault_get, fault);
+}
+EXPORT_SYMBOL_GPL(led_get_flash_fault);
+
+int led_set_flash_brightness(struct led_classdev_flash *fled_cdev,
+ u32 brightness)
+{
+ struct led_classdev *led_cdev = &fled_cdev->led_cdev;
+ struct led_flash_setting *s = &fled_cdev->brightness;
+
+ s->val = brightness;
+ led_clamp_align(s);
+
+ if (!(led_cdev->flags & LED_SUSPENDED))
+ return call_flash_op(fled_cdev, flash_brightness_set, s->val);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(led_set_flash_brightness);
+
+int led_update_flash_brightness(struct led_classdev_flash *fled_cdev)
+{
+ struct led_flash_setting *s = &fled_cdev->brightness;
+ u32 brightness;
+
+ if (has_flash_op(fled_cdev, flash_brightness_get)) {
+ int ret = call_flash_op(fled_cdev, flash_brightness_get,
+ &brightness);
+ if (ret < 0)
+ return ret;
+
+ s->val = brightness;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(led_update_flash_brightness);
+
+MODULE_AUTHOR("Jacek Anaszewski <j.anaszewski@samsung.com>");
+MODULE_DESCRIPTION("LED Flash class interface");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c
index dbeebac38d31..795ec994c663 100644
--- a/drivers/leds/led-class.c
+++ b/drivers/leds/led-class.c
@@ -179,6 +179,10 @@ EXPORT_SYMBOL_GPL(led_classdev_suspend);
void led_classdev_resume(struct led_classdev *led_cdev)
{
led_cdev->brightness_set(led_cdev, led_cdev->brightness);
+
+ if (led_cdev->flash_resume)
+ led_cdev->flash_resume(led_cdev);
+
led_cdev->flags &= ~LED_SUSPENDED;
}
EXPORT_SYMBOL_GPL(led_classdev_resume);
@@ -239,9 +243,8 @@ int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)
INIT_WORK(&led_cdev->set_brightness_work, set_brightness_delayed);
- init_timer(&led_cdev->blink_timer);
- led_cdev->blink_timer.function = led_timer_function;
- led_cdev->blink_timer.data = (unsigned long)led_cdev;
+ setup_timer(&led_cdev->blink_timer, led_timer_function,
+ (unsigned long)led_cdev);
#ifdef CONFIG_LEDS_TRIGGERS
led_trigger_set_default(led_cdev);
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index 7ea1ea42c2d2..d26af0a79a90 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -187,6 +187,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
led.gpiod = devm_get_gpiod_from_child(dev, child);
if (IS_ERR(led.gpiod)) {
fwnode_handle_put(child);
+ ret = PTR_ERR(led.gpiod);
goto err;
}
@@ -229,7 +230,7 @@ static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
err:
for (count = priv->num_leds - 2; count >= 0; count--)
delete_gpio_led(&priv->leds[count]);
- return ERR_PTR(-ENODEV);
+ return ERR_PTR(ret);
}
static const struct of_device_id of_gpio_leds_match[] = {
diff --git a/drivers/leds/leds-mc13783.c b/drivers/leds/leds-mc13783.c
index 85c3714e1b5a..e2b847fe22a1 100644
--- a/drivers/leds/leds-mc13783.c
+++ b/drivers/leds/leds-mc13783.c
@@ -134,9 +134,7 @@ static struct mc13xxx_leds_platform_data __init *mc13xxx_led_probe_dt(
if (!pdata)
return ERR_PTR(-ENOMEM);
- of_node_get(dev->parent->of_node);
-
- parent = of_find_node_by_name(dev->parent->of_node, "leds");
+ parent = of_get_child_by_name(dev->parent->of_node, "leds");
if (!parent)
goto out_node_put;
diff --git a/drivers/leds/leds.h b/drivers/leds/leds.h
index 2348dbda5269..79efe57c7405 100644
--- a/drivers/leds/leds.h
+++ b/drivers/leds/leds.h
@@ -20,7 +20,8 @@
static inline void led_set_brightness_async(struct led_classdev *led_cdev,
enum led_brightness value)
{
- led_cdev->brightness = min(value, led_cdev->max_brightness);
+ value = min(value, led_cdev->max_brightness);
+ led_cdev->brightness = value;
if (!(led_cdev->flags & LED_SUSPENDED))
led_cdev->brightness_set(led_cdev, value);
diff --git a/drivers/lguest/Makefile b/drivers/lguest/Makefile
index c4197503900e..16f52ee73994 100644
--- a/drivers/lguest/Makefile
+++ b/drivers/lguest/Makefile
@@ -1,6 +1,3 @@
-# Guest requires the device configuration and probing code.
-obj-$(CONFIG_LGUEST_GUEST) += lguest_device.o
-
# Host requires the other files, which can be a module.
obj-$(CONFIG_LGUEST) += lg.o
lg-y = core.o hypercalls.o page_tables.o interrupts_and_traps.o \
diff --git a/drivers/lguest/core.c b/drivers/lguest/core.c
index 6590558d1d31..7dc93aa004c8 100644
--- a/drivers/lguest/core.c
+++ b/drivers/lguest/core.c
@@ -208,6 +208,14 @@ void __lgwrite(struct lg_cpu *cpu, unsigned long addr, const void *b,
*/
int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
{
+ /* If the launcher asked for a register with LHREQ_GETREG */
+ if (cpu->reg_read) {
+ if (put_user(*cpu->reg_read, user))
+ return -EFAULT;
+ cpu->reg_read = NULL;
+ return sizeof(*cpu->reg_read);
+ }
+
/* We stop running once the Guest is dead. */
while (!cpu->lg->dead) {
unsigned int irq;
@@ -217,21 +225,12 @@ int run_guest(struct lg_cpu *cpu, unsigned long __user *user)
if (cpu->hcall)
do_hypercalls(cpu);
- /*
- * It's possible the Guest did a NOTIFY hypercall to the
- * Launcher.
- */
- if (cpu->pending_notify) {
- /*
- * Does it just needs to write to a registered
- * eventfd (ie. the appropriate virtqueue thread)?
- */
- if (!send_notify_to_eventfd(cpu)) {
- /* OK, we tell the main Launcher. */
- if (put_user(cpu->pending_notify, user))
- return -EFAULT;
- return sizeof(cpu->pending_notify);
- }
+ /* Do we have to tell the Launcher about a trap? */
+ if (cpu->pending.trap) {
+ if (copy_to_user(user, &cpu->pending,
+ sizeof(cpu->pending)))
+ return -EFAULT;
+ return sizeof(cpu->pending);
}
/*
diff --git a/drivers/lguest/hypercalls.c b/drivers/lguest/hypercalls.c
index 83511eb0923d..1219af493c0f 100644
--- a/drivers/lguest/hypercalls.c
+++ b/drivers/lguest/hypercalls.c
@@ -117,9 +117,6 @@ static void do_hcall(struct lg_cpu *cpu, struct hcall_args *args)
/* Similarly, this sets the halted flag for run_guest(). */
cpu->halted = 1;
break;
- case LHCALL_NOTIFY:
- cpu->pending_notify = args->arg1;
- break;
default:
/* It should be an architecture-specific hypercall. */
if (lguest_arch_do_hcall(cpu, args))
@@ -189,7 +186,7 @@ static void do_async_hcalls(struct lg_cpu *cpu)
* Stop doing hypercalls if they want to notify the Launcher:
* it needs to service this first.
*/
- if (cpu->pending_notify)
+ if (cpu->pending.trap)
break;
}
}
@@ -280,7 +277,7 @@ void do_hypercalls(struct lg_cpu *cpu)
* NOTIFY to the Launcher, we want to return now. Otherwise we do
* the hypercall.
*/
- if (!cpu->pending_notify) {
+ if (!cpu->pending.trap) {
do_hcall(cpu, cpu->hcall);
/*
* Tricky point: we reset the hcall pointer to mark the
diff --git a/drivers/lguest/lg.h b/drivers/lguest/lg.h
index 2eef40be4c04..307e8b39e7d1 100644
--- a/drivers/lguest/lg.h
+++ b/drivers/lguest/lg.h
@@ -50,7 +50,10 @@ struct lg_cpu {
/* Bitmap of what has changed: see CHANGED_* above. */
int changed;
- unsigned long pending_notify; /* pfn from LHCALL_NOTIFY */
+ /* Pending operation. */
+ struct lguest_pending pending;
+
+ unsigned long *reg_read; /* register from LHREQ_GETREG */
/* At end of a page shared mapped over lguest_pages in guest. */
unsigned long regs_page;
@@ -78,24 +81,18 @@ struct lg_cpu {
struct lg_cpu_arch arch;
};
-struct lg_eventfd {
- unsigned long addr;
- struct eventfd_ctx *event;
-};
-
-struct lg_eventfd_map {
- unsigned int num;
- struct lg_eventfd map[];
-};
-
/* The private info the thread maintains about the guest. */
struct lguest {
struct lguest_data __user *lguest_data;
struct lg_cpu cpus[NR_CPUS];
unsigned int nr_cpus;
+ /* Valid guest memory pages must be < this. */
u32 pfn_limit;
+ /* Device memory is >= pfn_limit and < device_limit. */
+ u32 device_limit;
+
/*
* This provides the offset to the base of guest-physical memory in the
* Launcher.
@@ -110,8 +107,6 @@ struct lguest {
unsigned int stack_pages;
u32 tsc_khz;
- struct lg_eventfd_map *eventfds;
-
/* Dead? */
const char *dead;
};
@@ -197,8 +192,10 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu);
void guest_set_pte(struct lg_cpu *cpu, unsigned long gpgdir,
unsigned long vaddr, pte_t val);
void map_switcher_in_guest(struct lg_cpu *cpu, struct lguest_pages *pages);
-bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode);
+bool demand_page(struct lg_cpu *cpu, unsigned long cr2, int errcode,
+ unsigned long *iomem);
void pin_page(struct lg_cpu *cpu, unsigned long vaddr);
+bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr);
unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr);
void page_table_guest_data_init(struct lg_cpu *cpu);
@@ -210,6 +207,7 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu);
int lguest_arch_init_hypercalls(struct lg_cpu *cpu);
int lguest_arch_do_hcall(struct lg_cpu *cpu, struct hcall_args *args);
void lguest_arch_setup_regs(struct lg_cpu *cpu, unsigned long start);
+unsigned long *lguest_arch_regptr(struct lg_cpu *cpu, size_t reg_off, bool any);
/* <arch>/switcher.S: */
extern char start_switcher_text[], end_switcher_text[], switch_to_guest[];
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
deleted file mode 100644
index 89088d6538fd..000000000000
--- a/drivers/lguest/lguest_device.c
+++ /dev/null
@@ -1,540 +0,0 @@
-/*P:050
- * Lguest guests use a very simple method to describe devices. It's a
- * series of device descriptors contained just above the top of normal Guest
- * memory.
- *
- * We use the standard "virtio" device infrastructure, which provides us with a
- * console, a network and a block driver. Each one expects some configuration
- * information and a "virtqueue" or two to send and receive data.
-:*/
-#include <linux/init.h>
-#include <linux/bootmem.h>
-#include <linux/lguest_launcher.h>
-#include <linux/virtio.h>
-#include <linux/virtio_config.h>
-#include <linux/interrupt.h>
-#include <linux/virtio_ring.h>
-#include <linux/err.h>
-#include <linux/export.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-#include <asm/paravirt.h>
-#include <asm/lguest_hcall.h>
-
-/* The pointer to our (page) of device descriptions. */
-static void *lguest_devices;
-
-/*
- * For Guests, device memory can be used as normal memory, so we cast away the
- * __iomem to quieten sparse.
- */
-static inline void *lguest_map(unsigned long phys_addr, unsigned long pages)
-{
- return (__force void *)ioremap_cache(phys_addr, PAGE_SIZE*pages);
-}
-
-static inline void lguest_unmap(void *addr)
-{
- iounmap((__force void __iomem *)addr);
-}
-
-/*D:100
- * Each lguest device is just a virtio device plus a pointer to its entry
- * in the lguest_devices page.
- */
-struct lguest_device {
- struct virtio_device vdev;
-
- /* The entry in the lguest_devices page for this device. */
- struct lguest_device_desc *desc;
-};
-
-/*
- * Since the virtio infrastructure hands us a pointer to the virtio_device all
- * the time, it helps to have a curt macro to get a pointer to the struct
- * lguest_device it's enclosed in.
- */
-#define to_lgdev(vd) container_of(vd, struct lguest_device, vdev)
-
-/*D:130
- * Device configurations
- *
- * The configuration information for a device consists of one or more
- * virtqueues, a feature bitmap, and some configuration bytes. The
- * configuration bytes don't really matter to us: the Launcher sets them up, and
- * the driver will look at them during setup.
- *
- * A convenient routine to return the device's virtqueue config array:
- * immediately after the descriptor.
- */
-static struct lguest_vqconfig *lg_vq(const struct lguest_device_desc *desc)
-{
- return (void *)(desc + 1);
-}
-
-/* The features come immediately after the virtqueues. */
-static u8 *lg_features(const struct lguest_device_desc *desc)
-{
- return (void *)(lg_vq(desc) + desc->num_vq);
-}
-
-/* The config space comes after the two feature bitmasks. */
-static u8 *lg_config(const struct lguest_device_desc *desc)
-{
- return lg_features(desc) + desc->feature_len * 2;
-}
-
-/* The total size of the config page used by this device (incl. desc) */
-static unsigned desc_size(const struct lguest_device_desc *desc)
-{
- return sizeof(*desc)
- + desc->num_vq * sizeof(struct lguest_vqconfig)
- + desc->feature_len * 2
- + desc->config_len;
-}
-
-/* This gets the device's feature bits. */
-static u64 lg_get_features(struct virtio_device *vdev)
-{
- unsigned int i;
- u32 features = 0;
- struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
- u8 *in_features = lg_features(desc);
-
- /* We do this the slow but generic way. */
- for (i = 0; i < min(desc->feature_len * 8, 32); i++)
- if (in_features[i / 8] & (1 << (i % 8)))
- features |= (1 << i);
-
- return features;
-}
-
-/*
- * To notify on reset or feature finalization, we (ab)use the NOTIFY
- * hypercall, with the descriptor address of the device.
- */
-static void status_notify(struct virtio_device *vdev)
-{
- unsigned long offset = (void *)to_lgdev(vdev)->desc - lguest_devices;
-
- hcall(LHCALL_NOTIFY, (max_pfn << PAGE_SHIFT) + offset, 0, 0, 0);
-}
-
-/*
- * The virtio core takes the features the Host offers, and copies the ones
- * supported by the driver into the vdev->features array. Once that's all
- * sorted out, this routine is called so we can tell the Host which features we
- * understand and accept.
- */
-static int lg_finalize_features(struct virtio_device *vdev)
-{
- unsigned int i, bits;
- struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
- /* Second half of bitmap is features we accept. */
- u8 *out_features = lg_features(desc) + desc->feature_len;
-
- /* 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);
-
- /*
- * 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 (__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. */
-static void lg_get(struct virtio_device *vdev, unsigned int offset,
- void *buf, unsigned len)
-{
- struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
-
- /* Check they didn't ask for more than the length of the config! */
- BUG_ON(offset + len > desc->config_len);
- memcpy(buf, lg_config(desc) + offset, len);
-}
-
-/* Setting the contents is also trivial. */
-static void lg_set(struct virtio_device *vdev, unsigned int offset,
- const void *buf, unsigned len)
-{
- struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
-
- /* Check they didn't ask for more than the length of the config! */
- BUG_ON(offset + len > desc->config_len);
- memcpy(lg_config(desc) + offset, buf, len);
-}
-
-/*
- * The operations to get and set the status word just access the status field
- * of the device descriptor.
- */
-static u8 lg_get_status(struct virtio_device *vdev)
-{
- return to_lgdev(vdev)->desc->status;
-}
-
-static void lg_set_status(struct virtio_device *vdev, u8 status)
-{
- BUG_ON(!status);
- to_lgdev(vdev)->desc->status = status;
-
- /* Tell Host immediately if we failed. */
- if (status & VIRTIO_CONFIG_S_FAILED)
- status_notify(vdev);
-}
-
-static void lg_reset(struct virtio_device *vdev)
-{
- /* 0 status means "reset" */
- to_lgdev(vdev)->desc->status = 0;
- status_notify(vdev);
-}
-
-/*
- * Virtqueues
- *
- * The other piece of infrastructure virtio needs is a "virtqueue": a way of
- * the Guest device registering buffers for the other side to read from or
- * write into (ie. send and receive buffers). Each device can have multiple
- * virtqueues: for example the console driver uses one queue for sending and
- * another for receiving.
- *
- * Fortunately for us, a very fast shared-memory-plus-descriptors virtqueue
- * already exists in virtio_ring.c. We just need to connect it up.
- *
- * We start with the information we need to keep about each virtqueue.
- */
-
-/*D:140 This is the information we remember about each virtqueue. */
-struct lguest_vq_info {
- /* A copy of the information contained in the device config. */
- struct lguest_vqconfig config;
-
- /* The address where we mapped the virtio ring, so we can unmap it. */
- void *pages;
-};
-
-/*
- * When the virtio_ring code wants to prod the Host, it calls us here and we
- * make a hypercall. We hand the physical address of the virtqueue so the Host
- * knows which virtqueue we're talking about.
- */
-static bool lg_notify(struct virtqueue *vq)
-{
- /*
- * We store our virtqueue information in the "priv" pointer of the
- * virtqueue structure.
- */
- struct lguest_vq_info *lvq = vq->priv;
-
- hcall(LHCALL_NOTIFY, lvq->config.pfn << PAGE_SHIFT, 0, 0, 0);
- return true;
-}
-
-/* An extern declaration inside a C file is bad form. Don't do it. */
-extern int lguest_setup_irq(unsigned int irq);
-
-/*
- * This routine finds the Nth virtqueue described in the configuration of
- * this device and sets it up.
- *
- * This is kind of an ugly duckling. It'd be nicer to have a standard
- * representation of a virtqueue in the configuration space, but it seems that
- * everyone wants to do it differently. The KVM coders want the Guest to
- * allocate its own pages and tell the Host where they are, but for lguest it's
- * simpler for the Host to simply tell us where the pages are.
- */
-static struct virtqueue *lg_find_vq(struct virtio_device *vdev,
- unsigned index,
- void (*callback)(struct virtqueue *vq),
- const char *name)
-{
- struct lguest_device *ldev = to_lgdev(vdev);
- struct lguest_vq_info *lvq;
- struct virtqueue *vq;
- int err;
-
- if (!name)
- return NULL;
-
- /* We must have this many virtqueues. */
- if (index >= ldev->desc->num_vq)
- return ERR_PTR(-ENOENT);
-
- lvq = kmalloc(sizeof(*lvq), GFP_KERNEL);
- if (!lvq)
- return ERR_PTR(-ENOMEM);
-
- /*
- * Make a copy of the "struct lguest_vqconfig" entry, which sits after
- * the descriptor. We need a copy because the config space might not
- * be aligned correctly.
- */
- memcpy(&lvq->config, lg_vq(ldev->desc)+index, sizeof(lvq->config));
-
- printk("Mapping virtqueue %i addr %lx\n", index,
- (unsigned long)lvq->config.pfn << PAGE_SHIFT);
- /* Figure out how many pages the ring will take, and map that memory */
- lvq->pages = lguest_map((unsigned long)lvq->config.pfn << PAGE_SHIFT,
- DIV_ROUND_UP(vring_size(lvq->config.num,
- LGUEST_VRING_ALIGN),
- PAGE_SIZE));
- if (!lvq->pages) {
- err = -ENOMEM;
- goto free_lvq;
- }
-
- /*
- * OK, tell virtio_ring.c to set up a virtqueue now we know its size
- * and we've got a pointer to its pages. Note that we set weak_barriers
- * to 'true': the host just a(nother) SMP CPU, so we only need inter-cpu
- * barriers.
- */
- vq = vring_new_virtqueue(index, lvq->config.num, LGUEST_VRING_ALIGN, vdev,
- true, lvq->pages, lg_notify, callback, name);
- if (!vq) {
- err = -ENOMEM;
- goto unmap;
- }
-
- /* Make sure the interrupt is allocated. */
- err = lguest_setup_irq(lvq->config.irq);
- if (err)
- goto destroy_vring;
-
- /*
- * Tell the interrupt for this virtqueue to go to the virtio_ring
- * interrupt handler.
- *
- * FIXME: We used to have a flag for the Host to tell us we could use
- * the interrupt as a source of randomness: it'd be nice to have that
- * back.
- */
- err = request_irq(lvq->config.irq, vring_interrupt, IRQF_SHARED,
- dev_name(&vdev->dev), vq);
- if (err)
- goto free_desc;
-
- /*
- * Last of all we hook up our 'struct lguest_vq_info" to the
- * virtqueue's priv pointer.
- */
- vq->priv = lvq;
- return vq;
-
-free_desc:
- irq_free_desc(lvq->config.irq);
-destroy_vring:
- vring_del_virtqueue(vq);
-unmap:
- lguest_unmap(lvq->pages);
-free_lvq:
- kfree(lvq);
- return ERR_PTR(err);
-}
-/*:*/
-
-/* Cleaning up a virtqueue is easy */
-static void lg_del_vq(struct virtqueue *vq)
-{
- struct lguest_vq_info *lvq = vq->priv;
-
- /* Release the interrupt */
- free_irq(lvq->config.irq, vq);
- /* Tell virtio_ring.c to free the virtqueue. */
- vring_del_virtqueue(vq);
- /* Unmap the pages containing the ring. */
- lguest_unmap(lvq->pages);
- /* Free our own queue information. */
- kfree(lvq);
-}
-
-static void lg_del_vqs(struct virtio_device *vdev)
-{
- struct virtqueue *vq, *n;
-
- list_for_each_entry_safe(vq, n, &vdev->vqs, list)
- lg_del_vq(vq);
-}
-
-static int lg_find_vqs(struct virtio_device *vdev, unsigned nvqs,
- struct virtqueue *vqs[],
- vq_callback_t *callbacks[],
- const char *names[])
-{
- struct lguest_device *ldev = to_lgdev(vdev);
- int i;
-
- /* We must have this many virtqueues. */
- if (nvqs > ldev->desc->num_vq)
- return -ENOENT;
-
- for (i = 0; i < nvqs; ++i) {
- vqs[i] = lg_find_vq(vdev, i, callbacks[i], names[i]);
- if (IS_ERR(vqs[i]))
- goto error;
- }
- return 0;
-
-error:
- lg_del_vqs(vdev);
- return PTR_ERR(vqs[i]);
-}
-
-static const char *lg_bus_name(struct virtio_device *vdev)
-{
- return "";
-}
-
-/* The ops structure which hooks everything together. */
-static const struct virtio_config_ops lguest_config_ops = {
- .get_features = lg_get_features,
- .finalize_features = lg_finalize_features,
- .get = lg_get,
- .set = lg_set,
- .get_status = lg_get_status,
- .set_status = lg_set_status,
- .reset = lg_reset,
- .find_vqs = lg_find_vqs,
- .del_vqs = lg_del_vqs,
- .bus_name = lg_bus_name,
-};
-
-/*
- * The root device for the lguest virtio devices. This makes them appear as
- * /sys/devices/lguest/0,1,2 not /sys/devices/0,1,2.
- */
-static struct device *lguest_root;
-
-/*D:120
- * This is the core of the lguest bus: actually adding a new device.
- * It's a separate function because it's neater that way, and because an
- * earlier version of the code supported hotplug and unplug. They were removed
- * early on because they were never used.
- *
- * As Andrew Tridgell says, "Untested code is buggy code".
- *
- * It's worth reading this carefully: we start with a pointer to the new device
- * descriptor in the "lguest_devices" page, and the offset into the device
- * descriptor page so we can uniquely identify it if things go badly wrong.
- */
-static void add_lguest_device(struct lguest_device_desc *d,
- unsigned int offset)
-{
- struct lguest_device *ldev;
-
- /* Start with zeroed memory; Linux's device layer counts on it. */
- ldev = kzalloc(sizeof(*ldev), GFP_KERNEL);
- if (!ldev) {
- printk(KERN_EMERG "Cannot allocate lguest dev %u type %u\n",
- offset, d->type);
- return;
- }
-
- /* This devices' parent is the lguest/ dir. */
- ldev->vdev.dev.parent = lguest_root;
- /*
- * The device type comes straight from the descriptor. There's also a
- * device vendor field in the virtio_device struct, which we leave as
- * 0.
- */
- ldev->vdev.id.device = d->type;
- /*
- * We have a simple set of routines for querying the device's
- * configuration information and setting its status.
- */
- ldev->vdev.config = &lguest_config_ops;
- /* And we remember the device's descriptor for lguest_config_ops. */
- ldev->desc = d;
-
- /*
- * register_virtio_device() sets up the generic fields for the struct
- * virtio_device and calls device_register(). This makes the bus
- * infrastructure look for a matching driver.
- */
- if (register_virtio_device(&ldev->vdev) != 0) {
- printk(KERN_ERR "Failed to register lguest dev %u type %u\n",
- offset, d->type);
- kfree(ldev);
- }
-}
-
-/*D:110
- * scan_devices() simply iterates through the device page. The type 0 is
- * reserved to mean "end of devices".
- */
-static void scan_devices(void)
-{
- unsigned int i;
- struct lguest_device_desc *d;
-
- /* We start at the page beginning, and skip over each entry. */
- for (i = 0; i < PAGE_SIZE; i += desc_size(d)) {
- d = lguest_devices + i;
-
- /* Once we hit a zero, stop. */
- if (d->type == 0)
- break;
-
- printk("Device at %i has size %u\n", i, desc_size(d));
- add_lguest_device(d, i);
- }
-}
-
-/*D:105
- * Fairly early in boot, lguest_devices_init() is called to set up the
- * lguest device infrastructure. We check that we are a Guest by checking
- * pv_info.name: there are other ways of checking, but this seems most
- * obvious to me.
- *
- * So we can access the "struct lguest_device_desc"s easily, we map that memory
- * and store the pointer in the global "lguest_devices". Then we register a
- * root device from which all our devices will hang (this seems to be the
- * correct sysfs incantation).
- *
- * Finally we call scan_devices() which adds all the devices found in the
- * lguest_devices page.
- */
-static int __init lguest_devices_init(void)
-{
- if (strcmp(pv_info.name, "lguest") != 0)
- return 0;
-
- lguest_root = root_device_register("lguest");
- if (IS_ERR(lguest_root))
- panic("Could not register lguest root");
-
- /* Devices are in a single page above top of "normal" mem */
- lguest_devices = lguest_map(max_pfn<<PAGE_SHIFT, 1);
-
- scan_devices();
- return 0;
-}
-/* We do this after core stuff, but before the drivers. */
-postcore_initcall(lguest_devices_init);
-
-/*D:150
- * At this point in the journey we used to now wade through the lguest
- * devices themselves: net, block and console. Since they're all now virtio
- * devices rather than lguest-specific, I've decided to ignore them. Mostly,
- * they're kind of boring. But this does mean you'll never experience the
- * thrill of reading the forbidden love scene buried deep in the block driver.
- *
- * "make Launcher" beckons, where we answer questions like "Where do Guests
- * come from?", and "What do you do when someone asks for optimization?".
- */
diff --git a/drivers/lguest/lguest_user.c b/drivers/lguest/lguest_user.c
index 4263f4cc8c55..c4c6113eb9a6 100644
--- a/drivers/lguest/lguest_user.c
+++ b/drivers/lguest/lguest_user.c
@@ -2,175 +2,62 @@
* launcher controls and communicates with the Guest. For example,
* the first write will tell us the Guest's memory layout and entry
* point. A read will run the Guest until something happens, such as
- * a signal or the Guest doing a NOTIFY out to the Launcher. There is
- * also a way for the Launcher to attach eventfds to particular NOTIFY
- * values instead of returning from the read() call.
+ * a signal or the Guest accessing a device.
:*/
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/sched.h>
-#include <linux/eventfd.h>
#include <linux/file.h>
#include <linux/slab.h>
#include <linux/export.h>
#include "lg.h"
-/*L:056
- * Before we move on, let's jump ahead and look at what the kernel does when
- * it needs to look up the eventfds. That will complete our picture of how we
- * use RCU.
- *
- * The notification value is in cpu->pending_notify: we return true if it went
- * to an eventfd.
- */
-bool send_notify_to_eventfd(struct lg_cpu *cpu)
-{
- unsigned int i;
- struct lg_eventfd_map *map;
-
- /*
- * This "rcu_read_lock()" helps track when someone is still looking at
- * the (RCU-using) eventfds array. It's not actually a lock at all;
- * indeed it's a noop in many configurations. (You didn't expect me to
- * explain all the RCU secrets here, did you?)
- */
- rcu_read_lock();
- /*
- * rcu_dereference is the counter-side of rcu_assign_pointer(); it
- * makes sure we don't access the memory pointed to by
- * cpu->lg->eventfds before cpu->lg->eventfds is set. Sounds crazy,
- * but Alpha allows this! Paul McKenney points out that a really
- * aggressive compiler could have the same effect:
- * http://lists.ozlabs.org/pipermail/lguest/2009-July/001560.html
- *
- * So play safe, use rcu_dereference to get the rcu-protected pointer:
- */
- map = rcu_dereference(cpu->lg->eventfds);
- /*
- * Simple array search: even if they add an eventfd while we do this,
- * we'll continue to use the old array and just won't see the new one.
- */
- for (i = 0; i < map->num; i++) {
- if (map->map[i].addr == cpu->pending_notify) {
- eventfd_signal(map->map[i].event, 1);
- cpu->pending_notify = 0;
- break;
- }
- }
- /* We're done with the rcu-protected variable cpu->lg->eventfds. */
- rcu_read_unlock();
-
- /* If we cleared the notification, it's because we found a match. */
- return cpu->pending_notify == 0;
-}
-
-/*L:055
- * One of the more tricksy tricks in the Linux Kernel is a technique called
- * Read Copy Update. Since one point of lguest is to teach lguest journeyers
- * about kernel coding, I use it here. (In case you're curious, other purposes
- * include learning about virtualization and instilling a deep appreciation for
- * simplicity and puppies).
- *
- * We keep a simple array which maps LHCALL_NOTIFY values to eventfds, but we
- * add new eventfds without ever blocking readers from accessing the array.
- * The current Launcher only does this during boot, so that never happens. But
- * Read Copy Update is cool, and adding a lock risks damaging even more puppies
- * than this code does.
- *
- * We allocate a brand new one-larger array, copy the old one and add our new
- * element. Then we make the lg eventfd pointer point to the new array.
- * That's the easy part: now we need to free the old one, but we need to make
- * sure no slow CPU somewhere is still looking at it. That's what
- * synchronize_rcu does for us: waits until every CPU has indicated that it has
- * moved on to know it's no longer using the old one.
- *
- * If that's unclear, see http://en.wikipedia.org/wiki/Read-copy-update.
- */
-static int add_eventfd(struct lguest *lg, unsigned long addr, int fd)
+/*L:052
+ The Launcher can get the registers, and also set some of them.
+*/
+static int getreg_setup(struct lg_cpu *cpu, const unsigned long __user *input)
{
- struct lg_eventfd_map *new, *old = lg->eventfds;
-
- /*
- * We don't allow notifications on value 0 anyway (pending_notify of
- * 0 means "nothing pending").
- */
- if (!addr)
- return -EINVAL;
-
- /*
- * Replace the old array with the new one, carefully: others can
- * be accessing it at the same time.
- */
- new = kmalloc(sizeof(*new) + sizeof(new->map[0]) * (old->num + 1),
- GFP_KERNEL);
- if (!new)
- return -ENOMEM;
+ unsigned long which;
- /* First make identical copy. */
- memcpy(new->map, old->map, sizeof(old->map[0]) * old->num);
- new->num = old->num;
-
- /* Now append new entry. */
- new->map[new->num].addr = addr;
- new->map[new->num].event = eventfd_ctx_fdget(fd);
- if (IS_ERR(new->map[new->num].event)) {
- int err = PTR_ERR(new->map[new->num].event);
- kfree(new);
- return err;
- }
- new->num++;
+ /* We re-use the ptrace structure to specify which register to read. */
+ if (get_user(which, input) != 0)
+ return -EFAULT;
/*
- * Now put new one in place: rcu_assign_pointer() is a fancy way of
- * doing "lg->eventfds = new", but it uses memory barriers to make
- * absolutely sure that the contents of "new" written above is nailed
- * down before we actually do the assignment.
+ * We set up the cpu register pointer, and their next read will
+ * actually get the value (instead of running the guest).
*
- * We have to think about these kinds of things when we're operating on
- * live data without locks.
+ * The last argument 'true' says we can access any register.
*/
- rcu_assign_pointer(lg->eventfds, new);
+ cpu->reg_read = lguest_arch_regptr(cpu, which, true);
+ if (!cpu->reg_read)
+ return -ENOENT;
- /*
- * We're not in a big hurry. Wait until no one's looking at old
- * version, then free it.
- */
- synchronize_rcu();
- kfree(old);
-
- return 0;
+ /* And because this is a write() call, we return the length used. */
+ return sizeof(unsigned long) * 2;
}
-/*L:052
- * Receiving notifications from the Guest is usually done by attaching a
- * particular LHCALL_NOTIFY value to an event filedescriptor. The eventfd will
- * become readable when the Guest does an LHCALL_NOTIFY with that value.
- *
- * This is really convenient for processing each virtqueue in a separate
- * thread.
- */
-static int attach_eventfd(struct lguest *lg, const unsigned long __user *input)
+static int setreg(struct lg_cpu *cpu, const unsigned long __user *input)
{
- unsigned long addr, fd;
- int err;
+ unsigned long which, value, *reg;
- if (get_user(addr, input) != 0)
+ /* We re-use the ptrace structure to specify which register to read. */
+ if (get_user(which, input) != 0)
return -EFAULT;
input++;
- if (get_user(fd, input) != 0)
+ if (get_user(value, input) != 0)
return -EFAULT;
- /*
- * Just make sure two callers don't add eventfds at once. We really
- * only need to lock against callers adding to the same Guest, so using
- * the Big Lguest Lock is overkill. But this is setup, not a fast path.
- */
- mutex_lock(&lguest_lock);
- err = add_eventfd(lg, addr, fd);
- mutex_unlock(&lguest_lock);
+ /* The last argument 'false' means we can't access all registers. */
+ reg = lguest_arch_regptr(cpu, which, false);
+ if (!reg)
+ return -ENOENT;
- return err;
+ *reg = value;
+
+ /* And because this is a write() call, we return the length used. */
+ return sizeof(unsigned long) * 3;
}
/*L:050
@@ -194,6 +81,23 @@ static int user_send_irq(struct lg_cpu *cpu, const unsigned long __user *input)
return 0;
}
+/*L:053
+ * Deliver a trap: this is used by the Launcher if it can't emulate
+ * an instruction.
+ */
+static int trap(struct lg_cpu *cpu, const unsigned long __user *input)
+{
+ unsigned long trapnum;
+
+ if (get_user(trapnum, input) != 0)
+ return -EFAULT;
+
+ if (!deliver_trap(cpu, trapnum))
+ return -EINVAL;
+
+ return 0;
+}
+
/*L:040
* Once our Guest is initialized, the Launcher makes it run by reading
* from /dev/lguest.
@@ -237,8 +141,8 @@ static ssize_t read(struct file *file, char __user *user, size_t size,loff_t*o)
* If we returned from read() last time because the Guest sent I/O,
* clear the flag.
*/
- if (cpu->pending_notify)
- cpu->pending_notify = 0;
+ if (cpu->pending.trap)
+ cpu->pending.trap = 0;
/* Run the Guest until something interesting happens. */
return run_guest(cpu, (unsigned long __user *)user);
@@ -319,7 +223,7 @@ static int initialize(struct file *file, const unsigned long __user *input)
/* "struct lguest" contains all we (the Host) know about a Guest. */
struct lguest *lg;
int err;
- unsigned long args[3];
+ unsigned long args[4];
/*
* We grab the Big Lguest lock, which protects against multiple
@@ -343,21 +247,15 @@ static int initialize(struct file *file, const unsigned long __user *input)
goto unlock;
}
- lg->eventfds = kmalloc(sizeof(*lg->eventfds), GFP_KERNEL);
- if (!lg->eventfds) {
- err = -ENOMEM;
- goto free_lg;
- }
- lg->eventfds->num = 0;
-
/* Populate the easy fields of our "struct lguest" */
lg->mem_base = (void __user *)args[0];
lg->pfn_limit = args[1];
+ lg->device_limit = args[3];
/* This is the first cpu (cpu 0) and it will start booting at args[2] */
err = lg_cpu_start(&lg->cpus[0], 0, args[2]);
if (err)
- goto free_eventfds;
+ goto free_lg;
/*
* Initialize the Guest's shadow page tables. This allocates
@@ -378,8 +276,6 @@ static int initialize(struct file *file, const unsigned long __user *input)
free_regs:
/* FIXME: This should be in free_vcpu */
free_page(lg->cpus[0].regs_page);
-free_eventfds:
- kfree(lg->eventfds);
free_lg:
kfree(lg);
unlock:
@@ -432,8 +328,12 @@ static ssize_t write(struct file *file, const char __user *in,
return initialize(file, input);
case LHREQ_IRQ:
return user_send_irq(cpu, input);
- case LHREQ_EVENTFD:
- return attach_eventfd(lg, input);
+ case LHREQ_GETREG:
+ return getreg_setup(cpu, input);
+ case LHREQ_SETREG:
+ return setreg(cpu, input);
+ case LHREQ_TRAP:
+ return trap(cpu, input);
default:
return -EINVAL;
}
@@ -478,11 +378,6 @@ static int close(struct inode *inode, struct file *file)
mmput(lg->cpus[i].mm);
}
- /* Release any eventfds they registered. */
- for (i = 0; i < lg->eventfds->num; i++)
- eventfd_ctx_put(lg->eventfds->map[i].event);
- kfree(lg->eventfds);
-
/*
* If lg->dead doesn't contain an error code it will be NULL or a
* kmalloc()ed string, either of which is ok to hand to kfree().
diff --git a/drivers/lguest/page_tables.c b/drivers/lguest/page_tables.c
index e8b55c3a6170..e3abebc912c0 100644
--- a/drivers/lguest/page_tables.c
+++ b/drivers/lguest/page_tables.c
@@ -250,6 +250,16 @@ static void release_pte(pte_t pte)
}
/*:*/
+static bool gpte_in_iomem(struct lg_cpu *cpu, pte_t gpte)
+{
+ /* We don't handle large pages. */
+ if (pte_flags(gpte) & _PAGE_PSE)
+ return false;
+
+ return (pte_pfn(gpte) >= cpu->lg->pfn_limit
+ && pte_pfn(gpte) < cpu->lg->device_limit);
+}
+
static bool check_gpte(struct lg_cpu *cpu, pte_t gpte)
{
if ((pte_flags(gpte) & _PAGE_PSE) ||
@@ -374,8 +384,14 @@ static pte_t *find_spte(struct lg_cpu *cpu, unsigned long vaddr, bool allocate,
*
* If we fixed up the fault (ie. we mapped the address), this routine returns
* true. Otherwise, it was a real fault and we need to tell the Guest.
+ *
+ * There's a corner case: they're trying to access memory between
+ * pfn_limit and device_limit, which is I/O memory. In this case, we
+ * return false and set @iomem to the physical address, so the the
+ * Launcher can handle the instruction manually.
*/
-bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
+bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode,
+ unsigned long *iomem)
{
unsigned long gpte_ptr;
pte_t gpte;
@@ -383,6 +399,8 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
pmd_t gpmd;
pgd_t gpgd;
+ *iomem = 0;
+
/* We never demand page the Switcher, so trying is a mistake. */
if (vaddr >= switcher_addr)
return false;
@@ -459,6 +477,12 @@ bool demand_page(struct lg_cpu *cpu, unsigned long vaddr, int errcode)
if ((errcode & 4) && !(pte_flags(gpte) & _PAGE_USER))
return false;
+ /* If they're accessing io memory, we expect a fault. */
+ if (gpte_in_iomem(cpu, gpte)) {
+ *iomem = (pte_pfn(gpte) << PAGE_SHIFT) | (vaddr & ~PAGE_MASK);
+ return false;
+ }
+
/*
* Check that the Guest PTE flags are OK, and the page number is below
* the pfn_limit (ie. not mapping the Launcher binary).
@@ -553,7 +577,9 @@ static bool page_writable(struct lg_cpu *cpu, unsigned long vaddr)
*/
void pin_page(struct lg_cpu *cpu, unsigned long vaddr)
{
- if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2))
+ unsigned long iomem;
+
+ if (!page_writable(cpu, vaddr) && !demand_page(cpu, vaddr, 2, &iomem))
kill_guest(cpu, "bad stack page %#lx", vaddr);
}
/*:*/
@@ -647,7 +673,7 @@ void guest_pagetable_flush_user(struct lg_cpu *cpu)
/*:*/
/* We walk down the guest page tables to get a guest-physical address */
-unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
+bool __guest_pa(struct lg_cpu *cpu, unsigned long vaddr, unsigned long *paddr)
{
pgd_t gpgd;
pte_t gpte;
@@ -656,31 +682,47 @@ unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
#endif
/* Still not set up? Just map 1:1. */
- if (unlikely(cpu->linear_pages))
- return vaddr;
+ if (unlikely(cpu->linear_pages)) {
+ *paddr = vaddr;
+ return true;
+ }
/* First step: get the top-level Guest page table entry. */
gpgd = lgread(cpu, gpgd_addr(cpu, vaddr), pgd_t);
/* Toplevel not present? We can't map it in. */
- if (!(pgd_flags(gpgd) & _PAGE_PRESENT)) {
- kill_guest(cpu, "Bad address %#lx", vaddr);
- return -1UL;
- }
+ if (!(pgd_flags(gpgd) & _PAGE_PRESENT))
+ goto fail;
#ifdef CONFIG_X86_PAE
gpmd = lgread(cpu, gpmd_addr(gpgd, vaddr), pmd_t);
- if (!(pmd_flags(gpmd) & _PAGE_PRESENT)) {
- kill_guest(cpu, "Bad address %#lx", vaddr);
- return -1UL;
- }
+ if (!(pmd_flags(gpmd) & _PAGE_PRESENT))
+ goto fail;
gpte = lgread(cpu, gpte_addr(cpu, gpmd, vaddr), pte_t);
#else
gpte = lgread(cpu, gpte_addr(cpu, gpgd, vaddr), pte_t);
#endif
if (!(pte_flags(gpte) & _PAGE_PRESENT))
- kill_guest(cpu, "Bad address %#lx", vaddr);
+ goto fail;
+
+ *paddr = pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
+ return true;
+
+fail:
+ *paddr = -1UL;
+ return false;
+}
- return pte_pfn(gpte) * PAGE_SIZE | (vaddr & ~PAGE_MASK);
+/*
+ * This is the version we normally use: kills the Guest if it uses a
+ * bad address
+ */
+unsigned long guest_pa(struct lg_cpu *cpu, unsigned long vaddr)
+{
+ unsigned long paddr;
+
+ if (!__guest_pa(cpu, vaddr, &paddr))
+ kill_guest(cpu, "Bad address %#lx", vaddr);
+ return paddr;
}
/*
@@ -912,7 +954,8 @@ static void __guest_set_pte(struct lg_cpu *cpu, int idx,
* now. This shaves 10% off a copy-on-write
* micro-benchmark.
*/
- if (pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED)) {
+ if ((pte_flags(gpte) & (_PAGE_DIRTY | _PAGE_ACCESSED))
+ && !gpte_in_iomem(cpu, gpte)) {
if (!check_gpte(cpu, gpte))
return;
set_pte(spte,
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c
index 922a1acbf652..30f2aef69d78 100644
--- a/drivers/lguest/x86/core.c
+++ b/drivers/lguest/x86/core.c
@@ -47,6 +47,7 @@
#include <asm/lguest.h>
#include <asm/uaccess.h>
#include <asm/i387.h>
+#include <asm/tlbflush.h>
#include "../lg.h"
static int cpu_had_pge;
@@ -181,6 +182,52 @@ static void run_guest_once(struct lg_cpu *cpu, struct lguest_pages *pages)
}
/*:*/
+unsigned long *lguest_arch_regptr(struct lg_cpu *cpu, size_t reg_off, bool any)
+{
+ switch (reg_off) {
+ case offsetof(struct pt_regs, bx):
+ return &cpu->regs->ebx;
+ case offsetof(struct pt_regs, cx):
+ return &cpu->regs->ecx;
+ case offsetof(struct pt_regs, dx):
+ return &cpu->regs->edx;
+ case offsetof(struct pt_regs, si):
+ return &cpu->regs->esi;
+ case offsetof(struct pt_regs, di):
+ return &cpu->regs->edi;
+ case offsetof(struct pt_regs, bp):
+ return &cpu->regs->ebp;
+ case offsetof(struct pt_regs, ax):
+ return &cpu->regs->eax;
+ case offsetof(struct pt_regs, ip):
+ return &cpu->regs->eip;
+ case offsetof(struct pt_regs, sp):
+ return &cpu->regs->esp;
+ }
+
+ /* Launcher can read these, but we don't allow any setting. */
+ if (any) {
+ switch (reg_off) {
+ case offsetof(struct pt_regs, ds):
+ return &cpu->regs->ds;
+ case offsetof(struct pt_regs, es):
+ return &cpu->regs->es;
+ case offsetof(struct pt_regs, fs):
+ return &cpu->regs->fs;
+ case offsetof(struct pt_regs, gs):
+ return &cpu->regs->gs;
+ case offsetof(struct pt_regs, cs):
+ return &cpu->regs->cs;
+ case offsetof(struct pt_regs, flags):
+ return &cpu->regs->eflags;
+ case offsetof(struct pt_regs, ss):
+ return &cpu->regs->ss;
+ }
+ }
+
+ return NULL;
+}
+
/*M:002
* There are hooks in the scheduler which we can register to tell when we
* get kicked off the CPU (preempt_notifier_register()). This would allow us
@@ -268,110 +315,73 @@ void lguest_arch_run_guest(struct lg_cpu *cpu)
* usually attached to a PC.
*
* When the Guest uses one of these instructions, we get a trap (General
- * Protection Fault) and come here. We see if it's one of those troublesome
- * instructions and skip over it. We return true if we did.
+ * Protection Fault) and come here. We queue this to be sent out to the
+ * Launcher to handle.
*/
-static int emulate_insn(struct lg_cpu *cpu)
-{
- u8 insn;
- unsigned int insnlen = 0, in = 0, small_operand = 0;
- /*
- * The eip contains the *virtual* address of the Guest's instruction:
- * walk the Guest's page tables to find the "physical" address.
- */
- unsigned long physaddr = guest_pa(cpu, cpu->regs->eip);
-
- /*
- * This must be the Guest kernel trying to do something, not userspace!
- * The bottom two bits of the CS segment register are the privilege
- * level.
- */
- if ((cpu->regs->cs & 3) != GUEST_PL)
- return 0;
-
- /* Decoding x86 instructions is icky. */
- insn = lgread(cpu, physaddr, u8);
- /*
- * Around 2.6.33, the kernel started using an emulation for the
- * cmpxchg8b instruction in early boot on many configurations. This
- * code isn't paravirtualized, and it tries to disable interrupts.
- * Ignore it, which will Mostly Work.
- */
- if (insn == 0xfa) {
- /* "cli", or Clear Interrupt Enable instruction. Skip it. */
- cpu->regs->eip++;
- return 1;
+/*
+ * The eip contains the *virtual* address of the Guest's instruction:
+ * we copy the instruction here so the Launcher doesn't have to walk
+ * the page tables to decode it. We handle the case (eg. in a kernel
+ * module) where the instruction is over two pages, and the pages are
+ * virtually but not physically contiguous.
+ *
+ * The longest possible x86 instruction is 15 bytes, but we don't handle
+ * anything that strange.
+ */
+static void copy_from_guest(struct lg_cpu *cpu,
+ void *dst, unsigned long vaddr, size_t len)
+{
+ size_t to_page_end = PAGE_SIZE - (vaddr % PAGE_SIZE);
+ unsigned long paddr;
+
+ BUG_ON(len > PAGE_SIZE);
+
+ /* If it goes over a page, copy in two parts. */
+ if (len > to_page_end) {
+ /* But make sure the next page is mapped! */
+ if (__guest_pa(cpu, vaddr + to_page_end, &paddr))
+ copy_from_guest(cpu, dst + to_page_end,
+ vaddr + to_page_end,
+ len - to_page_end);
+ else
+ /* Otherwise fill with zeroes. */
+ memset(dst + to_page_end, 0, len - to_page_end);
+ len = to_page_end;
}
- /*
- * 0x66 is an "operand prefix". It means a 16, not 32 bit in/out.
- */
- if (insn == 0x66) {
- small_operand = 1;
- /* The instruction is 1 byte so far, read the next byte. */
- insnlen = 1;
- insn = lgread(cpu, physaddr + insnlen, u8);
- }
+ /* This will kill the guest if it isn't mapped, but that
+ * shouldn't happen. */
+ __lgread(cpu, dst, guest_pa(cpu, vaddr), len);
+}
- /*
- * We can ignore the lower bit for the moment and decode the 4 opcodes
- * we need to emulate.
- */
- switch (insn & 0xFE) {
- case 0xE4: /* in <next byte>,%al */
- insnlen += 2;
- in = 1;
- break;
- case 0xEC: /* in (%dx),%al */
- insnlen += 1;
- in = 1;
- break;
- case 0xE6: /* out %al,<next byte> */
- insnlen += 2;
- break;
- case 0xEE: /* out %al,(%dx) */
- insnlen += 1;
- break;
- default:
- /* OK, we don't know what this is, can't emulate. */
- return 0;
- }
- /*
- * If it was an "IN" instruction, they expect the result to be read
- * into %eax, so we change %eax. We always return all-ones, which
- * traditionally means "there's nothing there".
- */
- if (in) {
- /* Lower bit tells means it's a 32/16 bit access */
- if (insn & 0x1) {
- if (small_operand)
- cpu->regs->eax |= 0xFFFF;
- else
- cpu->regs->eax = 0xFFFFFFFF;
- } else
- cpu->regs->eax |= 0xFF;
- }
- /* Finally, we've "done" the instruction, so move past it. */
- cpu->regs->eip += insnlen;
- /* Success! */
- return 1;
+static void setup_emulate_insn(struct lg_cpu *cpu)
+{
+ cpu->pending.trap = 13;
+ copy_from_guest(cpu, cpu->pending.insn, cpu->regs->eip,
+ sizeof(cpu->pending.insn));
+}
+
+static void setup_iomem_insn(struct lg_cpu *cpu, unsigned long iomem_addr)
+{
+ cpu->pending.trap = 14;
+ cpu->pending.addr = iomem_addr;
+ copy_from_guest(cpu, cpu->pending.insn, cpu->regs->eip,
+ sizeof(cpu->pending.insn));
}
/*H:050 Once we've re-enabled interrupts, we look at why the Guest exited. */
void lguest_arch_handle_trap(struct lg_cpu *cpu)
{
+ unsigned long iomem_addr;
+
switch (cpu->regs->trapnum) {
case 13: /* We've intercepted a General Protection Fault. */
- /*
- * Check if this was one of those annoying IN or OUT
- * instructions which we need to emulate. If so, we just go
- * back into the Guest after we've done it.
- */
+ /* Hand to Launcher to emulate those pesky IN and OUT insns */
if (cpu->regs->errcode == 0) {
- if (emulate_insn(cpu))
- return;
+ setup_emulate_insn(cpu);
+ return;
}
break;
case 14: /* We've intercepted a Page Fault. */
@@ -386,9 +396,16 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
* whether kernel or userspace code.
*/
if (demand_page(cpu, cpu->arch.last_pagefault,
- cpu->regs->errcode))
+ cpu->regs->errcode, &iomem_addr))
return;
+ /* Was this an access to memory mapped IO? */
+ if (iomem_addr) {
+ /* Tell Launcher, let it handle it. */
+ setup_iomem_insn(cpu, iomem_addr);
+ return;
+ }
+
/*
* OK, it's really not there (or not OK): the Guest needs to
* know. We write out the cr2 value so it knows where the
@@ -452,9 +469,9 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu)
static void adjust_pge(void *on)
{
if (on)
- write_cr4(read_cr4() | X86_CR4_PGE);
+ cr4_set_bits(X86_CR4_PGE);
else
- write_cr4(read_cr4() & ~X86_CR4_PGE);
+ cr4_clear_bits(X86_CR4_PGE);
}
/*H:020
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index c04fed9eb15d..84325f267acf 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -45,4 +45,10 @@ config PCC
states). Select this driver if your platform implements the
PCC clients mentioned above.
+config ALTERA_MBOX
+ tristate "Altera Mailbox"
+ help
+ An implementation of the Altera Mailbox soft core. It is used
+ to send message between processors. Say Y here if you want to use the
+ Altera mailbox support.
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index dd412c22208b..2e79231154cf 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -7,3 +7,5 @@ obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
obj-$(CONFIG_PCC) += pcc.o
+
+obj-$(CONFIG_ALTERA_MBOX) += mailbox-altera.o
diff --git a/drivers/mailbox/mailbox-altera.c b/drivers/mailbox/mailbox-altera.c
new file mode 100644
index 000000000000..a266265677d3
--- /dev/null
+++ b/drivers/mailbox/mailbox-altera.c
@@ -0,0 +1,388 @@
+/*
+ * Copyright Altera Corporation (C) 2013-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 <linux/device.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mailbox_controller.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+
+#define DRIVER_NAME "altera-mailbox"
+
+#define MAILBOX_CMD_REG 0x00
+#define MAILBOX_PTR_REG 0x04
+#define MAILBOX_STS_REG 0x08
+#define MAILBOX_INTMASK_REG 0x0C
+
+#define INT_PENDING_MSK 0x1
+#define INT_SPACE_MSK 0x2
+
+#define STS_PENDING_MSK 0x1
+#define STS_FULL_MSK 0x2
+#define STS_FULL_OFT 0x1
+
+#define MBOX_PENDING(status) (((status) & STS_PENDING_MSK))
+#define MBOX_FULL(status) (((status) & STS_FULL_MSK) >> STS_FULL_OFT)
+
+enum altera_mbox_msg {
+ MBOX_CMD = 0,
+ MBOX_PTR,
+};
+
+#define MBOX_POLLING_MS 5 /* polling interval 5ms */
+
+struct altera_mbox {
+ bool is_sender; /* 1-sender, 0-receiver */
+ bool intr_mode;
+ int irq;
+ void __iomem *mbox_base;
+ struct device *dev;
+ struct mbox_controller controller;
+
+ /* If the controller supports only RX polling mode */
+ struct timer_list rxpoll_timer;
+};
+
+static struct altera_mbox *mbox_chan_to_altera_mbox(struct mbox_chan *chan)
+{
+ if (!chan || !chan->con_priv)
+ return NULL;
+
+ return (struct altera_mbox *)chan->con_priv;
+}
+
+static inline int altera_mbox_full(struct altera_mbox *mbox)
+{
+ u32 status;
+
+ status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
+ return MBOX_FULL(status);
+}
+
+static inline int altera_mbox_pending(struct altera_mbox *mbox)
+{
+ u32 status;
+
+ status = readl_relaxed(mbox->mbox_base + MAILBOX_STS_REG);
+ return MBOX_PENDING(status);
+}
+
+static void altera_mbox_rx_intmask(struct altera_mbox *mbox, bool enable)
+{
+ u32 mask;
+
+ mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
+ if (enable)
+ mask |= INT_PENDING_MSK;
+ else
+ mask &= ~INT_PENDING_MSK;
+ writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
+}
+
+static void altera_mbox_tx_intmask(struct altera_mbox *mbox, bool enable)
+{
+ u32 mask;
+
+ mask = readl_relaxed(mbox->mbox_base + MAILBOX_INTMASK_REG);
+ if (enable)
+ mask |= INT_SPACE_MSK;
+ else
+ mask &= ~INT_SPACE_MSK;
+ writel_relaxed(mask, mbox->mbox_base + MAILBOX_INTMASK_REG);
+}
+
+static bool altera_mbox_is_sender(struct altera_mbox *mbox)
+{
+ u32 reg;
+ /* Write a magic number to PTR register and read back this register.
+ * This register is read-write if it is a sender.
+ */
+ #define MBOX_MAGIC 0xA5A5AA55
+ writel_relaxed(MBOX_MAGIC, mbox->mbox_base + MAILBOX_PTR_REG);
+ reg = readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
+ if (reg == MBOX_MAGIC) {
+ /* Clear to 0 */
+ writel_relaxed(0, mbox->mbox_base + MAILBOX_PTR_REG);
+ return true;
+ }
+ return false;
+}
+
+static void altera_mbox_rx_data(struct mbox_chan *chan)
+{
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+ u32 data[2];
+
+ if (altera_mbox_pending(mbox)) {
+ data[MBOX_PTR] =
+ readl_relaxed(mbox->mbox_base + MAILBOX_PTR_REG);
+ data[MBOX_CMD] =
+ readl_relaxed(mbox->mbox_base + MAILBOX_CMD_REG);
+ mbox_chan_received_data(chan, (void *)data);
+ }
+}
+
+static void altera_mbox_poll_rx(unsigned long data)
+{
+ struct mbox_chan *chan = (struct mbox_chan *)data;
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ altera_mbox_rx_data(chan);
+
+ mod_timer(&mbox->rxpoll_timer,
+ jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
+}
+
+static irqreturn_t altera_mbox_tx_interrupt(int irq, void *p)
+{
+ struct mbox_chan *chan = (struct mbox_chan *)p;
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ altera_mbox_tx_intmask(mbox, false);
+ mbox_chan_txdone(chan, 0);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t altera_mbox_rx_interrupt(int irq, void *p)
+{
+ struct mbox_chan *chan = (struct mbox_chan *)p;
+
+ altera_mbox_rx_data(chan);
+ return IRQ_HANDLED;
+}
+
+static int altera_mbox_startup_sender(struct mbox_chan *chan)
+{
+ int ret;
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ if (mbox->intr_mode) {
+ ret = request_irq(mbox->irq, altera_mbox_tx_interrupt, 0,
+ DRIVER_NAME, chan);
+ if (unlikely(ret)) {
+ dev_err(mbox->dev,
+ "failed to register mailbox interrupt:%d\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int altera_mbox_startup_receiver(struct mbox_chan *chan)
+{
+ int ret;
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ if (mbox->intr_mode) {
+ ret = request_irq(mbox->irq, altera_mbox_rx_interrupt, 0,
+ DRIVER_NAME, chan);
+ if (unlikely(ret)) {
+ mbox->intr_mode = false;
+ goto polling; /* use polling if failed */
+ }
+
+ altera_mbox_rx_intmask(mbox, true);
+ return 0;
+ }
+
+polling:
+ /* Setup polling timer */
+ setup_timer(&mbox->rxpoll_timer, altera_mbox_poll_rx,
+ (unsigned long)chan);
+ mod_timer(&mbox->rxpoll_timer,
+ jiffies + msecs_to_jiffies(MBOX_POLLING_MS));
+
+ return 0;
+}
+
+static int altera_mbox_send_data(struct mbox_chan *chan, void *data)
+{
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+ u32 *udata = (u32 *)data;
+
+ if (!mbox || !data)
+ return -EINVAL;
+ if (!mbox->is_sender) {
+ dev_warn(mbox->dev,
+ "failed to send. This is receiver mailbox.\n");
+ return -EINVAL;
+ }
+
+ if (altera_mbox_full(mbox))
+ return -EBUSY;
+
+ /* Enable interrupt before send */
+ if (mbox->intr_mode)
+ altera_mbox_tx_intmask(mbox, true);
+
+ /* Pointer register must write before command register */
+ writel_relaxed(udata[MBOX_PTR], mbox->mbox_base + MAILBOX_PTR_REG);
+ writel_relaxed(udata[MBOX_CMD], mbox->mbox_base + MAILBOX_CMD_REG);
+
+ return 0;
+}
+
+static bool altera_mbox_last_tx_done(struct mbox_chan *chan)
+{
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ /* Return false if mailbox is full */
+ return altera_mbox_full(mbox) ? false : true;
+}
+
+static bool altera_mbox_peek_data(struct mbox_chan *chan)
+{
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ return altera_mbox_pending(mbox) ? true : false;
+}
+
+static int altera_mbox_startup(struct mbox_chan *chan)
+{
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+ int ret = 0;
+
+ if (!mbox)
+ return -EINVAL;
+
+ if (mbox->is_sender)
+ ret = altera_mbox_startup_sender(chan);
+ else
+ ret = altera_mbox_startup_receiver(chan);
+
+ return ret;
+}
+
+static void altera_mbox_shutdown(struct mbox_chan *chan)
+{
+ struct altera_mbox *mbox = mbox_chan_to_altera_mbox(chan);
+
+ if (mbox->intr_mode) {
+ /* Unmask all interrupt masks */
+ writel_relaxed(~0, mbox->mbox_base + MAILBOX_INTMASK_REG);
+ free_irq(mbox->irq, chan);
+ } else if (!mbox->is_sender) {
+ del_timer_sync(&mbox->rxpoll_timer);
+ }
+}
+
+static struct mbox_chan_ops altera_mbox_ops = {
+ .send_data = altera_mbox_send_data,
+ .startup = altera_mbox_startup,
+ .shutdown = altera_mbox_shutdown,
+ .last_tx_done = altera_mbox_last_tx_done,
+ .peek_data = altera_mbox_peek_data,
+};
+
+static int altera_mbox_probe(struct platform_device *pdev)
+{
+ struct altera_mbox *mbox;
+ struct resource *regs;
+ struct mbox_chan *chans;
+ int ret;
+
+ mbox = devm_kzalloc(&pdev->dev, sizeof(*mbox),
+ GFP_KERNEL);
+ if (!mbox)
+ return -ENOMEM;
+
+ /* Allocated one channel */
+ chans = devm_kzalloc(&pdev->dev, sizeof(*chans), GFP_KERNEL);
+ if (!chans)
+ return -ENOMEM;
+
+ regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ mbox->mbox_base = devm_ioremap_resource(&pdev->dev, regs);
+ if (IS_ERR(mbox->mbox_base))
+ return PTR_ERR(mbox->mbox_base);
+
+ /* Check is it a sender or receiver? */
+ mbox->is_sender = altera_mbox_is_sender(mbox);
+
+ mbox->irq = platform_get_irq(pdev, 0);
+ if (mbox->irq >= 0)
+ mbox->intr_mode = true;
+
+ mbox->dev = &pdev->dev;
+
+ /* Hardware supports only one channel. */
+ chans[0].con_priv = mbox;
+ mbox->controller.dev = mbox->dev;
+ mbox->controller.num_chans = 1;
+ mbox->controller.chans = chans;
+ mbox->controller.ops = &altera_mbox_ops;
+
+ if (mbox->is_sender) {
+ if (mbox->intr_mode) {
+ mbox->controller.txdone_irq = true;
+ } else {
+ mbox->controller.txdone_poll = true;
+ mbox->controller.txpoll_period = MBOX_POLLING_MS;
+ }
+ }
+
+ ret = mbox_controller_register(&mbox->controller);
+ if (ret) {
+ dev_err(&pdev->dev, "Register mailbox failed\n");
+ goto err;
+ }
+
+ platform_set_drvdata(pdev, mbox);
+err:
+ return ret;
+}
+
+static int altera_mbox_remove(struct platform_device *pdev)
+{
+ struct altera_mbox *mbox = platform_get_drvdata(pdev);
+
+ if (!mbox)
+ return -EINVAL;
+
+ mbox_controller_unregister(&mbox->controller);
+
+ return 0;
+}
+
+static const struct of_device_id altera_mbox_match[] = {
+ { .compatible = "altr,mailbox-1.0" },
+ { /* Sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, altera_mbox_match);
+
+static struct platform_driver altera_mbox_driver = {
+ .probe = altera_mbox_probe,
+ .remove = altera_mbox_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = altera_mbox_match,
+ },
+};
+
+module_platform_driver(altera_mbox_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Altera mailbox specific functions");
+MODULE_AUTHOR("Ley Foon Tan <lftan@altera.com>");
+MODULE_ALIAS("platform:altera-mailbox");
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index 59aad4d5da53..19b491d2964f 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -87,7 +87,7 @@ static void msg_submit(struct mbox_chan *chan)
exit:
spin_unlock_irqrestore(&chan->lock, flags);
- if (!err && chan->txdone_method == TXDONE_BY_POLL)
+ if (!err && (chan->txdone_method & TXDONE_BY_POLL))
poll_txdone((unsigned long)chan->mbox);
}
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
index 6dbf6fcbdfaf..977c814cdf6f 100644
--- a/drivers/mailbox/pcc.c
+++ b/drivers/mailbox/pcc.c
@@ -386,16 +386,16 @@ static int __init pcc_init(void)
ret = acpi_pcc_probe();
if (ret) {
- pr_err("ACPI PCC probe failed.\n");
+ pr_debug("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;
+ if (IS_ERR(pcc_pdev)) {
+ pr_debug("Err creating PCC platform bundle\n");
+ return PTR_ERR(pcc_pdev);
}
return 0;
diff --git a/drivers/mcb/mcb-pci.c b/drivers/mcb/mcb-pci.c
index 5e1bd5db02c8..0af7361e377f 100644
--- a/drivers/mcb/mcb-pci.c
+++ b/drivers/mcb/mcb-pci.c
@@ -51,7 +51,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
priv->mapbase = pci_resource_start(pdev, 0);
if (!priv->mapbase) {
dev_err(&pdev->dev, "No PCI resource\n");
- goto err_start;
+ goto out_disable;
}
res = request_mem_region(priv->mapbase, CHAM_HEADER_SIZE,
@@ -59,14 +59,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
if (IS_ERR(res)) {
dev_err(&pdev->dev, "Failed to request PCI memory\n");
ret = PTR_ERR(res);
- goto err_start;
+ goto out_disable;
}
priv->base = ioremap(priv->mapbase, CHAM_HEADER_SIZE);
if (!priv->base) {
dev_err(&pdev->dev, "Cannot ioremap\n");
ret = -ENOMEM;
- goto err_ioremap;
+ goto out_release;
}
flags = pci_resource_flags(pdev, 0);
@@ -74,7 +74,7 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ret = -ENOTSUPP;
dev_err(&pdev->dev,
"IO mapped PCI devices are not supported\n");
- goto err_ioremap;
+ goto out_release;
}
pci_set_drvdata(pdev, priv);
@@ -82,14 +82,14 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
priv->bus = mcb_alloc_bus(&pdev->dev);
if (IS_ERR(priv->bus)) {
ret = PTR_ERR(priv->bus);
- goto err_drvdata;
+ goto out_iounmap;
}
priv->bus->get_irq = mcb_pci_get_irq;
ret = chameleon_parse_cells(priv->bus, priv->mapbase, priv->base);
if (ret < 0)
- goto err_drvdata;
+ goto out_iounmap;
num_cells = ret;
dev_dbg(&pdev->dev, "Found %d cells\n", num_cells);
@@ -98,11 +98,11 @@ static int mcb_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return 0;
-err_drvdata:
+out_iounmap:
iounmap(priv->base);
-err_ioremap:
+out_release:
pci_release_region(pdev, 0);
-err_start:
+out_disable:
pci_disable_device(pdev);
return ret;
}
diff --git a/drivers/md/Kconfig b/drivers/md/Kconfig
index 5bdedf6df153..63e05e32b462 100644
--- a/drivers/md/Kconfig
+++ b/drivers/md/Kconfig
@@ -5,6 +5,7 @@
menuconfig MD
bool "Multiple devices driver support (RAID and LVM)"
depends on BLOCK
+ select SRCU
help
Support multiple physical spindles through a single logical device.
Required for RAID and logical volume management.
@@ -177,7 +178,7 @@ config MD_FAULTY
source "drivers/md/bcache/Kconfig"
config BLK_DEV_DM_BUILTIN
- boolean
+ bool
config BLK_DEV_DM
tristate "Device mapper support"
@@ -196,7 +197,7 @@ config BLK_DEV_DM
If unsure, say N.
config DM_DEBUG
- boolean "Device mapper debugging support"
+ bool "Device mapper debugging support"
depends on BLK_DEV_DM
---help---
Enable this for messages that may help debug device-mapper problems.
@@ -230,9 +231,8 @@ config DM_CRYPT
transparently encrypts the data on it. You'll need to activate
the ciphers you're going to use in the cryptoapi configuration.
- Information on how to use dm-crypt can be found on
-
- <http://www.saout.de/misc/dm-crypt/>
+ For further information on dm-crypt and userspace tools see:
+ <http://code.google.com/p/cryptsetup/wiki/DMCrypt>
To compile this code as a module, choose M here: the module will
be called dm-crypt.
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c
index da3604e73e8a..3a5767968ba0 100644
--- a/drivers/md/bitmap.c
+++ b/drivers/md/bitmap.c
@@ -72,6 +72,19 @@ __acquires(bitmap->lock)
/* this page has not been allocated yet */
spin_unlock_irq(&bitmap->lock);
+ /* It is possible that this is being called inside a
+ * prepare_to_wait/finish_wait loop from raid5c:make_request().
+ * In general it is not permitted to sleep in that context as it
+ * can cause the loop to spin freely.
+ * That doesn't apply here as we can only reach this point
+ * once with any loop.
+ * When this function completes, either bp[page].map or
+ * bp[page].hijacked. In either case, this function will
+ * abort before getting to this point again. So there is
+ * no risk of a free-spin, and so it is safe to assert
+ * that sleeping here is allowed.
+ */
+ sched_annotate_sleep();
mappage = kzalloc(PAGE_SIZE, GFP_NOIO);
spin_lock_irq(&bitmap->lock);
@@ -1606,7 +1619,9 @@ void bitmap_destroy(struct mddev *mddev)
return;
mutex_lock(&mddev->bitmap_info.mutex);
+ spin_lock(&mddev->lock);
mddev->bitmap = NULL; /* disconnect from the md device */
+ spin_unlock(&mddev->lock);
mutex_unlock(&mddev->bitmap_info.mutex);
if (mddev->thread)
mddev->thread->timeout = MAX_SCHEDULE_TIMEOUT;
@@ -2196,11 +2211,13 @@ __ATTR(metadata, S_IRUGO|S_IWUSR, metadata_show, metadata_store);
static ssize_t can_clear_show(struct mddev *mddev, char *page)
{
int len;
+ spin_lock(&mddev->lock);
if (mddev->bitmap)
len = sprintf(page, "%s\n", (mddev->bitmap->need_sync ?
"false" : "true"));
else
len = sprintf(page, "\n");
+ spin_unlock(&mddev->lock);
return len;
}
@@ -2225,10 +2242,15 @@ __ATTR(can_clear, S_IRUGO|S_IWUSR, can_clear_show, can_clear_store);
static ssize_t
behind_writes_used_show(struct mddev *mddev, char *page)
{
+ ssize_t ret;
+ spin_lock(&mddev->lock);
if (mddev->bitmap == NULL)
- return sprintf(page, "0\n");
- return sprintf(page, "%lu\n",
- mddev->bitmap->behind_writes_used);
+ ret = sprintf(page, "0\n");
+ else
+ ret = sprintf(page, "%lu\n",
+ mddev->bitmap->behind_writes_used);
+ spin_unlock(&mddev->lock);
+ return ret;
}
static ssize_t
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index c33b49792b87..86dbbc737402 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -11,6 +11,7 @@
#include <linux/device-mapper.h>
#include <linux/dm-io.h>
#include <linux/slab.h>
+#include <linux/jiffies.h>
#include <linux/vmalloc.h>
#include <linux/shrinker.h>
#include <linux/module.h>
@@ -1739,7 +1740,7 @@ static unsigned get_max_age_hz(void)
static bool older_than(struct dm_buffer *b, unsigned long age_hz)
{
- return (jiffies - b->last_accessed) >= age_hz;
+ return time_after_eq(jiffies, b->last_accessed + age_hz);
}
static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz)
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 21b156242e42..c1c010498a21 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -683,7 +683,7 @@ static struct dm_cache_metadata *metadata_open(struct block_device *bdev,
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
DMERR("could not allocate metadata struct");
- return NULL;
+ return ERR_PTR(-ENOMEM);
}
atomic_set(&cmd->ref_count, 1);
@@ -745,7 +745,7 @@ static struct dm_cache_metadata *lookup_or_open(struct block_device *bdev,
return cmd;
cmd = metadata_open(bdev, data_block_size, may_format_device, policy_hint_size);
- if (cmd) {
+ if (!IS_ERR(cmd)) {
mutex_lock(&table_lock);
cmd2 = lookup(bdev);
if (cmd2) {
@@ -780,9 +780,10 @@ struct dm_cache_metadata *dm_cache_metadata_open(struct block_device *bdev,
{
struct dm_cache_metadata *cmd = lookup_or_open(bdev, data_block_size,
may_format_device, policy_hint_size);
- if (cmd && !same_params(cmd, data_block_size)) {
+
+ if (!IS_ERR(cmd) && !same_params(cmd, data_block_size)) {
dm_cache_metadata_close(cmd);
- return NULL;
+ return ERR_PTR(-EINVAL);
}
return cmd;
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index e1650539cc2f..7755af351867 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -11,6 +11,7 @@
#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>
+#include <linux/jiffies.h>
#include <linux/init.h>
#include <linux/mempool.h>
#include <linux/module.h>
@@ -1562,8 +1563,8 @@ static void process_bio(struct cache *cache, struct prealloc *structs,
static int need_commit_due_to_time(struct cache *cache)
{
- return jiffies < cache->last_commit_jiffies ||
- jiffies > cache->last_commit_jiffies + COMMIT_PERIOD;
+ return !time_in_range(jiffies, cache->last_commit_jiffies,
+ cache->last_commit_jiffies + COMMIT_PERIOD);
}
static int commit_if_needed(struct cache *cache)
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index 08981be7baa1..713a96237a80 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -18,9 +18,11 @@
#include <linux/slab.h>
#include <linux/crypto.h>
#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/backing-dev.h>
#include <linux/atomic.h>
#include <linux/scatterlist.h>
+#include <linux/rbtree.h>
#include <asm/page.h>
#include <asm/unaligned.h>
#include <crypto/hash.h>
@@ -58,7 +60,8 @@ struct dm_crypt_io {
atomic_t io_pending;
int error;
sector_t sector;
- struct dm_crypt_io *base_io;
+
+ struct rb_node rb_node;
} CRYPTO_MINALIGN_ATTR;
struct dm_crypt_request {
@@ -108,7 +111,8 @@ struct iv_tcw_private {
* Crypt: maps a linear range of a block device
* and encrypts / decrypts at the same time.
*/
-enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID };
+enum flags { DM_CRYPT_SUSPENDED, DM_CRYPT_KEY_VALID,
+ DM_CRYPT_SAME_CPU, DM_CRYPT_NO_OFFLOAD };
/*
* The fields in here must be read only after initialization.
@@ -121,14 +125,18 @@ struct crypt_config {
* pool for per bio private data, crypto requests and
* encryption requeusts/buffer pages
*/
- mempool_t *io_pool;
mempool_t *req_pool;
mempool_t *page_pool;
struct bio_set *bs;
+ struct mutex bio_alloc_lock;
struct workqueue_struct *io_queue;
struct workqueue_struct *crypt_queue;
+ struct task_struct *write_thread;
+ wait_queue_head_t write_thread_wait;
+ struct rb_root write_tree;
+
char *cipher;
char *cipher_string;
@@ -172,9 +180,6 @@ struct crypt_config {
};
#define MIN_IOS 16
-#define MIN_POOL_PAGES 32
-
-static struct kmem_cache *_crypt_io_pool;
static void clone_init(struct dm_crypt_io *, struct bio *);
static void kcryptd_queue_crypt(struct dm_crypt_io *io);
@@ -946,57 +951,70 @@ static int crypt_convert(struct crypt_config *cc,
return 0;
}
+static void crypt_free_buffer_pages(struct crypt_config *cc, struct bio *clone);
+
/*
* Generate a new unfragmented bio with the given size
* This should never violate the device limitations
- * May return a smaller bio when running out of pages, indicated by
- * *out_of_pages set to 1.
+ *
+ * This function may be called concurrently. If we allocate from the mempool
+ * concurrently, there is a possibility of deadlock. For example, if we have
+ * mempool of 256 pages, two processes, each wanting 256, pages allocate from
+ * the mempool concurrently, it may deadlock in a situation where both processes
+ * have allocated 128 pages and the mempool is exhausted.
+ *
+ * In order to avoid this scenario we allocate the pages under a mutex.
+ *
+ * In order to not degrade performance with excessive locking, we try
+ * non-blocking allocations without a mutex first but on failure we fallback
+ * to blocking allocations with a mutex.
*/
-static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size,
- unsigned *out_of_pages)
+static struct bio *crypt_alloc_buffer(struct dm_crypt_io *io, unsigned size)
{
struct crypt_config *cc = io->cc;
struct bio *clone;
unsigned int nr_iovecs = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
- gfp_t gfp_mask = GFP_NOIO | __GFP_HIGHMEM;
- unsigned i, len;
+ gfp_t gfp_mask = GFP_NOWAIT | __GFP_HIGHMEM;
+ unsigned i, len, remaining_size;
struct page *page;
+ struct bio_vec *bvec;
+
+retry:
+ if (unlikely(gfp_mask & __GFP_WAIT))
+ mutex_lock(&cc->bio_alloc_lock);
clone = bio_alloc_bioset(GFP_NOIO, nr_iovecs, cc->bs);
if (!clone)
- return NULL;
+ goto return_clone;
clone_init(io, clone);
- *out_of_pages = 0;
+
+ remaining_size = size;
for (i = 0; i < nr_iovecs; i++) {
page = mempool_alloc(cc->page_pool, gfp_mask);
if (!page) {
- *out_of_pages = 1;
- break;
+ crypt_free_buffer_pages(cc, clone);
+ bio_put(clone);
+ gfp_mask |= __GFP_WAIT;
+ goto retry;
}
- /*
- * If additional pages cannot be allocated without waiting,
- * return a partially-allocated bio. The caller will then try
- * to allocate more bios while submitting this partial bio.
- */
- gfp_mask = (gfp_mask | __GFP_NOWARN) & ~__GFP_WAIT;
+ len = (remaining_size > PAGE_SIZE) ? PAGE_SIZE : remaining_size;
- len = (size > PAGE_SIZE) ? PAGE_SIZE : size;
+ bvec = &clone->bi_io_vec[clone->bi_vcnt++];
+ bvec->bv_page = page;
+ bvec->bv_len = len;
+ bvec->bv_offset = 0;
- if (!bio_add_page(clone, page, len, 0)) {
- mempool_free(page, cc->page_pool);
- break;
- }
+ clone->bi_iter.bi_size += len;
- size -= len;
+ remaining_size -= len;
}
- if (!clone->bi_iter.bi_size) {
- bio_put(clone);
- return NULL;
- }
+return_clone:
+ if (unlikely(gfp_mask & __GFP_WAIT))
+ mutex_unlock(&cc->bio_alloc_lock);
return clone;
}
@@ -1020,7 +1038,6 @@ static void crypt_io_init(struct dm_crypt_io *io, struct crypt_config *cc,
io->base_bio = bio;
io->sector = sector;
io->error = 0;
- io->base_io = NULL;
io->ctx.req = NULL;
atomic_set(&io->io_pending, 0);
}
@@ -1033,13 +1050,11 @@ static void crypt_inc_pending(struct dm_crypt_io *io)
/*
* One of the bios was finished. Check for completion of
* the whole request and correctly clean up the buffer.
- * If base_io is set, wait for the last fragment to complete.
*/
static void crypt_dec_pending(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->cc;
struct bio *base_bio = io->base_bio;
- struct dm_crypt_io *base_io = io->base_io;
int error = io->error;
if (!atomic_dec_and_test(&io->io_pending))
@@ -1047,16 +1062,8 @@ static void crypt_dec_pending(struct dm_crypt_io *io)
if (io->ctx.req)
crypt_free_req(cc, io->ctx.req, base_bio);
- if (io != dm_per_bio_data(base_bio, cc->per_bio_data_size))
- mempool_free(io, cc->io_pool);
-
- if (likely(!base_io))
- bio_endio(base_bio, error);
- else {
- if (error && !base_io->error)
- base_io->error = error;
- crypt_dec_pending(base_io);
- }
+
+ bio_endio(base_bio, error);
}
/*
@@ -1138,37 +1145,97 @@ static int kcryptd_io_read(struct dm_crypt_io *io, gfp_t gfp)
return 0;
}
+static void kcryptd_io_read_work(struct work_struct *work)
+{
+ struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
+
+ crypt_inc_pending(io);
+ if (kcryptd_io_read(io, GFP_NOIO))
+ io->error = -ENOMEM;
+ crypt_dec_pending(io);
+}
+
+static void kcryptd_queue_read(struct dm_crypt_io *io)
+{
+ struct crypt_config *cc = io->cc;
+
+ INIT_WORK(&io->work, kcryptd_io_read_work);
+ queue_work(cc->io_queue, &io->work);
+}
+
static void kcryptd_io_write(struct dm_crypt_io *io)
{
struct bio *clone = io->ctx.bio_out;
+
generic_make_request(clone);
}
-static void kcryptd_io(struct work_struct *work)
+#define crypt_io_from_node(node) rb_entry((node), struct dm_crypt_io, rb_node)
+
+static int dmcrypt_write(void *data)
{
- struct dm_crypt_io *io = container_of(work, struct dm_crypt_io, work);
+ struct crypt_config *cc = data;
+ struct dm_crypt_io *io;
- if (bio_data_dir(io->base_bio) == READ) {
- crypt_inc_pending(io);
- if (kcryptd_io_read(io, GFP_NOIO))
- io->error = -ENOMEM;
- crypt_dec_pending(io);
- } else
- kcryptd_io_write(io);
-}
+ while (1) {
+ struct rb_root write_tree;
+ struct blk_plug plug;
-static void kcryptd_queue_io(struct dm_crypt_io *io)
-{
- struct crypt_config *cc = io->cc;
+ DECLARE_WAITQUEUE(wait, current);
- INIT_WORK(&io->work, kcryptd_io);
- queue_work(cc->io_queue, &io->work);
+ spin_lock_irq(&cc->write_thread_wait.lock);
+continue_locked:
+
+ if (!RB_EMPTY_ROOT(&cc->write_tree))
+ goto pop_from_list;
+
+ __set_current_state(TASK_INTERRUPTIBLE);
+ __add_wait_queue(&cc->write_thread_wait, &wait);
+
+ spin_unlock_irq(&cc->write_thread_wait.lock);
+
+ if (unlikely(kthread_should_stop())) {
+ set_task_state(current, TASK_RUNNING);
+ remove_wait_queue(&cc->write_thread_wait, &wait);
+ break;
+ }
+
+ schedule();
+
+ set_task_state(current, TASK_RUNNING);
+ spin_lock_irq(&cc->write_thread_wait.lock);
+ __remove_wait_queue(&cc->write_thread_wait, &wait);
+ goto continue_locked;
+
+pop_from_list:
+ write_tree = cc->write_tree;
+ cc->write_tree = RB_ROOT;
+ spin_unlock_irq(&cc->write_thread_wait.lock);
+
+ BUG_ON(rb_parent(write_tree.rb_node));
+
+ /*
+ * Note: we cannot walk the tree here with rb_next because
+ * the structures may be freed when kcryptd_io_write is called.
+ */
+ blk_start_plug(&plug);
+ do {
+ io = crypt_io_from_node(rb_first(&write_tree));
+ rb_erase(&io->rb_node, &write_tree);
+ kcryptd_io_write(io);
+ } while (!RB_EMPTY_ROOT(&write_tree));
+ blk_finish_plug(&plug);
+ }
+ return 0;
}
static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
{
struct bio *clone = io->ctx.bio_out;
struct crypt_config *cc = io->cc;
+ unsigned long flags;
+ sector_t sector;
+ struct rb_node **rbp, *parent;
if (unlikely(io->error < 0)) {
crypt_free_buffer_pages(cc, clone);
@@ -1182,20 +1249,34 @@ static void kcryptd_crypt_write_io_submit(struct dm_crypt_io *io, int async)
clone->bi_iter.bi_sector = cc->start + io->sector;
- if (async)
- kcryptd_queue_io(io);
- else
+ if (likely(!async) && test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags)) {
generic_make_request(clone);
+ return;
+ }
+
+ spin_lock_irqsave(&cc->write_thread_wait.lock, flags);
+ rbp = &cc->write_tree.rb_node;
+ parent = NULL;
+ sector = io->sector;
+ while (*rbp) {
+ parent = *rbp;
+ if (sector < crypt_io_from_node(parent)->sector)
+ rbp = &(*rbp)->rb_left;
+ else
+ rbp = &(*rbp)->rb_right;
+ }
+ rb_link_node(&io->rb_node, parent, rbp);
+ rb_insert_color(&io->rb_node, &cc->write_tree);
+
+ wake_up_locked(&cc->write_thread_wait);
+ spin_unlock_irqrestore(&cc->write_thread_wait.lock, flags);
}
static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
{
struct crypt_config *cc = io->cc;
struct bio *clone;
- struct dm_crypt_io *new_io;
int crypt_finished;
- unsigned out_of_pages = 0;
- unsigned remaining = io->base_bio->bi_iter.bi_size;
sector_t sector = io->sector;
int r;
@@ -1205,80 +1286,30 @@ static void kcryptd_crypt_write_convert(struct dm_crypt_io *io)
crypt_inc_pending(io);
crypt_convert_init(cc, &io->ctx, NULL, io->base_bio, sector);
- /*
- * The allocated buffers can be smaller than the whole bio,
- * so repeat the whole process until all the data can be handled.
- */
- while (remaining) {
- clone = crypt_alloc_buffer(io, remaining, &out_of_pages);
- if (unlikely(!clone)) {
- io->error = -ENOMEM;
- break;
- }
-
- io->ctx.bio_out = clone;
- io->ctx.iter_out = clone->bi_iter;
-
- remaining -= clone->bi_iter.bi_size;
- sector += bio_sectors(clone);
-
- crypt_inc_pending(io);
-
- r = crypt_convert(cc, &io->ctx);
- if (r < 0)
- io->error = -EIO;
-
- crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
-
- /* Encryption was already finished, submit io now */
- if (crypt_finished) {
- kcryptd_crypt_write_io_submit(io, 0);
-
- /*
- * If there was an error, do not try next fragments.
- * For async, error is processed in async handler.
- */
- if (unlikely(r < 0))
- break;
+ clone = crypt_alloc_buffer(io, io->base_bio->bi_iter.bi_size);
+ if (unlikely(!clone)) {
+ io->error = -EIO;
+ goto dec;
+ }
- io->sector = sector;
- }
+ io->ctx.bio_out = clone;
+ io->ctx.iter_out = clone->bi_iter;
- /*
- * Out of memory -> run queues
- * But don't wait if split was due to the io size restriction
- */
- if (unlikely(out_of_pages))
- congestion_wait(BLK_RW_ASYNC, HZ/100);
+ sector += bio_sectors(clone);
- /*
- * With async crypto it is unsafe to share the crypto context
- * between fragments, so switch to a new dm_crypt_io structure.
- */
- if (unlikely(!crypt_finished && remaining)) {
- new_io = mempool_alloc(cc->io_pool, GFP_NOIO);
- crypt_io_init(new_io, io->cc, io->base_bio, sector);
- crypt_inc_pending(new_io);
- crypt_convert_init(cc, &new_io->ctx, NULL,
- io->base_bio, sector);
- new_io->ctx.iter_in = io->ctx.iter_in;
-
- /*
- * Fragments after the first use the base_io
- * pending count.
- */
- if (!io->base_io)
- new_io->base_io = io;
- else {
- new_io->base_io = io->base_io;
- crypt_inc_pending(io->base_io);
- crypt_dec_pending(io);
- }
+ crypt_inc_pending(io);
+ r = crypt_convert(cc, &io->ctx);
+ if (r)
+ io->error = -EIO;
+ crypt_finished = atomic_dec_and_test(&io->ctx.cc_pending);
- io = new_io;
- }
+ /* Encryption was already finished, submit io now */
+ if (crypt_finished) {
+ kcryptd_crypt_write_io_submit(io, 0);
+ io->sector = sector;
}
+dec:
crypt_dec_pending(io);
}
@@ -1481,6 +1512,9 @@ static void crypt_dtr(struct dm_target *ti)
if (!cc)
return;
+ if (cc->write_thread)
+ kthread_stop(cc->write_thread);
+
if (cc->io_queue)
destroy_workqueue(cc->io_queue);
if (cc->crypt_queue)
@@ -1495,8 +1529,6 @@ static void crypt_dtr(struct dm_target *ti)
mempool_destroy(cc->page_pool);
if (cc->req_pool)
mempool_destroy(cc->req_pool);
- if (cc->io_pool)
- mempool_destroy(cc->io_pool);
if (cc->iv_gen_ops && cc->iv_gen_ops->dtr)
cc->iv_gen_ops->dtr(cc);
@@ -1688,7 +1720,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
char dummy;
static struct dm_arg _args[] = {
- {0, 1, "Invalid number of feature args"},
+ {0, 3, "Invalid number of feature args"},
};
if (argc < 5) {
@@ -1710,13 +1742,6 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (ret < 0)
goto bad;
- ret = -ENOMEM;
- cc->io_pool = mempool_create_slab_pool(MIN_IOS, _crypt_io_pool);
- if (!cc->io_pool) {
- ti->error = "Cannot allocate crypt io mempool";
- goto bad;
- }
-
cc->dmreq_start = sizeof(struct ablkcipher_request);
cc->dmreq_start += crypto_ablkcipher_reqsize(any_tfm(cc));
cc->dmreq_start = ALIGN(cc->dmreq_start, __alignof__(struct dm_crypt_request));
@@ -1734,6 +1759,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
iv_size_padding = crypto_ablkcipher_alignmask(any_tfm(cc));
}
+ ret = -ENOMEM;
cc->req_pool = mempool_create_kmalloc_pool(MIN_IOS, cc->dmreq_start +
sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size);
if (!cc->req_pool) {
@@ -1746,7 +1772,7 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
sizeof(struct dm_crypt_request) + iv_size_padding + cc->iv_size,
ARCH_KMALLOC_MINALIGN);
- cc->page_pool = mempool_create_page_pool(MIN_POOL_PAGES, 0);
+ cc->page_pool = mempool_create_page_pool(BIO_MAX_PAGES, 0);
if (!cc->page_pool) {
ti->error = "Cannot allocate page mempool";
goto bad;
@@ -1758,6 +1784,8 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
+ mutex_init(&cc->bio_alloc_lock);
+
ret = -EINVAL;
if (sscanf(argv[2], "%llu%c", &tmpll, &dummy) != 1) {
ti->error = "Invalid iv_offset sector";
@@ -1788,15 +1816,26 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
if (ret)
goto bad;
- opt_string = dm_shift_arg(&as);
+ while (opt_params--) {
+ opt_string = dm_shift_arg(&as);
+ if (!opt_string) {
+ ti->error = "Not enough feature arguments";
+ goto bad;
+ }
- if (opt_params == 1 && opt_string &&
- !strcasecmp(opt_string, "allow_discards"))
- ti->num_discard_bios = 1;
- else if (opt_params) {
- ret = -EINVAL;
- ti->error = "Invalid feature arguments";
- goto bad;
+ if (!strcasecmp(opt_string, "allow_discards"))
+ ti->num_discard_bios = 1;
+
+ else if (!strcasecmp(opt_string, "same_cpu_crypt"))
+ set_bit(DM_CRYPT_SAME_CPU, &cc->flags);
+
+ else if (!strcasecmp(opt_string, "submit_from_crypt_cpus"))
+ set_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
+
+ else {
+ ti->error = "Invalid feature arguments";
+ goto bad;
+ }
}
}
@@ -1807,13 +1846,28 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
goto bad;
}
- cc->crypt_queue = alloc_workqueue("kcryptd",
- WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+ if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
+ cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+ else
+ cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
+ num_online_cpus());
if (!cc->crypt_queue) {
ti->error = "Couldn't create kcryptd queue";
goto bad;
}
+ init_waitqueue_head(&cc->write_thread_wait);
+ cc->write_tree = RB_ROOT;
+
+ cc->write_thread = kthread_create(dmcrypt_write, cc, "dmcrypt_write");
+ if (IS_ERR(cc->write_thread)) {
+ ret = PTR_ERR(cc->write_thread);
+ cc->write_thread = NULL;
+ ti->error = "Couldn't spawn write thread";
+ goto bad;
+ }
+ wake_up_process(cc->write_thread);
+
ti->num_flush_bios = 1;
ti->discard_zeroes_data_unsupported = true;
@@ -1848,7 +1902,7 @@ static int crypt_map(struct dm_target *ti, struct bio *bio)
if (bio_data_dir(io->base_bio) == READ) {
if (kcryptd_io_read(io, GFP_NOWAIT))
- kcryptd_queue_io(io);
+ kcryptd_queue_read(io);
} else
kcryptd_queue_crypt(io);
@@ -1860,6 +1914,7 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
{
struct crypt_config *cc = ti->private;
unsigned i, sz = 0;
+ int num_feature_args = 0;
switch (type) {
case STATUSTYPE_INFO:
@@ -1878,8 +1933,18 @@ static void crypt_status(struct dm_target *ti, status_type_t type,
DMEMIT(" %llu %s %llu", (unsigned long long)cc->iv_offset,
cc->dev->name, (unsigned long long)cc->start);
- if (ti->num_discard_bios)
- DMEMIT(" 1 allow_discards");
+ num_feature_args += !!ti->num_discard_bios;
+ num_feature_args += test_bit(DM_CRYPT_SAME_CPU, &cc->flags);
+ num_feature_args += test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags);
+ if (num_feature_args) {
+ DMEMIT(" %d", num_feature_args);
+ if (ti->num_discard_bios)
+ DMEMIT(" allow_discards");
+ if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
+ DMEMIT(" same_cpu_crypt");
+ if (test_bit(DM_CRYPT_NO_OFFLOAD, &cc->flags))
+ DMEMIT(" submit_from_crypt_cpus");
+ }
break;
}
@@ -1976,7 +2041,7 @@ static int crypt_iterate_devices(struct dm_target *ti,
static struct target_type crypt_target = {
.name = "crypt",
- .version = {1, 13, 0},
+ .version = {1, 14, 0},
.module = THIS_MODULE,
.ctr = crypt_ctr,
.dtr = crypt_dtr,
@@ -1994,15 +2059,9 @@ static int __init dm_crypt_init(void)
{
int r;
- _crypt_io_pool = KMEM_CACHE(dm_crypt_io, 0);
- if (!_crypt_io_pool)
- return -ENOMEM;
-
r = dm_register_target(&crypt_target);
- if (r < 0) {
+ if (r < 0)
DMERR("register failed %d", r);
- kmem_cache_destroy(_crypt_io_pool);
- }
return r;
}
@@ -2010,7 +2069,6 @@ static int __init dm_crypt_init(void)
static void __exit dm_crypt_exit(void)
{
dm_unregister_target(&crypt_target);
- kmem_cache_destroy(_crypt_io_pool);
}
module_init(dm_crypt_init);
diff --git a/drivers/md/dm-io.c b/drivers/md/dm-io.c
index c09359db3a90..37de0173b6d2 100644
--- a/drivers/md/dm-io.c
+++ b/drivers/md/dm-io.c
@@ -290,6 +290,12 @@ static void do_region(int rw, unsigned region, struct dm_io_region *where,
unsigned short logical_block_size = queue_logical_block_size(q);
sector_t num_sectors;
+ /* Reject unsupported discard requests */
+ if ((rw & REQ_DISCARD) && !blk_queue_discard(q)) {
+ dec_count(io, region, -EOPNOTSUPP);
+ return;
+ }
+
/*
* where->count may be zero if rw holds a flush and we need to
* send a zero-sized flush.
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 73f791bb9ea4..c8a18e4ee9dc 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -639,8 +639,8 @@ static int check_name(const char *name)
/*
* On successful return, the caller must not attempt to acquire
- * _hash_lock without first calling dm_table_put, because dm_table_destroy
- * waits for this dm_table_put and could be called under this lock.
+ * _hash_lock without first calling dm_put_live_table, because dm_table_destroy
+ * waits for this dm_put_live_table and could be called under this lock.
*/
static struct dm_table *dm_get_inactive_table(struct mapped_device *md, int *srcu_idx)
{
diff --git a/drivers/md/dm-log-userspace-base.c b/drivers/md/dm-log-userspace-base.c
index b953db6cc229..03177ca0b009 100644
--- a/drivers/md/dm-log-userspace-base.c
+++ b/drivers/md/dm-log-userspace-base.c
@@ -6,6 +6,7 @@
#include <linux/bio.h>
#include <linux/slab.h>
+#include <linux/jiffies.h>
#include <linux/dm-dirty-log.h>
#include <linux/device-mapper.h>
#include <linux/dm-log-userspace.h>
@@ -829,7 +830,7 @@ static int userspace_is_remote_recovering(struct dm_dirty_log *log,
int r;
uint64_t region64 = region;
struct log_c *lc = log->context;
- static unsigned long long limit;
+ static unsigned long limit;
struct {
int64_t is_recovering;
uint64_t in_sync_hint;
@@ -845,7 +846,7 @@ static int userspace_is_remote_recovering(struct dm_dirty_log *log,
*/
if (region < lc->in_sync_hint)
return 0;
- else if (jiffies < limit)
+ else if (time_after(limit, jiffies))
return 1;
limit = jiffies + (HZ / 4);
diff --git a/drivers/md/dm-mpath.c b/drivers/md/dm-mpath.c
index 7b6b0f0f831a..d376dc87716e 100644
--- a/drivers/md/dm-mpath.c
+++ b/drivers/md/dm-mpath.c
@@ -11,6 +11,7 @@
#include "dm-path-selector.h"
#include "dm-uevent.h"
+#include <linux/blkdev.h>
#include <linux/ctype.h>
#include <linux/init.h>
#include <linux/mempool.h>
@@ -378,18 +379,18 @@ static int __must_push_back(struct multipath *m)
/*
* Map cloned requests
*/
-static int multipath_map(struct dm_target *ti, struct request *clone,
- union map_info *map_context)
+static int __multipath_map(struct dm_target *ti, struct request *clone,
+ union map_info *map_context,
+ struct request *rq, struct request **__clone)
{
struct multipath *m = (struct multipath *) ti->private;
int r = DM_MAPIO_REQUEUE;
- size_t nr_bytes = blk_rq_bytes(clone);
- unsigned long flags;
+ size_t nr_bytes = clone ? blk_rq_bytes(clone) : blk_rq_bytes(rq);
struct pgpath *pgpath;
struct block_device *bdev;
struct dm_mpath_io *mpio;
- spin_lock_irqsave(&m->lock, flags);
+ spin_lock_irq(&m->lock);
/* Do we need to select a new pgpath? */
if (!m->current_pgpath ||
@@ -411,25 +412,61 @@ static int multipath_map(struct dm_target *ti, struct request *clone,
/* ENOMEM, requeue */
goto out_unlock;
- bdev = pgpath->path.dev->bdev;
- clone->q = bdev_get_queue(bdev);
- clone->rq_disk = bdev->bd_disk;
- clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
mpio = map_context->ptr;
mpio->pgpath = pgpath;
mpio->nr_bytes = nr_bytes;
+
+ bdev = pgpath->path.dev->bdev;
+
+ spin_unlock_irq(&m->lock);
+
+ if (clone) {
+ /* Old request-based interface: allocated clone is passed in */
+ clone->q = bdev_get_queue(bdev);
+ clone->rq_disk = bdev->bd_disk;
+ clone->cmd_flags |= REQ_FAILFAST_TRANSPORT;
+ } else {
+ /* blk-mq request-based interface */
+ *__clone = blk_get_request(bdev_get_queue(bdev),
+ rq_data_dir(rq), GFP_KERNEL);
+ if (IS_ERR(*__clone))
+ /* ENOMEM, requeue */
+ return r;
+ (*__clone)->bio = (*__clone)->biotail = NULL;
+ (*__clone)->rq_disk = bdev->bd_disk;
+ (*__clone)->cmd_flags |= REQ_FAILFAST_TRANSPORT;
+ }
+
if (pgpath->pg->ps.type->start_io)
pgpath->pg->ps.type->start_io(&pgpath->pg->ps,
&pgpath->path,
nr_bytes);
- r = DM_MAPIO_REMAPPED;
+ return DM_MAPIO_REMAPPED;
out_unlock:
- spin_unlock_irqrestore(&m->lock, flags);
+ spin_unlock_irq(&m->lock);
return r;
}
+static int multipath_map(struct dm_target *ti, struct request *clone,
+ union map_info *map_context)
+{
+ return __multipath_map(ti, clone, map_context, NULL, NULL);
+}
+
+static int multipath_clone_and_map(struct dm_target *ti, struct request *rq,
+ union map_info *map_context,
+ struct request **clone)
+{
+ return __multipath_map(ti, NULL, map_context, rq, clone);
+}
+
+static void multipath_release_clone(struct request *clone)
+{
+ blk_put_request(clone);
+}
+
/*
* If we run out of usable paths, should we queue I/O or error it?
*/
@@ -1666,11 +1703,13 @@ out:
*---------------------------------------------------------------*/
static struct target_type multipath_target = {
.name = "multipath",
- .version = {1, 7, 0},
+ .version = {1, 8, 0},
.module = THIS_MODULE,
.ctr = multipath_ctr,
.dtr = multipath_dtr,
.map_rq = multipath_map,
+ .clone_and_map_rq = multipath_clone_and_map,
+ .release_clone_rq = multipath_release_clone,
.rq_end_io = multipath_end_io,
.presuspend = multipath_presuspend,
.postsuspend = multipath_postsuspend,
@@ -1694,16 +1733,15 @@ static int __init dm_multipath_init(void)
r = dm_register_target(&multipath_target);
if (r < 0) {
DMERR("register failed %d", r);
- kmem_cache_destroy(_mpio_cache);
- return -EINVAL;
+ r = -EINVAL;
+ goto bad_register_target;
}
kmultipathd = alloc_workqueue("kmpathd", WQ_MEM_RECLAIM, 0);
if (!kmultipathd) {
DMERR("failed to create workqueue kmpathd");
- dm_unregister_target(&multipath_target);
- kmem_cache_destroy(_mpio_cache);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto bad_alloc_kmultipathd;
}
/*
@@ -1716,16 +1754,23 @@ static int __init dm_multipath_init(void)
WQ_MEM_RECLAIM);
if (!kmpath_handlerd) {
DMERR("failed to create workqueue kmpath_handlerd");
- destroy_workqueue(kmultipathd);
- dm_unregister_target(&multipath_target);
- kmem_cache_destroy(_mpio_cache);
- return -ENOMEM;
+ r = -ENOMEM;
+ goto bad_alloc_kmpath_handlerd;
}
DMINFO("version %u.%u.%u loaded",
multipath_target.version[0], multipath_target.version[1],
multipath_target.version[2]);
+ return 0;
+
+bad_alloc_kmpath_handlerd:
+ destroy_workqueue(kmultipathd);
+bad_alloc_kmultipathd:
+ dm_unregister_target(&multipath_target);
+bad_register_target:
+ kmem_cache_destroy(_mpio_cache);
+
return r;
}
diff --git a/drivers/md/dm-raid.c b/drivers/md/dm-raid.c
index 07c0fa0fa284..88e4c7f24986 100644
--- a/drivers/md/dm-raid.c
+++ b/drivers/md/dm-raid.c
@@ -746,13 +746,7 @@ static int raid_is_congested(struct dm_target_callbacks *cb, int bits)
{
struct raid_set *rs = container_of(cb, struct raid_set, callbacks);
- if (rs->raid_type->level == 1)
- return md_raid1_congested(&rs->md, bits);
-
- if (rs->raid_type->level == 10)
- return md_raid10_congested(&rs->md, bits);
-
- return md_raid5_congested(&rs->md, bits);
+ return mddev_congested(&rs->md, bits);
}
/*
@@ -1243,7 +1237,7 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
argv++;
/* Skip over RAID params for now and find out # of devices */
- if (num_raid_params + 1 > argc) {
+ if (num_raid_params >= argc) {
ti->error = "Arguments do not agree with counts given";
return -EINVAL;
}
@@ -1254,6 +1248,12 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
return -EINVAL;
}
+ argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */
+ if (argc != (num_raid_devs * 2)) {
+ ti->error = "Supplied RAID devices does not match the count given";
+ return -EINVAL;
+ }
+
rs = context_alloc(ti, rt, (unsigned)num_raid_devs);
if (IS_ERR(rs))
return PTR_ERR(rs);
@@ -1262,16 +1262,8 @@ static int raid_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (ret)
goto bad;
- ret = -EINVAL;
-
- argc -= num_raid_params + 1; /* +1: we already have num_raid_devs */
argv += num_raid_params + 1;
- if (argc != (num_raid_devs * 2)) {
- ti->error = "Supplied RAID devices does not match the count given";
- goto bad;
- }
-
ret = dev_parms(rs, argv);
if (ret)
goto bad;
diff --git a/drivers/md/dm-raid1.c b/drivers/md/dm-raid1.c
index 7dfdb5c746d6..089d62751f7f 100644
--- a/drivers/md/dm-raid1.c
+++ b/drivers/md/dm-raid1.c
@@ -604,6 +604,15 @@ static void write_callback(unsigned long error, void *context)
return;
}
+ /*
+ * If the bio is discard, return an error, but do not
+ * degrade the array.
+ */
+ if (bio->bi_rw & REQ_DISCARD) {
+ bio_endio(bio, -EOPNOTSUPP);
+ return;
+ }
+
for (i = 0; i < ms->nr_mirrors; i++)
if (test_bit(i, &error))
fail_mirror(ms->mirror + i, DM_RAID1_WRITE_ERROR);
diff --git a/drivers/md/dm-snap-persistent.c b/drivers/md/dm-snap-persistent.c
index d6e88178d22c..808b8419bc48 100644
--- a/drivers/md/dm-snap-persistent.c
+++ b/drivers/md/dm-snap-persistent.c
@@ -200,16 +200,11 @@ err_area:
static void free_area(struct pstore *ps)
{
- if (ps->area)
- vfree(ps->area);
+ vfree(ps->area);
ps->area = NULL;
-
- if (ps->zero_area)
- vfree(ps->zero_area);
+ vfree(ps->zero_area);
ps->zero_area = NULL;
-
- if (ps->header_area)
- vfree(ps->header_area);
+ vfree(ps->header_area);
ps->header_area = NULL;
}
@@ -605,8 +600,7 @@ static void persistent_dtr(struct dm_exception_store *store)
free_area(ps);
/* Allocated in persistent_read_metadata */
- if (ps->callbacks)
- vfree(ps->callbacks);
+ vfree(ps->callbacks);
kfree(ps);
}
diff --git a/drivers/md/dm-snap.c b/drivers/md/dm-snap.c
index 864b03f47727..8b204ae216ab 100644
--- a/drivers/md/dm-snap.c
+++ b/drivers/md/dm-snap.c
@@ -1432,8 +1432,6 @@ out:
full_bio->bi_private = pe->full_bio_private;
atomic_inc(&full_bio->bi_remaining);
}
- free_pending_exception(pe);
-
increment_pending_exceptions_done_count();
up_write(&s->lock);
@@ -1450,6 +1448,8 @@ out:
}
retry_origin_bios(s, origin_bios);
+
+ free_pending_exception(pe);
}
static void commit_callback(void *context, int success)
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index 3afae9e062f8..6554d9148927 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -827,10 +827,11 @@ static int dm_table_set_type(struct dm_table *t)
{
unsigned i;
unsigned bio_based = 0, request_based = 0, hybrid = 0;
+ bool use_blk_mq = false;
struct dm_target *tgt;
struct dm_dev_internal *dd;
struct list_head *devices;
- unsigned live_md_type;
+ unsigned live_md_type = dm_get_md_type(t->md);
for (i = 0; i < t->num_targets; i++) {
tgt = t->targets + i;
@@ -854,8 +855,8 @@ static int dm_table_set_type(struct dm_table *t)
* Determine the type from the live device.
* Default to bio-based if device is new.
*/
- live_md_type = dm_get_md_type(t->md);
- if (live_md_type == DM_TYPE_REQUEST_BASED)
+ if (live_md_type == DM_TYPE_REQUEST_BASED ||
+ live_md_type == DM_TYPE_MQ_REQUEST_BASED)
request_based = 1;
else
bio_based = 1;
@@ -869,16 +870,6 @@ static int dm_table_set_type(struct dm_table *t)
BUG_ON(!request_based); /* No targets in this table */
- /* Non-request-stackable devices can't be used for request-based dm */
- devices = dm_table_get_devices(t);
- list_for_each_entry(dd, devices, list) {
- if (!blk_queue_stackable(bdev_get_queue(dd->dm_dev->bdev))) {
- DMWARN("table load rejected: including"
- " non-request-stackable devices");
- return -EINVAL;
- }
- }
-
/*
* Request-based dm supports only tables that have a single target now.
* To support multiple targets, request splitting support is needed,
@@ -890,7 +881,37 @@ static int dm_table_set_type(struct dm_table *t)
return -EINVAL;
}
- t->type = DM_TYPE_REQUEST_BASED;
+ /* Non-request-stackable devices can't be used for request-based dm */
+ devices = dm_table_get_devices(t);
+ list_for_each_entry(dd, devices, list) {
+ struct request_queue *q = bdev_get_queue(dd->dm_dev->bdev);
+
+ if (!blk_queue_stackable(q)) {
+ DMERR("table load rejected: including"
+ " non-request-stackable devices");
+ return -EINVAL;
+ }
+
+ if (q->mq_ops)
+ use_blk_mq = true;
+ }
+
+ if (use_blk_mq) {
+ /* verify _all_ devices in the table are blk-mq devices */
+ list_for_each_entry(dd, devices, list)
+ if (!bdev_get_queue(dd->dm_dev->bdev)->mq_ops) {
+ DMERR("table load rejected: not all devices"
+ " are blk-mq request-stackable");
+ return -EINVAL;
+ }
+ t->type = DM_TYPE_MQ_REQUEST_BASED;
+
+ } else if (hybrid && list_empty(devices) && live_md_type != DM_TYPE_NONE) {
+ /* inherit live MD type */
+ t->type = live_md_type;
+
+ } else
+ t->type = DM_TYPE_REQUEST_BASED;
return 0;
}
@@ -907,7 +928,15 @@ struct target_type *dm_table_get_immutable_target_type(struct dm_table *t)
bool dm_table_request_based(struct dm_table *t)
{
- return dm_table_get_type(t) == DM_TYPE_REQUEST_BASED;
+ unsigned table_type = dm_table_get_type(t);
+
+ return (table_type == DM_TYPE_REQUEST_BASED ||
+ table_type == DM_TYPE_MQ_REQUEST_BASED);
+}
+
+bool dm_table_mq_request_based(struct dm_table *t)
+{
+ return dm_table_get_type(t) == DM_TYPE_MQ_REQUEST_BASED;
}
static int dm_table_alloc_md_mempools(struct dm_table *t)
@@ -1360,6 +1389,14 @@ static int queue_supports_sg_merge(struct dm_target *ti, struct dm_dev *dev,
return q && !test_bit(QUEUE_FLAG_NO_SG_MERGE, &q->queue_flags);
}
+static int queue_supports_sg_gaps(struct dm_target *ti, struct dm_dev *dev,
+ sector_t start, sector_t len, void *data)
+{
+ struct request_queue *q = bdev_get_queue(dev->bdev);
+
+ return q && !test_bit(QUEUE_FLAG_SG_GAPS, &q->queue_flags);
+}
+
static bool dm_table_all_devices_attribute(struct dm_table *t,
iterate_devices_callout_fn func)
{
@@ -1480,6 +1517,11 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
else
queue_flag_set_unlocked(QUEUE_FLAG_NO_SG_MERGE, q);
+ if (dm_table_all_devices_attribute(t, queue_supports_sg_gaps))
+ queue_flag_clear_unlocked(QUEUE_FLAG_SG_GAPS, q);
+ else
+ queue_flag_set_unlocked(QUEUE_FLAG_SG_GAPS, q);
+
dm_table_set_integrity(t);
/*
diff --git a/drivers/md/dm-target.c b/drivers/md/dm-target.c
index 242e3cec397a..925ec1b15e75 100644
--- a/drivers/md/dm-target.c
+++ b/drivers/md/dm-target.c
@@ -137,13 +137,26 @@ static int io_err_map_rq(struct dm_target *ti, struct request *clone,
return -EIO;
}
+static int io_err_clone_and_map_rq(struct dm_target *ti, struct request *rq,
+ union map_info *map_context,
+ struct request **clone)
+{
+ return -EIO;
+}
+
+static void io_err_release_clone_rq(struct request *clone)
+{
+}
+
static struct target_type error_target = {
.name = "error",
- .version = {1, 2, 0},
+ .version = {1, 3, 0},
.ctr = io_err_ctr,
.dtr = io_err_dtr,
.map = io_err_map,
.map_rq = io_err_map_rq,
+ .clone_and_map_rq = io_err_clone_and_map_rq,
+ .release_clone_rq = io_err_release_clone_rq,
};
int __init dm_target_init(void)
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index 43adbb863f5a..79f694120ddf 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1635,15 +1635,6 @@ int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd,
return r;
}
-int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result)
-{
- down_read(&pmd->root_lock);
- *result = pmd->data_block_size;
- up_read(&pmd->root_lock);
-
- return 0;
-}
-
int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result)
{
int r = -EINVAL;
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index 921d15ee56a0..fac01a96d303 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -182,8 +182,6 @@ int dm_pool_get_free_metadata_block_count(struct dm_pool_metadata *pmd,
int dm_pool_get_metadata_dev_size(struct dm_pool_metadata *pmd,
dm_block_t *result);
-int dm_pool_get_data_block_size(struct dm_pool_metadata *pmd, sector_t *result);
-
int dm_pool_get_data_dev_size(struct dm_pool_metadata *pmd, dm_block_t *result);
int dm_pool_block_is_used(struct dm_pool_metadata *pmd, dm_block_t b, bool *result);
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 493478989dbd..654773cb1eee 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -11,6 +11,7 @@
#include <linux/device-mapper.h>
#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>
+#include <linux/jiffies.h>
#include <linux/log2.h>
#include <linux/list.h>
#include <linux/rculist.h>
@@ -1700,8 +1701,8 @@ static void process_cell_fail(struct thin_c *tc, struct dm_bio_prison_cell *cell
*/
static int need_commit_due_to_time(struct pool *pool)
{
- return jiffies < pool->last_commit_jiffies ||
- jiffies > pool->last_commit_jiffies + COMMIT_PERIOD;
+ return !time_in_range(jiffies, pool->last_commit_jiffies,
+ pool->last_commit_jiffies + COMMIT_PERIOD);
}
#define thin_pbd(node) rb_entry((node), struct dm_thin_endio_hook, rb_node)
@@ -3385,6 +3386,12 @@ static int pool_message(struct dm_target *ti, unsigned argc, char **argv)
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
+ if (get_pool_mode(pool) >= PM_READ_ONLY) {
+ DMERR("%s: unable to service pool target messages in READ_ONLY or FAIL mode",
+ dm_device_name(pool->pool_md));
+ return -EINVAL;
+ }
+
if (!strcasecmp(argv[0], "create_thin"))
r = process_create_thin_mesg(argc, argv, pool);
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 2caf5b374649..73f28802dc7a 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -20,6 +20,7 @@
#include <linux/hdreg.h>
#include <linux/delay.h>
#include <linux/wait.h>
+#include <linux/kthread.h>
#include <trace/events/block.h>
@@ -78,7 +79,8 @@ struct dm_io {
struct dm_rq_target_io {
struct mapped_device *md;
struct dm_target *ti;
- struct request *orig, clone;
+ struct request *orig, *clone;
+ struct kthread_work work;
int error;
union map_info info;
};
@@ -179,6 +181,7 @@ struct mapped_device {
* io objects are allocated from here.
*/
mempool_t *io_pool;
+ mempool_t *rq_pool;
struct bio_set *bs;
@@ -210,6 +213,9 @@ struct mapped_device {
unsigned internal_suspend_count;
struct dm_stats stats;
+
+ struct kthread_worker kworker;
+ struct task_struct *kworker_task;
};
/*
@@ -217,6 +223,7 @@ struct mapped_device {
*/
struct dm_md_mempools {
mempool_t *io_pool;
+ mempool_t *rq_pool;
struct bio_set *bs;
};
@@ -231,6 +238,7 @@ struct table_device {
#define RESERVED_MAX_IOS 1024
static struct kmem_cache *_io_cache;
static struct kmem_cache *_rq_tio_cache;
+static struct kmem_cache *_rq_cache;
/*
* Bio-based DM's mempools' reserved IOs set by the user.
@@ -288,9 +296,14 @@ static int __init local_init(void)
if (!_rq_tio_cache)
goto out_free_io_cache;
+ _rq_cache = kmem_cache_create("dm_clone_request", sizeof(struct request),
+ __alignof__(struct request), 0, NULL);
+ if (!_rq_cache)
+ goto out_free_rq_tio_cache;
+
r = dm_uevent_init();
if (r)
- goto out_free_rq_tio_cache;
+ goto out_free_rq_cache;
deferred_remove_workqueue = alloc_workqueue("kdmremove", WQ_UNBOUND, 1);
if (!deferred_remove_workqueue) {
@@ -312,6 +325,8 @@ out_free_workqueue:
destroy_workqueue(deferred_remove_workqueue);
out_uevent_exit:
dm_uevent_exit();
+out_free_rq_cache:
+ kmem_cache_destroy(_rq_cache);
out_free_rq_tio_cache:
kmem_cache_destroy(_rq_tio_cache);
out_free_io_cache:
@@ -325,6 +340,7 @@ static void local_exit(void)
flush_scheduled_work();
destroy_workqueue(deferred_remove_workqueue);
+ kmem_cache_destroy(_rq_cache);
kmem_cache_destroy(_rq_tio_cache);
kmem_cache_destroy(_io_cache);
unregister_blkdev(_major, _name);
@@ -577,6 +593,17 @@ static void free_rq_tio(struct dm_rq_target_io *tio)
mempool_free(tio, tio->md->io_pool);
}
+static struct request *alloc_clone_request(struct mapped_device *md,
+ gfp_t gfp_mask)
+{
+ return mempool_alloc(md->rq_pool, gfp_mask);
+}
+
+static void free_clone_request(struct mapped_device *md, struct request *rq)
+{
+ mempool_free(rq, md->rq_pool);
+}
+
static int md_in_flight(struct mapped_device *md)
{
return atomic_read(&md->pending[READ]) +
@@ -992,7 +1019,7 @@ static void end_clone_bio(struct bio *clone, int error)
* the md may be freed in dm_put() at the end of this function.
* Or do dm_get() before calling this function and dm_put() later.
*/
-static void rq_completed(struct mapped_device *md, int rw, int run_queue)
+static void rq_completed(struct mapped_device *md, int rw, bool run_queue)
{
atomic_dec(&md->pending[rw]);
@@ -1020,12 +1047,17 @@ static void free_rq_clone(struct request *clone)
struct dm_rq_target_io *tio = clone->end_io_data;
blk_rq_unprep_clone(clone);
+ if (clone->q && clone->q->mq_ops)
+ tio->ti->type->release_clone_rq(clone);
+ else
+ free_clone_request(tio->md, clone);
free_rq_tio(tio);
}
/*
* Complete the clone and the original request.
- * Must be called without queue lock.
+ * Must be called without clone's queue lock held,
+ * see end_clone_request() for more details.
*/
static void dm_end_request(struct request *clone, int error)
{
@@ -1054,23 +1086,23 @@ static void dm_end_request(struct request *clone, int error)
static void dm_unprep_request(struct request *rq)
{
- struct request *clone = rq->special;
+ struct dm_rq_target_io *tio = rq->special;
+ struct request *clone = tio->clone;
rq->special = NULL;
rq->cmd_flags &= ~REQ_DONTPREP;
- free_rq_clone(clone);
+ if (clone)
+ free_rq_clone(clone);
}
/*
* Requeue the original request of a clone.
*/
-void dm_requeue_unmapped_request(struct request *clone)
+static void dm_requeue_unmapped_original_request(struct mapped_device *md,
+ struct request *rq)
{
- int rw = rq_data_dir(clone);
- struct dm_rq_target_io *tio = clone->end_io_data;
- struct mapped_device *md = tio->md;
- struct request *rq = tio->orig;
+ int rw = rq_data_dir(rq);
struct request_queue *q = rq->q;
unsigned long flags;
@@ -1080,9 +1112,15 @@ void dm_requeue_unmapped_request(struct request *clone)
blk_requeue_request(q, rq);
spin_unlock_irqrestore(q->queue_lock, flags);
- rq_completed(md, rw, 0);
+ rq_completed(md, rw, false);
+}
+
+static void dm_requeue_unmapped_request(struct request *clone)
+{
+ struct dm_rq_target_io *tio = clone->end_io_data;
+
+ dm_requeue_unmapped_original_request(tio->md, tio->orig);
}
-EXPORT_SYMBOL_GPL(dm_requeue_unmapped_request);
static void __stop_queue(struct request_queue *q)
{
@@ -1151,8 +1189,15 @@ static void dm_done(struct request *clone, int error, bool mapped)
static void dm_softirq_done(struct request *rq)
{
bool mapped = true;
- struct request *clone = rq->completion_data;
- struct dm_rq_target_io *tio = clone->end_io_data;
+ struct dm_rq_target_io *tio = rq->special;
+ struct request *clone = tio->clone;
+
+ if (!clone) {
+ blk_end_request_all(rq, tio->error);
+ rq_completed(tio->md, rq_data_dir(rq), false);
+ free_rq_tio(tio);
+ return;
+ }
if (rq->cmd_flags & REQ_FAILED)
mapped = false;
@@ -1164,13 +1209,11 @@ static void dm_softirq_done(struct request *rq)
* Complete the clone and the original request with the error status
* through softirq context.
*/
-static void dm_complete_request(struct request *clone, int error)
+static void dm_complete_request(struct request *rq, int error)
{
- struct dm_rq_target_io *tio = clone->end_io_data;
- struct request *rq = tio->orig;
+ struct dm_rq_target_io *tio = rq->special;
tio->error = error;
- rq->completion_data = clone;
blk_complete_request(rq);
}
@@ -1178,40 +1221,40 @@ static void dm_complete_request(struct request *clone, int error)
* Complete the not-mapped clone and the original request with the error status
* through softirq context.
* Target's rq_end_io() function isn't called.
- * This may be used when the target's map_rq() function fails.
+ * This may be used when the target's map_rq() or clone_and_map_rq() functions fail.
*/
-void dm_kill_unmapped_request(struct request *clone, int error)
+static void dm_kill_unmapped_request(struct request *rq, int error)
{
- struct dm_rq_target_io *tio = clone->end_io_data;
- struct request *rq = tio->orig;
-
rq->cmd_flags |= REQ_FAILED;
- dm_complete_request(clone, error);
+ dm_complete_request(rq, error);
}
-EXPORT_SYMBOL_GPL(dm_kill_unmapped_request);
/*
- * Called with the queue lock held
+ * Called with the clone's queue lock held
*/
static void end_clone_request(struct request *clone, int error)
{
- /*
- * For just cleaning up the information of the queue in which
- * the clone was dispatched.
- * The clone is *NOT* freed actually here because it is alloced from
- * dm own mempool and REQ_ALLOCED isn't set in clone->cmd_flags.
- */
- __blk_put_request(clone->q, clone);
+ struct dm_rq_target_io *tio = clone->end_io_data;
+
+ if (!clone->q->mq_ops) {
+ /*
+ * For just cleaning up the information of the queue in which
+ * the clone was dispatched.
+ * The clone is *NOT* freed actually here because it is alloced
+ * from dm own mempool (REQ_ALLOCED isn't set).
+ */
+ __blk_put_request(clone->q, clone);
+ }
/*
* Actual request completion is done in a softirq context which doesn't
- * hold the queue lock. Otherwise, deadlock could occur because:
+ * hold the clone's queue lock. Otherwise, deadlock could occur because:
* - another request may be submitted by the upper level driver
* of the stacking during the completion
* - the submission which requires queue lock may be done
- * against this queue
+ * against this clone's queue
*/
- dm_complete_request(clone, error);
+ dm_complete_request(tio->orig, error);
}
/*
@@ -1689,19 +1732,19 @@ static void dm_request(struct request_queue *q, struct bio *bio)
_dm_request(q, bio);
}
-void dm_dispatch_request(struct request *rq)
+static void dm_dispatch_clone_request(struct request *clone, struct request *rq)
{
int r;
- if (blk_queue_io_stat(rq->q))
- rq->cmd_flags |= REQ_IO_STAT;
+ if (blk_queue_io_stat(clone->q))
+ clone->cmd_flags |= REQ_IO_STAT;
- rq->start_time = jiffies;
- r = blk_insert_cloned_request(rq->q, rq);
+ clone->start_time = jiffies;
+ r = blk_insert_cloned_request(clone->q, clone);
if (r)
+ /* must complete clone in terms of original request */
dm_complete_request(rq, r);
}
-EXPORT_SYMBOL_GPL(dm_dispatch_request);
static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig,
void *data)
@@ -1718,11 +1761,11 @@ static int dm_rq_bio_constructor(struct bio *bio, struct bio *bio_orig,
}
static int setup_clone(struct request *clone, struct request *rq,
- struct dm_rq_target_io *tio)
+ struct dm_rq_target_io *tio, gfp_t gfp_mask)
{
int r;
- r = blk_rq_prep_clone(clone, rq, tio->md->bs, GFP_ATOMIC,
+ r = blk_rq_prep_clone(clone, rq, tio->md->bs, gfp_mask,
dm_rq_bio_constructor, tio);
if (r)
return r;
@@ -1733,14 +1776,37 @@ static int setup_clone(struct request *clone, struct request *rq,
clone->end_io = end_clone_request;
clone->end_io_data = tio;
+ tio->clone = clone;
+
return 0;
}
static struct request *clone_rq(struct request *rq, struct mapped_device *md,
- gfp_t gfp_mask)
+ struct dm_rq_target_io *tio, gfp_t gfp_mask)
+{
+ struct request *clone = alloc_clone_request(md, gfp_mask);
+
+ if (!clone)
+ return NULL;
+
+ blk_rq_init(NULL, clone);
+ if (setup_clone(clone, rq, tio, gfp_mask)) {
+ /* -ENOMEM */
+ free_clone_request(md, clone);
+ return NULL;
+ }
+
+ return clone;
+}
+
+static void map_tio_request(struct kthread_work *work);
+
+static struct dm_rq_target_io *prep_tio(struct request *rq,
+ struct mapped_device *md, gfp_t gfp_mask)
{
- struct request *clone;
struct dm_rq_target_io *tio;
+ int srcu_idx;
+ struct dm_table *table;
tio = alloc_rq_tio(md, gfp_mask);
if (!tio)
@@ -1748,18 +1814,23 @@ static struct request *clone_rq(struct request *rq, struct mapped_device *md,
tio->md = md;
tio->ti = NULL;
+ tio->clone = NULL;
tio->orig = rq;
tio->error = 0;
memset(&tio->info, 0, sizeof(tio->info));
-
- clone = &tio->clone;
- if (setup_clone(clone, rq, tio)) {
- /* -ENOMEM */
- free_rq_tio(tio);
- return NULL;
+ init_kthread_work(&tio->work, map_tio_request);
+
+ table = dm_get_live_table(md, &srcu_idx);
+ if (!dm_table_mq_request_based(table)) {
+ if (!clone_rq(rq, md, tio, gfp_mask)) {
+ dm_put_live_table(md, srcu_idx);
+ free_rq_tio(tio);
+ return NULL;
+ }
}
+ dm_put_live_table(md, srcu_idx);
- return clone;
+ return tio;
}
/*
@@ -1768,18 +1839,18 @@ static struct request *clone_rq(struct request *rq, struct mapped_device *md,
static int dm_prep_fn(struct request_queue *q, struct request *rq)
{
struct mapped_device *md = q->queuedata;
- struct request *clone;
+ struct dm_rq_target_io *tio;
if (unlikely(rq->special)) {
DMWARN("Already has something in rq->special.");
return BLKPREP_KILL;
}
- clone = clone_rq(rq, md, GFP_ATOMIC);
- if (!clone)
+ tio = prep_tio(rq, md, GFP_ATOMIC);
+ if (!tio)
return BLKPREP_DEFER;
- rq->special = clone;
+ rq->special = tio;
rq->cmd_flags |= REQ_DONTPREP;
return BLKPREP_OK;
@@ -1787,17 +1858,36 @@ static int dm_prep_fn(struct request_queue *q, struct request *rq)
/*
* Returns:
- * 0 : the request has been processed (not requeued)
- * !0 : the request has been requeued
+ * 0 : the request has been processed
+ * DM_MAPIO_REQUEUE : the original request needs to be requeued
+ * < 0 : the request was completed due to failure
*/
-static int map_request(struct dm_target *ti, struct request *clone,
+static int map_request(struct dm_target *ti, struct request *rq,
struct mapped_device *md)
{
- int r, requeued = 0;
- struct dm_rq_target_io *tio = clone->end_io_data;
+ int r;
+ struct dm_rq_target_io *tio = rq->special;
+ struct request *clone = NULL;
+
+ if (tio->clone) {
+ clone = tio->clone;
+ r = ti->type->map_rq(ti, clone, &tio->info);
+ } else {
+ r = ti->type->clone_and_map_rq(ti, rq, &tio->info, &clone);
+ if (r < 0) {
+ /* The target wants to complete the I/O */
+ dm_kill_unmapped_request(rq, r);
+ return r;
+ }
+ if (IS_ERR(clone))
+ return DM_MAPIO_REQUEUE;
+ if (setup_clone(clone, rq, tio, GFP_KERNEL)) {
+ /* -ENOMEM */
+ ti->type->release_clone_rq(clone);
+ return DM_MAPIO_REQUEUE;
+ }
+ }
- tio->ti = ti;
- r = ti->type->map_rq(ti, clone, &tio->info);
switch (r) {
case DM_MAPIO_SUBMITTED:
/* The target has taken the I/O to submit by itself later */
@@ -1805,13 +1895,12 @@ static int map_request(struct dm_target *ti, struct request *clone,
case DM_MAPIO_REMAPPED:
/* The target has remapped the I/O so dispatch it */
trace_block_rq_remap(clone->q, clone, disk_devt(dm_disk(md)),
- blk_rq_pos(tio->orig));
- dm_dispatch_request(clone);
+ blk_rq_pos(rq));
+ dm_dispatch_clone_request(clone, rq);
break;
case DM_MAPIO_REQUEUE:
/* The target wants to requeue the I/O */
dm_requeue_unmapped_request(clone);
- requeued = 1;
break;
default:
if (r > 0) {
@@ -1820,20 +1909,27 @@ static int map_request(struct dm_target *ti, struct request *clone,
}
/* The target wants to complete the I/O */
- dm_kill_unmapped_request(clone, r);
- break;
+ dm_kill_unmapped_request(rq, r);
+ return r;
}
- return requeued;
+ return 0;
}
-static struct request *dm_start_request(struct mapped_device *md, struct request *orig)
+static void map_tio_request(struct kthread_work *work)
{
- struct request *clone;
+ struct dm_rq_target_io *tio = container_of(work, struct dm_rq_target_io, work);
+ struct request *rq = tio->orig;
+ struct mapped_device *md = tio->md;
+
+ if (map_request(tio->ti, rq, md) == DM_MAPIO_REQUEUE)
+ dm_requeue_unmapped_original_request(md, rq);
+}
+static void dm_start_request(struct mapped_device *md, struct request *orig)
+{
blk_start_request(orig);
- clone = orig->special;
- atomic_inc(&md->pending[rq_data_dir(clone)]);
+ atomic_inc(&md->pending[rq_data_dir(orig)]);
/*
* Hold the md reference here for the in-flight I/O.
@@ -1843,8 +1939,6 @@ static struct request *dm_start_request(struct mapped_device *md, struct request
* See the comment in rq_completed() too.
*/
dm_get(md);
-
- return clone;
}
/*
@@ -1857,7 +1951,8 @@ static void dm_request_fn(struct request_queue *q)
int srcu_idx;
struct dm_table *map = dm_get_live_table(md, &srcu_idx);
struct dm_target *ti;
- struct request *rq, *clone;
+ struct request *rq;
+ struct dm_rq_target_io *tio;
sector_t pos;
/*
@@ -1879,34 +1974,29 @@ static void dm_request_fn(struct request_queue *q)
ti = dm_table_find_target(map, pos);
if (!dm_target_is_valid(ti)) {
/*
- * Must perform setup, that dm_done() requires,
+ * Must perform setup, that rq_completed() requires,
* before calling dm_kill_unmapped_request
*/
DMERR_LIMIT("request attempted access beyond the end of device");
- clone = dm_start_request(md, rq);
- dm_kill_unmapped_request(clone, -EIO);
+ dm_start_request(md, rq);
+ dm_kill_unmapped_request(rq, -EIO);
continue;
}
if (ti->type->busy && ti->type->busy(ti))
goto delay_and_out;
- clone = dm_start_request(md, rq);
-
- spin_unlock(q->queue_lock);
- if (map_request(ti, clone, md))
- goto requeued;
+ dm_start_request(md, rq);
+ tio = rq->special;
+ /* Establish tio->ti before queuing work (map_tio_request) */
+ tio->ti = ti;
+ queue_kthread_work(&md->kworker, &tio->work);
BUG_ON(!irqs_disabled());
- spin_lock(q->queue_lock);
}
goto out;
-requeued:
- BUG_ON(!irqs_disabled());
- spin_lock(q->queue_lock);
-
delay_and_out:
blk_delay_queue(q, HZ / 10);
out:
@@ -2092,6 +2182,7 @@ static struct mapped_device *alloc_dev(int minor)
INIT_WORK(&md->work, dm_wq_work);
init_waitqueue_head(&md->eventq);
init_completion(&md->kobj_holder.completion);
+ md->kworker_task = NULL;
md->disk->major = _major;
md->disk->first_minor = minor;
@@ -2152,8 +2243,13 @@ static void free_dev(struct mapped_device *md)
unlock_fs(md);
bdput(md->bdev);
destroy_workqueue(md->wq);
+
+ if (md->kworker_task)
+ kthread_stop(md->kworker_task);
if (md->io_pool)
mempool_destroy(md->io_pool);
+ if (md->rq_pool)
+ mempool_destroy(md->rq_pool);
if (md->bs)
bioset_free(md->bs);
blk_integrity_unregister(md->disk);
@@ -2187,23 +2283,24 @@ static void __bind_mempools(struct mapped_device *md, struct dm_table *t)
bioset_free(md->bs);
md->bs = p->bs;
p->bs = NULL;
- } else if (dm_table_get_type(t) == DM_TYPE_REQUEST_BASED) {
- /*
- * There's no need to reload with request-based dm
- * because the size of front_pad doesn't change.
- * Note for future: If you are to reload bioset,
- * prep-ed requests in the queue may refer
- * to bio from the old bioset, so you must walk
- * through the queue to unprep.
- */
}
+ /*
+ * There's no need to reload with request-based dm
+ * because the size of front_pad doesn't change.
+ * Note for future: If you are to reload bioset,
+ * prep-ed requests in the queue may refer
+ * to bio from the old bioset, so you must walk
+ * through the queue to unprep.
+ */
goto out;
}
- BUG_ON(!p || md->io_pool || md->bs);
+ BUG_ON(!p || md->io_pool || md->rq_pool || md->bs);
md->io_pool = p->io_pool;
p->io_pool = NULL;
+ md->rq_pool = p->rq_pool;
+ p->rq_pool = NULL;
md->bs = p->bs;
p->bs = NULL;
@@ -2406,6 +2503,14 @@ unsigned dm_get_md_type(struct mapped_device *md)
return md->type;
}
+static bool dm_md_type_request_based(struct mapped_device *md)
+{
+ unsigned table_type = dm_get_md_type(md);
+
+ return (table_type == DM_TYPE_REQUEST_BASED ||
+ table_type == DM_TYPE_MQ_REQUEST_BASED);
+}
+
struct target_type *dm_get_immutable_target_type(struct mapped_device *md)
{
return md->immutable_target_type;
@@ -2443,6 +2548,11 @@ static int dm_init_request_based_queue(struct mapped_device *md)
blk_queue_prep_rq(md->queue, dm_prep_fn);
blk_queue_lld_busy(md->queue, dm_lld_busy);
+ /* Also initialize the request-based DM worker thread */
+ init_kthread_worker(&md->kworker);
+ md->kworker_task = kthread_run(kthread_worker_fn, &md->kworker,
+ "kdmwork-%s", dm_device_name(md));
+
elv_register_queue(md->queue);
return 1;
@@ -2453,8 +2563,7 @@ static int dm_init_request_based_queue(struct mapped_device *md)
*/
int dm_setup_md_queue(struct mapped_device *md)
{
- if ((dm_get_md_type(md) == DM_TYPE_REQUEST_BASED) &&
- !dm_init_request_based_queue(md)) {
+ if (dm_md_type_request_based(md) && !dm_init_request_based_queue(md)) {
DMWARN("Cannot initialize queue for request-based mapped device");
return -EINVAL;
}
@@ -2462,7 +2571,7 @@ int dm_setup_md_queue(struct mapped_device *md)
return 0;
}
-static struct mapped_device *dm_find_md(dev_t dev)
+struct mapped_device *dm_get_md(dev_t dev)
{
struct mapped_device *md;
unsigned minor = MINOR(dev);
@@ -2473,12 +2582,15 @@ static struct mapped_device *dm_find_md(dev_t dev)
spin_lock(&_minor_lock);
md = idr_find(&_minor_idr, minor);
- if (md && (md == MINOR_ALLOCED ||
- (MINOR(disk_devt(dm_disk(md))) != minor) ||
- dm_deleting_md(md) ||
- test_bit(DMF_FREEING, &md->flags))) {
- md = NULL;
- goto out;
+ if (md) {
+ if ((md == MINOR_ALLOCED ||
+ (MINOR(disk_devt(dm_disk(md))) != minor) ||
+ dm_deleting_md(md) ||
+ test_bit(DMF_FREEING, &md->flags))) {
+ md = NULL;
+ goto out;
+ }
+ dm_get(md);
}
out:
@@ -2486,16 +2598,6 @@ out:
return md;
}
-
-struct mapped_device *dm_get_md(dev_t dev)
-{
- struct mapped_device *md = dm_find_md(dev);
-
- if (md)
- dm_get(md);
-
- return md;
-}
EXPORT_SYMBOL_GPL(dm_get_md);
void *dm_get_mdptr(struct mapped_device *md)
@@ -2533,6 +2635,9 @@ static void __dm_destroy(struct mapped_device *md, bool wait)
set_bit(DMF_FREEING, &md->flags);
spin_unlock(&_minor_lock);
+ if (dm_request_based(md))
+ flush_kthread_worker(&md->kworker);
+
if (!dm_suspended_md(md)) {
dm_table_presuspend_targets(map);
dm_table_postsuspend_targets(map);
@@ -2776,8 +2881,10 @@ static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
* Stop md->queue before flushing md->wq in case request-based
* dm defers requests to md->wq from md->queue.
*/
- if (dm_request_based(md))
+ if (dm_request_based(md)) {
stop_queue(md->queue);
+ flush_kthread_worker(&md->kworker);
+ }
flush_workqueue(md->wq);
@@ -3123,24 +3230,35 @@ struct dm_md_mempools *dm_alloc_md_mempools(unsigned type, unsigned integrity, u
{
struct dm_md_mempools *pools = kzalloc(sizeof(*pools), GFP_KERNEL);
struct kmem_cache *cachep;
- unsigned int pool_size;
+ unsigned int pool_size = 0;
unsigned int front_pad;
if (!pools)
return NULL;
- if (type == DM_TYPE_BIO_BASED) {
+ switch (type) {
+ case DM_TYPE_BIO_BASED:
cachep = _io_cache;
pool_size = dm_get_reserved_bio_based_ios();
front_pad = roundup(per_bio_data_size, __alignof__(struct dm_target_io)) + offsetof(struct dm_target_io, clone);
- } else if (type == DM_TYPE_REQUEST_BASED) {
- cachep = _rq_tio_cache;
+ break;
+ case DM_TYPE_REQUEST_BASED:
pool_size = dm_get_reserved_rq_based_ios();
+ pools->rq_pool = mempool_create_slab_pool(pool_size, _rq_cache);
+ if (!pools->rq_pool)
+ goto out;
+ /* fall through to setup remaining rq-based pools */
+ case DM_TYPE_MQ_REQUEST_BASED:
+ cachep = _rq_tio_cache;
+ if (!pool_size)
+ pool_size = dm_get_reserved_rq_based_ios();
front_pad = offsetof(struct dm_rq_clone_bio_info, clone);
/* per_bio_data_size is not used. See __bind_mempools(). */
WARN_ON(per_bio_data_size != 0);
- } else
+ break;
+ default:
goto out;
+ }
pools->io_pool = mempool_create_slab_pool(pool_size, cachep);
if (!pools->io_pool)
@@ -3169,6 +3287,9 @@ void dm_free_md_mempools(struct dm_md_mempools *pools)
if (pools->io_pool)
mempool_destroy(pools->io_pool);
+ if (pools->rq_pool)
+ mempool_destroy(pools->rq_pool);
+
if (pools->bs)
bioset_free(pools->bs);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 84b0f9e4ba6c..59f53e79db82 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -34,9 +34,10 @@
/*
* Type of table and mapped_device's mempool
*/
-#define DM_TYPE_NONE 0
-#define DM_TYPE_BIO_BASED 1
-#define DM_TYPE_REQUEST_BASED 2
+#define DM_TYPE_NONE 0
+#define DM_TYPE_BIO_BASED 1
+#define DM_TYPE_REQUEST_BASED 2
+#define DM_TYPE_MQ_REQUEST_BASED 3
/*
* List of devices that a metadevice uses and should open/close.
@@ -73,6 +74,7 @@ int dm_table_any_busy_target(struct dm_table *t);
unsigned dm_table_get_type(struct dm_table *t);
struct target_type *dm_table_get_immutable_target_type(struct dm_table *t);
bool dm_table_request_based(struct dm_table *t);
+bool dm_table_mq_request_based(struct dm_table *t);
void dm_table_free_md_mempools(struct dm_table *t);
struct dm_md_mempools *dm_table_get_md_mempools(struct dm_table *t);
@@ -99,7 +101,8 @@ int dm_setup_md_queue(struct mapped_device *md);
/*
* To check whether the target type is request-based or not (bio-based).
*/
-#define dm_target_request_based(t) ((t)->type->map_rq != NULL)
+#define dm_target_request_based(t) (((t)->type->map_rq != NULL) || \
+ ((t)->type->clone_and_map_rq != NULL))
/*
* To check whether the target type is a hybrid (capable of being
diff --git a/drivers/md/faulty.c b/drivers/md/faulty.c
index e8b4574956c7..1277eb26b58a 100644
--- a/drivers/md/faulty.c
+++ b/drivers/md/faulty.c
@@ -332,13 +332,11 @@ static int run(struct mddev *mddev)
return 0;
}
-static int stop(struct mddev *mddev)
+static void faulty_free(struct mddev *mddev, void *priv)
{
- struct faulty_conf *conf = mddev->private;
+ struct faulty_conf *conf = priv;
kfree(conf);
- mddev->private = NULL;
- return 0;
}
static struct md_personality faulty_personality =
@@ -348,7 +346,7 @@ static struct md_personality faulty_personality =
.owner = THIS_MODULE,
.make_request = make_request,
.run = run,
- .stop = stop,
+ .free = faulty_free,
.status = status,
.check_reshape = reshape,
.size = faulty_size,
diff --git a/drivers/md/linear.c b/drivers/md/linear.c
index 64713b77df1c..fa7d577f3d12 100644
--- a/drivers/md/linear.c
+++ b/drivers/md/linear.c
@@ -34,7 +34,7 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector)
lo = 0;
hi = mddev->raid_disks - 1;
- conf = rcu_dereference(mddev->private);
+ conf = mddev->private;
/*
* Binary Search
@@ -60,18 +60,16 @@ static inline struct dev_info *which_dev(struct mddev *mddev, sector_t sector)
*
* Return amount of bytes we can take at this offset
*/
-static int linear_mergeable_bvec(struct request_queue *q,
+static int linear_mergeable_bvec(struct mddev *mddev,
struct bvec_merge_data *bvm,
struct bio_vec *biovec)
{
- struct mddev *mddev = q->queuedata;
struct dev_info *dev0;
unsigned long maxsectors, bio_sectors = bvm->bi_size >> 9;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
int maxbytes = biovec->bv_len;
struct request_queue *subq;
- rcu_read_lock();
dev0 = which_dev(mddev, sector);
maxsectors = dev0->end_sector - sector;
subq = bdev_get_queue(dev0->rdev->bdev);
@@ -81,7 +79,6 @@ static int linear_mergeable_bvec(struct request_queue *q,
maxbytes = min(maxbytes, subq->merge_bvec_fn(subq, bvm,
biovec));
}
- rcu_read_unlock();
if (maxsectors < bio_sectors)
maxsectors = 0;
@@ -97,24 +94,18 @@ static int linear_mergeable_bvec(struct request_queue *q,
return maxsectors << 9;
}
-static int linear_congested(void *data, int bits)
+static int linear_congested(struct mddev *mddev, int bits)
{
- struct mddev *mddev = data;
struct linear_conf *conf;
int i, ret = 0;
- if (mddev_congested(mddev, bits))
- return 1;
-
- rcu_read_lock();
- conf = rcu_dereference(mddev->private);
+ conf = mddev->private;
for (i = 0; i < mddev->raid_disks && !ret ; i++) {
struct request_queue *q = bdev_get_queue(conf->disks[i].rdev->bdev);
ret |= bdi_congested(&q->backing_dev_info, bits);
}
- rcu_read_unlock();
return ret;
}
@@ -123,12 +114,10 @@ static sector_t linear_size(struct mddev *mddev, sector_t sectors, int raid_disk
struct linear_conf *conf;
sector_t array_sectors;
- rcu_read_lock();
- conf = rcu_dereference(mddev->private);
+ conf = mddev->private;
WARN_ONCE(sectors || raid_disks,
"%s does not support generic reshape\n", __func__);
array_sectors = conf->array_sectors;
- rcu_read_unlock();
return array_sectors;
}
@@ -217,10 +206,6 @@ static int linear_run (struct mddev *mddev)
mddev->private = conf;
md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
- blk_queue_merge_bvec(mddev->queue, linear_mergeable_bvec);
- mddev->queue->backing_dev_info.congested_fn = linear_congested;
- mddev->queue->backing_dev_info.congested_data = mddev;
-
ret = md_integrity_register(mddev);
if (ret) {
kfree(conf);
@@ -252,38 +237,23 @@ static int linear_add(struct mddev *mddev, struct md_rdev *rdev)
if (!newconf)
return -ENOMEM;
- oldconf = rcu_dereference_protected(mddev->private,
- lockdep_is_held(
- &mddev->reconfig_mutex));
+ mddev_suspend(mddev);
+ oldconf = mddev->private;
mddev->raid_disks++;
- rcu_assign_pointer(mddev->private, newconf);
+ mddev->private = newconf;
md_set_array_sectors(mddev, linear_size(mddev, 0, 0));
set_capacity(mddev->gendisk, mddev->array_sectors);
+ mddev_resume(mddev);
revalidate_disk(mddev->gendisk);
- kfree_rcu(oldconf, rcu);
+ kfree(oldconf);
return 0;
}
-static int linear_stop (struct mddev *mddev)
+static void linear_free(struct mddev *mddev, void *priv)
{
- struct linear_conf *conf =
- rcu_dereference_protected(mddev->private,
- lockdep_is_held(
- &mddev->reconfig_mutex));
+ struct linear_conf *conf = priv;
- /*
- * We do not require rcu protection here since
- * we hold reconfig_mutex for both linear_add and
- * linear_stop, so they cannot race.
- * We should make sure any old 'conf's are properly
- * freed though.
- */
- rcu_barrier();
- blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf);
- mddev->private = NULL;
-
- return 0;
}
static void linear_make_request(struct mddev *mddev, struct bio *bio)
@@ -299,16 +269,12 @@ static void linear_make_request(struct mddev *mddev, struct bio *bio)
}
do {
- rcu_read_lock();
-
tmp_dev = which_dev(mddev, bio->bi_iter.bi_sector);
start_sector = tmp_dev->end_sector - tmp_dev->rdev->sectors;
end_sector = tmp_dev->end_sector;
data_offset = tmp_dev->rdev->data_offset;
bio->bi_bdev = tmp_dev->rdev->bdev;
- rcu_read_unlock();
-
if (unlikely(bio->bi_iter.bi_sector >= end_sector ||
bio->bi_iter.bi_sector < start_sector))
goto out_of_bounds;
@@ -355,6 +321,10 @@ static void linear_status (struct seq_file *seq, struct mddev *mddev)
seq_printf(seq, " %dk rounding", mddev->chunk_sectors / 2);
}
+static void linear_quiesce(struct mddev *mddev, int state)
+{
+}
+
static struct md_personality linear_personality =
{
.name = "linear",
@@ -362,10 +332,13 @@ static struct md_personality linear_personality =
.owner = THIS_MODULE,
.make_request = linear_make_request,
.run = linear_run,
- .stop = linear_stop,
+ .free = linear_free,
.status = linear_status,
.hot_add_disk = linear_add,
.size = linear_size,
+ .quiesce = linear_quiesce,
+ .congested = linear_congested,
+ .mergeable_bvec = linear_mergeable_bvec,
};
static int __init linear_init (void)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 709755fb6d7b..c8d2bac4e28b 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -72,6 +72,7 @@ static struct workqueue_struct *md_misc_wq;
static int remove_and_add_spares(struct mddev *mddev,
struct md_rdev *this);
+static void mddev_detach(struct mddev *mddev);
/*
* Default number of read corrections we'll attempt on an rdev
@@ -292,8 +293,8 @@ static void md_make_request(struct request_queue *q, struct bio *bio)
/* mddev_suspend makes sure no new requests are submitted
* to the device, and that any requests that have been submitted
* are completely handled.
- * Once ->stop is called and completes, the module will be completely
- * unused.
+ * Once mddev_detach() is called and completes, the module will be
+ * completely unused.
*/
void mddev_suspend(struct mddev *mddev)
{
@@ -321,10 +322,47 @@ EXPORT_SYMBOL_GPL(mddev_resume);
int mddev_congested(struct mddev *mddev, int bits)
{
- return mddev->suspended;
+ struct md_personality *pers = mddev->pers;
+ int ret = 0;
+
+ rcu_read_lock();
+ if (mddev->suspended)
+ ret = 1;
+ else if (pers && pers->congested)
+ ret = pers->congested(mddev, bits);
+ rcu_read_unlock();
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mddev_congested);
+static int md_congested(void *data, int bits)
+{
+ struct mddev *mddev = data;
+ return mddev_congested(mddev, bits);
}
-EXPORT_SYMBOL(mddev_congested);
+static int md_mergeable_bvec(struct request_queue *q,
+ struct bvec_merge_data *bvm,
+ struct bio_vec *biovec)
+{
+ struct mddev *mddev = q->queuedata;
+ int ret;
+ rcu_read_lock();
+ if (mddev->suspended) {
+ /* Must always allow one vec */
+ if (bvm->bi_size == 0)
+ ret = biovec->bv_len;
+ else
+ ret = 0;
+ } else {
+ struct md_personality *pers = mddev->pers;
+ if (pers && pers->mergeable_bvec)
+ ret = pers->mergeable_bvec(mddev, bvm, biovec);
+ else
+ ret = biovec->bv_len;
+ }
+ rcu_read_unlock();
+ return ret;
+}
/*
* Generic flush handling for md
*/
@@ -397,12 +435,12 @@ static void md_submit_flush_data(struct work_struct *ws)
void md_flush_request(struct mddev *mddev, struct bio *bio)
{
- spin_lock_irq(&mddev->write_lock);
+ spin_lock_irq(&mddev->lock);
wait_event_lock_irq(mddev->sb_wait,
!mddev->flush_bio,
- mddev->write_lock);
+ mddev->lock);
mddev->flush_bio = bio;
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock_irq(&mddev->lock);
INIT_WORK(&mddev->flush_work, submit_flushes);
queue_work(md_wq, &mddev->flush_work);
@@ -465,7 +503,7 @@ void mddev_init(struct mddev *mddev)
atomic_set(&mddev->active, 1);
atomic_set(&mddev->openers, 0);
atomic_set(&mddev->active_io, 0);
- spin_lock_init(&mddev->write_lock);
+ spin_lock_init(&mddev->lock);
atomic_set(&mddev->flush_pending, 0);
init_waitqueue_head(&mddev->sb_wait);
init_waitqueue_head(&mddev->recovery_wait);
@@ -552,32 +590,9 @@ static struct mddev *mddev_find(dev_t unit)
goto retry;
}
-static inline int __must_check mddev_lock(struct mddev *mddev)
-{
- return mutex_lock_interruptible(&mddev->reconfig_mutex);
-}
-
-/* Sometimes we need to take the lock in a situation where
- * failure due to interrupts is not acceptable.
- */
-static inline void mddev_lock_nointr(struct mddev *mddev)
-{
- mutex_lock(&mddev->reconfig_mutex);
-}
-
-static inline int mddev_is_locked(struct mddev *mddev)
-{
- return mutex_is_locked(&mddev->reconfig_mutex);
-}
-
-static inline int mddev_trylock(struct mddev *mddev)
-{
- return mutex_trylock(&mddev->reconfig_mutex);
-}
-
static struct attribute_group md_redundancy_group;
-static void mddev_unlock(struct mddev *mddev)
+void mddev_unlock(struct mddev *mddev)
{
if (mddev->to_remove) {
/* These cannot be removed under reconfig_mutex as
@@ -619,6 +634,7 @@ static void mddev_unlock(struct mddev *mddev)
md_wakeup_thread(mddev->thread);
spin_unlock(&pers_lock);
}
+EXPORT_SYMBOL_GPL(mddev_unlock);
static struct md_rdev *find_rdev_nr_rcu(struct mddev *mddev, int nr)
{
@@ -2230,7 +2246,7 @@ repeat:
return;
}
- spin_lock_irq(&mddev->write_lock);
+ spin_lock(&mddev->lock);
mddev->utime = get_seconds();
@@ -2287,7 +2303,7 @@ repeat:
}
sync_sbs(mddev, nospares);
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
pr_debug("md: updating %s RAID superblock on device (in sync %d)\n",
mdname(mddev), mddev->in_sync);
@@ -2326,15 +2342,15 @@ repeat:
md_super_wait(mddev);
/* if there was a failure, MD_CHANGE_DEVS was set, and we re-write super */
- spin_lock_irq(&mddev->write_lock);
+ spin_lock(&mddev->lock);
if (mddev->in_sync != sync_req ||
test_bit(MD_CHANGE_DEVS, &mddev->flags)) {
/* have to write it out again */
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
goto repeat;
}
clear_bit(MD_CHANGE_PENDING, &mddev->flags);
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
wake_up(&mddev->sb_wait);
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
sysfs_notify(&mddev->kobj, NULL, "sync_completed");
@@ -2381,40 +2397,41 @@ state_show(struct md_rdev *rdev, char *page)
{
char *sep = "";
size_t len = 0;
+ unsigned long flags = ACCESS_ONCE(rdev->flags);
- if (test_bit(Faulty, &rdev->flags) ||
+ if (test_bit(Faulty, &flags) ||
rdev->badblocks.unacked_exist) {
len+= sprintf(page+len, "%sfaulty",sep);
sep = ",";
}
- if (test_bit(In_sync, &rdev->flags)) {
+ if (test_bit(In_sync, &flags)) {
len += sprintf(page+len, "%sin_sync",sep);
sep = ",";
}
- if (test_bit(WriteMostly, &rdev->flags)) {
+ if (test_bit(WriteMostly, &flags)) {
len += sprintf(page+len, "%swrite_mostly",sep);
sep = ",";
}
- if (test_bit(Blocked, &rdev->flags) ||
+ if (test_bit(Blocked, &flags) ||
(rdev->badblocks.unacked_exist
- && !test_bit(Faulty, &rdev->flags))) {
+ && !test_bit(Faulty, &flags))) {
len += sprintf(page+len, "%sblocked", sep);
sep = ",";
}
- if (!test_bit(Faulty, &rdev->flags) &&
- !test_bit(In_sync, &rdev->flags)) {
+ if (!test_bit(Faulty, &flags) &&
+ !test_bit(In_sync, &flags)) {
len += sprintf(page+len, "%sspare", sep);
sep = ",";
}
- if (test_bit(WriteErrorSeen, &rdev->flags)) {
+ if (test_bit(WriteErrorSeen, &flags)) {
len += sprintf(page+len, "%swrite_error", sep);
sep = ",";
}
- if (test_bit(WantReplacement, &rdev->flags)) {
+ if (test_bit(WantReplacement, &flags)) {
len += sprintf(page+len, "%swant_replacement", sep);
sep = ",";
}
- if (test_bit(Replacement, &rdev->flags)) {
+ if (test_bit(Replacement, &flags)) {
len += sprintf(page+len, "%sreplacement", sep);
sep = ",";
}
@@ -2927,21 +2944,12 @@ rdev_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
{
struct rdev_sysfs_entry *entry = container_of(attr, struct rdev_sysfs_entry, attr);
struct md_rdev *rdev = container_of(kobj, struct md_rdev, kobj);
- struct mddev *mddev = rdev->mddev;
- ssize_t rv;
if (!entry->show)
return -EIO;
-
- rv = mddev ? mddev_lock(mddev) : -EBUSY;
- if (!rv) {
- if (rdev->mddev == NULL)
- rv = -EBUSY;
- else
- rv = entry->show(rdev, page);
- mddev_unlock(mddev);
- }
- return rv;
+ if (!rdev->mddev)
+ return -EBUSY;
+ return entry->show(rdev, page);
}
static ssize_t
@@ -3212,11 +3220,13 @@ safe_delay_store(struct mddev *mddev, const char *cbuf, size_t len)
mddev->safemode_delay = 0;
else {
unsigned long old_delay = mddev->safemode_delay;
- mddev->safemode_delay = (msec*HZ)/1000;
- if (mddev->safemode_delay == 0)
- mddev->safemode_delay = 1;
- if (mddev->safemode_delay < old_delay || old_delay == 0)
- md_safemode_timeout((unsigned long)mddev);
+ unsigned long new_delay = (msec*HZ)/1000;
+
+ if (new_delay == 0)
+ new_delay = 1;
+ mddev->safemode_delay = new_delay;
+ if (new_delay < old_delay || old_delay == 0)
+ mod_timer(&mddev->safemode_timer, jiffies+1);
}
return len;
}
@@ -3226,41 +3236,52 @@ __ATTR(safe_mode_delay, S_IRUGO|S_IWUSR,safe_delay_show, safe_delay_store);
static ssize_t
level_show(struct mddev *mddev, char *page)
{
- struct md_personality *p = mddev->pers;
+ struct md_personality *p;
+ int ret;
+ spin_lock(&mddev->lock);
+ p = mddev->pers;
if (p)
- return sprintf(page, "%s\n", p->name);
+ ret = sprintf(page, "%s\n", p->name);
else if (mddev->clevel[0])
- return sprintf(page, "%s\n", mddev->clevel);
+ ret = sprintf(page, "%s\n", mddev->clevel);
else if (mddev->level != LEVEL_NONE)
- return sprintf(page, "%d\n", mddev->level);
+ ret = sprintf(page, "%d\n", mddev->level);
else
- return 0;
+ ret = 0;
+ spin_unlock(&mddev->lock);
+ return ret;
}
static ssize_t
level_store(struct mddev *mddev, const char *buf, size_t len)
{
char clevel[16];
- ssize_t rv = len;
- struct md_personality *pers;
+ ssize_t rv;
+ size_t slen = len;
+ struct md_personality *pers, *oldpers;
long level;
- void *priv;
+ void *priv, *oldpriv;
struct md_rdev *rdev;
+ if (slen == 0 || slen >= sizeof(clevel))
+ return -EINVAL;
+
+ rv = mddev_lock(mddev);
+ if (rv)
+ return rv;
+
if (mddev->pers == NULL) {
- if (len == 0)
- return 0;
- if (len >= sizeof(mddev->clevel))
- return -ENOSPC;
- strncpy(mddev->clevel, buf, len);
- if (mddev->clevel[len-1] == '\n')
- len--;
- mddev->clevel[len] = 0;
+ strncpy(mddev->clevel, buf, slen);
+ if (mddev->clevel[slen-1] == '\n')
+ slen--;
+ mddev->clevel[slen] = 0;
mddev->level = LEVEL_NONE;
- return rv;
+ rv = len;
+ goto out_unlock;
}
+ rv = -EROFS;
if (mddev->ro)
- return -EROFS;
+ goto out_unlock;
/* request to change the personality. Need to ensure:
* - array is not engaged in resync/recovery/reshape
@@ -3268,25 +3289,25 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
* - new personality will access other array.
*/
+ rv = -EBUSY;
if (mddev->sync_thread ||
test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
mddev->reshape_position != MaxSector ||
mddev->sysfs_active)
- return -EBUSY;
+ goto out_unlock;
+ rv = -EINVAL;
if (!mddev->pers->quiesce) {
printk(KERN_WARNING "md: %s: %s does not support online personality change\n",
mdname(mddev), mddev->pers->name);
- return -EINVAL;
+ goto out_unlock;
}
/* Now find the new personality */
- if (len == 0 || len >= sizeof(clevel))
- return -EINVAL;
- strncpy(clevel, buf, len);
- if (clevel[len-1] == '\n')
- len--;
- clevel[len] = 0;
+ strncpy(clevel, buf, slen);
+ if (clevel[slen-1] == '\n')
+ slen--;
+ clevel[slen] = 0;
if (kstrtol(clevel, 10, &level))
level = LEVEL_NONE;
@@ -3297,20 +3318,23 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
if (!pers || !try_module_get(pers->owner)) {
spin_unlock(&pers_lock);
printk(KERN_WARNING "md: personality %s not loaded\n", clevel);
- return -EINVAL;
+ rv = -EINVAL;
+ goto out_unlock;
}
spin_unlock(&pers_lock);
if (pers == mddev->pers) {
/* Nothing to do! */
module_put(pers->owner);
- return rv;
+ rv = len;
+ goto out_unlock;
}
if (!pers->takeover) {
module_put(pers->owner);
printk(KERN_WARNING "md: %s: %s does not support personality takeover\n",
mdname(mddev), clevel);
- return -EINVAL;
+ rv = -EINVAL;
+ goto out_unlock;
}
rdev_for_each(rdev, mddev)
@@ -3330,30 +3354,29 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
module_put(pers->owner);
printk(KERN_WARNING "md: %s: %s would not accept array\n",
mdname(mddev), clevel);
- return PTR_ERR(priv);
+ rv = PTR_ERR(priv);
+ goto out_unlock;
}
/* Looks like we have a winner */
mddev_suspend(mddev);
- mddev->pers->stop(mddev);
+ mddev_detach(mddev);
- if (mddev->pers->sync_request == NULL &&
- pers->sync_request != NULL) {
- /* need to add the md_redundancy_group */
- if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
- printk(KERN_WARNING
- "md: cannot register extra attributes for %s\n",
- mdname(mddev));
- mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
- }
- if (mddev->pers->sync_request != NULL &&
- pers->sync_request == NULL) {
- /* need to remove the md_redundancy_group */
- if (mddev->to_remove == NULL)
- mddev->to_remove = &md_redundancy_group;
- }
+ spin_lock(&mddev->lock);
+ oldpers = mddev->pers;
+ oldpriv = mddev->private;
+ mddev->pers = pers;
+ mddev->private = priv;
+ strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
+ mddev->level = mddev->new_level;
+ mddev->layout = mddev->new_layout;
+ mddev->chunk_sectors = mddev->new_chunk_sectors;
+ mddev->delta_disks = 0;
+ mddev->reshape_backwards = 0;
+ mddev->degraded = 0;
+ spin_unlock(&mddev->lock);
- if (mddev->pers->sync_request == NULL &&
+ if (oldpers->sync_request == NULL &&
mddev->external) {
/* We are converting from a no-redundancy array
* to a redundancy array and metadata is managed
@@ -3367,6 +3390,24 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
mddev->safemode = 0;
}
+ oldpers->free(mddev, oldpriv);
+
+ if (oldpers->sync_request == NULL &&
+ pers->sync_request != NULL) {
+ /* need to add the md_redundancy_group */
+ if (sysfs_create_group(&mddev->kobj, &md_redundancy_group))
+ printk(KERN_WARNING
+ "md: cannot register extra attributes for %s\n",
+ mdname(mddev));
+ mddev->sysfs_action = sysfs_get_dirent(mddev->kobj.sd, "sync_action");
+ }
+ if (oldpers->sync_request != NULL &&
+ pers->sync_request == NULL) {
+ /* need to remove the md_redundancy_group */
+ if (mddev->to_remove == NULL)
+ mddev->to_remove = &md_redundancy_group;
+ }
+
rdev_for_each(rdev, mddev) {
if (rdev->raid_disk < 0)
continue;
@@ -3392,17 +3433,7 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
}
}
- module_put(mddev->pers->owner);
- mddev->pers = pers;
- mddev->private = priv;
- strlcpy(mddev->clevel, pers->name, sizeof(mddev->clevel));
- mddev->level = mddev->new_level;
- mddev->layout = mddev->new_layout;
- mddev->chunk_sectors = mddev->new_chunk_sectors;
- mddev->delta_disks = 0;
- mddev->reshape_backwards = 0;
- mddev->degraded = 0;
- if (mddev->pers->sync_request == NULL) {
+ if (pers->sync_request == NULL) {
/* this is now an array without redundancy, so
* it must always be in_sync
*/
@@ -3417,6 +3448,9 @@ level_store(struct mddev *mddev, const char *buf, size_t len)
md_update_sb(mddev, 1);
sysfs_notify(&mddev->kobj, NULL, "level");
md_new_event(mddev);
+ rv = len;
+out_unlock:
+ mddev_unlock(mddev);
return rv;
}
@@ -3439,28 +3473,32 @@ layout_store(struct mddev *mddev, const char *buf, size_t len)
{
char *e;
unsigned long n = simple_strtoul(buf, &e, 10);
+ int err;
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (mddev->pers) {
- int err;
if (mddev->pers->check_reshape == NULL)
- return -EBUSY;
- if (mddev->ro)
- return -EROFS;
- mddev->new_layout = n;
- err = mddev->pers->check_reshape(mddev);
- if (err) {
- mddev->new_layout = mddev->layout;
- return err;
+ err = -EBUSY;
+ else if (mddev->ro)
+ err = -EROFS;
+ else {
+ mddev->new_layout = n;
+ err = mddev->pers->check_reshape(mddev);
+ if (err)
+ mddev->new_layout = mddev->layout;
}
} else {
mddev->new_layout = n;
if (mddev->reshape_position == MaxSector)
mddev->layout = n;
}
- return len;
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_layout =
__ATTR(layout, S_IRUGO|S_IWUSR, layout_show, layout_store);
@@ -3483,32 +3521,39 @@ static ssize_t
raid_disks_store(struct mddev *mddev, const char *buf, size_t len)
{
char *e;
- int rv = 0;
+ int err;
unsigned long n = simple_strtoul(buf, &e, 10);
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (mddev->pers)
- rv = update_raid_disks(mddev, n);
+ err = update_raid_disks(mddev, n);
else if (mddev->reshape_position != MaxSector) {
struct md_rdev *rdev;
int olddisks = mddev->raid_disks - mddev->delta_disks;
+ err = -EINVAL;
rdev_for_each(rdev, mddev) {
if (olddisks < n &&
rdev->data_offset < rdev->new_data_offset)
- return -EINVAL;
+ goto out_unlock;
if (olddisks > n &&
rdev->data_offset > rdev->new_data_offset)
- return -EINVAL;
+ goto out_unlock;
}
+ err = 0;
mddev->delta_disks = n - olddisks;
mddev->raid_disks = n;
mddev->reshape_backwards = (mddev->delta_disks < 0);
} else
mddev->raid_disks = n;
- return rv ? rv : len;
+out_unlock:
+ mddev_unlock(mddev);
+ return err ? err : len;
}
static struct md_sysfs_entry md_raid_disks =
__ATTR(raid_disks, S_IRUGO|S_IWUSR, raid_disks_show, raid_disks_store);
@@ -3527,30 +3572,34 @@ chunk_size_show(struct mddev *mddev, char *page)
static ssize_t
chunk_size_store(struct mddev *mddev, const char *buf, size_t len)
{
+ int err;
char *e;
unsigned long n = simple_strtoul(buf, &e, 10);
if (!*buf || (*e && *e != '\n'))
return -EINVAL;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (mddev->pers) {
- int err;
if (mddev->pers->check_reshape == NULL)
- return -EBUSY;
- if (mddev->ro)
- return -EROFS;
- mddev->new_chunk_sectors = n >> 9;
- err = mddev->pers->check_reshape(mddev);
- if (err) {
- mddev->new_chunk_sectors = mddev->chunk_sectors;
- return err;
+ err = -EBUSY;
+ else if (mddev->ro)
+ err = -EROFS;
+ else {
+ mddev->new_chunk_sectors = n >> 9;
+ err = mddev->pers->check_reshape(mddev);
+ if (err)
+ mddev->new_chunk_sectors = mddev->chunk_sectors;
}
} else {
mddev->new_chunk_sectors = n >> 9;
if (mddev->reshape_position == MaxSector)
mddev->chunk_sectors = n >> 9;
}
- return len;
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_chunk_size =
__ATTR(chunk_size, S_IRUGO|S_IWUSR, chunk_size_show, chunk_size_store);
@@ -3566,20 +3615,27 @@ resync_start_show(struct mddev *mddev, char *page)
static ssize_t
resync_start_store(struct mddev *mddev, const char *buf, size_t len)
{
+ int err;
char *e;
unsigned long long n = simple_strtoull(buf, &e, 10);
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (mddev->pers && !test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
- return -EBUSY;
- if (cmd_match(buf, "none"))
+ err = -EBUSY;
+ else if (cmd_match(buf, "none"))
n = MaxSector;
else if (!*buf || (*e && *e != '\n'))
- return -EINVAL;
+ err = -EINVAL;
- mddev->recovery_cp = n;
- if (mddev->pers)
- set_bit(MD_CHANGE_CLEAN, &mddev->flags);
- return len;
+ if (!err) {
+ mddev->recovery_cp = n;
+ if (mddev->pers)
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_resync_start =
__ATTR(resync_start, S_IRUGO|S_IWUSR, resync_start_show, resync_start_store);
@@ -3677,8 +3733,39 @@ static int restart_array(struct mddev *mddev);
static ssize_t
array_state_store(struct mddev *mddev, const char *buf, size_t len)
{
- int err = -EINVAL;
+ int err;
enum array_state st = match_word(buf, array_states);
+
+ if (mddev->pers && (st == active || st == clean) && mddev->ro != 1) {
+ /* don't take reconfig_mutex when toggling between
+ * clean and active
+ */
+ spin_lock(&mddev->lock);
+ if (st == active) {
+ restart_array(mddev);
+ clear_bit(MD_CHANGE_PENDING, &mddev->flags);
+ wake_up(&mddev->sb_wait);
+ err = 0;
+ } else /* st == clean */ {
+ restart_array(mddev);
+ if (atomic_read(&mddev->writes_pending) == 0) {
+ if (mddev->in_sync == 0) {
+ mddev->in_sync = 1;
+ if (mddev->safemode == 1)
+ mddev->safemode = 0;
+ set_bit(MD_CHANGE_CLEAN, &mddev->flags);
+ }
+ err = 0;
+ } else
+ err = -EBUSY;
+ }
+ spin_unlock(&mddev->lock);
+ return err;
+ }
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ err = -EINVAL;
switch(st) {
case bad_word:
break;
@@ -3722,7 +3809,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
case clean:
if (mddev->pers) {
restart_array(mddev);
- spin_lock_irq(&mddev->write_lock);
+ spin_lock(&mddev->lock);
if (atomic_read(&mddev->writes_pending) == 0) {
if (mddev->in_sync == 0) {
mddev->in_sync = 1;
@@ -3733,7 +3820,7 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
err = 0;
} else
err = -EBUSY;
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
} else
err = -EINVAL;
break;
@@ -3754,14 +3841,14 @@ array_state_store(struct mddev *mddev, const char *buf, size_t len)
/* these cannot be set */
break;
}
- if (err)
- return err;
- else {
+
+ if (!err) {
if (mddev->hold_active == UNTIL_IOCTL)
mddev->hold_active = 0;
sysfs_notify_dirent_safe(mddev->sysfs_state);
- return len;
}
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_array_state =
__ATTR(array_state, S_IRUGO|S_IWUSR, array_state_show, array_state_store);
@@ -3822,6 +3909,11 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len)
minor != MINOR(dev))
return -EOVERFLOW;
+ flush_workqueue(md_misc_wq);
+
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (mddev->persistent) {
rdev = md_import_device(dev, mddev->major_version,
mddev->minor_version);
@@ -3845,6 +3937,7 @@ new_dev_store(struct mddev *mddev, const char *buf, size_t len)
out:
if (err)
export_rdev(rdev);
+ mddev_unlock(mddev);
return err ? err : len;
}
@@ -3856,7 +3949,11 @@ bitmap_store(struct mddev *mddev, const char *buf, size_t len)
{
char *end;
unsigned long chunk, end_chunk;
+ int err;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (!mddev->bitmap)
goto out;
/* buf should be <chunk> <chunk> ... or <chunk>-<chunk> ... (range) */
@@ -3874,6 +3971,7 @@ bitmap_store(struct mddev *mddev, const char *buf, size_t len)
}
bitmap_unplug(mddev->bitmap); /* flush the bits to disk */
out:
+ mddev_unlock(mddev);
return len;
}
@@ -3901,6 +3999,9 @@ size_store(struct mddev *mddev, const char *buf, size_t len)
if (err < 0)
return err;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (mddev->pers) {
err = update_size(mddev, sectors);
md_update_sb(mddev, 1);
@@ -3911,6 +4012,7 @@ size_store(struct mddev *mddev, const char *buf, size_t len)
else
err = -ENOSPC;
}
+ mddev_unlock(mddev);
return err ? err : len;
}
@@ -3940,21 +4042,28 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len)
{
int major, minor;
char *e;
+ int err;
/* Changing the details of 'external' metadata is
* always permitted. Otherwise there must be
* no devices attached to the array.
*/
+
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ err = -EBUSY;
if (mddev->external && strncmp(buf, "external:", 9) == 0)
;
else if (!list_empty(&mddev->disks))
- return -EBUSY;
+ goto out_unlock;
+ err = 0;
if (cmd_match(buf, "none")) {
mddev->persistent = 0;
mddev->external = 0;
mddev->major_version = 0;
mddev->minor_version = 90;
- return len;
+ goto out_unlock;
}
if (strncmp(buf, "external:", 9) == 0) {
size_t namelen = len-9;
@@ -3968,22 +4077,27 @@ metadata_store(struct mddev *mddev, const char *buf, size_t len)
mddev->external = 1;
mddev->major_version = 0;
mddev->minor_version = 90;
- return len;
+ goto out_unlock;
}
major = simple_strtoul(buf, &e, 10);
+ err = -EINVAL;
if (e==buf || *e != '.')
- return -EINVAL;
+ goto out_unlock;
buf = e+1;
minor = simple_strtoul(buf, &e, 10);
if (e==buf || (*e && *e != '\n') )
- return -EINVAL;
+ goto out_unlock;
+ err = -ENOENT;
if (major >= ARRAY_SIZE(super_types) || super_types[major].name == NULL)
- return -ENOENT;
+ goto out_unlock;
mddev->major_version = major;
mddev->minor_version = minor;
mddev->persistent = 1;
mddev->external = 0;
- return len;
+ err = 0;
+out_unlock:
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_metadata =
@@ -3993,20 +4107,21 @@ static ssize_t
action_show(struct mddev *mddev, char *page)
{
char *type = "idle";
- if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery))
+ unsigned long recovery = mddev->recovery;
+ if (test_bit(MD_RECOVERY_FROZEN, &recovery))
type = "frozen";
- else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
- (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) {
- if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery))
+ else if (test_bit(MD_RECOVERY_RUNNING, &recovery) ||
+ (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &recovery))) {
+ if (test_bit(MD_RECOVERY_RESHAPE, &recovery))
type = "reshape";
- else if (test_bit(MD_RECOVERY_SYNC, &mddev->recovery)) {
- if (!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ else if (test_bit(MD_RECOVERY_SYNC, &recovery)) {
+ if (!test_bit(MD_RECOVERY_REQUESTED, &recovery))
type = "resync";
- else if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+ else if (test_bit(MD_RECOVERY_CHECK, &recovery))
type = "check";
else
type = "repair";
- } else if (test_bit(MD_RECOVERY_RECOVER, &mddev->recovery))
+ } else if (test_bit(MD_RECOVERY_RECOVER, &recovery))
type = "recover";
}
return sprintf(page, "%s\n", type);
@@ -4027,7 +4142,10 @@ action_store(struct mddev *mddev, const char *page, size_t len)
flush_workqueue(md_misc_wq);
if (mddev->sync_thread) {
set_bit(MD_RECOVERY_INTR, &mddev->recovery);
- md_reap_sync_thread(mddev);
+ if (mddev_lock(mddev) == 0) {
+ md_reap_sync_thread(mddev);
+ mddev_unlock(mddev);
+ }
}
} else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) ||
test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))
@@ -4041,7 +4159,11 @@ action_store(struct mddev *mddev, const char *page, size_t len)
int err;
if (mddev->pers->start_reshape == NULL)
return -EINVAL;
- err = mddev->pers->start_reshape(mddev);
+ err = mddev_lock(mddev);
+ if (!err) {
+ err = mddev->pers->start_reshape(mddev);
+ mddev_unlock(mddev);
+ }
if (err)
return err;
sysfs_notify(&mddev->kobj, NULL, "degraded");
@@ -4225,22 +4347,36 @@ static ssize_t
min_sync_store(struct mddev *mddev, const char *buf, size_t len)
{
unsigned long long min;
+ int err;
+ int chunk;
+
if (kstrtoull(buf, 10, &min))
return -EINVAL;
+
+ spin_lock(&mddev->lock);
+ err = -EINVAL;
if (min > mddev->resync_max)
- return -EINVAL;
+ goto out_unlock;
+
+ err = -EBUSY;
if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
- return -EBUSY;
+ goto out_unlock;
/* Must be a multiple of chunk_size */
- if (mddev->chunk_sectors) {
+ chunk = mddev->chunk_sectors;
+ if (chunk) {
sector_t temp = min;
- if (sector_div(temp, mddev->chunk_sectors))
- return -EINVAL;
+
+ err = -EINVAL;
+ if (sector_div(temp, chunk))
+ goto out_unlock;
}
mddev->resync_min = min;
+ err = 0;
- return len;
+out_unlock:
+ spin_unlock(&mddev->lock);
+ return err ?: len;
}
static struct md_sysfs_entry md_min_sync =
@@ -4258,29 +4394,42 @@ max_sync_show(struct mddev *mddev, char *page)
static ssize_t
max_sync_store(struct mddev *mddev, const char *buf, size_t len)
{
+ int err;
+ spin_lock(&mddev->lock);
if (strncmp(buf, "max", 3) == 0)
mddev->resync_max = MaxSector;
else {
unsigned long long max;
+ int chunk;
+
+ err = -EINVAL;
if (kstrtoull(buf, 10, &max))
- return -EINVAL;
+ goto out_unlock;
if (max < mddev->resync_min)
- return -EINVAL;
+ goto out_unlock;
+
+ err = -EBUSY;
if (max < mddev->resync_max &&
mddev->ro == 0 &&
test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
- return -EBUSY;
+ goto out_unlock;
/* Must be a multiple of chunk_size */
- if (mddev->chunk_sectors) {
+ chunk = mddev->chunk_sectors;
+ if (chunk) {
sector_t temp = max;
- if (sector_div(temp, mddev->chunk_sectors))
- return -EINVAL;
+
+ err = -EINVAL;
+ if (sector_div(temp, chunk))
+ goto out_unlock;
}
mddev->resync_max = max;
}
wake_up(&mddev->recovery_wait);
- return len;
+ err = 0;
+out_unlock:
+ spin_unlock(&mddev->lock);
+ return err ?: len;
}
static struct md_sysfs_entry md_max_sync =
@@ -4297,14 +4446,20 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
- unsigned long long old = mddev->suspend_lo;
+ unsigned long long old;
+ int err;
- if (mddev->pers == NULL ||
- mddev->pers->quiesce == NULL)
- return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ err = -EINVAL;
+ if (mddev->pers == NULL ||
+ mddev->pers->quiesce == NULL)
+ goto unlock;
+ old = mddev->suspend_lo;
mddev->suspend_lo = new;
if (new >= old)
/* Shrinking suspended region */
@@ -4314,7 +4469,10 @@ suspend_lo_store(struct mddev *mddev, const char *buf, size_t len)
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
}
- return len;
+ err = 0;
+unlock:
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_suspend_lo =
__ATTR(suspend_lo, S_IRUGO|S_IWUSR, suspend_lo_show, suspend_lo_store);
@@ -4330,14 +4488,20 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len)
{
char *e;
unsigned long long new = simple_strtoull(buf, &e, 10);
- unsigned long long old = mddev->suspend_hi;
+ unsigned long long old;
+ int err;
- if (mddev->pers == NULL ||
- mddev->pers->quiesce == NULL)
- return -EINVAL;
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ err = -EINVAL;
+ if (mddev->pers == NULL ||
+ mddev->pers->quiesce == NULL)
+ goto unlock;
+ old = mddev->suspend_hi;
mddev->suspend_hi = new;
if (new <= old)
/* Shrinking suspended region */
@@ -4347,7 +4511,10 @@ suspend_hi_store(struct mddev *mddev, const char *buf, size_t len)
mddev->pers->quiesce(mddev, 1);
mddev->pers->quiesce(mddev, 0);
}
- return len;
+ err = 0;
+unlock:
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_suspend_hi =
__ATTR(suspend_hi, S_IRUGO|S_IWUSR, suspend_hi_show, suspend_hi_store);
@@ -4367,11 +4534,17 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
{
struct md_rdev *rdev;
char *e;
+ int err;
unsigned long long new = simple_strtoull(buf, &e, 10);
- if (mddev->pers)
- return -EBUSY;
+
if (buf == e || (*e && *e != '\n'))
return -EINVAL;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ err = -EBUSY;
+ if (mddev->pers)
+ goto unlock;
mddev->reshape_position = new;
mddev->delta_disks = 0;
mddev->reshape_backwards = 0;
@@ -4380,7 +4553,10 @@ reshape_position_store(struct mddev *mddev, const char *buf, size_t len)
mddev->new_chunk_sectors = mddev->chunk_sectors;
rdev_for_each(rdev, mddev)
rdev->new_data_offset = rdev->data_offset;
- return len;
+ err = 0;
+unlock:
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_reshape_position =
@@ -4398,6 +4574,8 @@ static ssize_t
reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
{
int backwards = 0;
+ int err;
+
if (cmd_match(buf, "forwards"))
backwards = 0;
else if (cmd_match(buf, "backwards"))
@@ -4407,16 +4585,19 @@ reshape_direction_store(struct mddev *mddev, const char *buf, size_t len)
if (mddev->reshape_backwards == backwards)
return len;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
/* check if we are allowed to change */
if (mddev->delta_disks)
- return -EBUSY;
-
- if (mddev->persistent &&
+ err = -EBUSY;
+ else if (mddev->persistent &&
mddev->major_version == 0)
- return -EINVAL;
-
- mddev->reshape_backwards = backwards;
- return len;
+ err = -EINVAL;
+ else
+ mddev->reshape_backwards = backwards;
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_reshape_direction =
@@ -4437,6 +4618,11 @@ static ssize_t
array_size_store(struct mddev *mddev, const char *buf, size_t len)
{
sector_t sectors;
+ int err;
+
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
if (strncmp(buf, "default", 7) == 0) {
if (mddev->pers)
@@ -4447,19 +4633,22 @@ array_size_store(struct mddev *mddev, const char *buf, size_t len)
mddev->external_size = 0;
} else {
if (strict_blocks_to_sectors(buf, &sectors) < 0)
- return -EINVAL;
- if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors)
- return -E2BIG;
-
- mddev->external_size = 1;
+ err = -EINVAL;
+ else if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors)
+ err = -E2BIG;
+ else
+ mddev->external_size = 1;
}
- mddev->array_sectors = sectors;
- if (mddev->pers) {
- set_capacity(mddev->gendisk, mddev->array_sectors);
- revalidate_disk(mddev->gendisk);
+ if (!err) {
+ mddev->array_sectors = sectors;
+ if (mddev->pers) {
+ set_capacity(mddev->gendisk, mddev->array_sectors);
+ revalidate_disk(mddev->gendisk);
+ }
}
- return len;
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry md_array_size =
@@ -4523,11 +4712,7 @@ md_attr_show(struct kobject *kobj, struct attribute *attr, char *page)
mddev_get(mddev);
spin_unlock(&all_mddevs_lock);
- rv = mddev_lock(mddev);
- if (!rv) {
- rv = entry->show(mddev, page);
- mddev_unlock(mddev);
- }
+ rv = entry->show(mddev, page);
mddev_put(mddev);
return rv;
}
@@ -4551,13 +4736,7 @@ md_attr_store(struct kobject *kobj, struct attribute *attr,
}
mddev_get(mddev);
spin_unlock(&all_mddevs_lock);
- if (entry->store == new_dev_store)
- flush_workqueue(md_misc_wq);
- rv = mddev_lock(mddev);
- if (!rv) {
- rv = entry->store(mddev, page, length);
- mddev_unlock(mddev);
- }
+ rv = entry->store(mddev, page, length);
mddev_put(mddev);
return rv;
}
@@ -4825,7 +5004,6 @@ int md_run(struct mddev *mddev)
mddev->clevel);
return -EINVAL;
}
- mddev->pers = pers;
spin_unlock(&pers_lock);
if (mddev->level != pers->level) {
mddev->level = pers->level;
@@ -4836,7 +5014,6 @@ int md_run(struct mddev *mddev)
if (mddev->reshape_position != MaxSector &&
pers->start_reshape == NULL) {
/* This personality cannot handle reshaping... */
- mddev->pers = NULL;
module_put(pers->owner);
return -EINVAL;
}
@@ -4880,35 +5057,38 @@ int md_run(struct mddev *mddev)
if (start_readonly && mddev->ro == 0)
mddev->ro = 2; /* read-only, but switch on first write */
- err = mddev->pers->run(mddev);
+ err = pers->run(mddev);
if (err)
printk(KERN_ERR "md: pers->run() failed ...\n");
- else if (mddev->pers->size(mddev, 0, 0) < mddev->array_sectors) {
+ else if (pers->size(mddev, 0, 0) < mddev->array_sectors) {
WARN_ONCE(!mddev->external_size, "%s: default size too small,"
" but 'external_size' not in effect?\n", __func__);
printk(KERN_ERR
"md: invalid array_size %llu > default size %llu\n",
(unsigned long long)mddev->array_sectors / 2,
- (unsigned long long)mddev->pers->size(mddev, 0, 0) / 2);
+ (unsigned long long)pers->size(mddev, 0, 0) / 2);
err = -EINVAL;
- mddev->pers->stop(mddev);
}
- if (err == 0 && mddev->pers->sync_request &&
+ if (err == 0 && pers->sync_request &&
(mddev->bitmap_info.file || mddev->bitmap_info.offset)) {
err = bitmap_create(mddev);
- if (err) {
+ if (err)
printk(KERN_ERR "%s: failed to create bitmap (%d)\n",
mdname(mddev), err);
- mddev->pers->stop(mddev);
- }
}
if (err) {
- module_put(mddev->pers->owner);
- mddev->pers = NULL;
+ mddev_detach(mddev);
+ pers->free(mddev, mddev->private);
+ module_put(pers->owner);
bitmap_destroy(mddev);
return err;
}
- if (mddev->pers->sync_request) {
+ if (mddev->queue) {
+ mddev->queue->backing_dev_info.congested_data = mddev;
+ mddev->queue->backing_dev_info.congested_fn = md_congested;
+ blk_queue_merge_bvec(mddev->queue, md_mergeable_bvec);
+ }
+ if (pers->sync_request) {
if (mddev->kobj.sd &&
sysfs_create_group(&mddev->kobj, &md_redundancy_group))
printk(KERN_WARNING
@@ -4927,7 +5107,10 @@ int md_run(struct mddev *mddev)
mddev->safemode_delay = (200 * HZ)/1000 +1; /* 200 msec delay */
mddev->in_sync = 1;
smp_wmb();
+ spin_lock(&mddev->lock);
+ mddev->pers = pers;
mddev->ready = 1;
+ spin_unlock(&mddev->lock);
rdev_for_each(rdev, mddev)
if (rdev->raid_disk >= 0)
if (sysfs_link_rdev(mddev, rdev))
@@ -5070,14 +5253,38 @@ void md_stop_writes(struct mddev *mddev)
}
EXPORT_SYMBOL_GPL(md_stop_writes);
+static void mddev_detach(struct mddev *mddev)
+{
+ struct bitmap *bitmap = mddev->bitmap;
+ /* wait for behind writes to complete */
+ if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
+ printk(KERN_INFO "md:%s: behind writes in progress - waiting to stop.\n",
+ mdname(mddev));
+ /* need to kick something here to make sure I/O goes? */
+ wait_event(bitmap->behind_wait,
+ atomic_read(&bitmap->behind_writes) == 0);
+ }
+ if (mddev->pers && mddev->pers->quiesce) {
+ mddev->pers->quiesce(mddev, 1);
+ mddev->pers->quiesce(mddev, 0);
+ }
+ md_unregister_thread(&mddev->thread);
+ if (mddev->queue)
+ blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
+}
+
static void __md_stop(struct mddev *mddev)
{
+ struct md_personality *pers = mddev->pers;
+ mddev_detach(mddev);
+ spin_lock(&mddev->lock);
mddev->ready = 0;
- mddev->pers->stop(mddev);
- if (mddev->pers->sync_request && mddev->to_remove == NULL)
- mddev->to_remove = &md_redundancy_group;
- module_put(mddev->pers->owner);
mddev->pers = NULL;
+ spin_unlock(&mddev->lock);
+ pers->free(mddev, mddev->private);
+ if (pers->sync_request && mddev->to_remove == NULL)
+ mddev->to_remove = &md_redundancy_group;
+ module_put(pers->owner);
clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery);
}
@@ -5226,8 +5433,11 @@ static int do_md_stop(struct mddev *mddev, int mode,
bitmap_destroy(mddev);
if (mddev->bitmap_info.file) {
- fput(mddev->bitmap_info.file);
+ struct file *f = mddev->bitmap_info.file;
+ spin_lock(&mddev->lock);
mddev->bitmap_info.file = NULL;
+ spin_unlock(&mddev->lock);
+ fput(f);
}
mddev->bitmap_info.offset = 0;
@@ -5436,37 +5646,31 @@ static int get_array_info(struct mddev *mddev, void __user *arg)
static int get_bitmap_file(struct mddev *mddev, void __user * arg)
{
mdu_bitmap_file_t *file = NULL; /* too big for stack allocation */
- char *ptr, *buf = NULL;
- int err = -ENOMEM;
+ char *ptr;
+ int err;
file = kmalloc(sizeof(*file), GFP_NOIO);
-
if (!file)
- goto out;
+ return -ENOMEM;
+ err = 0;
+ spin_lock(&mddev->lock);
/* bitmap disabled, zero the first byte and copy out */
- if (!mddev->bitmap || !mddev->bitmap->storage.file) {
+ if (!mddev->bitmap_info.file)
file->pathname[0] = '\0';
- goto copy_out;
- }
-
- buf = kmalloc(sizeof(file->pathname), GFP_KERNEL);
- if (!buf)
- goto out;
-
- ptr = d_path(&mddev->bitmap->storage.file->f_path,
- buf, sizeof(file->pathname));
- if (IS_ERR(ptr))
- goto out;
-
- strcpy(file->pathname, ptr);
+ else if ((ptr = d_path(&mddev->bitmap_info.file->f_path,
+ file->pathname, sizeof(file->pathname))),
+ IS_ERR(ptr))
+ err = PTR_ERR(ptr);
+ else
+ memmove(file->pathname, ptr,
+ sizeof(file->pathname)-(ptr-file->pathname));
+ spin_unlock(&mddev->lock);
-copy_out:
- err = 0;
- if (copy_to_user(arg, file, sizeof(*file)))
+ if (err == 0 &&
+ copy_to_user(arg, file, sizeof(*file)))
err = -EFAULT;
-out:
- kfree(buf);
+
kfree(file);
return err;
}
@@ -5789,22 +5993,24 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
if (fd >= 0) {
struct inode *inode;
- if (mddev->bitmap)
+ struct file *f;
+
+ if (mddev->bitmap || mddev->bitmap_info.file)
return -EEXIST; /* cannot add when bitmap is present */
- mddev->bitmap_info.file = fget(fd);
+ f = fget(fd);
- if (mddev->bitmap_info.file == NULL) {
+ if (f == NULL) {
printk(KERN_ERR "%s: error: failed to get bitmap file\n",
mdname(mddev));
return -EBADF;
}
- inode = mddev->bitmap_info.file->f_mapping->host;
+ inode = f->f_mapping->host;
if (!S_ISREG(inode->i_mode)) {
printk(KERN_ERR "%s: error: bitmap file must be a regular file\n",
mdname(mddev));
err = -EBADF;
- } else if (!(mddev->bitmap_info.file->f_mode & FMODE_WRITE)) {
+ } else if (!(f->f_mode & FMODE_WRITE)) {
printk(KERN_ERR "%s: error: bitmap file must open for write\n",
mdname(mddev));
err = -EBADF;
@@ -5814,10 +6020,10 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
err = -EBUSY;
}
if (err) {
- fput(mddev->bitmap_info.file);
- mddev->bitmap_info.file = NULL;
+ fput(f);
return err;
}
+ mddev->bitmap_info.file = f;
mddev->bitmap_info.offset = 0; /* file overrides offset */
} else if (mddev->bitmap == NULL)
return -ENOENT; /* cannot remove what isn't there */
@@ -5836,9 +6042,13 @@ static int set_bitmap_file(struct mddev *mddev, int fd)
mddev->pers->quiesce(mddev, 0);
}
if (fd < 0) {
- if (mddev->bitmap_info.file)
- fput(mddev->bitmap_info.file);
- mddev->bitmap_info.file = NULL;
+ struct file *f = mddev->bitmap_info.file;
+ if (f) {
+ spin_lock(&mddev->lock);
+ mddev->bitmap_info.file = NULL;
+ spin_unlock(&mddev->lock);
+ fput(f);
+ }
}
return err;
@@ -6251,6 +6461,11 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
case SET_DISK_FAULTY:
err = set_disk_faulty(mddev, new_decode_dev(arg));
goto out;
+
+ case GET_BITMAP_FILE:
+ err = get_bitmap_file(mddev, argp);
+ goto out;
+
}
if (cmd == ADD_NEW_DISK)
@@ -6342,10 +6557,6 @@ static int md_ioctl(struct block_device *bdev, fmode_t mode,
* Commands even a read-only array can execute:
*/
switch (cmd) {
- case GET_BITMAP_FILE:
- err = get_bitmap_file(mddev, argp);
- goto unlock;
-
case RESTART_ARRAY_RW:
err = restart_array(mddev);
goto unlock;
@@ -6873,9 +7084,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
return 0;
}
- if (mddev_lock(mddev) < 0)
- return -EINTR;
-
+ spin_lock(&mddev->lock);
if (mddev->pers || mddev->raid_disks || !list_empty(&mddev->disks)) {
seq_printf(seq, "%s : %sactive", mdname(mddev),
mddev->pers ? "" : "in");
@@ -6888,7 +7097,8 @@ static int md_seq_show(struct seq_file *seq, void *v)
}
sectors = 0;
- rdev_for_each(rdev, mddev) {
+ rcu_read_lock();
+ rdev_for_each_rcu(rdev, mddev) {
char b[BDEVNAME_SIZE];
seq_printf(seq, " %s[%d]",
bdevname(rdev->bdev,b), rdev->desc_nr);
@@ -6904,6 +7114,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "(R)");
sectors += rdev->sectors;
}
+ rcu_read_unlock();
if (!list_empty(&mddev->disks)) {
if (mddev->pers)
@@ -6946,7 +7157,7 @@ static int md_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "\n");
}
- mddev_unlock(mddev);
+ spin_unlock(&mddev->lock);
return 0;
}
@@ -7102,7 +7313,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)
if (mddev->safemode == 1)
mddev->safemode = 0;
if (mddev->in_sync) {
- spin_lock_irq(&mddev->write_lock);
+ spin_lock(&mddev->lock);
if (mddev->in_sync) {
mddev->in_sync = 0;
set_bit(MD_CHANGE_CLEAN, &mddev->flags);
@@ -7110,7 +7321,7 @@ void md_write_start(struct mddev *mddev, struct bio *bi)
md_wakeup_thread(mddev->thread);
did_change = 1;
}
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
}
if (did_change)
sysfs_notify_dirent_safe(mddev->sysfs_state);
@@ -7148,7 +7359,7 @@ int md_allow_write(struct mddev *mddev)
if (!mddev->pers->sync_request)
return 0;
- spin_lock_irq(&mddev->write_lock);
+ spin_lock(&mddev->lock);
if (mddev->in_sync) {
mddev->in_sync = 0;
set_bit(MD_CHANGE_CLEAN, &mddev->flags);
@@ -7156,11 +7367,11 @@ int md_allow_write(struct mddev *mddev)
if (mddev->safemode_delay &&
mddev->safemode == 0)
mddev->safemode = 1;
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
md_update_sb(mddev, 0);
sysfs_notify_dirent_safe(mddev->sysfs_state);
} else
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
if (test_bit(MD_CHANGE_PENDING, &mddev->flags))
return -EAGAIN;
@@ -7513,6 +7724,7 @@ void md_do_sync(struct md_thread *thread)
skip:
set_bit(MD_CHANGE_DEVS, &mddev->flags);
+ spin_lock(&mddev->lock);
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
/* We completed so min/max setting can be forgotten if used. */
if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
@@ -7521,6 +7733,8 @@ void md_do_sync(struct md_thread *thread)
} else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
mddev->resync_min = mddev->curr_resync_completed;
mddev->curr_resync = 0;
+ spin_unlock(&mddev->lock);
+
wake_up(&resync_wait);
set_bit(MD_RECOVERY_DONE, &mddev->recovery);
md_wakeup_thread(mddev->thread);
@@ -7688,7 +7902,7 @@ void md_check_recovery(struct mddev *mddev)
if (!mddev->external) {
int did_change = 0;
- spin_lock_irq(&mddev->write_lock);
+ spin_lock(&mddev->lock);
if (mddev->safemode &&
!atomic_read(&mddev->writes_pending) &&
!mddev->in_sync &&
@@ -7699,7 +7913,7 @@ void md_check_recovery(struct mddev *mddev)
}
if (mddev->safemode == 1)
mddev->safemode = 0;
- spin_unlock_irq(&mddev->write_lock);
+ spin_unlock(&mddev->lock);
if (did_change)
sysfs_notify_dirent_safe(mddev->sysfs_state);
}
@@ -7721,7 +7935,9 @@ void md_check_recovery(struct mddev *mddev)
* any transients in the value of "sync_action".
*/
mddev->curr_resync_completed = 0;
+ spin_lock(&mddev->lock);
set_bit(MD_RECOVERY_RUNNING, &mddev->recovery);
+ spin_unlock(&mddev->lock);
/* Clear some bits that don't mean anything, but
* might be left set
*/
diff --git a/drivers/md/md.h b/drivers/md/md.h
index 03cec5bdcaae..318ca8fd430f 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -386,7 +386,18 @@ struct mddev {
struct work_struct del_work; /* used for delayed sysfs removal */
- spinlock_t write_lock;
+ /* "lock" protects:
+ * flush_bio transition from NULL to !NULL
+ * rdev superblocks, events
+ * clearing MD_CHANGE_*
+ * in_sync - and related safemode and MD_CHANGE changes
+ * pers (also protected by reconfig_mutex and pending IO).
+ * clearing ->bitmap
+ * clearing ->bitmap_info.file
+ * changing ->resync_{min,max}
+ * setting MD_RECOVERY_RUNNING (which interacts with resync_{min,max})
+ */
+ spinlock_t lock;
wait_queue_head_t sb_wait; /* for waiting on superblock updates */
atomic_t pending_writes; /* number of active superblock writes */
@@ -439,13 +450,30 @@ struct mddev {
void (*sync_super)(struct mddev *mddev, struct md_rdev *rdev);
};
-static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)
+static inline int __must_check mddev_lock(struct mddev *mddev)
{
- int faulty = test_bit(Faulty, &rdev->flags);
- if (atomic_dec_and_test(&rdev->nr_pending) && faulty)
- set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ return mutex_lock_interruptible(&mddev->reconfig_mutex);
+}
+
+/* Sometimes we need to take the lock in a situation where
+ * failure due to interrupts is not acceptable.
+ */
+static inline void mddev_lock_nointr(struct mddev *mddev)
+{
+ mutex_lock(&mddev->reconfig_mutex);
+}
+
+static inline int mddev_is_locked(struct mddev *mddev)
+{
+ return mutex_is_locked(&mddev->reconfig_mutex);
}
+static inline int mddev_trylock(struct mddev *mddev)
+{
+ return mutex_trylock(&mddev->reconfig_mutex);
+}
+extern void mddev_unlock(struct mddev *mddev);
+
static inline void md_sync_acct(struct block_device *bdev, unsigned long nr_sectors)
{
atomic_add(nr_sectors, &bdev->bd_contains->bd_disk->sync_io);
@@ -459,7 +487,7 @@ struct md_personality
struct module *owner;
void (*make_request)(struct mddev *mddev, struct bio *bio);
int (*run)(struct mddev *mddev);
- int (*stop)(struct mddev *mddev);
+ void (*free)(struct mddev *mddev, void *priv);
void (*status)(struct seq_file *seq, struct mddev *mddev);
/* error_handler must set ->faulty and clear ->in_sync
* if appropriate, and should abort recovery if needed
@@ -490,6 +518,13 @@ struct md_personality
* array.
*/
void *(*takeover) (struct mddev *mddev);
+ /* congested implements bdi.congested_fn().
+ * Will not be called while array is 'suspended' */
+ int (*congested)(struct mddev *mddev, int bits);
+ /* mergeable_bvec is use to implement ->merge_bvec_fn */
+ int (*mergeable_bvec)(struct mddev *mddev,
+ struct bvec_merge_data *bvm,
+ struct bio_vec *biovec);
};
struct md_sysfs_entry {
@@ -624,4 +659,14 @@ static inline int mddev_check_plugged(struct mddev *mddev)
return !!blk_check_plugged(md_unplug, mddev,
sizeof(struct blk_plug_cb));
}
+
+static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)
+{
+ int faulty = test_bit(Faulty, &rdev->flags);
+ if (atomic_dec_and_test(&rdev->nr_pending) && faulty) {
+ set_bit(MD_RECOVERY_NEEDED, &mddev->recovery);
+ md_wakeup_thread(mddev->thread);
+ }
+}
+
#endif /* _MD_MD_H */
diff --git a/drivers/md/multipath.c b/drivers/md/multipath.c
index 399272f9c042..ac3ede2bd00e 100644
--- a/drivers/md/multipath.c
+++ b/drivers/md/multipath.c
@@ -153,15 +153,11 @@ static void multipath_status (struct seq_file *seq, struct mddev *mddev)
seq_printf (seq, "]");
}
-static int multipath_congested(void *data, int bits)
+static int multipath_congested(struct mddev *mddev, int bits)
{
- struct mddev *mddev = data;
struct mpconf *conf = mddev->private;
int i, ret = 0;
- if (mddev_congested(mddev, bits))
- return 1;
-
rcu_read_lock();
for (i = 0; i < mddev->raid_disks ; i++) {
struct md_rdev *rdev = rcu_dereference(conf->multipaths[i].rdev);
@@ -403,7 +399,7 @@ static int multipath_run (struct mddev *mddev)
/*
* copy the already verified devices into our private MULTIPATH
* bookkeeping area. [whatever we allocate in multipath_run(),
- * should be freed in multipath_stop()]
+ * should be freed in multipath_free()]
*/
conf = kzalloc(sizeof(struct mpconf), GFP_KERNEL);
@@ -489,9 +485,6 @@ static int multipath_run (struct mddev *mddev)
*/
md_set_array_sectors(mddev, multipath_size(mddev, 0, 0));
- mddev->queue->backing_dev_info.congested_fn = multipath_congested;
- mddev->queue->backing_dev_info.congested_data = mddev;
-
if (md_integrity_register(mddev))
goto out_free_conf;
@@ -507,17 +500,13 @@ out:
return -EIO;
}
-static int multipath_stop (struct mddev *mddev)
+static void multipath_free(struct mddev *mddev, void *priv)
{
- struct mpconf *conf = mddev->private;
+ struct mpconf *conf = priv;
- md_unregister_thread(&mddev->thread);
- blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
mempool_destroy(conf->pool);
kfree(conf->multipaths);
kfree(conf);
- mddev->private = NULL;
- return 0;
}
static struct md_personality multipath_personality =
@@ -527,12 +516,13 @@ static struct md_personality multipath_personality =
.owner = THIS_MODULE,
.make_request = multipath_make_request,
.run = multipath_run,
- .stop = multipath_stop,
+ .free = multipath_free,
.status = multipath_status,
.error_handler = multipath_error,
.hot_add_disk = multipath_add_disk,
.hot_remove_disk= multipath_remove_disk,
.size = multipath_size,
+ .congested = multipath_congested,
};
static int __init multipath_init (void)
diff --git a/drivers/md/persistent-data/Kconfig b/drivers/md/persistent-data/Kconfig
index 0c2dec7aec20..78c74bb71ba4 100644
--- a/drivers/md/persistent-data/Kconfig
+++ b/drivers/md/persistent-data/Kconfig
@@ -8,7 +8,7 @@ config DM_PERSISTENT_DATA
device-mapper targets such as the thin provisioning target.
config DM_DEBUG_BLOCK_STACK_TRACING
- boolean "Keep stack trace of persistent data block lock holders"
+ bool "Keep stack trace of persistent data block lock holders"
depends on STACKTRACE_SUPPORT && DM_PERSISTENT_DATA
select STACKTRACE
---help---
diff --git a/drivers/md/persistent-data/dm-space-map-disk.c b/drivers/md/persistent-data/dm-space-map-disk.c
index cfbf9617e465..ebb280a14325 100644
--- a/drivers/md/persistent-data/dm-space-map-disk.c
+++ b/drivers/md/persistent-data/dm-space-map-disk.c
@@ -78,7 +78,9 @@ static int sm_disk_count_is_more_than_one(struct dm_space_map *sm, dm_block_t b,
if (r)
return r;
- return count > 1;
+ *result = count > 1;
+
+ return 0;
}
static int sm_disk_set_count(struct dm_space_map *sm, dm_block_t b,
diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index ba6b85de96d2..a13f738a7b39 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -25,17 +25,13 @@
#include "raid0.h"
#include "raid5.h"
-static int raid0_congested(void *data, int bits)
+static int raid0_congested(struct mddev *mddev, int bits)
{
- struct mddev *mddev = data;
struct r0conf *conf = mddev->private;
struct md_rdev **devlist = conf->devlist;
int raid_disks = conf->strip_zone[0].nb_dev;
int i, ret = 0;
- if (mddev_congested(mddev, bits))
- return 1;
-
for (i = 0; i < raid_disks && !ret ; i++) {
struct request_queue *q = bdev_get_queue(devlist[i]->bdev);
@@ -263,8 +259,6 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
mdname(mddev),
(unsigned long long)smallest->sectors);
}
- mddev->queue->backing_dev_info.congested_fn = raid0_congested;
- mddev->queue->backing_dev_info.congested_data = mddev;
/*
* now since we have the hard sector sizes, we can make sure
@@ -356,17 +350,16 @@ static struct md_rdev *map_sector(struct mddev *mddev, struct strip_zone *zone,
/**
* raid0_mergeable_bvec -- tell bio layer if two requests can be merged
- * @q: request queue
+ * @mddev: the md device
* @bvm: properties of new bio
* @biovec: the request that could be merged to it.
*
* Return amount of bytes we can accept at this offset
*/
-static int raid0_mergeable_bvec(struct request_queue *q,
+static int raid0_mergeable_bvec(struct mddev *mddev,
struct bvec_merge_data *bvm,
struct bio_vec *biovec)
{
- struct mddev *mddev = q->queuedata;
struct r0conf *conf = mddev->private;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
sector_t sector_offset = sector;
@@ -422,7 +415,7 @@ static sector_t raid0_size(struct mddev *mddev, sector_t sectors, int raid_disks
return array_sectors;
}
-static int raid0_stop(struct mddev *mddev);
+static void raid0_free(struct mddev *mddev, void *priv);
static int raid0_run(struct mddev *mddev)
{
@@ -471,26 +464,22 @@ static int raid0_run(struct mddev *mddev)
mddev->queue->backing_dev_info.ra_pages = 2* stripe;
}
- blk_queue_merge_bvec(mddev->queue, raid0_mergeable_bvec);
dump_zones(mddev);
ret = md_integrity_register(mddev);
if (ret)
- raid0_stop(mddev);
+ raid0_free(mddev, conf);
return ret;
}
-static int raid0_stop(struct mddev *mddev)
+static void raid0_free(struct mddev *mddev, void *priv)
{
- struct r0conf *conf = mddev->private;
+ struct r0conf *conf = priv;
- blk_sync_queue(mddev->queue); /* the unplug fn references 'conf'*/
kfree(conf->strip_zone);
kfree(conf->devlist);
kfree(conf);
- mddev->private = NULL;
- return 0;
}
/*
@@ -724,11 +713,13 @@ static struct md_personality raid0_personality=
.owner = THIS_MODULE,
.make_request = raid0_make_request,
.run = raid0_run,
- .stop = raid0_stop,
+ .free = raid0_free,
.status = raid0_status,
.size = raid0_size,
.takeover = raid0_takeover,
.quiesce = raid0_quiesce,
+ .congested = raid0_congested,
+ .mergeable_bvec = raid0_mergeable_bvec,
};
static int __init raid0_init (void)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 40b35be34f8d..4153da5d4011 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -701,11 +701,10 @@ static int read_balance(struct r1conf *conf, struct r1bio *r1_bio, int *max_sect
return best_disk;
}
-static int raid1_mergeable_bvec(struct request_queue *q,
+static int raid1_mergeable_bvec(struct mddev *mddev,
struct bvec_merge_data *bvm,
struct bio_vec *biovec)
{
- struct mddev *mddev = q->queuedata;
struct r1conf *conf = mddev->private;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
int max = biovec->bv_len;
@@ -734,7 +733,7 @@ static int raid1_mergeable_bvec(struct request_queue *q,
}
-int md_raid1_congested(struct mddev *mddev, int bits)
+static int raid1_congested(struct mddev *mddev, int bits)
{
struct r1conf *conf = mddev->private;
int i, ret = 0;
@@ -763,15 +762,6 @@ int md_raid1_congested(struct mddev *mddev, int bits)
rcu_read_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(md_raid1_congested);
-
-static int raid1_congested(void *data, int bits)
-{
- struct mddev *mddev = data;
-
- return mddev_congested(mddev, bits) ||
- md_raid1_congested(mddev, bits);
-}
static void flush_pending_writes(struct r1conf *conf)
{
@@ -2206,7 +2196,8 @@ static int narrow_write_error(struct r1bio *r1_bio, int i)
if (rdev->badblocks.shift < 0)
return 0;
- block_sectors = 1 << rdev->badblocks.shift;
+ block_sectors = roundup(1 << rdev->badblocks.shift,
+ bdev_logical_block_size(rdev->bdev) >> 9);
sector = r1_bio->sector;
sectors = ((sector + block_sectors)
& ~(sector_t)(block_sectors - 1))
@@ -2882,7 +2873,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
return ERR_PTR(err);
}
-static int stop(struct mddev *mddev);
+static void raid1_free(struct mddev *mddev, void *priv);
static int run(struct mddev *mddev)
{
struct r1conf *conf;
@@ -2904,7 +2895,7 @@ static int run(struct mddev *mddev)
/*
* copy the already verified devices into our private RAID1
* bookkeeping area. [whatever we allocate in run(),
- * should be freed in stop()]
+ * should be freed in raid1_free()]
*/
if (mddev->private == NULL)
conf = setup_conf(mddev);
@@ -2955,10 +2946,6 @@ static int run(struct mddev *mddev)
md_set_array_sectors(mddev, raid1_size(mddev, 0, 0));
if (mddev->queue) {
- mddev->queue->backing_dev_info.congested_fn = raid1_congested;
- mddev->queue->backing_dev_info.congested_data = mddev;
- blk_queue_merge_bvec(mddev->queue, raid1_mergeable_bvec);
-
if (discard_supported)
queue_flag_set_unlocked(QUEUE_FLAG_DISCARD,
mddev->queue);
@@ -2968,37 +2955,23 @@ static int run(struct mddev *mddev)
}
ret = md_integrity_register(mddev);
- if (ret)
- stop(mddev);
+ if (ret) {
+ md_unregister_thread(&mddev->thread);
+ raid1_free(mddev, conf);
+ }
return ret;
}
-static int stop(struct mddev *mddev)
+static void raid1_free(struct mddev *mddev, void *priv)
{
- struct r1conf *conf = mddev->private;
- struct bitmap *bitmap = mddev->bitmap;
+ struct r1conf *conf = priv;
- /* wait for behind writes to complete */
- if (bitmap && atomic_read(&bitmap->behind_writes) > 0) {
- printk(KERN_INFO "md/raid1:%s: behind writes in progress - waiting to stop.\n",
- mdname(mddev));
- /* need to kick something here to make sure I/O goes? */
- wait_event(bitmap->behind_wait,
- atomic_read(&bitmap->behind_writes) == 0);
- }
-
- freeze_array(conf, 0);
- unfreeze_array(conf);
-
- md_unregister_thread(&mddev->thread);
if (conf->r1bio_pool)
mempool_destroy(conf->r1bio_pool);
kfree(conf->mirrors);
safe_put_page(conf->tmppage);
kfree(conf->poolinfo);
kfree(conf);
- mddev->private = NULL;
- return 0;
}
static int raid1_resize(struct mddev *mddev, sector_t sectors)
@@ -3181,7 +3154,7 @@ static struct md_personality raid1_personality =
.owner = THIS_MODULE,
.make_request = make_request,
.run = run,
- .stop = stop,
+ .free = raid1_free,
.status = status,
.error_handler = error,
.hot_add_disk = raid1_add_disk,
@@ -3193,6 +3166,8 @@ static struct md_personality raid1_personality =
.check_reshape = raid1_reshape,
.quiesce = raid1_quiesce,
.takeover = raid1_takeover,
+ .congested = raid1_congested,
+ .mergeable_bvec = raid1_mergeable_bvec,
};
static int __init raid_init(void)
diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
index 33bda55ef9f7..14ebb288c1ef 100644
--- a/drivers/md/raid1.h
+++ b/drivers/md/raid1.h
@@ -170,7 +170,4 @@ struct r1bio {
*/
#define R1BIO_MadeGood 7
#define R1BIO_WriteError 8
-
-extern int md_raid1_congested(struct mddev *mddev, int bits);
-
#endif
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 32e282f4c83c..a7196c49d15d 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -674,7 +674,7 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
/**
* raid10_mergeable_bvec -- tell bio layer if a two requests can be merged
- * @q: request queue
+ * @mddev: the md device
* @bvm: properties of new bio
* @biovec: the request that could be merged to it.
*
@@ -682,11 +682,10 @@ static sector_t raid10_find_virt(struct r10conf *conf, sector_t sector, int dev)
* This requires checking for end-of-chunk if near_copies != raid_disks,
* and for subordinate merge_bvec_fns if merge_check_needed.
*/
-static int raid10_mergeable_bvec(struct request_queue *q,
+static int raid10_mergeable_bvec(struct mddev *mddev,
struct bvec_merge_data *bvm,
struct bio_vec *biovec)
{
- struct mddev *mddev = q->queuedata;
struct r10conf *conf = mddev->private;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
int max;
@@ -910,7 +909,7 @@ retry:
return rdev;
}
-int md_raid10_congested(struct mddev *mddev, int bits)
+static int raid10_congested(struct mddev *mddev, int bits)
{
struct r10conf *conf = mddev->private;
int i, ret = 0;
@@ -934,15 +933,6 @@ int md_raid10_congested(struct mddev *mddev, int bits)
rcu_read_unlock();
return ret;
}
-EXPORT_SYMBOL_GPL(md_raid10_congested);
-
-static int raid10_congested(void *data, int bits)
-{
- struct mddev *mddev = data;
-
- return mddev_congested(mddev, bits) ||
- md_raid10_congested(mddev, bits);
-}
static void flush_pending_writes(struct r10conf *conf)
{
@@ -2582,7 +2572,8 @@ static int narrow_write_error(struct r10bio *r10_bio, int i)
if (rdev->badblocks.shift < 0)
return 0;
- block_sectors = 1 << rdev->badblocks.shift;
+ block_sectors = roundup(1 << rdev->badblocks.shift,
+ bdev_logical_block_size(rdev->bdev) >> 9);
sector = r10_bio->sector;
sectors = ((r10_bio->sector + block_sectors)
& ~(sector_t)(block_sectors - 1))
@@ -3757,8 +3748,6 @@ static int run(struct mddev *mddev)
if (mddev->queue) {
int stripe = conf->geo.raid_disks *
((mddev->chunk_sectors << 9) / PAGE_SIZE);
- mddev->queue->backing_dev_info.congested_fn = raid10_congested;
- mddev->queue->backing_dev_info.congested_data = mddev;
/* Calculate max read-ahead size.
* We need to readahead at least twice a whole stripe....
@@ -3767,7 +3756,6 @@ static int run(struct mddev *mddev)
stripe /= conf->geo.near_copies;
if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
- blk_queue_merge_bvec(mddev->queue, raid10_mergeable_bvec);
}
if (md_integrity_register(mddev))
@@ -3811,17 +3799,9 @@ out:
return -EIO;
}
-static int stop(struct mddev *mddev)
+static void raid10_free(struct mddev *mddev, void *priv)
{
- struct r10conf *conf = mddev->private;
-
- raise_barrier(conf, 0);
- lower_barrier(conf);
-
- md_unregister_thread(&mddev->thread);
- if (mddev->queue)
- /* the unplug fn references 'conf'*/
- blk_sync_queue(mddev->queue);
+ struct r10conf *conf = priv;
if (conf->r10bio_pool)
mempool_destroy(conf->r10bio_pool);
@@ -3830,8 +3810,6 @@ static int stop(struct mddev *mddev)
kfree(conf->mirrors_old);
kfree(conf->mirrors_new);
kfree(conf);
- mddev->private = NULL;
- return 0;
}
static void raid10_quiesce(struct mddev *mddev, int state)
@@ -3895,7 +3873,7 @@ static int raid10_resize(struct mddev *mddev, sector_t sectors)
return 0;
}
-static void *raid10_takeover_raid0(struct mddev *mddev)
+static void *raid10_takeover_raid0(struct mddev *mddev, sector_t size, int devs)
{
struct md_rdev *rdev;
struct r10conf *conf;
@@ -3905,6 +3883,7 @@ static void *raid10_takeover_raid0(struct mddev *mddev)
mdname(mddev));
return ERR_PTR(-EINVAL);
}
+ sector_div(size, devs);
/* Set new parameters */
mddev->new_level = 10;
@@ -3915,12 +3894,15 @@ static void *raid10_takeover_raid0(struct mddev *mddev)
mddev->raid_disks *= 2;
/* make sure it will be not marked as dirty */
mddev->recovery_cp = MaxSector;
+ mddev->dev_sectors = size;
conf = setup_conf(mddev);
if (!IS_ERR(conf)) {
rdev_for_each(rdev, mddev)
- if (rdev->raid_disk >= 0)
+ if (rdev->raid_disk >= 0) {
rdev->new_raid_disk = rdev->raid_disk * 2;
+ rdev->sectors = size;
+ }
conf->barrier = 1;
}
@@ -3943,7 +3925,9 @@ static void *raid10_takeover(struct mddev *mddev)
mdname(mddev));
return ERR_PTR(-EINVAL);
}
- return raid10_takeover_raid0(mddev);
+ return raid10_takeover_raid0(mddev,
+ raid0_conf->strip_zone->zone_end,
+ raid0_conf->strip_zone->nb_dev);
}
return ERR_PTR(-EINVAL);
}
@@ -4713,7 +4697,7 @@ static struct md_personality raid10_personality =
.owner = THIS_MODULE,
.make_request = make_request,
.run = run,
- .stop = stop,
+ .free = raid10_free,
.status = status,
.error_handler = error,
.hot_add_disk = raid10_add_disk,
@@ -4727,6 +4711,8 @@ static struct md_personality raid10_personality =
.check_reshape = raid10_check_reshape,
.start_reshape = raid10_start_reshape,
.finish_reshape = raid10_finish_reshape,
+ .congested = raid10_congested,
+ .mergeable_bvec = raid10_mergeable_bvec,
};
static int __init raid_init(void)
diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
index 157d69e83ff4..5ee6473ddc2c 100644
--- a/drivers/md/raid10.h
+++ b/drivers/md/raid10.h
@@ -150,7 +150,4 @@ enum r10bio_state {
*/
R10BIO_Previous,
};
-
-extern int md_raid10_congested(struct mddev *mddev, int bits);
-
#endif
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index c1b0d52bfcb0..e75d48c0421a 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -296,12 +296,9 @@ static void do_release_stripe(struct r5conf *conf, struct stripe_head *sh,
BUG_ON(atomic_read(&conf->active_stripes)==0);
if (test_bit(STRIPE_HANDLE, &sh->state)) {
if (test_bit(STRIPE_DELAYED, &sh->state) &&
- !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) {
+ !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
list_add_tail(&sh->lru, &conf->delayed_list);
- if (atomic_read(&conf->preread_active_stripes)
- < IO_THRESHOLD)
- md_wakeup_thread(conf->mddev->thread);
- } else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
+ else if (test_bit(STRIPE_BIT_DELAY, &sh->state) &&
sh->bm_seq - conf->seq_write > 0)
list_add_tail(&sh->lru, &conf->bitmap_list);
else {
@@ -2898,31 +2895,102 @@ static int want_replace(struct stripe_head *sh, int disk_idx)
* Returns 1 when no more member devices need to be checked, otherwise returns
* 0 to tell the loop in handle_stripe_fill to continue
*/
-static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
- int disk_idx, int disks)
+
+static int need_this_block(struct stripe_head *sh, struct stripe_head_state *s,
+ int disk_idx, int disks)
{
struct r5dev *dev = &sh->dev[disk_idx];
struct r5dev *fdev[2] = { &sh->dev[s->failed_num[0]],
&sh->dev[s->failed_num[1]] };
+ int i;
+
+
+ if (test_bit(R5_LOCKED, &dev->flags) ||
+ test_bit(R5_UPTODATE, &dev->flags))
+ /* No point reading this as we already have it or have
+ * decided to get it.
+ */
+ return 0;
+
+ if (dev->toread ||
+ (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)))
+ /* We need this block to directly satisfy a request */
+ return 1;
+
+ if (s->syncing || s->expanding ||
+ (s->replacing && want_replace(sh, disk_idx)))
+ /* When syncing, or expanding we read everything.
+ * When replacing, we need the replaced block.
+ */
+ return 1;
+
+ if ((s->failed >= 1 && fdev[0]->toread) ||
+ (s->failed >= 2 && fdev[1]->toread))
+ /* If we want to read from a failed device, then
+ * we need to actually read every other device.
+ */
+ return 1;
+
+ /* Sometimes neither read-modify-write nor reconstruct-write
+ * cycles can work. In those cases we read every block we
+ * can. Then the parity-update is certain to have enough to
+ * work with.
+ * This can only be a problem when we need to write something,
+ * and some device has failed. If either of those tests
+ * fail we need look no further.
+ */
+ if (!s->failed || !s->to_write)
+ return 0;
+
+ if (test_bit(R5_Insync, &dev->flags) &&
+ !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+ /* Pre-reads at not permitted until after short delay
+ * to gather multiple requests. However if this
+ * device is no Insync, the block could only be be computed
+ * and there is no need to delay that.
+ */
+ return 0;
+
+ for (i = 0; i < s->failed; i++) {
+ if (fdev[i]->towrite &&
+ !test_bit(R5_UPTODATE, &fdev[i]->flags) &&
+ !test_bit(R5_OVERWRITE, &fdev[i]->flags))
+ /* If we have a partial write to a failed
+ * device, then we will need to reconstruct
+ * the content of that device, so all other
+ * devices must be read.
+ */
+ return 1;
+ }
+
+ /* If we are forced to do a reconstruct-write, either because
+ * the current RAID6 implementation only supports that, or
+ * or because parity cannot be trusted and we are currently
+ * recovering it, there is extra need to be careful.
+ * If one of the devices that we would need to read, because
+ * it is not being overwritten (and maybe not written at all)
+ * is missing/faulty, then we need to read everything we can.
+ */
+ if (sh->raid_conf->level != 6 &&
+ sh->sector < sh->raid_conf->mddev->recovery_cp)
+ /* reconstruct-write isn't being forced */
+ return 0;
+ for (i = 0; i < s->failed; i++) {
+ if (!test_bit(R5_UPTODATE, &fdev[i]->flags) &&
+ !test_bit(R5_OVERWRITE, &fdev[i]->flags))
+ return 1;
+ }
+
+ return 0;
+}
+
+static int fetch_block(struct stripe_head *sh, struct stripe_head_state *s,
+ int disk_idx, int disks)
+{
+ struct r5dev *dev = &sh->dev[disk_idx];
/* is the data in this block needed, and can we get it? */
- if (!test_bit(R5_LOCKED, &dev->flags) &&
- !test_bit(R5_UPTODATE, &dev->flags) &&
- (dev->toread ||
- (dev->towrite && !test_bit(R5_OVERWRITE, &dev->flags)) ||
- s->syncing || s->expanding ||
- (s->replacing && want_replace(sh, disk_idx)) ||
- (s->failed >= 1 && fdev[0]->toread) ||
- (s->failed >= 2 && fdev[1]->toread) ||
- (sh->raid_conf->level <= 5 && s->failed && fdev[0]->towrite &&
- (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state)) &&
- !test_bit(R5_OVERWRITE, &fdev[0]->flags)) ||
- ((sh->raid_conf->level == 6 ||
- sh->sector >= sh->raid_conf->mddev->recovery_cp)
- && s->failed && s->to_write &&
- (s->to_write - s->non_overwrite <
- sh->raid_conf->raid_disks - sh->raid_conf->max_degraded) &&
- (!test_bit(R5_Insync, &dev->flags) || test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))))) {
+ if (need_this_block(sh, s, disk_idx, disks)) {
/* we would like to get this block, possibly by computing it,
* otherwise read it if the backing disk is insync
*/
@@ -3102,7 +3170,8 @@ static void handle_stripe_dirtying(struct r5conf *conf,
* generate correct data from the parity.
*/
if (conf->max_degraded == 2 ||
- (recovery_cp < MaxSector && sh->sector >= recovery_cp)) {
+ (recovery_cp < MaxSector && sh->sector >= recovery_cp &&
+ s->failed == 0)) {
/* Calculate the real rcw later - for now make it
* look like rcw is cheaper
*/
@@ -3195,6 +3264,11 @@ static void handle_stripe_dirtying(struct r5conf *conf,
(unsigned long long)sh->sector,
rcw, qread, test_bit(STRIPE_DELAYED, &sh->state));
}
+
+ if (rcw > disks && rmw > disks &&
+ !test_bit(STRIPE_PREREAD_ACTIVE, &sh->state))
+ set_bit(STRIPE_DELAYED, &sh->state);
+
/* now if nothing is locked, and if we have enough data,
* we can start a write request
*/
@@ -4076,7 +4150,7 @@ static void activate_bit_delay(struct r5conf *conf,
}
}
-int md_raid5_congested(struct mddev *mddev, int bits)
+static int raid5_congested(struct mddev *mddev, int bits)
{
struct r5conf *conf = mddev->private;
@@ -4093,24 +4167,14 @@ int md_raid5_congested(struct mddev *mddev, int bits)
return 0;
}
-EXPORT_SYMBOL_GPL(md_raid5_congested);
-
-static int raid5_congested(void *data, int bits)
-{
- struct mddev *mddev = data;
-
- return mddev_congested(mddev, bits) ||
- md_raid5_congested(mddev, bits);
-}
/* We want read requests to align with chunks where possible,
* but write requests don't need to.
*/
-static int raid5_mergeable_bvec(struct request_queue *q,
+static int raid5_mergeable_bvec(struct mddev *mddev,
struct bvec_merge_data *bvm,
struct bio_vec *biovec)
{
- struct mddev *mddev = q->queuedata;
sector_t sector = bvm->bi_sector + get_start_sect(bvm->bi_bdev);
int max;
unsigned int chunk_sectors = mddev->chunk_sectors;
@@ -5291,11 +5355,14 @@ static void raid5d(struct md_thread *thread)
static ssize_t
raid5_show_stripe_cache_size(struct mddev *mddev, char *page)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
+ int ret = 0;
+ spin_lock(&mddev->lock);
+ conf = mddev->private;
if (conf)
- return sprintf(page, "%d\n", conf->max_nr_stripes);
- else
- return 0;
+ ret = sprintf(page, "%d\n", conf->max_nr_stripes);
+ spin_unlock(&mddev->lock);
+ return ret;
}
int
@@ -5334,21 +5401,25 @@ EXPORT_SYMBOL(raid5_set_cache_size);
static ssize_t
raid5_store_stripe_cache_size(struct mddev *mddev, const char *page, size_t len)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
unsigned long new;
int err;
if (len >= PAGE_SIZE)
return -EINVAL;
- if (!conf)
- return -ENODEV;
-
if (kstrtoul(page, 10, &new))
return -EINVAL;
- err = raid5_set_cache_size(mddev, new);
+ err = mddev_lock(mddev);
if (err)
return err;
- return len;
+ conf = mddev->private;
+ if (!conf)
+ err = -ENODEV;
+ else
+ err = raid5_set_cache_size(mddev, new);
+ mddev_unlock(mddev);
+
+ return err ?: len;
}
static struct md_sysfs_entry
@@ -5359,29 +5430,40 @@ raid5_stripecache_size = __ATTR(stripe_cache_size, S_IRUGO | S_IWUSR,
static ssize_t
raid5_show_preread_threshold(struct mddev *mddev, char *page)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
+ int ret = 0;
+ spin_lock(&mddev->lock);
+ conf = mddev->private;
if (conf)
- return sprintf(page, "%d\n", conf->bypass_threshold);
- else
- return 0;
+ ret = sprintf(page, "%d\n", conf->bypass_threshold);
+ spin_unlock(&mddev->lock);
+ return ret;
}
static ssize_t
raid5_store_preread_threshold(struct mddev *mddev, const char *page, size_t len)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
unsigned long new;
+ int err;
+
if (len >= PAGE_SIZE)
return -EINVAL;
- if (!conf)
- return -ENODEV;
-
if (kstrtoul(page, 10, &new))
return -EINVAL;
- if (new > conf->max_nr_stripes)
- return -EINVAL;
- conf->bypass_threshold = new;
- return len;
+
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ conf = mddev->private;
+ if (!conf)
+ err = -ENODEV;
+ else if (new > conf->max_nr_stripes)
+ err = -EINVAL;
+ else
+ conf->bypass_threshold = new;
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry
@@ -5393,39 +5475,48 @@ raid5_preread_bypass_threshold = __ATTR(preread_bypass_threshold,
static ssize_t
raid5_show_skip_copy(struct mddev *mddev, char *page)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
+ int ret = 0;
+ spin_lock(&mddev->lock);
+ conf = mddev->private;
if (conf)
- return sprintf(page, "%d\n", conf->skip_copy);
- else
- return 0;
+ ret = sprintf(page, "%d\n", conf->skip_copy);
+ spin_unlock(&mddev->lock);
+ return ret;
}
static ssize_t
raid5_store_skip_copy(struct mddev *mddev, const char *page, size_t len)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
unsigned long new;
+ int err;
+
if (len >= PAGE_SIZE)
return -EINVAL;
- if (!conf)
- return -ENODEV;
-
if (kstrtoul(page, 10, &new))
return -EINVAL;
new = !!new;
- if (new == conf->skip_copy)
- return len;
- mddev_suspend(mddev);
- conf->skip_copy = new;
- if (new)
- mddev->queue->backing_dev_info.capabilities |=
- BDI_CAP_STABLE_WRITES;
- else
- mddev->queue->backing_dev_info.capabilities &=
- ~BDI_CAP_STABLE_WRITES;
- mddev_resume(mddev);
- return len;
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ conf = mddev->private;
+ if (!conf)
+ err = -ENODEV;
+ else if (new != conf->skip_copy) {
+ mddev_suspend(mddev);
+ conf->skip_copy = new;
+ if (new)
+ mddev->queue->backing_dev_info.capabilities |=
+ BDI_CAP_STABLE_WRITES;
+ else
+ mddev->queue->backing_dev_info.capabilities &=
+ ~BDI_CAP_STABLE_WRITES;
+ mddev_resume(mddev);
+ }
+ mddev_unlock(mddev);
+ return err ?: len;
}
static struct md_sysfs_entry
@@ -5449,11 +5540,14 @@ raid5_stripecache_active = __ATTR_RO(stripe_cache_active);
static ssize_t
raid5_show_group_thread_cnt(struct mddev *mddev, char *page)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
+ int ret = 0;
+ spin_lock(&mddev->lock);
+ conf = mddev->private;
if (conf)
- return sprintf(page, "%d\n", conf->worker_cnt_per_group);
- else
- return 0;
+ ret = sprintf(page, "%d\n", conf->worker_cnt_per_group);
+ spin_unlock(&mddev->lock);
+ return ret;
}
static int alloc_thread_groups(struct r5conf *conf, int cnt,
@@ -5463,7 +5557,7 @@ static int alloc_thread_groups(struct r5conf *conf, int cnt,
static ssize_t
raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf;
unsigned long new;
int err;
struct r5worker_group *new_groups, *old_groups;
@@ -5471,41 +5565,41 @@ raid5_store_group_thread_cnt(struct mddev *mddev, const char *page, size_t len)
if (len >= PAGE_SIZE)
return -EINVAL;
- if (!conf)
- return -ENODEV;
-
if (kstrtoul(page, 10, &new))
return -EINVAL;
- if (new == conf->worker_cnt_per_group)
- return len;
-
- mddev_suspend(mddev);
+ err = mddev_lock(mddev);
+ if (err)
+ return err;
+ conf = mddev->private;
+ if (!conf)
+ err = -ENODEV;
+ else if (new != conf->worker_cnt_per_group) {
+ mddev_suspend(mddev);
- old_groups = conf->worker_groups;
- if (old_groups)
- flush_workqueue(raid5_wq);
+ old_groups = conf->worker_groups;
+ if (old_groups)
+ flush_workqueue(raid5_wq);
- err = alloc_thread_groups(conf, new,
- &group_cnt, &worker_cnt_per_group,
- &new_groups);
- if (!err) {
- spin_lock_irq(&conf->device_lock);
- conf->group_cnt = group_cnt;
- conf->worker_cnt_per_group = worker_cnt_per_group;
- conf->worker_groups = new_groups;
- spin_unlock_irq(&conf->device_lock);
+ err = alloc_thread_groups(conf, new,
+ &group_cnt, &worker_cnt_per_group,
+ &new_groups);
+ if (!err) {
+ spin_lock_irq(&conf->device_lock);
+ conf->group_cnt = group_cnt;
+ conf->worker_cnt_per_group = worker_cnt_per_group;
+ conf->worker_groups = new_groups;
+ spin_unlock_irq(&conf->device_lock);
- if (old_groups)
- kfree(old_groups[0].workers);
- kfree(old_groups);
+ if (old_groups)
+ kfree(old_groups[0].workers);
+ kfree(old_groups);
+ }
+ mddev_resume(mddev);
}
+ mddev_unlock(mddev);
- mddev_resume(mddev);
-
- if (err)
- return err;
- return len;
+ return err ?: len;
}
static struct md_sysfs_entry
@@ -6173,11 +6267,6 @@ static int run(struct mddev *mddev)
if (mddev->queue->backing_dev_info.ra_pages < 2 * stripe)
mddev->queue->backing_dev_info.ra_pages = 2 * stripe;
- blk_queue_merge_bvec(mddev->queue, raid5_mergeable_bvec);
-
- mddev->queue->backing_dev_info.congested_data = mddev;
- mddev->queue->backing_dev_info.congested_fn = raid5_congested;
-
chunk_size = mddev->chunk_sectors << 9;
blk_queue_io_min(mddev->queue, chunk_size);
blk_queue_io_opt(mddev->queue, chunk_size *
@@ -6255,17 +6344,12 @@ abort:
return -EIO;
}
-static int stop(struct mddev *mddev)
+static void raid5_free(struct mddev *mddev, void *priv)
{
- struct r5conf *conf = mddev->private;
+ struct r5conf *conf = priv;
- md_unregister_thread(&mddev->thread);
- if (mddev->queue)
- mddev->queue->backing_dev_info.congested_fn = NULL;
free_conf(conf);
- mddev->private = NULL;
mddev->to_remove = &raid5_attrs_group;
- return 0;
}
static void status(struct seq_file *seq, struct mddev *mddev)
@@ -7039,7 +7123,7 @@ static struct md_personality raid6_personality =
.owner = THIS_MODULE,
.make_request = make_request,
.run = run,
- .stop = stop,
+ .free = raid5_free,
.status = status,
.error_handler = error,
.hot_add_disk = raid5_add_disk,
@@ -7053,6 +7137,8 @@ static struct md_personality raid6_personality =
.finish_reshape = raid5_finish_reshape,
.quiesce = raid5_quiesce,
.takeover = raid6_takeover,
+ .congested = raid5_congested,
+ .mergeable_bvec = raid5_mergeable_bvec,
};
static struct md_personality raid5_personality =
{
@@ -7061,7 +7147,7 @@ static struct md_personality raid5_personality =
.owner = THIS_MODULE,
.make_request = make_request,
.run = run,
- .stop = stop,
+ .free = raid5_free,
.status = status,
.error_handler = error,
.hot_add_disk = raid5_add_disk,
@@ -7075,6 +7161,8 @@ static struct md_personality raid5_personality =
.finish_reshape = raid5_finish_reshape,
.quiesce = raid5_quiesce,
.takeover = raid5_takeover,
+ .congested = raid5_congested,
+ .mergeable_bvec = raid5_mergeable_bvec,
};
static struct md_personality raid4_personality =
@@ -7084,7 +7172,7 @@ static struct md_personality raid4_personality =
.owner = THIS_MODULE,
.make_request = make_request,
.run = run,
- .stop = stop,
+ .free = raid5_free,
.status = status,
.error_handler = error,
.hot_add_disk = raid5_add_disk,
@@ -7098,6 +7186,8 @@ static struct md_personality raid4_personality =
.finish_reshape = raid5_finish_reshape,
.quiesce = raid5_quiesce,
.takeover = raid4_takeover,
+ .congested = raid5_congested,
+ .mergeable_bvec = raid5_mergeable_bvec,
};
static int __init raid5_init(void)
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index d59f5ca743cd..983e18a83db1 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -558,7 +558,6 @@ static inline int algorithm_is_DDF(int layout)
return layout >= 8 && layout <= 10;
}
-extern int md_raid5_congested(struct mddev *mddev, int bits);
extern void md_raid5_kick_device(struct r5conf *conf);
extern int raid5_set_cache_size(struct mddev *mddev, int size);
#endif
diff --git a/drivers/media/common/Kconfig b/drivers/media/common/Kconfig
index b85f88c8ddbd..21154dd87b0b 100644
--- a/drivers/media/common/Kconfig
+++ b/drivers/media/common/Kconfig
@@ -8,10 +8,6 @@ comment "common driver options"
config VIDEO_CX2341X
tristate
-config VIDEO_BTCX
- depends on PCI
- tristate
-
config VIDEO_TVEEPROM
tristate
depends on I2C
diff --git a/drivers/media/common/Makefile b/drivers/media/common/Makefile
index d208de3b7cc0..89b795df2cdd 100644
--- a/drivers/media/common/Makefile
+++ b/drivers/media/common/Makefile
@@ -1,5 +1,4 @@
obj-y += b2c2/ saa7146/ siano/
obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
-obj-$(CONFIG_VIDEO_BTCX) += btcx-risc.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_CYPRESS_FIRMWARE) += cypress_firmware.o
diff --git a/drivers/media/common/btcx-risc.c b/drivers/media/common/btcx-risc.c
deleted file mode 100644
index ac1b2687a20d..000000000000
--- a/drivers/media/common/btcx-risc.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
-
- btcx-risc.c
-
- bt848/bt878/cx2388x risc code generator.
-
- (c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/videodev2.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-
-#include "btcx-risc.h"
-
-MODULE_DESCRIPTION("some code shared by bttv and cx88xx drivers");
-MODULE_AUTHOR("Gerd Knorr");
-MODULE_LICENSE("GPL");
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"debug messages, default is 0 (no)");
-
-/* ---------------------------------------------------------- */
-/* allocate/free risc memory */
-
-static int memcnt;
-
-void btcx_riscmem_free(struct pci_dev *pci,
- struct btcx_riscmem *risc)
-{
- if (NULL == risc->cpu)
- return;
- if (debug) {
- memcnt--;
- printk("btcx: riscmem free [%d] dma=%lx\n",
- memcnt, (unsigned long)risc->dma);
- }
- pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
- memset(risc,0,sizeof(*risc));
-}
-
-int btcx_riscmem_alloc(struct pci_dev *pci,
- struct btcx_riscmem *risc,
- unsigned int size)
-{
- __le32 *cpu;
- dma_addr_t dma = 0;
-
- if (NULL != risc->cpu && risc->size < size)
- btcx_riscmem_free(pci,risc);
- if (NULL == risc->cpu) {
- cpu = pci_alloc_consistent(pci, size, &dma);
- if (NULL == cpu)
- return -ENOMEM;
- risc->cpu = cpu;
- risc->dma = dma;
- risc->size = size;
- if (debug) {
- memcnt++;
- printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
- memcnt, (unsigned long)dma, cpu, size);
- }
- }
- memset(risc->cpu,0,risc->size);
- return 0;
-}
-
-/* ---------------------------------------------------------- */
-/* screen overlay helpers */
-
-int
-btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
- struct v4l2_clip *clips, unsigned int n)
-{
- if (win->left < 0) {
- /* left */
- clips[n].c.left = 0;
- clips[n].c.top = 0;
- clips[n].c.width = -win->left;
- clips[n].c.height = win->height;
- n++;
- }
- if (win->left + win->width > swidth) {
- /* right */
- clips[n].c.left = swidth - win->left;
- clips[n].c.top = 0;
- clips[n].c.width = win->width - clips[n].c.left;
- clips[n].c.height = win->height;
- n++;
- }
- if (win->top < 0) {
- /* top */
- clips[n].c.left = 0;
- clips[n].c.top = 0;
- clips[n].c.width = win->width;
- clips[n].c.height = -win->top;
- n++;
- }
- if (win->top + win->height > sheight) {
- /* bottom */
- clips[n].c.left = 0;
- clips[n].c.top = sheight - win->top;
- clips[n].c.width = win->width;
- clips[n].c.height = win->height - clips[n].c.top;
- n++;
- }
- return n;
-}
-
-int
-btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
-{
- s32 nx,nw,dx;
- unsigned int i;
-
- /* fixup window */
- nx = (win->left + mask) & ~mask;
- nw = (win->width) & ~mask;
- if (nx + nw > win->left + win->width)
- nw -= mask+1;
- dx = nx - win->left;
- win->left = nx;
- win->width = nw;
- if (debug)
- printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
- win->width, win->height, win->left, win->top, dx);
-
- /* fixup clips */
- for (i = 0; i < n; i++) {
- nx = (clips[i].c.left-dx) & ~mask;
- nw = (clips[i].c.width) & ~mask;
- if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
- nw += mask+1;
- clips[i].c.left = nx;
- clips[i].c.width = nw;
- if (debug)
- printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n",
- clips[i].c.width, clips[i].c.height,
- clips[i].c.left, clips[i].c.top);
- }
- return 0;
-}
-
-void
-btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
-{
- struct v4l2_clip swap;
- int i,j,n;
-
- if (nclips < 2)
- return;
- for (i = nclips-2; i >= 0; i--) {
- for (n = 0, j = 0; j <= i; j++) {
- if (clips[j].c.left > clips[j+1].c.left) {
- swap = clips[j];
- clips[j] = clips[j+1];
- clips[j+1] = swap;
- n++;
- }
- }
- if (0 == n)
- break;
- }
-}
-
-void
-btcx_calc_skips(int line, int width, int *maxy,
- struct btcx_skiplist *skips, unsigned int *nskips,
- const struct v4l2_clip *clips, unsigned int nclips)
-{
- unsigned int clip,skip;
- int end, maxline;
-
- skip=0;
- maxline = 9999;
- for (clip = 0; clip < nclips; clip++) {
-
- /* sanity checks */
- if (clips[clip].c.left + clips[clip].c.width <= 0)
- continue;
- if (clips[clip].c.left > (signed)width)
- break;
-
- /* vertical range */
- if (line > clips[clip].c.top+clips[clip].c.height-1)
- continue;
- if (line < clips[clip].c.top) {
- if (maxline > clips[clip].c.top-1)
- maxline = clips[clip].c.top-1;
- continue;
- }
- if (maxline > clips[clip].c.top+clips[clip].c.height-1)
- maxline = clips[clip].c.top+clips[clip].c.height-1;
-
- /* horizontal range */
- if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
- /* new one */
- skips[skip].start = clips[clip].c.left;
- if (skips[skip].start < 0)
- skips[skip].start = 0;
- skips[skip].end = clips[clip].c.left + clips[clip].c.width;
- if (skips[skip].end > width)
- skips[skip].end = width;
- skip++;
- } else {
- /* overlaps -- expand last one */
- end = clips[clip].c.left + clips[clip].c.width;
- if (skips[skip-1].end < end)
- skips[skip-1].end = end;
- if (skips[skip-1].end > width)
- skips[skip-1].end = width;
- }
- }
- *nskips = skip;
- *maxy = maxline;
-
- if (debug) {
- printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
- for (skip = 0; skip < *nskips; skip++) {
- printk(" %d-%d",skips[skip].start,skips[skip].end);
- }
- printk("\n");
- }
-}
-
-/* ---------------------------------------------------------- */
-
-EXPORT_SYMBOL(btcx_riscmem_alloc);
-EXPORT_SYMBOL(btcx_riscmem_free);
-
-EXPORT_SYMBOL(btcx_screen_clips);
-EXPORT_SYMBOL(btcx_align);
-EXPORT_SYMBOL(btcx_sort_clips);
-EXPORT_SYMBOL(btcx_calc_skips);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/common/btcx-risc.h b/drivers/media/common/btcx-risc.h
index f8bc6e8e7b51..03583ef90506 100644
--- a/drivers/media/common/btcx-risc.h
+++ b/drivers/media/common/btcx-risc.h
@@ -26,9 +26,3 @@ void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
void btcx_calc_skips(int line, int width, int *maxy,
struct btcx_skiplist *skips, unsigned int *nskips,
const struct v4l2_clip *clips, unsigned int nclips);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index e4041f074909..686d3277dad1 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -68,13 +68,6 @@
#include "dvb_demux.h"
#include "dvb_net.h"
-static int dvb_net_debug;
-module_param(dvb_net_debug, int, 0444);
-MODULE_PARM_DESC(dvb_net_debug, "enable debug messages");
-
-#define dprintk(x...) do { if (dvb_net_debug) printk(x); } while (0)
-
-
static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
{
unsigned int j;
@@ -90,36 +83,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
#ifdef ULE_DEBUG
-#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x"
-#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5]
-
-#define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'))
-
-static void hexdump( const unsigned char *buf, unsigned short len )
+static void hexdump(const unsigned char *buf, unsigned short len)
{
- char str[80], octet[10];
- int ofs, i, l;
-
- for (ofs = 0; ofs < len; ofs += 16) {
- sprintf( str, "%03d: ", ofs );
-
- for (i = 0; i < 16; i++) {
- if ((i + ofs) < len)
- sprintf( octet, "%02x ", buf[ofs + i] );
- else
- strcpy( octet, " " );
-
- strcat( str, octet );
- }
- strcat( str, " " );
- l = strlen( str );
-
- for (i = 0; (i < 16) && ((i + ofs) < len); i++)
- str[l++] = isprint( buf[ofs + i] ) ? buf[ofs + i] : '.';
-
- str[l] = '\0';
- printk( KERN_WARNING "%s\n", str );
- }
+ print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
}
#endif
@@ -315,9 +281,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
return l; /* Stop extension header processing and discard SNDU. */
total_ext_len += l;
#ifdef ULE_DEBUG
- dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, "
- "l=%i, total_ext_len=%i\n", p->ule_next_hdr,
- (int) p->ule_sndu_type, l, total_ext_len);
+ pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n",
+ p->ule_next_hdr, (int)p->ule_sndu_type,
+ l, total_ext_len);
#endif
} while (p->ule_sndu_type < ETH_P_802_3_MIN);
@@ -700,8 +666,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
if (drop) {
#ifdef ULE_DEBUG
- dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n",
- MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr));
+ netdev_dbg(dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, dev addr: %pM\n",
+ priv->ule_skb->data, dev->dev_addr);
#endif
dev_kfree_skb(priv->ule_skb);
goto sndu_done;
@@ -964,8 +930,7 @@ static int dvb_net_filter_sec_set(struct net_device *dev,
(*secfilter)->filter_mask[10] = mac_mask[1];
(*secfilter)->filter_mask[11]=mac_mask[0];
- dprintk("%s: filter mac=%pM\n", dev->name, mac);
- dprintk("%s: filter mask=%pM\n", dev->name, mac_mask);
+ netdev_dbg(dev, "filter mac=%pM mask=%pM\n", mac, mac_mask);
return 0;
}
@@ -977,7 +942,7 @@ static int dvb_net_feed_start(struct net_device *dev)
struct dmx_demux *demux = priv->demux;
unsigned char *mac = (unsigned char *) dev->dev_addr;
- dprintk("%s: rx_mode %i\n", __func__, priv->rx_mode);
+ netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode);
mutex_lock(&priv->mutex);
if (priv->tsfeed || priv->secfeed || priv->secfilter || priv->multi_secfilter[0])
printk("%s: BUG %d\n", __func__, __LINE__);
@@ -987,7 +952,7 @@ static int dvb_net_feed_start(struct net_device *dev)
priv->tsfeed = NULL;
if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
- dprintk("%s: alloc secfeed\n", __func__);
+ netdev_dbg(dev, "alloc secfeed\n");
ret=demux->allocate_section_feed(demux, &priv->secfeed,
dvb_net_sec_callback);
if (ret<0) {
@@ -1005,38 +970,38 @@ static int dvb_net_feed_start(struct net_device *dev)
}
if (priv->rx_mode != RX_MODE_PROMISC) {
- dprintk("%s: set secfilter\n", __func__);
+ netdev_dbg(dev, "set secfilter\n");
dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_normal);
}
switch (priv->rx_mode) {
case RX_MODE_MULTI:
for (i = 0; i < priv->multi_num; i++) {
- dprintk("%s: set multi_secfilter[%d]\n", __func__, i);
+ netdev_dbg(dev, "set multi_secfilter[%d]\n", i);
dvb_net_filter_sec_set(dev, &priv->multi_secfilter[i],
priv->multi_macs[i], mask_normal);
}
break;
case RX_MODE_ALL_MULTI:
priv->multi_num=1;
- dprintk("%s: set multi_secfilter[0]\n", __func__);
+ netdev_dbg(dev, "set multi_secfilter[0]\n");
dvb_net_filter_sec_set(dev, &priv->multi_secfilter[0],
mac_allmulti, mask_allmulti);
break;
case RX_MODE_PROMISC:
priv->multi_num=0;
- dprintk("%s: set secfilter\n", __func__);
+ netdev_dbg(dev, "set secfilter\n");
dvb_net_filter_sec_set(dev, &priv->secfilter, mac, mask_promisc);
break;
}
- dprintk("%s: start filtering\n", __func__);
+ netdev_dbg(dev, "start filtering\n");
priv->secfeed->start_filtering(priv->secfeed);
} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
struct timespec timeout = { 0, 10000000 }; // 10 msec
/* we have payloads encapsulated in TS */
- dprintk("%s: alloc tsfeed\n", __func__);
+ netdev_dbg(dev, "alloc tsfeed\n");
ret = demux->allocate_ts_feed(demux, &priv->tsfeed, dvb_net_ts_callback);
if (ret < 0) {
printk("%s: could not allocate ts feed\n", dev->name);
@@ -1060,7 +1025,7 @@ static int dvb_net_feed_start(struct net_device *dev)
goto error;
}
- dprintk("%s: start filtering\n", __func__);
+ netdev_dbg(dev, "start filtering\n");
priv->tsfeed->start_filtering(priv->tsfeed);
} else
ret = -EINVAL;
@@ -1075,17 +1040,16 @@ static int dvb_net_feed_stop(struct net_device *dev)
struct dvb_net_priv *priv = netdev_priv(dev);
int i, ret = 0;
- dprintk("%s\n", __func__);
mutex_lock(&priv->mutex);
if (priv->feedtype == DVB_NET_FEEDTYPE_MPE) {
if (priv->secfeed) {
if (priv->secfeed->is_filtering) {
- dprintk("%s: stop secfeed\n", __func__);
+ netdev_dbg(dev, "stop secfeed\n");
priv->secfeed->stop_filtering(priv->secfeed);
}
if (priv->secfilter) {
- dprintk("%s: release secfilter\n", __func__);
+ netdev_dbg(dev, "release secfilter\n");
priv->secfeed->release_filter(priv->secfeed,
priv->secfilter);
priv->secfilter=NULL;
@@ -1093,8 +1057,8 @@ static int dvb_net_feed_stop(struct net_device *dev)
for (i=0; i<priv->multi_num; i++) {
if (priv->multi_secfilter[i]) {
- dprintk("%s: release multi_filter[%d]\n",
- __func__, i);
+ netdev_dbg(dev, "release multi_filter[%d]\n",
+ i);
priv->secfeed->release_filter(priv->secfeed,
priv->multi_secfilter[i]);
priv->multi_secfilter[i] = NULL;
@@ -1108,7 +1072,7 @@ static int dvb_net_feed_stop(struct net_device *dev)
} else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) {
if (priv->tsfeed) {
if (priv->tsfeed->is_filtering) {
- dprintk("%s: stop tsfeed\n", __func__);
+ netdev_dbg(dev, "stop tsfeed\n");
priv->tsfeed->stop_filtering(priv->tsfeed);
}
priv->demux->release_ts_feed(priv->demux, priv->tsfeed);
@@ -1148,16 +1112,16 @@ static void wq_set_multicast_list (struct work_struct *work)
netif_addr_lock_bh(dev);
if (dev->flags & IFF_PROMISC) {
- dprintk("%s: promiscuous mode\n", dev->name);
+ netdev_dbg(dev, "promiscuous mode\n");
priv->rx_mode = RX_MODE_PROMISC;
} else if ((dev->flags & IFF_ALLMULTI)) {
- dprintk("%s: allmulti mode\n", dev->name);
+ netdev_dbg(dev, "allmulti mode\n");
priv->rx_mode = RX_MODE_ALL_MULTI;
} else if (!netdev_mc_empty(dev)) {
struct netdev_hw_addr *ha;
- dprintk("%s: set_mc_list, %d entries\n",
- dev->name, netdev_mc_count(dev));
+ netdev_dbg(dev, "set_mc_list, %d entries\n",
+ netdev_mc_count(dev));
priv->rx_mode = RX_MODE_MULTI;
priv->multi_num = 0;
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 6c75418222e2..bb76727d924e 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -443,7 +443,8 @@ config DVB_CXD2820R
config DVB_RTL2830
tristate "Realtek RTL2830 DVB-T"
- depends on DVB_CORE && I2C
+ depends on DVB_CORE && I2C && I2C_MUX
+ select REGMAP
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
@@ -451,6 +452,7 @@ config DVB_RTL2830
config DVB_RTL2832
tristate "Realtek RTL2832 DVB-T"
depends on DVB_CORE && I2C && I2C_MUX
+ select REGMAP
default m if !MEDIA_SUBDRV_AUTOSELECT
help
Say Y when you want to support this frontend.
diff --git a/drivers/media/dvb-frontends/au8522.h b/drivers/media/dvb-frontends/au8522.h
index 83fe9a615619..612251958855 100644
--- a/drivers/media/dvb-frontends/au8522.h
+++ b/drivers/media/dvb-frontends/au8522.h
@@ -91,8 +91,3 @@ enum au8522_audio_input {
};
#endif /* __AU8522_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c
index 61e31f2d2f71..8c6663b6399d 100644
--- a/drivers/media/dvb-frontends/dib8000.c
+++ b/drivers/media/dvb-frontends/dib8000.c
@@ -1263,7 +1263,8 @@ static int dib8000_agc_startup(struct dvb_frontend *fe)
struct dib8000_state *state = fe->demodulator_priv;
enum frontend_tune_state *tune_state = &state->tune_state;
int ret = 0;
- u16 reg, upd_demod_gain_period = 0x8000;
+ u16 reg;
+ u32 upd_demod_gain_period = 0x8000;
switch (*tune_state) {
case CT_AGC_START:
diff --git a/drivers/media/dvb-frontends/hd29l2.c b/drivers/media/dvb-frontends/hd29l2.c
index d7b9d549156d..67c8e6df42e8 100644
--- a/drivers/media/dvb-frontends/hd29l2.c
+++ b/drivers/media/dvb-frontends/hd29l2.c
@@ -22,20 +22,24 @@
#include "hd29l2_priv.h"
+#define HD29L2_MAX_LEN (3)
+
/* write multiple registers */
static int hd29l2_wr_regs(struct hd29l2_priv *priv, u8 reg, u8 *val, int len)
{
int ret;
- u8 buf[2 + len];
+ u8 buf[2 + HD29L2_MAX_LEN];
struct i2c_msg msg[1] = {
{
.addr = priv->cfg.i2c_addr,
.flags = 0,
- .len = sizeof(buf),
+ .len = 2 + len,
.buf = buf,
}
};
+ if (len > HD29L2_MAX_LEN)
+ return -EINVAL;
buf[0] = 0x00;
buf[1] = reg;
memcpy(&buf[2], val, len);
@@ -118,7 +122,7 @@ static int hd29l2_wr_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 val, u8 mask)
}
/* read single register with mask */
-int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
+static int hd29l2_rd_reg_mask(struct hd29l2_priv *priv, u8 reg, u8 *val, u8 mask)
{
int ret, i;
u8 tmp;
diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c
index 5fd14f840ab0..99efeba3c31a 100644
--- a/drivers/media/dvb-frontends/lg2160.c
+++ b/drivers/media/dvb-frontends/lg2160.c
@@ -1456,9 +1456,3 @@ MODULE_DESCRIPTION("LG Electronics LG216x ATSC/MH Demodulator Driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.3");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/lgdt3305.c b/drivers/media/dvb-frontends/lgdt3305.c
index 92c891a571ab..d08570af1c10 100644
--- a/drivers/media/dvb-frontends/lgdt3305.c
+++ b/drivers/media/dvb-frontends/lgdt3305.c
@@ -236,12 +236,13 @@ static inline int lgdt3305_mpeg_mode(struct lgdt3305_state *state,
return lgdt3305_set_reg_bit(state, LGDT3305_TP_CTRL_1, 5, mode);
}
-static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
- enum lgdt3305_tp_clock_edge edge,
- enum lgdt3305_tp_valid_polarity valid)
+static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state)
{
u8 val;
int ret;
+ enum lgdt3305_tp_clock_edge edge = state->cfg->tpclk_edge;
+ enum lgdt3305_tp_clock_mode mode = state->cfg->tpclk_mode;
+ enum lgdt3305_tp_valid_polarity valid = state->cfg->tpvalid_polarity;
lg_dbg("edge = %d, valid = %d\n", edge, valid);
@@ -253,6 +254,8 @@ static int lgdt3305_mpeg_mode_polarity(struct lgdt3305_state *state,
if (edge)
val |= 0x08;
+ if (mode)
+ val |= 0x40;
if (valid)
val |= 0x01;
@@ -740,9 +743,7 @@ static int lgdt3304_set_parameters(struct dvb_frontend *fe)
goto fail;
/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
- ret = lgdt3305_mpeg_mode_polarity(state,
- state->cfg->tpclk_edge,
- state->cfg->tpvalid_polarity);
+ ret = lgdt3305_mpeg_mode_polarity(state);
fail:
return ret;
}
@@ -806,9 +807,7 @@ static int lgdt3305_set_parameters(struct dvb_frontend *fe)
goto fail;
/* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
- ret = lgdt3305_mpeg_mode_polarity(state,
- state->cfg->tpclk_edge,
- state->cfg->tpvalid_polarity);
+ ret = lgdt3305_mpeg_mode_polarity(state);
fail:
return ret;
}
@@ -1215,9 +1214,3 @@ MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.2");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/lgdt3305.h b/drivers/media/dvb-frontends/lgdt3305.h
index d9ab556c1b27..9c03e530e01b 100644
--- a/drivers/media/dvb-frontends/lgdt3305.h
+++ b/drivers/media/dvb-frontends/lgdt3305.h
@@ -37,6 +37,11 @@ enum lgdt3305_tp_clock_edge {
LGDT3305_TPCLK_FALLING_EDGE = 1,
};
+enum lgdt3305_tp_clock_mode {
+ LGDT3305_TPCLK_GATED = 0,
+ LGDT3305_TPCLK_FIXED = 1,
+};
+
enum lgdt3305_tp_valid_polarity {
LGDT3305_TP_VALID_LOW = 0,
LGDT3305_TP_VALID_HIGH = 1,
@@ -70,6 +75,7 @@ struct lgdt3305_config {
enum lgdt3305_mpeg_mode mpeg_mode;
enum lgdt3305_tp_clock_edge tpclk_edge;
+ enum lgdt3305_tp_clock_mode tpclk_mode;
enum lgdt3305_tp_valid_polarity tpvalid_polarity;
enum lgdt_demod_chip_type demod_chip;
};
diff --git a/drivers/media/dvb-frontends/lgdt330x.c b/drivers/media/dvb-frontends/lgdt330x.c
index e046622df0e4..2e1a61893fc1 100644
--- a/drivers/media/dvb-frontends/lgdt330x.c
+++ b/drivers/media/dvb-frontends/lgdt330x.c
@@ -823,9 +823,3 @@ MODULE_AUTHOR("Wilson Michaels");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(lgdt330x_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/lgdt330x.h b/drivers/media/dvb-frontends/lgdt330x.h
index ca0eab562e1e..8bb332219fc4 100644
--- a/drivers/media/dvb-frontends/lgdt330x.h
+++ b/drivers/media/dvb-frontends/lgdt330x.h
@@ -65,9 +65,3 @@ static inline struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config*
#endif // CONFIG_DVB_LGDT330X
#endif /* LGDT330X_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/lgdt330x_priv.h b/drivers/media/dvb-frontends/lgdt330x_priv.h
index 38c76695abfe..1922f09a02d0 100644
--- a/drivers/media/dvb-frontends/lgdt330x_priv.h
+++ b/drivers/media/dvb-frontends/lgdt330x_priv.h
@@ -69,9 +69,3 @@ enum I2C_REG {
};
#endif /* _LGDT330X_PRIV_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c
index e6f165a5b90d..8f54c39ca63f 100644
--- a/drivers/media/dvb-frontends/mb86a20s.c
+++ b/drivers/media/dvb-frontends/mb86a20s.c
@@ -22,10 +22,6 @@
#define NUM_LAYERS 3
-static int debug = 1;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
-
enum mb86a20s_bandwidth {
MB86A20S_13SEG = 0,
MB86A20S_13SEG_PARTIAL = 1,
diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h
index da4558bce60f..e4e0b80d3091 100644
--- a/drivers/media/dvb-frontends/mn88472.h
+++ b/drivers/media/dvb-frontends/mn88472.h
@@ -33,6 +33,12 @@ struct mn88472_config {
* DVB frontend.
*/
struct dvb_frontend **fe;
+
+ /*
+ * Xtal frequency.
+ * Hz
+ */
+ u32 xtal;
};
#endif
diff --git a/drivers/media/dvb-frontends/nxt200x.h b/drivers/media/dvb-frontends/nxt200x.h
index b518d545609e..e38d01fb6c2b 100644
--- a/drivers/media/dvb-frontends/nxt200x.h
+++ b/drivers/media/dvb-frontends/nxt200x.h
@@ -55,9 +55,3 @@ static inline struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* c
#endif // CONFIG_DVB_NXT200X
#endif /* NXT200X_H */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/or51132.c b/drivers/media/dvb-frontends/or51132.c
index 5ef921823c15..cbbd259eacfe 100644
--- a/drivers/media/dvb-frontends/or51132.c
+++ b/drivers/media/dvb-frontends/or51132.c
@@ -623,9 +623,3 @@ MODULE_AUTHOR("Trent Piepho");
MODULE_LICENSE("GPL");
EXPORT_SYMBOL(or51132_attach);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/or51132.h b/drivers/media/dvb-frontends/or51132.h
index 938958386cb1..cdb5be3c65d6 100644
--- a/drivers/media/dvb-frontends/or51132.h
+++ b/drivers/media/dvb-frontends/or51132.h
@@ -47,9 +47,3 @@ static inline struct dvb_frontend* or51132_attach(const struct or51132_config* c
#endif // CONFIG_DVB_OR51132
#endif // OR51132_H
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c
index 50e8b63e5169..e1b8df62bd59 100644
--- a/drivers/media/dvb-frontends/rtl2830.c
+++ b/drivers/media/dvb-frontends/rtl2830.c
@@ -13,261 +13,154 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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.
- */
-
-
-/*
- * Driver implements own I2C-adapter for tuner I2C access. That's since chip
- * have unusual I2C-gate control which closes gate automatically after each
- * I2C transfer. Using own I2C adapter we can workaround that.
*/
#include "rtl2830_priv.h"
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE 64
-
-/* write multiple hardware registers */
-static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, const u8 *val, int len)
+/* Our regmap is bypassing I2C adapter lock, thus we do it! */
+static int rtl2830_bulk_write(struct i2c_client *client, unsigned int reg,
+ const void *val, size_t val_count)
{
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
- u8 buf[MAX_XFER_SIZE];
- struct i2c_msg msg[1] = {
- {
- .addr = priv->cfg.i2c_addr,
- .flags = 0,
- .len = 1 + len,
- .buf = buf,
- }
- };
-
- if (1 + len > sizeof(buf)) {
- dev_warn(&priv->i2c->dev,
- "%s: i2c wr reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
- return -EINVAL;
- }
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
- ret = i2c_transfer(priv->i2c, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- dev_warn(&priv->i2c->dev, "%s: i2c wr failed=%d reg=%02x " \
- "len=%d\n", KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
+ i2c_lock_adapter(client->adapter);
+ ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
+ i2c_unlock_adapter(client->adapter);
return ret;
}
-/* read multiple hardware registers */
-static int rtl2830_rd(struct rtl2830_priv *priv, u8 reg, u8 *val, int len)
+static int rtl2830_update_bits(struct i2c_client *client, unsigned int reg,
+ unsigned int mask, unsigned int val)
{
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
- struct i2c_msg msg[2] = {
- {
- .addr = priv->cfg.i2c_addr,
- .flags = 0,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = priv->cfg.i2c_addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = val,
- }
- };
- ret = i2c_transfer(priv->i2c, msg, 2);
- if (ret == 2) {
- ret = 0;
- } else {
- dev_warn(&priv->i2c->dev, "%s: i2c rd failed=%d reg=%02x " \
- "len=%d\n", KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
+ i2c_lock_adapter(client->adapter);
+ ret = regmap_update_bits(dev->regmap, reg, mask, val);
+ i2c_unlock_adapter(client->adapter);
return ret;
}
-/* write multiple registers */
-static int rtl2830_wr_regs(struct rtl2830_priv *priv, u16 reg, const u8 *val,
- int len)
+static int rtl2830_bulk_read(struct i2c_client *client, unsigned int reg,
+ void *val, size_t val_count)
{
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
- u8 reg2 = (reg >> 0) & 0xff;
- u8 page = (reg >> 8) & 0xff;
-
- /* switch bank if needed */
- if (page != priv->page) {
- ret = rtl2830_wr(priv, 0x00, &page, 1);
- if (ret)
- return ret;
-
- priv->page = page;
- }
-
- return rtl2830_wr(priv, reg2, val, len);
-}
-
-/* read multiple registers */
-static int rtl2830_rd_regs(struct rtl2830_priv *priv, u16 reg, u8 *val, int len)
-{
- int ret;
- u8 reg2 = (reg >> 0) & 0xff;
- u8 page = (reg >> 8) & 0xff;
-
- /* switch bank if needed */
- if (page != priv->page) {
- ret = rtl2830_wr(priv, 0x00, &page, 1);
- if (ret)
- return ret;
-
- priv->page = page;
- }
- return rtl2830_rd(priv, reg2, val, len);
-}
-
-/* read single register */
-static int rtl2830_rd_reg(struct rtl2830_priv *priv, u16 reg, u8 *val)
-{
- return rtl2830_rd_regs(priv, reg, val, 1);
-}
-
-/* write single register with mask */
-static int rtl2830_wr_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 val, u8 mask)
-{
- int ret;
- u8 tmp;
-
- /* no need for read if whole reg is written */
- if (mask != 0xff) {
- ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
- if (ret)
- return ret;
-
- val &= mask;
- tmp &= ~mask;
- val |= tmp;
- }
-
- return rtl2830_wr_regs(priv, reg, &val, 1);
-}
-
-/* read single register with mask */
-static int rtl2830_rd_reg_mask(struct rtl2830_priv *priv, u16 reg, u8 *val, u8 mask)
-{
- int ret, i;
- u8 tmp;
-
- ret = rtl2830_rd_regs(priv, reg, &tmp, 1);
- if (ret)
- return ret;
-
- tmp &= mask;
-
- /* find position of the first bit */
- for (i = 0; i < 8; i++) {
- if ((mask >> i) & 0x01)
- break;
- }
- *val = tmp >> i;
-
- return 0;
+ i2c_lock_adapter(client->adapter);
+ ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
+ i2c_unlock_adapter(client->adapter);
+ return ret;
}
static int rtl2830_init(struct dvb_frontend *fe)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
+ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
int ret, i;
struct rtl2830_reg_val_mask tab[] = {
- { 0x00d, 0x01, 0x03 },
- { 0x00d, 0x10, 0x10 },
- { 0x104, 0x00, 0x1e },
- { 0x105, 0x80, 0x80 },
- { 0x110, 0x02, 0x03 },
- { 0x110, 0x08, 0x0c },
- { 0x17b, 0x00, 0x40 },
- { 0x17d, 0x05, 0x0f },
- { 0x17d, 0x50, 0xf0 },
- { 0x18c, 0x08, 0x0f },
- { 0x18d, 0x00, 0xc0 },
- { 0x188, 0x05, 0x0f },
- { 0x189, 0x00, 0xfc },
- { 0x2d5, 0x02, 0x02 },
- { 0x2f1, 0x02, 0x06 },
- { 0x2f1, 0x20, 0xf8 },
- { 0x16d, 0x00, 0x01 },
- { 0x1a6, 0x00, 0x80 },
- { 0x106, priv->cfg.vtop, 0x3f },
- { 0x107, priv->cfg.krf, 0x3f },
- { 0x112, 0x28, 0xff },
- { 0x103, priv->cfg.agc_targ_val, 0xff },
- { 0x00a, 0x02, 0x07 },
- { 0x140, 0x0c, 0x3c },
- { 0x140, 0x40, 0xc0 },
- { 0x15b, 0x05, 0x07 },
- { 0x15b, 0x28, 0x38 },
- { 0x15c, 0x05, 0x07 },
- { 0x15c, 0x28, 0x38 },
- { 0x115, priv->cfg.spec_inv, 0x01 },
- { 0x16f, 0x01, 0x07 },
- { 0x170, 0x18, 0x38 },
- { 0x172, 0x0f, 0x0f },
- { 0x173, 0x08, 0x38 },
- { 0x175, 0x01, 0x07 },
- { 0x176, 0x00, 0xc0 },
+ {0x00d, 0x01, 0x03},
+ {0x00d, 0x10, 0x10},
+ {0x104, 0x00, 0x1e},
+ {0x105, 0x80, 0x80},
+ {0x110, 0x02, 0x03},
+ {0x110, 0x08, 0x0c},
+ {0x17b, 0x00, 0x40},
+ {0x17d, 0x05, 0x0f},
+ {0x17d, 0x50, 0xf0},
+ {0x18c, 0x08, 0x0f},
+ {0x18d, 0x00, 0xc0},
+ {0x188, 0x05, 0x0f},
+ {0x189, 0x00, 0xfc},
+ {0x2d5, 0x02, 0x02},
+ {0x2f1, 0x02, 0x06},
+ {0x2f1, 0x20, 0xf8},
+ {0x16d, 0x00, 0x01},
+ {0x1a6, 0x00, 0x80},
+ {0x106, dev->pdata->vtop, 0x3f},
+ {0x107, dev->pdata->krf, 0x3f},
+ {0x112, 0x28, 0xff},
+ {0x103, dev->pdata->agc_targ_val, 0xff},
+ {0x00a, 0x02, 0x07},
+ {0x140, 0x0c, 0x3c},
+ {0x140, 0x40, 0xc0},
+ {0x15b, 0x05, 0x07},
+ {0x15b, 0x28, 0x38},
+ {0x15c, 0x05, 0x07},
+ {0x15c, 0x28, 0x38},
+ {0x115, dev->pdata->spec_inv, 0x01},
+ {0x16f, 0x01, 0x07},
+ {0x170, 0x18, 0x38},
+ {0x172, 0x0f, 0x0f},
+ {0x173, 0x08, 0x38},
+ {0x175, 0x01, 0x07},
+ {0x176, 0x00, 0xc0},
};
for (i = 0; i < ARRAY_SIZE(tab); i++) {
- ret = rtl2830_wr_reg_mask(priv, tab[i].reg, tab[i].val,
- tab[i].mask);
+ ret = rtl2830_update_bits(client, tab[i].reg, tab[i].mask,
+ tab[i].val);
if (ret)
goto err;
}
- ret = rtl2830_wr_regs(priv, 0x18f, "\x28\x00", 2);
+ ret = rtl2830_bulk_write(client, 0x18f, "\x28\x00", 2);
if (ret)
goto err;
- ret = rtl2830_wr_regs(priv, 0x195,
- "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
+ ret = rtl2830_bulk_write(client, 0x195,
+ "\x04\x06\x0a\x12\x0a\x12\x1e\x28", 8);
if (ret)
goto err;
/* TODO: spec init */
/* soft reset */
- ret = rtl2830_wr_reg_mask(priv, 0x101, 0x04, 0x04);
+ ret = rtl2830_update_bits(client, 0x101, 0x04, 0x04);
if (ret)
goto err;
- ret = rtl2830_wr_reg_mask(priv, 0x101, 0x00, 0x04);
+ ret = rtl2830_update_bits(client, 0x101, 0x04, 0x00);
if (ret)
goto err;
- priv->sleeping = false;
+ /* init stats here in order signal app which stats are supported */
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.len = 1;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.len = 1;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ /* start statistics polling */
+ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+
+ dev->sleeping = false;
return ret;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2830_sleep(struct dvb_frontend *fe)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- priv->sleeping = true;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
+
+ dev->sleeping = true;
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&dev->stat_work);
+ dev->fe_status = 0;
+
return 0;
}
static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *s)
+ struct dvb_frontend_tune_settings *s)
{
s->min_delay_ms = 500;
s->step_size = fe->ops.info.frequency_stepsize * 2;
@@ -278,11 +171,12 @@ static int rtl2830_get_tune_settings(struct dvb_frontend *fe,
static int rtl2830_set_frontend(struct dvb_frontend *fe)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u64 num;
- u8 buf[3], tmp;
+ u8 buf[3], u8tmp;
u32 if_ctl, if_frequency;
static const u8 bw_params1[3][34] = {
{
@@ -308,9 +202,8 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe)
{0xae, 0xba, 0xf3, 0x26, 0x66, 0x64}, /* 8 MHz */
};
- dev_dbg(&priv->i2c->dev,
- "%s: frequency=%d bandwidth_hz=%d inversion=%d\n",
- __func__, c->frequency, c->bandwidth_hz, c->inversion);
+ dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n",
+ c->frequency, c->bandwidth_hz, c->inversion);
/* program tuner */
if (fe->ops.tuner_ops.set_params)
@@ -327,11 +220,12 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe)
i = 2;
break;
default:
- dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__);
+ dev_err(&client->dev, "invalid bandwidth_hz %u\n",
+ c->bandwidth_hz);
return -EINVAL;
}
- ret = rtl2830_wr_reg_mask(priv, 0x008, i << 1, 0x06);
+ ret = rtl2830_update_bits(client, 0x008, 0x06, i << 1);
if (ret)
goto err;
@@ -340,70 +234,71 @@ static int rtl2830_set_frontend(struct dvb_frontend *fe)
ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
else
ret = -EINVAL;
-
- if (ret < 0)
+ if (ret)
goto err;
- num = if_frequency % priv->cfg.xtal;
+ num = if_frequency % dev->pdata->clk;
num *= 0x400000;
- num = div_u64(num, priv->cfg.xtal);
+ num = div_u64(num, dev->pdata->clk);
num = -num;
if_ctl = num & 0x3fffff;
- dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d if_ctl=%08x\n",
- __func__, if_frequency, if_ctl);
+ dev_dbg(&client->dev, "if_frequency=%d if_ctl=%08x\n",
+ if_frequency, if_ctl);
- ret = rtl2830_rd_reg_mask(priv, 0x119, &tmp, 0xc0); /* b[7:6] */
+ buf[0] = (if_ctl >> 16) & 0x3f;
+ buf[1] = (if_ctl >> 8) & 0xff;
+ buf[2] = (if_ctl >> 0) & 0xff;
+
+ ret = rtl2830_bulk_read(client, 0x119, &u8tmp, 1);
if (ret)
goto err;
- buf[0] = tmp << 6;
- buf[0] |= (if_ctl >> 16) & 0x3f;
- buf[1] = (if_ctl >> 8) & 0xff;
- buf[2] = (if_ctl >> 0) & 0xff;
+ buf[0] |= u8tmp & 0xc0; /* [7:6] */
- ret = rtl2830_wr_regs(priv, 0x119, buf, 3);
+ ret = rtl2830_bulk_write(client, 0x119, buf, 3);
if (ret)
goto err;
/* 1/2 split I2C write */
- ret = rtl2830_wr_regs(priv, 0x11c, &bw_params1[i][0], 17);
+ ret = rtl2830_bulk_write(client, 0x11c, &bw_params1[i][0], 17);
if (ret)
goto err;
/* 2/2 split I2C write */
- ret = rtl2830_wr_regs(priv, 0x12d, &bw_params1[i][17], 17);
+ ret = rtl2830_bulk_write(client, 0x12d, &bw_params1[i][17], 17);
if (ret)
goto err;
- ret = rtl2830_wr_regs(priv, 0x19d, bw_params2[i], 6);
+ ret = rtl2830_bulk_write(client, 0x19d, bw_params2[i], 6);
if (ret)
goto err;
return ret;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2830_get_frontend(struct dvb_frontend *fe)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[3];
- if (priv->sleeping)
+ if (dev->sleeping)
return 0;
- ret = rtl2830_rd_regs(priv, 0x33c, buf, 2);
+ ret = rtl2830_bulk_read(client, 0x33c, buf, 2);
if (ret)
goto err;
- ret = rtl2830_rd_reg(priv, 0x351, &buf[2]);
+ ret = rtl2830_bulk_read(client, 0x351, &buf[2], 1);
if (ret)
goto err;
- dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf);
+ dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf);
switch ((buf[0] >> 2) & 3) {
case 0:
@@ -493,280 +388,543 @@ static int rtl2830_get_frontend(struct dvb_frontend *fe)
return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2830_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
- u8 tmp;
+ u8 u8tmp;
+
*status = 0;
- if (priv->sleeping)
+ if (dev->sleeping)
return 0;
- ret = rtl2830_rd_reg_mask(priv, 0x351, &tmp, 0x78); /* [6:3] */
+ ret = rtl2830_bulk_read(client, 0x351, &u8tmp, 1);
if (ret)
goto err;
- if (tmp == 11) {
+ u8tmp = (u8tmp >> 3) & 0x0f; /* [6:3] */
+ if (u8tmp == 11) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- } else if (tmp == 10) {
+ } else if (u8tmp == 10) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI;
}
+ dev->fe_status = *status;
+
return ret;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2830_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- int ret, hierarchy, constellation;
- u8 buf[2], tmp;
- u16 tmp16;
-#define CONSTELLATION_NUM 3
-#define HIERARCHY_NUM 4
- static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
- { 70705899, 70705899, 70705899, 70705899 },
- { 82433173, 82433173, 87483115, 94445660 },
- { 92888734, 92888734, 95487525, 99770748 },
- };
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- if (priv->sleeping)
- return 0;
+ if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+ *snr = div_s64(c->cnr.stat[0].svalue, 100);
+ else
+ *snr = 0;
- /* reports SNR in resolution of 0.1 dB */
+ return 0;
+}
- ret = rtl2830_rd_reg(priv, 0x33c, &tmp);
- if (ret)
- goto err;
+static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
- constellation = (tmp >> 2) & 0x03; /* [3:2] */
- if (constellation > CONSTELLATION_NUM - 1)
- goto err;
+ *ber = (dev->post_bit_error - dev->post_bit_error_prev);
+ dev->post_bit_error_prev = dev->post_bit_error;
- hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
- if (hierarchy > HIERARCHY_NUM - 1)
- goto err;
+ return 0;
+}
- ret = rtl2830_rd_regs(priv, 0x40c, buf, 2);
- if (ret)
- goto err;
+static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
- tmp16 = buf[0] << 8 | buf[1];
+ return 0;
+}
+
+static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- if (tmp16)
- *snr = (snr_constant[constellation][hierarchy] -
- intlog10(tmp16)) / ((1 << 24) / 100);
+ if (c->strength.stat[0].scale == FE_SCALE_RELATIVE)
+ *strength = c->strength.stat[0].uvalue;
else
- *snr = 0;
+ *strength = 0;
return 0;
+}
+
+static struct dvb_frontend_ops rtl2830_ops = {
+ .delsys = {SYS_DVBT},
+ .info = {
+ .name = "Realtek RTL2830 (DVB-T)",
+ .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_64 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS
+ },
+
+ .init = rtl2830_init,
+ .sleep = rtl2830_sleep,
+
+ .get_tune_settings = rtl2830_get_tune_settings,
+
+ .set_frontend = rtl2830_set_frontend,
+ .get_frontend = rtl2830_get_frontend,
+
+ .read_status = rtl2830_read_status,
+ .read_snr = rtl2830_read_snr,
+ .read_ber = rtl2830_read_ber,
+ .read_ucblocks = rtl2830_read_ucblocks,
+ .read_signal_strength = rtl2830_read_signal_strength,
+};
+
+static void rtl2830_stat_work(struct work_struct *work)
+{
+ struct rtl2830_dev *dev = container_of(work, struct rtl2830_dev, stat_work.work);
+ struct i2c_client *client = dev->client;
+ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+ int ret, tmp;
+ u8 u8tmp, buf[2];
+ u16 u16tmp;
+
+ dev_dbg(&client->dev, "\n");
+
+ /* signal strength */
+ if (dev->fe_status & FE_HAS_SIGNAL) {
+ struct {signed int x:14; } s;
+
+ /* read IF AGC */
+ ret = rtl2830_bulk_read(client, 0x359, buf, 2);
+ if (ret)
+ goto err;
+
+ u16tmp = buf[0] << 8 | buf[1] << 0;
+ u16tmp &= 0x3fff; /* [13:0] */
+ tmp = s.x = u16tmp; /* 14-bit bin to 2 complement */
+ u16tmp = clamp_val(-4 * tmp + 32767, 0x0000, 0xffff);
+
+ dev_dbg(&client->dev, "IF AGC=%d\n", tmp);
+
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ c->strength.stat[0].uvalue = u16tmp;
+ } else {
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ /* CNR */
+ if (dev->fe_status & FE_HAS_VITERBI) {
+ unsigned hierarchy, constellation;
+ #define CONSTELLATION_NUM 3
+ #define HIERARCHY_NUM 4
+ static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+ {70705899, 70705899, 70705899, 70705899},
+ {82433173, 82433173, 87483115, 94445660},
+ {92888734, 92888734, 95487525, 99770748},
+ };
+
+ ret = rtl2830_bulk_read(client, 0x33c, &u8tmp, 1);
+ if (ret)
+ goto err;
+
+ constellation = (u8tmp >> 2) & 0x03; /* [3:2] */
+ if (constellation > CONSTELLATION_NUM - 1)
+ goto err_schedule_delayed_work;
+
+ hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */
+ if (hierarchy > HIERARCHY_NUM - 1)
+ goto err_schedule_delayed_work;
+
+ ret = rtl2830_bulk_read(client, 0x40c, buf, 2);
+ if (ret)
+ goto err;
+
+ u16tmp = buf[0] << 8 | buf[1] << 0;
+ if (u16tmp)
+ tmp = (constant[constellation][hierarchy] -
+ intlog10(u16tmp)) / ((1 << 24) / 10000);
+ else
+ tmp = 0;
+
+ dev_dbg(&client->dev, "CNR raw=%u\n", u16tmp);
+
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = tmp;
+ } else {
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ /* BER */
+ if (dev->fe_status & FE_HAS_LOCK) {
+ ret = rtl2830_bulk_read(client, 0x34e, buf, 2);
+ if (ret)
+ goto err;
+
+ u16tmp = buf[0] << 8 | buf[1] << 0;
+ dev->post_bit_error += u16tmp;
+ dev->post_bit_count += 1000000;
+
+ dev_dbg(&client->dev, "BER errors=%u total=1000000\n", u16tmp);
+
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
+ } else {
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+err_schedule_delayed_work:
+ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+ return;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
- return ret;
+ dev_dbg(&client->dev, "failed=%d\n", ret);
}
-static int rtl2830_read_ber(struct dvb_frontend *fe, u32 *ber)
+static int rtl2830_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
int ret;
- u8 buf[2];
+ u8 u8tmp;
- if (priv->sleeping)
- return 0;
+ dev_dbg(&client->dev, "onoff=%d\n", onoff);
+
+ /* enable / disable PID filter */
+ if (onoff)
+ u8tmp = 0x80;
+ else
+ u8tmp = 0x00;
- ret = rtl2830_rd_regs(priv, 0x34e, buf, 2);
+ ret = rtl2830_update_bits(client, 0x061, 0x80, u8tmp);
if (ret)
goto err;
- *ber = buf[0] << 8 | buf[1];
-
return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
-static int rtl2830_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+static int rtl2830_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid, int onoff)
{
- *ucblocks = 0;
- return 0;
-}
-
-static int rtl2830_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
- u8 buf[2];
- u16 if_agc_raw, if_agc;
+ u8 buf[4];
- if (priv->sleeping)
+ dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n",
+ index, pid, onoff);
+
+ /* skip invalid PIDs (0x2000) */
+ if (pid > 0x1fff || index > 32)
return 0;
- ret = rtl2830_rd_regs(priv, 0x359, buf, 2);
+ if (onoff)
+ set_bit(index, &dev->filters);
+ else
+ clear_bit(index, &dev->filters);
+
+ /* enable / disable PIDs */
+ buf[0] = (dev->filters >> 0) & 0xff;
+ buf[1] = (dev->filters >> 8) & 0xff;
+ buf[2] = (dev->filters >> 16) & 0xff;
+ buf[3] = (dev->filters >> 24) & 0xff;
+ ret = rtl2830_bulk_write(client, 0x062, buf, 4);
if (ret)
goto err;
- if_agc_raw = (buf[0] << 8 | buf[1]) & 0x3fff;
-
- if (if_agc_raw & (1 << 9))
- if_agc = -(~(if_agc_raw - 1) & 0x1ff);
- else
- if_agc = if_agc_raw;
-
- *strength = (u8) (55 - if_agc / 182);
- *strength |= *strength << 8;
+ /* add PID */
+ buf[0] = (pid >> 8) & 0xff;
+ buf[1] = (pid >> 0) & 0xff;
+ ret = rtl2830_bulk_write(client, 0x066 + 2 * index, buf, 2);
+ if (ret)
+ goto err;
return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
-static struct dvb_frontend_ops rtl2830_ops;
-
-static u32 rtl2830_tuner_i2c_func(struct i2c_adapter *adapter)
-{
- return I2C_FUNC_I2C;
-}
-
-static int rtl2830_tuner_i2c_xfer(struct i2c_adapter *i2c_adap,
- struct i2c_msg msg[], int num)
+/*
+ * I2C gate/mux/repeater logic
+ * We must use unlocked __i2c_transfer() here (through regmap) because of I2C
+ * adapter lock is already taken by tuner driver.
+ * Gate is closed automatically after single I2C transfer.
+ */
+static int rtl2830_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
{
- struct rtl2830_priv *priv = i2c_get_adapdata(i2c_adap);
+ struct i2c_client *client = mux_priv;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
int ret;
- /* open i2c-gate */
- ret = rtl2830_wr_reg_mask(priv, 0x101, 0x08, 0x08);
+ dev_dbg(&client->dev, "\n");
+
+ /* open I2C repeater for 1 transfer, closes automatically */
+ /* XXX: regmap_update_bits() does not lock I2C adapter */
+ ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
if (ret)
goto err;
- ret = i2c_transfer(priv->i2c, msg, num);
- if (ret < 0)
- dev_warn(&priv->i2c->dev, "%s: tuner i2c failed=%d\n",
- KBUILD_MODNAME, ret);
-
- return ret;
+ return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
-static struct i2c_algorithm rtl2830_tuner_i2c_algo = {
- .master_xfer = rtl2830_tuner_i2c_xfer,
- .functionality = rtl2830_tuner_i2c_func,
-};
+static struct dvb_frontend *rtl2830_get_dvb_frontend(struct i2c_client *client)
+{
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
-struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+ dev_dbg(&client->dev, "\n");
+
+ return &dev->fe;
+}
+
+static struct i2c_adapter *rtl2830_get_i2c_adapter(struct i2c_client *client)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
- return &priv->tuner_i2c_adapter;
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+
+ return dev->adapter;
}
-EXPORT_SYMBOL(rtl2830_get_tuner_i2c_adapter);
-static void rtl2830_release(struct dvb_frontend *fe)
+/*
+ * We implement own I2C access routines for regmap in order to get manual access
+ * to I2C adapter lock, which is needed for I2C mux adapter.
+ */
+static int rtl2830_regmap_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf, size_t val_size)
{
- struct rtl2830_priv *priv = fe->demodulator_priv;
+ struct i2c_client *client = context;
+ int ret;
+ struct i2c_msg msg[2] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = reg_size,
+ .buf = (u8 *)reg_buf,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = val_size,
+ .buf = val_buf,
+ }
+ };
- i2c_del_adapter(&priv->tuner_i2c_adapter);
- kfree(priv);
+ ret = __i2c_transfer(client->adapter, msg, 2);
+ if (ret != 2) {
+ dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ return ret;
+ }
+ return 0;
}
-struct dvb_frontend *rtl2830_attach(const struct rtl2830_config *cfg,
- struct i2c_adapter *i2c)
+static int rtl2830_regmap_write(void *context, const void *data, size_t count)
{
- struct rtl2830_priv *priv = NULL;
- int ret = 0;
- u8 tmp;
+ struct i2c_client *client = context;
+ int ret;
+ struct i2c_msg msg[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = count,
+ .buf = (u8 *)data,
+ }
+ };
+
+ ret = __i2c_transfer(client->adapter, msg, 1);
+ if (ret != 1) {
+ dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ return ret;
+ }
+ return 0;
+}
+
+static int rtl2830_regmap_gather_write(void *context, const void *reg,
+ size_t reg_len, const void *val,
+ size_t val_len)
+{
+ struct i2c_client *client = context;
+ int ret;
+ u8 buf[256];
+ struct i2c_msg msg[1] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1 + val_len,
+ .buf = buf,
+ }
+ };
+
+ buf[0] = *(u8 const *)reg;
+ memcpy(&buf[1], val, val_len);
+
+ ret = __i2c_transfer(client->adapter, msg, 1);
+ if (ret != 1) {
+ dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ return ret;
+ }
+ return 0;
+}
+
+static int rtl2830_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct rtl2830_platform_data *pdata = client->dev.platform_data;
+ struct rtl2830_dev *dev;
+ int ret;
+ u8 u8tmp;
+ static const struct regmap_bus regmap_bus = {
+ .read = rtl2830_regmap_read,
+ .write = rtl2830_regmap_write,
+ .gather_write = rtl2830_regmap_gather_write,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ };
+ static const struct regmap_range_cfg regmap_range_cfg[] = {
+ {
+ .selector_reg = 0x00,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ .range_min = 0 * 0x100,
+ .range_max = 5 * 0x100,
+ },
+ };
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = 5 * 0x100,
+ .ranges = regmap_range_cfg,
+ .num_ranges = ARRAY_SIZE(regmap_range_cfg),
+ };
+
+ dev_dbg(&client->dev, "\n");
+
+ if (pdata == NULL) {
+ ret = -EINVAL;
+ goto err;
+ }
/* allocate memory for the internal state */
- priv = kzalloc(sizeof(struct rtl2830_priv), GFP_KERNEL);
- if (priv == NULL)
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
- /* setup the priv */
- priv->i2c = i2c;
- memcpy(&priv->cfg, cfg, sizeof(struct rtl2830_config));
+ /* setup the state */
+ i2c_set_clientdata(client, dev);
+ dev->client = client;
+ dev->pdata = client->dev.platform_data;
+ dev->sleeping = true;
+ INIT_DELAYED_WORK(&dev->stat_work, rtl2830_stat_work);
+ dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
+ &regmap_config);
+ if (IS_ERR(dev->regmap)) {
+ ret = PTR_ERR(dev->regmap);
+ goto err_kfree;
+ }
/* check if the demod is there */
- ret = rtl2830_rd_reg(priv, 0x000, &tmp);
+ ret = rtl2830_bulk_read(client, 0x000, &u8tmp, 1);
if (ret)
- goto err;
-
- /* create dvb_frontend */
- memcpy(&priv->fe.ops, &rtl2830_ops, sizeof(struct dvb_frontend_ops));
- priv->fe.demodulator_priv = priv;
-
- /* create tuner i2c adapter */
- strlcpy(priv->tuner_i2c_adapter.name, "RTL2830 tuner I2C adapter",
- sizeof(priv->tuner_i2c_adapter.name));
- priv->tuner_i2c_adapter.algo = &rtl2830_tuner_i2c_algo;
- priv->tuner_i2c_adapter.algo_data = NULL;
- priv->tuner_i2c_adapter.dev.parent = &i2c->dev;
- i2c_set_adapdata(&priv->tuner_i2c_adapter, priv);
- if (i2c_add_adapter(&priv->tuner_i2c_adapter) < 0) {
- dev_err(&i2c->dev,
- "%s: tuner i2c bus could not be initialized\n",
- KBUILD_MODNAME);
- goto err;
+ goto err_regmap_exit;
+
+ /* create muxed i2c adapter for tuner */
+ dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+ client, 0, 0, 0, rtl2830_select, NULL);
+ if (dev->adapter == NULL) {
+ ret = -ENODEV;
+ goto err_regmap_exit;
}
- priv->sleeping = true;
+ /* create dvb frontend */
+ memcpy(&dev->fe.ops, &rtl2830_ops, sizeof(dev->fe.ops));
+ dev->fe.demodulator_priv = client;
+
+ /* setup callbacks */
+ pdata->get_dvb_frontend = rtl2830_get_dvb_frontend;
+ pdata->get_i2c_adapter = rtl2830_get_i2c_adapter;
+ pdata->pid_filter = rtl2830_pid_filter;
+ pdata->pid_filter_ctrl = rtl2830_pid_filter_ctrl;
- return &priv->fe;
+ dev_info(&client->dev, "Realtek RTL2830 successfully attached\n");
+
+ return 0;
+err_regmap_exit:
+ regmap_exit(dev->regmap);
+err_kfree:
+ kfree(dev);
err:
- dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
- kfree(priv);
- return NULL;
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
}
-EXPORT_SYMBOL(rtl2830_attach);
-static struct dvb_frontend_ops rtl2830_ops = {
- .delsys = { SYS_DVBT },
- .info = {
- .name = "Realtek RTL2830 (DVB-T)",
- .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_64 |
- FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO |
- FE_CAN_RECOVER |
- FE_CAN_MUTE_TS
- },
+static int rtl2830_remove(struct i2c_client *client)
+{
+ struct rtl2830_dev *dev = i2c_get_clientdata(client);
- .release = rtl2830_release,
+ dev_dbg(&client->dev, "\n");
- .init = rtl2830_init,
- .sleep = rtl2830_sleep,
+ i2c_del_mux_adapter(dev->adapter);
+ regmap_exit(dev->regmap);
+ kfree(dev);
- .get_tune_settings = rtl2830_get_tune_settings,
+ return 0;
+}
- .set_frontend = rtl2830_set_frontend,
- .get_frontend = rtl2830_get_frontend,
+static const struct i2c_device_id rtl2830_id_table[] = {
+ {"rtl2830", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, rtl2830_id_table);
- .read_status = rtl2830_read_status,
- .read_snr = rtl2830_read_snr,
- .read_ber = rtl2830_read_ber,
- .read_ucblocks = rtl2830_read_ucblocks,
- .read_signal_strength = rtl2830_read_signal_strength,
+static struct i2c_driver rtl2830_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rtl2830",
+ },
+ .probe = rtl2830_probe,
+ .remove = rtl2830_remove,
+ .id_table = rtl2830_id_table,
};
+module_i2c_driver(rtl2830_driver);
+
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Realtek RTL2830 DVB-T demodulator driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/rtl2830.h b/drivers/media/dvb-frontends/rtl2830.h
index 3313847fb0be..0cde151e6608 100644
--- a/drivers/media/dvb-frontends/rtl2830.h
+++ b/drivers/media/dvb-frontends/rtl2830.h
@@ -13,78 +13,37 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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.
*/
#ifndef RTL2830_H
#define RTL2830_H
-#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
-struct rtl2830_config {
- /*
- * Demodulator I2C address.
- */
- u8 i2c_addr;
-
- /*
- * Xtal frequency.
- * Hz
- * 4000000, 16000000, 25000000, 28800000
- */
- u32 xtal;
-
- /*
- * TS output mode.
- */
- u8 ts_mode;
+/**
+ * struct rtl2830_platform_data - Platform data for the rtl2830 driver
+ * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000).
+ * @spec_inv: Spectrum inversion.
+ * @vtop: AGC take-over point.
+ * @krf: AGC ratio.
+ * @agc_targ_val: AGC.
+ * @get_dvb_frontend: Get DVB frontend.
+ * @get_i2c_adapter: Get I2C adapter.
+ * @pid_filter: Set PID to PID filter.
+ * @pid_filter_ctrl: Control PID filter.
+ */
- /*
- * Spectrum inversion.
- */
+struct rtl2830_platform_data {
+ u32 clk;
bool spec_inv;
-
- /*
- */
u8 vtop;
-
- /*
- */
u8 krf;
-
- /*
- */
u8 agc_targ_val;
-};
-
-#if IS_ENABLED(CONFIG_DVB_RTL2830)
-extern struct dvb_frontend *rtl2830_attach(
- const struct rtl2830_config *config,
- struct i2c_adapter *i2c
-);
-extern struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
- struct dvb_frontend *fe
-);
-#else
-static inline struct dvb_frontend *rtl2830_attach(
- const struct rtl2830_config *config,
- struct i2c_adapter *i2c
-)
-{
- pr_warn("%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-
-static inline struct i2c_adapter *rtl2830_get_tuner_i2c_adapter(
- struct dvb_frontend *fe
-)
-{
- return NULL;
-}
-#endif
+ struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
+ struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
+ int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
+ int (*pid_filter_ctrl)(struct dvb_frontend *, int);
+};
#endif /* RTL2830_H */
diff --git a/drivers/media/dvb-frontends/rtl2830_priv.h b/drivers/media/dvb-frontends/rtl2830_priv.h
index fab10ecb3c3b..d50d5376c9c5 100644
--- a/drivers/media/dvb-frontends/rtl2830_priv.h
+++ b/drivers/media/dvb-frontends/rtl2830_priv.h
@@ -13,9 +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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef RTL2830_PRIV_H
@@ -24,16 +21,23 @@
#include "dvb_frontend.h"
#include "dvb_math.h"
#include "rtl2830.h"
+#include <linux/i2c-mux.h>
+#include <linux/math64.h>
+#include <linux/regmap.h>
-struct rtl2830_priv {
- struct i2c_adapter *i2c;
+struct rtl2830_dev {
+ struct rtl2830_platform_data *pdata;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct i2c_adapter *adapter;
struct dvb_frontend fe;
- struct rtl2830_config cfg;
- struct i2c_adapter tuner_i2c_adapter;
-
bool sleeping;
-
- u8 page; /* active register page */
+ unsigned long filters;
+ struct delayed_work stat_work;
+ fe_status_t fe_status;
+ u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */
+ u64 post_bit_error;
+ u64 post_bit_count;
};
struct rtl2830_reg_val_mask {
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index 9026e1aee163..5d2d8f45b4b6 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -2,6 +2,7 @@
* Realtek RTL2832 DVB-T demodulator driver
*
* Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ * Copyright (C) 2012-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
@@ -19,280 +20,191 @@
*/
#include "rtl2832_priv.h"
-#include "dvb_math.h"
-#include <linux/bitops.h>
-/* Max transfer size done by I2C transfer functions */
-#define MAX_XFER_SIZE 64
#define REG_MASK(b) (BIT(b + 1) - 1)
static const struct rtl2832_reg_entry registers[] = {
- [DVBT_SOFT_RST] = {0x1, 0x1, 2, 2},
- [DVBT_IIC_REPEAT] = {0x1, 0x1, 3, 3},
- [DVBT_TR_WAIT_MIN_8K] = {0x1, 0x88, 11, 2},
- [DVBT_RSD_BER_FAIL_VAL] = {0x1, 0x8f, 15, 0},
- [DVBT_EN_BK_TRK] = {0x1, 0xa6, 7, 7},
- [DVBT_AD_EN_REG] = {0x0, 0x8, 7, 7},
- [DVBT_AD_EN_REG1] = {0x0, 0x8, 6, 6},
- [DVBT_EN_BBIN] = {0x1, 0xb1, 0, 0},
- [DVBT_MGD_THD0] = {0x1, 0x95, 7, 0},
- [DVBT_MGD_THD1] = {0x1, 0x96, 7, 0},
- [DVBT_MGD_THD2] = {0x1, 0x97, 7, 0},
- [DVBT_MGD_THD3] = {0x1, 0x98, 7, 0},
- [DVBT_MGD_THD4] = {0x1, 0x99, 7, 0},
- [DVBT_MGD_THD5] = {0x1, 0x9a, 7, 0},
- [DVBT_MGD_THD6] = {0x1, 0x9b, 7, 0},
- [DVBT_MGD_THD7] = {0x1, 0x9c, 7, 0},
- [DVBT_EN_CACQ_NOTCH] = {0x1, 0x61, 4, 4},
- [DVBT_AD_AV_REF] = {0x0, 0x9, 6, 0},
- [DVBT_REG_PI] = {0x0, 0xa, 2, 0},
- [DVBT_PIP_ON] = {0x0, 0x21, 3, 3},
- [DVBT_SCALE1_B92] = {0x2, 0x92, 7, 0},
- [DVBT_SCALE1_B93] = {0x2, 0x93, 7, 0},
- [DVBT_SCALE1_BA7] = {0x2, 0xa7, 7, 0},
- [DVBT_SCALE1_BA9] = {0x2, 0xa9, 7, 0},
- [DVBT_SCALE1_BAA] = {0x2, 0xaa, 7, 0},
- [DVBT_SCALE1_BAB] = {0x2, 0xab, 7, 0},
- [DVBT_SCALE1_BAC] = {0x2, 0xac, 7, 0},
- [DVBT_SCALE1_BB0] = {0x2, 0xb0, 7, 0},
- [DVBT_SCALE1_BB1] = {0x2, 0xb1, 7, 0},
- [DVBT_KB_P1] = {0x1, 0x64, 3, 1},
- [DVBT_KB_P2] = {0x1, 0x64, 6, 4},
- [DVBT_KB_P3] = {0x1, 0x65, 2, 0},
- [DVBT_OPT_ADC_IQ] = {0x0, 0x6, 5, 4},
- [DVBT_AD_AVI] = {0x0, 0x9, 1, 0},
- [DVBT_AD_AVQ] = {0x0, 0x9, 3, 2},
- [DVBT_K1_CR_STEP12] = {0x2, 0xad, 9, 4},
- [DVBT_TRK_KS_P2] = {0x1, 0x6f, 2, 0},
- [DVBT_TRK_KS_I2] = {0x1, 0x70, 5, 3},
- [DVBT_TR_THD_SET2] = {0x1, 0x72, 3, 0},
- [DVBT_TRK_KC_P2] = {0x1, 0x73, 5, 3},
- [DVBT_TRK_KC_I2] = {0x1, 0x75, 2, 0},
- [DVBT_CR_THD_SET2] = {0x1, 0x76, 7, 6},
- [DVBT_PSET_IFFREQ] = {0x1, 0x19, 21, 0},
- [DVBT_SPEC_INV] = {0x1, 0x15, 0, 0},
- [DVBT_RSAMP_RATIO] = {0x1, 0x9f, 27, 2},
- [DVBT_CFREQ_OFF_RATIO] = {0x1, 0x9d, 23, 4},
- [DVBT_FSM_STAGE] = {0x3, 0x51, 6, 3},
- [DVBT_RX_CONSTEL] = {0x3, 0x3c, 3, 2},
- [DVBT_RX_HIER] = {0x3, 0x3c, 6, 4},
- [DVBT_RX_C_RATE_LP] = {0x3, 0x3d, 2, 0},
- [DVBT_RX_C_RATE_HP] = {0x3, 0x3d, 5, 3},
- [DVBT_GI_IDX] = {0x3, 0x51, 1, 0},
- [DVBT_FFT_MODE_IDX] = {0x3, 0x51, 2, 2},
- [DVBT_RSD_BER_EST] = {0x3, 0x4e, 15, 0},
- [DVBT_CE_EST_EVM] = {0x4, 0xc, 15, 0},
- [DVBT_RF_AGC_VAL] = {0x3, 0x5b, 13, 0},
- [DVBT_IF_AGC_VAL] = {0x3, 0x59, 13, 0},
- [DVBT_DAGC_VAL] = {0x3, 0x5, 7, 0},
- [DVBT_SFREQ_OFF] = {0x3, 0x18, 13, 0},
- [DVBT_CFREQ_OFF] = {0x3, 0x5f, 17, 0},
- [DVBT_POLAR_RF_AGC] = {0x0, 0xe, 1, 1},
- [DVBT_POLAR_IF_AGC] = {0x0, 0xe, 0, 0},
- [DVBT_AAGC_HOLD] = {0x1, 0x4, 5, 5},
- [DVBT_EN_RF_AGC] = {0x1, 0x4, 6, 6},
- [DVBT_EN_IF_AGC] = {0x1, 0x4, 7, 7},
- [DVBT_IF_AGC_MIN] = {0x1, 0x8, 7, 0},
- [DVBT_IF_AGC_MAX] = {0x1, 0x9, 7, 0},
- [DVBT_RF_AGC_MIN] = {0x1, 0xa, 7, 0},
- [DVBT_RF_AGC_MAX] = {0x1, 0xb, 7, 0},
- [DVBT_IF_AGC_MAN] = {0x1, 0xc, 6, 6},
- [DVBT_IF_AGC_MAN_VAL] = {0x1, 0xc, 13, 0},
- [DVBT_RF_AGC_MAN] = {0x1, 0xe, 6, 6},
- [DVBT_RF_AGC_MAN_VAL] = {0x1, 0xe, 13, 0},
- [DVBT_DAGC_TRG_VAL] = {0x1, 0x12, 7, 0},
- [DVBT_AGC_TARG_VAL_0] = {0x1, 0x2, 0, 0},
- [DVBT_AGC_TARG_VAL_8_1] = {0x1, 0x3, 7, 0},
- [DVBT_AAGC_LOOP_GAIN] = {0x1, 0xc7, 5, 1},
- [DVBT_LOOP_GAIN2_3_0] = {0x1, 0x4, 4, 1},
- [DVBT_LOOP_GAIN2_4] = {0x1, 0x5, 7, 7},
- [DVBT_LOOP_GAIN3] = {0x1, 0xc8, 4, 0},
- [DVBT_VTOP1] = {0x1, 0x6, 5, 0},
- [DVBT_VTOP2] = {0x1, 0xc9, 5, 0},
- [DVBT_VTOP3] = {0x1, 0xca, 5, 0},
- [DVBT_KRF1] = {0x1, 0xcb, 7, 0},
- [DVBT_KRF2] = {0x1, 0x7, 7, 0},
- [DVBT_KRF3] = {0x1, 0xcd, 7, 0},
- [DVBT_KRF4] = {0x1, 0xce, 7, 0},
- [DVBT_EN_GI_PGA] = {0x1, 0xe5, 0, 0},
- [DVBT_THD_LOCK_UP] = {0x1, 0xd9, 8, 0},
- [DVBT_THD_LOCK_DW] = {0x1, 0xdb, 8, 0},
- [DVBT_THD_UP1] = {0x1, 0xdd, 7, 0},
- [DVBT_THD_DW1] = {0x1, 0xde, 7, 0},
- [DVBT_INTER_CNT_LEN] = {0x1, 0xd8, 3, 0},
- [DVBT_GI_PGA_STATE] = {0x1, 0xe6, 3, 3},
- [DVBT_EN_AGC_PGA] = {0x1, 0xd7, 0, 0},
- [DVBT_CKOUTPAR] = {0x1, 0x7b, 5, 5},
- [DVBT_CKOUT_PWR] = {0x1, 0x7b, 6, 6},
- [DVBT_SYNC_DUR] = {0x1, 0x7b, 7, 7},
- [DVBT_ERR_DUR] = {0x1, 0x7c, 0, 0},
- [DVBT_SYNC_LVL] = {0x1, 0x7c, 1, 1},
- [DVBT_ERR_LVL] = {0x1, 0x7c, 2, 2},
- [DVBT_VAL_LVL] = {0x1, 0x7c, 3, 3},
- [DVBT_SERIAL] = {0x1, 0x7c, 4, 4},
- [DVBT_SER_LSB] = {0x1, 0x7c, 5, 5},
- [DVBT_CDIV_PH0] = {0x1, 0x7d, 3, 0},
- [DVBT_CDIV_PH1] = {0x1, 0x7d, 7, 4},
- [DVBT_MPEG_IO_OPT_2_2] = {0x0, 0x6, 7, 7},
- [DVBT_MPEG_IO_OPT_1_0] = {0x0, 0x7, 7, 6},
- [DVBT_CKOUTPAR_PIP] = {0x0, 0xb7, 4, 4},
- [DVBT_CKOUT_PWR_PIP] = {0x0, 0xb7, 3, 3},
- [DVBT_SYNC_LVL_PIP] = {0x0, 0xb7, 2, 2},
- [DVBT_ERR_LVL_PIP] = {0x0, 0xb7, 1, 1},
- [DVBT_VAL_LVL_PIP] = {0x0, 0xb7, 0, 0},
- [DVBT_CKOUTPAR_PID] = {0x0, 0xb9, 4, 4},
- [DVBT_CKOUT_PWR_PID] = {0x0, 0xb9, 3, 3},
- [DVBT_SYNC_LVL_PID] = {0x0, 0xb9, 2, 2},
- [DVBT_ERR_LVL_PID] = {0x0, 0xb9, 1, 1},
- [DVBT_VAL_LVL_PID] = {0x0, 0xb9, 0, 0},
- [DVBT_SM_PASS] = {0x1, 0x93, 11, 0},
- [DVBT_AD7_SETTING] = {0x0, 0x11, 15, 0},
- [DVBT_RSSI_R] = {0x3, 0x1, 6, 0},
- [DVBT_ACI_DET_IND] = {0x3, 0x12, 0, 0},
- [DVBT_REG_MON] = {0x0, 0xd, 1, 0},
- [DVBT_REG_MONSEL] = {0x0, 0xd, 2, 2},
- [DVBT_REG_GPE] = {0x0, 0xd, 7, 7},
- [DVBT_REG_GPO] = {0x0, 0x10, 0, 0},
- [DVBT_REG_4MSEL] = {0x0, 0x13, 0, 0},
+ [DVBT_SOFT_RST] = {0x101, 2, 2},
+ [DVBT_IIC_REPEAT] = {0x101, 3, 3},
+ [DVBT_TR_WAIT_MIN_8K] = {0x188, 11, 2},
+ [DVBT_RSD_BER_FAIL_VAL] = {0x18f, 15, 0},
+ [DVBT_EN_BK_TRK] = {0x1a6, 7, 7},
+ [DVBT_AD_EN_REG] = {0x008, 7, 7},
+ [DVBT_AD_EN_REG1] = {0x008, 6, 6},
+ [DVBT_EN_BBIN] = {0x1b1, 0, 0},
+ [DVBT_MGD_THD0] = {0x195, 7, 0},
+ [DVBT_MGD_THD1] = {0x196, 7, 0},
+ [DVBT_MGD_THD2] = {0x197, 7, 0},
+ [DVBT_MGD_THD3] = {0x198, 7, 0},
+ [DVBT_MGD_THD4] = {0x199, 7, 0},
+ [DVBT_MGD_THD5] = {0x19a, 7, 0},
+ [DVBT_MGD_THD6] = {0x19b, 7, 0},
+ [DVBT_MGD_THD7] = {0x19c, 7, 0},
+ [DVBT_EN_CACQ_NOTCH] = {0x161, 4, 4},
+ [DVBT_AD_AV_REF] = {0x009, 6, 0},
+ [DVBT_REG_PI] = {0x00a, 2, 0},
+ [DVBT_PIP_ON] = {0x021, 3, 3},
+ [DVBT_SCALE1_B92] = {0x292, 7, 0},
+ [DVBT_SCALE1_B93] = {0x293, 7, 0},
+ [DVBT_SCALE1_BA7] = {0x2a7, 7, 0},
+ [DVBT_SCALE1_BA9] = {0x2a9, 7, 0},
+ [DVBT_SCALE1_BAA] = {0x2aa, 7, 0},
+ [DVBT_SCALE1_BAB] = {0x2ab, 7, 0},
+ [DVBT_SCALE1_BAC] = {0x2ac, 7, 0},
+ [DVBT_SCALE1_BB0] = {0x2b0, 7, 0},
+ [DVBT_SCALE1_BB1] = {0x2b1, 7, 0},
+ [DVBT_KB_P1] = {0x164, 3, 1},
+ [DVBT_KB_P2] = {0x164, 6, 4},
+ [DVBT_KB_P3] = {0x165, 2, 0},
+ [DVBT_OPT_ADC_IQ] = {0x006, 5, 4},
+ [DVBT_AD_AVI] = {0x009, 1, 0},
+ [DVBT_AD_AVQ] = {0x009, 3, 2},
+ [DVBT_K1_CR_STEP12] = {0x2ad, 9, 4},
+ [DVBT_TRK_KS_P2] = {0x16f, 2, 0},
+ [DVBT_TRK_KS_I2] = {0x170, 5, 3},
+ [DVBT_TR_THD_SET2] = {0x172, 3, 0},
+ [DVBT_TRK_KC_P2] = {0x173, 5, 3},
+ [DVBT_TRK_KC_I2] = {0x175, 2, 0},
+ [DVBT_CR_THD_SET2] = {0x176, 7, 6},
+ [DVBT_PSET_IFFREQ] = {0x119, 21, 0},
+ [DVBT_SPEC_INV] = {0x115, 0, 0},
+ [DVBT_RSAMP_RATIO] = {0x19f, 27, 2},
+ [DVBT_CFREQ_OFF_RATIO] = {0x19d, 23, 4},
+ [DVBT_FSM_STAGE] = {0x351, 6, 3},
+ [DVBT_RX_CONSTEL] = {0x33c, 3, 2},
+ [DVBT_RX_HIER] = {0x33c, 6, 4},
+ [DVBT_RX_C_RATE_LP] = {0x33d, 2, 0},
+ [DVBT_RX_C_RATE_HP] = {0x33d, 5, 3},
+ [DVBT_GI_IDX] = {0x351, 1, 0},
+ [DVBT_FFT_MODE_IDX] = {0x351, 2, 2},
+ [DVBT_RSD_BER_EST] = {0x34e, 15, 0},
+ [DVBT_CE_EST_EVM] = {0x40c, 15, 0},
+ [DVBT_RF_AGC_VAL] = {0x35b, 13, 0},
+ [DVBT_IF_AGC_VAL] = {0x359, 13, 0},
+ [DVBT_DAGC_VAL] = {0x305, 7, 0},
+ [DVBT_SFREQ_OFF] = {0x318, 13, 0},
+ [DVBT_CFREQ_OFF] = {0x35f, 17, 0},
+ [DVBT_POLAR_RF_AGC] = {0x00e, 1, 1},
+ [DVBT_POLAR_IF_AGC] = {0x00e, 0, 0},
+ [DVBT_AAGC_HOLD] = {0x104, 5, 5},
+ [DVBT_EN_RF_AGC] = {0x104, 6, 6},
+ [DVBT_EN_IF_AGC] = {0x104, 7, 7},
+ [DVBT_IF_AGC_MIN] = {0x108, 7, 0},
+ [DVBT_IF_AGC_MAX] = {0x109, 7, 0},
+ [DVBT_RF_AGC_MIN] = {0x10a, 7, 0},
+ [DVBT_RF_AGC_MAX] = {0x10b, 7, 0},
+ [DVBT_IF_AGC_MAN] = {0x10c, 6, 6},
+ [DVBT_IF_AGC_MAN_VAL] = {0x10c, 13, 0},
+ [DVBT_RF_AGC_MAN] = {0x10e, 6, 6},
+ [DVBT_RF_AGC_MAN_VAL] = {0x10e, 13, 0},
+ [DVBT_DAGC_TRG_VAL] = {0x112, 7, 0},
+ [DVBT_AGC_TARG_VAL_0] = {0x102, 0, 0},
+ [DVBT_AGC_TARG_VAL_8_1] = {0x103, 7, 0},
+ [DVBT_AAGC_LOOP_GAIN] = {0x1c7, 5, 1},
+ [DVBT_LOOP_GAIN2_3_0] = {0x104, 4, 1},
+ [DVBT_LOOP_GAIN2_4] = {0x105, 7, 7},
+ [DVBT_LOOP_GAIN3] = {0x1c8, 4, 0},
+ [DVBT_VTOP1] = {0x106, 5, 0},
+ [DVBT_VTOP2] = {0x1c9, 5, 0},
+ [DVBT_VTOP3] = {0x1ca, 5, 0},
+ [DVBT_KRF1] = {0x1cb, 7, 0},
+ [DVBT_KRF2] = {0x107, 7, 0},
+ [DVBT_KRF3] = {0x1cd, 7, 0},
+ [DVBT_KRF4] = {0x1ce, 7, 0},
+ [DVBT_EN_GI_PGA] = {0x1e5, 0, 0},
+ [DVBT_THD_LOCK_UP] = {0x1d9, 8, 0},
+ [DVBT_THD_LOCK_DW] = {0x1db, 8, 0},
+ [DVBT_THD_UP1] = {0x1dd, 7, 0},
+ [DVBT_THD_DW1] = {0x1de, 7, 0},
+ [DVBT_INTER_CNT_LEN] = {0x1d8, 3, 0},
+ [DVBT_GI_PGA_STATE] = {0x1e6, 3, 3},
+ [DVBT_EN_AGC_PGA] = {0x1d7, 0, 0},
+ [DVBT_CKOUTPAR] = {0x17b, 5, 5},
+ [DVBT_CKOUT_PWR] = {0x17b, 6, 6},
+ [DVBT_SYNC_DUR] = {0x17b, 7, 7},
+ [DVBT_ERR_DUR] = {0x17c, 0, 0},
+ [DVBT_SYNC_LVL] = {0x17c, 1, 1},
+ [DVBT_ERR_LVL] = {0x17c, 2, 2},
+ [DVBT_VAL_LVL] = {0x17c, 3, 3},
+ [DVBT_SERIAL] = {0x17c, 4, 4},
+ [DVBT_SER_LSB] = {0x17c, 5, 5},
+ [DVBT_CDIV_PH0] = {0x17d, 3, 0},
+ [DVBT_CDIV_PH1] = {0x17d, 7, 4},
+ [DVBT_MPEG_IO_OPT_2_2] = {0x006, 7, 7},
+ [DVBT_MPEG_IO_OPT_1_0] = {0x007, 7, 6},
+ [DVBT_CKOUTPAR_PIP] = {0x0b7, 4, 4},
+ [DVBT_CKOUT_PWR_PIP] = {0x0b7, 3, 3},
+ [DVBT_SYNC_LVL_PIP] = {0x0b7, 2, 2},
+ [DVBT_ERR_LVL_PIP] = {0x0b7, 1, 1},
+ [DVBT_VAL_LVL_PIP] = {0x0b7, 0, 0},
+ [DVBT_CKOUTPAR_PID] = {0x0b9, 4, 4},
+ [DVBT_CKOUT_PWR_PID] = {0x0b9, 3, 3},
+ [DVBT_SYNC_LVL_PID] = {0x0b9, 2, 2},
+ [DVBT_ERR_LVL_PID] = {0x0b9, 1, 1},
+ [DVBT_VAL_LVL_PID] = {0x0b9, 0, 0},
+ [DVBT_SM_PASS] = {0x193, 11, 0},
+ [DVBT_AD7_SETTING] = {0x011, 15, 0},
+ [DVBT_RSSI_R] = {0x301, 6, 0},
+ [DVBT_ACI_DET_IND] = {0x312, 0, 0},
+ [DVBT_REG_MON] = {0x00d, 1, 0},
+ [DVBT_REG_MONSEL] = {0x00d, 2, 2},
+ [DVBT_REG_GPE] = {0x00d, 7, 7},
+ [DVBT_REG_GPO] = {0x010, 0, 0},
+ [DVBT_REG_4MSEL] = {0x013, 0, 0},
};
-/* write multiple hardware registers */
-static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+/* Our regmap is bypassing I2C adapter lock, thus we do it! */
+static int rtl2832_bulk_write(struct i2c_client *client, unsigned int reg,
+ const void *val, size_t val_count)
{
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
- u8 buf[MAX_XFER_SIZE];
- struct i2c_msg msg[1] = {
- {
- .addr = priv->cfg.i2c_addr,
- .flags = 0,
- .len = 1 + len,
- .buf = buf,
- }
- };
- if (1 + len > sizeof(buf)) {
- dev_warn(&priv->i2c->dev,
- "%s: i2c wr reg=%04x: len=%d is too big!\n",
- KBUILD_MODNAME, reg, len);
- return -EINVAL;
- }
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
-
- ret = i2c_transfer(priv->i2c_adapter, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- dev_warn(&priv->i2c->dev,
- "%s: i2c wr failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
+ i2c_lock_adapter(client->adapter);
+ ret = regmap_bulk_write(dev->regmap, reg, val, val_count);
+ i2c_unlock_adapter(client->adapter);
return ret;
}
-/* read multiple hardware registers */
-static int rtl2832_rd(struct rtl2832_priv *priv, u8 reg, u8 *val, int len)
+static int rtl2832_update_bits(struct i2c_client *client, unsigned int reg,
+ unsigned int mask, unsigned int val)
{
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
- struct i2c_msg msg[2] = {
- {
- .addr = priv->cfg.i2c_addr,
- .flags = 0,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = priv->cfg.i2c_addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = val,
- }
- };
- ret = i2c_transfer(priv->i2c_adapter, msg, 2);
- if (ret == 2) {
- ret = 0;
- } else {
- dev_warn(&priv->i2c->dev,
- "%s: i2c rd failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
+ i2c_lock_adapter(client->adapter);
+ ret = regmap_update_bits(dev->regmap, reg, mask, val);
+ i2c_unlock_adapter(client->adapter);
return ret;
}
-/* write multiple registers */
-static int rtl2832_wr_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
- int len)
-{
- int ret;
-
- /* switch bank if needed */
- if (page != priv->page) {
- ret = rtl2832_wr(priv, 0x00, &page, 1);
- if (ret)
- return ret;
-
- priv->page = page;
-}
-
-return rtl2832_wr(priv, reg, val, len);
-}
-
-/* read multiple registers */
-static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
- int len)
+static int rtl2832_bulk_read(struct i2c_client *client, unsigned int reg,
+ void *val, size_t val_count)
{
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
- /* switch bank if needed */
- if (page != priv->page) {
- ret = rtl2832_wr(priv, 0x00, &page, 1);
- if (ret)
- return ret;
-
- priv->page = page;
- }
-
- return rtl2832_rd(priv, reg, val, len);
-}
-
-/* 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);
-}
-
-/* read single register */
-static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
-{
- return rtl2832_rd_regs(priv, reg, page, val, 1);
+ i2c_lock_adapter(client->adapter);
+ ret = regmap_bulk_read(dev->regmap, reg, val, val_count);
+ i2c_unlock_adapter(client->adapter);
+ return ret;
}
-static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
+static int rtl2832_rd_demod_reg(struct rtl2832_dev *dev, int reg, u32 *val)
{
- int ret;
-
- u8 reg_start_addr;
- u8 msb, lsb;
- u8 page;
- u8 reading[4];
- u32 reading_tmp;
- int i;
-
- u8 len;
- u32 mask;
+ struct i2c_client *client = dev->client;
+ int ret, i;
+ u16 reg_start_addr;
+ u8 msb, lsb, reading[4], len;
+ u32 reading_tmp, mask;
reg_start_addr = registers[reg].start_address;
msb = registers[reg].msb;
lsb = registers[reg].lsb;
- page = registers[reg].page;
-
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);
- ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+ ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
if (ret)
goto err;
@@ -302,40 +214,27 @@ static int rtl2832_rd_demod_reg(struct rtl2832_priv *priv, int reg, u32 *val)
*val = (reading_tmp >> lsb) & mask;
- return ret;
-
+ return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
-
}
-static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
+static int rtl2832_wr_demod_reg(struct rtl2832_dev *dev, int reg, u32 val)
{
+ struct i2c_client *client = dev->client;
int ret, i;
- u8 len;
- u8 reg_start_addr;
- u8 msb, lsb;
- u8 page;
- u32 mask;
-
-
- u8 reading[4];
- u8 writing[4];
- u32 reading_tmp;
- u32 writing_tmp;
-
+ u16 reg_start_addr;
+ u8 msb, lsb, reading[4], writing[4], len;
+ u32 reading_tmp, writing_tmp, mask;
reg_start_addr = registers[reg].start_address;
msb = registers[reg].msb;
lsb = registers[reg].lsb;
- page = registers[reg].page;
-
len = (msb >> 3) + 1;
mask = REG_MASK(msb - lsb);
-
- ret = rtl2832_rd_regs(priv, reg_start_addr, page, &reading[0], len);
+ ret = rtl2832_bulk_read(client, reg_start_addr, reading, len);
if (ret)
goto err;
@@ -346,49 +245,23 @@ static int rtl2832_wr_demod_reg(struct rtl2832_priv *priv, int reg, u32 val)
writing_tmp = reading_tmp & ~(mask << lsb);
writing_tmp |= ((val & mask) << lsb);
-
for (i = 0; i < len; i++)
writing[i] = (writing_tmp >> ((len - 1 - i) * 8)) & 0xff;
- ret = rtl2832_wr_regs(priv, reg_start_addr, page, &writing[0], len);
- if (ret)
- goto err;
-
- return ret;
-
-err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
- return ret;
-
-}
-
-static int rtl2832_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
-{
- int ret;
- struct rtl2832_priv *priv = fe->demodulator_priv;
-
- dev_dbg(&priv->i2c->dev, "%s: enable=%d\n", __func__, enable);
-
- /* gate already open or close */
- if (priv->i2c_gate_state == enable)
- return 0;
-
- ret = rtl2832_wr_demod_reg(priv, DVBT_IIC_REPEAT, (enable ? 0x1 : 0x0));
+ ret = rtl2832_bulk_write(client, reg_start_addr, writing, len);
if (ret)
goto err;
- priv->i2c_gate_state = enable;
-
- return ret;
+ return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
-
static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
int ret;
u64 pset_iffreq;
u8 en_bbin = (if_freq == 0 ? 0x1 : 0x0);
@@ -397,30 +270,35 @@ static int rtl2832_set_if(struct dvb_frontend *fe, u32 if_freq)
* PSET_IFFREQ = - floor((IfFreqHz % CrystalFreqHz) * pow(2, 22)
* / CrystalFreqHz)
*/
-
- pset_iffreq = if_freq % priv->cfg.xtal;
+ pset_iffreq = if_freq % dev->pdata->clk;
pset_iffreq *= 0x400000;
- pset_iffreq = div_u64(pset_iffreq, priv->cfg.xtal);
+ pset_iffreq = div_u64(pset_iffreq, dev->pdata->clk);
pset_iffreq = -pset_iffreq;
pset_iffreq = pset_iffreq & 0x3fffff;
- dev_dbg(&priv->i2c->dev, "%s: if_frequency=%d pset_iffreq=%08x\n",
- __func__, if_freq, (unsigned)pset_iffreq);
+ dev_dbg(&client->dev, "if_frequency=%d pset_iffreq=%08x\n",
+ if_freq, (unsigned)pset_iffreq);
- ret = rtl2832_wr_demod_reg(priv, DVBT_EN_BBIN, en_bbin);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_EN_BBIN, en_bbin);
if (ret)
- return ret;
+ goto err;
- ret = rtl2832_wr_demod_reg(priv, DVBT_PSET_IFFREQ, pset_iffreq);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_PSET_IFFREQ, pset_iffreq);
+ if (ret)
+ goto err;
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2832_init(struct dvb_frontend *fe)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
+ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
const struct rtl2832_reg_value *init;
int i, ret, len;
-
/* initialization values for the demodulator registers */
struct rtl2832_reg_value rtl2832_initial_regs[] = {
{DVBT_AD_EN_REG, 0x1},
@@ -467,19 +345,19 @@ static int rtl2832_init(struct dvb_frontend *fe)
{DVBT_CR_THD_SET2, 0x1},
};
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ dev_dbg(&client->dev, "\n");
for (i = 0; i < ARRAY_SIZE(rtl2832_initial_regs); i++) {
- ret = rtl2832_wr_demod_reg(priv, rtl2832_initial_regs[i].reg,
+ ret = rtl2832_wr_demod_reg(dev, rtl2832_initial_regs[i].reg,
rtl2832_initial_regs[i].value);
if (ret)
goto err;
}
/* load tuner specific settings */
- dev_dbg(&priv->i2c->dev, "%s: load settings for tuner=%02x\n",
- __func__, priv->cfg.tuner);
- switch (priv->cfg.tuner) {
+ dev_dbg(&client->dev, "load settings for tuner=%02x\n",
+ dev->pdata->tuner);
+ switch (dev->pdata->tuner) {
case RTL2832_TUNER_FC0012:
case RTL2832_TUNER_FC0013:
len = ARRAY_SIZE(rtl2832_tuner_init_fc0012);
@@ -504,51 +382,60 @@ static int rtl2832_init(struct dvb_frontend *fe)
}
for (i = 0; i < len; i++) {
- ret = rtl2832_wr_demod_reg(priv, init[i].reg, init[i].value);
+ ret = rtl2832_wr_demod_reg(dev, init[i].reg, init[i].value);
if (ret)
goto err;
}
- /*
- * r820t NIM code does a software reset here at the demod -
- * may not be needed, as there's already a software reset at
- * set_params()
- */
-#if 1
- /* 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;
-#endif
-
- priv->sleeping = false;
-
- return ret;
+ /* init stats here in order signal app which stats are supported */
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->cnr.len = 1;
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.len = 1;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.len = 1;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ /* start statistics polling */
+ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+ dev->sleeping = false;
+ return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2832_sleep(struct dvb_frontend *fe)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
+ int ret;
+
+ dev_dbg(&client->dev, "\n");
+
+ dev->sleeping = true;
+ /* stop statistics polling */
+ cancel_delayed_work_sync(&dev->stat_work);
+ dev->fe_status = 0;
+
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
+ if (ret)
+ goto err;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
- priv->sleeping = true;
return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
}
static int rtl2832_get_tune_settings(struct dvb_frontend *fe,
struct dvb_frontend_tune_settings *s)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
+ dev_dbg(&client->dev, "\n");
s->min_delay_ms = 1000;
s->step_size = fe->ops.info.frequency_stepsize * 2;
s->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1;
@@ -557,7 +444,8 @@ static int rtl2832_get_tune_settings(struct dvb_frontend *fe,
static int rtl2832_set_frontend(struct dvb_frontend *fe)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i, j;
u64 bw_mode, num, num2;
@@ -588,17 +476,15 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
},
};
-
- dev_dbg(&priv->i2c->dev,
- "%s: frequency=%d bandwidth_hz=%d inversion=%d\n",
- __func__, c->frequency, c->bandwidth_hz, c->inversion);
+ dev_dbg(&client->dev, "frequency=%u bandwidth_hz=%u inversion=%u\n",
+ c->frequency, c->bandwidth_hz, c->inversion);
/* program tuner */
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);
+ ret = rtl2832_bulk_write(client, 0x192, "\x00\x0f\xff", 3);
if (ret)
goto err;
@@ -629,12 +515,14 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
bw_mode = 64000000;
break;
default:
- dev_dbg(&priv->i2c->dev, "%s: invalid bandwidth\n", __func__);
- return -EINVAL;
+ dev_err(&client->dev, "invalid bandwidth_hz %u\n",
+ c->bandwidth_hz);
+ ret = -EINVAL;
+ goto err;
}
for (j = 0; j < sizeof(bw_params[0]); j++) {
- ret = rtl2832_wr_regs(priv, 0x1c+j, 1, &bw_params[i][j], 1);
+ ret = rtl2832_bulk_write(client, 0x11c + j, &bw_params[i][j], 1);
if (ret)
goto err;
}
@@ -643,11 +531,11 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
* RSAMP_RATIO = floor(CrystalFreqHz * 7 * pow(2, 22)
* / ConstWithBandwidthMode)
*/
- num = priv->cfg.xtal * 7;
+ num = dev->pdata->clk * 7;
num *= 0x400000;
num = div_u64(num, bw_mode);
resamp_ratio = num & 0x3ffffff;
- ret = rtl2832_wr_demod_reg(priv, DVBT_RSAMP_RATIO, resamp_ratio);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_RSAMP_RATIO, resamp_ratio);
if (ret)
goto err;
@@ -656,48 +544,49 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
* / (CrystalFreqHz * 7))
*/
num = bw_mode << 20;
- num2 = priv->cfg.xtal * 7;
+ num2 = dev->pdata->clk * 7;
num = div_u64(num, num2);
num = -num;
cfreq_off_ratio = num & 0xfffff;
- ret = rtl2832_wr_demod_reg(priv, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_CFREQ_OFF_RATIO, cfreq_off_ratio);
if (ret)
goto err;
/* soft reset */
- ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
if (ret)
goto err;
- ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
if (ret)
goto err;
- return ret;
+ return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2832_get_frontend(struct dvb_frontend *fe)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
u8 buf[3];
- if (priv->sleeping)
+ if (dev->sleeping)
return 0;
- ret = rtl2832_rd_regs(priv, 0x3c, 3, buf, 2);
+ ret = rtl2832_bulk_read(client, 0x33c, buf, 2);
if (ret)
goto err;
- ret = rtl2832_rd_reg(priv, 0x51, 3, &buf[2]);
+ ret = rtl2832_bulk_read(client, 0x351, &buf[2], 1);
if (ret)
goto err;
- dev_dbg(&priv->i2c->dev, "%s: TPS=%*ph\n", __func__, 3, buf);
+ dev_dbg(&client->dev, "TPS=%*ph\n", 3, buf);
switch ((buf[0] >> 2) & 3) {
case 0:
@@ -787,403 +676,652 @@ static int rtl2832_get_frontend(struct dvb_frontend *fe)
return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2832_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
int ret;
u32 tmp;
- *status = 0;
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
- if (priv->sleeping)
+ dev_dbg(&client->dev, "\n");
+
+ *status = 0;
+ if (dev->sleeping)
return 0;
- ret = rtl2832_rd_demod_reg(priv, DVBT_FSM_STAGE, &tmp);
+ ret = rtl2832_rd_demod_reg(dev, DVBT_FSM_STAGE, &tmp);
if (ret)
goto err;
if (tmp == 11) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
- }
- /* TODO find out if this is also true for rtl2832? */
- /*else if (tmp == 10) {
+ } else if (tmp == 10) {
*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
FE_HAS_VITERBI;
- }*/
+ }
- return ret;
+ dev->fe_status = *status;
+ return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2832_read_snr(struct dvb_frontend *fe, u16 *snr)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
- int ret, hierarchy, constellation;
- u8 buf[2], tmp;
- u16 tmp16;
-#define CONSTELLATION_NUM 3
-#define HIERARCHY_NUM 4
- static const u32 snr_constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
- { 85387325, 85387325, 85387325, 85387325 },
- { 86676178, 86676178, 87167949, 87795660 },
- { 87659938, 87659938, 87885178, 88241743 },
- };
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
- /* reports SNR in resolution of 0.1 dB */
+ /* report SNR in resolution of 0.1 dB */
+ if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
+ *snr = div_s64(c->cnr.stat[0].svalue, 100);
+ else
+ *snr = 0;
- ret = rtl2832_rd_reg(priv, 0x3c, 3, &tmp);
- if (ret)
- goto err;
+ return 0;
+}
- constellation = (tmp >> 2) & 0x03; /* [3:2] */
- if (constellation > CONSTELLATION_NUM - 1)
- goto err;
+static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct rtl2832_dev *dev = fe->demodulator_priv;
- hierarchy = (tmp >> 4) & 0x07; /* [6:4] */
- if (hierarchy > HIERARCHY_NUM - 1)
- goto err;
+ *ber = (dev->post_bit_error - dev->post_bit_error_prev);
+ dev->post_bit_error_prev = dev->post_bit_error;
- ret = rtl2832_rd_regs(priv, 0x0c, 4, buf, 2);
- if (ret)
- goto err;
+ return 0;
+}
- tmp16 = buf[0] << 8 | buf[1];
+static void rtl2832_stat_work(struct work_struct *work)
+{
+ struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, stat_work.work);
+ struct i2c_client *client = dev->client;
+ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+ int ret, tmp;
+ u8 u8tmp, buf[2];
+ u16 u16tmp;
+
+ dev_dbg(&client->dev, "\n");
+
+ /* signal strength */
+ if (dev->fe_status & FE_HAS_SIGNAL) {
+ /* read digital AGC */
+ ret = rtl2832_bulk_read(client, 0x305, &u8tmp, 1);
+ if (ret)
+ goto err;
- if (tmp16)
- *snr = (snr_constant[constellation][hierarchy] -
- intlog10(tmp16)) / ((1 << 24) / 100);
- else
- *snr = 0;
+ dev_dbg(&client->dev, "digital agc=%02x", u8tmp);
- return 0;
+ u8tmp = ~u8tmp;
+ u16tmp = u8tmp << 8 | u8tmp << 0;
+
+ c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+ c->strength.stat[0].uvalue = u16tmp;
+ } else {
+ c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ /* CNR */
+ if (dev->fe_status & FE_HAS_VITERBI) {
+ unsigned hierarchy, constellation;
+ #define CONSTELLATION_NUM 3
+ #define HIERARCHY_NUM 4
+ static const u32 constant[CONSTELLATION_NUM][HIERARCHY_NUM] = {
+ {85387325, 85387325, 85387325, 85387325},
+ {86676178, 86676178, 87167949, 87795660},
+ {87659938, 87659938, 87885178, 88241743},
+ };
+
+ ret = rtl2832_bulk_read(client, 0x33c, &u8tmp, 1);
+ if (ret)
+ goto err;
+
+ constellation = (u8tmp >> 2) & 0x03; /* [3:2] */
+ if (constellation > CONSTELLATION_NUM - 1)
+ goto err_schedule_delayed_work;
+
+ hierarchy = (u8tmp >> 4) & 0x07; /* [6:4] */
+ if (hierarchy > HIERARCHY_NUM - 1)
+ goto err_schedule_delayed_work;
+
+ ret = rtl2832_bulk_read(client, 0x40c, buf, 2);
+ if (ret)
+ goto err;
+
+ u16tmp = buf[0] << 8 | buf[1] << 0;
+ if (u16tmp)
+ tmp = (constant[constellation][hierarchy] -
+ intlog10(u16tmp)) / ((1 << 24) / 10000);
+ else
+ tmp = 0;
+
+ dev_dbg(&client->dev, "cnr raw=%u\n", u16tmp);
+
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ c->cnr.stat[0].svalue = tmp;
+ } else {
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+ /* BER */
+ if (dev->fe_status & FE_HAS_LOCK) {
+ ret = rtl2832_bulk_read(client, 0x34e, buf, 2);
+ if (ret)
+ goto err;
+
+ u16tmp = buf[0] << 8 | buf[1] << 0;
+ dev->post_bit_error += u16tmp;
+ dev->post_bit_count += 1000000;
+
+ dev_dbg(&client->dev, "ber errors=%u total=1000000\n", u16tmp);
+
+ c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_error.stat[0].uvalue = dev->post_bit_error;
+ c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+ c->post_bit_count.stat[0].uvalue = dev->post_bit_count;
+ } else {
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ }
+
+err_schedule_delayed_work:
+ schedule_delayed_work(&dev->stat_work, msecs_to_jiffies(2000));
+ return;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
- return ret;
+ dev_dbg(&client->dev, "failed=%d\n", ret);
}
-static int rtl2832_read_ber(struct dvb_frontend *fe, u32 *ber)
+/*
+ * I2C gate/mux/repeater logic
+ * We must use unlocked __i2c_transfer() here (through regmap) because of I2C
+ * adapter lock is already taken by tuner driver.
+ * There is delay mechanism to avoid unneeded I2C gate open / close. Gate close
+ * is delayed here a little bit in order to see if there is sequence of I2C
+ * messages sent to same I2C bus.
+ */
+static void rtl2832_i2c_gate_work(struct work_struct *work)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = container_of(work, struct rtl2832_dev, i2c_gate_work.work);
+ struct i2c_client *client = dev->client;
int ret;
- u8 buf[2];
- ret = rtl2832_rd_regs(priv, 0x4e, 3, buf, 2);
+ /* close gate */
+ ret = rtl2832_update_bits(dev->client, 0x101, 0x08, 0x00);
if (ret)
goto err;
- *ber = buf[0] << 8 | buf[1];
+ return;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+}
+
+static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+{
+ struct rtl2832_dev *dev = mux_priv;
+ struct i2c_client *client = dev->client;
+ int ret;
+
+ /* terminate possible gate closing */
+ cancel_delayed_work(&dev->i2c_gate_work);
+
+ /*
+ * I2C adapter lock is already taken and due to that we will use
+ * regmap_update_bits() which does not lock again I2C adapter.
+ */
+ ret = regmap_update_bits(dev->regmap, 0x101, 0x08, 0x08);
+ if (ret)
+ goto err;
return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
-static struct dvb_frontend_ops rtl2832_ops;
+static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
+ u32 chan_id)
+{
+ struct rtl2832_dev *dev = mux_priv;
+
+ schedule_delayed_work(&dev->i2c_gate_work, usecs_to_jiffies(100));
+ return 0;
+}
+
+static struct dvb_frontend_ops rtl2832_ops = {
+ .delsys = { SYS_DVBT },
+ .info = {
+ .name = "Realtek RTL2832 (DVB-T)",
+ .frequency_min = 174000000,
+ .frequency_max = 862000000,
+ .frequency_stepsize = 166667,
+ .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_64 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_RECOVER |
+ FE_CAN_MUTE_TS
+ },
-static void rtl2832_release(struct dvb_frontend *fe)
+ .init = rtl2832_init,
+ .sleep = rtl2832_sleep,
+
+ .get_tune_settings = rtl2832_get_tune_settings,
+
+ .set_frontend = rtl2832_set_frontend,
+ .get_frontend = rtl2832_get_frontend,
+
+ .read_status = rtl2832_read_status,
+ .read_snr = rtl2832_read_snr,
+ .read_ber = rtl2832_read_ber,
+};
+
+static bool rtl2832_volatile_reg(struct device *dev, unsigned int reg)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ switch (reg) {
+ case 0x305:
+ case 0x33c:
+ case 0x34e:
+ case 0x351:
+ case 0x40c ... 0x40d:
+ return true;
+ default:
+ break;
+ }
- dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
- cancel_delayed_work_sync(&priv->i2c_gate_work);
- i2c_del_mux_adapter(priv->i2c_adapter_tuner);
- i2c_del_mux_adapter(priv->i2c_adapter);
- kfree(priv);
+ return false;
}
/*
- * Delay mechanism to avoid unneeded I2C gate open / close. Gate close is
- * delayed here a little bit in order to see if there is sequence of I2C
- * messages sent to same I2C bus.
- * We must use unlocked version of __i2c_transfer() in order to avoid deadlock
- * as lock is already taken by calling muxed i2c_transfer().
+ * We implement own I2C access routines for regmap in order to get manual access
+ * to I2C adapter lock, which is needed for I2C mux adapter.
*/
-static void rtl2832_i2c_gate_work(struct work_struct *work)
+static int rtl2832_regmap_read(void *context, const void *reg_buf,
+ size_t reg_size, void *val_buf, size_t val_size)
{
- struct rtl2832_priv *priv = container_of(work,
- struct rtl2832_priv, i2c_gate_work.work);
- struct i2c_adapter *adap = priv->i2c;
+ struct i2c_client *client = context;
int ret;
- u8 buf[2];
- struct i2c_msg msg[1] = {
+ struct i2c_msg msg[2] = {
{
- .addr = priv->cfg.i2c_addr,
+ .addr = client->addr,
.flags = 0,
- .len = sizeof(buf),
- .buf = buf,
+ .len = reg_size,
+ .buf = (u8 *)reg_buf,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = val_size,
+ .buf = val_buf,
}
};
- /* select reg bank 1 */
- buf[0] = 0x00;
- buf[1] = 0x01;
- ret = __i2c_transfer(adap, msg, 1);
- if (ret != 1)
- goto err;
-
- priv->page = 1;
-
- /* close I2C repeater gate */
- buf[0] = 0x01;
- buf[1] = 0x10;
- ret = __i2c_transfer(adap, msg, 1);
- if (ret != 1)
- goto err;
-
- priv->i2c_gate_state = false;
-
- return;
-err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
-
- return;
+ ret = __i2c_transfer(client->adapter, msg, 2);
+ if (ret != 2) {
+ dev_warn(&client->dev, "i2c reg read failed %d\n", ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ return ret;
+ }
+ return 0;
}
-static int rtl2832_select(struct i2c_adapter *adap, void *mux_priv, u32 chan_id)
+static int rtl2832_regmap_write(void *context, const void *data, size_t count)
{
- struct rtl2832_priv *priv = mux_priv;
+ struct i2c_client *client = context;
int ret;
- u8 buf[2], val;
struct i2c_msg msg[1] = {
{
- .addr = priv->cfg.i2c_addr,
+ .addr = client->addr,
.flags = 0,
- .len = sizeof(buf),
- .buf = buf,
+ .len = count,
+ .buf = (u8 *)data,
}
};
- struct i2c_msg msg_rd[2] = {
+
+ ret = __i2c_transfer(client->adapter, msg, 1);
+ if (ret != 1) {
+ dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ return ret;
+ }
+ return 0;
+}
+
+static int rtl2832_regmap_gather_write(void *context, const void *reg,
+ size_t reg_len, const void *val,
+ size_t val_len)
+{
+ struct i2c_client *client = context;
+ int ret;
+ u8 buf[256];
+ struct i2c_msg msg[1] = {
{
- .addr = priv->cfg.i2c_addr,
+ .addr = client->addr,
.flags = 0,
- .len = 1,
- .buf = "\x01",
- }, {
- .addr = priv->cfg.i2c_addr,
- .flags = I2C_M_RD,
- .len = 1,
- .buf = &val,
+ .len = 1 + val_len,
+ .buf = buf,
}
};
- /* terminate possible gate closing */
- cancel_delayed_work_sync(&priv->i2c_gate_work);
+ buf[0] = *(u8 const *)reg;
+ memcpy(&buf[1], val, val_len);
- if (priv->i2c_gate_state == chan_id)
- return 0;
-
- /* select reg bank 1 */
- buf[0] = 0x00;
- buf[1] = 0x01;
- ret = __i2c_transfer(adap, msg, 1);
- if (ret != 1)
- goto err;
-
- priv->page = 1;
+ ret = __i2c_transfer(client->adapter, msg, 1);
+ if (ret != 1) {
+ dev_warn(&client->dev, "i2c reg write failed %d\n", ret);
+ if (ret >= 0)
+ ret = -EREMOTEIO;
+ return ret;
+ }
+ return 0;
+}
- /* we must read that register, otherwise there will be errors */
- ret = __i2c_transfer(adap, msg_rd, 2);
- if (ret != 2)
- goto err;
+/*
+ * FIXME: Hack. Implement own regmap locking in order to silence lockdep
+ * recursive lock warning. That happens when regmap I2C client calls I2C mux
+ * adapter, which leads demod I2C repeater enable via demod regmap. Operation
+ * takes two regmap locks recursively - but those are different regmap instances
+ * in a two different I2C drivers, so it is not deadlock. Proper fix is to make
+ * regmap aware of lockdep.
+ */
+static void rtl2832_regmap_lock(void *__dev)
+{
+ struct rtl2832_dev *dev = __dev;
+ struct i2c_client *client = dev->client;
- /* open or close I2C repeater gate */
- buf[0] = 0x01;
- if (chan_id == 1)
- buf[1] = 0x18; /* open */
- else
- buf[1] = 0x10; /* close */
+ dev_dbg(&client->dev, "\n");
+ mutex_lock(&dev->regmap_mutex);
+}
- ret = __i2c_transfer(adap, msg, 1);
- if (ret != 1)
- goto err;
+static void rtl2832_regmap_unlock(void *__dev)
+{
+ struct rtl2832_dev *dev = __dev;
+ struct i2c_client *client = dev->client;
- priv->i2c_gate_state = chan_id;
+ dev_dbg(&client->dev, "\n");
+ mutex_unlock(&dev->regmap_mutex);
+}
- return 0;
-err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+static struct dvb_frontend *rtl2832_get_dvb_frontend(struct i2c_client *client)
+{
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
- return -EREMOTEIO;
+ dev_dbg(&client->dev, "\n");
+ return &dev->fe;
}
-static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
- u32 chan_id)
+static struct i2c_adapter *rtl2832_get_i2c_adapter(struct i2c_client *client)
{
- struct rtl2832_priv *priv = mux_priv;
- schedule_delayed_work(&priv->i2c_gate_work, usecs_to_jiffies(100));
- return 0;
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+ return dev->i2c_adapter_tuner;
}
-int rtl2832_enable_external_ts_if(struct dvb_frontend *fe)
+static int rtl2832_enable_slave_ts(struct i2c_client *client)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
int ret;
- dev_dbg(&priv->i2c->dev, "%s: setting PIP mode\n", __func__);
+ dev_dbg(&client->dev, "\n");
- ret = rtl2832_wr_regs(priv, 0x0c, 1, "\x5f\xff", 2);
+ ret = rtl2832_bulk_write(client, 0x10c, "\x5f\xff", 2);
if (ret)
goto err;
- ret = rtl2832_wr_demod_reg(priv, DVBT_PIP_ON, 0x1);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_PIP_ON, 0x1);
if (ret)
goto err;
- ret = rtl2832_wr_reg(priv, 0xbc, 0, 0x18);
+ ret = rtl2832_bulk_write(client, 0x0bc, "\x18", 1);
if (ret)
goto err;
- ret = rtl2832_wr_reg(priv, 0x22, 0, 0x01);
+ ret = rtl2832_bulk_write(client, 0x022, "\x01", 1);
if (ret)
goto err;
- ret = rtl2832_wr_reg(priv, 0x26, 0, 0x1f);
+ ret = rtl2832_bulk_write(client, 0x026, "\x1f", 1);
if (ret)
goto err;
- ret = rtl2832_wr_reg(priv, 0x27, 0, 0xff);
+ ret = rtl2832_bulk_write(client, 0x027, "\xff", 1);
if (ret)
goto err;
- ret = rtl2832_wr_regs(priv, 0x92, 1, "\x7f\xf7\xff", 3);
+ ret = rtl2832_bulk_write(client, 0x192, "\x7f\xf7\xff", 3);
if (ret)
goto err;
/* soft reset */
- ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x1);
if (ret)
goto err;
- ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+ ret = rtl2832_wr_demod_reg(dev, DVBT_SOFT_RST, 0x0);
if (ret)
goto err;
return 0;
err:
- dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
-
}
-EXPORT_SYMBOL(rtl2832_enable_external_ts_if);
-struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe)
+static int rtl2832_pid_filter_ctrl(struct dvb_frontend *fe, int onoff)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
- return priv->i2c_adapter_tuner;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
+ int ret;
+ u8 u8tmp;
+
+ dev_dbg(&client->dev, "onoff=%d\n", onoff);
+
+ /* enable / disable PID filter */
+ if (onoff)
+ u8tmp = 0x80;
+ else
+ u8tmp = 0x00;
+
+ ret = rtl2832_update_bits(client, 0x061, 0xc0, u8tmp);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
}
-EXPORT_SYMBOL(rtl2832_get_i2c_adapter);
-struct i2c_adapter *rtl2832_get_private_i2c_adapter(struct dvb_frontend *fe)
+static int rtl2832_pid_filter(struct dvb_frontend *fe, u8 index, u16 pid,
+ int onoff)
{
- struct rtl2832_priv *priv = fe->demodulator_priv;
- return priv->i2c_adapter;
+ struct rtl2832_dev *dev = fe->demodulator_priv;
+ struct i2c_client *client = dev->client;
+ int ret;
+ u8 buf[4];
+
+ dev_dbg(&client->dev, "index=%d pid=%04x onoff=%d\n",
+ index, pid, onoff);
+
+ /* skip invalid PIDs (0x2000) */
+ if (pid > 0x1fff || index > 32)
+ return 0;
+
+ if (onoff)
+ set_bit(index, &dev->filters);
+ else
+ clear_bit(index, &dev->filters);
+
+ /* enable / disable PIDs */
+ buf[0] = (dev->filters >> 0) & 0xff;
+ buf[1] = (dev->filters >> 8) & 0xff;
+ buf[2] = (dev->filters >> 16) & 0xff;
+ buf[3] = (dev->filters >> 24) & 0xff;
+ ret = rtl2832_bulk_write(client, 0x062, buf, 4);
+ if (ret)
+ goto err;
+
+ /* add PID */
+ buf[0] = (pid >> 8) & 0xff;
+ buf[1] = (pid >> 0) & 0xff;
+ ret = rtl2832_bulk_write(client, 0x066 + 2 * index, buf, 2);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
}
-EXPORT_SYMBOL(rtl2832_get_private_i2c_adapter);
-struct dvb_frontend *rtl2832_attach(const struct rtl2832_config *cfg,
- struct i2c_adapter *i2c)
+static int rtl2832_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
{
- struct rtl2832_priv *priv = NULL;
- int ret = 0;
+ struct rtl2832_platform_data *pdata = client->dev.platform_data;
+ struct i2c_adapter *i2c = client->adapter;
+ struct rtl2832_dev *dev;
+ int ret;
u8 tmp;
+ static const struct regmap_bus regmap_bus = {
+ .read = rtl2832_regmap_read,
+ .write = rtl2832_regmap_write,
+ .gather_write = rtl2832_regmap_gather_write,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ };
+ static const struct regmap_range_cfg regmap_range_cfg[] = {
+ {
+ .selector_reg = 0x00,
+ .selector_mask = 0xff,
+ .selector_shift = 0,
+ .window_start = 0,
+ .window_len = 0x100,
+ .range_min = 0 * 0x100,
+ .range_max = 5 * 0x100,
+ },
+ };
- dev_dbg(&i2c->dev, "%s:\n", __func__);
+ dev_dbg(&client->dev, "\n");
/* allocate memory for the internal state */
- priv = kzalloc(sizeof(struct rtl2832_priv), GFP_KERNEL);
- if (priv == NULL)
+ dev = kzalloc(sizeof(struct rtl2832_dev), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
goto err;
+ }
- /* setup the priv */
- priv->i2c = i2c;
- priv->tuner = cfg->tuner;
- memcpy(&priv->cfg, cfg, sizeof(struct rtl2832_config));
- INIT_DELAYED_WORK(&priv->i2c_gate_work, rtl2832_i2c_gate_work);
-
- /* create muxed i2c adapter for demod itself */
- priv->i2c_adapter = i2c_add_mux_adapter(i2c, &i2c->dev, priv, 0, 0, 0,
- rtl2832_select, NULL);
- if (priv->i2c_adapter == NULL)
- goto err;
+ /* setup the state */
+ i2c_set_clientdata(client, dev);
+ dev->client = client;
+ dev->pdata = client->dev.platform_data;
+ dev->sleeping = true;
+ INIT_DELAYED_WORK(&dev->i2c_gate_work, rtl2832_i2c_gate_work);
+ INIT_DELAYED_WORK(&dev->stat_work, rtl2832_stat_work);
+ /* create regmap */
+ mutex_init(&dev->regmap_mutex);
+ dev->regmap_config.reg_bits = 8,
+ dev->regmap_config.val_bits = 8,
+ dev->regmap_config.lock = rtl2832_regmap_lock,
+ dev->regmap_config.unlock = rtl2832_regmap_unlock,
+ dev->regmap_config.lock_arg = dev,
+ dev->regmap_config.volatile_reg = rtl2832_volatile_reg,
+ dev->regmap_config.max_register = 5 * 0x100,
+ dev->regmap_config.ranges = regmap_range_cfg,
+ dev->regmap_config.num_ranges = ARRAY_SIZE(regmap_range_cfg),
+ dev->regmap_config.cache_type = REGCACHE_RBTREE,
+ dev->regmap = regmap_init(&client->dev, &regmap_bus, client,
+ &dev->regmap_config);
+ if (IS_ERR(dev->regmap)) {
+ ret = PTR_ERR(dev->regmap);
+ goto err_kfree;
+ }
/* check if the demod is there */
- ret = rtl2832_rd_reg(priv, 0x00, 0x0, &tmp);
+ ret = rtl2832_bulk_read(client, 0x000, &tmp, 1);
if (ret)
- goto err;
+ goto err_regmap_exit;
/* create muxed i2c adapter for demod tuner bus */
- priv->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, priv,
- 0, 1, 0, rtl2832_select, rtl2832_deselect);
- if (priv->i2c_adapter_tuner == NULL)
- goto err;
+ dev->i2c_adapter_tuner = i2c_add_mux_adapter(i2c, &i2c->dev, dev,
+ 0, 0, 0, rtl2832_select, rtl2832_deselect);
+ if (dev->i2c_adapter_tuner == NULL) {
+ ret = -ENODEV;
+ goto err_regmap_exit;
+ }
/* create dvb_frontend */
- memcpy(&priv->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
- priv->fe.demodulator_priv = priv;
-
- /* TODO implement sleep mode */
- priv->sleeping = true;
-
- return &priv->fe;
+ memcpy(&dev->fe.ops, &rtl2832_ops, sizeof(struct dvb_frontend_ops));
+ dev->fe.demodulator_priv = dev;
+
+ /* setup callbacks */
+ pdata->get_dvb_frontend = rtl2832_get_dvb_frontend;
+ pdata->get_i2c_adapter = rtl2832_get_i2c_adapter;
+ pdata->enable_slave_ts = rtl2832_enable_slave_ts;
+ pdata->pid_filter = rtl2832_pid_filter;
+ pdata->pid_filter_ctrl = rtl2832_pid_filter_ctrl;
+ pdata->bulk_read = rtl2832_bulk_read;
+ pdata->bulk_write = rtl2832_bulk_write;
+ pdata->update_bits = rtl2832_update_bits;
+
+ dev_info(&client->dev, "Realtek RTL2832 successfully attached\n");
+ return 0;
+err_regmap_exit:
+ regmap_exit(dev->regmap);
+err_kfree:
+ kfree(dev);
err:
- dev_dbg(&i2c->dev, "%s: failed=%d\n", __func__, ret);
- if (priv && priv->i2c_adapter)
- i2c_del_mux_adapter(priv->i2c_adapter);
- kfree(priv);
- return NULL;
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
}
-EXPORT_SYMBOL(rtl2832_attach);
-static struct dvb_frontend_ops rtl2832_ops = {
- .delsys = { SYS_DVBT },
- .info = {
- .name = "Realtek RTL2832 (DVB-T)",
- .frequency_min = 174000000,
- .frequency_max = 862000000,
- .frequency_stepsize = 166667,
- .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_64 |
- FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO |
- FE_CAN_RECOVER |
- FE_CAN_MUTE_TS
- },
+static int rtl2832_remove(struct i2c_client *client)
+{
+ struct rtl2832_dev *dev = i2c_get_clientdata(client);
- .release = rtl2832_release,
+ dev_dbg(&client->dev, "\n");
- .init = rtl2832_init,
- .sleep = rtl2832_sleep,
+ cancel_delayed_work_sync(&dev->i2c_gate_work);
- .get_tune_settings = rtl2832_get_tune_settings,
+ i2c_del_mux_adapter(dev->i2c_adapter_tuner);
- .set_frontend = rtl2832_set_frontend,
- .get_frontend = rtl2832_get_frontend,
+ regmap_exit(dev->regmap);
- .read_status = rtl2832_read_status,
- .read_snr = rtl2832_read_snr,
- .read_ber = rtl2832_read_ber,
+ kfree(dev);
- .i2c_gate_ctrl = rtl2832_i2c_gate_ctrl,
+ return 0;
+}
+
+static const struct i2c_device_id rtl2832_id_table[] = {
+ {"rtl2832", 0},
+ {}
};
+MODULE_DEVICE_TABLE(i2c, rtl2832_id_table);
+
+static struct i2c_driver rtl2832_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "rtl2832",
+ },
+ .probe = rtl2832_probe,
+ .remove = rtl2832_remove,
+ .id_table = rtl2832_id_table,
+};
+
+module_i2c_driver(rtl2832_driver);
MODULE_AUTHOR("Thomas Mair <mair.thomas86@gmail.com>");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Realtek RTL2832 DVB-T demodulator driver");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.5");
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index 5254c1dfc8de..a8e912e679a5 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -2,6 +2,7 @@
* Realtek RTL2832 DVB-T demodulator driver
*
* Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ * Copyright (C) 2012-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
@@ -21,86 +22,42 @@
#ifndef RTL2832_H
#define RTL2832_H
-#include <linux/kconfig.h>
#include <linux/dvb/frontend.h>
+#include <linux/i2c-mux.h>
+
+/**
+ * struct rtl2832_platform_data - Platform data for the rtl2832 driver
+ * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000).
+ * @tuner: Used tuner model.
+ * @get_dvb_frontend: Get DVB frontend.
+ * @get_i2c_adapter: Get I2C adapter.
+ * @enable_slave_ts: Enable slave TS IF.
+ * @pid_filter: Set PID to PID filter.
+ * @pid_filter_ctrl: Control PID filter.
+ */
-struct rtl2832_config {
- /*
- * Demodulator I2C address.
- */
- u8 i2c_addr;
-
- /*
- * Xtal frequency.
- * Hz
- * 4000000, 16000000, 25000000, 28800000
- */
- u32 xtal;
-
+struct rtl2832_platform_data {
+ u32 clk;
/*
- * tuner
- * XXX: This must be keep sync with dvb_usb_rtl28xxu demod driver.
+ * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver.
*/
#define RTL2832_TUNER_TUA9001 0x24
#define RTL2832_TUNER_FC0012 0x26
#define RTL2832_TUNER_E4000 0x27
#define RTL2832_TUNER_FC0013 0x29
-#define RTL2832_TUNER_R820T 0x2a
-#define RTL2832_TUNER_R828D 0x2b
+#define RTL2832_TUNER_R820T 0x2a
+#define RTL2832_TUNER_R828D 0x2b
u8 tuner;
-};
-
-#if IS_ENABLED(CONFIG_DVB_RTL2832)
-struct dvb_frontend *rtl2832_attach(
- const struct rtl2832_config *cfg,
- struct i2c_adapter *i2c
-);
-
-extern struct i2c_adapter *rtl2832_get_i2c_adapter(
- struct dvb_frontend *fe
-);
-
-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(
- const struct rtl2832_config *config,
- struct i2c_adapter *i2c
-)
-{
- pr_warn("%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-
-static inline struct i2c_adapter *rtl2832_get_i2c_adapter(
- struct dvb_frontend *fe
-)
-{
- return NULL;
-}
-
-static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter(
- struct dvb_frontend *fe
-)
-{
- return NULL;
-}
-
-static inline int rtl2832_enable_external_ts_if(
- struct dvb_frontend *fe
-)
-{
- return -ENODEV;
-}
-
-#endif
+ struct dvb_frontend* (*get_dvb_frontend)(struct i2c_client *);
+ struct i2c_adapter* (*get_i2c_adapter)(struct i2c_client *);
+ int (*enable_slave_ts)(struct i2c_client *);
+ int (*pid_filter)(struct dvb_frontend *, u8, u16, int);
+ int (*pid_filter_ctrl)(struct dvb_frontend *, int);
+/* private: Register access for SDR module use only */
+ int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
+ int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
+ int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+};
#endif /* RTL2832_H */
diff --git a/drivers/media/dvb-frontends/rtl2832_priv.h b/drivers/media/dvb-frontends/rtl2832_priv.h
index ae469f032fe6..c3a922c37903 100644
--- a/drivers/media/dvb-frontends/rtl2832_priv.h
+++ b/drivers/media/dvb-frontends/rtl2832_priv.h
@@ -2,6 +2,7 @@
* Realtek RTL2832 DVB-T demodulator driver
*
* Copyright (C) 2012 Thomas Mair <thomas.mair86@gmail.com>
+ * Copyright (C) 2012-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
@@ -21,28 +22,34 @@
#ifndef RTL2832_PRIV_H
#define RTL2832_PRIV_H
+#include <linux/regmap.h>
+#include <linux/math64.h>
+#include <linux/bitops.h>
+
#include "dvb_frontend.h"
+#include "dvb_math.h"
#include "rtl2832.h"
-#include <linux/i2c-mux.h>
-struct rtl2832_priv {
- struct i2c_adapter *i2c;
- struct i2c_adapter *i2c_adapter;
+struct rtl2832_dev {
+ struct rtl2832_platform_data *pdata;
+ struct i2c_client *client;
+ struct mutex regmap_mutex;
+ struct regmap_config regmap_config;
+ struct regmap *regmap;
struct i2c_adapter *i2c_adapter_tuner;
struct dvb_frontend fe;
- struct rtl2832_config cfg;
-
- bool i2c_gate_state;
+ struct delayed_work stat_work;
+ fe_status_t fe_status;
+ u64 post_bit_error_prev; /* for old DVBv3 read_ber() calculation */
+ u64 post_bit_error;
+ u64 post_bit_count;
bool sleeping;
-
- u8 tuner;
- u8 page; /* active register page */
struct delayed_work i2c_gate_work;
+ unsigned long filters; /* PID filter */
};
struct rtl2832_reg_entry {
- u8 page;
- u8 start_address;
+ u16 start_address;
u8 msb;
u8 lsb;
};
@@ -52,7 +59,6 @@ struct rtl2832_reg_value {
u32 value;
};
-
/* Demod register bit names */
enum DVBT_REG_BIT_NAME {
DVBT_SOFT_RST,
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 2896b47c29d8..3ff8806ca584 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -22,7 +22,6 @@
*
*/
-#include "dvb_frontend.h"
#include "rtl2832_sdr.h"
#include "dvb_usb.h"
@@ -32,6 +31,7 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
+#include <linux/platform_device.h>
#include <linux/jiffies.h>
#include <linux/math64.h>
@@ -107,16 +107,12 @@ struct rtl2832_sdr_frame_buf {
struct list_head list;
};
-struct rtl2832_sdr_state {
+struct rtl2832_sdr_dev {
#define POWER_ON (1 << 1)
#define URB_BUF (1 << 2)
unsigned long flags;
- const struct rtl2832_config *cfg;
- struct dvb_frontend *fe;
- struct dvb_usb_device *d;
- struct i2c_adapter *i2c;
- u8 bank;
+ struct platform_device *pdev;
struct video_device vdev;
struct v4l2_device v4l2_dev;
@@ -160,200 +156,77 @@ struct rtl2832_sdr_state {
unsigned long jiffies_next;
};
-/* write multiple hardware registers */
-static int rtl2832_sdr_wr(struct rtl2832_sdr_state *s, u8 reg, const u8 *val,
- int len)
-{
- int ret;
-#define MAX_WR_LEN 24
-#define MAX_WR_XFER_LEN (MAX_WR_LEN + 1)
- u8 buf[MAX_WR_XFER_LEN];
- struct i2c_msg msg[1] = {
- {
- .addr = s->cfg->i2c_addr,
- .flags = 0,
- .len = 1 + len,
- .buf = buf,
- }
- };
-
- if (WARN_ON(len > MAX_WR_LEN))
- return -EINVAL;
-
- buf[0] = reg;
- memcpy(&buf[1], val, len);
-
- ret = i2c_transfer(s->i2c, msg, 1);
- if (ret == 1) {
- ret = 0;
- } else {
- dev_err(&s->i2c->dev,
- "%s: I2C wr failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
- return ret;
-}
-
-/* read multiple hardware registers */
-static int rtl2832_sdr_rd(struct rtl2832_sdr_state *s, u8 reg, u8 *val, int len)
-{
- int ret;
- struct i2c_msg msg[2] = {
- {
- .addr = s->cfg->i2c_addr,
- .flags = 0,
- .len = 1,
- .buf = &reg,
- }, {
- .addr = s->cfg->i2c_addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = val,
- }
- };
-
- ret = i2c_transfer(s->i2c, msg, 2);
- if (ret == 2) {
- ret = 0;
- } else {
- dev_err(&s->i2c->dev,
- "%s: I2C rd failed=%d reg=%02x len=%d\n",
- KBUILD_MODNAME, ret, reg, len);
- ret = -EREMOTEIO;
- }
- return ret;
-}
-
/* write multiple registers */
-static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_state *s, u16 reg,
+static int rtl2832_sdr_wr_regs(struct rtl2832_sdr_dev *dev, u16 reg,
const u8 *val, int len)
{
- int ret;
- u8 reg2 = (reg >> 0) & 0xff;
- u8 bank = (reg >> 8) & 0xff;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_client *client = pdata->i2c_client;
- /* switch bank if needed */
- if (bank != s->bank) {
- ret = rtl2832_sdr_wr(s, 0x00, &bank, 1);
- if (ret)
- return ret;
-
- s->bank = bank;
- }
-
- return rtl2832_sdr_wr(s, reg2, val, len);
+ return pdata->bulk_write(client, reg, val, len);
}
+#if 0
/* read multiple registers */
-static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_state *s, u16 reg, u8 *val,
+static int rtl2832_sdr_rd_regs(struct rtl2832_sdr_dev *dev, u16 reg, u8 *val,
int len)
{
- int ret;
- u8 reg2 = (reg >> 0) & 0xff;
- u8 bank = (reg >> 8) & 0xff;
-
- /* switch bank if needed */
- if (bank != s->bank) {
- ret = rtl2832_sdr_wr(s, 0x00, &bank, 1);
- if (ret)
- return ret;
-
- s->bank = bank;
- }
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_client *client = pdata->i2c_client;
- return rtl2832_sdr_rd(s, reg2, val, len);
+ return pdata->bulk_read(client, reg, val, len);
}
+#endif
/* write single register */
-static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_state *s, u16 reg, u8 val)
+static int rtl2832_sdr_wr_reg(struct rtl2832_sdr_dev *dev, u16 reg, u8 val)
{
- return rtl2832_sdr_wr_regs(s, reg, &val, 1);
+ return rtl2832_sdr_wr_regs(dev, reg, &val, 1);
}
-#if 0
-/* read single register */
-static int rtl2832_sdr_rd_reg(struct rtl2832_sdr_state *s, u16 reg, u8 *val)
-{
- return rtl2832_sdr_rd_regs(s, reg, val, 1);
-}
-#endif
-
/* write single register with mask */
-static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
+static int rtl2832_sdr_wr_reg_mask(struct rtl2832_sdr_dev *dev, u16 reg,
u8 val, u8 mask)
{
- int ret;
- u8 tmp;
-
- /* no need for read if whole reg is written */
- if (mask != 0xff) {
- ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1);
- if (ret)
- return ret;
-
- val &= mask;
- tmp &= ~mask;
- val |= tmp;
- }
-
- return rtl2832_sdr_wr_regs(s, reg, &val, 1);
-}
-
-#if 0
-/* read single register with mask */
-static int rtl2832_sdr_rd_reg_mask(struct rtl2832_sdr_state *s, u16 reg,
- u8 *val, u8 mask)
-{
- int ret, i;
- u8 tmp;
-
- ret = rtl2832_sdr_rd_regs(s, reg, &tmp, 1);
- if (ret)
- return ret;
-
- tmp &= mask;
-
- /* find position of the first bit */
- for (i = 0; i < 8; i++) {
- if ((mask >> i) & 0x01)
- break;
- }
- *val = tmp >> i;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct i2c_client *client = pdata->i2c_client;
- return 0;
+ return pdata->update_bits(client, reg, mask, val);
}
-#endif
/* Private functions */
static struct rtl2832_sdr_frame_buf *rtl2832_sdr_get_next_fill_buf(
- struct rtl2832_sdr_state *s)
+ struct rtl2832_sdr_dev *dev)
{
unsigned long flags;
struct rtl2832_sdr_frame_buf *buf = NULL;
- spin_lock_irqsave(&s->queued_bufs_lock, flags);
- if (list_empty(&s->queued_bufs))
+ spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+ if (list_empty(&dev->queued_bufs))
goto leave;
- buf = list_entry(s->queued_bufs.next,
+ buf = list_entry(dev->queued_bufs.next,
struct rtl2832_sdr_frame_buf, list);
list_del(&buf->list);
leave:
- spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+ spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
return buf;
}
-static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
+static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_dev *dev,
void *dst, const u8 *src, unsigned int src_len)
{
+ struct platform_device *pdev = dev->pdev;
unsigned int dst_len;
- if (s->pixelformat == V4L2_SDR_FMT_CU8) {
+ if (dev->pixelformat == V4L2_SDR_FMT_CU8) {
/* native stream, no need to convert */
memcpy(dst, src, src_len);
dst_len = src_len;
- } else if (s->pixelformat == V4L2_SDR_FMT_CU16LE) {
+ } else if (dev->pixelformat == V4L2_SDR_FMT_CU16LE) {
/* convert u8 to u16 */
unsigned int i;
u16 *u16dst = dst;
@@ -366,22 +239,21 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
}
/* calculate sample rate and output it in 10 seconds intervals */
- if (unlikely(time_is_before_jiffies(s->jiffies_next))) {
+ if (unlikely(time_is_before_jiffies(dev->jiffies_next))) {
#define MSECS 10000UL
unsigned int msecs = jiffies_to_msecs(jiffies -
- s->jiffies_next + msecs_to_jiffies(MSECS));
- unsigned int samples = s->sample - s->sample_measured;
-
- s->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
- s->sample_measured = s->sample;
- dev_dbg(&s->udev->dev,
- "slen=%u samples=%u msecs=%u sample rate=%lu\n",
- src_len, samples, msecs,
- samples * 1000UL / msecs);
+ dev->jiffies_next + msecs_to_jiffies(MSECS));
+ unsigned int samples = dev->sample - dev->sample_measured;
+
+ dev->jiffies_next = jiffies + msecs_to_jiffies(MSECS);
+ dev->sample_measured = dev->sample;
+ dev_dbg(&pdev->dev,
+ "slen=%u samples=%u msecs=%u sample rate=%lu\n",
+ src_len, samples, msecs, samples * 1000UL / msecs);
}
/* total number of I+Q pairs */
- s->sample += src_len / 2;
+ dev->sample += src_len / 2;
return dst_len;
}
@@ -392,13 +264,13 @@ static unsigned int rtl2832_sdr_convert_stream(struct rtl2832_sdr_state *s,
*/
static void rtl2832_sdr_urb_complete(struct urb *urb)
{
- struct rtl2832_sdr_state *s = urb->context;
+ struct rtl2832_sdr_dev *dev = urb->context;
+ struct platform_device *pdev = dev->pdev;
struct rtl2832_sdr_frame_buf *fbuf;
- dev_dbg_ratelimited(&s->udev->dev,
- "status=%d length=%d/%d errors=%d\n",
- urb->status, urb->actual_length,
- urb->transfer_buffer_length, urb->error_count);
+ dev_dbg_ratelimited(&pdev->dev, "status=%d length=%d/%d errors=%d\n",
+ urb->status, urb->actual_length,
+ urb->transfer_buffer_length, urb->error_count);
switch (urb->status) {
case 0: /* success */
@@ -409,8 +281,7 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- dev_err_ratelimited(&s->udev->dev, "urb failed=%d\n",
- urb->status);
+ dev_err_ratelimited(&pdev->dev, "urb failed=%d\n", urb->status);
break;
}
@@ -418,204 +289,192 @@ static void rtl2832_sdr_urb_complete(struct urb *urb)
void *ptr;
unsigned int len;
/* get free framebuffer */
- fbuf = rtl2832_sdr_get_next_fill_buf(s);
+ fbuf = rtl2832_sdr_get_next_fill_buf(dev);
if (unlikely(fbuf == NULL)) {
- s->vb_full++;
- dev_notice_ratelimited(&s->udev->dev,
- "videobuf is full, %d packets dropped\n",
- s->vb_full);
+ dev->vb_full++;
+ dev_notice_ratelimited(&pdev->dev,
+ "videobuf is full, %d packets dropped\n",
+ dev->vb_full);
goto skip;
}
/* fill framebuffer */
ptr = vb2_plane_vaddr(&fbuf->vb, 0);
- len = rtl2832_sdr_convert_stream(s, ptr, urb->transfer_buffer,
+ len = rtl2832_sdr_convert_stream(dev, ptr, urb->transfer_buffer,
urb->actual_length);
vb2_set_plane_payload(&fbuf->vb, 0, len);
v4l2_get_timestamp(&fbuf->vb.v4l2_buf.timestamp);
- fbuf->vb.v4l2_buf.sequence = s->sequence++;
+ fbuf->vb.v4l2_buf.sequence = dev->sequence++;
vb2_buffer_done(&fbuf->vb, VB2_BUF_STATE_DONE);
}
skip:
usb_submit_urb(urb, GFP_ATOMIC);
}
-static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_kill_urbs(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
int i;
- for (i = s->urbs_submitted - 1; i >= 0; i--) {
- dev_dbg(&s->udev->dev, "kill urb=%d\n", i);
+ for (i = dev->urbs_submitted - 1; i >= 0; i--) {
+ dev_dbg(&pdev->dev, "kill urb=%d\n", i);
/* stop the URB */
- usb_kill_urb(s->urb_list[i]);
+ usb_kill_urb(dev->urb_list[i]);
}
- s->urbs_submitted = 0;
+ dev->urbs_submitted = 0;
return 0;
}
-static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_submit_urbs(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
int i, ret;
- for (i = 0; i < s->urbs_initialized; i++) {
- dev_dbg(&s->udev->dev, "submit urb=%d\n", i);
- ret = usb_submit_urb(s->urb_list[i], GFP_ATOMIC);
+ for (i = 0; i < dev->urbs_initialized; i++) {
+ dev_dbg(&pdev->dev, "submit urb=%d\n", i);
+ ret = usb_submit_urb(dev->urb_list[i], GFP_ATOMIC);
if (ret) {
- dev_err(&s->udev->dev,
- "Could not submit urb no. %d - get them all back\n",
- i);
- rtl2832_sdr_kill_urbs(s);
+ dev_err(&pdev->dev,
+ "Could not submit urb no. %d - get them all back\n",
+ i);
+ rtl2832_sdr_kill_urbs(dev);
return ret;
}
- s->urbs_submitted++;
+ dev->urbs_submitted++;
}
return 0;
}
-static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_free_stream_bufs(struct rtl2832_sdr_dev *dev)
{
- if (s->flags & USB_STATE_URB_BUF) {
- while (s->buf_num) {
- s->buf_num--;
- dev_dbg(&s->udev->dev, "free buf=%d\n", s->buf_num);
- usb_free_coherent(s->udev, s->buf_size,
- s->buf_list[s->buf_num],
- s->dma_addr[s->buf_num]);
+ struct platform_device *pdev = dev->pdev;
+
+ if (dev->flags & USB_STATE_URB_BUF) {
+ while (dev->buf_num) {
+ dev->buf_num--;
+ dev_dbg(&pdev->dev, "free buf=%d\n", dev->buf_num);
+ usb_free_coherent(dev->udev, dev->buf_size,
+ dev->buf_list[dev->buf_num],
+ dev->dma_addr[dev->buf_num]);
}
}
- s->flags &= ~USB_STATE_URB_BUF;
+ dev->flags &= ~USB_STATE_URB_BUF;
return 0;
}
-static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_alloc_stream_bufs(struct rtl2832_sdr_dev *dev)
{
- s->buf_num = 0;
- s->buf_size = BULK_BUFFER_SIZE;
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "all in all I will use %u bytes for streaming\n",
- MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+ dev->buf_num = 0;
+ dev->buf_size = BULK_BUFFER_SIZE;
- for (s->buf_num = 0; s->buf_num < MAX_BULK_BUFS; s->buf_num++) {
- s->buf_list[s->buf_num] = usb_alloc_coherent(s->udev,
+ dev_dbg(&pdev->dev, "all in all I will use %u bytes for streaming\n",
+ MAX_BULK_BUFS * BULK_BUFFER_SIZE);
+
+ for (dev->buf_num = 0; dev->buf_num < MAX_BULK_BUFS; dev->buf_num++) {
+ dev->buf_list[dev->buf_num] = usb_alloc_coherent(dev->udev,
BULK_BUFFER_SIZE, GFP_ATOMIC,
- &s->dma_addr[s->buf_num]);
- if (!s->buf_list[s->buf_num]) {
- dev_dbg(&s->udev->dev, "alloc buf=%d failed\n",
- s->buf_num);
- rtl2832_sdr_free_stream_bufs(s);
+ &dev->dma_addr[dev->buf_num]);
+ if (!dev->buf_list[dev->buf_num]) {
+ dev_dbg(&pdev->dev, "alloc buf=%d failed\n",
+ dev->buf_num);
+ rtl2832_sdr_free_stream_bufs(dev);
return -ENOMEM;
}
- dev_dbg(&s->udev->dev, "alloc buf=%d %p (dma %llu)\n",
- s->buf_num, s->buf_list[s->buf_num],
- (long long)s->dma_addr[s->buf_num]);
- s->flags |= USB_STATE_URB_BUF;
+ dev_dbg(&pdev->dev, "alloc buf=%d %p (dma %llu)\n",
+ dev->buf_num, dev->buf_list[dev->buf_num],
+ (long long)dev->dma_addr[dev->buf_num]);
+ dev->flags |= USB_STATE_URB_BUF;
}
return 0;
}
-static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_free_urbs(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
int i;
- rtl2832_sdr_kill_urbs(s);
+ rtl2832_sdr_kill_urbs(dev);
- for (i = s->urbs_initialized - 1; i >= 0; i--) {
- if (s->urb_list[i]) {
- dev_dbg(&s->udev->dev, "free urb=%d\n", i);
+ for (i = dev->urbs_initialized - 1; i >= 0; i--) {
+ if (dev->urb_list[i]) {
+ dev_dbg(&pdev->dev, "free urb=%d\n", i);
/* free the URBs */
- usb_free_urb(s->urb_list[i]);
+ usb_free_urb(dev->urb_list[i]);
}
}
- s->urbs_initialized = 0;
+ dev->urbs_initialized = 0;
return 0;
}
-static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_alloc_urbs(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
int i, j;
/* allocate the URBs */
for (i = 0; i < MAX_BULK_BUFS; i++) {
- dev_dbg(&s->udev->dev, "alloc urb=%d\n", i);
- s->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
- if (!s->urb_list[i]) {
- dev_dbg(&s->udev->dev, "failed\n");
+ dev_dbg(&pdev->dev, "alloc urb=%d\n", i);
+ dev->urb_list[i] = usb_alloc_urb(0, GFP_ATOMIC);
+ if (!dev->urb_list[i]) {
+ dev_dbg(&pdev->dev, "failed\n");
for (j = 0; j < i; j++)
- usb_free_urb(s->urb_list[j]);
+ usb_free_urb(dev->urb_list[j]);
return -ENOMEM;
}
- usb_fill_bulk_urb(s->urb_list[i],
- s->udev,
- usb_rcvbulkpipe(s->udev, 0x81),
- s->buf_list[i],
+ usb_fill_bulk_urb(dev->urb_list[i],
+ dev->udev,
+ usb_rcvbulkpipe(dev->udev, 0x81),
+ dev->buf_list[i],
BULK_BUFFER_SIZE,
- rtl2832_sdr_urb_complete, s);
+ rtl2832_sdr_urb_complete, dev);
- s->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
- s->urb_list[i]->transfer_dma = s->dma_addr[i];
- s->urbs_initialized++;
+ dev->urb_list[i]->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
+ dev->urb_list[i]->transfer_dma = dev->dma_addr[i];
+ dev->urbs_initialized++;
}
return 0;
}
/* Must be called with vb_queue_lock hold */
-static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_state *s)
+static void rtl2832_sdr_cleanup_queued_bufs(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
unsigned long flags;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
- spin_lock_irqsave(&s->queued_bufs_lock, flags);
- while (!list_empty(&s->queued_bufs)) {
+ spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+ while (!list_empty(&dev->queued_bufs)) {
struct rtl2832_sdr_frame_buf *buf;
- buf = list_entry(s->queued_bufs.next,
+ buf = list_entry(dev->queued_bufs.next,
struct rtl2832_sdr_frame_buf, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
- spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
-}
-
-/* The user yanked out the cable... */
-static void rtl2832_sdr_release_sec(struct dvb_frontend *fe)
-{
- struct rtl2832_sdr_state *s = fe->sec_priv;
-
- dev_dbg(&s->udev->dev, "\n");
-
- mutex_lock(&s->vb_queue_lock);
- mutex_lock(&s->v4l2_lock);
- /* No need to keep the urbs around after disconnection */
- s->udev = NULL;
-
- v4l2_device_disconnect(&s->v4l2_dev);
- video_unregister_device(&s->vdev);
- mutex_unlock(&s->v4l2_lock);
- mutex_unlock(&s->vb_queue_lock);
-
- v4l2_device_put(&s->v4l2_dev);
-
- fe->sec_priv = NULL;
+ spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
}
static int rtl2832_sdr_querycap(struct file *file, void *fh,
struct v4l2_capability *cap)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
strlcpy(cap->driver, KBUILD_MODNAME, sizeof(cap->driver));
- strlcpy(cap->card, s->vdev.name, sizeof(cap->card));
- usb_make_path(s->udev, cap->bus_info, sizeof(cap->bus_info));
+ strlcpy(cap->card, dev->vdev.name, sizeof(cap->card));
+ usb_make_path(dev->udev, cap->bus_info, sizeof(cap->bus_info));
cap->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_STREAMING |
V4L2_CAP_READWRITE | V4L2_CAP_TUNER;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
@@ -627,26 +486,26 @@ static int rtl2832_sdr_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt, unsigned int *nbuffers,
unsigned int *nplanes, unsigned int sizes[], void *alloc_ctxs[])
{
- struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+ struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "nbuffers=%d\n", *nbuffers);
+ dev_dbg(&pdev->dev, "nbuffers=%d\n", *nbuffers);
/* Need at least 8 buffers */
if (vq->num_buffers + *nbuffers < 8)
*nbuffers = 8 - vq->num_buffers;
*nplanes = 1;
- sizes[0] = PAGE_ALIGN(s->buffersize);
- dev_dbg(&s->udev->dev, "nbuffers=%d sizes[0]=%d\n",
- *nbuffers, sizes[0]);
+ sizes[0] = PAGE_ALIGN(dev->buffersize);
+ dev_dbg(&pdev->dev, "nbuffers=%d sizes[0]=%d\n", *nbuffers, sizes[0]);
return 0;
}
static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb)
{
- struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
+ struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
/* Don't allow queing new buffers after device disconnection */
- if (!s->udev)
+ if (!dev->udev)
return -ENODEV;
return 0;
@@ -654,46 +513,48 @@ static int rtl2832_sdr_buf_prepare(struct vb2_buffer *vb)
static void rtl2832_sdr_buf_queue(struct vb2_buffer *vb)
{
- struct rtl2832_sdr_state *s = vb2_get_drv_priv(vb->vb2_queue);
+ struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct rtl2832_sdr_frame_buf *buf =
container_of(vb, struct rtl2832_sdr_frame_buf, vb);
unsigned long flags;
/* Check the device has not disconnected between prep and queuing */
- if (!s->udev) {
+ if (!dev->udev) {
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
return;
}
- spin_lock_irqsave(&s->queued_bufs_lock, flags);
- list_add_tail(&buf->list, &s->queued_bufs);
- spin_unlock_irqrestore(&s->queued_bufs_lock, flags);
+ spin_lock_irqsave(&dev->queued_bufs_lock, flags);
+ list_add_tail(&buf->list, &dev->queued_bufs);
+ spin_unlock_irqrestore(&dev->queued_bufs_lock, flags);
}
-static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_set_adc(struct rtl2832_sdr_dev *dev)
{
- struct dvb_frontend *fe = s->fe;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_frontend *fe = pdata->dvb_frontend;
int ret;
unsigned int f_sr, f_if;
u8 buf[4], u8tmp1, u8tmp2;
u64 u64tmp;
u32 u32tmp;
- dev_dbg(&s->udev->dev, "f_adc=%u\n", s->f_adc);
+ dev_dbg(&pdev->dev, "f_adc=%u\n", dev->f_adc);
- if (!test_bit(POWER_ON, &s->flags))
+ if (!test_bit(POWER_ON, &dev->flags))
return 0;
- if (s->f_adc == 0)
+ if (dev->f_adc == 0)
return 0;
- f_sr = s->f_adc;
+ f_sr = dev->f_adc;
- ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x00\x00", 2);
+ ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x00\x00", 2);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_regs(s, 0x115, "\x00\x00\x00\x00", 4);
+ ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x00\x00\x00\x00", 4);
if (ret)
goto err;
@@ -707,19 +568,19 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
goto err;
/* program IF */
- u64tmp = f_if % s->cfg->xtal;
+ u64tmp = f_if % pdata->clk;
u64tmp *= 0x400000;
- u64tmp = div_u64(u64tmp, s->cfg->xtal);
+ u64tmp = div_u64(u64tmp, pdata->clk);
u64tmp = -u64tmp;
u32tmp = u64tmp & 0x3fffff;
- dev_dbg(&s->udev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
+ dev_dbg(&pdev->dev, "f_if=%u if_ctl=%08x\n", f_if, u32tmp);
buf[0] = (u32tmp >> 16) & 0xff;
buf[1] = (u32tmp >> 8) & 0xff;
buf[2] = (u32tmp >> 0) & 0xff;
- ret = rtl2832_sdr_wr_regs(s, 0x119, buf, 3);
+ ret = rtl2832_sdr_wr_regs(dev, 0x119, buf, 3);
if (ret)
goto err;
@@ -733,208 +594,212 @@ static int rtl2832_sdr_set_adc(struct rtl2832_sdr_state *s)
u8tmp2 = 0xcd; /* enable ADC I, ADC Q */
}
- ret = rtl2832_sdr_wr_reg(s, 0x1b1, u8tmp1);
+ ret = rtl2832_sdr_wr_reg(dev, 0x1b1, u8tmp1);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_reg(s, 0x008, u8tmp2);
+ ret = rtl2832_sdr_wr_reg(dev, 0x008, u8tmp2);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_reg(s, 0x006, 0x80);
+ ret = rtl2832_sdr_wr_reg(dev, 0x006, 0x80);
if (ret)
goto err;
/* program sampling rate (resampling down) */
- u32tmp = div_u64(s->cfg->xtal * 0x400000ULL, f_sr * 4U);
+ u32tmp = div_u64(pdata->clk * 0x400000ULL, f_sr * 4U);
u32tmp <<= 2;
buf[0] = (u32tmp >> 24) & 0xff;
buf[1] = (u32tmp >> 16) & 0xff;
buf[2] = (u32tmp >> 8) & 0xff;
buf[3] = (u32tmp >> 0) & 0xff;
- ret = rtl2832_sdr_wr_regs(s, 0x19f, buf, 4);
+ ret = rtl2832_sdr_wr_regs(dev, 0x19f, buf, 4);
if (ret)
goto err;
/* low-pass filter */
- ret = rtl2832_sdr_wr_regs(s, 0x11c,
+ ret = rtl2832_sdr_wr_regs(dev, 0x11c,
"\xca\xdc\xd7\xd8\xe0\xf2\x0e\x35\x06\x50\x9c\x0d\x71\x11\x14\x71\x74\x19\x41\xa5",
20);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2);
+ ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2);
if (ret)
goto err;
/* mode */
- ret = rtl2832_sdr_wr_regs(s, 0x019, "\x05", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x05", 1);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_regs(s, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6);
+ ret = rtl2832_sdr_wr_regs(dev, 0x01a, "\x1b\x16\x0d\x06\x01\xff", 6);
if (ret)
goto err;
/* FSM */
- ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\xf0\x0f", 3);
+ ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\xf0\x0f", 3);
if (ret)
goto err;
/* PID filter */
- ret = rtl2832_sdr_wr_regs(s, 0x061, "\x60", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x061, "\x60", 1);
if (ret)
goto err;
/* used RF tuner based settings */
- switch (s->cfg->tuner) {
- case RTL2832_TUNER_E4000:
- ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x30", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x104, "\xd0", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x18", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x011, "\xd4", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x14", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xec", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x83", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x010, "\x49", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x87", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00d, "\x85", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x013, "\x02", 1);
+ switch (pdata->tuner) {
+ case RTL2832_SDR_TUNER_E4000:
+ ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x30", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xd0", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x18", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xd4", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x14", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xec", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x83", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x010, "\x49", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x87", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00d, "\x85", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x013, "\x02", 1);
break;
- case RTL2832_TUNER_FC0012:
- case RTL2832_TUNER_FC0013:
- ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x103, "\x5a", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x2c", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x16", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x011, "\xe9\xbf", 2);
- ret = rtl2832_sdr_wr_regs(s, 0x1e5, "\xf0", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1d9, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1db, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1dd, "\x11", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1de, "\xef", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1d8, "\x0c", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1e6, "\x02", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1d7, "\x09", 1);
+ case RTL2832_SDR_TUNER_FC0012:
+ case RTL2832_SDR_TUNER_FC0013:
+ ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x2c", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x16", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xe9\xbf", 2);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1e5, "\xf0", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1d9, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1db, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1dd, "\x11", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1de, "\xef", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1d8, "\x0c", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1e6, "\x02", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1d7, "\x09", 1);
break;
- case RTL2832_TUNER_R820T:
- ret = rtl2832_sdr_wr_regs(s, 0x112, "\x5a", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x102, "\x40", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x115, "\x01", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x103, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c7, "\x24", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x104, "\xcc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x105, "\xbe", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c8, "\x14", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x106, "\x35", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1c9, "\x21", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1ca, "\x21", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1cb, "\x00", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x107, "\x40", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1cd, "\x10", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x1ce, "\x10", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x108, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x109, "\x7f", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x10a, "\x80", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x10b, "\x7f", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x00e, "\xfc", 1);
- ret = rtl2832_sdr_wr_regs(s, 0x011, "\xf4", 1);
+ case RTL2832_SDR_TUNER_R820T:
+ case RTL2832_SDR_TUNER_R828D:
+ ret = rtl2832_sdr_wr_regs(dev, 0x112, "\x5a", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x102, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x01", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x103, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c7, "\x24", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x104, "\xcc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x105, "\xbe", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c8, "\x14", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x106, "\x35", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1c9, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1ca, "\x21", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1cb, "\x00", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x107, "\x40", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1cd, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x1ce, "\x10", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x108, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x109, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x10a, "\x80", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x10b, "\x7f", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x00e, "\xfc", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x011, "\xf4", 1);
break;
default:
- dev_notice(&s->udev->dev, "Unsupported tuner\n");
+ dev_notice(&pdev->dev, "Unsupported tuner\n");
}
/* software reset */
- ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x04, 0x04);
+ ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x04, 0x04);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_reg_mask(s, 0x101, 0x00, 0x04);
+ ret = rtl2832_sdr_wr_reg_mask(dev, 0x101, 0x00, 0x04);
if (ret)
goto err;
err:
return ret;
};
-static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_state *s)
+static void rtl2832_sdr_unset_adc(struct rtl2832_sdr_dev *dev)
{
+ struct platform_device *pdev = dev->pdev;
int ret;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
/* PID filter */
- ret = rtl2832_sdr_wr_regs(s, 0x061, "\xe0", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x061, "\xe0", 1);
if (ret)
goto err;
/* mode */
- ret = rtl2832_sdr_wr_regs(s, 0x019, "\x20", 1);
+ ret = rtl2832_sdr_wr_regs(dev, 0x019, "\x20", 1);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_regs(s, 0x017, "\x11\x10", 2);
+ ret = rtl2832_sdr_wr_regs(dev, 0x017, "\x11\x10", 2);
if (ret)
goto err;
/* FSM */
- ret = rtl2832_sdr_wr_regs(s, 0x192, "\x00\x0f\xff", 3);
+ ret = rtl2832_sdr_wr_regs(dev, 0x192, "\x00\x0f\xff", 3);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_regs(s, 0x13e, "\x40\x00", 2);
+ ret = rtl2832_sdr_wr_regs(dev, 0x13e, "\x40\x00", 2);
if (ret)
goto err;
- ret = rtl2832_sdr_wr_regs(s, 0x115, "\x06\x3f\xce\xcc", 4);
+ ret = rtl2832_sdr_wr_regs(dev, 0x115, "\x06\x3f\xce\xcc", 4);
if (ret)
goto err;
err:
return;
};
-static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_dev *dev)
{
- struct dvb_frontend *fe = s->fe;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_frontend *fe = pdata->dvb_frontend;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
struct v4l2_ctrl *bandwidth_auto;
struct v4l2_ctrl *bandwidth;
@@ -942,29 +807,29 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
/*
* tuner RF (Hz)
*/
- if (s->f_tuner == 0)
+ if (dev->f_tuner == 0)
return 0;
/*
* bandwidth (Hz)
*/
- bandwidth_auto = v4l2_ctrl_find(&s->hdl,
+ bandwidth_auto = v4l2_ctrl_find(&dev->hdl,
V4L2_CID_RF_TUNER_BANDWIDTH_AUTO);
- bandwidth = v4l2_ctrl_find(&s->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
+ bandwidth = v4l2_ctrl_find(&dev->hdl, V4L2_CID_RF_TUNER_BANDWIDTH);
if (v4l2_ctrl_g_ctrl(bandwidth_auto)) {
- c->bandwidth_hz = s->f_adc;
- v4l2_ctrl_s_ctrl(bandwidth, s->f_adc);
+ c->bandwidth_hz = dev->f_adc;
+ v4l2_ctrl_s_ctrl(bandwidth, dev->f_adc);
} else {
c->bandwidth_hz = v4l2_ctrl_g_ctrl(bandwidth);
}
- c->frequency = s->f_tuner;
+ c->frequency = dev->f_tuner;
c->delivery_system = SYS_DVBT;
- dev_dbg(&s->udev->dev, "frequency=%u bandwidth=%d\n",
- c->frequency, c->bandwidth_hz);
+ dev_dbg(&pdev->dev, "frequency=%u bandwidth=%d\n",
+ c->frequency, c->bandwidth_hz);
- if (!test_bit(POWER_ON, &s->flags))
+ if (!test_bit(POWER_ON, &dev->flags))
return 0;
if (fe->ops.tuner_ops.set_params)
@@ -973,11 +838,13 @@ static int rtl2832_sdr_set_tuner_freq(struct rtl2832_sdr_state *s)
return 0;
};
-static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
+static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_dev *dev)
{
- struct dvb_frontend *fe = s->fe;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_frontend *fe = pdata->dvb_frontend;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
if (fe->ops.tuner_ops.init)
fe->ops.tuner_ops.init(fe);
@@ -985,11 +852,13 @@ static int rtl2832_sdr_set_tuner(struct rtl2832_sdr_state *s)
return 0;
};
-static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
+static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_dev *dev)
{
- struct dvb_frontend *fe = s->fe;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_frontend *fe = pdata->dvb_frontend;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
if (fe->ops.tuner_ops.sleep)
fe->ops.tuner_ops.sleep(fe);
@@ -999,83 +868,89 @@ static void rtl2832_sdr_unset_tuner(struct rtl2832_sdr_state *s)
static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+ struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_usb_device *d = pdata->dvb_usb_device;
int ret;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
- if (!s->udev)
+ if (!dev->udev)
return -ENODEV;
- if (mutex_lock_interruptible(&s->v4l2_lock))
+ if (mutex_lock_interruptible(&dev->v4l2_lock))
return -ERESTARTSYS;
- if (s->d->props->power_ctrl)
- s->d->props->power_ctrl(s->d, 1);
+ if (d->props->power_ctrl)
+ d->props->power_ctrl(d, 1);
/* enable ADC */
- if (s->d->props->frontend_ctrl)
- s->d->props->frontend_ctrl(s->fe, 1);
+ if (d->props->frontend_ctrl)
+ d->props->frontend_ctrl(pdata->dvb_frontend, 1);
- set_bit(POWER_ON, &s->flags);
+ set_bit(POWER_ON, &dev->flags);
- ret = rtl2832_sdr_set_tuner(s);
+ ret = rtl2832_sdr_set_tuner(dev);
if (ret)
goto err;
- ret = rtl2832_sdr_set_tuner_freq(s);
+ ret = rtl2832_sdr_set_tuner_freq(dev);
if (ret)
goto err;
- ret = rtl2832_sdr_set_adc(s);
+ ret = rtl2832_sdr_set_adc(dev);
if (ret)
goto err;
- ret = rtl2832_sdr_alloc_stream_bufs(s);
+ ret = rtl2832_sdr_alloc_stream_bufs(dev);
if (ret)
goto err;
- ret = rtl2832_sdr_alloc_urbs(s);
+ ret = rtl2832_sdr_alloc_urbs(dev);
if (ret)
goto err;
- s->sequence = 0;
+ dev->sequence = 0;
- ret = rtl2832_sdr_submit_urbs(s);
+ ret = rtl2832_sdr_submit_urbs(dev);
if (ret)
goto err;
err:
- mutex_unlock(&s->v4l2_lock);
+ mutex_unlock(&dev->v4l2_lock);
return ret;
}
static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
{
- struct rtl2832_sdr_state *s = vb2_get_drv_priv(vq);
+ struct rtl2832_sdr_dev *dev = vb2_get_drv_priv(vq);
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_usb_device *d = pdata->dvb_usb_device;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
- mutex_lock(&s->v4l2_lock);
+ mutex_lock(&dev->v4l2_lock);
- rtl2832_sdr_kill_urbs(s);
- rtl2832_sdr_free_urbs(s);
- rtl2832_sdr_free_stream_bufs(s);
- rtl2832_sdr_cleanup_queued_bufs(s);
- rtl2832_sdr_unset_adc(s);
- rtl2832_sdr_unset_tuner(s);
+ rtl2832_sdr_kill_urbs(dev);
+ rtl2832_sdr_free_urbs(dev);
+ rtl2832_sdr_free_stream_bufs(dev);
+ rtl2832_sdr_cleanup_queued_bufs(dev);
+ rtl2832_sdr_unset_adc(dev);
+ rtl2832_sdr_unset_tuner(dev);
- clear_bit(POWER_ON, &s->flags);
+ clear_bit(POWER_ON, &dev->flags);
/* disable ADC */
- if (s->d->props->frontend_ctrl)
- s->d->props->frontend_ctrl(s->fe, 0);
+ if (d->props->frontend_ctrl)
+ d->props->frontend_ctrl(pdata->dvb_frontend, 0);
- if (s->d->props->power_ctrl)
- s->d->props->power_ctrl(s->d, 0);
+ if (d->props->power_ctrl)
+ d->props->power_ctrl(d, 0);
- mutex_unlock(&s->v4l2_lock);
+ mutex_unlock(&dev->v4l2_lock);
}
static struct vb2_ops rtl2832_sdr_vb2_ops = {
@@ -1091,9 +966,10 @@ static struct vb2_ops rtl2832_sdr_vb2_ops = {
static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *v)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "index=%d type=%d\n", v->index, v->type);
+ dev_dbg(&pdev->dev, "index=%d type=%d\n", v->index, v->type);
if (v->index == 0) {
strlcpy(v->name, "ADC: Realtek RTL2832", sizeof(v->name));
@@ -1117,9 +993,10 @@ static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *v)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
if (v->index > 1)
return -EINVAL;
@@ -1129,10 +1006,11 @@ static int rtl2832_sdr_s_tuner(struct file *file, void *priv,
static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
struct v4l2_frequency_band *band)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "tuner=%d type=%d index=%d\n",
- band->tuner, band->type, band->index);
+ dev_dbg(&pdev->dev, "tuner=%d type=%d index=%d\n",
+ band->tuner, band->type, band->index);
if (band->tuner == 0) {
if (band->index >= ARRAY_SIZE(bands_adc))
@@ -1154,17 +1032,17 @@ static int rtl2832_sdr_enum_freq_bands(struct file *file, void *priv,
static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
int ret = 0;
- dev_dbg(&s->udev->dev, "tuner=%d type=%d\n",
- f->tuner, f->type);
+ dev_dbg(&pdev->dev, "tuner=%d type=%d\n", f->tuner, f->type);
if (f->tuner == 0) {
- f->frequency = s->f_adc;
+ f->frequency = dev->f_adc;
f->type = V4L2_TUNER_ADC;
} else if (f->tuner == 1) {
- f->frequency = s->f_tuner;
+ f->frequency = dev->f_tuner;
f->type = V4L2_TUNER_RF;
} else {
return -EINVAL;
@@ -1176,11 +1054,12 @@ static int rtl2832_sdr_g_frequency(struct file *file, void *priv,
static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
int ret, band;
- dev_dbg(&s->udev->dev, "tuner=%d type=%d frequency=%u\n",
- f->tuner, f->type, f->frequency);
+ dev_dbg(&pdev->dev, "tuner=%d type=%d frequency=%u\n",
+ f->tuner, f->type, f->frequency);
/* ADC band midpoints */
#define BAND_ADC_0 ((bands_adc[0].rangehigh + bands_adc[1].rangelow) / 2)
@@ -1194,19 +1073,19 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
else
band = 2;
- s->f_adc = clamp_t(unsigned int, f->frequency,
+ dev->f_adc = clamp_t(unsigned int, f->frequency,
bands_adc[band].rangelow,
bands_adc[band].rangehigh);
- dev_dbg(&s->udev->dev, "ADC frequency=%u Hz\n", s->f_adc);
- ret = rtl2832_sdr_set_adc(s);
+ dev_dbg(&pdev->dev, "ADC frequency=%u Hz\n", dev->f_adc);
+ ret = rtl2832_sdr_set_adc(dev);
} else if (f->tuner == 1) {
- s->f_tuner = clamp_t(unsigned int, f->frequency,
+ dev->f_tuner = clamp_t(unsigned int, f->frequency,
bands_fm[0].rangelow,
bands_fm[0].rangehigh);
- dev_dbg(&s->udev->dev, "RF frequency=%u Hz\n", f->frequency);
+ dev_dbg(&pdev->dev, "RF frequency=%u Hz\n", f->frequency);
- ret = rtl2832_sdr_set_tuner_freq(s);
+ ret = rtl2832_sdr_set_tuner_freq(dev);
} else {
ret = -EINVAL;
}
@@ -1217,11 +1096,12 @@ static int rtl2832_sdr_s_frequency(struct file *file, void *priv,
static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
- if (f->index >= s->num_formats)
+ if (f->index >= dev->num_formats)
return -EINVAL;
strlcpy(f->description, formats[f->index].name, sizeof(f->description));
@@ -1233,12 +1113,13 @@ static int rtl2832_sdr_enum_fmt_sdr_cap(struct file *file, void *priv,
static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
- dev_dbg(&s->udev->dev, "\n");
+ dev_dbg(&pdev->dev, "\n");
- f->fmt.sdr.pixelformat = s->pixelformat;
- f->fmt.sdr.buffersize = s->buffersize;
+ f->fmt.sdr.pixelformat = dev->pixelformat;
+ f->fmt.sdr.buffersize = dev->buffersize;
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
@@ -1248,28 +1129,29 @@ static int rtl2832_sdr_g_fmt_sdr_cap(struct file *file, void *priv,
static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
- struct vb2_queue *q = &s->vb_queue;
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
+ struct vb2_queue *q = &dev->vb_queue;
int i;
- dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
- (char *)&f->fmt.sdr.pixelformat);
+ dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n",
+ (char *)&f->fmt.sdr.pixelformat);
if (vb2_is_busy(q))
return -EBUSY;
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
- for (i = 0; i < s->num_formats; i++) {
+ for (i = 0; i < dev->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
- s->pixelformat = formats[i].pixelformat;
- s->buffersize = formats[i].buffersize;
+ dev->pixelformat = formats[i].pixelformat;
+ dev->buffersize = formats[i].buffersize;
f->fmt.sdr.buffersize = formats[i].buffersize;
return 0;
}
}
- s->pixelformat = formats[0].pixelformat;
- s->buffersize = formats[0].buffersize;
+ dev->pixelformat = formats[0].pixelformat;
+ dev->buffersize = formats[0].buffersize;
f->fmt.sdr.pixelformat = formats[0].pixelformat;
f->fmt.sdr.buffersize = formats[0].buffersize;
@@ -1279,14 +1161,15 @@ static int rtl2832_sdr_s_fmt_sdr_cap(struct file *file, void *priv,
static int rtl2832_sdr_try_fmt_sdr_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct rtl2832_sdr_state *s = video_drvdata(file);
+ struct rtl2832_sdr_dev *dev = video_drvdata(file);
+ struct platform_device *pdev = dev->pdev;
int i;
- dev_dbg(&s->udev->dev, "pixelformat fourcc %4.4s\n",
- (char *)&f->fmt.sdr.pixelformat);
+ dev_dbg(&pdev->dev, "pixelformat fourcc %4.4s\n",
+ (char *)&f->fmt.sdr.pixelformat);
memset(f->fmt.sdr.reserved, 0, sizeof(f->fmt.sdr.reserved));
- for (i = 0; i < s->num_formats; i++) {
+ for (i = 0; i < dev->num_formats; i++) {
if (formats[i].pixelformat == f->fmt.sdr.pixelformat) {
f->fmt.sdr.buffersize = formats[i].buffersize;
return 0;
@@ -1348,37 +1231,38 @@ static struct video_device rtl2832_sdr_template = {
static int rtl2832_sdr_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct rtl2832_sdr_state *s =
- container_of(ctrl->handler, struct rtl2832_sdr_state,
+ struct rtl2832_sdr_dev *dev =
+ container_of(ctrl->handler, struct rtl2832_sdr_dev,
hdl);
- struct dvb_frontend *fe = s->fe;
+ struct platform_device *pdev = dev->pdev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
+ struct dvb_frontend *fe = pdata->dvb_frontend;
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
- dev_dbg(&s->udev->dev,
- "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
- ctrl->id, ctrl->name, ctrl->val,
- ctrl->minimum, ctrl->maximum, ctrl->step);
+ dev_dbg(&pdev->dev, "id=%d name=%s val=%d min=%lld max=%lld step=%lld\n",
+ ctrl->id, ctrl->name, ctrl->val, ctrl->minimum, ctrl->maximum,
+ ctrl->step);
switch (ctrl->id) {
case V4L2_CID_RF_TUNER_BANDWIDTH_AUTO:
case V4L2_CID_RF_TUNER_BANDWIDTH:
/* TODO: these controls should be moved to tuner drivers */
- if (s->bandwidth_auto->val) {
+ if (dev->bandwidth_auto->val) {
/* Round towards the closest legal value */
- s32 val = s->f_adc + div_u64(s->bandwidth->step, 2);
+ s32 val = dev->f_adc + div_u64(dev->bandwidth->step, 2);
u32 offset;
- val = clamp_t(s32, val, s->bandwidth->minimum,
- s->bandwidth->maximum);
- offset = val - s->bandwidth->minimum;
- offset = s->bandwidth->step *
- div_u64(offset, s->bandwidth->step);
- s->bandwidth->val = s->bandwidth->minimum + offset;
+ val = clamp_t(s32, val, dev->bandwidth->minimum,
+ dev->bandwidth->maximum);
+ offset = val - dev->bandwidth->minimum;
+ offset = dev->bandwidth->step *
+ div_u64(offset, dev->bandwidth->step);
+ dev->bandwidth->val = dev->bandwidth->minimum + offset;
}
- c->bandwidth_hz = s->bandwidth->val;
+ c->bandwidth_hz = dev->bandwidth->val;
- if (!test_bit(POWER_ON, &s->flags))
+ if (!test_bit(POWER_ON, &dev->flags))
return 0;
if (fe->ops.tuner_ops.set_params)
@@ -1399,154 +1283,195 @@ static const struct v4l2_ctrl_ops rtl2832_sdr_ctrl_ops = {
static void rtl2832_sdr_video_release(struct v4l2_device *v)
{
- struct rtl2832_sdr_state *s =
- container_of(v, struct rtl2832_sdr_state, v4l2_dev);
+ struct rtl2832_sdr_dev *dev =
+ container_of(v, struct rtl2832_sdr_dev, v4l2_dev);
+ struct platform_device *pdev = dev->pdev;
+
+ dev_dbg(&pdev->dev, "\n");
- v4l2_ctrl_handler_free(&s->hdl);
- v4l2_device_unregister(&s->v4l2_dev);
- kfree(s);
+ v4l2_ctrl_handler_free(&dev->hdl);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ kfree(dev);
}
-struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
- struct v4l2_subdev *sd)
+/* Platform driver interface */
+static int rtl2832_sdr_probe(struct platform_device *pdev)
{
- int ret;
- struct rtl2832_sdr_state *s;
+ struct rtl2832_sdr_dev *dev;
+ struct rtl2832_sdr_platform_data *pdata = pdev->dev.platform_data;
const struct v4l2_ctrl_ops *ops = &rtl2832_sdr_ctrl_ops;
- struct dvb_usb_device *d = i2c_get_adapdata(i2c);
+ struct v4l2_subdev *subdev;
+ int ret;
+
+ dev_dbg(&pdev->dev, "\n");
- s = kzalloc(sizeof(struct rtl2832_sdr_state), GFP_KERNEL);
- if (s == NULL) {
- dev_err(&d->udev->dev,
- "Could not allocate memory for rtl2832_sdr_state\n");
- return NULL;
+ if (!pdata) {
+ dev_err(&pdev->dev, "Cannot proceed without platform data\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ if (!pdev->dev.parent->driver) {
+ dev_dbg(&pdev->dev, "No parent device\n");
+ ret = -EINVAL;
+ goto err;
+ }
+ /* try to refcount host drv since we are the consumer */
+ if (!try_module_get(pdev->dev.parent->driver->owner)) {
+ dev_err(&pdev->dev, "Refcount fail");
+ ret = -EINVAL;
+ goto err;
+ }
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
+ goto err_module_put;
}
/* setup the state */
- s->fe = fe;
- s->d = d;
- s->udev = d->udev;
- s->i2c = i2c;
- s->cfg = cfg;
- s->f_adc = bands_adc[0].rangelow;
- s->f_tuner = bands_fm[0].rangelow;
- s->pixelformat = formats[0].pixelformat;
- s->buffersize = formats[0].buffersize;
- s->num_formats = NUM_FORMATS;
+ subdev = pdata->v4l2_subdev;
+ dev->pdev = pdev;
+ dev->udev = pdata->dvb_usb_device->udev;
+ dev->f_adc = bands_adc[0].rangelow;
+ dev->f_tuner = bands_fm[0].rangelow;
+ dev->pixelformat = formats[0].pixelformat;
+ dev->buffersize = formats[0].buffersize;
+ dev->num_formats = NUM_FORMATS;
if (!rtl2832_sdr_emulated_fmt)
- s->num_formats -= 1;
+ dev->num_formats -= 1;
- mutex_init(&s->v4l2_lock);
- mutex_init(&s->vb_queue_lock);
- spin_lock_init(&s->queued_bufs_lock);
- INIT_LIST_HEAD(&s->queued_bufs);
+ mutex_init(&dev->v4l2_lock);
+ mutex_init(&dev->vb_queue_lock);
+ spin_lock_init(&dev->queued_bufs_lock);
+ INIT_LIST_HEAD(&dev->queued_bufs);
/* Init videobuf2 queue structure */
- s->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
- s->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
- s->vb_queue.drv_priv = s;
- s->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf);
- s->vb_queue.ops = &rtl2832_sdr_vb2_ops;
- s->vb_queue.mem_ops = &vb2_vmalloc_memops;
- s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- ret = vb2_queue_init(&s->vb_queue);
+ dev->vb_queue.type = V4L2_BUF_TYPE_SDR_CAPTURE;
+ dev->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
+ dev->vb_queue.drv_priv = dev;
+ dev->vb_queue.buf_struct_size = sizeof(struct rtl2832_sdr_frame_buf);
+ dev->vb_queue.ops = &rtl2832_sdr_vb2_ops;
+ dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
+ dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ ret = vb2_queue_init(&dev->vb_queue);
if (ret) {
- dev_err(&s->udev->dev, "Could not initialize vb2 queue\n");
- goto err_free_mem;
+ dev_err(&pdev->dev, "Could not initialize vb2 queue\n");
+ goto err_kfree;
}
/* Register controls */
- switch (s->cfg->tuner) {
- case RTL2832_TUNER_E4000:
- v4l2_ctrl_handler_init(&s->hdl, 9);
- if (sd)
- v4l2_ctrl_add_handler(&s->hdl, sd->ctrl_handler, NULL);
+ switch (pdata->tuner) {
+ case RTL2832_SDR_TUNER_E4000:
+ v4l2_ctrl_handler_init(&dev->hdl, 9);
+ if (subdev)
+ v4l2_ctrl_add_handler(&dev->hdl, subdev->ctrl_handler, NULL);
break;
- case RTL2832_TUNER_R820T:
- v4l2_ctrl_handler_init(&s->hdl, 2);
- s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
- 0, 1, 1, 1);
- s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH,
- 0, 8000000, 100000, 0);
- v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ case RTL2832_SDR_TUNER_R820T:
+ case RTL2832_SDR_TUNER_R828D:
+ v4l2_ctrl_handler_init(&dev->hdl, 2);
+ dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+ 0, 1, 1, 1);
+ dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH,
+ 0, 8000000, 100000, 0);
+ v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
break;
- case RTL2832_TUNER_FC0012:
- case RTL2832_TUNER_FC0013:
- v4l2_ctrl_handler_init(&s->hdl, 2);
- s->bandwidth_auto = v4l2_ctrl_new_std(&s->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
- 0, 1, 1, 1);
- s->bandwidth = v4l2_ctrl_new_std(&s->hdl, ops,
- V4L2_CID_RF_TUNER_BANDWIDTH,
- 6000000, 8000000, 1000000,
- 6000000);
- v4l2_ctrl_auto_cluster(2, &s->bandwidth_auto, 0, false);
+ case RTL2832_SDR_TUNER_FC0012:
+ case RTL2832_SDR_TUNER_FC0013:
+ v4l2_ctrl_handler_init(&dev->hdl, 2);
+ dev->bandwidth_auto = v4l2_ctrl_new_std(&dev->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH_AUTO,
+ 0, 1, 1, 1);
+ dev->bandwidth = v4l2_ctrl_new_std(&dev->hdl, ops,
+ V4L2_CID_RF_TUNER_BANDWIDTH,
+ 6000000, 8000000, 1000000,
+ 6000000);
+ v4l2_ctrl_auto_cluster(2, &dev->bandwidth_auto, 0, false);
break;
default:
- v4l2_ctrl_handler_init(&s->hdl, 0);
- dev_notice(&s->udev->dev, "%s: Unsupported tuner\n",
- KBUILD_MODNAME);
- goto err_free_controls;
+ v4l2_ctrl_handler_init(&dev->hdl, 0);
+ dev_err(&pdev->dev, "Unsupported tuner\n");
+ goto err_v4l2_ctrl_handler_free;
}
-
- if (s->hdl.error) {
- ret = s->hdl.error;
- dev_err(&s->udev->dev, "Could not initialize controls\n");
- goto err_free_controls;
+ if (dev->hdl.error) {
+ ret = dev->hdl.error;
+ dev_err(&pdev->dev, "Could not initialize controls\n");
+ goto err_v4l2_ctrl_handler_free;
}
/* Init video_device structure */
- s->vdev = rtl2832_sdr_template;
- s->vdev.queue = &s->vb_queue;
- s->vdev.queue->lock = &s->vb_queue_lock;
- video_set_drvdata(&s->vdev, s);
+ dev->vdev = rtl2832_sdr_template;
+ dev->vdev.queue = &dev->vb_queue;
+ dev->vdev.queue->lock = &dev->vb_queue_lock;
+ video_set_drvdata(&dev->vdev, dev);
/* Register the v4l2_device structure */
- s->v4l2_dev.release = rtl2832_sdr_video_release;
- ret = v4l2_device_register(&s->udev->dev, &s->v4l2_dev);
+ dev->v4l2_dev.release = rtl2832_sdr_video_release;
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret) {
- dev_err(&s->udev->dev,
- "Failed to register v4l2-device (%d)\n", ret);
- goto err_free_controls;
+ dev_err(&pdev->dev, "Failed to register v4l2-device %d\n", ret);
+ goto err_v4l2_ctrl_handler_free;
}
- s->v4l2_dev.ctrl_handler = &s->hdl;
- s->vdev.v4l2_dev = &s->v4l2_dev;
- s->vdev.lock = &s->v4l2_lock;
- s->vdev.vfl_dir = VFL_DIR_RX;
+ dev->v4l2_dev.ctrl_handler = &dev->hdl;
+ dev->vdev.v4l2_dev = &dev->v4l2_dev;
+ dev->vdev.lock = &dev->v4l2_lock;
+ dev->vdev.vfl_dir = VFL_DIR_RX;
- ret = video_register_device(&s->vdev, VFL_TYPE_SDR, -1);
+ ret = video_register_device(&dev->vdev, VFL_TYPE_SDR, -1);
if (ret) {
- dev_err(&s->udev->dev,
- "Failed to register as video device (%d)\n",
- ret);
- goto err_unregister_v4l2_dev;
+ dev_err(&pdev->dev, "Failed to register as video device %d\n",
+ ret);
+ goto err_v4l2_device_unregister;
}
- dev_info(&s->udev->dev, "Registered as %s\n",
- video_device_node_name(&s->vdev));
-
- fe->sec_priv = s;
- fe->ops.release_sec = rtl2832_sdr_release_sec;
-
- dev_info(&s->i2c->dev, "%s: Realtek RTL2832 SDR attached\n",
- KBUILD_MODNAME);
- dev_notice(&s->udev->dev,
- "%s: SDR API is still slightly experimental and functionality changes may follow\n",
- KBUILD_MODNAME);
- return fe;
-
-err_unregister_v4l2_dev:
- v4l2_device_unregister(&s->v4l2_dev);
-err_free_controls:
- v4l2_ctrl_handler_free(&s->hdl);
-err_free_mem:
- kfree(s);
- return NULL;
+ dev_info(&pdev->dev, "Registered as %s\n",
+ video_device_node_name(&dev->vdev));
+ dev_info(&pdev->dev, "Realtek RTL2832 SDR attached\n");
+ dev_notice(&pdev->dev,
+ "SDR API is still slightly experimental and functionality changes may follow\n");
+ platform_set_drvdata(pdev, dev);
+ return 0;
+err_v4l2_device_unregister:
+ v4l2_device_unregister(&dev->v4l2_dev);
+err_v4l2_ctrl_handler_free:
+ v4l2_ctrl_handler_free(&dev->hdl);
+err_kfree:
+ kfree(dev);
+err_module_put:
+ module_put(pdev->dev.parent->driver->owner);
+err:
+ return ret;
}
-EXPORT_SYMBOL(rtl2832_sdr_attach);
+
+static int rtl2832_sdr_remove(struct platform_device *pdev)
+{
+ struct rtl2832_sdr_dev *dev = platform_get_drvdata(pdev);
+
+ dev_dbg(&pdev->dev, "\n");
+
+ mutex_lock(&dev->vb_queue_lock);
+ mutex_lock(&dev->v4l2_lock);
+ /* No need to keep the urbs around after disconnection */
+ dev->udev = NULL;
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ video_unregister_device(&dev->vdev);
+ mutex_unlock(&dev->v4l2_lock);
+ mutex_unlock(&dev->vb_queue_lock);
+ v4l2_device_put(&dev->v4l2_dev);
+ module_put(pdev->dev.parent->driver->owner);
+
+ return 0;
+}
+
+static struct platform_driver rtl2832_sdr_driver = {
+ .driver = {
+ .name = "rtl2832_sdr",
+ .owner = THIS_MODULE,
+ },
+ .probe = rtl2832_sdr_probe,
+ .remove = rtl2832_sdr_remove,
+};
+module_platform_driver(rtl2832_sdr_driver);
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Realtek RTL2832 SDR driver");
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.h b/drivers/media/dvb-frontends/rtl2832_sdr.h
index b865fadf184f..d2594768bff2 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.h
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.h
@@ -20,35 +20,48 @@
* GNU Radio plugin "gr-kernel" for device usage will be on:
* http://git.linuxtv.org/anttip/gr-kernel.git
*
- * TODO:
- * Help is very highly welcome for these + all the others you could imagine:
- * - move controls to V4L2 API
- * - use libv4l2 for stream format conversions
- * - gr-kernel: switch to v4l2_mmap (current read eats a lot of cpu)
- * - SDRSharp support
*/
#ifndef RTL2832_SDR_H
#define RTL2832_SDR_H
-#include <linux/kconfig.h>
+#include <linux/i2c.h>
#include <media/v4l2-subdev.h>
+#include "dvb_frontend.h"
-/* for config struct */
-#include "rtl2832.h"
+/**
+ * struct rtl2832_sdr_platform_data - Platform data for the rtl2832_sdr driver
+ * @clk: Clock frequency (4000000, 16000000, 25000000, 28800000).
+ * @tuner: Used tuner model.
+ * @i2c_client: rtl2832 demod driver I2C client.
+ * @bulk_read: rtl2832 driver private I/O interface.
+ * @bulk_write: rtl2832 driver private I/O interface.
+ * @update_bits: rtl2832 driver private I/O interface.
+ * @dvb_frontend: rtl2832 DVB frontend.
+ * @v4l2_subdev: Tuner v4l2 controls.
+ * @dvb_usb_device: DVB USB interface for USB streaming.
+ */
+
+struct rtl2832_sdr_platform_data {
+ u32 clk;
+ /*
+ * XXX: This list must be kept sync with dvb_usb_rtl28xxu USB IF driver.
+ */
+#define RTL2832_SDR_TUNER_TUA9001 0x24
+#define RTL2832_SDR_TUNER_FC0012 0x26
+#define RTL2832_SDR_TUNER_E4000 0x27
+#define RTL2832_SDR_TUNER_FC0013 0x29
+#define RTL2832_SDR_TUNER_R820T 0x2a
+#define RTL2832_SDR_TUNER_R828D 0x2b
+ u8 tuner;
-#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR)
-extern 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)
-{
- dev_warn(&i2c->dev, "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif
+ struct i2c_client *i2c_client;
+ int (*bulk_read)(struct i2c_client *, unsigned int, void *, size_t);
+ int (*bulk_write)(struct i2c_client *, unsigned int, const void *, size_t);
+ int (*update_bits)(struct i2c_client *, unsigned int, unsigned int, unsigned int);
+ struct dvb_frontend *dvb_frontend;
+ struct v4l2_subdev *v4l2_subdev;
+ struct dvb_usb_device *dvb_usb_device;
+};
#endif /* RTL2832_SDR_H */
diff --git a/drivers/media/dvb-frontends/s5h1409.c b/drivers/media/dvb-frontends/s5h1409.c
index f71b06221e14..5ff474a7ff29 100644
--- a/drivers/media/dvb-frontends/s5h1409.c
+++ b/drivers/media/dvb-frontends/s5h1409.c
@@ -1021,9 +1021,3 @@ static struct dvb_frontend_ops s5h1409_ops = {
MODULE_DESCRIPTION("Samsung S5H1409 QAM-B/ATSC Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb-frontends/s5h1409.h b/drivers/media/dvb-frontends/s5h1409.h
index 63b1e0a34e4e..9e143f5c8107 100644
--- a/drivers/media/dvb-frontends/s5h1409.h
+++ b/drivers/media/dvb-frontends/s5h1409.h
@@ -81,8 +81,3 @@ static inline struct dvb_frontend *s5h1409_attach(
#endif /* CONFIG_DVB_S5H1409 */
#endif /* __S5H1409_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb-frontends/s5h1411.c b/drivers/media/dvb-frontends/s5h1411.c
index 6cc4b7a9dd60..64f35fed7ae1 100644
--- a/drivers/media/dvb-frontends/s5h1411.c
+++ b/drivers/media/dvb-frontends/s5h1411.c
@@ -944,8 +944,3 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages");
MODULE_DESCRIPTION("Samsung S5H1411 QAM-B/ATSC Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb-frontends/s5h1411.h b/drivers/media/dvb-frontends/s5h1411.h
index e4f56871f982..1d7deb615674 100644
--- a/drivers/media/dvb-frontends/s5h1411.h
+++ b/drivers/media/dvb-frontends/s5h1411.h
@@ -83,8 +83,3 @@ static inline struct dvb_frontend *s5h1411_attach(
#endif /* CONFIG_DVB_S5H1411 */
#endif /* __S5H1411_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index ce9ab442b4b6..5db588ebfc24 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -19,16 +19,17 @@
static const struct dvb_frontend_ops si2168_ops;
/* execute firmware command */
-static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
+static int si2168_cmd_execute(struct i2c_client *client, struct si2168_cmd *cmd)
{
+ struct si2168_dev *dev = i2c_get_clientdata(client);
int ret;
unsigned long timeout;
- mutex_lock(&s->i2c_mutex);
+ mutex_lock(&dev->i2c_mutex);
if (cmd->wlen) {
/* write cmd and args for firmware */
- ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
+ ret = i2c_master_send(client, cmd->args, cmd->wlen);
if (ret < 0) {
goto err_mutex_unlock;
} else if (ret != cmd->wlen) {
@@ -39,10 +40,10 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
if (cmd->rlen) {
/* wait cmd execution terminate */
- #define TIMEOUT 50
+ #define TIMEOUT 70
timeout = jiffies + msecs_to_jiffies(TIMEOUT);
while (!time_after(jiffies, timeout)) {
- ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
+ ret = i2c_master_recv(client, cmd->args, cmd->rlen);
if (ret < 0) {
goto err_mutex_unlock;
} else if (ret != cmd->rlen) {
@@ -55,7 +56,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
break;
}
- dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
+ dev_dbg(&client->dev, "cmd execution took %d ms\n",
jiffies_to_msecs(jiffies) -
(jiffies_to_msecs(timeout) - TIMEOUT));
@@ -65,29 +66,26 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd)
}
}
- ret = 0;
+ mutex_unlock(&dev->i2c_mutex);
+ return 0;
err_mutex_unlock:
- mutex_unlock(&s->i2c_mutex);
- if (ret)
- goto err;
-
- return 0;
-err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ mutex_unlock(&dev->i2c_mutex);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
{
- struct si2168 *s = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
struct si2168_cmd cmd;
*status = 0;
- if (!s->active) {
+ if (!dev->active) {
ret = -EAGAIN;
goto err;
}
@@ -113,21 +111,10 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
goto err;
}
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
- /*
- * Possible values seen, in order from strong signal to weak:
- * 16 0001 0110 full lock
- * 1e 0001 1110 partial lock
- * 1a 0001 1010 partial lock
- * 18 0001 1000 no lock
- *
- * [b3:b1] lock bits
- * [b4] statistics ready? Set in a few secs after lock is gained.
- */
-
switch ((cmd.args[2] >> 1) & 0x03) {
case 0x01:
*status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
@@ -138,7 +125,7 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
break;
}
- s->fe_status = *status;
+ dev->fe_status = *status;
if (*status & FE_HAS_LOCK) {
c->cnr.len = 1;
@@ -149,30 +136,31 @@ static int si2168_read_status(struct dvb_frontend *fe, fe_status_t *status)
c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
}
- dev_dbg(&s->client->dev, "status=%02x args=%*ph\n",
+ dev_dbg(&client->dev, "status=%02x args=%*ph\n",
*status, cmd.rlen, cmd.args);
return 0;
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2168_set_frontend(struct dvb_frontend *fe)
{
- struct si2168 *s = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
struct si2168_cmd cmd;
u8 bandwidth, delivery_system;
- dev_dbg(&s->client->dev,
- "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u, stream_id=%d\n",
- c->delivery_system, c->modulation,
- c->frequency, c->bandwidth_hz, c->symbol_rate,
- c->inversion, c->stream_id);
+ dev_dbg(&client->dev,
+ "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%u stream_id=%u\n",
+ c->delivery_system, c->modulation, c->frequency,
+ c->bandwidth_hz, c->symbol_rate, c->inversion,
+ c->stream_id);
- if (!s->active) {
+ if (!dev->active) {
ret = -EAGAIN;
goto err;
}
@@ -192,7 +180,12 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
goto err;
}
- if (c->bandwidth_hz <= 5000000)
+ if (c->bandwidth_hz == 0) {
+ ret = -EINVAL;
+ goto err;
+ } else if (c->bandwidth_hz <= 2000000)
+ bandwidth = 0x02;
+ else if (c->bandwidth_hz <= 5000000)
bandwidth = 0x05;
else if (c->bandwidth_hz <= 6000000)
bandwidth = 0x06;
@@ -217,7 +210,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
memcpy(cmd.args, "\x88\x02\x02\x02\x02", 5);
cmd.wlen = 5;
cmd.rlen = 5;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -230,7 +223,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
memcpy(cmd.args, "\x89\x21\x06\x11\x89\x20", 6);
cmd.wlen = 6;
cmd.rlen = 3;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -241,7 +234,7 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
cmd.args[2] = c->stream_id == NO_STREAM_ID_FILTER ? 0 : 1;
cmd.wlen = 3;
cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
}
@@ -249,35 +242,35 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
memcpy(cmd.args, "\x51\x03", 2);
cmd.wlen = 2;
cmd.rlen = 12;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x12\x08\x04", 3);
cmd.wlen = 3;
cmd.rlen = 3;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x0c\x10\x12\x00", 6);
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x06\x10\x24\x00", 6);
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x07\x10\x00\x24", 6);
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -285,18 +278,18 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
cmd.args[4] = delivery_system | bandwidth;
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
/* set DVB-C symbol rate */
if (c->delivery_system == SYS_DVBC_ANNEX_A) {
memcpy(cmd.args, "\x14\x00\x02\x11", 4);
- cmd.args[4] = (c->symbol_rate / 1000) & 0xff;
+ cmd.args[4] = ((c->symbol_rate / 1000) >> 0) & 0xff;
cmd.args[5] = ((c->symbol_rate / 1000) >> 8) & 0xff;
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
}
@@ -304,88 +297,88 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
memcpy(cmd.args, "\x14\x00\x0f\x10\x10\x00", 6);
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6);
- cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10;
+ cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10;
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6);
- cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10;
+ cmd.args[5] |= dev->ts_clock_inv ? 0x00 : 0x10;
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x01\x12\x00\x00", 6);
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x14\x00\x01\x03\x0c\x00", 6);
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x85", 1);
cmd.wlen = 1;
cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
- s->delivery_system = c->delivery_system;
+ dev->delivery_system = c->delivery_system;
return 0;
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2168_init(struct dvb_frontend *fe)
{
- struct si2168 *s = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
int ret, len, remaining;
- const struct firmware *fw = NULL;
- u8 *fw_file;
- const unsigned int i2c_wr_max = 8;
+ const struct firmware *fw;
+ const char *fw_name;
struct si2168_cmd cmd;
unsigned int chip_id;
- dev_dbg(&s->client->dev, "\n");
+ dev_dbg(&client->dev, "\n");
/* initialize */
memcpy(cmd.args, "\xc0\x12\x00\x0c\x00\x0d\x16\x00\x00\x00\x00\x00\x00", 13);
cmd.wlen = 13;
cmd.rlen = 0;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
- if (s->fw_loaded) {
+ if (dev->fw_loaded) {
/* resume */
memcpy(cmd.args, "\xc0\x06\x08\x0f\x00\x20\x21\x01", 8);
cmd.wlen = 8;
cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
memcpy(cmd.args, "\x85", 1);
cmd.wlen = 1;
cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -396,7 +389,7 @@ static int si2168_init(struct dvb_frontend *fe)
memcpy(cmd.args, "\xc0\x06\x01\x0f\x00\x20\x20\x01", 8);
cmd.wlen = 8;
cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -404,7 +397,7 @@ static int si2168_init(struct dvb_frontend *fe)
memcpy(cmd.args, "\x02", 1);
cmd.wlen = 1;
cmd.rlen = 13;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -417,50 +410,48 @@ static int si2168_init(struct dvb_frontend *fe)
switch (chip_id) {
case SI2168_A20:
- fw_file = SI2168_A20_FIRMWARE;
+ fw_name = SI2168_A20_FIRMWARE;
break;
case SI2168_A30:
- fw_file = SI2168_A30_FIRMWARE;
+ fw_name = SI2168_A30_FIRMWARE;
break;
case SI2168_B40:
- fw_file = SI2168_B40_FIRMWARE;
+ fw_name = SI2168_B40_FIRMWARE;
break;
default:
- dev_err(&s->client->dev,
- "unknown chip version Si21%d-%c%c%c\n",
+ dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
cmd.args[2], cmd.args[1],
cmd.args[3], cmd.args[4]);
ret = -EINVAL;
goto err;
}
- /* cold state - try to download firmware */
- dev_info(&s->client->dev, "found a '%s' in cold state\n",
- si2168_ops.info.name);
+ dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
+ cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
/* request the firmware, this will block and timeout */
- ret = request_firmware(&fw, fw_file, &s->client->dev);
+ ret = request_firmware(&fw, fw_name, &client->dev);
if (ret) {
/* fallback mechanism to handle old name for Si2168 B40 fw */
if (chip_id == SI2168_B40) {
- fw_file = SI2168_B40_FIRMWARE_FALLBACK;
- ret = request_firmware(&fw, fw_file, &s->client->dev);
+ fw_name = SI2168_B40_FIRMWARE_FALLBACK;
+ ret = request_firmware(&fw, fw_name, &client->dev);
}
if (ret == 0) {
- dev_notice(&s->client->dev,
+ dev_notice(&client->dev,
"please install firmware file '%s'\n",
SI2168_B40_FIRMWARE);
} else {
- dev_err(&s->client->dev,
+ dev_err(&client->dev,
"firmware file '%s' not found\n",
- fw_file);
- goto error_fw_release;
+ fw_name);
+ goto err_release_firmware;
}
}
- dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
- fw_file);
+ dev_info(&client->dev, "downloading firmware from file '%s'\n",
+ fw_name);
if ((fw->size % 17 == 0) && (fw->data[0] > 5)) {
/* firmware is in the new format */
@@ -469,41 +460,37 @@ static int si2168_init(struct dvb_frontend *fe)
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;
- }
+ ret = si2168_cmd_execute(client, &cmd);
+ if (ret)
+ break;
}
- } else {
+ } else if (fw->size % 8 == 0) {
/* 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;
-
+ for (remaining = fw->size; remaining > 0; remaining -= 8) {
+ len = 8;
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;
- }
+ ret = si2168_cmd_execute(client, &cmd);
+ if (ret)
+ break;
}
+ } else {
+ /* bad or unknown firmware format */
+ ret = -EINVAL;
+ }
+
+ if (ret) {
+ dev_err(&client->dev, "firmware download failed %d\n", ret);
+ goto err_release_firmware;
}
release_firmware(fw);
- fw = NULL;
memcpy(cmd.args, "\x01\x01", 2);
cmd.wlen = 2;
cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -511,58 +498,56 @@ static int si2168_init(struct dvb_frontend *fe)
memcpy(cmd.args, "\x11", 1);
cmd.wlen = 1;
cmd.rlen = 10;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
- dev_dbg(&s->client->dev, "firmware version: %c.%c.%d\n",
+ dev_info(&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;
+ cmd.args[4] |= dev->ts_mode;
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
- s->fw_loaded = true;
-
- dev_info(&s->client->dev, "found a '%s' in warm state\n",
- si2168_ops.info.name);
+ dev->fw_loaded = true;
warm:
- s->active = true;
+ dev->active = true;
return 0;
-error_fw_release:
+err_release_firmware:
release_firmware(fw);
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2168_sleep(struct dvb_frontend *fe)
{
- struct si2168 *s = fe->demodulator_priv;
+ struct i2c_client *client = fe->demodulator_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
int ret;
struct si2168_cmd cmd;
- dev_dbg(&s->client->dev, "\n");
+ dev_dbg(&client->dev, "\n");
- s->active = false;
+ dev->active = false;
memcpy(cmd.args, "\x13", 1);
cmd.wlen = 1;
cmd.rlen = 0;
- ret = si2168_cmd_execute(s, &cmd);
+ ret = si2168_cmd_execute(client, &cmd);
if (ret)
goto err;
return 0;
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
@@ -581,21 +566,22 @@ static int si2168_get_tune_settings(struct dvb_frontend *fe,
*/
static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
{
- struct si2168 *s = mux_priv;
+ struct i2c_client *client = mux_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
int ret;
struct i2c_msg gate_open_msg = {
- .addr = s->client->addr,
+ .addr = client->addr,
.flags = 0,
.len = 3,
.buf = "\xc0\x0d\x01",
};
- mutex_lock(&s->i2c_mutex);
+ mutex_lock(&dev->i2c_mutex);
/* open tuner I2C gate */
- ret = __i2c_transfer(s->client->adapter, &gate_open_msg, 1);
+ ret = __i2c_transfer(client->adapter, &gate_open_msg, 1);
if (ret != 1) {
- dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
+ dev_warn(&client->dev, "i2c write failed=%d\n", ret);
if (ret >= 0)
ret = -EREMOTEIO;
} else {
@@ -607,26 +593,27 @@ static int si2168_select(struct i2c_adapter *adap, void *mux_priv, u32 chan)
static int si2168_deselect(struct i2c_adapter *adap, void *mux_priv, u32 chan)
{
- struct si2168 *s = mux_priv;
+ struct i2c_client *client = mux_priv;
+ struct si2168_dev *dev = i2c_get_clientdata(client);
int ret;
struct i2c_msg gate_close_msg = {
- .addr = s->client->addr,
+ .addr = client->addr,
.flags = 0,
.len = 3,
.buf = "\xc0\x0d\x00",
};
/* close tuner I2C gate */
- ret = __i2c_transfer(s->client->adapter, &gate_close_msg, 1);
+ ret = __i2c_transfer(client->adapter, &gate_close_msg, 1);
if (ret != 1) {
- dev_warn(&s->client->dev, "i2c write failed=%d\n", ret);
+ dev_warn(&client->dev, "i2c write failed=%d\n", ret);
if (ret >= 0)
ret = -EREMOTEIO;
} else {
ret = 0;
}
- mutex_unlock(&s->i2c_mutex);
+ mutex_unlock(&dev->i2c_mutex);
return ret;
}
@@ -635,6 +622,8 @@ static const struct dvb_frontend_ops si2168_ops = {
.delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
.info = {
.name = "Silicon Labs Si2168",
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 7200000,
.caps = FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
@@ -670,71 +659,69 @@ static int si2168_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct si2168_config *config = client->dev.platform_data;
- struct si2168 *s;
+ struct si2168_dev *dev;
int ret;
dev_dbg(&client->dev, "\n");
- s = kzalloc(sizeof(struct si2168), GFP_KERNEL);
- if (!s) {
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
ret = -ENOMEM;
dev_err(&client->dev, "kzalloc() failed\n");
goto err;
}
- s->client = client;
- mutex_init(&s->i2c_mutex);
+ mutex_init(&dev->i2c_mutex);
/* create mux i2c adapter for tuner */
- s->adapter = i2c_add_mux_adapter(client->adapter, &client->dev, s,
- 0, 0, 0, si2168_select, si2168_deselect);
- if (s->adapter == NULL) {
+ dev->adapter = i2c_add_mux_adapter(client->adapter, &client->dev,
+ client, 0, 0, 0, si2168_select, si2168_deselect);
+ if (dev->adapter == NULL) {
ret = -ENODEV;
- goto err;
+ goto err_kfree;
}
/* create dvb_frontend */
- memcpy(&s->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
- s->fe.demodulator_priv = s;
-
- *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;
+ memcpy(&dev->fe.ops, &si2168_ops, sizeof(struct dvb_frontend_ops));
+ dev->fe.demodulator_priv = client;
+ *config->i2c_adapter = dev->adapter;
+ *config->fe = &dev->fe;
+ dev->ts_mode = config->ts_mode;
+ dev->ts_clock_inv = config->ts_clock_inv;
+ dev->fw_loaded = false;
- i2c_set_clientdata(client, s);
+ i2c_set_clientdata(client, dev);
- dev_info(&s->client->dev,
- "Silicon Labs Si2168 successfully attached\n");
+ dev_info(&client->dev, "Silicon Labs Si2168 successfully attached\n");
return 0;
+err_kfree:
+ kfree(dev);
err:
- kfree(s);
dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2168_remove(struct i2c_client *client)
{
- struct si2168 *s = i2c_get_clientdata(client);
+ struct si2168_dev *dev = i2c_get_clientdata(client);
dev_dbg(&client->dev, "\n");
- i2c_del_mux_adapter(s->adapter);
+ i2c_del_mux_adapter(dev->adapter);
- s->fe.ops.release = NULL;
- s->fe.demodulator_priv = NULL;
+ dev->fe.ops.release = NULL;
+ dev->fe.demodulator_priv = NULL;
- kfree(s);
+ kfree(dev);
return 0;
}
-static const struct i2c_device_id si2168_id[] = {
+static const struct i2c_device_id si2168_id_table[] = {
{"si2168", 0},
{}
};
-MODULE_DEVICE_TABLE(i2c, si2168_id);
+MODULE_DEVICE_TABLE(i2c, si2168_id_table);
static struct i2c_driver si2168_driver = {
.driver = {
@@ -743,7 +730,7 @@ static struct i2c_driver si2168_driver = {
},
.probe = si2168_probe,
.remove = si2168_remove,
- .id_table = si2168_id,
+ .id_table = si2168_id_table,
};
module_i2c_driver(si2168_driver);
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index 87bc12146667..70d702ae6f49 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -36,14 +36,12 @@ struct si2168_config {
struct i2c_adapter **i2c_adapter;
/* TS mode */
+#define SI2168_TS_PARALLEL 0x06
+#define SI2168_TS_SERIAL 0x03
u8 ts_mode;
/* TS clock inverted */
bool ts_clock_inv;
-
};
-#define SI2168_TS_PARALLEL 0x06
-#define SI2168_TS_SERIAL 0x03
-
#endif
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index 60bc3349b6c3..aadd1367673f 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -28,8 +28,7 @@
#define SI2168_B40_FIRMWARE_FALLBACK "dvb-demod-si2168-02.fw"
/* state struct */
-struct si2168 {
- struct i2c_client *client;
+struct si2168_dev {
struct i2c_adapter *adapter;
struct mutex i2c_mutex;
struct dvb_frontend fe;
diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c
index 93596e0e640b..3012f196e9bd 100644
--- a/drivers/media/dvb-frontends/stb0899_algo.c
+++ b/drivers/media/dvb-frontends/stb0899_algo.c
@@ -19,6 +19,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/bitops.h>
#include "stb0899_drv.h"
#include "stb0899_priv.h"
#include "stb0899_reg.h"
@@ -1490,9 +1491,7 @@ enum stb0899_status stb0899_dvbs2_algo(struct stb0899_state *state)
/* Store signal parameters */
offsetfreq = STB0899_READ_S2REG(STB0899_S2DEMOD, CRL_FREQ);
- /* sign extend 30 bit value before using it in calculations */
- if (offsetfreq & (1 << 29))
- offsetfreq |= -1 << 30;
+ offsetfreq = sign_extend32(offsetfreq, 29);
offsetfreq = offsetfreq / ((1 << 30) / 1000);
offsetfreq *= (internal->master_clk / 1000000);
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index 19646fbb061d..c73899d3a53d 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -20,6 +20,7 @@
*/
#include <linux/init.h>
+#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
@@ -691,7 +692,7 @@ static int stb0899_wait_diseqc_fifo_empty(struct stb0899_state *state, int timeo
reg = stb0899_read_reg(state, STB0899_DISSTATUS);
if (!STB0899_GETFIELD(FIFOFULL, reg))
break;
- if ((jiffies - start) > timeout) {
+ if (time_after(jiffies, start + timeout)) {
dprintk(state->verbose, FE_ERROR, 1, "timed out !!");
return -ETIMEDOUT;
}
@@ -733,7 +734,7 @@ static int stb0899_wait_diseqc_rxidle(struct stb0899_state *state, int timeout)
while (!STB0899_GETFIELD(RXEND, reg)) {
reg = stb0899_read_reg(state, STB0899_DISRX_ST0);
- if (jiffies - start > timeout) {
+ if (time_after(jiffies, start + timeout)) {
dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
return -ETIMEDOUT;
}
@@ -782,7 +783,7 @@ static int stb0899_wait_diseqc_txidle(struct stb0899_state *state, int timeout)
while (!STB0899_GETFIELD(TXIDLE, reg)) {
reg = stb0899_read_reg(state, STB0899_DISSTATUS);
- if (jiffies - start > timeout) {
+ if (time_after(jiffies, start + timeout)) {
dprintk(state->verbose, FE_ERROR, 1, "timed out!!");
return -ETIMEDOUT;
}
diff --git a/drivers/media/dvb-frontends/tc90522.c b/drivers/media/dvb-frontends/tc90522.c
index b35d65c9cc05..dce22ce35d20 100644
--- a/drivers/media/dvb-frontends/tc90522.c
+++ b/drivers/media/dvb-frontends/tc90522.c
@@ -214,6 +214,7 @@ static int tc90522s_get_frontend(struct dvb_frontend *fe)
state = fe->demodulator_priv;
c = &fe->dtv_property_cache;
c->delivery_system = SYS_ISDBS;
+ c->symbol_rate = 28860000;
layers = 0;
ret = reg_read(state, 0xe6, val, 5);
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index 205d71364343..da58c9bb67c2 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -177,7 +177,7 @@ comment "Video decoders"
config VIDEO_ADV7180
tristate "Analog Devices ADV7180 decoder"
- depends on VIDEO_V4L2 && I2C
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
---help---
Support for the Analog Devices ADV7180 video decoder.
@@ -196,7 +196,7 @@ config VIDEO_ADV7183
config VIDEO_ADV7604
tristate "Analog Devices ADV7604 decoder"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
---help---
Support for the Analog Devices ADV7604 video decoder.
@@ -208,7 +208,8 @@ config VIDEO_ADV7604
config VIDEO_ADV7842
tristate "Analog Devices ADV7842 decoder"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ select HDMI
---help---
Support for the Analog Devices ADV7842 video decoder.
@@ -422,7 +423,7 @@ config VIDEO_ADV7393
config VIDEO_ADV7511
tristate "Analog Devices ADV7511 encoder"
- depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API && MEDIA_CONTROLLER
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
---help---
Support for the Analog Devices ADV7511 video encoder.
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index bffe6eb528a3..b75878c27c2a 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -30,56 +30,60 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <linux/mutex.h>
-
-#define ADV7180_INPUT_CONTROL_REG 0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM 0x00
-#define ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM_PED 0x10
-#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_J_SECAM 0x20
-#define ADV7180_INPUT_CONTROL_AD_PAL_N_NTSC_M_SECAM 0x30
-#define ADV7180_INPUT_CONTROL_NTSC_J 0x40
-#define ADV7180_INPUT_CONTROL_NTSC_M 0x50
-#define ADV7180_INPUT_CONTROL_PAL60 0x60
-#define ADV7180_INPUT_CONTROL_NTSC_443 0x70
-#define ADV7180_INPUT_CONTROL_PAL_BG 0x80
-#define ADV7180_INPUT_CONTROL_PAL_N 0x90
-#define ADV7180_INPUT_CONTROL_PAL_M 0xa0
-#define ADV7180_INPUT_CONTROL_PAL_M_PED 0xb0
-#define ADV7180_INPUT_CONTROL_PAL_COMB_N 0xc0
-#define ADV7180_INPUT_CONTROL_PAL_COMB_N_PED 0xd0
-#define ADV7180_INPUT_CONTROL_PAL_SECAM 0xe0
-#define ADV7180_INPUT_CONTROL_PAL_SECAM_PED 0xf0
+#include <linux/delay.h>
+
+#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM 0x0
+#define ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM_PED 0x1
+#define ADV7180_STD_AD_PAL_N_NTSC_J_SECAM 0x2
+#define ADV7180_STD_AD_PAL_N_NTSC_M_SECAM 0x3
+#define ADV7180_STD_NTSC_J 0x4
+#define ADV7180_STD_NTSC_M 0x5
+#define ADV7180_STD_PAL60 0x6
+#define ADV7180_STD_NTSC_443 0x7
+#define ADV7180_STD_PAL_BG 0x8
+#define ADV7180_STD_PAL_N 0x9
+#define ADV7180_STD_PAL_M 0xa
+#define ADV7180_STD_PAL_M_PED 0xb
+#define ADV7180_STD_PAL_COMB_N 0xc
+#define ADV7180_STD_PAL_COMB_N_PED 0xd
+#define ADV7180_STD_PAL_SECAM 0xe
+#define ADV7180_STD_PAL_SECAM_PED 0xf
+
+#define ADV7180_REG_INPUT_CONTROL 0x0000
#define ADV7180_INPUT_CONTROL_INSEL_MASK 0x0f
-#define ADV7180_EXTENDED_OUTPUT_CONTROL_REG 0x04
+#define ADV7182_REG_INPUT_VIDSEL 0x0002
+
+#define ADV7180_REG_EXTENDED_OUTPUT_CONTROL 0x0004
#define ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS 0xC5
-#define ADV7180_AUTODETECT_ENABLE_REG 0x07
+#define ADV7180_REG_AUTODETECT_ENABLE 0x07
#define ADV7180_AUTODETECT_DEFAULT 0x7f
/* Contrast */
-#define ADV7180_CON_REG 0x08 /*Unsigned */
+#define ADV7180_REG_CON 0x0008 /*Unsigned */
#define ADV7180_CON_MIN 0
#define ADV7180_CON_DEF 128
#define ADV7180_CON_MAX 255
/* Brightness*/
-#define ADV7180_BRI_REG 0x0a /*Signed */
+#define ADV7180_REG_BRI 0x000a /*Signed */
#define ADV7180_BRI_MIN -128
#define ADV7180_BRI_DEF 0
#define ADV7180_BRI_MAX 127
/* Hue */
-#define ADV7180_HUE_REG 0x0b /*Signed, inverted */
+#define ADV7180_REG_HUE 0x000b /*Signed, inverted */
#define ADV7180_HUE_MIN -127
#define ADV7180_HUE_DEF 0
#define ADV7180_HUE_MAX 128
-#define ADV7180_ADI_CTRL_REG 0x0e
-#define ADV7180_ADI_CTRL_IRQ_SPACE 0x20
+#define ADV7180_REG_CTRL 0x000e
+#define ADV7180_CTRL_IRQ_SPACE 0x20
-#define ADV7180_PWR_MAN_REG 0x0f
+#define ADV7180_REG_PWR_MAN 0x0f
#define ADV7180_PWR_MAN_ON 0x04
#define ADV7180_PWR_MAN_OFF 0x24
#define ADV7180_PWR_MAN_RES 0x80
-#define ADV7180_STATUS1_REG 0x10
+#define ADV7180_REG_STATUS1 0x0010
#define ADV7180_STATUS1_IN_LOCK 0x01
#define ADV7180_STATUS1_AUTOD_MASK 0x70
#define ADV7180_STATUS1_AUTOD_NTSM_M_J 0x00
@@ -91,49 +95,161 @@
#define ADV7180_STATUS1_AUTOD_PAL_COMB 0x60
#define ADV7180_STATUS1_AUTOD_SECAM_525 0x70
-#define ADV7180_IDENT_REG 0x11
+#define ADV7180_REG_IDENT 0x0011
#define ADV7180_ID_7180 0x18
-#define ADV7180_ICONF1_ADI 0x40
+#define ADV7180_REG_ICONF1 0x0040
#define ADV7180_ICONF1_ACTIVE_LOW 0x01
#define ADV7180_ICONF1_PSYNC_ONLY 0x10
#define ADV7180_ICONF1_ACTIVE_TO_CLR 0xC0
/* Saturation */
-#define ADV7180_SD_SAT_CB_REG 0xe3 /*Unsigned */
-#define ADV7180_SD_SAT_CR_REG 0xe4 /*Unsigned */
+#define ADV7180_REG_SD_SAT_CB 0x00e3 /*Unsigned */
+#define ADV7180_REG_SD_SAT_CR 0x00e4 /*Unsigned */
#define ADV7180_SAT_MIN 0
#define ADV7180_SAT_DEF 128
#define ADV7180_SAT_MAX 255
#define ADV7180_IRQ1_LOCK 0x01
#define ADV7180_IRQ1_UNLOCK 0x02
-#define ADV7180_ISR1_ADI 0x42
-#define ADV7180_ICR1_ADI 0x43
-#define ADV7180_IMR1_ADI 0x44
-#define ADV7180_IMR2_ADI 0x48
+#define ADV7180_REG_ISR1 0x0042
+#define ADV7180_REG_ICR1 0x0043
+#define ADV7180_REG_IMR1 0x0044
+#define ADV7180_REG_IMR2 0x0048
#define ADV7180_IRQ3_AD_CHANGE 0x08
-#define ADV7180_ISR3_ADI 0x4A
-#define ADV7180_ICR3_ADI 0x4B
-#define ADV7180_IMR3_ADI 0x4C
-#define ADV7180_IMR4_ADI 0x50
+#define ADV7180_REG_ISR3 0x004A
+#define ADV7180_REG_ICR3 0x004B
+#define ADV7180_REG_IMR3 0x004C
+#define ADV7180_REG_IMR4 0x50
-#define ADV7180_NTSC_V_BIT_END_REG 0xE6
+#define ADV7180_REG_NTSC_V_BIT_END 0x00E6
#define ADV7180_NTSC_V_BIT_END_MANUAL_NVEND 0x4F
+#define ADV7180_REG_VPP_SLAVE_ADDR 0xFD
+#define ADV7180_REG_CSI_SLAVE_ADDR 0xFE
+
+#define ADV7180_REG_FLCONTROL 0x40e0
+#define ADV7180_FLCONTROL_FL_ENABLE 0x1
+
+#define ADV7180_CSI_REG_PWRDN 0x00
+#define ADV7180_CSI_PWRDN 0x80
+
+#define ADV7180_INPUT_CVBS_AIN1 0x00
+#define ADV7180_INPUT_CVBS_AIN2 0x01
+#define ADV7180_INPUT_CVBS_AIN3 0x02
+#define ADV7180_INPUT_CVBS_AIN4 0x03
+#define ADV7180_INPUT_CVBS_AIN5 0x04
+#define ADV7180_INPUT_CVBS_AIN6 0x05
+#define ADV7180_INPUT_SVIDEO_AIN1_AIN2 0x06
+#define ADV7180_INPUT_SVIDEO_AIN3_AIN4 0x07
+#define ADV7180_INPUT_SVIDEO_AIN5_AIN6 0x08
+#define ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3 0x09
+#define ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0a
+
+#define ADV7182_INPUT_CVBS_AIN1 0x00
+#define ADV7182_INPUT_CVBS_AIN2 0x01
+#define ADV7182_INPUT_CVBS_AIN3 0x02
+#define ADV7182_INPUT_CVBS_AIN4 0x03
+#define ADV7182_INPUT_CVBS_AIN5 0x04
+#define ADV7182_INPUT_CVBS_AIN6 0x05
+#define ADV7182_INPUT_CVBS_AIN7 0x06
+#define ADV7182_INPUT_CVBS_AIN8 0x07
+#define ADV7182_INPUT_SVIDEO_AIN1_AIN2 0x08
+#define ADV7182_INPUT_SVIDEO_AIN3_AIN4 0x09
+#define ADV7182_INPUT_SVIDEO_AIN5_AIN6 0x0a
+#define ADV7182_INPUT_SVIDEO_AIN7_AIN8 0x0b
+#define ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3 0x0c
+#define ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6 0x0d
+#define ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2 0x0e
+#define ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4 0x0f
+#define ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6 0x10
+#define ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8 0x11
+
+#define ADV7180_DEFAULT_CSI_I2C_ADDR 0x44
+#define ADV7180_DEFAULT_VPP_I2C_ADDR 0x42
+
+#define V4L2_CID_ADV_FAST_SWITCH (V4L2_CID_USER_ADV7180_BASE + 0x00)
+
+struct adv7180_state;
+
+#define ADV7180_FLAG_RESET_POWERED BIT(0)
+#define ADV7180_FLAG_V2 BIT(1)
+#define ADV7180_FLAG_MIPI_CSI2 BIT(2)
+#define ADV7180_FLAG_I2P BIT(3)
+
+struct adv7180_chip_info {
+ unsigned int flags;
+ unsigned int valid_input_mask;
+ int (*set_std)(struct adv7180_state *st, unsigned int std);
+ int (*select_input)(struct adv7180_state *st, unsigned int input);
+ int (*init)(struct adv7180_state *state);
+};
+
struct adv7180_state {
struct v4l2_ctrl_handler ctrl_hdl;
struct v4l2_subdev sd;
+ struct media_pad pad;
struct mutex mutex; /* mutual excl. when accessing chip */
int irq;
v4l2_std_id curr_norm;
bool autodetect;
bool powered;
u8 input;
+
+ struct i2c_client *client;
+ unsigned int register_page;
+ struct i2c_client *csi_client;
+ struct i2c_client *vpp_client;
+ const struct adv7180_chip_info *chip_info;
+ enum v4l2_field field;
};
#define to_adv7180_sd(_ctrl) (&container_of(_ctrl->handler, \
struct adv7180_state, \
ctrl_hdl)->sd)
+static int adv7180_select_page(struct adv7180_state *state, unsigned int page)
+{
+ if (state->register_page != page) {
+ i2c_smbus_write_byte_data(state->client, ADV7180_REG_CTRL,
+ page);
+ state->register_page = page;
+ }
+
+ return 0;
+}
+
+static int adv7180_write(struct adv7180_state *state, unsigned int reg,
+ unsigned int value)
+{
+ lockdep_assert_held(&state->mutex);
+ adv7180_select_page(state, reg >> 8);
+ return i2c_smbus_write_byte_data(state->client, reg & 0xff, value);
+}
+
+static int adv7180_read(struct adv7180_state *state, unsigned int reg)
+{
+ lockdep_assert_held(&state->mutex);
+ adv7180_select_page(state, reg >> 8);
+ return i2c_smbus_read_byte_data(state->client, reg & 0xff);
+}
+
+static int adv7180_csi_write(struct adv7180_state *state, unsigned int reg,
+ unsigned int value)
+{
+ return i2c_smbus_write_byte_data(state->csi_client, reg, value);
+}
+
+static int adv7180_set_video_standard(struct adv7180_state *state,
+ unsigned int std)
+{
+ return state->chip_info->set_std(state, std);
+}
+
+static int adv7180_vpp_write(struct adv7180_state *state, unsigned int reg,
+ unsigned int value)
+{
+ return i2c_smbus_write_byte_data(state->vpp_client, reg, value);
+}
+
static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
{
/* in case V4L2_IN_ST_NO_SIGNAL */
@@ -165,22 +281,22 @@ static v4l2_std_id adv7180_std_to_v4l2(u8 status1)
static int v4l2_std_to_adv7180(v4l2_std_id std)
{
if (std == V4L2_STD_PAL_60)
- return ADV7180_INPUT_CONTROL_PAL60;
+ return ADV7180_STD_PAL60;
if (std == V4L2_STD_NTSC_443)
- return ADV7180_INPUT_CONTROL_NTSC_443;
+ return ADV7180_STD_NTSC_443;
if (std == V4L2_STD_PAL_N)
- return ADV7180_INPUT_CONTROL_PAL_N;
+ return ADV7180_STD_PAL_N;
if (std == V4L2_STD_PAL_M)
- return ADV7180_INPUT_CONTROL_PAL_M;
+ return ADV7180_STD_PAL_M;
if (std == V4L2_STD_PAL_Nc)
- return ADV7180_INPUT_CONTROL_PAL_COMB_N;
+ return ADV7180_STD_PAL_COMB_N;
if (std & V4L2_STD_PAL)
- return ADV7180_INPUT_CONTROL_PAL_BG;
+ return ADV7180_STD_PAL_BG;
if (std & V4L2_STD_NTSC)
- return ADV7180_INPUT_CONTROL_NTSC_M;
+ return ADV7180_STD_NTSC_M;
if (std & V4L2_STD_SECAM)
- return ADV7180_INPUT_CONTROL_PAL_SECAM;
+ return ADV7180_STD_PAL_SECAM;
return -EINVAL;
}
@@ -193,10 +309,10 @@ static u32 adv7180_status_to_v4l2(u8 status1)
return 0;
}
-static int __adv7180_status(struct i2c_client *client, u32 *status,
+static int __adv7180_status(struct adv7180_state *state, u32 *status,
v4l2_std_id *std)
{
- int status1 = i2c_smbus_read_byte_data(client, ADV7180_STATUS1_REG);
+ int status1 = adv7180_read(state, ADV7180_REG_STATUS1);
if (status1 < 0)
return status1;
@@ -225,7 +341,7 @@ static int adv7180_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
if (!state->autodetect || state->irq > 0)
*std = state->curr_norm;
else
- err = __adv7180_status(v4l2_get_subdevdata(sd), NULL, std);
+ err = __adv7180_status(state, NULL, std);
mutex_unlock(&state->mutex);
return err;
@@ -236,26 +352,19 @@ static int adv7180_s_routing(struct v4l2_subdev *sd, u32 input,
{
struct adv7180_state *state = to_state(sd);
int ret = mutex_lock_interruptible(&state->mutex);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
if (ret)
return ret;
- /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
- * all inputs and let the card driver take care of validation
- */
- if ((input & ADV7180_INPUT_CONTROL_INSEL_MASK) != input)
+ if (input > 31 || !(BIT(input) & state->chip_info->valid_input_mask)) {
+ ret = -EINVAL;
goto out;
+ }
- ret = i2c_smbus_read_byte_data(client, ADV7180_INPUT_CONTROL_REG);
-
- if (ret < 0)
- goto out;
+ ret = state->chip_info->select_input(state, input);
- ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
- ret = i2c_smbus_write_byte_data(client,
- ADV7180_INPUT_CONTROL_REG, ret | input);
- state->input = input;
+ if (ret == 0)
+ state->input = input;
out:
mutex_unlock(&state->mutex);
return ret;
@@ -268,74 +377,104 @@ static int adv7180_g_input_status(struct v4l2_subdev *sd, u32 *status)
if (ret)
return ret;
- ret = __adv7180_status(v4l2_get_subdevdata(sd), status, NULL);
+ ret = __adv7180_status(state, status, NULL);
mutex_unlock(&state->mutex);
return ret;
}
+static int adv7180_program_std(struct adv7180_state *state)
+{
+ int ret;
+
+ if (state->autodetect) {
+ ret = adv7180_set_video_standard(state,
+ ADV7180_STD_AD_PAL_BG_NTSC_J_SECAM);
+ if (ret < 0)
+ return ret;
+
+ __adv7180_status(state, NULL, &state->curr_norm);
+ } else {
+ ret = v4l2_std_to_adv7180(state->curr_norm);
+ if (ret < 0)
+ return ret;
+
+ ret = adv7180_set_video_standard(state, ret);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
static int adv7180_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct adv7180_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = mutex_lock_interruptible(&state->mutex);
+
if (ret)
return ret;
/* all standards -> autodetect */
if (std == V4L2_STD_ALL) {
- ret =
- i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
- | state->input);
- if (ret < 0)
- goto out;
-
- __adv7180_status(client, NULL, &state->curr_norm);
state->autodetect = true;
} else {
+ /* Make sure we can support this std */
ret = v4l2_std_to_adv7180(std);
if (ret < 0)
goto out;
- ret = i2c_smbus_write_byte_data(client,
- ADV7180_INPUT_CONTROL_REG,
- ret | state->input);
- if (ret < 0)
- goto out;
-
state->curr_norm = std;
state->autodetect = false;
}
- ret = 0;
+
+ ret = adv7180_program_std(state);
out:
mutex_unlock(&state->mutex);
return ret;
}
-static int adv7180_set_power(struct adv7180_state *state,
- struct i2c_client *client, bool on)
+static int adv7180_set_power(struct adv7180_state *state, bool on)
{
u8 val;
+ int ret;
if (on)
val = ADV7180_PWR_MAN_ON;
else
val = ADV7180_PWR_MAN_OFF;
- return i2c_smbus_write_byte_data(client, ADV7180_PWR_MAN_REG, val);
+ ret = adv7180_write(state, ADV7180_REG_PWR_MAN, val);
+ if (ret)
+ return ret;
+
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ if (on) {
+ adv7180_csi_write(state, 0xDE, 0x02);
+ adv7180_csi_write(state, 0xD2, 0xF7);
+ adv7180_csi_write(state, 0xD8, 0x65);
+ adv7180_csi_write(state, 0xE0, 0x09);
+ adv7180_csi_write(state, 0x2C, 0x00);
+ if (state->field == V4L2_FIELD_NONE)
+ adv7180_csi_write(state, 0x1D, 0x80);
+ adv7180_csi_write(state, 0x00, 0x00);
+ } else {
+ adv7180_csi_write(state, 0x00, 0x80);
+ }
+ }
+
+ return 0;
}
static int adv7180_s_power(struct v4l2_subdev *sd, int on)
{
struct adv7180_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
ret = mutex_lock_interruptible(&state->mutex);
if (ret)
return ret;
- ret = adv7180_set_power(state, client, on);
+ ret = adv7180_set_power(state, on);
if (ret == 0)
state->powered = on;
@@ -347,7 +486,6 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct v4l2_subdev *sd = to_adv7180_sd(ctrl);
struct adv7180_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret = mutex_lock_interruptible(&state->mutex);
int val;
@@ -356,26 +494,36 @@ static int adv7180_s_ctrl(struct v4l2_ctrl *ctrl)
val = ctrl->val;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ret = i2c_smbus_write_byte_data(client, ADV7180_BRI_REG, val);
+ ret = adv7180_write(state, ADV7180_REG_BRI, val);
break;
case V4L2_CID_HUE:
/*Hue is inverted according to HSL chart */
- ret = i2c_smbus_write_byte_data(client, ADV7180_HUE_REG, -val);
+ ret = adv7180_write(state, ADV7180_REG_HUE, -val);
break;
case V4L2_CID_CONTRAST:
- ret = i2c_smbus_write_byte_data(client, ADV7180_CON_REG, val);
+ ret = adv7180_write(state, ADV7180_REG_CON, val);
break;
case V4L2_CID_SATURATION:
/*
*This could be V4L2_CID_BLUE_BALANCE/V4L2_CID_RED_BALANCE
*Let's not confuse the user, everybody understands saturation
*/
- ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CB_REG,
- val);
+ ret = adv7180_write(state, ADV7180_REG_SD_SAT_CB, val);
if (ret < 0)
break;
- ret = i2c_smbus_write_byte_data(client, ADV7180_SD_SAT_CR_REG,
- val);
+ ret = adv7180_write(state, ADV7180_REG_SD_SAT_CR, val);
+ break;
+ case V4L2_CID_ADV_FAST_SWITCH:
+ if (ctrl->val) {
+ /* ADI required write */
+ adv7180_write(state, 0x80d9, 0x44);
+ adv7180_write(state, ADV7180_REG_FLCONTROL,
+ ADV7180_FLCONTROL_FL_ENABLE);
+ } else {
+ /* ADI required write */
+ adv7180_write(state, 0x80d9, 0xc4);
+ adv7180_write(state, ADV7180_REG_FLCONTROL, 0x00);
+ }
break;
default:
ret = -EINVAL;
@@ -389,6 +537,16 @@ static const struct v4l2_ctrl_ops adv7180_ctrl_ops = {
.s_ctrl = adv7180_s_ctrl,
};
+static const struct v4l2_ctrl_config adv7180_ctrl_fast_switch = {
+ .ops = &adv7180_ctrl_ops,
+ .id = V4L2_CID_ADV_FAST_SWITCH,
+ .name = "Fast Switching",
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .min = 0,
+ .max = 1,
+ .step = 1,
+};
+
static int adv7180_init_controls(struct adv7180_state *state)
{
v4l2_ctrl_handler_init(&state->ctrl_hdl, 4);
@@ -405,6 +563,8 @@ static int adv7180_init_controls(struct adv7180_state *state)
v4l2_ctrl_new_std(&state->ctrl_hdl, &adv7180_ctrl_ops,
V4L2_CID_HUE, ADV7180_HUE_MIN,
ADV7180_HUE_MAX, 1, ADV7180_HUE_DEF);
+ v4l2_ctrl_new_custom(&state->ctrl_hdl, &adv7180_ctrl_fast_switch, NULL);
+
state->sd.ctrl_handler = &state->ctrl_hdl;
if (state->ctrl_hdl.error) {
int err = state->ctrl_hdl.error;
@@ -421,13 +581,14 @@ static void adv7180_exit_controls(struct adv7180_state *state)
v4l2_ctrl_handler_free(&state->ctrl_hdl);
}
-static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
- u32 *code)
+static int adv7180_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
{
- if (index > 0)
+ if (code->index != 0)
return -EINVAL;
- *code = MEDIA_BUS_FMT_YUYV8_2X8;
+ code->code = MEDIA_BUS_FMT_YUYV8_2X8;
return 0;
}
@@ -439,23 +600,118 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- fmt->field = V4L2_FIELD_INTERLACED;
fmt->width = 720;
fmt->height = state->curr_norm & V4L2_STD_525_60 ? 480 : 576;
return 0;
}
+static int adv7180_set_field_mode(struct adv7180_state *state)
+{
+ if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
+ return 0;
+
+ if (state->field == V4L2_FIELD_NONE) {
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ adv7180_csi_write(state, 0x01, 0x20);
+ adv7180_csi_write(state, 0x02, 0x28);
+ adv7180_csi_write(state, 0x03, 0x38);
+ adv7180_csi_write(state, 0x04, 0x30);
+ adv7180_csi_write(state, 0x05, 0x30);
+ adv7180_csi_write(state, 0x06, 0x80);
+ adv7180_csi_write(state, 0x07, 0x70);
+ adv7180_csi_write(state, 0x08, 0x50);
+ }
+ adv7180_vpp_write(state, 0xa3, 0x00);
+ adv7180_vpp_write(state, 0x5b, 0x00);
+ adv7180_vpp_write(state, 0x55, 0x80);
+ } else {
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ adv7180_csi_write(state, 0x01, 0x18);
+ adv7180_csi_write(state, 0x02, 0x18);
+ adv7180_csi_write(state, 0x03, 0x30);
+ adv7180_csi_write(state, 0x04, 0x20);
+ adv7180_csi_write(state, 0x05, 0x28);
+ adv7180_csi_write(state, 0x06, 0x40);
+ adv7180_csi_write(state, 0x07, 0x58);
+ adv7180_csi_write(state, 0x08, 0x30);
+ }
+ adv7180_vpp_write(state, 0xa3, 0x70);
+ adv7180_vpp_write(state, 0x5b, 0x80);
+ adv7180_vpp_write(state, 0x55, 0x00);
+ }
+
+ return 0;
+}
+
+static int adv7180_get_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct adv7180_state *state = to_state(sd);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ format->format = *v4l2_subdev_get_try_format(fh, 0);
+ } else {
+ adv7180_mbus_fmt(sd, &format->format);
+ format->format.field = state->field;
+ }
+
+ return 0;
+}
+
+static int adv7180_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct adv7180_state *state = to_state(sd);
+ struct v4l2_mbus_framefmt *framefmt;
+
+ switch (format->format.field) {
+ case V4L2_FIELD_NONE:
+ if (!(state->chip_info->flags & ADV7180_FLAG_I2P))
+ format->format.field = V4L2_FIELD_INTERLACED;
+ break;
+ default:
+ format->format.field = V4L2_FIELD_INTERLACED;
+ break;
+ }
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ framefmt = &format->format;
+ if (state->field != format->format.field) {
+ state->field = format->format.field;
+ adv7180_set_power(state, false);
+ adv7180_set_field_mode(state);
+ adv7180_set_power(state, true);
+ }
+ } else {
+ framefmt = v4l2_subdev_get_try_format(fh, 0);
+ *framefmt = format->format;
+ }
+
+ return adv7180_mbus_fmt(sd, framefmt);
+}
+
static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
struct v4l2_mbus_config *cfg)
{
- /*
- * The ADV7180 sensor supports BT.601/656 output modes.
- * The BT.656 is default and not yet configurable by s/w.
- */
- cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
- cfg->type = V4L2_MBUS_BT656;
+ struct adv7180_state *state = to_state(sd);
+
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ cfg->type = V4L2_MBUS_CSI2;
+ cfg->flags = V4L2_MBUS_CSI2_1_LANE |
+ V4L2_MBUS_CSI2_CHANNEL_0 |
+ V4L2_MBUS_CSI2_CONTINUOUS_CLOCK;
+ } else {
+ /*
+ * The ADV7180 sensor supports BT.601/656 output modes.
+ * The BT.656 is default and not yet configurable by s/w.
+ */
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
+ V4L2_MBUS_DATA_ACTIVE_HIGH;
+ cfg->type = V4L2_MBUS_BT656;
+ }
return 0;
}
@@ -465,139 +721,439 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
- .enum_mbus_fmt = adv7180_enum_mbus_fmt,
- .try_mbus_fmt = adv7180_mbus_fmt,
- .g_mbus_fmt = adv7180_mbus_fmt,
- .s_mbus_fmt = adv7180_mbus_fmt,
.g_mbus_config = adv7180_g_mbus_config,
};
+
static const struct v4l2_subdev_core_ops adv7180_core_ops = {
.s_power = adv7180_s_power,
};
+static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
+ .enum_mbus_code = adv7180_enum_mbus_code,
+ .set_fmt = adv7180_set_pad_format,
+ .get_fmt = adv7180_get_pad_format,
+};
+
static const struct v4l2_subdev_ops adv7180_ops = {
.core = &adv7180_core_ops,
.video = &adv7180_video_ops,
+ .pad = &adv7180_pad_ops,
};
static irqreturn_t adv7180_irq(int irq, void *devid)
{
struct adv7180_state *state = devid;
- struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
u8 isr3;
mutex_lock(&state->mutex);
- i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
- ADV7180_ADI_CTRL_IRQ_SPACE);
- isr3 = i2c_smbus_read_byte_data(client, ADV7180_ISR3_ADI);
+ isr3 = adv7180_read(state, ADV7180_REG_ISR3);
/* clear */
- i2c_smbus_write_byte_data(client, ADV7180_ICR3_ADI, isr3);
- i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG, 0);
+ adv7180_write(state, ADV7180_REG_ICR3, isr3);
if (isr3 & ADV7180_IRQ3_AD_CHANGE && state->autodetect)
- __adv7180_status(client, NULL, &state->curr_norm);
+ __adv7180_status(state, NULL, &state->curr_norm);
mutex_unlock(&state->mutex);
return IRQ_HANDLED;
}
-static int init_device(struct i2c_client *client, struct adv7180_state *state)
+static int adv7180_init(struct adv7180_state *state)
{
int ret;
- /* Initialize adv7180 */
- /* Enable autodetection */
- if (state->autodetect) {
- ret =
- i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
- ADV7180_INPUT_CONTROL_AD_PAL_BG_NTSC_J_SECAM
- | state->input);
- if (ret < 0)
- return ret;
-
- ret =
- i2c_smbus_write_byte_data(client,
- ADV7180_AUTODETECT_ENABLE_REG,
- ADV7180_AUTODETECT_DEFAULT);
- if (ret < 0)
- return ret;
- } else {
- ret = v4l2_std_to_adv7180(state->curr_norm);
- if (ret < 0)
- return ret;
-
- ret =
- i2c_smbus_write_byte_data(client, ADV7180_INPUT_CONTROL_REG,
- ret | state->input);
- if (ret < 0)
- return ret;
-
- }
/* ITU-R BT.656-4 compatible */
- ret = i2c_smbus_write_byte_data(client,
- ADV7180_EXTENDED_OUTPUT_CONTROL_REG,
+ ret = adv7180_write(state, ADV7180_REG_EXTENDED_OUTPUT_CONTROL,
ADV7180_EXTENDED_OUTPUT_CONTROL_NTSCDIS);
if (ret < 0)
return ret;
/* Manually set V bit end position in NTSC mode */
- ret = i2c_smbus_write_byte_data(client,
- ADV7180_NTSC_V_BIT_END_REG,
+ return adv7180_write(state, ADV7180_REG_NTSC_V_BIT_END,
ADV7180_NTSC_V_BIT_END_MANUAL_NVEND);
+}
+
+static int adv7180_set_std(struct adv7180_state *state, unsigned int std)
+{
+ return adv7180_write(state, ADV7180_REG_INPUT_CONTROL,
+ (std << 4) | state->input);
+}
+
+static int adv7180_select_input(struct adv7180_state *state, unsigned int input)
+{
+ int ret;
+
+ ret = adv7180_read(state, ADV7180_REG_INPUT_CONTROL);
if (ret < 0)
return ret;
- /* read current norm */
- __adv7180_status(client, NULL, &state->curr_norm);
+ ret &= ~ADV7180_INPUT_CONTROL_INSEL_MASK;
+ ret |= input;
+ return adv7180_write(state, ADV7180_REG_INPUT_CONTROL, ret);
+}
- /* register for interrupts */
- if (state->irq > 0) {
- ret = request_threaded_irq(state->irq, NULL, adv7180_irq,
- IRQF_ONESHOT, KBUILD_MODNAME, state);
- if (ret)
- return ret;
+static int adv7182_init(struct adv7180_state *state)
+{
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+ adv7180_write(state, ADV7180_REG_CSI_SLAVE_ADDR,
+ ADV7180_DEFAULT_CSI_I2C_ADDR << 1);
+
+ if (state->chip_info->flags & ADV7180_FLAG_I2P)
+ adv7180_write(state, ADV7180_REG_VPP_SLAVE_ADDR,
+ ADV7180_DEFAULT_VPP_I2C_ADDR << 1);
+
+ if (state->chip_info->flags & ADV7180_FLAG_V2) {
+ /* ADI recommended writes for improved video quality */
+ adv7180_write(state, 0x0080, 0x51);
+ adv7180_write(state, 0x0081, 0x51);
+ adv7180_write(state, 0x0082, 0x68);
+ }
- ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
- ADV7180_ADI_CTRL_IRQ_SPACE);
- if (ret < 0)
- goto err;
+ /* ADI required writes */
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ adv7180_write(state, 0x0003, 0x4e);
+ adv7180_write(state, 0x0004, 0x57);
+ adv7180_write(state, 0x001d, 0xc0);
+ } else {
+ if (state->chip_info->flags & ADV7180_FLAG_V2)
+ adv7180_write(state, 0x0004, 0x17);
+ else
+ adv7180_write(state, 0x0004, 0x07);
+ adv7180_write(state, 0x0003, 0x0c);
+ adv7180_write(state, 0x001d, 0x40);
+ }
+
+ adv7180_write(state, 0x0013, 0x00);
+
+ return 0;
+}
+
+static int adv7182_set_std(struct adv7180_state *state, unsigned int std)
+{
+ return adv7180_write(state, ADV7182_REG_INPUT_VIDSEL, std << 4);
+}
+
+enum adv7182_input_type {
+ ADV7182_INPUT_TYPE_CVBS,
+ ADV7182_INPUT_TYPE_DIFF_CVBS,
+ ADV7182_INPUT_TYPE_SVIDEO,
+ ADV7182_INPUT_TYPE_YPBPR,
+};
+
+static enum adv7182_input_type adv7182_get_input_type(unsigned int input)
+{
+ switch (input) {
+ case ADV7182_INPUT_CVBS_AIN1:
+ case ADV7182_INPUT_CVBS_AIN2:
+ case ADV7182_INPUT_CVBS_AIN3:
+ case ADV7182_INPUT_CVBS_AIN4:
+ case ADV7182_INPUT_CVBS_AIN5:
+ case ADV7182_INPUT_CVBS_AIN6:
+ case ADV7182_INPUT_CVBS_AIN7:
+ case ADV7182_INPUT_CVBS_AIN8:
+ return ADV7182_INPUT_TYPE_CVBS;
+ case ADV7182_INPUT_SVIDEO_AIN1_AIN2:
+ case ADV7182_INPUT_SVIDEO_AIN3_AIN4:
+ case ADV7182_INPUT_SVIDEO_AIN5_AIN6:
+ case ADV7182_INPUT_SVIDEO_AIN7_AIN8:
+ return ADV7182_INPUT_TYPE_SVIDEO;
+ case ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3:
+ case ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6:
+ return ADV7182_INPUT_TYPE_YPBPR;
+ case ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2:
+ case ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4:
+ case ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6:
+ case ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8:
+ return ADV7182_INPUT_TYPE_DIFF_CVBS;
+ default: /* Will never happen */
+ return 0;
+ }
+}
+
+/* ADI recommended writes to registers 0x52, 0x53, 0x54 */
+static unsigned int adv7182_lbias_settings[][3] = {
+ [ADV7182_INPUT_TYPE_CVBS] = { 0xCB, 0x4E, 0x80 },
+ [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
+ [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
+ [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
+};
+
+static unsigned int adv7280_lbias_settings[][3] = {
+ [ADV7182_INPUT_TYPE_CVBS] = { 0xCD, 0x4E, 0x80 },
+ [ADV7182_INPUT_TYPE_DIFF_CVBS] = { 0xC0, 0x4E, 0x80 },
+ [ADV7182_INPUT_TYPE_SVIDEO] = { 0x0B, 0xCE, 0x80 },
+ [ADV7182_INPUT_TYPE_YPBPR] = { 0x0B, 0x4E, 0xC0 },
+};
+
+static int adv7182_select_input(struct adv7180_state *state, unsigned int input)
+{
+ enum adv7182_input_type input_type;
+ unsigned int *lbias;
+ unsigned int i;
+ int ret;
+
+ ret = adv7180_write(state, ADV7180_REG_INPUT_CONTROL, input);
+ if (ret)
+ return ret;
+
+ /* Reset clamp circuitry - ADI recommended writes */
+ adv7180_write(state, 0x809c, 0x00);
+ adv7180_write(state, 0x809c, 0xff);
+
+ input_type = adv7182_get_input_type(input);
+
+ switch (input_type) {
+ case ADV7182_INPUT_TYPE_CVBS:
+ case ADV7182_INPUT_TYPE_DIFF_CVBS:
+ /* ADI recommends to use the SH1 filter */
+ adv7180_write(state, 0x0017, 0x41);
+ break;
+ default:
+ adv7180_write(state, 0x0017, 0x01);
+ break;
+ }
+
+ if (state->chip_info->flags & ADV7180_FLAG_V2)
+ lbias = adv7280_lbias_settings[input_type];
+ else
+ lbias = adv7182_lbias_settings[input_type];
+
+ for (i = 0; i < ARRAY_SIZE(adv7182_lbias_settings[0]); i++)
+ adv7180_write(state, 0x0052 + i, lbias[i]);
+
+ if (input_type == ADV7182_INPUT_TYPE_DIFF_CVBS) {
+ /* ADI required writes to make differential CVBS work */
+ adv7180_write(state, 0x005f, 0xa8);
+ adv7180_write(state, 0x005a, 0x90);
+ adv7180_write(state, 0x0060, 0xb0);
+ adv7180_write(state, 0x80b6, 0x08);
+ adv7180_write(state, 0x80c0, 0xa0);
+ } else {
+ adv7180_write(state, 0x005f, 0xf0);
+ adv7180_write(state, 0x005a, 0xd0);
+ adv7180_write(state, 0x0060, 0x10);
+ adv7180_write(state, 0x80b6, 0x9c);
+ adv7180_write(state, 0x80c0, 0x00);
+ }
+
+ return 0;
+}
+
+static const struct adv7180_chip_info adv7180_info = {
+ .flags = ADV7180_FLAG_RESET_POWERED,
+ /* We cannot discriminate between LQFP and 40-pin LFCSP, so accept
+ * all inputs and let the card driver take care of validation
+ */
+ .valid_input_mask = BIT(ADV7180_INPUT_CVBS_AIN1) |
+ BIT(ADV7180_INPUT_CVBS_AIN2) |
+ BIT(ADV7180_INPUT_CVBS_AIN3) |
+ BIT(ADV7180_INPUT_CVBS_AIN4) |
+ BIT(ADV7180_INPUT_CVBS_AIN5) |
+ BIT(ADV7180_INPUT_CVBS_AIN6) |
+ BIT(ADV7180_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7180_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7180_INPUT_SVIDEO_AIN5_AIN6) |
+ BIT(ADV7180_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+ BIT(ADV7180_INPUT_YPRPB_AIN4_AIN5_AIN6),
+ .init = adv7180_init,
+ .set_std = adv7180_set_std,
+ .select_input = adv7180_select_input,
+};
+
+static const struct adv7180_chip_info adv7182_info = {
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+ BIT(ADV7182_INPUT_CVBS_AIN4) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7280_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+ BIT(ADV7182_INPUT_CVBS_AIN4) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7280_m_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+ BIT(ADV7182_INPUT_CVBS_AIN4) |
+ BIT(ADV7182_INPUT_CVBS_AIN5) |
+ BIT(ADV7182_INPUT_CVBS_AIN6) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+ BIT(ADV7182_INPUT_CVBS_AIN8) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+ BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+ BIT(ADV7182_INPUT_CVBS_AIN8) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7281_m_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+ BIT(ADV7182_INPUT_CVBS_AIN4) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+ BIT(ADV7182_INPUT_CVBS_AIN8) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+static const struct adv7180_chip_info adv7281_ma_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+ BIT(ADV7182_INPUT_CVBS_AIN4) |
+ BIT(ADV7182_INPUT_CVBS_AIN5) |
+ BIT(ADV7182_INPUT_CVBS_AIN6) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+ BIT(ADV7182_INPUT_CVBS_AIN8) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN5_AIN6) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_YPRPB_AIN1_AIN2_AIN3) |
+ BIT(ADV7182_INPUT_YPRPB_AIN4_AIN5_AIN6) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN5_AIN6) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7282_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_I2P,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+ BIT(ADV7182_INPUT_CVBS_AIN8) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static const struct adv7180_chip_info adv7282_m_info = {
+ .flags = ADV7180_FLAG_V2 | ADV7180_FLAG_MIPI_CSI2 | ADV7180_FLAG_I2P,
+ .valid_input_mask = BIT(ADV7182_INPUT_CVBS_AIN1) |
+ BIT(ADV7182_INPUT_CVBS_AIN2) |
+ BIT(ADV7182_INPUT_CVBS_AIN3) |
+ BIT(ADV7182_INPUT_CVBS_AIN4) |
+ BIT(ADV7182_INPUT_CVBS_AIN7) |
+ BIT(ADV7182_INPUT_CVBS_AIN8) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_SVIDEO_AIN7_AIN8) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN1_AIN2) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN3_AIN4) |
+ BIT(ADV7182_INPUT_DIFF_CVBS_AIN7_AIN8),
+ .init = adv7182_init,
+ .set_std = adv7182_set_std,
+ .select_input = adv7182_select_input,
+};
+
+static int init_device(struct adv7180_state *state)
+{
+ int ret;
+
+ mutex_lock(&state->mutex);
+
+ adv7180_write(state, ADV7180_REG_PWR_MAN, ADV7180_PWR_MAN_RES);
+ usleep_range(2000, 10000);
+
+ ret = state->chip_info->init(state);
+ if (ret)
+ goto out_unlock;
+
+ ret = adv7180_program_std(state);
+ if (ret)
+ goto out_unlock;
+
+ adv7180_set_field_mode(state);
+
+ /* register for interrupts */
+ if (state->irq > 0) {
/* config the Interrupt pin to be active low */
- ret = i2c_smbus_write_byte_data(client, ADV7180_ICONF1_ADI,
+ ret = adv7180_write(state, ADV7180_REG_ICONF1,
ADV7180_ICONF1_ACTIVE_LOW |
ADV7180_ICONF1_PSYNC_ONLY);
if (ret < 0)
- goto err;
+ goto out_unlock;
- ret = i2c_smbus_write_byte_data(client, ADV7180_IMR1_ADI, 0);
+ ret = adv7180_write(state, ADV7180_REG_IMR1, 0);
if (ret < 0)
- goto err;
+ goto out_unlock;
- ret = i2c_smbus_write_byte_data(client, ADV7180_IMR2_ADI, 0);
+ ret = adv7180_write(state, ADV7180_REG_IMR2, 0);
if (ret < 0)
- goto err;
+ goto out_unlock;
/* enable AD change interrupts interrupts */
- ret = i2c_smbus_write_byte_data(client, ADV7180_IMR3_ADI,
+ ret = adv7180_write(state, ADV7180_REG_IMR3,
ADV7180_IRQ3_AD_CHANGE);
if (ret < 0)
- goto err;
+ goto out_unlock;
- ret = i2c_smbus_write_byte_data(client, ADV7180_IMR4_ADI, 0);
+ ret = adv7180_write(state, ADV7180_REG_IMR4, 0);
if (ret < 0)
- goto err;
-
- ret = i2c_smbus_write_byte_data(client, ADV7180_ADI_CTRL_REG,
- 0);
- if (ret < 0)
- goto err;
+ goto out_unlock;
}
- return 0;
+out_unlock:
+ mutex_unlock(&state->mutex);
-err:
- free_irq(state->irq, state);
return ret;
}
@@ -616,26 +1172,63 @@ static int adv7180_probe(struct i2c_client *client,
client->addr, client->adapter->name);
state = devm_kzalloc(&client->dev, sizeof(*state), GFP_KERNEL);
- if (state == NULL) {
- ret = -ENOMEM;
- goto err;
+ if (state == NULL)
+ return -ENOMEM;
+
+ state->client = client;
+ state->field = V4L2_FIELD_INTERLACED;
+ state->chip_info = (struct adv7180_chip_info *)id->driver_data;
+
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
+ state->csi_client = i2c_new_dummy(client->adapter,
+ ADV7180_DEFAULT_CSI_I2C_ADDR);
+ if (!state->csi_client)
+ return -ENOMEM;
+ }
+
+ if (state->chip_info->flags & ADV7180_FLAG_I2P) {
+ state->vpp_client = i2c_new_dummy(client->adapter,
+ ADV7180_DEFAULT_VPP_I2C_ADDR);
+ if (!state->vpp_client) {
+ ret = -ENOMEM;
+ goto err_unregister_csi_client;
+ }
}
state->irq = client->irq;
mutex_init(&state->mutex);
state->autodetect = true;
- state->powered = true;
+ if (state->chip_info->flags & ADV7180_FLAG_RESET_POWERED)
+ state->powered = true;
+ else
+ state->powered = false;
state->input = 0;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &adv7180_ops);
+ sd->flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
ret = adv7180_init_controls(state);
if (ret)
- goto err_unreg_subdev;
- ret = init_device(client, state);
+ goto err_unregister_vpp_client;
+
+ state->pad.flags = MEDIA_PAD_FL_SOURCE;
+ sd->entity.flags |= MEDIA_ENT_T_V4L2_SUBDEV_DECODER;
+ ret = media_entity_init(&sd->entity, 1, &state->pad, 0);
if (ret)
goto err_free_ctrl;
+ ret = init_device(state);
+ if (ret)
+ goto err_media_entity_cleanup;
+
+ if (state->irq) {
+ ret = request_threaded_irq(client->irq, NULL, adv7180_irq,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+ KBUILD_MODNAME, state);
+ if (ret)
+ goto err_media_entity_cleanup;
+ }
+
ret = v4l2_async_register_subdev(sd);
if (ret)
goto err_free_irq;
@@ -645,11 +1238,17 @@ static int adv7180_probe(struct i2c_client *client,
err_free_irq:
if (state->irq > 0)
free_irq(client->irq, state);
+err_media_entity_cleanup:
+ media_entity_cleanup(&sd->entity);
err_free_ctrl:
adv7180_exit_controls(state);
-err_unreg_subdev:
+err_unregister_vpp_client:
+ if (state->chip_info->flags & ADV7180_FLAG_I2P)
+ i2c_unregister_device(state->vpp_client);
+err_unregister_csi_client:
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+ i2c_unregister_device(state->csi_client);
mutex_destroy(&state->mutex);
-err:
return ret;
}
@@ -663,15 +1262,32 @@ static int adv7180_remove(struct i2c_client *client)
if (state->irq > 0)
free_irq(client->irq, state);
+ media_entity_cleanup(&sd->entity);
adv7180_exit_controls(state);
+
+ if (state->chip_info->flags & ADV7180_FLAG_I2P)
+ i2c_unregister_device(state->vpp_client);
+ if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2)
+ i2c_unregister_device(state->csi_client);
+
mutex_destroy(&state->mutex);
+
return 0;
}
static const struct i2c_device_id adv7180_id[] = {
- {KBUILD_MODNAME, 0},
+ { "adv7180", (kernel_ulong_t)&adv7180_info },
+ { "adv7182", (kernel_ulong_t)&adv7182_info },
+ { "adv7280", (kernel_ulong_t)&adv7280_info },
+ { "adv7280-m", (kernel_ulong_t)&adv7280_m_info },
+ { "adv7281", (kernel_ulong_t)&adv7281_info },
+ { "adv7281-m", (kernel_ulong_t)&adv7281_m_info },
+ { "adv7281-ma", (kernel_ulong_t)&adv7281_ma_info },
+ { "adv7282", (kernel_ulong_t)&adv7282_info },
+ { "adv7282-m", (kernel_ulong_t)&adv7282_m_info },
{},
};
+MODULE_DEVICE_TABLE(i2c, adv7180_id);
#ifdef CONFIG_PM_SLEEP
static int adv7180_suspend(struct device *dev)
@@ -680,7 +1296,7 @@ static int adv7180_suspend(struct device *dev)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct adv7180_state *state = to_state(sd);
- return adv7180_set_power(state, client, false);
+ return adv7180_set_power(state, false);
}
static int adv7180_resume(struct device *dev)
@@ -690,14 +1306,14 @@ static int adv7180_resume(struct device *dev)
struct adv7180_state *state = to_state(sd);
int ret;
- if (state->powered) {
- ret = adv7180_set_power(state, client, true);
- if (ret)
- return ret;
- }
- ret = init_device(client, state);
+ ret = init_device(state);
if (ret < 0)
return ret;
+
+ ret = adv7180_set_power(state, state->powered);
+ if (ret)
+ return ret;
+
return 0;
}
@@ -708,8 +1324,6 @@ static SIMPLE_DEV_PM_OPS(adv7180_pm_ops, adv7180_suspend, adv7180_resume);
#define ADV7180_PM_OPS NULL
#endif
-MODULE_DEVICE_TABLE(i2c, adv7180_id);
-
static struct i2c_driver adv7180_driver = {
.driver = {
.owner = THIS_MODULE,
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index e43dd2e2a38a..d228b7c82310 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -333,21 +333,11 @@ static inline struct adv7604_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct adv7604_state, sd);
}
-static inline unsigned hblanking(const struct v4l2_bt_timings *t)
-{
- return V4L2_DV_BT_BLANKING_WIDTH(t);
-}
-
static inline unsigned htotal(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_FRAME_WIDTH(t);
}
-static inline unsigned vblanking(const struct v4l2_bt_timings *t)
-{
- return V4L2_DV_BT_BLANKING_HEIGHT(t);
-}
-
static inline unsigned vtotal(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_FRAME_HEIGHT(t);
@@ -466,11 +456,6 @@ static inline int cec_write(struct v4l2_subdev *sd, u8 reg, u8 val)
return adv_smbus_write_byte_data(state, ADV7604_PAGE_CEC, reg, val);
}
-static inline int cec_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8 val)
-{
- return cec_write(sd, reg, (cec_read(sd, reg) & ~mask) | val);
-}
-
static inline int infoframe_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
@@ -486,34 +471,6 @@ static inline int infoframe_write(struct v4l2_subdev *sd, u8 reg, u8 val)
reg, val);
}
-static inline int esdp_read(struct v4l2_subdev *sd, u8 reg)
-{
- struct adv7604_state *state = to_state(sd);
-
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_ESDP, reg);
-}
-
-static inline int esdp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
- struct adv7604_state *state = to_state(sd);
-
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_ESDP, reg, val);
-}
-
-static inline int dpp_read(struct v4l2_subdev *sd, u8 reg)
-{
- struct adv7604_state *state = to_state(sd);
-
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_DPP, reg);
-}
-
-static inline int dpp_write(struct v4l2_subdev *sd, u8 reg, u8 val)
-{
- struct adv7604_state *state = to_state(sd);
-
- return adv_smbus_write_byte_data(state, ADV7604_PAGE_DPP, reg, val);
-}
-
static inline int afe_read(struct v4l2_subdev *sd, u8 reg)
{
struct adv7604_state *state = to_state(sd);
@@ -561,32 +518,6 @@ static inline int edid_write(struct v4l2_subdev *sd, u8 reg, u8 val)
return adv_smbus_write_byte_data(state, ADV7604_PAGE_EDID, reg, val);
}
-static inline int edid_read_block(struct v4l2_subdev *sd, unsigned len, u8 *val)
-{
- struct adv7604_state *state = to_state(sd);
- struct i2c_client *client = state->i2c_clients[ADV7604_PAGE_EDID];
- u8 msgbuf0[1] = { 0 };
- u8 msgbuf1[256];
- struct i2c_msg msg[2] = {
- {
- .addr = client->addr,
- .len = 1,
- .buf = msgbuf0
- },
- {
- .addr = client->addr,
- .flags = I2C_M_RD,
- .len = len,
- .buf = msgbuf1
- },
- };
-
- if (i2c_transfer(client->adapter, msg, 2) < 0)
- return -EIO;
- memcpy(val, msgbuf1, len);
- return 0;
-}
-
static inline int edid_write_block(struct v4l2_subdev *sd,
unsigned len, const u8 *val)
{
@@ -652,13 +583,6 @@ static inline int hdmi_write_clr_set(struct v4l2_subdev *sd, u8 reg, u8 mask, u8
return hdmi_write(sd, reg, (hdmi_read(sd, reg) & ~mask) | val);
}
-static inline int test_read(struct v4l2_subdev *sd, u8 reg)
-{
- struct adv7604_state *state = to_state(sd);
-
- return adv_smbus_read_byte_data(state, ADV7604_PAGE_TEST, reg);
-}
-
static inline int test_write(struct v4l2_subdev *sd, u8 reg, u8 val)
{
struct adv7604_state *state = to_state(sd);
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 75d26dfd0939..7c215ee142c4 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -38,6 +38,7 @@
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <linux/v4l2-dv-timings.h>
+#include <linux/hdmi.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dv-timings.h>
@@ -220,21 +221,11 @@ static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
return &container_of(ctrl->handler, struct adv7842_state, hdl)->sd;
}
-static inline unsigned hblanking(const struct v4l2_bt_timings *t)
-{
- return V4L2_DV_BT_BLANKING_WIDTH(t);
-}
-
static inline unsigned htotal(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_FRAME_WIDTH(t);
}
-static inline unsigned vblanking(const struct v4l2_bt_timings *t)
-{
- return V4L2_DV_BT_BLANKING_HEIGHT(t);
-}
-
static inline unsigned vtotal(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_FRAME_HEIGHT(t);
@@ -2108,149 +2099,65 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
return err;
}
-/*********** avi info frame CEA-861-E **************/
-/* TODO move to common library */
-
-struct avi_info_frame {
- uint8_t f17;
- uint8_t y10;
- uint8_t a0;
- uint8_t b10;
- uint8_t s10;
- uint8_t c10;
- uint8_t m10;
- uint8_t r3210;
- uint8_t itc;
- uint8_t ec210;
- uint8_t q10;
- uint8_t sc10;
- uint8_t f47;
- uint8_t vic;
- uint8_t yq10;
- uint8_t cn10;
- uint8_t pr3210;
- uint16_t etb;
- uint16_t sbb;
- uint16_t elb;
- uint16_t srb;
-};
-
-static const char *y10_txt[4] = {
- "RGB",
- "YCbCr 4:2:2",
- "YCbCr 4:4:4",
- "Future",
-};
-
-static const char *c10_txt[4] = {
- "No Data",
- "SMPTE 170M",
- "ITU-R 709",
- "Extended Colorimetry information valied",
-};
-
-static const char *itc_txt[2] = {
- "No Data",
- "IT content",
-};
-
-static const char *ec210_txt[8] = {
- "xvYCC601",
- "xvYCC709",
- "sYCC601",
- "AdobeYCC601",
- "AdobeRGB",
- "5 reserved",
- "6 reserved",
- "7 reserved",
+struct adv7842_cfg_read_infoframe {
+ const char *desc;
+ u8 present_mask;
+ u8 head_addr;
+ u8 payload_addr;
};
-static const char *q10_txt[4] = {
- "Default",
- "Limited Range",
- "Full Range",
- "Reserved",
-};
-
-static void parse_avi_infoframe(struct v4l2_subdev *sd, uint8_t *buf,
- struct avi_info_frame *avi)
-{
- avi->f17 = (buf[1] >> 7) & 0x1;
- avi->y10 = (buf[1] >> 5) & 0x3;
- avi->a0 = (buf[1] >> 4) & 0x1;
- avi->b10 = (buf[1] >> 2) & 0x3;
- avi->s10 = buf[1] & 0x3;
- avi->c10 = (buf[2] >> 6) & 0x3;
- avi->m10 = (buf[2] >> 4) & 0x3;
- avi->r3210 = buf[2] & 0xf;
- avi->itc = (buf[3] >> 7) & 0x1;
- avi->ec210 = (buf[3] >> 4) & 0x7;
- avi->q10 = (buf[3] >> 2) & 0x3;
- avi->sc10 = buf[3] & 0x3;
- avi->f47 = (buf[4] >> 7) & 0x1;
- avi->vic = buf[4] & 0x7f;
- avi->yq10 = (buf[5] >> 6) & 0x3;
- avi->cn10 = (buf[5] >> 4) & 0x3;
- avi->pr3210 = buf[5] & 0xf;
- avi->etb = buf[6] + 256*buf[7];
- avi->sbb = buf[8] + 256*buf[9];
- avi->elb = buf[10] + 256*buf[11];
- avi->srb = buf[12] + 256*buf[13];
-}
-
-static void print_avi_infoframe(struct v4l2_subdev *sd)
+static void log_infoframe(struct v4l2_subdev *sd, struct adv7842_cfg_read_infoframe *cri)
{
int i;
- uint8_t buf[14];
- u8 avi_len;
- u8 avi_ver;
- struct avi_info_frame avi;
+ uint8_t buffer[32];
+ union hdmi_infoframe frame;
+ u8 len;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
- if (!(hdmi_read(sd, 0x05) & 0x80)) {
- v4l2_info(sd, "receive DVI-D signal (AVI infoframe not supported)\n");
- return;
- }
- if (!(io_read(sd, 0x60) & 0x01)) {
- v4l2_info(sd, "AVI infoframe not received\n");
+ if (!(io_read(sd, 0x60) & cri->present_mask)) {
+ v4l2_info(sd, "%s infoframe not received\n", cri->desc);
return;
}
- if (io_read(sd, 0x88) & 0x10) {
- v4l2_info(sd, "AVI infoframe checksum error has occurred earlier\n");
- io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
- if (io_read(sd, 0x88) & 0x10) {
- v4l2_info(sd, "AVI infoframe checksum error still present\n");
- io_write(sd, 0x8a, 0x10); /* clear AVI_INF_CKS_ERR_RAW */
- }
- }
+ for (i = 0; i < 3; i++)
+ buffer[i] = infoframe_read(sd, cri->head_addr + i);
- avi_len = infoframe_read(sd, 0xe2);
- avi_ver = infoframe_read(sd, 0xe1);
- v4l2_info(sd, "AVI infoframe version %d (%d byte)\n",
- avi_ver, avi_len);
+ len = buffer[2] + 1;
- if (avi_ver != 0x02)
+ if (len + 3 > sizeof(buffer)) {
+ v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
return;
+ }
+
+ for (i = 0; i < len; i++)
+ buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
- for (i = 0; i < 14; i++)
- buf[i] = infoframe_read(sd, i);
+ if (hdmi_infoframe_unpack(&frame, buffer) < 0) {
+ v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
+ return;
+ }
- v4l2_info(sd, "\t%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
- buf[8], buf[9], buf[10], buf[11], buf[12], buf[13]);
+ hdmi_infoframe_log(KERN_INFO, dev, &frame);
+}
- parse_avi_infoframe(sd, buf, &avi);
+static void adv7842_log_infoframes(struct v4l2_subdev *sd)
+{
+ int i;
+ struct adv7842_cfg_read_infoframe cri[] = {
+ { "AVI", 0x01, 0xe0, 0x00 },
+ { "Audio", 0x02, 0xe3, 0x1c },
+ { "SDP", 0x04, 0xe6, 0x2a },
+ { "Vendor", 0x10, 0xec, 0x54 }
+ };
- if (avi.vic)
- v4l2_info(sd, "\tVIC: %d\n", avi.vic);
- if (avi.itc)
- v4l2_info(sd, "\t%s\n", itc_txt[avi.itc]);
+ if (!(hdmi_read(sd, 0x05) & 0x80)) {
+ v4l2_info(sd, "receive DVI-D signal, no infoframes\n");
+ return;
+ }
- if (avi.y10)
- v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], !avi.c10 ? "" :
- (avi.c10 == 0x3 ? ec210_txt[avi.ec210] : c10_txt[avi.c10]));
- else
- v4l2_info(sd, "\t%s %s\n", y10_txt[avi.y10], q10_txt[avi.q10]);
+ for (i = 0; i < ARRAY_SIZE(cri); i++)
+ log_infoframe(sd, &cri[i]);
}
static const char * const prim_mode_txt[] = {
@@ -2464,7 +2371,8 @@ static int adv7842_cp_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "Deep color mode: %s\n",
deep_color_mode_txt[hdmi_read(sd, 0x0b) >> 6]);
- print_avi_infoframe(sd);
+ adv7842_log_infoframes(sd);
+
return 0;
}
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 2820f7c38cba..6ed16e569bbf 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -125,9 +125,9 @@ static u32 m5mols_swap_byte(u8 *data, u8 length)
if (length == 1)
return *data;
else if (length == 2)
- return be16_to_cpu(*((u16 *)data));
+ return be16_to_cpu(*((__be16 *)data));
else
- return be32_to_cpu(*((u32 *)data));
+ return be32_to_cpu(*((__be32 *)data));
}
/**
@@ -454,11 +454,6 @@ static int m5mols_get_version(struct v4l2_subdev *sd)
return ret;
}
- ver->fw = be16_to_cpu(ver->fw);
- ver->hw = be16_to_cpu(ver->hw);
- ver->param = be16_to_cpu(ver->param);
- ver->awb = be16_to_cpu(ver->awb);
-
v4l2_info(sd, "Manufacturer\t[%s]\n",
is_manufacturer(info, REG_SAMSUNG_ELECTRO) ?
"Samsung Electro-Machanics" :
diff --git a/drivers/media/i2c/msp3400-driver.c b/drivers/media/i2c/msp3400-driver.c
index 4d9c6bc34265..dcc68ec71732 100644
--- a/drivers/media/i2c/msp3400-driver.c
+++ b/drivers/media/i2c/msp3400-driver.c
@@ -904,11 +904,3 @@ static struct i2c_driver msp_driver = {
};
module_i2c_driver(msp_driver);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 45b3fca188ca..76431223f0ff 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -422,22 +422,25 @@ done:
return ret;
}
-static int mt9m032_get_pad_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9m032_get_pad_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
mutex_lock(&sensor->lock);
- crop->rect = *__mt9m032_get_pad_crop(sensor, fh, crop->which);
+ sel->r = *__mt9m032_get_pad_crop(sensor, fh, sel->which);
mutex_unlock(&sensor->lock);
return 0;
}
-static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9m032_set_pad_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9m032 *sensor = to_mt9m032(subdev);
struct v4l2_mbus_framefmt *format;
@@ -445,9 +448,12 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
struct v4l2_rect rect;
int ret = 0;
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
mutex_lock(&sensor->lock);
- if (sensor->streaming && crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (sensor->streaming && sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
ret = -EBUSY;
goto done;
}
@@ -455,13 +461,13 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
/* Clamp the crop rectangle boundaries and align them to a multiple of 2
* pixels to ensure a GRBG Bayer pattern.
*/
- rect.left = clamp(ALIGN(crop->rect.left, 2), MT9M032_COLUMN_START_MIN,
+ rect.left = clamp(ALIGN(sel->r.left, 2), MT9M032_COLUMN_START_MIN,
MT9M032_COLUMN_START_MAX);
- rect.top = clamp(ALIGN(crop->rect.top, 2), MT9M032_ROW_START_MIN,
+ rect.top = clamp(ALIGN(sel->r.top, 2), MT9M032_ROW_START_MIN,
MT9M032_ROW_START_MAX);
- rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
MT9M032_COLUMN_SIZE_MIN, MT9M032_COLUMN_SIZE_MAX);
- rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
MT9M032_ROW_SIZE_MIN, MT9M032_ROW_SIZE_MAX);
rect.width = min_t(unsigned int, rect.width,
@@ -469,21 +475,21 @@ static int mt9m032_set_pad_crop(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9M032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9m032_get_pad_crop(sensor, fh, crop->which);
+ __crop = __mt9m032_get_pad_crop(sensor, fh, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- format = __mt9m032_get_pad_format(sensor, fh, crop->which);
+ format = __mt9m032_get_pad_format(sensor, fh, sel->which);
format->width = rect.width;
format->height = rect.height;
}
*__crop = rect;
- crop->rect = rect;
+ sel->r = rect;
- if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE)
ret = mt9m032_update_geom_timing(sensor);
done:
@@ -690,8 +696,8 @@ static const struct v4l2_subdev_pad_ops mt9m032_pad_ops = {
.enum_frame_size = mt9m032_enum_frame_size,
.get_fmt = mt9m032_get_pad_format,
.set_fmt = mt9m032_set_pad_format,
- .set_crop = mt9m032_set_pad_crop,
- .get_crop = mt9m032_get_pad_crop,
+ .set_selection = mt9m032_set_pad_selection,
+ .get_selection = mt9m032_get_pad_selection,
};
static const struct v4l2_subdev_ops mt9m032_ops = {
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index edb76bd33d16..e3acae9a2ec3 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -581,37 +581,42 @@ static int mt9p031_set_format(struct v4l2_subdev *subdev,
return 0;
}
-static int mt9p031_get_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9p031_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
- crop->rect = *__mt9p031_get_pad_crop(mt9p031, fh, crop->pad,
- crop->which);
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ sel->r = *__mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which);
return 0;
}
-static int mt9p031_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9p031_set_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9p031 *mt9p031 = to_mt9p031(subdev);
struct v4l2_mbus_framefmt *__format;
struct v4l2_rect *__crop;
struct v4l2_rect rect;
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
/* Clamp the crop rectangle boundaries and align them to a multiple of 2
* pixels to ensure a GRBG Bayer pattern.
*/
- rect.left = clamp(ALIGN(crop->rect.left, 2), MT9P031_COLUMN_START_MIN,
+ rect.left = clamp(ALIGN(sel->r.left, 2), MT9P031_COLUMN_START_MIN,
MT9P031_COLUMN_START_MAX);
- rect.top = clamp(ALIGN(crop->rect.top, 2), MT9P031_ROW_START_MIN,
+ rect.top = clamp(ALIGN(sel->r.top, 2), MT9P031_ROW_START_MIN,
MT9P031_ROW_START_MAX);
- rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
MT9P031_WINDOW_WIDTH_MIN,
MT9P031_WINDOW_WIDTH_MAX);
- rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
MT9P031_WINDOW_HEIGHT_MIN,
MT9P031_WINDOW_HEIGHT_MAX);
@@ -620,20 +625,20 @@ static int mt9p031_set_crop(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9P031_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9p031_get_pad_crop(mt9p031, fh, crop->pad, crop->which);
+ __crop = __mt9p031_get_pad_crop(mt9p031, fh, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9p031_get_pad_format(mt9p031, fh, crop->pad,
- crop->which);
+ __format = __mt9p031_get_pad_format(mt9p031, fh, sel->pad,
+ sel->which);
__format->width = rect.width;
__format->height = rect.height;
}
*__crop = rect;
- crop->rect = rect;
+ sel->r = rect;
return 0;
}
@@ -980,8 +985,8 @@ static struct v4l2_subdev_pad_ops mt9p031_subdev_pad_ops = {
.enum_frame_size = mt9p031_enum_frame_size,
.get_fmt = mt9p031_get_format,
.set_fmt = mt9p031_set_format,
- .get_crop = mt9p031_get_crop,
- .set_crop = mt9p031_set_crop,
+ .get_selection = mt9p031_get_selection,
+ .set_selection = mt9p031_set_selection,
};
static struct v4l2_subdev_ops mt9p031_subdev_ops = {
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index d9e9889b579f..f6ca636b538d 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -401,39 +401,44 @@ static int mt9t001_set_format(struct v4l2_subdev *subdev,
return 0;
}
-static int mt9t001_get_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9t001_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
- crop->rect = *__mt9t001_get_pad_crop(mt9t001, fh, crop->pad,
- crop->which);
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ sel->r = *__mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which);
return 0;
}
-static int mt9t001_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9t001_set_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9t001 *mt9t001 = to_mt9t001(subdev);
struct v4l2_mbus_framefmt *__format;
struct v4l2_rect *__crop;
struct v4l2_rect rect;
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
/* Clamp the crop rectangle boundaries and align them to a multiple of 2
* pixels.
*/
- rect.left = clamp(ALIGN(crop->rect.left, 2),
+ rect.left = clamp(ALIGN(sel->r.left, 2),
MT9T001_COLUMN_START_MIN,
MT9T001_COLUMN_START_MAX);
- rect.top = clamp(ALIGN(crop->rect.top, 2),
+ rect.top = clamp(ALIGN(sel->r.top, 2),
MT9T001_ROW_START_MIN,
MT9T001_ROW_START_MAX);
- rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
MT9T001_WINDOW_WIDTH_MIN + 1,
MT9T001_WINDOW_WIDTH_MAX + 1);
- rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
MT9T001_WINDOW_HEIGHT_MIN + 1,
MT9T001_WINDOW_HEIGHT_MAX + 1);
@@ -442,20 +447,20 @@ static int mt9t001_set_crop(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int, rect.height,
MT9T001_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9t001_get_pad_crop(mt9t001, fh, crop->pad, crop->which);
+ __crop = __mt9t001_get_pad_crop(mt9t001, fh, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9t001_get_pad_format(mt9t001, fh, crop->pad,
- crop->which);
+ __format = __mt9t001_get_pad_format(mt9t001, fh, sel->pad,
+ sel->which);
__format->width = rect.width;
__format->height = rect.height;
}
*__crop = rect;
- crop->rect = rect;
+ sel->r = rect;
return 0;
}
@@ -819,8 +824,8 @@ static struct v4l2_subdev_pad_ops mt9t001_subdev_pad_ops = {
.enum_frame_size = mt9t001_enum_frame_size,
.get_fmt = mt9t001_get_format,
.set_fmt = mt9t001_set_format,
- .get_crop = mt9t001_get_crop,
- .set_crop = mt9t001_set_crop,
+ .get_selection = mt9t001_get_selection,
+ .set_selection = mt9t001_set_selection,
};
static struct v4l2_subdev_ops mt9t001_subdev_ops = {
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index 93687c1e4097..bd3f979a4d49 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -552,39 +552,44 @@ static int mt9v032_set_format(struct v4l2_subdev *subdev,
return 0;
}
-static int mt9v032_get_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9v032_get_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
- crop->rect = *__mt9v032_get_pad_crop(mt9v032, fh, crop->pad,
- crop->which);
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ sel->r = *__mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
return 0;
}
-static int mt9v032_set_crop(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int mt9v032_set_selection(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct mt9v032 *mt9v032 = to_mt9v032(subdev);
struct v4l2_mbus_framefmt *__format;
struct v4l2_rect *__crop;
struct v4l2_rect rect;
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
/* Clamp the crop rectangle boundaries and align them to a non multiple
* of 2 pixels to ensure a GRBG Bayer pattern.
*/
- rect.left = clamp(ALIGN(crop->rect.left + 1, 2) - 1,
+ rect.left = clamp(ALIGN(sel->r.left + 1, 2) - 1,
MT9V032_COLUMN_START_MIN,
MT9V032_COLUMN_START_MAX);
- rect.top = clamp(ALIGN(crop->rect.top + 1, 2) - 1,
+ rect.top = clamp(ALIGN(sel->r.top + 1, 2) - 1,
MT9V032_ROW_START_MIN,
MT9V032_ROW_START_MAX);
- rect.width = clamp_t(unsigned int, ALIGN(crop->rect.width, 2),
+ rect.width = clamp_t(unsigned int, ALIGN(sel->r.width, 2),
MT9V032_WINDOW_WIDTH_MIN,
MT9V032_WINDOW_WIDTH_MAX);
- rect.height = clamp_t(unsigned int, ALIGN(crop->rect.height, 2),
+ rect.height = clamp_t(unsigned int, ALIGN(sel->r.height, 2),
MT9V032_WINDOW_HEIGHT_MIN,
MT9V032_WINDOW_HEIGHT_MAX);
@@ -593,17 +598,17 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
rect.height = min_t(unsigned int,
rect.height, MT9V032_PIXEL_ARRAY_HEIGHT - rect.top);
- __crop = __mt9v032_get_pad_crop(mt9v032, fh, crop->pad, crop->which);
+ __crop = __mt9v032_get_pad_crop(mt9v032, fh, sel->pad, sel->which);
if (rect.width != __crop->width || rect.height != __crop->height) {
/* Reset the output image size if the crop rectangle size has
* been modified.
*/
- __format = __mt9v032_get_pad_format(mt9v032, fh, crop->pad,
- crop->which);
+ __format = __mt9v032_get_pad_format(mt9v032, fh, sel->pad,
+ sel->which);
__format->width = rect.width;
__format->height = rect.height;
- if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
mt9v032->hratio = 1;
mt9v032->vratio = 1;
mt9v032_configure_pixel_rate(mt9v032);
@@ -611,7 +616,7 @@ static int mt9v032_set_crop(struct v4l2_subdev *subdev,
}
*__crop = rect;
- crop->rect = rect;
+ sel->r = rect;
return 0;
}
@@ -844,8 +849,8 @@ static struct v4l2_subdev_pad_ops mt9v032_subdev_pad_ops = {
.enum_frame_size = mt9v032_enum_frame_size,
.get_fmt = mt9v032_get_format,
.set_fmt = mt9v032_set_format,
- .get_crop = mt9v032_get_crop,
- .set_crop = mt9v032_set_crop,
+ .get_selection = mt9v032_get_selection,
+ .set_selection = mt9v032_set_selection,
};
static struct v4l2_subdev_ops mt9v032_subdev_ops = {
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index d1c50c9d43ae..70071314789e 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -220,7 +220,7 @@ static int s5k4ecgx_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
msg[1].buf = rbuf;
ret = i2c_transfer(client->adapter, msg, 2);
- *val = be16_to_cpu(*((u16 *)rbuf));
+ *val = be16_to_cpu(*((__be16 *)rbuf));
v4l2_dbg(4, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
@@ -341,7 +341,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
v4l2_err(sd, "Failed to read firmware %s\n", S5K4ECGX_FIRMWARE);
return err;
}
- regs_num = le32_to_cpu(get_unaligned_le32(fw->data));
+ regs_num = get_unaligned_le32(fw->data);
v4l2_dbg(3, debug, sd, "FW: %s size %zu register sets %d\n",
S5K4ECGX_FIRMWARE, fw->size, regs_num);
@@ -351,8 +351,7 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
err = -EINVAL;
goto fw_out;
}
- crc_file = le32_to_cpu(get_unaligned_le32(fw->data +
- regs_num * FW_RECORD_SIZE));
+ crc_file = get_unaligned_le32(fw->data + regs_num * FW_RECORD_SIZE);
crc = crc32_le(~0, fw->data, regs_num * FW_RECORD_SIZE);
if (crc != crc_file) {
v4l2_err(sd, "FW: invalid crc (%#x:%#x)\n", crc, crc_file);
@@ -361,9 +360,9 @@ static int s5k4ecgx_load_firmware(struct v4l2_subdev *sd)
}
ptr = fw->data + FW_RECORD_SIZE;
for (i = 1; i < regs_num; i++) {
- addr = le32_to_cpu(get_unaligned_le32(ptr));
+ addr = get_unaligned_le32(ptr);
ptr += sizeof(u32);
- val = le16_to_cpu(get_unaligned_le16(ptr));
+ val = get_unaligned_le16(ptr);
ptr += sizeof(u16);
if (addr - addr_inc != 2)
err = s5k4ecgx_write(client, addr, val);
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 60a74d8d38d5..a3d7d0391302 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -353,7 +353,7 @@ static struct v4l2_rect s5k5baf_cis_rect = {
*
*/
static int s5k5baf_fw_parse(struct device *dev, struct s5k5baf_fw **fw,
- size_t count, const u16 *data)
+ size_t count, const __le16 *data)
{
struct s5k5baf_fw *f;
u16 *d, i, *end;
@@ -421,6 +421,7 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr)
{
struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
__be16 w, r;
+ u16 res;
struct i2c_msg msg[] = {
{ .addr = c->addr, .flags = 0,
.len = 2, .buf = (u8 *)&w },
@@ -434,15 +435,15 @@ static u16 s5k5baf_i2c_read(struct s5k5baf *state, u16 addr)
w = cpu_to_be16(addr);
ret = i2c_transfer(c->adapter, msg, 2);
- r = be16_to_cpu(r);
+ res = be16_to_cpu(r);
- v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, r);
+ v4l2_dbg(3, debug, c, "i2c_read: 0x%04x : 0x%04x\n", addr, res);
if (ret != 2) {
v4l2_err(c, "i2c_read: error during transfer (%d)\n", ret);
state->error = ret;
}
- return r;
+ return res;
}
static void s5k5baf_i2c_write(struct s5k5baf *state, u16 addr, u16 val)
@@ -1037,7 +1038,7 @@ static int s5k5baf_load_setfile(struct s5k5baf *state)
}
ret = s5k5baf_fw_parse(&c->dev, &state->fw, fw->size / 2,
- (u16 *)fw->data);
+ (__le16 *)fw->data);
release_firmware(fw);
@@ -1793,7 +1794,7 @@ static const struct v4l2_subdev_ops s5k5baf_subdev_ops = {
static int s5k5baf_configure_gpios(struct s5k5baf *state)
{
- static const char const *name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
+ static const char * const name[] = { "S5K5BAF_STBY", "S5K5BAF_RST" };
struct i2c_client *c = v4l2_get_subdevdata(&state->sd);
struct s5k5baf_gpio *g = state->gpios;
int ret, i;
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 2851581e0061..b1c583239dab 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -348,7 +348,7 @@ static int s5k6aa_i2c_read(struct i2c_client *client, u16 addr, u16 *val)
msg[1].buf = rbuf;
ret = i2c_transfer(client->adapter, msg, 2);
- *val = be16_to_cpu(*((u16 *)rbuf));
+ *val = be16_to_cpu(*((__be16 *)rbuf));
v4l2_dbg(3, debug, client, "i2c_read: 0x%04X : 0x%04x\n", addr, *val);
@@ -1161,17 +1161,21 @@ static int s5k6aa_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return ret;
}
-static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int s5k6aa_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
struct v4l2_rect *rect;
- memset(crop->reserved, 0, sizeof(crop->reserved));
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ memset(sel->reserved, 0, sizeof(sel->reserved));
mutex_lock(&s5k6aa->lock);
- rect = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
- crop->rect = *rect;
+ rect = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which);
+ sel->r = *rect;
mutex_unlock(&s5k6aa->lock);
v4l2_dbg(1, debug, sd, "Current crop rectangle: (%d,%d)/%dx%d\n",
@@ -1180,35 +1184,39 @@ static int s5k6aa_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
return 0;
}
-static int s5k6aa_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+static int s5k6aa_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct s5k6aa *s5k6aa = to_s5k6aa(sd);
struct v4l2_mbus_framefmt *mf;
unsigned int max_x, max_y;
struct v4l2_rect *crop_r;
+ if (sel->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
mutex_lock(&s5k6aa->lock);
- crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, crop->which);
+ crop_r = __s5k6aa_get_crop_rect(s5k6aa, fh, sel->which);
- if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
mf = &s5k6aa->preset->mbus_fmt;
s5k6aa->apply_crop = 1;
} else {
mf = v4l2_subdev_get_try_format(fh, 0);
}
- v4l_bound_align_image(&crop->rect.width, mf->width,
+ v4l_bound_align_image(&sel->r.width, mf->width,
S5K6AA_WIN_WIDTH_MAX, 1,
- &crop->rect.height, mf->height,
+ &sel->r.height, mf->height,
S5K6AA_WIN_HEIGHT_MAX, 1, 0);
- max_x = (S5K6AA_WIN_WIDTH_MAX - crop->rect.width) & ~1;
- max_y = (S5K6AA_WIN_HEIGHT_MAX - crop->rect.height) & ~1;
+ max_x = (S5K6AA_WIN_WIDTH_MAX - sel->r.width) & ~1;
+ max_y = (S5K6AA_WIN_HEIGHT_MAX - sel->r.height) & ~1;
- crop->rect.left = clamp_t(unsigned int, crop->rect.left, 0, max_x);
- crop->rect.top = clamp_t(unsigned int, crop->rect.top, 0, max_y);
+ sel->r.left = clamp_t(unsigned int, sel->r.left, 0, max_x);
+ sel->r.top = clamp_t(unsigned int, sel->r.top, 0, max_y);
- *crop_r = crop->rect;
+ *crop_r = sel->r;
mutex_unlock(&s5k6aa->lock);
@@ -1224,8 +1232,8 @@ static const struct v4l2_subdev_pad_ops s5k6aa_pad_ops = {
.enum_frame_interval = s5k6aa_enum_frame_interval,
.get_fmt = s5k6aa_get_fmt,
.set_fmt = s5k6aa_set_fmt,
- .get_crop = s5k6aa_get_crop,
- .set_crop = s5k6aa_set_crop,
+ .get_selection = s5k6aa_get_selection,
+ .set_selection = s5k6aa_set_selection,
};
static const struct v4l2_subdev_video_ops s5k6aa_video_ops = {
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
index e40d9027df3d..e3348db56c46 100644
--- a/drivers/media/i2c/smiapp-pll.c
+++ b/drivers/media/i2c/smiapp-pll.c
@@ -14,14 +14,9 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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/device.h>
#include <linux/gcd.h>
#include <linux/lcm.h>
#include <linux/module.h>
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
index e8f035a50c76..b98d143b64e1 100644
--- a/drivers/media/i2c/smiapp-pll.h
+++ b/drivers/media/i2c/smiapp-pll.h
@@ -14,19 +14,11 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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 SMIAPP_PLL_H
#define SMIAPP_PLL_H
-#include <linux/device.h>
-
/* CSI-2 or CCP-2 */
#define SMIAPP_PLL_BUS_TYPE_CSI2 0x00
#define SMIAPP_PLL_BUS_TYPE_PARALLEL 0x01
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 0df5070e73c7..d47eff5d3101 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -18,12 +18,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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>
@@ -31,11 +25,13 @@
#include <linux/device.h>
#include <linux/gpio.h>
#include <linux/module.h>
+#include <linux/of_gpio.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/smiapp.h>
#include <linux/v4l2-mediabus.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-of.h>
#include "smiapp.h"
@@ -523,14 +519,12 @@ 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;
rval = v4l2_ctrl_handler_init(&sensor->pixel_array->ctrl_handler, 12);
if (rval)
return rval;
+
sensor->pixel_array->ctrl_handler.lock = &sensor->mutex;
sensor->analog_gain = v4l2_ctrl_new_std(
@@ -576,21 +570,11 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
ARRAY_SIZE(smiapp_test_patterns) - 1,
0, 0, smiapp_test_patterns);
- for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
- int max_value = (1 << sensor->csi_format->width) - 1;
- sensor->test_data[i] =
- v4l2_ctrl_new_std(
- &sensor->pixel_array->ctrl_handler,
- &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
- 0, max_value, 1, max_value);
- }
-
if (sensor->pixel_array->ctrl_handler.error) {
dev_err(&client->dev,
"pixel array controls initialization failed (%d)\n",
sensor->pixel_array->ctrl_handler.error);
- rval = sensor->pixel_array->ctrl_handler.error;
- goto error;
+ return sensor->pixel_array->ctrl_handler.error;
}
sensor->pixel_array->sd.ctrl_handler =
@@ -600,15 +584,9 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
rval = v4l2_ctrl_handler_init(&sensor->src->ctrl_handler, 0);
if (rval)
- goto error;
- sensor->src->ctrl_handler.lock = &sensor->mutex;
-
- for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+ return rval;
- sensor->link_freq = v4l2_ctrl_new_int_menu(
- &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs),
- __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock);
+ sensor->src->ctrl_handler.lock = &sensor->mutex;
sensor->pixel_rate_csi = v4l2_ctrl_new_std(
&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
@@ -618,20 +596,41 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
dev_err(&client->dev,
"src controls initialization failed (%d)\n",
sensor->src->ctrl_handler.error);
- rval = sensor->src->ctrl_handler.error;
- goto error;
+ return sensor->src->ctrl_handler.error;
}
- sensor->src->sd.ctrl_handler =
- &sensor->src->ctrl_handler;
+ sensor->src->sd.ctrl_handler = &sensor->src->ctrl_handler;
return 0;
+}
+
+/*
+ * For controls that require information on available media bus codes
+ * and linke frequencies.
+ */
+static int smiapp_init_late_controls(struct smiapp_sensor *sensor)
+{
+ unsigned long *valid_link_freqs = &sensor->valid_link_freqs[
+ sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE];
+ unsigned int max, i;
-error:
- v4l2_ctrl_handler_free(&sensor->pixel_array->ctrl_handler);
- v4l2_ctrl_handler_free(&sensor->src->ctrl_handler);
+ for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++) {
+ int max_value = (1 << sensor->csi_format->width) - 1;
- return rval;
+ sensor->test_data[i] = v4l2_ctrl_new_std(
+ &sensor->pixel_array->ctrl_handler,
+ &smiapp_ctrl_ops, V4L2_CID_TEST_PATTERN_RED + i,
+ 0, max_value, 1, max_value);
+ }
+
+ for (max = 0; sensor->platform_data->op_sys_clock[max + 1]; max++);
+
+ sensor->link_freq = v4l2_ctrl_new_int_menu(
+ &sensor->src->ctrl_handler, &smiapp_ctrl_ops,
+ V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs),
+ __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock);
+
+ return sensor->src->ctrl_handler.error;
}
static void smiapp_free_controls(struct smiapp_sensor *sensor)
@@ -1487,7 +1486,7 @@ static int smiapp_start_streaming(struct smiapp_sensor *sensor)
if (rval < 0)
goto out;
- if ((sensor->flash_capability &
+ if ((sensor->limits[SMIAPP_LIMIT_FLASH_MODE_CAPABILITY] &
(SMIAPP_FLASH_MODE_CAPABILITY_SINGLE_STROBE |
SMIAPP_FLASH_MODE_CAPABILITY_MULTIPLE_STROBE)) &&
sensor->platform_data->strobe_setup != NULL &&
@@ -2338,10 +2337,9 @@ static DEVICE_ATTR(ident, S_IRUGO, smiapp_sysfs_ident_read, NULL);
* V4L2 subdev core operations
*/
-static int smiapp_identify_module(struct v4l2_subdev *subdev)
+static int smiapp_identify_module(struct smiapp_sensor *sensor)
{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct smiapp_module_info *minfo = &sensor->minfo;
unsigned int i;
int rval = 0;
@@ -2464,8 +2462,6 @@ static int smiapp_identify_module(struct v4l2_subdev *subdev)
minfo->name, minfo->manufacturer_id, minfo->model_id,
minfo->revision_number_major);
- strlcpy(subdev->name, sensor->minfo.name, sizeof(subdev->name));
-
return 0;
}
@@ -2473,13 +2469,71 @@ static const struct v4l2_subdev_ops smiapp_ops;
static const struct v4l2_subdev_internal_ops smiapp_internal_ops;
static const struct media_entity_operations smiapp_entity_ops;
-static int smiapp_registered(struct v4l2_subdev *subdev)
+static int smiapp_register_subdevs(struct smiapp_sensor *sensor)
{
- struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct smiapp_subdev *ssds[] = {
+ sensor->scaler,
+ sensor->binner,
+ sensor->pixel_array,
+ };
+ unsigned int i;
+ int rval;
+
+ for (i = 0; i < SMIAPP_SUBDEVS - 1; i++) {
+ struct smiapp_subdev *this = ssds[i + 1];
+ struct smiapp_subdev *last = ssds[i];
+
+ if (!last)
+ continue;
+
+ rval = media_entity_init(&this->sd.entity,
+ this->npads, this->pads, 0);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_init failed\n");
+ return rval;
+ }
+
+ rval = media_entity_create_link(&this->sd.entity,
+ this->source_pad,
+ &last->sd.entity,
+ last->sink_pad,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (rval) {
+ dev_err(&client->dev,
+ "media_entity_create_link failed\n");
+ return rval;
+ }
+
+ rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
+ &this->sd);
+ if (rval) {
+ dev_err(&client->dev,
+ "v4l2_device_register_subdev failed\n");
+ return rval;
+ }
+ }
+
+ return 0;
+}
+
+static void smiapp_cleanup(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+
+ device_remove_file(&client->dev, &dev_attr_nvm);
+ device_remove_file(&client->dev, &dev_attr_ident);
+
+ smiapp_free_controls(sensor);
+}
+
+static int smiapp_init(struct smiapp_sensor *sensor)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct smiapp_pll *pll = &sensor->pll;
struct smiapp_subdev *last = NULL;
- u32 tmp;
unsigned int i;
int rval;
@@ -2490,7 +2544,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
}
if (!sensor->platform_data->set_xclk) {
- sensor->ext_clk = devm_clk_get(&client->dev, "ext_clk");
+ sensor->ext_clk = devm_clk_get(&client->dev, NULL);
if (IS_ERR(sensor->ext_clk)) {
dev_err(&client->dev, "could not get clock\n");
return PTR_ERR(sensor->ext_clk);
@@ -2522,7 +2576,7 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
if (rval)
return -ENODEV;
- rval = smiapp_identify_module(subdev);
+ rval = smiapp_identify_module(sensor);
if (rval) {
rval = -ENODEV;
goto out_power_off;
@@ -2602,13 +2656,13 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
if (sensor->nvm == NULL) {
dev_err(&client->dev, "nvm buf allocation failed\n");
rval = -ENOMEM;
- goto out_ident_release;
+ goto out_cleanup;
}
if (device_create_file(&client->dev, &dev_attr_nvm) != 0) {
dev_err(&client->dev, "sysfs nvm entry failed\n");
rval = -EBUSY;
- goto out_ident_release;
+ goto out_cleanup;
}
}
@@ -2643,18 +2697,11 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
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;
@@ -2711,34 +2758,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
this->sd.owner = THIS_MODULE;
v4l2_set_subdevdata(&this->sd, client);
- rval = media_entity_init(&this->sd.entity,
- this->npads, this->pads, 0);
- if (rval) {
- dev_err(&client->dev,
- "media_entity_init failed\n");
- goto out_nvm_release;
- }
-
- rval = media_entity_create_link(&this->sd.entity,
- this->source_pad,
- &last->sd.entity,
- last->sink_pad,
- MEDIA_LNK_FL_ENABLED |
- MEDIA_LNK_FL_IMMUTABLE);
- if (rval) {
- dev_err(&client->dev,
- "media_entity_create_link failed\n");
- goto out_nvm_release;
- }
-
- rval = v4l2_device_register_subdev(sensor->src->sd.v4l2_dev,
- &this->sd);
- if (rval) {
- dev_err(&client->dev,
- "v4l2_device_register_subdev failed\n");
- goto out_nvm_release;
- }
-
last = this;
}
@@ -2750,40 +2769,66 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
smiapp_read_frame_fmt(sensor);
rval = smiapp_init_controls(sensor);
if (rval < 0)
- goto out_nvm_release;
+ goto out_cleanup;
+
+ rval = smiapp_call_quirk(sensor, init);
+ if (rval)
+ goto out_cleanup;
+
+ rval = smiapp_get_mbus_formats(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_cleanup;
+ }
+
+ rval = smiapp_init_late_controls(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_cleanup;
+ }
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;
+ goto out_cleanup;
}
sensor->streaming = false;
sensor->dev_init_done = true;
- /* check flash capability */
- rval = smiapp_read(sensor, SMIAPP_REG_U8_FLASH_MODE_CAPABILITY, &tmp);
- sensor->flash_capability = tmp;
- if (rval)
- goto out_nvm_release;
-
smiapp_power_off(sensor);
return 0;
-out_nvm_release:
- device_remove_file(&client->dev, &dev_attr_nvm);
-
-out_ident_release:
- device_remove_file(&client->dev, &dev_attr_ident);
+out_cleanup:
+ smiapp_cleanup(sensor);
out_power_off:
smiapp_power_off(sensor);
return rval;
}
+static int smiapp_registered(struct v4l2_subdev *subdev)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(subdev);
+ int rval;
+
+ if (!client->dev.of_node) {
+ rval = smiapp_init(sensor);
+ if (rval)
+ return rval;
+ }
+
+ rval = smiapp_register_subdevs(sensor);
+ if (rval)
+ smiapp_cleanup(sensor);
+
+ return rval;
+}
+
static int smiapp_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
struct smiapp_subdev *ssd = to_smiapp_subdev(sd);
@@ -2927,19 +2972,125 @@ static int smiapp_resume(struct device *dev)
#endif /* CONFIG_PM */
+static struct smiapp_platform_data *smiapp_get_pdata(struct device *dev)
+{
+ struct smiapp_platform_data *pdata;
+ struct v4l2_of_endpoint bus_cfg;
+ struct device_node *ep;
+ struct property *prop;
+ __be32 *val;
+ uint32_t asize;
+#ifdef CONFIG_OF
+ unsigned int i;
+#endif
+ int rval;
+
+ if (!dev->of_node)
+ return dev->platform_data;
+
+ ep = of_graph_get_next_endpoint(dev->of_node, NULL);
+ if (!ep)
+ return NULL;
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata) {
+ rval = -ENOMEM;
+ goto out_err;
+ }
+
+ v4l2_of_parse_endpoint(ep, &bus_cfg);
+
+ switch (bus_cfg.bus_type) {
+ case V4L2_MBUS_CSI2:
+ pdata->csi_signalling_mode = SMIAPP_CSI_SIGNALLING_MODE_CSI2;
+ break;
+ /* FIXME: add CCP2 support. */
+ default:
+ rval = -EINVAL;
+ goto out_err;
+ }
+
+ pdata->lanes = bus_cfg.bus.mipi_csi2.num_data_lanes;
+ dev_dbg(dev, "lanes %u\n", pdata->lanes);
+
+ /* xshutdown GPIO is optional */
+ pdata->xshutdown = of_get_named_gpio(dev->of_node, "reset-gpios", 0);
+
+ /* NVM size is not mandatory */
+ of_property_read_u32(dev->of_node, "nokia,nvm-size",
+ &pdata->nvm_size);
+
+ rval = of_property_read_u32(dev->of_node, "clock-frequency",
+ &pdata->ext_clk);
+ if (rval) {
+ dev_warn(dev, "can't get clock-frequency\n");
+ goto out_err;
+ }
+
+ dev_dbg(dev, "reset %d, nvm %d, clk %d, csi %d\n", pdata->xshutdown,
+ pdata->nvm_size, pdata->ext_clk, pdata->csi_signalling_mode);
+
+ rval = of_get_property(
+ dev->of_node, "link-frequencies", &asize) ? 0 : -ENOENT;
+ if (rval) {
+ dev_warn(dev, "can't get link-frequencies array size\n");
+ goto out_err;
+ }
+
+ pdata->op_sys_clock = devm_kzalloc(dev, asize, GFP_KERNEL);
+ if (!pdata->op_sys_clock) {
+ rval = -ENOMEM;
+ goto out_err;
+ }
+
+ asize /= sizeof(*pdata->op_sys_clock);
+ /*
+ * Read a 64-bit array --- this will be replaced with a
+ * of_property_read_u64_array() once it's merged.
+ */
+ prop = of_find_property(dev->of_node, "link-frequencies", NULL);
+ if (!prop)
+ goto out_err;
+ if (!prop->value)
+ goto out_err;
+ if (asize * sizeof(*pdata->op_sys_clock) > prop->length)
+ goto out_err;
+ val = prop->value;
+ if (IS_ERR(val))
+ goto out_err;
+
+#ifdef CONFIG_OF
+ for (i = 0; i < asize; i++)
+ pdata->op_sys_clock[i] = of_read_number(val + i * 2, 2);
+#endif
+
+ for (; asize > 0; asize--)
+ dev_dbg(dev, "freq %d: %lld\n", asize - 1,
+ pdata->op_sys_clock[asize - 1]);
+
+ of_node_put(ep);
+ return pdata;
+
+out_err:
+ of_node_put(ep);
+ return NULL;
+}
+
static int smiapp_probe(struct i2c_client *client,
const struct i2c_device_id *devid)
{
struct smiapp_sensor *sensor;
+ struct smiapp_platform_data *pdata = smiapp_get_pdata(&client->dev);
+ int rval;
- if (client->dev.platform_data == NULL)
+ if (pdata == NULL)
return -ENODEV;
sensor = devm_kzalloc(&client->dev, sizeof(*sensor), GFP_KERNEL);
if (sensor == NULL)
return -ENOMEM;
- sensor->platform_data = client->dev.platform_data;
+ sensor->platform_data = pdata;
mutex_init(&sensor->mutex);
mutex_init(&sensor->power_mutex);
sensor->src = &sensor->ssds[sensor->ssds_used];
@@ -2950,8 +3101,27 @@ static int smiapp_probe(struct i2c_client *client,
sensor->src->sensor = sensor;
sensor->src->pads[0].flags = MEDIA_PAD_FL_SOURCE;
- return media_entity_init(&sensor->src->sd.entity, 2,
+ rval = media_entity_init(&sensor->src->sd.entity, 2,
sensor->src->pads, 0);
+ if (rval < 0)
+ return rval;
+
+ if (client->dev.of_node) {
+ rval = smiapp_init(sensor);
+ if (rval)
+ goto out_media_entity_cleanup;
+ }
+
+ rval = v4l2_async_register_subdev(&sensor->src->sd);
+ if (rval < 0)
+ goto out_media_entity_cleanup;
+
+ return 0;
+
+out_media_entity_cleanup:
+ media_entity_cleanup(&sensor->src->sd.entity);
+
+ return rval;
}
static int smiapp_remove(struct i2c_client *client)
@@ -2960,6 +3130,8 @@ static int smiapp_remove(struct i2c_client *client)
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
unsigned int i;
+ v4l2_async_unregister_subdev(subdev);
+
if (sensor->power_count) {
if (gpio_is_valid(sensor->platform_data->xshutdown))
gpio_set_value(sensor->platform_data->xshutdown, 0);
@@ -2970,19 +3142,20 @@ static int smiapp_remove(struct i2c_client *client)
sensor->power_count = 0;
}
- device_remove_file(&client->dev, &dev_attr_ident);
- if (sensor->nvm)
- device_remove_file(&client->dev, &dev_attr_nvm);
-
for (i = 0; i < sensor->ssds_used; i++) {
v4l2_device_unregister_subdev(&sensor->ssds[i].sd);
media_entity_cleanup(&sensor->ssds[i].sd.entity);
}
- smiapp_free_controls(sensor);
+ smiapp_cleanup(sensor);
return 0;
}
+static const struct of_device_id smiapp_of_table[] = {
+ { .compatible = "nokia,smia" },
+ { },
+};
+
static const struct i2c_device_id smiapp_id_table[] = {
{ SMIAPP_NAME, 0 },
{ },
@@ -2996,6 +3169,7 @@ static const struct dev_pm_ops smiapp_pm_ops = {
static struct i2c_driver smiapp_i2c_driver = {
.driver = {
+ .of_match_table = smiapp_of_table,
.name = SMIAPP_NAME,
.pm = &smiapp_pm_ops,
},
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.c b/drivers/media/i2c/smiapp/smiapp-limits.c
index 847cb235e198..784b114d3f8b 100644
--- a/drivers/media/i2c/smiapp/smiapp-limits.c
+++ b/drivers/media/i2c/smiapp/smiapp-limits.c
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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 "smiapp.h"
diff --git a/drivers/media/i2c/smiapp/smiapp-limits.h b/drivers/media/i2c/smiapp/smiapp-limits.h
index 343e9c3827fc..b20124862a14 100644
--- a/drivers/media/i2c/smiapp/smiapp-limits.h
+++ b/drivers/media/i2c/smiapp/smiapp-limits.h
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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
- *
*/
#define SMIAPP_LIMIT_ANALOGUE_GAIN_CAPABILITY 0
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.c b/drivers/media/i2c/smiapp/smiapp-quirk.c
index e0bee8752122..abf9ea7a0fb7 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.c
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.c
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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>
@@ -220,9 +214,11 @@ static int jt8ev1_post_streamoff(struct smiapp_sensor *sensor)
return smiapp_write_8(sensor, 0x3328, 0x80);
}
-static unsigned long jt8ev1_pll_flags(struct smiapp_sensor *sensor)
+static int jt8ev1_init(struct smiapp_sensor *sensor)
{
- return SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+ sensor->pll.flags |= SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE;
+
+ return 0;
}
const struct smiapp_quirk smiapp_jt8ev1_quirk = {
@@ -230,7 +226,7 @@ const struct smiapp_quirk smiapp_jt8ev1_quirk = {
.post_poweron = jt8ev1_post_poweron,
.pre_streamon = jt8ev1_pre_streamon,
.post_streamoff = jt8ev1_post_streamoff,
- .pll_flags = jt8ev1_pll_flags,
+ .init = jt8ev1_init,
};
static int tcm8500md_limits(struct smiapp_sensor *sensor)
diff --git a/drivers/media/i2c/smiapp/smiapp-quirk.h b/drivers/media/i2c/smiapp/smiapp-quirk.h
index 46e9ea8bfa08..dac5566a2f7a 100644
--- a/drivers/media/i2c/smiapp/smiapp-quirk.h
+++ b/drivers/media/i2c/smiapp/smiapp-quirk.h
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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 __SMIAPP_QUIRK__
@@ -35,6 +29,9 @@ struct smiapp_sensor;
* @post_poweron: Called always after the sensor has been fully powered on.
* @pre_streamon: Called just before streaming is enabled.
* @post_streamon: Called right after stopping streaming.
+ * @pll_flags: Return flags for the PLL calculator.
+ * @init: Quirk initialisation, called the last in probe(). This is
+ * also appropriate for adding sensor specific controls, for instance.
* @reg_access: Register access quirk. The quirk may divert the access
* to another register, or no register at all.
*
@@ -53,6 +50,7 @@ struct smiapp_quirk {
int (*pre_streamon)(struct smiapp_sensor *sensor);
int (*post_streamoff)(struct smiapp_sensor *sensor);
unsigned long (*pll_flags)(struct smiapp_sensor *sensor);
+ int (*init)(struct smiapp_sensor *sensor);
int (*reg_access)(struct smiapp_sensor *sensor, bool write, u32 *reg,
u32 *val);
unsigned long flags;
@@ -74,14 +72,14 @@ void smiapp_replace_limit(struct smiapp_sensor *sensor,
.val = _val, \
}
-#define smiapp_call_quirk(_sensor, _quirk, ...) \
- (_sensor->minfo.quirk && \
- _sensor->minfo.quirk->_quirk ? \
- _sensor->minfo.quirk->_quirk(_sensor, ##__VA_ARGS__) : 0)
+#define smiapp_call_quirk(sensor, _quirk, ...) \
+ ((sensor)->minfo.quirk && \
+ (sensor)->minfo.quirk->_quirk ? \
+ (sensor)->minfo.quirk->_quirk(sensor, ##__VA_ARGS__) : 0)
-#define smiapp_needs_quirk(_sensor, _quirk) \
- (_sensor->minfo.quirk ? \
- _sensor->minfo.quirk->flags & _quirk : 0)
+#define smiapp_needs_quirk(sensor, _quirk) \
+ ((sensor)->minfo.quirk ? \
+ (sensor)->minfo.quirk->flags & _quirk : 0)
extern const struct smiapp_quirk smiapp_jt8ev1_quirk;
extern const struct smiapp_quirk smiapp_imx125es_quirk;
diff --git a/drivers/media/i2c/smiapp/smiapp-reg-defs.h b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
index c488ef028074..f928d4cc8e26 100644
--- a/drivers/media/i2c/smiapp/smiapp-reg-defs.h
+++ b/drivers/media/i2c/smiapp/smiapp-reg-defs.h
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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
- *
*/
#define SMIAPP_REG_MK_U8(r) ((SMIAPP_REG_8BIT << 16) | (r))
#define SMIAPP_REG_MK_U16(r) ((SMIAPP_REG_16BIT << 16) | (r))
diff --git a/drivers/media/i2c/smiapp/smiapp-reg.h b/drivers/media/i2c/smiapp/smiapp-reg.h
index b0dcbb8fa5e2..4c8b40614969 100644
--- a/drivers/media/i2c/smiapp/smiapp-reg.h
+++ b/drivers/media/i2c/smiapp/smiapp-reg.h
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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 __SMIAPP_REG_H_
diff --git a/drivers/media/i2c/smiapp/smiapp-regs.c b/drivers/media/i2c/smiapp/smiapp-regs.c
index a2098007fb70..6b6c20b61397 100644
--- a/drivers/media/i2c/smiapp/smiapp-regs.c
+++ b/drivers/media/i2c/smiapp/smiapp-regs.c
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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/drivers/media/i2c/smiapp/smiapp-regs.h b/drivers/media/i2c/smiapp/smiapp-regs.h
index 35521125a2cc..6dd0e499c845 100644
--- a/drivers/media/i2c/smiapp/smiapp-regs.h
+++ b/drivers/media/i2c/smiapp/smiapp-regs.h
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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 SMIAPP_REGS_H
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index f88f8ec344d3..ed010a8a49d7 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -14,12 +14,6 @@
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* 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 __SMIAPP_PRIV_H_
@@ -222,7 +216,6 @@ struct smiapp_sensor {
u8 scaling_mode;
u8 hvflip_inv_mask; /* H/VFLIP inversion due to sensor orientation */
- u8 flash_capability;
u8 frame_skip;
int power_count;
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
index 6f2dd9093d94..1fdce2f6f880 100644
--- a/drivers/media/i2c/soc_camera/ov2640.c
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -25,6 +25,7 @@
#include <media/v4l2-clk.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
+#include <media/v4l2-image-sizes.h>
#define VAL_SET(x, mask, rshift, lshift) \
((((x) >> rshift) & mask) << lshift)
@@ -268,33 +269,10 @@ struct regval_list {
u8 value;
};
-/* Supported resolutions */
-enum ov2640_width {
- W_QCIF = 176,
- W_QVGA = 320,
- W_CIF = 352,
- W_VGA = 640,
- W_SVGA = 800,
- W_XGA = 1024,
- W_SXGA = 1280,
- W_UXGA = 1600,
-};
-
-enum ov2640_height {
- H_QCIF = 144,
- H_QVGA = 240,
- H_CIF = 288,
- H_VGA = 480,
- H_SVGA = 600,
- H_XGA = 768,
- H_SXGA = 1024,
- H_UXGA = 1200,
-};
-
struct ov2640_win_size {
char *name;
- enum ov2640_width width;
- enum ov2640_height height;
+ u32 width;
+ u32 height;
const struct regval_list *regs;
};
@@ -495,17 +473,17 @@ static const struct regval_list ov2640_init_regs[] = {
static const struct regval_list ov2640_size_change_preamble_regs[] = {
{ BANK_SEL, BANK_SEL_DSP },
{ RESET, RESET_DVP },
- { HSIZE8, HSIZE8_SET(W_UXGA) },
- { VSIZE8, VSIZE8_SET(H_UXGA) },
+ { HSIZE8, HSIZE8_SET(UXGA_WIDTH) },
+ { VSIZE8, VSIZE8_SET(UXGA_HEIGHT) },
{ CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
- { HSIZE, HSIZE_SET(W_UXGA) },
- { VSIZE, VSIZE_SET(H_UXGA) },
+ { HSIZE, HSIZE_SET(UXGA_WIDTH) },
+ { VSIZE, VSIZE_SET(UXGA_HEIGHT) },
{ XOFFL, XOFFL_SET(0) },
{ YOFFL, YOFFL_SET(0) },
- { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
+ { VHYX, VHYX_HSIZE_SET(UXGA_WIDTH) | VHYX_VSIZE_SET(UXGA_HEIGHT) |
VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
- { TEST, TEST_HSIZE_SET(W_UXGA) },
+ { TEST, TEST_HSIZE_SET(UXGA_WIDTH) },
ENDMARKER,
};
@@ -519,45 +497,45 @@ static const struct regval_list ov2640_size_change_preamble_regs[] = {
{ RESET, 0x00}
static const struct regval_list ov2640_qcif_regs[] = {
- PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
+ PER_SIZE_REG_SEQ(QCIF_WIDTH, QCIF_HEIGHT, 3, 3, 4),
ENDMARKER,
};
static const struct regval_list ov2640_qvga_regs[] = {
- PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
+ PER_SIZE_REG_SEQ(QVGA_WIDTH, QVGA_HEIGHT, 2, 2, 4),
ENDMARKER,
};
static const struct regval_list ov2640_cif_regs[] = {
- PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
+ PER_SIZE_REG_SEQ(CIF_WIDTH, CIF_HEIGHT, 2, 2, 8),
ENDMARKER,
};
static const struct regval_list ov2640_vga_regs[] = {
- PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
+ PER_SIZE_REG_SEQ(VGA_WIDTH, VGA_HEIGHT, 0, 0, 2),
ENDMARKER,
};
static const struct regval_list ov2640_svga_regs[] = {
- PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
+ PER_SIZE_REG_SEQ(SVGA_WIDTH, SVGA_HEIGHT, 1, 1, 2),
ENDMARKER,
};
static const struct regval_list ov2640_xga_regs[] = {
- PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
+ PER_SIZE_REG_SEQ(XGA_WIDTH, XGA_HEIGHT, 0, 0, 2),
{ CTRLI, 0x00},
ENDMARKER,
};
static const struct regval_list ov2640_sxga_regs[] = {
- PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
+ PER_SIZE_REG_SEQ(SXGA_WIDTH, SXGA_HEIGHT, 0, 0, 2),
{ CTRLI, 0x00},
{ R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
ENDMARKER,
};
static const struct regval_list ov2640_uxga_regs[] = {
- PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
+ PER_SIZE_REG_SEQ(UXGA_WIDTH, UXGA_HEIGHT, 0, 0, 0),
{ CTRLI, 0x00},
{ R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
ENDMARKER,
@@ -567,14 +545,14 @@ static const struct regval_list ov2640_uxga_regs[] = {
{.name = n, .width = w , .height = h, .regs = r }
static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
- OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
- OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
- OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
- OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
- OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
- OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
- OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
- OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
+ OV2640_SIZE("QCIF", QCIF_WIDTH, QCIF_HEIGHT, ov2640_qcif_regs),
+ OV2640_SIZE("QVGA", QVGA_WIDTH, QVGA_HEIGHT, ov2640_qvga_regs),
+ OV2640_SIZE("CIF", CIF_WIDTH, CIF_HEIGHT, ov2640_cif_regs),
+ OV2640_SIZE("VGA", VGA_WIDTH, VGA_HEIGHT, ov2640_vga_regs),
+ OV2640_SIZE("SVGA", SVGA_WIDTH, SVGA_HEIGHT, ov2640_svga_regs),
+ OV2640_SIZE("XGA", XGA_WIDTH, XGA_HEIGHT, ov2640_xga_regs),
+ OV2640_SIZE("SXGA", SXGA_WIDTH, SXGA_HEIGHT, ov2640_sxga_regs),
+ OV2640_SIZE("UXGA", UXGA_WIDTH, UXGA_HEIGHT, ov2640_uxga_regs),
};
/*
@@ -867,7 +845,7 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd,
struct ov2640_priv *priv = to_ov2640(client);
if (!priv->win) {
- u32 width = W_SVGA, height = H_SVGA;
+ u32 width = SVGA_WIDTH, height = SVGA_HEIGHT;
priv->win = ov2640_select_win(&width, &height);
priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8;
}
@@ -954,8 +932,8 @@ static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
a->c.left = 0;
a->c.top = 0;
- a->c.width = W_UXGA;
- a->c.height = H_UXGA;
+ a->c.width = UXGA_WIDTH;
+ a->c.height = UXGA_HEIGHT;
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
return 0;
@@ -965,8 +943,8 @@ static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
a->bounds.left = 0;
a->bounds.top = 0;
- a->bounds.width = W_UXGA;
- a->bounds.height = H_UXGA;
+ a->bounds.width = UXGA_WIDTH;
+ a->bounds.height = UXGA_HEIGHT;
a->defrect = a->bounds;
a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
a->pixelaspect.numerator = 1;
diff --git a/drivers/media/i2c/ths8200.c b/drivers/media/i2c/ths8200.c
index 656d889c1c79..4ebd329d7b42 100644
--- a/drivers/media/i2c/ths8200.c
+++ b/drivers/media/i2c/ths8200.c
@@ -58,21 +58,11 @@ static inline struct ths8200_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct ths8200_state, sd);
}
-static inline unsigned hblanking(const struct v4l2_bt_timings *t)
-{
- return V4L2_DV_BT_BLANKING_WIDTH(t);
-}
-
static inline unsigned htotal(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_FRAME_WIDTH(t);
}
-static inline unsigned vblanking(const struct v4l2_bt_timings *t)
-{
- return V4L2_DV_BT_BLANKING_HEIGHT(t);
-}
-
static inline unsigned vtotal(const struct v4l2_bt_timings *t)
{
return V4L2_DV_BT_FRAME_HEIGHT(t);
diff --git a/drivers/media/mmc/siano/Kconfig b/drivers/media/mmc/siano/Kconfig
index aa05ad3c1ccb..7693487e2f63 100644
--- a/drivers/media/mmc/siano/Kconfig
+++ b/drivers/media/mmc/siano/Kconfig
@@ -6,6 +6,8 @@ config SMS_SDIO_DRV
tristate "Siano SMS1xxx based MDTV via SDIO interface"
depends on DVB_CORE && HAS_DMA
depends on MMC
+ depends on !RC_CORE || RC_CORE
select MEDIA_COMMON_OPTIONS
+ select SMS_SIANO_MDTV
---help---
Choose if you would like to have Siano's support for SDIO interface
diff --git a/drivers/media/pci/bt8xx/Kconfig b/drivers/media/pci/bt8xx/Kconfig
index 61d09e010814..4a93f6ded100 100644
--- a/drivers/media/pci/bt8xx/Kconfig
+++ b/drivers/media/pci/bt8xx/Kconfig
@@ -2,15 +2,17 @@ config VIDEO_BT848
tristate "BT848 Video For Linux"
depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
select I2C_ALGOBIT
- select VIDEO_BTCX
select VIDEOBUF_DMA_SG
depends on RC_CORE
+ depends on MEDIA_RADIO_SUPPORT
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_MSP3400 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TVAUDIO if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_TDA7432 if MEDIA_SUBDRV_AUTOSELECT
select VIDEO_SAA6588 if MEDIA_SUBDRV_AUTOSELECT
+ select RADIO_ADAPTERS
+ select RADIO_TEA575X
---help---
Support for BT848 based frame grabber/overlay boards. This includes
the Miro, Hauppauge and STB boards. Please read the material in
diff --git a/drivers/media/pci/bt8xx/Makefile b/drivers/media/pci/bt8xx/Makefile
index f9fe7c4e7d53..2d4c3dd88be1 100644
--- a/drivers/media/pci/bt8xx/Makefile
+++ b/drivers/media/pci/bt8xx/Makefile
@@ -1,6 +1,6 @@
bttv-objs := bttv-driver.o bttv-cards.o bttv-if.o \
bttv-risc.o bttv-vbi.o bttv-i2c.o bttv-gpio.o \
- bttv-input.o bttv-audio-hook.o
+ bttv-input.o bttv-audio-hook.o btcx-risc.o
obj-$(CONFIG_VIDEO_BT848) += bttv.o
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c
index 11765835d7b2..0939d399b774 100644
--- a/drivers/media/pci/bt8xx/bt878.c
+++ b/drivers/media/pci/bt8xx/bt878.c
@@ -590,9 +590,3 @@ module_init(bt878_init_module);
module_exit(bt878_cleanup_module);
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/btcx-risc.c b/drivers/media/pci/bt8xx/btcx-risc.c
new file mode 100644
index 000000000000..00f0880b6d66
--- /dev/null
+++ b/drivers/media/pci/bt8xx/btcx-risc.c
@@ -0,0 +1,240 @@
+/*
+
+ btcx-risc.c
+
+ bt848/bt878/cx2388x risc code generator.
+
+ (c) 2000-03 Gerd Knorr <kraxel@bytesex.org> [SuSE 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/videodev2.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+
+#include "btcx-risc.h"
+
+static unsigned int btcx_debug;
+module_param(btcx_debug, int, 0644);
+MODULE_PARM_DESC(btcx_debug,"debug messages, default is 0 (no)");
+
+/* ---------------------------------------------------------- */
+/* allocate/free risc memory */
+
+static int memcnt;
+
+void btcx_riscmem_free(struct pci_dev *pci,
+ struct btcx_riscmem *risc)
+{
+ if (NULL == risc->cpu)
+ return;
+ if (btcx_debug) {
+ memcnt--;
+ printk("btcx: riscmem free [%d] dma=%lx\n",
+ memcnt, (unsigned long)risc->dma);
+ }
+ pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
+ memset(risc,0,sizeof(*risc));
+}
+
+int btcx_riscmem_alloc(struct pci_dev *pci,
+ struct btcx_riscmem *risc,
+ unsigned int size)
+{
+ __le32 *cpu;
+ dma_addr_t dma = 0;
+
+ if (NULL != risc->cpu && risc->size < size)
+ btcx_riscmem_free(pci,risc);
+ if (NULL == risc->cpu) {
+ cpu = pci_alloc_consistent(pci, size, &dma);
+ if (NULL == cpu)
+ return -ENOMEM;
+ risc->cpu = cpu;
+ risc->dma = dma;
+ risc->size = size;
+ if (btcx_debug) {
+ memcnt++;
+ printk("btcx: riscmem alloc [%d] dma=%lx cpu=%p size=%d\n",
+ memcnt, (unsigned long)dma, cpu, size);
+ }
+ }
+ memset(risc->cpu,0,risc->size);
+ return 0;
+}
+
+/* ---------------------------------------------------------- */
+/* screen overlay helpers */
+
+int
+btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
+ struct v4l2_clip *clips, unsigned int n)
+{
+ if (win->left < 0) {
+ /* left */
+ clips[n].c.left = 0;
+ clips[n].c.top = 0;
+ clips[n].c.width = -win->left;
+ clips[n].c.height = win->height;
+ n++;
+ }
+ if (win->left + win->width > swidth) {
+ /* right */
+ clips[n].c.left = swidth - win->left;
+ clips[n].c.top = 0;
+ clips[n].c.width = win->width - clips[n].c.left;
+ clips[n].c.height = win->height;
+ n++;
+ }
+ if (win->top < 0) {
+ /* top */
+ clips[n].c.left = 0;
+ clips[n].c.top = 0;
+ clips[n].c.width = win->width;
+ clips[n].c.height = -win->top;
+ n++;
+ }
+ if (win->top + win->height > sheight) {
+ /* bottom */
+ clips[n].c.left = 0;
+ clips[n].c.top = sheight - win->top;
+ clips[n].c.width = win->width;
+ clips[n].c.height = win->height - clips[n].c.top;
+ n++;
+ }
+ return n;
+}
+
+int
+btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips, unsigned int n, int mask)
+{
+ s32 nx,nw,dx;
+ unsigned int i;
+
+ /* fixup window */
+ nx = (win->left + mask) & ~mask;
+ nw = (win->width) & ~mask;
+ if (nx + nw > win->left + win->width)
+ nw -= mask+1;
+ dx = nx - win->left;
+ win->left = nx;
+ win->width = nw;
+ if (btcx_debug)
+ printk(KERN_DEBUG "btcx: window align %dx%d+%d+%d [dx=%d]\n",
+ win->width, win->height, win->left, win->top, dx);
+
+ /* fixup clips */
+ for (i = 0; i < n; i++) {
+ nx = (clips[i].c.left-dx) & ~mask;
+ nw = (clips[i].c.width) & ~mask;
+ if (nx + nw < clips[i].c.left-dx + clips[i].c.width)
+ nw += mask+1;
+ clips[i].c.left = nx;
+ clips[i].c.width = nw;
+ if (btcx_debug)
+ printk(KERN_DEBUG "btcx: clip align %dx%d+%d+%d\n",
+ clips[i].c.width, clips[i].c.height,
+ clips[i].c.left, clips[i].c.top);
+ }
+ return 0;
+}
+
+void
+btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips)
+{
+ struct v4l2_clip swap;
+ int i,j,n;
+
+ if (nclips < 2)
+ return;
+ for (i = nclips-2; i >= 0; i--) {
+ for (n = 0, j = 0; j <= i; j++) {
+ if (clips[j].c.left > clips[j+1].c.left) {
+ swap = clips[j];
+ clips[j] = clips[j+1];
+ clips[j+1] = swap;
+ n++;
+ }
+ }
+ if (0 == n)
+ break;
+ }
+}
+
+void
+btcx_calc_skips(int line, int width, int *maxy,
+ struct btcx_skiplist *skips, unsigned int *nskips,
+ const struct v4l2_clip *clips, unsigned int nclips)
+{
+ unsigned int clip,skip;
+ int end, maxline;
+
+ skip=0;
+ maxline = 9999;
+ for (clip = 0; clip < nclips; clip++) {
+
+ /* sanity checks */
+ if (clips[clip].c.left + clips[clip].c.width <= 0)
+ continue;
+ if (clips[clip].c.left > (signed)width)
+ break;
+
+ /* vertical range */
+ if (line > clips[clip].c.top+clips[clip].c.height-1)
+ continue;
+ if (line < clips[clip].c.top) {
+ if (maxline > clips[clip].c.top-1)
+ maxline = clips[clip].c.top-1;
+ continue;
+ }
+ if (maxline > clips[clip].c.top+clips[clip].c.height-1)
+ maxline = clips[clip].c.top+clips[clip].c.height-1;
+
+ /* horizontal range */
+ if (0 == skip || clips[clip].c.left > skips[skip-1].end) {
+ /* new one */
+ skips[skip].start = clips[clip].c.left;
+ if (skips[skip].start < 0)
+ skips[skip].start = 0;
+ skips[skip].end = clips[clip].c.left + clips[clip].c.width;
+ if (skips[skip].end > width)
+ skips[skip].end = width;
+ skip++;
+ } else {
+ /* overlaps -- expand last one */
+ end = clips[clip].c.left + clips[clip].c.width;
+ if (skips[skip-1].end < end)
+ skips[skip-1].end = end;
+ if (skips[skip-1].end > width)
+ skips[skip-1].end = width;
+ }
+ }
+ *nskips = skip;
+ *maxy = maxline;
+
+ if (btcx_debug) {
+ printk(KERN_DEBUG "btcx: skips line %d-%d:",line,maxline);
+ for (skip = 0; skip < *nskips; skip++) {
+ printk(" %d-%d",skips[skip].start,skips[skip].end);
+ }
+ printk("\n");
+ }
+}
diff --git a/drivers/media/pci/bt8xx/btcx-risc.h b/drivers/media/pci/bt8xx/btcx-risc.h
new file mode 100644
index 000000000000..1ed7a000160a
--- /dev/null
+++ b/drivers/media/pci/bt8xx/btcx-risc.h
@@ -0,0 +1,26 @@
+struct btcx_riscmem {
+ unsigned int size;
+ __le32 *cpu;
+ __le32 *jmp;
+ dma_addr_t dma;
+};
+
+struct btcx_skiplist {
+ int start;
+ int end;
+};
+
+int btcx_riscmem_alloc(struct pci_dev *pci,
+ struct btcx_riscmem *risc,
+ unsigned int size);
+void btcx_riscmem_free(struct pci_dev *pci,
+ struct btcx_riscmem *risc);
+
+int btcx_screen_clips(int swidth, int sheight, struct v4l2_rect *win,
+ struct v4l2_clip *clips, unsigned int n);
+int btcx_align(struct v4l2_rect *win, struct v4l2_clip *clips,
+ unsigned int n, int mask);
+void btcx_sort_clips(struct v4l2_clip *clips, unsigned int nclips);
+void btcx_calc_skips(int line, int width, int *maxy,
+ struct btcx_skiplist *skips, unsigned int *nskips,
+ const struct v4l2_clip *clips, unsigned int nclips);
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index 41055606b969..4654fb65ca21 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -84,8 +84,7 @@ static void gv800s_init(struct bttv *btv);
static void td3116_muxsel(struct bttv *btv, unsigned int input);
static int terratec_active_radio_upgrade(struct bttv *btv);
-static int tea5757_read(struct bttv *btv);
-static int tea5757_write(struct bttv *btv, int value);
+static int tea575x_init(struct bttv *btv);
static void identify_by_eeprom(struct bttv *btv,
unsigned char eeprom_data[256]);
static int pvr_boot(struct bttv *btv);
@@ -3085,12 +3084,12 @@ static void miro_pinnacle_gpio(struct bttv *btv)
if (0 == (gpio & 0x20)) {
btv->has_radio = 1;
if (!miro_fmtuner[id]) {
- btv->has_matchbox = 1;
- btv->mbox_we = (1<<6);
- btv->mbox_most = (1<<7);
- btv->mbox_clk = (1<<8);
- btv->mbox_data = (1<<9);
- btv->mbox_mask = (1<<6)|(1<<7)|(1<<8)|(1<<9);
+ btv->has_tea575x = 1;
+ btv->tea_gpio.wren = 6;
+ btv->tea_gpio.most = 7;
+ btv->tea_gpio.clk = 8;
+ btv->tea_gpio.data = 9;
+ tea575x_init(btv);
}
} else {
btv->has_radio = 0;
@@ -3104,7 +3103,7 @@ static void miro_pinnacle_gpio(struct bttv *btv)
pr_info("%d: miro: id=%d tuner=%d radio=%s stereo=%s\n",
btv->c.nr, id+1, btv->tuner_type,
!btv->has_radio ? "no" :
- (btv->has_matchbox ? "matchbox" : "fmtuner"),
+ (btv->has_tea575x ? "tea575x" : "fmtuner"),
(-1 == msp) ? "no" : "yes");
} else {
/* new cards with microtune tuner */
@@ -3382,12 +3381,12 @@ void bttv_init_card2(struct bttv *btv)
break;
case BTTV_BOARD_VHX:
btv->has_radio = 1;
- btv->has_matchbox = 1;
- btv->mbox_we = 0x20;
- btv->mbox_most = 0;
- btv->mbox_clk = 0x08;
- btv->mbox_data = 0x10;
- btv->mbox_mask = 0x38;
+ btv->has_tea575x = 1;
+ btv->tea_gpio.wren = 5;
+ btv->tea_gpio.most = 6;
+ btv->tea_gpio.clk = 3;
+ btv->tea_gpio.data = 4;
+ tea575x_init(btv);
break;
case BTTV_BOARD_VOBIS_BOOSTAR:
case BTTV_BOARD_TERRATV:
@@ -3745,33 +3744,112 @@ static void hauppauge_eeprom(struct bttv *btv)
btv->radio_uses_msp_demodulator = 1;
}
-static int terratec_active_radio_upgrade(struct bttv *btv)
+/* ----------------------------------------------------------------------- */
+
+static void bttv_tea575x_set_pins(struct snd_tea575x *tea, u8 pins)
+{
+ struct bttv *btv = tea->private_data;
+ struct bttv_tea575x_gpio gpio = btv->tea_gpio;
+ u16 val = 0;
+
+ val |= (pins & TEA575X_DATA) ? (1 << gpio.data) : 0;
+ val |= (pins & TEA575X_CLK) ? (1 << gpio.clk) : 0;
+ val |= (pins & TEA575X_WREN) ? (1 << gpio.wren) : 0;
+
+ gpio_bits((1 << gpio.data) | (1 << gpio.clk) | (1 << gpio.wren), val);
+ if (btv->mbox_ior) {
+ /* IOW and CSEL active */
+ gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
+ udelay(5);
+ /* all inactive */
+ gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+ btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+ }
+}
+
+static u8 bttv_tea575x_get_pins(struct snd_tea575x *tea)
+{
+ struct bttv *btv = tea->private_data;
+ struct bttv_tea575x_gpio gpio = btv->tea_gpio;
+ u8 ret = 0;
+ u16 val;
+
+ if (btv->mbox_ior) {
+ /* IOR and CSEL active */
+ gpio_bits(btv->mbox_ior | btv->mbox_csel, 0);
+ udelay(5);
+ }
+ val = gpio_read();
+ if (btv->mbox_ior) {
+ /* all inactive */
+ gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
+ btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
+ }
+
+ if (val & (1 << gpio.data))
+ ret |= TEA575X_DATA;
+ if (val & (1 << gpio.most))
+ ret |= TEA575X_MOST;
+
+ return ret;
+}
+
+static void bttv_tea575x_set_direction(struct snd_tea575x *tea, bool output)
{
- int freq;
+ struct bttv *btv = tea->private_data;
+ struct bttv_tea575x_gpio gpio = btv->tea_gpio;
+ u32 mask = (1 << gpio.clk) | (1 << gpio.wren) | (1 << gpio.data) |
+ (1 << gpio.most);
+
+ if (output)
+ gpio_inout(mask, (1 << gpio.data) | (1 << gpio.clk) |
+ (1 << gpio.wren));
+ else
+ gpio_inout(mask, (1 << gpio.clk) | (1 << gpio.wren));
+}
+
+static struct snd_tea575x_ops bttv_tea_ops = {
+ .set_pins = bttv_tea575x_set_pins,
+ .get_pins = bttv_tea575x_get_pins,
+ .set_direction = bttv_tea575x_set_direction,
+};
+
+static int tea575x_init(struct bttv *btv)
+{
+ btv->tea.private_data = btv;
+ btv->tea.ops = &bttv_tea_ops;
+ if (!snd_tea575x_hw_init(&btv->tea)) {
+ pr_info("%d: detected TEA575x radio\n", btv->c.nr);
+ btv->tea.mute = false;
+ return 0;
+ }
+
+ btv->has_tea575x = 0;
+ btv->has_radio = 0;
+ return -ENODEV;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static int terratec_active_radio_upgrade(struct bttv *btv)
+{
btv->has_radio = 1;
- btv->has_matchbox = 1;
- btv->mbox_we = 0x10;
- btv->mbox_most = 0x20;
- btv->mbox_clk = 0x08;
- btv->mbox_data = 0x04;
- btv->mbox_mask = 0x3c;
+ btv->has_tea575x = 1;
+ btv->tea_gpio.wren = 4;
+ btv->tea_gpio.most = 5;
+ btv->tea_gpio.clk = 3;
+ btv->tea_gpio.data = 2;
btv->mbox_iow = 1 << 8;
btv->mbox_ior = 1 << 9;
btv->mbox_csel = 1 << 10;
- freq=88000/62.5;
- tea5757_write(btv, 5 * freq + 0x358); /* write 0x1ed8 */
- if (0x1ed8 == tea5757_read(btv)) {
+ if (!tea575x_init(btv)) {
pr_info("%d: Terratec Active Radio Upgrade found\n", btv->c.nr);
- btv->has_radio = 1;
- btv->has_saa6588 = 1;
- btv->has_matchbox = 1;
- } else {
- btv->has_radio = 0;
- btv->has_matchbox = 0;
+ btv->has_saa6588 = 1;
}
+
return 0;
}
@@ -4292,181 +4370,6 @@ init_PCI8604PW(struct bttv *btv)
}
}
-
-
-/* ----------------------------------------------------------------------- */
-/* Miro Pro radio stuff -- the tea5757 is connected to some GPIO ports */
-/*
- * Copyright (c) 1999 Csaba Halasz <qgehali@uni-miskolc.hu>
- * This code is placed under the terms of the GNU General Public License
- *
- * Brutally hacked by Dan Sheridan <dan.sheridan@contact.org.uk> djs52 8/3/00
- */
-
-static void bus_low(struct bttv *btv, int bit)
-{
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
- btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
- udelay(5);
- }
-
- gpio_bits(bit,0);
- udelay(5);
-
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
- udelay(5);
- }
-}
-
-static void bus_high(struct bttv *btv, int bit)
-{
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
- btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
- udelay(5);
- }
-
- gpio_bits(bit,bit);
- udelay(5);
-
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
- udelay(5);
- }
-}
-
-static int bus_in(struct bttv *btv, int bit)
-{
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
- btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
- udelay(5);
-
- gpio_bits(btv->mbox_iow | btv->mbox_csel, 0);
- udelay(5);
- }
- return gpio_read() & (bit);
-}
-
-/* TEA5757 register bits */
-#define TEA_FREQ 0:14
-#define TEA_BUFFER 15:15
-
-#define TEA_SIGNAL_STRENGTH 16:17
-
-#define TEA_PORT1 18:18
-#define TEA_PORT0 19:19
-
-#define TEA_BAND 20:21
-#define TEA_BAND_FM 0
-#define TEA_BAND_MW 1
-#define TEA_BAND_LW 2
-#define TEA_BAND_SW 3
-
-#define TEA_MONO 22:22
-#define TEA_ALLOW_STEREO 0
-#define TEA_FORCE_MONO 1
-
-#define TEA_SEARCH_DIRECTION 23:23
-#define TEA_SEARCH_DOWN 0
-#define TEA_SEARCH_UP 1
-
-#define TEA_STATUS 24:24
-#define TEA_STATUS_TUNED 0
-#define TEA_STATUS_SEARCHING 1
-
-/* Low-level stuff */
-static int tea5757_read(struct bttv *btv)
-{
- unsigned long timeout;
- int value = 0;
- int i;
-
- /* better safe than sorry */
- gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we);
-
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
- btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
- udelay(5);
- }
-
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"tea5757 read");
-
- bus_low(btv,btv->mbox_we);
- bus_low(btv,btv->mbox_clk);
-
- udelay(10);
- timeout= jiffies + msecs_to_jiffies(1000);
-
- /* wait for DATA line to go low; error if it doesn't */
- while (bus_in(btv,btv->mbox_data) && time_before(jiffies, timeout))
- schedule();
- if (bus_in(btv,btv->mbox_data)) {
- pr_warn("%d: tea5757: read timeout\n", btv->c.nr);
- return -1;
- }
-
- dprintk("%d: tea5757:", btv->c.nr);
- for (i = 0; i < 24; i++) {
- udelay(5);
- bus_high(btv,btv->mbox_clk);
- udelay(5);
- dprintk_cont("%c",
- bus_in(btv, btv->mbox_most) == 0 ? 'T' : '-');
- bus_low(btv,btv->mbox_clk);
- value <<= 1;
- value |= (bus_in(btv,btv->mbox_data) == 0)?0:1; /* MSB first */
- dprintk_cont("%c",
- bus_in(btv, btv->mbox_most) == 0 ? 'S' : 'M');
- }
- dprintk_cont("\n");
- dprintk("%d: tea5757: read 0x%X\n", btv->c.nr, value);
- return value;
-}
-
-static int tea5757_write(struct bttv *btv, int value)
-{
- int i;
- int reg = value;
-
- gpio_inout(btv->mbox_mask, btv->mbox_clk | btv->mbox_we | btv->mbox_data);
-
- if (btv->mbox_ior) {
- gpio_bits(btv->mbox_ior | btv->mbox_iow | btv->mbox_csel,
- btv->mbox_ior | btv->mbox_iow | btv->mbox_csel);
- udelay(5);
- }
- if (bttv_gpio)
- bttv_gpio_tracking(btv,"tea5757 write");
-
- dprintk("%d: tea5757: write 0x%X\n", btv->c.nr, value);
- bus_low(btv,btv->mbox_clk);
- bus_high(btv,btv->mbox_we);
- for (i = 0; i < 25; i++) {
- if (reg & 0x1000000)
- bus_high(btv,btv->mbox_data);
- else
- bus_low(btv,btv->mbox_data);
- reg <<= 1;
- bus_high(btv,btv->mbox_clk);
- udelay(10);
- bus_low(btv,btv->mbox_clk);
- udelay(10);
- }
- bus_low(btv,btv->mbox_we); /* unmute !!! */
- return 0;
-}
-
-void tea5757_set_freq(struct bttv *btv, unsigned short freq)
-{
- dprintk("tea5757_set_freq %d\n",freq);
- tea5757_write(btv, 5 * freq + 0x358); /* add 10.7MHz (see docs) */
-}
-
/* RemoteVision MX (rv605) muxsel helper [Miguel Freitas]
*
* This is needed because rv605 don't use a normal multiplex, but a crosspoint
@@ -5048,10 +4951,3 @@ int bttv_handle_chipset(struct bttv *btv)
pci_write_config_byte(btv->c.pci, PCI_LATENCY_TIMER, latency);
return 0;
}
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 4a8176c09fc9..4ec2a3c3f23c 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -1874,8 +1874,10 @@ static void bttv_set_frequency(struct bttv *btv, const struct v4l2_frequency *f)
if (new_freq.type == V4L2_TUNER_RADIO) {
radio_enable(btv);
btv->radio_freq = new_freq.frequency;
- if (btv->has_matchbox)
- tea5757_set_freq(btv, btv->radio_freq);
+ if (btv->has_tea575x) {
+ btv->tea.freq = btv->radio_freq;
+ snd_tea575x_set_freq(&btv->tea);
+ }
} else {
btv->tv_freq = new_freq.frequency;
}
@@ -2513,6 +2515,8 @@ static int bttv_querycap(struct file *file, void *priv,
if (btv->has_saa6588)
cap->device_caps |= V4L2_CAP_READWRITE |
V4L2_CAP_RDS_CAPTURE;
+ if (btv->has_tea575x)
+ cap->device_caps |= V4L2_CAP_HW_FREQ_SEEK;
}
return 0;
}
@@ -3242,6 +3246,9 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
+ if (btv->has_tea575x)
+ return snd_tea575x_g_tuner(&btv->tea, t);
+
return 0;
}
@@ -3259,6 +3266,30 @@ static int radio_s_tuner(struct file *file, void *priv,
return 0;
}
+static int radio_s_hw_freq_seek(struct file *file, void *priv,
+ const struct v4l2_hw_freq_seek *a)
+{
+ struct bttv_fh *fh = priv;
+ struct bttv *btv = fh->btv;
+
+ if (btv->has_tea575x)
+ return snd_tea575x_s_hw_freq_seek(file, &btv->tea, a);
+
+ return -ENOTTY;
+}
+
+static int radio_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
+{
+ struct bttv_fh *fh = priv;
+ struct bttv *btv = fh->btv;
+
+ if (btv->has_tea575x)
+ return snd_tea575x_enum_freq_bands(&btv->tea, band);
+
+ return -ENOTTY;
+}
+
static ssize_t radio_read(struct file *file, char __user *data,
size_t count, loff_t *ppos)
{
@@ -3316,6 +3347,8 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
.vidioc_s_tuner = radio_s_tuner,
.vidioc_g_frequency = bttv_g_frequency,
.vidioc_s_frequency = bttv_s_frequency,
+ .vidioc_s_hw_freq_seek = radio_s_hw_freq_seek,
+ .vidioc_enum_freq_bands = radio_enum_freq_bands,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
@@ -3884,7 +3917,6 @@ static struct video_device *vdev_init(struct bttv *btv,
*vfd = *template;
vfd->v4l2_dev = &btv->c.v4l2_dev;
vfd->release = video_device_release;
- vfd->debug = bttv_debug;
video_set_drvdata(vfd, btv);
snprintf(vfd->name, sizeof(vfd->name), "BT%d%s %s (%s)",
btv->id, (btv->id==848 && btv->revision==0x12) ? "A" : "",
@@ -4429,9 +4461,3 @@ static void __exit bttv_cleanup_module(void)
module_init(bttv_init_module);
module_exit(bttv_cleanup_module);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttv-gpio.c b/drivers/media/pci/bt8xx/bttv-gpio.c
index 3f364b7062b9..25b9916906d5 100644
--- a/drivers/media/pci/bt8xx/bttv-gpio.c
+++ b/drivers/media/pci/bt8xx/bttv-gpio.c
@@ -181,9 +181,3 @@ void bttv_gpio_bits(struct bttv_core *core, u32 mask, u32 bits)
btwrite(data,BT848_GPIO_DATA);
spin_unlock_irqrestore(&btv->gpio_lock,flags);
}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttv-if.c b/drivers/media/pci/bt8xx/bttv-if.c
index a6a540dc9e4b..538652e16a5c 100644
--- a/drivers/media/pci/bt8xx/bttv-if.c
+++ b/drivers/media/pci/bt8xx/bttv-if.c
@@ -113,9 +113,3 @@ int bttv_write_gpio(unsigned int card, unsigned long mask, unsigned long data)
bttv_gpio_tracking(btv,"extern write");
return 0;
}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c
index 4d3f05a19af3..3859dde98be2 100644
--- a/drivers/media/pci/bt8xx/bttv-risc.c
+++ b/drivers/media/pci/bt8xx/bttv-risc.c
@@ -901,9 +901,3 @@ bttv_overlay_risc(struct bttv *btv,
buf->vb.field = ov->field;
return 0;
}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c
index b433267d9aa9..e77129c92fa0 100644
--- a/drivers/media/pci/bt8xx/bttv-vbi.c
+++ b/drivers/media/pci/bt8xx/bttv-vbi.c
@@ -450,10 +450,3 @@ void bttv_vbi_fmt_reset(struct bttv_vbi_fmt *f, unsigned int norm)
/* See bttv_vbi_fmt_set(). */
f->end = tvnorm->vbistart[0] * 2 + 2;
}
-
-/* ----------------------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttv.h b/drivers/media/pci/bt8xx/bttv.h
index f08126244662..91301c3cad1e 100644
--- a/drivers/media/pci/bt8xx/bttv.h
+++ b/drivers/media/pci/bt8xx/bttv.h
@@ -378,8 +378,3 @@ extern void bttv_input_fini(struct bttv *dev);
extern void bttv_input_irq(struct bttv *dev);
#endif /* _BTTV_H_ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/bt8xx/bttvp.h b/drivers/media/pci/bt8xx/bttvp.h
index 9fe19488b30b..bc048c586b1f 100644
--- a/drivers/media/pci/bt8xx/bttvp.h
+++ b/drivers/media/pci/bt8xx/bttvp.h
@@ -42,6 +42,7 @@
#include <media/tveeprom.h>
#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
+#include <media/tea575x.h>
#include "bt848.h"
#include "bttv.h"
@@ -359,6 +360,10 @@ struct bttv_suspend_state {
struct bttv_buffer *vbi;
};
+struct bttv_tea575x_gpio {
+ u8 data, clk, wren, most;
+};
+
struct bttv {
struct bttv_core c;
@@ -445,12 +450,9 @@ struct bttv {
/* miro/pinnacle + Aimslab VHX
philips matchbox (tea5757 radio tuner) support */
- int has_matchbox;
- int mbox_we;
- int mbox_data;
- int mbox_clk;
- int mbox_most;
- int mbox_mask;
+ int has_tea575x;
+ struct bttv_tea575x_gpio tea_gpio;
+ struct snd_tea575x tea;
/* ISA stuff (Terratec Active Radio Upgrade) */
int mbox_ior;
@@ -531,9 +533,3 @@ static inline unsigned int bttv_muxsel(const struct bttv *btv,
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
#endif /* _BTTVP_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/pci/cx23885/Kconfig b/drivers/media/pci/cx23885/Kconfig
index f613314b360b..74d774e5227b 100644
--- a/drivers/media/pci/cx23885/Kconfig
+++ b/drivers/media/pci/cx23885/Kconfig
@@ -41,6 +41,7 @@ config VIDEO_CX23885
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT
select DVB_TUNER_DIB0070 if MEDIA_SUBDRV_AUTOSELECT
---help---
This is a video4linux driver for Conexant 23885 based
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index 06931f6fa26c..f384f295676e 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -710,6 +710,11 @@ struct cx23885_board cx23885_boards[] = {
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_HAUPPAUGE_HVR5525] = {
+ .name = "Hauppauge WinTV-HVR5525",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -993,6 +998,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x4254,
.subdevice = 0x0982,
.card = CX23885_BOARD_DVBSKY_T982,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0xf038,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR5525,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1165,6 +1174,8 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 85721:
/* WinTV-HVR1290 (PCIe, OEM, RCA in, IR,
Dual channel ATSC and Basic analog */
+ case 150329:
+ /* WinTV-HVR5525 (PCIe, DVB-S/S2, DVB-T/T2/C) */
break;
default:
printk(KERN_WARNING "%s: warning: "
@@ -1637,6 +1648,29 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
msleep(100);
cx23885_gpio_set(dev, GPIO_2);
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
+ /*
+ * GPIO-00 IR_WIDE
+ * GPIO-02 wake#
+ * GPIO-03 VAUX Pres.
+ * GPIO-07 PROG#
+ * GPIO-08 SAT_RESN
+ * GPIO-09 TER_RESN
+ * GPIO-10 B2_SENSE
+ * GPIO-11 B1_SENSE
+ * GPIO-15 IR_LED_STATUS
+ * GPIO-19 IR_NARROW
+ * GPIO-20 Blauster1
+ * ALTGPIO VAUX_SWITCH
+ * AUX_PLL_CLK : Blaster2
+ */
+ /* Put the parts into reset and back */
+ cx23885_gpio_enable(dev, GPIO_8 | GPIO_9, 1);
+ cx23885_gpio_clear(dev, GPIO_8 | GPIO_9);
+ msleep(100);
+ cx23885_gpio_set(dev, GPIO_8 | GPIO_9);
+ msleep(100);
+ break;
}
}
@@ -1879,6 +1913,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR4400:
case CX23885_BOARD_HAUPPAUGE_STARBURST:
case CX23885_BOARD_HAUPPAUGE_IMPACTVCBE:
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
@@ -2008,6 +2043,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_HAUPPAUGE_HVR5525:
+ 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 = 0xc; /* Serial bus + punctured clock */
+ 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:
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index a9c450d4b54e..45fbe1e4d2d0 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -74,6 +74,7 @@
#include "sp2.h"
#include "m88ds3103.h"
#include "m88ts2022.h"
+#include "m88rs6000t.h"
static unsigned int debug;
@@ -915,6 +916,16 @@ static const struct m88ds3103_config dvbsky_s952_portc_m88ds3103_config = {
.agc = 0x99,
};
+static const struct m88ds3103_config hauppauge_hvr5525_m88ds3103_config = {
+ .i2c_addr = 0x69,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .ts_mode = M88DS3103_TS_PARALLEL,
+ .ts_clk = 16000,
+ .ts_clk_pol = 1,
+ .agc = 0x99,
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -1058,6 +1069,116 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
.hostbus_diversity = 1,
};
+static int dvb_register_ci_mac(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct i2c_client *client_ci = NULL;
+ struct vb2_dvb_frontend *fe0;
+
+ fe0 = vb2_dvb_get_frontend(&port->frontends, 1);
+ if (!fe0)
+ return -EINVAL;
+
+ switch (dev->board) {
+ case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
+ static struct netup_card_info cinfo;
+
+ netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
+ memcpy(port->frontends.adapter.proposed_mac,
+ cinfo.port[port->nr - 1].mac, 6);
+ printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
+ port->nr, port->frontends.adapter.proposed_mac);
+
+ netup_ci_init(port);
+ return 0;
+ }
+ case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
+ struct altera_ci_config netup_ci_cfg = {
+ .dev = dev,/* magic number to identify*/
+ .adapter = &port->frontends.adapter,/* for CI */
+ .demux = &fe0->dvb.demux,/* for hw pid filter */
+ .fpga_rw = netup_altera_fpga_rw,
+ };
+
+ altera_ci_init(&netup_ci_cfg, port->nr);
+ return 0;
+ }
+ case CX23885_BOARD_TEVII_S470: {
+ u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+ if (port->nr != 1)
+ return 0;
+
+ /* 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 "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
+ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
+ return 0;
+ }
+ 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)
+ return 0;
+
+ /* 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 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);
+ return 0;
+ }
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_TT_CT2_4500_CI: {
+ u8 eeprom[256]; /* 24C02 i2c eeprom */
+ struct sp2_config sp2_config;
+ struct i2c_board_info info;
+ struct cx23885_i2c *i2c_bus2 = &dev->i2c_bus[1];
+
+ /* 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)
+ return -ENODEV;
+ if (!try_module_get(client_ci->dev.driver->owner)) {
+ i2c_unregister_device(client_ci);
+ return -ENODEV;
+ }
+ port->i2c_client_ci = client_ci;
+
+ if (port->nr != 1)
+ return 0;
+
+ /* 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);
+ return 0;
+ }
+ }
+ return 0;
+}
+
static int dvb_register(struct cx23885_tsport *port)
{
struct dib7000p_ops dib7000p_ops;
@@ -1066,11 +1187,10 @@ 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 = NULL, *client_tuner = NULL, *client_ci = NULL;
+ struct i2c_client *client_demod = NULL, *client_tuner = 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 */
@@ -1801,15 +1921,11 @@ static int dvb_register(struct cx23885_tsport *port)
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);
+ client_tuner->dev.driver == NULL)
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;
@@ -1832,8 +1948,7 @@ static int dvb_register(struct cx23885_tsport *port)
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)
+ 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);
@@ -1851,15 +1966,10 @@ static int dvb_register(struct cx23885_tsport *port)
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);
+ client_tuner->dev.driver == NULL)
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;
@@ -1885,8 +1995,7 @@ static int dvb_register(struct cx23885_tsport *port)
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)
+ 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);
@@ -1932,8 +2041,7 @@ static int dvb_register(struct cx23885_tsport *port)
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)
+ 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);
@@ -1978,8 +2086,7 @@ static int dvb_register(struct cx23885_tsport *port)
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)
+ 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);
@@ -1997,20 +2104,101 @@ static int dvb_register(struct cx23885_tsport *port)
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);
+ client_tuner->dev.driver == NULL)
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;
+ case CX23885_BOARD_HAUPPAUGE_HVR5525:
+ switch (port->nr) {
+ struct m88rs6000t_config m88rs6000t_config;
+
+ /* port b - satellite */
+ case 1:
+ /* attach frontend */
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+ &hauppauge_hvr5525_m88ds3103_config,
+ &dev->i2c_bus[0].i2c_adap, &adapter);
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ /* attach SEC */
+ if (!dvb_attach(a8293_attach, fe0->dvb.frontend,
+ &dev->i2c_bus[0].i2c_adap,
+ &hauppauge_a8293_config))
+ goto frontend_detach;
+
+ /* attach tuner */
+ memset(&m88rs6000t_config, 0, sizeof(m88rs6000t_config));
+ m88rs6000t_config.fe = fe0->dvb.frontend;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "m88rs6000t", I2C_NAME_SIZE);
+ info.addr = 0x21;
+ info.platform_data = &m88rs6000t_config;
+ request_module("%s", info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (!client_tuner || !client_tuner->dev.driver)
+ goto frontend_detach;
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
+
+ /* delegate signal strength measurement to tuner */
+ fe0->dvb.frontend->ops.read_signal_strength =
+ fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+ break;
+ /* port c - terrestrial/cable */
+ case 2:
+ /* 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_SERIAL;
+ 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("%s", info.type);
+ client_demod = i2c_new_device(&dev->i2c_bus[0].i2c_adap, &info);
+ if (!client_demod || !client_demod->dev.driver)
+ 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("%s", info.type);
+ client_tuner = i2c_new_device(&dev->i2c_bus[1].i2c_adap, &info);
+ if (!client_tuner || !client_tuner->dev.driver) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ port->i2c_client_demod = NULL;
+ 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;
+ }
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
@@ -2047,123 +2235,29 @@ static int dvb_register(struct cx23885_tsport *port)
if (ret)
goto frontend_detach;
- /* init CI & MAC */
- switch (dev->board) {
- case CX23885_BOARD_NETUP_DUAL_DVBS2_CI: {
- static struct netup_card_info cinfo;
-
- netup_get_card_info(&dev->i2c_bus[0].i2c_adap, &cinfo);
- memcpy(port->frontends.adapter.proposed_mac,
- cinfo.port[port->nr - 1].mac, 6);
- printk(KERN_INFO "NetUP Dual DVB-S2 CI card port%d MAC=%pM\n",
- port->nr, port->frontends.adapter.proposed_mac);
-
- netup_ci_init(port);
- break;
- }
- case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF: {
- struct altera_ci_config netup_ci_cfg = {
- .dev = dev,/* magic number to identify*/
- .adapter = &port->frontends.adapter,/* for CI */
- .demux = &fe0->dvb.demux,/* for hw pid filter */
- .fpga_rw = netup_altera_fpga_rw,
- };
-
- altera_ci_init(&netup_ci_cfg, port->nr);
- break;
- }
- case CX23885_BOARD_TEVII_S470: {
- u8 eeprom[256]; /* 24C02 i2c eeprom */
-
- 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 "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
- memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
- break;
- }
- 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)
- 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 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;
+ ret = dvb_register_ci_mac(port);
+ if (ret)
+ goto frontend_detach;
- if (port->nr != 1)
- break;
+ return 0;
- /* 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;
- }
+frontend_detach:
+ /* remove I2C client for tuner */
+ client_tuner = port->i2c_client_tuner;
+ if (client_tuner) {
+ module_put(client_tuner->dev.driver->owner);
+ i2c_unregister_device(client_tuner);
+ port->i2c_client_tuner = NULL;
}
- return ret;
+ /* remove I2C client for demodulator */
+ client_demod = port->i2c_client_demod;
+ if (client_demod) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ port->i2c_client_demod = NULL;
+ }
-frontend_detach:
port->gate_ctrl = NULL;
vb2_dvb_dealloc_frontends(&port->frontends);
return -EINVAL;
diff --git a/drivers/media/pci/cx23885/cx23885-i2c.c b/drivers/media/pci/cx23885/cx23885-i2c.c
index fd71306af6e2..1135ea3f6ce5 100644
--- a/drivers/media/pci/cx23885/cx23885-i2c.c
+++ b/drivers/media/pci/cx23885/cx23885-i2c.c
@@ -300,8 +300,8 @@ static void do_i2c_scan(char *name, struct i2c_client *c)
rc = i2c_master_recv(c, &buf, 0);
if (rc < 0)
continue;
- printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",
- name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ printk(KERN_INFO "%s: i2c scan: found device @ 0x%04x [%s]\n",
+ name, i, i2c_devs[i] ? i2c_devs[i] : "???");
}
}
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 36f2f96c40e4..aeda8d3990ae 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -99,7 +99,8 @@
#define CX23885_BOARD_DVBSKY_S950 49
#define CX23885_BOARD_DVBSKY_S952 50
#define CX23885_BOARD_DVBSKY_T982 51
-#define CX23885_BOARD_HAUPPAUGE_STARBURST 52
+#define CX23885_BOARD_HAUPPAUGE_HVR5525 52
+#define CX23885_BOARD_HAUPPAUGE_STARBURST 53
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
diff --git a/drivers/media/pci/cx25821/Kconfig b/drivers/media/pci/cx25821/Kconfig
index 6439a847680c..1755d3d2feaa 100644
--- a/drivers/media/pci/cx25821/Kconfig
+++ b/drivers/media/pci/cx25821/Kconfig
@@ -2,8 +2,7 @@ config VIDEO_CX25821
tristate "Conexant cx25821 support"
depends on VIDEO_DEV && PCI && I2C
select I2C_ALGOBIT
- select VIDEO_BTCX
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DMA_SG
---help---
This is a video4linux driver for Conexant 25821 based
TV cards.
diff --git a/drivers/media/pci/cx25821/Makefile b/drivers/media/pci/cx25821/Makefile
index fb76c3d3713a..c8f8598a2b86 100644
--- a/drivers/media/pci/cx25821/Makefile
+++ b/drivers/media/pci/cx25821/Makefile
@@ -1,9 +1,8 @@
cx25821-y := cx25821-core.o cx25821-cards.o cx25821-i2c.o \
cx25821-gpio.o cx25821-medusa-video.o \
- cx25821-video.o cx25821-video-upstream.o
+ cx25821-video.o
obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
ccflags-y += -Idrivers/media/i2c
-ccflags-y += -Idrivers/media/common
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index 2dd5bcaa7e53..24f964bcc53a 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -63,8 +63,11 @@ static int devno;
struct cx25821_audio_buffer {
unsigned int bpl;
- struct btcx_riscmem risc;
- struct videobuf_dmabuf dma;
+ struct cx25821_riscmem risc;
+ void *vaddr;
+ struct scatterlist *sglist;
+ int sglen;
+ int nr_pages;
};
struct cx25821_audio_dev {
@@ -87,8 +90,6 @@ struct cx25821_audio_dev {
unsigned int period_size;
unsigned int num_periods;
- struct videobuf_dmabuf *dma_risc;
-
struct cx25821_audio_buffer *buf;
struct snd_pcm_substream *substream;
@@ -142,6 +143,83 @@ MODULE_PARM_DESC(debug, "enable debug messages");
#define PCI_MSK_AUD_EXT (1 << 4)
#define PCI_MSK_AUD_INT (1 << 3)
+
+static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip, int nr_pages)
+{
+ struct cx25821_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 cx25821_alsa_dma_map(struct cx25821_audio_dev *dev)
+{
+ struct cx25821_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: cx25821_alsa_map_sg failed\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int cx25821_alsa_dma_unmap(struct cx25821_audio_dev *dev)
+{
+ struct cx25821_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 cx25821_alsa_dma_free(struct cx25821_audio_buffer *buf)
+{
+ vfree(buf->sglist);
+ buf->sglist = NULL;
+ vfree(buf->vaddr);
+ buf->vaddr = NULL;
+ return 0;
+}
+
/*
* BOARD Specific: Sets audio DMA
*/
@@ -330,15 +408,17 @@ out:
static int dsp_buffer_free(struct cx25821_audio_dev *chip)
{
+ struct cx25821_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);
+ cx25821_alsa_dma_unmap(chip);
+ cx25821_alsa_dma_free(chip->buf);
+ pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma);
kfree(chip->buf);
- chip->dma_risc = NULL;
+ chip->buf = NULL;
chip->dma_size = 0;
return 0;
@@ -430,8 +510,6 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
struct cx25821_audio_dev *chip = snd_pcm_substream_chip(substream);
- struct videobuf_dmabuf *dma;
-
struct cx25821_audio_buffer *buf;
int ret;
@@ -455,19 +533,18 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
chip->period_size = AUDIO_LINE_SIZE;
buf->bpl = chip->period_size;
+ chip->buf = buf;
- dma = &buf->dma;
- videobuf_dma_init(dma);
- ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+ ret = cx25821_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 = cx25821_alsa_dma_map(chip);
if (ret < 0)
goto error;
- ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, dma->sglist,
+ ret = cx25821_risc_databuffer_audio(chip->pci, &buf->risc, buf->sglist,
chip->period_size, chip->num_periods, 1);
if (ret < 0) {
pr_info("DEBUG: ERROR after cx25821_risc_databuffer_audio()\n");
@@ -479,16 +556,14 @@ static int snd_cx25821_hw_params(struct snd_pcm_substream *substream,
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
- 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;
error:
+ chip->buf = NULL;
kfree(buf);
return ret;
}
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index 389fffd2f36f..559f8293c53a 100644
--- a/drivers/media/pci/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -874,10 +874,9 @@ static int cx25821_dev_setup(struct cx25821_dev *dev)
if (dev->pci->device != 0x8210) {
pr_info("%s(): Exiting. Incorrect Hardware device = 0x%02x\n",
__func__, dev->pci->device);
- return -1;
- } else {
- pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device);
+ return -ENODEV;
}
+ pr_info("Athena Hardware device = 0x%02x\n", dev->pci->device);
/* Apply a sensible clock frequency for the PCIe bridge */
dev->clk_freq = 28000000;
@@ -966,11 +965,15 @@ void cx25821_dev_unregister(struct cx25821_dev *dev)
release_mem_region(dev->base_io_addr, pci_resource_len(dev->pci, 0));
- for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; i++) {
+ for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; i++) {
if (i == SRAM_CH08) /* audio channel */
continue;
+ /*
+ * TODO: enable when video output is properly
+ * supported.
if (i == SRAM_CH09 || i == SRAM_CH10)
cx25821_free_mem_upstream(&dev->channels[i]);
+ */
cx25821_video_unregister(dev, i);
}
@@ -979,14 +982,41 @@ void cx25821_dev_unregister(struct cx25821_dev *dev)
}
EXPORT_SYMBOL(cx25821_dev_unregister);
+int cx25821_riscmem_alloc(struct pci_dev *pci,
+ struct cx25821_riscmem *risc,
+ unsigned int size)
+{
+ __le32 *cpu;
+ dma_addr_t dma = 0;
+
+ if (NULL != risc->cpu && risc->size < size)
+ pci_free_consistent(pci, risc->size, risc->cpu, risc->dma);
+ if (NULL == risc->cpu) {
+ cpu = pci_zalloc_consistent(pci, size, &dma);
+ if (NULL == cpu)
+ return -ENOMEM;
+ risc->cpu = cpu;
+ risc->dma = dma;
+ risc->size = size;
+ }
+ return 0;
+}
+EXPORT_SYMBOL(cx25821_riscmem_alloc);
+
static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
- unsigned int lines)
+ unsigned int lines, bool jump)
{
struct scatterlist *sg;
unsigned int line, todo;
+ if (jump) {
+ *(rp++) = cpu_to_le32(RISC_JUMP);
+ *(rp++) = cpu_to_le32(0);
+ *(rp++) = cpu_to_le32(0); /* bits 63-32 */
+ }
+
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -1035,7 +1065,7 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
return rp;
}
-int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc,
struct scatterlist *sglist, unsigned int top_offset,
unsigned int bottom_offset, unsigned int bpl,
unsigned int padding, unsigned int lines)
@@ -1052,14 +1082,14 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
fields++;
/* estimate risc mem: worst case is one write per page border +
- one write per scan line + syncs + jump (all 2 dwords). Padding
+ one write per scan line + syncs + jump (all 3 dwords). Padding
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
/* write and jump need and extra dword */
instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE +
lines);
- instructions += 2;
- rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
+ instructions += 5;
+ rc = cx25821_riscmem_alloc(pci, risc, instructions * 12);
if (rc < 0)
return rc;
@@ -1069,17 +1099,17 @@ int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
if (UNSET != top_offset) {
rp = cx25821_risc_field(rp, sglist, top_offset, 0, bpl, padding,
- lines);
+ lines, true);
}
if (UNSET != bottom_offset) {
rp = cx25821_risc_field(rp, sglist, bottom_offset, 0x200, bpl,
- padding, lines);
+ padding, lines, UNSET == top_offset);
}
/* save pointer to jmp instruction address */
risc->jmp = rp;
- BUG_ON((risc->jmp - risc->cpu + 2) * sizeof(*risc->cpu) > risc->size);
+ BUG_ON((risc->jmp - risc->cpu + 3) * sizeof(*risc->cpu) > risc->size);
return 0;
}
@@ -1146,7 +1176,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
}
int cx25821_risc_databuffer_audio(struct pci_dev *pci,
- struct btcx_riscmem *risc,
+ struct cx25821_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
unsigned int lines, unsigned int lpi)
@@ -1163,7 +1193,7 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci,
instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
instructions += 1;
- rc = btcx_riscmem_alloc(pci, risc, instructions * 12);
+ rc = cx25821_riscmem_alloc(pci, risc, instructions * 12);
if (rc < 0)
return rc;
@@ -1179,40 +1209,14 @@ int cx25821_risc_databuffer_audio(struct pci_dev *pci,
}
EXPORT_SYMBOL(cx25821_risc_databuffer_audio);
-int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value)
-{
- __le32 *rp;
- int rc;
-
- rc = btcx_riscmem_alloc(pci, risc, 4 * 16);
-
- if (rc < 0)
- return rc;
-
- /* write risc instructions */
- rp = risc->cpu;
-
- *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ1);
- *(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);
- *(rp++) = cpu_to_le32(0); /* bits 63-32 */
- return 0;
-}
-
-void cx25821_free_buffer(struct videobuf_queue *q, struct cx25821_buffer *buf)
+void cx25821_free_buffer(struct cx25821_dev *dev, struct cx25821_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;
+ if (WARN_ON(buf->risc.size == 0))
+ return;
+ pci_free_consistent(dev->pci,
+ buf->risc.size, buf->risc.cpu, buf->risc.dma);
+ memset(&buf->risc, 0, sizeof(buf->risc));
}
static irqreturn_t cx25821_irq(int irq, void *dev_id)
@@ -1297,14 +1301,15 @@ static int cx25821_initdev(struct pci_dev *pci_dev,
goto fail_unregister_device;
}
+ 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_unregister_pci;
+ }
err = cx25821_dev_setup(dev);
- if (err) {
- if (err == -EBUSY)
- goto fail_unregister_device;
- else
- goto fail_unregister_pci;
- }
+ if (err)
+ goto fail_free_ctx;
/* print pci info */
pci_read_config_byte(pci_dev, PCI_CLASS_REVISION, &dev->pci_rev);
@@ -1334,6 +1339,8 @@ fail_irq:
pr_info("cx25821_initdev() can't get IRQ !\n");
cx25821_dev_unregister(dev);
+fail_free_ctx:
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
fail_unregister_pci:
pci_disable_device(pci_dev);
fail_unregister_device:
@@ -1357,6 +1364,7 @@ static void cx25821_finidev(struct pci_dev *pci_dev)
free_irq(pci_dev->irq, dev);
cx25821_dev_unregister(dev);
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
v4l2_device_unregister(v4l2_dev);
kfree(dev);
}
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index 3a419f134584..7bc495e4ece2 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -3,7 +3,7 @@
*
* Copyright (C) 2009 Conexant Systems Inc.
* Authors <shu.lin@conexant.com>, <hiep.huynh@conexant.com>
- * Based on Steven Toth <stoth@linuxtv.org> cx23885 driver
+ * Based on Steven Toth <stoth@linuxtv.org> cx25821 driver
* Parts adapted/taken from Eduardo Moscoso Rubino
* Copyright (C) 2009 Eduardo Moscoso Rubino <moscoso@TopoLogica.com>
*
@@ -46,10 +46,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 FORMAT_FLAGS_PACKED 0x01
static const struct cx25821_fmt formats[] = {
@@ -76,41 +72,6 @@ static const struct cx25821_fmt *cx25821_format_by_fourcc(unsigned int fourcc)
return NULL;
}
-void cx25821_video_wakeup(struct cx25821_dev *dev, struct cx25821_dmaqueue *q,
- u32 count)
-{
- struct cx25821_buffer *buf;
- int bc;
-
- for (bc = 0;; bc++) {
- if (list_empty(&q->active)) {
- dprintk(1, "bc=%d (=0: active empty)\n", bc);
- break;
- }
-
- buf = list_entry(q->active.next, struct cx25821_buffer,
- vb.queue);
-
- /* count comes from the hw and it 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);
- 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)
- pr_err("%s: %d buffers handled (should be 1)\n", __func__, bc);
-}
-
int cx25821_start_video_dma(struct cx25821_dev *dev,
struct cx25821_dmaqueue *q,
struct cx25821_buffer *buf,
@@ -123,7 +84,6 @@ int cx25821_start_video_dma(struct cx25821_dev *dev,
/* reset counter */
cx_write(channel->gpcnt_ctl, 3);
- q->count = 1;
/* enable irq */
cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | (1 << channel->i));
@@ -139,86 +99,8 @@ int cx25821_start_video_dma(struct cx25821_dev *dev,
return 0;
}
-static int cx25821_restart_video_queue(struct cx25821_dev *dev,
- struct cx25821_dmaqueue *q,
- const struct sram_channel *channel)
-{
- struct cx25821_buffer *buf, *prev;
- struct list_head *item;
-
- if (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx25821_buffer,
- vb.queue);
-
- cx25821_start_video_dma(dev, q, buf, channel);
-
- list_for_each(item, &q->active) {
- buf = list_entry(item, struct cx25821_buffer, vb.queue);
- 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 cx25821_buffer,
- vb.queue);
-
- if (NULL == prev) {
- list_move_tail(&buf->vb.queue, &q->active);
- cx25821_start_video_dma(dev, q, buf, channel);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- } 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);
- prev->risc.jmp[2] = cpu_to_le32(0); /* Bits 63 - 32 */
- } else {
- return 0;
- }
- prev = buf;
- }
-}
-
-static void cx25821_vid_timeout(unsigned long data)
-{
- struct cx25821_data *timeout_data = (struct cx25821_data *)data;
- struct cx25821_dev *dev = timeout_data->dev;
- const struct sram_channel *channel = timeout_data->channel;
- struct cx25821_dmaqueue *q = &dev->channels[channel->i].dma_vidq;
- struct cx25821_buffer *buf;
- unsigned long flags;
-
- /* cx25821_sram_channel_dump(dev, channel); */
- cx_clear(channel->dma_ctl, 0x11);
-
- spin_lock_irqsave(&dev->slock, flags);
- while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx25821_buffer,
- vb.queue);
- list_del(&buf->vb.queue);
-
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- }
-
- cx25821_restart_video_queue(dev, q, channel);
- spin_unlock_irqrestore(&dev->slock, flags);
-}
-
int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
{
- u32 count = 0;
int handled = 0;
u32 mask;
const struct sram_channel *channel = dev->channels[chan_num].sram_channels;
@@ -239,317 +121,201 @@ int cx25821_video_irq(struct cx25821_dev *dev, int chan_num, u32 status)
/* risc1 y */
if (status & FLD_VID_DST_RISC1) {
- spin_lock(&dev->slock);
- count = cx_read(channel->gpcnt);
- cx25821_video_wakeup(dev, &dev->channels[channel->i].dma_vidq,
- count);
- spin_unlock(&dev->slock);
- handled++;
- }
+ struct cx25821_dmaqueue *dmaq =
+ &dev->channels[channel->i].dma_vidq;
+ struct cx25821_buffer *buf;
- /* risc2 y */
- if (status & 0x10) {
- dprintk(2, "stopper video\n");
spin_lock(&dev->slock);
- cx25821_restart_video_queue(dev,
- &dev->channels[channel->i].dma_vidq, channel);
+ if (!list_empty(&dmaq->active)) {
+ buf = list_entry(dmaq->active.next,
+ struct cx25821_buffer, queue);
+
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ buf->vb.v4l2_buf.sequence = dmaq->count++;
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
+ }
spin_unlock(&dev->slock);
handled++;
}
return handled;
}
-static int cx25821_buffer_setup(struct videobuf_queue *q, unsigned int *count,
- unsigned int *size)
+static int cx25821_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 cx25821_channel *chan = q->priv_data;
-
- *size = chan->fmt->depth * chan->width * chan->height >> 3;
+ struct cx25821_channel *chan = q->drv_priv;
+ unsigned size = (chan->fmt->depth * chan->width * chan->height) >> 3;
- if (0 == *count)
- *count = 32;
-
- if (*size * *count > vid_limit * 1024 * 1024)
- *count = (vid_limit * 1024 * 1024) / *size;
+ if (fmt && fmt->fmt.pix.sizeimage < size)
+ return -EINVAL;
+ *num_planes = 1;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : size;
+ alloc_ctxs[0] = chan->dev->alloc_ctx;
return 0;
}
-static int cx25821_buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int cx25821_buffer_prepare(struct vb2_buffer *vb)
{
- struct cx25821_channel *chan = q->priv_data;
+ struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
struct cx25821_dev *dev = chan->dev;
struct cx25821_buffer *buf =
container_of(vb, struct cx25821_buffer, vb);
- int rc, init_buffer = 0;
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
u32 line0_offset;
- struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
int bpl_local = LINE_SIZE_D1;
+ int ret;
- BUG_ON(NULL == chan->fmt);
- if (chan->width < 48 || chan->width > 720 ||
- chan->height < 32 || chan->height > 576)
- return -EINVAL;
-
- buf->vb.size = (chan->width * chan->height * chan->fmt->depth) >> 3;
+ if (chan->pixel_formats == PIXEL_FRMT_411)
+ buf->bpl = (chan->fmt->depth * chan->width) >> 3;
+ else
+ buf->bpl = (chan->fmt->depth >> 3) * chan->width;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ if (vb2_plane_size(vb, 0) < chan->height * buf->bpl)
return -EINVAL;
+ vb2_set_plane_payload(vb, 0, chan->height * buf->bpl);
+ buf->vb.v4l2_buf.field = chan->field;
- if (buf->fmt != chan->fmt ||
- buf->vb.width != chan->width ||
- buf->vb.height != chan->height || buf->vb.field != field) {
- buf->fmt = chan->fmt;
- buf->vb.width = chan->width;
- buf->vb.height = chan->height;
- buf->vb.field = field;
- init_buffer = 1;
- }
+ if (chan->pixel_formats == PIXEL_FRMT_411) {
+ bpl_local = buf->bpl;
+ } else {
+ bpl_local = buf->bpl; /* Default */
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- init_buffer = 1;
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (0 != rc) {
- printk(KERN_DEBUG pr_fmt("videobuf_iolock failed!\n"));
- goto fail;
+ if (chan->use_cif_resolution) {
+ if (dev->tvnorm & V4L2_STD_625_50)
+ bpl_local = 352 << 1;
+ else
+ bpl_local = chan->cif_width << 1;
}
}
- dprintk(1, "init_buffer=%d\n", init_buffer);
-
- if (init_buffer) {
- if (chan->pixel_formats == PIXEL_FRMT_411)
- buf->bpl = (buf->fmt->depth * buf->vb.width) >> 3;
- else
- buf->bpl = (buf->fmt->depth >> 3) * (buf->vb.width);
-
- if (chan->pixel_formats == PIXEL_FRMT_411) {
- bpl_local = buf->bpl;
- } else {
- bpl_local = buf->bpl; /* Default */
-
- if (chan->use_cif_resolution) {
- if (dev->tvnorm & V4L2_STD_625_50)
- bpl_local = 352 << 1;
- else
- bpl_local = chan->cif_width << 1;
- }
- }
-
- switch (buf->vb.field) {
- case V4L2_FIELD_TOP:
- cx25821_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, 0, UNSET,
- buf->bpl, 0, buf->vb.height);
- break;
- case V4L2_FIELD_BOTTOM:
- cx25821_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, UNSET, 0,
- buf->bpl, 0, buf->vb.height);
- break;
- case V4L2_FIELD_INTERLACED:
- /* All other formats are top field first */
- line0_offset = 0;
- dprintk(1, "top field first\n");
-
- cx25821_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, line0_offset,
- bpl_local, bpl_local, bpl_local,
- buf->vb.height >> 1);
- break;
- case V4L2_FIELD_SEQ_TB:
- cx25821_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:
- cx25821_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 (chan->field) {
+ case V4L2_FIELD_TOP:
+ ret = cx25821_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, 0, UNSET,
+ buf->bpl, 0, chan->height);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ ret = cx25821_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, UNSET, 0,
+ buf->bpl, 0, chan->height);
+ break;
+ case V4L2_FIELD_INTERLACED:
+ /* All other formats are top field first */
+ line0_offset = 0;
+ dprintk(1, "top field first\n");
+
+ ret = cx25821_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, line0_offset,
+ bpl_local, bpl_local, bpl_local,
+ chan->height >> 1);
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ ret = cx25821_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ 0, buf->bpl * (chan->height >> 1),
+ buf->bpl, 0, chan->height >> 1);
+ break;
+ case V4L2_FIELD_SEQ_BT:
+ ret = cx25821_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ buf->bpl * (chan->height >> 1), 0,
+ buf->bpl, 0, chan->height >> 1);
+ break;
+ default:
+ WARN_ON(1);
+ ret = -EINVAL;
+ break;
}
dprintk(2, "[%p/%d] buffer_prep - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
- buf, buf->vb.i, chan->width, chan->height, chan->fmt->depth,
- chan->fmt->name, (unsigned long)buf->risc.dma);
-
- buf->vb.state = VIDEOBUF_PREPARED;
-
- return 0;
+ buf, buf->vb.v4l2_buf.index, chan->width, chan->height,
+ chan->fmt->depth, chan->fmt->name,
+ (unsigned long)buf->risc.dma);
-fail:
- cx25821_free_buffer(q, buf);
- return rc;
+ return ret;
}
-static void cx25821_buffer_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static void cx25821_buffer_finish(struct vb2_buffer *vb)
{
struct cx25821_buffer *buf =
container_of(vb, struct cx25821_buffer, vb);
+ struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
+ struct cx25821_dev *dev = chan->dev;
- cx25821_free_buffer(q, buf);
-}
-
-static int cx25821_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct cx25821_channel *chan = video_drvdata(file);
-
- return videobuf_mmap_mapper(&chan->vidq, vma);
+ cx25821_free_buffer(dev, buf);
}
-
-static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void cx25821_buffer_queue(struct vb2_buffer *vb)
{
struct cx25821_buffer *buf =
container_of(vb, struct cx25821_buffer, vb);
- struct cx25821_buffer *prev;
- struct cx25821_channel *chan = vq->priv_data;
+ struct cx25821_channel *chan = vb->vb2_queue->drv_priv;
struct cx25821_dev *dev = chan->dev;
+ struct cx25821_buffer *prev;
struct cx25821_dmaqueue *q = &dev->channels[chan->id].dma_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);
- buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
-
- dprintk(2, "jmp to stopper (0x%x)\n", buf->risc.jmp[1]);
-
- 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);
- cx25821_start_video_dma(dev, q, buf, chan->sram_channels);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies + BUFFER_TIMEOUT);
- dprintk(2, "[%p/%d] buffer_queue - first active, buf cnt = %d, q->count = %d\n",
- buf, buf->vb.i, buf->count, q->count);
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 12);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 12);
+ buf->risc.jmp[2] = cpu_to_le32(0); /* bits 63-32 */
+
+ if (list_empty(&q->active)) {
+ list_add_tail(&buf->queue, &q->active);
} else {
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
prev = list_entry(q->active.prev, struct cx25821_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);
-
- /* 64 bit bits 63-32 */
- prev->risc.jmp[2] = cpu_to_le32(0);
- dprintk(2, "[%p/%d] buffer_queue - append to active, buf->count=%d\n",
- buf, buf->vb.i, buf->count);
-
- } 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);
- }
+ queue);
+ list_add_tail(&buf->queue, &q->active);
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
}
-
- if (list_empty(&q->active))
- dprintk(2, "active queue empty!\n");
}
-static struct videobuf_queue_ops cx25821_video_qops = {
- .buf_setup = cx25821_buffer_setup,
- .buf_prepare = cx25821_buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = cx25821_buffer_release,
-};
-
-static ssize_t video_read(struct file *file, char __user * data, size_t count,
- loff_t *ppos)
+static int cx25821_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct v4l2_fh *fh = file->private_data;
- struct cx25821_channel *chan = video_drvdata(file);
+ struct cx25821_channel *chan = q->drv_priv;
struct cx25821_dev *dev = chan->dev;
- int err = 0;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- if (chan->streaming_fh && chan->streaming_fh != fh) {
- err = -EBUSY;
- goto unlock;
- }
- chan->streaming_fh = fh;
+ struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
+ struct cx25821_buffer *buf = list_entry(dmaq->active.next,
+ struct cx25821_buffer, queue);
- err = videobuf_read_one(&chan->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
-unlock:
- mutex_unlock(&dev->lock);
- return err;
-}
-
-static unsigned int video_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct cx25821_channel *chan = video_drvdata(file);
- unsigned long req_events = poll_requested_events(wait);
- unsigned int res = v4l2_ctrl_poll(file, wait);
-
- if (req_events & (POLLIN | POLLRDNORM))
- res |= videobuf_poll_stream(file, &chan->vidq, wait);
- return res;
-
- /* This doesn't belong in poll(). This can be done
- * much better with vb2. We keep this code here as a
- * reminder.
- if ((res & POLLIN) && buf->vb.state == VIDEOBUF_DONE) {
- struct cx25821_dev *dev = chan->dev;
-
- if (dev && chan->use_cif_resolution) {
- u8 cam_id = *((char *)buf->vb.baddr + 3);
- memcpy((char *)buf->vb.baddr,
- (char *)buf->vb.baddr + (chan->width * 2),
- (chan->width * 2));
- *((char *)buf->vb.baddr + 3) = cam_id;
- }
- }
- */
+ dmaq->count = 0;
+ cx25821_start_video_dma(dev, dmaq, buf, chan->sram_channels);
+ return 0;
}
-static int video_release(struct file *file)
+static void cx25821_stop_streaming(struct vb2_queue *q)
{
- struct cx25821_channel *chan = video_drvdata(file);
- struct v4l2_fh *fh = file->private_data;
+ struct cx25821_channel *chan = q->drv_priv;
struct cx25821_dev *dev = chan->dev;
- const struct sram_channel *sram_ch =
- dev->channels[0].sram_channels;
-
- mutex_lock(&dev->lock);
- /* stop the risc engine and fifo */
- cx_write(sram_ch->dma_ctl, 0); /* FIFO and RISC disable */
+ struct cx25821_dmaqueue *dmaq = &dev->channels[chan->id].dma_vidq;
+ unsigned long flags;
- /* stop video capture */
- if (chan->streaming_fh == fh) {
- videobuf_queue_cancel(&chan->vidq);
- chan->streaming_fh = NULL;
- }
+ cx_write(chan->sram_channels->dma_ctl, 0); /* FIFO and RISC disable */
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx25821_buffer *buf = list_entry(dmaq->active.next,
+ struct cx25821_buffer, queue);
- if (chan->vidq.read_buf) {
- cx25821_buffer_release(&chan->vidq, chan->vidq.read_buf);
- kfree(chan->vidq.read_buf);
+ list_del(&buf->queue);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
-
- videobuf_mmap_free(&chan->vidq);
- mutex_unlock(&dev->lock);
-
- return v4l2_fh_release(file);
+ spin_unlock_irqrestore(&dev->slock, flags);
}
+static struct vb2_ops cx25821_video_qops = {
+ .queue_setup = cx25821_queue_setup,
+ .buf_prepare = cx25821_buffer_prepare,
+ .buf_finish = cx25821_buffer_finish,
+ .buf_queue = cx25821_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = cx25821_start_streaming,
+ .stop_streaming = cx25821_stop_streaming,
+};
+
/* VIDEO IOCTLS */
static int cx25821_vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
@@ -571,7 +337,7 @@ static int cx25821_vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.width = chan->width;
f->fmt.pix.height = chan->height;
- f->fmt.pix.field = chan->vidq.field;
+ f->fmt.pix.field = chan->field;
f->fmt.pix.pixelformat = chan->fmt->fourcc;
f->fmt.pix.bytesperline = (chan->width * chan->fmt->depth) >> 3;
f->fmt.pix.sizeimage = chan->height * f->fmt.pix.bytesperline;
@@ -632,7 +398,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return err;
chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
- chan->vidq.field = f->fmt.pix.field;
+ chan->field = f->fmt.pix.field;
chan->width = f->fmt.pix.width;
chan->height = f->fmt.pix.height;
@@ -654,47 +420,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_channel *chan = video_drvdata(file);
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (chan->streaming_fh && chan->streaming_fh != priv)
- return -EBUSY;
- chan->streaming_fh = priv;
-
- return videobuf_streamon(&chan->vidq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx25821_channel *chan = video_drvdata(file);
-
- if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (chan->streaming_fh && chan->streaming_fh != priv)
- return -EBUSY;
- if (chan->streaming_fh == NULL)
- return 0;
-
- chan->streaming_fh = NULL;
- return videobuf_streamoff(&chan->vidq);
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- int ret_val = 0;
- struct cx25821_channel *chan = video_drvdata(file);
-
- ret_val = videobuf_dqbuf(&chan->vidq, p, file->f_flags & O_NONBLOCK);
- p->sequence = chan->dma_vidq.count;
-
- return ret_val;
-}
-
static int vidioc_log_status(struct file *file, void *priv)
{
struct cx25821_channel *chan = video_drvdata(file);
@@ -729,29 +454,6 @@ static int cx25821_vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int cx25821_vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *p)
-{
- struct cx25821_channel *chan = video_drvdata(file);
-
- return videobuf_reqbufs(&chan->vidq, p);
-}
-
-static int cx25821_vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct cx25821_channel *chan = video_drvdata(file);
-
- return videobuf_querybuf(&chan->vidq, p);
-}
-
-static int cx25821_vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx25821_channel *chan = video_drvdata(file);
-
- return videobuf_qbuf(&chan->vidq, p);
-}
-
static int cx25821_vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
{
struct cx25821_channel *chan = video_drvdata(file);
@@ -880,7 +582,7 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return err;
chan->fmt = cx25821_format_by_fourcc(f->fmt.pix.pixelformat);
- chan->vidq.field = f->fmt.pix.field;
+ chan->field = f->fmt.pix.field;
chan->width = f->fmt.pix.width;
chan->height = f->fmt.pix.height;
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_Y41P)
@@ -890,52 +592,6 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return 0;
}
-static ssize_t video_write(struct file *file, const char __user *data, size_t count,
- loff_t *ppos)
-{
- struct cx25821_channel *chan = video_drvdata(file);
- struct cx25821_dev *dev = chan->dev;
- struct v4l2_fh *fh = file->private_data;
- int err = 0;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- if (chan->streaming_fh && chan->streaming_fh != fh) {
- err = -EBUSY;
- goto unlock;
- }
- if (!chan->streaming_fh) {
- err = cx25821_vidupstream_init(chan, chan->pixel_formats);
- if (err)
- goto unlock;
- chan->streaming_fh = fh;
- }
-
- err = cx25821_write_frame(chan, data, count);
- count -= err;
- *ppos += err;
-
-unlock:
- mutex_unlock(&dev->lock);
- return err;
-}
-
-static int video_out_release(struct file *file)
-{
- struct cx25821_channel *chan = video_drvdata(file);
- struct cx25821_dev *dev = chan->dev;
- struct v4l2_fh *fh = file->private_data;
-
- mutex_lock(&dev->lock);
- if (chan->streaming_fh == fh) {
- cx25821_stop_upstream_video(chan);
- chan->streaming_fh = NULL;
- }
- mutex_unlock(&dev->lock);
-
- return v4l2_fh_release(file);
-}
-
static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
.s_ctrl = cx25821_s_ctrl,
};
@@ -943,11 +599,11 @@ static const struct v4l2_ctrl_ops cx25821_ctrl_ops = {
static const struct v4l2_file_operations video_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = cx25821_video_mmap,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -956,17 +612,19 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = cx25821_vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = cx25821_vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = cx25821_vidioc_reqbufs,
- .vidioc_querybuf = cx25821_vidioc_querybuf,
- .vidioc_qbuf = cx25821_vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .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_g_std = cx25821_vidioc_g_std,
.vidioc_s_std = cx25821_vidioc_s_std,
.vidioc_enum_input = cx25821_vidioc_enum_input,
.vidioc_g_input = cx25821_vidioc_g_input,
.vidioc_s_input = cx25821_vidioc_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
.vidioc_log_status = vidioc_log_status,
.vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
@@ -984,9 +642,11 @@ static const struct video_device cx25821_video_device = {
static const struct v4l2_file_operations video_out_fops = {
.owner = THIS_MODULE,
.open = v4l2_fh_open,
- .write = video_write,
- .release = video_out_release,
+ .release = vb2_fop_release,
+ .write = vb2_fop_write,
+ .poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
};
static const struct v4l2_ioctl_ops video_out_ioctl_ops = {
@@ -1019,9 +679,6 @@ void cx25821_video_unregister(struct cx25821_dev *dev, int chan_num)
if (video_is_registered(&dev->channels[chan_num].vdev)) {
video_unregister_device(&dev->channels[chan_num].vdev);
v4l2_ctrl_handler_free(&dev->channels[chan_num].hdl);
-
- btcx_riscmem_free(dev->pci,
- &dev->channels[chan_num].dma_vidq.stopper);
}
}
@@ -1035,10 +692,11 @@ int cx25821_video_register(struct cx25821_dev *dev)
spin_lock_init(&dev->slock);
- for (i = 0; i < MAX_VID_CHANNEL_NUM - 1; ++i) {
+ for (i = 0; i < MAX_VID_CAP_CHANNEL_NUM - 1; ++i) {
struct cx25821_channel *chan = &dev->channels[i];
struct video_device *vdev = &chan->vdev;
struct v4l2_ctrl_handler *hdl = &chan->hdl;
+ struct vb2_queue *q;
bool is_output = i > SRAM_CH08;
if (i == SRAM_CH08) /* audio channel */
@@ -1066,11 +724,9 @@ int cx25821_video_register(struct cx25821_dev *dev)
chan->out->chan = chan;
}
- cx25821_risc_stopper(dev->pci, &chan->dma_vidq.stopper,
- chan->sram_channels->dma_ctl, 0x11, 0);
-
chan->sram_channels = &cx25821_sram_channels[i];
chan->width = 720;
+ chan->field = V4L2_FIELD_INTERLACED;
if (dev->tvnorm & V4L2_STD_625_50)
chan->height = 576;
else
@@ -1084,19 +740,27 @@ int cx25821_video_register(struct cx25821_dev *dev)
cx_write(chan->sram_channels->int_stat, 0xffffffff);
INIT_LIST_HEAD(&chan->dma_vidq.active);
- INIT_LIST_HEAD(&chan->dma_vidq.queued);
- chan->timeout_data.dev = dev;
- chan->timeout_data.channel = &cx25821_sram_channels[i];
- chan->dma_vidq.timeout.function = cx25821_vid_timeout;
- chan->dma_vidq.timeout.data = (unsigned long)&chan->timeout_data;
- init_timer(&chan->dma_vidq.timeout);
+ q = &chan->vidq;
+
+ q->type = is_output ? V4L2_BUF_TYPE_VIDEO_OUTPUT :
+ V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->io_modes |= is_output ? VB2_WRITE : VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = chan;
+ q->buf_struct_size = sizeof(struct cx25821_buffer);
+ q->ops = &cx25821_video_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &dev->lock;
- if (!is_output)
- videobuf_queue_sg_init(&chan->vidq, &cx25821_video_qops, &dev->pci->dev,
- &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED, sizeof(struct cx25821_buffer),
- chan, &dev->lock);
+ if (!is_output) {
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_unreg;
+ }
/* register v4l devices */
*vdev = is_output ? cx25821_video_out_device : cx25821_video_device;
@@ -1106,6 +770,7 @@ int cx25821_video_register(struct cx25821_dev *dev)
else
vdev->vfl_dir = VFL_DIR_TX;
vdev->lock = &dev->lock;
+ vdev->queue = q;
snprintf(vdev->name, sizeof(vdev->name), "%s #%d", dev->name, i);
video_set_drvdata(vdev, chan);
diff --git a/drivers/media/pci/cx25821/cx25821.h b/drivers/media/pci/cx25821/cx25821.h
index 90bdc196929f..d81a08a2df4f 100644
--- a/drivers/media/pci/cx25821/cx25821.h
+++ b/drivers/media/pci/cx25821/cx25821.h
@@ -34,9 +34,8 @@
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf2-dma-sg.h>
-#include "btcx-risc.h"
#include "cx25821-reg.h"
#include "cx25821-medusa-reg.h"
#include "cx25821-sram.h"
@@ -89,6 +88,13 @@
#define CX25821_BOARD_CONEXANT_ATHENA10 1
#define MAX_VID_CHANNEL_NUM 12
+
+/*
+ * Maximum capture-only channels. This can go away once video/audio output
+ * is fully supported in this driver.
+ */
+#define MAX_VID_CAP_CHANNEL_NUM 10
+
#define VID_CHANNEL_NUM 8
struct cx25821_fmt {
@@ -111,16 +117,23 @@ enum cx25821_src_sel_type {
CX25821_SRC_SEL_PARALLEL_MPEG_VIDEO
};
+struct cx25821_riscmem {
+ unsigned int size;
+ __le32 *cpu;
+ __le32 *jmp;
+ dma_addr_t dma;
+};
+
/* buffer for one video frame */
struct cx25821_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+ struct vb2_buffer vb;
+ struct list_head queue;
/* cx25821 specific */
unsigned int bpl;
- struct btcx_riscmem risc;
+ struct cx25821_riscmem risc;
const struct cx25821_fmt *fmt;
- u32 count;
};
enum port {
@@ -159,17 +172,9 @@ struct cx25821_i2c {
struct cx25821_dmaqueue {
struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
- struct btcx_riscmem stopper;
u32 count;
};
-struct cx25821_data {
- struct cx25821_dev *dev;
- const struct sram_channel *channel;
-};
-
struct cx25821_dev;
struct cx25821_channel;
@@ -207,18 +212,17 @@ struct cx25821_video_out_data {
struct cx25821_channel {
unsigned id;
struct cx25821_dev *dev;
- struct v4l2_fh *streaming_fh;
struct v4l2_ctrl_handler hdl;
- struct cx25821_data timeout_data;
struct video_device vdev;
struct cx25821_dmaqueue dma_vidq;
- struct videobuf_queue vidq;
+ struct vb2_queue vidq;
const struct sram_channel *sram_channels;
const struct cx25821_fmt *fmt;
+ unsigned field;
unsigned int width, height;
int pixel_formats;
int use_cif_resolution;
@@ -244,6 +248,7 @@ struct cx25821_dev {
int hwrevision;
/* used by cx25821-alsa */
struct snd_card *card;
+ void *alloc_ctx;
u32 clk_freq;
@@ -405,21 +410,22 @@ extern int cx25821_sram_channel_setup(struct cx25821_dev *dev,
const struct sram_channel *ch, unsigned int bpl,
u32 risc);
-extern int cx25821_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+extern int cx25821_riscmem_alloc(struct pci_dev *pci,
+ struct cx25821_riscmem *risc,
+ unsigned int size);
+extern int cx25821_risc_buffer(struct pci_dev *pci, struct cx25821_riscmem *risc,
struct scatterlist *sglist,
unsigned int top_offset,
unsigned int bottom_offset,
unsigned int bpl,
unsigned int padding, unsigned int lines);
extern int cx25821_risc_databuffer_audio(struct pci_dev *pci,
- struct btcx_riscmem *risc,
+ struct cx25821_riscmem *risc,
struct scatterlist *sglist,
unsigned int bpl,
unsigned int lines, unsigned int lpi);
-extern void cx25821_free_buffer(struct videobuf_queue *q,
+extern void cx25821_free_buffer(struct cx25821_dev *dev,
struct cx25821_buffer *buf);
-extern int cx25821_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value);
extern void cx25821_sram_channel_dump(struct cx25821_dev *dev,
const struct sram_channel *ch);
extern void cx25821_sram_channel_dump_audio(struct cx25821_dev *dev,
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index d3c79d964f2c..b6be46e94289 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -1234,6 +1234,3 @@ static void __exit blackbird_fini(void)
module_init(blackbird_init);
module_exit(blackbird_fini);
-
-module_param_named(video_debug,cx8802_mpeg_template.debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages [video]");
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index dee177ed5fe9..c38d5a12e277 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -1091,10 +1091,3 @@ EXPORT_SYMBOL(cx88_core_put);
EXPORT_SYMBOL(cx88_ir_start);
EXPORT_SYMBOL(cx88_ir_stop);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 5780e2f013b4..1b2ed238cdb6 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -1504,8 +1504,8 @@ static int dvb_register(struct cx8802_dev *dev)
fe0->dvb.frontend = dvb_attach(stv0288_attach,
&tevii_tuner_earda_config,
&core->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
+ if (fe0->dvb.frontend != NULL) {
+ if (!dvb_attach(stb6000_attach, fe0->dvb.frontend, 0x61,
&core->i2c_adap))
goto frontend_detach;
core->prev_set_voltage = fe0->dvb.frontend->ops.set_voltage;
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index 1c1f69e6b0b9..a369b0840acf 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -833,10 +833,3 @@ EXPORT_SYMBOL(cx8802_start_dma);
EXPORT_SYMBOL(cx8802_register_driver);
EXPORT_SYMBOL(cx8802_unregister_driver);
EXPORT_SYMBOL(cx8802_get_driver);
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/pci/cx88/cx88-tvaudio.c b/drivers/media/pci/cx88/cx88-tvaudio.c
index 424fd97495dc..6bbce6ad6295 100644
--- a/drivers/media/pci/cx88/cx88-tvaudio.c
+++ b/drivers/media/pci/cx88/cx88-tvaudio.c
@@ -1050,10 +1050,3 @@ EXPORT_SYMBOL(cx88_newstation);
EXPORT_SYMBOL(cx88_set_stereo);
EXPORT_SYMBOL(cx88_get_stereo);
EXPORT_SYMBOL(cx88_audio_thread);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/pci/ivtv/ivtv-irq.c b/drivers/media/pci/ivtv/ivtv-irq.c
index ab6d5d25aa6f..e7d701777e53 100644
--- a/drivers/media/pci/ivtv/ivtv-irq.c
+++ b/drivers/media/pci/ivtv/ivtv-irq.c
@@ -357,7 +357,6 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
u32 uv_offset = offset + IVTV_YUV_BUFFER_UV_OFFSET;
int y_done = 0;
int bytes_written = 0;
- unsigned long flags = 0;
int idx = 0;
IVTV_DEBUG_HI_DMA("DEC PREPARE DMA %s: %08x %08x\n", s->name, s->q_predma.bytesused, offset);
@@ -407,16 +406,21 @@ void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock)
/* Sync Hardware SG List of buffers */
ivtv_stream_sync_for_device(s);
- if (lock)
+ if (lock) {
+ unsigned long flags = 0;
+
spin_lock_irqsave(&itv->dma_reg_lock, flags);
- if (!test_bit(IVTV_F_I_DMA, &itv->i_flags)) {
- ivtv_dma_dec_start(s);
- }
- else {
- set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
- }
- if (lock)
+ if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
+ ivtv_dma_dec_start(s);
+ else
+ set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
spin_unlock_irqrestore(&itv->dma_reg_lock, flags);
+ } else {
+ if (!test_bit(IVTV_F_I_DMA, &itv->i_flags))
+ ivtv_dma_dec_start(s);
+ else
+ set_bit(IVTV_F_S_DMA_PENDING, &s->s_flags);
+ }
}
static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c
index bee2329e0b2e..24152accc66c 100644
--- a/drivers/media/pci/ivtv/ivtv-udma.c
+++ b/drivers/media/pci/ivtv/ivtv-udma.c
@@ -124,10 +124,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
}
/* Get user pages for DMA Xfer */
- down_read(&current->mm->mmap_sem);
- err = get_user_pages(current, current->mm,
- user_dma.uaddr, user_dma.page_count, 0, 1, dma->map, NULL);
- up_read(&current->mm->mmap_sem);
+ err = get_user_pages_unlocked(current, current->mm,
+ user_dma.uaddr, user_dma.page_count, 0, 1, dma->map);
if (user_dma.page_count != err) {
IVTV_DEBUG_WARN("failed to map user pages, returned %d instead of %d\n",
diff --git a/drivers/media/pci/mantis/mantis_core.c b/drivers/media/pci/mantis/mantis_core.c
index 684d9061fe2a..82220ea72dd3 100644
--- a/drivers/media/pci/mantis/mantis_core.c
+++ b/drivers/media/pci/mantis/mantis_core.c
@@ -56,29 +56,6 @@ static int read_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
return 0;
}
-static int write_eeprom_byte(struct mantis_pci *mantis, u8 *data, u8 length)
-{
- int err;
-
- struct i2c_msg msg = {
- .addr = 0x50,
- .flags = 0,
- .buf = data,
- .len = length
- };
-
- err = i2c_transfer(&mantis->adapter, &msg, 1);
- if (err < 0) {
- dprintk(verbose, MANTIS_ERROR, 1,
- "ERROR: i2c write: < err=%i length=0x%02x d0=0x%02x, d1=0x%02x >",
- err, length, data[0], data[1]);
-
- return err;
- }
-
- return 0;
-}
-
static int get_mac_address(struct mantis_pci *mantis)
{
int err;
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 701b52f34689..99d09a7566d3 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -1084,11 +1084,6 @@ static int saa7134_s_ctrl(struct v4l2_ctrl *ctrl)
/* ------------------------------------------------------------------ */
-static inline struct vb2_queue *saa7134_queue(struct file *file)
-{
- return video_devdata(file)->queue;
-}
-
static int video_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c
index f773350e67b9..36c8ed77309c 100644
--- a/drivers/media/pci/smipcie/smipcie.c
+++ b/drivers/media/pci/smipcie/smipcie.c
@@ -448,16 +448,19 @@ static void smi_port_exit(struct smi_port *port)
port->enable = 0;
}
-static void smi_port_irq(struct smi_port *port, u32 int_status)
+static int smi_port_irq(struct smi_port *port, u32 int_status)
{
u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1;
+ int handled = 0;
if (int_status & port_req_irq) {
smi_port_disableInterrupt(port);
port->_int_status = int_status;
smi_port_clearInterrupt(port);
tasklet_schedule(&port->tasklet);
+ handled = 1;
}
+ return handled;
}
static irqreturn_t smi_irq_handler(int irq, void *dev_id)
@@ -465,18 +468,19 @@ 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];
+ int handled = 0;
u32 intr_status = smi_read(MSI_INT_STATUS);
/* ts0 interrupt.*/
if (dev->info->ts_0)
- smi_port_irq(port0, intr_status);
+ handled += smi_port_irq(port0, intr_status);
/* ts1 interrupt.*/
if (dev->info->ts_1)
- smi_port_irq(port1, intr_status);
+ handled += smi_port_irq(port1, intr_status);
- return IRQ_HANDLED;
+ return IRQ_RETVAL(handled);
}
static struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter,
diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c
index 8cbe6b49f4c2..570d119ea18b 100644
--- a/drivers/media/pci/solo6x10/solo6x10-core.c
+++ b/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -182,7 +182,7 @@ static ssize_t eeprom_store(struct device *dev, struct device_attribute *attr,
{
struct solo_dev *solo_dev =
container_of(dev, struct solo_dev, dev);
- unsigned short *p = (unsigned short *)buf;
+ u16 *p = (u16 *)buf;
int i;
if (count & 0x1)
@@ -212,7 +212,7 @@ static ssize_t eeprom_show(struct device *dev, struct device_attribute *attr,
{
struct solo_dev *solo_dev =
container_of(dev, struct solo_dev, dev);
- unsigned short *p = (unsigned short *)buf;
+ u16 *p = (u16 *)buf;
int count = (full_eeprom ? 128 : 64);
int i;
diff --git a/drivers/media/pci/solo6x10/solo6x10-eeprom.c b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
index da25ce4a6952..8e81186dc785 100644
--- a/drivers/media/pci/solo6x10/solo6x10-eeprom.c
+++ b/drivers/media/pci/solo6x10/solo6x10-eeprom.c
@@ -103,7 +103,7 @@ unsigned int solo_eeprom_ewen(struct solo_dev *solo_dev, int w_en)
__be16 solo_eeprom_read(struct solo_dev *solo_dev, int loc)
{
int read_cmd = loc | (EE_READ_CMD << ADDR_LEN);
- unsigned short retval = 0;
+ u16 retval = 0;
int i;
solo_eeprom_cmd(solo_dev, read_cmd);
diff --git a/drivers/media/pci/solo6x10/solo6x10-enc.c b/drivers/media/pci/solo6x10/solo6x10-enc.c
index d19c0aef5abc..d28211bb9674 100644
--- a/drivers/media/pci/solo6x10/solo6x10-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-enc.c
@@ -136,11 +136,11 @@ static void solo_capture_config(struct solo_dev *solo_dev)
int solo_osd_print(struct solo_enc_dev *solo_enc)
{
struct solo_dev *solo_dev = solo_enc->solo_dev;
- unsigned char *str = solo_enc->osd_text;
+ u8 *str = solo_enc->osd_text;
u8 *buf = solo_enc->osd_buf;
u32 reg;
const struct font_desc *vga = find_font("VGA8x16");
- const unsigned char *vga_data;
+ const u8 *vga_data;
int i, j;
if (WARN_ON_ONCE(!vga))
@@ -154,7 +154,7 @@ int solo_osd_print(struct solo_enc_dev *solo_enc)
}
memset(buf, 0, SOLO_OSD_WRITE_SIZE);
- vga_data = (const unsigned char *)vga->data;
+ vga_data = (const u8 *)vga->data;
for (i = 0; *str; i++, str++) {
for (j = 0; j < 16; j++) {
diff --git a/drivers/media/pci/solo6x10/solo6x10-g723.c b/drivers/media/pci/solo6x10/solo6x10-g723.c
index c7141f2e63bd..7ddc76709caa 100644
--- a/drivers/media/pci/solo6x10/solo6x10-g723.c
+++ b/drivers/media/pci/solo6x10/solo6x10-g723.c
@@ -56,8 +56,8 @@
struct solo_snd_pcm {
int on;
spinlock_t lock;
- struct solo_dev *solo_dev;
- unsigned char *g723_buf;
+ struct solo_dev *solo_dev;
+ u8 *g723_buf;
dma_addr_t g723_dma;
};
diff --git a/drivers/media/pci/solo6x10/solo6x10-jpeg.h b/drivers/media/pci/solo6x10/solo6x10-jpeg.h
index 1c66a46da514..3c611bd3f2d8 100644
--- a/drivers/media/pci/solo6x10/solo6x10-jpeg.h
+++ b/drivers/media/pci/solo6x10/solo6x10-jpeg.h
@@ -21,7 +21,7 @@
#ifndef __SOLO6X10_JPEG_H
#define __SOLO6X10_JPEG_H
-static const unsigned char jpeg_header[] = {
+static const u8 jpeg_header[] = {
0xff, 0xd8, 0xff, 0xfe, 0x00, 0x0d, 0x42, 0x6c,
0x75, 0x65, 0x63, 0x68, 0x65, 0x72, 0x72, 0x79,
0x20, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x20, 0x16,
@@ -106,7 +106,7 @@ static const unsigned char jpeg_header[] = {
/* This is the byte marker for the start of the DQT */
#define DQT_START 17
#define DQT_LEN 138
-static const unsigned char jpeg_dqt[4][DQT_LEN] = {
+static const u8 jpeg_dqt[4][DQT_LEN] = {
{
0xff, 0xdb, 0x00, 0x43, 0x00,
0x08, 0x06, 0x06, 0x07, 0x06, 0x05, 0x08, 0x07,
diff --git a/drivers/media/pci/solo6x10/solo6x10-tw28.c b/drivers/media/pci/solo6x10/solo6x10-tw28.c
index edd0781ee4b5..0632d3f7c73c 100644
--- a/drivers/media/pci/solo6x10/solo6x10-tw28.c
+++ b/drivers/media/pci/solo6x10/solo6x10-tw28.c
@@ -510,7 +510,7 @@ static int tw2815_setup(struct solo_dev *solo_dev, u8 dev_addr)
#define FIRST_ACTIVE_LINE 0x0008
#define LAST_ACTIVE_LINE 0x0102
-static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
+static void saa712x_write_regs(struct solo_dev *dev, const u8 *vals,
int start, int n)
{
for (; start < n; start++, vals++) {
@@ -532,7 +532,7 @@ static void saa712x_write_regs(struct solo_dev *dev, const uint8_t *vals,
static void saa712x_setup(struct solo_dev *dev)
{
const int reg_start = 0x26;
- const uint8_t saa7128_regs_ntsc[] = {
+ const u8 saa7128_regs_ntsc[] = {
/* :0x26 */
0x0d, 0x00,
/* :0x28 */
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index 6e933d383fa2..53fff5425c13 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -38,28 +38,28 @@
#define DMA_ALIGN 4096
/* 6010 M4V */
-static unsigned char vop_6010_ntsc_d1[] = {
+static u8 vop_6010_ntsc_d1[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
0x1f, 0x4c, 0x58, 0x10, 0xf0, 0x71, 0x18, 0x3f,
};
-static unsigned char vop_6010_ntsc_cif[] = {
+static u8 vop_6010_ntsc_cif[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
0x02, 0x48, 0x1d, 0xc0, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
0x1f, 0x4c, 0x2c, 0x10, 0x78, 0x51, 0x18, 0x3f,
};
-static unsigned char vop_6010_pal_d1[] = {
+static u8 vop_6010_pal_d1[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
0x1f, 0x4c, 0x58, 0x11, 0x20, 0x71, 0x18, 0x3f,
};
-static unsigned char vop_6010_pal_cif[] = {
+static u8 vop_6010_pal_cif[] = {
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20,
0x02, 0x48, 0x15, 0xc0, 0x00, 0x40, 0x00, 0x40,
0x00, 0x40, 0x00, 0x80, 0x00, 0x97, 0x53, 0x04,
@@ -67,25 +67,25 @@ static unsigned char vop_6010_pal_cif[] = {
};
/* 6110 h.264 */
-static unsigned char vop_6110_ntsc_d1[] = {
+static u8 vop_6110_ntsc_d1[] = {
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
0x9a, 0x74, 0x05, 0x81, 0xec, 0x80, 0x00, 0x00,
0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
};
-static unsigned char vop_6110_ntsc_cif[] = {
+static u8 vop_6110_ntsc_cif[] = {
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
0x9a, 0x74, 0x0b, 0x0f, 0xc8, 0x00, 0x00, 0x00,
0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
};
-static unsigned char vop_6110_pal_d1[] = {
+static u8 vop_6110_pal_d1[] = {
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
0x9a, 0x74, 0x05, 0x80, 0x93, 0x20, 0x00, 0x00,
0x00, 0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00,
};
-static unsigned char vop_6110_pal_cif[] = {
+static u8 vop_6110_pal_cif[] = {
0x00, 0x00, 0x00, 0x01, 0x67, 0x42, 0x00, 0x1e,
0x9a, 0x74, 0x0b, 0x04, 0xb2, 0x00, 0x00, 0x00,
0x01, 0x68, 0xce, 0x32, 0x28, 0x00, 0x00, 0x00,
@@ -149,7 +149,7 @@ void solo_update_mode(struct solo_enc_dev *solo_enc)
{
struct solo_dev *solo_dev = solo_enc->solo_dev;
int vop_len;
- unsigned char *vop;
+ u8 *vop;
solo_enc->interlaced = (solo_enc->mode & 0x08) ? 1 : 0;
solo_enc->bw_weight = max(solo_dev->fps / solo_enc->interval, 1);
@@ -239,8 +239,6 @@ static int solo_enc_on(struct solo_enc_dev *solo_enc)
if (solo_enc->bw_weight > solo_dev->enc_bw_remain)
return -EBUSY;
solo_enc->sequence = 0;
- solo_enc->motion_last_state = false;
- solo_enc->frames_since_last_motion = 0;
solo_dev->enc_bw_remain -= solo_enc->bw_weight;
if (solo_enc->type == SOLO_ENC_TYPE_EXT)
@@ -529,36 +527,12 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
}
if (!ret) {
- bool send_event = false;
-
vb->v4l2_buf.sequence = solo_enc->sequence++;
vb->v4l2_buf.timestamp.tv_sec = vop_sec(vh);
vb->v4l2_buf.timestamp.tv_usec = vop_usec(vh);
/* Check for motion flags */
- if (solo_is_motion_on(solo_enc)) {
- /* It takes a few frames for the hardware to detect
- * motion. Once it does it clears the motion detection
- * register and it takes again a few frames before
- * motion is seen. This means in practice that when the
- * motion field is 1, it will go back to 0 for the next
- * frame. This leads to motion detection event being
- * sent all the time, which is not what we want.
- * Instead wait a few frames before deciding that the
- * motion has halted. After some experimentation it
- * turns out that waiting for 5 frames works well.
- */
- if (enc_buf->motion == 0 &&
- solo_enc->motion_last_state &&
- solo_enc->frames_since_last_motion++ > 5)
- send_event = true;
- else if (enc_buf->motion) {
- solo_enc->frames_since_last_motion = 0;
- send_event = !solo_enc->motion_last_state;
- }
- }
-
- if (send_event) {
+ if (solo_is_motion_on(solo_enc) && enc_buf->motion) {
struct v4l2_event ev = {
.type = V4L2_EVENT_MOTION_DET,
.u.motion_det = {
@@ -568,8 +542,6 @@ static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
},
};
- solo_enc->motion_last_state = enc_buf->motion;
- solo_enc->frames_since_last_motion = 0;
v4l2_event_queue(solo_enc->vfd, &ev);
}
}
diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
index bd8edfa319b8..1ca54b08b3aa 100644
--- a/drivers/media/pci/solo6x10/solo6x10.h
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -159,8 +159,6 @@ struct solo_enc_dev {
u16 motion_thresh;
bool motion_global;
bool motion_enabled;
- bool motion_last_state;
- u8 frames_since_last_motion;
u16 width;
u16 height;
@@ -170,9 +168,9 @@ struct solo_enc_dev {
__aligned(4);
/* VOP stuff */
- unsigned char vop[64];
+ u8 vop[64];
int vop_len;
- unsigned char jpeg_header[1024];
+ u8 jpeg_header[1024];
int jpeg_len;
u32 fmt;
diff --git a/drivers/media/pci/sta2x11/Kconfig b/drivers/media/pci/sta2x11/Kconfig
index f6f30abc088b..e03587b1af71 100644
--- a/drivers/media/pci/sta2x11/Kconfig
+++ b/drivers/media/pci/sta2x11/Kconfig
@@ -5,6 +5,7 @@ config STA2X11_VIP
select VIDEO_ADV7180 if MEDIA_SUBDRV_AUTOSELECT
select VIDEOBUF2_DMA_CONTIG
depends on PCI && VIDEO_V4L2 && VIRT_TO_BUS
+ depends on VIDEO_V4L2_SUBDEV_API
depends on I2C
help
Say Y for support for STA2X11 VIP (Video Input Port) capture
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index c1f0617a6973..45199a12b9d9 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -1219,11 +1219,14 @@ static int stop_ts_capture(struct av7110 *budget)
static int start_ts_capture(struct av7110 *budget)
{
+ unsigned y;
+
dprintk(2, "budget: %p\n", budget);
if (budget->feeding1)
return ++budget->feeding1;
- memset(budget->grabbing, 0x00, TS_BUFLEN);
+ for (y = 0; y < TS_HEIGHT; y++)
+ memset(budget->grabbing + y * TS_WIDTH, 0x00, TS_WIDTH);
budget->ttbp = 0;
SAA7146_ISR_CLEAR(budget->dev, MASK_10); /* VPE */
SAA7146_IER_ENABLE(budget->dev, MASK_10); /* VPE */
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index 37d02fe09137..23e05499b509 100644
--- a/drivers/media/pci/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -231,63 +231,59 @@ static void vpeirq(unsigned long data)
}
-int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
- int uselocks, int nobusyloop)
+static int ttpci_budget_debiread_nolock(struct budget *budget, u32 config,
+ int addr, int count, int nobusyloop)
{
struct saa7146_dev *saa = budget->dev;
- int result = 0;
- unsigned long flags = 0;
-
- if (count > 4 || count <= 0)
- return 0;
-
- if (uselocks)
- spin_lock_irqsave(&budget->debilock, flags);
+ int result;
- if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
- if (uselocks)
- spin_unlock_irqrestore(&budget->debilock, flags);
+ result = saa7146_wait_for_debi_done(saa, nobusyloop);
+ if (result < 0)
return result;
- }
saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x10000 | (addr & 0xffff));
saa7146_write(saa, DEBI_CONFIG, config);
saa7146_write(saa, DEBI_PAGE, 0);
saa7146_write(saa, MC2, (2 << 16) | 2);
- if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
- if (uselocks)
- spin_unlock_irqrestore(&budget->debilock, flags);
+ result = saa7146_wait_for_debi_done(saa, nobusyloop);
+ if (result < 0)
return result;
- }
result = saa7146_read(saa, DEBI_AD);
result &= (0xffffffffUL >> ((4 - count) * 8));
-
- if (uselocks)
- spin_unlock_irqrestore(&budget->debilock, flags);
-
return result;
}
-int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
- int count, u32 value, int uselocks, int nobusyloop)
+int ttpci_budget_debiread(struct budget *budget, u32 config, int addr, int count,
+ int uselocks, int nobusyloop)
{
- struct saa7146_dev *saa = budget->dev;
- unsigned long flags = 0;
- int result;
-
if (count > 4 || count <= 0)
return 0;
- if (uselocks)
- spin_lock_irqsave(&budget->debilock, flags);
+ if (uselocks) {
+ unsigned long flags;
+ int result;
- if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
- if (uselocks)
- spin_unlock_irqrestore(&budget->debilock, flags);
+ spin_lock_irqsave(&budget->debilock, flags);
+ result = ttpci_budget_debiread_nolock(budget, config, addr,
+ count, nobusyloop);
+ spin_unlock_irqrestore(&budget->debilock, flags);
return result;
}
+ return ttpci_budget_debiread_nolock(budget, config, addr,
+ count, nobusyloop);
+}
+
+static int ttpci_budget_debiwrite_nolock(struct budget *budget, u32 config,
+ int addr, int count, u32 value, int nobusyloop)
+{
+ struct saa7146_dev *saa = budget->dev;
+ int result;
+
+ result = saa7146_wait_for_debi_done(saa, nobusyloop);
+ if (result < 0)
+ return result;
saa7146_write(saa, DEBI_COMMAND, (count << 17) | 0x00000 | (addr & 0xffff));
saa7146_write(saa, DEBI_CONFIG, config);
@@ -295,15 +291,28 @@ int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
saa7146_write(saa, DEBI_AD, value);
saa7146_write(saa, MC2, (2 << 16) | 2);
- if ((result = saa7146_wait_for_debi_done(saa, nobusyloop)) < 0) {
- if (uselocks)
- spin_unlock_irqrestore(&budget->debilock, flags);
- return result;
- }
+ result = saa7146_wait_for_debi_done(saa, nobusyloop);
+ return result < 0 ? result : 0;
+}
- if (uselocks)
+int ttpci_budget_debiwrite(struct budget *budget, u32 config, int addr,
+ int count, u32 value, int uselocks, int nobusyloop)
+{
+ if (count > 4 || count <= 0)
+ return 0;
+
+ if (uselocks) {
+ unsigned long flags;
+ int result;
+
+ spin_lock_irqsave(&budget->debilock, flags);
+ result = ttpci_budget_debiwrite_nolock(budget, config, addr,
+ count, value, nobusyloop);
spin_unlock_irqrestore(&budget->debilock, flags);
- return 0;
+ return result;
+ }
+ return ttpci_budget_debiwrite_nolock(budget, config, addr,
+ count, value, nobusyloop);
}
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h
index 7a7501bd165f..93f2335e004b 100644
--- a/drivers/media/pci/tw68/tw68.h
+++ b/drivers/media/pci/tw68/tw68.h
@@ -25,7 +25,6 @@
* GNU General Public License for more details.
*/
-#include <linux/version.h>
#include <linux/pci.h>
#include <linux/videodev2.h>
#include <linux/notifier.h>
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 765bffb49a72..d9b872b9285a 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -56,10 +56,8 @@ config VIDEO_VIU
config VIDEO_TIMBERDALE
tristate "Support for timberdale Video In/LogiWIN"
- depends on VIDEO_V4L2 && I2C && DMADEVICES
- depends on MFD_TIMBERDALE || COMPILE_TEST
- select DMA_ENGINE
- select TIMB_DMA
+ depends on VIDEO_V4L2 && I2C && VIDEO_V4L2_SUBDEV_API
+ depends on (MFD_TIMBERDALE && TIMB_DMA) || COMPILE_TEST
select VIDEO_ADV7180
select VIDEOBUF_DMA_CONTIG
---help---
@@ -118,6 +116,7 @@ config VIDEO_S3C_CAMIF
source "drivers/media/platform/soc_camera/Kconfig"
source "drivers/media/platform/exynos4-is/Kconfig"
source "drivers/media/platform/s5p-tv/Kconfig"
+source "drivers/media/platform/am437x/Kconfig"
endif # V4L_PLATFORM_DRIVERS
@@ -140,6 +139,7 @@ config VIDEO_CODA
depends on HAS_DMA
select SRAM
select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
select GENERIC_ALLOCATOR
---help---
@@ -213,7 +213,6 @@ config VIDEO_SAMSUNG_EXYNOS_GSC
config VIDEO_SH_VEU
tristate "SuperH VEU mem2mem video processing driver"
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
- depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
help
@@ -223,7 +222,7 @@ config VIDEO_SH_VEU
config VIDEO_RENESAS_VSP1
tristate "Renesas VSP1 Video Processing Engine"
depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API && HAS_DMA
- depends on ARCH_SHMOBILE || COMPILE_TEST
+ depends on (ARCH_SHMOBILE && OF) || COMPILE_TEST
select VIDEOBUF2_DMA_CONTIG
---help---
This is a V4L2 driver for the Renesas VSP1 video processing engine.
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index a49936b8ce8a..3ec154742083 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -46,4 +46,6 @@ obj-$(CONFIG_VIDEO_RENESAS_VSP1) += vsp1/
obj-y += omap/
+obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x/
+
ccflags-y += -I$(srctree)/drivers/media/i2c
diff --git a/drivers/media/platform/am437x/Kconfig b/drivers/media/platform/am437x/Kconfig
new file mode 100644
index 000000000000..7b023a76e32e
--- /dev/null
+++ b/drivers/media/platform/am437x/Kconfig
@@ -0,0 +1,11 @@
+config VIDEO_AM437X_VPFE
+ tristate "TI AM437x VPFE video capture driver"
+ depends on VIDEO_V4L2 && VIDEO_V4L2_SUBDEV_API
+ depends on SOC_AM43XX || COMPILE_TEST
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ Support for AM437x Video Processing Front End based Video
+ Capture Driver.
+
+ To compile this driver as a module, choose M here. The module
+ will be called am437x-vpfe.
diff --git a/drivers/media/platform/am437x/Makefile b/drivers/media/platform/am437x/Makefile
new file mode 100644
index 000000000000..d11fff16f260
--- /dev/null
+++ b/drivers/media/platform/am437x/Makefile
@@ -0,0 +1,3 @@
+# Makefile for AM437x VPFE driver
+
+obj-$(CONFIG_VIDEO_AM437X_VPFE) += am437x-vpfe.o
diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
new file mode 100644
index 000000000000..56a5cb0d2152
--- /dev/null
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -0,0 +1,2776 @@
+/*
+ * TI VPFE capture Driver
+ *
+ * Copyright (C) 2013 - 2014 Texas Instruments, Inc.
+ *
+ * Benoit Parrot <bparrot@ti.com>
+ * Lad, Prabhakar <prabhakar.csengg@gmail.com>
+ *
+ * This program is free software; you may 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-of.h>
+
+#include "am437x-vpfe.h"
+
+#define VPFE_MODULE_NAME "vpfe"
+#define VPFE_VERSION "0.1.0"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level 0-8");
+
+#define vpfe_dbg(level, dev, fmt, arg...) \
+ v4l2_dbg(level, debug, &dev->v4l2_dev, fmt, ##arg)
+#define vpfe_info(dev, fmt, arg...) \
+ v4l2_info(&dev->v4l2_dev, fmt, ##arg)
+#define vpfe_err(dev, fmt, arg...) \
+ v4l2_err(&dev->v4l2_dev, fmt, ##arg)
+
+/* standard information */
+struct vpfe_standard {
+ v4l2_std_id std_id;
+ unsigned int width;
+ unsigned int height;
+ struct v4l2_fract pixelaspect;
+ int frame_format;
+};
+
+static const struct vpfe_standard vpfe_standards[] = {
+ {V4L2_STD_525_60, 720, 480, {11, 10}, 1},
+ {V4L2_STD_625_50, 720, 576, {54, 59}, 1},
+};
+
+struct bus_format {
+ unsigned int width;
+ unsigned int bpp;
+};
+
+/*
+ * struct vpfe_fmt - VPFE media bus format information
+ * @name: V4L2 format description
+ * @code: V4L2 media bus format code
+ * @shifted: V4L2 media bus format code for the same pixel layout but
+ * shifted to be 8 bits per pixel. =0 if format is not shiftable.
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @width: Bits per pixel (when transferred over a bus)
+ * @bpp: Bytes per pixel (when stored in memory)
+ * @supported: Indicates format supported by subdev
+ */
+struct vpfe_fmt {
+ const char *name;
+ u32 fourcc;
+ u32 code;
+ struct bus_format l;
+ struct bus_format s;
+ bool supported;
+ u32 index;
+};
+
+static struct vpfe_fmt formats[] = {
+ {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
+ .l.width = 10,
+ .l.bpp = 4,
+ .s.width = 8,
+ .s.bpp = 2,
+ .supported = false,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
+ .l.width = 10,
+ .l.bpp = 4,
+ .s.width = 8,
+ .s.bpp = 2,
+ .supported = false,
+ }, {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
+ .l.width = 10,
+ .l.bpp = 4,
+ .s.width = 8,
+ .s.bpp = 2,
+ .supported = false,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
+ .l.width = 10,
+ .l.bpp = 4,
+ .s.width = 8,
+ .s.bpp = 2,
+ .supported = false,
+ }, {
+ .name = "RAW8 BGGR",
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .l.width = 10,
+ .l.bpp = 2,
+ .s.width = 8,
+ .s.bpp = 1,
+ .supported = false,
+ }, {
+ .name = "RAW8 GBRG",
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .l.width = 10,
+ .l.bpp = 2,
+ .s.width = 8,
+ .s.bpp = 1,
+ .supported = false,
+ }, {
+ .name = "RAW8 GRBG",
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .l.width = 10,
+ .l.bpp = 2,
+ .s.width = 8,
+ .s.bpp = 1,
+ .supported = false,
+ }, {
+ .name = "RAW8 RGGB",
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .l.width = 10,
+ .l.bpp = 2,
+ .s.width = 8,
+ .s.bpp = 1,
+ .supported = false,
+ }, {
+ .name = "RGB565 (LE)",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .l.width = 10,
+ .l.bpp = 4,
+ .s.width = 8,
+ .s.bpp = 2,
+ .supported = false,
+ }, {
+ .name = "RGB565 (BE)",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .l.width = 10,
+ .l.bpp = 4,
+ .s.width = 8,
+ .s.bpp = 2,
+ .supported = false,
+ },
+};
+
+static int
+__vpfe_get_format(struct vpfe_device *vpfe,
+ struct v4l2_format *format, unsigned int *bpp);
+
+static struct vpfe_fmt *find_format_by_code(unsigned int code)
+{
+ struct vpfe_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (fmt->code == code)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+static struct vpfe_fmt *find_format_by_pix(unsigned int pixelformat)
+{
+ struct vpfe_fmt *fmt;
+ unsigned int k;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ fmt = &formats[k];
+ if (fmt->fourcc == pixelformat)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+static void
+mbus_to_pix(struct vpfe_device *vpfe,
+ const struct v4l2_mbus_framefmt *mbus,
+ struct v4l2_pix_format *pix, unsigned int *bpp)
+{
+ struct vpfe_subdev_info *sdinfo = vpfe->current_subdev;
+ unsigned int bus_width = sdinfo->vpfe_param.bus_width;
+ struct vpfe_fmt *fmt;
+
+ fmt = find_format_by_code(mbus->code);
+ if (WARN_ON(fmt == NULL)) {
+ pr_err("Invalid mbus code set\n");
+ *bpp = 1;
+ return;
+ }
+
+ memset(pix, 0, sizeof(*pix));
+ v4l2_fill_pix_format(pix, mbus);
+ pix->pixelformat = fmt->fourcc;
+ *bpp = (bus_width == 10) ? fmt->l.bpp : fmt->s.bpp;
+
+ /* pitch should be 32 bytes aligned */
+ pix->bytesperline = ALIGN(pix->width * *bpp, 32);
+ pix->sizeimage = pix->bytesperline * pix->height;
+}
+
+static void pix_to_mbus(struct vpfe_device *vpfe,
+ struct v4l2_pix_format *pix_fmt,
+ struct v4l2_mbus_framefmt *mbus_fmt)
+{
+ struct vpfe_fmt *fmt;
+
+ fmt = find_format_by_pix(pix_fmt->pixelformat);
+ if (!fmt) {
+ /* default to first entry */
+ vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n",
+ pix_fmt->pixelformat);
+ fmt = &formats[0];
+ }
+
+ memset(mbus_fmt, 0, sizeof(*mbus_fmt));
+ v4l2_fill_mbus_format(mbus_fmt, pix_fmt, fmt->code);
+}
+
+/* Print Four-character-code (FOURCC) */
+static char *print_fourcc(u32 fmt)
+{
+ static char code[5];
+
+ code[0] = (unsigned char)(fmt & 0xff);
+ code[1] = (unsigned char)((fmt >> 8) & 0xff);
+ code[2] = (unsigned char)((fmt >> 16) & 0xff);
+ code[3] = (unsigned char)((fmt >> 24) & 0xff);
+ code[4] = '\0';
+
+ return code;
+}
+
+static int
+cmp_v4l2_format(const struct v4l2_format *lhs, const struct v4l2_format *rhs)
+{
+ return lhs->type == rhs->type &&
+ lhs->fmt.pix.width == rhs->fmt.pix.width &&
+ lhs->fmt.pix.height == rhs->fmt.pix.height &&
+ lhs->fmt.pix.pixelformat == rhs->fmt.pix.pixelformat &&
+ lhs->fmt.pix.field == rhs->fmt.pix.field &&
+ lhs->fmt.pix.colorspace == rhs->fmt.pix.colorspace &&
+ lhs->fmt.pix.ycbcr_enc == rhs->fmt.pix.ycbcr_enc &&
+ lhs->fmt.pix.quantization == rhs->fmt.pix.quantization;
+}
+
+static inline u32 vpfe_reg_read(struct vpfe_ccdc *ccdc, u32 offset)
+{
+ return ioread32(ccdc->ccdc_cfg.base_addr + offset);
+}
+
+static inline void vpfe_reg_write(struct vpfe_ccdc *ccdc, u32 val, u32 offset)
+{
+ iowrite32(val, ccdc->ccdc_cfg.base_addr + offset);
+}
+
+static inline struct vpfe_device *to_vpfe(struct vpfe_ccdc *ccdc)
+{
+ return container_of(ccdc, struct vpfe_device, ccdc);
+}
+
+static inline struct vpfe_cap_buffer *to_vpfe_buffer(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct vpfe_cap_buffer, vb);
+}
+
+static inline void vpfe_pcr_enable(struct vpfe_ccdc *ccdc, int flag)
+{
+ vpfe_reg_write(ccdc, !!flag, VPFE_PCR);
+}
+
+static void vpfe_config_enable(struct vpfe_ccdc *ccdc, int flag)
+{
+ unsigned int cfg;
+
+ if (!flag) {
+ cfg = vpfe_reg_read(ccdc, VPFE_CONFIG);
+ cfg &= ~(VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT);
+ } else {
+ cfg = VPFE_CONFIG_EN_ENABLE << VPFE_CONFIG_EN_SHIFT;
+ }
+
+ vpfe_reg_write(ccdc, cfg, VPFE_CONFIG);
+}
+
+static void vpfe_ccdc_setwin(struct vpfe_ccdc *ccdc,
+ struct v4l2_rect *image_win,
+ enum ccdc_frmfmt frm_fmt,
+ int bpp)
+{
+ int horz_start, horz_nr_pixels;
+ int vert_start, vert_nr_lines;
+ int val, mid_img;
+
+ /*
+ * ppc - per pixel count. indicates how many pixels per cell
+ * output to SDRAM. example, for ycbcr, it is one y and one c, so 2.
+ * raw capture this is 1
+ */
+ horz_start = image_win->left * bpp;
+ horz_nr_pixels = (image_win->width * bpp) - 1;
+ vpfe_reg_write(ccdc, (horz_start << VPFE_HORZ_INFO_SPH_SHIFT) |
+ horz_nr_pixels, VPFE_HORZ_INFO);
+
+ vert_start = image_win->top;
+
+ if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ vert_nr_lines = (image_win->height >> 1) - 1;
+ vert_start >>= 1;
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ /* configure VDINT0 */
+ val = (vert_start << VPFE_VDINT_VDINT0_SHIFT);
+ } else {
+ /* Since first line doesn't have any data */
+ vert_start += 1;
+ vert_nr_lines = image_win->height - 1;
+ /*
+ * configure VDINT0 and VDINT1. VDINT1 will be at half
+ * of image height
+ */
+ mid_img = vert_start + (image_win->height / 2);
+ val = (vert_start << VPFE_VDINT_VDINT0_SHIFT) |
+ (mid_img & VPFE_VDINT_VDINT1_MASK);
+ }
+
+ vpfe_reg_write(ccdc, val, VPFE_VDINT);
+
+ vpfe_reg_write(ccdc, (vert_start << VPFE_VERT_START_SLV0_SHIFT) |
+ vert_start, VPFE_VERT_START);
+ vpfe_reg_write(ccdc, vert_nr_lines, VPFE_VERT_LINES);
+}
+
+static void vpfe_reg_dump(struct vpfe_ccdc *ccdc)
+{
+ struct vpfe_device *vpfe = to_vpfe(ccdc);
+
+ vpfe_dbg(3, vpfe, "ALAW: 0x%x\n", vpfe_reg_read(ccdc, VPFE_ALAW));
+ vpfe_dbg(3, vpfe, "CLAMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_CLAMP));
+ vpfe_dbg(3, vpfe, "DCSUB: 0x%x\n", vpfe_reg_read(ccdc, VPFE_DCSUB));
+ vpfe_dbg(3, vpfe, "BLKCMP: 0x%x\n", vpfe_reg_read(ccdc, VPFE_BLKCMP));
+ vpfe_dbg(3, vpfe, "COLPTN: 0x%x\n", vpfe_reg_read(ccdc, VPFE_COLPTN));
+ vpfe_dbg(3, vpfe, "SDOFST: 0x%x\n", vpfe_reg_read(ccdc, VPFE_SDOFST));
+ vpfe_dbg(3, vpfe, "SYN_MODE: 0x%x\n",
+ vpfe_reg_read(ccdc, VPFE_SYNMODE));
+ vpfe_dbg(3, vpfe, "HSIZE_OFF: 0x%x\n",
+ vpfe_reg_read(ccdc, VPFE_HSIZE_OFF));
+ vpfe_dbg(3, vpfe, "HORZ_INFO: 0x%x\n",
+ vpfe_reg_read(ccdc, VPFE_HORZ_INFO));
+ vpfe_dbg(3, vpfe, "VERT_START: 0x%x\n",
+ vpfe_reg_read(ccdc, VPFE_VERT_START));
+ vpfe_dbg(3, vpfe, "VERT_LINES: 0x%x\n",
+ vpfe_reg_read(ccdc, VPFE_VERT_LINES));
+}
+
+static int
+vpfe_ccdc_validate_param(struct vpfe_ccdc *ccdc,
+ struct vpfe_ccdc_config_params_raw *ccdcparam)
+{
+ struct vpfe_device *vpfe = to_vpfe(ccdc);
+ u8 max_gamma, max_data;
+
+ if (!ccdcparam->alaw.enable)
+ return 0;
+
+ max_gamma = ccdc_gamma_width_max_bit(ccdcparam->alaw.gamma_wd);
+ max_data = ccdc_data_size_max_bit(ccdcparam->data_sz);
+
+ if (ccdcparam->alaw.gamma_wd > VPFE_CCDC_GAMMA_BITS_09_0 ||
+ ccdcparam->alaw.gamma_wd < VPFE_CCDC_GAMMA_BITS_15_6 ||
+ max_gamma > max_data) {
+ vpfe_dbg(1, vpfe, "Invalid data line select\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void
+vpfe_ccdc_update_raw_params(struct vpfe_ccdc *ccdc,
+ struct vpfe_ccdc_config_params_raw *raw_params)
+{
+ struct vpfe_ccdc_config_params_raw *config_params =
+ &ccdc->ccdc_cfg.bayer.config_params;
+
+ config_params = raw_params;
+}
+
+/*
+ * vpfe_ccdc_restore_defaults()
+ * This function will write defaults to all CCDC registers
+ */
+static void vpfe_ccdc_restore_defaults(struct vpfe_ccdc *ccdc)
+{
+ int i;
+
+ /* Disable CCDC */
+ vpfe_pcr_enable(ccdc, 0);
+
+ /* set all registers to default value */
+ for (i = 4; i <= 0x94; i += 4)
+ vpfe_reg_write(ccdc, 0, i);
+
+ vpfe_reg_write(ccdc, VPFE_NO_CULLING, VPFE_CULLING);
+ vpfe_reg_write(ccdc, VPFE_CCDC_GAMMA_BITS_11_2, VPFE_ALAW);
+}
+
+static int vpfe_ccdc_close(struct vpfe_ccdc *ccdc, struct device *dev)
+{
+ int dma_cntl, i, pcr;
+
+ /* If the CCDC module is still busy wait for it to be done */
+ for (i = 0; i < 10; i++) {
+ usleep_range(5000, 6000);
+ pcr = vpfe_reg_read(ccdc, VPFE_PCR);
+ if (!pcr)
+ break;
+
+ /* make sure it it is disabled */
+ vpfe_pcr_enable(ccdc, 0);
+ }
+
+ /* Disable CCDC by resetting all register to default POR values */
+ vpfe_ccdc_restore_defaults(ccdc);
+
+ /* if DMA_CNTL overflow bit is set. Clear it
+ * It appears to take a while for this to become quiescent ~20ms
+ */
+ for (i = 0; i < 10; i++) {
+ dma_cntl = vpfe_reg_read(ccdc, VPFE_DMA_CNTL);
+ if (!(dma_cntl & VPFE_DMA_CNTL_OVERFLOW))
+ break;
+
+ /* Clear the overflow bit */
+ vpfe_reg_write(ccdc, dma_cntl, VPFE_DMA_CNTL);
+ usleep_range(5000, 6000);
+ }
+
+ /* Disabled the module at the CONFIG level */
+ vpfe_config_enable(ccdc, 0);
+
+ pm_runtime_put_sync(dev);
+
+ return 0;
+}
+
+static int vpfe_ccdc_set_params(struct vpfe_ccdc *ccdc, void __user *params)
+{
+ struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+ struct vpfe_ccdc_config_params_raw raw_params;
+ int x;
+
+ if (ccdc->ccdc_cfg.if_type != VPFE_RAW_BAYER)
+ return -EINVAL;
+
+ x = copy_from_user(&raw_params, params, sizeof(raw_params));
+ if (x) {
+ vpfe_dbg(1, vpfe,
+ "vpfe_ccdc_set_params: error in copying ccdc params, %d\n",
+ x);
+ return -EFAULT;
+ }
+
+ if (!vpfe_ccdc_validate_param(ccdc, &raw_params)) {
+ vpfe_ccdc_update_raw_params(ccdc, &raw_params);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * vpfe_ccdc_config_ycbcr()
+ * This function will configure CCDC for YCbCr video capture
+ */
+static void vpfe_ccdc_config_ycbcr(struct vpfe_ccdc *ccdc)
+{
+ struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+ struct ccdc_params_ycbcr *params = &ccdc->ccdc_cfg.ycbcr;
+ u32 syn_mode;
+
+ vpfe_dbg(3, vpfe, "vpfe_ccdc_config_ycbcr:\n");
+ /*
+ * first restore the CCDC registers to default values
+ * This is important since we assume default values to be set in
+ * a lot of registers that we didn't touch
+ */
+ vpfe_ccdc_restore_defaults(ccdc);
+
+ /*
+ * configure pixel format, frame format, configure video frame
+ * format, enable output to SDRAM, enable internal timing generator
+ * and 8bit pack mode
+ */
+ syn_mode = (((params->pix_fmt & VPFE_SYN_MODE_INPMOD_MASK) <<
+ VPFE_SYN_MODE_INPMOD_SHIFT) |
+ ((params->frm_fmt & VPFE_SYN_FLDMODE_MASK) <<
+ VPFE_SYN_FLDMODE_SHIFT) | VPFE_VDHDEN_ENABLE |
+ VPFE_WEN_ENABLE | VPFE_DATA_PACK_ENABLE);
+
+ /* setup BT.656 sync mode */
+ if (params->bt656_enable) {
+ vpfe_reg_write(ccdc, VPFE_REC656IF_BT656_EN, VPFE_REC656IF);
+
+ /*
+ * configure the FID, VD, HD pin polarity,
+ * fld,hd pol positive, vd negative, 8-bit data
+ */
+ syn_mode |= VPFE_SYN_MODE_VD_POL_NEGATIVE;
+ if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT)
+ syn_mode |= VPFE_SYN_MODE_10BITS;
+ else
+ syn_mode |= VPFE_SYN_MODE_8BITS;
+ } else {
+ /* y/c external sync mode */
+ syn_mode |= (((params->fid_pol & VPFE_FID_POL_MASK) <<
+ VPFE_FID_POL_SHIFT) |
+ ((params->hd_pol & VPFE_HD_POL_MASK) <<
+ VPFE_HD_POL_SHIFT) |
+ ((params->vd_pol & VPFE_VD_POL_MASK) <<
+ VPFE_VD_POL_SHIFT));
+ }
+ vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE);
+
+ /* configure video window */
+ vpfe_ccdc_setwin(ccdc, &params->win,
+ params->frm_fmt, params->bytesperpixel);
+
+ /*
+ * configure the order of y cb cr in SDRAM, and disable latch
+ * internal register on vsync
+ */
+ if (ccdc->ccdc_cfg.if_type == VPFE_BT656_10BIT)
+ vpfe_reg_write(ccdc,
+ (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) |
+ VPFE_LATCH_ON_VSYNC_DISABLE |
+ VPFE_CCDCFG_BW656_10BIT, VPFE_CCDCFG);
+ else
+ vpfe_reg_write(ccdc,
+ (params->pix_order << VPFE_CCDCFG_Y8POS_SHIFT) |
+ VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG);
+
+ /*
+ * configure the horizontal line offset. This should be a
+ * on 32 byte boundary. So clear LSB 5 bits
+ */
+ vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF);
+
+ /* configure the memory line offset */
+ if (params->buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED)
+ /* two fields are interleaved in memory */
+ vpfe_reg_write(ccdc, VPFE_SDOFST_FIELD_INTERLEAVED,
+ VPFE_SDOFST);
+}
+
+static void
+vpfe_ccdc_config_black_clamp(struct vpfe_ccdc *ccdc,
+ struct vpfe_ccdc_black_clamp *bclamp)
+{
+ u32 val;
+
+ if (!bclamp->enable) {
+ /* configure DCSub */
+ val = (bclamp->dc_sub) & VPFE_BLK_DC_SUB_MASK;
+ vpfe_reg_write(ccdc, val, VPFE_DCSUB);
+ vpfe_reg_write(ccdc, VPFE_CLAMP_DEFAULT_VAL, VPFE_CLAMP);
+ return;
+ }
+ /*
+ * Configure gain, Start pixel, No of line to be avg,
+ * No of pixel/line to be avg, & Enable the Black clamping
+ */
+ val = ((bclamp->sgain & VPFE_BLK_SGAIN_MASK) |
+ ((bclamp->start_pixel & VPFE_BLK_ST_PXL_MASK) <<
+ VPFE_BLK_ST_PXL_SHIFT) |
+ ((bclamp->sample_ln & VPFE_BLK_SAMPLE_LINE_MASK) <<
+ VPFE_BLK_SAMPLE_LINE_SHIFT) |
+ ((bclamp->sample_pixel & VPFE_BLK_SAMPLE_LN_MASK) <<
+ VPFE_BLK_SAMPLE_LN_SHIFT) | VPFE_BLK_CLAMP_ENABLE);
+ vpfe_reg_write(ccdc, val, VPFE_CLAMP);
+ /* If Black clamping is enable then make dcsub 0 */
+ vpfe_reg_write(ccdc, VPFE_DCSUB_DEFAULT_VAL, VPFE_DCSUB);
+}
+
+static void
+vpfe_ccdc_config_black_compense(struct vpfe_ccdc *ccdc,
+ struct vpfe_ccdc_black_compensation *bcomp)
+{
+ u32 val;
+
+ val = ((bcomp->b & VPFE_BLK_COMP_MASK) |
+ ((bcomp->gb & VPFE_BLK_COMP_MASK) <<
+ VPFE_BLK_COMP_GB_COMP_SHIFT) |
+ ((bcomp->gr & VPFE_BLK_COMP_MASK) <<
+ VPFE_BLK_COMP_GR_COMP_SHIFT) |
+ ((bcomp->r & VPFE_BLK_COMP_MASK) <<
+ VPFE_BLK_COMP_R_COMP_SHIFT));
+ vpfe_reg_write(ccdc, val, VPFE_BLKCMP);
+}
+
+/*
+ * vpfe_ccdc_config_raw()
+ * This function will configure CCDC for Raw capture mode
+ */
+static void vpfe_ccdc_config_raw(struct vpfe_ccdc *ccdc)
+{
+ struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+ struct vpfe_ccdc_config_params_raw *config_params =
+ &ccdc->ccdc_cfg.bayer.config_params;
+ struct ccdc_params_raw *params = &ccdc->ccdc_cfg.bayer;
+ unsigned int syn_mode;
+ unsigned int val;
+
+ vpfe_dbg(3, vpfe, "vpfe_ccdc_config_raw:\n");
+
+ /* Reset CCDC */
+ vpfe_ccdc_restore_defaults(ccdc);
+
+ /* Disable latching function registers on VSYNC */
+ vpfe_reg_write(ccdc, VPFE_LATCH_ON_VSYNC_DISABLE, VPFE_CCDCFG);
+
+ /*
+ * Configure the vertical sync polarity(SYN_MODE.VDPOL),
+ * horizontal sync polarity (SYN_MODE.HDPOL), frame id polarity
+ * (SYN_MODE.FLDPOL), frame format(progressive or interlace),
+ * data size(SYNMODE.DATSIZ), &pixel format (Input mode), output
+ * SDRAM, enable internal timing generator
+ */
+ syn_mode = (((params->vd_pol & VPFE_VD_POL_MASK) << VPFE_VD_POL_SHIFT) |
+ ((params->hd_pol & VPFE_HD_POL_MASK) << VPFE_HD_POL_SHIFT) |
+ ((params->fid_pol & VPFE_FID_POL_MASK) <<
+ VPFE_FID_POL_SHIFT) | ((params->frm_fmt &
+ VPFE_FRM_FMT_MASK) << VPFE_FRM_FMT_SHIFT) |
+ ((config_params->data_sz & VPFE_DATA_SZ_MASK) <<
+ VPFE_DATA_SZ_SHIFT) | ((params->pix_fmt &
+ VPFE_PIX_FMT_MASK) << VPFE_PIX_FMT_SHIFT) |
+ VPFE_WEN_ENABLE | VPFE_VDHDEN_ENABLE);
+
+ /* Enable and configure aLaw register if needed */
+ if (config_params->alaw.enable) {
+ val = ((config_params->alaw.gamma_wd &
+ VPFE_ALAW_GAMMA_WD_MASK) | VPFE_ALAW_ENABLE);
+ vpfe_reg_write(ccdc, val, VPFE_ALAW);
+ vpfe_dbg(3, vpfe, "\nWriting 0x%x to ALAW...\n", val);
+ }
+
+ /* Configure video window */
+ vpfe_ccdc_setwin(ccdc, &params->win, params->frm_fmt,
+ params->bytesperpixel);
+
+ /* Configure Black Clamp */
+ vpfe_ccdc_config_black_clamp(ccdc, &config_params->blk_clamp);
+
+ /* Configure Black level compensation */
+ vpfe_ccdc_config_black_compense(ccdc, &config_params->blk_comp);
+
+ /* If data size is 8 bit then pack the data */
+ if ((config_params->data_sz == VPFE_CCDC_DATA_8BITS) ||
+ config_params->alaw.enable)
+ syn_mode |= VPFE_DATA_PACK_ENABLE;
+
+ /*
+ * Configure Horizontal offset register. If pack 8 is enabled then
+ * 1 pixel will take 1 byte
+ */
+ vpfe_reg_write(ccdc, params->bytesperline, VPFE_HSIZE_OFF);
+
+ vpfe_dbg(3, vpfe, "Writing %d (%x) to HSIZE_OFF\n",
+ params->bytesperline, params->bytesperline);
+
+ /* Set value for SDOFST */
+ if (params->frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (params->image_invert_enable) {
+ /* For interlace inverse mode */
+ vpfe_reg_write(ccdc, VPFE_INTERLACED_IMAGE_INVERT,
+ VPFE_SDOFST);
+ } else {
+ /* For interlace non inverse mode */
+ vpfe_reg_write(ccdc, VPFE_INTERLACED_NO_IMAGE_INVERT,
+ VPFE_SDOFST);
+ }
+ } else if (params->frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ vpfe_reg_write(ccdc, VPFE_PROGRESSIVE_NO_IMAGE_INVERT,
+ VPFE_SDOFST);
+ }
+
+ vpfe_reg_write(ccdc, syn_mode, VPFE_SYNMODE);
+
+ vpfe_reg_dump(ccdc);
+}
+
+static inline int
+vpfe_ccdc_set_buftype(struct vpfe_ccdc *ccdc,
+ enum ccdc_buftype buf_type)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc->ccdc_cfg.bayer.buf_type = buf_type;
+ else
+ ccdc->ccdc_cfg.ycbcr.buf_type = buf_type;
+
+ return 0;
+}
+
+static inline enum ccdc_buftype vpfe_ccdc_get_buftype(struct vpfe_ccdc *ccdc)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc->ccdc_cfg.bayer.buf_type;
+
+ return ccdc->ccdc_cfg.ycbcr.buf_type;
+}
+
+static int vpfe_ccdc_set_pixel_format(struct vpfe_ccdc *ccdc, u32 pixfmt)
+{
+ struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+
+ vpfe_dbg(1, vpfe, "vpfe_ccdc_set_pixel_format: if_type: %d, pixfmt:%s\n",
+ ccdc->ccdc_cfg.if_type, print_fourcc(pixfmt));
+
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ /*
+ * Need to clear it in case it was left on
+ * after the last capture.
+ */
+ ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 0;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_SBGGR8:
+ ccdc->ccdc_cfg.bayer.config_params.alaw.enable = 1;
+ break;
+
+ case V4L2_PIX_FMT_YUYV:
+ case V4L2_PIX_FMT_UYVY:
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_RGB565X:
+ break;
+
+ case V4L2_PIX_FMT_SBGGR16:
+ default:
+ return -EINVAL;
+ }
+ } else {
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YUYV:
+ ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_YCBYCR;
+ break;
+
+ case V4L2_PIX_FMT_UYVY:
+ ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static u32 vpfe_ccdc_get_pixel_format(struct vpfe_ccdc *ccdc)
+{
+ u32 pixfmt;
+
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ } else {
+ if (ccdc->ccdc_cfg.ycbcr.pix_order == CCDC_PIXORDER_YCBYCR)
+ pixfmt = V4L2_PIX_FMT_YUYV;
+ else
+ pixfmt = V4L2_PIX_FMT_UYVY;
+ }
+
+ return pixfmt;
+}
+
+static int
+vpfe_ccdc_set_image_window(struct vpfe_ccdc *ccdc,
+ struct v4l2_rect *win, unsigned int bpp)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER) {
+ ccdc->ccdc_cfg.bayer.win = *win;
+ ccdc->ccdc_cfg.bayer.bytesperpixel = bpp;
+ ccdc->ccdc_cfg.bayer.bytesperline = ALIGN(win->width * bpp, 32);
+ } else {
+ ccdc->ccdc_cfg.ycbcr.win = *win;
+ ccdc->ccdc_cfg.ycbcr.bytesperpixel = bpp;
+ ccdc->ccdc_cfg.ycbcr.bytesperline = ALIGN(win->width * bpp, 32);
+ }
+
+ return 0;
+}
+
+static inline void
+vpfe_ccdc_get_image_window(struct vpfe_ccdc *ccdc,
+ struct v4l2_rect *win)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ *win = ccdc->ccdc_cfg.bayer.win;
+ else
+ *win = ccdc->ccdc_cfg.ycbcr.win;
+}
+
+static inline unsigned int vpfe_ccdc_get_line_length(struct vpfe_ccdc *ccdc)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc->ccdc_cfg.bayer.bytesperline;
+
+ return ccdc->ccdc_cfg.ycbcr.bytesperline;
+}
+
+static inline int
+vpfe_ccdc_set_frame_format(struct vpfe_ccdc *ccdc,
+ enum ccdc_frmfmt frm_fmt)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ ccdc->ccdc_cfg.bayer.frm_fmt = frm_fmt;
+ else
+ ccdc->ccdc_cfg.ycbcr.frm_fmt = frm_fmt;
+
+ return 0;
+}
+
+static inline enum ccdc_frmfmt
+vpfe_ccdc_get_frame_format(struct vpfe_ccdc *ccdc)
+{
+ if (ccdc->ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ return ccdc->ccdc_cfg.bayer.frm_fmt;
+
+ return ccdc->ccdc_cfg.ycbcr.frm_fmt;
+}
+
+static inline int vpfe_ccdc_getfid(struct vpfe_ccdc *ccdc)
+{
+ return (vpfe_reg_read(ccdc, VPFE_SYNMODE) >> 15) & 1;
+}
+
+static inline void vpfe_set_sdr_addr(struct vpfe_ccdc *ccdc, unsigned long addr)
+{
+ vpfe_reg_write(ccdc, addr & 0xffffffe0, VPFE_SDR_ADDR);
+}
+
+static int vpfe_ccdc_set_hw_if_params(struct vpfe_ccdc *ccdc,
+ struct vpfe_hw_if_param *params)
+{
+ struct vpfe_device *vpfe = container_of(ccdc, struct vpfe_device, ccdc);
+
+ ccdc->ccdc_cfg.if_type = params->if_type;
+
+ switch (params->if_type) {
+ case VPFE_BT656:
+ case VPFE_YCBCR_SYNC_16:
+ case VPFE_YCBCR_SYNC_8:
+ case VPFE_BT656_10BIT:
+ ccdc->ccdc_cfg.ycbcr.vd_pol = params->vdpol;
+ ccdc->ccdc_cfg.ycbcr.hd_pol = params->hdpol;
+ break;
+
+ case VPFE_RAW_BAYER:
+ ccdc->ccdc_cfg.bayer.vd_pol = params->vdpol;
+ ccdc->ccdc_cfg.bayer.hd_pol = params->hdpol;
+ if (params->bus_width == 10)
+ ccdc->ccdc_cfg.bayer.config_params.data_sz =
+ VPFE_CCDC_DATA_10BITS;
+ else
+ ccdc->ccdc_cfg.bayer.config_params.data_sz =
+ VPFE_CCDC_DATA_8BITS;
+ vpfe_dbg(1, vpfe, "params.bus_width: %d\n",
+ params->bus_width);
+ vpfe_dbg(1, vpfe, "config_params.data_sz: %d\n",
+ ccdc->ccdc_cfg.bayer.config_params.data_sz);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static void vpfe_clear_intr(struct vpfe_ccdc *ccdc, int vdint)
+{
+ unsigned int vpfe_int_status;
+
+ vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS);
+
+ switch (vdint) {
+ /* VD0 interrupt */
+ case VPFE_VDINT0:
+ vpfe_int_status &= ~VPFE_VDINT0;
+ vpfe_int_status |= VPFE_VDINT0;
+ break;
+
+ /* VD1 interrupt */
+ case VPFE_VDINT1:
+ vpfe_int_status &= ~VPFE_VDINT1;
+ vpfe_int_status |= VPFE_VDINT1;
+ break;
+
+ /* VD2 interrupt */
+ case VPFE_VDINT2:
+ vpfe_int_status &= ~VPFE_VDINT2;
+ vpfe_int_status |= VPFE_VDINT2;
+ break;
+
+ /* Clear all interrupts */
+ default:
+ vpfe_int_status &= ~(VPFE_VDINT0 |
+ VPFE_VDINT1 |
+ VPFE_VDINT2);
+ vpfe_int_status |= (VPFE_VDINT0 |
+ VPFE_VDINT1 |
+ VPFE_VDINT2);
+ break;
+ }
+ /* Clear specific VDINT from the status register */
+ vpfe_reg_write(ccdc, vpfe_int_status, VPFE_IRQ_STS);
+
+ vpfe_int_status = vpfe_reg_read(ccdc, VPFE_IRQ_STS);
+
+ /* Acknowledge that we are done with all interrupts */
+ vpfe_reg_write(ccdc, 1, VPFE_IRQ_EOI);
+}
+
+static void vpfe_ccdc_config_defaults(struct vpfe_ccdc *ccdc)
+{
+ ccdc->ccdc_cfg.if_type = VPFE_RAW_BAYER;
+
+ ccdc->ccdc_cfg.ycbcr.pix_fmt = CCDC_PIXFMT_YCBCR_8BIT;
+ ccdc->ccdc_cfg.ycbcr.frm_fmt = CCDC_FRMFMT_INTERLACED;
+ ccdc->ccdc_cfg.ycbcr.fid_pol = VPFE_PINPOL_POSITIVE;
+ ccdc->ccdc_cfg.ycbcr.vd_pol = VPFE_PINPOL_POSITIVE;
+ ccdc->ccdc_cfg.ycbcr.hd_pol = VPFE_PINPOL_POSITIVE;
+ ccdc->ccdc_cfg.ycbcr.pix_order = CCDC_PIXORDER_CBYCRY;
+ ccdc->ccdc_cfg.ycbcr.buf_type = CCDC_BUFTYPE_FLD_INTERLEAVED;
+
+ ccdc->ccdc_cfg.ycbcr.win.left = 0;
+ ccdc->ccdc_cfg.ycbcr.win.top = 0;
+ ccdc->ccdc_cfg.ycbcr.win.width = 720;
+ ccdc->ccdc_cfg.ycbcr.win.height = 576;
+ ccdc->ccdc_cfg.ycbcr.bt656_enable = 1;
+
+ ccdc->ccdc_cfg.bayer.pix_fmt = CCDC_PIXFMT_RAW;
+ ccdc->ccdc_cfg.bayer.frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+ ccdc->ccdc_cfg.bayer.fid_pol = VPFE_PINPOL_POSITIVE;
+ ccdc->ccdc_cfg.bayer.vd_pol = VPFE_PINPOL_POSITIVE;
+ ccdc->ccdc_cfg.bayer.hd_pol = VPFE_PINPOL_POSITIVE;
+
+ ccdc->ccdc_cfg.bayer.win.left = 0;
+ ccdc->ccdc_cfg.bayer.win.top = 0;
+ ccdc->ccdc_cfg.bayer.win.width = 800;
+ ccdc->ccdc_cfg.bayer.win.height = 600;
+ ccdc->ccdc_cfg.bayer.config_params.data_sz = VPFE_CCDC_DATA_8BITS;
+ ccdc->ccdc_cfg.bayer.config_params.alaw.gamma_wd =
+ VPFE_CCDC_GAMMA_BITS_09_0;
+}
+
+/*
+ * vpfe_get_ccdc_image_format - Get image parameters based on CCDC settings
+ */
+static int vpfe_get_ccdc_image_format(struct vpfe_device *vpfe,
+ struct v4l2_format *f)
+{
+ struct v4l2_rect image_win;
+ enum ccdc_buftype buf_type;
+ enum ccdc_frmfmt frm_fmt;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win);
+ f->fmt.pix.width = image_win.width;
+ f->fmt.pix.height = image_win.height;
+ f->fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc);
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height;
+ buf_type = vpfe_ccdc_get_buftype(&vpfe->ccdc);
+ f->fmt.pix.pixelformat = vpfe_ccdc_get_pixel_format(&vpfe->ccdc);
+ frm_fmt = vpfe_ccdc_get_frame_format(&vpfe->ccdc);
+
+ if (frm_fmt == CCDC_FRMFMT_PROGRESSIVE) {
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ } else if (frm_fmt == CCDC_FRMFMT_INTERLACED) {
+ if (buf_type == CCDC_BUFTYPE_FLD_INTERLEAVED) {
+ f->fmt.pix.field = V4L2_FIELD_INTERLACED;
+ } else if (buf_type == CCDC_BUFTYPE_FLD_SEPARATED) {
+ f->fmt.pix.field = V4L2_FIELD_SEQ_TB;
+ } else {
+ vpfe_err(vpfe, "Invalid buf_type\n");
+ return -EINVAL;
+ }
+ } else {
+ vpfe_err(vpfe, "Invalid frm_fmt\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe)
+{
+ enum ccdc_frmfmt frm_fmt = CCDC_FRMFMT_INTERLACED;
+ int ret;
+
+ vpfe_dbg(2, vpfe, "vpfe_config_ccdc_image_format\n");
+
+ vpfe_dbg(1, vpfe, "pixelformat: %s\n",
+ print_fourcc(vpfe->fmt.fmt.pix.pixelformat));
+
+ if (vpfe_ccdc_set_pixel_format(&vpfe->ccdc,
+ vpfe->fmt.fmt.pix.pixelformat) < 0) {
+ vpfe_err(vpfe, "couldn't set pix format in ccdc\n");
+ return -EINVAL;
+ }
+
+ /* configure the image window */
+ vpfe_ccdc_set_image_window(&vpfe->ccdc, &vpfe->crop, vpfe->bpp);
+
+ switch (vpfe->fmt.fmt.pix.field) {
+ case V4L2_FIELD_INTERLACED:
+ /* do nothing, since it is default */
+ ret = vpfe_ccdc_set_buftype(
+ &vpfe->ccdc,
+ CCDC_BUFTYPE_FLD_INTERLEAVED);
+ break;
+
+ case V4L2_FIELD_NONE:
+ frm_fmt = CCDC_FRMFMT_PROGRESSIVE;
+ /* buffer type only applicable for interlaced scan */
+ break;
+
+ case V4L2_FIELD_SEQ_TB:
+ ret = vpfe_ccdc_set_buftype(
+ &vpfe->ccdc,
+ CCDC_BUFTYPE_FLD_SEPARATED);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ if (ret)
+ return ret;
+
+ return vpfe_ccdc_set_frame_format(&vpfe->ccdc, frm_fmt);
+}
+
+/*
+ * vpfe_config_image_format()
+ * For a given standard, this functions sets up the default
+ * pix format & crop values in the vpfe device and ccdc. It first
+ * starts with defaults based values from the standard table.
+ * It then checks if sub device support g_mbus_fmt and then override the
+ * values based on that.Sets crop values to match with scan resolution
+ * starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
+ * values in ccdc
+ */
+static int vpfe_config_image_format(struct vpfe_device *vpfe,
+ v4l2_std_id std_id)
+{
+ struct v4l2_pix_format *pix = &vpfe->fmt.fmt.pix;
+ int i, ret;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
+ if (vpfe_standards[i].std_id & std_id) {
+ vpfe->std_info.active_pixels =
+ vpfe_standards[i].width;
+ vpfe->std_info.active_lines =
+ vpfe_standards[i].height;
+ vpfe->std_info.frame_format =
+ vpfe_standards[i].frame_format;
+ vpfe->std_index = i;
+
+ break;
+ }
+ }
+
+ if (i == ARRAY_SIZE(vpfe_standards)) {
+ vpfe_err(vpfe, "standard not supported\n");
+ return -EINVAL;
+ }
+
+ vpfe->crop.top = vpfe->crop.left = 0;
+ vpfe->crop.width = vpfe->std_info.active_pixels;
+ vpfe->crop.height = vpfe->std_info.active_lines;
+ pix->width = vpfe->crop.width;
+ pix->height = vpfe->crop.height;
+ pix->pixelformat = V4L2_PIX_FMT_YUYV;
+
+ /* first field and frame format based on standard frame format */
+ if (vpfe->std_info.frame_format)
+ pix->field = V4L2_FIELD_INTERLACED;
+ else
+ pix->field = V4L2_FIELD_NONE;
+
+ ret = __vpfe_get_format(vpfe, &vpfe->fmt, &vpfe->bpp);
+ if (ret)
+ return ret;
+
+ /* Update the crop window based on found values */
+ vpfe->crop.width = pix->width;
+ vpfe->crop.height = pix->height;
+
+ return vpfe_config_ccdc_image_format(vpfe);
+}
+
+static int vpfe_initialize_device(struct vpfe_device *vpfe)
+{
+ struct vpfe_subdev_info *sdinfo;
+ int ret;
+
+ sdinfo = &vpfe->cfg->sub_devs[0];
+ sdinfo->sd = vpfe->sd[0];
+ vpfe->current_input = 0;
+ vpfe->std_index = 0;
+ /* Configure the default format information */
+ ret = vpfe_config_image_format(vpfe,
+ vpfe_standards[vpfe->std_index].std_id);
+ if (ret)
+ return ret;
+
+ pm_runtime_get_sync(vpfe->pdev);
+
+ vpfe_config_enable(&vpfe->ccdc, 1);
+
+ vpfe_ccdc_restore_defaults(&vpfe->ccdc);
+
+ /* Clear all VPFE interrupts */
+ vpfe_clear_intr(&vpfe->ccdc, -1);
+
+ return ret;
+}
+
+/*
+ * vpfe_release : This function is based on the vb2_fop_release
+ * helper function.
+ * It has been augmented to handle module power management,
+ * by disabling/enabling h/w module fcntl clock when necessary.
+ */
+static int vpfe_release(struct file *file)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ int ret;
+
+ mutex_lock(&vpfe->lock);
+
+ if (v4l2_fh_is_singular_file(file))
+ vpfe_ccdc_close(&vpfe->ccdc, vpfe->pdev);
+ ret = _vb2_fop_release(file, NULL);
+
+ mutex_unlock(&vpfe->lock);
+
+ return ret;
+}
+
+/*
+ * vpfe_open : This function is based on the v4l2_fh_open helper function.
+ * It has been augmented to handle module power management,
+ * by disabling/enabling h/w module fcntl clock when necessary.
+ */
+static int vpfe_open(struct file *file)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ int ret;
+
+ mutex_lock(&vpfe->lock);
+
+ ret = v4l2_fh_open(file);
+ if (ret) {
+ vpfe_err(vpfe, "v4l2_fh_open failed\n");
+ goto unlock;
+ }
+
+ if (!v4l2_fh_is_singular_file(file))
+ goto unlock;
+
+ if (vpfe_initialize_device(vpfe)) {
+ v4l2_fh_release(file);
+ ret = -ENODEV;
+ }
+
+unlock:
+ mutex_unlock(&vpfe->lock);
+ return ret;
+}
+
+/**
+ * vpfe_schedule_next_buffer: set next buffer address for capture
+ * @vpfe : ptr to vpfe device
+ *
+ * This function will get next buffer from the dma queue and
+ * set the buffer address in the vpfe register for capture.
+ * the buffer is marked active
+ *
+ * Assumes caller is holding vpfe->dma_queue_lock already
+ */
+static inline void vpfe_schedule_next_buffer(struct vpfe_device *vpfe)
+{
+ vpfe->next_frm = list_entry(vpfe->dma_queue.next,
+ struct vpfe_cap_buffer, list);
+ list_del(&vpfe->next_frm->list);
+
+ vpfe_set_sdr_addr(&vpfe->ccdc,
+ vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0));
+}
+
+static inline void vpfe_schedule_bottom_field(struct vpfe_device *vpfe)
+{
+ unsigned long addr;
+
+ addr = vb2_dma_contig_plane_dma_addr(&vpfe->next_frm->vb, 0) +
+ vpfe->field_off;
+
+ vpfe_set_sdr_addr(&vpfe->ccdc, addr);
+}
+
+/*
+ * vpfe_process_buffer_complete: process a completed buffer
+ * @vpfe : ptr to vpfe device
+ *
+ * This function time stamp the buffer and mark it as DONE. It also
+ * wake up any process waiting on the QUEUE and set the next buffer
+ * as current
+ */
+static inline void vpfe_process_buffer_complete(struct vpfe_device *vpfe)
+{
+ v4l2_get_timestamp(&vpfe->cur_frm->vb.v4l2_buf.timestamp);
+ vpfe->cur_frm->vb.v4l2_buf.field = vpfe->fmt.fmt.pix.field;
+ vpfe->cur_frm->vb.v4l2_buf.sequence = vpfe->sequence++;
+ vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_DONE);
+ vpfe->cur_frm = vpfe->next_frm;
+}
+
+/*
+ * vpfe_isr : ISR handler for vpfe capture (VINT0)
+ * @irq: irq number
+ * @dev_id: dev_id ptr
+ *
+ * It changes status of the captured buffer, takes next buffer from the queue
+ * and sets its address in VPFE registers
+ */
+static irqreturn_t vpfe_isr(int irq, void *dev)
+{
+ struct vpfe_device *vpfe = (struct vpfe_device *)dev;
+ enum v4l2_field field;
+ int intr_status;
+ int fid;
+
+ intr_status = vpfe_reg_read(&vpfe->ccdc, VPFE_IRQ_STS);
+
+ if (intr_status & VPFE_VDINT0) {
+ field = vpfe->fmt.fmt.pix.field;
+
+ if (field == V4L2_FIELD_NONE) {
+ /* handle progressive frame capture */
+ if (vpfe->cur_frm != vpfe->next_frm)
+ vpfe_process_buffer_complete(vpfe);
+ goto next_intr;
+ }
+
+ /* interlaced or TB capture check which field
+ we are in hardware */
+ fid = vpfe_ccdc_getfid(&vpfe->ccdc);
+
+ /* switch the software maintained field id */
+ vpfe->field ^= 1;
+ if (fid == vpfe->field) {
+ /* we are in-sync here,continue */
+ if (fid == 0) {
+ /*
+ * One frame is just being captured. If the
+ * next frame is available, release the
+ * current frame and move on
+ */
+ if (vpfe->cur_frm != vpfe->next_frm)
+ vpfe_process_buffer_complete(vpfe);
+ /*
+ * based on whether the two fields are stored
+ * interleave or separately in memory,
+ * reconfigure the CCDC memory address
+ */
+ if (field == V4L2_FIELD_SEQ_TB)
+ vpfe_schedule_bottom_field(vpfe);
+
+ goto next_intr;
+ }
+ /*
+ * if one field is just being captured configure
+ * the next frame get the next frame from the empty
+ * queue if no frame is available hold on to the
+ * current buffer
+ */
+ spin_lock(&vpfe->dma_queue_lock);
+ if (!list_empty(&vpfe->dma_queue) &&
+ vpfe->cur_frm == vpfe->next_frm)
+ vpfe_schedule_next_buffer(vpfe);
+ spin_unlock(&vpfe->dma_queue_lock);
+ } else if (fid == 0) {
+ /*
+ * out of sync. Recover from any hardware out-of-sync.
+ * May loose one frame
+ */
+ vpfe->field = fid;
+ }
+ }
+
+next_intr:
+ if (intr_status & VPFE_VDINT1) {
+ spin_lock(&vpfe->dma_queue_lock);
+ if (vpfe->fmt.fmt.pix.field == V4L2_FIELD_NONE &&
+ !list_empty(&vpfe->dma_queue) &&
+ vpfe->cur_frm == vpfe->next_frm)
+ vpfe_schedule_next_buffer(vpfe);
+ spin_unlock(&vpfe->dma_queue_lock);
+ }
+
+ vpfe_clear_intr(&vpfe->ccdc, intr_status);
+
+ return IRQ_HANDLED;
+}
+
+static inline void vpfe_detach_irq(struct vpfe_device *vpfe)
+{
+ unsigned int intr = VPFE_VDINT0;
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc);
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
+ intr |= VPFE_VDINT1;
+
+ vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_CLR);
+}
+
+static inline void vpfe_attach_irq(struct vpfe_device *vpfe)
+{
+ unsigned int intr = VPFE_VDINT0;
+ enum ccdc_frmfmt frame_format;
+
+ frame_format = vpfe_ccdc_get_frame_format(&vpfe->ccdc);
+ if (frame_format == CCDC_FRMFMT_PROGRESSIVE)
+ intr |= VPFE_VDINT1;
+
+ vpfe_reg_write(&vpfe->ccdc, intr, VPFE_IRQ_EN_SET);
+}
+
+static int vpfe_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+
+ vpfe_dbg(2, vpfe, "vpfe_querycap\n");
+
+ strlcpy(cap->driver, VPFE_MODULE_NAME, sizeof(cap->driver));
+ strlcpy(cap->card, "TI AM437x VPFE", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info),
+ "platform:%s", vpfe->v4l2_dev.name);
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
+
+ return 0;
+}
+
+/* get the format set at output pad of the adjacent subdev */
+static int __vpfe_get_format(struct vpfe_device *vpfe,
+ struct v4l2_format *format, unsigned int *bpp)
+{
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct vpfe_subdev_info *sdinfo;
+ struct v4l2_subdev_format fmt;
+ int ret;
+
+ sdinfo = vpfe->current_subdev;
+ if (!sdinfo->sd)
+ return -EINVAL;
+
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.pad = 0;
+
+ ret = v4l2_subdev_call(sdinfo->sd, pad, get_fmt, NULL, &fmt);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+
+ if (!ret) {
+ v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
+ mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp);
+ } else {
+ ret = v4l2_device_call_until_err(&vpfe->v4l2_dev,
+ sdinfo->grp_id,
+ video, g_mbus_fmt,
+ &mbus_fmt);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+ v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt);
+ mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp);
+ }
+
+ format->type = vpfe->fmt.type;
+
+ vpfe_dbg(1, vpfe,
+ "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n",
+ __func__, format->fmt.pix.width, format->fmt.pix.height,
+ print_fourcc(format->fmt.pix.pixelformat),
+ format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp);
+
+ return 0;
+}
+
+/* set the format at output pad of the adjacent subdev */
+static int __vpfe_set_format(struct vpfe_device *vpfe,
+ struct v4l2_format *format, unsigned int *bpp)
+{
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct vpfe_subdev_info *sdinfo;
+ struct v4l2_subdev_format fmt;
+ int ret;
+
+ vpfe_dbg(2, vpfe, "__vpfe_set_format\n");
+
+ sdinfo = vpfe->current_subdev;
+ if (!sdinfo->sd)
+ return -EINVAL;
+
+ fmt.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+ fmt.pad = 0;
+
+ pix_to_mbus(vpfe, &format->fmt.pix, &fmt.format);
+
+ ret = v4l2_subdev_call(sdinfo->sd, pad, set_fmt, NULL, &fmt);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+
+ if (!ret) {
+ v4l2_fill_pix_format(&format->fmt.pix, &fmt.format);
+ mbus_to_pix(vpfe, &fmt.format, &format->fmt.pix, bpp);
+ } else {
+ ret = v4l2_device_call_until_err(&vpfe->v4l2_dev,
+ sdinfo->grp_id,
+ video, s_mbus_fmt,
+ &mbus_fmt);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ return ret;
+
+ v4l2_fill_pix_format(&format->fmt.pix, &mbus_fmt);
+ mbus_to_pix(vpfe, &mbus_fmt, &format->fmt.pix, bpp);
+ }
+
+ format->type = vpfe->fmt.type;
+
+ vpfe_dbg(1, vpfe,
+ "%s size %dx%d (%s) bytesperline = %d, size = %d, bpp = %d\n",
+ __func__, format->fmt.pix.width, format->fmt.pix.height,
+ print_fourcc(format->fmt.pix.pixelformat),
+ format->fmt.pix.bytesperline, format->fmt.pix.sizeimage, *bpp);
+
+ return 0;
+}
+
+static int vpfe_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+
+ vpfe_dbg(2, vpfe, "vpfe_g_fmt\n");
+
+ *fmt = vpfe->fmt;
+
+ return 0;
+}
+
+static int vpfe_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ struct vpfe_fmt *fmt = NULL;
+ unsigned int k;
+
+ vpfe_dbg(2, vpfe, "vpfe_enum_format index:%d\n",
+ f->index);
+
+ sdinfo = vpfe->current_subdev;
+ if (!sdinfo->sd)
+ return -EINVAL;
+
+ if (f->index > ARRAY_SIZE(formats))
+ return -EINVAL;
+
+ for (k = 0; k < ARRAY_SIZE(formats); k++) {
+ if (formats[k].index == f->index) {
+ fmt = &formats[k];
+ break;
+ }
+ }
+ if (!fmt)
+ return -EINVAL;
+
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->fourcc;
+ f->type = vpfe->fmt.type;
+
+ vpfe_dbg(1, vpfe, "vpfe_enum_format: mbus index: %d code: %x pixelformat: %s [%s]\n",
+ f->index, fmt->code, print_fourcc(fmt->fourcc), fmt->name);
+
+ return 0;
+}
+
+static int vpfe_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ unsigned int bpp;
+
+ vpfe_dbg(2, vpfe, "vpfe_try_fmt\n");
+
+ return __vpfe_get_format(vpfe, fmt, &bpp);
+}
+
+static int vpfe_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct v4l2_format format;
+ unsigned int bpp;
+ int ret;
+
+ vpfe_dbg(2, vpfe, "vpfe_s_fmt\n");
+
+ /* If streaming is started, return error */
+ if (vb2_is_busy(&vpfe->buffer_queue)) {
+ vpfe_err(vpfe, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ ret = vpfe_try_fmt(file, priv, fmt);
+ if (ret)
+ return ret;
+
+
+ if (!cmp_v4l2_format(fmt, &format)) {
+ /* Sensor format is different from the requested format
+ * so we need to change it
+ */
+ ret = __vpfe_set_format(vpfe, fmt, &bpp);
+ if (ret)
+ return ret;
+ } else /* Just make sure all of the fields are consistent */
+ *fmt = format;
+
+ /* First detach any IRQ if currently attached */
+ vpfe_detach_irq(vpfe);
+ vpfe->fmt = *fmt;
+ vpfe->bpp = bpp;
+
+ /* Update the crop window based on found values */
+ vpfe->crop.width = fmt->fmt.pix.width;
+ vpfe->crop.height = fmt->fmt.pix.height;
+
+ /* set image capture parameters in the ccdc */
+ return vpfe_config_ccdc_image_format(vpfe);
+}
+
+static int vpfe_enum_size(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct v4l2_subdev_frame_size_enum fse;
+ struct vpfe_subdev_info *sdinfo;
+ struct v4l2_mbus_framefmt mbus;
+ struct v4l2_pix_format pix;
+ struct vpfe_fmt *fmt;
+ int ret;
+
+ vpfe_dbg(2, vpfe, "vpfe_enum_size\n");
+
+ /* check for valid format */
+ fmt = find_format_by_pix(fsize->pixel_format);
+ if (!fmt) {
+ vpfe_dbg(3, vpfe, "Invalid pixel code: %x, default used instead\n",
+ fsize->pixel_format);
+ return -EINVAL;
+ }
+
+ memset(fsize->reserved, 0x0, sizeof(fsize->reserved));
+
+ sdinfo = vpfe->current_subdev;
+ if (!sdinfo->sd)
+ return -EINVAL;
+
+ memset(&pix, 0x0, sizeof(pix));
+ /* Construct pix from parameter and use default for the rest */
+ pix.pixelformat = fsize->pixel_format;
+ pix.width = 640;
+ pix.height = 480;
+ pix.colorspace = V4L2_COLORSPACE_SRGB;
+ pix.field = V4L2_FIELD_NONE;
+ pix_to_mbus(vpfe, &pix, &mbus);
+
+ memset(&fse, 0x0, sizeof(fse));
+ fse.index = fsize->index;
+ fse.pad = 0;
+ fse.code = mbus.code;
+ ret = v4l2_subdev_call(sdinfo->sd, pad, enum_frame_size, NULL, &fse);
+ if (ret)
+ return -EINVAL;
+
+ vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d code: %x W:[%d,%d] H:[%d,%d]\n",
+ fse.index, fse.code, fse.min_width, fse.max_width,
+ fse.min_height, fse.max_height);
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = fse.max_width;
+ fsize->discrete.height = fse.max_height;
+
+ vpfe_dbg(1, vpfe, "vpfe_enum_size: index: %d pixformat: %s size: %dx%d\n",
+ fsize->index, print_fourcc(fsize->pixel_format),
+ fsize->discrete.width, fsize->discrete.height);
+
+ return 0;
+}
+
+/*
+ * vpfe_get_subdev_input_index - Get subdev index and subdev input index for a
+ * given app input index
+ */
+static int
+vpfe_get_subdev_input_index(struct vpfe_device *vpfe,
+ int *subdev_index,
+ int *subdev_input_index,
+ int app_input_index)
+{
+ struct vpfe_config *cfg = vpfe->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (app_input_index < (j + 1)) {
+ *subdev_index = i;
+ *subdev_input_index = app_input_index - j;
+ return 0;
+ }
+ j++;
+ }
+ return -EINVAL;
+}
+
+/*
+ * vpfe_get_app_input - Get app input index for a given subdev input index
+ * driver stores the input index of the current sub device and translate it
+ * when application request the current input
+ */
+static int vpfe_get_app_input_index(struct vpfe_device *vpfe,
+ int *app_input_index)
+{
+ struct vpfe_config *cfg = vpfe->cfg;
+ struct vpfe_subdev_info *sdinfo;
+ int i, j = 0;
+
+ for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) {
+ sdinfo = &cfg->sub_devs[i];
+ if (!strcmp(sdinfo->name, vpfe->current_subdev->name)) {
+ if (vpfe->current_input >= 1)
+ return -1;
+ *app_input_index = j + vpfe->current_input;
+ return 0;
+ }
+ j++;
+ }
+ return -EINVAL;
+}
+
+static int vpfe_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int subdev, index;
+
+ vpfe_dbg(2, vpfe, "vpfe_enum_input\n");
+
+ if (vpfe_get_subdev_input_index(vpfe, &subdev, &index,
+ inp->index) < 0) {
+ vpfe_dbg(1, vpfe,
+ "input information not found for the subdev\n");
+ return -EINVAL;
+ }
+ sdinfo = &vpfe->cfg->sub_devs[subdev];
+ *inp = sdinfo->inputs[index];
+
+ return 0;
+}
+
+static int vpfe_g_input(struct file *file, void *priv, unsigned int *index)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+
+ vpfe_dbg(2, vpfe, "vpfe_g_input\n");
+
+ return vpfe_get_app_input_index(vpfe, index);
+}
+
+/* Assumes caller is holding vpfe_dev->lock */
+static int vpfe_set_input(struct vpfe_device *vpfe, unsigned int index)
+{
+ int subdev_index = 0, inp_index = 0;
+ struct vpfe_subdev_info *sdinfo;
+ struct vpfe_route *route;
+ u32 input, output;
+ int ret;
+
+ vpfe_dbg(2, vpfe, "vpfe_set_input: index: %d\n", index);
+
+ /* If streaming is started, return error */
+ if (vb2_is_busy(&vpfe->buffer_queue)) {
+ vpfe_err(vpfe, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+ ret = vpfe_get_subdev_input_index(vpfe,
+ &subdev_index,
+ &inp_index,
+ index);
+ if (ret < 0) {
+ vpfe_err(vpfe, "invalid input index: %d\n", index);
+ goto get_out;
+ }
+
+ sdinfo = &vpfe->cfg->sub_devs[subdev_index];
+ sdinfo->sd = vpfe->sd[subdev_index];
+ route = &sdinfo->routes[inp_index];
+ if (route && sdinfo->can_route) {
+ input = route->input;
+ output = route->output;
+ if (sdinfo->sd) {
+ ret = v4l2_subdev_call(sdinfo->sd, video,
+ s_routing, input, output, 0);
+ if (ret) {
+ vpfe_err(vpfe, "s_routing failed\n");
+ ret = -EINVAL;
+ goto get_out;
+ }
+ }
+
+ }
+
+ vpfe->current_subdev = sdinfo;
+ if (sdinfo->sd)
+ vpfe->v4l2_dev.ctrl_handler = sdinfo->sd->ctrl_handler;
+ vpfe->current_input = index;
+ vpfe->std_index = 0;
+
+ /* set the bus/interface parameter for the sub device in ccdc */
+ ret = vpfe_ccdc_set_hw_if_params(&vpfe->ccdc, &sdinfo->vpfe_param);
+ if (ret)
+ return ret;
+
+ /* set the default image parameters in the device */
+ return vpfe_config_image_format(vpfe,
+ vpfe_standards[vpfe->std_index].std_id);
+
+get_out:
+ return ret;
+}
+
+static int vpfe_s_input(struct file *file, void *priv, unsigned int index)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+
+ vpfe_dbg(2, vpfe,
+ "vpfe_s_input: index: %d\n", index);
+
+ return vpfe_set_input(vpfe, index);
+}
+
+static int vpfe_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+
+ vpfe_dbg(2, vpfe, "vpfe_querystd\n");
+
+ sdinfo = vpfe->current_subdev;
+ if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD))
+ return -ENODATA;
+
+ /* Call querystd function of decoder device */
+ return v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id,
+ video, querystd, std_id);
+}
+
+static int vpfe_s_std(struct file *file, void *priv, v4l2_std_id std_id)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+ int ret;
+
+ vpfe_dbg(2, vpfe, "vpfe_s_std\n");
+
+ sdinfo = vpfe->current_subdev;
+ if (!(sdinfo->inputs[0].capabilities & V4L2_IN_CAP_STD))
+ return -ENODATA;
+
+ /* If streaming is started, return error */
+ if (vb2_is_busy(&vpfe->buffer_queue)) {
+ vpfe_err(vpfe, "%s device busy\n", __func__);
+ ret = -EBUSY;
+ return ret;
+ }
+
+ ret = v4l2_device_call_until_err(&vpfe->v4l2_dev, sdinfo->grp_id,
+ video, s_std, std_id);
+ if (ret < 0) {
+ vpfe_err(vpfe, "Failed to set standard\n");
+ return ret;
+ }
+ ret = vpfe_config_image_format(vpfe, std_id);
+
+ return ret;
+}
+
+static int vpfe_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct vpfe_subdev_info *sdinfo;
+
+ vpfe_dbg(2, vpfe, "vpfe_g_std\n");
+
+ sdinfo = vpfe->current_subdev;
+ if (sdinfo->inputs[0].capabilities != V4L2_IN_CAP_STD)
+ return -ENODATA;
+
+ *std_id = vpfe_standards[vpfe->std_index].std_id;
+
+ return 0;
+}
+
+/*
+ * vpfe_calculate_offsets : This function calculates buffers offset
+ * for top and bottom field
+ */
+static void vpfe_calculate_offsets(struct vpfe_device *vpfe)
+{
+ struct v4l2_rect image_win;
+
+ vpfe_dbg(2, vpfe, "vpfe_calculate_offsets\n");
+
+ vpfe_ccdc_get_image_window(&vpfe->ccdc, &image_win);
+ vpfe->field_off = image_win.height * image_win.width;
+}
+
+/*
+ * vpfe_queue_setup - Callback function for buffer setup.
+ * @vq: vb2_queue ptr
+ * @fmt: v4l2 format
+ * @nbuffers: ptr to number of buffers requested by application
+ * @nplanes:: contains number of distinct video planes needed to hold a frame
+ * @sizes[]: contains the size (in bytes) of each plane.
+ * @alloc_ctxs: ptr to allocation context
+ *
+ * This callback function is called when reqbuf() is called to adjust
+ * the buffer count and buffer size
+ */
+static int vpfe_queue_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
+{
+ struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
+
+ if (fmt && fmt->fmt.pix.sizeimage < vpfe->fmt.fmt.pix.sizeimage)
+ return -EINVAL;
+
+ if (vq->num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->num_buffers;
+
+ *nplanes = 1;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : vpfe->fmt.fmt.pix.sizeimage;
+ alloc_ctxs[0] = vpfe->alloc_ctx;
+
+ vpfe_dbg(1, vpfe,
+ "nbuffers=%d, size=%u\n", *nbuffers, sizes[0]);
+
+ /* Calculate field offset */
+ vpfe_calculate_offsets(vpfe);
+
+ return 0;
+}
+
+/*
+ * vpfe_buffer_prepare : callback function for buffer prepare
+ * @vb: ptr to vb2_buffer
+ *
+ * This is the callback function for buffer prepare when vb2_qbuf()
+ * function is called. The buffer is prepared and user space virtual address
+ * or user address is converted into physical address
+ */
+static int vpfe_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue);
+
+ vb2_set_plane_payload(vb, 0, vpfe->fmt.fmt.pix.sizeimage);
+
+ if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+ return -EINVAL;
+
+ vb->v4l2_buf.field = vpfe->fmt.fmt.pix.field;
+
+ return 0;
+}
+
+/*
+ * vpfe_buffer_queue : Callback function to add buffer to DMA queue
+ * @vb: ptr to vb2_buffer
+ */
+static void vpfe_buffer_queue(struct vb2_buffer *vb)
+{
+ struct vpfe_device *vpfe = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpfe_cap_buffer *buf = to_vpfe_buffer(vb);
+ unsigned long flags = 0;
+
+ /* add the buffer to the DMA queue */
+ spin_lock_irqsave(&vpfe->dma_queue_lock, flags);
+ list_add_tail(&buf->list, &vpfe->dma_queue);
+ spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
+}
+
+/*
+ * vpfe_start_streaming : Starts the DMA engine for streaming
+ * @vb: ptr to vb2_buffer
+ * @count: number of buffers
+ */
+static int vpfe_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
+ struct vpfe_cap_buffer *buf, *tmp;
+ struct vpfe_subdev_info *sdinfo;
+ unsigned long flags;
+ unsigned long addr;
+ int ret;
+
+ spin_lock_irqsave(&vpfe->dma_queue_lock, flags);
+
+ vpfe->field = 0;
+ vpfe->sequence = 0;
+
+ sdinfo = vpfe->current_subdev;
+
+ vpfe_attach_irq(vpfe);
+
+ if (vpfe->ccdc.ccdc_cfg.if_type == VPFE_RAW_BAYER)
+ vpfe_ccdc_config_raw(&vpfe->ccdc);
+ else
+ vpfe_ccdc_config_ycbcr(&vpfe->ccdc);
+
+ /* Get the next frame from the buffer queue */
+ vpfe->next_frm = list_entry(vpfe->dma_queue.next,
+ struct vpfe_cap_buffer, list);
+ vpfe->cur_frm = vpfe->next_frm;
+ /* Remove buffer from the buffer queue */
+ list_del(&vpfe->cur_frm->list);
+ spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
+
+ addr = vb2_dma_contig_plane_dma_addr(&vpfe->cur_frm->vb, 0);
+
+ vpfe_set_sdr_addr(&vpfe->ccdc, (unsigned long)(addr));
+
+ vpfe_pcr_enable(&vpfe->ccdc, 1);
+
+ ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 1);
+ if (ret < 0) {
+ vpfe_err(vpfe, "Error in attaching interrupt handle\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ list_for_each_entry_safe(buf, tmp, &vpfe->dma_queue, list) {
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+
+ return ret;
+}
+
+/*
+ * vpfe_stop_streaming : Stop the DMA engine
+ * @vq: ptr to vb2_queue
+ *
+ * This callback stops the DMA engine and any remaining buffers
+ * in the DMA queue are released.
+ */
+static void vpfe_stop_streaming(struct vb2_queue *vq)
+{
+ struct vpfe_device *vpfe = vb2_get_drv_priv(vq);
+ struct vpfe_subdev_info *sdinfo;
+ unsigned long flags;
+ int ret;
+
+ vpfe_pcr_enable(&vpfe->ccdc, 0);
+
+ vpfe_detach_irq(vpfe);
+
+ sdinfo = vpfe->current_subdev;
+ ret = v4l2_subdev_call(sdinfo->sd, video, s_stream, 0);
+ if (ret && ret != -ENOIOCTLCMD && ret != -ENODEV)
+ vpfe_dbg(1, vpfe, "stream off failed in subdev\n");
+
+ /* release all active buffers */
+ spin_lock_irqsave(&vpfe->dma_queue_lock, flags);
+ if (vpfe->cur_frm == vpfe->next_frm) {
+ vb2_buffer_done(&vpfe->cur_frm->vb, VB2_BUF_STATE_ERROR);
+ } else {
+ if (vpfe->cur_frm != NULL)
+ vb2_buffer_done(&vpfe->cur_frm->vb,
+ VB2_BUF_STATE_ERROR);
+ if (vpfe->next_frm != NULL)
+ vb2_buffer_done(&vpfe->next_frm->vb,
+ VB2_BUF_STATE_ERROR);
+ }
+
+ while (!list_empty(&vpfe->dma_queue)) {
+ vpfe->next_frm = list_entry(vpfe->dma_queue.next,
+ struct vpfe_cap_buffer, list);
+ list_del(&vpfe->next_frm->list);
+ vb2_buffer_done(&vpfe->next_frm->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&vpfe->dma_queue_lock, flags);
+}
+
+static int vpfe_cropcap(struct file *file, void *priv,
+ struct v4l2_cropcap *crop)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+
+ vpfe_dbg(2, vpfe, "vpfe_cropcap\n");
+
+ if (vpfe->std_index >= ARRAY_SIZE(vpfe_standards))
+ return -EINVAL;
+
+ memset(crop, 0, sizeof(struct v4l2_cropcap));
+
+ crop->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ crop->defrect.width = vpfe_standards[vpfe->std_index].width;
+ crop->bounds.width = crop->defrect.width;
+ crop->defrect.height = vpfe_standards[vpfe->std_index].height;
+ crop->bounds.height = crop->defrect.height;
+ crop->pixelaspect = vpfe_standards[vpfe->std_index].pixelaspect;
+
+ return 0;
+}
+
+static int
+vpfe_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ s->r.left = s->r.top = 0;
+ s->r.width = vpfe->crop.width;
+ s->r.height = vpfe->crop.height;
+ break;
+
+ case V4L2_SEL_TGT_CROP:
+ s->r = vpfe->crop;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int enclosed_rectangle(struct v4l2_rect *a, struct v4l2_rect *b)
+{
+ if (a->left < b->left || a->top < b->top)
+ return 0;
+
+ if (a->left + a->width > b->left + b->width)
+ return 0;
+
+ if (a->top + a->height > b->top + b->height)
+ return 0;
+
+ return 1;
+}
+
+static int
+vpfe_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ struct v4l2_rect cr = vpfe->crop;
+ struct v4l2_rect r = s->r;
+
+ /* If streaming is started, return error */
+ if (vb2_is_busy(&vpfe->buffer_queue)) {
+ vpfe_err(vpfe, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
+ s->target != V4L2_SEL_TGT_CROP)
+ return -EINVAL;
+
+ v4l_bound_align_image(&r.width, 0, cr.width, 0,
+ &r.height, 0, cr.height, 0, 0);
+
+ r.left = clamp_t(unsigned int, r.left, 0, cr.width - r.width);
+ r.top = clamp_t(unsigned int, r.top, 0, cr.height - r.height);
+
+ if (s->flags & V4L2_SEL_FLAG_LE && !enclosed_rectangle(&r, &s->r))
+ return -ERANGE;
+
+ if (s->flags & V4L2_SEL_FLAG_GE && !enclosed_rectangle(&s->r, &r))
+ return -ERANGE;
+
+ s->r = vpfe->crop = r;
+
+ vpfe_ccdc_set_image_window(&vpfe->ccdc, &r, vpfe->bpp);
+ vpfe->fmt.fmt.pix.width = r.width;
+ vpfe->fmt.fmt.pix.height = r.height;
+ vpfe->fmt.fmt.pix.bytesperline = vpfe_ccdc_get_line_length(&vpfe->ccdc);
+ vpfe->fmt.fmt.pix.sizeimage = vpfe->fmt.fmt.pix.bytesperline *
+ vpfe->fmt.fmt.pix.height;
+
+ vpfe_dbg(1, vpfe, "cropped (%d,%d)/%dx%d of %dx%d\n",
+ r.left, r.top, r.width, r.height, cr.width, cr.height);
+
+ return 0;
+}
+
+static long vpfe_ioctl_default(struct file *file, void *priv,
+ bool valid_prio, unsigned int cmd, void *param)
+{
+ struct vpfe_device *vpfe = video_drvdata(file);
+ int ret;
+
+ vpfe_dbg(2, vpfe, "vpfe_ioctl_default\n");
+
+ if (!valid_prio) {
+ vpfe_err(vpfe, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ /* If streaming is started, return error */
+ if (vb2_is_busy(&vpfe->buffer_queue)) {
+ vpfe_err(vpfe, "%s device busy\n", __func__);
+ return -EBUSY;
+ }
+
+ switch (cmd) {
+ case VIDIOC_AM437X_CCDC_CFG:
+ ret = vpfe_ccdc_set_params(&vpfe->ccdc, (void __user *)param);
+ if (ret) {
+ vpfe_dbg(2, vpfe,
+ "Error setting parameters in CCDC\n");
+ return ret;
+ }
+ ret = vpfe_get_ccdc_image_format(vpfe,
+ &vpfe->fmt);
+ if (ret < 0) {
+ vpfe_dbg(2, vpfe,
+ "Invalid image format at CCDC\n");
+ return ret;
+ }
+ break;
+
+ default:
+ ret = -ENOTTY;
+ break;
+ }
+
+ return ret;
+}
+
+static const struct vb2_ops vpfe_video_qops = {
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .queue_setup = vpfe_queue_setup,
+ .buf_prepare = vpfe_buffer_prepare,
+ .buf_queue = vpfe_buffer_queue,
+ .start_streaming = vpfe_start_streaming,
+ .stop_streaming = vpfe_stop_streaming,
+};
+
+/* vpfe capture driver file operations */
+static const struct v4l2_file_operations vpfe_fops = {
+ .owner = THIS_MODULE,
+ .open = vpfe_open,
+ .release = vpfe_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap,
+};
+
+/* vpfe capture ioctl operations */
+static const struct v4l2_ioctl_ops vpfe_ioctl_ops = {
+ .vidioc_querycap = vpfe_querycap,
+ .vidioc_enum_fmt_vid_cap = vpfe_enum_fmt,
+ .vidioc_g_fmt_vid_cap = vpfe_g_fmt,
+ .vidioc_s_fmt_vid_cap = vpfe_s_fmt,
+ .vidioc_try_fmt_vid_cap = vpfe_try_fmt,
+
+ .vidioc_enum_framesizes = vpfe_enum_size,
+
+ .vidioc_enum_input = vpfe_enum_input,
+ .vidioc_g_input = vpfe_g_input,
+ .vidioc_s_input = vpfe_s_input,
+
+ .vidioc_querystd = vpfe_querystd,
+ .vidioc_s_std = vpfe_s_std,
+ .vidioc_g_std = vpfe_g_std,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_log_status = v4l2_ctrl_log_status,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+
+ .vidioc_cropcap = vpfe_cropcap,
+ .vidioc_g_selection = vpfe_g_selection,
+ .vidioc_s_selection = vpfe_s_selection,
+
+ .vidioc_default = vpfe_ioctl_default,
+};
+
+static int
+vpfe_async_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_subdev *asd)
+{
+ struct vpfe_device *vpfe = container_of(notifier->v4l2_dev,
+ struct vpfe_device, v4l2_dev);
+ struct v4l2_subdev_mbus_code_enum mbus_code;
+ struct vpfe_subdev_info *sdinfo;
+ bool found = false;
+ int i, j;
+
+ vpfe_dbg(1, vpfe, "vpfe_async_bound\n");
+
+ for (i = 0; i < ARRAY_SIZE(vpfe->cfg->asd); i++) {
+ sdinfo = &vpfe->cfg->sub_devs[i];
+
+ if (!strcmp(sdinfo->name, subdev->name)) {
+ vpfe->sd[i] = subdev;
+ vpfe_info(vpfe,
+ "v4l2 sub device %s registered\n",
+ subdev->name);
+ vpfe->sd[i]->grp_id =
+ sdinfo->grp_id;
+ /* update tvnorms from the sub devices */
+ for (j = 0; j < 1; j++)
+ vpfe->video_dev->tvnorms |=
+ sdinfo->inputs[j].std;
+
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ vpfe_info(vpfe, "sub device (%s) not matched\n", subdev->name);
+ return -EINVAL;
+ }
+
+ /* setup the supported formats & indexes */
+ for (j = 0, i = 0; ; ++j) {
+ struct vpfe_fmt *fmt;
+ int ret;
+
+ memset(&mbus_code, 0, sizeof(mbus_code));
+ mbus_code.index = j;
+ ret = v4l2_subdev_call(subdev, pad, enum_mbus_code,
+ NULL, &mbus_code);
+ if (ret)
+ break;
+
+ fmt = find_format_by_code(mbus_code.code);
+ if (!fmt)
+ continue;
+
+ fmt->supported = true;
+ fmt->index = i++;
+ }
+
+ return 0;
+}
+
+static int vpfe_probe_complete(struct vpfe_device *vpfe)
+{
+ struct video_device *vdev;
+ struct vb2_queue *q;
+ int err;
+
+ spin_lock_init(&vpfe->dma_queue_lock);
+ mutex_init(&vpfe->lock);
+
+ vpfe->fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ /* set first sub device as current one */
+ vpfe->current_subdev = &vpfe->cfg->sub_devs[0];
+ vpfe->v4l2_dev.ctrl_handler = vpfe->sd[0]->ctrl_handler;
+
+ err = vpfe_set_input(vpfe, 0);
+ if (err)
+ goto probe_out;
+
+ /* Initialize videobuf2 queue as per the buffer type */
+ vpfe->alloc_ctx = vb2_dma_contig_init_ctx(vpfe->pdev);
+ if (IS_ERR(vpfe->alloc_ctx)) {
+ vpfe_err(vpfe, "Failed to get the context\n");
+ err = PTR_ERR(vpfe->alloc_ctx);
+ goto probe_out;
+ }
+
+ q = &vpfe->buffer_queue;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
+ q->drv_priv = vpfe;
+ q->ops = &vpfe_video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct vpfe_cap_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &vpfe->lock;
+ q->min_buffers_needed = 1;
+
+ err = vb2_queue_init(q);
+ if (err) {
+ vpfe_err(vpfe, "vb2_queue_init() failed\n");
+ vb2_dma_contig_cleanup_ctx(vpfe->alloc_ctx);
+ goto probe_out;
+ }
+
+ INIT_LIST_HEAD(&vpfe->dma_queue);
+
+ vdev = vpfe->video_dev;
+ strlcpy(vdev->name, VPFE_MODULE_NAME, sizeof(vdev->name));
+ vdev->release = video_device_release;
+ vdev->fops = &vpfe_fops;
+ vdev->ioctl_ops = &vpfe_ioctl_ops;
+ vdev->v4l2_dev = &vpfe->v4l2_dev;
+ vdev->vfl_dir = VFL_DIR_RX;
+ vdev->queue = q;
+ vdev->lock = &vpfe->lock;
+ video_set_drvdata(vdev, vpfe);
+ err = video_register_device(vpfe->video_dev, VFL_TYPE_GRABBER, -1);
+ if (err) {
+ vpfe_err(vpfe,
+ "Unable to register video device.\n");
+ goto probe_out;
+ }
+
+ return 0;
+
+probe_out:
+ v4l2_device_unregister(&vpfe->v4l2_dev);
+ return err;
+}
+
+static int vpfe_async_complete(struct v4l2_async_notifier *notifier)
+{
+ struct vpfe_device *vpfe = container_of(notifier->v4l2_dev,
+ struct vpfe_device, v4l2_dev);
+
+ return vpfe_probe_complete(vpfe);
+}
+
+static struct vpfe_config *
+vpfe_get_pdata(struct platform_device *pdev)
+{
+ struct device_node *endpoint = NULL, *rem = NULL;
+ struct v4l2_of_endpoint bus_cfg;
+ struct vpfe_subdev_info *sdinfo;
+ struct vpfe_config *pdata;
+ unsigned int flags;
+ unsigned int i;
+ int err;
+
+ dev_dbg(&pdev->dev, "vpfe_get_pdata\n");
+
+ if (!IS_ENABLED(CONFIG_OF) || !pdev->dev.of_node)
+ return pdev->dev.platform_data;
+
+ pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return NULL;
+
+ for (i = 0; ; i++) {
+ endpoint = of_graph_get_next_endpoint(pdev->dev.of_node,
+ endpoint);
+ if (!endpoint)
+ break;
+
+ sdinfo = &pdata->sub_devs[i];
+ sdinfo->grp_id = 0;
+
+ /* we only support camera */
+ sdinfo->inputs[0].index = i;
+ strcpy(sdinfo->inputs[0].name, "Camera");
+ sdinfo->inputs[0].type = V4L2_INPUT_TYPE_CAMERA;
+ sdinfo->inputs[0].std = V4L2_STD_ALL;
+ sdinfo->inputs[0].capabilities = V4L2_IN_CAP_STD;
+
+ sdinfo->can_route = 0;
+ sdinfo->routes = NULL;
+
+ of_property_read_u32(endpoint, "ti,am437x-vpfe-interface",
+ &sdinfo->vpfe_param.if_type);
+ if (sdinfo->vpfe_param.if_type < 0 ||
+ sdinfo->vpfe_param.if_type > 4) {
+ sdinfo->vpfe_param.if_type = VPFE_RAW_BAYER;
+ }
+
+ err = v4l2_of_parse_endpoint(endpoint, &bus_cfg);
+ if (err) {
+ dev_err(&pdev->dev, "Could not parse the endpoint\n");
+ goto done;
+ }
+
+ sdinfo->vpfe_param.bus_width = bus_cfg.bus.parallel.bus_width;
+
+ if (sdinfo->vpfe_param.bus_width < 8 ||
+ sdinfo->vpfe_param.bus_width > 16) {
+ dev_err(&pdev->dev, "Invalid bus width.\n");
+ goto done;
+ }
+
+ flags = bus_cfg.bus.parallel.flags;
+
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ sdinfo->vpfe_param.hdpol = 1;
+
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
+ sdinfo->vpfe_param.vdpol = 1;
+
+ rem = of_graph_get_remote_port_parent(endpoint);
+ if (!rem) {
+ dev_err(&pdev->dev, "Remote device at %s not found\n",
+ endpoint->full_name);
+ goto done;
+ }
+
+ strncpy(sdinfo->name, rem->name, sizeof(sdinfo->name));
+
+ pdata->asd[i] = devm_kzalloc(&pdev->dev,
+ sizeof(struct v4l2_async_subdev),
+ GFP_KERNEL);
+ pdata->asd[i]->match_type = V4L2_ASYNC_MATCH_OF;
+ pdata->asd[i]->match.of.node = rem;
+ of_node_put(endpoint);
+ of_node_put(rem);
+ }
+
+ of_node_put(endpoint);
+ return pdata;
+
+done:
+ of_node_put(endpoint);
+ of_node_put(rem);
+ return NULL;
+}
+
+/*
+ * vpfe_probe : This function creates device entries by register
+ * itself to the V4L2 driver and initializes fields of each
+ * device objects
+ */
+static int vpfe_probe(struct platform_device *pdev)
+{
+ struct vpfe_config *vpfe_cfg = vpfe_get_pdata(pdev);
+ struct vpfe_device *vpfe;
+ struct vpfe_ccdc *ccdc;
+ struct resource *res;
+ int ret;
+
+ if (!vpfe_cfg) {
+ dev_err(&pdev->dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ vpfe = devm_kzalloc(&pdev->dev, sizeof(*vpfe), GFP_KERNEL);
+ if (!vpfe)
+ return -ENOMEM;
+
+ vpfe->pdev = &pdev->dev;
+ vpfe->cfg = vpfe_cfg;
+ ccdc = &vpfe->ccdc;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ccdc->ccdc_cfg.base_addr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(ccdc->ccdc_cfg.base_addr))
+ return PTR_ERR(ccdc->ccdc_cfg.base_addr);
+
+ vpfe->irq = platform_get_irq(pdev, 0);
+ if (vpfe->irq <= 0) {
+ dev_err(&pdev->dev, "No IRQ resource\n");
+ return -ENODEV;
+ }
+
+ ret = devm_request_irq(vpfe->pdev, vpfe->irq, vpfe_isr, 0,
+ "vpfe_capture0", vpfe);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request interrupt\n");
+ return -EINVAL;
+ }
+
+ vpfe->video_dev = video_device_alloc();
+ if (!vpfe->video_dev) {
+ dev_err(&pdev->dev, "Unable to allocate video device\n");
+ return -ENOMEM;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &vpfe->v4l2_dev);
+ if (ret) {
+ vpfe_err(vpfe,
+ "Unable to register v4l2 device.\n");
+ goto probe_out_video_release;
+ }
+
+ /* set the driver data in platform device */
+ platform_set_drvdata(pdev, vpfe);
+ /* Enabling module functional clock */
+ pm_runtime_enable(&pdev->dev);
+
+ /* for now just enable it here instead of waiting for the open */
+ pm_runtime_get_sync(&pdev->dev);
+
+ vpfe_ccdc_config_defaults(ccdc);
+
+ pm_runtime_put_sync(&pdev->dev);
+
+ vpfe->sd = devm_kzalloc(&pdev->dev, sizeof(struct v4l2_subdev *) *
+ ARRAY_SIZE(vpfe->cfg->asd), GFP_KERNEL);
+ if (!vpfe->sd) {
+ ret = -ENOMEM;
+ goto probe_out_v4l2_unregister;
+ }
+
+ vpfe->notifier.subdevs = vpfe->cfg->asd;
+ vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd);
+ vpfe->notifier.bound = vpfe_async_bound;
+ vpfe->notifier.complete = vpfe_async_complete;
+ ret = v4l2_async_notifier_register(&vpfe->v4l2_dev,
+ &vpfe->notifier);
+ if (ret) {
+ vpfe_err(vpfe, "Error registering async notifier\n");
+ ret = -EINVAL;
+ goto probe_out_v4l2_unregister;
+ }
+
+ return 0;
+
+probe_out_v4l2_unregister:
+ v4l2_device_unregister(&vpfe->v4l2_dev);
+probe_out_video_release:
+ if (!video_is_registered(vpfe->video_dev))
+ video_device_release(vpfe->video_dev);
+ return ret;
+}
+
+/*
+ * vpfe_remove : It un-register device from V4L2 driver
+ */
+static int vpfe_remove(struct platform_device *pdev)
+{
+ struct vpfe_device *vpfe = platform_get_drvdata(pdev);
+
+ vpfe_dbg(2, vpfe, "vpfe_remove\n");
+
+ pm_runtime_disable(&pdev->dev);
+
+ v4l2_async_notifier_unregister(&vpfe->notifier);
+ v4l2_device_unregister(&vpfe->v4l2_dev);
+ video_unregister_device(vpfe->video_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static void vpfe_save_context(struct vpfe_ccdc *ccdc)
+{
+ ccdc->ccdc_ctx[VPFE_PCR >> 2] = vpfe_reg_read(ccdc, VPFE_PCR);
+ ccdc->ccdc_ctx[VPFE_SYNMODE >> 2] = vpfe_reg_read(ccdc, VPFE_SYNMODE);
+ ccdc->ccdc_ctx[VPFE_SDOFST >> 2] = vpfe_reg_read(ccdc, VPFE_SDOFST);
+ ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2] = vpfe_reg_read(ccdc, VPFE_SDR_ADDR);
+ ccdc->ccdc_ctx[VPFE_CLAMP >> 2] = vpfe_reg_read(ccdc, VPFE_CLAMP);
+ ccdc->ccdc_ctx[VPFE_DCSUB >> 2] = vpfe_reg_read(ccdc, VPFE_DCSUB);
+ ccdc->ccdc_ctx[VPFE_COLPTN >> 2] = vpfe_reg_read(ccdc, VPFE_COLPTN);
+ ccdc->ccdc_ctx[VPFE_BLKCMP >> 2] = vpfe_reg_read(ccdc, VPFE_BLKCMP);
+ ccdc->ccdc_ctx[VPFE_VDINT >> 2] = vpfe_reg_read(ccdc, VPFE_VDINT);
+ ccdc->ccdc_ctx[VPFE_ALAW >> 2] = vpfe_reg_read(ccdc, VPFE_ALAW);
+ ccdc->ccdc_ctx[VPFE_REC656IF >> 2] = vpfe_reg_read(ccdc, VPFE_REC656IF);
+ ccdc->ccdc_ctx[VPFE_CCDCFG >> 2] = vpfe_reg_read(ccdc, VPFE_CCDCFG);
+ ccdc->ccdc_ctx[VPFE_CULLING >> 2] = vpfe_reg_read(ccdc, VPFE_CULLING);
+ ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2] = vpfe_reg_read(ccdc,
+ VPFE_HD_VD_WID);
+ ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2] = vpfe_reg_read(ccdc,
+ VPFE_PIX_LINES);
+ ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2] = vpfe_reg_read(ccdc,
+ VPFE_HORZ_INFO);
+ ccdc->ccdc_ctx[VPFE_VERT_START >> 2] = vpfe_reg_read(ccdc,
+ VPFE_VERT_START);
+ ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2] = vpfe_reg_read(ccdc,
+ VPFE_VERT_LINES);
+ ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2] = vpfe_reg_read(ccdc,
+ VPFE_HSIZE_OFF);
+}
+
+static int vpfe_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vpfe_device *vpfe = platform_get_drvdata(pdev);
+ struct vpfe_ccdc *ccdc = &vpfe->ccdc;
+
+ /* if streaming has not started we don't care */
+ if (!vb2_start_streaming_called(&vpfe->buffer_queue))
+ return 0;
+
+ pm_runtime_get_sync(dev);
+ vpfe_config_enable(ccdc, 1);
+
+ /* Save VPFE context */
+ vpfe_save_context(ccdc);
+
+ /* Disable CCDC */
+ vpfe_pcr_enable(ccdc, 0);
+ vpfe_config_enable(ccdc, 0);
+
+ /* Disable both master and slave clock */
+ pm_runtime_put_sync(dev);
+
+ /* Select sleep pin state */
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static void vpfe_restore_context(struct vpfe_ccdc *ccdc)
+{
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SYNMODE >> 2], VPFE_SYNMODE);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CULLING >> 2], VPFE_CULLING);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDOFST >> 2], VPFE_SDOFST);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_SDR_ADDR >> 2], VPFE_SDR_ADDR);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CLAMP >> 2], VPFE_CLAMP);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_DCSUB >> 2], VPFE_DCSUB);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_COLPTN >> 2], VPFE_COLPTN);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_BLKCMP >> 2], VPFE_BLKCMP);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VDINT >> 2], VPFE_VDINT);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_ALAW >> 2], VPFE_ALAW);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_REC656IF >> 2], VPFE_REC656IF);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_CCDCFG >> 2], VPFE_CCDCFG);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PCR >> 2], VPFE_PCR);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HD_VD_WID >> 2],
+ VPFE_HD_VD_WID);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_PIX_LINES >> 2],
+ VPFE_PIX_LINES);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HORZ_INFO >> 2],
+ VPFE_HORZ_INFO);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_START >> 2],
+ VPFE_VERT_START);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_VERT_LINES >> 2],
+ VPFE_VERT_LINES);
+ vpfe_reg_write(ccdc, ccdc->ccdc_ctx[VPFE_HSIZE_OFF >> 2],
+ VPFE_HSIZE_OFF);
+}
+
+static int vpfe_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct vpfe_device *vpfe = platform_get_drvdata(pdev);
+ struct vpfe_ccdc *ccdc = &vpfe->ccdc;
+
+ /* if streaming has not started we don't care */
+ if (!vb2_start_streaming_called(&vpfe->buffer_queue))
+ return 0;
+
+ /* Enable both master and slave clock */
+ pm_runtime_get_sync(dev);
+ vpfe_config_enable(ccdc, 1);
+
+ /* Restore VPFE context */
+ vpfe_restore_context(ccdc);
+
+ vpfe_config_enable(ccdc, 0);
+ pm_runtime_put_sync(dev);
+
+ /* Select default pin state */
+ pinctrl_pm_select_default_state(dev);
+
+ return 0;
+}
+
+#endif
+
+static SIMPLE_DEV_PM_OPS(vpfe_pm_ops, vpfe_suspend, vpfe_resume);
+
+static const struct of_device_id vpfe_of_match[] = {
+ { .compatible = "ti,am437x-vpfe", },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, vpfe_of_match);
+
+static struct platform_driver vpfe_driver = {
+ .probe = vpfe_probe,
+ .remove = vpfe_remove,
+ .driver = {
+ .name = VPFE_MODULE_NAME,
+ .pm = &vpfe_pm_ops,
+ .of_match_table = of_match_ptr(vpfe_of_match),
+ },
+};
+
+module_platform_driver(vpfe_driver);
+
+MODULE_AUTHOR("Texas Instruments");
+MODULE_DESCRIPTION("TI AM437x VPFE driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(VPFE_VERSION);
diff --git a/drivers/media/platform/am437x/am437x-vpfe.h b/drivers/media/platform/am437x/am437x-vpfe.h
new file mode 100644
index 000000000000..0f557352313d
--- /dev/null
+++ b/drivers/media/platform/am437x/am437x-vpfe.h
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2013 - 2014 Texas Instruments, Inc.
+ *
+ * Benoit Parrot <bparrot@ti.com>
+ * Lad, Prabhakar <prabhakar.csengg@gmail.com>
+ *
+ * This program is free software; you may 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.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef AM437X_VPFE_H
+#define AM437X_VPFE_H
+
+#include <linux/am437x-vpfe.h>
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/i2c.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "am437x-vpfe_regs.h"
+
+enum vpfe_pin_pol {
+ VPFE_PINPOL_POSITIVE = 0,
+ VPFE_PINPOL_NEGATIVE,
+};
+
+enum vpfe_hw_if_type {
+ /* Raw Bayer */
+ VPFE_RAW_BAYER = 0,
+ /* BT656 - 8 bit */
+ VPFE_BT656,
+ /* BT656 - 10 bit */
+ VPFE_BT656_10BIT,
+ /* YCbCr - 8 bit with external sync */
+ VPFE_YCBCR_SYNC_8,
+ /* YCbCr - 16 bit with external sync */
+ VPFE_YCBCR_SYNC_16,
+};
+
+/* interface description */
+struct vpfe_hw_if_param {
+ enum vpfe_hw_if_type if_type;
+ enum vpfe_pin_pol hdpol;
+ enum vpfe_pin_pol vdpol;
+ unsigned int bus_width;
+};
+
+#define VPFE_MAX_SUBDEV 1
+#define VPFE_MAX_INPUTS 1
+
+struct vpfe_pixel_format {
+ struct v4l2_fmtdesc fmtdesc;
+ /* bytes per pixel */
+ int bpp;
+};
+
+struct vpfe_std_info {
+ int active_pixels;
+ int active_lines;
+ /* current frame format */
+ int frame_format;
+};
+
+struct vpfe_route {
+ u32 input;
+ u32 output;
+};
+
+struct vpfe_subdev_info {
+ char name[32];
+ /* Sub device group id */
+ int grp_id;
+ /* inputs available at the sub device */
+ struct v4l2_input inputs[VPFE_MAX_INPUTS];
+ /* Sub dev routing information for each input */
+ struct vpfe_route *routes;
+ /* check if sub dev supports routing */
+ int can_route;
+ /* ccdc bus/interface configuration */
+ struct vpfe_hw_if_param vpfe_param;
+ struct v4l2_subdev *sd;
+};
+
+struct vpfe_config {
+ /* information about each subdev */
+ struct vpfe_subdev_info sub_devs[VPFE_MAX_SUBDEV];
+ /* Flat array, arranged in groups */
+ struct v4l2_async_subdev *asd[VPFE_MAX_SUBDEV];
+};
+
+struct vpfe_cap_buffer {
+ struct vb2_buffer vb;
+ struct list_head list;
+};
+
+enum ccdc_pixfmt {
+ CCDC_PIXFMT_RAW = 0,
+ CCDC_PIXFMT_YCBCR_16BIT,
+ CCDC_PIXFMT_YCBCR_8BIT,
+};
+
+enum ccdc_frmfmt {
+ CCDC_FRMFMT_PROGRESSIVE = 0,
+ CCDC_FRMFMT_INTERLACED,
+};
+
+/* PIXEL ORDER IN MEMORY from LSB to MSB */
+/* only applicable for 8-bit input mode */
+enum ccdc_pixorder {
+ CCDC_PIXORDER_YCBYCR,
+ CCDC_PIXORDER_CBYCRY,
+};
+
+enum ccdc_buftype {
+ CCDC_BUFTYPE_FLD_INTERLEAVED,
+ CCDC_BUFTYPE_FLD_SEPARATED
+};
+
+
+/* returns the highest bit used for the gamma */
+static inline u8 ccdc_gamma_width_max_bit(enum vpfe_ccdc_gamma_width width)
+{
+ return 15 - width;
+}
+
+/* returns the highest bit used for this data size */
+static inline u8 ccdc_data_size_max_bit(enum vpfe_ccdc_data_size sz)
+{
+ return sz == VPFE_CCDC_DATA_8BITS ? 7 : 15 - sz;
+}
+
+/* Structure for CCDC configuration parameters for raw capture mode */
+struct ccdc_params_raw {
+ /* pixel format */
+ enum ccdc_pixfmt pix_fmt;
+ /* progressive or interlaced frame */
+ enum ccdc_frmfmt frm_fmt;
+ struct v4l2_rect win;
+ /* Current Format Bytes Per Pixels */
+ unsigned int bytesperpixel;
+ /* Current Format Bytes per Lines
+ * (Aligned to 32 bytes) used for HORZ_INFO
+ */
+ unsigned int bytesperline;
+ /* field id polarity */
+ enum vpfe_pin_pol fid_pol;
+ /* vertical sync polarity */
+ enum vpfe_pin_pol vd_pol;
+ /* horizontal sync polarity */
+ enum vpfe_pin_pol hd_pol;
+ /* interleaved or separated fields */
+ enum ccdc_buftype buf_type;
+ /*
+ * enable to store the image in inverse
+ * order in memory(bottom to top)
+ */
+ unsigned char image_invert_enable;
+ /* configurable parameters */
+ struct vpfe_ccdc_config_params_raw config_params;
+};
+
+struct ccdc_params_ycbcr {
+ /* pixel format */
+ enum ccdc_pixfmt pix_fmt;
+ /* progressive or interlaced frame */
+ enum ccdc_frmfmt frm_fmt;
+ struct v4l2_rect win;
+ /* Current Format Bytes Per Pixels */
+ unsigned int bytesperpixel;
+ /* Current Format Bytes per Lines
+ * (Aligned to 32 bytes) used for HORZ_INFO
+ */
+ unsigned int bytesperline;
+ /* field id polarity */
+ enum vpfe_pin_pol fid_pol;
+ /* vertical sync polarity */
+ enum vpfe_pin_pol vd_pol;
+ /* horizontal sync polarity */
+ enum vpfe_pin_pol hd_pol;
+ /* enable BT.656 embedded sync mode */
+ int bt656_enable;
+ /* cb:y:cr:y or y:cb:y:cr in memory */
+ enum ccdc_pixorder pix_order;
+ /* interleaved or separated fields */
+ enum ccdc_buftype buf_type;
+};
+
+/*
+ * CCDC operational configuration
+ */
+struct ccdc_config {
+ /* CCDC interface type */
+ enum vpfe_hw_if_type if_type;
+ /* Raw Bayer configuration */
+ struct ccdc_params_raw bayer;
+ /* YCbCr configuration */
+ struct ccdc_params_ycbcr ycbcr;
+ /* ccdc base address */
+ void __iomem *base_addr;
+};
+
+struct vpfe_ccdc {
+ struct ccdc_config ccdc_cfg;
+ u32 ccdc_ctx[VPFE_REG_END / sizeof(u32)];
+};
+
+struct vpfe_device {
+ /* V4l2 specific parameters */
+ /* Identifies video device for this channel */
+ struct video_device *video_dev;
+ /* sub devices */
+ struct v4l2_subdev **sd;
+ /* vpfe cfg */
+ struct vpfe_config *cfg;
+ /* V4l2 device */
+ struct v4l2_device v4l2_dev;
+ /* parent device */
+ struct device *pdev;
+ /* subdevice async Notifier */
+ struct v4l2_async_notifier notifier;
+ /* Indicates id of the field which is being displayed */
+ unsigned field;
+ unsigned sequence;
+ /* current interface type */
+ struct vpfe_hw_if_param vpfe_if_params;
+ /* ptr to currently selected sub device */
+ struct vpfe_subdev_info *current_subdev;
+ /* current input at the sub device */
+ int current_input;
+ /* Keeps track of the information about the standard */
+ struct vpfe_std_info std_info;
+ /* std index into std table */
+ int std_index;
+ /* IRQs used when CCDC output to SDRAM */
+ unsigned int irq;
+ /* Pointer pointing to current v4l2_buffer */
+ struct vpfe_cap_buffer *cur_frm;
+ /* Pointer pointing to next v4l2_buffer */
+ struct vpfe_cap_buffer *next_frm;
+ /* Used to store pixel format */
+ struct v4l2_format fmt;
+ /* Used to store current bytes per pixel based on current format */
+ unsigned int bpp;
+ /*
+ * used when IMP is chained to store the crop window which
+ * is different from the image window
+ */
+ struct v4l2_rect crop;
+ /* Buffer queue used in video-buf */
+ struct vb2_queue buffer_queue;
+ /* Allocator-specific contexts for each plane */
+ struct vb2_alloc_ctx *alloc_ctx;
+ /* Queue of filled frames */
+ struct list_head dma_queue;
+ /* IRQ lock for DMA queue */
+ spinlock_t dma_queue_lock;
+ /* lock used to access this structure */
+ struct mutex lock;
+ /*
+ * offset where second field starts from the starting of the
+ * buffer for field separated YCbCr formats
+ */
+ u32 field_off;
+ struct vpfe_ccdc ccdc;
+};
+
+#endif /* AM437X_VPFE_H */
diff --git a/drivers/media/platform/am437x/am437x-vpfe_regs.h b/drivers/media/platform/am437x/am437x-vpfe_regs.h
new file mode 100644
index 000000000000..4a0ed29723e8
--- /dev/null
+++ b/drivers/media/platform/am437x/am437x-vpfe_regs.h
@@ -0,0 +1,140 @@
+/*
+ * TI AM437x Image Sensor Interface Registers
+ *
+ * Copyright (C) 2013 - 2014 Texas Instruments, Inc.
+ *
+ * Benoit Parrot <bparrot@ti.com>
+ * Lad, Prabhakar <prabhakar.csengg@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether 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 AM437X_VPFE_REGS_H
+#define AM437X_VPFE_REGS_H
+
+/* VPFE module register offset */
+#define VPFE_REVISION 0x0
+#define VPFE_PCR 0x4
+#define VPFE_SYNMODE 0x8
+#define VPFE_HD_VD_WID 0xc
+#define VPFE_PIX_LINES 0x10
+#define VPFE_HORZ_INFO 0x14
+#define VPFE_VERT_START 0x18
+#define VPFE_VERT_LINES 0x1c
+#define VPFE_CULLING 0x20
+#define VPFE_HSIZE_OFF 0x24
+#define VPFE_SDOFST 0x28
+#define VPFE_SDR_ADDR 0x2c
+#define VPFE_CLAMP 0x30
+#define VPFE_DCSUB 0x34
+#define VPFE_COLPTN 0x38
+#define VPFE_BLKCMP 0x3c
+#define VPFE_VDINT 0x48
+#define VPFE_ALAW 0x4c
+#define VPFE_REC656IF 0x50
+#define VPFE_CCDCFG 0x54
+#define VPFE_DMA_CNTL 0x98
+#define VPFE_SYSCONFIG 0x104
+#define VPFE_CONFIG 0x108
+#define VPFE_IRQ_EOI 0x110
+#define VPFE_IRQ_STS_RAW 0x114
+#define VPFE_IRQ_STS 0x118
+#define VPFE_IRQ_EN_SET 0x11c
+#define VPFE_IRQ_EN_CLR 0x120
+#define VPFE_REG_END 0x124
+
+/* Define bit fields within selected registers */
+#define VPFE_FID_POL_MASK 1
+#define VPFE_FID_POL_SHIFT 4
+#define VPFE_HD_POL_MASK 1
+#define VPFE_HD_POL_SHIFT 3
+#define VPFE_VD_POL_MASK 1
+#define VPFE_VD_POL_SHIFT 2
+#define VPFE_HSIZE_OFF_MASK 0xffffffe0
+#define VPFE_32BYTE_ALIGN_VAL 31
+#define VPFE_FRM_FMT_MASK 0x1
+#define VPFE_FRM_FMT_SHIFT 7
+#define VPFE_DATA_SZ_MASK 7
+#define VPFE_DATA_SZ_SHIFT 8
+#define VPFE_PIX_FMT_MASK 3
+#define VPFE_PIX_FMT_SHIFT 12
+#define VPFE_VP2SDR_DISABLE 0xfffbffff
+#define VPFE_WEN_ENABLE (1 << 17)
+#define VPFE_SDR2RSZ_DISABLE 0xfff7ffff
+#define VPFE_VDHDEN_ENABLE (1 << 16)
+#define VPFE_LPF_ENABLE (1 << 14)
+#define VPFE_ALAW_ENABLE (1 << 3)
+#define VPFE_ALAW_GAMMA_WD_MASK 7
+#define VPFE_BLK_CLAMP_ENABLE (1 << 31)
+#define VPFE_BLK_SGAIN_MASK 0x1f
+#define VPFE_BLK_ST_PXL_MASK 0x7fff
+#define VPFE_BLK_ST_PXL_SHIFT 10
+#define VPFE_BLK_SAMPLE_LN_MASK 7
+#define VPFE_BLK_SAMPLE_LN_SHIFT 28
+#define VPFE_BLK_SAMPLE_LINE_MASK 7
+#define VPFE_BLK_SAMPLE_LINE_SHIFT 25
+#define VPFE_BLK_DC_SUB_MASK 0x03fff
+#define VPFE_BLK_COMP_MASK 0xff
+#define VPFE_BLK_COMP_GB_COMP_SHIFT 8
+#define VPFE_BLK_COMP_GR_COMP_SHIFT 16
+#define VPFE_BLK_COMP_R_COMP_SHIFT 24
+#define VPFE_LATCH_ON_VSYNC_DISABLE (1 << 15)
+#define VPFE_DATA_PACK_ENABLE (1 << 11)
+#define VPFE_HORZ_INFO_SPH_SHIFT 16
+#define VPFE_VERT_START_SLV0_SHIFT 16
+#define VPFE_VDINT_VDINT0_SHIFT 16
+#define VPFE_VDINT_VDINT1_MASK 0xffff
+#define VPFE_PPC_RAW 1
+#define VPFE_DCSUB_DEFAULT_VAL 0
+#define VPFE_CLAMP_DEFAULT_VAL 0
+#define VPFE_COLPTN_VAL 0xbb11bb11
+#define VPFE_TWO_BYTES_PER_PIXEL 2
+#define VPFE_INTERLACED_IMAGE_INVERT 0x4b6d
+#define VPFE_INTERLACED_NO_IMAGE_INVERT 0x0249
+#define VPFE_PROGRESSIVE_IMAGE_INVERT 0x4000
+#define VPFE_PROGRESSIVE_NO_IMAGE_INVERT 0
+#define VPFE_INTERLACED_HEIGHT_SHIFT 1
+#define VPFE_SYN_MODE_INPMOD_SHIFT 12
+#define VPFE_SYN_MODE_INPMOD_MASK 3
+#define VPFE_SYN_MODE_8BITS (7 << 8)
+#define VPFE_SYN_MODE_10BITS (6 << 8)
+#define VPFE_SYN_MODE_11BITS (5 << 8)
+#define VPFE_SYN_MODE_12BITS (4 << 8)
+#define VPFE_SYN_MODE_13BITS (3 << 8)
+#define VPFE_SYN_MODE_14BITS (2 << 8)
+#define VPFE_SYN_MODE_15BITS (1 << 8)
+#define VPFE_SYN_MODE_16BITS (0 << 8)
+#define VPFE_SYN_FLDMODE_MASK 1
+#define VPFE_SYN_FLDMODE_SHIFT 7
+#define VPFE_REC656IF_BT656_EN 3
+#define VPFE_SYN_MODE_VD_POL_NEGATIVE (1 << 2)
+#define VPFE_CCDCFG_Y8POS_SHIFT 11
+#define VPFE_CCDCFG_BW656_10BIT (1 << 5)
+#define VPFE_SDOFST_FIELD_INTERLEAVED 0x249
+#define VPFE_NO_CULLING 0xffff00ff
+#define VPFE_VDINT0 (1 << 0)
+#define VPFE_VDINT1 (1 << 1)
+#define VPFE_VDINT2 (1 << 2)
+#define VPFE_DMA_CNTL_OVERFLOW (1 << 31)
+
+#define VPFE_CONFIG_PCLK_INV_SHIFT 0
+#define VPFE_CONFIG_PCLK_INV_MASK 1
+#define VPFE_CONFIG_PCLK_INV_NOT_INV 0
+#define VPFE_CONFIG_PCLK_INV_INV 1
+#define VPFE_CONFIG_EN_SHIFT 1
+#define VPFE_CONFIG_EN_MASK 2
+#define VPFE_CONFIG_EN_DISABLE 0
+#define VPFE_CONFIG_EN_ENABLE 1
+#define VPFE_CONFIG_ST_SHIFT 2
+#define VPFE_CONFIG_ST_MASK 4
+#define VPFE_CONFIG_ST_OCP_ACTIVE 0
+#define VPFE_CONFIG_ST_OCP_STANDBY 1
+
+#endif /* AM437X_VPFE_REGS_H */
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index b4029ae293d3..856b542b35b9 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -718,6 +718,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
struct vb2_buffer *buf;
int gamma, ret, value;
u32 dst_fourcc;
+ int num_fb;
u32 stride;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
@@ -983,12 +984,14 @@ static int coda_start_encoding(struct coda_ctx *ctx)
v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
goto out;
}
+ num_fb = 2;
stride = q_data_src->bytesperline;
} else {
ctx->num_internal_frames = 0;
+ num_fb = 0;
stride = 0;
}
- coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
+ coda_write(dev, num_fb, CODA_CMD_SET_FRAME_BUF_NUM);
coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE);
if (dev->devtype->product == CODA_7541) {
@@ -1316,8 +1319,10 @@ static void coda_seq_end_work(struct work_struct *work)
static void coda_bit_release(struct coda_ctx *ctx)
{
+ mutex_lock(&ctx->buffer_mutex);
coda_free_framebuffers(ctx);
coda_free_context_buffers(ctx);
+ mutex_unlock(&ctx->buffer_mutex);
}
const struct coda_context_ops coda_bit_encode_ops = {
@@ -1431,9 +1436,10 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
height = val & CODA7_PICHEIGHT_MASK;
}
- if (width > q_data_dst->width || height > q_data_dst->height) {
+ if (width > q_data_dst->bytesperline || height > q_data_dst->height) {
v4l2_err(&dev->v4l2_dev, "stream is %dx%d, not %dx%d\n",
- width, height, q_data_dst->width, q_data_dst->height);
+ width, height, q_data_dst->bytesperline,
+ q_data_dst->height);
return -EINVAL;
}
@@ -1565,6 +1571,7 @@ 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;
+ struct coda_buffer_meta *meta;
u32 reg_addr, reg_stride;
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -1643,12 +1650,12 @@ 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;
+ meta = list_first_entry_or_null(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+
+ if (meta && ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
/* If this is the last buffer in the bitstream, add padding */
- 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];
@@ -1665,6 +1672,9 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
coda_kfifo_sync_to_device_full(ctx);
+ /* Clear decode success flag */
+ coda_write(dev, 0, CODA_RET_DEC_PIC_SUCCESS);
+
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
return 0;
@@ -1821,6 +1831,7 @@ static void coda_finish_decode(struct coda_ctx *ctx)
memset(&ctx->frame_metas[decoded_idx], 0,
sizeof(struct coda_buffer_meta));
ctx->frame_metas[decoded_idx].sequence = val;
+ ctx->sequence_offset++;
}
mutex_unlock(&ctx->bitstream_mutex);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 39330a70f752..6f32e6d6b156 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -37,6 +37,7 @@
#include <media/v4l2-mem2mem.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
#include "coda.h"
@@ -180,6 +181,7 @@ struct coda_video_device {
const char *name;
enum coda_inst_type type;
const struct coda_context_ops *ops;
+ bool direct;
u32 src_formats[CODA_MAX_FORMATS];
u32 dst_formats[CODA_MAX_FORMATS];
};
@@ -468,6 +470,18 @@ static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f)
return 0;
}
+static unsigned int coda_estimate_sizeimage(struct coda_ctx *ctx, u32 sizeimage,
+ u32 width, u32 height)
+{
+ /*
+ * 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.
+ */
+ return round_up(clamp(sizeimage, width * height / 8,
+ width * height * 2), PAGE_SIZE);
+}
+
static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
struct v4l2_format *f)
{
@@ -513,15 +527,10 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_MPEG4:
f->fmt.pix.bytesperline = 0;
- /*
- * 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);
+ f->fmt.pix.sizeimage = coda_estimate_sizeimage(ctx,
+ f->fmt.pix.sizeimage,
+ f->fmt.pix.width,
+ f->fmt.pix.height);
break;
default:
BUG();
@@ -592,7 +601,11 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv,
if (ret < 0)
return ret;
- if (!f->fmt.pix.colorspace) {
+ switch (f->fmt.pix.colorspace) {
+ case V4L2_COLORSPACE_REC709:
+ case V4L2_COLORSPACE_JPEG:
+ break;
+ default:
if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
else
@@ -670,6 +683,7 @@ static int coda_s_fmt_vid_out(struct file *file, void *priv,
ctx->colorspace = f->fmt.pix.colorspace;
+ memset(&f_cap, 0, sizeof(f_cap));
f_cap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
coda_g_fmt(file, priv, &f_cap);
f_cap.fmt.pix.width = f->fmt.pix.width;
@@ -908,7 +922,8 @@ static void coda_pic_run_work(struct work_struct *work)
ctx->ops->finish_run(ctx);
}
- if (ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out))
+ if ((ctx->aborting || (!ctx->streamon_cap && !ctx->streamon_out)) &&
+ ctx->ops->seq_end_work)
queue_work(dev->workqueue, &ctx->seq_end_work);
mutex_unlock(&dev->coda_mutex);
@@ -939,15 +954,43 @@ static int coda_job_ready(void *m2m_priv)
return 0;
}
- 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,
- "%d: not ready: not enough bitstream data.\n",
- ctx->idx);
- return 0;
+ if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit) {
+ struct list_head *meta;
+ bool stream_end;
+ int num_metas;
+ int src_bufs;
+
+ if (ctx->hold && !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx)) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "%d: not ready: on hold for more buffers.\n",
+ ctx->idx);
+ return 0;
+ }
+
+ stream_end = ctx->bit_stream_param &
+ CODA_BIT_STREAM_END_FLAG;
+
+ num_metas = 0;
+ list_for_each(meta, &ctx->buffer_meta_list)
+ num_metas++;
+
+ src_bufs = v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx);
+
+ if (!stream_end && (num_metas + src_bufs) < 2) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "%d: not ready: need 2 buffers available (%d, %d)\n",
+ ctx->idx, num_metas, src_bufs);
+ return 0;
+ }
+
+
+ if (!v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
+ !stream_end && (coda_get_bitstream_payload(ctx) < 512)) {
+ v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
+ "%d: not ready: not enough bitstream data (%d).\n",
+ ctx->idx, coda_get_bitstream_payload(ctx));
+ return 0;
+ }
}
if (ctx->aborting) {
@@ -1023,13 +1066,14 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
static void set_default_params(struct coda_ctx *ctx)
{
- unsigned int max_w, max_h, size;
+ unsigned int max_w, max_h, usize, csize;
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;
+ usize = max_w * max_h * 3 / 2;
+ csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h);
ctx->params.codec_mode = ctx->codec->mode;
ctx->colorspace = V4L2_COLORSPACE_REC709;
@@ -1044,14 +1088,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 = size;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = usize;
ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
- ctx->q_data[V4L2_M2M_DST].sizeimage = round_up(size, PAGE_SIZE);
+ ctx->q_data[V4L2_M2M_DST].sizeimage = csize;
} else {
ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
- ctx->q_data[V4L2_M2M_SRC].sizeimage = round_up(size, PAGE_SIZE);
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = csize;
ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
- ctx->q_data[V4L2_M2M_DST].sizeimage = size;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = usize;
}
ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
@@ -1080,6 +1124,7 @@ static int coda_queue_setup(struct vb2_queue *vq,
*nplanes = 1;
sizes[0] = size;
+ /* Set to vb2-dma-contig allocator context, ignored by vb2-vmalloc */
alloc_ctxs[0] = ctx->dev->alloc_ctx;
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
@@ -1109,6 +1154,7 @@ static int coda_buf_prepare(struct vb2_buffer *vb)
static void coda_buf_queue(struct vb2_buffer *vb)
{
struct coda_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_queue *vq = vb->vb2_queue;
struct coda_q_data *q_data;
q_data = get_q_data(ctx, vb->vb2_queue->type);
@@ -1117,8 +1163,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 (ctx->inst_type == CODA_INST_DECODER &&
- vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (ctx->bitstream.size && vq->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
/*
* For backwards compatibility, queuing an empty buffer marks
* the stream end
@@ -1218,7 +1263,7 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
return 0;
/* Allow BIT decoder device_run with no new buffers queued */
- if (ctx->inst_type == CODA_INST_DECODER)
+ if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit)
v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
ctx->gopcounter = ctx->params.gop_size - 1;
@@ -1271,7 +1316,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
coda_bit_stream_end_flag(ctx);
- ctx->isequence = 0;
+ ctx->qsequence = 0;
while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
v4l2_m2m_buf_done(buf, VB2_BUF_STATE_ERROR);
@@ -1290,6 +1335,10 @@ static void coda_stop_streaming(struct vb2_queue *q)
if (!ctx->streamon_out && !ctx->streamon_cap) {
struct coda_buffer_meta *meta;
+ if (ctx->ops->seq_end_work) {
+ queue_work(dev->workqueue, &ctx->seq_end_work);
+ flush_work(&ctx->seq_end_work);
+ }
mutex_lock(&ctx->bitstream_mutex);
while (!list_empty(&ctx->buffer_meta_list)) {
meta = list_first_entry(&ctx->buffer_meta_list,
@@ -1300,6 +1349,7 @@ static void coda_stop_streaming(struct vb2_queue *q)
mutex_unlock(&ctx->bitstream_mutex);
kfifo_init(&ctx->bitstream_fifo,
ctx->bitstream.vaddr, ctx->bitstream.size);
+ ctx->initialized = 0;
ctx->runcounter = 0;
ctx->aborting = 0;
}
@@ -1521,8 +1571,8 @@ int coda_decoder_queue_init(void *priv, struct vb2_queue *src_vq,
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
- src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->io_modes = VB2_DMABUF | VB2_MMAP | VB2_USERPTR;
+ src_vq->mem_ops = &vb2_vmalloc_memops;
ret = coda_queue_init(priv, src_vq);
if (ret)
@@ -1577,9 +1627,11 @@ static int coda_open(struct file *file)
ctx->cvd = to_coda_video_device(vdev);
ctx->inst_type = ctx->cvd->type;
ctx->ops = ctx->cvd->ops;
+ ctx->use_bit = !ctx->cvd->direct;
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);
+ if (ctx->ops->seq_end_work)
+ INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
v4l2_fh_init(&ctx->fh, video_devdata(file));
file->private_data = &ctx->fh;
v4l2_fh_add(&ctx->fh);
@@ -1630,22 +1682,25 @@ static int coda_open(struct file *file)
ctx->fh.ctrl_handler = &ctx->ctrls;
- 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;
+ if (ctx->use_bit) {
+ 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);
- if (!ctx->bitstream.vaddr) {
- v4l2_err(&dev->v4l2_dev,
- "failed to allocate bitstream ringbuffer");
- ret = -ENOMEM;
- goto err_dma_writecombine;
+ if (ctx->use_bit && ctx->inst_type == CODA_INST_DECODER) {
+ 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);
+ if (!ctx->bitstream.vaddr) {
+ v4l2_err(&dev->v4l2_dev,
+ "failed to allocate bitstream ringbuffer");
+ ret = -ENOMEM;
+ goto err_dma_writecombine;
+ }
}
kfifo_init(&ctx->bitstream_fifo,
ctx->bitstream.vaddr, ctx->bitstream.size);
@@ -1693,16 +1748,14 @@ static int coda_release(struct file *file)
v4l2_dbg(1, coda_debug, &dev->v4l2_dev, "Releasing instance %p\n",
ctx);
- debugfs_remove_recursive(ctx->debugfs_entry);
-
- if (ctx->inst_type == CODA_INST_DECODER)
+ if (ctx->inst_type == CODA_INST_DECODER && ctx->use_bit)
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);
/* In case the instance was not running, we still need to call SEQ_END */
- if (ctx->initialized) {
+ if (ctx->initialized && ctx->ops->seq_end_work) {
queue_work(dev->workqueue, &ctx->seq_end_work);
flush_work(&ctx->seq_end_work);
}
@@ -1728,6 +1781,7 @@ static int coda_release(struct file *file)
clear_bit(ctx->idx, &dev->instance_mask);
if (ctx->ops->release)
ctx->ops->release(ctx);
+ debugfs_remove_recursive(ctx->debugfs_entry);
kfree(ctx);
return 0;
@@ -1844,10 +1898,11 @@ static int coda_register_device(struct coda_dev *dev, int i)
{
struct video_device *vfd = &dev->vfd[i];
- if (i > ARRAY_SIZE(dev->vfd))
+ if (i >= dev->devtype->num_vdevs)
return -EINVAL;
- snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name);
+ snprintf(vfd->name, sizeof(vfd->name), "%s",
+ dev->devtype->vdevs[i]->name);
vfd->fops = &coda_fops;
vfd->ioctl_ops = &coda_ioctl_ops;
vfd->release = video_device_release_empty,
@@ -2001,7 +2056,6 @@ static const struct coda_devtype coda_devdata[] = {
static struct platform_device_id coda_platform_ids[] = {
{ .name = "coda-imx27", .driver_data = CODA_IMX27 },
- { .name = "coda-imx53", .driver_data = CODA_IMX53 },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, coda_platform_ids);
@@ -2142,6 +2196,7 @@ static int coda_probe(struct platform_device *pdev)
if (!dev->iram.vaddr) {
dev_warn(&pdev->dev, "unable to alloc iram\n");
} else {
+ memset(dev->iram.vaddr, 0, dev->iram.size);
dev->iram.blob.data = dev->iram.vaddr;
dev->iram.blob.size = dev->iram.size;
dev->iram.dentry = debugfs_create_blob("iram", 0644,
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index 5dd47e5f97c1..0c35cd5032ff 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -198,7 +198,6 @@ struct coda_ctx {
int initialized;
int streamon_out;
int streamon_cap;
- u32 isequence;
u32 qsequence;
u32 osequence;
u32 sequence_offset;
@@ -236,6 +235,7 @@ struct coda_ctx {
u32 frame_mem_ctrl;
int display_idx;
struct dentry *debugfs_entry;
+ bool use_bit;
};
extern int coda_debug;
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
index 8e015b8aa8fa..7d026241171b 100644
--- a/drivers/media/platform/coda/coda_regs.h
+++ b/drivers/media/platform/coda/coda_regs.h
@@ -304,9 +304,9 @@
#define CODA_RATECONTROL_AUTOSKIP_OFFSET 31
#define CODA_RATECONTROL_AUTOSKIP_MASK 0x01
#define CODA_RATECONTROL_INITIALDELAY_OFFSET 16
-#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7f
+#define CODA_RATECONTROL_INITIALDELAY_MASK 0x7fff
#define CODA_RATECONTROL_BITRATE_OFFSET 1
-#define CODA_RATECONTROL_BITRATE_MASK 0x7f
+#define CODA_RATECONTROL_BITRATE_MASK 0x7fff
#define CODA_RATECONTROL_ENABLE_OFFSET 0
#define CODA_RATECONTROL_ENABLE_MASK 0x01
#define CODA_CMD_ENC_SEQ_RC_BUF_SIZE 0x1b0
diff --git a/drivers/media/platform/davinci/Kconfig b/drivers/media/platform/davinci/Kconfig
index d9e1ddb586b1..469e9d28cec0 100644
--- a/drivers/media/platform/davinci/Kconfig
+++ b/drivers/media/platform/davinci/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_DAVINCI_VPIF_DISPLAY
tristate "TI DaVinci VPIF V4L2-Display driver"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L2
depends on ARCH_DAVINCI || COMPILE_TEST
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
@@ -16,7 +16,7 @@ config VIDEO_DAVINCI_VPIF_DISPLAY
config VIDEO_DAVINCI_VPIF_CAPTURE
tristate "TI DaVinci VPIF video capture driver"
- depends on VIDEO_DEV
+ depends on VIDEO_V4L2
depends on ARCH_DAVINCI || COMPILE_TEST
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
@@ -75,7 +75,7 @@ config VIDEO_DM365_ISIF
config VIDEO_DAVINCI_VPBE_DISPLAY
tristate "TI DaVinci VPBE V4L2-Display driver"
- depends on ARCH_DAVINCI
+ depends on VIDEO_V4L2 && ARCH_DAVINCI
depends on HAS_DMA
select VIDEOBUF2_DMA_CONTIG
help
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index 0abdb17fb19c..fa572aacdb3f 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -466,18 +466,6 @@ static inline void gsc_hw_clear_irq(struct gsc_dev *dev, int irq)
writel(cfg, dev->regs + GSC_IRQ);
}
-static inline void gsc_lock(struct vb2_queue *vq)
-{
- struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
- mutex_lock(&ctx->gsc_dev->lock);
-}
-
-static inline void gsc_unlock(struct vb2_queue *vq)
-{
- struct gsc_ctx *ctx = vb2_get_drv_priv(vq);
- mutex_unlock(&ctx->gsc_dev->lock);
-}
-
static inline bool gsc_ctx_state_is_set(u32 mask, struct gsc_ctx *ctx)
{
unsigned long flags;
diff --git a/drivers/media/platform/exynos-gsc/gsc-m2m.c b/drivers/media/platform/exynos-gsc/gsc-m2m.c
index 74e1de637e8f..d5cffef2e227 100644
--- a/drivers/media/platform/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/exynos-gsc/gsc-m2m.c
@@ -267,8 +267,8 @@ static struct vb2_ops gsc_m2m_qops = {
.queue_setup = gsc_m2m_queue_setup,
.buf_prepare = gsc_m2m_buf_prepare,
.buf_queue = gsc_m2m_buf_queue,
- .wait_prepare = gsc_unlock,
- .wait_finish = gsc_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.stop_streaming = gsc_m2m_stop_streaming,
.start_streaming = gsc_m2m_start_streaming,
};
@@ -590,6 +590,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->gsc_dev->lock;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -603,6 +604,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->gsc_dev->lock;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig
index 6265d36adceb..4bf5bd1e90d6 100644
--- a/drivers/media/platform/marvell-ccic/Kconfig
+++ b/drivers/media/platform/marvell-ccic/Kconfig
@@ -5,6 +5,7 @@ config VIDEO_CAFE_CCIC
select VIDEO_OV7670
select VIDEOBUF2_VMALLOC
select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_DMA_SG
---help---
This is a video4linux2 driver for the Marvell 88ALP01 integrated
CMOS camera controller. This is the controller found on first-
@@ -13,7 +14,7 @@ config VIDEO_CAFE_CCIC
config VIDEO_MMP_CAMERA
tristate "Marvell Armada 610 integrated camera controller support"
depends on ARCH_MMP && I2C && VIDEO_V4L2
- depends on HAS_DMA
+ depends on HAS_DMA && BROKEN
select VIDEO_OV7670
select I2C_GPIO
select VIDEOBUF2_DMA_SG
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 193373ff268d..dd5b1415f974 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -1913,7 +1913,6 @@ int mccic_register(struct mcam_camera *cam)
mutex_lock(&cam->s_mutex);
cam->vdev = mcam_v4l_template;
- cam->vdev.debug = 0;
cam->vdev.v4l2_dev = &cam->v4l2_dev;
video_set_drvdata(&cam->vdev, cam);
ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 51c2129bdcc6..deca80903c3a 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -220,6 +220,9 @@ static u32 isp_xclk_calc_divider(unsigned long *rate, unsigned long parent_rate)
return ISPTCTRL_CTRL_DIV_BYPASS;
}
+ if (*rate == 0)
+ *rate = 1;
+
divider = DIV_ROUND_CLOSEST(parent_rate, *rate);
if (divider >= ISPTCTRL_CTRL_DIV_BYPASS)
divider = ISPTCTRL_CTRL_DIV_BYPASS - 1;
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index aa40c8269ab8..54479d60cc0d 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -536,24 +536,12 @@ static void buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&camif->slock, flags);
}
-static void camif_lock(struct vb2_queue *vq)
-{
- struct camif_vp *vp = vb2_get_drv_priv(vq);
- mutex_lock(&vp->camif->lock);
-}
-
-static void camif_unlock(struct vb2_queue *vq)
-{
- struct camif_vp *vp = vb2_get_drv_priv(vq);
- mutex_unlock(&vp->camif->lock);
-}
-
static const struct vb2_ops s3c_camif_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .wait_prepare = camif_unlock,
- .wait_finish = camif_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
@@ -1161,6 +1149,7 @@ int s3c_camif_register_video_node(struct camif_dev *camif, int idx)
q->buf_struct_size = sizeof(struct camif_buffer);
q->drv_priv = vp;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &vp->camif->lock;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index 47ba8fbb0426..ec3e1248923d 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -12,7 +12,6 @@
#include <linux/module.h>
#include <linux/fs.h>
-#include <linux/version.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/slab.h>
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index fbfdf03b9054..8e44a59d8ec2 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -810,6 +810,7 @@ static int s5p_mfc_open(struct file *file)
q = &ctx->vq_dst;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
q->drv_priv = &ctx->fh;
+ q->lock = &dev->mfc_mutex;
if (vdev == dev->vfd_dec) {
q->io_modes = VB2_MMAP;
q->ops = get_dec_queue_ops();
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index c6c3452ccca1..aebe4fd7f03a 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -18,7 +18,6 @@
#include <linux/platform_device.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/version.h>
#include <linux/videodev2.h>
#include <linux/workqueue.h>
#include <media/v4l2-ctrls.h>
@@ -813,7 +812,7 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,
unsigned long flags;
switch (cmd->cmd) {
- case V4L2_ENC_CMD_STOP:
+ case V4L2_DEC_CMD_STOP:
if (cmd->flags != 0)
return -EINVAL;
@@ -944,22 +943,6 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
return 0;
}
-static void s5p_mfc_unlock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static void s5p_mfc_lock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_lock(&dev->mfc_mutex);
-}
-
static int s5p_mfc_buf_init(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
@@ -1107,8 +1090,8 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
static struct vb2_ops s5p_mfc_dec_qops = {
.queue_setup = s5p_mfc_queue_setup,
- .wait_prepare = s5p_mfc_unlock,
- .wait_finish = s5p_mfc_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.buf_init = s5p_mfc_buf_init,
.start_streaming = s5p_mfc_start_streaming,
.stop_streaming = s5p_mfc_stop_streaming,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index bd64f1dcbdb5..e65993f4b901 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -19,7 +19,6 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/sched.h>
-#include <linux/version.h>
#include <linux/videodev2.h>
#include <media/v4l2-event.h>
#include <linux/workqueue.h>
@@ -1867,22 +1866,6 @@ static int s5p_mfc_queue_setup(struct vb2_queue *vq,
return 0;
}
-static void s5p_mfc_unlock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_unlock(&dev->mfc_mutex);
-}
-
-static void s5p_mfc_lock(struct vb2_queue *q)
-{
- struct s5p_mfc_ctx *ctx = fh_to_ctx(q->drv_priv);
- struct s5p_mfc_dev *dev = ctx->dev;
-
- mutex_lock(&dev->mfc_mutex);
-}
-
static int s5p_mfc_buf_init(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
@@ -2052,8 +2035,8 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
static struct vb2_ops s5p_mfc_enc_qops = {
.queue_setup = s5p_mfc_queue_setup,
- .wait_prepare = s5p_mfc_unlock,
- .wait_finish = s5p_mfc_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.buf_init = s5p_mfc_buf_init,
.buf_prepare = s5p_mfc_buf_prepare,
.start_streaming = s5p_mfc_start_streaming,
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 9aea179943ce..d826c58b5d53 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1340,11 +1340,7 @@ static int s5p_mfc_init_decode_v6(struct s5p_mfc_ctx *ctx)
/* FMO_ASO_CTRL - 0: Enable, 1: Disable */
reg |= (fmo_aso_ctrl << S5P_FIMV_D_OPT_FMO_ASO_CTRL_MASK_V6);
- /* When user sets desplay_delay to 0,
- * It works as "display_delay enable" and delay set to 0.
- * If user wants display_delay disable, It should be
- * set to negative value. */
- if (ctx->display_delay >= 0) {
+ if (ctx->display_delay_enable) {
reg |= (0x1 << S5P_FIMV_D_OPT_DDELAY_EN_SHIFT_V6);
writel(ctx->display_delay, mfc_regs->d_display_delay);
}
diff --git a/drivers/media/platform/s5p-tv/mixer_video.c b/drivers/media/platform/s5p-tv/mixer_video.c
index b4d2696501e4..72d4f2e1efc0 100644
--- a/drivers/media/platform/s5p-tv/mixer_video.c
+++ b/drivers/media/platform/s5p-tv/mixer_video.c
@@ -926,22 +926,6 @@ static void buf_queue(struct vb2_buffer *vb)
mxr_dbg(mdev, "queuing buffer\n");
}
-static void wait_lock(struct vb2_queue *vq)
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
-
- mxr_dbg(layer->mdev, "%s\n", __func__);
- mutex_lock(&layer->mutex);
-}
-
-static void wait_unlock(struct vb2_queue *vq)
-{
- struct mxr_layer *layer = vb2_get_drv_priv(vq);
-
- mxr_dbg(layer->mdev, "%s\n", __func__);
- mutex_unlock(&layer->mutex);
-}
-
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct mxr_layer *layer = vb2_get_drv_priv(vq);
@@ -1040,8 +1024,8 @@ static void stop_streaming(struct vb2_queue *vq)
static struct vb2_ops mxr_video_qops = {
.queue_setup = queue_setup,
.buf_queue = buf_queue,
- .wait_prepare = wait_unlock,
- .wait_finish = wait_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
@@ -1122,6 +1106,7 @@ struct mxr_layer *mxr_base_layer_create(struct mxr_device *mdev,
.ops = &mxr_video_qops,
.min_buffers_needed = 1,
.mem_ops = &vb2_dma_contig_memops,
+ .lock = &layer->mutex,
};
return layer;
diff --git a/drivers/media/platform/sh_veu.c b/drivers/media/platform/sh_veu.c
index aaa1f6f25a29..a901b6248557 100644
--- a/drivers/media/platform/sh_veu.c
+++ b/drivers/media/platform/sh_veu.c
@@ -242,20 +242,6 @@ static void sh_veu_job_abort(void *priv)
veu->aborting = true;
}
-static void sh_veu_lock(void *priv)
-{
- struct sh_veu_dev *veu = priv;
-
- mutex_lock(&veu->fop_lock);
-}
-
-static void sh_veu_unlock(void *priv)
-{
- struct sh_veu_dev *veu = priv;
-
- mutex_unlock(&veu->fop_lock);
-}
-
static void sh_veu_process(struct sh_veu_dev *veu,
struct vb2_buffer *src_buf,
struct vb2_buffer *dst_buf)
@@ -950,36 +936,28 @@ static void sh_veu_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(veu->m2m_ctx, vb);
}
-static void sh_veu_wait_prepare(struct vb2_queue *q)
-{
- sh_veu_unlock(vb2_get_drv_priv(q));
-}
-
-static void sh_veu_wait_finish(struct vb2_queue *q)
-{
- sh_veu_lock(vb2_get_drv_priv(q));
-}
-
static const struct vb2_ops sh_veu_qops = {
.queue_setup = sh_veu_queue_setup,
.buf_prepare = sh_veu_buf_prepare,
.buf_queue = sh_veu_buf_queue,
- .wait_prepare = sh_veu_wait_prepare,
- .wait_finish = sh_veu_wait_finish,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
{
+ struct sh_veu_dev *veu = priv;
int ret;
memset(src_vq, 0, sizeof(*src_vq));
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
src_vq->io_modes = VB2_MMAP | VB2_USERPTR;
- src_vq->drv_priv = priv;
+ src_vq->drv_priv = veu;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
src_vq->ops = &sh_veu_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->lock = &veu->fop_lock;
ret = vb2_queue_init(src_vq);
if (ret < 0)
@@ -988,10 +966,11 @@ static int sh_veu_queue_init(void *priv, struct vb2_queue *src_vq,
memset(dst_vq, 0, sizeof(*dst_vq));
dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
dst_vq->io_modes = VB2_MMAP | VB2_USERPTR;
- dst_vq->drv_priv = priv;
+ dst_vq->drv_priv = veu;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
dst_vq->ops = &sh_veu_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->lock = &veu->fop_lock;
return vb2_queue_init(dst_vq);
}
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index 6d885239b16a..8526bf5c8429 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -455,8 +455,8 @@ static struct vb2_ops isi_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = soc_camera_unlock,
- .wait_finish = soc_camera_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------
@@ -465,6 +465,8 @@ static struct vb2_ops isi_video_qops = {
static int isi_camera_init_videobuf(struct vb2_queue *q,
struct soc_camera_device *icd)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP;
q->drv_priv = icd;
@@ -472,6 +474,7 @@ static int isi_camera_init_videobuf(struct vb2_queue *q,
q->ops = &isi_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &ici->host_lock;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 0b3299dee05d..3435fd2ca8ec 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -435,14 +435,16 @@ static struct vb2_ops mx3_videobuf_ops = {
.buf_queue = mx3_videobuf_queue,
.buf_cleanup = mx3_videobuf_release,
.buf_init = mx3_videobuf_init,
- .wait_prepare = soc_camera_unlock,
- .wait_finish = soc_camera_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.stop_streaming = mx3_stop_streaming,
};
static int mx3_camera_init_videobuf(struct vb2_queue *q,
struct soc_camera_device *icd)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR;
q->drv_priv = icd;
@@ -450,6 +452,7 @@ static int mx3_camera_init_videobuf(struct vb2_queue *q,
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct mx3_camera_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &ici->host_lock;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 9f1473c0a0cf..279ab9f6ae38 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -804,62 +804,26 @@ error:
vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
}
-static void rcar_vin_videobuf_release(struct vb2_buffer *vb)
+/*
+ * Wait for capture to stop and all in-flight buffers to be finished with by
+ * the video hardware. This must be called under &priv->lock
+ *
+ */
+static void rcar_vin_wait_stop_streaming(struct rcar_vin_priv *priv)
{
- struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct rcar_vin_priv *priv = ici->priv;
- unsigned int i;
- int buf_in_use = 0;
-
- spin_lock_irq(&priv->lock);
-
- /* Is the buffer in use by the VIN hardware? */
- for (i = 0; i < MAX_BUFFER_NUM; i++) {
- if (priv->queue_buf[i] == vb) {
- buf_in_use = 1;
- break;
- }
- }
-
- if (buf_in_use) {
- while (priv->state != STOPPED) {
-
- /* issue stop if running */
- if (priv->state == RUNNING)
- rcar_vin_request_capture_stop(priv);
+ while (priv->state != STOPPED) {
+ /* issue stop if running */
+ if (priv->state == RUNNING)
+ rcar_vin_request_capture_stop(priv);
- /* wait until capturing has been stopped */
- if (priv->state == STOPPING) {
- priv->request_to_stop = true;
- spin_unlock_irq(&priv->lock);
- wait_for_completion(&priv->capture_stop);
- spin_lock_irq(&priv->lock);
- }
- }
- /*
- * Capturing has now stopped. The buffer we have been asked
- * to release could be any of the current buffers in use, so
- * release all buffers that are in use by HW
- */
- for (i = 0; i < MAX_BUFFER_NUM; i++) {
- if (priv->queue_buf[i]) {
- vb2_buffer_done(priv->queue_buf[i],
- VB2_BUF_STATE_ERROR);
- priv->queue_buf[i] = NULL;
- }
+ /* wait until capturing has been stopped */
+ if (priv->state == STOPPING) {
+ priv->request_to_stop = true;
+ spin_unlock_irq(&priv->lock);
+ wait_for_completion(&priv->capture_stop);
+ spin_lock_irq(&priv->lock);
}
- } else {
- list_del_init(to_buf_list(vb));
}
-
- spin_unlock_irq(&priv->lock);
-}
-
-static int rcar_vin_videobuf_init(struct vb2_buffer *vb)
-{
- INIT_LIST_HEAD(to_buf_list(vb));
- return 0;
}
static void rcar_vin_stop_streaming(struct vb2_queue *vq)
@@ -868,21 +832,34 @@ static void rcar_vin_stop_streaming(struct vb2_queue *vq)
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
struct rcar_vin_priv *priv = ici->priv;
struct list_head *buf_head, *tmp;
+ int i;
spin_lock_irq(&priv->lock);
- list_for_each_safe(buf_head, tmp, &priv->capture)
+ rcar_vin_wait_stop_streaming(priv);
+
+ for (i = 0; i < MAX_BUFFER_NUM; i++) {
+ if (priv->queue_buf[i]) {
+ vb2_buffer_done(priv->queue_buf[i],
+ VB2_BUF_STATE_ERROR);
+ priv->queue_buf[i] = NULL;
+ }
+ }
+
+ list_for_each_safe(buf_head, tmp, &priv->capture) {
+ vb2_buffer_done(&list_entry(buf_head,
+ struct rcar_vin_buffer, list)->vb,
+ VB2_BUF_STATE_ERROR);
list_del_init(buf_head);
+ }
spin_unlock_irq(&priv->lock);
}
static struct vb2_ops rcar_vin_vb2_ops = {
.queue_setup = rcar_vin_videobuf_setup,
- .buf_init = rcar_vin_videobuf_init,
- .buf_cleanup = rcar_vin_videobuf_release,
.buf_queue = rcar_vin_videobuf_queue,
.stop_streaming = rcar_vin_stop_streaming,
- .wait_prepare = soc_camera_unlock,
- .wait_finish = soc_camera_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
static irqreturn_t rcar_vin_irq(int irq, void *data)
@@ -1808,6 +1785,8 @@ static int rcar_vin_querycap(struct soc_camera_host *ici,
static int rcar_vin_init_videobuf2(struct vb2_queue *vq,
struct soc_camera_device *icd)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vq->io_modes = VB2_MMAP | VB2_USERPTR;
vq->drv_priv = icd;
@@ -1815,6 +1794,7 @@ static int rcar_vin_init_videobuf2(struct vb2_queue *vq,
vq->mem_ops = &vb2_dma_contig_memops;
vq->buf_struct_size = sizeof(struct rcar_vin_buffer);
vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ vq->lock = &ici->host_lock;
return vb2_queue_init(vq);
}
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 71787702d4a2..9ce202f53934 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -496,8 +496,8 @@ static struct vb2_ops sh_mobile_ceu_videobuf_ops = {
.buf_queue = sh_mobile_ceu_videobuf_queue,
.buf_cleanup = sh_mobile_ceu_videobuf_release,
.buf_init = sh_mobile_ceu_videobuf_init,
- .wait_prepare = soc_camera_unlock,
- .wait_finish = soc_camera_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.stop_streaming = sh_mobile_ceu_stop_streaming,
};
@@ -1661,6 +1661,8 @@ static int sh_mobile_ceu_querycap(struct soc_camera_host *ici,
static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
struct soc_camera_device *icd)
{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
q->io_modes = VB2_MMAP | VB2_USERPTR;
q->drv_priv = icd;
@@ -1668,6 +1670,7 @@ static int sh_mobile_ceu_init_videobuf(struct vb2_queue *q,
q->mem_ops = &vb2_dma_contig_memops;
q->buf_struct_size = sizeof(struct sh_mobile_ceu_buffer);
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &ici->host_lock;
return vb2_queue_init(q);
}
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index b3db51c82bde..cee7b56f8404 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -843,22 +843,6 @@ static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
return res;
}
-void soc_camera_lock(struct vb2_queue *vq)
-{
- struct soc_camera_device *icd = vb2_get_drv_priv(vq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- mutex_lock(&ici->host_lock);
-}
-EXPORT_SYMBOL(soc_camera_lock);
-
-void soc_camera_unlock(struct vb2_queue *vq)
-{
- struct soc_camera_device *icd = vb2_get_drv_priv(vq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- mutex_unlock(&ici->host_lock);
-}
-EXPORT_SYMBOL(soc_camera_unlock);
-
static struct v4l2_file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
@@ -1813,8 +1797,6 @@ eadddev:
mutex_unlock(&ici->clk_lock);
}
eadd:
- video_device_release(icd->vdev);
- icd->vdev = NULL;
if (icd->vdev) {
video_device_release(icd->vdev);
icd->vdev = NULL;
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index d628d1a7cf9e..c44760b705da 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -25,6 +25,7 @@
#include <linux/io.h>
#include <linux/ioctl.h>
#include <linux/module.h>
+#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sched.h>
@@ -74,7 +75,7 @@
#define VPE_DEF_BUFS_PER_JOB 1 /* default one buffer per batch job */
/*
- * each VPE context can need up to 3 config desciptors, 7 input descriptors,
+ * each VPE context can need up to 3 config descriptors, 7 input descriptors,
* 3 output descriptors, and 10 control descriptors
*/
#define VPE_DESC_LIST_SIZE (10 * VPDMA_DTD_DESC_SIZE + \
@@ -373,7 +374,6 @@ struct vpe_dev {
struct vpe_ctx {
struct v4l2_fh fh;
struct vpe_dev *dev;
- struct v4l2_m2m_ctx *m2m_ctx;
struct v4l2_ctrl_handler hdl;
unsigned int field; /* current field */
@@ -887,10 +887,10 @@ static int job_ready(void *priv)
if (ctx->deinterlacing && ctx->src_vbs[2] == NULL)
needed += 2; /* need additional two most recent fields */
- if (v4l2_m2m_num_src_bufs_ready(ctx->m2m_ctx) < needed)
+ if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < needed)
return 0;
- if (v4l2_m2m_num_dst_bufs_ready(ctx->m2m_ctx) < needed)
+ if (v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < needed)
return 0;
return 1;
@@ -1100,15 +1100,15 @@ static void device_run(void *priv)
struct vpe_q_data *d_q_data = &ctx->q_data[Q_DATA_DST];
if (ctx->deinterlacing && ctx->src_vbs[2] == NULL) {
- ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ ctx->src_vbs[2] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
WARN_ON(ctx->src_vbs[2] == NULL);
- ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ ctx->src_vbs[1] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
WARN_ON(ctx->src_vbs[1] == NULL);
}
- ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ ctx->src_vbs[0] = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
WARN_ON(ctx->src_vbs[0] == NULL);
- ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ ctx->dst_vb = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
WARN_ON(ctx->dst_vb == NULL);
/* config descriptors */
@@ -1334,7 +1334,7 @@ static irqreturn_t vpe_irq(int irq_vpe, void *data)
finished:
vpe_dbg(ctx->dev, "finishing transaction\n");
ctx->bufs_completed = 0;
- v4l2_m2m_job_finish(dev->m2m_dev, ctx->m2m_ctx);
+ v4l2_m2m_job_finish(dev->m2m_dev, ctx->fh.m2m_ctx);
handled:
return IRQ_HANDLED;
}
@@ -1395,7 +1395,7 @@ static int vpe_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
struct vpe_q_data *q_data;
int i;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -1527,7 +1527,7 @@ static int __vpe_s_fmt(struct vpe_ctx *ctx, struct v4l2_format *f)
struct vb2_queue *vq;
int i;
- vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
return -EINVAL;
@@ -1739,52 +1739,6 @@ static int vpe_s_selection(struct file *file, void *fh,
return set_srcdst_params(ctx);
}
-static int vpe_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *reqbufs)
-{
- struct vpe_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
-}
-
-static int vpe_querybuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct vpe_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vpe_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct vpe_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vpe_dqbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct vpe_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
-}
-
-static int vpe_streamon(struct file *file, void *priv, enum v4l2_buf_type type)
-{
- struct vpe_ctx *ctx = file2ctx(file);
-
- return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
-}
-
-static int vpe_streamoff(struct file *file, void *priv, enum v4l2_buf_type type)
-{
- struct vpe_ctx *ctx = file2ctx(file);
-
- vpe_dump_regs(ctx->dev);
- vpdma_dump_regs(ctx->dev->vpdma);
-
- return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
-}
-
/*
* defines number of buffers/frames a context can process with VPE before
* switching to a different context. default value is 1 buffer per context
@@ -1814,14 +1768,14 @@ static const struct v4l2_ctrl_ops vpe_ctrl_ops = {
};
static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
- .vidioc_querycap = vpe_querycap,
+ .vidioc_querycap = vpe_querycap,
- .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt,
+ .vidioc_enum_fmt_vid_cap_mplane = vpe_enum_fmt,
.vidioc_g_fmt_vid_cap_mplane = vpe_g_fmt,
.vidioc_try_fmt_vid_cap_mplane = vpe_try_fmt,
.vidioc_s_fmt_vid_cap_mplane = vpe_s_fmt,
- .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt,
+ .vidioc_enum_fmt_vid_out_mplane = vpe_enum_fmt,
.vidioc_g_fmt_vid_out_mplane = vpe_g_fmt,
.vidioc_try_fmt_vid_out_mplane = vpe_try_fmt,
.vidioc_s_fmt_vid_out_mplane = vpe_s_fmt,
@@ -1829,16 +1783,15 @@ static const struct v4l2_ioctl_ops vpe_ioctl_ops = {
.vidioc_g_selection = vpe_g_selection,
.vidioc_s_selection = vpe_s_selection,
- .vidioc_reqbufs = vpe_reqbufs,
- .vidioc_querybuf = vpe_querybuf,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
- .vidioc_qbuf = vpe_qbuf,
- .vidioc_dqbuf = vpe_dqbuf,
-
- .vidioc_streamon = vpe_streamon,
- .vidioc_streamoff = vpe_streamoff,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
/*
@@ -1910,33 +1863,40 @@ static int vpe_buf_prepare(struct vb2_buffer *vb)
static void vpe_buf_queue(struct vb2_buffer *vb)
{
struct vpe_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
-static void vpe_wait_prepare(struct vb2_queue *q)
+static int vpe_start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct vpe_ctx *ctx = vb2_get_drv_priv(q);
- vpe_unlock(ctx);
+ /* currently we do nothing here */
+
+ return 0;
}
-static void vpe_wait_finish(struct vb2_queue *q)
+static void vpe_stop_streaming(struct vb2_queue *q)
{
struct vpe_ctx *ctx = vb2_get_drv_priv(q);
- vpe_lock(ctx);
+
+ vpe_dump_regs(ctx->dev);
+ vpdma_dump_regs(ctx->dev->vpdma);
}
static struct vb2_ops vpe_qops = {
.queue_setup = vpe_queue_setup,
.buf_prepare = vpe_buf_prepare,
.buf_queue = vpe_buf_queue,
- .wait_prepare = vpe_wait_prepare,
- .wait_finish = vpe_wait_finish,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = vpe_start_streaming,
+ .stop_streaming = vpe_stop_streaming,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
{
struct vpe_ctx *ctx = priv;
+ struct vpe_dev *dev = ctx->dev;
int ret;
memset(src_vq, 0, sizeof(*src_vq));
@@ -1947,6 +1907,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &vpe_qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &dev->dev_mutex;
ret = vb2_queue_init(src_vq);
if (ret)
@@ -1960,6 +1921,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->ops = &vpe_qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &dev->dev_mutex;
return vb2_queue_init(dst_vq);
}
@@ -1981,9 +1943,9 @@ static const struct v4l2_ctrl_config vpe_bufs_per_job = {
static int vpe_open(struct file *file)
{
struct vpe_dev *dev = video_drvdata(file);
- struct vpe_ctx *ctx = NULL;
struct vpe_q_data *s_q_data;
struct v4l2_ctrl_handler *hdl;
+ struct vpe_ctx *ctx;
int ret;
vpe_dbg(dev, "vpe_open\n");
@@ -2056,10 +2018,10 @@ static int vpe_open(struct file *file)
if (ret)
goto exit_fh;
- ctx->m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(dev->m2m_dev, ctx, &queue_init);
- if (IS_ERR(ctx->m2m_ctx)) {
- ret = PTR_ERR(ctx->m2m_ctx);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
goto exit_fh;
}
@@ -2078,7 +2040,7 @@ static int vpe_open(struct file *file)
ctx->load_mmrs = true;
vpe_dbg(dev, "created instance %p, m2m_ctx: %p\n",
- ctx, ctx->m2m_ctx);
+ ctx, ctx->fh.m2m_ctx);
mutex_unlock(&dev->dev_mutex);
@@ -2116,7 +2078,7 @@ static int vpe_release(struct file *file)
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
v4l2_ctrl_handler_free(&ctx->hdl);
- v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
kfree(ctx);
@@ -2133,39 +2095,13 @@ static int vpe_release(struct file *file)
return 0;
}
-static unsigned int vpe_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct vpe_ctx *ctx = file2ctx(file);
- struct vpe_dev *dev = ctx->dev;
- int ret;
-
- mutex_lock(&dev->dev_mutex);
- ret = v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
- mutex_unlock(&dev->dev_mutex);
- return ret;
-}
-
-static int vpe_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct vpe_ctx *ctx = file2ctx(file);
- struct vpe_dev *dev = ctx->dev;
- int ret;
-
- if (mutex_lock_interruptible(&dev->dev_mutex))
- return -ERESTARTSYS;
- ret = v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
- mutex_unlock(&dev->dev_mutex);
- return ret;
-}
-
static const struct v4l2_file_operations vpe_fops = {
.owner = THIS_MODULE,
.open = vpe_open,
.release = vpe_release,
- .poll = vpe_poll,
+ .poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
- .mmap = vpe_mmap,
+ .mmap = v4l2_m2m_fop_mmap,
};
static struct video_device vpe_videodev = {
@@ -2367,8 +2303,6 @@ static const struct of_device_id vpe_of_match[] = {
},
{},
};
-#else
-#define vpe_of_match NULL
#endif
static struct platform_driver vpe_pdrv = {
@@ -2376,7 +2310,7 @@ static struct platform_driver vpe_pdrv = {
.remove = vpe_remove,
.driver = {
.name = VPE_MODULE_NAME,
- .of_match_table = vpe_of_match,
+ .of_match_table = of_match_ptr(vpe_of_match),
},
};
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index 857e7866e8bc..32a798f2d953 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -689,7 +689,7 @@ static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = {
static const char * const vivid_ctrl_colorspace_strings[] = {
"SMPTE 170M",
- "REC 709",
+ "Rec. 709",
"sRGB",
"AdobeRGB",
"BT.2020",
@@ -716,7 +716,7 @@ static const char * const vivid_ctrl_ycbcr_enc_strings[] = {
"xvYCC 601",
"xvYCC 709",
"sYCC",
- "BT.2020 Non-Constant Luminance",
+ "BT.2020",
"BT.2020 Constant Luminance",
"SMPTE 240M",
NULL,
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
index fc9c6536ba02..34493f435d5a 100644
--- a/drivers/media/platform/vivid/vivid-tpg.c
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -352,13 +352,14 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
{ COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
};
bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
+ unsigned y_offset = full ? 0 : 16;
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);
+ rgb2ycbcr(full ? bt601_full : bt601, r, g, b, y_offset, y, cb, cr);
break;
case V4L2_YCBCR_ENC_BT2020:
rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
@@ -384,7 +385,7 @@ static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
case V4L2_YCBCR_ENC_709:
case V4L2_YCBCR_ENC_XV709:
default:
- rgb2ycbcr(full ? rec709_full : rec709, r, g, b, 0, y, cb, cr);
+ rgb2ycbcr(full ? rec709_full : rec709, r, g, b, y_offset, y, cb, cr);
break;
}
}
@@ -439,13 +440,14 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
{ COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
};
bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
+ unsigned y_offset = full ? 0 : 16;
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);
+ ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, y_offset, r, g, b);
break;
case V4L2_YCBCR_ENC_BT2020:
ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
@@ -480,7 +482,7 @@ static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
case V4L2_YCBCR_ENC_709:
case V4L2_YCBCR_ENC_XV709:
default:
- ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, 16, r, g, b);
+ ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, y_offset, r, g, b);
break;
}
}
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
index 9dc463a40ed3..bd8b1c760b3f 100644
--- a/drivers/media/platform/vivid/vivid-tpg.h
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -20,7 +20,6 @@
#ifndef _VIVID_TPG_H_
#define _VIVID_TPG_H_
-#include <linux/version.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/random.h>
diff --git a/drivers/media/platform/vsp1/vsp1.h b/drivers/media/platform/vsp1/vsp1.h
index 12467191dff4..989e96f7e360 100644
--- a/drivers/media/platform/vsp1/vsp1.h
+++ b/drivers/media/platform/vsp1/vsp1.h
@@ -16,7 +16,6 @@
#include <linux/io.h>
#include <linux/list.h>
#include <linux/mutex.h>
-#include <linux/platform_data/vsp1.h>
#include <media/media-device.h>
#include <media/v4l2-device.h>
@@ -40,9 +39,20 @@ struct vsp1_uds;
#define VSP1_MAX_UDS 3
#define VSP1_MAX_WPF 4
+#define VSP1_HAS_LIF (1 << 0)
+#define VSP1_HAS_LUT (1 << 1)
+#define VSP1_HAS_SRU (1 << 2)
+
+struct vsp1_platform_data {
+ unsigned int features;
+ unsigned int rpf_count;
+ unsigned int uds_count;
+ unsigned int wpf_count;
+};
+
struct vsp1_device {
struct device *dev;
- struct vsp1_platform_data *pdata;
+ struct vsp1_platform_data pdata;
void __iomem *mmio;
struct clk *clock;
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index b21f381a9862..401e2b77a0b6 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -20,7 +20,7 @@
#include "vsp1_bru.h"
#include "vsp1_rwpf.h"
-#define BRU_MIN_SIZE 4U
+#define BRU_MIN_SIZE 1U
#define BRU_MAX_SIZE 8190U
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index 5eb16e87d53f..913485a90e97 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -40,7 +40,7 @@ static irqreturn_t vsp1_irq_handler(int irq, void *data)
irqreturn_t ret = IRQ_NONE;
unsigned int i;
- for (i = 0; i < vsp1->pdata->wpf_count; ++i) {
+ for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
struct vsp1_rwpf *wpf = vsp1->wpf[i];
struct vsp1_pipeline *pipe;
u32 status;
@@ -181,7 +181,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->hst->entity.list_dev, &vsp1->entities);
- if (vsp1->pdata->features & VSP1_HAS_LIF) {
+ if (vsp1->pdata.features & VSP1_HAS_LIF) {
vsp1->lif = vsp1_lif_create(vsp1);
if (IS_ERR(vsp1->lif)) {
ret = PTR_ERR(vsp1->lif);
@@ -191,7 +191,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->lif->entity.list_dev, &vsp1->entities);
}
- if (vsp1->pdata->features & VSP1_HAS_LUT) {
+ if (vsp1->pdata.features & VSP1_HAS_LUT) {
vsp1->lut = vsp1_lut_create(vsp1);
if (IS_ERR(vsp1->lut)) {
ret = PTR_ERR(vsp1->lut);
@@ -201,7 +201,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->lut->entity.list_dev, &vsp1->entities);
}
- for (i = 0; i < vsp1->pdata->rpf_count; ++i) {
+ for (i = 0; i < vsp1->pdata.rpf_count; ++i) {
struct vsp1_rwpf *rpf;
rpf = vsp1_rpf_create(vsp1, i);
@@ -214,7 +214,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&rpf->entity.list_dev, &vsp1->entities);
}
- if (vsp1->pdata->features & VSP1_HAS_SRU) {
+ if (vsp1->pdata.features & VSP1_HAS_SRU) {
vsp1->sru = vsp1_sru_create(vsp1);
if (IS_ERR(vsp1->sru)) {
ret = PTR_ERR(vsp1->sru);
@@ -224,7 +224,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&vsp1->sru->entity.list_dev, &vsp1->entities);
}
- for (i = 0; i < vsp1->pdata->uds_count; ++i) {
+ for (i = 0; i < vsp1->pdata.uds_count; ++i) {
struct vsp1_uds *uds;
uds = vsp1_uds_create(vsp1, i);
@@ -237,7 +237,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
list_add_tail(&uds->entity.list_dev, &vsp1->entities);
}
- for (i = 0; i < vsp1->pdata->wpf_count; ++i) {
+ for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
struct vsp1_rwpf *wpf;
wpf = vsp1_wpf_create(vsp1, i);
@@ -261,7 +261,7 @@ static int vsp1_create_entities(struct vsp1_device *vsp1)
goto done;
}
- if (vsp1->pdata->features & VSP1_HAS_LIF) {
+ if (vsp1->pdata.features & VSP1_HAS_LIF) {
ret = media_entity_create_link(
&vsp1->wpf[0]->entity.subdev.entity, RWPF_PAD_SOURCE,
&vsp1->lif->entity.subdev.entity, LIF_PAD_SINK, 0);
@@ -294,7 +294,7 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
/* Reset any channel that might be running. */
status = vsp1_read(vsp1, VI6_STATUS);
- for (i = 0; i < vsp1->pdata->wpf_count; ++i) {
+ for (i = 0; i < vsp1->pdata.wpf_count; ++i) {
unsigned int timeout;
if (!(status & VI6_STATUS_SYS_ACT(i)))
@@ -318,10 +318,10 @@ static int vsp1_device_init(struct vsp1_device *vsp1)
vsp1_write(vsp1, VI6_CLK_DCSWT, (8 << VI6_CLK_DCSWT_CSTPW_SHIFT) |
(8 << VI6_CLK_DCSWT_CSTRW_SHIFT));
- for (i = 0; i < vsp1->pdata->rpf_count; ++i)
+ for (i = 0; i < vsp1->pdata.rpf_count; ++i)
vsp1_write(vsp1, VI6_DPR_RPF_ROUTE(i), VI6_DPR_NODE_UNUSED);
- for (i = 0; i < vsp1->pdata->uds_count; ++i)
+ for (i = 0; i < vsp1->pdata.uds_count; ++i)
vsp1_write(vsp1, VI6_DPR_UDS_ROUTE(i), VI6_DPR_NODE_UNUSED);
vsp1_write(vsp1, VI6_DPR_SRU_ROUTE, VI6_DPR_NODE_UNUSED);
@@ -428,28 +428,36 @@ static const struct dev_pm_ops vsp1_pm_ops = {
* Platform Driver
*/
-static int vsp1_validate_platform_data(struct platform_device *pdev,
- struct vsp1_platform_data *pdata)
+static int vsp1_parse_dt(struct vsp1_device *vsp1)
{
- if (pdata == NULL) {
- dev_err(&pdev->dev, "missing platform data\n");
- return -EINVAL;
- }
+ struct device_node *np = vsp1->dev->of_node;
+ struct vsp1_platform_data *pdata = &vsp1->pdata;
+
+ if (of_property_read_bool(np, "renesas,has-lif"))
+ pdata->features |= VSP1_HAS_LIF;
+ if (of_property_read_bool(np, "renesas,has-lut"))
+ pdata->features |= VSP1_HAS_LUT;
+ if (of_property_read_bool(np, "renesas,has-sru"))
+ pdata->features |= VSP1_HAS_SRU;
+
+ of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count);
+ of_property_read_u32(np, "renesas,#uds", &pdata->uds_count);
+ of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count);
if (pdata->rpf_count <= 0 || pdata->rpf_count > VSP1_MAX_RPF) {
- dev_err(&pdev->dev, "invalid number of RPF (%u)\n",
+ dev_err(vsp1->dev, "invalid number of RPF (%u)\n",
pdata->rpf_count);
return -EINVAL;
}
if (pdata->uds_count <= 0 || pdata->uds_count > VSP1_MAX_UDS) {
- dev_err(&pdev->dev, "invalid number of UDS (%u)\n",
+ dev_err(vsp1->dev, "invalid number of UDS (%u)\n",
pdata->uds_count);
return -EINVAL;
}
if (pdata->wpf_count <= 0 || pdata->wpf_count > VSP1_MAX_WPF) {
- dev_err(&pdev->dev, "invalid number of WPF (%u)\n",
+ dev_err(vsp1->dev, "invalid number of WPF (%u)\n",
pdata->wpf_count);
return -EINVAL;
}
@@ -457,33 +465,6 @@ static int vsp1_validate_platform_data(struct platform_device *pdev,
return 0;
}
-static struct vsp1_platform_data *
-vsp1_get_platform_data(struct platform_device *pdev)
-{
- struct device_node *np = pdev->dev.of_node;
- struct vsp1_platform_data *pdata;
-
- if (!IS_ENABLED(CONFIG_OF) || np == NULL)
- return pdev->dev.platform_data;
-
- pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
- if (pdata == NULL)
- return NULL;
-
- if (of_property_read_bool(np, "renesas,has-lif"))
- pdata->features |= VSP1_HAS_LIF;
- if (of_property_read_bool(np, "renesas,has-lut"))
- pdata->features |= VSP1_HAS_LUT;
- if (of_property_read_bool(np, "renesas,has-sru"))
- pdata->features |= VSP1_HAS_SRU;
-
- of_property_read_u32(np, "renesas,#rpf", &pdata->rpf_count);
- of_property_read_u32(np, "renesas,#uds", &pdata->uds_count);
- of_property_read_u32(np, "renesas,#wpf", &pdata->wpf_count);
-
- return pdata;
-}
-
static int vsp1_probe(struct platform_device *pdev)
{
struct vsp1_device *vsp1;
@@ -499,11 +480,7 @@ static int vsp1_probe(struct platform_device *pdev)
mutex_init(&vsp1->lock);
INIT_LIST_HEAD(&vsp1->entities);
- vsp1->pdata = vsp1_get_platform_data(pdev);
- if (vsp1->pdata == NULL)
- return -ENODEV;
-
- ret = vsp1_validate_platform_data(pdev, vsp1->pdata);
+ ret = vsp1_parse_dt(vsp1);
if (ret < 0)
return ret;
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index 80bedc554ee3..0bc0471746c9 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -26,11 +26,6 @@
* Device Access
*/
-static inline u32 vsp1_hsit_read(struct vsp1_hsit *hsit, u32 reg)
-{
- return vsp1_read(hsit->entity.vsp1, reg);
-}
-
static inline void vsp1_hsit_write(struct vsp1_hsit *hsit, u32 reg, u32 data)
{
vsp1_write(hsit->entity.vsp1, reg, data);
diff --git a/drivers/media/platform/vsp1/vsp1_regs.h b/drivers/media/platform/vsp1/vsp1_regs.h
index 55f163d32d15..da3c573e1efc 100644
--- a/drivers/media/platform/vsp1/vsp1_regs.h
+++ b/drivers/media/platform/vsp1/vsp1_regs.h
@@ -43,12 +43,12 @@
#define VI6_DISP_IRQ_ENB 0x0078
#define VI6_DISP_IRQ_ENB_DSTE (1 << 8)
#define VI6_DISP_IRQ_ENB_MAEE (1 << 5)
-#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << ((n) + 4))
+#define VI6_DISP_IRQ_ENB_LNEE(n) (1 << (n))
#define VI6_DISP_IRQ_STA 0x007c
#define VI6_DISP_IRQ_STA_DSE (1 << 8)
#define VI6_DISP_IRQ_STA_MAE (1 << 5)
-#define VI6_DISP_IRQ_STA_LNE(n) (1 << ((n) + 4))
+#define VI6_DISP_IRQ_STA_LNE(n) (1 << (n))
#define VI6_WPF_LINE_COUNT(n) (0x0084 + (n) * 4)
#define VI6_WPF_LINE_COUNT_MASK (0x1fffff << 0)
diff --git a/drivers/media/platform/vsp1/vsp1_rpf.c b/drivers/media/platform/vsp1/vsp1_rpf.c
index d14d26b718ef..3294529a3108 100644
--- a/drivers/media/platform/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rpf.c
@@ -106,11 +106,22 @@ static int rpf_s_stream(struct v4l2_subdev *subdev, int enable)
+ crop->left * fmtinfo->bpp[0] / 8;
pstride = format->plane_fmt[0].bytesperline
<< VI6_RPF_SRCM_PSTRIDE_Y_SHIFT;
+
+ vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
+ rpf->buf_addr[0] + rpf->offsets[0]);
+
if (format->num_planes > 1) {
rpf->offsets[1] = crop->top * format->plane_fmt[1].bytesperline
+ crop->left * fmtinfo->bpp[1] / 8;
pstride |= format->plane_fmt[1].bytesperline
<< VI6_RPF_SRCM_PSTRIDE_C_SHIFT;
+
+ vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C0,
+ rpf->buf_addr[1] + rpf->offsets[1]);
+
+ if (format->num_planes > 2)
+ vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_C1,
+ rpf->buf_addr[2] + rpf->offsets[1]);
}
vsp1_rpf_write(rpf, VI6_RPF_SRCM_PSTRIDE, pstride);
@@ -179,6 +190,13 @@ static void rpf_vdev_queue(struct vsp1_video *video,
struct vsp1_video_buffer *buf)
{
struct vsp1_rwpf *rpf = container_of(video, struct vsp1_rwpf, video);
+ unsigned int i;
+
+ for (i = 0; i < 3; ++i)
+ rpf->buf_addr[i] = buf->addr[i];
+
+ if (!vsp1_entity_is_streaming(&rpf->entity))
+ return;
vsp1_rpf_write(rpf, VI6_RPF_SRCM_ADDR_Y,
buf->addr[0] + rpf->offsets[0]);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.h b/drivers/media/platform/vsp1/vsp1_rwpf.h
index 28dd9e7b3838..2cf1f13d3bf9 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.h
@@ -39,6 +39,7 @@ struct vsp1_rwpf {
struct v4l2_rect crop;
unsigned int offsets[2];
+ dma_addr_t buf_addr[3];
};
static inline struct vsp1_rwpf *to_rwpf(struct v4l2_subdev *subdev)
diff --git a/drivers/media/platform/vsp1/vsp1_wpf.c b/drivers/media/platform/vsp1/vsp1_wpf.c
index 6e057762c933..1d2b3a2f1573 100644
--- a/drivers/media/platform/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/vsp1/vsp1_wpf.c
@@ -92,19 +92,20 @@ static int wpf_s_stream(struct v4l2_subdev *subdev, int enable)
return 0;
}
- /* Sources. If the pipeline has a single input configure it as the
- * master layer. Otherwise configure all inputs as sub-layers and
- * select the virtual RPF as the master layer.
+ /* Sources. If the pipeline has a single input and BRU is not used,
+ * configure it as the master layer. Otherwise configure all
+ * inputs as sub-layers and select the virtual RPF as the master
+ * layer.
*/
for (i = 0; i < pipe->num_inputs; ++i) {
struct vsp1_rwpf *input = pipe->inputs[i];
- srcrpf |= pipe->num_inputs == 1
+ srcrpf |= (!pipe->bru && pipe->num_inputs == 1)
? VI6_WPF_SRCRPF_RPF_ACT_MST(input->entity.index)
: VI6_WPF_SRCRPF_RPF_ACT_SUB(input->entity.index);
}
- if (pipe->num_inputs > 1)
+ if (pipe->bru || pipe->num_inputs > 1)
srcrpf |= VI6_WPF_SRCRPF_VIRACT_MST;
vsp1_wpf_write(wpf, VI6_WPF_SRCRPF, srcrpf);
@@ -280,7 +281,7 @@ struct vsp1_rwpf *vsp1_wpf_create(struct vsp1_device *vsp1, unsigned int index)
* except for the WPF0 source link if a LIF is present.
*/
flags = MEDIA_LNK_FL_ENABLED;
- if (!(vsp1->pdata->features & VSP1_HAS_LIF) || index != 0)
+ if (!(vsp1->pdata.features & VSP1_HAS_LIF) || index != 0)
flags |= MEDIA_LNK_FL_IMMUTABLE;
ret = media_entity_create_link(&wpf->entity.subdev.entity,
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index a739ad492e7b..ea9308796741 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -129,11 +129,11 @@ static int rtrack_s_mute_volume(struct radio_isa_card *isa, bool mute, int vol)
} else if (curvol < vol) {
outb(0x98, isa->io); /* volume up + sigstr + on */
for (; curvol < vol; curvol++)
- udelay(3000);
+ mdelay(3);
} else if (curvol > vol) {
outb(0x58, isa->io); /* volume down + sigstr + on */
for (; curvol > vol; curvol--)
- udelay(3000);
+ mdelay(3);
}
outb(0xd8, isa->io); /* volume steady + sigstr + on */
rt->curvol = vol;
diff --git a/drivers/media/radio/tea575x.c b/drivers/media/radio/tea575x.c
index f1a0867789fe..43d1ea53cb66 100644
--- a/drivers/media/radio/tea575x.c
+++ b/drivers/media/radio/tea575x.c
@@ -247,10 +247,9 @@ static int vidioc_querycap(struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_freq_bands(struct file *file, void *priv,
- struct v4l2_frequency_band *band)
+int snd_tea575x_enum_freq_bands(struct snd_tea575x *tea,
+ struct v4l2_frequency_band *band)
{
- struct snd_tea575x *tea = video_drvdata(file);
int index;
if (band->tuner != 0)
@@ -279,18 +278,25 @@ static int vidioc_enum_freq_bands(struct file *file, void *priv,
return 0;
}
+EXPORT_SYMBOL(snd_tea575x_enum_freq_bands);
-static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
+static int vidioc_enum_freq_bands(struct file *file, void *priv,
+ struct v4l2_frequency_band *band)
{
struct snd_tea575x *tea = video_drvdata(file);
+
+ return snd_tea575x_enum_freq_bands(tea, band);
+}
+
+int snd_tea575x_g_tuner(struct snd_tea575x *tea, struct v4l2_tuner *v)
+{
struct v4l2_frequency_band band_fm = { 0, };
if (v->index > 0)
return -EINVAL;
snd_tea575x_read(tea);
- vidioc_enum_freq_bands(file, priv, &band_fm);
+ snd_tea575x_enum_freq_bands(tea, &band_fm);
memset(v, 0, sizeof(*v));
strlcpy(v->name, tea->has_am ? "FM/AM" : "FM", sizeof(v->name));
@@ -304,6 +310,15 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->signal = tea->tuned ? 0xffff : 0;
return 0;
}
+EXPORT_SYMBOL(snd_tea575x_g_tuner);
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *v)
+{
+ struct snd_tea575x *tea = video_drvdata(file);
+
+ return snd_tea575x_g_tuner(tea, v);
+}
static int vidioc_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *v)
@@ -356,10 +371,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return 0;
}
-static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
- const struct v4l2_hw_freq_seek *a)
+int snd_tea575x_s_hw_freq_seek(struct file *file, struct snd_tea575x *tea,
+ const struct v4l2_hw_freq_seek *a)
{
- struct snd_tea575x *tea = video_drvdata(file);
unsigned long timeout;
int i, spacing;
@@ -442,6 +456,15 @@ static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
snd_tea575x_set_freq(tea);
return -ENODATA;
}
+EXPORT_SYMBOL(snd_tea575x_s_hw_freq_seek);
+
+static int vidioc_s_hw_freq_seek(struct file *file, void *fh,
+ const struct v4l2_hw_freq_seek *a)
+{
+ struct snd_tea575x *tea = video_drvdata(file);
+
+ return snd_tea575x_s_hw_freq_seek(file, tea, a);
+}
static int tea575x_s_ctrl(struct v4l2_ctrl *ctrl)
{
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.c b/drivers/media/radio/wl128x/fmdrv_rx.c
index 09632cb26cb6..cfaeb2417fbb 100644
--- a/drivers/media/radio/wl128x/fmdrv_rx.c
+++ b/drivers/media/radio/wl128x/fmdrv_rx.c
@@ -785,22 +785,6 @@ int fm_rx_set_rds_system(struct fmdev *fmdev, u8 rds_mode)
return 0;
}
-/* Returns current RDS operation mode */
-int fm_rx_get_rds_system(struct fmdev *fmdev, u8 *rds_mode)
-{
- if (fmdev->curr_fmmode != FM_MODE_RX)
- return -EPERM;
-
- if (rds_mode == NULL) {
- fmerr("Invalid memory\n");
- return -ENOMEM;
- }
-
- *rds_mode = fmdev->rx.rds_mode;
-
- return 0;
-}
-
/* Configures Alternate Frequency switch mode */
int fm_rx_set_af_switch(struct fmdev *fmdev, u8 af_mode)
{
diff --git a/drivers/media/radio/wl128x/fmdrv_rx.h b/drivers/media/radio/wl128x/fmdrv_rx.h
index 32add81f8d87..23922188882f 100644
--- a/drivers/media/radio/wl128x/fmdrv_rx.h
+++ b/drivers/media/radio/wl128x/fmdrv_rx.h
@@ -40,7 +40,6 @@ void fm_rx_reset_station_info(struct fmdev *);
int fm_rx_seek(struct fmdev *, u32, u32, u32);
int fm_rx_get_rds_mode(struct fmdev *, u8 *);
-int fm_rx_get_rds_system(struct fmdev *, u8 *);
int fm_rx_get_mute_mode(struct fmdev *, u8 *);
int fm_rx_get_volume(struct fmdev *, u16 *);
int fm_rx_get_band_freq_range(struct fmdev *,
diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig
index 580715c7fc5e..a896d3c83a1c 100644
--- a/drivers/media/rc/img-ir/Kconfig
+++ b/drivers/media/rc/img-ir/Kconfig
@@ -60,3 +60,18 @@ config IR_IMG_SANYO
help
Say Y here to enable support for the Sanyo protocol (used by Sanyo,
Aiwa, Chinon remotes) in the ImgTec infrared decoder block.
+
+config IR_IMG_RC5
+ bool "Philips RC5 protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the RC5 protocol in the ImgTec
+ infrared decoder block.
+
+config IR_IMG_RC6
+ bool "Philips RC6 protocol support"
+ depends on IR_IMG_HW
+ help
+ Say Y here to enable support for the RC6 protocol in the ImgTec
+ infrared decoder block.
+ Note: This version only supports mode 0.
diff --git a/drivers/media/rc/img-ir/Makefile b/drivers/media/rc/img-ir/Makefile
index 92a459d99509..8e6d458e66ad 100644
--- a/drivers/media/rc/img-ir/Makefile
+++ b/drivers/media/rc/img-ir/Makefile
@@ -6,6 +6,8 @@ img-ir-$(CONFIG_IR_IMG_JVC) += img-ir-jvc.o
img-ir-$(CONFIG_IR_IMG_SONY) += img-ir-sony.o
img-ir-$(CONFIG_IR_IMG_SHARP) += img-ir-sharp.o
img-ir-$(CONFIG_IR_IMG_SANYO) += img-ir-sanyo.o
+img-ir-$(CONFIG_IR_IMG_RC5) += img-ir-rc5.o
+img-ir-$(CONFIG_IR_IMG_RC6) += img-ir-rc6.o
img-ir-objs := $(img-ir-y)
obj-$(CONFIG_IR_IMG) += img-ir.o
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index 2fd47c9bf5d8..7bb71bc9f534 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -42,6 +42,12 @@ static struct img_ir_decoder *img_ir_decoders[] = {
#ifdef CONFIG_IR_IMG_SANYO
&img_ir_sanyo,
#endif
+#ifdef CONFIG_IR_IMG_RC5
+ &img_ir_rc5,
+#endif
+#ifdef CONFIG_IR_IMG_RC6
+ &img_ir_rc6,
+#endif
NULL
};
@@ -52,6 +58,11 @@ static struct img_ir_decoder *img_ir_decoders[] = {
#define IMG_IR_QUIRK_CODE_BROKEN 0x1 /* Decode is broken */
#define IMG_IR_QUIRK_CODE_LEN_INCR 0x2 /* Bit length needs increment */
+/*
+ * The decoder generates rapid interrupts without actually having
+ * received any new data after an incomplete IR code is decoded.
+ */
+#define IMG_IR_QUIRK_CODE_IRQ 0x4
/* functions for preprocessing timings, ensuring max is set */
@@ -542,6 +553,7 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
*/
spin_unlock_irq(&priv->lock);
del_timer_sync(&hw->end_timer);
+ del_timer_sync(&hw->suspend_timer);
spin_lock_irq(&priv->lock);
hw->stopping = false;
@@ -806,20 +818,24 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
struct img_ir_priv_hw *hw = &priv->hw;
const struct img_ir_decoder *dec = hw->decoder;
int ret = IMG_IR_SCANCODE;
- u32 scancode;
- enum rc_type protocol = RC_TYPE_UNKNOWN;
+ struct img_ir_scancode_req request;
+
+ request.protocol = RC_TYPE_UNKNOWN;
+ request.toggle = 0;
if (dec->scancode)
- ret = dec->scancode(len, raw, &protocol, &scancode, hw->enabled_protocols);
+ ret = dec->scancode(len, raw, hw->enabled_protocols, &request);
else if (len >= 32)
- scancode = (u32)raw;
+ request.scancode = (u32)raw;
else if (len < 32)
- scancode = (u32)raw & ((1 << len)-1);
+ request.scancode = (u32)raw & ((1 << len)-1);
dev_dbg(priv->dev, "data (%u bits) = %#llx\n",
len, (unsigned long long)raw);
if (ret == IMG_IR_SCANCODE) {
- dev_dbg(priv->dev, "decoded scan code %#x\n", scancode);
- rc_keydown(hw->rdev, protocol, scancode, 0);
+ dev_dbg(priv->dev, "decoded scan code %#x, toggle %u\n",
+ request.scancode, request.toggle);
+ rc_keydown(hw->rdev, request.protocol, request.scancode,
+ request.toggle);
img_ir_end_repeat(priv);
} else if (ret == IMG_IR_REPEATCODE) {
if (hw->mode == IMG_IR_M_REPEATING) {
@@ -857,6 +873,29 @@ static void img_ir_end_timer(unsigned long arg)
spin_unlock_irq(&priv->lock);
}
+/*
+ * Timer function to re-enable the current protocol after it had been
+ * cleared when invalid interrupts were generated due to a quirk in the
+ * img-ir decoder.
+ */
+static void img_ir_suspend_timer(unsigned long arg)
+{
+ struct img_ir_priv *priv = (struct img_ir_priv *)arg;
+
+ spin_lock_irq(&priv->lock);
+ /*
+ * Don't overwrite enabled valid/match IRQs if they have already been
+ * changed by e.g. a filter change.
+ */
+ if ((priv->hw.quirk_suspend_irq & IMG_IR_IRQ_EDGE) ==
+ img_ir_read(priv, IMG_IR_IRQ_ENABLE))
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE,
+ priv->hw.quirk_suspend_irq);
+ /* enable */
+ img_ir_write(priv, IMG_IR_CONTROL, priv->hw.reg_timings.ctrl);
+ spin_unlock_irq(&priv->lock);
+}
+
#ifdef CONFIG_COMMON_CLK
static void img_ir_change_frequency(struct img_ir_priv *priv,
struct clk_notifier_data *change)
@@ -922,15 +961,38 @@ void img_ir_isr_hw(struct img_ir_priv *priv, u32 irq_status)
if (!hw->decoder)
return;
+ ct = hw->decoder->control.code_type;
+
ir_status = img_ir_read(priv, IMG_IR_STATUS);
- if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)))
+ if (!(ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2))) {
+ if (!(priv->hw.ct_quirks[ct] & IMG_IR_QUIRK_CODE_IRQ) ||
+ hw->stopping)
+ return;
+ /*
+ * The below functionality is added as a work around to stop
+ * multiple Interrupts generated when an incomplete IR code is
+ * received by the decoder.
+ * The decoder generates rapid interrupts without actually
+ * having received any new data. After a single interrupt it's
+ * expected to clear up, but instead multiple interrupts are
+ * rapidly generated. only way to get out of this loop is to
+ * reset the control register after a short delay.
+ */
+ img_ir_write(priv, IMG_IR_CONTROL, 0);
+ hw->quirk_suspend_irq = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
+ img_ir_write(priv, IMG_IR_IRQ_ENABLE,
+ hw->quirk_suspend_irq & IMG_IR_IRQ_EDGE);
+
+ /* Timer activated to re-enable the protocol. */
+ mod_timer(&hw->suspend_timer,
+ jiffies + msecs_to_jiffies(5));
return;
+ }
ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2);
img_ir_write(priv, IMG_IR_STATUS, ir_status);
len = (ir_status & IMG_IR_RXDLEN) >> IMG_IR_RXDLEN_SHIFT;
/* some versions report wrong length for certain code types */
- ct = hw->decoder->control.code_type;
if (hw->ct_quirks[ct] & IMG_IR_QUIRK_CODE_LEN_INCR)
++len;
@@ -972,7 +1034,7 @@ static void img_ir_probe_hw_caps(struct img_ir_priv *priv)
hw->ct_quirks[IMG_IR_CODETYPE_PULSELEN]
|= IMG_IR_QUIRK_CODE_LEN_INCR;
hw->ct_quirks[IMG_IR_CODETYPE_BIPHASE]
- |= IMG_IR_QUIRK_CODE_BROKEN;
+ |= IMG_IR_QUIRK_CODE_IRQ;
hw->ct_quirks[IMG_IR_CODETYPE_2BITPULSEPOS]
|= IMG_IR_QUIRK_CODE_BROKEN;
}
@@ -991,6 +1053,8 @@ int img_ir_probe_hw(struct img_ir_priv *priv)
/* Set up the end timer */
setup_timer(&hw->end_timer, img_ir_end_timer, (unsigned long)priv);
+ setup_timer(&hw->suspend_timer, img_ir_suspend_timer,
+ (unsigned long)priv);
/* Register a clock notifier */
if (!IS_ERR(priv->clk)) {
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h
index 5c2b216c5fe3..91a297731661 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.h
+++ b/drivers/media/rc/img-ir/img-ir-hw.h
@@ -133,6 +133,20 @@ struct img_ir_timing_regvals {
#define IMG_IR_REPEATCODE 1 /* repeat the previous code */
/**
+ * struct img_ir_scancode_req - Scancode request data.
+ * @protocol: Protocol code of received message (defaults to
+ * RC_TYPE_UNKNOWN).
+ * @scancode: Scan code of received message (must be written by
+ * handler if IMG_IR_SCANCODE is returned).
+ * @toggle: Toggle bit (defaults to 0).
+ */
+struct img_ir_scancode_req {
+ enum rc_type protocol;
+ u32 scancode;
+ u8 toggle;
+};
+
+/**
* struct img_ir_decoder - Decoder settings for an IR protocol.
* @type: Protocol types bitmap.
* @tolerance: Timing tolerance as a percentage (default 10%).
@@ -162,8 +176,8 @@ struct img_ir_decoder {
struct img_ir_control control;
/* scancode logic */
- int (*scancode)(int len, u64 raw, enum rc_type *protocol,
- u32 *scancode, u64 enabled_protocols);
+ int (*scancode)(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request);
int (*filter)(const struct rc_scancode_filter *in,
struct img_ir_filter *out, u64 protocols);
};
@@ -173,6 +187,8 @@ extern struct img_ir_decoder img_ir_jvc;
extern struct img_ir_decoder img_ir_sony;
extern struct img_ir_decoder img_ir_sharp;
extern struct img_ir_decoder img_ir_sanyo;
+extern struct img_ir_decoder img_ir_rc5;
+extern struct img_ir_decoder img_ir_rc6;
/**
* struct img_ir_reg_timings - Reg values for decoder timings at clock rate.
@@ -204,6 +220,7 @@ enum img_ir_mode {
* @rdev: Remote control device
* @clk_nb: Notifier block for clock notify events.
* @end_timer: Timer until repeat timeout.
+ * @suspend_timer: Timer to re-enable protocol.
* @decoder: Current decoder settings.
* @enabled_protocols: Currently enabled protocols.
* @clk_hz: Current core clock rate in Hz.
@@ -214,12 +231,14 @@ enum img_ir_mode {
* @stopping: Indicates that decoder is being taken down and timers
* should not be restarted.
* @suspend_irqen: Saved IRQ enable mask over suspend.
+ * @quirk_suspend_irq: Saved IRQ enable mask over quirk suspend timer.
*/
struct img_ir_priv_hw {
unsigned int ct_quirks[4];
struct rc_dev *rdev;
struct notifier_block clk_nb;
struct timer_list end_timer;
+ struct timer_list suspend_timer;
const struct img_ir_decoder *decoder;
u64 enabled_protocols;
unsigned long clk_hz;
@@ -230,6 +249,7 @@ struct img_ir_priv_hw {
enum img_ir_mode mode;
bool stopping;
u32 suspend_irqen;
+ u32 quirk_suspend_irq;
};
static inline bool img_ir_hw_enabled(struct img_ir_priv_hw *hw)
diff --git a/drivers/media/rc/img-ir/img-ir-jvc.c b/drivers/media/rc/img-ir/img-ir-jvc.c
index a60dda8bf706..d3e2fc0bcfe1 100644
--- a/drivers/media/rc/img-ir/img-ir-jvc.c
+++ b/drivers/media/rc/img-ir/img-ir-jvc.c
@@ -12,8 +12,8 @@
#include "img-ir-hw.h"
/* Convert JVC data to a scancode */
-static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol,
- u32 *scancode, u64 enabled_protocols)
+static int img_ir_jvc_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
{
unsigned int cust, data;
@@ -23,8 +23,8 @@ static int img_ir_jvc_scancode(int len, u64 raw, enum rc_type *protocol,
cust = (raw >> 0) & 0xff;
data = (raw >> 8) & 0xff;
- *protocol = RC_TYPE_JVC;
- *scancode = cust << 8 | data;
+ request->protocol = RC_TYPE_JVC;
+ request->scancode = cust << 8 | data;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-nec.c b/drivers/media/rc/img-ir/img-ir-nec.c
index 739897549b5b..27a7ea8f1260 100644
--- a/drivers/media/rc/img-ir/img-ir-nec.c
+++ b/drivers/media/rc/img-ir/img-ir-nec.c
@@ -13,8 +13,8 @@
#include <linux/bitrev.h>
/* Convert NEC data to a scancode */
-static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
- u32 *scancode, u64 enabled_protocols)
+static int img_ir_nec_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
{
unsigned int addr, addr_inv, data, data_inv;
/* a repeat code has no data */
@@ -30,23 +30,23 @@ static int img_ir_nec_scancode(int len, u64 raw, enum rc_type *protocol,
if ((data_inv ^ data) != 0xff) {
/* 32-bit NEC (used by Apple and TiVo remotes) */
/* scan encoding: as transmitted, MSBit = first received bit */
- *scancode = bitrev8(addr) << 24 |
- bitrev8(addr_inv) << 16 |
- bitrev8(data) << 8 |
- bitrev8(data_inv);
+ request->scancode = bitrev8(addr) << 24 |
+ bitrev8(addr_inv) << 16 |
+ bitrev8(data) << 8 |
+ bitrev8(data_inv);
} else if ((addr_inv ^ addr) != 0xff) {
/* Extended NEC */
/* scan encoding: AAaaDD */
- *scancode = addr << 16 |
- addr_inv << 8 |
- data;
+ request->scancode = addr << 16 |
+ addr_inv << 8 |
+ data;
} else {
/* Normal NEC */
/* scan encoding: AADD */
- *scancode = addr << 8 |
- data;
+ request->scancode = addr << 8 |
+ data;
}
- *protocol = RC_TYPE_NEC;
+ request->protocol = RC_TYPE_NEC;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-rc5.c b/drivers/media/rc/img-ir/img-ir-rc5.c
new file mode 100644
index 000000000000..a8a28a377eee
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-rc5.c
@@ -0,0 +1,88 @@
+/*
+ * ImgTec IR Decoder setup for Philips RC-5 protocol.
+ *
+ * Copyright 2012-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert RC5 data to a scancode */
+static int img_ir_rc5_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
+{
+ unsigned int addr, cmd, tgl, start;
+
+ /* Quirk in the decoder shifts everything by 2 to the left. */
+ raw >>= 2;
+
+ start = (raw >> 13) & 0x01;
+ tgl = (raw >> 11) & 0x01;
+ addr = (raw >> 6) & 0x1f;
+ cmd = raw & 0x3f;
+ /*
+ * 12th bit is used to extend the command in extended RC5 and has
+ * no effect on standard RC5.
+ */
+ cmd += ((raw >> 12) & 0x01) ? 0 : 0x40;
+
+ if (!start)
+ return -EINVAL;
+
+ request->protocol = RC_TYPE_RC5;
+ request->scancode = addr << 8 | cmd;
+ request->toggle = tgl;
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert RC5 scancode to RC5 data filter */
+static int img_ir_rc5_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ /* Not supported by the hw. */
+ return -EINVAL;
+}
+
+/*
+ * RC-5 decoder
+ * see http://www.sbprojects.com/knowledge/ir/rc5.php
+ */
+struct img_ir_decoder img_ir_rc5 = {
+ .type = RC_BIT_RC5,
+ .control = {
+ .bitoriend2 = 1,
+ .code_type = IMG_IR_CODETYPE_BIPHASE,
+ .decodend2 = 1,
+ },
+ /* main timings */
+ .tolerance = 16,
+ .unit = 888888, /* 1/36k*32=888.888microseconds */
+ .timings = {
+ /* 10 symbol */
+ .s10 = {
+ .pulse = { 1 },
+ .space = { 1 },
+ },
+
+ /* 11 symbol */
+ .s11 = {
+ .pulse = { 1 },
+ .space = { 1 },
+ },
+
+ /* free time */
+ .ft = {
+ .minlen = 14,
+ .maxlen = 14,
+ .ft_min = 5,
+ },
+ },
+
+ /* scancode logic */
+ .scancode = img_ir_rc5_scancode,
+ .filter = img_ir_rc5_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir-rc6.c b/drivers/media/rc/img-ir/img-ir-rc6.c
new file mode 100644
index 000000000000..de1e27534968
--- /dev/null
+++ b/drivers/media/rc/img-ir/img-ir-rc6.c
@@ -0,0 +1,117 @@
+/*
+ * ImgTec IR Decoder setup for Philips RC-6 protocol.
+ *
+ * Copyright 2012-2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "img-ir-hw.h"
+
+/* Convert RC6 data to a scancode */
+static int img_ir_rc6_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
+{
+ unsigned int addr, cmd, mode, trl1, trl2;
+
+ /*
+ * Due to a side effect of the decoder handling the double length
+ * Trailer bit, the header information is a bit scrambled, and the
+ * raw data is shifted incorrectly.
+ * This workaround effectively recovers the header bits.
+ *
+ * The Header field should look like this:
+ *
+ * StartBit ModeBit2 ModeBit1 ModeBit0 TrailerBit
+ *
+ * But what we get is:
+ *
+ * ModeBit2 ModeBit1 ModeBit0 TrailerBit1 TrailerBit2
+ *
+ * The start bit is not important to recover the scancode.
+ */
+
+ raw >>= 27;
+
+ trl1 = (raw >> 17) & 0x01;
+ trl2 = (raw >> 16) & 0x01;
+
+ mode = (raw >> 18) & 0x07;
+ addr = (raw >> 8) & 0xff;
+ cmd = raw & 0xff;
+
+ /*
+ * Due to the above explained irregularity the trailer bits cannot
+ * have the same value.
+ */
+ if (trl1 == trl2)
+ return -EINVAL;
+
+ /* Only mode 0 supported for now */
+ if (mode)
+ return -EINVAL;
+
+ request->protocol = RC_TYPE_RC6_0;
+ request->scancode = addr << 8 | cmd;
+ request->toggle = trl2;
+ return IMG_IR_SCANCODE;
+}
+
+/* Convert RC6 scancode to RC6 data filter */
+static int img_ir_rc6_filter(const struct rc_scancode_filter *in,
+ struct img_ir_filter *out, u64 protocols)
+{
+ /* Not supported by the hw. */
+ return -EINVAL;
+}
+
+/*
+ * RC-6 decoder
+ * see http://www.sbprojects.com/knowledge/ir/rc6.php
+ */
+struct img_ir_decoder img_ir_rc6 = {
+ .type = RC_BIT_RC6_0,
+ .control = {
+ .bitorien = 1,
+ .code_type = IMG_IR_CODETYPE_BIPHASE,
+ .decoden = 1,
+ .decodinpol = 1,
+ },
+ /* main timings */
+ .tolerance = 20,
+ /*
+ * Due to a quirk in the img-ir decoder, default header values do
+ * not work, the values described below were extracted from
+ * successful RTL test cases.
+ */
+ .timings = {
+ /* leader symbol */
+ .ldr = {
+ .pulse = { 650 },
+ .space = { 660 },
+ },
+ /* 0 symbol */
+ .s00 = {
+ .pulse = { 370 },
+ .space = { 370 },
+ },
+ /* 01 symbol */
+ .s01 = {
+ .pulse = { 370 },
+ .space = { 370 },
+ },
+ /* free time */
+ .ft = {
+ .minlen = 21,
+ .maxlen = 21,
+ .ft_min = 2666, /* 2.666 ms */
+ },
+ },
+
+ /* scancode logic */
+ .scancode = img_ir_rc6_scancode,
+ .filter = img_ir_rc6_filter,
+};
diff --git a/drivers/media/rc/img-ir/img-ir-sanyo.c b/drivers/media/rc/img-ir/img-ir-sanyo.c
index 6b0653ecdf5a..f394994ffc22 100644
--- a/drivers/media/rc/img-ir/img-ir-sanyo.c
+++ b/drivers/media/rc/img-ir/img-ir-sanyo.c
@@ -23,8 +23,8 @@
#include "img-ir-hw.h"
/* Convert Sanyo data to a scancode */
-static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol,
- u32 *scancode, u64 enabled_protocols)
+static int img_ir_sanyo_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
{
unsigned int addr, addr_inv, data, data_inv;
/* a repeat code has no data */
@@ -44,8 +44,8 @@ static int img_ir_sanyo_scancode(int len, u64 raw, enum rc_type *protocol,
return -EINVAL;
/* Normal Sanyo */
- *protocol = RC_TYPE_SANYO;
- *scancode = addr << 8 | data;
+ request->protocol = RC_TYPE_SANYO;
+ request->scancode = addr << 8 | data;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-sharp.c b/drivers/media/rc/img-ir/img-ir-sharp.c
index 3300a38802ac..fe5acc4f030e 100644
--- a/drivers/media/rc/img-ir/img-ir-sharp.c
+++ b/drivers/media/rc/img-ir/img-ir-sharp.c
@@ -12,8 +12,8 @@
#include "img-ir-hw.h"
/* Convert Sharp data to a scancode */
-static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol,
- u32 *scancode, u64 enabled_protocols)
+static int img_ir_sharp_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
{
unsigned int addr, cmd, exp, chk;
@@ -32,8 +32,8 @@ static int img_ir_sharp_scancode(int len, u64 raw, enum rc_type *protocol,
/* probably the second half of the message */
return -EINVAL;
- *protocol = RC_TYPE_SHARP;
- *scancode = addr << 8 | cmd;
+ request->protocol = RC_TYPE_SHARP;
+ request->scancode = addr << 8 | cmd;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/img-ir/img-ir-sony.c b/drivers/media/rc/img-ir/img-ir-sony.c
index 3a0f17b0752c..7f7375f82ed6 100644
--- a/drivers/media/rc/img-ir/img-ir-sony.c
+++ b/drivers/media/rc/img-ir/img-ir-sony.c
@@ -12,8 +12,8 @@
#include "img-ir-hw.h"
/* Convert Sony data to a scancode */
-static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol,
- u32 *scancode, u64 enabled_protocols)
+static int img_ir_sony_scancode(int len, u64 raw, u64 enabled_protocols,
+ struct img_ir_scancode_req *request)
{
unsigned int dev, subdev, func;
@@ -25,7 +25,7 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol,
raw >>= 7;
dev = raw & 0x1f; /* next 5 bits */
subdev = 0;
- *protocol = RC_TYPE_SONY12;
+ request->protocol = RC_TYPE_SONY12;
break;
case 15:
if (!(enabled_protocols & RC_BIT_SONY15))
@@ -34,7 +34,7 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol,
raw >>= 7;
dev = raw & 0xff; /* next 8 bits */
subdev = 0;
- *protocol = RC_TYPE_SONY15;
+ request->protocol = RC_TYPE_SONY15;
break;
case 20:
if (!(enabled_protocols & RC_BIT_SONY20))
@@ -44,12 +44,12 @@ static int img_ir_sony_scancode(int len, u64 raw, enum rc_type *protocol,
dev = raw & 0x1f; /* next 5 bits */
raw >>= 5;
subdev = raw & 0xff; /* next 8 bits */
- *protocol = RC_TYPE_SONY20;
+ request->protocol = RC_TYPE_SONY20;
break;
default:
return -EINVAL;
}
- *scancode = dev << 16 | subdev << 8 | func;
+ request->scancode = dev << 16 | subdev << 8 | func;
return IMG_IR_SCANCODE;
}
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 1e0545a67959..4de0e85af805 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -553,14 +553,14 @@ unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
if (!ir->attached)
return POLLERR;
- poll_wait(file, &ir->buf->wait_poll, wait);
+ if (ir->buf) {
+ poll_wait(file, &ir->buf->wait_poll, wait);
- if (ir->buf)
if (lirc_buffer_empty(ir->buf))
ret = 0;
else
ret = POLLIN | POLLRDNORM;
- else
+ } else
ret = POLLERR;
dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 86ffcd54339e..f8c5e47a30aa 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1021,16 +1021,16 @@ static ssize_t store_protocols(struct device *device,
goto out;
}
- if (new_protocols == old_protocols) {
- rc = len;
- goto out;
+ if (new_protocols != old_protocols) {
+ *current_protocols = new_protocols;
+ IR_dprintk(1, "Protocols changed to 0x%llx\n",
+ (long long)new_protocols);
}
- *current_protocols = new_protocols;
- IR_dprintk(1, "Protocols changed to 0x%llx\n", (long long)new_protocols);
-
/*
- * If the protocol is changed the filter needs updating.
+ * If a protocol change was attempted the filter may need updating, even
+ * if the actual protocol mask hasn't changed (since the driver may have
+ * cleared the filter).
* Try setting the same filter with the new protocol (if any).
* Fall back to clearing the filter.
*/
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index 340f7f51eed4..7830aef3db45 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -23,6 +23,7 @@
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_platform.h>
+#include <linux/reset.h>
#include <media/rc-core.h>
#define SUNXI_IR_DEV "sunxi-ir"
@@ -55,12 +56,12 @@
#define REG_RXINT_RAI_EN BIT(4)
/* Rx FIFO available byte level */
-#define REG_RXINT_RAL(val) (((val) << 8) & (GENMASK(11, 8)))
+#define REG_RXINT_RAL(val) ((val) << 8)
/* Rx Interrupt Status */
#define SUNXI_IR_RXSTA_REG 0x30
/* RX FIFO Get Available Counter */
-#define REG_RXSTA_GET_AC(val) (((val) >> 8) & (GENMASK(5, 0)))
+#define REG_RXSTA_GET_AC(val) (((val) >> 8) & (ir->fifo_size * 2 - 1))
/* Clear all interrupt status value */
#define REG_RXSTA_CLEARALL 0xff
@@ -71,10 +72,6 @@
/* CIR_REG register idle threshold */
#define REG_CIR_ITHR(val) (((val) << 8) & (GENMASK(15, 8)))
-/* Hardware supported fifo size */
-#define SUNXI_IR_FIFO_SIZE 16
-/* How many messages in FIFO trigger IRQ */
-#define TRIGGER_LEVEL 8
/* Required frequency for IR0 or IR1 clock in CIR mode */
#define SUNXI_IR_BASE_CLK 8000000
/* Frequency after IR internal divider */
@@ -93,8 +90,10 @@ struct sunxi_ir {
struct rc_dev *rc;
void __iomem *base;
int irq;
+ int fifo_size;
struct clk *clk;
struct clk *apb_clk;
+ struct reset_control *rst;
const char *map_name;
};
@@ -113,11 +112,11 @@ static irqreturn_t sunxi_ir_irq(int irqno, void *dev_id)
/* clean all pending statuses */
writel(status | REG_RXSTA_CLEARALL, ir->base + SUNXI_IR_RXSTA_REG);
- if (status & REG_RXINT_RAI_EN) {
+ if (status & (REG_RXINT_RAI_EN | REG_RXINT_RPEI_EN)) {
/* How many messages in fifo */
rc = REG_RXSTA_GET_AC(status);
/* Sanity check */
- rc = rc > SUNXI_IR_FIFO_SIZE ? SUNXI_IR_FIFO_SIZE : rc;
+ rc = rc > ir->fifo_size ? ir->fifo_size : rc;
/* If we have data */
for (cnt = 0; cnt < rc; cnt++) {
/* for each bit in fifo */
@@ -154,6 +153,11 @@ static int sunxi_ir_probe(struct platform_device *pdev)
if (!ir)
return -ENOMEM;
+ if (of_device_is_compatible(dn, "allwinner,sun5i-a13-ir"))
+ ir->fifo_size = 64;
+ else
+ ir->fifo_size = 16;
+
/* Clock */
ir->apb_clk = devm_clk_get(dev, "apb");
if (IS_ERR(ir->apb_clk)) {
@@ -166,15 +170,29 @@ static int sunxi_ir_probe(struct platform_device *pdev)
return PTR_ERR(ir->clk);
}
+ /* Reset (optional) */
+ ir->rst = devm_reset_control_get_optional(dev, NULL);
+ if (IS_ERR(ir->rst)) {
+ ret = PTR_ERR(ir->rst);
+ if (ret == -EPROBE_DEFER)
+ return ret;
+ ir->rst = NULL;
+ } else {
+ ret = reset_control_deassert(ir->rst);
+ if (ret)
+ return ret;
+ }
+
ret = clk_set_rate(ir->clk, SUNXI_IR_BASE_CLK);
if (ret) {
dev_err(dev, "set ir base clock failed!\n");
- return ret;
+ goto exit_reset_assert;
}
if (clk_prepare_enable(ir->apb_clk)) {
dev_err(dev, "try to enable apb_ir_clk failed\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto exit_reset_assert;
}
if (clk_prepare_enable(ir->clk)) {
@@ -255,7 +273,7 @@ static int sunxi_ir_probe(struct platform_device *pdev)
* level
*/
writel(REG_RXINT_ROI_EN | REG_RXINT_RPEI_EN |
- REG_RXINT_RAI_EN | REG_RXINT_RAL(TRIGGER_LEVEL - 1),
+ REG_RXINT_RAI_EN | REG_RXINT_RAL(ir->fifo_size / 2 - 1),
ir->base + SUNXI_IR_RXINT_REG);
/* Enable IR Module */
@@ -271,6 +289,9 @@ exit_clkdisable_clk:
clk_disable_unprepare(ir->clk);
exit_clkdisable_apb_clk:
clk_disable_unprepare(ir->apb_clk);
+exit_reset_assert:
+ if (ir->rst)
+ reset_control_assert(ir->rst);
return ret;
}
@@ -282,6 +303,8 @@ static int sunxi_ir_remove(struct platform_device *pdev)
clk_disable_unprepare(ir->clk);
clk_disable_unprepare(ir->apb_clk);
+ if (ir->rst)
+ reset_control_assert(ir->rst);
spin_lock_irqsave(&ir->ir_lock, flags);
/* disable IR IRQ */
@@ -298,6 +321,7 @@ static int sunxi_ir_remove(struct platform_device *pdev)
static const struct of_device_id sunxi_ir_match[] = {
{ .compatible = "allwinner,sun4i-a10-ir", },
+ { .compatible = "allwinner,sun5i-a13-ir", },
{},
};
diff --git a/drivers/media/tuners/mt20xx.c b/drivers/media/tuners/mt20xx.c
index 0e74e97e0d1a..9e031040c13f 100644
--- a/drivers/media/tuners/mt20xx.c
+++ b/drivers/media/tuners/mt20xx.c
@@ -660,11 +660,3 @@ EXPORT_SYMBOL_GPL(microtune_attach);
MODULE_DESCRIPTION("Microtune tuner driver");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/mt2131.c b/drivers/media/tuners/mt2131.c
index f83b0c1ea6c8..6e2cdd2b6175 100644
--- a/drivers/media/tuners/mt2131.c
+++ b/drivers/media/tuners/mt2131.c
@@ -294,8 +294,3 @@ EXPORT_SYMBOL(mt2131_attach);
MODULE_AUTHOR("Steven Toth");
MODULE_DESCRIPTION("Microtune MT2131 silicon tuner driver");
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/tuners/mt2131.h b/drivers/media/tuners/mt2131.h
index 09ceaf68e47c..837c854b9c65 100644
--- a/drivers/media/tuners/mt2131.h
+++ b/drivers/media/tuners/mt2131.h
@@ -47,8 +47,3 @@ static inline struct dvb_frontend* mt2131_attach(struct dvb_frontend *fe,
#endif /* CONFIG_MEDIA_TUNER_MT2131 */
#endif /* __MT2131_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/tuners/mt2131_priv.h b/drivers/media/tuners/mt2131_priv.h
index 62aeedf5c550..91283b599cb3 100644
--- a/drivers/media/tuners/mt2131_priv.h
+++ b/drivers/media/tuners/mt2131_priv.h
@@ -41,8 +41,3 @@ struct mt2131_priv {
};
#endif /* __MT2131_PRIV_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c
index 1810ad66888e..f4ae04c3328a 100644
--- a/drivers/media/tuners/mxl5007t.c
+++ b/drivers/media/tuners/mxl5007t.c
@@ -938,11 +938,3 @@ MODULE_DESCRIPTION("MaxLinear MxL5007T Silicon IC tuner driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.2");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/mxl5007t.h b/drivers/media/tuners/mxl5007t.h
index 37b0942e2385..ae7037d681c5 100644
--- a/drivers/media/tuners/mxl5007t.h
+++ b/drivers/media/tuners/mxl5007t.h
@@ -93,12 +93,3 @@ static inline struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
#endif
#endif /* __MXL5007T_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index 2180de9d654a..fcf139dfdec6 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -19,16 +19,17 @@
static const struct dvb_tuner_ops si2157_ops;
/* execute firmware command */
-static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
+static int si2157_cmd_execute(struct i2c_client *client, struct si2157_cmd *cmd)
{
+ struct si2157_dev *dev = i2c_get_clientdata(client);
int ret;
unsigned long timeout;
- mutex_lock(&s->i2c_mutex);
+ mutex_lock(&dev->i2c_mutex);
if (cmd->wlen) {
/* write cmd and args for firmware */
- ret = i2c_master_send(s->client, cmd->args, cmd->wlen);
+ ret = i2c_master_send(client, cmd->args, cmd->wlen);
if (ret < 0) {
goto err_mutex_unlock;
} else if (ret != cmd->wlen) {
@@ -42,7 +43,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
#define TIMEOUT 80
timeout = jiffies + msecs_to_jiffies(TIMEOUT);
while (!time_after(jiffies, timeout)) {
- ret = i2c_master_recv(s->client, cmd->args, cmd->rlen);
+ ret = i2c_master_recv(client, cmd->args, cmd->rlen);
if (ret < 0) {
goto err_mutex_unlock;
} else if (ret != cmd->rlen) {
@@ -55,7 +56,7 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
break;
}
- dev_dbg(&s->client->dev, "cmd execution took %d ms\n",
+ dev_dbg(&client->dev, "cmd execution took %d ms\n",
jiffies_to_msecs(jiffies) -
(jiffies_to_msecs(timeout) - TIMEOUT));
@@ -65,35 +66,32 @@ static int si2157_cmd_execute(struct si2157 *s, struct si2157_cmd *cmd)
}
}
- ret = 0;
+ mutex_unlock(&dev->i2c_mutex);
+ return 0;
err_mutex_unlock:
- mutex_unlock(&s->i2c_mutex);
- if (ret)
- goto err;
-
- return 0;
-err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ mutex_unlock(&dev->i2c_mutex);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2157_init(struct dvb_frontend *fe)
{
- struct si2157 *s = fe->tuner_priv;
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
int ret, len, remaining;
struct si2157_cmd cmd;
- const struct firmware *fw = NULL;
- u8 *fw_file;
+ const struct firmware *fw;
+ const char *fw_name;
unsigned int chip_id;
- dev_dbg(&s->client->dev, "\n");
+ dev_dbg(&client->dev, "\n");
- if (s->fw_loaded)
+ if (dev->fw_loaded)
goto warm;
/* power up */
- if (s->chiptype == SI2157_CHIPTYPE_SI2146) {
+ if (dev->chiptype == SI2157_CHIPTYPE_SI2146) {
memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
cmd.wlen = 9;
} else {
@@ -101,7 +99,7 @@ static int si2157_init(struct dvb_frontend *fe)
cmd.wlen = 15;
}
cmd.rlen = 1;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -109,7 +107,7 @@ static int si2157_init(struct dvb_frontend *fe)
memcpy(cmd.args, "\x02", 1);
cmd.wlen = 1;
cmd.rlen = 13;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -125,121 +123,133 @@ static int si2157_init(struct dvb_frontend *fe)
switch (chip_id) {
case SI2158_A20:
case SI2148_A20:
- fw_file = SI2158_A20_FIRMWARE;
+ fw_name = SI2158_A20_FIRMWARE;
break;
case SI2157_A30:
case SI2147_A30:
case SI2146_A10:
- goto skip_fw_download;
+ fw_name = NULL;
+ break;
default:
- dev_err(&s->client->dev,
- "unknown chip version Si21%d-%c%c%c\n",
+ dev_err(&client->dev, "unknown chip version Si21%d-%c%c%c\n",
cmd.args[2], cmd.args[1],
cmd.args[3], cmd.args[4]);
ret = -EINVAL;
goto err;
}
- /* cold state - try to download firmware */
- dev_info(&s->client->dev, "found a '%s' in cold state\n",
- si2157_ops.info.name);
+ dev_info(&client->dev, "found a 'Silicon Labs Si21%d-%c%c%c'\n",
+ cmd.args[2], cmd.args[1], cmd.args[3], cmd.args[4]);
+
+ if (fw_name == NULL)
+ goto skip_fw_download;
/* request the firmware, this will block and timeout */
- ret = request_firmware(&fw, fw_file, &s->client->dev);
+ ret = request_firmware(&fw, fw_name, &client->dev);
if (ret) {
- dev_err(&s->client->dev, "firmware file '%s' not found\n",
- fw_file);
+ dev_err(&client->dev, "firmware file '%s' not found\n",
+ fw_name);
goto err;
}
/* firmware should be n chunks of 17 bytes */
if (fw->size % 17 != 0) {
- dev_err(&s->client->dev, "firmware file '%s' is invalid\n",
- fw_file);
+ dev_err(&client->dev, "firmware file '%s' is invalid\n",
+ fw_name);
ret = -EINVAL;
- goto fw_release_exit;
+ goto err_release_firmware;
}
- dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
- fw_file);
+ dev_info(&client->dev, "downloading firmware from file '%s'\n",
+ fw_name);
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 = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret) {
- dev_err(&s->client->dev,
- "firmware download failed=%d\n",
+ dev_err(&client->dev, "firmware download failed %d\n",
ret);
- goto fw_release_exit;
+ goto err_release_firmware;
}
}
release_firmware(fw);
- fw = NULL;
skip_fw_download:
/* reboot the tuner with new firmware? */
memcpy(cmd.args, "\x01\x01", 2);
cmd.wlen = 2;
cmd.rlen = 1;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
- s->fw_loaded = true;
+ /* query firmware version */
+ memcpy(cmd.args, "\x11", 1);
+ cmd.wlen = 1;
+ cmd.rlen = 10;
+ ret = si2157_cmd_execute(client, &cmd);
+ if (ret)
+ goto err;
+
+ dev_info(&client->dev, "firmware version: %c.%c.%d\n",
+ cmd.args[6], cmd.args[7], cmd.args[8]);
+
+ dev->fw_loaded = true;
warm:
- s->active = true;
+ dev->active = true;
return 0;
-fw_release_exit:
+err_release_firmware:
release_firmware(fw);
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2157_sleep(struct dvb_frontend *fe)
{
- struct si2157 *s = fe->tuner_priv;
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
int ret;
struct si2157_cmd cmd;
- dev_dbg(&s->client->dev, "\n");
+ dev_dbg(&client->dev, "\n");
- s->active = false;
+ dev->active = false;
/* standby */
memcpy(cmd.args, "\x16\x00", 2);
cmd.wlen = 2;
cmd.rlen = 1;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
return 0;
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
static int si2157_set_params(struct dvb_frontend *fe)
{
- struct si2157 *s = fe->tuner_priv;
+ struct i2c_client *client = fe->tuner_priv;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret;
struct si2157_cmd cmd;
u8 bandwidth, delivery_system;
- dev_dbg(&s->client->dev,
+ dev_dbg(&client->dev,
"delivery_system=%d frequency=%u bandwidth_hz=%u\n",
- c->delivery_system, c->frequency,
- c->bandwidth_hz);
+ c->delivery_system, c->frequency, c->bandwidth_hz);
- if (!s->active) {
+ if (!dev->active) {
ret = -EAGAIN;
goto err;
}
@@ -274,21 +284,21 @@ static int si2157_set_params(struct dvb_frontend *fe)
memcpy(cmd.args, "\x14\x00\x03\x07\x00\x00", 6);
cmd.args[4] = delivery_system | bandwidth;
- if (s->inversion)
+ if (dev->inversion)
cmd.args[5] = 0x01;
cmd.wlen = 6;
cmd.rlen = 4;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
- if (s->chiptype == SI2157_CHIPTYPE_SI2146)
+ if (dev->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);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
@@ -300,13 +310,13 @@ static int si2157_set_params(struct dvb_frontend *fe)
cmd.args[7] = (c->frequency >> 24) & 0xff;
cmd.wlen = 8;
cmd.rlen = 1;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
goto err;
return 0;
err:
- dev_dbg(&s->client->dev, "failed=%d\n", ret);
+ dev_dbg(&client->dev, "failed=%d\n", ret);
return ret;
}
@@ -334,70 +344,67 @@ static int si2157_probe(struct i2c_client *client,
{
struct si2157_config *cfg = client->dev.platform_data;
struct dvb_frontend *fe = cfg->fe;
- struct si2157 *s;
+ struct si2157_dev *dev;
struct si2157_cmd cmd;
int ret;
- s = kzalloc(sizeof(struct si2157), GFP_KERNEL);
- if (!s) {
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
ret = -ENOMEM;
dev_err(&client->dev, "kzalloc() failed\n");
goto err;
}
- s->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);
+ i2c_set_clientdata(client, dev);
+ dev->fe = cfg->fe;
+ dev->inversion = cfg->inversion;
+ dev->fw_loaded = false;
+ dev->chiptype = (u8)id->driver_data;
+ mutex_init(&dev->i2c_mutex);
/* check if the tuner is there */
cmd.wlen = 0;
cmd.rlen = 1;
- ret = si2157_cmd_execute(s, &cmd);
+ ret = si2157_cmd_execute(client, &cmd);
if (ret)
- goto err;
+ goto err_kfree;
- fe->tuner_priv = s;
- memcpy(&fe->ops.tuner_ops, &si2157_ops,
- sizeof(struct dvb_tuner_ops));
+ memcpy(&fe->ops.tuner_ops, &si2157_ops, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = client;
- i2c_set_clientdata(client, s);
-
- dev_info(&s->client->dev,
- "Silicon Labs %s successfully attached\n",
- s->chiptype == SI2157_CHIPTYPE_SI2146 ?
+ dev_info(&client->dev, "Silicon Labs %s successfully attached\n",
+ dev->chiptype == SI2157_CHIPTYPE_SI2146 ?
"Si2146" : "Si2147/2148/2157/2158");
return 0;
+
+err_kfree:
+ kfree(dev);
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
- kfree(s);
-
return ret;
}
static int si2157_remove(struct i2c_client *client)
{
- struct si2157 *s = i2c_get_clientdata(client);
- struct dvb_frontend *fe = s->fe;
+ struct si2157_dev *dev = i2c_get_clientdata(client);
+ struct dvb_frontend *fe = dev->fe;
dev_dbg(&client->dev, "\n");
memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
fe->tuner_priv = NULL;
- kfree(s);
+ kfree(dev);
return 0;
}
-static const struct i2c_device_id si2157_id[] = {
- {"si2157", 0},
- {"si2146", 1},
+static const struct i2c_device_id si2157_id_table[] = {
+ {"si2157", SI2157_CHIPTYPE_SI2157},
+ {"si2146", SI2157_CHIPTYPE_SI2146},
{}
};
-MODULE_DEVICE_TABLE(i2c, si2157_id);
+MODULE_DEVICE_TABLE(i2c, si2157_id_table);
static struct i2c_driver si2157_driver = {
.driver = {
@@ -406,7 +413,7 @@ static struct i2c_driver si2157_driver = {
},
.probe = si2157_probe,
.remove = si2157_remove,
- .id_table = si2157_id,
+ .id_table = si2157_id_table,
};
module_i2c_driver(si2157_driver);
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index d6e07cdd2a07..7aa53bce5593 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -21,9 +21,8 @@
#include "si2157.h"
/* state struct */
-struct si2157 {
+struct si2157_dev {
struct mutex i2c_mutex;
- struct i2c_client *client;
struct dvb_frontend *fe;
bool active;
bool fw_loaded;
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
index 4995b890c164..f8620741bb5f 100644
--- a/drivers/media/tuners/tda18271-fe.c
+++ b/drivers/media/tuners/tda18271-fe.c
@@ -1355,11 +1355,3 @@ MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.4");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/tda18271-maps.c b/drivers/media/tuners/tda18271-maps.c
index b62e925f643f..1e89dd93c4bb 100644
--- a/drivers/media/tuners/tda18271-maps.c
+++ b/drivers/media/tuners/tda18271-maps.c
@@ -1305,11 +1305,3 @@ int tda18271_assign_map_layout(struct dvb_frontend *fe)
return ret;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/tda18271-priv.h b/drivers/media/tuners/tda18271-priv.h
index b36a7b754772..cc80f544af34 100644
--- a/drivers/media/tuners/tda18271-priv.h
+++ b/drivers/media/tuners/tda18271-priv.h
@@ -226,11 +226,3 @@ extern int tda18271_calc_ir_measure(struct dvb_frontend *fe, u32 *freq);
extern int tda18271_calc_rf_cal(struct dvb_frontend *fe, u32 *freq);
#endif /* __TDA18271_PRIV_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/tda827x.c b/drivers/media/tuners/tda827x.c
index 73453a255cdc..edcb4a723aa1 100644
--- a/drivers/media/tuners/tda827x.c
+++ b/drivers/media/tuners/tda827x.c
@@ -907,11 +907,3 @@ MODULE_DESCRIPTION("DVB TDA827x driver");
MODULE_AUTHOR("Hartmut Hackmann <hartmut.hackmann@t-online.de>");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/tda8290.c b/drivers/media/tuners/tda8290.c
index ab4106c17b4c..998e82bba9c0 100644
--- a/drivers/media/tuners/tda8290.c
+++ b/drivers/media/tuners/tda8290.c
@@ -881,11 +881,3 @@ EXPORT_SYMBOL_GPL(tda829x_probe);
MODULE_DESCRIPTION("Philips/NXP TDA8290/TDA8295 analog IF demodulator driver");
MODULE_AUTHOR("Gerd Knorr, Hartmut Hackmann, Michael Krufky");
MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c
index 9823248d743f..56be6c29399b 100644
--- a/drivers/media/tuners/tda9887.c
+++ b/drivers/media/tuners/tda9887.c
@@ -707,11 +707,3 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
EXPORT_SYMBOL_GPL(tda9887_attach);
MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c
index ca274c2d8c70..8e9ce144da9a 100644
--- a/drivers/media/tuners/tuner-simple.c
+++ b/drivers/media/tuners/tuner-simple.c
@@ -1148,11 +1148,3 @@ EXPORT_SYMBOL_GPL(simple_tuner_attach);
MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
MODULE_LICENSE("GPL");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/au0828/Kconfig b/drivers/media/usb/au0828/Kconfig
index 1d410ac8f9a8..78b797e0b434 100644
--- a/drivers/media/usb/au0828/Kconfig
+++ b/drivers/media/usb/au0828/Kconfig
@@ -4,7 +4,7 @@ config VIDEO_AU0828
depends on I2C && INPUT && DVB_CORE && USB
select I2C_ALGOBIT
select VIDEO_TVEEPROM
- select VIDEOBUF_VMALLOC
+ select VIDEOBUF2_VMALLOC
select DVB_AU8522_DTV if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_XC5000 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_MXL5007T if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index da87f1cc31a9..edc27355f271 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -44,7 +44,7 @@ static void hvr950q_cs5340_audio(void *priv, int enable)
struct au0828_board au0828_boards[] = {
[AU0828_BOARD_UNKNOWN] = {
.name = "Unknown board",
- .tuner_type = UNSET,
+ .tuner_type = -1U,
.tuner_addr = ADDR_UNSET,
},
[AU0828_BOARD_HAUPPAUGE_HVR850] = {
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index 932d24f42b24..f67247cf1a5a 100644
--- a/drivers/media/usb/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -28,111 +28,67 @@
#include <linux/init.h>
#include <linux/slab.h>
-static unsigned int vbibufs = 5;
-module_param(vbibufs, int, 0644);
-MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
-
/* ------------------------------------------------------------------ */
-static void
-free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+static int vbi_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_dev *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.vbi_buf == buf)
- dev->isoc_ctl.vbi_buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
+ struct au0828_dev *dev = vb2_get_drv_priv(vq);
+ unsigned long img_size = dev->vbi_width * dev->vbi_height * 2;
+ unsigned long size;
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
-{
- struct au0828_fh *fh = q->priv_data;
- struct au0828_dev *dev = fh->dev;
+ size = fmt ? (fmt->fmt.vbi.samples_per_line *
+ (fmt->fmt.vbi.count[0] + fmt->fmt.vbi.count[1])) : img_size;
+ if (size < img_size)
+ return -EINVAL;
- *size = dev->vbi_width * dev->vbi_height * 2;
+ *nplanes = 1;
+ sizes[0] = size;
- if (0 == *count)
- *count = vbibufs;
- if (*count < 2)
- *count = 2;
- if (*count > 32)
- *count = 32;
return 0;
}
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int vbi_buffer_prepare(struct vb2_buffer *vb)
{
- struct au0828_fh *fh = q->priv_data;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
- int rc = 0;
+ unsigned long size;
- buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+ size = dev->vbi_width * dev->vbi_height * 2;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ if (vb2_plane_size(vb, 0) < size) {
+ pr_err("%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), size);
return -EINVAL;
-
- buf->vb.width = dev->vbi_width;
- buf->vb.height = dev->vbi_height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(q, &buf->vb, NULL);
- if (rc < 0)
- goto fail;
}
+ vb2_set_plane_payload(&buf->vb, 0, size);
- buf->vb.state = VIDEOBUF_PREPARED;
return 0;
-
-fail:
- free_buffer(q, buf);
- return rc;
}
static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
-{
- struct au0828_buffer *buf = container_of(vb,
- struct au0828_buffer,
- vb);
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_dev *dev = fh->dev;
- struct au0828_dmaqueue *vbiq = &dev->vbiq;
-
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vbiq->active);
-}
-
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+vbi_buffer_queue(struct vb2_buffer *vb)
{
+ struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
- free_buffer(q, buf);
+ struct au0828_dmaqueue *vbiq = &dev->vbiq;
+ unsigned long flags = 0;
+
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->list, &vbiq->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-struct videobuf_queue_ops au0828_vbi_qops = {
- .buf_setup = vbi_setup,
- .buf_prepare = vbi_prepare,
- .buf_queue = vbi_queue,
- .buf_release = vbi_release,
+struct vb2_ops au0828_vbi_qops = {
+ .queue_setup = vbi_queue_setup,
+ .buf_prepare = vbi_buffer_prepare,
+ .buf_queue = vbi_buffer_queue,
+ .start_streaming = au0828_start_analog_streaming,
+ .stop_streaming = au0828_stop_vbi_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 5f337b118bff..a27cb5fcdef8 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -22,7 +22,6 @@
/* Developer Notes:
*
- * VBI support is not yet working
* The hardware scaler supported is unimplemented
* AC97 audio support is unimplemented (only i2s audio mode)
*
@@ -219,9 +218,6 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
au0828_isocdbg("au0828: called au0828_prepare_isoc\n");
- /* De-allocates all pending stuff */
- au0828_uninit_isoc(dev);
-
dev->isoc_ctl.isoc_copy = isoc_copy;
dev->isoc_ctl.num_bufs = num_bufs;
@@ -285,8 +281,6 @@ static int au0828_init_isoc(struct au0828_dev *dev, int max_packets,
}
}
- init_waitqueue_head(&dma_q->wq);
-
/* submit urbs and enables IRQ */
for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
@@ -309,16 +303,12 @@ static inline void buffer_filled(struct au0828_dev *dev,
struct au0828_buffer *buf)
{
/* Advice that buffer was filled */
- au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- v4l2_get_timestamp(&buf->vb.ts);
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
- dev->isoc_ctl.buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
+ buf->vb.v4l2_buf.sequence = dev->frame_count++;
+ buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
static inline void vbi_buffer_filled(struct au0828_dev *dev,
@@ -326,16 +316,12 @@ static inline void vbi_buffer_filled(struct au0828_dev *dev,
struct au0828_buffer *buf)
{
/* Advice that buffer was filled */
- au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
-
- buf->vb.state = VIDEOBUF_DONE;
- buf->vb.field_count++;
- v4l2_get_timestamp(&buf->vb.ts);
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->top_field);
- dev->isoc_ctl.vbi_buf = NULL;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
+ buf->vb.v4l2_buf.sequence = dev->vbi_frame_count++;
+ buf->vb.v4l2_buf.field = V4L2_FIELD_INTERLACED;
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
/*
@@ -354,8 +340,8 @@ static void au0828_copy_video(struct au0828_dev *dev,
if (len == 0)
return;
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
+ if (dma_q->pos + len > buf->length)
+ len = buf->length - dma_q->pos;
startread = p;
remain = len;
@@ -373,11 +359,11 @@ static void au0828_copy_video(struct au0828_dev *dev,
lencopy = bytesperline - currlinedone;
lencopy = lencopy > remain ? remain : lencopy;
- if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ if ((char *)startwrite + lencopy > (char *)outp + buf->length) {
au0828_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ ((char *)outp + buf->length));
+ remain = (char *)outp + buf->length - (char *)startwrite;
lencopy = remain;
}
if (lencopy <= 0)
@@ -395,11 +381,11 @@ static void au0828_copy_video(struct au0828_dev *dev,
lencopy = bytesperline;
if ((char *)startwrite + lencopy > (char *)outp +
- buf->vb.size) {
+ buf->length) {
au0828_isocdbg("Overflow %zi bytes past buf end (2)\n",
((char *)startwrite + lencopy) -
- ((char *)outp + buf->vb.size));
- lencopy = remain = (char *)outp + buf->vb.size -
+ ((char *)outp + buf->length));
+ lencopy = remain = (char *)outp + buf->length -
(char *)startwrite;
}
if (lencopy <= 0)
@@ -435,7 +421,11 @@ static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
}
/* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, list);
+ /* Cleans up buffer - Useful for testing for frame/URB loss */
+ list_del(&(*buf)->list);
+ dma_q->pos = 0;
+ (*buf)->vb_buf = (*buf)->mem;
dev->isoc_ctl.buf = *buf;
return;
@@ -473,8 +463,8 @@ static void au0828_copy_vbi(struct au0828_dev *dev,
bytesperline = dev->vbi_width;
- if (dma_q->pos + len > buf->vb.size)
- len = buf->vb.size - dma_q->pos;
+ if (dma_q->pos + len > buf->length)
+ len = buf->length - dma_q->pos;
startread = p;
startwrite = outp + (dma_q->pos / 2);
@@ -497,7 +487,6 @@ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
struct au0828_buffer **buf)
{
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
- char *outp;
if (list_empty(&dma_q->active)) {
au0828_isocdbg("No active queue to serve\n");
@@ -507,13 +496,12 @@ static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
}
/* Get the next buffer */
- *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, list);
/* Cleans up buffer - Useful for testing for frame/URB loss */
- outp = videobuf_to_vmalloc(&(*buf)->vb);
- memset(outp, 0x00, (*buf)->vb.size);
-
+ list_del(&(*buf)->list);
+ dma_q->pos = 0;
+ (*buf)->vb_buf = (*buf)->mem;
dev->isoc_ctl.vbi_buf = *buf;
-
return;
}
@@ -549,11 +537,11 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
buf = dev->isoc_ctl.buf;
if (buf != NULL)
- outp = videobuf_to_vmalloc(&buf->vb);
+ outp = vb2_plane_vaddr(&buf->vb, 0);
vbi_buf = dev->isoc_ctl.vbi_buf;
if (vbi_buf != NULL)
- vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+ vbioutp = vb2_plane_vaddr(&vbi_buf->vb, 0);
for (i = 0; i < urb->number_of_packets; i++) {
int status = urb->iso_frame_desc[i].status;
@@ -593,8 +581,8 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
if (vbi_buf == NULL)
vbioutp = NULL;
else
- vbioutp = videobuf_to_vmalloc(
- &vbi_buf->vb);
+ vbioutp = vb2_plane_vaddr(
+ &vbi_buf->vb, 0);
/* Video */
if (buf != NULL)
@@ -603,7 +591,7 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
if (buf == NULL)
outp = NULL;
else
- outp = videobuf_to_vmalloc(&buf->vb);
+ outp = vb2_plane_vaddr(&buf->vb, 0);
/* As long as isoc traffic is arriving, keep
resetting the timer */
@@ -657,130 +645,59 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
return rc;
}
-static int
-buffer_setup(struct videobuf_queue *vq, unsigned int *count,
- unsigned int *size)
+static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
+ unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct au0828_fh *fh = vq->priv_data;
- *size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+ struct au0828_dev *dev = vb2_get_drv_priv(vq);
+ unsigned long img_size = dev->height * dev->bytesperline;
+ unsigned long size;
- if (0 == *count)
- *count = AU0828_DEF_BUF;
+ size = fmt ? fmt->fmt.pix.sizeimage : img_size;
+ if (size < img_size)
+ return -EINVAL;
- if (*count < AU0828_MIN_BUF)
- *count = AU0828_MIN_BUF;
- return 0;
-}
+ *nplanes = 1;
+ sizes[0] = size;
-/* This is called *without* dev->slock held; please keep it that way */
-static void free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
-{
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_dev *dev = fh->dev;
- unsigned long flags = 0;
- if (in_interrupt())
- BUG();
-
- /* We used to wait for the buffer to finish here, but this didn't work
- because, as we were keeping the state as VIDEOBUF_QUEUED,
- videobuf_queue_cancel marked it as finished for us.
- (Also, it could wedge forever if the hardware was misconfigured.)
-
- This should be safe; by the time we get here, the buffer isn't
- queued anymore. If we ever start marking the buffers as
- VIDEOBUF_ACTIVE, it won't be, though.
- */
- spin_lock_irqsave(&dev->slock, flags);
- if (dev->isoc_ctl.buf == buf)
- dev->isoc_ctl.buf = NULL;
- spin_unlock_irqrestore(&dev->slock, flags);
-
- videobuf_vmalloc_free(&buf->vb);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
+ return 0;
}
static int
-buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
- enum v4l2_field field)
+buffer_prepare(struct vb2_buffer *vb)
{
- struct au0828_fh *fh = vq->priv_data;
struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
- struct au0828_dev *dev = fh->dev;
- int rc = 0, urb_init = 0;
+ struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
- buf->vb.size = (fh->dev->width * fh->dev->height * 16 + 7) >> 3;
+ buf->length = dev->height * dev->bytesperline;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ if (vb2_plane_size(vb, 0) < buf->length) {
+ pr_err("%s data will not fit into plane (%lu < %lu)\n",
+ __func__, vb2_plane_size(vb, 0), buf->length);
return -EINVAL;
-
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
-
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- rc = videobuf_iolock(vq, &buf->vb, NULL);
- if (rc < 0) {
- pr_info("videobuf_iolock failed\n");
- goto fail;
- }
}
-
- if (!dev->isoc_ctl.num_bufs)
- urb_init = 1;
-
- if (urb_init) {
- rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
- AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
- au0828_isoc_copy);
- if (rc < 0) {
- pr_info("au0828_init_isoc failed\n");
- goto fail;
- }
- }
-
- buf->vb.state = VIDEOBUF_PREPARED;
+ vb2_set_plane_payload(&buf->vb, 0, buf->length);
return 0;
-
-fail:
- free_buffer(vq, buf);
- return rc;
}
static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+buffer_queue(struct vb2_buffer *vb)
{
struct au0828_buffer *buf = container_of(vb,
struct au0828_buffer,
vb);
- struct au0828_fh *fh = vq->priv_data;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = vb2_get_drv_priv(vb->vb2_queue);
struct au0828_dmaqueue *vidq = &dev->vidq;
+ unsigned long flags = 0;
- buf->vb.state = VIDEOBUF_QUEUED;
- list_add_tail(&buf->vb.queue, &vidq->active);
-}
-
-static void buffer_release(struct videobuf_queue *vq,
- struct videobuf_buffer *vb)
-{
- struct au0828_buffer *buf = container_of(vb,
- struct au0828_buffer,
- vb);
+ buf->mem = vb2_plane_vaddr(vb, 0);
+ buf->length = vb2_plane_size(vb, 0);
- free_buffer(vq, buf);
+ spin_lock_irqsave(&dev->slock, flags);
+ list_add_tail(&buf->list, &vidq->active);
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static struct videobuf_queue_ops au0828_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/* ------------------------------------------------------------------
- V4L2 interface
- ------------------------------------------------------------------*/
-
static int au0828_i2s_init(struct au0828_dev *dev)
{
/* Enable i2s mode */
@@ -829,7 +746,7 @@ static int au0828_analog_stream_enable(struct au0828_dev *d)
return 0;
}
-int au0828_analog_stream_disable(struct au0828_dev *d)
+static int au0828_analog_stream_disable(struct au0828_dev *d)
{
dprintk(1, "au0828_analog_stream_disable called\n");
au0828_writereg(d, AU0828_SENSORCTRL_100, 0x0);
@@ -862,78 +779,133 @@ static int au0828_stream_interrupt(struct au0828_dev *dev)
return 0;
}
-/*
- * au0828_release_resources
- * unregister v4l2 devices
- */
-void au0828_analog_unregister(struct au0828_dev *dev)
+int au0828_start_analog_streaming(struct vb2_queue *vq, unsigned int count)
{
- dprintk(1, "au0828_release_resources called\n");
- mutex_lock(&au0828_sysfs_lock);
+ struct au0828_dev *dev = vb2_get_drv_priv(vq);
+ int rc = 0;
- if (dev->vdev)
- video_unregister_device(dev->vdev);
- if (dev->vbi_dev)
- video_unregister_device(dev->vbi_dev);
+ dprintk(1, "au0828_start_analog_streaming called %d\n",
+ dev->streaming_users);
- mutex_unlock(&au0828_sysfs_lock);
-}
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ dev->frame_count = 0;
+ else
+ dev->vbi_frame_count = 0;
+
+ if (dev->streaming_users == 0) {
+ /* If we were doing ac97 instead of i2s, it would go here...*/
+ au0828_i2s_init(dev);
+ rc = au0828_init_isoc(dev, AU0828_ISO_PACKETS_PER_URB,
+ AU0828_MAX_ISO_BUFS, dev->max_pkt_size,
+ au0828_isoc_copy);
+ if (rc < 0) {
+ pr_info("au0828_init_isoc failed\n");
+ return rc;
+ }
+ if (vq->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video,
+ s_stream, 1);
+ dev->vid_timeout_running = 1;
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+ } else if (vq->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
+ }
+ dev->streaming_users++;
+ return rc;
+}
-/* Usage lock check functions */
-static int res_get(struct au0828_fh *fh, unsigned int bit)
+static void au0828_stop_streaming(struct vb2_queue *vq)
{
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = vb2_get_drv_priv(vq);
+ struct au0828_dmaqueue *vidq = &dev->vidq;
+ unsigned long flags = 0;
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
+ dprintk(1, "au0828_stop_streaming called %d\n", dev->streaming_users);
- /* is it free? */
- if (dev->resources & bit) {
- /* no, someone else uses it */
- return 0;
+ if (dev->streaming_users-- == 1)
+ au0828_uninit_isoc(dev);
+
+ v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf != NULL) {
+ vb2_buffer_done(&dev->isoc_ctl.buf->vb, VB2_BUF_STATE_ERROR);
+ dev->isoc_ctl.buf = NULL;
}
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- dprintk(1, "res: get %d\n", bit);
+ while (!list_empty(&vidq->active)) {
+ struct au0828_buffer *buf;
- return 1;
+ buf = list_entry(vidq->active.next, struct au0828_buffer, list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ list_del(&buf->list);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static int res_check(struct au0828_fh *fh, unsigned int bit)
+void au0828_stop_vbi_streaming(struct vb2_queue *vq)
{
- return fh->resources & bit;
-}
+ struct au0828_dev *dev = vb2_get_drv_priv(vq);
+ struct au0828_dmaqueue *vbiq = &dev->vbiq;
+ unsigned long flags = 0;
-static int res_locked(struct au0828_dev *dev, unsigned int bit)
-{
- return dev->resources & bit;
-}
+ dprintk(1, "au0828_stop_vbi_streaming called %d\n",
+ dev->streaming_users);
-static void res_free(struct au0828_fh *fh, unsigned int bits)
-{
- struct au0828_dev *dev = fh->dev;
+ if (dev->streaming_users-- == 1)
+ au0828_uninit_isoc(dev);
- BUG_ON((fh->resources & bits) != bits);
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.vbi_buf != NULL) {
+ vb2_buffer_done(&dev->isoc_ctl.vbi_buf->vb,
+ VB2_BUF_STATE_ERROR);
+ dev->isoc_ctl.vbi_buf = NULL;
+ }
+ while (!list_empty(&vbiq->active)) {
+ struct au0828_buffer *buf;
+
+ buf = list_entry(vbiq->active.next, struct au0828_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- dprintk(1, "res: put %d\n", bits);
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
}
-static int get_ressource(struct au0828_fh *fh)
+static struct vb2_ops au0828_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .start_streaming = au0828_start_analog_streaming,
+ .stop_streaming = au0828_stop_streaming,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+};
+
+/* ------------------------------------------------------------------
+ V4L2 interface
+ ------------------------------------------------------------------*/
+/*
+ * au0828_analog_unregister
+ * unregister v4l2 devices
+ */
+void au0828_analog_unregister(struct au0828_dev *dev)
{
- switch (fh->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- return AU0828_RESOURCE_VIDEO;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- return AU0828_RESOURCE_VBI;
- default:
- BUG();
- return 0;
- }
+ dprintk(1, "au0828_analog_unregister called\n");
+ mutex_lock(&au0828_sysfs_lock);
+
+ if (dev->vdev)
+ video_unregister_device(dev->vdev);
+ if (dev->vbi_dev)
+ video_unregister_device(dev->vbi_dev);
+
+ mutex_unlock(&au0828_sysfs_lock);
}
/* This function ensures that video frames continue to be delivered even if
@@ -951,8 +923,8 @@ static void au0828_vid_buffer_timeout(unsigned long data)
buf = dev->isoc_ctl.buf;
if (buf != NULL) {
- vid_data = videobuf_to_vmalloc(&buf->vb);
- memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+ vid_data = vb2_plane_vaddr(&buf->vb, 0);
+ memset(vid_data, 0x00, buf->length); /* Blank green frame */
buffer_filled(dev, dma_q, buf);
}
get_next_buf(dma_q, &buf);
@@ -975,8 +947,8 @@ static void au0828_vbi_buffer_timeout(unsigned long data)
buf = dev->isoc_ctl.vbi_buf;
if (buf != NULL) {
- vbi_data = videobuf_to_vmalloc(&buf->vb);
- memset(vbi_data, 0x00, buf->vb.size);
+ vbi_data = vb2_plane_vaddr(&buf->vb, 0);
+ memset(vbi_data, 0x00, buf->length);
vbi_buffer_filled(dev, dma_q, buf);
}
vbi_get_next_buf(dma_q, &buf);
@@ -986,105 +958,65 @@ static void au0828_vbi_buffer_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock, flags);
}
-
static int au0828_v4l2_open(struct file *filp)
{
- int ret = 0;
- struct video_device *vdev = video_devdata(filp);
struct au0828_dev *dev = video_drvdata(filp);
- struct au0828_fh *fh;
- int type;
-
- 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;
- default:
- return -EINVAL;
- }
-
- fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
- if (NULL == fh) {
- dprintk(1, "Failed allocate au0828_fh struct!\n");
- return -ENOMEM;
- }
+ int ret;
- fh->type = type;
- fh->dev = dev;
- v4l2_fh_init(&fh->fh, vdev);
- filp->private_data = fh;
+ dprintk(1,
+ "%s called std_set %d dev_state %d stream users %d users %d\n",
+ __func__, dev->std_set_in_tuner_core, dev->dev_state,
+ dev->streaming_users, dev->users);
- if (mutex_lock_interruptible(&dev->lock)) {
- kfree(fh);
+ if (mutex_lock_interruptible(&dev->lock))
return -ERESTARTSYS;
+
+ ret = v4l2_fh_open(filp);
+ if (ret) {
+ au0828_isocdbg("%s: v4l2_fh_open() returned error %d\n",
+ __func__, ret);
+ mutex_unlock(&dev->lock);
+ return ret;
}
+
if (dev->users == 0) {
au0828_analog_stream_enable(dev);
au0828_analog_stream_reset(dev);
-
- /* If we were doing ac97 instead of i2s, it would go here...*/
- au0828_i2s_init(dev);
-
dev->stream_state = STREAM_OFF;
dev->dev_state |= DEV_INITIALIZED;
}
-
dev->users++;
mutex_unlock(&dev->lock);
-
- videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct au0828_buffer), fh,
- &dev->lock);
-
- /* VBI Setup */
- videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
- NULL, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct au0828_buffer), fh,
- &dev->lock);
- v4l2_fh_add(&fh->fh);
return ret;
}
static int au0828_v4l2_close(struct file *filp)
{
int ret;
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(filp);
+ struct video_device *vdev = video_devdata(filp);
+
+ dprintk(1,
+ "%s called std_set %d dev_state %d stream users %d users %d\n",
+ __func__, dev->std_set_in_tuner_core, dev->dev_state,
+ dev->streaming_users, dev->users);
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
mutex_lock(&dev->lock);
- if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+ if (vdev->vfl_type == VFL_TYPE_GRABBER && dev->vid_timeout_running) {
/* Cancel timeout thread in case they didn't call streamoff */
dev->vid_timeout_running = 0;
del_timer_sync(&dev->vid_timeout);
-
- videobuf_stop(&fh->vb_vidq);
- res_free(fh, AU0828_RESOURCE_VIDEO);
- }
-
- if (res_check(fh, AU0828_RESOURCE_VBI)) {
+ } else if (vdev->vfl_type == VFL_TYPE_VBI &&
+ dev->vbi_timeout_running) {
/* Cancel timeout thread in case they didn't call streamoff */
dev->vbi_timeout_running = 0;
del_timer_sync(&dev->vbi_timeout);
-
- videobuf_stop(&fh->vb_vbiq);
- res_free(fh, AU0828_RESOURCE_VBI);
}
- if (dev->users == 1 && video_is_registered(video_devdata(filp))) {
- au0828_analog_stream_disable(dev);
-
- au0828_uninit_isoc(dev);
+ if (dev->dev_state == DEV_DISCONNECTED)
+ goto end;
+ if (dev->users == 1) {
/* Save some power by putting tuner to sleep */
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_power, 0);
dev->std_set_in_tuner_core = 0;
@@ -1095,13 +1027,10 @@ static int au0828_v4l2_close(struct file *filp)
if (ret < 0)
pr_info("Au0828 can't set alternate to 0!\n");
}
- mutex_unlock(&dev->lock);
-
- videobuf_mmap_free(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vbiq);
- kfree(fh);
+end:
+ _vb2_fop_release(filp, NULL);
dev->users--;
- wake_up_interruptible_nr(&dev->open, 1);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -1113,6 +1042,9 @@ static void au0828_init_tuner(struct au0828_dev *dev)
.type = V4L2_TUNER_ANALOG_TV,
};
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
if (dev->std_set_in_tuner_core)
return;
dev->std_set_in_tuner_core = 1;
@@ -1125,98 +1057,6 @@ static void au0828_init_tuner(struct au0828_dev *dev)
i2c_gate_ctrl(dev, 0);
}
-static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
- size_t count, loff_t *pos)
-{
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- au0828_init_tuner(dev);
- mutex_unlock(&dev->lock);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (res_locked(dev, AU0828_RESOURCE_VIDEO))
- return -EBUSY;
-
- return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, AU0828_RESOURCE_VBI))
- return -EBUSY;
-
- if (dev->vbi_timeout_running == 0) {
- /* Handle case where caller tries to read without
- calling streamon first */
- dev->vbi_timeout_running = 1;
- mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
- }
-
- return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
- filp->f_flags & O_NONBLOCK);
- }
-
- return 0;
-}
-
-static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
-{
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
- unsigned long req_events = poll_requested_events(wait);
- unsigned int res;
-
- if (check_dev(dev) < 0)
- return POLLERR;
-
- res = v4l2_ctrl_poll(filp, wait);
- if (!(req_events & (POLLIN | POLLRDNORM)))
- return res;
-
- if (mutex_lock_interruptible(&dev->lock))
- return -ERESTARTSYS;
- au0828_init_tuner(dev);
- mutex_unlock(&dev->lock);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- if (!res_get(fh, AU0828_RESOURCE_VIDEO))
- return POLLERR;
- return res | videobuf_poll_stream(filp, &fh->vb_vidq, wait);
- }
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- if (!res_get(fh, AU0828_RESOURCE_VBI))
- return POLLERR;
- return res | videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
- }
- return POLLERR;
-}
-
-static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
-{
- struct au0828_fh *fh = filp->private_data;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
-
- return rc;
-}
-
static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
struct v4l2_format *format)
{
@@ -1268,13 +1108,14 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
return 0;
}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
strlcpy(cap->driver, "au0828", sizeof(cap->driver));
strlcpy(cap->card, dev->board.name, sizeof(cap->card));
@@ -1300,6 +1141,8 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
if (f->index)
return -EINVAL;
+ dprintk(1, "%s called\n", __func__);
+
f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
strcpy(f->description, "Packed YUV2");
@@ -1312,8 +1155,10 @@ static int vidioc_enum_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 au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
@@ -1329,8 +1174,10 @@ 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 au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
return au0828_set_format(dev, VIDIOC_TRY_FMT, f);
}
@@ -1338,15 +1185,17 @@ 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 au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
int rc;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ if (vb2_is_busy(&dev->vb_vidq)) {
pr_info("%s queue busy\n", __func__);
rc = -EBUSY;
goto out;
@@ -1359,8 +1208,16 @@ out:
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
+ if (norm == dev->std)
+ return 0;
+
+ if (dev->streaming_users > 0)
+ return -EBUSY;
dev->std = norm;
@@ -1383,8 +1240,10 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
*norm = dev->std;
return 0;
@@ -1393,8 +1252,7 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *input)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
unsigned int tmp;
static const char *inames[] = {
@@ -1407,6 +1265,9 @@ static int vidioc_enum_input(struct file *file, void *priv,
[AU0828_VMUX_DEBUG] = "tv debug"
};
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
tmp = input->index;
if (tmp >= AU0828_MAX_INPUT)
@@ -1432,8 +1293,11 @@ static int vidioc_enum_input(struct file *file, void *priv,
static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
*i = dev->ctrl_input;
return 0;
}
@@ -1442,6 +1306,9 @@ static void au0828_s_input(struct au0828_dev *dev, int index)
{
int i;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
switch (AUVI_INPUT(index).type) {
case AU0828_VMUX_SVIDEO:
dev->input_type = AU0828_VMUX_SVIDEO;
@@ -1491,8 +1358,7 @@ static void au0828_s_input(struct au0828_dev *dev, int index)
static int vidioc_s_input(struct file *file, void *priv, unsigned int index)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
dprintk(1, "VIDIOC_S_INPUT in function %s, input=%d\n", __func__,
index);
@@ -1510,6 +1376,8 @@ static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
if (a->index > 1)
return -EINVAL;
+ dprintk(1, "%s called\n", __func__);
+
if (a->index == 0)
strcpy(a->name, "Television");
else
@@ -1521,8 +1389,10 @@ static int vidioc_enumaudio(struct file *file, void *priv, struct v4l2_audio *a)
static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
a->index = dev->ctrl_ainput;
if (a->index == 0)
@@ -1536,22 +1406,26 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio *a)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
if (a->index != dev->ctrl_ainput)
return -EINVAL;
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
return 0;
}
static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
if (t->index != 0)
return -EINVAL;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
strcpy(t->name, "Auvitek tuner");
au0828_init_tuner(dev);
@@ -1564,12 +1438,14 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
static int vidioc_s_tuner(struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
if (t->index != 0)
return -EINVAL;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
au0828_init_tuner(dev);
i2c_gate_ctrl(dev, 1);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
@@ -1585,11 +1461,12 @@ static int vidioc_s_tuner(struct file *file, void *priv,
static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
if (freq->tuner != 0)
return -EINVAL;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
freq->frequency = dev->ctrl_freq;
return 0;
}
@@ -1597,13 +1474,15 @@ static int vidioc_g_frequency(struct file *file, void *priv,
static int vidioc_s_frequency(struct file *file, void *priv,
const struct v4l2_frequency *freq)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
struct v4l2_frequency new_freq = *freq;
if (freq->tuner != 0)
return -EINVAL;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
au0828_init_tuner(dev);
i2c_gate_ctrl(dev, 1);
@@ -1625,8 +1504,10 @@ static int vidioc_s_frequency(struct file *file, void *priv,
static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
struct v4l2_format *format)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
format->fmt.vbi.samples_per_line = dev->vbi_width;
format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
@@ -1646,12 +1527,14 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
static int vidioc_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cc)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
if (cc->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
+
cc->bounds.left = 0;
cc->bounds.top = 0;
cc->bounds.width = dev->width;
@@ -1665,105 +1548,14 @@ static int vidioc_cropcap(struct file *file, void *priv,
return 0;
}
-static int vidioc_streamon(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc = -EINVAL;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (unlikely(type != fh->type))
- return -EINVAL;
-
- dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (unlikely(!res_get(fh, get_ressource(fh))))
- return -EBUSY;
-
- au0828_init_tuner(dev);
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- au0828_analog_stream_enable(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
- }
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- rc = videobuf_streamon(&fh->vb_vidq);
- dev->vid_timeout_running = 1;
- mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- rc = videobuf_streamon(&fh->vb_vbiq);
- dev->vbi_timeout_running = 1;
- mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
- }
-
- return rc;
-}
-
-static int vidioc_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type type)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
- int i;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
- return -EINVAL;
- if (type != fh->type)
- return -EINVAL;
-
- dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
- fh, type, fh->resources, dev->resources);
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- dev->vid_timeout_running = 0;
- del_timer_sync(&dev->vid_timeout);
-
- au0828_analog_stream_disable(dev);
- v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
- rc = au0828_stream_interrupt(dev);
- if (rc != 0)
- return rc;
-
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- if (AUVI_INPUT(i).audio_setup == NULL)
- continue;
- (AUVI_INPUT(i).audio_setup)(dev, 0);
- }
-
- if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh, AU0828_RESOURCE_VIDEO);
- }
- } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- dev->vbi_timeout_running = 0;
- del_timer_sync(&dev->vbi_timeout);
-
- if (res_check(fh, AU0828_RESOURCE_VBI)) {
- videobuf_streamoff(&fh->vb_vbiq);
- res_free(fh, AU0828_RESOURCE_VBI);
- }
- }
-
- return 0;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
reg->val = au0828_read(dev, reg->reg);
reg->size = 1;
@@ -1773,8 +1565,10 @@ static int vidioc_g_register(struct file *file, void *priv,
static int vidioc_s_register(struct file *file, void *priv,
const struct v4l2_dbg_register *reg)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = video_drvdata(file);
+
+ dprintk(1, "%s called std_set %d dev_state %d\n", __func__,
+ dev->std_set_in_tuner_core, dev->dev_state);
return au0828_writereg(dev, reg->reg, reg->val);
}
@@ -1784,93 +1578,13 @@ static int vidioc_log_status(struct file *file, void *fh)
{
struct video_device *vdev = video_devdata(file);
+ dprintk(1, "%s called\n", __func__);
+
v4l2_ctrl_log_status(file, fh);
v4l2_device_call_all(vdev->v4l2_dev, 0, core, log_status);
return 0;
}
-static int vidioc_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *rb)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_reqbufs(&fh->vb_vidq, rb);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_reqbufs(&fh->vb_vbiq, rb);
-
- return rc;
-}
-
-static int vidioc_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *b)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_querybuf(&fh->vb_vidq, b);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_querybuf(&fh->vb_vbiq, b);
-
- return rc;
-}
-
-static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_qbuf(&fh->vb_vidq, b);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_qbuf(&fh->vb_vbiq, b);
-
- return rc;
-}
-
-static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
-{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
-
- rc = check_dev(dev);
- if (rc < 0)
- return rc;
-
- /* Workaround for a bug in the au0828 hardware design that sometimes
- results in the colorspace being inverted */
- if (dev->greenscreen_detected == 1) {
- dprintk(1, "Detected green frame. Resetting stream...\n");
- au0828_analog_stream_reset(dev);
- dev->greenscreen_detected = 0;
- }
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- rc = videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
- else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- rc = videobuf_dqbuf(&fh->vb_vbiq, b, file->f_flags & O_NONBLOCK);
-
- return rc;
-}
-
void au0828_v4l2_suspend(struct au0828_dev *dev)
{
struct urb *urb;
@@ -1938,9 +1652,9 @@ static struct v4l2_file_operations au0828_v4l_fops = {
.owner = THIS_MODULE,
.open = au0828_v4l2_open,
.release = au0828_v4l2_close,
- .read = au0828_v4l2_read,
- .poll = au0828_v4l2_poll,
- .mmap = au0828_v4l2_mmap,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
@@ -1957,17 +1671,24 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+
.vidioc_s_std = vidioc_s_std,
.vidioc_g_std = vidioc_g_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,
@@ -1988,6 +1709,42 @@ static const struct video_device au0828_video_template = {
.tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL_M,
};
+static int au0828_vb2_setup(struct au0828_dev *dev)
+{
+ int rc;
+ struct vb2_queue *q;
+
+ /* Setup Videobuf2 for Video capture */
+ q = &dev->vb_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct au0828_buffer);
+ q->ops = &au0828_video_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+
+ rc = vb2_queue_init(q);
+ if (rc < 0)
+ return rc;
+
+ /* Setup Videobuf2 for VBI capture */
+ q = &dev->vb_vbiq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ q->io_modes = VB2_READ | VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct au0828_buffer);
+ q->ops = &au0828_vbi_qops;
+ q->mem_ops = &vb2_vmalloc_memops;
+
+ rc = vb2_queue_init(q);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
/**************************************************************************/
int au0828_analog_register(struct au0828_dev *dev,
@@ -2030,7 +1787,6 @@ int au0828_analog_register(struct au0828_dev *dev,
}
if (!(dev->isoc_in_endpointaddr)) {
pr_info("Could not locate isoc endpoint\n");
- kfree(dev);
return -ENODEV;
}
@@ -2039,17 +1795,12 @@ int au0828_analog_register(struct au0828_dev *dev,
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
INIT_LIST_HEAD(&dev->vbiq.active);
- INIT_LIST_HEAD(&dev->vbiq.queued);
-
- dev->vid_timeout.function = au0828_vid_buffer_timeout;
- dev->vid_timeout.data = (unsigned long) dev;
- init_timer(&dev->vid_timeout);
- dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
- dev->vbi_timeout.data = (unsigned long) dev;
- init_timer(&dev->vbi_timeout);
+ setup_timer(&dev->vid_timeout, au0828_vid_buffer_timeout,
+ (unsigned long)dev);
+ setup_timer(&dev->vbi_timeout, au0828_vbi_buffer_timeout,
+ (unsigned long)dev);
dev->width = NTSC_STD_W;
dev->height = NTSC_STD_H;
@@ -2078,18 +1829,34 @@ int au0828_analog_register(struct au0828_dev *dev,
goto err_vdev;
}
+ mutex_init(&dev->vb_queue_lock);
+ mutex_init(&dev->vb_vbi_queue_lock);
+
/* Fill the video capture device struct */
*dev->vdev = au0828_video_template;
dev->vdev->v4l2_dev = &dev->v4l2_dev;
dev->vdev->lock = &dev->lock;
+ dev->vdev->queue = &dev->vb_vidq;
+ dev->vdev->queue->lock = &dev->vb_queue_lock;
strcpy(dev->vdev->name, "au0828a video");
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
dev->vbi_dev->v4l2_dev = &dev->v4l2_dev;
dev->vbi_dev->lock = &dev->lock;
+ dev->vbi_dev->queue = &dev->vb_vbiq;
+ dev->vbi_dev->queue->lock = &dev->vb_vbi_queue_lock;
strcpy(dev->vbi_dev->name, "au0828a vbi");
+ /* initialize videobuf2 stuff */
+ retval = au0828_vb2_setup(dev);
+ if (retval != 0) {
+ dprintk(1, "unable to setup videobuf2 queues (error = %d).\n",
+ retval);
+ ret = -ENODEV;
+ goto err_vbi_dev;
+ }
+
/* Register the v4l2 device */
video_set_drvdata(dev->vdev, dev);
retval = video_register_device(dev->vdev, VFL_TYPE_GRABBER, -1);
@@ -2097,7 +1864,7 @@ int au0828_analog_register(struct au0828_dev *dev,
dprintk(1, "unable to register video device (error = %d).\n",
retval);
ret = -ENODEV;
- goto err_vbi_dev;
+ goto err_reg_vdev;
}
/* Register the vbi device */
@@ -2107,13 +1874,18 @@ int au0828_analog_register(struct au0828_dev *dev,
dprintk(1, "unable to register vbi device (error = %d).\n",
retval);
ret = -ENODEV;
- goto err_vbi_dev;
+ goto err_reg_vbi_dev;
}
dprintk(1, "%s completed!\n", __func__);
return 0;
+err_reg_vbi_dev:
+ video_unregister_device(dev->vdev);
+err_reg_vdev:
+ vb2_queue_release(&dev->vb_vidq);
+ vb2_queue_release(&dev->vb_vbiq);
err_vbi_dev:
video_device_release(dev->vbi_dev);
err_vdev:
diff --git a/drivers/media/usb/au0828/au0828.h b/drivers/media/usb/au0828/au0828.h
index 36815a369c68..eb1518742ae6 100644
--- a/drivers/media/usb/au0828/au0828.h
+++ b/drivers/media/usb/au0828/au0828.h
@@ -28,7 +28,7 @@
/* Analog */
#include <linux/videodev2.h>
-#include <media/videobuf-vmalloc.h>
+#include <media/videobuf2-vmalloc.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
@@ -126,17 +126,7 @@ enum au0828_dev_state {
DEV_MISCONFIGURED = 0x04
};
-struct au0828_fh {
- /* must be the first field of this struct! */
- struct v4l2_fh fh;
-
- struct au0828_dev *dev;
- unsigned int resources;
-
- struct videobuf_queue vb_vidq;
- struct videobuf_queue vb_vbiq;
- enum v4l2_buf_type type;
-};
+struct au0828_dev;
struct au0828_usb_isoc_ctl {
/* max packet size of isoc transaction */
@@ -177,21 +167,20 @@ struct au0828_usb_isoc_ctl {
/* buffer for one video frame */
struct au0828_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+ struct vb2_buffer vb;
+ struct list_head list;
- struct list_head frame;
+ void *mem;
+ unsigned long length;
int top_field;
- int receiving;
+ /* pointer to vmalloc memory address in vb */
+ char *vb_buf;
};
struct au0828_dmaqueue {
struct list_head active;
- struct list_head queued;
-
- wait_queue_head_t wq;
-
/* Counters to control buffer fill */
- int pos;
+ int pos;
};
struct au0828_dev {
@@ -220,14 +209,26 @@ struct au0828_dev {
struct au0828_rc *ir;
#endif
- int users;
- unsigned int resources; /* resources in use */
struct video_device *vdev;
struct video_device *vbi_dev;
+
+ /* Videobuf2 */
+ struct vb2_queue vb_vidq;
+ struct vb2_queue vb_vbiq;
+ struct mutex vb_queue_lock;
+ struct mutex vb_vbi_queue_lock;
+
+ unsigned int frame_count;
+ unsigned int vbi_frame_count;
+
struct timer_list vid_timeout;
int vid_timeout_running;
struct timer_list vbi_timeout;
int vbi_timeout_running;
+
+ int users;
+ int streaming_users;
+
int width;
int height;
int vbi_width;
@@ -242,7 +243,6 @@ struct au0828_dev {
__u8 isoc_in_endpointaddr;
u8 isoc_init_ok;
int greenscreen_detected;
- unsigned int frame_count;
int ctrl_freq;
int input_type;
int std_set_in_tuner_core;
@@ -277,6 +277,7 @@ struct au0828_dev {
char *dig_transfer_buffer[URB_COUNT];
};
+
/* ----------------------------------------------------------- */
#define au0828_read(dev, reg) au0828_readreg(dev, reg)
#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
@@ -309,13 +310,15 @@ extern int au0828_i2c_unregister(struct au0828_dev *dev);
/* ----------------------------------------------------------- */
/* au0828-video.c */
-int au0828_analog_register(struct au0828_dev *dev,
+extern int au0828_analog_register(struct au0828_dev *dev,
struct usb_interface *interface);
-int au0828_analog_stream_disable(struct au0828_dev *d);
-void au0828_analog_unregister(struct au0828_dev *dev);
+extern void au0828_analog_unregister(struct au0828_dev *dev);
+extern int au0828_start_analog_streaming(struct vb2_queue *vq,
+ unsigned int count);
+extern void au0828_stop_vbi_streaming(struct vb2_queue *vq);
#ifdef CONFIG_VIDEO_AU0828_V4L2
-void au0828_v4l2_suspend(struct au0828_dev *dev);
-void au0828_v4l2_resume(struct au0828_dev *dev);
+extern void au0828_v4l2_suspend(struct au0828_dev *dev);
+extern void au0828_v4l2_resume(struct au0828_dev *dev);
#else
static inline void au0828_v4l2_suspend(struct au0828_dev *dev) { };
static inline void au0828_v4l2_resume(struct au0828_dev *dev) { };
@@ -329,7 +332,7 @@ void au0828_dvb_suspend(struct au0828_dev *dev);
void au0828_dvb_resume(struct au0828_dev *dev);
/* au0828-vbi.c */
-extern struct videobuf_queue_ops au0828_vbi_qops;
+extern struct vb2_ops au0828_vbi_qops;
#define dprintk(level, fmt, arg...)\
do { if (au0828_debug & level)\
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index ae05d591f228..da03733690bd 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -1403,7 +1403,6 @@ 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)
@@ -1424,11 +1423,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
}
} 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) {
- clear_bit(nr, &cx231xx_devused);
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto err_if;
}
snprintf(dev->name, 29, "cx231xx #%d", nr);
@@ -1582,7 +1583,7 @@ err_v4l2:
usb_set_intfdata(interface, NULL);
err_if:
usb_put_dev(udev);
- clear_bit(dev->devno, &cx231xx_devused);
+ clear_bit(nr, &cx231xx_devused);
return retval;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 53ca12c1ff69..ecea76fe07f6 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -2062,7 +2062,6 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
- vfd->debug = video_debug;
vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index f9e262eb0db9..6d6f3ee812f6 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -532,15 +532,7 @@ struct cx231xx_video_mode {
unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
u16 end_point_addr;
};
-/*
-struct cx23885_dmaqueue {
- struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
- struct btcx_riscmem stopper;
- u32 count;
-};
-*/
+
struct cx231xx_tsport {
struct cx231xx *dev;
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb.h b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
index 14e111e13e54..41c6363dff08 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb.h
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb.h
@@ -354,6 +354,7 @@ struct dvb_usb_adapter {
* @name: device name
* @rc_map: name of rc codes table
* @rc_polling_active: set when RC polling is active
+ * @intf: pointer to the device's struct usb_interface
* @udev: pointer to the device's struct usb_device
* @rc: remote controller configuration
* @powered: indicated whether the device is power or not
@@ -370,6 +371,7 @@ struct dvb_usb_device {
const char *name;
const char *rc_map;
bool rc_polling_active;
+ struct usb_interface *intf;
struct usb_device *udev;
struct dvb_usb_rc rc;
int powered;
diff --git a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
index 1950f37df835..9913e0f59485 100644
--- a/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
+++ b/drivers/media/usb/dvb-usb-v2/dvb_usb_core.c
@@ -868,6 +868,7 @@ int dvb_usbv2_probe(struct usb_interface *intf,
goto err;
}
+ d->intf = intf;
d->name = driver_info->name;
d->rc_map = driver_info->rc_map;
d->udev = udev;
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 994de53a574b..5de6f7c04d09 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -126,9 +126,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct lme2510_state {
unsigned long int_urb_due;
+ fe_status_t lock_status;
u8 id;
u8 tuner_config;
- u8 signal_lock;
u8 signal_level;
u8 signal_sn;
u8 time_key;
@@ -143,6 +143,12 @@ struct lme2510_state {
void *buffer;
struct urb *lme_urb;
void *usb_buffer;
+ /* Frontend original calls */
+ int (*fe_read_status)(struct dvb_frontend *, fe_status_t *);
+ int (*fe_read_signal_strength)(struct dvb_frontend *, u16 *);
+ int (*fe_read_snr)(struct dvb_frontend *, u16 *);
+ int (*fe_read_ber)(struct dvb_frontend *, u32 *);
+ int (*fe_read_ucblocks)(struct dvb_frontend *, u32 *);
int (*fe_set_voltage)(struct dvb_frontend *, fe_sec_voltage_t);
u8 dvb_usb_lme2510_firmware;
};
@@ -258,6 +264,7 @@ static void lme2510_int_response(struct urb *lme_urb)
static u8 *ibuf, *rbuf;
int i = 0, offset;
u32 key;
+ u8 signal_lock = 0;
switch (lme_urb->status) {
case 0:
@@ -298,8 +305,7 @@ static void lme2510_int_response(struct urb *lme_urb)
case 0xbb:
switch (st->tuner_config) {
case TUNER_LG:
- if (ibuf[2] > 0)
- st->signal_lock = ibuf[2];
+ signal_lock = ibuf[2] & BIT(5);
st->signal_level = ibuf[4];
st->signal_sn = ibuf[3];
st->time_key = ibuf[7];
@@ -308,29 +314,29 @@ static void lme2510_int_response(struct urb *lme_urb)
case TUNER_S0194:
/* Tweak for earlier firmware*/
if (ibuf[1] == 0x03) {
- if (ibuf[2] > 1)
- st->signal_lock = ibuf[2];
+ signal_lock = ibuf[2] & BIT(4);
st->signal_level = ibuf[3];
st->signal_sn = ibuf[4];
} else {
st->signal_level = ibuf[4];
st->signal_sn = ibuf[5];
- st->signal_lock =
- (st->signal_lock & 0xf7) +
- ((ibuf[2] & 0x01) << 0x03);
}
break;
case TUNER_RS2000:
- if (ibuf[2] & 0x1)
- st->signal_lock = 0xff;
- else
- st->signal_lock = 0x00;
+ signal_lock = ibuf[2] & 0xee;
st->signal_level = ibuf[5];
st->signal_sn = ibuf[4];
st->time_key = ibuf[7];
default:
break;
}
+
+ /* Interrupt will also throw just BIT 0 as lock */
+ signal_lock |= ibuf[2] & BIT(0);
+
+ if (!signal_lock)
+ st->lock_status &= ~FE_HAS_LOCK;
+
debug_data_snipet(5, "INT Remote data snipet in", ibuf);
break;
case 0xcc:
@@ -344,15 +350,17 @@ static void lme2510_int_response(struct urb *lme_urb)
usb_submit_urb(lme_urb, GFP_ATOMIC);
- /* interrupt urb is due every 48 msecs while streaming
- * add 12msecs for system lag */
- st->int_urb_due = jiffies + msecs_to_jiffies(60);
+ /* Interrupt urb is due every 48 msecs while streaming the buffer
+ * stores up to 4 periods if missed. Allow 200 msec for next interrupt.
+ */
+ st->int_urb_due = jiffies + msecs_to_jiffies(200);
}
static int lme2510_int_read(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
struct lme2510_state *lme_int = adap_to_priv(adap);
+ struct usb_host_endpoint *ep;
lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -374,6 +382,12 @@ static int lme2510_int_read(struct dvb_usb_adapter *adap)
adap,
8);
+ /* Quirk of pipe reporting PIPE_BULK but behaves as interrupt */
+ ep = usb_pipe_endpoint(d->udev, lme_int->lme_urb->pipe);
+
+ if (usb_endpoint_type(&ep->desc) == USB_ENDPOINT_XFER_BULK)
+ lme_int->lme_urb->pipe = usb_rcvbulkpipe(d->udev, 0xa),
+
lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
@@ -449,170 +463,13 @@ static int lme2510_return_status(struct dvb_usb_device *d)
static int lme2510_msg(struct dvb_usb_device *d,
u8 *wbuf, int wlen, u8 *rbuf, int rlen)
{
- int ret = 0;
struct lme2510_state *st = d->priv;
- if (st->i2c_talk_onoff == 1) {
-
- ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
-
- switch (st->tuner_config) {
- case TUNER_LG:
- if (wbuf[2] == 0x1c) {
- if (wbuf[3] == 0x0e) {
- st->signal_lock = rbuf[1];
- if ((st->stream_on & 1) &&
- (st->signal_lock & 0x10)) {
- lme2510_stream_restart(d);
- st->i2c_talk_onoff = 0;
- }
- msleep(80);
- }
- }
- break;
- case TUNER_S7395:
- if (wbuf[2] == 0xd0) {
- if (wbuf[3] == 0x24) {
- st->signal_lock = rbuf[1];
- if ((st->stream_on & 1) &&
- (st->signal_lock & 0x8)) {
- lme2510_stream_restart(d);
- st->i2c_talk_onoff = 0;
- }
- }
- }
- break;
- case TUNER_S0194:
- if (wbuf[2] == 0xd0) {
- if (wbuf[3] == 0x1b) {
- st->signal_lock = rbuf[1];
- if ((st->stream_on & 1) &&
- (st->signal_lock & 0x8)) {
- lme2510_stream_restart(d);
- st->i2c_talk_onoff = 0;
- }
- }
- }
- break;
- case TUNER_RS2000:
- default:
- break;
- }
- } else {
- /* TODO rewrite this section */
- switch (st->tuner_config) {
- case TUNER_LG:
- switch (wbuf[3]) {
- case 0x0e:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
- break;
- case 0x43:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_level;
- break;
- case 0x1c:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_sn;
- break;
- case 0x15:
- case 0x16:
- case 0x17:
- case 0x18:
- rbuf[0] = 0x55;
- rbuf[1] = 0x00;
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- break;
- }
- break;
- case TUNER_S7395:
- switch (wbuf[3]) {
- case 0x10:
- rbuf[0] = 0x55;
- rbuf[1] = (st->signal_level & 0x80)
- ? 0 : (st->signal_level * 2);
- break;
- case 0x2d:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_sn;
- break;
- case 0x24:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
- break;
- case 0x2e:
- case 0x26:
- case 0x27:
- rbuf[0] = 0x55;
- rbuf[1] = 0x00;
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- break;
- }
- break;
- case TUNER_S0194:
- switch (wbuf[3]) {
- case 0x18:
- rbuf[0] = 0x55;
- rbuf[1] = (st->signal_level & 0x80)
- ? 0 : (st->signal_level * 2);
- break;
- case 0x24:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_sn;
- break;
- case 0x1b:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
- break;
- case 0x19:
- case 0x25:
- case 0x1e:
- case 0x1d:
- rbuf[0] = 0x55;
- rbuf[1] = 0x00;
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- break;
- }
- break;
- case TUNER_RS2000:
- switch (wbuf[3]) {
- case 0x8c:
- rbuf[0] = 0x55;
- rbuf[1] = st->signal_lock;
-
- /* If int_urb_due overdue
- * set rbuf[1] to 0 to clear lock */
- if (time_after(jiffies, st->int_urb_due))
- rbuf[1] = 0;
-
- break;
- default:
- lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
- st->i2c_talk_onoff = 1;
- break;
- }
- default:
- break;
- }
-
- deb_info(4, "I2C From Interrupt Message out(%02x) in(%02x)",
- wbuf[3], rbuf[1]);
-
- }
+ st->i2c_talk_onoff = 1;
- return ret;
+ return lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
}
-
static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
{
@@ -935,26 +792,8 @@ static struct stv0299_config sharp_z0194_config = {
.set_symbol_rate = sharp_z0194a_set_symbol_rate,
};
-static int dm04_rs2000_set_ts_param(struct dvb_frontend *fe,
- int caller)
-{
- struct dvb_usb_adapter *adap = fe_to_adap(fe);
- struct dvb_usb_device *d = adap_to_d(adap);
- struct lme2510_state *st = d->priv;
-
- mutex_lock(&d->i2c_mutex);
- if ((st->i2c_talk_onoff == 1) && (st->stream_on & 1)) {
- st->i2c_talk_onoff = 0;
- lme2510_stream_restart(d);
- }
- mutex_unlock(&d->i2c_mutex);
-
- return 0;
-}
-
static struct m88rs2000_config m88rs2000_config = {
- .demod_addr = 0x68,
- .set_ts_params = dm04_rs2000_set_ts_param,
+ .demod_addr = 0x68
};
static struct ts2020_config ts2020_config = {
@@ -998,27 +837,101 @@ static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
return (ret < 0) ? -ENODEV : 0;
}
-static int dm04_rs2000_read_signal_strength(struct dvb_frontend *fe,
- u16 *strength)
+static int dm04_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ struct lme2510_state *st = d->priv;
+ int ret = 0;
+
+ if (st->i2c_talk_onoff) {
+ if (st->fe_read_status) {
+ ret = st->fe_read_status(fe, status);
+ if (ret < 0)
+ return ret;
+ }
+
+ st->lock_status = *status;
+
+ if (*status & FE_HAS_LOCK && st->stream_on) {
+ mutex_lock(&d->i2c_mutex);
+
+ st->i2c_talk_onoff = 0;
+ ret = lme2510_stream_restart(d);
+
+ mutex_unlock(&d->i2c_mutex);
+ }
+
+ return ret;
+ }
+
+ /* Timeout of interrupt reached on RS2000 */
+ if (st->tuner_config == TUNER_RS2000 &&
+ time_after(jiffies, st->int_urb_due))
+ st->lock_status &= ~FE_HAS_LOCK;
+
+ *status = st->lock_status;
+
+ if (!(*status & FE_HAS_LOCK))
+ st->i2c_talk_onoff = 1;
+
+ return ret;
+}
+
+static int dm04_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct lme2510_state *st = fe_to_priv(fe);
- *strength = (u16)((u32)st->signal_level * 0xffff / 0xff);
+ if (st->fe_read_signal_strength && !st->stream_on)
+ return st->fe_read_signal_strength(fe, strength);
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ *strength = 0xff - st->signal_level;
+ *strength |= *strength << 8;
+ break;
+ /* fall through */
+ case TUNER_S7395:
+ case TUNER_S0194:
+ *strength = 0xffff - (((st->signal_level * 2) << 8) * 5 / 4);
+ break;
+ case TUNER_RS2000:
+ *strength = (u16)((u32)st->signal_level * 0xffff / 0xff);
+ }
return 0;
}
-static int dm04_rs2000_read_snr(struct dvb_frontend *fe, u16 *snr)
+static int dm04_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct lme2510_state *st = fe_to_priv(fe);
- *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f);
+ if (st->fe_read_snr && !st->stream_on)
+ return st->fe_read_snr(fe, snr);
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ *snr = 0xff - st->signal_sn;
+ *snr |= *snr << 8;
+ break;
+ /* fall through */
+ case TUNER_S7395:
+ case TUNER_S0194:
+ *snr = (u16)((0xff - st->signal_sn - 0xa1) * 3) << 8;
+ break;
+ case TUNER_RS2000:
+ *snr = (u16)((u32)st->signal_sn * 0xffff / 0x7f);
+ }
return 0;
}
static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber)
{
+ struct lme2510_state *st = fe_to_priv(fe);
+
+ if (st->fe_read_ber && !st->stream_on)
+ return st->fe_read_ber(fe, ber);
+
*ber = 0;
return 0;
@@ -1026,6 +939,11 @@ static int dm04_read_ber(struct dvb_frontend *fe, u32 *ber)
static int dm04_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
{
+ struct lme2510_state *st = fe_to_priv(fe);
+
+ if (st->fe_read_ucblocks && !st->stream_on)
+ return st->fe_read_ucblocks(fe, ucblocks);
+
*ucblocks = 0;
return 0;
@@ -1119,15 +1037,6 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
st->tuner_config = TUNER_RS2000;
st->fe_set_voltage =
adap->fe[0]->ops.set_voltage;
-
- adap->fe[0]->ops.read_signal_strength =
- dm04_rs2000_read_signal_strength;
- adap->fe[0]->ops.read_snr =
- dm04_rs2000_read_snr;
- adap->fe[0]->ops.read_ber =
- dm04_read_ber;
- adap->fe[0]->ops.read_ucblocks =
- dm04_read_ucblocks;
}
break;
}
@@ -1146,7 +1055,19 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
return -ENODEV;
}
+ st->fe_read_status = adap->fe[0]->ops.read_status;
+ st->fe_read_signal_strength = adap->fe[0]->ops.read_signal_strength;
+ st->fe_read_snr = adap->fe[0]->ops.read_snr;
+ st->fe_read_ber = adap->fe[0]->ops.read_ber;
+ st->fe_read_ucblocks = adap->fe[0]->ops.read_ucblocks;
+
+ adap->fe[0]->ops.read_status = dm04_read_status;
+ adap->fe[0]->ops.read_signal_strength = dm04_read_signal_strength;
+ adap->fe[0]->ops.read_snr = dm04_read_snr;
+ adap->fe[0]->ops.read_ber = dm04_read_ber;
+ adap->fe[0]->ops.read_ucblocks = dm04_read_ucblocks;
adap->fe[0]->ops.set_voltage = dm04_lme2510_set_voltage;
+
ret = lme_name(adap);
return ret;
}
@@ -1288,7 +1209,6 @@ static void *lme2510_exit_int(struct dvb_usb_device *d)
if (st->usb_buffer != NULL) {
st->i2c_talk_onoff = 1;
- st->signal_lock = 0;
st->signal_level = 0;
st->signal_sn = 0;
buffer = st->usb_buffer;
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
index 0a98d04c53e4..ecefa5c477fa 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.c
@@ -604,9 +604,3 @@ MODULE_DESCRIPTION("MaxLinear MxL111SF DVB-T demodulator driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
index 2d4530f5be54..0bd83e52669c 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-demod.h
@@ -47,9 +47,3 @@ struct dvb_frontend *mxl111sf_demod_attach(struct mxl111sf_state *mxl_state,
#endif /* CONFIG_DVB_USB_MXL111SF */
#endif /* __MXL111SF_DEMOD_H__ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
index a619410adde4..2180c13a6dcc 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
@@ -755,9 +755,3 @@ int mxl111sf_gpio_mode_switch(struct mxl111sf_state *state, unsigned int mode)
}
return 0;
}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
index b85a5772d771..16fa4d4daf88 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.h
@@ -48,9 +48,3 @@ int mxl111sf_config_pin_mux_modes(struct mxl111sf_state *state,
enum mxl111sf_mux_config pin_mux_config);
#endif /* _DVB_USB_MXL111SF_GPIO_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
index a101d06eb143..283495c84ba3 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.c
@@ -842,9 +842,3 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
return i == num ? num : -EREMOTEIO;
}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
index 465762145ad2..c486fe02f018 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-i2c.h
@@ -27,9 +27,3 @@ int mxl111sf_i2c_xfer(struct i2c_adapter *adap,
struct i2c_msg msg[], int num);
#endif /* _DVB_USB_MXL111SF_I2C_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
index f6b348024bec..5b0191178f9f 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.c
@@ -335,9 +335,3 @@ int mxl111sf_idac_config(struct mxl111sf_state *state,
return ret;
}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
index 0643738de7de..25aa4a1ea755 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-phy.h
@@ -45,9 +45,3 @@ int mxl111sf_idac_config(struct mxl111sf_state *state,
u8 current_value, u8 hysteresis_value);
#endif /* _DVB_USB_MXL111SF_PHY_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
index 89bf115e927e..1f4bfbcdbabb 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-reg.h
@@ -171,9 +171,3 @@
#define V6_DIG_RF_PWR_MSB_REG 0x47
#endif /* _DVB_USB_MXL111SF_REG_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
index a8d2c7053674..444579be0b77 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.c
@@ -515,11 +515,3 @@ MODULE_DESCRIPTION("MaxLinear MxL111SF CMOS tuner driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1");
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
index 2046db22519e..e6caab21a197 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-tuner.h
@@ -77,12 +77,3 @@ struct dvb_frontend *mxl111sf_tuner_attach(struct dvb_frontend *fe,
#endif
#endif /* __MXL111SF_TUNER_H__ */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
-
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.c b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
index c3447eaf1104..bec12b0e076b 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.c
@@ -1425,9 +1425,3 @@ MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_DESCRIPTION("Driver for MaxLinear MxL111SF");
MODULE_VERSION("1.0");
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf.h b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
index 8516c011b7cc..ee70df1f1e94 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf.h
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf.h
@@ -152,9 +152,3 @@ extern int dvb_usb_mxl111sf_debug;
})
#endif /* _DVB_USB_MXL111SF_H_ */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 896a225ee011..77dcfdf547ac 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -22,42 +22,6 @@
#include "rtl28xxu.h"
-#include "rtl2830.h"
-#include "rtl2832.h"
-#include "rtl2832_sdr.h"
-#include "mn88472.h"
-#include "mn88473.h"
-
-#include "qt1010.h"
-#include "mt2060.h"
-#include "mxl5005s.h"
-#include "fc0012.h"
-#include "fc0013.h"
-#include "e4000.h"
-#include "fc2580.h"
-#include "tua9001.h"
-#include "r820t.h"
-
-
-#ifdef CONFIG_MEDIA_ATTACH
-#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
- void *__r = NULL; \
- typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
- if (__a) { \
- __r = (void *) __a(ARGS); \
- if (__r == NULL) \
- symbol_put(FUNCTION); \
- } \
- __r; \
-})
-
-#else
-#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
- FUNCTION(ARGS); \
-})
-
-#endif
-
static int rtl28xxu_disable_rc;
module_param_named(disable_rc, rtl28xxu_disable_rc, int, 0644);
MODULE_PARM_DESC(disable_rc, "disable RTL2832U remote controller");
@@ -65,20 +29,14 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
{
+ struct rtl28xxu_dev *dev = d->priv;
int ret;
unsigned int pipe;
u8 requesttype;
- u8 *buf;
-
- buf = kmalloc(req->size, GFP_KERNEL);
- if (!buf) {
- ret = -ENOMEM;
- goto err;
- }
if (req->index & CMD_WR_FLAG) {
/* write */
- memcpy(buf, req->data, req->size);
+ memcpy(dev->buf, req->data, req->size);
requesttype = (USB_TYPE_VENDOR | USB_DIR_OUT);
pipe = usb_sndctrlpipe(d->udev, 0);
} else {
@@ -88,30 +46,23 @@ static int rtl28xxu_ctrl_msg(struct dvb_usb_device *d, struct rtl28xxu_req *req)
}
ret = usb_control_msg(d->udev, pipe, 0, requesttype, req->value,
- req->index, buf, req->size, 1000);
-
+ req->index, dev->buf, req->size, 1000);
dvb_usb_dbg_usb_control_msg(d->udev, 0, requesttype, req->value,
- req->index, buf, req->size);
-
- if (ret > 0)
- ret = 0;
+ req->index, dev->buf, req->size);
+ if (ret < 0)
+ goto err;
/* read request, copy returned data to return buf */
- if (!ret && requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
- memcpy(req->data, buf, req->size);
+ if (requesttype == (USB_TYPE_VENDOR | USB_DIR_IN))
+ memcpy(req->data, dev->buf, req->size);
- kfree(buf);
-
- if (ret)
- goto err;
-
- return ret;
+ return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
-static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+static int rtl28xxu_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
{
struct rtl28xxu_req req;
@@ -129,7 +80,7 @@ static int rtl28xx_wr_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
return rtl28xxu_ctrl_msg(d, &req);
}
-static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
+static int rtl28xxu_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
{
struct rtl28xxu_req req;
@@ -147,17 +98,17 @@ static int rtl2831_rd_regs(struct dvb_usb_device *d, u16 reg, u8 *val, int len)
return rtl28xxu_ctrl_msg(d, &req);
}
-static int rtl28xx_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
+static int rtl28xxu_wr_reg(struct dvb_usb_device *d, u16 reg, u8 val)
{
- return rtl28xx_wr_regs(d, reg, &val, 1);
+ return rtl28xxu_wr_regs(d, reg, &val, 1);
}
-static int rtl28xx_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
+static int rtl28xxu_rd_reg(struct dvb_usb_device *d, u16 reg, u8 *val)
{
- return rtl2831_rd_regs(d, reg, val, 1);
+ return rtl28xxu_rd_regs(d, reg, val, 1);
}
-static int rtl28xx_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
+static int rtl28xxu_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
u8 mask)
{
int ret;
@@ -165,7 +116,7 @@ static int rtl28xx_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
/* no need for read if whole reg is written */
if (mask != 0xff) {
- ret = rtl28xx_rd_reg(d, reg, &tmp);
+ ret = rtl28xxu_rd_reg(d, reg, &tmp);
if (ret)
return ret;
@@ -174,7 +125,7 @@ static int rtl28xx_wr_reg_mask(struct dvb_usb_device *d, u16 reg, u8 val,
val |= tmp;
}
- return rtl28xx_wr_reg(d, reg, val);
+ return rtl28xxu_wr_reg(d, reg, val);
}
/* I2C */
@@ -183,7 +134,7 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
{
int ret;
struct dvb_usb_device *d = i2c_get_adapdata(adap);
- struct rtl28xxu_priv *priv = d->priv;
+ struct rtl28xxu_dev *dev = d->priv;
struct rtl28xxu_req req;
/*
@@ -220,7 +171,7 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
} else if (msg[0].addr == 0x10) {
/* method 1 - integrated demod */
req.value = (msg[0].buf[0] << 8) | (msg[0].addr << 1);
- req.index = CMD_DEMOD_RD | priv->page;
+ req.index = CMD_DEMOD_RD | dev->page;
req.size = msg[1].len;
req.data = &msg[1].buf[0];
ret = rtl28xxu_ctrl_msg(d, &req);
@@ -256,12 +207,12 @@ static int rtl28xxu_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
/* method 1 - integrated demod */
if (msg[0].buf[0] == 0x00) {
/* save demod page for later demod access */
- priv->page = msg[0].buf[1];
+ dev->page = msg[0].buf[1];
ret = 0;
} else {
req.value = (msg[0].buf[0] << 8) |
(msg[0].addr << 1);
- req.index = CMD_DEMOD_WR | priv->page;
+ req.index = CMD_DEMOD_WR | dev->page;
req.size = msg[0].len-1;
req.data = &msg[0].buf[1];
ret = rtl28xxu_ctrl_msg(d, &req);
@@ -303,7 +254,7 @@ static struct i2c_algorithm rtl28xxu_i2c_algo = {
static int rtl2831u_read_config(struct dvb_usb_device *d)
{
- struct rtl28xxu_priv *priv = d_to_priv(d);
+ struct rtl28xxu_dev *dev = d_to_priv(d);
int ret;
u8 buf[1];
/* open RTL2831U/RTL2830 I2C gate */
@@ -312,7 +263,7 @@ static int rtl2831u_read_config(struct dvb_usb_device *d)
struct rtl28xxu_req req_mt2060 = {0x00c0, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_qt1010 = {0x0fc4, CMD_I2C_RD, 1, buf};
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ dev_dbg(&d->intf->dev, "\n");
/*
* RTL2831U GPIOs
@@ -323,12 +274,12 @@ static int rtl2831u_read_config(struct dvb_usb_device *d)
*/
/* GPIO direction */
- ret = rtl28xx_wr_reg(d, SYS_GPIO_DIR, 0x0a);
+ ret = rtl28xxu_wr_reg(d, SYS_GPIO_DIR, 0x0a);
if (ret)
goto err;
/* enable as output GPIO0, GPIO2, GPIO4 */
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_EN, 0x15);
+ ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_EN, 0x15);
if (ret)
goto err;
@@ -340,7 +291,7 @@ static int rtl2831u_read_config(struct dvb_usb_device *d)
/* demod needs some time to wake up */
msleep(20);
- priv->tuner_name = "NONE";
+ dev->tuner_name = "NONE";
/* open demod I2C gate */
ret = rtl28xxu_ctrl_msg(d, &req_gate_open);
@@ -350,8 +301,8 @@ static int rtl2831u_read_config(struct dvb_usb_device *d)
/* check QT1010 ID(?) register; reg=0f val=2c */
ret = rtl28xxu_ctrl_msg(d, &req_qt1010);
if (ret == 0 && buf[0] == 0x2c) {
- priv->tuner = TUNER_RTL2830_QT1010;
- priv->tuner_name = "QT1010";
+ dev->tuner = TUNER_RTL2830_QT1010;
+ dev->tuner_name = "QT1010";
goto found;
}
@@ -363,28 +314,28 @@ static int rtl2831u_read_config(struct dvb_usb_device *d)
/* check MT2060 ID register; reg=00 val=63 */
ret = rtl28xxu_ctrl_msg(d, &req_mt2060);
if (ret == 0 && buf[0] == 0x63) {
- priv->tuner = TUNER_RTL2830_MT2060;
- priv->tuner_name = "MT2060";
+ dev->tuner = TUNER_RTL2830_MT2060;
+ dev->tuner_name = "MT2060";
goto found;
}
/* assume MXL5005S */
- priv->tuner = TUNER_RTL2830_MXL5005S;
- priv->tuner_name = "MXL5005S";
+ dev->tuner = TUNER_RTL2830_MXL5005S;
+ dev->tuner_name = "MXL5005S";
goto found;
found:
- dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
+ dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name);
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
static int rtl2832u_read_config(struct dvb_usb_device *d)
{
- struct rtl28xxu_priv *priv = d_to_priv(d);
+ struct rtl28xxu_dev *dev = d_to_priv(d);
int ret;
u8 buf[2];
/* open RTL2832U/RTL2832 I2C gate */
@@ -407,14 +358,14 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
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__);
+ dev_dbg(&d->intf->dev, "\n");
/* enable GPIO3 and GPIO6 as output */
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x40);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x40);
if (ret)
goto err;
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x48, 0x48);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x48, 0x48);
if (ret)
goto err;
@@ -428,134 +379,134 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret)
goto err;
- priv->tuner_name = "NONE";
+ dev->tuner_name = "NONE";
/* check FC0012 ID register; reg=00 val=a1 */
ret = rtl28xxu_ctrl_msg(d, &req_fc0012);
if (ret == 0 && buf[0] == 0xa1) {
- priv->tuner = TUNER_RTL2832_FC0012;
- priv->tuner_name = "FC0012";
+ dev->tuner = TUNER_RTL2832_FC0012;
+ dev->tuner_name = "FC0012";
goto tuner_found;
}
/* check FC0013 ID register; reg=00 val=a3 */
ret = rtl28xxu_ctrl_msg(d, &req_fc0013);
if (ret == 0 && buf[0] == 0xa3) {
- priv->tuner = TUNER_RTL2832_FC0013;
- priv->tuner_name = "FC0013";
+ dev->tuner = TUNER_RTL2832_FC0013;
+ dev->tuner_name = "FC0013";
goto tuner_found;
}
/* check MT2266 ID register; reg=00 val=85 */
ret = rtl28xxu_ctrl_msg(d, &req_mt2266);
if (ret == 0 && buf[0] == 0x85) {
- priv->tuner = TUNER_RTL2832_MT2266;
- priv->tuner_name = "MT2266";
+ dev->tuner = TUNER_RTL2832_MT2266;
+ dev->tuner_name = "MT2266";
goto tuner_found;
}
/* check FC2580 ID register; reg=01 val=56 */
ret = rtl28xxu_ctrl_msg(d, &req_fc2580);
if (ret == 0 && buf[0] == 0x56) {
- priv->tuner = TUNER_RTL2832_FC2580;
- priv->tuner_name = "FC2580";
+ dev->tuner = TUNER_RTL2832_FC2580;
+ dev->tuner_name = "FC2580";
goto tuner_found;
}
/* check MT2063 ID register; reg=00 val=9e || 9c */
ret = rtl28xxu_ctrl_msg(d, &req_mt2063);
if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
- priv->tuner = TUNER_RTL2832_MT2063;
- priv->tuner_name = "MT2063";
+ dev->tuner = TUNER_RTL2832_MT2063;
+ dev->tuner_name = "MT2063";
goto tuner_found;
}
/* check MAX3543 ID register; reg=00 val=38 */
ret = rtl28xxu_ctrl_msg(d, &req_max3543);
if (ret == 0 && buf[0] == 0x38) {
- priv->tuner = TUNER_RTL2832_MAX3543;
- priv->tuner_name = "MAX3543";
+ dev->tuner = TUNER_RTL2832_MAX3543;
+ dev->tuner_name = "MAX3543";
goto tuner_found;
}
/* check TUA9001 ID register; reg=7e val=2328 */
ret = rtl28xxu_ctrl_msg(d, &req_tua9001);
if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
- priv->tuner = TUNER_RTL2832_TUA9001;
- priv->tuner_name = "TUA9001";
+ dev->tuner = TUNER_RTL2832_TUA9001;
+ dev->tuner_name = "TUA9001";
goto tuner_found;
}
/* check MXL5007R ID register; reg=d9 val=14 */
ret = rtl28xxu_ctrl_msg(d, &req_mxl5007t);
if (ret == 0 && buf[0] == 0x14) {
- priv->tuner = TUNER_RTL2832_MXL5007T;
- priv->tuner_name = "MXL5007T";
+ dev->tuner = TUNER_RTL2832_MXL5007T;
+ dev->tuner_name = "MXL5007T";
goto tuner_found;
}
/* check E4000 ID register; reg=02 val=40 */
ret = rtl28xxu_ctrl_msg(d, &req_e4000);
if (ret == 0 && buf[0] == 0x40) {
- priv->tuner = TUNER_RTL2832_E4000;
- priv->tuner_name = "E4000";
+ dev->tuner = TUNER_RTL2832_E4000;
+ dev->tuner_name = "E4000";
goto tuner_found;
}
/* check TDA18272 ID register; reg=00 val=c760 */
ret = rtl28xxu_ctrl_msg(d, &req_tda18272);
if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
- priv->tuner = TUNER_RTL2832_TDA18272;
- priv->tuner_name = "TDA18272";
+ dev->tuner = TUNER_RTL2832_TDA18272;
+ dev->tuner_name = "TDA18272";
goto tuner_found;
}
/* check R820T ID register; reg=00 val=69 */
ret = rtl28xxu_ctrl_msg(d, &req_r820t);
if (ret == 0 && buf[0] == 0x69) {
- priv->tuner = TUNER_RTL2832_R820T;
- priv->tuner_name = "R820T";
+ dev->tuner = TUNER_RTL2832_R820T;
+ dev->tuner_name = "R820T";
goto tuner_found;
}
/* check R828D ID register; reg=00 val=69 */
ret = rtl28xxu_ctrl_msg(d, &req_r828d);
if (ret == 0 && buf[0] == 0x69) {
- priv->tuner = TUNER_RTL2832_R828D;
- priv->tuner_name = "R828D";
+ dev->tuner = TUNER_RTL2832_R828D;
+ dev->tuner_name = "R828D";
goto tuner_found;
}
tuner_found:
- dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
+ dev_dbg(&d->intf->dev, "tuner=%s\n", dev->tuner_name);
/* probe slave demod */
- if (priv->tuner == TUNER_RTL2832_R828D) {
+ if (dev->tuner == TUNER_RTL2832_R828D) {
/* power on MN88472 demod on GPIO0 */
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01);
+ ret = rtl28xxu_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);
+ ret = rtl28xxu_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);
+ ret = rtl28xxu_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;
+ dev_dbg(&d->intf->dev, "MN88472 found\n");
+ dev->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;
+ dev_dbg(&d->intf->dev, "MN88473 found\n");
+ dev->slave_demod = SLAVE_DEMOD_MN88473;
goto demod_found;
}
}
@@ -568,14 +519,51 @@ demod_found:
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
-static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
- .ts_mode = 0,
+static int rtl28xxu_read_config(struct dvb_usb_device *d)
+{
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U)
+ return rtl2831u_read_config(d);
+ else
+ return rtl2832u_read_config(d);
+}
+
+static int rtl28xxu_identify_state(struct dvb_usb_device *d, const char **name)
+{
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+ int ret;
+ struct rtl28xxu_req req_demod_i2c = {0x0020, CMD_I2C_DA_RD, 0, NULL};
+
+ dev_dbg(&d->intf->dev, "\n");
+
+ /*
+ * Detect chip type using I2C command that is not supported
+ * by old RTL2831U.
+ */
+ ret = rtl28xxu_ctrl_msg(d, &req_demod_i2c);
+ if (ret == -EPIPE) {
+ dev->chip_id = CHIP_ID_RTL2831U;
+ } else if (ret == 0) {
+ dev->chip_id = CHIP_ID_RTL2832U;
+ } else {
+ dev_err(&d->intf->dev, "chip type detection failed %d\n", ret);
+ goto err;
+ }
+ dev_dbg(&d->intf->dev, "chip_id=%u\n", dev->chip_id);
+
+ return WARM;
+err:
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static const struct rtl2830_platform_data rtl2830_mt2060_platform_data = {
+ .clk = 28800000,
.spec_inv = 1,
.vtop = 0x20,
.krf = 0x04,
@@ -583,20 +571,16 @@ static const struct rtl2830_config rtl28xxu_rtl2830_mt2060_config = {
};
-static const struct rtl2830_config rtl28xxu_rtl2830_qt1010_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
- .ts_mode = 0,
+static const struct rtl2830_platform_data rtl2830_qt1010_platform_data = {
+ .clk = 28800000,
.spec_inv = 1,
.vtop = 0x20,
.krf = 0x04,
.agc_targ_val = 0x2d,
};
-static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
- .ts_mode = 0,
+static const struct rtl2830_platform_data rtl2830_mxl5005s_platform_data = {
+ .clk = 28800000,
.spec_inv = 0,
.vtop = 0x3f,
.krf = 0x04,
@@ -606,69 +590,81 @@ static const struct rtl2830_config rtl28xxu_rtl2830_mxl5005s_config = {
static int rtl2831u_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap_to_d(adap);
- struct rtl28xxu_priv *priv = d_to_priv(d);
- const struct rtl2830_config *rtl2830_config;
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+ struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data;
+ struct i2c_board_info board_info;
+ struct i2c_client *client;
int ret;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ dev_dbg(&d->intf->dev, "\n");
- switch (priv->tuner) {
+ switch (dev->tuner) {
case TUNER_RTL2830_QT1010:
- rtl2830_config = &rtl28xxu_rtl2830_qt1010_config;
+ *pdata = rtl2830_qt1010_platform_data;
break;
case TUNER_RTL2830_MT2060:
- rtl2830_config = &rtl28xxu_rtl2830_mt2060_config;
+ *pdata = rtl2830_mt2060_platform_data;
break;
case TUNER_RTL2830_MXL5005S:
- rtl2830_config = &rtl28xxu_rtl2830_mxl5005s_config;
+ *pdata = rtl2830_mxl5005s_platform_data;
break;
default:
- dev_err(&d->udev->dev, "%s: unknown tuner=%s\n",
- KBUILD_MODNAME, priv->tuner_name);
+ dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name);
ret = -ENODEV;
goto err;
}
/* attach demodulator */
- adap->fe[0] = dvb_attach(rtl2830_attach, rtl2830_config, &d->i2c_adap);
- if (!adap->fe[0]) {
+ memset(&board_info, 0, sizeof(board_info));
+ strlcpy(board_info.type, "rtl2830", I2C_NAME_SIZE);
+ board_info.addr = 0x10;
+ board_info.platform_data = pdata;
+ request_module("%s", board_info.type);
+ client = i2c_new_device(&d->i2c_adap, &board_info);
+ if (client == NULL || client->dev.driver == NULL) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
ret = -ENODEV;
goto err;
}
+ adap->fe[0] = pdata->get_dvb_frontend(client);
+ dev->demod_i2c_adapter = pdata->get_i2c_adapter(client);
+
+ dev->i2c_client_demod = client;
+
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
-static const struct rtl2832_config rtl28xxu_rtl2832_fc0012_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
+static const struct rtl2832_platform_data rtl2832_fc0012_platform_data = {
+ .clk = 28800000,
.tuner = TUNER_RTL2832_FC0012
};
-static const struct rtl2832_config rtl28xxu_rtl2832_fc0013_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
+static const struct rtl2832_platform_data rtl2832_fc0013_platform_data = {
+ .clk = 28800000,
.tuner = TUNER_RTL2832_FC0013
};
-static const struct rtl2832_config rtl28xxu_rtl2832_tua9001_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
+static const struct rtl2832_platform_data rtl2832_tua9001_platform_data = {
+ .clk = 28800000,
.tuner = TUNER_RTL2832_TUA9001,
};
-static const struct rtl2832_config rtl28xxu_rtl2832_e4000_config = {
- .i2c_addr = 0x10, /* 0x20 */
- .xtal = 28800000,
+static const struct rtl2832_platform_data rtl2832_e4000_platform_data = {
+ .clk = 28800000,
.tuner = TUNER_RTL2832_E4000,
};
-static const struct rtl2832_config rtl28xxu_rtl2832_r820t_config = {
- .i2c_addr = 0x10,
- .xtal = 28800000,
+static const struct rtl2832_platform_data rtl2832_r820t_platform_data = {
+ .clk = 28800000,
.tuner = TUNER_RTL2832_R820T,
};
@@ -678,12 +674,12 @@ static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
int ret;
u8 val;
- dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg);
+ dev_dbg(&d->intf->dev, "cmd=%d arg=%d\n", cmd, arg);
switch (cmd) {
case FC_FE_CALLBACK_VHF_ENABLE:
/* set output values */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
+ ret = rtl28xxu_rd_reg(d, SYS_GPIO_OUT_VAL, &val);
if (ret)
goto err;
@@ -693,7 +689,7 @@ static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
val |= 0x40; /* set GPIO6 high */
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, val);
+ ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_VAL, val);
if (ret)
goto err;
break;
@@ -703,7 +699,7 @@ static int rtl2832u_fc0012_tuner_callback(struct dvb_usb_device *d,
}
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
@@ -713,7 +709,7 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d,
int ret;
u8 val;
- dev_dbg(&d->udev->dev, "%s: cmd=%d arg=%d\n", __func__, cmd, arg);
+ dev_dbg(&d->intf->dev, "cmd=%d arg=%d\n", cmd, arg);
/*
* CEN always enabled by hardware wiring
@@ -728,7 +724,7 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d,
else
val = (0 << 4);
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x10);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x10);
if (ret)
goto err;
break;
@@ -738,7 +734,7 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d,
else
val = (0 << 1);
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x02);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, val, 0x02);
if (ret)
goto err;
break;
@@ -746,40 +742,46 @@ static int rtl2832u_tua9001_tuner_callback(struct dvb_usb_device *d,
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
-static int rtl2832u_tuner_callback(struct dvb_usb_device *d, int cmd, int arg)
-{
- struct rtl28xxu_priv *priv = d->priv;
-
- switch (priv->tuner) {
- case TUNER_RTL2832_FC0012:
- return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
- case TUNER_RTL2832_TUA9001:
- return rtl2832u_tua9001_tuner_callback(d, cmd, arg);
- default:
- break;
- }
-
- return 0;
-}
-
static int rtl2832u_frontend_callback(void *adapter_priv, int component,
int cmd, int arg)
{
- struct i2c_adapter *adap = adapter_priv;
- struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct i2c_adapter *adapter = adapter_priv;
+ struct device *parent = adapter->dev.parent;
+ struct i2c_adapter *parent_adapter;
+ struct dvb_usb_device *d;
+ struct rtl28xxu_dev *dev;
+
+ /*
+ * All tuners are connected to demod muxed I2C adapter. We have to
+ * resolve its parent adapter in order to get handle for this driver
+ * private data. That is a bit hackish solution, GPIO or direct driver
+ * callback would be better...
+ */
+ if (parent != NULL && parent->type == &i2c_adapter_type)
+ parent_adapter = to_i2c_adapter(parent);
+ else
+ return -EINVAL;
+
+ d = i2c_get_adapdata(parent_adapter);
+ dev = d->priv;
- dev_dbg(&d->udev->dev, "%s: component=%d cmd=%d arg=%d\n",
- __func__, component, cmd, arg);
+ dev_dbg(&d->intf->dev, "component=%d cmd=%d arg=%d\n",
+ component, cmd, arg);
switch (component) {
case DVB_FRONTEND_COMPONENT_TUNER:
- return rtl2832u_tuner_callback(d, cmd, arg);
+ switch (dev->tuner) {
+ case TUNER_RTL2832_FC0012:
+ return rtl2832u_fc0012_tuner_callback(d, cmd, arg);
+ case TUNER_RTL2832_TUA9001:
+ return rtl2832u_tua9001_tuner_callback(d, cmd, arg);
+ }
default:
- break;
+ return -EINVAL;
}
return 0;
@@ -787,57 +789,70 @@ static int rtl2832u_frontend_callback(void *adapter_priv, int component,
static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
{
- int ret;
struct dvb_usb_device *d = adap_to_d(adap);
- struct rtl28xxu_priv *priv = d_to_priv(d);
- const struct rtl2832_config *rtl2832_config;
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+ struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
+ struct i2c_board_info board_info;
+ struct i2c_client *client;
+ int ret;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ dev_dbg(&d->intf->dev, "\n");
- switch (priv->tuner) {
+ switch (dev->tuner) {
case TUNER_RTL2832_FC0012:
- rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+ *pdata = rtl2832_fc0012_platform_data;
break;
case TUNER_RTL2832_FC0013:
- rtl2832_config = &rtl28xxu_rtl2832_fc0013_config;
+ *pdata = rtl2832_fc0013_platform_data;
break;
case TUNER_RTL2832_FC2580:
/* FIXME: do not abuse fc0012 settings */
- rtl2832_config = &rtl28xxu_rtl2832_fc0012_config;
+ *pdata = rtl2832_fc0012_platform_data;
break;
case TUNER_RTL2832_TUA9001:
- rtl2832_config = &rtl28xxu_rtl2832_tua9001_config;
+ *pdata = rtl2832_tua9001_platform_data;
break;
case TUNER_RTL2832_E4000:
- rtl2832_config = &rtl28xxu_rtl2832_e4000_config;
+ *pdata = rtl2832_e4000_platform_data;
break;
case TUNER_RTL2832_R820T:
case TUNER_RTL2832_R828D:
- rtl2832_config = &rtl28xxu_rtl2832_r820t_config;
+ *pdata = rtl2832_r820t_platform_data;
break;
default:
- dev_err(&d->udev->dev, "%s: unknown tuner=%s\n",
- KBUILD_MODNAME, priv->tuner_name);
+ dev_err(&d->intf->dev, "unknown tuner %s\n", dev->tuner_name);
ret = -ENODEV;
goto err;
}
/* attach demodulator */
- adap->fe[0] = dvb_attach(rtl2832_attach, rtl2832_config, &d->i2c_adap);
- if (!adap->fe[0]) {
+ memset(&board_info, 0, sizeof(board_info));
+ strlcpy(board_info.type, "rtl2832", I2C_NAME_SIZE);
+ board_info.addr = 0x10;
+ board_info.platform_data = pdata;
+ request_module("%s", board_info.type);
+ client = i2c_new_device(&d->i2c_adap, &board_info);
+ if (client == NULL || client->dev.driver == NULL) {
ret = -ENODEV;
goto err;
}
- /* RTL2832 I2C repeater */
- priv->demod_i2c_adapter = rtl2832_get_i2c_adapter(adap->fe[0]);
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ adap->fe[0] = pdata->get_dvb_frontend(client);
+ dev->demod_i2c_adapter = pdata->get_i2c_adapter(client);
+
+ dev->i2c_client_demod = client;
/* set fe callback */
adap->fe[0]->callback = rtl2832u_frontend_callback;
- if (priv->slave_demod) {
+ if (dev->slave_demod) {
struct i2c_board_info info = {};
- struct i2c_client *client;
/*
* We continue on reduced mode, without DVB-T2/C, using master
@@ -846,28 +861,29 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
ret = 0;
/* attach slave demodulator */
- if (priv->slave_demod == SLAVE_DEMOD_MN88472) {
+ if (dev->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);
+ mn88472_config.xtal = 20500000;
info.addr = 0x18;
info.platform_data = &mn88472_config;
request_module(info.type);
- client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ client = i2c_new_device(&d->i2c_adap, &info);
if (client == NULL || client->dev.driver == NULL) {
- priv->slave_demod = SLAVE_DEMOD_NONE;
+ dev->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;
+ dev->slave_demod = SLAVE_DEMOD_NONE;
goto err_slave_demod_failed;
}
- priv->i2c_client_slave_demod = client;
+ dev->i2c_client_slave_demod = client;
} else {
struct mn88473_config mn88473_config = {};
@@ -877,29 +893,64 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
info.addr = 0x18;
info.platform_data = &mn88473_config;
request_module(info.type);
- client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ client = i2c_new_device(&d->i2c_adap, &info);
if (client == NULL || client->dev.driver == NULL) {
- priv->slave_demod = SLAVE_DEMOD_NONE;
+ dev->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;
+ dev->slave_demod = SLAVE_DEMOD_NONE;
goto err_slave_demod_failed;
}
- priv->i2c_client_slave_demod = client;
+ dev->i2c_client_slave_demod = client;
}
}
return 0;
err_slave_demod_failed:
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
+static int rtl28xxu_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct rtl28xxu_dev *dev = adap_to_priv(adap);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U)
+ return rtl2831u_frontend_attach(adap);
+ else
+ return rtl2832u_frontend_attach(adap);
+}
+
+static int rtl28xxu_frontend_detach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+ struct i2c_client *client;
+
+ dev_dbg(&d->intf->dev, "\n");
+
+ /* remove I2C slave demod */
+ client = dev->i2c_client_slave_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ /* remove I2C demod */
+ client = dev->i2c_client_demod;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ return 0;
+}
+
static struct qt1010_config rtl28xxu_qt1010_config = {
.i2c_address = 0x62, /* 0xc4 */
};
@@ -930,33 +981,30 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
- struct rtl28xxu_priv *priv = d_to_priv(d);
- struct i2c_adapter *rtl2830_tuner_i2c;
+ struct rtl28xxu_dev *dev = d_to_priv(d);
struct dvb_frontend *fe;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
-
- /* use rtl2830 driver I2C adapter, for more info see rtl2830 driver */
- rtl2830_tuner_i2c = rtl2830_get_tuner_i2c_adapter(adap->fe[0]);
+ dev_dbg(&d->intf->dev, "\n");
- switch (priv->tuner) {
+ switch (dev->tuner) {
case TUNER_RTL2830_QT1010:
fe = dvb_attach(qt1010_attach, adap->fe[0],
- rtl2830_tuner_i2c, &rtl28xxu_qt1010_config);
+ dev->demod_i2c_adapter,
+ &rtl28xxu_qt1010_config);
break;
case TUNER_RTL2830_MT2060:
fe = dvb_attach(mt2060_attach, adap->fe[0],
- rtl2830_tuner_i2c, &rtl28xxu_mt2060_config,
- 1220);
+ dev->demod_i2c_adapter,
+ &rtl28xxu_mt2060_config, 1220);
break;
case TUNER_RTL2830_MXL5005S:
fe = dvb_attach(mxl5005s_attach, adap->fe[0],
- rtl2830_tuner_i2c, &rtl28xxu_mxl5005s_config);
+ dev->demod_i2c_adapter,
+ &rtl28xxu_mxl5005s_config);
break;
default:
fe = NULL;
- dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
- priv->tuner);
+ dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner);
}
if (fe == NULL) {
@@ -966,7 +1014,7 @@ static int rtl2831u_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
@@ -1002,45 +1050,38 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
struct dvb_usb_device *d = adap_to_d(adap);
- struct rtl28xxu_priv *priv = d_to_priv(d);
+ struct rtl28xxu_dev *dev = d_to_priv(d);
struct dvb_frontend *fe = NULL;
struct i2c_board_info info;
struct i2c_client *client;
+ struct v4l2_subdev *subdev = NULL;
+ struct platform_device *pdev;
+ struct rtl2832_sdr_platform_data pdata;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ dev_dbg(&d->intf->dev, "\n");
memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&pdata, 0, sizeof(pdata));
- switch (priv->tuner) {
+ switch (dev->tuner) {
case TUNER_RTL2832_FC0012:
fe = dvb_attach(fc0012_attach, adap->fe[0],
- &d->i2c_adap, &rtl2832u_fc0012_config);
+ dev->demod_i2c_adapter, &rtl2832u_fc0012_config);
/* since fc0012 includs reading the signal strength delegate
* that to the tuner driver */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
-
- /* attach SDR */
- dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
- &rtl28xxu_rtl2832_fc0012_config, NULL);
break;
case TUNER_RTL2832_FC0013:
fe = dvb_attach(fc0013_attach, adap->fe[0],
- &d->i2c_adap, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
+ dev->demod_i2c_adapter, 0xc6>>1, 0, FC_XTAL_28_8_MHZ);
/* fc0013 also supports signal strength reading */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
-
- /* attach SDR */
- dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
- &rtl28xxu_rtl2832_fc0013_config, NULL);
break;
case TUNER_RTL2832_E4000: {
- struct v4l2_subdev *sd;
- struct i2c_adapter *i2c_adap_internal =
- rtl2832_get_private_i2c_adapter(adap->fe[0]);
struct e4000_config e4000_config = {
.fe = adap->fe[0],
.clock = 28800000,
@@ -1051,7 +1092,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
info.platform_data = &e4000_config;
request_module(info.type);
- client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ client = i2c_new_device(dev->demod_i2c_adapter, &info);
if (client == NULL || client->dev.driver == NULL)
break;
@@ -1060,157 +1101,183 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
break;
}
- priv->i2c_client_tuner = client;
- sd = i2c_get_clientdata(client);
- i2c_set_adapdata(i2c_adap_internal, d);
-
- /* attach SDR */
- dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0],
- i2c_adap_internal,
- &rtl28xxu_rtl2832_e4000_config, sd);
+ dev->i2c_client_tuner = client;
+ subdev = i2c_get_clientdata(client);
}
break;
case TUNER_RTL2832_FC2580:
- fe = dvb_attach(fc2580_attach, adap->fe[0], &d->i2c_adap,
+ fe = dvb_attach(fc2580_attach, adap->fe[0],
+ dev->demod_i2c_adapter,
&rtl2832u_fc2580_config);
break;
case TUNER_RTL2832_TUA9001:
/* enable GPIO1 and GPIO4 as output */
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x12);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x12);
if (ret)
goto err;
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x12, 0x12);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x12, 0x12);
if (ret)
goto err;
- fe = dvb_attach(tua9001_attach, adap->fe[0], &d->i2c_adap,
+ fe = dvb_attach(tua9001_attach, adap->fe[0],
+ dev->demod_i2c_adapter,
&rtl2832u_tua9001_config);
break;
case TUNER_RTL2832_R820T:
- fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+ fe = dvb_attach(r820t_attach, adap->fe[0],
+ dev->demod_i2c_adapter,
&rtl2832u_r820t_config);
/* Use tuner to get the signal strength */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->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;
case TUNER_RTL2832_R828D:
fe = dvb_attach(r820t_attach, adap->fe[0],
- priv->demod_i2c_adapter,
+ dev->demod_i2c_adapter,
&rtl2832u_r828d_config);
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,
+ dev->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);
+ dev_err(&d->intf->dev, "unknown tuner %d\n", dev->tuner);
}
-
- if (fe == NULL && priv->i2c_client_tuner == NULL) {
+ if (fe == NULL && dev->i2c_client_tuner == NULL) {
ret = -ENODEV;
goto err;
}
+ /* register SDR */
+ switch (dev->tuner) {
+ case TUNER_RTL2832_FC0012:
+ case TUNER_RTL2832_FC0013:
+ case TUNER_RTL2832_E4000:
+ case TUNER_RTL2832_R820T:
+ case TUNER_RTL2832_R828D:
+ pdata.clk = dev->rtl2832_platform_data.clk;
+ pdata.tuner = dev->tuner;
+ pdata.i2c_client = dev->i2c_client_demod;
+ pdata.bulk_read = dev->rtl2832_platform_data.bulk_read;
+ pdata.bulk_write = dev->rtl2832_platform_data.bulk_write;
+ pdata.update_bits = dev->rtl2832_platform_data.update_bits;
+ pdata.dvb_frontend = adap->fe[0];
+ pdata.dvb_usb_device = d;
+ pdata.v4l2_subdev = subdev;
+
+ request_module("%s", "rtl2832_sdr");
+ pdev = platform_device_register_data(&d->intf->dev,
+ "rtl2832_sdr",
+ PLATFORM_DEVID_AUTO,
+ &pdata, sizeof(pdata));
+ if (pdev == NULL || pdev->dev.driver == NULL)
+ break;
+ dev->platform_device_sdr = pdev;
+ break;
+ default:
+ dev_dbg(&d->intf->dev, "no SDR for tuner=%d\n", dev->tuner);
+ }
+
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
+static int rtl28xxu_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct rtl28xxu_dev *dev = adap_to_priv(adap);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U)
+ return rtl2831u_tuner_attach(adap);
+ else
+ return rtl2832u_tuner_attach(adap);
+}
+
+static int rtl28xxu_tuner_detach(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap_to_d(adap);
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+ struct i2c_client *client;
+ struct platform_device *pdev;
+
+ dev_dbg(&d->intf->dev, "\n");
+
+ /* remove platform SDR */
+ pdev = dev->platform_device_sdr;
+ if (pdev)
+ platform_device_unregister(pdev);
+
+ /* remove I2C tuner */
+ client = dev->i2c_client_tuner;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ return 0;
+}
+
static int rtl28xxu_init(struct dvb_usb_device *d)
{
int ret;
u8 val;
- dev_dbg(&d->udev->dev, "%s:\n", __func__);
+ dev_dbg(&d->intf->dev, "\n");
/* init USB endpoints */
- ret = rtl28xx_rd_reg(d, USB_SYSCTL_0, &val);
+ ret = rtl28xxu_rd_reg(d, USB_SYSCTL_0, &val);
if (ret)
goto err;
/* enable DMA and Full Packet Mode*/
val |= 0x09;
- ret = rtl28xx_wr_reg(d, USB_SYSCTL_0, val);
+ ret = rtl28xxu_wr_reg(d, USB_SYSCTL_0, val);
if (ret)
goto err;
/* set EPA maximum packet size to 0x0200 */
- ret = rtl28xx_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
+ ret = rtl28xxu_wr_regs(d, USB_EPA_MAXPKT, "\x00\x02\x00\x00", 4);
if (ret)
goto err;
/* change EPA FIFO length */
- ret = rtl28xx_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
+ ret = rtl28xxu_wr_regs(d, USB_EPA_FIFO_CFG, "\x14\x00\x00\x00", 4);
if (ret)
goto err;
return ret;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
-static void rtl28xxu_exit(struct dvb_usb_device *d)
-{
- struct rtl28xxu_priv *priv = d->priv;
- 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);
- }
-
- return;
-}
-
static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
u8 gpio, sys0, epa_ctl[2];
- dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+ dev_dbg(&d->intf->dev, "onoff=%d\n", onoff);
/* demod adc */
- ret = rtl28xx_rd_reg(d, SYS_SYS0, &sys0);
+ ret = rtl28xxu_rd_reg(d, SYS_SYS0, &sys0);
if (ret)
goto err;
/* tuner power, read GPIOs */
- ret = rtl28xx_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
+ ret = rtl28xxu_rd_reg(d, SYS_GPIO_OUT_VAL, &gpio);
if (ret)
goto err;
- dev_dbg(&d->udev->dev, "%s: RD SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__,
- sys0, gpio);
+ dev_dbg(&d->intf->dev, "RD SYS0=%02x GPIO_OUT_VAL=%02x\n", sys0, gpio);
if (onoff) {
gpio |= 0x01; /* GPIO0 = 1 */
@@ -1229,21 +1296,20 @@ static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
epa_ctl[1] = 0x02; /* set reset */
}
- dev_dbg(&d->udev->dev, "%s: WR SYS0=%02x GPIO_OUT_VAL=%02x\n", __func__,
- sys0, gpio);
+ dev_dbg(&d->intf->dev, "WR SYS0=%02x GPIO_OUT_VAL=%02x\n", sys0, gpio);
/* demod adc */
- ret = rtl28xx_wr_reg(d, SYS_SYS0, sys0);
+ ret = rtl28xxu_wr_reg(d, SYS_SYS0, sys0);
if (ret)
goto err;
/* tuner power, write GPIOs */
- ret = rtl28xx_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
+ ret = rtl28xxu_wr_reg(d, SYS_GPIO_OUT_VAL, gpio);
if (ret)
goto err;
/* streaming EP: stall & reset */
- ret = rtl28xx_wr_regs(d, USB_EPA_CTL, epa_ctl, 2);
+ ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, epa_ctl, 2);
if (ret)
goto err;
@@ -1252,7 +1318,7 @@ static int rtl2831u_power_ctrl(struct dvb_usb_device *d, int onoff)
return ret;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
@@ -1260,31 +1326,31 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
{
int ret;
- dev_dbg(&d->udev->dev, "%s: onoff=%d\n", __func__, onoff);
+ dev_dbg(&d->intf->dev, "onoff=%d\n", onoff);
if (onoff) {
/* GPIO3=1, GPIO4=0 */
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x08, 0x18);
if (ret)
goto err;
/* suspend? */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL1, 0x00, 0x10);
if (ret)
goto err;
/* enable PLL */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x80, 0x80);
if (ret)
goto err;
/* disable reset */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x20, 0x20);
if (ret)
goto err;
/* streaming EP: clear stall & reset */
- ret = rtl28xx_wr_regs(d, USB_EPA_CTL, "\x00\x00", 2);
+ ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, "\x00\x00", 2);
if (ret)
goto err;
@@ -1293,35 +1359,49 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
goto err;
} else {
/* GPIO4=1 */
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x10, 0x10);
if (ret)
goto err;
/* disable PLL */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80);
+ ret = rtl28xxu_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80);
if (ret)
goto err;
/* streaming EP: set stall & reset */
- ret = rtl28xx_wr_regs(d, USB_EPA_CTL, "\x10\x02", 2);
+ ret = rtl28xxu_wr_regs(d, USB_EPA_CTL, "\x10\x02", 2);
if (ret)
goto err;
}
return ret;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
-static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff)
+static int rtl28xxu_power_ctrl(struct dvb_usb_device *d, int onoff)
+{
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U)
+ return rtl2831u_power_ctrl(d, onoff);
+ else
+ return rtl2832u_power_ctrl(d, onoff);
+}
+
+static int rtl28xxu_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);
+ struct rtl28xxu_dev *dev = fe_to_priv(fe);
+ struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
int ret;
u8 val;
- dev_dbg(&d->udev->dev, "%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+ dev_dbg(&d->intf->dev, "fe=%d onoff=%d\n", fe->id, onoff);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U)
+ return 0;
/* control internal demod ADC */
if (fe->id == 0 && onoff)
@@ -1329,20 +1409,20 @@ static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff)
else
val = 0x00; /* disable ADC */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48);
+ ret = rtl28xxu_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]);
+ ret = pdata->enable_slave_ts(dev->i2c_client_demod);
if (ret)
goto err;
}
return 0;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
@@ -1350,7 +1430,7 @@ err:
static int rtl2831u_rc_query(struct dvb_usb_device *d)
{
int ret, i;
- struct rtl28xxu_priv *priv = d->priv;
+ struct rtl28xxu_dev *dev = d->priv;
u8 buf[5];
u32 rc_code;
struct rtl28xxu_reg_val rc_nec_tab[] = {
@@ -1371,17 +1451,17 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
};
/* init remote controller */
- if (!priv->rc_active) {
+ if (!dev->rc_active) {
for (i = 0; i < ARRAY_SIZE(rc_nec_tab); i++) {
- ret = rtl28xx_wr_reg(d, rc_nec_tab[i].reg,
+ ret = rtl28xxu_wr_reg(d, rc_nec_tab[i].reg,
rc_nec_tab[i].val);
if (ret)
goto err;
}
- priv->rc_active = true;
+ dev->rc_active = true;
}
- ret = rtl2831_rd_regs(d, SYS_IRRC_RP, buf, 5);
+ ret = rtl28xxu_rd_regs(d, SYS_IRRC_RP, buf, 5);
if (ret)
goto err;
@@ -1403,19 +1483,19 @@ static int rtl2831u_rc_query(struct dvb_usb_device *d)
rc_keydown(d->rc_dev, RC_TYPE_NEC, rc_code, 0);
- ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
+ ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1);
if (ret)
goto err;
/* repeated intentionally to avoid extra keypress */
- ret = rtl28xx_wr_reg(d, SYS_IRRC_SR, 1);
+ ret = rtl28xxu_wr_reg(d, SYS_IRRC_SR, 1);
if (ret)
goto err;
}
return ret;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
@@ -1433,7 +1513,7 @@ static int rtl2831u_get_rc_config(struct dvb_usb_device *d,
static int rtl2832u_rc_query(struct dvb_usb_device *d)
{
int ret, i, len;
- struct rtl28xxu_priv *priv = d->priv;
+ struct rtl28xxu_dev *dev = d->priv;
struct ir_raw_event ev;
u8 buf[128];
static const struct rtl28xxu_reg_val_mask refresh_tab[] = {
@@ -1443,7 +1523,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
};
/* init remote controller */
- if (!priv->rc_active) {
+ if (!dev->rc_active) {
static const struct rtl28xxu_reg_val_mask init_tab[] = {
{SYS_DEMOD_CTL1, 0x00, 0x04},
{SYS_DEMOD_CTL1, 0x00, 0x08},
@@ -1464,36 +1544,36 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
};
for (i = 0; i < ARRAY_SIZE(init_tab); i++) {
- ret = rtl28xx_wr_reg_mask(d, init_tab[i].reg,
+ ret = rtl28xxu_wr_reg_mask(d, init_tab[i].reg,
init_tab[i].val, init_tab[i].mask);
if (ret)
goto err;
}
- priv->rc_active = true;
+ dev->rc_active = true;
}
- ret = rtl28xx_rd_reg(d, IR_RX_IF, &buf[0]);
+ ret = rtl28xxu_rd_reg(d, IR_RX_IF, &buf[0]);
if (ret)
goto err;
if (buf[0] != 0x83)
goto exit;
- ret = rtl28xx_rd_reg(d, IR_RX_BC, &buf[0]);
+ ret = rtl28xxu_rd_reg(d, IR_RX_BC, &buf[0]);
if (ret)
goto err;
len = buf[0];
/* read raw code from hw */
- ret = rtl2831_rd_regs(d, IR_RX_BUF, buf, len);
+ ret = rtl28xxu_rd_regs(d, IR_RX_BUF, buf, len);
if (ret)
goto err;
/* let hw receive new code */
for (i = 0; i < ARRAY_SIZE(refresh_tab); i++) {
- ret = rtl28xx_wr_reg_mask(d, refresh_tab[i].reg,
+ ret = rtl28xxu_wr_reg_mask(d, refresh_tab[i].reg,
refresh_tab[i].val, refresh_tab[i].mask);
if (ret)
goto err;
@@ -1514,7 +1594,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
exit:
return ret;
err:
- dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ dev_dbg(&d->intf->dev, "failed=%d\n", ret);
return ret;
}
@@ -1523,7 +1603,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
{
/* disable IR interrupts in order to avoid SDR sample loss */
if (rtl28xxu_disable_rc)
- return rtl28xx_wr_reg(d, IR_RX_IE, 0x00);
+ return rtl28xxu_wr_reg(d, IR_RX_IE, 0x00);
/* load empty to enable rc */
if (!rc->map_name)
@@ -1535,52 +1615,80 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
return 0;
}
+
+static int rtl28xxu_get_rc_config(struct dvb_usb_device *d,
+ struct dvb_usb_rc *rc)
+{
+ struct rtl28xxu_dev *dev = d_to_priv(d);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U)
+ return rtl2831u_get_rc_config(d, rc);
+ else
+ return rtl2832u_get_rc_config(d, rc);
+}
#else
-#define rtl2831u_get_rc_config NULL
-#define rtl2832u_get_rc_config NULL
+#define rtl28xxu_get_rc_config NULL
#endif
-static const struct dvb_usb_device_properties rtl2831u_props = {
- .driver_name = KBUILD_MODNAME,
- .owner = THIS_MODULE,
- .adapter_nr = adapter_nr,
- .size_of_priv = sizeof(struct rtl28xxu_priv),
+static int rtl28xxu_pid_filter_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct rtl28xxu_dev *dev = adap_to_priv(adap);
- .power_ctrl = rtl2831u_power_ctrl,
- .i2c_algo = &rtl28xxu_i2c_algo,
- .read_config = rtl2831u_read_config,
- .frontend_attach = rtl2831u_frontend_attach,
- .tuner_attach = rtl2831u_tuner_attach,
- .init = rtl28xxu_init,
- .get_rc_config = rtl2831u_get_rc_config,
+ if (dev->chip_id == CHIP_ID_RTL2831U) {
+ struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data;
- .num_adapters = 1,
- .adapter = {
- {
- .stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
- },
- },
-};
+ return pdata->pid_filter_ctrl(adap->fe[0], onoff);
+ } else {
+ struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
-static const struct dvb_usb_device_properties rtl2832u_props = {
+ return pdata->pid_filter_ctrl(adap->fe[0], onoff);
+ }
+}
+
+static int rtl28xxu_pid_filter(struct dvb_usb_adapter *adap, int index,
+ u16 pid, int onoff)
+{
+ struct rtl28xxu_dev *dev = adap_to_priv(adap);
+
+ if (dev->chip_id == CHIP_ID_RTL2831U) {
+ struct rtl2830_platform_data *pdata = &dev->rtl2830_platform_data;
+
+ return pdata->pid_filter(adap->fe[0], index, pid, onoff);
+ } else {
+ struct rtl2832_platform_data *pdata = &dev->rtl2832_platform_data;
+
+ return pdata->pid_filter(adap->fe[0], index, pid, onoff);
+ }
+}
+
+static const struct dvb_usb_device_properties rtl28xxu_props = {
.driver_name = KBUILD_MODNAME,
.owner = THIS_MODULE,
.adapter_nr = adapter_nr,
- .size_of_priv = sizeof(struct rtl28xxu_priv),
+ .size_of_priv = sizeof(struct rtl28xxu_dev),
- .power_ctrl = rtl2832u_power_ctrl,
- .frontend_ctrl = rtl2832u_frontend_ctrl,
+ .identify_state = rtl28xxu_identify_state,
+ .power_ctrl = rtl28xxu_power_ctrl,
+ .frontend_ctrl = rtl28xxu_frontend_ctrl,
.i2c_algo = &rtl28xxu_i2c_algo,
- .read_config = rtl2832u_read_config,
- .frontend_attach = rtl2832u_frontend_attach,
- .tuner_attach = rtl2832u_tuner_attach,
+ .read_config = rtl28xxu_read_config,
+ .frontend_attach = rtl28xxu_frontend_attach,
+ .frontend_detach = rtl28xxu_frontend_detach,
+ .tuner_attach = rtl28xxu_tuner_attach,
+ .tuner_detach = rtl28xxu_tuner_detach,
.init = rtl28xxu_init,
- .exit = rtl28xxu_exit,
- .get_rc_config = rtl2832u_get_rc_config,
+ .get_rc_config = rtl28xxu_get_rc_config,
.num_adapters = 1,
.adapter = {
{
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER |
+ DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+
+ .pid_filter_count = 32,
+ .pid_filter_ctrl = rtl28xxu_pid_filter_ctrl,
+ .pid_filter = rtl28xxu_pid_filter,
+
.stream = DVB_USB_STREAM_BULK(0x81, 6, 8 * 512),
},
},
@@ -1589,69 +1697,69 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
static const struct usb_device_id rtl28xxu_id_table[] = {
/* RTL2831U devices: */
{ DVB_USB_DEVICE(USB_VID_REALTEK, USB_PID_REALTEK_RTL2831U,
- &rtl2831u_props, "Realtek RTL2831U reference design", NULL) },
+ &rtl28xxu_props, "Realtek RTL2831U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT,
- &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+ &rtl28xxu_props, "Freecom USB2.0 DVB-T", NULL) },
{ DVB_USB_DEVICE(USB_VID_WIDEVIEW, USB_PID_FREECOM_DVBT_2,
- &rtl2831u_props, "Freecom USB2.0 DVB-T", NULL) },
+ &rtl28xxu_props, "Freecom USB2.0 DVB-T", NULL) },
/* RTL2832U devices: */
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2832,
- &rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
+ &rtl28xxu_props, "Realtek RTL2832U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_REALTEK, 0x2838,
- &rtl2832u_props, "Realtek RTL2832U reference design", NULL) },
+ &rtl28xxu_props, "Realtek RTL2832U reference design", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_BLACK_REV1,
- &rtl2832u_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) },
+ &rtl28xxu_props, "TerraTec Cinergy T Stick Black", RC_MAP_TERRATEC_SLIM) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_DELOCK_USB2_DVBT,
- &rtl2832u_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
+ &rtl28xxu_props, "G-Tek Electronics Group Lifeview LV5TDLX DVB-T", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK,
- &rtl2832u_props, "TerraTec NOXON DAB Stick", NULL) },
+ &rtl28xxu_props, "TerraTec NOXON DAB Stick", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV2,
- &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
+ &rtl28xxu_props, "TerraTec NOXON DAB Stick (rev 2)", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, USB_PID_NOXON_DAB_STICK_REV3,
- &rtl2832u_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) },
+ &rtl28xxu_props, "TerraTec NOXON DAB Stick (rev 3)", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_TREKSTOR_TERRES_2_0,
- &rtl2832u_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
+ &rtl28xxu_props, "Trekstor DVB-T Stick Terres 2.0", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1101,
- &rtl2832u_props, "Dexatek DK DVB-T Dongle", NULL) },
+ &rtl28xxu_props, "Dexatek DK DVB-T Dongle", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6680,
- &rtl2832u_props, "DigitalNow Quad DVB-T Receiver", NULL) },
+ &rtl28xxu_props, "DigitalNow Quad DVB-T Receiver", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_MINID,
- &rtl2832u_props, "Leadtek Winfast DTV Dongle Mini D", NULL) },
+ &rtl28xxu_props, "Leadtek Winfast DTV Dongle Mini D", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d3,
- &rtl2832u_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
+ &rtl28xxu_props, "TerraTec Cinergy T Stick RC (Rev. 3)", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1102,
- &rtl2832u_props, "Dexatek DK mini DVB-T Dongle", NULL) },
+ &rtl28xxu_props, "Dexatek DK mini DVB-T Dongle", NULL) },
{ DVB_USB_DEVICE(USB_VID_TERRATEC, 0x00d7,
- &rtl2832u_props, "TerraTec Cinergy T Stick+", NULL) },
+ &rtl28xxu_props, "TerraTec Cinergy T Stick+", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd3a8,
- &rtl2832u_props, "ASUS My Cinema-U3100Mini Plus V2", NULL) },
+ &rtl28xxu_props, "ASUS My Cinema-U3100Mini Plus V2", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd393,
- &rtl2832u_props, "GIGABYTE U7300", NULL) },
+ &rtl28xxu_props, "GIGABYTE U7300", NULL) },
{ DVB_USB_DEVICE(USB_VID_DEXATEK, 0x1104,
- &rtl2832u_props, "MSI DIGIVOX Micro HD", NULL) },
+ &rtl28xxu_props, "MSI DIGIVOX Micro HD", NULL) },
{ DVB_USB_DEVICE(USB_VID_COMPRO, 0x0620,
- &rtl2832u_props, "Compro VideoMate U620F", NULL) },
+ &rtl28xxu_props, "Compro VideoMate U620F", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd394,
- &rtl2832u_props, "MaxMedia HU394-T", NULL) },
+ &rtl28xxu_props, "MaxMedia HU394-T", NULL) },
{ DVB_USB_DEVICE(USB_VID_LEADTEK, 0x6a03,
- &rtl2832u_props, "Leadtek WinFast DTV Dongle mini", NULL) },
+ &rtl28xxu_props, "Leadtek WinFast DTV Dongle mini", NULL) },
{ DVB_USB_DEVICE(USB_VID_GTEK, USB_PID_CPYTO_REDI_PC50A,
- &rtl2832u_props, "Crypto ReDi PC 50 A", NULL) },
+ &rtl28xxu_props, "Crypto ReDi PC 50 A", NULL) },
{ DVB_USB_DEVICE(USB_VID_KYE, 0x707f,
- &rtl2832u_props, "Genius TVGo DVB-T03", NULL) },
+ &rtl28xxu_props, "Genius TVGo DVB-T03", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, 0xd395,
- &rtl2832u_props, "Peak DVB-T USB", NULL) },
+ &rtl28xxu_props, "Peak DVB-T USB", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV20_RTL2832U,
- &rtl2832u_props, "Sveon STV20", NULL) },
+ &rtl28xxu_props, "Sveon STV20", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV21,
- &rtl2832u_props, "Sveon STV21", NULL) },
+ &rtl28xxu_props, "Sveon STV21", NULL) },
{ DVB_USB_DEVICE(USB_VID_KWORLD_2, USB_PID_SVEON_STV27,
- &rtl2832u_props, "Sveon STV27", NULL) },
+ &rtl28xxu_props, "Sveon STV27", NULL) },
/* RTL2832P devices: */
{ DVB_USB_DEVICE(USB_VID_HANFTEK, 0x0131,
- &rtl2832u_props, "Astrometa DVB-T2", NULL) },
+ &rtl28xxu_props, "Astrometa DVB-T2", NULL) },
{ }
};
MODULE_DEVICE_TABLE(usb, rtl28xxu_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index 3e3ea9d64a38..1b5d7ffb685e 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -22,8 +22,26 @@
#ifndef RTL28XXU_H
#define RTL28XXU_H
+#include <linux/platform_device.h>
+
#include "dvb_usb.h"
+#include "rtl2830.h"
+#include "rtl2832.h"
+#include "rtl2832_sdr.h"
+#include "mn88472.h"
+#include "mn88473.h"
+
+#include "qt1010.h"
+#include "mt2060.h"
+#include "mxl5005s.h"
+#include "fc0012.h"
+#include "fc0013.h"
+#include "e4000.h"
+#include "fc2580.h"
+#include "tua9001.h"
+#include "r820t.h"
+
/*
* USB commands
* (usb_control_msg() index parameter)
@@ -50,19 +68,26 @@
#define CMD_I2C_DA_WR 0x0610
-struct rtl28xxu_priv {
+struct rtl28xxu_dev {
+ u8 buf[28];
u8 chip_id;
u8 tuner;
char *tuner_name;
u8 page; /* integrated demod active register page */
struct i2c_adapter *demod_i2c_adapter;
bool rc_active;
+ struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
struct i2c_client *i2c_client_slave_demod;
+ struct platform_device *platform_device_sdr;
#define SLAVE_DEMOD_NONE 0
#define SLAVE_DEMOD_MN88472 1
#define SLAVE_DEMOD_MN88473 2
unsigned int slave_demod:2;
+ union {
+ struct rtl2830_platform_data rtl2830_platform_data;
+ struct rtl2832_platform_data rtl2832_platform_data;
+ };
};
enum rtl28xxu_chip_id {
diff --git a/drivers/media/usb/dvb-usb/m920x.c b/drivers/media/usb/dvb-usb/m920x.c
index abf8ab2e02e5..eafc5c82467f 100644
--- a/drivers/media/usb/dvb-usb/m920x.c
+++ b/drivers/media/usb/dvb-usb/m920x.c
@@ -1269,8 +1269,3 @@ MODULE_AUTHOR("Aapo Tahkola <aet@rasterburn.org>");
MODULE_DESCRIPTION("DVB Driver for ULI M920x");
MODULE_VERSION("0.1");
MODULE_LICENSE("GPL");
-
-/*
- * Local variables:
- * c-basic-offset: 8
- */
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 44ae1e0661e6..49a5f9532bd8 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -820,7 +820,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev)
if (urb_size > ep_size * npackets)
npackets = DIV_ROUND_UP(urb_size, ep_size);
- em28xx_info("Number of URBs: %d, with %d packets and %d size",
+ em28xx_info("Number of URBs: %d, with %d packets and %d size\n",
num_urb, npackets, urb_size);
/* Estimate the bytes per period */
@@ -981,7 +981,7 @@ static int em28xx_audio_fini(struct em28xx *dev)
return 0;
}
- em28xx_info("Closing audio extension");
+ em28xx_info("Closing audio extension\n");
if (dev->adev.sndcard) {
snd_card_disconnect(dev->adev.sndcard);
@@ -1005,7 +1005,7 @@ static int em28xx_audio_suspend(struct em28xx *dev)
if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
return 0;
- em28xx_info("Suspending audio extension");
+ em28xx_info("Suspending audio extension\n");
em28xx_deinit_isoc_audio(dev);
atomic_set(&dev->adev.stream_started, 0);
return 0;
@@ -1019,7 +1019,7 @@ static int em28xx_audio_resume(struct em28xx *dev)
if (dev->usb_audio_type != EM28XX_USB_AUDIO_VENDOR)
return 0;
- em28xx_info("Resuming audio extension");
+ em28xx_info("Resuming audio extension\n");
/* Nothing to do other than schedule_work() ?? */
schedule_work(&dev->adev.wq_trigger);
return 0;
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 86461a708abe..37456079f490 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -1125,7 +1125,7 @@ int em28xx_suspend_extension(struct em28xx *dev)
{
const struct em28xx_ops *ops = NULL;
- em28xx_info("Suspending extensions");
+ em28xx_info("Suspending extensions\n");
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
if (ops->suspend)
@@ -1139,7 +1139,7 @@ int em28xx_resume_extension(struct em28xx *dev)
{
const struct em28xx_ops *ops = NULL;
- em28xx_info("Resuming extensions");
+ em28xx_info("Resuming extensions\n");
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(ops, &em28xx_extension_devlist, next) {
if (ops->resume)
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 9877b699c6bc..aee70d483264 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -1724,7 +1724,7 @@ static int em28xx_dvb_fini(struct em28xx *dev)
if (!dev->dvb)
return 0;
- em28xx_info("Closing DVB extension");
+ em28xx_info("Closing DVB extension\n");
dvb = dev->dvb;
client = dvb->i2c_client_tuner;
@@ -1775,17 +1775,17 @@ static int em28xx_dvb_suspend(struct em28xx *dev)
if (!dev->board.has_dvb)
return 0;
- em28xx_info("Suspending DVB extension");
+ em28xx_info("Suspending DVB extension\n");
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
if (dvb->fe[0]) {
ret = dvb_frontend_suspend(dvb->fe[0]);
- em28xx_info("fe0 suspend %d", ret);
+ em28xx_info("fe0 suspend %d\n", ret);
}
if (dvb->fe[1]) {
dvb_frontend_suspend(dvb->fe[1]);
- em28xx_info("fe1 suspend %d", ret);
+ em28xx_info("fe1 suspend %d\n", ret);
}
}
@@ -1802,18 +1802,18 @@ static int em28xx_dvb_resume(struct em28xx *dev)
if (!dev->board.has_dvb)
return 0;
- em28xx_info("Resuming DVB extension");
+ em28xx_info("Resuming DVB extension\n");
if (dev->dvb) {
struct em28xx_dvb *dvb = dev->dvb;
if (dvb->fe[0]) {
ret = dvb_frontend_resume(dvb->fe[0]);
- em28xx_info("fe0 resume %d", ret);
+ em28xx_info("fe0 resume %d\n", ret);
}
if (dvb->fe[1]) {
ret = dvb_frontend_resume(dvb->fe[1]);
- em28xx_info("fe1 resume %d", ret);
+ em28xx_info("fe1 resume %d\n", ret);
}
}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index d8dc03aadfbd..4007356d991d 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -654,8 +654,6 @@ next_button:
if (dev->num_button_polling_addresses) {
memset(dev->button_polling_last_values, 0,
EM28XX_NUM_BUTTON_ADDRESSES_MAX);
- INIT_DELAYED_WORK(&dev->buttons_query_work,
- em28xx_query_buttons);
schedule_delayed_work(&dev->buttons_query_work,
msecs_to_jiffies(dev->button_polling_interval));
}
@@ -689,6 +687,7 @@ static int em28xx_ir_init(struct em28xx *dev)
}
kref_get(&dev->ref);
+ INIT_DELAYED_WORK(&dev->buttons_query_work, em28xx_query_buttons);
if (dev->board.buttons)
em28xx_init_buttons(dev);
@@ -833,7 +832,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
return 0;
}
- em28xx_info("Closing input extension");
+ em28xx_info("Closing input extension\n");
em28xx_shutdown_buttons(dev);
@@ -862,7 +861,7 @@ static int em28xx_ir_suspend(struct em28xx *dev)
if (dev->is_audio_only)
return 0;
- em28xx_info("Suspending input extension");
+ em28xx_info("Suspending input extension\n");
if (ir)
cancel_delayed_work_sync(&ir->work);
cancel_delayed_work_sync(&dev->buttons_query_work);
@@ -879,7 +878,7 @@ static int em28xx_ir_resume(struct em28xx *dev)
if (dev->is_audio_only)
return 0;
- em28xx_info("Resuming input extension");
+ em28xx_info("Resuming input extension\n");
/* if suspend calls ir_raw_event_unregister(), the should call
ir_raw_event_register() */
if (ir)
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index cf7f58b76292..9ecf65629b3d 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1958,7 +1958,7 @@ static int em28xx_v4l2_fini(struct em28xx *dev)
if (v4l2 == NULL)
return 0;
- em28xx_info("Closing video extension");
+ em28xx_info("Closing video extension\n");
mutex_lock(&dev->lock);
@@ -2007,7 +2007,7 @@ static int em28xx_v4l2_suspend(struct em28xx *dev)
if (!dev->has_video)
return 0;
- em28xx_info("Suspending video extension");
+ em28xx_info("Suspending video extension\n");
em28xx_stop_urbs(dev);
return 0;
}
@@ -2020,7 +2020,7 @@ static int em28xx_v4l2_resume(struct em28xx *dev)
if (!dev->has_video)
return 0;
- em28xx_info("Resuming video extension");
+ em28xx_info("Resuming video extension\n");
/* what do we do here */
return 0;
}
@@ -2192,7 +2192,6 @@ static struct video_device
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2->v4l2_dev;
- vfd->debug = video_debug;
vfd->lock = &dev->lock;
if (dev->board.is_webcam)
vfd->tvnorms = 0;
diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig
index eed10d782535..60af3b167f3b 100644
--- a/drivers/media/usb/gspca/Kconfig
+++ b/drivers/media/usb/gspca/Kconfig
@@ -395,6 +395,16 @@ config USB_GSPCA_TOPRO
To compile this driver as a module, choose M here: the
module will be called gspca_topro.
+config USB_GSPCA_TOUPTEK
+ tristate "Touptek USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the ToupTek UCMOS
+ / AmScope MU series camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_touptek.
+
config USB_GSPCA_TV8532
tristate "TV8532 USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/usb/gspca/Makefile b/drivers/media/usb/gspca/Makefile
index f46975e4c82d..9f5ccecb9c8a 100644
--- a/drivers/media/usb/gspca/Makefile
+++ b/drivers/media/usb/gspca/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_USB_GSPCA_STK1135) += gspca_stk1135.o
obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o
obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
obj-$(CONFIG_USB_GSPCA_TOPRO) += gspca_topro.o
+obj-$(CONFIG_USB_GSPCA_TOUPTEK) += gspca_touptek.o
obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
obj-$(CONFIG_USB_GSPCA_VICAM) += gspca_vicam.o
@@ -86,6 +87,7 @@ gspca_stv0680-objs := stv0680.o
gspca_sunplus-objs := sunplus.o
gspca_t613-objs := t613.o
gspca_topro-objs := topro.o
+gspca_touptek-objs := touptek.o
gspca_tv8532-objs := tv8532.o
gspca_vc032x-objs := vc032x.o
gspca_vicam-objs := vicam.o
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index 43d65057a5fe..e54cee856a80 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1562,7 +1562,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
struct v4l2_streamparm *parm)
{
struct gspca_dev *gspca_dev = video_drvdata(filp);
- int n;
+ unsigned int n;
n = parm->parm.capture.readbuffers;
if (n == 0 || n >= GSPCA_MAX_FRAMES)
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index 90f0d637cd9d..a9c866d6d82d 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -12,6 +12,8 @@
* PS3 Eye camera enhanced by Richard Kaswy http://kaswy.free.fr
* PS3 Eye camera - brightness, contrast, awb, agc, aec controls
* added by Max Thrun <bear24rw@gmail.com>
+ * PS3 Eye camera - FPS range extended by Joseph Howse
+ * <josephhowse@nummist.com> http://nummist.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
@@ -116,7 +118,7 @@ static const struct v4l2_pix_format ov767x_mode[] = {
.colorspace = V4L2_COLORSPACE_JPEG},
};
-static const u8 qvga_rates[] = {125, 100, 75, 60, 50, 40, 30};
+static const u8 qvga_rates[] = {187, 150, 137, 125, 100, 75, 60, 50, 37, 30};
static const u8 vga_rates[] = {60, 50, 40, 30, 15};
static const struct framerates ov772x_framerates[] = {
@@ -769,12 +771,16 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
{15, 0x03, 0x41, 0x04},
};
static const struct rate_s rate_1[] = { /* 320x240 */
+/* {205, 0x01, 0xc1, 0x02}, * 205 FPS: video is partly corrupt */
+ {187, 0x01, 0x81, 0x02}, /* 187 FPS or below: video is valid */
+ {150, 0x01, 0xc1, 0x04},
+ {137, 0x02, 0xc1, 0x02},
{125, 0x02, 0x81, 0x02},
{100, 0x02, 0xc1, 0x04},
{75, 0x03, 0xc1, 0x04},
{60, 0x04, 0xc1, 0x04},
{50, 0x02, 0x41, 0x04},
- {40, 0x03, 0x41, 0x04},
+ {37, 0x03, 0x41, 0x04},
{30, 0x04, 0x41, 0x04},
};
diff --git a/drivers/media/usb/gspca/stv06xx/stv06xx.c b/drivers/media/usb/gspca/stv06xx/stv06xx.c
index 49d209bbf9ee..6ac93d8db427 100644
--- a/drivers/media/usb/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/usb/gspca/stv06xx/stv06xx.c
@@ -505,13 +505,13 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
{
int ret = -EINVAL;
- if (len == 1 && data[0] == 0x80) {
+ if (len == 1 && (data[0] == 0x80 || data[0] == 0x10)) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
input_sync(gspca_dev->input_dev);
ret = 0;
}
- if (len == 1 && data[0] == 0x88) {
+ if (len == 1 && (data[0] == 0x88 || data[0] == 0x11)) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
input_sync(gspca_dev->input_dev);
ret = 0;
diff --git a/drivers/media/usb/gspca/touptek.c b/drivers/media/usb/gspca/touptek.c
new file mode 100644
index 000000000000..7bac6bc96063
--- /dev/null
+++ b/drivers/media/usb/gspca/touptek.c
@@ -0,0 +1,731 @@
+/*
+ * ToupTek UCMOS / AmScope MU series camera driver
+ * TODO: contrast with ScopeTek / AmScope MDC cameras
+ *
+ * Copyright (C) 2012-2014 John McMaster <JohnDMcMaster@gmail.com>
+ *
+ * Special thanks to Bushing for helping with the decrypt algorithm and
+ * Sean O'Sullivan / the Rensselaer Center for Open Source
+ * Software (RCOS) for helping me learn kernel development
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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 "gspca.h"
+
+#define MODULE_NAME "touptek"
+
+MODULE_AUTHOR("John McMaster");
+MODULE_DESCRIPTION("ToupTek UCMOS / Amscope MU microscope camera driver");
+MODULE_LICENSE("GPL");
+
+/*
+ * Exposure reg is linear with exposure time
+ * Exposure (sec), E (reg)
+ * 0.000400, 0x0002
+ * 0.001000, 0x0005
+ * 0.005000, 0x0019
+ * 0.020000, 0x0064
+ * 0.080000, 0x0190
+ * 0.400000, 0x07D0
+ * 1.000000, 0x1388
+ * 2.000000, 0x2710
+ *
+ * Three gain stages
+ * 0x1000: master channel enable bit
+ * 0x007F: low gain bits
+ * 0x0080: medium gain bit
+ * 0x0100: high gain bit
+ * gain = enable * (1 + regH) * (1 + regM) * z * regL
+ *
+ * Gain implementation
+ * Want to do something similar to mt9v011.c's set_balance
+ *
+ * Gain does not vary with resolution (checked 640x480 vs 1600x1200)
+ *
+ * Constant derivation:
+ *
+ * Raw data:
+ * Gain, GTOP, B, R, GBOT
+ * 1.00, 0x105C, 0x1068, 0x10C8, 0x105C
+ * 1.20, 0x106E, 0x107E, 0x10D6, 0x106E
+ * 1.40, 0x10C0, 0x10CA, 0x10E5, 0x10C0
+ * 1.60, 0x10C9, 0x10D4, 0x10F3, 0x10C9
+ * 1.80, 0x10D2, 0x10DE, 0x11C1, 0x10D2
+ * 2.00, 0x10DC, 0x10E9, 0x11C8, 0x10DC
+ * 2.20, 0x10E5, 0x10F3, 0x11CF, 0x10E5
+ * 2.40, 0x10EE, 0x10FE, 0x11D7, 0x10EE
+ * 2.60, 0x10F7, 0x11C4, 0x11DE, 0x10F7
+ * 2.80, 0x11C0, 0x11CA, 0x11E5, 0x11C0
+ * 3.00, 0x11C5, 0x11CF, 0x11ED, 0x11C5
+ *
+ * zR = 0.0069605943152454778
+ * about 3/431 = 0.0069605568445475635
+ * zB = 0.0095695970695970703
+ * about 6/627 = 0.0095693779904306216
+ * zG = 0.010889328063241107
+ * about 6/551 = 0.010889292196007259
+ * about 10 bits for constant + 7 bits for value => at least 17 bit
+ * intermediate with 32 bit ints should be fine for overflow etc
+ * Essentially gains are in range 0-0x001FF
+ *
+ * However, V4L expects a main gain channel + R and B balance
+ * To keep things simple for now saturate the values of balance is too high/low
+ * This isn't really ideal but easy way to fit the Linux model
+ *
+ * Converted using gain model turns out to be quite linear:
+ * Gain, GTOP, B, R, GBOT
+ * 1.00, 92, 104, 144, 92
+ * 1.20, 110, 126, 172, 110
+ * 1.40, 128, 148, 202, 128
+ * 1.60, 146, 168, 230, 146
+ * 1.80, 164, 188, 260, 164
+ * 2.00, 184, 210, 288, 184
+ * 2.20, 202, 230, 316, 202
+ * 2.40, 220, 252, 348, 220
+ * 2.60, 238, 272, 376, 238
+ * 2.80, 256, 296, 404, 256
+ * 3.00, 276, 316, 436, 276
+ *
+ * Maximum gain is 0x7FF * 2 * 2 => 0x1FFC (8188)
+ * or about 13 effective bits of gain
+ * The highest the commercial driver goes in my setup 436
+ * However, because could *maybe* damage circuits
+ * limit the gain until have a reason to go higher
+ * Solution: gain clipped and warning emitted
+ */
+#define GAIN_MAX 511
+
+/* Frame sync is a short read */
+#define BULK_SIZE 0x4000
+
+/* MT9E001 reg names to give a rough approximation */
+#define REG_COARSE_INTEGRATION_TIME_ 0x3012
+#define REG_GROUPED_PARAMETER_HOLD_ 0x3022
+#define REG_MODE_SELECT 0x0100
+#define REG_OP_SYS_CLK_DIV 0x030A
+#define REG_VT_SYS_CLK_DIV 0x0302
+#define REG_PRE_PLL_CLK_DIV 0x0304
+#define REG_VT_PIX_CLK_DIV 0x0300
+#define REG_OP_PIX_CLK_DIV 0x0308
+#define REG_PLL_MULTIPLIER 0x0306
+#define REG_COARSE_INTEGRATION_TIME_ 0x3012
+#define REG_FRAME_LENGTH_LINES 0x0340
+#define REG_FRAME_LENGTH_LINES_ 0x300A
+#define REG_GREEN1_GAIN 0x3056
+#define REG_GREEN2_GAIN 0x305C
+#define REG_GROUPED_PARAMETER_HOLD 0x0104
+#define REG_LINE_LENGTH_PCK_ 0x300C
+#define REG_MODE_SELECT 0x0100
+#define REG_PLL_MULTIPLIER 0x0306
+#define REG_READ_MODE 0x3040
+#define REG_BLUE_GAIN 0x3058
+#define REG_RED_GAIN 0x305A
+#define REG_RESET_REGISTER 0x301A
+#define REG_SCALE_M 0x0404
+#define REG_SCALING_MODE 0x0400
+#define REG_SOFTWARE_RESET 0x0103
+#define REG_X_ADDR_END 0x0348
+#define REG_X_ADDR_START 0x0344
+#define REG_X_ADDR_START 0x0344
+#define REG_X_OUTPUT_SIZE 0x034C
+#define REG_Y_ADDR_END 0x034A
+#define REG_Y_ADDR_START 0x0346
+#define REG_Y_OUTPUT_SIZE 0x034E
+
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ /* How many bytes this frame */
+ unsigned int this_f;
+
+ /*
+ Device has separate gains for each Bayer quadrant
+ V4L supports master gain which is referenced to G1/G2 and supplies
+ individual balance controls for R/B
+ */
+ struct v4l2_ctrl *blue;
+ struct v4l2_ctrl *red;
+};
+
+/* Used to simplify reg write error handling */
+struct cmd {
+ u16 value;
+ u16 index;
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+ {800, 600,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .bytesperline = 800,
+ .sizeimage = 800 * 600,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {1600, 1200,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .bytesperline = 1600,
+ .sizeimage = 1600 * 1200,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {3264, 2448,
+ V4L2_PIX_FMT_SGRBG8,
+ V4L2_FIELD_NONE,
+ .bytesperline = 3264,
+ .sizeimage = 3264 * 2448,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+/*
+ * As theres no known frame sync, the only way to keep synced is to try hard
+ * to never miss any packets
+ */
+#if MAX_NURBS < 4
+#error "Not enough URBs in the gspca table"
+#endif
+
+static int val_reply(struct gspca_dev *gspca_dev, const char *reply, int rc)
+{
+ if (rc < 0) {
+ PERR("reply has error %d", rc);
+ return -EIO;
+ }
+ if (rc != 1) {
+ PERR("Bad reply size %d", rc);
+ return -EIO;
+ }
+ if (reply[0] != 0x08) {
+ PERR("Bad reply 0x%02X", reply[0]);
+ return -EIO;
+ }
+ return 0;
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ char buff[1];
+ int rc;
+
+ PDEBUG(D_USBO,
+ "reg_w bReq=0x0B, bReqT=0xC0, wVal=0x%04X, wInd=0x%04X\n",
+ value, index);
+ rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0x0B, 0xC0, value, index, buff, 1, 500);
+ PDEBUG(D_USBO, "rc=%d, ret={0x%02X}", rc, buff[0]);
+ if (rc < 0) {
+ PERR("Failed reg_w(0x0B, 0xC0, 0x%04X, 0x%04X) w/ rc %d\n",
+ value, index, rc);
+ gspca_dev->usb_err = rc;
+ return;
+ }
+ if (val_reply(gspca_dev, buff, rc)) {
+ PERR("Bad reply to reg_w(0x0B, 0xC0, 0x%04X, 0x%04X\n",
+ value, index);
+ gspca_dev->usb_err = -EIO;
+ }
+}
+
+static void reg_w_buf(struct gspca_dev *gspca_dev,
+ const struct cmd *p, int l)
+{
+ do {
+ reg_w(gspca_dev, p->value, p->index);
+ p++;
+ } while (--l > 0);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev, s32 val)
+{
+ u16 value;
+ unsigned int w = gspca_dev->pixfmt.width;
+
+ if (w == 800)
+ value = val * 5;
+ else if (w == 1600)
+ value = val * 3;
+ else if (w == 3264)
+ value = val * 3 / 2;
+ else {
+ PERR("Invalid width %u\n", w);
+ gspca_dev->usb_err = -EINVAL;
+ return;
+ }
+ PDEBUG(D_STREAM, "exposure: 0x%04X ms\n", value);
+ /* Wonder if theres a good reason for sending it twice */
+ /* probably not but leave it in because...why not */
+ reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_);
+ reg_w(gspca_dev, value, REG_COARSE_INTEGRATION_TIME_);
+}
+
+static int gainify(int in)
+{
+ /*
+ * TODO: check if there are any issues with corner cases
+ * 0x000 (0):0x07F (127): regL
+ * 0x080 (128) - 0x0FF (255): regM, regL
+ * 0x100 (256) - max: regH, regM, regL
+ */
+ if (in <= 0x7F)
+ return 0x1000 | in;
+ else if (in <= 0xFF)
+ return 0x1080 | in / 2;
+ else
+ return 0x1180 | in / 4;
+}
+
+static void setggain(struct gspca_dev *gspca_dev, u16 global_gain)
+{
+ u16 normalized;
+
+ normalized = gainify(global_gain);
+ PDEBUG(D_STREAM, "gain G1/G2 (0x%04X): 0x%04X (src 0x%04X)\n",
+ REG_GREEN1_GAIN,
+ normalized, global_gain);
+
+ reg_w(gspca_dev, normalized, REG_GREEN1_GAIN);
+ reg_w(gspca_dev, normalized, REG_GREEN2_GAIN);
+}
+
+static void setbgain(struct gspca_dev *gspca_dev,
+ u16 gain, u16 global_gain)
+{
+ u16 normalized;
+
+ normalized = global_gain +
+ ((u32)global_gain) * gain / GAIN_MAX;
+ if (normalized > GAIN_MAX) {
+ PDEBUG(D_STREAM, "Truncating blue 0x%04X w/ value 0x%04X\n",
+ GAIN_MAX, normalized);
+ normalized = GAIN_MAX;
+ }
+ normalized = gainify(normalized);
+ PDEBUG(D_STREAM, "gain B (0x%04X): 0x%04X w/ source 0x%04X\n",
+ REG_BLUE_GAIN, normalized, gain);
+
+ reg_w(gspca_dev, normalized, REG_BLUE_GAIN);
+}
+
+static void setrgain(struct gspca_dev *gspca_dev,
+ u16 gain, u16 global_gain)
+{
+ u16 normalized;
+
+ normalized = global_gain +
+ ((u32)global_gain) * gain / GAIN_MAX;
+ if (normalized > GAIN_MAX) {
+ PDEBUG(D_STREAM, "Truncating gain 0x%04X w/ value 0x%04X\n",
+ GAIN_MAX, normalized);
+ normalized = GAIN_MAX;
+ }
+ normalized = gainify(normalized);
+ PDEBUG(D_STREAM, "gain R (0x%04X): 0x%04X w / source 0x%04X\n",
+ REG_RED_GAIN, normalized, gain);
+
+ reg_w(gspca_dev, normalized, REG_RED_GAIN);
+}
+
+static void configure_wh(struct gspca_dev *gspca_dev)
+{
+ unsigned int w = gspca_dev->pixfmt.width;
+
+ PDEBUG(D_STREAM, "configure_wh\n");
+
+ if (w == 800) {
+ static const struct cmd reg_init_res[] = {
+ {0x0060, REG_X_ADDR_START},
+ {0x0CD9, REG_X_ADDR_END},
+ {0x0036, REG_Y_ADDR_START},
+ {0x098F, REG_Y_ADDR_END},
+ {0x07C7, REG_READ_MODE},
+ };
+
+ reg_w_buf(gspca_dev,
+ reg_init_res, ARRAY_SIZE(reg_init_res));
+ } else if (w == 1600) {
+ static const struct cmd reg_init_res[] = {
+ {0x009C, REG_X_ADDR_START},
+ {0x0D19, REG_X_ADDR_END},
+ {0x0068, REG_Y_ADDR_START},
+ {0x09C5, REG_Y_ADDR_END},
+ {0x06C3, REG_READ_MODE},
+ };
+
+ reg_w_buf(gspca_dev,
+ reg_init_res, ARRAY_SIZE(reg_init_res));
+ } else if (w == 3264) {
+ static const struct cmd reg_init_res[] = {
+ {0x00E8, REG_X_ADDR_START},
+ {0x0DA7, REG_X_ADDR_END},
+ {0x009E, REG_Y_ADDR_START},
+ {0x0A2D, REG_Y_ADDR_END},
+ {0x0241, REG_READ_MODE},
+ };
+
+ reg_w_buf(gspca_dev,
+ reg_init_res, ARRAY_SIZE(reg_init_res));
+ } else {
+ PERR("bad width %u\n", w);
+ gspca_dev->usb_err = -EINVAL;
+ return;
+ }
+
+ reg_w(gspca_dev, 0x0000, REG_SCALING_MODE);
+ reg_w(gspca_dev, 0x0010, REG_SCALE_M);
+ reg_w(gspca_dev, w, REG_X_OUTPUT_SIZE);
+ reg_w(gspca_dev, gspca_dev->pixfmt.height, REG_Y_OUTPUT_SIZE);
+
+ if (w == 800) {
+ reg_w(gspca_dev, 0x0384, REG_FRAME_LENGTH_LINES_);
+ reg_w(gspca_dev, 0x0960, REG_LINE_LENGTH_PCK_);
+ } else if (w == 1600) {
+ reg_w(gspca_dev, 0x0640, REG_FRAME_LENGTH_LINES_);
+ reg_w(gspca_dev, 0x0FA0, REG_LINE_LENGTH_PCK_);
+ } else if (w == 3264) {
+ reg_w(gspca_dev, 0x0B4B, REG_FRAME_LENGTH_LINES_);
+ reg_w(gspca_dev, 0x1F40, REG_LINE_LENGTH_PCK_);
+ } else {
+ PERR("bad width %u\n", w);
+ gspca_dev->usb_err = -EINVAL;
+ return;
+ }
+}
+
+/* Packets that were encrypted, no idea if the grouping is significant */
+static void configure_encrypted(struct gspca_dev *gspca_dev)
+{
+ static const struct cmd reg_init_begin[] = {
+ {0x0100, REG_SOFTWARE_RESET},
+ {0x0000, REG_MODE_SELECT},
+ {0x0100, REG_GROUPED_PARAMETER_HOLD},
+ {0x0004, REG_VT_PIX_CLK_DIV},
+ {0x0001, REG_VT_SYS_CLK_DIV},
+ {0x0008, REG_OP_PIX_CLK_DIV},
+ {0x0001, REG_OP_SYS_CLK_DIV},
+ {0x0004, REG_PRE_PLL_CLK_DIV},
+ {0x0040, REG_PLL_MULTIPLIER},
+ {0x0000, REG_GROUPED_PARAMETER_HOLD},
+ {0x0100, REG_GROUPED_PARAMETER_HOLD},
+ };
+ static const struct cmd reg_init_end[] = {
+ {0x0000, REG_GROUPED_PARAMETER_HOLD},
+ {0x0301, 0x31AE},
+ {0x0805, 0x3064},
+ {0x0071, 0x3170},
+ {0x10DE, REG_RESET_REGISTER},
+ {0x0000, REG_MODE_SELECT},
+ {0x0010, REG_PLL_MULTIPLIER},
+ {0x0100, REG_MODE_SELECT},
+ };
+
+ PDEBUG(D_STREAM, "Encrypted begin, w = %u\n", gspca_dev->pixfmt.width);
+ reg_w_buf(gspca_dev, reg_init_begin, ARRAY_SIZE(reg_init_begin));
+ configure_wh(gspca_dev);
+ reg_w_buf(gspca_dev, reg_init_end, ARRAY_SIZE(reg_init_end));
+ reg_w(gspca_dev, 0x0100, REG_GROUPED_PARAMETER_HOLD);
+ reg_w(gspca_dev, 0x0000, REG_GROUPED_PARAMETER_HOLD);
+
+ PDEBUG(D_STREAM, "Encrypted end\n");
+}
+
+static int configure(struct gspca_dev *gspca_dev)
+{
+ int rc;
+ uint8_t buff[4];
+
+ PDEBUG(D_STREAM, "configure()\n");
+
+ /*
+ * First driver sets a sort of encryption key
+ * A number of futur requests of this type have wValue and wIndex
+ * encrypted as follows:
+ * -Compute key = this wValue rotate left by 4 bits
+ * (decrypt.py rotates right because we are decrypting)
+ * -Later packets encrypt packets by XOR'ing with key
+ * XOR encrypt/decrypt is symmetrical
+ * wValue, and wIndex are encrypted
+ * bRequest is not and bRequestType is always 0xC0
+ * This allows resyncing if key is unknown?
+ * By setting 0 we XOR with 0 and the shifting and XOR drops out
+ */
+ rc = usb_control_msg(gspca_dev->dev, usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0x16, 0xC0, 0x0000, 0x0000, buff, 2, 500);
+ if (val_reply(gspca_dev, buff, rc)) {
+ PERR("failed key req");
+ return -EIO;
+ }
+
+ /*
+ * Next does some sort of 2 packet challenge / response
+ * evidence suggests its an Atmel I2C crypto part but nobody cares to
+ * look
+ * (to make sure its not cloned hardware?)
+ * Ignore: I want to work with their hardware, not clone it
+ * 16 bytes out challenge, requestType: 0x40
+ * 16 bytes in response, requestType: 0xC0
+ */
+
+ rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500);
+ if (rc < 0) {
+ PERR("failed to replay packet 176 w/ rc %d\n", rc);
+ return rc;
+ }
+
+ rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x01, 0x40, 0x0000, 0x000F, NULL, 0, 500);
+ if (rc < 0) {
+ PERR("failed to replay packet 178 w/ rc %d\n", rc);
+ return rc;
+ }
+
+ rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x01, 0x40, 0x0001, 0x000F, NULL, 0, 500);
+ if (rc < 0) {
+ PERR("failed to replay packet 180 w/ rc %d\n", rc);
+ return rc;
+ }
+
+ /*
+ * Serial number? Doesn't seem to be required
+ * cam1: \xE6\x0D\x00\x00, cam2: \x70\x19\x00\x00
+ * rc = usb_control_msg(gspca_dev->dev,
+ * usb_rcvctrlpipe(gspca_dev->dev, 0),
+ * 0x20, 0xC0, 0x0000, 0x0000, buff, 4, 500);
+ */
+
+ /* Large (EEPROM?) read, skip it since no idea what to do with it */
+ gspca_dev->usb_err = 0;
+ configure_encrypted(gspca_dev);
+ if (gspca_dev->usb_err)
+ return gspca_dev->usb_err;
+
+ /* Omitted this by accident, does not work without it */
+ rc = usb_control_msg(gspca_dev->dev, usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x01, 0x40, 0x0003, 0x000F, NULL, 0, 500);
+ if (rc < 0) {
+ PERR("failed to replay final packet w/ rc %d\n", rc);
+ return rc;
+ }
+
+ PDEBUG(D_STREAM, "Configure complete\n");
+ return 0;
+}
+
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+
+ /* Yes we want URBs and we want them now! */
+ gspca_dev->cam.no_urb_create = 0;
+ gspca_dev->cam.bulk_nurbs = 4;
+ /* Largest size the windows driver uses */
+ gspca_dev->cam.bulk_size = BULK_SIZE;
+ /* Def need to use bulk transfers */
+ gspca_dev->cam.bulk = 1;
+
+ return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int rc;
+
+ sd->this_f = 0;
+
+ rc = configure(gspca_dev);
+ if (rc < 0) {
+ PERR("Failed configure");
+ return rc;
+ }
+ /* First two frames have messed up gains
+ Drop them to avoid special cases in user apps? */
+ return 0;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (len != BULK_SIZE) {
+ /* can we finish a frame? */
+ if (sd->this_f + len == gspca_dev->pixfmt.sizeimage) {
+ gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+ PDEBUG(D_FRAM, "finish frame sz %u/%u w/ len %u\n",
+ sd->this_f, gspca_dev->pixfmt.sizeimage, len);
+ /* lost some data, discard the frame */
+ } else {
+ gspca_frame_add(gspca_dev, DISCARD_PACKET, NULL, 0);
+ PDEBUG(D_FRAM, "abort frame sz %u/%u w/ len %u\n",
+ sd->this_f, gspca_dev->pixfmt.sizeimage, len);
+ }
+ sd->this_f = 0;
+ } else {
+ if (sd->this_f == 0)
+ gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
+ else
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+ sd->this_f += len;
+ }
+}
+
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ return 0;
+}
+
+static int sd_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gspca_dev *gspca_dev =
+ container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_err = 0;
+
+ if (!gspca_dev->streaming)
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ setexposure(gspca_dev, ctrl->val);
+ break;
+ case V4L2_CID_GAIN:
+ /* gspca_dev->gain automatically updated */
+ setggain(gspca_dev, gspca_dev->gain->val);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ sd->blue->val = ctrl->val;
+ setbgain(gspca_dev, sd->blue->val, gspca_dev->gain->val);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ sd->red->val = ctrl->val;
+ setrgain(gspca_dev, sd->red->val, gspca_dev->gain->val);
+ break;
+ }
+ return gspca_dev->usb_err;
+}
+
+static const struct v4l2_ctrl_ops sd_ctrl_ops = {
+ .s_ctrl = sd_s_ctrl,
+};
+
+static int sd_init_controls(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct v4l2_ctrl_handler *hdl = &gspca_dev->ctrl_handler;
+
+ gspca_dev->vdev.ctrl_handler = hdl;
+ v4l2_ctrl_handler_init(hdl, 4);
+
+ gspca_dev->exposure = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ /* Mostly limited by URB timeouts */
+ /* XXX: make dynamic based on frame rate? */
+ V4L2_CID_EXPOSURE, 0, 800, 1, 350);
+ gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_GAIN, 0, 511, 1, 128);
+ sd->blue = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_BLUE_BALANCE, 0, 1023, 1, 80);
+ sd->red = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
+ V4L2_CID_RED_BALANCE, 0, 1023, 1, 295);
+
+ if (hdl->error) {
+ PERR("Could not initialize controls\n");
+ return hdl->error;
+ }
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .config = sd_config,
+ .init = sd_init,
+ .init_controls = sd_init_controls,
+ .start = sd_start,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* Table of supported USB devices */
+static const struct usb_device_id device_table[] = {
+ /* Commented out devices should be related */
+ /* AS: AmScope, TT: ToupTek */
+ /* { USB_DEVICE(0x0547, 0x6035) }, TT UCMOS00350KPA */
+ /* { USB_DEVICE(0x0547, 0x6130) }, TT UCMOS01300KPA */
+ /* { USB_DEVICE(0x0547, 0x6200) }, TT UCMOS02000KPA */
+ /* { USB_DEVICE(0x0547, 0x6310) }, TT UCMOS03100KPA */
+ /* { USB_DEVICE(0x0547, 0x6510) }, TT UCMOS05100KPA */
+ /* { USB_DEVICE(0x0547, 0x6800) }, TT UCMOS08000KPA */
+ /* { USB_DEVICE(0x0547, 0x6801) }, TT UCMOS08000KPB */
+ { USB_DEVICE(0x0547, 0x6801) }, /* TT UCMOS08000KPB, AS MU800 */
+ /* { USB_DEVICE(0x0547, 0x6900) }, TT UCMOS09000KPA */
+ /* { USB_DEVICE(0x0547, 0x6901) }, TT UCMOS09000KPB */
+ /* { USB_DEVICE(0x0547, 0x6010) }, TT UCMOS10000KPA */
+ /* { USB_DEVICE(0x0547, 0x6014) }, TT UCMOS14000KPA */
+ /* { USB_DEVICE(0x0547, 0x6131) }, TT UCMOS01300KMA */
+ /* { USB_DEVICE(0x0547, 0x6511) }, TT UCMOS05100KMA */
+ /* { USB_DEVICE(0x0547, 0x8080) }, TT UHCCD00800KPA */
+ /* { USB_DEVICE(0x0547, 0x8140) }, TT UHCCD01400KPA */
+ /* { USB_DEVICE(0x0547, 0x8141) }, TT EXCCD01400KPA */
+ /* { USB_DEVICE(0x0547, 0x8200) }, TT UHCCD02000KPA */
+ /* { USB_DEVICE(0x0547, 0x8201) }, TT UHCCD02000KPB */
+ /* { USB_DEVICE(0x0547, 0x8310) }, TT UHCCD03100KPA */
+ /* { USB_DEVICE(0x0547, 0x8500) }, TT UHCCD05000KPA */
+ /* { USB_DEVICE(0x0547, 0x8510) }, TT UHCCD05100KPA */
+ /* { USB_DEVICE(0x0547, 0x8600) }, TT UHCCD06000KPA */
+ /* { USB_DEVICE(0x0547, 0x8800) }, TT UHCCD08000KPA */
+ /* { USB_DEVICE(0x0547, 0x8315) }, TT UHCCD03150KPA */
+ /* { USB_DEVICE(0x0547, 0x7800) }, TT UHCCD00800KMA */
+ /* { USB_DEVICE(0x0547, 0x7140) }, TT UHCCD01400KMA */
+ /* { USB_DEVICE(0x0547, 0x7141) }, TT UHCCD01400KMB */
+ /* { USB_DEVICE(0x0547, 0x7200) }, TT UHCCD02000KMA */
+ /* { USB_DEVICE(0x0547, 0x7315) }, TT UHCCD03150KMA */
+ { }
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+static int __init sd_mod_init(void)
+{
+ int ret;
+
+ ret = usb_register(&sd_driver);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/usb/gspca/vc032x.c b/drivers/media/usb/gspca/vc032x.c
index c00ac57de510..b4efb2fb36fa 100644
--- a/drivers/media/usb/gspca/vc032x.c
+++ b/drivers/media/usb/gspca/vc032x.c
@@ -68,12 +68,12 @@ enum sensors {
static const struct v4l2_pix_format vc0321_mode[] = {
{320, 240, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
- .bytesperline = 320,
+ .bytesperline = 320 * 2,
.sizeimage = 320 * 240 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
{640, 480, V4L2_PIX_FMT_YVYU, V4L2_FIELD_NONE,
- .bytesperline = 640,
+ .bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
@@ -97,17 +97,17 @@ static const struct v4l2_pix_format vc0323_mode[] = {
};
static const struct v4l2_pix_format bi_mode[] = {
{320, 240, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
- .bytesperline = 320,
+ .bytesperline = 320 * 2,
.sizeimage = 320 * 240 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 2},
{640, 480, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
- .bytesperline = 640,
+ .bytesperline = 640 * 2,
.sizeimage = 640 * 480 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1},
{1280, 1024, V4L2_PIX_FMT_YUYV, V4L2_FIELD_NONE,
- .bytesperline = 1280,
+ .bytesperline = 1280 * 2,
.sizeimage = 1280 * 1024 * 2,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0},
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.c b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
index cc06d5e4adcc..45276c628482 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-audio.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.c
@@ -84,13 +84,3 @@ void pvr2_msp3400_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
}
}
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-audio.h b/drivers/media/usb/pvrusb2/pvrusb2-audio.h
index e3e63d750891..27cefb5cb170 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-audio.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-audio.h
@@ -25,13 +25,3 @@
#include "pvrusb2-hdw-internal.h"
void pvr2_msp3400_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
#endif /* __PVRUSB2_AUDIO_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index c8761c71c9d2..924fc4c6019a 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -418,14 +418,3 @@ struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
return cp;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.h b/drivers/media/usb/pvrusb2/pvrusb2-context.h
index d657e53bbfa3..1c1d442d9ea3 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.h
@@ -83,12 +83,3 @@ int pvr2_context_global_init(void);
void pvr2_context_global_done(void);
#endif /* __PVRUSB2_CONTEXT_H */
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
index 88320900dbd4..f82f0f0f2c04 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.c
@@ -82,14 +82,3 @@ void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sd->ops->audio->s_routing(sd, input, 0, 0);
}
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
index 53ba548b72a7..86c17bee56f9 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cs53l32a.h
@@ -36,13 +36,3 @@
void pvr2_cs53l32a_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
#endif /* __PVRUSB2_AUDIO_CS53L32A_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
index 7d5a7139a45a..958db170a048 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.c
@@ -596,14 +596,3 @@ int pvr2_ctrl_value_to_sym(struct pvr2_ctrl *cptr,
} while(0); LOCK_GIVE(cptr->hdw->big_lock);
return ret;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
index 794ff90121c7..c175571868a3 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ctrl.h
@@ -110,13 +110,3 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *,
unsigned int *len);
#endif /* __PVRUSB2_CTRL_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
index c514d0b9ffdc..1a81aa70509b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -152,15 +152,3 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sd->ops->audio->s_routing(sd, (u32)aud_input, 0, 0);
}
}
-
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
index e35c2322a08c..2eed7b7ee25e 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-cx2584x-v4l.h
@@ -40,13 +40,3 @@ void pvr2_cx25840_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
#endif /* __PVRUSB2_CX2584X_V4L_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debug.h b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
index be79249f8628..4ef2ebcd97a5 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debug.h
@@ -57,13 +57,3 @@ extern int pvrusb2_debug;
#endif /* __PVRUSB2_HDW_INTERNAL_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
index 4279ebb811a1..e4022bcb155b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
@@ -322,14 +322,3 @@ int pvr2_debugifc_docmd(struct pvr2_hdw *hdw,const char *buf,
return 0;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
index 2f8d46761cd0..a8dfc55f136f 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.h
@@ -40,13 +40,3 @@ int pvr2_debugifc_docmd(struct pvr2_hdw *,
const char *buf_ptr,unsigned int buf_size);
#endif /* __PVRUSB2_DEBUGIFC_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
index adc501d3c287..06c4c3dabcde 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.c
@@ -564,13 +564,3 @@ MODULE_FIRMWARE(PVR2_FIRMWARE_29xxx);
MODULE_FIRMWARE(PVR2_FIRMWARE_24xxx);
MODULE_FIRMWARE(PVR2_FIRMWARE_73xxx);
MODULE_FIRMWARE(PVR2_FIRMWARE_75xxx);
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
index 273c8d4b3853..5aeefb6a991f 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-devattr.h
@@ -187,13 +187,3 @@ struct pvr2_device_desc {
extern struct usb_device_id pvr2_device_table[];
#endif /* __PVRUSB2_HDW_INTERNAL_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
index 9515f3a68f8f..e1907cd0c3b7 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.c
@@ -152,13 +152,3 @@ int pvr2_eeprom_analyze(struct pvr2_hdw *hdw)
return 0;
}
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
index cca3216f94cc..f1e33c807f46 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-eeprom.h
@@ -27,13 +27,3 @@ struct pvr2_hdw;
int pvr2_eeprom_analyze(struct pvr2_hdw *);
#endif /* __PVRUSB2_EEPROM_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
index f7702aeeda3f..593b3e9b6bfd 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.c
@@ -538,14 +538,3 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
return status;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
index 232fefbcd1ac..a2bfb48f1ecd 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-encoder.h
@@ -30,13 +30,3 @@ int pvr2_encoder_start(struct pvr2_hdw *);
int pvr2_encoder_stop(struct pvr2_hdw *);
#endif /* __PVRUSB2_ENCODER_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
index 614755ea2ea3..06a15a68bcfd 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-fx2-cmd.h
@@ -60,13 +60,3 @@
#define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3u
#endif /* _PVRUSB2_FX2_CMD_H_ */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
index 036952f2a3cb..1f9c02801cee 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw-internal.h
@@ -394,13 +394,3 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *);
void pvr2_hdw_status_poll(struct pvr2_hdw *);
#endif /* __PVRUSB2_HDW_INTERNAL_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 2fd9b5e0e2a9..930593d7028d 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2425,22 +2425,18 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
}
if (!hdw) goto fail;
- init_timer(&hdw->quiescent_timer);
- hdw->quiescent_timer.data = (unsigned long)hdw;
- hdw->quiescent_timer.function = pvr2_hdw_quiescent_timeout;
+ setup_timer(&hdw->quiescent_timer, pvr2_hdw_quiescent_timeout,
+ (unsigned long)hdw);
- init_timer(&hdw->decoder_stabilization_timer);
- hdw->decoder_stabilization_timer.data = (unsigned long)hdw;
- hdw->decoder_stabilization_timer.function =
- pvr2_hdw_decoder_stabilization_timeout;
+ setup_timer(&hdw->decoder_stabilization_timer,
+ pvr2_hdw_decoder_stabilization_timeout,
+ (unsigned long)hdw);
- init_timer(&hdw->encoder_wait_timer);
- hdw->encoder_wait_timer.data = (unsigned long)hdw;
- hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
+ setup_timer(&hdw->encoder_wait_timer, pvr2_hdw_encoder_wait_timeout,
+ (unsigned long)hdw);
- init_timer(&hdw->encoder_run_timer);
- hdw->encoder_run_timer.data = (unsigned long)hdw;
- hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout;
+ setup_timer(&hdw->encoder_run_timer, pvr2_hdw_encoder_run_timeout,
+ (unsigned long)hdw);
hdw->master_state = PVR2_STATE_DEAD;
@@ -3680,10 +3676,8 @@ static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
hdw->ctl_timeout_flag = 0;
hdw->ctl_write_pend_flag = 0;
hdw->ctl_read_pend_flag = 0;
- init_timer(&timer);
+ setup_timer(&timer, pvr2_ctl_timeout, (unsigned long)hdw);
timer.expires = jiffies + timeout;
- timer.data = (unsigned long)hdw;
- timer.function = pvr2_ctl_timeout;
if (write_len) {
hdw->cmd_debug_state = 2;
@@ -4035,11 +4029,6 @@ int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
}
-int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
-{
- return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF);
-}
-
int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
{
@@ -4301,9 +4290,8 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
the encoder. */
if (!hdw->state_encoder_waitok) {
hdw->encoder_wait_timer.expires =
- jiffies +
- (HZ * TIME_MSEC_ENCODER_WAIT
- / 1000);
+ jiffies + msecs_to_jiffies(
+ TIME_MSEC_ENCODER_WAIT);
add_timer(&hdw->encoder_wait_timer);
}
}
@@ -4426,8 +4414,8 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw)
if (pvr2_encoder_start(hdw) < 0) return !0;
hdw->state_encoder_run = !0;
if (!hdw->state_encoder_runok) {
- hdw->encoder_run_timer.expires =
- jiffies + (HZ * TIME_MSEC_ENCODER_OK / 1000);
+ hdw->encoder_run_timer.expires = jiffies +
+ msecs_to_jiffies(TIME_MSEC_ENCODER_OK);
add_timer(&hdw->encoder_run_timer);
}
}
@@ -4518,9 +4506,8 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
but before we did the pending check. */
if (!hdw->state_decoder_quiescent) {
hdw->quiescent_timer.expires =
- jiffies +
- (HZ * TIME_MSEC_DECODER_WAIT
- / 1000);
+ jiffies + msecs_to_jiffies(
+ TIME_MSEC_DECODER_WAIT);
add_timer(&hdw->quiescent_timer);
}
}
@@ -4544,9 +4531,8 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
hdw->state_decoder_run = !0;
if (hdw->decoder_client_id == PVR2_CLIENT_ID_SAA7115) {
hdw->decoder_stabilization_timer.expires =
- jiffies +
- (HZ * TIME_MSEC_DECODER_STABILIZATION_WAIT /
- 1000);
+ jiffies + msecs_to_jiffies(
+ TIME_MSEC_DECODER_STABILIZATION_WAIT);
add_timer(&hdw->decoder_stabilization_timer);
} else {
hdw->state_decoder_ready = !0;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
index 41847076f51a..a82a00dd7329 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.h
@@ -271,9 +271,6 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *);
/* Execute simple reset command */
int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
-/* suspend */
-int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *);
-
/* Order decoder to reset */
int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
@@ -343,13 +340,3 @@ void pvr2_hdw_trigger_module_log(struct pvr2_hdw *hdw);
int pvr2_upload_firmware2(struct pvr2_hdw *hdw);
#endif /* __PVRUSB2_HDW_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
index b5e929f1bf82..4baa9d632a4e 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.c
@@ -686,13 +686,3 @@ void pvr2_i2c_core_done(struct pvr2_hdw *hdw)
hdw->i2c_linked = 0;
}
}
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
index 6a75769200bd..a10a3e8e9345 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-i2c-core.h
@@ -27,14 +27,3 @@ void pvr2_i2c_core_done(struct pvr2_hdw *);
#endif /* __PVRUSB2_I2C_ADAPTER_H */
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index 1e354747de3f..0c08f22bdfce 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
@@ -682,14 +682,3 @@ int pvr2_buffer_get_id(struct pvr2_buffer *bp)
{
return bp->id;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.h b/drivers/media/usb/pvrusb2/pvrusb2-io.h
index afb7e87c0394..0c47c6a95ab2 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.h
@@ -90,13 +90,3 @@ int pvr2_buffer_get_id(struct pvr2_buffer *);
int pvr2_buffer_queue(struct pvr2_buffer *);
#endif /* __PVRUSB2_IO_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
index bba6115c9ae8..cd995b54732e 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.c
@@ -499,14 +499,3 @@ int pvr2_ioread_read(struct pvr2_ioread *cp,void __user *buf,unsigned int cnt)
cp,req_cnt,ret);
return ret;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
index 100e0780e1aa..0b1f0fbc3438 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-ioread.h
@@ -36,13 +36,3 @@ int pvr2_ioread_read(struct pvr2_ioread *,void __user *buf,unsigned int cnt);
int pvr2_ioread_avail(struct pvr2_ioread *);
#endif /* __PVRUSB2_IOREAD_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-main.c b/drivers/media/usb/pvrusb2/pvrusb2-main.c
index c1d9bb61cd77..86be902a0049 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-main.c
@@ -169,14 +169,3 @@ MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");
MODULE_VERSION("0.9.1");
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.c b/drivers/media/usb/pvrusb2/pvrusb2-std.c
index 453627b07833..9a596a3a4c27 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.c
@@ -398,14 +398,3 @@ v4l2_std_id pvr2_std_get_usable(void)
{
return CSTD_ALL;
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-std.h b/drivers/media/usb/pvrusb2/pvrusb2-std.h
index a35c53d0b320..ed4ec0474429 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-std.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-std.h
@@ -47,13 +47,3 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
v4l2_std_id pvr2_std_get_usable(void);
#endif /* __PVRUSB2_STD_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
index 6ef1335b2858..06fe63ced58c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.c
@@ -848,14 +848,3 @@ static ssize_t debugcmd_store(struct device *class_dev,
return count;
}
#endif /* CONFIG_VIDEO_PVRUSB2_DEBUGIFC */
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
index 6d875bfe7991..6f0579e1e07b 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-sysfs.h
@@ -34,13 +34,3 @@ struct pvr2_sysfs *pvr2_sysfs_create(struct pvr2_context *,
struct pvr2_sysfs_class *);
#endif /* __PVRUSB2_SYSFS_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-util.h b/drivers/media/usb/pvrusb2/pvrusb2-util.h
index 92b75544ee2e..5465bf9cd73e 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-util.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-util.h
@@ -50,13 +50,3 @@
#endif /* __PVRUSB2_UTIL_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
index 536210b39428..35e4ea530494 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.c
@@ -1362,13 +1362,3 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
pvr2_v4l2_destroy_no_lock(vp);
return NULL;
}
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
index 34c011a7b107..e455c9515841 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-v4l2.h
@@ -27,13 +27,3 @@ struct pvr2_v4l2;
struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *);
#endif /* __PVRUSB2_V4L2_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 75 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
index 2e205c99eb96..139b39740534 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.c
@@ -101,14 +101,3 @@ void pvr2_saa7115_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sd->ops->video->s_routing(sd, input, 0, 0);
}
}
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
index 3b0bd5db602b..dacf3ec7f9e1 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-video-v4l.h
@@ -36,13 +36,3 @@
void pvr2_saa7115_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *);
#endif /* __PVRUSB2_VIDEO_V4L_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
index 3ac8d751a5c0..f1df94a2436f 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.c
@@ -56,15 +56,3 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *hdw, struct v4l2_subdev *sd)
sd->ops->audio->s_routing(sd, input, 0, 0);
}
}
-
-
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
index 0577bc7246fb..a4ee12e28d5c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2-wm8775.h
@@ -40,13 +40,3 @@ void pvr2_wm8775_subdev_update(struct pvr2_hdw *, struct v4l2_subdev *sd);
#endif /* __PVRUSB2_WM8775_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2.h b/drivers/media/usb/pvrusb2/pvrusb2.h
index 240de9b35661..95f98a87abb3 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2.h
+++ b/drivers/media/usb/pvrusb2/pvrusb2.h
@@ -30,13 +30,3 @@
#define PVR_NUM 20
#endif /* __PVRUSB2_H */
-
-/*
- Stuff for Emacs to see, in order to encourage consistent editing style:
- *** Local Variables: ***
- *** mode: c ***
- *** fill-column: 70 ***
- *** tab-width: 8 ***
- *** c-basic-offset: 8 ***
- *** End: ***
- */
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index 15b754da4a2c..702267e208ba 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -508,7 +508,8 @@ static void pwc_isoc_cleanup(struct pwc_device *pdev)
}
/* Must be called with vb_queue_lock hold */
-static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
+static void pwc_cleanup_queued_bufs(struct pwc_device *pdev,
+ enum vb2_buffer_state state)
{
unsigned long flags = 0;
@@ -519,7 +520,7 @@ static void pwc_cleanup_queued_bufs(struct pwc_device *pdev)
buf = list_entry(pdev->queued_bufs.next, struct pwc_frame_buf,
list);
list_del(&buf->list);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ vb2_buffer_done(&buf->vb, state);
}
spin_unlock_irqrestore(&pdev->queued_bufs_lock, flags);
}
@@ -674,7 +675,7 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
/* And cleanup any queued bufs!! */
- pwc_cleanup_queued_bufs(pdev);
+ pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_QUEUED);
}
mutex_unlock(&pdev->v4l2_lock);
@@ -692,7 +693,9 @@ static void stop_streaming(struct vb2_queue *vq)
pwc_isoc_cleanup(pdev);
}
- pwc_cleanup_queued_bufs(pdev);
+ pwc_cleanup_queued_bufs(pdev, VB2_BUF_STATE_ERROR);
+ if (pdev->fill_buf)
+ vb2_buffer_done(&pdev->fill_buf->vb, VB2_BUF_STATE_ERROR);
mutex_unlock(&pdev->v4l2_lock);
}
@@ -1125,7 +1128,6 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
if (pdev->vb_queue.streaming)
pwc_isoc_cleanup(pdev);
pdev->udev = NULL;
- pwc_cleanup_queued_bufs(pdev);
v4l2_device_disconnect(&pdev->v4l2_dev);
video_unregister_device(&pdev->vdev);
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index de55e96fed15..0f3c34d47ec3 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -2274,9 +2274,7 @@ static int s2255_probe(struct usb_interface *interface,
dev_err(&interface->dev, "Could not find bulk-in endpoint\n");
goto errorEP;
}
- init_timer(&dev->timer);
- dev->timer.function = s2255_timer;
- dev->timer.data = (unsigned long)dev->fw_data;
+ setup_timer(&dev->timer, s2255_timer, (unsigned long)dev->fw_data);
init_waitqueue_head(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
struct s2255_vc *vc = &dev->vc[i];
diff --git a/drivers/media/usb/siano/Kconfig b/drivers/media/usb/siano/Kconfig
index 5afbd9a4b55c..d37b742d4f7a 100644
--- a/drivers/media/usb/siano/Kconfig
+++ b/drivers/media/usb/siano/Kconfig
@@ -5,7 +5,9 @@
config SMS_USB_DRV
tristate "Siano SMS1xxx based MDTV receiver"
depends on DVB_CORE && HAS_DMA
+ depends on !RC_CORE || RC_CORE
select MEDIA_COMMON_OPTIONS
+ select SMS_SIANO_MDTV
---help---
Choose if you would like to have Siano's support for USB interface
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index a47629108c1b..65a326c5128f 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -38,10 +38,6 @@
#include "stk1160.h"
#include "stk1160-reg.h"
-static unsigned int vidioc_debug;
-module_param(vidioc_debug, int, 0644);
-MODULE_PARM_DESC(vidioc_debug, "enable debug messages [vidioc]");
-
static bool keep_buffers;
module_param(keep_buffers, bool, 0644);
MODULE_PARM_DESC(keep_buffers, "don't release buffers upon stop streaming");
@@ -659,7 +655,6 @@ int stk1160_video_register(struct stk1160 *dev)
/* Initialize video_device with a template structure */
dev->vdev = v4l_template;
- dev->vdev.debug = vidioc_debug;
dev->vdev.queue = &dev->vb_vidq;
/*
diff --git a/drivers/media/usb/stkwebcam/stk-webcam.c b/drivers/media/usb/stkwebcam/stk-webcam.c
index 3588dc38db87..e08fa587332f 100644
--- a/drivers/media/usb/stkwebcam/stk-webcam.c
+++ b/drivers/media/usb/stkwebcam/stk-webcam.c
@@ -1262,7 +1262,6 @@ static int stk_register_video_device(struct stk_camera *dev)
dev->vdev = stk_v4l_data;
dev->vdev.lock = &dev->lock;
- dev->vdev.debug = debug;
dev->vdev.v4l2_dev = &dev->v4l2_dev;
video_set_drvdata(&dev->vdev, dev);
err = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, -1);
diff --git a/drivers/media/usb/tm6000/tm6000-video.c b/drivers/media/usb/tm6000/tm6000-video.c
index 793577fc4633..0f14d3ccc7b4 100644
--- a/drivers/media/usb/tm6000/tm6000-video.c
+++ b/drivers/media/usb/tm6000/tm6000-video.c
@@ -941,7 +941,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
if (NULL == fmt) {
- dprintk(dev, V4L2_DEBUG_IOCTL_ARG, "Fourcc format (0x%08x)"
+ dprintk(dev, 2, "Fourcc format (0x%08x)"
" invalid.\n", f->fmt.pix.pixelformat);
return -EINVAL;
}
@@ -1622,7 +1622,6 @@ static struct video_device *vdev_init(struct tm6000_core *dev,
*vfd = *template;
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
- vfd->debug = tm6000_debug;
vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
diff --git a/drivers/media/usb/usbvision/usbvision-core.c b/drivers/media/usb/usbvision/usbvision-core.c
index 302aa07c458f..44b0c28d69b6 100644
--- a/drivers/media/usb/usbvision/usbvision-core.c
+++ b/drivers/media/usb/usbvision/usbvision-core.c
@@ -2194,9 +2194,8 @@ static void usbvision_power_off_timer(unsigned long data)
void usbvision_init_power_off_timer(struct usb_usbvision *usbvision)
{
- init_timer(&usbvision->power_off_timer);
- usbvision->power_off_timer.data = (long)usbvision;
- usbvision->power_off_timer.function = usbvision_power_off_timer;
+ setup_timer(&usbvision->power_off_timer, usbvision_power_off_timer,
+ (unsigned long)usbvision);
}
void usbvision_set_power_off_timer(struct usb_usbvision *usbvision)
@@ -2502,11 +2501,3 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
usbvision_set_audio(usbvision, audio[channel]);
return 0;
}
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/usbvision/usbvision-i2c.c b/drivers/media/usb/usbvision/usbvision-i2c.c
index ba262a32bd3a..26dbcb1146af 100644
--- a/drivers/media/usb/usbvision/usbvision-i2c.c
+++ b/drivers/media/usb/usbvision/usbvision-i2c.c
@@ -445,11 +445,3 @@ static struct i2c_adapter i2c_adap_template = {
.owner = THIS_MODULE,
.name = "usbvision",
};
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index 693d5f409138..cd2fbf11e3b4 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -1716,11 +1716,3 @@ static void __exit usbvision_exit(void)
module_init(usbvision_init);
module_exit(usbvision_exit);
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/usbvision/usbvision.h b/drivers/media/usb/usbvision/usbvision.h
index a0c73cf1517c..77aeb1ed9a81 100644
--- a/drivers/media/usb/usbvision/usbvision.h
+++ b/drivers/media/usb/usbvision/usbvision.h
@@ -517,11 +517,3 @@ int usbvision_power_off(struct usb_usbvision *usbvision);
int usbvision_power_on(struct usb_usbvision *usbvision);
#endif /* __LINUX_USBVISION_H */
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 6a4b0b8cd270..cf27006c29dc 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -138,6 +138,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_RGB565,
},
{
+ .name = "BGR 8:8:8 (BGR3)",
+ .guid = UVC_GUID_FORMAT_BGR3,
+ .fcc = V4L2_PIX_FMT_BGR24,
+ },
+ {
.name = "H.264",
.guid = UVC_GUID_FORMAT_H264,
.fcc = V4L2_PIX_FMT_H264,
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index cc960723b926..10c554e7655c 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -143,20 +143,6 @@ static void uvc_buffer_finish(struct vb2_buffer *vb)
uvc_video_clock_update(stream, &vb->v4l2_buf, buf);
}
-static void uvc_wait_prepare(struct vb2_queue *vq)
-{
- struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
-
- mutex_unlock(&queue->mutex);
-}
-
-static void uvc_wait_finish(struct vb2_queue *vq)
-{
- struct uvc_video_queue *queue = vb2_get_drv_priv(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);
@@ -195,8 +181,8 @@ static struct vb2_ops uvc_queue_qops = {
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.buf_finish = uvc_buffer_finish,
- .wait_prepare = uvc_wait_prepare,
- .wait_finish = uvc_wait_finish,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.start_streaming = uvc_start_streaming,
.stop_streaming = uvc_stop_streaming,
};
@@ -214,6 +200,7 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
queue->queue.mem_ops = &vb2_vmalloc_memops;
queue->queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC
| V4L2_BUF_FLAG_TSTAMP_SRC_SOE;
+ queue->queue.lock = &queue->mutex;
ret = vb2_queue_init(&queue->queue);
if (ret)
return ret;
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 9c5cbcf16529..43e953f73e02 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -13,7 +13,6 @@
#include <linux/compat.h>
#include <linux/kernel.h>
-#include <linux/version.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 9637e8b86949..20ccc9d315dc 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1734,13 +1734,13 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
uvc_video_clock_reset(stream);
+ if (!uvc_queue_streaming(&stream->queue))
+ return 0;
+
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0)
return ret;
- if (!uvc_queue_streaming(&stream->queue))
- return 0;
-
return uvc_init_video(stream, GFP_NOIO);
}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index f0a04b532ede..c63e5b55e143 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -109,6 +109,9 @@
#define UVC_GUID_FORMAT_RGBP \
{ 'R', 'G', 'B', 'P', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_BGR3 \
+ { 0x7d, 0xeb, 0x36, 0xe4, 0x4f, 0x52, 0xce, 0x11, \
+ 0x9f, 0x53, 0x00, 0x20, 0xaf, 0x0b, 0xa7, 0x70}
#define UVC_GUID_FORMAT_M420 \
{ 'M', '4', '2', '0', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
diff --git a/drivers/media/usb/zr364xx/zr364xx.c b/drivers/media/usb/zr364xx/zr364xx.c
index 5c006277b8b1..ca850316d379 100644
--- a/drivers/media/usb/zr364xx/zr364xx.c
+++ b/drivers/media/usb/zr364xx/zr364xx.c
@@ -1454,8 +1454,6 @@ static int zr364xx_probe(struct usb_interface *intf,
cam->vdev.v4l2_dev = &cam->v4l2_dev;
cam->vdev.ctrl_handler = &cam->ctrl_handler;
video_set_drvdata(&cam->vdev, cam);
- if (debug)
- cam->vdev.debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
cam->udev = udev;
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 9aa530a8bea9..86bb93fd7db8 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -47,15 +47,15 @@ static ssize_t index_show(struct device *cd,
}
static DEVICE_ATTR_RO(index);
-static ssize_t debug_show(struct device *cd,
+static ssize_t dev_debug_show(struct device *cd,
struct device_attribute *attr, char *buf)
{
struct video_device *vdev = to_video_device(cd);
- return sprintf(buf, "%i\n", vdev->debug);
+ return sprintf(buf, "%i\n", vdev->dev_debug);
}
-static ssize_t debug_store(struct device *cd, struct device_attribute *attr,
+static ssize_t dev_debug_store(struct device *cd, struct device_attribute *attr,
const char *buf, size_t len)
{
struct video_device *vdev = to_video_device(cd);
@@ -66,10 +66,10 @@ static ssize_t debug_store(struct device *cd, struct device_attribute *attr,
if (res)
return res;
- vdev->debug = value;
+ vdev->dev_debug = value;
return len;
}
-static DEVICE_ATTR_RW(debug);
+static DEVICE_ATTR_RW(dev_debug);
static ssize_t name_show(struct device *cd,
struct device_attribute *attr, char *buf)
@@ -82,7 +82,7 @@ static DEVICE_ATTR_RO(name);
static struct attribute *video_device_attrs[] = {
&dev_attr_name.attr,
- &dev_attr_debug.attr,
+ &dev_attr_dev_debug.attr,
&dev_attr_index.attr,
NULL,
};
@@ -304,7 +304,8 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
return -EINVAL;
if (video_is_registered(vdev))
ret = vdev->fops->read(filp, buf, sz, off);
- if (vdev->debug)
+ if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) &&
+ (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING))
printk(KERN_DEBUG "%s: read: %zd (%d)\n",
video_device_node_name(vdev), sz, ret);
return ret;
@@ -320,7 +321,8 @@ static ssize_t v4l2_write(struct file *filp, const char __user *buf,
return -EINVAL;
if (video_is_registered(vdev))
ret = vdev->fops->write(filp, buf, sz, off);
- if (vdev->debug)
+ if ((vdev->dev_debug & V4L2_DEV_DEBUG_FOP) &&
+ (vdev->dev_debug & V4L2_DEV_DEBUG_STREAMING))
printk(KERN_DEBUG "%s: write: %zd (%d)\n",
video_device_node_name(vdev), sz, ret);
return ret;
@@ -335,7 +337,7 @@ static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
return DEFAULT_POLLMASK;
if (video_is_registered(vdev))
res = vdev->fops->poll(filp, poll);
- if (vdev->debug > 2)
+ if (vdev->dev_debug & V4L2_DEV_DEBUG_POLL)
printk(KERN_DEBUG "%s: poll: %08x\n",
video_device_node_name(vdev), res);
return res;
@@ -404,7 +406,7 @@ static unsigned long v4l2_get_unmapped_area(struct file *filp,
if (!video_is_registered(vdev))
return -ENODEV;
ret = vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
- if (vdev->debug)
+ if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
printk(KERN_DEBUG "%s: get_unmapped_area (%d)\n",
video_device_node_name(vdev), ret);
return ret;
@@ -420,7 +422,7 @@ static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
return -ENODEV;
if (video_is_registered(vdev))
ret = vdev->fops->mmap(filp, vm);
- if (vdev->debug)
+ if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
printk(KERN_DEBUG "%s: mmap (%d)\n",
video_device_node_name(vdev), ret);
return ret;
@@ -450,7 +452,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
ret = -ENODEV;
}
- if (vdev->debug)
+ if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
printk(KERN_DEBUG "%s: open (%d)\n",
video_device_node_name(vdev), ret);
/* decrease the refcount in case of an error */
@@ -467,7 +469,7 @@ static int v4l2_release(struct inode *inode, struct file *filp)
if (vdev->fops->release)
ret = vdev->fops->release(filp);
- if (vdev->debug)
+ if (vdev->dev_debug & V4L2_DEV_DEBUG_FOP)
printk(KERN_DEBUG "%s: release\n",
video_device_node_name(vdev));
@@ -1033,10 +1035,3 @@ MODULE_AUTHOR("Alan Cox, Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers v2");
MODULE_LICENSE("GPL");
MODULE_ALIAS_CHARDEV_MAJOR(VIDEO_MAJOR);
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index faac2f4e0f3a..b08407225db1 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -2339,7 +2339,7 @@ static long __video_do_ioctl(struct file *file,
const struct v4l2_ioctl_info *info;
void *fh = file->private_data;
struct v4l2_fh *vfh = NULL;
- int debug = vfd->debug;
+ int dev_debug = vfd->dev_debug;
long ret = -ENOTTY;
if (ops == NULL) {
@@ -2388,11 +2388,15 @@ static long __video_do_ioctl(struct file *file,
}
done:
- if (debug) {
+ if (dev_debug & (V4L2_DEV_DEBUG_IOCTL | V4L2_DEV_DEBUG_IOCTL_ARG)) {
+ if (!(dev_debug & V4L2_DEV_DEBUG_STREAMING) &&
+ (cmd == VIDIOC_QBUF || cmd == VIDIOC_DQBUF))
+ return ret;
+
v4l_printk_ioctl(video_device_node_name(vfd), cmd);
if (ret < 0)
pr_cont(": error %ld", ret);
- if (debug == V4L2_DEBUG_IOCTL)
+ if (!(dev_debug & V4L2_DEV_DEBUG_IOCTL_ARG))
pr_cont("\n");
else if (_IOC_DIR(cmd) == _IOC_NONE)
info->debug(arg, write_only);
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 543631c3557a..19a034e79be4 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -283,10 +283,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
- rval = v4l2_subdev_call(sd, pad, get_crop, subdev_fh, crop);
- if (rval != -ENOIOCTLCMD)
- return rval;
-
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
sel.pad = crop->pad;
@@ -308,10 +304,6 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (rval)
return rval;
- rval = v4l2_subdev_call(sd, pad, set_crop, subdev_fh, crop);
- if (rval != -ENOIOCTLCMD)
- return rval;
-
memset(&sel, 0, sizeof(sel));
sel.which = crop->which;
sel.pad = crop->pad;
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 3ff15f1c9d70..f669cedca8bd 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -145,12 +145,11 @@ struct videobuf_dmabuf *videobuf_to_dma(struct videobuf_buffer *buf)
}
EXPORT_SYMBOL_GPL(videobuf_to_dma);
-void videobuf_dma_init(struct videobuf_dmabuf *dma)
+static void videobuf_dma_init(struct videobuf_dmabuf *dma)
{
memset(dma, 0, sizeof(*dma));
dma->magic = MAGIC_DMABUF;
}
-EXPORT_SYMBOL_GPL(videobuf_dma_init);
static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
int direction, unsigned long data, unsigned long size)
@@ -195,7 +194,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
return 0;
}
-int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
+static int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
unsigned long data, unsigned long size)
{
int ret;
@@ -206,9 +205,8 @@ int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
return ret;
}
-EXPORT_SYMBOL_GPL(videobuf_dma_init_user);
-int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
+static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
int nr_pages)
{
int i;
@@ -267,9 +265,8 @@ out_free_pages:
return -ENOMEM;
}
-EXPORT_SYMBOL_GPL(videobuf_dma_init_kernel);
-int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
+static int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
dma_addr_t addr, int nr_pages)
{
dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n",
@@ -284,9 +281,8 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
return 0;
}
-EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
+static int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
{
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
BUG_ON(0 == dma->nr_pages);
@@ -328,7 +324,6 @@ int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
return 0;
}
-EXPORT_SYMBOL_GPL(videobuf_dma_map);
int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
{
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index fba944e50227..bcde88572429 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -95,7 +95,7 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
if (vb2_get_contig_userptr(vaddr, size, &vma, &physp))
goto fail_pages_array_alloc;
buf->vma = vma;
- buf->vaddr = ioremap_nocache(physp, size);
+ buf->vaddr = (__force void *)ioremap_nocache(physp, size);
if (!buf->vaddr)
goto fail_pages_array_alloc;
} else {
@@ -155,7 +155,7 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
kfree(buf->pages);
} else {
vb2_put_vma(buf->vma);
- iounmap(buf->vaddr);
+ iounmap((__force void __iomem *)buf->vaddr);
}
kfree(buf);
}
@@ -211,6 +211,7 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
return 0;
}
+#ifdef CONFIG_HAS_DMA
/*********************************************/
/* DMABUF ops for exporters */
/*********************************************/
@@ -380,6 +381,8 @@ static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flag
return dbuf;
}
+#endif /* CONFIG_HAS_DMA */
+
/*********************************************/
/* callbacks for DMABUF buffers */
@@ -437,7 +440,9 @@ const struct vb2_mem_ops vb2_vmalloc_memops = {
.put = vb2_vmalloc_put,
.get_userptr = vb2_vmalloc_get_userptr,
.put_userptr = vb2_vmalloc_put_userptr,
+#ifdef CONFIG_HAS_DMA
.get_dmabuf = vb2_vmalloc_get_dmabuf,
+#endif
.map_dmabuf = vb2_vmalloc_map_dmabuf,
.unmap_dmabuf = vb2_vmalloc_unmap_dmabuf,
.attach_dmabuf = vb2_vmalloc_attach_dmabuf,
diff --git a/drivers/memory/fsl-corenet-cf.c b/drivers/memory/fsl-corenet-cf.c
index fc7ab5a3561e..d708ded5457b 100644
--- a/drivers/memory/fsl-corenet-cf.c
+++ b/drivers/memory/fsl-corenet-cf.c
@@ -27,18 +27,29 @@ enum ccf_version {
struct ccf_info {
enum ccf_version version;
int err_reg_offs;
+ bool has_brr;
};
static const struct ccf_info ccf1_info = {
.version = CCF1,
.err_reg_offs = 0xa00,
+ .has_brr = false,
};
static const struct ccf_info ccf2_info = {
.version = CCF2,
.err_reg_offs = 0xe40,
+ .has_brr = true,
};
+/*
+ * This register is present but not documented, with different values for
+ * IP_ID, on other chips with fsl,corenet2-cf such as t4240 and b4860.
+ */
+#define CCF_BRR 0xbf8
+#define CCF_BRR_IPID 0xffff0000
+#define CCF_BRR_IPID_T1040 0x09310000
+
static const struct of_device_id ccf_matches[] = {
{
.compatible = "fsl,corenet1-cf",
@@ -66,6 +77,8 @@ struct ccf_err_regs {
/* LAE/CV also valid for errdis and errinten */
#define ERRDET_LAE (1 << 0) /* Local Access Error */
#define ERRDET_CV (1 << 1) /* Coherency Violation */
+#define ERRDET_UTID (1 << 2) /* Unavailable Target ID (t1040) */
+#define ERRDET_MCST (1 << 3) /* Multicast Stash (t1040) */
#define ERRDET_CTYPE_SHIFT 26 /* Capture Type (ccf2 only) */
#define ERRDET_CTYPE_MASK (0x1f << ERRDET_CTYPE_SHIFT)
#define ERRDET_CAP (1 << 31) /* Capture Valid (ccf2 only) */
@@ -84,6 +97,7 @@ struct ccf_private {
struct device *dev;
void __iomem *regs;
struct ccf_err_regs __iomem *err_regs;
+ bool t1040;
};
static irqreturn_t ccf_irq(int irq, void *dev_id)
@@ -142,6 +156,12 @@ static irqreturn_t ccf_irq(int irq, void *dev_id)
if (errdet & ERRDET_CV)
dev_crit(ccf->dev, "Coherency Violation\n");
+ if (errdet & ERRDET_UTID)
+ dev_crit(ccf->dev, "Unavailable Target ID\n");
+
+ if (errdet & ERRDET_MCST)
+ dev_crit(ccf->dev, "Multicast Stash\n");
+
if (cap_valid) {
dev_crit(ccf->dev, "address 0x%09llx, src id 0x%x\n",
addr, src_id);
@@ -157,6 +177,7 @@ static int ccf_probe(struct platform_device *pdev)
struct ccf_private *ccf;
struct resource *r;
const struct of_device_id *match;
+ u32 errinten;
int ret, irq;
match = of_match_device(ccf_matches, &pdev->dev);
@@ -183,6 +204,13 @@ static int ccf_probe(struct platform_device *pdev)
ccf->info = match->data;
ccf->err_regs = ccf->regs + ccf->info->err_reg_offs;
+ if (ccf->info->has_brr) {
+ u32 brr = ioread32be(ccf->regs + CCF_BRR);
+
+ if ((brr & CCF_BRR_IPID) == CCF_BRR_IPID_T1040)
+ ccf->t1040 = true;
+ }
+
dev_set_drvdata(&pdev->dev, ccf);
irq = platform_get_irq(pdev, 0);
@@ -197,15 +225,19 @@ static int ccf_probe(struct platform_device *pdev)
return ret;
}
+ errinten = ERRDET_LAE | ERRDET_CV;
+ if (ccf->t1040)
+ errinten |= ERRDET_UTID | ERRDET_MCST;
+
switch (ccf->info->version) {
case CCF1:
/* On CCF1 this register enables rather than disables. */
- iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errdis);
+ iowrite32be(errinten, &ccf->err_regs->errdis);
break;
case CCF2:
iowrite32be(0, &ccf->err_regs->errdis);
- iowrite32be(ERRDET_LAE | ERRDET_CV, &ccf->err_regs->errinten);
+ iowrite32be(errinten, &ccf->err_regs->errinten);
break;
}
diff --git a/drivers/message/Makefile b/drivers/message/Makefile
index 97ef5a01ad11..755676ded67c 100644
--- a/drivers/message/Makefile
+++ b/drivers/message/Makefile
@@ -2,5 +2,4 @@
# Makefile for MPT based block devices
#
-obj-$(CONFIG_I2O) += i2o/
obj-$(CONFIG_FUSION) += fusion/
diff --git a/drivers/message/i2o/Kconfig b/drivers/message/i2o/Kconfig
deleted file mode 100644
index 5afa0e393ecf..000000000000
--- a/drivers/message/i2o/Kconfig
+++ /dev/null
@@ -1,121 +0,0 @@
-
-menuconfig I2O
- tristate "I2O device support"
- depends on PCI
- ---help---
- The Intelligent Input/Output (I2O) architecture allows hardware
- drivers to be split into two parts: an operating system specific
- module called the OSM and an hardware specific module called the
- HDM. The OSM can talk to a whole range of HDM's, and ideally the
- HDM's are not OS dependent. This allows for the same HDM driver to
- be used under different operating systems if the relevant OSM is in
- place. In order for this to work, you need to have an I2O interface
- adapter card in your computer. This card contains a special I/O
- processor (IOP), thus allowing high speeds since the CPU does not
- have to deal with I/O.
-
- If you say Y here, you will get a choice of interface adapter
- drivers and OSM's with the following questions.
-
- To compile this support as a module, choose M here: the
- modules will be called i2o_core.
-
- If unsure, say N.
-
-if I2O
-
-config I2O_LCT_NOTIFY_ON_CHANGES
- bool "Enable LCT notification"
- default y
- ---help---
- Only say N here if you have a I2O controller from SUN. The SUN
- firmware doesn't support LCT notification on changes. If this option
- is enabled on such a controller the driver will hang up in a endless
- loop. On all other controllers say Y.
-
- If unsure, say Y.
-
-config I2O_EXT_ADAPTEC
- bool "Enable Adaptec extensions"
- default y
- ---help---
- Say Y for support of raidutils for Adaptec I2O controllers. You also
- have to say Y to "I2O Configuration support", "I2O SCSI OSM" below
- and to "SCSI generic support" under "SCSI device configuration".
-
-config I2O_EXT_ADAPTEC_DMA64
- bool "Enable 64-bit DMA"
- depends on I2O_EXT_ADAPTEC && ( 64BIT || HIGHMEM64G )
- default y
- ---help---
- Say Y for support of 64-bit DMA transfer mode on Adaptec I2O
- controllers.
- Note: You need at least firmware version 3709.
-
-config I2O_CONFIG
- tristate "I2O Configuration support"
- depends on VIRT_TO_BUS
- ---help---
- Say Y for support of the configuration interface for the I2O adapters.
- If you have a RAID controller from Adaptec and you want to use the
- raidutils to manage your RAID array, you have to say Y here.
-
- To compile this support as a module, choose M here: the
- module will be called i2o_config.
-
- Note: If you want to use the new API you have to download the
- i2o_config patch from http://i2o.shadowconnect.com/
-
-config I2O_CONFIG_OLD_IOCTL
- bool "Enable ioctls (OBSOLETE)"
- depends on I2O_CONFIG
- default y
- ---help---
- Enables old ioctls.
-
-config I2O_BUS
- tristate "I2O Bus Adapter OSM"
- ---help---
- Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
- provides access to the busses on the I2O controller. The main purpose
- is to rescan the bus to find new devices.
-
- To compile this support as a module, choose M here: the
- module will be called i2o_bus.
-
-config I2O_BLOCK
- tristate "I2O Block OSM"
- depends on BLOCK
- ---help---
- Include support for the I2O Block OSM. The Block OSM presents disk
- and other structured block devices to the operating system. If you
- are using an RAID controller, you could access the array only by
- the Block OSM driver. But it is possible to access the single disks
- by the SCSI OSM driver, for example to monitor the disks.
-
- To compile this support as a module, choose M here: the
- module will be called i2o_block.
-
-config I2O_SCSI
- tristate "I2O SCSI OSM"
- depends on SCSI
- ---help---
- Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
- I2O controller. You can use both the SCSI and Block OSM together if
- you wish. To access a RAID array, you must use the Block OSM driver.
- But you could use the SCSI OSM driver to monitor the single disks.
-
- To compile this support as a module, choose M here: the
- module will be called i2o_scsi.
-
-config I2O_PROC
- tristate "I2O /proc support"
- ---help---
- If you say Y here and to "/proc file system support", you will be
- able to read I2O related information from the virtual directory
- /proc/i2o.
-
- To compile this support as a module, choose M here: the
- module will be called i2o_proc.
-
-endif # I2O
diff --git a/drivers/message/i2o/bus-osm.c b/drivers/message/i2o/bus-osm.c
deleted file mode 100644
index c463dc2efc09..000000000000
--- a/drivers/message/i2o/bus-osm.c
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Bus Adapter OSM
- *
- * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- * Fixes/additions:
- * Markus Lidel <Markus.Lidel@shadowconnect.com>
- * initial version.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-
-#define OSM_NAME "bus-osm"
-#define OSM_VERSION "1.317"
-#define OSM_DESCRIPTION "I2O Bus Adapter OSM"
-
-static struct i2o_driver i2o_bus_driver;
-
-/* Bus OSM class handling definition */
-static struct i2o_class_id i2o_bus_class_id[] = {
- {I2O_CLASS_BUS_ADAPTER},
- {I2O_CLASS_END}
-};
-
-/**
- * i2o_bus_scan - Scan the bus for new devices
- * @dev: I2O device of the bus, which should be scanned
- *
- * Scans the bus dev for new / removed devices. After the scan a new LCT
- * will be fetched automatically.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_bus_scan(struct i2o_device *dev)
-{
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return -ETIMEDOUT;
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.
- tid);
-
- return i2o_msg_post_wait(dev->iop, msg, 60);
-};
-
-/**
- * i2o_bus_store_scan - Scan the I2O Bus Adapter
- * @d: device which should be scanned
- * @attr: device_attribute
- * @buf: output buffer
- * @count: buffer size
- *
- * Returns count.
- */
-static ssize_t i2o_bus_store_scan(struct device *d,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct i2o_device *i2o_dev = to_i2o_device(d);
- int rc;
-
- if ((rc = i2o_bus_scan(i2o_dev)))
- osm_warn("bus scan failed %d\n", rc);
-
- return count;
-}
-
-/* Bus Adapter OSM device attributes */
-static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
-
-/**
- * i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it
- * @dev: device to verify if it is a I2O Bus Adapter device
- *
- * Because we want all Bus Adapters always return 0.
- * Except when we fail. Then we are sad.
- *
- * Returns 0, except when we fail to excel.
- */
-static int i2o_bus_probe(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
- int rc;
-
- rc = device_create_file(dev, &dev_attr_scan);
- if (rc)
- goto err_out;
-
- osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
-
- return 0;
-
-err_out:
- put_device(dev);
- return rc;
-};
-
-/**
- * i2o_bus_remove - remove the I2O Bus Adapter device from the system again
- * @dev: I2O Bus Adapter device which should be removed
- *
- * Always returns 0.
- */
-static int i2o_bus_remove(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
-
- device_remove_file(dev, &dev_attr_scan);
-
- put_device(dev);
-
- osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
-
- return 0;
-};
-
-/* Bus Adapter OSM driver struct */
-static struct i2o_driver i2o_bus_driver = {
- .name = OSM_NAME,
- .classes = i2o_bus_class_id,
- .driver = {
- .probe = i2o_bus_probe,
- .remove = i2o_bus_remove,
- },
-};
-
-/**
- * i2o_bus_init - Bus Adapter OSM initialization function
- *
- * Only register the Bus Adapter OSM in the I2O core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_bus_init(void)
-{
- int rc;
-
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
- /* Register Bus Adapter OSM into I2O core */
- rc = i2o_driver_register(&i2o_bus_driver);
- if (rc) {
- osm_err("Could not register Bus Adapter OSM\n");
- return rc;
- }
-
- return 0;
-};
-
-/**
- * i2o_bus_exit - Bus Adapter OSM exit function
- *
- * Unregisters Bus Adapter OSM from I2O core.
- */
-static void __exit i2o_bus_exit(void)
-{
- i2o_driver_unregister(&i2o_bus_driver);
-};
-
-MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_bus_init);
-module_exit(i2o_bus_exit);
diff --git a/drivers/message/i2o/config-osm.c b/drivers/message/i2o/config-osm.c
deleted file mode 100644
index 3bba7aa82e58..000000000000
--- a/drivers/message/i2o/config-osm.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Configuration OSM
- *
- * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- * Fixes/additions:
- * Markus Lidel <Markus.Lidel@shadowconnect.com>
- * initial version.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/dcache.h>
-#include <linux/namei.h>
-#include <linux/fs.h>
-
-#include <asm/uaccess.h>
-
-#define OSM_NAME "config-osm"
-#define OSM_VERSION "1.323"
-#define OSM_DESCRIPTION "I2O Configuration OSM"
-
-/* access mode user rw */
-#define S_IWRSR (S_IRUSR | S_IWUSR)
-
-static struct i2o_driver i2o_config_driver;
-
-/* Config OSM driver struct */
-static struct i2o_driver i2o_config_driver = {
- .name = OSM_NAME,
-};
-
-#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
-#include "i2o_config.c"
-#endif
-
-/**
- * i2o_config_init - Configuration OSM initialization function
- *
- * Registers Configuration OSM in the I2O core and if old ioctl's are
- * compiled in initialize them.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_config_init(void)
-{
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
- if (i2o_driver_register(&i2o_config_driver)) {
- osm_err("handler register failed.\n");
- return -EBUSY;
- }
-#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
- if (i2o_config_old_init()) {
- osm_err("old config handler initialization failed\n");
- i2o_driver_unregister(&i2o_config_driver);
- return -EBUSY;
- }
-#endif
-
- return 0;
-}
-
-/**
- * i2o_config_exit - Configuration OSM exit function
- *
- * If old ioctl's are compiled in exit remove them and unregisters
- * Configuration OSM from I2O core.
- */
-static void i2o_config_exit(void)
-{
-#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
- i2o_config_old_exit();
-#endif
-
- i2o_driver_unregister(&i2o_config_driver);
-}
-
-MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_config_init);
-module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/debug.c b/drivers/message/i2o/debug.c
deleted file mode 100644
index ce62d8bfe1c8..000000000000
--- a/drivers/message/i2o/debug.c
+++ /dev/null
@@ -1,472 +0,0 @@
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-
-static void i2o_report_util_cmd(u8 cmd);
-static void i2o_report_exec_cmd(u8 cmd);
-static void i2o_report_fail_status(u8 req_status, u32 * msg);
-static void i2o_report_common_status(u8 req_status);
-static void i2o_report_common_dsc(u16 detailed_status);
-
-/*
- * Used for error reporting/debugging purposes.
- * Report Cmd name, Request status, Detailed Status.
- */
-void i2o_report_status(const char *severity, const char *str,
- struct i2o_message *m)
-{
- u32 *msg = (u32 *) m;
- u8 cmd = (msg[1] >> 24) & 0xFF;
- u8 req_status = (msg[4] >> 24) & 0xFF;
- u16 detailed_status = msg[4] & 0xFFFF;
-
- if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
- return; // No status in this reply
-
- printk("%s%s: ", severity, str);
-
- if (cmd < 0x1F) // Utility cmd
- i2o_report_util_cmd(cmd);
-
- else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd
- i2o_report_exec_cmd(cmd);
- else
- printk("Cmd = %0#2x, ", cmd); // Other cmds
-
- if (msg[0] & MSG_FAIL) {
- i2o_report_fail_status(req_status, msg);
- return;
- }
-
- i2o_report_common_status(req_status);
-
- if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
- i2o_report_common_dsc(detailed_status);
- else
- printk(" / DetailedStatus = %0#4x.\n",
- detailed_status);
-}
-
-/* Used to dump a message to syslog during debugging */
-void i2o_dump_message(struct i2o_message *m)
-{
-#ifdef DEBUG
- u32 *msg = (u32 *) m;
- int i;
- printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
- msg[0] >> 16 & 0xffff, msg);
- for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++)
- printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]);
-#endif
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following fail status are common to all classes.
- * The preserved message must be handled in the reply handler.
- */
-static void i2o_report_fail_status(u8 req_status, u32 * msg)
-{
- static char *FAIL_STATUS[] = {
- "0x80", /* not used */
- "SERVICE_SUSPENDED", /* 0x81 */
- "SERVICE_TERMINATED", /* 0x82 */
- "CONGESTION",
- "FAILURE",
- "STATE_ERROR",
- "TIME_OUT",
- "ROUTING_FAILURE",
- "INVALID_VERSION",
- "INVALID_OFFSET",
- "INVALID_MSG_FLAGS",
- "FRAME_TOO_SMALL",
- "FRAME_TOO_LARGE",
- "INVALID_TARGET_ID",
- "INVALID_INITIATOR_ID",
- "INVALID_INITIATOR_CONTEX", /* 0x8F */
- "UNKNOWN_FAILURE" /* 0xFF */
- };
-
- if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
- printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n",
- req_status);
- else
- printk("TRANSPORT_%s.\n",
- FAIL_STATUS[req_status & 0x0F]);
-
- /* Dump some details */
-
- printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n",
- (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
- printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
- (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
- printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n",
- msg[5] >> 16, msg[5] & 0xFFF);
-
- printk(KERN_ERR " Severity: 0x%02X\n", (msg[4] >> 16) & 0xFF);
- if (msg[4] & (1 << 16))
- printk(KERN_DEBUG "(FormatError), "
- "this msg can never be delivered/processed.\n");
- if (msg[4] & (1 << 17))
- printk(KERN_DEBUG "(PathError), "
- "this msg can no longer be delivered/processed.\n");
- if (msg[4] & (1 << 18))
- printk(KERN_DEBUG "(PathState), "
- "the system state does not allow delivery.\n");
- if (msg[4] & (1 << 19))
- printk(KERN_DEBUG
- "(Congestion), resources temporarily not available;"
- "do not retry immediately.\n");
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following reply status are common to all classes.
- */
-static void i2o_report_common_status(u8 req_status)
-{
- static char *REPLY_STATUS[] = {
- "SUCCESS",
- "ABORT_DIRTY",
- "ABORT_NO_DATA_TRANSFER",
- "ABORT_PARTIAL_TRANSFER",
- "ERROR_DIRTY",
- "ERROR_NO_DATA_TRANSFER",
- "ERROR_PARTIAL_TRANSFER",
- "PROCESS_ABORT_DIRTY",
- "PROCESS_ABORT_NO_DATA_TRANSFER",
- "PROCESS_ABORT_PARTIAL_TRANSFER",
- "TRANSACTION_ERROR",
- "PROGRESS_REPORT"
- };
-
- if (req_status >= ARRAY_SIZE(REPLY_STATUS))
- printk("RequestStatus = %0#2x", req_status);
- else
- printk("%s", REPLY_STATUS[req_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes.
- * Following detailed status are valid for executive class,
- * utility class, DDM class and for transaction error replies.
- */
-static void i2o_report_common_dsc(u16 detailed_status)
-{
- static char *COMMON_DSC[] = {
- "SUCCESS",
- "0x01", // not used
- "BAD_KEY",
- "TCL_ERROR",
- "REPLY_BUFFER_FULL",
- "NO_SUCH_PAGE",
- "INSUFFICIENT_RESOURCE_SOFT",
- "INSUFFICIENT_RESOURCE_HARD",
- "0x08", // not used
- "CHAIN_BUFFER_TOO_LARGE",
- "UNSUPPORTED_FUNCTION",
- "DEVICE_LOCKED",
- "DEVICE_RESET",
- "INAPPROPRIATE_FUNCTION",
- "INVALID_INITIATOR_ADDRESS",
- "INVALID_MESSAGE_FLAGS",
- "INVALID_OFFSET",
- "INVALID_PARAMETER",
- "INVALID_REQUEST",
- "INVALID_TARGET_ADDRESS",
- "MESSAGE_TOO_LARGE",
- "MESSAGE_TOO_SMALL",
- "MISSING_PARAMETER",
- "TIMEOUT",
- "UNKNOWN_ERROR",
- "UNKNOWN_FUNCTION",
- "UNSUPPORTED_VERSION",
- "DEVICE_BUSY",
- "DEVICE_NOT_AVAILABLE"
- };
-
- if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
- printk(" / DetailedStatus = %0#4x.\n",
- detailed_status);
- else
- printk(" / %s.\n", COMMON_DSC[detailed_status]);
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_util_cmd(u8 cmd)
-{
- switch (cmd) {
- case I2O_CMD_UTIL_NOP:
- printk("UTIL_NOP, ");
- break;
- case I2O_CMD_UTIL_ABORT:
- printk("UTIL_ABORT, ");
- break;
- case I2O_CMD_UTIL_CLAIM:
- printk("UTIL_CLAIM, ");
- break;
- case I2O_CMD_UTIL_RELEASE:
- printk("UTIL_CLAIM_RELEASE, ");
- break;
- case I2O_CMD_UTIL_CONFIG_DIALOG:
- printk("UTIL_CONFIG_DIALOG, ");
- break;
- case I2O_CMD_UTIL_DEVICE_RESERVE:
- printk("UTIL_DEVICE_RESERVE, ");
- break;
- case I2O_CMD_UTIL_DEVICE_RELEASE:
- printk("UTIL_DEVICE_RELEASE, ");
- break;
- case I2O_CMD_UTIL_EVT_ACK:
- printk("UTIL_EVENT_ACKNOWLEDGE, ");
- break;
- case I2O_CMD_UTIL_EVT_REGISTER:
- printk("UTIL_EVENT_REGISTER, ");
- break;
- case I2O_CMD_UTIL_LOCK:
- printk("UTIL_LOCK, ");
- break;
- case I2O_CMD_UTIL_LOCK_RELEASE:
- printk("UTIL_LOCK_RELEASE, ");
- break;
- case I2O_CMD_UTIL_PARAMS_GET:
- printk("UTIL_PARAMS_GET, ");
- break;
- case I2O_CMD_UTIL_PARAMS_SET:
- printk("UTIL_PARAMS_SET, ");
- break;
- case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
- printk("UTIL_REPLY_FAULT_NOTIFY, ");
- break;
- default:
- printk("Cmd = %0#2x, ", cmd);
- }
-}
-
-/*
- * Used for error reporting/debugging purposes
- */
-static void i2o_report_exec_cmd(u8 cmd)
-{
- switch (cmd) {
- case I2O_CMD_ADAPTER_ASSIGN:
- printk("EXEC_ADAPTER_ASSIGN, ");
- break;
- case I2O_CMD_ADAPTER_READ:
- printk("EXEC_ADAPTER_READ, ");
- break;
- case I2O_CMD_ADAPTER_RELEASE:
- printk("EXEC_ADAPTER_RELEASE, ");
- break;
- case I2O_CMD_BIOS_INFO_SET:
- printk("EXEC_BIOS_INFO_SET, ");
- break;
- case I2O_CMD_BOOT_DEVICE_SET:
- printk("EXEC_BOOT_DEVICE_SET, ");
- break;
- case I2O_CMD_CONFIG_VALIDATE:
- printk("EXEC_CONFIG_VALIDATE, ");
- break;
- case I2O_CMD_CONN_SETUP:
- printk("EXEC_CONN_SETUP, ");
- break;
- case I2O_CMD_DDM_DESTROY:
- printk("EXEC_DDM_DESTROY, ");
- break;
- case I2O_CMD_DDM_ENABLE:
- printk("EXEC_DDM_ENABLE, ");
- break;
- case I2O_CMD_DDM_QUIESCE:
- printk("EXEC_DDM_QUIESCE, ");
- break;
- case I2O_CMD_DDM_RESET:
- printk("EXEC_DDM_RESET, ");
- break;
- case I2O_CMD_DDM_SUSPEND:
- printk("EXEC_DDM_SUSPEND, ");
- break;
- case I2O_CMD_DEVICE_ASSIGN:
- printk("EXEC_DEVICE_ASSIGN, ");
- break;
- case I2O_CMD_DEVICE_RELEASE:
- printk("EXEC_DEVICE_RELEASE, ");
- break;
- case I2O_CMD_HRT_GET:
- printk("EXEC_HRT_GET, ");
- break;
- case I2O_CMD_ADAPTER_CLEAR:
- printk("EXEC_IOP_CLEAR, ");
- break;
- case I2O_CMD_ADAPTER_CONNECT:
- printk("EXEC_IOP_CONNECT, ");
- break;
- case I2O_CMD_ADAPTER_RESET:
- printk("EXEC_IOP_RESET, ");
- break;
- case I2O_CMD_LCT_NOTIFY:
- printk("EXEC_LCT_NOTIFY, ");
- break;
- case I2O_CMD_OUTBOUND_INIT:
- printk("EXEC_OUTBOUND_INIT, ");
- break;
- case I2O_CMD_PATH_ENABLE:
- printk("EXEC_PATH_ENABLE, ");
- break;
- case I2O_CMD_PATH_QUIESCE:
- printk("EXEC_PATH_QUIESCE, ");
- break;
- case I2O_CMD_PATH_RESET:
- printk("EXEC_PATH_RESET, ");
- break;
- case I2O_CMD_STATIC_MF_CREATE:
- printk("EXEC_STATIC_MF_CREATE, ");
- break;
- case I2O_CMD_STATIC_MF_RELEASE:
- printk("EXEC_STATIC_MF_RELEASE, ");
- break;
- case I2O_CMD_STATUS_GET:
- printk("EXEC_STATUS_GET, ");
- break;
- case I2O_CMD_SW_DOWNLOAD:
- printk("EXEC_SW_DOWNLOAD, ");
- break;
- case I2O_CMD_SW_UPLOAD:
- printk("EXEC_SW_UPLOAD, ");
- break;
- case I2O_CMD_SW_REMOVE:
- printk("EXEC_SW_REMOVE, ");
- break;
- case I2O_CMD_SYS_ENABLE:
- printk("EXEC_SYS_ENABLE, ");
- break;
- case I2O_CMD_SYS_MODIFY:
- printk("EXEC_SYS_MODIFY, ");
- break;
- case I2O_CMD_SYS_QUIESCE:
- printk("EXEC_SYS_QUIESCE, ");
- break;
- case I2O_CMD_SYS_TAB_SET:
- printk("EXEC_SYS_TAB_SET, ");
- break;
- default:
- printk("Cmd = %#02x, ", cmd);
- }
-}
-
-void i2o_debug_state(struct i2o_controller *c)
-{
- printk(KERN_INFO "%s: State = ", c->name);
- switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
- case 0x01:
- printk("INIT\n");
- break;
- case 0x02:
- printk("RESET\n");
- break;
- case 0x04:
- printk("HOLD\n");
- break;
- case 0x05:
- printk("READY\n");
- break;
- case 0x08:
- printk("OPERATIONAL\n");
- break;
- case 0x10:
- printk("FAILED\n");
- break;
- case 0x11:
- printk("FAULTED\n");
- break;
- default:
- printk("%x (unknown !!)\n",
- ((i2o_status_block *) c->status_block.virt)->iop_state);
- }
-};
-
-void i2o_dump_hrt(struct i2o_controller *c)
-{
- u32 *rows = (u32 *) c->hrt.virt;
- u8 *p = (u8 *) c->hrt.virt;
- u8 *d;
- int count;
- int length;
- int i;
- int state;
-
- if (p[3] != 0) {
- printk(KERN_ERR
- "%s: HRT table for controller is too new a version.\n",
- c->name);
- return;
- }
-
- count = p[0] | (p[1] << 8);
- length = p[2];
-
- printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
- c->name, count, length << 2);
-
- rows += 2;
-
- for (i = 0; i < count; i++) {
- printk(KERN_INFO "Adapter %08X: ", rows[0]);
- p = (u8 *) (rows + 1);
- d = (u8 *) (rows + 2);
- state = p[1] << 8 | p[0];
-
- printk("TID %04X:[", state & 0xFFF);
- state >>= 12;
- if (state & (1 << 0))
- printk("H"); /* Hidden */
- if (state & (1 << 2)) {
- printk("P"); /* Present */
- if (state & (1 << 1))
- printk("C"); /* Controlled */
- }
- if (state > 9)
- printk("*"); /* Hard */
-
- printk("]:");
-
- switch (p[3] & 0xFFFF) {
- case 0:
- /* Adapter private bus - easy */
- printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
- d[1] << 8 | d[0], *(u32 *) (d + 4));
- break;
- case 1:
- /* ISA bus */
- printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
- d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
- break;
-
- case 2: /* EISA bus */
- printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
- p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
- break;
-
- case 3: /* MCA bus */
- printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
- d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
- break;
-
- case 4: /* PCI bus */
- printk("PCI %d: Bus %d Device %d Function %d", p[2],
- d[2], d[1], d[0]);
- break;
-
- case 0x80: /* Other */
- default:
- printk("Unsupported bus type.");
- break;
- }
- printk("\n");
- rows += length;
- }
-}
-
-EXPORT_SYMBOL(i2o_dump_message);
diff --git a/drivers/message/i2o/device.c b/drivers/message/i2o/device.c
deleted file mode 100644
index 98348f420b52..000000000000
--- a/drivers/message/i2o/device.c
+++ /dev/null
@@ -1,594 +0,0 @@
-/*
- * Functions to handle I2O devices
- *
- * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- * Fixes/additions:
- * Markus Lidel <Markus.Lidel@shadowconnect.com>
- * initial version.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "core.h"
-
-/**
- * i2o_device_issue_claim - claim or release a device
- * @dev: I2O device to claim or release
- * @cmd: claim or release command
- * @type: type of claim
- *
- * Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent
- * is set by cmd. dev is the I2O device which should be claim or
- * released and the type is the claim type (see the I2O spec).
- *
- * Returs 0 on success or negative error code on failure.
- */
-static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
- u32 type)
-{
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid);
- msg->body[0] = cpu_to_le32(type);
-
- return i2o_msg_post_wait(dev->iop, msg, 60);
-}
-
-/**
- * i2o_device_claim - claim a device for use by an OSM
- * @dev: I2O device to claim
- *
- * Do the leg work to assign a device to a given OSM. If the claim succeeds,
- * the owner is the primary. If the attempt fails a negative errno code
- * is returned. On success zero is returned.
- */
-int i2o_device_claim(struct i2o_device *dev)
-{
- int rc = 0;
-
- mutex_lock(&dev->lock);
-
- rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
- if (!rc)
- pr_debug("i2o: claim of device %d succeeded\n",
- dev->lct_data.tid);
- else
- pr_debug("i2o: claim of device %d failed %d\n",
- dev->lct_data.tid, rc);
-
- mutex_unlock(&dev->lock);
-
- return rc;
-}
-
-/**
- * i2o_device_claim_release - release a device that the OSM is using
- * @dev: device to release
- *
- * Drop a claim by an OSM on a given I2O device.
- *
- * AC - some devices seem to want to refuse an unclaim until they have
- * finished internal processing. It makes sense since you don't want a
- * new device to go reconfiguring the entire system until you are done.
- * Thus we are prepared to wait briefly.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_device_claim_release(struct i2o_device *dev)
-{
- int tries;
- int rc = 0;
-
- mutex_lock(&dev->lock);
-
- /*
- * If the controller takes a nonblocking approach to
- * releases we have to sleep/poll for a few times.
- */
- for (tries = 0; tries < 10; tries++) {
- rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE,
- I2O_CLAIM_PRIMARY);
- if (!rc)
- break;
-
- ssleep(1);
- }
-
- if (!rc)
- pr_debug("i2o: claim release of device %d succeeded\n",
- dev->lct_data.tid);
- else
- pr_debug("i2o: claim release of device %d failed %d\n",
- dev->lct_data.tid, rc);
-
- mutex_unlock(&dev->lock);
-
- return rc;
-}
-
-/**
- * i2o_device_release - release the memory for a I2O device
- * @dev: I2O device which should be released
- *
- * Release the allocated memory. This function is called if refcount of
- * device reaches 0 automatically.
- */
-static void i2o_device_release(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
-
- pr_debug("i2o: device %s released\n", dev_name(dev));
-
- kfree(i2o_dev);
-}
-
-/**
- * class_id_show - Displays class id of I2O device
- * @dev: device of which the class id should be displayed
- * @attr: pointer to device attribute
- * @buf: buffer into which the class id should be printed
- *
- * Returns the number of bytes which are printed into the buffer.
- */
-static ssize_t class_id_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
-
- sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id);
- return strlen(buf) + 1;
-}
-static DEVICE_ATTR_RO(class_id);
-
-/**
- * tid_show - Displays TID of I2O device
- * @dev: device of which the TID should be displayed
- * @attr: pointer to device attribute
- * @buf: buffer into which the TID should be printed
- *
- * Returns the number of bytes which are printed into the buffer.
- */
-static ssize_t tid_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
-
- sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid);
- return strlen(buf) + 1;
-}
-static DEVICE_ATTR_RO(tid);
-
-/* I2O device attributes */
-static struct attribute *i2o_device_attrs[] = {
- &dev_attr_class_id.attr,
- &dev_attr_tid.attr,
- NULL,
-};
-
-static const struct attribute_group i2o_device_group = {
- .attrs = i2o_device_attrs,
-};
-
-const struct attribute_group *i2o_device_groups[] = {
- &i2o_device_group,
- NULL,
-};
-
-/**
- * i2o_device_alloc - Allocate a I2O device and initialize it
- *
- * Allocate the memory for a I2O device and initialize locks and lists
- *
- * Returns the allocated I2O device or a negative error code if the device
- * could not be allocated.
- */
-static struct i2o_device *i2o_device_alloc(void)
-{
- struct i2o_device *dev;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return ERR_PTR(-ENOMEM);
-
- INIT_LIST_HEAD(&dev->list);
- mutex_init(&dev->lock);
-
- dev->device.bus = &i2o_bus_type;
- dev->device.release = &i2o_device_release;
-
- return dev;
-}
-
-/**
- * i2o_device_add - allocate a new I2O device and add it to the IOP
- * @c: I2O controller that the device is on
- * @entry: LCT entry of the I2O device
- *
- * Allocate a new I2O device and initialize it with the LCT entry. The
- * device is appended to the device list of the controller.
- *
- * Returns zero on success, or a -ve errno.
- */
-static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry)
-{
- struct i2o_device *i2o_dev, *tmp;
- int rc;
-
- i2o_dev = i2o_device_alloc();
- if (IS_ERR(i2o_dev)) {
- printk(KERN_ERR "i2o: unable to allocate i2o device\n");
- return PTR_ERR(i2o_dev);
- }
-
- i2o_dev->lct_data = *entry;
-
- dev_set_name(&i2o_dev->device, "%d:%03x", c->unit,
- i2o_dev->lct_data.tid);
-
- i2o_dev->iop = c;
- i2o_dev->device.parent = &c->device;
-
- rc = device_register(&i2o_dev->device);
- if (rc)
- goto err;
-
- list_add_tail(&i2o_dev->list, &c->devices);
-
- /* create user entries for this device */
- tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
- if (tmp && (tmp != i2o_dev)) {
- rc = sysfs_create_link(&i2o_dev->device.kobj,
- &tmp->device.kobj, "user");
- if (rc)
- goto unreg_dev;
- }
-
- /* create user entries referring to this device */
- list_for_each_entry(tmp, &c->devices, list)
- if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
- && (tmp != i2o_dev)) {
- rc = sysfs_create_link(&tmp->device.kobj,
- &i2o_dev->device.kobj, "user");
- if (rc)
- goto rmlink1;
- }
-
- /* create parent entries for this device */
- tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
- if (tmp && (tmp != i2o_dev)) {
- rc = sysfs_create_link(&i2o_dev->device.kobj,
- &tmp->device.kobj, "parent");
- if (rc)
- goto rmlink1;
- }
-
- /* create parent entries referring to this device */
- list_for_each_entry(tmp, &c->devices, list)
- if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
- && (tmp != i2o_dev)) {
- rc = sysfs_create_link(&tmp->device.kobj,
- &i2o_dev->device.kobj, "parent");
- if (rc)
- goto rmlink2;
- }
-
- i2o_driver_notify_device_add_all(i2o_dev);
-
- pr_debug("i2o: device %s added\n", dev_name(&i2o_dev->device));
-
- return 0;
-
-rmlink2:
- /* If link creating failed halfway, we loop whole list to cleanup.
- * And we don't care wrong removing of link, because sysfs_remove_link
- * will take care of it.
- */
- list_for_each_entry(tmp, &c->devices, list) {
- if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
- sysfs_remove_link(&tmp->device.kobj, "parent");
- }
- sysfs_remove_link(&i2o_dev->device.kobj, "parent");
-rmlink1:
- list_for_each_entry(tmp, &c->devices, list)
- if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
- sysfs_remove_link(&tmp->device.kobj, "user");
- sysfs_remove_link(&i2o_dev->device.kobj, "user");
-unreg_dev:
- list_del(&i2o_dev->list);
- device_unregister(&i2o_dev->device);
-err:
- kfree(i2o_dev);
- return rc;
-}
-
-/**
- * i2o_device_remove - remove an I2O device from the I2O core
- * @i2o_dev: I2O device which should be released
- *
- * Is used on I2O controller removal or LCT modification, when the device
- * is removed from the system. Note that the device could still hang
- * around until the refcount reaches 0.
- */
-void i2o_device_remove(struct i2o_device *i2o_dev)
-{
- struct i2o_device *tmp;
- struct i2o_controller *c = i2o_dev->iop;
-
- i2o_driver_notify_device_remove_all(i2o_dev);
-
- sysfs_remove_link(&i2o_dev->device.kobj, "parent");
- sysfs_remove_link(&i2o_dev->device.kobj, "user");
-
- list_for_each_entry(tmp, &c->devices, list) {
- if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
- sysfs_remove_link(&tmp->device.kobj, "parent");
- if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
- sysfs_remove_link(&tmp->device.kobj, "user");
- }
- list_del(&i2o_dev->list);
-
- device_unregister(&i2o_dev->device);
-}
-
-/**
- * i2o_device_parse_lct - Parse a previously fetched LCT and create devices
- * @c: I2O controller from which the LCT should be parsed.
- *
- * The Logical Configuration Table tells us what we can talk to on the
- * board. For every entry we create an I2O device, which is registered in
- * the I2O core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_device_parse_lct(struct i2o_controller *c)
-{
- struct i2o_device *dev, *tmp;
- i2o_lct *lct;
- u32 *dlct = c->dlct.virt;
- int max = 0, i = 0;
- u16 table_size;
- u32 buf;
-
- mutex_lock(&c->lct_lock);
-
- kfree(c->lct);
-
- buf = le32_to_cpu(*dlct++);
- table_size = buf & 0xffff;
-
- lct = c->lct = kmalloc(table_size * 4, GFP_KERNEL);
- if (!lct) {
- mutex_unlock(&c->lct_lock);
- return -ENOMEM;
- }
-
- lct->lct_ver = buf >> 28;
- lct->boot_tid = buf >> 16 & 0xfff;
- lct->table_size = table_size;
- lct->change_ind = le32_to_cpu(*dlct++);
- lct->iop_flags = le32_to_cpu(*dlct++);
-
- table_size -= 3;
-
- pr_debug("%s: LCT has %d entries (LCT size: %d)\n", c->name, max,
- lct->table_size);
-
- while (table_size > 0) {
- i2o_lct_entry *entry = &lct->lct_entry[max];
- int found = 0;
-
- buf = le32_to_cpu(*dlct++);
- entry->entry_size = buf & 0xffff;
- entry->tid = buf >> 16 & 0xfff;
-
- entry->change_ind = le32_to_cpu(*dlct++);
- entry->device_flags = le32_to_cpu(*dlct++);
-
- buf = le32_to_cpu(*dlct++);
- entry->class_id = buf & 0xfff;
- entry->version = buf >> 12 & 0xf;
- entry->vendor_id = buf >> 16;
-
- entry->sub_class = le32_to_cpu(*dlct++);
-
- buf = le32_to_cpu(*dlct++);
- entry->user_tid = buf & 0xfff;
- entry->parent_tid = buf >> 12 & 0xfff;
- entry->bios_info = buf >> 24;
-
- memcpy(&entry->identity_tag, dlct, 8);
- dlct += 2;
-
- entry->event_capabilities = le32_to_cpu(*dlct++);
-
- /* add new devices, which are new in the LCT */
- list_for_each_entry_safe(dev, tmp, &c->devices, list) {
- if (entry->tid == dev->lct_data.tid) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- i2o_device_add(c, entry);
-
- table_size -= 9;
- max++;
- }
-
- /* remove devices, which are not in the LCT anymore */
- list_for_each_entry_safe(dev, tmp, &c->devices, list) {
- int found = 0;
-
- for (i = 0; i < max; i++) {
- if (lct->lct_entry[i].tid == dev->lct_data.tid) {
- found = 1;
- break;
- }
- }
-
- if (!found)
- i2o_device_remove(dev);
- }
-
- mutex_unlock(&c->lct_lock);
-
- return 0;
-}
-
-/*
- * Run time support routines
- */
-
-/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
- *
- * This function can be used for all UtilParamsGet/Set operations.
- * The OperationList is given in oplist-buffer,
- * and results are returned in reslist-buffer.
- * Note that the minimum sized reslist is 8 bytes and contains
- * ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
- */
-int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
- int oplen, void *reslist, int reslen)
-{
- struct i2o_message *msg;
- int i = 0;
- int rc;
- struct i2o_dma res;
- struct i2o_controller *c = i2o_dev->iop;
- struct device *dev = &c->pdev->dev;
-
- res.virt = NULL;
-
- if (i2o_dma_alloc(dev, &res, reslen))
- return -ENOMEM;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg)) {
- i2o_dma_free(dev, &res);
- return PTR_ERR(msg);
- }
-
- i = 0;
- msg->u.head[1] =
- cpu_to_le32(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid);
- msg->body[i++] = cpu_to_le32(0x00000000);
- msg->body[i++] = cpu_to_le32(0x4C000000 | oplen); /* OperationList */
- memcpy(&msg->body[i], oplist, oplen);
- i += (oplen / 4 + (oplen % 4 ? 1 : 0));
- msg->body[i++] = cpu_to_le32(0xD0000000 | res.len); /* ResultList */
- msg->body[i++] = cpu_to_le32(res.phys);
-
- msg->u.head[0] =
- cpu_to_le32(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) |
- SGL_OFFSET_5);
-
- rc = i2o_msg_post_wait_mem(c, msg, 10, &res);
-
- /* This only looks like a memory leak - don't "fix" it. */
- if (rc == -ETIMEDOUT)
- return rc;
-
- memcpy(reslist, res.virt, res.len);
- i2o_dma_free(dev, &res);
-
- return rc;
-}
-
-/*
- * Query one field group value or a whole scalar group.
- */
-int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
- void *buf, int buflen)
-{
- u32 opblk[] = { cpu_to_le32(0x00000001),
- cpu_to_le32((u16) group << 16 | I2O_PARAMS_FIELD_GET),
- cpu_to_le32((s16) field << 16 | 0x00000001)
- };
- u8 *resblk; /* 8 bytes for header */
- int rc;
-
- resblk = kmalloc(buflen + 8, GFP_KERNEL);
- if (!resblk)
- return -ENOMEM;
-
- rc = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
- sizeof(opblk), resblk, buflen + 8);
-
- memcpy(buf, resblk + 8, buflen); /* cut off header */
-
- kfree(resblk);
-
- return rc;
-}
-
-/*
- * if oper == I2O_PARAMS_TABLE_GET, get from all rows
- * if fieldcount == -1 return all fields
- * ibuf and ibuflen are unused (use NULL, 0)
- * else return specific fields
- * ibuf contains fieldindexes
- *
- * if oper == I2O_PARAMS_LIST_GET, get from specific rows
- * if fieldcount == -1 return all fields
- * ibuf contains rowcount, keyvalues
- * else return specific fields
- * fieldcount is # of fieldindexes
- * ibuf contains fieldindexes, rowcount, keyvalues
- *
- * You could also use directly function i2o_issue_params().
- */
-int i2o_parm_table_get(struct i2o_device *dev, int oper, int group,
- int fieldcount, void *ibuf, int ibuflen, void *resblk,
- int reslen)
-{
- u16 *opblk;
- int size;
-
- size = 10 + ibuflen;
- if (size % 4)
- size += 4 - size % 4;
-
- opblk = kmalloc(size, GFP_KERNEL);
- if (opblk == NULL) {
- printk(KERN_ERR "i2o: no memory for query buffer.\n");
- return -ENOMEM;
- }
-
- opblk[0] = 1; /* operation count */
- opblk[1] = 0; /* pad */
- opblk[2] = oper;
- opblk[3] = group;
- opblk[4] = fieldcount;
- memcpy(opblk + 5, ibuf, ibuflen); /* other params */
-
- size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
- size, resblk, reslen);
-
- kfree(opblk);
- if (size > reslen)
- return reslen;
-
- return size;
-}
-
-EXPORT_SYMBOL(i2o_device_claim);
-EXPORT_SYMBOL(i2o_device_claim_release);
-EXPORT_SYMBOL(i2o_parm_field_get);
-EXPORT_SYMBOL(i2o_parm_table_get);
-EXPORT_SYMBOL(i2o_parm_issue);
diff --git a/drivers/message/i2o/driver.c b/drivers/message/i2o/driver.c
deleted file mode 100644
index 1b18a0d1d05b..000000000000
--- a/drivers/message/i2o/driver.c
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs
- *
- * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.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.
- *
- * Fixes/additions:
- * Markus Lidel <Markus.Lidel@shadowconnect.com>
- * initial version.
- */
-
-#include <linux/device.h>
-#include <linux/module.h>
-#include <linux/rwsem.h>
-#include <linux/i2o.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "core.h"
-
-#define OSM_NAME "i2o"
-
-/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
-static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
-module_param_named(max_drivers, i2o_max_drivers, uint, 0);
-MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
-
-/* I2O drivers lock and array */
-static spinlock_t i2o_drivers_lock;
-static struct i2o_driver **i2o_drivers;
-
-/**
- * i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM)
- * @dev: device which should be verified
- * @drv: the driver to match against
- *
- * Used by the bus to check if the driver wants to handle the device.
- *
- * Returns 1 if the class ids of the driver match the class id of the
- * device, otherwise 0.
- */
-static int i2o_bus_match(struct device *dev, struct device_driver *drv)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_driver *i2o_drv = to_i2o_driver(drv);
- struct i2o_class_id *ids = i2o_drv->classes;
-
- if (ids)
- while (ids->class_id != I2O_CLASS_END) {
- if (ids->class_id == i2o_dev->lct_data.class_id)
- return 1;
- ids++;
- }
- return 0;
-};
-
-/* I2O bus type */
-struct bus_type i2o_bus_type = {
- .name = "i2o",
- .match = i2o_bus_match,
- .dev_groups = i2o_device_groups,
-};
-
-/**
- * i2o_driver_register - Register a I2O driver (OSM) in the I2O core
- * @drv: I2O driver which should be registered
- *
- * Registers the OSM drv in the I2O core and creates an event queues if
- * necessary.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_driver_register(struct i2o_driver *drv)
-{
- struct i2o_controller *c;
- int i;
- int rc = 0;
- unsigned long flags;
-
- osm_debug("Register driver %s\n", drv->name);
-
- if (drv->event) {
- drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1,
- drv->name);
- if (!drv->event_queue) {
- osm_err("Could not initialize event queue for driver "
- "%s\n", drv->name);
- return -EFAULT;
- }
- osm_debug("Event queue initialized for driver %s\n", drv->name);
- } else
- drv->event_queue = NULL;
-
- drv->driver.name = drv->name;
- drv->driver.bus = &i2o_bus_type;
-
- spin_lock_irqsave(&i2o_drivers_lock, flags);
-
- for (i = 0; i2o_drivers[i]; i++)
- if (i >= i2o_max_drivers) {
- osm_err("too many drivers registered, increase "
- "max_drivers\n");
- spin_unlock_irqrestore(&i2o_drivers_lock, flags);
- rc = -EFAULT;
- goto out;
- }
-
- drv->context = i;
- i2o_drivers[i] = drv;
-
- spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-
- osm_debug("driver %s gets context id %d\n", drv->name, drv->context);
-
- list_for_each_entry(c, &i2o_controllers, list) {
- struct i2o_device *i2o_dev;
-
- i2o_driver_notify_controller_add(drv, c);
- list_for_each_entry(i2o_dev, &c->devices, list)
- i2o_driver_notify_device_add(drv, i2o_dev);
- }
-
- rc = driver_register(&drv->driver);
- if (rc)
- goto out;
-
- return 0;
-out:
- if (drv->event_queue) {
- destroy_workqueue(drv->event_queue);
- drv->event_queue = NULL;
- }
-
- return rc;
-};
-
-/**
- * i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core
- * @drv: I2O driver which should be unregistered
- *
- * Unregisters the OSM drv from the I2O core and cleanup event queues if
- * necessary.
- */
-void i2o_driver_unregister(struct i2o_driver *drv)
-{
- struct i2o_controller *c;
- unsigned long flags;
-
- osm_debug("unregister driver %s\n", drv->name);
-
- driver_unregister(&drv->driver);
-
- list_for_each_entry(c, &i2o_controllers, list) {
- struct i2o_device *i2o_dev;
-
- list_for_each_entry(i2o_dev, &c->devices, list)
- i2o_driver_notify_device_remove(drv, i2o_dev);
-
- i2o_driver_notify_controller_remove(drv, c);
- }
-
- spin_lock_irqsave(&i2o_drivers_lock, flags);
- i2o_drivers[drv->context] = NULL;
- spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-
- if (drv->event_queue) {
- destroy_workqueue(drv->event_queue);
- drv->event_queue = NULL;
- osm_debug("event queue removed for %s\n", drv->name);
- }
-};
-
-/**
- * i2o_driver_dispatch - dispatch an I2O reply message
- * @c: I2O controller of the message
- * @m: I2O message number
- *
- * The reply is delivered to the driver from which the original message
- * was. This function is only called from interrupt context.
- *
- * Returns 0 on success and the message should not be flushed. Returns > 0
- * on success and if the message should be flushed afterwords. Returns
- * negative error code on failure (the message will be flushed too).
- */
-int i2o_driver_dispatch(struct i2o_controller *c, u32 m)
-{
- struct i2o_driver *drv;
- struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
- u32 context = le32_to_cpu(msg->u.s.icntxt);
- unsigned long flags;
-
- if (unlikely(context >= i2o_max_drivers)) {
- osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
- context);
- return -EIO;
- }
-
- spin_lock_irqsave(&i2o_drivers_lock, flags);
- drv = i2o_drivers[context];
- spin_unlock_irqrestore(&i2o_drivers_lock, flags);
-
- if (unlikely(!drv)) {
- osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
- context);
- return -EIO;
- }
-
- if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
- struct i2o_device *dev, *tmp;
- struct i2o_event *evt;
- u16 size;
- u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
-
- osm_debug("event received from device %d\n", tid);
-
- if (!drv->event)
- return -EIO;
-
- /* cut of header from message size (in 32-bit words) */
- size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
-
- evt = kzalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
- if (!evt)
- return -ENOMEM;
-
- evt->size = size;
- evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
- evt->event_indicator = le32_to_cpu(msg->body[0]);
- memcpy(&evt->data, &msg->body[1], size * 4);
-
- list_for_each_entry_safe(dev, tmp, &c->devices, list)
- if (dev->lct_data.tid == tid) {
- evt->i2o_dev = dev;
- break;
- }
-
- INIT_WORK(&evt->work, drv->event);
- queue_work(drv->event_queue, &evt->work);
- return 1;
- }
-
- if (unlikely(!drv->reply)) {
- osm_debug("%s: Reply to driver %s, but no reply function"
- " defined!\n", c->name, drv->name);
- return -EIO;
- }
-
- return drv->reply(c, m, msg);
-}
-
-/**
- * i2o_driver_notify_controller_add_all - Send notify of added controller
- * @c: newly added controller
- *
- * Send notifications to all registered drivers that a new controller was
- * added.
- */
-void i2o_driver_notify_controller_add_all(struct i2o_controller *c)
-{
- int i;
- struct i2o_driver *drv;
-
- for (i = 0; i < i2o_max_drivers; i++) {
- drv = i2o_drivers[i];
-
- if (drv)
- i2o_driver_notify_controller_add(drv, c);
- }
-}
-
-/**
- * i2o_driver_notify_controller_remove_all - Send notify of removed controller
- * @c: controller that is being removed
- *
- * Send notifications to all registered drivers that a controller was
- * removed.
- */
-void i2o_driver_notify_controller_remove_all(struct i2o_controller *c)
-{
- int i;
- struct i2o_driver *drv;
-
- for (i = 0; i < i2o_max_drivers; i++) {
- drv = i2o_drivers[i];
-
- if (drv)
- i2o_driver_notify_controller_remove(drv, c);
- }
-}
-
-/**
- * i2o_driver_notify_device_add_all - Send notify of added device
- * @i2o_dev: newly added I2O device
- *
- * Send notifications to all registered drivers that a device was added.
- */
-void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev)
-{
- int i;
- struct i2o_driver *drv;
-
- for (i = 0; i < i2o_max_drivers; i++) {
- drv = i2o_drivers[i];
-
- if (drv)
- i2o_driver_notify_device_add(drv, i2o_dev);
- }
-}
-
-/**
- * i2o_driver_notify_device_remove_all - Send notify of removed device
- * @i2o_dev: device that is being removed
- *
- * Send notifications to all registered drivers that a device was removed.
- */
-void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev)
-{
- int i;
- struct i2o_driver *drv;
-
- for (i = 0; i < i2o_max_drivers; i++) {
- drv = i2o_drivers[i];
-
- if (drv)
- i2o_driver_notify_device_remove(drv, i2o_dev);
- }
-}
-
-/**
- * i2o_driver_init - initialize I2O drivers (OSMs)
- *
- * Registers the I2O bus and allocate memory for the array of OSMs.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int __init i2o_driver_init(void)
-{
- int rc = 0;
-
- spin_lock_init(&i2o_drivers_lock);
-
- if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64)) {
- osm_warn("max_drivers set to %d, but must be >=2 and <= 64\n",
- i2o_max_drivers);
- i2o_max_drivers = I2O_MAX_DRIVERS;
- }
- osm_info("max drivers = %d\n", i2o_max_drivers);
-
- i2o_drivers =
- kcalloc(i2o_max_drivers, sizeof(*i2o_drivers), GFP_KERNEL);
- if (!i2o_drivers)
- return -ENOMEM;
-
- rc = bus_register(&i2o_bus_type);
-
- if (rc < 0)
- kfree(i2o_drivers);
-
- return rc;
-};
-
-/**
- * i2o_driver_exit - clean up I2O drivers (OSMs)
- *
- * Unregisters the I2O bus and frees driver array.
- */
-void i2o_driver_exit(void)
-{
- bus_unregister(&i2o_bus_type);
- kfree(i2o_drivers);
-};
-
-EXPORT_SYMBOL(i2o_driver_register);
-EXPORT_SYMBOL(i2o_driver_unregister);
-EXPORT_SYMBOL(i2o_driver_notify_controller_add_all);
-EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all);
-EXPORT_SYMBOL(i2o_driver_notify_device_add_all);
-EXPORT_SYMBOL(i2o_driver_notify_device_remove_all);
diff --git a/drivers/message/i2o/exec-osm.c b/drivers/message/i2o/exec-osm.c
deleted file mode 100644
index a3970e56ae53..000000000000
--- a/drivers/message/i2o/exec-osm.c
+++ /dev/null
@@ -1,612 +0,0 @@
-/*
- * Executive OSM
- *
- * Copyright (C) 1999-2002 Red Hat Software
- *
- * Written by Alan Cox, Building Number Three 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.
- *
- * A lot of the I2O message side code from this is taken from the Red
- * Creek RCPCI45 adapter driver by Red Creek Communications
- *
- * Fixes/additions:
- * Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- * Deepak Saxena <deepak@plexity.net>
- * Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * Alan Cox <alan@lxorguk.ukuu.org.uk>:
- * Ported to Linux 2.5.
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Minor fixes for 2.6.
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Support for sysfs included.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/delay.h>
-#include <linux/workqueue.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/sched.h> /* wait_event_interruptible_timeout() needs this */
-#include <asm/param.h> /* HZ */
-#include "core.h"
-
-#define OSM_NAME "exec-osm"
-
-struct i2o_driver i2o_exec_driver;
-
-/* global wait list for POST WAIT */
-static LIST_HEAD(i2o_exec_wait_list);
-
-/* Wait struct needed for POST WAIT */
-struct i2o_exec_wait {
- wait_queue_head_t *wq; /* Pointer to Wait queue */
- struct i2o_dma dma; /* DMA buffers to free on failure */
- u32 tcntxt; /* transaction context from reply */
- int complete; /* 1 if reply received otherwise 0 */
- u32 m; /* message id */
- struct i2o_message *msg; /* pointer to the reply message */
- struct list_head list; /* node in global wait list */
- spinlock_t lock; /* lock before modifying */
-};
-
-/* Work struct needed to handle LCT NOTIFY replies */
-struct i2o_exec_lct_notify_work {
- struct work_struct work; /* work struct */
- struct i2o_controller *c; /* controller on which the LCT NOTIFY
- was received */
-};
-
-/* Exec OSM class handling definition */
-static struct i2o_class_id i2o_exec_class_id[] = {
- {I2O_CLASS_EXECUTIVE},
- {I2O_CLASS_END}
-};
-
-/**
- * i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it
- *
- * Allocate the i2o_exec_wait struct and initialize the wait.
- *
- * Returns i2o_exec_wait pointer on success or negative error code on
- * failure.
- */
-static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
-{
- struct i2o_exec_wait *wait;
-
- wait = kzalloc(sizeof(*wait), GFP_KERNEL);
- if (!wait)
- return NULL;
-
- INIT_LIST_HEAD(&wait->list);
- spin_lock_init(&wait->lock);
-
- return wait;
-};
-
-/**
- * i2o_exec_wait_free - Free an i2o_exec_wait struct
- * @wait: I2O wait data which should be cleaned up
- */
-static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
-{
- kfree(wait);
-};
-
-/**
- * i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
- * @c: controller
- * @msg: message to post
- * @timeout: time in seconds to wait
- * @dma: i2o_dma struct of the DMA buffer to free on failure
- *
- * This API allows an OSM to post a message and then be told whether or
- * not the system received a successful reply. If the message times out
- * then the value '-ETIMEDOUT' is returned. This is a special case. In
- * this situation the message may (should) complete at an indefinite time
- * in the future. When it completes it will use the memory buffer
- * attached to the request. If -ETIMEDOUT is returned then the memory
- * buffer must not be freed. Instead the event completion will free them
- * for you. In all other cases the buffer are your problem.
- *
- * Returns 0 on success, negative error code on timeout or positive error
- * code from reply.
- */
-int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
- unsigned long timeout, struct i2o_dma *dma)
-{
- DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
- struct i2o_exec_wait *wait;
- static u32 tcntxt = 0x80000000;
- unsigned long flags;
- int rc = 0;
-
- wait = i2o_exec_wait_alloc();
- if (!wait) {
- i2o_msg_nop(c, msg);
- return -ENOMEM;
- }
-
- if (tcntxt == 0xffffffff)
- tcntxt = 0x80000000;
-
- if (dma)
- wait->dma = *dma;
-
- /*
- * Fill in the message initiator context and transaction context.
- * We will only use transaction contexts >= 0x80000000 for POST WAIT,
- * so we could find a POST WAIT reply easier in the reply handler.
- */
- msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
- wait->tcntxt = tcntxt++;
- msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);
-
- wait->wq = &wq;
- /*
- * we add elements to the head, because if a entry in the list will
- * never be removed, we have to iterate over it every time
- */
- list_add(&wait->list, &i2o_exec_wait_list);
-
- /*
- * Post the message to the controller. At some point later it will
- * return. If we time out before it returns then complete will be zero.
- */
- i2o_msg_post(c, msg);
-
- wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);
-
- spin_lock_irqsave(&wait->lock, flags);
-
- wait->wq = NULL;
-
- if (wait->complete)
- rc = le32_to_cpu(wait->msg->body[0]) >> 24;
- else {
- /*
- * We cannot remove it now. This is important. When it does
- * terminate (which it must do if the controller has not
- * died...) then it will otherwise scribble on stuff.
- *
- * FIXME: try abort message
- */
- if (dma)
- dma->virt = NULL;
-
- rc = -ETIMEDOUT;
- }
-
- spin_unlock_irqrestore(&wait->lock, flags);
-
- if (rc != -ETIMEDOUT) {
- i2o_flush_reply(c, wait->m);
- i2o_exec_wait_free(wait);
- }
-
- return rc;
-};
-
-/**
- * i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP
- * @c: I2O controller which answers
- * @m: message id
- * @msg: pointer to the I2O reply message
- * @context: transaction context of request
- *
- * This function is called in interrupt context only. If the reply reached
- * before the timeout, the i2o_exec_wait struct is filled with the message
- * and the task will be waked up. The task is now responsible for returning
- * the message m back to the controller! If the message reaches us after
- * the timeout clean up the i2o_exec_wait struct (including allocated
- * DMA buffer).
- *
- * Return 0 on success and if the message m should not be given back to the
- * I2O controller, or >0 on success and if the message should be given back
- * afterwords. Returns negative error code on failure. In this case the
- * message must also be given back to the controller.
- */
-static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
- struct i2o_message *msg, u32 context)
-{
- struct i2o_exec_wait *wait, *tmp;
- unsigned long flags;
- int rc = 1;
-
- /*
- * We need to search through the i2o_exec_wait_list to see if the given
- * message is still outstanding. If not, it means that the IOP took
- * longer to respond to the message than we had allowed and timer has
- * already expired. Not much we can do about that except log it for
- * debug purposes, increase timeout, and recompile.
- */
- list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
- if (wait->tcntxt == context) {
- spin_lock_irqsave(&wait->lock, flags);
-
- list_del(&wait->list);
-
- wait->m = m;
- wait->msg = msg;
- wait->complete = 1;
-
- if (wait->wq)
- rc = 0;
- else
- rc = -1;
-
- spin_unlock_irqrestore(&wait->lock, flags);
-
- if (rc) {
- struct device *dev;
-
- dev = &c->pdev->dev;
-
- pr_debug("%s: timedout reply received!\n",
- c->name);
- i2o_dma_free(dev, &wait->dma);
- i2o_exec_wait_free(wait);
- } else
- wake_up_interruptible(wait->wq);
-
- return rc;
- }
- }
-
- osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
- context);
-
- return -1;
-};
-
-/**
- * i2o_exec_show_vendor_id - Displays Vendor ID of controller
- * @d: device of which the Vendor ID should be displayed
- * @attr: device_attribute to display
- * @buf: buffer into which the Vendor ID should be printed
- *
- * Returns number of bytes printed into buffer.
- */
-static ssize_t i2o_exec_show_vendor_id(struct device *d,
- struct device_attribute *attr, char *buf)
-{
- struct i2o_device *dev = to_i2o_device(d);
- u16 id;
-
- if (!i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {
- sprintf(buf, "0x%04x", le16_to_cpu(id));
- return strlen(buf) + 1;
- }
-
- return 0;
-};
-
-/**
- * i2o_exec_show_product_id - Displays Product ID of controller
- * @d: device of which the Product ID should be displayed
- * @attr: device_attribute to display
- * @buf: buffer into which the Product ID should be printed
- *
- * Returns number of bytes printed into buffer.
- */
-static ssize_t i2o_exec_show_product_id(struct device *d,
- struct device_attribute *attr,
- char *buf)
-{
- struct i2o_device *dev = to_i2o_device(d);
- u16 id;
-
- if (!i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) {
- sprintf(buf, "0x%04x", le16_to_cpu(id));
- return strlen(buf) + 1;
- }
-
- return 0;
-};
-
-/* Exec-OSM device attributes */
-static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL);
-static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
-
-/**
- * i2o_exec_probe - Called if a new I2O device (executive class) appears
- * @dev: I2O device which should be probed
- *
- * Registers event notification for every event from Executive device. The
- * return is always 0, because we want all devices of class Executive.
- *
- * Returns 0 on success.
- */
-static int i2o_exec_probe(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
- int rc;
-
- rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
- if (rc) goto err_out;
-
- rc = device_create_file(dev, &dev_attr_vendor_id);
- if (rc) goto err_evtreg;
- rc = device_create_file(dev, &dev_attr_product_id);
- if (rc) goto err_vid;
-
- i2o_dev->iop->exec = i2o_dev;
-
- return 0;
-
-err_vid:
- device_remove_file(dev, &dev_attr_vendor_id);
-err_evtreg:
- i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
-err_out:
- return rc;
-};
-
-/**
- * i2o_exec_remove - Called on I2O device removal
- * @dev: I2O device which was removed
- *
- * Unregisters event notification from Executive I2O device.
- *
- * Returns 0 on success.
- */
-static int i2o_exec_remove(struct device *dev)
-{
- device_remove_file(dev, &dev_attr_product_id);
- device_remove_file(dev, &dev_attr_vendor_id);
-
- i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
-
- return 0;
-};
-
-#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
-/**
- * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
- * @c: I2O controller to which the request should be send
- * @change_ind: change indicator
- *
- * This function sends a LCT NOTIFY request to the I2O controller with
- * the change indicator change_ind. If the change_ind == 0 the controller
- * replies immediately after the request. If change_ind > 0 the reply is
- * send after change indicator of the LCT is > change_ind.
- */
-static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
-{
- i2o_status_block *sb = c->status_block.virt;
- struct device *dev;
- struct i2o_message *msg;
-
- mutex_lock(&c->lct_lock);
-
- dev = &c->pdev->dev;
-
- if (i2o_dma_realloc(dev, &c->dlct,
- le32_to_cpu(sb->expected_lct_size))) {
- mutex_unlock(&c->lct_lock);
- return -ENOMEM;
- }
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg)) {
- mutex_unlock(&c->lct_lock);
- return PTR_ERR(msg);
- }
-
- msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
- msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
- msg->u.s.tcntxt = cpu_to_le32(0x00000000);
- msg->body[0] = cpu_to_le32(0xffffffff);
- msg->body[1] = cpu_to_le32(change_ind);
- msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
- msg->body[3] = cpu_to_le32(c->dlct.phys);
-
- i2o_msg_post(c, msg);
-
- mutex_unlock(&c->lct_lock);
-
- return 0;
-}
-#endif
-
-/**
- * i2o_exec_lct_modified - Called on LCT NOTIFY reply
- * @_work: work struct for a specific controller
- *
- * This function handles asynchronus LCT NOTIFY replies. It parses the
- * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
- * again, otherwise send LCT NOTIFY to get informed on next LCT change.
- */
-static void i2o_exec_lct_modified(struct work_struct *_work)
-{
- struct i2o_exec_lct_notify_work *work =
- container_of(_work, struct i2o_exec_lct_notify_work, work);
- u32 change_ind = 0;
- struct i2o_controller *c = work->c;
-
- kfree(work);
-
- if (i2o_device_parse_lct(c) != -EAGAIN)
- change_ind = c->lct->change_ind + 1;
-
-#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
- i2o_exec_lct_notify(c, change_ind);
-#endif
-};
-
-/**
- * i2o_exec_reply - I2O Executive reply handler
- * @c: I2O controller from which the reply comes
- * @m: message id
- * @msg: pointer to the I2O reply message
- *
- * This function is always called from interrupt context. If a POST WAIT
- * reply was received, pass it to the complete function. If a LCT NOTIFY
- * reply was received, a new event is created to handle the update.
- *
- * Returns 0 on success and if the reply should not be flushed or > 0
- * on success and if the reply should be flushed. Returns negative error
- * code on failure and if the reply should be flushed.
- */
-static int i2o_exec_reply(struct i2o_controller *c, u32 m,
- struct i2o_message *msg)
-{
- u32 context;
-
- if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
- struct i2o_message __iomem *pmsg;
- u32 pm;
-
- /*
- * If Fail bit is set we must take the transaction context of
- * the preserved message to find the right request again.
- */
-
- pm = le32_to_cpu(msg->body[3]);
- pmsg = i2o_msg_in_to_virt(c, pm);
- context = readl(&pmsg->u.s.tcntxt);
-
- i2o_report_status(KERN_INFO, "i2o_core", msg);
-
- /* Release the preserved msg */
- i2o_msg_nop_mfa(c, pm);
- } else
- context = le32_to_cpu(msg->u.s.tcntxt);
-
- if (context & 0x80000000)
- return i2o_msg_post_wait_complete(c, m, msg, context);
-
- if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
- struct i2o_exec_lct_notify_work *work;
-
- pr_debug("%s: LCT notify received\n", c->name);
-
- work = kmalloc(sizeof(*work), GFP_ATOMIC);
- if (!work)
- return -ENOMEM;
-
- work->c = c;
-
- INIT_WORK(&work->work, i2o_exec_lct_modified);
- queue_work(i2o_exec_driver.event_queue, &work->work);
- return 1;
- }
-
- /*
- * If this happens, we want to dump the message to the syslog so
- * it can be sent back to the card manufacturer by the end user
- * to aid in debugging.
- *
- */
- printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
- "Message dumped to syslog\n", c->name);
- i2o_dump_message(msg);
-
- return -EFAULT;
-}
-
-/**
- * i2o_exec_event - Event handling function
- * @work: Work item in occurring event
- *
- * Handles events send by the Executive device. At the moment does not do
- * anything useful.
- */
-static void i2o_exec_event(struct work_struct *work)
-{
- struct i2o_event *evt = container_of(work, struct i2o_event, work);
-
- if (likely(evt->i2o_dev))
- osm_debug("Event received from device: %d\n",
- evt->i2o_dev->lct_data.tid);
- kfree(evt);
-};
-
-/**
- * i2o_exec_lct_get - Get the IOP's Logical Configuration Table
- * @c: I2O controller from which the LCT should be fetched
- *
- * Send a LCT NOTIFY request to the controller, and wait
- * I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is
- * to large, retry it.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_exec_lct_get(struct i2o_controller *c)
-{
- struct i2o_message *msg;
- int i = 0;
- int rc = -EAGAIN;
-
- for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] =
- cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->body[0] = cpu_to_le32(0xffffffff);
- msg->body[1] = cpu_to_le32(0x00000000);
- msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
- msg->body[3] = cpu_to_le32(c->dlct.phys);
-
- rc = i2o_msg_post_wait(c, msg, I2O_TIMEOUT_LCT_GET);
- if (rc < 0)
- break;
-
- rc = i2o_device_parse_lct(c);
- if (rc != -EAGAIN)
- break;
- }
-
- return rc;
-}
-
-/* Exec OSM driver struct */
-struct i2o_driver i2o_exec_driver = {
- .name = OSM_NAME,
- .reply = i2o_exec_reply,
- .event = i2o_exec_event,
- .classes = i2o_exec_class_id,
- .driver = {
- .probe = i2o_exec_probe,
- .remove = i2o_exec_remove,
- },
-};
-
-/**
- * i2o_exec_init - Registers the Exec OSM
- *
- * Registers the Exec OSM in the I2O core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int __init i2o_exec_init(void)
-{
- return i2o_driver_register(&i2o_exec_driver);
-};
-
-/**
- * i2o_exec_exit - Removes the Exec OSM
- *
- * Unregisters the Exec OSM from the I2O core.
- */
-void i2o_exec_exit(void)
-{
- i2o_driver_unregister(&i2o_exec_driver);
-};
-
-EXPORT_SYMBOL(i2o_msg_post_wait_mem);
-EXPORT_SYMBOL(i2o_exec_lct_get);
diff --git a/drivers/message/i2o/i2o_block.c b/drivers/message/i2o/i2o_block.c
deleted file mode 100644
index 6fc3866965df..000000000000
--- a/drivers/message/i2o/i2o_block.c
+++ /dev/null
@@ -1,1228 +0,0 @@
-/*
- * Block OSM
- *
- * Copyright (C) 1999-2002 Red Hat Software
- *
- * Written by Alan Cox, Building Number Three 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.
- *
- * For the purpose of avoiding doubt the preferred form of the work
- * for making modifications shall be a standards compliant form such
- * gzipped tar and not one requiring a proprietary or patent encumbered
- * tool to unpack.
- *
- * Fixes/additions:
- * Steve Ralston:
- * Multiple device handling error fixes,
- * Added a queue depth.
- * Alan Cox:
- * FC920 has an rmw bug. Dont or in the end marker.
- * Removed queue walk, fixed for 64bitness.
- * Rewrote much of the code over time
- * Added indirect block lists
- * Handle 64K limits on many controllers
- * Don't use indirects on the Promise (breaks)
- * Heavily chop down the queue depths
- * Deepak Saxena:
- * Independent queues per IOP
- * Support for dynamic device creation/deletion
- * Code cleanup
- * Support for larger I/Os through merge* functions
- * (taken from DAC960 driver)
- * Boji T Kannanthanam:
- * Set the I2O Block devices to be detected in increasing
- * order of TIDs during boot.
- * Search and set the I2O block device that we boot off
- * from as the first device to be claimed (as /dev/i2o/hda)
- * Properly attach/detach I2O gendisk structure from the
- * system gendisk list. The I2O block devices now appear in
- * /proc/partitions.
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Minor bugfixes for 2.6.
- */
-
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/i2o.h>
-#include <linux/mutex.h>
-
-#include <linux/mempool.h>
-
-#include <linux/genhd.h>
-#include <linux/blkdev.h>
-#include <linux/hdreg.h>
-
-#include <scsi/scsi.h>
-
-#include "i2o_block.h"
-
-#define OSM_NAME "block-osm"
-#define OSM_VERSION "1.325"
-#define OSM_DESCRIPTION "I2O Block Device OSM"
-
-static DEFINE_MUTEX(i2o_block_mutex);
-static struct i2o_driver i2o_block_driver;
-
-/* global Block OSM request mempool */
-static struct i2o_block_mempool i2o_blk_req_pool;
-
-/* Block OSM class handling definition */
-static struct i2o_class_id i2o_block_class_id[] = {
- {I2O_CLASS_RANDOM_BLOCK_STORAGE},
- {I2O_CLASS_END}
-};
-
-/**
- * i2o_block_device_free - free the memory of the I2O Block device
- * @dev: I2O Block device, which should be cleaned up
- *
- * Frees the request queue, gendisk and the i2o_block_device structure.
- */
-static void i2o_block_device_free(struct i2o_block_device *dev)
-{
- blk_cleanup_queue(dev->gd->queue);
-
- put_disk(dev->gd);
-
- kfree(dev);
-};
-
-/**
- * i2o_block_remove - remove the I2O Block device from the system again
- * @dev: I2O Block device which should be removed
- *
- * Remove gendisk from system and free all allocated memory.
- *
- * Always returns 0.
- */
-static int i2o_block_remove(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev);
-
- osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid,
- i2o_blk_dev->gd->disk_name);
-
- i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0);
-
- del_gendisk(i2o_blk_dev->gd);
-
- dev_set_drvdata(dev, NULL);
-
- i2o_device_claim_release(i2o_dev);
-
- i2o_block_device_free(i2o_blk_dev);
-
- return 0;
-};
-
-/**
- * i2o_block_device flush - Flush all dirty data of I2O device dev
- * @dev: I2O device which should be flushed
- *
- * Flushes all dirty data on device dev.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_flush(struct i2o_device *dev)
-{
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->
- lct_data.tid);
- msg->body[0] = cpu_to_le32(60 << 16);
- osm_debug("Flushing...\n");
-
- return i2o_msg_post_wait(dev->iop, msg, 60);
-};
-
-/**
- * i2o_block_device_mount - Mount (load) the media of device dev
- * @dev: I2O device which should receive the mount request
- * @media_id: Media Identifier
- *
- * Load a media into drive. Identifier should be set to -1, because the
- * spec does not support any other value.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id)
-{
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->
- lct_data.tid);
- msg->body[0] = cpu_to_le32(-1);
- msg->body[1] = cpu_to_le32(0x00000000);
- osm_debug("Mounting...\n");
-
- return i2o_msg_post_wait(dev->iop, msg, 2);
-};
-
-/**
- * i2o_block_device_lock - Locks the media of device dev
- * @dev: I2O device which should receive the lock request
- * @media_id: Media Identifier
- *
- * Lock media of device dev to prevent removal. The media identifier
- * should be set to -1, because the spec does not support any other value.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id)
-{
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->
- lct_data.tid);
- msg->body[0] = cpu_to_le32(-1);
- osm_debug("Locking...\n");
-
- return i2o_msg_post_wait(dev->iop, msg, 2);
-};
-
-/**
- * i2o_block_device_unlock - Unlocks the media of device dev
- * @dev: I2O device which should receive the unlocked request
- * @media_id: Media Identifier
- *
- * Unlocks the media in device dev. The media identifier should be set to
- * -1, because the spec does not support any other value.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id)
-{
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->
- lct_data.tid);
- msg->body[0] = cpu_to_le32(media_id);
- osm_debug("Unlocking...\n");
-
- return i2o_msg_post_wait(dev->iop, msg, 2);
-};
-
-/**
- * i2o_block_device_power - Power management for device dev
- * @dev: I2O device which should receive the power management request
- * @op: Operation to send
- *
- * Send a power management request to the device dev.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_device_power(struct i2o_block_device *dev, u8 op)
-{
- struct i2o_device *i2o_dev = dev->i2o_dev;
- struct i2o_controller *c = i2o_dev->iop;
- struct i2o_message *msg;
- int rc;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->
- lct_data.tid);
- msg->body[0] = cpu_to_le32(op << 24);
- osm_debug("Power...\n");
-
- rc = i2o_msg_post_wait(c, msg, 60);
- if (!rc)
- dev->power = op;
-
- return rc;
-};
-
-/**
- * i2o_block_request_alloc - Allocate an I2O block request struct
- *
- * Allocates an I2O block request struct and initialize the list.
- *
- * Returns a i2o_block_request pointer on success or negative error code
- * on failure.
- */
-static inline struct i2o_block_request *i2o_block_request_alloc(void)
-{
- struct i2o_block_request *ireq;
-
- ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC);
- if (!ireq)
- return ERR_PTR(-ENOMEM);
-
- INIT_LIST_HEAD(&ireq->queue);
- sg_init_table(ireq->sg_table, I2O_MAX_PHYS_SEGMENTS);
-
- return ireq;
-};
-
-/**
- * i2o_block_request_free - Frees a I2O block request
- * @ireq: I2O block request which should be freed
- *
- * Frees the allocated memory (give it back to the request mempool).
- */
-static inline void i2o_block_request_free(struct i2o_block_request *ireq)
-{
- mempool_free(ireq, i2o_blk_req_pool.pool);
-};
-
-/**
- * i2o_block_sglist_alloc - Allocate the SG list and map it
- * @c: I2O controller to which the request belongs
- * @ireq: I2O block request
- * @mptr: message body pointer
- *
- * Builds the SG list and map it to be accessible by the controller.
- *
- * Returns 0 on failure or 1 on success.
- */
-static inline int i2o_block_sglist_alloc(struct i2o_controller *c,
- struct i2o_block_request *ireq,
- u32 ** mptr)
-{
- int nents;
- enum dma_data_direction direction;
-
- ireq->dev = &c->pdev->dev;
- nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table);
-
- if (rq_data_dir(ireq->req) == READ)
- direction = PCI_DMA_FROMDEVICE;
- else
- direction = PCI_DMA_TODEVICE;
-
- ireq->sg_nents = nents;
-
- return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);
-};
-
-/**
- * i2o_block_sglist_free - Frees the SG list
- * @ireq: I2O block request from which the SG should be freed
- *
- * Frees the SG list from the I2O block request.
- */
-static inline void i2o_block_sglist_free(struct i2o_block_request *ireq)
-{
- enum dma_data_direction direction;
-
- if (rq_data_dir(ireq->req) == READ)
- direction = PCI_DMA_FROMDEVICE;
- else
- direction = PCI_DMA_TODEVICE;
-
- dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);
-};
-
-/**
- * i2o_block_prep_req_fn - Allocates I2O block device specific struct
- * @q: request queue for the request
- * @req: the request to prepare
- *
- * Allocate the necessary i2o_block_request struct and connect it to
- * the request. This is needed that we not lose the SG list later on.
- *
- * Returns BLKPREP_OK on success or BLKPREP_DEFER on failure.
- */
-static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
-{
- struct i2o_block_device *i2o_blk_dev = q->queuedata;
- struct i2o_block_request *ireq;
-
- if (unlikely(!i2o_blk_dev)) {
- osm_err("block device already removed\n");
- return BLKPREP_KILL;
- }
-
- /* connect the i2o_block_request to the request */
- if (!req->special) {
- ireq = i2o_block_request_alloc();
- if (IS_ERR(ireq)) {
- osm_debug("unable to allocate i2o_block_request!\n");
- return BLKPREP_DEFER;
- }
-
- ireq->i2o_blk_dev = i2o_blk_dev;
- req->special = ireq;
- ireq->req = req;
- }
- /* do not come back here */
- req->cmd_flags |= REQ_DONTPREP;
-
- return BLKPREP_OK;
-};
-
-/**
- * i2o_block_delayed_request_fn - delayed request queue function
- * @work: the delayed request with the queue to start
- *
- * If the request queue is stopped for a disk, and there is no open
- * request, a new event is created, which calls this function to start
- * the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never
- * be started again.
- */
-static void i2o_block_delayed_request_fn(struct work_struct *work)
-{
- struct i2o_block_delayed_request *dreq =
- container_of(work, struct i2o_block_delayed_request,
- work.work);
- struct request_queue *q = dreq->queue;
- unsigned long flags;
-
- spin_lock_irqsave(q->queue_lock, flags);
- blk_start_queue(q);
- spin_unlock_irqrestore(q->queue_lock, flags);
- kfree(dreq);
-};
-
-/**
- * i2o_block_end_request - Post-processing of completed commands
- * @req: request which should be completed
- * @error: 0 for success, < 0 for error
- * @nr_bytes: number of bytes to complete
- *
- * Mark the request as complete. The lock must not be held when entering.
- *
- */
-static void i2o_block_end_request(struct request *req, int error,
- int nr_bytes)
-{
- struct i2o_block_request *ireq = req->special;
- struct i2o_block_device *dev = ireq->i2o_blk_dev;
- struct request_queue *q = req->q;
- unsigned long flags;
-
- if (blk_end_request(req, error, nr_bytes))
- if (error)
- blk_end_request_all(req, -EIO);
-
- spin_lock_irqsave(q->queue_lock, flags);
-
- if (likely(dev)) {
- dev->open_queue_depth--;
- list_del(&ireq->queue);
- }
-
- blk_start_queue(q);
-
- spin_unlock_irqrestore(q->queue_lock, flags);
-
- i2o_block_sglist_free(ireq);
- i2o_block_request_free(ireq);
-};
-
-/**
- * i2o_block_reply - Block OSM reply handler.
- * @c: I2O controller from which the message arrives
- * @m: message id of reply
- * @msg: the actual I2O message reply
- *
- * This function gets all the message replies.
- *
- */
-static int i2o_block_reply(struct i2o_controller *c, u32 m,
- struct i2o_message *msg)
-{
- struct request *req;
- int error = 0;
-
- req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
- if (unlikely(!req)) {
- osm_err("NULL reply received!\n");
- return -1;
- }
-
- /*
- * Lets see what is cooking. We stuffed the
- * request in the context.
- */
-
- if ((le32_to_cpu(msg->body[0]) >> 24) != 0) {
- u32 status = le32_to_cpu(msg->body[0]);
- /*
- * Device not ready means two things. One is that the
- * the thing went offline (but not a removal media)
- *
- * The second is that you have a SuperTrak 100 and the
- * firmware got constipated. Unlike standard i2o card
- * setups the supertrak returns an error rather than
- * blocking for the timeout in these cases.
- *
- * Don't stick a supertrak100 into cache aggressive modes
- */
-
- osm_err("TID %03x error status: 0x%02x, detailed status: "
- "0x%04x\n", (le32_to_cpu(msg->u.head[1]) >> 12 & 0xfff),
- status >> 24, status & 0xffff);
-
- req->errors++;
-
- error = -EIO;
- }
-
- i2o_block_end_request(req, error, le32_to_cpu(msg->body[1]));
-
- return 1;
-};
-
-static void i2o_block_event(struct work_struct *work)
-{
- struct i2o_event *evt = container_of(work, struct i2o_event, work);
- osm_debug("event received\n");
- kfree(evt);
-};
-
-/*
- * SCSI-CAM for ioctl geometry mapping
- * Duplicated with SCSI - this should be moved into somewhere common
- * perhaps genhd ?
- *
- * LBA -> CHS mapping table taken from:
- *
- * "Incorporating the I2O Architecture into BIOS for Intel Architecture
- * Platforms"
- *
- * This is an I2O document that is only available to I2O members,
- * not developers.
- *
- * From my understanding, this is how all the I2O cards do this
- *
- * Disk Size | Sectors | Heads | Cylinders
- * ---------------+---------+-------+-------------------
- * 1 < X <= 528M | 63 | 16 | X/(63 * 16 * 512)
- * 528M < X <= 1G | 63 | 32 | X/(63 * 32 * 512)
- * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512)
- * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512)
- *
- */
-#define BLOCK_SIZE_528M 1081344
-#define BLOCK_SIZE_1G 2097152
-#define BLOCK_SIZE_21G 4403200
-#define BLOCK_SIZE_42G 8806400
-#define BLOCK_SIZE_84G 17612800
-
-static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls,
- unsigned char *hds, unsigned char *secs)
-{
- unsigned long heads, sectors, cylinders;
-
- sectors = 63L; /* Maximize sectors per track */
- if (capacity <= BLOCK_SIZE_528M)
- heads = 16;
- else if (capacity <= BLOCK_SIZE_1G)
- heads = 32;
- else if (capacity <= BLOCK_SIZE_21G)
- heads = 64;
- else if (capacity <= BLOCK_SIZE_42G)
- heads = 128;
- else
- heads = 255;
-
- cylinders = (unsigned long)capacity / (heads * sectors);
-
- *cyls = (unsigned short)cylinders; /* Stuff return values */
- *secs = (unsigned char)sectors;
- *hds = (unsigned char)heads;
-}
-
-/**
- * i2o_block_open - Open the block device
- * @bdev: block device being opened
- * @mode: file open mode
- *
- * Power up the device, mount and lock the media. This function is called,
- * if the block device is opened for access.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_open(struct block_device *bdev, fmode_t mode)
-{
- struct i2o_block_device *dev = bdev->bd_disk->private_data;
-
- if (!dev->i2o_dev)
- return -ENODEV;
-
- mutex_lock(&i2o_block_mutex);
- if (dev->power > 0x1f)
- i2o_block_device_power(dev, 0x02);
-
- i2o_block_device_mount(dev->i2o_dev, -1);
-
- i2o_block_device_lock(dev->i2o_dev, -1);
-
- osm_debug("Ready.\n");
- mutex_unlock(&i2o_block_mutex);
-
- return 0;
-};
-
-/**
- * i2o_block_release - Release the I2O block device
- * @disk: gendisk device being released
- * @mode: file open mode
- *
- * Unlock and unmount the media, and power down the device. Gets called if
- * the block device is closed.
- */
-static void i2o_block_release(struct gendisk *disk, fmode_t mode)
-{
- struct i2o_block_device *dev = disk->private_data;
- u8 operation;
-
- /*
- * This is to deal with the case of an application
- * opening a device and then the device disappears while
- * it's in use, and then the application tries to release
- * it. ex: Unmounting a deleted RAID volume at reboot.
- * If we send messages, it will just cause FAILs since
- * the TID no longer exists.
- */
- if (!dev->i2o_dev)
- return;
-
- mutex_lock(&i2o_block_mutex);
- i2o_block_device_flush(dev->i2o_dev);
-
- i2o_block_device_unlock(dev->i2o_dev, -1);
-
- if (dev->flags & (1 << 3 | 1 << 4)) /* Removable */
- operation = 0x21;
- else
- operation = 0x24;
-
- i2o_block_device_power(dev, operation);
- mutex_unlock(&i2o_block_mutex);
-}
-
-static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo)
-{
- i2o_block_biosparam(get_capacity(bdev->bd_disk),
- &geo->cylinders, &geo->heads, &geo->sectors);
- return 0;
-}
-
-/**
- * i2o_block_ioctl - Issue device specific ioctl calls.
- * @bdev: block device being opened
- * @mode: file open mode
- * @cmd: ioctl command
- * @arg: arg
- *
- * Handles ioctl request for the block device.
- *
- * Return 0 on success or negative error on failure.
- */
-static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode,
- unsigned int cmd, unsigned long arg)
-{
- struct gendisk *disk = bdev->bd_disk;
- struct i2o_block_device *dev = disk->private_data;
- int ret = -ENOTTY;
-
- /* Anyone capable of this syscall can do *real bad* things */
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- mutex_lock(&i2o_block_mutex);
- switch (cmd) {
- case BLKI2OGRSTRAT:
- ret = put_user(dev->rcache, (int __user *)arg);
- break;
- case BLKI2OGWSTRAT:
- ret = put_user(dev->wcache, (int __user *)arg);
- break;
- case BLKI2OSRSTRAT:
- ret = -EINVAL;
- if (arg < 0 || arg > CACHE_SMARTFETCH)
- break;
- dev->rcache = arg;
- ret = 0;
- break;
- case BLKI2OSWSTRAT:
- ret = -EINVAL;
- if (arg != 0
- && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK))
- break;
- dev->wcache = arg;
- ret = 0;
- break;
- }
- mutex_unlock(&i2o_block_mutex);
-
- return ret;
-};
-
-/**
- * i2o_block_check_events - Have we seen a media change?
- * @disk: gendisk which should be verified
- * @clearing: events being cleared
- *
- * Verifies if the media has changed.
- *
- * Returns 1 if the media was changed or 0 otherwise.
- */
-static unsigned int i2o_block_check_events(struct gendisk *disk,
- unsigned int clearing)
-{
- struct i2o_block_device *p = disk->private_data;
-
- if (p->media_change_flag) {
- p->media_change_flag = 0;
- return DISK_EVENT_MEDIA_CHANGE;
- }
- return 0;
-}
-
-/**
- * i2o_block_transfer - Transfer a request to/from the I2O controller
- * @req: the request which should be transferred
- *
- * This function converts the request into a I2O message. The necessary
- * DMA buffers are allocated and after everything is setup post the message
- * to the I2O controller. No cleanup is done by this function. It is done
- * on the interrupt side when the reply arrives.
- *
- * Return 0 on success or negative error code on failure.
- */
-static int i2o_block_transfer(struct request *req)
-{
- struct i2o_block_device *dev = req->rq_disk->private_data;
- struct i2o_controller *c;
- u32 tid;
- struct i2o_message *msg;
- u32 *mptr;
- struct i2o_block_request *ireq = req->special;
- u32 tcntxt;
- u32 sgl_offset = SGL_OFFSET_8;
- u32 ctl_flags = 0x00000000;
- int rc;
- u32 cmd;
-
- if (unlikely(!dev->i2o_dev)) {
- osm_err("transfer to removed drive\n");
- rc = -ENODEV;
- goto exit;
- }
-
- tid = dev->i2o_dev->lct_data.tid;
- c = dev->i2o_dev->iop;
-
- msg = i2o_msg_get(c);
- if (IS_ERR(msg)) {
- rc = PTR_ERR(msg);
- goto exit;
- }
-
- tcntxt = i2o_cntxt_list_add(c, req);
- if (!tcntxt) {
- rc = -ENOMEM;
- goto nop_msg;
- }
-
- msg->u.s.icntxt = cpu_to_le32(i2o_block_driver.context);
- msg->u.s.tcntxt = cpu_to_le32(tcntxt);
-
- mptr = &msg->body[0];
-
- if (rq_data_dir(req) == READ) {
- cmd = I2O_CMD_BLOCK_READ << 24;
-
- switch (dev->rcache) {
- case CACHE_PREFETCH:
- ctl_flags = 0x201F0008;
- break;
-
- case CACHE_SMARTFETCH:
- if (blk_rq_sectors(req) > 16)
- ctl_flags = 0x201F0008;
- else
- ctl_flags = 0x001F0000;
- break;
-
- default:
- break;
- }
- } else {
- cmd = I2O_CMD_BLOCK_WRITE << 24;
-
- switch (dev->wcache) {
- case CACHE_WRITETHROUGH:
- ctl_flags = 0x001F0008;
- break;
- case CACHE_WRITEBACK:
- ctl_flags = 0x001F0010;
- break;
- case CACHE_SMARTBACK:
- if (blk_rq_sectors(req) > 16)
- ctl_flags = 0x001F0004;
- else
- ctl_flags = 0x001F0010;
- break;
- case CACHE_SMARTTHROUGH:
- if (blk_rq_sectors(req) > 16)
- ctl_flags = 0x001F0004;
- else
- ctl_flags = 0x001F0010;
- default:
- break;
- }
- }
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC
- if (c->adaptec) {
- u8 cmd[10];
- u32 scsi_flags;
- u16 hwsec;
-
- hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT;
- memset(cmd, 0, 10);
-
- sgl_offset = SGL_OFFSET_12;
-
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_PRIVATE << 24 | HOST_TID << 12 | tid);
-
- *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
- *mptr++ = cpu_to_le32(tid);
-
- /*
- * ENABLE_DISCONNECT
- * SIMPLE_TAG
- * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
- */
- if (rq_data_dir(req) == READ) {
- cmd[0] = READ_10;
- scsi_flags = 0x60a0000a;
- } else {
- cmd[0] = WRITE_10;
- scsi_flags = 0xa0a0000a;
- }
-
- *mptr++ = cpu_to_le32(scsi_flags);
-
- *((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec);
- *((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec);
-
- memcpy(mptr, cmd, 10);
- mptr += 4;
- *mptr++ = cpu_to_le32(blk_rq_bytes(req));
- } else
-#endif
- {
- msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
- *mptr++ = cpu_to_le32(ctl_flags);
- *mptr++ = cpu_to_le32(blk_rq_bytes(req));
- *mptr++ =
- cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT));
- *mptr++ =
- cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT));
- }
-
- if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
- rc = -ENOMEM;
- goto context_remove;
- }
-
- msg->u.head[0] =
- cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
-
- list_add_tail(&ireq->queue, &dev->open_queue);
- dev->open_queue_depth++;
-
- i2o_msg_post(c, msg);
-
- return 0;
-
- context_remove:
- i2o_cntxt_list_remove(c, req);
-
- nop_msg:
- i2o_msg_nop(c, msg);
-
- exit:
- return rc;
-};
-
-/**
- * i2o_block_request_fn - request queue handling function
- * @q: request queue from which the request could be fetched
- *
- * Takes the next request from the queue, transfers it and if no error
- * occurs dequeue it from the queue. On arrival of the reply the message
- * will be processed further. If an error occurs requeue the request.
- */
-static void i2o_block_request_fn(struct request_queue *q)
-{
- struct request *req;
-
- while ((req = blk_peek_request(q)) != NULL) {
- if (req->cmd_type == REQ_TYPE_FS) {
- struct i2o_block_delayed_request *dreq;
- struct i2o_block_request *ireq = req->special;
- unsigned int queue_depth;
-
- queue_depth = ireq->i2o_blk_dev->open_queue_depth;
-
- if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
- if (!i2o_block_transfer(req)) {
- blk_start_request(req);
- continue;
- } else
- osm_info("transfer error\n");
- }
-
- if (queue_depth)
- break;
-
- /* stop the queue and retry later */
- dreq = kmalloc(sizeof(*dreq), GFP_ATOMIC);
- if (!dreq)
- continue;
-
- dreq->queue = q;
- INIT_DELAYED_WORK(&dreq->work,
- i2o_block_delayed_request_fn);
-
- if (!queue_delayed_work(i2o_block_driver.event_queue,
- &dreq->work,
- I2O_BLOCK_RETRY_TIME))
- kfree(dreq);
- else {
- blk_stop_queue(q);
- break;
- }
- } else {
- blk_start_request(req);
- __blk_end_request_all(req, -EIO);
- }
- }
-};
-
-/* I2O Block device operations definition */
-static const struct block_device_operations i2o_block_fops = {
- .owner = THIS_MODULE,
- .open = i2o_block_open,
- .release = i2o_block_release,
- .ioctl = i2o_block_ioctl,
- .compat_ioctl = i2o_block_ioctl,
- .getgeo = i2o_block_getgeo,
- .check_events = i2o_block_check_events,
-};
-
-/**
- * i2o_block_device_alloc - Allocate memory for a I2O Block device
- *
- * Allocate memory for the i2o_block_device struct, gendisk and request
- * queue and initialize them as far as no additional information is needed.
- *
- * Returns a pointer to the allocated I2O Block device on success or a
- * negative error code on failure.
- */
-static struct i2o_block_device *i2o_block_device_alloc(void)
-{
- struct i2o_block_device *dev;
- struct gendisk *gd;
- struct request_queue *queue;
- int rc;
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- osm_err("Insufficient memory to allocate I2O Block disk.\n");
- rc = -ENOMEM;
- goto exit;
- }
-
- INIT_LIST_HEAD(&dev->open_queue);
- spin_lock_init(&dev->lock);
- dev->rcache = CACHE_PREFETCH;
- dev->wcache = CACHE_WRITEBACK;
-
- /* allocate a gendisk with 16 partitions */
- gd = alloc_disk(16);
- if (!gd) {
- osm_err("Insufficient memory to allocate gendisk.\n");
- rc = -ENOMEM;
- goto cleanup_dev;
- }
-
- /* initialize the request queue */
- queue = blk_init_queue(i2o_block_request_fn, &dev->lock);
- if (!queue) {
- osm_err("Insufficient memory to allocate request queue.\n");
- rc = -ENOMEM;
- goto cleanup_queue;
- }
-
- blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
-
- gd->major = I2O_MAJOR;
- gd->queue = queue;
- gd->fops = &i2o_block_fops;
- gd->private_data = dev;
-
- dev->gd = gd;
-
- return dev;
-
- cleanup_queue:
- put_disk(gd);
-
- cleanup_dev:
- kfree(dev);
-
- exit:
- return ERR_PTR(rc);
-};
-
-/**
- * i2o_block_probe - verify if dev is a I2O Block device and install it
- * @dev: device to verify if it is a I2O Block device
- *
- * We only verify if the user_tid of the device is 0xfff and then install
- * the device. Otherwise it is used by some other device (e. g. RAID).
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_block_probe(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_controller *c = i2o_dev->iop;
- struct i2o_block_device *i2o_blk_dev;
- struct gendisk *gd;
- struct request_queue *queue;
- static int unit = 0;
- int rc;
- u64 size;
- u32 blocksize;
- u16 body_size = 4;
- u16 power;
- unsigned short max_sectors;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC
- if (c->adaptec)
- body_size = 8;
-#endif
-
- if (c->limit_sectors)
- max_sectors = I2O_MAX_SECTORS_LIMITED;
- else
- max_sectors = I2O_MAX_SECTORS;
-
- /* skip devices which are used by IOP */
- if (i2o_dev->lct_data.user_tid != 0xfff) {
- osm_debug("skipping used device %03x\n", i2o_dev->lct_data.tid);
- return -ENODEV;
- }
-
- if (i2o_device_claim(i2o_dev)) {
- osm_warn("Unable to claim device. Installation aborted\n");
- rc = -EFAULT;
- goto exit;
- }
-
- i2o_blk_dev = i2o_block_device_alloc();
- if (IS_ERR(i2o_blk_dev)) {
- osm_err("could not alloc a new I2O block device");
- rc = PTR_ERR(i2o_blk_dev);
- goto claim_release;
- }
-
- i2o_blk_dev->i2o_dev = i2o_dev;
- dev_set_drvdata(dev, i2o_blk_dev);
-
- /* setup gendisk */
- gd = i2o_blk_dev->gd;
- gd->first_minor = unit << 4;
- sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit);
- gd->driverfs_dev = &i2o_dev->device;
-
- /* setup request queue */
- queue = gd->queue;
- queue->queuedata = i2o_blk_dev;
-
- blk_queue_max_hw_sectors(queue, max_sectors);
- blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size));
-
- osm_debug("max sectors = %d\n", queue->max_sectors);
- osm_debug("phys segments = %d\n", queue->max_phys_segments);
- osm_debug("max hw segments = %d\n", queue->max_hw_segments);
-
- /*
- * Ask for the current media data. If that isn't supported
- * then we ask for the device capacity data
- */
- if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
- !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
- blk_queue_logical_block_size(queue, le32_to_cpu(blocksize));
- } else
- osm_warn("unable to get blocksize of %s\n", gd->disk_name);
-
- if (!i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) ||
- !i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8)) {
- set_capacity(gd, le64_to_cpu(size) >> KERNEL_SECTOR_SHIFT);
- } else
- osm_warn("could not get size of %s\n", gd->disk_name);
-
- if (!i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2))
- i2o_blk_dev->power = power;
-
- i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff);
-
- add_disk(gd);
-
- unit++;
-
- osm_info("device added (TID: %03x): %s\n", i2o_dev->lct_data.tid,
- i2o_blk_dev->gd->disk_name);
-
- return 0;
-
- claim_release:
- i2o_device_claim_release(i2o_dev);
-
- exit:
- return rc;
-};
-
-/* Block OSM driver struct */
-static struct i2o_driver i2o_block_driver = {
- .name = OSM_NAME,
- .event = i2o_block_event,
- .reply = i2o_block_reply,
- .classes = i2o_block_class_id,
- .driver = {
- .probe = i2o_block_probe,
- .remove = i2o_block_remove,
- },
-};
-
-/**
- * i2o_block_init - Block OSM initialization function
- *
- * Allocate the slab and mempool for request structs, registers i2o_block
- * block device and finally register the Block OSM in the I2O core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_block_init(void)
-{
- int rc;
- int size;
-
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
- /* Allocate request mempool and slab */
- size = sizeof(struct i2o_block_request);
- i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
- SLAB_HWCACHE_ALIGN, NULL);
- if (!i2o_blk_req_pool.slab) {
- osm_err("can't init request slab\n");
- rc = -ENOMEM;
- goto exit;
- }
-
- i2o_blk_req_pool.pool =
- mempool_create_slab_pool(I2O_BLOCK_REQ_MEMPOOL_SIZE,
- i2o_blk_req_pool.slab);
- if (!i2o_blk_req_pool.pool) {
- osm_err("can't init request mempool\n");
- rc = -ENOMEM;
- goto free_slab;
- }
-
- /* Register the block device interfaces */
- rc = register_blkdev(I2O_MAJOR, "i2o_block");
- if (rc) {
- osm_err("unable to register block device\n");
- goto free_mempool;
- }
-#ifdef MODULE
- osm_info("registered device at major %d\n", I2O_MAJOR);
-#endif
-
- /* Register Block OSM into I2O core */
- rc = i2o_driver_register(&i2o_block_driver);
- if (rc) {
- osm_err("Could not register Block driver\n");
- goto unregister_blkdev;
- }
-
- return 0;
-
- unregister_blkdev:
- unregister_blkdev(I2O_MAJOR, "i2o_block");
-
- free_mempool:
- mempool_destroy(i2o_blk_req_pool.pool);
-
- free_slab:
- kmem_cache_destroy(i2o_blk_req_pool.slab);
-
- exit:
- return rc;
-};
-
-/**
- * i2o_block_exit - Block OSM exit function
- *
- * Unregisters Block OSM from I2O core, unregisters i2o_block block device
- * and frees the mempool and slab.
- */
-static void __exit i2o_block_exit(void)
-{
- /* Unregister I2O Block OSM from I2O core */
- i2o_driver_unregister(&i2o_block_driver);
-
- /* Unregister block device */
- unregister_blkdev(I2O_MAJOR, "i2o_block");
-
- /* Free request mempool and slab */
- mempool_destroy(i2o_blk_req_pool.pool);
- kmem_cache_destroy(i2o_blk_req_pool.slab);
-};
-
-MODULE_AUTHOR("Red Hat");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_block_init);
-module_exit(i2o_block_exit);
diff --git a/drivers/message/i2o/i2o_proc.c b/drivers/message/i2o/i2o_proc.c
deleted file mode 100644
index b7d87cd227a9..000000000000
--- a/drivers/message/i2o/i2o_proc.c
+++ /dev/null
@@ -1,2045 +0,0 @@
-/*
- * procfs handler for Linux I2O subsystem
- *
- * (c) Copyright 1999 Deepak Saxena
- *
- * Originally written by Deepak Saxena(deepak@plexity.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 is an initial test release. The code is based on the design of the
- * ide procfs system (drivers/block/ide-proc.c). Some code taken from
- * i2o-core module by Alan Cox.
- *
- * DISCLAIMER: This code is still under development/test and may cause
- * your system to behave unpredictably. Use at your own discretion.
- *
- *
- * Fixes/additions:
- * Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
- * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
- * University of Helsinki, Department of Computer Science
- * LAN entries
- * Markus Lidel <Markus.Lidel@shadowconnect.com>
- * Changes for new I2O API
- */
-
-#define OSM_NAME "proc-osm"
-#define OSM_VERSION "1.316"
-#define OSM_DESCRIPTION "I2O ProcFS OSM"
-
-#define I2O_MAX_MODULES 4
-// FIXME!
-#define FMT_U64_HEX "0x%08x%08x"
-#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
-
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/pci.h>
-#include <linux/i2o.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/seq_file.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/spinlock.h>
-#include <linux/workqueue.h>
-
-#include <asm/io.h>
-#include <asm/uaccess.h>
-#include <asm/byteorder.h>
-
-/* Structure used to define /proc entries */
-typedef struct _i2o_proc_entry_t {
- char *name; /* entry name */
- umode_t mode; /* mode */
- const struct file_operations *fops; /* open function */
-} i2o_proc_entry;
-
-/* global I2O /proc/i2o entry */
-static struct proc_dir_entry *i2o_proc_dir_root;
-
-/* proc OSM driver struct */
-static struct i2o_driver i2o_proc_driver = {
- .name = OSM_NAME,
-};
-
-static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
-{
- int i;
-
- /* 19990419 -sralston
- * The I2O v1.5 (and v2.0 so far) "official specification"
- * got serial numbers WRONG!
- * Apparently, and despite what Section 3.4.4 says and
- * Figure 3-35 shows (pg 3-39 in the pdf doc),
- * the convention / consensus seems to be:
- * + First byte is SNFormat
- * + Second byte is SNLen (but only if SNFormat==7 (?))
- * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
- */
- switch (serialno[0]) {
- case I2O_SNFORMAT_BINARY: /* Binary */
- seq_printf(seq, "0x");
- for (i = 0; i < serialno[1]; i++) {
- seq_printf(seq, "%02X", serialno[2 + i]);
- }
- break;
-
- case I2O_SNFORMAT_ASCII: /* ASCII */
- if (serialno[1] < ' ') { /* printable or SNLen? */
- /* sanity */
- max_len =
- (max_len < serialno[1]) ? max_len : serialno[1];
- serialno[1 + max_len] = '\0';
-
- /* just print it */
- seq_printf(seq, "%s", &serialno[2]);
- } else {
- /* print chars for specified length */
- for (i = 0; i < serialno[1]; i++) {
- seq_printf(seq, "%c", serialno[2 + i]);
- }
- }
- break;
-
- case I2O_SNFORMAT_UNICODE: /* UNICODE */
- seq_printf(seq, "UNICODE Format. Can't Display\n");
- break;
-
- case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */
- seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
- break;
-
- case I2O_SNFORMAT_WAN: /* WAN MAC Address */
- /* FIXME: Figure out what a WAN access address looks like?? */
- seq_printf(seq, "WAN Access Address");
- break;
-
-/* plus new in v2.0 */
- case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */
- /* FIXME: Figure out what a LAN-64 address really looks like?? */
- seq_printf(seq,
- "LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
- serialno[8], serialno[9], &serialno[2]);
- break;
-
- case I2O_SNFORMAT_DDM: /* I2O DDM */
- seq_printf(seq,
- "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
- *(u16 *) & serialno[2],
- *(u16 *) & serialno[4], *(u16 *) & serialno[6]);
- break;
-
- case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */
- case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */
- /* FIXME: Figure if this is even close?? */
- seq_printf(seq,
- "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
- *(u32 *) & serialno[2],
- *(u32 *) & serialno[6],
- *(u32 *) & serialno[10], *(u32 *) & serialno[14]);
- break;
-
- case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */
- case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */
- default:
- seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]);
- break;
- }
-
- return 0;
-}
-
-/**
- * i2o_get_class_name - do i2o class name lookup
- * @class: class number
- *
- * Return a descriptive string for an i2o class.
- */
-static const char *i2o_get_class_name(int class)
-{
- int idx = 16;
- static char *i2o_class_name[] = {
- "Executive",
- "Device Driver Module",
- "Block Device",
- "Tape Device",
- "LAN Interface",
- "WAN Interface",
- "Fibre Channel Port",
- "Fibre Channel Device",
- "SCSI Device",
- "ATE Port",
- "ATE Device",
- "Floppy Controller",
- "Floppy Device",
- "Secondary Bus Port",
- "Peer Transport Agent",
- "Peer Transport",
- "Unknown"
- };
-
- switch (class & 0xfff) {
- case I2O_CLASS_EXECUTIVE:
- idx = 0;
- break;
- case I2O_CLASS_DDM:
- idx = 1;
- break;
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- idx = 2;
- break;
- case I2O_CLASS_SEQUENTIAL_STORAGE:
- idx = 3;
- break;
- case I2O_CLASS_LAN:
- idx = 4;
- break;
- case I2O_CLASS_WAN:
- idx = 5;
- break;
- case I2O_CLASS_FIBRE_CHANNEL_PORT:
- idx = 6;
- break;
- case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
- idx = 7;
- break;
- case I2O_CLASS_SCSI_PERIPHERAL:
- idx = 8;
- break;
- case I2O_CLASS_ATE_PORT:
- idx = 9;
- break;
- case I2O_CLASS_ATE_PERIPHERAL:
- idx = 10;
- break;
- case I2O_CLASS_FLOPPY_CONTROLLER:
- idx = 11;
- break;
- case I2O_CLASS_FLOPPY_DEVICE:
- idx = 12;
- break;
- case I2O_CLASS_BUS_ADAPTER:
- idx = 13;
- break;
- case I2O_CLASS_PEER_TRANSPORT_AGENT:
- idx = 14;
- break;
- case I2O_CLASS_PEER_TRANSPORT:
- idx = 15;
- break;
- }
-
- return i2o_class_name[idx];
-}
-
-#define SCSI_TABLE_SIZE 13
-static char *scsi_devices[] = {
- "Direct-Access Read/Write",
- "Sequential-Access Storage",
- "Printer",
- "Processor",
- "WORM Device",
- "CD-ROM Device",
- "Scanner Device",
- "Optical Memory Device",
- "Medium Changer Device",
- "Communications Device",
- "Graphics Art Pre-Press Device",
- "Graphics Art Pre-Press Device",
- "Array Controller Device"
-};
-
-static char *chtostr(char *tmp, u8 *chars, int n)
-{
- tmp[0] = 0;
- return strncat(tmp, (char *)chars, n);
-}
-
-static int i2o_report_query_status(struct seq_file *seq, int block_status,
- char *group)
-{
- switch (block_status) {
- case -ETIMEDOUT:
- return seq_printf(seq, "Timeout reading group %s.\n", group);
- case -ENOMEM:
- return seq_printf(seq, "No free memory to read the table.\n");
- case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
- return seq_printf(seq, "Group %s not supported.\n", group);
- default:
- return seq_printf(seq,
- "Error reading group %s. BlockStatus 0x%02X\n",
- group, -block_status);
- }
-}
-
-static char *bus_strings[] = {
- "Local Bus",
- "ISA",
- "EISA",
- "PCI",
- "PCMCIA",
- "NUBUS",
- "CARDBUS"
-};
-
-static int i2o_seq_show_hrt(struct seq_file *seq, void *v)
-{
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt;
- u32 bus;
- int i;
-
- if (hrt->hrt_version) {
- seq_printf(seq,
- "HRT table for controller is too new a version.\n");
- return 0;
- }
-
- seq_printf(seq, "HRT has %d entries of %d bytes each.\n",
- hrt->num_entries, hrt->entry_len << 2);
-
- for (i = 0; i < hrt->num_entries; i++) {
- seq_printf(seq, "Entry %d:\n", i);
- seq_printf(seq, " Adapter ID: %0#10x\n",
- hrt->hrt_entry[i].adapter_id);
- seq_printf(seq, " Controlling tid: %0#6x\n",
- hrt->hrt_entry[i].parent_tid);
-
- if (hrt->hrt_entry[i].bus_type != 0x80) {
- bus = hrt->hrt_entry[i].bus_type;
- seq_printf(seq, " %s Information\n",
- bus_strings[bus]);
-
- switch (bus) {
- case I2O_BUS_LOCAL:
- seq_printf(seq, " IOBase: %0#6x,",
- hrt->hrt_entry[i].bus.local_bus.
- LbBaseIOPort);
- seq_printf(seq, " MemoryBase: %0#10x\n",
- hrt->hrt_entry[i].bus.local_bus.
- LbBaseMemoryAddress);
- break;
-
- case I2O_BUS_ISA:
- seq_printf(seq, " IOBase: %0#6x,",
- hrt->hrt_entry[i].bus.isa_bus.
- IsaBaseIOPort);
- seq_printf(seq, " MemoryBase: %0#10x,",
- hrt->hrt_entry[i].bus.isa_bus.
- IsaBaseMemoryAddress);
- seq_printf(seq, " CSN: %0#4x,",
- hrt->hrt_entry[i].bus.isa_bus.CSN);
- break;
-
- case I2O_BUS_EISA:
- seq_printf(seq, " IOBase: %0#6x,",
- hrt->hrt_entry[i].bus.eisa_bus.
- EisaBaseIOPort);
- seq_printf(seq, " MemoryBase: %0#10x,",
- hrt->hrt_entry[i].bus.eisa_bus.
- EisaBaseMemoryAddress);
- seq_printf(seq, " Slot: %0#4x,",
- hrt->hrt_entry[i].bus.eisa_bus.
- EisaSlotNumber);
- break;
-
- case I2O_BUS_PCI:
- seq_printf(seq, " Bus: %0#4x",
- hrt->hrt_entry[i].bus.pci_bus.
- PciBusNumber);
- seq_printf(seq, " Dev: %0#4x",
- hrt->hrt_entry[i].bus.pci_bus.
- PciDeviceNumber);
- seq_printf(seq, " Func: %0#4x",
- hrt->hrt_entry[i].bus.pci_bus.
- PciFunctionNumber);
- seq_printf(seq, " Vendor: %0#6x",
- hrt->hrt_entry[i].bus.pci_bus.
- PciVendorID);
- seq_printf(seq, " Device: %0#6x\n",
- hrt->hrt_entry[i].bus.pci_bus.
- PciDeviceID);
- break;
-
- default:
- seq_printf(seq, " Unsupported Bus Type\n");
- }
- } else
- seq_printf(seq, " Unknown Bus Type\n");
- }
-
- return 0;
-}
-
-static int i2o_seq_show_lct(struct seq_file *seq, void *v)
-{
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- i2o_lct *lct = (i2o_lct *) c->lct;
- int entries;
- int i;
-
-#define BUS_TABLE_SIZE 3
- static char *bus_ports[] = {
- "Generic Bus",
- "SCSI Bus",
- "Fibre Channel Bus"
- };
-
- entries = (lct->table_size - 3) / 9;
-
- seq_printf(seq, "LCT contains %d %s\n", entries,
- entries == 1 ? "entry" : "entries");
- if (lct->boot_tid)
- seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid);
-
- seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind);
-
- for (i = 0; i < entries; i++) {
- seq_printf(seq, "Entry %d\n", i);
- seq_printf(seq, " Class, SubClass : %s",
- i2o_get_class_name(lct->lct_entry[i].class_id));
-
- /*
- * Classes which we'll print subclass info for
- */
- switch (lct->lct_entry[i].class_id & 0xFFF) {
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- switch (lct->lct_entry[i].sub_class) {
- case 0x00:
- seq_printf(seq, ", Direct-Access Read/Write");
- break;
-
- case 0x04:
- seq_printf(seq, ", WORM Drive");
- break;
-
- case 0x05:
- seq_printf(seq, ", CD-ROM Drive");
- break;
-
- case 0x07:
- seq_printf(seq, ", Optical Memory Device");
- break;
-
- default:
- seq_printf(seq, ", Unknown (0x%02x)",
- lct->lct_entry[i].sub_class);
- break;
- }
- break;
-
- case I2O_CLASS_LAN:
- switch (lct->lct_entry[i].sub_class & 0xFF) {
- case 0x30:
- seq_printf(seq, ", Ethernet");
- break;
-
- case 0x40:
- seq_printf(seq, ", 100base VG");
- break;
-
- case 0x50:
- seq_printf(seq, ", IEEE 802.5/Token-Ring");
- break;
-
- case 0x60:
- seq_printf(seq, ", ANSI X3T9.5 FDDI");
- break;
-
- case 0x70:
- seq_printf(seq, ", Fibre Channel");
- break;
-
- default:
- seq_printf(seq, ", Unknown Sub-Class (0x%02x)",
- lct->lct_entry[i].sub_class & 0xFF);
- break;
- }
- break;
-
- case I2O_CLASS_SCSI_PERIPHERAL:
- if (lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
- seq_printf(seq, ", %s",
- scsi_devices[lct->lct_entry[i].
- sub_class]);
- else
- seq_printf(seq, ", Unknown Device Type");
- break;
-
- case I2O_CLASS_BUS_ADAPTER:
- if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
- seq_printf(seq, ", %s",
- bus_ports[lct->lct_entry[i].
- sub_class]);
- else
- seq_printf(seq, ", Unknown Bus Type");
- break;
- }
- seq_printf(seq, "\n");
-
- seq_printf(seq, " Local TID : 0x%03x\n",
- lct->lct_entry[i].tid);
- seq_printf(seq, " User TID : 0x%03x\n",
- lct->lct_entry[i].user_tid);
- seq_printf(seq, " Parent TID : 0x%03x\n",
- lct->lct_entry[i].parent_tid);
- seq_printf(seq, " Identity Tag : 0x%x%x%x%x%x%x%x%x\n",
- lct->lct_entry[i].identity_tag[0],
- lct->lct_entry[i].identity_tag[1],
- lct->lct_entry[i].identity_tag[2],
- lct->lct_entry[i].identity_tag[3],
- lct->lct_entry[i].identity_tag[4],
- lct->lct_entry[i].identity_tag[5],
- lct->lct_entry[i].identity_tag[6],
- lct->lct_entry[i].identity_tag[7]);
- seq_printf(seq, " Change Indicator : %0#10x\n",
- lct->lct_entry[i].change_ind);
- seq_printf(seq, " Event Capab Mask : %0#10x\n",
- lct->lct_entry[i].device_flags);
- }
-
- return 0;
-}
-
-static int i2o_seq_show_status(struct seq_file *seq, void *v)
-{
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- char prodstr[25];
- int version;
- i2o_status_block *sb = c->status_block.virt;
-
- i2o_status_get(c); // reread the status block
-
- seq_printf(seq, "Organization ID : %0#6x\n", sb->org_id);
-
- version = sb->i2o_version;
-
-/* FIXME for Spec 2.0
- if (version == 0x02) {
- seq_printf(seq, "Lowest I2O version supported: ");
- switch(workspace[2]) {
- case 0x00:
- seq_printf(seq, "1.0\n");
- break;
- case 0x01:
- seq_printf(seq, "1.5\n");
- break;
- case 0x02:
- seq_printf(seq, "2.0\n");
- break;
- }
-
- seq_printf(seq, "Highest I2O version supported: ");
- switch(workspace[3]) {
- case 0x00:
- seq_printf(seq, "1.0\n");
- break;
- case 0x01:
- seq_printf(seq, "1.5\n");
- break;
- case 0x02:
- seq_printf(seq, "2.0\n");
- break;
- }
- }
-*/
- seq_printf(seq, "IOP ID : %0#5x\n", sb->iop_id);
- seq_printf(seq, "Host Unit ID : %0#6x\n", sb->host_unit_id);
- seq_printf(seq, "Segment Number : %0#5x\n", sb->segment_number);
-
- seq_printf(seq, "I2O version : ");
- switch (version) {
- case 0x00:
- seq_printf(seq, "1.0\n");
- break;
- case 0x01:
- seq_printf(seq, "1.5\n");
- break;
- case 0x02:
- seq_printf(seq, "2.0\n");
- break;
- default:
- seq_printf(seq, "Unknown version\n");
- }
-
- seq_printf(seq, "IOP State : ");
- switch (sb->iop_state) {
- case 0x01:
- seq_printf(seq, "INIT\n");
- break;
-
- case 0x02:
- seq_printf(seq, "RESET\n");
- break;
-
- case 0x04:
- seq_printf(seq, "HOLD\n");
- break;
-
- case 0x05:
- seq_printf(seq, "READY\n");
- break;
-
- case 0x08:
- seq_printf(seq, "OPERATIONAL\n");
- break;
-
- case 0x10:
- seq_printf(seq, "FAILED\n");
- break;
-
- case 0x11:
- seq_printf(seq, "FAULTED\n");
- break;
-
- default:
- seq_printf(seq, "Unknown\n");
- break;
- }
-
- seq_printf(seq, "Messenger Type : ");
- switch (sb->msg_type) {
- case 0x00:
- seq_printf(seq, "Memory mapped\n");
- break;
- case 0x01:
- seq_printf(seq, "Memory mapped only\n");
- break;
- case 0x02:
- seq_printf(seq, "Remote only\n");
- break;
- case 0x03:
- seq_printf(seq, "Memory mapped and remote\n");
- break;
- default:
- seq_printf(seq, "Unknown\n");
- }
-
- seq_printf(seq, "Inbound Frame Size : %d bytes\n",
- sb->inbound_frame_size << 2);
- seq_printf(seq, "Max Inbound Frames : %d\n",
- sb->max_inbound_frames);
- seq_printf(seq, "Current Inbound Frames : %d\n",
- sb->cur_inbound_frames);
- seq_printf(seq, "Max Outbound Frames : %d\n",
- sb->max_outbound_frames);
-
- /* Spec doesn't say if NULL terminated or not... */
- memcpy(prodstr, sb->product_id, 24);
- prodstr[24] = '\0';
- seq_printf(seq, "Product ID : %s\n", prodstr);
- seq_printf(seq, "Expected LCT Size : %d bytes\n",
- sb->expected_lct_size);
-
- seq_printf(seq, "IOP Capabilities\n");
- seq_printf(seq, " Context Field Size Support : ");
- switch (sb->iop_capabilities & 0x0000003) {
- case 0:
- seq_printf(seq, "Supports only 32-bit context fields\n");
- break;
- case 1:
- seq_printf(seq, "Supports only 64-bit context fields\n");
- break;
- case 2:
- seq_printf(seq, "Supports 32-bit and 64-bit context fields, "
- "but not concurrently\n");
- break;
- case 3:
- seq_printf(seq, "Supports 32-bit and 64-bit context fields "
- "concurrently\n");
- break;
- default:
- seq_printf(seq, "0x%08x\n", sb->iop_capabilities);
- }
- seq_printf(seq, " Current Context Field Size : ");
- switch (sb->iop_capabilities & 0x0000000C) {
- case 0:
- seq_printf(seq, "not configured\n");
- break;
- case 4:
- seq_printf(seq, "Supports only 32-bit context fields\n");
- break;
- case 8:
- seq_printf(seq, "Supports only 64-bit context fields\n");
- break;
- case 12:
- seq_printf(seq, "Supports both 32-bit or 64-bit context fields "
- "concurrently\n");
- break;
- default:
- seq_printf(seq, "\n");
- }
- seq_printf(seq, " Inbound Peer Support : %s\n",
- (sb->
- iop_capabilities & 0x00000010) ? "Supported" :
- "Not supported");
- seq_printf(seq, " Outbound Peer Support : %s\n",
- (sb->
- iop_capabilities & 0x00000020) ? "Supported" :
- "Not supported");
- seq_printf(seq, " Peer to Peer Support : %s\n",
- (sb->
- iop_capabilities & 0x00000040) ? "Supported" :
- "Not supported");
-
- seq_printf(seq, "Desired private memory size : %d kB\n",
- sb->desired_mem_size >> 10);
- seq_printf(seq, "Allocated private memory size : %d kB\n",
- sb->current_mem_size >> 10);
- seq_printf(seq, "Private memory base address : %0#10x\n",
- sb->current_mem_base);
- seq_printf(seq, "Desired private I/O size : %d kB\n",
- sb->desired_io_size >> 10);
- seq_printf(seq, "Allocated private I/O size : %d kB\n",
- sb->current_io_size >> 10);
- seq_printf(seq, "Private I/O base address : %0#10x\n",
- sb->current_io_base);
-
- return 0;
-}
-
-static int i2o_seq_show_hw(struct seq_file *seq, void *v)
-{
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- static u32 work32[5];
- static u8 *work8 = (u8 *) work32;
- static u16 *work16 = (u16 *) work32;
- int token;
- u32 hwcap;
-
- static char *cpu_table[] = {
- "Intel 80960 series",
- "AMD2900 series",
- "Motorola 68000 series",
- "ARM series",
- "MIPS series",
- "Sparc series",
- "PowerPC series",
- "Intel x86 series"
- };
-
- token =
- i2o_parm_field_get(c->exec, 0x0000, -1, &work32, sizeof(work32));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0x0000 IOP Hardware");
- return 0;
- }
-
- seq_printf(seq, "I2O Vendor ID : %0#6x\n", work16[0]);
- seq_printf(seq, "Product ID : %0#6x\n", work16[1]);
- seq_printf(seq, "CPU : ");
- if (work8[16] > 8)
- seq_printf(seq, "Unknown\n");
- else
- seq_printf(seq, "%s\n", cpu_table[work8[16]]);
- /* Anyone using ProcessorVersion? */
-
- seq_printf(seq, "RAM : %dkB\n", work32[1] >> 10);
- seq_printf(seq, "Non-Volatile Mem : %dkB\n", work32[2] >> 10);
-
- hwcap = work32[3];
- seq_printf(seq, "Capabilities : 0x%08x\n", hwcap);
- seq_printf(seq, " [%s] Self booting\n",
- (hwcap & 0x00000001) ? "+" : "-");
- seq_printf(seq, " [%s] Upgradable IRTOS\n",
- (hwcap & 0x00000002) ? "+" : "-");
- seq_printf(seq, " [%s] Supports downloading DDMs\n",
- (hwcap & 0x00000004) ? "+" : "-");
- seq_printf(seq, " [%s] Supports installing DDMs\n",
- (hwcap & 0x00000008) ? "+" : "-");
- seq_printf(seq, " [%s] Battery-backed RAM\n",
- (hwcap & 0x00000010) ? "+" : "-");
-
- return 0;
-}
-
-/* Executive group 0003h - Executing DDM List (table) */
-static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v)
-{
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- int token;
- int i;
-
- typedef struct _i2o_exec_execute_ddm_table {
- u16 ddm_tid;
- u8 module_type;
- u8 reserved;
- u16 i2o_vendor_id;
- u16 module_id;
- u8 module_name_version[28];
- u32 data_size;
- u32 code_size;
- } i2o_exec_execute_ddm_table;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- i2o_exec_execute_ddm_table ddm_table[I2O_MAX_MODULES];
- } *result;
-
- i2o_exec_execute_ddm_table ddm_table;
- char tmp[28 + 1];
-
- result = kmalloc(sizeof(*result), GFP_KERNEL);
- if (!result)
- return -ENOMEM;
-
- token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0003, -1,
- NULL, 0, result, sizeof(*result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0x0003 Executing DDM List");
- goto out;
- }
-
- seq_printf(seq,
- "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n");
- ddm_table = result->ddm_table[0];
-
- for (i = 0; i < result->row_count; ddm_table = result->ddm_table[++i]) {
- seq_printf(seq, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
-
- switch (ddm_table.module_type) {
- case 0x01:
- seq_printf(seq, "Downloaded DDM ");
- break;
- case 0x22:
- seq_printf(seq, "Embedded DDM ");
- break;
- default:
- seq_printf(seq, " ");
- }
-
- seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id);
- seq_printf(seq, "%-#8x", ddm_table.module_id);
- seq_printf(seq, "%-29s",
- chtostr(tmp, ddm_table.module_name_version, 28));
- seq_printf(seq, "%9d ", ddm_table.data_size);
- seq_printf(seq, "%8d", ddm_table.code_size);
-
- seq_printf(seq, "\n");
- }
- out:
- kfree(result);
- return 0;
-}
-
-/* Executive group 0004h - Driver Store (scalar) */
-static int i2o_seq_show_driver_store(struct seq_file *seq, void *v)
-{
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- u32 work32[8];
- int token;
-
- token =
- i2o_parm_field_get(c->exec, 0x0004, -1, &work32, sizeof(work32));
- if (token < 0) {
- i2o_report_query_status(seq, token, "0x0004 Driver Store");
- return 0;
- }
-
- seq_printf(seq, "Module limit : %d\n"
- "Module count : %d\n"
- "Current space : %d kB\n"
- "Free space : %d kB\n",
- work32[0], work32[1], work32[2] >> 10, work32[3] >> 10);
-
- return 0;
-}
-
-/* Executive group 0005h - Driver Store Table (table) */
-static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v)
-{
- typedef struct _i2o_driver_store {
- u16 stored_ddm_index;
- u8 module_type;
- u8 reserved;
- u16 i2o_vendor_id;
- u16 module_id;
- u8 module_name_version[28];
- u8 date[8];
- u32 module_size;
- u32 mpb_size;
- u32 module_flags;
- } i2o_driver_store_table;
-
- struct i2o_controller *c = (struct i2o_controller *)seq->private;
- int token;
- int i;
-
- typedef struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- i2o_driver_store_table dst[I2O_MAX_MODULES];
- } i2o_driver_result_table;
-
- i2o_driver_result_table *result;
- i2o_driver_store_table *dst;
- char tmp[28 + 1];
-
- result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
- if (result == NULL)
- return -ENOMEM;
-
- token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0005, -1,
- NULL, 0, result, sizeof(*result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0x0005 DRIVER STORE TABLE");
- kfree(result);
- return 0;
- }
-
- seq_printf(seq,
- "# Module_type Vendor Mod_id Module_name Vrs"
- "Date Mod_size Par_size Flags\n");
- for (i = 0, dst = &result->dst[0]; i < result->row_count;
- dst = &result->dst[++i]) {
- seq_printf(seq, "%-3d", dst->stored_ddm_index);
- switch (dst->module_type) {
- case 0x01:
- seq_printf(seq, "Downloaded DDM ");
- break;
- case 0x22:
- seq_printf(seq, "Embedded DDM ");
- break;
- default:
- seq_printf(seq, " ");
- }
-
- seq_printf(seq, "%-#7x", dst->i2o_vendor_id);
- seq_printf(seq, "%-#8x", dst->module_id);
- seq_printf(seq, "%-29s",
- chtostr(tmp, dst->module_name_version, 28));
- seq_printf(seq, "%-9s", chtostr(tmp, dst->date, 8));
- seq_printf(seq, "%8d ", dst->module_size);
- seq_printf(seq, "%8d ", dst->mpb_size);
- seq_printf(seq, "0x%04x", dst->module_flags);
- seq_printf(seq, "\n");
- }
-
- kfree(result);
- return 0;
-}
-
-/* Generic group F000h - Params Descriptor (table) */
-static int i2o_seq_show_groups(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
- int i;
- u8 properties;
-
- typedef struct _i2o_group_info {
- u16 group_number;
- u16 field_count;
- u16 row_count;
- u8 properties;
- u8 reserved;
- } i2o_group_info;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- i2o_group_info group[256];
- } *result;
-
- result = kmalloc(sizeof(*result), GFP_KERNEL);
- if (!result)
- return -ENOMEM;
-
- token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
- result, sizeof(*result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0xF000 Params Descriptor");
- goto out;
- }
-
- seq_printf(seq,
- "# Group FieldCount RowCount Type Add Del Clear\n");
-
- for (i = 0; i < result->row_count; i++) {
- seq_printf(seq, "%-3d", i);
- seq_printf(seq, "0x%04X ", result->group[i].group_number);
- seq_printf(seq, "%10d ", result->group[i].field_count);
- seq_printf(seq, "%8d ", result->group[i].row_count);
-
- properties = result->group[i].properties;
- if (properties & 0x1)
- seq_printf(seq, "Table ");
- else
- seq_printf(seq, "Scalar ");
- if (properties & 0x2)
- seq_printf(seq, " + ");
- else
- seq_printf(seq, " - ");
- if (properties & 0x4)
- seq_printf(seq, " + ");
- else
- seq_printf(seq, " - ");
- if (properties & 0x8)
- seq_printf(seq, " + ");
- else
- seq_printf(seq, " - ");
-
- seq_printf(seq, "\n");
- }
-
- if (result->more_flag)
- seq_printf(seq, "There is more...\n");
- out:
- kfree(result);
- return 0;
-}
-
-/* Generic group F001h - Physical Device Table (table) */
-static int i2o_seq_show_phys_device(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
- int i;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- u32 adapter_id[64];
- } result;
-
- token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF001, -1, NULL, 0,
- &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0xF001 Physical Device Table");
- return 0;
- }
-
- if (result.row_count)
- seq_printf(seq, "# AdapterId\n");
-
- for (i = 0; i < result.row_count; i++) {
- seq_printf(seq, "%-2d", i);
- seq_printf(seq, "%#7x\n", result.adapter_id[i]);
- }
-
- if (result.more_flag)
- seq_printf(seq, "There is more...\n");
-
- return 0;
-}
-
-/* Generic group F002h - Claimed Table (table) */
-static int i2o_seq_show_claimed(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
- int i;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- u16 claimed_tid[64];
- } result;
-
- token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF002, -1, NULL, 0,
- &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0xF002 Claimed Table");
- return 0;
- }
-
- if (result.row_count)
- seq_printf(seq, "# ClaimedTid\n");
-
- for (i = 0; i < result.row_count; i++) {
- seq_printf(seq, "%-2d", i);
- seq_printf(seq, "%#7x\n", result.claimed_tid[i]);
- }
-
- if (result.more_flag)
- seq_printf(seq, "There is more...\n");
-
- return 0;
-}
-
-/* Generic group F003h - User Table (table) */
-static int i2o_seq_show_users(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
- int i;
-
- typedef struct _i2o_user_table {
- u16 instance;
- u16 user_tid;
- u8 claim_type;
- u8 reserved1;
- u16 reserved2;
- } i2o_user_table;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- i2o_user_table user[64];
- } *result;
-
- result = kmalloc(sizeof(*result), GFP_KERNEL);
- if (!result)
- return -ENOMEM;
-
- token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF003, -1, NULL, 0,
- result, sizeof(*result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0xF003 User Table");
- goto out;
- }
-
- seq_printf(seq, "# Instance UserTid ClaimType\n");
-
- for (i = 0; i < result->row_count; i++) {
- seq_printf(seq, "%-3d", i);
- seq_printf(seq, "%#8x ", result->user[i].instance);
- seq_printf(seq, "%#7x ", result->user[i].user_tid);
- seq_printf(seq, "%#9x\n", result->user[i].claim_type);
- }
-
- if (result->more_flag)
- seq_printf(seq, "There is more...\n");
- out:
- kfree(result);
- return 0;
-}
-
-/* Generic group F005h - Private message extensions (table) (optional) */
-static int i2o_seq_show_priv_msgs(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
- int i;
-
- typedef struct _i2o_private {
- u16 ext_instance;
- u16 organization_id;
- u16 x_function_code;
- } i2o_private;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- i2o_private extension[64];
- } result;
-
- token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
- &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0xF005 Private Message Extensions (optional)");
- return 0;
- }
-
- seq_printf(seq, "Instance# OrgId FunctionCode\n");
-
- for (i = 0; i < result.row_count; i++) {
- seq_printf(seq, "%0#9x ", result.extension[i].ext_instance);
- seq_printf(seq, "%0#6x ", result.extension[i].organization_id);
- seq_printf(seq, "%0#6x", result.extension[i].x_function_code);
-
- seq_printf(seq, "\n");
- }
-
- if (result.more_flag)
- seq_printf(seq, "There is more...\n");
-
- return 0;
-}
-
-/* Generic group F006h - Authorized User Table (table) */
-static int i2o_seq_show_authorized_users(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
- int i;
-
- struct {
- u16 result_count;
- u16 pad;
- u16 block_size;
- u8 block_status;
- u8 error_info_size;
- u16 row_count;
- u16 more_flag;
- u32 alternate_tid[64];
- } result;
-
- token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF006, -1, NULL, 0,
- &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0xF006 Autohorized User Table");
- return 0;
- }
-
- if (result.row_count)
- seq_printf(seq, "# AlternateTid\n");
-
- for (i = 0; i < result.row_count; i++) {
- seq_printf(seq, "%-2d", i);
- seq_printf(seq, "%#7x ", result.alternate_tid[i]);
- }
-
- if (result.more_flag)
- seq_printf(seq, "There is more...\n");
-
- return 0;
-}
-
-/* Generic group F100h - Device Identity (scalar) */
-static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number
- // == (allow) 512d bytes (max)
- static u16 *work16 = (u16 *) work32;
- int token;
- char tmp[16 + 1];
-
- token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0xF100 Device Identity");
- return 0;
- }
-
- seq_printf(seq, "Device Class : %s\n", i2o_get_class_name(work16[0]));
- seq_printf(seq, "Owner TID : %0#5x\n", work16[2]);
- seq_printf(seq, "Parent TID : %0#5x\n", work16[3]);
- seq_printf(seq, "Vendor info : %s\n",
- chtostr(tmp, (u8 *) (work32 + 2), 16));
- seq_printf(seq, "Product info : %s\n",
- chtostr(tmp, (u8 *) (work32 + 6), 16));
- seq_printf(seq, "Description : %s\n",
- chtostr(tmp, (u8 *) (work32 + 10), 16));
- seq_printf(seq, "Product rev. : %s\n",
- chtostr(tmp, (u8 *) (work32 + 14), 8));
-
- seq_printf(seq, "Serial number : ");
- print_serial_number(seq, (u8 *) (work32 + 16),
- /* allow for SNLen plus
- * possible trailing '\0'
- */
- sizeof(work32) - (16 * sizeof(u32)) - 2);
- seq_printf(seq, "\n");
-
- return 0;
-}
-
-static int i2o_seq_show_dev_name(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
-
- seq_printf(seq, "%s\n", dev_name(&d->device));
-
- return 0;
-}
-
-/* Generic group F101h - DDM Identity (scalar) */
-static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
-
- struct {
- u16 ddm_tid;
- u8 module_name[24];
- u8 module_rev[8];
- u8 sn_format;
- u8 serial_number[12];
- u8 pad[256]; // allow up to 256 byte (max) serial number
- } result;
-
- char tmp[24 + 1];
-
- token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0xF101 DDM Identity");
- return 0;
- }
-
- seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid);
- seq_printf(seq, "Module name : %s\n",
- chtostr(tmp, result.module_name, 24));
- seq_printf(seq, "Module revision : %s\n",
- chtostr(tmp, result.module_rev, 8));
-
- seq_printf(seq, "Serial number : ");
- print_serial_number(seq, result.serial_number, sizeof(result) - 36);
- /* allow for SNLen plus possible trailing '\0' */
-
- seq_printf(seq, "\n");
-
- return 0;
-}
-
-/* Generic group F102h - User Information (scalar) */
-static int i2o_seq_show_uinfo(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
-
- struct {
- u8 device_name[64];
- u8 service_name[64];
- u8 physical_location[64];
- u8 instance_number[4];
- } result;
-
- char tmp[64 + 1];
-
- token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token, "0xF102 User Information");
- return 0;
- }
-
- seq_printf(seq, "Device name : %s\n",
- chtostr(tmp, result.device_name, 64));
- seq_printf(seq, "Service name : %s\n",
- chtostr(tmp, result.service_name, 64));
- seq_printf(seq, "Physical name : %s\n",
- chtostr(tmp, result.physical_location, 64));
- seq_printf(seq, "Instance number : %s\n",
- chtostr(tmp, result.instance_number, 4));
-
- return 0;
-}
-
-/* Generic group F103h - SGL Operating Limits (scalar) */
-static int i2o_seq_show_sgl_limits(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- static u32 work32[12];
- static u16 *work16 = (u16 *) work32;
- static u8 *work8 = (u8 *) work32;
- int token;
-
- token = i2o_parm_field_get(d, 0xF103, -1, &work32, sizeof(work32));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0xF103 SGL Operating Limits");
- return 0;
- }
-
- seq_printf(seq, "SGL chain size : %d\n", work32[0]);
- seq_printf(seq, "Max SGL chain size : %d\n", work32[1]);
- seq_printf(seq, "SGL chain size target : %d\n", work32[2]);
- seq_printf(seq, "SGL frag count : %d\n", work16[6]);
- seq_printf(seq, "Max SGL frag count : %d\n", work16[7]);
- seq_printf(seq, "SGL frag count target : %d\n", work16[8]);
-
-/* FIXME
- if (d->i2oversion == 0x02)
- {
-*/
- seq_printf(seq, "SGL data alignment : %d\n", work16[8]);
- seq_printf(seq, "SGL addr limit : %d\n", work8[20]);
- seq_printf(seq, "SGL addr sizes supported : ");
- if (work8[21] & 0x01)
- seq_printf(seq, "32 bit ");
- if (work8[21] & 0x02)
- seq_printf(seq, "64 bit ");
- if (work8[21] & 0x04)
- seq_printf(seq, "96 bit ");
- if (work8[21] & 0x08)
- seq_printf(seq, "128 bit ");
- seq_printf(seq, "\n");
-/*
- }
-*/
-
- return 0;
-}
-
-/* Generic group F200h - Sensors (scalar) */
-static int i2o_seq_show_sensors(struct seq_file *seq, void *v)
-{
- struct i2o_device *d = (struct i2o_device *)seq->private;
- int token;
-
- struct {
- u16 sensor_instance;
- u8 component;
- u16 component_instance;
- u8 sensor_class;
- u8 sensor_type;
- u8 scaling_exponent;
- u32 actual_reading;
- u32 minimum_reading;
- u32 low2lowcat_treshold;
- u32 lowcat2low_treshold;
- u32 lowwarn2low_treshold;
- u32 low2lowwarn_treshold;
- u32 norm2lowwarn_treshold;
- u32 lowwarn2norm_treshold;
- u32 nominal_reading;
- u32 hiwarn2norm_treshold;
- u32 norm2hiwarn_treshold;
- u32 high2hiwarn_treshold;
- u32 hiwarn2high_treshold;
- u32 hicat2high_treshold;
- u32 hi2hicat_treshold;
- u32 maximum_reading;
- u8 sensor_state;
- u16 event_enable;
- } result;
-
- token = i2o_parm_field_get(d, 0xF200, -1, &result, sizeof(result));
-
- if (token < 0) {
- i2o_report_query_status(seq, token,
- "0xF200 Sensors (optional)");
- return 0;
- }
-
- seq_printf(seq, "Sensor instance : %d\n", result.sensor_instance);
-
- seq_printf(seq, "Component : %d = ", result.component);
- switch (result.component) {
- case 0:
- seq_printf(seq, "Other");
- break;
- case 1:
- seq_printf(seq, "Planar logic Board");
- break;
- case 2:
- seq_printf(seq, "CPU");
- break;
- case 3:
- seq_printf(seq, "Chassis");
- break;
- case 4:
- seq_printf(seq, "Power Supply");
- break;
- case 5:
- seq_printf(seq, "Storage");
- break;
- case 6:
- seq_printf(seq, "External");
- break;
- }
- seq_printf(seq, "\n");
-
- seq_printf(seq, "Component instance : %d\n",
- result.component_instance);
- seq_printf(seq, "Sensor class : %s\n",
- result.sensor_class ? "Analog" : "Digital");
-
- seq_printf(seq, "Sensor type : %d = ", result.sensor_type);
- switch (result.sensor_type) {
- case 0:
- seq_printf(seq, "Other\n");
- break;
- case 1:
- seq_printf(seq, "Thermal\n");
- break;
- case 2:
- seq_printf(seq, "DC voltage (DC volts)\n");
- break;
- case 3:
- seq_printf(seq, "AC voltage (AC volts)\n");
- break;
- case 4:
- seq_printf(seq, "DC current (DC amps)\n");
- break;
- case 5:
- seq_printf(seq, "AC current (AC volts)\n");
- break;
- case 6:
- seq_printf(seq, "Door open\n");
- break;
- case 7:
- seq_printf(seq, "Fan operational\n");
- break;
- }
-
- seq_printf(seq, "Scaling exponent : %d\n",
- result.scaling_exponent);
- seq_printf(seq, "Actual reading : %d\n", result.actual_reading);
- seq_printf(seq, "Minimum reading : %d\n", result.minimum_reading);
- seq_printf(seq, "Low2LowCat treshold : %d\n",
- result.low2lowcat_treshold);
- seq_printf(seq, "LowCat2Low treshold : %d\n",
- result.lowcat2low_treshold);
- seq_printf(seq, "LowWarn2Low treshold : %d\n",
- result.lowwarn2low_treshold);
- seq_printf(seq, "Low2LowWarn treshold : %d\n",
- result.low2lowwarn_treshold);
- seq_printf(seq, "Norm2LowWarn treshold : %d\n",
- result.norm2lowwarn_treshold);
- seq_printf(seq, "LowWarn2Norm treshold : %d\n",
- result.lowwarn2norm_treshold);
- seq_printf(seq, "Nominal reading : %d\n", result.nominal_reading);
- seq_printf(seq, "HiWarn2Norm treshold : %d\n",
- result.hiwarn2norm_treshold);
- seq_printf(seq, "Norm2HiWarn treshold : %d\n",
- result.norm2hiwarn_treshold);
- seq_printf(seq, "High2HiWarn treshold : %d\n",
- result.high2hiwarn_treshold);
- seq_printf(seq, "HiWarn2High treshold : %d\n",
- result.hiwarn2high_treshold);
- seq_printf(seq, "HiCat2High treshold : %d\n",
- result.hicat2high_treshold);
- seq_printf(seq, "High2HiCat treshold : %d\n",
- result.hi2hicat_treshold);
- seq_printf(seq, "Maximum reading : %d\n", result.maximum_reading);
-
- seq_printf(seq, "Sensor state : %d = ", result.sensor_state);
- switch (result.sensor_state) {
- case 0:
- seq_printf(seq, "Normal\n");
- break;
- case 1:
- seq_printf(seq, "Abnormal\n");
- break;
- case 2:
- seq_printf(seq, "Unknown\n");
- break;
- case 3:
- seq_printf(seq, "Low Catastrophic (LoCat)\n");
- break;
- case 4:
- seq_printf(seq, "Low (Low)\n");
- break;
- case 5:
- seq_printf(seq, "Low Warning (LoWarn)\n");
- break;
- case 6:
- seq_printf(seq, "High Warning (HiWarn)\n");
- break;
- case 7:
- seq_printf(seq, "High (High)\n");
- break;
- case 8:
- seq_printf(seq, "High Catastrophic (HiCat)\n");
- break;
- }
-
- seq_printf(seq, "Event_enable : 0x%02X\n", result.event_enable);
- seq_printf(seq, " [%s] Operational state change. \n",
- (result.event_enable & 0x01) ? "+" : "-");
- seq_printf(seq, " [%s] Low catastrophic. \n",
- (result.event_enable & 0x02) ? "+" : "-");
- seq_printf(seq, " [%s] Low reading. \n",
- (result.event_enable & 0x04) ? "+" : "-");
- seq_printf(seq, " [%s] Low warning. \n",
- (result.event_enable & 0x08) ? "+" : "-");
- seq_printf(seq,
- " [%s] Change back to normal from out of range state. \n",
- (result.event_enable & 0x10) ? "+" : "-");
- seq_printf(seq, " [%s] High warning. \n",
- (result.event_enable & 0x20) ? "+" : "-");
- seq_printf(seq, " [%s] High reading. \n",
- (result.event_enable & 0x40) ? "+" : "-");
- seq_printf(seq, " [%s] High catastrophic. \n",
- (result.event_enable & 0x80) ? "+" : "-");
-
- return 0;
-}
-
-static int i2o_seq_open_hrt(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_hrt, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_lct(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_lct, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_status(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_status, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_hw(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_hw, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_ddm_table, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_driver_store(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_driver_store, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_drivers_stored, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_groups(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_groups, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_phys_device(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_phys_device, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_claimed(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_claimed, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_users(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_users, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_priv_msgs, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_authorized_users,
- PDE_DATA(inode));
-};
-
-static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_dev_identity, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_ddm_identity, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_uinfo(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_uinfo, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_sgl_limits, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_sensors(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_sensors, PDE_DATA(inode));
-};
-
-static int i2o_seq_open_dev_name(struct inode *inode, struct file *file)
-{
- return single_open(file, i2o_seq_show_dev_name, PDE_DATA(inode));
-};
-
-static const struct file_operations i2o_seq_fops_lct = {
- .open = i2o_seq_open_lct,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_hrt = {
- .open = i2o_seq_open_hrt,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_status = {
- .open = i2o_seq_open_status,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_hw = {
- .open = i2o_seq_open_hw,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_ddm_table = {
- .open = i2o_seq_open_ddm_table,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_driver_store = {
- .open = i2o_seq_open_driver_store,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_drivers_stored = {
- .open = i2o_seq_open_drivers_stored,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_groups = {
- .open = i2o_seq_open_groups,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_phys_device = {
- .open = i2o_seq_open_phys_device,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_claimed = {
- .open = i2o_seq_open_claimed,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_users = {
- .open = i2o_seq_open_users,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_priv_msgs = {
- .open = i2o_seq_open_priv_msgs,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_authorized_users = {
- .open = i2o_seq_open_authorized_users,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_dev_name = {
- .open = i2o_seq_open_dev_name,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_dev_identity = {
- .open = i2o_seq_open_dev_identity,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_ddm_identity = {
- .open = i2o_seq_open_ddm_identity,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_uinfo = {
- .open = i2o_seq_open_uinfo,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_sgl_limits = {
- .open = i2o_seq_open_sgl_limits,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static const struct file_operations i2o_seq_fops_sensors = {
- .open = i2o_seq_open_sensors,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-/*
- * IOP specific entries...write field just in case someone
- * ever wants one.
- */
-static i2o_proc_entry i2o_proc_generic_iop_entries[] = {
- {"hrt", S_IFREG | S_IRUGO, &i2o_seq_fops_hrt},
- {"lct", S_IFREG | S_IRUGO, &i2o_seq_fops_lct},
- {"status", S_IFREG | S_IRUGO, &i2o_seq_fops_status},
- {"hw", S_IFREG | S_IRUGO, &i2o_seq_fops_hw},
- {"ddm_table", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_table},
- {"driver_store", S_IFREG | S_IRUGO, &i2o_seq_fops_driver_store},
- {"drivers_stored", S_IFREG | S_IRUGO, &i2o_seq_fops_drivers_stored},
- {NULL, 0, NULL}
-};
-
-/*
- * Device specific entries
- */
-static i2o_proc_entry generic_dev_entries[] = {
- {"groups", S_IFREG | S_IRUGO, &i2o_seq_fops_groups},
- {"phys_dev", S_IFREG | S_IRUGO, &i2o_seq_fops_phys_device},
- {"claimed", S_IFREG | S_IRUGO, &i2o_seq_fops_claimed},
- {"users", S_IFREG | S_IRUGO, &i2o_seq_fops_users},
- {"priv_msgs", S_IFREG | S_IRUGO, &i2o_seq_fops_priv_msgs},
- {"authorized_users", S_IFREG | S_IRUGO, &i2o_seq_fops_authorized_users},
- {"dev_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_identity},
- {"ddm_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_identity},
- {"user_info", S_IFREG | S_IRUGO, &i2o_seq_fops_uinfo},
- {"sgl_limits", S_IFREG | S_IRUGO, &i2o_seq_fops_sgl_limits},
- {"sensors", S_IFREG | S_IRUGO, &i2o_seq_fops_sensors},
- {NULL, 0, NULL}
-};
-
-/*
- * Storage unit specific entries (SCSI Periph, BS) with device names
- */
-static i2o_proc_entry rbs_dev_entries[] = {
- {"dev_name", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_name},
- {NULL, 0, NULL}
-};
-
-/**
- * i2o_proc_create_entries - Creates proc dir entries
- * @dir: proc dir entry under which the entries should be placed
- * @i2o_pe: pointer to the entries which should be added
- * @data: pointer to I2O controller or device
- *
- * Create proc dir entries for a I2O controller or I2O device.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_proc_create_entries(struct proc_dir_entry *dir,
- i2o_proc_entry * i2o_pe, void *data)
-{
- struct proc_dir_entry *tmp;
-
- while (i2o_pe->name) {
- tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir,
- i2o_pe->fops, data);
- if (!tmp)
- return -1;
-
- i2o_pe++;
- }
-
- return 0;
-}
-
-/**
- * i2o_proc_device_add - Add an I2O device to the proc dir
- * @dir: proc dir entry to which the device should be added
- * @dev: I2O device which should be added
- *
- * Add an I2O device to the proc dir entry dir and create the entries for
- * the device depending on the class of the I2O device.
- */
-static void i2o_proc_device_add(struct proc_dir_entry *dir,
- struct i2o_device *dev)
-{
- char buff[10];
- struct proc_dir_entry *devdir;
- i2o_proc_entry *i2o_pe = NULL;
-
- sprintf(buff, "%03x", dev->lct_data.tid);
-
- osm_debug("adding device /proc/i2o/%s/%s\n", dev->iop->name, buff);
-
- devdir = proc_mkdir_data(buff, 0, dir, dev);
- if (!devdir) {
- osm_warn("Could not allocate procdir!\n");
- return;
- }
-
- i2o_proc_create_entries(devdir, generic_dev_entries, dev);
-
- /* Inform core that we want updates about this device's status */
- switch (dev->lct_data.class_id) {
- case I2O_CLASS_SCSI_PERIPHERAL:
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- i2o_pe = rbs_dev_entries;
- break;
- default:
- break;
- }
- if (i2o_pe)
- i2o_proc_create_entries(devdir, i2o_pe, dev);
-}
-
-/**
- * i2o_proc_iop_add - Add an I2O controller to the i2o proc tree
- * @dir: parent proc dir entry
- * @c: I2O controller which should be added
- *
- * Add the entries to the parent proc dir entry. Also each device is added
- * to the controllers proc dir entry.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_proc_iop_add(struct proc_dir_entry *dir,
- struct i2o_controller *c)
-{
- struct proc_dir_entry *iopdir;
- struct i2o_device *dev;
-
- osm_debug("adding IOP /proc/i2o/%s\n", c->name);
-
- iopdir = proc_mkdir_data(c->name, 0, dir, c);
- if (!iopdir)
- return -1;
-
- i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c);
-
- list_for_each_entry(dev, &c->devices, list)
- i2o_proc_device_add(iopdir, dev);
-
- return 0;
-}
-
-/**
- * i2o_proc_fs_create - Create the i2o proc fs.
- *
- * Iterate over each I2O controller and create the entries for it.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_proc_fs_create(void)
-{
- struct i2o_controller *c;
-
- i2o_proc_dir_root = proc_mkdir("i2o", NULL);
- if (!i2o_proc_dir_root)
- return -1;
-
- list_for_each_entry(c, &i2o_controllers, list)
- i2o_proc_iop_add(i2o_proc_dir_root, c);
-
- return 0;
-};
-
-/**
- * i2o_proc_fs_destroy - Cleanup the all i2o proc entries
- *
- * Iterate over each I2O controller and remove the entries for it.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __exit i2o_proc_fs_destroy(void)
-{
- remove_proc_subtree("i2o", NULL);
-
- return 0;
-};
-
-/**
- * i2o_proc_init - Init function for procfs
- *
- * Registers Proc OSM and creates procfs entries.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_proc_init(void)
-{
- int rc;
-
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
- rc = i2o_driver_register(&i2o_proc_driver);
- if (rc)
- return rc;
-
- rc = i2o_proc_fs_create();
- if (rc) {
- i2o_driver_unregister(&i2o_proc_driver);
- return rc;
- }
-
- return 0;
-};
-
-/**
- * i2o_proc_exit - Exit function for procfs
- *
- * Unregisters Proc OSM and removes procfs entries.
- */
-static void __exit i2o_proc_exit(void)
-{
- i2o_driver_unregister(&i2o_proc_driver);
- i2o_proc_fs_destroy();
-};
-
-MODULE_AUTHOR("Deepak Saxena");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_proc_init);
-module_exit(i2o_proc_exit);
diff --git a/drivers/message/i2o/i2o_scsi.c b/drivers/message/i2o/i2o_scsi.c
deleted file mode 100644
index 8152e9fa9d95..000000000000
--- a/drivers/message/i2o/i2o_scsi.c
+++ /dev/null
@@ -1,814 +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, 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.
- *
- * For the avoidance of doubt the "preferred form" of this code is one which
- * is in an open non patent encumbered format. Where cryptographic key signing
- * forms part of the process of creating an executable the information
- * including keys needed to generate an equivalently functional executable
- * are deemed to be part of the source code.
- *
- * Complications for I2O scsi
- *
- * o Each (bus,lun) is a logical device in I2O. We keep a map
- * table. We spoof failed selection for unmapped units
- * o Request sense buffers can come back for free.
- * o Scatter gather is a bit dynamic. We have to investigate at
- * setup time.
- * o Some of our resources are dynamically shared. The i2o core
- * needs a message reservation protocol to avoid swap v net
- * deadlocking. We need to back off queue requests.
- *
- * In general the firmware wants to help. Where its help isn't performance
- * useful we just ignore the aid. Its not worth the code in truth.
- *
- * Fixes/additions:
- * Steve Ralston:
- * Scatter gather now works
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Minor fixes for 2.6.
- *
- * To Do:
- * 64bit cleanups
- * Fix the resource management problems.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/string.h>
-#include <linux/ioport.h>
-#include <linux/jiffies.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/proc_fs.h>
-#include <linux/prefetch.h>
-#include <linux/pci.h>
-#include <linux/blkdev.h>
-#include <linux/i2o.h>
-#include <linux/scatterlist.h>
-
-#include <asm/dma.h>
-#include <asm/io.h>
-#include <linux/atomic.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/sg.h>
-
-#define OSM_NAME "scsi-osm"
-#define OSM_VERSION "1.316"
-#define OSM_DESCRIPTION "I2O SCSI Peripheral OSM"
-
-static struct i2o_driver i2o_scsi_driver;
-
-static unsigned int i2o_scsi_max_id = 16;
-static unsigned int i2o_scsi_max_lun = 255;
-
-struct i2o_scsi_host {
- struct Scsi_Host *scsi_host; /* pointer to the SCSI host */
- struct i2o_controller *iop; /* pointer to the I2O controller */
- u64 lun; /* lun's used for block devices */
- struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */
-};
-
-static struct scsi_host_template i2o_scsi_host_template;
-
-#define I2O_SCSI_CAN_QUEUE 4
-
-/* SCSI OSM class handling definition */
-static struct i2o_class_id i2o_scsi_class_id[] = {
- {I2O_CLASS_SCSI_PERIPHERAL},
- {I2O_CLASS_END}
-};
-
-static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
-{
- struct i2o_scsi_host *i2o_shost;
- struct i2o_device *i2o_dev;
- struct Scsi_Host *scsi_host;
- int max_channel = 0;
- u8 type;
- int i;
- size_t size;
- u16 body_size = 6;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC
- if (c->adaptec)
- body_size = 8;
-#endif
-
- list_for_each_entry(i2o_dev, &c->devices, list)
- if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
- if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
- && (type == 0x01)) /* SCSI bus */
- max_channel++;
- }
-
- if (!max_channel) {
- osm_warn("no channels found on %s\n", c->name);
- return ERR_PTR(-EFAULT);
- }
-
- size = max_channel * sizeof(struct i2o_device *)
- + sizeof(struct i2o_scsi_host);
-
- scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
- if (!scsi_host) {
- osm_warn("Could not allocate SCSI host\n");
- return ERR_PTR(-ENOMEM);
- }
-
- scsi_host->max_channel = max_channel - 1;
- scsi_host->max_id = i2o_scsi_max_id;
- scsi_host->max_lun = i2o_scsi_max_lun;
- scsi_host->this_id = c->unit;
- scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
-
- i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
- i2o_shost->scsi_host = scsi_host;
- i2o_shost->iop = c;
- i2o_shost->lun = 1;
-
- i = 0;
- list_for_each_entry(i2o_dev, &c->devices, list)
- if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
- if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
- && (type == 0x01)) /* only SCSI bus */
- i2o_shost->channel[i++] = i2o_dev;
-
- if (i >= max_channel)
- break;
- }
-
- return i2o_shost;
-};
-
-/**
- * i2o_scsi_get_host - Get an I2O SCSI host
- * @c: I2O controller to for which to get the SCSI host
- *
- * If the I2O controller already exists as SCSI host, the SCSI host
- * is returned, otherwise the I2O controller is added to the SCSI
- * core.
- *
- * Returns pointer to the I2O SCSI host on success or NULL on failure.
- */
-static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c)
-{
- return c->driver_data[i2o_scsi_driver.context];
-};
-
-/**
- * i2o_scsi_remove - Remove I2O device from SCSI core
- * @dev: device which should be removed
- *
- * Removes the I2O device from the SCSI core again.
- *
- * Returns 0 on success.
- */
-static int i2o_scsi_remove(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_controller *c = i2o_dev->iop;
- struct i2o_scsi_host *i2o_shost;
- struct scsi_device *scsi_dev;
-
- osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
-
- i2o_shost = i2o_scsi_get_host(c);
-
- shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
- if (scsi_dev->hostdata == i2o_dev) {
- sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
- scsi_remove_device(scsi_dev);
- scsi_device_put(scsi_dev);
- break;
- }
-
- return 0;
-};
-
-/**
- * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it
- * @dev: device to verify if it is a I2O SCSI device
- *
- * Retrieve channel, id and lun for I2O device. If everything goes well
- * register the I2O device as SCSI device on the I2O SCSI controller.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_scsi_probe(struct device *dev)
-{
- struct i2o_device *i2o_dev = to_i2o_device(dev);
- struct i2o_controller *c = i2o_dev->iop;
- struct i2o_scsi_host *i2o_shost;
- struct Scsi_Host *scsi_host;
- struct i2o_device *parent;
- struct scsi_device *scsi_dev;
- u32 id = -1;
- u64 lun = -1;
- int channel = -1;
- int i, rc;
-
- i2o_shost = i2o_scsi_get_host(c);
- if (!i2o_shost)
- return -EFAULT;
-
- scsi_host = i2o_shost->scsi_host;
-
- switch (i2o_dev->lct_data.class_id) {
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- case I2O_CLASS_EXECUTIVE:
-#ifdef CONFIG_I2O_EXT_ADAPTEC
- if (c->adaptec) {
- u8 type;
- struct i2o_device *d = i2o_shost->channel[0];
-
- if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1)
- && (type == 0x01)) /* SCSI bus */
- if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
- channel = 0;
- if (i2o_dev->lct_data.class_id ==
- I2O_CLASS_RANDOM_BLOCK_STORAGE)
- lun =
- cpu_to_le64(i2o_shost->
- lun++);
- else
- lun = 0;
- }
- }
-#endif
- break;
-
- case I2O_CLASS_SCSI_PERIPHERAL:
- if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4))
- return -EFAULT;
-
- if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8))
- return -EFAULT;
-
- parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
- if (!parent) {
- osm_warn("can not find parent of device %03x\n",
- i2o_dev->lct_data.tid);
- return -EFAULT;
- }
-
- for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
- if (i2o_shost->channel[i] == parent)
- channel = i;
- break;
-
- default:
- return -EFAULT;
- }
-
- if (channel == -1) {
- osm_warn("can not find channel of device %03x\n",
- i2o_dev->lct_data.tid);
- return -EFAULT;
- }
-
- if (le32_to_cpu(id) >= scsi_host->max_id) {
- osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)",
- le32_to_cpu(id), scsi_host->max_id);
- return -EFAULT;
- }
-
- if (le64_to_cpu(lun) >= scsi_host->max_lun) {
- osm_warn("SCSI device lun (%llu) >= max_lun of I2O host (%llu)",
- le64_to_cpu(lun), scsi_host->max_lun);
- return -EFAULT;
- }
-
- scsi_dev =
- __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id),
- le64_to_cpu(lun), i2o_dev);
-
- if (IS_ERR(scsi_dev)) {
- osm_warn("can not add SCSI device %03x\n",
- i2o_dev->lct_data.tid);
- return PTR_ERR(scsi_dev);
- }
-
- rc = sysfs_create_link(&i2o_dev->device.kobj,
- &scsi_dev->sdev_gendev.kobj, "scsi");
- if (rc)
- goto err;
-
- osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %llu\n",
- i2o_dev->lct_data.tid, channel, le32_to_cpu(id),
- le64_to_cpu(lun));
-
- return 0;
-
-err:
- scsi_remove_device(scsi_dev);
- return rc;
-};
-
-static const char *i2o_scsi_info(struct Scsi_Host *SChost)
-{
- struct i2o_scsi_host *hostdata;
- hostdata = (struct i2o_scsi_host *)SChost->hostdata;
- return hostdata->iop->name;
-}
-
-/**
- * i2o_scsi_reply - SCSI OSM message reply handler
- * @c: controller issuing the reply
- * @m: message id for flushing
- * @msg: the message from the controller
- *
- * Process reply messages (interrupts in normal scsi controller think).
- * We can get a variety of messages to process. The normal path is
- * scsi command completions. We must also deal with IOP failures,
- * the reply to a bus reset and the reply to a LUN query.
- *
- * Returns 0 on success and if the reply should not be flushed or > 0
- * on success and if the reply should be flushed. Returns negative error
- * code on failure and if the reply should be flushed.
- */
-static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
- struct i2o_message *msg)
-{
- struct scsi_cmnd *cmd;
- u32 error;
- struct device *dev;
-
- cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
- if (unlikely(!cmd)) {
- osm_err("NULL reply received!\n");
- return -1;
- }
-
- /*
- * Low byte is device status, next is adapter status,
- * (then one byte reserved), then request status.
- */
- error = le32_to_cpu(msg->body[0]);
-
- osm_debug("Completed %0x%p\n", cmd);
-
- cmd->result = error & 0xff;
- /*
- * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
- * the SCSI layer handle the error
- */
- if (cmd->result)
- memcpy(cmd->sense_buffer, &msg->body[3],
- min(SCSI_SENSE_BUFFERSIZE, 40));
-
- /* only output error code if AdapterStatus is not HBA_SUCCESS */
- if ((error >> 8) & 0xff)
- osm_err("SCSI error %08x\n", error);
-
- dev = &c->pdev->dev;
-
- scsi_dma_unmap(cmd);
-
- cmd->scsi_done(cmd);
-
- return 1;
-};
-
-/**
- * i2o_scsi_notify_device_add - Retrieve notifications of added devices
- * @i2o_dev: the I2O device which was added
- *
- * If a I2O device is added we catch the notification, because I2O classes
- * other than SCSI peripheral will not be received through
- * i2o_scsi_probe().
- */
-static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
-{
- switch (i2o_dev->lct_data.class_id) {
- case I2O_CLASS_EXECUTIVE:
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- i2o_scsi_probe(&i2o_dev->device);
- break;
-
- default:
- break;
- }
-};
-
-/**
- * i2o_scsi_notify_device_remove - Retrieve notifications of removed devices
- * @i2o_dev: the I2O device which was removed
- *
- * If a I2O device is removed, we catch the notification to remove the
- * corresponding SCSI device.
- */
-static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
-{
- switch (i2o_dev->lct_data.class_id) {
- case I2O_CLASS_EXECUTIVE:
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- i2o_scsi_remove(&i2o_dev->device);
- break;
-
- default:
- break;
- }
-};
-
-/**
- * i2o_scsi_notify_controller_add - Retrieve notifications of added controllers
- * @c: the controller which was added
- *
- * If a I2O controller is added, we catch the notification to add a
- * corresponding Scsi_Host.
- */
-static void i2o_scsi_notify_controller_add(struct i2o_controller *c)
-{
- struct i2o_scsi_host *i2o_shost;
- int rc;
-
- i2o_shost = i2o_scsi_host_alloc(c);
- if (IS_ERR(i2o_shost)) {
- osm_err("Could not initialize SCSI host\n");
- return;
- }
-
- rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
- if (rc) {
- osm_err("Could not add SCSI host\n");
- scsi_host_put(i2o_shost->scsi_host);
- return;
- }
-
- c->driver_data[i2o_scsi_driver.context] = i2o_shost;
-
- osm_debug("new I2O SCSI host added\n");
-};
-
-/**
- * i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers
- * @c: the controller which was removed
- *
- * If a I2O controller is removed, we catch the notification to remove the
- * corresponding Scsi_Host.
- */
-static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
-{
- struct i2o_scsi_host *i2o_shost;
- i2o_shost = i2o_scsi_get_host(c);
- if (!i2o_shost)
- return;
-
- c->driver_data[i2o_scsi_driver.context] = NULL;
-
- scsi_remove_host(i2o_shost->scsi_host);
- scsi_host_put(i2o_shost->scsi_host);
- osm_debug("I2O SCSI host removed\n");
-};
-
-/* SCSI OSM driver struct */
-static struct i2o_driver i2o_scsi_driver = {
- .name = OSM_NAME,
- .reply = i2o_scsi_reply,
- .classes = i2o_scsi_class_id,
- .notify_device_add = i2o_scsi_notify_device_add,
- .notify_device_remove = i2o_scsi_notify_device_remove,
- .notify_controller_add = i2o_scsi_notify_controller_add,
- .notify_controller_remove = i2o_scsi_notify_controller_remove,
- .driver = {
- .probe = i2o_scsi_probe,
- .remove = i2o_scsi_remove,
- },
-};
-
-/**
- * i2o_scsi_queuecommand - queue a SCSI command
- * @SCpnt: scsi command pointer
- * @done: callback for completion
- *
- * Issue a scsi command asynchronously. Return 0 on success or 1 if
- * we hit an error (normally message queue congestion). The only
- * minor complication here is that I2O deals with the device addressing
- * so we have to map the bus/dev/lun back to an I2O handle as well
- * as faking absent devices ourself.
- *
- * Locks: takes the controller lock on error path only
- */
-
-static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
- void (*done) (struct scsi_cmnd *))
-{
- struct i2o_controller *c;
- struct i2o_device *i2o_dev;
- int tid;
- struct i2o_message *msg;
- /*
- * ENABLE_DISCONNECT
- * SIMPLE_TAG
- * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
- */
- u32 scsi_flags = 0x20a00000;
- u32 sgl_offset;
- u32 *mptr;
- u32 cmd = I2O_CMD_SCSI_EXEC << 24;
- int rc = 0;
-
- /*
- * Do the incoming paperwork
- */
- i2o_dev = SCpnt->device->hostdata;
-
- SCpnt->scsi_done = done;
-
- if (unlikely(!i2o_dev)) {
- osm_warn("no I2O device in request\n");
- SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
- goto exit;
- }
- c = i2o_dev->iop;
- tid = i2o_dev->lct_data.tid;
-
- osm_debug("qcmd: Tid = %03x\n", tid);
- osm_debug("Real scsi messages.\n");
-
- /*
- * Put together a scsi execscb message
- */
- switch (SCpnt->sc_data_direction) {
- case PCI_DMA_NONE:
- /* DATA NO XFER */
- sgl_offset = SGL_OFFSET_0;
- break;
-
- case PCI_DMA_TODEVICE:
- /* DATA OUT (iop-->dev) */
- scsi_flags |= 0x80000000;
- sgl_offset = SGL_OFFSET_10;
- break;
-
- case PCI_DMA_FROMDEVICE:
- /* DATA IN (iop<--dev) */
- scsi_flags |= 0x40000000;
- sgl_offset = SGL_OFFSET_10;
- break;
-
- default:
- /* Unknown - kill the command */
- SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
- goto exit;
- }
-
- /*
- * Obtain an I2O message. If there are none free then
- * throw it back to the scsi layer
- */
-
- msg = i2o_msg_get(c);
- if (IS_ERR(msg)) {
- rc = SCSI_MLQUEUE_HOST_BUSY;
- goto exit;
- }
-
- mptr = &msg->body[0];
-
-#if 0 /* this code can't work */
-#ifdef CONFIG_I2O_EXT_ADAPTEC
- if (c->adaptec) {
- u32 adpt_flags = 0;
-
- if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
- i2o_sg_io_hdr_t __user *usr_ptr =
- ((Sg_request *) (SCpnt->sc_request->
- upper_private_data))->header.
- usr_ptr;
-
- if (usr_ptr)
- get_user(adpt_flags, &usr_ptr->flags);
- }
-
- switch (i2o_dev->lct_data.class_id) {
- case I2O_CLASS_EXECUTIVE:
- case I2O_CLASS_RANDOM_BLOCK_STORAGE:
- /* interpret flag has to be set for executive */
- adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
- break;
-
- default:
- break;
- }
-
- /*
- * for Adaptec controllers we use the PRIVATE command, because
- * the normal SCSI EXEC doesn't support all SCSI commands on
- * all controllers (for example READ CAPACITY).
- */
- if (sgl_offset == SGL_OFFSET_10)
- sgl_offset = SGL_OFFSET_12;
- cmd = I2O_CMD_PRIVATE << 24;
- *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
- *mptr++ = cpu_to_le32(adpt_flags | tid);
- }
-#endif
-#endif
-
- msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
- msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context);
-
- /* We want the SCSI control block back */
- msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt));
-
- /* LSI_920_PCI_QUIRK
- *
- * Intermittant observations of msg frame word data corruption
- * observed on msg[4] after:
- * WRITE, READ-MODIFY-WRITE
- * operations. 19990606 -sralston
- *
- * (Hence we build this word via tag. Its good practice anyway
- * we don't want fetches over PCI needlessly)
- */
-
- /* Attach tags to the devices */
- /* FIXME: implement
- if(SCpnt->device->tagged_supported) {
- if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
- scsi_flags |= 0x01000000;
- else if(SCpnt->tag == ORDERED_QUEUE_TAG)
- scsi_flags |= 0x01800000;
- }
- */
-
- *mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len);
-
- /* Write SCSI command into the message - always 16 byte block */
- memcpy(mptr, SCpnt->cmnd, 16);
- mptr += 4;
-
- if (sgl_offset != SGL_OFFSET_0) {
- /* write size of data addressed by SGL */
- *mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
-
- /* Now fill in the SGList and command */
-
- if (scsi_sg_count(SCpnt)) {
- if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
- scsi_sg_count(SCpnt),
- SCpnt->sc_data_direction, &mptr))
- goto nomem;
- }
- }
-
- /* Stick the headers on */
- msg->u.head[0] =
- cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
-
- /* Queue the message */
- i2o_msg_post(c, msg);
-
- osm_debug("Issued %0x%p\n", SCpnt);
-
- return 0;
-
- nomem:
- rc = -ENOMEM;
- i2o_msg_nop(c, msg);
-
- exit:
- return rc;
-}
-
-static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
-
-/**
- * i2o_scsi_abort - abort a running command
- * @SCpnt: command to abort
- *
- * Ask the I2O controller to abort a command. This is an asynchrnous
- * process and our callback handler will see the command complete with an
- * aborted message if it succeeds.
- *
- * Returns 0 if the command is successfully aborted or negative error code
- * on failure.
- */
-static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
-{
- struct i2o_device *i2o_dev;
- struct i2o_controller *c;
- struct i2o_message *msg;
- int tid;
- int status = FAILED;
-
- osm_warn("Aborting command block.\n");
-
- i2o_dev = SCpnt->device->hostdata;
- c = i2o_dev->iop;
- tid = i2o_dev->lct_data.tid;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return SCSI_MLQUEUE_HOST_BUSY;
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
- msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
-
- if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
- status = SUCCESS;
-
- return status;
-}
-
-/**
- * i2o_scsi_bios_param - Invent disk geometry
- * @sdev: scsi device
- * @dev: block layer device
- * @capacity: size in sectors
- * @ip: geometry array
- *
- * This is anyone's guess quite frankly. We use the same rules everyone
- * else appears to and hope. It seems to work.
- */
-
-static int i2o_scsi_bios_param(struct scsi_device *sdev,
- struct block_device *dev, sector_t capacity,
- int *ip)
-{
- int size;
-
- size = capacity;
- ip[0] = 64; /* heads */
- ip[1] = 32; /* sectors */
- if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */
- ip[0] = 255; /* heads */
- ip[1] = 63; /* sectors */
- ip[2] = size / (255 * 63); /* cylinders */
- }
- return 0;
-}
-
-static struct scsi_host_template i2o_scsi_host_template = {
- .proc_name = OSM_NAME,
- .name = OSM_DESCRIPTION,
- .info = i2o_scsi_info,
- .queuecommand = i2o_scsi_queuecommand,
- .eh_abort_handler = i2o_scsi_abort,
- .bios_param = i2o_scsi_bios_param,
- .can_queue = I2O_SCSI_CAN_QUEUE,
- .sg_tablesize = 8,
- .cmd_per_lun = 6,
- .use_clustering = ENABLE_CLUSTERING,
-};
-
-/**
- * i2o_scsi_init - SCSI OSM initialization function
- *
- * Register SCSI OSM into I2O core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_scsi_init(void)
-{
- int rc;
-
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
- /* Register SCSI OSM into I2O core */
- rc = i2o_driver_register(&i2o_scsi_driver);
- if (rc) {
- osm_err("Could not register SCSI driver\n");
- return rc;
- }
-
- return 0;
-};
-
-/**
- * i2o_scsi_exit - SCSI OSM exit function
- *
- * Unregisters SCSI OSM from I2O core.
- */
-static void __exit i2o_scsi_exit(void)
-{
- /* Unregister I2O SCSI OSM from I2O core */
- i2o_driver_unregister(&i2o_scsi_driver);
-};
-
-MODULE_AUTHOR("Red Hat Software");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-module_init(i2o_scsi_init);
-module_exit(i2o_scsi_exit);
diff --git a/drivers/message/i2o/iop.c b/drivers/message/i2o/iop.c
deleted file mode 100644
index 92752fb5b2d3..000000000000
--- a/drivers/message/i2o/iop.c
+++ /dev/null
@@ -1,1247 +0,0 @@
-/*
- * Functions to handle I2O controllers and I2O message handling
- *
- * Copyright (C) 1999-2002 Red Hat Software
- *
- * Written by Alan Cox, Building Number Three 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.
- *
- * A lot of the I2O message side code from this is taken from the
- * Red Creek RCPCI45 adapter driver by Red Creek Communications
- *
- * Fixes/additions:
- * Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- * Deepak Saxena <deepak@plexity.net>
- * Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * Alan Cox <alan@lxorguk.ukuu.org.uk>:
- * Ported to Linux 2.5.
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Minor fixes for 2.6.
- */
-
-#include <linux/module.h>
-#include <linux/i2o.h>
-#include <linux/delay.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-#include "core.h"
-
-#define OSM_NAME "i2o"
-#define OSM_VERSION "1.325"
-#define OSM_DESCRIPTION "I2O subsystem"
-
-/* global I2O controller list */
-LIST_HEAD(i2o_controllers);
-
-/*
- * global I2O System Table. Contains information about all the IOPs in the
- * system. Used to inform IOPs about each others existence.
- */
-static struct i2o_dma i2o_systab;
-
-static int i2o_hrt_get(struct i2o_controller *c);
-
-/**
- * i2o_msg_get_wait - obtain an I2O message from the IOP
- * @c: I2O controller
- * @wait: how long to wait until timeout
- *
- * This function waits up to wait seconds for a message slot to be
- * available.
- *
- * On a success the message is returned and the pointer to the message is
- * set in msg. The returned message is the physical page frame offset
- * address from the read port (see the i2o spec). If no message is
- * available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
- */
-struct i2o_message *i2o_msg_get_wait(struct i2o_controller *c, int wait)
-{
- unsigned long timeout = jiffies + wait * HZ;
- struct i2o_message *msg;
-
- while (IS_ERR(msg = i2o_msg_get(c))) {
- if (time_after(jiffies, timeout)) {
- osm_debug("%s: Timeout waiting for message frame.\n",
- c->name);
- return ERR_PTR(-ETIMEDOUT);
- }
- schedule_timeout_uninterruptible(1);
- }
-
- return msg;
-};
-
-#if BITS_PER_LONG == 64
-/**
- * i2o_cntxt_list_add - Append a pointer to context list and return a id
- * @c: controller to which the context list belong
- * @ptr: pointer to add to the context list
- *
- * Because the context field in I2O is only 32-bit large, on 64-bit the
- * pointer is to large to fit in the context field. The i2o_cntxt_list
- * functions therefore map pointers to context fields.
- *
- * Returns context id > 0 on success or 0 on failure.
- */
-u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
-{
- struct i2o_context_list_element *entry;
- unsigned long flags;
-
- if (!ptr)
- osm_err("%s: couldn't add NULL pointer to context list!\n",
- c->name);
-
- entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
- if (!entry) {
- osm_err("%s: Could not allocate memory for context list element"
- "\n", c->name);
- return 0;
- }
-
- entry->ptr = ptr;
- entry->timestamp = jiffies;
- INIT_LIST_HEAD(&entry->list);
-
- spin_lock_irqsave(&c->context_list_lock, flags);
-
- if (unlikely(atomic_inc_and_test(&c->context_list_counter)))
- atomic_inc(&c->context_list_counter);
-
- entry->context = atomic_read(&c->context_list_counter);
-
- list_add(&entry->list, &c->context_list);
-
- spin_unlock_irqrestore(&c->context_list_lock, flags);
-
- osm_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
-
- return entry->context;
-};
-
-/**
- * i2o_cntxt_list_remove - Remove a pointer from the context list
- * @c: controller to which the context list belong
- * @ptr: pointer which should be removed from the context list
- *
- * Removes a previously added pointer from the context list and returns
- * the matching context id.
- *
- * Returns context id on success or 0 on failure.
- */
-u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
-{
- struct i2o_context_list_element *entry;
- u32 context = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&c->context_list_lock, flags);
- list_for_each_entry(entry, &c->context_list, list)
- if (entry->ptr == ptr) {
- list_del(&entry->list);
- context = entry->context;
- kfree(entry);
- break;
- }
- spin_unlock_irqrestore(&c->context_list_lock, flags);
-
- if (!context)
- osm_warn("%s: Could not remove nonexistent ptr %p\n", c->name,
- ptr);
-
- osm_debug("%s: remove ptr from context list %d -> %p\n", c->name,
- context, ptr);
-
- return context;
-};
-
-/**
- * i2o_cntxt_list_get - Get a pointer from the context list and remove it
- * @c: controller to which the context list belong
- * @context: context id to which the pointer belong
- *
- * Returns pointer to the matching context id on success or NULL on
- * failure.
- */
-void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
-{
- struct i2o_context_list_element *entry;
- unsigned long flags;
- void *ptr = NULL;
-
- spin_lock_irqsave(&c->context_list_lock, flags);
- list_for_each_entry(entry, &c->context_list, list)
- if (entry->context == context) {
- list_del(&entry->list);
- ptr = entry->ptr;
- kfree(entry);
- break;
- }
- spin_unlock_irqrestore(&c->context_list_lock, flags);
-
- if (!ptr)
- osm_warn("%s: context id %d not found\n", c->name, context);
-
- osm_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
- ptr);
-
- return ptr;
-};
-
-/**
- * i2o_cntxt_list_get_ptr - Get a context id from the context list
- * @c: controller to which the context list belong
- * @ptr: pointer to which the context id should be fetched
- *
- * Returns context id which matches to the pointer on success or 0 on
- * failure.
- */
-u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
-{
- struct i2o_context_list_element *entry;
- u32 context = 0;
- unsigned long flags;
-
- spin_lock_irqsave(&c->context_list_lock, flags);
- list_for_each_entry(entry, &c->context_list, list)
- if (entry->ptr == ptr) {
- context = entry->context;
- break;
- }
- spin_unlock_irqrestore(&c->context_list_lock, flags);
-
- if (!context)
- osm_warn("%s: Could not find nonexistent ptr %p\n", c->name,
- ptr);
-
- osm_debug("%s: get context id from context list %p -> %d\n", c->name,
- ptr, context);
-
- return context;
-};
-#endif
-
-/**
- * i2o_iop_find - Find an I2O controller by id
- * @unit: unit number of the I2O controller to search for
- *
- * Lookup the I2O controller on the controller list.
- *
- * Returns pointer to the I2O controller on success or NULL if not found.
- */
-struct i2o_controller *i2o_find_iop(int unit)
-{
- struct i2o_controller *c;
-
- list_for_each_entry(c, &i2o_controllers, list) {
- if (c->unit == unit)
- return c;
- }
-
- return NULL;
-};
-
-/**
- * i2o_iop_find_device - Find a I2O device on an I2O controller
- * @c: I2O controller where the I2O device hangs on
- * @tid: TID of the I2O device to search for
- *
- * Searches the devices of the I2O controller for a device with TID tid and
- * returns it.
- *
- * Returns a pointer to the I2O device if found, otherwise NULL.
- */
-struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid)
-{
- struct i2o_device *dev;
-
- list_for_each_entry(dev, &c->devices, list)
- if (dev->lct_data.tid == tid)
- return dev;
-
- return NULL;
-};
-
-/**
- * i2o_quiesce_controller - quiesce controller
- * @c: controller
- *
- * Quiesce an IOP. Causes IOP to make external operation quiescent
- * (i2o 'READY' state). Internal operation of the IOP continues normally.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_quiesce(struct i2o_controller *c)
-{
- struct i2o_message *msg;
- i2o_status_block *sb = c->status_block.virt;
- int rc;
-
- i2o_status_get(c);
-
- /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
- if ((sb->iop_state != ADAPTER_STATE_READY) &&
- (sb->iop_state != ADAPTER_STATE_OPERATIONAL))
- return 0;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 |
- ADAPTER_TID);
-
- /* Long timeout needed for quiesce if lots of devices */
- if ((rc = i2o_msg_post_wait(c, msg, 240)))
- osm_info("%s: Unable to quiesce (status=%#x).\n", c->name, -rc);
- else
- osm_debug("%s: Quiesced.\n", c->name);
-
- i2o_status_get(c); // Entered READY state
-
- return rc;
-};
-
-/**
- * i2o_iop_enable - move controller from ready to OPERATIONAL
- * @c: I2O controller
- *
- * Enable IOP. This allows the IOP to resume external operations and
- * reverses the effect of a quiesce. Returns zero or an error code if
- * an error occurs.
- */
-static int i2o_iop_enable(struct i2o_controller *c)
-{
- struct i2o_message *msg;
- i2o_status_block *sb = c->status_block.virt;
- int rc;
-
- i2o_status_get(c);
-
- /* Enable only allowed on READY state */
- if (sb->iop_state != ADAPTER_STATE_READY)
- return -EINVAL;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 |
- ADAPTER_TID);
-
- /* How long of a timeout do we need? */
- if ((rc = i2o_msg_post_wait(c, msg, 240)))
- osm_err("%s: Could not enable (status=%#x).\n", c->name, -rc);
- else
- osm_debug("%s: Enabled.\n", c->name);
-
- i2o_status_get(c); // entered OPERATIONAL state
-
- return rc;
-};
-
-/**
- * i2o_iop_quiesce_all - Quiesce all I2O controllers on the system
- *
- * Quiesce all I2O controllers which are connected to the system.
- */
-static inline void i2o_iop_quiesce_all(void)
-{
- struct i2o_controller *c, *tmp;
-
- list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
- if (!c->no_quiesce)
- i2o_iop_quiesce(c);
- }
-};
-
-/**
- * i2o_iop_enable_all - Enables all controllers on the system
- *
- * Enables all I2O controllers which are connected to the system.
- */
-static inline void i2o_iop_enable_all(void)
-{
- struct i2o_controller *c, *tmp;
-
- list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
- i2o_iop_enable(c);
-};
-
-/**
- * i2o_clear_controller - Bring I2O controller into HOLD state
- * @c: controller
- *
- * Clear an IOP to HOLD state, ie. terminate external operations, clear all
- * input queues and prepare for a system restart. IOP's internal operation
- * continues normally and the outbound queue is alive. The IOP is not
- * expected to rebuild its LCT.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_clear(struct i2o_controller *c)
-{
- struct i2o_message *msg;
- int rc;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- /* Quiesce all IOPs first */
- i2o_iop_quiesce_all();
-
- msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 |
- ADAPTER_TID);
-
- if ((rc = i2o_msg_post_wait(c, msg, 30)))
- osm_info("%s: Unable to clear (status=%#x).\n", c->name, -rc);
- else
- osm_debug("%s: Cleared.\n", c->name);
-
- /* Enable all IOPs */
- i2o_iop_enable_all();
-
- return rc;
-}
-
-/**
- * i2o_iop_init_outbound_queue - setup the outbound message queue
- * @c: I2O controller
- *
- * Clear and (re)initialize IOP's outbound queue and post the message
- * frames to the IOP.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
-{
- u32 m;
- volatile u8 *status = c->status.virt;
- struct i2o_message *msg;
- ulong timeout;
- int i;
-
- osm_debug("%s: Initializing Outbound Queue...\n", c->name);
-
- memset(c->status.virt, 0, 4);
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
- msg->u.s.tcntxt = cpu_to_le32(0x00000000);
- msg->body[0] = cpu_to_le32(PAGE_SIZE);
- /* Outbound msg frame size in words and Initcode */
- msg->body[1] = cpu_to_le32(I2O_OUTBOUND_MSG_FRAME_SIZE << 16 | 0x80);
- msg->body[2] = cpu_to_le32(0xd0000004);
- msg->body[3] = cpu_to_le32(i2o_dma_low(c->status.phys));
- msg->body[4] = cpu_to_le32(i2o_dma_high(c->status.phys));
-
- i2o_msg_post(c, msg);
-
- timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
- while (*status <= I2O_CMD_IN_PROGRESS) {
- if (time_after(jiffies, timeout)) {
- osm_warn("%s: Timeout Initializing\n", c->name);
- return -ETIMEDOUT;
- }
- schedule_timeout_uninterruptible(1);
- }
-
- m = c->out_queue.phys;
-
- /* Post frames */
- for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
- i2o_flush_reply(c, m);
- udelay(1); /* Promise */
- m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
- }
-
- return 0;
-}
-
-/**
- * i2o_iop_reset - reset an I2O controller
- * @c: controller to reset
- *
- * Reset the IOP into INIT state and wait until IOP gets into RESET state.
- * Terminate all external operations, clear IOP's inbound and outbound
- * queues, terminate all DDMs, and reload the IOP's operating environment
- * and all local DDMs. The IOP rebuilds its LCT.
- */
-static int i2o_iop_reset(struct i2o_controller *c)
-{
- volatile u8 *status = c->status.virt;
- struct i2o_message *msg;
- unsigned long timeout;
- i2o_status_block *sb = c->status_block.virt;
- int rc = 0;
-
- osm_debug("%s: Resetting controller\n", c->name);
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- memset(c->status_block.virt, 0, 8);
-
- /* Quiesce all IOPs first */
- i2o_iop_quiesce_all();
-
- msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
- msg->u.s.tcntxt = cpu_to_le32(0x00000000);
- msg->body[0] = cpu_to_le32(0x00000000);
- msg->body[1] = cpu_to_le32(0x00000000);
- msg->body[2] = cpu_to_le32(i2o_dma_low(c->status.phys));
- msg->body[3] = cpu_to_le32(i2o_dma_high(c->status.phys));
-
- i2o_msg_post(c, msg);
-
- /* Wait for a reply */
- timeout = jiffies + I2O_TIMEOUT_RESET * HZ;
- while (!*status) {
- if (time_after(jiffies, timeout))
- break;
-
- schedule_timeout_uninterruptible(1);
- }
-
- switch (*status) {
- case I2O_CMD_REJECTED:
- osm_warn("%s: IOP reset rejected\n", c->name);
- rc = -EPERM;
- break;
-
- case I2O_CMD_IN_PROGRESS:
- /*
- * Once the reset is sent, the IOP goes into the INIT state
- * which is indeterminate. We need to wait until the IOP has
- * rebooted before we can let the system talk to it. We read
- * the inbound Free_List until a message is available. If we
- * can't read one in the given amount of time, we assume the
- * IOP could not reboot properly.
- */
- osm_debug("%s: Reset in progress, waiting for reboot...\n",
- c->name);
-
- while (IS_ERR(msg = i2o_msg_get_wait(c, I2O_TIMEOUT_RESET))) {
- if (time_after(jiffies, timeout)) {
- osm_err("%s: IOP reset timeout.\n", c->name);
- rc = PTR_ERR(msg);
- goto exit;
- }
- schedule_timeout_uninterruptible(1);
- }
- i2o_msg_nop(c, msg);
-
- /* from here all quiesce commands are safe */
- c->no_quiesce = 0;
-
- /* verify if controller is in state RESET */
- i2o_status_get(c);
-
- if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
- osm_warn("%s: reset completed, but adapter not in RESET"
- " state.\n", c->name);
- else
- osm_debug("%s: reset completed.\n", c->name);
-
- break;
-
- default:
- osm_err("%s: IOP reset timeout.\n", c->name);
- rc = -ETIMEDOUT;
- break;
- }
-
- exit:
- /* Enable all IOPs */
- i2o_iop_enable_all();
-
- return rc;
-};
-
-/**
- * i2o_iop_activate - Bring controller up to HOLD
- * @c: controller
- *
- * This function brings an I2O controller into HOLD state. The adapter
- * is reset if necessary and then the queues and resource table are read.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_activate(struct i2o_controller *c)
-{
- i2o_status_block *sb = c->status_block.virt;
- int rc;
- int state;
-
- /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
- /* In READY state, Get status */
-
- rc = i2o_status_get(c);
- if (rc) {
- osm_info("%s: Unable to obtain status, attempting a reset.\n",
- c->name);
- rc = i2o_iop_reset(c);
- if (rc)
- return rc;
- }
-
- if (sb->i2o_version > I2OVER15) {
- osm_err("%s: Not running version 1.5 of the I2O Specification."
- "\n", c->name);
- return -ENODEV;
- }
-
- switch (sb->iop_state) {
- case ADAPTER_STATE_FAULTED:
- osm_err("%s: hardware fault\n", c->name);
- return -EFAULT;
-
- case ADAPTER_STATE_READY:
- case ADAPTER_STATE_OPERATIONAL:
- case ADAPTER_STATE_HOLD:
- case ADAPTER_STATE_FAILED:
- osm_debug("%s: already running, trying to reset...\n", c->name);
- rc = i2o_iop_reset(c);
- if (rc)
- return rc;
- }
-
- /* preserve state */
- state = sb->iop_state;
-
- rc = i2o_iop_init_outbound_queue(c);
- if (rc)
- return rc;
-
- /* if adapter was not in RESET state clear now */
- if (state != ADAPTER_STATE_RESET)
- i2o_iop_clear(c);
-
- i2o_status_get(c);
-
- if (sb->iop_state != ADAPTER_STATE_HOLD) {
- osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
- return -EIO;
- }
-
- return i2o_hrt_get(c);
-};
-
-static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
-{
- i2o_status_block *sb = c->status_block.virt;
- struct resource *res = &c->mem_resource;
- resource_size_t size, align;
- int err;
-
- res->name = c->pdev->bus->name;
- res->flags = flags;
- res->start = 0;
- res->end = 0;
- osm_info("%s: requires private memory resources.\n", c->name);
-
- if (flags & IORESOURCE_MEM) {
- size = sb->desired_mem_size;
- align = 1 << 20; /* unspecified, use 1Mb and play safe */
- } else {
- size = sb->desired_io_size;
- align = 1 << 12; /* unspecified, use 4Kb and play safe */
- }
-
- err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
- NULL, NULL);
- if (err < 0)
- return;
-
- if (flags & IORESOURCE_MEM) {
- c->mem_alloc = 1;
- sb->current_mem_size = resource_size(res);
- sb->current_mem_base = res->start;
- } else if (flags & IORESOURCE_IO) {
- c->io_alloc = 1;
- sb->current_io_size = resource_size(res);
- sb->current_io_base = res->start;
- }
- osm_info("%s: allocated PCI space %pR\n", c->name, res);
-}
-
-/**
- * i2o_iop_systab_set - Set the I2O System Table of the specified IOP
- * @c: I2O controller to which the system table should be send
- *
- * Before the systab could be set i2o_systab_build() must be called.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_systab_set(struct i2o_controller *c)
-{
- struct i2o_message *msg;
- i2o_status_block *sb = c->status_block.virt;
- struct device *dev = &c->pdev->dev;
- int rc;
-
- if (sb->current_mem_size < sb->desired_mem_size)
- i2o_res_alloc(c, IORESOURCE_MEM);
-
- if (sb->current_io_size < sb->desired_io_size)
- i2o_res_alloc(c, IORESOURCE_IO);
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len,
- PCI_DMA_TODEVICE);
- if (!i2o_systab.phys) {
- i2o_msg_nop(c, msg);
- return -ENOMEM;
- }
-
- msg->u.head[0] = cpu_to_le32(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 |
- ADAPTER_TID);
-
- /*
- * Provide three SGL-elements:
- * System table (SysTab), Private memory space declaration and
- * Private i/o space declaration
- */
-
- msg->body[0] = cpu_to_le32(c->unit + 2);
- msg->body[1] = cpu_to_le32(0x00000000);
- msg->body[2] = cpu_to_le32(0x54000000 | i2o_systab.len);
- msg->body[3] = cpu_to_le32(i2o_systab.phys);
- msg->body[4] = cpu_to_le32(0x54000000 | sb->current_mem_size);
- msg->body[5] = cpu_to_le32(sb->current_mem_base);
- msg->body[6] = cpu_to_le32(0xd4000000 | sb->current_io_size);
- msg->body[6] = cpu_to_le32(sb->current_io_base);
-
- rc = i2o_msg_post_wait(c, msg, 120);
-
- dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len,
- PCI_DMA_TODEVICE);
-
- if (rc < 0)
- osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name,
- -rc);
- else
- osm_debug("%s: SysTab set.\n", c->name);
-
- return rc;
-}
-
-/**
- * i2o_iop_online - Bring a controller online into OPERATIONAL state.
- * @c: I2O controller
- *
- * Send the system table and enable the I2O controller.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_iop_online(struct i2o_controller *c)
-{
- int rc;
-
- rc = i2o_iop_systab_set(c);
- if (rc)
- return rc;
-
- /* In READY state */
- osm_debug("%s: Attempting to enable...\n", c->name);
- rc = i2o_iop_enable(c);
- if (rc)
- return rc;
-
- return 0;
-};
-
-/**
- * i2o_iop_remove - Remove the I2O controller from the I2O core
- * @c: I2O controller
- *
- * Remove the I2O controller from the I2O core. If devices are attached to
- * the controller remove these also and finally reset the controller.
- */
-void i2o_iop_remove(struct i2o_controller *c)
-{
- struct i2o_device *dev, *tmp;
-
- osm_debug("%s: deleting controller\n", c->name);
-
- i2o_driver_notify_controller_remove_all(c);
-
- list_del(&c->list);
-
- list_for_each_entry_safe(dev, tmp, &c->devices, list)
- i2o_device_remove(dev);
-
- device_del(&c->device);
-
- /* Ask the IOP to switch to RESET state */
- i2o_iop_reset(c);
-}
-
-/**
- * i2o_systab_build - Build system table
- *
- * The system table contains information about all the IOPs in the system
- * (duh) and is used by the Executives on the IOPs to establish peer2peer
- * connections. We're not supporting peer2peer at the moment, but this
- * will be needed down the road for things like lan2lan forwarding.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_systab_build(void)
-{
- struct i2o_controller *c, *tmp;
- int num_controllers = 0;
- u32 change_ind = 0;
- int count = 0;
- struct i2o_sys_tbl *systab = i2o_systab.virt;
-
- list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
- num_controllers++;
-
- if (systab) {
- change_ind = systab->change_ind;
- kfree(i2o_systab.virt);
- }
-
- /* Header + IOPs */
- i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers *
- sizeof(struct i2o_sys_tbl_entry);
-
- systab = i2o_systab.virt = kzalloc(i2o_systab.len, GFP_KERNEL);
- if (!systab) {
- osm_err("unable to allocate memory for System Table\n");
- return -ENOMEM;
- }
-
- systab->version = I2OVERSION;
- systab->change_ind = change_ind + 1;
-
- list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
- i2o_status_block *sb;
-
- if (count >= num_controllers) {
- osm_err("controller added while building system table"
- "\n");
- break;
- }
-
- sb = c->status_block.virt;
-
- /*
- * Get updated IOP state so we have the latest information
- *
- * We should delete the controller at this point if it
- * doesn't respond since if it's not on the system table
- * it is techninically not part of the I2O subsystem...
- */
- if (unlikely(i2o_status_get(c))) {
- osm_err("%s: Deleting b/c could not get status while "
- "attempting to build system table\n", c->name);
- i2o_iop_remove(c);
- continue; // try the next one
- }
-
- systab->iops[count].org_id = sb->org_id;
- systab->iops[count].iop_id = c->unit + 2;
- systab->iops[count].seg_num = 0;
- systab->iops[count].i2o_version = sb->i2o_version;
- systab->iops[count].iop_state = sb->iop_state;
- systab->iops[count].msg_type = sb->msg_type;
- systab->iops[count].frame_size = sb->inbound_frame_size;
- systab->iops[count].last_changed = change_ind;
- systab->iops[count].iop_capabilities = sb->iop_capabilities;
- systab->iops[count].inbound_low =
- i2o_dma_low(c->base.phys + I2O_IN_PORT);
- systab->iops[count].inbound_high =
- i2o_dma_high(c->base.phys + I2O_IN_PORT);
-
- count++;
- }
-
- systab->num_entries = count;
-
- return 0;
-};
-
-/**
- * i2o_parse_hrt - Parse the hardware resource table.
- * @c: I2O controller
- *
- * We don't do anything with it except dumping it (in debug mode).
- *
- * Returns 0.
- */
-static int i2o_parse_hrt(struct i2o_controller *c)
-{
- i2o_dump_hrt(c);
- return 0;
-};
-
-/**
- * i2o_status_get - Get the status block from the I2O controller
- * @c: I2O controller
- *
- * Issue a status query on the controller. This updates the attached
- * status block. The status block could then be accessed through
- * c->status_block.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_status_get(struct i2o_controller *c)
-{
- struct i2o_message *msg;
- volatile u8 *status_block;
- unsigned long timeout;
-
- status_block = (u8 *) c->status_block.virt;
- memset(c->status_block.virt, 0, sizeof(i2o_status_block));
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
- msg->u.s.tcntxt = cpu_to_le32(0x00000000);
- msg->body[0] = cpu_to_le32(0x00000000);
- msg->body[1] = cpu_to_le32(0x00000000);
- msg->body[2] = cpu_to_le32(i2o_dma_low(c->status_block.phys));
- msg->body[3] = cpu_to_le32(i2o_dma_high(c->status_block.phys));
- msg->body[4] = cpu_to_le32(sizeof(i2o_status_block)); /* always 88 bytes */
-
- i2o_msg_post(c, msg);
-
- /* Wait for a reply */
- timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ;
- while (status_block[87] != 0xFF) {
- if (time_after(jiffies, timeout)) {
- osm_err("%s: Get status timeout.\n", c->name);
- return -ETIMEDOUT;
- }
-
- schedule_timeout_uninterruptible(1);
- }
-
-#ifdef DEBUG
- i2o_debug_state(c);
-#endif
-
- return 0;
-}
-
-/*
- * i2o_hrt_get - Get the Hardware Resource Table from the I2O controller
- * @c: I2O controller from which the HRT should be fetched
- *
- * The HRT contains information about possible hidden devices but is
- * mostly useless to us.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_hrt_get(struct i2o_controller *c)
-{
- int rc;
- int i;
- i2o_hrt *hrt = c->hrt.virt;
- u32 size = sizeof(i2o_hrt);
- struct device *dev = &c->pdev->dev;
-
- for (i = 0; i < I2O_HRT_GET_TRIES; i++) {
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(SIX_WORD_MSG_SIZE | SGL_OFFSET_4);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 |
- ADAPTER_TID);
- msg->body[0] = cpu_to_le32(0xd0000000 | c->hrt.len);
- msg->body[1] = cpu_to_le32(c->hrt.phys);
-
- rc = i2o_msg_post_wait_mem(c, msg, 20, &c->hrt);
-
- if (rc < 0) {
- osm_err("%s: Unable to get HRT (status=%#x)\n", c->name,
- -rc);
- return rc;
- }
-
- size = hrt->num_entries * hrt->entry_len << 2;
- if (size > c->hrt.len) {
- if (i2o_dma_realloc(dev, &c->hrt, size))
- return -ENOMEM;
- else
- hrt = c->hrt.virt;
- } else
- return i2o_parse_hrt(c);
- }
-
- osm_err("%s: Unable to get HRT after %d tries, giving up\n", c->name,
- I2O_HRT_GET_TRIES);
-
- return -EBUSY;
-}
-
-/**
- * i2o_iop_release - release the memory for a I2O controller
- * @dev: I2O controller which should be released
- *
- * Release the allocated memory. This function is called if refcount of
- * device reaches 0 automatically.
- */
-static void i2o_iop_release(struct device *dev)
-{
- struct i2o_controller *c = to_i2o_controller(dev);
-
- i2o_iop_free(c);
-};
-
-/**
- * i2o_iop_alloc - Allocate and initialize a i2o_controller struct
- *
- * Allocate the necessary memory for a i2o_controller struct and
- * initialize the lists and message mempool.
- *
- * Returns a pointer to the I2O controller or a negative error code on
- * failure.
- */
-struct i2o_controller *i2o_iop_alloc(void)
-{
- static int unit = 0; /* 0 and 1 are NULL IOP and Local Host */
- struct i2o_controller *c;
- char poolname[32];
-
- c = kzalloc(sizeof(*c), GFP_KERNEL);
- if (!c) {
- osm_err("i2o: Insufficient memory to allocate a I2O controller."
- "\n");
- return ERR_PTR(-ENOMEM);
- }
-
- c->unit = unit++;
- sprintf(c->name, "iop%d", c->unit);
-
- snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name);
- if (i2o_pool_alloc
- (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32),
- I2O_MSG_INPOOL_MIN)) {
- kfree(c);
- return ERR_PTR(-ENOMEM);
- };
-
- INIT_LIST_HEAD(&c->devices);
- spin_lock_init(&c->lock);
- mutex_init(&c->lct_lock);
-
- device_initialize(&c->device);
-
- c->device.release = &i2o_iop_release;
-
- dev_set_name(&c->device, "iop%d", c->unit);
-
-#if BITS_PER_LONG == 64
- spin_lock_init(&c->context_list_lock);
- atomic_set(&c->context_list_counter, 0);
- INIT_LIST_HEAD(&c->context_list);
-#endif
-
- return c;
-};
-
-/**
- * i2o_iop_add - Initialize the I2O controller and add him to the I2O core
- * @c: controller
- *
- * Initialize the I2O controller and if no error occurs add him to the I2O
- * core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_iop_add(struct i2o_controller *c)
-{
- int rc;
-
- if ((rc = device_add(&c->device))) {
- osm_err("%s: could not add controller\n", c->name);
- goto iop_reset;
- }
-
- osm_info("%s: Activating I2O controller...\n", c->name);
- osm_info("%s: This may take a few minutes if there are many devices\n",
- c->name);
-
- if ((rc = i2o_iop_activate(c))) {
- osm_err("%s: could not activate controller\n", c->name);
- goto device_del;
- }
-
- osm_debug("%s: building sys table...\n", c->name);
-
- if ((rc = i2o_systab_build()))
- goto device_del;
-
- osm_debug("%s: online controller...\n", c->name);
-
- if ((rc = i2o_iop_online(c)))
- goto device_del;
-
- osm_debug("%s: getting LCT...\n", c->name);
-
- if ((rc = i2o_exec_lct_get(c)))
- goto device_del;
-
- list_add(&c->list, &i2o_controllers);
-
- i2o_driver_notify_controller_add_all(c);
-
- osm_info("%s: Controller added\n", c->name);
-
- return 0;
-
- device_del:
- device_del(&c->device);
-
- iop_reset:
- i2o_iop_reset(c);
-
- return rc;
-};
-
-/**
- * i2o_event_register - Turn on/off event notification for a I2O device
- * @dev: I2O device which should receive the event registration request
- * @drv: driver which want to get notified
- * @tcntxt: transaction context to use with this notifier
- * @evt_mask: mask of events
- *
- * Create and posts an event registration message to the task. No reply
- * is waited for, or expected. If you do not want further notifications,
- * call the i2o_event_register again with a evt_mask of 0.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv,
- int tcntxt, u32 evt_mask)
-{
- struct i2o_controller *c = dev->iop;
- struct i2o_message *msg;
-
- msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
- if (IS_ERR(msg))
- return PTR_ERR(msg);
-
- msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
- msg->u.head[1] =
- cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->
- lct_data.tid);
- msg->u.s.icntxt = cpu_to_le32(drv->context);
- msg->u.s.tcntxt = cpu_to_le32(tcntxt);
- msg->body[0] = cpu_to_le32(evt_mask);
-
- i2o_msg_post(c, msg);
-
- return 0;
-};
-
-/**
- * i2o_iop_init - I2O main initialization function
- *
- * Initialize the I2O drivers (OSM) functions, register the Executive OSM,
- * initialize the I2O PCI part and finally initialize I2O device stuff.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int __init i2o_iop_init(void)
-{
- int rc = 0;
-
- printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
-
- if ((rc = i2o_driver_init()))
- goto exit;
-
- if ((rc = i2o_exec_init()))
- goto driver_exit;
-
- if ((rc = i2o_pci_init()))
- goto exec_exit;
-
- return 0;
-
- exec_exit:
- i2o_exec_exit();
-
- driver_exit:
- i2o_driver_exit();
-
- exit:
- return rc;
-}
-
-/**
- * i2o_iop_exit - I2O main exit function
- *
- * Removes I2O controllers from PCI subsystem and shut down OSMs.
- */
-static void __exit i2o_iop_exit(void)
-{
- i2o_pci_exit();
- i2o_exec_exit();
- i2o_driver_exit();
-};
-
-module_init(i2o_iop_init);
-module_exit(i2o_iop_exit);
-
-MODULE_AUTHOR("Red Hat Software");
-MODULE_LICENSE("GPL");
-MODULE_DESCRIPTION(OSM_DESCRIPTION);
-MODULE_VERSION(OSM_VERSION);
-
-#if BITS_PER_LONG == 64
-EXPORT_SYMBOL(i2o_cntxt_list_add);
-EXPORT_SYMBOL(i2o_cntxt_list_get);
-EXPORT_SYMBOL(i2o_cntxt_list_remove);
-EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
-#endif
-EXPORT_SYMBOL(i2o_msg_get_wait);
-EXPORT_SYMBOL(i2o_find_iop);
-EXPORT_SYMBOL(i2o_iop_find_device);
-EXPORT_SYMBOL(i2o_event_register);
-EXPORT_SYMBOL(i2o_status_get);
-EXPORT_SYMBOL(i2o_controllers);
diff --git a/drivers/message/i2o/memory.c b/drivers/message/i2o/memory.c
deleted file mode 100644
index 292b41e49fbd..000000000000
--- a/drivers/message/i2o/memory.c
+++ /dev/null
@@ -1,313 +0,0 @@
-/*
- * Functions to handle I2O memory
- *
- * Pulled from the inlines in i2o headers and uninlined
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the 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/i2o.h>
-#include <linux/delay.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include "core.h"
-
-/* Protects our 32/64bit mask switching */
-static DEFINE_MUTEX(mem_lock);
-
-/**
- * i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
- * @c: I2O controller for which the calculation should be done
- * @body_size: maximum body size used for message in 32-bit words.
- *
- * Return the maximum number of SG elements in a SG list.
- */
-u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
-{
- i2o_status_block *sb = c->status_block.virt;
- u16 sg_count =
- (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
- body_size;
-
- if (c->pae_support) {
- /*
- * for 64-bit a SG attribute element must be added and each
- * SG element needs 12 bytes instead of 8.
- */
- sg_count -= 2;
- sg_count /= 3;
- } else
- sg_count /= 2;
-
- if (c->short_req && (sg_count > 8))
- sg_count = 8;
-
- return sg_count;
-}
-EXPORT_SYMBOL_GPL(i2o_sg_tablesize);
-
-
-/**
- * i2o_dma_map_single - Map pointer to controller and fill in I2O message.
- * @c: I2O controller
- * @ptr: pointer to the data which should be mapped
- * @size: size of data in bytes
- * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- * @sg_ptr: pointer to the SG list inside the I2O message
- *
- * This function does all necessary DMA handling and also writes the I2O
- * SGL elements into the I2O message. For details on DMA handling see also
- * dma_map_single(). The pointer sg_ptr will only be set to the end of the
- * SG list if the allocation was successful.
- *
- * Returns DMA address which must be checked for failures using
- * dma_mapping_error().
- */
-dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
- size_t size,
- enum dma_data_direction direction,
- u32 ** sg_ptr)
-{
- u32 sg_flags;
- u32 *mptr = *sg_ptr;
- dma_addr_t dma_addr;
-
- switch (direction) {
- case DMA_TO_DEVICE:
- sg_flags = 0xd4000000;
- break;
- case DMA_FROM_DEVICE:
- sg_flags = 0xd0000000;
- break;
- default:
- return 0;
- }
-
- dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
- if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
- *mptr++ = cpu_to_le32(0x7C020002);
- *mptr++ = cpu_to_le32(PAGE_SIZE);
- }
-#endif
-
- *mptr++ = cpu_to_le32(sg_flags | size);
- *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support)
- *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
-#endif
- *sg_ptr = mptr;
- }
- return dma_addr;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_map_single);
-
-/**
- * i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
- * @c: I2O controller
- * @sg: SG list to be mapped
- * @sg_count: number of elements in the SG list
- * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
- * @sg_ptr: pointer to the SG list inside the I2O message
- *
- * This function does all necessary DMA handling and also writes the I2O
- * SGL elements into the I2O message. For details on DMA handling see also
- * dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
- * list if the allocation was successful.
- *
- * Returns 0 on failure or 1 on success.
- */
-int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg,
- int sg_count, enum dma_data_direction direction, u32 ** sg_ptr)
-{
- u32 sg_flags;
- u32 *mptr = *sg_ptr;
-
- switch (direction) {
- case DMA_TO_DEVICE:
- sg_flags = 0x14000000;
- break;
- case DMA_FROM_DEVICE:
- sg_flags = 0x10000000;
- break;
- default:
- return 0;
- }
-
- sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
- if (!sg_count)
- return 0;
-
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
- *mptr++ = cpu_to_le32(0x7C020002);
- *mptr++ = cpu_to_le32(PAGE_SIZE);
- }
-#endif
-
- while (sg_count-- > 0) {
- if (!sg_count)
- sg_flags |= 0xC0000000;
- *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
- *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if ((sizeof(dma_addr_t) > 4) && c->pae_support)
- *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
-#endif
- sg = sg_next(sg);
- }
- *sg_ptr = mptr;
-
- return 1;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_map_sg);
-
-/**
- * i2o_dma_alloc - Allocate DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which should get the DMA buffer
- * @len: length of the new DMA memory
- *
- * Allocate a coherent DMA memory and write the pointers into addr.
- *
- * Returns 0 on success or -ENOMEM on failure.
- */
-int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len)
-{
- struct pci_dev *pdev = to_pci_dev(dev);
- int dma_64 = 0;
-
- mutex_lock(&mem_lock);
- if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_BIT_MASK(64))) {
- dma_64 = 1;
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- mutex_unlock(&mem_lock);
- return -ENOMEM;
- }
- }
-
- addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL);
-
- if ((sizeof(dma_addr_t) > 4) && dma_64)
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
- printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
- mutex_unlock(&mem_lock);
-
- if (!addr->virt)
- return -ENOMEM;
-
- memset(addr->virt, 0, len);
- addr->len = len;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_alloc);
-
-
-/**
- * i2o_dma_free - Free DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: i2o_dma struct which contains the DMA buffer
- *
- * Free a coherent DMA memory and set virtual address of addr to NULL.
- */
-void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
-{
- if (addr->virt) {
- if (addr->phys)
- dma_free_coherent(dev, addr->len, addr->virt,
- addr->phys);
- else
- kfree(addr->virt);
- addr->virt = NULL;
- }
-}
-EXPORT_SYMBOL_GPL(i2o_dma_free);
-
-
-/**
- * i2o_dma_realloc - Realloc DMA memory
- * @dev: struct device pointer to the PCI device of the I2O controller
- * @addr: pointer to a i2o_dma struct DMA buffer
- * @len: new length of memory
- *
- * If there was something allocated in the addr, free it first. If len > 0
- * than try to allocate it and write the addresses back to the addr
- * structure. If len == 0 set the virtual address to NULL.
- *
- * Returns the 0 on success or negative error code on failure.
- */
-int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len)
-{
- i2o_dma_free(dev, addr);
-
- if (len)
- return i2o_dma_alloc(dev, addr, len);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(i2o_dma_realloc);
-
-/*
- * i2o_pool_alloc - Allocate an slab cache and mempool
- * @mempool: pointer to struct i2o_pool to write data into.
- * @name: name which is used to identify cache
- * @size: size of each object
- * @min_nr: minimum number of objects
- *
- * First allocates a slab cache with name and size. Then allocates a
- * mempool which uses the slab cache for allocation and freeing.
- *
- * Returns 0 on success or negative error code on failure.
- */
-int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
- size_t size, int min_nr)
-{
- pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
- if (!pool->name)
- goto exit;
- strcpy(pool->name, name);
-
- pool->slab =
- kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!pool->slab)
- goto free_name;
-
- pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
- if (!pool->mempool)
- goto free_slab;
-
- return 0;
-
-free_slab:
- kmem_cache_destroy(pool->slab);
-
-free_name:
- kfree(pool->name);
-
-exit:
- return -ENOMEM;
-}
-EXPORT_SYMBOL_GPL(i2o_pool_alloc);
-
-/*
- * i2o_pool_free - Free slab cache and mempool again
- * @mempool: pointer to struct i2o_pool which should be freed
- *
- * Note that you have to return all objects to the mempool again before
- * calling i2o_pool_free().
- */
-void i2o_pool_free(struct i2o_pool *pool)
-{
- mempool_destroy(pool->mempool);
- kmem_cache_destroy(pool->slab);
- kfree(pool->name);
-};
-EXPORT_SYMBOL_GPL(i2o_pool_free);
diff --git a/drivers/message/i2o/pci.c b/drivers/message/i2o/pci.c
deleted file mode 100644
index 0f9f3e1a2b6b..000000000000
--- a/drivers/message/i2o/pci.c
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * PCI handling of I2O controller
- *
- * Copyright (C) 1999-2002 Red Hat Software
- *
- * Written by Alan Cox, Building Number Three 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.
- *
- * A lot of the I2O message side code from this is taken from the Red
- * Creek RCPCI45 adapter driver by Red Creek Communications
- *
- * Fixes/additions:
- * Philipp Rumpf
- * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
- * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
- * Deepak Saxena <deepak@plexity.net>
- * Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
- * Alan Cox <alan@lxorguk.ukuu.org.uk>:
- * Ported to Linux 2.5.
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Minor fixes for 2.6.
- * Markus Lidel <Markus.Lidel@shadowconnect.com>:
- * Support for sysfs included.
- */
-
-#include <linux/pci.h>
-#include <linux/interrupt.h>
-#include <linux/slab.h>
-#include <linux/i2o.h>
-#include <linux/module.h>
-#include "core.h"
-
-#define OSM_DESCRIPTION "I2O-subsystem"
-
-/* PCI device id table for all I2O controllers */
-static struct pci_device_id i2o_pci_ids[] = {
- {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
- {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
- {.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
- .subvendor = PCI_VENDOR_ID_PROMISE,.subdevice = PCI_ANY_ID},
- {0}
-};
-
-/**
- * i2o_pci_free - Frees the DMA memory for the I2O controller
- * @c: I2O controller to free
- *
- * Remove all allocated DMA memory and unmap memory IO regions. If MTRR
- * is enabled, also remove it again.
- */
-static void i2o_pci_free(struct i2o_controller *c)
-{
- struct device *dev;
-
- dev = &c->pdev->dev;
-
- i2o_dma_free(dev, &c->out_queue);
- i2o_dma_free(dev, &c->status_block);
- kfree(c->lct);
- i2o_dma_free(dev, &c->dlct);
- i2o_dma_free(dev, &c->hrt);
- i2o_dma_free(dev, &c->status);
-
- if (c->raptor && c->in_queue.virt)
- iounmap(c->in_queue.virt);
-
- if (c->base.virt)
- iounmap(c->base.virt);
-
- pci_release_regions(c->pdev);
-}
-
-/**
- * i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller
- * @c: I2O controller
- *
- * Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All
- * IO mappings are also done here. If MTRR is enabled, also do add memory
- * regions here.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_pci_alloc(struct i2o_controller *c)
-{
- struct pci_dev *pdev = c->pdev;
- struct device *dev = &pdev->dev;
- int i;
-
- if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
- printk(KERN_ERR "%s: device already claimed\n", c->name);
- return -ENODEV;
- }
-
- for (i = 0; i < 6; i++) {
- /* Skip I/O spaces */
- if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
- if (!c->base.phys) {
- c->base.phys = pci_resource_start(pdev, i);
- c->base.len = pci_resource_len(pdev, i);
-
- /*
- * If we know what card it is, set the size
- * correctly. Code is taken from dpt_i2o.c
- */
- if (pdev->device == 0xa501) {
- if (pdev->subsystem_device >= 0xc032 &&
- pdev->subsystem_device <= 0xc03b) {
- if (c->base.len > 0x400000)
- c->base.len = 0x400000;
- } else {
- if (c->base.len > 0x100000)
- c->base.len = 0x100000;
- }
- }
- if (!c->raptor)
- break;
- } else {
- c->in_queue.phys = pci_resource_start(pdev, i);
- c->in_queue.len = pci_resource_len(pdev, i);
- break;
- }
- }
- }
-
- if (i == 6) {
- printk(KERN_ERR "%s: I2O controller has no memory regions"
- " defined.\n", c->name);
- i2o_pci_free(c);
- return -EINVAL;
- }
-
- /* Map the I2O controller */
- if (c->raptor) {
- printk(KERN_INFO "%s: PCI I2O controller\n", c->name);
- printk(KERN_INFO " BAR0 at 0x%08lX size=%ld\n",
- (unsigned long)c->base.phys, (unsigned long)c->base.len);
- printk(KERN_INFO " BAR1 at 0x%08lX size=%ld\n",
- (unsigned long)c->in_queue.phys,
- (unsigned long)c->in_queue.len);
- } else
- printk(KERN_INFO "%s: PCI I2O controller at %08lX size=%ld\n",
- c->name, (unsigned long)c->base.phys,
- (unsigned long)c->base.len);
-
- c->base.virt = ioremap_nocache(c->base.phys, c->base.len);
- if (!c->base.virt) {
- printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
- i2o_pci_free(c);
- return -ENOMEM;
- }
-
- if (c->raptor) {
- c->in_queue.virt =
- ioremap_nocache(c->in_queue.phys, c->in_queue.len);
- if (!c->in_queue.virt) {
- printk(KERN_ERR "%s: Unable to map controller.\n",
- c->name);
- i2o_pci_free(c);
- return -ENOMEM;
- }
- } else
- c->in_queue = c->base;
-
- c->irq_status = c->base.virt + I2O_IRQ_STATUS;
- c->irq_mask = c->base.virt + I2O_IRQ_MASK;
- c->in_port = c->base.virt + I2O_IN_PORT;
- c->out_port = c->base.virt + I2O_OUT_PORT;
-
- /* Motorola/Freescale chip does not follow spec */
- if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
- /* Check if CPU is enabled */
- if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
- printk(KERN_INFO "%s: MPC82XX needs CPU running to "
- "service I2O.\n", c->name);
- i2o_pci_free(c);
- return -ENODEV;
- } else {
- c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
- c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
- c->in_port += I2O_MOTOROLA_PORT_OFFSET;
- c->out_port += I2O_MOTOROLA_PORT_OFFSET;
- printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
- c->name);
- }
- }
-
- if (i2o_dma_alloc(dev, &c->status, 8)) {
- i2o_pci_free(c);
- return -ENOMEM;
- }
-
- if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) {
- i2o_pci_free(c);
- return -ENOMEM;
- }
-
- if (i2o_dma_alloc(dev, &c->dlct, 8192)) {
- i2o_pci_free(c);
- return -ENOMEM;
- }
-
- if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) {
- i2o_pci_free(c);
- return -ENOMEM;
- }
-
- if (i2o_dma_alloc(dev, &c->out_queue,
- I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
- sizeof(u32))) {
- i2o_pci_free(c);
- return -ENOMEM;
- }
-
- pci_set_drvdata(pdev, c);
-
- return 0;
-}
-
-/**
- * i2o_pci_interrupt - Interrupt handler for I2O controller
- * @irq: interrupt line
- * @dev_id: pointer to the I2O controller
- *
- * Handle an interrupt from a PCI based I2O controller. This turns out
- * to be rather simple. We keep the controller pointer in the cookie.
- */
-static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id)
-{
- struct i2o_controller *c = dev_id;
- u32 m;
- irqreturn_t rc = IRQ_NONE;
-
- while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
- m = readl(c->out_port);
- if (m == I2O_QUEUE_EMPTY) {
- /*
- * Old 960 steppings had a bug in the I2O unit that
- * caused the queue to appear empty when it wasn't.
- */
- m = readl(c->out_port);
- if (unlikely(m == I2O_QUEUE_EMPTY))
- break;
- }
-
- /* dispatch it */
- if (i2o_driver_dispatch(c, m))
- /* flush it if result != 0 */
- i2o_flush_reply(c, m);
-
- rc = IRQ_HANDLED;
- }
-
- return rc;
-}
-
-/**
- * i2o_pci_irq_enable - Allocate interrupt for I2O controller
- * @c: i2o_controller that the request is for
- *
- * Allocate an interrupt for the I2O controller, and activate interrupts
- * on the I2O controller.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_pci_irq_enable(struct i2o_controller *c)
-{
- struct pci_dev *pdev = c->pdev;
- int rc;
-
- writel(0xffffffff, c->irq_mask);
-
- if (pdev->irq) {
- rc = request_irq(pdev->irq, i2o_pci_interrupt, IRQF_SHARED,
- c->name, c);
- if (rc < 0) {
- printk(KERN_ERR "%s: unable to allocate interrupt %d."
- "\n", c->name, pdev->irq);
- return rc;
- }
- }
-
- writel(0x00000000, c->irq_mask);
-
- printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
-
- return 0;
-}
-
-/**
- * i2o_pci_irq_disable - Free interrupt for I2O controller
- * @c: I2O controller
- *
- * Disable interrupts in I2O controller and then free interrupt.
- */
-static void i2o_pci_irq_disable(struct i2o_controller *c)
-{
- writel(0xffffffff, c->irq_mask);
-
- if (c->pdev->irq > 0)
- free_irq(c->pdev->irq, c);
-}
-
-/**
- * i2o_pci_probe - Probe the PCI device for an I2O controller
- * @pdev: PCI device to test
- * @id: id which matched with the PCI device id table
- *
- * Probe the PCI device for any device which is a memory of the
- * Intelligent, I2O class or an Adaptec Zero Channel Controller. We
- * attempt to set up each such device and register it with the core.
- *
- * Returns 0 on success or negative error code on failure.
- */
-static int i2o_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct i2o_controller *c;
- int rc;
- struct pci_dev *i960 = NULL;
-
- printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
-
- if ((pdev->class & 0xff) > 1) {
- printk(KERN_WARNING "i2o: %s does not support I2O 1.5 "
- "(skipping).\n", pci_name(pdev));
- return -ENODEV;
- }
-
- if ((rc = pci_enable_device(pdev))) {
- printk(KERN_WARNING "i2o: couldn't enable device %s\n",
- pci_name(pdev));
- return rc;
- }
-
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
- printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
- pci_name(pdev));
- rc = -ENODEV;
- goto disable;
- }
-
- pci_set_master(pdev);
-
- c = i2o_iop_alloc();
- if (IS_ERR(c)) {
- printk(KERN_ERR "i2o: couldn't allocate memory for %s\n",
- pci_name(pdev));
- rc = PTR_ERR(c);
- goto disable;
- } else
- printk(KERN_INFO "%s: controller found (%s)\n", c->name,
- pci_name(pdev));
-
- c->pdev = pdev;
- c->device.parent = &pdev->dev;
-
- /* Cards that fall apart if you hit them with large I/O loads... */
- if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) {
- c->short_req = 1;
- printk(KERN_INFO "%s: Symbios FC920 workarounds activated.\n",
- c->name);
- }
-
- if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
- /*
- * Expose the ship behind i960 for initialization, or it will
- * failed
- */
- i960 = pci_get_slot(c->pdev->bus,
- PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
-
- if (i960) {
- pci_write_config_word(i960, 0x42, 0);
- pci_dev_put(i960);
- }
-
- c->promise = 1;
- c->limit_sectors = 1;
- }
-
- if (pdev->subsystem_vendor == PCI_VENDOR_ID_DPT)
- c->adaptec = 1;
-
- /* Cards that go bananas if you quiesce them before you reset them. */
- if (pdev->vendor == PCI_VENDOR_ID_DPT) {
- c->no_quiesce = 1;
- if (pdev->device == 0xa511)
- c->raptor = 1;
-
- if (pdev->subsystem_device == 0xc05a) {
- c->limit_sectors = 1;
- printk(KERN_INFO
- "%s: limit sectors per request to %d\n", c->name,
- I2O_MAX_SECTORS_LIMITED);
- }
-#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
- if (sizeof(dma_addr_t) > 4) {
- if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
- printk(KERN_INFO "%s: 64-bit DMA unavailable\n",
- c->name);
- else {
- c->pae_support = 1;
- printk(KERN_INFO "%s: using 64-bit DMA\n",
- c->name);
- }
- }
-#endif
- }
-
- if ((rc = i2o_pci_alloc(c))) {
- printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
- "failed\n", c->name);
- goto free_controller;
- }
-
- if (i2o_pci_irq_enable(c)) {
- printk(KERN_ERR "%s: unable to enable interrupts for I2O "
- "controller\n", c->name);
- goto free_pci;
- }
-
- if ((rc = i2o_iop_add(c)))
- goto uninstall;
-
- if (i960)
- pci_write_config_word(i960, 0x42, 0x03ff);
-
- return 0;
-
- uninstall:
- i2o_pci_irq_disable(c);
-
- free_pci:
- i2o_pci_free(c);
-
- free_controller:
- i2o_iop_free(c);
-
- disable:
- pci_disable_device(pdev);
-
- return rc;
-}
-
-/**
- * i2o_pci_remove - Removes a I2O controller from the system
- * @pdev: I2O controller which should be removed
- *
- * Reset the I2O controller, disable interrupts and remove all allocated
- * resources.
- */
-static void i2o_pci_remove(struct pci_dev *pdev)
-{
- struct i2o_controller *c;
- c = pci_get_drvdata(pdev);
-
- i2o_iop_remove(c);
- i2o_pci_irq_disable(c);
- i2o_pci_free(c);
-
- pci_disable_device(pdev);
-
- printk(KERN_INFO "%s: Controller removed.\n", c->name);
-
- put_device(&c->device);
-};
-
-/* PCI driver for I2O controller */
-static struct pci_driver i2o_pci_driver = {
- .name = "PCI_I2O",
- .id_table = i2o_pci_ids,
- .probe = i2o_pci_probe,
- .remove = i2o_pci_remove,
-};
-
-/**
- * i2o_pci_init - registers I2O PCI driver in PCI subsystem
- *
- * Returns > 0 on success or negative error code on failure.
- */
-int __init i2o_pci_init(void)
-{
- return pci_register_driver(&i2o_pci_driver);
-};
-
-/**
- * i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem
- */
-void __exit i2o_pci_exit(void)
-{
- pci_unregister_driver(&i2o_pci_driver);
-};
-
-MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
diff --git a/drivers/mfd/88pm860x-core.c b/drivers/mfd/88pm860x-core.c
index 3a2604580164..d2a85cde68da 100644
--- a/drivers/mfd/88pm860x-core.c
+++ b/drivers/mfd/88pm860x-core.c
@@ -1111,7 +1111,7 @@ static int verify_addr(struct i2c_client *i2c)
return 0;
}
-static struct regmap_config pm860x_regmap_config = {
+static const struct regmap_config pm860x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 2e6b7311fabc..38356e39adba 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -195,6 +195,18 @@ config MFD_DA9063
Additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_DA9150
+ tristate "Dialog Semiconductor DA9150 Charger Fuel-Gauge chip"
+ depends on I2C=y
+ select MFD_CORE
+ select REGMAP_I2C
+ select REGMAP_IRQ
+ help
+ This adds support for the DA9150 integrated charger and fuel-gauge
+ chip. This driver provides common support for accessing the device.
+ Additional drivers must be enabled in order to use the specific
+ features of the device.
+
config MFD_DLN2
tristate "Diolan DLN2 support"
select MFD_CORE
@@ -417,6 +429,7 @@ config MFD_MAX14577
config MFD_MAX77686
bool "Maxim Semiconductor MAX77686/802 PMIC Support"
depends on I2C=y
+ depends on OF
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
@@ -589,6 +602,20 @@ config MFD_PM8921_CORE
Say M here if you want to include support for PM8921 chip as a module.
This will build a module called "pm8921-core".
+config MFD_QCOM_RPM
+ tristate "Qualcomm Resource Power Manager (RPM)"
+ depends on ARCH_QCOM && OF
+ help
+ If you say yes to this option, support will be included for the
+ Resource Power Manager system found in the Qualcomm 8660, 8960 and
+ 8064 based devices.
+
+ This is required to access many regulators, clocks and bus
+ frequencies controlled by the RPM on these devices.
+
+ Say M here if you want to include support for the Qualcomm RPM as a
+ module. This will build a module called "qcom_rpm".
+
config MFD_SPMI_PMIC
tristate "Qualcomm SPMI PMICs"
depends on ARCH_QCOM || COMPILE_TEST
@@ -623,6 +650,18 @@ config MFD_RTSX_PCI
types of memory cards, such as Memory Stick, Memory Stick Pro,
Secure Digital and MultiMediaCard.
+config MFD_RT5033
+ tristate "Richtek RT5033 Power Management IC"
+ depends on I2C=y
+ select MFD_CORE
+ select REGMAP_I2C
+ help
+ This driver provides for the Richtek RT5033 Power Management IC,
+ which includes the I2C driver and the Core APIs. This driver provides
+ common support for accessing the device. The device supports multiple
+ sub-devices like charger, fuel gauge, flash LED, current source,
+ LDO and Buck.
+
config MFD_RTSX_USB
tristate "Realtek USB card reader"
depends on USB
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 53467e211381..19f3d744e3bd 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -113,7 +113,7 @@ obj-$(CONFIG_MFD_DA9055) += da9055.o
da9063-objs := da9063-core.o da9063-irq.o da9063-i2c.o
obj-$(CONFIG_MFD_DA9063) += da9063.o
-
+obj-$(CONFIG_MFD_DA9150) += da9150-core.o
obj-$(CONFIG_MFD_MAX14577) += max14577.o
obj-$(CONFIG_MFD_MAX77686) += max77686.o
obj-$(CONFIG_MFD_MAX77693) += max77693.o
@@ -153,6 +153,7 @@ obj-$(CONFIG_MFD_SI476X_CORE) += si476x-core.o
obj-$(CONFIG_MFD_CS5535) += cs5535-mfd.o
obj-$(CONFIG_MFD_OMAP_USB_HOST) += omap-usb-host.o omap-usb-tll.o
obj-$(CONFIG_MFD_PM8921_CORE) += pm8921-core.o ssbi.o
+obj-$(CONFIG_MFD_QCOM_RPM) += qcom_rpm.o
obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
@@ -176,6 +177,7 @@ 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
+obj-$(CONFIG_MFD_RT5033) += rt5033.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/da9063-core.c b/drivers/mfd/da9063-core.c
index f38bc98a3c57..facd3610ac77 100644
--- a/drivers/mfd/da9063-core.c
+++ b/drivers/mfd/da9063-core.c
@@ -86,6 +86,7 @@ static const struct mfd_cell da9063_devs[] = {
},
{
.name = DA9063_DRVNAME_WATCHDOG,
+ .of_compatible = "dlg,da9063-watchdog",
},
{
.name = DA9063_DRVNAME_HWMON,
@@ -101,6 +102,7 @@ static const struct mfd_cell da9063_devs[] = {
.name = DA9063_DRVNAME_RTC,
.num_resources = ARRAY_SIZE(da9063_rtc_resources),
.resources = da9063_rtc_resources,
+ .of_compatible = "dlg,da9063-rtc",
},
{
.name = DA9063_DRVNAME_VIBRATION,
diff --git a/drivers/mfd/da9063-i2c.c b/drivers/mfd/da9063-i2c.c
index 21fd8d9a217b..6f3a7c0001f9 100644
--- a/drivers/mfd/da9063-i2c.c
+++ b/drivers/mfd/da9063-i2c.c
@@ -25,6 +25,9 @@
#include <linux/mfd/da9063/pdata.h>
#include <linux/mfd/da9063/registers.h>
+#include <linux/of.h>
+#include <linux/regulator/of_regulator.h>
+
static const struct regmap_range da9063_ad_readable_ranges[] = {
{
.range_min = DA9063_REG_PAGE_CON,
@@ -203,6 +206,11 @@ static struct regmap_config da9063_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
+static const struct of_device_id da9063_dt_ids[] = {
+ { .compatible = "dlg,da9063", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9063_dt_ids);
static int da9063_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -257,6 +265,7 @@ static struct i2c_driver da9063_i2c_driver = {
.driver = {
.name = "da9063",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(da9063_dt_ids),
},
.probe = da9063_i2c_probe,
.remove = da9063_i2c_remove,
diff --git a/drivers/mfd/da9150-core.c b/drivers/mfd/da9150-core.c
new file mode 100644
index 000000000000..4d757b97ef9a
--- /dev/null
+++ b/drivers/mfd/da9150-core.c
@@ -0,0 +1,413 @@
+/*
+ * DA9150 Core MFD Driver
+ *
+ * Copyright (c) 2014 Dialog Semiconductor
+ *
+ * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/irq.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/da9150/core.h>
+#include <linux/mfd/da9150/registers.h>
+
+static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case DA9150_PAGE_CON:
+ case DA9150_STATUS_A:
+ case DA9150_STATUS_B:
+ case DA9150_STATUS_C:
+ case DA9150_STATUS_D:
+ case DA9150_STATUS_E:
+ case DA9150_STATUS_F:
+ case DA9150_STATUS_G:
+ case DA9150_STATUS_H:
+ case DA9150_STATUS_I:
+ case DA9150_STATUS_J:
+ case DA9150_STATUS_K:
+ case DA9150_STATUS_L:
+ case DA9150_STATUS_N:
+ case DA9150_FAULT_LOG_A:
+ case DA9150_FAULT_LOG_B:
+ case DA9150_EVENT_E:
+ case DA9150_EVENT_F:
+ case DA9150_EVENT_G:
+ case DA9150_EVENT_H:
+ case DA9150_CONTROL_B:
+ case DA9150_CONTROL_C:
+ case DA9150_GPADC_MAN:
+ case DA9150_GPADC_RES_A:
+ case DA9150_GPADC_RES_B:
+ case DA9150_ADETVB_CFG_C:
+ case DA9150_ADETD_STAT:
+ case DA9150_ADET_CMPSTAT:
+ case DA9150_ADET_CTRL_A:
+ case DA9150_PPR_TCTR_B:
+ case DA9150_COREBTLD_STAT_A:
+ case DA9150_CORE_DATA_A:
+ case DA9150_CORE_DATA_B:
+ case DA9150_CORE_DATA_C:
+ case DA9150_CORE_DATA_D:
+ case DA9150_CORE2WIRE_STAT_A:
+ case DA9150_FW_CTRL_C:
+ case DA9150_FG_CTRL_B:
+ case DA9150_FW_CTRL_B:
+ case DA9150_GPADC_CMAN:
+ case DA9150_GPADC_CRES_A:
+ case DA9150_GPADC_CRES_B:
+ case DA9150_CC_ICHG_RES_A:
+ case DA9150_CC_ICHG_RES_B:
+ case DA9150_CC_IAVG_RES_A:
+ case DA9150_CC_IAVG_RES_B:
+ case DA9150_TAUX_CTRL_A:
+ case DA9150_TAUX_VALUE_H:
+ case DA9150_TAUX_VALUE_L:
+ case DA9150_TBAT_RES_A:
+ case DA9150_TBAT_RES_B:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static const struct regmap_range_cfg da9150_range_cfg[] = {
+ {
+ .range_min = DA9150_PAGE_CON,
+ .range_max = DA9150_TBAT_RES_B,
+ .selector_reg = DA9150_PAGE_CON,
+ .selector_mask = DA9150_I2C_PAGE_MASK,
+ .selector_shift = DA9150_I2C_PAGE_SHIFT,
+ .window_start = 0,
+ .window_len = 256,
+ },
+};
+
+static struct regmap_config da9150_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .ranges = da9150_range_cfg,
+ .num_ranges = ARRAY_SIZE(da9150_range_cfg),
+ .max_register = DA9150_TBAT_RES_B,
+
+ .cache_type = REGCACHE_RBTREE,
+
+ .volatile_reg = da9150_volatile_reg,
+};
+
+u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
+{
+ int val, ret;
+
+ ret = regmap_read(da9150->regmap, reg, &val);
+ if (ret)
+ dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
+ reg, ret);
+
+ return (u8) val;
+}
+EXPORT_SYMBOL_GPL(da9150_reg_read);
+
+void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
+{
+ int ret;
+
+ ret = regmap_write(da9150->regmap, reg, val);
+ if (ret)
+ dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_reg_write);
+
+void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
+{
+ int ret;
+
+ ret = regmap_update_bits(da9150->regmap, reg, mask, val);
+ if (ret)
+ dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_set_bits);
+
+void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
+{
+ int ret;
+
+ ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
+ if (ret)
+ dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_read);
+
+void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
+{
+ int ret;
+
+ ret = regmap_raw_write(da9150->regmap, reg, buf, count);
+ if (ret)
+ dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
+ reg, ret);
+}
+EXPORT_SYMBOL_GPL(da9150_bulk_write);
+
+static struct regmap_irq da9150_irqs[] = {
+ [DA9150_IRQ_VBUS] = {
+ .reg_offset = 0,
+ .mask = DA9150_E_VBUS_MASK,
+ },
+ [DA9150_IRQ_CHG] = {
+ .reg_offset = 0,
+ .mask = DA9150_E_CHG_MASK,
+ },
+ [DA9150_IRQ_TCLASS] = {
+ .reg_offset = 0,
+ .mask = DA9150_E_TCLASS_MASK,
+ },
+ [DA9150_IRQ_TJUNC] = {
+ .reg_offset = 0,
+ .mask = DA9150_E_TJUNC_MASK,
+ },
+ [DA9150_IRQ_VFAULT] = {
+ .reg_offset = 0,
+ .mask = DA9150_E_VFAULT_MASK,
+ },
+ [DA9150_IRQ_CONF] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_CONF_MASK,
+ },
+ [DA9150_IRQ_DAT] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_DAT_MASK,
+ },
+ [DA9150_IRQ_DTYPE] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_DTYPE_MASK,
+ },
+ [DA9150_IRQ_ID] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_ID_MASK,
+ },
+ [DA9150_IRQ_ADP] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_ADP_MASK,
+ },
+ [DA9150_IRQ_SESS_END] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_SESS_END_MASK,
+ },
+ [DA9150_IRQ_SESS_VLD] = {
+ .reg_offset = 1,
+ .mask = DA9150_E_SESS_VLD_MASK,
+ },
+ [DA9150_IRQ_FG] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_FG_MASK,
+ },
+ [DA9150_IRQ_GP] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_GP_MASK,
+ },
+ [DA9150_IRQ_TBAT] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_TBAT_MASK,
+ },
+ [DA9150_IRQ_GPIOA] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_GPIOA_MASK,
+ },
+ [DA9150_IRQ_GPIOB] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_GPIOB_MASK,
+ },
+ [DA9150_IRQ_GPIOC] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_GPIOC_MASK,
+ },
+ [DA9150_IRQ_GPIOD] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_GPIOD_MASK,
+ },
+ [DA9150_IRQ_GPADC] = {
+ .reg_offset = 2,
+ .mask = DA9150_E_GPADC_MASK,
+ },
+ [DA9150_IRQ_WKUP] = {
+ .reg_offset = 3,
+ .mask = DA9150_E_WKUP_MASK,
+ },
+};
+
+static struct regmap_irq_chip da9150_regmap_irq_chip = {
+ .name = "da9150_irq",
+ .status_base = DA9150_EVENT_E,
+ .mask_base = DA9150_IRQ_MASK_E,
+ .ack_base = DA9150_EVENT_E,
+ .num_regs = DA9150_NUM_IRQ_REGS,
+ .irqs = da9150_irqs,
+ .num_irqs = ARRAY_SIZE(da9150_irqs),
+};
+
+static struct resource da9150_gpadc_resources[] = {
+ {
+ .name = "GPADC",
+ .start = DA9150_IRQ_GPADC,
+ .end = DA9150_IRQ_GPADC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource da9150_charger_resources[] = {
+ {
+ .name = "CHG_STATUS",
+ .start = DA9150_IRQ_CHG,
+ .end = DA9150_IRQ_CHG,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CHG_TJUNC",
+ .start = DA9150_IRQ_TJUNC,
+ .end = DA9150_IRQ_TJUNC,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CHG_VFAULT",
+ .start = DA9150_IRQ_VFAULT,
+ .end = DA9150_IRQ_VFAULT,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .name = "CHG_VBUS",
+ .start = DA9150_IRQ_VBUS,
+ .end = DA9150_IRQ_VBUS,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell da9150_devs[] = {
+ {
+ .name = "da9150-gpadc",
+ .of_compatible = "dlg,da9150-gpadc",
+ .resources = da9150_gpadc_resources,
+ .num_resources = ARRAY_SIZE(da9150_gpadc_resources),
+ },
+ {
+ .name = "da9150-charger",
+ .of_compatible = "dlg,da9150-charger",
+ .resources = da9150_charger_resources,
+ .num_resources = ARRAY_SIZE(da9150_charger_resources),
+ },
+};
+
+static int da9150_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct da9150 *da9150;
+ struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
+ int ret;
+
+ da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
+ if (!da9150)
+ return -ENOMEM;
+
+ da9150->dev = &client->dev;
+ da9150->irq = client->irq;
+ i2c_set_clientdata(client, da9150);
+
+ da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
+ if (IS_ERR(da9150->regmap)) {
+ ret = PTR_ERR(da9150->regmap);
+ dev_err(da9150->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ da9150->irq_base = pdata ? pdata->irq_base : -1;
+
+ ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ da9150->irq_base, &da9150_regmap_irq_chip,
+ &da9150->regmap_irq_data);
+ if (ret)
+ return ret;
+
+ da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
+ enable_irq_wake(da9150->irq);
+
+ ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
+ ARRAY_SIZE(da9150_devs), NULL,
+ da9150->irq_base, NULL);
+ if (ret) {
+ dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
+ regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int da9150_remove(struct i2c_client *client)
+{
+ struct da9150 *da9150 = i2c_get_clientdata(client);
+
+ regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
+ mfd_remove_devices(da9150->dev);
+
+ return 0;
+}
+
+static void da9150_shutdown(struct i2c_client *client)
+{
+ struct da9150 *da9150 = i2c_get_clientdata(client);
+
+ /* Make sure we have a wakup source for the device */
+ da9150_set_bits(da9150, DA9150_CONFIG_D,
+ DA9150_WKUP_PM_EN_MASK,
+ DA9150_WKUP_PM_EN_MASK);
+
+ /* Set device to DISABLED mode */
+ da9150_set_bits(da9150, DA9150_CONTROL_C,
+ DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
+}
+
+static const struct i2c_device_id da9150_i2c_id[] = {
+ { "da9150", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
+
+static const struct of_device_id da9150_of_match[] = {
+ { .compatible = "dlg,da9150", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, da9150_of_match);
+
+static struct i2c_driver da9150_driver = {
+ .driver = {
+ .name = "da9150",
+ .of_match_table = of_match_ptr(da9150_of_match),
+ },
+ .probe = da9150_probe,
+ .remove = da9150_remove,
+ .shutdown = da9150_shutdown,
+ .id_table = da9150_i2c_id,
+};
+
+module_i2c_driver(da9150_driver);
+
+MODULE_DESCRIPTION("MFD Core Driver for DA9150");
+MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/davinci_voicecodec.c b/drivers/mfd/davinci_voicecodec.c
index c835e85539b2..9bbc642a7b9d 100644
--- a/drivers/mfd/davinci_voicecodec.c
+++ b/drivers/mfd/davinci_voicecodec.c
@@ -33,7 +33,7 @@
#include <linux/mfd/davinci_voicecodec.h>
-static struct regmap_config davinci_vc_regmap = {
+static const struct regmap_config davinci_vc_regmap = {
.reg_bits = 32,
.val_bits = 32,
};
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 16162bf43656..cc1a404328c2 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -675,15 +675,6 @@ bool prcmu_has_arm_maxopp(void)
}
/**
- * prcmu_get_boot_status - PRCMU boot status checking
- * Returns: the current PRCMU boot status
- */
-int prcmu_get_boot_status(void)
-{
- return readb(tcdm_base + PRCM_BOOT_STATUS);
-}
-
-/**
* prcmu_set_rc_a2p - This function is used to run few power state sequences
* @val: Value to be set, i.e. transition requested
* Returns: 0 on success, -EINVAL on invalid argument
diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c
index 6d49685d4ee4..1be9bd1c046d 100644
--- a/drivers/mfd/dln2.c
+++ b/drivers/mfd/dln2.c
@@ -587,12 +587,19 @@ 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_stop_rx_urbs(struct dln2_dev *dln2)
+{
+ int i;
+
+ for (i = 0; i < DLN2_MAX_URBS; i++)
+ usb_kill_urb(dln2->rx_urb[i]);
+}
+
static void dln2_free(struct dln2_dev *dln2)
{
dln2_free_rx_urbs(dln2);
@@ -604,9 +611,7 @@ 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);
@@ -620,8 +625,19 @@ static int dln2_setup_rx_urbs(struct dln2_dev *dln2,
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);
+ return 0;
+}
+
+static int dln2_start_rx_urbs(struct dln2_dev *dln2, gfp_t gfp)
+{
+ struct device *dev = &dln2->interface->dev;
+ int ret;
+ int i;
+
+ for (i = 0; i < DLN2_MAX_URBS; i++) {
+ ret = usb_submit_urb(dln2->rx_urb[i], gfp);
if (ret < 0) {
dev_err(dev, "failed to submit RX URB: %d\n", ret);
return ret;
@@ -665,9 +681,8 @@ static const struct mfd_cell dln2_devs[] = {
},
};
-static void dln2_disconnect(struct usb_interface *interface)
+static void dln2_stop(struct dln2_dev *dln2)
{
- struct dln2_dev *dln2 = usb_get_intfdata(interface);
int i, j;
/* don't allow starting new transfers */
@@ -696,6 +711,15 @@ static void dln2_disconnect(struct usb_interface *interface)
/* wait for transfers to end */
wait_event(dln2->disconnect_wq, !dln2->active_transfers);
+ dln2_stop_rx_urbs(dln2);
+}
+
+static void dln2_disconnect(struct usb_interface *interface)
+{
+ struct dln2_dev *dln2 = usb_get_intfdata(interface);
+
+ dln2_stop(dln2);
+
mfd_remove_devices(&interface->dev);
dln2_free(dln2);
@@ -738,28 +762,53 @@ static int dln2_probe(struct usb_interface *interface,
ret = dln2_setup_rx_urbs(dln2, hostif);
if (ret)
- goto out_cleanup;
+ goto out_free;
+
+ ret = dln2_start_rx_urbs(dln2, GFP_KERNEL);
+ if (ret)
+ goto out_stop_rx;
ret = dln2_hw_init(dln2);
if (ret < 0) {
dev_err(dev, "failed to initialize hardware\n");
- goto out_cleanup;
+ goto out_stop_rx;
}
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;
+ goto out_stop_rx;
}
return 0;
-out_cleanup:
+out_stop_rx:
+ dln2_stop_rx_urbs(dln2);
+
+out_free:
dln2_free(dln2);
return ret;
}
+static int dln2_suspend(struct usb_interface *iface, pm_message_t message)
+{
+ struct dln2_dev *dln2 = usb_get_intfdata(iface);
+
+ dln2_stop(dln2);
+
+ return 0;
+}
+
+static int dln2_resume(struct usb_interface *iface)
+{
+ struct dln2_dev *dln2 = usb_get_intfdata(iface);
+
+ dln2->disconnect = false;
+
+ return dln2_start_rx_urbs(dln2, GFP_NOIO);
+}
+
static const struct usb_device_id dln2_table[] = {
{ USB_DEVICE(0xa257, 0x2013) },
{ }
@@ -772,6 +821,8 @@ static struct usb_driver dln2_driver = {
.probe = dln2_probe,
.disconnect = dln2_disconnect,
.id_table = dln2_table,
+ .suspend = dln2_suspend,
+ .resume = dln2_resume,
};
module_usb_driver(dln2_driver);
diff --git a/drivers/mfd/hi6421-pmic-core.c b/drivers/mfd/hi6421-pmic-core.c
index 321a2656fd00..7210ae28bf81 100644
--- a/drivers/mfd/hi6421-pmic-core.c
+++ b/drivers/mfd/hi6421-pmic-core.c
@@ -35,7 +35,7 @@ static const struct mfd_cell hi6421_devs[] = {
{ .name = "hi6421-regulator", },
};
-static struct regmap_config hi6421_regmap_config = {
+static const struct regmap_config hi6421_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 8,
diff --git a/drivers/mfd/intel_soc_pmic_core.c b/drivers/mfd/intel_soc_pmic_core.c
index df7b0642a5b4..80cef048b904 100644
--- a/drivers/mfd/intel_soc_pmic_core.c
+++ b/drivers/mfd/intel_soc_pmic_core.c
@@ -64,6 +64,9 @@ static int intel_soc_pmic_i2c_probe(struct i2c_client *i2c,
config = (struct intel_soc_pmic_config *)id->driver_data;
pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL);
+ if (!pmic)
+ return -ENOMEM;
+
dev_set_drvdata(dev, pmic);
pmic->regmap = devm_regmap_init_i2c(i2c, config->regmap_config);
diff --git a/drivers/mfd/intel_soc_pmic_core.h b/drivers/mfd/intel_soc_pmic_core.h
index 33aacd9baddc..9498d6719847 100644
--- a/drivers/mfd/intel_soc_pmic_core.h
+++ b/drivers/mfd/intel_soc_pmic_core.h
@@ -23,7 +23,7 @@ struct intel_soc_pmic_config {
unsigned long irq_flags;
struct mfd_cell *cell_dev;
int n_cell_devs;
- struct regmap_config *regmap_config;
+ const struct regmap_config *regmap_config;
struct regmap_irq_chip *irq_chip;
};
diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c
index c85e2ecb868a..4cc1b324e971 100644
--- a/drivers/mfd/intel_soc_pmic_crc.c
+++ b/drivers/mfd/intel_soc_pmic_crc.c
@@ -111,7 +111,7 @@ static struct mfd_cell crystal_cove_dev[] = {
},
};
-static struct regmap_config crystal_cove_regmap_config = {
+static const struct regmap_config crystal_cove_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/drivers/mfd/lm3533-core.c b/drivers/mfd/lm3533-core.c
index 8c29f7b27324..d42fbb667d8c 100644
--- a/drivers/mfd/lm3533-core.c
+++ b/drivers/mfd/lm3533-core.c
@@ -583,7 +583,7 @@ static bool lm3533_precious_register(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config regmap_config = {
+static const struct regmap_config regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = LM3533_REG_MAX,
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index 5c38df35a84d..a56e4ba5227b 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -75,6 +75,7 @@ static struct lpc_sch_info sch_chipset_info[] = {
[LPC_QUARK_X1000] = {
.io_size_gpio = GPIO_IO_SIZE,
.irq_gpio = GPIO_IRQ_QUARK_X1000,
+ .io_size_wdt = WDT_IO_SIZE,
},
};
diff --git a/drivers/mfd/max77686.c b/drivers/mfd/max77686.c
index 929795eae9fc..760d08d7923d 100644
--- a/drivers/mfd/max77686.c
+++ b/drivers/mfd/max77686.c
@@ -111,17 +111,17 @@ static bool max77802_is_volatile_reg(struct device *dev, unsigned int reg)
max77802_rtc_is_volatile_reg(dev, reg));
}
-static struct regmap_config max77686_regmap_config = {
+static const struct regmap_config max77686_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
-static struct regmap_config max77686_rtc_regmap_config = {
+static const struct regmap_config max77686_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
-static struct regmap_config max77802_regmap_config = {
+static const struct regmap_config max77802_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.writeable_reg = max77802_is_accessible_reg,
@@ -205,24 +205,10 @@ static const struct of_device_id max77686_pmic_dt_match[] = {
{ },
};
-static struct max77686_platform_data *max77686_i2c_parse_dt_pdata(struct device
- *dev)
-{
- struct max77686_platform_data *pd;
-
- pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return NULL;
-
- dev->platform_data = pd;
- return pd;
-}
-
static int max77686_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct max77686_dev *max77686 = NULL;
- struct max77686_platform_data *pdata = dev_get_platdata(&i2c->dev);
const struct of_device_id *match;
unsigned int data;
int ret = 0;
@@ -233,14 +219,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
const struct mfd_cell *cells;
int n_devs;
- if (IS_ENABLED(CONFIG_OF) && i2c->dev.of_node && !pdata)
- pdata = max77686_i2c_parse_dt_pdata(&i2c->dev);
-
- if (!pdata) {
- dev_err(&i2c->dev, "No platform data found.\n");
- return -EINVAL;
- }
-
max77686 = devm_kzalloc(&i2c->dev,
sizeof(struct max77686_dev), GFP_KERNEL);
if (!max77686)
@@ -259,7 +237,6 @@ static int max77686_i2c_probe(struct i2c_client *i2c,
max77686->dev = &i2c->dev;
max77686->i2c = i2c;
- max77686->wakeup = pdata->wakeup;
max77686->irq = i2c->irq;
if (max77686->type == TYPE_MAX77686) {
diff --git a/drivers/mfd/mc13xxx-i2c.c b/drivers/mfd/mc13xxx-i2c.c
index ae3addb153a2..68b844811566 100644
--- a/drivers/mfd/mc13xxx-i2c.c
+++ b/drivers/mfd/mc13xxx-i2c.c
@@ -46,7 +46,7 @@ static const struct of_device_id mc13xxx_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
-static struct regmap_config mc13xxx_regmap_i2c_config = {
+static const struct regmap_config mc13xxx_regmap_i2c_config = {
.reg_bits = 8,
.val_bits = 24,
diff --git a/drivers/mfd/mc13xxx-spi.c b/drivers/mfd/mc13xxx-spi.c
index 702925e242c9..58a170e45d88 100644
--- a/drivers/mfd/mc13xxx-spi.c
+++ b/drivers/mfd/mc13xxx-spi.c
@@ -48,7 +48,7 @@ static const struct of_device_id mc13xxx_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mc13xxx_dt_ids);
-static struct regmap_config mc13xxx_regmap_spi_config = {
+static const struct regmap_config mc13xxx_regmap_spi_config = {
.reg_bits = 7,
.pad_bits = 1,
.val_bits = 24,
diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c
index 04cd54dd507c..1d924d1533c0 100644
--- a/drivers/mfd/omap-usb-host.c
+++ b/drivers/mfd/omap-usb-host.c
@@ -129,16 +129,6 @@ static inline u32 usbhs_read(void __iomem *base, u32 reg)
return readl_relaxed(base + reg);
}
-static inline void usbhs_writeb(void __iomem *base, u8 reg, u8 val)
-{
- writeb_relaxed(val, base + reg);
-}
-
-static inline u8 usbhs_readb(void __iomem *base, u8 reg)
-{
- return readb_relaxed(base + reg);
-}
-
/*-------------------------------------------------------------------------*/
/**
diff --git a/drivers/mfd/pcf50633-core.c b/drivers/mfd/pcf50633-core.c
index 43664eb69c93..6155d123a84e 100644
--- a/drivers/mfd/pcf50633-core.c
+++ b/drivers/mfd/pcf50633-core.c
@@ -183,7 +183,7 @@ static int pcf50633_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(pcf50633_pm, pcf50633_suspend, pcf50633_resume);
-static struct regmap_config pcf50633_regmap_config = {
+static const struct regmap_config pcf50633_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
diff --git a/drivers/mfd/qcom_rpm.c b/drivers/mfd/qcom_rpm.c
new file mode 100644
index 000000000000..f696328c2933
--- /dev/null
+++ b/drivers/mfd/qcom_rpm.c
@@ -0,0 +1,581 @@
+/*
+ * Copyright (c) 2014, Sony Mobile Communications AB.
+ * Copyright (c) 2013, The Linux Foundation. All rights reserved.
+ * Author: Bjorn Andersson <bjorn.andersson@sonymobile.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 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/module.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/qcom_rpm.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include <dt-bindings/mfd/qcom-rpm.h>
+
+struct qcom_rpm_resource {
+ unsigned target_id;
+ unsigned status_id;
+ unsigned select_id;
+ unsigned size;
+};
+
+struct qcom_rpm_data {
+ u32 version;
+ const struct qcom_rpm_resource *resource_table;
+ unsigned n_resources;
+};
+
+struct qcom_rpm {
+ struct device *dev;
+ struct regmap *ipc_regmap;
+ unsigned ipc_offset;
+ unsigned ipc_bit;
+
+ struct completion ack;
+ struct mutex lock;
+
+ void __iomem *status_regs;
+ void __iomem *ctrl_regs;
+ void __iomem *req_regs;
+
+ u32 ack_status;
+
+ const struct qcom_rpm_data *data;
+};
+
+#define RPM_STATUS_REG(rpm, i) ((rpm)->status_regs + (i) * 4)
+#define RPM_CTRL_REG(rpm, i) ((rpm)->ctrl_regs + (i) * 4)
+#define RPM_REQ_REG(rpm, i) ((rpm)->req_regs + (i) * 4)
+
+#define RPM_REQUEST_TIMEOUT (5 * HZ)
+
+#define RPM_REQUEST_CONTEXT 3
+#define RPM_REQ_SELECT 11
+#define RPM_ACK_CONTEXT 15
+#define RPM_ACK_SELECTOR 23
+#define RPM_SELECT_SIZE 7
+
+#define RPM_NOTIFICATION BIT(30)
+#define RPM_REJECTED BIT(31)
+
+#define RPM_SIGNAL BIT(2)
+
+static const struct qcom_rpm_resource apq8064_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 },
+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 },
+ [QCOM_RPM_MM_FABRIC_CLK] = { 29, 13, 10, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 },
+ [QCOM_RPM_MMFPB_CLK] = { 33, 17, 14, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 1 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 1 },
+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 },
+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 1 },
+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 1 },
+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 },
+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 30 },
+ [QCOM_RPM_MM_FABRIC_HALT] = { 89, 27, 26, 1 },
+ [QCOM_RPM_MM_FABRIC_MODE] = { 91, 28, 27, 1 },
+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 94, 29, 28, 1 },
+ [QCOM_RPM_MM_FABRIC_ARB] = { 95, 30, 29, 21 },
+ [QCOM_RPM_PM8921_SMPS1] = { 116, 31, 30, 2 },
+ [QCOM_RPM_PM8921_SMPS2] = { 118, 33, 31, 2 },
+ [QCOM_RPM_PM8921_SMPS3] = { 120, 35, 32, 2 },
+ [QCOM_RPM_PM8921_SMPS4] = { 122, 37, 33, 2 },
+ [QCOM_RPM_PM8921_SMPS5] = { 124, 39, 34, 2 },
+ [QCOM_RPM_PM8921_SMPS6] = { 126, 41, 35, 2 },
+ [QCOM_RPM_PM8921_SMPS7] = { 128, 43, 36, 2 },
+ [QCOM_RPM_PM8921_SMPS8] = { 130, 45, 37, 2 },
+ [QCOM_RPM_PM8921_LDO1] = { 132, 47, 38, 2 },
+ [QCOM_RPM_PM8921_LDO2] = { 134, 49, 39, 2 },
+ [QCOM_RPM_PM8921_LDO3] = { 136, 51, 40, 2 },
+ [QCOM_RPM_PM8921_LDO4] = { 138, 53, 41, 2 },
+ [QCOM_RPM_PM8921_LDO5] = { 140, 55, 42, 2 },
+ [QCOM_RPM_PM8921_LDO6] = { 142, 57, 43, 2 },
+ [QCOM_RPM_PM8921_LDO7] = { 144, 59, 44, 2 },
+ [QCOM_RPM_PM8921_LDO8] = { 146, 61, 45, 2 },
+ [QCOM_RPM_PM8921_LDO9] = { 148, 63, 46, 2 },
+ [QCOM_RPM_PM8921_LDO10] = { 150, 65, 47, 2 },
+ [QCOM_RPM_PM8921_LDO11] = { 152, 67, 48, 2 },
+ [QCOM_RPM_PM8921_LDO12] = { 154, 69, 49, 2 },
+ [QCOM_RPM_PM8921_LDO13] = { 156, 71, 50, 2 },
+ [QCOM_RPM_PM8921_LDO14] = { 158, 73, 51, 2 },
+ [QCOM_RPM_PM8921_LDO15] = { 160, 75, 52, 2 },
+ [QCOM_RPM_PM8921_LDO16] = { 162, 77, 53, 2 },
+ [QCOM_RPM_PM8921_LDO17] = { 164, 79, 54, 2 },
+ [QCOM_RPM_PM8921_LDO18] = { 166, 81, 55, 2 },
+ [QCOM_RPM_PM8921_LDO19] = { 168, 83, 56, 2 },
+ [QCOM_RPM_PM8921_LDO20] = { 170, 85, 57, 2 },
+ [QCOM_RPM_PM8921_LDO21] = { 172, 87, 58, 2 },
+ [QCOM_RPM_PM8921_LDO22] = { 174, 89, 59, 2 },
+ [QCOM_RPM_PM8921_LDO23] = { 176, 91, 60, 2 },
+ [QCOM_RPM_PM8921_LDO24] = { 178, 93, 61, 2 },
+ [QCOM_RPM_PM8921_LDO25] = { 180, 95, 62, 2 },
+ [QCOM_RPM_PM8921_LDO26] = { 182, 97, 63, 2 },
+ [QCOM_RPM_PM8921_LDO27] = { 184, 99, 64, 2 },
+ [QCOM_RPM_PM8921_LDO28] = { 186, 101, 65, 2 },
+ [QCOM_RPM_PM8921_LDO29] = { 188, 103, 66, 2 },
+ [QCOM_RPM_PM8921_CLK1] = { 190, 105, 67, 2 },
+ [QCOM_RPM_PM8921_CLK2] = { 192, 107, 68, 2 },
+ [QCOM_RPM_PM8921_LVS1] = { 194, 109, 69, 1 },
+ [QCOM_RPM_PM8921_LVS2] = { 195, 110, 70, 1 },
+ [QCOM_RPM_PM8921_LVS3] = { 196, 111, 71, 1 },
+ [QCOM_RPM_PM8921_LVS4] = { 197, 112, 72, 1 },
+ [QCOM_RPM_PM8921_LVS5] = { 198, 113, 73, 1 },
+ [QCOM_RPM_PM8921_LVS6] = { 199, 114, 74, 1 },
+ [QCOM_RPM_PM8921_LVS7] = { 200, 115, 75, 1 },
+ [QCOM_RPM_PM8821_SMPS1] = { 201, 116, 76, 2 },
+ [QCOM_RPM_PM8821_SMPS2] = { 203, 118, 77, 2 },
+ [QCOM_RPM_PM8821_LDO1] = { 205, 120, 78, 2 },
+ [QCOM_RPM_PM8921_NCP] = { 207, 122, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 209, 124, 81, 1 },
+ [QCOM_RPM_USB_OTG_SWITCH] = { 210, 125, 82, 1 },
+ [QCOM_RPM_HDMI_SWITCH] = { 211, 126, 83, 1 },
+ [QCOM_RPM_DDR_DMM] = { 212, 127, 84, 2 },
+ [QCOM_RPM_VDDMIN_GPIO] = { 215, 131, 89, 1 },
+};
+
+static const struct qcom_rpm_data apq8064_template = {
+ .version = 3,
+ .resource_table = apq8064_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(apq8064_rpm_resource_table),
+};
+
+static const struct qcom_rpm_resource msm8660_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 32, 12, 5, 1 },
+ [QCOM_RPM_PXO_CLK] = { 33, 13, 6, 1 },
+ [QCOM_RPM_PLL_4] = { 34, 14, 7, 1 },
+ [QCOM_RPM_APPS_FABRIC_CLK] = { 35, 15, 8, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 36, 16, 9, 1 },
+ [QCOM_RPM_MM_FABRIC_CLK] = { 37, 17, 10, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 38, 18, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 39, 19, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 40, 20, 13, 1 },
+ [QCOM_RPM_MMFPB_CLK] = { 41, 21, 14, 1 },
+ [QCOM_RPM_SMI_CLK] = { 42, 22, 15, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 43, 23, 16, 1 },
+ [QCOM_RPM_APPS_L2_CACHE_CTL] = { 44, 24, 17, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 45, 25, 18, 2 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 47, 26, 19, 3 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 51, 28, 21, 6 },
+ [QCOM_RPM_SYS_FABRIC_HALT] = { 63, 29, 22, 2 },
+ [QCOM_RPM_SYS_FABRIC_MODE] = { 65, 30, 23, 3 },
+ [QCOM_RPM_SYS_FABRIC_ARB] = { 69, 32, 25, 22 },
+ [QCOM_RPM_MM_FABRIC_HALT] = { 105, 33, 26, 2 },
+ [QCOM_RPM_MM_FABRIC_MODE] = { 107, 34, 27, 3 },
+ [QCOM_RPM_MM_FABRIC_ARB] = { 111, 36, 29, 23 },
+ [QCOM_RPM_PM8901_SMPS0] = { 134, 37, 30, 2 },
+ [QCOM_RPM_PM8901_SMPS1] = { 136, 39, 31, 2 },
+ [QCOM_RPM_PM8901_SMPS2] = { 138, 41, 32, 2 },
+ [QCOM_RPM_PM8901_SMPS3] = { 140, 43, 33, 2 },
+ [QCOM_RPM_PM8901_SMPS4] = { 142, 45, 34, 2 },
+ [QCOM_RPM_PM8901_LDO0] = { 144, 47, 35, 2 },
+ [QCOM_RPM_PM8901_LDO1] = { 146, 49, 36, 2 },
+ [QCOM_RPM_PM8901_LDO2] = { 148, 51, 37, 2 },
+ [QCOM_RPM_PM8901_LDO3] = { 150, 53, 38, 2 },
+ [QCOM_RPM_PM8901_LDO4] = { 152, 55, 39, 2 },
+ [QCOM_RPM_PM8901_LDO5] = { 154, 57, 40, 2 },
+ [QCOM_RPM_PM8901_LDO6] = { 156, 59, 41, 2 },
+ [QCOM_RPM_PM8901_LVS0] = { 158, 61, 42, 1 },
+ [QCOM_RPM_PM8901_LVS1] = { 159, 62, 43, 1 },
+ [QCOM_RPM_PM8901_LVS2] = { 160, 63, 44, 1 },
+ [QCOM_RPM_PM8901_LVS3] = { 161, 64, 45, 1 },
+ [QCOM_RPM_PM8901_MVS] = { 162, 65, 46, 1 },
+ [QCOM_RPM_PM8058_SMPS0] = { 163, 66, 47, 2 },
+ [QCOM_RPM_PM8058_SMPS1] = { 165, 68, 48, 2 },
+ [QCOM_RPM_PM8058_SMPS2] = { 167, 70, 49, 2 },
+ [QCOM_RPM_PM8058_SMPS3] = { 169, 72, 50, 2 },
+ [QCOM_RPM_PM8058_SMPS4] = { 171, 74, 51, 2 },
+ [QCOM_RPM_PM8058_LDO0] = { 173, 76, 52, 2 },
+ [QCOM_RPM_PM8058_LDO1] = { 175, 78, 53, 2 },
+ [QCOM_RPM_PM8058_LDO2] = { 177, 80, 54, 2 },
+ [QCOM_RPM_PM8058_LDO3] = { 179, 82, 55, 2 },
+ [QCOM_RPM_PM8058_LDO4] = { 181, 84, 56, 2 },
+ [QCOM_RPM_PM8058_LDO5] = { 183, 86, 57, 2 },
+ [QCOM_RPM_PM8058_LDO6] = { 185, 88, 58, 2 },
+ [QCOM_RPM_PM8058_LDO7] = { 187, 90, 59, 2 },
+ [QCOM_RPM_PM8058_LDO8] = { 189, 92, 60, 2 },
+ [QCOM_RPM_PM8058_LDO9] = { 191, 94, 61, 2 },
+ [QCOM_RPM_PM8058_LDO10] = { 193, 96, 62, 2 },
+ [QCOM_RPM_PM8058_LDO11] = { 195, 98, 63, 2 },
+ [QCOM_RPM_PM8058_LDO12] = { 197, 100, 64, 2 },
+ [QCOM_RPM_PM8058_LDO13] = { 199, 102, 65, 2 },
+ [QCOM_RPM_PM8058_LDO14] = { 201, 104, 66, 2 },
+ [QCOM_RPM_PM8058_LDO15] = { 203, 106, 67, 2 },
+ [QCOM_RPM_PM8058_LDO16] = { 205, 108, 68, 2 },
+ [QCOM_RPM_PM8058_LDO17] = { 207, 110, 69, 2 },
+ [QCOM_RPM_PM8058_LDO18] = { 209, 112, 70, 2 },
+ [QCOM_RPM_PM8058_LDO19] = { 211, 114, 71, 2 },
+ [QCOM_RPM_PM8058_LDO20] = { 213, 116, 72, 2 },
+ [QCOM_RPM_PM8058_LDO21] = { 215, 118, 73, 2 },
+ [QCOM_RPM_PM8058_LDO22] = { 217, 120, 74, 2 },
+ [QCOM_RPM_PM8058_LDO23] = { 219, 122, 75, 2 },
+ [QCOM_RPM_PM8058_LDO24] = { 221, 124, 76, 2 },
+ [QCOM_RPM_PM8058_LDO25] = { 223, 126, 77, 2 },
+ [QCOM_RPM_PM8058_LVS0] = { 225, 128, 78, 1 },
+ [QCOM_RPM_PM8058_LVS1] = { 226, 129, 79, 1 },
+ [QCOM_RPM_PM8058_NCP] = { 227, 130, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 229, 132, 81, 1 },
+};
+
+static const struct qcom_rpm_data msm8660_template = {
+ .version = 2,
+ .resource_table = msm8660_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(msm8660_rpm_resource_table),
+};
+
+static const struct qcom_rpm_resource msm8960_rpm_resource_table[] = {
+ [QCOM_RPM_CXO_CLK] = { 25, 9, 5, 1 },
+ [QCOM_RPM_PXO_CLK] = { 26, 10, 6, 1 },
+ [QCOM_RPM_APPS_FABRIC_CLK] = { 27, 11, 8, 1 },
+ [QCOM_RPM_SYS_FABRIC_CLK] = { 28, 12, 9, 1 },
+ [QCOM_RPM_MM_FABRIC_CLK] = { 29, 13, 10, 1 },
+ [QCOM_RPM_DAYTONA_FABRIC_CLK] = { 30, 14, 11, 1 },
+ [QCOM_RPM_SFPB_CLK] = { 31, 15, 12, 1 },
+ [QCOM_RPM_CFPB_CLK] = { 32, 16, 13, 1 },
+ [QCOM_RPM_MMFPB_CLK] = { 33, 17, 14, 1 },
+ [QCOM_RPM_EBI1_CLK] = { 34, 18, 16, 1 },
+ [QCOM_RPM_APPS_FABRIC_HALT] = { 35, 19, 18, 1 },
+ [QCOM_RPM_APPS_FABRIC_MODE] = { 37, 20, 19, 1 },
+ [QCOM_RPM_APPS_FABRIC_IOCTL] = { 40, 21, 20, 1 },
+ [QCOM_RPM_APPS_FABRIC_ARB] = { 41, 22, 21, 12 },
+ [QCOM_RPM_SYS_FABRIC_HALT] = { 53, 23, 22, 1 },
+ [QCOM_RPM_SYS_FABRIC_MODE] = { 55, 24, 23, 1 },
+ [QCOM_RPM_SYS_FABRIC_IOCTL] = { 58, 25, 24, 1 },
+ [QCOM_RPM_SYS_FABRIC_ARB] = { 59, 26, 25, 29 },
+ [QCOM_RPM_MM_FABRIC_HALT] = { 88, 27, 26, 1 },
+ [QCOM_RPM_MM_FABRIC_MODE] = { 90, 28, 27, 1 },
+ [QCOM_RPM_MM_FABRIC_IOCTL] = { 93, 29, 28, 1 },
+ [QCOM_RPM_MM_FABRIC_ARB] = { 94, 30, 29, 23 },
+ [QCOM_RPM_PM8921_SMPS1] = { 117, 31, 30, 2 },
+ [QCOM_RPM_PM8921_SMPS2] = { 119, 33, 31, 2 },
+ [QCOM_RPM_PM8921_SMPS3] = { 121, 35, 32, 2 },
+ [QCOM_RPM_PM8921_SMPS4] = { 123, 37, 33, 2 },
+ [QCOM_RPM_PM8921_SMPS5] = { 125, 39, 34, 2 },
+ [QCOM_RPM_PM8921_SMPS6] = { 127, 41, 35, 2 },
+ [QCOM_RPM_PM8921_SMPS7] = { 129, 43, 36, 2 },
+ [QCOM_RPM_PM8921_SMPS8] = { 131, 45, 37, 2 },
+ [QCOM_RPM_PM8921_LDO1] = { 133, 47, 38, 2 },
+ [QCOM_RPM_PM8921_LDO2] = { 135, 49, 39, 2 },
+ [QCOM_RPM_PM8921_LDO3] = { 137, 51, 40, 2 },
+ [QCOM_RPM_PM8921_LDO4] = { 139, 53, 41, 2 },
+ [QCOM_RPM_PM8921_LDO5] = { 141, 55, 42, 2 },
+ [QCOM_RPM_PM8921_LDO6] = { 143, 57, 43, 2 },
+ [QCOM_RPM_PM8921_LDO7] = { 145, 59, 44, 2 },
+ [QCOM_RPM_PM8921_LDO8] = { 147, 61, 45, 2 },
+ [QCOM_RPM_PM8921_LDO9] = { 149, 63, 46, 2 },
+ [QCOM_RPM_PM8921_LDO10] = { 151, 65, 47, 2 },
+ [QCOM_RPM_PM8921_LDO11] = { 153, 67, 48, 2 },
+ [QCOM_RPM_PM8921_LDO12] = { 155, 69, 49, 2 },
+ [QCOM_RPM_PM8921_LDO13] = { 157, 71, 50, 2 },
+ [QCOM_RPM_PM8921_LDO14] = { 159, 73, 51, 2 },
+ [QCOM_RPM_PM8921_LDO15] = { 161, 75, 52, 2 },
+ [QCOM_RPM_PM8921_LDO16] = { 163, 77, 53, 2 },
+ [QCOM_RPM_PM8921_LDO17] = { 165, 79, 54, 2 },
+ [QCOM_RPM_PM8921_LDO18] = { 167, 81, 55, 2 },
+ [QCOM_RPM_PM8921_LDO19] = { 169, 83, 56, 2 },
+ [QCOM_RPM_PM8921_LDO20] = { 171, 85, 57, 2 },
+ [QCOM_RPM_PM8921_LDO21] = { 173, 87, 58, 2 },
+ [QCOM_RPM_PM8921_LDO22] = { 175, 89, 59, 2 },
+ [QCOM_RPM_PM8921_LDO23] = { 177, 91, 60, 2 },
+ [QCOM_RPM_PM8921_LDO24] = { 179, 93, 61, 2 },
+ [QCOM_RPM_PM8921_LDO25] = { 181, 95, 62, 2 },
+ [QCOM_RPM_PM8921_LDO26] = { 183, 97, 63, 2 },
+ [QCOM_RPM_PM8921_LDO27] = { 185, 99, 64, 2 },
+ [QCOM_RPM_PM8921_LDO28] = { 187, 101, 65, 2 },
+ [QCOM_RPM_PM8921_LDO29] = { 189, 103, 66, 2 },
+ [QCOM_RPM_PM8921_CLK1] = { 191, 105, 67, 2 },
+ [QCOM_RPM_PM8921_CLK2] = { 193, 107, 68, 2 },
+ [QCOM_RPM_PM8921_LVS1] = { 195, 109, 69, 1 },
+ [QCOM_RPM_PM8921_LVS2] = { 196, 110, 70, 1 },
+ [QCOM_RPM_PM8921_LVS3] = { 197, 111, 71, 1 },
+ [QCOM_RPM_PM8921_LVS4] = { 198, 112, 72, 1 },
+ [QCOM_RPM_PM8921_LVS5] = { 199, 113, 73, 1 },
+ [QCOM_RPM_PM8921_LVS6] = { 200, 114, 74, 1 },
+ [QCOM_RPM_PM8921_LVS7] = { 201, 115, 75, 1 },
+ [QCOM_RPM_PM8921_NCP] = { 202, 116, 80, 2 },
+ [QCOM_RPM_CXO_BUFFERS] = { 204, 118, 81, 1 },
+ [QCOM_RPM_USB_OTG_SWITCH] = { 205, 119, 82, 1 },
+ [QCOM_RPM_HDMI_SWITCH] = { 206, 120, 83, 1 },
+ [QCOM_RPM_DDR_DMM] = { 207, 121, 84, 2 },
+};
+
+static const struct qcom_rpm_data msm8960_template = {
+ .version = 3,
+ .resource_table = msm8960_rpm_resource_table,
+ .n_resources = ARRAY_SIZE(msm8960_rpm_resource_table),
+};
+
+static const struct of_device_id qcom_rpm_of_match[] = {
+ { .compatible = "qcom,rpm-apq8064", .data = &apq8064_template },
+ { .compatible = "qcom,rpm-msm8660", .data = &msm8660_template },
+ { .compatible = "qcom,rpm-msm8960", .data = &msm8960_template },
+ { }
+};
+MODULE_DEVICE_TABLE(of, qcom_rpm_of_match);
+
+int qcom_rpm_write(struct qcom_rpm *rpm,
+ int state,
+ int resource,
+ u32 *buf, size_t count)
+{
+ const struct qcom_rpm_resource *res;
+ const struct qcom_rpm_data *data = rpm->data;
+ u32 sel_mask[RPM_SELECT_SIZE] = { 0 };
+ int left;
+ int ret = 0;
+ int i;
+
+ if (WARN_ON(resource < 0 || resource >= data->n_resources))
+ return -EINVAL;
+
+ res = &data->resource_table[resource];
+ if (WARN_ON(res->size != count))
+ return -EINVAL;
+
+ mutex_lock(&rpm->lock);
+
+ for (i = 0; i < res->size; i++)
+ writel_relaxed(buf[i], RPM_REQ_REG(rpm, res->target_id + i));
+
+ bitmap_set((unsigned long *)sel_mask, res->select_id, 1);
+ for (i = 0; i < ARRAY_SIZE(sel_mask); i++) {
+ writel_relaxed(sel_mask[i],
+ RPM_CTRL_REG(rpm, RPM_REQ_SELECT + i));
+ }
+
+ writel_relaxed(BIT(state), RPM_CTRL_REG(rpm, RPM_REQUEST_CONTEXT));
+
+ reinit_completion(&rpm->ack);
+ regmap_write(rpm->ipc_regmap, rpm->ipc_offset, BIT(rpm->ipc_bit));
+
+ left = wait_for_completion_timeout(&rpm->ack, RPM_REQUEST_TIMEOUT);
+ if (!left)
+ ret = -ETIMEDOUT;
+ else if (rpm->ack_status & RPM_REJECTED)
+ ret = -EIO;
+
+ mutex_unlock(&rpm->lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(qcom_rpm_write);
+
+static irqreturn_t qcom_rpm_ack_interrupt(int irq, void *dev)
+{
+ struct qcom_rpm *rpm = dev;
+ u32 ack;
+ int i;
+
+ ack = readl_relaxed(RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
+ for (i = 0; i < RPM_SELECT_SIZE; i++)
+ writel_relaxed(0, RPM_CTRL_REG(rpm, RPM_ACK_SELECTOR + i));
+ writel(0, RPM_CTRL_REG(rpm, RPM_ACK_CONTEXT));
+
+ if (ack & RPM_NOTIFICATION) {
+ dev_warn(rpm->dev, "ignoring notification!\n");
+ } else {
+ rpm->ack_status = ack;
+ complete(&rpm->ack);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qcom_rpm_err_interrupt(int irq, void *dev)
+{
+ struct qcom_rpm *rpm = dev;
+
+ regmap_write(rpm->ipc_regmap, rpm->ipc_offset, BIT(rpm->ipc_bit));
+ dev_err(rpm->dev, "RPM triggered fatal error\n");
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t qcom_rpm_wakeup_interrupt(int irq, void *dev)
+{
+ return IRQ_HANDLED;
+}
+
+static int qcom_rpm_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device_node *syscon_np;
+ struct resource *res;
+ struct qcom_rpm *rpm;
+ u32 fw_version[3];
+ int irq_wakeup;
+ int irq_ack;
+ int irq_err;
+ int ret;
+
+ rpm = devm_kzalloc(&pdev->dev, sizeof(*rpm), GFP_KERNEL);
+ if (!rpm)
+ return -ENOMEM;
+
+ rpm->dev = &pdev->dev;
+ mutex_init(&rpm->lock);
+ init_completion(&rpm->ack);
+
+ irq_ack = platform_get_irq_byname(pdev, "ack");
+ if (irq_ack < 0) {
+ dev_err(&pdev->dev, "required ack interrupt missing\n");
+ return irq_ack;
+ }
+
+ irq_err = platform_get_irq_byname(pdev, "err");
+ if (irq_err < 0) {
+ dev_err(&pdev->dev, "required err interrupt missing\n");
+ return irq_err;
+ }
+
+ irq_wakeup = platform_get_irq_byname(pdev, "wakeup");
+ if (irq_wakeup < 0) {
+ dev_err(&pdev->dev, "required wakeup interrupt missing\n");
+ return irq_wakeup;
+ }
+
+ match = of_match_device(qcom_rpm_of_match, &pdev->dev);
+ rpm->data = match->data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rpm->status_regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rpm->status_regs))
+ return PTR_ERR(rpm->status_regs);
+ rpm->ctrl_regs = rpm->status_regs + 0x400;
+ rpm->req_regs = rpm->status_regs + 0x600;
+
+ syscon_np = of_parse_phandle(pdev->dev.of_node, "qcom,ipc", 0);
+ if (!syscon_np) {
+ dev_err(&pdev->dev, "no qcom,ipc node\n");
+ return -ENODEV;
+ }
+
+ rpm->ipc_regmap = syscon_node_to_regmap(syscon_np);
+ if (IS_ERR(rpm->ipc_regmap))
+ return PTR_ERR(rpm->ipc_regmap);
+
+ ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,ipc", 1,
+ &rpm->ipc_offset);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "no offset in qcom,ipc\n");
+ return -EINVAL;
+ }
+
+ ret = of_property_read_u32_index(pdev->dev.of_node, "qcom,ipc", 2,
+ &rpm->ipc_bit);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "no bit in qcom,ipc\n");
+ return -EINVAL;
+ }
+
+ dev_set_drvdata(&pdev->dev, rpm);
+
+ fw_version[0] = readl(RPM_STATUS_REG(rpm, 0));
+ fw_version[1] = readl(RPM_STATUS_REG(rpm, 1));
+ fw_version[2] = readl(RPM_STATUS_REG(rpm, 2));
+ if (fw_version[0] != rpm->data->version) {
+ dev_err(&pdev->dev,
+ "RPM version %u.%u.%u incompatible with driver version %u",
+ fw_version[0],
+ fw_version[1],
+ fw_version[2],
+ rpm->data->version);
+ return -EFAULT;
+ }
+
+ dev_info(&pdev->dev, "RPM firmware %u.%u.%u\n", fw_version[0],
+ fw_version[1],
+ fw_version[2]);
+
+ ret = devm_request_irq(&pdev->dev,
+ irq_ack,
+ qcom_rpm_ack_interrupt,
+ IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND,
+ "qcom_rpm_ack",
+ rpm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request ack interrupt\n");
+ return ret;
+ }
+
+ ret = irq_set_irq_wake(irq_ack, 1);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to mark ack irq as wakeup\n");
+
+ ret = devm_request_irq(&pdev->dev,
+ irq_err,
+ qcom_rpm_err_interrupt,
+ IRQF_TRIGGER_RISING,
+ "qcom_rpm_err",
+ rpm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request err interrupt\n");
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev,
+ irq_wakeup,
+ qcom_rpm_wakeup_interrupt,
+ IRQF_TRIGGER_RISING,
+ "qcom_rpm_wakeup",
+ rpm);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to request wakeup interrupt\n");
+ return ret;
+ }
+
+ ret = irq_set_irq_wake(irq_wakeup, 1);
+ if (ret)
+ dev_warn(&pdev->dev, "failed to mark wakeup irq as wakeup\n");
+
+ return of_platform_populate(pdev->dev.of_node, NULL, NULL, &pdev->dev);
+}
+
+static int qcom_rpm_remove(struct platform_device *pdev)
+{
+ of_platform_depopulate(&pdev->dev);
+ return 0;
+}
+
+static struct platform_driver qcom_rpm_driver = {
+ .probe = qcom_rpm_probe,
+ .remove = qcom_rpm_remove,
+ .driver = {
+ .name = "qcom_rpm",
+ .of_match_table = qcom_rpm_of_match,
+ },
+};
+
+static int __init qcom_rpm_init(void)
+{
+ return platform_driver_register(&qcom_rpm_driver);
+}
+arch_initcall(qcom_rpm_init);
+
+static void __exit qcom_rpm_exit(void)
+{
+ platform_driver_unregister(&qcom_rpm_driver);
+}
+module_exit(qcom_rpm_exit)
+
+MODULE_DESCRIPTION("Qualcomm Resource Power Manager driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Bjorn Andersson <bjorn.andersson@sonymobile.com>");
diff --git a/drivers/mfd/retu-mfd.c b/drivers/mfd/retu-mfd.c
index 663f8a37aa6b..2d64430c719b 100644
--- a/drivers/mfd/retu-mfd.c
+++ b/drivers/mfd/retu-mfd.c
@@ -222,7 +222,7 @@ static struct regmap_bus retu_bus = {
.val_format_endian_default = REGMAP_ENDIAN_NATIVE,
};
-static struct regmap_config retu_config = {
+static const struct regmap_config retu_config = {
.reg_bits = 8,
.val_bits = 16,
};
diff --git a/drivers/mfd/rt5033.c b/drivers/mfd/rt5033.c
new file mode 100644
index 000000000000..db395a6c52bc
--- /dev/null
+++ b/drivers/mfd/rt5033.c
@@ -0,0 +1,142 @@
+/*
+ * MFD core driver for the Richtek RT5033.
+ *
+ * RT5033 comprises multiple sub-devices switcing charger, fuel gauge,
+ * flash LED, current source, LDO and BUCK regulators.
+ *
+ * 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/err.h>
+#include <linux/module.h>
+#include <linux/interrupt.h>
+#include <linux/of_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/rt5033.h>
+#include <linux/mfd/rt5033-private.h>
+
+static const struct regmap_irq rt5033_irqs[] = {
+ { .mask = RT5033_PMIC_IRQ_BUCKOCP, },
+ { .mask = RT5033_PMIC_IRQ_BUCKLV, },
+ { .mask = RT5033_PMIC_IRQ_SAFELDOLV, },
+ { .mask = RT5033_PMIC_IRQ_LDOLV, },
+ { .mask = RT5033_PMIC_IRQ_OT, },
+ { .mask = RT5033_PMIC_IRQ_VDDA_UV, },
+};
+
+static const struct regmap_irq_chip rt5033_irq_chip = {
+ .name = "rt5033",
+ .status_base = RT5033_REG_PMIC_IRQ_STAT,
+ .mask_base = RT5033_REG_PMIC_IRQ_CTRL,
+ .mask_invert = true,
+ .num_regs = 1,
+ .irqs = rt5033_irqs,
+ .num_irqs = ARRAY_SIZE(rt5033_irqs),
+};
+
+static const struct mfd_cell rt5033_devs[] = {
+ { .name = "rt5033-regulator", },
+ {
+ .name = "rt5033-charger",
+ .of_compatible = "richtek,rt5033-charger",
+ }, {
+ .name = "rt5033-battery",
+ .of_compatible = "richtek,rt5033-battery",
+ },
+};
+
+static const struct regmap_config rt5033_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RT5033_REG_END,
+};
+
+static int rt5033_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct rt5033_dev *rt5033;
+ unsigned int dev_id;
+ int ret;
+
+ rt5033 = devm_kzalloc(&i2c->dev, sizeof(*rt5033), GFP_KERNEL);
+ if (!rt5033)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, rt5033);
+ rt5033->dev = &i2c->dev;
+ rt5033->irq = i2c->irq;
+ rt5033->wakeup = true;
+
+ rt5033->regmap = devm_regmap_init_i2c(i2c, &rt5033_regmap_config);
+ if (IS_ERR(rt5033->regmap)) {
+ dev_err(&i2c->dev, "Failed to allocate register map.\n");
+ return PTR_ERR(rt5033->regmap);
+ }
+
+ ret = regmap_read(rt5033->regmap, RT5033_REG_DEVICE_ID, &dev_id);
+ if (ret) {
+ dev_err(&i2c->dev, "Device not found\n");
+ return -ENODEV;
+ }
+ dev_info(&i2c->dev, "Device found Device ID: %04x\n", dev_id);
+
+ ret = regmap_add_irq_chip(rt5033->regmap, rt5033->irq,
+ IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+ 0, &rt5033_irq_chip, &rt5033->irq_data);
+ if (ret) {
+ dev_err(&i2c->dev, "Failed to request IRQ %d: %d\n",
+ rt5033->irq, ret);
+ return ret;
+ }
+
+ ret = mfd_add_devices(rt5033->dev, -1, rt5033_devs,
+ ARRAY_SIZE(rt5033_devs), NULL, 0,
+ regmap_irq_get_domain(rt5033->irq_data));
+ if (ret < 0) {
+ dev_err(&i2c->dev, "Failed to add RT5033 child devices.\n");
+ return ret;
+ }
+
+ device_init_wakeup(rt5033->dev, rt5033->wakeup);
+
+ return 0;
+}
+
+static int rt5033_i2c_remove(struct i2c_client *i2c)
+{
+ mfd_remove_devices(&i2c->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id rt5033_i2c_id[] = {
+ { "rt5033", },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, rt5033_i2c_id);
+
+static const struct of_device_id rt5033_dt_match[] = {
+ { .compatible = "richtek,rt5033", },
+ { }
+};
+
+static struct i2c_driver rt5033_driver = {
+ .driver = {
+ .name = "rt5033",
+ .of_match_table = of_match_ptr(rt5033_dt_match),
+ },
+ .probe = rt5033_i2c_probe,
+ .remove = rt5033_i2c_remove,
+ .id_table = rt5033_i2c_id,
+};
+module_i2c_driver(rt5033_driver);
+
+MODULE_ALIAS("i2c:rt5033");
+MODULE_DESCRIPTION("Richtek RT5033 multi-function core driver");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c
index 210d1f85679e..ede50244f265 100644
--- a/drivers/mfd/rtsx_usb.c
+++ b/drivers/mfd/rtsx_usb.c
@@ -681,9 +681,27 @@ static void rtsx_usb_disconnect(struct usb_interface *intf)
#ifdef CONFIG_PM
static int rtsx_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
+ struct rtsx_ucr *ucr =
+ (struct rtsx_ucr *)usb_get_intfdata(intf);
+ u16 val = 0;
+
dev_dbg(&intf->dev, "%s called with pm message 0x%04x\n",
__func__, message.event);
+ if (PMSG_IS_AUTO(message)) {
+ if (mutex_trylock(&ucr->dev_mutex)) {
+ rtsx_usb_get_card_status(ucr, &val);
+ mutex_unlock(&ucr->dev_mutex);
+
+ /* Defer the autosuspend if card exists */
+ if (val & (SD_CD | MS_CD))
+ return -EAGAIN;
+ } else {
+ /* There is an ongoing operation*/
+ return -EAGAIN;
+ }
+ }
+
return 0;
}
diff --git a/drivers/mfd/smsc-ece1099.c b/drivers/mfd/smsc-ece1099.c
index 90112d4cc905..03246880d484 100644
--- a/drivers/mfd/smsc-ece1099.c
+++ b/drivers/mfd/smsc-ece1099.c
@@ -24,7 +24,7 @@
#include <linux/mfd/smsc.h>
#include <linux/of_platform.h>
-static struct regmap_config smsc_regmap_config = {
+static const struct regmap_config smsc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = SMSC_VEN_ID_H,
diff --git a/drivers/mfd/sun6i-prcm.c b/drivers/mfd/sun6i-prcm.c
index 2f2e9f062571..191173166d65 100644
--- a/drivers/mfd/sun6i-prcm.c
+++ b/drivers/mfd/sun6i-prcm.c
@@ -41,6 +41,14 @@ static const struct resource sun6i_a31_apb0_gates_clk_res[] = {
},
};
+static const struct resource sun6i_a31_ir_clk_res[] = {
+ {
+ .start = 0x54,
+ .end = 0x57,
+ .flags = IORESOURCE_MEM,
+ },
+};
+
static const struct resource sun6i_a31_apb0_rstc_res[] = {
{
.start = 0xb0,
@@ -69,6 +77,12 @@ static const struct mfd_cell sun6i_a31_prcm_subdevs[] = {
.resources = sun6i_a31_apb0_gates_clk_res,
},
{
+ .name = "sun6i-a31-ir-clk",
+ .of_compatible = "allwinner,sun4i-a10-mod0-clk",
+ .num_resources = ARRAY_SIZE(sun6i_a31_ir_clk_res),
+ .resources = sun6i_a31_ir_clk_res,
+ },
+ {
.name = "sun6i-a31-apb0-clock-reset",
.of_compatible = "allwinner,sun6i-a31-clock-reset",
.num_resources = ARRAY_SIZE(sun6i_a31_apb0_rstc_res),
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index 80a919a8ca97..7d1cfc1d3ce0 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -145,7 +145,7 @@ int tps65217_clear_bits(struct tps65217 *tps, unsigned int reg,
}
EXPORT_SYMBOL_GPL(tps65217_clear_bits);
-static struct regmap_config tps65217_regmap_config = {
+static const struct regmap_config tps65217_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/drivers/mfd/tps65218.c b/drivers/mfd/tps65218.c
index d6b764349f9d..7af11a8b9753 100644
--- a/drivers/mfd/tps65218.c
+++ b/drivers/mfd/tps65218.c
@@ -135,7 +135,7 @@ static const struct regmap_access_table tps65218_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(tps65218_yes_ranges),
};
-static struct regmap_config tps65218_regmap_config = {
+static const struct regmap_config tps65218_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.cache_type = REGCACHE_RBTREE,
diff --git a/drivers/mfd/twl-core.c b/drivers/mfd/twl-core.c
index db11b4f40611..489674a2497e 100644
--- a/drivers/mfd/twl-core.c
+++ b/drivers/mfd/twl-core.c
@@ -207,7 +207,7 @@ static struct twl_mapping twl4030_map[] = {
{ 2, TWL5031_BASEADD_INTERRUPTS },
};
-static struct reg_default twl4030_49_defaults[] = {
+static const struct reg_default twl4030_49_defaults[] = {
/* Audio Registers */
{ 0x01, 0x00}, /* CODEC_MODE */
{ 0x02, 0x00}, /* OPTION */
@@ -306,7 +306,7 @@ static const struct regmap_access_table twl4030_49_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(twl4030_49_volatile_ranges),
};
-static struct regmap_config twl4030_regmap_config[4] = {
+static const struct regmap_config twl4030_regmap_config[4] = {
{
/* Address 0x48 */
.reg_bits = 8,
@@ -369,7 +369,7 @@ static struct twl_mapping twl6030_map[] = {
{ 1, TWL6030_BASEADD_GASGAUGE },
};
-static struct regmap_config twl6030_regmap_config[3] = {
+static const struct regmap_config twl6030_regmap_config[3] = {
{
/* Address 0x48 */
.reg_bits = 8,
@@ -1087,7 +1087,7 @@ twl_probe(struct i2c_client *client, const struct i2c_device_id *id)
struct twl4030_platform_data *pdata = dev_get_platdata(&client->dev);
struct device_node *node = client->dev.of_node;
struct platform_device *pdev;
- struct regmap_config *twl_regmap_config;
+ const struct regmap_config *twl_regmap_config;
int irq_base = 0;
int status;
unsigned i, num_slaves;
diff --git a/drivers/mfd/twl6040.c b/drivers/mfd/twl6040.c
index 9687645162ae..f71ee3dbc2a2 100644
--- a/drivers/mfd/twl6040.c
+++ b/drivers/mfd/twl6040.c
@@ -44,7 +44,7 @@
#define VIBRACTRL_MEMBER(reg) ((reg == TWL6040_REG_VIBCTLL) ? 0 : 1)
#define TWL6040_NUM_SUPPLIES (2)
-static struct reg_default twl6040_defaults[] = {
+static const struct reg_default twl6040_defaults[] = {
{ 0x01, 0x4B }, /* REG_ASICID (ro) */
{ 0x02, 0x00 }, /* REG_ASICREV (ro) */
{ 0x03, 0x00 }, /* REG_INTID */
@@ -580,7 +580,7 @@ static bool twl6040_writeable_reg(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config twl6040_regmap_config = {
+static const struct regmap_config twl6040_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index 6ca9d25cc3f0..53ae5af5d6e4 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -36,12 +36,12 @@
static const struct mfd_cell wm8994_regulator_devs[] = {
{
.name = "wm8994-ldo",
- .id = 1,
+ .id = 0,
.pm_runtime_no_callbacks = true,
},
{
.name = "wm8994-ldo",
- .id = 2,
+ .id = 1,
.pm_runtime_no_callbacks = true,
},
};
@@ -344,7 +344,7 @@ static int wm8994_device_init(struct wm8994 *wm8994, int irq)
dev_set_drvdata(wm8994->dev, wm8994);
/* Add the on-chip regulators first for bootstrapping */
- ret = mfd_add_devices(wm8994->dev, -1,
+ ret = mfd_add_devices(wm8994->dev, 0,
wm8994_regulator_devs,
ARRAY_SIZE(wm8994_regulator_devs),
NULL, 0, NULL);
diff --git a/drivers/misc/ad525x_dpot-spi.c b/drivers/misc/ad525x_dpot-spi.c
index 9da04ede04f3..f4c82eafa8e5 100644
--- a/drivers/misc/ad525x_dpot-spi.c
+++ b/drivers/misc/ad525x_dpot-spi.c
@@ -15,18 +15,21 @@
static int write8(void *client, u8 val)
{
u8 data = val;
+
return spi_write(client, &data, 1);
}
static int write16(void *client, u8 reg, u8 val)
{
u8 data[2] = {reg, val};
+
return spi_write(client, data, 2);
}
static int write24(void *client, u8 reg, u16 val)
{
u8 data[3] = {reg, val >> 8, val};
+
return spi_write(client, data, 3);
}
@@ -34,6 +37,7 @@ static int read8(void *client)
{
int ret;
u8 data;
+
ret = spi_read(client, &data, 1);
if (ret < 0)
return ret;
diff --git a/drivers/misc/ad525x_dpot.c b/drivers/misc/ad525x_dpot.c
index a43053daad0e..15e88078ba1e 100644
--- a/drivers/misc/ad525x_dpot.c
+++ b/drivers/misc/ad525x_dpot.c
@@ -176,6 +176,7 @@ static s32 dpot_read_i2c(struct dpot_data *dpot, u8 reg)
{
int value;
unsigned ctrl = 0;
+
switch (dpot->uid) {
case DPOT_UID(AD5246_ID):
case DPOT_UID(AD5247_ID):
@@ -333,7 +334,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
case DPOT_UID(AD5246_ID):
case DPOT_UID(AD5247_ID):
return dpot_write_d8(dpot, value);
- break;
case DPOT_UID(AD5245_ID):
case DPOT_UID(AD5241_ID):
@@ -345,7 +345,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
0 : DPOT_AD5282_RDAC_AB;
return dpot_write_r8d8(dpot, ctrl, value);
- break;
case DPOT_UID(AD5171_ID):
case DPOT_UID(AD5273_ID):
if (reg & DPOT_ADDR_OTP) {
@@ -355,7 +354,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
ctrl = DPOT_AD5273_FUSE;
}
return dpot_write_r8d8(dpot, ctrl, value);
- break;
case DPOT_UID(AD5172_ID):
case DPOT_UID(AD5173_ID):
ctrl = ((reg & DPOT_RDAC_MASK) == DPOT_RDAC0) ?
@@ -367,7 +365,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
ctrl |= DPOT_AD5170_2_3_FUSE;
}
return dpot_write_r8d8(dpot, ctrl, value);
- break;
case DPOT_UID(AD5170_ID):
if (reg & DPOT_ADDR_OTP) {
tmp = dpot_read_r8d16(dpot, tmp);
@@ -376,7 +373,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
ctrl = DPOT_AD5170_2_3_FUSE;
}
return dpot_write_r8d8(dpot, ctrl, value);
- break;
case DPOT_UID(AD5272_ID):
case DPOT_UID(AD5274_ID):
dpot_write_r8d8(dpot, DPOT_AD5270_1_2_4_CTRLREG << 2,
@@ -391,7 +387,6 @@ static s32 dpot_write_i2c(struct dpot_data *dpot, u8 reg, u16 value)
return dpot_write_r8d8(dpot, (DPOT_AD5270_1_2_4_RDAC << 2) |
(value >> 8), value & 0xFF);
- break;
default:
if (reg & DPOT_ADDR_CMD)
return dpot_write_d8(dpot, reg);
diff --git a/drivers/misc/cxl/Makefile b/drivers/misc/cxl/Makefile
index 165e98fef2c2..edb494d3ff27 100644
--- a/drivers/misc/cxl/Makefile
+++ b/drivers/misc/cxl/Makefile
@@ -1,3 +1,6 @@
-cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o
+cxl-y += main.o file.o irq.o fault.o native.o context.o sysfs.o debugfs.o pci.o trace.o
obj-$(CONFIG_CXL) += cxl.o
obj-$(CONFIG_CXL_BASE) += base.o
+
+# For tracepoints to include our trace.h from tracepoint infrastructure:
+CFLAGS_trace.o := -I$(src)
diff --git a/drivers/misc/cxl/cxl.h b/drivers/misc/cxl/cxl.h
index 28078f8894a5..a1cee4767ec6 100644
--- a/drivers/misc/cxl/cxl.h
+++ b/drivers/misc/cxl/cxl.h
@@ -287,6 +287,13 @@ static const cxl_p2n_reg_t CXL_PSL_WED_An = {0x0A0};
#define CXL_PE_SOFTWARE_STATE_S (1ul << (31 - 30)) /* Suspend */
#define CXL_PE_SOFTWARE_STATE_T (1ul << (31 - 31)) /* Terminate */
+/****** CXL_PSL_RXCTL_An (Implementation Specific) **************************
+ * Controls AFU Hang Pulse, which sets the timeout for the AFU to respond to
+ * the PSL for any response (except MMIO). Timeouts will occur between 1x to 2x
+ * of the hang pulse frequency.
+ */
+#define CXL_PSL_RXCTL_AFUHP_4S 0x7000000000000000ULL
+
/* SPA->sw_command_status */
#define CXL_SPA_SW_CMD_MASK 0xffff000000000000ULL
#define CXL_SPA_SW_CMD_TERMINATE 0x0001000000000000ULL
@@ -375,6 +382,10 @@ struct cxl_afu {
int slice;
int modes_supported;
int current_mode;
+ int crs_num;
+ u64 crs_len;
+ u64 crs_offset;
+ struct list_head crs;
enum prefault_modes prefault_mode;
bool psa;
bool pp_psa;
@@ -481,6 +492,8 @@ void cxl_release_one_irq(struct cxl *adapter, int hwirq);
int cxl_alloc_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter, unsigned int num);
void cxl_release_irq_ranges(struct cxl_irq_ranges *irqs, struct cxl *adapter);
int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq, unsigned int virq);
+int cxl_update_image_control(struct cxl *adapter);
+int cxl_reset(struct cxl *adapter);
/* common == phyp + powernv */
struct cxl_process_element_common {
@@ -542,6 +555,15 @@ static inline void __iomem *_cxl_p2n_addr(struct cxl_afu *afu, cxl_p2n_reg_t reg
#define cxl_p2n_read(afu, reg) \
in_be64(_cxl_p2n_addr(afu, reg))
+
+#define cxl_afu_cr_read64(afu, cr, off) \
+ in_le64((afu)->afu_desc_mmio + (afu)->crs_offset + ((cr) * (afu)->crs_len) + (off))
+#define cxl_afu_cr_read32(afu, cr, off) \
+ in_le32((afu)->afu_desc_mmio + (afu)->crs_offset + ((cr) * (afu)->crs_len) + (off))
+u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off);
+u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off);
+
+
struct cxl_calls {
void (*cxl_slbia)(struct mm_struct *mm);
struct module *owner;
diff --git a/drivers/misc/cxl/fault.c b/drivers/misc/cxl/fault.c
index f8684bca2d79..5286b8b704f5 100644
--- a/drivers/misc/cxl/fault.c
+++ b/drivers/misc/cxl/fault.c
@@ -20,6 +20,7 @@
#include <asm/mmu.h>
#include "cxl.h"
+#include "trace.h"
static bool sste_matches(struct cxl_sste *sste, struct copro_slb *slb)
{
@@ -75,6 +76,7 @@ static void cxl_load_segment(struct cxl_context *ctx, struct copro_slb *slb)
pr_devel("CXL Populating SST[%li]: %#llx %#llx\n",
sste - ctx->sstp, slb->vsid, slb->esid);
+ trace_cxl_ste_write(ctx, sste - ctx->sstp, slb->esid, slb->vsid);
sste->vsid_data = cpu_to_be64(slb->vsid);
sste->esid_data = cpu_to_be64(slb->esid);
@@ -116,6 +118,7 @@ static int cxl_handle_segment_miss(struct cxl_context *ctx,
int rc;
pr_devel("CXL interrupt: Segment fault pe: %i ea: %#llx\n", ctx->pe, ea);
+ trace_cxl_ste_miss(ctx, ea);
if ((rc = cxl_fault_segment(ctx, mm, ea)))
cxl_ack_ae(ctx);
@@ -135,6 +138,8 @@ static void cxl_handle_page_fault(struct cxl_context *ctx,
int result;
unsigned long access, flags, inv_flags = 0;
+ trace_cxl_pte_miss(ctx, dsisr, dar);
+
if ((result = copro_handle_mm_fault(mm, dar, dsisr, &flt))) {
pr_devel("copro_handle_mm_fault failed: %#x\n", result);
return cxl_ack_ae(ctx);
@@ -180,6 +185,12 @@ void cxl_handle_fault(struct work_struct *fault_work)
return;
}
+ /* Early return if the context is being / has been detached */
+ if (ctx->status == CLOSED) {
+ cxl_ack_ae(ctx);
+ return;
+ }
+
pr_devel("CXL BOTTOM HALF handling fault for afu pe: %i. "
"DSISR: %#llx DAR: %#llx\n", ctx->pe, dsisr, dar);
diff --git a/drivers/misc/cxl/file.c b/drivers/misc/cxl/file.c
index b15d8113877c..2364bcadb9a9 100644
--- a/drivers/misc/cxl/file.c
+++ b/drivers/misc/cxl/file.c
@@ -23,6 +23,7 @@
#include <asm/copro.h>
#include "cxl.h"
+#include "trace.h"
#define CXL_NUM_MINORS 256 /* Total to reserve */
#define CXL_DEV_MINORS 13 /* 1 control + 4 AFUs * 3 (dedicated/master/shared) */
@@ -186,9 +187,13 @@ static long afu_ioctl_start_work(struct cxl_context *ctx,
*/
ctx->pid = get_pid(get_task_pid(current, PIDTYPE_PID));
+ trace_cxl_attach(ctx, work.work_element_descriptor, work.num_interrupts, amr);
+
if ((rc = cxl_attach_process(ctx, false, work.work_element_descriptor,
- amr)))
+ amr))) {
+ afu_release_irqs(ctx);
goto out;
+ }
ctx->status = STARTED;
rc = 0;
diff --git a/drivers/misc/cxl/irq.c b/drivers/misc/cxl/irq.c
index c294925f73ee..c8929c526691 100644
--- a/drivers/misc/cxl/irq.c
+++ b/drivers/misc/cxl/irq.c
@@ -17,6 +17,7 @@
#include <misc/cxl.h>
#include "cxl.h"
+#include "trace.h"
/* XXX: This is implementation specific */
static irqreturn_t handle_psl_slice_error(struct cxl_context *ctx, u64 dsisr, u64 errstat)
@@ -100,6 +101,8 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
dsisr = irq_info->dsisr;
dar = irq_info->dar;
+ trace_cxl_psl_irq(ctx, irq, dsisr, dar);
+
pr_devel("CXL interrupt %i for afu pe: %i DSISR: %#llx DAR: %#llx\n", irq, ctx->pe, dsisr, dar);
if (dsisr & CXL_PSL_DSISR_An_DS) {
@@ -167,6 +170,7 @@ static irqreturn_t cxl_irq(int irq, void *data, struct cxl_irq_info *irq_info)
}
cxl_ack_irq(ctx, CXL_PSL_TFC_An_A, 0);
+ return IRQ_HANDLED;
}
if (dsisr & CXL_PSL_DSISR_An_OC)
pr_devel("CXL interrupt: OS Context Warning\n");
@@ -237,6 +241,7 @@ static irqreturn_t cxl_irq_afu(int irq, void *data)
return IRQ_HANDLED;
}
+ trace_cxl_afu_irq(ctx, afu_irq, irq, hwirq);
pr_devel("Received AFU interrupt %i for pe: %i (virq %i hwirq %lx)\n",
afu_irq, ctx->pe, irq, hwirq);
@@ -436,7 +441,7 @@ int afu_register_irqs(struct cxl_context *ctx, u32 count)
*/
INIT_LIST_HEAD(&ctx->irq_names);
for (r = 1; r < CXL_IRQ_RANGES; r++) {
- for (i = 0; i < ctx->irqs.range[r]; hwirq++, i++) {
+ for (i = 0; i < ctx->irqs.range[r]; i++) {
irq_name = kmalloc(sizeof(struct cxl_irq_name),
GFP_KERNEL);
if (!irq_name)
diff --git a/drivers/misc/cxl/main.c b/drivers/misc/cxl/main.c
index 4cde9b661642..8ccddceead66 100644
--- a/drivers/misc/cxl/main.c
+++ b/drivers/misc/cxl/main.c
@@ -23,6 +23,7 @@
#include <misc/cxl.h>
#include "cxl.h"
+#include "trace.h"
static DEFINE_SPINLOCK(adapter_idr_lock);
static DEFINE_IDR(cxl_adapter_idr);
@@ -48,6 +49,7 @@ static inline void _cxl_slbia(struct cxl_context *ctx, struct mm_struct *mm)
ctx->afu->adapter->adapter_num, ctx->afu->slice, ctx->pe);
spin_lock_irqsave(&ctx->sste_lock, flags);
+ trace_cxl_slbia(ctx);
memset(ctx->sstp, 0, ctx->sst_size);
spin_unlock_irqrestore(&ctx->sste_lock, flags);
mb();
diff --git a/drivers/misc/cxl/native.c b/drivers/misc/cxl/native.c
index f2b37b41a0da..29185fc61276 100644
--- a/drivers/misc/cxl/native.c
+++ b/drivers/misc/cxl/native.c
@@ -18,24 +18,28 @@
#include <misc/cxl.h>
#include "cxl.h"
+#include "trace.h"
static int afu_control(struct cxl_afu *afu, u64 command,
u64 result, u64 mask, bool enabled)
{
u64 AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+ int rc = 0;
spin_lock(&afu->afu_cntl_lock);
pr_devel("AFU command starting: %llx\n", command);
+ trace_cxl_afu_ctrl(afu, command);
+
cxl_p2n_write(afu, CXL_AFU_Cntl_An, AFU_Cntl | command);
AFU_Cntl = cxl_p2n_read(afu, CXL_AFU_Cntl_An);
while ((AFU_Cntl & mask) != result) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&afu->dev, "WARNING: AFU control timed out!\n");
- spin_unlock(&afu->afu_cntl_lock);
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
pr_devel_ratelimited("AFU control... (0x%.16llx)\n",
AFU_Cntl | command);
@@ -44,9 +48,11 @@ static int afu_control(struct cxl_afu *afu, u64 command,
};
pr_devel("AFU command complete: %llx\n", command);
afu->enabled = enabled;
+out:
+ trace_cxl_afu_ctrl_done(afu, command, rc);
spin_unlock(&afu->afu_cntl_lock);
- return 0;
+ return rc;
}
static int afu_enable(struct cxl_afu *afu)
@@ -91,6 +97,9 @@ int cxl_psl_purge(struct cxl_afu *afu)
u64 dsisr, dar;
u64 start, end;
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+ int rc = 0;
+
+ trace_cxl_psl_ctrl(afu, CXL_PSL_SCNTL_An_Pc);
pr_devel("PSL purge request\n");
@@ -107,7 +116,8 @@ int cxl_psl_purge(struct cxl_afu *afu)
== CXL_PSL_SCNTL_An_Ps_Pending) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&afu->dev, "WARNING: PSL Purge timed out!\n");
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
dsisr = cxl_p2n_read(afu, CXL_PSL_DSISR_An);
pr_devel_ratelimited("PSL purging... PSL_CNTL: 0x%.16llx PSL_DSISR: 0x%.16llx\n", PSL_CNTL, dsisr);
@@ -128,7 +138,9 @@ int cxl_psl_purge(struct cxl_afu *afu)
cxl_p1n_write(afu, CXL_PSL_SCNTL_An,
PSL_CNTL & ~CXL_PSL_SCNTL_An_Pc);
- return 0;
+out:
+ trace_cxl_psl_ctrl_done(afu, CXL_PSL_SCNTL_An_Pc, rc);
+ return rc;
}
static int spa_max_procs(int spa_size)
@@ -185,6 +197,7 @@ static int alloc_spa(struct cxl_afu *afu)
static void release_spa(struct cxl_afu *afu)
{
+ cxl_p1n_write(afu, CXL_PSL_SPAP_An, 0);
free_pages((unsigned long) afu->spa, afu->spa_order);
}
@@ -278,6 +291,9 @@ static int do_process_element_cmd(struct cxl_context *ctx,
{
u64 state;
unsigned long timeout = jiffies + (HZ * CXL_TIMEOUT);
+ int rc = 0;
+
+ trace_cxl_llcmd(ctx, cmd);
WARN_ON(!ctx->afu->enabled);
@@ -289,12 +305,14 @@ static int do_process_element_cmd(struct cxl_context *ctx,
while (1) {
if (time_after_eq(jiffies, timeout)) {
dev_warn(&ctx->afu->dev, "WARNING: Process Element Command timed out!\n");
- return -EBUSY;
+ rc = -EBUSY;
+ goto out;
}
state = be64_to_cpup(ctx->afu->sw_command_status);
if (state == ~0ULL) {
pr_err("cxl: Error adding process element to AFU\n");
- return -1;
+ rc = -1;
+ goto out;
}
if ((state & (CXL_SPA_SW_CMD_MASK | CXL_SPA_SW_STATE_MASK | CXL_SPA_SW_LINK_MASK)) ==
(cmd | (cmd >> 16) | ctx->pe))
@@ -309,7 +327,9 @@ static int do_process_element_cmd(struct cxl_context *ctx,
schedule();
}
- return 0;
+out:
+ trace_cxl_llcmd_done(ctx, cmd, rc);
+ return rc;
}
static int add_process_element(struct cxl_context *ctx)
@@ -629,6 +649,8 @@ static inline int detach_process_native_afu_directed(struct cxl_context *ctx)
int cxl_detach_process(struct cxl_context *ctx)
{
+ trace_cxl_detach(ctx);
+
if (ctx->afu->current_mode == CXL_MODE_DEDICATED)
return detach_process_native_dedicated(ctx);
@@ -667,6 +689,7 @@ static void recover_psl_err(struct cxl_afu *afu, u64 errstat)
int cxl_ack_irq(struct cxl_context *ctx, u64 tfc, u64 psl_reset_mask)
{
+ trace_cxl_psl_irq_ack(ctx, tfc);
if (tfc)
cxl_p2n_write(ctx->afu, CXL_PSL_TFC_An, tfc);
if (psl_reset_mask)
diff --git a/drivers/misc/cxl/pci.c b/drivers/misc/cxl/pci.c
index 0f2cc9f8b4db..1ef01647265f 100644
--- a/drivers/misc/cxl/pci.c
+++ b/drivers/misc/cxl/pci.c
@@ -21,6 +21,7 @@
#include <asm/msi_bitmap.h>
#include <asm/pci-bridge.h> /* for struct pci_controller */
#include <asm/pnv-pci.h>
+#include <asm/io.h>
#include "cxl.h"
@@ -113,6 +114,24 @@
#define AFUD_EB_LEN(val) EXTRACT_PPC_BITS(val, 8, 63)
#define AFUD_READ_EB_OFF(afu) AFUD_READ(afu, 0x48)
+u16 cxl_afu_cr_read16(struct cxl_afu *afu, int cr, u64 off)
+{
+ u64 aligned_off = off & ~0x3L;
+ u32 val;
+
+ val = cxl_afu_cr_read32(afu, cr, aligned_off);
+ return (val >> ((off & 0x2) * 8)) & 0xffff;
+}
+
+u8 cxl_afu_cr_read8(struct cxl_afu *afu, int cr, u64 off)
+{
+ u64 aligned_off = off & ~0x3L;
+ u32 val;
+
+ val = cxl_afu_cr_read32(afu, cr, aligned_off);
+ return (val >> ((off & 0x3) * 8)) & 0xff;
+}
+
static DEFINE_PCI_DEVICE_TABLE(cxl_pci_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x0477), },
{ PCI_DEVICE(PCI_VENDOR_ID_IBM, 0x044b), },
@@ -316,7 +335,7 @@ static int init_implementation_adapter_regs(struct cxl *adapter, struct pci_dev
u64 psl_dsnctl;
u64 chipid;
- if (!(np = pnv_pci_to_phb_node(dev)))
+ if (!(np = pnv_pci_get_phb_node(dev)))
return -ENODEV;
while (np && !(prop = of_get_property(np, "ibm,chip-id", NULL)))
@@ -348,7 +367,7 @@ static int init_implementation_afu_regs(struct cxl_afu *afu)
cxl_p1n_write(afu, CXL_PSL_COALLOC_A, 0xFF000000FEFEFEFEULL);
/* for debugging with trace arrays */
cxl_p1n_write(afu, CXL_PSL_SLICE_TRACE, 0x0000FFFF00000000ULL);
- cxl_p1n_write(afu, CXL_PSL_RXCTL_A, 0xF000000000000000ULL);
+ cxl_p1n_write(afu, CXL_PSL_RXCTL_A, CXL_PSL_RXCTL_AFUHP_4S);
return 0;
}
@@ -361,6 +380,41 @@ int cxl_setup_irq(struct cxl *adapter, unsigned int hwirq,
return pnv_cxl_ioda_msi_setup(dev, hwirq, virq);
}
+int cxl_update_image_control(struct cxl *adapter)
+{
+ struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+ int rc;
+ int vsec;
+ u8 image_state;
+
+ if (!(vsec = find_cxl_vsec(dev))) {
+ dev_err(&dev->dev, "ABORTING: CXL VSEC not found!\n");
+ return -ENODEV;
+ }
+
+ if ((rc = CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state))) {
+ dev_err(&dev->dev, "failed to read image state: %i\n", rc);
+ return rc;
+ }
+
+ if (adapter->perst_loads_image)
+ image_state |= CXL_VSEC_PERST_LOADS_IMAGE;
+ else
+ image_state &= ~CXL_VSEC_PERST_LOADS_IMAGE;
+
+ if (adapter->perst_select_user)
+ image_state |= CXL_VSEC_PERST_SELECT_USER;
+ else
+ image_state &= ~CXL_VSEC_PERST_SELECT_USER;
+
+ if ((rc = CXL_WRITE_VSEC_IMAGE_STATE(dev, vsec, image_state))) {
+ dev_err(&dev->dev, "failed to update image control: %i\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
int cxl_alloc_one_irq(struct cxl *adapter)
{
struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
@@ -520,6 +574,7 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu)
val = AFUD_READ_INFO(afu);
afu->pp_irqs = AFUD_NUM_INTS_PER_PROC(val);
afu->max_procs_virtualised = AFUD_NUM_PROCS(val);
+ afu->crs_num = AFUD_NUM_CRS(val);
if (AFUD_AFU_DIRECTED(val))
afu->modes_supported |= CXL_MODE_DIRECTED;
@@ -534,11 +589,17 @@ static int cxl_read_afu_descriptor(struct cxl_afu *afu)
if ((afu->pp_psa = AFUD_PPPSA_PP(val)))
afu->pp_offset = AFUD_READ_PPPSA_OFF(afu);
+ val = AFUD_READ_CR(afu);
+ afu->crs_len = AFUD_CR_LEN(val) * 256;
+ afu->crs_offset = AFUD_READ_CR_OFF(afu);
+
return 0;
}
static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
{
+ int i;
+
if (afu->psa && afu->adapter->ps_size <
(afu->pp_offset + afu->pp_size*afu->max_procs_virtualised)) {
dev_err(&afu->dev, "per-process PSA can't fit inside the PSA!\n");
@@ -548,6 +609,13 @@ static int cxl_afu_descriptor_looks_ok(struct cxl_afu *afu)
if (afu->pp_psa && (afu->pp_size < PAGE_SIZE))
dev_warn(&afu->dev, "AFU uses < PAGE_SIZE per-process PSA!");
+ for (i = 0; i < afu->crs_num; i++) {
+ if ((cxl_afu_cr_read32(afu, i, 0) == 0)) {
+ dev_err(&afu->dev, "ABORTING: AFU configuration record %i is invalid\n", i);
+ return -EINVAL;
+ }
+ }
+
return 0;
}
@@ -706,6 +774,42 @@ static void cxl_remove_afu(struct cxl_afu *afu)
device_unregister(&afu->dev);
}
+int cxl_reset(struct cxl *adapter)
+{
+ struct pci_dev *dev = to_pci_dev(adapter->dev.parent);
+ int rc;
+ int i;
+ u32 val;
+
+ dev_info(&dev->dev, "CXL reset\n");
+
+ for (i = 0; i < adapter->slices; i++)
+ cxl_remove_afu(adapter->afu[i]);
+
+ /* pcie_warm_reset requests a fundamental pci reset which includes a
+ * PERST assert/deassert. PERST triggers a loading of the image
+ * if "user" or "factory" is selected in sysfs */
+ if ((rc = pci_set_pcie_reset_state(dev, pcie_warm_reset))) {
+ dev_err(&dev->dev, "cxl: pcie_warm_reset failed\n");
+ return rc;
+ }
+
+ /* the PERST done above fences the PHB. So, reset depends on EEH
+ * to unbind the driver, tell Sapphire to reinit the PHB, and rebind
+ * the driver. Do an mmio read explictly to ensure EEH notices the
+ * fenced PHB. Retry for a few seconds before giving up. */
+ i = 0;
+ while (((val = mmio_read32be(adapter->p1_mmio)) != 0xffffffff) &&
+ (i < 5)) {
+ msleep(500);
+ i++;
+ }
+
+ if (val != 0xffffffff)
+ dev_err(&dev->dev, "cxl: PERST failed to trigger EEH\n");
+
+ return rc;
+}
static int cxl_map_adapter_regs(struct cxl *adapter, struct pci_dev *dev)
{
@@ -770,8 +874,8 @@ static int cxl_read_vsec(struct cxl *adapter, struct pci_dev *dev)
CXL_READ_VSEC_BASE_IMAGE(dev, vsec, &adapter->base_image);
CXL_READ_VSEC_IMAGE_STATE(dev, vsec, &image_state);
adapter->user_image_loaded = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED);
- adapter->perst_loads_image = !!(image_state & CXL_VSEC_PERST_LOADS_IMAGE);
- adapter->perst_select_user = !!(image_state & CXL_VSEC_PERST_SELECT_USER);
+ adapter->perst_loads_image = true;
+ adapter->perst_select_user = !!(image_state & CXL_VSEC_USER_IMAGE_LOADED);
CXL_READ_VSEC_NAFUS(dev, vsec, &adapter->slices);
CXL_READ_VSEC_AFU_DESC_OFF(dev, vsec, &afu_desc_off);
@@ -879,6 +983,9 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev)
if ((rc = cxl_vsec_looks_ok(adapter, dev)))
goto err2;
+ if ((rc = cxl_update_image_control(adapter)))
+ goto err2;
+
if ((rc = cxl_map_adapter_regs(adapter, dev)))
goto err2;
@@ -888,9 +995,15 @@ static struct cxl *cxl_init_adapter(struct pci_dev *dev)
if ((rc = init_implementation_adapter_regs(adapter, dev)))
goto err3;
- if ((rc = pnv_phb_to_cxl(dev)))
+ if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_CAPI)))
goto err3;
+ /* If recovery happened, the last step is to turn on snooping.
+ * In the non-recovery case this has no effect */
+ if ((rc = pnv_phb_to_cxl_mode(dev, OPAL_PHB_CAPI_MODE_SNOOP_ON))) {
+ goto err3;
+ }
+
if ((rc = cxl_register_psl_err_irq(adapter)))
goto err3;
diff --git a/drivers/misc/cxl/sysfs.c b/drivers/misc/cxl/sysfs.c
index 461bdbd5d483..d0c38c7bc0c4 100644
--- a/drivers/misc/cxl/sysfs.c
+++ b/drivers/misc/cxl/sysfs.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/device.h>
#include <linux/sysfs.h>
+#include <linux/pci_regs.h>
#include "cxl.h"
@@ -56,11 +57,68 @@ static ssize_t image_loaded_show(struct device *device,
return scnprintf(buf, PAGE_SIZE, "factory\n");
}
+static ssize_t reset_adapter_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+ int rc;
+ int val;
+
+ rc = sscanf(buf, "%i", &val);
+ if ((rc != 1) || (val != 1))
+ return -EINVAL;
+
+ if ((rc = cxl_reset(adapter)))
+ return rc;
+ return count;
+}
+
+static ssize_t load_image_on_perst_show(struct device *device,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+
+ if (!adapter->perst_loads_image)
+ return scnprintf(buf, PAGE_SIZE, "none\n");
+
+ if (adapter->perst_select_user)
+ return scnprintf(buf, PAGE_SIZE, "user\n");
+ return scnprintf(buf, PAGE_SIZE, "factory\n");
+}
+
+static ssize_t load_image_on_perst_store(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct cxl *adapter = to_cxl_adapter(device);
+ int rc;
+
+ if (!strncmp(buf, "none", 4))
+ adapter->perst_loads_image = false;
+ else if (!strncmp(buf, "user", 4)) {
+ adapter->perst_select_user = true;
+ adapter->perst_loads_image = true;
+ } else if (!strncmp(buf, "factory", 7)) {
+ adapter->perst_select_user = false;
+ adapter->perst_loads_image = true;
+ } else
+ return -EINVAL;
+
+ if ((rc = cxl_update_image_control(adapter)))
+ return rc;
+
+ return count;
+}
+
static struct device_attribute adapter_attrs[] = {
__ATTR_RO(caia_version),
__ATTR_RO(psl_revision),
__ATTR_RO(base_image),
__ATTR_RO(image_loaded),
+ __ATTR_RW(load_image_on_perst),
+ __ATTR(reset, S_IWUSR, NULL, reset_adapter_store),
};
@@ -310,8 +368,6 @@ static struct device_attribute afu_attrs[] = {
__ATTR(reset, S_IWUSR, NULL, reset_store_afu),
};
-
-
int cxl_sysfs_adapter_add(struct cxl *adapter)
{
int i, rc;
@@ -334,31 +390,191 @@ void cxl_sysfs_adapter_remove(struct cxl *adapter)
device_remove_file(&adapter->dev, &adapter_attrs[i]);
}
+struct afu_config_record {
+ struct kobject kobj;
+ struct bin_attribute config_attr;
+ struct list_head list;
+ int cr;
+ u16 device;
+ u16 vendor;
+ u32 class;
+};
+
+#define to_cr(obj) container_of(obj, struct afu_config_record, kobj)
+
+static ssize_t vendor_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct afu_config_record *cr = to_cr(kobj);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->vendor);
+}
+
+static ssize_t device_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct afu_config_record *cr = to_cr(kobj);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%.4x\n", cr->device);
+}
+
+static ssize_t class_show(struct kobject *kobj,
+ struct kobj_attribute *attr, char *buf)
+{
+ struct afu_config_record *cr = to_cr(kobj);
+
+ return scnprintf(buf, PAGE_SIZE, "0x%.6x\n", cr->class);
+}
+
+static ssize_t afu_read_config(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct afu_config_record *cr = to_cr(kobj);
+ struct cxl_afu *afu = to_cxl_afu(container_of(kobj->parent, struct device, kobj));
+
+ u64 i, j, val, size = afu->crs_len;
+
+ if (off > size)
+ return 0;
+ if (off + count > size)
+ count = size - off;
+
+ for (i = 0; i < count;) {
+ val = cxl_afu_cr_read64(afu, cr->cr, off & ~0x7);
+ for (j = off & 0x7; j < 8 && i < count; i++, j++, off++)
+ buf[i] = (val >> (j * 8)) & 0xff;
+ }
+
+ return count;
+}
+
+static struct kobj_attribute vendor_attribute =
+ __ATTR_RO(vendor);
+static struct kobj_attribute device_attribute =
+ __ATTR_RO(device);
+static struct kobj_attribute class_attribute =
+ __ATTR_RO(class);
+
+static struct attribute *afu_cr_attrs[] = {
+ &vendor_attribute.attr,
+ &device_attribute.attr,
+ &class_attribute.attr,
+ NULL,
+};
+
+static void release_afu_config_record(struct kobject *kobj)
+{
+ struct afu_config_record *cr = to_cr(kobj);
+
+ kfree(cr);
+}
+
+static struct kobj_type afu_config_record_type = {
+ .sysfs_ops = &kobj_sysfs_ops,
+ .release = release_afu_config_record,
+ .default_attrs = afu_cr_attrs,
+};
+
+static struct afu_config_record *cxl_sysfs_afu_new_cr(struct cxl_afu *afu, int cr_idx)
+{
+ struct afu_config_record *cr;
+ int rc;
+
+ cr = kzalloc(sizeof(struct afu_config_record), GFP_KERNEL);
+ if (!cr)
+ return ERR_PTR(-ENOMEM);
+
+ cr->cr = cr_idx;
+ cr->device = cxl_afu_cr_read16(afu, cr_idx, PCI_DEVICE_ID);
+ cr->vendor = cxl_afu_cr_read16(afu, cr_idx, PCI_VENDOR_ID);
+ cr->class = cxl_afu_cr_read32(afu, cr_idx, PCI_CLASS_REVISION) >> 8;
+
+ /*
+ * Export raw AFU PCIe like config record. For now this is read only by
+ * root - we can expand that later to be readable by non-root and maybe
+ * even writable provided we have a good use-case. Once we suport
+ * exposing AFUs through a virtual PHB they will get that for free from
+ * Linux' PCI infrastructure, but until then it's not clear that we
+ * need it for anything since the main use case is just identifying
+ * AFUs, which can be done via the vendor, device and class attributes.
+ */
+ sysfs_bin_attr_init(&cr->config_attr);
+ cr->config_attr.attr.name = "config";
+ cr->config_attr.attr.mode = S_IRUSR;
+ cr->config_attr.size = afu->crs_len;
+ cr->config_attr.read = afu_read_config;
+
+ rc = kobject_init_and_add(&cr->kobj, &afu_config_record_type,
+ &afu->dev.kobj, "cr%i", cr->cr);
+ if (rc)
+ goto err;
+
+ rc = sysfs_create_bin_file(&cr->kobj, &cr->config_attr);
+ if (rc)
+ goto err1;
+
+ rc = kobject_uevent(&cr->kobj, KOBJ_ADD);
+ if (rc)
+ goto err2;
+
+ return cr;
+err2:
+ sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
+err1:
+ kobject_put(&cr->kobj);
+ return ERR_PTR(rc);
+err:
+ kfree(cr);
+ return ERR_PTR(rc);
+}
+
+void cxl_sysfs_afu_remove(struct cxl_afu *afu)
+{
+ struct afu_config_record *cr, *tmp;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
+ device_remove_file(&afu->dev, &afu_attrs[i]);
+
+ list_for_each_entry_safe(cr, tmp, &afu->crs, list) {
+ sysfs_remove_bin_file(&cr->kobj, &cr->config_attr);
+ kobject_put(&cr->kobj);
+ }
+}
+
int cxl_sysfs_afu_add(struct cxl_afu *afu)
{
+ struct afu_config_record *cr;
int i, rc;
+ INIT_LIST_HEAD(&afu->crs);
+
for (i = 0; i < ARRAY_SIZE(afu_attrs); i++) {
if ((rc = device_create_file(&afu->dev, &afu_attrs[i])))
goto err;
}
+ for (i = 0; i < afu->crs_num; i++) {
+ cr = cxl_sysfs_afu_new_cr(afu, i);
+ if (IS_ERR(cr)) {
+ rc = PTR_ERR(cr);
+ goto err1;
+ }
+ list_add(&cr->list, &afu->crs);
+ }
+
return 0;
+err1:
+ cxl_sysfs_afu_remove(afu);
+ return rc;
err:
for (i--; i >= 0; i--)
device_remove_file(&afu->dev, &afu_attrs[i]);
return rc;
}
-void cxl_sysfs_afu_remove(struct cxl_afu *afu)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(afu_attrs); i++)
- device_remove_file(&afu->dev, &afu_attrs[i]);
-}
-
int cxl_sysfs_afu_m_add(struct cxl_afu *afu)
{
int i, rc;
diff --git a/drivers/misc/cxl/trace.c b/drivers/misc/cxl/trace.c
new file mode 100644
index 000000000000..c2b06d319e6e
--- /dev/null
+++ b/drivers/misc/cxl/trace.c
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#ifndef __CHECKER__
+#define CREATE_TRACE_POINTS
+#include "trace.h"
+#endif
diff --git a/drivers/misc/cxl/trace.h b/drivers/misc/cxl/trace.h
new file mode 100644
index 000000000000..ae434d87887e
--- /dev/null
+++ b/drivers/misc/cxl/trace.h
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2015 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cxl
+
+#if !defined(_CXL_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _CXL_TRACE_H
+
+#include <linux/tracepoint.h>
+
+#include "cxl.h"
+
+#define DSISR_FLAGS \
+ { CXL_PSL_DSISR_An_DS, "DS" }, \
+ { CXL_PSL_DSISR_An_DM, "DM" }, \
+ { CXL_PSL_DSISR_An_ST, "ST" }, \
+ { CXL_PSL_DSISR_An_UR, "UR" }, \
+ { CXL_PSL_DSISR_An_PE, "PE" }, \
+ { CXL_PSL_DSISR_An_AE, "AE" }, \
+ { CXL_PSL_DSISR_An_OC, "OC" }, \
+ { CXL_PSL_DSISR_An_M, "M" }, \
+ { CXL_PSL_DSISR_An_P, "P" }, \
+ { CXL_PSL_DSISR_An_A, "A" }, \
+ { CXL_PSL_DSISR_An_S, "S" }, \
+ { CXL_PSL_DSISR_An_K, "K" }
+
+#define TFC_FLAGS \
+ { CXL_PSL_TFC_An_A, "A" }, \
+ { CXL_PSL_TFC_An_C, "C" }, \
+ { CXL_PSL_TFC_An_AE, "AE" }, \
+ { CXL_PSL_TFC_An_R, "R" }
+
+#define LLCMD_NAMES \
+ { CXL_SPA_SW_CMD_TERMINATE, "TERMINATE" }, \
+ { CXL_SPA_SW_CMD_REMOVE, "REMOVE" }, \
+ { CXL_SPA_SW_CMD_SUSPEND, "SUSPEND" }, \
+ { CXL_SPA_SW_CMD_RESUME, "RESUME" }, \
+ { CXL_SPA_SW_CMD_ADD, "ADD" }, \
+ { CXL_SPA_SW_CMD_UPDATE, "UPDATE" }
+
+#define AFU_COMMANDS \
+ { 0, "DISABLE" }, \
+ { CXL_AFU_Cntl_An_E, "ENABLE" }, \
+ { CXL_AFU_Cntl_An_RA, "RESET" }
+
+#define PSL_COMMANDS \
+ { CXL_PSL_SCNTL_An_Pc, "PURGE" }, \
+ { CXL_PSL_SCNTL_An_Sc, "SUSPEND" }
+
+
+DECLARE_EVENT_CLASS(cxl_pe_class,
+ TP_PROTO(struct cxl_context *ctx),
+
+ TP_ARGS(ctx),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ ),
+
+ TP_printk("afu%i.%i pe=%i",
+ __entry->card,
+ __entry->afu,
+ __entry->pe
+ )
+);
+
+
+TRACE_EVENT(cxl_attach,
+ TP_PROTO(struct cxl_context *ctx, u64 wed, s16 num_interrupts, u64 amr),
+
+ TP_ARGS(ctx, wed, num_interrupts, amr),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(pid_t, pid)
+ __field(u64, wed)
+ __field(u64, amr)
+ __field(s16, num_interrupts)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->pid = pid_nr(ctx->pid);
+ __entry->wed = wed;
+ __entry->amr = amr;
+ __entry->num_interrupts = num_interrupts;
+ ),
+
+ TP_printk("afu%i.%i pid=%i pe=%i wed=0x%.16llx irqs=%i amr=0x%llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pid,
+ __entry->pe,
+ __entry->wed,
+ __entry->num_interrupts,
+ __entry->amr
+ )
+);
+
+DEFINE_EVENT(cxl_pe_class, cxl_detach,
+ TP_PROTO(struct cxl_context *ctx),
+ TP_ARGS(ctx)
+);
+
+TRACE_EVENT(cxl_afu_irq,
+ TP_PROTO(struct cxl_context *ctx, int afu_irq, int virq, irq_hw_number_t hwirq),
+
+ TP_ARGS(ctx, afu_irq, virq, hwirq),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u16, afu_irq)
+ __field(int, virq)
+ __field(irq_hw_number_t, hwirq)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->afu_irq = afu_irq;
+ __entry->virq = virq;
+ __entry->hwirq = hwirq;
+ ),
+
+ TP_printk("afu%i.%i pe=%i afu_irq=%i virq=%i hwirq=0x%lx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->afu_irq,
+ __entry->virq,
+ __entry->hwirq
+ )
+);
+
+TRACE_EVENT(cxl_psl_irq,
+ TP_PROTO(struct cxl_context *ctx, int irq, u64 dsisr, u64 dar),
+
+ TP_ARGS(ctx, irq, dsisr, dar),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(int, irq)
+ __field(u64, dsisr)
+ __field(u64, dar)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->irq = irq;
+ __entry->dsisr = dsisr;
+ __entry->dar = dar;
+ ),
+
+ TP_printk("afu%i.%i pe=%i irq=%i dsisr=%s dar=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->irq,
+ __print_flags(__entry->dsisr, "|", DSISR_FLAGS),
+ __entry->dar
+ )
+);
+
+TRACE_EVENT(cxl_psl_irq_ack,
+ TP_PROTO(struct cxl_context *ctx, u64 tfc),
+
+ TP_ARGS(ctx, tfc),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, tfc)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->tfc = tfc;
+ ),
+
+ TP_printk("afu%i.%i pe=%i tfc=%s",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_flags(__entry->tfc, "|", TFC_FLAGS)
+ )
+);
+
+TRACE_EVENT(cxl_ste_miss,
+ TP_PROTO(struct cxl_context *ctx, u64 dar),
+
+ TP_ARGS(ctx, dar),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, dar)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->dar = dar;
+ ),
+
+ TP_printk("afu%i.%i pe=%i dar=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->dar
+ )
+);
+
+TRACE_EVENT(cxl_ste_write,
+ TP_PROTO(struct cxl_context *ctx, unsigned int idx, u64 e, u64 v),
+
+ TP_ARGS(ctx, idx, e, v),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(unsigned int, idx)
+ __field(u64, e)
+ __field(u64, v)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->idx = idx;
+ __entry->e = e;
+ __entry->v = v;
+ ),
+
+ TP_printk("afu%i.%i pe=%i SSTE[%i] E=0x%.16llx V=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __entry->idx,
+ __entry->e,
+ __entry->v
+ )
+);
+
+TRACE_EVENT(cxl_pte_miss,
+ TP_PROTO(struct cxl_context *ctx, u64 dsisr, u64 dar),
+
+ TP_ARGS(ctx, dsisr, dar),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, dsisr)
+ __field(u64, dar)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->dsisr = dsisr;
+ __entry->dar = dar;
+ ),
+
+ TP_printk("afu%i.%i pe=%i dsisr=%s dar=0x%.16llx",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_flags(__entry->dsisr, "|", DSISR_FLAGS),
+ __entry->dar
+ )
+);
+
+TRACE_EVENT(cxl_llcmd,
+ TP_PROTO(struct cxl_context *ctx, u64 cmd),
+
+ TP_ARGS(ctx, cmd),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, cmd)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i pe=%i cmd=%s",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_symbolic_u64(__entry->cmd, LLCMD_NAMES)
+ )
+);
+
+TRACE_EVENT(cxl_llcmd_done,
+ TP_PROTO(struct cxl_context *ctx, u64 cmd, int rc),
+
+ TP_ARGS(ctx, cmd, rc),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u16, pe)
+ __field(u64, cmd)
+ __field(int, rc)
+ ),
+
+ TP_fast_assign(
+ __entry->card = ctx->afu->adapter->adapter_num;
+ __entry->afu = ctx->afu->slice;
+ __entry->pe = ctx->pe;
+ __entry->rc = rc;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i pe=%i cmd=%s rc=%i",
+ __entry->card,
+ __entry->afu,
+ __entry->pe,
+ __print_symbolic_u64(__entry->cmd, LLCMD_NAMES),
+ __entry->rc
+ )
+);
+
+DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd),
+
+ TP_ARGS(afu, cmd),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u64, cmd)
+ ),
+
+ TP_fast_assign(
+ __entry->card = afu->adapter->adapter_num;
+ __entry->afu = afu->slice;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i cmd=%s",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, AFU_COMMANDS)
+ )
+);
+
+DECLARE_EVENT_CLASS(cxl_afu_psl_ctrl_done,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
+
+ TP_ARGS(afu, cmd, rc),
+
+ TP_STRUCT__entry(
+ __field(u8, card)
+ __field(u8, afu)
+ __field(u64, cmd)
+ __field(int, rc)
+ ),
+
+ TP_fast_assign(
+ __entry->card = afu->adapter->adapter_num;
+ __entry->afu = afu->slice;
+ __entry->rc = rc;
+ __entry->cmd = cmd;
+ ),
+
+ TP_printk("afu%i.%i cmd=%s rc=%i",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, AFU_COMMANDS),
+ __entry->rc
+ )
+);
+
+DEFINE_EVENT(cxl_afu_psl_ctrl, cxl_afu_ctrl,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd),
+ TP_ARGS(afu, cmd)
+);
+
+DEFINE_EVENT(cxl_afu_psl_ctrl_done, cxl_afu_ctrl_done,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
+ TP_ARGS(afu, cmd, rc)
+);
+
+DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl, cxl_psl_ctrl,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd),
+ TP_ARGS(afu, cmd),
+
+ TP_printk("psl%i.%i cmd=%s",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, PSL_COMMANDS)
+ )
+);
+
+DEFINE_EVENT_PRINT(cxl_afu_psl_ctrl_done, cxl_psl_ctrl_done,
+ TP_PROTO(struct cxl_afu *afu, u64 cmd, int rc),
+ TP_ARGS(afu, cmd, rc),
+
+ TP_printk("psl%i.%i cmd=%s rc=%i",
+ __entry->card,
+ __entry->afu,
+ __print_symbolic_u64(__entry->cmd, PSL_COMMANDS),
+ __entry->rc
+ )
+);
+
+DEFINE_EVENT(cxl_pe_class, cxl_slbia,
+ TP_PROTO(struct cxl_context *ctx),
+ TP_ARGS(ctx)
+);
+
+#endif /* _CXL_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE trace
+#include <trace/define_trace.h>
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 180a5442fd4b..38552a31304a 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -145,8 +145,11 @@ enclosure_register(struct device *dev, const char *name, int components,
if (err)
goto err;
- for (i = 0; i < components; i++)
+ for (i = 0; i < components; i++) {
edev->component[i].number = -1;
+ edev->component[i].slot = -1;
+ edev->component[i].power_status = 1;
+ }
mutex_lock(&container_list_lock);
list_add_tail(&edev->node, &container_list);
@@ -273,27 +276,26 @@ enclosure_component_find_by_name(struct enclosure_device *edev,
static const struct attribute_group *enclosure_component_groups[];
/**
- * enclosure_component_register - add a particular component to an enclosure
+ * enclosure_component_alloc - prepare a new enclosure component
* @edev: the enclosure to add the component
* @num: the device number
* @type: the type of component being added
* @name: an optional name to appear in sysfs (leave NULL if none)
*
- * Registers the component. The name is optional for enclosures that
- * give their components a unique name. If not, leave the field NULL
- * and a name will be assigned.
+ * The name is optional for enclosures that give their components a unique
+ * name. If not, leave the field NULL and a name will be assigned.
*
* Returns a pointer to the enclosure component or an error.
*/
struct enclosure_component *
-enclosure_component_register(struct enclosure_device *edev,
- unsigned int number,
- enum enclosure_component_type type,
- const char *name)
+enclosure_component_alloc(struct enclosure_device *edev,
+ unsigned int number,
+ enum enclosure_component_type type,
+ const char *name)
{
struct enclosure_component *ecomp;
struct device *cdev;
- int err, i;
+ int i;
char newname[COMPONENT_NAME_SIZE];
if (number >= edev->components)
@@ -327,14 +329,30 @@ enclosure_component_register(struct enclosure_device *edev,
cdev->release = enclosure_component_release;
cdev->groups = enclosure_component_groups;
+ return ecomp;
+}
+EXPORT_SYMBOL_GPL(enclosure_component_alloc);
+
+/**
+ * enclosure_component_register - publishes an initialized enclosure component
+ * @ecomp: component to add
+ *
+ * Returns 0 on successful registration, releases the component otherwise
+ */
+int enclosure_component_register(struct enclosure_component *ecomp)
+{
+ struct device *cdev;
+ int err;
+
+ cdev = &ecomp->cdev;
err = device_register(cdev);
if (err) {
ecomp->number = -1;
put_device(cdev);
- return ERR_PTR(err);
+ return err;
}
- return ecomp;
+ return 0;
}
EXPORT_SYMBOL_GPL(enclosure_component_register);
@@ -417,8 +435,21 @@ static ssize_t components_show(struct device *cdev,
}
static DEVICE_ATTR_RO(components);
+static ssize_t id_show(struct device *cdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct enclosure_device *edev = to_enclosure_device(cdev);
+
+ if (edev->cb->show_id)
+ return edev->cb->show_id(edev, buf);
+ return -EINVAL;
+}
+static DEVICE_ATTR_RO(id);
+
static struct attribute *enclosure_class_attrs[] = {
&dev_attr_components.attr,
+ &dev_attr_id.attr,
NULL,
};
ATTRIBUTE_GROUPS(enclosure_class);
@@ -553,6 +584,40 @@ static ssize_t set_component_locate(struct device *cdev,
return count;
}
+static ssize_t get_component_power_status(struct device *cdev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct enclosure_device *edev = to_enclosure_device(cdev->parent);
+ struct enclosure_component *ecomp = to_enclosure_component(cdev);
+
+ if (edev->cb->get_power_status)
+ edev->cb->get_power_status(edev, ecomp);
+ return snprintf(buf, 40, "%s\n", ecomp->power_status ? "on" : "off");
+}
+
+static ssize_t set_component_power_status(struct device *cdev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct enclosure_device *edev = to_enclosure_device(cdev->parent);
+ struct enclosure_component *ecomp = to_enclosure_component(cdev);
+ int val;
+
+ if (strncmp(buf, "on", 2) == 0 &&
+ (buf[2] == '\n' || buf[2] == '\0'))
+ val = 1;
+ else if (strncmp(buf, "off", 3) == 0 &&
+ (buf[3] == '\n' || buf[3] == '\0'))
+ val = 0;
+ else
+ return -EINVAL;
+
+ if (edev->cb->set_power_status)
+ edev->cb->set_power_status(edev, ecomp, val);
+ return count;
+}
+
static ssize_t get_component_type(struct device *cdev,
struct device_attribute *attr, char *buf)
{
@@ -561,6 +626,20 @@ static ssize_t get_component_type(struct device *cdev,
return snprintf(buf, 40, "%s\n", enclosure_type[ecomp->type]);
}
+static ssize_t get_component_slot(struct device *cdev,
+ struct device_attribute *attr, char *buf)
+{
+ struct enclosure_component *ecomp = to_enclosure_component(cdev);
+ int slot;
+
+ /* if the enclosure does not override then use 'number' as a stand-in */
+ if (ecomp->slot >= 0)
+ slot = ecomp->slot;
+ else
+ slot = ecomp->number;
+
+ return snprintf(buf, 40, "%d\n", slot);
+}
static DEVICE_ATTR(fault, S_IRUGO | S_IWUSR, get_component_fault,
set_component_fault);
@@ -570,14 +649,19 @@ static DEVICE_ATTR(active, S_IRUGO | S_IWUSR, get_component_active,
set_component_active);
static DEVICE_ATTR(locate, S_IRUGO | S_IWUSR, get_component_locate,
set_component_locate);
+static DEVICE_ATTR(power_status, S_IRUGO | S_IWUSR, get_component_power_status,
+ set_component_power_status);
static DEVICE_ATTR(type, S_IRUGO, get_component_type, NULL);
+static DEVICE_ATTR(slot, S_IRUGO, get_component_slot, NULL);
static struct attribute *enclosure_component_attrs[] = {
&dev_attr_fault.attr,
&dev_attr_status.attr,
&dev_attr_active.attr,
&dev_attr_locate.attr,
+ &dev_attr_power_status.attr,
&dev_attr_type.attr,
+ &dev_attr_slot.attr,
NULL
};
ATTRIBUTE_GROUPS(enclosure_component);
diff --git a/drivers/misc/genwqe/card_base.h b/drivers/misc/genwqe/card_base.h
index c64d7cad1085..e7353449874b 100644
--- a/drivers/misc/genwqe/card_base.h
+++ b/drivers/misc/genwqe/card_base.h
@@ -34,7 +34,6 @@
#include <linux/semaphore.h>
#include <linux/uaccess.h>
#include <linux/io.h>
-#include <linux/version.h>
#include <linux/debugfs.h>
#include <linux/slab.h>
diff --git a/drivers/misc/genwqe/card_sysfs.c b/drivers/misc/genwqe/card_sysfs.c
index 2c33fbca9225..6ab31eff0536 100644
--- a/drivers/misc/genwqe/card_sysfs.c
+++ b/drivers/misc/genwqe/card_sysfs.c
@@ -24,7 +24,6 @@
* debugging, please also see the debugfs interfaces of this driver.
*/
-#include <linux/version.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/module.h>
diff --git a/drivers/misc/ioc4.c b/drivers/misc/ioc4.c
index 3336ddca45ac..8758d033db23 100644
--- a/drivers/misc/ioc4.c
+++ b/drivers/misc/ioc4.c
@@ -144,9 +144,9 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
{
union ioc4_int_out int_out;
union ioc4_gpcr gpcr;
- unsigned int state, last_state = 1;
+ unsigned int state, last_state;
uint64_t start, end, period;
- unsigned int count = 0;
+ unsigned int count;
/* Enable output */
gpcr.raw = 0;
@@ -167,19 +167,20 @@ ioc4_clock_calibrate(struct ioc4_driver_data *idd)
mmiowb();
/* Check square wave period averaged over some number of cycles */
- do {
- int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
- state = int_out.fields.int_out;
- if (!last_state && state) {
- count++;
- if (count == IOC4_CALIBRATE_END) {
- end = ktime_get_ns();
- break;
- } else if (count == IOC4_CALIBRATE_DISCARD)
- start = ktime_get_ns();
- }
- last_state = state;
- } while (1);
+ start = ktime_get_ns();
+ state = 1; /* make sure the first read isn't a rising edge */
+ for (count = 0; count <= IOC4_CALIBRATE_END; count++) {
+ do { /* wait for a rising edge */
+ last_state = state;
+ int_out.raw = readl(&idd->idd_misc_regs->int_out.raw);
+ state = int_out.fields.int_out;
+ } while (last_state || !state);
+
+ /* discard the first few cycles */
+ if (count == IOC4_CALIBRATE_DISCARD)
+ start = ktime_get_ns();
+ }
+ end = ktime_get_ns();
/* Calculation rearranged to preserve intermediate precision.
* Logically:
diff --git a/drivers/misc/mei/amthif.c b/drivers/misc/mei/amthif.c
index 79f53941779d..c4cb9a984a5f 100644
--- a/drivers/misc/mei/amthif.c
+++ b/drivers/misc/mei/amthif.c
@@ -97,23 +97,25 @@ int mei_amthif_host_init(struct mei_device *dev)
/* allocate storage for ME message buffer */
msg_buf = kcalloc(dev->iamthif_mtu,
sizeof(unsigned char), GFP_KERNEL);
- if (!msg_buf)
- return -ENOMEM;
+ if (!msg_buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
dev->iamthif_msg_buf = msg_buf;
ret = mei_cl_link(cl, MEI_IAMTHIF_HOST_CLIENT_ID);
-
if (ret < 0) {
- dev_err(dev->dev,
- "amthif: failed link client %d\n", ret);
- return ret;
+ dev_err(dev->dev, "amthif: failed cl_link %d\n", ret);
+ goto out;
}
ret = mei_cl_connect(cl, NULL);
dev->iamthif_state = MEI_IAMTHIF_IDLE;
+out:
+ mei_me_cl_put(me_cl);
return ret;
}
diff --git a/drivers/misc/mei/bus.c b/drivers/misc/mei/bus.c
index b3a72bca5242..be767f4db26a 100644
--- a/drivers/misc/mei/bus.c
+++ b/drivers/misc/mei/bus.c
@@ -224,46 +224,53 @@ void mei_cl_driver_unregister(struct mei_cl_driver *driver)
}
EXPORT_SYMBOL_GPL(mei_cl_driver_unregister);
-static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
+static ssize_t ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
bool blocking)
{
struct mei_device *dev;
- struct mei_me_client *me_cl;
- struct mei_cl_cb *cb;
- int rets;
+ struct mei_me_client *me_cl = NULL;
+ struct mei_cl_cb *cb = NULL;
+ ssize_t rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
dev = cl->dev;
- if (cl->state != MEI_FILE_CONNECTED)
- return -ENODEV;
+ mutex_lock(&dev->device_lock);
+ if (cl->state != MEI_FILE_CONNECTED) {
+ rets = -ENODEV;
+ goto out;
+ }
/* Check if we have an ME client device */
me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
- if (!me_cl)
- return -ENOTTY;
+ if (!me_cl) {
+ rets = -ENOTTY;
+ goto out;
+ }
- if (length > me_cl->props.max_msg_length)
- return -EFBIG;
+ if (length > me_cl->props.max_msg_length) {
+ rets = -EFBIG;
+ goto out;
+ }
cb = mei_io_cb_init(cl, NULL);
- if (!cb)
- return -ENOMEM;
+ if (!cb) {
+ rets = -ENOMEM;
+ goto out;
+ }
rets = mei_io_cb_alloc_req_buf(cb, length);
- if (rets < 0) {
- mei_io_cb_free(cb);
- return rets;
- }
+ if (rets < 0)
+ goto out;
memcpy(cb->request_buffer.data, buf, length);
- mutex_lock(&dev->device_lock);
-
rets = mei_cl_write(cl, cb, blocking);
+out:
+ mei_me_cl_put(me_cl);
mutex_unlock(&dev->device_lock);
if (rets < 0)
mei_io_cb_free(cb);
@@ -271,12 +278,12 @@ static int ___mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length,
return rets;
}
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
{
struct mei_device *dev;
struct mei_cl_cb *cb;
size_t r_length;
- int err;
+ ssize_t rets;
if (WARN_ON(!cl || !cl->dev))
return -ENODEV;
@@ -286,11 +293,9 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
mutex_lock(&dev->device_lock);
if (!cl->read_cb) {
- err = mei_cl_read_start(cl, length);
- if (err < 0) {
- mutex_unlock(&dev->device_lock);
- return err;
- }
+ rets = mei_cl_read_start(cl, length);
+ if (rets < 0)
+ goto out;
}
if (cl->reading_state != MEI_READ_COMPLETE &&
@@ -313,13 +318,13 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
cb = cl->read_cb;
if (cl->reading_state != MEI_READ_COMPLETE) {
- r_length = 0;
+ rets = 0;
goto out;
}
r_length = min_t(size_t, length, cb->buf_idx);
-
memcpy(buf, cb->response_buffer.data, r_length);
+ rets = r_length;
mei_io_cb_free(cb);
cl->reading_state = MEI_IDLE;
@@ -328,20 +333,20 @@ int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length)
out:
mutex_unlock(&dev->device_lock);
- return r_length;
+ return rets;
}
-inline int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
+inline ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length)
{
return ___mei_cl_send(cl, buf, length, 0);
}
-inline int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
+inline ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length)
{
return ___mei_cl_send(cl, buf, length, 1);
}
-int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
+ssize_t mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
{
struct mei_cl *cl = device->cl;
@@ -355,7 +360,7 @@ int mei_cl_send(struct mei_cl_device *device, u8 *buf, size_t length)
}
EXPORT_SYMBOL_GPL(mei_cl_send);
-int mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
+ssize_t mei_cl_recv(struct mei_cl_device *device, u8 *buf, size_t length)
{
struct mei_cl *cl = device->cl;
diff --git a/drivers/misc/mei/client.c b/drivers/misc/mei/client.c
index 1382d551d7ed..dfbddfe1c7a0 100644
--- a/drivers/misc/mei/client.c
+++ b/drivers/misc/mei/client.c
@@ -27,7 +27,63 @@
#include "client.h"
/**
+ * mei_me_cl_init - initialize me client
+ *
+ * @me_cl: me client
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl)
+{
+ INIT_LIST_HEAD(&me_cl->list);
+ kref_init(&me_cl->refcnt);
+}
+
+/**
+ * mei_me_cl_get - increases me client refcount
+ *
+ * @me_cl: me client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * Return: me client or NULL
+ */
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl)
+{
+ if (me_cl)
+ kref_get(&me_cl->refcnt);
+
+ return me_cl;
+}
+
+/**
+ * mei_me_cl_release - unlink and free me client
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @ref: me_client refcount
+ */
+static void mei_me_cl_release(struct kref *ref)
+{
+ struct mei_me_client *me_cl =
+ container_of(ref, struct mei_me_client, refcnt);
+ list_del(&me_cl->list);
+ kfree(me_cl);
+}
+/**
+ * mei_me_cl_put - decrease me client refcount and free client if necessary
+ *
+ * Locking: called under "dev->device_lock" lock
+ *
+ * @me_cl: me client
+ */
+void mei_me_cl_put(struct mei_me_client *me_cl)
+{
+ if (me_cl)
+ kref_put(&me_cl->refcnt, mei_me_cl_release);
+}
+
+/**
* mei_me_cl_by_uuid - locate me client by uuid
+ * increases ref count
*
* @dev: mei device
* @uuid: me client uuid
@@ -43,13 +99,14 @@ struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
list_for_each_entry(me_cl, &dev->me_clients, list)
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
- return me_cl;
+ return mei_me_cl_get(me_cl);
return NULL;
}
/**
* mei_me_cl_by_id - locate me client by client id
+ * increases ref count
*
* @dev: the device structure
* @client_id: me client id
@@ -65,12 +122,14 @@ struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id)
list_for_each_entry(me_cl, &dev->me_clients, list)
if (me_cl->client_id == client_id)
- return me_cl;
+ return mei_me_cl_get(me_cl);
+
return NULL;
}
/**
* mei_me_cl_by_uuid_id - locate me client by client id and uuid
+ * increases ref count
*
* @dev: the device structure
* @uuid: me client uuid
@@ -88,31 +147,67 @@ struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
list_for_each_entry(me_cl, &dev->me_clients, list)
if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
me_cl->client_id == client_id)
- return me_cl;
+ return mei_me_cl_get(me_cl);
+
return NULL;
}
/**
- * mei_me_cl_remove - remove me client matching uuid and client_id
+ * mei_me_cl_rm_by_uuid - remove all me clients matching uuid
*
* @dev: the device structure
* @uuid: me client uuid
- * @client_id: me client address
+ *
+ * Locking: called under "dev->device_lock" lock
*/
-void mei_me_cl_remove(struct mei_device *dev, const uuid_le *uuid, u8 client_id)
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid)
{
struct mei_me_client *me_cl, *next;
+ dev_dbg(dev->dev, "remove %pUl\n", uuid);
+ list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
+ if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0)
+ mei_me_cl_put(me_cl);
+}
+
+/**
+ * mei_me_cl_rm_by_uuid_id - remove all me clients matching client id
+ *
+ * @dev: the device structure
+ * @uuid: me client uuid
+ * @id: me client id
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev, const uuid_le *uuid, u8 id)
+{
+ struct mei_me_client *me_cl, *next;
+ const uuid_le *pn;
+
+ dev_dbg(dev->dev, "remove %pUl %d\n", uuid, id);
list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
- if (uuid_le_cmp(*uuid, me_cl->props.protocol_name) == 0 &&
- me_cl->client_id == client_id) {
- list_del(&me_cl->list);
- kfree(me_cl);
- break;
- }
+ pn = &me_cl->props.protocol_name;
+ if (me_cl->client_id == id && uuid_le_cmp(*uuid, *pn) == 0)
+ mei_me_cl_put(me_cl);
}
}
+/**
+ * mei_me_cl_rm_all - remove all me clients
+ *
+ * @dev: the device structure
+ *
+ * Locking: called under "dev->device_lock" lock
+ */
+void mei_me_cl_rm_all(struct mei_device *dev)
+{
+ struct mei_me_client *me_cl, *next;
+
+ list_for_each_entry_safe(me_cl, next, &dev->me_clients, list)
+ mei_me_cl_put(me_cl);
+}
+
+
/**
* mei_cl_cmp_id - tells if the clients are the same
@@ -695,6 +790,7 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
+ int rets = 0;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
@@ -704,18 +800,19 @@ int mei_cl_flow_ctrl_creds(struct mei_cl *cl)
if (cl->mei_flow_ctrl_creds > 0)
return 1;
- me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
+ me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return -ENOENT;
}
- if (me_cl->mei_flow_ctrl_creds) {
+ if (me_cl->mei_flow_ctrl_creds > 0) {
+ rets = 1;
if (WARN_ON(me_cl->props.single_recv_buf == 0))
- return -EINVAL;
- return 1;
+ rets = -EINVAL;
}
- return 0;
+ mei_me_cl_put(me_cl);
+ return rets;
}
/**
@@ -732,28 +829,36 @@ int mei_cl_flow_ctrl_reduce(struct mei_cl *cl)
{
struct mei_device *dev;
struct mei_me_client *me_cl;
+ int rets;
if (WARN_ON(!cl || !cl->dev))
return -EINVAL;
dev = cl->dev;
- me_cl = mei_me_cl_by_id(dev, cl->me_client_id);
+ me_cl = mei_me_cl_by_uuid_id(dev, &cl->cl_uuid, cl->me_client_id);
if (!me_cl) {
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return -ENOENT;
}
if (me_cl->props.single_recv_buf) {
- if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
+ if (WARN_ON(me_cl->mei_flow_ctrl_creds <= 0)) {
+ rets = -EINVAL;
+ goto out;
+ }
me_cl->mei_flow_ctrl_creds--;
} else {
- if (WARN_ON(cl->mei_flow_ctrl_creds <= 0))
- return -EINVAL;
+ if (WARN_ON(cl->mei_flow_ctrl_creds <= 0)) {
+ rets = -EINVAL;
+ goto out;
+ }
cl->mei_flow_ctrl_creds--;
}
- return 0;
+ rets = 0;
+out:
+ mei_me_cl_put(me_cl);
+ return rets;
}
/**
@@ -788,6 +893,9 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
cl_err(dev, cl, "no such me client %d\n", cl->me_client_id);
return -ENOTTY;
}
+ /* always allocate at least client max message */
+ length = max_t(size_t, length, me_cl->props.max_msg_length);
+ mei_me_cl_put(me_cl);
rets = pm_runtime_get(dev->dev);
if (rets < 0 && rets != -EINPROGRESS) {
@@ -802,8 +910,6 @@ int mei_cl_read_start(struct mei_cl *cl, size_t length)
goto out;
}
- /* always allocate at least client max message */
- length = max_t(size_t, length, me_cl->props.max_msg_length);
rets = mei_io_cb_alloc_resp_buf(cb, length);
if (rets)
goto out;
diff --git a/drivers/misc/mei/client.h b/drivers/misc/mei/client.h
index d9d0c1525259..cfcde8e97fc4 100644
--- a/drivers/misc/mei/client.h
+++ b/drivers/misc/mei/client.h
@@ -24,15 +24,22 @@
#include "mei_dev.h"
+/*
+ * reference counting base function
+ */
+void mei_me_cl_init(struct mei_me_client *me_cl);
+void mei_me_cl_put(struct mei_me_client *me_cl);
+struct mei_me_client *mei_me_cl_get(struct mei_me_client *me_cl);
+
struct mei_me_client *mei_me_cl_by_uuid(const struct mei_device *dev,
- const uuid_le *cuuid);
+ const uuid_le *uuid);
struct mei_me_client *mei_me_cl_by_id(struct mei_device *dev, u8 client_id);
-
struct mei_me_client *mei_me_cl_by_uuid_id(struct mei_device *dev,
const uuid_le *uuid, u8 client_id);
-
-void mei_me_cl_remove(struct mei_device *dev,
- const uuid_le *uuid, u8 client_id);
+void mei_me_cl_rm_by_uuid(struct mei_device *dev, const uuid_le *uuid);
+void mei_me_cl_rm_by_uuid_id(struct mei_device *dev,
+ const uuid_le *uuid, u8 id);
+void mei_me_cl_rm_all(struct mei_device *dev);
/*
* MEI IO Functions
diff --git a/drivers/misc/mei/debugfs.c b/drivers/misc/mei/debugfs.c
index b60b4263cf0f..b125380ee871 100644
--- a/drivers/misc/mei/debugfs.c
+++ b/drivers/misc/mei/debugfs.c
@@ -21,20 +21,22 @@
#include <linux/mei.h>
#include "mei_dev.h"
+#include "client.h"
#include "hw.h"
static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
size_t cnt, loff_t *ppos)
{
struct mei_device *dev = fp->private_data;
- struct mei_me_client *me_cl;
+ struct mei_me_client *me_cl, *n;
size_t bufsz = 1;
char *buf;
int i = 0;
int pos = 0;
int ret;
-#define HDR " |id|fix| UUID |con|msg len|sb|\n"
+#define HDR \
+" |id|fix| UUID |con|msg len|sb|refc|\n"
mutex_lock(&dev->device_lock);
@@ -54,16 +56,22 @@ static ssize_t mei_dbgfs_read_meclients(struct file *fp, char __user *ubuf,
if (dev->dev_state != MEI_DEV_ENABLED)
goto out;
- list_for_each_entry(me_cl, &dev->me_clients, list) {
-
- pos += scnprintf(buf + pos, bufsz - pos,
- "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|\n",
- i++, me_cl->client_id,
- me_cl->props.fixed_address,
- &me_cl->props.protocol_name,
- me_cl->props.max_number_of_connections,
- me_cl->props.max_msg_length,
- me_cl->props.single_recv_buf);
+ list_for_each_entry_safe(me_cl, n, &dev->me_clients, list) {
+
+ me_cl = mei_me_cl_get(me_cl);
+ if (me_cl) {
+ pos += scnprintf(buf + pos, bufsz - pos,
+ "%2d|%2d|%3d|%pUl|%3d|%7d|%2d|%4d|\n",
+ i++, me_cl->client_id,
+ me_cl->props.fixed_address,
+ &me_cl->props.protocol_name,
+ me_cl->props.max_number_of_connections,
+ me_cl->props.max_msg_length,
+ me_cl->props.single_recv_buf,
+ atomic_read(&me_cl->refcnt.refcount));
+ }
+
+ mei_me_cl_put(me_cl);
}
out:
mutex_unlock(&dev->device_lock);
diff --git a/drivers/misc/mei/hbm.c b/drivers/misc/mei/hbm.c
index 239d7f5d6a92..c8412d41e4f1 100644
--- a/drivers/misc/mei/hbm.c
+++ b/drivers/misc/mei/hbm.c
@@ -105,21 +105,6 @@ void mei_hbm_idle(struct mei_device *dev)
}
/**
- * mei_me_cl_remove_all - remove all me clients
- *
- * @dev: the device structure
- */
-static void mei_me_cl_remove_all(struct mei_device *dev)
-{
- struct mei_me_client *me_cl, *next;
-
- list_for_each_entry_safe(me_cl, next, &dev->me_clients, list) {
- list_del(&me_cl->list);
- kfree(me_cl);
- }
-}
-
-/**
* mei_hbm_reset - reset hbm counters and book keeping data structurs
*
* @dev: the device structure
@@ -128,7 +113,7 @@ void mei_hbm_reset(struct mei_device *dev)
{
dev->me_client_index = 0;
- mei_me_cl_remove_all(dev);
+ mei_me_cl_rm_all(dev);
mei_hbm_idle(dev);
}
@@ -339,11 +324,16 @@ static int mei_hbm_me_cl_add(struct mei_device *dev,
struct hbm_props_response *res)
{
struct mei_me_client *me_cl;
+ const uuid_le *uuid = &res->client_properties.protocol_name;
+
+ mei_me_cl_rm_by_uuid(dev, uuid);
me_cl = kzalloc(sizeof(struct mei_me_client), GFP_KERNEL);
if (!me_cl)
return -ENOMEM;
+ mei_me_cl_init(me_cl);
+
me_cl->props = res->client_properties;
me_cl->client_id = res->me_addr;
me_cl->mei_flow_ctrl_creds = 0;
@@ -484,6 +474,7 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
struct hbm_flow_control *flow)
{
struct mei_me_client *me_cl;
+ int rets;
me_cl = mei_me_cl_by_id(dev, flow->me_addr);
if (!me_cl) {
@@ -492,14 +483,19 @@ static int mei_hbm_add_single_flow_creds(struct mei_device *dev,
return -ENOENT;
}
- if (WARN_ON(me_cl->props.single_recv_buf == 0))
- return -EINVAL;
+ if (WARN_ON(me_cl->props.single_recv_buf == 0)) {
+ rets = -EINVAL;
+ goto out;
+ }
me_cl->mei_flow_ctrl_creds++;
dev_dbg(dev->dev, "recv flow ctrl msg ME %d (single) creds = %d.\n",
flow->me_addr, me_cl->mei_flow_ctrl_creds);
- return 0;
+ rets = 0;
+out:
+ mei_me_cl_put(me_cl);
+ return rets;
}
/**
diff --git a/drivers/misc/mei/hw-me.c b/drivers/misc/mei/hw-me.c
index 06ff0a2ec960..f8fd503dfbd6 100644
--- a/drivers/misc/mei/hw-me.c
+++ b/drivers/misc/mei/hw-me.c
@@ -242,7 +242,7 @@ static int mei_me_hw_reset(struct mei_device *dev, bool intr_enable)
if ((hcsr & H_RST) == H_RST) {
dev_warn(dev->dev, "H_RST is set = 0x%08X", hcsr);
hcsr &= ~H_RST;
- mei_me_reg_write(hw, H_CSR, hcsr);
+ mei_hcsr_set(hw, hcsr);
hcsr = mei_hcsr_read(hw);
}
@@ -335,6 +335,7 @@ static int mei_me_hw_ready_wait(struct mei_device *dev)
return -ETIME;
}
+ mei_me_hw_reset_release(dev);
dev->recvd_hw_ready = false;
return 0;
}
@@ -731,9 +732,7 @@ irqreturn_t mei_me_irq_thread_handler(int irq, void *dev_id)
/* check if we need to start the dev */
if (!mei_host_is_ready(dev)) {
if (mei_hw_is_ready(dev)) {
- mei_me_hw_reset_release(dev);
dev_dbg(dev->dev, "we need to start the dev.\n");
-
dev->recvd_hw_ready = true;
wake_up(&dev->wait_hw_ready);
} else {
diff --git a/drivers/misc/mei/main.c b/drivers/misc/mei/main.c
index ae56ba6ca0e3..3c019c0e60eb 100644
--- a/drivers/misc/mei/main.c
+++ b/drivers/misc/mei/main.c
@@ -303,7 +303,7 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
size_t length, loff_t *offset)
{
struct mei_cl *cl = file->private_data;
- struct mei_me_client *me_cl;
+ struct mei_me_client *me_cl = NULL;
struct mei_cl_cb *write_cb = NULL;
struct mei_device *dev;
unsigned long timeout = 0;
@@ -399,12 +399,14 @@ static ssize_t mei_write(struct file *file, const char __user *ubuf,
"amthif write failed with status = %d\n", rets);
goto out;
}
+ mei_me_cl_put(me_cl);
mutex_unlock(&dev->device_lock);
return length;
}
rets = mei_cl_write(cl, write_cb, false);
out:
+ mei_me_cl_put(me_cl);
mutex_unlock(&dev->device_lock);
if (rets < 0)
mei_io_cb_free(write_cb);
@@ -433,24 +435,19 @@ static int mei_ioctl_connect_client(struct file *file,
cl = file->private_data;
dev = cl->dev;
- if (dev->dev_state != MEI_DEV_ENABLED) {
- rets = -ENODEV;
- goto end;
- }
+ if (dev->dev_state != MEI_DEV_ENABLED)
+ return -ENODEV;
if (cl->state != MEI_FILE_INITIALIZING &&
- cl->state != MEI_FILE_DISCONNECTED) {
- rets = -EBUSY;
- goto end;
- }
+ cl->state != MEI_FILE_DISCONNECTED)
+ return -EBUSY;
/* find ME client we're trying to connect to */
me_cl = mei_me_cl_by_uuid(dev, &data->in_client_uuid);
if (!me_cl || me_cl->props.fixed_address) {
dev_dbg(dev->dev, "Cannot connect to FW Client UUID = %pUl\n",
&data->in_client_uuid);
- rets = -ENOTTY;
- goto end;
+ return -ENOTTY;
}
cl->me_client_id = me_cl->client_id;
@@ -487,17 +484,16 @@ static int mei_ioctl_connect_client(struct file *file,
goto end;
}
-
/* prepare the output buffer */
client = &data->out_client_properties;
client->max_msg_length = me_cl->props.max_msg_length;
client->protocol_version = me_cl->props.protocol_version;
dev_dbg(dev->dev, "Can connect?\n");
-
rets = mei_cl_connect(cl, file);
end:
+ mei_me_cl_put(me_cl);
return rets;
}
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 3dad74a8d496..6c6ce9381535 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -172,12 +172,14 @@ struct mei_fw_status {
* struct mei_me_client - representation of me (fw) client
*
* @list: link in me client list
+ * @refcnt: struct reference count
* @props: client properties
* @client_id: me client id
* @mei_flow_ctrl_creds: flow control credits
*/
struct mei_me_client {
struct list_head list;
+ struct kref refcnt;
struct mei_client_properties props;
u8 client_id;
u8 mei_flow_ctrl_creds;
@@ -345,9 +347,9 @@ struct mei_cl_device *mei_cl_add_device(struct mei_device *dev,
struct mei_cl_ops *ops);
void mei_cl_remove_device(struct mei_cl_device *device);
-int __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
-int __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_async_send(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_send(struct mei_cl *cl, u8 *buf, size_t length);
+ssize_t __mei_cl_recv(struct mei_cl *cl, u8 *buf, size_t length);
void mei_cl_bus_rx_event(struct mei_cl *cl);
void mei_cl_bus_remove_devices(struct mei_device *dev);
int mei_cl_bus_init(void);
diff --git a/drivers/misc/mei/nfc.c b/drivers/misc/mei/nfc.c
index 60ca9240368e..bb61a119b8bb 100644
--- a/drivers/misc/mei/nfc.c
+++ b/drivers/misc/mei/nfc.c
@@ -521,6 +521,7 @@ int mei_nfc_host_init(struct mei_device *dev)
cl_info->me_client_id = me_cl->client_id;
cl_info->cl_uuid = me_cl->props.protocol_name;
+ mei_me_cl_put(me_cl);
ret = mei_cl_link(cl_info, MEI_HOST_CLIENT_ID_ANY);
if (ret)
@@ -539,6 +540,7 @@ int mei_nfc_host_init(struct mei_device *dev)
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
+ mei_me_cl_put(me_cl);
ret = mei_cl_link(cl, MEI_HOST_CLIENT_ID_ANY);
if (ret)
diff --git a/drivers/misc/mei/wd.c b/drivers/misc/mei/wd.c
index b1d892cea94d..475f1dea45bf 100644
--- a/drivers/misc/mei/wd.c
+++ b/drivers/misc/mei/wd.c
@@ -76,6 +76,7 @@ int mei_wd_host_init(struct mei_device *dev)
cl->me_client_id = me_cl->client_id;
cl->cl_uuid = me_cl->props.protocol_name;
+ mei_me_cl_put(me_cl);
ret = mei_cl_link(cl, MEI_WD_HOST_CLIENT_ID);
diff --git a/drivers/misc/ti-st/st_core.c b/drivers/misc/ti-st/st_core.c
index 54be83d3efdd..c8c6a363069c 100644
--- a/drivers/misc/ti-st/st_core.c
+++ b/drivers/misc/ti-st/st_core.c
@@ -343,12 +343,26 @@ void st_int_recv(void *disc_data,
/* Unknow packet? */
default:
type = *ptr;
- if (st_gdata->list[type] == NULL) {
- pr_err("chip/interface misbehavior dropping"
- " frame starting with 0x%02x", type);
- goto done;
+ /* Default case means non-HCILL packets,
+ * possibilities are packets for:
+ * (a) valid protocol - Supported Protocols within
+ * the ST_MAX_CHANNELS.
+ * (b) registered protocol - Checked by
+ * "st_gdata->list[type] == NULL)" are supported
+ * protocols only.
+ * Rules out any invalid protocol and
+ * unregistered protocols with channel ID < 16.
+ */
+
+ if ((type >= ST_MAX_CHANNELS) ||
+ (st_gdata->list[type] == NULL)) {
+ pr_err("chip/interface misbehavior: "
+ "dropping frame starting "
+ "with 0x%02x\n", type);
+ goto done;
}
+
st_gdata->rx_skb = alloc_skb(
st_gdata->list[type]->max_frame_size,
GFP_ATOMIC);
@@ -893,5 +907,3 @@ void st_core_exit(struct st_data_s *st_gdata)
kfree(st_gdata);
}
}
-
-
diff --git a/drivers/misc/ti-st/st_kim.c b/drivers/misc/ti-st/st_kim.c
index e4b7ee4f57b8..18e7a03985d4 100644
--- a/drivers/misc/ti-st/st_kim.c
+++ b/drivers/misc/ti-st/st_kim.c
@@ -36,7 +36,8 @@
#include <linux/skbuff.h>
#include <linux/ti_wilink_st.h>
#include <linux/module.h>
-
+#include <linux/of.h>
+#include <linux/of_device.h>
#define MAX_ST_DEVICES 3 /* Imagine 1 on each UART for now */
static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
@@ -44,6 +45,9 @@ static struct platform_device *st_kim_devices[MAX_ST_DEVICES];
/**********************************************************************/
/* internal functions */
+struct ti_st_plat_data *dt_pdata;
+static struct ti_st_plat_data *get_platform_data(struct device *dev);
+
/**
* st_get_plat_device -
* function which returns the reference to the platform device
@@ -215,6 +219,7 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
{
unsigned short version = 0, chip = 0, min_ver = 0, maj_ver = 0;
const char read_ver_cmd[] = { 0x01, 0x01, 0x10, 0x00 };
+ long timeout;
pr_debug("%s", __func__);
@@ -224,10 +229,11 @@ static long read_local_version(struct kim_data_s *kim_gdata, char *bts_scr_name)
return -EIO;
}
- if (!wait_for_completion_interruptible_timeout(
- &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME))) {
- pr_err(" waiting for ver info- timed out ");
- return -ETIMEDOUT;
+ timeout = wait_for_completion_interruptible_timeout(
+ &kim_gdata->kim_rcvd, msecs_to_jiffies(CMD_RESP_TIME));
+ if (timeout <= 0) {
+ pr_err(" waiting for ver info- timed out or received signal");
+ return timeout ? -ERESTARTSYS : -ETIMEDOUT;
}
reinit_completion(&kim_gdata->kim_rcvd);
/* the positions 12 & 13 in the response buffer provide with the
@@ -391,13 +397,14 @@ static long download_firmware(struct kim_data_s *kim_gdata)
break;
case ACTION_WAIT_EVENT: /* wait */
pr_debug("W");
- if (!wait_for_completion_interruptible_timeout(
+ err = wait_for_completion_interruptible_timeout(
&kim_gdata->kim_rcvd,
- msecs_to_jiffies(CMD_RESP_TIME))) {
- pr_err("response timeout during fw download ");
+ msecs_to_jiffies(CMD_RESP_TIME));
+ if (err <= 0) {
+ pr_err("response timeout/signaled during fw download ");
/* timed out */
release_firmware(kim_gdata->fw_entry);
- return -ETIMEDOUT;
+ return err ? -ERESTARTSYS : -ETIMEDOUT;
}
reinit_completion(&kim_gdata->kim_rcvd);
break;
@@ -462,7 +469,12 @@ long st_kim_start(void *kim_data)
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
pr_info(" %s", __func__);
- pdata = kim_gdata->kim_pdev->dev.platform_data;
+ if (kim_gdata->kim_pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else {
+ pdata = kim_gdata->kim_pdev->dev.platform_data;
+ }
do {
/* platform specific enabling code here */
@@ -522,12 +534,18 @@ long st_kim_stop(void *kim_data)
{
long err = 0;
struct kim_data_s *kim_gdata = (struct kim_data_s *)kim_data;
- struct ti_st_plat_data *pdata =
- kim_gdata->kim_pdev->dev.platform_data;
+ struct ti_st_plat_data *pdata;
struct tty_struct *tty = kim_gdata->core_data->tty;
reinit_completion(&kim_gdata->ldisc_installed);
+ if (kim_gdata->kim_pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else
+ pdata = kim_gdata->kim_pdev->dev.platform_data;
+
+
if (tty) { /* can be called before ldisc is installed */
/* Flush any pending characters in the driver and discipline. */
tty_ldisc_flush(tty);
@@ -620,7 +638,7 @@ static ssize_t show_baud_rate(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct kim_data_s *kim_data = dev_get_drvdata(dev);
- return sprintf(buf, "%ld\n", kim_data->baud_rate);
+ return sprintf(buf, "%d\n", kim_data->baud_rate);
}
static ssize_t show_flow_cntrl(struct device *dev,
@@ -676,12 +694,16 @@ void st_kim_ref(struct st_data_s **core_data, int id)
struct kim_data_s *kim_gdata;
/* get kim_gdata reference from platform device */
pdev = st_get_plat_device(id);
- if (!pdev) {
- *core_data = NULL;
- return;
- }
+ if (!pdev)
+ goto err;
kim_gdata = platform_get_drvdata(pdev);
+ if (!kim_gdata)
+ goto err;
+
*core_data = kim_gdata->core_data;
+ return;
+err:
+ *core_data = NULL;
}
static int kim_version_open(struct inode *i, struct file *f)
@@ -715,13 +737,53 @@ static const struct file_operations list_debugfs_fops = {
* board-*.c file
*/
+static const struct of_device_id kim_of_match[] = {
+{
+ .compatible = "kim",
+ },
+ {}
+};
+MODULE_DEVICE_TABLE(of, kim_of_match);
+
+static struct ti_st_plat_data *get_platform_data(struct device *dev)
+{
+ struct device_node *np = dev->of_node;
+ const u32 *dt_property;
+ int len;
+
+ dt_pdata = kzalloc(sizeof(*dt_pdata), GFP_KERNEL);
+
+ if (!dt_pdata)
+ pr_err("Can't allocate device_tree platform data\n");
+
+ dt_property = of_get_property(np, "dev_name", &len);
+ if (dt_property)
+ memcpy(&dt_pdata->dev_name, dt_property, len);
+ of_property_read_u32(np, "nshutdown_gpio",
+ &dt_pdata->nshutdown_gpio);
+ of_property_read_u32(np, "flow_cntrl", &dt_pdata->flow_cntrl);
+ of_property_read_u32(np, "baud_rate", &dt_pdata->baud_rate);
+
+ return dt_pdata;
+}
+
static struct dentry *kim_debugfs_dir;
static int kim_probe(struct platform_device *pdev)
{
struct kim_data_s *kim_gdata;
- struct ti_st_plat_data *pdata = pdev->dev.platform_data;
+ struct ti_st_plat_data *pdata;
int err;
+ if (pdev->dev.of_node)
+ pdata = get_platform_data(&pdev->dev);
+ else
+ pdata = pdev->dev.platform_data;
+
+ if (pdata == NULL) {
+ dev_err(&pdev->dev, "Platform Data is missing\n");
+ return -ENXIO;
+ }
+
if ((pdev->id != -1) && (pdev->id < MAX_ST_DEVICES)) {
/* multiple devices could exist */
st_kim_devices[pdev->id] = pdev;
@@ -750,14 +812,14 @@ static int kim_probe(struct platform_device *pdev)
kim_gdata->nshutdown = pdata->nshutdown_gpio;
err = gpio_request(kim_gdata->nshutdown, "kim");
if (unlikely(err)) {
- pr_err(" gpio %ld request failed ", kim_gdata->nshutdown);
+ pr_err(" gpio %d request failed ", kim_gdata->nshutdown);
return err;
}
/* Configure nShutdown GPIO as output=0 */
err = gpio_direction_output(kim_gdata->nshutdown, 0);
if (unlikely(err)) {
- pr_err(" unable to configure gpio %ld", kim_gdata->nshutdown);
+ pr_err(" unable to configure gpio %d", kim_gdata->nshutdown);
return err;
}
/* get reference of pdev for request_firmware
@@ -781,8 +843,7 @@ static int kim_probe(struct platform_device *pdev)
kim_debugfs_dir = debugfs_create_dir("ti-st", NULL);
if (!kim_debugfs_dir) {
pr_err(" debugfs entries creation failed ");
- err = -EIO;
- goto err_debugfs_dir;
+ return 0;
}
debugfs_create_file("version", S_IRUGO, kim_debugfs_dir,
@@ -791,9 +852,6 @@ static int kim_probe(struct platform_device *pdev)
kim_gdata, &list_debugfs_fops);
return 0;
-err_debugfs_dir:
- sysfs_remove_group(&pdev->dev.kobj, &uim_attr_grp);
-
err_sysfs_group:
st_core_exit(kim_gdata->core_data);
@@ -806,9 +864,16 @@ err_core_init:
static int kim_remove(struct platform_device *pdev)
{
/* free the GPIOs requested */
- struct ti_st_plat_data *pdata = pdev->dev.platform_data;
+ struct ti_st_plat_data *pdata;
struct kim_data_s *kim_gdata;
+ if (pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else {
+ pdata = pdev->dev.platform_data;
+ }
+
kim_gdata = platform_get_drvdata(pdev);
/* Free the Bluetooth/FM/GPIO
@@ -826,27 +891,44 @@ static int kim_remove(struct platform_device *pdev)
kfree(kim_gdata);
kim_gdata = NULL;
+ kfree(dt_pdata);
+ dt_pdata = NULL;
+
return 0;
}
static int kim_suspend(struct platform_device *pdev, pm_message_t state)
{
- struct ti_st_plat_data *pdata = pdev->dev.platform_data;
+ struct ti_st_plat_data *pdata;
+
+ if (pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else {
+ pdata = pdev->dev.platform_data;
+ }
if (pdata->suspend)
return pdata->suspend(pdev, state);
- return -EOPNOTSUPP;
+ return 0;
}
static int kim_resume(struct platform_device *pdev)
{
- struct ti_st_plat_data *pdata = pdev->dev.platform_data;
+ struct ti_st_plat_data *pdata;
+
+ if (pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else {
+ pdata = pdev->dev.platform_data;
+ }
if (pdata->resume)
return pdata->resume(pdev);
- return -EOPNOTSUPP;
+ return 0;
}
/**********************************************************************/
@@ -858,6 +940,8 @@ static struct platform_driver kim_platform_driver = {
.resume = kim_resume,
.driver = {
.name = "kim",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(kim_of_match),
},
};
diff --git a/drivers/misc/ti-st/st_ll.c b/drivers/misc/ti-st/st_ll.c
index 93b4d67cc4a3..518e1b7f2f95 100644
--- a/drivers/misc/ti-st/st_ll.c
+++ b/drivers/misc/ti-st/st_ll.c
@@ -26,6 +26,7 @@
#include <linux/ti_wilink_st.h>
/**********************************************************************/
+
/* internal functions */
static void send_ll_cmd(struct st_data_s *st_data,
unsigned char cmd)
@@ -53,7 +54,13 @@ static void ll_device_want_to_sleep(struct st_data_s *st_data)
/* communicate to platform about chip asleep */
kim_data = st_data->kim_data;
- pdata = kim_data->kim_pdev->dev.platform_data;
+ if (kim_data->kim_pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else {
+ pdata = kim_data->kim_pdev->dev.platform_data;
+ }
+
if (pdata->chip_asleep)
pdata->chip_asleep(NULL);
}
@@ -86,7 +93,13 @@ static void ll_device_want_to_wakeup(struct st_data_s *st_data)
/* communicate to platform about chip wakeup */
kim_data = st_data->kim_data;
- pdata = kim_data->kim_pdev->dev.platform_data;
+ if (kim_data->kim_pdev->dev.of_node) {
+ pr_debug("use device tree data");
+ pdata = dt_pdata;
+ } else {
+ pdata = kim_data->kim_pdev->dev.platform_data;
+ }
+
if (pdata->chip_awake)
pdata->chip_awake(NULL);
}
diff --git a/drivers/misc/vmw_vmci/vmci_driver.c b/drivers/misc/vmw_vmci/vmci_driver.c
index 3dee7ae123e7..032d35cf93ca 100644
--- a/drivers/misc/vmw_vmci/vmci_driver.c
+++ b/drivers/misc/vmw_vmci/vmci_driver.c
@@ -113,5 +113,5 @@ module_exit(vmci_drv_exit);
MODULE_AUTHOR("VMware, Inc.");
MODULE_DESCRIPTION("VMware Virtual Machine Communication Interface.");
-MODULE_VERSION("1.1.0.0-k");
+MODULE_VERSION("1.1.1.0-k");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/misc/vmw_vmci/vmci_host.c b/drivers/misc/vmw_vmci/vmci_host.c
index 1723a6e4f2e8..66fc9921fc85 100644
--- a/drivers/misc/vmw_vmci/vmci_host.c
+++ b/drivers/misc/vmw_vmci/vmci_host.c
@@ -218,13 +218,12 @@ static int drv_cp_harray_to_user(void __user *user_buf_uva,
}
/*
- * Sets up a given context for notify to work. Calls drv_map_bool_ptr()
- * which maps the notify boolean in user VA in kernel space.
+ * Sets up a given context for notify to work. Maps the notify
+ * boolean in user VA into kernel space.
*/
static int vmci_host_setup_notify(struct vmci_ctx *context,
unsigned long uva)
{
- struct page *page;
int retval;
if (context->notify_page) {
@@ -243,14 +242,16 @@ static int vmci_host_setup_notify(struct vmci_ctx *context,
/*
* Lock physical page backing a given user VA.
*/
- retval = get_user_pages_fast(PAGE_ALIGN(uva), 1, 1, &page);
- if (retval != 1)
+ retval = get_user_pages_fast(uva, 1, 1, &context->notify_page);
+ if (retval != 1) {
+ context->notify_page = NULL;
return VMCI_ERROR_GENERIC;
+ }
/*
* Map the locked page and set up notify pointer.
*/
- context->notify = kmap(page) + (uva & (PAGE_SIZE - 1));
+ context->notify = kmap(context->notify_page) + (uva & (PAGE_SIZE - 1));
vmci_ctx_check_signal_notify(context);
return VMCI_SUCCESS;
diff --git a/drivers/misc/vmw_vmci/vmci_queue_pair.c b/drivers/misc/vmw_vmci/vmci_queue_pair.c
index 7aaaf51e1596..35f19a683822 100644
--- a/drivers/misc/vmw_vmci/vmci_queue_pair.c
+++ b/drivers/misc/vmw_vmci/vmci_queue_pair.c
@@ -370,12 +370,12 @@ static int __qp_memcpy_to_queue(struct vmci_queue *queue,
to_copy = size - bytes_copied;
if (is_iovec) {
- struct iovec *iov = (struct iovec *)src;
+ struct msghdr *msg = (struct msghdr *)src;
int err;
/* The iovec will track bytes_copied internally. */
- err = memcpy_fromiovec((u8 *)va + page_offset,
- iov, to_copy);
+ err = memcpy_from_msg((u8 *)va + page_offset,
+ msg, to_copy);
if (err != 0) {
if (kernel_if->host)
kunmap(kernel_if->u.h.page[page_index]);
@@ -580,7 +580,7 @@ static int qp_memcpy_from_queue(void *dest,
*/
static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,
u64 queue_offset,
- const void *src,
+ const void *msg,
size_t src_offset, size_t size)
{
@@ -588,7 +588,7 @@ static int qp_memcpy_to_queue_iov(struct vmci_queue *queue,
* We ignore src_offset because src is really a struct iovec * and will
* maintain offset internally.
*/
- return __qp_memcpy_to_queue(queue, queue_offset, src, size, true);
+ return __qp_memcpy_to_queue(queue, queue_offset, msg, size, true);
}
/*
@@ -3223,13 +3223,13 @@ EXPORT_SYMBOL_GPL(vmci_qpair_peek);
* of bytes enqueued or < 0 on error.
*/
ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
- void *iov,
+ struct msghdr *msg,
size_t iov_size,
int buf_type)
{
ssize_t result;
- if (!qpair || !iov)
+ if (!qpair)
return VMCI_ERROR_INVALID_ARGS;
qp_lock(qpair);
@@ -3238,7 +3238,7 @@ ssize_t vmci_qpair_enquev(struct vmci_qp *qpair,
result = qp_enqueue_locked(qpair->produce_q,
qpair->consume_q,
qpair->produce_q_size,
- iov, iov_size,
+ msg, iov_size,
qp_memcpy_to_queue_iov);
if (result == VMCI_ERROR_QUEUEPAIR_NOT_READY &&
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 4409d79ed650..c69afb5e264e 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -2147,7 +2147,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
*/
snprintf(md->disk->disk_name, sizeof(md->disk->disk_name),
- "mmcblk%d%s", md->name_idx, subname ? subname : "");
+ "mmcblk%u%s", md->name_idx, subname ? subname : "");
if (mmc_card_mmc(card))
blk_queue_logical_block_size(md->queue.queue,
@@ -2193,7 +2193,6 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
{
sector_t size;
- struct mmc_blk_data *md;
if (!mmc_card_sd(card) && mmc_card_blockaddr(card)) {
/*
@@ -2209,9 +2208,8 @@ static struct mmc_blk_data *mmc_blk_alloc(struct mmc_card *card)
size = card->csd.capacity << (card->csd.read_blkbits - 9);
}
- md = mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
+ return mmc_blk_alloc_req(card, &card->dev, size, false, NULL,
MMC_BLK_DATA_AREA_MAIN);
- return md;
}
static int mmc_blk_alloc_part(struct mmc_card *card,
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 0a7430f94d29..7dac4695163b 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -2342,20 +2342,16 @@ static int mmc_test_hw_reset(struct mmc_test_card *test)
struct mmc_host *host = card->host;
int err;
- err = mmc_hw_reset_check(host);
+ if (!mmc_card_mmc(card) || !mmc_can_reset(card))
+ return RESULT_UNSUP_CARD;
+
+ err = mmc_hw_reset(host);
if (!err)
return RESULT_OK;
+ else if (err == -EOPNOTSUPP)
+ return RESULT_UNSUP_HOST;
- if (err == -ENOSYS)
- return RESULT_FAIL;
-
- if (err != -EOPNOTSUPP)
- return err;
-
- if (!mmc_can_reset(card))
- return RESULT_UNSUP_CARD;
-
- return RESULT_UNSUP_HOST;
+ return RESULT_FAIL;
}
static const struct mmc_test_case mmc_test_cases[] = {
diff --git a/drivers/mmc/core/Makefile b/drivers/mmc/core/Makefile
index 38ed210ce2f3..2c25138f28b7 100644
--- a/drivers/mmc/core/Makefile
+++ b/drivers/mmc/core/Makefile
@@ -8,5 +8,5 @@ mmc_core-y := core.o bus.o host.o \
sdio.o sdio_ops.o sdio_bus.o \
sdio_cis.o sdio_io.o sdio_irq.o \
quirks.o slot-gpio.o
-
+mmc_core-$(CONFIG_OF) += pwrseq.o pwrseq_simple.o pwrseq_emmc.o
mmc_core-$(CONFIG_DEBUG_FS) += debugfs.o
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 86d271148528..c5ef10065a4a 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -16,6 +16,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/stat.h>
+#include <linux/of.h>
#include <linux/pm_runtime.h>
#include <linux/mmc/card.h>
@@ -321,6 +322,8 @@ int mmc_add_card(struct mmc_card *card)
#endif
mmc_init_context_info(card->host);
+ card->dev.of_node = mmc_of_find_child_device(card->host, 0);
+
ret = device_add(&card->dev);
if (ret)
return ret;
@@ -349,6 +352,7 @@ void mmc_remove_card(struct mmc_card *card)
mmc_hostname(card->host), card->rca);
}
device_del(&card->dev);
+ of_node_put(card->dev.of_node);
}
put_device(&card->dev);
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 9584bffa8b22..23f10f72e5f3 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -40,6 +40,7 @@
#include "bus.h"
#include "host.h"
#include "sdio_bus.h"
+#include "pwrseq.h"
#include "mmc_ops.h"
#include "sd_ops.h"
@@ -185,13 +186,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
EXPORT_SYMBOL(mmc_request_done);
-static void
-mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
+static int mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
{
#ifdef CONFIG_MMC_DEBUG
unsigned int i, sz;
struct scatterlist *sg;
#endif
+ if (mmc_card_removed(host->card))
+ return -ENOMEDIUM;
if (mrq->sbc) {
pr_debug("<%s: starting CMD%u arg %08x flags %08x>\n",
@@ -251,6 +253,8 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mmc_host_clk_hold(host);
led_trigger_event(host->led, LED_FULL);
host->ops->request(host, mrq);
+
+ return 0;
}
/**
@@ -271,7 +275,7 @@ void mmc_start_bkops(struct mmc_card *card, bool from_exception)
BUG_ON(!card);
- if (!card->ext_csd.bkops_en || mmc_card_doing_bkops(card))
+ if (!card->ext_csd.man_bkops_en || mmc_card_doing_bkops(card))
return;
err = mmc_read_bkops_status(card);
@@ -345,29 +349,34 @@ static void mmc_wait_done(struct mmc_request *mrq)
*/
static int __mmc_start_data_req(struct mmc_host *host, struct mmc_request *mrq)
{
+ int err;
+
mrq->done = mmc_wait_data_done;
mrq->host = host;
- if (mmc_card_removed(host->card)) {
- mrq->cmd->error = -ENOMEDIUM;
+
+ err = mmc_start_request(host, mrq);
+ if (err) {
+ mrq->cmd->error = err;
mmc_wait_data_done(mrq);
- return -ENOMEDIUM;
}
- mmc_start_request(host, mrq);
- return 0;
+ return err;
}
static int __mmc_start_req(struct mmc_host *host, struct mmc_request *mrq)
{
+ int err;
+
init_completion(&mrq->completion);
mrq->done = mmc_wait_done;
- if (mmc_card_removed(host->card)) {
- mrq->cmd->error = -ENOMEDIUM;
+
+ err = mmc_start_request(host, mrq);
+ if (err) {
+ mrq->cmd->error = err;
complete(&mrq->completion);
- return -ENOMEDIUM;
}
- mmc_start_request(host, mrq);
- return 0;
+
+ return err;
}
/*
@@ -1077,6 +1086,30 @@ void mmc_set_ungated(struct mmc_host *host)
}
#endif
+int mmc_execute_tuning(struct mmc_card *card)
+{
+ struct mmc_host *host = card->host;
+ u32 opcode;
+ int err;
+
+ if (!host->ops->execute_tuning)
+ return 0;
+
+ if (mmc_card_mmc(card))
+ opcode = MMC_SEND_TUNING_BLOCK_HS200;
+ else
+ opcode = MMC_SEND_TUNING_BLOCK;
+
+ mmc_host_clk_hold(host);
+ err = host->ops->execute_tuning(host, opcode);
+ mmc_host_clk_release(host);
+
+ if (err)
+ pr_err("%s: tuning execution failed\n", mmc_hostname(host));
+
+ return err;
+}
+
/*
* Change the bus mode (open drain/push-pull) of a host.
*/
@@ -1232,6 +1265,34 @@ EXPORT_SYMBOL(mmc_of_parse_voltage);
#endif /* CONFIG_OF */
+static int mmc_of_get_func_num(struct device_node *node)
+{
+ u32 reg;
+ int ret;
+
+ ret = of_property_read_u32(node, "reg", &reg);
+ if (ret < 0)
+ return ret;
+
+ return reg;
+}
+
+struct device_node *mmc_of_find_child_device(struct mmc_host *host,
+ unsigned func_num)
+{
+ struct device_node *node;
+
+ if (!host->parent || !host->parent->of_node)
+ return NULL;
+
+ for_each_child_of_node(host->parent->of_node, node) {
+ if (mmc_of_get_func_num(node) == func_num)
+ return node;
+ }
+
+ return NULL;
+}
+
#ifdef CONFIG_REGULATOR
/**
@@ -1555,6 +1616,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
mmc_host_clk_hold(host);
+ mmc_pwrseq_pre_power_on(host);
+
host->ios.vdd = fls(ocr) - 1;
host->ios.power_mode = MMC_POWER_UP;
/* Set initial state and call mmc_set_ios */
@@ -1574,6 +1637,8 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
*/
mmc_delay(10);
+ mmc_pwrseq_post_power_on(host);
+
host->ios.clock = host->f_init;
host->ios.power_mode = MMC_POWER_ON;
@@ -1595,6 +1660,8 @@ void mmc_power_off(struct mmc_host *host)
mmc_host_clk_hold(host);
+ mmc_pwrseq_power_off(host);
+
host->ios.clock = 0;
host->ios.vdd = 0;
@@ -2245,67 +2312,28 @@ static void mmc_hw_reset_for_init(struct mmc_host *host)
mmc_host_clk_release(host);
}
-int mmc_can_reset(struct mmc_card *card)
-{
- u8 rst_n_function;
-
- if (!mmc_card_mmc(card))
- return 0;
- rst_n_function = card->ext_csd.rst_n_function;
- if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
- return 0;
- return 1;
-}
-EXPORT_SYMBOL(mmc_can_reset);
-
-static int mmc_do_hw_reset(struct mmc_host *host, int check)
+int mmc_hw_reset(struct mmc_host *host)
{
- struct mmc_card *card = host->card;
-
- if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
- return -EOPNOTSUPP;
+ int ret;
- if (!card)
+ if (!host->card)
return -EINVAL;
- if (!mmc_can_reset(card))
+ mmc_bus_get(host);
+ if (!host->bus_ops || host->bus_dead || !host->bus_ops->reset) {
+ mmc_bus_put(host);
return -EOPNOTSUPP;
-
- mmc_host_clk_hold(host);
- mmc_set_clock(host, host->f_init);
-
- host->ops->hw_reset(host);
-
- /* If the reset has happened, then a status command will fail */
- if (check) {
- u32 status;
-
- if (!mmc_send_status(card, &status)) {
- mmc_host_clk_release(host);
- return -ENOSYS;
- }
}
- /* Set initial state and call mmc_set_ios */
- mmc_set_initial_state(host);
+ ret = host->bus_ops->reset(host);
+ mmc_bus_put(host);
- mmc_host_clk_release(host);
+ pr_warn("%s: tried to reset card\n", mmc_hostname(host));
- return host->bus_ops->power_restore(host);
-}
-
-int mmc_hw_reset(struct mmc_host *host)
-{
- return mmc_do_hw_reset(host, 0);
+ return ret;
}
EXPORT_SYMBOL(mmc_hw_reset);
-int mmc_hw_reset_check(struct mmc_host *host)
-{
- return mmc_do_hw_reset(host, 1);
-}
-EXPORT_SYMBOL(mmc_hw_reset_check);
-
static int mmc_rescan_try_freq(struct mmc_host *host, unsigned freq)
{
host->f_init = freq;
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index d76597c65e3a..cfba3c05aab1 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -27,11 +27,15 @@ struct mmc_bus_ops {
int (*power_restore)(struct mmc_host *);
int (*alive)(struct mmc_host *);
int (*shutdown)(struct mmc_host *);
+ int (*reset)(struct mmc_host *);
};
void mmc_attach_bus(struct mmc_host *host, const struct mmc_bus_ops *ops);
void mmc_detach_bus(struct mmc_host *host);
+struct device_node *mmc_of_find_child_device(struct mmc_host *host,
+ unsigned func_num);
+
void mmc_init_erase(struct mmc_card *card);
void mmc_set_chip_select(struct mmc_host *host, int mode);
@@ -82,5 +86,8 @@ void mmc_add_card_debugfs(struct mmc_card *card);
void mmc_remove_card_debugfs(struct mmc_card *card);
void mmc_init_context_info(struct mmc_host *host);
+
+int mmc_execute_tuning(struct mmc_card *card);
+
#endif
diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index 270d58a4c43d..8be0df758e68 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -29,13 +29,20 @@
#include "core.h"
#include "host.h"
+#include "slot-gpio.h"
+#include "pwrseq.h"
#define cls_dev_to_mmc_host(d) container_of(d, struct mmc_host, class_dev)
+static DEFINE_IDR(mmc_host_idr);
+static DEFINE_SPINLOCK(mmc_host_lock);
+
static void mmc_host_classdev_release(struct device *dev)
{
struct mmc_host *host = cls_dev_to_mmc_host(dev);
- mutex_destroy(&host->slot.lock);
+ spin_lock(&mmc_host_lock);
+ idr_remove(&mmc_host_idr, host->index);
+ spin_unlock(&mmc_host_lock);
kfree(host);
}
@@ -54,9 +61,6 @@ void mmc_unregister_host_class(void)
class_unregister(&mmc_host_class);
}
-static DEFINE_IDR(mmc_host_idr);
-static DEFINE_SPINLOCK(mmc_host_lock);
-
#ifdef CONFIG_MMC_CLKGATE
static ssize_t clkgate_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -367,16 +371,10 @@ int mmc_of_parse(struct mmc_host *host)
ret = mmc_gpiod_request_cd(host, "cd", 0, true,
0, &cd_gpio_invert);
- if (ret) {
- if (ret == -EPROBE_DEFER)
- return ret;
- if (ret != -ENOENT) {
- dev_err(host->parent,
- "Failed to request CD GPIO: %d\n",
- ret);
- }
- } else
+ if (!ret)
dev_info(host->parent, "Got CD GPIO\n");
+ else if (ret != -ENOENT)
+ return ret;
/*
* There are two ways to flag that the CD line is inverted:
@@ -397,16 +395,10 @@ int mmc_of_parse(struct mmc_host *host)
ro_cap_invert = of_property_read_bool(np, "wp-inverted");
ret = mmc_gpiod_request_ro(host, "wp", 0, false, 0, &ro_gpio_invert);
- if (ret) {
- if (ret == -EPROBE_DEFER)
- goto out;
- if (ret != -ENOENT) {
- dev_err(host->parent,
- "Failed to request WP GPIO: %d\n",
- ret);
- }
- } else
+ if (!ret)
dev_info(host->parent, "Got WP GPIO\n");
+ else if (ret != -ENOENT)
+ return ret;
/* See the comment on CD inversion above */
if (ro_cap_invert ^ ro_gpio_invert)
@@ -457,11 +449,7 @@ int mmc_of_parse(struct mmc_host *host)
host->dsr_req = 0;
}
- return 0;
-
-out:
- mmc_gpio_free_cd(host);
- return ret;
+ return mmc_pwrseq_alloc(host);
}
EXPORT_SYMBOL(mmc_of_parse);
@@ -491,8 +479,10 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->index = err;
spin_unlock(&mmc_host_lock);
idr_preload_end();
- if (err < 0)
- goto free;
+ if (err < 0) {
+ kfree(host);
+ return NULL;
+ }
dev_set_name(&host->class_dev, "mmc%d", host->index);
@@ -501,10 +491,12 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->class_dev.class = &mmc_host_class;
device_initialize(&host->class_dev);
- mmc_host_clk_init(host);
+ if (mmc_gpio_alloc(host)) {
+ put_device(&host->class_dev);
+ return NULL;
+ }
- mutex_init(&host->slot.lock);
- host->slot.cd_irq = -EINVAL;
+ mmc_host_clk_init(host);
spin_lock_init(&host->lock);
init_waitqueue_head(&host->wq);
@@ -525,10 +517,6 @@ struct mmc_host *mmc_alloc_host(int extra, struct device *dev)
host->max_blk_count = PAGE_CACHE_SIZE / 512;
return host;
-
-free:
- kfree(host);
- return NULL;
}
EXPORT_SYMBOL(mmc_alloc_host);
@@ -601,10 +589,7 @@ EXPORT_SYMBOL(mmc_remove_host);
*/
void mmc_free_host(struct mmc_host *host)
{
- spin_lock(&mmc_host_lock);
- idr_remove(&mmc_host_idr, host->index);
- spin_unlock(&mmc_host_lock);
-
+ mmc_pwrseq_free(host);
put_device(&host->class_dev);
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 7466ce098e60..1d41e8541f38 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -483,11 +483,13 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
/* check whether the eMMC card supports BKOPS */
if (ext_csd[EXT_CSD_BKOPS_SUPPORT] & 0x1) {
card->ext_csd.bkops = 1;
- card->ext_csd.bkops_en = ext_csd[EXT_CSD_BKOPS_EN];
+ card->ext_csd.man_bkops_en =
+ (ext_csd[EXT_CSD_BKOPS_EN] &
+ EXT_CSD_MANUAL_BKOPS_MASK);
card->ext_csd.raw_bkops_status =
ext_csd[EXT_CSD_BKOPS_STATUS];
- if (!card->ext_csd.bkops_en)
- pr_info("%s: BKOPS_EN bit is not set\n",
+ if (!card->ext_csd.man_bkops_en)
+ pr_info("%s: MAN_BKOPS_EN bit is not set\n",
mmc_hostname(card->host));
}
@@ -1155,38 +1157,6 @@ bus_speed:
return err;
}
-const u8 tuning_blk_pattern_4bit[MMC_TUNING_BLK_PATTERN_4BIT_SIZE] = {
- 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
- 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
- 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
- 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
- 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
- 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
- 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
- 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
-};
-EXPORT_SYMBOL(tuning_blk_pattern_4bit);
-
-const u8 tuning_blk_pattern_8bit[MMC_TUNING_BLK_PATTERN_8BIT_SIZE] = {
- 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
- 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
- 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
- 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
- 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
- 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
- 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
- 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
- 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
- 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
- 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
- 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
- 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
- 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
- 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
- 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
-};
-EXPORT_SYMBOL(tuning_blk_pattern_8bit);
-
/*
* Execute tuning sequence to seek the proper bus operating
* conditions for HS200 and HS400, which sends CMD21 to the device.
@@ -1194,7 +1164,6 @@ EXPORT_SYMBOL(tuning_blk_pattern_8bit);
static int mmc_hs200_tuning(struct mmc_card *card)
{
struct mmc_host *host = card->host;
- int err = 0;
/*
* Timing should be adjusted to the HS400 target
@@ -1205,18 +1174,7 @@ static int mmc_hs200_tuning(struct mmc_card *card)
if (host->ops->prepare_hs400_tuning)
host->ops->prepare_hs400_tuning(host, &host->ios);
- if (host->ops->execute_tuning) {
- mmc_host_clk_hold(host);
- err = host->ops->execute_tuning(host,
- MMC_SEND_TUNING_BLOCK_HS200);
- mmc_host_clk_release(host);
-
- if (err)
- pr_err("%s: tuning execution failed\n",
- mmc_hostname(host));
- }
-
- return err;
+ return mmc_execute_tuning(card);
}
/*
@@ -1297,6 +1255,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
/*
+ * Call the optional HC's init_card function to handle quirks.
+ */
+ if (host->ops->init_card)
+ host->ops->init_card(host, card);
+
+ /*
* For native busses: set card RCA and quit open drain mode.
*/
if (!mmc_host_is_spi(host)) {
@@ -1821,6 +1785,46 @@ static int mmc_power_restore(struct mmc_host *host)
return ret;
}
+int mmc_can_reset(struct mmc_card *card)
+{
+ u8 rst_n_function;
+
+ rst_n_function = card->ext_csd.rst_n_function;
+ if ((rst_n_function & EXT_CSD_RST_N_EN_MASK) != EXT_CSD_RST_N_ENABLED)
+ return 0;
+ return 1;
+}
+EXPORT_SYMBOL(mmc_can_reset);
+
+static int mmc_reset(struct mmc_host *host)
+{
+ struct mmc_card *card = host->card;
+ u32 status;
+
+ if (!(host->caps & MMC_CAP_HW_RESET) || !host->ops->hw_reset)
+ return -EOPNOTSUPP;
+
+ if (!mmc_can_reset(card))
+ return -EOPNOTSUPP;
+
+ mmc_host_clk_hold(host);
+ mmc_set_clock(host, host->f_init);
+
+ host->ops->hw_reset(host);
+
+ /* If the reset has happened, then a status command will fail */
+ if (!mmc_send_status(card, &status)) {
+ mmc_host_clk_release(host);
+ return -ENOSYS;
+ }
+
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
+ mmc_host_clk_release(host);
+
+ return mmc_power_restore(host);
+}
+
static const struct mmc_bus_ops mmc_ops = {
.remove = mmc_remove,
.detect = mmc_detect,
@@ -1831,6 +1835,7 @@ static const struct mmc_bus_ops mmc_ops = {
.power_restore = mmc_power_restore,
.alive = mmc_alive,
.shutdown = mmc_shutdown,
+ .reset = mmc_reset,
};
/*
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 3b044c5b029c..0ea042dc7443 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -23,6 +23,36 @@
#define MMC_OPS_TIMEOUT_MS (10 * 60 * 1000) /* 10 minute timeout */
+static const u8 tuning_blk_pattern_4bit[] = {
+ 0xff, 0x0f, 0xff, 0x00, 0xff, 0xcc, 0xc3, 0xcc,
+ 0xc3, 0x3c, 0xcc, 0xff, 0xfe, 0xff, 0xfe, 0xef,
+ 0xff, 0xdf, 0xff, 0xdd, 0xff, 0xfb, 0xff, 0xfb,
+ 0xbf, 0xff, 0x7f, 0xff, 0x77, 0xf7, 0xbd, 0xef,
+ 0xff, 0xf0, 0xff, 0xf0, 0x0f, 0xfc, 0xcc, 0x3c,
+ 0xcc, 0x33, 0xcc, 0xcf, 0xff, 0xef, 0xff, 0xee,
+ 0xff, 0xfd, 0xff, 0xfd, 0xdf, 0xff, 0xbf, 0xff,
+ 0xbb, 0xff, 0xf7, 0xff, 0xf7, 0x7f, 0x7b, 0xde,
+};
+
+static const u8 tuning_blk_pattern_8bit[] = {
+ 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00,
+ 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc, 0xcc,
+ 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff, 0xff,
+ 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee, 0xff,
+ 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd, 0xdd,
+ 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff, 0xbb,
+ 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff, 0xff,
+ 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee, 0xff,
+ 0xff, 0xff, 0xff, 0x00, 0xff, 0xff, 0xff, 0x00,
+ 0x00, 0xff, 0xff, 0xcc, 0xcc, 0xcc, 0x33, 0xcc,
+ 0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0xcc, 0xff,
+ 0xff, 0xff, 0xee, 0xff, 0xff, 0xff, 0xee, 0xee,
+ 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff, 0xff, 0xdd,
+ 0xdd, 0xff, 0xff, 0xff, 0xbb, 0xff, 0xff, 0xff,
+ 0xbb, 0xbb, 0xff, 0xff, 0xff, 0x77, 0xff, 0xff,
+ 0xff, 0x77, 0x77, 0xff, 0x77, 0xbb, 0xdd, 0xee,
+};
+
static inline int __mmc_send_status(struct mmc_card *card, u32 *status,
bool ignore_crc)
{
diff --git a/drivers/mmc/core/pwrseq.c b/drivers/mmc/core/pwrseq.c
new file mode 100644
index 000000000000..862356123d78
--- /dev/null
+++ b/drivers/mmc/core/pwrseq.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * MMC power sequence management
+ */
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+
+#include <linux/mmc/host.h>
+
+#include "pwrseq.h"
+
+struct mmc_pwrseq_match {
+ const char *compatible;
+ int (*alloc)(struct mmc_host *host, struct device *dev);
+};
+
+static struct mmc_pwrseq_match pwrseq_match[] = {
+ {
+ .compatible = "mmc-pwrseq-simple",
+ .alloc = mmc_pwrseq_simple_alloc,
+ }, {
+ .compatible = "mmc-pwrseq-emmc",
+ .alloc = mmc_pwrseq_emmc_alloc,
+ },
+};
+
+static struct mmc_pwrseq_match *mmc_pwrseq_find(struct device_node *np)
+{
+ struct mmc_pwrseq_match *match = ERR_PTR(-ENODEV);
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(pwrseq_match); i++) {
+ if (of_device_is_compatible(np, pwrseq_match[i].compatible)) {
+ match = &pwrseq_match[i];
+ break;
+ }
+ }
+
+ return match;
+}
+
+int mmc_pwrseq_alloc(struct mmc_host *host)
+{
+ struct platform_device *pdev;
+ struct device_node *np;
+ struct mmc_pwrseq_match *match;
+ int ret = 0;
+
+ np = of_parse_phandle(host->parent->of_node, "mmc-pwrseq", 0);
+ if (!np)
+ return 0;
+
+ pdev = of_find_device_by_node(np);
+ if (!pdev) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ match = mmc_pwrseq_find(np);
+ if (IS_ERR(match)) {
+ ret = PTR_ERR(match);
+ goto err;
+ }
+
+ ret = match->alloc(host, &pdev->dev);
+ if (!ret)
+ dev_info(host->parent, "allocated mmc-pwrseq\n");
+
+err:
+ of_node_put(np);
+ return ret;
+}
+
+void mmc_pwrseq_pre_power_on(struct mmc_host *host)
+{
+ struct mmc_pwrseq *pwrseq = host->pwrseq;
+
+ if (pwrseq && pwrseq->ops && pwrseq->ops->pre_power_on)
+ pwrseq->ops->pre_power_on(host);
+}
+
+void mmc_pwrseq_post_power_on(struct mmc_host *host)
+{
+ struct mmc_pwrseq *pwrseq = host->pwrseq;
+
+ if (pwrseq && pwrseq->ops && pwrseq->ops->post_power_on)
+ pwrseq->ops->post_power_on(host);
+}
+
+void mmc_pwrseq_power_off(struct mmc_host *host)
+{
+ struct mmc_pwrseq *pwrseq = host->pwrseq;
+
+ if (pwrseq && pwrseq->ops && pwrseq->ops->power_off)
+ pwrseq->ops->power_off(host);
+}
+
+void mmc_pwrseq_free(struct mmc_host *host)
+{
+ struct mmc_pwrseq *pwrseq = host->pwrseq;
+
+ if (pwrseq && pwrseq->ops && pwrseq->ops->free)
+ pwrseq->ops->free(host);
+}
diff --git a/drivers/mmc/core/pwrseq.h b/drivers/mmc/core/pwrseq.h
new file mode 100644
index 000000000000..aba3409e8d6e
--- /dev/null
+++ b/drivers/mmc/core/pwrseq.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _MMC_CORE_PWRSEQ_H
+#define _MMC_CORE_PWRSEQ_H
+
+struct mmc_pwrseq_ops {
+ void (*pre_power_on)(struct mmc_host *host);
+ void (*post_power_on)(struct mmc_host *host);
+ void (*power_off)(struct mmc_host *host);
+ void (*free)(struct mmc_host *host);
+};
+
+struct mmc_pwrseq {
+ struct mmc_pwrseq_ops *ops;
+};
+
+#ifdef CONFIG_OF
+
+int mmc_pwrseq_alloc(struct mmc_host *host);
+void mmc_pwrseq_pre_power_on(struct mmc_host *host);
+void mmc_pwrseq_post_power_on(struct mmc_host *host);
+void mmc_pwrseq_power_off(struct mmc_host *host);
+void mmc_pwrseq_free(struct mmc_host *host);
+
+int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev);
+int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev);
+
+#else
+
+static inline int mmc_pwrseq_alloc(struct mmc_host *host) { return 0; }
+static inline void mmc_pwrseq_pre_power_on(struct mmc_host *host) {}
+static inline void mmc_pwrseq_post_power_on(struct mmc_host *host) {}
+static inline void mmc_pwrseq_power_off(struct mmc_host *host) {}
+static inline void mmc_pwrseq_free(struct mmc_host *host) {}
+
+#endif
+
+#endif
diff --git a/drivers/mmc/core/pwrseq_emmc.c b/drivers/mmc/core/pwrseq_emmc.c
new file mode 100644
index 000000000000..a2d545904fbf
--- /dev/null
+++ b/drivers/mmc/core/pwrseq_emmc.c
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015, Samsung Electronics Co., Ltd.
+ *
+ * Author: Marek Szyprowski <m.szyprowski@samsung.com>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Simple eMMC hardware reset provider
+ */
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/reboot.h>
+
+#include <linux/mmc/host.h>
+
+#include "pwrseq.h"
+
+struct mmc_pwrseq_emmc {
+ struct mmc_pwrseq pwrseq;
+ struct notifier_block reset_nb;
+ struct gpio_desc *reset_gpio;
+};
+
+static void __mmc_pwrseq_emmc_reset(struct mmc_pwrseq_emmc *pwrseq)
+{
+ gpiod_set_value(pwrseq->reset_gpio, 1);
+ udelay(1);
+ gpiod_set_value(pwrseq->reset_gpio, 0);
+ udelay(200);
+}
+
+static void mmc_pwrseq_emmc_reset(struct mmc_host *host)
+{
+ struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
+ struct mmc_pwrseq_emmc, pwrseq);
+
+ __mmc_pwrseq_emmc_reset(pwrseq);
+}
+
+static void mmc_pwrseq_emmc_free(struct mmc_host *host)
+{
+ struct mmc_pwrseq_emmc *pwrseq = container_of(host->pwrseq,
+ struct mmc_pwrseq_emmc, pwrseq);
+
+ unregister_restart_handler(&pwrseq->reset_nb);
+ gpiod_put(pwrseq->reset_gpio);
+ kfree(pwrseq);
+ host->pwrseq = NULL;
+}
+
+static struct mmc_pwrseq_ops mmc_pwrseq_emmc_ops = {
+ .post_power_on = mmc_pwrseq_emmc_reset,
+ .free = mmc_pwrseq_emmc_free,
+};
+
+static int mmc_pwrseq_emmc_reset_nb(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ struct mmc_pwrseq_emmc *pwrseq = container_of(this,
+ struct mmc_pwrseq_emmc, reset_nb);
+
+ __mmc_pwrseq_emmc_reset(pwrseq);
+ return NOTIFY_DONE;
+}
+
+int mmc_pwrseq_emmc_alloc(struct mmc_host *host, struct device *dev)
+{
+ struct mmc_pwrseq_emmc *pwrseq;
+ int ret = 0;
+
+ pwrseq = kzalloc(sizeof(struct mmc_pwrseq_emmc), GFP_KERNEL);
+ if (!pwrseq)
+ return -ENOMEM;
+
+ pwrseq->reset_gpio = gpiod_get_index(dev, "reset", 0, GPIOD_OUT_LOW);
+ if (IS_ERR(pwrseq->reset_gpio)) {
+ ret = PTR_ERR(pwrseq->reset_gpio);
+ goto free;
+ }
+
+ /*
+ * register reset handler to ensure emmc reset also from
+ * emergency_reboot(), priority 129 schedules it just before
+ * system reboot
+ */
+ pwrseq->reset_nb.notifier_call = mmc_pwrseq_emmc_reset_nb;
+ pwrseq->reset_nb.priority = 129;
+ register_restart_handler(&pwrseq->reset_nb);
+
+ pwrseq->pwrseq.ops = &mmc_pwrseq_emmc_ops;
+ host->pwrseq = &pwrseq->pwrseq;
+
+ return 0;
+free:
+ kfree(pwrseq);
+ return ret;
+}
diff --git a/drivers/mmc/core/pwrseq_simple.c b/drivers/mmc/core/pwrseq_simple.c
new file mode 100644
index 000000000000..e9f1d8d84613
--- /dev/null
+++ b/drivers/mmc/core/pwrseq_simple.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Simple MMC power sequence management
+ */
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/of_gpio.h>
+#include <linux/gpio/consumer.h>
+
+#include <linux/mmc/host.h>
+
+#include "pwrseq.h"
+
+struct mmc_pwrseq_simple {
+ struct mmc_pwrseq pwrseq;
+ bool clk_enabled;
+ struct clk *ext_clk;
+ int nr_gpios;
+ struct gpio_desc *reset_gpios[0];
+};
+
+static void mmc_pwrseq_simple_set_gpios_value(struct mmc_pwrseq_simple *pwrseq,
+ int value)
+{
+ int i;
+
+ for (i = 0; i < pwrseq->nr_gpios; i++)
+ if (!IS_ERR(pwrseq->reset_gpios[i]))
+ gpiod_set_value_cansleep(pwrseq->reset_gpios[i], value);
+}
+
+static void mmc_pwrseq_simple_pre_power_on(struct mmc_host *host)
+{
+ struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
+ struct mmc_pwrseq_simple, pwrseq);
+
+ if (!IS_ERR(pwrseq->ext_clk) && !pwrseq->clk_enabled) {
+ clk_prepare_enable(pwrseq->ext_clk);
+ pwrseq->clk_enabled = true;
+ }
+
+ mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+}
+
+static void mmc_pwrseq_simple_post_power_on(struct mmc_host *host)
+{
+ struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
+ struct mmc_pwrseq_simple, pwrseq);
+
+ mmc_pwrseq_simple_set_gpios_value(pwrseq, 0);
+}
+
+static void mmc_pwrseq_simple_power_off(struct mmc_host *host)
+{
+ struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
+ struct mmc_pwrseq_simple, pwrseq);
+
+ mmc_pwrseq_simple_set_gpios_value(pwrseq, 1);
+
+ if (!IS_ERR(pwrseq->ext_clk) && pwrseq->clk_enabled) {
+ clk_disable_unprepare(pwrseq->ext_clk);
+ pwrseq->clk_enabled = false;
+ }
+}
+
+static void mmc_pwrseq_simple_free(struct mmc_host *host)
+{
+ struct mmc_pwrseq_simple *pwrseq = container_of(host->pwrseq,
+ struct mmc_pwrseq_simple, pwrseq);
+ int i;
+
+ for (i = 0; i < pwrseq->nr_gpios; i++)
+ if (!IS_ERR(pwrseq->reset_gpios[i]))
+ gpiod_put(pwrseq->reset_gpios[i]);
+
+ if (!IS_ERR(pwrseq->ext_clk))
+ clk_put(pwrseq->ext_clk);
+
+ kfree(pwrseq);
+ host->pwrseq = NULL;
+}
+
+static struct mmc_pwrseq_ops mmc_pwrseq_simple_ops = {
+ .pre_power_on = mmc_pwrseq_simple_pre_power_on,
+ .post_power_on = mmc_pwrseq_simple_post_power_on,
+ .power_off = mmc_pwrseq_simple_power_off,
+ .free = mmc_pwrseq_simple_free,
+};
+
+int mmc_pwrseq_simple_alloc(struct mmc_host *host, struct device *dev)
+{
+ struct mmc_pwrseq_simple *pwrseq;
+ int i, nr_gpios, ret = 0;
+
+ nr_gpios = of_gpio_named_count(dev->of_node, "reset-gpios");
+ if (nr_gpios < 0)
+ nr_gpios = 0;
+
+ pwrseq = kzalloc(sizeof(struct mmc_pwrseq_simple) + nr_gpios *
+ sizeof(struct gpio_desc *), GFP_KERNEL);
+ if (!pwrseq)
+ return -ENOMEM;
+
+ pwrseq->ext_clk = clk_get(dev, "ext_clock");
+ if (IS_ERR(pwrseq->ext_clk) &&
+ PTR_ERR(pwrseq->ext_clk) != -ENOENT) {
+ ret = PTR_ERR(pwrseq->ext_clk);
+ goto free;
+ }
+
+ for (i = 0; i < nr_gpios; i++) {
+ pwrseq->reset_gpios[i] = gpiod_get_index(dev, "reset", i,
+ GPIOD_OUT_HIGH);
+ if (IS_ERR(pwrseq->reset_gpios[i]) &&
+ PTR_ERR(pwrseq->reset_gpios[i]) != -ENOENT &&
+ PTR_ERR(pwrseq->reset_gpios[i]) != -ENOSYS) {
+ ret = PTR_ERR(pwrseq->reset_gpios[i]);
+
+ while (--i)
+ gpiod_put(pwrseq->reset_gpios[i]);
+
+ goto clk_put;
+ }
+ }
+
+ pwrseq->nr_gpios = nr_gpios;
+ pwrseq->pwrseq.ops = &mmc_pwrseq_simple_ops;
+ host->pwrseq = &pwrseq->pwrseq;
+
+ return 0;
+clk_put:
+ if (!IS_ERR(pwrseq->ext_clk))
+ clk_put(pwrseq->ext_clk);
+free:
+ kfree(pwrseq);
+ return ret;
+}
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index d90a6de7901d..ad4d43eae99d 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -660,15 +660,10 @@ static int mmc_sd_init_uhs_card(struct mmc_card *card)
* SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
* SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
*/
- if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
- (card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
- card->sd_bus_speed == UHS_SDR104_BUS_SPEED)) {
- mmc_host_clk_hold(card->host);
- err = card->host->ops->execute_tuning(card->host,
- MMC_SEND_TUNING_BLOCK);
- mmc_host_clk_release(card->host);
- }
-
+ if (!mmc_host_is_spi(card->host) &&
+ (card->sd_bus_speed == UHS_SDR50_BUS_SPEED ||
+ card->sd_bus_speed == UHS_SDR104_BUS_SPEED))
+ err = mmc_execute_tuning(card);
out:
kfree(status);
@@ -933,6 +928,12 @@ static int mmc_sd_init_card(struct mmc_host *host, u32 ocr,
}
/*
+ * Call the optional HC's init_card function to handle quirks.
+ */
+ if (host->ops->init_card)
+ host->ops->init_card(host, card);
+
+ /*
* For native busses: get card RCA and quit open drain mode.
*/
if (!mmc_host_is_spi(host)) {
@@ -1191,6 +1192,12 @@ static int mmc_sd_power_restore(struct mmc_host *host)
return ret;
}
+static int mmc_sd_reset(struct mmc_host *host)
+{
+ mmc_power_cycle(host, host->card->ocr);
+ return mmc_sd_power_restore(host);
+}
+
static const struct mmc_bus_ops mmc_sd_ops = {
.remove = mmc_sd_remove,
.detect = mmc_sd_detect,
@@ -1201,6 +1208,7 @@ static const struct mmc_bus_ops mmc_sd_ops = {
.power_restore = mmc_sd_power_restore,
.alive = mmc_sd_alive,
.shutdown = mmc_sd_suspend,
+ .reset = mmc_sd_reset,
};
/*
@@ -1271,4 +1279,3 @@ err:
return err;
}
-
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index fd0750b5a634..ce6cc47206b0 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -567,17 +567,11 @@ static int mmc_sdio_init_uhs_card(struct mmc_card *card)
* SPI mode doesn't define CMD19 and tuning is only valid for SDR50 and
* SDR104 mode SD-cards. Note that tuning is mandatory for SDR104.
*/
- if (!mmc_host_is_spi(card->host) && card->host->ops->execute_tuning &&
- ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
- (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104))) {
- mmc_host_clk_hold(card->host);
- err = card->host->ops->execute_tuning(card->host,
- MMC_SEND_TUNING_BLOCK);
- mmc_host_clk_release(card->host);
- }
-
+ if (!mmc_host_is_spi(card->host) &&
+ ((card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR50) ||
+ (card->sw_caps.sd3_bus_mode & SD_MODE_UHS_SDR104)))
+ err = mmc_execute_tuning(card);
out:
-
return err;
}
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 60885316afba..bee02e644d62 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -22,7 +22,9 @@
#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio_func.h>
+#include <linux/of.h>
+#include "core.h"
#include "sdio_cis.h"
#include "sdio_bus.h"
@@ -295,6 +297,13 @@ static void sdio_acpi_set_handle(struct sdio_func *func)
static inline void sdio_acpi_set_handle(struct sdio_func *func) {}
#endif
+static void sdio_set_of_node(struct sdio_func *func)
+{
+ struct mmc_host *host = func->card->host;
+
+ func->dev.of_node = mmc_of_find_child_device(host, func->num);
+}
+
/*
* Register a new SDIO function with the driver model.
*/
@@ -304,6 +313,7 @@ int sdio_add_func(struct sdio_func *func)
dev_set_name(&func->dev, "%s:%d", mmc_card_id(func->card), func->num);
+ sdio_set_of_node(func);
sdio_acpi_set_handle(func);
ret = device_add(&func->dev);
if (ret == 0) {
@@ -327,6 +337,7 @@ void sdio_remove_func(struct sdio_func *func)
dev_pm_domain_detach(&func->dev, false);
device_del(&func->dev);
+ of_node_put(func->dev.of_node);
put_device(&func->dev);
}
diff --git a/drivers/mmc/core/slot-gpio.c b/drivers/mmc/core/slot-gpio.c
index 69bbf2adb329..27117ba47073 100644
--- a/drivers/mmc/core/slot-gpio.c
+++ b/drivers/mmc/core/slot-gpio.c
@@ -18,11 +18,14 @@
#include <linux/module.h>
#include <linux/slab.h>
+#include "slot-gpio.h"
+
struct mmc_gpio {
struct gpio_desc *ro_gpio;
struct gpio_desc *cd_gpio;
bool override_ro_active_level;
bool override_cd_active_level;
+ irqreturn_t (*cd_gpio_isr)(int irq, void *dev_id);
char *ro_label;
char cd_label[0];
};
@@ -38,32 +41,20 @@ static irqreturn_t mmc_gpio_cd_irqt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int mmc_gpio_alloc(struct mmc_host *host)
+int mmc_gpio_alloc(struct mmc_host *host)
{
size_t len = strlen(dev_name(host->parent)) + 4;
- struct mmc_gpio *ctx;
-
- mutex_lock(&host->slot.lock);
-
- ctx = host->slot.handler_priv;
- if (!ctx) {
- /*
- * devm_kzalloc() can be called after device_initialize(), even
- * before device_add(), i.e., between mmc_alloc_host() and
- * mmc_add_host()
- */
- ctx = devm_kzalloc(&host->class_dev, sizeof(*ctx) + 2 * len,
- GFP_KERNEL);
- if (ctx) {
- ctx->ro_label = ctx->cd_label + len;
- snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
- snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
- host->slot.handler_priv = ctx;
- }
+ struct mmc_gpio *ctx = devm_kzalloc(host->parent,
+ sizeof(*ctx) + 2 * len, GFP_KERNEL);
+
+ if (ctx) {
+ ctx->ro_label = ctx->cd_label + len;
+ snprintf(ctx->cd_label, len, "%s cd", dev_name(host->parent));
+ snprintf(ctx->ro_label, len, "%s ro", dev_name(host->parent));
+ host->slot.handler_priv = ctx;
+ host->slot.cd_irq = -EINVAL;
}
- mutex_unlock(&host->slot.lock);
-
return ctx ? 0 : -ENOMEM;
}
@@ -103,29 +94,19 @@ EXPORT_SYMBOL(mmc_gpio_get_cd);
* @gpio: gpio number requested
*
* As devm_* managed functions are used in mmc_gpio_request_ro(), client
- * drivers do not need to explicitly call mmc_gpio_free_ro() for freeing up,
- * if the requesting and freeing are only needed at probing and unbinding time
- * for once. However, if client drivers do something special like runtime
- * switching for write-protection, they are responsible for calling
- * mmc_gpio_request_ro() and mmc_gpio_free_ro() as a pair on their own.
+ * drivers do not need to worry about freeing up memory.
*
* Returns zero on success, else an error.
*/
int mmc_gpio_request_ro(struct mmc_host *host, unsigned int gpio)
{
- struct mmc_gpio *ctx;
+ struct mmc_gpio *ctx = host->slot.handler_priv;
int ret;
if (!gpio_is_valid(gpio))
return -EINVAL;
- ret = mmc_gpio_alloc(host);
- if (ret < 0)
- return ret;
-
- ctx = host->slot.handler_priv;
-
- ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
+ ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
ctx->ro_label);
if (ret < 0)
return ret;
@@ -156,8 +137,10 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host)
irq = -EINVAL;
if (irq >= 0) {
- ret = devm_request_threaded_irq(&host->class_dev, irq,
- NULL, mmc_gpio_cd_irqt,
+ if (!ctx->cd_gpio_isr)
+ ctx->cd_gpio_isr = mmc_gpio_cd_irqt;
+ ret = devm_request_threaded_irq(host->parent, irq,
+ NULL, ctx->cd_gpio_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
ctx->cd_label, host);
if (ret < 0)
@@ -171,6 +154,19 @@ void mmc_gpiod_request_cd_irq(struct mmc_host *host)
}
EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
+/* Register an alternate interrupt service routine for
+ * the card-detect GPIO.
+ */
+void mmc_gpio_set_cd_isr(struct mmc_host *host,
+ irqreturn_t (*isr)(int irq, void *dev_id))
+{
+ struct mmc_gpio *ctx = host->slot.handler_priv;
+
+ WARN_ON(ctx->cd_gpio_isr);
+ ctx->cd_gpio_isr = isr;
+}
+EXPORT_SYMBOL(mmc_gpio_set_cd_isr);
+
/**
* mmc_gpio_request_cd - request a gpio for card-detection
* @host: mmc host
@@ -178,11 +174,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
* @debounce: debounce time in microseconds
*
* As devm_* managed functions are used in mmc_gpio_request_cd(), client
- * drivers do not need to explicitly call mmc_gpio_free_cd() for freeing up,
- * if the requesting and freeing are only needed at probing and unbinding time
- * for once. However, if client drivers do something special like runtime
- * switching for card-detection, they are responsible for calling
- * mmc_gpio_request_cd() and mmc_gpio_free_cd() as a pair on their own.
+ * drivers do not need to worry about freeing up memory.
*
* If GPIO debouncing is desired, set the debounce parameter to a non-zero
* value. The caller is responsible for ensuring that the GPIO driver associated
@@ -193,16 +185,10 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd_irq);
int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
unsigned int debounce)
{
- struct mmc_gpio *ctx;
+ struct mmc_gpio *ctx = host->slot.handler_priv;
int ret;
- ret = mmc_gpio_alloc(host);
- if (ret < 0)
- return ret;
-
- ctx = host->slot.handler_priv;
-
- ret = devm_gpio_request_one(&host->class_dev, gpio, GPIOF_DIR_IN,
+ ret = devm_gpio_request_one(host->parent, gpio, GPIOF_DIR_IN,
ctx->cd_label);
if (ret < 0)
/*
@@ -226,55 +212,6 @@ int mmc_gpio_request_cd(struct mmc_host *host, unsigned int gpio,
EXPORT_SYMBOL(mmc_gpio_request_cd);
/**
- * mmc_gpio_free_ro - free the write-protection gpio
- * @host: mmc host
- *
- * It's provided only for cases that client drivers need to manually free
- * up the write-protection gpio requested by mmc_gpio_request_ro().
- */
-void mmc_gpio_free_ro(struct mmc_host *host)
-{
- struct mmc_gpio *ctx = host->slot.handler_priv;
- int gpio;
-
- if (!ctx || !ctx->ro_gpio)
- return;
-
- gpio = desc_to_gpio(ctx->ro_gpio);
- ctx->ro_gpio = NULL;
-
- devm_gpio_free(&host->class_dev, gpio);
-}
-EXPORT_SYMBOL(mmc_gpio_free_ro);
-
-/**
- * mmc_gpio_free_cd - free the card-detection gpio
- * @host: mmc host
- *
- * It's provided only for cases that client drivers need to manually free
- * up the card-detection gpio requested by mmc_gpio_request_cd().
- */
-void mmc_gpio_free_cd(struct mmc_host *host)
-{
- struct mmc_gpio *ctx = host->slot.handler_priv;
- int gpio;
-
- if (!ctx || !ctx->cd_gpio)
- return;
-
- if (host->slot.cd_irq >= 0) {
- devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
- host->slot.cd_irq = -EINVAL;
- }
-
- gpio = desc_to_gpio(ctx->cd_gpio);
- ctx->cd_gpio = NULL;
-
- devm_gpio_free(&host->class_dev, gpio);
-}
-EXPORT_SYMBOL(mmc_gpio_free_cd);
-
-/**
* mmc_gpiod_request_cd - request a gpio descriptor for card-detection
* @host: mmc host
* @con_id: function within the GPIO consumer
@@ -285,8 +222,7 @@ EXPORT_SYMBOL(mmc_gpio_free_cd);
* to NULL to ignore
*
* Use this function in place of mmc_gpio_request_cd() to use the GPIO
- * descriptor API. Note that it is paired with mmc_gpiod_free_cd() not
- * mmc_gpio_free_cd(). Note also that it must be called prior to mmc_add_host()
+ * descriptor API. Note that it must be called prior to mmc_add_host()
* otherwise the caller must also call mmc_gpiod_request_cd_irq().
*
* Returns zero on success, else an error.
@@ -295,16 +231,10 @@ int mmc_gpiod_request_cd(struct mmc_host *host, const char *con_id,
unsigned int idx, bool override_active_level,
unsigned int debounce, bool *gpio_invert)
{
- struct mmc_gpio *ctx;
+ struct mmc_gpio *ctx = host->slot.handler_priv;
struct gpio_desc *desc;
int ret;
- ret = mmc_gpio_alloc(host);
- if (ret < 0)
- return ret;
-
- ctx = host->slot.handler_priv;
-
if (!con_id)
con_id = ctx->cd_label;
@@ -339,8 +269,7 @@ EXPORT_SYMBOL(mmc_gpiod_request_cd);
* set to NULL to ignore
*
* Use this function in place of mmc_gpio_request_ro() to use the GPIO
- * descriptor API. Note that it is paired with mmc_gpiod_free_ro() not
- * mmc_gpio_free_ro().
+ * descriptor API.
*
* Returns zero on success, else an error.
*/
@@ -348,16 +277,10 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
unsigned int idx, bool override_active_level,
unsigned int debounce, bool *gpio_invert)
{
- struct mmc_gpio *ctx;
+ struct mmc_gpio *ctx = host->slot.handler_priv;
struct gpio_desc *desc;
int ret;
- ret = mmc_gpio_alloc(host);
- if (ret < 0)
- return ret;
-
- ctx = host->slot.handler_priv;
-
if (!con_id)
con_id = ctx->ro_label;
@@ -380,28 +303,3 @@ int mmc_gpiod_request_ro(struct mmc_host *host, const char *con_id,
return 0;
}
EXPORT_SYMBOL(mmc_gpiod_request_ro);
-
-/**
- * mmc_gpiod_free_cd - free the card-detection gpio descriptor
- * @host: mmc host
- *
- * It's provided only for cases that client drivers need to manually free
- * up the card-detection gpio requested by mmc_gpiod_request_cd().
- */
-void mmc_gpiod_free_cd(struct mmc_host *host)
-{
- struct mmc_gpio *ctx = host->slot.handler_priv;
-
- if (!ctx || !ctx->cd_gpio)
- return;
-
- if (host->slot.cd_irq >= 0) {
- devm_free_irq(&host->class_dev, host->slot.cd_irq, host);
- host->slot.cd_irq = -EINVAL;
- }
-
- devm_gpiod_put(host->parent, ctx->cd_gpio);
-
- ctx->cd_gpio = NULL;
-}
-EXPORT_SYMBOL(mmc_gpiod_free_cd);
diff --git a/drivers/mmc/core/slot-gpio.h b/drivers/mmc/core/slot-gpio.h
new file mode 100644
index 000000000000..8c1854dc5d58
--- /dev/null
+++ b/drivers/mmc/core/slot-gpio.h
@@ -0,0 +1,13 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ *
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _MMC_CORE_SLOTGPIO_H
+#define _MMC_CORE_SLOTGPIO_H
+
+int mmc_gpio_alloc(struct mmc_host *host);
+
+#endif
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 2d6fbdd11803..61ac63a3776a 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -57,6 +57,7 @@ config MMC_SDHCI_IO_ACCESSORS
config MMC_SDHCI_BIG_ENDIAN_32BIT_BYTE_SWAPPER
bool
+ depends on MMC_SDHCI
select MMC_SDHCI_IO_ACCESSORS
help
This option is selected by drivers running on big endian hosts
@@ -82,6 +83,7 @@ config MMC_SDHCI_PCI
config MMC_RICOH_MMC
bool "Ricoh MMC Controller Disabler"
depends on MMC_SDHCI_PCI
+ default y
help
This adds a pci quirk to disable Ricoh MMC Controller. This
proprietary controller is unnecessary because the SDHCI driver
@@ -228,6 +230,7 @@ config MMC_SDHCI_PXAV3
tristate "Marvell MMP2 SD Host Controller support (PXAV3)"
depends on CLKDEV_LOOKUP
depends on MMC_SDHCI_PLTFM
+ depends on ARCH_MMP || COMPILE_TEST
default CPU_MMP2
help
This selects the Marvell(R) PXAV3 SD Host Controller.
@@ -240,6 +243,7 @@ config MMC_SDHCI_PXAV2
tristate "Marvell PXA9XX SD Host Controller support (PXAV2)"
depends on CLKDEV_LOOKUP
depends on MMC_SDHCI_PLTFM
+ depends on ARCH_MMP || COMPILE_TEST
default CPU_PXA910
help
This selects the Marvell(R) PXAV2 SD Host Controller.
@@ -292,6 +296,17 @@ config MMC_SDHCI_BCM2835
If unsure, say N.
+config MMC_SDHCI_F_SDH30
+ tristate "SDHCI support for Fujitsu Semiconductor F_SDH30"
+ depends on MMC_SDHCI_PLTFM
+ depends on OF
+ help
+ This selects the Secure Digital Host Controller Interface (SDHCI)
+ Needed by some Fujitsu SoC for MMC / SD / SDIO support.
+ If you have a controller with this interface, say Y or M here.
+
+ If unsure, say N.
+
config MMC_MOXART
tristate "MOXART SD/MMC Host Controller support"
depends on ARCH_MOXART && MMC
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index f7b0a77cf419..6a7cfe0de332 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_MMC_SDHCI_PXAV3) += sdhci-pxav3.o
obj-$(CONFIG_MMC_SDHCI_PXAV2) += sdhci-pxav2.o
obj-$(CONFIG_MMC_SDHCI_S3C) += sdhci-s3c.o
obj-$(CONFIG_MMC_SDHCI_SIRF) += sdhci-sirf.o
+obj-$(CONFIG_MMC_SDHCI_F_SDH30) += sdhci_f_sdh30.o
obj-$(CONFIG_MMC_SDHCI_SPEAR) += sdhci-spear.o
obj-$(CONFIG_MMC_WBSD) += wbsd.o
obj-$(CONFIG_MMC_AU1X) += au1xmmc.o
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 509365cb22c6..fe32948c6114 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -21,43 +21,7 @@
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
-
-#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)
-#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
-#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
- SDMMC_CLKSEL_CCLK_DRIVE(y) | \
- SDMMC_CLKSEL_CCLK_DIVIDER(z))
-#define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
-
-#define EXYNOS4210_FIXED_CIU_CLK_DIV 2
-#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
-
-/* Block number in eMMC */
-#define DWMCI_BLOCK_NUM 0xFFFFFFFF
-
-#define SDMMC_EMMCP_BASE 0x1000
-#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
-#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200)
-#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204)
-#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C)
-
-/* SMU control bits */
-#define DWMCI_MPSCTRL_SECURE_READ_BIT BIT(7)
-#define DWMCI_MPSCTRL_SECURE_WRITE_BIT BIT(6)
-#define DWMCI_MPSCTRL_NON_SECURE_READ_BIT BIT(5)
-#define DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4)
-#define DWMCI_MPSCTRL_USE_FUSE_KEY BIT(3)
-#define DWMCI_MPSCTRL_ECB_MODE BIT(2)
-#define DWMCI_MPSCTRL_ENCRYPTION BIT(1)
-#define DWMCI_MPSCTRL_VALID BIT(0)
-
-#define EXYNOS_CCLKIN_MIN 50000000 /* unit: HZ */
+#include "dw_mmc-exynos.h"
/* Variations in Exynos specific dw-mshc controller */
enum dw_mci_exynos_type {
@@ -114,11 +78,11 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
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 |
- DWMCI_MPSCTRL_NON_SECURE_READ_BIT |
- DWMCI_MPSCTRL_VALID |
- DWMCI_MPSCTRL_NON_SECURE_WRITE_BIT);
+ mci_writel(host, MPSEND0, SDMMC_ENDING_SEC_NR_MAX);
+ mci_writel(host, MPSCTRL0, SDMMC_MPSCTRL_SECURE_WRITE_BIT |
+ SDMMC_MPSCTRL_NON_SECURE_READ_BIT |
+ SDMMC_MPSCTRL_VALID |
+ SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT);
}
return 0;
@@ -127,9 +91,9 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
static int dw_mci_exynos_setup_clock(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- unsigned long rate = clk_get_rate(host->ciu_clk);
- host->bus_hz = rate / (priv->ciu_div + 1);
+ host->bus_hz /= (priv->ciu_div + 1);
+
return 0;
}
@@ -232,8 +196,11 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
mci_writel(host, CLKSEL, priv->sdr_timing);
}
- /* Don't care if wanted clock is zero */
- if (!wanted)
+ /*
+ * Don't care if wanted clock is zero or
+ * ciu clock is unavailable
+ */
+ if (!wanted || IS_ERR(host->ciu_clk))
return;
/* Guaranteed minimum frequency for cclkin */
@@ -263,10 +230,8 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
int ret;
priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- dev_err(host->dev, "mem alloc failed for private data\n");
+ if (!priv)
return -ENOMEM;
- }
for (idx = 0; idx < ARRAY_SIZE(exynos_compat); idx++) {
if (of_device_is_compatible(np, exynos_compat[idx].compatible))
@@ -375,64 +340,23 @@ out:
return loc;
}
-static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
- struct dw_mci_tuning_data *tuning_data)
+static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot)
{
struct dw_mci *host = slot->host;
struct mmc_host *mmc = slot->mmc;
- const u8 *blk_pattern = tuning_data->blk_pattern;
- u8 *blk_test;
- unsigned int blksz = tuning_data->blksz;
u8 start_smpl, smpl, candiates = 0;
s8 found = -1;
int ret = 0;
- blk_test = kmalloc(blksz, GFP_KERNEL);
- if (!blk_test)
- return -ENOMEM;
-
start_smpl = dw_mci_exynos_get_clksmpl(host);
do {
- struct mmc_request mrq = {NULL};
- struct mmc_command cmd = {0};
- struct mmc_command stop = {0};
- struct mmc_data data = {0};
- struct scatterlist sg;
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- stop.opcode = MMC_STOP_TRANSMISSION;
- stop.arg = 0;
- stop.flags = MMC_RSP_R1B | MMC_CMD_AC;
-
- data.blksz = blksz;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = &sg;
- data.sg_len = 1;
-
- sg_init_one(&sg, blk_test, blksz);
- mrq.cmd = &cmd;
- mrq.stop = &stop;
- mrq.data = &data;
- host->mrq = &mrq;
-
mci_writel(host, TMOUT, ~0);
smpl = dw_mci_exynos_move_next_clksmpl(host);
- mmc_wait_for_req(mmc, &mrq);
+ if (!mmc_send_tuning(mmc))
+ candiates |= (1 << smpl);
- if (!cmd.error && !data.error) {
- if (!memcmp(blk_pattern, blk_test, blksz))
- candiates |= (1 << smpl);
- } else {
- dev_dbg(host->dev,
- "Tuning error: cmd.error:%d, data.error:%d\n",
- cmd.error, data.error);
- }
} while (start_smpl != smpl);
found = dw_mci_exynos_get_best_clksmpl(candiates);
@@ -441,7 +365,6 @@ static int dw_mci_exynos_execute_tuning(struct dw_mci_slot *slot, u32 opcode,
else
ret = -EIO;
- kfree(blk_test);
return ret;
}
@@ -499,7 +422,7 @@ static const struct dev_pm_ops dw_mci_exynos_pmops = {
static struct platform_driver dw_mci_exynos_pltfm_driver = {
.probe = dw_mci_exynos_probe,
- .remove = __exit_p(dw_mci_pltfm_remove),
+ .remove = dw_mci_pltfm_remove,
.driver = {
.name = "dwmmc_exynos",
.of_match_table = dw_mci_exynos_match,
diff --git a/drivers/mmc/host/dw_mmc-exynos.h b/drivers/mmc/host/dw_mmc-exynos.h
new file mode 100644
index 000000000000..7872ce586b55
--- /dev/null
+++ b/drivers/mmc/host/dw_mmc-exynos.h
@@ -0,0 +1,56 @@
+/*
+ * Exynos Specific Extensions for Synopsys DW Multimedia Card Interface driver
+ *
+ * Copyright (C) 2012-2014 Samsung Electronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#ifndef _DW_MMC_EXYNOS_H_
+#define _DW_MMC_EXYNOS_H_
+
+/* Extended Register's Offset */
+#define SDMMC_CLKSEL 0x09C
+#define SDMMC_CLKSEL64 0x0A8
+
+/* CLKSEL register defines */
+#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)
+#define SDMMC_CLKSEL_GET_DRV_WD3(x) (((x) >> 16) & 0x7)
+#define SDMMC_CLKSEL_TIMING(x, y, z) (SDMMC_CLKSEL_CCLK_SAMPLE(x) | \
+ SDMMC_CLKSEL_CCLK_DRIVE(y) | \
+ SDMMC_CLKSEL_CCLK_DIVIDER(z))
+#define SDMMC_CLKSEL_WAKEUP_INT BIT(11)
+
+/* Protector Register */
+#define SDMMC_EMMCP_BASE 0x1000
+#define SDMMC_MPSECURITY (SDMMC_EMMCP_BASE + 0x0010)
+#define SDMMC_MPSBEGIN0 (SDMMC_EMMCP_BASE + 0x0200)
+#define SDMMC_MPSEND0 (SDMMC_EMMCP_BASE + 0x0204)
+#define SDMMC_MPSCTRL0 (SDMMC_EMMCP_BASE + 0x020C)
+
+/* SMU control defines */
+#define SDMMC_MPSCTRL_SECURE_READ_BIT BIT(7)
+#define SDMMC_MPSCTRL_SECURE_WRITE_BIT BIT(6)
+#define SDMMC_MPSCTRL_NON_SECURE_READ_BIT BIT(5)
+#define SDMMC_MPSCTRL_NON_SECURE_WRITE_BIT BIT(4)
+#define SDMMC_MPSCTRL_USE_FUSE_KEY BIT(3)
+#define SDMMC_MPSCTRL_ECB_MODE BIT(2)
+#define SDMMC_MPSCTRL_ENCRYPTION BIT(1)
+#define SDMMC_MPSCTRL_VALID BIT(0)
+
+/* Maximum number of Ending sector */
+#define SDMMC_ENDING_SEC_NR_MAX 0xFFFFFFFF
+
+/* Fixed clock divider */
+#define EXYNOS4210_FIXED_CIU_CLK_DIV 2
+#define EXYNOS4412_FIXED_CIU_CLK_DIV 4
+
+/* Minimal required clock frequency for cclkin, unit: HZ */
+#define EXYNOS_CCLKIN_MIN 50000000
+
+#endif /* _DW_MMC_EXYNOS_H_ */
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 5650ac488cf3..e2a726a503ee 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -133,7 +133,7 @@ static SIMPLE_DEV_PM_OPS(dw_mci_rockchip_pmops,
static struct platform_driver dw_mci_rockchip_pltfm_driver = {
.probe = dw_mci_rockchip_probe,
- .remove = __exit_p(dw_mci_pltfm_remove),
+ .remove = dw_mci_pltfm_remove,
.driver = {
.name = "dwmmc_rockchip",
.of_match_table = dw_mci_rockchip_match,
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 67c04518ec4c..4d2e3c2e1830 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -27,6 +27,7 @@
#include <linux/stat.h>
#include <linux/delay.h>
#include <linux/irq.h>
+#include <linux/mmc/card.h>
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
@@ -313,7 +314,9 @@ static u32 dw_mci_prep_stop_abort(struct dw_mci *host, struct mmc_command *cmd)
if (cmdr == MMC_READ_SINGLE_BLOCK ||
cmdr == MMC_READ_MULTIPLE_BLOCK ||
cmdr == MMC_WRITE_BLOCK ||
- cmdr == MMC_WRITE_MULTIPLE_BLOCK) {
+ cmdr == MMC_WRITE_MULTIPLE_BLOCK ||
+ cmdr == MMC_SEND_TUNING_BLOCK ||
+ cmdr == MMC_SEND_TUNING_BLOCK_HS200) {
stop->opcode = MMC_STOP_TRANSMISSION;
stop->arg = 0;
stop->flags = MMC_RSP_R1B | MMC_CMD_AC;
@@ -758,6 +761,7 @@ disable:
static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
{
+ unsigned long irqflags;
int sg_len;
u32 temp;
@@ -794,9 +798,11 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
mci_writel(host, CTRL, temp);
/* Disable RX/TX IRQs, let DMA handle it */
+ spin_lock_irqsave(&host->irq_lock, irqflags);
temp = mci_readl(host, INTMASK);
temp &= ~(SDMMC_INT_RXDR | SDMMC_INT_TXDR);
mci_writel(host, INTMASK, temp);
+ spin_unlock_irqrestore(&host->irq_lock, irqflags);
host->dma_ops->start(host, sg_len);
@@ -805,6 +811,7 @@ static int dw_mci_submit_data_dma(struct dw_mci *host, struct mmc_data *data)
static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
{
+ unsigned long irqflags;
u32 temp;
data->error = -EINPROGRESS;
@@ -833,9 +840,12 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
host->part_buf_count = 0;
mci_writel(host, RINTSTS, SDMMC_INT_TXDR | SDMMC_INT_RXDR);
+
+ spin_lock_irqsave(&host->irq_lock, irqflags);
temp = mci_readl(host, INTMASK);
temp |= SDMMC_INT_TXDR | SDMMC_INT_RXDR;
mci_writel(host, INTMASK, temp);
+ spin_unlock_irqrestore(&host->irq_lock, irqflags);
temp = mci_readl(host, CTRL);
temp &= ~SDMMC_CTRL_DMA_ENABLE;
@@ -926,7 +936,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->sdio_id)))
+ if (!test_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags))
clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
mci_writel(host, CLKENA, clk_en_a);
@@ -1109,6 +1119,12 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
return;
}
}
+ set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
+ regs = mci_readl(slot->host, PWREN);
+ regs |= (1 << slot->id);
+ mci_writel(slot->host, PWREN, regs);
+ break;
+ case MMC_POWER_ON:
if (!IS_ERR(mmc->supply.vqmmc) && !slot->host->vqmmc_enabled) {
ret = regulator_enable(mmc->supply.vqmmc);
if (ret < 0)
@@ -1117,10 +1133,6 @@ static void dw_mci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
else
slot->host->vqmmc_enabled = true;
}
- set_bit(DW_MMC_CARD_NEED_INIT, &slot->flags);
- regs = mci_readl(slot->host, PWREN);
- regs |= (1 << slot->id);
- mci_writel(slot->host, PWREN, regs);
break;
case MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc))
@@ -1245,27 +1257,37 @@ static int dw_mci_get_cd(struct mmc_host *mmc)
return present;
}
-/*
- * Disable lower power mode.
- *
- * Low power mode will stop the card clock when idle. According to the
- * description of the CLKENA register we should disable low power mode
- * for SDIO cards if we need SDIO interrupts to work.
- *
- * This function is fast if low power mode is already disabled.
- */
-static void dw_mci_disable_low_power(struct dw_mci_slot *slot)
+static void dw_mci_init_card(struct mmc_host *mmc, struct mmc_card *card)
{
+ struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
- u32 clk_en_a;
- const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
- clk_en_a = mci_readl(host, CLKENA);
+ /*
+ * Low power mode will stop the card clock when idle. According to the
+ * description of the CLKENA register we should disable low power mode
+ * for SDIO cards if we need SDIO interrupts to work.
+ */
+ if (mmc->caps & MMC_CAP_SDIO_IRQ) {
+ const u32 clken_low_pwr = SDMMC_CLKEN_LOW_PWR << slot->id;
+ u32 clk_en_a_old;
+ u32 clk_en_a;
- if (clk_en_a & clken_low_pwr) {
- mci_writel(host, CLKENA, clk_en_a & ~clken_low_pwr);
- mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
- SDMMC_CMD_PRV_DAT_WAIT, 0);
+ clk_en_a_old = mci_readl(host, CLKENA);
+
+ if (card->type == MMC_TYPE_SDIO ||
+ card->type == MMC_TYPE_SD_COMBO) {
+ set_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
+ clk_en_a = clk_en_a_old & ~clken_low_pwr;
+ } else {
+ clear_bit(DW_MMC_CARD_NO_LOW_PWR, &slot->flags);
+ clk_en_a = clk_en_a_old | clken_low_pwr;
+ }
+
+ if (clk_en_a != clk_en_a_old) {
+ mci_writel(host, CLKENA, clk_en_a);
+ mci_send_cmd(slot, SDMMC_CMD_UPD_CLK |
+ SDMMC_CMD_PRV_DAT_WAIT, 0);
+ }
}
}
@@ -1273,25 +1295,20 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
{
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
+ unsigned long irqflags;
u32 int_mask;
+ spin_lock_irqsave(&host->irq_lock, irqflags);
+
/* Enable/disable Slot Specific SDIO interrupt */
int_mask = mci_readl(host, INTMASK);
- if (enb) {
- /*
- * Turn off low power mode if it was enabled. This is a bit of
- * a heavy operation and we disable / enable IRQs a lot, so
- * we'll leave low power mode disabled and it will get
- * re-enabled again in dw_mci_setup_bus().
- */
- dw_mci_disable_low_power(slot);
+ if (enb)
+ int_mask |= SDMMC_INT_SDIO(slot->sdio_id);
+ else
+ int_mask &= ~SDMMC_INT_SDIO(slot->sdio_id);
+ mci_writel(host, INTMASK, int_mask);
- mci_writel(host, INTMASK,
- (int_mask | SDMMC_INT_SDIO(slot->sdio_id)));
- } else {
- mci_writel(host, INTMASK,
- (int_mask & ~SDMMC_INT_SDIO(slot->sdio_id)));
- }
+ spin_unlock_irqrestore(&host->irq_lock, irqflags);
}
static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
@@ -1299,30 +1316,10 @@ static int dw_mci_execute_tuning(struct mmc_host *mmc, u32 opcode)
struct dw_mci_slot *slot = mmc_priv(mmc);
struct dw_mci *host = slot->host;
const struct dw_mci_drv_data *drv_data = host->drv_data;
- struct dw_mci_tuning_data tuning_data;
int err = -ENOSYS;
- if (opcode == MMC_SEND_TUNING_BLOCK_HS200) {
- if (mmc->ios.bus_width == MMC_BUS_WIDTH_8) {
- tuning_data.blk_pattern = tuning_blk_pattern_8bit;
- tuning_data.blksz = sizeof(tuning_blk_pattern_8bit);
- } else if (mmc->ios.bus_width == MMC_BUS_WIDTH_4) {
- tuning_data.blk_pattern = tuning_blk_pattern_4bit;
- tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
- } else {
- return -EINVAL;
- }
- } else if (opcode == MMC_SEND_TUNING_BLOCK) {
- tuning_data.blk_pattern = tuning_blk_pattern_4bit;
- tuning_data.blksz = sizeof(tuning_blk_pattern_4bit);
- } else {
- dev_err(host->dev,
- "Undefined command(%d) for tuning\n", opcode);
- return -EINVAL;
- }
-
if (drv_data && drv_data->execute_tuning)
- err = drv_data->execute_tuning(slot, opcode, &tuning_data);
+ err = drv_data->execute_tuning(slot);
return err;
}
@@ -1337,7 +1334,7 @@ static const struct mmc_host_ops dw_mci_ops = {
.execute_tuning = dw_mci_execute_tuning,
.card_busy = dw_mci_card_busy,
.start_signal_voltage_switch = dw_mci_switch_voltage,
-
+ .init_card = dw_mci_init_card,
};
static void dw_mci_request_end(struct dw_mci *host, struct mmc_request *mrq)
@@ -2319,9 +2316,9 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
#ifdef CONFIG_MMC_DW_IDMAC
mmc->max_segs = host->ring_size;
mmc->max_blk_size = 65536;
- mmc->max_blk_count = host->ring_size;
mmc->max_seg_size = 0x1000;
- mmc->max_req_size = mmc->max_seg_size * mmc->max_blk_count;
+ mmc->max_req_size = mmc->max_seg_size * host->ring_size;
+ mmc->max_blk_count = mmc->max_req_size / 512;
#else
mmc->max_segs = 64;
mmc->max_blk_size = 65536; /* BLKSIZ is 16 bits */
@@ -2533,10 +2530,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
u32 clock_frequency;
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata) {
- dev_err(dev, "could not allocate memory for pdata\n");
+ if (!pdata)
return ERR_PTR(-ENOMEM);
- }
/* find out number of slots supported */
if (of_property_read_u32(dev->of_node, "num-slots",
@@ -2660,6 +2655,7 @@ int dw_mci_probe(struct dw_mci *host)
host->quirks = host->pdata->quirks;
spin_lock_init(&host->lock);
+ spin_lock_init(&host->irq_lock);
INIT_LIST_HEAD(&host->queue);
/*
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 0d0f7a271d63..18c4afe683b8 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -244,15 +244,11 @@ struct dw_mci_slot {
unsigned long flags;
#define DW_MMC_CARD_PRESENT 0
#define DW_MMC_CARD_NEED_INIT 1
+#define DW_MMC_CARD_NO_LOW_PWR 2
int id;
int sdio_id;
};
-struct dw_mci_tuning_data {
- const u8 *blk_pattern;
- unsigned int blksz;
-};
-
/**
* dw_mci driver data - dw-mshc implementation specific driver data.
* @caps: mmc subsystem specified capabilities of the controller(s).
@@ -274,7 +270,6 @@ struct dw_mci_drv_data {
void (*prepare_command)(struct dw_mci *host, u32 *cmdr);
void (*set_ios)(struct dw_mci *host, struct mmc_ios *ios);
int (*parse_dt)(struct dw_mci *host);
- int (*execute_tuning)(struct dw_mci_slot *slot, u32 opcode,
- struct dw_mci_tuning_data *tuning_data);
+ int (*execute_tuning)(struct dw_mci_slot *slot);
};
#endif /* _DW_MMC_H_ */
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 8232e9a02d40..7fe16194ebc8 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -430,7 +430,6 @@ static void mmci_init_sg(struct mmci_host *host, struct mmc_data *data)
static void mmci_dma_setup(struct mmci_host *host)
{
const char *rxname, *txname;
- dma_cap_mask_t mask;
struct variant_data *variant = host->variant;
host->dma_rx_channel = dma_request_slave_channel(mmc_dev(host->mmc), "rx");
@@ -439,10 +438,6 @@ static void mmci_dma_setup(struct mmci_host *host)
/* initialize pre request cookie */
host->next_data.cookie = 1;
- /* Try to acquire a generic DMA engine slave channel */
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
/*
* If only an RX channel is specified, the driver will
* attempt to use it bidirectionally, however if it is
@@ -1739,10 +1734,10 @@ static int mmci_probe(struct amba_device *dev,
pm_runtime_set_autosuspend_delay(&dev->dev, 50);
pm_runtime_use_autosuspend(&dev->dev);
- pm_runtime_put(&dev->dev);
mmc_add_host(mmc);
+ pm_runtime_put(&dev->dev);
return 0;
clk_disable:
diff --git a/drivers/mmc/host/moxart-mmc.c b/drivers/mmc/host/moxart-mmc.c
index f3e18d08e852..006f1862444b 100644
--- a/drivers/mmc/host/moxart-mmc.c
+++ b/drivers/mmc/host/moxart-mmc.c
@@ -17,6 +17,7 @@
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
+#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/blkdev.h>
#include <linux/dma-mapping.h>
@@ -562,7 +563,6 @@ static int moxart_probe(struct platform_device *pdev)
struct dma_slave_config cfg;
struct clk *clk;
void __iomem *reg_mmc;
- dma_cap_mask_t mask;
int irq, ret;
u32 i;
@@ -586,9 +586,8 @@ static int moxart_probe(struct platform_device *pdev)
goto out;
}
- clk = of_clk_get(node, 0);
+ clk = devm_clk_get(dev, NULL);
if (IS_ERR(clk)) {
- dev_err(dev, "of_clk_get failed\n");
ret = PTR_ERR(clk);
goto out;
}
@@ -599,10 +598,9 @@ static int moxart_probe(struct platform_device *pdev)
goto out;
}
- mmc_of_parse(mmc);
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
+ ret = mmc_of_parse(mmc);
+ if (ret)
+ goto out;
host = mmc_priv(mmc);
host->mmc = mmc;
@@ -611,8 +609,8 @@ static int moxart_probe(struct platform_device *pdev)
host->timeout = msecs_to_jiffies(1000);
host->sysclk = clk_get_rate(clk);
host->fifo_width = readl(host->base + REG_FEATURE) << 2;
- host->dma_chan_tx = of_dma_request_slave_channel(node, "tx");
- host->dma_chan_rx = of_dma_request_slave_channel(node, "rx");
+ host->dma_chan_tx = dma_request_slave_channel_reason(dev, "tx");
+ host->dma_chan_rx = dma_request_slave_channel_reason(dev, "rx");
spin_lock_init(&host->lock);
@@ -622,6 +620,11 @@ static int moxart_probe(struct platform_device *pdev)
mmc->ocr_avail = 0xffff00; /* Support 2.0v - 3.6v power. */
if (IS_ERR(host->dma_chan_tx) || IS_ERR(host->dma_chan_rx)) {
+ if (PTR_ERR(host->dma_chan_tx) == -EPROBE_DEFER ||
+ PTR_ERR(host->dma_chan_rx) == -EPROBE_DEFER) {
+ ret = -EPROBE_DEFER;
+ goto out;
+ }
dev_dbg(dev, "PIO mode transfer enabled\n");
host->have_dma = false;
} else {
@@ -700,9 +703,6 @@ static int moxart_remove(struct platform_device *pdev)
writel(readl(host->base + REG_CLOCK_CONTROL) | CLK_OFF,
host->base + REG_CLOCK_CONTROL);
}
-
- kfree(host);
-
return 0;
}
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index 4f8618f4522d..a448498e3af2 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -25,7 +25,6 @@
#include <linux/of_irq.h>
#include <linux/mmc/host.h>
#include <linux/mmc/slot-gpio.h>
-#include <linux/pinctrl/consumer.h>
#include <asm/sizes.h>
#include <asm/unaligned.h>
@@ -704,7 +703,6 @@ static int mvsd_probe(struct platform_device *pdev)
const struct mbus_dram_target_info *dram;
struct resource *r;
int ret, irq;
- struct pinctrl *pinctrl;
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@@ -721,10 +719,6 @@ static int mvsd_probe(struct platform_device *pdev)
host->mmc = mmc;
host->dev = &pdev->dev;
- pinctrl = devm_pinctrl_get_select_default(&pdev->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&pdev->dev, "no pins associated\n");
-
/*
* Some non-DT platforms do not pass a clock, and the clock
* frequency is passed through platform_data. On DT platforms,
@@ -828,8 +822,6 @@ static int mvsd_probe(struct platform_device *pdev)
out:
if (mmc) {
- mmc_gpio_free_cd(mmc);
- mmc_gpio_free_ro(mmc);
if (!IS_ERR(host->clk))
clk_disable_unprepare(host->clk);
mmc_free_host(mmc);
@@ -844,8 +836,6 @@ static int mvsd_remove(struct platform_device *pdev)
struct mvsd_host *host = mmc_priv(mmc);
- mmc_gpio_free_cd(mmc);
- mmc_gpio_free_ro(mmc);
mmc_remove_host(mmc);
del_timer_sync(&host->timer);
mvsd_power_down(host);
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index 60c4ca97a727..a82411a2c024 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -677,8 +677,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
return 0;
out_free_dma:
- if (ssp->dmach)
- dma_release_channel(ssp->dmach);
+ dma_release_channel(ssp->dmach);
out_clk_disable:
clk_disable_unprepare(ssp->clk);
out_mmc_free:
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index 7c71dcdcba8b..f84cfb01716d 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -36,6 +36,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/core.h>
#include <linux/mmc/mmc.h>
+#include <linux/mmc/slot-gpio.h>
#include <linux/io.h>
#include <linux/irq.h>
#include <linux/gpio.h>
@@ -251,55 +252,24 @@ static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
static int omap_hsmmc_card_detect(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_hsmmc_platform_data *mmc = host->pdata;
- /* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(mmc->switch_pin);
+ return mmc_gpio_get_cd(host->mmc);
}
static int omap_hsmmc_get_wp(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_hsmmc_platform_data *mmc = host->pdata;
- /* NOTE: assumes write protect signal is active-high */
- return gpio_get_value_cansleep(mmc->gpio_wp);
+ return mmc_gpio_get_ro(host->mmc);
}
static int omap_hsmmc_get_cover_state(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_hsmmc_platform_data *mmc = host->pdata;
- /* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(mmc->switch_pin);
+ return mmc_gpio_get_cd(host->mmc);
}
-#ifdef CONFIG_PM
-
-static int omap_hsmmc_suspend_cdirq(struct device *dev)
-{
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- disable_irq(host->card_detect_irq);
- return 0;
-}
-
-static int omap_hsmmc_resume_cdirq(struct device *dev)
-{
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- enable_irq(host->card_detect_irq);
- return 0;
-}
-
-#else
-
-#define omap_hsmmc_suspend_cdirq NULL
-#define omap_hsmmc_resume_cdirq NULL
-
-#endif
-
#ifdef CONFIG_REGULATOR
static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
@@ -464,7 +434,10 @@ static inline int omap_hsmmc_have_reg(void)
#endif
-static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host,
+static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id);
+
+static int omap_hsmmc_gpio_init(struct mmc_host *mmc,
+ struct omap_hsmmc_host *host,
struct omap_hsmmc_platform_data *pdata)
{
int ret;
@@ -477,46 +450,24 @@ static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host,
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");
+ mmc_gpio_set_cd_isr(mmc, omap_hsmmc_detect);
+ ret = mmc_gpio_request_cd(mmc, pdata->switch_pin, 0);
if (ret)
return ret;
- ret = gpio_direction_input(pdata->switch_pin);
- if (ret)
- goto err_free_sp;
} else {
pdata->switch_pin = -EINVAL;
}
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->gpio_wp);
+ ret = mmc_gpio_request_ro(mmc, pdata->gpio_wp);
if (ret)
- goto err_free_wp;
+ return ret;
} else {
pdata->gpio_wp = -EINVAL;
}
return 0;
-
-err_free_wp:
- gpio_free(pdata->gpio_wp);
-err_free_cd:
- if (gpio_is_valid(pdata->switch_pin))
-err_free_sp:
- gpio_free(pdata->switch_pin);
- return ret;
-}
-
-static void omap_hsmmc_gpio_free(struct omap_hsmmc_host *host,
- struct omap_hsmmc_platform_data *pdata)
-{
- if (gpio_is_valid(pdata->gpio_wp))
- gpio_free(pdata->gpio_wp);
- if (gpio_is_valid(pdata->switch_pin))
- gpio_free(pdata->switch_pin);
}
/*
@@ -1978,13 +1929,6 @@ static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
{
struct omap_hsmmc_platform_data *pdata;
struct device_node *np = dev->of_node;
- u32 bus_width, max_freq;
- int cd_gpio, wp_gpio;
-
- cd_gpio = of_get_named_gpio(np, "cd-gpios", 0);
- wp_gpio = of_get_named_gpio(np, "wp-gpios", 0);
- if (cd_gpio == -EPROBE_DEFER || wp_gpio == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
if (!pdata)
@@ -1993,34 +1937,20 @@ static struct omap_hsmmc_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;
- pdata->switch_pin = cd_gpio;
- pdata->gpio_wp = wp_gpio;
+ pdata->switch_pin = -EINVAL;
+ pdata->gpio_wp = -EINVAL;
if (of_find_property(np, "ti,non-removable", NULL)) {
pdata->nonremovable = true;
pdata->no_regulator_off_init = true;
}
- of_property_read_u32(np, "bus-width", &bus_width);
- if (bus_width == 4)
- pdata->caps |= MMC_CAP_4_BIT_DATA;
- else if (bus_width == 8)
- pdata->caps |= MMC_CAP_8_BIT_DATA;
if (of_find_property(np, "ti,needs-special-reset", NULL))
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->features |= HSMMC_HAS_HSPE_SUPPORT;
- if (of_find_property(np, "keep-power-in-suspend", NULL))
- pdata->pm_caps |= MMC_PM_KEEP_POWER;
-
- if (of_find_property(np, "enable-sdio-wakeup", NULL))
- pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
-
return pdata;
}
#else
@@ -2078,6 +2008,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
goto err;
}
+ ret = mmc_of_parse(mmc);
+ if (ret)
+ goto err1;
+
host = mmc_priv(mmc);
host->mmc = mmc;
host->pdata = pdata;
@@ -2091,7 +2025,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->next_data.cookie = 1;
host->pbias_enabled = 0;
- ret = omap_hsmmc_gpio_init(host, pdata);
+ ret = omap_hsmmc_gpio_init(mmc, host, pdata);
if (ret)
goto err_gpio;
@@ -2106,7 +2040,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (pdata->max_freq > 0)
mmc->f_max = pdata->max_freq;
- else
+ else if (mmc->f_max == 0)
mmc->f_max = OMAP_MMC_MAX_CLOCK;
spin_lock_init(&host->irq_lock);
@@ -2160,7 +2094,7 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (mmc_pdata(host)->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
- mmc->pm_caps = mmc_pdata(host)->pm_caps;
+ mmc->pm_caps |= mmc_pdata(host)->pm_caps;
omap_hsmmc_conf_bus_power(host);
@@ -2222,22 +2156,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
- /* Request IRQ for card detect */
- if (host->card_detect_irq) {
- ret = devm_request_threaded_irq(&pdev->dev,
- host->card_detect_irq,
- NULL, omap_hsmmc_detect,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- mmc_hostname(mmc), host);
- if (ret) {
- dev_err(mmc_dev(host->mmc),
- "Unable to grab MMC CD IRQ\n");
- goto err_irq_cd;
- }
- host->suspend = omap_hsmmc_suspend_cdirq;
- host->resume = omap_hsmmc_resume_cdirq;
- }
-
omap_hsmmc_disable_irq(host);
/*
@@ -2276,7 +2194,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
err_slot_name:
mmc_remove_host(mmc);
-err_irq_cd:
if (host->use_reg)
omap_hsmmc_reg_put(host);
err_irq:
@@ -2289,7 +2206,6 @@ err_irq:
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
err1:
- omap_hsmmc_gpio_free(host, pdata);
err_gpio:
mmc_free_host(mmc);
err:
@@ -2315,32 +2231,12 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
- omap_hsmmc_gpio_free(host, host->pdata);
mmc_free_host(host->mmc);
return 0;
}
#ifdef CONFIG_PM
-static int omap_hsmmc_prepare(struct device *dev)
-{
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- if (host->suspend)
- return host->suspend(dev);
-
- return 0;
-}
-
-static void omap_hsmmc_complete(struct device *dev)
-{
- struct omap_hsmmc_host *host = dev_get_drvdata(dev);
-
- if (host->resume)
- host->resume(dev);
-
-}
-
static int omap_hsmmc_suspend(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
@@ -2398,8 +2294,6 @@ static int omap_hsmmc_resume(struct device *dev)
}
#else
-#define omap_hsmmc_prepare NULL
-#define omap_hsmmc_complete NULL
#define omap_hsmmc_suspend NULL
#define omap_hsmmc_resume NULL
#endif
@@ -2484,8 +2378,6 @@ static int omap_hsmmc_runtime_resume(struct device *dev)
static struct dev_pm_ops omap_hsmmc_dev_pm_ops = {
.suspend = omap_hsmmc_suspend,
.resume = omap_hsmmc_resume,
- .prepare = omap_hsmmc_prepare,
- .complete = omap_hsmmc_complete,
.runtime_suspend = omap_hsmmc_runtime_suspend,
.runtime_resume = omap_hsmmc_runtime_resume,
};
diff --git a/drivers/mmc/host/rtsx_pci_sdmmc.c b/drivers/mmc/host/rtsx_pci_sdmmc.c
index c70b602f8f1e..1d3d6c4bfdc6 100644
--- a/drivers/mmc/host/rtsx_pci_sdmmc.c
+++ b/drivers/mmc/host/rtsx_pci_sdmmc.c
@@ -28,6 +28,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/mmc/sd.h>
+#include <linux/mmc/sdio.h>
#include <linux/mmc/card.h>
#include <linux/mfd/rtsx_pci.h>
#include <asm/unaligned.h>
@@ -53,9 +54,9 @@ struct realtek_pci_sdmmc {
#define SDMMC_POWER_ON 1
#define SDMMC_POWER_OFF 0
- unsigned int sg_count;
+ int sg_count;
s32 cookie;
- unsigned int cookie_sg_count;
+ int cookie_sg_count;
bool using_cookie;
};
@@ -71,30 +72,83 @@ static inline void sd_clear_error(struct realtek_pci_sdmmc *host)
}
#ifdef DEBUG
-static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
+static void dump_reg_range(struct realtek_pci_sdmmc *host, u16 start, u16 end)
{
- struct rtsx_pcr *pcr = host->pcr;
- u16 i;
- u8 *ptr;
+ u16 len = end - start + 1;
+ int i;
+ u8 data[8];
+
+ for (i = 0; i < len; i += 8) {
+ int j;
+ int n = min(8, len - i);
+
+ memset(&data, 0, sizeof(data));
+ for (j = 0; j < n; j++)
+ rtsx_pci_read_register(host->pcr, start + i + j,
+ data + j);
+ dev_dbg(sdmmc_dev(host), "0x%04X(%d): %8ph\n",
+ start + i, n, data);
+ }
+}
- /* Print SD host internal registers */
- rtsx_pci_init_cmd(pcr);
- for (i = 0xFDA0; i <= 0xFDAE; i++)
- rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
- for (i = 0xFD52; i <= 0xFD69; i++)
- rtsx_pci_add_cmd(pcr, READ_REG_CMD, i, 0, 0);
- rtsx_pci_send_cmd(pcr, 100);
-
- ptr = rtsx_pci_get_cmd_data(pcr);
- for (i = 0xFDA0; i <= 0xFDAE; i++)
- dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
- for (i = 0xFD52; i <= 0xFD69; i++)
- dev_dbg(sdmmc_dev(host), "0x%04X: 0x%02x\n", i, *(ptr++));
+static void sd_print_debug_regs(struct realtek_pci_sdmmc *host)
+{
+ dump_reg_range(host, 0xFDA0, 0xFDB3);
+ dump_reg_range(host, 0xFD52, 0xFD69);
}
#else
#define sd_print_debug_regs(host)
#endif /* DEBUG */
+static inline int sd_get_cd_int(struct realtek_pci_sdmmc *host)
+{
+ return rtsx_pci_readl(host->pcr, RTSX_BIPR) & SD_EXIST;
+}
+
+static void sd_cmd_set_sd_cmd(struct rtsx_pcr *pcr, struct mmc_command *cmd)
+{
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF,
+ SD_CMD_START | cmd->opcode);
+ rtsx_pci_write_be32(pcr, SD_CMD1, cmd->arg);
+}
+
+static void sd_cmd_set_data_len(struct rtsx_pcr *pcr, u16 blocks, u16 blksz)
+{
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, blocks);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, blocks >> 8);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, blksz);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, blksz >> 8);
+}
+
+static int sd_response_type(struct mmc_command *cmd)
+{
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ return SD_RSP_TYPE_R0;
+ case MMC_RSP_R1:
+ return SD_RSP_TYPE_R1;
+ case MMC_RSP_R1 & ~MMC_RSP_CRC:
+ return SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
+ case MMC_RSP_R1B:
+ return SD_RSP_TYPE_R1b;
+ case MMC_RSP_R2:
+ return SD_RSP_TYPE_R2;
+ case MMC_RSP_R3:
+ return SD_RSP_TYPE_R3;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int sd_status_index(int resp_type)
+{
+ if (resp_type == SD_RSP_TYPE_R0)
+ return 0;
+ else if (resp_type == SD_RSP_TYPE_R2)
+ return 16;
+
+ return 5;
+}
/*
* sd_pre_dma_transfer - do dma_map_sg() or using cookie
*
@@ -166,123 +220,6 @@ static void sdmmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
data->host_cookie = 0;
}
-static int sd_read_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
- u8 *buf, int buf_len, int timeout)
-{
- struct rtsx_pcr *pcr = host->pcr;
- int err, i;
- u8 trans_mode;
-
- dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD%d\n", __func__, cmd[0] - 0x40);
-
- if (!buf)
- buf_len = 0;
-
- if ((cmd[0] & 0x3F) == MMC_SEND_TUNING_BLOCK)
- trans_mode = SD_TM_AUTO_TUNING;
- else
- trans_mode = SD_TM_NORMAL_READ;
-
- rtsx_pci_init_cmd(pcr);
-
- for (i = 0; i < 5; i++)
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0 + i, 0xFF, cmd[i]);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H,
- 0xFF, (u8)(byte_cnt >> 8));
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF,
- SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
- SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
- if (trans_mode != SD_TM_AUTO_TUNING)
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
- CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER,
- 0xFF, trans_mode | SD_TRANSFER_START);
- rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
- SD_TRANSFER_END, SD_TRANSFER_END);
-
- err = rtsx_pci_send_cmd(pcr, timeout);
- if (err < 0) {
- sd_print_debug_regs(host);
- dev_dbg(sdmmc_dev(host),
- "rtsx_pci_send_cmd fail (err = %d)\n", err);
- return err;
- }
-
- if (buf && buf_len) {
- err = rtsx_pci_read_ppbuf(pcr, buf, buf_len);
- if (err < 0) {
- dev_dbg(sdmmc_dev(host),
- "rtsx_pci_read_ppbuf fail (err = %d)\n", err);
- return err;
- }
- }
-
- return 0;
-}
-
-static int sd_write_data(struct realtek_pci_sdmmc *host, u8 *cmd, u16 byte_cnt,
- u8 *buf, int buf_len, int timeout)
-{
- struct rtsx_pcr *pcr = host->pcr;
- int err, i;
- u8 trans_mode;
-
- if (!buf)
- buf_len = 0;
-
- if (buf && buf_len) {
- err = rtsx_pci_write_ppbuf(pcr, buf, buf_len);
- if (err < 0) {
- dev_dbg(sdmmc_dev(host),
- "rtsx_pci_write_ppbuf fail (err = %d)\n", err);
- return err;
- }
- }
-
- trans_mode = cmd ? SD_TM_AUTO_WRITE_2 : SD_TM_AUTO_WRITE_3;
- rtsx_pci_init_cmd(pcr);
-
- if (cmd) {
- dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d\n", __func__,
- cmd[0] - 0x40);
-
- for (i = 0; i < 5; i++)
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
- SD_CMD0 + i, 0xFF, cmd[i]);
- }
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, (u8)byte_cnt);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H,
- 0xFF, (u8)(byte_cnt >> 8));
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L, 0xFF, 1);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H, 0xFF, 0);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF,
- SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
- SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
- trans_mode | SD_TRANSFER_START);
- rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
- SD_TRANSFER_END, SD_TRANSFER_END);
-
- err = rtsx_pci_send_cmd(pcr, timeout);
- if (err < 0) {
- sd_print_debug_regs(host);
- dev_dbg(sdmmc_dev(host),
- "rtsx_pci_send_cmd fail (err = %d)\n", err);
- return err;
- }
-
- return 0;
-}
-
static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
struct mmc_command *cmd)
{
@@ -293,47 +230,18 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
int timeout = 100;
int i;
u8 *ptr;
- int stat_idx = 0;
- u8 rsp_type;
- int rsp_len = 5;
+ int rsp_type;
+ int stat_idx;
bool clock_toggled = false;
dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
__func__, cmd_idx, arg);
- /* Response type:
- * R0
- * R1, R5, R6, R7
- * R1b
- * R2
- * R3, R4
- */
- switch (mmc_resp_type(cmd)) {
- case MMC_RSP_NONE:
- rsp_type = SD_RSP_TYPE_R0;
- rsp_len = 0;
- break;
- case MMC_RSP_R1:
- rsp_type = SD_RSP_TYPE_R1;
- break;
- case MMC_RSP_R1 & ~MMC_RSP_CRC:
- rsp_type = SD_RSP_TYPE_R1 | SD_NO_CHECK_CRC7;
- break;
- case MMC_RSP_R1B:
- rsp_type = SD_RSP_TYPE_R1b;
- break;
- case MMC_RSP_R2:
- rsp_type = SD_RSP_TYPE_R2;
- rsp_len = 16;
- break;
- case MMC_RSP_R3:
- rsp_type = SD_RSP_TYPE_R3;
- break;
- default:
- dev_dbg(sdmmc_dev(host), "cmd->flag is not valid\n");
- err = -EINVAL;
+ rsp_type = sd_response_type(cmd);
+ if (rsp_type < 0)
goto out;
- }
+
+ stat_idx = sd_status_index(rsp_type);
if (rsp_type == SD_RSP_TYPE_R1b)
timeout = 3000;
@@ -348,13 +256,7 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
}
rtsx_pci_init_cmd(pcr);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD0, 0xFF, 0x40 | cmd_idx);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD1, 0xFF, (u8)(arg >> 24));
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD2, 0xFF, (u8)(arg >> 16));
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD3, 0xFF, (u8)(arg >> 8));
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CMD4, 0xFF, (u8)arg);
-
+ sd_cmd_set_sd_cmd(pcr, cmd);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, rsp_type);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, PINGPONG_BUFFER);
@@ -368,12 +270,10 @@ static void sd_send_cmd_get_rsp(struct realtek_pci_sdmmc *host,
/* Read data from ping-pong buffer */
for (i = PPBUF_BASE2; i < PPBUF_BASE2 + 16; i++)
rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
- stat_idx = 16;
} else if (rsp_type != SD_RSP_TYPE_R0) {
/* Read data from SD_CMDx registers */
for (i = SD_CMD0; i <= SD_CMD4; i++)
rtsx_pci_add_cmd(pcr, READ_REG_CMD, (u16)i, 0, 0);
- stat_idx = 5;
}
rtsx_pci_add_cmd(pcr, READ_REG_CMD, SD_STAT1, 0, 0);
@@ -438,71 +338,213 @@ out:
SD_CLK_TOGGLE_EN | SD_CLK_FORCE_STOP, 0);
}
-static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
+static int sd_read_data(struct realtek_pci_sdmmc *host, struct mmc_command *cmd,
+ u16 byte_cnt, u8 *buf, int buf_len, int timeout)
+{
+ struct rtsx_pcr *pcr = host->pcr;
+ int err;
+ u8 trans_mode;
+
+ dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
+ __func__, cmd->opcode, cmd->arg);
+
+ if (!buf)
+ buf_len = 0;
+
+ if (cmd->opcode == MMC_SEND_TUNING_BLOCK)
+ trans_mode = SD_TM_AUTO_TUNING;
+ else
+ trans_mode = SD_TM_NORMAL_READ;
+
+ rtsx_pci_init_cmd(pcr);
+ sd_cmd_set_sd_cmd(pcr, cmd);
+ sd_cmd_set_data_len(pcr, 1, byte_cnt);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF,
+ SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+ SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_6);
+ if (trans_mode != SD_TM_AUTO_TUNING)
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD,
+ CARD_DATA_SOURCE, 0x01, PINGPONG_BUFFER);
+
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER,
+ 0xFF, trans_mode | SD_TRANSFER_START);
+ rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
+ SD_TRANSFER_END, SD_TRANSFER_END);
+
+ err = rtsx_pci_send_cmd(pcr, timeout);
+ if (err < 0) {
+ sd_print_debug_regs(host);
+ dev_dbg(sdmmc_dev(host),
+ "rtsx_pci_send_cmd fail (err = %d)\n", err);
+ return err;
+ }
+
+ if (buf && buf_len) {
+ err = rtsx_pci_read_ppbuf(pcr, buf, buf_len);
+ if (err < 0) {
+ dev_dbg(sdmmc_dev(host),
+ "rtsx_pci_read_ppbuf fail (err = %d)\n", err);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+static int sd_write_data(struct realtek_pci_sdmmc *host,
+ struct mmc_command *cmd, u16 byte_cnt, u8 *buf, int buf_len,
+ int timeout)
+{
+ struct rtsx_pcr *pcr = host->pcr;
+ int err;
+
+ dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
+ __func__, cmd->opcode, cmd->arg);
+
+ if (!buf)
+ buf_len = 0;
+
+ sd_send_cmd_get_rsp(host, cmd);
+ if (cmd->error)
+ return cmd->error;
+
+ if (buf && buf_len) {
+ err = rtsx_pci_write_ppbuf(pcr, buf, buf_len);
+ if (err < 0) {
+ dev_dbg(sdmmc_dev(host),
+ "rtsx_pci_write_ppbuf fail (err = %d)\n", err);
+ return err;
+ }
+ }
+
+ rtsx_pci_init_cmd(pcr);
+ sd_cmd_set_data_len(pcr, 1, byte_cnt);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF,
+ SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+ SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
+ SD_TRANSFER_START | SD_TM_AUTO_WRITE_3);
+ rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
+ SD_TRANSFER_END, SD_TRANSFER_END);
+
+ err = rtsx_pci_send_cmd(pcr, timeout);
+ if (err < 0) {
+ sd_print_debug_regs(host);
+ dev_dbg(sdmmc_dev(host),
+ "rtsx_pci_send_cmd fail (err = %d)\n", err);
+ return err;
+ }
+
+ return 0;
+}
+
+static int sd_read_long_data(struct realtek_pci_sdmmc *host,
+ struct mmc_request *mrq)
{
struct rtsx_pcr *pcr = host->pcr;
struct mmc_host *mmc = host->mmc;
struct mmc_card *card = mmc->card;
+ struct mmc_command *cmd = mrq->cmd;
struct mmc_data *data = mrq->data;
int uhs = mmc_card_uhs(card);
- int read = (data->flags & MMC_DATA_READ) ? 1 : 0;
- u8 cfg2, trans_mode;
+ u8 cfg2 = 0;
int err;
+ int resp_type;
size_t data_len = data->blksz * data->blocks;
- if (read) {
- cfg2 = SD_CALCULATE_CRC7 | SD_CHECK_CRC16 |
- SD_NO_WAIT_BUSY_END | SD_CHECK_CRC7 | SD_RSP_LEN_0;
- trans_mode = SD_TM_AUTO_READ_3;
- } else {
- cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
- SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
- trans_mode = SD_TM_AUTO_WRITE_3;
- }
+ dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
+ __func__, cmd->opcode, cmd->arg);
+
+ resp_type = sd_response_type(cmd);
+ if (resp_type < 0)
+ return resp_type;
if (!uhs)
cfg2 |= SD_NO_CHECK_WAIT_CRC_TO;
rtsx_pci_init_cmd(pcr);
-
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_L, 0xFF, 0x00);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BYTE_CNT_H, 0xFF, 0x02);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_L,
- 0xFF, (u8)data->blocks);
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_BLOCK_CNT_H,
- 0xFF, (u8)(data->blocks >> 8));
-
+ sd_cmd_set_sd_cmd(pcr, cmd);
+ sd_cmd_set_data_len(pcr, data->blocks, data->blksz);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0,
DMA_DONE_INT, DMA_DONE_INT);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3,
- 0xFF, (u8)(data_len >> 24));
+ 0xFF, (u8)(data_len >> 24));
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2,
- 0xFF, (u8)(data_len >> 16));
+ 0xFF, (u8)(data_len >> 16));
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1,
- 0xFF, (u8)(data_len >> 8));
+ 0xFF, (u8)(data_len >> 8));
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len);
- if (read) {
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL,
- 0x03 | DMA_PACK_SIZE_MASK,
- DMA_DIR_FROM_CARD | DMA_EN | DMA_512);
- } else {
- rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL,
- 0x03 | DMA_PACK_SIZE_MASK,
- DMA_DIR_TO_CARD | DMA_EN | DMA_512);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL,
+ 0x03 | DMA_PACK_SIZE_MASK,
+ DMA_DIR_FROM_CARD | DMA_EN | DMA_512);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
+ 0x01, RING_BUFFER);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2 | resp_type);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
+ SD_TRANSFER_START | SD_TM_AUTO_READ_2);
+ rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
+ SD_TRANSFER_END, SD_TRANSFER_END);
+ rtsx_pci_send_cmd_no_wait(pcr);
+
+ err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, 1, 10000);
+ if (err < 0) {
+ sd_print_debug_regs(host);
+ sd_clear_error(host);
+ return err;
}
+ return 0;
+}
+
+static int sd_write_long_data(struct realtek_pci_sdmmc *host,
+ struct mmc_request *mrq)
+{
+ struct rtsx_pcr *pcr = host->pcr;
+ struct mmc_host *mmc = host->mmc;
+ struct mmc_card *card = mmc->card;
+ struct mmc_command *cmd = mrq->cmd;
+ struct mmc_data *data = mrq->data;
+ int uhs = mmc_card_uhs(card);
+ u8 cfg2;
+ int err;
+ size_t data_len = data->blksz * data->blocks;
+
+ sd_send_cmd_get_rsp(host, cmd);
+ if (cmd->error)
+ return cmd->error;
+
+ dev_dbg(sdmmc_dev(host), "%s: SD/MMC CMD %d, arg = 0x%08x\n",
+ __func__, cmd->opcode, cmd->arg);
+
+ cfg2 = SD_NO_CALCULATE_CRC7 | SD_CHECK_CRC16 |
+ SD_NO_WAIT_BUSY_END | SD_NO_CHECK_CRC7 | SD_RSP_LEN_0;
+
+ if (!uhs)
+ cfg2 |= SD_NO_CHECK_WAIT_CRC_TO;
+
+ rtsx_pci_init_cmd(pcr);
+ sd_cmd_set_data_len(pcr, data->blocks, data->blksz);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, IRQSTAT0,
+ DMA_DONE_INT, DMA_DONE_INT);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC3,
+ 0xFF, (u8)(data_len >> 24));
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC2,
+ 0xFF, (u8)(data_len >> 16));
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC1,
+ 0xFF, (u8)(data_len >> 8));
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMATC0, 0xFF, (u8)data_len);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, DMACTL,
+ 0x03 | DMA_PACK_SIZE_MASK,
+ DMA_DIR_TO_CARD | DMA_EN | DMA_512);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, CARD_DATA_SOURCE,
0x01, RING_BUFFER);
-
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_CFG2, 0xFF, cfg2);
rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, SD_TRANSFER, 0xFF,
- trans_mode | SD_TRANSFER_START);
+ SD_TRANSFER_START | SD_TM_AUTO_WRITE_3);
rtsx_pci_add_cmd(pcr, CHECK_REG_CMD, SD_TRANSFER,
SD_TRANSFER_END, SD_TRANSFER_END);
-
rtsx_pci_send_cmd_no_wait(pcr);
-
- err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, read, 10000);
+ err = rtsx_pci_dma_transfer(pcr, data->sg, host->sg_count, 0, 10000);
if (err < 0) {
sd_clear_error(host);
return err;
@@ -511,6 +553,23 @@ static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
return 0;
}
+static int sd_rw_multi(struct realtek_pci_sdmmc *host, struct mmc_request *mrq)
+{
+ struct mmc_data *data = mrq->data;
+
+ if (host->sg_count < 0) {
+ data->error = host->sg_count;
+ dev_dbg(sdmmc_dev(host), "%s: sg_count = %d is invalid\n",
+ __func__, host->sg_count);
+ return data->error;
+ }
+
+ if (data->flags & MMC_DATA_READ)
+ return sd_read_long_data(host, mrq);
+
+ return sd_write_long_data(host, mrq);
+}
+
static inline void sd_enable_initial_mode(struct realtek_pci_sdmmc *host)
{
rtsx_pci_write_register(host->pcr, SD_CFG1,
@@ -528,10 +587,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host,
{
struct mmc_command *cmd = mrq->cmd;
struct mmc_data *data = mrq->data;
- u8 _cmd[5], *buf;
-
- _cmd[0] = 0x40 | (u8)cmd->opcode;
- put_unaligned_be32(cmd->arg, (u32 *)(&_cmd[1]));
+ u8 *buf;
buf = kzalloc(data->blksz, GFP_NOIO);
if (!buf) {
@@ -543,7 +599,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host,
if (host->initial_mode)
sd_disable_initial_mode(host);
- cmd->error = sd_read_data(host, _cmd, (u16)data->blksz, buf,
+ cmd->error = sd_read_data(host, cmd, (u16)data->blksz, buf,
data->blksz, 200);
if (host->initial_mode)
@@ -553,7 +609,7 @@ static void sd_normal_rw(struct realtek_pci_sdmmc *host,
} else {
sg_copy_to_buffer(data->sg, data->sg_len, buf, data->blksz);
- cmd->error = sd_write_data(host, _cmd, (u16)data->blksz, buf,
+ cmd->error = sd_write_data(host, cmd, (u16)data->blksz, buf,
data->blksz, 200);
}
@@ -653,14 +709,14 @@ static int sd_tuning_rx_cmd(struct realtek_pci_sdmmc *host,
u8 opcode, u8 sample_point)
{
int err;
- u8 cmd[5] = {0};
+ struct mmc_command cmd = {0};
err = sd_change_phase(host, sample_point, true);
if (err < 0)
return err;
- cmd[0] = 0x40 | opcode;
- err = sd_read_data(host, cmd, 0x40, NULL, 0, 100);
+ cmd.opcode = opcode;
+ err = sd_read_data(host, &cmd, 0x40, NULL, 0, 100);
if (err < 0) {
/* Wait till SD DATA IDLE */
sd_wait_data_idle(host);
@@ -727,6 +783,12 @@ static int sd_tuning_rx(struct realtek_pci_sdmmc *host, u8 opcode)
return 0;
}
+static inline int sdio_extblock_cmd(struct mmc_command *cmd,
+ struct mmc_data *data)
+{
+ return (cmd->opcode == SD_IO_RW_EXTENDED) && (data->blksz == 512);
+}
+
static inline int sd_rw_cmd(struct mmc_command *cmd)
{
return mmc_op_multi(cmd->opcode) ||
@@ -748,7 +810,7 @@ static void sd_request(struct work_struct *work)
unsigned int data_size = 0;
int err;
- if (host->eject) {
+ if (host->eject || !sd_get_cd_int(host)) {
cmd->error = -ENOMEDIUM;
goto finish;
}
@@ -776,17 +838,15 @@ static void sd_request(struct work_struct *work)
if (mrq->data)
data_size = data->blocks * data->blksz;
- if (!data_size || sd_rw_cmd(cmd)) {
+ if (!data_size) {
sd_send_cmd_get_rsp(host, cmd);
+ } else if (sd_rw_cmd(cmd) || sdio_extblock_cmd(cmd, data)) {
+ cmd->error = sd_rw_multi(host, mrq);
+ if (!host->using_cookie)
+ sdmmc_post_req(host->mmc, host->mrq, 0);
- if (!cmd->error && data_size) {
- sd_rw_multi(host, mrq);
- if (!host->using_cookie)
- sdmmc_post_req(host->mmc, host->mrq, 0);
-
- if (mmc_op_multi(cmd->opcode) && mrq->stop)
- sd_send_cmd_get_rsp(host, mrq->stop);
- }
+ if (mmc_op_multi(cmd->opcode) && mrq->stop)
+ sd_send_cmd_get_rsp(host, mrq->stop);
} else {
sd_normal_rw(host, mrq);
}
@@ -801,8 +861,10 @@ static void sd_request(struct work_struct *work)
mutex_unlock(&pcr->pcr_mutex);
finish:
- if (cmd->error)
- dev_dbg(sdmmc_dev(host), "cmd->error = %d\n", cmd->error);
+ if (cmd->error) {
+ dev_dbg(sdmmc_dev(host), "CMD %d 0x%08x error(%d)\n",
+ cmd->opcode, cmd->arg, cmd->error);
+ }
mutex_lock(&host->host_mutex);
host->mrq = NULL;
@@ -820,7 +882,7 @@ static void sdmmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
host->mrq = mrq;
mutex_unlock(&host->host_mutex);
- if (sd_rw_cmd(mrq->cmd))
+ if (sd_rw_cmd(mrq->cmd) || sdio_extblock_cmd(mrq->cmd, data))
host->using_cookie = sd_pre_dma_transfer(host, data, false);
queue_work(host->workq, &host->work);
@@ -1066,7 +1128,7 @@ static int sdmmc_get_cd(struct mmc_host *mmc)
u32 val;
if (host->eject)
- return -ENOMEDIUM;
+ return cd;
mutex_lock(&pcr->pcr_mutex);
@@ -1317,6 +1379,7 @@ static void rtsx_pci_sdmmc_card_event(struct platform_device *pdev)
{
struct realtek_pci_sdmmc *host = platform_get_drvdata(pdev);
+ host->cookie = -1;
mmc_detect_change(host->mmc, 0);
}
@@ -1349,6 +1412,7 @@ static int rtsx_pci_sdmmc_drv_probe(struct platform_device *pdev)
host->pcr = pcr;
host->mmc = mmc;
host->pdev = pdev;
+ host->cookie = -1;
host->power_state = SDMMC_POWER_OFF;
INIT_WORK(&host->work, sd_request);
platform_set_drvdata(pdev, host);
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 970314e0aac8..a45ed39d062c 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -158,7 +158,7 @@ static int sdhci_acpi_emmc_probe_slot(struct platform_device *pdev,
host = c->host;
- /* Platform specific code during emmc proble slot goes here */
+ /* Platform specific code during emmc probe slot goes here */
if (hid && uid && !strcmp(hid, "80860F14") && !strcmp(uid, "1") &&
sdhci_readl(host, SDHCI_CAPABILITIES) == 0x446cc8b2 &&
@@ -179,7 +179,7 @@ static int sdhci_acpi_sdio_probe_slot(struct platform_device *pdev,
host = c->host;
- /* Platform specific code during emmc proble slot goes here */
+ /* Platform specific code during sdio probe slot goes here */
return 0;
}
@@ -195,7 +195,7 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
host = c->host;
- /* Platform specific code during emmc proble slot goes here */
+ /* Platform specific code during sd probe slot goes here */
return 0;
}
@@ -448,18 +448,13 @@ static int sdhci_acpi_runtime_resume(struct device *dev)
return sdhci_runtime_resume_host(c->host);
}
-static int sdhci_acpi_runtime_idle(struct device *dev)
-{
- return 0;
-}
-
#endif
static const struct dev_pm_ops sdhci_acpi_pm_ops = {
.suspend = sdhci_acpi_suspend,
.resume = sdhci_acpi_resume,
SET_RUNTIME_PM_OPS(sdhci_acpi_runtime_suspend,
- sdhci_acpi_runtime_resume, sdhci_acpi_runtime_idle)
+ sdhci_acpi_runtime_resume, NULL)
};
static struct platform_driver sdhci_acpi_driver = {
diff --git a/drivers/mmc/host/sdhci-bcm-kona.c b/drivers/mmc/host/sdhci-bcm-kona.c
index e7e4fbdcbfe0..34bb8f92586e 100644
--- a/drivers/mmc/host/sdhci-bcm-kona.c
+++ b/drivers/mmc/host/sdhci-bcm-kona.c
@@ -254,7 +254,9 @@ static int sdhci_bcm_kona_probe(struct platform_device *pdev)
kona_dev = sdhci_pltfm_priv(pltfm_priv);
mutex_init(&kona_dev->write_lock);
- mmc_of_parse(host->mmc);
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto err_pltfm_free;
if (!host->mmc->f_max) {
dev_err(&pdev->dev, "Missing max-freq for SDHCI cfg\n");
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index af1f7c0f9545..10ef8244a239 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -1080,10 +1080,10 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
goto disable_clk;
pm_runtime_set_active(&pdev->dev);
- pm_runtime_enable(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, 50);
pm_runtime_use_autosuspend(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
+ pm_runtime_enable(&pdev->dev);
return 0;
@@ -1103,16 +1103,15 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
struct pltfm_imx_data *imx_data = pltfm_host->priv;
int dead = (readl(host->ioaddr + SDHCI_INT_STATUS) == 0xffffffff);
- sdhci_remove_host(host, dead);
-
- pm_runtime_dont_use_autosuspend(&pdev->dev);
+ pm_runtime_get_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
- 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);
- }
+ sdhci_remove_host(host, dead);
+
+ clk_disable_unprepare(imx_data->clk_per);
+ clk_disable_unprepare(imx_data->clk_ipg);
+ clk_disable_unprepare(imx_data->clk_ahb);
sdhci_pltfm_free(pdev);
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index 8872c85c63d4..17fe02ed6672 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -276,6 +276,14 @@ static void esdhc_pltfm_set_bus_width(struct sdhci_host *host, int width)
ESDHC_CTRL_BUSWIDTH_MASK, ctrl);
}
+static void esdhc_reset(struct sdhci_host *host, u8 mask)
+{
+ sdhci_reset(host, mask);
+
+ sdhci_writel(host, host->ier, SDHCI_INT_ENABLE);
+ sdhci_writel(host, host->ier, SDHCI_SIGNAL_ENABLE);
+}
+
static const struct sdhci_ops sdhci_esdhc_ops = {
.read_l = esdhc_readl,
.read_w = esdhc_readw,
@@ -290,7 +298,7 @@ static const struct sdhci_ops sdhci_esdhc_ops = {
.platform_init = esdhc_of_platform_init,
.adma_workaround = esdhci_of_adma_workaround,
.set_bus_width = esdhc_pltfm_set_bus_width,
- .reset = sdhci_reset,
+ .reset = esdhc_reset,
.set_uhs_signaling = sdhci_set_uhs_signaling,
};
@@ -362,13 +370,19 @@ static int sdhci_esdhc_probe(struct platform_device *pdev)
}
/* call to generic mmc_of_parse to support additional capabilities */
- mmc_of_parse(host->mmc);
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto err;
+
mmc_of_parse_voltage(np, &host->ocr_mask);
ret = sdhci_add_host(host);
if (ret)
- sdhci_pltfm_free(pdev);
+ goto err;
+ return 0;
+ err:
+ sdhci_pltfm_free(pdev);
return ret;
}
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 4f38554ce679..29eaff78238e 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -1367,11 +1367,6 @@ static int sdhci_pci_runtime_resume(struct device *dev)
return 0;
}
-static int sdhci_pci_runtime_idle(struct device *dev)
-{
- return 0;
-}
-
#else /* CONFIG_PM */
#define sdhci_pci_suspend NULL
@@ -1383,7 +1378,7 @@ static const struct dev_pm_ops sdhci_pci_pm_ops = {
.suspend = sdhci_pci_suspend,
.resume = sdhci_pci_resume,
SET_RUNTIME_PM_OPS(sdhci_pci_runtime_suspend,
- sdhci_pci_runtime_resume, sdhci_pci_runtime_idle)
+ sdhci_pci_runtime_resume, NULL)
};
/*****************************************************************************\
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index ca3424e7ef71..b5103a247bc1 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -62,6 +62,7 @@ struct sdhci_pxa {
struct clk *clk_core;
struct clk *clk_io;
u8 power_mode;
+ void __iomem *sdio3_conf_reg;
};
/*
@@ -72,6 +73,14 @@ struct sdhci_pxa {
#define SDHCI_WINDOW_BASE(i) (0x84 + ((i) << 3))
#define SDHCI_MAX_WIN_NUM 8
+/*
+ * Fields below belong to SDIO3 Configuration Register (third register
+ * region for the Armada 38x flavor)
+ */
+
+#define SDIO3_CONF_CLK_INV BIT(0)
+#define SDIO3_CONF_SD_FB_CLK BIT(2)
+
static int mv_conf_mbus_windows(struct platform_device *pdev,
const struct mbus_dram_target_info *dram)
{
@@ -118,6 +127,51 @@ static int mv_conf_mbus_windows(struct platform_device *pdev,
return 0;
}
+static int armada_38x_quirks(struct platform_device *pdev,
+ struct sdhci_host *host)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_pxa *pxa = pltfm_host->priv;
+ struct resource *res;
+
+ host->quirks |= SDHCI_QUIRK_MISSING_CAPS;
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "conf-sdio3");
+ if (res) {
+ pxa->sdio3_conf_reg = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pxa->sdio3_conf_reg))
+ return PTR_ERR(pxa->sdio3_conf_reg);
+ } else {
+ /*
+ * According to erratum 'FE-2946959' both SDR50 and DDR50
+ * modes require specific clock adjustments in SDIO3
+ * Configuration register, if the adjustment is not done,
+ * remove them from the capabilities.
+ */
+ host->caps1 = sdhci_readl(host, SDHCI_CAPABILITIES_1);
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR50 | SDHCI_SUPPORT_DDR50);
+
+ dev_warn(&pdev->dev, "conf-sdio3 register not found: disabling SDR50 and DDR50 modes.\nConsider updating your dtb\n");
+ }
+
+ /*
+ * According to erratum 'ERR-7878951' Armada 38x SDHCI
+ * controller has different capabilities than the ones shown
+ * in its registers
+ */
+ host->caps = sdhci_readl(host, SDHCI_CAPABILITIES);
+ if (of_property_read_bool(np, "no-1-8-v")) {
+ host->caps &= ~SDHCI_CAN_VDD_180;
+ host->mmc->caps &= ~MMC_CAP_1_8V_DDR;
+ } else {
+ host->caps &= ~SDHCI_CAN_VDD_330;
+ }
+ host->caps1 &= ~(SDHCI_SUPPORT_SDR104 | SDHCI_USE_SDR50_TUNING);
+
+ return 0;
+}
+
static void pxav3_reset(struct sdhci_host *host, u8 mask)
{
struct platform_device *pdev = to_platform_device(mmc_dev(host->mmc));
@@ -194,6 +248,8 @@ static void pxav3_gen_init_74_clocks(struct sdhci_host *host, u8 power_mode)
static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_pxa *pxa = pltfm_host->priv;
u16 ctrl_2;
/*
@@ -223,6 +279,24 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
break;
}
+ /*
+ * Update SDIO3 Configuration register according to erratum
+ * FE-2946959
+ */
+ if (pxa->sdio3_conf_reg) {
+ u8 reg_val = readb(pxa->sdio3_conf_reg);
+
+ if (uhs == MMC_TIMING_UHS_SDR50 ||
+ uhs == MMC_TIMING_UHS_DDR50) {
+ reg_val &= ~SDIO3_CONF_CLK_INV;
+ reg_val |= SDIO3_CONF_SD_FB_CLK;
+ } else {
+ reg_val |= SDIO3_CONF_CLK_INV;
+ reg_val &= ~SDIO3_CONF_SD_FB_CLK;
+ }
+ writeb(reg_val, pxa->sdio3_conf_reg);
+ }
+
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
dev_dbg(mmc_dev(host->mmc),
"%s uhs = %d, ctrl_2 = %04X\n",
@@ -268,8 +342,8 @@ static struct sdhci_pxa_platdata *pxav3_get_mmc_pdata(struct device *dev)
if (!pdata)
return NULL;
- of_property_read_u32(np, "mrvl,clk-delay-cycles", &clk_delay_cycles);
- if (clk_delay_cycles > 0)
+ if (!of_property_read_u32(np, "mrvl,clk-delay-cycles",
+ &clk_delay_cycles))
pdata->clk_delay_cycles = clk_delay_cycles;
return pdata;
@@ -318,15 +392,18 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
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;
+
if (of_device_is_compatible(np, "marvell,armada-380-sdhci")) {
+ ret = armada_38x_quirks(pdev, host);
+ if (ret < 0)
+ goto err_clk_get;
ret = mv_conf_mbus_windows(pdev, mv_mbus_dram_info());
if (ret < 0)
goto err_mbus_win;
}
- /* enable 1/8V DDR capable */
- host->mmc->caps |= MMC_CAP_1_8V_DDR;
-
match = of_match_device(of_match_ptr(sdhci_pxav3_of_match), &pdev->dev);
if (match) {
ret = mmc_of_parse(host->mmc);
@@ -365,10 +442,11 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
}
}
- pm_runtime_enable(&pdev->dev);
- pm_runtime_get_sync(&pdev->dev);
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
pm_runtime_set_autosuspend_delay(&pdev->dev, PXAV3_RPM_DELAY_MS);
pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
ret = sdhci_add_host(host);
@@ -391,14 +469,13 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
return 0;
err_add_host:
- pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
err_of_parse:
err_cd_req:
err_mbus_win:
clk_disable_unprepare(pxa->clk_io);
- if (!IS_ERR(pxa->clk_core))
- clk_disable_unprepare(pxa->clk_core);
+ clk_disable_unprepare(pxa->clk_core);
err_clk_get:
sdhci_pltfm_free(pdev);
return ret;
@@ -411,12 +488,13 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
struct sdhci_pxa *pxa = pltfm_host->priv;
pm_runtime_get_sync(&pdev->dev);
- sdhci_remove_host(host, 1);
pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
+ sdhci_remove_host(host, 1);
clk_disable_unprepare(pxa->clk_io);
- if (!IS_ERR(pxa->clk_core))
- clk_disable_unprepare(pxa->clk_core);
+ clk_disable_unprepare(pxa->clk_core);
sdhci_pltfm_free(pdev);
@@ -457,11 +535,11 @@ 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;
+ int ret;
- spin_lock_irqsave(&host->lock, flags);
- host->runtime_suspended = true;
- spin_unlock_irqrestore(&host->lock, flags);
+ ret = sdhci_runtime_suspend_host(host);
+ if (ret)
+ return ret;
clk_disable_unprepare(pxa->clk_io);
if (!IS_ERR(pxa->clk_core))
@@ -475,17 +553,12 @@ 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;
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);
-
- return 0;
+ return sdhci_runtime_resume_host(host);
}
#endif
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index c45b8932d843..c6d2dd7317c1 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -12,6 +12,7 @@
* published by the Free Software Foundation.
*/
+#include <linux/spinlock.h>
#include <linux/delay.h>
#include <linux/dma-mapping.h>
#include <linux/platform_device.h>
@@ -312,7 +313,14 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_s3c_set_clock(host, clock);
+ /* Reset SD Clock Enable */
+ clk = sdhci_readw(host, SDHCI_CLOCK_CONTROL);
+ clk &= ~SDHCI_CLOCK_CARD_EN;
+ sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
+
+ spin_unlock_irq(&host->lock);
ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
+ spin_lock_irq(&host->lock);
if (ret != 0) {
dev_err(dev, "%s: failed to set clock rate %uHz\n",
mmc_hostname(host->mmc), clock);
@@ -607,7 +615,9 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
pm_runtime_use_autosuspend(&pdev->dev);
pm_suspend_ignore_children(&pdev->dev, 1);
- mmc_of_parse(host->mmc);
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto err_req_regs;
ret = sdhci_add_host(host);
if (ret) {
diff --git a/drivers/mmc/host/sdhci-sirf.c b/drivers/mmc/host/sdhci-sirf.c
index dd29d47c07aa..f6f82ec3618d 100644
--- a/drivers/mmc/host/sdhci-sirf.c
+++ b/drivers/mmc/host/sdhci-sirf.c
@@ -15,7 +15,9 @@
#include <linux/mmc/slot-gpio.h>
#include "sdhci-pltfm.h"
+#define SDHCI_CLK_DELAY_SETTING 0x4C
#define SDHCI_SIRF_8BITBUS BIT(3)
+#define SIRF_TUNING_COUNT 128
struct sdhci_sirf_priv {
struct clk *clk;
@@ -49,7 +51,76 @@ static void sdhci_sirf_set_bus_width(struct sdhci_host *host, int width)
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
+static int sdhci_sirf_execute_tuning(struct sdhci_host *host, u32 opcode)
+{
+ int tuning_seq_cnt = 3;
+ u8 phase, tuned_phases[SIRF_TUNING_COUNT];
+ u8 tuned_phase_cnt = 0;
+ int rc, longest_range = 0;
+ int start = -1, end = 0, tuning_value = -1, range = 0;
+ u16 clock_setting;
+ struct mmc_host *mmc = host->mmc;
+
+ clock_setting = sdhci_readw(host, SDHCI_CLK_DELAY_SETTING);
+ clock_setting &= ~0x3fff;
+
+retry:
+ phase = 0;
+ do {
+ sdhci_writel(host,
+ clock_setting | phase | (phase << 7) | (phase << 16),
+ SDHCI_CLK_DELAY_SETTING);
+
+ if (!mmc_send_tuning(mmc)) {
+ /* Tuning is successful at this tuning point */
+ tuned_phases[tuned_phase_cnt++] = phase;
+ dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
+ mmc_hostname(mmc), phase);
+ if (start == -1)
+ start = phase;
+ end = phase;
+ range++;
+ if (phase == (SIRF_TUNING_COUNT - 1)
+ && range > longest_range)
+ tuning_value = (start + end) / 2;
+ } else {
+ dev_dbg(mmc_dev(mmc), "%s: Found bad phase = %d\n",
+ mmc_hostname(mmc), phase);
+ if (range > longest_range) {
+ tuning_value = (start + end) / 2;
+ longest_range = range;
+ }
+ start = -1;
+ end = range = 0;
+ }
+ } while (++phase < ARRAY_SIZE(tuned_phases));
+
+ if (tuned_phase_cnt && tuning_value > 0) {
+ /*
+ * Finally set the selected phase in delay
+ * line hw block.
+ */
+ phase = tuning_value;
+ sdhci_writel(host,
+ clock_setting | phase | (phase << 7) | (phase << 16),
+ SDHCI_CLK_DELAY_SETTING);
+
+ dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
+ mmc_hostname(mmc), phase);
+ } else {
+ if (--tuning_seq_cnt)
+ goto retry;
+ /* Tuning failed */
+ dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
+ mmc_hostname(mmc));
+ rc = -EIO;
+ }
+
+ return rc;
+}
+
static struct sdhci_ops sdhci_sirf_ops = {
+ .platform_execute_tuning = sdhci_sirf_execute_tuning,
.set_clock = sdhci_set_clock,
.get_max_clock = sdhci_sirf_get_max_clk,
.set_bus_width = sdhci_sirf_set_bus_width,
@@ -138,9 +209,6 @@ static int sdhci_sirf_remove(struct platform_device *pdev)
sdhci_pltfm_unregister(pdev);
- if (gpio_is_valid(priv->gpio_cd))
- mmc_gpio_free_cd(host->mmc);
-
clk_disable_unprepare(priv->clk);
return 0;
}
diff --git a/drivers/mmc/host/sdhci-st.c b/drivers/mmc/host/sdhci-st.c
index 328f348c7243..882b07e9667e 100644
--- a/drivers/mmc/host/sdhci-st.c
+++ b/drivers/mmc/host/sdhci-st.c
@@ -78,10 +78,9 @@ static int sdhci_st_probe(struct platform_device *pdev)
}
ret = mmc_of_parse(host->mmc);
-
if (ret) {
dev_err(&pdev->dev, "Failed mmc_of_parse\n");
- return ret;
+ goto err_of;
}
clk_prepare_enable(clk);
@@ -108,6 +107,7 @@ static int sdhci_st_probe(struct platform_device *pdev)
err_out:
clk_disable_unprepare(clk);
+err_of:
sdhci_pltfm_free(pdev);
return ret;
diff --git a/drivers/mmc/host/sdhci-tegra.c b/drivers/mmc/host/sdhci-tegra.c
index 59797106af93..f3778d58d1cd 100644
--- a/drivers/mmc/host/sdhci-tegra.c
+++ b/drivers/mmc/host/sdhci-tegra.c
@@ -41,6 +41,7 @@
#define NVQUIRK_DISABLE_SDR50 BIT(3)
#define NVQUIRK_DISABLE_SDR104 BIT(4)
#define NVQUIRK_DISABLE_DDR50 BIT(5)
+#define NVQUIRK_SHADOW_XFER_MODE_REG BIT(6)
struct sdhci_tegra_soc_data {
const struct sdhci_pltfm_data *pdata;
@@ -67,6 +68,31 @@ static u16 tegra_sdhci_readw(struct sdhci_host *host, int reg)
return readw(host->ioaddr + reg);
}
+static void tegra_sdhci_writew(struct sdhci_host *host, u16 val, int reg)
+{
+ struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_tegra *tegra_host = pltfm_host->priv;
+ const struct sdhci_tegra_soc_data *soc_data = tegra_host->soc_data;
+
+ if (soc_data->nvquirks & NVQUIRK_SHADOW_XFER_MODE_REG) {
+ switch (reg) {
+ case SDHCI_TRANSFER_MODE:
+ /*
+ * Postpone this write, we must do it together with a
+ * command write that is down below.
+ */
+ pltfm_host->xfer_mode_shadow = val;
+ return;
+ case SDHCI_COMMAND:
+ writel((val << 16) | pltfm_host->xfer_mode_shadow,
+ host->ioaddr + SDHCI_TRANSFER_MODE);
+ return;
+ }
+ }
+
+ writew(val, host->ioaddr + reg);
+}
+
static void tegra_sdhci_writel(struct sdhci_host *host, u32 val, int reg)
{
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
@@ -147,6 +173,7 @@ static void tegra_sdhci_set_bus_width(struct sdhci_host *host, int bus_width)
static const struct sdhci_ops tegra_sdhci_ops = {
.get_ro = tegra_sdhci_get_ro,
.read_w = tegra_sdhci_readw,
+ .write_w = tegra_sdhci_writew,
.write_l = tegra_sdhci_writel,
.set_clock = sdhci_set_clock,
.set_bus_width = tegra_sdhci_set_bus_width,
@@ -201,7 +228,8 @@ static struct sdhci_tegra_soc_data soc_data_tegra114 = {
.pdata = &sdhci_tegra114_pdata,
.nvquirks = NVQUIRK_DISABLE_SDR50 |
NVQUIRK_DISABLE_DDR50 |
- NVQUIRK_DISABLE_SDR104,
+ NVQUIRK_DISABLE_SDR104 |
+ NVQUIRK_SHADOW_XFER_MODE_REG,
};
static const struct of_device_id sdhci_tegra_dt_match[] = {
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index f1a488ee432f..0ad412a4876f 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -53,6 +53,9 @@ static void sdhci_finish_command(struct sdhci_host *);
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);
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+ struct mmc_data *data,
+ struct sdhci_host_next *next);
#ifdef CONFIG_PM
static int sdhci_runtime_pm_get(struct sdhci_host *host);
@@ -505,9 +508,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
goto fail;
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)
+ host->sg_count = sdhci_pre_dma_transfer(host, data, NULL);
+ if (host->sg_count < 0)
goto unmap_align;
desc = host->adma_table;
@@ -531,8 +533,6 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
- (PAGE_SIZE - offset));
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
}
@@ -639,8 +639,6 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
(sg_dma_address(sg) & host->align_mask);
buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
- (PAGE_SIZE - size));
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
@@ -649,8 +647,9 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
}
}
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, direction);
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len, direction);
}
static u8 sdhci_calc_timeout(struct sdhci_host *host, struct mmc_command *cmd)
@@ -846,11 +845,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} else {
int sg_cnt;
- sg_cnt = dma_map_sg(mmc_dev(host->mmc),
- data->sg, data->sg_len,
- (data->flags & MMC_DATA_READ) ?
- DMA_FROM_DEVICE :
- DMA_TO_DEVICE);
+ sg_cnt = sdhci_pre_dma_transfer(host, data, NULL);
if (sg_cnt == 0) {
/*
* This only happens when someone fed
@@ -909,7 +904,7 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
static void sdhci_set_transfer_mode(struct sdhci_host *host,
struct mmc_command *cmd)
{
- u16 mode;
+ u16 mode = 0;
struct mmc_data *data = cmd->data;
if (data == NULL) {
@@ -927,9 +922,11 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
WARN_ON(!host->data);
- mode = SDHCI_TRNS_BLK_CNT_EN;
+ if (!(host->quirks2 & SDHCI_QUIRK2_SUPPORT_SINGLE))
+ mode = SDHCI_TRNS_BLK_CNT_EN;
+
if (mmc_op_multi(cmd->opcode) || data->blocks > 1) {
- mode |= SDHCI_TRNS_MULTI;
+ mode = SDHCI_TRNS_BLK_CNT_EN | SDHCI_TRNS_MULTI;
/*
* If we are sending CMD23, CMD12 never gets sent
* on successful completion (so no Auto-CMD12).
@@ -963,8 +960,10 @@ static void sdhci_finish_data(struct sdhci_host *host)
if (host->flags & SDHCI_USE_ADMA)
sdhci_adma_table_post(host, data);
else {
- dma_unmap_sg(mmc_dev(host->mmc), data->sg,
- data->sg_len, (data->flags & MMC_DATA_READ) ?
+ if (!data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc),
+ data->sg, data->sg_len,
+ (data->flags & MMC_DATA_READ) ?
DMA_FROM_DEVICE : DMA_TO_DEVICE);
}
}
@@ -1630,7 +1629,7 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
* signalling timeout and CRC errors even on CMD0. Resetting
* it on each ios seems to solve the problem.
*/
- if(host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
+ if (host->quirks & SDHCI_QUIRK_RESET_CMD_DATA_ON_IOS)
sdhci_do_reset(host, SDHCI_RESET_CMD | SDHCI_RESET_DATA);
mmiowb();
@@ -1832,6 +1831,10 @@ static int sdhci_do_start_signal_voltage_switch(struct sdhci_host *host,
ctrl |= SDHCI_CTRL_VDD_180;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
+ /* Some controller need to do more when switching */
+ if (host->ops->voltage_switch)
+ host->ops->voltage_switch(host);
+
/* 1.8V regulator output should be stable within 5 ms */
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
if (ctrl & SDHCI_CTRL_VDD_180)
@@ -1960,6 +1963,8 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
ctrl = sdhci_readw(host, SDHCI_HOST_CONTROL2);
ctrl |= SDHCI_CTRL_EXEC_TUNING;
+ if (host->quirks2 & SDHCI_QUIRK2_TUNING_WORK_AROUND)
+ ctrl |= SDHCI_CTRL_TUNED_CLK;
sdhci_writew(host, ctrl, SDHCI_HOST_CONTROL2);
/*
@@ -2129,6 +2134,77 @@ static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable)
}
}
+static void sdhci_post_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ int err)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+ struct mmc_data *data = mrq->data;
+
+ if (host->flags & SDHCI_REQ_USE_DMA) {
+ if (data->host_cookie)
+ dma_unmap_sg(mmc_dev(host->mmc), data->sg, data->sg_len,
+ data->flags & MMC_DATA_WRITE ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+ mrq->data->host_cookie = 0;
+ }
+}
+
+static int sdhci_pre_dma_transfer(struct sdhci_host *host,
+ struct mmc_data *data,
+ struct sdhci_host_next *next)
+{
+ int sg_count;
+
+ if (!next && data->host_cookie &&
+ data->host_cookie != host->next_data.cookie) {
+ pr_debug(DRIVER_NAME "[%s] invalid cookie: %d, next-cookie %d\n",
+ __func__, data->host_cookie, host->next_data.cookie);
+ data->host_cookie = 0;
+ }
+
+ /* Check if next job is already prepared */
+ if (next ||
+ (!next && data->host_cookie != host->next_data.cookie)) {
+ sg_count = dma_map_sg(mmc_dev(host->mmc), data->sg,
+ data->sg_len,
+ data->flags & MMC_DATA_WRITE ?
+ DMA_TO_DEVICE : DMA_FROM_DEVICE);
+
+ } else {
+ sg_count = host->next_data.sg_count;
+ host->next_data.sg_count = 0;
+ }
+
+
+ if (sg_count == 0)
+ return -EINVAL;
+
+ if (next) {
+ next->sg_count = sg_count;
+ data->host_cookie = ++next->cookie < 0 ? 1 : next->cookie;
+ } else
+ host->sg_count = sg_count;
+
+ return sg_count;
+}
+
+static void sdhci_pre_req(struct mmc_host *mmc, struct mmc_request *mrq,
+ bool is_first_req)
+{
+ struct sdhci_host *host = mmc_priv(mmc);
+
+ if (mrq->data->host_cookie) {
+ mrq->data->host_cookie = 0;
+ return;
+ }
+
+ if (host->flags & SDHCI_REQ_USE_DMA)
+ if (sdhci_pre_dma_transfer(host,
+ mrq->data,
+ &host->next_data) < 0)
+ mrq->data->host_cookie = 0;
+}
+
static void sdhci_card_event(struct mmc_host *mmc)
{
struct sdhci_host *host = mmc_priv(mmc);
@@ -2162,6 +2238,8 @@ static void sdhci_card_event(struct mmc_host *mmc)
static const struct mmc_host_ops sdhci_ops = {
.request = sdhci_request,
+ .post_req = sdhci_post_req,
+ .pre_req = sdhci_pre_req,
.set_ios = sdhci_set_ios,
.get_cd = sdhci_get_cd,
.get_ro = sdhci_get_ro,
@@ -2793,9 +2871,9 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
/* Force clock and power re-program */
host->pwr = 0;
host->clock = 0;
+ sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
sdhci_do_set_ios(host, &host->mmc->ios);
- sdhci_do_start_signal_voltage_switch(host, &host->mmc->ios);
if ((host_flags & SDHCI_PV_ENABLED) &&
!(host->quirks2 & SDHCI_QUIRK2_PRESET_VALUE_BROKEN)) {
spin_lock_irqsave(&host->lock, flags);
@@ -3019,6 +3097,7 @@ int sdhci_add_host(struct sdhci_host *host)
host->max_clk = host->ops->get_max_clock(host);
}
+ host->next_data.cookie = 1;
/*
* In case of Host Controller v3.00, find out whether clock
* multiplier is supported.
@@ -3338,9 +3417,9 @@ int sdhci_add_host(struct sdhci_host *host)
setup_timer(&host->timer, sdhci_timeout_timer, (unsigned long)host);
- if (host->version >= SDHCI_SPEC_300) {
- init_waitqueue_head(&host->buf_ready_int);
+ init_waitqueue_head(&host->buf_ready_int);
+ if (host->version >= SDHCI_SPEC_300) {
/* Initialize re-tuning timer */
init_timer(&host->tuning_timer);
host->tuning_timer.data = (unsigned long)host;
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 41a2c34299ed..0315e1844330 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -339,6 +339,7 @@ struct sdhci_ops {
void (*adma_workaround)(struct sdhci_host *host, u32 intmask);
void (*platform_init)(struct sdhci_host *host);
void (*card_event)(struct sdhci_host *host);
+ void (*voltage_switch)(struct sdhci_host *host);
};
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
diff --git a/drivers/mmc/host/sdhci_f_sdh30.c b/drivers/mmc/host/sdhci_f_sdh30.c
new file mode 100644
index 000000000000..2fe8b91481b3
--- /dev/null
+++ b/drivers/mmc/host/sdhci_f_sdh30.c
@@ -0,0 +1,237 @@
+/*
+ * linux/drivers/mmc/host/sdhci_f_sdh30.c
+ *
+ * Copyright (C) 2013 - 2015 Fujitsu Semiconductor, Ltd
+ * Vincent Yang <vincent.yang@tw.fujitsu.com>
+ * Copyright (C) 2015 Linaro Ltd Andy Green <andy.green@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, version 2 of the License.
+ */
+
+#include <linux/err.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/clk.h>
+
+#include "sdhci-pltfm.h"
+
+/* F_SDH30 extended Controller registers */
+#define F_SDH30_AHB_CONFIG 0x100
+#define F_SDH30_AHB_BIGED 0x00000040
+#define F_SDH30_BUSLOCK_DMA 0x00000020
+#define F_SDH30_BUSLOCK_EN 0x00000010
+#define F_SDH30_SIN 0x00000008
+#define F_SDH30_AHB_INCR_16 0x00000004
+#define F_SDH30_AHB_INCR_8 0x00000002
+#define F_SDH30_AHB_INCR_4 0x00000001
+
+#define F_SDH30_TUNING_SETTING 0x108
+#define F_SDH30_CMD_CHK_DIS 0x00010000
+
+#define F_SDH30_IO_CONTROL2 0x114
+#define F_SDH30_CRES_O_DN 0x00080000
+#define F_SDH30_MSEL_O_1_8 0x00040000
+
+#define F_SDH30_ESD_CONTROL 0x124
+#define F_SDH30_EMMC_RST 0x00000002
+#define F_SDH30_EMMC_HS200 0x01000000
+
+#define F_SDH30_CMD_DAT_DELAY 0x200
+
+#define F_SDH30_MIN_CLOCK 400000
+
+struct f_sdhost_priv {
+ struct clk *clk_iface;
+ struct clk *clk;
+ u32 vendor_hs200;
+ struct device *dev;
+};
+
+void sdhci_f_sdh30_soft_voltage_switch(struct sdhci_host *host)
+{
+ struct f_sdhost_priv *priv = sdhci_priv(host);
+ u32 ctrl = 0;
+
+ usleep_range(2500, 3000);
+ ctrl = sdhci_readl(host, F_SDH30_IO_CONTROL2);
+ ctrl |= F_SDH30_CRES_O_DN;
+ sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
+ ctrl |= F_SDH30_MSEL_O_1_8;
+ sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
+
+ ctrl &= ~F_SDH30_CRES_O_DN;
+ sdhci_writel(host, ctrl, F_SDH30_IO_CONTROL2);
+ usleep_range(2500, 3000);
+
+ if (priv->vendor_hs200) {
+ dev_info(priv->dev, "%s: setting hs200\n", __func__);
+ ctrl = sdhci_readl(host, F_SDH30_ESD_CONTROL);
+ ctrl |= priv->vendor_hs200;
+ sdhci_writel(host, ctrl, F_SDH30_ESD_CONTROL);
+ }
+
+ ctrl = sdhci_readl(host, F_SDH30_TUNING_SETTING);
+ ctrl |= F_SDH30_CMD_CHK_DIS;
+ sdhci_writel(host, ctrl, F_SDH30_TUNING_SETTING);
+}
+
+unsigned int sdhci_f_sdh30_get_min_clock(struct sdhci_host *host)
+{
+ return F_SDH30_MIN_CLOCK;
+}
+
+void sdhci_f_sdh30_reset(struct sdhci_host *host, u8 mask)
+{
+ if (sdhci_readw(host, SDHCI_CLOCK_CONTROL) == 0)
+ sdhci_writew(host, 0xBC01, SDHCI_CLOCK_CONTROL);
+
+ sdhci_reset(host, mask);
+}
+
+static const struct sdhci_ops sdhci_f_sdh30_ops = {
+ .voltage_switch = sdhci_f_sdh30_soft_voltage_switch,
+ .get_min_clock = sdhci_f_sdh30_get_min_clock,
+ .reset = sdhci_f_sdh30_reset,
+ .set_clock = sdhci_set_clock,
+ .set_bus_width = sdhci_set_bus_width,
+ .set_uhs_signaling = sdhci_set_uhs_signaling,
+};
+
+static int sdhci_f_sdh30_probe(struct platform_device *pdev)
+{
+ struct sdhci_host *host;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int irq, ctrl = 0, ret = 0;
+ struct f_sdhost_priv *priv;
+ u32 reg = 0;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "%s: no irq specified\n", __func__);
+ return irq;
+ }
+
+ host = sdhci_alloc_host(dev, sizeof(struct sdhci_host) +
+ sizeof(struct f_sdhost_priv));
+ if (IS_ERR(host))
+ return PTR_ERR(host);
+
+ priv = sdhci_priv(host);
+ priv->dev = dev;
+
+ host->quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC |
+ SDHCI_QUIRK_INVERTED_WRITE_PROTECT;
+ host->quirks2 = SDHCI_QUIRK2_SUPPORT_SINGLE |
+ SDHCI_QUIRK2_TUNING_WORK_AROUND;
+
+ ret = mmc_of_parse(host->mmc);
+ if (ret)
+ goto err;
+
+ platform_set_drvdata(pdev, host);
+
+ sdhci_get_of_property(pdev);
+ host->hw_name = "f_sdh30";
+ host->ops = &sdhci_f_sdh30_ops;
+ host->irq = irq;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ host->ioaddr = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(host->ioaddr)) {
+ ret = PTR_ERR(host->ioaddr);
+ goto err;
+ }
+
+ priv->clk_iface = devm_clk_get(&pdev->dev, "iface");
+ if (IS_ERR(priv->clk_iface)) {
+ ret = PTR_ERR(priv->clk_iface);
+ goto err;
+ }
+
+ ret = clk_prepare_enable(priv->clk_iface);
+ if (ret)
+ goto err;
+
+ priv->clk = devm_clk_get(&pdev->dev, "core");
+ if (IS_ERR(priv->clk)) {
+ ret = PTR_ERR(priv->clk);
+ goto err_clk;
+ }
+
+ ret = clk_prepare_enable(priv->clk);
+ if (ret)
+ goto err_clk;
+
+ /* init vendor specific regs */
+ ctrl = sdhci_readw(host, F_SDH30_AHB_CONFIG);
+ ctrl |= F_SDH30_SIN | F_SDH30_AHB_INCR_16 | F_SDH30_AHB_INCR_8 |
+ F_SDH30_AHB_INCR_4;
+ ctrl &= ~(F_SDH30_AHB_BIGED | F_SDH30_BUSLOCK_EN);
+ sdhci_writew(host, ctrl, F_SDH30_AHB_CONFIG);
+
+ reg = sdhci_readl(host, F_SDH30_ESD_CONTROL);
+ sdhci_writel(host, reg & ~F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
+ msleep(20);
+ sdhci_writel(host, reg | F_SDH30_EMMC_RST, F_SDH30_ESD_CONTROL);
+
+ reg = sdhci_readl(host, SDHCI_CAPABILITIES);
+ if (reg & SDHCI_CAN_DO_8BIT)
+ priv->vendor_hs200 = F_SDH30_EMMC_HS200;
+
+ ret = sdhci_add_host(host);
+ if (ret)
+ goto err_add_host;
+
+ return 0;
+
+err_add_host:
+ clk_disable_unprepare(priv->clk);
+err_clk:
+ clk_disable_unprepare(priv->clk_iface);
+err:
+ sdhci_free_host(host);
+ return ret;
+}
+
+static int sdhci_f_sdh30_remove(struct platform_device *pdev)
+{
+ struct sdhci_host *host = platform_get_drvdata(pdev);
+ struct f_sdhost_priv *priv = sdhci_priv(host);
+
+ sdhci_remove_host(host, readl(host->ioaddr + SDHCI_INT_STATUS) ==
+ 0xffffffff);
+
+ clk_disable_unprepare(priv->clk_iface);
+ clk_disable_unprepare(priv->clk);
+
+ sdhci_free_host(host);
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static const struct of_device_id f_sdh30_dt_ids[] = {
+ { .compatible = "fujitsu,mb86s70-sdhci-3.0" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, f_sdh30_dt_ids);
+
+static struct platform_driver sdhci_f_sdh30_driver = {
+ .driver = {
+ .name = "f_sdh30",
+ .of_match_table = f_sdh30_dt_ids,
+ .pm = SDHCI_PLTFM_PMOPS,
+ },
+ .probe = sdhci_f_sdh30_probe,
+ .remove = sdhci_f_sdh30_remove,
+};
+
+module_platform_driver(sdhci_f_sdh30_driver);
+
+MODULE_DESCRIPTION("F_SDH30 SD Card Controller driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("FUJITSU SEMICONDUCTOR LTD.");
+MODULE_ALIAS("platform:f_sdh30");
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index 00c8ebdf8ec7..6906a905cd54 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -35,10 +35,13 @@
#define EXT_ACC 0xe4
+#define host_to_priv(host) container_of((host)->pdata, struct sh_mobile_sdhi, mmc_data)
+
struct sh_mobile_sdhi_of_data {
unsigned long tmio_flags;
unsigned long capabilities;
unsigned long capabilities2;
+ enum dma_slave_buswidth dma_buswidth;
dma_addr_t dma_rx_offset;
};
@@ -58,6 +61,7 @@ static const struct sh_mobile_sdhi_of_data of_rcar_gen2_compatible = {
.tmio_flags = TMIO_MMC_HAS_IDLE_WAIT | TMIO_MMC_WRPROTECT_DISABLE |
TMIO_MMC_CLK_ACTUAL,
.capabilities = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ,
+ .dma_buswidth = DMA_SLAVE_BUSWIDTH_4_BYTES,
.dma_rx_offset = 0x2000,
};
@@ -84,16 +88,43 @@ struct sh_mobile_sdhi {
struct tmio_mmc_dma dma_priv;
};
+static void sh_mobile_sdhi_sdbuf_width(struct tmio_mmc_host *host, int width)
+{
+ u32 val;
+
+ /*
+ * see also
+ * sh_mobile_sdhi_of_data :: dma_buswidth
+ */
+ switch (sd_ctrl_read16(host, CTL_VERSION)) {
+ case 0x490C:
+ val = (width == 32) ? 0x0001 : 0x0000;
+ break;
+ case 0xCB0D:
+ val = (width == 32) ? 0x0000 : 0x0001;
+ break;
+ default:
+ /* nothing to do */
+ return;
+ }
+
+ sd_ctrl_write16(host, EXT_ACC, val);
+}
+
static int sh_mobile_sdhi_clk_enable(struct platform_device *pdev, unsigned int *f)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
- struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+ struct sh_mobile_sdhi *priv = host_to_priv(host);
int ret = clk_prepare_enable(priv->clk);
if (ret < 0)
return ret;
*f = clk_get_rate(priv->clk);
+
+ /* enable 16bit data access on SDBUF as default */
+ sh_mobile_sdhi_sdbuf_width(host, 16);
+
return 0;
}
@@ -101,7 +132,7 @@ static void sh_mobile_sdhi_clk_disable(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
- struct sh_mobile_sdhi *priv = container_of(host->pdata, struct sh_mobile_sdhi, mmc_data);
+ struct sh_mobile_sdhi *priv = host_to_priv(host);
clk_disable_unprepare(priv->clk);
}
@@ -113,7 +144,7 @@ static int sh_mobile_sdhi_wait_idle(struct tmio_mmc_host *host)
udelay(1);
if (!timeout) {
- dev_warn(host->pdata->dev, "timeout waiting for SD bus idle\n");
+ dev_warn(&host->pdev->dev, "timeout waiting for SD bus idle\n");
return -EBUSY;
}
@@ -156,14 +187,13 @@ static int sh_mobile_sdhi_multi_io_quirk(struct mmc_card *card,
return blk_size;
}
-static void sh_mobile_sdhi_cd_wakeup(const struct platform_device *pdev)
+static void sh_mobile_sdhi_enable_dma(struct tmio_mmc_host *host, bool enable)
{
- mmc_detect_change(platform_get_drvdata(pdev), msecs_to_jiffies(100));
-}
+ sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
-static const struct sh_mobile_sdhi_ops sdhi_ops = {
- .cd_wakeup = sh_mobile_sdhi_cd_wakeup,
-};
+ /* enable 32bit access if DMA mode if possibile */
+ sh_mobile_sdhi_sdbuf_width(host, enable ? 32 : 16);
+}
static int sh_mobile_sdhi_probe(struct platform_device *pdev)
{
@@ -177,7 +207,6 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
int irq, ret, i = 0;
bool multiplexed_isr = true;
struct tmio_mmc_dma *dma_priv;
- u16 ver;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res)
@@ -192,26 +221,31 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
mmc_data = &priv->mmc_data;
dma_priv = &priv->dma_priv;
- if (p) {
- if (p->init) {
- ret = p->init(pdev, &sdhi_ops);
- if (ret)
- return ret;
- }
- }
-
priv->clk = devm_clk_get(&pdev->dev, NULL);
if (IS_ERR(priv->clk)) {
ret = PTR_ERR(priv->clk);
dev_err(&pdev->dev, "cannot get clock: %d\n", ret);
- goto eclkget;
+ goto eprobe;
}
- mmc_data->clk_enable = sh_mobile_sdhi_clk_enable;
- mmc_data->clk_disable = sh_mobile_sdhi_clk_disable;
+ host = tmio_mmc_host_alloc(pdev);
+ if (!host) {
+ ret = -ENOMEM;
+ goto eprobe;
+ }
+
+ host->dma = dma_priv;
+ host->write16_hook = sh_mobile_sdhi_write16_hook;
+ host->clk_enable = sh_mobile_sdhi_clk_enable;
+ host->clk_disable = sh_mobile_sdhi_clk_disable;
+ host->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
+ /* SD control register space size is 0x100, 0x200 for bus_shift=1 */
+ if (resource_size(res) > 0x100)
+ host->bus_shift = 1;
+ else
+ host->bus_shift = 0;
+
mmc_data->capabilities = MMC_CAP_MMC_HIGHSPEED;
- mmc_data->write16_hook = sh_mobile_sdhi_write16_hook;
- mmc_data->multi_io_quirk = sh_mobile_sdhi_multi_io_quirk;
if (p) {
mmc_data->flags = p->tmio_flags;
mmc_data->ocr_mask = p->tmio_ocr_mask;
@@ -231,11 +265,10 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
dma_priv->slave_id_rx = p->dma_slave_rx;
}
}
-
- dma_priv->alignment_shift = 1; /* 2-byte alignment */
dma_priv->filter = shdma_chan_filter;
+ dma_priv->enable = sh_mobile_sdhi_enable_dma;
- mmc_data->dma = dma_priv;
+ mmc_data->alignment_shift = 1; /* 2-byte alignment */
/*
* All SDHI blocks support 2-byte and larger block sizes in 4-bit
@@ -258,33 +291,18 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
*/
mmc_data->flags |= TMIO_MMC_SDIO_STATUS_QUIRK;
- /*
- * All SDHI have DMA control register
- */
- mmc_data->flags |= TMIO_MMC_HAVE_CTL_DMA_REG;
-
if (of_id && of_id->data) {
const struct sh_mobile_sdhi_of_data *of_data = of_id->data;
mmc_data->flags |= of_data->tmio_flags;
mmc_data->capabilities |= of_data->capabilities;
mmc_data->capabilities2 |= of_data->capabilities2;
- dma_priv->dma_rx_offset = of_data->dma_rx_offset;
+ mmc_data->dma_rx_offset = of_data->dma_rx_offset;
+ dma_priv->dma_buswidth = of_data->dma_buswidth;
}
- /* SD control register space size is 0x100, 0x200 for bus_shift=1 */
- mmc_data->bus_shift = resource_size(res) >> 9;
-
- ret = tmio_mmc_host_probe(&host, pdev, mmc_data);
+ ret = tmio_mmc_host_probe(host, mmc_data);
if (ret < 0)
- goto eprobe;
-
- /*
- * FIXME:
- * this Workaround can be more clever method
- */
- ver = sd_ctrl_read16(host, CTL_VERSION);
- if (ver == 0xCB0D)
- sd_ctrl_write16(host, EXT_ACC, 1);
+ goto efree;
/*
* Allow one or more specific (named) ISRs or
@@ -351,10 +369,9 @@ static int sh_mobile_sdhi_probe(struct platform_device *pdev)
eirq:
tmio_mmc_host_remove(host);
+efree:
+ tmio_mmc_host_free(host);
eprobe:
-eclkget:
- if (p && p->cleanup)
- p->cleanup(pdev);
return ret;
}
@@ -362,13 +379,9 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
{
struct mmc_host *mmc = platform_get_drvdata(pdev);
struct tmio_mmc_host *host = mmc_priv(mmc);
- struct sh_mobile_sdhi_info *p = pdev->dev.platform_data;
tmio_mmc_host_remove(host);
- if (p && p->cleanup)
- p->cleanup(pdev);
-
return 0;
}
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index 15cb8b7ffc34..e8a4218b5726 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -21,8 +21,6 @@
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/clk/sunxi.h>
-
#include <linux/gpio.h>
#include <linux/platform_device.h>
#include <linux/spinlock.h>
@@ -229,6 +227,8 @@ struct sunxi_mmc_host {
/* clock management */
struct clk *clk_ahb;
struct clk *clk_mmc;
+ struct clk *clk_sample;
+ struct clk *clk_output;
/* irq */
spinlock_t lock;
@@ -252,7 +252,7 @@ static int sunxi_mmc_reset_host(struct sunxi_mmc_host *host)
unsigned long expire = jiffies + msecs_to_jiffies(250);
u32 rval;
- mmc_writel(host, REG_CMDR, SDXC_HARDWARE_RESET);
+ mmc_writel(host, REG_GCTRL, SDXC_HARDWARE_RESET);
do {
rval = mmc_readl(host, REG_GCTRL);
} while (time_before(jiffies, expire) && (rval & SDXC_HARDWARE_RESET));
@@ -310,7 +310,9 @@ static void sunxi_mmc_init_idma_des(struct sunxi_mmc_host *host,
}
pdes[0].config |= SDXC_IDMAC_DES0_FD;
- pdes[i - 1].config = SDXC_IDMAC_DES0_OWN | SDXC_IDMAC_DES0_LD;
+ pdes[i - 1].config |= SDXC_IDMAC_DES0_LD | SDXC_IDMAC_DES0_ER;
+ pdes[i - 1].config &= ~SDXC_IDMAC_DES0_DIC;
+ pdes[i - 1].buf_addr_ptr2 = 0;
/*
* Avoid the io-store starting the idmac hitting io-mem before the
@@ -570,6 +572,15 @@ static irqreturn_t sunxi_mmc_handle_manual_stop(int irq, void *dev_id)
}
dev_err(mmc_dev(host->mmc), "data error, sending stop command\n");
+
+ /*
+ * We will never have more than one outstanding request,
+ * and we do not complete the request until after
+ * we've cleared host->manual_stop_mrq so we do not need to
+ * spin lock this function.
+ * Additionally we have wait states within this function
+ * so having it in a lock is a very bad idea.
+ */
sunxi_mmc_send_manual_stop(host, mrq);
spin_lock_irqsave(&host->lock, iflags);
@@ -616,7 +627,7 @@ static int sunxi_mmc_oclk_onoff(struct sunxi_mmc_host *host, u32 oclk_en)
static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
struct mmc_ios *ios)
{
- u32 rate, oclk_dly, rval, sclk_dly, src_clk;
+ u32 rate, oclk_dly, rval, sclk_dly;
int ret;
rate = clk_round_rate(host->clk_mmc, ios->clock);
@@ -642,34 +653,31 @@ static int sunxi_mmc_clk_set_rate(struct sunxi_mmc_host *host,
/* determine delays */
if (rate <= 400000) {
- oclk_dly = 0;
- sclk_dly = 7;
+ oclk_dly = 180;
+ sclk_dly = 42;
} else if (rate <= 25000000) {
- oclk_dly = 0;
- sclk_dly = 5;
+ oclk_dly = 180;
+ sclk_dly = 75;
} else if (rate <= 50000000) {
if (ios->timing == MMC_TIMING_UHS_DDR50) {
- oclk_dly = 2;
- sclk_dly = 4;
+ oclk_dly = 60;
+ sclk_dly = 120;
} else {
- oclk_dly = 3;
- sclk_dly = 5;
+ oclk_dly = 90;
+ sclk_dly = 150;
}
+ } else if (rate <= 100000000) {
+ oclk_dly = 6;
+ sclk_dly = 24;
+ } else if (rate <= 200000000) {
+ oclk_dly = 3;
+ sclk_dly = 12;
} else {
- /* rate > 50000000 */
- oclk_dly = 2;
- sclk_dly = 4;
+ return -EINVAL;
}
- src_clk = clk_get_rate(clk_get_parent(host->clk_mmc));
- if (src_clk >= 300000000 && src_clk <= 400000000) {
- if (oclk_dly)
- oclk_dly--;
- if (sclk_dly)
- sclk_dly--;
- }
-
- clk_sunxi_mmc_phase_control(host->clk_mmc, sclk_dly, oclk_dly);
+ clk_set_phase(host->clk_sample, sclk_dly);
+ clk_set_phase(host->clk_output, oclk_dly);
return sunxi_mmc_oclk_onoff(host, 1);
}
@@ -766,6 +774,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
unsigned long iflags;
u32 imask = SDXC_INTERRUPT_ERROR_BIT;
u32 cmd_val = SDXC_START | (cmd->opcode & 0x3f);
+ bool wait_dma = host->wait_dma;
int ret;
/* Check for set_ios errors (should never happen) */
@@ -816,7 +825,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
if (cmd->data->flags & MMC_DATA_WRITE)
cmd_val |= SDXC_WRITE;
else
- host->wait_dma = true;
+ wait_dma = true;
} else {
imask |= SDXC_COMMAND_DONE;
}
@@ -850,6 +859,7 @@ static void sunxi_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
}
host->mrq = mrq;
+ host->wait_dma = wait_dma;
mmc_writel(host, REG_IMASK, host->sdio_imask | imask);
mmc_writel(host, REG_CARG, cmd->arg);
mmc_writel(host, REG_CMDR, cmd_val);
@@ -908,6 +918,18 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
return PTR_ERR(host->clk_mmc);
}
+ host->clk_output = devm_clk_get(&pdev->dev, "output");
+ if (IS_ERR(host->clk_output)) {
+ dev_err(&pdev->dev, "Could not get output clock\n");
+ return PTR_ERR(host->clk_output);
+ }
+
+ host->clk_sample = devm_clk_get(&pdev->dev, "sample");
+ if (IS_ERR(host->clk_sample)) {
+ dev_err(&pdev->dev, "Could not get sample clock\n");
+ return PTR_ERR(host->clk_sample);
+ }
+
host->reset = devm_reset_control_get(&pdev->dev, "ahb");
ret = clk_prepare_enable(host->clk_ahb);
@@ -922,11 +944,23 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
goto error_disable_clk_ahb;
}
+ ret = clk_prepare_enable(host->clk_output);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable output clk err %d\n", ret);
+ goto error_disable_clk_mmc;
+ }
+
+ ret = clk_prepare_enable(host->clk_sample);
+ if (ret) {
+ dev_err(&pdev->dev, "Enable sample clk err %d\n", ret);
+ goto error_disable_clk_output;
+ }
+
if (!IS_ERR(host->reset)) {
ret = reset_control_deassert(host->reset);
if (ret) {
dev_err(&pdev->dev, "reset err %d\n", ret);
- goto error_disable_clk_mmc;
+ goto error_disable_clk_sample;
}
}
@@ -945,6 +979,10 @@ static int sunxi_mmc_resource_request(struct sunxi_mmc_host *host,
error_assert_reset:
if (!IS_ERR(host->reset))
reset_control_assert(host->reset);
+error_disable_clk_sample:
+ clk_disable_unprepare(host->clk_sample);
+error_disable_clk_output:
+ clk_disable_unprepare(host->clk_output);
error_disable_clk_mmc:
clk_disable_unprepare(host->clk_mmc);
error_disable_clk_ahb:
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 2ca0afaab792..f746df493892 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -88,14 +88,19 @@ static int tmio_mmc_probe(struct platform_device *pdev)
if (!res)
return -EINVAL;
- /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
- pdata->bus_shift = resource_size(res) >> 10;
pdata->flags |= TMIO_MMC_HAVE_HIGH_REG;
- ret = tmio_mmc_host_probe(&host, pdev, pdata);
- if (ret)
+ host = tmio_mmc_host_alloc(pdev);
+ if (!host)
goto cell_disable;
+ /* SD control register space size is 0x200, 0x400 for bus_shift=1 */
+ host->bus_shift = resource_size(res) >> 10;
+
+ ret = tmio_mmc_host_probe(host, pdata);
+ if (ret)
+ goto host_free;
+
ret = request_irq(irq, tmio_mmc_irq, IRQF_TRIGGER_FALLING,
dev_name(&pdev->dev), host);
if (ret)
@@ -108,6 +113,8 @@ static int tmio_mmc_probe(struct platform_device *pdev)
host_remove:
tmio_mmc_host_remove(host);
+host_free:
+ tmio_mmc_host_free(host);
cell_disable:
if (cell->disable)
cell->disable(pdev);
diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
index a34ecbe1c1ad..fc3805ed69d1 100644
--- a/drivers/mmc/host/tmio_mmc.h
+++ b/drivers/mmc/host/tmio_mmc.h
@@ -16,6 +16,7 @@
#ifndef TMIO_MMC_H
#define TMIO_MMC_H
+#include <linux/dmaengine.h>
#include <linux/highmem.h>
#include <linux/mmc/tmio.h>
#include <linux/mutex.h>
@@ -39,6 +40,17 @@
#define TMIO_MASK_IRQ (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
struct tmio_mmc_data;
+struct tmio_mmc_host;
+
+struct tmio_mmc_dma {
+ void *chan_priv_tx;
+ void *chan_priv_rx;
+ int slave_id_tx;
+ int slave_id_rx;
+ enum dma_slave_buswidth dma_buswidth;
+ bool (*filter)(struct dma_chan *chan, void *arg);
+ void (*enable)(struct tmio_mmc_host *host, bool enable);
+};
struct tmio_mmc_host {
void __iomem *ctl;
@@ -56,9 +68,11 @@ struct tmio_mmc_host {
struct scatterlist *sg_orig;
unsigned int sg_len;
unsigned int sg_off;
+ unsigned long bus_shift;
struct platform_device *pdev;
struct tmio_mmc_data *pdata;
+ struct tmio_mmc_dma *dma;
/* DMA support */
bool force_pio;
@@ -83,10 +97,17 @@ struct tmio_mmc_host {
struct mutex ios_lock; /* protect set_ios() context */
bool native_hotplug;
bool sdio_irq_enabled;
+
+ int (*write16_hook)(struct tmio_mmc_host *host, int addr);
+ int (*clk_enable)(struct platform_device *pdev, unsigned int *f);
+ void (*clk_disable)(struct platform_device *pdev);
+ int (*multi_io_quirk)(struct mmc_card *card,
+ unsigned int direction, int blk_size);
};
-int tmio_mmc_host_probe(struct tmio_mmc_host **host,
- struct platform_device *pdev,
+struct tmio_mmc_host *tmio_mmc_host_alloc(struct platform_device *pdev);
+void tmio_mmc_host_free(struct tmio_mmc_host *host);
+int tmio_mmc_host_probe(struct tmio_mmc_host *host,
struct tmio_mmc_data *pdata);
void tmio_mmc_host_remove(struct tmio_mmc_host *host);
void tmio_mmc_do_data_irq(struct tmio_mmc_host *host);
@@ -151,19 +172,19 @@ int tmio_mmc_host_runtime_resume(struct device *dev);
static inline u16 sd_ctrl_read16(struct tmio_mmc_host *host, int addr)
{
- return readw(host->ctl + (addr << host->pdata->bus_shift));
+ return readw(host->ctl + (addr << host->bus_shift));
}
static inline void sd_ctrl_read16_rep(struct tmio_mmc_host *host, int addr,
u16 *buf, int count)
{
- readsw(host->ctl + (addr << host->pdata->bus_shift), buf, count);
+ readsw(host->ctl + (addr << host->bus_shift), buf, count);
}
static inline u32 sd_ctrl_read32(struct tmio_mmc_host *host, int addr)
{
- return readw(host->ctl + (addr << host->pdata->bus_shift)) |
- readw(host->ctl + ((addr + 2) << host->pdata->bus_shift)) << 16;
+ return readw(host->ctl + (addr << host->bus_shift)) |
+ readw(host->ctl + ((addr + 2) << host->bus_shift)) << 16;
}
static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val)
@@ -171,21 +192,21 @@ static inline void sd_ctrl_write16(struct tmio_mmc_host *host, int addr, u16 val
/* If there is a hook and it returns non-zero then there
* is an error and the write should be skipped
*/
- if (host->pdata->write16_hook && host->pdata->write16_hook(host, addr))
+ if (host->write16_hook && host->write16_hook(host, addr))
return;
- writew(val, host->ctl + (addr << host->pdata->bus_shift));
+ writew(val, host->ctl + (addr << host->bus_shift));
}
static inline void sd_ctrl_write16_rep(struct tmio_mmc_host *host, int addr,
u16 *buf, int count)
{
- writesw(host->ctl + (addr << host->pdata->bus_shift), buf, count);
+ writesw(host->ctl + (addr << host->bus_shift), buf, count);
}
static inline void sd_ctrl_write32(struct tmio_mmc_host *host, int addr, u32 val)
{
- writew(val, host->ctl + (addr << host->pdata->bus_shift));
- writew(val >> 16, host->ctl + ((addr + 2) << host->pdata->bus_shift));
+ writew(val, host->ctl + (addr << host->bus_shift));
+ writew(val >> 16, host->ctl + ((addr + 2) << host->bus_shift));
}
diff --git a/drivers/mmc/host/tmio_mmc_dma.c b/drivers/mmc/host/tmio_mmc_dma.c
index 7d077388b9eb..331bb618e398 100644
--- a/drivers/mmc/host/tmio_mmc_dma.c
+++ b/drivers/mmc/host/tmio_mmc_dma.c
@@ -28,8 +28,8 @@ void tmio_mmc_enable_dma(struct tmio_mmc_host *host, bool enable)
if (!host->chan_tx || !host->chan_rx)
return;
- if (host->pdata->flags & TMIO_MMC_HAVE_CTL_DMA_REG)
- sd_ctrl_write16(host, CTL_DMA_ENABLE, enable ? 2 : 0);
+ if (host->dma->enable)
+ host->dma->enable(host, enable);
}
void tmio_mmc_abort_dma(struct tmio_mmc_host *host)
@@ -49,11 +49,10 @@ static void tmio_mmc_start_dma_rx(struct tmio_mmc_host *host)
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_rx;
- struct tmio_mmc_data *pdata = host->pdata;
dma_cookie_t cookie;
int ret, i;
bool aligned = true, multiple = true;
- unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+ unsigned int align = (1 << host->pdata->alignment_shift) - 1;
for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align)
@@ -126,11 +125,10 @@ static void tmio_mmc_start_dma_tx(struct tmio_mmc_host *host)
struct scatterlist *sg = host->sg_ptr, *sg_tmp;
struct dma_async_tx_descriptor *desc = NULL;
struct dma_chan *chan = host->chan_tx;
- struct tmio_mmc_data *pdata = host->pdata;
dma_cookie_t cookie;
int ret, i;
bool aligned = true, multiple = true;
- unsigned int align = (1 << pdata->dma->alignment_shift) - 1;
+ unsigned int align = (1 << host->pdata->alignment_shift) - 1;
for_each_sg(sg, sg_tmp, host->sg_len, i) {
if (sg_tmp->offset & align)
@@ -262,8 +260,8 @@ out:
void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdata)
{
/* We can only either use DMA for both Tx and Rx or not use it at all */
- if (!pdata->dma || (!host->pdev->dev.of_node &&
- (!pdata->dma->chan_priv_tx || !pdata->dma->chan_priv_rx)))
+ if (!host->dma || (!host->pdev->dev.of_node &&
+ (!host->dma->chan_priv_tx || !host->dma->chan_priv_rx)))
return;
if (!host->chan_tx && !host->chan_rx) {
@@ -280,7 +278,7 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
dma_cap_set(DMA_SLAVE, mask);
host->chan_tx = dma_request_slave_channel_compat(mask,
- pdata->dma->filter, pdata->dma->chan_priv_tx,
+ host->dma->filter, host->dma->chan_priv_tx,
&host->pdev->dev, "tx");
dev_dbg(&host->pdev->dev, "%s: TX: got channel %p\n", __func__,
host->chan_tx);
@@ -288,18 +286,20 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
if (!host->chan_tx)
return;
- if (pdata->dma->chan_priv_tx)
- cfg.slave_id = pdata->dma->slave_id_tx;
+ if (host->dma->chan_priv_tx)
+ cfg.slave_id = host->dma->slave_id_tx;
cfg.direction = DMA_MEM_TO_DEV;
- cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->pdata->bus_shift);
- cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ cfg.dst_addr = res->start + (CTL_SD_DATA_PORT << host->bus_shift);
+ cfg.dst_addr_width = host->dma->dma_buswidth;
+ if (!cfg.dst_addr_width)
+ cfg.dst_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
cfg.src_addr = 0;
ret = dmaengine_slave_config(host->chan_tx, &cfg);
if (ret < 0)
goto ecfgtx;
host->chan_rx = dma_request_slave_channel_compat(mask,
- pdata->dma->filter, pdata->dma->chan_priv_rx,
+ host->dma->filter, host->dma->chan_priv_rx,
&host->pdev->dev, "rx");
dev_dbg(&host->pdev->dev, "%s: RX: got channel %p\n", __func__,
host->chan_rx);
@@ -307,11 +307,13 @@ void tmio_mmc_request_dma(struct tmio_mmc_host *host, struct tmio_mmc_data *pdat
if (!host->chan_rx)
goto ereqrx;
- if (pdata->dma->chan_priv_rx)
- cfg.slave_id = pdata->dma->slave_id_rx;
+ if (host->dma->chan_priv_rx)
+ cfg.slave_id = host->dma->slave_id_rx;
cfg.direction = DMA_DEV_TO_MEM;
- cfg.src_addr = cfg.dst_addr + pdata->dma->dma_rx_offset;
- cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
+ cfg.src_addr = cfg.dst_addr + host->pdata->dma_rx_offset;
+ cfg.src_addr_width = host->dma->dma_buswidth;
+ if (!cfg.src_addr_width)
+ cfg.src_addr_width = DMA_SLAVE_BUSWIDTH_2_BYTES;
cfg.dst_addr = 0;
ret = dmaengine_slave_config(host->chan_rx, &cfg);
if (ret < 0)
diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
index 250bf8c9f998..a31c3573d386 100644
--- a/drivers/mmc/host/tmio_mmc_pio.c
+++ b/drivers/mmc/host/tmio_mmc_pio.c
@@ -835,13 +835,12 @@ fail:
static int tmio_mmc_clk_update(struct tmio_mmc_host *host)
{
struct mmc_host *mmc = host->mmc;
- struct tmio_mmc_data *pdata = host->pdata;
int ret;
- if (!pdata->clk_enable)
+ if (!host->clk_enable)
return -ENOTSUPP;
- ret = pdata->clk_enable(host->pdev, &mmc->f_max);
+ ret = host->clk_enable(host->pdev, &mmc->f_max);
if (!ret)
mmc->f_min = mmc->f_max / 512;
@@ -1005,10 +1004,9 @@ static int tmio_multi_io_quirk(struct mmc_card *card,
unsigned int direction, int blk_size)
{
struct tmio_mmc_host *host = mmc_priv(card->host);
- struct tmio_mmc_data *pdata = host->pdata;
- if (pdata->multi_io_quirk)
- return pdata->multi_io_quirk(card, direction, blk_size);
+ if (host->multi_io_quirk)
+ return host->multi_io_quirk(card, direction, blk_size);
return blk_size;
}
@@ -1054,12 +1052,37 @@ static void tmio_mmc_of_parse(struct platform_device *pdev,
pdata->flags |= TMIO_MMC_WRPROTECT_DISABLE;
}
-int tmio_mmc_host_probe(struct tmio_mmc_host **host,
- struct platform_device *pdev,
- struct tmio_mmc_data *pdata)
+struct tmio_mmc_host*
+tmio_mmc_host_alloc(struct platform_device *pdev)
{
- struct tmio_mmc_host *_host;
+ struct tmio_mmc_host *host;
struct mmc_host *mmc;
+
+ mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev);
+ if (!mmc)
+ return NULL;
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+ host->pdev = pdev;
+
+ return host;
+}
+EXPORT_SYMBOL(tmio_mmc_host_alloc);
+
+void tmio_mmc_host_free(struct tmio_mmc_host *host)
+{
+ mmc_free_host(host->mmc);
+
+ host->mmc = NULL;
+}
+EXPORT_SYMBOL(tmio_mmc_host_free);
+
+int tmio_mmc_host_probe(struct tmio_mmc_host *_host,
+ struct tmio_mmc_data *pdata)
+{
+ struct platform_device *pdev = _host->pdev;
+ struct mmc_host *mmc = _host->mmc;
struct resource *res_ctl;
int ret;
u32 irq_mask = TMIO_MASK_CMD;
@@ -1067,25 +1090,17 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
tmio_mmc_of_parse(pdev, pdata);
if (!(pdata->flags & TMIO_MMC_HAS_IDLE_WAIT))
- pdata->write16_hook = NULL;
+ _host->write16_hook = NULL;
res_ctl = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res_ctl)
return -EINVAL;
- mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &pdev->dev);
- if (!mmc)
- return -ENOMEM;
-
ret = mmc_of_parse(mmc);
if (ret < 0)
goto host_free;
- pdata->dev = &pdev->dev;
- _host = mmc_priv(mmc);
_host->pdata = pdata;
- _host->mmc = mmc;
- _host->pdev = pdev;
platform_set_drvdata(pdev, mmc);
_host->set_pwr = pdata->set_pwr;
@@ -1192,12 +1207,9 @@ int tmio_mmc_host_probe(struct tmio_mmc_host **host,
mmc_gpiod_request_cd_irq(mmc);
}
- *host = _host;
-
return 0;
host_free:
- mmc_free_host(mmc);
return ret;
}
@@ -1222,7 +1234,6 @@ void tmio_mmc_host_remove(struct tmio_mmc_host *host)
pm_runtime_disable(&pdev->dev);
iounmap(host->ctl);
- mmc_free_host(mmc);
}
EXPORT_SYMBOL(tmio_mmc_host_remove);
@@ -1237,8 +1248,8 @@ int tmio_mmc_host_runtime_suspend(struct device *dev)
if (host->clk_cache)
tmio_mmc_clk_stop(host);
- if (host->pdata->clk_disable)
- host->pdata->clk_disable(host->pdev);
+ if (host->clk_disable)
+ host->clk_disable(host->pdev);
return 0;
}
diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c
index 4666262edaca..e2cdd5fb1423 100644
--- a/drivers/mmc/host/toshsd.c
+++ b/drivers/mmc/host/toshsd.c
@@ -176,7 +176,8 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id)
spin_lock_irqsave(&host->lock, flags);
if (!sg_miter_next(sg_miter))
- return IRQ_HANDLED;
+ goto done;
+
buf = sg_miter->addr;
/* Ensure we dont read more than one block. The chip will interrupt us
@@ -198,6 +199,7 @@ static irqreturn_t toshsd_thread_irq(int irq, void *dev_id)
sg_miter->consumed = count;
sg_miter_stop(sg_miter);
+done:
spin_unlock_irqrestore(&host->lock, flags);
return IRQ_HANDLED;
@@ -699,18 +701,7 @@ static struct pci_driver toshsd_driver = {
.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_pci_driver(toshsd_driver);
MODULE_AUTHOR("Ondrej Zary, Richard Betts");
MODULE_DESCRIPTION("Toshiba PCI Secure Digital Host Controller Interface driver");
diff --git a/drivers/mmc/host/vub300.c b/drivers/mmc/host/vub300.c
index 4262296c12fa..fbabbb82b354 100644
--- a/drivers/mmc/host/vub300.c
+++ b/drivers/mmc/host/vub300.c
@@ -659,7 +659,7 @@ static void __vub300_irqpoll_response(struct vub300_mmc_host *vub300)
static void __do_poll(struct vub300_mmc_host *vub300)
{
/* cmd_mutex is held by vub300_pollwork_thread */
- long commretval;
+ unsigned long commretval;
mod_timer(&vub300->inactivity_timer, jiffies + HZ);
init_completion(&vub300->irqpoll_complete);
send_irqpoll(vub300);
@@ -671,8 +671,6 @@ static void __do_poll(struct vub300_mmc_host *vub300)
vub300->usb_timed_out = 1;
usb_kill_urb(vub300->command_out_urb);
usb_kill_urb(vub300->command_res_urb);
- } else if (commretval < 0) {
- vub300_queue_poll_work(vub300, 1);
} else { /* commretval > 0 */
__vub300_irqpoll_response(vub300);
}
diff --git a/drivers/mtd/bcm47xxpart.c b/drivers/mtd/bcm47xxpart.c
index cc13ea5ce4d5..c0720c1ee4c9 100644
--- a/drivers/mtd/bcm47xxpart.c
+++ b/drivers/mtd/bcm47xxpart.c
@@ -15,6 +15,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#include <uapi/linux/magic.h>
+
/*
* NAND flash on Netgear R6250 was verified to contain 15 partitions.
* This will result in allocating too big array for some old devices, but the
@@ -39,7 +41,8 @@
#define ML_MAGIC1 0x39685a42
#define ML_MAGIC2 0x26594131
#define TRX_MAGIC 0x30524448
-#define SQSH_MAGIC 0x71736873 /* shsq */
+#define SHSQ_MAGIC 0x71736873 /* shsq (weird ZTE H218N endianness) */
+#define UBI_EC_MAGIC 0x23494255 /* UBI# */
struct trx_header {
uint32_t magic;
@@ -50,7 +53,7 @@ struct trx_header {
uint32_t offset[3];
} __packed;
-static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
+static void bcm47xxpart_add_part(struct mtd_partition *part, const char *name,
u64 offset, uint32_t mask_flags)
{
part->name = name;
@@ -58,6 +61,26 @@ static void bcm47xxpart_add_part(struct mtd_partition *part, char *name,
part->mask_flags = mask_flags;
}
+static const char *bcm47xxpart_trx_data_part_name(struct mtd_info *master,
+ size_t offset)
+{
+ uint32_t buf;
+ size_t bytes_read;
+
+ if (mtd_read(master, offset, sizeof(buf), &bytes_read,
+ (uint8_t *)&buf) < 0) {
+ pr_err("mtd_read error while parsing (offset: 0x%X)!\n",
+ offset);
+ goto out_default;
+ }
+
+ if (buf == UBI_EC_MAGIC)
+ return "ubi";
+
+out_default:
+ return "rootfs";
+}
+
static int bcm47xxpart_parse(struct mtd_info *master,
struct mtd_partition **pparts,
struct mtd_part_parser_data *data)
@@ -73,8 +96,12 @@ static int bcm47xxpart_parse(struct mtd_info *master,
int last_trx_part = -1;
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
- if (blocksize <= 0x10000)
- blocksize = 0x10000;
+ /*
+ * Some really old flashes (like AT45DB*) had smaller erasesize-s, but
+ * partitions were aligned to at least 0x1000 anyway.
+ */
+ if (blocksize < 0x1000)
+ blocksize = 0x1000;
/* Alloc */
parts = kzalloc(sizeof(struct mtd_partition) * BCM47XXPART_MAX_PARTS,
@@ -186,8 +213,11 @@ static int bcm47xxpart_parse(struct mtd_info *master,
* we want to have jffs2 (overlay) in the same mtd.
*/
if (trx->offset[i]) {
+ const char *name;
+
+ name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
bcm47xxpart_add_part(&parts[curr_part++],
- "rootfs",
+ name,
offset + trx->offset[i],
0);
i++;
@@ -205,7 +235,8 @@ static int bcm47xxpart_parse(struct mtd_info *master,
}
/* Squashfs on devices not using TRX */
- if (buf[0x000 / 4] == SQSH_MAGIC) {
+ if (le32_to_cpu(buf[0x000 / 4]) == SQUASHFS_MAGIC ||
+ buf[0x000 / 4] == SHSQ_MAGIC) {
bcm47xxpart_add_part(&parts[curr_part++], "rootfs",
offset, 0);
continue;
diff --git a/drivers/mtd/chips/map_ram.c b/drivers/mtd/chips/map_ram.c
index 991c2a1c05d3..afb43d5e1782 100644
--- a/drivers/mtd/chips/map_ram.c
+++ b/drivers/mtd/chips/map_ram.c
@@ -68,6 +68,7 @@ static struct mtd_info *map_ram_probe(struct map_info *map)
mtd->_get_unmapped_area = mapram_unmapped_area;
mtd->_read = mapram_read;
mtd->_write = mapram_write;
+ mtd->_panic_write = mapram_write;
mtd->_sync = mapram_nop;
mtd->flags = MTD_CAP_RAM;
mtd->writesize = 1;
diff --git a/drivers/mtd/chips/map_rom.c b/drivers/mtd/chips/map_rom.c
index 47a43cf7e5c6..e67f73ab44c9 100644
--- a/drivers/mtd/chips/map_rom.c
+++ b/drivers/mtd/chips/map_rom.c
@@ -11,6 +11,7 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/init.h>
+#include <linux/of.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/map.h>
@@ -28,6 +29,15 @@ static struct mtd_chip_driver maprom_chipdrv = {
.module = THIS_MODULE
};
+static unsigned int default_erasesize(struct map_info *map)
+{
+ const __be32 *erase_size = NULL;
+
+ erase_size = of_get_property(map->device_node, "erase-size", NULL);
+
+ return !erase_size ? map->size : be32_to_cpu(*erase_size);
+}
+
static struct mtd_info *map_rom_probe(struct map_info *map)
{
struct mtd_info *mtd;
@@ -47,8 +57,9 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
mtd->_sync = maprom_nop;
mtd->_erase = maprom_erase;
mtd->flags = MTD_CAP_ROM;
- mtd->erasesize = map->size;
+ mtd->erasesize = default_erasesize(map);
mtd->writesize = 1;
+ mtd->writebufsize = 1;
__module_get(THIS_MODULE);
return mtd;
diff --git a/drivers/mtd/devices/st_spi_fsm.c b/drivers/mtd/devices/st_spi_fsm.c
index 54ffe5223e64..3060025c8af4 100644
--- a/drivers/mtd/devices/st_spi_fsm.c
+++ b/drivers/mtd/devices/st_spi_fsm.c
@@ -24,6 +24,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of.h>
+#include <linux/clk.h>
#include "serial_flash_cmds.h"
@@ -262,6 +263,7 @@ struct stfsm {
struct mtd_info mtd;
struct mutex lock;
struct flash_info *info;
+ struct clk *clk;
uint32_t configuration;
uint32_t fifo_dir_delay;
@@ -663,6 +665,23 @@ static struct stfsm_seq stfsm_seq_write_status = {
SEQ_CFG_STARTSEQ),
};
+/* Dummy sequence to read one byte of data from flash into the FIFO */
+static const struct stfsm_seq stfsm_seq_load_fifo_byte = {
+ .data_size = TRANSFER_SIZE(1),
+ .seq_opc[0] = (SEQ_OPC_PADS_1 |
+ SEQ_OPC_CYCLES(8) |
+ SEQ_OPC_OPCODE(SPINOR_OP_RDID)),
+ .seq = {
+ STFSM_INST_CMD1,
+ STFSM_INST_DATA_READ,
+ STFSM_INST_STOP,
+ },
+ .seq_cfg = (SEQ_CFG_PADS_1 |
+ SEQ_CFG_READNOTWRITE |
+ SEQ_CFG_CSDEASSERT |
+ SEQ_CFG_STARTSEQ),
+};
+
static int stfsm_n25q_en_32bit_addr_seq(struct stfsm_seq *seq)
{
seq->seq_opc[0] = (SEQ_OPC_PADS_1 | SEQ_OPC_CYCLES(8) |
@@ -695,22 +714,6 @@ static inline uint32_t stfsm_fifo_available(struct stfsm *fsm)
return (readl(fsm->base + SPI_FAST_SEQ_STA) >> 5) & 0x7f;
}
-static void stfsm_clear_fifo(struct stfsm *fsm)
-{
- uint32_t avail;
-
- for (;;) {
- avail = stfsm_fifo_available(fsm);
- if (!avail)
- break;
-
- while (avail) {
- readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
- avail--;
- }
- }
-}
-
static inline void stfsm_load_seq(struct stfsm *fsm,
const struct stfsm_seq *seq)
{
@@ -772,6 +775,68 @@ static void stfsm_read_fifo(struct stfsm *fsm, uint32_t *buf, uint32_t size)
}
}
+/*
+ * Clear the data FIFO
+ *
+ * Typically, this is only required during driver initialisation, where no
+ * assumptions can be made regarding the state of the FIFO.
+ *
+ * The process of clearing the FIFO is complicated by fact that while it is
+ * possible for the FIFO to contain an arbitrary number of bytes [1], the
+ * SPI_FAST_SEQ_STA register only reports the number of complete 32-bit words
+ * present. Furthermore, data can only be drained from the FIFO by reading
+ * complete 32-bit words.
+ *
+ * With this in mind, a two stage process is used to the clear the FIFO:
+ *
+ * 1. Read any complete 32-bit words from the FIFO, as reported by the
+ * SPI_FAST_SEQ_STA register.
+ *
+ * 2. Mop up any remaining bytes. At this point, it is not known if there
+ * are 0, 1, 2, or 3 bytes in the FIFO. To handle all cases, a dummy FSM
+ * sequence is used to load one byte at a time, until a complete 32-bit
+ * word is formed; at most, 4 bytes will need to be loaded.
+ *
+ * [1] It is theoretically possible for the FIFO to contain an arbitrary number
+ * of bits. However, since there are no known use-cases that leave
+ * incomplete bytes in the FIFO, only words and bytes are considered here.
+ */
+static void stfsm_clear_fifo(struct stfsm *fsm)
+{
+ const struct stfsm_seq *seq = &stfsm_seq_load_fifo_byte;
+ uint32_t words, i;
+
+ /* 1. Clear any 32-bit words */
+ words = stfsm_fifo_available(fsm);
+ if (words) {
+ for (i = 0; i < words; i++)
+ readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
+ dev_dbg(fsm->dev, "cleared %d words from FIFO\n", words);
+ }
+
+ /*
+ * 2. Clear any remaining bytes
+ * - Load the FIFO, one byte at a time, until a complete 32-bit word
+ * is available.
+ */
+ for (i = 0, words = 0; i < 4 && !words; i++) {
+ stfsm_load_seq(fsm, seq);
+ stfsm_wait_seq(fsm);
+ words = stfsm_fifo_available(fsm);
+ }
+
+ /* - A single word must be available now */
+ if (words != 1) {
+ dev_err(fsm->dev, "failed to clear bytes from the data FIFO\n");
+ return;
+ }
+
+ /* - Read the 32-bit word */
+ readl(fsm->base + SPI_FAST_SEQ_DATA_REG);
+
+ dev_dbg(fsm->dev, "cleared %d byte(s) from the data FIFO\n", 4 - i);
+}
+
static int stfsm_write_fifo(struct stfsm *fsm, const uint32_t *buf,
uint32_t size)
{
@@ -1521,11 +1586,11 @@ static int stfsm_write(struct stfsm *fsm, const uint8_t *buf,
uint32_t size_lb;
uint32_t size_mop;
uint32_t tmp[4];
+ uint32_t i;
uint32_t page_buf[FLASH_PAGESIZE_32];
uint8_t *t = (uint8_t *)&tmp;
const uint8_t *p;
int ret;
- int i;
dev_dbg(fsm->dev, "writing %d bytes to 0x%08x\n", size, offset);
@@ -1843,8 +1908,7 @@ static void stfsm_set_freq(struct stfsm *fsm, uint32_t spi_freq)
uint32_t emi_freq;
uint32_t clk_div;
- /* TODO: Make this dynamic */
- emi_freq = STFSM_DEFAULT_EMI_FREQ;
+ emi_freq = clk_get_rate(fsm->clk);
/*
* Calculate clk_div - values between 2 and 128
@@ -1994,6 +2058,18 @@ static int stfsm_probe(struct platform_device *pdev)
return PTR_ERR(fsm->base);
}
+ fsm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(fsm->clk)) {
+ dev_err(fsm->dev, "Couldn't find EMI clock.\n");
+ return PTR_ERR(fsm->clk);
+ }
+
+ ret = clk_prepare_enable(fsm->clk);
+ if (ret) {
+ dev_err(fsm->dev, "Failed to enable EMI clock.\n");
+ return ret;
+ }
+
mutex_init(&fsm->lock);
ret = stfsm_init(fsm);
@@ -2058,6 +2134,28 @@ static int stfsm_remove(struct platform_device *pdev)
return mtd_device_unregister(&fsm->mtd);
}
+#ifdef CONFIG_PM_SLEEP
+static int stfsmfsm_suspend(struct device *dev)
+{
+ struct stfsm *fsm = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(fsm->clk);
+
+ return 0;
+}
+
+static int stfsmfsm_resume(struct device *dev)
+{
+ struct stfsm *fsm = dev_get_drvdata(dev);
+
+ clk_prepare_enable(fsm->clk);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(stfsm_pm_ops, stfsmfsm_suspend, stfsmfsm_resume);
+
static const struct of_device_id stfsm_match[] = {
{ .compatible = "st,spi-fsm", },
{},
@@ -2070,6 +2168,7 @@ static struct platform_driver stfsm_driver = {
.driver = {
.name = "st-spi-fsm",
.of_match_table = stfsm_match,
+ .pm = &stfsm_pm_ops,
},
};
module_platform_driver(stfsm_driver);
diff --git a/drivers/mtd/maps/physmap_of.c b/drivers/mtd/maps/physmap_of.c
index f35cd2081314..ff26e979b1a1 100644
--- a/drivers/mtd/maps/physmap_of.c
+++ b/drivers/mtd/maps/physmap_of.c
@@ -269,6 +269,16 @@ static int of_flash_probe(struct platform_device *dev)
info->list[i].mtd = obsolete_probe(dev,
&info->list[i].map);
}
+
+ /* Fall back to mapping region as ROM */
+ if (!info->list[i].mtd) {
+ dev_warn(&dev->dev,
+ "do_map_probe() failed for type %s\n",
+ probe_type);
+
+ info->list[i].mtd = do_map_probe("map_rom",
+ &info->list[i].map);
+ }
mtd_list[i] = info->list[i].mtd;
err = -ENXIO;
diff --git a/drivers/mtd/mtdblock.c b/drivers/mtd/mtdblock.c
index 485ea751c7f9..bb4c14f83c75 100644
--- a/drivers/mtd/mtdblock.c
+++ b/drivers/mtd/mtdblock.c
@@ -45,8 +45,6 @@ struct mtdblk_dev {
enum { STATE_EMPTY, STATE_CLEAN, STATE_DIRTY } cache_state;
};
-static DEFINE_MUTEX(mtdblks_lock);
-
/*
* Cache stuff...
*
@@ -286,10 +284,8 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
pr_debug("mtdblock_open\n");
- mutex_lock(&mtdblks_lock);
if (mtdblk->count) {
mtdblk->count++;
- mutex_unlock(&mtdblks_lock);
return 0;
}
@@ -302,8 +298,6 @@ static int mtdblock_open(struct mtd_blktrans_dev *mbd)
mtdblk->cache_data = NULL;
}
- mutex_unlock(&mtdblks_lock);
-
pr_debug("ok\n");
return 0;
@@ -315,8 +309,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd)
pr_debug("mtdblock_release\n");
- mutex_lock(&mtdblks_lock);
-
mutex_lock(&mtdblk->cache_mutex);
write_cached_data(mtdblk);
mutex_unlock(&mtdblk->cache_mutex);
@@ -331,8 +323,6 @@ static void mtdblock_release(struct mtd_blktrans_dev *mbd)
vfree(mtdblk->cache_data);
}
- mutex_unlock(&mtdblks_lock);
-
pr_debug("ok\n");
}
diff --git a/drivers/mtd/mtdchar.c b/drivers/mtd/mtdchar.c
index 53563955931b..55fa27ecf4e1 100644
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -49,7 +49,6 @@ static DEFINE_MUTEX(mtd_mutex);
*/
struct mtd_file_info {
struct mtd_info *mtd;
- struct inode *ino;
enum mtd_file_modes mode;
};
@@ -59,10 +58,6 @@ static loff_t mtdchar_lseek(struct file *file, loff_t offset, int orig)
return fixed_size_llseek(file, offset, orig, mfi->mtd->size);
}
-static int count;
-static struct vfsmount *mnt;
-static struct file_system_type mtd_inodefs_type;
-
static int mtdchar_open(struct inode *inode, struct file *file)
{
int minor = iminor(inode);
@@ -70,7 +65,6 @@ static int mtdchar_open(struct inode *inode, struct file *file)
int ret = 0;
struct mtd_info *mtd;
struct mtd_file_info *mfi;
- struct inode *mtd_ino;
pr_debug("MTD_open\n");
@@ -78,10 +72,6 @@ static int mtdchar_open(struct inode *inode, struct file *file)
if ((file->f_mode & FMODE_WRITE) && (minor & 1))
return -EACCES;
- ret = simple_pin_fs(&mtd_inodefs_type, &mnt, &count);
- if (ret)
- return ret;
-
mutex_lock(&mtd_mutex);
mtd = get_mtd_device(NULL, devnum);
@@ -95,43 +85,26 @@ static int mtdchar_open(struct inode *inode, struct file *file)
goto out1;
}
- mtd_ino = iget_locked(mnt->mnt_sb, devnum);
- if (!mtd_ino) {
- ret = -ENOMEM;
- goto out1;
- }
- if (mtd_ino->i_state & I_NEW) {
- mtd_ino->i_private = mtd;
- mtd_ino->i_mode = S_IFCHR;
- mtd_ino->i_data.backing_dev_info = mtd->backing_dev_info;
- unlock_new_inode(mtd_ino);
- }
- file->f_mapping = mtd_ino->i_mapping;
-
/* You can't open it RW if it's not a writeable device */
if ((file->f_mode & FMODE_WRITE) && !(mtd->flags & MTD_WRITEABLE)) {
ret = -EACCES;
- goto out2;
+ goto out1;
}
mfi = kzalloc(sizeof(*mfi), GFP_KERNEL);
if (!mfi) {
ret = -ENOMEM;
- goto out2;
+ goto out1;
}
- mfi->ino = mtd_ino;
mfi->mtd = mtd;
file->private_data = mfi;
mutex_unlock(&mtd_mutex);
return 0;
-out2:
- iput(mtd_ino);
out1:
put_mtd_device(mtd);
out:
mutex_unlock(&mtd_mutex);
- simple_release_fs(&mnt, &count);
return ret;
} /* mtdchar_open */
@@ -148,12 +121,9 @@ static int mtdchar_close(struct inode *inode, struct file *file)
if ((file->f_mode & FMODE_WRITE))
mtd_sync(mtd);
- iput(mfi->ino);
-
put_mtd_device(mtd);
file->private_data = NULL;
kfree(mfi);
- simple_release_fs(&mnt, &count);
return 0;
} /* mtdchar_close */
@@ -1117,6 +1087,13 @@ static unsigned long mtdchar_get_unmapped_area(struct file *file,
ret = mtd_get_unmapped_area(mtd, len, offset, flags);
return ret == -EOPNOTSUPP ? -ENODEV : ret;
}
+
+static unsigned mtdchar_mmap_capabilities(struct file *file)
+{
+ struct mtd_file_info *mfi = file->private_data;
+
+ return mtd_mmap_capabilities(mfi->mtd);
+}
#endif
/*
@@ -1160,27 +1137,10 @@ static const struct file_operations mtd_fops = {
.mmap = mtdchar_mmap,
#ifndef CONFIG_MMU
.get_unmapped_area = mtdchar_get_unmapped_area,
+ .mmap_capabilities = mtdchar_mmap_capabilities,
#endif
};
-static const struct super_operations mtd_ops = {
- .drop_inode = generic_delete_inode,
- .statfs = simple_statfs,
-};
-
-static struct dentry *mtd_inodefs_mount(struct file_system_type *fs_type,
- int flags, const char *dev_name, void *data)
-{
- return mount_pseudo(fs_type, "mtd_inode:", &mtd_ops, NULL, MTD_INODE_FS_MAGIC);
-}
-
-static struct file_system_type mtd_inodefs_type = {
- .name = "mtd_inodefs",
- .mount = mtd_inodefs_mount,
- .kill_sb = kill_anon_super,
-};
-MODULE_ALIAS_FS("mtd_inodefs");
-
int __init init_mtdchar(void)
{
int ret;
@@ -1193,23 +1153,11 @@ int __init init_mtdchar(void)
return ret;
}
- ret = register_filesystem(&mtd_inodefs_type);
- if (ret) {
- pr_err("Can't register mtd_inodefs filesystem, error %d\n",
- ret);
- goto err_unregister_chdev;
- }
-
- return ret;
-
-err_unregister_chdev:
- __unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
return ret;
}
void __exit cleanup_mtdchar(void)
{
- unregister_filesystem(&mtd_inodefs_type);
__unregister_chrdev(MTD_CHAR_MAJOR, 0, 1 << MINORBITS, "mtd");
}
diff --git a/drivers/mtd/mtdconcat.c b/drivers/mtd/mtdconcat.c
index b9000563b9f4..239a8c806b67 100644
--- a/drivers/mtd/mtdconcat.c
+++ b/drivers/mtd/mtdconcat.c
@@ -311,7 +311,8 @@ concat_write_oob(struct mtd_info *mtd, loff_t to, struct mtd_oob_ops *ops)
devops.len = subdev->size - to;
err = mtd_write_oob(subdev, to, &devops);
- ops->retlen += devops.oobretlen;
+ ops->retlen += devops.retlen;
+ ops->oobretlen += devops.oobretlen;
if (err)
return err;
@@ -732,8 +733,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
concat->mtd.ecc_stats.badblocks = subdev[0]->ecc_stats.badblocks;
- concat->mtd.backing_dev_info = subdev[0]->backing_dev_info;
-
concat->subdev[0] = subdev[0];
for (i = 1; i < num_devs; i++) {
@@ -761,14 +760,6 @@ struct mtd_info *mtd_concat_create(struct mtd_info *subdev[], /* subdevices to c
subdev[i]->flags & MTD_WRITEABLE;
}
- /* only permit direct mapping if the BDIs are all the same
- * - copy-mapping is still permitted
- */
- if (concat->mtd.backing_dev_info !=
- subdev[i]->backing_dev_info)
- concat->mtd.backing_dev_info =
- &default_backing_dev_info;
-
concat->mtd.size += subdev[i]->size;
concat->mtd.ecc_stats.badblocks +=
subdev[i]->ecc_stats.badblocks;
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
index 4c611871d7e6..11883bd26d9d 100644
--- a/drivers/mtd/mtdcore.c
+++ b/drivers/mtd/mtdcore.c
@@ -37,39 +37,14 @@
#include <linux/backing-dev.h>
#include <linux/gfp.h>
#include <linux/slab.h>
+#include <linux/reboot.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include "mtdcore.h"
-/*
- * backing device capabilities for non-mappable devices (such as NAND flash)
- * - permits private mappings, copies are taken of the data
- */
-static struct backing_dev_info mtd_bdi_unmappable = {
- .capabilities = BDI_CAP_MAP_COPY,
-};
-
-/*
- * backing device capabilities for R/O mappable devices (such as ROM)
- * - permits private mappings, copies are taken of the data
- * - permits non-writable shared mappings
- */
-static struct backing_dev_info mtd_bdi_ro_mappable = {
- .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
- BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP),
-};
-
-/*
- * backing device capabilities for writable mappable devices (such as RAM)
- * - permits private mappings, copies are taken of the data
- * - permits non-writable shared mappings
- */
-static struct backing_dev_info mtd_bdi_rw_mappable = {
- .capabilities = (BDI_CAP_MAP_COPY | BDI_CAP_MAP_DIRECT |
- BDI_CAP_EXEC_MAP | BDI_CAP_READ_MAP |
- BDI_CAP_WRITE_MAP),
+static struct backing_dev_info mtd_bdi = {
};
static int mtd_cls_suspend(struct device *dev, pm_message_t state);
@@ -365,6 +340,34 @@ static struct device_type mtd_devtype = {
.release = mtd_release,
};
+#ifndef CONFIG_MMU
+unsigned mtd_mmap_capabilities(struct mtd_info *mtd)
+{
+ switch (mtd->type) {
+ case MTD_RAM:
+ return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_EXEC |
+ NOMMU_MAP_READ | NOMMU_MAP_WRITE;
+ case MTD_ROM:
+ return NOMMU_MAP_COPY | NOMMU_MAP_DIRECT | NOMMU_MAP_EXEC |
+ NOMMU_MAP_READ;
+ default:
+ return NOMMU_MAP_COPY;
+ }
+}
+EXPORT_SYMBOL_GPL(mtd_mmap_capabilities);
+#endif
+
+static int mtd_reboot_notifier(struct notifier_block *n, unsigned long state,
+ void *cmd)
+{
+ struct mtd_info *mtd;
+
+ mtd = container_of(n, struct mtd_info, reboot_notifier);
+ mtd->_reboot(mtd);
+
+ return NOTIFY_DONE;
+}
+
/**
* add_mtd_device - register an MTD device
* @mtd: pointer to new MTD device info structure
@@ -380,19 +383,7 @@ int add_mtd_device(struct mtd_info *mtd)
struct mtd_notifier *not;
int i, error;
- if (!mtd->backing_dev_info) {
- switch (mtd->type) {
- case MTD_RAM:
- mtd->backing_dev_info = &mtd_bdi_rw_mappable;
- break;
- case MTD_ROM:
- mtd->backing_dev_info = &mtd_bdi_ro_mappable;
- break;
- default:
- mtd->backing_dev_info = &mtd_bdi_unmappable;
- break;
- }
- }
+ mtd->backing_dev_info = &mtd_bdi;
BUG_ON(mtd->writesize == 0);
mutex_lock(&mtd_table_mutex);
@@ -565,6 +556,19 @@ int mtd_device_parse_register(struct mtd_info *mtd, const char * const *types,
err = -ENODEV;
}
+ /*
+ * FIXME: some drivers unfortunately call this function more than once.
+ * So we have to check if we've already assigned the reboot notifier.
+ *
+ * Generally, we can make multiple calls work for most cases, but it
+ * does cause problems with parse_mtd_partitions() above (e.g.,
+ * cmdlineparts will register partitions more than once).
+ */
+ if (mtd->_reboot && !mtd->reboot_notifier.notifier_call) {
+ mtd->reboot_notifier.notifier_call = mtd_reboot_notifier;
+ register_reboot_notifier(&mtd->reboot_notifier);
+ }
+
return err;
}
EXPORT_SYMBOL_GPL(mtd_device_parse_register);
@@ -579,6 +583,9 @@ int mtd_device_unregister(struct mtd_info *master)
{
int err;
+ if (master->_reboot)
+ unregister_reboot_notifier(&master->reboot_notifier);
+
err = del_mtd_partitions(master);
if (err)
return err;
@@ -1237,17 +1244,9 @@ static int __init init_mtd(void)
if (ret)
goto err_reg;
- ret = mtd_bdi_init(&mtd_bdi_unmappable, "mtd-unmap");
- if (ret)
- goto err_bdi1;
-
- ret = mtd_bdi_init(&mtd_bdi_ro_mappable, "mtd-romap");
- if (ret)
- goto err_bdi2;
-
- ret = mtd_bdi_init(&mtd_bdi_rw_mappable, "mtd-rwmap");
+ ret = mtd_bdi_init(&mtd_bdi, "mtd");
if (ret)
- goto err_bdi3;
+ goto err_bdi;
proc_mtd = proc_create("mtd", 0, NULL, &mtd_proc_ops);
@@ -1260,11 +1259,7 @@ static int __init init_mtd(void)
out_procfs:
if (proc_mtd)
remove_proc_entry("mtd", NULL);
-err_bdi3:
- bdi_destroy(&mtd_bdi_ro_mappable);
-err_bdi2:
- bdi_destroy(&mtd_bdi_unmappable);
-err_bdi1:
+err_bdi:
class_unregister(&mtd_class);
err_reg:
pr_err("Error registering mtd class or bdi: %d\n", ret);
@@ -1277,9 +1272,7 @@ static void __exit cleanup_mtd(void)
if (proc_mtd)
remove_proc_entry("mtd", NULL);
class_unregister(&mtd_class);
- bdi_destroy(&mtd_bdi_unmappable);
- bdi_destroy(&mtd_bdi_ro_mappable);
- bdi_destroy(&mtd_bdi_rw_mappable);
+ bdi_destroy(&mtd_bdi);
}
module_init(init_mtd);
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
index a3e3a7d074d5..e779de315ade 100644
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -378,7 +378,6 @@ static struct mtd_part *allocate_partition(struct mtd_info *master,
slave->mtd.name = name;
slave->mtd.owner = master->owner;
- slave->mtd.backing_dev_info = master->backing_dev_info;
/* NOTE: we don't arrange MTDs as a tree; it'd be error-prone
* to have the same data be in two different partitions.
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 7d0150d20432..5b76a173cd95 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -421,7 +421,7 @@ config MTD_NAND_ORION
config MTD_NAND_FSL_ELBC
tristate "NAND support for Freescale eLBC controllers"
- depends on PPC_OF
+ depends on PPC
select FSL_LBC
help
Various Freescale chips, including the 8313, include a NAND Flash
@@ -524,4 +524,9 @@ config MTD_NAND_SUNXI
help
Enables support for NAND Flash chips on Allwinner SoCs.
+config MTD_NAND_HISI504
+ tristate "Support for NAND controller on Hisilicon SoC Hip04"
+ help
+ Enables support for NAND controller on Hisilicon SoC Hip04.
+
endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index bd38f21d2e28..582bbd05aff7 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -51,5 +51,6 @@ obj-$(CONFIG_MTD_NAND_GPMI_NAND) += gpmi-nand/
obj-$(CONFIG_MTD_NAND_XWAY) += xway_nand.o
obj-$(CONFIG_MTD_NAND_BCM47XXNFLASH) += bcm47xxnflash/
obj-$(CONFIG_MTD_NAND_SUNXI) += sunxi_nand.o
+obj-$(CONFIG_MTD_NAND_HISI504) += hisi504_nand.o
nand-objs := nand_base.o nand_bbt.o nand_timings.o
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
index f1d555cfb332..842f8fe91b56 100644
--- a/drivers/mtd/nand/ams-delta.c
+++ b/drivers/mtd/nand/ams-delta.c
@@ -183,7 +183,7 @@ static int ams_delta_init(struct platform_device *pdev)
return -ENXIO;
/* Allocate memory for MTD device structure and private data */
- ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
+ ams_delta_mtd = kzalloc(sizeof(struct mtd_info) +
sizeof(struct nand_chip), GFP_KERNEL);
if (!ams_delta_mtd) {
printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
@@ -196,10 +196,6 @@ static int ams_delta_init(struct platform_device *pdev)
/* Get pointer to private data */
this = (struct nand_chip *) (&ams_delta_mtd[1]);
- /* Initialize structures */
- memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
- memset(this, 0, sizeof(struct nand_chip));
-
/* Link the private data with the MTD structure */
ams_delta_mtd->priv = this;
diff --git a/drivers/mtd/nand/atmel_nand.c b/drivers/mtd/nand/atmel_nand.c
index a345e7b2463a..d93c849b70b5 100644
--- a/drivers/mtd/nand/atmel_nand.c
+++ b/drivers/mtd/nand/atmel_nand.c
@@ -63,6 +63,10 @@ module_param(on_flash_bbt, int, 0);
#include "atmel_nand_ecc.h" /* Hardware ECC registers */
#include "atmel_nand_nfc.h" /* Nand Flash Controller definition */
+struct atmel_nand_caps {
+ bool pmecc_correct_erase_page;
+};
+
/* oob layout for large page size
* bad block info is on bytes 0 and 1
* the bytes have to be consecutives to avoid
@@ -124,6 +128,7 @@ struct atmel_nand_host {
struct atmel_nfc *nfc;
+ struct atmel_nand_caps *caps;
bool has_pmecc;
u8 pmecc_corr_cap;
u16 pmecc_sector_size;
@@ -847,7 +852,11 @@ static int pmecc_correction(struct mtd_info *mtd, u32 pmecc_stat, uint8_t *buf,
struct atmel_nand_host *host = nand_chip->priv;
int i, err_nbr;
uint8_t *buf_pos;
- int total_err = 0;
+ int max_bitflips = 0;
+
+ /* If can correct bitfilps from erased page, do the normal check */
+ if (host->caps->pmecc_correct_erase_page)
+ goto normal_check;
for (i = 0; i < nand_chip->ecc.total; i++)
if (ecc[i] != 0xff)
@@ -874,13 +883,13 @@ normal_check:
pmecc_correct_data(mtd, buf_pos, ecc, i,
nand_chip->ecc.bytes, err_nbr);
mtd->ecc_stats.corrected += err_nbr;
- total_err += err_nbr;
+ max_bitflips = max_t(int, max_bitflips, err_nbr);
}
}
pmecc_stat >>= 1;
}
- return total_err;
+ return max_bitflips;
}
static void pmecc_enable(struct atmel_nand_host *host, int ecc_op)
@@ -1474,6 +1483,8 @@ static void atmel_nand_hwctl(struct mtd_info *mtd, int mode)
ecc_writel(host->ecc, CR, ATMEL_ECC_RST);
}
+static const struct of_device_id atmel_nand_dt_ids[];
+
static int atmel_of_init_port(struct atmel_nand_host *host,
struct device_node *np)
{
@@ -1483,6 +1494,9 @@ static int atmel_of_init_port(struct atmel_nand_host *host,
struct atmel_nand_data *board = &host->board;
enum of_gpio_flags flags = 0;
+ host->caps = (struct atmel_nand_caps *)
+ of_match_device(atmel_nand_dt_ids, host->dev)->data;
+
if (of_property_read_u32(np, "atmel,nand-addr-offset", &val) == 0) {
if (val >= 32) {
dev_err(host->dev, "invalid addr-offset %u\n", val);
@@ -2288,8 +2302,17 @@ static int atmel_nand_remove(struct platform_device *pdev)
return 0;
}
+static struct atmel_nand_caps at91rm9200_caps = {
+ .pmecc_correct_erase_page = false,
+};
+
+static struct atmel_nand_caps sama5d4_caps = {
+ .pmecc_correct_erase_page = true,
+};
+
static const struct of_device_id atmel_nand_dt_ids[] = {
- { .compatible = "atmel,at91rm9200-nand" },
+ { .compatible = "atmel,at91rm9200-nand", .data = &at91rm9200_caps },
+ { .compatible = "atmel,sama5d4-nand", .data = &sama5d4_caps },
{ /* sentinel */ }
};
diff --git a/drivers/mtd/nand/denali.c b/drivers/mtd/nand/denali.c
index b3b7ca1bafb8..f44c6061536a 100644
--- a/drivers/mtd/nand/denali.c
+++ b/drivers/mtd/nand/denali.c
@@ -1041,7 +1041,7 @@ static void denali_setup_dma(struct denali_nand_info *denali, int op)
index_addr(denali, mode | ((addr >> 16) << 8), 0x2200);
/* 3. set memory low address bits 23:8 */
- index_addr(denali, mode | ((addr & 0xff) << 8), 0x2300);
+ index_addr(denali, mode | ((addr & 0xffff) << 8), 0x2300);
/* 4. interrupt when complete, burst len = 64 bytes */
index_addr(denali, mode | 0x14000, 0x2400);
@@ -1328,35 +1328,6 @@ static void denali_cmdfunc(struct mtd_info *mtd, unsigned int cmd, int col,
break;
}
}
-
-/* stubs for ECC functions not used by the NAND core */
-static int denali_ecc_calculate(struct mtd_info *mtd, const uint8_t *data,
- uint8_t *ecc_code)
-{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
-
- dev_err(denali->dev, "denali_ecc_calculate called unexpectedly\n");
- BUG();
- return -EIO;
-}
-
-static int denali_ecc_correct(struct mtd_info *mtd, uint8_t *data,
- uint8_t *read_ecc, uint8_t *calc_ecc)
-{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
-
- dev_err(denali->dev, "denali_ecc_correct called unexpectedly\n");
- BUG();
- return -EIO;
-}
-
-static void denali_ecc_hwctl(struct mtd_info *mtd, int mode)
-{
- struct denali_nand_info *denali = mtd_to_denali(mtd);
-
- dev_err(denali->dev, "denali_ecc_hwctl called unexpectedly\n");
- BUG();
-}
/* end NAND core entry points */
/* Initialization code to bring the device up to a known good state */
@@ -1609,15 +1580,6 @@ int denali_init(struct denali_nand_info *denali)
denali->totalblks = denali->mtd.size >> denali->nand.phys_erase_shift;
denali->blksperchip = denali->totalblks / denali->nand.numchips;
- /*
- * These functions are required by the NAND core framework, otherwise,
- * the NAND core will assert. However, we don't need them, so we'll stub
- * them out.
- */
- denali->nand.ecc.calculate = denali_ecc_calculate;
- denali->nand.ecc.correct = denali_ecc_correct;
- denali->nand.ecc.hwctl = denali_ecc_hwctl;
-
/* override the default read operations */
denali->nand.ecc.size = ECC_SECTOR_SIZE * denali->devnum;
denali->nand.ecc.read_page = denali_read_page;
diff --git a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
index 4f3851a24bb2..33f3c3c54dbc 100644
--- a/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
+++ b/drivers/mtd/nand/gpmi-nand/gpmi-nand.c
@@ -1294,14 +1294,6 @@ exit_auxiliary:
* ecc.read_page or ecc.read_page_raw function. Thus, the fact that MTD wants an
* ECC-based or raw view of the page is implicit in which function it calls
* (there is a similar pair of ECC-based/raw functions for writing).
- *
- * FIXME: The following paragraph is incorrect, now that there exist
- * ecc.read_oob_raw and ecc.write_oob_raw functions.
- *
- * Since MTD assumes the OOB is not covered by ECC, there is no pair of
- * ECC-based/raw functions for reading or or writing the OOB. The fact that the
- * caller wants an ECC-based or raw view of the page is not propagated down to
- * this driver.
*/
static int gpmi_ecc_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
int page)
@@ -2029,7 +2021,6 @@ static int gpmi_nand_probe(struct platform_device *pdev)
exit_nfc_init:
release_resources(this);
exit_acquire_resources:
- dev_err(this->dev, "driver registration failed: %d\n", ret);
return ret;
}
diff --git a/drivers/mtd/nand/hisi504_nand.c b/drivers/mtd/nand/hisi504_nand.c
new file mode 100644
index 000000000000..289ad3ac3e80
--- /dev/null
+++ b/drivers/mtd/nand/hisi504_nand.c
@@ -0,0 +1,891 @@
+/*
+ * Hisilicon NAND Flash controller driver
+ *
+ * Copyright © 2012-2014 HiSilicon Technologies Co., Ltd.
+ * http://www.hisilicon.com
+ *
+ * Author: Zhou Wang <wangzhou.bry@gmail.com>
+ * The initial developer of the original code is Zhiyong Cai
+ * <caizhiyong@huawei.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#include <linux/of.h>
+#include <linux/of_mtd.h>
+#include <linux/mtd/mtd.h>
+#include <linux/sizes.h>
+#include <linux/clk.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/mtd/nand.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/mtd/partitions.h>
+
+#define HINFC504_MAX_CHIP (4)
+#define HINFC504_W_LATCH (5)
+#define HINFC504_R_LATCH (7)
+#define HINFC504_RW_LATCH (3)
+
+#define HINFC504_NFC_TIMEOUT (2 * HZ)
+#define HINFC504_NFC_PM_TIMEOUT (1 * HZ)
+#define HINFC504_NFC_DMA_TIMEOUT (5 * HZ)
+#define HINFC504_CHIP_DELAY (25)
+
+#define HINFC504_REG_BASE_ADDRESS_LEN (0x100)
+#define HINFC504_BUFFER_BASE_ADDRESS_LEN (2048 + 128)
+
+#define HINFC504_ADDR_CYCLE_MASK 0x4
+
+#define HINFC504_CON 0x00
+#define HINFC504_CON_OP_MODE_NORMAL BIT(0)
+#define HINFC504_CON_PAGEISZE_SHIFT (1)
+#define HINFC504_CON_PAGESIZE_MASK (0x07)
+#define HINFC504_CON_BUS_WIDTH BIT(4)
+#define HINFC504_CON_READY_BUSY_SEL BIT(8)
+#define HINFC504_CON_ECCTYPE_SHIFT (9)
+#define HINFC504_CON_ECCTYPE_MASK (0x07)
+
+#define HINFC504_PWIDTH 0x04
+#define SET_HINFC504_PWIDTH(_w_lcnt, _r_lcnt, _rw_hcnt) \
+ ((_w_lcnt) | (((_r_lcnt) & 0x0F) << 4) | (((_rw_hcnt) & 0x0F) << 8))
+
+#define HINFC504_CMD 0x0C
+#define HINFC504_ADDRL 0x10
+#define HINFC504_ADDRH 0x14
+#define HINFC504_DATA_NUM 0x18
+
+#define HINFC504_OP 0x1C
+#define HINFC504_OP_READ_DATA_EN BIT(1)
+#define HINFC504_OP_WAIT_READY_EN BIT(2)
+#define HINFC504_OP_CMD2_EN BIT(3)
+#define HINFC504_OP_WRITE_DATA_EN BIT(4)
+#define HINFC504_OP_ADDR_EN BIT(5)
+#define HINFC504_OP_CMD1_EN BIT(6)
+#define HINFC504_OP_NF_CS_SHIFT (7)
+#define HINFC504_OP_NF_CS_MASK (3)
+#define HINFC504_OP_ADDR_CYCLE_SHIFT (9)
+#define HINFC504_OP_ADDR_CYCLE_MASK (7)
+
+#define HINFC504_STATUS 0x20
+#define HINFC504_READY BIT(0)
+
+#define HINFC504_INTEN 0x24
+#define HINFC504_INTEN_DMA BIT(9)
+#define HINFC504_INTEN_UE BIT(6)
+#define HINFC504_INTEN_CE BIT(5)
+
+#define HINFC504_INTS 0x28
+#define HINFC504_INTS_DMA BIT(9)
+#define HINFC504_INTS_UE BIT(6)
+#define HINFC504_INTS_CE BIT(5)
+
+#define HINFC504_INTCLR 0x2C
+#define HINFC504_INTCLR_DMA BIT(9)
+#define HINFC504_INTCLR_UE BIT(6)
+#define HINFC504_INTCLR_CE BIT(5)
+
+#define HINFC504_ECC_STATUS 0x5C
+#define HINFC504_ECC_16_BIT_SHIFT 12
+
+#define HINFC504_DMA_CTRL 0x60
+#define HINFC504_DMA_CTRL_DMA_START BIT(0)
+#define HINFC504_DMA_CTRL_WE BIT(1)
+#define HINFC504_DMA_CTRL_DATA_AREA_EN BIT(2)
+#define HINFC504_DMA_CTRL_OOB_AREA_EN BIT(3)
+#define HINFC504_DMA_CTRL_BURST4_EN BIT(4)
+#define HINFC504_DMA_CTRL_BURST8_EN BIT(5)
+#define HINFC504_DMA_CTRL_BURST16_EN BIT(6)
+#define HINFC504_DMA_CTRL_ADDR_NUM_SHIFT (7)
+#define HINFC504_DMA_CTRL_ADDR_NUM_MASK (1)
+#define HINFC504_DMA_CTRL_CS_SHIFT (8)
+#define HINFC504_DMA_CTRL_CS_MASK (0x03)
+
+#define HINFC504_DMA_ADDR_DATA 0x64
+#define HINFC504_DMA_ADDR_OOB 0x68
+
+#define HINFC504_DMA_LEN 0x6C
+#define HINFC504_DMA_LEN_OOB_SHIFT (16)
+#define HINFC504_DMA_LEN_OOB_MASK (0xFFF)
+
+#define HINFC504_DMA_PARA 0x70
+#define HINFC504_DMA_PARA_DATA_RW_EN BIT(0)
+#define HINFC504_DMA_PARA_OOB_RW_EN BIT(1)
+#define HINFC504_DMA_PARA_DATA_EDC_EN BIT(2)
+#define HINFC504_DMA_PARA_OOB_EDC_EN BIT(3)
+#define HINFC504_DMA_PARA_DATA_ECC_EN BIT(4)
+#define HINFC504_DMA_PARA_OOB_ECC_EN BIT(5)
+
+#define HINFC_VERSION 0x74
+#define HINFC504_LOG_READ_ADDR 0x7C
+#define HINFC504_LOG_READ_LEN 0x80
+
+#define HINFC504_NANDINFO_LEN 0x10
+
+struct hinfc_host {
+ struct nand_chip chip;
+ struct mtd_info mtd;
+ struct device *dev;
+ void __iomem *iobase;
+ void __iomem *mmio;
+ struct completion cmd_complete;
+ unsigned int offset;
+ unsigned int command;
+ int chipselect;
+ unsigned int addr_cycle;
+ u32 addr_value[2];
+ u32 cache_addr_value[2];
+ char *buffer;
+ dma_addr_t dma_buffer;
+ dma_addr_t dma_oob;
+ int version;
+ unsigned int irq_status; /* interrupt status */
+};
+
+static inline unsigned int hinfc_read(struct hinfc_host *host, unsigned int reg)
+{
+ return readl(host->iobase + reg);
+}
+
+static inline void hinfc_write(struct hinfc_host *host, unsigned int value,
+ unsigned int reg)
+{
+ writel(value, host->iobase + reg);
+}
+
+static void wait_controller_finished(struct hinfc_host *host)
+{
+ unsigned long timeout = jiffies + HINFC504_NFC_TIMEOUT;
+ int val;
+
+ while (time_before(jiffies, timeout)) {
+ val = hinfc_read(host, HINFC504_STATUS);
+ if (host->command == NAND_CMD_ERASE2) {
+ /* nfc is ready */
+ while (!(val & HINFC504_READY)) {
+ usleep_range(500, 1000);
+ val = hinfc_read(host, HINFC504_STATUS);
+ }
+ return;
+ }
+
+ if (val & HINFC504_READY)
+ return;
+ }
+
+ /* wait cmd timeout */
+ dev_err(host->dev, "Wait NAND controller exec cmd timeout.\n");
+}
+
+static void hisi_nfc_dma_transfer(struct hinfc_host *host, int todev)
+{
+ struct mtd_info *mtd = &host->mtd;
+ struct nand_chip *chip = mtd->priv;
+ unsigned long val;
+ int ret;
+
+ hinfc_write(host, host->dma_buffer, HINFC504_DMA_ADDR_DATA);
+ hinfc_write(host, host->dma_oob, HINFC504_DMA_ADDR_OOB);
+
+ if (chip->ecc.mode == NAND_ECC_NONE) {
+ hinfc_write(host, ((mtd->oobsize & HINFC504_DMA_LEN_OOB_MASK)
+ << HINFC504_DMA_LEN_OOB_SHIFT), HINFC504_DMA_LEN);
+
+ hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
+ | HINFC504_DMA_PARA_OOB_RW_EN, HINFC504_DMA_PARA);
+ } else {
+ if (host->command == NAND_CMD_READOOB)
+ hinfc_write(host, HINFC504_DMA_PARA_OOB_RW_EN
+ | HINFC504_DMA_PARA_OOB_EDC_EN
+ | HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
+ else
+ hinfc_write(host, HINFC504_DMA_PARA_DATA_RW_EN
+ | HINFC504_DMA_PARA_OOB_RW_EN
+ | HINFC504_DMA_PARA_DATA_EDC_EN
+ | HINFC504_DMA_PARA_OOB_EDC_EN
+ | HINFC504_DMA_PARA_DATA_ECC_EN
+ | HINFC504_DMA_PARA_OOB_ECC_EN, HINFC504_DMA_PARA);
+
+ }
+
+ val = (HINFC504_DMA_CTRL_DMA_START | HINFC504_DMA_CTRL_BURST4_EN
+ | HINFC504_DMA_CTRL_BURST8_EN | HINFC504_DMA_CTRL_BURST16_EN
+ | HINFC504_DMA_CTRL_DATA_AREA_EN | HINFC504_DMA_CTRL_OOB_AREA_EN
+ | ((host->addr_cycle == 4 ? 1 : 0)
+ << HINFC504_DMA_CTRL_ADDR_NUM_SHIFT)
+ | ((host->chipselect & HINFC504_DMA_CTRL_CS_MASK)
+ << HINFC504_DMA_CTRL_CS_SHIFT));
+
+ if (todev)
+ val |= HINFC504_DMA_CTRL_WE;
+
+ init_completion(&host->cmd_complete);
+
+ hinfc_write(host, val, HINFC504_DMA_CTRL);
+ ret = wait_for_completion_timeout(&host->cmd_complete,
+ HINFC504_NFC_DMA_TIMEOUT);
+
+ if (!ret) {
+ dev_err(host->dev, "DMA operation(irq) timeout!\n");
+ /* sanity check */
+ val = hinfc_read(host, HINFC504_DMA_CTRL);
+ if (!(val & HINFC504_DMA_CTRL_DMA_START))
+ dev_err(host->dev, "DMA is already done but without irq ACK!\n");
+ else
+ dev_err(host->dev, "DMA is really timeout!\n");
+ }
+}
+
+static int hisi_nfc_send_cmd_pageprog(struct hinfc_host *host)
+{
+ host->addr_value[0] &= 0xffff0000;
+
+ hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+ hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
+ hinfc_write(host, NAND_CMD_PAGEPROG << 8 | NAND_CMD_SEQIN,
+ HINFC504_CMD);
+
+ hisi_nfc_dma_transfer(host, 1);
+
+ return 0;
+}
+
+static int hisi_nfc_send_cmd_readstart(struct hinfc_host *host)
+{
+ struct mtd_info *mtd = &host->mtd;
+
+ if ((host->addr_value[0] == host->cache_addr_value[0]) &&
+ (host->addr_value[1] == host->cache_addr_value[1]))
+ return 0;
+
+ host->addr_value[0] &= 0xffff0000;
+
+ hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+ hinfc_write(host, host->addr_value[1], HINFC504_ADDRH);
+ hinfc_write(host, NAND_CMD_READSTART << 8 | NAND_CMD_READ0,
+ HINFC504_CMD);
+
+ hinfc_write(host, 0, HINFC504_LOG_READ_ADDR);
+ hinfc_write(host, mtd->writesize + mtd->oobsize,
+ HINFC504_LOG_READ_LEN);
+
+ hisi_nfc_dma_transfer(host, 0);
+
+ host->cache_addr_value[0] = host->addr_value[0];
+ host->cache_addr_value[1] = host->addr_value[1];
+
+ return 0;
+}
+
+static int hisi_nfc_send_cmd_erase(struct hinfc_host *host)
+{
+ hinfc_write(host, host->addr_value[0], HINFC504_ADDRL);
+ hinfc_write(host, (NAND_CMD_ERASE2 << 8) | NAND_CMD_ERASE1,
+ HINFC504_CMD);
+
+ hinfc_write(host, HINFC504_OP_WAIT_READY_EN
+ | HINFC504_OP_CMD2_EN
+ | HINFC504_OP_CMD1_EN
+ | HINFC504_OP_ADDR_EN
+ | ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+ << HINFC504_OP_NF_CS_SHIFT)
+ | ((host->addr_cycle & HINFC504_OP_ADDR_CYCLE_MASK)
+ << HINFC504_OP_ADDR_CYCLE_SHIFT),
+ HINFC504_OP);
+
+ wait_controller_finished(host);
+
+ return 0;
+}
+
+static int hisi_nfc_send_cmd_readid(struct hinfc_host *host)
+{
+ hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
+ hinfc_write(host, NAND_CMD_READID, HINFC504_CMD);
+ hinfc_write(host, 0, HINFC504_ADDRL);
+
+ hinfc_write(host, HINFC504_OP_CMD1_EN | HINFC504_OP_ADDR_EN
+ | HINFC504_OP_READ_DATA_EN
+ | ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+ << HINFC504_OP_NF_CS_SHIFT)
+ | 1 << HINFC504_OP_ADDR_CYCLE_SHIFT, HINFC504_OP);
+
+ wait_controller_finished(host);
+
+ return 0;
+}
+
+static int hisi_nfc_send_cmd_status(struct hinfc_host *host)
+{
+ hinfc_write(host, HINFC504_NANDINFO_LEN, HINFC504_DATA_NUM);
+ hinfc_write(host, NAND_CMD_STATUS, HINFC504_CMD);
+ hinfc_write(host, HINFC504_OP_CMD1_EN
+ | HINFC504_OP_READ_DATA_EN
+ | ((host->chipselect & HINFC504_OP_NF_CS_MASK)
+ << HINFC504_OP_NF_CS_SHIFT),
+ HINFC504_OP);
+
+ wait_controller_finished(host);
+
+ return 0;
+}
+
+static int hisi_nfc_send_cmd_reset(struct hinfc_host *host, int chipselect)
+{
+ hinfc_write(host, NAND_CMD_RESET, HINFC504_CMD);
+
+ hinfc_write(host, HINFC504_OP_CMD1_EN
+ | ((chipselect & HINFC504_OP_NF_CS_MASK)
+ << HINFC504_OP_NF_CS_SHIFT)
+ | HINFC504_OP_WAIT_READY_EN,
+ HINFC504_OP);
+
+ wait_controller_finished(host);
+
+ return 0;
+}
+
+static void hisi_nfc_select_chip(struct mtd_info *mtd, int chipselect)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+
+ if (chipselect < 0)
+ return;
+
+ host->chipselect = chipselect;
+}
+
+static uint8_t hisi_nfc_read_byte(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+
+ if (host->command == NAND_CMD_STATUS)
+ return *(uint8_t *)(host->mmio);
+
+ host->offset++;
+
+ if (host->command == NAND_CMD_READID)
+ return *(uint8_t *)(host->mmio + host->offset - 1);
+
+ return *(uint8_t *)(host->buffer + host->offset - 1);
+}
+
+static u16 hisi_nfc_read_word(struct mtd_info *mtd)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+
+ host->offset += 2;
+ return *(u16 *)(host->buffer + host->offset - 2);
+}
+
+static void
+hisi_nfc_write_buf(struct mtd_info *mtd, const uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+
+ memcpy(host->buffer + host->offset, buf, len);
+ host->offset += len;
+}
+
+static void hisi_nfc_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+
+ memcpy(buf, host->buffer + host->offset, len);
+ host->offset += len;
+}
+
+static void set_addr(struct mtd_info *mtd, int column, int page_addr)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+ unsigned int command = host->command;
+
+ host->addr_cycle = 0;
+ host->addr_value[0] = 0;
+ host->addr_value[1] = 0;
+
+ /* Serially input address */
+ if (column != -1) {
+ /* Adjust columns for 16 bit buswidth */
+ if (chip->options & NAND_BUSWIDTH_16 &&
+ !nand_opcode_8bits(command))
+ column >>= 1;
+
+ host->addr_value[0] = column & 0xffff;
+ host->addr_cycle = 2;
+ }
+ if (page_addr != -1) {
+ host->addr_value[0] |= (page_addr & 0xffff)
+ << (host->addr_cycle * 8);
+ host->addr_cycle += 2;
+ /* One more address cycle for devices > 128MiB */
+ if (chip->chipsize > (128 << 20)) {
+ host->addr_cycle += 1;
+ if (host->command == NAND_CMD_ERASE1)
+ host->addr_value[0] |= ((page_addr >> 16) & 0xff) << 16;
+ else
+ host->addr_value[1] |= ((page_addr >> 16) & 0xff);
+ }
+ }
+}
+
+static void hisi_nfc_cmdfunc(struct mtd_info *mtd, unsigned command, int column,
+ int page_addr)
+{
+ struct nand_chip *chip = mtd->priv;
+ struct hinfc_host *host = chip->priv;
+ int is_cache_invalid = 1;
+ unsigned int flag = 0;
+
+ host->command = command;
+
+ switch (command) {
+ case NAND_CMD_READ0:
+ case NAND_CMD_READOOB:
+ if (command == NAND_CMD_READ0)
+ host->offset = column;
+ else
+ host->offset = column + mtd->writesize;
+
+ is_cache_invalid = 0;
+ set_addr(mtd, column, page_addr);
+ hisi_nfc_send_cmd_readstart(host);
+ break;
+
+ case NAND_CMD_SEQIN:
+ host->offset = column;
+ set_addr(mtd, column, page_addr);
+ break;
+
+ case NAND_CMD_ERASE1:
+ set_addr(mtd, column, page_addr);
+ break;
+
+ case NAND_CMD_PAGEPROG:
+ hisi_nfc_send_cmd_pageprog(host);
+ break;
+
+ case NAND_CMD_ERASE2:
+ hisi_nfc_send_cmd_erase(host);
+ break;
+
+ case NAND_CMD_READID:
+ host->offset = column;
+ memset(host->mmio, 0, 0x10);
+ hisi_nfc_send_cmd_readid(host);
+ break;
+
+ case NAND_CMD_STATUS:
+ flag = hinfc_read(host, HINFC504_CON);
+ if (chip->ecc.mode == NAND_ECC_HW)
+ hinfc_write(host,
+ flag & ~(HINFC504_CON_ECCTYPE_MASK <<
+ HINFC504_CON_ECCTYPE_SHIFT), HINFC504_CON);
+
+ host->offset = 0;
+ memset(host->mmio, 0, 0x10);
+ hisi_nfc_send_cmd_status(host);
+ hinfc_write(host, flag, HINFC504_CON);
+ break;
+
+ case NAND_CMD_RESET:
+ hisi_nfc_send_cmd_reset(host, host->chipselect);
+ break;
+
+ default:
+ dev_err(host->dev, "Error: unsupported cmd(cmd=%x, col=%x, page=%x)\n",
+ command, column, page_addr);
+ }
+
+ if (is_cache_invalid) {
+ host->cache_addr_value[0] = ~0;
+ host->cache_addr_value[1] = ~0;
+ }
+}
+
+static irqreturn_t hinfc_irq_handle(int irq, void *devid)
+{
+ struct hinfc_host *host = devid;
+ unsigned int flag;
+
+ flag = hinfc_read(host, HINFC504_INTS);
+ /* store interrupts state */
+ host->irq_status |= flag;
+
+ if (flag & HINFC504_INTS_DMA) {
+ hinfc_write(host, HINFC504_INTCLR_DMA, HINFC504_INTCLR);
+ complete(&host->cmd_complete);
+ } else if (flag & HINFC504_INTS_CE) {
+ hinfc_write(host, HINFC504_INTCLR_CE, HINFC504_INTCLR);
+ } else if (flag & HINFC504_INTS_UE) {
+ hinfc_write(host, HINFC504_INTCLR_UE, HINFC504_INTCLR);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int hisi_nand_read_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, uint8_t *buf, int oob_required, int page)
+{
+ struct hinfc_host *host = chip->priv;
+ int max_bitflips = 0, stat = 0, stat_max = 0, status_ecc;
+ int stat_1, stat_2;
+
+ chip->read_buf(mtd, buf, mtd->writesize);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ /* errors which can not be corrected by ECC */
+ if (host->irq_status & HINFC504_INTS_UE) {
+ mtd->ecc_stats.failed++;
+ } else if (host->irq_status & HINFC504_INTS_CE) {
+ /* TODO: need add other ECC modes! */
+ switch (chip->ecc.strength) {
+ case 16:
+ status_ecc = hinfc_read(host, HINFC504_ECC_STATUS) >>
+ HINFC504_ECC_16_BIT_SHIFT & 0x0fff;
+ stat_2 = status_ecc & 0x3f;
+ stat_1 = status_ecc >> 6 & 0x3f;
+ stat = stat_1 + stat_2;
+ stat_max = max_t(int, stat_1, stat_2);
+ }
+ mtd->ecc_stats.corrected += stat;
+ max_bitflips = max_t(int, max_bitflips, stat_max);
+ }
+ host->irq_status = 0;
+
+ return max_bitflips;
+}
+
+static int hisi_nand_read_oob(struct mtd_info *mtd, struct nand_chip *chip,
+ int page)
+{
+ struct hinfc_host *host = chip->priv;
+
+ chip->cmdfunc(mtd, NAND_CMD_READOOB, 0, page);
+ chip->read_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ if (host->irq_status & HINFC504_INTS_UE) {
+ host->irq_status = 0;
+ return -EBADMSG;
+ }
+
+ host->irq_status = 0;
+ return 0;
+}
+
+static int hisi_nand_write_page_hwecc(struct mtd_info *mtd,
+ struct nand_chip *chip, const uint8_t *buf, int oob_required)
+{
+ chip->write_buf(mtd, buf, mtd->writesize);
+ if (oob_required)
+ chip->write_buf(mtd, chip->oob_poi, mtd->oobsize);
+
+ return 0;
+}
+
+static void hisi_nfc_host_init(struct hinfc_host *host)
+{
+ struct nand_chip *chip = &host->chip;
+ unsigned int flag = 0;
+
+ host->version = hinfc_read(host, HINFC_VERSION);
+ host->addr_cycle = 0;
+ host->addr_value[0] = 0;
+ host->addr_value[1] = 0;
+ host->cache_addr_value[0] = ~0;
+ host->cache_addr_value[1] = ~0;
+ host->chipselect = 0;
+
+ /* default page size: 2K, ecc_none. need modify */
+ flag = HINFC504_CON_OP_MODE_NORMAL | HINFC504_CON_READY_BUSY_SEL
+ | ((0x001 & HINFC504_CON_PAGESIZE_MASK)
+ << HINFC504_CON_PAGEISZE_SHIFT)
+ | ((0x0 & HINFC504_CON_ECCTYPE_MASK)
+ << HINFC504_CON_ECCTYPE_SHIFT)
+ | ((chip->options & NAND_BUSWIDTH_16) ?
+ HINFC504_CON_BUS_WIDTH : 0);
+ hinfc_write(host, flag, HINFC504_CON);
+
+ memset(host->mmio, 0xff, HINFC504_BUFFER_BASE_ADDRESS_LEN);
+
+ hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
+ HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
+
+ /* enable DMA irq */
+ hinfc_write(host, HINFC504_INTEN_DMA, HINFC504_INTEN);
+}
+
+static struct nand_ecclayout nand_ecc_2K_16bits = {
+ .oobavail = 6,
+ .oobfree = { {2, 6} },
+};
+
+static int hisi_nfc_ecc_probe(struct hinfc_host *host)
+{
+ unsigned int flag;
+ int size, strength, ecc_bits;
+ struct device *dev = host->dev;
+ struct nand_chip *chip = &host->chip;
+ struct mtd_info *mtd = &host->mtd;
+ struct device_node *np = host->dev->of_node;
+
+ size = of_get_nand_ecc_step_size(np);
+ strength = of_get_nand_ecc_strength(np);
+ if (size != 1024) {
+ dev_err(dev, "error ecc size: %d\n", size);
+ return -EINVAL;
+ }
+
+ if ((size == 1024) && ((strength != 8) && (strength != 16) &&
+ (strength != 24) && (strength != 40))) {
+ dev_err(dev, "ecc size and strength do not match\n");
+ return -EINVAL;
+ }
+
+ chip->ecc.size = size;
+ chip->ecc.strength = strength;
+
+ chip->ecc.read_page = hisi_nand_read_page_hwecc;
+ chip->ecc.read_oob = hisi_nand_read_oob;
+ chip->ecc.write_page = hisi_nand_write_page_hwecc;
+
+ switch (chip->ecc.strength) {
+ case 16:
+ ecc_bits = 6;
+ if (mtd->writesize == 2048)
+ chip->ecc.layout = &nand_ecc_2K_16bits;
+
+ /* TODO: add more page size support */
+ break;
+
+ /* TODO: add more ecc strength support */
+ default:
+ dev_err(dev, "not support strength: %d\n", chip->ecc.strength);
+ return -EINVAL;
+ }
+
+ flag = hinfc_read(host, HINFC504_CON);
+ /* add ecc type configure */
+ flag |= ((ecc_bits & HINFC504_CON_ECCTYPE_MASK)
+ << HINFC504_CON_ECCTYPE_SHIFT);
+ hinfc_write(host, flag, HINFC504_CON);
+
+ /* enable ecc irq */
+ flag = hinfc_read(host, HINFC504_INTEN) & 0xfff;
+ hinfc_write(host, flag | HINFC504_INTEN_UE | HINFC504_INTEN_CE,
+ HINFC504_INTEN);
+
+ return 0;
+}
+
+static int hisi_nfc_probe(struct platform_device *pdev)
+{
+ int ret = 0, irq, buswidth, flag, max_chips = HINFC504_MAX_CHIP;
+ struct device *dev = &pdev->dev;
+ struct hinfc_host *host;
+ struct nand_chip *chip;
+ struct mtd_info *mtd;
+ struct resource *res;
+ struct device_node *np = dev->of_node;
+ struct mtd_part_parser_data ppdata;
+
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+ if (!host)
+ return -ENOMEM;
+ host->dev = dev;
+
+ platform_set_drvdata(pdev, host);
+ chip = &host->chip;
+ mtd = &host->mtd;
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(dev, "no IRQ resource defined\n");
+ ret = -ENXIO;
+ goto err_res;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ host->iobase = devm_ioremap_resource(dev, res);
+ if (IS_ERR(host->iobase)) {
+ ret = PTR_ERR(host->iobase);
+ goto err_res;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ host->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR(host->mmio)) {
+ ret = PTR_ERR(host->mmio);
+ dev_err(dev, "devm_ioremap_resource[1] fail\n");
+ goto err_res;
+ }
+
+ mtd->priv = chip;
+ mtd->owner = THIS_MODULE;
+ mtd->name = "hisi_nand";
+ mtd->dev.parent = &pdev->dev;
+
+ chip->priv = host;
+ chip->cmdfunc = hisi_nfc_cmdfunc;
+ chip->select_chip = hisi_nfc_select_chip;
+ chip->read_byte = hisi_nfc_read_byte;
+ chip->read_word = hisi_nfc_read_word;
+ chip->write_buf = hisi_nfc_write_buf;
+ chip->read_buf = hisi_nfc_read_buf;
+ chip->chip_delay = HINFC504_CHIP_DELAY;
+
+ chip->ecc.mode = of_get_nand_ecc_mode(np);
+
+ buswidth = of_get_nand_bus_width(np);
+ if (buswidth == 16)
+ chip->options |= NAND_BUSWIDTH_16;
+
+ hisi_nfc_host_init(host);
+
+ ret = devm_request_irq(dev, irq, hinfc_irq_handle, IRQF_DISABLED,
+ "nandc", host);
+ if (ret) {
+ dev_err(dev, "failed to request IRQ\n");
+ goto err_res;
+ }
+
+ ret = nand_scan_ident(mtd, max_chips, NULL);
+ if (ret) {
+ ret = -ENODEV;
+ goto err_res;
+ }
+
+ host->buffer = dmam_alloc_coherent(dev, mtd->writesize + mtd->oobsize,
+ &host->dma_buffer, GFP_KERNEL);
+ if (!host->buffer) {
+ ret = -ENOMEM;
+ goto err_res;
+ }
+
+ host->dma_oob = host->dma_buffer + mtd->writesize;
+ memset(host->buffer, 0xff, mtd->writesize + mtd->oobsize);
+
+ flag = hinfc_read(host, HINFC504_CON);
+ flag &= ~(HINFC504_CON_PAGESIZE_MASK << HINFC504_CON_PAGEISZE_SHIFT);
+ switch (mtd->writesize) {
+ case 2048:
+ flag |= (0x001 << HINFC504_CON_PAGEISZE_SHIFT); break;
+ /*
+ * TODO: add more pagesize support,
+ * default pagesize has been set in hisi_nfc_host_init
+ */
+ default:
+ dev_err(dev, "NON-2KB page size nand flash\n");
+ ret = -EINVAL;
+ goto err_res;
+ }
+ hinfc_write(host, flag, HINFC504_CON);
+
+ if (chip->ecc.mode == NAND_ECC_HW)
+ hisi_nfc_ecc_probe(host);
+
+ ret = nand_scan_tail(mtd);
+ if (ret) {
+ dev_err(dev, "nand_scan_tail failed: %d\n", ret);
+ goto err_res;
+ }
+
+ ppdata.of_node = np;
+ ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
+ if (ret) {
+ dev_err(dev, "Err MTD partition=%d\n", ret);
+ goto err_mtd;
+ }
+
+ return 0;
+
+err_mtd:
+ nand_release(mtd);
+err_res:
+ return ret;
+}
+
+static int hisi_nfc_remove(struct platform_device *pdev)
+{
+ struct hinfc_host *host = platform_get_drvdata(pdev);
+ struct mtd_info *mtd = &host->mtd;
+
+ nand_release(mtd);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int hisi_nfc_suspend(struct device *dev)
+{
+ struct hinfc_host *host = dev_get_drvdata(dev);
+ unsigned long timeout = jiffies + HINFC504_NFC_PM_TIMEOUT;
+
+ while (time_before(jiffies, timeout)) {
+ if (((hinfc_read(host, HINFC504_STATUS) & 0x1) == 0x0) &&
+ (hinfc_read(host, HINFC504_DMA_CTRL) &
+ HINFC504_DMA_CTRL_DMA_START)) {
+ cond_resched();
+ return 0;
+ }
+ }
+
+ dev_err(host->dev, "nand controller suspend timeout.\n");
+
+ return -EAGAIN;
+}
+
+static int hisi_nfc_resume(struct device *dev)
+{
+ int cs;
+ struct hinfc_host *host = dev_get_drvdata(dev);
+ struct nand_chip *chip = &host->chip;
+
+ for (cs = 0; cs < chip->numchips; cs++)
+ hisi_nfc_send_cmd_reset(host, cs);
+ hinfc_write(host, SET_HINFC504_PWIDTH(HINFC504_W_LATCH,
+ HINFC504_R_LATCH, HINFC504_RW_LATCH), HINFC504_PWIDTH);
+
+ return 0;
+}
+#endif
+static SIMPLE_DEV_PM_OPS(hisi_nfc_pm_ops, hisi_nfc_suspend, hisi_nfc_resume);
+
+static const struct of_device_id nfc_id_table[] = {
+ { .compatible = "hisilicon,504-nfc" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, nfc_id_table);
+
+static struct platform_driver hisi_nfc_driver = {
+ .driver = {
+ .name = "hisi_nand",
+ .of_match_table = nfc_id_table,
+ .pm = &hisi_nfc_pm_ops,
+ },
+ .probe = hisi_nfc_probe,
+ .remove = hisi_nfc_remove,
+};
+
+module_platform_driver(hisi_nfc_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Zhou Wang");
+MODULE_AUTHOR("Zhiyong Cai");
+MODULE_DESCRIPTION("Hisilicon Nand Flash Controller Driver");
diff --git a/drivers/mtd/nand/jz4740_nand.c b/drivers/mtd/nand/jz4740_nand.c
index 1633ec9c5108..ebf2cce04cba 100644
--- a/drivers/mtd/nand/jz4740_nand.c
+++ b/drivers/mtd/nand/jz4740_nand.c
@@ -69,7 +69,7 @@ struct jz_nand {
int selected_bank;
- struct jz_nand_platform_data *pdata;
+ struct gpio_desc *busy_gpio;
bool is_reading;
};
@@ -131,7 +131,7 @@ static void jz_nand_cmd_ctrl(struct mtd_info *mtd, int dat, unsigned int ctrl)
static int jz_nand_dev_ready(struct mtd_info *mtd)
{
struct jz_nand *nand = mtd_to_jz_nand(mtd);
- return gpio_get_value_cansleep(nand->pdata->busy_gpio);
+ return gpiod_get_value_cansleep(nand->busy_gpio);
}
static void jz_nand_hwctl(struct mtd_info *mtd, int mode)
@@ -423,14 +423,12 @@ static int jz_nand_probe(struct platform_device *pdev)
if (ret)
goto err_free;
- if (pdata && gpio_is_valid(pdata->busy_gpio)) {
- ret = gpio_request(pdata->busy_gpio, "NAND busy pin");
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to request busy gpio %d: %d\n",
- pdata->busy_gpio, ret);
- goto err_iounmap_mmio;
- }
+ nand->busy_gpio = devm_gpiod_get_optional(&pdev->dev, "busy", GPIOD_IN);
+ if (IS_ERR(nand->busy_gpio)) {
+ ret = PTR_ERR(nand->busy_gpio);
+ dev_err(&pdev->dev, "Failed to request busy gpio %d\n",
+ ret);
+ goto err_iounmap_mmio;
}
mtd = &nand->mtd;
@@ -454,10 +452,9 @@ static int jz_nand_probe(struct platform_device *pdev)
chip->cmd_ctrl = jz_nand_cmd_ctrl;
chip->select_chip = jz_nand_select_chip;
- if (pdata && gpio_is_valid(pdata->busy_gpio))
+ if (nand->busy_gpio)
chip->dev_ready = jz_nand_dev_ready;
- nand->pdata = pdata;
platform_set_drvdata(pdev, nand);
/* We are going to autodetect NAND chips in the banks specified in the
@@ -496,7 +493,7 @@ static int jz_nand_probe(struct platform_device *pdev)
}
if (chipnr == 0) {
dev_err(&pdev->dev, "No NAND chips found\n");
- goto err_gpio_busy;
+ goto err_iounmap_mmio;
}
if (pdata && pdata->ident_callback) {
@@ -533,9 +530,6 @@ err_unclaim_banks:
nand->bank_base[bank - 1]);
}
writel(0, nand->base + JZ_REG_NAND_CTRL);
-err_gpio_busy:
- if (pdata && gpio_is_valid(pdata->busy_gpio))
- gpio_free(pdata->busy_gpio);
err_iounmap_mmio:
jz_nand_iounmap_resource(nand->mem, nand->base);
err_free:
@@ -546,7 +540,6 @@ err_free:
static int jz_nand_remove(struct platform_device *pdev)
{
struct jz_nand *nand = platform_get_drvdata(pdev);
- struct jz_nand_platform_data *pdata = dev_get_platdata(&pdev->dev);
size_t i;
nand_release(&nand->mtd);
@@ -562,8 +555,6 @@ static int jz_nand_remove(struct platform_device *pdev)
gpio_free(JZ_GPIO_MEM_CS0 + bank - 1);
}
}
- if (pdata && gpio_is_valid(pdata->busy_gpio))
- gpio_free(pdata->busy_gpio);
jz_nand_iounmap_resource(nand->mem, nand->base);
diff --git a/drivers/mtd/nand/nand_base.c b/drivers/mtd/nand/nand_base.c
index 41585dfb206f..df7eb4ff07d1 100644
--- a/drivers/mtd/nand/nand_base.c
+++ b/drivers/mtd/nand/nand_base.c
@@ -157,7 +157,6 @@ static uint8_t nand_read_byte(struct mtd_info *mtd)
/**
* nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
- * nand_read_byte16 - [DEFAULT] read one byte endianness aware from the chip
* @mtd: MTD device structure
*
* Default read function for 16bit buswidth with endianness conversion.
@@ -1751,11 +1750,10 @@ static int nand_read_oob_std(struct mtd_info *mtd, struct nand_chip *chip,
static int nand_read_oob_syndrome(struct mtd_info *mtd, struct nand_chip *chip,
int page)
{
- uint8_t *buf = chip->oob_poi;
int length = mtd->oobsize;
int chunk = chip->ecc.bytes + chip->ecc.prepad + chip->ecc.postpad;
int eccsize = chip->ecc.size;
- uint8_t *bufpoi = buf;
+ uint8_t *bufpoi = chip->oob_poi;
int i, toread, sndrnd = 0, pos;
chip->cmdfunc(mtd, NAND_CMD_READ0, chip->ecc.size, page);
@@ -2944,6 +2942,16 @@ static void nand_resume(struct mtd_info *mtd)
__func__);
}
+/**
+ * nand_shutdown - [MTD Interface] Finish the current NAND operation and
+ * prevent further operations
+ * @mtd: MTD device structure
+ */
+static void nand_shutdown(struct mtd_info *mtd)
+{
+ nand_get_device(mtd, FL_SHUTDOWN);
+}
+
/* Set default functions */
static void nand_set_defaults(struct nand_chip *chip, int busw)
{
@@ -4028,22 +4036,24 @@ int nand_scan_tail(struct mtd_info *mtd)
ecc->read_oob = nand_read_oob_std;
ecc->write_oob = nand_write_oob_std;
/*
- * Board driver should supply ecc.size and ecc.bytes values to
- * select how many bits are correctable; see nand_bch_init()
- * for details. Otherwise, default to 4 bits for large page
- * devices.
+ * Board driver should supply ecc.size and ecc.strength values
+ * to select how many bits are correctable. Otherwise, default
+ * to 4 bits for large page devices.
*/
if (!ecc->size && (mtd->oobsize >= 64)) {
ecc->size = 512;
- ecc->bytes = DIV_ROUND_UP(13 * ecc->strength, 8);
+ ecc->strength = 4;
}
+
+ /* See nand_bch_init() for details. */
+ ecc->bytes = DIV_ROUND_UP(
+ ecc->strength * fls(8 * ecc->size), 8);
ecc->priv = nand_bch_init(mtd, ecc->size, ecc->bytes,
&ecc->layout);
if (!ecc->priv) {
pr_warn("BCH ECC initialization failed!\n");
BUG();
}
- ecc->strength = ecc->bytes * 8 / fls(8 * ecc->size);
break;
case NAND_ECC_NONE:
@@ -4146,6 +4156,7 @@ int nand_scan_tail(struct mtd_info *mtd)
mtd->_unlock = NULL;
mtd->_suspend = nand_suspend;
mtd->_resume = nand_resume;
+ mtd->_reboot = nand_shutdown;
mtd->_block_isreserved = nand_block_isreserved;
mtd->_block_isbad = nand_block_isbad;
mtd->_block_markbad = nand_block_markbad;
@@ -4161,7 +4172,7 @@ int nand_scan_tail(struct mtd_info *mtd)
* properly set.
*/
if (!mtd->bitflip_threshold)
- mtd->bitflip_threshold = mtd->ecc_strength;
+ mtd->bitflip_threshold = DIV_ROUND_UP(mtd->ecc_strength * 3, 4);
/* Check, if we should skip the bad block table scan */
if (chip->options & NAND_SKIP_BBTSCAN)
diff --git a/drivers/mtd/nand/nandsim.c b/drivers/mtd/nand/nandsim.c
index ab5bbf567439..f2324271b94e 100644
--- a/drivers/mtd/nand/nandsim.c
+++ b/drivers/mtd/nand/nandsim.c
@@ -245,7 +245,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define STATE_DATAOUT 0x00001000 /* waiting for page data output */
#define STATE_DATAOUT_ID 0x00002000 /* waiting for ID bytes output */
#define STATE_DATAOUT_STATUS 0x00003000 /* waiting for status output */
-#define STATE_DATAOUT_STATUS_M 0x00004000 /* waiting for multi-plane status output */
#define STATE_DATAOUT_MASK 0x00007000 /* data output states mask */
/* Previous operation is done, ready to accept new requests */
@@ -269,7 +268,6 @@ MODULE_PARM_DESC(bch, "Enable BCH ecc and set how many bits should "
#define OPT_ANY 0xFFFFFFFF /* any chip supports this operation */
#define OPT_PAGE512 0x00000002 /* 512-byte page chips */
#define OPT_PAGE2048 0x00000008 /* 2048-byte page chips */
-#define OPT_SMARTMEDIA 0x00000010 /* SmartMedia technology chips */
#define OPT_PAGE512_8BIT 0x00000040 /* 512-byte page chips with 8-bit bus width */
#define OPT_PAGE4096 0x00000080 /* 4096-byte page chips */
#define OPT_LARGEPAGE (OPT_PAGE2048 | OPT_PAGE4096) /* 2048 & 4096-byte page chips */
@@ -1096,8 +1094,6 @@ static char *get_state_name(uint32_t state)
return "STATE_DATAOUT_ID";
case STATE_DATAOUT_STATUS:
return "STATE_DATAOUT_STATUS";
- case STATE_DATAOUT_STATUS_M:
- return "STATE_DATAOUT_STATUS_M";
case STATE_READY:
return "STATE_READY";
case STATE_UNKNOWN:
@@ -1865,7 +1861,6 @@ static void switch_state(struct nandsim *ns)
break;
case STATE_DATAOUT_STATUS:
- case STATE_DATAOUT_STATUS_M:
ns->regs.count = ns->regs.num = 0;
break;
@@ -2005,7 +2000,6 @@ static void ns_nand_write_byte(struct mtd_info *mtd, u_char byte)
}
if (NS_STATE(ns->state) == STATE_DATAOUT_STATUS
- || NS_STATE(ns->state) == STATE_DATAOUT_STATUS_M
|| NS_STATE(ns->state) == STATE_DATAOUT) {
int row = ns->regs.row;
@@ -2343,6 +2337,7 @@ static int __init ns_init_module(void)
}
chip->ecc.mode = NAND_ECC_SOFT_BCH;
chip->ecc.size = 512;
+ chip->ecc.strength = bch;
chip->ecc.bytes = eccbytes;
NS_INFO("using %u-bit/%u bytes BCH ECC\n", bch, chip->ecc.size);
}
diff --git a/drivers/mtd/nand/omap2.c b/drivers/mtd/nand/omap2.c
index 63f858e6bf39..60fa89939c24 100644
--- a/drivers/mtd/nand/omap2.c
+++ b/drivers/mtd/nand/omap2.c
@@ -1048,10 +1048,9 @@ static int omap_dev_ready(struct mtd_info *mtd)
* @mtd: MTD device structure
* @mode: Read/Write mode
*
- * When using BCH, sector size is hardcoded to 512 bytes.
- * Using wrapping mode 6 both for reading and writing if ELM module not uses
- * for error correction.
- * On writing,
+ * When using BCH with SW correction (i.e. no ELM), sector size is set
+ * to 512 bytes and we use BCH_WRAPMODE_6 wrapping mode
+ * for both reading and writing with:
* eccsize0 = 0 (no additional protected byte in spare area)
* eccsize1 = 32 (skip 32 nibbles = 16 bytes per sector in spare area)
*/
@@ -1071,15 +1070,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
case OMAP_ECC_BCH4_CODE_HW_DETECTION_SW:
bch_type = 0;
nsectors = 1;
- if (mode == NAND_ECC_READ) {
- wr_mode = BCH_WRAPMODE_6;
- ecc_size0 = BCH_ECC_SIZE0;
- ecc_size1 = BCH_ECC_SIZE1;
- } else {
- wr_mode = BCH_WRAPMODE_6;
- ecc_size0 = BCH_ECC_SIZE0;
- ecc_size1 = BCH_ECC_SIZE1;
- }
+ wr_mode = BCH_WRAPMODE_6;
+ ecc_size0 = BCH_ECC_SIZE0;
+ ecc_size1 = BCH_ECC_SIZE1;
break;
case OMAP_ECC_BCH4_CODE_HW:
bch_type = 0;
@@ -1097,15 +1090,9 @@ static void __maybe_unused omap_enable_hwecc_bch(struct mtd_info *mtd, int mode)
case OMAP_ECC_BCH8_CODE_HW_DETECTION_SW:
bch_type = 1;
nsectors = 1;
- if (mode == NAND_ECC_READ) {
- wr_mode = BCH_WRAPMODE_6;
- ecc_size0 = BCH_ECC_SIZE0;
- ecc_size1 = BCH_ECC_SIZE1;
- } else {
- wr_mode = BCH_WRAPMODE_6;
- ecc_size0 = BCH_ECC_SIZE0;
- ecc_size1 = BCH_ECC_SIZE1;
- }
+ wr_mode = BCH_WRAPMODE_6;
+ ecc_size0 = BCH_ECC_SIZE0;
+ ecc_size1 = BCH_ECC_SIZE1;
break;
case OMAP_ECC_BCH8_CODE_HW:
bch_type = 1;
diff --git a/drivers/mtd/nand/sunxi_nand.c b/drivers/mtd/nand/sunxi_nand.c
index ccaa8e283388..6f93b2990d25 100644
--- a/drivers/mtd/nand/sunxi_nand.c
+++ b/drivers/mtd/nand/sunxi_nand.c
@@ -1110,8 +1110,6 @@ static int sunxi_nand_ecc_init(struct mtd_info *mtd, struct nand_ecc_ctrl *ecc,
switch (ecc->mode) {
case NAND_ECC_SOFT_BCH:
- ecc->bytes = DIV_ROUND_UP(ecc->strength * fls(8 * ecc->size),
- 8);
break;
case NAND_ECC_HW:
ret = sunxi_nand_hw_ecc_ctrl_init(mtd, ecc, np);
diff --git a/drivers/mtd/nftlmount.c b/drivers/mtd/nftlmount.c
index 51b9d6af307f..a5dfbfbebfca 100644
--- a/drivers/mtd/nftlmount.c
+++ b/drivers/mtd/nftlmount.c
@@ -89,9 +89,10 @@ static int find_boot_record(struct NFTLrecord *nftl)
}
/* To be safer with BIOS, also use erase mark as discriminant */
- if ((ret = nftl_read_oob(mtd, block * nftl->EraseSize +
+ ret = nftl_read_oob(mtd, block * nftl->EraseSize +
SECTORSIZE + 8, 8, &retlen,
- (char *)&h1) < 0)) {
+ (char *)&h1);
+ if (ret < 0) {
printk(KERN_WARNING "ANAND header found at 0x%x in mtd%d, but OOB data read failed (err %d)\n",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue;
@@ -109,8 +110,9 @@ static int find_boot_record(struct NFTLrecord *nftl)
}
/* Finally reread to check ECC */
- if ((ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
- &retlen, buf) < 0)) {
+ ret = mtd->read(mtd, block * nftl->EraseSize, SECTORSIZE,
+ &retlen, buf);
+ if (ret < 0) {
printk(KERN_NOTICE "ANAND header found at 0x%x in mtd%d, but ECC read failed (err %d)\n",
block * nftl->EraseSize, nftl->mbd.mtd->index, ret);
continue;
@@ -228,9 +230,11 @@ device is already correct.
The new DiskOnChip driver already scanned the bad block table. Just query it.
if ((i & (SECTORSIZE - 1)) == 0) {
/* read one sector for every SECTORSIZE of blocks */
- if ((ret = mtd->read(nftl->mbd.mtd, block * nftl->EraseSize +
- i + SECTORSIZE, SECTORSIZE, &retlen,
- buf)) < 0) {
+ ret = mtd->read(nftl->mbd.mtd,
+ block * nftl->EraseSize + i +
+ SECTORSIZE, SECTORSIZE,
+ &retlen, buf);
+ if (ret < 0) {
printk(KERN_NOTICE "Read of bad sector table failed (err %d)\n",
ret);
kfree(nftl->ReplUnitTable);
diff --git a/drivers/mtd/spi-nor/fsl-quadspi.c b/drivers/mtd/spi-nor/fsl-quadspi.c
index 39763b94f67d..1c7308c2c77d 100644
--- a/drivers/mtd/spi-nor/fsl-quadspi.c
+++ b/drivers/mtd/spi-nor/fsl-quadspi.c
@@ -57,7 +57,9 @@
#define QUADSPI_BUF3CR 0x1c
#define QUADSPI_BUF3CR_ALLMST_SHIFT 31
-#define QUADSPI_BUF3CR_ALLMST (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
+#define QUADSPI_BUF3CR_ALLMST_MASK (1 << QUADSPI_BUF3CR_ALLMST_SHIFT)
+#define QUADSPI_BUF3CR_ADATSZ_SHIFT 8
+#define QUADSPI_BUF3CR_ADATSZ_MASK (0xFF << QUADSPI_BUF3CR_ADATSZ_SHIFT)
#define QUADSPI_BFGENCR 0x20
#define QUADSPI_BFGENCR_PAR_EN_SHIFT 16
@@ -198,18 +200,21 @@ struct fsl_qspi_devtype_data {
enum fsl_qspi_devtype devtype;
int rxfifo;
int txfifo;
+ int ahb_buf_size;
};
static struct fsl_qspi_devtype_data vybrid_data = {
.devtype = FSL_QUADSPI_VYBRID,
.rxfifo = 128,
- .txfifo = 64
+ .txfifo = 64,
+ .ahb_buf_size = 1024
};
static struct fsl_qspi_devtype_data imx6sx_data = {
.devtype = FSL_QUADSPI_IMX6SX,
.rxfifo = 128,
- .txfifo = 512
+ .txfifo = 512,
+ .ahb_buf_size = 1024
};
#define FSL_QSPI_MAX_CHIP 4
@@ -227,6 +232,7 @@ struct fsl_qspi {
u32 nor_num;
u32 clk_rate;
unsigned int chip_base_addr; /* We may support two chips. */
+ bool has_second_chip;
};
static inline int is_vybrid_qspi(struct fsl_qspi *q)
@@ -583,7 +589,12 @@ static void fsl_qspi_init_abh_read(struct fsl_qspi *q)
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF0CR);
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF1CR);
writel(QUADSPI_BUFXCR_INVALID_MSTRID, base + QUADSPI_BUF2CR);
- writel(QUADSPI_BUF3CR_ALLMST, base + QUADSPI_BUF3CR);
+ /*
+ * Set ADATSZ with the maximum AHB buffer size to improve the
+ * read performance.
+ */
+ writel(QUADSPI_BUF3CR_ALLMST_MASK | ((q->devtype_data->ahb_buf_size / 8)
+ << QUADSPI_BUF3CR_ADATSZ_SHIFT), base + QUADSPI_BUF3CR);
/* We only use the buffer3 */
writel(0, base + QUADSPI_BUF0IND);
@@ -783,7 +794,6 @@ static int fsl_qspi_probe(struct platform_device *pdev)
struct spi_nor *nor;
struct mtd_info *mtd;
int ret, i = 0;
- bool has_second_chip = false;
const struct of_device_id *of_id =
of_match_device(fsl_qspi_dt_ids, &pdev->dev);
@@ -798,37 +808,30 @@ static int fsl_qspi_probe(struct platform_device *pdev)
/* find the resources */
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "QuadSPI");
q->iobase = devm_ioremap_resource(dev, res);
- if (IS_ERR(q->iobase)) {
- ret = PTR_ERR(q->iobase);
- goto map_failed;
- }
+ if (IS_ERR(q->iobase))
+ return PTR_ERR(q->iobase);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
"QuadSPI-memory");
q->ahb_base = devm_ioremap_resource(dev, res);
- if (IS_ERR(q->ahb_base)) {
- ret = PTR_ERR(q->ahb_base);
- goto map_failed;
- }
+ if (IS_ERR(q->ahb_base))
+ return PTR_ERR(q->ahb_base);
+
q->memmap_phy = res->start;
/* find the clocks */
q->clk_en = devm_clk_get(dev, "qspi_en");
- if (IS_ERR(q->clk_en)) {
- ret = PTR_ERR(q->clk_en);
- goto map_failed;
- }
+ if (IS_ERR(q->clk_en))
+ return PTR_ERR(q->clk_en);
q->clk = devm_clk_get(dev, "qspi");
- if (IS_ERR(q->clk)) {
- ret = PTR_ERR(q->clk);
- goto map_failed;
- }
+ if (IS_ERR(q->clk))
+ return PTR_ERR(q->clk);
ret = clk_prepare_enable(q->clk_en);
if (ret) {
dev_err(dev, "can not enable the qspi_en clock\n");
- goto map_failed;
+ return ret;
}
ret = clk_prepare_enable(q->clk);
@@ -860,14 +863,14 @@ static int fsl_qspi_probe(struct platform_device *pdev)
goto irq_failed;
if (of_get_property(np, "fsl,qspi-has-second-chip", NULL))
- has_second_chip = true;
+ q->has_second_chip = true;
/* iterate the subnodes. */
for_each_available_child_of_node(dev->of_node, np) {
char modalias[40];
/* skip the holes */
- if (!has_second_chip)
+ if (!q->has_second_chip)
i *= 2;
nor = &q->nor[i];
@@ -890,24 +893,24 @@ static int fsl_qspi_probe(struct platform_device *pdev)
ret = of_modalias_node(np, modalias, sizeof(modalias));
if (ret < 0)
- goto map_failed;
+ goto irq_failed;
ret = of_property_read_u32(np, "spi-max-frequency",
&q->clk_rate);
if (ret < 0)
- goto map_failed;
+ goto irq_failed;
/* set the chip address for READID */
fsl_qspi_set_base_addr(q, nor);
ret = spi_nor_scan(nor, modalias, SPI_NOR_QUAD);
if (ret)
- goto map_failed;
+ goto irq_failed;
ppdata.of_node = np;
ret = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0);
if (ret)
- goto map_failed;
+ goto irq_failed;
/* Set the correct NOR size now. */
if (q->nor_size == 0) {
@@ -939,19 +942,19 @@ static int fsl_qspi_probe(struct platform_device *pdev)
clk_disable(q->clk);
clk_disable(q->clk_en);
- dev_info(dev, "QuadSPI SPI NOR flash driver\n");
return 0;
last_init_failed:
- for (i = 0; i < q->nor_num; i++)
+ for (i = 0; i < q->nor_num; i++) {
+ /* skip the holes */
+ if (!q->has_second_chip)
+ i *= 2;
mtd_device_unregister(&q->mtd[i]);
-
+ }
irq_failed:
clk_disable_unprepare(q->clk);
clk_failed:
clk_disable_unprepare(q->clk_en);
-map_failed:
- dev_err(dev, "Freescale QuadSPI probe failed\n");
return ret;
}
@@ -960,8 +963,12 @@ static int fsl_qspi_remove(struct platform_device *pdev)
struct fsl_qspi *q = platform_get_drvdata(pdev);
int i;
- for (i = 0; i < q->nor_num; i++)
+ for (i = 0; i < q->nor_num; i++) {
+ /* skip the holes */
+ if (!q->has_second_chip)
+ i *= 2;
mtd_device_unregister(&q->mtd[i]);
+ }
/* disable the hardware */
writel(QUADSPI_MCR_MDIS_MASK, q->iobase + QUADSPI_MCR);
@@ -972,6 +979,22 @@ static int fsl_qspi_remove(struct platform_device *pdev)
return 0;
}
+static int fsl_qspi_suspend(struct platform_device *pdev, pm_message_t state)
+{
+ return 0;
+}
+
+static int fsl_qspi_resume(struct platform_device *pdev)
+{
+ struct fsl_qspi *q = platform_get_drvdata(pdev);
+
+ fsl_qspi_nor_setup(q);
+ fsl_qspi_set_map_addr(q);
+ fsl_qspi_nor_setup_last(q);
+
+ return 0;
+}
+
static struct platform_driver fsl_qspi_driver = {
.driver = {
.name = "fsl-quadspi",
@@ -980,6 +1003,8 @@ static struct platform_driver fsl_qspi_driver = {
},
.probe = fsl_qspi_probe,
.remove = fsl_qspi_remove,
+ .suspend = fsl_qspi_suspend,
+ .resume = fsl_qspi_resume,
};
module_platform_driver(fsl_qspi_driver);
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
index 0f8ec3c2d015..b6a5a0c269e1 100644
--- a/drivers/mtd/spi-nor/spi-nor.c
+++ b/drivers/mtd/spi-nor/spi-nor.c
@@ -538,6 +538,7 @@ static const struct spi_device_id spi_nor_ids[] = {
/* GigaDevice */
{ "gd25q32", INFO(0xc84016, 0, 64 * 1024, 64, SECT_4K) },
{ "gd25q64", INFO(0xc84017, 0, 64 * 1024, 128, SECT_4K) },
+ { "gd25q128", INFO(0xc84018, 0, 64 * 1024, 256, SECT_4K) },
/* Intel/Numonyx -- xxxs33b */
{ "160s33b", INFO(0x898911, 0, 64 * 1024, 32, 0) },
@@ -560,14 +561,14 @@ static const struct spi_device_id spi_nor_ids[] = {
{ "mx66l1g55g", INFO(0xc2261b, 0, 64 * 1024, 2048, SPI_NOR_QUAD_READ) },
/* Micron */
- { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, 0) },
- { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, 0) },
- { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, 0) },
- { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, 0) },
- { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K) },
- { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K) },
- { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, USE_FSR) },
- { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, USE_FSR) },
+ { "n25q032", INFO(0x20ba16, 0, 64 * 1024, 64, SPI_NOR_QUAD_READ) },
+ { "n25q064", INFO(0x20ba17, 0, 64 * 1024, 128, SPI_NOR_QUAD_READ) },
+ { "n25q128a11", INFO(0x20bb18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
+ { "n25q128a13", INFO(0x20ba18, 0, 64 * 1024, 256, SPI_NOR_QUAD_READ) },
+ { "n25q256a", INFO(0x20ba19, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_QUAD_READ) },
+ { "n25q512a", INFO(0x20bb20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+ { "n25q512ax3", INFO(0x20ba20, 0, 64 * 1024, 1024, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
+ { "n25q00", INFO(0x20ba21, 0, 64 * 1024, 2048, SECT_4K | USE_FSR | SPI_NOR_QUAD_READ) },
/* PMC */
{ "pm25lv512", INFO(0, 0, 32 * 1024, 2, SECT_4K_PMC) },
@@ -891,6 +892,45 @@ static int spansion_quad_enable(struct spi_nor *nor)
return 0;
}
+static int micron_quad_enable(struct spi_nor *nor)
+{
+ int ret;
+ u8 val;
+
+ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error %d reading EVCR\n", ret);
+ return ret;
+ }
+
+ write_enable(nor);
+
+ /* set EVCR, enable quad I/O */
+ nor->cmd_buf[0] = val & ~EVCR_QUAD_EN_MICRON;
+ ret = nor->write_reg(nor, SPINOR_OP_WD_EVCR, nor->cmd_buf, 1, 0);
+ if (ret < 0) {
+ dev_err(nor->dev, "error while writing EVCR register\n");
+ return ret;
+ }
+
+ ret = spi_nor_wait_till_ready(nor);
+ if (ret)
+ return ret;
+
+ /* read EVCR and check it */
+ ret = nor->read_reg(nor, SPINOR_OP_RD_EVCR, &val, 1);
+ if (ret < 0) {
+ dev_err(nor->dev, "error %d reading EVCR\n", ret);
+ return ret;
+ }
+ if (val & EVCR_QUAD_EN_MICRON) {
+ dev_err(nor->dev, "Micron EVCR Quad bit not clear\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
{
int status;
@@ -903,6 +943,13 @@ static int set_quad_mode(struct spi_nor *nor, struct flash_info *info)
return -EINVAL;
}
return status;
+ case CFI_MFR_ST:
+ status = micron_quad_enable(nor);
+ if (status) {
+ dev_err(nor->dev, "Micron quad-read not enabled\n");
+ return -EINVAL;
+ }
+ return status;
default:
status = spansion_quad_enable(nor);
if (status) {
diff --git a/drivers/mtd/ubi/block.c b/drivers/mtd/ubi/block.c
index 6b6bce28bd63..db2c05b6fe7f 100644
--- a/drivers/mtd/ubi/block.c
+++ b/drivers/mtd/ubi/block.c
@@ -42,11 +42,12 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
-#include <linux/vmalloc.h>
#include <linux/mtd/ubi.h>
#include <linux/workqueue.h>
#include <linux/blkdev.h>
+#include <linux/blk-mq.h>
#include <linux/hdreg.h>
+#include <linux/scatterlist.h>
#include <asm/div64.h>
#include "ubi-media.h"
@@ -67,6 +68,11 @@ struct ubiblock_param {
char name[UBIBLOCK_PARAM_LEN+1];
};
+struct ubiblock_pdu {
+ struct work_struct work;
+ struct ubi_sgl usgl;
+};
+
/* Numbers of elements set in the @ubiblock_param array */
static int ubiblock_devs __initdata;
@@ -84,11 +90,10 @@ struct ubiblock {
struct request_queue *rq;
struct workqueue_struct *wq;
- struct work_struct work;
struct mutex dev_mutex;
- spinlock_t queue_lock;
struct list_head list;
+ struct blk_mq_tag_set tag_set;
};
/* Linked list of all ubiblock instances */
@@ -181,31 +186,20 @@ static struct ubiblock *find_dev_nolock(int ubi_num, int vol_id)
return NULL;
}
-static int ubiblock_read_to_buf(struct ubiblock *dev, char *buffer,
- int leb, int offset, int len)
+static int ubiblock_read(struct ubiblock_pdu *pdu)
{
- int ret;
-
- ret = ubi_read(dev->desc, leb, buffer, offset, len);
- if (ret) {
- dev_err(disk_to_dev(dev->gd), "%d while reading from LEB %d (offset %d, length %d)",
- ret, leb, offset, len);
- return ret;
- }
- return 0;
-}
+ int ret, leb, offset, bytes_left, to_read;
+ u64 pos;
+ struct request *req = blk_mq_rq_from_pdu(pdu);
+ struct ubiblock *dev = req->q->queuedata;
-static int ubiblock_read(struct ubiblock *dev, char *buffer,
- sector_t sec, int len)
-{
- int ret, leb, offset;
- int bytes_left = len;
- int to_read = len;
- u64 pos = sec << 9;
+ to_read = blk_rq_bytes(req);
+ pos = blk_rq_pos(req) << 9;
/* Get LEB:offset address to read from */
offset = do_div(pos, dev->leb_size);
leb = pos;
+ bytes_left = to_read;
while (bytes_left) {
/*
@@ -215,11 +209,10 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
if (offset + to_read > dev->leb_size)
to_read = dev->leb_size - offset;
- ret = ubiblock_read_to_buf(dev, buffer, leb, offset, to_read);
- if (ret)
+ ret = ubi_read_sg(dev->desc, leb, &pdu->usgl, offset, to_read);
+ if (ret < 0)
return ret;
- buffer += to_read;
bytes_left -= to_read;
to_read = bytes_left;
leb += 1;
@@ -228,79 +221,6 @@ static int ubiblock_read(struct ubiblock *dev, char *buffer,
return 0;
}
-static int do_ubiblock_request(struct ubiblock *dev, struct request *req)
-{
- int len, ret;
- sector_t sec;
-
- if (req->cmd_type != REQ_TYPE_FS)
- return -EIO;
-
- if (blk_rq_pos(req) + blk_rq_cur_sectors(req) >
- get_capacity(req->rq_disk))
- return -EIO;
-
- if (rq_data_dir(req) != READ)
- return -ENOSYS; /* Write not implemented */
-
- sec = blk_rq_pos(req);
- len = blk_rq_cur_bytes(req);
-
- /*
- * Let's prevent the device from being removed while we're doing I/O
- * work. Notice that this means we serialize all the I/O operations,
- * but it's probably of no impact given the NAND core serializes
- * flash access anyway.
- */
- mutex_lock(&dev->dev_mutex);
- ret = ubiblock_read(dev, bio_data(req->bio), sec, len);
- mutex_unlock(&dev->dev_mutex);
-
- return ret;
-}
-
-static void ubiblock_do_work(struct work_struct *work)
-{
- struct ubiblock *dev =
- container_of(work, struct ubiblock, work);
- struct request_queue *rq = dev->rq;
- struct request *req;
- int res;
-
- spin_lock_irq(rq->queue_lock);
-
- req = blk_fetch_request(rq);
- while (req) {
-
- spin_unlock_irq(rq->queue_lock);
- res = do_ubiblock_request(dev, req);
- spin_lock_irq(rq->queue_lock);
-
- /*
- * If we're done with this request,
- * we need to fetch a new one
- */
- if (!__blk_end_request_cur(req, res))
- req = blk_fetch_request(rq);
- }
-
- spin_unlock_irq(rq->queue_lock);
-}
-
-static void ubiblock_request(struct request_queue *rq)
-{
- struct ubiblock *dev;
- struct request *req;
-
- dev = rq->queuedata;
-
- if (!dev)
- while ((req = blk_fetch_request(rq)) != NULL)
- __blk_end_request_all(req, -ENODEV);
- else
- queue_work(dev->wq, &dev->work);
-}
-
static int ubiblock_open(struct block_device *bdev, fmode_t mode)
{
struct ubiblock *dev = bdev->bd_disk->private_data;
@@ -374,6 +294,63 @@ static const struct block_device_operations ubiblock_ops = {
.getgeo = ubiblock_getgeo,
};
+static void ubiblock_do_work(struct work_struct *work)
+{
+ int ret;
+ struct ubiblock_pdu *pdu = container_of(work, struct ubiblock_pdu, work);
+ struct request *req = blk_mq_rq_from_pdu(pdu);
+
+ blk_mq_start_request(req);
+
+ /*
+ * It is safe to ignore the return value of blk_rq_map_sg() because
+ * the number of sg entries is limited to UBI_MAX_SG_COUNT
+ * and ubi_read_sg() will check that limit.
+ */
+ blk_rq_map_sg(req->q, req, pdu->usgl.sg);
+
+ ret = ubiblock_read(pdu);
+ blk_mq_end_request(req, ret);
+}
+
+static int ubiblock_queue_rq(struct blk_mq_hw_ctx *hctx,
+ const struct blk_mq_queue_data *bd)
+{
+ struct request *req = bd->rq;
+ struct ubiblock *dev = hctx->queue->queuedata;
+ struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
+
+ if (req->cmd_type != REQ_TYPE_FS)
+ return BLK_MQ_RQ_QUEUE_ERROR;
+
+ if (rq_data_dir(req) != READ)
+ return BLK_MQ_RQ_QUEUE_ERROR; /* Write not implemented */
+
+ ubi_sgl_init(&pdu->usgl);
+ queue_work(dev->wq, &pdu->work);
+
+ return BLK_MQ_RQ_QUEUE_OK;
+}
+
+static int ubiblock_init_request(void *data, struct request *req,
+ unsigned int hctx_idx,
+ unsigned int request_idx,
+ unsigned int numa_node)
+{
+ struct ubiblock_pdu *pdu = blk_mq_rq_to_pdu(req);
+
+ sg_init_table(pdu->usgl.sg, UBI_MAX_SG_COUNT);
+ INIT_WORK(&pdu->work, ubiblock_do_work);
+
+ return 0;
+}
+
+static struct blk_mq_ops ubiblock_mq_ops = {
+ .queue_rq = ubiblock_queue_rq,
+ .init_request = ubiblock_init_request,
+ .map_queue = blk_mq_map_queue,
+};
+
int ubiblock_create(struct ubi_volume_info *vi)
{
struct ubiblock *dev;
@@ -417,14 +394,28 @@ int ubiblock_create(struct ubi_volume_info *vi)
set_capacity(gd, disk_capacity);
dev->gd = gd;
- spin_lock_init(&dev->queue_lock);
- dev->rq = blk_init_queue(ubiblock_request, &dev->queue_lock);
- if (!dev->rq) {
- dev_err(disk_to_dev(gd), "blk_init_queue failed");
- ret = -ENODEV;
+ dev->tag_set.ops = &ubiblock_mq_ops;
+ dev->tag_set.queue_depth = 64;
+ dev->tag_set.numa_node = NUMA_NO_NODE;
+ dev->tag_set.flags = BLK_MQ_F_SHOULD_MERGE;
+ dev->tag_set.cmd_size = sizeof(struct ubiblock_pdu);
+ dev->tag_set.driver_data = dev;
+ dev->tag_set.nr_hw_queues = 1;
+
+ ret = blk_mq_alloc_tag_set(&dev->tag_set);
+ if (ret) {
+ dev_err(disk_to_dev(dev->gd), "blk_mq_alloc_tag_set failed");
goto out_put_disk;
}
+ dev->rq = blk_mq_init_queue(&dev->tag_set);
+ if (IS_ERR(dev->rq)) {
+ dev_err(disk_to_dev(gd), "blk_mq_init_queue failed");
+ ret = PTR_ERR(dev->rq);
+ goto out_free_tags;
+ }
+ blk_queue_max_segments(dev->rq, UBI_MAX_SG_COUNT);
+
dev->rq->queuedata = dev;
dev->gd->queue = dev->rq;
@@ -437,7 +428,6 @@ int ubiblock_create(struct ubi_volume_info *vi)
ret = -ENOMEM;
goto out_free_queue;
}
- INIT_WORK(&dev->work, ubiblock_do_work);
mutex_lock(&devices_mutex);
list_add_tail(&dev->list, &ubiblock_devices);
@@ -451,6 +441,8 @@ int ubiblock_create(struct ubi_volume_info *vi)
out_free_queue:
blk_cleanup_queue(dev->rq);
+out_free_tags:
+ blk_mq_free_tag_set(&dev->tag_set);
out_put_disk:
put_disk(dev->gd);
out_free_dev:
@@ -461,8 +453,13 @@ out_free_dev:
static void ubiblock_cleanup(struct ubiblock *dev)
{
+ /* Stop new requests to arrive */
del_gendisk(dev->gd);
+ /* Flush pending work */
+ destroy_workqueue(dev->wq);
+ /* Finally destroy the blk queue */
blk_cleanup_queue(dev->rq);
+ blk_mq_free_tag_set(&dev->tag_set);
dev_info(disk_to_dev(dev->gd), "released");
put_disk(dev->gd);
}
@@ -490,9 +487,6 @@ int ubiblock_remove(struct ubi_volume_info *vi)
list_del(&dev->list);
mutex_unlock(&devices_mutex);
- /* Flush pending work and stop this workqueue */
- destroy_workqueue(dev->wq);
-
ubiblock_cleanup(dev);
mutex_unlock(&dev->dev_mutex);
kfree(dev);
@@ -583,22 +577,28 @@ open_volume_desc(const char *name, int ubi_num, int vol_id)
return ubi_open_volume(ubi_num, vol_id, UBI_READONLY);
}
-static int __init ubiblock_create_from_param(void)
+static void __init ubiblock_create_from_param(void)
{
- int i, ret;
+ int i, ret = 0;
struct ubiblock_param *p;
struct ubi_volume_desc *desc;
struct ubi_volume_info vi;
+ /*
+ * If there is an error creating one of the ubiblocks, continue on to
+ * create the following ubiblocks. This helps in a circumstance where
+ * the kernel command-line specifies multiple block devices and some
+ * may be broken, but we still want the working ones to come up.
+ */
for (i = 0; i < ubiblock_devs; i++) {
p = &ubiblock_param[i];
desc = open_volume_desc(p->name, p->ubi_num, p->vol_id);
if (IS_ERR(desc)) {
- pr_err("UBI: block: can't open volume, err=%ld\n",
- PTR_ERR(desc));
- ret = PTR_ERR(desc);
- break;
+ pr_err(
+ "UBI: block: can't open volume on ubi%d_%d, err=%ld",
+ p->ubi_num, p->vol_id, PTR_ERR(desc));
+ continue;
}
ubi_get_volume_info(desc, &vi);
@@ -606,12 +606,12 @@ static int __init ubiblock_create_from_param(void)
ret = ubiblock_create(&vi);
if (ret) {
- pr_err("UBI: block: can't add '%s' volume, err=%d\n",
- vi.name, ret);
- break;
+ pr_err(
+ "UBI: block: can't add '%s' volume on ubi%d_%d, err=%d",
+ vi.name, p->ubi_num, p->vol_id, ret);
+ continue;
}
}
- return ret;
}
static void ubiblock_remove_all(void)
@@ -620,8 +620,6 @@ static void ubiblock_remove_all(void)
struct ubiblock *dev;
list_for_each_entry_safe(dev, next, &ubiblock_devices, list) {
- /* Flush pending work and stop workqueue */
- destroy_workqueue(dev->wq);
/* The module is being forcefully removed */
WARN_ON(dev->desc);
/* Remove from device list */
@@ -639,10 +637,12 @@ int __init ubiblock_init(void)
if (ubiblock_major < 0)
return ubiblock_major;
- /* Attach block devices from 'block=' module param */
- ret = ubiblock_create_from_param();
- if (ret)
- goto err_remove;
+ /*
+ * Attach block devices from 'block=' module param.
+ * Even if one block device in the param list fails to come up,
+ * still allow the module to load and leave any others up.
+ */
+ ubiblock_create_from_param();
/*
* Block devices are only created upon user requests, so we ignore
@@ -655,7 +655,6 @@ int __init ubiblock_init(void)
err_unreg:
unregister_blkdev(ubiblock_major, "ubiblock");
-err_remove:
ubiblock_remove_all();
return ret;
}
diff --git a/drivers/mtd/ubi/build.c b/drivers/mtd/ubi/build.c
index 3405be46ebe9..ba01a8d22d28 100644
--- a/drivers/mtd/ubi/build.c
+++ b/drivers/mtd/ubi/build.c
@@ -923,7 +923,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
/* Make sure ubi_num is not busy */
if (ubi_devices[ubi_num]) {
- ubi_err(ubi, "ubi%d already exists", ubi_num);
+ ubi_err(ubi, "already exists");
return -EEXIST;
}
}
@@ -973,7 +973,7 @@ int ubi_attach_mtd_dev(struct mtd_info *mtd, int ubi_num,
mutex_init(&ubi->fm_mutex);
init_rwsem(&ubi->fm_sem);
- ubi_msg(ubi, "attaching mtd%d to ubi%d", mtd->index, ubi_num);
+ ubi_msg(ubi, "attaching mtd%d", mtd->index);
err = io_init(ubi, max_beb_per1024);
if (err)
@@ -1428,7 +1428,7 @@ static int __init ubi_mtd_param_parse(const char *val, struct kernel_param *kp)
}
if (len == 0) {
- pr_err("UBI warning: empty 'mtd=' parameter - ignored\n");
+ pr_warn("UBI warning: empty 'mtd=' parameter - ignored\n");
return 0;
}
diff --git a/drivers/mtd/ubi/cdev.c b/drivers/mtd/ubi/cdev.c
index 3410ea8109f8..d647e504f9b1 100644
--- a/drivers/mtd/ubi/cdev.c
+++ b/drivers/mtd/ubi/cdev.c
@@ -48,26 +48,25 @@
/**
* get_exclusive - get exclusive access to an UBI volume.
- * @ubi: UBI device description object
* @desc: volume descriptor
*
* This function changes UBI volume open mode to "exclusive". Returns previous
* mode value (positive integer) in case of success and a negative error code
* in case of failure.
*/
-static int get_exclusive(struct ubi_device *ubi, struct ubi_volume_desc *desc)
+static int get_exclusive(struct ubi_volume_desc *desc)
{
int users, err;
struct ubi_volume *vol = desc->vol;
spin_lock(&vol->ubi->volumes_lock);
- users = vol->readers + vol->writers + vol->exclusive;
+ users = vol->readers + vol->writers + vol->exclusive + vol->metaonly;
ubi_assert(users > 0);
if (users > 1) {
- ubi_err(ubi, "%d users for volume %d", users, vol->vol_id);
+ ubi_err(vol->ubi, "%d users for volume %d", users, vol->vol_id);
err = -EBUSY;
} else {
- vol->readers = vol->writers = 0;
+ vol->readers = vol->writers = vol->metaonly = 0;
vol->exclusive = 1;
err = desc->mode;
desc->mode = UBI_EXCLUSIVE;
@@ -87,13 +86,15 @@ static void revoke_exclusive(struct ubi_volume_desc *desc, int mode)
struct ubi_volume *vol = desc->vol;
spin_lock(&vol->ubi->volumes_lock);
- ubi_assert(vol->readers == 0 && vol->writers == 0);
+ ubi_assert(vol->readers == 0 && vol->writers == 0 && vol->metaonly == 0);
ubi_assert(vol->exclusive == 1 && desc->mode == UBI_EXCLUSIVE);
vol->exclusive = 0;
if (mode == UBI_READONLY)
vol->readers = 1;
else if (mode == UBI_READWRITE)
vol->writers = 1;
+ else if (mode == UBI_METAONLY)
+ vol->metaonly = 1;
else
vol->exclusive = 1;
spin_unlock(&vol->ubi->volumes_lock);
@@ -421,7 +422,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
break;
}
- err = get_exclusive(ubi, desc);
+ err = get_exclusive(desc);
if (err < 0)
break;
@@ -457,7 +458,7 @@ static long vol_cdev_ioctl(struct file *file, unsigned int cmd,
req.bytes < 0 || req.lnum >= vol->usable_leb_size)
break;
- err = get_exclusive(ubi, desc);
+ err = get_exclusive(desc);
if (err < 0)
break;
@@ -734,7 +735,7 @@ static int rename_volumes(struct ubi_device *ubi,
goto out_free;
}
- re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_READWRITE);
+ re->desc = ubi_open_volume(ubi->ubi_num, vol_id, UBI_METAONLY);
if (IS_ERR(re->desc)) {
err = PTR_ERR(re->desc);
ubi_err(ubi, "cannot open volume %d, error %d",
diff --git a/drivers/mtd/ubi/eba.c b/drivers/mtd/ubi/eba.c
index a40020cf0923..da4c79259f67 100644
--- a/drivers/mtd/ubi/eba.c
+++ b/drivers/mtd/ubi/eba.c
@@ -426,6 +426,7 @@ retry:
pnum, vol_id, lnum);
err = -EBADMSG;
} else
+ err = -EINVAL;
ubi_ro_mode(ubi);
}
goto out_free;
@@ -480,6 +481,61 @@ out_unlock:
}
/**
+ * ubi_eba_read_leb_sg - read data into a scatter gather list.
+ * @ubi: UBI device description object
+ * @vol: volume description object
+ * @lnum: logical eraseblock number
+ * @sgl: UBI scatter gather list to store the read data
+ * @offset: offset from where to read
+ * @len: how many bytes to read
+ * @check: data CRC check flag
+ *
+ * This function works exactly like ubi_eba_read_leb(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+ struct ubi_sgl *sgl, int lnum, int offset, int len,
+ int check)
+{
+ int to_read;
+ int ret;
+ struct scatterlist *sg;
+
+ for (;;) {
+ ubi_assert(sgl->list_pos < UBI_MAX_SG_COUNT);
+ sg = &sgl->sg[sgl->list_pos];
+ if (len < sg->length - sgl->page_pos)
+ to_read = len;
+ else
+ to_read = sg->length - sgl->page_pos;
+
+ ret = ubi_eba_read_leb(ubi, vol, lnum,
+ sg_virt(sg) + sgl->page_pos, offset,
+ to_read, check);
+ if (ret < 0)
+ return ret;
+
+ offset += to_read;
+ len -= to_read;
+ if (!len) {
+ sgl->page_pos += to_read;
+ if (sgl->page_pos == sg->length) {
+ sgl->list_pos++;
+ sgl->page_pos = 0;
+ }
+
+ break;
+ }
+
+ sgl->list_pos++;
+ sgl->page_pos = 0;
+ }
+
+ return ret;
+}
+
+/**
* recover_peb - recover from write failure.
* @ubi: UBI device description object
* @pnum: the physical eraseblock to recover
diff --git a/drivers/mtd/ubi/fastmap.c b/drivers/mtd/ubi/fastmap.c
index b56672bf3294..db3defdfc3c0 100644
--- a/drivers/mtd/ubi/fastmap.c
+++ b/drivers/mtd/ubi/fastmap.c
@@ -1196,6 +1196,19 @@ static int ubi_write_fastmap(struct ubi_device *ubi,
fm_pos += sizeof(*fec);
ubi_assert(fm_pos <= ubi->fm_size);
}
+
+ for (i = 0; i < UBI_PROT_QUEUE_LEN; i++) {
+ list_for_each_entry(wl_e, &ubi->pq[i], u.list) {
+ fec = (struct ubi_fm_ec *)(fm_raw + fm_pos);
+
+ fec->pnum = cpu_to_be32(wl_e->pnum);
+ fec->ec = cpu_to_be32(wl_e->ec);
+
+ used_peb_count++;
+ fm_pos += sizeof(*fec);
+ ubi_assert(fm_pos <= ubi->fm_size);
+ }
+ }
fmh->used_peb_count = cpu_to_be32(used_peb_count);
for (node = rb_first(&ubi->scrub); node; node = rb_next(node)) {
diff --git a/drivers/mtd/ubi/io.c b/drivers/mtd/ubi/io.c
index 396aaa543362..ed0bcb35472f 100644
--- a/drivers/mtd/ubi/io.c
+++ b/drivers/mtd/ubi/io.c
@@ -1419,8 +1419,7 @@ int ubi_self_check_all_ff(struct ubi_device *ubi, int pnum, int offset, int len)
fail:
ubi_err(ubi, "self-check failed for PEB %d", pnum);
- ubi_msg(ubi, "hex dump of the %d-%d region",
- offset, offset + len);
+ ubi_msg(ubi, "hex dump of the %d-%d region", offset, offset + len);
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 32, 1, buf, len, 1);
err = -EINVAL;
error:
diff --git a/drivers/mtd/ubi/kapi.c b/drivers/mtd/ubi/kapi.c
index f3bab669f6bb..478e00cf2d9e 100644
--- a/drivers/mtd/ubi/kapi.c
+++ b/drivers/mtd/ubi/kapi.c
@@ -137,7 +137,7 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
return ERR_PTR(-EINVAL);
if (mode != UBI_READONLY && mode != UBI_READWRITE &&
- mode != UBI_EXCLUSIVE)
+ mode != UBI_EXCLUSIVE && mode != UBI_METAONLY)
return ERR_PTR(-EINVAL);
/*
@@ -182,10 +182,17 @@ struct ubi_volume_desc *ubi_open_volume(int ubi_num, int vol_id, int mode)
break;
case UBI_EXCLUSIVE:
- if (vol->exclusive || vol->writers || vol->readers)
+ if (vol->exclusive || vol->writers || vol->readers ||
+ vol->metaonly)
goto out_unlock;
vol->exclusive = 1;
break;
+
+ case UBI_METAONLY:
+ if (vol->metaonly || vol->exclusive)
+ goto out_unlock;
+ vol->metaonly = 1;
+ break;
}
get_device(&vol->dev);
vol->ref_count += 1;
@@ -343,6 +350,10 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
break;
case UBI_EXCLUSIVE:
vol->exclusive = 0;
+ break;
+ case UBI_METAONLY:
+ vol->metaonly = 0;
+ break;
}
vol->ref_count -= 1;
spin_unlock(&ubi->volumes_lock);
@@ -355,6 +366,43 @@ void ubi_close_volume(struct ubi_volume_desc *desc)
EXPORT_SYMBOL_GPL(ubi_close_volume);
/**
+ * leb_read_sanity_check - does sanity checks on read requests.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ *
+ * This function is used by ubi_leb_read() and ubi_leb_read_sg()
+ * to perform sanity checks.
+ */
+static int leb_read_sanity_check(struct ubi_volume_desc *desc, int lnum,
+ int offset, int len)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int vol_id = vol->vol_id;
+
+ if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
+ lnum >= vol->used_ebs || offset < 0 || len < 0 ||
+ offset + len > vol->usable_leb_size)
+ return -EINVAL;
+
+ if (vol->vol_type == UBI_STATIC_VOLUME) {
+ if (vol->used_ebs == 0)
+ /* Empty static UBI volume */
+ return 0;
+ if (lnum == vol->used_ebs - 1 &&
+ offset + len > vol->last_eb_bytes)
+ return -EINVAL;
+ }
+
+ if (vol->upd_marker)
+ return -EBADF;
+
+ return 0;
+}
+
+/**
* ubi_leb_read - read data.
* @desc: volume descriptor
* @lnum: logical eraseblock number to read from
@@ -390,22 +438,10 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
- if (vol_id < 0 || vol_id >= ubi->vtbl_slots || lnum < 0 ||
- lnum >= vol->used_ebs || offset < 0 || len < 0 ||
- offset + len > vol->usable_leb_size)
- return -EINVAL;
-
- if (vol->vol_type == UBI_STATIC_VOLUME) {
- if (vol->used_ebs == 0)
- /* Empty static UBI volume */
- return 0;
- if (lnum == vol->used_ebs - 1 &&
- offset + len > vol->last_eb_bytes)
- return -EINVAL;
- }
+ err = leb_read_sanity_check(desc, lnum, offset, len);
+ if (err < 0)
+ return err;
- if (vol->upd_marker)
- return -EBADF;
if (len == 0)
return 0;
@@ -419,6 +455,46 @@ int ubi_leb_read(struct ubi_volume_desc *desc, int lnum, char *buf, int offset,
}
EXPORT_SYMBOL_GPL(ubi_leb_read);
+
+/**
+ * ubi_leb_read_sg - read data into a scatter gather list.
+ * @desc: volume descriptor
+ * @lnum: logical eraseblock number to read from
+ * @buf: buffer where to store the read data
+ * @offset: offset within the logical eraseblock to read from
+ * @len: how many bytes to read
+ * @check: whether UBI has to check the read data's CRC or not.
+ *
+ * This function works exactly like ubi_leb_read_sg(). But instead of
+ * storing the read data into a buffer it writes to an UBI scatter gather
+ * list.
+ */
+int ubi_leb_read_sg(struct ubi_volume_desc *desc, int lnum, struct ubi_sgl *sgl,
+ int offset, int len, int check)
+{
+ struct ubi_volume *vol = desc->vol;
+ struct ubi_device *ubi = vol->ubi;
+ int err, vol_id = vol->vol_id;
+
+ dbg_gen("read %d bytes from LEB %d:%d:%d", len, vol_id, lnum, offset);
+
+ err = leb_read_sanity_check(desc, lnum, offset, len);
+ if (err < 0)
+ return err;
+
+ if (len == 0)
+ return 0;
+
+ err = ubi_eba_read_leb_sg(ubi, vol, sgl, lnum, offset, len, check);
+ if (err && mtd_is_eccerr(err) && vol->vol_type == UBI_STATIC_VOLUME) {
+ ubi_warn(ubi, "mark volume %d as corrupted", vol_id);
+ vol->corrupted = 1;
+ }
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(ubi_leb_read_sg);
+
/**
* ubi_leb_write - write data.
* @desc: volume descriptor
diff --git a/drivers/mtd/ubi/misc.c b/drivers/mtd/ubi/misc.c
index dbda77e556cb..2a45ac210b16 100644
--- a/drivers/mtd/ubi/misc.c
+++ b/drivers/mtd/ubi/misc.c
@@ -74,6 +74,8 @@ int ubi_check_volume(struct ubi_device *ubi, int vol_id)
for (i = 0; i < vol->used_ebs; i++) {
int size;
+ cond_resched();
+
if (i == vol->used_ebs - 1)
size = vol->last_eb_bytes;
else
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
index f80ffaba9058..c5be82d9d345 100644
--- a/drivers/mtd/ubi/ubi.h
+++ b/drivers/mtd/ubi/ubi.h
@@ -50,13 +50,13 @@
#define UBI_NAME_STR "ubi"
/* Normal UBI messages */
-#define ubi_msg(ubi, fmt, ...) pr_notice("UBI-%d: %s:" fmt "\n", \
- ubi->ubi_num, __func__, ##__VA_ARGS__)
+#define ubi_msg(ubi, fmt, ...) pr_notice(UBI_NAME_STR "%d: " fmt "\n", \
+ ubi->ubi_num, ##__VA_ARGS__)
/* UBI warning messages */
-#define ubi_warn(ubi, fmt, ...) pr_warn("UBI-%d warning: %s: " fmt "\n", \
+#define ubi_warn(ubi, fmt, ...) pr_warn(UBI_NAME_STR "%d warning: %s: " fmt "\n", \
ubi->ubi_num, __func__, ##__VA_ARGS__)
/* UBI error messages */
-#define ubi_err(ubi, fmt, ...) pr_err("UBI-%d error: %s: " fmt "\n", \
+#define ubi_err(ubi, fmt, ...) pr_err(UBI_NAME_STR "%d error: %s: " fmt "\n", \
ubi->ubi_num, __func__, ##__VA_ARGS__)
/* Background thread name pattern */
@@ -261,6 +261,7 @@ struct ubi_fm_pool {
* @readers: number of users holding this volume in read-only mode
* @writers: number of users holding this volume in read-write mode
* @exclusive: whether somebody holds this volume in exclusive mode
+ * @metaonly: whether somebody is altering only meta data of this volume
*
* @reserved_pebs: how many physical eraseblocks are reserved for this volume
* @vol_type: volume type (%UBI_DYNAMIC_VOLUME or %UBI_STATIC_VOLUME)
@@ -309,6 +310,7 @@ struct ubi_volume {
int readers;
int writers;
int exclusive;
+ int metaonly;
int reserved_pebs;
int vol_type;
@@ -339,7 +341,8 @@ struct ubi_volume {
/**
* struct ubi_volume_desc - UBI volume descriptor returned when it is opened.
* @vol: reference to the corresponding volume description object
- * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, or %UBI_EXCLUSIVE)
+ * @mode: open mode (%UBI_READONLY, %UBI_READWRITE, %UBI_EXCLUSIVE
+ * or %UBI_METAONLY)
*/
struct ubi_volume_desc {
struct ubi_volume *vol;
@@ -390,7 +393,8 @@ struct ubi_debug_info {
* @volumes_lock: protects @volumes, @rsvd_pebs, @avail_pebs, beb_rsvd_pebs,
* @beb_rsvd_level, @bad_peb_count, @good_peb_count, @vol_count,
* @vol->readers, @vol->writers, @vol->exclusive,
- * @vol->ref_count, @vol->mapping and @vol->eba_tbl.
+ * @vol->metaonly, @vol->ref_count, @vol->mapping and
+ * @vol->eba_tbl.
* @ref_count: count of references on the UBI device
* @image_seq: image sequence number recorded on EC headers
*
@@ -791,6 +795,9 @@ int ubi_eba_unmap_leb(struct ubi_device *ubi, struct ubi_volume *vol,
int lnum);
int ubi_eba_read_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
void *buf, int offset, int len, int check);
+int ubi_eba_read_leb_sg(struct ubi_device *ubi, struct ubi_volume *vol,
+ struct ubi_sgl *sgl, int lnum, int offset, int len,
+ int check);
int ubi_eba_write_leb(struct ubi_device *ubi, struct ubi_volume *vol, int lnum,
const void *buf, int offset, int len);
int ubi_eba_write_leb_st(struct ubi_device *ubi, struct ubi_volume *vol,
diff --git a/drivers/mtd/ubi/vtbl.c b/drivers/mtd/ubi/vtbl.c
index f8fc3081bbb4..68c9c5ea676f 100644
--- a/drivers/mtd/ubi/vtbl.c
+++ b/drivers/mtd/ubi/vtbl.c
@@ -655,14 +655,13 @@ static int init_volumes(struct ubi_device *ubi,
/**
* check_av - check volume attaching information.
- * @ubi: UBI device description object
* @vol: UBI volume description object
* @av: volume attaching information
*
* This function returns zero if the volume attaching information is consistent
* to the data read from the volume tabla, and %-EINVAL if not.
*/
-static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol,
+static int check_av(const struct ubi_volume *vol,
const struct ubi_ainf_volume *av)
{
int err;
@@ -690,7 +689,7 @@ static int check_av(const struct ubi_device *ubi, const struct ubi_volume *vol,
return 0;
bad:
- ubi_err(ubi, "bad attaching information, error %d", err);
+ ubi_err(vol->ubi, "bad attaching information, error %d", err);
ubi_dump_av(av);
ubi_dump_vol_info(vol);
return -EINVAL;
@@ -753,7 +752,7 @@ static int check_attaching_info(const struct ubi_device *ubi,
ubi_msg(ubi, "finish volume %d removal", av->vol_id);
ubi_remove_av(ai, av);
} else if (av) {
- err = check_av(ubi, vol, av);
+ err = check_av(vol, av);
if (err)
return err;
}
diff --git a/drivers/mtd/ubi/wl.c b/drivers/mtd/ubi/wl.c
index 834f6fe1f5fa..8f7bde6a85d6 100644
--- a/drivers/mtd/ubi/wl.c
+++ b/drivers/mtd/ubi/wl.c
@@ -470,11 +470,8 @@ struct ubi_wl_entry *ubi_wl_get_fm_peb(struct ubi_device *ubi, int anchor)
{
struct ubi_wl_entry *e = NULL;
- if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1)) {
- ubi_warn(ubi, "Can't get peb for fastmap:anchor=%d, free_cnt=%d, reserved=%d",
- anchor, ubi->free_count, ubi->beb_rsvd_pebs);
+ if (!ubi->free.rb_node || (ubi->free_count - ubi->beb_rsvd_pebs < 1))
goto out;
- }
if (anchor)
e = find_anchor_wl_entry(&ubi->free);
@@ -1806,11 +1803,8 @@ int ubi_thread(void *u)
for (;;) {
int err;
- if (kthread_should_stop()) {
- ubi_msg(ubi, "background thread \"%s\" should stop, PID %d",
- ubi->bgt_name, task_pid_nr(current));
+ if (kthread_should_stop())
break;
- }
if (try_to_freeze())
continue;
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index d6607ee9c855..84673ebcf428 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -197,6 +197,7 @@ config NETCONSOLE_DYNAMIC
config NETPOLL
def_bool NETCONSOLE
+ select SRCU
config NET_POLL_CONTROLLER
def_bool NETPOLL
diff --git a/drivers/net/arcnet/com20020-pci.c b/drivers/net/arcnet/com20020-pci.c
index 6c99ff0b0bdd..96edc1346124 100644
--- a/drivers/net/arcnet/com20020-pci.c
+++ b/drivers/net/arcnet/com20020-pci.c
@@ -78,6 +78,9 @@ static int com20020pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
priv = devm_kzalloc(&pdev->dev, sizeof(struct com20020_priv),
GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
ci = (struct com20020_pci_card_info *)id->driver_data;
priv->ci = ci;
@@ -211,8 +214,17 @@ static struct com20020_pci_card_info card_info_sohard = {
.flags = ARC_CAN_10MBIT,
};
-static struct com20020_pci_card_info card_info_eae = {
- .name = "EAE PLX-PCI",
+static struct com20020_pci_card_info card_info_eae_arc1 = {
+ .name = "EAE PLX-PCI ARC1",
+ .devcount = 1,
+ .chan_map_tbl = {
+ { 2, 0x00, 0x08 },
+ },
+ .flags = ARC_CAN_10MBIT,
+};
+
+static struct com20020_pci_card_info card_info_eae_ma1 = {
+ .name = "EAE PLX-PCI MA1",
.devcount = 2,
.chan_map_tbl = {
{ 2, 0x00, 0x08 },
@@ -356,9 +368,15 @@ static const struct pci_device_id com20020pci_id_table[] = {
},
{
0x10B5, 0x9050,
+ 0x10B5, 0x3263,
+ 0, 0,
+ (kernel_ulong_t)&card_info_eae_arc1
+ },
+ {
+ 0x10B5, 0x9050,
0x10B5, 0x3292,
0, 0,
- (kernel_ulong_t)&card_info_eae
+ (kernel_ulong_t)&card_info_eae_ma1
},
{
0x14BA, 0x6000,
diff --git a/drivers/net/bonding/bond_3ad.c b/drivers/net/bonding/bond_3ad.c
index 8baa87df1738..cfc4a9c1000a 100644
--- a/drivers/net/bonding/bond_3ad.c
+++ b/drivers/net/bonding/bond_3ad.c
@@ -467,11 +467,14 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
/* set the partner sync. to on if the partner is sync,
* and the port is matched
*/
- if ((port->sm_vars & AD_PORT_MATCHED)
- && (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION))
+ if ((port->sm_vars & AD_PORT_MATCHED) &&
+ (lacpdu->actor_state & AD_STATE_SYNCHRONIZATION)) {
partner->port_state |= AD_STATE_SYNCHRONIZATION;
- else
+ pr_debug("%s partner sync=1\n", port->slave->dev->name);
+ } else {
partner->port_state &= ~AD_STATE_SYNCHRONIZATION;
+ pr_debug("%s partner sync=0\n", port->slave->dev->name);
+ }
}
}
@@ -726,6 +729,8 @@ static inline void __update_lacpdu_from_port(struct port *port)
lacpdu->actor_port_priority = htons(port->actor_port_priority);
lacpdu->actor_port = htons(port->actor_port_number);
lacpdu->actor_state = port->actor_oper_port_state;
+ pr_debug("update lacpdu: %s, actor port state %x\n",
+ port->slave->dev->name, port->actor_oper_port_state);
/* lacpdu->reserved_3_1 initialized
* lacpdu->tlv_type_partner_info initialized
@@ -898,7 +903,9 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
if ((port->sm_vars & AD_PORT_SELECTED) &&
(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) &&
!__check_agg_selection_timer(port)) {
- port->sm_mux_state = AD_MUX_COLLECTING_DISTRIBUTING;
+ if (port->aggregator->is_active)
+ port->sm_mux_state =
+ AD_MUX_COLLECTING_DISTRIBUTING;
} else if (!(port->sm_vars & AD_PORT_SELECTED) ||
(port->sm_vars & AD_PORT_STANDBY)) {
/* if UNSELECTED or STANDBY */
@@ -910,12 +917,16 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
*/
__set_agg_ports_ready(port->aggregator, __agg_ports_are_ready(port->aggregator));
port->sm_mux_state = AD_MUX_DETACHED;
+ } else if (port->aggregator->is_active) {
+ port->actor_oper_port_state |=
+ AD_STATE_SYNCHRONIZATION;
}
break;
case AD_MUX_COLLECTING_DISTRIBUTING:
if (!(port->sm_vars & AD_PORT_SELECTED) ||
(port->sm_vars & AD_PORT_STANDBY) ||
- !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION)) {
+ !(port->partner_oper.port_state & AD_STATE_SYNCHRONIZATION) ||
+ !(port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) {
port->sm_mux_state = AD_MUX_ATTACHED;
} else {
/* if port state hasn't changed make
@@ -937,8 +948,10 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
/* check if the state machine was changed */
if (port->sm_mux_state != last_state) {
- pr_debug("Mux Machine: Port=%d, Last State=%d, Curr State=%d\n",
- port->actor_port_number, last_state,
+ pr_debug("Mux Machine: Port=%d (%s), Last State=%d, Curr State=%d\n",
+ port->actor_port_number,
+ port->slave->dev->name,
+ last_state,
port->sm_mux_state);
switch (port->sm_mux_state) {
case AD_MUX_DETACHED:
@@ -953,7 +966,12 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
port->sm_mux_timer_counter = __ad_timer_to_ticks(AD_WAIT_WHILE_TIMER, 0);
break;
case AD_MUX_ATTACHED:
- port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION;
+ if (port->aggregator->is_active)
+ port->actor_oper_port_state |=
+ AD_STATE_SYNCHRONIZATION;
+ else
+ port->actor_oper_port_state &=
+ ~AD_STATE_SYNCHRONIZATION;
port->actor_oper_port_state &= ~AD_STATE_COLLECTING;
port->actor_oper_port_state &= ~AD_STATE_DISTRIBUTING;
ad_disable_collecting_distributing(port,
@@ -963,6 +981,7 @@ static void ad_mux_machine(struct port *port, bool *update_slave_arr)
case AD_MUX_COLLECTING_DISTRIBUTING:
port->actor_oper_port_state |= AD_STATE_COLLECTING;
port->actor_oper_port_state |= AD_STATE_DISTRIBUTING;
+ port->actor_oper_port_state |= AD_STATE_SYNCHRONIZATION;
ad_enable_collecting_distributing(port,
update_slave_arr);
port->ntt = true;
@@ -1044,8 +1063,10 @@ static void ad_rx_machine(struct lacpdu *lacpdu, struct port *port)
/* check if the State machine was changed or new lacpdu arrived */
if ((port->sm_rx_state != last_state) || (lacpdu)) {
- pr_debug("Rx Machine: Port=%d, Last State=%d, Curr State=%d\n",
- port->actor_port_number, last_state,
+ pr_debug("Rx Machine: Port=%d (%s), Last State=%d, Curr State=%d\n",
+ port->actor_port_number,
+ port->slave->dev->name,
+ last_state,
port->sm_rx_state);
switch (port->sm_rx_state) {
case AD_RX_INITIALIZE:
@@ -1394,6 +1415,9 @@ static void ad_port_selection_logic(struct port *port, bool *update_slave_arr)
aggregator = __get_first_agg(port);
ad_agg_selection_logic(aggregator, update_slave_arr);
+
+ if (!port->aggregator->is_active)
+ port->actor_oper_port_state &= ~AD_STATE_SYNCHRONIZATION;
}
/* Decide if "agg" is a better choice for the new active aggregator that
@@ -2195,8 +2219,10 @@ static int bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave,
switch (lacpdu->subtype) {
case AD_TYPE_LACPDU:
ret = RX_HANDLER_CONSUMED;
- netdev_dbg(slave->bond->dev, "Received LACPDU on port %d\n",
- port->actor_port_number);
+ netdev_dbg(slave->bond->dev,
+ "Received LACPDU on port %d slave %s\n",
+ port->actor_port_number,
+ slave->dev->name);
/* Protect against concurrent state machines */
spin_lock(&slave->bond->mode_lock);
ad_rx_machine(lacpdu, port);
@@ -2288,7 +2314,10 @@ void bond_3ad_adapter_duplex_changed(struct slave *slave)
port->actor_admin_port_key &= ~AD_DUPLEX_KEY_MASKS;
port->actor_oper_port_key = port->actor_admin_port_key |=
__get_duplex(port);
- netdev_dbg(slave->bond->dev, "Port %d changed duplex\n", port->actor_port_number);
+ netdev_dbg(slave->bond->dev, "Port %d slave %s changed duplex\n",
+ port->actor_port_number, slave->dev->name);
+ if (port->actor_oper_port_key & AD_DUPLEX_KEY_MASKS)
+ port->sm_vars |= AD_PORT_LACP_ENABLED;
/* there is no need to reselect a new aggregator, just signal the
* state machines to reinitialize
*/
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 0dceba1a2ba1..b979c265fc51 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -77,6 +77,7 @@
#include <net/pkt_sched.h>
#include <linux/rculist.h>
#include <net/flow_keys.h>
+#include <net/switchdev.h>
#include <net/bonding.h>
#include <net/bond_3ad.h>
#include <net/bond_alb.h>
@@ -334,7 +335,7 @@ static int bond_vlan_rx_kill_vid(struct net_device *bond_dev,
*
* Returns zero if carrier state does not change, nonzero if it does.
*/
-static int bond_set_carrier(struct bonding *bond)
+int bond_set_carrier(struct bonding *bond)
{
struct list_head *iter;
struct slave *slave;
@@ -789,7 +790,7 @@ void bond_change_active_slave(struct bonding *bond, struct slave *new_active)
}
new_active->delay = 0;
- new_active->link = BOND_LINK_UP;
+ bond_set_slave_link_state(new_active, BOND_LINK_UP);
if (BOND_MODE(bond) == BOND_MODE_8023AD)
bond_3ad_handle_link_change(new_active, BOND_LINK_UP);
@@ -979,7 +980,11 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
netdev_features_t mask;
struct slave *slave;
- mask = features;
+ /* If any slave has the offload feature flag set,
+ * set the offload flag on the bond.
+ */
+ mask = features | NETIF_F_HW_SWITCH_OFFLOAD;
+
features &= ~NETIF_F_ONE_FOR_ALL;
features |= NETIF_F_ALL_FOR_ALL;
@@ -998,7 +1003,7 @@ static netdev_features_t bond_fix_features(struct net_device *dev,
NETIF_F_HIGHDMA | NETIF_F_LRO)
#define BOND_ENC_FEATURES (NETIF_F_ALL_CSUM | NETIF_F_SG | NETIF_F_RXCSUM |\
- NETIF_F_TSO | NETIF_F_GSO_UDP_TUNNEL)
+ NETIF_F_TSO)
static void bond_compute_features(struct bonding *bond)
{
@@ -1034,7 +1039,7 @@ static void bond_compute_features(struct bonding *bond)
done:
bond_dev->vlan_features = vlan_features;
- bond_dev->hw_enc_features = enc_features;
+ bond_dev->hw_enc_features = enc_features | NETIF_F_GSO_ENCAP_ALL;
bond_dev->hard_header_len = max_hard_header_len;
bond_dev->gso_max_segs = gso_max_segs;
netif_set_gso_max_size(bond_dev, gso_max_size);
@@ -1176,6 +1181,56 @@ static void bond_free_slave(struct slave *slave)
kfree(slave);
}
+static void bond_fill_ifbond(struct bonding *bond, struct ifbond *info)
+{
+ info->bond_mode = BOND_MODE(bond);
+ info->miimon = bond->params.miimon;
+ info->num_slaves = bond->slave_cnt;
+}
+
+static void bond_fill_ifslave(struct slave *slave, struct ifslave *info)
+{
+ strcpy(info->slave_name, slave->dev->name);
+ info->link = slave->link;
+ info->state = bond_slave_state(slave);
+ info->link_failure_count = slave->link_failure_count;
+}
+
+static void bond_netdev_notify(struct net_device *dev,
+ struct netdev_bonding_info *info)
+{
+ rtnl_lock();
+ netdev_bonding_info_change(dev, info);
+ rtnl_unlock();
+}
+
+static void bond_netdev_notify_work(struct work_struct *_work)
+{
+ struct netdev_notify_work *w =
+ container_of(_work, struct netdev_notify_work, work.work);
+
+ bond_netdev_notify(w->dev, &w->bonding_info);
+ dev_put(w->dev);
+ kfree(w);
+}
+
+void bond_queue_slave_event(struct slave *slave)
+{
+ struct bonding *bond = slave->bond;
+ struct netdev_notify_work *nnw = kzalloc(sizeof(*nnw), GFP_ATOMIC);
+
+ if (!nnw)
+ return;
+
+ dev_hold(slave->dev);
+ nnw->dev = slave->dev;
+ bond_fill_ifslave(slave, &nnw->bonding_info.slave);
+ bond_fill_ifbond(bond, &nnw->bonding_info.master);
+ INIT_DELAYED_WORK(&nnw->work, bond_netdev_notify_work);
+
+ queue_delayed_work(slave->bond->wq, &nnw->work, 0);
+}
+
/* enslave device <slave> to bond device <master> */
int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
{
@@ -1439,19 +1494,22 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
if (bond->params.miimon) {
if (bond_check_dev_link(bond, slave_dev, 0) == BMSR_LSTATUS) {
if (bond->params.updelay) {
- new_slave->link = BOND_LINK_BACK;
+ bond_set_slave_link_state(new_slave,
+ BOND_LINK_BACK);
new_slave->delay = bond->params.updelay;
} else {
- new_slave->link = BOND_LINK_UP;
+ bond_set_slave_link_state(new_slave,
+ BOND_LINK_UP);
}
} else {
- new_slave->link = BOND_LINK_DOWN;
+ bond_set_slave_link_state(new_slave, BOND_LINK_DOWN);
}
} else if (bond->params.arp_interval) {
- new_slave->link = (netif_carrier_ok(slave_dev) ?
- BOND_LINK_UP : BOND_LINK_DOWN);
+ bond_set_slave_link_state(new_slave,
+ (netif_carrier_ok(slave_dev) ?
+ BOND_LINK_UP : BOND_LINK_DOWN));
} else {
- new_slave->link = BOND_LINK_UP;
+ bond_set_slave_link_state(new_slave, BOND_LINK_UP);
}
if (new_slave->link != BOND_LINK_DOWN)
@@ -1567,6 +1625,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
new_slave->link != BOND_LINK_DOWN ? "an up" : "a down");
/* enslave is successful */
+ bond_queue_slave_event(new_slave);
return 0;
/* Undo stages on error */
@@ -1816,11 +1875,7 @@ static int bond_release_and_destroy(struct net_device *bond_dev,
static int bond_info_query(struct net_device *bond_dev, struct ifbond *info)
{
struct bonding *bond = netdev_priv(bond_dev);
-
- info->bond_mode = BOND_MODE(bond);
- info->miimon = bond->params.miimon;
- info->num_slaves = bond->slave_cnt;
-
+ bond_fill_ifbond(bond, info);
return 0;
}
@@ -1834,10 +1889,7 @@ static int bond_slave_info_query(struct net_device *bond_dev, struct ifslave *in
bond_for_each_slave(bond, slave, iter) {
if (i++ == (int)info->slave_id) {
res = 0;
- strcpy(info->slave_name, slave->dev->name);
- info->link = slave->link;
- info->state = bond_slave_state(slave);
- info->link_failure_count = slave->link_failure_count;
+ bond_fill_ifslave(slave, info);
break;
}
}
@@ -1867,7 +1919,7 @@ static int bond_miimon_inspect(struct bonding *bond)
if (link_state)
continue;
- slave->link = BOND_LINK_FAIL;
+ bond_set_slave_link_state(slave, BOND_LINK_FAIL);
slave->delay = bond->params.downdelay;
if (slave->delay) {
netdev_info(bond->dev, "link status down for %sinterface %s, disabling it in %d ms\n",
@@ -1882,7 +1934,7 @@ static int bond_miimon_inspect(struct bonding *bond)
case BOND_LINK_FAIL:
if (link_state) {
/* recovered before downdelay expired */
- slave->link = BOND_LINK_UP;
+ bond_set_slave_link_state(slave, BOND_LINK_UP);
slave->last_link_up = jiffies;
netdev_info(bond->dev, "link status up again after %d ms for interface %s\n",
(bond->params.downdelay - slave->delay) *
@@ -1904,7 +1956,7 @@ static int bond_miimon_inspect(struct bonding *bond)
if (!link_state)
continue;
- slave->link = BOND_LINK_BACK;
+ bond_set_slave_link_state(slave, BOND_LINK_BACK);
slave->delay = bond->params.updelay;
if (slave->delay) {
@@ -1917,7 +1969,8 @@ static int bond_miimon_inspect(struct bonding *bond)
/*FALLTHRU*/
case BOND_LINK_BACK:
if (!link_state) {
- slave->link = BOND_LINK_DOWN;
+ bond_set_slave_link_state(slave,
+ BOND_LINK_DOWN);
netdev_info(bond->dev, "link status down again after %d ms for interface %s\n",
(bond->params.updelay - slave->delay) *
bond->params.miimon,
@@ -1955,7 +2008,7 @@ static void bond_miimon_commit(struct bonding *bond)
continue;
case BOND_LINK_UP:
- slave->link = BOND_LINK_UP;
+ bond_set_slave_link_state(slave, BOND_LINK_UP);
slave->last_link_up = jiffies;
primary = rtnl_dereference(bond->primary_slave);
@@ -1995,7 +2048,7 @@ static void bond_miimon_commit(struct bonding *bond)
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- slave->link = BOND_LINK_DOWN;
+ bond_set_slave_link_state(slave, BOND_LINK_DOWN);
if (BOND_MODE(bond) == BOND_MODE_ACTIVEBACKUP ||
BOND_MODE(bond) == BOND_MODE_8023AD)
@@ -2578,7 +2631,7 @@ static void bond_ab_arp_commit(struct bonding *bond)
struct slave *current_arp_slave;
current_arp_slave = rtnl_dereference(bond->current_arp_slave);
- slave->link = BOND_LINK_UP;
+ bond_set_slave_link_state(slave, BOND_LINK_UP);
if (current_arp_slave) {
bond_set_slave_inactive_flags(
current_arp_slave,
@@ -2601,7 +2654,7 @@ static void bond_ab_arp_commit(struct bonding *bond)
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
- slave->link = BOND_LINK_DOWN;
+ bond_set_slave_link_state(slave, BOND_LINK_DOWN);
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
@@ -2680,7 +2733,7 @@ static bool bond_ab_arp_probe(struct bonding *bond)
* up when it is actually down
*/
if (!bond_slave_is_up(slave) && slave->link == BOND_LINK_UP) {
- slave->link = BOND_LINK_DOWN;
+ bond_set_slave_link_state(slave, BOND_LINK_DOWN);
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
@@ -2700,7 +2753,7 @@ static bool bond_ab_arp_probe(struct bonding *bond)
if (!new_slave)
goto check_state;
- new_slave->link = BOND_LINK_BACK;
+ bond_set_slave_link_state(new_slave, BOND_LINK_BACK);
bond_set_slave_active_flags(new_slave, BOND_SLAVE_NOTIFY_LATER);
bond_arp_send_all(bond, new_slave);
new_slave->last_link_up = jiffies;
@@ -3066,7 +3119,7 @@ static int bond_open(struct net_device *bond_dev)
slave != rcu_access_pointer(bond->curr_active_slave)) {
bond_set_slave_inactive_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
- } else {
+ } else if (BOND_MODE(bond) != BOND_MODE_8023AD) {
bond_set_slave_active_flags(slave,
BOND_SLAVE_NOTIFY_NOW);
}
@@ -3734,7 +3787,7 @@ out:
* usable slave array is formed in the control path. The xmit function
* just calculates hash and sends the packet out.
*/
-int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev)
+static int bond_3ad_xor_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct bonding *bond = netdev_priv(dev);
struct slave *slave;
@@ -3952,6 +4005,8 @@ static const struct net_device_ops bond_netdev_ops = {
.ndo_add_slave = bond_enslave,
.ndo_del_slave = bond_release,
.ndo_fix_features = bond_fix_features,
+ .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink,
+ .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink,
};
static const struct device_type bond_type = {
@@ -4010,7 +4065,7 @@ void bond_setup(struct net_device *bond_dev)
NETIF_F_HW_VLAN_CTAG_FILTER;
bond_dev->hw_features &= ~(NETIF_F_ALL_CSUM & ~NETIF_F_HW_CSUM);
- bond_dev->hw_features |= NETIF_F_GSO_UDP_TUNNEL;
+ bond_dev->hw_features |= NETIF_F_GSO_ENCAP_ALL;
bond_dev->features |= bond_dev->hw_features;
}
diff --git a/drivers/net/bonding/bond_options.c b/drivers/net/bonding/bond_options.c
index 1a61cc9b3402..4df28943d222 100644
--- a/drivers/net/bonding/bond_options.c
+++ b/drivers/net/bonding/bond_options.c
@@ -186,7 +186,7 @@ static const struct bond_opt_value bond_tlb_dynamic_lb_tbl[] = {
{ NULL, -1, 0}
};
-static const struct bond_option bond_opts[] = {
+static const struct bond_option bond_opts[BOND_OPT_LAST] = {
[BOND_OPT_MODE] = {
.id = BOND_OPT_MODE,
.name = "mode",
@@ -379,8 +379,7 @@ static const struct bond_option bond_opts[] = {
.values = bond_tlb_dynamic_lb_tbl,
.flags = BOND_OPTFLAG_IFDOWN,
.set = bond_option_tlb_dynamic_lb_set,
- },
- { }
+ }
};
/* Searches for an option by name */
@@ -1182,6 +1181,7 @@ static int bond_option_min_links_set(struct bonding *bond,
netdev_info(bond->dev, "Setting min links value to %llu\n",
newval->value);
bond->params.min_links = newval->value;
+ bond_set_carrier(bond);
return 0;
}
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
index 5e40a8b68cbe..b3b922adc0e4 100644
--- a/drivers/net/caif/caif_hsi.c
+++ b/drivers/net/caif/caif_hsi.c
@@ -1415,7 +1415,6 @@ static int caif_hsi_newlink(struct net *src_net, struct net_device *dev,
cfhsi = netdev_priv(dev);
cfhsi_netlink_parms(data, cfhsi);
- dev_net_set(cfhsi->ndev, src_net);
get_ops = symbol_get(cfhsi_get_ops);
if (!get_ops) {
diff --git a/drivers/net/can/at91_can.c b/drivers/net/can/at91_can.c
index d0c2463b573f..eeb4b8b6b335 100644
--- a/drivers/net/can/at91_can.c
+++ b/drivers/net/can/at91_can.c
@@ -138,7 +138,6 @@ struct at91_devtype_data {
struct at91_priv {
struct can_priv can; /* must be the first member! */
- struct net_device *dev;
struct napi_struct napi;
void __iomem *reg_base;
@@ -1350,7 +1349,6 @@ static int at91_can_probe(struct platform_device *pdev)
priv->can.do_get_berr_counter = at91_get_berr_counter;
priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_LISTENONLY;
- priv->dev = dev;
priv->reg_base = addr;
priv->devtype_data = *devtype_data;
priv->clk = clk;
diff --git a/drivers/net/can/bfin_can.c b/drivers/net/can/bfin_can.c
index 417d50998e31..e7a6363e736b 100644
--- a/drivers/net/can/bfin_can.c
+++ b/drivers/net/can/bfin_can.c
@@ -352,6 +352,7 @@ static int bfin_can_err(struct net_device *dev, u16 isrc, u16 status)
netdev_dbg(dev, "bus-off mode interrupt\n");
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
+ priv->can.can_stats.bus_off++;
can_bus_off(dev);
}
diff --git a/drivers/net/can/c_can/c_can.c b/drivers/net/can/c_can/c_can.c
index c672c4dcffac..041525d2595c 100644
--- a/drivers/net/can/c_can/c_can.c
+++ b/drivers/net/can/c_can/c_can.c
@@ -869,7 +869,7 @@ static int c_can_handle_state_change(struct net_device *dev,
case C_CAN_BUS_OFF:
/* bus-off state */
priv->can.state = CAN_STATE_BUS_OFF;
- can_bus_off(dev);
+ priv->can.can_stats.bus_off++;
break;
default:
break;
diff --git a/drivers/net/can/cc770/cc770.c b/drivers/net/can/cc770/cc770.c
index c486fe510f37..c11d44984036 100644
--- a/drivers/net/can/cc770/cc770.c
+++ b/drivers/net/can/cc770/cc770.c
@@ -535,6 +535,7 @@ static int cc770_err(struct net_device *dev, u8 status)
cc770_write_reg(priv, control, CTRL_INI);
cf->can_id |= CAN_ERR_BUSOFF;
priv->can.state = CAN_STATE_BUS_OFF;
+ priv->can.can_stats.bus_off++;
can_bus_off(dev);
} else if (status & STAT_WARN) {
cf->can_id |= CAN_ERR_CRTL;
diff --git a/drivers/net/can/dev.c b/drivers/net/can/dev.c
index 847c1f813261..3c82e02e3dae 100644
--- a/drivers/net/can/dev.c
+++ b/drivers/net/can/dev.c
@@ -289,9 +289,11 @@ static void can_update_state_error_stats(struct net_device *dev,
priv->can_stats.error_passive++;
break;
case CAN_STATE_BUS_OFF:
+ priv->can_stats.bus_off++;
+ break;
default:
break;
- };
+ }
}
static int can_tx_state_to_frame(struct net_device *dev, enum can_state state)
@@ -544,7 +546,6 @@ void can_bus_off(struct net_device *dev)
netdev_dbg(dev, "bus-off\n");
netif_carrier_off(dev);
- priv->can_stats.bus_off++;
if (priv->restart_ms)
mod_timer(&priv->restart_timer,
diff --git a/drivers/net/can/flexcan.c b/drivers/net/can/flexcan.c
index b1d583ba9674..80c46ad4cee4 100644
--- a/drivers/net/can/flexcan.c
+++ b/drivers/net/can/flexcan.c
@@ -247,7 +247,6 @@ struct flexcan_devtype_data {
struct flexcan_priv {
struct can_priv can;
- struct net_device *dev;
struct napi_struct napi;
void __iomem *base;
@@ -1220,7 +1219,6 @@ static int flexcan_probe(struct platform_device *pdev)
CAN_CTRLMODE_LISTENONLY | CAN_CTRLMODE_3_SAMPLES |
CAN_CTRLMODE_BERR_REPORTING;
priv->base = base;
- priv->dev = dev;
priv->clk_ipg = clk_ipg;
priv->clk_per = clk_per;
priv->pdata = dev_get_platdata(&pdev->dev);
diff --git a/drivers/net/can/janz-ican3.c b/drivers/net/can/janz-ican3.c
index 1b118394907f..4dd183a3643a 100644
--- a/drivers/net/can/janz-ican3.c
+++ b/drivers/net/can/janz-ican3.c
@@ -1008,6 +1008,7 @@ static int ican3_handle_cevtind(struct ican3_dev *mod, struct ican3_msg *msg)
if (status & SR_BS) {
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
+ mod->can.can_stats.bus_off++;
can_bus_off(dev);
} else if (status & SR_ES) {
if (rxerr >= 128 || txerr >= 128)
@@ -1678,8 +1679,7 @@ static int ican3_get_berr_counter(const struct net_device *ndev,
if (ret)
return ret;
- ret = wait_for_completion_timeout(&mod->buserror_comp, HZ);
- if (ret == 0) {
+ if (!wait_for_completion_timeout(&mod->buserror_comp, HZ)) {
netdev_info(mod->ndev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
@@ -1704,8 +1704,7 @@ static ssize_t ican3_sysfs_show_term(struct device *dev,
if (ret)
return ret;
- ret = wait_for_completion_timeout(&mod->termination_comp, HZ);
- if (ret == 0) {
+ if (!wait_for_completion_timeout(&mod->termination_comp, HZ)) {
netdev_info(mod->ndev, "%s timed out\n", __func__);
return -ETIMEDOUT;
}
diff --git a/drivers/net/can/m_can/m_can.c b/drivers/net/can/m_can/m_can.c
index 244529881be9..2e04b3aeeb37 100644
--- a/drivers/net/can/m_can/m_can.c
+++ b/drivers/net/can/m_can/m_can.c
@@ -589,6 +589,7 @@ static int m_can_handle_state_change(struct net_device *dev,
/* bus-off state */
priv->can.state = CAN_STATE_BUS_OFF;
m_can_disable_all_interrupts(priv);
+ priv->can.can_stats.bus_off++;
can_bus_off(dev);
break;
default:
diff --git a/drivers/net/can/pch_can.c b/drivers/net/can/pch_can.c
index a67eb01f3028..e187ca783da0 100644
--- a/drivers/net/can/pch_can.c
+++ b/drivers/net/can/pch_can.c
@@ -505,6 +505,7 @@ static void pch_can_error(struct net_device *ndev, u32 status)
pch_can_set_rx_all(priv, 0);
state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
+ priv->can.can_stats.bus_off++;
can_bus_off(ndev);
}
diff --git a/drivers/net/can/rcar_can.c b/drivers/net/can/rcar_can.c
index 91cd48ca0efc..7deb80dcbe8c 100644
--- a/drivers/net/can/rcar_can.c
+++ b/drivers/net/can/rcar_can.c
@@ -331,6 +331,7 @@ static void rcar_can_error(struct net_device *ndev)
priv->can.state = CAN_STATE_BUS_OFF;
/* Clear interrupt condition */
writeb(~RCAR_CAN_EIFR_BOEIF, &priv->regs->eifr);
+ priv->can.can_stats.bus_off++;
can_bus_off(ndev);
if (skb)
cf->can_id |= CAN_ERR_BUSOFF;
diff --git a/drivers/net/can/softing/softing_main.c b/drivers/net/can/softing/softing_main.c
index 2bf98d862302..7621f91a8a20 100644
--- a/drivers/net/can/softing/softing_main.c
+++ b/drivers/net/can/softing/softing_main.c
@@ -261,6 +261,7 @@ static int softing_handle_1(struct softing *card)
++priv->can.can_stats.error_passive;
else if (can_state == CAN_STATE_BUS_OFF) {
/* this calls can_close_cleanup() */
+ ++priv->can.can_stats.bus_off;
can_bus_off(netdev);
netif_stop_queue(netdev);
}
diff --git a/drivers/net/can/spi/mcp251x.c b/drivers/net/can/spi/mcp251x.c
index c66d699640a9..bf63fee4e743 100644
--- a/drivers/net/can/spi/mcp251x.c
+++ b/drivers/net/can/spi/mcp251x.c
@@ -905,6 +905,7 @@ static irqreturn_t mcp251x_can_ist(int irq, void *dev_id)
if (priv->can.state == CAN_STATE_BUS_OFF) {
if (priv->can.restart_ms == 0) {
priv->force_quit = 1;
+ priv->can.can_stats.bus_off++;
can_bus_off(net);
mcp251x_hw_sleep(spi);
break;
diff --git a/drivers/net/can/ti_hecc.c b/drivers/net/can/ti_hecc.c
index 9a07eafe554b..e95a9e1a889f 100644
--- a/drivers/net/can/ti_hecc.c
+++ b/drivers/net/can/ti_hecc.c
@@ -715,6 +715,7 @@ static int ti_hecc_error(struct net_device *ndev, int int_status,
hecc_clear_bit(priv, HECC_CANMC, HECC_CANMC_CCR);
/* Disable all interrupts in bus-off to avoid int hog */
hecc_write(priv, HECC_CANGIM, 0);
+ ++priv->can.can_stats.bus_off;
can_bus_off(ndev);
}
diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
index a77db919363c..bcb272f6c68a 100644
--- a/drivers/net/can/usb/Kconfig
+++ b/drivers/net/can/usb/Kconfig
@@ -25,7 +25,7 @@ config CAN_KVASER_USB
tristate "Kvaser CAN/USB interface"
---help---
This driver adds support for Kvaser CAN/USB devices like Kvaser
- Leaf Light.
+ Leaf Light and Kvaser USBcan II.
The driver provides support for the following devices:
- Kvaser Leaf Light
@@ -46,6 +46,12 @@ config CAN_KVASER_USB
- Kvaser USBcan R
- Kvaser Leaf Light v2
- Kvaser Mini PCI Express HS
+ - Kvaser USBcan II HS/HS
+ - Kvaser USBcan II HS/LS
+ - Kvaser USBcan Rugged ("USBcan Rev B")
+ - Kvaser Memorator HS/HS
+ - Kvaser Memorator HS/LS
+ - Scania VCI2 (if you have the Kvaser logo on top)
If unsure, say N.
@@ -53,10 +59,18 @@ config CAN_KVASER_USB
module will be called kvaser_usb.
config CAN_PEAK_USB
- tristate "PEAK PCAN-USB/USB Pro interfaces"
+ tristate "PEAK PCAN-USB/USB Pro interfaces for CAN 2.0b/CAN-FD"
---help---
- This driver supports the PCAN-USB and PCAN-USB Pro adapters
- from PEAK-System Technik (http://www.peak-system.com).
+ This driver supports the PEAK-System Technik USB adapters that enable
+ access to the CAN bus, with repect to the CAN 2.0b and/or CAN-FD
+ standards, that is:
+
+ PCAN-USB single CAN 2.0b channel USB adapter
+ PCAN-USB Pro dual CAN 2.0b channels USB adapter
+ PCAN-USB FD single CAN-FD channel USB adapter
+ PCAN-USB Pro FD dual CAN-FD channels USB adapter
+
+ (see also http://www.peak-system.com).
config CAN_8DEV_USB
tristate "8 devices USB2CAN interface"
diff --git a/drivers/net/can/usb/ems_usb.c b/drivers/net/can/usb/ems_usb.c
index 29d3f0938eb8..9376f5e5b94e 100644
--- a/drivers/net/can/usb/ems_usb.c
+++ b/drivers/net/can/usb/ems_usb.c
@@ -347,6 +347,7 @@ static void ems_usb_rx_err(struct ems_usb *dev, struct ems_cpc_msg *msg)
dev->can.state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
+ dev->can.can_stats.bus_off++;
can_bus_off(dev->netdev);
} else if (state & SJA1000_SR_ES) {
dev->can.state = CAN_STATE_ERROR_WARNING;
diff --git a/drivers/net/can/usb/esd_usb2.c b/drivers/net/can/usb/esd_usb2.c
index c063a54ab8dd..bacca0bd89c1 100644
--- a/drivers/net/can/usb/esd_usb2.c
+++ b/drivers/net/can/usb/esd_usb2.c
@@ -250,6 +250,7 @@ static void esd_usb2_rx_event(struct esd_usb2_net_priv *priv,
case ESD_BUSSTATE_BUSOFF:
priv->can.state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
+ priv->can.can_stats.bus_off++;
can_bus_off(priv->netdev);
break;
case ESD_BUSSTATE_WARN:
diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
index 7af379ca861b..2928f7003041 100644
--- a/drivers/net/can/usb/kvaser_usb.c
+++ b/drivers/net/can/usb/kvaser_usb.c
@@ -6,10 +6,12 @@
* Parts of this driver are based on the following:
* - Kvaser linux leaf driver (version 4.78)
* - CAN driver for esd CAN-USB/2
+ * - Kvaser linux usbcanII driver (version 5.3)
*
* Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
* Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
* Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
+ * Copyright (C) 2015 Valeo S.A.
*/
#include <linux/completion.h>
@@ -30,8 +32,9 @@
#define RX_BUFFER_SIZE 3072
#define CAN_USB_CLOCK 8000000
#define MAX_NET_DEVICES 3
+#define MAX_USBCAN_NET_DEVICES 2
-/* Kvaser USB devices */
+/* Kvaser Leaf USB devices */
#define KVASER_VENDOR_ID 0x0bfd
#define USB_LEAF_DEVEL_PRODUCT_ID 10
#define USB_LEAF_LITE_PRODUCT_ID 11
@@ -56,6 +59,24 @@
#define USB_LEAF_LITE_V2_PRODUCT_ID 288
#define USB_MINI_PCIE_HS_PRODUCT_ID 289
+static inline bool kvaser_is_leaf(const struct usb_device_id *id)
+{
+ return id->idProduct >= USB_LEAF_DEVEL_PRODUCT_ID &&
+ id->idProduct <= USB_MINI_PCIE_HS_PRODUCT_ID;
+}
+
+/* Kvaser USBCan-II devices */
+#define USB_USBCAN_REVB_PRODUCT_ID 2
+#define USB_VCI2_PRODUCT_ID 3
+#define USB_USBCAN2_PRODUCT_ID 4
+#define USB_MEMORATOR_PRODUCT_ID 5
+
+static inline bool kvaser_is_usbcan(const struct usb_device_id *id)
+{
+ return id->idProduct >= USB_USBCAN_REVB_PRODUCT_ID &&
+ id->idProduct <= USB_MEMORATOR_PRODUCT_ID;
+}
+
/* USB devices features */
#define KVASER_HAS_SILENT_MODE BIT(0)
#define KVASER_HAS_TXRX_ERRORS BIT(1)
@@ -73,7 +94,7 @@
#define MSG_FLAG_TX_ACK BIT(6)
#define MSG_FLAG_TX_REQUEST BIT(7)
-/* Can states */
+/* Can states (M16C CxSTRH register) */
#define M16C_STATE_BUS_RESET BIT(0)
#define M16C_STATE_BUS_ERROR BIT(4)
#define M16C_STATE_BUS_PASSIVE BIT(5)
@@ -98,7 +119,11 @@
#define CMD_START_CHIP_REPLY 27
#define CMD_STOP_CHIP 28
#define CMD_STOP_CHIP_REPLY 29
-#define CMD_GET_CARD_INFO2 32
+
+#define CMD_LEAF_GET_CARD_INFO2 32
+#define CMD_USBCAN_RESET_CLOCK 32
+#define CMD_USBCAN_CLOCK_OVERFLOW_EVENT 33
+
#define CMD_GET_CARD_INFO 34
#define CMD_GET_CARD_INFO_REPLY 35
#define CMD_GET_SOFTWARE_INFO 38
@@ -108,8 +133,9 @@
#define CMD_RESET_ERROR_COUNTER 49
#define CMD_TX_ACKNOWLEDGE 50
#define CMD_CAN_ERROR_EVENT 51
-#define CMD_USB_THROTTLE 77
-#define CMD_LOG_MESSAGE 106
+
+#define CMD_LEAF_USB_THROTTLE 77
+#define CMD_LEAF_LOG_MESSAGE 106
/* error factors */
#define M16C_EF_ACKE BIT(0)
@@ -121,6 +147,14 @@
#define M16C_EF_RCVE BIT(6)
#define M16C_EF_TRE BIT(7)
+/* Only Leaf-based devices can report M16C error factors,
+ * thus define our own error status flags for USBCANII
+ */
+#define USBCAN_ERROR_STATE_NONE 0
+#define USBCAN_ERROR_STATE_TX_ERROR BIT(0)
+#define USBCAN_ERROR_STATE_RX_ERROR BIT(1)
+#define USBCAN_ERROR_STATE_BUSERROR BIT(2)
+
/* bittiming parameters */
#define KVASER_USB_TSEG1_MIN 1
#define KVASER_USB_TSEG1_MAX 16
@@ -137,9 +171,18 @@
#define KVASER_CTRL_MODE_SELFRECEPTION 3
#define KVASER_CTRL_MODE_OFF 4
-/* log message */
+/* Extended CAN identifier flag */
#define KVASER_EXTENDED_FRAME BIT(31)
+/* Kvaser USB CAN dongles are divided into two major families:
+ * - Leaf: Based on Renesas M32C, running firmware labeled as 'filo'
+ * - UsbcanII: Based on Renesas M16C, running firmware labeled as 'helios'
+ */
+enum kvaser_usb_family {
+ KVASER_LEAF,
+ KVASER_USBCAN,
+};
+
struct kvaser_msg_simple {
u8 tid;
u8 channel;
@@ -148,30 +191,55 @@ struct kvaser_msg_simple {
struct kvaser_msg_cardinfo {
u8 tid;
u8 nchannels;
- __le32 serial_number;
- __le32 padding;
+ union {
+ struct {
+ __le32 serial_number;
+ __le32 padding;
+ } __packed leaf0;
+ struct {
+ __le32 serial_number_low;
+ __le32 serial_number_high;
+ } __packed usbcan0;
+ } __packed;
__le32 clock_resolution;
__le32 mfgdate;
u8 ean[8];
u8 hw_revision;
- u8 usb_hs_mode;
- __le16 padding2;
+ union {
+ struct {
+ u8 usb_hs_mode;
+ } __packed leaf1;
+ struct {
+ u8 padding;
+ } __packed usbcan1;
+ } __packed;
+ __le16 padding;
} __packed;
struct kvaser_msg_cardinfo2 {
u8 tid;
- u8 channel;
+ u8 reserved;
u8 pcb_id[24];
__le32 oem_unlock_code;
} __packed;
-struct kvaser_msg_softinfo {
+struct leaf_msg_softinfo {
u8 tid;
- u8 channel;
+ u8 padding0;
__le32 sw_options;
__le32 fw_version;
__le16 max_outstanding_tx;
- __le16 padding[9];
+ __le16 padding1[9];
+} __packed;
+
+struct usbcan_msg_softinfo {
+ u8 tid;
+ u8 fw_name[5];
+ __le16 max_outstanding_tx;
+ u8 padding[6];
+ __le32 fw_version;
+ __le16 checksum;
+ __le16 sw_options;
} __packed;
struct kvaser_msg_busparams {
@@ -188,36 +256,86 @@ struct kvaser_msg_tx_can {
u8 channel;
u8 tid;
u8 msg[14];
- u8 padding;
- u8 flags;
+ union {
+ struct {
+ u8 padding;
+ u8 flags;
+ } __packed leaf;
+ struct {
+ u8 flags;
+ u8 padding;
+ } __packed usbcan;
+ } __packed;
+} __packed;
+
+struct kvaser_msg_rx_can_header {
+ u8 channel;
+ u8 flag;
} __packed;
-struct kvaser_msg_rx_can {
+struct leaf_msg_rx_can {
u8 channel;
u8 flag;
+
__le16 time[3];
u8 msg[14];
} __packed;
-struct kvaser_msg_chip_state_event {
+struct usbcan_msg_rx_can {
+ u8 channel;
+ u8 flag;
+
+ u8 msg[14];
+ __le16 time;
+} __packed;
+
+struct leaf_msg_chip_state_event {
u8 tid;
u8 channel;
+
__le16 time[3];
u8 tx_errors_count;
u8 rx_errors_count;
+
u8 status;
u8 padding[3];
} __packed;
-struct kvaser_msg_tx_acknowledge {
+struct usbcan_msg_chip_state_event {
+ u8 tid;
+ u8 channel;
+
+ u8 tx_errors_count;
+ u8 rx_errors_count;
+ __le16 time;
+
+ u8 status;
+ u8 padding[3];
+} __packed;
+
+struct kvaser_msg_tx_acknowledge_header {
u8 channel;
u8 tid;
+} __packed;
+
+struct leaf_msg_tx_acknowledge {
+ u8 channel;
+ u8 tid;
+
__le16 time[3];
u8 flags;
u8 time_offset;
} __packed;
-struct kvaser_msg_error_event {
+struct usbcan_msg_tx_acknowledge {
+ u8 channel;
+ u8 tid;
+
+ __le16 time;
+ __le16 padding;
+} __packed;
+
+struct leaf_msg_error_event {
u8 tid;
u8 flags;
__le16 time[3];
@@ -229,6 +347,18 @@ struct kvaser_msg_error_event {
u8 error_factor;
} __packed;
+struct usbcan_msg_error_event {
+ u8 tid;
+ u8 padding;
+ u8 tx_errors_count_ch0;
+ u8 rx_errors_count_ch0;
+ u8 tx_errors_count_ch1;
+ u8 rx_errors_count_ch1;
+ u8 status_ch0;
+ u8 status_ch1;
+ __le16 time;
+} __packed;
+
struct kvaser_msg_ctrl_mode {
u8 tid;
u8 channel;
@@ -243,7 +373,7 @@ struct kvaser_msg_flush_queue {
u8 padding[3];
} __packed;
-struct kvaser_msg_log_message {
+struct leaf_msg_log_message {
u8 channel;
u8 flags;
__le16 time[3];
@@ -260,19 +390,57 @@ struct kvaser_msg {
struct kvaser_msg_simple simple;
struct kvaser_msg_cardinfo cardinfo;
struct kvaser_msg_cardinfo2 cardinfo2;
- struct kvaser_msg_softinfo softinfo;
struct kvaser_msg_busparams busparams;
+
+ struct kvaser_msg_rx_can_header rx_can_header;
+ struct kvaser_msg_tx_acknowledge_header tx_acknowledge_header;
+
+ union {
+ struct leaf_msg_softinfo softinfo;
+ struct leaf_msg_rx_can rx_can;
+ struct leaf_msg_chip_state_event chip_state_event;
+ struct leaf_msg_tx_acknowledge tx_acknowledge;
+ struct leaf_msg_error_event error_event;
+ struct leaf_msg_log_message log_message;
+ } __packed leaf;
+
+ union {
+ struct usbcan_msg_softinfo softinfo;
+ struct usbcan_msg_rx_can rx_can;
+ struct usbcan_msg_chip_state_event chip_state_event;
+ struct usbcan_msg_tx_acknowledge tx_acknowledge;
+ struct usbcan_msg_error_event error_event;
+ } __packed usbcan;
+
struct kvaser_msg_tx_can tx_can;
- struct kvaser_msg_rx_can rx_can;
- struct kvaser_msg_chip_state_event chip_state_event;
- struct kvaser_msg_tx_acknowledge tx_acknowledge;
- struct kvaser_msg_error_event error_event;
struct kvaser_msg_ctrl_mode ctrl_mode;
struct kvaser_msg_flush_queue flush_queue;
- struct kvaser_msg_log_message log_message;
} u;
} __packed;
+/* Summary of a kvaser error event, for a unified Leaf/Usbcan error
+ * handling. Some discrepancies between the two families exist:
+ *
+ * - USBCAN firmware does not report M16C "error factors"
+ * - USBCAN controllers has difficulties reporting if the raised error
+ * event is for ch0 or ch1. They leave such arbitration to the OS
+ * driver by letting it compare error counters with previous values
+ * and decide the error event's channel. Thus for USBCAN, the channel
+ * field is only advisory.
+ */
+struct kvaser_usb_error_summary {
+ u8 channel, status, txerr, rxerr;
+ union {
+ struct {
+ u8 error_factor;
+ } leaf;
+ struct {
+ u8 other_ch_status;
+ u8 error_state;
+ } usbcan;
+ };
+};
+
struct kvaser_usb_tx_urb_context {
struct kvaser_usb_net_priv *priv;
u32 echo_index;
@@ -288,6 +456,7 @@ struct kvaser_usb {
u32 fw_version;
unsigned int nchannels;
+ enum kvaser_usb_family family;
bool rxinitdone;
void *rxbuf[MAX_RX_URBS];
@@ -311,6 +480,7 @@ struct kvaser_usb_net_priv {
};
static const struct usb_device_id kvaser_usb_table[] = {
+ /* Leaf family IDs */
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
@@ -360,6 +530,17 @@ static const struct usb_device_id kvaser_usb_table[] = {
.driver_info = KVASER_HAS_TXRX_ERRORS },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_V2_PRODUCT_ID) },
{ USB_DEVICE(KVASER_VENDOR_ID, USB_MINI_PCIE_HS_PRODUCT_ID) },
+
+ /* USBCANII family IDs */
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN2_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_USBCAN_REVB_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMORATOR_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+ { USB_DEVICE(KVASER_VENDOR_ID, USB_VCI2_PRODUCT_ID),
+ .driver_info = KVASER_HAS_TXRX_ERRORS },
+
{ }
};
MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
@@ -463,7 +644,14 @@ static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
if (err)
return err;
- dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
+ switch (dev->family) {
+ case KVASER_LEAF:
+ dev->fw_version = le32_to_cpu(msg.u.leaf.softinfo.fw_version);
+ break;
+ case KVASER_USBCAN:
+ dev->fw_version = le32_to_cpu(msg.u.usbcan.softinfo.fw_version);
+ break;
+ }
return 0;
}
@@ -482,7 +670,9 @@ static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
return err;
dev->nchannels = msg.u.cardinfo.nchannels;
- if (dev->nchannels > MAX_NET_DEVICES)
+ if ((dev->nchannels > MAX_NET_DEVICES) ||
+ (dev->family == KVASER_USBCAN &&
+ dev->nchannels > MAX_USBCAN_NET_DEVICES))
return -EINVAL;
return 0;
@@ -496,8 +686,10 @@ static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
struct kvaser_usb_net_priv *priv;
struct sk_buff *skb;
struct can_frame *cf;
- u8 channel = msg->u.tx_acknowledge.channel;
- u8 tid = msg->u.tx_acknowledge.tid;
+ u8 channel, tid;
+
+ channel = msg->u.tx_acknowledge_header.channel;
+ tid = msg->u.tx_acknowledge_header.tid;
if (channel >= dev->nchannels) {
dev_err(dev->udev->dev.parent,
@@ -615,158 +807,280 @@ static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
priv->tx_contexts[i].echo_index = MAX_TX_URBS;
}
-static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
- const struct kvaser_msg *msg)
+static void kvaser_usb_rx_error_update_can_state(struct kvaser_usb_net_priv *priv,
+ const struct kvaser_usb_error_summary *es,
+ struct can_frame *cf)
{
- struct can_frame *cf;
- struct sk_buff *skb;
- struct net_device_stats *stats;
- struct kvaser_usb_net_priv *priv;
- unsigned int new_state;
- u8 channel, status, txerr, rxerr, error_factor;
+ struct kvaser_usb *dev = priv->dev;
+ struct net_device_stats *stats = &priv->netdev->stats;
+ enum can_state cur_state, new_state, tx_state, rx_state;
- switch (msg->id) {
- case CMD_CAN_ERROR_EVENT:
- channel = msg->u.error_event.channel;
- status = msg->u.error_event.status;
- txerr = msg->u.error_event.tx_errors_count;
- rxerr = msg->u.error_event.rx_errors_count;
- error_factor = msg->u.error_event.error_factor;
- break;
- case CMD_LOG_MESSAGE:
- channel = msg->u.log_message.channel;
- status = msg->u.log_message.data[0];
- txerr = msg->u.log_message.data[2];
- rxerr = msg->u.log_message.data[3];
- error_factor = msg->u.log_message.data[1];
+ netdev_dbg(priv->netdev, "Error status: 0x%02x\n", es->status);
+
+ new_state = cur_state = priv->can.state;
+
+ if (es->status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET))
+ new_state = CAN_STATE_BUS_OFF;
+ else if (es->status & M16C_STATE_BUS_PASSIVE)
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ else if (es->status & M16C_STATE_BUS_ERROR) {
+ /* Guard against spurious error events after a busoff */
+ if (cur_state < CAN_STATE_BUS_OFF) {
+ if ((es->txerr >= 128) || (es->rxerr >= 128))
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ else if ((es->txerr >= 96) || (es->rxerr >= 96))
+ new_state = CAN_STATE_ERROR_WARNING;
+ else if (cur_state > CAN_STATE_ERROR_ACTIVE)
+ new_state = CAN_STATE_ERROR_ACTIVE;
+ }
+ }
+
+ if (!es->status)
+ new_state = CAN_STATE_ERROR_ACTIVE;
+
+ if (new_state != cur_state) {
+ tx_state = (es->txerr >= es->rxerr) ? new_state : 0;
+ rx_state = (es->txerr <= es->rxerr) ? new_state : 0;
+
+ can_change_state(priv->netdev, cf, tx_state, rx_state);
+ }
+
+ if (priv->can.restart_ms &&
+ (cur_state >= CAN_STATE_BUS_OFF) &&
+ (new_state < CAN_STATE_BUS_OFF)) {
+ priv->can.can_stats.restarts++;
+ }
+
+ switch (dev->family) {
+ case KVASER_LEAF:
+ if (es->leaf.error_factor) {
+ priv->can.can_stats.bus_error++;
+ stats->rx_errors++;
+ }
break;
- case CMD_CHIP_STATE_EVENT:
- channel = msg->u.chip_state_event.channel;
- status = msg->u.chip_state_event.status;
- txerr = msg->u.chip_state_event.tx_errors_count;
- rxerr = msg->u.chip_state_event.rx_errors_count;
- error_factor = 0;
+ case KVASER_USBCAN:
+ if (es->usbcan.error_state & USBCAN_ERROR_STATE_TX_ERROR)
+ stats->tx_errors++;
+ if (es->usbcan.error_state & USBCAN_ERROR_STATE_RX_ERROR)
+ stats->rx_errors++;
+ if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
+ priv->can.can_stats.bus_error++;
+ }
break;
- default:
- dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
- msg->id);
- return;
}
- if (channel >= dev->nchannels) {
+ priv->bec.txerr = es->txerr;
+ priv->bec.rxerr = es->rxerr;
+}
+
+static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
+ const struct kvaser_usb_error_summary *es)
+{
+ struct can_frame *cf, tmp_cf = { .can_id = CAN_ERR_FLAG, .can_dlc = CAN_ERR_DLC };
+ struct sk_buff *skb;
+ struct net_device_stats *stats;
+ struct kvaser_usb_net_priv *priv;
+ enum can_state old_state, new_state;
+
+ if (es->channel >= dev->nchannels) {
dev_err(dev->udev->dev.parent,
- "Invalid channel number (%d)\n", channel);
+ "Invalid channel number (%d)\n", es->channel);
return;
}
- priv = dev->nets[channel];
+ priv = dev->nets[es->channel];
stats = &priv->netdev->stats;
+ /* Update all of the can interface's state and error counters before
+ * trying any memory allocation that can actually fail with -ENOMEM.
+ *
+ * We send a temporary stack-allocated error can frame to
+ * can_change_state() for the very same reason.
+ *
+ * TODO: Split can_change_state() responsibility between updating the
+ * can interface's state and counters, and the setting up of can error
+ * frame ID and data to userspace. Remove stack allocation afterwards.
+ */
+ old_state = priv->can.state;
+ kvaser_usb_rx_error_update_can_state(priv, es, &tmp_cf);
+ new_state = priv->can.state;
+
skb = alloc_can_err_skb(priv->netdev, &cf);
if (!skb) {
stats->rx_dropped++;
return;
}
+ memcpy(cf, &tmp_cf, sizeof(*cf));
+
+ if (new_state != old_state) {
+ if (es->status &
+ (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) {
+ if (!priv->can.restart_ms)
+ kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
+ netif_carrier_off(priv->netdev);
+ }
- new_state = priv->can.state;
-
- netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
+ if (priv->can.restart_ms &&
+ (old_state >= CAN_STATE_BUS_OFF) &&
+ (new_state < CAN_STATE_BUS_OFF)) {
+ cf->can_id |= CAN_ERR_RESTARTED;
+ netif_carrier_on(priv->netdev);
+ }
+ }
- if (status & (M16C_STATE_BUS_OFF | M16C_STATE_BUS_RESET)) {
- cf->can_id |= CAN_ERR_BUSOFF;
+ switch (dev->family) {
+ case KVASER_LEAF:
+ if (es->leaf.error_factor) {
+ cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
+
+ if (es->leaf.error_factor & M16C_EF_ACKE)
+ cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
+ if (es->leaf.error_factor & M16C_EF_CRCE)
+ cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
+ CAN_ERR_PROT_LOC_CRC_DEL);
+ if (es->leaf.error_factor & M16C_EF_FORME)
+ cf->data[2] |= CAN_ERR_PROT_FORM;
+ if (es->leaf.error_factor & M16C_EF_STFE)
+ cf->data[2] |= CAN_ERR_PROT_STUFF;
+ if (es->leaf.error_factor & M16C_EF_BITE0)
+ cf->data[2] |= CAN_ERR_PROT_BIT0;
+ if (es->leaf.error_factor & M16C_EF_BITE1)
+ cf->data[2] |= CAN_ERR_PROT_BIT1;
+ if (es->leaf.error_factor & M16C_EF_TRE)
+ cf->data[2] |= CAN_ERR_PROT_TX;
+ }
+ break;
+ case KVASER_USBCAN:
+ if (es->usbcan.error_state & USBCAN_ERROR_STATE_BUSERROR) {
+ cf->can_id |= CAN_ERR_BUSERROR;
+ }
+ break;
+ }
- priv->can.can_stats.bus_off++;
- if (!priv->can.restart_ms)
- kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
+ cf->data[6] = es->txerr;
+ cf->data[7] = es->rxerr;
- netif_carrier_off(priv->netdev);
+ stats->rx_packets++;
+ stats->rx_bytes += cf->can_dlc;
+ netif_rx(skb);
+}
- new_state = CAN_STATE_BUS_OFF;
- } else if (status & M16C_STATE_BUS_PASSIVE) {
- if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
- cf->can_id |= CAN_ERR_CRTL;
-
- if (txerr || rxerr)
- cf->data[1] = (txerr > rxerr)
- ? CAN_ERR_CRTL_TX_PASSIVE
- : CAN_ERR_CRTL_RX_PASSIVE;
- else
- cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE |
- CAN_ERR_CRTL_RX_PASSIVE;
-
- priv->can.can_stats.error_passive++;
- }
+/* For USBCAN, report error to userspace iff the channels's errors counter
+ * has changed, or we're the only channel seeing a bus error state.
+ */
+static void kvaser_usbcan_conditionally_rx_error(const struct kvaser_usb *dev,
+ struct kvaser_usb_error_summary *es)
+{
+ struct kvaser_usb_net_priv *priv;
+ int channel;
+ bool report_error;
- new_state = CAN_STATE_ERROR_PASSIVE;
- } else if (status & M16C_STATE_BUS_ERROR) {
- if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
- ((txerr >= 96) || (rxerr >= 96))) {
- cf->can_id |= CAN_ERR_CRTL;
- cf->data[1] = (txerr > rxerr)
- ? CAN_ERR_CRTL_TX_WARNING
- : CAN_ERR_CRTL_RX_WARNING;
-
- priv->can.can_stats.error_warning++;
- new_state = CAN_STATE_ERROR_WARNING;
- } else if ((priv->can.state > CAN_STATE_ERROR_ACTIVE) &&
- ((txerr < 96) && (rxerr < 96))) {
- cf->can_id |= CAN_ERR_PROT;
- cf->data[2] = CAN_ERR_PROT_ACTIVE;
-
- new_state = CAN_STATE_ERROR_ACTIVE;
- }
+ channel = es->channel;
+ if (channel >= dev->nchannels) {
+ dev_err(dev->udev->dev.parent,
+ "Invalid channel number (%d)\n", channel);
+ return;
}
- if (!status) {
- cf->can_id |= CAN_ERR_PROT;
- cf->data[2] = CAN_ERR_PROT_ACTIVE;
+ priv = dev->nets[channel];
+ report_error = false;
- new_state = CAN_STATE_ERROR_ACTIVE;
+ if (es->txerr != priv->bec.txerr) {
+ es->usbcan.error_state |= USBCAN_ERROR_STATE_TX_ERROR;
+ report_error = true;
+ }
+ if (es->rxerr != priv->bec.rxerr) {
+ es->usbcan.error_state |= USBCAN_ERROR_STATE_RX_ERROR;
+ report_error = true;
+ }
+ if ((es->status & M16C_STATE_BUS_ERROR) &&
+ !(es->usbcan.other_ch_status & M16C_STATE_BUS_ERROR)) {
+ es->usbcan.error_state |= USBCAN_ERROR_STATE_BUSERROR;
+ report_error = true;
}
- if (priv->can.restart_ms &&
- (priv->can.state >= CAN_STATE_BUS_OFF) &&
- (new_state < CAN_STATE_BUS_OFF)) {
- cf->can_id |= CAN_ERR_RESTARTED;
- netif_carrier_on(priv->netdev);
+ if (report_error)
+ kvaser_usb_rx_error(dev, es);
+}
- priv->can.can_stats.restarts++;
- }
+static void kvaser_usbcan_rx_error(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_error_summary es = { };
- if (error_factor) {
- priv->can.can_stats.bus_error++;
- stats->rx_errors++;
+ switch (msg->id) {
+ /* Sometimes errors are sent as unsolicited chip state events */
+ case CMD_CHIP_STATE_EVENT:
+ es.channel = msg->u.usbcan.chip_state_event.channel;
+ es.status = msg->u.usbcan.chip_state_event.status;
+ es.txerr = msg->u.usbcan.chip_state_event.tx_errors_count;
+ es.rxerr = msg->u.usbcan.chip_state_event.rx_errors_count;
+ kvaser_usbcan_conditionally_rx_error(dev, &es);
+ break;
- cf->can_id |= CAN_ERR_BUSERROR | CAN_ERR_PROT;
-
- if (error_factor & M16C_EF_ACKE)
- cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
- if (error_factor & M16C_EF_CRCE)
- cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
- CAN_ERR_PROT_LOC_CRC_DEL);
- if (error_factor & M16C_EF_FORME)
- cf->data[2] |= CAN_ERR_PROT_FORM;
- if (error_factor & M16C_EF_STFE)
- cf->data[2] |= CAN_ERR_PROT_STUFF;
- if (error_factor & M16C_EF_BITE0)
- cf->data[2] |= CAN_ERR_PROT_BIT0;
- if (error_factor & M16C_EF_BITE1)
- cf->data[2] |= CAN_ERR_PROT_BIT1;
- if (error_factor & M16C_EF_TRE)
- cf->data[2] |= CAN_ERR_PROT_TX;
- }
+ case CMD_CAN_ERROR_EVENT:
+ es.channel = 0;
+ es.status = msg->u.usbcan.error_event.status_ch0;
+ es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch0;
+ es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch0;
+ es.usbcan.other_ch_status =
+ msg->u.usbcan.error_event.status_ch1;
+ kvaser_usbcan_conditionally_rx_error(dev, &es);
+
+ /* The USBCAN firmware supports up to 2 channels.
+ * Now that ch0 was checked, check if ch1 has any errors.
+ */
+ if (dev->nchannels == MAX_USBCAN_NET_DEVICES) {
+ es.channel = 1;
+ es.status = msg->u.usbcan.error_event.status_ch1;
+ es.txerr = msg->u.usbcan.error_event.tx_errors_count_ch1;
+ es.rxerr = msg->u.usbcan.error_event.rx_errors_count_ch1;
+ es.usbcan.other_ch_status =
+ msg->u.usbcan.error_event.status_ch0;
+ kvaser_usbcan_conditionally_rx_error(dev, &es);
+ }
+ break;
- cf->data[6] = txerr;
- cf->data[7] = rxerr;
+ default:
+ dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+ msg->id);
+ }
+}
- priv->bec.txerr = txerr;
- priv->bec.rxerr = rxerr;
+static void kvaser_leaf_rx_error(const struct kvaser_usb *dev,
+ const struct kvaser_msg *msg)
+{
+ struct kvaser_usb_error_summary es = { };
- priv->can.state = new_state;
+ switch (msg->id) {
+ case CMD_CAN_ERROR_EVENT:
+ es.channel = msg->u.leaf.error_event.channel;
+ es.status = msg->u.leaf.error_event.status;
+ es.txerr = msg->u.leaf.error_event.tx_errors_count;
+ es.rxerr = msg->u.leaf.error_event.rx_errors_count;
+ es.leaf.error_factor = msg->u.leaf.error_event.error_factor;
+ break;
+ case CMD_LEAF_LOG_MESSAGE:
+ es.channel = msg->u.leaf.log_message.channel;
+ es.status = msg->u.leaf.log_message.data[0];
+ es.txerr = msg->u.leaf.log_message.data[2];
+ es.rxerr = msg->u.leaf.log_message.data[3];
+ es.leaf.error_factor = msg->u.leaf.log_message.data[1];
+ break;
+ case CMD_CHIP_STATE_EVENT:
+ es.channel = msg->u.leaf.chip_state_event.channel;
+ es.status = msg->u.leaf.chip_state_event.status;
+ es.txerr = msg->u.leaf.chip_state_event.tx_errors_count;
+ es.rxerr = msg->u.leaf.chip_state_event.rx_errors_count;
+ es.leaf.error_factor = 0;
+ break;
+ default:
+ dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
+ msg->id);
+ return;
+ }
- stats->rx_packets++;
- stats->rx_bytes += cf->can_dlc;
- netif_rx(skb);
+ kvaser_usb_rx_error(dev, &es);
}
static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
@@ -776,16 +1090,19 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
struct sk_buff *skb;
struct net_device_stats *stats = &priv->netdev->stats;
- if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
+ if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
MSG_FLAG_NERR)) {
netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
- msg->u.rx_can.flag);
+ msg->u.rx_can_header.flag);
stats->rx_errors++;
return;
}
- if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
+ if (msg->u.rx_can_header.flag & MSG_FLAG_OVERRUN) {
+ stats->rx_over_errors++;
+ stats->rx_errors++;
+
skb = alloc_can_err_skb(priv->netdev, &cf);
if (!skb) {
stats->rx_dropped++;
@@ -795,9 +1112,6 @@ static void kvaser_usb_rx_can_err(const struct kvaser_usb_net_priv *priv,
cf->can_id |= CAN_ERR_CRTL;
cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
- stats->rx_over_errors++;
- stats->rx_errors++;
-
stats->rx_packets++;
stats->rx_bytes += cf->can_dlc;
netif_rx(skb);
@@ -811,7 +1125,8 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
struct can_frame *cf;
struct sk_buff *skb;
struct net_device_stats *stats;
- u8 channel = msg->u.rx_can.channel;
+ u8 channel = msg->u.rx_can_header.channel;
+ const u8 *rx_msg = NULL; /* GCC */
if (channel >= dev->nchannels) {
dev_err(dev->udev->dev.parent,
@@ -822,60 +1137,68 @@ static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
priv = dev->nets[channel];
stats = &priv->netdev->stats;
- if ((msg->u.rx_can.flag & MSG_FLAG_ERROR_FRAME) &&
- (msg->id == CMD_LOG_MESSAGE)) {
- kvaser_usb_rx_error(dev, msg);
+ if ((msg->u.rx_can_header.flag & MSG_FLAG_ERROR_FRAME) &&
+ (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE)) {
+ kvaser_leaf_rx_error(dev, msg);
return;
- } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
- MSG_FLAG_NERR |
- MSG_FLAG_OVERRUN)) {
+ } else if (msg->u.rx_can_header.flag & (MSG_FLAG_ERROR_FRAME |
+ MSG_FLAG_NERR |
+ MSG_FLAG_OVERRUN)) {
kvaser_usb_rx_can_err(priv, msg);
return;
- } else if (msg->u.rx_can.flag & ~MSG_FLAG_REMOTE_FRAME) {
+ } else if (msg->u.rx_can_header.flag & ~MSG_FLAG_REMOTE_FRAME) {
netdev_warn(priv->netdev,
"Unhandled frame (flags: 0x%02x)",
- msg->u.rx_can.flag);
+ msg->u.rx_can_header.flag);
return;
}
+ switch (dev->family) {
+ case KVASER_LEAF:
+ rx_msg = msg->u.leaf.rx_can.msg;
+ break;
+ case KVASER_USBCAN:
+ rx_msg = msg->u.usbcan.rx_can.msg;
+ break;
+ }
+
skb = alloc_can_skb(priv->netdev, &cf);
if (!skb) {
stats->tx_dropped++;
return;
}
- if (msg->id == CMD_LOG_MESSAGE) {
- cf->can_id = le32_to_cpu(msg->u.log_message.id);
+ if (dev->family == KVASER_LEAF && msg->id == CMD_LEAF_LOG_MESSAGE) {
+ cf->can_id = le32_to_cpu(msg->u.leaf.log_message.id);
if (cf->can_id & KVASER_EXTENDED_FRAME)
cf->can_id &= CAN_EFF_MASK | CAN_EFF_FLAG;
else
cf->can_id &= CAN_SFF_MASK;
- cf->can_dlc = get_can_dlc(msg->u.log_message.dlc);
+ cf->can_dlc = get_can_dlc(msg->u.leaf.log_message.dlc);
- if (msg->u.log_message.flags & MSG_FLAG_REMOTE_FRAME)
+ if (msg->u.leaf.log_message.flags & MSG_FLAG_REMOTE_FRAME)
cf->can_id |= CAN_RTR_FLAG;
else
- memcpy(cf->data, &msg->u.log_message.data,
+ memcpy(cf->data, &msg->u.leaf.log_message.data,
cf->can_dlc);
} else {
- cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
- (msg->u.rx_can.msg[1] & 0x3f);
+ cf->can_id = ((rx_msg[0] & 0x1f) << 6) | (rx_msg[1] & 0x3f);
if (msg->id == CMD_RX_EXT_MESSAGE) {
cf->can_id <<= 18;
- cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
- ((msg->u.rx_can.msg[3] & 0xff) << 6) |
- (msg->u.rx_can.msg[4] & 0x3f);
+ cf->can_id |= ((rx_msg[2] & 0x0f) << 14) |
+ ((rx_msg[3] & 0xff) << 6) |
+ (rx_msg[4] & 0x3f);
cf->can_id |= CAN_EFF_FLAG;
}
- cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
+ cf->can_dlc = get_can_dlc(rx_msg[5]);
- if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME)
+ if (msg->u.rx_can_header.flag & MSG_FLAG_REMOTE_FRAME)
cf->can_id |= CAN_RTR_FLAG;
else
- memcpy(cf->data, &msg->u.rx_can.msg[6],
+ memcpy(cf->data, &rx_msg[6],
cf->can_dlc);
}
@@ -938,21 +1261,35 @@ static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
case CMD_RX_STD_MESSAGE:
case CMD_RX_EXT_MESSAGE:
- case CMD_LOG_MESSAGE:
+ kvaser_usb_rx_can_msg(dev, msg);
+ break;
+
+ case CMD_LEAF_LOG_MESSAGE:
+ if (dev->family != KVASER_LEAF)
+ goto warn;
kvaser_usb_rx_can_msg(dev, msg);
break;
case CMD_CHIP_STATE_EVENT:
case CMD_CAN_ERROR_EVENT:
- kvaser_usb_rx_error(dev, msg);
+ if (dev->family == KVASER_LEAF)
+ kvaser_leaf_rx_error(dev, msg);
+ else
+ kvaser_usbcan_rx_error(dev, msg);
break;
case CMD_TX_ACKNOWLEDGE:
kvaser_usb_tx_acknowledge(dev, msg);
break;
+ /* Ignored messages */
+ case CMD_USBCAN_CLOCK_OVERFLOW_EVENT:
+ if (dev->family != KVASER_USBCAN)
+ goto warn;
+ break;
+
default:
- dev_warn(dev->udev->dev.parent,
+warn: dev_warn(dev->udev->dev.parent,
"Unhandled message (%d)\n", msg->id);
break;
}
@@ -1172,7 +1509,7 @@ static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
dev->rxbuf[i],
dev->rxbuf_dma[i]);
- for (i = 0; i < MAX_NET_DEVICES; i++) {
+ for (i = 0; i < dev->nchannels; i++) {
struct kvaser_usb_net_priv *priv = dev->nets[i];
if (priv)
@@ -1280,6 +1617,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
struct kvaser_msg *msg;
int i, err;
int ret = NETDEV_TX_OK;
+ u8 *msg_tx_can_flags = NULL; /* GCC */
if (can_dropped_invalid_skb(netdev, skb))
return NETDEV_TX_OK;
@@ -1301,9 +1639,19 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
msg = buf;
msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
- msg->u.tx_can.flags = 0;
msg->u.tx_can.channel = priv->channel;
+ switch (dev->family) {
+ case KVASER_LEAF:
+ msg_tx_can_flags = &msg->u.tx_can.leaf.flags;
+ break;
+ case KVASER_USBCAN:
+ msg_tx_can_flags = &msg->u.tx_can.usbcan.flags;
+ break;
+ }
+
+ *msg_tx_can_flags = 0;
+
if (cf->can_id & CAN_EFF_FLAG) {
msg->id = CMD_TX_EXT_MESSAGE;
msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
@@ -1321,7 +1669,7 @@ static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
if (cf->can_id & CAN_RTR_FLAG)
- msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
+ *msg_tx_can_flags |= MSG_FLAG_REMOTE_FRAME;
for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
@@ -1590,6 +1938,17 @@ static int kvaser_usb_probe(struct usb_interface *intf,
if (!dev)
return -ENOMEM;
+ if (kvaser_is_leaf(id)) {
+ dev->family = KVASER_LEAF;
+ } else if (kvaser_is_usbcan(id)) {
+ dev->family = KVASER_USBCAN;
+ } else {
+ dev_err(&intf->dev,
+ "Product ID (%d) does not belong to any known Kvaser USB family",
+ id->idProduct);
+ return -ENODEV;
+ }
+
err = kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
if (err) {
dev_err(&intf->dev, "Cannot get usb endpoint(s)");
diff --git a/drivers/net/can/usb/peak_usb/Makefile b/drivers/net/can/usb/peak_usb/Makefile
index 1aefbc88d643..1839e9ca62e7 100644
--- a/drivers/net/can/usb/peak_usb/Makefile
+++ b/drivers/net/can/usb/peak_usb/Makefile
@@ -1,2 +1,2 @@
obj-$(CONFIG_CAN_PEAK_USB) += peak_usb.o
-peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o
+peak_usb-y = pcan_usb_core.o pcan_usb.o pcan_usb_pro.o pcan_usb_fd.o
diff --git a/drivers/net/can/usb/peak_usb/pcan_ucan.h b/drivers/net/can/usb/peak_usb/pcan_ucan.h
new file mode 100644
index 000000000000..1ba7c25002e1
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_ucan.h
@@ -0,0 +1,222 @@
+/*
+ * CAN driver for PEAK System micro-CAN based adapters
+ *
+ * Copyright (C) 2003-2011 PEAK System-Technik GmbH
+ * Copyright (C) 2011-2013 Stephane Grosjean <s.grosjean@peak-system.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.
+ */
+#ifndef PUCAN_H
+#define PUCAN_H
+
+/* uCAN commands opcodes list (low-order 10 bits) */
+#define PUCAN_CMD_NOP 0x000
+#define PUCAN_CMD_RESET_MODE 0x001
+#define PUCAN_CMD_NORMAL_MODE 0x002
+#define PUCAN_CMD_LISTEN_ONLY_MODE 0x003
+#define PUCAN_CMD_TIMING_SLOW 0x004
+#define PUCAN_CMD_TIMING_FAST 0x005
+#define PUCAN_CMD_FILTER_STD 0x008
+#define PUCAN_CMD_TX_ABORT 0x009
+#define PUCAN_CMD_WR_ERR_CNT 0x00a
+#define PUCAN_CMD_RX_FRAME_ENABLE 0x00b
+#define PUCAN_CMD_RX_FRAME_DISABLE 0x00c
+#define PUCAN_CMD_END_OF_COLLECTION 0x3ff
+
+/* uCAN received messages list */
+#define PUCAN_MSG_CAN_RX 0x0001
+#define PUCAN_MSG_ERROR 0x0002
+#define PUCAN_MSG_STATUS 0x0003
+#define PUCAN_MSG_BUSLOAD 0x0004
+#define PUCAN_MSG_CAN_TX 0x1000
+
+/* uCAN command common header */
+struct __packed pucan_command {
+ __le16 opcode_channel;
+ u16 args[3];
+};
+
+/* uCAN TIMING_SLOW command fields */
+#define PUCAN_TSLOW_SJW_T(s, t) (((s) & 0xf) | ((!!(t)) << 7))
+#define PUCAN_TSLOW_TSEG2(t) ((t) & 0xf)
+#define PUCAN_TSLOW_TSEG1(t) ((t) & 0x3f)
+#define PUCAN_TSLOW_BRP(b) ((b) & 0x3ff)
+
+struct __packed pucan_timing_slow {
+ __le16 opcode_channel;
+
+ u8 ewl; /* Error Warning limit */
+ u8 sjw_t; /* Sync Jump Width + Triple sampling */
+ u8 tseg2; /* Timing SEGment 2 */
+ u8 tseg1; /* Timing SEGment 1 */
+
+ __le16 brp; /* BaudRate Prescaler */
+};
+
+/* uCAN TIMING_FAST command fields */
+#define PUCAN_TFAST_SJW(s) ((s) & 0x3)
+#define PUCAN_TFAST_TSEG2(t) ((t) & 0x7)
+#define PUCAN_TFAST_TSEG1(t) ((t) & 0xf)
+#define PUCAN_TFAST_BRP(b) ((b) & 0x3ff)
+
+struct __packed pucan_timing_fast {
+ __le16 opcode_channel;
+
+ u8 unused;
+ u8 sjw; /* Sync Jump Width */
+ u8 tseg2; /* Timing SEGment 2 */
+ u8 tseg1; /* Timing SEGment 1 */
+
+ __le16 brp; /* BaudRate Prescaler */
+};
+
+/* uCAN FILTER_STD command fields */
+#define PUCAN_FLTSTD_ROW_IDX_BITS 6
+
+struct __packed pucan_filter_std {
+ __le16 opcode_channel;
+
+ __le16 idx;
+ __le32 mask; /* CAN-ID bitmask in idx range */
+};
+
+/* uCAN WR_ERR_CNT command fields */
+#define PUCAN_WRERRCNT_TE 0x4000 /* Tx error cntr write Enable */
+#define PUCAN_WRERRCNT_RE 0x8000 /* Rx error cntr write Enable */
+
+struct __packed pucan_wr_err_cnt {
+ __le16 opcode_channel;
+
+ __le16 sel_mask;
+ u8 tx_counter; /* Tx error counter new value */
+ u8 rx_counter; /* Rx error counter new value */
+
+ u16 unused;
+};
+
+/* uCAN RX_FRAME_ENABLE command fields */
+#define PUCAN_FLTEXT_ERROR 0x0001
+#define PUCAN_FLTEXT_BUSLOAD 0x0002
+
+struct __packed pucan_filter_ext {
+ __le16 opcode_channel;
+
+ __le16 ext_mask;
+ u32 unused;
+};
+
+/* uCAN received messages global format */
+struct __packed pucan_msg {
+ __le16 size;
+ __le16 type;
+ __le32 ts_low;
+ __le32 ts_high;
+};
+
+/* uCAN flags for CAN/CANFD messages */
+#define PUCAN_MSG_SELF_RECEIVE 0x80
+#define PUCAN_MSG_ERROR_STATE_IND 0x40 /* error state indicator */
+#define PUCAN_MSG_BITRATE_SWITCH 0x20 /* bitrate switch */
+#define PUCAN_MSG_EXT_DATA_LEN 0x10 /* extended data length */
+#define PUCAN_MSG_SINGLE_SHOT 0x08
+#define PUCAN_MSG_LOOPED_BACK 0x04
+#define PUCAN_MSG_EXT_ID 0x02
+#define PUCAN_MSG_RTR 0x01
+
+struct __packed pucan_rx_msg {
+ __le16 size;
+ __le16 type;
+ __le32 ts_low;
+ __le32 ts_high;
+ __le32 tag_low;
+ __le32 tag_high;
+ u8 channel_dlc;
+ u8 client;
+ __le16 flags;
+ __le32 can_id;
+ u8 d[0];
+};
+
+/* uCAN error types */
+#define PUCAN_ERMSG_BIT_ERROR 0
+#define PUCAN_ERMSG_FORM_ERROR 1
+#define PUCAN_ERMSG_STUFF_ERROR 2
+#define PUCAN_ERMSG_OTHER_ERROR 3
+#define PUCAN_ERMSG_ERR_CNT_DEC 4
+
+struct __packed pucan_error_msg {
+ __le16 size;
+ __le16 type;
+ __le32 ts_low;
+ __le32 ts_high;
+ u8 channel_type_d;
+ u8 code_g;
+ u8 tx_err_cnt;
+ u8 rx_err_cnt;
+};
+
+#define PUCAN_BUS_PASSIVE 0x20
+#define PUCAN_BUS_WARNING 0x40
+#define PUCAN_BUS_BUSOFF 0x80
+
+struct __packed pucan_status_msg {
+ __le16 size;
+ __le16 type;
+ __le32 ts_low;
+ __le32 ts_high;
+ u8 channel_p_w_b;
+ u8 unused[3];
+};
+
+/* uCAN transmitted message format */
+#define PUCAN_MSG_CHANNEL_DLC(c, d) (((c) & 0xf) | ((d) << 4))
+
+struct __packed pucan_tx_msg {
+ __le16 size;
+ __le16 type;
+ __le32 tag_low;
+ __le32 tag_high;
+ u8 channel_dlc;
+ u8 client;
+ __le16 flags;
+ __le32 can_id;
+ u8 d[0];
+};
+
+/* build the cmd opcode_channel field with respect to the correct endianness */
+static inline __le16 pucan_cmd_opcode_channel(struct peak_usb_device *dev,
+ int opcode)
+{
+ return cpu_to_le16(((dev->ctrl_idx) << 12) | ((opcode) & 0x3ff));
+}
+
+/* return the channel number part from any received message channel_dlc field */
+static inline int pucan_msg_get_channel(struct pucan_rx_msg *rm)
+{
+ return rm->channel_dlc & 0xf;
+}
+
+/* return the dlc value from any received message channel_dlc field */
+static inline int pucan_msg_get_dlc(struct pucan_rx_msg *rm)
+{
+ return rm->channel_dlc >> 4;
+}
+
+static inline int pucan_ermsg_get_channel(struct pucan_error_msg *em)
+{
+ return em->channel_type_d & 0x0f;
+}
+
+static inline int pucan_stmsg_get_channel(struct pucan_status_msg *sm)
+{
+ return sm->channel_p_w_b & 0x0f;
+}
+
+#endif
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb.c b/drivers/net/can/usb/peak_usb/pcan_usb.c
index 4e1659d07979..72427f21edff 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb.c
@@ -488,6 +488,7 @@ static int pcan_usb_decode_error(struct pcan_usb_msg_context *mc, u8 n,
switch (new_state) {
case CAN_STATE_BUS_OFF:
cf->can_id |= CAN_ERR_BUSOFF;
+ mc->pdev->dev.can.can_stats.bus_off++;
can_bus_off(mc->netdev);
break;
@@ -854,10 +855,11 @@ static int pcan_usb_probe(struct usb_interface *intf)
/*
* describe the PCAN-USB adapter
*/
-struct peak_usb_adapter pcan_usb = {
+const struct peak_usb_adapter pcan_usb = {
.name = "PCAN-USB",
.device_id = PCAN_USB_PRODUCT_ID,
.ctrl_count = 1,
+ .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY,
.clock = {
.freq = PCAN_USB_CRYSTAL_HZ / 2 ,
},
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.c b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
index c62f48a1161d..7921cff93a63 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.c
@@ -37,16 +37,19 @@ MODULE_LICENSE("GPL v2");
static struct usb_device_id peak_usb_table[] = {
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USB_PRODUCT_ID)},
{USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPRO_PRODUCT_ID)},
+ {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBFD_PRODUCT_ID)},
+ {USB_DEVICE(PCAN_USB_VENDOR_ID, PCAN_USBPROFD_PRODUCT_ID)},
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, peak_usb_table);
/* List of supported PCAN-USB adapters (NULL terminated list) */
-static struct peak_usb_adapter *peak_usb_adapters_list[] = {
+static const struct peak_usb_adapter *const peak_usb_adapters_list[] = {
&pcan_usb,
&pcan_usb_pro,
- NULL,
+ &pcan_usb_fd,
+ &pcan_usb_pro_fd,
};
/*
@@ -65,7 +68,7 @@ void pcan_dump_mem(char *prompt, void *p, int l)
* initialize a time_ref object with usb adapter own settings
*/
void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
- struct peak_usb_adapter *adapter)
+ const struct peak_usb_adapter *adapter)
{
if (time_ref) {
memset(time_ref, 0, sizeof(struct peak_time_ref));
@@ -165,6 +168,21 @@ void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts,
}
/*
+ * post received skb after having set any hw timestamp
+ */
+int peak_usb_netif_rx(struct sk_buff *skb,
+ struct peak_time_ref *time_ref, u32 ts_low, u32 ts_high)
+{
+ struct skb_shared_hwtstamps *hwts = skb_hwtstamps(skb);
+ struct timeval tv;
+
+ peak_usb_get_ts_tv(time_ref, ts_low, &tv);
+ hwts->hwtstamp = timeval_to_ktime(tv);
+
+ return netif_rx(skb);
+}
+
+/*
* callback for bulk Rx urb
*/
static void peak_usb_read_bulk_callback(struct urb *urb)
@@ -253,7 +271,7 @@ static void peak_usb_write_bulk_callback(struct urb *urb)
case 0:
/* transmission complete */
netdev->stats.tx_packets++;
- netdev->stats.tx_bytes += context->dlc;
+ netdev->stats.tx_bytes += context->data_len;
/* prevent tx timeout */
netdev->trans_start = jiffies;
@@ -289,7 +307,7 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
struct peak_usb_device *dev = netdev_priv(netdev);
struct peak_tx_urb_context *context = NULL;
struct net_device_stats *stats = &netdev->stats;
- struct can_frame *cf = (struct can_frame *)skb->data;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
struct urb *urb;
u8 *obuf;
int i, err;
@@ -322,7 +340,9 @@ static netdev_tx_t peak_usb_ndo_start_xmit(struct sk_buff *skb,
}
context->echo_index = i;
- context->dlc = cf->can_dlc;
+
+ /* Note: this works with CANFD frames too */
+ context->data_len = cfd->len;
usb_anchor_urb(urb, &dev->tx_submitted);
@@ -679,19 +699,43 @@ static int peak_usb_set_mode(struct net_device *netdev, enum can_mode mode)
}
/*
- * candev callback used to set device bitrate.
+ * candev callback used to set device nominal/arbitration bitrate.
*/
static int peak_usb_set_bittiming(struct net_device *netdev)
{
struct peak_usb_device *dev = netdev_priv(netdev);
- struct can_bittiming *bt = &dev->can.bittiming;
+ const struct peak_usb_adapter *pa = dev->adapter;
- if (dev->adapter->dev_set_bittiming) {
- int err = dev->adapter->dev_set_bittiming(dev, bt);
+ if (pa->dev_set_bittiming) {
+ struct can_bittiming *bt = &dev->can.bittiming;
+ int err = pa->dev_set_bittiming(dev, bt);
if (err)
netdev_info(netdev, "couldn't set bitrate (err %d)\n",
- err);
+ err);
+ return err;
+ }
+
+ return 0;
+}
+
+/*
+ * candev callback used to set device data bitrate.
+ */
+static int peak_usb_set_data_bittiming(struct net_device *netdev)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+ const struct peak_usb_adapter *pa = dev->adapter;
+
+ if (pa->dev_set_data_bittiming) {
+ struct can_bittiming *bt = &dev->can.data_bittiming;
+ int err = pa->dev_set_data_bittiming(dev, bt);
+
+ if (err)
+ netdev_info(netdev,
+ "couldn't set data bitrate (err %d)\n",
+ err);
+
return err;
}
@@ -709,7 +753,7 @@ static const struct net_device_ops peak_usb_netdev_ops = {
* create one device which is attached to CAN controller #ctrl_idx of the
* usb adapter.
*/
-static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
+static int peak_usb_create_dev(const struct peak_usb_adapter *peak_usb_adapter,
struct usb_interface *intf, int ctrl_idx)
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
@@ -750,9 +794,11 @@ static int peak_usb_create_dev(struct peak_usb_adapter *peak_usb_adapter,
dev->can.clock = peak_usb_adapter->clock;
dev->can.bittiming_const = &peak_usb_adapter->bittiming_const;
dev->can.do_set_bittiming = peak_usb_set_bittiming;
+ dev->can.data_bittiming_const = &peak_usb_adapter->data_bittiming_const;
+ dev->can.do_set_data_bittiming = peak_usb_set_data_bittiming;
dev->can.do_set_mode = peak_usb_set_mode;
- dev->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES |
- CAN_CTRLMODE_LISTENONLY;
+ dev->can.do_get_berr_counter = peak_usb_adapter->do_get_berr_counter;
+ dev->can.ctrlmode_supported = peak_usb_adapter->ctrlmode_supported;
netdev->netdev_ops = &peak_usb_netdev_ops;
@@ -857,17 +903,18 @@ static int peak_usb_probe(struct usb_interface *intf,
{
struct usb_device *usb_dev = interface_to_usbdev(intf);
const u16 usb_id_product = le16_to_cpu(usb_dev->descriptor.idProduct);
- struct peak_usb_adapter *peak_usb_adapter, **pp;
+ const struct peak_usb_adapter *peak_usb_adapter = NULL;
int i, err = -ENOMEM;
usb_dev = interface_to_usbdev(intf);
/* get corresponding PCAN-USB adapter */
- for (pp = peak_usb_adapters_list; *pp; pp++)
- if ((*pp)->device_id == usb_id_product)
+ for (i = 0; i < ARRAY_SIZE(peak_usb_adapters_list); i++)
+ if (peak_usb_adapters_list[i]->device_id == usb_id_product) {
+ peak_usb_adapter = peak_usb_adapters_list[i];
break;
+ }
- peak_usb_adapter = *pp;
if (!peak_usb_adapter) {
/* should never come except device_id bad usage in this file */
pr_err("%s: didn't find device id. 0x%x in devices list\n",
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_core.h b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
index 073b47ff8eee..9e624f05ad4d 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_core.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_core.h
@@ -25,6 +25,8 @@
/* supported device ids. */
#define PCAN_USB_PRODUCT_ID 0x000c
#define PCAN_USBPRO_PRODUCT_ID 0x000d
+#define PCAN_USBPROFD_PRODUCT_ID 0x0011
+#define PCAN_USBFD_PRODUCT_ID 0x0012
#define PCAN_USB_DRIVER_NAME "peak_usb"
@@ -44,8 +46,10 @@ struct peak_usb_device;
struct peak_usb_adapter {
char *name;
u32 device_id;
+ u32 ctrlmode_supported;
struct can_clock clock;
const struct can_bittiming_const bittiming_const;
+ const struct can_bittiming_const data_bittiming_const;
unsigned int ctrl_count;
int (*intf_probe)(struct usb_interface *intf);
@@ -57,6 +61,8 @@ struct peak_usb_adapter {
int (*dev_close)(struct peak_usb_device *dev);
int (*dev_set_bittiming)(struct peak_usb_device *dev,
struct can_bittiming *bt);
+ int (*dev_set_data_bittiming)(struct peak_usb_device *dev,
+ struct can_bittiming *bt);
int (*dev_set_bus)(struct peak_usb_device *dev, u8 onoff);
int (*dev_get_device_id)(struct peak_usb_device *dev, u32 *device_id);
int (*dev_decode_buf)(struct peak_usb_device *dev, struct urb *urb);
@@ -66,6 +72,8 @@ struct peak_usb_adapter {
int (*dev_stop)(struct peak_usb_device *dev);
int (*dev_restart_async)(struct peak_usb_device *dev, struct urb *urb,
u8 *buf);
+ int (*do_get_berr_counter)(const struct net_device *netdev,
+ struct can_berr_counter *bec);
u8 ep_msg_in;
u8 ep_msg_out[PCAN_USB_MAX_CHANNEL];
u8 ts_used_bits;
@@ -78,21 +86,23 @@ struct peak_usb_adapter {
int sizeof_dev_private;
};
-extern struct peak_usb_adapter pcan_usb;
-extern struct peak_usb_adapter pcan_usb_pro;
+extern const struct peak_usb_adapter pcan_usb;
+extern const struct peak_usb_adapter pcan_usb_pro;
+extern const struct peak_usb_adapter pcan_usb_fd;
+extern const struct peak_usb_adapter pcan_usb_pro_fd;
struct peak_time_ref {
struct timeval tv_host_0, tv_host;
u32 ts_dev_1, ts_dev_2;
u64 ts_total;
u32 tick_count;
- struct peak_usb_adapter *adapter;
+ const struct peak_usb_adapter *adapter;
};
struct peak_tx_urb_context {
struct peak_usb_device *dev;
u32 echo_index;
- u8 dlc;
+ u8 data_len;
struct urb *urb;
};
@@ -102,7 +112,7 @@ struct peak_tx_urb_context {
/* PEAK-System USB device */
struct peak_usb_device {
struct can_priv can;
- struct peak_usb_adapter *adapter;
+ const struct peak_usb_adapter *adapter;
unsigned int ctrl_idx;
u32 state;
@@ -134,12 +144,14 @@ void pcan_dump_mem(char *prompt, void *p, int l);
/* common timestamp management */
void peak_usb_init_time_ref(struct peak_time_ref *time_ref,
- struct peak_usb_adapter *adapter);
+ const struct peak_usb_adapter *adapter);
void peak_usb_update_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_set_ts_now(struct peak_time_ref *time_ref, u32 ts_now);
void peak_usb_get_ts_tv(struct peak_time_ref *time_ref, u32 ts,
struct timeval *tv);
-
+int peak_usb_netif_rx(struct sk_buff *skb,
+ struct peak_time_ref *time_ref, u32 ts_low, u32 ts_high);
void peak_usb_async_complete(struct urb *urb);
void peak_usb_restart_complete(struct peak_usb_device *dev);
+
#endif
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_fd.c b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
new file mode 100644
index 000000000000..962c3f027383
--- /dev/null
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_fd.c
@@ -0,0 +1,1095 @@
+/*
+ * CAN driver for PEAK System PCAN-USB FD / PCAN-USB Pro FD adapter
+ *
+ * Copyright (C) 2013-2014 Stephane Grosjean <s.grosjean@peak-system.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/netdevice.h>
+#include <linux/usb.h>
+#include <linux/module.h>
+
+#include <linux/can.h>
+#include <linux/can/dev.h>
+#include <linux/can/error.h>
+
+#include "pcan_usb_core.h"
+#include "pcan_usb_pro.h"
+#include "pcan_ucan.h"
+
+MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB FD adapter");
+MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro FD adapter");
+
+#define PCAN_USBPROFD_CHANNEL_COUNT 2
+#define PCAN_USBFD_CHANNEL_COUNT 1
+
+/* PCAN-USB Pro FD adapter internal clock (Hz) */
+#define PCAN_UFD_CRYSTAL_HZ 80000000
+
+#define PCAN_UFD_CMD_BUFFER_SIZE 512
+#define PCAN_UFD_LOSPD_PKT_SIZE 64
+
+/* PCAN-USB Pro FD command timeout (ms.) */
+#define PCAN_UFD_CMD_TIMEOUT_MS 1000
+
+/* PCAN-USB Pro FD rx/tx buffers size */
+#define PCAN_UFD_RX_BUFFER_SIZE 2048
+#define PCAN_UFD_TX_BUFFER_SIZE 512
+
+/* read some versions info from the hw devcie */
+struct __packed pcan_ufd_fw_info {
+ __le16 size_of; /* sizeof this */
+ __le16 type; /* type of this structure */
+ u8 hw_type; /* Type of hardware (HW_TYPE_xxx) */
+ u8 bl_version[3]; /* Bootloader version */
+ u8 hw_version; /* Hardware version (PCB) */
+ u8 fw_version[3]; /* Firmware version */
+ __le32 dev_id[2]; /* "device id" per CAN */
+ __le32 ser_no; /* S/N */
+ __le32 flags; /* special functions */
+};
+
+/* handle device specific info used by the netdevices */
+struct pcan_usb_fd_if {
+ struct peak_usb_device *dev[PCAN_USB_MAX_CHANNEL];
+ struct pcan_ufd_fw_info fw_info;
+ struct peak_time_ref time_ref;
+ int cm_ignore_count;
+ int dev_opened_count;
+};
+
+/* device information */
+struct pcan_usb_fd_device {
+ struct peak_usb_device dev;
+ struct can_berr_counter bec;
+ struct pcan_usb_fd_if *usb_if;
+ u8 *cmd_buffer_addr;
+};
+
+/* Extended USB commands (non uCAN commands) */
+
+/* Clock Modes command */
+#define PCAN_UFD_CMD_CLK_SET 0x80
+
+#define PCAN_UFD_CLK_80MHZ 0x0
+#define PCAN_UFD_CLK_60MHZ 0x1
+#define PCAN_UFD_CLK_40MHZ 0x2
+#define PCAN_UFD_CLK_30MHZ 0x3
+#define PCAN_UFD_CLK_24MHZ 0x4
+#define PCAN_UFD_CLK_20MHZ 0x5
+#define PCAN_UFD_CLK_DEF PCAN_UFD_CLK_80MHZ
+
+struct __packed pcan_ufd_clock {
+ __le16 opcode_channel;
+
+ u8 mode;
+ u8 unused[5];
+};
+
+/* LED control command */
+#define PCAN_UFD_CMD_LED_SET 0x86
+
+#define PCAN_UFD_LED_DEV 0x00
+#define PCAN_UFD_LED_FAST 0x01
+#define PCAN_UFD_LED_SLOW 0x02
+#define PCAN_UFD_LED_ON 0x03
+#define PCAN_UFD_LED_OFF 0x04
+#define PCAN_UFD_LED_DEF PCAN_UFD_LED_DEV
+
+struct __packed pcan_ufd_led {
+ __le16 opcode_channel;
+
+ u8 mode;
+ u8 unused[5];
+};
+
+/* Extended usage of uCAN commands CMD_RX_FRAME_xxxABLE for PCAN-USB Pro FD */
+#define PCAN_UFD_FLTEXT_CALIBRATION 0x8000
+
+struct __packed pcan_ufd_filter_ext {
+ __le16 opcode_channel;
+
+ __le16 ext_mask;
+ u16 unused;
+ __le16 usb_mask;
+};
+
+/* Extended usage of uCAN messages for PCAN-USB Pro FD */
+#define PCAN_UFD_MSG_CALIBRATION 0x100
+
+struct __packed pcan_ufd_ts_msg {
+ __le16 size;
+ __le16 type;
+ __le32 ts_low;
+ __le32 ts_high;
+ __le16 usb_frame_index;
+ u16 unused;
+};
+
+#define PCAN_UFD_MSG_OVERRUN 0x101
+
+#define PCAN_UFD_OVMSG_CHANNEL(o) ((o)->channel & 0xf)
+
+struct __packed pcan_ufd_ovr_msg {
+ __le16 size;
+ __le16 type;
+ __le32 ts_low;
+ __le32 ts_high;
+ u8 channel;
+ u8 unused[3];
+};
+
+static inline int pufd_omsg_get_channel(struct pcan_ufd_ovr_msg *om)
+{
+ return om->channel & 0xf;
+}
+
+/* Clock mode frequency values */
+static const u32 pcan_usb_fd_clk_freq[6] = {
+ [PCAN_UFD_CLK_80MHZ] = 80000000,
+ [PCAN_UFD_CLK_60MHZ] = 60000000,
+ [PCAN_UFD_CLK_40MHZ] = 40000000,
+ [PCAN_UFD_CLK_30MHZ] = 30000000,
+ [PCAN_UFD_CLK_24MHZ] = 24000000,
+ [PCAN_UFD_CLK_20MHZ] = 20000000
+};
+
+/* return a device USB interface */
+static inline
+struct pcan_usb_fd_if *pcan_usb_fd_dev_if(struct peak_usb_device *dev)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+ return pdev->usb_if;
+}
+
+/* return a device USB commands buffer */
+static inline void *pcan_usb_fd_cmd_buffer(struct peak_usb_device *dev)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+ return pdev->cmd_buffer_addr;
+}
+
+/* send PCAN-USB Pro FD commands synchronously */
+static int pcan_usb_fd_send_cmd(struct peak_usb_device *dev, void *cmd_tail)
+{
+ void *cmd_head = pcan_usb_fd_cmd_buffer(dev);
+ int err;
+ u8 *packet_ptr;
+ int i, n = 1, packet_len;
+ ptrdiff_t cmd_len;
+
+ /* usb device unregistered? */
+ if (!(dev->state & PCAN_USB_STATE_CONNECTED))
+ return 0;
+
+ /* if a packet is not filled completely by commands, the command list
+ * is terminated with an "end of collection" record.
+ */
+ cmd_len = cmd_tail - cmd_head;
+ if (cmd_len <= (PCAN_UFD_CMD_BUFFER_SIZE - sizeof(u64))) {
+ memset(cmd_tail, 0xff, sizeof(u64));
+ cmd_len += sizeof(u64);
+ }
+
+ packet_ptr = cmd_head;
+
+ /* firmware is not able to re-assemble 512 bytes buffer in full-speed */
+ if ((dev->udev->speed != USB_SPEED_HIGH) &&
+ (cmd_len > PCAN_UFD_LOSPD_PKT_SIZE)) {
+ packet_len = PCAN_UFD_LOSPD_PKT_SIZE;
+ n += cmd_len / packet_len;
+ } else {
+ packet_len = cmd_len;
+ }
+
+ for (i = 0; i < n; i++) {
+ err = usb_bulk_msg(dev->udev,
+ usb_sndbulkpipe(dev->udev,
+ PCAN_USBPRO_EP_CMDOUT),
+ packet_ptr, packet_len,
+ NULL, PCAN_UFD_CMD_TIMEOUT_MS);
+ if (err) {
+ netdev_err(dev->netdev,
+ "sending command failure: %d\n", err);
+ break;
+ }
+
+ packet_ptr += packet_len;
+ }
+
+ return err;
+}
+
+/* build the commands list in the given buffer, to enter operational mode */
+static int pcan_usb_fd_build_restart_cmd(struct peak_usb_device *dev, u8 *buf)
+{
+ struct pucan_wr_err_cnt *prc;
+ struct pucan_command *cmd;
+ u8 *pc = buf;
+
+ /* 1st, reset error counters: */
+ prc = (struct pucan_wr_err_cnt *)pc;
+ prc->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PUCAN_CMD_WR_ERR_CNT);
+
+ /* select both counters */
+ prc->sel_mask = cpu_to_le16(PUCAN_WRERRCNT_TE|PUCAN_WRERRCNT_RE);
+
+ /* and reset their values */
+ prc->tx_counter = 0;
+ prc->rx_counter = 0;
+
+ /* moves the pointer forward */
+ pc += sizeof(struct pucan_wr_err_cnt);
+
+ /* next, go back to operational mode */
+ cmd = (struct pucan_command *)pc;
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ (dev->can.ctrlmode & CAN_CTRLMODE_LISTENONLY) ?
+ PUCAN_CMD_LISTEN_ONLY_MODE :
+ PUCAN_CMD_NORMAL_MODE);
+ pc += sizeof(struct pucan_command);
+
+ return pc - buf;
+}
+
+/* set CAN bus on/off */
+static int pcan_usb_fd_set_bus(struct peak_usb_device *dev, u8 onoff)
+{
+ u8 *pc = pcan_usb_fd_cmd_buffer(dev);
+ int l;
+
+ if (onoff) {
+ /* build the cmds list to enter operational mode */
+ l = pcan_usb_fd_build_restart_cmd(dev, pc);
+ } else {
+ struct pucan_command *cmd = (struct pucan_command *)pc;
+
+ /* build cmd to go back to reset mode */
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PUCAN_CMD_RESET_MODE);
+ l = sizeof(struct pucan_command);
+ }
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, pc + l);
+}
+
+/* set filtering masks:
+ *
+ * idx in range [0..63] selects a row #idx, all rows otherwise
+ * mask in range [0..0xffffffff] defines up to 32 CANIDs in the row(s)
+ *
+ * Each bit of this 64 x 32 bits array defines a CANID value:
+ *
+ * bit[i,j] = 1 implies that CANID=(i x 32)+j will be received, while
+ * bit[i,j] = 0 implies that CANID=(i x 32)+j will be discarded.
+ */
+static int pcan_usb_fd_set_filter_std(struct peak_usb_device *dev, int idx,
+ u32 mask)
+{
+ struct pucan_filter_std *cmd = pcan_usb_fd_cmd_buffer(dev);
+ int i, n;
+
+ /* select all rows when idx is out of range [0..63] */
+ if ((idx < 0) || (idx >= (1 << PUCAN_FLTSTD_ROW_IDX_BITS))) {
+ n = 1 << PUCAN_FLTSTD_ROW_IDX_BITS;
+ idx = 0;
+
+ /* select the row (and only the row) otherwise */
+ } else {
+ n = idx + 1;
+ }
+
+ for (i = idx; i < n; i++, cmd++) {
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PUCAN_CMD_FILTER_STD);
+ cmd->idx = cpu_to_le16(i);
+ cmd->mask = cpu_to_le32(mask);
+ }
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, cmd);
+}
+
+/* set/unset notifications filter:
+ *
+ * onoff sets(1)/unset(0) notifications
+ * mask each bit defines a kind of notification to set/unset
+ */
+static int pcan_usb_fd_set_filter_ext(struct peak_usb_device *dev,
+ bool onoff, u16 ext_mask, u16 usb_mask)
+{
+ struct pcan_ufd_filter_ext *cmd = pcan_usb_fd_cmd_buffer(dev);
+
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ (onoff) ? PUCAN_CMD_RX_FRAME_ENABLE :
+ PUCAN_CMD_RX_FRAME_DISABLE);
+
+ cmd->ext_mask = cpu_to_le16(ext_mask);
+ cmd->usb_mask = cpu_to_le16(usb_mask);
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, ++cmd);
+}
+
+/* setup LED control */
+static int pcan_usb_fd_set_can_led(struct peak_usb_device *dev, u8 led_mode)
+{
+ struct pcan_ufd_led *cmd = pcan_usb_fd_cmd_buffer(dev);
+
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PCAN_UFD_CMD_LED_SET);
+ cmd->mode = led_mode;
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, ++cmd);
+}
+
+/* set CAN clock domain */
+static int pcan_usb_fd_set_clock_domain(struct peak_usb_device *dev,
+ u8 clk_mode)
+{
+ struct pcan_ufd_clock *cmd = pcan_usb_fd_cmd_buffer(dev);
+
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PCAN_UFD_CMD_CLK_SET);
+ cmd->mode = clk_mode;
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, ++cmd);
+}
+
+/* set bittiming for CAN and CAN-FD header */
+static int pcan_usb_fd_set_bittiming_slow(struct peak_usb_device *dev,
+ struct can_bittiming *bt)
+{
+ struct pucan_timing_slow *cmd = pcan_usb_fd_cmd_buffer(dev);
+
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PUCAN_CMD_TIMING_SLOW);
+ cmd->sjw_t = PUCAN_TSLOW_SJW_T(bt->sjw - 1,
+ dev->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES);
+
+ cmd->tseg2 = PUCAN_TSLOW_TSEG2(bt->phase_seg2 - 1);
+ cmd->tseg1 = PUCAN_TSLOW_TSEG1(bt->prop_seg + bt->phase_seg1 - 1);
+ cmd->brp = cpu_to_le16(PUCAN_TSLOW_BRP(bt->brp - 1));
+
+ cmd->ewl = 96; /* default */
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, ++cmd);
+}
+
+/* set CAN-FD bittiming for data */
+static int pcan_usb_fd_set_bittiming_fast(struct peak_usb_device *dev,
+ struct can_bittiming *bt)
+{
+ struct pucan_timing_fast *cmd = pcan_usb_fd_cmd_buffer(dev);
+
+ cmd->opcode_channel = pucan_cmd_opcode_channel(dev,
+ PUCAN_CMD_TIMING_FAST);
+ cmd->sjw = PUCAN_TFAST_SJW(bt->sjw - 1);
+ cmd->tseg2 = PUCAN_TFAST_TSEG2(bt->phase_seg2 - 1);
+ cmd->tseg1 = PUCAN_TFAST_TSEG1(bt->prop_seg + bt->phase_seg1 - 1);
+ cmd->brp = cpu_to_le16(PUCAN_TFAST_BRP(bt->brp - 1));
+
+ /* send the command */
+ return pcan_usb_fd_send_cmd(dev, ++cmd);
+}
+
+/* handle restart but in asynchronously way
+ * (uses PCAN-USB Pro code to complete asynchronous request)
+ */
+static int pcan_usb_fd_restart_async(struct peak_usb_device *dev,
+ struct urb *urb, u8 *buf)
+{
+ u8 *pc = buf;
+
+ /* build the entire cmds list in the provided buffer, to go back into
+ * operational mode.
+ */
+ pc += pcan_usb_fd_build_restart_cmd(dev, pc);
+
+ /* add EOC */
+ memset(pc, 0xff, sizeof(struct pucan_command));
+ pc += sizeof(struct pucan_command);
+
+ /* complete the URB */
+ usb_fill_bulk_urb(urb, dev->udev,
+ usb_sndbulkpipe(dev->udev, PCAN_USBPRO_EP_CMDOUT),
+ buf, pc - buf,
+ pcan_usb_pro_restart_complete, dev);
+
+ /* and submit it. */
+ return usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static int pcan_usb_fd_drv_loaded(struct peak_usb_device *dev, bool loaded)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+
+ pdev->cmd_buffer_addr[0] = 0;
+ pdev->cmd_buffer_addr[1] = !!loaded;
+
+ return pcan_usb_pro_send_req(dev,
+ PCAN_USBPRO_REQ_FCT,
+ PCAN_USBPRO_FCT_DRVLD,
+ pdev->cmd_buffer_addr,
+ PCAN_USBPRO_FCT_DRVLD_REQ_LEN);
+}
+
+static int pcan_usb_fd_decode_canmsg(struct pcan_usb_fd_if *usb_if,
+ struct pucan_msg *rx_msg)
+{
+ struct pucan_rx_msg *rm = (struct pucan_rx_msg *)rx_msg;
+ struct peak_usb_device *dev = usb_if->dev[pucan_msg_get_channel(rm)];
+ struct net_device *netdev = dev->netdev;
+ struct canfd_frame *cfd;
+ struct sk_buff *skb;
+ const u16 rx_msg_flags = le16_to_cpu(rm->flags);
+
+ if (rx_msg_flags & PUCAN_MSG_EXT_DATA_LEN) {
+ /* CANFD frame case */
+ skb = alloc_canfd_skb(netdev, &cfd);
+ if (!skb)
+ return -ENOMEM;
+
+ if (rx_msg_flags & PUCAN_MSG_BITRATE_SWITCH)
+ cfd->flags |= CANFD_BRS;
+
+ if (rx_msg_flags & PUCAN_MSG_ERROR_STATE_IND)
+ cfd->flags |= CANFD_ESI;
+
+ cfd->len = can_dlc2len(get_canfd_dlc(pucan_msg_get_dlc(rm)));
+ } else {
+ /* CAN 2.0 frame case */
+ skb = alloc_can_skb(netdev, (struct can_frame **)&cfd);
+ if (!skb)
+ return -ENOMEM;
+
+ cfd->len = get_can_dlc(pucan_msg_get_dlc(rm));
+ }
+
+ cfd->can_id = le32_to_cpu(rm->can_id);
+
+ if (rx_msg_flags & PUCAN_MSG_EXT_ID)
+ cfd->can_id |= CAN_EFF_FLAG;
+
+ if (rx_msg_flags & PUCAN_MSG_RTR)
+ cfd->can_id |= CAN_RTR_FLAG;
+ else
+ memcpy(cfd->data, rm->d, cfd->len);
+
+ peak_usb_netif_rx(skb, &usb_if->time_ref,
+ le32_to_cpu(rm->ts_low), le32_to_cpu(rm->ts_high));
+
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += cfd->len;
+
+ return 0;
+}
+
+/* handle uCAN status message */
+static int pcan_usb_fd_decode_status(struct pcan_usb_fd_if *usb_if,
+ struct pucan_msg *rx_msg)
+{
+ struct pucan_status_msg *sm = (struct pucan_status_msg *)rx_msg;
+ struct peak_usb_device *dev = usb_if->dev[pucan_stmsg_get_channel(sm)];
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+ enum can_state new_state = CAN_STATE_ERROR_ACTIVE;
+ enum can_state rx_state, tx_state;
+ struct net_device *netdev = dev->netdev;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /* nothing should be sent while in BUS_OFF state */
+ if (dev->can.state == CAN_STATE_BUS_OFF)
+ return 0;
+
+ if (sm->channel_p_w_b & PUCAN_BUS_BUSOFF) {
+ new_state = CAN_STATE_BUS_OFF;
+ } else if (sm->channel_p_w_b & PUCAN_BUS_PASSIVE) {
+ new_state = CAN_STATE_ERROR_PASSIVE;
+ } else if (sm->channel_p_w_b & PUCAN_BUS_WARNING) {
+ new_state = CAN_STATE_ERROR_WARNING;
+ } else {
+ /* no error bit (so, no error skb, back to active state) */
+ dev->can.state = CAN_STATE_ERROR_ACTIVE;
+ pdev->bec.txerr = 0;
+ pdev->bec.rxerr = 0;
+ return 0;
+ }
+
+ /* state hasn't changed */
+ if (new_state == dev->can.state)
+ return 0;
+
+ /* handle bus state change */
+ tx_state = (pdev->bec.txerr >= pdev->bec.rxerr) ? new_state : 0;
+ rx_state = (pdev->bec.txerr <= pdev->bec.rxerr) ? new_state : 0;
+
+ /* allocate an skb to store the error frame */
+ skb = alloc_can_err_skb(netdev, &cf);
+ if (skb)
+ can_change_state(netdev, cf, tx_state, rx_state);
+
+ /* things must be done even in case of OOM */
+ if (new_state == CAN_STATE_BUS_OFF)
+ can_bus_off(netdev);
+
+ if (!skb)
+ return -ENOMEM;
+
+ peak_usb_netif_rx(skb, &usb_if->time_ref,
+ le32_to_cpu(sm->ts_low), le32_to_cpu(sm->ts_high));
+
+ netdev->stats.rx_packets++;
+ netdev->stats.rx_bytes += cf->can_dlc;
+
+ return 0;
+}
+
+/* handle uCAN error message */
+static int pcan_usb_fd_decode_error(struct pcan_usb_fd_if *usb_if,
+ struct pucan_msg *rx_msg)
+{
+ struct pucan_error_msg *er = (struct pucan_error_msg *)rx_msg;
+ struct peak_usb_device *dev = usb_if->dev[pucan_ermsg_get_channel(er)];
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+
+ /* keep a trace of tx and rx error counters for later use */
+ pdev->bec.txerr = er->tx_err_cnt;
+ pdev->bec.rxerr = er->rx_err_cnt;
+
+ return 0;
+}
+
+/* handle uCAN overrun message */
+static int pcan_usb_fd_decode_overrun(struct pcan_usb_fd_if *usb_if,
+ struct pucan_msg *rx_msg)
+{
+ struct pcan_ufd_ovr_msg *ov = (struct pcan_ufd_ovr_msg *)rx_msg;
+ struct peak_usb_device *dev = usb_if->dev[pufd_omsg_get_channel(ov)];
+ struct net_device *netdev = dev->netdev;
+ struct can_frame *cf;
+ struct sk_buff *skb;
+
+ /* allocate an skb to store the error frame */
+ skb = alloc_can_err_skb(netdev, &cf);
+ if (!skb)
+ return -ENOMEM;
+
+ cf->can_id |= CAN_ERR_CRTL;
+ cf->data[1] |= CAN_ERR_CRTL_RX_OVERFLOW;
+
+ peak_usb_netif_rx(skb, &usb_if->time_ref,
+ le32_to_cpu(ov->ts_low), le32_to_cpu(ov->ts_high));
+
+ netdev->stats.rx_over_errors++;
+ netdev->stats.rx_errors++;
+
+ return 0;
+}
+
+/* handle USB calibration message */
+static void pcan_usb_fd_decode_ts(struct pcan_usb_fd_if *usb_if,
+ struct pucan_msg *rx_msg)
+{
+ struct pcan_ufd_ts_msg *ts = (struct pcan_ufd_ts_msg *)rx_msg;
+
+ /* should wait until clock is stabilized */
+ if (usb_if->cm_ignore_count > 0)
+ usb_if->cm_ignore_count--;
+ else
+ peak_usb_set_ts_now(&usb_if->time_ref, le32_to_cpu(ts->ts_low));
+}
+
+/* callback for bulk IN urb */
+static int pcan_usb_fd_decode_buf(struct peak_usb_device *dev, struct urb *urb)
+{
+ struct pcan_usb_fd_if *usb_if = pcan_usb_fd_dev_if(dev);
+ struct net_device *netdev = dev->netdev;
+ struct pucan_msg *rx_msg;
+ u8 *msg_ptr, *msg_end;
+ int err = 0;
+
+ /* loop reading all the records from the incoming message */
+ msg_ptr = urb->transfer_buffer;
+ msg_end = urb->transfer_buffer + urb->actual_length;
+ for (; msg_ptr < msg_end;) {
+ u16 rx_msg_type, rx_msg_size;
+
+ rx_msg = (struct pucan_msg *)msg_ptr;
+ if (!rx_msg->size) {
+ /* null packet found: end of list */
+ break;
+ }
+
+ rx_msg_size = le16_to_cpu(rx_msg->size);
+ rx_msg_type = le16_to_cpu(rx_msg->type);
+
+ /* check if the record goes out of current packet */
+ if (msg_ptr + rx_msg_size > msg_end) {
+ netdev_err(netdev,
+ "got frag rec: should inc usb rx buf sze\n");
+ err = -EBADMSG;
+ break;
+ }
+
+ switch (rx_msg_type) {
+ case PUCAN_MSG_CAN_RX:
+ err = pcan_usb_fd_decode_canmsg(usb_if, rx_msg);
+ if (err < 0)
+ goto fail;
+ break;
+
+ case PCAN_UFD_MSG_CALIBRATION:
+ pcan_usb_fd_decode_ts(usb_if, rx_msg);
+ break;
+
+ case PUCAN_MSG_ERROR:
+ err = pcan_usb_fd_decode_error(usb_if, rx_msg);
+ if (err < 0)
+ goto fail;
+ break;
+
+ case PUCAN_MSG_STATUS:
+ err = pcan_usb_fd_decode_status(usb_if, rx_msg);
+ if (err < 0)
+ goto fail;
+ break;
+
+ case PCAN_UFD_MSG_OVERRUN:
+ err = pcan_usb_fd_decode_overrun(usb_if, rx_msg);
+ if (err < 0)
+ goto fail;
+ break;
+
+ default:
+ netdev_err(netdev,
+ "unhandled msg type 0x%02x (%d): ignored\n",
+ rx_msg_type, rx_msg_type);
+ break;
+ }
+
+ msg_ptr += rx_msg_size;
+ }
+
+fail:
+ if (err)
+ pcan_dump_mem("received msg",
+ urb->transfer_buffer, urb->actual_length);
+ return err;
+}
+
+/* CAN/CANFD frames encoding callback */
+static int pcan_usb_fd_encode_msg(struct peak_usb_device *dev,
+ struct sk_buff *skb, u8 *obuf, size_t *size)
+{
+ struct pucan_tx_msg *tx_msg = (struct pucan_tx_msg *)obuf;
+ struct canfd_frame *cfd = (struct canfd_frame *)skb->data;
+ u16 tx_msg_size, tx_msg_flags;
+ u8 can_dlc;
+
+ tx_msg_size = ALIGN(sizeof(struct pucan_tx_msg) + cfd->len, 4);
+ tx_msg->size = cpu_to_le16(tx_msg_size);
+ tx_msg->type = cpu_to_le16(PUCAN_MSG_CAN_TX);
+
+ tx_msg_flags = 0;
+ if (cfd->can_id & CAN_EFF_FLAG) {
+ tx_msg_flags |= PUCAN_MSG_EXT_ID;
+ tx_msg->can_id = cpu_to_le32(cfd->can_id & CAN_EFF_MASK);
+ } else {
+ tx_msg->can_id = cpu_to_le32(cfd->can_id & CAN_SFF_MASK);
+ }
+
+ if (can_is_canfd_skb(skb)) {
+ /* considering a CANFD frame */
+ can_dlc = can_len2dlc(cfd->len);
+
+ tx_msg_flags |= PUCAN_MSG_EXT_DATA_LEN;
+
+ if (cfd->flags & CANFD_BRS)
+ tx_msg_flags |= PUCAN_MSG_BITRATE_SWITCH;
+
+ if (cfd->flags & CANFD_ESI)
+ tx_msg_flags |= PUCAN_MSG_ERROR_STATE_IND;
+ } else {
+ /* CAND 2.0 frames */
+ can_dlc = cfd->len;
+
+ if (cfd->can_id & CAN_RTR_FLAG)
+ tx_msg_flags |= PUCAN_MSG_RTR;
+ }
+
+ tx_msg->flags = cpu_to_le16(tx_msg_flags);
+ tx_msg->channel_dlc = PUCAN_MSG_CHANNEL_DLC(dev->ctrl_idx, can_dlc);
+ memcpy(tx_msg->d, cfd->data, cfd->len);
+
+ /* add null size message to tag the end (messages are 32-bits aligned)
+ */
+ tx_msg = (struct pucan_tx_msg *)(obuf + tx_msg_size);
+
+ tx_msg->size = 0;
+
+ /* set the whole size of the USB packet to send */
+ *size = tx_msg_size + sizeof(u32);
+
+ return 0;
+}
+
+/* start the interface (last chance before set bus on) */
+static int pcan_usb_fd_start(struct peak_usb_device *dev)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+ int err;
+
+ /* set filter mode: all acceptance */
+ err = pcan_usb_fd_set_filter_std(dev, -1, 0xffffffff);
+ if (err)
+ return err;
+
+ /* opening first device: */
+ if (pdev->usb_if->dev_opened_count == 0) {
+ /* reset time_ref */
+ peak_usb_init_time_ref(&pdev->usb_if->time_ref,
+ &pcan_usb_pro_fd);
+
+ /* enable USB calibration messages */
+ err = pcan_usb_fd_set_filter_ext(dev, 1,
+ PUCAN_FLTEXT_ERROR,
+ PCAN_UFD_FLTEXT_CALIBRATION);
+ }
+
+ pdev->usb_if->dev_opened_count++;
+
+ /* reset cached error counters */
+ pdev->bec.txerr = 0;
+ pdev->bec.rxerr = 0;
+
+ return err;
+}
+
+/* socket callback used to copy berr counters values receieved through USB */
+static int pcan_usb_fd_get_berr_counter(const struct net_device *netdev,
+ struct can_berr_counter *bec)
+{
+ struct peak_usb_device *dev = netdev_priv(netdev);
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+
+ *bec = pdev->bec;
+
+ /* must return 0 */
+ return 0;
+}
+
+/* stop interface (last chance before set bus off) */
+static int pcan_usb_fd_stop(struct peak_usb_device *dev)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+
+ /* turn off special msgs for that interface if no other dev opened */
+ if (pdev->usb_if->dev_opened_count == 1)
+ pcan_usb_fd_set_filter_ext(dev, 0,
+ PUCAN_FLTEXT_ERROR,
+ PCAN_UFD_FLTEXT_CALIBRATION);
+ pdev->usb_if->dev_opened_count--;
+
+ return 0;
+}
+
+/* called when probing, to initialize a device object */
+static int pcan_usb_fd_init(struct peak_usb_device *dev)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+ int i, err = -ENOMEM;
+
+ /* do this for 1st channel only */
+ if (!dev->prev_siblings) {
+ /* allocate netdevices common structure attached to first one */
+ pdev->usb_if = kzalloc(sizeof(*pdev->usb_if), GFP_KERNEL);
+ if (!pdev->usb_if)
+ goto err_out;
+
+ /* allocate command buffer once for all for the interface */
+ pdev->cmd_buffer_addr = kmalloc(PCAN_UFD_CMD_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (!pdev->cmd_buffer_addr)
+ goto err_out_1;
+
+ /* number of ts msgs to ignore before taking one into account */
+ pdev->usb_if->cm_ignore_count = 5;
+
+ err = pcan_usb_pro_send_req(dev, PCAN_USBPRO_REQ_INFO,
+ PCAN_USBPRO_INFO_FW,
+ &pdev->usb_if->fw_info,
+ sizeof(pdev->usb_if->fw_info));
+ if (err) {
+ dev_err(dev->netdev->dev.parent,
+ "unable to read %s firmware info (err %d)\n",
+ dev->adapter->name, err);
+ goto err_out_2;
+ }
+
+ /* explicit use of dev_xxx() instead of netdev_xxx() here:
+ * information displayed are related to the device itself, not
+ * to the canx (channel) device.
+ */
+ dev_info(dev->netdev->dev.parent,
+ "PEAK-System %s v%u fw v%u.%u.%u (%u channels)\n",
+ dev->adapter->name, pdev->usb_if->fw_info.hw_version,
+ pdev->usb_if->fw_info.fw_version[0],
+ pdev->usb_if->fw_info.fw_version[1],
+ pdev->usb_if->fw_info.fw_version[2],
+ dev->adapter->ctrl_count);
+
+ /* the currently supported hw is non-ISO */
+ dev->can.ctrlmode = CAN_CTRLMODE_FD_NON_ISO;
+
+ /* tell the hardware the can driver is running */
+ err = pcan_usb_fd_drv_loaded(dev, 1);
+ if (err) {
+ dev_err(dev->netdev->dev.parent,
+ "unable to tell %s driver is loaded (err %d)\n",
+ dev->adapter->name, err);
+ goto err_out_2;
+ }
+ } else {
+ /* otherwise, simply copy previous sibling's values */
+ struct pcan_usb_fd_device *ppdev =
+ container_of(dev->prev_siblings,
+ struct pcan_usb_fd_device, dev);
+
+ pdev->usb_if = ppdev->usb_if;
+ pdev->cmd_buffer_addr = ppdev->cmd_buffer_addr;
+ }
+
+ pdev->usb_if->dev[dev->ctrl_idx] = dev;
+ dev->device_number =
+ le32_to_cpu(pdev->usb_if->fw_info.dev_id[dev->ctrl_idx]);
+
+ /* set clock domain */
+ for (i = 0; i < ARRAY_SIZE(pcan_usb_fd_clk_freq); i++)
+ if (dev->adapter->clock.freq == pcan_usb_fd_clk_freq[i])
+ break;
+
+ if (i >= ARRAY_SIZE(pcan_usb_fd_clk_freq)) {
+ dev_warn(dev->netdev->dev.parent,
+ "incompatible clock frequencies\n");
+ err = -EINVAL;
+ goto err_out_2;
+ }
+
+ pcan_usb_fd_set_clock_domain(dev, i);
+
+ /* set LED in default state (end of init phase) */
+ pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_DEF);
+
+ return 0;
+
+err_out_2:
+ kfree(pdev->cmd_buffer_addr);
+err_out_1:
+ kfree(pdev->usb_if);
+err_out:
+ return err;
+}
+
+/* called when driver module is being unloaded */
+static void pcan_usb_fd_exit(struct peak_usb_device *dev)
+{
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+
+ /* when rmmod called before unplug and if down, should reset things
+ * before leaving
+ */
+ if (dev->can.state != CAN_STATE_STOPPED) {
+ /* set bus off on the corresponding channel */
+ pcan_usb_fd_set_bus(dev, 0);
+ }
+
+ /* switch off corresponding CAN LEDs */
+ pcan_usb_fd_set_can_led(dev, PCAN_UFD_LED_OFF);
+
+ /* if channel #0 (only) */
+ if (dev->ctrl_idx == 0) {
+ /* turn off calibration message if any device were opened */
+ if (pdev->usb_if->dev_opened_count > 0)
+ pcan_usb_fd_set_filter_ext(dev, 0,
+ PUCAN_FLTEXT_ERROR,
+ PCAN_UFD_FLTEXT_CALIBRATION);
+
+ /* tell USB adapter that the driver is being unloaded */
+ pcan_usb_fd_drv_loaded(dev, 0);
+ }
+}
+
+/* called when the USB adapter is unplugged */
+static void pcan_usb_fd_free(struct peak_usb_device *dev)
+{
+ /* last device: can free shared objects now */
+ if (!dev->prev_siblings && !dev->next_siblings) {
+ struct pcan_usb_fd_device *pdev =
+ container_of(dev, struct pcan_usb_fd_device, dev);
+
+ /* free commands buffer */
+ kfree(pdev->cmd_buffer_addr);
+
+ /* free usb interface object */
+ kfree(pdev->usb_if);
+ }
+}
+
+/* describes the PCAN-USB FD adapter */
+const struct peak_usb_adapter pcan_usb_fd = {
+ .name = "PCAN-USB FD",
+ .device_id = PCAN_USBFD_PRODUCT_ID,
+ .ctrl_count = PCAN_USBFD_CHANNEL_COUNT,
+ .ctrlmode_supported = CAN_CTRLMODE_FD |
+ CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY,
+ .clock = {
+ .freq = PCAN_UFD_CRYSTAL_HZ,
+ },
+ .bittiming_const = {
+ .name = "pcan_usb_fd",
+ .tseg1_min = 1,
+ .tseg1_max = 64,
+ .tseg2_min = 1,
+ .tseg2_max = 16,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+ },
+ .data_bittiming_const = {
+ .name = "pcan_usb_fd",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+ },
+
+ /* size of device private data */
+ .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
+
+ /* timestamps usage */
+ .ts_used_bits = 32,
+ .ts_period = 1000000, /* calibration period in ts. */
+ .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
+ .us_per_ts_shift = 0,
+
+ /* give here messages in/out endpoints */
+ .ep_msg_in = PCAN_USBPRO_EP_MSGIN,
+ .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0},
+
+ /* size of rx/tx usb buffers */
+ .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE,
+ .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE,
+
+ /* device callbacks */
+ .intf_probe = pcan_usb_pro_probe, /* same as PCAN-USB Pro */
+ .dev_init = pcan_usb_fd_init,
+
+ .dev_exit = pcan_usb_fd_exit,
+ .dev_free = pcan_usb_fd_free,
+ .dev_set_bus = pcan_usb_fd_set_bus,
+ .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
+ .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
+ .dev_decode_buf = pcan_usb_fd_decode_buf,
+ .dev_start = pcan_usb_fd_start,
+ .dev_stop = pcan_usb_fd_stop,
+ .dev_restart_async = pcan_usb_fd_restart_async,
+ .dev_encode_msg = pcan_usb_fd_encode_msg,
+
+ .do_get_berr_counter = pcan_usb_fd_get_berr_counter,
+};
+
+/* describes the PCAN-USB Pro FD adapter */
+const struct peak_usb_adapter pcan_usb_pro_fd = {
+ .name = "PCAN-USB Pro FD",
+ .device_id = PCAN_USBPROFD_PRODUCT_ID,
+ .ctrl_count = PCAN_USBPROFD_CHANNEL_COUNT,
+ .ctrlmode_supported = CAN_CTRLMODE_FD |
+ CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY,
+ .clock = {
+ .freq = PCAN_UFD_CRYSTAL_HZ,
+ },
+ .bittiming_const = {
+ .name = "pcan_usb_pro_fd",
+ .tseg1_min = 1,
+ .tseg1_max = 64,
+ .tseg2_min = 1,
+ .tseg2_max = 16,
+ .sjw_max = 16,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+ },
+ .data_bittiming_const = {
+ .name = "pcan_usb_pro_fd",
+ .tseg1_min = 1,
+ .tseg1_max = 16,
+ .tseg2_min = 1,
+ .tseg2_max = 8,
+ .sjw_max = 4,
+ .brp_min = 1,
+ .brp_max = 1024,
+ .brp_inc = 1,
+ },
+
+ /* size of device private data */
+ .sizeof_dev_private = sizeof(struct pcan_usb_fd_device),
+
+ /* timestamps usage */
+ .ts_used_bits = 32,
+ .ts_period = 1000000, /* calibration period in ts. */
+ .us_per_ts_scale = 1, /* us = (ts * scale) >> shift */
+ .us_per_ts_shift = 0,
+
+ /* give here messages in/out endpoints */
+ .ep_msg_in = PCAN_USBPRO_EP_MSGIN,
+ .ep_msg_out = {PCAN_USBPRO_EP_MSGOUT_0, PCAN_USBPRO_EP_MSGOUT_1},
+
+ /* size of rx/tx usb buffers */
+ .rx_buffer_size = PCAN_UFD_RX_BUFFER_SIZE,
+ .tx_buffer_size = PCAN_UFD_TX_BUFFER_SIZE,
+
+ /* device callbacks */
+ .intf_probe = pcan_usb_pro_probe, /* same as PCAN-USB Pro */
+ .dev_init = pcan_usb_fd_init,
+
+ .dev_exit = pcan_usb_fd_exit,
+ .dev_free = pcan_usb_fd_free,
+ .dev_set_bus = pcan_usb_fd_set_bus,
+ .dev_set_bittiming = pcan_usb_fd_set_bittiming_slow,
+ .dev_set_data_bittiming = pcan_usb_fd_set_bittiming_fast,
+ .dev_decode_buf = pcan_usb_fd_decode_buf,
+ .dev_start = pcan_usb_fd_start,
+ .dev_stop = pcan_usb_fd_stop,
+ .dev_restart_async = pcan_usb_fd_restart_async,
+ .dev_encode_msg = pcan_usb_fd_encode_msg,
+
+ .do_get_berr_counter = pcan_usb_fd_get_berr_counter,
+};
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
index 4cfa3b8605b1..dec51717635e 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.c
@@ -27,14 +27,6 @@
MODULE_SUPPORTED_DEVICE("PEAK-System PCAN-USB Pro adapter");
-/* PCAN-USB Pro Endpoints */
-#define PCAN_USBPRO_EP_CMDOUT 1
-#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN)
-#define PCAN_USBPRO_EP_MSGOUT_0 2
-#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN)
-#define PCAN_USBPRO_EP_MSGOUT_1 3
-#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN)
-
#define PCAN_USBPRO_CHANNEL_COUNT 2
/* PCAN-USB Pro adapter internal clock (MHz) */
@@ -322,8 +314,8 @@ static int pcan_usb_pro_wait_rsp(struct peak_usb_device *dev,
return (i >= PCAN_USBPRO_RSP_SUBMIT_MAX) ? -ERANGE : err;
}
-static int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id,
- int req_value, void *req_addr, int req_size)
+int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id,
+ int req_value, void *req_addr, int req_size)
{
int err;
u8 req_type;
@@ -475,7 +467,7 @@ static int pcan_usb_pro_set_bittiming(struct peak_usb_device *dev,
return pcan_usb_pro_set_bitrate(dev, ccbt);
}
-static void pcan_usb_pro_restart_complete(struct urb *urb)
+void pcan_usb_pro_restart_complete(struct urb *urb)
{
/* can delete usb resources */
peak_usb_async_complete(urb);
@@ -634,6 +626,7 @@ static int pcan_usb_pro_handle_error(struct pcan_usb_pro_interface *usb_if,
switch (new_state) {
case CAN_STATE_BUS_OFF:
can_frame->can_id |= CAN_ERR_BUSOFF;
+ dev->can.can_stats.bus_off++;
can_bus_off(netdev);
break;
@@ -977,7 +970,7 @@ static void pcan_usb_pro_free(struct peak_usb_device *dev)
/*
* probe function for new PCAN-USB Pro usb interface
*/
-static int pcan_usb_pro_probe(struct usb_interface *intf)
+int pcan_usb_pro_probe(struct usb_interface *intf)
{
struct usb_host_interface *if_desc;
int i;
@@ -1011,10 +1004,11 @@ static int pcan_usb_pro_probe(struct usb_interface *intf)
/*
* describe the PCAN-USB Pro adapter
*/
-struct peak_usb_adapter pcan_usb_pro = {
+const struct peak_usb_adapter pcan_usb_pro = {
.name = "PCAN-USB Pro",
.device_id = PCAN_USBPRO_PRODUCT_ID,
.ctrl_count = PCAN_USBPRO_CHANNEL_COUNT,
+ .ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES | CAN_CTRLMODE_LISTENONLY,
.clock = {
.freq = PCAN_USBPRO_CRYSTAL_HZ,
},
diff --git a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
index 837cee267132..a62f7ab8980f 100644
--- a/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
+++ b/drivers/net/can/usb/peak_usb/pcan_usb_pro.h
@@ -27,6 +27,14 @@
#define PCAN_USBPRO_INFO_BL 0
#define PCAN_USBPRO_INFO_FW 1
+/* PCAN-USB Pro (FD) Endpoints */
+#define PCAN_USBPRO_EP_CMDOUT 1
+#define PCAN_USBPRO_EP_CMDIN (PCAN_USBPRO_EP_CMDOUT | USB_DIR_IN)
+#define PCAN_USBPRO_EP_MSGOUT_0 2
+#define PCAN_USBPRO_EP_MSGIN (PCAN_USBPRO_EP_MSGOUT_0 | USB_DIR_IN)
+#define PCAN_USBPRO_EP_MSGOUT_1 3
+#define PCAN_USBPRO_EP_UNUSED (PCAN_USBPRO_EP_MSGOUT_1 | USB_DIR_IN)
+
/* Vendor Request value for XXX_FCT */
#define PCAN_USBPRO_FCT_DRVLD 5 /* tell device driver is loaded */
#define PCAN_USBPRO_FCT_DRVLD_REQ_LEN 16
@@ -176,4 +184,9 @@ union pcan_usb_pro_rec {
struct pcan_usb_pro_txmsg tx_msg;
};
+int pcan_usb_pro_probe(struct usb_interface *intf);
+int pcan_usb_pro_send_req(struct peak_usb_device *dev, int req_id,
+ int req_value, void *req_addr, int req_size);
+void pcan_usb_pro_restart_complete(struct urb *urb);
+
#endif
diff --git a/drivers/net/can/usb/usb_8dev.c b/drivers/net/can/usb/usb_8dev.c
index ef674ecb82f8..dd52c7a4c80d 100644
--- a/drivers/net/can/usb/usb_8dev.c
+++ b/drivers/net/can/usb/usb_8dev.c
@@ -377,6 +377,7 @@ static void usb_8dev_rx_err_msg(struct usb_8dev_priv *priv,
case USB_8DEV_STATUSMSG_BUSOFF:
priv->can.state = CAN_STATE_BUS_OFF;
cf->can_id |= CAN_ERR_BUSOFF;
+ priv->can.can_stats.bus_off++;
can_bus_off(priv->netdev);
break;
case USB_8DEV_STATUSMSG_OVERRUN:
diff --git a/drivers/net/dsa/bcm_sf2.c b/drivers/net/dsa/bcm_sf2.c
index feb29c4526f7..4daffb284931 100644
--- a/drivers/net/dsa/bcm_sf2.c
+++ b/drivers/net/dsa/bcm_sf2.c
@@ -233,6 +233,35 @@ static void bcm_sf2_eee_enable_set(struct dsa_switch *ds, int port, bool enable)
core_writel(priv, reg, CORE_EEE_EN_CTRL);
}
+static void bcm_sf2_gphy_enable_set(struct dsa_switch *ds, bool enable)
+{
+ struct bcm_sf2_priv *priv = ds_to_priv(ds);
+ u32 reg;
+
+ reg = reg_readl(priv, REG_SPHY_CNTRL);
+ if (enable) {
+ reg |= PHY_RESET;
+ reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS | CK25_DIS);
+ reg_writel(priv, reg, REG_SPHY_CNTRL);
+ udelay(21);
+ reg = reg_readl(priv, REG_SPHY_CNTRL);
+ reg &= ~PHY_RESET;
+ } else {
+ reg |= EXT_PWR_DOWN | IDDQ_BIAS | PHY_RESET;
+ reg_writel(priv, reg, REG_SPHY_CNTRL);
+ mdelay(1);
+ reg |= CK25_DIS;
+ }
+ reg_writel(priv, reg, REG_SPHY_CNTRL);
+
+ /* Use PHY-driven LED signaling */
+ if (!enable) {
+ reg = reg_readl(priv, REG_LED_CNTRL(0));
+ reg |= SPDLNK_SRC_SEL;
+ reg_writel(priv, reg, REG_LED_CNTRL(0));
+ }
+}
+
static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
struct phy_device *phy)
{
@@ -248,6 +277,24 @@ static int bcm_sf2_port_setup(struct dsa_switch *ds, int port,
/* Clear the Rx and Tx disable bits and set to no spanning tree */
core_writel(priv, 0, CORE_G_PCTL_PORT(port));
+ /* Re-enable the GPHY and re-apply workarounds */
+ if (port == 0 && priv->hw_params.num_gphy == 1) {
+ bcm_sf2_gphy_enable_set(ds, true);
+ if (phy) {
+ /* if phy_stop() has been called before, phy
+ * will be in halted state, and phy_start()
+ * will call resume.
+ *
+ * the resume path does not configure back
+ * autoneg settings, and since we hard reset
+ * the phy manually here, we need to reset the
+ * state machine also.
+ */
+ phy->state = PHY_READY;
+ phy_init_hw(phy);
+ }
+ }
+
/* Enable port 7 interrupts to get notified */
if (port == 7)
intrl2_1_mask_clear(priv, P_IRQ_MASK(P7_IRQ_OFF));
@@ -281,6 +328,9 @@ static void bcm_sf2_port_disable(struct dsa_switch *ds, int port,
intrl2_1_writel(priv, P_IRQ_MASK(P7_IRQ_OFF), INTRL2_CPU_CLEAR);
}
+ if (port == 0 && priv->hw_params.num_gphy == 1)
+ bcm_sf2_gphy_enable_set(ds, false);
+
if (dsa_is_cpu_port(ds, port))
off = CORE_IMP_CTL;
else
@@ -400,6 +450,16 @@ static int bcm_sf2_sw_rst(struct bcm_sf2_priv *priv)
return 0;
}
+static void bcm_sf2_intr_disable(struct bcm_sf2_priv *priv)
+{
+ intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+ intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+ intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+ intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
+ intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
+ intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+}
+
static int bcm_sf2_sw_setup(struct dsa_switch *ds)
{
const char *reg_names[BCM_SF2_REGS_NUM] = BCM_SF2_REGS_NAME;
@@ -440,12 +500,7 @@ static int bcm_sf2_sw_setup(struct dsa_switch *ds)
}
/* Disable all interrupts and request them */
- intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
- intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
- intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
- intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
- intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
- intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+ bcm_sf2_intr_disable(priv);
ret = request_irq(priv->irq0, bcm_sf2_switch_0_isr, 0,
"switch_0", priv);
@@ -747,12 +802,7 @@ static int bcm_sf2_sw_suspend(struct dsa_switch *ds)
struct bcm_sf2_priv *priv = ds_to_priv(ds);
unsigned int port;
- intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
- intrl2_0_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
- intrl2_0_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
- intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_MASK_SET);
- intrl2_1_writel(priv, 0xffffffff, INTRL2_CPU_CLEAR);
- intrl2_1_writel(priv, 0, INTRL2_CPU_MASK_CLEAR);
+ bcm_sf2_intr_disable(priv);
/* Disable all ports physically present including the IMP
* port, the other ones have already been disabled during
@@ -771,7 +821,6 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
{
struct bcm_sf2_priv *priv = ds_to_priv(ds);
unsigned int port;
- u32 reg;
int ret;
ret = bcm_sf2_sw_rst(priv);
@@ -780,17 +829,8 @@ static int bcm_sf2_sw_resume(struct dsa_switch *ds)
return ret;
}
- /* Reinitialize the single GPHY */
- if (priv->hw_params.num_gphy == 1) {
- reg = reg_readl(priv, REG_SPHY_CNTRL);
- reg |= PHY_RESET;
- reg &= ~(EXT_PWR_DOWN | IDDQ_BIAS);
- reg_writel(priv, reg, REG_SPHY_CNTRL);
- udelay(21);
- reg = reg_readl(priv, REG_SPHY_CNTRL);
- reg &= ~PHY_RESET;
- reg_writel(priv, reg, REG_SPHY_CNTRL);
- }
+ if (priv->hw_params.num_gphy == 1)
+ bcm_sf2_gphy_enable_set(ds, true);
for (port = 0; port < DSA_MAX_PORTS; port++) {
if ((1 << port) & ds->phys_port_mask)
diff --git a/drivers/net/dsa/bcm_sf2_regs.h b/drivers/net/dsa/bcm_sf2_regs.h
index 1bb49cb699ab..cabdfa5e217a 100644
--- a/drivers/net/dsa/bcm_sf2_regs.h
+++ b/drivers/net/dsa/bcm_sf2_regs.h
@@ -61,6 +61,10 @@
#define LPI_COUNT_SHIFT 9
#define LPI_COUNT_MASK 0x3F
+#define REG_LED_CNTRL_BASE 0x90
+#define REG_LED_CNTRL(x) (REG_LED_CNTRL_BASE + (x) * 4)
+#define SPDLNK_SRC_SEL (1 << 24)
+
/* Register set relative to 'INTRL2_0' and 'INTRL2_1' */
#define INTRL2_CPU_STATUS 0x00
#define INTRL2_CPU_SET 0x04
diff --git a/drivers/net/dsa/mv88e6131.c b/drivers/net/dsa/mv88e6131.c
index 1230f52aa70e..2540ef0142af 100644
--- a/drivers/net/dsa/mv88e6131.c
+++ b/drivers/net/dsa/mv88e6131.c
@@ -139,7 +139,8 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
int nexthop;
nexthop = 0x1f;
- if (i != ds->index && i < ds->dst->pd->nr_chips)
+ if (ds->pd->rtable &&
+ i != ds->index && i < ds->dst->pd->nr_chips)
nexthop = ds->pd->rtable[i] & 0x1f;
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
diff --git a/drivers/net/dsa/mv88e6352.c b/drivers/net/dsa/mv88e6352.c
index 258d9ef5ef25..e13adc7b3dda 100644
--- a/drivers/net/dsa/mv88e6352.c
+++ b/drivers/net/dsa/mv88e6352.c
@@ -22,17 +22,14 @@
#include <net/dsa.h>
#include "mv88e6xxx.h"
-static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask)
+static int mv88e6352_wait(struct dsa_switch *ds, int reg, int offset, u16 mask)
{
unsigned long timeout = jiffies + HZ / 10;
while (time_before(jiffies, timeout)) {
int ret;
- ret = REG_READ(REG_GLOBAL2, reg);
- if (ret < 0)
- return ret;
-
+ ret = REG_READ(reg, offset);
if (!(ret & mask))
return 0;
@@ -43,17 +40,17 @@ static int mv88e6352_wait(struct dsa_switch *ds, int reg, u16 mask)
static inline int mv88e6352_phy_wait(struct dsa_switch *ds)
{
- return mv88e6352_wait(ds, 0x18, 0x8000);
+ return mv88e6352_wait(ds, REG_GLOBAL2, 0x18, 0x8000);
}
static inline int mv88e6352_eeprom_load_wait(struct dsa_switch *ds)
{
- return mv88e6352_wait(ds, 0x14, 0x0800);
+ return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x0800);
}
static inline int mv88e6352_eeprom_busy_wait(struct dsa_switch *ds)
{
- return mv88e6352_wait(ds, 0x14, 0x8000);
+ return mv88e6352_wait(ds, REG_GLOBAL2, 0x14, 0x8000);
}
static int __mv88e6352_phy_read(struct dsa_switch *ds, int addr, int regnum)
diff --git a/drivers/net/dsa/mv88e6xxx.c b/drivers/net/dsa/mv88e6xxx.c
index cd6807c6b4ed..3e7e31a6abb7 100644
--- a/drivers/net/dsa/mv88e6xxx.c
+++ b/drivers/net/dsa/mv88e6xxx.c
@@ -85,6 +85,12 @@ int mv88e6xxx_reg_read(struct dsa_switch *ds, int addr, int reg)
ret = __mv88e6xxx_reg_read(bus, ds->pd->sw_addr, addr, reg);
mutex_unlock(&ps->smi_mutex);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(ds->master_dev, "<- addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
+ addr, reg, ret);
+
return ret;
}
@@ -128,6 +134,9 @@ int mv88e6xxx_reg_write(struct dsa_switch *ds, int addr, int reg, u16 val)
if (bus == NULL)
return -EINVAL;
+ dev_dbg(ds->master_dev, "-> addr: 0x%.2x reg: 0x%.2x val: 0x%.4x\n",
+ addr, reg, val);
+
mutex_lock(&ps->smi_mutex);
ret = __mv88e6xxx_reg_write(bus, ds->pd->sw_addr, addr, reg, val);
mutex_unlock(&ps->smi_mutex);
diff --git a/drivers/net/ethernet/3com/3c589_cs.c b/drivers/net/ethernet/3com/3c589_cs.c
index f18647c23559..c5a320507556 100644
--- a/drivers/net/ethernet/3com/3c589_cs.c
+++ b/drivers/net/ethernet/3com/3c589_cs.c
@@ -518,11 +518,8 @@ static int el3_open(struct net_device *dev)
netif_start_queue(dev);
tc589_reset(dev);
- init_timer(&lp->media);
- lp->media.function = media_check;
- lp->media.data = (unsigned long) dev;
- lp->media.expires = jiffies + HZ;
- add_timer(&lp->media);
+ setup_timer(&lp->media, media_check, (unsigned long)dev);
+ mod_timer(&lp->media, jiffies + HZ);
dev_dbg(&link->dev, "%s: opened, status %4.4x.\n",
dev->name, inw(dev->base_addr + EL3_STATUS));
diff --git a/drivers/net/ethernet/3com/typhoon.c b/drivers/net/ethernet/3com/typhoon.c
index dede43f4ce09..8f8418d2ac4a 100644
--- a/drivers/net/ethernet/3com/typhoon.c
+++ b/drivers/net/ethernet/3com/typhoon.c
@@ -769,11 +769,11 @@ typhoon_start_tx(struct sk_buff *skb, struct net_device *dev)
first_txd->processFlags |= TYPHOON_TX_PF_IP_CHKSUM;
}
- if(vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
first_txd->processFlags |=
TYPHOON_TX_PF_INSERT_VLAN | TYPHOON_TX_PF_VLAN_PRIORITY;
first_txd->processFlags |=
- cpu_to_le32(htons(vlan_tx_tag_get(skb)) <<
+ cpu_to_le32(htons(skb_vlan_tag_get(skb)) <<
TYPHOON_TX_PF_VLAN_TAG_SHIFT);
}
diff --git a/drivers/net/ethernet/agere/et131x.c b/drivers/net/ethernet/agere/et131x.c
index 384dc163851b..e0f3d197e7f2 100644
--- a/drivers/net/ethernet/agere/et131x.c
+++ b/drivers/net/ethernet/agere/et131x.c
@@ -3127,7 +3127,8 @@ static void et131x_error_timer_handler(unsigned long data)
}
/* This is a periodic timer, so reschedule */
- mod_timer(&adapter->error_timer, jiffies + TX_ERROR_PERIOD * HZ / 1000);
+ mod_timer(&adapter->error_timer, jiffies +
+ msecs_to_jiffies(TX_ERROR_PERIOD));
}
static void et131x_adapter_memory_free(struct et131x_adapter *adapter)
@@ -3647,7 +3648,8 @@ static int et131x_open(struct net_device *netdev)
/* Start the timer to track NIC errors */
init_timer(&adapter->error_timer);
- adapter->error_timer.expires = jiffies + TX_ERROR_PERIOD * HZ / 1000;
+ adapter->error_timer.expires = jiffies +
+ msecs_to_jiffies(TX_ERROR_PERIOD);
adapter->error_timer.function = et131x_error_timer_handler;
adapter->error_timer.data = (unsigned long)adapter;
add_timer(&adapter->error_timer);
diff --git a/drivers/net/ethernet/alteon/acenic.c b/drivers/net/ethernet/alteon/acenic.c
index b68074803de3..b90a26b13fdf 100644
--- a/drivers/net/ethernet/alteon/acenic.c
+++ b/drivers/net/ethernet/alteon/acenic.c
@@ -2429,9 +2429,9 @@ restart:
flagsize = (skb->len << 16) | (BD_FLG_END);
if (skb->ip_summed == CHECKSUM_PARTIAL)
flagsize |= BD_FLG_TCP_UDP_SUM;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
flagsize |= BD_FLG_VLAN_TAG;
- vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = skb_vlan_tag_get(skb);
}
desc = ap->tx_ring + idx;
idx = (idx + 1) % ACE_TX_RING_ENTRIES(ap);
@@ -2450,9 +2450,9 @@ restart:
flagsize = (skb_headlen(skb) << 16);
if (skb->ip_summed == CHECKSUM_PARTIAL)
flagsize |= BD_FLG_TCP_UDP_SUM;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
flagsize |= BD_FLG_VLAN_TAG;
- vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = skb_vlan_tag_get(skb);
}
ace_load_tx_bd(ap, ap->tx_ring + idx, mapping, flagsize, vlan_tag);
diff --git a/drivers/net/ethernet/amd/Kconfig b/drivers/net/ethernet/amd/Kconfig
index 7a5e4aa5415e..c638c85f3954 100644
--- a/drivers/net/ethernet/amd/Kconfig
+++ b/drivers/net/ethernet/amd/Kconfig
@@ -45,7 +45,7 @@ config AMD8111_ETH
config LANCE
tristate "AMD LANCE and PCnet (AT1500 and NE2100) support"
- depends on ISA && ISA_DMA_API
+ depends on ISA && ISA_DMA_API && !ARM
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
@@ -142,7 +142,7 @@ config PCMCIA_NMCLAN
config NI65
tristate "NI6510 support"
- depends on ISA && ISA_DMA_API
+ depends on ISA && ISA_DMA_API && !ARM
---help---
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
@@ -179,7 +179,7 @@ config SUNLANCE
config AMD_XGBE
tristate "AMD 10GbE Ethernet driver"
- depends on OF_NET && HAS_IOMEM
+ depends on (OF_NET || ACPI) && HAS_IOMEM
select PHYLIB
select AMD_XGBE_PHY
select BITREVERSE
diff --git a/drivers/net/ethernet/amd/amd8111e.c b/drivers/net/ethernet/amd/amd8111e.c
index 841e6558db68..4c2ae2221780 100644
--- a/drivers/net/ethernet/amd/amd8111e.c
+++ b/drivers/net/ethernet/amd/amd8111e.c
@@ -1299,11 +1299,11 @@ static netdev_tx_t amd8111e_start_xmit(struct sk_buff *skb,
lp->tx_ring[tx_index].tx_flags = 0;
#if AMD8111E_VLAN_TAG_USED
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
lp->tx_ring[tx_index].tag_ctrl_cmd |=
cpu_to_le16(TCC_VLAN_INSERT);
lp->tx_ring[tx_index].tag_ctrl_info =
- cpu_to_le16(vlan_tx_tag_get(skb));
+ cpu_to_le16(skb_vlan_tag_get(skb));
}
#endif
diff --git a/drivers/net/ethernet/amd/atarilance.c b/drivers/net/ethernet/amd/atarilance.c
index e07ce5ff2d48..b10964e8cb54 100644
--- a/drivers/net/ethernet/amd/atarilance.c
+++ b/drivers/net/ethernet/amd/atarilance.c
@@ -553,8 +553,8 @@ static unsigned long __init lance_probe1( struct net_device *dev,
if (lp->cardtype == PAM_CARD ||
memaddr == (unsigned short *)0xffe00000) {
/* PAMs card and Riebl on ST use level 5 autovector */
- if (request_irq(IRQ_AUTO_5, lance_interrupt, IRQ_TYPE_PRIO,
- "PAM,Riebl-ST Ethernet", dev)) {
+ if (request_irq(IRQ_AUTO_5, lance_interrupt, 0,
+ "PAM,Riebl-ST Ethernet", dev)) {
printk( "Lance: request for irq %d failed\n", IRQ_AUTO_5 );
return 0;
}
@@ -567,8 +567,8 @@ static unsigned long __init lance_probe1( struct net_device *dev,
printk( "Lance: request for VME interrupt failed\n" );
return 0;
}
- if (request_irq(irq, lance_interrupt, IRQ_TYPE_PRIO,
- "Riebl-VME Ethernet", dev)) {
+ if (request_irq(irq, lance_interrupt, 0, "Riebl-VME Ethernet",
+ dev)) {
printk( "Lance: request for irq %u failed\n", irq );
return 0;
}
diff --git a/drivers/net/ethernet/amd/nmclan_cs.c b/drivers/net/ethernet/amd/nmclan_cs.c
index 5b22764ba88d..27245efe9f50 100644
--- a/drivers/net/ethernet/amd/nmclan_cs.c
+++ b/drivers/net/ethernet/amd/nmclan_cs.c
@@ -952,6 +952,8 @@ static irqreturn_t mace_interrupt(int irq, void *dev_id)
do {
/* WARNING: MACE_IR is a READ/CLEAR port! */
status = inb(ioaddr + AM2150_MACE_BASE + MACE_IR);
+ if (!(status & ~MACE_IMR_DEFAULT) && IntrCnt == MACE_MAX_IR_ITERATIONS)
+ return IRQ_NONE;
pr_debug("mace_interrupt: irq 0x%X status 0x%X.\n", irq, status);
diff --git a/drivers/net/ethernet/amd/pcnet32.c b/drivers/net/ethernet/amd/pcnet32.c
index e2e3aaf501a2..11d6e6561df1 100644
--- a/drivers/net/ethernet/amd/pcnet32.c
+++ b/drivers/net/ethernet/amd/pcnet32.c
@@ -2806,7 +2806,7 @@ static void pcnet32_check_media(struct net_device *dev, int verbose)
/*
* Check for loss of link and link establishment.
- * Can not use mii_check_media because it does nothing if mode is forced.
+ * Could possibly be changed to use mii_check_media instead.
*/
static void pcnet32_watchdog(struct net_device *dev)
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
index 76479d04b903..2c063b60db4b 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-debugfs.c
@@ -328,7 +328,7 @@ void xgbe_debugfs_init(struct xgbe_prv_data *pdata)
buf = kasprintf(GFP_KERNEL, "amd-xgbe-%s", pdata->netdev->name);
pdata->xgbe_debugfs = debugfs_create_dir(buf, NULL);
- if (pdata->xgbe_debugfs == NULL) {
+ if (!pdata->xgbe_debugfs) {
netdev_err(pdata->netdev, "debugfs_create_dir failed\n");
return;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
index a50891f52197..d81fc6bd4759 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-desc.c
@@ -422,7 +422,6 @@ static void xgbe_wrapper_rx_descriptor_init(struct xgbe_prv_data *pdata)
ring->cur = 0;
ring->dirty = 0;
- memset(&ring->rx, 0, sizeof(ring->rx));
hw_if->rx_desc_init(channel);
}
@@ -621,35 +620,6 @@ err_out:
return 0;
}
-static void xgbe_realloc_rx_buffer(struct xgbe_channel *channel)
-{
- struct xgbe_prv_data *pdata = channel->pdata;
- struct xgbe_hw_if *hw_if = &pdata->hw_if;
- struct xgbe_ring *ring = channel->rx_ring;
- struct xgbe_ring_data *rdata;
- int i;
-
- DBGPR("-->xgbe_realloc_rx_buffer: rx_ring->rx.realloc_index = %u\n",
- ring->rx.realloc_index);
-
- for (i = 0; i < ring->dirty; i++) {
- rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index);
-
- /* Reset rdata values */
- xgbe_unmap_rdata(pdata, rdata);
-
- if (xgbe_map_rx_buffer(pdata, ring, rdata))
- break;
-
- hw_if->rx_desc_reset(rdata);
-
- ring->rx.realloc_index++;
- }
- ring->dirty = 0;
-
- DBGPR("<--xgbe_realloc_rx_buffer\n");
-}
-
void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if)
{
DBGPR("-->xgbe_init_function_ptrs_desc\n");
@@ -657,7 +627,7 @@ void xgbe_init_function_ptrs_desc(struct xgbe_desc_if *desc_if)
desc_if->alloc_ring_resources = xgbe_alloc_ring_resources;
desc_if->free_ring_resources = xgbe_free_ring_resources;
desc_if->map_tx_skb = xgbe_map_tx_skb;
- desc_if->realloc_rx_buffer = xgbe_realloc_rx_buffer;
+ desc_if->map_rx_buffer = xgbe_map_rx_buffer;
desc_if->unmap_rdata = xgbe_unmap_rdata;
desc_if->wrapper_tx_desc_init = xgbe_wrapper_tx_descriptor_init;
desc_if->wrapper_rx_desc_init = xgbe_wrapper_rx_descriptor_init;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
index 4c66cd1d1e60..400757b49872 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-dev.c
@@ -115,6 +115,7 @@
*/
#include <linux/phy.h>
+#include <linux/mdio.h>
#include <linux/clk.h>
#include <linux/bitrev.h>
#include <linux/crc32.h>
@@ -130,7 +131,7 @@ static unsigned int xgbe_usec_to_riwt(struct xgbe_prv_data *pdata,
DBGPR("-->xgbe_usec_to_riwt\n");
- rate = clk_get_rate(pdata->sysclk);
+ rate = pdata->sysclk_rate;
/*
* Convert the input usec value to the watchdog timer value. Each
@@ -153,7 +154,7 @@ static unsigned int xgbe_riwt_to_usec(struct xgbe_prv_data *pdata,
DBGPR("-->xgbe_riwt_to_usec\n");
- rate = clk_get_rate(pdata->sysclk);
+ rate = pdata->sysclk_rate;
/*
* Convert the input watchdog timer value to the usec value. Each
@@ -673,6 +674,9 @@ static void xgbe_enable_mac_interrupts(struct xgbe_prv_data *pdata)
static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata)
{
+ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x3)
+ return 0;
+
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x3);
return 0;
@@ -680,6 +684,9 @@ static int xgbe_set_gmii_speed(struct xgbe_prv_data *pdata)
static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata)
{
+ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0x2)
+ return 0;
+
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0x2);
return 0;
@@ -687,6 +694,9 @@ static int xgbe_set_gmii_2500_speed(struct xgbe_prv_data *pdata)
static int xgbe_set_xgmii_speed(struct xgbe_prv_data *pdata)
{
+ if (XGMAC_IOREAD_BITS(pdata, MAC_TCR, SS) == 0)
+ return 0;
+
XGMAC_IOWRITE_BITS(pdata, MAC_TCR, SS, 0);
return 0;
@@ -881,6 +891,23 @@ static void xgbe_write_mmd_regs(struct xgbe_prv_data *pdata, int prtad,
else
mmd_address = (pdata->mdio_mmd << 16) | (mmd_reg & 0xffff);
+ /* If the PCS is changing modes, match the MAC speed to it */
+ if (((mmd_address >> 16) == MDIO_MMD_PCS) &&
+ ((mmd_address & 0xffff) == MDIO_CTRL2)) {
+ struct phy_device *phydev = pdata->phydev;
+
+ if (mmd_data & MDIO_PCS_CTRL2_TYPE) {
+ /* KX mode */
+ if (phydev->supported & SUPPORTED_1000baseKX_Full)
+ xgbe_set_gmii_speed(pdata);
+ else
+ xgbe_set_gmii_2500_speed(pdata);
+ } else {
+ /* KR mode */
+ xgbe_set_xgmii_speed(pdata);
+ }
+ }
+
/* The PCS registers are accessed using mmio. The underlying APB3
* management interface uses indirect addressing to access the MMD
* register sets. This requires accessing of the PCS register in two
@@ -1359,6 +1386,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
unsigned int tso_context, vlan_context;
unsigned int tx_set_ic;
int start_index = ring->cur;
+ int cur_index = ring->cur;
int i;
DBGPR("-->xgbe_dev_xmit\n");
@@ -1401,7 +1429,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
else
tx_set_ic = 0;
- rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+ rdata = XGBE_GET_DESC_DATA(ring, cur_index);
rdesc = rdata->rdesc;
/* Create a context descriptor if this is a TSO packet */
@@ -1444,8 +1472,8 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
ring->tx.cur_vlan_ctag = packet->vlan_ctag;
}
- ring->cur++;
- rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+ cur_index++;
+ rdata = XGBE_GET_DESC_DATA(ring, cur_index);
rdesc = rdata->rdesc;
}
@@ -1473,7 +1501,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, CTXT, 0);
/* Set OWN bit if not the first descriptor */
- if (ring->cur != start_index)
+ if (cur_index != start_index)
XGMAC_SET_BITS_LE(rdesc->desc3, TX_NORMAL_DESC3, OWN, 1);
if (tso) {
@@ -1497,9 +1525,9 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
packet->length);
}
- for (i = ring->cur - start_index + 1; i < packet->rdesc_count; i++) {
- ring->cur++;
- rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
+ for (i = cur_index - start_index + 1; i < packet->rdesc_count; i++) {
+ cur_index++;
+ rdata = XGBE_GET_DESC_DATA(ring, cur_index);
rdesc = rdata->rdesc;
/* Update buffer address */
@@ -1551,7 +1579,7 @@ static void xgbe_dev_xmit(struct xgbe_channel *channel)
/* Make sure ownership is written to the descriptor */
wmb();
- ring->cur++;
+ ring->cur = cur_index + 1;
if (!packet->skb->xmit_more ||
netif_xmit_stopped(netdev_get_tx_queue(pdata->netdev,
channel->queue_index)))
@@ -2107,6 +2135,23 @@ static void xgbe_config_jumbo_enable(struct xgbe_prv_data *pdata)
XGMAC_IOWRITE_BITS(pdata, MAC_RCR, JE, val);
}
+static void xgbe_config_mac_speed(struct xgbe_prv_data *pdata)
+{
+ switch (pdata->phy_speed) {
+ case SPEED_10000:
+ xgbe_set_xgmii_speed(pdata);
+ break;
+
+ case SPEED_2500:
+ xgbe_set_gmii_2500_speed(pdata);
+ break;
+
+ case SPEED_1000:
+ xgbe_set_gmii_speed(pdata);
+ break;
+ }
+}
+
static void xgbe_config_checksum_offload(struct xgbe_prv_data *pdata)
{
if (pdata->netdev->features & NETIF_F_RXCSUM)
@@ -2757,6 +2802,7 @@ static int xgbe_init(struct xgbe_prv_data *pdata)
xgbe_config_mac_address(pdata);
xgbe_config_jumbo_enable(pdata);
xgbe_config_flow_control(pdata);
+ xgbe_config_mac_speed(pdata);
xgbe_config_checksum_offload(pdata);
xgbe_config_vlan_support(pdata);
xgbe_config_mmc(pdata);
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
index 7bb5f07dbeef..b93d4404d975 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-drv.c
@@ -225,6 +225,11 @@ static inline unsigned int xgbe_tx_avail_desc(struct xgbe_ring *ring)
return (ring->rdesc_count - (ring->cur - ring->dirty));
}
+static inline unsigned int xgbe_rx_dirty_desc(struct xgbe_ring *ring)
+{
+ return (ring->cur - ring->dirty);
+}
+
static int xgbe_maybe_stop_tx_queue(struct xgbe_channel *channel,
struct xgbe_ring *ring, unsigned int count)
{
@@ -337,12 +342,13 @@ static irqreturn_t xgbe_isr(int irq, void *data)
dma_ch_isr = XGMAC_DMA_IOREAD(channel, DMA_CH_SR);
DBGPR(" DMA_CH%u_ISR = %08x\n", i, dma_ch_isr);
- /* If we get a TI or RI interrupt that means per channel DMA
- * interrupts are not enabled, so we use the private data napi
- * structure, not the per channel napi structure
+ /* The TI or RI interrupt bits may still be set even if using
+ * per channel DMA interrupts. Check to be sure those are not
+ * enabled before using the private data napi structure.
*/
- if (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) ||
- XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI)) {
+ if (!pdata->per_channel_irq &&
+ (XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, TI) ||
+ XGMAC_GET_BITS(dma_ch_isr, DMA_CH_SR, RI))) {
if (napi_schedule_prep(&pdata->napi)) {
/* Disable Tx and Rx interrupts */
xgbe_disable_rx_tx_ints(pdata);
@@ -410,17 +416,13 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer)
struct xgbe_channel *channel = container_of(timer,
struct xgbe_channel,
tx_timer);
- struct xgbe_ring *ring = channel->tx_ring;
struct xgbe_prv_data *pdata = channel->pdata;
struct napi_struct *napi;
- unsigned long flags;
DBGPR("-->xgbe_tx_timer\n");
napi = (pdata->per_channel_irq) ? &channel->napi : &pdata->napi;
- spin_lock_irqsave(&ring->lock, flags);
-
if (napi_schedule_prep(napi)) {
/* Disable Tx and Rx interrupts */
if (pdata->per_channel_irq)
@@ -434,8 +436,6 @@ static enum hrtimer_restart xgbe_tx_timer(struct hrtimer *timer)
channel->tx_timer_active = 0;
- spin_unlock_irqrestore(&ring->lock, flags);
-
DBGPR("<--xgbe_tx_timer\n");
return HRTIMER_NORESTART;
@@ -523,6 +523,7 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
hw_feat->sph = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, SPHEN);
hw_feat->tso = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, TSOEN);
hw_feat->dma_debug = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, DBGMEMA);
+ hw_feat->rss = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, RSSEN);
hw_feat->tc_cnt = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R, NUMTC);
hw_feat->hash_table_size = XGMAC_GET_BITS(mac_hfr1, MAC_HWF1R,
HASHTBLSZ);
@@ -552,13 +553,14 @@ void xgbe_get_all_hw_features(struct xgbe_prv_data *pdata)
break;
}
- /* The Queue and Channel counts are zero based so increment them
+ /* The Queue, Channel and TC counts are zero based so increment them
* to get the actual number
*/
hw_feat->rx_q_cnt++;
hw_feat->tx_q_cnt++;
hw_feat->rx_ch_cnt++;
hw_feat->tx_ch_cnt++;
+ hw_feat->tc_cnt++;
DBGPR("<--xgbe_get_all_hw_features\n");
}
@@ -692,7 +694,7 @@ static void xgbe_adjust_link(struct net_device *netdev)
struct phy_device *phydev = pdata->phydev;
int new_state = 0;
- if (phydev == NULL)
+ if (!phydev)
return;
if (phydev->link) {
@@ -927,7 +929,7 @@ static void xgbe_stop(struct xgbe_prv_data *pdata)
DBGPR("<--xgbe_stop\n");
}
-static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset)
+static void xgbe_restart_dev(struct xgbe_prv_data *pdata)
{
struct xgbe_channel *channel;
struct xgbe_hw_if *hw_if = &pdata->hw_if;
@@ -950,9 +952,8 @@ static void xgbe_restart_dev(struct xgbe_prv_data *pdata, unsigned int reset)
xgbe_free_tx_data(pdata);
xgbe_free_rx_data(pdata);
- /* Issue software reset to device if requested */
- if (reset)
- hw_if->exit(pdata);
+ /* Issue software reset to device */
+ hw_if->exit(pdata);
xgbe_start(pdata);
@@ -967,7 +968,7 @@ static void xgbe_restart(struct work_struct *work)
rtnl_lock();
- xgbe_restart_dev(pdata, 1);
+ xgbe_restart_dev(pdata);
rtnl_unlock();
}
@@ -1165,8 +1166,8 @@ static void xgbe_prep_tx_tstamp(struct xgbe_prv_data *pdata,
static void xgbe_prep_vlan(struct sk_buff *skb, struct xgbe_packet_data *packet)
{
- if (vlan_tx_tag_present(skb))
- packet->vlan_ctag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb))
+ packet->vlan_ctag = skb_vlan_tag_get(skb);
}
static int xgbe_prep_tso(struct sk_buff *skb, struct xgbe_packet_data *packet)
@@ -1247,9 +1248,9 @@ static void xgbe_packet_info(struct xgbe_prv_data *pdata,
XGMAC_SET_BITS(packet->attributes, TX_PACKET_ATTRIBUTES,
CSUM_ENABLE, 1);
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
/* VLAN requires an extra descriptor if tag is different */
- if (vlan_tx_tag_get(skb) != ring->tx.cur_vlan_ctag)
+ if (skb_vlan_tag_get(skb) != ring->tx.cur_vlan_ctag)
/* We can share with the TSO context descriptor */
if (!context_desc) {
context_desc = 1;
@@ -1446,7 +1447,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
struct xgbe_ring *ring;
struct xgbe_packet_data *packet;
struct netdev_queue *txq;
- unsigned long flags;
int ret;
DBGPR("-->xgbe_xmit: skb->len = %d\n", skb->len);
@@ -1458,8 +1458,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
ret = NETDEV_TX_OK;
- spin_lock_irqsave(&ring->lock, flags);
-
if (skb->len == 0) {
netdev_err(netdev, "empty skb received from stack\n");
dev_kfree_skb_any(skb);
@@ -1506,10 +1504,6 @@ static int xgbe_xmit(struct sk_buff *skb, struct net_device *netdev)
ret = NETDEV_TX_OK;
tx_netdev_return:
- spin_unlock_irqrestore(&ring->lock, flags);
-
- DBGPR("<--xgbe_xmit\n");
-
return ret;
}
@@ -1587,7 +1581,7 @@ static int xgbe_change_mtu(struct net_device *netdev, int mtu)
pdata->rx_buf_size = ret;
netdev->mtu = mtu;
- xgbe_restart_dev(pdata, 0);
+ xgbe_restart_dev(pdata);
DBGPR("<--xgbe_change_mtu\n");
@@ -1776,15 +1770,28 @@ struct net_device_ops *xgbe_get_netdev_ops(void)
static void xgbe_rx_refresh(struct xgbe_channel *channel)
{
struct xgbe_prv_data *pdata = channel->pdata;
+ struct xgbe_hw_if *hw_if = &pdata->hw_if;
struct xgbe_desc_if *desc_if = &pdata->desc_if;
struct xgbe_ring *ring = channel->rx_ring;
struct xgbe_ring_data *rdata;
- desc_if->realloc_rx_buffer(channel);
+ while (ring->dirty != ring->cur) {
+ rdata = XGBE_GET_DESC_DATA(ring, ring->dirty);
+
+ /* Reset rdata values */
+ desc_if->unmap_rdata(pdata, rdata);
+
+ if (desc_if->map_rx_buffer(pdata, ring, rdata))
+ break;
+
+ hw_if->rx_desc_reset(rdata);
+
+ ring->dirty++;
+ }
/* Update the Rx Tail Pointer Register with address of
* the last cleaned entry */
- rdata = XGBE_GET_DESC_DATA(ring, ring->rx.realloc_index - 1);
+ rdata = XGBE_GET_DESC_DATA(ring, ring->dirty - 1);
XGMAC_DMA_IOWRITE(channel, DMA_CH_RDTR_LO,
lower_32_bits(rdata->rdesc_dma));
}
@@ -1824,7 +1831,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
struct xgbe_ring_desc *rdesc;
struct net_device *netdev = pdata->netdev;
struct netdev_queue *txq;
- unsigned long flags;
int processed = 0;
unsigned int tx_packets = 0, tx_bytes = 0;
@@ -1836,8 +1842,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
txq = netdev_get_tx_queue(netdev, channel->queue_index);
- spin_lock_irqsave(&ring->lock, flags);
-
while ((processed < XGBE_TX_DESC_MAX_PROC) &&
(ring->dirty != ring->cur)) {
rdata = XGBE_GET_DESC_DATA(ring, ring->dirty);
@@ -1868,7 +1872,7 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
}
if (!processed)
- goto unlock;
+ return 0;
netdev_tx_completed_queue(txq, tx_packets, tx_bytes);
@@ -1880,9 +1884,6 @@ static int xgbe_tx_poll(struct xgbe_channel *channel)
DBGPR("<--xgbe_tx_poll: processed=%d\n", processed);
-unlock:
- spin_unlock_irqrestore(&ring->lock, flags);
-
return processed;
}
@@ -1934,7 +1935,7 @@ static int xgbe_rx_poll(struct xgbe_channel *channel, int budget)
read_again:
rdata = XGBE_GET_DESC_DATA(ring, ring->cur);
- if (ring->dirty > (XGBE_RX_DESC_CNT >> 3))
+ if (xgbe_rx_dirty_desc(ring) > (XGBE_RX_DESC_CNT >> 3))
xgbe_rx_refresh(channel);
if (hw_if->dev_read(channel))
@@ -1942,7 +1943,6 @@ read_again:
received++;
ring->cur++;
- ring->dirty++;
incomplete = XGMAC_GET_BITS(packet->attributes,
RX_PACKET_ATTRIBUTES,
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-main.c b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
index dbd3850b8b0a..32dd65137051 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-main.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-main.c
@@ -123,7 +123,10 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_net.h>
+#include <linux/of_address.h>
#include <linux/clk.h>
+#include <linux/property.h>
+#include <linux/acpi.h>
#include "xgbe.h"
#include "xgbe-common.h"
@@ -148,6 +151,7 @@ static void xgbe_default_config(struct xgbe_prv_data *pdata)
pdata->pause_autoneg = 1;
pdata->tx_pause = 1;
pdata->rx_pause = 1;
+ pdata->phy_speed = SPEED_UNKNOWN;
pdata->power_down = 0;
pdata->default_autoneg = AUTONEG_ENABLE;
pdata->default_speed = SPEED_10000;
@@ -161,6 +165,96 @@ static void xgbe_init_all_fptrs(struct xgbe_prv_data *pdata)
xgbe_init_function_ptrs_desc(&pdata->desc_if);
}
+#ifdef CONFIG_ACPI
+static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
+{
+ struct acpi_device *adev = pdata->adev;
+ struct device *dev = pdata->dev;
+ u32 property;
+ acpi_handle handle;
+ acpi_status status;
+ unsigned long long data;
+ int cca;
+ int ret;
+
+ /* Obtain the system clock setting */
+ ret = device_property_read_u32(dev, XGBE_ACPI_DMA_FREQ, &property);
+ if (ret) {
+ dev_err(dev, "unable to obtain %s property\n",
+ XGBE_ACPI_DMA_FREQ);
+ return ret;
+ }
+ pdata->sysclk_rate = property;
+
+ /* Obtain the PTP clock setting */
+ ret = device_property_read_u32(dev, XGBE_ACPI_PTP_FREQ, &property);
+ if (ret) {
+ dev_err(dev, "unable to obtain %s property\n",
+ XGBE_ACPI_PTP_FREQ);
+ return ret;
+ }
+ pdata->ptpclk_rate = property;
+
+ /* Retrieve the device cache coherency value */
+ handle = adev->handle;
+ do {
+ status = acpi_evaluate_integer(handle, "_CCA", NULL, &data);
+ if (!ACPI_FAILURE(status)) {
+ cca = data;
+ break;
+ }
+
+ status = acpi_get_parent(handle, &handle);
+ } while (!ACPI_FAILURE(status));
+
+ if (ACPI_FAILURE(status)) {
+ dev_err(dev, "error obtaining acpi coherency value\n");
+ return -EINVAL;
+ }
+ pdata->coherent = !!cca;
+
+ return 0;
+}
+#else /* CONFIG_ACPI */
+static int xgbe_acpi_support(struct xgbe_prv_data *pdata)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_ACPI */
+
+#ifdef CONFIG_OF
+static int xgbe_of_support(struct xgbe_prv_data *pdata)
+{
+ struct device *dev = pdata->dev;
+
+ /* Obtain the system clock setting */
+ pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK);
+ if (IS_ERR(pdata->sysclk)) {
+ dev_err(dev, "dma devm_clk_get failed\n");
+ return PTR_ERR(pdata->sysclk);
+ }
+ pdata->sysclk_rate = clk_get_rate(pdata->sysclk);
+
+ /* Obtain the PTP clock setting */
+ pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK);
+ if (IS_ERR(pdata->ptpclk)) {
+ dev_err(dev, "ptp devm_clk_get failed\n");
+ return PTR_ERR(pdata->ptpclk);
+ }
+ pdata->ptpclk_rate = clk_get_rate(pdata->ptpclk);
+
+ /* Retrieve the device cache coherency value */
+ pdata->coherent = of_dma_is_coherent(dev->of_node);
+
+ return 0;
+}
+#else /* CONFIG_OF */
+static int xgbe_of_support(struct xgbe_prv_data *pdata)
+{
+ return -EINVAL;
+}
+#endif /*CONFIG_OF */
+
static int xgbe_probe(struct platform_device *pdev)
{
struct xgbe_prv_data *pdata;
@@ -169,7 +263,7 @@ static int xgbe_probe(struct platform_device *pdev)
struct net_device *netdev;
struct device *dev = &pdev->dev;
struct resource *res;
- const u8 *mac_addr;
+ const char *phy_mode;
unsigned int i;
int ret;
@@ -186,6 +280,7 @@ static int xgbe_probe(struct platform_device *pdev)
pdata = netdev_priv(netdev);
pdata->netdev = netdev;
pdata->pdev = pdev;
+ pdata->adev = ACPI_COMPANION(dev);
pdata->dev = dev;
platform_set_drvdata(pdev, netdev);
@@ -194,6 +289,9 @@ static int xgbe_probe(struct platform_device *pdev)
mutex_init(&pdata->rss_mutex);
spin_lock_init(&pdata->tstamp_lock);
+ /* Check if we should use ACPI or DT */
+ pdata->use_acpi = (!pdata->adev || acpi_disabled) ? 0 : 1;
+
/* Set and validate the number of descriptors for a ring */
BUILD_BUG_ON_NOT_POWER_OF_2(XGBE_TX_DESC_CNT);
pdata->tx_desc_count = XGBE_TX_DESC_CNT;
@@ -212,22 +310,6 @@ static int xgbe_probe(struct platform_device *pdev)
goto err_io;
}
- /* Obtain the system clock setting */
- pdata->sysclk = devm_clk_get(dev, XGBE_DMA_CLOCK);
- if (IS_ERR(pdata->sysclk)) {
- dev_err(dev, "dma devm_clk_get failed\n");
- ret = PTR_ERR(pdata->sysclk);
- goto err_io;
- }
-
- /* Obtain the PTP clock setting */
- pdata->ptpclk = devm_clk_get(dev, XGBE_PTP_CLOCK);
- if (IS_ERR(pdata->ptpclk)) {
- dev_err(dev, "ptp devm_clk_get failed\n");
- ret = PTR_ERR(pdata->ptpclk);
- goto err_io;
- }
-
/* Obtain the mmio areas for the device */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pdata->xgmac_regs = devm_ioremap_resource(dev, res);
@@ -247,16 +329,42 @@ static int xgbe_probe(struct platform_device *pdev)
}
DBGPR(" xpcs_regs = %p\n", pdata->xpcs_regs);
- /* Set the DMA mask */
- if (!dev->dma_mask)
- dev->dma_mask = &dev->coherent_dma_mask;
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
- if (ret) {
- dev_err(dev, "dma_set_mask_and_coherent failed\n");
+ /* Retrieve the MAC address */
+ ret = device_property_read_u8_array(dev, XGBE_MAC_ADDR_PROPERTY,
+ pdata->mac_addr,
+ sizeof(pdata->mac_addr));
+ if (ret || !is_valid_ether_addr(pdata->mac_addr)) {
+ dev_err(dev, "invalid %s property\n", XGBE_MAC_ADDR_PROPERTY);
+ if (!ret)
+ ret = -EINVAL;
goto err_io;
}
- if (of_property_read_bool(dev->of_node, "dma-coherent")) {
+ /* Retrieve the PHY mode - it must be "xgmii" */
+ ret = device_property_read_string(dev, XGBE_PHY_MODE_PROPERTY,
+ &phy_mode);
+ if (ret || strcmp(phy_mode, phy_modes(PHY_INTERFACE_MODE_XGMII))) {
+ dev_err(dev, "invalid %s property\n", XGBE_PHY_MODE_PROPERTY);
+ if (!ret)
+ ret = -EINVAL;
+ goto err_io;
+ }
+ pdata->phy_mode = PHY_INTERFACE_MODE_XGMII;
+
+ /* Check for per channel interrupt support */
+ if (device_property_present(dev, XGBE_DMA_IRQS_PROPERTY))
+ pdata->per_channel_irq = 1;
+
+ /* Obtain device settings unique to ACPI/OF */
+ if (pdata->use_acpi)
+ ret = xgbe_acpi_support(pdata);
+ else
+ ret = xgbe_of_support(pdata);
+ if (ret)
+ goto err_io;
+
+ /* Set the DMA coherency values */
+ if (pdata->coherent) {
pdata->axdomain = XGBE_DMA_OS_AXDOMAIN;
pdata->arcache = XGBE_DMA_OS_ARCACHE;
pdata->awcache = XGBE_DMA_OS_AWCACHE;
@@ -266,10 +374,16 @@ static int xgbe_probe(struct platform_device *pdev)
pdata->awcache = XGBE_DMA_SYS_AWCACHE;
}
- /* Check for per channel interrupt support */
- if (of_property_read_bool(dev->of_node, XGBE_DMA_IRQS))
- pdata->per_channel_irq = 1;
+ /* Set the DMA mask */
+ if (!dev->dma_mask)
+ dev->dma_mask = &dev->coherent_dma_mask;
+ ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(40));
+ if (ret) {
+ dev_err(dev, "dma_set_mask_and_coherent failed\n");
+ goto err_io;
+ }
+ /* Get the device interrupt */
ret = platform_get_irq(pdev, 0);
if (ret < 0) {
dev_err(dev, "platform_get_irq 0 failed\n");
@@ -279,6 +393,7 @@ static int xgbe_probe(struct platform_device *pdev)
netdev->irq = pdata->dev_irq;
netdev->base_addr = (unsigned long)pdata->xgmac_regs;
+ memcpy(netdev->dev_addr, pdata->mac_addr, netdev->addr_len);
/* Set all the function pointers */
xgbe_init_all_fptrs(pdata);
@@ -291,23 +406,6 @@ static int xgbe_probe(struct platform_device *pdev)
/* Populate the hardware features */
xgbe_get_all_hw_features(pdata);
- /* Retrieve the MAC address */
- mac_addr = of_get_mac_address(dev->of_node);
- if (!mac_addr) {
- dev_err(dev, "invalid mac address for this device\n");
- ret = -EINVAL;
- goto err_io;
- }
- memcpy(netdev->dev_addr, mac_addr, netdev->addr_len);
-
- /* Retrieve the PHY mode - it must be "xgmii" */
- pdata->phy_mode = of_get_phy_mode(dev->of_node);
- if (pdata->phy_mode != PHY_INTERFACE_MODE_XGMII) {
- dev_err(dev, "invalid phy-mode specified for this device\n");
- ret = -EINVAL;
- goto err_io;
- }
-
/* Set default configuration data */
xgbe_default_config(pdata);
@@ -491,18 +589,35 @@ static int xgbe_resume(struct device *dev)
}
#endif /* CONFIG_PM */
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgbe_acpi_match[] = {
+ { "AMDI8001", 0 },
+ {},
+};
+
+MODULE_DEVICE_TABLE(acpi, xgbe_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
static const struct of_device_id xgbe_of_match[] = {
{ .compatible = "amd,xgbe-seattle-v1a", },
{},
};
MODULE_DEVICE_TABLE(of, xgbe_of_match);
+#endif
+
static SIMPLE_DEV_PM_OPS(xgbe_pm_ops, xgbe_suspend, xgbe_resume);
static struct platform_driver xgbe_driver = {
.driver = {
.name = "amd-xgbe",
+#ifdef CONFIG_ACPI
+ .acpi_match_table = xgbe_acpi_match,
+#endif
+#ifdef CONFIG_OF
.of_match_table = xgbe_of_match,
+#endif
.pm = &xgbe_pm_ops,
},
.probe = xgbe_probe,
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
index 363b210560f3..59e267f3f1b7 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-mdio.c
@@ -205,25 +205,16 @@ void xgbe_dump_phy_registers(struct xgbe_prv_data *pdata)
int xgbe_mdio_register(struct xgbe_prv_data *pdata)
{
- struct device_node *phy_node;
struct mii_bus *mii;
struct phy_device *phydev;
int ret = 0;
DBGPR("-->xgbe_mdio_register\n");
- /* Retrieve the phy-handle */
- phy_node = of_parse_phandle(pdata->dev->of_node, "phy-handle", 0);
- if (!phy_node) {
- dev_err(pdata->dev, "unable to parse phy-handle\n");
- return -EINVAL;
- }
-
mii = mdiobus_alloc();
- if (mii == NULL) {
+ if (!mii) {
dev_err(pdata->dev, "mdiobus_alloc failed\n");
- ret = -ENOMEM;
- goto err_node_get;
+ return -ENOMEM;
}
/* Register on the MDIO bus (don't probe any PHYs) */
@@ -252,18 +243,19 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
request_module(MDIO_MODULE_PREFIX MDIO_ID_FMT,
MDIO_ID_ARGS(phydev->c45_ids.device_ids[MDIO_MMD_PCS]));
- of_node_get(phy_node);
- phydev->dev.of_node = phy_node;
ret = phy_device_register(phydev);
if (ret) {
dev_err(pdata->dev, "phy_device_register failed\n");
- of_node_put(phy_node);
+ goto err_phy_device;
+ }
+ if (!phydev->dev.driver) {
+ dev_err(pdata->dev, "phy driver probe failed\n");
+ ret = -EIO;
goto err_phy_device;
}
/* Add a reference to the PHY driver so it can't be unloaded */
- pdata->phy_module = phydev->dev.driver ?
- phydev->dev.driver->owner : NULL;
+ pdata->phy_module = phydev->dev.driver->owner;
if (!try_module_get(pdata->phy_module)) {
dev_err(pdata->dev, "try_module_get failed\n");
ret = -EIO;
@@ -283,8 +275,6 @@ int xgbe_mdio_register(struct xgbe_prv_data *pdata)
pdata->phydev = phydev;
- of_node_put(phy_node);
-
DBGPHY_REGS(pdata);
DBGPR("<--xgbe_mdio_register\n");
@@ -300,9 +290,6 @@ err_mdiobus_register:
err_mdiobus_alloc:
mdiobus_free(mii);
-err_node_get:
- of_node_put(phy_node);
-
return ret;
}
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
index a1bf9d1cdae1..f326178ef376 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
+++ b/drivers/net/ethernet/amd/xgbe/xgbe-ptp.c
@@ -171,15 +171,9 @@ static int xgbe_adjtime(struct ptp_clock_info *info, s64 delta)
struct xgbe_prv_data,
ptp_clock_info);
unsigned long flags;
- u64 nsec;
spin_lock_irqsave(&pdata->tstamp_lock, flags);
-
- nsec = timecounter_read(&pdata->tstamp_tc);
-
- nsec += delta;
- timecounter_init(&pdata->tstamp_tc, &pdata->tstamp_cc, nsec);
-
+ timecounter_adjtime(&pdata->tstamp_tc, delta);
spin_unlock_irqrestore(&pdata->tstamp_lock, flags);
return 0;
@@ -239,7 +233,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata)
snprintf(info->name, sizeof(info->name), "%s",
netdev_name(pdata->netdev));
info->owner = THIS_MODULE;
- info->max_adj = clk_get_rate(pdata->ptpclk);
+ info->max_adj = pdata->ptpclk_rate;
info->adjfreq = xgbe_adjfreq;
info->adjtime = xgbe_adjtime;
info->gettime = xgbe_gettime;
@@ -260,7 +254,7 @@ void xgbe_ptp_register(struct xgbe_prv_data *pdata)
*/
dividend = 50000000;
dividend <<= 32;
- pdata->tstamp_addend = div_u64(dividend, clk_get_rate(pdata->ptpclk));
+ pdata->tstamp_addend = div_u64(dividend, pdata->ptpclk_rate);
/* Setup the timecounter */
cc->read = xgbe_cc_read;
diff --git a/drivers/net/ethernet/amd/xgbe/xgbe.h b/drivers/net/ethernet/amd/xgbe/xgbe.h
index f9ec762ac3f0..13e8f95c077c 100644
--- a/drivers/net/ethernet/amd/xgbe/xgbe.h
+++ b/drivers/net/ethernet/amd/xgbe/xgbe.h
@@ -124,7 +124,7 @@
#include <linux/if_vlan.h>
#include <linux/bitops.h>
#include <linux/ptp_clock_kernel.h>
-#include <linux/clocksource.h>
+#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <net/dcbnl.h>
@@ -182,10 +182,18 @@
#define XGBE_PHY_NAME "amd_xgbe_phy"
#define XGBE_PRTAD 0
+/* Common property names */
+#define XGBE_MAC_ADDR_PROPERTY "mac-address"
+#define XGBE_PHY_MODE_PROPERTY "phy-mode"
+#define XGBE_DMA_IRQS_PROPERTY "amd,per-channel-interrupt"
+
/* Device-tree clock names */
#define XGBE_DMA_CLOCK "dma_clk"
#define XGBE_PTP_CLOCK "ptp_clk"
-#define XGBE_DMA_IRQS "amd,per-channel-interrupt"
+
+/* ACPI property names */
+#define XGBE_ACPI_DMA_FREQ "amd,dma-freq"
+#define XGBE_ACPI_PTP_FREQ "amd,ptp-freq"
/* Timestamp support - values based on 50MHz PTP clock
* 50MHz => 20 nsec
@@ -361,8 +369,7 @@ struct xgbe_ring {
* cur - Tx: index of descriptor to be used for current transfer
* Rx: index of descriptor to check for packet availability
* dirty - Tx: index of descriptor to check for transfer complete
- * Rx: count of descriptors in which a packet has been received
- * (used with skb_realloc_index to refresh the ring)
+ * Rx: index of descriptor to check for buffer reallocation
*/
unsigned int cur;
unsigned int dirty;
@@ -377,11 +384,6 @@ struct xgbe_ring {
unsigned short cur_mss;
unsigned short cur_vlan_ctag;
} tx;
-
- struct {
- unsigned int realloc_index;
- unsigned int realloc_threshold;
- } rx;
};
} ____cacheline_aligned;
@@ -596,7 +598,8 @@ struct xgbe_desc_if {
int (*alloc_ring_resources)(struct xgbe_prv_data *);
void (*free_ring_resources)(struct xgbe_prv_data *);
int (*map_tx_skb)(struct xgbe_channel *, struct sk_buff *);
- void (*realloc_rx_buffer)(struct xgbe_channel *);
+ int (*map_rx_buffer)(struct xgbe_prv_data *, struct xgbe_ring *,
+ struct xgbe_ring_data *);
void (*unmap_rdata)(struct xgbe_prv_data *, struct xgbe_ring_data *);
void (*wrapper_tx_desc_init)(struct xgbe_prv_data *);
void (*wrapper_rx_desc_init)(struct xgbe_prv_data *);
@@ -650,8 +653,12 @@ struct xgbe_hw_features {
struct xgbe_prv_data {
struct net_device *netdev;
struct platform_device *pdev;
+ struct acpi_device *adev;
struct device *dev;
+ /* ACPI or DT flag */
+ unsigned int use_acpi;
+
/* XGMAC/XPCS related mmio registers */
void __iomem *xgmac_regs; /* XGMAC CSRs */
void __iomem *xpcs_regs; /* XPCS MMD registers */
@@ -672,6 +679,7 @@ struct xgbe_prv_data {
struct xgbe_desc_if desc_if;
/* AXI DMA settings */
+ unsigned int coherent;
unsigned int axdomain;
unsigned int arcache;
unsigned int awcache;
@@ -739,6 +747,7 @@ struct xgbe_prv_data {
unsigned int phy_rx_pause;
/* Netdev related settings */
+ unsigned char mac_addr[ETH_ALEN];
netdev_features_t netdev_features;
struct napi_struct napi;
struct xgbe_mmc_stats mmc_stats;
@@ -748,7 +757,9 @@ struct xgbe_prv_data {
/* Device clocks */
struct clk *sysclk;
+ unsigned long sysclk_rate;
struct clk *ptpclk;
+ unsigned long ptpclk_rate;
/* Timestamp support */
spinlock_t tstamp_lock;
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
index 7ba83ffb08ac..869d97fcf781 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_hw.c
@@ -593,10 +593,12 @@ static int xgene_enet_reset(struct xgene_enet_pdata *pdata)
if (!xgene_ring_mgr_init(pdata))
return -ENODEV;
- clk_prepare_enable(pdata->clk);
- clk_disable_unprepare(pdata->clk);
- clk_prepare_enable(pdata->clk);
- xgene_enet_ecc_init(pdata);
+ if (!efi_enabled(EFI_BOOT)) {
+ clk_prepare_enable(pdata->clk);
+ clk_disable_unprepare(pdata->clk);
+ clk_prepare_enable(pdata->clk);
+ xgene_enet_ecc_init(pdata);
+ }
xgene_enet_config_ring_if_assoc(pdata);
/* Enable auto-incr for scanning */
@@ -663,15 +665,20 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
struct phy_device *phy_dev;
struct device *dev = &pdata->pdev->dev;
- phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
- if (!phy_np) {
- netdev_dbg(ndev, "No phy-handle found\n");
- return -ENODEV;
+ if (dev->of_node) {
+ phy_np = of_parse_phandle(dev->of_node, "phy-handle", 0);
+ if (!phy_np) {
+ netdev_dbg(ndev, "No phy-handle found in DT\n");
+ return -ENODEV;
+ }
+ pdata->phy_dev = of_phy_find_device(phy_np);
}
- phy_dev = of_phy_connect(ndev, phy_np, &xgene_enet_adjust_link,
- 0, pdata->phy_mode);
- if (!phy_dev) {
+ phy_dev = pdata->phy_dev;
+
+ if (!phy_dev ||
+ phy_connect_direct(ndev, phy_dev, &xgene_enet_adjust_link,
+ pdata->phy_mode)) {
netdev_err(ndev, "Could not connect to PHY\n");
return -ENODEV;
}
@@ -681,32 +688,71 @@ static int xgene_enet_phy_connect(struct net_device *ndev)
~SUPPORTED_100baseT_Half &
~SUPPORTED_1000baseT_Half;
phy_dev->advertising = phy_dev->supported;
- pdata->phy_dev = phy_dev;
return 0;
}
-int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
+static int xgene_mdiobus_register(struct xgene_enet_pdata *pdata,
+ struct mii_bus *mdio)
{
- struct net_device *ndev = pdata->ndev;
struct device *dev = &pdata->pdev->dev;
+ struct net_device *ndev = pdata->ndev;
+ struct phy_device *phy;
struct device_node *child_np;
struct device_node *mdio_np = NULL;
- struct mii_bus *mdio_bus;
int ret;
+ u32 phy_id;
+
+ if (dev->of_node) {
+ for_each_child_of_node(dev->of_node, child_np) {
+ if (of_device_is_compatible(child_np,
+ "apm,xgene-mdio")) {
+ mdio_np = child_np;
+ break;
+ }
+ }
- for_each_child_of_node(dev->of_node, child_np) {
- if (of_device_is_compatible(child_np, "apm,xgene-mdio")) {
- mdio_np = child_np;
- break;
+ if (!mdio_np) {
+ netdev_dbg(ndev, "No mdio node in the dts\n");
+ return -ENXIO;
}
- }
- if (!mdio_np) {
- netdev_dbg(ndev, "No mdio node in the dts\n");
- return -ENXIO;
+ return of_mdiobus_register(mdio, mdio_np);
}
+ /* Mask out all PHYs from auto probing. */
+ mdio->phy_mask = ~0;
+
+ /* Register the MDIO bus */
+ ret = mdiobus_register(mdio);
+ if (ret)
+ return ret;
+
+ ret = device_property_read_u32(dev, "phy-channel", &phy_id);
+ if (ret)
+ ret = device_property_read_u32(dev, "phy-addr", &phy_id);
+ if (ret)
+ return -EINVAL;
+
+ phy = get_phy_device(mdio, phy_id, true);
+ if (!phy || IS_ERR(phy))
+ return -EIO;
+
+ ret = phy_device_register(phy);
+ if (ret)
+ phy_device_free(phy);
+ else
+ pdata->phy_dev = phy;
+
+ return ret;
+}
+
+int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
+{
+ struct net_device *ndev = pdata->ndev;
+ struct mii_bus *mdio_bus;
+ int ret;
+
mdio_bus = mdiobus_alloc();
if (!mdio_bus)
return -ENOMEM;
@@ -720,7 +766,7 @@ int xgene_enet_mdio_config(struct xgene_enet_pdata *pdata)
mdio_bus->priv = pdata;
mdio_bus->parent = &ndev->dev;
- ret = of_mdiobus_register(mdio_bus, mdio_np);
+ ret = xgene_mdiobus_register(pdata, mdio_bus);
if (ret) {
netdev_err(ndev, "Failed to register MDIO bus\n");
mdiobus_free(mdio_bus);
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
index 83a50280bb70..4de62b210c85 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.c
@@ -24,6 +24,10 @@
#include "xgene_enet_sgmac.h"
#include "xgene_enet_xgmac.h"
+#define RES_ENET_CSR 0
+#define RES_RING_CSR 1
+#define RES_RING_CMD 2
+
static void xgene_enet_init_bufpool(struct xgene_enet_desc_ring *buf_pool)
{
struct xgene_enet_raw_desc16 *raw_desc;
@@ -369,6 +373,8 @@ static int xgene_enet_process_ring(struct xgene_enet_desc_ring *ring,
if (unlikely(xgene_enet_is_desc_slot_empty(raw_desc)))
break;
+ /* read fpqnum field after dataaddr field */
+ dma_rmb();
if (is_rx_desc(raw_desc))
ret = xgene_enet_rx_frame(ring, raw_desc);
else
@@ -746,6 +752,41 @@ static const struct net_device_ops xgene_ndev_ops = {
.ndo_set_mac_address = xgene_enet_set_mac_address,
};
+static int xgene_get_mac_address(struct device *dev,
+ unsigned char *addr)
+{
+ int ret;
+
+ ret = device_property_read_u8_array(dev, "local-mac-address", addr, 6);
+ if (ret)
+ ret = device_property_read_u8_array(dev, "mac-address",
+ addr, 6);
+ if (ret)
+ return -ENODEV;
+
+ return ETH_ALEN;
+}
+
+static int xgene_get_phy_mode(struct device *dev)
+{
+ int i, ret;
+ char *modestr;
+
+ ret = device_property_read_string(dev, "phy-connection-type",
+ (const char **)&modestr);
+ if (ret)
+ ret = device_property_read_string(dev, "phy-mode",
+ (const char **)&modestr);
+ if (ret)
+ return -ENODEV;
+
+ for (i = 0; i < PHY_INTERFACE_MODE_MAX; i++) {
+ if (!strcasecmp(modestr, phy_modes(i)))
+ return i;
+ }
+ return -ENODEV;
+}
+
static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
{
struct platform_device *pdev;
@@ -753,32 +794,45 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
struct device *dev;
struct resource *res;
void __iomem *base_addr;
- const char *mac;
int ret;
pdev = pdata->pdev;
dev = &pdev->dev;
ndev = pdata->ndev;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "enet_csr");
- pdata->base_addr = devm_ioremap_resource(dev, res);
- if (IS_ERR(pdata->base_addr)) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, RES_ENET_CSR);
+ if (!res) {
+ dev_err(dev, "Resource enet_csr not defined\n");
+ return -ENODEV;
+ }
+ pdata->base_addr = devm_ioremap(dev, res->start, resource_size(res));
+ if (!pdata->base_addr) {
dev_err(dev, "Unable to retrieve ENET Port CSR region\n");
- return PTR_ERR(pdata->base_addr);
+ return -ENOMEM;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_csr");
- pdata->ring_csr_addr = devm_ioremap_resource(dev, res);
- if (IS_ERR(pdata->ring_csr_addr)) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CSR);
+ if (!res) {
+ dev_err(dev, "Resource ring_csr not defined\n");
+ return -ENODEV;
+ }
+ pdata->ring_csr_addr = devm_ioremap(dev, res->start,
+ resource_size(res));
+ if (!pdata->ring_csr_addr) {
dev_err(dev, "Unable to retrieve ENET Ring CSR region\n");
- return PTR_ERR(pdata->ring_csr_addr);
+ return -ENOMEM;
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ring_cmd");
- pdata->ring_cmd_addr = devm_ioremap_resource(dev, res);
- if (IS_ERR(pdata->ring_cmd_addr)) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, RES_RING_CMD);
+ if (!res) {
+ dev_err(dev, "Resource ring_cmd not defined\n");
+ return -ENODEV;
+ }
+ pdata->ring_cmd_addr = devm_ioremap(dev, res->start,
+ resource_size(res));
+ if (!pdata->ring_cmd_addr) {
dev_err(dev, "Unable to retrieve ENET Ring command region\n");
- return PTR_ERR(pdata->ring_cmd_addr);
+ return -ENOMEM;
}
ret = platform_get_irq(pdev, 0);
@@ -789,14 +843,12 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
}
pdata->rx_irq = ret;
- mac = of_get_mac_address(dev->of_node);
- if (mac)
- memcpy(ndev->dev_addr, mac, ndev->addr_len);
- else
+ if (xgene_get_mac_address(dev, ndev->dev_addr) != ETH_ALEN)
eth_hw_addr_random(ndev);
+
memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
- pdata->phy_mode = of_get_phy_mode(pdev->dev.of_node);
+ pdata->phy_mode = xgene_get_phy_mode(dev);
if (pdata->phy_mode < 0) {
dev_err(dev, "Unable to get phy-connection-type\n");
return pdata->phy_mode;
@@ -809,11 +861,9 @@ static int xgene_enet_get_resources(struct xgene_enet_pdata *pdata)
}
pdata->clk = devm_clk_get(&pdev->dev, NULL);
- ret = IS_ERR(pdata->clk);
if (IS_ERR(pdata->clk)) {
- dev_err(&pdev->dev, "can't get clock\n");
- ret = PTR_ERR(pdata->clk);
- return ret;
+ /* Firmware may have set up the clock already. */
+ pdata->clk = NULL;
}
base_addr = pdata->base_addr;
@@ -924,7 +974,7 @@ static int xgene_enet_probe(struct platform_device *pdev)
goto err;
}
- ret = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ ret = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(64));
if (ret) {
netdev_err(ndev, "No usable DMA configuration\n");
goto err;
@@ -972,17 +1022,28 @@ static int xgene_enet_remove(struct platform_device *pdev)
return 0;
}
-static struct of_device_id xgene_enet_match[] = {
+#ifdef CONFIG_ACPI
+static const struct acpi_device_id xgene_enet_acpi_match[] = {
+ { "APMC0D05", },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, xgene_enet_acpi_match);
+#endif
+
+#ifdef CONFIG_OF
+static struct of_device_id xgene_enet_of_match[] = {
{.compatible = "apm,xgene-enet",},
{},
};
-MODULE_DEVICE_TABLE(of, xgene_enet_match);
+MODULE_DEVICE_TABLE(of, xgene_enet_of_match);
+#endif
static struct platform_driver xgene_enet_driver = {
.driver = {
.name = "xgene-enet",
- .of_match_table = xgene_enet_match,
+ .of_match_table = of_match_ptr(xgene_enet_of_match),
+ .acpi_match_table = ACPI_PTR(xgene_enet_acpi_match),
},
.probe = xgene_enet_probe,
.remove = xgene_enet_remove,
diff --git a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
index f9958fae6ffd..c2d465c3db66 100644
--- a/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
+++ b/drivers/net/ethernet/apm/xgene/xgene_enet_main.h
@@ -22,7 +22,10 @@
#ifndef __XGENE_ENET_MAIN_H__
#define __XGENE_ENET_MAIN_H__
+#include <linux/acpi.h>
#include <linux/clk.h>
+#include <linux/efi.h>
+#include <linux/io.h>
#include <linux/of_platform.h>
#include <linux/of_net.h>
#include <linux/of_mdio.h>
diff --git a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
index c9946c6c119e..587f63e87588 100644
--- a/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
+++ b/drivers/net/ethernet/atheros/atl1c/atl1c_main.c
@@ -2235,8 +2235,8 @@ static netdev_tx_t atl1c_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_OK;
}
- if (unlikely(vlan_tx_tag_present(skb))) {
- u16 vlan = vlan_tx_tag_get(skb);
+ if (unlikely(skb_vlan_tag_present(skb))) {
+ u16 vlan = skb_vlan_tag_get(skb);
__le16 tag;
vlan = cpu_to_le16(vlan);
diff --git a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
index 2326579f9454..59a03a193e83 100644
--- a/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
+++ b/drivers/net/ethernet/atheros/atl1e/atl1e_main.c
@@ -1892,8 +1892,8 @@ static netdev_tx_t atl1e_xmit_frame(struct sk_buff *skb,
tpd = atl1e_get_tpd(adapter);
- if (vlan_tx_tag_present(skb)) {
- u16 vlan_tag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb)) {
+ u16 vlan_tag = skb_vlan_tag_get(skb);
u16 atl1e_vlan_tag;
tpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT;
@@ -2373,9 +2373,8 @@ static int atl1e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
netif_napi_add(netdev, &adapter->napi, atl1e_clean, 64);
- init_timer(&adapter->phy_config_timer);
- adapter->phy_config_timer.function = atl1e_phy_config;
- adapter->phy_config_timer.data = (unsigned long) adapter;
+ setup_timer(&adapter->phy_config_timer, atl1e_phy_config,
+ (unsigned long)adapter);
/* get user settings */
atl1e_check_options(adapter);
diff --git a/drivers/net/ethernet/atheros/atlx/atl1.c b/drivers/net/ethernet/atheros/atlx/atl1.c
index 2c8f398aeda9..eca1d113fee1 100644
--- a/drivers/net/ethernet/atheros/atlx/atl1.c
+++ b/drivers/net/ethernet/atheros/atlx/atl1.c
@@ -2415,8 +2415,8 @@ static netdev_tx_t atl1_xmit_frame(struct sk_buff *skb,
(u16) atomic_read(&tpd_ring->next_to_use));
memset(ptpd, 0, sizeof(struct tx_packet_desc));
- if (vlan_tx_tag_present(skb)) {
- vlan_tag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb)) {
+ vlan_tag = skb_vlan_tag_get(skb);
vlan_tag = (vlan_tag << 4) | (vlan_tag >> 13) |
((vlan_tag >> 9) & 0x8);
ptpd->word3 |= 1 << TPD_INS_VL_TAG_SHIFT;
diff --git a/drivers/net/ethernet/atheros/atlx/atl2.c b/drivers/net/ethernet/atheros/atlx/atl2.c
index 84a09e8ddd9c..46a535318c7a 100644
--- a/drivers/net/ethernet/atheros/atlx/atl2.c
+++ b/drivers/net/ethernet/atheros/atlx/atl2.c
@@ -887,8 +887,8 @@ static netdev_tx_t atl2_xmit_frame(struct sk_buff *skb,
offset = ((u32)(skb->len-copy_len + 3) & ~3);
}
#ifdef NETIF_F_HW_VLAN_CTAG_TX
- if (vlan_tx_tag_present(skb)) {
- u16 vlan_tag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb)) {
+ u16 vlan_tag = skb_vlan_tag_get(skb);
vlan_tag = (vlan_tag << 4) |
(vlan_tag >> 13) |
((vlan_tag >> 9) & 0x8);
@@ -1436,13 +1436,11 @@ static int atl2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
atl2_check_options(adapter);
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = atl2_watchdog;
- adapter->watchdog_timer.data = (unsigned long) adapter;
+ setup_timer(&adapter->watchdog_timer, atl2_watchdog,
+ (unsigned long)adapter);
- init_timer(&adapter->phy_config_timer);
- adapter->phy_config_timer.function = atl2_phy_config;
- adapter->phy_config_timer.data = (unsigned long) adapter;
+ setup_timer(&adapter->phy_config_timer, atl2_phy_config,
+ (unsigned long)adapter);
INIT_WORK(&adapter->reset_task, atl2_reset_task);
INIT_WORK(&adapter->link_chg_task, atl2_link_chg_task);
diff --git a/drivers/net/ethernet/broadcom/b44.c b/drivers/net/ethernet/broadcom/b44.c
index d86d6baf9681..bd5916a60cb5 100644
--- a/drivers/net/ethernet/broadcom/b44.c
+++ b/drivers/net/ethernet/broadcom/b44.c
@@ -121,7 +121,7 @@ static struct pci_driver b44_pci_driver = {
static const struct ssb_device_id b44_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET, SSB_ANY_REV),
- SSB_DEVTABLE_END
+ {},
};
MODULE_DEVICE_TABLE(ssb, b44_ssb_tbl);
diff --git a/drivers/net/ethernet/broadcom/bgmac.c b/drivers/net/ethernet/broadcom/bgmac.c
index 3007d95fbb9f..676ffe093180 100644
--- a/drivers/net/ethernet/broadcom/bgmac.c
+++ b/drivers/net/ethernet/broadcom/bgmac.c
@@ -21,7 +21,7 @@
static const struct bcma_device_id bgmac_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_4706_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_MAC_GBIT, BCMA_ANY_REV, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
+ {},
};
MODULE_DEVICE_TABLE(bcma, bgmac_bcma_tbl);
@@ -1412,6 +1412,7 @@ static void bgmac_mii_unregister(struct bgmac *bgmac)
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipattach */
static int bgmac_probe(struct bcma_device *core)
{
+ struct bcma_chipinfo *ci = &core->bus->chipinfo;
struct net_device *net_dev;
struct bgmac *bgmac;
struct ssb_sprom *sprom = &core->bus->sprom;
@@ -1474,8 +1475,8 @@ static int bgmac_probe(struct bcma_device *core)
bgmac_chip_reset(bgmac);
/* For Northstar, we have to take all GMAC core out of reset */
- if (core->id.id == BCMA_CHIP_ID_BCM4707 ||
- core->id.id == BCMA_CHIP_ID_BCM53018) {
+ if (ci->id == BCMA_CHIP_ID_BCM4707 ||
+ ci->id == BCMA_CHIP_ID_BCM53018) {
struct bcma_device *ns_core;
int ns_gmac;
diff --git a/drivers/net/ethernet/broadcom/bnx2.c b/drivers/net/ethernet/broadcom/bnx2.c
index 823d01c5684c..02bf0b86995b 100644
--- a/drivers/net/ethernet/broadcom/bnx2.c
+++ b/drivers/net/ethernet/broadcom/bnx2.c
@@ -6597,9 +6597,9 @@ bnx2_start_xmit(struct sk_buff *skb, struct net_device *dev)
vlan_tag_flags |= TX_BD_FLAGS_TCP_UDP_CKSUM;
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
vlan_tag_flags |=
- (TX_BD_FLAGS_VLAN_TAG | (vlan_tx_tag_get(skb) << 16));
+ (TX_BD_FLAGS_VLAN_TAG | (skb_vlan_tag_get(skb) << 16));
}
if ((mss = skb_shinfo(skb)->gso_size)) {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
index c3a6072134f5..756053c028be 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x.h
@@ -22,7 +22,7 @@
#include <linux/ptp_clock_kernel.h>
#include <linux/net_tstamp.h>
-#include <linux/clocksource.h>
+#include <linux/timecounter.h>
/* compilation time flags */
@@ -1138,12 +1138,8 @@ struct bnx2x_port {
u32 link_config[LINK_CONFIG_SIZE];
u32 supported[LINK_CONFIG_SIZE];
-/* link settings - missing defines */
-#define SUPPORTED_2500baseX_Full (1 << 15)
u32 advertising[LINK_CONFIG_SIZE];
-/* link settings - missing defines */
-#define ADVERTISED_2500baseX_Full (1 << 15)
u32 phy_addr;
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
index e468ed3f210f..0a9faa134a9a 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_cmn.c
@@ -3865,9 +3865,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
"sending pkt %u @%p next_idx %u bd %u @%p\n",
pkt_prod, tx_buf, txdata->tx_pkt_prod, bd_prod, tx_start_bd);
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
tx_start_bd->vlan_or_ethertype =
- cpu_to_le16(vlan_tx_tag_get(skb));
+ cpu_to_le16(skb_vlan_tag_get(skb));
tx_start_bd->bd_flags.as_bitfield |=
(X_ETH_OUTBAND_VLAN << ETH_TX_BD_FLAGS_VLAN_MODE_SHIFT);
} else {
diff --git a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
index 72eef9fc883e..7155e1d2c208 100644
--- a/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
+++ b/drivers/net/ethernet/broadcom/bnx2x/bnx2x_main.c
@@ -9169,7 +9169,7 @@ static void bnx2x_disable_ptp(struct bnx2x *bp)
}
/* Called during unload, to stop PTP-related stuff */
-void bnx2x_stop_ptp(struct bnx2x *bp)
+static void bnx2x_stop_ptp(struct bnx2x *bp)
{
/* Cancel PTP work queue. Should be done after the Tx queues are
* drained to prevent additional scheduling.
@@ -13267,14 +13267,10 @@ static int bnx2x_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
static int bnx2x_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
struct bnx2x *bp = container_of(ptp, struct bnx2x, ptp_clock_info);
- u64 now;
DP(BNX2X_MSG_PTP, "PTP adjtime called, delta = %llx\n", delta);
- now = timecounter_read(&bp->timecounter);
- now += delta;
- /* Re-init the timecounter */
- timecounter_init(&bp->timecounter, &bp->cyclecounter, now);
+ timecounter_adjtime(&bp->timecounter, delta);
return 0;
}
@@ -13322,7 +13318,7 @@ static int bnx2x_ptp_enable(struct ptp_clock_info *ptp,
return -ENOTSUPP;
}
-void bnx2x_register_phc(struct bnx2x *bp)
+static void bnx2x_register_phc(struct bnx2x *bp)
{
/* Fill the ptp_clock_info struct and register PTP clock*/
bp->ptp_clock_info.owner = THIS_MODULE;
@@ -14614,7 +14610,7 @@ static void bnx2x_init_cyclecounter(struct bnx2x *bp)
{
memset(&bp->cyclecounter, 0, sizeof(bp->cyclecounter));
bp->cyclecounter.read = bnx2x_cyclecounter_read;
- bp->cyclecounter.mask = CLOCKSOURCE_MASK(64);
+ bp->cyclecounter.mask = CYCLECOUNTER_MASK(64);
bp->cyclecounter.shift = 1;
bp->cyclecounter.mult = 1;
}
@@ -14639,7 +14635,7 @@ static int bnx2x_send_reset_timesync_ramrod(struct bnx2x *bp)
return bnx2x_func_state_change(bp, &func_params);
}
-int bnx2x_enable_ptp_packets(struct bnx2x *bp)
+static int bnx2x_enable_ptp_packets(struct bnx2x *bp)
{
struct bnx2x_queue_state_params q_params;
int rc, i;
diff --git a/drivers/net/ethernet/broadcom/tg3.c b/drivers/net/ethernet/broadcom/tg3.c
index 96bf01ba32dd..23a019cee279 100644
--- a/drivers/net/ethernet/broadcom/tg3.c
+++ b/drivers/net/ethernet/broadcom/tg3.c
@@ -8008,9 +8008,9 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
!mss && skb->len > VLAN_ETH_FRAME_LEN)
base_flags |= TXD_FLAG_JMB_PKT;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
base_flags |= TXD_FLAG_VLAN;
- vlan = vlan_tx_tag_get(skb);
+ vlan = skb_vlan_tag_get(skb);
}
if ((unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP)) &&
@@ -11573,11 +11573,7 @@ static int tg3_start(struct tg3 *tp, bool reset_phy, bool test_irq,
tg3_flag_set(tp, INIT_COMPLETE);
tg3_enable_ints(tp);
- if (init)
- tg3_ptp_init(tp);
- else
- tg3_ptp_resume(tp);
-
+ tg3_ptp_resume(tp);
tg3_full_unlock(tp);
@@ -11698,13 +11694,6 @@ static int tg3_open(struct net_device *dev)
pci_set_power_state(tp->pdev, PCI_D3hot);
}
- if (tg3_flag(tp, PTP_CAPABLE)) {
- tp->ptp_clock = ptp_clock_register(&tp->ptp_info,
- &tp->pdev->dev);
- if (IS_ERR(tp->ptp_clock))
- tp->ptp_clock = NULL;
- }
-
return err;
}
@@ -11718,8 +11707,6 @@ static int tg3_close(struct net_device *dev)
return -EAGAIN;
}
- tg3_ptp_fini(tp);
-
tg3_stop(tp);
/* Clear stats across close / open calls */
@@ -17868,8 +17855,10 @@ static int tg3_init_one(struct pci_dev *pdev,
*/
if ((tr32(HOSTCC_MODE) & HOSTCC_MODE_ENABLE) ||
(tr32(WDMAC_MODE) & WDMAC_MODE_ENABLE)) {
+ tg3_full_lock(tp, 0);
tw32(MEMARB_MODE, MEMARB_MODE_ENABLE);
tg3_halt(tp, RESET_KIND_SHUTDOWN, 1);
+ tg3_full_unlock(tp);
}
err = tg3_test_dma(tp);
@@ -17897,6 +17886,14 @@ static int tg3_init_one(struct pci_dev *pdev,
goto err_out_apeunmap;
}
+ if (tg3_flag(tp, PTP_CAPABLE)) {
+ tg3_ptp_init(tp);
+ tp->ptp_clock = ptp_clock_register(&tp->ptp_info,
+ &tp->pdev->dev);
+ if (IS_ERR(tp->ptp_clock))
+ tp->ptp_clock = NULL;
+ }
+
netdev_info(dev, "Tigon3 [partno(%s) rev %04x] (%s) MAC address %pM\n",
tp->board_part_number,
tg3_chip_rev_id(tp),
@@ -17972,6 +17969,8 @@ static void tg3_remove_one(struct pci_dev *pdev)
if (dev) {
struct tg3 *tp = netdev_priv(dev);
+ tg3_ptp_fini(tp);
+
release_firmware(tp->fw);
tg3_reset_task_cancel(tp);
diff --git a/drivers/net/ethernet/brocade/bna/bnad.c b/drivers/net/ethernet/brocade/bna/bnad.c
index 323721838cf9..7714d7790089 100644
--- a/drivers/net/ethernet/brocade/bna/bnad.c
+++ b/drivers/net/ethernet/brocade/bna/bnad.c
@@ -2824,8 +2824,8 @@ bnad_txq_wi_prepare(struct bnad *bnad, struct bna_tcb *tcb,
u32 gso_size;
u16 vlan_tag = 0;
- if (vlan_tx_tag_present(skb)) {
- vlan_tag = (u16)vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb)) {
+ vlan_tag = (u16)skb_vlan_tag_get(skb);
flags |= (BNA_TXQ_WI_CF_INS_PRIO | BNA_TXQ_WI_CF_INS_VLAN);
}
if (test_bit(BNAD_RF_CEE_RUNNING, &bnad->run_flags)) {
diff --git a/drivers/net/ethernet/cadence/macb.c b/drivers/net/ethernet/cadence/macb.c
index 3767271c7667..ad76b8e35a00 100644
--- a/drivers/net/ethernet/cadence/macb.c
+++ b/drivers/net/ethernet/cadence/macb.c
@@ -1691,7 +1691,7 @@ static int hash_get_index(__u8 *addr)
for (j = 0; j < 6; j++) {
for (i = 0, bitval = 0; i < 8; i++)
- bitval ^= hash_bit_value(i*6 + j, addr);
+ bitval ^= hash_bit_value(i * 6 + j, addr);
hash_index |= (bitval << j);
}
@@ -1827,12 +1827,23 @@ static int macb_close(struct net_device *dev)
static void gem_update_stats(struct macb *bp)
{
- u32 __iomem *reg = bp->regs + GEM_OTX;
+ int i;
u32 *p = &bp->hw_stats.gem.tx_octets_31_0;
- u32 *end = &bp->hw_stats.gem.rx_udp_checksum_errors + 1;
- for (; p < end; p++, reg++)
- *p += __raw_readl(reg);
+ for (i = 0; i < GEM_STATS_LEN; ++i, ++p) {
+ u32 offset = gem_statistics[i].offset;
+ u64 val = __raw_readl(bp->regs + offset);
+
+ bp->ethtool_stats[i] += val;
+ *p += val;
+
+ if (offset == GEM_OCTTXL || offset == GEM_OCTRXL) {
+ /* Add GEM_OCTTXH, GEM_OCTRXH */
+ val = __raw_readl(bp->regs + offset + 4);
+ bp->ethtool_stats[i] += ((u64)val) << 32;
+ *(++p) += val;
+ }
+ }
}
static struct net_device_stats *gem_get_stats(struct macb *bp)
@@ -1873,6 +1884,39 @@ static struct net_device_stats *gem_get_stats(struct macb *bp)
return nstat;
}
+static void gem_get_ethtool_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct macb *bp;
+
+ bp = netdev_priv(dev);
+ gem_update_stats(bp);
+ memcpy(data, &bp->ethtool_stats, sizeof(u64) * GEM_STATS_LEN);
+}
+
+static int gem_get_sset_count(struct net_device *dev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return GEM_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
+static void gem_get_ethtool_strings(struct net_device *dev, u32 sset, u8 *p)
+{
+ int i;
+
+ switch (sset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < GEM_STATS_LEN; i++, p += ETH_GSTRING_LEN)
+ memcpy(p, gem_statistics[i].stat_string,
+ ETH_GSTRING_LEN);
+ break;
+ }
+}
+
struct net_device_stats *macb_get_stats(struct net_device *dev)
{
struct macb *bp = netdev_priv(dev);
@@ -1991,6 +2035,18 @@ const struct ethtool_ops macb_ethtool_ops = {
};
EXPORT_SYMBOL_GPL(macb_ethtool_ops);
+static const struct ethtool_ops gem_ethtool_ops = {
+ .get_settings = macb_get_settings,
+ .set_settings = macb_set_settings,
+ .get_regs_len = macb_get_regs_len,
+ .get_regs = macb_get_regs,
+ .get_link = ethtool_op_get_link,
+ .get_ts_info = ethtool_op_get_ts_info,
+ .get_ethtool_stats = gem_get_ethtool_stats,
+ .get_strings = gem_get_ethtool_strings,
+ .get_sset_count = gem_get_sset_count,
+};
+
int macb_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
{
struct macb *bp = netdev_priv(dev);
@@ -2148,7 +2204,7 @@ static void macb_probe_queues(void __iomem *mem,
(*num_queues)++;
}
-static int __init macb_probe(struct platform_device *pdev)
+static int macb_probe(struct platform_device *pdev)
{
struct macb_platform_data *pdata;
struct resource *regs;
@@ -2278,7 +2334,6 @@ static int __init macb_probe(struct platform_device *pdev)
dev->netdev_ops = &macb_netdev_ops;
netif_napi_add(dev, &bp->napi, macb_poll, 64);
- dev->ethtool_ops = &macb_ethtool_ops;
dev->base_addr = regs->start;
@@ -2292,12 +2347,14 @@ static int __init macb_probe(struct platform_device *pdev)
bp->macbgem_ops.mog_free_rx_buffers = gem_free_rx_buffers;
bp->macbgem_ops.mog_init_rings = gem_init_rings;
bp->macbgem_ops.mog_rx = gem_rx;
+ dev->ethtool_ops = &gem_ethtool_ops;
} else {
bp->max_tx_length = MACB_MAX_TX_LEN;
bp->macbgem_ops.mog_alloc_rx_buffers = macb_alloc_rx_buffers;
bp->macbgem_ops.mog_free_rx_buffers = macb_free_rx_buffers;
bp->macbgem_ops.mog_init_rings = macb_init_rings;
bp->macbgem_ops.mog_rx = macb_rx;
+ dev->ethtool_ops = &macb_ethtool_ops;
}
/* Set features */
@@ -2386,7 +2443,7 @@ err_out:
return err;
}
-static int __exit macb_remove(struct platform_device *pdev)
+static int macb_remove(struct platform_device *pdev)
{
struct net_device *dev;
struct macb *bp;
@@ -2411,8 +2468,7 @@ static int __exit macb_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
-static int macb_suspend(struct device *dev)
+static int __maybe_unused macb_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct net_device *netdev = platform_get_drvdata(pdev);
@@ -2429,7 +2485,7 @@ static int macb_suspend(struct device *dev)
return 0;
}
-static int macb_resume(struct device *dev)
+static int __maybe_unused macb_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct net_device *netdev = platform_get_drvdata(pdev);
@@ -2444,12 +2500,12 @@ static int macb_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(macb_pm_ops, macb_suspend, macb_resume);
static struct platform_driver macb_driver = {
- .remove = __exit_p(macb_remove),
+ .probe = macb_probe,
+ .remove = macb_remove,
.driver = {
.name = "macb",
.of_match_table = of_match_ptr(macb_dt_ids),
@@ -2457,7 +2513,7 @@ static struct platform_driver macb_driver = {
},
};
-module_platform_driver_probe(macb_driver, macb_probe);
+module_platform_driver(macb_driver);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cadence MACB/GEM Ethernet driver");
diff --git a/drivers/net/ethernet/cadence/macb.h b/drivers/net/ethernet/cadence/macb.h
index 084191b6fad2..31dc080f2437 100644
--- a/drivers/net/ethernet/cadence/macb.h
+++ b/drivers/net/ethernet/cadence/macb.h
@@ -15,263 +15,309 @@
#define MACB_MAX_QUEUES 8
/* MACB register offsets */
-#define MACB_NCR 0x0000
-#define MACB_NCFGR 0x0004
-#define MACB_NSR 0x0008
-#define MACB_TAR 0x000c /* AT91RM9200 only */
-#define MACB_TCR 0x0010 /* AT91RM9200 only */
-#define MACB_TSR 0x0014
-#define MACB_RBQP 0x0018
-#define MACB_TBQP 0x001c
-#define MACB_RSR 0x0020
-#define MACB_ISR 0x0024
-#define MACB_IER 0x0028
-#define MACB_IDR 0x002c
-#define MACB_IMR 0x0030
-#define MACB_MAN 0x0034
-#define MACB_PTR 0x0038
-#define MACB_PFR 0x003c
-#define MACB_FTO 0x0040
-#define MACB_SCF 0x0044
-#define MACB_MCF 0x0048
-#define MACB_FRO 0x004c
-#define MACB_FCSE 0x0050
-#define MACB_ALE 0x0054
-#define MACB_DTF 0x0058
-#define MACB_LCOL 0x005c
-#define MACB_EXCOL 0x0060
-#define MACB_TUND 0x0064
-#define MACB_CSE 0x0068
-#define MACB_RRE 0x006c
-#define MACB_ROVR 0x0070
-#define MACB_RSE 0x0074
-#define MACB_ELE 0x0078
-#define MACB_RJA 0x007c
-#define MACB_USF 0x0080
-#define MACB_STE 0x0084
-#define MACB_RLE 0x0088
-#define MACB_TPF 0x008c
-#define MACB_HRB 0x0090
-#define MACB_HRT 0x0094
-#define MACB_SA1B 0x0098
-#define MACB_SA1T 0x009c
-#define MACB_SA2B 0x00a0
-#define MACB_SA2T 0x00a4
-#define MACB_SA3B 0x00a8
-#define MACB_SA3T 0x00ac
-#define MACB_SA4B 0x00b0
-#define MACB_SA4T 0x00b4
-#define MACB_TID 0x00b8
-#define MACB_TPQ 0x00bc
-#define MACB_USRIO 0x00c0
-#define MACB_WOL 0x00c4
-#define MACB_MID 0x00fc
+#define MACB_NCR 0x0000 /* Network Control */
+#define MACB_NCFGR 0x0004 /* Network Config */
+#define MACB_NSR 0x0008 /* Network Status */
+#define MACB_TAR 0x000c /* AT91RM9200 only */
+#define MACB_TCR 0x0010 /* AT91RM9200 only */
+#define MACB_TSR 0x0014 /* Transmit Status */
+#define MACB_RBQP 0x0018 /* RX Q Base Address */
+#define MACB_TBQP 0x001c /* TX Q Base Address */
+#define MACB_RSR 0x0020 /* Receive Status */
+#define MACB_ISR 0x0024 /* Interrupt Status */
+#define MACB_IER 0x0028 /* Interrupt Enable */
+#define MACB_IDR 0x002c /* Interrupt Disable */
+#define MACB_IMR 0x0030 /* Interrupt Mask */
+#define MACB_MAN 0x0034 /* PHY Maintenance */
+#define MACB_PTR 0x0038
+#define MACB_PFR 0x003c
+#define MACB_FTO 0x0040
+#define MACB_SCF 0x0044
+#define MACB_MCF 0x0048
+#define MACB_FRO 0x004c
+#define MACB_FCSE 0x0050
+#define MACB_ALE 0x0054
+#define MACB_DTF 0x0058
+#define MACB_LCOL 0x005c
+#define MACB_EXCOL 0x0060
+#define MACB_TUND 0x0064
+#define MACB_CSE 0x0068
+#define MACB_RRE 0x006c
+#define MACB_ROVR 0x0070
+#define MACB_RSE 0x0074
+#define MACB_ELE 0x0078
+#define MACB_RJA 0x007c
+#define MACB_USF 0x0080
+#define MACB_STE 0x0084
+#define MACB_RLE 0x0088
+#define MACB_TPF 0x008c
+#define MACB_HRB 0x0090
+#define MACB_HRT 0x0094
+#define MACB_SA1B 0x0098
+#define MACB_SA1T 0x009c
+#define MACB_SA2B 0x00a0
+#define MACB_SA2T 0x00a4
+#define MACB_SA3B 0x00a8
+#define MACB_SA3T 0x00ac
+#define MACB_SA4B 0x00b0
+#define MACB_SA4T 0x00b4
+#define MACB_TID 0x00b8
+#define MACB_TPQ 0x00bc
+#define MACB_USRIO 0x00c0
+#define MACB_WOL 0x00c4
+#define MACB_MID 0x00fc
/* GEM register offsets. */
-#define GEM_NCFGR 0x0004
-#define GEM_USRIO 0x000c
-#define GEM_DMACFG 0x0010
-#define GEM_HRB 0x0080
-#define GEM_HRT 0x0084
-#define GEM_SA1B 0x0088
-#define GEM_SA1T 0x008C
-#define GEM_SA2B 0x0090
-#define GEM_SA2T 0x0094
-#define GEM_SA3B 0x0098
-#define GEM_SA3T 0x009C
-#define GEM_SA4B 0x00A0
-#define GEM_SA4T 0x00A4
-#define GEM_OTX 0x0100
-#define GEM_DCFG1 0x0280
-#define GEM_DCFG2 0x0284
-#define GEM_DCFG3 0x0288
-#define GEM_DCFG4 0x028c
-#define GEM_DCFG5 0x0290
-#define GEM_DCFG6 0x0294
-#define GEM_DCFG7 0x0298
-
-#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2))
-#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
-#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2))
-#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2))
-#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
-#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
+#define GEM_NCFGR 0x0004 /* Network Config */
+#define GEM_USRIO 0x000c /* User IO */
+#define GEM_DMACFG 0x0010 /* DMA Configuration */
+#define GEM_HRB 0x0080 /* Hash Bottom */
+#define GEM_HRT 0x0084 /* Hash Top */
+#define GEM_SA1B 0x0088 /* Specific1 Bottom */
+#define GEM_SA1T 0x008C /* Specific1 Top */
+#define GEM_SA2B 0x0090 /* Specific2 Bottom */
+#define GEM_SA2T 0x0094 /* Specific2 Top */
+#define GEM_SA3B 0x0098 /* Specific3 Bottom */
+#define GEM_SA3T 0x009C /* Specific3 Top */
+#define GEM_SA4B 0x00A0 /* Specific4 Bottom */
+#define GEM_SA4T 0x00A4 /* Specific4 Top */
+#define GEM_OTX 0x0100 /* Octets transmitted */
+#define GEM_OCTTXL 0x0100 /* Octets transmitted [31:0] */
+#define GEM_OCTTXH 0x0104 /* Octets transmitted [47:32] */
+#define GEM_TXCNT 0x0108 /* Frames Transmitted counter */
+#define GEM_TXBCCNT 0x010c /* Broadcast Frames counter */
+#define GEM_TXMCCNT 0x0110 /* Multicast Frames counter */
+#define GEM_TXPAUSECNT 0x0114 /* Pause Frames Transmitted Counter */
+#define GEM_TX64CNT 0x0118 /* 64 byte Frames TX counter */
+#define GEM_TX65CNT 0x011c /* 65-127 byte Frames TX counter */
+#define GEM_TX128CNT 0x0120 /* 128-255 byte Frames TX counter */
+#define GEM_TX256CNT 0x0124 /* 256-511 byte Frames TX counter */
+#define GEM_TX512CNT 0x0128 /* 512-1023 byte Frames TX counter */
+#define GEM_TX1024CNT 0x012c /* 1024-1518 byte Frames TX counter */
+#define GEM_TX1519CNT 0x0130 /* 1519+ byte Frames TX counter */
+#define GEM_TXURUNCNT 0x0134 /* TX under run error counter */
+#define GEM_SNGLCOLLCNT 0x0138 /* Single Collision Frame Counter */
+#define GEM_MULTICOLLCNT 0x013c /* Multiple Collision Frame Counter */
+#define GEM_EXCESSCOLLCNT 0x0140 /* Excessive Collision Frame Counter */
+#define GEM_LATECOLLCNT 0x0144 /* Late Collision Frame Counter */
+#define GEM_TXDEFERCNT 0x0148 /* Deferred Transmission Frame Counter */
+#define GEM_TXCSENSECNT 0x014c /* Carrier Sense Error Counter */
+#define GEM_ORX 0x0150 /* Octets received */
+#define GEM_OCTRXL 0x0150 /* Octets received [31:0] */
+#define GEM_OCTRXH 0x0154 /* Octets received [47:32] */
+#define GEM_RXCNT 0x0158 /* Frames Received Counter */
+#define GEM_RXBROADCNT 0x015c /* Broadcast Frames Received Counter */
+#define GEM_RXMULTICNT 0x0160 /* Multicast Frames Received Counter */
+#define GEM_RXPAUSECNT 0x0164 /* Pause Frames Received Counter */
+#define GEM_RX64CNT 0x0168 /* 64 byte Frames RX Counter */
+#define GEM_RX65CNT 0x016c /* 65-127 byte Frames RX Counter */
+#define GEM_RX128CNT 0x0170 /* 128-255 byte Frames RX Counter */
+#define GEM_RX256CNT 0x0174 /* 256-511 byte Frames RX Counter */
+#define GEM_RX512CNT 0x0178 /* 512-1023 byte Frames RX Counter */
+#define GEM_RX1024CNT 0x017c /* 1024-1518 byte Frames RX Counter */
+#define GEM_RX1519CNT 0x0180 /* 1519+ byte Frames RX Counter */
+#define GEM_RXUNDRCNT 0x0184 /* Undersize Frames Received Counter */
+#define GEM_RXOVRCNT 0x0188 /* Oversize Frames Received Counter */
+#define GEM_RXJABCNT 0x018c /* Jabbers Received Counter */
+#define GEM_RXFCSCNT 0x0190 /* Frame Check Sequence Error Counter */
+#define GEM_RXLENGTHCNT 0x0194 /* Length Field Error Counter */
+#define GEM_RXSYMBCNT 0x0198 /* Symbol Error Counter */
+#define GEM_RXALIGNCNT 0x019c /* Alignment Error Counter */
+#define GEM_RXRESERRCNT 0x01a0 /* Receive Resource Error Counter */
+#define GEM_RXORCNT 0x01a4 /* Receive Overrun Counter */
+#define GEM_RXIPCCNT 0x01a8 /* IP header Checksum Error Counter */
+#define GEM_RXTCPCCNT 0x01ac /* TCP Checksum Error Counter */
+#define GEM_RXUDPCCNT 0x01b0 /* UDP Checksum Error Counter */
+#define GEM_DCFG1 0x0280 /* Design Config 1 */
+#define GEM_DCFG2 0x0284 /* Design Config 2 */
+#define GEM_DCFG3 0x0288 /* Design Config 3 */
+#define GEM_DCFG4 0x028c /* Design Config 4 */
+#define GEM_DCFG5 0x0290 /* Design Config 5 */
+#define GEM_DCFG6 0x0294 /* Design Config 6 */
+#define GEM_DCFG7 0x0298 /* Design Config 7 */
+
+#define GEM_ISR(hw_q) (0x0400 + ((hw_q) << 2))
+#define GEM_TBQP(hw_q) (0x0440 + ((hw_q) << 2))
+#define GEM_RBQP(hw_q) (0x0480 + ((hw_q) << 2))
+#define GEM_IER(hw_q) (0x0600 + ((hw_q) << 2))
+#define GEM_IDR(hw_q) (0x0620 + ((hw_q) << 2))
+#define GEM_IMR(hw_q) (0x0640 + ((hw_q) << 2))
/* Bitfields in NCR */
-#define MACB_LB_OFFSET 0
-#define MACB_LB_SIZE 1
-#define MACB_LLB_OFFSET 1
-#define MACB_LLB_SIZE 1
-#define MACB_RE_OFFSET 2
-#define MACB_RE_SIZE 1
-#define MACB_TE_OFFSET 3
-#define MACB_TE_SIZE 1
-#define MACB_MPE_OFFSET 4
-#define MACB_MPE_SIZE 1
-#define MACB_CLRSTAT_OFFSET 5
-#define MACB_CLRSTAT_SIZE 1
-#define MACB_INCSTAT_OFFSET 6
-#define MACB_INCSTAT_SIZE 1
-#define MACB_WESTAT_OFFSET 7
-#define MACB_WESTAT_SIZE 1
-#define MACB_BP_OFFSET 8
-#define MACB_BP_SIZE 1
-#define MACB_TSTART_OFFSET 9
-#define MACB_TSTART_SIZE 1
-#define MACB_THALT_OFFSET 10
-#define MACB_THALT_SIZE 1
-#define MACB_NCR_TPF_OFFSET 11
-#define MACB_NCR_TPF_SIZE 1
-#define MACB_TZQ_OFFSET 12
-#define MACB_TZQ_SIZE 1
+#define MACB_LB_OFFSET 0 /* reserved */
+#define MACB_LB_SIZE 1
+#define MACB_LLB_OFFSET 1 /* Loop back local */
+#define MACB_LLB_SIZE 1
+#define MACB_RE_OFFSET 2 /* Receive enable */
+#define MACB_RE_SIZE 1
+#define MACB_TE_OFFSET 3 /* Transmit enable */
+#define MACB_TE_SIZE 1
+#define MACB_MPE_OFFSET 4 /* Management port enable */
+#define MACB_MPE_SIZE 1
+#define MACB_CLRSTAT_OFFSET 5 /* Clear stats regs */
+#define MACB_CLRSTAT_SIZE 1
+#define MACB_INCSTAT_OFFSET 6 /* Incremental stats regs */
+#define MACB_INCSTAT_SIZE 1
+#define MACB_WESTAT_OFFSET 7 /* Write enable stats regs */
+#define MACB_WESTAT_SIZE 1
+#define MACB_BP_OFFSET 8 /* Back pressure */
+#define MACB_BP_SIZE 1
+#define MACB_TSTART_OFFSET 9 /* Start transmission */
+#define MACB_TSTART_SIZE 1
+#define MACB_THALT_OFFSET 10 /* Transmit halt */
+#define MACB_THALT_SIZE 1
+#define MACB_NCR_TPF_OFFSET 11 /* Transmit pause frame */
+#define MACB_NCR_TPF_SIZE 1
+#define MACB_TZQ_OFFSET 12 /* Transmit zero quantum pause frame */
+#define MACB_TZQ_SIZE 1
/* Bitfields in NCFGR */
-#define MACB_SPD_OFFSET 0
-#define MACB_SPD_SIZE 1
-#define MACB_FD_OFFSET 1
-#define MACB_FD_SIZE 1
-#define MACB_BIT_RATE_OFFSET 2
-#define MACB_BIT_RATE_SIZE 1
-#define MACB_JFRAME_OFFSET 3
-#define MACB_JFRAME_SIZE 1
-#define MACB_CAF_OFFSET 4
-#define MACB_CAF_SIZE 1
-#define MACB_NBC_OFFSET 5
-#define MACB_NBC_SIZE 1
-#define MACB_NCFGR_MTI_OFFSET 6
-#define MACB_NCFGR_MTI_SIZE 1
-#define MACB_UNI_OFFSET 7
-#define MACB_UNI_SIZE 1
-#define MACB_BIG_OFFSET 8
-#define MACB_BIG_SIZE 1
-#define MACB_EAE_OFFSET 9
-#define MACB_EAE_SIZE 1
-#define MACB_CLK_OFFSET 10
-#define MACB_CLK_SIZE 2
-#define MACB_RTY_OFFSET 12
-#define MACB_RTY_SIZE 1
-#define MACB_PAE_OFFSET 13
-#define MACB_PAE_SIZE 1
-#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */
-#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */
-#define MACB_RBOF_OFFSET 14
-#define MACB_RBOF_SIZE 2
-#define MACB_RLCE_OFFSET 16
-#define MACB_RLCE_SIZE 1
-#define MACB_DRFCS_OFFSET 17
-#define MACB_DRFCS_SIZE 1
-#define MACB_EFRHD_OFFSET 18
-#define MACB_EFRHD_SIZE 1
-#define MACB_IRXFCS_OFFSET 19
-#define MACB_IRXFCS_SIZE 1
+#define MACB_SPD_OFFSET 0 /* Speed */
+#define MACB_SPD_SIZE 1
+#define MACB_FD_OFFSET 1 /* Full duplex */
+#define MACB_FD_SIZE 1
+#define MACB_BIT_RATE_OFFSET 2 /* Discard non-VLAN frames */
+#define MACB_BIT_RATE_SIZE 1
+#define MACB_JFRAME_OFFSET 3 /* reserved */
+#define MACB_JFRAME_SIZE 1
+#define MACB_CAF_OFFSET 4 /* Copy all frames */
+#define MACB_CAF_SIZE 1
+#define MACB_NBC_OFFSET 5 /* No broadcast */
+#define MACB_NBC_SIZE 1
+#define MACB_NCFGR_MTI_OFFSET 6 /* Multicast hash enable */
+#define MACB_NCFGR_MTI_SIZE 1
+#define MACB_UNI_OFFSET 7 /* Unicast hash enable */
+#define MACB_UNI_SIZE 1
+#define MACB_BIG_OFFSET 8 /* Receive 1536 byte frames */
+#define MACB_BIG_SIZE 1
+#define MACB_EAE_OFFSET 9 /* External address match enable */
+#define MACB_EAE_SIZE 1
+#define MACB_CLK_OFFSET 10
+#define MACB_CLK_SIZE 2
+#define MACB_RTY_OFFSET 12 /* Retry test */
+#define MACB_RTY_SIZE 1
+#define MACB_PAE_OFFSET 13 /* Pause enable */
+#define MACB_PAE_SIZE 1
+#define MACB_RM9200_RMII_OFFSET 13 /* AT91RM9200 only */
+#define MACB_RM9200_RMII_SIZE 1 /* AT91RM9200 only */
+#define MACB_RBOF_OFFSET 14 /* Receive buffer offset */
+#define MACB_RBOF_SIZE 2
+#define MACB_RLCE_OFFSET 16 /* Length field error frame discard */
+#define MACB_RLCE_SIZE 1
+#define MACB_DRFCS_OFFSET 17 /* FCS remove */
+#define MACB_DRFCS_SIZE 1
+#define MACB_EFRHD_OFFSET 18
+#define MACB_EFRHD_SIZE 1
+#define MACB_IRXFCS_OFFSET 19
+#define MACB_IRXFCS_SIZE 1
/* GEM specific NCFGR bitfields. */
-#define GEM_GBE_OFFSET 10
-#define GEM_GBE_SIZE 1
-#define GEM_CLK_OFFSET 18
-#define GEM_CLK_SIZE 3
-#define GEM_DBW_OFFSET 21
-#define GEM_DBW_SIZE 2
-#define GEM_RXCOEN_OFFSET 24
-#define GEM_RXCOEN_SIZE 1
+#define GEM_GBE_OFFSET 10 /* Gigabit mode enable */
+#define GEM_GBE_SIZE 1
+#define GEM_CLK_OFFSET 18 /* MDC clock division */
+#define GEM_CLK_SIZE 3
+#define GEM_DBW_OFFSET 21 /* Data bus width */
+#define GEM_DBW_SIZE 2
+#define GEM_RXCOEN_OFFSET 24
+#define GEM_RXCOEN_SIZE 1
/* Constants for data bus width. */
-#define GEM_DBW32 0
-#define GEM_DBW64 1
-#define GEM_DBW128 2
+#define GEM_DBW32 0 /* 32 bit AMBA AHB data bus width */
+#define GEM_DBW64 1 /* 64 bit AMBA AHB data bus width */
+#define GEM_DBW128 2 /* 128 bit AMBA AHB data bus width */
/* Bitfields in DMACFG. */
-#define GEM_FBLDO_OFFSET 0
-#define GEM_FBLDO_SIZE 5
-#define GEM_ENDIA_OFFSET 7
-#define GEM_ENDIA_SIZE 1
-#define GEM_RXBMS_OFFSET 8
-#define GEM_RXBMS_SIZE 2
-#define GEM_TXPBMS_OFFSET 10
-#define GEM_TXPBMS_SIZE 1
-#define GEM_TXCOEN_OFFSET 11
-#define GEM_TXCOEN_SIZE 1
-#define GEM_RXBS_OFFSET 16
-#define GEM_RXBS_SIZE 8
-#define GEM_DDRP_OFFSET 24
-#define GEM_DDRP_SIZE 1
+#define GEM_FBLDO_OFFSET 0 /* fixed burst length for DMA */
+#define GEM_FBLDO_SIZE 5
+#define GEM_ENDIA_OFFSET 7 /* endian swap mode for packet data access */
+#define GEM_ENDIA_SIZE 1
+#define GEM_RXBMS_OFFSET 8 /* RX packet buffer memory size select */
+#define GEM_RXBMS_SIZE 2
+#define GEM_TXPBMS_OFFSET 10 /* TX packet buffer memory size select */
+#define GEM_TXPBMS_SIZE 1
+#define GEM_TXCOEN_OFFSET 11 /* TX IP/TCP/UDP checksum gen offload */
+#define GEM_TXCOEN_SIZE 1
+#define GEM_RXBS_OFFSET 16 /* DMA receive buffer size */
+#define GEM_RXBS_SIZE 8
+#define GEM_DDRP_OFFSET 24 /* disc_when_no_ahb */
+#define GEM_DDRP_SIZE 1
/* Bitfields in NSR */
-#define MACB_NSR_LINK_OFFSET 0
-#define MACB_NSR_LINK_SIZE 1
-#define MACB_MDIO_OFFSET 1
-#define MACB_MDIO_SIZE 1
-#define MACB_IDLE_OFFSET 2
-#define MACB_IDLE_SIZE 1
+#define MACB_NSR_LINK_OFFSET 0 /* pcs_link_state */
+#define MACB_NSR_LINK_SIZE 1
+#define MACB_MDIO_OFFSET 1 /* status of the mdio_in pin */
+#define MACB_MDIO_SIZE 1
+#define MACB_IDLE_OFFSET 2 /* The PHY management logic is idle */
+#define MACB_IDLE_SIZE 1
/* Bitfields in TSR */
-#define MACB_UBR_OFFSET 0
-#define MACB_UBR_SIZE 1
-#define MACB_COL_OFFSET 1
-#define MACB_COL_SIZE 1
-#define MACB_TSR_RLE_OFFSET 2
-#define MACB_TSR_RLE_SIZE 1
-#define MACB_TGO_OFFSET 3
-#define MACB_TGO_SIZE 1
-#define MACB_BEX_OFFSET 4
-#define MACB_BEX_SIZE 1
-#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */
-#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */
-#define MACB_COMP_OFFSET 5
-#define MACB_COMP_SIZE 1
-#define MACB_UND_OFFSET 6
-#define MACB_UND_SIZE 1
+#define MACB_UBR_OFFSET 0 /* Used bit read */
+#define MACB_UBR_SIZE 1
+#define MACB_COL_OFFSET 1 /* Collision occurred */
+#define MACB_COL_SIZE 1
+#define MACB_TSR_RLE_OFFSET 2 /* Retry limit exceeded */
+#define MACB_TSR_RLE_SIZE 1
+#define MACB_TGO_OFFSET 3 /* Transmit go */
+#define MACB_TGO_SIZE 1
+#define MACB_BEX_OFFSET 4 /* TX frame corruption due to AHB error */
+#define MACB_BEX_SIZE 1
+#define MACB_RM9200_BNQ_OFFSET 4 /* AT91RM9200 only */
+#define MACB_RM9200_BNQ_SIZE 1 /* AT91RM9200 only */
+#define MACB_COMP_OFFSET 5 /* Trnasmit complete */
+#define MACB_COMP_SIZE 1
+#define MACB_UND_OFFSET 6 /* Trnasmit under run */
+#define MACB_UND_SIZE 1
/* Bitfields in RSR */
-#define MACB_BNA_OFFSET 0
-#define MACB_BNA_SIZE 1
-#define MACB_REC_OFFSET 1
-#define MACB_REC_SIZE 1
-#define MACB_OVR_OFFSET 2
-#define MACB_OVR_SIZE 1
+#define MACB_BNA_OFFSET 0 /* Buffer not available */
+#define MACB_BNA_SIZE 1
+#define MACB_REC_OFFSET 1 /* Frame received */
+#define MACB_REC_SIZE 1
+#define MACB_OVR_OFFSET 2 /* Receive overrun */
+#define MACB_OVR_SIZE 1
/* Bitfields in ISR/IER/IDR/IMR */
-#define MACB_MFD_OFFSET 0
-#define MACB_MFD_SIZE 1
-#define MACB_RCOMP_OFFSET 1
-#define MACB_RCOMP_SIZE 1
-#define MACB_RXUBR_OFFSET 2
-#define MACB_RXUBR_SIZE 1
-#define MACB_TXUBR_OFFSET 3
-#define MACB_TXUBR_SIZE 1
-#define MACB_ISR_TUND_OFFSET 4
-#define MACB_ISR_TUND_SIZE 1
-#define MACB_ISR_RLE_OFFSET 5
-#define MACB_ISR_RLE_SIZE 1
-#define MACB_TXERR_OFFSET 6
-#define MACB_TXERR_SIZE 1
-#define MACB_TCOMP_OFFSET 7
-#define MACB_TCOMP_SIZE 1
-#define MACB_ISR_LINK_OFFSET 9
-#define MACB_ISR_LINK_SIZE 1
-#define MACB_ISR_ROVR_OFFSET 10
-#define MACB_ISR_ROVR_SIZE 1
-#define MACB_HRESP_OFFSET 11
-#define MACB_HRESP_SIZE 1
-#define MACB_PFR_OFFSET 12
-#define MACB_PFR_SIZE 1
-#define MACB_PTZ_OFFSET 13
-#define MACB_PTZ_SIZE 1
+#define MACB_MFD_OFFSET 0 /* Management frame sent */
+#define MACB_MFD_SIZE 1
+#define MACB_RCOMP_OFFSET 1 /* Receive complete */
+#define MACB_RCOMP_SIZE 1
+#define MACB_RXUBR_OFFSET 2 /* RX used bit read */
+#define MACB_RXUBR_SIZE 1
+#define MACB_TXUBR_OFFSET 3 /* TX used bit read */
+#define MACB_TXUBR_SIZE 1
+#define MACB_ISR_TUND_OFFSET 4 /* Enable TX buffer under run interrupt */
+#define MACB_ISR_TUND_SIZE 1
+#define MACB_ISR_RLE_OFFSET 5 /* EN retry exceeded/late coll interrupt */
+#define MACB_ISR_RLE_SIZE 1
+#define MACB_TXERR_OFFSET 6 /* EN TX frame corrupt from error interrupt */
+#define MACB_TXERR_SIZE 1
+#define MACB_TCOMP_OFFSET 7 /* Enable transmit complete interrupt */
+#define MACB_TCOMP_SIZE 1
+#define MACB_ISR_LINK_OFFSET 9 /* Enable link change interrupt */
+#define MACB_ISR_LINK_SIZE 1
+#define MACB_ISR_ROVR_OFFSET 10 /* Enable receive overrun interrupt */
+#define MACB_ISR_ROVR_SIZE 1
+#define MACB_HRESP_OFFSET 11 /* Enable hrsep not OK interrupt */
+#define MACB_HRESP_SIZE 1
+#define MACB_PFR_OFFSET 12 /* Enable pause frame w/ quantum interrupt */
+#define MACB_PFR_SIZE 1
+#define MACB_PTZ_OFFSET 13 /* Enable pause time zero interrupt */
+#define MACB_PTZ_SIZE 1
/* Bitfields in MAN */
-#define MACB_DATA_OFFSET 0
-#define MACB_DATA_SIZE 16
-#define MACB_CODE_OFFSET 16
-#define MACB_CODE_SIZE 2
-#define MACB_REGA_OFFSET 18
-#define MACB_REGA_SIZE 5
-#define MACB_PHYA_OFFSET 23
-#define MACB_PHYA_SIZE 5
-#define MACB_RW_OFFSET 28
-#define MACB_RW_SIZE 2
-#define MACB_SOF_OFFSET 30
-#define MACB_SOF_SIZE 2
+#define MACB_DATA_OFFSET 0 /* data */
+#define MACB_DATA_SIZE 16
+#define MACB_CODE_OFFSET 16 /* Must be written to 10 */
+#define MACB_CODE_SIZE 2
+#define MACB_REGA_OFFSET 18 /* Register address */
+#define MACB_REGA_SIZE 5
+#define MACB_PHYA_OFFSET 23 /* PHY address */
+#define MACB_PHYA_SIZE 5
+#define MACB_RW_OFFSET 28 /* Operation. 10 is read. 01 is write. */
+#define MACB_RW_SIZE 2
+#define MACB_SOF_OFFSET 30 /* Must be written to 1 for Clause 22 */
+#define MACB_SOF_SIZE 2
/* Bitfields in USRIO (AVR32) */
#define MACB_MII_OFFSET 0
@@ -286,7 +332,7 @@
/* Bitfields in USRIO (AT91) */
#define MACB_RMII_OFFSET 0
#define MACB_RMII_SIZE 1
-#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
+#define GEM_RGMII_OFFSET 0 /* GEM gigabit mode */
#define GEM_RGMII_SIZE 1
#define MACB_CLKEN_OFFSET 1
#define MACB_CLKEN_SIZE 1
@@ -389,8 +435,7 @@
#define queue_writel(queue, reg, value) \
__raw_writel((value), (queue)->bp->regs + (queue)->reg)
-/*
- * Conditional GEM/MACB macros. These perform the operation to the correct
+/* Conditional GEM/MACB macros. These perform the operation to the correct
* register dependent on whether the device is a GEM or a MACB. For registers
* and bitfields that are common across both devices, use macb_{read,write}l
* to avoid the cost of the conditional.
@@ -413,8 +458,7 @@
__v; \
})
-/**
- * struct macb_dma_desc - Hardware DMA descriptor
+/* struct macb_dma_desc - Hardware DMA descriptor
* @addr: DMA address of data buffer
* @ctrl: Control and status bits
*/
@@ -503,8 +547,7 @@ struct macb_dma_desc {
/* limit RX checksum offload to TCP and UDP packets */
#define GEM_RX_CSUM_CHECKED_MASK 2
-/**
- * struct macb_tx_skb - data about an skb which is being transmitted
+/* struct macb_tx_skb - data about an skb which is being transmitted
* @skb: skb currently being transmitted, only set for the last buffer
* of the frame
* @mapping: DMA address of the skb's fragment buffer
@@ -519,8 +562,7 @@ struct macb_tx_skb {
bool mapped_as_page;
};
-/*
- * Hardware-collected statistics. Used when updating the network
+/* Hardware-collected statistics. Used when updating the network
* device stats by a periodic timer.
*/
struct macb_stats {
@@ -595,6 +637,107 @@ struct gem_stats {
u32 rx_udp_checksum_errors;
};
+/* Describes the name and offset of an individual statistic register, as
+ * returned by `ethtool -S`. Also describes which net_device_stats statistics
+ * this register should contribute to.
+ */
+struct gem_statistic {
+ char stat_string[ETH_GSTRING_LEN];
+ int offset;
+ u32 stat_bits;
+};
+
+/* Bitfield defs for net_device_stat statistics */
+#define GEM_NDS_RXERR_OFFSET 0
+#define GEM_NDS_RXLENERR_OFFSET 1
+#define GEM_NDS_RXOVERERR_OFFSET 2
+#define GEM_NDS_RXCRCERR_OFFSET 3
+#define GEM_NDS_RXFRAMEERR_OFFSET 4
+#define GEM_NDS_RXFIFOERR_OFFSET 5
+#define GEM_NDS_TXERR_OFFSET 6
+#define GEM_NDS_TXABORTEDERR_OFFSET 7
+#define GEM_NDS_TXCARRIERERR_OFFSET 8
+#define GEM_NDS_TXFIFOERR_OFFSET 9
+#define GEM_NDS_COLLISIONS_OFFSET 10
+
+#define GEM_STAT_TITLE(name, title) GEM_STAT_TITLE_BITS(name, title, 0)
+#define GEM_STAT_TITLE_BITS(name, title, bits) { \
+ .stat_string = title, \
+ .offset = GEM_##name, \
+ .stat_bits = bits \
+}
+
+/* list of gem statistic registers. The names MUST match the
+ * corresponding GEM_* definitions.
+ */
+static const struct gem_statistic gem_statistics[] = {
+ GEM_STAT_TITLE(OCTTXL, "tx_octets"), /* OCTTXH combined with OCTTXL */
+ GEM_STAT_TITLE(TXCNT, "tx_frames"),
+ GEM_STAT_TITLE(TXBCCNT, "tx_broadcast_frames"),
+ GEM_STAT_TITLE(TXMCCNT, "tx_multicast_frames"),
+ GEM_STAT_TITLE(TXPAUSECNT, "tx_pause_frames"),
+ GEM_STAT_TITLE(TX64CNT, "tx_64_byte_frames"),
+ GEM_STAT_TITLE(TX65CNT, "tx_65_127_byte_frames"),
+ GEM_STAT_TITLE(TX128CNT, "tx_128_255_byte_frames"),
+ GEM_STAT_TITLE(TX256CNT, "tx_256_511_byte_frames"),
+ GEM_STAT_TITLE(TX512CNT, "tx_512_1023_byte_frames"),
+ GEM_STAT_TITLE(TX1024CNT, "tx_1024_1518_byte_frames"),
+ GEM_STAT_TITLE(TX1519CNT, "tx_greater_than_1518_byte_frames"),
+ GEM_STAT_TITLE_BITS(TXURUNCNT, "tx_underrun",
+ GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_TXFIFOERR)),
+ GEM_STAT_TITLE_BITS(SNGLCOLLCNT, "tx_single_collision_frames",
+ GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)),
+ GEM_STAT_TITLE_BITS(MULTICOLLCNT, "tx_multiple_collision_frames",
+ GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)),
+ GEM_STAT_TITLE_BITS(EXCESSCOLLCNT, "tx_excessive_collisions",
+ GEM_BIT(NDS_TXERR)|
+ GEM_BIT(NDS_TXABORTEDERR)|
+ GEM_BIT(NDS_COLLISIONS)),
+ GEM_STAT_TITLE_BITS(LATECOLLCNT, "tx_late_collisions",
+ GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)),
+ GEM_STAT_TITLE(TXDEFERCNT, "tx_deferred_frames"),
+ GEM_STAT_TITLE_BITS(TXCSENSECNT, "tx_carrier_sense_errors",
+ GEM_BIT(NDS_TXERR)|GEM_BIT(NDS_COLLISIONS)),
+ GEM_STAT_TITLE(OCTRXL, "rx_octets"), /* OCTRXH combined with OCTRXL */
+ GEM_STAT_TITLE(RXCNT, "rx_frames"),
+ GEM_STAT_TITLE(RXBROADCNT, "rx_broadcast_frames"),
+ GEM_STAT_TITLE(RXMULTICNT, "rx_multicast_frames"),
+ GEM_STAT_TITLE(RXPAUSECNT, "rx_pause_frames"),
+ GEM_STAT_TITLE(RX64CNT, "rx_64_byte_frames"),
+ GEM_STAT_TITLE(RX65CNT, "rx_65_127_byte_frames"),
+ GEM_STAT_TITLE(RX128CNT, "rx_128_255_byte_frames"),
+ GEM_STAT_TITLE(RX256CNT, "rx_256_511_byte_frames"),
+ GEM_STAT_TITLE(RX512CNT, "rx_512_1023_byte_frames"),
+ GEM_STAT_TITLE(RX1024CNT, "rx_1024_1518_byte_frames"),
+ GEM_STAT_TITLE(RX1519CNT, "rx_greater_than_1518_byte_frames"),
+ GEM_STAT_TITLE_BITS(RXUNDRCNT, "rx_undersized_frames",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)),
+ GEM_STAT_TITLE_BITS(RXOVRCNT, "rx_oversize_frames",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)),
+ GEM_STAT_TITLE_BITS(RXJABCNT, "rx_jabbers",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXLENERR)),
+ GEM_STAT_TITLE_BITS(RXFCSCNT, "rx_frame_check_sequence_errors",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXCRCERR)),
+ GEM_STAT_TITLE_BITS(RXLENGTHCNT, "rx_length_field_frame_errors",
+ GEM_BIT(NDS_RXERR)),
+ GEM_STAT_TITLE_BITS(RXSYMBCNT, "rx_symbol_errors",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXFRAMEERR)),
+ GEM_STAT_TITLE_BITS(RXALIGNCNT, "rx_alignment_errors",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXOVERERR)),
+ GEM_STAT_TITLE_BITS(RXRESERRCNT, "rx_resource_errors",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXOVERERR)),
+ GEM_STAT_TITLE_BITS(RXORCNT, "rx_overruns",
+ GEM_BIT(NDS_RXERR)|GEM_BIT(NDS_RXFIFOERR)),
+ GEM_STAT_TITLE_BITS(RXIPCCNT, "rx_ip_header_checksum_errors",
+ GEM_BIT(NDS_RXERR)),
+ GEM_STAT_TITLE_BITS(RXTCPCCNT, "rx_tcp_checksum_errors",
+ GEM_BIT(NDS_RXERR)),
+ GEM_STAT_TITLE_BITS(RXUDPCCNT, "rx_udp_checksum_errors",
+ GEM_BIT(NDS_RXERR)),
+};
+
+#define GEM_STATS_LEN ARRAY_SIZE(gem_statistics)
+
struct macb;
struct macb_or_gem_ops {
@@ -673,6 +816,8 @@ struct macb {
dma_addr_t skb_physaddr; /* phys addr from pci_map_single */
int skb_length; /* saved skb length for pci_unmap_single */
unsigned int max_tx_length;
+
+ u64 ethtool_stats[GEM_STATS_LEN];
};
extern const struct ethtool_ops macb_ethtool_ops;
diff --git a/drivers/net/ethernet/chelsio/cxgb/sge.c b/drivers/net/ethernet/chelsio/cxgb/sge.c
index babe2a915b00..526ea74e82d9 100644
--- a/drivers/net/ethernet/chelsio/cxgb/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb/sge.c
@@ -1860,9 +1860,9 @@ netdev_tx_t t1_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
cpl->iff = dev->if_port;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
cpl->vlan_valid = 1;
- cpl->vlan = htons(vlan_tx_tag_get(skb));
+ cpl->vlan = htons(skb_vlan_tag_get(skb));
st->vlan_insert++;
} else
cpl->vlan_valid = 0;
diff --git a/drivers/net/ethernet/chelsio/cxgb3/mc5.c b/drivers/net/ethernet/chelsio/cxgb3/mc5.c
index e13b7fe9d082..338301b11518 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/mc5.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/mc5.c
@@ -97,14 +97,6 @@ static int mc5_cmd_write(struct adapter *adapter, u32 cmd)
F_DBGIRSPVALID, 1, MAX_WRITE_ATTEMPTS, 1);
}
-static inline void dbgi_wr_addr3(struct adapter *adapter, u32 v1, u32 v2,
- u32 v3)
-{
- t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR0, v1);
- t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR1, v2);
- t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_ADDR2, v3);
-}
-
static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
u32 v3)
{
@@ -113,14 +105,6 @@ static inline void dbgi_wr_data3(struct adapter *adapter, u32 v1, u32 v2,
t3_write_reg(adapter, A_MC5_DB_DBGI_REQ_DATA2, v3);
}
-static inline void dbgi_rd_rsp3(struct adapter *adapter, u32 *v1, u32 *v2,
- u32 *v3)
-{
- *v1 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA0);
- *v2 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA1);
- *v3 = t3_read_reg(adapter, A_MC5_DB_DBGI_RSP_DATA2);
-}
-
/*
* Write data to the TCAM register at address (0, 0, addr_lo) using the TCAM
* command cmd. The data to be written must have been set up by the caller.
diff --git a/drivers/net/ethernet/chelsio/cxgb3/sge.c b/drivers/net/ethernet/chelsio/cxgb3/sge.c
index 3dfcf600fcc6..d6aa602f168d 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/sge.c
@@ -1148,8 +1148,8 @@ static void write_tx_pkt_wr(struct adapter *adap, struct sk_buff *skb,
cpl->len = htonl(skb->len);
cntrl = V_TXPKT_INTF(pi->port_id);
- if (vlan_tx_tag_present(skb))
- cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(vlan_tx_tag_get(skb));
+ if (skb_vlan_tag_present(skb))
+ cntrl |= F_TXPKT_VLAN_VLD | V_TXPKT_VLAN(skb_vlan_tag_get(skb));
tso_info = V_LSO_MSS(skb_shinfo(skb)->gso_size);
if (tso_info) {
@@ -1282,7 +1282,7 @@ netdev_tx_t t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
qs->port_stats[SGE_PSTAT_TX_CSUM]++;
if (skb_shinfo(skb)->gso_size)
qs->port_stats[SGE_PSTAT_TSO]++;
- if (vlan_tx_tag_present(skb))
+ if (skb_vlan_tag_present(skb))
qs->port_stats[SGE_PSTAT_VLANINS]++;
/*
diff --git a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
index c74a898fcd4f..184a8d545ac4 100644
--- a/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb3/t3_hw.c
@@ -727,9 +727,9 @@ static int get_vpd_params(struct adapter *adapter, struct vpd_params *p)
p->xauicfg[1] = simple_strtoul(vpd.xaui1cfg_data, NULL, 16);
}
- for (i = 0; i < 6; i++)
- p->eth_base[i] = hex_to_bin(vpd.na_data[2 * i]) * 16 +
- hex_to_bin(vpd.na_data[2 * i + 1]);
+ ret = hex2bin(p->eth_base, vpd.na_data, 6);
+ if (ret < 0)
+ return -EINVAL;
return 0;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/Makefile b/drivers/net/ethernet/chelsio/cxgb4/Makefile
index b85280775997..ae50cd72358c 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/Makefile
+++ b/drivers/net/ethernet/chelsio/cxgb4/Makefile
@@ -4,6 +4,6 @@
obj-$(CONFIG_CHELSIO_T4) += cxgb4.o
-cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o
+cxgb4-objs := cxgb4_main.o l2t.o t4_hw.o sge.o clip_tbl.o
cxgb4-$(CONFIG_CHELSIO_T4_DCB) += cxgb4_dcb.o
cxgb4-$(CONFIG_DEBUG_FS) += cxgb4_debugfs.o
diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
new file mode 100644
index 000000000000..9062a8434246
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.c
@@ -0,0 +1,317 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved.
+ *
+ * Written by Deepak (deepak.s@chelsio.com)
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
+ * release for licensing terms and conditions.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/jhash.h>
+#include <linux/if_vlan.h>
+#include <net/addrconf.h>
+#include "cxgb4.h"
+#include "clip_tbl.h"
+
+static inline unsigned int ipv4_clip_hash(struct clip_tbl *c, const u32 *key)
+{
+ unsigned int clipt_size_half = c->clipt_size / 2;
+
+ return jhash_1word(*key, 0) % clipt_size_half;
+}
+
+static inline unsigned int ipv6_clip_hash(struct clip_tbl *d, const u32 *key)
+{
+ unsigned int clipt_size_half = d->clipt_size / 2;
+ u32 xor = key[0] ^ key[1] ^ key[2] ^ key[3];
+
+ return clipt_size_half +
+ (jhash_1word(xor, 0) % clipt_size_half);
+}
+
+static unsigned int clip_addr_hash(struct clip_tbl *ctbl, const u32 *addr,
+ int addr_len)
+{
+ return addr_len == 4 ? ipv4_clip_hash(ctbl, addr) :
+ ipv6_clip_hash(ctbl, addr);
+}
+
+static int clip6_get_mbox(const struct net_device *dev,
+ const struct in6_addr *lip)
+{
+ struct adapter *adap = netdev2adap(dev);
+ struct fw_clip_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
+ c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c));
+ *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
+ *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+ return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
+}
+
+static int clip6_release_mbox(const struct net_device *dev,
+ const struct in6_addr *lip)
+{
+ struct adapter *adap = netdev2adap(dev);
+ struct fw_clip_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
+ c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c));
+ *(__be64 *)&c.ip_hi = *(__be64 *)(lip->s6_addr);
+ *(__be64 *)&c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
+ return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
+}
+
+int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6)
+{
+ struct adapter *adap = netdev2adap(dev);
+ struct clip_tbl *ctbl = adap->clipt;
+ struct clip_entry *ce, *cte;
+ u32 *addr = (u32 *)lip;
+ int hash;
+ int addr_len;
+ int ret = 0;
+
+ if (!ctbl)
+ return 0;
+
+ if (v6)
+ addr_len = 16;
+ else
+ addr_len = 4;
+
+ hash = clip_addr_hash(ctbl, addr, addr_len);
+
+ read_lock_bh(&ctbl->lock);
+ list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
+ if (addr_len == cte->addr_len &&
+ memcmp(lip, cte->addr, cte->addr_len) == 0) {
+ ce = cte;
+ read_unlock_bh(&ctbl->lock);
+ goto found;
+ }
+ }
+ read_unlock_bh(&ctbl->lock);
+
+ write_lock_bh(&ctbl->lock);
+ if (!list_empty(&ctbl->ce_free_head)) {
+ ce = list_first_entry(&ctbl->ce_free_head,
+ struct clip_entry, list);
+ list_del(&ce->list);
+ INIT_LIST_HEAD(&ce->list);
+ spin_lock_init(&ce->lock);
+ atomic_set(&ce->refcnt, 0);
+ atomic_dec(&ctbl->nfree);
+ ce->addr_len = addr_len;
+ memcpy(ce->addr, lip, addr_len);
+ list_add_tail(&ce->list, &ctbl->hash_list[hash]);
+ if (v6) {
+ ret = clip6_get_mbox(dev, (const struct in6_addr *)lip);
+ if (ret) {
+ write_unlock_bh(&ctbl->lock);
+ return ret;
+ }
+ }
+ } else {
+ write_unlock_bh(&ctbl->lock);
+ return -ENOMEM;
+ }
+ write_unlock_bh(&ctbl->lock);
+found:
+ atomic_inc(&ce->refcnt);
+
+ return 0;
+}
+EXPORT_SYMBOL(cxgb4_clip_get);
+
+void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6)
+{
+ struct adapter *adap = netdev2adap(dev);
+ struct clip_tbl *ctbl = adap->clipt;
+ struct clip_entry *ce, *cte;
+ u32 *addr = (u32 *)lip;
+ int hash;
+ int addr_len;
+
+ if (v6)
+ addr_len = 16;
+ else
+ addr_len = 4;
+
+ hash = clip_addr_hash(ctbl, addr, addr_len);
+
+ read_lock_bh(&ctbl->lock);
+ list_for_each_entry(cte, &ctbl->hash_list[hash], list) {
+ if (addr_len == cte->addr_len &&
+ memcmp(lip, cte->addr, cte->addr_len) == 0) {
+ ce = cte;
+ read_unlock_bh(&ctbl->lock);
+ goto found;
+ }
+ }
+ read_unlock_bh(&ctbl->lock);
+
+ return;
+found:
+ write_lock_bh(&ctbl->lock);
+ spin_lock_bh(&ce->lock);
+ if (atomic_dec_and_test(&ce->refcnt)) {
+ list_del(&ce->list);
+ INIT_LIST_HEAD(&ce->list);
+ list_add_tail(&ce->list, &ctbl->ce_free_head);
+ atomic_inc(&ctbl->nfree);
+ if (v6)
+ clip6_release_mbox(dev, (const struct in6_addr *)lip);
+ }
+ spin_unlock_bh(&ce->lock);
+ write_unlock_bh(&ctbl->lock);
+}
+EXPORT_SYMBOL(cxgb4_clip_release);
+
+/* Retrieves IPv6 addresses from a root device (bond, vlan) associated with
+ * a physical device.
+ * The physical device reference is needed to send the actul CLIP command.
+ */
+static int cxgb4_update_dev_clip(struct net_device *root_dev,
+ struct net_device *dev)
+{
+ struct inet6_dev *idev = NULL;
+ struct inet6_ifaddr *ifa;
+ int ret = 0;
+
+ idev = __in6_dev_get(root_dev);
+ if (!idev)
+ return ret;
+
+ read_lock_bh(&idev->lock);
+ list_for_each_entry(ifa, &idev->addr_list, if_list) {
+ ret = cxgb4_clip_get(dev, (const u32 *)ifa->addr.s6_addr, 1);
+ if (ret < 0)
+ break;
+ }
+ read_unlock_bh(&idev->lock);
+
+ return ret;
+}
+
+int cxgb4_update_root_dev_clip(struct net_device *dev)
+{
+ struct net_device *root_dev = NULL;
+ int i, ret = 0;
+
+ /* First populate the real net device's IPv6 addresses */
+ ret = cxgb4_update_dev_clip(dev, dev);
+ if (ret)
+ return ret;
+
+ /* Parse all bond and vlan devices layered on top of the physical dev */
+ root_dev = netdev_master_upper_dev_get_rcu(dev);
+ if (root_dev) {
+ ret = cxgb4_update_dev_clip(root_dev, dev);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < VLAN_N_VID; i++) {
+ root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i);
+ if (!root_dev)
+ continue;
+
+ ret = cxgb4_update_dev_clip(root_dev, dev);
+ if (ret)
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(cxgb4_update_root_dev_clip);
+
+int clip_tbl_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adapter = seq->private;
+ struct clip_tbl *ctbl = adapter->clipt;
+ struct clip_entry *ce;
+ char ip[60];
+ int i;
+
+ read_lock_bh(&ctbl->lock);
+
+ seq_puts(seq, "IP Address Users\n");
+ for (i = 0 ; i < ctbl->clipt_size; ++i) {
+ list_for_each_entry(ce, &ctbl->hash_list[i], list) {
+ ip[0] = '\0';
+ if (ce->addr_len == 16)
+ sprintf(ip, "%pI6c", ce->addr);
+ else
+ sprintf(ip, "%pI4c", ce->addr);
+ seq_printf(seq, "%-25s %u\n", ip,
+ atomic_read(&ce->refcnt));
+ }
+ }
+ seq_printf(seq, "Free clip entries : %d\n", atomic_read(&ctbl->nfree));
+
+ read_unlock_bh(&ctbl->lock);
+
+ return 0;
+}
+
+struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start,
+ unsigned int clipt_end)
+{
+ struct clip_entry *cl_list;
+ struct clip_tbl *ctbl;
+ unsigned int clipt_size;
+ int i;
+
+ if (clipt_start >= clipt_end)
+ return NULL;
+ clipt_size = clipt_end - clipt_start + 1;
+ if (clipt_size < CLIPT_MIN_HASH_BUCKETS)
+ return NULL;
+
+ ctbl = t4_alloc_mem(sizeof(*ctbl) +
+ clipt_size*sizeof(struct list_head));
+ if (!ctbl)
+ return NULL;
+
+ ctbl->clipt_start = clipt_start;
+ ctbl->clipt_size = clipt_size;
+ INIT_LIST_HEAD(&ctbl->ce_free_head);
+
+ atomic_set(&ctbl->nfree, clipt_size);
+ rwlock_init(&ctbl->lock);
+
+ for (i = 0; i < ctbl->clipt_size; ++i)
+ INIT_LIST_HEAD(&ctbl->hash_list[i]);
+
+ cl_list = t4_alloc_mem(clipt_size*sizeof(struct clip_entry));
+ ctbl->cl_list = (void *)cl_list;
+
+ for (i = 0; i < clipt_size; i++) {
+ INIT_LIST_HEAD(&cl_list[i].list);
+ list_add_tail(&cl_list[i].list, &ctbl->ce_free_head);
+ }
+
+ return ctbl;
+}
+
+void t4_cleanup_clip_tbl(struct adapter *adap)
+{
+ struct clip_tbl *ctbl = adap->clipt;
+
+ if (ctbl) {
+ if (ctbl->cl_list)
+ t4_free_mem(ctbl->cl_list);
+ t4_free_mem(ctbl);
+ }
+}
+EXPORT_SYMBOL(t4_cleanup_clip_tbl);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
new file mode 100644
index 000000000000..2eaba0161cf8
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/clip_tbl.h
@@ -0,0 +1,41 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ * Copyright (C) 2003-2014 Chelsio Communications. All rights reserved.
+ *
+ * Written by Deepak (deepak.s@chelsio.com)
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the LICENSE file included in this
+ * release for licensing terms and conditions.
+ */
+
+struct clip_entry {
+ spinlock_t lock; /* Hold while modifying clip reference */
+ atomic_t refcnt;
+ struct list_head list;
+ u32 addr[4];
+ int addr_len;
+};
+
+struct clip_tbl {
+ unsigned int clipt_start;
+ unsigned int clipt_size;
+ rwlock_t lock;
+ atomic_t nfree;
+ struct list_head ce_free_head;
+ void *cl_list;
+ struct list_head hash_list[0];
+};
+
+enum {
+ CLIPT_MIN_HASH_BUCKETS = 2,
+};
+
+struct clip_tbl *t4_init_clip_tbl(unsigned int clipt_start,
+ unsigned int clipt_end);
+int cxgb4_clip_get(const struct net_device *dev, const u32 *lip, u8 v6);
+void cxgb4_clip_release(const struct net_device *dev, const u32 *lip, u8 v6);
+int clip_tbl_show(struct seq_file *seq, void *v);
+int cxgb4_update_root_dev_clip(struct net_device *dev);
+void t4_cleanup_clip_tbl(struct adapter *adap);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
index 5ab5c3133acd..d6cda17efe6e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4.h
@@ -49,16 +49,6 @@
#include <asm/io.h>
#include "cxgb4_uld.h"
-#define T4FW_VERSION_MAJOR 0x01
-#define T4FW_VERSION_MINOR 0x0C
-#define T4FW_VERSION_MICRO 0x19
-#define T4FW_VERSION_BUILD 0x00
-
-#define T5FW_VERSION_MAJOR 0x01
-#define T5FW_VERSION_MINOR 0x0C
-#define T5FW_VERSION_MICRO 0x19
-#define T5FW_VERSION_BUILD 0x00
-
#define CH_WARN(adap, fmt, ...) dev_warn(adap->pdev_dev, fmt, ## __VA_ARGS__)
enum {
@@ -231,6 +221,7 @@ struct sge_params {
struct tp_params {
unsigned int ntxchan; /* # of Tx channels */
unsigned int tre; /* log2 of core clocks per TP tick */
+ unsigned int la_mask; /* what events are recorded by TP LA */
unsigned short tx_modq_map; /* TX modulation scheduler queue to */
/* channel map */
@@ -290,11 +281,21 @@ enum chip_type {
T5_LAST_REV = T5_A1,
};
+struct devlog_params {
+ u32 memtype; /* which memory (EDC0, EDC1, MC) */
+ u32 start; /* start of log in firmware memory */
+ u32 size; /* size of log */
+};
+
struct adapter_params {
struct sge_params sge;
struct tp_params tp;
struct vpd_params vpd;
struct pci_params pci;
+ struct devlog_params devlog;
+ enum pcie_memwin drv_memwin;
+
+ unsigned int cim_la_size;
unsigned int sf_size; /* serial flash size in bytes */
unsigned int sf_nsec; /* # of flash sectors */
@@ -476,6 +477,22 @@ struct sge_rspq { /* state for an SGE response queue */
struct adapter *adap;
struct net_device *netdev; /* associated net device */
rspq_handler_t handler;
+#ifdef CONFIG_NET_RX_BUSY_POLL
+#define CXGB_POLL_STATE_IDLE 0
+#define CXGB_POLL_STATE_NAPI BIT(0) /* NAPI owns this poll */
+#define CXGB_POLL_STATE_POLL BIT(1) /* poll owns this poll */
+#define CXGB_POLL_STATE_NAPI_YIELD BIT(2) /* NAPI yielded this poll */
+#define CXGB_POLL_STATE_POLL_YIELD BIT(3) /* poll yielded this poll */
+#define CXGB_POLL_YIELD (CXGB_POLL_STATE_NAPI_YIELD | \
+ CXGB_POLL_STATE_POLL_YIELD)
+#define CXGB_POLL_LOCKED (CXGB_POLL_STATE_NAPI | \
+ CXGB_POLL_STATE_POLL)
+#define CXGB_POLL_USER_PEND (CXGB_POLL_STATE_POLL | \
+ CXGB_POLL_STATE_POLL_YIELD)
+ unsigned int bpoll_state;
+ spinlock_t bpoll_lock; /* lock for busy poll */
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
};
struct sge_eth_stats { /* Ethernet queue statistics */
@@ -658,6 +675,9 @@ struct adapter {
unsigned int l2t_start;
unsigned int l2t_end;
struct l2t_data *l2t;
+ unsigned int clipt_start;
+ unsigned int clipt_end;
+ struct clip_tbl *clipt;
void *uld_handle[CXGB4_ULD_MAX];
struct list_head list_node;
struct list_head rcu_node;
@@ -877,6 +897,102 @@ static inline struct adapter *netdev2adap(const struct net_device *dev)
return netdev2pinfo(dev)->adapter;
}
+#ifdef CONFIG_NET_RX_BUSY_POLL
+static inline void cxgb_busy_poll_init_lock(struct sge_rspq *q)
+{
+ spin_lock_init(&q->bpoll_lock);
+ q->bpoll_state = CXGB_POLL_STATE_IDLE;
+}
+
+static inline bool cxgb_poll_lock_napi(struct sge_rspq *q)
+{
+ bool rc = true;
+
+ spin_lock(&q->bpoll_lock);
+ if (q->bpoll_state & CXGB_POLL_LOCKED) {
+ q->bpoll_state |= CXGB_POLL_STATE_NAPI_YIELD;
+ rc = false;
+ } else {
+ q->bpoll_state = CXGB_POLL_STATE_NAPI;
+ }
+ spin_unlock(&q->bpoll_lock);
+ return rc;
+}
+
+static inline bool cxgb_poll_unlock_napi(struct sge_rspq *q)
+{
+ bool rc = false;
+
+ spin_lock(&q->bpoll_lock);
+ if (q->bpoll_state & CXGB_POLL_STATE_POLL_YIELD)
+ rc = true;
+ q->bpoll_state = CXGB_POLL_STATE_IDLE;
+ spin_unlock(&q->bpoll_lock);
+ return rc;
+}
+
+static inline bool cxgb_poll_lock_poll(struct sge_rspq *q)
+{
+ bool rc = true;
+
+ spin_lock_bh(&q->bpoll_lock);
+ if (q->bpoll_state & CXGB_POLL_LOCKED) {
+ q->bpoll_state |= CXGB_POLL_STATE_POLL_YIELD;
+ rc = false;
+ } else {
+ q->bpoll_state |= CXGB_POLL_STATE_POLL;
+ }
+ spin_unlock_bh(&q->bpoll_lock);
+ return rc;
+}
+
+static inline bool cxgb_poll_unlock_poll(struct sge_rspq *q)
+{
+ bool rc = false;
+
+ spin_lock_bh(&q->bpoll_lock);
+ if (q->bpoll_state & CXGB_POLL_STATE_POLL_YIELD)
+ rc = true;
+ q->bpoll_state = CXGB_POLL_STATE_IDLE;
+ spin_unlock_bh(&q->bpoll_lock);
+ return rc;
+}
+
+static inline bool cxgb_poll_busy_polling(struct sge_rspq *q)
+{
+ return q->bpoll_state & CXGB_POLL_USER_PEND;
+}
+#else
+static inline void cxgb_busy_poll_init_lock(struct sge_rspq *q)
+{
+}
+
+static inline bool cxgb_poll_lock_napi(struct sge_rspq *q)
+{
+ return true;
+}
+
+static inline bool cxgb_poll_unlock_napi(struct sge_rspq *q)
+{
+ return false;
+}
+
+static inline bool cxgb_poll_lock_poll(struct sge_rspq *q)
+{
+ return false;
+}
+
+static inline bool cxgb_poll_unlock_poll(struct sge_rspq *q)
+{
+ return false;
+}
+
+static inline bool cxgb_poll_busy_polling(struct sge_rspq *q)
+{
+ return false;
+}
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
void t4_os_portmod_changed(const struct adapter *adap, int port_id);
void t4_os_link_changed(struct adapter *adap, int port_id, int link_stat);
@@ -905,6 +1021,7 @@ irqreturn_t t4_sge_intr_msix(int irq, void *cookie);
int t4_sge_init(struct adapter *adap);
void t4_sge_start(struct adapter *adap);
void t4_sge_stop(struct adapter *adap);
+int cxgb_busy_poll(struct napi_struct *napi);
extern int dbfifo_int_thresh;
#define for_each_port(adapter, iter) \
@@ -995,12 +1112,16 @@ static inline int t4_memory_write(struct adapter *adap, int mtype, u32 addr,
int t4_seeprom_wp(struct adapter *adapter, bool enable);
int get_vpd_params(struct adapter *adapter, struct vpd_params *p);
+int t4_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented);
int t4_load_fw(struct adapter *adapter, const u8 *fw_data, unsigned int size);
+int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op);
int t4_fw_upgrade(struct adapter *adap, unsigned int mbox,
const u8 *fw_data, unsigned int size, int force);
unsigned int t4_flash_cfg_addr(struct adapter *adapter);
int t4_get_fw_version(struct adapter *adapter, u32 *vers);
int t4_get_tp_version(struct adapter *adapter, u32 *vers);
+int t4_get_exprom_version(struct adapter *adapter, u32 *vers);
int t4_prep_fw(struct adapter *adap, struct fw_info *fw_info,
const u8 *fw_data, unsigned int fw_size,
struct fw_hdr *card_fw, enum dev_state state, int *reset);
@@ -1013,6 +1134,8 @@ int cxgb4_t4_bar2_sge_qregs(struct adapter *adapter,
u64 *pbar2_qoffset,
unsigned int *pbar2_qid);
+unsigned int qtimer_val(const struct adapter *adap,
+ const struct sge_rspq *q);
int t4_init_sge_params(struct adapter *adapter);
int t4_init_tp_params(struct adapter *adap);
int t4_filter_field_shift(const struct adapter *adap, int filter_sel);
@@ -1022,20 +1145,46 @@ int t4_config_rss_range(struct adapter *adapter, int mbox, unsigned int viid,
int start, int n, const u16 *rspq, unsigned int nrspq);
int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
unsigned int flags);
+int t4_read_rss(struct adapter *adapter, u16 *entries);
+void t4_read_rss_key(struct adapter *adapter, u32 *key);
+void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx);
+void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
+ u32 *valp);
+void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
+ u32 *vfl, u32 *vfh);
+u32 t4_read_rss_pf_map(struct adapter *adapter);
+u32 t4_read_rss_pf_mask(struct adapter *adapter);
+
int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
u64 *parity);
int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data,
u64 *parity);
+void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]);
+void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[]);
+int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data,
+ size_t n);
+int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data,
+ size_t n);
+int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n,
+ unsigned int *valp);
+int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n,
+ const unsigned int *valp);
+int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr);
+void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres);
const char *t4_get_port_type_description(enum fw_port_type port_type);
void t4_get_port_stats(struct adapter *adap, int idx, struct port_stats *p);
void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log);
+void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN]);
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
unsigned int mask, unsigned int val);
+void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr);
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6);
void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
const unsigned short *alpha, const unsigned short *beta);
+void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf);
+
void t4_mk_filtdelwr(unsigned int ftid, struct fw_filter_wr *wr, int qid);
void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
index a35d1ec6950e..6074680bc985 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.c
@@ -22,7 +22,7 @@
/* DCBx version control
*/
-char *dcb_ver_array[] = {
+static const char * const dcb_ver_array[] = {
"Unknown",
"DCBx-CIN",
"DCBx-CEE 1.01",
@@ -428,7 +428,10 @@ static void cxgb4_getpgtccfg(struct net_device *dev, int tc,
}
*pgid = (be32_to_cpu(pcmd.u.dcb.pgid.pgid) >> (tc * 4)) & 0xf;
- INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
+ if (local)
+ INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
+ else
+ INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
if (err != FW_PORT_DCB_CFG_SUCCESS) {
@@ -900,6 +903,88 @@ cxgb4_ieee_negotiation_complete(struct net_device *dev,
(dcb->supported & DCB_CAP_DCBX_VER_IEEE));
}
+static int cxgb4_ieee_read_ets(struct net_device *dev, struct ieee_ets *ets,
+ int local)
+{
+ struct port_info *pi = netdev2pinfo(dev);
+ struct port_dcb_info *dcb = &pi->dcb;
+ struct adapter *adap = pi->adapter;
+ uint32_t tc_info;
+ struct fw_port_cmd pcmd;
+ int i, bwg, err;
+
+ if (!(dcb->msgs & (CXGB4_DCB_FW_PGID | CXGB4_DCB_FW_PGRATE)))
+ return 0;
+
+ ets->ets_cap = dcb->pg_num_tcs_supported;
+
+ if (local) {
+ ets->willing = 1;
+ INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
+ } else {
+ INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
+ }
+
+ pcmd.u.dcb.pgid.type = FW_PORT_DCB_TYPE_PGID;
+ err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
+ if (err != FW_PORT_DCB_CFG_SUCCESS) {
+ dev_err(adap->pdev_dev, "DCB read PGID failed with %d\n", -err);
+ return err;
+ }
+
+ tc_info = be32_to_cpu(pcmd.u.dcb.pgid.pgid);
+
+ if (local)
+ INIT_PORT_DCB_READ_LOCAL_CMD(pcmd, pi->port_id);
+ else
+ INIT_PORT_DCB_READ_PEER_CMD(pcmd, pi->port_id);
+
+ pcmd.u.dcb.pgrate.type = FW_PORT_DCB_TYPE_PGRATE;
+ err = t4_wr_mbox(adap, adap->mbox, &pcmd, sizeof(pcmd), &pcmd);
+ if (err != FW_PORT_DCB_CFG_SUCCESS) {
+ dev_err(adap->pdev_dev, "DCB read PGRATE failed with %d\n",
+ -err);
+ return err;
+ }
+
+ for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) {
+ bwg = (tc_info >> ((7 - i) * 4)) & 0xF;
+ ets->prio_tc[i] = bwg;
+ ets->tc_tx_bw[i] = pcmd.u.dcb.pgrate.pgrate[i];
+ ets->tc_rx_bw[i] = ets->tc_tx_bw[i];
+ ets->tc_tsa[i] = pcmd.u.dcb.pgrate.tsa[i];
+ }
+
+ return 0;
+}
+
+static int cxgb4_ieee_get_ets(struct net_device *dev, struct ieee_ets *ets)
+{
+ return cxgb4_ieee_read_ets(dev, ets, 1);
+}
+
+/* We reuse this for peer PFC as well, as we can't have it enabled one way */
+static int cxgb4_ieee_get_pfc(struct net_device *dev, struct ieee_pfc *pfc)
+{
+ struct port_info *pi = netdev2pinfo(dev);
+ struct port_dcb_info *dcb = &pi->dcb;
+
+ memset(pfc, 0, sizeof(struct ieee_pfc));
+
+ if (!(dcb->msgs & CXGB4_DCB_FW_PFC))
+ return 0;
+
+ pfc->pfc_cap = dcb->pfc_num_tcs_supported;
+ pfc->pfc_en = bitswap_1(dcb->pfcen);
+
+ return 0;
+}
+
+static int cxgb4_ieee_peer_ets(struct net_device *dev, struct ieee_ets *ets)
+{
+ return cxgb4_ieee_read_ets(dev, ets, 0);
+}
+
/* Fill in the Application User Priority Map associated with the
* specified Application.
* Priority for IEEE dcb_app is an integer, with 0 being a valid value
@@ -1106,14 +1191,23 @@ static int cxgb4_cee_peer_getpfc(struct net_device *dev, struct cee_pfc *pfc)
struct port_info *pi = netdev2pinfo(dev);
cxgb4_getnumtcs(dev, DCB_NUMTCS_ATTR_PFC, &(pfc->tcs_supported));
- pfc->pfc_en = pi->dcb.pfcen;
+
+ /* Firmware sends this to us in a formwat that is a bit flipped version
+ * of spec, correct it before we send it to host. This is taken care of
+ * by bit shifting in other uses of pfcen
+ */
+ pfc->pfc_en = bitswap_1(pi->dcb.pfcen);
return 0;
}
const struct dcbnl_rtnl_ops cxgb4_dcb_ops = {
+ .ieee_getets = cxgb4_ieee_get_ets,
+ .ieee_getpfc = cxgb4_ieee_get_pfc,
.ieee_getapp = cxgb4_ieee_getapp,
.ieee_setapp = cxgb4_ieee_setapp,
+ .ieee_peer_getets = cxgb4_ieee_peer_ets,
+ .ieee_peer_getpfc = cxgb4_ieee_get_pfc,
/* CEE std */
.getstate = cxgb4_getstate,
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
index 31ce425616c9..ccf24d3dc982 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_dcb.h
@@ -136,6 +136,17 @@ void cxgb4_dcb_handle_fw_update(struct adapter *, const struct fw_port_cmd *);
void cxgb4_dcb_set_caps(struct adapter *, const struct fw_port_cmd *);
extern const struct dcbnl_rtnl_ops cxgb4_dcb_ops;
+static inline __u8 bitswap_1(unsigned char val)
+{
+ return ((val & 0x80) >> 7) |
+ ((val & 0x40) >> 5) |
+ ((val & 0x20) >> 3) |
+ ((val & 0x10) >> 1) |
+ ((val & 0x08) << 1) |
+ ((val & 0x04) << 3) |
+ ((val & 0x02) << 5) |
+ ((val & 0x01) << 7);
+}
#define CXGB4_DCB_ENABLED true
#else /* !CONFIG_CHELSIO_T4_DCB */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
index c98a350d857e..78854ceb0870 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.c
@@ -36,13 +36,1867 @@
#include <linux/debugfs.h>
#include <linux/string_helpers.h>
#include <linux/sort.h>
+#include <linux/ctype.h>
#include "cxgb4.h"
#include "t4_regs.h"
+#include "t4_values.h"
#include "t4fw_api.h"
#include "cxgb4_debugfs.h"
+#include "clip_tbl.h"
#include "l2t.h"
+/* generic seq_file support for showing a table of size rows x width. */
+static void *seq_tab_get_idx(struct seq_tab *tb, loff_t pos)
+{
+ pos -= tb->skip_first;
+ return pos >= tb->rows ? NULL : &tb->data[pos * tb->width];
+}
+
+static void *seq_tab_start(struct seq_file *seq, loff_t *pos)
+{
+ struct seq_tab *tb = seq->private;
+
+ if (tb->skip_first && *pos == 0)
+ return SEQ_START_TOKEN;
+
+ return seq_tab_get_idx(tb, *pos);
+}
+
+static void *seq_tab_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ v = seq_tab_get_idx(seq->private, *pos + 1);
+ if (v)
+ ++*pos;
+ return v;
+}
+
+static void seq_tab_stop(struct seq_file *seq, void *v)
+{
+}
+
+static int seq_tab_show(struct seq_file *seq, void *v)
+{
+ const struct seq_tab *tb = seq->private;
+
+ return tb->show(seq, v, ((char *)v - tb->data) / tb->width);
+}
+
+static const struct seq_operations seq_tab_ops = {
+ .start = seq_tab_start,
+ .next = seq_tab_next,
+ .stop = seq_tab_stop,
+ .show = seq_tab_show
+};
+
+struct seq_tab *seq_open_tab(struct file *f, unsigned int rows,
+ unsigned int width, unsigned int have_header,
+ int (*show)(struct seq_file *seq, void *v, int i))
+{
+ struct seq_tab *p;
+
+ p = __seq_open_private(f, &seq_tab_ops, sizeof(*p) + rows * width);
+ if (p) {
+ p->show = show;
+ p->rows = rows;
+ p->width = width;
+ p->skip_first = have_header != 0;
+ }
+ return p;
+}
+
+/* Trim the size of a seq_tab to the supplied number of rows. The operation is
+ * irreversible.
+ */
+static int seq_tab_trim(struct seq_tab *p, unsigned int new_rows)
+{
+ if (new_rows > p->rows)
+ return -EINVAL;
+ p->rows = new_rows;
+ return 0;
+}
+
+static int cim_la_show(struct seq_file *seq, void *v, int idx)
+{
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "Status Data PC LS0Stat LS0Addr "
+ " LS0Data\n");
+ else {
+ const u32 *p = v;
+
+ seq_printf(seq,
+ " %02x %x%07x %x%07x %08x %08x %08x%08x%08x%08x\n",
+ (p[0] >> 4) & 0xff, p[0] & 0xf, p[1] >> 4,
+ p[1] & 0xf, p[2] >> 4, p[2] & 0xf, p[3], p[4], p[5],
+ p[6], p[7]);
+ }
+ return 0;
+}
+
+static int cim_la_show_3in1(struct seq_file *seq, void *v, int idx)
+{
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq, "Status Data PC\n");
+ } else {
+ const u32 *p = v;
+
+ seq_printf(seq, " %02x %08x %08x\n", p[5] & 0xff, p[6],
+ p[7]);
+ seq_printf(seq, " %02x %02x%06x %02x%06x\n",
+ (p[3] >> 8) & 0xff, p[3] & 0xff, p[4] >> 8,
+ p[4] & 0xff, p[5] >> 8);
+ seq_printf(seq, " %02x %x%07x %x%07x\n", (p[0] >> 4) & 0xff,
+ p[0] & 0xf, p[1] >> 4, p[1] & 0xf, p[2] >> 4);
+ }
+ return 0;
+}
+
+static int cim_la_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ unsigned int cfg;
+ struct seq_tab *p;
+ struct adapter *adap = inode->i_private;
+
+ ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg);
+ if (ret)
+ return ret;
+
+ p = seq_open_tab(file, adap->params.cim_la_size / 8, 8 * sizeof(u32), 1,
+ cfg & UPDBGLACAPTPCONLY_F ?
+ cim_la_show_3in1 : cim_la_show);
+ if (!p)
+ return -ENOMEM;
+
+ ret = t4_cim_read_la(adap, (u32 *)p->data, NULL);
+ if (ret)
+ seq_release_private(inode, file);
+ return ret;
+}
+
+static const struct file_operations cim_la_fops = {
+ .owner = THIS_MODULE,
+ .open = cim_la_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+static int cim_qcfg_show(struct seq_file *seq, void *v)
+{
+ static const char * const qname[] = {
+ "TP0", "TP1", "ULP", "SGE0", "SGE1", "NC-SI",
+ "ULP0", "ULP1", "ULP2", "ULP3", "SGE", "NC-SI",
+ "SGE0-RX", "SGE1-RX"
+ };
+
+ int i;
+ struct adapter *adap = seq->private;
+ u16 base[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
+ u16 size[CIM_NUM_IBQ + CIM_NUM_OBQ_T5];
+ u32 stat[(4 * (CIM_NUM_IBQ + CIM_NUM_OBQ_T5))];
+ u16 thres[CIM_NUM_IBQ];
+ u32 obq_wr_t4[2 * CIM_NUM_OBQ], *wr;
+ u32 obq_wr_t5[2 * CIM_NUM_OBQ_T5];
+ u32 *p = stat;
+ int cim_num_obq = is_t4(adap->params.chip) ?
+ CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
+
+ i = t4_cim_read(adap, is_t4(adap->params.chip) ? UP_IBQ_0_RDADDR_A :
+ UP_IBQ_0_SHADOW_RDADDR_A,
+ ARRAY_SIZE(stat), stat);
+ if (!i) {
+ if (is_t4(adap->params.chip)) {
+ i = t4_cim_read(adap, UP_OBQ_0_REALADDR_A,
+ ARRAY_SIZE(obq_wr_t4), obq_wr_t4);
+ wr = obq_wr_t4;
+ } else {
+ i = t4_cim_read(adap, UP_OBQ_0_SHADOW_REALADDR_A,
+ ARRAY_SIZE(obq_wr_t5), obq_wr_t5);
+ wr = obq_wr_t5;
+ }
+ }
+ if (i)
+ return i;
+
+ t4_read_cimq_cfg(adap, base, size, thres);
+
+ seq_printf(seq,
+ " Queue Base Size Thres RdPtr WrPtr SOP EOP Avail\n");
+ for (i = 0; i < CIM_NUM_IBQ; i++, p += 4)
+ seq_printf(seq, "%7s %5x %5u %5u %6x %4x %4u %4u %5u\n",
+ qname[i], base[i], size[i], thres[i],
+ IBQRDADDR_G(p[0]), IBQWRADDR_G(p[1]),
+ QUESOPCNT_G(p[3]), QUEEOPCNT_G(p[3]),
+ QUEREMFLITS_G(p[2]) * 16);
+ for ( ; i < CIM_NUM_IBQ + cim_num_obq; i++, p += 4, wr += 2)
+ seq_printf(seq, "%7s %5x %5u %12x %4x %4u %4u %5u\n",
+ qname[i], base[i], size[i],
+ QUERDADDR_G(p[0]) & 0x3fff, wr[0] - base[i],
+ QUESOPCNT_G(p[3]), QUEEOPCNT_G(p[3]),
+ QUEREMFLITS_G(p[2]) * 16);
+ return 0;
+}
+
+static int cim_qcfg_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, cim_qcfg_show, inode->i_private);
+}
+
+static const struct file_operations cim_qcfg_fops = {
+ .owner = THIS_MODULE,
+ .open = cim_qcfg_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int cimq_show(struct seq_file *seq, void *v, int idx)
+{
+ const u32 *p = v;
+
+ seq_printf(seq, "%#06x: %08x %08x %08x %08x\n", idx * 16, p[0], p[1],
+ p[2], p[3]);
+ return 0;
+}
+
+static int cim_ibq_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ struct seq_tab *p;
+ unsigned int qid = (uintptr_t)inode->i_private & 7;
+ struct adapter *adap = inode->i_private - qid;
+
+ p = seq_open_tab(file, CIM_IBQ_SIZE, 4 * sizeof(u32), 0, cimq_show);
+ if (!p)
+ return -ENOMEM;
+
+ ret = t4_read_cim_ibq(adap, qid, (u32 *)p->data, CIM_IBQ_SIZE * 4);
+ if (ret < 0)
+ seq_release_private(inode, file);
+ else
+ ret = 0;
+ return ret;
+}
+
+static const struct file_operations cim_ibq_fops = {
+ .owner = THIS_MODULE,
+ .open = cim_ibq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+static int cim_obq_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ struct seq_tab *p;
+ unsigned int qid = (uintptr_t)inode->i_private & 7;
+ struct adapter *adap = inode->i_private - qid;
+
+ p = seq_open_tab(file, 6 * CIM_OBQ_SIZE, 4 * sizeof(u32), 0, cimq_show);
+ if (!p)
+ return -ENOMEM;
+
+ ret = t4_read_cim_obq(adap, qid, (u32 *)p->data, 6 * CIM_OBQ_SIZE * 4);
+ if (ret < 0) {
+ seq_release_private(inode, file);
+ } else {
+ seq_tab_trim(p, ret / 4);
+ ret = 0;
+ }
+ return ret;
+}
+
+static const struct file_operations cim_obq_fops = {
+ .owner = THIS_MODULE,
+ .open = cim_obq_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+struct field_desc {
+ const char *name;
+ unsigned int start;
+ unsigned int width;
+};
+
+static void field_desc_show(struct seq_file *seq, u64 v,
+ const struct field_desc *p)
+{
+ char buf[32];
+ int line_size = 0;
+
+ while (p->name) {
+ u64 mask = (1ULL << p->width) - 1;
+ int len = scnprintf(buf, sizeof(buf), "%s: %llu", p->name,
+ ((unsigned long long)v >> p->start) & mask);
+
+ if (line_size + len >= 79) {
+ line_size = 8;
+ seq_puts(seq, "\n ");
+ }
+ seq_printf(seq, "%s ", buf);
+ line_size += len + 1;
+ p++;
+ }
+ seq_putc(seq, '\n');
+}
+
+static struct field_desc tp_la0[] = {
+ { "RcfOpCodeOut", 60, 4 },
+ { "State", 56, 4 },
+ { "WcfState", 52, 4 },
+ { "RcfOpcSrcOut", 50, 2 },
+ { "CRxError", 49, 1 },
+ { "ERxError", 48, 1 },
+ { "SanityFailed", 47, 1 },
+ { "SpuriousMsg", 46, 1 },
+ { "FlushInputMsg", 45, 1 },
+ { "FlushInputCpl", 44, 1 },
+ { "RssUpBit", 43, 1 },
+ { "RssFilterHit", 42, 1 },
+ { "Tid", 32, 10 },
+ { "InitTcb", 31, 1 },
+ { "LineNumber", 24, 7 },
+ { "Emsg", 23, 1 },
+ { "EdataOut", 22, 1 },
+ { "Cmsg", 21, 1 },
+ { "CdataOut", 20, 1 },
+ { "EreadPdu", 19, 1 },
+ { "CreadPdu", 18, 1 },
+ { "TunnelPkt", 17, 1 },
+ { "RcfPeerFin", 16, 1 },
+ { "RcfReasonOut", 12, 4 },
+ { "TxCchannel", 10, 2 },
+ { "RcfTxChannel", 8, 2 },
+ { "RxEchannel", 6, 2 },
+ { "RcfRxChannel", 5, 1 },
+ { "RcfDataOutSrdy", 4, 1 },
+ { "RxDvld", 3, 1 },
+ { "RxOoDvld", 2, 1 },
+ { "RxCongestion", 1, 1 },
+ { "TxCongestion", 0, 1 },
+ { NULL }
+};
+
+static int tp_la_show(struct seq_file *seq, void *v, int idx)
+{
+ const u64 *p = v;
+
+ field_desc_show(seq, *p, tp_la0);
+ return 0;
+}
+
+static int tp_la_show2(struct seq_file *seq, void *v, int idx)
+{
+ const u64 *p = v;
+
+ if (idx)
+ seq_putc(seq, '\n');
+ field_desc_show(seq, p[0], tp_la0);
+ if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
+ field_desc_show(seq, p[1], tp_la0);
+ return 0;
+}
+
+static int tp_la_show3(struct seq_file *seq, void *v, int idx)
+{
+ static struct field_desc tp_la1[] = {
+ { "CplCmdIn", 56, 8 },
+ { "CplCmdOut", 48, 8 },
+ { "ESynOut", 47, 1 },
+ { "EAckOut", 46, 1 },
+ { "EFinOut", 45, 1 },
+ { "ERstOut", 44, 1 },
+ { "SynIn", 43, 1 },
+ { "AckIn", 42, 1 },
+ { "FinIn", 41, 1 },
+ { "RstIn", 40, 1 },
+ { "DataIn", 39, 1 },
+ { "DataInVld", 38, 1 },
+ { "PadIn", 37, 1 },
+ { "RxBufEmpty", 36, 1 },
+ { "RxDdp", 35, 1 },
+ { "RxFbCongestion", 34, 1 },
+ { "TxFbCongestion", 33, 1 },
+ { "TxPktSumSrdy", 32, 1 },
+ { "RcfUlpType", 28, 4 },
+ { "Eread", 27, 1 },
+ { "Ebypass", 26, 1 },
+ { "Esave", 25, 1 },
+ { "Static0", 24, 1 },
+ { "Cread", 23, 1 },
+ { "Cbypass", 22, 1 },
+ { "Csave", 21, 1 },
+ { "CPktOut", 20, 1 },
+ { "RxPagePoolFull", 18, 2 },
+ { "RxLpbkPkt", 17, 1 },
+ { "TxLpbkPkt", 16, 1 },
+ { "RxVfValid", 15, 1 },
+ { "SynLearned", 14, 1 },
+ { "SetDelEntry", 13, 1 },
+ { "SetInvEntry", 12, 1 },
+ { "CpcmdDvld", 11, 1 },
+ { "CpcmdSave", 10, 1 },
+ { "RxPstructsFull", 8, 2 },
+ { "EpcmdDvld", 7, 1 },
+ { "EpcmdFlush", 6, 1 },
+ { "EpcmdTrimPrefix", 5, 1 },
+ { "EpcmdTrimPostfix", 4, 1 },
+ { "ERssIp4Pkt", 3, 1 },
+ { "ERssIp6Pkt", 2, 1 },
+ { "ERssTcpUdpPkt", 1, 1 },
+ { "ERssFceFipPkt", 0, 1 },
+ { NULL }
+ };
+ static struct field_desc tp_la2[] = {
+ { "CplCmdIn", 56, 8 },
+ { "MpsVfVld", 55, 1 },
+ { "MpsPf", 52, 3 },
+ { "MpsVf", 44, 8 },
+ { "SynIn", 43, 1 },
+ { "AckIn", 42, 1 },
+ { "FinIn", 41, 1 },
+ { "RstIn", 40, 1 },
+ { "DataIn", 39, 1 },
+ { "DataInVld", 38, 1 },
+ { "PadIn", 37, 1 },
+ { "RxBufEmpty", 36, 1 },
+ { "RxDdp", 35, 1 },
+ { "RxFbCongestion", 34, 1 },
+ { "TxFbCongestion", 33, 1 },
+ { "TxPktSumSrdy", 32, 1 },
+ { "RcfUlpType", 28, 4 },
+ { "Eread", 27, 1 },
+ { "Ebypass", 26, 1 },
+ { "Esave", 25, 1 },
+ { "Static0", 24, 1 },
+ { "Cread", 23, 1 },
+ { "Cbypass", 22, 1 },
+ { "Csave", 21, 1 },
+ { "CPktOut", 20, 1 },
+ { "RxPagePoolFull", 18, 2 },
+ { "RxLpbkPkt", 17, 1 },
+ { "TxLpbkPkt", 16, 1 },
+ { "RxVfValid", 15, 1 },
+ { "SynLearned", 14, 1 },
+ { "SetDelEntry", 13, 1 },
+ { "SetInvEntry", 12, 1 },
+ { "CpcmdDvld", 11, 1 },
+ { "CpcmdSave", 10, 1 },
+ { "RxPstructsFull", 8, 2 },
+ { "EpcmdDvld", 7, 1 },
+ { "EpcmdFlush", 6, 1 },
+ { "EpcmdTrimPrefix", 5, 1 },
+ { "EpcmdTrimPostfix", 4, 1 },
+ { "ERssIp4Pkt", 3, 1 },
+ { "ERssIp6Pkt", 2, 1 },
+ { "ERssTcpUdpPkt", 1, 1 },
+ { "ERssFceFipPkt", 0, 1 },
+ { NULL }
+ };
+ const u64 *p = v;
+
+ if (idx)
+ seq_putc(seq, '\n');
+ field_desc_show(seq, p[0], tp_la0);
+ if (idx < (TPLA_SIZE / 2 - 1) || p[1] != ~0ULL)
+ field_desc_show(seq, p[1], (p[0] & BIT(17)) ? tp_la2 : tp_la1);
+ return 0;
+}
+
+static int tp_la_open(struct inode *inode, struct file *file)
+{
+ struct seq_tab *p;
+ struct adapter *adap = inode->i_private;
+
+ switch (DBGLAMODE_G(t4_read_reg(adap, TP_DBG_LA_CONFIG_A))) {
+ case 2:
+ p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0,
+ tp_la_show2);
+ break;
+ case 3:
+ p = seq_open_tab(file, TPLA_SIZE / 2, 2 * sizeof(u64), 0,
+ tp_la_show3);
+ break;
+ default:
+ p = seq_open_tab(file, TPLA_SIZE, sizeof(u64), 0, tp_la_show);
+ }
+ if (!p)
+ return -ENOMEM;
+
+ t4_tp_read_la(adap, (u64 *)p->data, NULL);
+ return 0;
+}
+
+static ssize_t tp_la_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ int err;
+ char s[32];
+ unsigned long val;
+ size_t size = min(sizeof(s) - 1, count);
+ struct adapter *adap = FILE_DATA(file)->i_private;
+
+ if (copy_from_user(s, buf, size))
+ return -EFAULT;
+ s[size] = '\0';
+ err = kstrtoul(s, 0, &val);
+ if (err)
+ return err;
+ if (val > 0xffff)
+ return -EINVAL;
+ adap->params.tp.la_mask = val << 16;
+ t4_set_reg_field(adap, TP_DBG_LA_CONFIG_A, 0xffff0000U,
+ adap->params.tp.la_mask);
+ return count;
+}
+
+static const struct file_operations tp_la_fops = {
+ .owner = THIS_MODULE,
+ .open = tp_la_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private,
+ .write = tp_la_write
+};
+
+static int ulprx_la_show(struct seq_file *seq, void *v, int idx)
+{
+ const u32 *p = v;
+
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, " Pcmd Type Message"
+ " Data\n");
+ else
+ seq_printf(seq, "%08x%08x %4x %08x %08x%08x%08x%08x\n",
+ p[1], p[0], p[2], p[3], p[7], p[6], p[5], p[4]);
+ return 0;
+}
+
+static int ulprx_la_open(struct inode *inode, struct file *file)
+{
+ struct seq_tab *p;
+ struct adapter *adap = inode->i_private;
+
+ p = seq_open_tab(file, ULPRX_LA_SIZE, 8 * sizeof(u32), 1,
+ ulprx_la_show);
+ if (!p)
+ return -ENOMEM;
+
+ t4_ulprx_read_la(adap, (u32 *)p->data);
+ return 0;
+}
+
+static const struct file_operations ulprx_la_fops = {
+ .owner = THIS_MODULE,
+ .open = ulprx_la_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+/* Show the PM memory stats. These stats include:
+ *
+ * TX:
+ * Read: memory read operation
+ * Write Bypass: cut-through
+ * Bypass + mem: cut-through and save copy
+ *
+ * RX:
+ * Read: memory read
+ * Write Bypass: cut-through
+ * Flush: payload trim or drop
+ */
+static int pm_stats_show(struct seq_file *seq, void *v)
+{
+ static const char * const tx_pm_stats[] = {
+ "Read:", "Write bypass:", "Write mem:", "Bypass + mem:"
+ };
+ static const char * const rx_pm_stats[] = {
+ "Read:", "Write bypass:", "Write mem:", "Flush:"
+ };
+
+ int i;
+ u32 tx_cnt[PM_NSTATS], rx_cnt[PM_NSTATS];
+ u64 tx_cyc[PM_NSTATS], rx_cyc[PM_NSTATS];
+ struct adapter *adap = seq->private;
+
+ t4_pmtx_get_stats(adap, tx_cnt, tx_cyc);
+ t4_pmrx_get_stats(adap, rx_cnt, rx_cyc);
+
+ seq_printf(seq, "%13s %10s %20s\n", " ", "Tx pcmds", "Tx bytes");
+ for (i = 0; i < PM_NSTATS - 1; i++)
+ seq_printf(seq, "%-13s %10u %20llu\n",
+ tx_pm_stats[i], tx_cnt[i], tx_cyc[i]);
+
+ seq_printf(seq, "%13s %10s %20s\n", " ", "Rx pcmds", "Rx bytes");
+ for (i = 0; i < PM_NSTATS - 1; i++)
+ seq_printf(seq, "%-13s %10u %20llu\n",
+ rx_pm_stats[i], rx_cnt[i], rx_cyc[i]);
+ return 0;
+}
+
+static int pm_stats_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, pm_stats_show, inode->i_private);
+}
+
+static ssize_t pm_stats_clear(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ struct adapter *adap = FILE_DATA(file)->i_private;
+
+ t4_write_reg(adap, PM_RX_STAT_CONFIG_A, 0);
+ t4_write_reg(adap, PM_TX_STAT_CONFIG_A, 0);
+ return count;
+}
+
+static const struct file_operations pm_stats_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = pm_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = pm_stats_clear
+};
+
+static int cctrl_tbl_show(struct seq_file *seq, void *v)
+{
+ static const char * const dec_fac[] = {
+ "0.5", "0.5625", "0.625", "0.6875", "0.75", "0.8125", "0.875",
+ "0.9375" };
+
+ int i;
+ u16 incr[NMTUS][NCCTRL_WIN];
+ struct adapter *adap = seq->private;
+
+ t4_read_cong_tbl(adap, incr);
+
+ for (i = 0; i < NCCTRL_WIN; ++i) {
+ seq_printf(seq, "%2d: %4u %4u %4u %4u %4u %4u %4u %4u\n", i,
+ incr[0][i], incr[1][i], incr[2][i], incr[3][i],
+ incr[4][i], incr[5][i], incr[6][i], incr[7][i]);
+ seq_printf(seq, "%8u %4u %4u %4u %4u %4u %4u %4u %5u %s\n",
+ incr[8][i], incr[9][i], incr[10][i], incr[11][i],
+ incr[12][i], incr[13][i], incr[14][i], incr[15][i],
+ adap->params.a_wnd[i],
+ dec_fac[adap->params.b_wnd[i]]);
+ }
+ return 0;
+}
+
+DEFINE_SIMPLE_DEBUGFS_FILE(cctrl_tbl);
+
+/* Format a value in a unit that differs from the value's native unit by the
+ * given factor.
+ */
+static char *unit_conv(char *buf, size_t len, unsigned int val,
+ unsigned int factor)
+{
+ unsigned int rem = val % factor;
+
+ if (rem == 0) {
+ snprintf(buf, len, "%u", val / factor);
+ } else {
+ while (rem % 10 == 0)
+ rem /= 10;
+ snprintf(buf, len, "%u.%u", val / factor, rem);
+ }
+ return buf;
+}
+
+static int clk_show(struct seq_file *seq, void *v)
+{
+ char buf[32];
+ struct adapter *adap = seq->private;
+ unsigned int cclk_ps = 1000000000 / adap->params.vpd.cclk; /* in ps */
+ u32 res = t4_read_reg(adap, TP_TIMER_RESOLUTION_A);
+ unsigned int tre = TIMERRESOLUTION_G(res);
+ unsigned int dack_re = DELAYEDACKRESOLUTION_G(res);
+ unsigned long long tp_tick_us = (cclk_ps << tre) / 1000000; /* in us */
+
+ seq_printf(seq, "Core clock period: %s ns\n",
+ unit_conv(buf, sizeof(buf), cclk_ps, 1000));
+ seq_printf(seq, "TP timer tick: %s us\n",
+ unit_conv(buf, sizeof(buf), (cclk_ps << tre), 1000000));
+ seq_printf(seq, "TCP timestamp tick: %s us\n",
+ unit_conv(buf, sizeof(buf),
+ (cclk_ps << TIMESTAMPRESOLUTION_G(res)), 1000000));
+ seq_printf(seq, "DACK tick: %s us\n",
+ unit_conv(buf, sizeof(buf), (cclk_ps << dack_re), 1000000));
+ seq_printf(seq, "DACK timer: %u us\n",
+ ((cclk_ps << dack_re) / 1000000) *
+ t4_read_reg(adap, TP_DACK_TIMER_A));
+ seq_printf(seq, "Retransmit min: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_RXT_MIN_A));
+ seq_printf(seq, "Retransmit max: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_RXT_MAX_A));
+ seq_printf(seq, "Persist timer min: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_PERS_MIN_A));
+ seq_printf(seq, "Persist timer max: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_PERS_MAX_A));
+ seq_printf(seq, "Keepalive idle timer: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_KEEP_IDLE_A));
+ seq_printf(seq, "Keepalive interval: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_KEEP_INTVL_A));
+ seq_printf(seq, "Initial SRTT: %llu us\n",
+ tp_tick_us * INITSRTT_G(t4_read_reg(adap, TP_INIT_SRTT_A)));
+ seq_printf(seq, "FINWAIT2 timer: %llu us\n",
+ tp_tick_us * t4_read_reg(adap, TP_FINWAIT2_TIMER_A));
+
+ return 0;
+}
+
+DEFINE_SIMPLE_DEBUGFS_FILE(clk);
+
+/* Firmware Device Log dump. */
+static const char * const devlog_level_strings[] = {
+ [FW_DEVLOG_LEVEL_EMERG] = "EMERG",
+ [FW_DEVLOG_LEVEL_CRIT] = "CRIT",
+ [FW_DEVLOG_LEVEL_ERR] = "ERR",
+ [FW_DEVLOG_LEVEL_NOTICE] = "NOTICE",
+ [FW_DEVLOG_LEVEL_INFO] = "INFO",
+ [FW_DEVLOG_LEVEL_DEBUG] = "DEBUG"
+};
+
+static const char * const devlog_facility_strings[] = {
+ [FW_DEVLOG_FACILITY_CORE] = "CORE",
+ [FW_DEVLOG_FACILITY_SCHED] = "SCHED",
+ [FW_DEVLOG_FACILITY_TIMER] = "TIMER",
+ [FW_DEVLOG_FACILITY_RES] = "RES",
+ [FW_DEVLOG_FACILITY_HW] = "HW",
+ [FW_DEVLOG_FACILITY_FLR] = "FLR",
+ [FW_DEVLOG_FACILITY_DMAQ] = "DMAQ",
+ [FW_DEVLOG_FACILITY_PHY] = "PHY",
+ [FW_DEVLOG_FACILITY_MAC] = "MAC",
+ [FW_DEVLOG_FACILITY_PORT] = "PORT",
+ [FW_DEVLOG_FACILITY_VI] = "VI",
+ [FW_DEVLOG_FACILITY_FILTER] = "FILTER",
+ [FW_DEVLOG_FACILITY_ACL] = "ACL",
+ [FW_DEVLOG_FACILITY_TM] = "TM",
+ [FW_DEVLOG_FACILITY_QFC] = "QFC",
+ [FW_DEVLOG_FACILITY_DCB] = "DCB",
+ [FW_DEVLOG_FACILITY_ETH] = "ETH",
+ [FW_DEVLOG_FACILITY_OFLD] = "OFLD",
+ [FW_DEVLOG_FACILITY_RI] = "RI",
+ [FW_DEVLOG_FACILITY_ISCSI] = "ISCSI",
+ [FW_DEVLOG_FACILITY_FCOE] = "FCOE",
+ [FW_DEVLOG_FACILITY_FOISCSI] = "FOISCSI",
+ [FW_DEVLOG_FACILITY_FOFCOE] = "FOFCOE"
+};
+
+/* Information gathered by Device Log Open routine for the display routine.
+ */
+struct devlog_info {
+ unsigned int nentries; /* number of entries in log[] */
+ unsigned int first; /* first [temporal] entry in log[] */
+ struct fw_devlog_e log[0]; /* Firmware Device Log */
+};
+
+/* Dump a Firmaware Device Log entry.
+ */
+static int devlog_show(struct seq_file *seq, void *v)
+{
+ if (v == SEQ_START_TOKEN)
+ seq_printf(seq, "%10s %15s %8s %8s %s\n",
+ "Seq#", "Tstamp", "Level", "Facility", "Message");
+ else {
+ struct devlog_info *dinfo = seq->private;
+ int fidx = (uintptr_t)v - 2;
+ unsigned long index;
+ struct fw_devlog_e *e;
+
+ /* Get a pointer to the log entry to display. Skip unused log
+ * entries.
+ */
+ index = dinfo->first + fidx;
+ if (index >= dinfo->nentries)
+ index -= dinfo->nentries;
+ e = &dinfo->log[index];
+ if (e->timestamp == 0)
+ return 0;
+
+ /* Print the message. This depends on the firmware using
+ * exactly the same formating strings as the kernel so we may
+ * eventually have to put a format interpreter in here ...
+ */
+ seq_printf(seq, "%10d %15llu %8s %8s ",
+ e->seqno, e->timestamp,
+ (e->level < ARRAY_SIZE(devlog_level_strings)
+ ? devlog_level_strings[e->level]
+ : "UNKNOWN"),
+ (e->facility < ARRAY_SIZE(devlog_facility_strings)
+ ? devlog_facility_strings[e->facility]
+ : "UNKNOWN"));
+ seq_printf(seq, e->fmt, e->params[0], e->params[1],
+ e->params[2], e->params[3], e->params[4],
+ e->params[5], e->params[6], e->params[7]);
+ }
+ return 0;
+}
+
+/* Sequential File Operations for Device Log.
+ */
+static inline void *devlog_get_idx(struct devlog_info *dinfo, loff_t pos)
+{
+ if (pos > dinfo->nentries)
+ return NULL;
+
+ return (void *)(uintptr_t)(pos + 1);
+}
+
+static void *devlog_start(struct seq_file *seq, loff_t *pos)
+{
+ struct devlog_info *dinfo = seq->private;
+
+ return (*pos
+ ? devlog_get_idx(dinfo, *pos)
+ : SEQ_START_TOKEN);
+}
+
+static void *devlog_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ struct devlog_info *dinfo = seq->private;
+
+ (*pos)++;
+ return devlog_get_idx(dinfo, *pos);
+}
+
+static void devlog_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations devlog_seq_ops = {
+ .start = devlog_start,
+ .next = devlog_next,
+ .stop = devlog_stop,
+ .show = devlog_show
+};
+
+/* Set up for reading the firmware's device log. We read the entire log here
+ * and then display it incrementally in devlog_show().
+ */
+static int devlog_open(struct inode *inode, struct file *file)
+{
+ struct adapter *adap = inode->i_private;
+ struct devlog_params *dparams = &adap->params.devlog;
+ struct devlog_info *dinfo;
+ unsigned int index;
+ u32 fseqno;
+ int ret;
+
+ /* If we don't know where the log is we can't do anything.
+ */
+ if (dparams->start == 0)
+ return -ENXIO;
+
+ /* Allocate the space to read in the firmware's device log and set up
+ * for the iterated call to our display function.
+ */
+ dinfo = __seq_open_private(file, &devlog_seq_ops,
+ sizeof(*dinfo) + dparams->size);
+ if (!dinfo)
+ return -ENOMEM;
+
+ /* Record the basic log buffer information and read in the raw log.
+ */
+ dinfo->nentries = (dparams->size / sizeof(struct fw_devlog_e));
+ dinfo->first = 0;
+ spin_lock(&adap->win0_lock);
+ ret = t4_memory_rw(adap, adap->params.drv_memwin, dparams->memtype,
+ dparams->start, dparams->size, (__be32 *)dinfo->log,
+ T4_MEMORY_READ);
+ spin_unlock(&adap->win0_lock);
+ if (ret) {
+ seq_release_private(inode, file);
+ return ret;
+ }
+
+ /* Translate log multi-byte integral elements into host native format
+ * and determine where the first entry in the log is.
+ */
+ for (fseqno = ~((u32)0), index = 0; index < dinfo->nentries; index++) {
+ struct fw_devlog_e *e = &dinfo->log[index];
+ int i;
+ __u32 seqno;
+
+ if (e->timestamp == 0)
+ continue;
+
+ e->timestamp = (__force __be64)be64_to_cpu(e->timestamp);
+ seqno = be32_to_cpu(e->seqno);
+ for (i = 0; i < 8; i++)
+ e->params[i] =
+ (__force __be32)be32_to_cpu(e->params[i]);
+
+ if (seqno < fseqno) {
+ fseqno = seqno;
+ dinfo->first = index;
+ }
+ }
+ return 0;
+}
+
+static const struct file_operations devlog_fops = {
+ .owner = THIS_MODULE,
+ .open = devlog_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+static int mbox_show(struct seq_file *seq, void *v)
+{
+ static const char * const owner[] = { "none", "FW", "driver",
+ "unknown" };
+
+ int i;
+ unsigned int mbox = (uintptr_t)seq->private & 7;
+ struct adapter *adap = seq->private - mbox;
+ void __iomem *addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A);
+ unsigned int ctrl_reg = (is_t4(adap->params.chip)
+ ? CIM_PF_MAILBOX_CTRL_A
+ : CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A);
+ void __iomem *ctrl = adap->regs + PF_REG(mbox, ctrl_reg);
+
+ i = MBOWNER_G(readl(ctrl));
+ seq_printf(seq, "mailbox owned by %s\n\n", owner[i]);
+
+ for (i = 0; i < MBOX_LEN; i += 8)
+ seq_printf(seq, "%016llx\n",
+ (unsigned long long)readq(addr + i));
+ return 0;
+}
+
+static int mbox_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, mbox_show, inode->i_private);
+}
+
+static ssize_t mbox_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ int i;
+ char c = '\n', s[256];
+ unsigned long long data[8];
+ const struct inode *ino;
+ unsigned int mbox;
+ struct adapter *adap;
+ void __iomem *addr;
+ void __iomem *ctrl;
+
+ if (count > sizeof(s) - 1 || !count)
+ return -EINVAL;
+ if (copy_from_user(s, buf, count))
+ return -EFAULT;
+ s[count] = '\0';
+
+ if (sscanf(s, "%llx %llx %llx %llx %llx %llx %llx %llx%c", &data[0],
+ &data[1], &data[2], &data[3], &data[4], &data[5], &data[6],
+ &data[7], &c) < 8 || c != '\n')
+ return -EINVAL;
+
+ ino = FILE_DATA(file);
+ mbox = (uintptr_t)ino->i_private & 7;
+ adap = ino->i_private - mbox;
+ addr = adap->regs + PF_REG(mbox, CIM_PF_MAILBOX_DATA_A);
+ ctrl = addr + MBOX_LEN;
+
+ if (MBOWNER_G(readl(ctrl)) != X_MBOWNER_PL)
+ return -EBUSY;
+
+ for (i = 0; i < 8; i++)
+ writeq(data[i], addr + 8 * i);
+
+ writel(MBMSGVALID_F | MBOWNER_V(X_MBOWNER_FW), ctrl);
+ return count;
+}
+
+static const struct file_operations mbox_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = mbox_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = mbox_write
+};
+
+static ssize_t flash_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ loff_t pos = *ppos;
+ loff_t avail = FILE_DATA(file)->i_size;
+ struct adapter *adap = file->private_data;
+
+ if (pos < 0)
+ return -EINVAL;
+ if (pos >= avail)
+ return 0;
+ if (count > avail - pos)
+ count = avail - pos;
+
+ while (count) {
+ size_t len;
+ int ret, ofst;
+ u8 data[256];
+
+ ofst = pos & 3;
+ len = min(count + ofst, sizeof(data));
+ ret = t4_read_flash(adap, pos - ofst, (len + 3) / 4,
+ (u32 *)data, 1);
+ if (ret)
+ return ret;
+
+ len -= ofst;
+ if (copy_to_user(buf, data + ofst, len))
+ return -EFAULT;
+
+ buf += len;
+ pos += len;
+ count -= len;
+ }
+ count = pos - *ppos;
+ *ppos = pos;
+ return count;
+}
+
+static const struct file_operations flash_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = mem_open,
+ .read = flash_read,
+};
+
+static inline void tcamxy2valmask(u64 x, u64 y, u8 *addr, u64 *mask)
+{
+ *mask = x | y;
+ y = (__force u64)cpu_to_be64(y);
+ memcpy(addr, (char *)&y + 2, ETH_ALEN);
+}
+
+static int mps_tcam_show(struct seq_file *seq, void *v)
+{
+ if (v == SEQ_START_TOKEN)
+ seq_puts(seq, "Idx Ethernet address Mask Vld Ports PF"
+ " VF Replication "
+ "P0 P1 P2 P3 ML\n");
+ else {
+ u64 mask;
+ u8 addr[ETH_ALEN];
+ struct adapter *adap = seq->private;
+ unsigned int idx = (uintptr_t)v - 2;
+ u64 tcamy = t4_read_reg64(adap, MPS_CLS_TCAM_Y_L(idx));
+ u64 tcamx = t4_read_reg64(adap, MPS_CLS_TCAM_X_L(idx));
+ u32 cls_lo = t4_read_reg(adap, MPS_CLS_SRAM_L(idx));
+ u32 cls_hi = t4_read_reg(adap, MPS_CLS_SRAM_H(idx));
+ u32 rplc[4] = {0, 0, 0, 0};
+
+ if (tcamx & tcamy) {
+ seq_printf(seq, "%3u -\n", idx);
+ goto out;
+ }
+
+ if (cls_lo & REPLICATE_F) {
+ struct fw_ldst_cmd ldst_cmd;
+ int ret;
+
+ memset(&ldst_cmd, 0, sizeof(ldst_cmd));
+ ldst_cmd.op_to_addrspace =
+ htonl(FW_CMD_OP_V(FW_LDST_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F |
+ FW_LDST_CMD_ADDRSPACE_V(
+ FW_LDST_ADDRSPC_MPS));
+ ldst_cmd.cycles_to_len16 = htonl(FW_LEN16(ldst_cmd));
+ ldst_cmd.u.mps.fid_ctl =
+ htons(FW_LDST_CMD_FID_V(FW_LDST_MPS_RPLC) |
+ FW_LDST_CMD_CTL_V(idx));
+ ret = t4_wr_mbox(adap, adap->mbox, &ldst_cmd,
+ sizeof(ldst_cmd), &ldst_cmd);
+ if (ret)
+ dev_warn(adap->pdev_dev, "Can't read MPS "
+ "replication map for idx %d: %d\n",
+ idx, -ret);
+ else {
+ rplc[0] = ntohl(ldst_cmd.u.mps.rplc31_0);
+ rplc[1] = ntohl(ldst_cmd.u.mps.rplc63_32);
+ rplc[2] = ntohl(ldst_cmd.u.mps.rplc95_64);
+ rplc[3] = ntohl(ldst_cmd.u.mps.rplc127_96);
+ }
+ }
+
+ tcamxy2valmask(tcamx, tcamy, addr, &mask);
+ seq_printf(seq, "%3u %02x:%02x:%02x:%02x:%02x:%02x %012llx"
+ "%3c %#x%4u%4d",
+ idx, addr[0], addr[1], addr[2], addr[3], addr[4],
+ addr[5], (unsigned long long)mask,
+ (cls_lo & SRAM_VLD_F) ? 'Y' : 'N', PORTMAP_G(cls_hi),
+ PF_G(cls_lo),
+ (cls_lo & VF_VALID_F) ? VF_G(cls_lo) : -1);
+ if (cls_lo & REPLICATE_F)
+ seq_printf(seq, " %08x %08x %08x %08x",
+ rplc[3], rplc[2], rplc[1], rplc[0]);
+ else
+ seq_printf(seq, "%36c", ' ');
+ seq_printf(seq, "%4u%3u%3u%3u %#x\n",
+ SRAM_PRIO0_G(cls_lo), SRAM_PRIO1_G(cls_lo),
+ SRAM_PRIO2_G(cls_lo), SRAM_PRIO3_G(cls_lo),
+ (cls_lo >> MULTILISTEN0_S) & 0xf);
+ }
+out: return 0;
+}
+
+static inline void *mps_tcam_get_idx(struct seq_file *seq, loff_t pos)
+{
+ struct adapter *adap = seq->private;
+ int max_mac_addr = is_t4(adap->params.chip) ?
+ NUM_MPS_CLS_SRAM_L_INSTANCES :
+ NUM_MPS_T5_CLS_SRAM_L_INSTANCES;
+ return ((pos <= max_mac_addr) ? (void *)(uintptr_t)(pos + 1) : NULL);
+}
+
+static void *mps_tcam_start(struct seq_file *seq, loff_t *pos)
+{
+ return *pos ? mps_tcam_get_idx(seq, *pos) : SEQ_START_TOKEN;
+}
+
+static void *mps_tcam_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ ++*pos;
+ return mps_tcam_get_idx(seq, *pos);
+}
+
+static void mps_tcam_stop(struct seq_file *seq, void *v)
+{
+}
+
+static const struct seq_operations mps_tcam_seq_ops = {
+ .start = mps_tcam_start,
+ .next = mps_tcam_next,
+ .stop = mps_tcam_stop,
+ .show = mps_tcam_show
+};
+
+static int mps_tcam_open(struct inode *inode, struct file *file)
+{
+ int res = seq_open(file, &mps_tcam_seq_ops);
+
+ if (!res) {
+ struct seq_file *seq = file->private_data;
+
+ seq->private = inode->i_private;
+ }
+ return res;
+}
+
+static const struct file_operations mps_tcam_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = mps_tcam_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+/* Display various sensor information.
+ */
+static int sensors_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adap = seq->private;
+ u32 param[7], val[7];
+ int ret;
+
+ /* Note that if the sensors haven't been initialized and turned on
+ * we'll get values of 0, so treat those as "<unknown>" ...
+ */
+ param[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) |
+ FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_TMP));
+ param[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_DIAG) |
+ FW_PARAMS_PARAM_Y_V(FW_PARAM_DEV_DIAG_VDD));
+ ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2,
+ param, val);
+
+ if (ret < 0 || val[0] == 0)
+ seq_puts(seq, "Temperature: <unknown>\n");
+ else
+ seq_printf(seq, "Temperature: %dC\n", val[0]);
+
+ if (ret < 0 || val[1] == 0)
+ seq_puts(seq, "Core VDD: <unknown>\n");
+ else
+ seq_printf(seq, "Core VDD: %dmV\n", val[1]);
+
+ return 0;
+}
+
+DEFINE_SIMPLE_DEBUGFS_FILE(sensors);
+
+#if IS_ENABLED(CONFIG_IPV6)
+static int clip_tbl_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, clip_tbl_show, inode->i_private);
+}
+
+static const struct file_operations clip_tbl_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = clip_tbl_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release
+};
+#endif
+
+/*RSS Table.
+ */
+
+static int rss_show(struct seq_file *seq, void *v, int idx)
+{
+ u16 *entry = v;
+
+ seq_printf(seq, "%4d: %4u %4u %4u %4u %4u %4u %4u %4u\n",
+ idx * 8, entry[0], entry[1], entry[2], entry[3], entry[4],
+ entry[5], entry[6], entry[7]);
+ return 0;
+}
+
+static int rss_open(struct inode *inode, struct file *file)
+{
+ int ret;
+ struct seq_tab *p;
+ struct adapter *adap = inode->i_private;
+
+ p = seq_open_tab(file, RSS_NENTRIES / 8, 8 * sizeof(u16), 0, rss_show);
+ if (!p)
+ return -ENOMEM;
+
+ ret = t4_read_rss(adap, (u16 *)p->data);
+ if (ret)
+ seq_release_private(inode, file);
+
+ return ret;
+}
+
+static const struct file_operations rss_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = rss_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+/* RSS Configuration.
+ */
+
+/* Small utility function to return the strings "yes" or "no" if the supplied
+ * argument is non-zero.
+ */
+static const char *yesno(int x)
+{
+ static const char *yes = "yes";
+ static const char *no = "no";
+
+ return x ? yes : no;
+}
+
+static int rss_config_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adapter = seq->private;
+ static const char * const keymode[] = {
+ "global",
+ "global and per-VF scramble",
+ "per-PF and per-VF scramble",
+ "per-VF and per-VF scramble",
+ };
+ u32 rssconf;
+
+ rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_A);
+ seq_printf(seq, "TP_RSS_CONFIG: %#x\n", rssconf);
+ seq_printf(seq, " Tnl4TupEnIpv6: %3s\n", yesno(rssconf &
+ TNL4TUPENIPV6_F));
+ seq_printf(seq, " Tnl2TupEnIpv6: %3s\n", yesno(rssconf &
+ TNL2TUPENIPV6_F));
+ seq_printf(seq, " Tnl4TupEnIpv4: %3s\n", yesno(rssconf &
+ TNL4TUPENIPV4_F));
+ seq_printf(seq, " Tnl2TupEnIpv4: %3s\n", yesno(rssconf &
+ TNL2TUPENIPV4_F));
+ seq_printf(seq, " TnlTcpSel: %3s\n", yesno(rssconf & TNLTCPSEL_F));
+ seq_printf(seq, " TnlIp6Sel: %3s\n", yesno(rssconf & TNLIP6SEL_F));
+ seq_printf(seq, " TnlVrtSel: %3s\n", yesno(rssconf & TNLVRTSEL_F));
+ seq_printf(seq, " TnlMapEn: %3s\n", yesno(rssconf & TNLMAPEN_F));
+ seq_printf(seq, " OfdHashSave: %3s\n", yesno(rssconf &
+ OFDHASHSAVE_F));
+ seq_printf(seq, " OfdVrtSel: %3s\n", yesno(rssconf & OFDVRTSEL_F));
+ seq_printf(seq, " OfdMapEn: %3s\n", yesno(rssconf & OFDMAPEN_F));
+ seq_printf(seq, " OfdLkpEn: %3s\n", yesno(rssconf & OFDLKPEN_F));
+ seq_printf(seq, " Syn4TupEnIpv6: %3s\n", yesno(rssconf &
+ SYN4TUPENIPV6_F));
+ seq_printf(seq, " Syn2TupEnIpv6: %3s\n", yesno(rssconf &
+ SYN2TUPENIPV6_F));
+ seq_printf(seq, " Syn4TupEnIpv4: %3s\n", yesno(rssconf &
+ SYN4TUPENIPV4_F));
+ seq_printf(seq, " Syn2TupEnIpv4: %3s\n", yesno(rssconf &
+ SYN2TUPENIPV4_F));
+ seq_printf(seq, " Syn4TupEnIpv6: %3s\n", yesno(rssconf &
+ SYN4TUPENIPV6_F));
+ seq_printf(seq, " SynIp6Sel: %3s\n", yesno(rssconf & SYNIP6SEL_F));
+ seq_printf(seq, " SynVrt6Sel: %3s\n", yesno(rssconf & SYNVRTSEL_F));
+ seq_printf(seq, " SynMapEn: %3s\n", yesno(rssconf & SYNMAPEN_F));
+ seq_printf(seq, " SynLkpEn: %3s\n", yesno(rssconf & SYNLKPEN_F));
+ seq_printf(seq, " ChnEn: %3s\n", yesno(rssconf &
+ CHANNELENABLE_F));
+ seq_printf(seq, " PrtEn: %3s\n", yesno(rssconf &
+ PORTENABLE_F));
+ seq_printf(seq, " TnlAllLkp: %3s\n", yesno(rssconf &
+ TNLALLLOOKUP_F));
+ seq_printf(seq, " VrtEn: %3s\n", yesno(rssconf &
+ VIRTENABLE_F));
+ seq_printf(seq, " CngEn: %3s\n", yesno(rssconf &
+ CONGESTIONENABLE_F));
+ seq_printf(seq, " HashToeplitz: %3s\n", yesno(rssconf &
+ HASHTOEPLITZ_F));
+ seq_printf(seq, " Udp4En: %3s\n", yesno(rssconf & UDPENABLE_F));
+ seq_printf(seq, " Disable: %3s\n", yesno(rssconf & DISABLE_F));
+
+ seq_puts(seq, "\n");
+
+ rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_TNL_A);
+ seq_printf(seq, "TP_RSS_CONFIG_TNL: %#x\n", rssconf);
+ seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf));
+ seq_printf(seq, " MaskFilter: %3d\n", MASKFILTER_G(rssconf));
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) > CHELSIO_T5) {
+ seq_printf(seq, " HashAll: %3s\n",
+ yesno(rssconf & HASHALL_F));
+ seq_printf(seq, " HashEth: %3s\n",
+ yesno(rssconf & HASHETH_F));
+ }
+ seq_printf(seq, " UseWireCh: %3s\n", yesno(rssconf & USEWIRECH_F));
+
+ seq_puts(seq, "\n");
+
+ rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_OFD_A);
+ seq_printf(seq, "TP_RSS_CONFIG_OFD: %#x\n", rssconf);
+ seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf));
+ seq_printf(seq, " RRCplMapEn: %3s\n", yesno(rssconf &
+ RRCPLMAPEN_F));
+ seq_printf(seq, " RRCplQueWidth: %3d\n", RRCPLQUEWIDTH_G(rssconf));
+
+ seq_puts(seq, "\n");
+
+ rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_SYN_A);
+ seq_printf(seq, "TP_RSS_CONFIG_SYN: %#x\n", rssconf);
+ seq_printf(seq, " MaskSize: %3d\n", MASKSIZE_G(rssconf));
+ seq_printf(seq, " UseWireCh: %3s\n", yesno(rssconf & USEWIRECH_F));
+
+ seq_puts(seq, "\n");
+
+ rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A);
+ seq_printf(seq, "TP_RSS_CONFIG_VRT: %#x\n", rssconf);
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) > CHELSIO_T5) {
+ seq_printf(seq, " KeyWrAddrX: %3d\n",
+ KEYWRADDRX_G(rssconf));
+ seq_printf(seq, " KeyExtend: %3s\n",
+ yesno(rssconf & KEYEXTEND_F));
+ }
+ seq_printf(seq, " VfRdRg: %3s\n", yesno(rssconf & VFRDRG_F));
+ seq_printf(seq, " VfRdEn: %3s\n", yesno(rssconf & VFRDEN_F));
+ seq_printf(seq, " VfPerrEn: %3s\n", yesno(rssconf & VFPERREN_F));
+ seq_printf(seq, " KeyPerrEn: %3s\n", yesno(rssconf & KEYPERREN_F));
+ seq_printf(seq, " DisVfVlan: %3s\n", yesno(rssconf &
+ DISABLEVLAN_F));
+ seq_printf(seq, " EnUpSwt: %3s\n", yesno(rssconf & ENABLEUP0_F));
+ seq_printf(seq, " HashDelay: %3d\n", HASHDELAY_G(rssconf));
+ if (CHELSIO_CHIP_VERSION(adapter->params.chip) <= CHELSIO_T5)
+ seq_printf(seq, " VfWrAddr: %3d\n", VFWRADDR_G(rssconf));
+ seq_printf(seq, " KeyMode: %s\n", keymode[KEYMODE_G(rssconf)]);
+ seq_printf(seq, " VfWrEn: %3s\n", yesno(rssconf & VFWREN_F));
+ seq_printf(seq, " KeyWrEn: %3s\n", yesno(rssconf & KEYWREN_F));
+ seq_printf(seq, " KeyWrAddr: %3d\n", KEYWRADDR_G(rssconf));
+
+ seq_puts(seq, "\n");
+
+ rssconf = t4_read_reg(adapter, TP_RSS_CONFIG_CNG_A);
+ seq_printf(seq, "TP_RSS_CONFIG_CNG: %#x\n", rssconf);
+ seq_printf(seq, " ChnCount3: %3s\n", yesno(rssconf & CHNCOUNT3_F));
+ seq_printf(seq, " ChnCount2: %3s\n", yesno(rssconf & CHNCOUNT2_F));
+ seq_printf(seq, " ChnCount1: %3s\n", yesno(rssconf & CHNCOUNT1_F));
+ seq_printf(seq, " ChnCount0: %3s\n", yesno(rssconf & CHNCOUNT0_F));
+ seq_printf(seq, " ChnUndFlow3: %3s\n", yesno(rssconf &
+ CHNUNDFLOW3_F));
+ seq_printf(seq, " ChnUndFlow2: %3s\n", yesno(rssconf &
+ CHNUNDFLOW2_F));
+ seq_printf(seq, " ChnUndFlow1: %3s\n", yesno(rssconf &
+ CHNUNDFLOW1_F));
+ seq_printf(seq, " ChnUndFlow0: %3s\n", yesno(rssconf &
+ CHNUNDFLOW0_F));
+ seq_printf(seq, " RstChn3: %3s\n", yesno(rssconf & RSTCHN3_F));
+ seq_printf(seq, " RstChn2: %3s\n", yesno(rssconf & RSTCHN2_F));
+ seq_printf(seq, " RstChn1: %3s\n", yesno(rssconf & RSTCHN1_F));
+ seq_printf(seq, " RstChn0: %3s\n", yesno(rssconf & RSTCHN0_F));
+ seq_printf(seq, " UpdVld: %3s\n", yesno(rssconf & UPDVLD_F));
+ seq_printf(seq, " Xoff: %3s\n", yesno(rssconf & XOFF_F));
+ seq_printf(seq, " UpdChn3: %3s\n", yesno(rssconf & UPDCHN3_F));
+ seq_printf(seq, " UpdChn2: %3s\n", yesno(rssconf & UPDCHN2_F));
+ seq_printf(seq, " UpdChn1: %3s\n", yesno(rssconf & UPDCHN1_F));
+ seq_printf(seq, " UpdChn0: %3s\n", yesno(rssconf & UPDCHN0_F));
+ seq_printf(seq, " Queue: %3d\n", QUEUE_G(rssconf));
+
+ return 0;
+}
+
+DEFINE_SIMPLE_DEBUGFS_FILE(rss_config);
+
+/* RSS Secret Key.
+ */
+
+static int rss_key_show(struct seq_file *seq, void *v)
+{
+ u32 key[10];
+
+ t4_read_rss_key(seq->private, key);
+ seq_printf(seq, "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x\n",
+ key[9], key[8], key[7], key[6], key[5], key[4], key[3],
+ key[2], key[1], key[0]);
+ return 0;
+}
+
+static int rss_key_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, rss_key_show, inode->i_private);
+}
+
+static ssize_t rss_key_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *pos)
+{
+ int i, j;
+ u32 key[10];
+ char s[100], *p;
+ struct adapter *adap = FILE_DATA(file)->i_private;
+
+ if (count > sizeof(s) - 1)
+ return -EINVAL;
+ if (copy_from_user(s, buf, count))
+ return -EFAULT;
+ for (i = count; i > 0 && isspace(s[i - 1]); i--)
+ ;
+ s[i] = '\0';
+
+ for (p = s, i = 9; i >= 0; i--) {
+ key[i] = 0;
+ for (j = 0; j < 8; j++, p++) {
+ if (!isxdigit(*p))
+ return -EINVAL;
+ key[i] = (key[i] << 4) | hex2val(*p);
+ }
+ }
+
+ t4_write_rss_key(adap, key, -1);
+ return count;
+}
+
+static const struct file_operations rss_key_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = rss_key_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+ .write = rss_key_write
+};
+
+/* PF RSS Configuration.
+ */
+
+struct rss_pf_conf {
+ u32 rss_pf_map;
+ u32 rss_pf_mask;
+ u32 rss_pf_config;
+};
+
+static int rss_pf_config_show(struct seq_file *seq, void *v, int idx)
+{
+ struct rss_pf_conf *pfconf;
+
+ if (v == SEQ_START_TOKEN) {
+ /* use the 0th entry to dump the PF Map Index Size */
+ pfconf = seq->private + offsetof(struct seq_tab, data);
+ seq_printf(seq, "PF Map Index Size = %d\n\n",
+ LKPIDXSIZE_G(pfconf->rss_pf_map));
+
+ seq_puts(seq, " RSS PF VF Hash Tuple Enable Default\n");
+ seq_puts(seq, " Enable IPF Mask Mask IPv6 IPv4 UDP Queue\n");
+ seq_puts(seq, " PF Map Chn Prt Map Size Size Four Two Four Two Four Ch1 Ch0\n");
+ } else {
+ #define G_PFnLKPIDX(map, n) \
+ (((map) >> PF1LKPIDX_S*(n)) & PF0LKPIDX_M)
+ #define G_PFnMSKSIZE(mask, n) \
+ (((mask) >> PF1MSKSIZE_S*(n)) & PF1MSKSIZE_M)
+
+ pfconf = v;
+ seq_printf(seq, "%3d %3s %3s %3s %3d %3d %3d %3s %3s %3s %3s %3s %3d %3d\n",
+ idx,
+ yesno(pfconf->rss_pf_config & MAPENABLE_F),
+ yesno(pfconf->rss_pf_config & CHNENABLE_F),
+ yesno(pfconf->rss_pf_config & PRTENABLE_F),
+ G_PFnLKPIDX(pfconf->rss_pf_map, idx),
+ G_PFnMSKSIZE(pfconf->rss_pf_mask, idx),
+ IVFWIDTH_G(pfconf->rss_pf_config),
+ yesno(pfconf->rss_pf_config & IP6FOURTUPEN_F),
+ yesno(pfconf->rss_pf_config & IP6TWOTUPEN_F),
+ yesno(pfconf->rss_pf_config & IP4FOURTUPEN_F),
+ yesno(pfconf->rss_pf_config & IP4TWOTUPEN_F),
+ yesno(pfconf->rss_pf_config & UDPFOURTUPEN_F),
+ CH1DEFAULTQUEUE_G(pfconf->rss_pf_config),
+ CH0DEFAULTQUEUE_G(pfconf->rss_pf_config));
+
+ #undef G_PFnLKPIDX
+ #undef G_PFnMSKSIZE
+ }
+ return 0;
+}
+
+static int rss_pf_config_open(struct inode *inode, struct file *file)
+{
+ struct adapter *adapter = inode->i_private;
+ struct seq_tab *p;
+ u32 rss_pf_map, rss_pf_mask;
+ struct rss_pf_conf *pfconf;
+ int pf;
+
+ p = seq_open_tab(file, 8, sizeof(*pfconf), 1, rss_pf_config_show);
+ if (!p)
+ return -ENOMEM;
+
+ pfconf = (struct rss_pf_conf *)p->data;
+ rss_pf_map = t4_read_rss_pf_map(adapter);
+ rss_pf_mask = t4_read_rss_pf_mask(adapter);
+ for (pf = 0; pf < 8; pf++) {
+ pfconf[pf].rss_pf_map = rss_pf_map;
+ pfconf[pf].rss_pf_mask = rss_pf_mask;
+ t4_read_rss_pf_config(adapter, pf, &pfconf[pf].rss_pf_config);
+ }
+ return 0;
+}
+
+static const struct file_operations rss_pf_config_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = rss_pf_config_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+/* VF RSS Configuration.
+ */
+
+struct rss_vf_conf {
+ u32 rss_vf_vfl;
+ u32 rss_vf_vfh;
+};
+
+static int rss_vf_config_show(struct seq_file *seq, void *v, int idx)
+{
+ if (v == SEQ_START_TOKEN) {
+ seq_puts(seq, " RSS Hash Tuple Enable\n");
+ seq_puts(seq, " Enable IVF Dis Enb IPv6 IPv4 UDP Def Secret Key\n");
+ seq_puts(seq, " VF Chn Prt Map VLAN uP Four Two Four Two Four Que Idx Hash\n");
+ } else {
+ struct rss_vf_conf *vfconf = v;
+
+ seq_printf(seq, "%3d %3s %3s %3d %3s %3s %3s %3s %3s %3s %3s %4d %3d %#10x\n",
+ idx,
+ yesno(vfconf->rss_vf_vfh & VFCHNEN_F),
+ yesno(vfconf->rss_vf_vfh & VFPRTEN_F),
+ VFLKPIDX_G(vfconf->rss_vf_vfh),
+ yesno(vfconf->rss_vf_vfh & VFVLNEX_F),
+ yesno(vfconf->rss_vf_vfh & VFUPEN_F),
+ yesno(vfconf->rss_vf_vfh & VFIP4FOURTUPEN_F),
+ yesno(vfconf->rss_vf_vfh & VFIP6TWOTUPEN_F),
+ yesno(vfconf->rss_vf_vfh & VFIP4FOURTUPEN_F),
+ yesno(vfconf->rss_vf_vfh & VFIP4TWOTUPEN_F),
+ yesno(vfconf->rss_vf_vfh & ENABLEUDPHASH_F),
+ DEFAULTQUEUE_G(vfconf->rss_vf_vfh),
+ KEYINDEX_G(vfconf->rss_vf_vfh),
+ vfconf->rss_vf_vfl);
+ }
+ return 0;
+}
+
+static int rss_vf_config_open(struct inode *inode, struct file *file)
+{
+ struct adapter *adapter = inode->i_private;
+ struct seq_tab *p;
+ struct rss_vf_conf *vfconf;
+ int vf;
+
+ p = seq_open_tab(file, 128, sizeof(*vfconf), 1, rss_vf_config_show);
+ if (!p)
+ return -ENOMEM;
+
+ vfconf = (struct rss_vf_conf *)p->data;
+ for (vf = 0; vf < 128; vf++) {
+ t4_read_rss_vf_config(adapter, vf, &vfconf[vf].rss_vf_vfl,
+ &vfconf[vf].rss_vf_vfh);
+ }
+ return 0;
+}
+
+static const struct file_operations rss_vf_config_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = rss_vf_config_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release_private
+};
+
+/**
+ * ethqset2pinfo - return port_info of an Ethernet Queue Set
+ * @adap: the adapter
+ * @qset: Ethernet Queue Set
+ */
+static inline struct port_info *ethqset2pinfo(struct adapter *adap, int qset)
+{
+ int pidx;
+
+ for_each_port(adap, pidx) {
+ struct port_info *pi = adap2pinfo(adap, pidx);
+
+ if (qset >= pi->first_qset &&
+ qset < pi->first_qset + pi->nqsets)
+ return pi;
+ }
+
+ /* should never happen! */
+ BUG_ON(1);
+ return NULL;
+}
+
+static int sge_qinfo_show(struct seq_file *seq, void *v)
+{
+ struct adapter *adap = seq->private;
+ int eth_entries = DIV_ROUND_UP(adap->sge.ethqsets, 4);
+ int toe_entries = DIV_ROUND_UP(adap->sge.ofldqsets, 4);
+ int rdma_entries = DIV_ROUND_UP(adap->sge.rdmaqs, 4);
+ int ciq_entries = DIV_ROUND_UP(adap->sge.rdmaciqs, 4);
+ int ctrl_entries = DIV_ROUND_UP(MAX_CTRL_QUEUES, 4);
+ int i, r = (uintptr_t)v - 1;
+ int toe_idx = r - eth_entries;
+ int rdma_idx = toe_idx - toe_entries;
+ int ciq_idx = rdma_idx - rdma_entries;
+ int ctrl_idx = ciq_idx - ciq_entries;
+ int fq_idx = ctrl_idx - ctrl_entries;
+
+ if (r)
+ seq_putc(seq, '\n');
+
+#define S3(fmt_spec, s, v) \
+do { \
+ seq_printf(seq, "%-12s", s); \
+ for (i = 0; i < n; ++i) \
+ seq_printf(seq, " %16" fmt_spec, v); \
+ seq_putc(seq, '\n'); \
+} while (0)
+#define S(s, v) S3("s", s, v)
+#define T(s, v) S3("u", s, tx[i].v)
+#define R(s, v) S3("u", s, rx[i].v)
+
+ if (r < eth_entries) {
+ int base_qset = r * 4;
+ const struct sge_eth_rxq *rx = &adap->sge.ethrxq[base_qset];
+ const struct sge_eth_txq *tx = &adap->sge.ethtxq[base_qset];
+ int n = min(4, adap->sge.ethqsets - 4 * r);
+
+ S("QType:", "Ethernet");
+ S("Interface:",
+ rx[i].rspq.netdev ? rx[i].rspq.netdev->name : "N/A");
+ T("TxQ ID:", q.cntxt_id);
+ T("TxQ size:", q.size);
+ T("TxQ inuse:", q.in_use);
+ T("TxQ CIDX:", q.cidx);
+ T("TxQ PIDX:", q.pidx);
+#ifdef CONFIG_CHELSIO_T4_DCB
+ T("DCB Prio:", dcb_prio);
+ S3("u", "DCB PGID:",
+ (ethqset2pinfo(adap, base_qset + i)->dcb.pgid >>
+ 4*(7-tx[i].dcb_prio)) & 0xf);
+ S3("u", "DCB PFC:",
+ (ethqset2pinfo(adap, base_qset + i)->dcb.pfcen >>
+ 1*(7-tx[i].dcb_prio)) & 0x1);
+#endif
+ R("RspQ ID:", rspq.abs_id);
+ R("RspQ size:", rspq.size);
+ R("RspQE size:", rspq.iqe_len);
+ R("RspQ CIDX:", rspq.cidx);
+ R("RspQ Gen:", rspq.gen);
+ S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq));
+ S3("u", "Intr pktcnt:",
+ adap->sge.counter_val[rx[i].rspq.pktcnt_idx]);
+ R("FL ID:", fl.cntxt_id);
+ R("FL size:", fl.size - 8);
+ R("FL pend:", fl.pend_cred);
+ R("FL avail:", fl.avail);
+ R("FL PIDX:", fl.pidx);
+ R("FL CIDX:", fl.cidx);
+ } else if (toe_idx < toe_entries) {
+ const struct sge_ofld_rxq *rx = &adap->sge.ofldrxq[toe_idx * 4];
+ const struct sge_ofld_txq *tx = &adap->sge.ofldtxq[toe_idx * 4];
+ int n = min(4, adap->sge.ofldqsets - 4 * toe_idx);
+
+ S("QType:", "TOE");
+ T("TxQ ID:", q.cntxt_id);
+ T("TxQ size:", q.size);
+ T("TxQ inuse:", q.in_use);
+ T("TxQ CIDX:", q.cidx);
+ T("TxQ PIDX:", q.pidx);
+ R("RspQ ID:", rspq.abs_id);
+ R("RspQ size:", rspq.size);
+ R("RspQE size:", rspq.iqe_len);
+ R("RspQ CIDX:", rspq.cidx);
+ R("RspQ Gen:", rspq.gen);
+ S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq));
+ S3("u", "Intr pktcnt:",
+ adap->sge.counter_val[rx[i].rspq.pktcnt_idx]);
+ R("FL ID:", fl.cntxt_id);
+ R("FL size:", fl.size - 8);
+ R("FL pend:", fl.pend_cred);
+ R("FL avail:", fl.avail);
+ R("FL PIDX:", fl.pidx);
+ R("FL CIDX:", fl.cidx);
+ } else if (rdma_idx < rdma_entries) {
+ const struct sge_ofld_rxq *rx =
+ &adap->sge.rdmarxq[rdma_idx * 4];
+ int n = min(4, adap->sge.rdmaqs - 4 * rdma_idx);
+
+ S("QType:", "RDMA-CPL");
+ R("RspQ ID:", rspq.abs_id);
+ R("RspQ size:", rspq.size);
+ R("RspQE size:", rspq.iqe_len);
+ R("RspQ CIDX:", rspq.cidx);
+ R("RspQ Gen:", rspq.gen);
+ S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq));
+ S3("u", "Intr pktcnt:",
+ adap->sge.counter_val[rx[i].rspq.pktcnt_idx]);
+ R("FL ID:", fl.cntxt_id);
+ R("FL size:", fl.size - 8);
+ R("FL pend:", fl.pend_cred);
+ R("FL avail:", fl.avail);
+ R("FL PIDX:", fl.pidx);
+ R("FL CIDX:", fl.cidx);
+ } else if (ciq_idx < ciq_entries) {
+ const struct sge_ofld_rxq *rx = &adap->sge.rdmaciq[ciq_idx * 4];
+ int n = min(4, adap->sge.rdmaciqs - 4 * ciq_idx);
+
+ S("QType:", "RDMA-CIQ");
+ R("RspQ ID:", rspq.abs_id);
+ R("RspQ size:", rspq.size);
+ R("RspQE size:", rspq.iqe_len);
+ R("RspQ CIDX:", rspq.cidx);
+ R("RspQ Gen:", rspq.gen);
+ S3("u", "Intr delay:", qtimer_val(adap, &rx[i].rspq));
+ S3("u", "Intr pktcnt:",
+ adap->sge.counter_val[rx[i].rspq.pktcnt_idx]);
+ } else if (ctrl_idx < ctrl_entries) {
+ const struct sge_ctrl_txq *tx = &adap->sge.ctrlq[ctrl_idx * 4];
+ int n = min(4, adap->params.nports - 4 * ctrl_idx);
+
+ S("QType:", "Control");
+ T("TxQ ID:", q.cntxt_id);
+ T("TxQ size:", q.size);
+ T("TxQ inuse:", q.in_use);
+ T("TxQ CIDX:", q.cidx);
+ T("TxQ PIDX:", q.pidx);
+ } else if (fq_idx == 0) {
+ const struct sge_rspq *evtq = &adap->sge.fw_evtq;
+
+ seq_printf(seq, "%-12s %16s\n", "QType:", "FW event queue");
+ seq_printf(seq, "%-12s %16u\n", "RspQ ID:", evtq->abs_id);
+ seq_printf(seq, "%-12s %16u\n", "RspQ size:", evtq->size);
+ seq_printf(seq, "%-12s %16u\n", "RspQE size:", evtq->iqe_len);
+ seq_printf(seq, "%-12s %16u\n", "RspQ CIDX:", evtq->cidx);
+ seq_printf(seq, "%-12s %16u\n", "RspQ Gen:", evtq->gen);
+ seq_printf(seq, "%-12s %16u\n", "Intr delay:",
+ qtimer_val(adap, evtq));
+ seq_printf(seq, "%-12s %16u\n", "Intr pktcnt:",
+ adap->sge.counter_val[evtq->pktcnt_idx]);
+ }
+#undef R
+#undef T
+#undef S
+#undef S3
+return 0;
+}
+
+static int sge_queue_entries(const struct adapter *adap)
+{
+ return DIV_ROUND_UP(adap->sge.ethqsets, 4) +
+ DIV_ROUND_UP(adap->sge.ofldqsets, 4) +
+ DIV_ROUND_UP(adap->sge.rdmaqs, 4) +
+ DIV_ROUND_UP(adap->sge.rdmaciqs, 4) +
+ DIV_ROUND_UP(MAX_CTRL_QUEUES, 4) + 1;
+}
+
+static void *sge_queue_start(struct seq_file *seq, loff_t *pos)
+{
+ int entries = sge_queue_entries(seq->private);
+
+ return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static void sge_queue_stop(struct seq_file *seq, void *v)
+{
+}
+
+static void *sge_queue_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+ int entries = sge_queue_entries(seq->private);
+
+ ++*pos;
+ return *pos < entries ? (void *)((uintptr_t)*pos + 1) : NULL;
+}
+
+static const struct seq_operations sge_qinfo_seq_ops = {
+ .start = sge_queue_start,
+ .next = sge_queue_next,
+ .stop = sge_queue_stop,
+ .show = sge_qinfo_show
+};
+
+static int sge_qinfo_open(struct inode *inode, struct file *file)
+{
+ int res = seq_open(file, &sge_qinfo_seq_ops);
+
+ if (!res) {
+ struct seq_file *seq = file->private_data;
+
+ seq->private = inode->i_private;
+ }
+ return res;
+}
+
+static const struct file_operations sge_qinfo_debugfs_fops = {
+ .owner = THIS_MODULE,
+ .open = sge_qinfo_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
+int mem_open(struct inode *inode, struct file *file)
+{
+ unsigned int mem;
+ struct adapter *adap;
+
+ file->private_data = inode->i_private;
+
+ mem = (uintptr_t)file->private_data & 0x3;
+ adap = file->private_data - mem;
+
+ (void)t4_fwcache(adap, FW_PARAM_DEV_FWCACHE_FLUSH);
+
+ return 0;
+}
+
static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
loff_t *ppos)
{
@@ -80,7 +1934,6 @@ static ssize_t mem_read(struct file *file, char __user *buf, size_t count,
*ppos = pos + count;
return count;
}
-
static const struct file_operations mem_debugfs_fops = {
.owner = THIS_MODULE,
.open = simple_open,
@@ -88,15 +1941,18 @@ static const struct file_operations mem_debugfs_fops = {
.llseek = default_llseek,
};
+static void set_debugfs_file_size(struct dentry *de, loff_t size)
+{
+ if (!IS_ERR(de) && de->d_inode)
+ de->d_inode->i_size = size;
+}
+
static void add_debugfs_mem(struct adapter *adap, const char *name,
unsigned int idx, unsigned int size_mb)
{
- struct dentry *de;
-
- de = debugfs_create_file(name, S_IRUSR, adap->debugfs_root,
- (void *)adap + idx, &mem_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = size_mb << 20;
+ debugfs_create_file_size(name, S_IRUSR, adap->debugfs_root,
+ (void *)adap + idx, &mem_debugfs_fops,
+ size_mb << 20);
}
/* Add an array of Debug FS files.
@@ -119,14 +1975,65 @@ int t4_setup_debugfs(struct adapter *adap)
{
int i;
u32 size;
+ struct dentry *de;
static struct t4_debugfs_entry t4_debugfs_files[] = {
+ { "cim_la", &cim_la_fops, S_IRUSR, 0 },
+ { "cim_qcfg", &cim_qcfg_fops, S_IRUSR, 0 },
+ { "clk", &clk_debugfs_fops, S_IRUSR, 0 },
+ { "devlog", &devlog_fops, S_IRUSR, 0 },
+ { "mbox0", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 0 },
+ { "mbox1", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 1 },
+ { "mbox2", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 2 },
+ { "mbox3", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 3 },
+ { "mbox4", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 4 },
+ { "mbox5", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 5 },
+ { "mbox6", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 6 },
+ { "mbox7", &mbox_debugfs_fops, S_IRUSR | S_IWUSR, 7 },
{ "l2t", &t4_l2t_fops, S_IRUSR, 0},
+ { "mps_tcam", &mps_tcam_debugfs_fops, S_IRUSR, 0 },
+ { "rss", &rss_debugfs_fops, S_IRUSR, 0 },
+ { "rss_config", &rss_config_debugfs_fops, S_IRUSR, 0 },
+ { "rss_key", &rss_key_debugfs_fops, S_IRUSR, 0 },
+ { "rss_pf_config", &rss_pf_config_debugfs_fops, S_IRUSR, 0 },
+ { "rss_vf_config", &rss_vf_config_debugfs_fops, S_IRUSR, 0 },
+ { "sge_qinfo", &sge_qinfo_debugfs_fops, S_IRUSR, 0 },
+ { "ibq_tp0", &cim_ibq_fops, S_IRUSR, 0 },
+ { "ibq_tp1", &cim_ibq_fops, S_IRUSR, 1 },
+ { "ibq_ulp", &cim_ibq_fops, S_IRUSR, 2 },
+ { "ibq_sge0", &cim_ibq_fops, S_IRUSR, 3 },
+ { "ibq_sge1", &cim_ibq_fops, S_IRUSR, 4 },
+ { "ibq_ncsi", &cim_ibq_fops, S_IRUSR, 5 },
+ { "obq_ulp0", &cim_obq_fops, S_IRUSR, 0 },
+ { "obq_ulp1", &cim_obq_fops, S_IRUSR, 1 },
+ { "obq_ulp2", &cim_obq_fops, S_IRUSR, 2 },
+ { "obq_ulp3", &cim_obq_fops, S_IRUSR, 3 },
+ { "obq_sge", &cim_obq_fops, S_IRUSR, 4 },
+ { "obq_ncsi", &cim_obq_fops, S_IRUSR, 5 },
+ { "tp_la", &tp_la_fops, S_IRUSR, 0 },
+ { "ulprx_la", &ulprx_la_fops, S_IRUSR, 0 },
+ { "sensors", &sensors_debugfs_fops, S_IRUSR, 0 },
+ { "pm_stats", &pm_stats_debugfs_fops, S_IRUSR, 0 },
+ { "cctrl", &cctrl_tbl_debugfs_fops, S_IRUSR, 0 },
+#if IS_ENABLED(CONFIG_IPV6)
+ { "clip_tbl", &clip_tbl_debugfs_fops, S_IRUSR, 0 },
+#endif
+ };
+
+ /* Debug FS nodes common to all T5 and later adapters.
+ */
+ static struct t4_debugfs_entry t5_debugfs_files[] = {
+ { "obq_sge_rx_q0", &cim_obq_fops, S_IRUSR, 6 },
+ { "obq_sge_rx_q1", &cim_obq_fops, S_IRUSR, 7 },
};
add_debugfs_files(adap,
t4_debugfs_files,
ARRAY_SIZE(t4_debugfs_files));
+ if (!is_t4(adap->params.chip))
+ add_debugfs_files(adap,
+ t5_debugfs_files,
+ ARRAY_SIZE(t5_debugfs_files));
i = t4_read_reg(adap, MA_TARGET_MEM_ENABLE_A);
if (i & EDRAM0_ENABLE_F) {
@@ -154,5 +2061,10 @@ int t4_setup_debugfs(struct adapter *adap)
EXT_MEM1_SIZE_G(size));
}
}
+
+ de = debugfs_create_file("flash", S_IRUSR, adap->debugfs_root, adap,
+ &flash_debugfs_fops);
+ set_debugfs_file_size(de, adap->params.sf_size);
+
return 0;
}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h
index a3d8867efd3d..8f418ba868bd 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_debugfs.h
@@ -37,16 +37,49 @@
#include <linux/export.h>
+#define FILE_DATA(_file) ((_file)->f_path.dentry->d_inode)
+
+#define DEFINE_SIMPLE_DEBUGFS_FILE(name) \
+static int name##_open(struct inode *inode, struct file *file) \
+{ \
+ return single_open(file, name##_show, inode->i_private); \
+} \
+static const struct file_operations name##_debugfs_fops = { \
+ .owner = THIS_MODULE, \
+ .open = name##_open, \
+ .read = seq_read, \
+ .llseek = seq_lseek, \
+ .release = single_release \
+}
+
struct t4_debugfs_entry {
const char *name;
const struct file_operations *ops;
- mode_t mode;
+ umode_t mode;
unsigned char data;
};
+struct seq_tab {
+ int (*show)(struct seq_file *seq, void *v, int idx);
+ unsigned int rows; /* # of entries */
+ unsigned char width; /* size in bytes of each entry */
+ unsigned char skip_first; /* whether the first line is a header */
+ char data[0]; /* the table data */
+};
+
+static inline unsigned int hex2val(char c)
+{
+ return isdigit(c) ? c - '0' : tolower(c) - 'a' + 10;
+}
+
+struct seq_tab *seq_open_tab(struct file *f, unsigned int rows,
+ unsigned int width, unsigned int have_header,
+ int (*show)(struct seq_file *seq, void *v, int i));
+
int t4_setup_debugfs(struct adapter *adap);
void add_debugfs_files(struct adapter *adap,
struct t4_debugfs_entry *files,
unsigned int nfiles);
+int mem_open(struct inode *inode, struct file *file);
#endif
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
index ccf3436024bc..a22cf932ca35 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_main.c
@@ -62,14 +62,18 @@
#include <net/netevent.h>
#include <net/addrconf.h>
#include <net/bonding.h>
+#include <net/addrconf.h>
#include <asm/uaccess.h>
#include "cxgb4.h"
#include "t4_regs.h"
+#include "t4_values.h"
#include "t4_msg.h"
#include "t4fw_api.h"
+#include "t4fw_version.h"
#include "cxgb4_dcb.h"
#include "cxgb4_debugfs.h"
+#include "clip_tbl.h"
#include "l2t.h"
#ifdef DRV_VERSION
@@ -78,99 +82,6 @@
#define DRV_VERSION "2.0.0-ko"
#define DRV_DESC "Chelsio T4/T5 Network Driver"
-/*
- * Max interrupt hold-off timer value in us. Queues fall back to this value
- * under extreme memory pressure so it's largish to give the system time to
- * recover.
- */
-#define MAX_SGE_TIMERVAL 200U
-
-enum {
- /*
- * Physical Function provisioning constants.
- */
- PFRES_NVI = 4, /* # of Virtual Interfaces */
- PFRES_NETHCTRL = 128, /* # of EQs used for ETH or CTRL Qs */
- PFRES_NIQFLINT = 128, /* # of ingress Qs/w Free List(s)/intr
- */
- PFRES_NEQ = 256, /* # of egress queues */
- PFRES_NIQ = 0, /* # of ingress queues */
- PFRES_TC = 0, /* PCI-E traffic class */
- PFRES_NEXACTF = 128, /* # of exact MPS filters */
-
- PFRES_R_CAPS = FW_CMD_CAP_PF,
- PFRES_WX_CAPS = FW_CMD_CAP_PF,
-
-#ifdef CONFIG_PCI_IOV
- /*
- * Virtual Function provisioning constants. We need two extra Ingress
- * Queues with Interrupt capability to serve as the VF's Firmware
- * Event Queue and Forwarded Interrupt Queue (when using MSI mode) --
- * neither will have Free Lists associated with them). For each
- * Ethernet/Control Egress Queue and for each Free List, we need an
- * Egress Context.
- */
- VFRES_NPORTS = 1, /* # of "ports" per VF */
- VFRES_NQSETS = 2, /* # of "Queue Sets" per VF */
-
- VFRES_NVI = VFRES_NPORTS, /* # of Virtual Interfaces */
- VFRES_NETHCTRL = VFRES_NQSETS, /* # of EQs used for ETH or CTRL Qs */
- VFRES_NIQFLINT = VFRES_NQSETS+2,/* # of ingress Qs/w Free List(s)/intr */
- VFRES_NEQ = VFRES_NQSETS*2, /* # of egress queues */
- VFRES_NIQ = 0, /* # of non-fl/int ingress queues */
- VFRES_TC = 0, /* PCI-E traffic class */
- VFRES_NEXACTF = 16, /* # of exact MPS filters */
-
- VFRES_R_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF|FW_CMD_CAP_PORT,
- VFRES_WX_CAPS = FW_CMD_CAP_DMAQ|FW_CMD_CAP_VF,
-#endif
-};
-
-/*
- * Provide a Port Access Rights Mask for the specified PF/VF. This is very
- * static and likely not to be useful in the long run. We really need to
- * implement some form of persistent configuration which the firmware
- * controls.
- */
-static unsigned int pfvfres_pmask(struct adapter *adapter,
- unsigned int pf, unsigned int vf)
-{
- unsigned int portn, portvec;
-
- /*
- * Give PF's access to all of the ports.
- */
- if (vf == 0)
- return FW_PFVF_CMD_PMASK_M;
-
- /*
- * For VFs, we'll assign them access to the ports based purely on the
- * PF. We assign active ports in order, wrapping around if there are
- * fewer active ports than PFs: e.g. active port[pf % nports].
- * Unfortunately the adapter's port_info structs haven't been
- * initialized yet so we have to compute this.
- */
- if (adapter->params.nports == 0)
- return 0;
-
- portn = pf % adapter->params.nports;
- portvec = adapter->params.portvec;
- for (;;) {
- /*
- * Isolate the lowest set bit in the port vector. If we're at
- * the port number that we want, return that as the pmask.
- * otherwise mask that bit out of the port vector and
- * decrement our port number ...
- */
- unsigned int pmask = portvec ^ (portvec & (portvec-1));
- if (portn == 0)
- return pmask;
- portn--;
- portvec &= ~pmask;
- }
- /*NOTREACHED*/
-}
-
enum {
MAX_TXQ_ENTRIES = 16384,
MAX_CTRL_TXQ_ENTRIES = 1024,
@@ -263,7 +174,8 @@ MODULE_PARM_DESC(force_init, "Forcibly become Master PF and initialize adapter")
static uint force_old_init;
module_param(force_old_init, uint, 0644);
-MODULE_PARM_DESC(force_old_init, "Force old initialization sequence");
+MODULE_PARM_DESC(force_old_init, "Force old initialization sequence, deprecated"
+ " parameter");
static int dflt_msg_enable = DFLT_MSG_ENABLE;
@@ -292,13 +204,14 @@ static unsigned int intr_holdoff[SGE_NTIMERS - 1] = { 5, 10, 20, 50, 100 };
module_param_array(intr_holdoff, uint, NULL, 0644);
MODULE_PARM_DESC(intr_holdoff, "values for queue interrupt hold-off timers "
- "0..4 in microseconds");
+ "0..4 in microseconds, deprecated parameter");
static unsigned int intr_cnt[SGE_NCOUNTERS - 1] = { 4, 8, 16 };
module_param_array(intr_cnt, uint, NULL, 0644);
MODULE_PARM_DESC(intr_cnt,
- "thresholds 1..3 for queue interrupt packet counters");
+ "thresholds 1..3 for queue interrupt packet counters, "
+ "deprecated parameter");
/*
* Normally we tell the chip to deliver Ingress Packets into our DMA buffers
@@ -318,7 +231,8 @@ static bool vf_acls;
#ifdef CONFIG_PCI_IOV
module_param(vf_acls, bool, 0644);
-MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement");
+MODULE_PARM_DESC(vf_acls, "if set enable virtualization L2 ACL enforcement, "
+ "deprecated parameter");
/* Configure the number of PCI-E Virtual Function which are to be instantiated
* on SR-IOV Capable Physical Functions.
@@ -340,32 +254,11 @@ module_param(select_queue, int, 0644);
MODULE_PARM_DESC(select_queue,
"Select between kernel provided method of selecting or driver method of selecting TX queue. Default is kernel method.");
-/*
- * The filter TCAM has a fixed portion and a variable portion. The fixed
- * portion can match on source/destination IP IPv4/IPv6 addresses and TCP/UDP
- * ports. The variable portion is 36 bits which can include things like Exact
- * Match MAC Index (9 bits), Ether Type (16 bits), IP Protocol (8 bits),
- * [Inner] VLAN Tag (17 bits), etc. which, if all were somehow selected, would
- * far exceed the 36-bit budget for this "compressed" header portion of the
- * filter. Thus, we have a scarce resource which must be carefully managed.
- *
- * By default we set this up to mostly match the set of filter matching
- * capabilities of T3 but with accommodations for some of T4's more
- * interesting features:
- *
- * { IP Fragment (1), MPS Match Type (3), IP Protocol (8),
- * [Inner] VLAN (17), Port (3), FCoE (1) }
- */
-enum {
- TP_VLAN_PRI_MAP_DEFAULT = HW_TPL_FR_MT_PR_IV_P_FC,
- TP_VLAN_PRI_MAP_FIRST = FCOE_SHIFT,
- TP_VLAN_PRI_MAP_LAST = FRAGMENTATION_SHIFT,
-};
-
-static unsigned int tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT;
+static unsigned int tp_vlan_pri_map = HW_TPL_FR_MT_PR_IV_P_FC;
module_param(tp_vlan_pri_map, uint, 0644);
-MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration");
+MODULE_PARM_DESC(tp_vlan_pri_map, "global compressed filter configuration, "
+ "deprecated parameter");
static struct dentry *cxgb4_debugfs_root;
@@ -671,7 +564,7 @@ static void filter_rpl(struct adapter *adap, const struct cpl_set_tcb_rpl *rpl)
if (idx >= adap->tids.ftid_base && nidx <
(adap->tids.nftids + adap->tids.nsftids)) {
idx = nidx;
- ret = GET_TCB_COOKIE(rpl->cookie);
+ ret = TCB_COOKIE_G(rpl->cookie);
f = &adap->tids.ftid_tab[idx];
if (ret == FW_FILTER_WR_FLT_DELETED) {
@@ -723,7 +616,7 @@ static int fwevtq_handler(struct sge_rspq *q, const __be64 *rsp,
if (likely(opcode == CPL_SGE_EGR_UPDATE)) {
const struct cpl_sge_egr_update *p = (void *)rsp;
- unsigned int qid = EGR_QID(ntohl(p->opcode_qid));
+ unsigned int qid = EGR_QID_G(ntohl(p->opcode_qid));
struct sge_txq *txq;
txq = q->adap->sge.egr_map[qid - q->adap->sge.egr_start];
@@ -833,11 +726,11 @@ static void disable_msi(struct adapter *adapter)
static irqreturn_t t4_nondata_intr(int irq, void *cookie)
{
struct adapter *adap = cookie;
+ u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A));
- u32 v = t4_read_reg(adap, MYPF_REG(PL_PF_INT_CAUSE));
- if (v & PFSW) {
+ if (v & PFSW_F) {
adap->swintr = 1;
- t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE), v);
+ t4_write_reg(adap, MYPF_REG(PL_PF_INT_CAUSE_A), v);
}
t4_slow_intr_handler(adap);
return IRQ_HANDLED;
@@ -1030,8 +923,14 @@ static void quiesce_rx(struct adapter *adap)
for (i = 0; i < ARRAY_SIZE(adap->sge.ingr_map); i++) {
struct sge_rspq *q = adap->sge.ingr_map[i];
- if (q && q->handler)
+ if (q && q->handler) {
napi_disable(&q->napi);
+ local_bh_disable();
+ while (!cxgb_poll_lock_napi(q))
+ mdelay(1);
+ local_bh_enable();
+ }
+
}
}
@@ -1047,12 +946,14 @@ static void enable_rx(struct adapter *adap)
if (!q)
continue;
- if (q->handler)
+ if (q->handler) {
+ cxgb_busy_poll_init_lock(q);
napi_enable(&q->napi);
+ }
/* 0-increment GTS to start the timer and enable interrupts */
- t4_write_reg(adap, MYPF_REG(SGE_PF_GTS),
- SEINTARM(q->intr_params) |
- INGRESSQID(q->cntxt_id));
+ t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A),
+ SEINTARM_V(q->intr_params) |
+ INGRESSQID_V(q->cntxt_id));
}
}
@@ -1176,10 +1077,10 @@ freeout: t4_free_sge_resources(adap);
}
t4_write_reg(adap, is_t4(adap->params.chip) ?
- MPS_TRC_RSS_CONTROL :
- MPS_T5_TRC_RSS_CONTROL,
- RSSCONTROL(netdev2pinfo(adap->port[0])->tx_chan) |
- QUEUENUMBER(s->ethrxq[0].rspq.abs_id));
+ MPS_TRC_RSS_CONTROL_A :
+ MPS_T5_TRC_RSS_CONTROL_A,
+ RSSCONTROL_V(netdev2pinfo(adap->port[0])->tx_chan) |
+ QUEUENUMBER_V(s->ethrxq[0].rspq.abs_id));
return 0;
}
@@ -1518,6 +1419,7 @@ static int get_eeprom_len(struct net_device *dev)
static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
{
struct adapter *adapter = netdev2adap(dev);
+ u32 exprom_vers;
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
@@ -1535,6 +1437,14 @@ static void get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
FW_HDR_FW_VER_MINOR_G(adapter->params.tp_vers),
FW_HDR_FW_VER_MICRO_G(adapter->params.tp_vers),
FW_HDR_FW_VER_BUILD_G(adapter->params.tp_vers));
+
+ if (!t4_get_exprom_version(adapter, &exprom_vers))
+ snprintf(info->erom_version, sizeof(info->erom_version),
+ "%u.%u.%u.%u",
+ FW_HDR_FW_VER_MAJOR_G(exprom_vers),
+ FW_HDR_FW_VER_MINOR_G(exprom_vers),
+ FW_HDR_FW_VER_MICRO_G(exprom_vers),
+ FW_HDR_FW_VER_BUILD_G(exprom_vers));
}
static void get_strings(struct net_device *dev, u32 stringset, u8 *data)
@@ -1589,9 +1499,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
collect_sge_port_stats(adapter, pi, (struct queue_port_stats *)data);
data += sizeof(struct queue_port_stats) / sizeof(u64);
if (!is_t4(adapter->params.chip)) {
- t4_write_reg(adapter, SGE_STAT_CFG, STATSOURCE_T5(7));
- val1 = t4_read_reg(adapter, SGE_STAT_TOTAL);
- val2 = t4_read_reg(adapter, SGE_STAT_MATCH);
+ t4_write_reg(adapter, SGE_STAT_CFG_A, STATSOURCE_T5_V(7));
+ val1 = t4_read_reg(adapter, SGE_STAT_TOTAL_A);
+ val2 = t4_read_reg(adapter, SGE_STAT_MATCH_A);
*data = val1 - val2;
data++;
*data = val2;
@@ -2608,8 +2518,8 @@ static int closest_thres(const struct sge *s, int thres)
/*
* Return a queue's interrupt hold-off time in us. 0 means no timer.
*/
-static unsigned int qtimer_val(const struct adapter *adap,
- const struct sge_rspq *q)
+unsigned int qtimer_val(const struct adapter *adap,
+ const struct sge_rspq *q)
{
unsigned int idx = q->intr_params >> 1;
@@ -3346,40 +3256,6 @@ static int tid_init(struct tid_info *t)
return 0;
}
-int cxgb4_clip_get(const struct net_device *dev,
- const struct in6_addr *lip)
-{
- struct adapter *adap;
- struct fw_clip_cmd c;
-
- adap = netdev2adap(dev);
- memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
- c.alloc_to_len16 = htonl(FW_CLIP_CMD_ALLOC_F | FW_LEN16(c));
- c.ip_hi = *(__be64 *)(lip->s6_addr);
- c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
- return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
-}
-EXPORT_SYMBOL(cxgb4_clip_get);
-
-int cxgb4_clip_release(const struct net_device *dev,
- const struct in6_addr *lip)
-{
- struct adapter *adap;
- struct fw_clip_cmd c;
-
- adap = netdev2adap(dev);
- memset(&c, 0, sizeof(c));
- c.op_to_write = htonl(FW_CMD_OP_V(FW_CLIP_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_READ_F);
- c.alloc_to_len16 = htonl(FW_CLIP_CMD_FREE_F | FW_LEN16(c));
- c.ip_hi = *(__be64 *)(lip->s6_addr);
- c.ip_lo = *(__be64 *)(lip->s6_addr + 8);
- return t4_wr_mbox_meat(adap, adap->mbox, &c, sizeof(c), &c, false);
-}
-EXPORT_SYMBOL(cxgb4_clip_release);
-
/**
* cxgb4_create_server - create an IP server
* @dev: the device
@@ -3415,8 +3291,8 @@ int cxgb4_create_server(const struct net_device *dev, unsigned int stid,
req->peer_ip = htonl(0);
chan = rxq_to_chan(&adap->sge, queue);
req->opt0 = cpu_to_be64(TX_CHAN_V(chan));
- req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
- SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
+ req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) |
+ SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue));
ret = t4_mgmt_tx(adap, skb);
return net_xmit_eval(ret);
}
@@ -3458,8 +3334,8 @@ int cxgb4_create_server6(const struct net_device *dev, unsigned int stid,
req->peer_ip_lo = cpu_to_be64(0);
chan = rxq_to_chan(&adap->sge, queue);
req->opt0 = cpu_to_be64(TX_CHAN_V(chan));
- req->opt1 = cpu_to_be64(CONN_POLICY_ASK |
- SYN_RSS_ENABLE | SYN_RSS_QUEUE(queue));
+ req->opt1 = cpu_to_be64(CONN_POLICY_V(CPL_CONN_POLICY_ASK) |
+ SYN_RSS_ENABLE_F | SYN_RSS_QUEUE_V(queue));
ret = t4_mgmt_tx(adap, skb);
return net_xmit_eval(ret);
}
@@ -3482,8 +3358,8 @@ int cxgb4_remove_server(const struct net_device *dev, unsigned int stid,
req = (struct cpl_close_listsvr_req *)__skb_put(skb, sizeof(*req));
INIT_TP_WR(req, 0);
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_CLOSE_LISTSRV_REQ, stid));
- req->reply_ctrl = htons(NO_REPLY(0) | (ipv6 ? LISTSVR_IPV6(1) :
- LISTSVR_IPV6(0)) | QUEUENO(queue));
+ req->reply_ctrl = htons(NO_REPLY_V(0) | (ipv6 ? LISTSVR_IPV6_V(1) :
+ LISTSVR_IPV6_V(0)) | QUEUENO_V(queue));
ret = t4_mgmt_tx(adap, skb);
return net_xmit_eval(ret);
}
@@ -3600,14 +3476,14 @@ unsigned int cxgb4_dbfifo_count(const struct net_device *dev, int lpfifo)
struct adapter *adap = netdev2adap(dev);
u32 v1, v2, lp_count, hp_count;
- v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
- v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2);
+ v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A);
+ v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A);
if (is_t4(adap->params.chip)) {
- lp_count = G_LP_COUNT(v1);
- hp_count = G_HP_COUNT(v1);
+ lp_count = LP_COUNT_G(v1);
+ hp_count = HP_COUNT_G(v1);
} else {
- lp_count = G_LP_COUNT_T5(v1);
- hp_count = G_HP_COUNT_T5(v2);
+ lp_count = LP_COUNT_T5_G(v1);
+ hp_count = HP_COUNT_T5_G(v2);
}
return lpfifo ? lp_count : hp_count;
}
@@ -3653,10 +3529,10 @@ void cxgb4_iscsi_init(struct net_device *dev, unsigned int tag_mask,
{
struct adapter *adap = netdev2adap(dev);
- t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK, tag_mask);
- t4_write_reg(adap, ULP_RX_ISCSI_PSZ, HPZ0(pgsz_order[0]) |
- HPZ1(pgsz_order[1]) | HPZ2(pgsz_order[2]) |
- HPZ3(pgsz_order[3]));
+ t4_write_reg(adap, ULP_RX_ISCSI_TAGMASK_A, tag_mask);
+ t4_write_reg(adap, ULP_RX_ISCSI_PSZ_A, HPZ0_V(pgsz_order[0]) |
+ HPZ1_V(pgsz_order[1]) | HPZ2_V(pgsz_order[2]) |
+ HPZ3_V(pgsz_order[3]));
}
EXPORT_SYMBOL(cxgb4_iscsi_init);
@@ -3666,14 +3542,14 @@ int cxgb4_flush_eq_cache(struct net_device *dev)
int ret;
ret = t4_fwaddrspace_write(adap, adap->mbox,
- 0xe1000000 + A_SGE_CTXT_CMD, 0x20000000);
+ 0xe1000000 + SGE_CTXT_CMD_A, 0x20000000);
return ret;
}
EXPORT_SYMBOL(cxgb4_flush_eq_cache);
static int read_eq_indices(struct adapter *adap, u16 qid, u16 *pidx, u16 *cidx)
{
- u32 addr = t4_read_reg(adap, A_SGE_DBQ_CTXT_BADDR) + 24 * qid + 8;
+ u32 addr = t4_read_reg(adap, SGE_DBQ_CTXT_BADDR_A) + 24 * qid + 8;
__be64 indices;
int ret;
@@ -3702,14 +3578,20 @@ int cxgb4_sync_txq_pidx(struct net_device *dev, u16 qid, u16 pidx,
if (pidx != hw_pidx) {
u16 delta;
+ u32 val;
if (pidx >= hw_pidx)
delta = pidx - hw_pidx;
else
delta = size - hw_pidx + pidx;
+
+ if (is_t4(adap->params.chip))
+ val = PIDX_V(delta);
+ else
+ val = PIDX_T5_V(delta);
wmb();
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- QID(qid) | PIDX(delta));
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
+ QID_V(qid) | val);
}
out:
return ret;
@@ -3721,8 +3603,8 @@ void cxgb4_disable_db_coalescing(struct net_device *dev)
struct adapter *adap;
adap = netdev2adap(dev);
- t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE,
- F_NOCOALESCE);
+ t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F,
+ NOCOALESCE_F);
}
EXPORT_SYMBOL(cxgb4_disable_db_coalescing);
@@ -3731,7 +3613,7 @@ void cxgb4_enable_db_coalescing(struct net_device *dev)
struct adapter *adap;
adap = netdev2adap(dev);
- t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_NOCOALESCE, 0);
+ t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, NOCOALESCE_F, 0);
}
EXPORT_SYMBOL(cxgb4_enable_db_coalescing);
@@ -3809,8 +3691,8 @@ u64 cxgb4_read_sge_timestamp(struct net_device *dev)
struct adapter *adap;
adap = netdev2adap(dev);
- lo = t4_read_reg(adap, SGE_TIMESTAMP_LO);
- hi = GET_TSVAL(t4_read_reg(adap, SGE_TIMESTAMP_HI));
+ lo = t4_read_reg(adap, SGE_TIMESTAMP_LO_A);
+ hi = TSVAL_G(t4_read_reg(adap, SGE_TIMESTAMP_HI_A));
return ((u64)hi << 32) | (u64)lo;
}
@@ -3870,14 +3752,14 @@ static void drain_db_fifo(struct adapter *adap, int usecs)
u32 v1, v2, lp_count, hp_count;
do {
- v1 = t4_read_reg(adap, A_SGE_DBFIFO_STATUS);
- v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2);
+ v1 = t4_read_reg(adap, SGE_DBFIFO_STATUS_A);
+ v2 = t4_read_reg(adap, SGE_DBFIFO_STATUS2_A);
if (is_t4(adap->params.chip)) {
- lp_count = G_LP_COUNT(v1);
- hp_count = G_HP_COUNT(v1);
+ lp_count = LP_COUNT_G(v1);
+ hp_count = HP_COUNT_G(v1);
} else {
- lp_count = G_LP_COUNT_T5(v1);
- hp_count = G_HP_COUNT_T5(v2);
+ lp_count = LP_COUNT_T5_G(v1);
+ hp_count = HP_COUNT_T5_G(v2);
}
if (lp_count == 0 && hp_count == 0)
@@ -3904,8 +3786,8 @@ static void enable_txq_db(struct adapter *adap, struct sge_txq *q)
* are committed before we tell HW about them.
*/
wmb();
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- QID(q->cntxt_id) | PIDX(q->db_pidx_inc));
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
+ QID_V(q->cntxt_id) | PIDX_V(q->db_pidx_inc));
q->db_pidx_inc = 0;
}
q->db_disabled = 0;
@@ -3952,9 +3834,9 @@ static void process_db_full(struct work_struct *work)
drain_db_fifo(adap, dbfifo_drain_delay);
enable_dbs(adap);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_EMPTY);
- t4_set_reg_field(adap, SGE_INT_ENABLE3,
- DBFIFO_HP_INT | DBFIFO_LP_INT,
- DBFIFO_HP_INT | DBFIFO_LP_INT);
+ t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
+ DBFIFO_HP_INT_F | DBFIFO_LP_INT_F,
+ DBFIFO_HP_INT_F | DBFIFO_LP_INT_F);
}
static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
@@ -3968,14 +3850,20 @@ static void sync_txq_pidx(struct adapter *adap, struct sge_txq *q)
goto out;
if (q->db_pidx != hw_pidx) {
u16 delta;
+ u32 val;
if (q->db_pidx >= hw_pidx)
delta = q->db_pidx - hw_pidx;
else
delta = q->size - hw_pidx + q->db_pidx;
+
+ if (is_t4(adap->params.chip))
+ val = PIDX_V(delta);
+ else
+ val = PIDX_T5_V(delta);
wmb();
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- QID(q->cntxt_id) | PIDX(delta));
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
+ QID_V(q->cntxt_id) | val);
}
out:
q->db_disabled = 0;
@@ -4024,14 +3912,14 @@ static void process_db_drop(struct work_struct *work)
dev_err(adap->pdev_dev, "doorbell drop recovery: "
"qid=%d, pidx_inc=%d\n", qid, pidx_inc);
else
- writel(PIDX_T5(pidx_inc) | QID(bar2_qid),
+ writel(PIDX_T5_V(pidx_inc) | QID_V(bar2_qid),
adap->bar2 + bar2_qoffset + SGE_UDB_KDOORBELL);
/* Re-enable BAR2 WC */
t4_set_reg_field(adap, 0x10b0, 1<<15, 1<<15);
}
- t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_DROPPED_DB, 0);
+ t4_set_reg_field(adap, SGE_DOORBELL_CONTROL_A, DROPPED_DB_F, 0);
}
void t4_db_full(struct adapter *adap)
@@ -4039,8 +3927,8 @@ void t4_db_full(struct adapter *adap)
if (is_t4(adap->params.chip)) {
disable_dbs(adap);
notify_rdma_uld(adap, CXGB4_CONTROL_DB_FULL);
- t4_set_reg_field(adap, SGE_INT_ENABLE3,
- DBFIFO_HP_INT | DBFIFO_LP_INT, 0);
+ t4_set_reg_field(adap, SGE_INT_ENABLE3_A,
+ DBFIFO_HP_INT_F | DBFIFO_LP_INT_F, 0);
queue_work(adap->workq, &adap->db_full_task);
}
}
@@ -4081,7 +3969,7 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
lli.nports = adap->params.nports;
lli.wr_cred = adap->params.ofldq_wr_cred;
lli.adapter_type = adap->params.chip;
- lli.iscsi_iolen = MAXRXDATA_GET(t4_read_reg(adap, TP_PARA_REG2));
+ lli.iscsi_iolen = MAXRXDATA_G(t4_read_reg(adap, TP_PARA_REG2_A));
lli.cclk_ps = 1000000000 / adap->params.vpd.cclk;
lli.udb_density = 1 << adap->params.sge.eq_qpp;
lli.ucq_density = 1 << adap->params.sge.iq_qpp;
@@ -4089,8 +3977,8 @@ static void uld_attach(struct adapter *adap, unsigned int uld)
/* MODQ_REQ_MAP sets queues 0-3 to chan 0-3 */
for (i = 0; i < NCHAN; i++)
lli.tx_modq[i] = i;
- lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS);
- lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL);
+ lli.gts_reg = adap->regs + MYPF_REG(SGE_PF_GTS_A);
+ lli.db_reg = adap->regs + MYPF_REG(SGE_PF_KDOORBELL_A);
lli.fw_vers = adap->params.fw_vers;
lli.dbfifo_int_thresh = dbfifo_int_thresh;
lli.sge_ingpadboundary = adap->sge.fl_align;
@@ -4220,148 +4108,61 @@ int cxgb4_unregister_uld(enum cxgb4_uld type)
}
EXPORT_SYMBOL(cxgb4_unregister_uld);
-/* Check if netdev on which event is occured belongs to us or not. Return
- * success (true) if it belongs otherwise failure (false).
- * Called with rcu_read_lock() held.
- */
#if IS_ENABLED(CONFIG_IPV6)
-static bool cxgb4_netdev(const struct net_device *netdev)
+static int cxgb4_inet6addr_handler(struct notifier_block *this,
+ unsigned long event, void *data)
{
+ struct inet6_ifaddr *ifa = data;
+ struct net_device *event_dev = ifa->idev->dev;
+ const struct device *parent = NULL;
+#if IS_ENABLED(CONFIG_BONDING)
struct adapter *adap;
- int i;
-
- list_for_each_entry_rcu(adap, &adap_rcu_list, rcu_node)
- for (i = 0; i < MAX_NPORTS; i++)
- if (adap->port[i] == netdev)
- return true;
- return false;
-}
+#endif
+ if (event_dev->priv_flags & IFF_802_1Q_VLAN)
+ event_dev = vlan_dev_real_dev(event_dev);
+#if IS_ENABLED(CONFIG_BONDING)
+ if (event_dev->flags & IFF_MASTER) {
+ list_for_each_entry(adap, &adapter_list, list_node) {
+ switch (event) {
+ case NETDEV_UP:
+ cxgb4_clip_get(adap->port[0],
+ (const u32 *)ifa, 1);
+ break;
+ case NETDEV_DOWN:
+ cxgb4_clip_release(adap->port[0],
+ (const u32 *)ifa, 1);
+ break;
+ default:
+ break;
+ }
+ }
+ return NOTIFY_OK;
+ }
+#endif
-static int clip_add(struct net_device *event_dev, struct inet6_ifaddr *ifa,
- unsigned long event)
-{
- int ret = NOTIFY_DONE;
+ if (event_dev)
+ parent = event_dev->dev.parent;
- rcu_read_lock();
- if (cxgb4_netdev(event_dev)) {
+ if (parent && parent->driver == &cxgb4_driver.driver) {
switch (event) {
case NETDEV_UP:
- ret = cxgb4_clip_get(event_dev, &ifa->addr);
- if (ret < 0) {
- rcu_read_unlock();
- return ret;
- }
- ret = NOTIFY_OK;
+ cxgb4_clip_get(event_dev, (const u32 *)ifa, 1);
break;
case NETDEV_DOWN:
- cxgb4_clip_release(event_dev, &ifa->addr);
- ret = NOTIFY_OK;
+ cxgb4_clip_release(event_dev, (const u32 *)ifa, 1);
break;
default:
break;
}
}
- rcu_read_unlock();
- return ret;
-}
-
-static int cxgb4_inet6addr_handler(struct notifier_block *this,
- unsigned long event, void *data)
-{
- struct inet6_ifaddr *ifa = data;
- struct net_device *event_dev;
- int ret = NOTIFY_DONE;
- struct bonding *bond = netdev_priv(ifa->idev->dev);
- struct list_head *iter;
- struct slave *slave;
- struct pci_dev *first_pdev = NULL;
-
- if (ifa->idev->dev->priv_flags & IFF_802_1Q_VLAN) {
- event_dev = vlan_dev_real_dev(ifa->idev->dev);
- ret = clip_add(event_dev, ifa, event);
- } else if (ifa->idev->dev->flags & IFF_MASTER) {
- /* It is possible that two different adapters are bonded in one
- * bond. We need to find such different adapters and add clip
- * in all of them only once.
- */
- bond_for_each_slave(bond, slave, iter) {
- if (!first_pdev) {
- ret = clip_add(slave->dev, ifa, event);
- /* If clip_add is success then only initialize
- * first_pdev since it means it is our device
- */
- if (ret == NOTIFY_OK)
- first_pdev = to_pci_dev(
- slave->dev->dev.parent);
- } else if (first_pdev !=
- to_pci_dev(slave->dev->dev.parent))
- ret = clip_add(slave->dev, ifa, event);
- }
- } else
- ret = clip_add(ifa->idev->dev, ifa, event);
-
- return ret;
+ return NOTIFY_OK;
}
+static bool inet6addr_registered;
static struct notifier_block cxgb4_inet6addr_notifier = {
.notifier_call = cxgb4_inet6addr_handler
};
-/* Retrieves IPv6 addresses from a root device (bond, vlan) associated with
- * a physical device.
- * The physical device reference is needed to send the actul CLIP command.
- */
-static int update_dev_clip(struct net_device *root_dev, struct net_device *dev)
-{
- struct inet6_dev *idev = NULL;
- struct inet6_ifaddr *ifa;
- int ret = 0;
-
- idev = __in6_dev_get(root_dev);
- if (!idev)
- return ret;
-
- read_lock_bh(&idev->lock);
- list_for_each_entry(ifa, &idev->addr_list, if_list) {
- ret = cxgb4_clip_get(dev, &ifa->addr);
- if (ret < 0)
- break;
- }
- read_unlock_bh(&idev->lock);
-
- return ret;
-}
-
-static int update_root_dev_clip(struct net_device *dev)
-{
- struct net_device *root_dev = NULL;
- int i, ret = 0;
-
- /* First populate the real net device's IPv6 addresses */
- ret = update_dev_clip(dev, dev);
- if (ret)
- return ret;
-
- /* Parse all bond and vlan devices layered on top of the physical dev */
- root_dev = netdev_master_upper_dev_get_rcu(dev);
- if (root_dev) {
- ret = update_dev_clip(root_dev, dev);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < VLAN_N_VID; i++) {
- root_dev = __vlan_find_dev_deep_rcu(dev, htons(ETH_P_8021Q), i);
- if (!root_dev)
- continue;
-
- ret = update_dev_clip(root_dev, dev);
- if (ret)
- break;
- }
- return ret;
-}
-
static void update_clip(const struct adapter *adap)
{
int i;
@@ -4375,7 +4176,7 @@ static void update_clip(const struct adapter *adap)
ret = 0;
if (dev)
- ret = update_root_dev_clip(dev);
+ ret = cxgb4_update_root_dev_clip(dev);
if (ret < 0)
break;
@@ -4567,13 +4368,13 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
f->fs.val.lip[i] = val[i];
f->fs.mask.lip[i] = ~0;
}
- if (adap->params.tp.vlan_pri_map & F_PORT) {
+ if (adap->params.tp.vlan_pri_map & PORT_F) {
f->fs.val.iport = port;
f->fs.mask.iport = mask;
}
}
- if (adap->params.tp.vlan_pri_map & F_PROTOCOL) {
+ if (adap->params.tp.vlan_pri_map & PROTOCOL_F) {
f->fs.val.proto = IPPROTO_TCP;
f->fs.mask.proto = ~0;
}
@@ -4779,11 +4580,15 @@ static const struct net_device_ops cxgb4_netdev_ops = {
#ifdef CONFIG_NET_POLL_CONTROLLER
.ndo_poll_controller = cxgb_netpoll,
#endif
+#ifdef CONFIG_NET_RX_BUSY_POLL
+ .ndo_busy_poll = cxgb_busy_poll,
+#endif
+
};
void t4_fatal_err(struct adapter *adap)
{
- t4_set_reg_field(adap, SGE_CONTROL, GLOBALENABLE, 0);
+ t4_set_reg_field(adap, SGE_CONTROL_A, GLOBALENABLE_F, 0);
t4_intr_disable(adap);
dev_alert(adap->pdev_dev, "encountered fatal error, adapter stopped\n");
}
@@ -4858,16 +4663,16 @@ static void setup_memwin(struct adapter *adap)
mem_win2_base = MEMWIN2_BASE_T5;
mem_win2_aperture = MEMWIN2_APERTURE_T5;
}
- t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 0),
- mem_win0_base | BIR(0) |
- WINDOW(ilog2(MEMWIN0_APERTURE) - 10));
- t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 1),
- mem_win1_base | BIR(0) |
- WINDOW(ilog2(MEMWIN1_APERTURE) - 10));
- t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2),
- mem_win2_base | BIR(0) |
- WINDOW(ilog2(mem_win2_aperture) - 10));
- t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 2));
+ t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 0),
+ mem_win0_base | BIR_V(0) |
+ WINDOW_V(ilog2(MEMWIN0_APERTURE) - 10));
+ t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 1),
+ mem_win1_base | BIR_V(0) |
+ WINDOW_V(ilog2(MEMWIN1_APERTURE) - 10));
+ t4_write_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2),
+ mem_win2_base | BIR_V(0) |
+ WINDOW_V(ilog2(mem_win2_aperture) - 10));
+ t4_read_reg(adap, PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 2));
}
static void setup_memwin_rdma(struct adapter *adap)
@@ -4881,13 +4686,13 @@ static void setup_memwin_rdma(struct adapter *adap)
start += OCQ_WIN_OFFSET(adap->pdev, &adap->vres);
sz_kb = roundup_pow_of_two(adap->vres.ocq.size) >> 10;
t4_write_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, 3),
- start | BIR(1) | WINDOW(ilog2(sz_kb)));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, 3),
+ start | BIR_V(1) | WINDOW_V(ilog2(sz_kb)));
t4_write_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3),
adap->vres.ocq.start);
t4_read_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, 3));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, 3));
}
}
@@ -4936,38 +4741,38 @@ static int adap_init1(struct adapter *adap, struct fw_caps_config_cmd *c)
t4_sge_init(adap);
/* tweak some settings */
- t4_write_reg(adap, TP_SHIFT_CNT, 0x64f8849);
- t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(PAGE_SHIFT - 12));
- t4_write_reg(adap, TP_PIO_ADDR, TP_INGRESS_CONFIG);
- v = t4_read_reg(adap, TP_PIO_DATA);
- t4_write_reg(adap, TP_PIO_DATA, v & ~CSUM_HAS_PSEUDO_HDR);
+ t4_write_reg(adap, TP_SHIFT_CNT_A, 0x64f8849);
+ t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(PAGE_SHIFT - 12));
+ t4_write_reg(adap, TP_PIO_ADDR_A, TP_INGRESS_CONFIG_A);
+ v = t4_read_reg(adap, TP_PIO_DATA_A);
+ t4_write_reg(adap, TP_PIO_DATA_A, v & ~CSUM_HAS_PSEUDO_HDR_F);
/* first 4 Tx modulation queues point to consecutive Tx channels */
adap->params.tp.tx_modq_map = 0xE4;
- t4_write_reg(adap, A_TP_TX_MOD_QUEUE_REQ_MAP,
- V_TX_MOD_QUEUE_REQ_MAP(adap->params.tp.tx_modq_map));
+ t4_write_reg(adap, TP_TX_MOD_QUEUE_REQ_MAP_A,
+ TX_MOD_QUEUE_REQ_MAP_V(adap->params.tp.tx_modq_map));
/* associate each Tx modulation queue with consecutive Tx channels */
v = 0x84218421;
- t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
- &v, 1, A_TP_TX_SCHED_HDR);
- t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
- &v, 1, A_TP_TX_SCHED_FIFO);
- t4_write_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
- &v, 1, A_TP_TX_SCHED_PCMD);
+ t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &v, 1, TP_TX_SCHED_HDR_A);
+ t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &v, 1, TP_TX_SCHED_FIFO_A);
+ t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &v, 1, TP_TX_SCHED_PCMD_A);
#define T4_TX_MODQ_10G_WEIGHT_DEFAULT 16 /* in KB units */
if (is_offload(adap)) {
- t4_write_reg(adap, A_TP_TX_MOD_QUEUE_WEIGHT0,
- V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
- V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
- V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
- V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
- t4_write_reg(adap, A_TP_TX_MOD_CHANNEL_WEIGHT,
- V_TX_MODQ_WEIGHT0(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
- V_TX_MODQ_WEIGHT1(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
- V_TX_MODQ_WEIGHT2(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
- V_TX_MODQ_WEIGHT3(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
+ t4_write_reg(adap, TP_TX_MOD_QUEUE_WEIGHT0_A,
+ TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
+ t4_write_reg(adap, TP_TX_MOD_CHANNEL_WEIGHT_A,
+ TX_MODQ_WEIGHT0_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ TX_MODQ_WEIGHT1_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ TX_MODQ_WEIGHT2_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT) |
+ TX_MODQ_WEIGHT3_V(T4_TX_MODQ_10G_WEIGHT_DEFAULT));
}
/* get basic stuff going */
@@ -5013,16 +4818,16 @@ static int adap_init0_tweaks(struct adapter *adapter)
rx_dma_offset);
rx_dma_offset = 2;
}
- t4_set_reg_field(adapter, SGE_CONTROL,
- PKTSHIFT_MASK,
- PKTSHIFT(rx_dma_offset));
+ t4_set_reg_field(adapter, SGE_CONTROL_A,
+ PKTSHIFT_V(PKTSHIFT_M),
+ PKTSHIFT_V(rx_dma_offset));
/*
* Don't include the "IP Pseudo Header" in CPL_RX_PKT checksums: Linux
* adds the pseudo header itself.
*/
- t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG,
- CSUM_HAS_PSEUDO_HDR, 0);
+ t4_tp_wr_bits_indirect(adapter, TP_INGRESS_CONFIG_A,
+ CSUM_HAS_PSEUDO_HDR_F, 0);
return 0;
}
@@ -5046,7 +4851,7 @@ static int adap_init0_config(struct adapter *adapter, int reset)
*/
if (reset) {
ret = t4_fw_reset(adapter, adapter->mbox,
- PIORSTMODE | PIORST);
+ PIORSTMODE_F | PIORST_F);
if (ret < 0)
goto bye;
}
@@ -5212,12 +5017,9 @@ static int adap_init0_config(struct adapter *adapter, int reset)
if (ret < 0)
goto bye;
- /*
- * Return successfully and note that we're operating with parameters
- * not supplied by the driver, rather than from hard-wired
- * initialization constants burried in the driver.
+ /* Emit Firmware Configuration File information and return
+ * successfully.
*/
- adapter->flags |= USING_SOFT_PARAMS;
dev_info(adapter->pdev_dev, "Successfully configured using Firmware "\
"Configuration File \"%s\", version %#x, computed checksum %#x\n",
config_name, finiver, cfcsum);
@@ -5235,249 +5037,6 @@ bye:
return ret;
}
-/*
- * Attempt to initialize the adapter via hard-coded, driver supplied
- * parameters ...
- */
-static int adap_init0_no_config(struct adapter *adapter, int reset)
-{
- struct sge *s = &adapter->sge;
- struct fw_caps_config_cmd caps_cmd;
- u32 v;
- int i, ret;
-
- /*
- * Reset device if necessary
- */
- if (reset) {
- ret = t4_fw_reset(adapter, adapter->mbox,
- PIORSTMODE | PIORST);
- if (ret < 0)
- goto bye;
- }
-
- /*
- * Get device capabilities and select which we'll be using.
- */
- memset(&caps_cmd, 0, sizeof(caps_cmd));
- caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_READ_F);
- caps_cmd.cfvalid_to_len16 = htonl(FW_LEN16(caps_cmd));
- ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
- &caps_cmd);
- if (ret < 0)
- goto bye;
-
- if (caps_cmd.niccaps & htons(FW_CAPS_CONFIG_NIC_VM)) {
- if (!vf_acls)
- caps_cmd.niccaps ^= htons(FW_CAPS_CONFIG_NIC_VM);
- else
- caps_cmd.niccaps = htons(FW_CAPS_CONFIG_NIC_VM);
- } else if (vf_acls) {
- dev_err(adapter->pdev_dev, "virtualization ACLs not supported");
- goto bye;
- }
- caps_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST_F | FW_CMD_WRITE_F);
- ret = t4_wr_mbox(adapter, adapter->mbox, &caps_cmd, sizeof(caps_cmd),
- NULL);
- if (ret < 0)
- goto bye;
-
- /*
- * Tweak configuration based on system architecture, module
- * parameters, etc.
- */
- ret = adap_init0_tweaks(adapter);
- if (ret < 0)
- goto bye;
-
- /*
- * Select RSS Global Mode we want to use. We use "Basic Virtual"
- * mode which maps each Virtual Interface to its own section of
- * the RSS Table and we turn on all map and hash enables ...
- */
- adapter->flags |= RSS_TNLALLLOOKUP;
- ret = t4_config_glbl_rss(adapter, adapter->mbox,
- FW_RSS_GLB_CONFIG_CMD_MODE_BASICVIRTUAL,
- FW_RSS_GLB_CONFIG_CMD_TNLMAPEN_F |
- FW_RSS_GLB_CONFIG_CMD_HASHTOEPLITZ_F |
- ((adapter->flags & RSS_TNLALLLOOKUP) ?
- FW_RSS_GLB_CONFIG_CMD_TNLALLLKP_F : 0));
- if (ret < 0)
- goto bye;
-
- /*
- * Set up our own fundamental resource provisioning ...
- */
- ret = t4_cfg_pfvf(adapter, adapter->mbox, adapter->fn, 0,
- PFRES_NEQ, PFRES_NETHCTRL,
- PFRES_NIQFLINT, PFRES_NIQ,
- PFRES_TC, PFRES_NVI,
- FW_PFVF_CMD_CMASK_M,
- pfvfres_pmask(adapter, adapter->fn, 0),
- PFRES_NEXACTF,
- PFRES_R_CAPS, PFRES_WX_CAPS);
- if (ret < 0)
- goto bye;
-
- /*
- * Perform low level SGE initialization. We need to do this before we
- * send the firmware the INITIALIZE command because that will cause
- * any other PF Drivers which are waiting for the Master
- * Initialization to proceed forward.
- */
- for (i = 0; i < SGE_NTIMERS - 1; i++)
- s->timer_val[i] = min(intr_holdoff[i], MAX_SGE_TIMERVAL);
- s->timer_val[SGE_NTIMERS - 1] = MAX_SGE_TIMERVAL;
- s->counter_val[0] = 1;
- for (i = 1; i < SGE_NCOUNTERS; i++)
- s->counter_val[i] = min(intr_cnt[i - 1],
- THRESHOLD_0_GET(THRESHOLD_0_MASK));
- t4_sge_init(adapter);
-
-#ifdef CONFIG_PCI_IOV
- /*
- * Provision resource limits for Virtual Functions. We currently
- * grant them all the same static resource limits except for the Port
- * Access Rights Mask which we're assigning based on the PF. All of
- * the static provisioning stuff for both the PF and VF really needs
- * to be managed in a persistent manner for each device which the
- * firmware controls.
- */
- {
- int pf, vf;
-
- for (pf = 0; pf < ARRAY_SIZE(num_vf); pf++) {
- if (num_vf[pf] <= 0)
- continue;
-
- /* VF numbering starts at 1! */
- for (vf = 1; vf <= num_vf[pf]; vf++) {
- ret = t4_cfg_pfvf(adapter, adapter->mbox,
- pf, vf,
- VFRES_NEQ, VFRES_NETHCTRL,
- VFRES_NIQFLINT, VFRES_NIQ,
- VFRES_TC, VFRES_NVI,
- FW_PFVF_CMD_CMASK_M,
- pfvfres_pmask(
- adapter, pf, vf),
- VFRES_NEXACTF,
- VFRES_R_CAPS, VFRES_WX_CAPS);
- if (ret < 0)
- dev_warn(adapter->pdev_dev,
- "failed to "\
- "provision pf/vf=%d/%d; "
- "err=%d\n", pf, vf, ret);
- }
- }
- }
-#endif
-
- /*
- * Set up the default filter mode. Later we'll want to implement this
- * via a firmware command, etc. ... This needs to be done before the
- * firmare initialization command ... If the selected set of fields
- * isn't equal to the default value, we'll need to make sure that the
- * field selections will fit in the 36-bit budget.
- */
- if (tp_vlan_pri_map != TP_VLAN_PRI_MAP_DEFAULT) {
- int j, bits = 0;
-
- for (j = TP_VLAN_PRI_MAP_FIRST; j <= TP_VLAN_PRI_MAP_LAST; j++)
- switch (tp_vlan_pri_map & (1 << j)) {
- case 0:
- /* compressed filter field not enabled */
- break;
- case FCOE_MASK:
- bits += 1;
- break;
- case PORT_MASK:
- bits += 3;
- break;
- case VNIC_ID_MASK:
- bits += 17;
- break;
- case VLAN_MASK:
- bits += 17;
- break;
- case TOS_MASK:
- bits += 8;
- break;
- case PROTOCOL_MASK:
- bits += 8;
- break;
- case ETHERTYPE_MASK:
- bits += 16;
- break;
- case MACMATCH_MASK:
- bits += 9;
- break;
- case MPSHITTYPE_MASK:
- bits += 3;
- break;
- case FRAGMENTATION_MASK:
- bits += 1;
- break;
- }
-
- if (bits > 36) {
- dev_err(adapter->pdev_dev,
- "tp_vlan_pri_map=%#x needs %d bits > 36;"\
- " using %#x\n", tp_vlan_pri_map, bits,
- TP_VLAN_PRI_MAP_DEFAULT);
- tp_vlan_pri_map = TP_VLAN_PRI_MAP_DEFAULT;
- }
- }
- v = tp_vlan_pri_map;
- t4_write_indirect(adapter, TP_PIO_ADDR, TP_PIO_DATA,
- &v, 1, TP_VLAN_PRI_MAP);
-
- /*
- * We need Five Tuple Lookup mode to be set in TP_GLOBAL_CONFIG order
- * to support any of the compressed filter fields above. Newer
- * versions of the firmware do this automatically but it doesn't hurt
- * to set it here. Meanwhile, we do _not_ need to set Lookup Every
- * Packet in TP_INGRESS_CONFIG to support matching non-TCP packets
- * since the firmware automatically turns this on and off when we have
- * a non-zero number of filters active (since it does have a
- * performance impact).
- */
- if (tp_vlan_pri_map)
- t4_set_reg_field(adapter, TP_GLOBAL_CONFIG,
- FIVETUPLELOOKUP_MASK,
- FIVETUPLELOOKUP_MASK);
-
- /*
- * Tweak some settings.
- */
- t4_write_reg(adapter, TP_SHIFT_CNT, SYNSHIFTMAX(6) |
- RXTSHIFTMAXR1(4) | RXTSHIFTMAXR2(15) |
- PERSHIFTBACKOFFMAX(8) | PERSHIFTMAX(8) |
- KEEPALIVEMAXR1(4) | KEEPALIVEMAXR2(9));
-
- /*
- * Get basic stuff going by issuing the Firmware Initialize command.
- * Note that this _must_ be after all PFVF commands ...
- */
- ret = t4_fw_initialize(adapter, adapter->mbox);
- if (ret < 0)
- goto bye;
-
- /*
- * Return successfully!
- */
- dev_info(adapter->pdev_dev, "Successfully configured using built-in "\
- "driver parameters\n");
- return 0;
-
- /*
- * Something bad happened. Return the error ...
- */
-bye:
- return ret;
-}
-
static struct fw_info fw_info_array[] = {
{
.chip = CHELSIO_T4,
@@ -5529,6 +5088,8 @@ static int adap_init0(struct adapter *adap)
enum dev_state state;
u32 params[7], val[7];
struct fw_caps_config_cmd caps_cmd;
+ struct fw_devlog_cmd devlog_cmd;
+ u32 devlog_meminfo;
int reset = 1;
/* Contact FW, advertising Master capability */
@@ -5590,8 +5151,7 @@ static int adap_init0(struct adapter *adap)
state, &reset);
/* Cleaning up */
- if (fw != NULL)
- release_firmware(fw);
+ release_firmware(fw);
t4_free_mem(card_fw);
if (ret < 0)
@@ -5609,6 +5169,30 @@ static int adap_init0(struct adapter *adap)
if (ret < 0)
goto bye;
+ /* Read firmware device log parameters. We really need to find a way
+ * to get these parameters initialized with some default values (which
+ * are likely to be correct) for the case where we either don't
+ * attache to the firmware or it's crashed when we probe the adapter.
+ * That way we'll still be able to perform early firmware startup
+ * debugging ... If the request to get the Firmware's Device Log
+ * parameters fails, we'll live so we don't make that a fatal error.
+ */
+ memset(&devlog_cmd, 0, sizeof(devlog_cmd));
+ devlog_cmd.op_to_write = htonl(FW_CMD_OP_V(FW_DEVLOG_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_READ_F);
+ devlog_cmd.retval_len16 = htonl(FW_LEN16(devlog_cmd));
+ ret = t4_wr_mbox(adap, adap->mbox, &devlog_cmd, sizeof(devlog_cmd),
+ &devlog_cmd);
+ if (ret == 0) {
+ devlog_meminfo =
+ ntohl(devlog_cmd.memtype_devlog_memaddr16_devlog);
+ adap->params.devlog.memtype =
+ FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(devlog_meminfo);
+ adap->params.devlog.start =
+ FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(devlog_meminfo) << 4;
+ adap->params.devlog.size = ntohl(devlog_cmd.memsize_devlog);
+ }
+
/*
* Find out what ports are available to us. Note that we need to do
* this before calling adap_init0_no_config() since it needs nports
@@ -5624,88 +5208,58 @@ static int adap_init0(struct adapter *adap)
adap->params.nports = hweight32(port_vec);
adap->params.portvec = port_vec;
- /*
- * If the firmware is initialized already (and we're not forcing a
- * master initialization), note that we're living with existing
- * adapter parameters. Otherwise, it's time to try initializing the
- * adapter ...
+ /* If the firmware is initialized already, emit a simply note to that
+ * effect. Otherwise, it's time to try initializing the adapter.
*/
if (state == DEV_STATE_INIT) {
dev_info(adap->pdev_dev, "Coming up as %s: "\
"Adapter already initialized\n",
adap->flags & MASTER_PF ? "MASTER" : "SLAVE");
- adap->flags |= USING_SOFT_PARAMS;
} else {
dev_info(adap->pdev_dev, "Coming up as MASTER: "\
"Initializing adapter\n");
- /*
- * If the firmware doesn't support Configuration
- * Files warn user and exit,
+
+ /* Find out whether we're dealing with a version of the
+ * firmware which has configuration file support.
*/
- if (ret < 0)
- dev_warn(adap->pdev_dev, "Firmware doesn't support "
- "configuration file.\n");
- if (force_old_init)
- ret = adap_init0_no_config(adap, reset);
- else {
- /*
- * Find out whether we're dealing with a version of
- * the firmware which has configuration file support.
- */
- params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
- FW_PARAMS_PARAM_X_V(
- FW_PARAMS_PARAM_DEV_CF));
- ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
- params, val);
-
- /*
- * If the firmware doesn't support Configuration
- * Files, use the old Driver-based, hard-wired
- * initialization. Otherwise, try using the
- * Configuration File support and fall back to the
- * Driver-based initialization if there's no
- * Configuration File found.
- */
- if (ret < 0)
- ret = adap_init0_no_config(adap, reset);
- else {
- /*
- * The firmware provides us with a memory
- * buffer where we can load a Configuration
- * File from the host if we want to override
- * the Configuration File in flash.
- */
+ params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_CF));
+ ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 1,
+ params, val);
- ret = adap_init0_config(adap, reset);
- if (ret == -ENOENT) {
- dev_info(adap->pdev_dev,
- "No Configuration File present "
- "on adapter. Using hard-wired "
- "configuration parameters.\n");
- ret = adap_init0_no_config(adap, reset);
- }
- }
+ /* If the firmware doesn't support Configuration Files,
+ * return an error.
+ */
+ if (ret < 0) {
+ dev_err(adap->pdev_dev, "firmware doesn't support "
+ "Firmware Configuration Files\n");
+ goto bye;
+ }
+
+ /* The firmware provides us with a memory buffer where we can
+ * load a Configuration File from the host if we want to
+ * override the Configuration File in flash.
+ */
+ ret = adap_init0_config(adap, reset);
+ if (ret == -ENOENT) {
+ dev_err(adap->pdev_dev, "no Configuration File "
+ "present on adapter.\n");
+ goto bye;
}
if (ret < 0) {
- dev_err(adap->pdev_dev,
- "could not initialize adapter, error %d\n",
- -ret);
+ dev_err(adap->pdev_dev, "could not initialize "
+ "adapter, error %d\n", -ret);
goto bye;
}
}
- /*
- * If we're living with non-hard-coded parameters (either from a
- * Firmware Configuration File or values programmed by a different PF
- * Driver), give the SGE code a chance to pull in anything that it
- * needs ... Note that this must be called after we retrieve our VPD
- * parameters in order to know how to convert core ticks to seconds.
+ /* Give the SGE code a chance to pull in anything that it needs ...
+ * Note that this must be called after we retrieve our VPD parameters
+ * in order to know how to convert core ticks to seconds, etc.
*/
- if (adap->flags & USING_SOFT_PARAMS) {
- ret = t4_sge_init(adap);
- if (ret < 0)
- goto bye;
- }
+ ret = t4_sge_init(adap);
+ if (ret < 0)
+ goto bye;
if (is_bypass_device(adap->pdev->device))
adap->params.bypass = 1;
@@ -5739,6 +5293,14 @@ static int adap_init0(struct adapter *adap)
adap->tids.nftids = val[4] - val[3] + 1;
adap->sge.ingr_start = val[5];
+ params[0] = FW_PARAM_PFVF(CLIP_START);
+ params[1] = FW_PARAM_PFVF(CLIP_END);
+ ret = t4_query_params(adap, adap->mbox, adap->fn, 0, 2, params, val);
+ if (ret < 0)
+ goto bye;
+ adap->clipt_start = val[0];
+ adap->clipt_end = val[1];
+
/* query params related to active filter region */
params[0] = FW_PARAM_PFVF(ACTIVE_FILTER_START);
params[1] = FW_PARAM_PFVF(ACTIVE_FILTER_END);
@@ -6401,7 +5963,7 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
goto out_unmap_bar0;
/* We control everything through one PF */
- func = SOURCEPF_GET(readl(regs + PL_WHOAMI));
+ func = SOURCEPF_G(readl(regs + PL_WHOAMI_A));
if (func != ent->driver_data) {
iounmap(regs);
pci_disable_device(pdev);
@@ -6467,9 +6029,11 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
if (!is_t4(adapter->params.chip)) {
- s_qpp = QUEUESPERPAGEPF1 * adapter->fn;
- qpp = 1 << QUEUESPERPAGEPF0_GET(t4_read_reg(adapter,
- SGE_EGRESS_QUEUES_PER_PAGE_PF) >> s_qpp);
+ s_qpp = (QUEUESPERPAGEPF0_S +
+ (QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) *
+ adapter->fn);
+ qpp = 1 << QUEUESPERPAGEPF0_G(t4_read_reg(adapter,
+ SGE_EGRESS_QUEUES_PER_PAGE_PF_A) >> s_qpp);
num_seg = PAGE_SIZE / SEGMENT_SIZE;
/* Each segment size is 128B. Write coalescing is enabled only
@@ -6557,6 +6121,18 @@ static int init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->params.offload = 0;
}
+#if IS_ENABLED(CONFIG_IPV6)
+ adapter->clipt = t4_init_clip_tbl(adapter->clipt_start,
+ adapter->clipt_end);
+ if (!adapter->clipt) {
+ /* We tolerate a lack of clip_table, giving up
+ * some functionality
+ */
+ dev_warn(&pdev->dev,
+ "could not allocate Clip table, continuing\n");
+ adapter->params.offload = 0;
+ }
+#endif
if (is_offload(adapter) && tid_init(&adapter->tids) < 0) {
dev_warn(&pdev->dev, "could not allocate TID table, "
"continuing\n");
@@ -6682,6 +6258,9 @@ static void remove_one(struct pci_dev *pdev)
cxgb_down(adapter);
free_some_resources(adapter);
+#if IS_ENABLED(CONFIG_IPV6)
+ t4_cleanup_clip_tbl(adapter);
+#endif
iounmap(adapter->regs);
if (!is_t4(adapter->params.chip))
iounmap(adapter->bar2);
@@ -6720,7 +6299,10 @@ static int __init cxgb4_init_module(void)
debugfs_remove(cxgb4_debugfs_root);
#if IS_ENABLED(CONFIG_IPV6)
- register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
+ if (!inet6addr_registered) {
+ register_inet6addr_notifier(&cxgb4_inet6addr_notifier);
+ inet6addr_registered = true;
+ }
#endif
return ret;
@@ -6729,7 +6311,10 @@ static int __init cxgb4_init_module(void)
static void __exit cxgb4_cleanup_module(void)
{
#if IS_ENABLED(CONFIG_IPV6)
- unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier);
+ if (inet6addr_registered) {
+ unregister_inet6addr_notifier(&cxgb4_inet6addr_notifier);
+ inet6addr_registered = false;
+ }
#endif
pci_unregister_driver(&cxgb4_driver);
debugfs_remove(cxgb4_debugfs_root); /* NULL ok */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
index 152b4c4c7809..78ab4d406ce2 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/cxgb4_uld.h
@@ -173,9 +173,6 @@ int cxgb4_create_server_filter(const struct net_device *dev, unsigned int stid,
unsigned char port, unsigned char mask);
int cxgb4_remove_server_filter(const struct net_device *dev, unsigned int stid,
unsigned int queue, bool ipv6);
-int cxgb4_clip_get(const struct net_device *dev, const struct in6_addr *lip);
-int cxgb4_clip_release(const struct net_device *dev,
- const struct in6_addr *lip);
static inline void set_wr_txq(struct sk_buff *skb, int prio, int queue)
{
diff --git a/drivers/net/ethernet/chelsio/cxgb4/l2t.c b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
index a047baa9fd04..252efc29321f 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/l2t.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/l2t.c
@@ -46,6 +46,7 @@
#include "t4_msg.h"
#include "t4fw_api.h"
#include "t4_regs.h"
+#include "t4_values.h"
#define VLAN_NONE 0xfff
@@ -150,8 +151,8 @@ static int write_l2e(struct adapter *adap, struct l2t_entry *e, int sync)
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_L2T_WRITE_REQ,
e->idx | (sync ? F_SYNC_WR : 0) |
- TID_QID(adap->sge.fw_evtq.abs_id)));
- req->params = htons(L2T_W_PORT(e->lport) | L2T_W_NOREPLY(!sync));
+ TID_QID_V(adap->sge.fw_evtq.abs_id)));
+ req->params = htons(L2T_W_PORT_V(e->lport) | L2T_W_NOREPLY_V(!sync));
req->l2t_idx = htons(e->idx);
req->vlan = htons(e->vlan);
if (e->neigh && !(e->neigh->dev->flags & IFF_LOOPBACK))
@@ -425,7 +426,7 @@ u64 cxgb4_select_ntuple(struct net_device *dev,
* in the Compressed Filter Tuple.
*/
if (tp->vlan_shift >= 0 && l2t->vlan != VLAN_NONE)
- ntuple |= (u64)(F_FT_VLAN_VLD | l2t->vlan) << tp->vlan_shift;
+ ntuple |= (u64)(FT_VLAN_VLD_F | l2t->vlan) << tp->vlan_shift;
if (tp->port_shift >= 0)
ntuple |= (u64)l2t->lport << tp->port_shift;
@@ -439,9 +440,9 @@ u64 cxgb4_select_ntuple(struct net_device *dev,
u32 pf = FW_VIID_PFN_G(viid);
u32 vld = FW_VIID_VIVLD_G(viid);
- ntuple |= (u64)(V_FT_VNID_ID_VF(vf) |
- V_FT_VNID_ID_PF(pf) |
- V_FT_VNID_ID_VLD(vld)) << tp->vnic_shift;
+ ntuple |= (u64)(FT_VNID_ID_VF_V(vf) |
+ FT_VNID_ID_PF_V(pf) |
+ FT_VNID_ID_VLD_V(vld)) << tp->vnic_shift;
}
return ntuple;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/sge.c b/drivers/net/ethernet/chelsio/cxgb4/sge.c
index ebf935a1e352..b4b9f6048fe7 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/sge.c
@@ -43,8 +43,12 @@
#include <linux/export.h>
#include <net/ipv6.h>
#include <net/tcp.h>
+#ifdef CONFIG_NET_RX_BUSY_POLL
+#include <net/busy_poll.h>
+#endif /* CONFIG_NET_RX_BUSY_POLL */
#include "cxgb4.h"
#include "t4_regs.h"
+#include "t4_values.h"
#include "t4_msg.h"
#include "t4fw_api.h"
@@ -521,10 +525,12 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
{
u32 val;
if (q->pend_cred >= 8) {
- val = PIDX(q->pend_cred / 8);
- if (!is_t4(adap->params.chip))
- val |= DBTYPE(1);
- val |= DBPRIO(1);
+ if (is_t4(adap->params.chip))
+ val = PIDX_V(q->pend_cred / 8);
+ else
+ val = PIDX_T5_V(q->pend_cred / 8) |
+ DBTYPE_F;
+ val |= DBPRIO_F;
wmb();
/* If we don't have access to the new User Doorbell (T5+), use
@@ -532,10 +538,10 @@ static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
* mechanism.
*/
if (unlikely(q->bar2_addr == NULL)) {
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- val | QID(q->cntxt_id));
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
+ val | QID_V(q->cntxt_id));
} else {
- writel(val | QID(q->bar2_qid),
+ writel(val | QID_V(q->bar2_qid),
q->bar2_addr + SGE_UDB_KDOORBELL);
/* This Write memory Barrier will force the write to
@@ -818,7 +824,8 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *q,
sgl->addr0 = cpu_to_be64(addr[1]);
}
- sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_NSGE(nfrags));
+ sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
+ ULPTX_NSGE_V(nfrags));
if (likely(--nfrags == 0))
return;
/*
@@ -884,7 +891,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
* doorbell mechanism; otherwise use the new BAR2 mechanism.
*/
if (unlikely(q->bar2_addr == NULL)) {
- u32 val = PIDX(n);
+ u32 val = PIDX_V(n);
unsigned long flags;
/* For T4 we need to participate in the Doorbell Recovery
@@ -892,14 +899,14 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
*/
spin_lock_irqsave(&q->db_lock, flags);
if (!q->db_disabled)
- t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL),
- QID(q->cntxt_id) | val);
+ t4_write_reg(adap, MYPF_REG(SGE_PF_KDOORBELL_A),
+ QID_V(q->cntxt_id) | val);
else
q->db_pidx_inc += n;
q->db_pidx = q->pidx;
spin_unlock_irqrestore(&q->db_lock, flags);
} else {
- u32 val = PIDX_T5(n);
+ u32 val = PIDX_T5_V(n);
/* T4 and later chips share the same PIDX field offset within
* the doorbell, but T5 and later shrank the field in order to
@@ -907,7 +914,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
* large in the first place (14 bits) so we just use the T5
* and later limits and warn if a Queue ID is too large.
*/
- WARN_ON(val & DBPRIO(1));
+ WARN_ON(val & DBPRIO_F);
/* If we're only writing a single TX Descriptor and we can use
* Inferred QID registers, we can use the Write Combining
@@ -923,7 +930,7 @@ static inline void ring_tx_db(struct adapter *adap, struct sge_txq *q, int n)
(q->bar2_addr + SGE_UDB_WCDOORBELL),
wr);
} else {
- writel(val | QID(q->bar2_qid),
+ writel(val | QID_V(q->bar2_qid),
q->bar2_addr + SGE_UDB_KDOORBELL);
}
@@ -1150,9 +1157,9 @@ out_free: dev_kfree_skb_any(skb);
cntrl = TXPKT_L4CSUM_DIS | TXPKT_IPCSUM_DIS;
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
q->vlan_ins++;
- cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb));
+ cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb));
}
cpl->ctrl0 = htonl(TXPKT_OPCODE(CPL_TX_PKT_XT) |
@@ -1716,6 +1723,7 @@ static void do_gro(struct sge_eth_rxq *rxq, const struct pkt_gl *gl,
skb->truesize += skb->data_len;
skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_record_rx_queue(skb, rxq->rspq.idx);
+ skb_mark_napi_id(skb, &rxq->rspq.napi);
if (rxq->rspq.netdev->features & NETIF_F_RXHASH)
skb_set_hash(skb, (__force u32)pkt->rsshdr.hash_val,
PKT_HASH_TYPE_L3);
@@ -1758,7 +1766,8 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
pkt = (const struct cpl_rx_pkt *)rsp;
csum_ok = pkt->csum_calc && !pkt->err_vec &&
(q->netdev->features & NETIF_F_RXCSUM);
- if ((pkt->l2info & htonl(RXF_TCP)) &&
+ if ((pkt->l2info & htonl(RXF_TCP_F)) &&
+ !(cxgb_poll_busy_polling(q)) &&
(q->netdev->features & NETIF_F_GRO) && csum_ok && !pkt->ip_frag) {
do_gro(rxq, si, pkt);
return 0;
@@ -1780,11 +1789,11 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
rxq->stats.pkts++;
- if (csum_ok && (pkt->l2info & htonl(RXF_UDP | RXF_TCP))) {
+ if (csum_ok && (pkt->l2info & htonl(RXF_UDP_F | RXF_TCP_F))) {
if (!pkt->ip_frag) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
rxq->stats.rx_cso++;
- } else if (pkt->l2info & htonl(RXF_IP)) {
+ } else if (pkt->l2info & htonl(RXF_IP_F)) {
__sum16 c = (__force __sum16)pkt->csum;
skb->csum = csum_unfold(c);
skb->ip_summed = CHECKSUM_COMPLETE;
@@ -1797,6 +1806,7 @@ int t4_ethrx_handler(struct sge_rspq *q, const __be64 *rsp,
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), ntohs(pkt->vlan));
rxq->stats.vlan_ex++;
}
+ skb_mark_napi_id(skb, &q->napi);
netif_receive_skb(skb);
return 0;
}
@@ -1959,6 +1969,38 @@ static int process_responses(struct sge_rspq *q, int budget)
return budget - budget_left;
}
+#ifdef CONFIG_NET_RX_BUSY_POLL
+int cxgb_busy_poll(struct napi_struct *napi)
+{
+ struct sge_rspq *q = container_of(napi, struct sge_rspq, napi);
+ unsigned int params, work_done;
+ u32 val;
+
+ if (!cxgb_poll_lock_poll(q))
+ return LL_FLUSH_BUSY;
+
+ work_done = process_responses(q, 4);
+ params = QINTR_TIMER_IDX(TIMERREG_COUNTER0_X) | QINTR_CNT_EN;
+ q->next_intr_params = params;
+ val = CIDXINC_V(work_done) | SEINTARM_V(params);
+
+ /* If we don't have access to the new User GTS (T5+), use the old
+ * doorbell mechanism; otherwise use the new BAR2 mechanism.
+ */
+ if (unlikely(!q->bar2_addr))
+ t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A),
+ val | INGRESSQID_V((u32)q->cntxt_id));
+ else {
+ writel(val | INGRESSQID_V(q->bar2_qid),
+ q->bar2_addr + SGE_UDB_GTS);
+ wmb();
+ }
+
+ cxgb_poll_unlock_poll(q);
+ return work_done;
+}
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
/**
* napi_rx_handler - the NAPI handler for Rx processing
* @napi: the napi instance
@@ -1974,9 +2016,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
{
unsigned int params;
struct sge_rspq *q = container_of(napi, struct sge_rspq, napi);
- int work_done = process_responses(q, budget);
+ int work_done;
u32 val;
+ if (!cxgb_poll_lock_napi(q))
+ return budget;
+
+ work_done = process_responses(q, budget);
if (likely(work_done < budget)) {
int timer_index;
@@ -2001,19 +2047,20 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
} else
params = QINTR_TIMER_IDX(7);
- val = CIDXINC(work_done) | SEINTARM(params);
+ val = CIDXINC_V(work_done) | SEINTARM_V(params);
/* If we don't have access to the new User GTS (T5+), use the old
* doorbell mechanism; otherwise use the new BAR2 mechanism.
*/
if (unlikely(q->bar2_addr == NULL)) {
- t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS),
- val | INGRESSQID((u32)q->cntxt_id));
+ t4_write_reg(q->adap, MYPF_REG(SGE_PF_GTS_A),
+ val | INGRESSQID_V((u32)q->cntxt_id));
} else {
- writel(val | INGRESSQID(q->bar2_qid),
+ writel(val | INGRESSQID_V(q->bar2_qid),
q->bar2_addr + SGE_UDB_GTS);
wmb();
}
+ cxgb_poll_unlock_napi(q);
return work_done;
}
@@ -2056,16 +2103,16 @@ static unsigned int process_intrq(struct adapter *adap)
rspq_next(q);
}
- val = CIDXINC(credits) | SEINTARM(q->intr_params);
+ val = CIDXINC_V(credits) | SEINTARM_V(q->intr_params);
/* If we don't have access to the new User GTS (T5+), use the old
* doorbell mechanism; otherwise use the new BAR2 mechanism.
*/
if (unlikely(q->bar2_addr == NULL)) {
- t4_write_reg(adap, MYPF_REG(SGE_PF_GTS),
- val | INGRESSQID(q->cntxt_id));
+ t4_write_reg(adap, MYPF_REG(SGE_PF_GTS_A),
+ val | INGRESSQID_V(q->cntxt_id));
} else {
- writel(val | INGRESSQID(q->bar2_qid),
+ writel(val | INGRESSQID_V(q->bar2_qid),
q->bar2_addr + SGE_UDB_GTS);
wmb();
}
@@ -2095,7 +2142,7 @@ static irqreturn_t t4_intr_intx(int irq, void *cookie)
{
struct adapter *adap = cookie;
- t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI), 0);
+ t4_write_reg(adap, MYPF_REG(PCIE_PF_CLI_A), 0);
if (t4_slow_intr_handler(adap) | process_intrq(adap))
return IRQ_HANDLED;
return IRQ_NONE; /* probably shared interrupt */
@@ -2142,9 +2189,9 @@ static void sge_rx_timer_cb(unsigned long data)
}
}
- t4_write_reg(adap, SGE_DEBUG_INDEX, 13);
- idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH);
- idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+ t4_write_reg(adap, SGE_DEBUG_INDEX_A, 13);
+ idma_same_state_cnt[0] = t4_read_reg(adap, SGE_DEBUG_DATA_HIGH_A);
+ idma_same_state_cnt[1] = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A);
for (i = 0; i < 2; i++) {
u32 debug0, debug11;
@@ -2188,12 +2235,12 @@ static void sge_rx_timer_cb(unsigned long data)
/* Read and save the SGE IDMA State and Queue ID information.
* We do this every time in case it changes across time ...
*/
- t4_write_reg(adap, SGE_DEBUG_INDEX, 0);
- debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+ t4_write_reg(adap, SGE_DEBUG_INDEX_A, 0);
+ debug0 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A);
s->idma_state[i] = (debug0 >> (i * 9)) & 0x3f;
- t4_write_reg(adap, SGE_DEBUG_INDEX, 11);
- debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW);
+ t4_write_reg(adap, SGE_DEBUG_INDEX_A, 11);
+ debug11 = t4_read_reg(adap, SGE_DEBUG_DATA_LOW_A);
s->idma_qid[i] = (debug11 >> (i * 16)) & 0xffff;
CH_WARN(adap, "SGE idma%u, queue%u, maybe stuck state%u %dsecs (debug0=%#x, debug11=%#x)\n",
@@ -2337,6 +2384,7 @@ int t4_sge_alloc_rxq(struct adapter *adap, struct sge_rspq *iq, bool fwevtq,
goto err;
netif_napi_add(dev, &iq->napi, napi_rx_handler, 64);
+ napi_hash_add(&iq->napi);
iq->cur_desc = iq->desc;
iq->cidx = 0;
iq->gen = 1;
@@ -2594,6 +2642,7 @@ static void free_rspq_fl(struct adapter *adap, struct sge_rspq *rq,
rq->cntxt_id, fl_id, 0xffff);
dma_free_coherent(adap->pdev_dev, (rq->size + 1) * rq->iqe_len,
rq->desc, rq->phys_addr);
+ napi_hash_del(&rq->napi);
netif_napi_del(&rq->napi);
rq->netdev = NULL;
rq->cntxt_id = rq->abs_id = 0;
@@ -2738,24 +2787,11 @@ void t4_sge_stop(struct adapter *adap)
}
/**
- * t4_sge_init - initialize SGE
+ * t4_sge_init_soft - grab core SGE values needed by SGE code
* @adap: the adapter
*
- * Performs SGE initialization needed every time after a chip reset.
- * We do not initialize any of the queues here, instead the driver
- * top-level must request them individually.
- *
- * Called in two different modes:
- *
- * 1. Perform actual hardware initialization and record hard-coded
- * parameters which were used. This gets used when we're the
- * Master PF and the Firmware Configuration File support didn't
- * work for some reason.
- *
- * 2. We're not the Master PF or initialization was performed with
- * a Firmware Configuration File. In this case we need to grab
- * any of the SGE operating parameters that we need to have in
- * order to do our job and make sure we can live with them ...
+ * We need to grab the SGE operating parameters that we need to have
+ * in order to do our job and make sure we can live with them.
*/
static int t4_sge_init_soft(struct adapter *adap)
@@ -2770,8 +2806,8 @@ static int t4_sge_init_soft(struct adapter *adap)
* process_responses() and that only packet data is going to the
* Free Lists.
*/
- if ((t4_read_reg(adap, SGE_CONTROL) & RXPKTCPLMODE_MASK) !=
- RXPKTCPLMODE(X_RXPKTCPLMODE_SPLIT)) {
+ if ((t4_read_reg(adap, SGE_CONTROL_A) & RXPKTCPLMODE_F) !=
+ RXPKTCPLMODE_V(RXPKTCPLMODE_SPLIT_X)) {
dev_err(adap->pdev_dev, "bad SGE CPL MODE\n");
return -EINVAL;
}
@@ -2785,7 +2821,7 @@ static int t4_sge_init_soft(struct adapter *adap)
* XXX meet our needs!
*/
#define READ_FL_BUF(x) \
- t4_read_reg(adap, SGE_FL_BUFFER_SIZE0+(x)*sizeof(u32))
+ t4_read_reg(adap, SGE_FL_BUFFER_SIZE0_A+(x)*sizeof(u32))
fl_small_pg = READ_FL_BUF(RX_SMALL_PG_BUF);
fl_large_pg = READ_FL_BUF(RX_LARGE_PG_BUF);
@@ -2823,99 +2859,38 @@ static int t4_sge_init_soft(struct adapter *adap)
* Retrieve our RX interrupt holdoff timer values and counter
* threshold values from the SGE parameters.
*/
- timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1);
- timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3);
- timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5);
+ timer_value_0_and_1 = t4_read_reg(adap, SGE_TIMER_VALUE_0_AND_1_A);
+ timer_value_2_and_3 = t4_read_reg(adap, SGE_TIMER_VALUE_2_AND_3_A);
+ timer_value_4_and_5 = t4_read_reg(adap, SGE_TIMER_VALUE_4_AND_5_A);
s->timer_val[0] = core_ticks_to_us(adap,
- TIMERVALUE0_GET(timer_value_0_and_1));
+ TIMERVALUE0_G(timer_value_0_and_1));
s->timer_val[1] = core_ticks_to_us(adap,
- TIMERVALUE1_GET(timer_value_0_and_1));
+ TIMERVALUE1_G(timer_value_0_and_1));
s->timer_val[2] = core_ticks_to_us(adap,
- TIMERVALUE2_GET(timer_value_2_and_3));
+ TIMERVALUE2_G(timer_value_2_and_3));
s->timer_val[3] = core_ticks_to_us(adap,
- TIMERVALUE3_GET(timer_value_2_and_3));
+ TIMERVALUE3_G(timer_value_2_and_3));
s->timer_val[4] = core_ticks_to_us(adap,
- TIMERVALUE4_GET(timer_value_4_and_5));
+ TIMERVALUE4_G(timer_value_4_and_5));
s->timer_val[5] = core_ticks_to_us(adap,
- TIMERVALUE5_GET(timer_value_4_and_5));
+ TIMERVALUE5_G(timer_value_4_and_5));
- ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD);
- s->counter_val[0] = THRESHOLD_0_GET(ingress_rx_threshold);
- s->counter_val[1] = THRESHOLD_1_GET(ingress_rx_threshold);
- s->counter_val[2] = THRESHOLD_2_GET(ingress_rx_threshold);
- s->counter_val[3] = THRESHOLD_3_GET(ingress_rx_threshold);
-
- return 0;
-}
-
-static int t4_sge_init_hard(struct adapter *adap)
-{
- struct sge *s = &adap->sge;
-
- /*
- * Set up our basic SGE mode to deliver CPL messages to our Ingress
- * Queue and Packet Date to the Free List.
- */
- t4_set_reg_field(adap, SGE_CONTROL, RXPKTCPLMODE_MASK,
- RXPKTCPLMODE_MASK);
-
- /*
- * Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
- * and generate an interrupt when this occurs so we can recover.
- */
- if (is_t4(adap->params.chip)) {
- t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
- V_HP_INT_THRESH(M_HP_INT_THRESH) |
- V_LP_INT_THRESH(M_LP_INT_THRESH),
- V_HP_INT_THRESH(dbfifo_int_thresh) |
- V_LP_INT_THRESH(dbfifo_int_thresh));
- } else {
- t4_set_reg_field(adap, A_SGE_DBFIFO_STATUS,
- V_LP_INT_THRESH_T5(M_LP_INT_THRESH_T5),
- V_LP_INT_THRESH_T5(dbfifo_int_thresh));
- t4_set_reg_field(adap, SGE_DBFIFO_STATUS2,
- V_HP_INT_THRESH_T5(M_HP_INT_THRESH_T5),
- V_HP_INT_THRESH_T5(dbfifo_int_thresh));
- }
- t4_set_reg_field(adap, A_SGE_DOORBELL_CONTROL, F_ENABLE_DROP,
- F_ENABLE_DROP);
-
- /*
- * SGE_FL_BUFFER_SIZE0 (RX_SMALL_PG_BUF) is set up by
- * t4_fixup_host_params().
- */
- s->fl_pg_order = FL_PG_ORDER;
- if (s->fl_pg_order)
- t4_write_reg(adap,
- SGE_FL_BUFFER_SIZE0+RX_LARGE_PG_BUF*sizeof(u32),
- PAGE_SIZE << FL_PG_ORDER);
- t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_SMALL_MTU_BUF*sizeof(u32),
- FL_MTU_SMALL_BUFSIZE(adap));
- t4_write_reg(adap, SGE_FL_BUFFER_SIZE0+RX_LARGE_MTU_BUF*sizeof(u32),
- FL_MTU_LARGE_BUFSIZE(adap));
-
- /*
- * Note that the SGE Ingress Packet Count Interrupt Threshold and
- * Timer Holdoff values must be supplied by our caller.
- */
- t4_write_reg(adap, SGE_INGRESS_RX_THRESHOLD,
- THRESHOLD_0(s->counter_val[0]) |
- THRESHOLD_1(s->counter_val[1]) |
- THRESHOLD_2(s->counter_val[2]) |
- THRESHOLD_3(s->counter_val[3]));
- t4_write_reg(adap, SGE_TIMER_VALUE_0_AND_1,
- TIMERVALUE0(us_to_core_ticks(adap, s->timer_val[0])) |
- TIMERVALUE1(us_to_core_ticks(adap, s->timer_val[1])));
- t4_write_reg(adap, SGE_TIMER_VALUE_2_AND_3,
- TIMERVALUE2(us_to_core_ticks(adap, s->timer_val[2])) |
- TIMERVALUE3(us_to_core_ticks(adap, s->timer_val[3])));
- t4_write_reg(adap, SGE_TIMER_VALUE_4_AND_5,
- TIMERVALUE4(us_to_core_ticks(adap, s->timer_val[4])) |
- TIMERVALUE5(us_to_core_ticks(adap, s->timer_val[5])));
+ ingress_rx_threshold = t4_read_reg(adap, SGE_INGRESS_RX_THRESHOLD_A);
+ s->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold);
+ s->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold);
+ s->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold);
+ s->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold);
return 0;
}
+/**
+ * t4_sge_init - initialize SGE
+ * @adap: the adapter
+ *
+ * Perform low-level SGE code initialization needed every time after a
+ * chip reset.
+ */
int t4_sge_init(struct adapter *adap)
{
struct sge *s = &adap->sge;
@@ -2927,9 +2902,9 @@ int t4_sge_init(struct adapter *adap)
* Ingress Padding Boundary and Egress Status Page Size are set up by
* t4_fixup_host_params().
*/
- sge_control = t4_read_reg(adap, SGE_CONTROL);
- s->pktshift = PKTSHIFT_GET(sge_control);
- s->stat_len = (sge_control & EGRSTATUSPAGESIZE_MASK) ? 128 : 64;
+ sge_control = t4_read_reg(adap, SGE_CONTROL_A);
+ s->pktshift = PKTSHIFT_G(sge_control);
+ s->stat_len = (sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64;
/* T4 uses a single control field to specify both the PCIe Padding and
* Packing Boundary. T5 introduced the ability to specify these
@@ -2937,8 +2912,8 @@ int t4_sge_init(struct adapter *adap)
* within Packed Buffer Mode is the maximum of these two
* specifications.
*/
- ingpadboundary = 1 << (INGPADBOUNDARY_GET(sge_control) +
- X_INGPADBOUNDARY_SHIFT);
+ ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_control) +
+ INGPADBOUNDARY_SHIFT_X);
if (is_t4(adap->params.chip)) {
s->fl_align = ingpadboundary;
} else {
@@ -2956,10 +2931,7 @@ int t4_sge_init(struct adapter *adap)
s->fl_align = max(ingpadboundary, ingpackboundary);
}
- if (adap->flags & USING_SOFT_PARAMS)
- ret = t4_sge_init_soft(adap);
- else
- ret = t4_sge_init_hard(adap);
+ ret = t4_sge_init_soft(adap);
if (ret < 0)
return ret;
@@ -2975,11 +2947,11 @@ int t4_sge_init(struct adapter *adap)
* buffers and a new field which only applies to Packed Mode Free List
* buffers.
*/
- sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL);
+ sge_conm_ctrl = t4_read_reg(adap, SGE_CONM_CTRL_A);
if (is_t4(adap->params.chip))
- egress_threshold = EGRTHRESHOLD_GET(sge_conm_ctrl);
+ egress_threshold = EGRTHRESHOLD_G(sge_conm_ctrl);
else
- egress_threshold = EGRTHRESHOLDPACKING_GET(sge_conm_ctrl);
+ egress_threshold = EGRTHRESHOLDPACKING_G(sge_conm_ctrl);
s->fl_starve_thres = 2*egress_threshold + 1;
setup_timer(&s->rx_timer, sge_rx_timer_cb, (unsigned long)adap);
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
index c132d9030729..4d643b65265e 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.c
@@ -35,6 +35,7 @@
#include <linux/delay.h>
#include "cxgb4.h"
#include "t4_regs.h"
+#include "t4_values.h"
#include "t4fw_api.h"
/**
@@ -149,20 +150,20 @@ void t4_write_indirect(struct adapter *adap, unsigned int addr_reg,
*/
void t4_hw_pci_read_cfg4(struct adapter *adap, int reg, u32 *val)
{
- u32 req = ENABLE | FUNCTION(adap->fn) | reg;
+ u32 req = ENABLE_F | FUNCTION_V(adap->fn) | REGISTER_V(reg);
if (is_t4(adap->params.chip))
- req |= F_LOCALCFG;
+ req |= LOCALCFG_F;
- t4_write_reg(adap, PCIE_CFG_SPACE_REQ, req);
- *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA);
+ t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, req);
+ *val = t4_read_reg(adap, PCIE_CFG_SPACE_DATA_A);
/* Reset ENABLE to 0 so reads of PCIE_CFG_SPACE_DATA won't cause a
* Configuration Space read. (None of the other fields matter when
* ENABLE is 0 so a simple register write is easier than a
* read-modify-write via t4_set_reg_field().)
*/
- t4_write_reg(adap, PCIE_CFG_SPACE_REQ, 0);
+ t4_write_reg(adap, PCIE_CFG_SPACE_REQ_A, 0);
}
/*
@@ -187,8 +188,8 @@ static void t4_report_fw_error(struct adapter *adap)
};
u32 pcie_fw;
- pcie_fw = t4_read_reg(adap, MA_PCIE_FW);
- if (pcie_fw & PCIE_FW_ERR)
+ pcie_fw = t4_read_reg(adap, PCIE_FW_A);
+ if (pcie_fw & PCIE_FW_ERR_F)
dev_err(adap->pdev_dev, "Firmware reports adapter error: %s\n",
reason[PCIE_FW_EVAL_G(pcie_fw)]);
}
@@ -264,8 +265,8 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
u64 res;
int i, ms, delay_idx;
const __be64 *p = cmd;
- u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA);
- u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL);
+ u32 data_reg = PF_REG(mbox, CIM_PF_MAILBOX_DATA_A);
+ u32 ctl_reg = PF_REG(mbox, CIM_PF_MAILBOX_CTRL_A);
if ((size & 15) || size > MBOX_LEN)
return -EINVAL;
@@ -277,9 +278,9 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
if (adap->pdev->error_state != pci_channel_io_normal)
return -EIO;
- v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
+ v = MBOWNER_G(t4_read_reg(adap, ctl_reg));
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
- v = MBOWNER_GET(t4_read_reg(adap, ctl_reg));
+ v = MBOWNER_G(t4_read_reg(adap, ctl_reg));
if (v != MBOX_OWNER_DRV)
return v ? -EBUSY : -ETIMEDOUT;
@@ -287,7 +288,7 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
for (i = 0; i < size; i += 8)
t4_write_reg64(adap, data_reg + i, be64_to_cpu(*p++));
- t4_write_reg(adap, ctl_reg, MBMSGVALID | MBOWNER(MBOX_OWNER_FW));
+ t4_write_reg(adap, ctl_reg, MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW));
t4_read_reg(adap, ctl_reg); /* flush write */
delay_idx = 0;
@@ -303,8 +304,8 @@ int t4_wr_mbox_meat(struct adapter *adap, int mbox, const void *cmd, int size,
mdelay(ms);
v = t4_read_reg(adap, ctl_reg);
- if (MBOWNER_GET(v) == MBOX_OWNER_DRV) {
- if (!(v & MBMSGVALID)) {
+ if (MBOWNER_G(v) == MBOX_OWNER_DRV) {
+ if (!(v & MBMSGVALID_F)) {
t4_write_reg(adap, ctl_reg, 0);
continue;
}
@@ -350,27 +351,27 @@ int t4_mc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
u32 mc_bist_status_rdata, mc_bist_data_pattern;
if (is_t4(adap->params.chip)) {
- mc_bist_cmd = MC_BIST_CMD;
- mc_bist_cmd_addr = MC_BIST_CMD_ADDR;
- mc_bist_cmd_len = MC_BIST_CMD_LEN;
- mc_bist_status_rdata = MC_BIST_STATUS_RDATA;
- mc_bist_data_pattern = MC_BIST_DATA_PATTERN;
+ mc_bist_cmd = MC_BIST_CMD_A;
+ mc_bist_cmd_addr = MC_BIST_CMD_ADDR_A;
+ mc_bist_cmd_len = MC_BIST_CMD_LEN_A;
+ mc_bist_status_rdata = MC_BIST_STATUS_RDATA_A;
+ mc_bist_data_pattern = MC_BIST_DATA_PATTERN_A;
} else {
- mc_bist_cmd = MC_REG(MC_P_BIST_CMD, idx);
- mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR, idx);
- mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN, idx);
- mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA, idx);
- mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN, idx);
+ mc_bist_cmd = MC_REG(MC_P_BIST_CMD_A, idx);
+ mc_bist_cmd_addr = MC_REG(MC_P_BIST_CMD_ADDR_A, idx);
+ mc_bist_cmd_len = MC_REG(MC_P_BIST_CMD_LEN_A, idx);
+ mc_bist_status_rdata = MC_REG(MC_P_BIST_STATUS_RDATA_A, idx);
+ mc_bist_data_pattern = MC_REG(MC_P_BIST_DATA_PATTERN_A, idx);
}
- if (t4_read_reg(adap, mc_bist_cmd) & START_BIST)
+ if (t4_read_reg(adap, mc_bist_cmd) & START_BIST_F)
return -EBUSY;
t4_write_reg(adap, mc_bist_cmd_addr, addr & ~0x3fU);
t4_write_reg(adap, mc_bist_cmd_len, 64);
t4_write_reg(adap, mc_bist_data_pattern, 0xc);
- t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE(1) | START_BIST |
- BIST_CMD_GAP(1));
- i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST, 0, 10, 1);
+ t4_write_reg(adap, mc_bist_cmd, BIST_OPCODE_V(1) | START_BIST_F |
+ BIST_CMD_GAP_V(1));
+ i = t4_wait_op_done(adap, mc_bist_cmd, START_BIST_F, 0, 10, 1);
if (i)
return i;
@@ -403,31 +404,31 @@ int t4_edc_read(struct adapter *adap, int idx, u32 addr, __be32 *data, u64 *ecc)
u32 edc_bist_cmd_data_pattern, edc_bist_status_rdata;
if (is_t4(adap->params.chip)) {
- edc_bist_cmd = EDC_REG(EDC_BIST_CMD, idx);
- edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR, idx);
- edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN, idx);
- edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN,
- idx);
- edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA,
+ edc_bist_cmd = EDC_REG(EDC_BIST_CMD_A, idx);
+ edc_bist_cmd_addr = EDC_REG(EDC_BIST_CMD_ADDR_A, idx);
+ edc_bist_cmd_len = EDC_REG(EDC_BIST_CMD_LEN_A, idx);
+ edc_bist_cmd_data_pattern = EDC_REG(EDC_BIST_DATA_PATTERN_A,
idx);
+ edc_bist_status_rdata = EDC_REG(EDC_BIST_STATUS_RDATA_A,
+ idx);
} else {
- edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD, idx);
- edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx);
- edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx);
+ edc_bist_cmd = EDC_REG_T5(EDC_H_BIST_CMD_A, idx);
+ edc_bist_cmd_addr = EDC_REG_T5(EDC_H_BIST_CMD_ADDR_A, idx);
+ edc_bist_cmd_len = EDC_REG_T5(EDC_H_BIST_CMD_LEN_A, idx);
edc_bist_cmd_data_pattern =
- EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx);
+ EDC_REG_T5(EDC_H_BIST_DATA_PATTERN_A, idx);
edc_bist_status_rdata =
- EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx);
+ EDC_REG_T5(EDC_H_BIST_STATUS_RDATA_A, idx);
}
- if (t4_read_reg(adap, edc_bist_cmd) & START_BIST)
+ if (t4_read_reg(adap, edc_bist_cmd) & START_BIST_F)
return -EBUSY;
t4_write_reg(adap, edc_bist_cmd_addr, addr & ~0x3fU);
t4_write_reg(adap, edc_bist_cmd_len, 64);
t4_write_reg(adap, edc_bist_cmd_data_pattern, 0xc);
t4_write_reg(adap, edc_bist_cmd,
- BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST);
- i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST, 0, 10, 1);
+ BIST_OPCODE_V(1) | BIST_CMD_GAP_V(1) | START_BIST_F);
+ i = t4_wait_op_done(adap, edc_bist_cmd, START_BIST_F, 0, 10, 1);
if (i)
return i;
@@ -505,13 +506,13 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
* the address is relative to BAR0.
*/
mem_reg = t4_read_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN,
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A,
win));
- mem_aperture = 1 << (GET_WINDOW(mem_reg) + 10);
- mem_base = GET_PCIEOFST(mem_reg) << 10;
+ mem_aperture = 1 << (WINDOW_G(mem_reg) + WINDOW_SHIFT_X);
+ mem_base = PCIEOFST_G(mem_reg) << PCIEOFST_SHIFT_X;
if (is_t4(adap->params.chip))
mem_base -= adap->t4_bar0;
- win_pf = is_t4(adap->params.chip) ? 0 : V_PFNUM(adap->fn);
+ win_pf = is_t4(adap->params.chip) ? 0 : PFNUM_V(adap->fn);
/* Calculate our initial PCI-E Memory Window Position and Offset into
* that Window.
@@ -524,10 +525,10 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
* attempt to use the new value.)
*/
t4_write_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win),
pos | win_pf);
t4_read_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win));
/* Transfer data to/from the adapter as long as there's an integral
* number of 32-bit transfers to complete.
@@ -552,11 +553,11 @@ int t4_memory_rw(struct adapter *adap, int win, int mtype, u32 addr,
pos += mem_aperture;
offset = 0;
t4_write_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET,
- win), pos | win_pf);
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A,
+ win), pos | win_pf);
t4_read_reg(adap,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET,
- win));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A,
+ win));
}
}
@@ -760,14 +761,13 @@ static int sf1_read(struct adapter *adapter, unsigned int byte_cnt, int cont,
if (!byte_cnt || byte_cnt > 4)
return -EINVAL;
- if (t4_read_reg(adapter, SF_OP) & SF_BUSY)
+ if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F)
return -EBUSY;
- cont = cont ? SF_CONT : 0;
- lock = lock ? SF_LOCK : 0;
- t4_write_reg(adapter, SF_OP, lock | cont | BYTECNT(byte_cnt - 1));
- ret = t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5);
+ t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) |
+ SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1));
+ ret = t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5);
if (!ret)
- *valp = t4_read_reg(adapter, SF_DATA);
+ *valp = t4_read_reg(adapter, SF_DATA_A);
return ret;
}
@@ -788,14 +788,12 @@ static int sf1_write(struct adapter *adapter, unsigned int byte_cnt, int cont,
{
if (!byte_cnt || byte_cnt > 4)
return -EINVAL;
- if (t4_read_reg(adapter, SF_OP) & SF_BUSY)
+ if (t4_read_reg(adapter, SF_OP_A) & SF_BUSY_F)
return -EBUSY;
- cont = cont ? SF_CONT : 0;
- lock = lock ? SF_LOCK : 0;
- t4_write_reg(adapter, SF_DATA, val);
- t4_write_reg(adapter, SF_OP, lock |
- cont | BYTECNT(byte_cnt - 1) | OP_WR);
- return t4_wait_op_done(adapter, SF_OP, SF_BUSY, 0, SF_ATTEMPTS, 5);
+ t4_write_reg(adapter, SF_DATA_A, val);
+ t4_write_reg(adapter, SF_OP_A, SF_LOCK_V(lock) |
+ SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) | OP_V(1));
+ return t4_wait_op_done(adapter, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS, 5);
}
/**
@@ -837,8 +835,8 @@ static int flash_wait_op(struct adapter *adapter, int attempts, int delay)
* (i.e., big-endian), otherwise as 32-bit words in the platform's
* natural endianess.
*/
-static int t4_read_flash(struct adapter *adapter, unsigned int addr,
- unsigned int nwords, u32 *data, int byte_oriented)
+int t4_read_flash(struct adapter *adapter, unsigned int addr,
+ unsigned int nwords, u32 *data, int byte_oriented)
{
int ret;
@@ -854,7 +852,7 @@ static int t4_read_flash(struct adapter *adapter, unsigned int addr,
for ( ; nwords; nwords--, data++) {
ret = sf1_read(adapter, 4, nwords > 1, nwords == 1, data);
if (nwords == 1)
- t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
+ t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */
if (ret)
return ret;
if (byte_oriented)
@@ -902,7 +900,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
if (ret)
goto unlock;
- t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
+ t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */
/* Read the page to verify the write succeeded */
ret = t4_read_flash(adapter, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
@@ -918,7 +916,7 @@ static int t4_write_flash(struct adapter *adapter, unsigned int addr,
return 0;
unlock:
- t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
+ t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */
return ret;
}
@@ -950,6 +948,43 @@ int t4_get_tp_version(struct adapter *adapter, u32 *vers)
1, vers, 0);
}
+/**
+ * t4_get_exprom_version - return the Expansion ROM version (if any)
+ * @adapter: the adapter
+ * @vers: where to place the version
+ *
+ * Reads the Expansion ROM header from FLASH and returns the version
+ * number (if present) through the @vers return value pointer. We return
+ * this in the Firmware Version Format since it's convenient. Return
+ * 0 on success, -ENOENT if no Expansion ROM is present.
+ */
+int t4_get_exprom_version(struct adapter *adap, u32 *vers)
+{
+ struct exprom_header {
+ unsigned char hdr_arr[16]; /* must start with 0x55aa */
+ unsigned char hdr_ver[4]; /* Expansion ROM version */
+ } *hdr;
+ u32 exprom_header_buf[DIV_ROUND_UP(sizeof(struct exprom_header),
+ sizeof(u32))];
+ int ret;
+
+ ret = t4_read_flash(adap, FLASH_EXP_ROM_START,
+ ARRAY_SIZE(exprom_header_buf), exprom_header_buf,
+ 0);
+ if (ret)
+ return ret;
+
+ hdr = (struct exprom_header *)exprom_header_buf;
+ if (hdr->hdr_arr[0] != 0x55 || hdr->hdr_arr[1] != 0xaa)
+ return -ENOENT;
+
+ *vers = (FW_HDR_FW_VER_MAJOR_V(hdr->hdr_ver[0]) |
+ FW_HDR_FW_VER_MINOR_V(hdr->hdr_ver[1]) |
+ FW_HDR_FW_VER_MICRO_V(hdr->hdr_ver[2]) |
+ FW_HDR_FW_VER_BUILD_V(hdr->hdr_ver[3]));
+ return 0;
+}
+
/* Is the given firmware API compatible with the one the driver was compiled
* with?
*/
@@ -1113,7 +1148,7 @@ static int t4_flash_erase_sectors(struct adapter *adapter, int start, int end)
}
start++;
}
- t4_write_reg(adapter, SF_OP, 0); /* unlock SF */
+ t4_write_reg(adapter, SF_OP_A, 0); /* unlock SF */
return ret;
}
@@ -1241,6 +1276,45 @@ out:
return ret;
}
+/**
+ * t4_fwcache - firmware cache operation
+ * @adap: the adapter
+ * @op : the operation (flush or flush and invalidate)
+ */
+int t4_fwcache(struct adapter *adap, enum fw_params_param_dev_fwcache op)
+{
+ struct fw_params_cmd c;
+
+ memset(&c, 0, sizeof(c));
+ c.op_to_vfn =
+ cpu_to_be32(FW_CMD_OP_V(FW_PARAMS_CMD) |
+ FW_CMD_REQUEST_F | FW_CMD_WRITE_F |
+ FW_PARAMS_CMD_PFN_V(adap->fn) |
+ FW_PARAMS_CMD_VFN_V(0));
+ c.retval_len16 = cpu_to_be32(FW_LEN16(c));
+ c.param[0].mnem =
+ cpu_to_be32(FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_DEV) |
+ FW_PARAMS_PARAM_X_V(FW_PARAMS_PARAM_DEV_FWCACHE));
+ c.param[0].val = (__force __be32)op;
+
+ return t4_wr_mbox(adap, adap->mbox, &c, sizeof(c), NULL);
+}
+
+void t4_ulprx_read_la(struct adapter *adap, u32 *la_buf)
+{
+ unsigned int i, j;
+
+ for (i = 0; i < 8; i++) {
+ u32 *p = la_buf + i;
+
+ t4_write_reg(adap, ULP_RX_LA_CTL_A, i);
+ j = t4_read_reg(adap, ULP_RX_LA_WRPTR_A);
+ t4_write_reg(adap, ULP_RX_LA_RDPTR_A, j);
+ for (j = 0; j < ULPRX_LA_SIZE; j++, p += 8)
+ *p = t4_read_reg(adap, ULP_RX_LA_RDDATA_A);
+ }
+}
+
#define ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G | \
FW_PORT_CAP_ANEG)
@@ -1365,95 +1439,97 @@ static int t4_handle_intr_status(struct adapter *adapter, unsigned int reg,
static void pcie_intr_handler(struct adapter *adapter)
{
static const struct intr_info sysbus_intr_info[] = {
- { RNPP, "RXNP array parity error", -1, 1 },
- { RPCP, "RXPC array parity error", -1, 1 },
- { RCIP, "RXCIF array parity error", -1, 1 },
- { RCCP, "Rx completions control array parity error", -1, 1 },
- { RFTP, "RXFT array parity error", -1, 1 },
+ { RNPP_F, "RXNP array parity error", -1, 1 },
+ { RPCP_F, "RXPC array parity error", -1, 1 },
+ { RCIP_F, "RXCIF array parity error", -1, 1 },
+ { RCCP_F, "Rx completions control array parity error", -1, 1 },
+ { RFTP_F, "RXFT array parity error", -1, 1 },
{ 0 }
};
static const struct intr_info pcie_port_intr_info[] = {
- { TPCP, "TXPC array parity error", -1, 1 },
- { TNPP, "TXNP array parity error", -1, 1 },
- { TFTP, "TXFT array parity error", -1, 1 },
- { TCAP, "TXCA array parity error", -1, 1 },
- { TCIP, "TXCIF array parity error", -1, 1 },
- { RCAP, "RXCA array parity error", -1, 1 },
- { OTDD, "outbound request TLP discarded", -1, 1 },
- { RDPE, "Rx data parity error", -1, 1 },
- { TDUE, "Tx uncorrectable data error", -1, 1 },
+ { TPCP_F, "TXPC array parity error", -1, 1 },
+ { TNPP_F, "TXNP array parity error", -1, 1 },
+ { TFTP_F, "TXFT array parity error", -1, 1 },
+ { TCAP_F, "TXCA array parity error", -1, 1 },
+ { TCIP_F, "TXCIF array parity error", -1, 1 },
+ { RCAP_F, "RXCA array parity error", -1, 1 },
+ { OTDD_F, "outbound request TLP discarded", -1, 1 },
+ { RDPE_F, "Rx data parity error", -1, 1 },
+ { TDUE_F, "Tx uncorrectable data error", -1, 1 },
{ 0 }
};
static const struct intr_info pcie_intr_info[] = {
- { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
- { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
- { MSIDATAPERR, "MSI data parity error", -1, 1 },
- { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
- { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
- { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
- { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
- { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
- { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
- { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
- { CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
- { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
- { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
- { DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
- { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
- { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
- { HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
- { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
- { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
- { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
- { FIDPERR, "PCI FID parity error", -1, 1 },
- { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
- { MATAGPERR, "PCI MA tag parity error", -1, 1 },
- { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
- { RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
- { RXWRPERR, "PCI Rx write parity error", -1, 1 },
- { RPLPERR, "PCI replay buffer parity error", -1, 1 },
- { PCIESINT, "PCI core secondary fault", -1, 1 },
- { PCIEPINT, "PCI core primary fault", -1, 1 },
- { UNXSPLCPLERR, "PCI unexpected split completion error", -1, 0 },
+ { MSIADDRLPERR_F, "MSI AddrL parity error", -1, 1 },
+ { MSIADDRHPERR_F, "MSI AddrH parity error", -1, 1 },
+ { MSIDATAPERR_F, "MSI data parity error", -1, 1 },
+ { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLPERR_F, "PCI PIO completion FIFO parity error", -1, 1 },
+ { PIOREQPERR_F, "PCI PIO request FIFO parity error", -1, 1 },
+ { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { CCNTPERR_F, "PCI CMD channel count parity error", -1, 1 },
+ { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 },
+ { DCNTPERR_F, "PCI DMA channel count parity error", -1, 1 },
+ { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 },
+ { HCNTPERR_F, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR_F, "PCI FID parity error", -1, 1 },
+ { INTXCLRPERR_F, "PCI INTx clear parity error", -1, 1 },
+ { MATAGPERR_F, "PCI MA tag parity error", -1, 1 },
+ { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 },
+ { RXCPLPERR_F, "PCI Rx completion parity error", -1, 1 },
+ { RXWRPERR_F, "PCI Rx write parity error", -1, 1 },
+ { RPLPERR_F, "PCI replay buffer parity error", -1, 1 },
+ { PCIESINT_F, "PCI core secondary fault", -1, 1 },
+ { PCIEPINT_F, "PCI core primary fault", -1, 1 },
+ { UNXSPLCPLERR_F, "PCI unexpected split completion error",
+ -1, 0 },
{ 0 }
};
static struct intr_info t5_pcie_intr_info[] = {
- { MSTGRPPERR, "Master Response Read Queue parity error",
+ { MSTGRPPERR_F, "Master Response Read Queue parity error",
-1, 1 },
- { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
- { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
- { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
- { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
- { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
- { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
- { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
+ { MSTTIMEOUTPERR_F, "Master Timeout FIFO parity error", -1, 1 },
+ { MSIXSTIPERR_F, "MSI-X STI SRAM parity error", -1, 1 },
+ { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLGRPPERR_F, "PCI PIO completion Group FIFO parity error",
-1, 1 },
- { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
+ { PIOREQGRPPERR_F, "PCI PIO request Group FIFO parity error",
-1, 1 },
- { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
- { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
- { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
- { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
- { DREQWRPERR, "PCI DMA channel write request parity error",
+ { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { MSTTAGQPERR_F, "PCI master tag queue parity error", -1, 1 },
+ { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 },
+ { DREQWRPERR_F, "PCI DMA channel write request parity error",
-1, 1 },
- { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
- { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
- { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
- { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
- { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
- { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
- { FIDPERR, "PCI FID parity error", -1, 1 },
- { VFIDPERR, "PCI INTx clear parity error", -1, 1 },
- { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
- { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
- { IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
+ { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 },
+ { HREQWRPERR_F, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR_F, "PCI FID parity error", -1, 1 },
+ { VFIDPERR_F, "PCI INTx clear parity error", -1, 1 },
+ { MAGRPPERR_F, "PCI MA group FIFO parity error", -1, 1 },
+ { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 },
+ { IPRXHDRGRPPERR_F, "PCI IP Rx header group parity error",
-1, 1 },
- { IPRXDATAGRPPERR, "PCI IP Rx data group parity error", -1, 1 },
- { RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
- { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
- { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
- { READRSPERR, "Outbound read error", -1, 0 },
+ { IPRXDATAGRPPERR_F, "PCI IP Rx data group parity error",
+ -1, 1 },
+ { RPLPERR_F, "PCI IP replay buffer parity error", -1, 1 },
+ { IPSOTPERR_F, "PCI IP SOT buffer parity error", -1, 1 },
+ { TRGT1GRPPERR_F, "PCI TRGT1 group FIFOs parity error", -1, 1 },
+ { READRSPERR_F, "Outbound read error", -1, 0 },
{ 0 }
};
@@ -1461,15 +1537,15 @@ static void pcie_intr_handler(struct adapter *adapter)
if (is_t4(adapter->params.chip))
fat = t4_handle_intr_status(adapter,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
- sysbus_intr_info) +
+ PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A,
+ sysbus_intr_info) +
t4_handle_intr_status(adapter,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
- pcie_port_intr_info) +
- t4_handle_intr_status(adapter, PCIE_INT_CAUSE,
+ PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A,
+ pcie_port_intr_info) +
+ t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A,
pcie_intr_info);
else
- fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE,
+ fat = t4_handle_intr_status(adapter, PCIE_INT_CAUSE_A,
t5_pcie_intr_info);
if (fat)
@@ -1483,11 +1559,11 @@ static void tp_intr_handler(struct adapter *adapter)
{
static const struct intr_info tp_intr_info[] = {
{ 0x3fffffff, "TP parity error", -1, 1 },
- { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
+ { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adapter, TP_INT_CAUSE, tp_intr_info))
+ if (t4_handle_intr_status(adapter, TP_INT_CAUSE_A, tp_intr_info))
t4_fatal_err(adapter);
}
@@ -1499,102 +1575,107 @@ static void sge_intr_handler(struct adapter *adapter)
u64 v;
static const struct intr_info sge_intr_info[] = {
- { ERR_CPL_EXCEED_IQE_SIZE,
+ { ERR_CPL_EXCEED_IQE_SIZE_F,
"SGE received CPL exceeding IQE size", -1, 1 },
- { ERR_INVALID_CIDX_INC,
+ { ERR_INVALID_CIDX_INC_F,
"SGE GTS CIDX increment too large", -1, 0 },
- { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
- { DBFIFO_LP_INT, NULL, -1, 0, t4_db_full },
- { DBFIFO_HP_INT, NULL, -1, 0, t4_db_full },
- { ERR_DROPPED_DB, NULL, -1, 0, t4_db_dropped },
- { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0,
+ { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 },
+ { DBFIFO_LP_INT_F, NULL, -1, 0, t4_db_full },
+ { DBFIFO_HP_INT_F, NULL, -1, 0, t4_db_full },
+ { ERR_DROPPED_DB_F, NULL, -1, 0, t4_db_dropped },
+ { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F,
"SGE IQID > 1023 received CPL for FL", -1, 0 },
- { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1,
0 },
- { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1,
0 },
- { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1,
0 },
- { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1,
0 },
- { ERR_ING_CTXT_PRIO,
+ { ERR_ING_CTXT_PRIO_F,
"SGE too many priority ingress contexts", -1, 0 },
- { ERR_EGR_CTXT_PRIO,
+ { ERR_EGR_CTXT_PRIO_F,
"SGE too many priority egress contexts", -1, 0 },
- { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 },
- { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 },
+ { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 },
+ { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 },
{ 0 }
};
- v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1) |
- ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2) << 32);
+ v = (u64)t4_read_reg(adapter, SGE_INT_CAUSE1_A) |
+ ((u64)t4_read_reg(adapter, SGE_INT_CAUSE2_A) << 32);
if (v) {
dev_alert(adapter->pdev_dev, "SGE parity error (%#llx)\n",
(unsigned long long)v);
- t4_write_reg(adapter, SGE_INT_CAUSE1, v);
- t4_write_reg(adapter, SGE_INT_CAUSE2, v >> 32);
+ t4_write_reg(adapter, SGE_INT_CAUSE1_A, v);
+ t4_write_reg(adapter, SGE_INT_CAUSE2_A, v >> 32);
}
- if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3, sge_intr_info) ||
+ if (t4_handle_intr_status(adapter, SGE_INT_CAUSE3_A, sge_intr_info) ||
v != 0)
t4_fatal_err(adapter);
}
+#define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\
+ OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F)
+#define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\
+ IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F)
+
/*
* CIM interrupt handler.
*/
static void cim_intr_handler(struct adapter *adapter)
{
static const struct intr_info cim_intr_info[] = {
- { PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
- { OBQPARERR, "CIM OBQ parity error", -1, 1 },
- { IBQPARERR, "CIM IBQ parity error", -1, 1 },
- { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 },
- { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 },
- { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 },
- { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
+ { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 },
+ { CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 },
+ { CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 },
+ { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 },
+ { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 },
+ { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 },
+ { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 },
{ 0 }
};
static const struct intr_info cim_upintr_info[] = {
- { RSVDSPACEINT, "CIM reserved space access", -1, 1 },
- { ILLTRANSINT, "CIM illegal transaction", -1, 1 },
- { ILLWRINT, "CIM illegal write", -1, 1 },
- { ILLRDINT, "CIM illegal read", -1, 1 },
- { ILLRDBEINT, "CIM illegal read BE", -1, 1 },
- { ILLWRBEINT, "CIM illegal write BE", -1, 1 },
- { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 },
- { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 },
- { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
- { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 },
- { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
- { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
- { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 },
- { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 },
- { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 },
- { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 },
- { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 },
- { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 },
- { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 },
- { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 },
- { SGLRDPLINT , "CIM single read from PL space", -1, 1 },
- { SGLWRPLINT , "CIM single write to PL space", -1, 1 },
- { BLKRDPLINT , "CIM block read from PL space", -1, 1 },
- { BLKWRPLINT , "CIM block write to PL space", -1, 1 },
- { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 },
- { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 },
- { TIMEOUTINT , "CIM PIF timeout", -1, 1 },
- { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 },
+ { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 },
+ { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 },
+ { ILLWRINT_F, "CIM illegal write", -1, 1 },
+ { ILLRDINT_F, "CIM illegal read", -1, 1 },
+ { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 },
+ { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 },
+ { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 },
+ { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 },
+ { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 },
+ { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 },
+ { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 },
+ { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 },
+ { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 },
+ { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 },
+ { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 },
+ { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 },
+ { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 },
+ { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 },
+ { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 },
+ { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 },
+ { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 },
+ { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 },
+ { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 },
+ { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 },
+ { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 },
+ { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 },
+ { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 },
+ { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 },
{ 0 }
};
int fat;
- if (t4_read_reg(adapter, MA_PCIE_FW) & PCIE_FW_ERR)
+ if (t4_read_reg(adapter, PCIE_FW_A) & PCIE_FW_ERR_F)
t4_report_fw_error(adapter);
- fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE,
+ fat = t4_handle_intr_status(adapter, CIM_HOST_INT_CAUSE_A,
cim_intr_info) +
- t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE,
+ t4_handle_intr_status(adapter, CIM_HOST_UPACC_INT_CAUSE_A,
cim_upintr_info);
if (fat)
t4_fatal_err(adapter);
@@ -1611,7 +1692,7 @@ static void ulprx_intr_handler(struct adapter *adapter)
{ 0 }
};
- if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE, ulprx_intr_info))
+ if (t4_handle_intr_status(adapter, ULP_RX_INT_CAUSE_A, ulprx_intr_info))
t4_fatal_err(adapter);
}
@@ -1621,19 +1702,19 @@ static void ulprx_intr_handler(struct adapter *adapter)
static void ulptx_intr_handler(struct adapter *adapter)
{
static const struct intr_info ulptx_intr_info[] = {
- { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1,
0 },
- { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1,
0 },
- { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1,
0 },
- { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1,
0 },
{ 0xfffffff, "ULPTX parity error", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE, ulptx_intr_info))
+ if (t4_handle_intr_status(adapter, ULP_TX_INT_CAUSE_A, ulptx_intr_info))
t4_fatal_err(adapter);
}
@@ -1643,19 +1724,20 @@ static void ulptx_intr_handler(struct adapter *adapter)
static void pmtx_intr_handler(struct adapter *adapter)
{
static const struct intr_info pmtx_intr_info[] = {
- { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
- { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
- { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
- { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
- { PMTX_FRAMING_ERROR, "PMTX framing error", -1, 1 },
- { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 },
- { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1, 1 },
- { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 },
- { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1},
+ { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 },
+ { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 },
+ { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 },
+ { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 },
+ { PMTX_FRAMING_ERROR_F, "PMTX framing error", -1, 1 },
+ { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 },
+ { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error",
+ -1, 1 },
+ { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 },
+ { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1},
{ 0 }
};
- if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE, pmtx_intr_info))
+ if (t4_handle_intr_status(adapter, PM_TX_INT_CAUSE_A, pmtx_intr_info))
t4_fatal_err(adapter);
}
@@ -1665,16 +1747,17 @@ static void pmtx_intr_handler(struct adapter *adapter)
static void pmrx_intr_handler(struct adapter *adapter)
{
static const struct intr_info pmrx_intr_info[] = {
- { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
- { PMRX_FRAMING_ERROR, "PMRX framing error", -1, 1 },
- { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
- { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1, 1 },
- { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 },
- { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1},
+ { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 },
+ { PMRX_FRAMING_ERROR_F, "PMRX framing error", -1, 1 },
+ { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 },
+ { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error",
+ -1, 1 },
+ { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 },
+ { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1},
{ 0 }
};
- if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE, pmrx_intr_info))
+ if (t4_handle_intr_status(adapter, PM_RX_INT_CAUSE_A, pmrx_intr_info))
t4_fatal_err(adapter);
}
@@ -1684,16 +1767,16 @@ static void pmrx_intr_handler(struct adapter *adapter)
static void cplsw_intr_handler(struct adapter *adapter)
{
static const struct intr_info cplsw_intr_info[] = {
- { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
- { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
- { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
- { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 },
- { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 },
- { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 },
+ { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 },
+ { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 },
+ { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 },
+ { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 },
+ { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 },
+ { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE, cplsw_intr_info))
+ if (t4_handle_intr_status(adapter, CPL_INTR_CAUSE_A, cplsw_intr_info))
t4_fatal_err(adapter);
}
@@ -1703,15 +1786,15 @@ static void cplsw_intr_handler(struct adapter *adapter)
static void le_intr_handler(struct adapter *adap)
{
static const struct intr_info le_intr_info[] = {
- { LIPMISS, "LE LIP miss", -1, 0 },
- { LIP0, "LE 0 LIP error", -1, 0 },
- { PARITYERR, "LE parity error", -1, 1 },
- { UNKNOWNCMD, "LE unknown command", -1, 1 },
- { REQQPARERR, "LE request queue parity error", -1, 1 },
+ { LIPMISS_F, "LE LIP miss", -1, 0 },
+ { LIP0_F, "LE 0 LIP error", -1, 0 },
+ { PARITYERR_F, "LE parity error", -1, 1 },
+ { UNKNOWNCMD_F, "LE unknown command", -1, 1 },
+ { REQQPARERR_F, "LE request queue parity error", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE, le_intr_info))
+ if (t4_handle_intr_status(adap, LE_DB_INT_CAUSE_A, le_intr_info))
t4_fatal_err(adap);
}
@@ -1725,19 +1808,22 @@ static void mps_intr_handler(struct adapter *adapter)
{ 0 }
};
static const struct intr_info mps_tx_intr_info[] = {
- { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 },
- { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
- { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 },
- { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 },
- { BUBBLE, "MPS Tx underflow", -1, 1 },
- { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 },
- { FRMERR, "MPS Tx framing error", -1, 1 },
+ { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 },
+ { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 },
+ { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error",
+ -1, 1 },
+ { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error",
+ -1, 1 },
+ { BUBBLE_F, "MPS Tx underflow", -1, 1 },
+ { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 },
+ { FRMERR_F, "MPS Tx framing error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_trc_intr_info[] = {
- { FILTMEM, "MPS TRC filter parity error", -1, 1 },
- { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 },
- { MISCPERR, "MPS TRC misc parity error", -1, 1 },
+ { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 },
+ { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error",
+ -1, 1 },
+ { MISCPERR_F, "MPS TRC misc parity error", -1, 1 },
{ 0 }
};
static const struct intr_info mps_stat_sram_intr_info[] = {
@@ -1753,37 +1839,37 @@ static void mps_intr_handler(struct adapter *adapter)
{ 0 }
};
static const struct intr_info mps_cls_intr_info[] = {
- { MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
- { MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
- { HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
+ { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 },
+ { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 },
+ { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 },
{ 0 }
};
int fat;
- fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE,
+ fat = t4_handle_intr_status(adapter, MPS_RX_PERR_INT_CAUSE_A,
mps_rx_intr_info) +
- t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE,
+ t4_handle_intr_status(adapter, MPS_TX_INT_CAUSE_A,
mps_tx_intr_info) +
- t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE,
+ t4_handle_intr_status(adapter, MPS_TRC_INT_CAUSE_A,
mps_trc_intr_info) +
- t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM,
+ t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_SRAM_A,
mps_stat_sram_intr_info) +
- t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO,
+ t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A,
mps_stat_tx_intr_info) +
- t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO,
+ t4_handle_intr_status(adapter, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A,
mps_stat_rx_intr_info) +
- t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE,
+ t4_handle_intr_status(adapter, MPS_CLS_INT_CAUSE_A,
mps_cls_intr_info);
- t4_write_reg(adapter, MPS_INT_CAUSE, CLSINT | TRCINT |
- RXINT | TXINT | STATINT);
- t4_read_reg(adapter, MPS_INT_CAUSE); /* flush */
+ t4_write_reg(adapter, MPS_INT_CAUSE_A, 0);
+ t4_read_reg(adapter, MPS_INT_CAUSE_A); /* flush */
if (fat)
t4_fatal_err(adapter);
}
-#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE)
+#define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \
+ ECC_UE_INT_CAUSE_F)
/*
* EDC/MC interrupt handler.
@@ -1795,40 +1881,40 @@ static void mem_intr_handler(struct adapter *adapter, int idx)
unsigned int addr, cnt_addr, v;
if (idx <= MEM_EDC1) {
- addr = EDC_REG(EDC_INT_CAUSE, idx);
- cnt_addr = EDC_REG(EDC_ECC_STATUS, idx);
+ addr = EDC_REG(EDC_INT_CAUSE_A, idx);
+ cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx);
} else if (idx == MEM_MC) {
if (is_t4(adapter->params.chip)) {
- addr = MC_INT_CAUSE;
- cnt_addr = MC_ECC_STATUS;
+ addr = MC_INT_CAUSE_A;
+ cnt_addr = MC_ECC_STATUS_A;
} else {
- addr = MC_P_INT_CAUSE;
- cnt_addr = MC_P_ECC_STATUS;
+ addr = MC_P_INT_CAUSE_A;
+ cnt_addr = MC_P_ECC_STATUS_A;
}
} else {
- addr = MC_REG(MC_P_INT_CAUSE, 1);
- cnt_addr = MC_REG(MC_P_ECC_STATUS, 1);
+ addr = MC_REG(MC_P_INT_CAUSE_A, 1);
+ cnt_addr = MC_REG(MC_P_ECC_STATUS_A, 1);
}
v = t4_read_reg(adapter, addr) & MEM_INT_MASK;
- if (v & PERR_INT_CAUSE)
+ if (v & PERR_INT_CAUSE_F)
dev_alert(adapter->pdev_dev, "%s FIFO parity error\n",
name[idx]);
- if (v & ECC_CE_INT_CAUSE) {
- u32 cnt = ECC_CECNT_GET(t4_read_reg(adapter, cnt_addr));
+ if (v & ECC_CE_INT_CAUSE_F) {
+ u32 cnt = ECC_CECNT_G(t4_read_reg(adapter, cnt_addr));
- t4_write_reg(adapter, cnt_addr, ECC_CECNT_MASK);
+ t4_write_reg(adapter, cnt_addr, ECC_CECNT_V(ECC_CECNT_M));
if (printk_ratelimit())
dev_warn(adapter->pdev_dev,
"%u %s correctable ECC data error%s\n",
cnt, name[idx], cnt > 1 ? "s" : "");
}
- if (v & ECC_UE_INT_CAUSE)
+ if (v & ECC_UE_INT_CAUSE_F)
dev_alert(adapter->pdev_dev,
"%s uncorrectable ECC data error\n", name[idx]);
t4_write_reg(adapter, addr, v);
- if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE))
+ if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F))
t4_fatal_err(adapter);
}
@@ -1837,26 +1923,26 @@ static void mem_intr_handler(struct adapter *adapter, int idx)
*/
static void ma_intr_handler(struct adapter *adap)
{
- u32 v, status = t4_read_reg(adap, MA_INT_CAUSE);
+ u32 v, status = t4_read_reg(adap, MA_INT_CAUSE_A);
- if (status & MEM_PERR_INT_CAUSE) {
+ if (status & MEM_PERR_INT_CAUSE_F) {
dev_alert(adap->pdev_dev,
"MA parity error, parity status %#x\n",
- t4_read_reg(adap, MA_PARITY_ERROR_STATUS));
+ t4_read_reg(adap, MA_PARITY_ERROR_STATUS1_A));
if (is_t5(adap->params.chip))
dev_alert(adap->pdev_dev,
"MA parity error, parity status %#x\n",
t4_read_reg(adap,
- MA_PARITY_ERROR_STATUS2));
+ MA_PARITY_ERROR_STATUS2_A));
}
- if (status & MEM_WRAP_INT_CAUSE) {
- v = t4_read_reg(adap, MA_INT_WRAP_STATUS);
+ if (status & MEM_WRAP_INT_CAUSE_F) {
+ v = t4_read_reg(adap, MA_INT_WRAP_STATUS_A);
dev_alert(adap->pdev_dev, "MA address wrap-around error by "
"client %u to address %#x\n",
- MEM_WRAP_CLIENT_NUM_GET(v),
- MEM_WRAP_ADDRESS_GET(v) << 4);
+ MEM_WRAP_CLIENT_NUM_G(v),
+ MEM_WRAP_ADDRESS_G(v) << 4);
}
- t4_write_reg(adap, MA_INT_CAUSE, status);
+ t4_write_reg(adap, MA_INT_CAUSE_A, status);
t4_fatal_err(adap);
}
@@ -1866,13 +1952,13 @@ static void ma_intr_handler(struct adapter *adap)
static void smb_intr_handler(struct adapter *adap)
{
static const struct intr_info smb_intr_info[] = {
- { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
- { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
- { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
+ { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 },
+ { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 },
+ { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adap, SMB_INT_CAUSE, smb_intr_info))
+ if (t4_handle_intr_status(adap, SMB_INT_CAUSE_A, smb_intr_info))
t4_fatal_err(adap);
}
@@ -1882,14 +1968,14 @@ static void smb_intr_handler(struct adapter *adap)
static void ncsi_intr_handler(struct adapter *adap)
{
static const struct intr_info ncsi_intr_info[] = {
- { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
- { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
- { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
- { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 },
+ { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 },
+ { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 },
+ { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 },
+ { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adap, NCSI_INT_CAUSE, ncsi_intr_info))
+ if (t4_handle_intr_status(adap, NCSI_INT_CAUSE_A, ncsi_intr_info))
t4_fatal_err(adap);
}
@@ -1901,23 +1987,23 @@ static void xgmac_intr_handler(struct adapter *adap, int port)
u32 v, int_cause_reg;
if (is_t4(adap->params.chip))
- int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE);
+ int_cause_reg = PORT_REG(port, XGMAC_PORT_INT_CAUSE_A);
else
- int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE);
+ int_cause_reg = T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A);
v = t4_read_reg(adap, int_cause_reg);
- v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR;
+ v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F;
if (!v)
return;
- if (v & TXFIFO_PRTY_ERR)
+ if (v & TXFIFO_PRTY_ERR_F)
dev_alert(adap->pdev_dev, "XGMAC %d Tx FIFO parity error\n",
port);
- if (v & RXFIFO_PRTY_ERR)
+ if (v & RXFIFO_PRTY_ERR_F)
dev_alert(adap->pdev_dev, "XGMAC %d Rx FIFO parity error\n",
port);
- t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE), v);
+ t4_write_reg(adap, PORT_REG(port, XGMAC_PORT_INT_CAUSE_A), v);
t4_fatal_err(adap);
}
@@ -1927,19 +2013,19 @@ static void xgmac_intr_handler(struct adapter *adap, int port)
static void pl_intr_handler(struct adapter *adap)
{
static const struct intr_info pl_intr_info[] = {
- { FATALPERR, "T4 fatal parity error", -1, 1 },
- { PERRVFID, "PL VFID_MAP parity error", -1, 1 },
+ { FATALPERR_F, "T4 fatal parity error", -1, 1 },
+ { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 },
{ 0 }
};
- if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE, pl_intr_info))
+ if (t4_handle_intr_status(adap, PL_PL_INT_CAUSE_A, pl_intr_info))
t4_fatal_err(adap);
}
-#define PF_INTR_MASK (PFSW)
-#define GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
- EDC1 | LE | TP | MA | PM_TX | PM_RX | ULP_RX | \
- CPL_SWITCH | SGE | ULP_TX)
+#define PF_INTR_MASK (PFSW_F)
+#define GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | EDC0_F | \
+ EDC1_F | LE_F | TP_F | MA_F | PM_TX_F | PM_RX_F | ULP_RX_F | \
+ CPL_SWITCH_F | SGE_F | ULP_TX_F)
/**
* t4_slow_intr_handler - control path interrupt handler
@@ -1951,60 +2037,60 @@ static void pl_intr_handler(struct adapter *adap)
*/
int t4_slow_intr_handler(struct adapter *adapter)
{
- u32 cause = t4_read_reg(adapter, PL_INT_CAUSE);
+ u32 cause = t4_read_reg(adapter, PL_INT_CAUSE_A);
if (!(cause & GLBL_INTR_MASK))
return 0;
- if (cause & CIM)
+ if (cause & CIM_F)
cim_intr_handler(adapter);
- if (cause & MPS)
+ if (cause & MPS_F)
mps_intr_handler(adapter);
- if (cause & NCSI)
+ if (cause & NCSI_F)
ncsi_intr_handler(adapter);
- if (cause & PL)
+ if (cause & PL_F)
pl_intr_handler(adapter);
- if (cause & SMB)
+ if (cause & SMB_F)
smb_intr_handler(adapter);
- if (cause & XGMAC0)
+ if (cause & XGMAC0_F)
xgmac_intr_handler(adapter, 0);
- if (cause & XGMAC1)
+ if (cause & XGMAC1_F)
xgmac_intr_handler(adapter, 1);
- if (cause & XGMAC_KR0)
+ if (cause & XGMAC_KR0_F)
xgmac_intr_handler(adapter, 2);
- if (cause & XGMAC_KR1)
+ if (cause & XGMAC_KR1_F)
xgmac_intr_handler(adapter, 3);
- if (cause & PCIE)
+ if (cause & PCIE_F)
pcie_intr_handler(adapter);
- if (cause & MC)
+ if (cause & MC_F)
mem_intr_handler(adapter, MEM_MC);
- if (!is_t4(adapter->params.chip) && (cause & MC1))
+ if (!is_t4(adapter->params.chip) && (cause & MC1_S))
mem_intr_handler(adapter, MEM_MC1);
- if (cause & EDC0)
+ if (cause & EDC0_F)
mem_intr_handler(adapter, MEM_EDC0);
- if (cause & EDC1)
+ if (cause & EDC1_F)
mem_intr_handler(adapter, MEM_EDC1);
- if (cause & LE)
+ if (cause & LE_F)
le_intr_handler(adapter);
- if (cause & TP)
+ if (cause & TP_F)
tp_intr_handler(adapter);
- if (cause & MA)
+ if (cause & MA_F)
ma_intr_handler(adapter);
- if (cause & PM_TX)
+ if (cause & PM_TX_F)
pmtx_intr_handler(adapter);
- if (cause & PM_RX)
+ if (cause & PM_RX_F)
pmrx_intr_handler(adapter);
- if (cause & ULP_RX)
+ if (cause & ULP_RX_F)
ulprx_intr_handler(adapter);
- if (cause & CPL_SWITCH)
+ if (cause & CPL_SWITCH_F)
cplsw_intr_handler(adapter);
- if (cause & SGE)
+ if (cause & SGE_F)
sge_intr_handler(adapter);
- if (cause & ULP_TX)
+ if (cause & ULP_TX_F)
ulptx_intr_handler(adapter);
/* Clear the interrupts just processed for which we are the master. */
- t4_write_reg(adapter, PL_INT_CAUSE, cause & GLBL_INTR_MASK);
- (void) t4_read_reg(adapter, PL_INT_CAUSE); /* flush */
+ t4_write_reg(adapter, PL_INT_CAUSE_A, cause & GLBL_INTR_MASK);
+ (void)t4_read_reg(adapter, PL_INT_CAUSE_A); /* flush */
return 1;
}
@@ -2023,19 +2109,19 @@ int t4_slow_intr_handler(struct adapter *adapter)
*/
void t4_intr_enable(struct adapter *adapter)
{
- u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI));
-
- t4_write_reg(adapter, SGE_INT_ENABLE3, ERR_CPL_EXCEED_IQE_SIZE |
- ERR_INVALID_CIDX_INC | ERR_CPL_OPCODE_0 |
- ERR_DROPPED_DB | ERR_DATA_CPL_ON_HIGH_QID1 |
- ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 |
- ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 |
- ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO |
- ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR |
- DBFIFO_HP_INT | DBFIFO_LP_INT |
- EGRESS_SIZE_ERR);
- t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), PF_INTR_MASK);
- t4_set_reg_field(adapter, PL_INT_MAP0, 0, 1 << pf);
+ u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A));
+
+ t4_write_reg(adapter, SGE_INT_ENABLE3_A, ERR_CPL_EXCEED_IQE_SIZE_F |
+ ERR_INVALID_CIDX_INC_F | ERR_CPL_OPCODE_0_F |
+ ERR_DROPPED_DB_F | ERR_DATA_CPL_ON_HIGH_QID1_F |
+ ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F |
+ ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F |
+ ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F |
+ ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F |
+ DBFIFO_HP_INT_F | DBFIFO_LP_INT_F |
+ EGRESS_SIZE_ERR_F);
+ t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), PF_INTR_MASK);
+ t4_set_reg_field(adapter, PL_INT_MAP0_A, 0, 1 << pf);
}
/**
@@ -2048,10 +2134,10 @@ void t4_intr_enable(struct adapter *adapter)
*/
void t4_intr_disable(struct adapter *adapter)
{
- u32 pf = SOURCEPF_GET(t4_read_reg(adapter, PL_WHOAMI));
+ u32 pf = SOURCEPF_G(t4_read_reg(adapter, PL_WHOAMI_A));
- t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE), 0);
- t4_set_reg_field(adapter, PL_INT_MAP0, 1 << pf, 0);
+ t4_write_reg(adapter, MYPF_REG(PL_PF_INT_ENABLE_A), 0);
+ t4_set_reg_field(adapter, PL_INT_MAP0_A, 1 << pf, 0);
}
/**
@@ -2166,6 +2252,147 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
return t4_wr_mbox(adapter, mbox, &c, sizeof(c), NULL);
}
+/* Read an RSS table row */
+static int rd_rss_row(struct adapter *adap, int row, u32 *val)
+{
+ t4_write_reg(adap, TP_RSS_LKP_TABLE_A, 0xfff00000 | row);
+ return t4_wait_op_done_val(adap, TP_RSS_LKP_TABLE_A, LKPTBLROWVLD_F, 1,
+ 5, 0, val);
+}
+
+/**
+ * t4_read_rss - read the contents of the RSS mapping table
+ * @adapter: the adapter
+ * @map: holds the contents of the RSS mapping table
+ *
+ * Reads the contents of the RSS hash->queue mapping table.
+ */
+int t4_read_rss(struct adapter *adapter, u16 *map)
+{
+ u32 val;
+ int i, ret;
+
+ for (i = 0; i < RSS_NENTRIES / 2; ++i) {
+ ret = rd_rss_row(adapter, i, &val);
+ if (ret)
+ return ret;
+ *map++ = LKPTBLQUEUE0_G(val);
+ *map++ = LKPTBLQUEUE1_G(val);
+ }
+ return 0;
+}
+
+/**
+ * t4_read_rss_key - read the global RSS key
+ * @adap: the adapter
+ * @key: 10-entry array holding the 320-bit RSS key
+ *
+ * Reads the global 320-bit RSS key.
+ */
+void t4_read_rss_key(struct adapter *adap, u32 *key)
+{
+ t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
+ TP_RSS_SECRET_KEY0_A);
+}
+
+/**
+ * t4_write_rss_key - program one of the RSS keys
+ * @adap: the adapter
+ * @key: 10-entry array holding the 320-bit RSS key
+ * @idx: which RSS key to write
+ *
+ * Writes one of the RSS keys with the given 320-bit value. If @idx is
+ * 0..15 the corresponding entry in the RSS key table is written,
+ * otherwise the global RSS key is written.
+ */
+void t4_write_rss_key(struct adapter *adap, const u32 *key, int idx)
+{
+ t4_write_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A, key, 10,
+ TP_RSS_SECRET_KEY0_A);
+ if (idx >= 0 && idx < 16)
+ t4_write_reg(adap, TP_RSS_CONFIG_VRT_A,
+ KEYWRADDR_V(idx) | KEYWREN_F);
+}
+
+/**
+ * t4_read_rss_pf_config - read PF RSS Configuration Table
+ * @adapter: the adapter
+ * @index: the entry in the PF RSS table to read
+ * @valp: where to store the returned value
+ *
+ * Reads the PF RSS Configuration Table at the specified index and returns
+ * the value found there.
+ */
+void t4_read_rss_pf_config(struct adapter *adapter, unsigned int index,
+ u32 *valp)
+{
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ valp, 1, TP_RSS_PF0_CONFIG_A + index);
+}
+
+/**
+ * t4_read_rss_vf_config - read VF RSS Configuration Table
+ * @adapter: the adapter
+ * @index: the entry in the VF RSS table to read
+ * @vfl: where to store the returned VFL
+ * @vfh: where to store the returned VFH
+ *
+ * Reads the VF RSS Configuration Table at the specified index and returns
+ * the (VFL, VFH) values found there.
+ */
+void t4_read_rss_vf_config(struct adapter *adapter, unsigned int index,
+ u32 *vfl, u32 *vfh)
+{
+ u32 vrt, mask, data;
+
+ mask = VFWRADDR_V(VFWRADDR_M);
+ data = VFWRADDR_V(index);
+
+ /* Request that the index'th VF Table values be read into VFL/VFH.
+ */
+ vrt = t4_read_reg(adapter, TP_RSS_CONFIG_VRT_A);
+ vrt &= ~(VFRDRG_F | VFWREN_F | KEYWREN_F | mask);
+ vrt |= data | VFRDEN_F;
+ t4_write_reg(adapter, TP_RSS_CONFIG_VRT_A, vrt);
+
+ /* Grab the VFL/VFH values ...
+ */
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ vfl, 1, TP_RSS_VFL_CONFIG_A);
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ vfh, 1, TP_RSS_VFH_CONFIG_A);
+}
+
+/**
+ * t4_read_rss_pf_map - read PF RSS Map
+ * @adapter: the adapter
+ *
+ * Reads the PF RSS Map register and returns its value.
+ */
+u32 t4_read_rss_pf_map(struct adapter *adapter)
+{
+ u32 pfmap;
+
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &pfmap, 1, TP_RSS_PF_MAP_A);
+ return pfmap;
+}
+
+/**
+ * t4_read_rss_pf_mask - read PF RSS Mask
+ * @adapter: the adapter
+ *
+ * Reads the PF RSS Mask register and returns its value.
+ */
+u32 t4_read_rss_pf_mask(struct adapter *adapter)
+{
+ u32 pfmask;
+
+ t4_read_indirect(adapter, TP_PIO_ADDR_A, TP_PIO_DATA_A,
+ &pfmask, 1, TP_RSS_PF_MSK_A);
+ return pfmask;
+}
+
/**
* t4_tp_get_tcp_stats - read TP's TCP MIB counters
* @adap: the adapter
@@ -2178,23 +2405,23 @@ int t4_config_glbl_rss(struct adapter *adapter, int mbox, unsigned int mode,
void t4_tp_get_tcp_stats(struct adapter *adap, struct tp_tcp_stats *v4,
struct tp_tcp_stats *v6)
{
- u32 val[TP_MIB_TCP_RXT_SEG_LO - TP_MIB_TCP_OUT_RST + 1];
+ u32 val[TP_MIB_TCP_RXT_SEG_LO_A - TP_MIB_TCP_OUT_RST_A + 1];
-#define STAT_IDX(x) ((TP_MIB_TCP_##x) - TP_MIB_TCP_OUT_RST)
+#define STAT_IDX(x) ((TP_MIB_TCP_##x##_A) - TP_MIB_TCP_OUT_RST_A)
#define STAT(x) val[STAT_IDX(x)]
#define STAT64(x) (((u64)STAT(x##_HI) << 32) | STAT(x##_LO))
if (v4) {
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val,
- ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+ ARRAY_SIZE(val), TP_MIB_TCP_OUT_RST_A);
v4->tcpOutRsts = STAT(OUT_RST);
v4->tcpInSegs = STAT64(IN_SEG);
v4->tcpOutSegs = STAT64(OUT_SEG);
v4->tcpRetransSegs = STAT64(RXT_SEG);
}
if (v6) {
- t4_read_indirect(adap, TP_MIB_INDEX, TP_MIB_DATA, val,
- ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST);
+ t4_read_indirect(adap, TP_MIB_INDEX_A, TP_MIB_DATA_A, val,
+ ARRAY_SIZE(val), TP_MIB_TCP_V6OUT_RST_A);
v6->tcpOutRsts = STAT(OUT_RST);
v6->tcpInSegs = STAT64(IN_SEG);
v6->tcpOutSegs = STAT64(OUT_SEG);
@@ -2219,16 +2446,37 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
int i;
for (i = 0; i < NMTUS; ++i) {
- t4_write_reg(adap, TP_MTU_TABLE,
- MTUINDEX(0xff) | MTUVALUE(i));
- v = t4_read_reg(adap, TP_MTU_TABLE);
- mtus[i] = MTUVALUE_GET(v);
+ t4_write_reg(adap, TP_MTU_TABLE_A,
+ MTUINDEX_V(0xff) | MTUVALUE_V(i));
+ v = t4_read_reg(adap, TP_MTU_TABLE_A);
+ mtus[i] = MTUVALUE_G(v);
if (mtu_log)
- mtu_log[i] = MTUWIDTH_GET(v);
+ mtu_log[i] = MTUWIDTH_G(v);
}
}
/**
+ * t4_read_cong_tbl - reads the congestion control table
+ * @adap: the adapter
+ * @incr: where to store the alpha values
+ *
+ * Reads the additive increments programmed into the HW congestion
+ * control table.
+ */
+void t4_read_cong_tbl(struct adapter *adap, u16 incr[NMTUS][NCCTRL_WIN])
+{
+ unsigned int mtu, w;
+
+ for (mtu = 0; mtu < NMTUS; ++mtu)
+ for (w = 0; w < NCCTRL_WIN; ++w) {
+ t4_write_reg(adap, TP_CCTRL_TABLE_A,
+ ROWINDEX_V(0xffff) | (mtu << 5) | w);
+ incr[mtu][w] = (u16)t4_read_reg(adap,
+ TP_CCTRL_TABLE_A) & 0x1fff;
+ }
+}
+
+/**
* t4_tp_wr_bits_indirect - set/clear bits in an indirect TP register
* @adap: the adapter
* @addr: the indirect TP register address
@@ -2240,9 +2488,9 @@ void t4_read_mtu_tbl(struct adapter *adap, u16 *mtus, u8 *mtu_log)
void t4_tp_wr_bits_indirect(struct adapter *adap, unsigned int addr,
unsigned int mask, unsigned int val)
{
- t4_write_reg(adap, TP_PIO_ADDR, addr);
- val |= t4_read_reg(adap, TP_PIO_DATA) & ~mask;
- t4_write_reg(adap, TP_PIO_DATA, val);
+ t4_write_reg(adap, TP_PIO_ADDR_A, addr);
+ val |= t4_read_reg(adap, TP_PIO_DATA_A) & ~mask;
+ t4_write_reg(adap, TP_PIO_DATA_A, val);
}
/**
@@ -2321,8 +2569,8 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
if (!(mtu & ((1 << log2) >> 2))) /* round */
log2--;
- t4_write_reg(adap, TP_MTU_TABLE, MTUINDEX(i) |
- MTUWIDTH(log2) | MTUVALUE(mtu));
+ t4_write_reg(adap, TP_MTU_TABLE_A, MTUINDEX_V(i) |
+ MTUWIDTH_V(log2) | MTUVALUE_V(mtu));
for (w = 0; w < NCCTRL_WIN; ++w) {
unsigned int inc;
@@ -2330,13 +2578,67 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
inc = max(((mtu - 40) * alpha[w]) / avg_pkts[w],
CC_MIN_INCR);
- t4_write_reg(adap, TP_CCTRL_TABLE, (i << 21) |
+ t4_write_reg(adap, TP_CCTRL_TABLE_A, (i << 21) |
(w << 16) | (beta[w] << 13) | inc);
}
}
}
/**
+ * t4_pmtx_get_stats - returns the HW stats from PMTX
+ * @adap: the adapter
+ * @cnt: where to store the count statistics
+ * @cycles: where to store the cycle statistics
+ *
+ * Returns performance statistics from PMTX.
+ */
+void t4_pmtx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
+{
+ int i;
+ u32 data[2];
+
+ for (i = 0; i < PM_NSTATS; i++) {
+ t4_write_reg(adap, PM_TX_STAT_CONFIG_A, i + 1);
+ cnt[i] = t4_read_reg(adap, PM_TX_STAT_COUNT_A);
+ if (is_t4(adap->params.chip)) {
+ cycles[i] = t4_read_reg64(adap, PM_TX_STAT_LSB_A);
+ } else {
+ t4_read_indirect(adap, PM_TX_DBG_CTRL_A,
+ PM_TX_DBG_DATA_A, data, 2,
+ PM_TX_DBG_STAT_MSB_A);
+ cycles[i] = (((u64)data[0] << 32) | data[1]);
+ }
+ }
+}
+
+/**
+ * t4_pmrx_get_stats - returns the HW stats from PMRX
+ * @adap: the adapter
+ * @cnt: where to store the count statistics
+ * @cycles: where to store the cycle statistics
+ *
+ * Returns performance statistics from PMRX.
+ */
+void t4_pmrx_get_stats(struct adapter *adap, u32 cnt[], u64 cycles[])
+{
+ int i;
+ u32 data[2];
+
+ for (i = 0; i < PM_NSTATS; i++) {
+ t4_write_reg(adap, PM_RX_STAT_CONFIG_A, i + 1);
+ cnt[i] = t4_read_reg(adap, PM_RX_STAT_COUNT_A);
+ if (is_t4(adap->params.chip)) {
+ cycles[i] = t4_read_reg64(adap, PM_RX_STAT_LSB_A);
+ } else {
+ t4_read_indirect(adap, PM_RX_DBG_CTRL_A,
+ PM_RX_DBG_DATA_A, data, 2,
+ PM_RX_DBG_STAT_MSB_A);
+ cycles[i] = (((u64)data[0] << 32) | data[1]);
+ }
+ }
+}
+
+/**
* get_mps_bg_map - return the buffer groups associated with a port
* @adap: the adapter
* @idx: the port index
@@ -2347,7 +2649,7 @@ void t4_load_mtus(struct adapter *adap, const unsigned short *mtus,
*/
static unsigned int get_mps_bg_map(struct adapter *adap, int idx)
{
- u32 n = NUMPORTS_GET(t4_read_reg(adap, MPS_CMN_CTL));
+ u32 n = NUMPORTS_G(t4_read_reg(adap, MPS_CMN_CTL_A));
if (n == 0)
return idx == 0 ? 0xf : 0;
@@ -2485,11 +2787,11 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
if (is_t4(adap->params.chip)) {
mag_id_reg_l = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_LO);
mag_id_reg_h = PORT_REG(port, XGMAC_PORT_MAGIC_MACID_HI);
- port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2);
+ port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A);
} else {
mag_id_reg_l = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_LO);
mag_id_reg_h = T5_PORT_REG(port, MAC_PORT_MAGIC_MACID_HI);
- port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2);
+ port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A);
}
if (addr) {
@@ -2499,8 +2801,8 @@ void t4_wol_magic_enable(struct adapter *adap, unsigned int port,
t4_write_reg(adap, mag_id_reg_h,
(addr[0] << 8) | addr[1]);
}
- t4_set_reg_field(adap, port_cfg_reg, MAGICEN,
- addr ? MAGICEN : 0);
+ t4_set_reg_field(adap, port_cfg_reg, MAGICEN_F,
+ addr ? MAGICEN_F : 0);
}
/**
@@ -2525,20 +2827,21 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
u32 port_cfg_reg;
if (is_t4(adap->params.chip))
- port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2);
+ port_cfg_reg = PORT_REG(port, XGMAC_PORT_CFG2_A);
else
- port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2);
+ port_cfg_reg = T5_PORT_REG(port, MAC_PORT_CFG2_A);
if (!enable) {
- t4_set_reg_field(adap, port_cfg_reg, PATEN, 0);
+ t4_set_reg_field(adap, port_cfg_reg, PATEN_F, 0);
return 0;
}
if (map > 0xff)
return -EINVAL;
#define EPIO_REG(name) \
- (is_t4(adap->params.chip) ? PORT_REG(port, XGMAC_PORT_EPIO_##name) : \
- T5_PORT_REG(port, MAC_PORT_EPIO_##name))
+ (is_t4(adap->params.chip) ? \
+ PORT_REG(port, XGMAC_PORT_EPIO_##name##_A) : \
+ T5_PORT_REG(port, MAC_PORT_EPIO_##name##_A))
t4_write_reg(adap, EPIO_REG(DATA1), mask0 >> 32);
t4_write_reg(adap, EPIO_REG(DATA2), mask1);
@@ -2550,21 +2853,21 @@ int t4_wol_pat_enable(struct adapter *adap, unsigned int port, unsigned int map,
/* write byte masks */
t4_write_reg(adap, EPIO_REG(DATA0), mask0);
- t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i) | EPIOWR);
+ t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i) | EPIOWR_F);
t4_read_reg(adap, EPIO_REG(OP)); /* flush */
- if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY)
+ if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F)
return -ETIMEDOUT;
/* write CRC */
t4_write_reg(adap, EPIO_REG(DATA0), crc);
- t4_write_reg(adap, EPIO_REG(OP), ADDRESS(i + 32) | EPIOWR);
+ t4_write_reg(adap, EPIO_REG(OP), ADDRESS_V(i + 32) | EPIOWR_F);
t4_read_reg(adap, EPIO_REG(OP)); /* flush */
- if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY)
+ if (t4_read_reg(adap, EPIO_REG(OP)) & SF_BUSY_F)
return -ETIMEDOUT;
}
#undef EPIO_REG
- t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2), 0, PATEN);
+ t4_set_reg_field(adap, PORT_REG(port, XGMAC_PORT_CFG2_A), 0, PATEN_F);
return 0;
}
@@ -2749,9 +3052,9 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)
"IDMA_FL_SEND_COMPLETION_TO_IMSG",
};
static const u32 sge_regs[] = {
- SGE_DEBUG_DATA_LOW_INDEX_2,
- SGE_DEBUG_DATA_LOW_INDEX_3,
- SGE_DEBUG_DATA_HIGH_INDEX_10,
+ SGE_DEBUG_DATA_LOW_INDEX_2_A,
+ SGE_DEBUG_DATA_LOW_INDEX_3_A,
+ SGE_DEBUG_DATA_HIGH_INDEX_10_A,
};
const char **sge_idma_decode;
int sge_idma_decode_nstates;
@@ -2818,7 +3121,7 @@ retry:
if (ret < 0) {
if ((ret == -EBUSY || ret == -ETIMEDOUT) && retries-- > 0)
goto retry;
- if (t4_read_reg(adap, MA_PCIE_FW) & PCIE_FW_ERR)
+ if (t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_ERR_F)
t4_report_fw_error(adap);
return ret;
}
@@ -2868,8 +3171,8 @@ retry:
* timeout ... and then retry if we haven't exhausted
* our retries ...
*/
- pcie_fw = t4_read_reg(adap, MA_PCIE_FW);
- if (!(pcie_fw & (PCIE_FW_ERR|PCIE_FW_INIT))) {
+ pcie_fw = t4_read_reg(adap, PCIE_FW_A);
+ if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) {
if (waiting <= 0) {
if (retries-- > 0)
goto retry;
@@ -2884,9 +3187,9 @@ retry:
* report errors preferentially.
*/
if (state) {
- if (pcie_fw & PCIE_FW_ERR)
+ if (pcie_fw & PCIE_FW_ERR_F)
*state = DEV_STATE_ERR;
- else if (pcie_fw & PCIE_FW_INIT)
+ else if (pcie_fw & PCIE_FW_INIT_F)
*state = DEV_STATE_INIT;
}
@@ -2896,7 +3199,7 @@ retry:
* for our caller.
*/
if (master_mbox == PCIE_FW_MASTER_M &&
- (pcie_fw & PCIE_FW_MASTER_VLD))
+ (pcie_fw & PCIE_FW_MASTER_VLD_F))
master_mbox = PCIE_FW_MASTER_G(pcie_fw);
break;
}
@@ -2985,7 +3288,7 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
memset(&c, 0, sizeof(c));
INIT_CMD(c, RESET, WRITE);
- c.val = htonl(PIORST | PIORSTMODE);
+ c.val = htonl(PIORST_F | PIORSTMODE_F);
c.halt_pkd = htonl(FW_RESET_CMD_HALT_F);
ret = t4_wr_mbox(adap, mbox, &c, sizeof(c), NULL);
}
@@ -3004,8 +3307,8 @@ static int t4_fw_halt(struct adapter *adap, unsigned int mbox, int force)
* rather than a RESET ... if it's new enough to understand that ...
*/
if (ret == 0 || force) {
- t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, UPCRST);
- t4_set_reg_field(adap, PCIE_FW, PCIE_FW_HALT_F,
+ t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F);
+ t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F,
PCIE_FW_HALT_F);
}
@@ -3045,7 +3348,7 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
* doing it automatically, we need to clear the PCIE_FW.HALT
* bit.
*/
- t4_set_reg_field(adap, PCIE_FW, PCIE_FW_HALT_F, 0);
+ t4_set_reg_field(adap, PCIE_FW_A, PCIE_FW_HALT_F, 0);
/*
* If we've been given a valid mailbox, first try to get the
@@ -3055,21 +3358,21 @@ static int t4_fw_restart(struct adapter *adap, unsigned int mbox, int reset)
* hitting the chip with a hammer.
*/
if (mbox <= PCIE_FW_MASTER_M) {
- t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0);
+ t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0);
msleep(100);
if (t4_fw_reset(adap, mbox,
- PIORST | PIORSTMODE) == 0)
+ PIORST_F | PIORSTMODE_F) == 0)
return 0;
}
- t4_write_reg(adap, PL_RST, PIORST | PIORSTMODE);
+ t4_write_reg(adap, PL_RST_A, PIORST_F | PIORSTMODE_F);
msleep(2000);
} else {
int ms;
- t4_set_reg_field(adap, CIM_BOOT_CFG, UPCRST, 0);
+ t4_set_reg_field(adap, CIM_BOOT_CFG_A, UPCRST_F, 0);
for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) {
- if (!(t4_read_reg(adap, PCIE_FW) & PCIE_FW_HALT_F))
+ if (!(t4_read_reg(adap, PCIE_FW_A) & PCIE_FW_HALT_F))
return 0;
msleep(100);
ms += 100;
@@ -3148,22 +3451,23 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
unsigned int fl_align = cache_line_size < 32 ? 32 : cache_line_size;
unsigned int fl_align_log = fls(fl_align) - 1;
- t4_write_reg(adap, SGE_HOST_PAGE_SIZE,
- HOSTPAGESIZEPF0(sge_hps) |
- HOSTPAGESIZEPF1(sge_hps) |
- HOSTPAGESIZEPF2(sge_hps) |
- HOSTPAGESIZEPF3(sge_hps) |
- HOSTPAGESIZEPF4(sge_hps) |
- HOSTPAGESIZEPF5(sge_hps) |
- HOSTPAGESIZEPF6(sge_hps) |
- HOSTPAGESIZEPF7(sge_hps));
+ t4_write_reg(adap, SGE_HOST_PAGE_SIZE_A,
+ HOSTPAGESIZEPF0_V(sge_hps) |
+ HOSTPAGESIZEPF1_V(sge_hps) |
+ HOSTPAGESIZEPF2_V(sge_hps) |
+ HOSTPAGESIZEPF3_V(sge_hps) |
+ HOSTPAGESIZEPF4_V(sge_hps) |
+ HOSTPAGESIZEPF5_V(sge_hps) |
+ HOSTPAGESIZEPF6_V(sge_hps) |
+ HOSTPAGESIZEPF7_V(sge_hps));
if (is_t4(adap->params.chip)) {
- t4_set_reg_field(adap, SGE_CONTROL,
- INGPADBOUNDARY_MASK |
- EGRSTATUSPAGESIZE_MASK,
- INGPADBOUNDARY(fl_align_log - 5) |
- EGRSTATUSPAGESIZE(stat_len != 64));
+ t4_set_reg_field(adap, SGE_CONTROL_A,
+ INGPADBOUNDARY_V(INGPADBOUNDARY_M) |
+ EGRSTATUSPAGESIZE_F,
+ INGPADBOUNDARY_V(fl_align_log -
+ INGPADBOUNDARY_SHIFT_X) |
+ EGRSTATUSPAGESIZE_V(stat_len != 64));
} else {
/* T5 introduced the separation of the Free List Padding and
* Packing Boundaries. Thus, we can select a smaller Padding
@@ -3193,15 +3497,15 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
fl_align = 64;
fl_align_log = 6;
}
- t4_set_reg_field(adap, SGE_CONTROL,
- INGPADBOUNDARY_MASK |
- EGRSTATUSPAGESIZE_MASK,
- INGPADBOUNDARY(INGPCIEBOUNDARY_32B_X) |
- EGRSTATUSPAGESIZE(stat_len != 64));
+ t4_set_reg_field(adap, SGE_CONTROL_A,
+ INGPADBOUNDARY_V(INGPADBOUNDARY_M) |
+ EGRSTATUSPAGESIZE_F,
+ INGPADBOUNDARY_V(INGPCIEBOUNDARY_32B_X) |
+ EGRSTATUSPAGESIZE_V(stat_len != 64));
t4_set_reg_field(adap, SGE_CONTROL2_A,
INGPACKBOUNDARY_V(INGPACKBOUNDARY_M),
INGPACKBOUNDARY_V(fl_align_log -
- INGPACKBOUNDARY_SHIFT_X));
+ INGPACKBOUNDARY_SHIFT_X));
}
/*
* Adjust various SGE Free List Host Buffer Sizes.
@@ -3224,15 +3528,15 @@ int t4_fixup_host_params(struct adapter *adap, unsigned int page_size,
* Default Firmware Configuration File but we need to adjust it for
* this host's cache line size.
*/
- t4_write_reg(adap, SGE_FL_BUFFER_SIZE0, page_size);
- t4_write_reg(adap, SGE_FL_BUFFER_SIZE2,
- (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2) + fl_align-1)
+ t4_write_reg(adap, SGE_FL_BUFFER_SIZE0_A, page_size);
+ t4_write_reg(adap, SGE_FL_BUFFER_SIZE2_A,
+ (t4_read_reg(adap, SGE_FL_BUFFER_SIZE2_A) + fl_align-1)
& ~(fl_align-1));
- t4_write_reg(adap, SGE_FL_BUFFER_SIZE3,
- (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3) + fl_align-1)
+ t4_write_reg(adap, SGE_FL_BUFFER_SIZE3_A,
+ (t4_read_reg(adap, SGE_FL_BUFFER_SIZE3_A) + fl_align-1)
& ~(fl_align-1));
- t4_write_reg(adap, ULP_RX_TDDP_PSZ, HPZ0(page_shift - 12));
+ t4_write_reg(adap, ULP_RX_TDDP_PSZ_A, HPZ0_V(page_shift - 12));
return 0;
}
@@ -3917,12 +4221,12 @@ int t4_wait_dev_ready(void __iomem *regs)
{
u32 whoami;
- whoami = readl(regs + PL_WHOAMI);
+ whoami = readl(regs + PL_WHOAMI_A);
if (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS)
return 0;
msleep(500);
- whoami = readl(regs + PL_WHOAMI);
+ whoami = readl(regs + PL_WHOAMI_A);
return (whoami != 0xffffffff && whoami != CIM_PF_NOACCESS ? 0 : -EIO);
}
@@ -3946,7 +4250,7 @@ static int get_flash_params(struct adapter *adap)
ret = sf1_write(adap, 1, 1, 0, SF_RD_ID);
if (!ret)
ret = sf1_read(adap, 3, 0, 1, &info);
- t4_write_reg(adap, SF_OP, 0); /* unlock SF */
+ t4_write_reg(adap, SF_OP_A, 0); /* unlock SF */
if (ret)
return ret;
@@ -3969,7 +4273,7 @@ static int get_flash_params(struct adapter *adap)
return -EINVAL;
adap->params.sf_size = 1 << info;
adap->params.sf_fw_start =
- t4_read_reg(adap, CIM_BOOT_CFG) & BOOTADDR_MASK;
+ t4_read_reg(adap, CIM_BOOT_CFG_A) & BOOTADDR_M;
if (adap->params.sf_size < FLASH_MIN_SIZE)
dev_warn(adap->pdev_dev, "WARNING!!! FLASH size %#x < %#x!!!\n",
@@ -3993,7 +4297,7 @@ int t4_prep_adapter(struct adapter *adapter)
u32 pl_rev;
get_pci_mode(adapter, &adapter->params.pci);
- pl_rev = G_REV(t4_read_reg(adapter, PL_REV));
+ pl_rev = REV_G(t4_read_reg(adapter, PL_REV_A));
ret = get_flash_params(adapter);
if (ret < 0) {
@@ -4019,6 +4323,7 @@ int t4_prep_adapter(struct adapter *adapter)
return -EINVAL;
}
+ adapter->params.cim_la_size = CIMLA_SIZE;
init_cong_ctrl(adapter->params.a_wnd, adapter->params.b_wnd);
/*
@@ -4133,7 +4438,7 @@ int t4_init_sge_params(struct adapter *adapter)
/* Extract the SGE Page Size for our PF.
*/
- hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE);
+ hps = t4_read_reg(adapter, SGE_HOST_PAGE_SIZE_A);
s_hps = (HOSTPAGESIZEPF0_S +
(HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * adapter->fn);
sge_params->hps = ((hps >> s_hps) & HOSTPAGESIZEPF0_M);
@@ -4142,10 +4447,10 @@ int t4_init_sge_params(struct adapter *adapter)
*/
s_qpp = (QUEUESPERPAGEPF0_S +
(QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * adapter->fn);
- qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF);
- sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_MASK);
- qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF);
- sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_MASK);
+ qpp = t4_read_reg(adapter, SGE_EGRESS_QUEUES_PER_PAGE_PF_A);
+ sge_params->eq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M);
+ qpp = t4_read_reg(adapter, SGE_INGRESS_QUEUES_PER_PAGE_PF_A);
+ sge_params->iq_qpp = ((qpp >> s_qpp) & QUEUESPERPAGEPF0_M);
return 0;
}
@@ -4161,9 +4466,9 @@ int t4_init_tp_params(struct adapter *adap)
int chan;
u32 v;
- v = t4_read_reg(adap, TP_TIMER_RESOLUTION);
- adap->params.tp.tre = TIMERRESOLUTION_GET(v);
- adap->params.tp.dack_re = DELAYEDACKRESOLUTION_GET(v);
+ v = t4_read_reg(adap, TP_TIMER_RESOLUTION_A);
+ adap->params.tp.tre = TIMERRESOLUTION_G(v);
+ adap->params.tp.dack_re = DELAYEDACKRESOLUTION_G(v);
/* MODQ_REQ_MAP defaults to setting queues 0-3 to chan 0-3 */
for (chan = 0; chan < NCHAN; chan++)
@@ -4172,27 +4477,27 @@ int t4_init_tp_params(struct adapter *adap)
/* Cache the adapter's Compressed Filter Mode and global Incress
* Configuration.
*/
- t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+ t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
&adap->params.tp.vlan_pri_map, 1,
- TP_VLAN_PRI_MAP);
- t4_read_indirect(adap, TP_PIO_ADDR, TP_PIO_DATA,
+ TP_VLAN_PRI_MAP_A);
+ t4_read_indirect(adap, TP_PIO_ADDR_A, TP_PIO_DATA_A,
&adap->params.tp.ingress_config, 1,
- TP_INGRESS_CONFIG);
+ TP_INGRESS_CONFIG_A);
/* Now that we have TP_VLAN_PRI_MAP cached, we can calculate the field
* shift positions of several elements of the Compressed Filter Tuple
* for this adapter which we need frequently ...
*/
- adap->params.tp.vlan_shift = t4_filter_field_shift(adap, F_VLAN);
- adap->params.tp.vnic_shift = t4_filter_field_shift(adap, F_VNIC_ID);
- adap->params.tp.port_shift = t4_filter_field_shift(adap, F_PORT);
+ adap->params.tp.vlan_shift = t4_filter_field_shift(adap, VLAN_F);
+ adap->params.tp.vnic_shift = t4_filter_field_shift(adap, VNIC_ID_F);
+ adap->params.tp.port_shift = t4_filter_field_shift(adap, PORT_F);
adap->params.tp.protocol_shift = t4_filter_field_shift(adap,
- F_PROTOCOL);
+ PROTOCOL_F);
/* If TP_INGRESS_CONFIG.VNID == 0, then TP_VLAN_PRI_MAP.VNIC_ID
* represents the presense of an Outer VLAN instead of a VNIC ID.
*/
- if ((adap->params.tp.ingress_config & F_VNIC) == 0)
+ if ((adap->params.tp.ingress_config & VNIC_F) == 0)
adap->params.tp.vnic_shift = -1;
return 0;
@@ -4218,35 +4523,35 @@ int t4_filter_field_shift(const struct adapter *adap, int filter_sel)
for (sel = 1, field_shift = 0; sel < filter_sel; sel <<= 1) {
switch (filter_mode & sel) {
- case F_FCOE:
- field_shift += W_FT_FCOE;
+ case FCOE_F:
+ field_shift += FT_FCOE_W;
break;
- case F_PORT:
- field_shift += W_FT_PORT;
+ case PORT_F:
+ field_shift += FT_PORT_W;
break;
- case F_VNIC_ID:
- field_shift += W_FT_VNIC_ID;
+ case VNIC_ID_F:
+ field_shift += FT_VNIC_ID_W;
break;
- case F_VLAN:
- field_shift += W_FT_VLAN;
+ case VLAN_F:
+ field_shift += FT_VLAN_W;
break;
- case F_TOS:
- field_shift += W_FT_TOS;
+ case TOS_F:
+ field_shift += FT_TOS_W;
break;
- case F_PROTOCOL:
- field_shift += W_FT_PROTOCOL;
+ case PROTOCOL_F:
+ field_shift += FT_PROTOCOL_W;
break;
- case F_ETHERTYPE:
- field_shift += W_FT_ETHERTYPE;
+ case ETHERTYPE_F:
+ field_shift += FT_ETHERTYPE_W;
break;
- case F_MACMATCH:
- field_shift += W_FT_MACMATCH;
+ case MACMATCH_F:
+ field_shift += FT_MACMATCH_W;
break;
- case F_MPSHITTYPE:
- field_shift += W_FT_MPSHITTYPE;
+ case MPSHITTYPE_F:
+ field_shift += FT_MPSHITTYPE_W;
break;
- case F_FRAGMENTATION:
- field_shift += W_FT_FRAGMENTATION;
+ case FRAGMENTATION_F:
+ field_shift += FT_FRAGMENTATION_W;
break;
}
}
@@ -4311,3 +4616,289 @@ int t4_port_init(struct adapter *adap, int mbox, int pf, int vf)
}
return 0;
}
+
+/**
+ * t4_read_cimq_cfg - read CIM queue configuration
+ * @adap: the adapter
+ * @base: holds the queue base addresses in bytes
+ * @size: holds the queue sizes in bytes
+ * @thres: holds the queue full thresholds in bytes
+ *
+ * Returns the current configuration of the CIM queues, starting with
+ * the IBQs, then the OBQs.
+ */
+void t4_read_cimq_cfg(struct adapter *adap, u16 *base, u16 *size, u16 *thres)
+{
+ unsigned int i, v;
+ int cim_num_obq = is_t4(adap->params.chip) ?
+ CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
+
+ for (i = 0; i < CIM_NUM_IBQ; i++) {
+ t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, IBQSELECT_F |
+ QUENUMSELECT_V(i));
+ v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
+ /* value is in 256-byte units */
+ *base++ = CIMQBASE_G(v) * 256;
+ *size++ = CIMQSIZE_G(v) * 256;
+ *thres++ = QUEFULLTHRSH_G(v) * 8; /* 8-byte unit */
+ }
+ for (i = 0; i < cim_num_obq; i++) {
+ t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
+ QUENUMSELECT_V(i));
+ v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
+ /* value is in 256-byte units */
+ *base++ = CIMQBASE_G(v) * 256;
+ *size++ = CIMQSIZE_G(v) * 256;
+ }
+}
+
+/**
+ * t4_read_cim_ibq - read the contents of a CIM inbound queue
+ * @adap: the adapter
+ * @qid: the queue index
+ * @data: where to store the queue contents
+ * @n: capacity of @data in 32-bit words
+ *
+ * Reads the contents of the selected CIM queue starting at address 0 up
+ * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on
+ * error and the number of 32-bit words actually read on success.
+ */
+int t4_read_cim_ibq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
+{
+ int i, err, attempts;
+ unsigned int addr;
+ const unsigned int nwords = CIM_IBQ_SIZE * 4;
+
+ if (qid > 5 || (n & 3))
+ return -EINVAL;
+
+ addr = qid * nwords;
+ if (n > nwords)
+ n = nwords;
+
+ /* It might take 3-10ms before the IBQ debug read access is allowed.
+ * Wait for 1 Sec with a delay of 1 usec.
+ */
+ attempts = 1000000;
+
+ for (i = 0; i < n; i++, addr++) {
+ t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, IBQDBGADDR_V(addr) |
+ IBQDBGEN_F);
+ err = t4_wait_op_done(adap, CIM_IBQ_DBG_CFG_A, IBQDBGBUSY_F, 0,
+ attempts, 1);
+ if (err)
+ return err;
+ *data++ = t4_read_reg(adap, CIM_IBQ_DBG_DATA_A);
+ }
+ t4_write_reg(adap, CIM_IBQ_DBG_CFG_A, 0);
+ return i;
+}
+
+/**
+ * t4_read_cim_obq - read the contents of a CIM outbound queue
+ * @adap: the adapter
+ * @qid: the queue index
+ * @data: where to store the queue contents
+ * @n: capacity of @data in 32-bit words
+ *
+ * Reads the contents of the selected CIM queue starting at address 0 up
+ * to the capacity of @data. @n must be a multiple of 4. Returns < 0 on
+ * error and the number of 32-bit words actually read on success.
+ */
+int t4_read_cim_obq(struct adapter *adap, unsigned int qid, u32 *data, size_t n)
+{
+ int i, err;
+ unsigned int addr, v, nwords;
+ int cim_num_obq = is_t4(adap->params.chip) ?
+ CIM_NUM_OBQ : CIM_NUM_OBQ_T5;
+
+ if ((qid > (cim_num_obq - 1)) || (n & 3))
+ return -EINVAL;
+
+ t4_write_reg(adap, CIM_QUEUE_CONFIG_REF_A, OBQSELECT_F |
+ QUENUMSELECT_V(qid));
+ v = t4_read_reg(adap, CIM_QUEUE_CONFIG_CTRL_A);
+
+ addr = CIMQBASE_G(v) * 64; /* muliple of 256 -> muliple of 4 */
+ nwords = CIMQSIZE_G(v) * 64; /* same */
+ if (n > nwords)
+ n = nwords;
+
+ for (i = 0; i < n; i++, addr++) {
+ t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, OBQDBGADDR_V(addr) |
+ OBQDBGEN_F);
+ err = t4_wait_op_done(adap, CIM_OBQ_DBG_CFG_A, OBQDBGBUSY_F, 0,
+ 2, 1);
+ if (err)
+ return err;
+ *data++ = t4_read_reg(adap, CIM_OBQ_DBG_DATA_A);
+ }
+ t4_write_reg(adap, CIM_OBQ_DBG_CFG_A, 0);
+ return i;
+}
+
+/**
+ * t4_cim_read - read a block from CIM internal address space
+ * @adap: the adapter
+ * @addr: the start address within the CIM address space
+ * @n: number of words to read
+ * @valp: where to store the result
+ *
+ * Reads a block of 4-byte words from the CIM intenal address space.
+ */
+int t4_cim_read(struct adapter *adap, unsigned int addr, unsigned int n,
+ unsigned int *valp)
+{
+ int ret = 0;
+
+ if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F)
+ return -EBUSY;
+
+ for ( ; !ret && n--; addr += 4) {
+ t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr);
+ ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F,
+ 0, 5, 2);
+ if (!ret)
+ *valp++ = t4_read_reg(adap, CIM_HOST_ACC_DATA_A);
+ }
+ return ret;
+}
+
+/**
+ * t4_cim_write - write a block into CIM internal address space
+ * @adap: the adapter
+ * @addr: the start address within the CIM address space
+ * @n: number of words to write
+ * @valp: set of values to write
+ *
+ * Writes a block of 4-byte words into the CIM intenal address space.
+ */
+int t4_cim_write(struct adapter *adap, unsigned int addr, unsigned int n,
+ const unsigned int *valp)
+{
+ int ret = 0;
+
+ if (t4_read_reg(adap, CIM_HOST_ACC_CTRL_A) & HOSTBUSY_F)
+ return -EBUSY;
+
+ for ( ; !ret && n--; addr += 4) {
+ t4_write_reg(adap, CIM_HOST_ACC_DATA_A, *valp++);
+ t4_write_reg(adap, CIM_HOST_ACC_CTRL_A, addr | HOSTWRITE_F);
+ ret = t4_wait_op_done(adap, CIM_HOST_ACC_CTRL_A, HOSTBUSY_F,
+ 0, 5, 2);
+ }
+ return ret;
+}
+
+static int t4_cim_write1(struct adapter *adap, unsigned int addr,
+ unsigned int val)
+{
+ return t4_cim_write(adap, addr, 1, &val);
+}
+
+/**
+ * t4_cim_read_la - read CIM LA capture buffer
+ * @adap: the adapter
+ * @la_buf: where to store the LA data
+ * @wrptr: the HW write pointer within the capture buffer
+ *
+ * Reads the contents of the CIM LA buffer with the most recent entry at
+ * the end of the returned data and with the entry at @wrptr first.
+ * We try to leave the LA in the running state we find it in.
+ */
+int t4_cim_read_la(struct adapter *adap, u32 *la_buf, unsigned int *wrptr)
+{
+ int i, ret;
+ unsigned int cfg, val, idx;
+
+ ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &cfg);
+ if (ret)
+ return ret;
+
+ if (cfg & UPDBGLAEN_F) { /* LA is running, freeze it */
+ ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A, 0);
+ if (ret)
+ return ret;
+ }
+
+ ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val);
+ if (ret)
+ goto restart;
+
+ idx = UPDBGLAWRPTR_G(val);
+ if (wrptr)
+ *wrptr = idx;
+
+ for (i = 0; i < adap->params.cim_la_size; i++) {
+ ret = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A,
+ UPDBGLARDPTR_V(idx) | UPDBGLARDEN_F);
+ if (ret)
+ break;
+ ret = t4_cim_read(adap, UP_UP_DBG_LA_CFG_A, 1, &val);
+ if (ret)
+ break;
+ if (val & UPDBGLARDEN_F) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+ ret = t4_cim_read(adap, UP_UP_DBG_LA_DATA_A, 1, &la_buf[i]);
+ if (ret)
+ break;
+ idx = (idx + 1) & UPDBGLARDPTR_M;
+ }
+restart:
+ if (cfg & UPDBGLAEN_F) {
+ int r = t4_cim_write1(adap, UP_UP_DBG_LA_CFG_A,
+ cfg & ~UPDBGLARDEN_F);
+ if (!ret)
+ ret = r;
+ }
+ return ret;
+}
+
+/**
+ * t4_tp_read_la - read TP LA capture buffer
+ * @adap: the adapter
+ * @la_buf: where to store the LA data
+ * @wrptr: the HW write pointer within the capture buffer
+ *
+ * Reads the contents of the TP LA buffer with the most recent entry at
+ * the end of the returned data and with the entry at @wrptr first.
+ * We leave the LA in the running state we find it in.
+ */
+void t4_tp_read_la(struct adapter *adap, u64 *la_buf, unsigned int *wrptr)
+{
+ bool last_incomplete;
+ unsigned int i, cfg, val, idx;
+
+ cfg = t4_read_reg(adap, TP_DBG_LA_CONFIG_A) & 0xffff;
+ if (cfg & DBGLAENABLE_F) /* freeze LA */
+ t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
+ adap->params.tp.la_mask | (cfg ^ DBGLAENABLE_F));
+
+ val = t4_read_reg(adap, TP_DBG_LA_CONFIG_A);
+ idx = DBGLAWPTR_G(val);
+ last_incomplete = DBGLAMODE_G(val) >= 2 && (val & DBGLAWHLF_F) == 0;
+ if (last_incomplete)
+ idx = (idx + 1) & DBGLARPTR_M;
+ if (wrptr)
+ *wrptr = idx;
+
+ val &= 0xffff;
+ val &= ~DBGLARPTR_V(DBGLARPTR_M);
+ val |= adap->params.tp.la_mask;
+
+ for (i = 0; i < TPLA_SIZE; i++) {
+ t4_write_reg(adap, TP_DBG_LA_CONFIG_A, DBGLARPTR_V(idx) | val);
+ la_buf[i] = t4_read_reg64(adap, TP_DBG_LA_DATAL_A);
+ idx = (idx + 1) & DBGLARPTR_M;
+ }
+
+ /* Wipe out last entry if it isn't valid */
+ if (last_incomplete)
+ la_buf[TPLA_SIZE - 1] = ~0ULL;
+
+ if (cfg & DBGLAENABLE_F) /* restore running state */
+ t4_write_reg(adap, TP_DBG_LA_CONFIG_A,
+ cfg | adap->params.tp.la_mask);
+}
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
index c19a90e7f7d1..380b15c0417a 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_hw.h
@@ -48,6 +48,7 @@ enum {
NMTUS = 16, /* size of MTU table */
NCCTRL_WIN = 32, /* # of congestion control windows */
L2T_SIZE = 4096, /* # of L2T entries */
+ PM_NSTATS = 5, /* # of PM stats */
MBOX_LEN = 64, /* mailbox size in bytes */
TRACE_LEN = 112, /* length of trace data and mask */
FILTER_OPT_LEN = 36, /* filter tuple width for optional components */
@@ -56,6 +57,17 @@ enum {
};
enum {
+ CIM_NUM_IBQ = 6, /* # of CIM IBQs */
+ CIM_NUM_OBQ = 6, /* # of CIM OBQs */
+ CIM_NUM_OBQ_T5 = 8, /* # of CIM OBQs for T5 adapter */
+ CIMLA_SIZE = 2048, /* # of 32-bit words in CIM LA */
+ CIM_IBQ_SIZE = 128, /* # of 128-bit words in a CIM IBQ */
+ CIM_OBQ_SIZE = 128, /* # of 128-bit words in a CIM OBQ */
+ TPLA_SIZE = 128, /* # of 64-bit words in TP LA */
+ ULPRX_LA_SIZE = 512, /* # of 256-bit words in ULP_RX LA */
+};
+
+enum {
SF_PAGE_SIZE = 256, /* serial flash page size */
SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
};
@@ -110,6 +122,18 @@ enum {
SGE_INGPADBOUNDARY_SHIFT = 5,/* ingress queue pad boundary */
};
+/* PCI-e memory window access */
+enum pcie_memwin {
+ MEMWIN_NIC = 0,
+ MEMWIN_RSVD1 = 1,
+ MEMWIN_RSVD2 = 2,
+ MEMWIN_RDMA = 3,
+ MEMWIN_RSVD4 = 4,
+ MEMWIN_FOISCSI = 5,
+ MEMWIN_CSIOSTOR = 6,
+ MEMWIN_RSVD7 = 7,
+};
+
struct sge_qstat { /* data written to SGE queue status entries */
__be32 qid;
__be16 cidx;
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
index 0f89f68948ab..0fb975e258b3 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_msg.h
@@ -124,6 +124,13 @@ enum CPL_error {
};
enum {
+ CPL_CONN_POLICY_AUTO = 0,
+ CPL_CONN_POLICY_ASK = 1,
+ CPL_CONN_POLICY_FILTER = 2,
+ CPL_CONN_POLICY_DENY = 3
+};
+
+enum {
ULP_MODE_NONE = 0,
ULP_MODE_ISCSI = 2,
ULP_MODE_RDMA = 4,
@@ -160,16 +167,28 @@ union opcode_tid {
u8 opcode;
};
-#define CPL_OPCODE(x) ((x) << 24)
-#define G_CPL_OPCODE(x) (((x) >> 24) & 0xFF)
-#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE(opcode) | (tid))
+#define CPL_OPCODE_S 24
+#define CPL_OPCODE_V(x) ((x) << CPL_OPCODE_S)
+#define CPL_OPCODE_G(x) (((x) >> CPL_OPCODE_S) & 0xFF)
+#define TID_G(x) ((x) & 0xFFFFFF)
+
+/* tid is assumed to be 24-bits */
+#define MK_OPCODE_TID(opcode, tid) (CPL_OPCODE_V(opcode) | (tid))
+
#define OPCODE_TID(cmd) ((cmd)->ot.opcode_tid)
-#define GET_TID(cmd) (ntohl(OPCODE_TID(cmd)) & 0xFFFFFF)
+
+/* extract the TID from a CPL command */
+#define GET_TID(cmd) (TID_G(be32_to_cpu(OPCODE_TID(cmd))))
/* partitioning of TID fields that also carry a queue id */
-#define GET_TID_TID(x) ((x) & 0x3fff)
-#define GET_TID_QID(x) (((x) >> 14) & 0x3ff)
-#define TID_QID(x) ((x) << 14)
+#define TID_TID_S 0
+#define TID_TID_M 0x3fff
+#define TID_TID_G(x) (((x) >> TID_TID_S) & TID_TID_M)
+
+#define TID_QID_S 14
+#define TID_QID_M 0x3ff
+#define TID_QID_V(x) ((x) << TID_QID_S)
+#define TID_QID_G(x) (((x) >> TID_QID_S) & TID_QID_M)
struct rss_header {
u8 opcode;
@@ -199,8 +218,8 @@ struct work_request_hdr {
};
/* wr_hi fields */
-#define S_WR_OP 24
-#define V_WR_OP(x) ((__u64)(x) << S_WR_OP)
+#define WR_OP_S 24
+#define WR_OP_V(x) ((__u64)(x) << WR_OP_S)
#define WR_HDR struct work_request_hdr wr
@@ -270,17 +289,42 @@ struct cpl_pass_open_req {
__be32 local_ip;
__be32 peer_ip;
__be64 opt0;
-#define NO_CONG(x) ((x) << 4)
-#define DELACK(x) ((x) << 5)
-#define DSCP(x) ((x) << 22)
-#define TCAM_BYPASS(x) ((u64)(x) << 48)
-#define NAGLE(x) ((u64)(x) << 49)
__be64 opt1;
-#define SYN_RSS_ENABLE (1 << 0)
-#define SYN_RSS_QUEUE(x) ((x) << 2)
-#define CONN_POLICY_ASK (1 << 22)
};
+/* option 0 fields */
+#define NO_CONG_S 4
+#define NO_CONG_V(x) ((x) << NO_CONG_S)
+#define NO_CONG_F NO_CONG_V(1U)
+
+#define DELACK_S 5
+#define DELACK_V(x) ((x) << DELACK_S)
+#define DELACK_F DELACK_V(1U)
+
+#define DSCP_S 22
+#define DSCP_M 0x3F
+#define DSCP_V(x) ((x) << DSCP_S)
+#define DSCP_G(x) (((x) >> DSCP_S) & DSCP_M)
+
+#define TCAM_BYPASS_S 48
+#define TCAM_BYPASS_V(x) ((__u64)(x) << TCAM_BYPASS_S)
+#define TCAM_BYPASS_F TCAM_BYPASS_V(1ULL)
+
+#define NAGLE_S 49
+#define NAGLE_V(x) ((__u64)(x) << NAGLE_S)
+#define NAGLE_F NAGLE_V(1ULL)
+
+/* option 1 fields */
+#define SYN_RSS_ENABLE_S 0
+#define SYN_RSS_ENABLE_V(x) ((x) << SYN_RSS_ENABLE_S)
+#define SYN_RSS_ENABLE_F SYN_RSS_ENABLE_V(1U)
+
+#define SYN_RSS_QUEUE_S 2
+#define SYN_RSS_QUEUE_V(x) ((x) << SYN_RSS_QUEUE_S)
+
+#define CONN_POLICY_S 22
+#define CONN_POLICY_V(x) ((x) << CONN_POLICY_S)
+
struct cpl_pass_open_req6 {
WR_HDR;
union opcode_tid ot;
@@ -304,16 +348,37 @@ struct cpl_pass_accept_rpl {
WR_HDR;
union opcode_tid ot;
__be32 opt2;
-#define RX_COALESCE_VALID(x) ((x) << 11)
-#define RX_COALESCE(x) ((x) << 12)
-#define PACE(x) ((x) << 16)
-#define TX_QUEUE(x) ((x) << 23)
-#define CCTRL_ECN(x) ((x) << 27)
-#define TSTAMPS_EN(x) ((x) << 29)
-#define SACK_EN(x) ((x) << 30)
__be64 opt0;
};
+/* option 2 fields */
+#define RX_COALESCE_VALID_S 11
+#define RX_COALESCE_VALID_V(x) ((x) << RX_COALESCE_VALID_S)
+#define RX_COALESCE_VALID_F RX_COALESCE_VALID_V(1U)
+
+#define RX_COALESCE_S 12
+#define RX_COALESCE_V(x) ((x) << RX_COALESCE_S)
+
+#define PACE_S 16
+#define PACE_V(x) ((x) << PACE_S)
+
+#define TX_QUEUE_S 23
+#define TX_QUEUE_M 0x7
+#define TX_QUEUE_V(x) ((x) << TX_QUEUE_S)
+#define TX_QUEUE_G(x) (((x) >> TX_QUEUE_S) & TX_QUEUE_M)
+
+#define CCTRL_ECN_S 27
+#define CCTRL_ECN_V(x) ((x) << CCTRL_ECN_S)
+#define CCTRL_ECN_F CCTRL_ECN_V(1U)
+
+#define TSTAMPS_EN_S 29
+#define TSTAMPS_EN_V(x) ((x) << TSTAMPS_EN_S)
+#define TSTAMPS_EN_F TSTAMPS_EN_V(1U)
+
+#define SACK_EN_S 30
+#define SACK_EN_V(x) ((x) << SACK_EN_S)
+#define SACK_EN_F SACK_EN_V(1U)
+
struct cpl_t5_pass_accept_rpl {
WR_HDR;
union opcode_tid ot;
@@ -384,30 +449,61 @@ struct cpl_t5_act_open_req6 {
struct cpl_act_open_rpl {
union opcode_tid ot;
__be32 atid_status;
-#define GET_AOPEN_STATUS(x) ((x) & 0xff)
-#define GET_AOPEN_ATID(x) (((x) >> 8) & 0xffffff)
};
+/* cpl_act_open_rpl.atid_status fields */
+#define AOPEN_STATUS_S 0
+#define AOPEN_STATUS_M 0xFF
+#define AOPEN_STATUS_G(x) (((x) >> AOPEN_STATUS_S) & AOPEN_STATUS_M)
+
+#define AOPEN_ATID_S 8
+#define AOPEN_ATID_M 0xFFFFFF
+#define AOPEN_ATID_G(x) (((x) >> AOPEN_ATID_S) & AOPEN_ATID_M)
+
struct cpl_pass_establish {
union opcode_tid ot;
__be32 rsvd;
__be32 tos_stid;
-#define PASS_OPEN_TID(x) ((x) << 0)
-#define PASS_OPEN_TOS(x) ((x) << 24)
-#define GET_PASS_OPEN_TID(x) (((x) >> 0) & 0xFFFFFF)
-#define GET_POPEN_TID(x) ((x) & 0xffffff)
-#define GET_POPEN_TOS(x) (((x) >> 24) & 0xff)
__be16 mac_idx;
__be16 tcp_opt;
-#define GET_TCPOPT_WSCALE_OK(x) (((x) >> 5) & 1)
-#define GET_TCPOPT_SACK(x) (((x) >> 6) & 1)
-#define GET_TCPOPT_TSTAMP(x) (((x) >> 7) & 1)
-#define GET_TCPOPT_SND_WSCALE(x) (((x) >> 8) & 0xf)
-#define GET_TCPOPT_MSS(x) (((x) >> 12) & 0xf)
__be32 snd_isn;
__be32 rcv_isn;
};
+/* cpl_pass_establish.tos_stid fields */
+#define PASS_OPEN_TID_S 0
+#define PASS_OPEN_TID_M 0xFFFFFF
+#define PASS_OPEN_TID_V(x) ((x) << PASS_OPEN_TID_S)
+#define PASS_OPEN_TID_G(x) (((x) >> PASS_OPEN_TID_S) & PASS_OPEN_TID_M)
+
+#define PASS_OPEN_TOS_S 24
+#define PASS_OPEN_TOS_M 0xFF
+#define PASS_OPEN_TOS_V(x) ((x) << PASS_OPEN_TOS_S)
+#define PASS_OPEN_TOS_G(x) (((x) >> PASS_OPEN_TOS_S) & PASS_OPEN_TOS_M)
+
+/* cpl_pass_establish.tcp_opt fields (also applies to act_open_establish) */
+#define TCPOPT_WSCALE_OK_S 5
+#define TCPOPT_WSCALE_OK_M 0x1
+#define TCPOPT_WSCALE_OK_G(x) \
+ (((x) >> TCPOPT_WSCALE_OK_S) & TCPOPT_WSCALE_OK_M)
+
+#define TCPOPT_SACK_S 6
+#define TCPOPT_SACK_M 0x1
+#define TCPOPT_SACK_G(x) (((x) >> TCPOPT_SACK_S) & TCPOPT_SACK_M)
+
+#define TCPOPT_TSTAMP_S 7
+#define TCPOPT_TSTAMP_M 0x1
+#define TCPOPT_TSTAMP_G(x) (((x) >> TCPOPT_TSTAMP_S) & TCPOPT_TSTAMP_M)
+
+#define TCPOPT_SND_WSCALE_S 8
+#define TCPOPT_SND_WSCALE_M 0xF
+#define TCPOPT_SND_WSCALE_G(x) \
+ (((x) >> TCPOPT_SND_WSCALE_S) & TCPOPT_SND_WSCALE_M)
+
+#define TCPOPT_MSS_S 12
+#define TCPOPT_MSS_M 0xF
+#define TCPOPT_MSS_G(x) (((x) >> TCPOPT_MSS_S) & TCPOPT_MSS_M)
+
struct cpl_act_establish {
union opcode_tid ot;
__be32 rsvd;
@@ -422,24 +518,39 @@ struct cpl_get_tcb {
WR_HDR;
union opcode_tid ot;
__be16 reply_ctrl;
-#define QUEUENO(x) ((x) << 0)
-#define REPLY_CHAN(x) ((x) << 14)
-#define NO_REPLY(x) ((x) << 15)
__be16 cookie;
};
+/* cpl_get_tcb.reply_ctrl fields */
+#define QUEUENO_S 0
+#define QUEUENO_V(x) ((x) << QUEUENO_S)
+
+#define REPLY_CHAN_S 14
+#define REPLY_CHAN_V(x) ((x) << REPLY_CHAN_S)
+#define REPLY_CHAN_F REPLY_CHAN_V(1U)
+
+#define NO_REPLY_S 15
+#define NO_REPLY_V(x) ((x) << NO_REPLY_S)
+#define NO_REPLY_F NO_REPLY_V(1U)
+
struct cpl_set_tcb_field {
WR_HDR;
union opcode_tid ot;
__be16 reply_ctrl;
__be16 word_cookie;
-#define TCB_WORD(x) ((x) << 0)
-#define TCB_COOKIE(x) ((x) << 5)
-#define GET_TCB_COOKIE(x) (((x) >> 5) & 7)
__be64 mask;
__be64 val;
};
+/* cpl_set_tcb_field.word_cookie fields */
+#define TCB_WORD_S 0
+#define TCB_WORD(x) ((x) << TCB_WORD_S)
+
+#define TCB_COOKIE_S 5
+#define TCB_COOKIE_M 0x7
+#define TCB_COOKIE_V(x) ((x) << TCB_COOKIE_S)
+#define TCB_COOKIE_G(x) (((x) >> TCB_COOKIE_S) & TCB_COOKIE_M)
+
struct cpl_set_tcb_rpl {
union opcode_tid ot;
__be16 rsvd;
@@ -466,10 +577,14 @@ struct cpl_close_listsvr_req {
WR_HDR;
union opcode_tid ot;
__be16 reply_ctrl;
-#define LISTSVR_IPV6(x) ((x) << 14)
__be16 rsvd;
};
+/* additional cpl_close_listsvr_req.reply_ctrl field */
+#define LISTSVR_IPV6_S 14
+#define LISTSVR_IPV6_V(x) ((x) << LISTSVR_IPV6_S)
+#define LISTSVR_IPV6_F LISTSVR_IPV6_V(1U)
+
struct cpl_close_listsvr_rpl {
union opcode_tid ot;
u8 rsvd[3];
@@ -565,6 +680,34 @@ struct cpl_tx_pkt_lso_core {
/* encapsulated CPL (TX_PKT, TX_PKT_XT or TX_DATA) follows here */
};
+/* cpl_tx_pkt_lso_core.lso_ctrl fields */
+#define LSO_TCPHDR_LEN_S 0
+#define LSO_TCPHDR_LEN_V(x) ((x) << LSO_TCPHDR_LEN_S)
+
+#define LSO_IPHDR_LEN_S 4
+#define LSO_IPHDR_LEN_V(x) ((x) << LSO_IPHDR_LEN_S)
+
+#define LSO_ETHHDR_LEN_S 16
+#define LSO_ETHHDR_LEN_V(x) ((x) << LSO_ETHHDR_LEN_S)
+
+#define LSO_IPV6_S 20
+#define LSO_IPV6_V(x) ((x) << LSO_IPV6_S)
+#define LSO_IPV6_F LSO_IPV6_V(1U)
+
+#define LSO_LAST_SLICE_S 22
+#define LSO_LAST_SLICE_V(x) ((x) << LSO_LAST_SLICE_S)
+#define LSO_LAST_SLICE_F LSO_LAST_SLICE_V(1U)
+
+#define LSO_FIRST_SLICE_S 23
+#define LSO_FIRST_SLICE_V(x) ((x) << LSO_FIRST_SLICE_S)
+#define LSO_FIRST_SLICE_F LSO_FIRST_SLICE_V(1U)
+
+#define LSO_OPCODE_S 24
+#define LSO_OPCODE_V(x) ((x) << LSO_OPCODE_S)
+
+#define LSO_T5_XFER_SIZE_S 0
+#define LSO_T5_XFER_SIZE_V(x) ((x) << LSO_T5_XFER_SIZE_S)
+
struct cpl_tx_pkt_lso {
WR_HDR;
struct cpl_tx_pkt_lso_core c;
@@ -574,8 +717,6 @@ struct cpl_tx_pkt_lso {
struct cpl_iscsi_hdr {
union opcode_tid ot;
__be16 pdu_len_ddp;
-#define ISCSI_PDU_LEN(x) ((x) & 0x7FFF)
-#define ISCSI_DDP (1 << 15)
__be16 len;
__be32 seq;
__be16 urg;
@@ -583,6 +724,16 @@ struct cpl_iscsi_hdr {
u8 status;
};
+/* cpl_iscsi_hdr.pdu_len_ddp fields */
+#define ISCSI_PDU_LEN_S 0
+#define ISCSI_PDU_LEN_M 0x7FFF
+#define ISCSI_PDU_LEN_V(x) ((x) << ISCSI_PDU_LEN_S)
+#define ISCSI_PDU_LEN_G(x) (((x) >> ISCSI_PDU_LEN_S) & ISCSI_PDU_LEN_M)
+
+#define ISCSI_DDP_S 15
+#define ISCSI_DDP_V(x) ((x) << ISCSI_DDP_S)
+#define ISCSI_DDP_F ISCSI_DDP_V(1U)
+
struct cpl_rx_data {
union opcode_tid ot;
__be16 rsvd;
@@ -639,49 +790,61 @@ struct cpl_rx_pkt {
__be16 vlan;
__be16 len;
__be32 l2info;
-#define RXF_UDP (1 << 22)
-#define RXF_TCP (1 << 23)
-#define RXF_IP (1 << 24)
-#define RXF_IP6 (1 << 25)
__be16 hdr_len;
__be16 err_vec;
};
+#define RXF_UDP_S 22
+#define RXF_UDP_V(x) ((x) << RXF_UDP_S)
+#define RXF_UDP_F RXF_UDP_V(1U)
+
+#define RXF_TCP_S 23
+#define RXF_TCP_V(x) ((x) << RXF_TCP_S)
+#define RXF_TCP_F RXF_TCP_V(1U)
+
+#define RXF_IP_S 24
+#define RXF_IP_V(x) ((x) << RXF_IP_S)
+#define RXF_IP_F RXF_IP_V(1U)
+
+#define RXF_IP6_S 25
+#define RXF_IP6_V(x) ((x) << RXF_IP6_S)
+#define RXF_IP6_F RXF_IP6_V(1U)
+
/* rx_pkt.l2info fields */
-#define S_RX_ETHHDR_LEN 0
-#define M_RX_ETHHDR_LEN 0x1F
-#define V_RX_ETHHDR_LEN(x) ((x) << S_RX_ETHHDR_LEN)
-#define G_RX_ETHHDR_LEN(x) (((x) >> S_RX_ETHHDR_LEN) & M_RX_ETHHDR_LEN)
-
-#define S_RX_T5_ETHHDR_LEN 0
-#define M_RX_T5_ETHHDR_LEN 0x3F
-#define V_RX_T5_ETHHDR_LEN(x) ((x) << S_RX_T5_ETHHDR_LEN)
-#define G_RX_T5_ETHHDR_LEN(x) (((x) >> S_RX_T5_ETHHDR_LEN) & M_RX_T5_ETHHDR_LEN)
-
-#define S_RX_MACIDX 8
-#define M_RX_MACIDX 0x1FF
-#define V_RX_MACIDX(x) ((x) << S_RX_MACIDX)
-#define G_RX_MACIDX(x) (((x) >> S_RX_MACIDX) & M_RX_MACIDX)
-
-#define S_RXF_SYN 21
-#define V_RXF_SYN(x) ((x) << S_RXF_SYN)
-#define F_RXF_SYN V_RXF_SYN(1U)
-
-#define S_RX_CHAN 28
-#define M_RX_CHAN 0xF
-#define V_RX_CHAN(x) ((x) << S_RX_CHAN)
-#define G_RX_CHAN(x) (((x) >> S_RX_CHAN) & M_RX_CHAN)
+#define RX_ETHHDR_LEN_S 0
+#define RX_ETHHDR_LEN_M 0x1F
+#define RX_ETHHDR_LEN_V(x) ((x) << RX_ETHHDR_LEN_S)
+#define RX_ETHHDR_LEN_G(x) (((x) >> RX_ETHHDR_LEN_S) & RX_ETHHDR_LEN_M)
+
+#define RX_T5_ETHHDR_LEN_S 0
+#define RX_T5_ETHHDR_LEN_M 0x3F
+#define RX_T5_ETHHDR_LEN_V(x) ((x) << RX_T5_ETHHDR_LEN_S)
+#define RX_T5_ETHHDR_LEN_G(x) (((x) >> RX_T5_ETHHDR_LEN_S) & RX_T5_ETHHDR_LEN_M)
+
+#define RX_MACIDX_S 8
+#define RX_MACIDX_M 0x1FF
+#define RX_MACIDX_V(x) ((x) << RX_MACIDX_S)
+#define RX_MACIDX_G(x) (((x) >> RX_MACIDX_S) & RX_MACIDX_M)
+
+#define RXF_SYN_S 21
+#define RXF_SYN_V(x) ((x) << RXF_SYN_S)
+#define RXF_SYN_F RXF_SYN_V(1U)
+
+#define RX_CHAN_S 28
+#define RX_CHAN_M 0xF
+#define RX_CHAN_V(x) ((x) << RX_CHAN_S)
+#define RX_CHAN_G(x) (((x) >> RX_CHAN_S) & RX_CHAN_M)
/* rx_pkt.hdr_len fields */
-#define S_RX_TCPHDR_LEN 0
-#define M_RX_TCPHDR_LEN 0x3F
-#define V_RX_TCPHDR_LEN(x) ((x) << S_RX_TCPHDR_LEN)
-#define G_RX_TCPHDR_LEN(x) (((x) >> S_RX_TCPHDR_LEN) & M_RX_TCPHDR_LEN)
+#define RX_TCPHDR_LEN_S 0
+#define RX_TCPHDR_LEN_M 0x3F
+#define RX_TCPHDR_LEN_V(x) ((x) << RX_TCPHDR_LEN_S)
+#define RX_TCPHDR_LEN_G(x) (((x) >> RX_TCPHDR_LEN_S) & RX_TCPHDR_LEN_M)
-#define S_RX_IPHDR_LEN 6
-#define M_RX_IPHDR_LEN 0x3FF
-#define V_RX_IPHDR_LEN(x) ((x) << S_RX_IPHDR_LEN)
-#define G_RX_IPHDR_LEN(x) (((x) >> S_RX_IPHDR_LEN) & M_RX_IPHDR_LEN)
+#define RX_IPHDR_LEN_S 6
+#define RX_IPHDR_LEN_M 0x3FF
+#define RX_IPHDR_LEN_V(x) ((x) << RX_IPHDR_LEN_S)
+#define RX_IPHDR_LEN_G(x) (((x) >> RX_IPHDR_LEN_S) & RX_IPHDR_LEN_M)
struct cpl_trace_pkt {
u8 opcode;
@@ -730,14 +893,22 @@ struct cpl_l2t_write_req {
WR_HDR;
union opcode_tid ot;
__be16 params;
-#define L2T_W_INFO(x) ((x) << 2)
-#define L2T_W_PORT(x) ((x) << 8)
-#define L2T_W_NOREPLY(x) ((x) << 15)
__be16 l2t_idx;
__be16 vlan;
u8 dst_mac[6];
};
+/* cpl_l2t_write_req.params fields */
+#define L2T_W_INFO_S 2
+#define L2T_W_INFO_V(x) ((x) << L2T_W_INFO_S)
+
+#define L2T_W_PORT_S 8
+#define L2T_W_PORT_V(x) ((x) << L2T_W_PORT_S)
+
+#define L2T_W_NOREPLY_S 15
+#define L2T_W_NOREPLY_V(x) ((x) << L2T_W_NOREPLY_S)
+#define L2T_W_NOREPLY_F L2T_W_NOREPLY_V(1U)
+
struct cpl_l2t_write_rpl {
union opcode_tid ot;
u8 status;
@@ -752,11 +923,15 @@ struct cpl_rdma_terminate {
struct cpl_sge_egr_update {
__be32 opcode_qid;
-#define EGR_QID(x) ((x) & 0x1FFFF)
__be16 cidx;
__be16 pidx;
};
+/* cpl_sge_egr_update.ot fields */
+#define EGR_QID_S 0
+#define EGR_QID_M 0x1FFFF
+#define EGR_QID_G(x) (((x) >> EGR_QID_S) & EGR_QID_M)
+
/* cpl_fw*.type values */
enum {
FW_TYPE_CMD_RPL = 0,
@@ -849,22 +1024,30 @@ struct ulptx_sge_pair {
struct ulptx_sgl {
__be32 cmd_nsge;
-#define ULPTX_NSGE(x) ((x) << 0)
-#define ULPTX_MORE (1U << 23)
__be32 len0;
__be64 addr0;
struct ulptx_sge_pair sge[0];
};
+#define ULPTX_NSGE_S 0
+#define ULPTX_NSGE_V(x) ((x) << ULPTX_NSGE_S)
+
+#define ULPTX_MORE_S 23
+#define ULPTX_MORE_V(x) ((x) << ULPTX_MORE_S)
+#define ULPTX_MORE_F ULPTX_MORE_V(1U)
+
struct ulp_mem_io {
WR_HDR;
__be32 cmd;
__be32 len16; /* command length */
__be32 dlen; /* data length in 32-byte units */
__be32 lock_addr;
-#define ULP_MEMIO_LOCK(x) ((x) << 31)
};
+#define ULP_MEMIO_LOCK_S 31
+#define ULP_MEMIO_LOCK_V(x) ((x) << ULP_MEMIO_LOCK_S)
+#define ULP_MEMIO_LOCK_F ULP_MEMIO_LOCK_V(1U)
+
/* additional ulp_mem_io.cmd fields */
#define ULP_MEMIO_ORDER_S 23
#define ULP_MEMIO_ORDER_V(x) ((x) << ULP_MEMIO_ORDER_S)
@@ -874,13 +1057,9 @@ struct ulp_mem_io {
#define T5_ULP_MEMIO_IMM_V(x) ((x) << T5_ULP_MEMIO_IMM_S)
#define T5_ULP_MEMIO_IMM_F T5_ULP_MEMIO_IMM_V(1U)
-#define S_T5_ULP_MEMIO_IMM 23
-#define V_T5_ULP_MEMIO_IMM(x) ((x) << S_T5_ULP_MEMIO_IMM)
-#define F_T5_ULP_MEMIO_IMM V_T5_ULP_MEMIO_IMM(1U)
-
-#define S_T5_ULP_MEMIO_ORDER 22
-#define V_T5_ULP_MEMIO_ORDER(x) ((x) << S_T5_ULP_MEMIO_ORDER)
-#define F_T5_ULP_MEMIO_ORDER V_T5_ULP_MEMIO_ORDER(1U)
+#define T5_ULP_MEMIO_ORDER_S 22
+#define T5_ULP_MEMIO_ORDER_V(x) ((x) << T5_ULP_MEMIO_ORDER_S)
+#define T5_ULP_MEMIO_ORDER_F T5_ULP_MEMIO_ORDER_V(1U)
/* ulp_mem_io.lock_addr fields */
#define ULP_MEMIO_ADDR_S 0
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
index 9e4f95a91fb4..ddfb5b846045 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_pci_id_tbl.h
@@ -153,6 +153,7 @@ CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN
CH_PCI_ID_TABLE_FENTRY(0x5086), /* Custom 2x T580-CR */
CH_PCI_ID_TABLE_FENTRY(0x5087), /* Custom T580-CR */
CH_PCI_ID_TABLE_FENTRY(0x5088), /* Custom T570-CR */
+ CH_PCI_ID_TABLE_FENTRY(0x5089), /* Custom T520-CR */
CH_PCI_DEVICE_ID_TABLE_DEFINE_END;
#endif /* CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
index d7bd34ee65bd..231a725f6d5d 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_regs.h
@@ -63,460 +63,779 @@
#define MC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
#define EDC_BIST_STATUS_REG(reg_addr, idx) ((reg_addr) + (idx) * 4)
-#define SGE_PF_KDOORBELL 0x0
-#define QID_MASK 0xffff8000U
-#define QID_SHIFT 15
-#define QID(x) ((x) << QID_SHIFT)
-#define DBPRIO(x) ((x) << 14)
-#define DBTYPE(x) ((x) << 13)
-#define PIDX_MASK 0x00003fffU
-#define PIDX_SHIFT 0
-#define PIDX(x) ((x) << PIDX_SHIFT)
-#define PIDX_SHIFT_T5 0
-#define PIDX_T5(x) ((x) << PIDX_SHIFT_T5)
-
-
-#define SGE_TIMERREGS 6
-#define SGE_PF_GTS 0x4
-#define INGRESSQID_MASK 0xffff0000U
-#define INGRESSQID_SHIFT 16
-#define INGRESSQID(x) ((x) << INGRESSQID_SHIFT)
-#define TIMERREG_MASK 0x0000e000U
-#define TIMERREG_SHIFT 13
-#define TIMERREG(x) ((x) << TIMERREG_SHIFT)
-#define SEINTARM_MASK 0x00001000U
-#define SEINTARM_SHIFT 12
-#define SEINTARM(x) ((x) << SEINTARM_SHIFT)
-#define CIDXINC_MASK 0x00000fffU
-#define CIDXINC_SHIFT 0
-#define CIDXINC(x) ((x) << CIDXINC_SHIFT)
-
-#define X_RXPKTCPLMODE_SPLIT 1
-#define X_INGPADBOUNDARY_SHIFT 5
-
-#define SGE_CONTROL 0x1008
-#define SGE_CONTROL2_A 0x1124
-#define DCASYSTYPE 0x00080000U
-#define RXPKTCPLMODE_MASK 0x00040000U
-#define RXPKTCPLMODE_SHIFT 18
-#define RXPKTCPLMODE(x) ((x) << RXPKTCPLMODE_SHIFT)
-#define EGRSTATUSPAGESIZE_MASK 0x00020000U
-#define EGRSTATUSPAGESIZE_SHIFT 17
-#define EGRSTATUSPAGESIZE(x) ((x) << EGRSTATUSPAGESIZE_SHIFT)
-#define PKTSHIFT_MASK 0x00001c00U
-#define PKTSHIFT_SHIFT 10
-#define PKTSHIFT(x) ((x) << PKTSHIFT_SHIFT)
-#define PKTSHIFT_GET(x) (((x) & PKTSHIFT_MASK) >> PKTSHIFT_SHIFT)
-#define INGPCIEBOUNDARY_32B_X 0
-#define INGPCIEBOUNDARY_MASK 0x00000380U
-#define INGPCIEBOUNDARY_SHIFT 7
-#define INGPCIEBOUNDARY(x) ((x) << INGPCIEBOUNDARY_SHIFT)
-#define INGPADBOUNDARY_MASK 0x00000070U
-#define INGPADBOUNDARY_SHIFT 4
-#define INGPADBOUNDARY(x) ((x) << INGPADBOUNDARY_SHIFT)
-#define INGPADBOUNDARY_GET(x) (((x) & INGPADBOUNDARY_MASK) \
- >> INGPADBOUNDARY_SHIFT)
-#define INGPACKBOUNDARY_16B_X 0
-#define INGPACKBOUNDARY_SHIFT_X 5
+#define SGE_PF_KDOORBELL_A 0x0
+
+#define QID_S 15
+#define QID_V(x) ((x) << QID_S)
+
+#define DBPRIO_S 14
+#define DBPRIO_V(x) ((x) << DBPRIO_S)
+#define DBPRIO_F DBPRIO_V(1U)
+
+#define PIDX_S 0
+#define PIDX_V(x) ((x) << PIDX_S)
+
+#define SGE_VF_KDOORBELL_A 0x0
+
+#define DBTYPE_S 13
+#define DBTYPE_V(x) ((x) << DBTYPE_S)
+#define DBTYPE_F DBTYPE_V(1U)
+
+#define PIDX_T5_S 0
+#define PIDX_T5_M 0x1fffU
+#define PIDX_T5_V(x) ((x) << PIDX_T5_S)
+#define PIDX_T5_G(x) (((x) >> PIDX_T5_S) & PIDX_T5_M)
+
+#define SGE_PF_GTS_A 0x4
+
+#define INGRESSQID_S 16
+#define INGRESSQID_V(x) ((x) << INGRESSQID_S)
+
+#define TIMERREG_S 13
+#define TIMERREG_V(x) ((x) << TIMERREG_S)
+
+#define SEINTARM_S 12
+#define SEINTARM_V(x) ((x) << SEINTARM_S)
+
+#define CIDXINC_S 0
+#define CIDXINC_M 0xfffU
+#define CIDXINC_V(x) ((x) << CIDXINC_S)
+
+#define SGE_CONTROL_A 0x1008
+#define SGE_CONTROL2_A 0x1124
+
+#define RXPKTCPLMODE_S 18
+#define RXPKTCPLMODE_V(x) ((x) << RXPKTCPLMODE_S)
+#define RXPKTCPLMODE_F RXPKTCPLMODE_V(1U)
+
+#define EGRSTATUSPAGESIZE_S 17
+#define EGRSTATUSPAGESIZE_V(x) ((x) << EGRSTATUSPAGESIZE_S)
+#define EGRSTATUSPAGESIZE_F EGRSTATUSPAGESIZE_V(1U)
+
+#define PKTSHIFT_S 10
+#define PKTSHIFT_M 0x7U
+#define PKTSHIFT_V(x) ((x) << PKTSHIFT_S)
+#define PKTSHIFT_G(x) (((x) >> PKTSHIFT_S) & PKTSHIFT_M)
+
+#define INGPCIEBOUNDARY_S 7
+#define INGPCIEBOUNDARY_V(x) ((x) << INGPCIEBOUNDARY_S)
+
+#define INGPADBOUNDARY_S 4
+#define INGPADBOUNDARY_M 0x7U
+#define INGPADBOUNDARY_V(x) ((x) << INGPADBOUNDARY_S)
+#define INGPADBOUNDARY_G(x) (((x) >> INGPADBOUNDARY_S) & INGPADBOUNDARY_M)
+
+#define EGRPCIEBOUNDARY_S 1
+#define EGRPCIEBOUNDARY_V(x) ((x) << EGRPCIEBOUNDARY_S)
#define INGPACKBOUNDARY_S 16
#define INGPACKBOUNDARY_M 0x7U
#define INGPACKBOUNDARY_V(x) ((x) << INGPACKBOUNDARY_S)
#define INGPACKBOUNDARY_G(x) (((x) >> INGPACKBOUNDARY_S) \
& INGPACKBOUNDARY_M)
-#define EGRPCIEBOUNDARY_MASK 0x0000000eU
-#define EGRPCIEBOUNDARY_SHIFT 1
-#define EGRPCIEBOUNDARY(x) ((x) << EGRPCIEBOUNDARY_SHIFT)
-#define GLOBALENABLE 0x00000001U
-#define SGE_HOST_PAGE_SIZE 0x100c
+#define GLOBALENABLE_S 0
+#define GLOBALENABLE_V(x) ((x) << GLOBALENABLE_S)
+#define GLOBALENABLE_F GLOBALENABLE_V(1U)
+
+#define SGE_HOST_PAGE_SIZE_A 0x100c
+
+#define HOSTPAGESIZEPF7_S 28
+#define HOSTPAGESIZEPF7_M 0xfU
+#define HOSTPAGESIZEPF7_V(x) ((x) << HOSTPAGESIZEPF7_S)
+#define HOSTPAGESIZEPF7_G(x) (((x) >> HOSTPAGESIZEPF7_S) & HOSTPAGESIZEPF7_M)
+
+#define HOSTPAGESIZEPF6_S 24
+#define HOSTPAGESIZEPF6_M 0xfU
+#define HOSTPAGESIZEPF6_V(x) ((x) << HOSTPAGESIZEPF6_S)
+#define HOSTPAGESIZEPF6_G(x) (((x) >> HOSTPAGESIZEPF6_S) & HOSTPAGESIZEPF6_M)
+
+#define HOSTPAGESIZEPF5_S 20
+#define HOSTPAGESIZEPF5_M 0xfU
+#define HOSTPAGESIZEPF5_V(x) ((x) << HOSTPAGESIZEPF5_S)
+#define HOSTPAGESIZEPF5_G(x) (((x) >> HOSTPAGESIZEPF5_S) & HOSTPAGESIZEPF5_M)
+
+#define HOSTPAGESIZEPF4_S 16
+#define HOSTPAGESIZEPF4_M 0xfU
+#define HOSTPAGESIZEPF4_V(x) ((x) << HOSTPAGESIZEPF4_S)
+#define HOSTPAGESIZEPF4_G(x) (((x) >> HOSTPAGESIZEPF4_S) & HOSTPAGESIZEPF4_M)
+
+#define HOSTPAGESIZEPF3_S 12
+#define HOSTPAGESIZEPF3_M 0xfU
+#define HOSTPAGESIZEPF3_V(x) ((x) << HOSTPAGESIZEPF3_S)
+#define HOSTPAGESIZEPF3_G(x) (((x) >> HOSTPAGESIZEPF3_S) & HOSTPAGESIZEPF3_M)
+
+#define HOSTPAGESIZEPF2_S 8
+#define HOSTPAGESIZEPF2_M 0xfU
+#define HOSTPAGESIZEPF2_V(x) ((x) << HOSTPAGESIZEPF2_S)
+#define HOSTPAGESIZEPF2_G(x) (((x) >> HOSTPAGESIZEPF2_S) & HOSTPAGESIZEPF2_M)
+
+#define HOSTPAGESIZEPF1_S 4
+#define HOSTPAGESIZEPF1_M 0xfU
+#define HOSTPAGESIZEPF1_V(x) ((x) << HOSTPAGESIZEPF1_S)
+#define HOSTPAGESIZEPF1_G(x) (((x) >> HOSTPAGESIZEPF1_S) & HOSTPAGESIZEPF1_M)
+
+#define HOSTPAGESIZEPF0_S 0
+#define HOSTPAGESIZEPF0_M 0xfU
+#define HOSTPAGESIZEPF0_V(x) ((x) << HOSTPAGESIZEPF0_S)
+#define HOSTPAGESIZEPF0_G(x) (((x) >> HOSTPAGESIZEPF0_S) & HOSTPAGESIZEPF0_M)
+
+#define SGE_EGRESS_QUEUES_PER_PAGE_PF_A 0x1010
+#define SGE_EGRESS_QUEUES_PER_PAGE_VF_A 0x1014
-#define HOSTPAGESIZEPF7_MASK 0x0000000fU
-#define HOSTPAGESIZEPF7_SHIFT 28
-#define HOSTPAGESIZEPF7(x) ((x) << HOSTPAGESIZEPF7_SHIFT)
+#define QUEUESPERPAGEPF1_S 4
-#define HOSTPAGESIZEPF6_MASK 0x0000000fU
-#define HOSTPAGESIZEPF6_SHIFT 24
-#define HOSTPAGESIZEPF6(x) ((x) << HOSTPAGESIZEPF6_SHIFT)
+#define QUEUESPERPAGEPF0_S 0
+#define QUEUESPERPAGEPF0_M 0xfU
+#define QUEUESPERPAGEPF0_V(x) ((x) << QUEUESPERPAGEPF0_S)
+#define QUEUESPERPAGEPF0_G(x) (((x) >> QUEUESPERPAGEPF0_S) & QUEUESPERPAGEPF0_M)
-#define HOSTPAGESIZEPF5_MASK 0x0000000fU
-#define HOSTPAGESIZEPF5_SHIFT 20
-#define HOSTPAGESIZEPF5(x) ((x) << HOSTPAGESIZEPF5_SHIFT)
+#define SGE_INT_CAUSE1_A 0x1024
+#define SGE_INT_CAUSE2_A 0x1030
+#define SGE_INT_CAUSE3_A 0x103c
+
+#define ERR_FLM_DBP_S 31
+#define ERR_FLM_DBP_V(x) ((x) << ERR_FLM_DBP_S)
+#define ERR_FLM_DBP_F ERR_FLM_DBP_V(1U)
+
+#define ERR_FLM_IDMA1_S 30
+#define ERR_FLM_IDMA1_V(x) ((x) << ERR_FLM_IDMA1_S)
+#define ERR_FLM_IDMA1_F ERR_FLM_IDMA1_V(1U)
+
+#define ERR_FLM_IDMA0_S 29
+#define ERR_FLM_IDMA0_V(x) ((x) << ERR_FLM_IDMA0_S)
+#define ERR_FLM_IDMA0_F ERR_FLM_IDMA0_V(1U)
+
+#define ERR_FLM_HINT_S 28
+#define ERR_FLM_HINT_V(x) ((x) << ERR_FLM_HINT_S)
+#define ERR_FLM_HINT_F ERR_FLM_HINT_V(1U)
+
+#define ERR_PCIE_ERROR3_S 27
+#define ERR_PCIE_ERROR3_V(x) ((x) << ERR_PCIE_ERROR3_S)
+#define ERR_PCIE_ERROR3_F ERR_PCIE_ERROR3_V(1U)
+
+#define ERR_PCIE_ERROR2_S 26
+#define ERR_PCIE_ERROR2_V(x) ((x) << ERR_PCIE_ERROR2_S)
+#define ERR_PCIE_ERROR2_F ERR_PCIE_ERROR2_V(1U)
+
+#define ERR_PCIE_ERROR1_S 25
+#define ERR_PCIE_ERROR1_V(x) ((x) << ERR_PCIE_ERROR1_S)
+#define ERR_PCIE_ERROR1_F ERR_PCIE_ERROR1_V(1U)
+
+#define ERR_PCIE_ERROR0_S 24
+#define ERR_PCIE_ERROR0_V(x) ((x) << ERR_PCIE_ERROR0_S)
+#define ERR_PCIE_ERROR0_F ERR_PCIE_ERROR0_V(1U)
+
+#define ERR_CPL_EXCEED_IQE_SIZE_S 22
+#define ERR_CPL_EXCEED_IQE_SIZE_V(x) ((x) << ERR_CPL_EXCEED_IQE_SIZE_S)
+#define ERR_CPL_EXCEED_IQE_SIZE_F ERR_CPL_EXCEED_IQE_SIZE_V(1U)
+
+#define ERR_INVALID_CIDX_INC_S 21
+#define ERR_INVALID_CIDX_INC_V(x) ((x) << ERR_INVALID_CIDX_INC_S)
+#define ERR_INVALID_CIDX_INC_F ERR_INVALID_CIDX_INC_V(1U)
+
+#define ERR_CPL_OPCODE_0_S 19
+#define ERR_CPL_OPCODE_0_V(x) ((x) << ERR_CPL_OPCODE_0_S)
+#define ERR_CPL_OPCODE_0_F ERR_CPL_OPCODE_0_V(1U)
+
+#define ERR_DROPPED_DB_S 18
+#define ERR_DROPPED_DB_V(x) ((x) << ERR_DROPPED_DB_S)
+#define ERR_DROPPED_DB_F ERR_DROPPED_DB_V(1U)
+
+#define ERR_DATA_CPL_ON_HIGH_QID1_S 17
+#define ERR_DATA_CPL_ON_HIGH_QID1_V(x) ((x) << ERR_DATA_CPL_ON_HIGH_QID1_S)
+#define ERR_DATA_CPL_ON_HIGH_QID1_F ERR_DATA_CPL_ON_HIGH_QID1_V(1U)
+
+#define ERR_DATA_CPL_ON_HIGH_QID0_S 16
+#define ERR_DATA_CPL_ON_HIGH_QID0_V(x) ((x) << ERR_DATA_CPL_ON_HIGH_QID0_S)
+#define ERR_DATA_CPL_ON_HIGH_QID0_F ERR_DATA_CPL_ON_HIGH_QID0_V(1U)
+
+#define ERR_BAD_DB_PIDX3_S 15
+#define ERR_BAD_DB_PIDX3_V(x) ((x) << ERR_BAD_DB_PIDX3_S)
+#define ERR_BAD_DB_PIDX3_F ERR_BAD_DB_PIDX3_V(1U)
+
+#define ERR_BAD_DB_PIDX2_S 14
+#define ERR_BAD_DB_PIDX2_V(x) ((x) << ERR_BAD_DB_PIDX2_S)
+#define ERR_BAD_DB_PIDX2_F ERR_BAD_DB_PIDX2_V(1U)
+
+#define ERR_BAD_DB_PIDX1_S 13
+#define ERR_BAD_DB_PIDX1_V(x) ((x) << ERR_BAD_DB_PIDX1_S)
+#define ERR_BAD_DB_PIDX1_F ERR_BAD_DB_PIDX1_V(1U)
+
+#define ERR_BAD_DB_PIDX0_S 12
+#define ERR_BAD_DB_PIDX0_V(x) ((x) << ERR_BAD_DB_PIDX0_S)
+#define ERR_BAD_DB_PIDX0_F ERR_BAD_DB_PIDX0_V(1U)
+
+#define ERR_ING_CTXT_PRIO_S 10
+#define ERR_ING_CTXT_PRIO_V(x) ((x) << ERR_ING_CTXT_PRIO_S)
+#define ERR_ING_CTXT_PRIO_F ERR_ING_CTXT_PRIO_V(1U)
+
+#define ERR_EGR_CTXT_PRIO_S 9
+#define ERR_EGR_CTXT_PRIO_V(x) ((x) << ERR_EGR_CTXT_PRIO_S)
+#define ERR_EGR_CTXT_PRIO_F ERR_EGR_CTXT_PRIO_V(1U)
+
+#define DBFIFO_HP_INT_S 8
+#define DBFIFO_HP_INT_V(x) ((x) << DBFIFO_HP_INT_S)
+#define DBFIFO_HP_INT_F DBFIFO_HP_INT_V(1U)
+
+#define DBFIFO_LP_INT_S 7
+#define DBFIFO_LP_INT_V(x) ((x) << DBFIFO_LP_INT_S)
+#define DBFIFO_LP_INT_F DBFIFO_LP_INT_V(1U)
+
+#define INGRESS_SIZE_ERR_S 5
+#define INGRESS_SIZE_ERR_V(x) ((x) << INGRESS_SIZE_ERR_S)
+#define INGRESS_SIZE_ERR_F INGRESS_SIZE_ERR_V(1U)
+
+#define EGRESS_SIZE_ERR_S 4
+#define EGRESS_SIZE_ERR_V(x) ((x) << EGRESS_SIZE_ERR_S)
+#define EGRESS_SIZE_ERR_F EGRESS_SIZE_ERR_V(1U)
+
+#define SGE_INT_ENABLE3_A 0x1040
+#define SGE_FL_BUFFER_SIZE0_A 0x1044
+#define SGE_FL_BUFFER_SIZE1_A 0x1048
+#define SGE_FL_BUFFER_SIZE2_A 0x104c
+#define SGE_FL_BUFFER_SIZE3_A 0x1050
+#define SGE_FL_BUFFER_SIZE4_A 0x1054
+#define SGE_FL_BUFFER_SIZE5_A 0x1058
+#define SGE_FL_BUFFER_SIZE6_A 0x105c
+#define SGE_FL_BUFFER_SIZE7_A 0x1060
+#define SGE_FL_BUFFER_SIZE8_A 0x1064
+
+#define SGE_INGRESS_RX_THRESHOLD_A 0x10a0
+
+#define THRESHOLD_0_S 24
+#define THRESHOLD_0_M 0x3fU
+#define THRESHOLD_0_V(x) ((x) << THRESHOLD_0_S)
+#define THRESHOLD_0_G(x) (((x) >> THRESHOLD_0_S) & THRESHOLD_0_M)
+
+#define THRESHOLD_1_S 16
+#define THRESHOLD_1_M 0x3fU
+#define THRESHOLD_1_V(x) ((x) << THRESHOLD_1_S)
+#define THRESHOLD_1_G(x) (((x) >> THRESHOLD_1_S) & THRESHOLD_1_M)
+
+#define THRESHOLD_2_S 8
+#define THRESHOLD_2_M 0x3fU
+#define THRESHOLD_2_V(x) ((x) << THRESHOLD_2_S)
+#define THRESHOLD_2_G(x) (((x) >> THRESHOLD_2_S) & THRESHOLD_2_M)
+
+#define THRESHOLD_3_S 0
+#define THRESHOLD_3_M 0x3fU
+#define THRESHOLD_3_V(x) ((x) << THRESHOLD_3_S)
+#define THRESHOLD_3_G(x) (((x) >> THRESHOLD_3_S) & THRESHOLD_3_M)
+
+#define SGE_CONM_CTRL_A 0x1094
+
+#define EGRTHRESHOLD_S 8
+#define EGRTHRESHOLD_M 0x3fU
+#define EGRTHRESHOLD_V(x) ((x) << EGRTHRESHOLD_S)
+#define EGRTHRESHOLD_G(x) (((x) >> EGRTHRESHOLD_S) & EGRTHRESHOLD_M)
+
+#define EGRTHRESHOLDPACKING_S 14
+#define EGRTHRESHOLDPACKING_M 0x3fU
+#define EGRTHRESHOLDPACKING_V(x) ((x) << EGRTHRESHOLDPACKING_S)
+#define EGRTHRESHOLDPACKING_G(x) \
+ (((x) >> EGRTHRESHOLDPACKING_S) & EGRTHRESHOLDPACKING_M)
+
+#define SGE_TIMESTAMP_LO_A 0x1098
+#define SGE_TIMESTAMP_HI_A 0x109c
+
+#define TSOP_S 28
+#define TSOP_M 0x3U
+#define TSOP_V(x) ((x) << TSOP_S)
+#define TSOP_G(x) (((x) >> TSOP_S) & TSOP_M)
+
+#define TSVAL_S 0
+#define TSVAL_M 0xfffffffU
+#define TSVAL_V(x) ((x) << TSVAL_S)
+#define TSVAL_G(x) (((x) >> TSVAL_S) & TSVAL_M)
+
+#define SGE_DBFIFO_STATUS_A 0x10a4
+
+#define HP_INT_THRESH_S 28
+#define HP_INT_THRESH_M 0xfU
+#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S)
+
+#define LP_INT_THRESH_S 12
+#define LP_INT_THRESH_M 0xfU
+#define LP_INT_THRESH_V(x) ((x) << LP_INT_THRESH_S)
+
+#define SGE_DOORBELL_CONTROL_A 0x10a8
+
+#define NOCOALESCE_S 26
+#define NOCOALESCE_V(x) ((x) << NOCOALESCE_S)
+#define NOCOALESCE_F NOCOALESCE_V(1U)
+
+#define ENABLE_DROP_S 13
+#define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S)
+#define ENABLE_DROP_F ENABLE_DROP_V(1U)
+
+#define SGE_TIMER_VALUE_0_AND_1_A 0x10b8
+
+#define TIMERVALUE0_S 16
+#define TIMERVALUE0_M 0xffffU
+#define TIMERVALUE0_V(x) ((x) << TIMERVALUE0_S)
+#define TIMERVALUE0_G(x) (((x) >> TIMERVALUE0_S) & TIMERVALUE0_M)
+
+#define TIMERVALUE1_S 0
+#define TIMERVALUE1_M 0xffffU
+#define TIMERVALUE1_V(x) ((x) << TIMERVALUE1_S)
+#define TIMERVALUE1_G(x) (((x) >> TIMERVALUE1_S) & TIMERVALUE1_M)
+
+#define SGE_TIMER_VALUE_2_AND_3_A 0x10bc
+
+#define TIMERVALUE2_S 16
+#define TIMERVALUE2_M 0xffffU
+#define TIMERVALUE2_V(x) ((x) << TIMERVALUE2_S)
+#define TIMERVALUE2_G(x) (((x) >> TIMERVALUE2_S) & TIMERVALUE2_M)
+
+#define TIMERVALUE3_S 0
+#define TIMERVALUE3_M 0xffffU
+#define TIMERVALUE3_V(x) ((x) << TIMERVALUE3_S)
+#define TIMERVALUE3_G(x) (((x) >> TIMERVALUE3_S) & TIMERVALUE3_M)
+
+#define SGE_TIMER_VALUE_4_AND_5_A 0x10c0
+
+#define TIMERVALUE4_S 16
+#define TIMERVALUE4_M 0xffffU
+#define TIMERVALUE4_V(x) ((x) << TIMERVALUE4_S)
+#define TIMERVALUE4_G(x) (((x) >> TIMERVALUE4_S) & TIMERVALUE4_M)
-#define HOSTPAGESIZEPF4_MASK 0x0000000fU
-#define HOSTPAGESIZEPF4_SHIFT 16
-#define HOSTPAGESIZEPF4(x) ((x) << HOSTPAGESIZEPF4_SHIFT)
+#define TIMERVALUE5_S 0
+#define TIMERVALUE5_M 0xffffU
+#define TIMERVALUE5_V(x) ((x) << TIMERVALUE5_S)
+#define TIMERVALUE5_G(x) (((x) >> TIMERVALUE5_S) & TIMERVALUE5_M)
-#define HOSTPAGESIZEPF3_MASK 0x0000000fU
-#define HOSTPAGESIZEPF3_SHIFT 12
-#define HOSTPAGESIZEPF3(x) ((x) << HOSTPAGESIZEPF3_SHIFT)
+#define SGE_DEBUG_INDEX_A 0x10cc
+#define SGE_DEBUG_DATA_HIGH_A 0x10d0
+#define SGE_DEBUG_DATA_LOW_A 0x10d4
-#define HOSTPAGESIZEPF2_MASK 0x0000000fU
-#define HOSTPAGESIZEPF2_SHIFT 8
-#define HOSTPAGESIZEPF2(x) ((x) << HOSTPAGESIZEPF2_SHIFT)
+#define SGE_DEBUG_DATA_LOW_INDEX_2_A 0x12c8
+#define SGE_DEBUG_DATA_LOW_INDEX_3_A 0x12cc
+#define SGE_DEBUG_DATA_HIGH_INDEX_10_A 0x12a8
-#define HOSTPAGESIZEPF1_M 0x0000000fU
-#define HOSTPAGESIZEPF1_S 4
-#define HOSTPAGESIZEPF1(x) ((x) << HOSTPAGESIZEPF1_S)
+#define SGE_INGRESS_QUEUES_PER_PAGE_PF_A 0x10f4
+#define SGE_INGRESS_QUEUES_PER_PAGE_VF_A 0x10f8
-#define HOSTPAGESIZEPF0_M 0x0000000fU
-#define HOSTPAGESIZEPF0_S 0
-#define HOSTPAGESIZEPF0(x) ((x) << HOSTPAGESIZEPF0_S)
+#define HP_INT_THRESH_S 28
+#define HP_INT_THRESH_M 0xfU
+#define HP_INT_THRESH_V(x) ((x) << HP_INT_THRESH_S)
-#define SGE_EGRESS_QUEUES_PER_PAGE_PF 0x1010
-#define SGE_EGRESS_QUEUES_PER_PAGE_VF_A 0x1014
+#define HP_COUNT_S 16
+#define HP_COUNT_M 0x7ffU
+#define HP_COUNT_G(x) (((x) >> HP_COUNT_S) & HP_COUNT_M)
-#define QUEUESPERPAGEPF1_S 4
+#define LP_INT_THRESH_S 12
+#define LP_INT_THRESH_M 0xfU
+#define LP_INT_THRESH_V(x) ((x) << LP_INT_THRESH_S)
-#define QUEUESPERPAGEPF0_S 0
-#define QUEUESPERPAGEPF0_MASK 0x0000000fU
-#define QUEUESPERPAGEPF0_GET(x) ((x) & QUEUESPERPAGEPF0_MASK)
+#define LP_COUNT_S 0
+#define LP_COUNT_M 0x7ffU
+#define LP_COUNT_G(x) (((x) >> LP_COUNT_S) & LP_COUNT_M)
-#define QUEUESPERPAGEPF0 0
-#define QUEUESPERPAGEPF1 4
+#define LP_INT_THRESH_T5_S 18
+#define LP_INT_THRESH_T5_M 0xfffU
+#define LP_INT_THRESH_T5_V(x) ((x) << LP_INT_THRESH_T5_S)
-/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues.
- * The User Doorbells are each 128 bytes in length with a Simple Doorbell at
- * offsets 8x and a Write Combining single 64-byte Egress Queue Unit
- * (X_IDXSIZE_UNIT) Gather Buffer interface at offset 64. For Ingress Queues,
- * we have a Going To Sleep register at offsets 8x+4.
- *
- * As noted above, we have many instances of the Simple Doorbell and Going To
- * Sleep registers at offsets 8x and 8x+4, respectively. We want to use a
- * non-64-byte aligned offset for the Simple Doorbell in order to attempt to
- * avoid buffering of the writes to the Simple Doorbell and we want to use a
- * non-contiguous offset for the Going To Sleep writes in order to avoid
- * possible combining between them.
- */
-#define SGE_UDB_SIZE 128
-#define SGE_UDB_KDOORBELL 8
-#define SGE_UDB_GTS 20
-#define SGE_UDB_WCDOORBELL 64
-
-#define SGE_INT_CAUSE1 0x1024
-#define SGE_INT_CAUSE2 0x1030
-#define SGE_INT_CAUSE3 0x103c
-#define ERR_FLM_DBP 0x80000000U
-#define ERR_FLM_IDMA1 0x40000000U
-#define ERR_FLM_IDMA0 0x20000000U
-#define ERR_FLM_HINT 0x10000000U
-#define ERR_PCIE_ERROR3 0x08000000U
-#define ERR_PCIE_ERROR2 0x04000000U
-#define ERR_PCIE_ERROR1 0x02000000U
-#define ERR_PCIE_ERROR0 0x01000000U
-#define ERR_TIMER_ABOVE_MAX_QID 0x00800000U
-#define ERR_CPL_EXCEED_IQE_SIZE 0x00400000U
-#define ERR_INVALID_CIDX_INC 0x00200000U
-#define ERR_ITP_TIME_PAUSED 0x00100000U
-#define ERR_CPL_OPCODE_0 0x00080000U
-#define ERR_DROPPED_DB 0x00040000U
-#define ERR_DATA_CPL_ON_HIGH_QID1 0x00020000U
-#define ERR_DATA_CPL_ON_HIGH_QID0 0x00010000U
-#define ERR_BAD_DB_PIDX3 0x00008000U
-#define ERR_BAD_DB_PIDX2 0x00004000U
-#define ERR_BAD_DB_PIDX1 0x00002000U
-#define ERR_BAD_DB_PIDX0 0x00001000U
-#define ERR_ING_PCIE_CHAN 0x00000800U
-#define ERR_ING_CTXT_PRIO 0x00000400U
-#define ERR_EGR_CTXT_PRIO 0x00000200U
-#define DBFIFO_HP_INT 0x00000100U
-#define DBFIFO_LP_INT 0x00000080U
-#define REG_ADDRESS_ERR 0x00000040U
-#define INGRESS_SIZE_ERR 0x00000020U
-#define EGRESS_SIZE_ERR 0x00000010U
-#define ERR_INV_CTXT3 0x00000008U
-#define ERR_INV_CTXT2 0x00000004U
-#define ERR_INV_CTXT1 0x00000002U
-#define ERR_INV_CTXT0 0x00000001U
-
-#define SGE_INT_ENABLE3 0x1040
-#define SGE_FL_BUFFER_SIZE0 0x1044
-#define SGE_FL_BUFFER_SIZE1 0x1048
-#define SGE_FL_BUFFER_SIZE2 0x104c
-#define SGE_FL_BUFFER_SIZE3 0x1050
-#define SGE_FL_BUFFER_SIZE4 0x1054
-#define SGE_FL_BUFFER_SIZE5 0x1058
-#define SGE_FL_BUFFER_SIZE6 0x105c
-#define SGE_FL_BUFFER_SIZE7 0x1060
-#define SGE_FL_BUFFER_SIZE8 0x1064
-
-#define SGE_INGRESS_RX_THRESHOLD 0x10a0
-#define THRESHOLD_0_MASK 0x3f000000U
-#define THRESHOLD_0_SHIFT 24
-#define THRESHOLD_0(x) ((x) << THRESHOLD_0_SHIFT)
-#define THRESHOLD_0_GET(x) (((x) & THRESHOLD_0_MASK) >> THRESHOLD_0_SHIFT)
-#define THRESHOLD_1_MASK 0x003f0000U
-#define THRESHOLD_1_SHIFT 16
-#define THRESHOLD_1(x) ((x) << THRESHOLD_1_SHIFT)
-#define THRESHOLD_1_GET(x) (((x) & THRESHOLD_1_MASK) >> THRESHOLD_1_SHIFT)
-#define THRESHOLD_2_MASK 0x00003f00U
-#define THRESHOLD_2_SHIFT 8
-#define THRESHOLD_2(x) ((x) << THRESHOLD_2_SHIFT)
-#define THRESHOLD_2_GET(x) (((x) & THRESHOLD_2_MASK) >> THRESHOLD_2_SHIFT)
-#define THRESHOLD_3_MASK 0x0000003fU
-#define THRESHOLD_3_SHIFT 0
-#define THRESHOLD_3(x) ((x) << THRESHOLD_3_SHIFT)
-#define THRESHOLD_3_GET(x) (((x) & THRESHOLD_3_MASK) >> THRESHOLD_3_SHIFT)
-
-#define SGE_CONM_CTRL 0x1094
-#define EGRTHRESHOLD_MASK 0x00003f00U
-#define EGRTHRESHOLDshift 8
-#define EGRTHRESHOLD(x) ((x) << EGRTHRESHOLDshift)
-#define EGRTHRESHOLD_GET(x) (((x) & EGRTHRESHOLD_MASK) >> EGRTHRESHOLDshift)
-
-#define EGRTHRESHOLDPACKING_MASK 0x3fU
-#define EGRTHRESHOLDPACKING_SHIFT 14
-#define EGRTHRESHOLDPACKING(x) ((x) << EGRTHRESHOLDPACKING_SHIFT)
-#define EGRTHRESHOLDPACKING_GET(x) (((x) >> EGRTHRESHOLDPACKING_SHIFT) & \
- EGRTHRESHOLDPACKING_MASK)
-
-#define SGE_DBFIFO_STATUS 0x10a4
-#define HP_INT_THRESH_SHIFT 28
-#define HP_INT_THRESH_MASK 0xfU
-#define HP_INT_THRESH(x) ((x) << HP_INT_THRESH_SHIFT)
-#define LP_INT_THRESH_SHIFT 12
-#define LP_INT_THRESH_MASK 0xfU
-#define LP_INT_THRESH(x) ((x) << LP_INT_THRESH_SHIFT)
-
-#define SGE_DOORBELL_CONTROL 0x10a8
-#define ENABLE_DROP (1 << 13)
-
-#define S_NOCOALESCE 26
-#define V_NOCOALESCE(x) ((x) << S_NOCOALESCE)
-#define F_NOCOALESCE V_NOCOALESCE(1U)
-
-#define SGE_TIMESTAMP_LO 0x1098
-#define SGE_TIMESTAMP_HI 0x109c
-#define S_TSVAL 0
-#define M_TSVAL 0xfffffffU
-#define GET_TSVAL(x) (((x) >> S_TSVAL) & M_TSVAL)
-
-#define SGE_TIMER_VALUE_0_AND_1 0x10b8
-#define TIMERVALUE0_MASK 0xffff0000U
-#define TIMERVALUE0_SHIFT 16
-#define TIMERVALUE0(x) ((x) << TIMERVALUE0_SHIFT)
-#define TIMERVALUE0_GET(x) (((x) & TIMERVALUE0_MASK) >> TIMERVALUE0_SHIFT)
-#define TIMERVALUE1_MASK 0x0000ffffU
-#define TIMERVALUE1_SHIFT 0
-#define TIMERVALUE1(x) ((x) << TIMERVALUE1_SHIFT)
-#define TIMERVALUE1_GET(x) (((x) & TIMERVALUE1_MASK) >> TIMERVALUE1_SHIFT)
-
-#define SGE_TIMER_VALUE_2_AND_3 0x10bc
-#define TIMERVALUE2_MASK 0xffff0000U
-#define TIMERVALUE2_SHIFT 16
-#define TIMERVALUE2(x) ((x) << TIMERVALUE2_SHIFT)
-#define TIMERVALUE2_GET(x) (((x) & TIMERVALUE2_MASK) >> TIMERVALUE2_SHIFT)
-#define TIMERVALUE3_MASK 0x0000ffffU
-#define TIMERVALUE3_SHIFT 0
-#define TIMERVALUE3(x) ((x) << TIMERVALUE3_SHIFT)
-#define TIMERVALUE3_GET(x) (((x) & TIMERVALUE3_MASK) >> TIMERVALUE3_SHIFT)
-
-#define SGE_TIMER_VALUE_4_AND_5 0x10c0
-#define TIMERVALUE4_MASK 0xffff0000U
-#define TIMERVALUE4_SHIFT 16
-#define TIMERVALUE4(x) ((x) << TIMERVALUE4_SHIFT)
-#define TIMERVALUE4_GET(x) (((x) & TIMERVALUE4_MASK) >> TIMERVALUE4_SHIFT)
-#define TIMERVALUE5_MASK 0x0000ffffU
-#define TIMERVALUE5_SHIFT 0
-#define TIMERVALUE5(x) ((x) << TIMERVALUE5_SHIFT)
-#define TIMERVALUE5_GET(x) (((x) & TIMERVALUE5_MASK) >> TIMERVALUE5_SHIFT)
-
-#define SGE_DEBUG_INDEX 0x10cc
-#define SGE_DEBUG_DATA_HIGH 0x10d0
-#define SGE_DEBUG_DATA_LOW 0x10d4
-#define SGE_DEBUG_DATA_LOW_INDEX_2 0x12c8
-#define SGE_DEBUG_DATA_LOW_INDEX_3 0x12cc
-#define SGE_DEBUG_DATA_HIGH_INDEX_10 0x12a8
-#define SGE_INGRESS_QUEUES_PER_PAGE_PF 0x10f4
-#define SGE_INGRESS_QUEUES_PER_PAGE_VF_A 0x10f8
+#define LP_COUNT_T5_S 0
+#define LP_COUNT_T5_M 0x3ffffU
+#define LP_COUNT_T5_G(x) (((x) >> LP_COUNT_T5_S) & LP_COUNT_T5_M)
+
+#define SGE_DOORBELL_CONTROL_A 0x10a8
+
+#define SGE_STAT_TOTAL_A 0x10e4
+#define SGE_STAT_MATCH_A 0x10e8
+#define SGE_STAT_CFG_A 0x10ec
+
+#define STATSOURCE_T5_S 9
+#define STATSOURCE_T5_V(x) ((x) << STATSOURCE_T5_S)
+
+#define SGE_DBFIFO_STATUS2_A 0x1118
+
+#define HP_INT_THRESH_T5_S 10
+#define HP_INT_THRESH_T5_M 0xfU
+#define HP_INT_THRESH_T5_V(x) ((x) << HP_INT_THRESH_T5_S)
+
+#define HP_COUNT_T5_S 0
+#define HP_COUNT_T5_M 0x3ffU
+#define HP_COUNT_T5_G(x) (((x) >> HP_COUNT_T5_S) & HP_COUNT_T5_M)
+
+#define ENABLE_DROP_S 13
+#define ENABLE_DROP_V(x) ((x) << ENABLE_DROP_S)
+#define ENABLE_DROP_F ENABLE_DROP_V(1U)
+
+#define DROPPED_DB_S 0
+#define DROPPED_DB_V(x) ((x) << DROPPED_DB_S)
+#define DROPPED_DB_F DROPPED_DB_V(1U)
+
+#define SGE_CTXT_CMD_A 0x11fc
+#define SGE_DBQ_CTXT_BADDR_A 0x1084
+
+/* registers for module PCIE */
+#define PCIE_PF_CFG_A 0x40
+
+#define AIVEC_S 4
+#define AIVEC_M 0x3ffU
+#define AIVEC_V(x) ((x) << AIVEC_S)
+
+#define PCIE_PF_CLI_A 0x44
+#define PCIE_INT_CAUSE_A 0x3004
+
+#define UNXSPLCPLERR_S 29
+#define UNXSPLCPLERR_V(x) ((x) << UNXSPLCPLERR_S)
+#define UNXSPLCPLERR_F UNXSPLCPLERR_V(1U)
+
+#define PCIEPINT_S 28
+#define PCIEPINT_V(x) ((x) << PCIEPINT_S)
+#define PCIEPINT_F PCIEPINT_V(1U)
+
+#define PCIESINT_S 27
+#define PCIESINT_V(x) ((x) << PCIESINT_S)
+#define PCIESINT_F PCIESINT_V(1U)
+
+#define RPLPERR_S 26
+#define RPLPERR_V(x) ((x) << RPLPERR_S)
+#define RPLPERR_F RPLPERR_V(1U)
+
+#define RXWRPERR_S 25
+#define RXWRPERR_V(x) ((x) << RXWRPERR_S)
+#define RXWRPERR_F RXWRPERR_V(1U)
+
+#define RXCPLPERR_S 24
+#define RXCPLPERR_V(x) ((x) << RXCPLPERR_S)
+#define RXCPLPERR_F RXCPLPERR_V(1U)
+
+#define PIOTAGPERR_S 23
+#define PIOTAGPERR_V(x) ((x) << PIOTAGPERR_S)
+#define PIOTAGPERR_F PIOTAGPERR_V(1U)
+
+#define MATAGPERR_S 22
+#define MATAGPERR_V(x) ((x) << MATAGPERR_S)
+#define MATAGPERR_F MATAGPERR_V(1U)
+
+#define INTXCLRPERR_S 21
+#define INTXCLRPERR_V(x) ((x) << INTXCLRPERR_S)
+#define INTXCLRPERR_F INTXCLRPERR_V(1U)
+
+#define FIDPERR_S 20
+#define FIDPERR_V(x) ((x) << FIDPERR_S)
+#define FIDPERR_F FIDPERR_V(1U)
+
+#define CFGSNPPERR_S 19
+#define CFGSNPPERR_V(x) ((x) << CFGSNPPERR_S)
+#define CFGSNPPERR_F CFGSNPPERR_V(1U)
+
+#define HRSPPERR_S 18
+#define HRSPPERR_V(x) ((x) << HRSPPERR_S)
+#define HRSPPERR_F HRSPPERR_V(1U)
+
+#define HREQPERR_S 17
+#define HREQPERR_V(x) ((x) << HREQPERR_S)
+#define HREQPERR_F HREQPERR_V(1U)
+
+#define HCNTPERR_S 16
+#define HCNTPERR_V(x) ((x) << HCNTPERR_S)
+#define HCNTPERR_F HCNTPERR_V(1U)
+
+#define DRSPPERR_S 15
+#define DRSPPERR_V(x) ((x) << DRSPPERR_S)
+#define DRSPPERR_F DRSPPERR_V(1U)
+
+#define DREQPERR_S 14
+#define DREQPERR_V(x) ((x) << DREQPERR_S)
+#define DREQPERR_F DREQPERR_V(1U)
+
+#define DCNTPERR_S 13
+#define DCNTPERR_V(x) ((x) << DCNTPERR_S)
+#define DCNTPERR_F DCNTPERR_V(1U)
+
+#define CRSPPERR_S 12
+#define CRSPPERR_V(x) ((x) << CRSPPERR_S)
+#define CRSPPERR_F CRSPPERR_V(1U)
+
+#define CREQPERR_S 11
+#define CREQPERR_V(x) ((x) << CREQPERR_S)
+#define CREQPERR_F CREQPERR_V(1U)
+
+#define CCNTPERR_S 10
+#define CCNTPERR_V(x) ((x) << CCNTPERR_S)
+#define CCNTPERR_F CCNTPERR_V(1U)
+
+#define TARTAGPERR_S 9
+#define TARTAGPERR_V(x) ((x) << TARTAGPERR_S)
+#define TARTAGPERR_F TARTAGPERR_V(1U)
+
+#define PIOREQPERR_S 8
+#define PIOREQPERR_V(x) ((x) << PIOREQPERR_S)
+#define PIOREQPERR_F PIOREQPERR_V(1U)
+
+#define PIOCPLPERR_S 7
+#define PIOCPLPERR_V(x) ((x) << PIOCPLPERR_S)
+#define PIOCPLPERR_F PIOCPLPERR_V(1U)
+
+#define MSIXDIPERR_S 6
+#define MSIXDIPERR_V(x) ((x) << MSIXDIPERR_S)
+#define MSIXDIPERR_F MSIXDIPERR_V(1U)
+
+#define MSIXDATAPERR_S 5
+#define MSIXDATAPERR_V(x) ((x) << MSIXDATAPERR_S)
+#define MSIXDATAPERR_F MSIXDATAPERR_V(1U)
+
+#define MSIXADDRHPERR_S 4
+#define MSIXADDRHPERR_V(x) ((x) << MSIXADDRHPERR_S)
+#define MSIXADDRHPERR_F MSIXADDRHPERR_V(1U)
+
+#define MSIXADDRLPERR_S 3
+#define MSIXADDRLPERR_V(x) ((x) << MSIXADDRLPERR_S)
+#define MSIXADDRLPERR_F MSIXADDRLPERR_V(1U)
+
+#define MSIDATAPERR_S 2
+#define MSIDATAPERR_V(x) ((x) << MSIDATAPERR_S)
+#define MSIDATAPERR_F MSIDATAPERR_V(1U)
+
+#define MSIADDRHPERR_S 1
+#define MSIADDRHPERR_V(x) ((x) << MSIADDRHPERR_S)
+#define MSIADDRHPERR_F MSIADDRHPERR_V(1U)
+
+#define MSIADDRLPERR_S 0
+#define MSIADDRLPERR_V(x) ((x) << MSIADDRLPERR_S)
+#define MSIADDRLPERR_F MSIADDRLPERR_V(1U)
+
+#define READRSPERR_S 29
+#define READRSPERR_V(x) ((x) << READRSPERR_S)
+#define READRSPERR_F READRSPERR_V(1U)
+
+#define TRGT1GRPPERR_S 28
+#define TRGT1GRPPERR_V(x) ((x) << TRGT1GRPPERR_S)
+#define TRGT1GRPPERR_F TRGT1GRPPERR_V(1U)
+
+#define IPSOTPERR_S 27
+#define IPSOTPERR_V(x) ((x) << IPSOTPERR_S)
+#define IPSOTPERR_F IPSOTPERR_V(1U)
+
+#define IPRETRYPERR_S 26
+#define IPRETRYPERR_V(x) ((x) << IPRETRYPERR_S)
+#define IPRETRYPERR_F IPRETRYPERR_V(1U)
+
+#define IPRXDATAGRPPERR_S 25
+#define IPRXDATAGRPPERR_V(x) ((x) << IPRXDATAGRPPERR_S)
+#define IPRXDATAGRPPERR_F IPRXDATAGRPPERR_V(1U)
+
+#define IPRXHDRGRPPERR_S 24
+#define IPRXHDRGRPPERR_V(x) ((x) << IPRXHDRGRPPERR_S)
+#define IPRXHDRGRPPERR_F IPRXHDRGRPPERR_V(1U)
+
+#define MAGRPPERR_S 22
+#define MAGRPPERR_V(x) ((x) << MAGRPPERR_S)
+#define MAGRPPERR_F MAGRPPERR_V(1U)
+
+#define VFIDPERR_S 21
+#define VFIDPERR_V(x) ((x) << VFIDPERR_S)
+#define VFIDPERR_F VFIDPERR_V(1U)
+
+#define HREQWRPERR_S 16
+#define HREQWRPERR_V(x) ((x) << HREQWRPERR_S)
+#define HREQWRPERR_F HREQWRPERR_V(1U)
+
+#define DREQWRPERR_S 13
+#define DREQWRPERR_V(x) ((x) << DREQWRPERR_S)
+#define DREQWRPERR_F DREQWRPERR_V(1U)
+
+#define CREQRDPERR_S 11
+#define CREQRDPERR_V(x) ((x) << CREQRDPERR_S)
+#define CREQRDPERR_F CREQRDPERR_V(1U)
+
+#define MSTTAGQPERR_S 10
+#define MSTTAGQPERR_V(x) ((x) << MSTTAGQPERR_S)
+#define MSTTAGQPERR_F MSTTAGQPERR_V(1U)
+
+#define PIOREQGRPPERR_S 8
+#define PIOREQGRPPERR_V(x) ((x) << PIOREQGRPPERR_S)
+#define PIOREQGRPPERR_F PIOREQGRPPERR_V(1U)
+
+#define PIOCPLGRPPERR_S 7
+#define PIOCPLGRPPERR_V(x) ((x) << PIOCPLGRPPERR_S)
+#define PIOCPLGRPPERR_F PIOCPLGRPPERR_V(1U)
+
+#define MSIXSTIPERR_S 2
+#define MSIXSTIPERR_V(x) ((x) << MSIXSTIPERR_S)
+#define MSIXSTIPERR_F MSIXSTIPERR_V(1U)
+
+#define MSTTIMEOUTPERR_S 1
+#define MSTTIMEOUTPERR_V(x) ((x) << MSTTIMEOUTPERR_S)
+#define MSTTIMEOUTPERR_F MSTTIMEOUTPERR_V(1U)
+
+#define MSTGRPPERR_S 0
+#define MSTGRPPERR_V(x) ((x) << MSTGRPPERR_S)
+#define MSTGRPPERR_F MSTGRPPERR_V(1U)
+
+#define PCIE_NONFAT_ERR_A 0x3010
+#define PCIE_CFG_SPACE_REQ_A 0x3060
+#define PCIE_CFG_SPACE_DATA_A 0x3064
+#define PCIE_MEM_ACCESS_BASE_WIN_A 0x3068
+
+#define PCIEOFST_S 10
+#define PCIEOFST_M 0x3fffffU
+#define PCIEOFST_G(x) (((x) >> PCIEOFST_S) & PCIEOFST_M)
+
+#define BIR_S 8
+#define BIR_M 0x3U
+#define BIR_V(x) ((x) << BIR_S)
+#define BIR_G(x) (((x) >> BIR_S) & BIR_M)
+
+#define WINDOW_S 0
+#define WINDOW_M 0xffU
+#define WINDOW_V(x) ((x) << WINDOW_S)
+#define WINDOW_G(x) (((x) >> WINDOW_S) & WINDOW_M)
+
+#define PCIE_MEM_ACCESS_OFFSET_A 0x306c
+
+#define ENABLE_S 30
+#define ENABLE_V(x) ((x) << ENABLE_S)
+#define ENABLE_F ENABLE_V(1U)
+
+#define LOCALCFG_S 28
+#define LOCALCFG_V(x) ((x) << LOCALCFG_S)
+#define LOCALCFG_F LOCALCFG_V(1U)
+
+#define FUNCTION_S 12
+#define FUNCTION_V(x) ((x) << FUNCTION_S)
+
+#define REGISTER_S 0
+#define REGISTER_V(x) ((x) << REGISTER_S)
+
+#define PFNUM_S 0
+#define PFNUM_V(x) ((x) << PFNUM_S)
+
+#define PCIE_FW_A 0x30b8
+
+#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A 0x5908
+
+#define RNPP_S 31
+#define RNPP_V(x) ((x) << RNPP_S)
+#define RNPP_F RNPP_V(1U)
+
+#define RPCP_S 29
+#define RPCP_V(x) ((x) << RPCP_S)
+#define RPCP_F RPCP_V(1U)
+
+#define RCIP_S 27
+#define RCIP_V(x) ((x) << RCIP_S)
+#define RCIP_F RCIP_V(1U)
+
+#define RCCP_S 26
+#define RCCP_V(x) ((x) << RCCP_S)
+#define RCCP_F RCCP_V(1U)
+
+#define RFTP_S 23
+#define RFTP_V(x) ((x) << RFTP_S)
+#define RFTP_F RFTP_V(1U)
+
+#define PTRP_S 20
+#define PTRP_V(x) ((x) << PTRP_S)
+#define PTRP_F PTRP_V(1U)
-#define S_HP_INT_THRESH 28
-#define M_HP_INT_THRESH 0xfU
-#define V_HP_INT_THRESH(x) ((x) << S_HP_INT_THRESH)
-#define S_LP_INT_THRESH_T5 18
-#define V_LP_INT_THRESH_T5(x) ((x) << S_LP_INT_THRESH_T5)
-#define M_LP_COUNT_T5 0x3ffffU
-#define G_LP_COUNT_T5(x) (((x) >> S_LP_COUNT) & M_LP_COUNT_T5)
-#define M_HP_COUNT 0x7ffU
-#define S_HP_COUNT 16
-#define G_HP_COUNT(x) (((x) >> S_HP_COUNT) & M_HP_COUNT)
-#define S_LP_INT_THRESH 12
-#define M_LP_INT_THRESH 0xfU
-#define M_LP_INT_THRESH_T5 0xfffU
-#define V_LP_INT_THRESH(x) ((x) << S_LP_INT_THRESH)
-#define M_LP_COUNT 0x7ffU
-#define S_LP_COUNT 0
-#define G_LP_COUNT(x) (((x) >> S_LP_COUNT) & M_LP_COUNT)
-#define A_SGE_DBFIFO_STATUS 0x10a4
-
-#define SGE_STAT_TOTAL 0x10e4
-#define SGE_STAT_MATCH 0x10e8
-
-#define SGE_STAT_CFG 0x10ec
-#define S_STATSOURCE_T5 9
-#define STATSOURCE_T5(x) ((x) << S_STATSOURCE_T5)
-
-#define SGE_DBFIFO_STATUS2 0x1118
-#define M_HP_COUNT_T5 0x3ffU
-#define G_HP_COUNT_T5(x) ((x) & M_HP_COUNT_T5)
-#define S_HP_INT_THRESH_T5 10
-#define M_HP_INT_THRESH_T5 0xfU
-#define V_HP_INT_THRESH_T5(x) ((x) << S_HP_INT_THRESH_T5)
-
-#define S_ENABLE_DROP 13
-#define V_ENABLE_DROP(x) ((x) << S_ENABLE_DROP)
-#define F_ENABLE_DROP V_ENABLE_DROP(1U)
-#define S_DROPPED_DB 0
-#define V_DROPPED_DB(x) ((x) << S_DROPPED_DB)
-#define F_DROPPED_DB V_DROPPED_DB(1U)
-#define A_SGE_DOORBELL_CONTROL 0x10a8
-
-#define A_SGE_CTXT_CMD 0x11fc
-#define A_SGE_DBQ_CTXT_BADDR 0x1084
-
-#define PCIE_PF_CFG 0x40
-#define AIVEC(x) ((x) << 4)
-#define AIVEC_MASK 0x3ffU
-
-#define PCIE_PF_CLI 0x44
-#define PCIE_INT_CAUSE 0x3004
-#define UNXSPLCPLERR 0x20000000U
-#define PCIEPINT 0x10000000U
-#define PCIESINT 0x08000000U
-#define RPLPERR 0x04000000U
-#define RXWRPERR 0x02000000U
-#define RXCPLPERR 0x01000000U
-#define PIOTAGPERR 0x00800000U
-#define MATAGPERR 0x00400000U
-#define INTXCLRPERR 0x00200000U
-#define FIDPERR 0x00100000U
-#define CFGSNPPERR 0x00080000U
-#define HRSPPERR 0x00040000U
-#define HREQPERR 0x00020000U
-#define HCNTPERR 0x00010000U
-#define DRSPPERR 0x00008000U
-#define DREQPERR 0x00004000U
-#define DCNTPERR 0x00002000U
-#define CRSPPERR 0x00001000U
-#define CREQPERR 0x00000800U
-#define CCNTPERR 0x00000400U
-#define TARTAGPERR 0x00000200U
-#define PIOREQPERR 0x00000100U
-#define PIOCPLPERR 0x00000080U
-#define MSIXDIPERR 0x00000040U
-#define MSIXDATAPERR 0x00000020U
-#define MSIXADDRHPERR 0x00000010U
-#define MSIXADDRLPERR 0x00000008U
-#define MSIDATAPERR 0x00000004U
-#define MSIADDRHPERR 0x00000002U
-#define MSIADDRLPERR 0x00000001U
-
-#define READRSPERR 0x20000000U
-#define TRGT1GRPPERR 0x10000000U
-#define IPSOTPERR 0x08000000U
-#define IPRXDATAGRPPERR 0x02000000U
-#define IPRXHDRGRPPERR 0x01000000U
-#define MAGRPPERR 0x00400000U
-#define VFIDPERR 0x00200000U
-#define HREQWRPERR 0x00010000U
-#define DREQWRPERR 0x00002000U
-#define MSTTAGQPERR 0x00000400U
-#define PIOREQGRPPERR 0x00000100U
-#define PIOCPLGRPPERR 0x00000080U
-#define MSIXSTIPERR 0x00000004U
-#define MSTTIMEOUTPERR 0x00000002U
-#define MSTGRPPERR 0x00000001U
-
-#define PCIE_NONFAT_ERR 0x3010
-#define PCIE_CFG_SPACE_REQ 0x3060
-#define PCIE_CFG_SPACE_DATA 0x3064
-#define PCIE_MEM_ACCESS_BASE_WIN 0x3068
-#define S_PCIEOFST 10
-#define M_PCIEOFST 0x3fffffU
-#define GET_PCIEOFST(x) (((x) >> S_PCIEOFST) & M_PCIEOFST)
-#define PCIEOFST_MASK 0xfffffc00U
-#define BIR_MASK 0x00000300U
-#define BIR_SHIFT 8
-#define BIR(x) ((x) << BIR_SHIFT)
-#define WINDOW_MASK 0x000000ffU
-#define WINDOW_SHIFT 0
-#define WINDOW(x) ((x) << WINDOW_SHIFT)
-#define GET_WINDOW(x) (((x) >> WINDOW_SHIFT) & WINDOW_MASK)
-#define PCIE_MEM_ACCESS_OFFSET 0x306c
-#define ENABLE (1U << 30)
-#define FUNCTION(x) ((x) << 12)
-#define F_LOCALCFG (1U << 28)
-
-#define S_PFNUM 0
-#define V_PFNUM(x) ((x) << S_PFNUM)
-
-#define PCIE_FW 0x30b8
-#define PCIE_FW_ERR 0x80000000U
-#define PCIE_FW_INIT 0x40000000U
-#define PCIE_FW_HALT 0x20000000U
-#define PCIE_FW_MASTER_VLD 0x00008000U
-#define PCIE_FW_MASTER(x) ((x) << 12)
-#define PCIE_FW_MASTER_MASK 0x7
-#define PCIE_FW_MASTER_GET(x) (((x) >> 12) & PCIE_FW_MASTER_MASK)
-
-#define PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS 0x5908
-#define RNPP 0x80000000U
-#define RPCP 0x20000000U
-#define RCIP 0x08000000U
-#define RCCP 0x04000000U
-#define RFTP 0x00800000U
-#define PTRP 0x00100000U
-
-#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS 0x59a4
-#define TPCP 0x40000000U
-#define TNPP 0x20000000U
-#define TFTP 0x10000000U
-#define TCAP 0x08000000U
-#define TCIP 0x04000000U
-#define RCAP 0x02000000U
-#define PLUP 0x00800000U
-#define PLDN 0x00400000U
-#define OTDD 0x00200000U
-#define GTRP 0x00100000U
-#define RDPE 0x00040000U
-#define TDCE 0x00020000U
-#define TDUE 0x00010000U
-
-#define MC_INT_CAUSE 0x7518
-#define MC_P_INT_CAUSE 0x41318
-#define ECC_UE_INT_CAUSE 0x00000004U
-#define ECC_CE_INT_CAUSE 0x00000002U
-#define PERR_INT_CAUSE 0x00000001U
-
-#define MC_ECC_STATUS 0x751c
-#define MC_P_ECC_STATUS 0x4131c
-#define ECC_CECNT_MASK 0xffff0000U
-#define ECC_CECNT_SHIFT 16
-#define ECC_CECNT(x) ((x) << ECC_CECNT_SHIFT)
-#define ECC_CECNT_GET(x) (((x) & ECC_CECNT_MASK) >> ECC_CECNT_SHIFT)
-#define ECC_UECNT_MASK 0x0000ffffU
-#define ECC_UECNT_SHIFT 0
-#define ECC_UECNT(x) ((x) << ECC_UECNT_SHIFT)
-#define ECC_UECNT_GET(x) (((x) & ECC_UECNT_MASK) >> ECC_UECNT_SHIFT)
-
-#define MC_BIST_CMD 0x7600
-#define START_BIST 0x80000000U
-#define BIST_CMD_GAP_MASK 0x0000ff00U
-#define BIST_CMD_GAP_SHIFT 8
-#define BIST_CMD_GAP(x) ((x) << BIST_CMD_GAP_SHIFT)
-#define BIST_OPCODE_MASK 0x00000003U
-#define BIST_OPCODE_SHIFT 0
-#define BIST_OPCODE(x) ((x) << BIST_OPCODE_SHIFT)
-
-#define MC_BIST_CMD_ADDR 0x7604
-#define MC_BIST_CMD_LEN 0x7608
-#define MC_BIST_DATA_PATTERN 0x760c
-#define BIST_DATA_TYPE_MASK 0x0000000fU
-#define BIST_DATA_TYPE_SHIFT 0
-#define BIST_DATA_TYPE(x) ((x) << BIST_DATA_TYPE_SHIFT)
-
-#define MC_BIST_STATUS_RDATA 0x7688
+#define PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A 0x59a4
+#define TPCP_S 30
+#define TPCP_V(x) ((x) << TPCP_S)
+#define TPCP_F TPCP_V(1U)
+
+#define TNPP_S 29
+#define TNPP_V(x) ((x) << TNPP_S)
+#define TNPP_F TNPP_V(1U)
+
+#define TFTP_S 28
+#define TFTP_V(x) ((x) << TFTP_S)
+#define TFTP_F TFTP_V(1U)
+
+#define TCAP_S 27
+#define TCAP_V(x) ((x) << TCAP_S)
+#define TCAP_F TCAP_V(1U)
+
+#define TCIP_S 26
+#define TCIP_V(x) ((x) << TCIP_S)
+#define TCIP_F TCIP_V(1U)
+
+#define RCAP_S 25
+#define RCAP_V(x) ((x) << RCAP_S)
+#define RCAP_F RCAP_V(1U)
+
+#define PLUP_S 23
+#define PLUP_V(x) ((x) << PLUP_S)
+#define PLUP_F PLUP_V(1U)
+
+#define PLDN_S 22
+#define PLDN_V(x) ((x) << PLDN_S)
+#define PLDN_F PLDN_V(1U)
+
+#define OTDD_S 21
+#define OTDD_V(x) ((x) << OTDD_S)
+#define OTDD_F OTDD_V(1U)
+
+#define GTRP_S 20
+#define GTRP_V(x) ((x) << GTRP_S)
+#define GTRP_F GTRP_V(1U)
+
+#define RDPE_S 18
+#define RDPE_V(x) ((x) << RDPE_S)
+#define RDPE_F RDPE_V(1U)
+
+#define TDCE_S 17
+#define TDCE_V(x) ((x) << TDCE_S)
+#define TDCE_F TDCE_V(1U)
+
+#define TDUE_S 16
+#define TDUE_V(x) ((x) << TDUE_S)
+#define TDUE_F TDUE_V(1U)
+
+/* registers for module MC */
+#define MC_INT_CAUSE_A 0x7518
+#define MC_P_INT_CAUSE_A 0x41318
+
+#define ECC_UE_INT_CAUSE_S 2
+#define ECC_UE_INT_CAUSE_V(x) ((x) << ECC_UE_INT_CAUSE_S)
+#define ECC_UE_INT_CAUSE_F ECC_UE_INT_CAUSE_V(1U)
+
+#define ECC_CE_INT_CAUSE_S 1
+#define ECC_CE_INT_CAUSE_V(x) ((x) << ECC_CE_INT_CAUSE_S)
+#define ECC_CE_INT_CAUSE_F ECC_CE_INT_CAUSE_V(1U)
+
+#define PERR_INT_CAUSE_S 0
+#define PERR_INT_CAUSE_V(x) ((x) << PERR_INT_CAUSE_S)
+#define PERR_INT_CAUSE_F PERR_INT_CAUSE_V(1U)
+
+#define MC_ECC_STATUS_A 0x751c
+#define MC_P_ECC_STATUS_A 0x4131c
+
+#define ECC_CECNT_S 16
+#define ECC_CECNT_M 0xffffU
+#define ECC_CECNT_V(x) ((x) << ECC_CECNT_S)
+#define ECC_CECNT_G(x) (((x) >> ECC_CECNT_S) & ECC_CECNT_M)
+
+#define ECC_UECNT_S 0
+#define ECC_UECNT_M 0xffffU
+#define ECC_UECNT_V(x) ((x) << ECC_UECNT_S)
+#define ECC_UECNT_G(x) (((x) >> ECC_UECNT_S) & ECC_UECNT_M)
+
+#define MC_BIST_CMD_A 0x7600
+
+#define START_BIST_S 31
+#define START_BIST_V(x) ((x) << START_BIST_S)
+#define START_BIST_F START_BIST_V(1U)
+
+#define BIST_CMD_GAP_S 8
+#define BIST_CMD_GAP_V(x) ((x) << BIST_CMD_GAP_S)
+
+#define BIST_OPCODE_S 0
+#define BIST_OPCODE_V(x) ((x) << BIST_OPCODE_S)
+
+#define MC_BIST_CMD_ADDR_A 0x7604
+#define MC_BIST_CMD_LEN_A 0x7608
+#define MC_BIST_DATA_PATTERN_A 0x760c
+
+#define MC_BIST_STATUS_RDATA_A 0x7688
+
+/* registers for module MA */
#define MA_EDRAM0_BAR_A 0x77c0
#define EDRAM0_SIZE_S 0
@@ -574,263 +893,608 @@
#define EXT_MEM0_ENABLE_V(x) ((x) << EXT_MEM0_ENABLE_S)
#define EXT_MEM0_ENABLE_F EXT_MEM0_ENABLE_V(1U)
-#define MA_INT_CAUSE 0x77e0
-#define MEM_PERR_INT_CAUSE 0x00000002U
-#define MEM_WRAP_INT_CAUSE 0x00000001U
-
-#define MA_INT_WRAP_STATUS 0x77e4
-#define MEM_WRAP_ADDRESS_MASK 0xfffffff0U
-#define MEM_WRAP_ADDRESS_SHIFT 4
-#define MEM_WRAP_ADDRESS_GET(x) (((x) & MEM_WRAP_ADDRESS_MASK) >> MEM_WRAP_ADDRESS_SHIFT)
-#define MEM_WRAP_CLIENT_NUM_MASK 0x0000000fU
-#define MEM_WRAP_CLIENT_NUM_SHIFT 0
-#define MEM_WRAP_CLIENT_NUM_GET(x) (((x) & MEM_WRAP_CLIENT_NUM_MASK) >> MEM_WRAP_CLIENT_NUM_SHIFT)
-#define MA_PCIE_FW 0x30b8
-#define MA_PARITY_ERROR_STATUS 0x77f4
-#define MA_PARITY_ERROR_STATUS2 0x7804
-
-#define EDC_0_BASE_ADDR 0x7900
-
-#define EDC_BIST_CMD 0x7904
-#define EDC_BIST_CMD_ADDR 0x7908
-#define EDC_BIST_CMD_LEN 0x790c
-#define EDC_BIST_DATA_PATTERN 0x7910
-#define EDC_BIST_STATUS_RDATA 0x7928
-#define EDC_INT_CAUSE 0x7978
-#define ECC_UE_PAR 0x00000020U
-#define ECC_CE_PAR 0x00000010U
-#define PERR_PAR_CAUSE 0x00000008U
-
-#define EDC_ECC_STATUS 0x797c
-
-#define EDC_1_BASE_ADDR 0x7980
-
-#define CIM_BOOT_CFG 0x7b00
-#define BOOTADDR_MASK 0xffffff00U
-#define UPCRST 0x1U
-
-#define CIM_PF_MAILBOX_DATA 0x240
-#define CIM_PF_MAILBOX_CTRL 0x280
-#define MBMSGVALID 0x00000008U
-#define MBINTREQ 0x00000004U
-#define MBOWNER_MASK 0x00000003U
-#define MBOWNER_SHIFT 0
-#define MBOWNER(x) ((x) << MBOWNER_SHIFT)
-#define MBOWNER_GET(x) (((x) & MBOWNER_MASK) >> MBOWNER_SHIFT)
-
-#define CIM_PF_HOST_INT_ENABLE 0x288
-#define MBMSGRDYINTEN(x) ((x) << 19)
-
-#define CIM_PF_HOST_INT_CAUSE 0x28c
-#define MBMSGRDYINT 0x00080000U
-
-#define CIM_HOST_INT_CAUSE 0x7b2c
-#define TIEQOUTPARERRINT 0x00100000U
-#define TIEQINPARERRINT 0x00080000U
-#define MBHOSTPARERR 0x00040000U
-#define MBUPPARERR 0x00020000U
-#define IBQPARERR 0x0001f800U
-#define IBQTP0PARERR 0x00010000U
-#define IBQTP1PARERR 0x00008000U
-#define IBQULPPARERR 0x00004000U
-#define IBQSGELOPARERR 0x00002000U
-#define IBQSGEHIPARERR 0x00001000U
-#define IBQNCSIPARERR 0x00000800U
-#define OBQPARERR 0x000007e0U
-#define OBQULP0PARERR 0x00000400U
-#define OBQULP1PARERR 0x00000200U
-#define OBQULP2PARERR 0x00000100U
-#define OBQULP3PARERR 0x00000080U
-#define OBQSGEPARERR 0x00000040U
-#define OBQNCSIPARERR 0x00000020U
-#define PREFDROPINT 0x00000002U
-#define UPACCNONZERO 0x00000001U
-
-#define CIM_HOST_UPACC_INT_CAUSE 0x7b34
-#define EEPROMWRINT 0x40000000U
-#define TIMEOUTMAINT 0x20000000U
-#define TIMEOUTINT 0x10000000U
-#define RSPOVRLOOKUPINT 0x08000000U
-#define REQOVRLOOKUPINT 0x04000000U
-#define BLKWRPLINT 0x02000000U
-#define BLKRDPLINT 0x01000000U
-#define SGLWRPLINT 0x00800000U
-#define SGLRDPLINT 0x00400000U
-#define BLKWRCTLINT 0x00200000U
-#define BLKRDCTLINT 0x00100000U
-#define SGLWRCTLINT 0x00080000U
-#define SGLRDCTLINT 0x00040000U
-#define BLKWREEPROMINT 0x00020000U
-#define BLKRDEEPROMINT 0x00010000U
-#define SGLWREEPROMINT 0x00008000U
-#define SGLRDEEPROMINT 0x00004000U
-#define BLKWRFLASHINT 0x00002000U
-#define BLKRDFLASHINT 0x00001000U
-#define SGLWRFLASHINT 0x00000800U
-#define SGLRDFLASHINT 0x00000400U
-#define BLKWRBOOTINT 0x00000200U
-#define BLKRDBOOTINT 0x00000100U
-#define SGLWRBOOTINT 0x00000080U
-#define SGLRDBOOTINT 0x00000040U
-#define ILLWRBEINT 0x00000020U
-#define ILLRDBEINT 0x00000010U
-#define ILLRDINT 0x00000008U
-#define ILLWRINT 0x00000004U
-#define ILLTRANSINT 0x00000002U
-#define RSVDSPACEINT 0x00000001U
-
-#define TP_OUT_CONFIG 0x7d04
-#define VLANEXTENABLE_MASK 0x0000f000U
-#define VLANEXTENABLE_SHIFT 12
-
-#define TP_GLOBAL_CONFIG 0x7d08
-#define FIVETUPLELOOKUP_SHIFT 17
-#define FIVETUPLELOOKUP_MASK 0x00060000U
-#define FIVETUPLELOOKUP(x) ((x) << FIVETUPLELOOKUP_SHIFT)
-#define FIVETUPLELOOKUP_GET(x) (((x) & FIVETUPLELOOKUP_MASK) >> \
- FIVETUPLELOOKUP_SHIFT)
-
-#define TP_PARA_REG2 0x7d68
-#define MAXRXDATA_MASK 0xffff0000U
-#define MAXRXDATA_SHIFT 16
-#define MAXRXDATA_GET(x) (((x) & MAXRXDATA_MASK) >> MAXRXDATA_SHIFT)
-
-#define TP_TIMER_RESOLUTION 0x7d90
-#define TIMERRESOLUTION_MASK 0x00ff0000U
-#define TIMERRESOLUTION_SHIFT 16
-#define TIMERRESOLUTION_GET(x) (((x) & TIMERRESOLUTION_MASK) >> TIMERRESOLUTION_SHIFT)
-#define DELAYEDACKRESOLUTION_MASK 0x000000ffU
-#define DELAYEDACKRESOLUTION_SHIFT 0
-#define DELAYEDACKRESOLUTION_GET(x) \
- (((x) & DELAYEDACKRESOLUTION_MASK) >> DELAYEDACKRESOLUTION_SHIFT)
-
-#define TP_SHIFT_CNT 0x7dc0
-#define SYNSHIFTMAX_SHIFT 24
-#define SYNSHIFTMAX_MASK 0xff000000U
-#define SYNSHIFTMAX(x) ((x) << SYNSHIFTMAX_SHIFT)
-#define SYNSHIFTMAX_GET(x) (((x) & SYNSHIFTMAX_MASK) >> \
- SYNSHIFTMAX_SHIFT)
-#define RXTSHIFTMAXR1_SHIFT 20
-#define RXTSHIFTMAXR1_MASK 0x00f00000U
-#define RXTSHIFTMAXR1(x) ((x) << RXTSHIFTMAXR1_SHIFT)
-#define RXTSHIFTMAXR1_GET(x) (((x) & RXTSHIFTMAXR1_MASK) >> \
- RXTSHIFTMAXR1_SHIFT)
-#define RXTSHIFTMAXR2_SHIFT 16
-#define RXTSHIFTMAXR2_MASK 0x000f0000U
-#define RXTSHIFTMAXR2(x) ((x) << RXTSHIFTMAXR2_SHIFT)
-#define RXTSHIFTMAXR2_GET(x) (((x) & RXTSHIFTMAXR2_MASK) >> \
- RXTSHIFTMAXR2_SHIFT)
-#define PERSHIFTBACKOFFMAX_SHIFT 12
-#define PERSHIFTBACKOFFMAX_MASK 0x0000f000U
-#define PERSHIFTBACKOFFMAX(x) ((x) << PERSHIFTBACKOFFMAX_SHIFT)
-#define PERSHIFTBACKOFFMAX_GET(x) (((x) & PERSHIFTBACKOFFMAX_MASK) >> \
- PERSHIFTBACKOFFMAX_SHIFT)
-#define PERSHIFTMAX_SHIFT 8
-#define PERSHIFTMAX_MASK 0x00000f00U
-#define PERSHIFTMAX(x) ((x) << PERSHIFTMAX_SHIFT)
-#define PERSHIFTMAX_GET(x) (((x) & PERSHIFTMAX_MASK) >> \
- PERSHIFTMAX_SHIFT)
-#define KEEPALIVEMAXR1_SHIFT 4
-#define KEEPALIVEMAXR1_MASK 0x000000f0U
-#define KEEPALIVEMAXR1(x) ((x) << KEEPALIVEMAXR1_SHIFT)
-#define KEEPALIVEMAXR1_GET(x) (((x) & KEEPALIVEMAXR1_MASK) >> \
- KEEPALIVEMAXR1_SHIFT)
-#define KEEPALIVEMAXR2_SHIFT 0
-#define KEEPALIVEMAXR2_MASK 0x0000000fU
-#define KEEPALIVEMAXR2(x) ((x) << KEEPALIVEMAXR2_SHIFT)
-#define KEEPALIVEMAXR2_GET(x) (((x) & KEEPALIVEMAXR2_MASK) >> \
- KEEPALIVEMAXR2_SHIFT)
-
-#define TP_CCTRL_TABLE 0x7ddc
-#define TP_MTU_TABLE 0x7de4
-#define MTUINDEX_MASK 0xff000000U
-#define MTUINDEX_SHIFT 24
-#define MTUINDEX(x) ((x) << MTUINDEX_SHIFT)
-#define MTUWIDTH_MASK 0x000f0000U
-#define MTUWIDTH_SHIFT 16
-#define MTUWIDTH(x) ((x) << MTUWIDTH_SHIFT)
-#define MTUWIDTH_GET(x) (((x) & MTUWIDTH_MASK) >> MTUWIDTH_SHIFT)
-#define MTUVALUE_MASK 0x00003fffU
-#define MTUVALUE_SHIFT 0
-#define MTUVALUE(x) ((x) << MTUVALUE_SHIFT)
-#define MTUVALUE_GET(x) (((x) & MTUVALUE_MASK) >> MTUVALUE_SHIFT)
-
-#define TP_RSS_LKP_TABLE 0x7dec
-#define LKPTBLROWVLD 0x80000000U
-#define LKPTBLQUEUE1_MASK 0x000ffc00U
-#define LKPTBLQUEUE1_SHIFT 10
-#define LKPTBLQUEUE1(x) ((x) << LKPTBLQUEUE1_SHIFT)
-#define LKPTBLQUEUE1_GET(x) (((x) & LKPTBLQUEUE1_MASK) >> LKPTBLQUEUE1_SHIFT)
-#define LKPTBLQUEUE0_MASK 0x000003ffU
-#define LKPTBLQUEUE0_SHIFT 0
-#define LKPTBLQUEUE0(x) ((x) << LKPTBLQUEUE0_SHIFT)
-#define LKPTBLQUEUE0_GET(x) (((x) & LKPTBLQUEUE0_MASK) >> LKPTBLQUEUE0_SHIFT)
-
-#define TP_PIO_ADDR 0x7e40
-#define TP_PIO_DATA 0x7e44
-#define TP_MIB_INDEX 0x7e50
-#define TP_MIB_DATA 0x7e54
-#define TP_INT_CAUSE 0x7e74
-#define FLMTXFLSTEMPTY 0x40000000U
-
-#define TP_VLAN_PRI_MAP 0x140
-#define FRAGMENTATION_SHIFT 9
-#define FRAGMENTATION_MASK 0x00000200U
-#define MPSHITTYPE_MASK 0x00000100U
-#define MACMATCH_MASK 0x00000080U
-#define ETHERTYPE_MASK 0x00000040U
-#define PROTOCOL_MASK 0x00000020U
-#define TOS_MASK 0x00000010U
-#define VLAN_MASK 0x00000008U
-#define VNIC_ID_MASK 0x00000004U
-#define PORT_MASK 0x00000002U
-#define FCOE_SHIFT 0
-#define FCOE_MASK 0x00000001U
-
-#define TP_INGRESS_CONFIG 0x141
-#define VNIC 0x00000800U
-#define CSUM_HAS_PSEUDO_HDR 0x00000400U
-#define RM_OVLAN 0x00000200U
-#define LOOKUPEVERYPKT 0x00000100U
-
-#define TP_MIB_MAC_IN_ERR_0 0x0
-#define TP_MIB_TCP_OUT_RST 0xc
-#define TP_MIB_TCP_IN_SEG_HI 0x10
-#define TP_MIB_TCP_IN_SEG_LO 0x11
-#define TP_MIB_TCP_OUT_SEG_HI 0x12
-#define TP_MIB_TCP_OUT_SEG_LO 0x13
-#define TP_MIB_TCP_RXT_SEG_HI 0x14
-#define TP_MIB_TCP_RXT_SEG_LO 0x15
-#define TP_MIB_TNL_CNG_DROP_0 0x18
-#define TP_MIB_TCP_V6IN_ERR_0 0x28
-#define TP_MIB_TCP_V6OUT_RST 0x2c
-#define TP_MIB_OFD_ARP_DROP 0x36
-#define TP_MIB_TNL_DROP_0 0x44
-#define TP_MIB_OFD_VLN_DROP_0 0x58
-
-#define ULP_TX_INT_CAUSE 0x8dcc
-#define PBL_BOUND_ERR_CH3 0x80000000U
-#define PBL_BOUND_ERR_CH2 0x40000000U
-#define PBL_BOUND_ERR_CH1 0x20000000U
-#define PBL_BOUND_ERR_CH0 0x10000000U
-
-#define PM_RX_INT_CAUSE 0x8fdc
-#define ZERO_E_CMD_ERROR 0x00400000U
-#define PMRX_FRAMING_ERROR 0x003ffff0U
-#define OCSPI_PAR_ERROR 0x00000008U
-#define DB_OPTIONS_PAR_ERROR 0x00000004U
-#define IESPI_PAR_ERROR 0x00000002U
-#define E_PCMD_PAR_ERROR 0x00000001U
-
-#define PM_TX_INT_CAUSE 0x8ffc
-#define PCMD_LEN_OVFL0 0x80000000U
-#define PCMD_LEN_OVFL1 0x40000000U
-#define PCMD_LEN_OVFL2 0x20000000U
-#define ZERO_C_CMD_ERROR 0x10000000U
-#define PMTX_FRAMING_ERROR 0x0ffffff0U
-#define OESPI_PAR_ERROR 0x00000008U
-#define ICSPI_PAR_ERROR 0x00000002U
-#define C_PCMD_PAR_ERROR 0x00000001U
+#define MA_INT_CAUSE_A 0x77e0
+
+#define MEM_PERR_INT_CAUSE_S 1
+#define MEM_PERR_INT_CAUSE_V(x) ((x) << MEM_PERR_INT_CAUSE_S)
+#define MEM_PERR_INT_CAUSE_F MEM_PERR_INT_CAUSE_V(1U)
+
+#define MEM_WRAP_INT_CAUSE_S 0
+#define MEM_WRAP_INT_CAUSE_V(x) ((x) << MEM_WRAP_INT_CAUSE_S)
+#define MEM_WRAP_INT_CAUSE_F MEM_WRAP_INT_CAUSE_V(1U)
+
+#define MA_INT_WRAP_STATUS_A 0x77e4
+
+#define MEM_WRAP_ADDRESS_S 4
+#define MEM_WRAP_ADDRESS_M 0xfffffffU
+#define MEM_WRAP_ADDRESS_G(x) (((x) >> MEM_WRAP_ADDRESS_S) & MEM_WRAP_ADDRESS_M)
+
+#define MEM_WRAP_CLIENT_NUM_S 0
+#define MEM_WRAP_CLIENT_NUM_M 0xfU
+#define MEM_WRAP_CLIENT_NUM_G(x) \
+ (((x) >> MEM_WRAP_CLIENT_NUM_S) & MEM_WRAP_CLIENT_NUM_M)
+
+#define MA_PARITY_ERROR_STATUS_A 0x77f4
+#define MA_PARITY_ERROR_STATUS1_A 0x77f4
+#define MA_PARITY_ERROR_STATUS2_A 0x7804
+
+/* registers for module EDC_0 */
+#define EDC_0_BASE_ADDR 0x7900
+
+#define EDC_BIST_CMD_A 0x7904
+#define EDC_BIST_CMD_ADDR_A 0x7908
+#define EDC_BIST_CMD_LEN_A 0x790c
+#define EDC_BIST_DATA_PATTERN_A 0x7910
+#define EDC_BIST_STATUS_RDATA_A 0x7928
+#define EDC_INT_CAUSE_A 0x7978
+
+#define ECC_UE_PAR_S 5
+#define ECC_UE_PAR_V(x) ((x) << ECC_UE_PAR_S)
+#define ECC_UE_PAR_F ECC_UE_PAR_V(1U)
+
+#define ECC_CE_PAR_S 4
+#define ECC_CE_PAR_V(x) ((x) << ECC_CE_PAR_S)
+#define ECC_CE_PAR_F ECC_CE_PAR_V(1U)
+
+#define PERR_PAR_CAUSE_S 3
+#define PERR_PAR_CAUSE_V(x) ((x) << PERR_PAR_CAUSE_S)
+#define PERR_PAR_CAUSE_F PERR_PAR_CAUSE_V(1U)
+
+#define EDC_ECC_STATUS_A 0x797c
+
+/* registers for module EDC_1 */
+#define EDC_1_BASE_ADDR 0x7980
+
+/* registers for module CIM */
+#define CIM_BOOT_CFG_A 0x7b00
+#define CIM_PF_MAILBOX_CTRL_SHADOW_COPY_A 0x290
+
+#define BOOTADDR_M 0xffffff00U
+
+#define UPCRST_S 0
+#define UPCRST_V(x) ((x) << UPCRST_S)
+#define UPCRST_F UPCRST_V(1U)
+
+#define CIM_PF_MAILBOX_DATA_A 0x240
+#define CIM_PF_MAILBOX_CTRL_A 0x280
+
+#define MBMSGVALID_S 3
+#define MBMSGVALID_V(x) ((x) << MBMSGVALID_S)
+#define MBMSGVALID_F MBMSGVALID_V(1U)
+
+#define MBINTREQ_S 2
+#define MBINTREQ_V(x) ((x) << MBINTREQ_S)
+#define MBINTREQ_F MBINTREQ_V(1U)
+
+#define MBOWNER_S 0
+#define MBOWNER_M 0x3U
+#define MBOWNER_V(x) ((x) << MBOWNER_S)
+#define MBOWNER_G(x) (((x) >> MBOWNER_S) & MBOWNER_M)
+
+#define CIM_PF_HOST_INT_ENABLE_A 0x288
+
+#define MBMSGRDYINTEN_S 19
+#define MBMSGRDYINTEN_V(x) ((x) << MBMSGRDYINTEN_S)
+#define MBMSGRDYINTEN_F MBMSGRDYINTEN_V(1U)
+
+#define CIM_PF_HOST_INT_CAUSE_A 0x28c
+
+#define MBMSGRDYINT_S 19
+#define MBMSGRDYINT_V(x) ((x) << MBMSGRDYINT_S)
+#define MBMSGRDYINT_F MBMSGRDYINT_V(1U)
+
+#define CIM_HOST_INT_CAUSE_A 0x7b2c
+
+#define TIEQOUTPARERRINT_S 20
+#define TIEQOUTPARERRINT_V(x) ((x) << TIEQOUTPARERRINT_S)
+#define TIEQOUTPARERRINT_F TIEQOUTPARERRINT_V(1U)
+
+#define TIEQINPARERRINT_S 19
+#define TIEQINPARERRINT_V(x) ((x) << TIEQINPARERRINT_S)
+#define TIEQINPARERRINT_F TIEQINPARERRINT_V(1U)
+
+#define PREFDROPINT_S 1
+#define PREFDROPINT_V(x) ((x) << PREFDROPINT_S)
+#define PREFDROPINT_F PREFDROPINT_V(1U)
+
+#define UPACCNONZERO_S 0
+#define UPACCNONZERO_V(x) ((x) << UPACCNONZERO_S)
+#define UPACCNONZERO_F UPACCNONZERO_V(1U)
+
+#define MBHOSTPARERR_S 18
+#define MBHOSTPARERR_V(x) ((x) << MBHOSTPARERR_S)
+#define MBHOSTPARERR_F MBHOSTPARERR_V(1U)
+
+#define MBUPPARERR_S 17
+#define MBUPPARERR_V(x) ((x) << MBUPPARERR_S)
+#define MBUPPARERR_F MBUPPARERR_V(1U)
+
+#define IBQTP0PARERR_S 16
+#define IBQTP0PARERR_V(x) ((x) << IBQTP0PARERR_S)
+#define IBQTP0PARERR_F IBQTP0PARERR_V(1U)
+
+#define IBQTP1PARERR_S 15
+#define IBQTP1PARERR_V(x) ((x) << IBQTP1PARERR_S)
+#define IBQTP1PARERR_F IBQTP1PARERR_V(1U)
+
+#define IBQULPPARERR_S 14
+#define IBQULPPARERR_V(x) ((x) << IBQULPPARERR_S)
+#define IBQULPPARERR_F IBQULPPARERR_V(1U)
+
+#define IBQSGELOPARERR_S 13
+#define IBQSGELOPARERR_V(x) ((x) << IBQSGELOPARERR_S)
+#define IBQSGELOPARERR_F IBQSGELOPARERR_V(1U)
+
+#define IBQSGEHIPARERR_S 12
+#define IBQSGEHIPARERR_V(x) ((x) << IBQSGEHIPARERR_S)
+#define IBQSGEHIPARERR_F IBQSGEHIPARERR_V(1U)
+
+#define IBQNCSIPARERR_S 11
+#define IBQNCSIPARERR_V(x) ((x) << IBQNCSIPARERR_S)
+#define IBQNCSIPARERR_F IBQNCSIPARERR_V(1U)
+
+#define OBQULP0PARERR_S 10
+#define OBQULP0PARERR_V(x) ((x) << OBQULP0PARERR_S)
+#define OBQULP0PARERR_F OBQULP0PARERR_V(1U)
+
+#define OBQULP1PARERR_S 9
+#define OBQULP1PARERR_V(x) ((x) << OBQULP1PARERR_S)
+#define OBQULP1PARERR_F OBQULP1PARERR_V(1U)
+
+#define OBQULP2PARERR_S 8
+#define OBQULP2PARERR_V(x) ((x) << OBQULP2PARERR_S)
+#define OBQULP2PARERR_F OBQULP2PARERR_V(1U)
+
+#define OBQULP3PARERR_S 7
+#define OBQULP3PARERR_V(x) ((x) << OBQULP3PARERR_S)
+#define OBQULP3PARERR_F OBQULP3PARERR_V(1U)
+
+#define OBQSGEPARERR_S 6
+#define OBQSGEPARERR_V(x) ((x) << OBQSGEPARERR_S)
+#define OBQSGEPARERR_F OBQSGEPARERR_V(1U)
+
+#define OBQNCSIPARERR_S 5
+#define OBQNCSIPARERR_V(x) ((x) << OBQNCSIPARERR_S)
+#define OBQNCSIPARERR_F OBQNCSIPARERR_V(1U)
+
+#define CIM_HOST_UPACC_INT_CAUSE_A 0x7b34
+
+#define EEPROMWRINT_S 30
+#define EEPROMWRINT_V(x) ((x) << EEPROMWRINT_S)
+#define EEPROMWRINT_F EEPROMWRINT_V(1U)
+
+#define TIMEOUTMAINT_S 29
+#define TIMEOUTMAINT_V(x) ((x) << TIMEOUTMAINT_S)
+#define TIMEOUTMAINT_F TIMEOUTMAINT_V(1U)
+
+#define TIMEOUTINT_S 28
+#define TIMEOUTINT_V(x) ((x) << TIMEOUTINT_S)
+#define TIMEOUTINT_F TIMEOUTINT_V(1U)
+
+#define RSPOVRLOOKUPINT_S 27
+#define RSPOVRLOOKUPINT_V(x) ((x) << RSPOVRLOOKUPINT_S)
+#define RSPOVRLOOKUPINT_F RSPOVRLOOKUPINT_V(1U)
+
+#define REQOVRLOOKUPINT_S 26
+#define REQOVRLOOKUPINT_V(x) ((x) << REQOVRLOOKUPINT_S)
+#define REQOVRLOOKUPINT_F REQOVRLOOKUPINT_V(1U)
+
+#define BLKWRPLINT_S 25
+#define BLKWRPLINT_V(x) ((x) << BLKWRPLINT_S)
+#define BLKWRPLINT_F BLKWRPLINT_V(1U)
+
+#define BLKRDPLINT_S 24
+#define BLKRDPLINT_V(x) ((x) << BLKRDPLINT_S)
+#define BLKRDPLINT_F BLKRDPLINT_V(1U)
+
+#define SGLWRPLINT_S 23
+#define SGLWRPLINT_V(x) ((x) << SGLWRPLINT_S)
+#define SGLWRPLINT_F SGLWRPLINT_V(1U)
+
+#define SGLRDPLINT_S 22
+#define SGLRDPLINT_V(x) ((x) << SGLRDPLINT_S)
+#define SGLRDPLINT_F SGLRDPLINT_V(1U)
+
+#define BLKWRCTLINT_S 21
+#define BLKWRCTLINT_V(x) ((x) << BLKWRCTLINT_S)
+#define BLKWRCTLINT_F BLKWRCTLINT_V(1U)
+
+#define BLKRDCTLINT_S 20
+#define BLKRDCTLINT_V(x) ((x) << BLKRDCTLINT_S)
+#define BLKRDCTLINT_F BLKRDCTLINT_V(1U)
+
+#define SGLWRCTLINT_S 19
+#define SGLWRCTLINT_V(x) ((x) << SGLWRCTLINT_S)
+#define SGLWRCTLINT_F SGLWRCTLINT_V(1U)
+
+#define SGLRDCTLINT_S 18
+#define SGLRDCTLINT_V(x) ((x) << SGLRDCTLINT_S)
+#define SGLRDCTLINT_F SGLRDCTLINT_V(1U)
+
+#define BLKWREEPROMINT_S 17
+#define BLKWREEPROMINT_V(x) ((x) << BLKWREEPROMINT_S)
+#define BLKWREEPROMINT_F BLKWREEPROMINT_V(1U)
+
+#define BLKRDEEPROMINT_S 16
+#define BLKRDEEPROMINT_V(x) ((x) << BLKRDEEPROMINT_S)
+#define BLKRDEEPROMINT_F BLKRDEEPROMINT_V(1U)
+
+#define SGLWREEPROMINT_S 15
+#define SGLWREEPROMINT_V(x) ((x) << SGLWREEPROMINT_S)
+#define SGLWREEPROMINT_F SGLWREEPROMINT_V(1U)
+
+#define SGLRDEEPROMINT_S 14
+#define SGLRDEEPROMINT_V(x) ((x) << SGLRDEEPROMINT_S)
+#define SGLRDEEPROMINT_F SGLRDEEPROMINT_V(1U)
+
+#define BLKWRFLASHINT_S 13
+#define BLKWRFLASHINT_V(x) ((x) << BLKWRFLASHINT_S)
+#define BLKWRFLASHINT_F BLKWRFLASHINT_V(1U)
+
+#define BLKRDFLASHINT_S 12
+#define BLKRDFLASHINT_V(x) ((x) << BLKRDFLASHINT_S)
+#define BLKRDFLASHINT_F BLKRDFLASHINT_V(1U)
+
+#define SGLWRFLASHINT_S 11
+#define SGLWRFLASHINT_V(x) ((x) << SGLWRFLASHINT_S)
+#define SGLWRFLASHINT_F SGLWRFLASHINT_V(1U)
+
+#define SGLRDFLASHINT_S 10
+#define SGLRDFLASHINT_V(x) ((x) << SGLRDFLASHINT_S)
+#define SGLRDFLASHINT_F SGLRDFLASHINT_V(1U)
+
+#define BLKWRBOOTINT_S 9
+#define BLKWRBOOTINT_V(x) ((x) << BLKWRBOOTINT_S)
+#define BLKWRBOOTINT_F BLKWRBOOTINT_V(1U)
+
+#define BLKRDBOOTINT_S 8
+#define BLKRDBOOTINT_V(x) ((x) << BLKRDBOOTINT_S)
+#define BLKRDBOOTINT_F BLKRDBOOTINT_V(1U)
+
+#define SGLWRBOOTINT_S 7
+#define SGLWRBOOTINT_V(x) ((x) << SGLWRBOOTINT_S)
+#define SGLWRBOOTINT_F SGLWRBOOTINT_V(1U)
+
+#define SGLRDBOOTINT_S 6
+#define SGLRDBOOTINT_V(x) ((x) << SGLRDBOOTINT_S)
+#define SGLRDBOOTINT_F SGLRDBOOTINT_V(1U)
+
+#define ILLWRBEINT_S 5
+#define ILLWRBEINT_V(x) ((x) << ILLWRBEINT_S)
+#define ILLWRBEINT_F ILLWRBEINT_V(1U)
+
+#define ILLRDBEINT_S 4
+#define ILLRDBEINT_V(x) ((x) << ILLRDBEINT_S)
+#define ILLRDBEINT_F ILLRDBEINT_V(1U)
+
+#define ILLRDINT_S 3
+#define ILLRDINT_V(x) ((x) << ILLRDINT_S)
+#define ILLRDINT_F ILLRDINT_V(1U)
+
+#define ILLWRINT_S 2
+#define ILLWRINT_V(x) ((x) << ILLWRINT_S)
+#define ILLWRINT_F ILLWRINT_V(1U)
+
+#define ILLTRANSINT_S 1
+#define ILLTRANSINT_V(x) ((x) << ILLTRANSINT_S)
+#define ILLTRANSINT_F ILLTRANSINT_V(1U)
+
+#define RSVDSPACEINT_S 0
+#define RSVDSPACEINT_V(x) ((x) << RSVDSPACEINT_S)
+#define RSVDSPACEINT_F RSVDSPACEINT_V(1U)
+
+/* registers for module TP */
+#define DBGLAWHLF_S 23
+#define DBGLAWHLF_V(x) ((x) << DBGLAWHLF_S)
+#define DBGLAWHLF_F DBGLAWHLF_V(1U)
+
+#define DBGLAWPTR_S 16
+#define DBGLAWPTR_M 0x7fU
+#define DBGLAWPTR_G(x) (((x) >> DBGLAWPTR_S) & DBGLAWPTR_M)
+
+#define DBGLAENABLE_S 12
+#define DBGLAENABLE_V(x) ((x) << DBGLAENABLE_S)
+#define DBGLAENABLE_F DBGLAENABLE_V(1U)
+
+#define DBGLARPTR_S 0
+#define DBGLARPTR_M 0x7fU
+#define DBGLARPTR_V(x) ((x) << DBGLARPTR_S)
+
+#define TP_DBG_LA_DATAL_A 0x7ed8
+#define TP_DBG_LA_CONFIG_A 0x7ed4
+#define TP_OUT_CONFIG_A 0x7d04
+#define TP_GLOBAL_CONFIG_A 0x7d08
+
+#define DBGLAMODE_S 14
+#define DBGLAMODE_M 0x3U
+#define DBGLAMODE_G(x) (((x) >> DBGLAMODE_S) & DBGLAMODE_M)
+
+#define FIVETUPLELOOKUP_S 17
+#define FIVETUPLELOOKUP_M 0x3U
+#define FIVETUPLELOOKUP_V(x) ((x) << FIVETUPLELOOKUP_S)
+#define FIVETUPLELOOKUP_G(x) (((x) >> FIVETUPLELOOKUP_S) & FIVETUPLELOOKUP_M)
+
+#define TP_PARA_REG2_A 0x7d68
+
+#define MAXRXDATA_S 16
+#define MAXRXDATA_M 0xffffU
+#define MAXRXDATA_G(x) (((x) >> MAXRXDATA_S) & MAXRXDATA_M)
+
+#define TP_TIMER_RESOLUTION_A 0x7d90
+
+#define TIMERRESOLUTION_S 16
+#define TIMERRESOLUTION_M 0xffU
+#define TIMERRESOLUTION_G(x) (((x) >> TIMERRESOLUTION_S) & TIMERRESOLUTION_M)
+
+#define TIMESTAMPRESOLUTION_S 8
+#define TIMESTAMPRESOLUTION_M 0xffU
+#define TIMESTAMPRESOLUTION_G(x) \
+ (((x) >> TIMESTAMPRESOLUTION_S) & TIMESTAMPRESOLUTION_M)
+
+#define DELAYEDACKRESOLUTION_S 0
+#define DELAYEDACKRESOLUTION_M 0xffU
+#define DELAYEDACKRESOLUTION_G(x) \
+ (((x) >> DELAYEDACKRESOLUTION_S) & DELAYEDACKRESOLUTION_M)
+
+#define TP_SHIFT_CNT_A 0x7dc0
+#define TP_RXT_MIN_A 0x7d98
+#define TP_RXT_MAX_A 0x7d9c
+#define TP_PERS_MIN_A 0x7da0
+#define TP_PERS_MAX_A 0x7da4
+#define TP_KEEP_IDLE_A 0x7da8
+#define TP_KEEP_INTVL_A 0x7dac
+#define TP_INIT_SRTT_A 0x7db0
+#define TP_DACK_TIMER_A 0x7db4
+#define TP_FINWAIT2_TIMER_A 0x7db8
+
+#define INITSRTT_S 0
+#define INITSRTT_M 0xffffU
+#define INITSRTT_G(x) (((x) >> INITSRTT_S) & INITSRTT_M)
+
+#define PERSMAX_S 0
+#define PERSMAX_M 0x3fffffffU
+#define PERSMAX_V(x) ((x) << PERSMAX_S)
+#define PERSMAX_G(x) (((x) >> PERSMAX_S) & PERSMAX_M)
+
+#define SYNSHIFTMAX_S 24
+#define SYNSHIFTMAX_M 0xffU
+#define SYNSHIFTMAX_V(x) ((x) << SYNSHIFTMAX_S)
+#define SYNSHIFTMAX_G(x) (((x) >> SYNSHIFTMAX_S) & SYNSHIFTMAX_M)
+
+#define RXTSHIFTMAXR1_S 20
+#define RXTSHIFTMAXR1_M 0xfU
+#define RXTSHIFTMAXR1_V(x) ((x) << RXTSHIFTMAXR1_S)
+#define RXTSHIFTMAXR1_G(x) (((x) >> RXTSHIFTMAXR1_S) & RXTSHIFTMAXR1_M)
+
+#define RXTSHIFTMAXR2_S 16
+#define RXTSHIFTMAXR2_M 0xfU
+#define RXTSHIFTMAXR2_V(x) ((x) << RXTSHIFTMAXR2_S)
+#define RXTSHIFTMAXR2_G(x) (((x) >> RXTSHIFTMAXR2_S) & RXTSHIFTMAXR2_M)
+
+#define PERSHIFTBACKOFFMAX_S 12
+#define PERSHIFTBACKOFFMAX_M 0xfU
+#define PERSHIFTBACKOFFMAX_V(x) ((x) << PERSHIFTBACKOFFMAX_S)
+#define PERSHIFTBACKOFFMAX_G(x) \
+ (((x) >> PERSHIFTBACKOFFMAX_S) & PERSHIFTBACKOFFMAX_M)
+
+#define PERSHIFTMAX_S 8
+#define PERSHIFTMAX_M 0xfU
+#define PERSHIFTMAX_V(x) ((x) << PERSHIFTMAX_S)
+#define PERSHIFTMAX_G(x) (((x) >> PERSHIFTMAX_S) & PERSHIFTMAX_M)
+
+#define KEEPALIVEMAXR1_S 4
+#define KEEPALIVEMAXR1_M 0xfU
+#define KEEPALIVEMAXR1_V(x) ((x) << KEEPALIVEMAXR1_S)
+#define KEEPALIVEMAXR1_G(x) (((x) >> KEEPALIVEMAXR1_S) & KEEPALIVEMAXR1_M)
+
+#define KEEPALIVEMAXR2_S 0
+#define KEEPALIVEMAXR2_M 0xfU
+#define KEEPALIVEMAXR2_V(x) ((x) << KEEPALIVEMAXR2_S)
+#define KEEPALIVEMAXR2_G(x) (((x) >> KEEPALIVEMAXR2_S) & KEEPALIVEMAXR2_M)
+
+#define ROWINDEX_S 16
+#define ROWINDEX_V(x) ((x) << ROWINDEX_S)
+
+#define TP_CCTRL_TABLE_A 0x7ddc
+#define TP_MTU_TABLE_A 0x7de4
+
+#define MTUINDEX_S 24
+#define MTUINDEX_V(x) ((x) << MTUINDEX_S)
+
+#define MTUWIDTH_S 16
+#define MTUWIDTH_M 0xfU
+#define MTUWIDTH_V(x) ((x) << MTUWIDTH_S)
+#define MTUWIDTH_G(x) (((x) >> MTUWIDTH_S) & MTUWIDTH_M)
+
+#define MTUVALUE_S 0
+#define MTUVALUE_M 0x3fffU
+#define MTUVALUE_V(x) ((x) << MTUVALUE_S)
+#define MTUVALUE_G(x) (((x) >> MTUVALUE_S) & MTUVALUE_M)
+
+#define TP_RSS_LKP_TABLE_A 0x7dec
+
+#define LKPTBLROWVLD_S 31
+#define LKPTBLROWVLD_V(x) ((x) << LKPTBLROWVLD_S)
+#define LKPTBLROWVLD_F LKPTBLROWVLD_V(1U)
+
+#define LKPTBLQUEUE1_S 10
+#define LKPTBLQUEUE1_M 0x3ffU
+#define LKPTBLQUEUE1_G(x) (((x) >> LKPTBLQUEUE1_S) & LKPTBLQUEUE1_M)
+
+#define LKPTBLQUEUE0_S 0
+#define LKPTBLQUEUE0_M 0x3ffU
+#define LKPTBLQUEUE0_G(x) (((x) >> LKPTBLQUEUE0_S) & LKPTBLQUEUE0_M)
+
+#define TP_PIO_ADDR_A 0x7e40
+#define TP_PIO_DATA_A 0x7e44
+#define TP_MIB_INDEX_A 0x7e50
+#define TP_MIB_DATA_A 0x7e54
+#define TP_INT_CAUSE_A 0x7e74
+
+#define FLMTXFLSTEMPTY_S 30
+#define FLMTXFLSTEMPTY_V(x) ((x) << FLMTXFLSTEMPTY_S)
+#define FLMTXFLSTEMPTY_F FLMTXFLSTEMPTY_V(1U)
+
+#define TP_VLAN_PRI_MAP_A 0x140
+
+#define FRAGMENTATION_S 9
+#define FRAGMENTATION_V(x) ((x) << FRAGMENTATION_S)
+#define FRAGMENTATION_F FRAGMENTATION_V(1U)
+
+#define MPSHITTYPE_S 8
+#define MPSHITTYPE_V(x) ((x) << MPSHITTYPE_S)
+#define MPSHITTYPE_F MPSHITTYPE_V(1U)
+
+#define MACMATCH_S 7
+#define MACMATCH_V(x) ((x) << MACMATCH_S)
+#define MACMATCH_F MACMATCH_V(1U)
+
+#define ETHERTYPE_S 6
+#define ETHERTYPE_V(x) ((x) << ETHERTYPE_S)
+#define ETHERTYPE_F ETHERTYPE_V(1U)
+
+#define PROTOCOL_S 5
+#define PROTOCOL_V(x) ((x) << PROTOCOL_S)
+#define PROTOCOL_F PROTOCOL_V(1U)
+
+#define TOS_S 4
+#define TOS_V(x) ((x) << TOS_S)
+#define TOS_F TOS_V(1U)
+
+#define VLAN_S 3
+#define VLAN_V(x) ((x) << VLAN_S)
+#define VLAN_F VLAN_V(1U)
+
+#define VNIC_ID_S 2
+#define VNIC_ID_V(x) ((x) << VNIC_ID_S)
+#define VNIC_ID_F VNIC_ID_V(1U)
+
+#define PORT_S 1
+#define PORT_V(x) ((x) << PORT_S)
+#define PORT_F PORT_V(1U)
+
+#define FCOE_S 0
+#define FCOE_V(x) ((x) << FCOE_S)
+#define FCOE_F FCOE_V(1U)
+
+#define FILTERMODE_S 15
+#define FILTERMODE_V(x) ((x) << FILTERMODE_S)
+#define FILTERMODE_F FILTERMODE_V(1U)
+
+#define FCOEMASK_S 14
+#define FCOEMASK_V(x) ((x) << FCOEMASK_S)
+#define FCOEMASK_F FCOEMASK_V(1U)
+
+#define TP_INGRESS_CONFIG_A 0x141
+
+#define VNIC_S 11
+#define VNIC_V(x) ((x) << VNIC_S)
+#define VNIC_F VNIC_V(1U)
+
+#define CSUM_HAS_PSEUDO_HDR_S 10
+#define CSUM_HAS_PSEUDO_HDR_V(x) ((x) << CSUM_HAS_PSEUDO_HDR_S)
+#define CSUM_HAS_PSEUDO_HDR_F CSUM_HAS_PSEUDO_HDR_V(1U)
+
+#define TP_MIB_MAC_IN_ERR_0_A 0x0
+#define TP_MIB_TCP_OUT_RST_A 0xc
+#define TP_MIB_TCP_IN_SEG_HI_A 0x10
+#define TP_MIB_TCP_IN_SEG_LO_A 0x11
+#define TP_MIB_TCP_OUT_SEG_HI_A 0x12
+#define TP_MIB_TCP_OUT_SEG_LO_A 0x13
+#define TP_MIB_TCP_RXT_SEG_HI_A 0x14
+#define TP_MIB_TCP_RXT_SEG_LO_A 0x15
+#define TP_MIB_TNL_CNG_DROP_0_A 0x18
+#define TP_MIB_TCP_V6IN_ERR_0_A 0x28
+#define TP_MIB_TCP_V6OUT_RST_A 0x2c
+#define TP_MIB_OFD_ARP_DROP_A 0x36
+#define TP_MIB_TNL_DROP_0_A 0x44
+#define TP_MIB_OFD_VLN_DROP_0_A 0x58
+
+#define ULP_TX_INT_CAUSE_A 0x8dcc
+
+#define PBL_BOUND_ERR_CH3_S 31
+#define PBL_BOUND_ERR_CH3_V(x) ((x) << PBL_BOUND_ERR_CH3_S)
+#define PBL_BOUND_ERR_CH3_F PBL_BOUND_ERR_CH3_V(1U)
+
+#define PBL_BOUND_ERR_CH2_S 30
+#define PBL_BOUND_ERR_CH2_V(x) ((x) << PBL_BOUND_ERR_CH2_S)
+#define PBL_BOUND_ERR_CH2_F PBL_BOUND_ERR_CH2_V(1U)
+
+#define PBL_BOUND_ERR_CH1_S 29
+#define PBL_BOUND_ERR_CH1_V(x) ((x) << PBL_BOUND_ERR_CH1_S)
+#define PBL_BOUND_ERR_CH1_F PBL_BOUND_ERR_CH1_V(1U)
+
+#define PBL_BOUND_ERR_CH0_S 28
+#define PBL_BOUND_ERR_CH0_V(x) ((x) << PBL_BOUND_ERR_CH0_S)
+#define PBL_BOUND_ERR_CH0_F PBL_BOUND_ERR_CH0_V(1U)
+
+#define PM_RX_INT_CAUSE_A 0x8fdc
+#define PM_RX_STAT_CONFIG_A 0x8fc8
+#define PM_RX_STAT_COUNT_A 0x8fcc
+#define PM_RX_STAT_LSB_A 0x8fd0
+#define PM_RX_DBG_CTRL_A 0x8fd0
+#define PM_RX_DBG_DATA_A 0x8fd4
+#define PM_RX_DBG_STAT_MSB_A 0x10013
+
+#define PMRX_FRAMING_ERROR_F 0x003ffff0U
+
+#define ZERO_E_CMD_ERROR_S 22
+#define ZERO_E_CMD_ERROR_V(x) ((x) << ZERO_E_CMD_ERROR_S)
+#define ZERO_E_CMD_ERROR_F ZERO_E_CMD_ERROR_V(1U)
+
+#define OCSPI_PAR_ERROR_S 3
+#define OCSPI_PAR_ERROR_V(x) ((x) << OCSPI_PAR_ERROR_S)
+#define OCSPI_PAR_ERROR_F OCSPI_PAR_ERROR_V(1U)
+
+#define DB_OPTIONS_PAR_ERROR_S 2
+#define DB_OPTIONS_PAR_ERROR_V(x) ((x) << DB_OPTIONS_PAR_ERROR_S)
+#define DB_OPTIONS_PAR_ERROR_F DB_OPTIONS_PAR_ERROR_V(1U)
+
+#define IESPI_PAR_ERROR_S 1
+#define IESPI_PAR_ERROR_V(x) ((x) << IESPI_PAR_ERROR_S)
+#define IESPI_PAR_ERROR_F IESPI_PAR_ERROR_V(1U)
+
+#define PMRX_E_PCMD_PAR_ERROR_S 0
+#define PMRX_E_PCMD_PAR_ERROR_V(x) ((x) << PMRX_E_PCMD_PAR_ERROR_S)
+#define PMRX_E_PCMD_PAR_ERROR_F PMRX_E_PCMD_PAR_ERROR_V(1U)
+
+#define PM_TX_INT_CAUSE_A 0x8ffc
+#define PM_TX_STAT_CONFIG_A 0x8fe8
+#define PM_TX_STAT_COUNT_A 0x8fec
+#define PM_TX_STAT_LSB_A 0x8ff0
+#define PM_TX_DBG_CTRL_A 0x8ff0
+#define PM_TX_DBG_DATA_A 0x8ff4
+#define PM_TX_DBG_STAT_MSB_A 0x1001a
+
+#define PCMD_LEN_OVFL0_S 31
+#define PCMD_LEN_OVFL0_V(x) ((x) << PCMD_LEN_OVFL0_S)
+#define PCMD_LEN_OVFL0_F PCMD_LEN_OVFL0_V(1U)
+
+#define PCMD_LEN_OVFL1_S 30
+#define PCMD_LEN_OVFL1_V(x) ((x) << PCMD_LEN_OVFL1_S)
+#define PCMD_LEN_OVFL1_F PCMD_LEN_OVFL1_V(1U)
+
+#define PCMD_LEN_OVFL2_S 29
+#define PCMD_LEN_OVFL2_V(x) ((x) << PCMD_LEN_OVFL2_S)
+#define PCMD_LEN_OVFL2_F PCMD_LEN_OVFL2_V(1U)
+
+#define ZERO_C_CMD_ERROR_S 28
+#define ZERO_C_CMD_ERROR_V(x) ((x) << ZERO_C_CMD_ERROR_S)
+#define ZERO_C_CMD_ERROR_F ZERO_C_CMD_ERROR_V(1U)
+
+#define PMTX_FRAMING_ERROR_F 0x0ffffff0U
+
+#define OESPI_PAR_ERROR_S 3
+#define OESPI_PAR_ERROR_V(x) ((x) << OESPI_PAR_ERROR_S)
+#define OESPI_PAR_ERROR_F OESPI_PAR_ERROR_V(1U)
+
+#define ICSPI_PAR_ERROR_S 1
+#define ICSPI_PAR_ERROR_V(x) ((x) << ICSPI_PAR_ERROR_S)
+#define ICSPI_PAR_ERROR_F ICSPI_PAR_ERROR_V(1U)
+
+#define PMTX_C_PCMD_PAR_ERROR_S 0
+#define PMTX_C_PCMD_PAR_ERROR_V(x) ((x) << PMTX_C_PCMD_PAR_ERROR_S)
+#define PMTX_C_PCMD_PAR_ERROR_F PMTX_C_PCMD_PAR_ERROR_V(1U)
#define MPS_PORT_STAT_TX_PORT_BYTES_L 0x400
#define MPS_PORT_STAT_TX_PORT_BYTES_H 0x404
@@ -959,41 +1623,57 @@
#define MPS_PORT_STAT_RX_PORT_PPP7_H 0x60c
#define MPS_PORT_STAT_RX_PORT_LESS_64B_L 0x610
#define MPS_PORT_STAT_RX_PORT_LESS_64B_H 0x614
-#define MAC_PORT_CFG2 0x818
#define MAC_PORT_MAGIC_MACID_LO 0x824
#define MAC_PORT_MAGIC_MACID_HI 0x828
-#define MAC_PORT_EPIO_DATA0 0x8c0
-#define MAC_PORT_EPIO_DATA1 0x8c4
-#define MAC_PORT_EPIO_DATA2 0x8c8
-#define MAC_PORT_EPIO_DATA3 0x8cc
-#define MAC_PORT_EPIO_OP 0x8d0
-
-#define MPS_CMN_CTL 0x9000
-#define NUMPORTS_MASK 0x00000003U
-#define NUMPORTS_SHIFT 0
-#define NUMPORTS_GET(x) (((x) & NUMPORTS_MASK) >> NUMPORTS_SHIFT)
-
-#define MPS_INT_CAUSE 0x9008
-#define STATINT 0x00000020U
-#define TXINT 0x00000010U
-#define RXINT 0x00000008U
-#define TRCINT 0x00000004U
-#define CLSINT 0x00000002U
-#define PLINT 0x00000001U
-
-#define MPS_TX_INT_CAUSE 0x9408
-#define PORTERR 0x00010000U
-#define FRMERR 0x00008000U
-#define SECNTERR 0x00004000U
-#define BUBBLE 0x00002000U
-#define TXDESCFIFO 0x00001e00U
-#define TXDATAFIFO 0x000001e0U
-#define NCSIFIFO 0x00000010U
-#define TPFIFO 0x0000000fU
-
-#define MPS_STAT_PERR_INT_CAUSE_SRAM 0x9614
-#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO 0x9620
-#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO 0x962c
+
+#define MAC_PORT_EPIO_DATA0_A 0x8c0
+#define MAC_PORT_EPIO_DATA1_A 0x8c4
+#define MAC_PORT_EPIO_DATA2_A 0x8c8
+#define MAC_PORT_EPIO_DATA3_A 0x8cc
+#define MAC_PORT_EPIO_OP_A 0x8d0
+
+#define MAC_PORT_CFG2_A 0x818
+
+#define MPS_CMN_CTL_A 0x9000
+
+#define NUMPORTS_S 0
+#define NUMPORTS_M 0x3U
+#define NUMPORTS_G(x) (((x) >> NUMPORTS_S) & NUMPORTS_M)
+
+#define MPS_INT_CAUSE_A 0x9008
+#define MPS_TX_INT_CAUSE_A 0x9408
+
+#define FRMERR_S 15
+#define FRMERR_V(x) ((x) << FRMERR_S)
+#define FRMERR_F FRMERR_V(1U)
+
+#define SECNTERR_S 14
+#define SECNTERR_V(x) ((x) << SECNTERR_S)
+#define SECNTERR_F SECNTERR_V(1U)
+
+#define BUBBLE_S 13
+#define BUBBLE_V(x) ((x) << BUBBLE_S)
+#define BUBBLE_F BUBBLE_V(1U)
+
+#define TXDESCFIFO_S 9
+#define TXDESCFIFO_M 0xfU
+#define TXDESCFIFO_V(x) ((x) << TXDESCFIFO_S)
+
+#define TXDATAFIFO_S 5
+#define TXDATAFIFO_M 0xfU
+#define TXDATAFIFO_V(x) ((x) << TXDATAFIFO_S)
+
+#define NCSIFIFO_S 4
+#define NCSIFIFO_V(x) ((x) << NCSIFIFO_S)
+#define NCSIFIFO_F NCSIFIFO_V(1U)
+
+#define TPFIFO_S 0
+#define TPFIFO_M 0xfU
+#define TPFIFO_V(x) ((x) << TPFIFO_S)
+
+#define MPS_STAT_PERR_INT_CAUSE_SRAM_A 0x9614
+#define MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A 0x9620
+#define MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A 0x962c
#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_L 0x9640
#define MPS_STAT_RX_BG_0_MAC_DROP_FRAME_H 0x9644
@@ -1027,294 +1707,851 @@
#define MPS_STAT_RX_BG_2_LB_TRUNC_FRAME_H 0x96b4
#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_L 0x96b8
#define MPS_STAT_RX_BG_3_LB_TRUNC_FRAME_H 0x96bc
-#define MPS_TRC_CFG 0x9800
-#define TRCFIFOEMPTY 0x00000010U
-#define TRCIGNOREDROPINPUT 0x00000008U
-#define TRCKEEPDUPLICATES 0x00000004U
-#define TRCEN 0x00000002U
-#define TRCMULTIFILTER 0x00000001U
-
-#define MPS_TRC_RSS_CONTROL 0x9808
-#define MPS_T5_TRC_RSS_CONTROL 0xa00c
-#define RSSCONTROL_MASK 0x00ff0000U
-#define RSSCONTROL_SHIFT 16
-#define RSSCONTROL(x) ((x) << RSSCONTROL_SHIFT)
-#define QUEUENUMBER_MASK 0x0000ffffU
-#define QUEUENUMBER_SHIFT 0
-#define QUEUENUMBER(x) ((x) << QUEUENUMBER_SHIFT)
-
-#define MPS_TRC_FILTER_MATCH_CTL_A 0x9810
-#define TFINVERTMATCH 0x01000000U
-#define TFPKTTOOLARGE 0x00800000U
-#define TFEN 0x00400000U
-#define TFPORT_MASK 0x003c0000U
-#define TFPORT_SHIFT 18
-#define TFPORT(x) ((x) << TFPORT_SHIFT)
-#define TFPORT_GET(x) (((x) & TFPORT_MASK) >> TFPORT_SHIFT)
-#define TFDROP 0x00020000U
-#define TFSOPEOPERR 0x00010000U
-#define TFLENGTH_MASK 0x00001f00U
-#define TFLENGTH_SHIFT 8
-#define TFLENGTH(x) ((x) << TFLENGTH_SHIFT)
-#define TFLENGTH_GET(x) (((x) & TFLENGTH_MASK) >> TFLENGTH_SHIFT)
-#define TFOFFSET_MASK 0x0000001fU
-#define TFOFFSET_SHIFT 0
-#define TFOFFSET(x) ((x) << TFOFFSET_SHIFT)
-#define TFOFFSET_GET(x) (((x) & TFOFFSET_MASK) >> TFOFFSET_SHIFT)
-
-#define MPS_TRC_FILTER_MATCH_CTL_B 0x9820
-#define TFMINPKTSIZE_MASK 0x01ff0000U
-#define TFMINPKTSIZE_SHIFT 16
-#define TFMINPKTSIZE(x) ((x) << TFMINPKTSIZE_SHIFT)
-#define TFMINPKTSIZE_GET(x) (((x) & TFMINPKTSIZE_MASK) >> TFMINPKTSIZE_SHIFT)
-#define TFCAPTUREMAX_MASK 0x00003fffU
-#define TFCAPTUREMAX_SHIFT 0
-#define TFCAPTUREMAX(x) ((x) << TFCAPTUREMAX_SHIFT)
-#define TFCAPTUREMAX_GET(x) (((x) & TFCAPTUREMAX_MASK) >> TFCAPTUREMAX_SHIFT)
-
-#define MPS_TRC_INT_CAUSE 0x985c
-#define MISCPERR 0x00000100U
-#define PKTFIFO 0x000000f0U
-#define FILTMEM 0x0000000fU
-
-#define MPS_TRC_FILTER0_MATCH 0x9c00
-#define MPS_TRC_FILTER0_DONT_CARE 0x9c80
-#define MPS_TRC_FILTER1_MATCH 0x9d00
-#define MPS_CLS_INT_CAUSE 0xd028
-#define PLERRENB 0x00000008U
-#define HASHSRAM 0x00000004U
-#define MATCHTCAM 0x00000002U
-#define MATCHSRAM 0x00000001U
-
-#define MPS_RX_PERR_INT_CAUSE 0x11074
-
-#define CPL_INTR_CAUSE 0x19054
-#define CIM_OP_MAP_PERR 0x00000020U
-#define CIM_OVFL_ERROR 0x00000010U
-#define TP_FRAMING_ERROR 0x00000008U
-#define SGE_FRAMING_ERROR 0x00000004U
-#define CIM_FRAMING_ERROR 0x00000002U
-#define ZERO_SWITCH_ERROR 0x00000001U
-
-#define SMB_INT_CAUSE 0x19090
-#define MSTTXFIFOPARINT 0x00200000U
-#define MSTRXFIFOPARINT 0x00100000U
-#define SLVFIFOPARINT 0x00080000U
-
-#define ULP_RX_INT_CAUSE 0x19158
-#define ULP_RX_ISCSI_TAGMASK 0x19164
-#define ULP_RX_ISCSI_PSZ 0x19168
-#define HPZ3_MASK 0x0f000000U
-#define HPZ3_SHIFT 24
-#define HPZ3(x) ((x) << HPZ3_SHIFT)
-#define HPZ2_MASK 0x000f0000U
-#define HPZ2_SHIFT 16
-#define HPZ2(x) ((x) << HPZ2_SHIFT)
-#define HPZ1_MASK 0x00000f00U
-#define HPZ1_SHIFT 8
-#define HPZ1(x) ((x) << HPZ1_SHIFT)
-#define HPZ0_MASK 0x0000000fU
-#define HPZ0_SHIFT 0
-#define HPZ0(x) ((x) << HPZ0_SHIFT)
-
-#define ULP_RX_TDDP_PSZ 0x19178
-
-#define SF_DATA 0x193f8
-#define SF_OP 0x193fc
-#define SF_BUSY 0x80000000U
-#define SF_LOCK 0x00000010U
-#define SF_CONT 0x00000008U
-#define BYTECNT_MASK 0x00000006U
-#define BYTECNT_SHIFT 1
-#define BYTECNT(x) ((x) << BYTECNT_SHIFT)
-#define OP_WR 0x00000001U
-
-#define PL_PF_INT_CAUSE 0x3c0
-#define PFSW 0x00000008U
-#define PFSGE 0x00000004U
-#define PFCIM 0x00000002U
-#define PFMPS 0x00000001U
-
-#define PL_PF_INT_ENABLE 0x3c4
-#define PL_PF_CTL 0x3c8
-#define SWINT 0x00000001U
-
-#define PL_WHOAMI 0x19400
-#define SOURCEPF_MASK 0x00000700U
-#define SOURCEPF_SHIFT 8
-#define SOURCEPF(x) ((x) << SOURCEPF_SHIFT)
-#define SOURCEPF_GET(x) (((x) & SOURCEPF_MASK) >> SOURCEPF_SHIFT)
-#define ISVF 0x00000080U
-#define VFID_MASK 0x0000007fU
-#define VFID_SHIFT 0
-#define VFID(x) ((x) << VFID_SHIFT)
-#define VFID_GET(x) (((x) & VFID_MASK) >> VFID_SHIFT)
-
-#define PL_INT_CAUSE 0x1940c
-#define ULP_TX 0x08000000U
-#define SGE 0x04000000U
-#define HMA 0x02000000U
-#define CPL_SWITCH 0x01000000U
-#define ULP_RX 0x00800000U
-#define PM_RX 0x00400000U
-#define PM_TX 0x00200000U
-#define MA 0x00100000U
-#define TP 0x00080000U
-#define LE 0x00040000U
-#define EDC1 0x00020000U
-#define EDC0 0x00010000U
-#define MC 0x00008000U
-#define PCIE 0x00004000U
-#define PMU 0x00002000U
-#define XGMAC_KR1 0x00001000U
-#define XGMAC_KR0 0x00000800U
-#define XGMAC1 0x00000400U
-#define XGMAC0 0x00000200U
-#define SMB 0x00000100U
-#define SF 0x00000080U
-#define PL 0x00000040U
-#define NCSI 0x00000020U
-#define MPS 0x00000010U
-#define MI 0x00000008U
-#define DBG 0x00000004U
-#define I2CM 0x00000002U
-#define CIM 0x00000001U
-
-#define MC1 0x31
-#define PL_INT_ENABLE 0x19410
-#define PL_INT_MAP0 0x19414
-#define PL_RST 0x19428
-#define PIORST 0x00000002U
-#define PIORSTMODE 0x00000001U
-
-#define PL_PL_INT_CAUSE 0x19430
-#define FATALPERR 0x00000010U
-#define PERRVFID 0x00000001U
-
-#define PL_REV 0x1943c
-
-#define S_REV 0
-#define M_REV 0xfU
-#define V_REV(x) ((x) << S_REV)
-#define G_REV(x) (((x) >> S_REV) & M_REV)
-
-#define LE_DB_CONFIG 0x19c04
-#define HASHEN 0x00100000U
-
-#define LE_DB_SERVER_INDEX 0x19c18
-#define LE_DB_ACT_CNT_IPV4 0x19c20
-#define LE_DB_ACT_CNT_IPV6 0x19c24
-
-#define LE_DB_INT_CAUSE 0x19c3c
-#define REQQPARERR 0x00010000U
-#define UNKNOWNCMD 0x00008000U
-#define PARITYERR 0x00000040U
-#define LIPMISS 0x00000020U
-#define LIP0 0x00000010U
-
-#define LE_DB_TID_HASHBASE 0x19df8
-
-#define NCSI_INT_CAUSE 0x1a0d8
-#define CIM_DM_PRTY_ERR 0x00000100U
-#define MPS_DM_PRTY_ERR 0x00000080U
-#define TXFIFO_PRTY_ERR 0x00000002U
-#define RXFIFO_PRTY_ERR 0x00000001U
-
-#define XGMAC_PORT_CFG2 0x1018
-#define PATEN 0x00040000U
-#define MAGICEN 0x00020000U
-#define XGMAC_PORT_MAGIC_MACID_LO 0x1024
-#define XGMAC_PORT_MAGIC_MACID_HI 0x1028
+#define MPS_TRC_CFG_A 0x9800
+
+#define TRCFIFOEMPTY_S 4
+#define TRCFIFOEMPTY_V(x) ((x) << TRCFIFOEMPTY_S)
+#define TRCFIFOEMPTY_F TRCFIFOEMPTY_V(1U)
+
+#define TRCIGNOREDROPINPUT_S 3
+#define TRCIGNOREDROPINPUT_V(x) ((x) << TRCIGNOREDROPINPUT_S)
+#define TRCIGNOREDROPINPUT_F TRCIGNOREDROPINPUT_V(1U)
+
+#define TRCKEEPDUPLICATES_S 2
+#define TRCKEEPDUPLICATES_V(x) ((x) << TRCKEEPDUPLICATES_S)
+#define TRCKEEPDUPLICATES_F TRCKEEPDUPLICATES_V(1U)
+
+#define TRCEN_S 1
+#define TRCEN_V(x) ((x) << TRCEN_S)
+#define TRCEN_F TRCEN_V(1U)
+
+#define TRCMULTIFILTER_S 0
+#define TRCMULTIFILTER_V(x) ((x) << TRCMULTIFILTER_S)
+#define TRCMULTIFILTER_F TRCMULTIFILTER_V(1U)
+
+#define MPS_TRC_RSS_CONTROL_A 0x9808
+#define MPS_T5_TRC_RSS_CONTROL_A 0xa00c
+
+#define RSSCONTROL_S 16
+#define RSSCONTROL_V(x) ((x) << RSSCONTROL_S)
+
+#define QUEUENUMBER_S 0
+#define QUEUENUMBER_V(x) ((x) << QUEUENUMBER_S)
+
+#define TP_RSS_CONFIG_A 0x7df0
+
+#define TNL4TUPENIPV6_S 31
+#define TNL4TUPENIPV6_V(x) ((x) << TNL4TUPENIPV6_S)
+#define TNL4TUPENIPV6_F TNL4TUPENIPV6_V(1U)
+
+#define TNL2TUPENIPV6_S 30
+#define TNL2TUPENIPV6_V(x) ((x) << TNL2TUPENIPV6_S)
+#define TNL2TUPENIPV6_F TNL2TUPENIPV6_V(1U)
+
+#define TNL4TUPENIPV4_S 29
+#define TNL4TUPENIPV4_V(x) ((x) << TNL4TUPENIPV4_S)
+#define TNL4TUPENIPV4_F TNL4TUPENIPV4_V(1U)
+
+#define TNL2TUPENIPV4_S 28
+#define TNL2TUPENIPV4_V(x) ((x) << TNL2TUPENIPV4_S)
+#define TNL2TUPENIPV4_F TNL2TUPENIPV4_V(1U)
+
+#define TNLTCPSEL_S 27
+#define TNLTCPSEL_V(x) ((x) << TNLTCPSEL_S)
+#define TNLTCPSEL_F TNLTCPSEL_V(1U)
+
+#define TNLIP6SEL_S 26
+#define TNLIP6SEL_V(x) ((x) << TNLIP6SEL_S)
+#define TNLIP6SEL_F TNLIP6SEL_V(1U)
+
+#define TNLVRTSEL_S 25
+#define TNLVRTSEL_V(x) ((x) << TNLVRTSEL_S)
+#define TNLVRTSEL_F TNLVRTSEL_V(1U)
+
+#define TNLMAPEN_S 24
+#define TNLMAPEN_V(x) ((x) << TNLMAPEN_S)
+#define TNLMAPEN_F TNLMAPEN_V(1U)
+
+#define OFDHASHSAVE_S 19
+#define OFDHASHSAVE_V(x) ((x) << OFDHASHSAVE_S)
+#define OFDHASHSAVE_F OFDHASHSAVE_V(1U)
+
+#define OFDVRTSEL_S 18
+#define OFDVRTSEL_V(x) ((x) << OFDVRTSEL_S)
+#define OFDVRTSEL_F OFDVRTSEL_V(1U)
+
+#define OFDMAPEN_S 17
+#define OFDMAPEN_V(x) ((x) << OFDMAPEN_S)
+#define OFDMAPEN_F OFDMAPEN_V(1U)
+
+#define OFDLKPEN_S 16
+#define OFDLKPEN_V(x) ((x) << OFDLKPEN_S)
+#define OFDLKPEN_F OFDLKPEN_V(1U)
+
+#define SYN4TUPENIPV6_S 15
+#define SYN4TUPENIPV6_V(x) ((x) << SYN4TUPENIPV6_S)
+#define SYN4TUPENIPV6_F SYN4TUPENIPV6_V(1U)
+
+#define SYN2TUPENIPV6_S 14
+#define SYN2TUPENIPV6_V(x) ((x) << SYN2TUPENIPV6_S)
+#define SYN2TUPENIPV6_F SYN2TUPENIPV6_V(1U)
+
+#define SYN4TUPENIPV4_S 13
+#define SYN4TUPENIPV4_V(x) ((x) << SYN4TUPENIPV4_S)
+#define SYN4TUPENIPV4_F SYN4TUPENIPV4_V(1U)
+
+#define SYN2TUPENIPV4_S 12
+#define SYN2TUPENIPV4_V(x) ((x) << SYN2TUPENIPV4_S)
+#define SYN2TUPENIPV4_F SYN2TUPENIPV4_V(1U)
+
+#define SYNIP6SEL_S 11
+#define SYNIP6SEL_V(x) ((x) << SYNIP6SEL_S)
+#define SYNIP6SEL_F SYNIP6SEL_V(1U)
+
+#define SYNVRTSEL_S 10
+#define SYNVRTSEL_V(x) ((x) << SYNVRTSEL_S)
+#define SYNVRTSEL_F SYNVRTSEL_V(1U)
+
+#define SYNMAPEN_S 9
+#define SYNMAPEN_V(x) ((x) << SYNMAPEN_S)
+#define SYNMAPEN_F SYNMAPEN_V(1U)
+
+#define SYNLKPEN_S 8
+#define SYNLKPEN_V(x) ((x) << SYNLKPEN_S)
+#define SYNLKPEN_F SYNLKPEN_V(1U)
+
+#define CHANNELENABLE_S 7
+#define CHANNELENABLE_V(x) ((x) << CHANNELENABLE_S)
+#define CHANNELENABLE_F CHANNELENABLE_V(1U)
+
+#define PORTENABLE_S 6
+#define PORTENABLE_V(x) ((x) << PORTENABLE_S)
+#define PORTENABLE_F PORTENABLE_V(1U)
+
+#define TNLALLLOOKUP_S 5
+#define TNLALLLOOKUP_V(x) ((x) << TNLALLLOOKUP_S)
+#define TNLALLLOOKUP_F TNLALLLOOKUP_V(1U)
+
+#define VIRTENABLE_S 4
+#define VIRTENABLE_V(x) ((x) << VIRTENABLE_S)
+#define VIRTENABLE_F VIRTENABLE_V(1U)
+
+#define CONGESTIONENABLE_S 3
+#define CONGESTIONENABLE_V(x) ((x) << CONGESTIONENABLE_S)
+#define CONGESTIONENABLE_F CONGESTIONENABLE_V(1U)
+
+#define HASHTOEPLITZ_S 2
+#define HASHTOEPLITZ_V(x) ((x) << HASHTOEPLITZ_S)
+#define HASHTOEPLITZ_F HASHTOEPLITZ_V(1U)
+
+#define UDPENABLE_S 1
+#define UDPENABLE_V(x) ((x) << UDPENABLE_S)
+#define UDPENABLE_F UDPENABLE_V(1U)
+
+#define DISABLE_S 0
+#define DISABLE_V(x) ((x) << DISABLE_S)
+#define DISABLE_F DISABLE_V(1U)
+
+#define TP_RSS_CONFIG_TNL_A 0x7df4
+
+#define MASKSIZE_S 28
+#define MASKSIZE_M 0xfU
+#define MASKSIZE_V(x) ((x) << MASKSIZE_S)
+#define MASKSIZE_G(x) (((x) >> MASKSIZE_S) & MASKSIZE_M)
+
+#define MASKFILTER_S 16
+#define MASKFILTER_M 0x7ffU
+#define MASKFILTER_V(x) ((x) << MASKFILTER_S)
+#define MASKFILTER_G(x) (((x) >> MASKFILTER_S) & MASKFILTER_M)
+
+#define USEWIRECH_S 0
+#define USEWIRECH_V(x) ((x) << USEWIRECH_S)
+#define USEWIRECH_F USEWIRECH_V(1U)
+
+#define HASHALL_S 2
+#define HASHALL_V(x) ((x) << HASHALL_S)
+#define HASHALL_F HASHALL_V(1U)
+
+#define HASHETH_S 1
+#define HASHETH_V(x) ((x) << HASHETH_S)
+#define HASHETH_F HASHETH_V(1U)
+
+#define TP_RSS_CONFIG_OFD_A 0x7df8
+
+#define RRCPLMAPEN_S 20
+#define RRCPLMAPEN_V(x) ((x) << RRCPLMAPEN_S)
+#define RRCPLMAPEN_F RRCPLMAPEN_V(1U)
+
+#define RRCPLQUEWIDTH_S 16
+#define RRCPLQUEWIDTH_M 0xfU
+#define RRCPLQUEWIDTH_V(x) ((x) << RRCPLQUEWIDTH_S)
+#define RRCPLQUEWIDTH_G(x) (((x) >> RRCPLQUEWIDTH_S) & RRCPLQUEWIDTH_M)
+
+#define TP_RSS_CONFIG_SYN_A 0x7dfc
+#define TP_RSS_CONFIG_VRT_A 0x7e00
+
+#define VFRDRG_S 25
+#define VFRDRG_V(x) ((x) << VFRDRG_S)
+#define VFRDRG_F VFRDRG_V(1U)
+
+#define VFRDEN_S 24
+#define VFRDEN_V(x) ((x) << VFRDEN_S)
+#define VFRDEN_F VFRDEN_V(1U)
+
+#define VFPERREN_S 23
+#define VFPERREN_V(x) ((x) << VFPERREN_S)
+#define VFPERREN_F VFPERREN_V(1U)
+
+#define KEYPERREN_S 22
+#define KEYPERREN_V(x) ((x) << KEYPERREN_S)
+#define KEYPERREN_F KEYPERREN_V(1U)
+
+#define DISABLEVLAN_S 21
+#define DISABLEVLAN_V(x) ((x) << DISABLEVLAN_S)
+#define DISABLEVLAN_F DISABLEVLAN_V(1U)
+
+#define ENABLEUP0_S 20
+#define ENABLEUP0_V(x) ((x) << ENABLEUP0_S)
+#define ENABLEUP0_F ENABLEUP0_V(1U)
+
+#define HASHDELAY_S 16
+#define HASHDELAY_M 0xfU
+#define HASHDELAY_V(x) ((x) << HASHDELAY_S)
+#define HASHDELAY_G(x) (((x) >> HASHDELAY_S) & HASHDELAY_M)
+
+#define VFWRADDR_S 8
+#define VFWRADDR_M 0x7fU
+#define VFWRADDR_V(x) ((x) << VFWRADDR_S)
+#define VFWRADDR_G(x) (((x) >> VFWRADDR_S) & VFWRADDR_M)
+
+#define KEYMODE_S 6
+#define KEYMODE_M 0x3U
+#define KEYMODE_V(x) ((x) << KEYMODE_S)
+#define KEYMODE_G(x) (((x) >> KEYMODE_S) & KEYMODE_M)
+
+#define VFWREN_S 5
+#define VFWREN_V(x) ((x) << VFWREN_S)
+#define VFWREN_F VFWREN_V(1U)
+
+#define KEYWREN_S 4
+#define KEYWREN_V(x) ((x) << KEYWREN_S)
+#define KEYWREN_F KEYWREN_V(1U)
+
+#define KEYWRADDR_S 0
+#define KEYWRADDR_M 0xfU
+#define KEYWRADDR_V(x) ((x) << KEYWRADDR_S)
+#define KEYWRADDR_G(x) (((x) >> KEYWRADDR_S) & KEYWRADDR_M)
+
+#define KEYWRADDRX_S 30
+#define KEYWRADDRX_M 0x3U
+#define KEYWRADDRX_V(x) ((x) << KEYWRADDRX_S)
+#define KEYWRADDRX_G(x) (((x) >> KEYWRADDRX_S) & KEYWRADDRX_M)
+
+#define KEYEXTEND_S 26
+#define KEYEXTEND_V(x) ((x) << KEYEXTEND_S)
+#define KEYEXTEND_F KEYEXTEND_V(1U)
+
+#define LKPIDXSIZE_S 24
+#define LKPIDXSIZE_M 0x3U
+#define LKPIDXSIZE_V(x) ((x) << LKPIDXSIZE_S)
+#define LKPIDXSIZE_G(x) (((x) >> LKPIDXSIZE_S) & LKPIDXSIZE_M)
+
+#define TP_RSS_VFL_CONFIG_A 0x3a
+#define TP_RSS_VFH_CONFIG_A 0x3b
+
+#define ENABLEUDPHASH_S 31
+#define ENABLEUDPHASH_V(x) ((x) << ENABLEUDPHASH_S)
+#define ENABLEUDPHASH_F ENABLEUDPHASH_V(1U)
+
+#define VFUPEN_S 30
+#define VFUPEN_V(x) ((x) << VFUPEN_S)
+#define VFUPEN_F VFUPEN_V(1U)
+
+#define VFVLNEX_S 28
+#define VFVLNEX_V(x) ((x) << VFVLNEX_S)
+#define VFVLNEX_F VFVLNEX_V(1U)
+
+#define VFPRTEN_S 27
+#define VFPRTEN_V(x) ((x) << VFPRTEN_S)
+#define VFPRTEN_F VFPRTEN_V(1U)
+
+#define VFCHNEN_S 26
+#define VFCHNEN_V(x) ((x) << VFCHNEN_S)
+#define VFCHNEN_F VFCHNEN_V(1U)
+
+#define DEFAULTQUEUE_S 16
+#define DEFAULTQUEUE_M 0x3ffU
+#define DEFAULTQUEUE_G(x) (((x) >> DEFAULTQUEUE_S) & DEFAULTQUEUE_M)
+
+#define VFIP6TWOTUPEN_S 6
+#define VFIP6TWOTUPEN_V(x) ((x) << VFIP6TWOTUPEN_S)
+#define VFIP6TWOTUPEN_F VFIP6TWOTUPEN_V(1U)
+
+#define VFIP4FOURTUPEN_S 5
+#define VFIP4FOURTUPEN_V(x) ((x) << VFIP4FOURTUPEN_S)
+#define VFIP4FOURTUPEN_F VFIP4FOURTUPEN_V(1U)
+
+#define VFIP4TWOTUPEN_S 4
+#define VFIP4TWOTUPEN_V(x) ((x) << VFIP4TWOTUPEN_S)
+#define VFIP4TWOTUPEN_F VFIP4TWOTUPEN_V(1U)
+
+#define KEYINDEX_S 0
+#define KEYINDEX_M 0xfU
+#define KEYINDEX_G(x) (((x) >> KEYINDEX_S) & KEYINDEX_M)
+
+#define MAPENABLE_S 31
+#define MAPENABLE_V(x) ((x) << MAPENABLE_S)
+#define MAPENABLE_F MAPENABLE_V(1U)
+
+#define CHNENABLE_S 30
+#define CHNENABLE_V(x) ((x) << CHNENABLE_S)
+#define CHNENABLE_F CHNENABLE_V(1U)
+
+#define PRTENABLE_S 29
+#define PRTENABLE_V(x) ((x) << PRTENABLE_S)
+#define PRTENABLE_F PRTENABLE_V(1U)
+
+#define UDPFOURTUPEN_S 28
+#define UDPFOURTUPEN_V(x) ((x) << UDPFOURTUPEN_S)
+#define UDPFOURTUPEN_F UDPFOURTUPEN_V(1U)
+
+#define IP6FOURTUPEN_S 27
+#define IP6FOURTUPEN_V(x) ((x) << IP6FOURTUPEN_S)
+#define IP6FOURTUPEN_F IP6FOURTUPEN_V(1U)
-#define XGMAC_PORT_EPIO_DATA0 0x10c0
-#define XGMAC_PORT_EPIO_DATA1 0x10c4
-#define XGMAC_PORT_EPIO_DATA2 0x10c8
-#define XGMAC_PORT_EPIO_DATA3 0x10cc
-#define XGMAC_PORT_EPIO_OP 0x10d0
-#define EPIOWR 0x00000100U
-#define ADDRESS_MASK 0x000000ffU
-#define ADDRESS_SHIFT 0
-#define ADDRESS(x) ((x) << ADDRESS_SHIFT)
+#define IP6TWOTUPEN_S 26
+#define IP6TWOTUPEN_V(x) ((x) << IP6TWOTUPEN_S)
+#define IP6TWOTUPEN_F IP6TWOTUPEN_V(1U)
-#define MAC_PORT_INT_CAUSE 0x8dc
-#define XGMAC_PORT_INT_CAUSE 0x10dc
+#define IP4FOURTUPEN_S 25
+#define IP4FOURTUPEN_V(x) ((x) << IP4FOURTUPEN_S)
+#define IP4FOURTUPEN_F IP4FOURTUPEN_V(1U)
-#define A_TP_TX_MOD_QUEUE_REQ_MAP 0x7e28
+#define IP4TWOTUPEN_S 24
+#define IP4TWOTUPEN_V(x) ((x) << IP4TWOTUPEN_S)
+#define IP4TWOTUPEN_F IP4TWOTUPEN_V(1U)
-#define A_TP_TX_MOD_CHANNEL_WEIGHT 0x7e34
+#define IVFWIDTH_S 20
+#define IVFWIDTH_M 0xfU
+#define IVFWIDTH_V(x) ((x) << IVFWIDTH_S)
+#define IVFWIDTH_G(x) (((x) >> IVFWIDTH_S) & IVFWIDTH_M)
-#define S_TX_MOD_QUEUE_REQ_MAP 0
-#define M_TX_MOD_QUEUE_REQ_MAP 0xffffU
-#define V_TX_MOD_QUEUE_REQ_MAP(x) ((x) << S_TX_MOD_QUEUE_REQ_MAP)
+#define CH1DEFAULTQUEUE_S 10
+#define CH1DEFAULTQUEUE_M 0x3ffU
+#define CH1DEFAULTQUEUE_V(x) ((x) << CH1DEFAULTQUEUE_S)
+#define CH1DEFAULTQUEUE_G(x) (((x) >> CH1DEFAULTQUEUE_S) & CH1DEFAULTQUEUE_M)
-#define A_TP_TX_MOD_QUEUE_WEIGHT0 0x7e30
+#define CH0DEFAULTQUEUE_S 0
+#define CH0DEFAULTQUEUE_M 0x3ffU
+#define CH0DEFAULTQUEUE_V(x) ((x) << CH0DEFAULTQUEUE_S)
+#define CH0DEFAULTQUEUE_G(x) (((x) >> CH0DEFAULTQUEUE_S) & CH0DEFAULTQUEUE_M)
-#define S_TX_MODQ_WEIGHT3 24
-#define M_TX_MODQ_WEIGHT3 0xffU
-#define V_TX_MODQ_WEIGHT3(x) ((x) << S_TX_MODQ_WEIGHT3)
+#define VFLKPIDX_S 8
+#define VFLKPIDX_M 0xffU
+#define VFLKPIDX_G(x) (((x) >> VFLKPIDX_S) & VFLKPIDX_M)
-#define S_TX_MODQ_WEIGHT2 16
-#define M_TX_MODQ_WEIGHT2 0xffU
-#define V_TX_MODQ_WEIGHT2(x) ((x) << S_TX_MODQ_WEIGHT2)
+#define TP_RSS_CONFIG_CNG_A 0x7e04
+#define TP_RSS_SECRET_KEY0_A 0x40
+#define TP_RSS_PF0_CONFIG_A 0x30
+#define TP_RSS_PF_MAP_A 0x38
+#define TP_RSS_PF_MSK_A 0x39
-#define S_TX_MODQ_WEIGHT1 8
-#define M_TX_MODQ_WEIGHT1 0xffU
-#define V_TX_MODQ_WEIGHT1(x) ((x) << S_TX_MODQ_WEIGHT1)
+#define PF1LKPIDX_S 3
-#define S_TX_MODQ_WEIGHT0 0
-#define M_TX_MODQ_WEIGHT0 0xffU
-#define V_TX_MODQ_WEIGHT0(x) ((x) << S_TX_MODQ_WEIGHT0)
+#define PF0LKPIDX_M 0x7U
-#define A_TP_TX_SCHED_HDR 0x23
+#define PF1MSKSIZE_S 4
+#define PF1MSKSIZE_M 0xfU
-#define A_TP_TX_SCHED_FIFO 0x24
+#define CHNCOUNT3_S 31
+#define CHNCOUNT3_V(x) ((x) << CHNCOUNT3_S)
+#define CHNCOUNT3_F CHNCOUNT3_V(1U)
-#define A_TP_TX_SCHED_PCMD 0x25
+#define CHNCOUNT2_S 30
+#define CHNCOUNT2_V(x) ((x) << CHNCOUNT2_S)
+#define CHNCOUNT2_F CHNCOUNT2_V(1U)
-#define S_VNIC 11
-#define V_VNIC(x) ((x) << S_VNIC)
-#define F_VNIC V_VNIC(1U)
+#define CHNCOUNT1_S 29
+#define CHNCOUNT1_V(x) ((x) << CHNCOUNT1_S)
+#define CHNCOUNT1_F CHNCOUNT1_V(1U)
-#define S_FRAGMENTATION 9
-#define V_FRAGMENTATION(x) ((x) << S_FRAGMENTATION)
-#define F_FRAGMENTATION V_FRAGMENTATION(1U)
+#define CHNCOUNT0_S 28
+#define CHNCOUNT0_V(x) ((x) << CHNCOUNT0_S)
+#define CHNCOUNT0_F CHNCOUNT0_V(1U)
-#define S_MPSHITTYPE 8
-#define V_MPSHITTYPE(x) ((x) << S_MPSHITTYPE)
-#define F_MPSHITTYPE V_MPSHITTYPE(1U)
+#define CHNUNDFLOW3_S 27
+#define CHNUNDFLOW3_V(x) ((x) << CHNUNDFLOW3_S)
+#define CHNUNDFLOW3_F CHNUNDFLOW3_V(1U)
-#define S_MACMATCH 7
-#define V_MACMATCH(x) ((x) << S_MACMATCH)
-#define F_MACMATCH V_MACMATCH(1U)
+#define CHNUNDFLOW2_S 26
+#define CHNUNDFLOW2_V(x) ((x) << CHNUNDFLOW2_S)
+#define CHNUNDFLOW2_F CHNUNDFLOW2_V(1U)
-#define S_ETHERTYPE 6
-#define V_ETHERTYPE(x) ((x) << S_ETHERTYPE)
-#define F_ETHERTYPE V_ETHERTYPE(1U)
+#define CHNUNDFLOW1_S 25
+#define CHNUNDFLOW1_V(x) ((x) << CHNUNDFLOW1_S)
+#define CHNUNDFLOW1_F CHNUNDFLOW1_V(1U)
-#define S_PROTOCOL 5
-#define V_PROTOCOL(x) ((x) << S_PROTOCOL)
-#define F_PROTOCOL V_PROTOCOL(1U)
+#define CHNUNDFLOW0_S 24
+#define CHNUNDFLOW0_V(x) ((x) << CHNUNDFLOW0_S)
+#define CHNUNDFLOW0_F CHNUNDFLOW0_V(1U)
-#define S_TOS 4
-#define V_TOS(x) ((x) << S_TOS)
-#define F_TOS V_TOS(1U)
+#define RSTCHN3_S 19
+#define RSTCHN3_V(x) ((x) << RSTCHN3_S)
+#define RSTCHN3_F RSTCHN3_V(1U)
-#define S_VLAN 3
-#define V_VLAN(x) ((x) << S_VLAN)
-#define F_VLAN V_VLAN(1U)
+#define RSTCHN2_S 18
+#define RSTCHN2_V(x) ((x) << RSTCHN2_S)
+#define RSTCHN2_F RSTCHN2_V(1U)
-#define S_VNIC_ID 2
-#define V_VNIC_ID(x) ((x) << S_VNIC_ID)
-#define F_VNIC_ID V_VNIC_ID(1U)
+#define RSTCHN1_S 17
+#define RSTCHN1_V(x) ((x) << RSTCHN1_S)
+#define RSTCHN1_F RSTCHN1_V(1U)
-#define S_PORT 1
-#define V_PORT(x) ((x) << S_PORT)
-#define F_PORT V_PORT(1U)
+#define RSTCHN0_S 16
+#define RSTCHN0_V(x) ((x) << RSTCHN0_S)
+#define RSTCHN0_F RSTCHN0_V(1U)
-#define S_FCOE 0
-#define V_FCOE(x) ((x) << S_FCOE)
-#define F_FCOE V_FCOE(1U)
+#define UPDVLD_S 15
+#define UPDVLD_V(x) ((x) << UPDVLD_S)
+#define UPDVLD_F UPDVLD_V(1U)
+
+#define XOFF_S 14
+#define XOFF_V(x) ((x) << XOFF_S)
+#define XOFF_F XOFF_V(1U)
+
+#define UPDCHN3_S 13
+#define UPDCHN3_V(x) ((x) << UPDCHN3_S)
+#define UPDCHN3_F UPDCHN3_V(1U)
+
+#define UPDCHN2_S 12
+#define UPDCHN2_V(x) ((x) << UPDCHN2_S)
+#define UPDCHN2_F UPDCHN2_V(1U)
+
+#define UPDCHN1_S 11
+#define UPDCHN1_V(x) ((x) << UPDCHN1_S)
+#define UPDCHN1_F UPDCHN1_V(1U)
+
+#define UPDCHN0_S 10
+#define UPDCHN0_V(x) ((x) << UPDCHN0_S)
+#define UPDCHN0_F UPDCHN0_V(1U)
+
+#define QUEUE_S 0
+#define QUEUE_M 0x3ffU
+#define QUEUE_V(x) ((x) << QUEUE_S)
+#define QUEUE_G(x) (((x) >> QUEUE_S) & QUEUE_M)
+
+#define MPS_TRC_INT_CAUSE_A 0x985c
+
+#define MISCPERR_S 8
+#define MISCPERR_V(x) ((x) << MISCPERR_S)
+#define MISCPERR_F MISCPERR_V(1U)
+
+#define PKTFIFO_S 4
+#define PKTFIFO_M 0xfU
+#define PKTFIFO_V(x) ((x) << PKTFIFO_S)
+
+#define FILTMEM_S 0
+#define FILTMEM_M 0xfU
+#define FILTMEM_V(x) ((x) << FILTMEM_S)
+
+#define MPS_CLS_INT_CAUSE_A 0xd028
+
+#define HASHSRAM_S 2
+#define HASHSRAM_V(x) ((x) << HASHSRAM_S)
+#define HASHSRAM_F HASHSRAM_V(1U)
+
+#define MATCHTCAM_S 1
+#define MATCHTCAM_V(x) ((x) << MATCHTCAM_S)
+#define MATCHTCAM_F MATCHTCAM_V(1U)
+
+#define MATCHSRAM_S 0
+#define MATCHSRAM_V(x) ((x) << MATCHSRAM_S)
+#define MATCHSRAM_F MATCHSRAM_V(1U)
+
+#define MPS_RX_PERR_INT_CAUSE_A 0x11074
+
+#define MPS_CLS_TCAM_Y_L_A 0xf000
+#define MPS_CLS_TCAM_X_L_A 0xf008
+
+#define MPS_CLS_TCAM_Y_L(idx) (MPS_CLS_TCAM_Y_L_A + (idx) * 16)
+#define NUM_MPS_CLS_TCAM_Y_L_INSTANCES 512
+
+#define MPS_CLS_TCAM_X_L(idx) (MPS_CLS_TCAM_X_L_A + (idx) * 16)
+#define NUM_MPS_CLS_TCAM_X_L_INSTANCES 512
+
+#define MPS_CLS_SRAM_L_A 0xe000
+#define MPS_CLS_SRAM_H_A 0xe004
+
+#define MPS_CLS_SRAM_L(idx) (MPS_CLS_SRAM_L_A + (idx) * 8)
+#define NUM_MPS_CLS_SRAM_L_INSTANCES 336
+
+#define MPS_CLS_SRAM_H(idx) (MPS_CLS_SRAM_H_A + (idx) * 8)
+#define NUM_MPS_CLS_SRAM_H_INSTANCES 336
+
+#define MULTILISTEN0_S 25
+
+#define REPLICATE_S 11
+#define REPLICATE_V(x) ((x) << REPLICATE_S)
+#define REPLICATE_F REPLICATE_V(1U)
+
+#define PF_S 8
+#define PF_M 0x7U
+#define PF_G(x) (((x) >> PF_S) & PF_M)
+
+#define VF_VALID_S 7
+#define VF_VALID_V(x) ((x) << VF_VALID_S)
+#define VF_VALID_F VF_VALID_V(1U)
+
+#define VF_S 0
+#define VF_M 0x7fU
+#define VF_G(x) (((x) >> VF_S) & VF_M)
+
+#define SRAM_PRIO3_S 22
+#define SRAM_PRIO3_M 0x7U
+#define SRAM_PRIO3_G(x) (((x) >> SRAM_PRIO3_S) & SRAM_PRIO3_M)
+
+#define SRAM_PRIO2_S 19
+#define SRAM_PRIO2_M 0x7U
+#define SRAM_PRIO2_G(x) (((x) >> SRAM_PRIO2_S) & SRAM_PRIO2_M)
+
+#define SRAM_PRIO1_S 16
+#define SRAM_PRIO1_M 0x7U
+#define SRAM_PRIO1_G(x) (((x) >> SRAM_PRIO1_S) & SRAM_PRIO1_M)
+
+#define SRAM_PRIO0_S 13
+#define SRAM_PRIO0_M 0x7U
+#define SRAM_PRIO0_G(x) (((x) >> SRAM_PRIO0_S) & SRAM_PRIO0_M)
+
+#define SRAM_VLD_S 12
+#define SRAM_VLD_V(x) ((x) << SRAM_VLD_S)
+#define SRAM_VLD_F SRAM_VLD_V(1U)
+
+#define PORTMAP_S 0
+#define PORTMAP_M 0xfU
+#define PORTMAP_G(x) (((x) >> PORTMAP_S) & PORTMAP_M)
+
+#define CPL_INTR_CAUSE_A 0x19054
+
+#define CIM_OP_MAP_PERR_S 5
+#define CIM_OP_MAP_PERR_V(x) ((x) << CIM_OP_MAP_PERR_S)
+#define CIM_OP_MAP_PERR_F CIM_OP_MAP_PERR_V(1U)
+
+#define CIM_OVFL_ERROR_S 4
+#define CIM_OVFL_ERROR_V(x) ((x) << CIM_OVFL_ERROR_S)
+#define CIM_OVFL_ERROR_F CIM_OVFL_ERROR_V(1U)
+
+#define TP_FRAMING_ERROR_S 3
+#define TP_FRAMING_ERROR_V(x) ((x) << TP_FRAMING_ERROR_S)
+#define TP_FRAMING_ERROR_F TP_FRAMING_ERROR_V(1U)
+
+#define SGE_FRAMING_ERROR_S 2
+#define SGE_FRAMING_ERROR_V(x) ((x) << SGE_FRAMING_ERROR_S)
+#define SGE_FRAMING_ERROR_F SGE_FRAMING_ERROR_V(1U)
+
+#define CIM_FRAMING_ERROR_S 1
+#define CIM_FRAMING_ERROR_V(x) ((x) << CIM_FRAMING_ERROR_S)
+#define CIM_FRAMING_ERROR_F CIM_FRAMING_ERROR_V(1U)
+
+#define ZERO_SWITCH_ERROR_S 0
+#define ZERO_SWITCH_ERROR_V(x) ((x) << ZERO_SWITCH_ERROR_S)
+#define ZERO_SWITCH_ERROR_F ZERO_SWITCH_ERROR_V(1U)
+
+#define SMB_INT_CAUSE_A 0x19090
+
+#define MSTTXFIFOPARINT_S 21
+#define MSTTXFIFOPARINT_V(x) ((x) << MSTTXFIFOPARINT_S)
+#define MSTTXFIFOPARINT_F MSTTXFIFOPARINT_V(1U)
+
+#define MSTRXFIFOPARINT_S 20
+#define MSTRXFIFOPARINT_V(x) ((x) << MSTRXFIFOPARINT_S)
+#define MSTRXFIFOPARINT_F MSTRXFIFOPARINT_V(1U)
+
+#define SLVFIFOPARINT_S 19
+#define SLVFIFOPARINT_V(x) ((x) << SLVFIFOPARINT_S)
+#define SLVFIFOPARINT_F SLVFIFOPARINT_V(1U)
+
+#define ULP_RX_INT_CAUSE_A 0x19158
+#define ULP_RX_ISCSI_TAGMASK_A 0x19164
+#define ULP_RX_ISCSI_PSZ_A 0x19168
+#define ULP_RX_LA_CTL_A 0x1923c
+#define ULP_RX_LA_RDPTR_A 0x19240
+#define ULP_RX_LA_RDDATA_A 0x19244
+#define ULP_RX_LA_WRPTR_A 0x19248
+
+#define HPZ3_S 24
+#define HPZ3_V(x) ((x) << HPZ3_S)
+
+#define HPZ2_S 16
+#define HPZ2_V(x) ((x) << HPZ2_S)
+
+#define HPZ1_S 8
+#define HPZ1_V(x) ((x) << HPZ1_S)
+
+#define HPZ0_S 0
+#define HPZ0_V(x) ((x) << HPZ0_S)
+
+#define ULP_RX_TDDP_PSZ_A 0x19178
+
+/* registers for module SF */
+#define SF_DATA_A 0x193f8
+#define SF_OP_A 0x193fc
+
+#define SF_BUSY_S 31
+#define SF_BUSY_V(x) ((x) << SF_BUSY_S)
+#define SF_BUSY_F SF_BUSY_V(1U)
+
+#define SF_LOCK_S 4
+#define SF_LOCK_V(x) ((x) << SF_LOCK_S)
+#define SF_LOCK_F SF_LOCK_V(1U)
+
+#define SF_CONT_S 3
+#define SF_CONT_V(x) ((x) << SF_CONT_S)
+#define SF_CONT_F SF_CONT_V(1U)
+
+#define BYTECNT_S 1
+#define BYTECNT_V(x) ((x) << BYTECNT_S)
+
+#define OP_S 0
+#define OP_V(x) ((x) << OP_S)
+#define OP_F OP_V(1U)
+
+#define PL_PF_INT_CAUSE_A 0x3c0
+
+#define PFSW_S 3
+#define PFSW_V(x) ((x) << PFSW_S)
+#define PFSW_F PFSW_V(1U)
+
+#define PFCIM_S 1
+#define PFCIM_V(x) ((x) << PFCIM_S)
+#define PFCIM_F PFCIM_V(1U)
+
+#define PL_PF_INT_ENABLE_A 0x3c4
+#define PL_PF_CTL_A 0x3c8
+
+#define PL_WHOAMI_A 0x19400
+
+#define SOURCEPF_S 8
+#define SOURCEPF_M 0x7U
+#define SOURCEPF_G(x) (((x) >> SOURCEPF_S) & SOURCEPF_M)
+
+#define PL_INT_CAUSE_A 0x1940c
+
+#define ULP_TX_S 27
+#define ULP_TX_V(x) ((x) << ULP_TX_S)
+#define ULP_TX_F ULP_TX_V(1U)
+
+#define SGE_S 26
+#define SGE_V(x) ((x) << SGE_S)
+#define SGE_F SGE_V(1U)
+
+#define CPL_SWITCH_S 24
+#define CPL_SWITCH_V(x) ((x) << CPL_SWITCH_S)
+#define CPL_SWITCH_F CPL_SWITCH_V(1U)
+
+#define ULP_RX_S 23
+#define ULP_RX_V(x) ((x) << ULP_RX_S)
+#define ULP_RX_F ULP_RX_V(1U)
+
+#define PM_RX_S 22
+#define PM_RX_V(x) ((x) << PM_RX_S)
+#define PM_RX_F PM_RX_V(1U)
+
+#define PM_TX_S 21
+#define PM_TX_V(x) ((x) << PM_TX_S)
+#define PM_TX_F PM_TX_V(1U)
+
+#define MA_S 20
+#define MA_V(x) ((x) << MA_S)
+#define MA_F MA_V(1U)
+
+#define TP_S 19
+#define TP_V(x) ((x) << TP_S)
+#define TP_F TP_V(1U)
+
+#define LE_S 18
+#define LE_V(x) ((x) << LE_S)
+#define LE_F LE_V(1U)
+
+#define EDC1_S 17
+#define EDC1_V(x) ((x) << EDC1_S)
+#define EDC1_F EDC1_V(1U)
+
+#define EDC0_S 16
+#define EDC0_V(x) ((x) << EDC0_S)
+#define EDC0_F EDC0_V(1U)
+
+#define MC_S 15
+#define MC_V(x) ((x) << MC_S)
+#define MC_F MC_V(1U)
+
+#define PCIE_S 14
+#define PCIE_V(x) ((x) << PCIE_S)
+#define PCIE_F PCIE_V(1U)
+
+#define XGMAC_KR1_S 12
+#define XGMAC_KR1_V(x) ((x) << XGMAC_KR1_S)
+#define XGMAC_KR1_F XGMAC_KR1_V(1U)
+
+#define XGMAC_KR0_S 11
+#define XGMAC_KR0_V(x) ((x) << XGMAC_KR0_S)
+#define XGMAC_KR0_F XGMAC_KR0_V(1U)
+
+#define XGMAC1_S 10
+#define XGMAC1_V(x) ((x) << XGMAC1_S)
+#define XGMAC1_F XGMAC1_V(1U)
+
+#define XGMAC0_S 9
+#define XGMAC0_V(x) ((x) << XGMAC0_S)
+#define XGMAC0_F XGMAC0_V(1U)
+
+#define SMB_S 8
+#define SMB_V(x) ((x) << SMB_S)
+#define SMB_F SMB_V(1U)
+
+#define SF_S 7
+#define SF_V(x) ((x) << SF_S)
+#define SF_F SF_V(1U)
+
+#define PL_S 6
+#define PL_V(x) ((x) << PL_S)
+#define PL_F PL_V(1U)
+
+#define NCSI_S 5
+#define NCSI_V(x) ((x) << NCSI_S)
+#define NCSI_F NCSI_V(1U)
+
+#define MPS_S 4
+#define MPS_V(x) ((x) << MPS_S)
+#define MPS_F MPS_V(1U)
+
+#define CIM_S 0
+#define CIM_V(x) ((x) << CIM_S)
+#define CIM_F CIM_V(1U)
+
+#define MC1_S 31
+
+#define PL_INT_ENABLE_A 0x19410
+#define PL_INT_MAP0_A 0x19414
+#define PL_RST_A 0x19428
+
+#define PIORST_S 1
+#define PIORST_V(x) ((x) << PIORST_S)
+#define PIORST_F PIORST_V(1U)
+
+#define PIORSTMODE_S 0
+#define PIORSTMODE_V(x) ((x) << PIORSTMODE_S)
+#define PIORSTMODE_F PIORSTMODE_V(1U)
+
+#define PL_PL_INT_CAUSE_A 0x19430
+
+#define FATALPERR_S 4
+#define FATALPERR_V(x) ((x) << FATALPERR_S)
+#define FATALPERR_F FATALPERR_V(1U)
+
+#define PERRVFID_S 0
+#define PERRVFID_V(x) ((x) << PERRVFID_S)
+#define PERRVFID_F PERRVFID_V(1U)
+
+#define PL_REV_A 0x1943c
+
+#define REV_S 0
+#define REV_M 0xfU
+#define REV_V(x) ((x) << REV_S)
+#define REV_G(x) (((x) >> REV_S) & REV_M)
+
+#define LE_DB_INT_CAUSE_A 0x19c3c
+
+#define REQQPARERR_S 16
+#define REQQPARERR_V(x) ((x) << REQQPARERR_S)
+#define REQQPARERR_F REQQPARERR_V(1U)
+
+#define UNKNOWNCMD_S 15
+#define UNKNOWNCMD_V(x) ((x) << UNKNOWNCMD_S)
+#define UNKNOWNCMD_F UNKNOWNCMD_V(1U)
+
+#define PARITYERR_S 6
+#define PARITYERR_V(x) ((x) << PARITYERR_S)
+#define PARITYERR_F PARITYERR_V(1U)
+
+#define LIPMISS_S 5
+#define LIPMISS_V(x) ((x) << LIPMISS_S)
+#define LIPMISS_F LIPMISS_V(1U)
+
+#define LIP0_S 4
+#define LIP0_V(x) ((x) << LIP0_S)
+#define LIP0_F LIP0_V(1U)
+
+#define NCSI_INT_CAUSE_A 0x1a0d8
+
+#define CIM_DM_PRTY_ERR_S 8
+#define CIM_DM_PRTY_ERR_V(x) ((x) << CIM_DM_PRTY_ERR_S)
+#define CIM_DM_PRTY_ERR_F CIM_DM_PRTY_ERR_V(1U)
+
+#define MPS_DM_PRTY_ERR_S 7
+#define MPS_DM_PRTY_ERR_V(x) ((x) << MPS_DM_PRTY_ERR_S)
+#define MPS_DM_PRTY_ERR_F MPS_DM_PRTY_ERR_V(1U)
+
+#define TXFIFO_PRTY_ERR_S 1
+#define TXFIFO_PRTY_ERR_V(x) ((x) << TXFIFO_PRTY_ERR_S)
+#define TXFIFO_PRTY_ERR_F TXFIFO_PRTY_ERR_V(1U)
+
+#define RXFIFO_PRTY_ERR_S 0
+#define RXFIFO_PRTY_ERR_V(x) ((x) << RXFIFO_PRTY_ERR_S)
+#define RXFIFO_PRTY_ERR_F RXFIFO_PRTY_ERR_V(1U)
+
+#define XGMAC_PORT_CFG2_A 0x1018
+
+#define PATEN_S 18
+#define PATEN_V(x) ((x) << PATEN_S)
+#define PATEN_F PATEN_V(1U)
+
+#define MAGICEN_S 17
+#define MAGICEN_V(x) ((x) << MAGICEN_S)
+#define MAGICEN_F MAGICEN_V(1U)
+
+#define XGMAC_PORT_MAGIC_MACID_LO 0x1024
+#define XGMAC_PORT_MAGIC_MACID_HI 0x1028
+
+#define XGMAC_PORT_EPIO_DATA0_A 0x10c0
+#define XGMAC_PORT_EPIO_DATA1_A 0x10c4
+#define XGMAC_PORT_EPIO_DATA2_A 0x10c8
+#define XGMAC_PORT_EPIO_DATA3_A 0x10cc
+#define XGMAC_PORT_EPIO_OP_A 0x10d0
+
+#define EPIOWR_S 8
+#define EPIOWR_V(x) ((x) << EPIOWR_S)
+#define EPIOWR_F EPIOWR_V(1U)
+
+#define ADDRESS_S 0
+#define ADDRESS_V(x) ((x) << ADDRESS_S)
+
+#define MAC_PORT_INT_CAUSE_A 0x8dc
+#define XGMAC_PORT_INT_CAUSE_A 0x10dc
+
+#define TP_TX_MOD_QUEUE_REQ_MAP_A 0x7e28
+
+#define TP_TX_MOD_QUEUE_WEIGHT0_A 0x7e30
+#define TP_TX_MOD_CHANNEL_WEIGHT_A 0x7e34
+
+#define TX_MOD_QUEUE_REQ_MAP_S 0
+#define TX_MOD_QUEUE_REQ_MAP_V(x) ((x) << TX_MOD_QUEUE_REQ_MAP_S)
+
+#define TX_MODQ_WEIGHT3_S 24
+#define TX_MODQ_WEIGHT3_V(x) ((x) << TX_MODQ_WEIGHT3_S)
+
+#define TX_MODQ_WEIGHT2_S 16
+#define TX_MODQ_WEIGHT2_V(x) ((x) << TX_MODQ_WEIGHT2_S)
+
+#define TX_MODQ_WEIGHT1_S 8
+#define TX_MODQ_WEIGHT1_V(x) ((x) << TX_MODQ_WEIGHT1_S)
+
+#define TX_MODQ_WEIGHT0_S 0
+#define TX_MODQ_WEIGHT0_V(x) ((x) << TX_MODQ_WEIGHT0_S)
+
+#define TP_TX_SCHED_HDR_A 0x23
+#define TP_TX_SCHED_FIFO_A 0x24
+#define TP_TX_SCHED_PCMD_A 0x25
#define NUM_MPS_CLS_SRAM_L_INSTANCES 336
#define NUM_MPS_T5_CLS_SRAM_L_INSTANCES 512
@@ -1329,62 +2566,149 @@
#define MC_STRIDE (MC_1_BASE_ADDR - MC_0_BASE_ADDR)
#define MC_REG(reg, idx) (reg + MC_STRIDE * idx)
-#define MC_P_BIST_CMD 0x41400
-#define MC_P_BIST_CMD_ADDR 0x41404
-#define MC_P_BIST_CMD_LEN 0x41408
-#define MC_P_BIST_DATA_PATTERN 0x4140c
-#define MC_P_BIST_STATUS_RDATA 0x41488
-#define EDC_T50_BASE_ADDR 0x50000
-#define EDC_H_BIST_CMD 0x50004
-#define EDC_H_BIST_CMD_ADDR 0x50008
-#define EDC_H_BIST_CMD_LEN 0x5000c
-#define EDC_H_BIST_DATA_PATTERN 0x50010
-#define EDC_H_BIST_STATUS_RDATA 0x50028
-
-#define EDC_T51_BASE_ADDR 0x50800
+#define MC_P_BIST_CMD_A 0x41400
+#define MC_P_BIST_CMD_ADDR_A 0x41404
+#define MC_P_BIST_CMD_LEN_A 0x41408
+#define MC_P_BIST_DATA_PATTERN_A 0x4140c
+#define MC_P_BIST_STATUS_RDATA_A 0x41488
+
+#define EDC_T50_BASE_ADDR 0x50000
+
+#define EDC_H_BIST_CMD_A 0x50004
+#define EDC_H_BIST_CMD_ADDR_A 0x50008
+#define EDC_H_BIST_CMD_LEN_A 0x5000c
+#define EDC_H_BIST_DATA_PATTERN_A 0x50010
+#define EDC_H_BIST_STATUS_RDATA_A 0x50028
+
+#define EDC_T51_BASE_ADDR 0x50800
+
#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
-#define A_PL_VF_REV 0x4
-#define A_PL_VF_WHOAMI 0x0
-#define A_PL_VF_REVISION 0x8
+#define PL_VF_REV_A 0x4
+#define PL_VF_WHOAMI_A 0x0
+#define PL_VF_REVISION_A 0x8
-#define S_CHIPID 4
-#define M_CHIPID 0xfU
-#define V_CHIPID(x) ((x) << S_CHIPID)
-#define G_CHIPID(x) (((x) >> S_CHIPID) & M_CHIPID)
+/* registers for module CIM */
+#define CIM_HOST_ACC_CTRL_A 0x7b50
+#define CIM_HOST_ACC_DATA_A 0x7b54
+#define UP_UP_DBG_LA_CFG_A 0x140
+#define UP_UP_DBG_LA_DATA_A 0x144
-/* TP_VLAN_PRI_MAP controls which subset of fields will be present in the
- * Compressed Filter Tuple for LE filters. Each bit set in TP_VLAN_PRI_MAP
- * selects for a particular field being present. These fields, when present
- * in the Compressed Filter Tuple, have the following widths in bits.
- */
-#define W_FT_FCOE 1
-#define W_FT_PORT 3
-#define W_FT_VNIC_ID 17
-#define W_FT_VLAN 17
-#define W_FT_TOS 8
-#define W_FT_PROTOCOL 8
-#define W_FT_ETHERTYPE 16
-#define W_FT_MACMATCH 9
-#define W_FT_MPSHITTYPE 3
-#define W_FT_FRAGMENTATION 1
-
-/* Some of the Compressed Filter Tuple fields have internal structure. These
- * bit shifts/masks describe those structures. All shifts are relative to the
- * base position of the fields within the Compressed Filter Tuple
- */
-#define S_FT_VLAN_VLD 16
-#define V_FT_VLAN_VLD(x) ((x) << S_FT_VLAN_VLD)
-#define F_FT_VLAN_VLD V_FT_VLAN_VLD(1U)
+#define HOSTBUSY_S 17
+#define HOSTBUSY_V(x) ((x) << HOSTBUSY_S)
+#define HOSTBUSY_F HOSTBUSY_V(1U)
+
+#define HOSTWRITE_S 16
+#define HOSTWRITE_V(x) ((x) << HOSTWRITE_S)
+#define HOSTWRITE_F HOSTWRITE_V(1U)
+
+#define CIM_IBQ_DBG_CFG_A 0x7b60
+
+#define IBQDBGADDR_S 16
+#define IBQDBGADDR_M 0xfffU
+#define IBQDBGADDR_V(x) ((x) << IBQDBGADDR_S)
+#define IBQDBGADDR_G(x) (((x) >> IBQDBGADDR_S) & IBQDBGADDR_M)
+
+#define IBQDBGBUSY_S 1
+#define IBQDBGBUSY_V(x) ((x) << IBQDBGBUSY_S)
+#define IBQDBGBUSY_F IBQDBGBUSY_V(1U)
+
+#define IBQDBGEN_S 0
+#define IBQDBGEN_V(x) ((x) << IBQDBGEN_S)
+#define IBQDBGEN_F IBQDBGEN_V(1U)
+
+#define CIM_OBQ_DBG_CFG_A 0x7b64
+
+#define OBQDBGADDR_S 16
+#define OBQDBGADDR_M 0xfffU
+#define OBQDBGADDR_V(x) ((x) << OBQDBGADDR_S)
+#define OBQDBGADDR_G(x) (((x) >> OBQDBGADDR_S) & OBQDBGADDR_M)
+
+#define OBQDBGBUSY_S 1
+#define OBQDBGBUSY_V(x) ((x) << OBQDBGBUSY_S)
+#define OBQDBGBUSY_F OBQDBGBUSY_V(1U)
+
+#define OBQDBGEN_S 0
+#define OBQDBGEN_V(x) ((x) << OBQDBGEN_S)
+#define OBQDBGEN_F OBQDBGEN_V(1U)
+
+#define CIM_IBQ_DBG_DATA_A 0x7b68
+#define CIM_OBQ_DBG_DATA_A 0x7b6c
+
+#define UPDBGLARDEN_S 1
+#define UPDBGLARDEN_V(x) ((x) << UPDBGLARDEN_S)
+#define UPDBGLARDEN_F UPDBGLARDEN_V(1U)
+
+#define UPDBGLAEN_S 0
+#define UPDBGLAEN_V(x) ((x) << UPDBGLAEN_S)
+#define UPDBGLAEN_F UPDBGLAEN_V(1U)
+
+#define UPDBGLARDPTR_S 2
+#define UPDBGLARDPTR_M 0xfffU
+#define UPDBGLARDPTR_V(x) ((x) << UPDBGLARDPTR_S)
+
+#define UPDBGLAWRPTR_S 16
+#define UPDBGLAWRPTR_M 0xfffU
+#define UPDBGLAWRPTR_G(x) (((x) >> UPDBGLAWRPTR_S) & UPDBGLAWRPTR_M)
+
+#define UPDBGLACAPTPCONLY_S 30
+#define UPDBGLACAPTPCONLY_V(x) ((x) << UPDBGLACAPTPCONLY_S)
+#define UPDBGLACAPTPCONLY_F UPDBGLACAPTPCONLY_V(1U)
+
+#define CIM_QUEUE_CONFIG_REF_A 0x7b48
+#define CIM_QUEUE_CONFIG_CTRL_A 0x7b4c
+
+#define CIMQSIZE_S 24
+#define CIMQSIZE_M 0x3fU
+#define CIMQSIZE_G(x) (((x) >> CIMQSIZE_S) & CIMQSIZE_M)
+
+#define CIMQBASE_S 16
+#define CIMQBASE_M 0x3fU
+#define CIMQBASE_G(x) (((x) >> CIMQBASE_S) & CIMQBASE_M)
+
+#define QUEFULLTHRSH_S 0
+#define QUEFULLTHRSH_M 0x1ffU
+#define QUEFULLTHRSH_G(x) (((x) >> QUEFULLTHRSH_S) & QUEFULLTHRSH_M)
+
+#define UP_IBQ_0_RDADDR_A 0x10
+#define UP_IBQ_0_SHADOW_RDADDR_A 0x280
+#define UP_OBQ_0_REALADDR_A 0x104
+#define UP_OBQ_0_SHADOW_REALADDR_A 0x394
+
+#define IBQRDADDR_S 0
+#define IBQRDADDR_M 0x1fffU
+#define IBQRDADDR_G(x) (((x) >> IBQRDADDR_S) & IBQRDADDR_M)
+
+#define IBQWRADDR_S 0
+#define IBQWRADDR_M 0x1fffU
+#define IBQWRADDR_G(x) (((x) >> IBQWRADDR_S) & IBQWRADDR_M)
+
+#define QUERDADDR_S 0
+#define QUERDADDR_M 0x7fffU
+#define QUERDADDR_G(x) (((x) >> QUERDADDR_S) & QUERDADDR_M)
+
+#define QUEREMFLITS_S 0
+#define QUEREMFLITS_M 0x7ffU
+#define QUEREMFLITS_G(x) (((x) >> QUEREMFLITS_S) & QUEREMFLITS_M)
+
+#define QUEEOPCNT_S 16
+#define QUEEOPCNT_M 0xfffU
+#define QUEEOPCNT_G(x) (((x) >> QUEEOPCNT_S) & QUEEOPCNT_M)
+
+#define QUESOPCNT_S 0
+#define QUESOPCNT_M 0xfffU
+#define QUESOPCNT_G(x) (((x) >> QUESOPCNT_S) & QUESOPCNT_M)
-#define S_FT_VNID_ID_VF 0
-#define V_FT_VNID_ID_VF(x) ((x) << S_FT_VNID_ID_VF)
+#define OBQSELECT_S 4
+#define OBQSELECT_V(x) ((x) << OBQSELECT_S)
+#define OBQSELECT_F OBQSELECT_V(1U)
-#define S_FT_VNID_ID_PF 7
-#define V_FT_VNID_ID_PF(x) ((x) << S_FT_VNID_ID_PF)
+#define IBQSELECT_S 3
+#define IBQSELECT_V(x) ((x) << IBQSELECT_S)
+#define IBQSELECT_F IBQSELECT_V(1U)
-#define S_FT_VNID_ID_VLD 16
-#define V_FT_VNID_ID_VLD(x) ((x) << S_FT_VNID_ID_VLD)
+#define QUENUMSELECT_S 0
+#define QUENUMSELECT_V(x) ((x) << QUENUMSELECT_S)
#endif /* __T4_REGS_H */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4_values.h b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
new file mode 100644
index 000000000000..19b2dcf6acde
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4_values.h
@@ -0,0 +1,124 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __T4_VALUES_H__
+#define __T4_VALUES_H__
+
+/* This file contains definitions for various T4 register value hardware
+ * constants. The types of values encoded here are predominantly those for
+ * register fields which control "modal" behavior. For the most part, we do
+ * not include definitions for register fields which are simple numeric
+ * metrics, etc.
+ */
+
+/* SGE register field values.
+ */
+
+/* CONTROL1 register */
+#define RXPKTCPLMODE_SPLIT_X 1
+
+#define INGPCIEBOUNDARY_SHIFT_X 5
+#define INGPCIEBOUNDARY_32B_X 0
+
+#define INGPADBOUNDARY_SHIFT_X 5
+
+/* CONTROL2 register */
+#define INGPACKBOUNDARY_SHIFT_X 5
+#define INGPACKBOUNDARY_16B_X 0
+
+/* GTS register */
+#define SGE_TIMERREGS 6
+#define TIMERREG_COUNTER0_X 0
+
+/* T5 and later support a new BAR2-based doorbell mechanism for Egress Queues.
+ * The User Doorbells are each 128 bytes in length with a Simple Doorbell at
+ * offsets 8x and a Write Combining single 64-byte Egress Queue Unit
+ * (IDXSIZE_UNIT_X) Gather Buffer interface at offset 64. For Ingress Queues,
+ * we have a Going To Sleep register at offsets 8x+4.
+ *
+ * As noted above, we have many instances of the Simple Doorbell and Going To
+ * Sleep registers at offsets 8x and 8x+4, respectively. We want to use a
+ * non-64-byte aligned offset for the Simple Doorbell in order to attempt to
+ * avoid buffering of the writes to the Simple Doorbell and we want to use a
+ * non-contiguous offset for the Going To Sleep writes in order to avoid
+ * possible combining between them.
+ */
+#define SGE_UDB_SIZE 128
+#define SGE_UDB_KDOORBELL 8
+#define SGE_UDB_GTS 20
+#define SGE_UDB_WCDOORBELL 64
+
+/* CIM register field values.
+ */
+#define X_MBOWNER_FW 1
+#define X_MBOWNER_PL 2
+
+/* PCI-E definitions */
+#define WINDOW_SHIFT_X 10
+#define PCIEOFST_SHIFT_X 10
+
+/* TP_VLAN_PRI_MAP controls which subset of fields will be present in the
+ * Compressed Filter Tuple for LE filters. Each bit set in TP_VLAN_PRI_MAP
+ * selects for a particular field being present. These fields, when present
+ * in the Compressed Filter Tuple, have the following widths in bits.
+ */
+#define FT_FCOE_W 1
+#define FT_PORT_W 3
+#define FT_VNIC_ID_W 17
+#define FT_VLAN_W 17
+#define FT_TOS_W 8
+#define FT_PROTOCOL_W 8
+#define FT_ETHERTYPE_W 16
+#define FT_MACMATCH_W 9
+#define FT_MPSHITTYPE_W 3
+#define FT_FRAGMENTATION_W 1
+
+/* Some of the Compressed Filter Tuple fields have internal structure. These
+ * bit shifts/masks describe those structures. All shifts are relative to the
+ * base position of the fields within the Compressed Filter Tuple
+ */
+#define FT_VLAN_VLD_S 16
+#define FT_VLAN_VLD_V(x) ((x) << FT_VLAN_VLD_S)
+#define FT_VLAN_VLD_F FT_VLAN_VLD_V(1U)
+
+#define FT_VNID_ID_VF_S 0
+#define FT_VNID_ID_VF_V(x) ((x) << FT_VNID_ID_VF_S)
+
+#define FT_VNID_ID_PF_S 7
+#define FT_VNID_ID_PF_V(x) ((x) << FT_VNID_ID_PF_S)
+
+#define FT_VNID_ID_VLD_S 16
+#define FT_VNID_ID_VLD_V(x) ((x) << FT_VNID_ID_VLD_S)
+
+#endif /* __T4_VALUES_H__ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
index 7c0aec85137a..9b353a88cbda 100644
--- a/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_api.h
@@ -673,6 +673,7 @@ enum fw_cmd_opcodes {
FW_RSS_IND_TBL_CMD = 0x20,
FW_RSS_GLB_CONFIG_CMD = 0x22,
FW_RSS_VI_CONFIG_CMD = 0x23,
+ FW_DEVLOG_CMD = 0x25,
FW_CLIP_CMD = 0x28,
FW_LASTC2E_CMD = 0x40,
FW_ERROR_CMD = 0x80,
@@ -1058,9 +1059,11 @@ enum fw_params_param_dev {
FW_PARAMS_PARAM_DEV_FWREV = 0x0B,
FW_PARAMS_PARAM_DEV_TPREV = 0x0C,
FW_PARAMS_PARAM_DEV_CF = 0x0D,
+ FW_PARAMS_PARAM_DEV_DIAG = 0x11,
FW_PARAMS_PARAM_DEV_MAXORDIRD_QP = 0x13, /* max supported QP IRD/ORD */
FW_PARAMS_PARAM_DEV_MAXIRD_ADAPTER = 0x14, /* max supported adap IRD */
FW_PARAMS_PARAM_DEV_ULPTX_MEMWRITE_DSGL = 0x17,
+ FW_PARAMS_PARAM_DEV_FWCACHE = 0x18,
};
/*
@@ -1120,6 +1123,16 @@ enum fw_params_param_dmaq {
FW_PARAMS_PARAM_DMAQ_EQ_DCBPRIO_ETH = 0x13,
};
+enum fw_params_param_dev_diag {
+ FW_PARAM_DEV_DIAG_TMP = 0x00,
+ FW_PARAM_DEV_DIAG_VDD = 0x01,
+};
+
+enum fw_params_param_dev_fwcache {
+ FW_PARAM_DEV_FWCACHE_FLUSH = 0x00,
+ FW_PARAM_DEV_FWCACHE_FLUSHINV = 0x01,
+};
+
#define FW_PARAMS_MNEM_S 24
#define FW_PARAMS_MNEM_V(x) ((x) << FW_PARAMS_MNEM_S)
@@ -3005,21 +3018,29 @@ enum fw_hdr_chip {
#define FW_HDR_FW_VER_MAJOR_S 24
#define FW_HDR_FW_VER_MAJOR_M 0xff
+#define FW_HDR_FW_VER_MAJOR_V(x) \
+ ((x) << FW_HDR_FW_VER_MAJOR_S)
#define FW_HDR_FW_VER_MAJOR_G(x) \
(((x) >> FW_HDR_FW_VER_MAJOR_S) & FW_HDR_FW_VER_MAJOR_M)
#define FW_HDR_FW_VER_MINOR_S 16
#define FW_HDR_FW_VER_MINOR_M 0xff
+#define FW_HDR_FW_VER_MINOR_V(x) \
+ ((x) << FW_HDR_FW_VER_MINOR_S)
#define FW_HDR_FW_VER_MINOR_G(x) \
(((x) >> FW_HDR_FW_VER_MINOR_S) & FW_HDR_FW_VER_MINOR_M)
#define FW_HDR_FW_VER_MICRO_S 8
#define FW_HDR_FW_VER_MICRO_M 0xff
+#define FW_HDR_FW_VER_MICRO_V(x) \
+ ((x) << FW_HDR_FW_VER_MICRO_S)
#define FW_HDR_FW_VER_MICRO_G(x) \
(((x) >> FW_HDR_FW_VER_MICRO_S) & FW_HDR_FW_VER_MICRO_M)
#define FW_HDR_FW_VER_BUILD_S 0
#define FW_HDR_FW_VER_BUILD_M 0xff
+#define FW_HDR_FW_VER_BUILD_V(x) \
+ ((x) << FW_HDR_FW_VER_BUILD_S)
#define FW_HDR_FW_VER_BUILD_G(x) \
(((x) >> FW_HDR_FW_VER_BUILD_S) & FW_HDR_FW_VER_BUILD_M)
@@ -3038,4 +3059,84 @@ enum fw_hdr_flags {
FW_HDR_FLAGS_RESET_HALT = 0x00000001,
};
+/* length of the formatting string */
+#define FW_DEVLOG_FMT_LEN 192
+
+/* maximum number of the formatting string parameters */
+#define FW_DEVLOG_FMT_PARAMS_NUM 8
+
+/* priority levels */
+enum fw_devlog_level {
+ FW_DEVLOG_LEVEL_EMERG = 0x0,
+ FW_DEVLOG_LEVEL_CRIT = 0x1,
+ FW_DEVLOG_LEVEL_ERR = 0x2,
+ FW_DEVLOG_LEVEL_NOTICE = 0x3,
+ FW_DEVLOG_LEVEL_INFO = 0x4,
+ FW_DEVLOG_LEVEL_DEBUG = 0x5,
+ FW_DEVLOG_LEVEL_MAX = 0x5,
+};
+
+/* facilities that may send a log message */
+enum fw_devlog_facility {
+ FW_DEVLOG_FACILITY_CORE = 0x00,
+ FW_DEVLOG_FACILITY_CF = 0x01,
+ FW_DEVLOG_FACILITY_SCHED = 0x02,
+ FW_DEVLOG_FACILITY_TIMER = 0x04,
+ FW_DEVLOG_FACILITY_RES = 0x06,
+ FW_DEVLOG_FACILITY_HW = 0x08,
+ FW_DEVLOG_FACILITY_FLR = 0x10,
+ FW_DEVLOG_FACILITY_DMAQ = 0x12,
+ FW_DEVLOG_FACILITY_PHY = 0x14,
+ FW_DEVLOG_FACILITY_MAC = 0x16,
+ FW_DEVLOG_FACILITY_PORT = 0x18,
+ FW_DEVLOG_FACILITY_VI = 0x1A,
+ FW_DEVLOG_FACILITY_FILTER = 0x1C,
+ FW_DEVLOG_FACILITY_ACL = 0x1E,
+ FW_DEVLOG_FACILITY_TM = 0x20,
+ FW_DEVLOG_FACILITY_QFC = 0x22,
+ FW_DEVLOG_FACILITY_DCB = 0x24,
+ FW_DEVLOG_FACILITY_ETH = 0x26,
+ FW_DEVLOG_FACILITY_OFLD = 0x28,
+ FW_DEVLOG_FACILITY_RI = 0x2A,
+ FW_DEVLOG_FACILITY_ISCSI = 0x2C,
+ FW_DEVLOG_FACILITY_FCOE = 0x2E,
+ FW_DEVLOG_FACILITY_FOISCSI = 0x30,
+ FW_DEVLOG_FACILITY_FOFCOE = 0x32,
+ FW_DEVLOG_FACILITY_MAX = 0x32,
+};
+
+/* log message format */
+struct fw_devlog_e {
+ __be64 timestamp;
+ __be32 seqno;
+ __be16 reserved1;
+ __u8 level;
+ __u8 facility;
+ __u8 fmt[FW_DEVLOG_FMT_LEN];
+ __be32 params[FW_DEVLOG_FMT_PARAMS_NUM];
+ __be32 reserved3[4];
+};
+
+struct fw_devlog_cmd {
+ __be32 op_to_write;
+ __be32 retval_len16;
+ __u8 level;
+ __u8 r2[7];
+ __be32 memtype_devlog_memaddr16_devlog;
+ __be32 memsize_devlog;
+ __be32 r3[2];
+};
+
+#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S 28
+#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M 0xf
+#define FW_DEVLOG_CMD_MEMTYPE_DEVLOG_G(x) \
+ (((x) >> FW_DEVLOG_CMD_MEMTYPE_DEVLOG_S) & \
+ FW_DEVLOG_CMD_MEMTYPE_DEVLOG_M)
+
+#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S 0
+#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M 0xfffffff
+#define FW_DEVLOG_CMD_MEMADDR16_DEVLOG_G(x) \
+ (((x) >> FW_DEVLOG_CMD_MEMADDR16_DEVLOG_S) & \
+ FW_DEVLOG_CMD_MEMADDR16_DEVLOG_M)
+
#endif /* _T4FW_INTERFACE_H_ */
diff --git a/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
new file mode 100644
index 000000000000..e2bd3f747858
--- /dev/null
+++ b/drivers/net/ethernet/chelsio/cxgb4/t4fw_version.h
@@ -0,0 +1,48 @@
+/*
+ * This file is part of the Chelsio T4 Ethernet driver for Linux.
+ *
+ * Copyright (c) 2003-2014 Chelsio Communications, Inc. All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * - Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer.
+ *
+ * - Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __T4FW_VERSION_H__
+#define __T4FW_VERSION_H__
+
+#define T4FW_VERSION_MAJOR 0x01
+#define T4FW_VERSION_MINOR 0x0C
+#define T4FW_VERSION_MICRO 0x19
+#define T4FW_VERSION_BUILD 0x00
+
+#define T5FW_VERSION_MAJOR 0x01
+#define T5FW_VERSION_MINOR 0x0C
+#define T5FW_VERSION_MICRO 0x19
+#define T5FW_VERSION_BUILD 0x00
+
+#endif
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
index a936ee8958c7..122e2964e63b 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/cxgb4vf_main.c
@@ -380,9 +380,9 @@ static void qenable(struct sge_rspq *rspq)
* enable interrupts.
*/
t4_write_reg(rspq->adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
- CIDXINC(0) |
- SEINTARM(rspq->intr_params) |
- INGRESSQID(rspq->cntxt_id));
+ CIDXINC_V(0) |
+ SEINTARM_V(rspq->intr_params) |
+ INGRESSQID_V(rspq->cntxt_id));
}
/*
@@ -403,9 +403,9 @@ static void enable_rx(struct adapter *adapter)
*/
if (adapter->flags & USING_MSI)
t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
- CIDXINC(0) |
- SEINTARM(s->intrq.intr_params) |
- INGRESSQID(s->intrq.cntxt_id));
+ CIDXINC_V(0) |
+ SEINTARM_V(s->intrq.intr_params) |
+ INGRESSQID_V(s->intrq.cntxt_id));
}
@@ -450,7 +450,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
/* FW can send EGR_UPDATEs encapsulated in a CPL_FW4_MSG.
*/
const struct cpl_sge_egr_update *p = (void *)(rsp + 3);
- opcode = G_CPL_OPCODE(ntohl(p->opcode_qid));
+ opcode = CPL_OPCODE_G(ntohl(p->opcode_qid));
if (opcode != CPL_SGE_EGR_UPDATE) {
dev_err(adapter->pdev_dev, "unexpected FW4/CPL %#x on FW event queue\n"
, opcode);
@@ -471,7 +471,7 @@ static int fwevtq_handler(struct sge_rspq *rspq, const __be64 *rsp,
* free TX Queue Descriptors ...
*/
const struct cpl_sge_egr_update *p = cpl;
- unsigned int qid = EGR_QID(be32_to_cpu(p->opcode_qid));
+ unsigned int qid = EGR_QID_G(be32_to_cpu(p->opcode_qid));
struct sge *s = &adapter->sge;
struct sge_txq *tq;
struct sge_eth_txq *txq;
@@ -1673,7 +1673,7 @@ static void cxgb4vf_get_regs(struct net_device *dev,
reg_block_dump(adapter, regbuf,
T4VF_PL_BASE_ADDR + T4VF_MOD_MAP_PL_FIRST,
T4VF_PL_BASE_ADDR + (is_t4(adapter->params.chip)
- ? A_PL_VF_WHOAMI : A_PL_VF_REVISION));
+ ? PL_VF_WHOAMI_A : PL_VF_REVISION_A));
reg_block_dump(adapter, regbuf,
T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_FIRST,
T4VF_CIM_BASE_ADDR + T4VF_MOD_MAP_CIM_LAST);
@@ -2294,26 +2294,22 @@ static int adap_init0(struct adapter *adapter)
* threshold values from the SGE parameters.
*/
s->timer_val[0] = core_ticks_to_us(adapter,
- TIMERVALUE0_GET(sge_params->sge_timer_value_0_and_1));
+ TIMERVALUE0_G(sge_params->sge_timer_value_0_and_1));
s->timer_val[1] = core_ticks_to_us(adapter,
- TIMERVALUE1_GET(sge_params->sge_timer_value_0_and_1));
+ TIMERVALUE1_G(sge_params->sge_timer_value_0_and_1));
s->timer_val[2] = core_ticks_to_us(adapter,
- TIMERVALUE0_GET(sge_params->sge_timer_value_2_and_3));
+ TIMERVALUE0_G(sge_params->sge_timer_value_2_and_3));
s->timer_val[3] = core_ticks_to_us(adapter,
- TIMERVALUE1_GET(sge_params->sge_timer_value_2_and_3));
+ TIMERVALUE1_G(sge_params->sge_timer_value_2_and_3));
s->timer_val[4] = core_ticks_to_us(adapter,
- TIMERVALUE0_GET(sge_params->sge_timer_value_4_and_5));
+ TIMERVALUE0_G(sge_params->sge_timer_value_4_and_5));
s->timer_val[5] = core_ticks_to_us(adapter,
- TIMERVALUE1_GET(sge_params->sge_timer_value_4_and_5));
-
- s->counter_val[0] =
- THRESHOLD_0_GET(sge_params->sge_ingress_rx_threshold);
- s->counter_val[1] =
- THRESHOLD_1_GET(sge_params->sge_ingress_rx_threshold);
- s->counter_val[2] =
- THRESHOLD_2_GET(sge_params->sge_ingress_rx_threshold);
- s->counter_val[3] =
- THRESHOLD_3_GET(sge_params->sge_ingress_rx_threshold);
+ TIMERVALUE1_G(sge_params->sge_timer_value_4_and_5));
+
+ s->counter_val[0] = THRESHOLD_0_G(sge_params->sge_ingress_rx_threshold);
+ s->counter_val[1] = THRESHOLD_1_G(sge_params->sge_ingress_rx_threshold);
+ s->counter_val[2] = THRESHOLD_2_G(sge_params->sge_ingress_rx_threshold);
+ s->counter_val[3] = THRESHOLD_3_G(sge_params->sge_ingress_rx_threshold);
/*
* Grab our Virtual Interface resource allocation, extract the
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
index f7fd1317d996..0545f0de1c52 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/sge.c
@@ -47,6 +47,7 @@
#include "t4vf_defs.h"
#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4_values.h"
#include "../cxgb4/t4fw_api.h"
#include "../cxgb4/t4_msg.h"
@@ -531,11 +532,11 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
*/
if (fl->pend_cred >= FL_PER_EQ_UNIT) {
if (is_t4(adapter->params.chip))
- val = PIDX(fl->pend_cred / FL_PER_EQ_UNIT);
+ val = PIDX_V(fl->pend_cred / FL_PER_EQ_UNIT);
else
- val = PIDX_T5(fl->pend_cred / FL_PER_EQ_UNIT) |
- DBTYPE(1);
- val |= DBPRIO(1);
+ val = PIDX_T5_V(fl->pend_cred / FL_PER_EQ_UNIT) |
+ DBTYPE_F;
+ val |= DBPRIO_F;
/* Make sure all memory writes to the Free List queue are
* committed before we tell the hardware about them.
@@ -549,9 +550,9 @@ static inline void ring_fl_db(struct adapter *adapter, struct sge_fl *fl)
if (unlikely(fl->bar2_addr == NULL)) {
t4_write_reg(adapter,
T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
- QID(fl->cntxt_id) | val);
+ QID_V(fl->cntxt_id) | val);
} else {
- writel(val | QID(fl->bar2_qid),
+ writel(val | QID_V(fl->bar2_qid),
fl->bar2_addr + SGE_UDB_KDOORBELL);
/* This Write memory Barrier will force the write to
@@ -925,7 +926,7 @@ static void write_sgl(const struct sk_buff *skb, struct sge_txq *tq,
}
sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
- ULPTX_NSGE(nfrags));
+ ULPTX_NSGE_V(nfrags));
if (likely(--nfrags == 0))
return;
/*
@@ -979,12 +980,12 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
* doorbell mechanism; otherwise use the new BAR2 mechanism.
*/
if (unlikely(tq->bar2_addr == NULL)) {
- u32 val = PIDX(n);
+ u32 val = PIDX_V(n);
t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_KDOORBELL,
- QID(tq->cntxt_id) | val);
+ QID_V(tq->cntxt_id) | val);
} else {
- u32 val = PIDX_T5(n);
+ u32 val = PIDX_T5_V(n);
/* T4 and later chips share the same PIDX field offset within
* the doorbell, but T5 and later shrank the field in order to
@@ -992,7 +993,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
* large in the first place (14 bits) so we just use the T5
* and later limits and warn if a Queue ID is too large.
*/
- WARN_ON(val & DBPRIO(1));
+ WARN_ON(val & DBPRIO_F);
/* If we're only writing a single Egress Unit and the BAR2
* Queue ID is 0, we can use the Write Combining Doorbell
@@ -1023,7 +1024,7 @@ static inline void ring_tx_db(struct adapter *adapter, struct sge_txq *tq,
count--;
}
} else
- writel(val | QID(tq->bar2_qid),
+ writel(val | QID_V(tq->bar2_qid),
tq->bar2_addr + SGE_UDB_KDOORBELL);
/* This Write Memory Barrier will force the write to the User
@@ -1325,9 +1326,9 @@ int t4vf_eth_xmit(struct sk_buff *skb, struct net_device *dev)
* If there's a VLAN tag present, add that to the list of things to
* do in this Work Request.
*/
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
txq->vlan_ins++;
- cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(vlan_tx_tag_get(skb));
+ cntrl |= TXPKT_VLAN_VLD | TXPKT_VLAN(skb_vlan_tag_get(skb));
}
/*
@@ -1603,7 +1604,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
* If this is a good TCP packet and we have Generic Receive Offload
* enabled, handle the packet in the GRO path.
*/
- if ((pkt->l2info & cpu_to_be32(RXF_TCP)) &&
+ if ((pkt->l2info & cpu_to_be32(RXF_TCP_F)) &&
(rspq->netdev->features & NETIF_F_GRO) && csum_ok &&
!pkt->ip_frag) {
do_gro(rxq, gl, pkt);
@@ -1625,7 +1626,7 @@ int t4vf_ethrx_handler(struct sge_rspq *rspq, const __be64 *rsp,
rxq->stats.pkts++;
if (csum_ok && !pkt->err_vec &&
- (be32_to_cpu(pkt->l2info) & (RXF_UDP|RXF_TCP))) {
+ (be32_to_cpu(pkt->l2info) & (RXF_UDP_F | RXF_TCP_F))) {
if (!pkt->ip_frag)
skb->ip_summed = CHECKSUM_UNNECESSARY;
else {
@@ -1875,13 +1876,13 @@ static int napi_rx_handler(struct napi_struct *napi, int budget)
if (unlikely(work_done == 0))
rspq->unhandled_irqs++;
- val = CIDXINC(work_done) | SEINTARM(intr_params);
+ val = CIDXINC_V(work_done) | SEINTARM_V(intr_params);
if (is_t4(rspq->adapter->params.chip)) {
t4_write_reg(rspq->adapter,
T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
- val | INGRESSQID((u32)rspq->cntxt_id));
+ val | INGRESSQID_V((u32)rspq->cntxt_id));
} else {
- writel(val | INGRESSQID(rspq->bar2_qid),
+ writel(val | INGRESSQID_V(rspq->bar2_qid),
rspq->bar2_addr + SGE_UDB_GTS);
wmb();
}
@@ -1975,12 +1976,12 @@ static unsigned int process_intrq(struct adapter *adapter)
rspq_next(intrq);
}
- val = CIDXINC(work_done) | SEINTARM(intrq->intr_params);
+ val = CIDXINC_V(work_done) | SEINTARM_V(intrq->intr_params);
if (is_t4(adapter->params.chip))
t4_write_reg(adapter, T4VF_SGE_BASE_ADDR + SGE_VF_GTS,
- val | INGRESSQID(intrq->cntxt_id));
+ val | INGRESSQID_V(intrq->cntxt_id));
else {
- writel(val | INGRESSQID(intrq->bar2_qid),
+ writel(val | INGRESSQID_V(intrq->bar2_qid),
intrq->bar2_addr + SGE_UDB_GTS);
wmb();
}
@@ -2583,7 +2584,7 @@ int t4vf_sge_init(struct adapter *adapter)
fl0, fl1);
return -EINVAL;
}
- if ((sge_params->sge_control & RXPKTCPLMODE_MASK) == 0) {
+ if ((sge_params->sge_control & RXPKTCPLMODE_F) == 0) {
dev_err(adapter->pdev_dev, "bad SGE CPL MODE\n");
return -EINVAL;
}
@@ -2593,9 +2594,9 @@ int t4vf_sge_init(struct adapter *adapter)
*/
if (fl1)
s->fl_pg_order = ilog2(fl1) - PAGE_SHIFT;
- s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_MASK)
+ s->stat_len = ((sge_params->sge_control & EGRSTATUSPAGESIZE_F)
? 128 : 64);
- s->pktshift = PKTSHIFT_GET(sge_params->sge_control);
+ s->pktshift = PKTSHIFT_G(sge_params->sge_control);
/* T4 uses a single control field to specify both the PCIe Padding and
* Packing Boundary. T5 introduced the ability to specify these
@@ -2607,8 +2608,8 @@ int t4vf_sge_init(struct adapter *adapter)
* end doing this because it would initialize the Padding Boundary and
* leave the Packing Boundary initialized to 0 (16 bytes).)
*/
- ingpadboundary = 1 << (INGPADBOUNDARY_GET(sge_params->sge_control) +
- X_INGPADBOUNDARY_SHIFT);
+ ingpadboundary = 1 << (INGPADBOUNDARY_G(sge_params->sge_control) +
+ INGPADBOUNDARY_SHIFT_X);
if (is_t4(adapter->params.chip)) {
s->fl_align = ingpadboundary;
} else {
@@ -2633,7 +2634,7 @@ int t4vf_sge_init(struct adapter *adapter)
* Congestion Threshold is in units of 2 Free List pointers.)
*/
s->fl_starve_thres
- = EGRTHRESHOLD_GET(sge_params->sge_congestion_control)*2 + 1;
+ = EGRTHRESHOLD_G(sge_params->sge_congestion_control)*2 + 1;
/*
* Set up tasklet timers.
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h
index c7b127d93767..b516b12b1884 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_defs.h
@@ -64,8 +64,8 @@
* Mailbox Data in the fixed CIM PF map and the programmable VF map must
* match. However, it's a useful convention ...
*/
-#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA
-#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA!
+#if T4VF_MBDATA_BASE_ADDR != CIM_PF_MAILBOX_DATA_A
+#error T4VF_MBDATA_BASE_ADDR must match CIM_PF_MAILBOX_DATA_A!
#endif
/*
diff --git a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
index 60426cf890a7..1b5506df35b1 100644
--- a/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
+++ b/drivers/net/ethernet/chelsio/cxgb4vf/t4vf_hw.c
@@ -39,6 +39,7 @@
#include "t4vf_defs.h"
#include "../cxgb4/t4_regs.h"
+#include "../cxgb4/t4_values.h"
#include "../cxgb4/t4fw_api.h"
/*
@@ -137,9 +138,9 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
* Loop trying to get ownership of the mailbox. Return an error
* if we can't gain ownership.
*/
- v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl));
+ v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl));
for (i = 0; v == MBOX_OWNER_NONE && i < 3; i++)
- v = MBOWNER_GET(t4_read_reg(adapter, mbox_ctl));
+ v = MBOWNER_G(t4_read_reg(adapter, mbox_ctl));
if (v != MBOX_OWNER_DRV)
return v == MBOX_OWNER_FW ? -EBUSY : -ETIMEDOUT;
@@ -161,7 +162,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
t4_read_reg(adapter, mbox_data); /* flush write */
t4_write_reg(adapter, mbox_ctl,
- MBMSGVALID | MBOWNER(MBOX_OWNER_FW));
+ MBMSGVALID_F | MBOWNER_V(MBOX_OWNER_FW));
t4_read_reg(adapter, mbox_ctl); /* flush write */
/*
@@ -183,14 +184,14 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
* If we're the owner, see if this is the reply we wanted.
*/
v = t4_read_reg(adapter, mbox_ctl);
- if (MBOWNER_GET(v) == MBOX_OWNER_DRV) {
+ if (MBOWNER_G(v) == MBOX_OWNER_DRV) {
/*
* If the Message Valid bit isn't on, revoke ownership
* of the mailbox and continue waiting for our reply.
*/
- if ((v & MBMSGVALID) == 0) {
+ if ((v & MBMSGVALID_F) == 0) {
t4_write_reg(adapter, mbox_ctl,
- MBOWNER(MBOX_OWNER_NONE));
+ MBOWNER_V(MBOX_OWNER_NONE));
continue;
}
@@ -216,7 +217,7 @@ int t4vf_wr_mbox_core(struct adapter *adapter, const void *cmd, int size,
& FW_CMD_REQUEST_F) != 0);
}
t4_write_reg(adapter, mbox_ctl,
- MBOWNER(MBOX_OWNER_NONE));
+ MBOWNER_V(MBOX_OWNER_NONE));
return -FW_CMD_RETVAL_G(v);
}
}
@@ -530,19 +531,19 @@ int t4vf_get_sge_params(struct adapter *adapter)
int v;
params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL));
+ FW_PARAMS_PARAM_XYZ_V(SGE_CONTROL_A));
params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE));
+ FW_PARAMS_PARAM_XYZ_V(SGE_HOST_PAGE_SIZE_A));
params[2] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0));
+ FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE0_A));
params[3] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1));
+ FW_PARAMS_PARAM_XYZ_V(SGE_FL_BUFFER_SIZE1_A));
params[4] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1));
+ FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_0_AND_1_A));
params[5] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3));
+ FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_2_AND_3_A));
params[6] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5));
+ FW_PARAMS_PARAM_XYZ_V(SGE_TIMER_VALUE_4_AND_5_A));
v = t4vf_query_params(adapter, 7, params, vals);
if (v)
return v;
@@ -578,9 +579,9 @@ int t4vf_get_sge_params(struct adapter *adapter)
}
params[0] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD));
+ FW_PARAMS_PARAM_XYZ_V(SGE_INGRESS_RX_THRESHOLD_A));
params[1] = (FW_PARAMS_MNEM_V(FW_PARAMS_MNEM_REG) |
- FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL));
+ FW_PARAMS_PARAM_XYZ_V(SGE_CONM_CTRL_A));
v = t4vf_query_params(adapter, 2, params, vals);
if (v)
return v;
@@ -617,8 +618,8 @@ int t4vf_get_sge_params(struct adapter *adapter)
* the driver can just use it.
*/
whoami = t4_read_reg(adapter,
- T4VF_PL_BASE_ADDR + A_PL_VF_WHOAMI);
- pf = SOURCEPF_GET(whoami);
+ T4VF_PL_BASE_ADDR + PL_VF_WHOAMI_A);
+ pf = SOURCEPF_G(whoami);
s_hps = (HOSTPAGESIZEPF0_S +
(HOSTPAGESIZEPF1_S - HOSTPAGESIZEPF0_S) * pf);
@@ -630,10 +631,10 @@ int t4vf_get_sge_params(struct adapter *adapter)
(QUEUESPERPAGEPF1_S - QUEUESPERPAGEPF0_S) * pf);
sge_params->sge_vf_eq_qpp =
((sge_params->sge_egress_queues_per_page >> s_qpp)
- & QUEUESPERPAGEPF0_MASK);
+ & QUEUESPERPAGEPF0_M);
sge_params->sge_vf_iq_qpp =
((sge_params->sge_ingress_queues_per_page >> s_qpp)
- & QUEUESPERPAGEPF0_MASK);
+ & QUEUESPERPAGEPF0_M);
}
return 0;
@@ -1592,7 +1593,7 @@ int t4vf_prep_adapter(struct adapter *adapter)
break;
case CHELSIO_T5:
- chipid = G_REV(t4_read_reg(adapter, A_PL_VF_REV));
+ chipid = REV_G(t4_read_reg(adapter, PL_VF_REV_A));
adapter->params.chip |= CHELSIO_CHIP_CODE(CHELSIO_T5, chipid);
break;
}
diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig
index 7403dff8f14a..905ac5f5d9a6 100644
--- a/drivers/net/ethernet/cirrus/Kconfig
+++ b/drivers/net/ethernet/cirrus/Kconfig
@@ -32,7 +32,8 @@ config CS89x0
will be called cs89x0.
config CS89x0_PLATFORM
- bool "CS89x0 platform driver support"
+ bool "CS89x0 platform driver support" if HAS_IOPORT_MAP
+ default !HAS_IOPORT_MAP
depends on CS89x0
help
Say Y to compile the cs89x0 driver as a platform driver. This
diff --git a/drivers/net/ethernet/cirrus/ep93xx_eth.c b/drivers/net/ethernet/cirrus/ep93xx_eth.c
index 3a12c096ea1c..de9f7c97d916 100644
--- a/drivers/net/ethernet/cirrus/ep93xx_eth.c
+++ b/drivers/net/ethernet/cirrus/ep93xx_eth.c
@@ -475,8 +475,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep)
if (d)
dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_FROM_DEVICE);
- if (ep->rx_buf[i] != NULL)
- kfree(ep->rx_buf[i]);
+ kfree(ep->rx_buf[i]);
}
for (i = 0; i < TX_QUEUE_ENTRIES; i++) {
@@ -486,8 +485,7 @@ static void ep93xx_free_buffers(struct ep93xx_priv *ep)
if (d)
dma_unmap_single(dev, d, PKT_BUF_SIZE, DMA_TO_DEVICE);
- if (ep->tx_buf[i] != NULL)
- kfree(ep->tx_buf[i]);
+ kfree(ep->tx_buf[i]);
}
dma_free_coherent(dev, sizeof(struct ep93xx_descs), ep->descs,
diff --git a/drivers/net/ethernet/cisco/enic/enic.h b/drivers/net/ethernet/cisco/enic/enic.h
index 25c4d88853d8..84b6a2b46aec 100644
--- a/drivers/net/ethernet/cisco/enic/enic.h
+++ b/drivers/net/ethernet/cisco/enic/enic.h
@@ -33,7 +33,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION "2.1.1.67"
+#define DRV_VERSION "2.1.1.83"
#define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
@@ -188,6 +188,7 @@ struct enic {
struct enic_rfs_flw_tbl rfs_h;
u32 rx_copybreak;
u8 rss_key[ENIC_RSS_LEN];
+ struct vnic_gen_stats gen_stats;
};
static inline struct device *enic_get_dev(struct enic *enic)
@@ -242,6 +243,19 @@ static inline unsigned int enic_msix_notify_intr(struct enic *enic)
return enic->rq_count + enic->wq_count + 1;
}
+static inline int enic_dma_map_check(struct enic *enic, dma_addr_t dma_addr)
+{
+ if (unlikely(pci_dma_mapping_error(enic->pdev, dma_addr))) {
+ net_warn_ratelimited("%s: PCI dma mapping failed!\n",
+ enic->netdev->name);
+ enic->gen_stats.dma_map_error++;
+
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
void enic_reset_addr_lists(struct enic *enic);
int enic_sriov_enabled(struct enic *enic);
int enic_is_valid_vf(struct enic *enic, int vf);
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.c b/drivers/net/ethernet/cisco/enic/enic_dev.c
index 87ddc44b590e..f8d2a6a34282 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.c
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.c
@@ -177,40 +177,6 @@ int enic_dev_intr_coal_timer_info(struct enic *enic)
return err;
}
-int enic_vnic_dev_deinit(struct enic *enic)
-{
- int err;
-
- spin_lock_bh(&enic->devcmd_lock);
- err = vnic_dev_deinit(enic->vdev);
- spin_unlock_bh(&enic->devcmd_lock);
-
- return err;
-}
-
-int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp)
-{
- int err;
-
- spin_lock_bh(&enic->devcmd_lock);
- err = vnic_dev_init_prov2(enic->vdev,
- (u8 *)vp, vic_provinfo_size(vp));
- spin_unlock_bh(&enic->devcmd_lock);
-
- return err;
-}
-
-int enic_dev_deinit_done(struct enic *enic, int *status)
-{
- int err;
-
- spin_lock_bh(&enic->devcmd_lock);
- err = vnic_dev_deinit_done(enic->vdev, status);
- spin_unlock_bh(&enic->devcmd_lock);
-
- return err;
-}
-
/* rtnl lock is held */
int enic_vlan_rx_add_vid(struct net_device *netdev, __be16 proto, u16 vid)
{
@@ -237,28 +203,6 @@ int enic_vlan_rx_kill_vid(struct net_device *netdev, __be16 proto, u16 vid)
return err;
}
-int enic_dev_enable2(struct enic *enic, int active)
-{
- int err;
-
- spin_lock_bh(&enic->devcmd_lock);
- err = vnic_dev_enable2(enic->vdev, active);
- spin_unlock_bh(&enic->devcmd_lock);
-
- return err;
-}
-
-int enic_dev_enable2_done(struct enic *enic, int *status)
-{
- int err;
-
- spin_lock_bh(&enic->devcmd_lock);
- err = vnic_dev_enable2_done(enic->vdev, status);
- spin_unlock_bh(&enic->devcmd_lock);
-
- return err;
-}
-
int enic_dev_status_to_errno(int devcmd_status)
{
switch (devcmd_status) {
diff --git a/drivers/net/ethernet/cisco/enic/enic_dev.h b/drivers/net/ethernet/cisco/enic/enic_dev.h
index 10bb970b2f35..f5bb058b3f96 100644
--- a/drivers/net/ethernet/cisco/enic/enic_dev.h
+++ b/drivers/net/ethernet/cisco/enic/enic_dev.h
@@ -55,11 +55,6 @@ int enic_dev_set_ig_vlan_rewrite_mode(struct enic *enic);
int enic_dev_enable(struct enic *enic);
int enic_dev_disable(struct enic *enic);
int enic_dev_intr_coal_timer_info(struct enic *enic);
-int enic_vnic_dev_deinit(struct enic *enic);
-int enic_dev_init_prov2(struct enic *enic, struct vic_provinfo *vp);
-int enic_dev_deinit_done(struct enic *enic, int *status);
-int enic_dev_enable2(struct enic *enic, int arg);
-int enic_dev_enable2_done(struct enic *enic, int *status);
int enic_dev_status_to_errno(int devcmd_status);
#endif /* _ENIC_DEV_H_ */
diff --git a/drivers/net/ethernet/cisco/enic/enic_ethtool.c b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
index eba1eb846d34..28d9ca675a27 100644
--- a/drivers/net/ethernet/cisco/enic/enic_ethtool.c
+++ b/drivers/net/ethernet/cisco/enic/enic_ethtool.c
@@ -24,6 +24,7 @@
#include "enic_dev.h"
#include "enic_clsf.h"
#include "vnic_rss.h"
+#include "vnic_stats.h"
struct enic_stat {
char name[ETH_GSTRING_LEN];
@@ -40,6 +41,11 @@ struct enic_stat {
.index = offsetof(struct vnic_rx_stats, stat) / sizeof(u64) \
}
+#define ENIC_GEN_STAT(stat) { \
+ .name = #stat, \
+ .index = offsetof(struct vnic_gen_stats, stat) / sizeof(u64)\
+}
+
static const struct enic_stat enic_tx_stats[] = {
ENIC_TX_STAT(tx_frames_ok),
ENIC_TX_STAT(tx_unicast_frames_ok),
@@ -78,10 +84,15 @@ static const struct enic_stat enic_rx_stats[] = {
ENIC_RX_STAT(rx_frames_to_max),
};
+static const struct enic_stat enic_gen_stats[] = {
+ ENIC_GEN_STAT(dma_map_error),
+};
+
static const unsigned int enic_n_tx_stats = ARRAY_SIZE(enic_tx_stats);
static const unsigned int enic_n_rx_stats = ARRAY_SIZE(enic_rx_stats);
+static const unsigned int enic_n_gen_stats = ARRAY_SIZE(enic_gen_stats);
-void enic_intr_coal_set_rx(struct enic *enic, u32 timer)
+static void enic_intr_coal_set_rx(struct enic *enic, u32 timer)
{
int i;
int intr;
@@ -146,6 +157,10 @@ static void enic_get_strings(struct net_device *netdev, u32 stringset,
memcpy(data, enic_rx_stats[i].name, ETH_GSTRING_LEN);
data += ETH_GSTRING_LEN;
}
+ for (i = 0; i < enic_n_gen_stats; i++) {
+ memcpy(data, enic_gen_stats[i].name, ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
break;
}
}
@@ -154,7 +169,7 @@ static int enic_get_sset_count(struct net_device *netdev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
- return enic_n_tx_stats + enic_n_rx_stats;
+ return enic_n_tx_stats + enic_n_rx_stats + enic_n_gen_stats;
default:
return -EOPNOTSUPP;
}
@@ -173,6 +188,8 @@ static void enic_get_ethtool_stats(struct net_device *netdev,
*(data++) = ((u64 *)&vstats->tx)[enic_tx_stats[i].index];
for (i = 0; i < enic_n_rx_stats; i++)
*(data++) = ((u64 *)&vstats->rx)[enic_rx_stats[i].index];
+ for (i = 0; i < enic_n_gen_stats; i++)
+ *(data++) = ((u64 *)&enic->gen_stats)[enic_gen_stats[i].index];
}
static u32 enic_get_msglevel(struct net_device *netdev)
diff --git a/drivers/net/ethernet/cisco/enic/enic_main.c b/drivers/net/ethernet/cisco/enic/enic_main.c
index e356afa44e7d..9cbe038a388e 100644
--- a/drivers/net/ethernet/cisco/enic/enic_main.c
+++ b/drivers/net/ethernet/cisco/enic/enic_main.c
@@ -45,6 +45,7 @@
#ifdef CONFIG_NET_RX_BUSY_POLL
#include <net/busy_poll.h>
#endif
+#include <linux/crash_dump.h>
#include "cq_enet_desc.h"
#include "vnic_dev.h"
@@ -88,7 +89,7 @@ MODULE_DEVICE_TABLE(pci, enic_id_table);
* coalescing timer values
* {rx_rate in Mbps, mapping percentage of the range}
*/
-struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = {
+static struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = {
{4000, 0},
{4400, 10},
{5060, 20},
@@ -105,7 +106,7 @@ struct enic_intr_mod_table mod_table[ENIC_MAX_COALESCE_TIMERS + 1] = {
/* This table helps the driver to pick different ranges for rx coalescing
* timer depending on the link speed.
*/
-struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = {
+static struct enic_intr_mod_range mod_range[ENIC_MAX_LINK_SPEEDS] = {
{0, 0}, /* 0 - 4 Gbps */
{0, 3}, /* 4 - 10 Gbps */
{3, 6}, /* 10 - 40 Gbps */
@@ -351,80 +352,94 @@ static irqreturn_t enic_isr_msix_notify(int irq, void *data)
return IRQ_HANDLED;
}
-static inline void enic_queue_wq_skb_cont(struct enic *enic,
- struct vnic_wq *wq, struct sk_buff *skb,
- unsigned int len_left, int loopback)
+static int enic_queue_wq_skb_cont(struct enic *enic, struct vnic_wq *wq,
+ struct sk_buff *skb, unsigned int len_left,
+ int loopback)
{
const skb_frag_t *frag;
+ dma_addr_t dma_addr;
/* Queue additional data fragments */
for (frag = skb_shinfo(skb)->frags; len_left; frag++) {
len_left -= skb_frag_size(frag);
- enic_queue_wq_desc_cont(wq, skb,
- skb_frag_dma_map(&enic->pdev->dev,
- frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE),
- skb_frag_size(frag),
- (len_left == 0), /* EOP? */
- loopback);
+ dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag, 0,
+ skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ if (unlikely(enic_dma_map_check(enic, dma_addr)))
+ return -ENOMEM;
+ enic_queue_wq_desc_cont(wq, skb, dma_addr, skb_frag_size(frag),
+ (len_left == 0), /* EOP? */
+ loopback);
}
+
+ return 0;
}
-static inline void enic_queue_wq_skb_vlan(struct enic *enic,
- struct vnic_wq *wq, struct sk_buff *skb,
- int vlan_tag_insert, unsigned int vlan_tag, int loopback)
+static int enic_queue_wq_skb_vlan(struct enic *enic, struct vnic_wq *wq,
+ struct sk_buff *skb, int vlan_tag_insert,
+ unsigned int vlan_tag, int loopback)
{
unsigned int head_len = skb_headlen(skb);
unsigned int len_left = skb->len - head_len;
int eop = (len_left == 0);
+ dma_addr_t dma_addr;
+ int err = 0;
+
+ dma_addr = pci_map_single(enic->pdev, skb->data, head_len,
+ PCI_DMA_TODEVICE);
+ if (unlikely(enic_dma_map_check(enic, dma_addr)))
+ return -ENOMEM;
/* Queue the main skb fragment. The fragments are no larger
* than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
* than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
* per fragment is queued.
*/
- enic_queue_wq_desc(wq, skb,
- pci_map_single(enic->pdev, skb->data,
- head_len, PCI_DMA_TODEVICE),
- head_len,
- vlan_tag_insert, vlan_tag,
- eop, loopback);
+ enic_queue_wq_desc(wq, skb, dma_addr, head_len, vlan_tag_insert,
+ vlan_tag, eop, loopback);
if (!eop)
- enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
+ err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
+
+ return err;
}
-static inline void enic_queue_wq_skb_csum_l4(struct enic *enic,
- struct vnic_wq *wq, struct sk_buff *skb,
- int vlan_tag_insert, unsigned int vlan_tag, int loopback)
+static int enic_queue_wq_skb_csum_l4(struct enic *enic, struct vnic_wq *wq,
+ struct sk_buff *skb, int vlan_tag_insert,
+ unsigned int vlan_tag, int loopback)
{
unsigned int head_len = skb_headlen(skb);
unsigned int len_left = skb->len - head_len;
unsigned int hdr_len = skb_checksum_start_offset(skb);
unsigned int csum_offset = hdr_len + skb->csum_offset;
int eop = (len_left == 0);
+ dma_addr_t dma_addr;
+ int err = 0;
+
+ dma_addr = pci_map_single(enic->pdev, skb->data, head_len,
+ PCI_DMA_TODEVICE);
+ if (unlikely(enic_dma_map_check(enic, dma_addr)))
+ return -ENOMEM;
/* Queue the main skb fragment. The fragments are no larger
* than max MTU(9000)+ETH_HDR_LEN(14) bytes, which is less
* than WQ_ENET_MAX_DESC_LEN length. So only one descriptor
* per fragment is queued.
*/
- enic_queue_wq_desc_csum_l4(wq, skb,
- pci_map_single(enic->pdev, skb->data,
- head_len, PCI_DMA_TODEVICE),
- head_len,
- csum_offset,
- hdr_len,
- vlan_tag_insert, vlan_tag,
- eop, loopback);
+ enic_queue_wq_desc_csum_l4(wq, skb, dma_addr, head_len, csum_offset,
+ hdr_len, vlan_tag_insert, vlan_tag, eop,
+ loopback);
if (!eop)
- enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
+ err = enic_queue_wq_skb_cont(enic, wq, skb, len_left, loopback);
+
+ return err;
}
-static inline void enic_queue_wq_skb_tso(struct enic *enic,
- struct vnic_wq *wq, struct sk_buff *skb, unsigned int mss,
- int vlan_tag_insert, unsigned int vlan_tag, int loopback)
+static int enic_queue_wq_skb_tso(struct enic *enic, struct vnic_wq *wq,
+ struct sk_buff *skb, unsigned int mss,
+ int vlan_tag_insert, unsigned int vlan_tag,
+ int loopback)
{
unsigned int frag_len_left = skb_headlen(skb);
unsigned int len_left = skb->len - frag_len_left;
@@ -454,20 +469,19 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
*/
while (frag_len_left) {
len = min(frag_len_left, (unsigned int)WQ_ENET_MAX_DESC_LEN);
- dma_addr = pci_map_single(enic->pdev, skb->data + offset,
- len, PCI_DMA_TODEVICE);
- enic_queue_wq_desc_tso(wq, skb,
- dma_addr,
- len,
- mss, hdr_len,
- vlan_tag_insert, vlan_tag,
- eop && (len == frag_len_left), loopback);
+ dma_addr = pci_map_single(enic->pdev, skb->data + offset, len,
+ PCI_DMA_TODEVICE);
+ if (unlikely(enic_dma_map_check(enic, dma_addr)))
+ return -ENOMEM;
+ enic_queue_wq_desc_tso(wq, skb, dma_addr, len, mss, hdr_len,
+ vlan_tag_insert, vlan_tag,
+ eop && (len == frag_len_left), loopback);
frag_len_left -= len;
offset += len;
}
if (eop)
- return;
+ return 0;
/* Queue WQ_ENET_MAX_DESC_LEN length descriptors
* for additional data fragments
@@ -483,16 +497,18 @@ static inline void enic_queue_wq_skb_tso(struct enic *enic,
dma_addr = skb_frag_dma_map(&enic->pdev->dev, frag,
offset, len,
DMA_TO_DEVICE);
- enic_queue_wq_desc_cont(wq, skb,
- dma_addr,
- len,
- (len_left == 0) &&
- (len == frag_len_left), /* EOP? */
- loopback);
+ if (unlikely(enic_dma_map_check(enic, dma_addr)))
+ return -ENOMEM;
+ enic_queue_wq_desc_cont(wq, skb, dma_addr, len,
+ (len_left == 0) &&
+ (len == frag_len_left),/*EOP*/
+ loopback);
frag_len_left -= len;
offset += len;
}
}
+
+ return 0;
}
static inline void enic_queue_wq_skb(struct enic *enic,
@@ -502,25 +518,42 @@ static inline void enic_queue_wq_skb(struct enic *enic,
unsigned int vlan_tag = 0;
int vlan_tag_insert = 0;
int loopback = 0;
+ int err;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
/* VLAN tag from trunking driver */
vlan_tag_insert = 1;
- vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = skb_vlan_tag_get(skb);
} else if (enic->loop_enable) {
vlan_tag = enic->loop_tag;
loopback = 1;
}
if (mss)
- enic_queue_wq_skb_tso(enic, wq, skb, mss,
- vlan_tag_insert, vlan_tag, loopback);
+ err = enic_queue_wq_skb_tso(enic, wq, skb, mss,
+ vlan_tag_insert, vlan_tag,
+ loopback);
else if (skb->ip_summed == CHECKSUM_PARTIAL)
- enic_queue_wq_skb_csum_l4(enic, wq, skb,
- vlan_tag_insert, vlan_tag, loopback);
+ err = enic_queue_wq_skb_csum_l4(enic, wq, skb, vlan_tag_insert,
+ vlan_tag, loopback);
else
- enic_queue_wq_skb_vlan(enic, wq, skb,
- vlan_tag_insert, vlan_tag, loopback);
+ err = enic_queue_wq_skb_vlan(enic, wq, skb, vlan_tag_insert,
+ vlan_tag, loopback);
+ if (unlikely(err)) {
+ struct vnic_wq_buf *buf;
+
+ buf = wq->to_use->prev;
+ /* while not EOP of previous pkt && queue not empty.
+ * For all non EOP bufs, os_buf is NULL.
+ */
+ while (!buf->os_buf && (buf->next != wq->to_clean)) {
+ enic_free_wq_buf(wq, buf);
+ wq->ring.desc_avail++;
+ buf = buf->prev;
+ }
+ wq->to_use = buf->next;
+ dev_kfree_skb(skb);
+ }
}
/* netif_tx_lock held, process context with BHs disabled, or BH */
@@ -950,8 +983,12 @@ static int enic_rq_alloc_buf(struct vnic_rq *rq)
if (!skb)
return -ENOMEM;
- dma_addr = pci_map_single(enic->pdev, skb->data,
- len, PCI_DMA_FROMDEVICE);
+ dma_addr = pci_map_single(enic->pdev, skb->data, len,
+ PCI_DMA_FROMDEVICE);
+ if (unlikely(enic_dma_map_check(enic, dma_addr))) {
+ dev_kfree_skb(skb);
+ return -ENOMEM;
+ }
enic_queue_rq_desc(rq, skb, os_buf_index,
dma_addr, len);
@@ -1266,7 +1303,7 @@ static void enic_set_rx_cpu_rmap(struct enic *enic)
#endif /* CONFIG_RFS_ACCEL */
#ifdef CONFIG_NET_RX_BUSY_POLL
-int enic_busy_poll(struct napi_struct *napi)
+static int enic_busy_poll(struct napi_struct *napi)
{
struct net_device *netdev = napi->dev;
struct enic *enic = netdev_priv(netdev);
@@ -2231,6 +2268,18 @@ static void enic_dev_deinit(struct enic *enic)
enic_clear_intr_mode(enic);
}
+static void enic_kdump_kernel_config(struct enic *enic)
+{
+ if (is_kdump_kernel()) {
+ dev_info(enic_get_dev(enic), "Running from within kdump kernel. Using minimal resources\n");
+ enic->rq_count = 1;
+ enic->wq_count = 1;
+ enic->config.rq_desc_count = ENIC_MIN_RQ_DESCS;
+ enic->config.wq_desc_count = ENIC_MIN_WQ_DESCS;
+ enic->config.mtu = min_t(u16, 1500, enic->config.mtu);
+ }
+}
+
static int enic_dev_init(struct enic *enic)
{
struct device *dev = enic_get_dev(enic);
@@ -2260,6 +2309,10 @@ static int enic_dev_init(struct enic *enic)
enic_get_res_counts(enic);
+ /* modify resource count if we are in kdump_kernel
+ */
+ enic_kdump_kernel_config(enic);
+
/* Set interrupt mode based on resource counts and system
* capabilities
*/
diff --git a/drivers/net/ethernet/cisco/enic/vnic_stats.h b/drivers/net/ethernet/cisco/enic/vnic_stats.h
index 77750ec93954..74c81ed6fdab 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_stats.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_stats.h
@@ -62,6 +62,11 @@ struct vnic_rx_stats {
u64 rsvd[16];
};
+/* Generic statistics */
+struct vnic_gen_stats {
+ u64 dma_map_error;
+};
+
struct vnic_stats {
struct vnic_tx_stats tx;
struct vnic_rx_stats rx;
diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.c b/drivers/net/ethernet/cisco/enic/vnic_wq.c
index 3e6b8d54dafc..b5a1c937fad2 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_wq.c
+++ b/drivers/net/ethernet/cisco/enic/vnic_wq.c
@@ -47,11 +47,14 @@ static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
wq->ring.desc_size * buf->index;
if (buf->index + 1 == count) {
buf->next = wq->bufs[0];
+ buf->next->prev = buf;
break;
} else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES(count)) {
buf->next = wq->bufs[i + 1];
+ buf->next->prev = buf;
} else {
buf->next = buf + 1;
+ buf->next->prev = buf;
buf++;
}
}
diff --git a/drivers/net/ethernet/cisco/enic/vnic_wq.h b/drivers/net/ethernet/cisco/enic/vnic_wq.h
index 816f1ad6072f..296154351823 100644
--- a/drivers/net/ethernet/cisco/enic/vnic_wq.h
+++ b/drivers/net/ethernet/cisco/enic/vnic_wq.h
@@ -62,6 +62,7 @@ struct vnic_wq_buf {
uint8_t cq_entry; /* Gets completion event from hw */
uint8_t desc_skip_cnt; /* Num descs to occupy */
uint8_t compressed_send; /* Both hdr and payload in one desc */
+ struct vnic_wq_buf *prev;
};
/* Break the vnic_wq_buf allocations into blocks of 32/64 entries */
diff --git a/drivers/net/ethernet/davicom/dm9000.c b/drivers/net/ethernet/davicom/dm9000.c
index ef0bb58750e6..c0a7813603c3 100644
--- a/drivers/net/ethernet/davicom/dm9000.c
+++ b/drivers/net/ethernet/davicom/dm9000.c
@@ -36,6 +36,9 @@
#include <linux/platform_device.h>
#include <linux/irq.h>
#include <linux/slab.h>
+#include <linux/regulator/consumer.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <asm/delay.h>
#include <asm/irq.h>
@@ -1426,11 +1429,48 @@ dm9000_probe(struct platform_device *pdev)
struct dm9000_plat_data *pdata = dev_get_platdata(&pdev->dev);
struct board_info *db; /* Point a board information structure */
struct net_device *ndev;
+ struct device *dev = &pdev->dev;
const unsigned char *mac_src;
int ret = 0;
int iosize;
int i;
u32 id_val;
+ int reset_gpios;
+ enum of_gpio_flags flags;
+ struct regulator *power;
+
+ power = devm_regulator_get(dev, "vcc");
+ if (IS_ERR(power)) {
+ if (PTR_ERR(power) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ dev_dbg(dev, "no regulator provided\n");
+ } else {
+ ret = regulator_enable(power);
+ if (ret != 0) {
+ dev_err(dev,
+ "Failed to enable power regulator: %d\n", ret);
+ return ret;
+ }
+ dev_dbg(dev, "regulator enabled\n");
+ }
+
+ reset_gpios = of_get_named_gpio_flags(dev->of_node, "reset-gpios", 0,
+ &flags);
+ if (gpio_is_valid(reset_gpios)) {
+ ret = devm_gpio_request_one(dev, reset_gpios, flags,
+ "dm9000_reset");
+ if (ret) {
+ dev_err(dev, "failed to request reset gpio %d: %d\n",
+ reset_gpios, ret);
+ return -ENODEV;
+ }
+
+ /* According to manual PWRST# Low Period Min 1ms */
+ msleep(2);
+ gpio_set_value(reset_gpios, 1);
+ /* Needs 3ms to read eeprom when PWRST is deasserted */
+ msleep(4);
+ }
if (!pdata) {
pdata = dm9000_parse_dt(&pdev->dev);
diff --git a/drivers/net/ethernet/dec/tulip/winbond-840.c b/drivers/net/ethernet/dec/tulip/winbond-840.c
index 6aa887e0e1cb..9beb3d34d4ba 100644
--- a/drivers/net/ethernet/dec/tulip/winbond-840.c
+++ b/drivers/net/ethernet/dec/tulip/winbond-840.c
@@ -904,7 +904,7 @@ static void init_registers(struct net_device *dev)
}
#elif defined(__powerpc__) || defined(__i386__) || defined(__alpha__) || defined(__ia64__) || defined(__x86_64__)
i |= 0xE000;
-#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC)
+#elif defined(CONFIG_SPARC) || defined (CONFIG_PARISC) || defined(CONFIG_ARM)
i |= 0x4800;
#else
#warning Processor architecture undefined
diff --git a/drivers/net/ethernet/emulex/benet/be.h b/drivers/net/ethernet/emulex/benet/be.h
index 712e7f8e1df7..27de37aa90af 100644
--- a/drivers/net/ethernet/emulex/benet/be.h
+++ b/drivers/net/ethernet/emulex/benet/be.h
@@ -59,26 +59,6 @@
#define OC_SUBSYS_DEVICE_ID3 0xE612
#define OC_SUBSYS_DEVICE_ID4 0xE652
-static inline char *nic_name(struct pci_dev *pdev)
-{
- switch (pdev->device) {
- case OC_DEVICE_ID1:
- return OC_NAME;
- case OC_DEVICE_ID2:
- return OC_NAME_BE;
- case OC_DEVICE_ID3:
- case OC_DEVICE_ID4:
- return OC_NAME_LANCER;
- case BE_DEVICE_ID2:
- return BE3_NAME;
- case OC_DEVICE_ID5:
- case OC_DEVICE_ID6:
- return OC_NAME_SH;
- default:
- return BE_NAME;
- }
-}
-
/* Number of bytes of an RX frame that are copied to skb->data */
#define BE_HDR_LEN ((u16) 64)
/* allocate extra space to allow tunneling decapsulation without head reallocation */
@@ -243,7 +223,6 @@ struct be_tx_stats {
u64 tx_bytes;
u64 tx_pkts;
u64 tx_reqs;
- u64 tx_wrbs;
u64 tx_compl;
ulong tx_jiffies;
u32 tx_stops;
@@ -266,6 +245,9 @@ struct be_tx_obj {
/* Remember the skbs that were transmitted */
struct sk_buff *sent_skb_list[TX_Q_LEN];
struct be_tx_stats stats;
+ u16 pend_wrb_cnt; /* Number of WRBs yet to be given to HW */
+ u16 last_req_wrb_cnt; /* wrb cnt of the last req in the Q */
+ u16 last_req_hdr; /* index of the last req's hdr-wrb */
} ____cacheline_aligned_in_smp;
/* Struct to remember the pages posted for rx frags */
@@ -379,15 +361,14 @@ enum vf_state {
ASSIGNED = 1
};
-#define BE_FLAGS_LINK_STATUS_INIT 1
-#define BE_FLAGS_SRIOV_ENABLED (1 << 2)
-#define BE_FLAGS_WORKER_SCHEDULED (1 << 3)
-#define BE_FLAGS_VLAN_PROMISC (1 << 4)
-#define BE_FLAGS_MCAST_PROMISC (1 << 5)
-#define BE_FLAGS_NAPI_ENABLED (1 << 9)
-#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD (1 << 11)
-#define BE_FLAGS_VXLAN_OFFLOADS (1 << 12)
-#define BE_FLAGS_SETUP_DONE (1 << 13)
+#define BE_FLAGS_LINK_STATUS_INIT BIT(1)
+#define BE_FLAGS_SRIOV_ENABLED BIT(2)
+#define BE_FLAGS_WORKER_SCHEDULED BIT(3)
+#define BE_FLAGS_NAPI_ENABLED BIT(6)
+#define BE_FLAGS_QNQ_ASYNC_EVT_RCVD BIT(7)
+#define BE_FLAGS_VXLAN_OFFLOADS BIT(8)
+#define BE_FLAGS_SETUP_DONE BIT(9)
+#define BE_FLAGS_EVT_INCOMPATIBLE_SFP BIT(10)
#define BE_UC_PMAC_COUNT 30
#define BE_VF_UC_PMAC_COUNT 2
@@ -397,6 +378,8 @@ enum vf_state {
#define LANCER_DELETE_FW_DUMP 0x2
struct phy_info {
+/* From SFF-8472 spec */
+#define SFP_VENDOR_NAME_LEN 17
u8 transceiver;
u8 autoneg;
u8 fc_autoneg;
@@ -410,6 +393,8 @@ struct phy_info {
u32 advertising;
u32 supported;
u8 cable_type;
+ u8 vendor_name[SFP_VENDOR_NAME_LEN];
+ u8 vendor_pn[SFP_VENDOR_NAME_LEN];
};
struct be_resources {
@@ -467,8 +452,6 @@ struct be_adapter {
struct be_drv_stats drv_stats;
struct be_aic_obj aic_obj[MAX_EVT_QS];
- u16 vlans_added;
- unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)];
u8 vlan_prio_bmap; /* Available Priority BitMap */
u16 recommended_prio; /* Recommended Priority */
struct be_dma_mem rx_filter; /* Cmd DMA mem for rx-filter */
@@ -484,8 +467,15 @@ struct be_adapter {
/* Ethtool knobs and info */
char fw_ver[FW_VER_LEN];
char fw_on_flash[FW_VER_LEN];
+
+ /* IFACE filtering fields */
int if_handle; /* Used to configure filtering */
+ u32 if_flags; /* Interface filtering flags */
u32 *pmac_id; /* MAC addr handle used by BE card */
+ u32 uc_macs; /* Count of secondary UC MAC programmed */
+ unsigned long vids[BITS_TO_LONGS(VLAN_N_VID)];
+ u16 vlans_added;
+
u32 beacon_state; /* for set_phys_id */
bool eeh_error;
@@ -493,7 +483,7 @@ struct be_adapter {
bool hw_error;
u32 port_num;
- bool promiscuous;
+ char port_name;
u8 mc_type;
u32 function_mode;
u32 function_caps;
@@ -526,7 +516,6 @@ struct be_adapter {
struct phy_info phy;
u8 wol_cap;
bool wol_en;
- u32 uc_macs; /* Count of secondary UC MAC programmed */
u16 asic_rev;
u16 qnq_vid;
u32 msg_enable;
@@ -732,19 +721,6 @@ static inline bool is_ipv4_pkt(struct sk_buff *skb)
return skb->protocol == htons(ETH_P_IP) && ip_hdr(skb)->version == 4;
}
-static inline void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
-{
- u32 addr;
-
- addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
-
- mac[5] = (u8)(addr & 0xFF);
- mac[4] = (u8)((addr >> 8) & 0xFF);
- mac[3] = (u8)((addr >> 16) & 0xFF);
- /* Use the OUI from the current MAC address */
- memcpy(mac, adapter->netdev->dev_addr, 3);
-}
-
static inline bool be_multi_rxq(const struct be_adapter *adapter)
{
return adapter->num_rx_qs > 1;
@@ -767,129 +743,6 @@ static inline void be_clear_all_error(struct be_adapter *adapter)
adapter->fw_timeout = false;
}
-static inline bool be_is_wol_excluded(struct be_adapter *adapter)
-{
- struct pci_dev *pdev = adapter->pdev;
-
- if (!be_physfn(adapter))
- return true;
-
- switch (pdev->subsystem_device) {
- case OC_SUBSYS_DEVICE_ID1:
- case OC_SUBSYS_DEVICE_ID2:
- case OC_SUBSYS_DEVICE_ID3:
- case OC_SUBSYS_DEVICE_ID4:
- return true;
- default:
- return false;
- }
-}
-
-static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
-{
- return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
-}
-
-#ifdef CONFIG_NET_RX_BUSY_POLL
-static inline bool be_lock_napi(struct be_eq_obj *eqo)
-{
- bool status = true;
-
- spin_lock(&eqo->lock); /* BH is already disabled */
- if (eqo->state & BE_EQ_LOCKED) {
- WARN_ON(eqo->state & BE_EQ_NAPI);
- eqo->state |= BE_EQ_NAPI_YIELD;
- status = false;
- } else {
- eqo->state = BE_EQ_NAPI;
- }
- spin_unlock(&eqo->lock);
- return status;
-}
-
-static inline void be_unlock_napi(struct be_eq_obj *eqo)
-{
- spin_lock(&eqo->lock); /* BH is already disabled */
-
- WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD));
- eqo->state = BE_EQ_IDLE;
-
- spin_unlock(&eqo->lock);
-}
-
-static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
-{
- bool status = true;
-
- spin_lock_bh(&eqo->lock);
- if (eqo->state & BE_EQ_LOCKED) {
- eqo->state |= BE_EQ_POLL_YIELD;
- status = false;
- } else {
- eqo->state |= BE_EQ_POLL;
- }
- spin_unlock_bh(&eqo->lock);
- return status;
-}
-
-static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
-{
- spin_lock_bh(&eqo->lock);
-
- WARN_ON(eqo->state & (BE_EQ_NAPI));
- eqo->state = BE_EQ_IDLE;
-
- spin_unlock_bh(&eqo->lock);
-}
-
-static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
-{
- spin_lock_init(&eqo->lock);
- eqo->state = BE_EQ_IDLE;
-}
-
-static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
-{
- local_bh_disable();
-
- /* It's enough to just acquire napi lock on the eqo to stop
- * be_busy_poll() from processing any queueus.
- */
- while (!be_lock_napi(eqo))
- mdelay(1);
-
- local_bh_enable();
-}
-
-#else /* CONFIG_NET_RX_BUSY_POLL */
-
-static inline bool be_lock_napi(struct be_eq_obj *eqo)
-{
- return true;
-}
-
-static inline void be_unlock_napi(struct be_eq_obj *eqo)
-{
-}
-
-static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
-{
- return false;
-}
-
-static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
-{
-}
-
-static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
-{
-}
-
-static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
-{
-}
-#endif /* CONFIG_NET_RX_BUSY_POLL */
-
void be_cq_notify(struct be_adapter *adapter, u16 qid, bool arm,
u16 num_popped);
void be_link_status_update(struct be_adapter *adapter, u8 link_status);
@@ -898,16 +751,6 @@ int be_load_fw(struct be_adapter *adapter, u8 *func);
bool be_is_wol_supported(struct be_adapter *adapter);
bool be_pause_supported(struct be_adapter *adapter);
u32 be_get_fw_log_level(struct be_adapter *adapter);
-
-static inline int fw_major_num(const char *fw_ver)
-{
- int fw_major = 0;
-
- sscanf(fw_ver, "%d.", &fw_major);
-
- return fw_major;
-}
-
int be_update_queues(struct be_adapter *adapter);
int be_poll(struct napi_struct *napi, int budget);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c
index fead5c65a4f0..36916cfa70f9 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.c
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.c
@@ -19,6 +19,22 @@
#include "be.h"
#include "be_cmds.h"
+static char *be_port_misconfig_evt_desc[] = {
+ "A valid SFP module detected",
+ "Optics faulted/ incorrectly installed/ not installed.",
+ "Optics of two types installed.",
+ "Incompatible optics.",
+ "Unknown port SFP status"
+};
+
+static char *be_port_misconfig_remedy_desc[] = {
+ "",
+ "Reseat optics. If issue not resolved, replace",
+ "Remove one optic or install matching pair of optics",
+ "Replace with compatible optics for card to function",
+ ""
+};
+
static struct be_cmd_priv_map cmd_priv_map[] = {
{
OPCODE_ETH_ACPI_WOL_MAGIC_CONFIG,
@@ -249,6 +265,29 @@ static void be_async_link_state_process(struct be_adapter *adapter,
evt->port_link_status & LINK_STATUS_MASK);
}
+static void be_async_port_misconfig_event_process(struct be_adapter *adapter,
+ struct be_mcc_compl *compl)
+{
+ struct be_async_event_misconfig_port *evt =
+ (struct be_async_event_misconfig_port *)compl;
+ u32 sfp_mismatch_evt = le32_to_cpu(evt->event_data_word1);
+ struct device *dev = &adapter->pdev->dev;
+ u8 port_misconfig_evt;
+
+ port_misconfig_evt =
+ ((sfp_mismatch_evt >> (adapter->hba_port_num * 8)) & 0xff);
+
+ /* Log an error message that would allow a user to determine
+ * whether the SFPs have an issue
+ */
+ dev_info(dev, "Port %c: %s %s", adapter->port_name,
+ be_port_misconfig_evt_desc[port_misconfig_evt],
+ be_port_misconfig_remedy_desc[port_misconfig_evt]);
+
+ if (port_misconfig_evt == INCOMPATIBLE_SFP)
+ adapter->flags |= BE_FLAGS_EVT_INCOMPATIBLE_SFP;
+}
+
/* Grp5 CoS Priority evt */
static void be_async_grp5_cos_priority_process(struct be_adapter *adapter,
struct be_mcc_compl *compl)
@@ -334,6 +373,16 @@ static void be_async_dbg_evt_process(struct be_adapter *adapter,
}
}
+static void be_async_sliport_evt_process(struct be_adapter *adapter,
+ struct be_mcc_compl *cmp)
+{
+ u8 event_type = (cmp->flags >> ASYNC_EVENT_TYPE_SHIFT) &
+ ASYNC_EVENT_TYPE_MASK;
+
+ if (event_type == ASYNC_EVENT_PORT_MISCONFIG)
+ be_async_port_misconfig_event_process(adapter, cmp);
+}
+
static inline bool is_link_state_evt(u32 flags)
{
return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
@@ -352,6 +401,12 @@ static inline bool is_dbg_evt(u32 flags)
ASYNC_EVENT_CODE_QNQ;
}
+static inline bool is_sliport_evt(u32 flags)
+{
+ return ((flags >> ASYNC_EVENT_CODE_SHIFT) & ASYNC_EVENT_CODE_MASK) ==
+ ASYNC_EVENT_CODE_SLIPORT;
+}
+
static void be_mcc_event_process(struct be_adapter *adapter,
struct be_mcc_compl *compl)
{
@@ -361,6 +416,8 @@ static void be_mcc_event_process(struct be_adapter *adapter,
be_async_grp5_evt_process(adapter, compl);
else if (is_dbg_evt(compl->flags))
be_async_dbg_evt_process(adapter, compl);
+ else if (is_sliport_evt(compl->flags))
+ be_async_sliport_evt_process(adapter, compl);
}
static struct be_mcc_compl *be_mcc_compl_get(struct be_adapter *adapter)
@@ -573,7 +630,7 @@ static int lancer_wait_ready(struct be_adapter *adapter)
{
#define SLIPORT_READY_TIMEOUT 30
u32 sliport_status;
- int status = 0, i;
+ int i;
for (i = 0; i < SLIPORT_READY_TIMEOUT; i++) {
sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET);
@@ -584,9 +641,9 @@ static int lancer_wait_ready(struct be_adapter *adapter)
}
if (i == SLIPORT_READY_TIMEOUT)
- status = -1;
+ return sliport_status ? : -1;
- return status;
+ return 0;
}
static bool lancer_provisioning_error(struct be_adapter *adapter)
@@ -624,7 +681,7 @@ int lancer_test_and_set_rdy_state(struct be_adapter *adapter)
iowrite32(SLI_PORT_CONTROL_IP_MASK,
adapter->db + SLIPORT_CONTROL_OFFSET);
- /* check adapter has corrected the error */
+ /* check if adapter has corrected the error */
status = lancer_wait_ready(adapter);
sliport_status = ioread32(adapter->db +
SLIPORT_STATUS_OFFSET);
@@ -655,7 +712,11 @@ int be_fw_wait_ready(struct be_adapter *adapter)
if (lancer_chip(adapter)) {
status = lancer_wait_ready(adapter);
- return status;
+ if (status) {
+ stage = status;
+ goto err;
+ }
+ return 0;
}
do {
@@ -671,7 +732,8 @@ int be_fw_wait_ready(struct be_adapter *adapter)
timeout += 2;
} while (timeout < 60);
- dev_err(dev, "POST timeout; stage=0x%x\n", stage);
+err:
+ dev_err(dev, "POST timeout; stage=%#x\n", stage);
return -1;
}
@@ -1166,9 +1228,15 @@ static int be_cmd_mccq_ext_create(struct be_adapter *adapter,
ctxt, 1);
}
- /* Subscribe to Link State and Group 5 Events(bits 1 and 5 set) */
- req->async_event_bitmap[0] = cpu_to_le32(0x00000022);
- req->async_event_bitmap[0] |= cpu_to_le32(1 << ASYNC_EVENT_CODE_QNQ);
+ /* Subscribe to Link State, Sliport Event and Group 5 Events
+ * (bits 1, 5 and 17 set)
+ */
+ req->async_event_bitmap[0] =
+ cpu_to_le32(BIT(ASYNC_EVENT_CODE_LINK_STATE) |
+ BIT(ASYNC_EVENT_CODE_GRP_5) |
+ BIT(ASYNC_EVENT_CODE_QNQ) |
+ BIT(ASYNC_EVENT_CODE_SLIPORT));
+
be_dws_cpu_to_le(ctxt, sizeof(req->context));
be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
@@ -1881,7 +1949,7 @@ err:
return status;
}
-int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+static int __be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
{
struct be_mcc_wrb *wrb;
struct be_dma_mem *mem = &adapter->rx_filter;
@@ -1901,31 +1969,13 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
wrb, mem);
req->if_id = cpu_to_le32(adapter->if_handle);
- if (flags & IFF_PROMISC) {
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_VLAN_PROMISCUOUS |
- BE_IF_FLAGS_MCAST_PROMISCUOUS);
- if (value == ON)
- req->if_flags =
- cpu_to_le32(BE_IF_FLAGS_PROMISCUOUS |
- BE_IF_FLAGS_VLAN_PROMISCUOUS |
- BE_IF_FLAGS_MCAST_PROMISCUOUS);
- } else if (flags & IFF_ALLMULTI) {
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
- req->if_flags = cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS);
- } else if (flags & BE_FLAGS_VLAN_PROMISC) {
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
-
- if (value == ON)
- req->if_flags =
- cpu_to_le32(BE_IF_FLAGS_VLAN_PROMISCUOUS);
- } else {
+ req->if_flags_mask = cpu_to_le32(flags);
+ req->if_flags = (value == ON) ? req->if_flags_mask : 0;
+
+ if (flags & BE_IF_FLAGS_MULTICAST) {
struct netdev_hw_addr *ha;
int i = 0;
- req->if_flags_mask = cpu_to_le32(BE_IF_FLAGS_MULTICAST);
- req->if_flags = cpu_to_le32(BE_IF_FLAGS_MULTICAST);
-
/* Reset mcast promisc mode if already set by setting mask
* and not setting flags field
*/
@@ -1937,24 +1987,26 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN);
}
- if ((req->if_flags_mask & cpu_to_le32(be_if_cap_flags(adapter))) !=
- req->if_flags_mask) {
- dev_warn(&adapter->pdev->dev,
- "Cannot set rx filter flags 0x%x\n",
- req->if_flags_mask);
- dev_warn(&adapter->pdev->dev,
- "Interface is capable of 0x%x flags only\n",
- be_if_cap_flags(adapter));
- }
- req->if_flags_mask &= cpu_to_le32(be_if_cap_flags(adapter));
-
status = be_mcc_notify_wait(adapter);
-
err:
spin_unlock_bh(&adapter->mcc_lock);
return status;
}
+int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if ((flags & be_if_cap_flags(adapter)) != flags) {
+ dev_warn(dev, "Cannot set rx filter flags 0x%x\n", flags);
+ dev_warn(dev, "Interface is capable of 0x%x flags only\n",
+ be_if_cap_flags(adapter));
+ }
+ flags &= be_if_cap_flags(adapter);
+
+ return __be_cmd_rx_filter(adapter, flags, value);
+}
+
/* Uses synchrounous mcc */
int be_cmd_set_flow_control(struct be_adapter *adapter, u32 tx_fc, u32 rx_fc)
{
@@ -2355,6 +2407,24 @@ int be_cmd_query_cable_type(struct be_adapter *adapter)
return status;
}
+int be_cmd_query_sfp_info(struct be_adapter *adapter)
+{
+ u8 page_data[PAGE_DATA_LEN];
+ int status;
+
+ status = be_cmd_read_port_transceiver_data(adapter, TR_PAGE_A0,
+ page_data);
+ if (!status) {
+ strlcpy(adapter->phy.vendor_name, page_data +
+ SFP_VENDOR_NAME_OFFSET, SFP_VENDOR_NAME_LEN - 1);
+ strlcpy(adapter->phy.vendor_pn,
+ page_data + SFP_VENDOR_PN_OFFSET,
+ SFP_VENDOR_NAME_LEN - 1);
+ }
+
+ return status;
+}
+
int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name)
{
struct lancer_cmd_req_delete_object *req;
@@ -2431,7 +2501,8 @@ err_unlock:
}
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
- u32 flash_type, u32 flash_opcode, u32 buf_size)
+ u32 flash_type, u32 flash_opcode, u32 img_offset,
+ u32 buf_size)
{
struct be_mcc_wrb *wrb;
struct be_cmd_write_flashrom *req;
@@ -2452,6 +2523,9 @@ int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
cmd);
req->params.op_type = cpu_to_le32(flash_type);
+ if (flash_type == OPTYPE_OFFSET_SPECIFIED)
+ req->params.offset = cpu_to_le32(img_offset);
+
req->params.op_code = cpu_to_le32(flash_opcode);
req->params.data_buf_size = cpu_to_le32(buf_size);
@@ -2472,10 +2546,10 @@ err_unlock:
}
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
- u16 optype, int offset)
+ u16 img_optype, u32 img_offset, u32 crc_offset)
{
- struct be_mcc_wrb *wrb;
struct be_cmd_read_flash_crc *req;
+ struct be_mcc_wrb *wrb;
int status;
spin_lock_bh(&adapter->mcc_lock);
@@ -2491,9 +2565,13 @@ int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
OPCODE_COMMON_READ_FLASHROM, sizeof(*req),
wrb, NULL);
- req->params.op_type = cpu_to_le32(optype);
+ req->params.op_type = cpu_to_le32(img_optype);
+ if (img_optype == OPTYPE_OFFSET_SPECIFIED)
+ req->params.offset = cpu_to_le32(img_offset + crc_offset);
+ else
+ req->params.offset = cpu_to_le32(crc_offset);
+
req->params.op_code = cpu_to_le32(FLASHROM_OPER_REPORT);
- req->params.offset = cpu_to_le32(offset);
req->params.data_buf_size = cpu_to_le32(0x4);
status = be_mcc_notify_wait(adapter);
@@ -2742,7 +2820,7 @@ err:
return status;
}
-int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
+static int be_cmd_set_qos(struct be_adapter *adapter, u32 bps, u32 domain)
{
struct be_mcc_wrb *wrb;
struct be_cmd_req_set_qos *req;
@@ -3236,6 +3314,24 @@ err:
return status;
}
+static bool be_is_wol_excluded(struct be_adapter *adapter)
+{
+ struct pci_dev *pdev = adapter->pdev;
+
+ if (!be_physfn(adapter))
+ return true;
+
+ switch (pdev->subsystem_device) {
+ case OC_SUBSYS_DEVICE_ID1:
+ case OC_SUBSYS_DEVICE_ID2:
+ case OC_SUBSYS_DEVICE_ID3:
+ case OC_SUBSYS_DEVICE_ID4:
+ return true;
+ default:
+ return false;
+ }
+}
+
int be_cmd_get_acpi_wol_cap(struct be_adapter *adapter)
{
struct be_mcc_wrb *wrb;
@@ -3422,42 +3518,34 @@ err:
return status;
}
-int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name)
+int be_cmd_query_port_name(struct be_adapter *adapter)
{
- struct be_mcc_wrb *wrb;
struct be_cmd_req_get_port_name *req;
+ struct be_mcc_wrb *wrb;
int status;
- if (!lancer_chip(adapter)) {
- *port_name = adapter->hba_port_num + '0';
- return 0;
- }
-
- spin_lock_bh(&adapter->mcc_lock);
-
- wrb = wrb_from_mccq(adapter);
- if (!wrb) {
- status = -EBUSY;
- goto err;
- }
+ if (mutex_lock_interruptible(&adapter->mbox_lock))
+ return -1;
+ wrb = wrb_from_mbox(adapter);
req = embedded_payload(wrb);
be_wrb_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
OPCODE_COMMON_GET_PORT_NAME, sizeof(*req), wrb,
NULL);
- req->hdr.version = 1;
+ if (!BEx_chip(adapter))
+ req->hdr.version = 1;
- status = be_mcc_notify_wait(adapter);
+ status = be_mbox_notify_wait(adapter);
if (!status) {
struct be_cmd_resp_get_port_name *resp = embedded_payload(wrb);
- *port_name = resp->port_name[adapter->hba_port_num];
+ adapter->port_name = resp->port_name[adapter->hba_port_num];
} else {
- *port_name = adapter->hba_port_num + '0';
+ adapter->port_name = adapter->hba_port_num + '0';
}
-err:
- spin_unlock_bh(&adapter->mcc_lock);
+
+ mutex_unlock(&adapter->mbox_lock);
return status;
}
@@ -3751,6 +3839,7 @@ int be_cmd_config_qos(struct be_adapter *adapter, u32 max_rate, u16 link_speed,
be_reset_nic_desc(&nic_desc);
nic_desc.pf_num = adapter->pf_number;
nic_desc.vf_num = domain;
+ nic_desc.bw_min = 0;
if (lancer_chip(adapter)) {
nic_desc.hdr.desc_type = NIC_RESOURCE_DESC_TYPE_V0;
nic_desc.hdr.desc_len = RESOURCE_DESC_SIZE_V0;
@@ -4092,7 +4181,7 @@ int be_cmd_set_logical_link_config(struct be_adapter *adapter,
int status;
if (BEx_chip(adapter) || lancer_chip(adapter))
- return 0;
+ return -EOPNOTSUPP;
spin_lock_bh(&adapter->mcc_lock);
diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.h b/drivers/net/ethernet/emulex/benet/be_cmds.h
index eb5085d6794f..db761e8e42a3 100644
--- a/drivers/net/ethernet/emulex/benet/be_cmds.h
+++ b/drivers/net/ethernet/emulex/benet/be_cmds.h
@@ -44,10 +44,10 @@ struct be_mcc_wrb {
} payload;
};
-#define CQE_FLAGS_VALID_MASK (1 << 31)
-#define CQE_FLAGS_ASYNC_MASK (1 << 30)
-#define CQE_FLAGS_COMPLETED_MASK (1 << 28)
-#define CQE_FLAGS_CONSUMED_MASK (1 << 27)
+#define CQE_FLAGS_VALID_MASK BIT(31)
+#define CQE_FLAGS_ASYNC_MASK BIT(30)
+#define CQE_FLAGS_COMPLETED_MASK BIT(28)
+#define CQE_FLAGS_CONSUMED_MASK BIT(27)
/* Completion Status */
enum mcc_base_status {
@@ -102,6 +102,8 @@ struct be_mcc_compl {
#define ASYNC_EVENT_PVID_STATE 0x3
#define ASYNC_EVENT_CODE_QNQ 0x6
#define ASYNC_DEBUG_EVENT_TYPE_QNQ 1
+#define ASYNC_EVENT_CODE_SLIPORT 0x11
+#define ASYNC_EVENT_PORT_MISCONFIG 0x9
enum {
LINK_DOWN = 0x0,
@@ -169,6 +171,15 @@ struct be_async_event_qnq {
u32 flags;
} __packed;
+#define INCOMPATIBLE_SFP 0x3
+/* async event indicating misconfigured port */
+struct be_async_event_misconfig_port {
+ u32 event_data_word1;
+ u32 event_data_word2;
+ u32 rsvd0;
+ u32 flags;
+} __packed;
+
struct be_mcc_mailbox {
struct be_mcc_wrb wrb;
struct be_mcc_compl compl;
@@ -586,6 +597,10 @@ enum be_if_flags {
BE_IF_FLAGS_PASS_L3L4_ERRORS | BE_IF_FLAGS_MULTICAST |\
BE_IF_FLAGS_UNTAGGED)
+#define BE_IF_FLAGS_ALL_PROMISCUOUS (BE_IF_FLAGS_PROMISCUOUS | \
+ BE_IF_FLAGS_VLAN_PROMISCUOUS |\
+ BE_IF_FLAGS_MCAST_PROMISCUOUS)
+
/* An RX interface is an object with one or more MAC addresses and
* filtering capabilities. */
struct be_cmd_req_if_create {
@@ -1024,6 +1039,8 @@ enum {
#define SFP_PLUS_SFF_8472_COMP 0x5E
#define SFP_PLUS_CABLE_TYPE_OFFSET 0x8
#define SFP_PLUS_COPPER_CABLE 0x4
+#define SFP_VENDOR_NAME_OFFSET 0x14
+#define SFP_VENDOR_PN_OFFSET 0x28
#define PAGE_DATA_LEN 256
struct be_cmd_resp_port_type {
@@ -1091,6 +1108,10 @@ struct be_cmd_req_query_fw_cfg {
u32 rsvd[31];
};
+/* ASIC revisions */
+#define ASIC_REV_B0 0x10
+#define ASIC_REV_P2 0x11
+
struct be_cmd_resp_query_fw_cfg {
struct be_cmd_resp_hdr hdr;
u32 be_config_number;
@@ -1161,7 +1182,173 @@ struct be_cmd_resp_get_beacon_state {
u8 rsvd0[3];
} __packed;
+/* Flashrom related descriptors */
+#define MAX_FLASH_COMP 32
+
+#define OPTYPE_ISCSI_ACTIVE 0
+#define OPTYPE_REDBOOT 1
+#define OPTYPE_BIOS 2
+#define OPTYPE_PXE_BIOS 3
+#define OPTYPE_OFFSET_SPECIFIED 7
+#define OPTYPE_FCOE_BIOS 8
+#define OPTYPE_ISCSI_BACKUP 9
+#define OPTYPE_FCOE_FW_ACTIVE 10
+#define OPTYPE_FCOE_FW_BACKUP 11
+#define OPTYPE_NCSI_FW 13
+#define OPTYPE_REDBOOT_DIR 18
+#define OPTYPE_REDBOOT_CONFIG 19
+#define OPTYPE_SH_PHY_FW 21
+#define OPTYPE_FLASHISM_JUMPVECTOR 22
+#define OPTYPE_UFI_DIR 23
+#define OPTYPE_PHY_FW 99
+
+#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 262144 /* Max OPTION ROM image sz */
+#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 262144 /* Max Redboot image sz */
+#define FLASH_IMAGE_MAX_SIZE_g2 1310720 /* Max firmware image size */
+
+#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 262144
+#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144
+#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 524288 /* Max OPTION ROM image sz */
+#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 1048576 /* Max Redboot image sz */
+#define FLASH_IMAGE_MAX_SIZE_g3 2097152 /* Max firmware image size */
+
+/* Offsets for components on Flash. */
+#define FLASH_REDBOOT_START_g2 0
+#define FLASH_FCoE_BIOS_START_g2 524288
+#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 1048576
+#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 2359296
+#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 3670016
+#define FLASH_FCoE_BACKUP_IMAGE_START_g2 4980736
+#define FLASH_iSCSI_BIOS_START_g2 7340032
+#define FLASH_PXE_BIOS_START_g2 7864320
+
+#define FLASH_REDBOOT_START_g3 262144
+#define FLASH_PHY_FW_START_g3 1310720
+#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 2097152
+#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 4194304
+#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 6291456
+#define FLASH_FCoE_BACKUP_IMAGE_START_g3 8388608
+#define FLASH_iSCSI_BIOS_START_g3 12582912
+#define FLASH_PXE_BIOS_START_g3 13107200
+#define FLASH_FCoE_BIOS_START_g3 13631488
+#define FLASH_NCSI_START_g3 15990784
+
+#define IMAGE_NCSI 16
+#define IMAGE_OPTION_ROM_PXE 32
+#define IMAGE_OPTION_ROM_FCoE 33
+#define IMAGE_OPTION_ROM_ISCSI 34
+#define IMAGE_FLASHISM_JUMPVECTOR 48
+#define IMAGE_FIRMWARE_iSCSI 160
+#define IMAGE_FIRMWARE_FCoE 162
+#define IMAGE_FIRMWARE_BACKUP_iSCSI 176
+#define IMAGE_FIRMWARE_BACKUP_FCoE 178
+#define IMAGE_FIRMWARE_PHY 192
+#define IMAGE_REDBOOT_DIR 208
+#define IMAGE_REDBOOT_CONFIG 209
+#define IMAGE_UFI_DIR 210
+#define IMAGE_BOOT_CODE 224
+
+struct controller_id {
+ u32 vendor;
+ u32 device;
+ u32 subvendor;
+ u32 subdevice;
+};
+
+struct flash_comp {
+ unsigned long offset;
+ int optype;
+ int size;
+ int img_type;
+};
+
+struct image_hdr {
+ u32 imageid;
+ u32 imageoffset;
+ u32 imagelength;
+ u32 image_checksum;
+ u8 image_version[32];
+};
+
+struct flash_file_hdr_g2 {
+ u8 sign[32];
+ u32 cksum;
+ u32 antidote;
+ struct controller_id cont_id;
+ u32 file_len;
+ u32 chunk_num;
+ u32 total_chunks;
+ u32 num_imgs;
+ u8 build[24];
+};
+
+/* First letter of the build version of the image */
+#define BLD_STR_UFI_TYPE_BE2 '2'
+#define BLD_STR_UFI_TYPE_BE3 '3'
+#define BLD_STR_UFI_TYPE_SH '4'
+
+struct flash_file_hdr_g3 {
+ u8 sign[52];
+ u8 ufi_version[4];
+ u32 file_len;
+ u32 cksum;
+ u32 antidote;
+ u32 num_imgs;
+ u8 build[24];
+ u8 asic_type_rev;
+ u8 rsvd[31];
+};
+
+struct flash_section_hdr {
+ u32 format_rev;
+ u32 cksum;
+ u32 antidote;
+ u32 num_images;
+ u8 id_string[128];
+ u32 rsvd[4];
+} __packed;
+
+struct flash_section_hdr_g2 {
+ u32 format_rev;
+ u32 cksum;
+ u32 antidote;
+ u32 build_num;
+ u8 id_string[128];
+ u32 rsvd[8];
+} __packed;
+
+struct flash_section_entry {
+ u32 type;
+ u32 offset;
+ u32 pad_size;
+ u32 image_size;
+ u32 cksum;
+ u32 entry_point;
+ u16 optype;
+ u16 rsvd0;
+ u32 rsvd1;
+ u8 ver_data[32];
+} __packed;
+
+struct flash_section_info {
+ u8 cookie[32];
+ struct flash_section_hdr fsec_hdr;
+ struct flash_section_entry fsec_entry[32];
+} __packed;
+
+struct flash_section_info_g2 {
+ u8 cookie[32];
+ struct flash_section_hdr_g2 fsec_hdr;
+ struct flash_section_entry fsec_entry[32];
+} __packed;
+
/****************** Firmware Flash ******************/
+#define FLASHROM_OPER_FLASH 1
+#define FLASHROM_OPER_SAVE 2
+#define FLASHROM_OPER_REPORT 4
+#define FLASHROM_OPER_PHY_FLASH 9
+#define FLASHROM_OPER_PHY_SAVE 10
+
struct flashrom_params {
u32 op_code;
u32 op_type;
@@ -1366,6 +1553,7 @@ enum {
PHY_TYPE_QSFP,
PHY_TYPE_KR4_40GB,
PHY_TYPE_KR2_20GB,
+ PHY_TYPE_TN_8022,
PHY_TYPE_DISABLED = 255
};
@@ -1429,6 +1617,20 @@ struct be_cmd_req_set_qos {
};
/*********************** Controller Attributes ***********************/
+struct mgmt_hba_attribs {
+ u32 rsvd0[24];
+ u8 controller_model_number[32];
+ u32 rsvd1[79];
+ u8 rsvd2[3];
+ u8 phy_port;
+ u32 rsvd3[13];
+} __packed;
+
+struct mgmt_controller_attrib {
+ struct mgmt_hba_attribs hba_attribs;
+ u32 rsvd0[10];
+} __packed;
+
struct be_cmd_req_cntl_attribs {
struct be_cmd_req_hdr hdr;
};
@@ -2070,8 +2272,10 @@ int be_cmd_get_beacon_state(struct be_adapter *adapter, u8 port_num,
int be_cmd_read_port_transceiver_data(struct be_adapter *adapter,
u8 page_num, u8 *data);
int be_cmd_query_cable_type(struct be_adapter *adapter);
+int be_cmd_query_sfp_info(struct be_adapter *adapter);
int be_cmd_write_flashrom(struct be_adapter *adapter, struct be_dma_mem *cmd,
- u32 flash_oper, u32 flash_opcode, u32 buf_size);
+ u32 flash_oper, u32 flash_opcode, u32 img_offset,
+ u32 buf_size);
int lancer_cmd_write_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
u32 data_size, u32 data_offset,
const char *obj_name, u32 *data_written,
@@ -2081,7 +2285,7 @@ int lancer_cmd_read_object(struct be_adapter *adapter, struct be_dma_mem *cmd,
u32 *data_read, u32 *eof, u8 *addn_status);
int lancer_cmd_delete_object(struct be_adapter *adapter, const char *obj_name);
int be_cmd_get_flash_crc(struct be_adapter *adapter, u8 *flashed_crc,
- u16 optype, int offset);
+ u16 img_optype, u32 img_offset, u32 crc_offset);
int be_cmd_enable_magic_wol(struct be_adapter *adapter, u8 *mac,
struct be_dma_mem *nonemb_cmd);
int be_cmd_fw_init(struct be_adapter *adapter);
@@ -2136,7 +2340,7 @@ int lancer_initiate_dump(struct be_adapter *adapter);
int lancer_delete_dump(struct be_adapter *adapter);
bool dump_present(struct be_adapter *adapter);
int lancer_test_and_set_rdy_state(struct be_adapter *adapter);
-int be_cmd_query_port_name(struct be_adapter *adapter, u8 *port_name);
+int be_cmd_query_port_name(struct be_adapter *adapter);
int be_cmd_get_func_config(struct be_adapter *adapter,
struct be_resources *res);
int be_cmd_get_profile_config(struct be_adapter *adapter,
diff --git a/drivers/net/ethernet/emulex/benet/be_ethtool.c b/drivers/net/ethernet/emulex/benet/be_ethtool.c
index 73a500ccbf69..4d2de4700769 100644
--- a/drivers/net/ethernet/emulex/benet/be_ethtool.c
+++ b/drivers/net/ethernet/emulex/benet/be_ethtool.c
@@ -193,8 +193,6 @@ static const struct be_ethtool_stat et_tx_stats[] = {
{DRVSTAT_TX_INFO(tx_pkts)},
/* Number of skbs queued for trasmission by the driver */
{DRVSTAT_TX_INFO(tx_reqs)},
- /* Number of TX work request blocks DMAed to HW */
- {DRVSTAT_TX_INFO(tx_wrbs)},
/* Number of times the TX queue was stopped due to lack
* of spaces in the TXQ.
*/
@@ -707,15 +705,17 @@ be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
if (ecmd->autoneg != adapter->phy.fc_autoneg)
return -EINVAL;
- adapter->tx_fc = ecmd->tx_pause;
- adapter->rx_fc = ecmd->rx_pause;
- status = be_cmd_set_flow_control(adapter,
- adapter->tx_fc, adapter->rx_fc);
- if (status)
+ status = be_cmd_set_flow_control(adapter, ecmd->tx_pause,
+ ecmd->rx_pause);
+ if (status) {
dev_warn(&adapter->pdev->dev, "Pause param set failed\n");
+ return be_cmd_status(status);
+ }
- return be_cmd_status(status);
+ adapter->tx_fc = ecmd->tx_pause;
+ adapter->rx_fc = ecmd->rx_pause;
+ return 0;
}
static int be_set_phys_id(struct net_device *netdev,
diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h
index 295ee0835ba0..48840889db62 100644
--- a/drivers/net/ethernet/emulex/benet/be_hw.h
+++ b/drivers/net/ethernet/emulex/benet/be_hw.h
@@ -75,7 +75,7 @@
* atomically without having to arbitrate for the PCI Interrupt Disable bit
* with the OS.
*/
-#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK (1 << 29) /* bit 29 */
+#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK BIT(29) /* bit 29 */
/********* PCI Function Capability *********/
#define BE_FUNCTION_CAPS_RSS 0x2
@@ -171,94 +171,6 @@
#define RETRIEVE_FAT 0
#define QUERY_FAT 1
-/* Flashrom related descriptors */
-#define MAX_FLASH_COMP 32
-#define IMAGE_TYPE_FIRMWARE 160
-#define IMAGE_TYPE_BOOTCODE 224
-#define IMAGE_TYPE_OPTIONROM 32
-
-#define NUM_FLASHDIR_ENTRIES 32
-
-#define OPTYPE_ISCSI_ACTIVE 0
-#define OPTYPE_REDBOOT 1
-#define OPTYPE_BIOS 2
-#define OPTYPE_PXE_BIOS 3
-#define OPTYPE_FCOE_BIOS 8
-#define OPTYPE_ISCSI_BACKUP 9
-#define OPTYPE_FCOE_FW_ACTIVE 10
-#define OPTYPE_FCOE_FW_BACKUP 11
-#define OPTYPE_NCSI_FW 13
-#define OPTYPE_REDBOOT_DIR 18
-#define OPTYPE_REDBOOT_CONFIG 19
-#define OPTYPE_SH_PHY_FW 21
-#define OPTYPE_FLASHISM_JUMPVECTOR 22
-#define OPTYPE_UFI_DIR 23
-#define OPTYPE_PHY_FW 99
-#define TN_8022 13
-
-#define FLASHROM_OPER_PHY_FLASH 9
-#define FLASHROM_OPER_PHY_SAVE 10
-#define FLASHROM_OPER_FLASH 1
-#define FLASHROM_OPER_SAVE 2
-#define FLASHROM_OPER_REPORT 4
-
-#define FLASH_IMAGE_MAX_SIZE_g2 (1310720) /* Max firmware image size */
-#define FLASH_BIOS_IMAGE_MAX_SIZE_g2 (262144) /* Max OPTION ROM image sz */
-#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g2 (262144) /* Max Redboot image sz */
-#define FLASH_IMAGE_MAX_SIZE_g3 (2097152) /* Max firmware image size */
-#define FLASH_BIOS_IMAGE_MAX_SIZE_g3 (524288) /* Max OPTION ROM image sz */
-#define FLASH_REDBOOT_IMAGE_MAX_SIZE_g3 (1048576) /* Max Redboot image sz */
-#define FLASH_NCSI_IMAGE_MAX_SIZE_g3 (262144)
-#define FLASH_PHY_FW_IMAGE_MAX_SIZE_g3 262144
-
-#define FLASH_NCSI_MAGIC (0x16032009)
-#define FLASH_NCSI_DISABLED (0)
-#define FLASH_NCSI_ENABLED (1)
-
-#define FLASH_NCSI_BITFILE_HDR_OFFSET (0x600000)
-
-/* Offsets for components on Flash. */
-#define FLASH_iSCSI_PRIMARY_IMAGE_START_g2 (1048576)
-#define FLASH_iSCSI_BACKUP_IMAGE_START_g2 (2359296)
-#define FLASH_FCoE_PRIMARY_IMAGE_START_g2 (3670016)
-#define FLASH_FCoE_BACKUP_IMAGE_START_g2 (4980736)
-#define FLASH_iSCSI_BIOS_START_g2 (7340032)
-#define FLASH_PXE_BIOS_START_g2 (7864320)
-#define FLASH_FCoE_BIOS_START_g2 (524288)
-#define FLASH_REDBOOT_START_g2 (0)
-
-#define FLASH_NCSI_START_g3 (15990784)
-#define FLASH_iSCSI_PRIMARY_IMAGE_START_g3 (2097152)
-#define FLASH_iSCSI_BACKUP_IMAGE_START_g3 (4194304)
-#define FLASH_FCoE_PRIMARY_IMAGE_START_g3 (6291456)
-#define FLASH_FCoE_BACKUP_IMAGE_START_g3 (8388608)
-#define FLASH_iSCSI_BIOS_START_g3 (12582912)
-#define FLASH_PXE_BIOS_START_g3 (13107200)
-#define FLASH_FCoE_BIOS_START_g3 (13631488)
-#define FLASH_REDBOOT_START_g3 (262144)
-#define FLASH_PHY_FW_START_g3 1310720
-
-#define IMAGE_NCSI 16
-#define IMAGE_OPTION_ROM_PXE 32
-#define IMAGE_OPTION_ROM_FCoE 33
-#define IMAGE_OPTION_ROM_ISCSI 34
-#define IMAGE_FLASHISM_JUMPVECTOR 48
-#define IMAGE_FLASH_ISM 49
-#define IMAGE_JUMP_VECTOR 50
-#define IMAGE_FIRMWARE_iSCSI 160
-#define IMAGE_FIRMWARE_COMP_iSCSI 161
-#define IMAGE_FIRMWARE_FCoE 162
-#define IMAGE_FIRMWARE_COMP_FCoE 163
-#define IMAGE_FIRMWARE_BACKUP_iSCSI 176
-#define IMAGE_FIRMWARE_BACKUP_COMP_iSCSI 177
-#define IMAGE_FIRMWARE_BACKUP_FCoE 178
-#define IMAGE_FIRMWARE_BACKUP_COMP_FCoE 179
-#define IMAGE_FIRMWARE_PHY 192
-#define IMAGE_REDBOOT_DIR 208
-#define IMAGE_REDBOOT_CONFIG 209
-#define IMAGE_UFI_DIR 210
-#define IMAGE_BOOT_CODE 224
-
/************* Rx Packet Type Encoding **************/
#define BE_UNICAST_PACKET 0
#define BE_MULTICAST_PACKET 1
@@ -281,10 +193,10 @@ struct be_eq_entry {
/* TX Queue Descriptor */
#define ETH_WRB_FRAG_LEN_MASK 0xFFFF
struct be_eth_wrb {
- u32 frag_pa_hi; /* dword 0 */
- u32 frag_pa_lo; /* dword 1 */
- u32 rsvd0; /* dword 2 */
- u32 frag_len; /* dword 3: bits 0 - 15 */
+ __le32 frag_pa_hi; /* dword 0 */
+ __le32 frag_pa_lo; /* dword 1 */
+ u32 rsvd0; /* dword 2 */
+ __le32 frag_len; /* dword 3: bits 0 - 15 */
} __packed;
/* Pseudo amap definition for eth_hdr_wrb in which each bit of the
@@ -311,8 +223,13 @@ struct amap_eth_hdr_wrb {
u8 vlan_tag[16];
} __packed;
+#define TX_HDR_WRB_COMPL 1 /* word 2 */
+#define TX_HDR_WRB_EVT BIT(1) /* word 2 */
+#define TX_HDR_WRB_NUM_SHIFT 13 /* word 2: bits 13:17 */
+#define TX_HDR_WRB_NUM_MASK 0x1F /* word 2: bits 13:17 */
+
struct be_eth_hdr_wrb {
- u32 dw[4];
+ __le32 dw[4];
};
/********* Tx Compl Status Encoding *********/
@@ -435,138 +352,3 @@ struct amap_eth_rx_compl_v1 {
struct be_eth_rx_compl {
u32 dw[4];
};
-
-struct mgmt_hba_attribs {
- u8 flashrom_version_string[32];
- u8 manufacturer_name[32];
- u32 supported_modes;
- u32 rsvd0[3];
- u8 ncsi_ver_string[12];
- u32 default_extended_timeout;
- u8 controller_model_number[32];
- u8 controller_description[64];
- u8 controller_serial_number[32];
- u8 ip_version_string[32];
- u8 firmware_version_string[32];
- u8 bios_version_string[32];
- u8 redboot_version_string[32];
- u8 driver_version_string[32];
- u8 fw_on_flash_version_string[32];
- u32 functionalities_supported;
- u16 max_cdblength;
- u8 asic_revision;
- u8 generational_guid[16];
- u8 hba_port_count;
- u16 default_link_down_timeout;
- u8 iscsi_ver_min_max;
- u8 multifunction_device;
- u8 cache_valid;
- u8 hba_status;
- u8 max_domains_supported;
- u8 phy_port;
- u32 firmware_post_status;
- u32 hba_mtu[8];
- u32 rsvd1[4];
-};
-
-struct mgmt_controller_attrib {
- struct mgmt_hba_attribs hba_attribs;
- u16 pci_vendor_id;
- u16 pci_device_id;
- u16 pci_sub_vendor_id;
- u16 pci_sub_system_id;
- u8 pci_bus_number;
- u8 pci_device_number;
- u8 pci_function_number;
- u8 interface_type;
- u64 unique_identifier;
- u32 rsvd0[5];
-};
-
-struct controller_id {
- u32 vendor;
- u32 device;
- u32 subvendor;
- u32 subdevice;
-};
-
-struct flash_comp {
- unsigned long offset;
- int optype;
- int size;
- int img_type;
-};
-
-struct image_hdr {
- u32 imageid;
- u32 imageoffset;
- u32 imagelength;
- u32 image_checksum;
- u8 image_version[32];
-};
-struct flash_file_hdr_g2 {
- u8 sign[32];
- u32 cksum;
- u32 antidote;
- struct controller_id cont_id;
- u32 file_len;
- u32 chunk_num;
- u32 total_chunks;
- u32 num_imgs;
- u8 build[24];
-};
-
-struct flash_file_hdr_g3 {
- u8 sign[52];
- u8 ufi_version[4];
- u32 file_len;
- u32 cksum;
- u32 antidote;
- u32 num_imgs;
- u8 build[24];
- u8 asic_type_rev;
- u8 rsvd[31];
-};
-
-struct flash_section_hdr {
- u32 format_rev;
- u32 cksum;
- u32 antidote;
- u32 num_images;
- u8 id_string[128];
- u32 rsvd[4];
-} __packed;
-
-struct flash_section_hdr_g2 {
- u32 format_rev;
- u32 cksum;
- u32 antidote;
- u32 build_num;
- u8 id_string[128];
- u32 rsvd[8];
-} __packed;
-
-struct flash_section_entry {
- u32 type;
- u32 offset;
- u32 pad_size;
- u32 image_size;
- u32 cksum;
- u32 entry_point;
- u16 optype;
- u16 rsvd0;
- u32 rsvd1;
- u8 ver_data[32];
-} __packed;
-
-struct flash_section_info {
- u8 cookie[32];
- struct flash_section_hdr fsec_hdr;
- struct flash_section_entry fsec_entry[32];
-} __packed;
-
-struct flash_section_info_g2 {
- u8 cookie[32];
- struct flash_section_hdr_g2 fsec_hdr;
- struct flash_section_entry fsec_entry[32];
-} __packed;
diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c
index d48806b5cd88..0a816859aca5 100644
--- a/drivers/net/ethernet/emulex/benet/be_main.c
+++ b/drivers/net/ethernet/emulex/benet/be_main.c
@@ -26,7 +26,6 @@
#include <net/vxlan.h>
MODULE_VERSION(DRV_VER);
-MODULE_DEVICE_TABLE(pci, be_dev_ids);
MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
MODULE_AUTHOR("Emulex Corporation");
MODULE_LICENSE("GPL");
@@ -662,48 +661,40 @@ void be_link_status_update(struct be_adapter *adapter, u8 link_status)
netif_carrier_off(netdev);
}
-static void be_tx_stats_update(struct be_tx_obj *txo,
- u32 wrb_cnt, u32 copied, u32 gso_segs,
- bool stopped)
+static void be_tx_stats_update(struct be_tx_obj *txo, struct sk_buff *skb)
{
struct be_tx_stats *stats = tx_stats(txo);
u64_stats_update_begin(&stats->sync);
stats->tx_reqs++;
- stats->tx_wrbs += wrb_cnt;
- stats->tx_bytes += copied;
- stats->tx_pkts += (gso_segs ? gso_segs : 1);
- if (stopped)
- stats->tx_stops++;
+ stats->tx_bytes += skb->len;
+ stats->tx_pkts += (skb_shinfo(skb)->gso_segs ? : 1);
u64_stats_update_end(&stats->sync);
}
-/* Determine number of WRB entries needed to xmit data in an skb */
-static u32 wrb_cnt_for_skb(struct be_adapter *adapter, struct sk_buff *skb,
- bool *dummy)
+/* Returns number of WRBs needed for the skb */
+static u32 skb_wrb_cnt(struct sk_buff *skb)
{
- int cnt = (skb->len > skb->data_len);
-
- cnt += skb_shinfo(skb)->nr_frags;
-
- /* to account for hdr wrb */
- cnt++;
- if (lancer_chip(adapter) || !(cnt & 1)) {
- *dummy = false;
- } else {
- /* add a dummy to make it an even num */
- cnt++;
- *dummy = true;
- }
- BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT);
- return cnt;
+ /* +1 for the header wrb */
+ return 1 + (skb_headlen(skb) ? 1 : 0) + skb_shinfo(skb)->nr_frags;
}
static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
{
- wrb->frag_pa_hi = upper_32_bits(addr);
- wrb->frag_pa_lo = addr & 0xFFFFFFFF;
- wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
+ wrb->frag_pa_hi = cpu_to_le32(upper_32_bits(addr));
+ wrb->frag_pa_lo = cpu_to_le32(lower_32_bits(addr));
+ wrb->frag_len = cpu_to_le32(len & ETH_WRB_FRAG_LEN_MASK);
+ wrb->rsvd0 = 0;
+}
+
+/* A dummy wrb is just all zeros. Using a separate routine for dummy-wrb
+ * to avoid the swap and shift/mask operations in wrb_fill().
+ */
+static inline void wrb_fill_dummy(struct be_eth_wrb *wrb)
+{
+ wrb->frag_pa_hi = 0;
+ wrb->frag_pa_lo = 0;
+ wrb->frag_len = 0;
wrb->rsvd0 = 0;
}
@@ -713,7 +704,7 @@ static inline u16 be_get_tx_vlan_tag(struct be_adapter *adapter,
u8 vlan_prio;
u16 vlan_tag;
- vlan_tag = vlan_tx_tag_get(skb);
+ vlan_tag = skb_vlan_tag_get(skb);
vlan_prio = (vlan_tag & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT;
/* If vlan priority provided by OS is NOT in available bmap */
if (!(adapter->vlan_prio_bmap & (1 << vlan_prio)))
@@ -764,52 +755,57 @@ static void wrb_fill_hdr(struct be_adapter *adapter, struct be_eth_hdr_wrb *hdr,
SET_TX_WRB_HDR_BITS(udpcs, hdr, 1);
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
SET_TX_WRB_HDR_BITS(vlan, hdr, 1);
vlan_tag = be_get_tx_vlan_tag(adapter, skb);
SET_TX_WRB_HDR_BITS(vlan_tag, hdr, vlan_tag);
}
- /* To skip HW VLAN tagging: evt = 1, compl = 0 */
- SET_TX_WRB_HDR_BITS(complete, hdr, !skip_hw_vlan);
- SET_TX_WRB_HDR_BITS(event, hdr, 1);
SET_TX_WRB_HDR_BITS(num_wrb, hdr, wrb_cnt);
SET_TX_WRB_HDR_BITS(len, hdr, len);
+
+ /* Hack to skip HW VLAN tagging needs evt = 1, compl = 0
+ * When this hack is not needed, the evt bit is set while ringing DB
+ */
+ if (skip_hw_vlan)
+ SET_TX_WRB_HDR_BITS(event, hdr, 1);
}
static void unmap_tx_frag(struct device *dev, struct be_eth_wrb *wrb,
bool unmap_single)
{
dma_addr_t dma;
+ u32 frag_len = le32_to_cpu(wrb->frag_len);
- be_dws_le_to_cpu(wrb, sizeof(*wrb));
- dma = (u64)wrb->frag_pa_hi << 32 | (u64)wrb->frag_pa_lo;
- if (wrb->frag_len) {
+ dma = (u64)le32_to_cpu(wrb->frag_pa_hi) << 32 |
+ (u64)le32_to_cpu(wrb->frag_pa_lo);
+ if (frag_len) {
if (unmap_single)
- dma_unmap_single(dev, dma, wrb->frag_len,
- DMA_TO_DEVICE);
+ dma_unmap_single(dev, dma, frag_len, DMA_TO_DEVICE);
else
- dma_unmap_page(dev, dma, wrb->frag_len, DMA_TO_DEVICE);
+ dma_unmap_page(dev, dma, frag_len, DMA_TO_DEVICE);
}
}
-static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
- struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb,
- bool skip_hw_vlan)
+/* Returns the number of WRBs used up by the skb */
+static u32 be_xmit_enqueue(struct be_adapter *adapter, struct be_tx_obj *txo,
+ struct sk_buff *skb, bool skip_hw_vlan)
{
- dma_addr_t busaddr;
- int i, copied = 0;
+ u32 i, copied = 0, wrb_cnt = skb_wrb_cnt(skb);
struct device *dev = &adapter->pdev->dev;
- struct sk_buff *first_skb = skb;
- struct be_eth_wrb *wrb;
+ struct be_queue_info *txq = &txo->q;
struct be_eth_hdr_wrb *hdr;
bool map_single = false;
- u16 map_head;
+ struct be_eth_wrb *wrb;
+ dma_addr_t busaddr;
+ u16 head = txq->head;
hdr = queue_head_node(txq);
+ wrb_fill_hdr(adapter, hdr, skb, wrb_cnt, skb->len, skip_hw_vlan);
+ be_dws_cpu_to_le(hdr, sizeof(*hdr));
+
queue_head_inc(txq);
- map_head = txq->head;
if (skb->len > skb->data_len) {
int len = skb_headlen(skb);
@@ -820,7 +816,6 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
map_single = true;
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, len);
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
copied += len;
}
@@ -834,35 +829,44 @@ static int make_tx_wrbs(struct be_adapter *adapter, struct be_queue_info *txq,
goto dma_err;
wrb = queue_head_node(txq);
wrb_fill(wrb, busaddr, skb_frag_size(frag));
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
queue_head_inc(txq);
copied += skb_frag_size(frag);
}
- if (dummy_wrb) {
- wrb = queue_head_node(txq);
- wrb_fill(wrb, 0, 0);
- be_dws_cpu_to_le(wrb, sizeof(*wrb));
- queue_head_inc(txq);
- }
+ BUG_ON(txo->sent_skb_list[head]);
+ txo->sent_skb_list[head] = skb;
+ txo->last_req_hdr = head;
+ atomic_add(wrb_cnt, &txq->used);
+ txo->last_req_wrb_cnt = wrb_cnt;
+ txo->pend_wrb_cnt += wrb_cnt;
- wrb_fill_hdr(adapter, hdr, first_skb, wrb_cnt, copied, skip_hw_vlan);
- be_dws_cpu_to_le(hdr, sizeof(*hdr));
+ be_tx_stats_update(txo, skb);
+ return wrb_cnt;
- return copied;
dma_err:
- txq->head = map_head;
+ /* Bring the queue back to the state it was in before this
+ * routine was invoked.
+ */
+ txq->head = head;
+ /* skip the first wrb (hdr); it's not mapped */
+ queue_head_inc(txq);
while (copied) {
wrb = queue_head_node(txq);
unmap_tx_frag(dev, wrb, map_single);
map_single = false;
- copied -= wrb->frag_len;
+ copied -= le32_to_cpu(wrb->frag_len);
adapter->drv_stats.dma_map_errors++;
queue_head_inc(txq);
}
+ txq->head = head;
return 0;
}
+static inline int qnq_async_evt_rcvd(struct be_adapter *adapter)
+{
+ return adapter->flags & BE_FLAGS_QNQ_ASYNC_EVT_RCVD;
+}
+
static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
struct sk_buff *skb,
bool *skip_hw_vlan)
@@ -873,7 +877,7 @@ static struct sk_buff *be_insert_vlan_in_pkt(struct be_adapter *adapter,
if (unlikely(!skb))
return skb;
- if (vlan_tx_tag_present(skb))
+ if (skb_vlan_tag_present(skb))
vlan_tag = be_get_tx_vlan_tag(adapter, skb);
if (qnq_async_evt_rcvd(adapter) && adapter->pvid) {
@@ -932,7 +936,7 @@ static bool be_ipv6_exthdr_check(struct sk_buff *skb)
static int be_vlan_tag_tx_chk(struct be_adapter *adapter, struct sk_buff *skb)
{
- return vlan_tx_tag_present(skb) || adapter->pvid || adapter->qnq_vid;
+ return skb_vlan_tag_present(skb) || adapter->pvid || adapter->qnq_vid;
}
static int be_ipv6_tx_stall_chk(struct be_adapter *adapter, struct sk_buff *skb)
@@ -955,7 +959,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
eth_hdr_len = ntohs(skb->protocol) == ETH_P_8021Q ?
VLAN_ETH_HLEN : ETH_HLEN;
if (skb->len <= 60 &&
- (lancer_chip(adapter) || vlan_tx_tag_present(skb)) &&
+ (lancer_chip(adapter) || skb_vlan_tag_present(skb)) &&
is_ipv4_pkt(skb)) {
ip = (struct iphdr *)ip_hdr(skb);
pskb_trim(skb, eth_hdr_len + ntohs(ip->tot_len));
@@ -973,7 +977,7 @@ static struct sk_buff *be_lancer_xmit_workarounds(struct be_adapter *adapter,
* Manually insert VLAN in pkt.
*/
if (skb->ip_summed != CHECKSUM_PARTIAL &&
- vlan_tx_tag_present(skb)) {
+ skb_vlan_tag_present(skb)) {
skb = be_insert_vlan_in_pkt(adapter, skb, skip_hw_vlan);
if (unlikely(!skb))
goto err;
@@ -1030,52 +1034,64 @@ static struct sk_buff *be_xmit_workarounds(struct be_adapter *adapter,
return skb;
}
+static void be_xmit_flush(struct be_adapter *adapter, struct be_tx_obj *txo)
+{
+ struct be_queue_info *txq = &txo->q;
+ struct be_eth_hdr_wrb *hdr = queue_index_node(txq, txo->last_req_hdr);
+
+ /* Mark the last request eventable if it hasn't been marked already */
+ if (!(hdr->dw[2] & cpu_to_le32(TX_HDR_WRB_EVT)))
+ hdr->dw[2] |= cpu_to_le32(TX_HDR_WRB_EVT | TX_HDR_WRB_COMPL);
+
+ /* compose a dummy wrb if there are odd set of wrbs to notify */
+ if (!lancer_chip(adapter) && (txo->pend_wrb_cnt & 1)) {
+ wrb_fill_dummy(queue_head_node(txq));
+ queue_head_inc(txq);
+ atomic_inc(&txq->used);
+ txo->pend_wrb_cnt++;
+ hdr->dw[2] &= ~cpu_to_le32(TX_HDR_WRB_NUM_MASK <<
+ TX_HDR_WRB_NUM_SHIFT);
+ hdr->dw[2] |= cpu_to_le32((txo->last_req_wrb_cnt + 1) <<
+ TX_HDR_WRB_NUM_SHIFT);
+ }
+ be_txq_notify(adapter, txo, txo->pend_wrb_cnt);
+ txo->pend_wrb_cnt = 0;
+}
+
static netdev_tx_t be_xmit(struct sk_buff *skb, struct net_device *netdev)
{
+ bool skip_hw_vlan = false, flush = !skb->xmit_more;
struct be_adapter *adapter = netdev_priv(netdev);
- struct be_tx_obj *txo = &adapter->tx_obj[skb_get_queue_mapping(skb)];
+ u16 q_idx = skb_get_queue_mapping(skb);
+ struct be_tx_obj *txo = &adapter->tx_obj[q_idx];
struct be_queue_info *txq = &txo->q;
- bool dummy_wrb, stopped = false;
- u32 wrb_cnt = 0, copied = 0;
- bool skip_hw_vlan = false;
- u32 start = txq->head;
+ u16 wrb_cnt;
skb = be_xmit_workarounds(adapter, skb, &skip_hw_vlan);
- if (!skb) {
- tx_stats(txo)->tx_drv_drops++;
- return NETDEV_TX_OK;
- }
-
- wrb_cnt = wrb_cnt_for_skb(adapter, skb, &dummy_wrb);
+ if (unlikely(!skb))
+ goto drop;
- copied = make_tx_wrbs(adapter, txq, skb, wrb_cnt, dummy_wrb,
- skip_hw_vlan);
- if (copied) {
- int gso_segs = skb_shinfo(skb)->gso_segs;
+ wrb_cnt = be_xmit_enqueue(adapter, txo, skb, skip_hw_vlan);
+ if (unlikely(!wrb_cnt)) {
+ dev_kfree_skb_any(skb);
+ goto drop;
+ }
- /* record the sent skb in the sent_skb table */
- BUG_ON(txo->sent_skb_list[start]);
- txo->sent_skb_list[start] = skb;
+ if ((atomic_read(&txq->used) + BE_MAX_TX_FRAG_COUNT) >= txq->len) {
+ netif_stop_subqueue(netdev, q_idx);
+ tx_stats(txo)->tx_stops++;
+ }
- /* Ensure txq has space for the next skb; Else stop the queue
- * *BEFORE* ringing the tx doorbell, so that we serialze the
- * tx compls of the current transmit which'll wake up the queue
- */
- atomic_add(wrb_cnt, &txq->used);
- if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >=
- txq->len) {
- netif_stop_subqueue(netdev, skb_get_queue_mapping(skb));
- stopped = true;
- }
+ if (flush || __netif_subqueue_stopped(netdev, q_idx))
+ be_xmit_flush(adapter, txo);
- be_txq_notify(adapter, txo, wrb_cnt);
+ return NETDEV_TX_OK;
+drop:
+ tx_stats(txo)->tx_drv_drops++;
+ /* Flush the already enqueued tx requests */
+ if (flush && txo->pend_wrb_cnt)
+ be_xmit_flush(adapter, txo);
- be_tx_stats_update(txo, wrb_cnt, copied, gso_segs, stopped);
- } else {
- txq->head = start;
- tx_stats(txo)->tx_drv_drops++;
- dev_kfree_skb_any(skb);
- }
return NETDEV_TX_OK;
}
@@ -1096,6 +1112,43 @@ static int be_change_mtu(struct net_device *netdev, int new_mtu)
return 0;
}
+static inline bool be_in_all_promisc(struct be_adapter *adapter)
+{
+ return (adapter->if_flags & BE_IF_FLAGS_ALL_PROMISCUOUS) ==
+ BE_IF_FLAGS_ALL_PROMISCUOUS;
+}
+
+static int be_set_vlan_promisc(struct be_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+ int status;
+
+ if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS)
+ return 0;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, ON);
+ if (!status) {
+ dev_info(dev, "Enabled VLAN promiscuous mode\n");
+ adapter->if_flags |= BE_IF_FLAGS_VLAN_PROMISCUOUS;
+ } else {
+ dev_err(dev, "Failed to enable VLAN promiscuous mode\n");
+ }
+ return status;
+}
+
+static int be_clear_vlan_promisc(struct be_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+ int status;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_VLAN_PROMISCUOUS, OFF);
+ if (!status) {
+ dev_info(dev, "Disabling VLAN promiscuous mode\n");
+ adapter->if_flags &= ~BE_IF_FLAGS_VLAN_PROMISCUOUS;
+ }
+ return status;
+}
+
/*
* A max of 64 (BE_NUM_VLANS_SUPPORTED) vlans can be configured in BE.
* If the user configures more, place BE in vlan promiscuous mode.
@@ -1108,11 +1161,11 @@ static int be_vid_config(struct be_adapter *adapter)
int status = 0;
/* No need to further configure vids if in promiscuous mode */
- if (adapter->promiscuous)
+ if (be_in_all_promisc(adapter))
return 0;
if (adapter->vlans_added > be_max_vlans(adapter))
- goto set_vlan_promisc;
+ return be_set_vlan_promisc(adapter);
/* Construct VLAN Table to give to HW */
for_each_set_bit(i, adapter->vids, VLAN_N_VID)
@@ -1120,36 +1173,14 @@ static int be_vid_config(struct be_adapter *adapter)
status = be_cmd_vlan_config(adapter, adapter->if_handle, vids, num);
if (status) {
+ dev_err(dev, "Setting HW VLAN filtering failed\n");
/* Set to VLAN promisc mode as setting VLAN filter failed */
if (addl_status(status) ==
MCC_ADDL_STATUS_INSUFFICIENT_RESOURCES)
- goto set_vlan_promisc;
- dev_err(dev, "Setting HW VLAN filtering failed\n");
- } else {
- if (adapter->flags & BE_FLAGS_VLAN_PROMISC) {
- /* hw VLAN filtering re-enabled. */
- status = be_cmd_rx_filter(adapter,
- BE_FLAGS_VLAN_PROMISC, OFF);
- if (!status) {
- dev_info(dev,
- "Disabling VLAN Promiscuous mode\n");
- adapter->flags &= ~BE_FLAGS_VLAN_PROMISC;
- }
- }
+ return be_set_vlan_promisc(adapter);
+ } else if (adapter->if_flags & BE_IF_FLAGS_VLAN_PROMISCUOUS) {
+ status = be_clear_vlan_promisc(adapter);
}
-
- return status;
-
-set_vlan_promisc:
- if (adapter->flags & BE_FLAGS_VLAN_PROMISC)
- return 0;
-
- status = be_cmd_rx_filter(adapter, BE_FLAGS_VLAN_PROMISC, ON);
- if (!status) {
- dev_info(dev, "Enable VLAN Promiscuous mode\n");
- adapter->flags |= BE_FLAGS_VLAN_PROMISC;
- } else
- dev_err(dev, "Failed to enable VLAN Promiscuous mode\n");
return status;
}
@@ -1191,79 +1222,99 @@ static int be_vlan_rem_vid(struct net_device *netdev, __be16 proto, u16 vid)
return be_vid_config(adapter);
}
-static void be_clear_promisc(struct be_adapter *adapter)
+static void be_clear_all_promisc(struct be_adapter *adapter)
{
- adapter->promiscuous = false;
- adapter->flags &= ~(BE_FLAGS_VLAN_PROMISC | BE_FLAGS_MCAST_PROMISC);
+ be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, OFF);
+ adapter->if_flags &= ~BE_IF_FLAGS_ALL_PROMISCUOUS;
+}
- be_cmd_rx_filter(adapter, IFF_PROMISC, OFF);
+static void be_set_all_promisc(struct be_adapter *adapter)
+{
+ be_cmd_rx_filter(adapter, BE_IF_FLAGS_ALL_PROMISCUOUS, ON);
+ adapter->if_flags |= BE_IF_FLAGS_ALL_PROMISCUOUS;
}
-static void be_set_rx_mode(struct net_device *netdev)
+static void be_set_mc_promisc(struct be_adapter *adapter)
{
- struct be_adapter *adapter = netdev_priv(netdev);
int status;
- if (netdev->flags & IFF_PROMISC) {
- be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
- adapter->promiscuous = true;
- goto done;
- }
+ if (adapter->if_flags & BE_IF_FLAGS_MCAST_PROMISCUOUS)
+ return;
- /* BE was previously in promiscuous mode; disable it */
- if (adapter->promiscuous) {
- be_clear_promisc(adapter);
- if (adapter->vlans_added)
- be_vid_config(adapter);
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MCAST_PROMISCUOUS, ON);
+ if (!status)
+ adapter->if_flags |= BE_IF_FLAGS_MCAST_PROMISCUOUS;
+}
+
+static void be_set_mc_list(struct be_adapter *adapter)
+{
+ int status;
+
+ status = be_cmd_rx_filter(adapter, BE_IF_FLAGS_MULTICAST, ON);
+ if (!status)
+ adapter->if_flags &= ~BE_IF_FLAGS_MCAST_PROMISCUOUS;
+ else
+ be_set_mc_promisc(adapter);
+}
+
+static void be_set_uc_list(struct be_adapter *adapter)
+{
+ struct netdev_hw_addr *ha;
+ int i = 1; /* First slot is claimed by the Primary MAC */
+
+ for (; adapter->uc_macs > 0; adapter->uc_macs--, i++)
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[i], 0);
+
+ if (netdev_uc_count(adapter->netdev) > be_max_uc(adapter)) {
+ be_set_all_promisc(adapter);
+ return;
}
- /* Enable multicast promisc if num configured exceeds what we support */
- if (netdev->flags & IFF_ALLMULTI ||
- netdev_mc_count(netdev) > be_max_mc(adapter))
- goto set_mcast_promisc;
+ netdev_for_each_uc_addr(ha, adapter->netdev) {
+ adapter->uc_macs++; /* First slot is for Primary MAC */
+ be_cmd_pmac_add(adapter, (u8 *)ha->addr, adapter->if_handle,
+ &adapter->pmac_id[adapter->uc_macs], 0);
+ }
+}
- if (netdev_uc_count(netdev) != adapter->uc_macs) {
- struct netdev_hw_addr *ha;
- int i = 1; /* First slot is claimed by the Primary MAC */
+static void be_clear_uc_list(struct be_adapter *adapter)
+{
+ int i;
- for (; adapter->uc_macs > 0; adapter->uc_macs--, i++) {
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[i], 0);
- }
+ for (i = 1; i < (adapter->uc_macs + 1); i++)
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[i], 0);
+ adapter->uc_macs = 0;
+}
- if (netdev_uc_count(netdev) > be_max_uc(adapter)) {
- be_cmd_rx_filter(adapter, IFF_PROMISC, ON);
- adapter->promiscuous = true;
- goto done;
- }
+static void be_set_rx_mode(struct net_device *netdev)
+{
+ struct be_adapter *adapter = netdev_priv(netdev);
- netdev_for_each_uc_addr(ha, adapter->netdev) {
- adapter->uc_macs++; /* First slot is for Primary MAC */
- be_cmd_pmac_add(adapter, (u8 *)ha->addr,
- adapter->if_handle,
- &adapter->pmac_id[adapter->uc_macs], 0);
- }
+ if (netdev->flags & IFF_PROMISC) {
+ be_set_all_promisc(adapter);
+ return;
}
- status = be_cmd_rx_filter(adapter, IFF_MULTICAST, ON);
- if (!status) {
- if (adapter->flags & BE_FLAGS_MCAST_PROMISC)
- adapter->flags &= ~BE_FLAGS_MCAST_PROMISC;
- goto done;
+ /* Interface was previously in promiscuous mode; disable it */
+ if (be_in_all_promisc(adapter)) {
+ be_clear_all_promisc(adapter);
+ if (adapter->vlans_added)
+ be_vid_config(adapter);
}
-set_mcast_promisc:
- if (adapter->flags & BE_FLAGS_MCAST_PROMISC)
+ /* Enable multicast promisc if num configured exceeds what we support */
+ if (netdev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(netdev) > be_max_mc(adapter)) {
+ be_set_mc_promisc(adapter);
return;
+ }
- /* Set to MCAST promisc mode if setting MULTICAST address fails
- * or if num configured exceeds what we support
- */
- status = be_cmd_rx_filter(adapter, IFF_ALLMULTI, ON);
- if (!status)
- adapter->flags |= BE_FLAGS_MCAST_PROMISC;
-done:
- return;
+ if (netdev_uc_count(netdev) != adapter->uc_macs)
+ be_set_uc_list(adapter);
+
+ be_set_mc_list(adapter);
}
static int be_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)
@@ -1959,32 +2010,34 @@ static struct be_eth_tx_compl *be_tx_compl_get(struct be_queue_info *tx_cq)
static u16 be_tx_compl_process(struct be_adapter *adapter,
struct be_tx_obj *txo, u16 last_index)
{
+ struct sk_buff **sent_skbs = txo->sent_skb_list;
struct be_queue_info *txq = &txo->q;
+ u16 frag_index, num_wrbs = 0;
+ struct sk_buff *skb = NULL;
+ bool unmap_skb_hdr = false;
struct be_eth_wrb *wrb;
- struct sk_buff **sent_skbs = txo->sent_skb_list;
- struct sk_buff *sent_skb;
- u16 cur_index, num_wrbs = 1; /* account for hdr wrb */
- bool unmap_skb_hdr = true;
-
- sent_skb = sent_skbs[txq->tail];
- BUG_ON(!sent_skb);
- sent_skbs[txq->tail] = NULL;
-
- /* skip header wrb */
- queue_tail_inc(txq);
do {
- cur_index = txq->tail;
+ if (sent_skbs[txq->tail]) {
+ /* Free skb from prev req */
+ if (skb)
+ dev_consume_skb_any(skb);
+ skb = sent_skbs[txq->tail];
+ sent_skbs[txq->tail] = NULL;
+ queue_tail_inc(txq); /* skip hdr wrb */
+ num_wrbs++;
+ unmap_skb_hdr = true;
+ }
wrb = queue_tail_node(txq);
+ frag_index = txq->tail;
unmap_tx_frag(&adapter->pdev->dev, wrb,
- (unmap_skb_hdr && skb_headlen(sent_skb)));
+ (unmap_skb_hdr && skb_headlen(skb)));
unmap_skb_hdr = false;
-
- num_wrbs++;
queue_tail_inc(txq);
- } while (cur_index != last_index);
+ num_wrbs++;
+ } while (frag_index != last_index);
+ dev_consume_skb_any(skb);
- dev_consume_skb_any(sent_skb);
return num_wrbs;
}
@@ -2068,12 +2121,11 @@ static void be_rx_cq_clean(struct be_rx_obj *rxo)
static void be_tx_compl_clean(struct be_adapter *adapter)
{
+ u16 end_idx, notified_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
+ struct device *dev = &adapter->pdev->dev;
struct be_tx_obj *txo;
struct be_queue_info *txq;
struct be_eth_tx_compl *txcp;
- u16 end_idx, cmpl = 0, timeo = 0, num_wrbs = 0;
- struct sk_buff *sent_skb;
- bool dummy_wrb;
int i, pending_txqs;
/* Stop polling for compls when HW has been silent for 10ms */
@@ -2095,7 +2147,7 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
atomic_sub(num_wrbs, &txq->used);
timeo = 0;
}
- if (atomic_read(&txq->used) == 0)
+ if (atomic_read(&txq->used) == txo->pend_wrb_cnt)
pending_txqs--;
}
@@ -2105,21 +2157,29 @@ static void be_tx_compl_clean(struct be_adapter *adapter)
mdelay(1);
} while (true);
+ /* Free enqueued TX that was never notified to HW */
for_all_tx_queues(adapter, txo, i) {
txq = &txo->q;
- if (atomic_read(&txq->used))
- dev_err(&adapter->pdev->dev, "%d pending tx-compls\n",
- atomic_read(&txq->used));
- /* free posted tx for which compls will never arrive */
- while (atomic_read(&txq->used)) {
- sent_skb = txo->sent_skb_list[txq->tail];
+ if (atomic_read(&txq->used)) {
+ dev_info(dev, "txq%d: cleaning %d pending tx-wrbs\n",
+ i, atomic_read(&txq->used));
+ notified_idx = txq->tail;
end_idx = txq->tail;
- num_wrbs = wrb_cnt_for_skb(adapter, sent_skb,
- &dummy_wrb);
- index_adv(&end_idx, num_wrbs - 1, txq->len);
+ index_adv(&end_idx, atomic_read(&txq->used) - 1,
+ txq->len);
+ /* Use the tx-compl process logic to handle requests
+ * that were not sent to the HW.
+ */
num_wrbs = be_tx_compl_process(adapter, txo, end_idx);
atomic_sub(num_wrbs, &txq->used);
+ BUG_ON(atomic_read(&txq->used));
+ txo->pend_wrb_cnt = 0;
+ /* Since hw was never notified of these requests,
+ * reset TXQ indices
+ */
+ txq->head = notified_idx;
+ txq->tail = notified_idx;
}
}
}
@@ -2514,6 +2574,106 @@ static void be_process_tx(struct be_adapter *adapter, struct be_tx_obj *txo,
}
}
+#ifdef CONFIG_NET_RX_BUSY_POLL
+static inline bool be_lock_napi(struct be_eq_obj *eqo)
+{
+ bool status = true;
+
+ spin_lock(&eqo->lock); /* BH is already disabled */
+ if (eqo->state & BE_EQ_LOCKED) {
+ WARN_ON(eqo->state & BE_EQ_NAPI);
+ eqo->state |= BE_EQ_NAPI_YIELD;
+ status = false;
+ } else {
+ eqo->state = BE_EQ_NAPI;
+ }
+ spin_unlock(&eqo->lock);
+ return status;
+}
+
+static inline void be_unlock_napi(struct be_eq_obj *eqo)
+{
+ spin_lock(&eqo->lock); /* BH is already disabled */
+
+ WARN_ON(eqo->state & (BE_EQ_POLL | BE_EQ_NAPI_YIELD));
+ eqo->state = BE_EQ_IDLE;
+
+ spin_unlock(&eqo->lock);
+}
+
+static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
+{
+ bool status = true;
+
+ spin_lock_bh(&eqo->lock);
+ if (eqo->state & BE_EQ_LOCKED) {
+ eqo->state |= BE_EQ_POLL_YIELD;
+ status = false;
+ } else {
+ eqo->state |= BE_EQ_POLL;
+ }
+ spin_unlock_bh(&eqo->lock);
+ return status;
+}
+
+static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
+{
+ spin_lock_bh(&eqo->lock);
+
+ WARN_ON(eqo->state & (BE_EQ_NAPI));
+ eqo->state = BE_EQ_IDLE;
+
+ spin_unlock_bh(&eqo->lock);
+}
+
+static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
+{
+ spin_lock_init(&eqo->lock);
+ eqo->state = BE_EQ_IDLE;
+}
+
+static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
+{
+ local_bh_disable();
+
+ /* It's enough to just acquire napi lock on the eqo to stop
+ * be_busy_poll() from processing any queueus.
+ */
+ while (!be_lock_napi(eqo))
+ mdelay(1);
+
+ local_bh_enable();
+}
+
+#else /* CONFIG_NET_RX_BUSY_POLL */
+
+static inline bool be_lock_napi(struct be_eq_obj *eqo)
+{
+ return true;
+}
+
+static inline void be_unlock_napi(struct be_eq_obj *eqo)
+{
+}
+
+static inline bool be_lock_busy_poll(struct be_eq_obj *eqo)
+{
+ return false;
+}
+
+static inline void be_unlock_busy_poll(struct be_eq_obj *eqo)
+{
+}
+
+static inline void be_enable_busy_poll(struct be_eq_obj *eqo)
+{
+}
+
+static inline void be_disable_busy_poll(struct be_eq_obj *eqo)
+{
+}
+#endif /* CONFIG_NET_RX_BUSY_POLL */
+
int be_poll(struct napi_struct *napi, int budget)
{
struct be_eq_obj *eqo = container_of(napi, struct be_eq_obj, napi);
@@ -2833,11 +2993,7 @@ static int be_close(struct net_device *netdev)
be_tx_compl_clean(adapter);
be_rx_qs_destroy(adapter);
-
- for (i = 1; i < (adapter->uc_macs + 1); i++)
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[i], 0);
- adapter->uc_macs = 0;
+ be_clear_uc_list(adapter);
for_all_evt_queues(adapter, eqo, i) {
if (msix_enabled(adapter))
@@ -3008,6 +3164,19 @@ static int be_setup_wol(struct be_adapter *adapter, bool enable)
return status;
}
+static void be_vf_eth_addr_generate(struct be_adapter *adapter, u8 *mac)
+{
+ u32 addr;
+
+ addr = jhash(adapter->netdev->dev_addr, ETH_ALEN, 0);
+
+ mac[5] = (u8)(addr & 0xFF);
+ mac[4] = (u8)((addr >> 8) & 0xFF);
+ mac[3] = (u8)((addr >> 16) & 0xFF);
+ /* Use the OUI from the current MAC address */
+ memcpy(mac, adapter->netdev->dev_addr, 3);
+}
+
/*
* Generate a seed MAC address from the PF MAC Address using jhash.
* MAC Address for VFs are assigned incrementally starting from the seed.
@@ -3108,14 +3277,9 @@ static void be_cancel_worker(struct be_adapter *adapter)
static void be_mac_clear(struct be_adapter *adapter)
{
- int i;
-
if (adapter->pmac_id) {
- for (i = 0; i < (adapter->uc_macs + 1); i++)
- be_cmd_pmac_del(adapter, adapter->if_handle,
- adapter->pmac_id[i], 0);
- adapter->uc_macs = 0;
-
+ be_cmd_pmac_del(adapter, adapter->if_handle,
+ adapter->pmac_id[0], 0);
kfree(adapter->pmac_id);
adapter->pmac_id = NULL;
}
@@ -3171,13 +3335,32 @@ static int be_clear(struct be_adapter *adapter)
return 0;
}
+static int be_if_create(struct be_adapter *adapter, u32 *if_handle,
+ u32 cap_flags, u32 vf)
+{
+ u32 en_flags;
+ int status;
+
+ en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
+ BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS |
+ BE_IF_FLAGS_RSS;
+
+ en_flags &= cap_flags;
+
+ status = be_cmd_if_create(adapter, cap_flags, en_flags,
+ if_handle, vf);
+
+ return status;
+}
+
static int be_vfs_if_create(struct be_adapter *adapter)
{
struct be_resources res = {0};
struct be_vf_cfg *vf_cfg;
- u32 cap_flags, en_flags, vf;
- int status = 0;
+ u32 cap_flags, vf;
+ int status;
+ /* If a FW profile exists, then cap_flags are updated */
cap_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
BE_IF_FLAGS_MULTICAST;
@@ -3189,18 +3372,13 @@ static int be_vfs_if_create(struct be_adapter *adapter)
cap_flags = res.if_cap_flags;
}
- /* If a FW profile exists, then cap_flags are updated */
- en_flags = cap_flags & (BE_IF_FLAGS_UNTAGGED |
- BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST);
- status =
- be_cmd_if_create(adapter, cap_flags, en_flags,
- &vf_cfg->if_handle, vf + 1);
+ status = be_if_create(adapter, &vf_cfg->if_handle,
+ cap_flags, vf + 1);
if (status)
- goto err;
+ return status;
}
-err:
- return status;
+
+ return 0;
}
static int be_vf_setup_init(struct be_adapter *adapter)
@@ -3385,7 +3563,7 @@ static void be_setup_init(struct be_adapter *adapter)
adapter->phy.link_speed = -1;
adapter->if_handle = -1;
adapter->be3_native = false;
- adapter->promiscuous = false;
+ adapter->if_flags = 0;
if (be_physfn(adapter))
adapter->cmd_privileges = MAX_PRIVILEGES;
else
@@ -3512,7 +3690,9 @@ static int be_get_config(struct be_adapter *adapter)
if (status)
return status;
- if (be_physfn(adapter)) {
+ be_cmd_query_port_name(adapter);
+
+ if (be_physfn(adapter)) {
status = be_cmd_get_active_profile(adapter, &profile_id);
if (!status)
dev_info(&adapter->pdev->dev,
@@ -3638,10 +3818,20 @@ int be_update_queues(struct be_adapter *adapter)
return status;
}
+static inline int fw_major_num(const char *fw_ver)
+{
+ int fw_major = 0, i;
+
+ i = sscanf(fw_ver, "%d.", &fw_major);
+ if (i != 1)
+ return 0;
+
+ return fw_major;
+}
+
static int be_setup(struct be_adapter *adapter)
{
struct device *dev = &adapter->pdev->dev;
- u32 tx_fc, rx_fc, en_flags;
int status;
be_setup_init(adapter);
@@ -3657,13 +3847,8 @@ static int be_setup(struct be_adapter *adapter)
if (status)
goto err;
- en_flags = BE_IF_FLAGS_UNTAGGED | BE_IF_FLAGS_BROADCAST |
- BE_IF_FLAGS_MULTICAST | BE_IF_FLAGS_PASS_L3L4_ERRORS;
- if (adapter->function_caps & BE_FUNCTION_CAPS_RSS)
- en_flags |= BE_IF_FLAGS_RSS;
- en_flags = en_flags & be_if_cap_flags(adapter);
- status = be_cmd_if_create(adapter, be_if_cap_flags(adapter), en_flags,
- &adapter->if_handle, 0);
+ status = be_if_create(adapter, &adapter->if_handle,
+ be_if_cap_flags(adapter), 0);
if (status)
goto err;
@@ -3696,11 +3881,14 @@ static int be_setup(struct be_adapter *adapter)
be_cmd_get_acpi_wol_cap(adapter);
- be_cmd_get_flow_control(adapter, &tx_fc, &rx_fc);
+ status = be_cmd_set_flow_control(adapter, adapter->tx_fc,
+ adapter->rx_fc);
+ if (status)
+ be_cmd_get_flow_control(adapter, &adapter->tx_fc,
+ &adapter->rx_fc);
- if (rx_fc != adapter->rx_fc || tx_fc != adapter->tx_fc)
- be_cmd_set_flow_control(adapter, adapter->tx_fc,
- adapter->rx_fc);
+ dev_info(&adapter->pdev->dev, "HW Flow control - TX:%d RX:%d\n",
+ adapter->tx_fc, adapter->rx_fc);
if (be_physfn(adapter))
be_cmd_set_logical_link_config(adapter,
@@ -3739,7 +3927,7 @@ static char flash_cookie[2][16] = {"*** SE FLAS", "H DIRECTORY *** "};
static bool phy_flashing_required(struct be_adapter *adapter)
{
- return (adapter->phy.phy_type == TN_8022 &&
+ return (adapter->phy.phy_type == PHY_TYPE_TN_8022 &&
adapter->phy.interface_type == PHY_TYPE_BASET_10GB);
}
@@ -3790,7 +3978,8 @@ static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p,
int status;
u8 crc[4];
- status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_size - 4);
+ status = be_cmd_get_flash_crc(adapter, crc, img_optype, img_offset,
+ img_size - 4);
if (status)
return status;
@@ -3806,13 +3995,13 @@ static int be_check_flash_crc(struct be_adapter *adapter, const u8 *p,
}
static int be_flash(struct be_adapter *adapter, const u8 *img,
- struct be_dma_mem *flash_cmd, int optype, int img_size)
+ struct be_dma_mem *flash_cmd, int optype, int img_size,
+ u32 img_offset)
{
+ u32 flash_op, num_bytes, total_bytes = img_size, bytes_sent = 0;
struct be_cmd_write_flashrom *req = flash_cmd->va;
- u32 total_bytes, flash_op, num_bytes;
int status;
- total_bytes = img_size;
while (total_bytes) {
num_bytes = min_t(u32, 32*1024, total_bytes);
@@ -3833,12 +4022,15 @@ static int be_flash(struct be_adapter *adapter, const u8 *img,
memcpy(req->data_buf, img, num_bytes);
img += num_bytes;
status = be_cmd_write_flashrom(adapter, flash_cmd, optype,
- flash_op, num_bytes);
+ flash_op, img_offset +
+ bytes_sent, num_bytes);
if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST &&
optype == OPTYPE_PHY_FW)
break;
else if (status)
return status;
+
+ bytes_sent += num_bytes;
}
return 0;
}
@@ -3906,6 +4098,7 @@ static int be_flash_BEx(struct be_adapter *adapter,
pflashcomp = gen2_flash_types;
filehdr_size = sizeof(struct flash_file_hdr_g2);
num_comp = ARRAY_SIZE(gen2_flash_types);
+ img_hdrs_size = 0;
}
/* Get flash section info*/
@@ -3950,7 +4143,7 @@ static int be_flash_BEx(struct be_adapter *adapter,
return -1;
status = be_flash(adapter, p, flash_cmd, pflashcomp[i].optype,
- pflashcomp[i].size);
+ pflashcomp[i].size, 0);
if (status) {
dev_err(dev, "Flashing section type 0x%x failed\n",
pflashcomp[i].img_type);
@@ -4017,12 +4210,12 @@ static int be_flash_skyhawk(struct be_adapter *adapter,
struct be_dma_mem *flash_cmd, int num_of_images)
{
int img_hdrs_size = num_of_images * sizeof(struct image_hdr);
+ bool crc_match, old_fw_img, flash_offset_support = true;
struct device *dev = &adapter->pdev->dev;
struct flash_section_info *fsec = NULL;
u32 img_offset, img_size, img_type;
+ u16 img_optype, flash_optype;
int status, i, filehdr_size;
- bool crc_match, old_fw_img;
- u16 img_optype;
const u8 *p;
filehdr_size = sizeof(struct flash_file_hdr_g3);
@@ -4032,6 +4225,7 @@ static int be_flash_skyhawk(struct be_adapter *adapter,
return -EINVAL;
}
+retry_flash:
for (i = 0; i < le32_to_cpu(fsec->fsec_hdr.num_images); i++) {
img_offset = le32_to_cpu(fsec->fsec_entry[i].offset);
img_size = le32_to_cpu(fsec->fsec_entry[i].pad_size);
@@ -4041,6 +4235,12 @@ static int be_flash_skyhawk(struct be_adapter *adapter,
if (img_optype == 0xFFFF)
continue;
+
+ if (flash_offset_support)
+ flash_optype = OPTYPE_OFFSET_SPECIFIED;
+ else
+ flash_optype = img_optype;
+
/* Don't bother verifying CRC if an old FW image is being
* flashed
*/
@@ -4049,16 +4249,26 @@ static int be_flash_skyhawk(struct be_adapter *adapter,
status = be_check_flash_crc(adapter, fw->data, img_offset,
img_size, filehdr_size +
- img_hdrs_size, img_optype,
+ img_hdrs_size, flash_optype,
&crc_match);
- /* The current FW image on the card does not recognize the new
- * FLASH op_type. The FW download is partially complete.
- * Reboot the server now to enable FW image to recognize the
- * new FLASH op_type. To complete the remaining process,
- * download the same FW again after the reboot.
- */
if (base_status(status) == MCC_STATUS_ILLEGAL_REQUEST ||
base_status(status) == MCC_STATUS_ILLEGAL_FIELD) {
+ /* The current FW image on the card does not support
+ * OFFSET based flashing. Retry using older mechanism
+ * of OPTYPE based flashing
+ */
+ if (flash_optype == OPTYPE_OFFSET_SPECIFIED) {
+ flash_offset_support = false;
+ goto retry_flash;
+ }
+
+ /* The current FW image on the card does not recognize
+ * the new FLASH op_type. The FW download is partially
+ * complete. Reboot the server now to enable FW image
+ * to recognize the new FLASH op_type. To complete the
+ * remaining process, download the same FW again after
+ * the reboot.
+ */
dev_err(dev, "Flash incomplete. Reset the server\n");
dev_err(dev, "Download FW image again after reset\n");
return -EAGAIN;
@@ -4076,7 +4286,19 @@ flash:
if (p + img_size > fw->data + fw->size)
return -1;
- status = be_flash(adapter, p, flash_cmd, img_optype, img_size);
+ status = be_flash(adapter, p, flash_cmd, flash_optype, img_size,
+ img_offset);
+
+ /* The current FW image on the card does not support OFFSET
+ * based flashing. Retry using older mechanism of OPTYPE based
+ * flashing
+ */
+ if (base_status(status) == MCC_STATUS_ILLEGAL_FIELD &&
+ flash_optype == OPTYPE_OFFSET_SPECIFIED) {
+ flash_offset_support = false;
+ goto retry_flash;
+ }
+
/* For old FW images ignore ILLEGAL_FIELD error or errors on
* UFI_DIR region
*/
@@ -4179,98 +4401,105 @@ static int lancer_fw_download(struct be_adapter *adapter,
return 0;
}
-#define UFI_TYPE2 2
-#define UFI_TYPE3 3
-#define UFI_TYPE3R 10
-#define UFI_TYPE4 4
+#define BE2_UFI 2
+#define BE3_UFI 3
+#define BE3R_UFI 10
+#define SH_UFI 4
+#define SH_P2_UFI 11
+
static int be_get_ufi_type(struct be_adapter *adapter,
struct flash_file_hdr_g3 *fhdr)
{
- if (!fhdr)
- goto be_get_ufi_exit;
+ if (!fhdr) {
+ dev_err(&adapter->pdev->dev, "Invalid FW UFI file");
+ return -1;
+ }
- if (skyhawk_chip(adapter) && fhdr->build[0] == '4')
- return UFI_TYPE4;
- else if (BE3_chip(adapter) && fhdr->build[0] == '3') {
- if (fhdr->asic_type_rev == 0x10)
- return UFI_TYPE3R;
- else
- return UFI_TYPE3;
- } else if (BE2_chip(adapter) && fhdr->build[0] == '2')
- return UFI_TYPE2;
+ /* First letter of the build version is used to identify
+ * which chip this image file is meant for.
+ */
+ switch (fhdr->build[0]) {
+ case BLD_STR_UFI_TYPE_SH:
+ return (fhdr->asic_type_rev == ASIC_REV_P2) ? SH_P2_UFI :
+ SH_UFI;
+ case BLD_STR_UFI_TYPE_BE3:
+ return (fhdr->asic_type_rev == ASIC_REV_B0) ? BE3R_UFI :
+ BE3_UFI;
+ case BLD_STR_UFI_TYPE_BE2:
+ return BE2_UFI;
+ default:
+ return -1;
+ }
+}
-be_get_ufi_exit:
- dev_err(&adapter->pdev->dev,
- "UFI and Interface are not compatible for flashing\n");
- return -1;
+/* Check if the flash image file is compatible with the adapter that
+ * is being flashed.
+ * BE3 chips with asic-rev B0 must be flashed only with BE3R_UFI type.
+ * Skyhawk chips with asic-rev P2 must be flashed only with SH_P2_UFI type.
+ */
+static bool be_check_ufi_compatibility(struct be_adapter *adapter,
+ struct flash_file_hdr_g3 *fhdr)
+{
+ int ufi_type = be_get_ufi_type(adapter, fhdr);
+
+ switch (ufi_type) {
+ case SH_P2_UFI:
+ return skyhawk_chip(adapter);
+ case SH_UFI:
+ return (skyhawk_chip(adapter) &&
+ adapter->asic_rev < ASIC_REV_P2);
+ case BE3R_UFI:
+ return BE3_chip(adapter);
+ case BE3_UFI:
+ return (BE3_chip(adapter) && adapter->asic_rev < ASIC_REV_B0);
+ case BE2_UFI:
+ return BE2_chip(adapter);
+ default:
+ return false;
+ }
}
static int be_fw_download(struct be_adapter *adapter, const struct firmware* fw)
{
+ struct device *dev = &adapter->pdev->dev;
struct flash_file_hdr_g3 *fhdr3;
- struct image_hdr *img_hdr_ptr = NULL;
+ struct image_hdr *img_hdr_ptr;
+ int status = 0, i, num_imgs;
struct be_dma_mem flash_cmd;
- const u8 *p;
- int status = 0, i = 0, num_imgs = 0, ufi_type = 0;
- flash_cmd.size = sizeof(struct be_cmd_write_flashrom);
- flash_cmd.va = dma_alloc_coherent(&adapter->pdev->dev, flash_cmd.size,
- &flash_cmd.dma, GFP_KERNEL);
- if (!flash_cmd.va) {
- status = -ENOMEM;
- goto be_fw_exit;
+ fhdr3 = (struct flash_file_hdr_g3 *)fw->data;
+ if (!be_check_ufi_compatibility(adapter, fhdr3)) {
+ dev_err(dev, "Flash image is not compatible with adapter\n");
+ return -EINVAL;
}
- p = fw->data;
- fhdr3 = (struct flash_file_hdr_g3 *)p;
-
- ufi_type = be_get_ufi_type(adapter, fhdr3);
+ flash_cmd.size = sizeof(struct be_cmd_write_flashrom);
+ flash_cmd.va = dma_alloc_coherent(dev, flash_cmd.size, &flash_cmd.dma,
+ GFP_KERNEL);
+ if (!flash_cmd.va)
+ return -ENOMEM;
num_imgs = le32_to_cpu(fhdr3->num_imgs);
for (i = 0; i < num_imgs; i++) {
img_hdr_ptr = (struct image_hdr *)(fw->data +
(sizeof(struct flash_file_hdr_g3) +
i * sizeof(struct image_hdr)));
- if (le32_to_cpu(img_hdr_ptr->imageid) == 1) {
- switch (ufi_type) {
- case UFI_TYPE4:
- status = be_flash_skyhawk(adapter, fw,
- &flash_cmd, num_imgs);
- break;
- case UFI_TYPE3R:
- status = be_flash_BEx(adapter, fw, &flash_cmd,
- num_imgs);
- break;
- case UFI_TYPE3:
- /* Do not flash this ufi on BE3-R cards */
- if (adapter->asic_rev < 0x10)
- status = be_flash_BEx(adapter, fw,
- &flash_cmd,
- num_imgs);
- else {
- status = -EINVAL;
- dev_err(&adapter->pdev->dev,
- "Can't load BE3 UFI on BE3R\n");
- }
- }
- }
- }
-
- if (ufi_type == UFI_TYPE2)
- status = be_flash_BEx(adapter, fw, &flash_cmd, 0);
- else if (ufi_type == -1)
- status = -EINVAL;
+ if (!BE2_chip(adapter) &&
+ le32_to_cpu(img_hdr_ptr->imageid) != 1)
+ continue;
- dma_free_coherent(&adapter->pdev->dev, flash_cmd.size, flash_cmd.va,
- flash_cmd.dma);
- if (status) {
- dev_err(&adapter->pdev->dev, "Firmware load error\n");
- goto be_fw_exit;
+ if (skyhawk_chip(adapter))
+ status = be_flash_skyhawk(adapter, fw, &flash_cmd,
+ num_imgs);
+ else
+ status = be_flash_BEx(adapter, fw, &flash_cmd,
+ num_imgs);
}
- dev_info(&adapter->pdev->dev, "Firmware flashed successfully\n");
+ dma_free_coherent(dev, flash_cmd.size, flash_cmd.va, flash_cmd.dma);
+ if (!status)
+ dev_info(dev, "Firmware flashed successfully\n");
-be_fw_exit:
return status;
}
@@ -4304,7 +4533,8 @@ fw_exit:
return status;
}
-static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh)
+static int be_ndo_bridge_setlink(struct net_device *dev, struct nlmsghdr *nlh,
+ u16 flags)
{
struct be_adapter *adapter = netdev_priv(dev);
struct nlattr *attr, *br_spec;
@@ -4832,6 +5062,20 @@ static void be_func_recovery_task(struct work_struct *work)
msecs_to_jiffies(1000));
}
+static void be_log_sfp_info(struct be_adapter *adapter)
+{
+ int status;
+
+ status = be_cmd_query_sfp_info(adapter);
+ if (!status) {
+ dev_err(&adapter->pdev->dev,
+ "Unqualified SFP+ detected on %c from %s part no: %s",
+ adapter->port_name, adapter->phy.vendor_name,
+ adapter->phy.vendor_pn);
+ }
+ adapter->flags &= ~BE_FLAGS_EVT_INCOMPATIBLE_SFP;
+}
+
static void be_worker(struct work_struct *work)
{
struct be_adapter *adapter =
@@ -4870,6 +5114,9 @@ static void be_worker(struct work_struct *work)
be_eqd_update(adapter);
+ if (adapter->flags & BE_FLAGS_EVT_INCOMPATIBLE_SFP)
+ be_log_sfp_info(adapter);
+
reschedule:
adapter->work_counter++;
schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
@@ -4916,12 +5163,31 @@ static inline char *func_name(struct be_adapter *adapter)
return be_physfn(adapter) ? "PF" : "VF";
}
+static inline char *nic_name(struct pci_dev *pdev)
+{
+ switch (pdev->device) {
+ case OC_DEVICE_ID1:
+ return OC_NAME;
+ case OC_DEVICE_ID2:
+ return OC_NAME_BE;
+ case OC_DEVICE_ID3:
+ case OC_DEVICE_ID4:
+ return OC_NAME_LANCER;
+ case BE_DEVICE_ID2:
+ return BE3_NAME;
+ case OC_DEVICE_ID5:
+ case OC_DEVICE_ID6:
+ return OC_NAME_SH;
+ default:
+ return BE_NAME;
+ }
+}
+
static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
{
- int status = 0;
struct be_adapter *adapter;
struct net_device *netdev;
- char port_name;
+ int status = 0;
dev_info(&pdev->dev, "%s version is %s\n", DRV_NAME, DRV_VER);
@@ -5015,10 +5281,8 @@ static int be_probe(struct pci_dev *pdev, const struct pci_device_id *pdev_id)
schedule_delayed_work(&adapter->func_recovery_work,
msecs_to_jiffies(1000));
- be_cmd_query_port_name(adapter, &port_name);
-
dev_info(&pdev->dev, "%s: %s %s port %c\n", nic_name(pdev),
- func_name(adapter), mc_name(adapter), port_name);
+ func_name(adapter), mc_name(adapter), adapter->port_name);
return 0;
@@ -5083,6 +5347,10 @@ static int be_resume(struct pci_dev *pdev)
if (status)
return status;
+ status = be_cmd_reset_function(adapter);
+ if (status)
+ return status;
+
be_intr_set(adapter, true);
/* tell fw we're ready to fire cmds */
status = be_cmd_fw_init(adapter);
diff --git a/drivers/net/ethernet/freescale/Kconfig b/drivers/net/ethernet/freescale/Kconfig
index 270308315d43..ba84c4a9ce32 100644
--- a/drivers/net/ethernet/freescale/Kconfig
+++ b/drivers/net/ethernet/freescale/Kconfig
@@ -69,7 +69,8 @@ config FSL_XGMAC_MDIO
select PHYLIB
select OF_MDIO
---help---
- This driver supports the MDIO bus on the Fman 10G Ethernet MACs.
+ This driver supports the MDIO bus on the Fman 10G Ethernet MACs, and
+ on the FMan mEMAC (which supports both Clauses 22 and 45)
config UCC_GETH
tristate "Freescale QE Gigabit Ethernet"
diff --git a/drivers/net/ethernet/freescale/fec.h b/drivers/net/ethernet/freescale/fec.h
index 40132929daf7..a86af8a7485d 100644
--- a/drivers/net/ethernet/freescale/fec.h
+++ b/drivers/net/ethernet/freescale/fec.h
@@ -16,6 +16,7 @@
#include <linux/clocksource.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
+#include <linux/timecounter.h>
#if defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x) || \
defined(CONFIG_M520x) || defined(CONFIG_M532x) || \
@@ -356,6 +357,7 @@ struct bufdesc_ex {
#define FEC_ENET_RXB ((uint)0x01000000) /* A buffer was received */
#define FEC_ENET_MII ((uint)0x00800000) /* MII interrupt */
#define FEC_ENET_EBERR ((uint)0x00400000) /* SDMA bus error */
+#define FEC_ENET_WAKEUP ((uint)0x00020000) /* Wakeup request */
#define FEC_ENET_TXF (FEC_ENET_TXF_0 | FEC_ENET_TXF_1 | FEC_ENET_TXF_2)
#define FEC_ENET_RXF (FEC_ENET_RXF_0 | FEC_ENET_RXF_1 | FEC_ENET_RXF_2)
#define FEC_ENET_TS_AVAIL ((uint)0x00010000)
@@ -513,6 +515,7 @@ struct fec_enet_private {
int irq[FEC_IRQ_NUM];
bool bufdesc_ex;
int pause_flag;
+ int wol_flag;
u32 quirks;
struct napi_struct napi;
diff --git a/drivers/net/ethernet/freescale/fec_main.c b/drivers/net/ethernet/freescale/fec_main.c
index bba87775419d..9bb6220663b2 100644
--- a/drivers/net/ethernet/freescale/fec_main.c
+++ b/drivers/net/ethernet/freescale/fec_main.c
@@ -188,6 +188,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define FEC_MMFR_RA(v) ((v & 0x1f) << 18)
#define FEC_MMFR_TA (2 << 16)
#define FEC_MMFR_DATA(v) (v & 0xffff)
+/* FEC ECR bits definition */
+#define FEC_ECR_MAGICEN (1 << 2)
+#define FEC_ECR_SLEEP (1 << 3)
#define FEC_MII_TIMEOUT 30000 /* us */
@@ -196,6 +199,9 @@ MODULE_PARM_DESC(macaddr, "FEC Ethernet MAC address");
#define FEC_PAUSE_FLAG_AUTONEG 0x1
#define FEC_PAUSE_FLAG_ENABLE 0x2
+#define FEC_WOL_HAS_MAGIC_PACKET (0x1 << 0)
+#define FEC_WOL_FLAG_ENABLE (0x1 << 1)
+#define FEC_WOL_FLAG_SLEEP_ON (0x1 << 2)
#define COPYBREAK_DEFAULT 256
@@ -1090,7 +1096,9 @@ static void
fec_stop(struct net_device *ndev)
{
struct fec_enet_private *fep = netdev_priv(ndev);
+ struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
u32 rmii_mode = readl(fep->hwp + FEC_R_CNTRL) & (1 << 8);
+ u32 val;
/* We cannot expect a graceful transmit stop without link !!! */
if (fep->link) {
@@ -1104,17 +1112,28 @@ fec_stop(struct net_device *ndev)
* For i.MX6SX SOC, enet use AXI bus, we use disable MAC
* instead of reset MAC itself.
*/
- if (fep->quirks & FEC_QUIRK_HAS_AVB) {
- writel(0, fep->hwp + FEC_ECNTRL);
+ if (!(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
+ if (fep->quirks & FEC_QUIRK_HAS_AVB) {
+ writel(0, fep->hwp + FEC_ECNTRL);
+ } else {
+ writel(1, fep->hwp + FEC_ECNTRL);
+ udelay(10);
+ }
+ writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
} else {
- writel(1, fep->hwp + FEC_ECNTRL);
- udelay(10);
+ writel(FEC_DEFAULT_IMASK | FEC_ENET_WAKEUP, fep->hwp + FEC_IMASK);
+ val = readl(fep->hwp + FEC_ECNTRL);
+ val |= (FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
+ writel(val, fep->hwp + FEC_ECNTRL);
+
+ if (pdata && pdata->sleep_mode_enable)
+ pdata->sleep_mode_enable(true);
}
writel(fep->phy_speed, fep->hwp + FEC_MII_SPEED);
- writel(FEC_DEFAULT_IMASK, fep->hwp + FEC_IMASK);
/* We have to keep ENET enabled to have MII interrupt stay working */
- if (fep->quirks & FEC_QUIRK_ENET_MAC) {
+ if (fep->quirks & FEC_QUIRK_ENET_MAC &&
+ !(fep->wol_flag & FEC_WOL_FLAG_SLEEP_ON)) {
writel(2, fep->hwp + FEC_ECNTRL);
writel(rmii_mode, fep->hwp + FEC_R_CNTRL);
}
@@ -1170,12 +1189,13 @@ static void
fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
{
struct fec_enet_private *fep;
- struct bufdesc *bdp;
+ struct bufdesc *bdp, *bdp_t;
unsigned short status;
struct sk_buff *skb;
struct fec_enet_priv_tx_q *txq;
struct netdev_queue *nq;
int index = 0;
+ int i, bdnum;
int entries_free;
fep = netdev_priv(ndev);
@@ -1196,18 +1216,29 @@ fec_enet_tx_queue(struct net_device *ndev, u16 queue_id)
if (bdp == txq->cur_tx)
break;
- index = fec_enet_get_bd_index(txq->tx_bd_base, bdp, fep);
-
+ bdp_t = bdp;
+ bdnum = 1;
+ index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
skb = txq->tx_skbuff[index];
- txq->tx_skbuff[index] = NULL;
- if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
- dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
- bdp->cbd_datlen, DMA_TO_DEVICE);
- bdp->cbd_bufaddr = 0;
- if (!skb) {
- bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
- continue;
+ while (!skb) {
+ bdp_t = fec_enet_get_nextdesc(bdp_t, fep, queue_id);
+ index = fec_enet_get_bd_index(txq->tx_bd_base, bdp_t, fep);
+ skb = txq->tx_skbuff[index];
+ bdnum++;
}
+ if (skb_shinfo(skb)->nr_frags &&
+ (status = bdp_t->cbd_sc) & BD_ENET_TX_READY)
+ break;
+
+ for (i = 0; i < bdnum; i++) {
+ if (!IS_TSO_HEADER(txq, bdp->cbd_bufaddr))
+ dma_unmap_single(&fep->pdev->dev, bdp->cbd_bufaddr,
+ bdp->cbd_datlen, DMA_TO_DEVICE);
+ bdp->cbd_bufaddr = 0;
+ if (i < bdnum - 1)
+ bdp = fec_enet_get_nextdesc(bdp, fep, queue_id);
+ }
+ txq->tx_skbuff[index] = NULL;
/* Check for errors. */
if (status & (BD_ENET_TX_HB | BD_ENET_TX_LC |
@@ -2428,6 +2459,44 @@ static int fec_enet_set_tunable(struct net_device *netdev,
return ret;
}
+static void
+fec_enet_get_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ if (fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET) {
+ wol->supported = WAKE_MAGIC;
+ wol->wolopts = fep->wol_flag & FEC_WOL_FLAG_ENABLE ? WAKE_MAGIC : 0;
+ } else {
+ wol->supported = wol->wolopts = 0;
+ }
+}
+
+static int
+fec_enet_set_wol(struct net_device *ndev, struct ethtool_wolinfo *wol)
+{
+ struct fec_enet_private *fep = netdev_priv(ndev);
+
+ if (!(fep->wol_flag & FEC_WOL_HAS_MAGIC_PACKET))
+ return -EINVAL;
+
+ if (wol->wolopts & ~WAKE_MAGIC)
+ return -EINVAL;
+
+ device_set_wakeup_enable(&ndev->dev, wol->wolopts & WAKE_MAGIC);
+ if (device_may_wakeup(&ndev->dev)) {
+ fep->wol_flag |= FEC_WOL_FLAG_ENABLE;
+ if (fep->irq[0] > 0)
+ enable_irq_wake(fep->irq[0]);
+ } else {
+ fep->wol_flag &= (~FEC_WOL_FLAG_ENABLE);
+ if (fep->irq[0] > 0)
+ disable_irq_wake(fep->irq[0]);
+ }
+
+ return 0;
+}
+
static const struct ethtool_ops fec_enet_ethtool_ops = {
.get_settings = fec_enet_get_settings,
.set_settings = fec_enet_set_settings,
@@ -2446,6 +2515,8 @@ static const struct ethtool_ops fec_enet_ethtool_ops = {
.get_ts_info = fec_enet_get_ts_info,
.get_tunable = fec_enet_get_tunable,
.set_tunable = fec_enet_set_tunable,
+ .get_wol = fec_enet_get_wol,
+ .set_wol = fec_enet_set_wol,
};
static int fec_enet_ioctl(struct net_device *ndev, struct ifreq *rq, int cmd)
@@ -2525,12 +2596,9 @@ static void fec_enet_free_queue(struct net_device *ndev)
}
for (i = 0; i < fep->num_rx_queues; i++)
- if (fep->rx_queue[i])
- kfree(fep->rx_queue[i]);
-
+ kfree(fep->rx_queue[i]);
for (i = 0; i < fep->num_tx_queues; i++)
- if (fep->tx_queue[i])
- kfree(fep->tx_queue[i]);
+ kfree(fep->tx_queue[i]);
}
static int fec_enet_alloc_queue(struct net_device *ndev)
@@ -2706,6 +2774,9 @@ fec_enet_open(struct net_device *ndev)
phy_start(fep->phy_dev);
netif_tx_start_all_queues(ndev);
+ device_set_wakeup_enable(&ndev->dev, fep->wol_flag &
+ FEC_WOL_FLAG_ENABLE);
+
return 0;
err_enet_mii_probe:
@@ -3155,6 +3226,9 @@ fec_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ndev);
+ if (of_get_property(np, "fsl,magic-packet", NULL))
+ fep->wol_flag |= FEC_WOL_HAS_MAGIC_PACKET;
+
phy_node = of_parse_phandle(np, "phy-handle", 0);
if (!phy_node && of_phy_is_fixed_link(np)) {
ret = of_phy_register_fixed_link(np);
@@ -3249,6 +3323,8 @@ fec_probe(struct platform_device *pdev)
0, pdev->name, ndev);
if (ret)
goto failed_irq;
+
+ fep->irq[i] = irq;
}
init_completion(&fep->mdio_done);
@@ -3265,6 +3341,9 @@ fec_probe(struct platform_device *pdev)
if (ret)
goto failed_register;
+ device_init_wakeup(&ndev->dev, fep->wol_flag &
+ FEC_WOL_HAS_MAGIC_PACKET);
+
if (fep->bufdesc_ex && fep->ptp_clock)
netdev_info(ndev, "registered PHC device %d\n", fep->dev_id);
@@ -3318,6 +3397,8 @@ static int __maybe_unused fec_suspend(struct device *dev)
rtnl_lock();
if (netif_running(ndev)) {
+ if (fep->wol_flag & FEC_WOL_FLAG_ENABLE)
+ fep->wol_flag |= FEC_WOL_FLAG_SLEEP_ON;
phy_stop(fep->phy_dev);
napi_disable(&fep->napi);
netif_tx_lock_bh(ndev);
@@ -3325,11 +3406,12 @@ static int __maybe_unused fec_suspend(struct device *dev)
netif_tx_unlock_bh(ndev);
fec_stop(ndev);
fec_enet_clk_enable(ndev, false);
- pinctrl_pm_select_sleep_state(&fep->pdev->dev);
+ if (!(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
+ pinctrl_pm_select_sleep_state(&fep->pdev->dev);
}
rtnl_unlock();
- if (fep->reg_phy)
+ if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE))
regulator_disable(fep->reg_phy);
/* SOC supply clock to phy, when clock is disabled, phy link down
@@ -3345,9 +3427,11 @@ static int __maybe_unused fec_resume(struct device *dev)
{
struct net_device *ndev = dev_get_drvdata(dev);
struct fec_enet_private *fep = netdev_priv(ndev);
+ struct fec_platform_data *pdata = fep->pdev->dev.platform_data;
int ret;
+ int val;
- if (fep->reg_phy) {
+ if (fep->reg_phy && !(fep->wol_flag & FEC_WOL_FLAG_ENABLE)) {
ret = regulator_enable(fep->reg_phy);
if (ret)
return ret;
@@ -3355,12 +3439,21 @@ static int __maybe_unused fec_resume(struct device *dev)
rtnl_lock();
if (netif_running(ndev)) {
- pinctrl_pm_select_default_state(&fep->pdev->dev);
ret = fec_enet_clk_enable(ndev, true);
if (ret) {
rtnl_unlock();
goto failed_clk;
}
+ if (fep->wol_flag & FEC_WOL_FLAG_ENABLE) {
+ if (pdata && pdata->sleep_mode_enable)
+ pdata->sleep_mode_enable(false);
+ val = readl(fep->hwp + FEC_ECNTRL);
+ val &= ~(FEC_ECR_MAGICEN | FEC_ECR_SLEEP);
+ writel(val, fep->hwp + FEC_ECNTRL);
+ fep->wol_flag &= ~FEC_WOL_FLAG_SLEEP_ON;
+ } else {
+ pinctrl_pm_select_default_state(&fep->pdev->dev);
+ }
fec_restart(ndev);
netif_tx_lock_bh(ndev);
netif_device_attach(ndev);
diff --git a/drivers/net/ethernet/freescale/fec_ptp.c b/drivers/net/ethernet/freescale/fec_ptp.c
index 992c8c3db553..1f9cf2345266 100644
--- a/drivers/net/ethernet/freescale/fec_ptp.c
+++ b/drivers/net/ethernet/freescale/fec_ptp.c
@@ -374,23 +374,9 @@ static int fec_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
struct fec_enet_private *fep =
container_of(ptp, struct fec_enet_private, ptp_caps);
unsigned long flags;
- u64 now;
- u32 counter;
spin_lock_irqsave(&fep->tmreg_lock, flags);
-
- now = timecounter_read(&fep->tc);
- now += delta;
-
- /* Get the timer value based on adjusted timestamp.
- * Update the counter with the masked value.
- */
- counter = now & fep->cc.mask;
- writel(counter, fep->hwp + FEC_ATIME);
-
- /* reset the timecounter */
- timecounter_init(&fep->tc, &fep->cc, now);
-
+ timecounter_adjtime(&fep->tc, delta);
spin_unlock_irqrestore(&fep->tmreg_lock, flags);
return 0;
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
index 9e2bcb807923..a17628769a1f 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet-main.c
@@ -278,14 +278,20 @@ static int fs_enet_tx_napi(struct napi_struct *napi, int budget)
fep->stats.collisions++;
/* unmap */
- dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp),
- skb->len, DMA_TO_DEVICE);
+ if (fep->mapped_as_page[dirtyidx])
+ dma_unmap_page(fep->dev, CBDR_BUFADDR(bdp),
+ CBDR_DATLEN(bdp), DMA_TO_DEVICE);
+ else
+ dma_unmap_single(fep->dev, CBDR_BUFADDR(bdp),
+ CBDR_DATLEN(bdp), DMA_TO_DEVICE);
/*
* Free the sk buffer associated with this last transmit.
*/
- dev_kfree_skb(skb);
- fep->tx_skbuff[dirtyidx] = NULL;
+ if (skb) {
+ dev_kfree_skb(skb);
+ fep->tx_skbuff[dirtyidx] = NULL;
+ }
/*
* Update pointer to next buffer descriptor to be transmitted.
@@ -299,7 +305,7 @@ static int fs_enet_tx_napi(struct napi_struct *napi, int budget)
* Since we have freed up a buffer, the ring is no longer
* full.
*/
- if (!fep->tx_free++)
+ if (++fep->tx_free >= MAX_SKB_FRAGS)
do_wake = 1;
has_tx_work = 1;
}
@@ -509,6 +515,9 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
cbd_t __iomem *bdp;
int curidx;
u16 sc;
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ skb_frag_t *frag;
+ int len;
#ifdef CONFIG_FS_ENET_MPC5121_FEC
if (((unsigned long)skb->data) & 0x3) {
@@ -530,7 +539,7 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
*/
bdp = fep->cur_tx;
- if (!fep->tx_free || (CBDR_SC(bdp) & BD_ENET_TX_READY)) {
+ if (fep->tx_free <= nr_frags || (CBDR_SC(bdp) & BD_ENET_TX_READY)) {
netif_stop_queue(dev);
spin_unlock(&fep->tx_lock);
@@ -543,35 +552,42 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
}
curidx = bdp - fep->tx_bd_base;
- /*
- * Clear all of the status flags.
- */
- CBDC_SC(bdp, BD_ENET_TX_STATS);
-
- /*
- * Save skb pointer.
- */
- fep->tx_skbuff[curidx] = skb;
-
- fep->stats.tx_bytes += skb->len;
+ len = skb->len;
+ fep->stats.tx_bytes += len;
+ if (nr_frags)
+ len -= skb->data_len;
+ fep->tx_free -= nr_frags + 1;
/*
* Push the data cache so the CPM does not get stale memory data.
*/
CBDW_BUFADDR(bdp, dma_map_single(fep->dev,
- skb->data, skb->len, DMA_TO_DEVICE));
- CBDW_DATLEN(bdp, skb->len);
+ skb->data, len, DMA_TO_DEVICE));
+ CBDW_DATLEN(bdp, len);
+
+ fep->mapped_as_page[curidx] = 0;
+ frag = skb_shinfo(skb)->frags;
+ while (nr_frags) {
+ CBDC_SC(bdp,
+ BD_ENET_TX_STATS | BD_ENET_TX_LAST | BD_ENET_TX_TC);
+ CBDS_SC(bdp, BD_ENET_TX_READY);
+
+ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
+ bdp++, curidx++;
+ else
+ bdp = fep->tx_bd_base, curidx = 0;
- /*
- * If this was the last BD in the ring, start at the beginning again.
- */
- if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
- fep->cur_tx++;
- else
- fep->cur_tx = fep->tx_bd_base;
+ len = skb_frag_size(frag);
+ CBDW_BUFADDR(bdp, skb_frag_dma_map(fep->dev, frag, 0, len,
+ DMA_TO_DEVICE));
+ CBDW_DATLEN(bdp, len);
- if (!--fep->tx_free)
- netif_stop_queue(dev);
+ fep->tx_skbuff[curidx] = NULL;
+ fep->mapped_as_page[curidx] = 1;
+
+ frag++;
+ nr_frags--;
+ }
/* Trigger transmission start */
sc = BD_ENET_TX_READY | BD_ENET_TX_INTR |
@@ -582,8 +598,22 @@ static int fs_enet_start_xmit(struct sk_buff *skb, struct net_device *dev)
* yay for hw reuse :) */
if (skb->len <= 60)
sc |= BD_ENET_TX_PAD;
+ CBDC_SC(bdp, BD_ENET_TX_STATS);
CBDS_SC(bdp, sc);
+ /* Save skb pointer. */
+ fep->tx_skbuff[curidx] = skb;
+
+ /* If this was the last BD in the ring, start at the beginning again. */
+ if ((CBDR_SC(bdp) & BD_ENET_TX_WRAP) == 0)
+ bdp++;
+ else
+ bdp = fep->tx_bd_base;
+ fep->cur_tx = bdp;
+
+ if (fep->tx_free < MAX_SKB_FRAGS)
+ netif_stop_queue(dev);
+
skb_tx_timestamp(skb);
(*fep->ops->tx_kickstart)(dev);
@@ -917,7 +947,7 @@ static int fs_enet_probe(struct platform_device *ofdev)
}
fpi->rx_ring = 32;
- fpi->tx_ring = 32;
+ fpi->tx_ring = 64;
fpi->rx_copybreak = 240;
fpi->napi_weight = 17;
fpi->phy_node = of_parse_phandle(ofdev->dev.of_node, "phy-handle", 0);
@@ -955,7 +985,8 @@ static int fs_enet_probe(struct platform_device *ofdev)
privsize = sizeof(*fep) +
sizeof(struct sk_buff **) *
- (fpi->rx_ring + fpi->tx_ring);
+ (fpi->rx_ring + fpi->tx_ring) +
+ sizeof(char) * fpi->tx_ring;
ndev = alloc_etherdev(privsize);
if (!ndev) {
@@ -978,6 +1009,8 @@ static int fs_enet_probe(struct platform_device *ofdev)
fep->rx_skbuff = (struct sk_buff **)&fep[1];
fep->tx_skbuff = fep->rx_skbuff + fpi->rx_ring;
+ fep->mapped_as_page = (char *)(fep->rx_skbuff + fpi->rx_ring +
+ fpi->tx_ring);
spin_lock_init(&fep->lock);
spin_lock_init(&fep->tx_lock);
@@ -1007,6 +1040,8 @@ static int fs_enet_probe(struct platform_device *ofdev)
netif_carrier_off(ndev);
+ ndev->features |= NETIF_F_SG;
+
ret = register_netdev(ndev);
if (ret)
goto out_free_bd;
diff --git a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
index 3a4b49e0e717..f184d8f952e2 100644
--- a/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
+++ b/drivers/net/ethernet/freescale/fs_enet/fs_enet.h
@@ -134,6 +134,7 @@ struct fs_enet_private {
void __iomem *ring_base;
struct sk_buff **rx_skbuff;
struct sk_buff **tx_skbuff;
+ char *mapped_as_page;
cbd_t __iomem *rx_bd_base; /* Address of Rx and Tx buffers. */
cbd_t __iomem *tx_bd_base;
cbd_t __iomem *dirty_tx; /* ring entries to be free()ed. */
diff --git a/drivers/net/ethernet/freescale/gianfar.c b/drivers/net/ethernet/freescale/gianfar.c
index 5645342f5b28..43df78882e48 100644
--- a/drivers/net/ethernet/freescale/gianfar.c
+++ b/drivers/net/ethernet/freescale/gianfar.c
@@ -116,7 +116,8 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev);
static void gfar_reset_task(struct work_struct *work);
static void gfar_timeout(struct net_device *dev);
static int gfar_close(struct net_device *dev);
-struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr);
+static struct sk_buff *gfar_new_skb(struct net_device *dev,
+ dma_addr_t *bufaddr);
static int gfar_set_mac_address(struct net_device *dev);
static int gfar_change_mtu(struct net_device *dev, int new_mtu);
static irqreturn_t gfar_error(int irq, void *dev_id);
@@ -176,7 +177,7 @@ static int gfar_init_bds(struct net_device *ndev)
struct gfar_priv_rx_q *rx_queue = NULL;
struct txbd8 *txbdp;
struct rxbd8 *rxbdp;
- u32 *rfbptr;
+ u32 __iomem *rfbptr;
int i, j;
dma_addr_t bufaddr;
@@ -554,7 +555,7 @@ static void gfar_ints_enable(struct gfar_private *priv)
}
}
-void lock_tx_qs(struct gfar_private *priv)
+static void lock_tx_qs(struct gfar_private *priv)
{
int i;
@@ -562,7 +563,7 @@ void lock_tx_qs(struct gfar_private *priv)
spin_lock(&priv->tx_queue[i]->txlock);
}
-void unlock_tx_qs(struct gfar_private *priv)
+static void unlock_tx_qs(struct gfar_private *priv)
{
int i;
@@ -763,7 +764,7 @@ static int gfar_of_init(struct platform_device *ofdev, struct net_device **pdev)
u32 *tx_queues, *rx_queues;
unsigned short mode, poll_mode;
- if (!np || !of_device_is_available(np))
+ if (!np)
return -ENODEV;
if (of_device_is_compatible(np, "fsl,etsec2")) {
@@ -2169,7 +2170,7 @@ static inline void gfar_tx_checksum(struct sk_buff *skb, struct txfcb *fcb,
void inline gfar_tx_vlan(struct sk_buff *skb, struct txfcb *fcb)
{
fcb->flags |= TXFCB_VLN;
- fcb->vlctl = vlan_tx_tag_get(skb);
+ fcb->vlctl = skb_vlan_tag_get(skb);
}
static inline struct txbd8 *skip_txbd(struct txbd8 *bdp, int stride,
@@ -2229,7 +2230,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
regs = tx_queue->grp->regs;
do_csum = (CHECKSUM_PARTIAL == skb->ip_summed);
- do_vlan = vlan_tx_tag_present(skb);
+ do_vlan = skb_vlan_tag_present(skb);
do_tstamp = (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
priv->hwts_tx_en;
@@ -2671,7 +2672,7 @@ static struct sk_buff *gfar_alloc_skb(struct net_device *dev)
return skb;
}
-struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr)
+static struct sk_buff *gfar_new_skb(struct net_device *dev, dma_addr_t *bufaddr)
{
struct gfar_private *priv = netdev_priv(dev);
struct sk_buff *skb;
diff --git a/drivers/net/ethernet/freescale/gianfar.h b/drivers/net/ethernet/freescale/gianfar.h
index b581b8823a2a..9e1802400c23 100644
--- a/drivers/net/ethernet/freescale/gianfar.h
+++ b/drivers/net/ethernet/freescale/gianfar.h
@@ -1039,7 +1039,7 @@ struct gfar_priv_rx_q {
/* RX Coalescing values */
unsigned char rxcoalescing;
unsigned long rxic;
- u32 *rfbptr;
+ u32 __iomem *rfbptr;
};
enum gfar_irqinfo_id {
diff --git a/drivers/net/ethernet/freescale/gianfar_ethtool.c b/drivers/net/ethernet/freescale/gianfar_ethtool.c
index 3e1a9c1a67a9..fda12fb32ec7 100644
--- a/drivers/net/ethernet/freescale/gianfar_ethtool.c
+++ b/drivers/net/ethernet/freescale/gianfar_ethtool.c
@@ -1586,7 +1586,7 @@ static int gfar_write_filer_table(struct gfar_private *priv,
return -EBUSY;
/* Fill regular entries */
- for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].ctrl);
+ for (; i < MAX_FILER_IDX - 1 && (tab->fe[i].ctrl | tab->fe[i].prop);
i++)
gfar_write_filer(priv, i, tab->fe[i].ctrl, tab->fe[i].prop);
/* Fill the rest with fall-troughs */
diff --git a/drivers/net/ethernet/freescale/xgmac_mdio.c b/drivers/net/ethernet/freescale/xgmac_mdio.c
index 6e7db66069aa..3a83bc2c613c 100644
--- a/drivers/net/ethernet/freescale/xgmac_mdio.c
+++ b/drivers/net/ethernet/freescale/xgmac_mdio.c
@@ -32,18 +32,19 @@ struct tgec_mdio_controller {
__be32 mdio_addr; /* MDIO address */
} __packed;
+#define MDIO_STAT_ENC BIT(6)
#define MDIO_STAT_CLKDIV(x) (((x>>1) & 0xff) << 8)
-#define MDIO_STAT_BSY (1 << 0)
-#define MDIO_STAT_RD_ER (1 << 1)
+#define MDIO_STAT_BSY BIT(0)
+#define MDIO_STAT_RD_ER BIT(1)
#define MDIO_CTL_DEV_ADDR(x) (x & 0x1f)
#define MDIO_CTL_PORT_ADDR(x) ((x & 0x1f) << 5)
-#define MDIO_CTL_PRE_DIS (1 << 10)
-#define MDIO_CTL_SCAN_EN (1 << 11)
-#define MDIO_CTL_POST_INC (1 << 14)
-#define MDIO_CTL_READ (1 << 15)
+#define MDIO_CTL_PRE_DIS BIT(10)
+#define MDIO_CTL_SCAN_EN BIT(11)
+#define MDIO_CTL_POST_INC BIT(14)
+#define MDIO_CTL_READ BIT(15)
#define MDIO_DATA(x) (x & 0xffff)
-#define MDIO_DATA_BSY (1 << 31)
+#define MDIO_DATA_BSY BIT(31)
/*
* Wait until the MDIO bus is free
@@ -51,12 +52,16 @@ struct tgec_mdio_controller {
static int xgmac_wait_until_free(struct device *dev,
struct tgec_mdio_controller __iomem *regs)
{
- uint32_t status;
+ unsigned int timeout;
/* Wait till the bus is free */
- status = spin_event_timeout(
- !((in_be32(&regs->mdio_stat)) & MDIO_STAT_BSY), TIMEOUT, 0);
- if (!status) {
+ timeout = TIMEOUT;
+ while ((ioread32be(&regs->mdio_stat) & MDIO_STAT_BSY) && timeout) {
+ cpu_relax();
+ timeout--;
+ }
+
+ if (!timeout) {
dev_err(dev, "timeout waiting for bus to be free\n");
return -ETIMEDOUT;
}
@@ -70,12 +75,16 @@ static int xgmac_wait_until_free(struct device *dev,
static int xgmac_wait_until_done(struct device *dev,
struct tgec_mdio_controller __iomem *regs)
{
- uint32_t status;
+ unsigned int timeout;
/* Wait till the MDIO write is complete */
- status = spin_event_timeout(
- !((in_be32(&regs->mdio_data)) & MDIO_DATA_BSY), TIMEOUT, 0);
- if (!status) {
+ timeout = TIMEOUT;
+ while ((ioread32be(&regs->mdio_data) & MDIO_DATA_BSY) && timeout) {
+ cpu_relax();
+ timeout--;
+ }
+
+ if (!timeout) {
dev_err(dev, "timeout waiting for operation to complete\n");
return -ETIMEDOUT;
}
@@ -91,29 +100,42 @@ static int xgmac_wait_until_done(struct device *dev,
static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 value)
{
struct tgec_mdio_controller __iomem *regs = bus->priv;
- uint16_t dev_addr = regnum >> 16;
+ uint16_t dev_addr;
+ u32 mdio_ctl, mdio_stat;
int ret;
- /* Setup the MII Mgmt clock speed */
- out_be32(&regs->mdio_stat, MDIO_STAT_CLKDIV(100));
+ mdio_stat = ioread32be(&regs->mdio_stat);
+ if (regnum & MII_ADDR_C45) {
+ /* Clause 45 (ie 10G) */
+ dev_addr = (regnum >> 16) & 0x1f;
+ mdio_stat |= MDIO_STAT_ENC;
+ } else {
+ /* Clause 22 (ie 1G) */
+ dev_addr = regnum & 0x1f;
+ mdio_stat &= ~MDIO_STAT_ENC;
+ }
+
+ iowrite32be(mdio_stat, &regs->mdio_stat);
ret = xgmac_wait_until_free(&bus->dev, regs);
if (ret)
return ret;
/* Set the port and dev addr */
- out_be32(&regs->mdio_ctl,
- MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr));
+ mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
+ iowrite32be(mdio_ctl, &regs->mdio_ctl);
/* Set the register address */
- out_be32(&regs->mdio_addr, regnum & 0xffff);
+ if (regnum & MII_ADDR_C45) {
+ iowrite32be(regnum & 0xffff, &regs->mdio_addr);
- ret = xgmac_wait_until_free(&bus->dev, regs);
- if (ret)
- return ret;
+ ret = xgmac_wait_until_free(&bus->dev, regs);
+ if (ret)
+ return ret;
+ }
/* Write the value to the register */
- out_be32(&regs->mdio_data, MDIO_DATA(value));
+ iowrite32be(MDIO_DATA(value), &regs->mdio_data);
ret = xgmac_wait_until_done(&bus->dev, regs);
if (ret)
@@ -130,13 +152,22 @@ static int xgmac_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 val
static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
{
struct tgec_mdio_controller __iomem *regs = bus->priv;
- uint16_t dev_addr = regnum >> 16;
+ uint16_t dev_addr;
+ uint32_t mdio_stat;
uint32_t mdio_ctl;
uint16_t value;
int ret;
- /* Setup the MII Mgmt clock speed */
- out_be32(&regs->mdio_stat, MDIO_STAT_CLKDIV(100));
+ mdio_stat = ioread32be(&regs->mdio_stat);
+ if (regnum & MII_ADDR_C45) {
+ dev_addr = (regnum >> 16) & 0x1f;
+ mdio_stat |= MDIO_STAT_ENC;
+ } else {
+ dev_addr = regnum & 0x1f;
+ mdio_stat &= ~MDIO_STAT_ENC;
+ }
+
+ iowrite32be(mdio_stat, &regs->mdio_stat);
ret = xgmac_wait_until_free(&bus->dev, regs);
if (ret)
@@ -144,54 +175,38 @@ static int xgmac_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
/* Set the Port and Device Addrs */
mdio_ctl = MDIO_CTL_PORT_ADDR(phy_id) | MDIO_CTL_DEV_ADDR(dev_addr);
- out_be32(&regs->mdio_ctl, mdio_ctl);
+ iowrite32be(mdio_ctl, &regs->mdio_ctl);
/* Set the register address */
- out_be32(&regs->mdio_addr, regnum & 0xffff);
+ if (regnum & MII_ADDR_C45) {
+ iowrite32be(regnum & 0xffff, &regs->mdio_addr);
- ret = xgmac_wait_until_free(&bus->dev, regs);
- if (ret)
- return ret;
+ ret = xgmac_wait_until_free(&bus->dev, regs);
+ if (ret)
+ return ret;
+ }
/* Initiate the read */
- out_be32(&regs->mdio_ctl, mdio_ctl | MDIO_CTL_READ);
+ iowrite32be(mdio_ctl | MDIO_CTL_READ, &regs->mdio_ctl);
ret = xgmac_wait_until_done(&bus->dev, regs);
if (ret)
return ret;
/* Return all Fs if nothing was there */
- if (in_be32(&regs->mdio_stat) & MDIO_STAT_RD_ER) {
+ if (ioread32be(&regs->mdio_stat) & MDIO_STAT_RD_ER) {
dev_err(&bus->dev,
"Error while reading PHY%d reg at %d.%hhu\n",
phy_id, dev_addr, regnum);
return 0xffff;
}
- value = in_be32(&regs->mdio_data) & 0xffff;
+ value = ioread32be(&regs->mdio_data) & 0xffff;
dev_dbg(&bus->dev, "read %04x\n", value);
return value;
}
-/* Reset the MIIM registers, and wait for the bus to free */
-static int xgmac_mdio_reset(struct mii_bus *bus)
-{
- struct tgec_mdio_controller __iomem *regs = bus->priv;
- int ret;
-
- mutex_lock(&bus->mdio_lock);
-
- /* Setup the MII Mgmt clock speed */
- out_be32(&regs->mdio_stat, MDIO_STAT_CLKDIV(100));
-
- ret = xgmac_wait_until_free(&bus->dev, regs);
-
- mutex_unlock(&bus->mdio_lock);
-
- return ret;
-}
-
static int xgmac_mdio_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -205,15 +220,13 @@ static int xgmac_mdio_probe(struct platform_device *pdev)
return ret;
}
- bus = mdiobus_alloc_size(PHY_MAX_ADDR * sizeof(int));
+ bus = mdiobus_alloc();
if (!bus)
return -ENOMEM;
bus->name = "Freescale XGMAC MDIO Bus";
bus->read = xgmac_mdio_read;
bus->write = xgmac_mdio_write;
- bus->reset = xgmac_mdio_reset;
- bus->irq = bus->priv;
bus->parent = &pdev->dev;
snprintf(bus->id, MII_BUS_ID_SIZE, "%llx", (unsigned long long)res.start);
@@ -258,6 +271,9 @@ static struct of_device_id xgmac_mdio_match[] = {
{
.compatible = "fsl,fman-xmdio",
},
+ {
+ .compatible = "fsl,fman-memac-mdio",
+ },
{},
};
MODULE_DEVICE_TABLE(of, xgmac_mdio_match);
diff --git a/drivers/net/ethernet/hisilicon/Kconfig b/drivers/net/ethernet/hisilicon/Kconfig
index e9421731b05e..a54d89791311 100644
--- a/drivers/net/ethernet/hisilicon/Kconfig
+++ b/drivers/net/ethernet/hisilicon/Kconfig
@@ -24,4 +24,13 @@ config HIX5HD2_GMAC
help
This selects the hix5hd2 mac family network device.
+config HIP04_ETH
+ tristate "HISILICON P04 Ethernet support"
+ select PHYLIB
+ select MARVELL_PHY
+ select MFD_SYSCON
+ ---help---
+ If you wish to compile a kernel for a hardware with hisilicon p04 SoC and
+ want to use the internal ethernet then you should answer Y to this.
+
endif # NET_VENDOR_HISILICON
diff --git a/drivers/net/ethernet/hisilicon/Makefile b/drivers/net/ethernet/hisilicon/Makefile
index 9175e84622d4..6c14540a4dc5 100644
--- a/drivers/net/ethernet/hisilicon/Makefile
+++ b/drivers/net/ethernet/hisilicon/Makefile
@@ -3,3 +3,4 @@
#
obj-$(CONFIG_HIX5HD2_GMAC) += hix5hd2_gmac.o
+obj-$(CONFIG_HIP04_ETH) += hip04_mdio.o hip04_eth.o
diff --git a/drivers/net/ethernet/hisilicon/hip04_eth.c b/drivers/net/ethernet/hisilicon/hip04_eth.c
new file mode 100644
index 000000000000..b72d238695d7
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hip04_eth.c
@@ -0,0 +1,971 @@
+
+/* Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/etherdevice.h>
+#include <linux/platform_device.h>
+#include <linux/interrupt.h>
+#include <linux/ktime.h>
+#include <linux/of_address.h>
+#include <linux/phy.h>
+#include <linux/of_mdio.h>
+#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#define PPE_CFG_RX_ADDR 0x100
+#define PPE_CFG_POOL_GRP 0x300
+#define PPE_CFG_RX_BUF_SIZE 0x400
+#define PPE_CFG_RX_FIFO_SIZE 0x500
+#define PPE_CURR_BUF_CNT 0xa200
+
+#define GE_DUPLEX_TYPE 0x08
+#define GE_MAX_FRM_SIZE_REG 0x3c
+#define GE_PORT_MODE 0x40
+#define GE_PORT_EN 0x44
+#define GE_SHORT_RUNTS_THR_REG 0x50
+#define GE_TX_LOCAL_PAGE_REG 0x5c
+#define GE_TRANSMIT_CONTROL_REG 0x60
+#define GE_CF_CRC_STRIP_REG 0x1b0
+#define GE_MODE_CHANGE_REG 0x1b4
+#define GE_RECV_CONTROL_REG 0x1e0
+#define GE_STATION_MAC_ADDRESS 0x210
+#define PPE_CFG_CPU_ADD_ADDR 0x580
+#define PPE_CFG_MAX_FRAME_LEN_REG 0x408
+#define PPE_CFG_BUS_CTRL_REG 0x424
+#define PPE_CFG_RX_CTRL_REG 0x428
+#define PPE_CFG_RX_PKT_MODE_REG 0x438
+#define PPE_CFG_QOS_VMID_GEN 0x500
+#define PPE_CFG_RX_PKT_INT 0x538
+#define PPE_INTEN 0x600
+#define PPE_INTSTS 0x608
+#define PPE_RINT 0x604
+#define PPE_CFG_STS_MODE 0x700
+#define PPE_HIS_RX_PKT_CNT 0x804
+
+/* REG_INTERRUPT */
+#define RCV_INT BIT(10)
+#define RCV_NOBUF BIT(8)
+#define RCV_DROP BIT(7)
+#define TX_DROP BIT(6)
+#define DEF_INT_ERR (RCV_NOBUF | RCV_DROP | TX_DROP)
+#define DEF_INT_MASK (RCV_INT | DEF_INT_ERR)
+
+/* TX descriptor config */
+#define TX_FREE_MEM BIT(0)
+#define TX_READ_ALLOC_L3 BIT(1)
+#define TX_FINISH_CACHE_INV BIT(2)
+#define TX_CLEAR_WB BIT(4)
+#define TX_L3_CHECKSUM BIT(5)
+#define TX_LOOP_BACK BIT(11)
+
+/* RX error */
+#define RX_PKT_DROP BIT(0)
+#define RX_L2_ERR BIT(1)
+#define RX_PKT_ERR (RX_PKT_DROP | RX_L2_ERR)
+
+#define SGMII_SPEED_1000 0x08
+#define SGMII_SPEED_100 0x07
+#define SGMII_SPEED_10 0x06
+#define MII_SPEED_100 0x01
+#define MII_SPEED_10 0x00
+
+#define GE_DUPLEX_FULL BIT(0)
+#define GE_DUPLEX_HALF 0x00
+#define GE_MODE_CHANGE_EN BIT(0)
+
+#define GE_TX_AUTO_NEG BIT(5)
+#define GE_TX_ADD_CRC BIT(6)
+#define GE_TX_SHORT_PAD_THROUGH BIT(7)
+
+#define GE_RX_STRIP_CRC BIT(0)
+#define GE_RX_STRIP_PAD BIT(3)
+#define GE_RX_PAD_EN BIT(4)
+
+#define GE_AUTO_NEG_CTL BIT(0)
+
+#define GE_RX_INT_THRESHOLD BIT(6)
+#define GE_RX_TIMEOUT 0x04
+
+#define GE_RX_PORT_EN BIT(1)
+#define GE_TX_PORT_EN BIT(2)
+
+#define PPE_CFG_STS_RX_PKT_CNT_RC BIT(12)
+
+#define PPE_CFG_RX_PKT_ALIGN BIT(18)
+#define PPE_CFG_QOS_VMID_MODE BIT(14)
+#define PPE_CFG_QOS_VMID_GRP_SHIFT 8
+
+#define PPE_CFG_RX_FIFO_FSFU BIT(11)
+#define PPE_CFG_RX_DEPTH_SHIFT 16
+#define PPE_CFG_RX_START_SHIFT 0
+#define PPE_CFG_RX_CTRL_ALIGN_SHIFT 11
+
+#define PPE_CFG_BUS_LOCAL_REL BIT(14)
+#define PPE_CFG_BUS_BIG_ENDIEN BIT(0)
+
+#define RX_DESC_NUM 128
+#define TX_DESC_NUM 256
+#define TX_NEXT(N) (((N) + 1) & (TX_DESC_NUM-1))
+#define RX_NEXT(N) (((N) + 1) & (RX_DESC_NUM-1))
+
+#define GMAC_PPE_RX_PKT_MAX_LEN 379
+#define GMAC_MAX_PKT_LEN 1516
+#define GMAC_MIN_PKT_LEN 31
+#define RX_BUF_SIZE 1600
+#define RESET_TIMEOUT 1000
+#define TX_TIMEOUT (6 * HZ)
+
+#define DRV_NAME "hip04-ether"
+#define DRV_VERSION "v1.0"
+
+#define HIP04_MAX_TX_COALESCE_USECS 200
+#define HIP04_MIN_TX_COALESCE_USECS 100
+#define HIP04_MAX_TX_COALESCE_FRAMES 200
+#define HIP04_MIN_TX_COALESCE_FRAMES 100
+
+struct tx_desc {
+ u32 send_addr;
+ u32 send_size;
+ u32 next_addr;
+ u32 cfg;
+ u32 wb_addr;
+} __aligned(64);
+
+struct rx_desc {
+ u16 reserved_16;
+ u16 pkt_len;
+ u32 reserve1[3];
+ u32 pkt_err;
+ u32 reserve2[4];
+};
+
+struct hip04_priv {
+ void __iomem *base;
+ int phy_mode;
+ int chan;
+ unsigned int port;
+ unsigned int speed;
+ unsigned int duplex;
+ unsigned int reg_inten;
+
+ struct napi_struct napi;
+ struct net_device *ndev;
+
+ struct tx_desc *tx_desc;
+ dma_addr_t tx_desc_dma;
+ struct sk_buff *tx_skb[TX_DESC_NUM];
+ dma_addr_t tx_phys[TX_DESC_NUM];
+ unsigned int tx_head;
+
+ int tx_coalesce_frames;
+ int tx_coalesce_usecs;
+ struct hrtimer tx_coalesce_timer;
+
+ unsigned char *rx_buf[RX_DESC_NUM];
+ dma_addr_t rx_phys[RX_DESC_NUM];
+ unsigned int rx_head;
+ unsigned int rx_buf_size;
+
+ struct device_node *phy_node;
+ struct phy_device *phy;
+ struct regmap *map;
+ struct work_struct tx_timeout_task;
+
+ /* written only by tx cleanup */
+ unsigned int tx_tail ____cacheline_aligned_in_smp;
+};
+
+static inline unsigned int tx_count(unsigned int head, unsigned int tail)
+{
+ return (head - tail) % (TX_DESC_NUM - 1);
+}
+
+static void hip04_config_port(struct net_device *ndev, u32 speed, u32 duplex)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ u32 val;
+
+ priv->speed = speed;
+ priv->duplex = duplex;
+
+ switch (priv->phy_mode) {
+ case PHY_INTERFACE_MODE_SGMII:
+ if (speed == SPEED_1000)
+ val = SGMII_SPEED_1000;
+ else if (speed == SPEED_100)
+ val = SGMII_SPEED_100;
+ else
+ val = SGMII_SPEED_10;
+ break;
+ case PHY_INTERFACE_MODE_MII:
+ if (speed == SPEED_100)
+ val = MII_SPEED_100;
+ else
+ val = MII_SPEED_10;
+ break;
+ default:
+ netdev_warn(ndev, "not supported mode\n");
+ val = MII_SPEED_10;
+ break;
+ }
+ writel_relaxed(val, priv->base + GE_PORT_MODE);
+
+ val = duplex ? GE_DUPLEX_FULL : GE_DUPLEX_HALF;
+ writel_relaxed(val, priv->base + GE_DUPLEX_TYPE);
+
+ val = GE_MODE_CHANGE_EN;
+ writel_relaxed(val, priv->base + GE_MODE_CHANGE_REG);
+}
+
+static void hip04_reset_ppe(struct hip04_priv *priv)
+{
+ u32 val, tmp, timeout = 0;
+
+ do {
+ regmap_read(priv->map, priv->port * 4 + PPE_CURR_BUF_CNT, &val);
+ regmap_read(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, &tmp);
+ if (timeout++ > RESET_TIMEOUT)
+ break;
+ } while (val & 0xfff);
+}
+
+static void hip04_config_fifo(struct hip04_priv *priv)
+{
+ u32 val;
+
+ val = readl_relaxed(priv->base + PPE_CFG_STS_MODE);
+ val |= PPE_CFG_STS_RX_PKT_CNT_RC;
+ writel_relaxed(val, priv->base + PPE_CFG_STS_MODE);
+
+ val = BIT(priv->port);
+ regmap_write(priv->map, priv->port * 4 + PPE_CFG_POOL_GRP, val);
+
+ val = priv->port << PPE_CFG_QOS_VMID_GRP_SHIFT;
+ val |= PPE_CFG_QOS_VMID_MODE;
+ writel_relaxed(val, priv->base + PPE_CFG_QOS_VMID_GEN);
+
+ val = RX_BUF_SIZE;
+ regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_BUF_SIZE, val);
+
+ val = RX_DESC_NUM << PPE_CFG_RX_DEPTH_SHIFT;
+ val |= PPE_CFG_RX_FIFO_FSFU;
+ val |= priv->chan << PPE_CFG_RX_START_SHIFT;
+ regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_FIFO_SIZE, val);
+
+ val = NET_IP_ALIGN << PPE_CFG_RX_CTRL_ALIGN_SHIFT;
+ writel_relaxed(val, priv->base + PPE_CFG_RX_CTRL_REG);
+
+ val = PPE_CFG_RX_PKT_ALIGN;
+ writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_MODE_REG);
+
+ val = PPE_CFG_BUS_LOCAL_REL | PPE_CFG_BUS_BIG_ENDIEN;
+ writel_relaxed(val, priv->base + PPE_CFG_BUS_CTRL_REG);
+
+ val = GMAC_PPE_RX_PKT_MAX_LEN;
+ writel_relaxed(val, priv->base + PPE_CFG_MAX_FRAME_LEN_REG);
+
+ val = GMAC_MAX_PKT_LEN;
+ writel_relaxed(val, priv->base + GE_MAX_FRM_SIZE_REG);
+
+ val = GMAC_MIN_PKT_LEN;
+ writel_relaxed(val, priv->base + GE_SHORT_RUNTS_THR_REG);
+
+ val = readl_relaxed(priv->base + GE_TRANSMIT_CONTROL_REG);
+ val |= GE_TX_AUTO_NEG | GE_TX_ADD_CRC | GE_TX_SHORT_PAD_THROUGH;
+ writel_relaxed(val, priv->base + GE_TRANSMIT_CONTROL_REG);
+
+ val = GE_RX_STRIP_CRC;
+ writel_relaxed(val, priv->base + GE_CF_CRC_STRIP_REG);
+
+ val = readl_relaxed(priv->base + GE_RECV_CONTROL_REG);
+ val |= GE_RX_STRIP_PAD | GE_RX_PAD_EN;
+ writel_relaxed(val, priv->base + GE_RECV_CONTROL_REG);
+
+ val = GE_AUTO_NEG_CTL;
+ writel_relaxed(val, priv->base + GE_TX_LOCAL_PAGE_REG);
+}
+
+static void hip04_mac_enable(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ u32 val;
+
+ /* enable tx & rx */
+ val = readl_relaxed(priv->base + GE_PORT_EN);
+ val |= GE_RX_PORT_EN | GE_TX_PORT_EN;
+ writel_relaxed(val, priv->base + GE_PORT_EN);
+
+ /* clear rx int */
+ val = RCV_INT;
+ writel_relaxed(val, priv->base + PPE_RINT);
+
+ /* config recv int */
+ val = GE_RX_INT_THRESHOLD | GE_RX_TIMEOUT;
+ writel_relaxed(val, priv->base + PPE_CFG_RX_PKT_INT);
+
+ /* enable interrupt */
+ priv->reg_inten = DEF_INT_MASK;
+ writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN);
+}
+
+static void hip04_mac_disable(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ u32 val;
+
+ /* disable int */
+ priv->reg_inten &= ~(DEF_INT_MASK);
+ writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN);
+
+ /* disable tx & rx */
+ val = readl_relaxed(priv->base + GE_PORT_EN);
+ val &= ~(GE_RX_PORT_EN | GE_TX_PORT_EN);
+ writel_relaxed(val, priv->base + GE_PORT_EN);
+}
+
+static void hip04_set_xmit_desc(struct hip04_priv *priv, dma_addr_t phys)
+{
+ writel(phys, priv->base + PPE_CFG_CPU_ADD_ADDR);
+}
+
+static void hip04_set_recv_desc(struct hip04_priv *priv, dma_addr_t phys)
+{
+ regmap_write(priv->map, priv->port * 4 + PPE_CFG_RX_ADDR, phys);
+}
+
+static u32 hip04_recv_cnt(struct hip04_priv *priv)
+{
+ return readl(priv->base + PPE_HIS_RX_PKT_CNT);
+}
+
+static void hip04_update_mac_address(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+
+ writel_relaxed(((ndev->dev_addr[0] << 8) | (ndev->dev_addr[1])),
+ priv->base + GE_STATION_MAC_ADDRESS);
+ writel_relaxed(((ndev->dev_addr[2] << 24) | (ndev->dev_addr[3] << 16) |
+ (ndev->dev_addr[4] << 8) | (ndev->dev_addr[5])),
+ priv->base + GE_STATION_MAC_ADDRESS + 4);
+}
+
+static int hip04_set_mac_address(struct net_device *ndev, void *addr)
+{
+ eth_mac_addr(ndev, addr);
+ hip04_update_mac_address(ndev);
+ return 0;
+}
+
+static int hip04_tx_reclaim(struct net_device *ndev, bool force)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ unsigned tx_tail = priv->tx_tail;
+ struct tx_desc *desc;
+ unsigned int bytes_compl = 0, pkts_compl = 0;
+ unsigned int count;
+
+ smp_rmb();
+ count = tx_count(ACCESS_ONCE(priv->tx_head), tx_tail);
+ if (count == 0)
+ goto out;
+
+ while (count) {
+ desc = &priv->tx_desc[tx_tail];
+ if (desc->send_addr != 0) {
+ if (force)
+ desc->send_addr = 0;
+ else
+ break;
+ }
+
+ if (priv->tx_phys[tx_tail]) {
+ dma_unmap_single(&ndev->dev, priv->tx_phys[tx_tail],
+ priv->tx_skb[tx_tail]->len,
+ DMA_TO_DEVICE);
+ priv->tx_phys[tx_tail] = 0;
+ }
+ pkts_compl++;
+ bytes_compl += priv->tx_skb[tx_tail]->len;
+ dev_kfree_skb(priv->tx_skb[tx_tail]);
+ priv->tx_skb[tx_tail] = NULL;
+ tx_tail = TX_NEXT(tx_tail);
+ count--;
+ }
+
+ priv->tx_tail = tx_tail;
+ smp_wmb(); /* Ensure tx_tail visible to xmit */
+
+out:
+ if (pkts_compl || bytes_compl)
+ netdev_completed_queue(ndev, pkts_compl, bytes_compl);
+
+ if (unlikely(netif_queue_stopped(ndev)) && (count < (TX_DESC_NUM - 1)))
+ netif_wake_queue(ndev);
+
+ return count;
+}
+
+static int hip04_mac_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ unsigned int tx_head = priv->tx_head, count;
+ struct tx_desc *desc = &priv->tx_desc[tx_head];
+ dma_addr_t phys;
+
+ smp_rmb();
+ count = tx_count(tx_head, ACCESS_ONCE(priv->tx_tail));
+ if (count == (TX_DESC_NUM - 1)) {
+ netif_stop_queue(ndev);
+ return NETDEV_TX_BUSY;
+ }
+
+ phys = dma_map_single(&ndev->dev, skb->data, skb->len, DMA_TO_DEVICE);
+ if (dma_mapping_error(&ndev->dev, phys)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ priv->tx_skb[tx_head] = skb;
+ priv->tx_phys[tx_head] = phys;
+ desc->send_addr = cpu_to_be32(phys);
+ desc->send_size = cpu_to_be32(skb->len);
+ desc->cfg = cpu_to_be32(TX_CLEAR_WB | TX_FINISH_CACHE_INV);
+ phys = priv->tx_desc_dma + tx_head * sizeof(struct tx_desc);
+ desc->wb_addr = cpu_to_be32(phys);
+ skb_tx_timestamp(skb);
+
+ hip04_set_xmit_desc(priv, phys);
+ priv->tx_head = TX_NEXT(tx_head);
+ count++;
+ netdev_sent_queue(ndev, skb->len);
+
+ stats->tx_bytes += skb->len;
+ stats->tx_packets++;
+
+ /* Ensure tx_head update visible to tx reclaim */
+ smp_wmb();
+
+ /* queue is getting full, better start cleaning up now */
+ if (count >= priv->tx_coalesce_frames) {
+ if (napi_schedule_prep(&priv->napi)) {
+ /* disable rx interrupt and timer */
+ priv->reg_inten &= ~(RCV_INT);
+ writel_relaxed(DEF_INT_MASK & ~RCV_INT,
+ priv->base + PPE_INTEN);
+ hrtimer_cancel(&priv->tx_coalesce_timer);
+ __napi_schedule(&priv->napi);
+ }
+ } else if (!hrtimer_is_queued(&priv->tx_coalesce_timer)) {
+ /* cleanup not pending yet, start a new timer */
+ hrtimer_start_expires(&priv->tx_coalesce_timer,
+ HRTIMER_MODE_REL);
+ }
+
+ return NETDEV_TX_OK;
+}
+
+static int hip04_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct hip04_priv *priv = container_of(napi, struct hip04_priv, napi);
+ struct net_device *ndev = priv->ndev;
+ struct net_device_stats *stats = &ndev->stats;
+ unsigned int cnt = hip04_recv_cnt(priv);
+ struct rx_desc *desc;
+ struct sk_buff *skb;
+ unsigned char *buf;
+ bool last = false;
+ dma_addr_t phys;
+ int rx = 0;
+ int tx_remaining;
+ u16 len;
+ u32 err;
+
+ while (cnt && !last) {
+ buf = priv->rx_buf[priv->rx_head];
+ skb = build_skb(buf, priv->rx_buf_size);
+ if (unlikely(!skb))
+ net_dbg_ratelimited("build_skb failed\n");
+
+ dma_unmap_single(&ndev->dev, priv->rx_phys[priv->rx_head],
+ RX_BUF_SIZE, DMA_FROM_DEVICE);
+ priv->rx_phys[priv->rx_head] = 0;
+
+ desc = (struct rx_desc *)skb->data;
+ len = be16_to_cpu(desc->pkt_len);
+ err = be32_to_cpu(desc->pkt_err);
+
+ if (0 == len) {
+ dev_kfree_skb_any(skb);
+ last = true;
+ } else if ((err & RX_PKT_ERR) || (len >= GMAC_MAX_PKT_LEN)) {
+ dev_kfree_skb_any(skb);
+ stats->rx_dropped++;
+ stats->rx_errors++;
+ } else {
+ skb_reserve(skb, NET_SKB_PAD + NET_IP_ALIGN);
+ skb_put(skb, len);
+ skb->protocol = eth_type_trans(skb, ndev);
+ napi_gro_receive(&priv->napi, skb);
+ stats->rx_packets++;
+ stats->rx_bytes += len;
+ rx++;
+ }
+
+ buf = netdev_alloc_frag(priv->rx_buf_size);
+ if (!buf)
+ goto done;
+ phys = dma_map_single(&ndev->dev, buf,
+ RX_BUF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&ndev->dev, phys))
+ goto done;
+ priv->rx_buf[priv->rx_head] = buf;
+ priv->rx_phys[priv->rx_head] = phys;
+ hip04_set_recv_desc(priv, phys);
+
+ priv->rx_head = RX_NEXT(priv->rx_head);
+ if (rx >= budget)
+ goto done;
+
+ if (--cnt == 0)
+ cnt = hip04_recv_cnt(priv);
+ }
+
+ if (!(priv->reg_inten & RCV_INT)) {
+ /* enable rx interrupt */
+ priv->reg_inten |= RCV_INT;
+ writel_relaxed(priv->reg_inten, priv->base + PPE_INTEN);
+ }
+ napi_complete(napi);
+done:
+ /* clean up tx descriptors and start a new timer if necessary */
+ tx_remaining = hip04_tx_reclaim(ndev, false);
+ if (rx < budget && tx_remaining)
+ hrtimer_start_expires(&priv->tx_coalesce_timer, HRTIMER_MODE_REL);
+
+ return rx;
+}
+
+static irqreturn_t hip04_mac_interrupt(int irq, void *dev_id)
+{
+ struct net_device *ndev = (struct net_device *)dev_id;
+ struct hip04_priv *priv = netdev_priv(ndev);
+ struct net_device_stats *stats = &ndev->stats;
+ u32 ists = readl_relaxed(priv->base + PPE_INTSTS);
+
+ if (!ists)
+ return IRQ_NONE;
+
+ writel_relaxed(DEF_INT_MASK, priv->base + PPE_RINT);
+
+ if (unlikely(ists & DEF_INT_ERR)) {
+ if (ists & (RCV_NOBUF | RCV_DROP)) {
+ stats->rx_errors++;
+ stats->rx_dropped++;
+ netdev_err(ndev, "rx drop\n");
+ }
+ if (ists & TX_DROP) {
+ stats->tx_dropped++;
+ netdev_err(ndev, "tx drop\n");
+ }
+ }
+
+ if (ists & RCV_INT && napi_schedule_prep(&priv->napi)) {
+ /* disable rx interrupt */
+ priv->reg_inten &= ~(RCV_INT);
+ writel_relaxed(DEF_INT_MASK & ~RCV_INT, priv->base + PPE_INTEN);
+ hrtimer_cancel(&priv->tx_coalesce_timer);
+ __napi_schedule(&priv->napi);
+ }
+
+ return IRQ_HANDLED;
+}
+
+enum hrtimer_restart tx_done(struct hrtimer *hrtimer)
+{
+ struct hip04_priv *priv;
+
+ priv = container_of(hrtimer, struct hip04_priv, tx_coalesce_timer);
+
+ if (napi_schedule_prep(&priv->napi)) {
+ /* disable rx interrupt */
+ priv->reg_inten &= ~(RCV_INT);
+ writel_relaxed(DEF_INT_MASK & ~RCV_INT, priv->base + PPE_INTEN);
+ __napi_schedule(&priv->napi);
+ }
+
+ return HRTIMER_NORESTART;
+}
+
+static void hip04_adjust_link(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ struct phy_device *phy = priv->phy;
+
+ if ((priv->speed != phy->speed) || (priv->duplex != phy->duplex)) {
+ hip04_config_port(ndev, phy->speed, phy->duplex);
+ phy_print_status(phy);
+ }
+}
+
+static int hip04_mac_open(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ int i;
+
+ priv->rx_head = 0;
+ priv->tx_head = 0;
+ priv->tx_tail = 0;
+ hip04_reset_ppe(priv);
+
+ for (i = 0; i < RX_DESC_NUM; i++) {
+ dma_addr_t phys;
+
+ phys = dma_map_single(&ndev->dev, priv->rx_buf[i],
+ RX_BUF_SIZE, DMA_FROM_DEVICE);
+ if (dma_mapping_error(&ndev->dev, phys))
+ return -EIO;
+
+ priv->rx_phys[i] = phys;
+ hip04_set_recv_desc(priv, phys);
+ }
+
+ if (priv->phy)
+ phy_start(priv->phy);
+
+ netdev_reset_queue(ndev);
+ netif_start_queue(ndev);
+ hip04_mac_enable(ndev);
+ napi_enable(&priv->napi);
+
+ return 0;
+}
+
+static int hip04_mac_stop(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ int i;
+
+ napi_disable(&priv->napi);
+ netif_stop_queue(ndev);
+ hip04_mac_disable(ndev);
+ hip04_tx_reclaim(ndev, true);
+ hip04_reset_ppe(priv);
+
+ if (priv->phy)
+ phy_stop(priv->phy);
+
+ for (i = 0; i < RX_DESC_NUM; i++) {
+ if (priv->rx_phys[i]) {
+ dma_unmap_single(&ndev->dev, priv->rx_phys[i],
+ RX_BUF_SIZE, DMA_FROM_DEVICE);
+ priv->rx_phys[i] = 0;
+ }
+ }
+
+ return 0;
+}
+
+static void hip04_timeout(struct net_device *ndev)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+
+ schedule_work(&priv->tx_timeout_task);
+}
+
+static void hip04_tx_timeout_task(struct work_struct *work)
+{
+ struct hip04_priv *priv;
+
+ priv = container_of(work, struct hip04_priv, tx_timeout_task);
+ hip04_mac_stop(priv->ndev);
+ hip04_mac_open(priv->ndev);
+}
+
+static struct net_device_stats *hip04_get_stats(struct net_device *ndev)
+{
+ return &ndev->stats;
+}
+
+static int hip04_get_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct hip04_priv *priv = netdev_priv(netdev);
+
+ ec->tx_coalesce_usecs = priv->tx_coalesce_usecs;
+ ec->tx_max_coalesced_frames = priv->tx_coalesce_frames;
+
+ return 0;
+}
+
+static int hip04_set_coalesce(struct net_device *netdev,
+ struct ethtool_coalesce *ec)
+{
+ struct hip04_priv *priv = netdev_priv(netdev);
+
+ /* Check not supported parameters */
+ if ((ec->rx_max_coalesced_frames) || (ec->rx_coalesce_usecs_irq) ||
+ (ec->rx_max_coalesced_frames_irq) || (ec->tx_coalesce_usecs_irq) ||
+ (ec->use_adaptive_rx_coalesce) || (ec->use_adaptive_tx_coalesce) ||
+ (ec->pkt_rate_low) || (ec->rx_coalesce_usecs_low) ||
+ (ec->rx_max_coalesced_frames_low) || (ec->tx_coalesce_usecs_high) ||
+ (ec->tx_max_coalesced_frames_low) || (ec->pkt_rate_high) ||
+ (ec->tx_coalesce_usecs_low) || (ec->rx_coalesce_usecs_high) ||
+ (ec->rx_max_coalesced_frames_high) || (ec->rx_coalesce_usecs) ||
+ (ec->tx_max_coalesced_frames_irq) ||
+ (ec->stats_block_coalesce_usecs) ||
+ (ec->tx_max_coalesced_frames_high) || (ec->rate_sample_interval))
+ return -EOPNOTSUPP;
+
+ if ((ec->tx_coalesce_usecs > HIP04_MAX_TX_COALESCE_USECS ||
+ ec->tx_coalesce_usecs < HIP04_MIN_TX_COALESCE_USECS) ||
+ (ec->tx_max_coalesced_frames > HIP04_MAX_TX_COALESCE_FRAMES ||
+ ec->tx_max_coalesced_frames < HIP04_MIN_TX_COALESCE_FRAMES))
+ return -EINVAL;
+
+ priv->tx_coalesce_usecs = ec->tx_coalesce_usecs;
+ priv->tx_coalesce_frames = ec->tx_max_coalesced_frames;
+
+ return 0;
+}
+
+static void hip04_get_drvinfo(struct net_device *netdev,
+ struct ethtool_drvinfo *drvinfo)
+{
+ strlcpy(drvinfo->driver, DRV_NAME, sizeof(drvinfo->driver));
+ strlcpy(drvinfo->version, DRV_VERSION, sizeof(drvinfo->version));
+}
+
+static struct ethtool_ops hip04_ethtool_ops = {
+ .get_coalesce = hip04_get_coalesce,
+ .set_coalesce = hip04_set_coalesce,
+ .get_drvinfo = hip04_get_drvinfo,
+};
+
+static struct net_device_ops hip04_netdev_ops = {
+ .ndo_open = hip04_mac_open,
+ .ndo_stop = hip04_mac_stop,
+ .ndo_get_stats = hip04_get_stats,
+ .ndo_start_xmit = hip04_mac_start_xmit,
+ .ndo_set_mac_address = hip04_set_mac_address,
+ .ndo_tx_timeout = hip04_timeout,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_change_mtu = eth_change_mtu,
+};
+
+static int hip04_alloc_ring(struct net_device *ndev, struct device *d)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ int i;
+
+ priv->tx_desc = dma_alloc_coherent(d,
+ TX_DESC_NUM * sizeof(struct tx_desc),
+ &priv->tx_desc_dma, GFP_KERNEL);
+ if (!priv->tx_desc)
+ return -ENOMEM;
+
+ priv->rx_buf_size = RX_BUF_SIZE +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+ for (i = 0; i < RX_DESC_NUM; i++) {
+ priv->rx_buf[i] = netdev_alloc_frag(priv->rx_buf_size);
+ if (!priv->rx_buf[i])
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+static void hip04_free_ring(struct net_device *ndev, struct device *d)
+{
+ struct hip04_priv *priv = netdev_priv(ndev);
+ int i;
+
+ for (i = 0; i < RX_DESC_NUM; i++)
+ if (priv->rx_buf[i])
+ put_page(virt_to_head_page(priv->rx_buf[i]));
+
+ for (i = 0; i < TX_DESC_NUM; i++)
+ if (priv->tx_skb[i])
+ dev_kfree_skb_any(priv->tx_skb[i]);
+
+ dma_free_coherent(d, TX_DESC_NUM * sizeof(struct tx_desc),
+ priv->tx_desc, priv->tx_desc_dma);
+}
+
+static int hip04_mac_probe(struct platform_device *pdev)
+{
+ struct device *d = &pdev->dev;
+ struct device_node *node = d->of_node;
+ struct of_phandle_args arg;
+ struct net_device *ndev;
+ struct hip04_priv *priv;
+ struct resource *res;
+ unsigned int irq;
+ ktime_t txtime;
+ int ret;
+
+ ndev = alloc_etherdev(sizeof(struct hip04_priv));
+ if (!ndev)
+ return -ENOMEM;
+
+ priv = netdev_priv(ndev);
+ priv->ndev = ndev;
+ platform_set_drvdata(pdev, ndev);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(d, res);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
+ goto init_fail;
+ }
+
+ ret = of_parse_phandle_with_fixed_args(node, "port-handle", 2, 0, &arg);
+ if (ret < 0) {
+ dev_warn(d, "no port-handle\n");
+ goto init_fail;
+ }
+
+ priv->port = arg.args[0];
+ priv->chan = arg.args[1] * RX_DESC_NUM;
+
+ hrtimer_init(&priv->tx_coalesce_timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
+
+ /* BQL will try to keep the TX queue as short as possible, but it can't
+ * be faster than tx_coalesce_usecs, so we need a fast timeout here,
+ * but also long enough to gather up enough frames to ensure we don't
+ * get more interrupts than necessary.
+ * 200us is enough for 16 frames of 1500 bytes at gigabit ethernet rate
+ */
+ priv->tx_coalesce_frames = TX_DESC_NUM * 3 / 4;
+ priv->tx_coalesce_usecs = 200;
+ /* allow timer to fire after half the time at the earliest */
+ txtime = ktime_set(0, priv->tx_coalesce_usecs * NSEC_PER_USEC / 2);
+ hrtimer_set_expires_range(&priv->tx_coalesce_timer, txtime, txtime);
+ priv->tx_coalesce_timer.function = tx_done;
+
+ priv->map = syscon_node_to_regmap(arg.np);
+ if (IS_ERR(priv->map)) {
+ dev_warn(d, "no syscon hisilicon,hip04-ppe\n");
+ ret = PTR_ERR(priv->map);
+ goto init_fail;
+ }
+
+ priv->phy_mode = of_get_phy_mode(node);
+ if (priv->phy_mode < 0) {
+ dev_warn(d, "not find phy-mode\n");
+ ret = -EINVAL;
+ goto init_fail;
+ }
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq <= 0) {
+ ret = -EINVAL;
+ goto init_fail;
+ }
+
+ ret = devm_request_irq(d, irq, hip04_mac_interrupt,
+ 0, pdev->name, ndev);
+ if (ret) {
+ netdev_err(ndev, "devm_request_irq failed\n");
+ goto init_fail;
+ }
+
+ priv->phy_node = of_parse_phandle(node, "phy-handle", 0);
+ if (priv->phy_node) {
+ priv->phy = of_phy_connect(ndev, priv->phy_node,
+ &hip04_adjust_link,
+ 0, priv->phy_mode);
+ if (!priv->phy) {
+ ret = -EPROBE_DEFER;
+ goto init_fail;
+ }
+ }
+
+ INIT_WORK(&priv->tx_timeout_task, hip04_tx_timeout_task);
+
+ ether_setup(ndev);
+ ndev->netdev_ops = &hip04_netdev_ops;
+ ndev->ethtool_ops = &hip04_ethtool_ops;
+ ndev->watchdog_timeo = TX_TIMEOUT;
+ ndev->priv_flags |= IFF_UNICAST_FLT;
+ ndev->irq = irq;
+ netif_napi_add(ndev, &priv->napi, hip04_rx_poll, NAPI_POLL_WEIGHT);
+ SET_NETDEV_DEV(ndev, &pdev->dev);
+
+ hip04_reset_ppe(priv);
+ if (priv->phy_mode == PHY_INTERFACE_MODE_MII)
+ hip04_config_port(ndev, SPEED_100, DUPLEX_FULL);
+
+ hip04_config_fifo(priv);
+ random_ether_addr(ndev->dev_addr);
+ hip04_update_mac_address(ndev);
+
+ ret = hip04_alloc_ring(ndev, d);
+ if (ret) {
+ netdev_err(ndev, "alloc ring fail\n");
+ goto alloc_fail;
+ }
+
+ ret = register_netdev(ndev);
+ if (ret) {
+ free_netdev(ndev);
+ goto alloc_fail;
+ }
+
+ return 0;
+
+alloc_fail:
+ hip04_free_ring(ndev, d);
+init_fail:
+ of_node_put(priv->phy_node);
+ free_netdev(ndev);
+ return ret;
+}
+
+static int hip04_remove(struct platform_device *pdev)
+{
+ struct net_device *ndev = platform_get_drvdata(pdev);
+ struct hip04_priv *priv = netdev_priv(ndev);
+ struct device *d = &pdev->dev;
+
+ if (priv->phy)
+ phy_disconnect(priv->phy);
+
+ hip04_free_ring(ndev, d);
+ unregister_netdev(ndev);
+ free_irq(ndev->irq, ndev);
+ of_node_put(priv->phy_node);
+ cancel_work_sync(&priv->tx_timeout_task);
+ free_netdev(ndev);
+
+ return 0;
+}
+
+static const struct of_device_id hip04_mac_match[] = {
+ { .compatible = "hisilicon,hip04-mac" },
+ { }
+};
+
+MODULE_DEVICE_TABLE(of, hip04_mac_match);
+
+static struct platform_driver hip04_mac_driver = {
+ .probe = hip04_mac_probe,
+ .remove = hip04_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = hip04_mac_match,
+ },
+};
+module_platform_driver(hip04_mac_driver);
+
+MODULE_DESCRIPTION("HISILICON P04 Ethernet driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/hisilicon/hip04_mdio.c b/drivers/net/ethernet/hisilicon/hip04_mdio.c
new file mode 100644
index 000000000000..b3bac25db99c
--- /dev/null
+++ b/drivers/net/ethernet/hisilicon/hip04_mdio.c
@@ -0,0 +1,186 @@
+/* Copyright (c) 2014 Linaro Ltd.
+ * Copyright (c) 2014 Hisilicon Limited.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/of_mdio.h>
+#include <linux/delay.h>
+
+#define MDIO_CMD_REG 0x0
+#define MDIO_ADDR_REG 0x4
+#define MDIO_WDATA_REG 0x8
+#define MDIO_RDATA_REG 0xc
+#define MDIO_STA_REG 0x10
+
+#define MDIO_START BIT(14)
+#define MDIO_R_VALID BIT(1)
+#define MDIO_READ (BIT(12) | BIT(11) | MDIO_START)
+#define MDIO_WRITE (BIT(12) | BIT(10) | MDIO_START)
+
+struct hip04_mdio_priv {
+ void __iomem *base;
+};
+
+#define WAIT_TIMEOUT 10
+static int hip04_mdio_wait_ready(struct mii_bus *bus)
+{
+ struct hip04_mdio_priv *priv = bus->priv;
+ int i;
+
+ for (i = 0; readl_relaxed(priv->base + MDIO_CMD_REG) & MDIO_START; i++) {
+ if (i == WAIT_TIMEOUT)
+ return -ETIMEDOUT;
+ msleep(20);
+ }
+
+ return 0;
+}
+
+static int hip04_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+ struct hip04_mdio_priv *priv = bus->priv;
+ u32 val;
+ int ret;
+
+ ret = hip04_mdio_wait_ready(bus);
+ if (ret < 0)
+ goto out;
+
+ val = regnum | (mii_id << 5) | MDIO_READ;
+ writel_relaxed(val, priv->base + MDIO_CMD_REG);
+
+ ret = hip04_mdio_wait_ready(bus);
+ if (ret < 0)
+ goto out;
+
+ val = readl_relaxed(priv->base + MDIO_STA_REG);
+ if (val & MDIO_R_VALID) {
+ dev_err(bus->parent, "SMI bus read not valid\n");
+ ret = -ENODEV;
+ goto out;
+ }
+
+ val = readl_relaxed(priv->base + MDIO_RDATA_REG);
+ ret = val & 0xFFFF;
+out:
+ return ret;
+}
+
+static int hip04_mdio_write(struct mii_bus *bus, int mii_id,
+ int regnum, u16 value)
+{
+ struct hip04_mdio_priv *priv = bus->priv;
+ u32 val;
+ int ret;
+
+ ret = hip04_mdio_wait_ready(bus);
+ if (ret < 0)
+ goto out;
+
+ writel_relaxed(value, priv->base + MDIO_WDATA_REG);
+ val = regnum | (mii_id << 5) | MDIO_WRITE;
+ writel_relaxed(val, priv->base + MDIO_CMD_REG);
+out:
+ return ret;
+}
+
+static int hip04_mdio_reset(struct mii_bus *bus)
+{
+ int temp, i;
+
+ for (i = 0; i < PHY_MAX_ADDR; i++) {
+ hip04_mdio_write(bus, i, 22, 0);
+ temp = hip04_mdio_read(bus, i, MII_BMCR);
+ if (temp < 0)
+ continue;
+
+ temp |= BMCR_RESET;
+ if (hip04_mdio_write(bus, i, MII_BMCR, temp) < 0)
+ continue;
+ }
+
+ mdelay(500);
+ return 0;
+}
+
+static int hip04_mdio_probe(struct platform_device *pdev)
+{
+ struct resource *r;
+ struct mii_bus *bus;
+ struct hip04_mdio_priv *priv;
+ int ret;
+
+ bus = mdiobus_alloc_size(sizeof(struct hip04_mdio_priv));
+ if (!bus) {
+ dev_err(&pdev->dev, "Cannot allocate MDIO bus\n");
+ return -ENOMEM;
+ }
+
+ bus->name = "hip04_mdio_bus";
+ bus->read = hip04_mdio_read;
+ bus->write = hip04_mdio_write;
+ bus->reset = hip04_mdio_reset;
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-mii", dev_name(&pdev->dev));
+ bus->parent = &pdev->dev;
+ priv = bus->priv;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->base = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(priv->base)) {
+ ret = PTR_ERR(priv->base);
+ goto out_mdio;
+ }
+
+ ret = of_mdiobus_register(bus, pdev->dev.of_node);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Cannot register MDIO bus (%d)\n", ret);
+ goto out_mdio;
+ }
+
+ platform_set_drvdata(pdev, bus);
+
+ return 0;
+
+out_mdio:
+ mdiobus_free(bus);
+ return ret;
+}
+
+static int hip04_mdio_remove(struct platform_device *pdev)
+{
+ struct mii_bus *bus = platform_get_drvdata(pdev);
+
+ mdiobus_unregister(bus);
+ mdiobus_free(bus);
+
+ return 0;
+}
+
+static const struct of_device_id hip04_mdio_match[] = {
+ { .compatible = "hisilicon,hip04-mdio" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, hip04_mdio_match);
+
+static struct platform_driver hip04_mdio_driver = {
+ .probe = hip04_mdio_probe,
+ .remove = hip04_mdio_remove,
+ .driver = {
+ .name = "hip04-mdio",
+ .owner = THIS_MODULE,
+ .of_match_table = hip04_mdio_match,
+ },
+};
+
+module_platform_driver(hip04_mdio_driver);
+
+MODULE_DESCRIPTION("HISILICON P04 MDIO interface driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:hip04-mdio");
diff --git a/drivers/net/ethernet/ibm/ehea/ehea_main.c b/drivers/net/ethernet/ibm/ehea/ehea_main.c
index 566b17db135a..e8a1adb7a962 100644
--- a/drivers/net/ethernet/ibm/ehea/ehea_main.c
+++ b/drivers/net/ethernet/ibm/ehea/ehea_main.c
@@ -2064,9 +2064,9 @@ static int ehea_start_xmit(struct sk_buff *skb, struct net_device *dev)
memset(swqe, 0, SWQE_HEADER_SIZE);
atomic_dec(&pr->swqe_avail);
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
swqe->tx_control |= EHEA_SWQE_VLAN_INSERT;
- swqe->vlan_tag = vlan_tx_tag_get(skb);
+ swqe->vlan_tag = skb_vlan_tag_get(skb);
}
pr->tx_packets++;
diff --git a/drivers/net/ethernet/ibm/emac/core.c b/drivers/net/ethernet/ibm/emac/core.c
index 9388a83818f2..162762d1a12c 100644
--- a/drivers/net/ethernet/ibm/emac/core.c
+++ b/drivers/net/ethernet/ibm/emac/core.c
@@ -2367,7 +2367,7 @@ static int emac_wait_deps(struct emac_instance *dev)
err = emac_check_deps(dev, deps) ? 0 : -ENODEV;
for (i = 0; i < EMAC_DEP_COUNT; i++) {
of_node_put(deps[i].node);
- if (err && deps[i].ofdev)
+ if (err)
of_dev_put(deps[i].ofdev);
}
if (err == 0) {
diff --git a/drivers/net/ethernet/intel/Kconfig b/drivers/net/ethernet/intel/Kconfig
index 4d61ef50b465..f4ff465584a0 100644
--- a/drivers/net/ethernet/intel/Kconfig
+++ b/drivers/net/ethernet/intel/Kconfig
@@ -192,6 +192,17 @@ config IXGBE
To compile this driver as a module, choose M here. The module
will be called ixgbe.
+config IXGBE_VXLAN
+ bool "Virtual eXtensible Local Area Network Support"
+ default n
+ depends on IXGBE && VXLAN && !(IXGBE=y && VXLAN=m)
+ ---help---
+ This allows one to create VXLAN virtual interfaces that provide
+ Layer 2 Networks over Layer 3 Networks. VXLAN is often used
+ to tunnel virtual network infrastructure in virtualized environments.
+ Say Y here if you want to use Virtual eXtensible Local Area Network
+ (VXLAN) in the driver.
+
config IXGBE_HWMON
bool "Intel(R) 10GbE PCI Express adapters HWMON support"
default y
diff --git a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
index b691eb4f6376..4270ad2d4ddf 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_ethtool.c
@@ -24,6 +24,7 @@
/* ethtool support for e1000 */
#include "e1000.h"
+#include <linux/jiffies.h>
#include <linux/uaccess.h>
enum {NETDEV_STATS, E1000_STATS};
@@ -1460,7 +1461,7 @@ static int e1000_run_loopback_test(struct e1000_adapter *adapter)
ret_val = 13; /* ret_val is the same as mis-compare */
break;
}
- if (jiffies >= (time + 2)) {
+ if (time_after_eq(jiffies, time + 2)) {
ret_val = 14; /* error code for time out error */
break;
}
diff --git a/drivers/net/ethernet/intel/e1000/e1000_main.c b/drivers/net/ethernet/intel/e1000/e1000_main.c
index 83140cbb5f01..7f997d36948f 100644
--- a/drivers/net/ethernet/intel/e1000/e1000_main.c
+++ b/drivers/net/ethernet/intel/e1000/e1000_main.c
@@ -2977,7 +2977,6 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
struct e1000_tx_ring *tx_ring, int tx_flags,
int count)
{
- struct e1000_hw *hw = &adapter->hw;
struct e1000_tx_desc *tx_desc = NULL;
struct e1000_tx_buffer *buffer_info;
u32 txd_upper = 0, txd_lower = E1000_TXD_CMD_IFCS;
@@ -3031,11 +3030,6 @@ static void e1000_tx_queue(struct e1000_adapter *adapter,
wmb();
tx_ring->next_to_use = i;
- writel(i, hw->hw_addr + tx_ring->tdt);
- /* we need this if more than one processor can write to our tail
- * at a time, it synchronizes IO on IA64/Altix systems
- */
- mmiowb();
}
/* 82547 workaround to avoid controller hang in half-duplex environment.
@@ -3226,9 +3220,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
tx_flags |= E1000_TX_FLAGS_VLAN;
- tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+ tx_flags |= (skb_vlan_tag_get(skb) <<
+ E1000_TX_FLAGS_VLAN_SHIFT);
}
first = tx_ring->next_to_use;
@@ -3263,6 +3258,15 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
/* Make sure there is space in the ring for the next send. */
e1000_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 2);
+ if (!skb->xmit_more ||
+ netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) {
+ writel(tx_ring->next_to_use, hw->hw_addr + tx_ring->tdt);
+ /* we need this if more than one processor can write to
+ * our tail at a time, it synchronizes IO on IA64/Altix
+ * systems
+ */
+ mmiowb();
+ }
} else {
dev_kfree_skb_any(skb);
tx_ring->buffer_info[first].time_stamp = 0;
diff --git a/drivers/net/ethernet/intel/e1000e/e1000.h b/drivers/net/ethernet/intel/e1000e/e1000.h
index 7785240a0da1..9416e5a7e0c8 100644
--- a/drivers/net/ethernet/intel/e1000e/e1000.h
+++ b/drivers/net/ethernet/intel/e1000e/e1000.h
@@ -34,7 +34,7 @@
#include <linux/pci-aspm.h>
#include <linux/crc32.h>
#include <linux/if_vlan.h>
-#include <linux/clocksource.h>
+#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/ptp_classify.h>
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index e14fd85f64eb..1e8c40fd5c3d 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -4189,7 +4189,7 @@ static int e1000_sw_init(struct e1000_adapter *adapter)
/* Setup hardware time stamping cyclecounter */
if (adapter->flags & FLAG_HAS_HW_TIMESTAMP) {
adapter->cc.read = e1000e_cyclecounter_read;
- adapter->cc.mask = CLOCKSOURCE_MASK(64);
+ adapter->cc.mask = CYCLECOUNTER_MASK(64);
adapter->cc.mult = 1;
/* cc.shift set in e1000e_get_base_tininca() */
@@ -5444,16 +5444,6 @@ static void e1000_tx_queue(struct e1000_ring *tx_ring, int tx_flags, int count)
wmb();
tx_ring->next_to_use = i;
-
- if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
- e1000e_update_tdt_wa(tx_ring, i);
- else
- writel(i, tx_ring->tail);
-
- /* we need this if more than one processor can write to our tail
- * at a time, it synchronizes IO on IA64/Altix systems
- */
- mmiowb();
}
#define MINIMUM_DHCP_PACKET_SIZE 282
@@ -5463,8 +5453,8 @@ static int e1000_transfer_dhcp_info(struct e1000_adapter *adapter,
struct e1000_hw *hw = &adapter->hw;
u16 length, offset;
- if (vlan_tx_tag_present(skb) &&
- !((vlan_tx_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
+ if (skb_vlan_tag_present(skb) &&
+ !((skb_vlan_tag_get(skb) == adapter->hw.mng_cookie.vlan_id) &&
(adapter->hw.mng_cookie.status &
E1000_MNG_DHCP_COOKIE_STATUS_VLAN)))
return 0;
@@ -5603,9 +5593,10 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
if (e1000_maybe_stop_tx(tx_ring, count + 2))
return NETDEV_TX_BUSY;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
tx_flags |= E1000_TX_FLAGS_VLAN;
- tx_flags |= (vlan_tx_tag_get(skb) << E1000_TX_FLAGS_VLAN_SHIFT);
+ tx_flags |= (skb_vlan_tag_get(skb) <<
+ E1000_TX_FLAGS_VLAN_SHIFT);
}
first = tx_ring->next_to_use;
@@ -5635,8 +5626,9 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
count = e1000_tx_map(tx_ring, skb, first, adapter->tx_fifo_limit,
nr_frags);
if (count) {
- if (unlikely((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
- !adapter->tx_hwtstamp_skb)) {
+ if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
+ (adapter->flags & FLAG_HAS_HW_TIMESTAMP) &&
+ !adapter->tx_hwtstamp_skb) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
tx_flags |= E1000_TX_FLAGS_HWTSTAMP;
adapter->tx_hwtstamp_skb = skb_get(skb);
@@ -5653,6 +5645,21 @@ static netdev_tx_t e1000_xmit_frame(struct sk_buff *skb,
(MAX_SKB_FRAGS *
DIV_ROUND_UP(PAGE_SIZE,
adapter->tx_fifo_limit) + 2));
+
+ if (!skb->xmit_more ||
+ netif_xmit_stopped(netdev_get_tx_queue(netdev, 0))) {
+ if (adapter->flags2 & FLAG2_PCIM2PCI_ARBITER_WA)
+ e1000e_update_tdt_wa(tx_ring,
+ tx_ring->next_to_use);
+ else
+ writel(tx_ring->next_to_use, tx_ring->tail);
+
+ /* we need this if more than one processor can write
+ * to our tail at a time, it synchronizes IO on
+ *IA64/Altix systems
+ */
+ mmiowb();
+ }
} else {
dev_kfree_skb_any(skb);
tx_ring->buffer_info[first].time_stamp = 0;
diff --git a/drivers/net/ethernet/intel/e1000e/ptp.c b/drivers/net/ethernet/intel/e1000e/ptp.c
index fb1a914a3ad4..978ef9c4a043 100644
--- a/drivers/net/ethernet/intel/e1000e/ptp.c
+++ b/drivers/net/ethernet/intel/e1000e/ptp.c
@@ -90,12 +90,9 @@ static int e1000e_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
struct e1000_adapter *adapter = container_of(ptp, struct e1000_adapter,
ptp_clock_info);
unsigned long flags;
- s64 now;
spin_lock_irqsave(&adapter->systim_lock, flags);
- now = timecounter_read(&adapter->tc);
- now += delta;
- timecounter_init(&adapter->tc, &adapter->cc, now);
+ timecounter_adjtime(&adapter->tc, delta);
spin_unlock_irqrestore(&adapter->systim_lock, flags);
return 0;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_main.c b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
index eb088b129bc7..84ab9eea2768 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_main.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_main.c
@@ -97,7 +97,6 @@ static bool fm10k_alloc_mapped_page(struct fm10k_ring *rx_ring,
*/
if (dma_mapping_error(rx_ring->dev, dma)) {
__free_page(page);
- bi->page = NULL;
rx_ring->rx_stats.alloc_failed++;
return false;
@@ -147,8 +146,8 @@ void fm10k_alloc_rx_buffers(struct fm10k_ring *rx_ring, u16 cleaned_count)
i -= rx_ring->count;
}
- /* clear the hdr_addr for the next_to_use descriptor */
- rx_desc->q.hdr_addr = 0;
+ /* clear the status bits for the next_to_use descriptor */
+ rx_desc->d.staterr = 0;
cleaned_count--;
} while (cleaned_count);
@@ -194,7 +193,7 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring,
rx_ring->next_to_alloc = (nta < rx_ring->count) ? nta : 0;
/* transfer page from old buffer to new buffer */
- memcpy(new_buff, old_buff, sizeof(struct fm10k_rx_buffer));
+ *new_buff = *old_buff;
/* sync the buffer for use by the device */
dma_sync_single_range_for_device(rx_ring->dev, old_buff->dma,
@@ -203,12 +202,17 @@ static void fm10k_reuse_rx_page(struct fm10k_ring *rx_ring,
DMA_FROM_DEVICE);
}
+static inline bool fm10k_page_is_reserved(struct page *page)
+{
+ return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+}
+
static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer,
struct page *page,
unsigned int truesize)
{
/* avoid re-using remote pages */
- if (unlikely(page_to_nid(page) != numa_mem_id()))
+ if (unlikely(fm10k_page_is_reserved(page)))
return false;
#if (PAGE_SIZE < 8192)
@@ -218,22 +222,19 @@ static bool fm10k_can_reuse_rx_page(struct fm10k_rx_buffer *rx_buffer,
/* flip page offset to other buffer */
rx_buffer->page_offset ^= FM10K_RX_BUFSZ;
-
- /* Even if we own the page, we are not allowed to use atomic_set()
- * This would break get_page_unless_zero() users.
- */
- atomic_inc(&page->_count);
#else
/* move offset up to the next cache line */
rx_buffer->page_offset += truesize;
if (rx_buffer->page_offset > (PAGE_SIZE - FM10K_RX_BUFSZ))
return false;
-
- /* bump ref count on page before it is given to the stack */
- get_page(page);
#endif
+ /* Even if we own the page, we are not allowed to use atomic_set()
+ * This would break get_page_unless_zero() users.
+ */
+ atomic_inc(&page->_count);
+
return true;
}
@@ -270,12 +271,12 @@ static bool fm10k_add_rx_frag(struct fm10k_ring *rx_ring,
memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
- /* we can reuse buffer as-is, just make sure it is local */
- if (likely(page_to_nid(page) == numa_mem_id()))
+ /* page is not reserved, we can reuse buffer as-is */
+ if (likely(!fm10k_page_is_reserved(page)))
return true;
/* this page cannot be reused so discard it */
- put_page(page);
+ __free_page(page);
return false;
}
@@ -293,7 +294,6 @@ static struct sk_buff *fm10k_fetch_rx_buffer(struct fm10k_ring *rx_ring,
struct page *page;
rx_buffer = &rx_ring->rx_buffer[rx_ring->next_to_clean];
-
page = rx_buffer->page;
prefetchw(page);
@@ -727,6 +727,12 @@ static __be16 fm10k_tx_encap_offload(struct sk_buff *skb)
struct ethhdr *eth_hdr;
u8 l4_hdr = 0;
+/* fm10k supports 184 octets of outer+inner headers. Minus 20 for inner L4. */
+#define FM10K_MAX_ENCAP_TRANSPORT_OFFSET 164
+ if (skb_inner_transport_header(skb) - skb_mac_header(skb) >
+ FM10K_MAX_ENCAP_TRANSPORT_OFFSET)
+ return 0;
+
switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
l4_hdr = ip_hdr(skb)->protocol;
@@ -965,8 +971,8 @@ static void fm10k_tx_map(struct fm10k_ring *tx_ring,
tx_desc = FM10K_TX_DESC(tx_ring, i);
/* add HW VLAN tag */
- if (vlan_tx_tag_present(skb))
- tx_desc->vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+ if (skb_vlan_tag_present(skb))
+ tx_desc->vlan = cpu_to_le16(skb_vlan_tag_get(skb));
else
tx_desc->vlan = 0;
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
index 14a4ea795c01..9f5457c9e627 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_mbx.c
@@ -1194,12 +1194,11 @@ static s32 fm10k_mbx_process_disconnect(struct fm10k_hw *hw,
{
const enum fm10k_mbx_state state = mbx->state;
const u32 *hdr = &mbx->mbx_hdr;
- u16 head, tail;
+ u16 head;
s32 err;
- /* we will need to pull all of the fields for verification */
+ /* we will need to pull the header field for verification */
head = FM10K_MSG_HDR_FIELD_GET(*hdr, HEAD);
- tail = FM10K_MSG_HDR_FIELD_GET(*hdr, TAIL);
/* We should not be receiving disconnect if Rx is incomplete */
if (mbx->pushed)
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
index 8811364b91cb..cfde8bac1aeb 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_netdev.c
@@ -609,7 +609,7 @@ static netdev_tx_t fm10k_xmit_frame(struct sk_buff *skb, struct net_device *dev)
int err;
if ((skb->protocol == htons(ETH_P_8021Q)) &&
- !vlan_tx_tag_present(skb)) {
+ !skb_vlan_tag_present(skb)) {
/* FM10K only supports hardware tagging, any tags in frame
* are considered 2nd level or "outer" tags
*/
@@ -1414,13 +1414,12 @@ struct net_device *fm10k_alloc_netdev(void)
dev->vlan_features |= dev->features;
/* configure tunnel offloads */
- dev->hw_enc_features = NETIF_F_IP_CSUM |
- NETIF_F_TSO |
- NETIF_F_TSO6 |
- NETIF_F_TSO_ECN |
- NETIF_F_GSO_UDP_TUNNEL |
- NETIF_F_IPV6_CSUM |
- NETIF_F_SG;
+ dev->hw_enc_features |= NETIF_F_IP_CSUM |
+ NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_TSO_ECN |
+ NETIF_F_GSO_UDP_TUNNEL |
+ NETIF_F_IPV6_CSUM;
/* we want to leave these both on as we cannot disable VLAN tag
* insertion or stripping on the hardware since it is contained
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
index 275423d4f777..7e4711958e46 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_pf.c
@@ -330,13 +330,10 @@ static s32 fm10k_update_xc_addr_pf(struct fm10k_hw *hw, u16 glort,
struct fm10k_mac_update mac_update;
u32 msg[5];
- /* if glort is not valid return error */
- if (!fm10k_glort_valid_pf(hw, glort))
+ /* if glort or vlan are not valid return error */
+ if (!fm10k_glort_valid_pf(hw, glort) || vid >= FM10K_VLAN_TABLE_VID_MAX)
return FM10K_ERR_PARAM;
- /* drop upper 4 bits of VLAN ID */
- vid = (vid << 4) >> 4;
-
/* record fields */
mac_update.mac_lower = cpu_to_le32(((u32)mac[2] << 24) |
((u32)mac[3] << 16) |
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c
index 7822809436a3..d966044e017a 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_ptp.c
@@ -57,7 +57,6 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb)
struct sk_buff_head *list = &interface->ts_tx_skb_queue;
struct sk_buff *clone;
unsigned long flags;
- __le16 dglort;
/* create clone for us to return on the Tx path */
clone = skb_clone_sk(skb);
@@ -65,8 +64,6 @@ void fm10k_ts_tx_enqueue(struct fm10k_intfc *interface, struct sk_buff *skb)
return;
FM10K_CB(clone)->ts_tx_timeout = jiffies + FM10K_TS_TX_TIMEOUT;
- dglort = FM10K_CB(clone)->fi.w.dglort;
-
spin_lock_irqsave(&list->lock, flags);
/* attempt to locate any buffers with the same dglort,
diff --git a/drivers/net/ethernet/intel/fm10k/fm10k_type.h b/drivers/net/ethernet/intel/fm10k/fm10k_type.h
index 280296f29154..7c6d9d5a8ae5 100644
--- a/drivers/net/ethernet/intel/fm10k/fm10k_type.h
+++ b/drivers/net/ethernet/intel/fm10k/fm10k_type.h
@@ -354,7 +354,7 @@ struct fm10k_hw;
/* Define timeouts for resets and disables */
#define FM10K_QUEUE_DISABLE_TIMEOUT 100
-#define FM10K_RESET_TIMEOUT 100
+#define FM10K_RESET_TIMEOUT 150
/* VF registers */
#define FM10K_VFCTRL 0x00000
diff --git a/drivers/net/ethernet/intel/i40e/i40e.h b/drivers/net/ethernet/intel/i40e/i40e.h
index fc50f6461b13..2b65cdcad6ba 100644
--- a/drivers/net/ethernet/intel/i40e/i40e.h
+++ b/drivers/net/ethernet/intel/i40e/i40e.h
@@ -87,11 +87,12 @@
#define I40E_MINIMUM_FCOE 1 /* minimum number of QPs for FCoE */
#endif /* I40E_FCOE */
#define I40E_MAX_AQ_BUF_SIZE 4096
-#define I40E_AQ_LEN 128
-#define I40E_AQ_WORK_LIMIT 16
+#define I40E_AQ_LEN 256
+#define I40E_AQ_WORK_LIMIT 32
#define I40E_MAX_USER_PRIORITY 8
#define I40E_DEFAULT_MSG_ENABLE 4
#define I40E_QUEUE_WAIT_RETRY_LIMIT 10
+#define I40E_INT_NAME_STR_LEN (IFNAMSIZ + 9)
#define I40E_NVM_VERSION_LO_SHIFT 0
#define I40E_NVM_VERSION_LO_MASK (0xff << I40E_NVM_VERSION_LO_SHIFT)
@@ -147,6 +148,7 @@ enum i40e_state_t {
__I40E_FD_FLUSH_REQUESTED,
__I40E_RESET_FAILED,
__I40E_PORT_TX_SUSPENDED,
+ __I40E_VF_DISABLE,
};
enum i40e_interrupt_policy {
@@ -268,7 +270,7 @@ struct i40e_pf {
u16 rx_itr_default;
u16 tx_itr_default;
u16 msg_enable;
- char misc_int_name[IFNAMSIZ + 9];
+ char int_name[I40E_INT_NAME_STR_LEN];
u16 adminq_work_limit; /* num of admin receive queue desc to process */
unsigned long service_timer_period;
unsigned long service_timer_previous;
@@ -524,7 +526,7 @@ struct i40e_q_vector {
cpumask_t affinity_mask;
struct rcu_head rcu; /* to avoid race with update stats on free */
- char name[IFNAMSIZ + 9];
+ char name[I40E_INT_NAME_STR_LEN];
} ____cacheline_internodealigned_in_smp;
/* lan device */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq.h b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
index 564d0b0192f7..de17b6fbcc4e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq.h
@@ -148,7 +148,7 @@ static inline int i40e_aq_rc_to_posix(u32 aq_ret, u16 aq_rc)
/* general information */
#define I40E_AQ_LARGE_BUF 512
-#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */
+#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */
void i40e_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
u16 opcode);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
index 8835aeeff23e..929e3d72a01e 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_adminq_cmd.h
@@ -256,6 +256,8 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_lldp_stop = 0x0A05,
i40e_aqc_opc_lldp_start = 0x0A06,
i40e_aqc_opc_get_cee_dcb_cfg = 0x0A07,
+ i40e_aqc_opc_lldp_set_local_mib = 0x0A08,
+ i40e_aqc_opc_lldp_stop_start_spec_agent = 0x0A09,
/* Tunnel commands */
i40e_aqc_opc_add_udp_tunnel = 0x0B00,
@@ -268,6 +270,8 @@ enum i40e_admin_queue_opc {
/* OEM commands */
i40e_aqc_opc_oem_parameter_change = 0xFE00,
i40e_aqc_opc_oem_device_status_change = 0xFE01,
+ i40e_aqc_opc_oem_ocsd_initialize = 0xFE02,
+ i40e_aqc_opc_oem_ocbb_initialize = 0xFE03,
/* debug commands */
i40e_aqc_opc_debug_get_deviceid = 0xFF00,
@@ -276,7 +280,6 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_debug_write_reg = 0xFF04,
i40e_aqc_opc_debug_modify_reg = 0xFF07,
i40e_aqc_opc_debug_dump_internals = 0xFF08,
- i40e_aqc_opc_debug_modify_internals = 0xFF09,
};
/* command structures and indirect data structures */
@@ -410,6 +413,7 @@ struct i40e_aqc_list_capabilities_element_resp {
#define I40E_AQ_CAP_ID_VSI 0x0017
#define I40E_AQ_CAP_ID_DCB 0x0018
#define I40E_AQ_CAP_ID_FCOE 0x0021
+#define I40E_AQ_CAP_ID_ISCSI 0x0022
#define I40E_AQ_CAP_ID_RSS 0x0040
#define I40E_AQ_CAP_ID_RXQ 0x0041
#define I40E_AQ_CAP_ID_TXQ 0x0042
@@ -454,8 +458,11 @@ struct i40e_aqc_arp_proxy_data {
__le32 pfpm_proxyfc;
__le32 ip_addr;
u8 mac_addr[6];
+ u8 reserved[2];
};
+I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data);
+
/* Set NS Proxy Table Entry Command (indirect 0x0105) */
struct i40e_aqc_ns_proxy_data {
__le16 table_idx_mac_addr_0;
@@ -481,6 +488,8 @@ struct i40e_aqc_ns_proxy_data {
u8 ipv6_addr_1[16];
};
+I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data);
+
/* Manage LAA Command (0x0106) - obsolete */
struct i40e_aqc_mng_laa {
__le16 command_flags;
@@ -491,6 +500,8 @@ struct i40e_aqc_mng_laa {
u8 reserved2[6];
};
+I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa);
+
/* Manage MAC Address Read Command (indirect 0x0107) */
struct i40e_aqc_mac_address_read {
__le16 command_flags;
@@ -562,6 +573,8 @@ struct i40e_aqc_get_switch_config_header_resp {
u8 reserved[12];
};
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp);
+
struct i40e_aqc_switch_config_element_resp {
u8 element_type;
#define I40E_AQ_SW_ELEM_TYPE_MAC 1
@@ -587,6 +600,8 @@ struct i40e_aqc_switch_config_element_resp {
__le16 element_info;
};
+I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp);
+
/* Get Switch Configuration (indirect 0x0200)
* an array of elements are returned in the response buffer
* the first in the array is the header, remainder are elements
@@ -596,6 +611,8 @@ struct i40e_aqc_get_switch_config_resp {
struct i40e_aqc_switch_config_element_resp element[1];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp);
+
/* Add Statistics (direct 0x0201)
* Remove Statistics (direct 0x0202)
*/
@@ -661,6 +678,8 @@ struct i40e_aqc_switch_resource_alloc_element_resp {
u8 reserved2[6];
};
+I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
+
/* Add VSI (indirect 0x0210)
* this indirect command uses struct i40e_aqc_vsi_properties_data
* as the indirect buffer (128 bytes)
@@ -1092,6 +1111,8 @@ struct i40e_aqc_remove_tag {
u8 reserved[12];
};
+I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag);
+
/* Add multicast E-Tag (direct 0x0257)
* del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields
* and no external data
@@ -1207,7 +1228,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
} ipaddr;
__le16 flags;
#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
+#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
I40E_AQC_ADD_CLOUD_FILTER_SHIFT)
/* 0x0000 reserved */
#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
@@ -1240,7 +1261,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
u8 reserved[4];
__le16 queue_number;
#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \
+#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \
I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
u8 reserved2[14];
/* response section */
@@ -1359,6 +1380,8 @@ struct i40e_aqc_configure_vsi_ets_sla_bw_data {
u8 reserved1[28];
};
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data);
+
/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407)
* responds with i40e_aqc_qs_handles_resp
*/
@@ -1370,6 +1393,8 @@ struct i40e_aqc_configure_vsi_tc_bw_data {
__le16 qs_handles[8];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data);
+
/* Query vsi bw configuration (indirect 0x0408) */
struct i40e_aqc_query_vsi_bw_config_resp {
u8 tc_valid_bits;
@@ -1383,6 +1408,8 @@ struct i40e_aqc_query_vsi_bw_config_resp {
u8 reserved3[23];
};
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp);
+
/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */
struct i40e_aqc_query_vsi_ets_sla_config_resp {
u8 tc_valid_bits;
@@ -1394,6 +1421,8 @@ struct i40e_aqc_query_vsi_ets_sla_config_resp {
__le16 tc_bw_max[2];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp);
+
/* Configure Switching Component Bandwidth Limit (direct 0x0410) */
struct i40e_aqc_configure_switching_comp_bw_limit {
__le16 seid;
@@ -1421,6 +1450,8 @@ struct i40e_aqc_configure_switching_comp_ets_data {
u8 reserved2[96];
};
+I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data);
+
/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */
struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
u8 tc_valid_bits;
@@ -1432,6 +1463,9 @@ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
u8 reserved1[28];
};
+I40E_CHECK_STRUCT_LEN(0x40,
+ i40e_aqc_configure_switching_comp_ets_bw_limit_data);
+
/* Configure Switching Component Bandwidth Allocation per Tc
* (indirect 0x0417)
*/
@@ -1443,6 +1477,8 @@ struct i40e_aqc_configure_switching_comp_bw_config_data {
u8 reserved1[20];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data);
+
/* Query Switching Component Configuration (indirect 0x0418) */
struct i40e_aqc_query_switching_comp_ets_config_resp {
u8 tc_valid_bits;
@@ -1453,6 +1489,8 @@ struct i40e_aqc_query_switching_comp_ets_config_resp {
u8 reserved2[23];
};
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp);
+
/* Query PhysicalPort ETS Configuration (indirect 0x0419) */
struct i40e_aqc_query_port_ets_config_resp {
u8 reserved[4];
@@ -1468,6 +1506,8 @@ struct i40e_aqc_query_port_ets_config_resp {
u8 reserved3[32];
};
+I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp);
+
/* Query Switching Component Bandwidth Allocation per Traffic Type
* (indirect 0x041A)
*/
@@ -1482,6 +1522,8 @@ struct i40e_aqc_query_switching_comp_bw_config_resp {
__le16 tc_bw_max[2];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp);
+
/* Suspend/resume port TX traffic
* (direct 0x041B and 0x041C) uses the generic SEID struct
*/
@@ -1495,6 +1537,8 @@ struct i40e_aqc_configure_partition_bw_data {
u8 max_bw[16]; /* bandwidth limit */
};
+I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data);
+
/* Get and set the active HMC resource profile and status.
* (direct 0x0500) and (direct 0x0501)
*/
@@ -1577,6 +1621,8 @@ struct i40e_aqc_module_desc {
u8 reserved2[8];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc);
+
struct i40e_aq_get_phy_abilities_resp {
__le32 phy_type; /* bitmap using the above enum for offsets */
u8 link_speed; /* bitmap using the above enum bit patterns */
@@ -1605,6 +1651,8 @@ struct i40e_aq_get_phy_abilities_resp {
struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
};
+I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp);
+
/* Set PHY Config (direct 0x0601) */
struct i40e_aq_set_phy_config { /* same bits as above in all */
__le32 phy_type;
@@ -1788,12 +1836,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update);
/* NVM Config Read (indirect 0x0704) */
struct i40e_aqc_nvm_config_read {
__le16 cmd_flags;
-#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
-#define ANVM_READ_SINGLE_FEATURE 0
-#define ANVM_READ_MULTIPLE_FEATURES 1
+#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
+#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0
+#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1
__le16 element_count;
- __le16 element_id; /* Feature/field ID */
- u8 reserved[2];
+ __le16 element_id; /* Feature/field ID */
+ __le16 element_id_msw; /* MSWord of field ID */
__le32 address_high;
__le32 address_low;
};
@@ -1811,21 +1859,32 @@ struct i40e_aqc_nvm_config_write {
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write);
+/* Used for 0x0704 as well as for 0x0705 commands */
+#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1
+#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \
+ (1 << I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT)
+#define I40E_AQ_ANVM_FEATURE 0
+#define I40E_AQ_ANVM_IMMEDIATE_FIELD (1 << FEATURE_OR_IMMEDIATE_SHIFT)
struct i40e_aqc_nvm_config_data_feature {
__le16 feature_id;
- __le16 instance_id;
+#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01
+#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08
+#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10
__le16 feature_options;
__le16 feature_selection;
};
+I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature);
+
struct i40e_aqc_nvm_config_data_immediate_field {
-#define ANVM_FEATURE_OR_IMMEDIATE_MASK 0x2
- __le16 field_id;
- __le16 instance_id;
+ __le32 field_id;
+ __le32 field_value;
__le16 field_options;
- __le16 field_value;
+ __le16 reserved;
};
+I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field);
+
/* Send to PF command (indirect 0x0801) id is only used by PF
* Send to VF command (indirect 0x0802) id is only used by PF
* Send to Peer PF command (indirect 0x0803)
@@ -2026,12 +2085,54 @@ struct i40e_aqc_get_cee_dcb_cfg_resp {
u8 oper_tc_bw[8];
u8 oper_pfc_en;
__le16 oper_app_prio;
+#define I40E_AQC_CEE_APP_FCOE_SHIFT 0x0
+#define I40E_AQC_CEE_APP_FCOE_MASK (0x7 << I40E_AQC_CEE_APP_FCOE_SHIFT)
+#define I40E_AQC_CEE_APP_ISCSI_SHIFT 0x3
+#define I40E_AQC_CEE_APP_ISCSI_MASK (0x7 << I40E_AQC_CEE_APP_ISCSI_SHIFT)
+#define I40E_AQC_CEE_APP_FIP_SHIFT 0x8
+#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT)
+#define I40E_AQC_CEE_APP_FIP_MASK (0x7 << I40E_AQC_CEE_APP_FIP_SHIFT)
__le32 tlv_status;
+#define I40E_AQC_CEE_PG_STATUS_SHIFT 0x0
+#define I40E_AQC_CEE_PG_STATUS_MASK (0x7 << I40E_AQC_CEE_PG_STATUS_SHIFT)
+#define I40E_AQC_CEE_PFC_STATUS_SHIFT 0x3
+#define I40E_AQC_CEE_PFC_STATUS_MASK (0x7 << I40E_AQC_CEE_PFC_STATUS_SHIFT)
+#define I40E_AQC_CEE_APP_STATUS_SHIFT 0x8
+#define I40E_AQC_CEE_APP_STATUS_MASK (0x7 << I40E_AQC_CEE_APP_STATUS_SHIFT)
u8 reserved[12];
};
I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_cee_dcb_cfg_resp);
+/* Set Local LLDP MIB (indirect 0x0A08)
+ * Used to replace the local MIB of a given LLDP agent. e.g. DCBx
+ */
+struct i40e_aqc_lldp_set_local_mib {
+#define SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT 0
+#define SET_LOCAL_MIB_AC_TYPE_DCBX_MASK (1 << SET_LOCAL_MIB_AC_TYPE_DCBX_SHIFT)
+ u8 type;
+ u8 reserved0;
+ __le16 length;
+ u8 reserved1[4];
+ __le32 address_high;
+ __le32 address_low;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_set_local_mib);
+
+/* Stop/Start LLDP Agent (direct 0x0A09)
+ * Used for stopping/starting specific LLDP agent. e.g. DCBx
+ */
+struct i40e_aqc_lldp_stop_start_specific_agent {
+#define I40E_AQC_START_SPECIFIC_AGENT_SHIFT 0
+#define I40E_AQC_START_SPECIFIC_AGENT_MASK \
+ (1 << I40E_AQC_START_SPECIFIC_AGENT_SHIFT)
+ u8 command;
+ u8 reserved[15];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_lldp_stop_start_specific_agent);
+
/* Add Udp Tunnel command and completion (direct 0x0B00) */
struct i40e_aqc_add_udp_tunnel {
__le16 udp_port;
@@ -2106,7 +2207,8 @@ struct i40e_aqc_oem_param_change {
#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
#define I40E_AQ_OEM_PARAM_MAC 2
__le32 param_value1;
- u8 param_value2[8];
+ __le16 param_value2;
+ u8 reserved[6];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change);
@@ -2120,6 +2222,28 @@ struct i40e_aqc_oem_state_change {
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change);
+/* Initialize OCSD (0xFE02, direct) */
+struct i40e_aqc_opc_oem_ocsd_initialize {
+ u8 type_status;
+ u8 reserved1[3];
+ __le32 ocsd_memory_block_addr_high;
+ __le32 ocsd_memory_block_addr_low;
+ __le32 requested_update_interval;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize);
+
+/* Initialize OCBB (0xFE03, direct) */
+struct i40e_aqc_opc_oem_ocbb_initialize {
+ u8 type_status;
+ u8 reserved1[3];
+ __le32 ocbb_memory_block_addr_high;
+ __le32 ocbb_memory_block_addr_low;
+ u8 reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize);
+
/* debug commands */
/* get device id (0xFF00) uses the generic structure */
diff --git a/drivers/net/ethernet/intel/i40e/i40e_common.c b/drivers/net/ethernet/intel/i40e/i40e_common.c
index 3d741ee99a2c..11a9ffebf8d8 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_common.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_common.c
@@ -742,6 +742,65 @@ i40e_status i40e_get_san_mac_addr(struct i40e_hw *hw, u8 *mac_addr)
#endif
/**
+ * i40e_read_pba_string - Reads part number string from EEPROM
+ * @hw: pointer to hardware structure
+ * @pba_num: stores the part number string from the EEPROM
+ * @pba_num_size: part number string buffer length
+ *
+ * Reads the part number string from the EEPROM.
+ **/
+i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num,
+ u32 pba_num_size)
+{
+ i40e_status status = 0;
+ u16 pba_word = 0;
+ u16 pba_size = 0;
+ u16 pba_ptr = 0;
+ u16 i = 0;
+
+ status = i40e_read_nvm_word(hw, I40E_SR_PBA_FLAGS, &pba_word);
+ if (status || (pba_word != 0xFAFA)) {
+ hw_dbg(hw, "Failed to read PBA flags or flag is invalid.\n");
+ return status;
+ }
+
+ status = i40e_read_nvm_word(hw, I40E_SR_PBA_BLOCK_PTR, &pba_ptr);
+ if (status) {
+ hw_dbg(hw, "Failed to read PBA Block pointer.\n");
+ return status;
+ }
+
+ status = i40e_read_nvm_word(hw, pba_ptr, &pba_size);
+ if (status) {
+ hw_dbg(hw, "Failed to read PBA Block size.\n");
+ return status;
+ }
+
+ /* Subtract one to get PBA word count (PBA Size word is included in
+ * total size)
+ */
+ pba_size--;
+ if (pba_num_size < (((u32)pba_size * 2) + 1)) {
+ hw_dbg(hw, "Buffer to small for PBA data.\n");
+ return I40E_ERR_PARAM;
+ }
+
+ for (i = 0; i < pba_size; i++) {
+ status = i40e_read_nvm_word(hw, (pba_ptr + 1) + i, &pba_word);
+ if (status) {
+ hw_dbg(hw, "Failed to read PBA Block word %d.\n", i);
+ return status;
+ }
+
+ pba_num[(i * 2)] = (pba_word >> 8) & 0xFF;
+ pba_num[(i * 2) + 1] = pba_word & 0xFF;
+ }
+ pba_num[(pba_size * 2)] = '\0';
+
+ return status;
+}
+
+/**
* i40e_get_media_type - Gets media type
* @hw: pointer to the hardware structure
**/
@@ -1083,8 +1142,10 @@ void i40e_led_set(struct i40e_hw *hw, u32 mode, bool blink)
if (mode == I40E_LINK_ACTIVITY)
blink = false;
- gpio_val |= (blink ? 1 : 0) <<
- I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT;
+ if (blink)
+ gpio_val |= (1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT);
+ else
+ gpio_val &= ~(1 << I40E_GLGEN_GPIO_CTL_LED_BLINK_SHIFT);
wr32(hw, I40E_GLGEN_GPIO_CTL(i), gpio_val);
break;
@@ -2035,6 +2096,43 @@ i40e_status i40e_aq_send_msg_to_vf(struct i40e_hw *hw, u16 vfid,
}
/**
+ * i40e_aq_debug_read_register
+ * @hw: pointer to the hw struct
+ * @reg_addr: register address
+ * @reg_val: register value
+ * @cmd_details: pointer to command details structure or NULL
+ *
+ * Read the register using the admin queue commands
+ **/
+i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw,
+ u32 reg_addr, u64 *reg_val,
+ struct i40e_asq_cmd_details *cmd_details)
+{
+ struct i40e_aq_desc desc;
+ struct i40e_aqc_debug_reg_read_write *cmd_resp =
+ (struct i40e_aqc_debug_reg_read_write *)&desc.params.raw;
+ i40e_status status;
+
+ if (reg_val == NULL)
+ return I40E_ERR_PARAM;
+
+ i40e_fill_default_direct_cmd_desc(&desc,
+ i40e_aqc_opc_debug_read_reg);
+
+ cmd_resp->address = cpu_to_le32(reg_addr);
+
+ status = i40e_asq_send_command(hw, &desc, NULL, 0, cmd_details);
+
+ if (!status) {
+ *reg_val = ((u64)cmd_resp->value_high << 32) |
+ (u64)cmd_resp->value_low;
+ *reg_val = le64_to_cpu(*reg_val);
+ }
+
+ return status;
+}
+
+/**
* i40e_aq_debug_write_register
* @hw: pointer to the hw struct
* @reg_addr: register address
@@ -2264,6 +2362,7 @@ i40e_aq_erase_nvm_exit:
#define I40E_DEV_FUNC_CAP_VSI 0x17
#define I40E_DEV_FUNC_CAP_DCB 0x18
#define I40E_DEV_FUNC_CAP_FCOE 0x21
+#define I40E_DEV_FUNC_CAP_ISCSI 0x22
#define I40E_DEV_FUNC_CAP_RSS 0x40
#define I40E_DEV_FUNC_CAP_RX_QUEUES 0x41
#define I40E_DEV_FUNC_CAP_TX_QUEUES 0x42
@@ -2292,6 +2391,7 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
enum i40e_admin_queue_opc list_type_opc)
{
struct i40e_aqc_list_capabilities_element_resp *cap;
+ u32 valid_functions, num_functions;
u32 number, logical_id, phys_id;
struct i40e_hw_capabilities *p;
u32 i = 0;
@@ -2362,6 +2462,10 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
if (number == 1)
p->fcoe = true;
break;
+ case I40E_DEV_FUNC_CAP_ISCSI:
+ if (number == 1)
+ p->iscsi = true;
+ break;
case I40E_DEV_FUNC_CAP_RSS:
p->rss = true;
p->rss_table_size = number;
@@ -2427,6 +2531,34 @@ static void i40e_parse_discover_capabilities(struct i40e_hw *hw, void *buff,
if (p->npar_enable || p->mfp_mode_1)
p->fcoe = false;
+ /* count the enabled ports (aka the "not disabled" ports) */
+ hw->num_ports = 0;
+ for (i = 0; i < 4; i++) {
+ u32 port_cfg_reg = I40E_PRTGEN_CNF + (4 * i);
+ u64 port_cfg = 0;
+
+ /* use AQ read to get the physical register offset instead
+ * of the port relative offset
+ */
+ i40e_aq_debug_read_register(hw, port_cfg_reg, &port_cfg, NULL);
+ if (!(port_cfg & I40E_PRTGEN_CNF_PORT_DIS_MASK))
+ hw->num_ports++;
+ }
+
+ valid_functions = p->valid_functions;
+ num_functions = 0;
+ while (valid_functions) {
+ if (valid_functions & 1)
+ num_functions++;
+ valid_functions >>= 1;
+ }
+
+ /* partition id is 1-based, and functions are evenly spread
+ * across the ports as partitions
+ */
+ hw->partition_id = (hw->pf_id / hw->num_ports) + 1;
+ hw->num_partitions = num_functions / hw->num_ports;
+
/* additional HW specific goodies that might
* someday be HW version specific
*/
diff --git a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
index cb0de455683e..61236f983971 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_debugfs.c
@@ -1890,7 +1890,6 @@ static ssize_t i40e_dbg_command_write(struct file *filp,
dev_info(&pf->pdev->dev, " dump desc tx <vsi_seid> <ring_id> [<desc_n>]\n");
dev_info(&pf->pdev->dev, " dump desc rx <vsi_seid> <ring_id> [<desc_n>]\n");
dev_info(&pf->pdev->dev, " dump desc aq\n");
- dev_info(&pf->pdev->dev, " dump stats\n");
dev_info(&pf->pdev->dev, " dump reset stats\n");
dev_info(&pf->pdev->dev, " msg_enable [level]\n");
dev_info(&pf->pdev->dev, " read <reg>\n");
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
index 951e8767fc50..b8230dc205ec 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ethtool.c
@@ -219,6 +219,16 @@ static const char i40e_gstrings_test[][ETH_GSTRING_LEN] = {
#define I40E_TEST_LEN (sizeof(i40e_gstrings_test) / ETH_GSTRING_LEN)
/**
+ * i40e_partition_setting_complaint - generic complaint for MFP restriction
+ * @pf: the PF struct
+ **/
+static void i40e_partition_setting_complaint(struct i40e_pf *pf)
+{
+ dev_info(&pf->pdev->dev,
+ "The link settings are allowed to be changed only from the first partition of a given port. Please switch to the first partition in order to change the setting.\n");
+}
+
+/**
* i40e_get_settings - Get Link Speed and Duplex settings
* @netdev: network interface device structure
* @ecmd: ethtool command
@@ -485,6 +495,14 @@ static int i40e_set_settings(struct net_device *netdev,
u8 autoneg;
u32 advertise;
+ /* Changing port settings is not supported if this isn't the
+ * port's controlling PF
+ */
+ if (hw->partition_id != 1) {
+ i40e_partition_setting_complaint(pf);
+ return -EOPNOTSUPP;
+ }
+
if (vsi != pf->vsi[pf->lan_vsi])
return -EOPNOTSUPP;
@@ -687,6 +705,14 @@ static int i40e_set_pauseparam(struct net_device *netdev,
u8 aq_failures;
int err = 0;
+ /* Changing the port's flow control is not supported if this isn't the
+ * port's controlling PF
+ */
+ if (hw->partition_id != 1) {
+ i40e_partition_setting_complaint(pf);
+ return -EOPNOTSUPP;
+ }
+
if (vsi != pf->vsi[pf->lan_vsi])
return -EOPNOTSUPP;
@@ -1503,7 +1529,7 @@ static void i40e_get_wol(struct net_device *netdev,
/* NVM bit on means WoL disabled for the port */
i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits);
- if ((1 << hw->port) & wol_nvm_bits) {
+ if ((1 << hw->port) & wol_nvm_bits || hw->partition_id != 1) {
wol->supported = 0;
wol->wolopts = 0;
} else {
@@ -1512,13 +1538,28 @@ static void i40e_get_wol(struct net_device *netdev,
}
}
+/**
+ * i40e_set_wol - set the WakeOnLAN configuration
+ * @netdev: the netdev in question
+ * @wol: the ethtool WoL setting data
+ **/
static int i40e_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
{
struct i40e_netdev_priv *np = netdev_priv(netdev);
struct i40e_pf *pf = np->vsi->back;
+ struct i40e_vsi *vsi = np->vsi;
struct i40e_hw *hw = &pf->hw;
u16 wol_nvm_bits;
+ /* WoL not supported if this isn't the controlling PF on the port */
+ if (hw->partition_id != 1) {
+ i40e_partition_setting_complaint(pf);
+ return -EOPNOTSUPP;
+ }
+
+ if (vsi != pf->vsi[pf->lan_vsi])
+ return -EOPNOTSUPP;
+
/* NVM bit on means WoL disabled for the port */
i40e_read_nvm_word(hw, I40E_SR_NVM_WAKE_ON_LAN, &wol_nvm_bits);
if (((1 << hw->port) & wol_nvm_bits))
diff --git a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
index a8b8bd95108d..27c206e62da7 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_fcoe.c
@@ -39,15 +39,6 @@
#include "i40e_fcoe.h"
/**
- * i40e_rx_is_fip - returns true if the rx packet type is FIP
- * @ptype: the packet type field from rx descriptor write-back
- **/
-static inline bool i40e_rx_is_fip(u16 ptype)
-{
- return ptype == I40E_RX_PTYPE_L2_FIP_PAY2;
-}
-
-/**
* i40e_rx_is_fcoe - returns true if the rx packet type is FCoE
* @ptype: the packet type field from rx descriptor write-back
**/
@@ -404,6 +395,7 @@ int i40e_fcoe_vsi_init(struct i40e_vsi *vsi, struct i40e_vsi_context *ctxt)
I40E_AQ_VSI_PROP_INGRESS_UP_VALID |
I40E_AQ_VSI_PROP_EGRESS_UP_VALID));
+ info->switch_id = cpu_to_le16(I40E_AQ_VSI_SW_ID_FLAG_ALLOW_LB);
enabled_tc = i40e_get_fcoe_tc_map(pf);
i40e_vsi_setup_queue_map(vsi, ctxt, enabled_tc, true);
@@ -1511,12 +1503,16 @@ void i40e_fcoe_config_netdev(struct net_device *netdev, struct i40e_vsi *vsi)
strlcpy(netdev->name, "fcoe%d", IFNAMSIZ-1);
netdev->mtu = FCOE_MTU;
SET_NETDEV_DEV(netdev, &pf->pdev->dev);
+ /* set different dev_port value 1 for FCoE netdev than the default
+ * zero dev_port value for PF netdev, this helps biosdevname user
+ * tool to differentiate them correctly while both attached to the
+ * same PCI function.
+ */
+ netdev->dev_port = 1;
i40e_add_filter(vsi, hw->mac.san_addr, 0, false, false);
i40e_add_filter(vsi, (u8[6]) FC_FCOE_FLOGI_MAC, 0, false, false);
i40e_add_filter(vsi, FIP_ALL_FCOE_MACS, 0, false, false);
i40e_add_filter(vsi, FIP_ALL_ENODE_MACS, 0, false, false);
- i40e_add_filter(vsi, FIP_ALL_VN2VN_MACS, 0, false, false);
- i40e_add_filter(vsi, FIP_ALL_P2P_MACS, 0, false, false);
/* use san mac */
ether_addr_copy(netdev->dev_addr, hw->mac.san_addr);
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a5f2660d552d..cbe281be1c9f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -39,7 +39,7 @@ static const char i40e_driver_string[] =
#define DRV_VERSION_MAJOR 1
#define DRV_VERSION_MINOR 2
-#define DRV_VERSION_BUILD 2
+#define DRV_VERSION_BUILD 6
#define DRV_VERSION __stringify(DRV_VERSION_MAJOR) "." \
__stringify(DRV_VERSION_MINOR) "." \
__stringify(DRV_VERSION_BUILD) DRV_KERN
@@ -2819,8 +2819,9 @@ static void i40e_vsi_configure_msix(struct i40e_vsi *vsi)
* i40e_enable_misc_int_causes - enable the non-queue interrupts
* @hw: ptr to the hardware info
**/
-static void i40e_enable_misc_int_causes(struct i40e_hw *hw)
+static void i40e_enable_misc_int_causes(struct i40e_pf *pf)
{
+ struct i40e_hw *hw = &pf->hw;
u32 val;
/* clear things first */
@@ -2832,11 +2833,13 @@ static void i40e_enable_misc_int_causes(struct i40e_hw *hw)
I40E_PFINT_ICR0_ENA_GRST_MASK |
I40E_PFINT_ICR0_ENA_PCI_EXCEPTION_MASK |
I40E_PFINT_ICR0_ENA_GPIO_MASK |
- I40E_PFINT_ICR0_ENA_TIMESYNC_MASK |
I40E_PFINT_ICR0_ENA_HMC_ERR_MASK |
I40E_PFINT_ICR0_ENA_VFLR_MASK |
I40E_PFINT_ICR0_ENA_ADMINQ_MASK;
+ if (pf->flags & I40E_FLAG_PTP)
+ val |= I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
+
wr32(hw, I40E_PFINT_ICR0_ENA, val);
/* SW_ITR_IDX = 0, but don't change INTENA */
@@ -2866,7 +2869,7 @@ static void i40e_configure_msi_and_legacy(struct i40e_vsi *vsi)
q_vector->tx.latency_range = I40E_LOW_LATENCY;
wr32(hw, I40E_PFINT_ITR0(I40E_TX_ITR), q_vector->tx.itr);
- i40e_enable_misc_int_causes(hw);
+ i40e_enable_misc_int_causes(pf);
/* FIRSTQ_INDX = 0, FIRSTQ_TYPE = 0 (rx) */
wr32(hw, I40E_PFINT_LNKLST0, 0);
@@ -2937,7 +2940,7 @@ void i40e_irq_dynamic_enable(struct i40e_vsi *vsi, int vector)
/**
* i40e_irq_dynamic_disable - Disable default interrupt generation settings
* @vsi: pointer to a vsi
- * @vector: enable a particular Hw Interrupt vector
+ * @vector: disable a particular Hw Interrupt vector
**/
void i40e_irq_dynamic_disable(struct i40e_vsi *vsi, int vector)
{
@@ -3402,10 +3405,10 @@ static int i40e_vsi_request_irq(struct i40e_vsi *vsi, char *basename)
err = i40e_vsi_request_irq_msix(vsi, basename);
else if (pf->flags & I40E_FLAG_MSI_ENABLED)
err = request_irq(pf->pdev->irq, i40e_intr, 0,
- pf->misc_int_name, pf);
+ pf->int_name, pf);
else
err = request_irq(pf->pdev->irq, i40e_intr, IRQF_SHARED,
- pf->misc_int_name, pf);
+ pf->int_name, pf);
if (err)
dev_info(&pf->pdev->dev, "request_irq failed, Error %d\n", err);
@@ -3999,6 +4002,35 @@ static int i40e_pf_wait_txq_disabled(struct i40e_pf *pf)
#endif
/**
+ * i40e_get_iscsi_tc_map - Return TC map for iSCSI APP
+ * @pf: pointer to pf
+ *
+ * Get TC map for ISCSI PF type that will include iSCSI TC
+ * and LAN TC.
+ **/
+static u8 i40e_get_iscsi_tc_map(struct i40e_pf *pf)
+{
+ struct i40e_dcb_app_priority_table app;
+ struct i40e_hw *hw = &pf->hw;
+ u8 enabled_tc = 1; /* TC0 is always enabled */
+ u8 tc, i;
+ /* Get the iSCSI APP TLV */
+ struct i40e_dcbx_config *dcbcfg = &hw->local_dcbx_config;
+
+ for (i = 0; i < dcbcfg->numapps; i++) {
+ app = dcbcfg->app[i];
+ if (app.selector == I40E_APP_SEL_TCPIP &&
+ app.protocolid == I40E_APP_PROTOID_ISCSI) {
+ tc = dcbcfg->etscfg.prioritytable[app.priority];
+ enabled_tc |= (1 << tc);
+ break;
+ }
+ }
+
+ return enabled_tc;
+}
+
+/**
* i40e_dcb_get_num_tc - Get the number of TCs from DCBx config
* @dcbcfg: the corresponding DCBx configuration structure
*
@@ -4061,18 +4093,23 @@ static u8 i40e_pf_get_num_tc(struct i40e_pf *pf)
if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
return 1;
+ /* SFP mode will be enabled for all TCs on port */
+ if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+ return i40e_dcb_get_num_tc(dcbcfg);
+
/* MFP mode return count of enabled TCs for this PF */
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if (pf->hw.func_caps.iscsi)
+ enabled_tc = i40e_get_iscsi_tc_map(pf);
+ else
enabled_tc = pf->hw.func_caps.enabled_tcmap;
- for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
- if (enabled_tc & (1 << i))
- num_tc++;
- }
- return num_tc;
- }
- /* SFP mode will be enabled for all TCs on port */
- return i40e_dcb_get_num_tc(dcbcfg);
+ /* At least have TC0 */
+ enabled_tc = (enabled_tc ? enabled_tc : 0x1);
+ for (i = 0; i < I40E_MAX_TRAFFIC_CLASS; i++) {
+ if (enabled_tc & (1 << i))
+ num_tc++;
+ }
+ return num_tc;
}
/**
@@ -4110,12 +4147,15 @@ static u8 i40e_pf_get_tc_map(struct i40e_pf *pf)
if (!(pf->flags & I40E_FLAG_DCB_ENABLED))
return i40e_pf_get_default_tc(pf);
- /* MFP mode will have enabled TCs set by FW */
- if (pf->flags & I40E_FLAG_MFP_ENABLED)
- return pf->hw.func_caps.enabled_tcmap;
-
/* SFP mode we want PF to be enabled for all TCs */
- return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config);
+ if (!(pf->flags & I40E_FLAG_MFP_ENABLED))
+ return i40e_dcb_get_enabled_tc(&pf->hw.local_dcbx_config);
+
+ /* MPF enabled and iSCSI PF type */
+ if (pf->hw.func_caps.iscsi)
+ return i40e_get_iscsi_tc_map(pf);
+ else
+ return pf->hw.func_caps.enabled_tcmap;
}
/**
@@ -4505,9 +4545,6 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
struct i40e_hw *hw = &pf->hw;
int err = 0;
- if (pf->hw.func_caps.npar_enable)
- goto out;
-
/* Get the initial DCB configuration */
err = i40e_init_dcb(hw);
if (!err) {
@@ -4533,7 +4570,8 @@ static int i40e_init_pf_dcb(struct i40e_pf *pf)
"DCBX offload is supported for this PF.\n");
}
} else {
- dev_info(&pf->pdev->dev, "AQ Querying DCB configuration failed: %d\n",
+ dev_info(&pf->pdev->dev,
+ "AQ Querying DCB configuration failed: aq_err %d\n",
pf->hw.aq.asq_last_status);
}
@@ -4557,6 +4595,15 @@ static void i40e_print_link_message(struct i40e_vsi *vsi, bool isup)
return;
}
+ /* Warn user if link speed on NPAR enabled partition is not at
+ * least 10GB
+ */
+ if (vsi->back->hw.func_caps.npar_enable &&
+ (vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_1GB ||
+ vsi->back->hw.phy.link_info.link_speed == I40E_LINK_SPEED_100MB))
+ netdev_warn(vsi->netdev,
+ "The partition detected link speed that is less than 10Gbps\n");
+
switch (vsi->back->hw.phy.link_info.link_speed) {
case I40E_LINK_SPEED_40GB:
strlcpy(speed, "40 Gbps", SPEED_SIZE);
@@ -4836,7 +4883,7 @@ static int i40e_open(struct net_device *netdev)
int i40e_vsi_open(struct i40e_vsi *vsi)
{
struct i40e_pf *pf = vsi->back;
- char int_name[IFNAMSIZ];
+ char int_name[I40E_INT_NAME_STR_LEN];
int err;
/* allocate descriptors */
@@ -4870,7 +4917,7 @@ int i40e_vsi_open(struct i40e_vsi *vsi)
goto err_set_queues;
} else if (vsi->type == I40E_VSI_FDIR) {
- snprintf(int_name, sizeof(int_name) - 1, "%s-%s-fdir",
+ snprintf(int_name, sizeof(int_name) - 1, "%s-%s:fdir",
dev_driver_string(&pf->pdev->dev),
dev_name(&pf->pdev->dev));
err = i40e_vsi_request_irq(vsi, int_name);
@@ -5494,14 +5541,18 @@ static void i40e_link_event(struct i40e_pf *pf)
{
bool new_link, old_link;
struct i40e_vsi *vsi = pf->vsi[pf->lan_vsi];
+ u8 new_link_speed, old_link_speed;
/* set this to force the get_link_status call to refresh state */
pf->hw.phy.get_link_info = true;
old_link = (pf->hw.phy.link_info_old.link_info & I40E_AQ_LINK_UP);
new_link = i40e_get_link_status(&pf->hw);
+ old_link_speed = pf->hw.phy.link_info_old.link_speed;
+ new_link_speed = pf->hw.phy.link_info.link_speed;
if (new_link == old_link &&
+ new_link_speed == old_link_speed &&
(test_bit(__I40E_DOWN, &vsi->state) ||
new_link == netif_carrier_ok(vsi->netdev)))
return;
@@ -6175,8 +6226,9 @@ static void i40e_reset_and_rebuild(struct i40e_pf *pf, bool reinit)
#ifdef CONFIG_I40E_DCB
ret = i40e_init_pf_dcb(pf);
if (ret) {
- dev_info(&pf->pdev->dev, "init_pf_dcb failed: %d\n", ret);
- goto end_core_reset;
+ dev_info(&pf->pdev->dev, "DCB init failed %d, disabled\n", ret);
+ pf->flags &= ~I40E_FLAG_DCB_CAPABLE;
+ /* Continue without DCB enabled */
}
#endif /* CONFIG_I40E_DCB */
#ifdef I40E_FCOE
@@ -6881,17 +6933,17 @@ static int i40e_init_msix(struct i40e_pf *pf)
if (pf->flags & I40E_FLAG_FD_SB_ENABLED)
other_vecs++;
+ /* Scale down if necessary, and the rings will share vectors */
+ pf->num_lan_msix = min_t(int, pf->num_lan_msix,
+ (hw->func_caps.num_msix_vectors - other_vecs));
+ v_budget = pf->num_lan_msix + other_vecs;
+
#ifdef I40E_FCOE
if (pf->flags & I40E_FLAG_FCOE_ENABLED) {
pf->num_fcoe_msix = pf->num_fcoe_qps;
v_budget += pf->num_fcoe_msix;
}
-
#endif
- /* Scale down if necessary, and the rings will share vectors */
- pf->num_lan_msix = min_t(int, pf->num_lan_msix,
- (hw->func_caps.num_msix_vectors - other_vecs));
- v_budget = pf->num_lan_msix + other_vecs;
pf->msix_entries = kcalloc(v_budget, sizeof(struct msix_entry),
GFP_KERNEL);
@@ -7113,16 +7165,16 @@ static int i40e_setup_misc_vector(struct i40e_pf *pf)
*/
if (!test_bit(__I40E_RESET_RECOVERY_PENDING, &pf->state)) {
err = request_irq(pf->msix_entries[0].vector,
- i40e_intr, 0, pf->misc_int_name, pf);
+ i40e_intr, 0, pf->int_name, pf);
if (err) {
dev_info(&pf->pdev->dev,
"request_irq for %s failed: %d\n",
- pf->misc_int_name, err);
+ pf->int_name, err);
return -EFAULT;
}
}
- i40e_enable_misc_int_causes(hw);
+ i40e_enable_misc_int_causes(pf);
/* associate no queues to the misc vector */
wr32(hw, I40E_PFINT_LNKLST0, I40E_QUEUE_END_OF_LIST);
@@ -7306,7 +7358,7 @@ static int i40e_sw_init(struct i40e_pf *pf)
#endif /* I40E_FCOE */
#ifdef CONFIG_PCI_IOV
- if (pf->hw.func_caps.num_vfs) {
+ if (pf->hw.func_caps.num_vfs && pf->hw.partition_id == 1) {
pf->num_vf_qps = I40E_DEFAULT_QUEUES_PER_VF;
pf->flags |= I40E_FLAG_SRIOV_ENABLED;
pf->num_req_vfs = min_t(int,
@@ -7766,7 +7818,8 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
enabled_tc = i40e_pf_get_tc_map(pf);
/* MFP mode setup queue map and update VSI */
- if (pf->flags & I40E_FLAG_MFP_ENABLED) {
+ if ((pf->flags & I40E_FLAG_MFP_ENABLED) &&
+ !(pf->hw.func_caps.iscsi)) { /* NIC type PF */
memset(&ctxt, 0, sizeof(ctxt));
ctxt.seid = pf->main_vsi_seid;
ctxt.pf_num = pf->hw.pf_id;
@@ -7787,6 +7840,8 @@ static int i40e_add_vsi(struct i40e_vsi *vsi)
/* Default/Main VSI is only enabled for TC0
* reconfigure it to enable all TCs that are
* available on the port in SFP mode.
+ * For MFP case the iSCSI PF would use this
+ * flow to enable LAN+iSCSI TC.
*/
ret = i40e_vsi_config_tc(vsi, enabled_tc);
if (ret) {
@@ -9164,7 +9219,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
hw->aq.asq_buf_size = I40E_MAX_AQ_BUF_SIZE;
pf->adminq_work_limit = I40E_AQ_WORK_LIMIT;
- snprintf(pf->misc_int_name, sizeof(pf->misc_int_name) - 1,
+ snprintf(pf->int_name, sizeof(pf->int_name) - 1,
"%s-%s:misc",
dev_driver_string(&pf->pdev->dev), dev_name(&pdev->dev));
@@ -9227,6 +9282,16 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_configure_lan_hmc;
}
+ /* Disable LLDP for NICs that have firmware versions lower than v4.3.
+ * Ignore error return codes because if it was already disabled via
+ * hardware settings this will fail
+ */
+ if (((pf->hw.aq.fw_maj_ver == 4) && (pf->hw.aq.fw_min_ver < 3)) ||
+ (pf->hw.aq.fw_maj_ver < 4)) {
+ dev_info(&pdev->dev, "Stopping firmware LLDP agent.\n");
+ i40e_aq_stop_lldp(hw, true, NULL);
+ }
+
i40e_get_mac_addr(hw, hw->mac.addr);
if (!is_valid_ether_addr(hw->mac.addr)) {
dev_info(&pdev->dev, "invalid MAC address %pM\n", hw->mac.addr);
@@ -9256,7 +9321,7 @@ static int i40e_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
#ifdef CONFIG_I40E_DCB
err = i40e_init_pf_dcb(pf);
if (err) {
- dev_info(&pdev->dev, "init_pf_dcb failed: %d\n", err);
+ dev_info(&pdev->dev, "DCB init failed %d, disabled\n", err);
pf->flags &= ~I40E_FLAG_DCB_CAPABLE;
/* Continue without DCB enabled */
}
@@ -9671,6 +9736,8 @@ static int i40e_suspend(struct pci_dev *pdev, pm_message_t state)
set_bit(__I40E_SUSPENDED, &pf->state);
set_bit(__I40E_DOWN, &pf->state);
+ del_timer_sync(&pf->service_timer);
+ cancel_work_sync(&pf->service_task);
rtnl_lock();
i40e_prep_for_reset(pf);
rtnl_unlock();
diff --git a/drivers/net/ethernet/intel/i40e/i40e_prototype.h b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
index 2fb4306597e8..68e852a96680 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_prototype.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_prototype.h
@@ -71,6 +71,9 @@ i40e_status i40e_aq_get_firmware_version(struct i40e_hw *hw,
i40e_status i40e_aq_debug_write_register(struct i40e_hw *hw,
u32 reg_addr, u64 reg_val,
struct i40e_asq_cmd_details *cmd_details);
+i40e_status i40e_aq_debug_read_register(struct i40e_hw *hw,
+ u32 reg_addr, u64 *reg_val,
+ struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_phy_debug(struct i40e_hw *hw, u8 cmd_flags,
struct i40e_asq_cmd_details *cmd_details);
i40e_status i40e_aq_set_default_vsi(struct i40e_hw *hw, u16 vsi_id,
@@ -245,6 +248,8 @@ void i40e_clear_pxe_mode(struct i40e_hw *hw);
bool i40e_get_link_status(struct i40e_hw *hw);
i40e_status i40e_get_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
i40e_status i40e_get_port_mac_addr(struct i40e_hw *hw, u8 *mac_addr);
+i40e_status i40e_read_pba_string(struct i40e_hw *hw, u8 *pba_num,
+ u32 pba_num_size);
i40e_status i40e_validate_mac_addr(u8 *mac_addr);
void i40e_pre_tx_queue_cfg(struct i40e_hw *hw, u32 queue, bool enable);
#ifdef I40E_FCOE
diff --git a/drivers/net/ethernet/intel/i40e/i40e_ptp.c b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
index 6d1ec926aa37..fabcfa1b45b2 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_ptp.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_ptp.c
@@ -247,7 +247,12 @@ void i40e_ptp_rx_hang(struct i40e_vsi *vsi)
u32 prttsyn_stat;
int n;
- if (!(pf->flags & I40E_FLAG_PTP))
+ /* Since we cannot turn off the Rx timestamp logic if the device is
+ * configured for Tx timestamping, we check if Rx timestamping is
+ * configured. We don't want to spuriously warn about Rx timestamp
+ * hangs if we don't care about the timestamps.
+ */
+ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx)
return;
prttsyn_stat = rd32(hw, I40E_PRTTSYN_STAT_1);
@@ -305,6 +310,13 @@ void i40e_ptp_tx_hwtstamp(struct i40e_pf *pf)
u32 hi, lo;
u64 ns;
+ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_tx)
+ return;
+
+ /* don't attempt to timestamp if we don't have an skb */
+ if (!pf->ptp_tx_skb)
+ return;
+
lo = rd32(hw, I40E_PRTTSYN_TXTIME_L);
hi = rd32(hw, I40E_PRTTSYN_TXTIME_H);
@@ -338,7 +350,7 @@ void i40e_ptp_rx_hwtstamp(struct i40e_pf *pf, struct sk_buff *skb, u8 index)
/* Since we cannot turn off the Rx timestamp logic if the device is
* doing Tx timestamping, check if Rx timestamping is configured.
*/
- if (!pf->ptp_rx)
+ if (!(pf->flags & I40E_FLAG_PTP) || !pf->ptp_rx)
return;
hw = &pf->hw;
@@ -467,7 +479,12 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
switch (config->rx_filter) {
case HWTSTAMP_FILTER_NONE:
pf->ptp_rx = false;
- tsyntype = 0;
+ /* We set the type to V1, but do not enable UDP packet
+ * recognition. In this way, we should be as close to
+ * disabling PTP Rx timestamps as possible since V1 packets
+ * are always UDP, since L2 packets are a V2 feature.
+ */
+ tsyntype = I40E_PRTTSYN_CTL1_TSYNTYPE_V1;
break;
case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
@@ -521,17 +538,18 @@ static int i40e_ptp_set_timestamp_mode(struct i40e_pf *pf,
regval &= ~I40E_PFINT_ICR0_ENA_TIMESYNC_MASK;
wr32(hw, I40E_PFINT_ICR0_ENA, regval);
- /* There is no simple on/off switch for Rx. To "disable" Rx support,
- * ignore any received timestamps, rather than turn off the clock.
+ /* Although there is no simple on/off switch for Rx, we "disable" Rx
+ * timestamps by setting to V1 only mode and clear the UDP
+ * recognition. This ought to disable all PTP Rx timestamps as V1
+ * packets are always over UDP. Note that software is configured to
+ * ignore Rx timestamps via the pf->ptp_rx flag.
*/
- if (pf->ptp_rx) {
- regval = rd32(hw, I40E_PRTTSYN_CTL1);
- /* clear everything but the enable bit */
- regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK;
- /* now enable bits for desired Rx timestamps */
- regval |= tsyntype;
- wr32(hw, I40E_PRTTSYN_CTL1, regval);
- }
+ regval = rd32(hw, I40E_PRTTSYN_CTL1);
+ /* clear everything but the enable bit */
+ regval &= I40E_PRTTSYN_CTL1_TSYNENA_MASK;
+ /* now enable bits for desired Rx timestamps */
+ regval |= tsyntype;
+ wr32(hw, I40E_PRTTSYN_CTL1, regval);
return 0;
}
diff --git a/drivers/net/ethernet/intel/i40e/i40e_txrx.c b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
index cecb340898fe..2206d2d36f0f 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_txrx.c
@@ -836,8 +836,8 @@ static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
{
u32 val = I40E_PFINT_DYN_CTLN_INTENA_MASK |
I40E_PFINT_DYN_CTLN_SWINT_TRIG_MASK |
- I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK
- /* allow 00 to be written to the index */;
+ I40E_PFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK;
+ /* allow 00 to be written to the index */
wr32(&vsi->back->hw,
I40E_PFINT_DYN_CTLN(q_vector->v_idx + vsi->base_vector - 1),
@@ -1098,6 +1098,8 @@ int i40e_setup_rx_descriptors(struct i40e_ring *rx_ring)
if (!rx_ring->rx_bi)
goto err;
+ u64_stats_init(&rx_ring->syncp);
+
/* Round up to nearest 4K */
rx_ring->size = ring_is_16byte_desc_enabled(rx_ring)
? rx_ring->count * sizeof(union i40e_16byte_rx_desc)
@@ -1815,8 +1817,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
u32 tx_flags = 0;
/* if we have a HW VLAN tag being added, default to the HW one */
- if (vlan_tx_tag_present(skb)) {
- tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT;
+ if (skb_vlan_tag_present(skb)) {
+ tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT;
tx_flags |= I40E_TX_FLAGS_HW_VLAN;
/* else if it is a SW VLAN, check the next protocol and store the tag */
} else if (protocol == htons(ETH_P_8021Q)) {
@@ -1939,6 +1941,9 @@ static int i40e_tsyn(struct i40e_ring *tx_ring, struct sk_buff *skb,
* we are not already transmitting a packet to be timestamped
*/
pf = i40e_netdev_to_pf(tx_ring->netdev);
+ if (!(pf->flags & I40E_FLAG_PTP))
+ return 0;
+
if (pf->ptp_tx &&
!test_and_set_bit_lock(__I40E_PTP_TX_IN_PROGRESS, &pf->state)) {
skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS;
diff --git a/drivers/net/ethernet/intel/i40e/i40e_type.h b/drivers/net/ethernet/intel/i40e/i40e_type.h
index c1f2eb963357..e9901ef06a63 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40e/i40e_type.h
@@ -211,6 +211,7 @@ struct i40e_hw_capabilities {
bool evb_802_1_qbh; /* Bridge Port Extension */
bool dcb;
bool fcoe;
+ bool iscsi; /* Indicates iSCSI enabled */
bool mfp_mode_1;
bool mgmt_cem;
bool ieee_1588;
@@ -431,7 +432,7 @@ struct i40e_hw {
u8 __iomem *hw_addr;
void *back;
- /* function pointer structs */
+ /* subsystem structs */
struct i40e_phy_info phy;
struct i40e_mac_info mac;
struct i40e_bus_info bus;
@@ -458,6 +459,11 @@ struct i40e_hw {
u8 pf_id;
u16 main_vsi_seid;
+ /* for multi-function MACs */
+ u16 partition_id;
+ u16 num_partitions;
+ u16 num_ports;
+
/* Closest numa node to the device */
u16 numa_node;
@@ -1135,6 +1141,8 @@ struct i40e_hw_port_stats {
/* Checksum and Shadow RAM pointers */
#define I40E_SR_NVM_CONTROL_WORD 0x00
#define I40E_SR_EMP_MODULE_PTR 0x0F
+#define I40E_SR_PBA_FLAGS 0x15
+#define I40E_SR_PBA_BLOCK_PTR 0x16
#define I40E_SR_NVM_IMAGE_VERSION 0x18
#define I40E_SR_NVM_WAKE_ON_LAN 0x19
#define I40E_SR_ALTERNATE_SAN_MAC_ADDRESS_PTR 0x27
diff --git a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
index 5bae89550657..40f042af4131 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_virtchnl_pf.c
@@ -647,6 +647,9 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
int i;
u32 reg;
+ if (test_and_set_bit(__I40E_VF_DISABLE, &pf->state))
+ return;
+
/* warn the VF */
clear_bit(I40E_VF_STAT_ACTIVE, &vf->vf_states);
@@ -668,13 +671,13 @@ void i40e_reset_vf(struct i40e_vf *vf, bool flr)
/* poll VPGEN_VFRSTAT reg to make sure
* that reset is complete
*/
- for (i = 0; i < 100; i++) {
- /* vf reset requires driver to first reset the
- * vf and then poll the status register to make sure
- * that the requested op was completed
- * successfully
+ for (i = 0; i < 10; i++) {
+ /* VF reset requires driver to first reset the VF and then
+ * poll the status register to make sure that the reset
+ * completed successfully. Due to internal HW FIFO flushes,
+ * we must wait 10ms before the register will be valid.
*/
- usleep_range(10, 20);
+ usleep_range(10000, 20000);
reg = rd32(hw, I40E_VPGEN_VFRSTAT(vf->vf_id));
if (reg & I40E_VPGEN_VFRSTAT_VFRD_MASK) {
rsd = true;
@@ -706,6 +709,7 @@ complete_reset:
/* tell the VF the reset is done */
wr32(hw, I40E_VFGEN_RSTAT1(vf->vf_id), I40E_VFR_VFACTIVE);
i40e_flush(hw);
+ clear_bit(__I40E_VF_DISABLE, &pf->state);
}
/**
@@ -790,11 +794,18 @@ void i40e_free_vfs(struct i40e_pf *pf)
if (!pf->vf)
return;
+ while (test_and_set_bit(__I40E_VF_DISABLE, &pf->state))
+ usleep_range(1000, 2000);
- /* Disable interrupt 0 so we don't try to handle the VFLR. */
- i40e_irq_dynamic_disable_icr0(pf);
+ /* Disable IOV before freeing resources. This lets any VF drivers
+ * running in the host get themselves cleaned up before we yank
+ * the carpet out from underneath their feet.
+ */
+ if (!pci_vfs_assigned(pf->pdev))
+ pci_disable_sriov(pf->pdev);
+
+ msleep(20); /* let any messages in transit get finished up */
- mdelay(10); /* let any messages in transit get finished up */
/* free up vf resources */
tmp = pf->num_alloc_vfs;
pf->num_alloc_vfs = 0;
@@ -813,7 +824,6 @@ void i40e_free_vfs(struct i40e_pf *pf)
* before this function ever gets called.
*/
if (!pci_vfs_assigned(pf->pdev)) {
- pci_disable_sriov(pf->pdev);
/* Acknowledge VFLR for all VFS. Without this, VFs will fail to
* work correctly when SR-IOV gets re-enabled.
*/
@@ -827,9 +837,7 @@ void i40e_free_vfs(struct i40e_pf *pf)
dev_warn(&pf->pdev->dev,
"unable to disable SR-IOV because VFs are assigned.\n");
}
-
- /* Re-enable interrupt 0. */
- i40e_irq_dynamic_enable_icr0(pf);
+ clear_bit(__I40E_VF_DISABLE, &pf->state);
}
#ifdef CONFIG_PCI_IOV
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h
index 6c31bf22c2c3..60f04e96a80e 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq.h
@@ -148,7 +148,7 @@ static inline int i40e_aq_rc_to_posix(u32 aq_ret, u16 aq_rc)
/* general information */
#define I40E_AQ_LARGE_BUF 512
-#define I40E_ASQ_CMD_TIMEOUT 100 /* msecs */
+#define I40E_ASQ_CMD_TIMEOUT 250 /* msecs */
void i40evf_fill_default_direct_cmd_desc(struct i40e_aq_desc *desc,
u16 opcode);
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
index ff1b16370da9..e715bccfb5d2 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_adminq_cmd.h
@@ -268,6 +268,8 @@ enum i40e_admin_queue_opc {
/* OEM commands */
i40e_aqc_opc_oem_parameter_change = 0xFE00,
i40e_aqc_opc_oem_device_status_change = 0xFE01,
+ i40e_aqc_opc_oem_ocsd_initialize = 0xFE02,
+ i40e_aqc_opc_oem_ocbb_initialize = 0xFE03,
/* debug commands */
i40e_aqc_opc_debug_get_deviceid = 0xFF00,
@@ -276,7 +278,6 @@ enum i40e_admin_queue_opc {
i40e_aqc_opc_debug_write_reg = 0xFF04,
i40e_aqc_opc_debug_modify_reg = 0xFF07,
i40e_aqc_opc_debug_dump_internals = 0xFF08,
- i40e_aqc_opc_debug_modify_internals = 0xFF09,
};
/* command structures and indirect data structures */
@@ -410,6 +411,7 @@ struct i40e_aqc_list_capabilities_element_resp {
#define I40E_AQ_CAP_ID_VSI 0x0017
#define I40E_AQ_CAP_ID_DCB 0x0018
#define I40E_AQ_CAP_ID_FCOE 0x0021
+#define I40E_AQ_CAP_ID_ISCSI 0x0022
#define I40E_AQ_CAP_ID_RSS 0x0040
#define I40E_AQ_CAP_ID_RXQ 0x0041
#define I40E_AQ_CAP_ID_TXQ 0x0042
@@ -454,8 +456,11 @@ struct i40e_aqc_arp_proxy_data {
__le32 pfpm_proxyfc;
__le32 ip_addr;
u8 mac_addr[6];
+ u8 reserved[2];
};
+I40E_CHECK_STRUCT_LEN(0x14, i40e_aqc_arp_proxy_data);
+
/* Set NS Proxy Table Entry Command (indirect 0x0105) */
struct i40e_aqc_ns_proxy_data {
__le16 table_idx_mac_addr_0;
@@ -481,6 +486,8 @@ struct i40e_aqc_ns_proxy_data {
u8 ipv6_addr_1[16];
};
+I40E_CHECK_STRUCT_LEN(0x3c, i40e_aqc_ns_proxy_data);
+
/* Manage LAA Command (0x0106) - obsolete */
struct i40e_aqc_mng_laa {
__le16 command_flags;
@@ -491,6 +498,8 @@ struct i40e_aqc_mng_laa {
u8 reserved2[6];
};
+I40E_CHECK_CMD_LENGTH(i40e_aqc_mng_laa);
+
/* Manage MAC Address Read Command (indirect 0x0107) */
struct i40e_aqc_mac_address_read {
__le16 command_flags;
@@ -562,6 +571,8 @@ struct i40e_aqc_get_switch_config_header_resp {
u8 reserved[12];
};
+I40E_CHECK_CMD_LENGTH(i40e_aqc_get_switch_config_header_resp);
+
struct i40e_aqc_switch_config_element_resp {
u8 element_type;
#define I40E_AQ_SW_ELEM_TYPE_MAC 1
@@ -587,6 +598,8 @@ struct i40e_aqc_switch_config_element_resp {
__le16 element_info;
};
+I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_config_element_resp);
+
/* Get Switch Configuration (indirect 0x0200)
* an array of elements are returned in the response buffer
* the first in the array is the header, remainder are elements
@@ -596,6 +609,8 @@ struct i40e_aqc_get_switch_config_resp {
struct i40e_aqc_switch_config_element_resp element[1];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_get_switch_config_resp);
+
/* Add Statistics (direct 0x0201)
* Remove Statistics (direct 0x0202)
*/
@@ -661,6 +676,8 @@ struct i40e_aqc_switch_resource_alloc_element_resp {
u8 reserved2[6];
};
+I40E_CHECK_STRUCT_LEN(0x10, i40e_aqc_switch_resource_alloc_element_resp);
+
/* Add VSI (indirect 0x0210)
* this indirect command uses struct i40e_aqc_vsi_properties_data
* as the indirect buffer (128 bytes)
@@ -1092,6 +1109,8 @@ struct i40e_aqc_remove_tag {
u8 reserved[12];
};
+I40E_CHECK_CMD_LENGTH(i40e_aqc_remove_tag);
+
/* Add multicast E-Tag (direct 0x0257)
* del multicast E-Tag (direct 0x0258) only uses pv_seid and etag fields
* and no external data
@@ -1207,7 +1226,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
} ipaddr;
__le16 flags;
#define I40E_AQC_ADD_CLOUD_FILTER_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
+#define I40E_AQC_ADD_CLOUD_FILTER_MASK (0x3F << \
I40E_AQC_ADD_CLOUD_FILTER_SHIFT)
/* 0x0000 reserved */
#define I40E_AQC_ADD_CLOUD_FILTER_OIP 0x0001
@@ -1240,7 +1259,7 @@ struct i40e_aqc_add_remove_cloud_filters_element_data {
u8 reserved[4];
__le16 queue_number;
#define I40E_AQC_ADD_CLOUD_QUEUE_SHIFT 0
-#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x3F << \
+#define I40E_AQC_ADD_CLOUD_QUEUE_MASK (0x7FF << \
I40E_AQC_ADD_CLOUD_QUEUE_SHIFT)
u8 reserved2[14];
/* response section */
@@ -1359,6 +1378,8 @@ struct i40e_aqc_configure_vsi_ets_sla_bw_data {
u8 reserved1[28];
};
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_configure_vsi_ets_sla_bw_data);
+
/* Configure VSI Bandwidth Allocation per Traffic Type (indirect 0x0407)
* responds with i40e_aqc_qs_handles_resp
*/
@@ -1370,6 +1391,8 @@ struct i40e_aqc_configure_vsi_tc_bw_data {
__le16 qs_handles[8];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_vsi_tc_bw_data);
+
/* Query vsi bw configuration (indirect 0x0408) */
struct i40e_aqc_query_vsi_bw_config_resp {
u8 tc_valid_bits;
@@ -1383,6 +1406,8 @@ struct i40e_aqc_query_vsi_bw_config_resp {
u8 reserved3[23];
};
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_vsi_bw_config_resp);
+
/* Query VSI Bandwidth Allocation per Traffic Type (indirect 0x040A) */
struct i40e_aqc_query_vsi_ets_sla_config_resp {
u8 tc_valid_bits;
@@ -1394,6 +1419,8 @@ struct i40e_aqc_query_vsi_ets_sla_config_resp {
__le16 tc_bw_max[2];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_vsi_ets_sla_config_resp);
+
/* Configure Switching Component Bandwidth Limit (direct 0x0410) */
struct i40e_aqc_configure_switching_comp_bw_limit {
__le16 seid;
@@ -1421,6 +1448,8 @@ struct i40e_aqc_configure_switching_comp_ets_data {
u8 reserved2[96];
};
+I40E_CHECK_STRUCT_LEN(0x80, i40e_aqc_configure_switching_comp_ets_data);
+
/* Configure Switching Component Bandwidth Limits per Tc (indirect 0x0416) */
struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
u8 tc_valid_bits;
@@ -1432,6 +1461,9 @@ struct i40e_aqc_configure_switching_comp_ets_bw_limit_data {
u8 reserved1[28];
};
+I40E_CHECK_STRUCT_LEN(0x40,
+ i40e_aqc_configure_switching_comp_ets_bw_limit_data);
+
/* Configure Switching Component Bandwidth Allocation per Tc
* (indirect 0x0417)
*/
@@ -1443,6 +1475,8 @@ struct i40e_aqc_configure_switching_comp_bw_config_data {
u8 reserved1[20];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_configure_switching_comp_bw_config_data);
+
/* Query Switching Component Configuration (indirect 0x0418) */
struct i40e_aqc_query_switching_comp_ets_config_resp {
u8 tc_valid_bits;
@@ -1453,6 +1487,8 @@ struct i40e_aqc_query_switching_comp_ets_config_resp {
u8 reserved2[23];
};
+I40E_CHECK_STRUCT_LEN(0x40, i40e_aqc_query_switching_comp_ets_config_resp);
+
/* Query PhysicalPort ETS Configuration (indirect 0x0419) */
struct i40e_aqc_query_port_ets_config_resp {
u8 reserved[4];
@@ -1468,6 +1504,8 @@ struct i40e_aqc_query_port_ets_config_resp {
u8 reserved3[32];
};
+I40E_CHECK_STRUCT_LEN(0x44, i40e_aqc_query_port_ets_config_resp);
+
/* Query Switching Component Bandwidth Allocation per Traffic Type
* (indirect 0x041A)
*/
@@ -1482,6 +1520,8 @@ struct i40e_aqc_query_switching_comp_bw_config_resp {
__le16 tc_bw_max[2];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_query_switching_comp_bw_config_resp);
+
/* Suspend/resume port TX traffic
* (direct 0x041B and 0x041C) uses the generic SEID struct
*/
@@ -1495,6 +1535,8 @@ struct i40e_aqc_configure_partition_bw_data {
u8 max_bw[16]; /* bandwidth limit */
};
+I40E_CHECK_STRUCT_LEN(0x22, i40e_aqc_configure_partition_bw_data);
+
/* Get and set the active HMC resource profile and status.
* (direct 0x0500) and (direct 0x0501)
*/
@@ -1577,6 +1619,8 @@ struct i40e_aqc_module_desc {
u8 reserved2[8];
};
+I40E_CHECK_STRUCT_LEN(0x20, i40e_aqc_module_desc);
+
struct i40e_aq_get_phy_abilities_resp {
__le32 phy_type; /* bitmap using the above enum for offsets */
u8 link_speed; /* bitmap using the above enum bit patterns */
@@ -1605,6 +1649,8 @@ struct i40e_aq_get_phy_abilities_resp {
struct i40e_aqc_module_desc qualified_module[I40E_AQ_PHY_MAX_QMS];
};
+I40E_CHECK_STRUCT_LEN(0x218, i40e_aq_get_phy_abilities_resp);
+
/* Set PHY Config (direct 0x0601) */
struct i40e_aq_set_phy_config { /* same bits as above in all */
__le32 phy_type;
@@ -1788,12 +1834,12 @@ I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_update);
/* NVM Config Read (indirect 0x0704) */
struct i40e_aqc_nvm_config_read {
__le16 cmd_flags;
-#define ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
-#define ANVM_READ_SINGLE_FEATURE 0
-#define ANVM_READ_MULTIPLE_FEATURES 1
+#define I40E_AQ_ANVM_SINGLE_OR_MULTIPLE_FEATURES_MASK 1
+#define I40E_AQ_ANVM_READ_SINGLE_FEATURE 0
+#define I40E_AQ_ANVM_READ_MULTIPLE_FEATURES 1
__le16 element_count;
- __le16 element_id; /* Feature/field ID */
- u8 reserved[2];
+ __le16 element_id; /* Feature/field ID */
+ __le16 element_id_msw; /* MSWord of field ID */
__le32 address_high;
__le32 address_low;
};
@@ -1811,21 +1857,32 @@ struct i40e_aqc_nvm_config_write {
I40E_CHECK_CMD_LENGTH(i40e_aqc_nvm_config_write);
+/* Used for 0x0704 as well as for 0x0705 commands */
+#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT 1
+#define I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_MASK \
+ (1 << I40E_AQ_ANVM_FEATURE_OR_IMMEDIATE_SHIFT)
+#define I40E_AQ_ANVM_FEATURE 0
+#define I40E_AQ_ANVM_IMMEDIATE_FIELD (1 << FEATURE_OR_IMMEDIATE_SHIFT)
struct i40e_aqc_nvm_config_data_feature {
__le16 feature_id;
- __le16 instance_id;
+#define I40E_AQ_ANVM_FEATURE_OPTION_OEM_ONLY 0x01
+#define I40E_AQ_ANVM_FEATURE_OPTION_DWORD_MAP 0x08
+#define I40E_AQ_ANVM_FEATURE_OPTION_POR_CSR 0x10
__le16 feature_options;
__le16 feature_selection;
};
+I40E_CHECK_STRUCT_LEN(0x6, i40e_aqc_nvm_config_data_feature);
+
struct i40e_aqc_nvm_config_data_immediate_field {
-#define ANVM_FEATURE_OR_IMMEDIATE_MASK 0x2
- __le16 field_id;
- __le16 instance_id;
+ __le32 field_id;
+ __le32 field_value;
__le16 field_options;
- __le16 field_value;
+ __le16 reserved;
};
+I40E_CHECK_STRUCT_LEN(0xc, i40e_aqc_nvm_config_data_immediate_field);
+
/* Send to PF command (indirect 0x0801) id is only used by PF
* Send to VF command (indirect 0x0802) id is only used by PF
* Send to Peer PF command (indirect 0x0803)
@@ -2082,7 +2139,8 @@ struct i40e_aqc_oem_param_change {
#define I40E_AQ_OEM_PARAM_TYPE_BW_CTL 1
#define I40E_AQ_OEM_PARAM_MAC 2
__le32 param_value1;
- u8 param_value2[8];
+ __le16 param_value2;
+ u8 reserved[6];
};
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_param_change);
@@ -2096,6 +2154,28 @@ struct i40e_aqc_oem_state_change {
I40E_CHECK_CMD_LENGTH(i40e_aqc_oem_state_change);
+/* Initialize OCSD (0xFE02, direct) */
+struct i40e_aqc_opc_oem_ocsd_initialize {
+ u8 type_status;
+ u8 reserved1[3];
+ __le32 ocsd_memory_block_addr_high;
+ __le32 ocsd_memory_block_addr_low;
+ __le32 requested_update_interval;
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocsd_initialize);
+
+/* Initialize OCBB (0xFE03, direct) */
+struct i40e_aqc_opc_oem_ocbb_initialize {
+ u8 type_status;
+ u8 reserved1[3];
+ __le32 ocbb_memory_block_addr_high;
+ __le32 ocbb_memory_block_addr_low;
+ u8 reserved2[4];
+};
+
+I40E_CHECK_CMD_LENGTH(i40e_aqc_opc_oem_ocbb_initialize);
+
/* debug commands */
/* get device id (0xFF00) uses the generic structure */
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
index 04c7c1557a0c..29004382f462 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.c
@@ -192,6 +192,8 @@ static inline u32 i40e_get_head(struct i40e_ring *tx_ring)
return le32_to_cpu(*(volatile __le32 *)head);
}
+#define WB_STRIDE 0x3
+
/**
* i40e_clean_tx_irq - Reclaim resources after transmit completes
* @tx_ring: tx ring to clean
@@ -293,6 +295,14 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
tx_ring->q_vector->tx.total_bytes += total_bytes;
tx_ring->q_vector->tx.total_packets += total_packets;
+ if (budget &&
+ !((i & WB_STRIDE) == WB_STRIDE) &&
+ !test_bit(__I40E_DOWN, &tx_ring->vsi->state) &&
+ (I40E_DESC_UNUSED(tx_ring) != tx_ring->count))
+ tx_ring->arm_wb = true;
+ else
+ tx_ring->arm_wb = false;
+
if (check_for_tx_hang(tx_ring) && i40e_check_tx_hang(tx_ring)) {
/* schedule immediate reset if we believe we hung */
dev_info(tx_ring->dev, "Detected Tx Unit Hang\n"
@@ -344,6 +354,24 @@ static bool i40e_clean_tx_irq(struct i40e_ring *tx_ring, int budget)
}
/**
+ * i40e_force_wb -Arm hardware to do a wb on noncache aligned descriptors
+ * @vsi: the VSI we care about
+ * @q_vector: the vector on which to force writeback
+ *
+ **/
+static void i40e_force_wb(struct i40e_vsi *vsi, struct i40e_q_vector *q_vector)
+{
+ u32 val = I40E_VFINT_DYN_CTLN_INTENA_MASK |
+ I40E_VFINT_DYN_CTLN_SWINT_TRIG_MASK |
+ I40E_VFINT_DYN_CTLN_SW_ITR_INDX_ENA_MASK;
+ /* allow 00 to be written to the index */
+
+ wr32(&vsi->back->hw,
+ I40E_VFINT_DYN_CTLN1(q_vector->v_idx + vsi->base_vector - 1),
+ val);
+}
+
+/**
* i40e_set_new_dynamic_itr - Find new ITR level
* @rc: structure containing ring performance data
*
@@ -568,6 +596,8 @@ int i40evf_setup_rx_descriptors(struct i40e_ring *rx_ring)
if (!rx_ring->rx_bi)
goto err;
+ u64_stats_init(&rx_ring->syncp);
+
/* Round up to nearest 4K */
rx_ring->size = ring_is_16byte_desc_enabled(rx_ring)
? rx_ring->count * sizeof(union i40e_16byte_rx_desc)
@@ -1065,6 +1095,7 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
struct i40e_vsi *vsi = q_vector->vsi;
struct i40e_ring *ring;
bool clean_complete = true;
+ bool arm_wb = false;
int budget_per_ring;
if (test_bit(__I40E_DOWN, &vsi->state)) {
@@ -1075,8 +1106,10 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
/* Since the actual Tx work is minimal, we can give the Tx a larger
* budget and be more aggressive about cleaning up the Tx descriptors.
*/
- i40e_for_each_ring(ring, q_vector->tx)
+ i40e_for_each_ring(ring, q_vector->tx) {
clean_complete &= i40e_clean_tx_irq(ring, vsi->work_limit);
+ arm_wb |= ring->arm_wb;
+ }
/* We attempt to distribute budget to each Rx queue fairly, but don't
* allow the budget to go below 1 because that would exit polling early.
@@ -1087,8 +1120,11 @@ int i40evf_napi_poll(struct napi_struct *napi, int budget)
clean_complete &= i40e_clean_rx_irq(ring, budget_per_ring);
/* If work not completed, return budget and polling will return */
- if (!clean_complete)
+ if (!clean_complete) {
+ if (arm_wb)
+ i40e_force_wb(vsi, q_vector);
return budget;
+ }
/* Work is done so exit the polling mode and re-enable the interrupt */
napi_complete(napi);
@@ -1122,8 +1158,8 @@ static int i40e_tx_prepare_vlan_flags(struct sk_buff *skb,
u32 tx_flags = 0;
/* if we have a HW VLAN tag being added, default to the HW one */
- if (vlan_tx_tag_present(skb)) {
- tx_flags |= vlan_tx_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT;
+ if (skb_vlan_tag_present(skb)) {
+ tx_flags |= skb_vlan_tag_get(skb) << I40E_TX_FLAGS_VLAN_SHIFT;
tx_flags |= I40E_TX_FLAGS_HW_VLAN;
/* else if it is a SW VLAN, check the next protocol and store the tag */
} else if (protocol == htons(ETH_P_8021Q)) {
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
index c7f29626eada..4e15903b2b6d 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_txrx.h
@@ -238,6 +238,7 @@ struct i40e_ring {
u8 atr_count;
bool ring_active; /* is ring online or not */
+ bool arm_wb; /* do something to arm write back */
/* stats structs */
struct i40e_queue_stats stats;
diff --git a/drivers/net/ethernet/intel/i40evf/i40e_type.h b/drivers/net/ethernet/intel/i40evf/i40e_type.h
index 68aec11f6523..3d0fdaab5cc8 100644
--- a/drivers/net/ethernet/intel/i40evf/i40e_type.h
+++ b/drivers/net/ethernet/intel/i40evf/i40e_type.h
@@ -211,6 +211,7 @@ struct i40e_hw_capabilities {
bool evb_802_1_qbh; /* Bridge Port Extension */
bool dcb;
bool fcoe;
+ bool iscsi; /* Indicates iSCSI enabled */
bool mfp_mode_1;
bool mgmt_cem;
bool ieee_1588;
@@ -425,7 +426,7 @@ struct i40e_hw {
u8 __iomem *hw_addr;
void *back;
- /* function pointer structs */
+ /* subsystem structs */
struct i40e_phy_info phy;
struct i40e_mac_info mac;
struct i40e_bus_info bus;
@@ -452,6 +453,11 @@ struct i40e_hw {
u8 pf_id;
u16 main_vsi_seid;
+ /* for multi-function MACs */
+ u16 partition_id;
+ u16 num_partitions;
+ u16 num_ports;
+
/* Closest numa node to the device */
u16 numa_node;
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_main.c b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
index cabaf599f562..8d8c201c63c1 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_main.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_main.c
@@ -36,7 +36,7 @@ char i40evf_driver_name[] = "i40evf";
static const char i40evf_driver_string[] =
"Intel(R) XL710/X710 Virtual Function Network Driver";
-#define DRV_VERSION "1.0.6"
+#define DRV_VERSION "1.2.0"
const char i40evf_driver_version[] = DRV_VERSION;
static const char i40evf_copyright[] =
"Copyright (c) 2013 - 2014 Intel Corporation.";
@@ -313,10 +313,6 @@ static irqreturn_t i40evf_msix_aq(int irq, void *data)
val = val | I40E_PFINT_DYN_CTL0_CLEARPBA_MASK;
wr32(hw, I40E_VFINT_DYN_CTL01, val);
- /* re-enable interrupt causes */
- wr32(hw, I40E_VFINT_ICR0_ENA1, ena_mask);
- wr32(hw, I40E_VFINT_DYN_CTL01, I40E_VFINT_DYN_CTL01_INTENA_MASK);
-
/* schedule work on the private workqueue */
schedule_work(&adapter->adminq_task);
@@ -947,30 +943,6 @@ static int i40evf_up_complete(struct i40evf_adapter *adapter)
}
/**
- * i40evf_clean_all_rx_rings - Free Rx Buffers for all queues
- * @adapter: board private structure
- **/
-static void i40evf_clean_all_rx_rings(struct i40evf_adapter *adapter)
-{
- int i;
-
- for (i = 0; i < adapter->num_active_queues; i++)
- i40evf_clean_rx_ring(adapter->rx_rings[i]);
-}
-
-/**
- * i40evf_clean_all_tx_rings - Free Tx Buffers for all queues
- * @adapter: board private structure
- **/
-static void i40evf_clean_all_tx_rings(struct i40evf_adapter *adapter)
-{
- int i;
-
- for (i = 0; i < adapter->num_active_queues; i++)
- i40evf_clean_tx_ring(adapter->tx_rings[i]);
-}
-
-/**
* i40e_down - Shutdown the connection processing
* @adapter: board private structure
**/
@@ -982,6 +954,12 @@ void i40evf_down(struct i40evf_adapter *adapter)
if (adapter->state == __I40EVF_DOWN)
return;
+ while (test_and_set_bit(__I40EVF_IN_CRITICAL_TASK,
+ &adapter->crit_section))
+ usleep_range(500, 1000);
+
+ i40evf_irq_disable(adapter);
+
/* remove all MAC filters */
list_for_each_entry(f, &adapter->mac_filter_list, list) {
f->remove = true;
@@ -992,25 +970,27 @@ void i40evf_down(struct i40evf_adapter *adapter)
}
if (!(adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED) &&
adapter->state != __I40EVF_RESETTING) {
- adapter->aq_required |= I40EVF_FLAG_AQ_DEL_MAC_FILTER;
+ /* cancel any current operation */
+ adapter->current_op = I40E_VIRTCHNL_OP_UNKNOWN;
+ adapter->aq_pending = 0;
+ /* Schedule operations to close down the HW. Don't wait
+ * here for this to complete. The watchdog is still running
+ * and it will take care of this.
+ */
+ adapter->aq_required = I40EVF_FLAG_AQ_DEL_MAC_FILTER;
adapter->aq_required |= I40EVF_FLAG_AQ_DEL_VLAN_FILTER;
- /* disable receives */
adapter->aq_required |= I40EVF_FLAG_AQ_DISABLE_QUEUES;
- mod_timer_pending(&adapter->watchdog_timer, jiffies + 1);
- msleep(20);
}
netif_tx_disable(netdev);
netif_tx_stop_all_queues(netdev);
- i40evf_irq_disable(adapter);
-
i40evf_napi_disable_all(adapter);
- netif_carrier_off(netdev);
+ msleep(20);
- i40evf_clean_all_tx_rings(adapter);
- i40evf_clean_all_rx_rings(adapter);
+ netif_carrier_off(netdev);
+ clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
}
/**
@@ -1356,8 +1336,13 @@ static void i40evf_watchdog_task(struct work_struct *work)
/* Process admin queue tasks. After init, everything gets done
* here so we don't race on the admin queue.
*/
- if (adapter->aq_pending)
+ if (adapter->aq_pending) {
+ if (!i40evf_asq_done(hw)) {
+ dev_dbg(&adapter->pdev->dev, "Admin queue timeout\n");
+ i40evf_send_api_ver(adapter);
+ }
goto watchdog_done;
+ }
if (adapter->aq_required & I40EVF_FLAG_AQ_MAP_VECTORS) {
i40evf_map_queues(adapter);
@@ -1401,11 +1386,14 @@ static void i40evf_watchdog_task(struct work_struct *work)
if (adapter->state == __I40EVF_RUNNING)
i40evf_request_stats(adapter);
-
- i40evf_irq_enable(adapter, true);
- i40evf_fire_sw_int(adapter, 0xFF);
-
watchdog_done:
+ if (adapter->state == __I40EVF_RUNNING) {
+ i40evf_irq_enable_queues(adapter, ~0);
+ i40evf_fire_sw_int(adapter, 0xFF);
+ } else {
+ i40evf_fire_sw_int(adapter, 0x1);
+ }
+
clear_bit(__I40EVF_IN_CRITICAL_TASK, &adapter->crit_section);
restart_watchdog:
if (adapter->state == __I40EVF_REMOVE)
@@ -1633,17 +1621,17 @@ static void i40evf_adminq_task(struct work_struct *work)
u16 pending;
if (adapter->flags & I40EVF_FLAG_PF_COMMS_FAILED)
- return;
+ goto out;
event.buf_len = I40EVF_MAX_AQ_BUF_SIZE;
event.msg_buf = kzalloc(event.buf_len, GFP_KERNEL);
if (!event.msg_buf)
- return;
+ goto out;
v_msg = (struct i40e_virtchnl_msg *)&event.desc;
do {
ret = i40evf_clean_arq_element(hw, &event, &pending);
- if (ret)
+ if (ret || !v_msg->v_opcode)
break; /* No event to process or error cleaning ARQ */
i40evf_virtchnl_completion(adapter, v_msg->v_opcode,
@@ -1688,10 +1676,10 @@ static void i40evf_adminq_task(struct work_struct *work)
if (oldval != val)
wr32(hw, hw->aq.asq.len, val);
+ kfree(event.msg_buf);
+out:
/* re-enable Admin queue interrupt cause */
i40evf_misc_irq_enable(adapter);
-
- kfree(event.msg_buf);
}
/**
@@ -2053,12 +2041,8 @@ static void i40evf_init_task(struct work_struct *work)
/* aq msg sent, awaiting reply */
err = i40evf_verify_api_ver(adapter);
if (err) {
- dev_info(&pdev->dev, "Unable to verify API version (%d), retrying\n",
- err);
- if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
- dev_info(&pdev->dev, "Resending request\n");
+ if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK)
err = i40evf_send_api_ver(adapter);
- }
goto err;
}
err = i40evf_send_vf_config_msg(adapter);
@@ -2081,7 +2065,6 @@ static void i40evf_init_task(struct work_struct *work)
}
err = i40evf_get_vf_config(adapter);
if (err == I40E_ERR_ADMIN_QUEUE_NO_WORK) {
- dev_info(&pdev->dev, "Resending VF config request\n");
err = i40evf_send_vf_config_msg(adapter);
goto err;
}
@@ -2230,12 +2213,18 @@ err:
static void i40evf_shutdown(struct pci_dev *pdev)
{
struct net_device *netdev = pci_get_drvdata(pdev);
+ struct i40evf_adapter *adapter = netdev_priv(netdev);
netif_device_detach(netdev);
if (netif_running(netdev))
i40evf_close(netdev);
+ /* Prevent the watchdog from running. */
+ adapter->state = __I40EVF_REMOVE;
+ adapter->aq_required = 0;
+ adapter->aq_pending = 0;
+
#ifdef CONFIG_PM
pci_save_state(pdev);
@@ -2448,7 +2437,18 @@ static void i40evf_remove(struct pci_dev *pdev)
unregister_netdev(netdev);
adapter->netdev_registered = false;
}
+
+ /* Shut down all the garbage mashers on the detention level */
adapter->state = __I40EVF_REMOVE;
+ adapter->aq_required = 0;
+ adapter->aq_pending = 0;
+ i40evf_request_reset(adapter);
+ msleep(20);
+ /* If the FW isn't responding, kick it once, but only once. */
+ if (!i40evf_asq_done(hw)) {
+ i40evf_request_reset(adapter);
+ msleep(20);
+ }
if (adapter->msix_entries) {
i40evf_misc_irq_disable(adapter);
@@ -2477,6 +2477,10 @@ static void i40evf_remove(struct pci_dev *pdev)
list_del(&f->list);
kfree(f);
}
+ list_for_each_entry_safe(f, ftmp, &adapter->vlan_filter_list, list) {
+ list_del(&f->list);
+ kfree(f);
+ }
free_netdev(netdev);
diff --git a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
index 5fde5a7f4591..3f0c85ecbca6 100644
--- a/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
+++ b/drivers/net/ethernet/intel/i40evf/i40evf_virtchnl.c
@@ -715,14 +715,14 @@ void i40evf_virtchnl_completion(struct i40evf_adapter *adapter,
}
return;
}
- if (v_opcode != adapter->current_op)
- dev_info(&adapter->pdev->dev, "Pending op is %d, received %d\n",
- adapter->current_op, v_opcode);
if (v_retval) {
dev_err(&adapter->pdev->dev, "%s: PF returned error %d to our request %d\n",
__func__, v_retval, v_opcode);
}
switch (v_opcode) {
+ case I40E_VIRTCHNL_OP_VERSION:
+ /* no action, but also not an error */
+ break;
case I40E_VIRTCHNL_OP_GET_STATS: {
struct i40e_eth_stats *stats =
(struct i40e_eth_stats *)msg;
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 82d891e183b1..c2bd4f98a837 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -29,7 +29,7 @@
#include "e1000_mac.h"
#include "e1000_82575.h"
-#include <linux/clocksource.h>
+#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/bitops.h>
@@ -343,6 +343,9 @@ struct hwmon_buff {
};
#endif
+#define IGB_N_EXTTS 2
+#define IGB_N_PEROUT 2
+#define IGB_N_SDP 4
#define IGB_RETA_SIZE 128
/* board specific private data structure */
@@ -439,6 +442,12 @@ struct igb_adapter {
u32 tx_hwtstamp_timeouts;
u32 rx_hwtstamp_cleared;
+ struct ptp_pin_desc sdp_config[IGB_N_SDP];
+ struct {
+ struct timespec start;
+ struct timespec period;
+ } perout[IGB_N_PEROUT];
+
char fw_version[32];
#ifdef CONFIG_IGB_HWMON
struct hwmon_buff *igb_hwmon_buff;
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index ff59897a9463..f366b3b96d03 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -5035,9 +5035,9 @@ netdev_tx_t igb_xmit_frame_ring(struct sk_buff *skb,
skb_tx_timestamp(skb);
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
tx_flags |= IGB_TX_FLAGS_VLAN;
- tx_flags |= (vlan_tx_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
+ tx_flags |= (skb_vlan_tag_get(skb) << IGB_TX_FLAGS_VLAN_SHIFT);
}
/* record initial flags and protocol */
@@ -5384,6 +5384,80 @@ void igb_update_stats(struct igb_adapter *adapter,
}
}
+static void igb_tsync_interrupt(struct igb_adapter *adapter)
+{
+ struct e1000_hw *hw = &adapter->hw;
+ struct ptp_clock_event event;
+ struct timespec ts;
+ u32 ack = 0, tsauxc, sec, nsec, tsicr = rd32(E1000_TSICR);
+
+ if (tsicr & TSINTR_SYS_WRAP) {
+ event.type = PTP_CLOCK_PPS;
+ if (adapter->ptp_caps.pps)
+ ptp_clock_event(adapter->ptp_clock, &event);
+ else
+ dev_err(&adapter->pdev->dev, "unexpected SYS WRAP");
+ ack |= TSINTR_SYS_WRAP;
+ }
+
+ if (tsicr & E1000_TSICR_TXTS) {
+ /* retrieve hardware timestamp */
+ schedule_work(&adapter->ptp_tx_work);
+ ack |= E1000_TSICR_TXTS;
+ }
+
+ if (tsicr & TSINTR_TT0) {
+ spin_lock(&adapter->tmreg_lock);
+ ts = timespec_add(adapter->perout[0].start,
+ adapter->perout[0].period);
+ wr32(E1000_TRGTTIML0, ts.tv_nsec);
+ wr32(E1000_TRGTTIMH0, ts.tv_sec);
+ tsauxc = rd32(E1000_TSAUXC);
+ tsauxc |= TSAUXC_EN_TT0;
+ wr32(E1000_TSAUXC, tsauxc);
+ adapter->perout[0].start = ts;
+ spin_unlock(&adapter->tmreg_lock);
+ ack |= TSINTR_TT0;
+ }
+
+ if (tsicr & TSINTR_TT1) {
+ spin_lock(&adapter->tmreg_lock);
+ ts = timespec_add(adapter->perout[1].start,
+ adapter->perout[1].period);
+ wr32(E1000_TRGTTIML1, ts.tv_nsec);
+ wr32(E1000_TRGTTIMH1, ts.tv_sec);
+ tsauxc = rd32(E1000_TSAUXC);
+ tsauxc |= TSAUXC_EN_TT1;
+ wr32(E1000_TSAUXC, tsauxc);
+ adapter->perout[1].start = ts;
+ spin_unlock(&adapter->tmreg_lock);
+ ack |= TSINTR_TT1;
+ }
+
+ if (tsicr & TSINTR_AUTT0) {
+ nsec = rd32(E1000_AUXSTMPL0);
+ sec = rd32(E1000_AUXSTMPH0);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 0;
+ event.timestamp = sec * 1000000000ULL + nsec;
+ ptp_clock_event(adapter->ptp_clock, &event);
+ ack |= TSINTR_AUTT0;
+ }
+
+ if (tsicr & TSINTR_AUTT1) {
+ nsec = rd32(E1000_AUXSTMPL1);
+ sec = rd32(E1000_AUXSTMPH1);
+ event.type = PTP_CLOCK_EXTTS;
+ event.index = 1;
+ event.timestamp = sec * 1000000000ULL + nsec;
+ ptp_clock_event(adapter->ptp_clock, &event);
+ ack |= TSINTR_AUTT1;
+ }
+
+ /* acknowledge the interrupts */
+ wr32(E1000_TSICR, ack);
+}
+
static irqreturn_t igb_msix_other(int irq, void *data)
{
struct igb_adapter *adapter = data;
@@ -5415,16 +5489,8 @@ static irqreturn_t igb_msix_other(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
- if (icr & E1000_ICR_TS) {
- u32 tsicr = rd32(E1000_TSICR);
-
- if (tsicr & E1000_TSICR_TXTS) {
- /* acknowledge the interrupt */
- wr32(E1000_TSICR, E1000_TSICR_TXTS);
- /* retrieve hardware timestamp */
- schedule_work(&adapter->ptp_tx_work);
- }
- }
+ if (icr & E1000_ICR_TS)
+ igb_tsync_interrupt(adapter);
wr32(E1000_EIMS, adapter->eims_other);
@@ -6011,8 +6077,12 @@ static void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
adapter->vf_data[vf].flags |= IGB_VF_FLAG_CTS;
/* reply to reset with ack and vf mac address */
- msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
- memcpy(addr, vf_mac, ETH_ALEN);
+ if (!is_zero_ether_addr(vf_mac)) {
+ msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
+ memcpy(addr, vf_mac, ETH_ALEN);
+ } else {
+ msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_NACK;
+ }
igb_write_mbx(hw, msgbuf, 3, vf);
}
@@ -6203,16 +6273,8 @@ static irqreturn_t igb_intr_msi(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
- if (icr & E1000_ICR_TS) {
- u32 tsicr = rd32(E1000_TSICR);
-
- if (tsicr & E1000_TSICR_TXTS) {
- /* acknowledge the interrupt */
- wr32(E1000_TSICR, E1000_TSICR_TXTS);
- /* retrieve hardware timestamp */
- schedule_work(&adapter->ptp_tx_work);
- }
- }
+ if (icr & E1000_ICR_TS)
+ igb_tsync_interrupt(adapter);
napi_schedule(&q_vector->napi);
@@ -6257,16 +6319,8 @@ static irqreturn_t igb_intr(int irq, void *data)
mod_timer(&adapter->watchdog_timer, jiffies + 1);
}
- if (icr & E1000_ICR_TS) {
- u32 tsicr = rd32(E1000_TSICR);
-
- if (tsicr & E1000_TSICR_TXTS) {
- /* acknowledge the interrupt */
- wr32(E1000_TSICR, E1000_TSICR_TXTS);
- /* retrieve hardware timestamp */
- schedule_work(&adapter->ptp_tx_work);
- }
- }
+ if (icr & E1000_ICR_TS)
+ igb_tsync_interrupt(adapter);
napi_schedule(&q_vector->napi);
@@ -6527,15 +6581,17 @@ static void igb_reuse_rx_page(struct igb_ring *rx_ring,
DMA_FROM_DEVICE);
}
+static inline bool igb_page_is_reserved(struct page *page)
+{
+ return (page_to_nid(page) != numa_mem_id()) || page->pfmemalloc;
+}
+
static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
struct page *page,
unsigned int truesize)
{
/* avoid re-using remote pages */
- if (unlikely(page_to_nid(page) != numa_node_id()))
- return false;
-
- if (unlikely(page->pfmemalloc))
+ if (unlikely(igb_page_is_reserved(page)))
return false;
#if (PAGE_SIZE < 8192)
@@ -6545,22 +6601,19 @@ static bool igb_can_reuse_rx_page(struct igb_rx_buffer *rx_buffer,
/* flip page offset to other buffer */
rx_buffer->page_offset ^= IGB_RX_BUFSZ;
-
- /* Even if we own the page, we are not allowed to use atomic_set()
- * This would break get_page_unless_zero() users.
- */
- atomic_inc(&page->_count);
#else
/* move offset up to the next cache line */
rx_buffer->page_offset += truesize;
if (rx_buffer->page_offset > (PAGE_SIZE - IGB_RX_BUFSZ))
return false;
-
- /* bump ref count on page before it is given to the stack */
- get_page(page);
#endif
+ /* Even if we own the page, we are not allowed to use atomic_set()
+ * This would break get_page_unless_zero() users.
+ */
+ atomic_inc(&page->_count);
+
return true;
}
@@ -6603,13 +6656,12 @@ static bool igb_add_rx_frag(struct igb_ring *rx_ring,
memcpy(__skb_put(skb, size), va, ALIGN(size, sizeof(long)));
- /* we can reuse buffer as-is, just make sure it is local */
- if (likely((page_to_nid(page) == numa_node_id()) &&
- !page->pfmemalloc))
+ /* page is not reserved, we can reuse buffer as-is */
+ if (likely(!igb_page_is_reserved(page)))
return true;
/* this page cannot be reused so discard it */
- put_page(page);
+ __free_page(page);
return false;
}
@@ -6627,7 +6679,6 @@ static struct sk_buff *igb_fetch_rx_buffer(struct igb_ring *rx_ring,
struct page *page;
rx_buffer = &rx_ring->rx_buffer_info[rx_ring->next_to_clean];
-
page = rx_buffer->page;
prefetchw(page);
@@ -7042,8 +7093,8 @@ void igb_alloc_rx_buffers(struct igb_ring *rx_ring, u16 cleaned_count)
i -= rx_ring->count;
}
- /* clear the hdr_addr for the next_to_use descriptor */
- rx_desc->read.hdr_addr = 0;
+ /* clear the status bits for the next_to_use descriptor */
+ rx_desc->wb.upper.status_error = 0;
cleaned_count--;
} while (cleaned_count);
diff --git a/drivers/net/ethernet/intel/igb/igb_ptp.c b/drivers/net/ethernet/intel/igb/igb_ptp.c
index 794c139f0cc0..d20fc8ed11f1 100644
--- a/drivers/net/ethernet/intel/igb/igb_ptp.c
+++ b/drivers/net/ethernet/intel/igb/igb_ptp.c
@@ -256,14 +256,9 @@ static int igb_ptp_adjtime_82576(struct ptp_clock_info *ptp, s64 delta)
struct igb_adapter *igb = container_of(ptp, struct igb_adapter,
ptp_caps);
unsigned long flags;
- s64 now;
spin_lock_irqsave(&igb->tmreg_lock, flags);
-
- now = timecounter_read(&igb->tc);
- now += delta;
- timecounter_init(&igb->tc, &igb->cc, now);
-
+ timecounter_adjtime(&igb->tc, delta);
spin_unlock_irqrestore(&igb->tmreg_lock, flags);
return 0;
@@ -360,12 +355,239 @@ static int igb_ptp_settime_i210(struct ptp_clock_info *ptp,
return 0;
}
+static void igb_pin_direction(int pin, int input, u32 *ctrl, u32 *ctrl_ext)
+{
+ u32 *ptr = pin < 2 ? ctrl : ctrl_ext;
+ u32 mask[IGB_N_SDP] = {
+ E1000_CTRL_SDP0_DIR,
+ E1000_CTRL_SDP1_DIR,
+ E1000_CTRL_EXT_SDP2_DIR,
+ E1000_CTRL_EXT_SDP3_DIR,
+ };
+
+ if (input)
+ *ptr &= ~mask[pin];
+ else
+ *ptr |= mask[pin];
+}
+
+static void igb_pin_extts(struct igb_adapter *igb, int chan, int pin)
+{
+ struct e1000_hw *hw = &igb->hw;
+ u32 aux0_sel_sdp[IGB_N_SDP] = {
+ AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3,
+ };
+ u32 aux1_sel_sdp[IGB_N_SDP] = {
+ AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3,
+ };
+ u32 ts_sdp_en[IGB_N_SDP] = {
+ TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN,
+ };
+ u32 ctrl, ctrl_ext, tssdp = 0;
+
+ ctrl = rd32(E1000_CTRL);
+ ctrl_ext = rd32(E1000_CTRL_EXT);
+ tssdp = rd32(E1000_TSSDP);
+
+ igb_pin_direction(pin, 1, &ctrl, &ctrl_ext);
+
+ /* Make sure this pin is not enabled as an output. */
+ tssdp &= ~ts_sdp_en[pin];
+
+ if (chan == 1) {
+ tssdp &= ~AUX1_SEL_SDP3;
+ tssdp |= aux1_sel_sdp[pin] | AUX1_TS_SDP_EN;
+ } else {
+ tssdp &= ~AUX0_SEL_SDP3;
+ tssdp |= aux0_sel_sdp[pin] | AUX0_TS_SDP_EN;
+ }
+
+ wr32(E1000_TSSDP, tssdp);
+ wr32(E1000_CTRL, ctrl);
+ wr32(E1000_CTRL_EXT, ctrl_ext);
+}
+
+static void igb_pin_perout(struct igb_adapter *igb, int chan, int pin)
+{
+ struct e1000_hw *hw = &igb->hw;
+ u32 aux0_sel_sdp[IGB_N_SDP] = {
+ AUX0_SEL_SDP0, AUX0_SEL_SDP1, AUX0_SEL_SDP2, AUX0_SEL_SDP3,
+ };
+ u32 aux1_sel_sdp[IGB_N_SDP] = {
+ AUX1_SEL_SDP0, AUX1_SEL_SDP1, AUX1_SEL_SDP2, AUX1_SEL_SDP3,
+ };
+ u32 ts_sdp_en[IGB_N_SDP] = {
+ TS_SDP0_EN, TS_SDP1_EN, TS_SDP2_EN, TS_SDP3_EN,
+ };
+ u32 ts_sdp_sel_tt0[IGB_N_SDP] = {
+ TS_SDP0_SEL_TT0, TS_SDP1_SEL_TT0,
+ TS_SDP2_SEL_TT0, TS_SDP3_SEL_TT0,
+ };
+ u32 ts_sdp_sel_tt1[IGB_N_SDP] = {
+ TS_SDP0_SEL_TT1, TS_SDP1_SEL_TT1,
+ TS_SDP2_SEL_TT1, TS_SDP3_SEL_TT1,
+ };
+ u32 ts_sdp_sel_clr[IGB_N_SDP] = {
+ TS_SDP0_SEL_FC1, TS_SDP1_SEL_FC1,
+ TS_SDP2_SEL_FC1, TS_SDP3_SEL_FC1,
+ };
+ u32 ctrl, ctrl_ext, tssdp = 0;
+
+ ctrl = rd32(E1000_CTRL);
+ ctrl_ext = rd32(E1000_CTRL_EXT);
+ tssdp = rd32(E1000_TSSDP);
+
+ igb_pin_direction(pin, 0, &ctrl, &ctrl_ext);
+
+ /* Make sure this pin is not enabled as an input. */
+ if ((tssdp & AUX0_SEL_SDP3) == aux0_sel_sdp[pin])
+ tssdp &= ~AUX0_TS_SDP_EN;
+
+ if ((tssdp & AUX1_SEL_SDP3) == aux1_sel_sdp[pin])
+ tssdp &= ~AUX1_TS_SDP_EN;
+
+ tssdp &= ~ts_sdp_sel_clr[pin];
+ if (chan == 1)
+ tssdp |= ts_sdp_sel_tt1[pin];
+ else
+ tssdp |= ts_sdp_sel_tt0[pin];
+
+ tssdp |= ts_sdp_en[pin];
+
+ wr32(E1000_TSSDP, tssdp);
+ wr32(E1000_CTRL, ctrl);
+ wr32(E1000_CTRL_EXT, ctrl_ext);
+}
+
+static int igb_ptp_feature_enable_i210(struct ptp_clock_info *ptp,
+ struct ptp_clock_request *rq, int on)
+{
+ struct igb_adapter *igb =
+ container_of(ptp, struct igb_adapter, ptp_caps);
+ struct e1000_hw *hw = &igb->hw;
+ u32 tsauxc, tsim, tsauxc_mask, tsim_mask, trgttiml, trgttimh;
+ unsigned long flags;
+ struct timespec ts;
+ int pin;
+ s64 ns;
+
+ switch (rq->type) {
+ case PTP_CLK_REQ_EXTTS:
+ if (on) {
+ pin = ptp_find_pin(igb->ptp_clock, PTP_PF_EXTTS,
+ rq->extts.index);
+ if (pin < 0)
+ return -EBUSY;
+ }
+ if (rq->extts.index == 1) {
+ tsauxc_mask = TSAUXC_EN_TS1;
+ tsim_mask = TSINTR_AUTT1;
+ } else {
+ tsauxc_mask = TSAUXC_EN_TS0;
+ tsim_mask = TSINTR_AUTT0;
+ }
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+ tsauxc = rd32(E1000_TSAUXC);
+ tsim = rd32(E1000_TSIM);
+ if (on) {
+ igb_pin_extts(igb, rq->extts.index, pin);
+ tsauxc |= tsauxc_mask;
+ tsim |= tsim_mask;
+ } else {
+ tsauxc &= ~tsauxc_mask;
+ tsim &= ~tsim_mask;
+ }
+ wr32(E1000_TSAUXC, tsauxc);
+ wr32(E1000_TSIM, tsim);
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+ return 0;
+
+ case PTP_CLK_REQ_PEROUT:
+ if (on) {
+ pin = ptp_find_pin(igb->ptp_clock, PTP_PF_PEROUT,
+ rq->perout.index);
+ if (pin < 0)
+ return -EBUSY;
+ }
+ ts.tv_sec = rq->perout.period.sec;
+ ts.tv_nsec = rq->perout.period.nsec;
+ ns = timespec_to_ns(&ts);
+ ns = ns >> 1;
+ if (on && ns < 500000LL) {
+ /* 2k interrupts per second is an awful lot. */
+ return -EINVAL;
+ }
+ ts = ns_to_timespec(ns);
+ if (rq->perout.index == 1) {
+ tsauxc_mask = TSAUXC_EN_TT1;
+ tsim_mask = TSINTR_TT1;
+ trgttiml = E1000_TRGTTIML1;
+ trgttimh = E1000_TRGTTIMH1;
+ } else {
+ tsauxc_mask = TSAUXC_EN_TT0;
+ tsim_mask = TSINTR_TT0;
+ trgttiml = E1000_TRGTTIML0;
+ trgttimh = E1000_TRGTTIMH0;
+ }
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+ tsauxc = rd32(E1000_TSAUXC);
+ tsim = rd32(E1000_TSIM);
+ if (on) {
+ int i = rq->perout.index;
+
+ igb_pin_perout(igb, i, pin);
+ igb->perout[i].start.tv_sec = rq->perout.start.sec;
+ igb->perout[i].start.tv_nsec = rq->perout.start.nsec;
+ igb->perout[i].period.tv_sec = ts.tv_sec;
+ igb->perout[i].period.tv_nsec = ts.tv_nsec;
+ wr32(trgttiml, rq->perout.start.sec);
+ wr32(trgttimh, rq->perout.start.nsec);
+ tsauxc |= tsauxc_mask;
+ tsim |= tsim_mask;
+ } else {
+ tsauxc &= ~tsauxc_mask;
+ tsim &= ~tsim_mask;
+ }
+ wr32(E1000_TSAUXC, tsauxc);
+ wr32(E1000_TSIM, tsim);
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+ return 0;
+
+ case PTP_CLK_REQ_PPS:
+ spin_lock_irqsave(&igb->tmreg_lock, flags);
+ tsim = rd32(E1000_TSIM);
+ if (on)
+ tsim |= TSINTR_SYS_WRAP;
+ else
+ tsim &= ~TSINTR_SYS_WRAP;
+ wr32(E1000_TSIM, tsim);
+ spin_unlock_irqrestore(&igb->tmreg_lock, flags);
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+
static int igb_ptp_feature_enable(struct ptp_clock_info *ptp,
struct ptp_clock_request *rq, int on)
{
return -EOPNOTSUPP;
}
+static int igb_ptp_verify_pin(struct ptp_clock_info *ptp, unsigned int pin,
+ enum ptp_pin_function func, unsigned int chan)
+{
+ switch (func) {
+ case PTP_PF_NONE:
+ case PTP_PF_EXTTS:
+ case PTP_PF_PEROUT:
+ break;
+ case PTP_PF_PHYSYNC:
+ return -1;
+ }
+ return 0;
+}
+
/**
* igb_ptp_tx_work
* @work: pointer to work struct
@@ -756,6 +978,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
struct net_device *netdev = adapter->netdev;
+ int i;
switch (hw->mac.type) {
case e1000_82576:
@@ -770,7 +993,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->ptp_caps.settime = igb_ptp_settime_82576;
adapter->ptp_caps.enable = igb_ptp_feature_enable;
adapter->cc.read = igb_ptp_read_82576;
- adapter->cc.mask = CLOCKSOURCE_MASK(64);
+ adapter->cc.mask = CYCLECOUNTER_MASK(64);
adapter->cc.mult = 1;
adapter->cc.shift = IGB_82576_TSYNC_SHIFT;
/* Dial the nominal frequency. */
@@ -790,7 +1013,7 @@ void igb_ptp_init(struct igb_adapter *adapter)
adapter->ptp_caps.settime = igb_ptp_settime_82576;
adapter->ptp_caps.enable = igb_ptp_feature_enable;
adapter->cc.read = igb_ptp_read_82580;
- adapter->cc.mask = CLOCKSOURCE_MASK(IGB_NBITS_82580);
+ adapter->cc.mask = CYCLECOUNTER_MASK(IGB_NBITS_82580);
adapter->cc.mult = 1;
adapter->cc.shift = 0;
/* Enable the timer functions by clearing bit 31. */
@@ -798,16 +1021,27 @@ void igb_ptp_init(struct igb_adapter *adapter)
break;
case e1000_i210:
case e1000_i211:
+ for (i = 0; i < IGB_N_SDP; i++) {
+ struct ptp_pin_desc *ppd = &adapter->sdp_config[i];
+
+ snprintf(ppd->name, sizeof(ppd->name), "SDP%d", i);
+ ppd->index = i;
+ ppd->func = PTP_PF_NONE;
+ }
snprintf(adapter->ptp_caps.name, 16, "%pm", netdev->dev_addr);
adapter->ptp_caps.owner = THIS_MODULE;
adapter->ptp_caps.max_adj = 62499999;
- adapter->ptp_caps.n_ext_ts = 0;
- adapter->ptp_caps.pps = 0;
+ adapter->ptp_caps.n_ext_ts = IGB_N_EXTTS;
+ adapter->ptp_caps.n_per_out = IGB_N_PEROUT;
+ adapter->ptp_caps.n_pins = IGB_N_SDP;
+ adapter->ptp_caps.pps = 1;
+ adapter->ptp_caps.pin_config = adapter->sdp_config;
adapter->ptp_caps.adjfreq = igb_ptp_adjfreq_82580;
adapter->ptp_caps.adjtime = igb_ptp_adjtime_i210;
adapter->ptp_caps.gettime = igb_ptp_gettime_i210;
adapter->ptp_caps.settime = igb_ptp_settime_i210;
- adapter->ptp_caps.enable = igb_ptp_feature_enable;
+ adapter->ptp_caps.enable = igb_ptp_feature_enable_i210;
+ adapter->ptp_caps.verify = igb_ptp_verify_pin;
/* Enable the timer functions by clearing bit 31. */
wr32(E1000_TSAUXC, 0x0);
break;
@@ -905,6 +1139,7 @@ void igb_ptp_stop(struct igb_adapter *adapter)
void igb_ptp_reset(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
+ unsigned long flags;
if (!(adapter->flags & IGB_FLAG_PTP))
return;
@@ -912,6 +1147,8 @@ void igb_ptp_reset(struct igb_adapter *adapter)
/* reset the tstamp_config */
igb_ptp_set_timestamp_mode(adapter, &adapter->tstamp_config);
+ spin_lock_irqsave(&adapter->tmreg_lock, flags);
+
switch (adapter->hw.mac.type) {
case e1000_82576:
/* Dial the nominal frequency. */
@@ -922,23 +1159,25 @@ void igb_ptp_reset(struct igb_adapter *adapter)
case e1000_i350:
case e1000_i210:
case e1000_i211:
- /* Enable the timer functions and interrupts. */
wr32(E1000_TSAUXC, 0x0);
+ wr32(E1000_TSSDP, 0x0);
wr32(E1000_TSIM, TSYNC_INTERRUPTS);
wr32(E1000_IMS, E1000_IMS_TS);
break;
default:
/* No work to do. */
- return;
+ goto out;
}
/* Re-initialize the timer. */
if ((hw->mac.type == e1000_i210) || (hw->mac.type == e1000_i211)) {
struct timespec ts = ktime_to_timespec(ktime_get_real());
- igb_ptp_settime_i210(&adapter->ptp_caps, &ts);
+ igb_ptp_write_i210(adapter, &ts);
} else {
timecounter_init(&adapter->tc, &adapter->cc,
ktime_to_ns(ktime_get_real()));
}
+out:
+ spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
}
diff --git a/drivers/net/ethernet/intel/igbvf/netdev.c b/drivers/net/ethernet/intel/igbvf/netdev.c
index 63c807c9b21c..ebf9d4a42fdd 100644
--- a/drivers/net/ethernet/intel/igbvf/netdev.c
+++ b/drivers/net/ethernet/intel/igbvf/netdev.c
@@ -1907,7 +1907,8 @@ static void igbvf_watchdog_task(struct work_struct *work)
static int igbvf_tso(struct igbvf_adapter *adapter,
struct igbvf_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags, u8 *hdr_len)
+ struct sk_buff *skb, u32 tx_flags, u8 *hdr_len,
+ __be16 protocol)
{
struct e1000_adv_tx_context_desc *context_desc;
struct igbvf_buffer *buffer_info;
@@ -1927,7 +1928,7 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
l4len = tcp_hdrlen(skb);
*hdr_len += l4len;
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = 0;
iph->check = 0;
@@ -1958,7 +1959,7 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
- if (skb->protocol == htons(ETH_P_IP))
+ if (protocol == htons(ETH_P_IP))
tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
tu_cmd |= E1000_ADVTXD_TUCMD_L4T_TCP;
@@ -1984,7 +1985,8 @@ static int igbvf_tso(struct igbvf_adapter *adapter,
static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
struct igbvf_ring *tx_ring,
- struct sk_buff *skb, u32 tx_flags)
+ struct sk_buff *skb, u32 tx_flags,
+ __be16 protocol)
{
struct e1000_adv_tx_context_desc *context_desc;
unsigned int i;
@@ -2011,7 +2013,7 @@ static inline bool igbvf_tx_csum(struct igbvf_adapter *adapter,
tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
- switch (skb->protocol) {
+ switch (protocol) {
case htons(ETH_P_IP):
tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
if (ip_hdr(skb)->protocol == IPPROTO_TCP)
@@ -2211,6 +2213,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
u8 hdr_len = 0;
int count = 0;
int tso = 0;
+ __be16 protocol = vlan_get_protocol(skb);
if (test_bit(__IGBVF_DOWN, &adapter->state)) {
dev_kfree_skb_any(skb);
@@ -2234,18 +2237,19 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
return NETDEV_TX_BUSY;
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
tx_flags |= IGBVF_TX_FLAGS_VLAN;
- tx_flags |= (vlan_tx_tag_get(skb) << IGBVF_TX_FLAGS_VLAN_SHIFT);
+ tx_flags |= (skb_vlan_tag_get(skb) <<
+ IGBVF_TX_FLAGS_VLAN_SHIFT);
}
- if (skb->protocol == htons(ETH_P_IP))
+ if (protocol == htons(ETH_P_IP))
tx_flags |= IGBVF_TX_FLAGS_IPV4;
first = tx_ring->next_to_use;
tso = skb_is_gso(skb) ?
- igbvf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len) : 0;
+ igbvf_tso(adapter, tx_ring, skb, tx_flags, &hdr_len, protocol) : 0;
if (unlikely(tso < 0)) {
dev_kfree_skb_any(skb);
return NETDEV_TX_OK;
@@ -2253,7 +2257,7 @@ static netdev_tx_t igbvf_xmit_frame_ring_adv(struct sk_buff *skb,
if (tso)
tx_flags |= IGBVF_TX_FLAGS_TSO;
- else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags) &&
+ else if (igbvf_tx_csum(adapter, tx_ring, skb, tx_flags, protocol) &&
(skb->ip_summed == CHECKSUM_PARTIAL))
tx_flags |= IGBVF_TX_FLAGS_CSUM;
diff --git a/drivers/net/ethernet/intel/ixgb/ixgb_main.c b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
index aa87605b144a..11a1bdbe3fd9 100644
--- a/drivers/net/ethernet/intel/ixgb/ixgb_main.c
+++ b/drivers/net/ethernet/intel/ixgb/ixgb_main.c
@@ -1532,9 +1532,9 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
DESC_NEEDED)))
return NETDEV_TX_BUSY;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
tx_flags |= IXGB_TX_FLAGS_VLAN;
- vlan_id = vlan_tx_tag_get(skb);
+ vlan_id = skb_vlan_tag_get(skb);
}
first = adapter->tx_ring.next_to_use;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index b6137be43920..7dcbbec09a70 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -38,7 +38,7 @@
#include <linux/if_vlan.h>
#include <linux/jiffies.h>
-#include <linux/clocksource.h>
+#include <linux/timecounter.h>
#include <linux/net_tstamp.h>
#include <linux/ptp_clock_kernel.h>
@@ -76,6 +76,8 @@
#define IXGBE_MAX_RXD 4096
#define IXGBE_MIN_RXD 64
+#define IXGBE_ETH_P_LLDP 0x88CC
+
/* flow control */
#define IXGBE_MIN_FCRTL 0x40
#define IXGBE_MAX_FCRTL 0x7FF80
@@ -753,6 +755,7 @@ struct ixgbe_adapter {
u32 timer_event_accumulator;
u32 vferr_refcount;
struct ixgbe_mac_addr *mac_table;
+ u16 vxlan_port;
struct kobject *info_kobj;
#ifdef CONFIG_IXGBE_HWMON
struct hwmon_buff *ixgbe_hwmon_buff;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index 2ed2c7de2304..70cc4c5c0a01 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -50,6 +50,7 @@
#include <linux/if_bridge.h>
#include <linux/prefetch.h>
#include <scsi/fc/fc_fcoe.h>
+#include <net/vxlan.h>
#ifdef CONFIG_OF
#include <linux/of_net.h>
@@ -1396,12 +1397,23 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
union ixgbe_adv_rx_desc *rx_desc,
struct sk_buff *skb)
{
+ __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
+ __le16 hdr_info = rx_desc->wb.lower.lo_dword.hs_rss.hdr_info;
+ bool encap_pkt = false;
+
skb_checksum_none_assert(skb);
/* Rx csum disabled */
if (!(ring->netdev->features & NETIF_F_RXCSUM))
return;
+ if ((pkt_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_VXLAN)) &&
+ (hdr_info & cpu_to_le16(IXGBE_RXDADV_PKTTYPE_TUNNEL >> 16))) {
+ encap_pkt = true;
+ skb->encapsulation = 1;
+ skb->ip_summed = CHECKSUM_NONE;
+ }
+
/* if IP and error */
if (ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_IPCS) &&
ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_IPE)) {
@@ -1413,8 +1425,6 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
return;
if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_TCPE)) {
- __le16 pkt_info = rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
-
/*
* 82599 errata, UDP frames with a 0 checksum can be marked as
* checksum errors.
@@ -1429,6 +1439,17 @@ static inline void ixgbe_rx_checksum(struct ixgbe_ring *ring,
/* It must be a TCP or UDP packet with a valid checksum */
skb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (encap_pkt) {
+ if (!ixgbe_test_staterr(rx_desc, IXGBE_RXD_STAT_OUTERIPCS))
+ return;
+
+ if (ixgbe_test_staterr(rx_desc, IXGBE_RXDADV_ERR_OUTERIPER)) {
+ ring->rx_stats.csum_err++;
+ return;
+ }
+ /* If we checked the outer header let the stack know */
+ skb->csum_level = 1;
+ }
}
static bool ixgbe_alloc_mapped_page(struct ixgbe_ring *rx_ring,
@@ -3564,10 +3585,24 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
/* Enable MAC Anti-Spoofing */
hw->mac.ops.set_mac_anti_spoofing(hw, (adapter->num_vfs != 0),
adapter->num_vfs);
+
+ /* Ensure LLDP is set for Ethertype Antispoofing if we will be
+ * calling set_ethertype_anti_spoofing for each VF in loop below
+ */
+ if (hw->mac.ops.set_ethertype_anti_spoofing)
+ IXGBE_WRITE_REG(hw, IXGBE_ETQF(IXGBE_ETQF_FILTER_LLDP),
+ (IXGBE_ETQF_FILTER_EN | /* enable filter */
+ IXGBE_ETQF_TX_ANTISPOOF | /* tx antispoof */
+ IXGBE_ETH_P_LLDP)); /* LLDP eth type */
+
/* For VFs that have spoof checking turned off */
for (i = 0; i < adapter->num_vfs; i++) {
if (!adapter->vfinfo[i].spoofchk_enabled)
ixgbe_ndo_set_vf_spoofchk(adapter->netdev, i, false);
+
+ /* enable ethertype anti spoofing if hw supports it */
+ if (hw->mac.ops.set_ethertype_anti_spoofing)
+ hw->mac.ops.set_ethertype_anti_spoofing(hw, true, i);
}
}
@@ -5627,6 +5662,10 @@ static int ixgbe_open(struct net_device *netdev)
ixgbe_up_complete(adapter);
+#if IS_ENABLED(CONFIG_IXGBE_VXLAN)
+ vxlan_get_rx_port(netdev);
+
+#endif
return 0;
err_set_queues:
@@ -7217,8 +7256,8 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
first->gso_segs = 1;
/* if we have a HW VLAN tag being added default to the HW one */
- if (vlan_tx_tag_present(skb)) {
- tx_flags |= vlan_tx_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
+ if (skb_vlan_tag_present(skb)) {
+ tx_flags |= skb_vlan_tag_get(skb) << IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_HW_VLAN;
/* else if it is a SW VLAN check the next protocol and store the tag */
} else if (protocol == htons(ETH_P_8021Q)) {
@@ -7227,11 +7266,11 @@ netdev_tx_t ixgbe_xmit_frame_ring(struct sk_buff *skb,
if (!vhdr)
goto out_drop;
- protocol = vhdr->h_vlan_encapsulated_proto;
tx_flags |= ntohs(vhdr->h_vlan_TCI) <<
IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_SW_VLAN;
}
+ protocol = vlan_get_protocol(skb);
if (unlikely(skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
adapter->ptp_clock &&
@@ -7771,6 +7810,64 @@ static int ixgbe_set_features(struct net_device *netdev,
return 0;
}
+/**
+ * ixgbe_add_vxlan_port - Get notifications about VXLAN ports that come up
+ * @dev: The port's netdev
+ * @sa_family: Socket Family that VXLAN is notifiying us about
+ * @port: New UDP port number that VXLAN started listening to
+ **/
+static void ixgbe_add_vxlan_port(struct net_device *dev, sa_family_t sa_family,
+ __be16 port)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 new_port = ntohs(port);
+
+ if (sa_family == AF_INET6)
+ return;
+
+ if (adapter->vxlan_port == new_port) {
+ netdev_info(dev, "Port %d already offloaded\n", new_port);
+ return;
+ }
+
+ if (adapter->vxlan_port) {
+ netdev_info(dev,
+ "Hit Max num of UDP ports, not adding port %d\n",
+ new_port);
+ return;
+ }
+
+ adapter->vxlan_port = new_port;
+ IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, new_port);
+}
+
+/**
+ * ixgbe_del_vxlan_port - Get notifications about VXLAN ports that go away
+ * @dev: The port's netdev
+ * @sa_family: Socket Family that VXLAN is notifying us about
+ * @port: UDP port number that VXLAN stopped listening to
+ **/
+static void ixgbe_del_vxlan_port(struct net_device *dev, sa_family_t sa_family,
+ __be16 port)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(dev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ u16 new_port = ntohs(port);
+
+ if (sa_family == AF_INET6)
+ return;
+
+ if (adapter->vxlan_port != new_port) {
+ netdev_info(dev, "Port %d was not found, not deleting\n",
+ new_port);
+ return;
+ }
+
+ adapter->vxlan_port = 0;
+ IXGBE_WRITE_REG(hw, IXGBE_VXLANCTRL, 0);
+}
+
static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
struct net_device *dev,
const unsigned char *addr, u16 vid,
@@ -7786,7 +7883,7 @@ static int ixgbe_ndo_fdb_add(struct ndmsg *ndm, struct nlattr *tb[],
}
static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
- struct nlmsghdr *nlh)
+ struct nlmsghdr *nlh, u16 flags)
{
struct ixgbe_adapter *adapter = netdev_priv(dev);
struct nlattr *attr, *br_spec;
@@ -7982,6 +8079,8 @@ static const struct net_device_ops ixgbe_netdev_ops = {
.ndo_bridge_getlink = ixgbe_ndo_bridge_getlink,
.ndo_dfwd_add_station = ixgbe_fwd_add,
.ndo_dfwd_del_station = ixgbe_fwd_del,
+ .ndo_add_vxlan_port = ixgbe_add_vxlan_port,
+ .ndo_del_vxlan_port = ixgbe_del_vxlan_port,
};
/**
@@ -8339,6 +8438,15 @@ skip_sriov:
netdev->priv_flags |= IFF_UNICAST_FLT;
netdev->priv_flags |= IFF_SUPP_NOFCS;
+ switch (adapter->hw.mac.type) {
+ case ixgbe_mac_X550:
+ case ixgbe_mac_X550EM_x:
+ netdev->hw_enc_features |= NETIF_F_RXCSUM;
+ break;
+ default:
+ break;
+ }
+
#ifdef CONFIG_IXGBE_DCB
netdev->dcbnl_ops = &dcbnl_ops;
#endif
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
index 5fd4b5271f9a..79c00f57d3e7 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c
@@ -261,18 +261,9 @@ static int ixgbe_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
struct ixgbe_adapter *adapter =
container_of(ptp, struct ixgbe_adapter, ptp_caps);
unsigned long flags;
- u64 now;
spin_lock_irqsave(&adapter->tmreg_lock, flags);
-
- now = timecounter_read(&adapter->tc);
- now += delta;
-
- /* reset the timecounter */
- timecounter_init(&adapter->tc,
- &adapter->cc,
- now);
-
+ timecounter_adjtime(&adapter->tc, delta);
spin_unlock_irqrestore(&adapter->tmreg_lock, flags);
ixgbe_ptp_setup_sdp(adapter);
@@ -802,7 +793,7 @@ void ixgbe_ptp_start_cyclecounter(struct ixgbe_adapter *adapter)
memset(&adapter->cc, 0, sizeof(adapter->cc));
adapter->cc.read = ixgbe_ptp_read;
- adapter->cc.mask = CLOCKSOURCE_MASK(64);
+ adapter->cc.mask = CYCLECOUNTER_MASK(64);
adapter->cc.shift = shift;
adapter->cc.mult = 1;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index c76ba90ecc6e..7f37fe7269a7 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -101,9 +101,6 @@ static int __ixgbe_enable_sriov(struct ixgbe_adapter *adapter)
adapter->dcb_cfg.num_tcs.pfc_tcs = 1;
}
- /* We do not support RSS w/ SR-IOV */
- adapter->ring_feature[RING_F_RSS].limit = 1;
-
/* Disable RSC when in SR-IOV mode */
adapter->flags2 &= ~(IXGBE_FLAG2_RSC_CAPABLE |
IXGBE_FLAG2_RSC_ENABLED);
@@ -1097,14 +1094,12 @@ static int ixgbe_enable_port_vlan(struct ixgbe_adapter *adapter, int vf,
u16 vlan, u8 qos)
{
struct ixgbe_hw *hw = &adapter->hw;
- int err = 0;
+ int err;
- if (adapter->vfinfo[vf].pf_vlan)
- err = ixgbe_set_vf_vlan(adapter, false,
- adapter->vfinfo[vf].pf_vlan,
- vf);
+ err = ixgbe_set_vf_vlan(adapter, true, vlan, vf);
if (err)
goto out;
+
ixgbe_set_vmvir(adapter, vlan, qos, vf);
ixgbe_set_vmolr(hw, vf, false);
if (adapter->vfinfo[vf].spoofchk_enabled)
@@ -1143,6 +1138,11 @@ static int ixgbe_disable_port_vlan(struct ixgbe_adapter *adapter, int vf)
hw->mac.ops.set_vlan_anti_spoofing(hw, false, vf);
if (adapter->vfinfo[vf].vlan_count)
adapter->vfinfo[vf].vlan_count--;
+
+ /* disable hide VLAN on X550 */
+ if (hw->mac.type >= ixgbe_mac_X550)
+ ixgbe_write_qde(adapter, vf, IXGBE_QDE_ENABLE);
+
adapter->vfinfo[vf].pf_vlan = 0;
adapter->vfinfo[vf].pf_qos = 0;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
index d101b25dc4b6..fc5ecee56ca8 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_type.h
@@ -378,6 +378,8 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_SPOOF_MACAS_MASK 0xFF
#define IXGBE_SPOOF_VLANAS_MASK 0xFF00
#define IXGBE_SPOOF_VLANAS_SHIFT 8
+#define IXGBE_SPOOF_ETHERTYPEAS 0xFF000000
+#define IXGBE_SPOOF_ETHERTYPEAS_SHIFT 16
#define IXGBE_PFVFSPOOF_REG_COUNT 8
#define IXGBE_DCA_TXCTRL(_i) (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */
@@ -399,6 +401,7 @@ struct ixgbe_thermal_sensor_data {
#define IXGBE_WUPL 0x05900
#define IXGBE_WUPM 0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */
+#define IXGBE_VXLANCTRL 0x0000507C /* Rx filter VXLAN UDPPORT Register */
#define IXGBE_FHFT(_n) (0x09000 + ((_n) * 0x100)) /* Flex host filter table */
#define IXGBE_FHFT_EXT(_n) (0x09800 + ((_n) * 0x100)) /* Ext Flexible Host
* Filter Table */
@@ -1540,6 +1543,7 @@ enum {
#define IXGBE_MAX_ETQF_FILTERS 8
#define IXGBE_ETQF_FCOE 0x08000000 /* bit 27 */
#define IXGBE_ETQF_BCN 0x10000000 /* bit 28 */
+#define IXGBE_ETQF_TX_ANTISPOOF 0x20000000 /* bit 29 */
#define IXGBE_ETQF_1588 0x40000000 /* bit 30 */
#define IXGBE_ETQF_FILTER_EN 0x80000000 /* bit 31 */
#define IXGBE_ETQF_POOL_ENABLE (1 << 26) /* bit 26 */
@@ -1565,6 +1569,9 @@ enum {
#define IXGBE_ETQF_FILTER_FCOE 2
#define IXGBE_ETQF_FILTER_1588 3
#define IXGBE_ETQF_FILTER_FIP 4
+#define IXGBE_ETQF_FILTER_LLDP 5
+#define IXGBE_ETQF_FILTER_LACP 6
+
/* VLAN Control Bit Masks */
#define IXGBE_VLNCTRL_VET 0x0000FFFF /* bits 0-15 */
#define IXGBE_VLNCTRL_CFI 0x10000000 /* bit 28 */
@@ -2122,6 +2129,7 @@ enum {
#define IXGBE_RXD_STAT_IPCS 0x40 /* IP xsum calculated */
#define IXGBE_RXD_STAT_PIF 0x80 /* passed in-exact filter */
#define IXGBE_RXD_STAT_CRCV 0x100 /* Speculative CRC Valid */
+#define IXGBE_RXD_STAT_OUTERIPCS 0x100 /* Cloud IP xsum calculated */
#define IXGBE_RXD_STAT_VEXT 0x200 /* 1st VLAN found */
#define IXGBE_RXD_STAT_UDPV 0x400 /* Valid UDP checksum */
#define IXGBE_RXD_STAT_DYNINT 0x800 /* Pkt caused INT via DYNINT */
@@ -2139,6 +2147,7 @@ enum {
#define IXGBE_RXD_ERR_IPE 0x80 /* IP Checksum Error */
#define IXGBE_RXDADV_ERR_MASK 0xfff00000 /* RDESC.ERRORS mask */
#define IXGBE_RXDADV_ERR_SHIFT 20 /* RDESC.ERRORS shift */
+#define IXGBE_RXDADV_ERR_OUTERIPER 0x04000000 /* CRC IP Header error */
#define IXGBE_RXDADV_ERR_FCEOFE 0x80000000 /* FCoEFe/IPE */
#define IXGBE_RXDADV_ERR_FCERR 0x00700000 /* FCERR/FDIRERR */
#define IXGBE_RXDADV_ERR_FDIR_LEN 0x00100000 /* FDIR Length error */
@@ -2227,6 +2236,8 @@ enum {
#define IXGBE_RXDADV_PKTTYPE_UDP 0x00000200 /* UDP hdr present */
#define IXGBE_RXDADV_PKTTYPE_SCTP 0x00000400 /* SCTP hdr present */
#define IXGBE_RXDADV_PKTTYPE_NFS 0x00000800 /* NFS hdr present */
+#define IXGBE_RXDADV_PKTTYPE_VXLAN 0x00000800 /* VXLAN hdr present */
+#define IXGBE_RXDADV_PKTTYPE_TUNNEL 0x00010000 /* Tunnel type */
#define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP 0x00001000 /* IPSec ESP */
#define IXGBE_RXDADV_PKTTYPE_IPSEC_AH 0x00002000 /* IPSec AH */
#define IXGBE_RXDADV_PKTTYPE_LINKSEC 0x00004000 /* LinkSec Encap */
@@ -3056,6 +3067,7 @@ struct ixgbe_mac_operations {
s32 (*set_fw_drv_ver)(struct ixgbe_hw *, u8, u8, u8, u8);
s32 (*get_thermal_sensor_data)(struct ixgbe_hw *);
s32 (*init_thermal_sensor_thresh)(struct ixgbe_hw *hw);
+ void (*set_ethertype_anti_spoofing)(struct ixgbe_hw *, bool, int);
/* DMA Coalescing */
s32 (*dmac_config)(struct ixgbe_hw *hw);
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
index ba54ff07b438..49395420c9b3 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x540.c
@@ -55,9 +55,6 @@ s32 ixgbe_get_invariants_X540(struct ixgbe_hw *hw)
{
struct ixgbe_mac_info *mac = &hw->mac;
- /* Call PHY identify routine to get the phy type */
- ixgbe_identify_phy_generic(hw);
-
mac->mcft_size = IXGBE_X540_MC_TBL_SIZE;
mac->vft_size = IXGBE_X540_VFT_TBL_SIZE;
mac->num_rar_entries = IXGBE_X540_RAR_ENTRIES;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
index ffdd1231f419..50bf81908dd6 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_x550.c
@@ -80,7 +80,7 @@ static s32 ixgbe_write_phy_reg_x550em(struct ixgbe_hw *hw, u32 reg_addr,
* Initializes the EEPROM parameters ixgbe_eeprom_info within the
* ixgbe_hw struct in order to set up EEPROM access.
**/
-s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
+static s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
{
struct ixgbe_eeprom_info *eeprom = &hw->eeprom;
u32 eec;
@@ -110,8 +110,8 @@ s32 ixgbe_init_eeprom_params_X550(struct ixgbe_hw *hw)
* @device_type: 3 bit device type
* @phy_data: Pointer to read data from the register
**/
-s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
- u32 device_type, u32 *data)
+static s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 *data)
{
u32 i, command, error;
@@ -158,7 +158,8 @@ s32 ixgbe_read_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
*
* Reads a 16 bit word from the EEPROM using the hostif.
**/
-s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
+static s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 *data)
{
s32 status;
struct ixgbe_hic_read_shadow_ram buffer;
@@ -193,8 +194,8 @@ s32 ixgbe_read_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
*
* Reads a 16 bit word(s) from the EEPROM using the hostif.
**/
-s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
- u16 offset, u16 words, u16 *data)
+static s32 ixgbe_read_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
+ u16 offset, u16 words, u16 *data)
{
struct ixgbe_hic_read_shadow_ram buffer;
u32 current_word = 0;
@@ -331,7 +332,8 @@ static s32 ixgbe_checksum_ptr_x550(struct ixgbe_hw *hw, u16 ptr,
*
* Returns a negative error code on error, or the 16-bit checksum
**/
-s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size)
+static s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer,
+ u32 buffer_size)
{
u16 eeprom_ptrs[IXGBE_EEPROM_LAST_WORD + 1];
u16 *local_buffer;
@@ -407,7 +409,7 @@ s32 ixgbe_calc_checksum_X550(struct ixgbe_hw *hw, u16 *buffer, u32 buffer_size)
*
* Returns a negative error code on error, or the 16-bit checksum
**/
-s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
+static s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
{
return ixgbe_calc_checksum_X550(hw, NULL, 0);
}
@@ -419,7 +421,7 @@ s32 ixgbe_calc_eeprom_checksum_X550(struct ixgbe_hw *hw)
*
* Reads a 16 bit word from the EEPROM using the hostif.
**/
-s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
+static s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
{
s32 status = 0;
@@ -440,7 +442,8 @@ s32 ixgbe_read_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 *data)
* Performs checksum calculation and validates the EEPROM checksum. If the
* caller does not need checksum_val, the value can be NULL.
**/
-s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val)
+static s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw,
+ u16 *checksum_val)
{
s32 status;
u16 checksum;
@@ -489,7 +492,8 @@ s32 ixgbe_validate_eeprom_checksum_X550(struct ixgbe_hw *hw, u16 *checksum_val)
*
* Write a 16 bit word to the EEPROM using the hostif.
**/
-s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
+static s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset,
+ u16 data)
{
s32 status;
struct ixgbe_hic_write_shadow_ram buffer;
@@ -517,7 +521,7 @@ s32 ixgbe_write_ee_hostif_data_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
*
* Write a 16 bit word to the EEPROM using the hostif.
**/
-s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
+static s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
{
s32 status = 0;
@@ -537,7 +541,7 @@ s32 ixgbe_write_ee_hostif_X550(struct ixgbe_hw *hw, u16 offset, u16 data)
*
* Issue a shadow RAM dump to FW to copy EEPROM from shadow RAM to the flash.
**/
-s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
+static s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
{
s32 status = 0;
union ixgbe_hic_hdr2 buffer;
@@ -560,7 +564,7 @@ s32 ixgbe_update_flash_X550(struct ixgbe_hw *hw)
* checksum and updates the EEPROM and instructs the hardware to update
* the flash.
**/
-s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
+static s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
{
s32 status;
u16 checksum = 0;
@@ -600,8 +604,9 @@ s32 ixgbe_update_eeprom_checksum_X550(struct ixgbe_hw *hw)
*
* Write a 16 bit word(s) to the EEPROM using the hostif.
**/
-s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
- u16 offset, u16 words, u16 *data)
+static s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
+ u16 offset, u16 words,
+ u16 *data)
{
s32 status = 0;
u32 i = 0;
@@ -630,7 +635,7 @@ s32 ixgbe_write_ee_hostif_buffer_X550(struct ixgbe_hw *hw,
/** ixgbe_init_mac_link_ops_X550em - init mac link function pointers
* @hw: pointer to hardware structure
**/
-void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
+static void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
{
struct ixgbe_mac_info *mac = &hw->mac;
@@ -647,7 +652,7 @@ void ixgbe_init_mac_link_ops_X550em(struct ixgbe_hw *hw)
/** ixgbe_setup_sfp_modules_X550em - Setup SFP module
* @hw: pointer to hardware structure
*/
-s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
+static s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
{
bool setup_linear;
u16 reg_slice, edc_mode;
@@ -703,9 +708,9 @@ s32 ixgbe_setup_sfp_modules_X550em(struct ixgbe_hw *hw)
* @speed: pointer to link speed
* @autoneg: true when autoneg or autotry is enabled
**/
-s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
- ixgbe_link_speed *speed,
- bool *autoneg)
+static s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
+ ixgbe_link_speed *speed,
+ bool *autoneg)
{
/* SFP */
if (hw->phy.media_type == ixgbe_media_type_fiber) {
@@ -740,8 +745,8 @@ s32 ixgbe_get_link_capabilities_X550em(struct ixgbe_hw *hw,
* @device_type: 3 bit device type
* @data: Data to write to the register
**/
-s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
- u32 device_type, u32 data)
+static s32 ixgbe_write_iosf_sb_reg_x550(struct ixgbe_hw *hw, u32 reg_addr,
+ u32 device_type, u32 data)
{
u32 i, command, error;
@@ -904,7 +909,7 @@ static s32 ixgbe_setup_ixfi_x550em(struct ixgbe_hw *hw, ixgbe_link_speed *speed)
*
* Configures the integrated KX4 PHY.
**/
-s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
{
s32 status;
u32 reg_val;
@@ -942,7 +947,7 @@ s32 ixgbe_setup_kx4_x550em(struct ixgbe_hw *hw)
*
* Configures the integrated KR PHY.
**/
-s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
{
s32 status;
u32 reg_val;
@@ -987,7 +992,7 @@ s32 ixgbe_setup_kr_x550em(struct ixgbe_hw *hw)
* A return of a non-zero value indicates an error, and the base driver should
* not report link up.
**/
-s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
{
u32 status;
u16 lasi, autoneg_status, speed;
@@ -1049,7 +1054,7 @@ s32 ixgbe_setup_internal_phy_x550em(struct ixgbe_hw *hw)
* set during init_shared_code because the PHY/SFP type was
* not known. Perform the SFP init if necessary.
**/
-s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
+static s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
{
struct ixgbe_phy_info *phy = &hw->phy;
s32 ret_val;
@@ -1102,7 +1107,7 @@ s32 ixgbe_init_phy_ops_X550em(struct ixgbe_hw *hw)
* Returns the media type (fiber, copper, backplane)
*
*/
-enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
+static enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
{
enum ixgbe_media_type media_type;
@@ -1129,7 +1134,7 @@ enum ixgbe_media_type ixgbe_get_media_type_X550em(struct ixgbe_hw *hw)
/** ixgbe_init_ext_t_x550em - Start (unstall) the external Base T PHY.
** @hw: pointer to hardware structure
**/
-s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
+static s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
{
u32 status;
u16 reg;
@@ -1202,7 +1207,7 @@ s32 ixgbe_init_ext_t_x550em(struct ixgbe_hw *hw)
** and clears all interrupts, perform a PHY reset, and perform a link (MAC)
** reset.
**/
-s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
+static s32 ixgbe_reset_hw_X550em(struct ixgbe_hw *hw)
{
ixgbe_link_speed link_speed;
s32 status;
@@ -1295,6 +1300,28 @@ mac_reset_top:
return status;
}
+/** ixgbe_set_ethertype_anti_spoofing_X550 - Enable/Disable Ethertype
+ * anti-spoofing
+ * @hw: pointer to hardware structure
+ * @enable: enable or disable switch for Ethertype anti-spoofing
+ * @vf: Virtual Function pool - VF Pool to set for Ethertype anti-spoofing
+ **/
+void ixgbe_set_ethertype_anti_spoofing_X550(struct ixgbe_hw *hw, bool enable,
+ int vf)
+{
+ int vf_target_reg = vf >> 3;
+ int vf_target_shift = vf % 8 + IXGBE_SPOOF_ETHERTYPEAS_SHIFT;
+ u32 pfvfspoof;
+
+ pfvfspoof = IXGBE_READ_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg));
+ if (enable)
+ pfvfspoof |= (1 << vf_target_shift);
+ else
+ pfvfspoof &= ~(1 << vf_target_shift);
+
+ IXGBE_WRITE_REG(hw, IXGBE_PFVFSPOOF(vf_target_reg), pfvfspoof);
+}
+
#define X550_COMMON_MAC \
.init_hw = &ixgbe_init_hw_generic, \
.start_hw = &ixgbe_start_hw_X540, \
@@ -1329,6 +1356,8 @@ mac_reset_top:
.init_uta_tables = &ixgbe_init_uta_tables_generic, \
.set_mac_anti_spoofing = &ixgbe_set_mac_anti_spoofing, \
.set_vlan_anti_spoofing = &ixgbe_set_vlan_anti_spoofing, \
+ .set_ethertype_anti_spoofing = \
+ &ixgbe_set_ethertype_anti_spoofing_X550, \
.acquire_swfw_sync = &ixgbe_acquire_swfw_sync_X540, \
.release_swfw_sync = &ixgbe_release_swfw_sync_X540, \
.disable_rx_buff = &ixgbe_disable_rx_buff_generic, \
@@ -1345,7 +1374,6 @@ static struct ixgbe_mac_operations mac_ops_X550 = {
.get_san_mac_addr = &ixgbe_get_san_mac_addr_generic,
.get_wwn_prefix = &ixgbe_get_wwn_prefix_generic,
.setup_link = &ixgbe_setup_mac_link_X540,
- .set_rxpba = &ixgbe_set_rxpba_generic,
.get_link_capabilities = &ixgbe_get_copper_link_capabilities_generic,
.setup_sfp = NULL,
};
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
index 8c44ab25f3fa..3a9b356dff01 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf.h
@@ -43,6 +43,13 @@
#define BP_EXTENDED_STATS
#endif
+#define IXGBE_MAX_TXD_PWR 14
+#define IXGBE_MAX_DATA_PER_TXD BIT(IXGBE_MAX_TXD_PWR)
+
+/* Tx Descriptors needed, worst case */
+#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD)
+#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+
/* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */
struct ixgbevf_tx_buffer {
@@ -85,6 +92,18 @@ struct ixgbevf_rx_queue_stats {
u64 csum_err;
};
+enum ixgbevf_ring_state_t {
+ __IXGBEVF_TX_DETECT_HANG,
+ __IXGBEVF_HANG_CHECK_ARMED,
+};
+
+#define check_for_tx_hang(ring) \
+ test_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state)
+#define set_check_for_tx_hang(ring) \
+ set_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state)
+#define clear_check_for_tx_hang(ring) \
+ clear_bit(__IXGBEVF_TX_DETECT_HANG, &(ring)->state)
+
struct ixgbevf_ring {
struct ixgbevf_ring *next;
struct net_device *netdev;
@@ -101,7 +120,7 @@ struct ixgbevf_ring {
struct ixgbevf_tx_buffer *tx_buffer_info;
struct ixgbevf_rx_buffer *rx_buffer_info;
};
-
+ unsigned long state;
struct ixgbevf_stats stats;
struct u64_stats_sync syncp;
union {
@@ -124,6 +143,7 @@ struct ixgbevf_ring {
#define MAX_RX_QUEUES IXGBE_VF_MAX_RX_QUEUES
#define MAX_TX_QUEUES IXGBE_VF_MAX_TX_QUEUES
+#define IXGBEVF_MAX_RSS_QUEUES 2
#define IXGBEVF_DEFAULT_TXD 1024
#define IXGBEVF_DEFAULT_RXD 512
@@ -347,8 +367,6 @@ struct ixgbevf_adapter {
/* this field must be first, see ixgbevf_process_skb_fields */
unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
- struct timer_list watchdog_timer;
- struct work_struct reset_task;
struct ixgbevf_q_vector *q_vector[MAX_MSIX_Q_VECTORS];
/* Interrupt Throttle Rate */
@@ -378,8 +396,7 @@ struct ixgbevf_adapter {
* thus the additional *_CAPABLE flags.
*/
u32 flags;
-#define IXGBE_FLAG_IN_WATCHDOG_TASK (u32)(1)
-
+#define IXGBEVF_FLAG_RESET_REQUESTED (u32)(1)
#define IXGBEVF_FLAG_QUEUE_RESET_REQUESTED (u32)(1 << 2)
struct msix_entry *msix_entries;
@@ -415,9 +432,11 @@ struct ixgbevf_adapter {
u32 link_speed;
bool link_up;
- spinlock_t mbx_lock;
+ struct timer_list service_timer;
+ struct work_struct service_task;
- struct work_struct watchdog_task;
+ spinlock_t mbx_lock;
+ unsigned long last_reset;
};
enum ixbgevf_state_t {
@@ -426,7 +445,8 @@ enum ixbgevf_state_t {
__IXGBEVF_DOWN,
__IXGBEVF_DISABLED,
__IXGBEVF_REMOVING,
- __IXGBEVF_WORK_INIT,
+ __IXGBEVF_SERVICE_SCHED,
+ __IXGBEVF_SERVICE_INITED,
};
enum ixgbevf_boards {
diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
index 62a0d8e0f17d..4186981e562d 100644
--- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
+++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c
@@ -98,6 +98,23 @@ static int debug = -1;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
+static void ixgbevf_service_event_schedule(struct ixgbevf_adapter *adapter)
+{
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
+ !test_bit(__IXGBEVF_REMOVING, &adapter->state) &&
+ !test_and_set_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state))
+ schedule_work(&adapter->service_task);
+}
+
+static void ixgbevf_service_event_complete(struct ixgbevf_adapter *adapter)
+{
+ BUG_ON(!test_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state));
+
+ /* flush memory to make sure state is correct before next watchdog */
+ smp_mb__before_atomic();
+ clear_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state);
+}
+
/* forward decls */
static void ixgbevf_queue_reset_subtask(struct ixgbevf_adapter *adapter);
static void ixgbevf_set_itr(struct ixgbevf_q_vector *q_vector);
@@ -111,8 +128,8 @@ static void ixgbevf_remove_adapter(struct ixgbe_hw *hw)
return;
hw->hw_addr = NULL;
dev_err(&adapter->pdev->dev, "Adapter removed\n");
- if (test_bit(__IXGBEVF_WORK_INIT, &adapter->state))
- schedule_work(&adapter->watchdog_task);
+ if (test_bit(__IXGBEVF_SERVICE_INITED, &adapter->state))
+ ixgbevf_service_event_schedule(adapter);
}
static void ixgbevf_check_remove(struct ixgbe_hw *hw, u32 reg)
@@ -199,14 +216,72 @@ static void ixgbevf_unmap_and_free_tx_resource(struct ixgbevf_ring *tx_ring,
/* tx_buffer must be completely set up in the transmit path */
}
-#define IXGBE_MAX_TXD_PWR 14
-#define IXGBE_MAX_DATA_PER_TXD (1 << IXGBE_MAX_TXD_PWR)
+static u64 ixgbevf_get_tx_completed(struct ixgbevf_ring *ring)
+{
+ return ring->stats.packets;
+}
+
+static u32 ixgbevf_get_tx_pending(struct ixgbevf_ring *ring)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(ring->netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+
+ u32 head = IXGBE_READ_REG(hw, IXGBE_VFTDH(ring->reg_idx));
+ u32 tail = IXGBE_READ_REG(hw, IXGBE_VFTDT(ring->reg_idx));
+
+ if (head != tail)
+ return (head < tail) ?
+ tail - head : (tail + ring->count - head);
+
+ return 0;
+}
+
+static inline bool ixgbevf_check_tx_hang(struct ixgbevf_ring *tx_ring)
+{
+ u32 tx_done = ixgbevf_get_tx_completed(tx_ring);
+ u32 tx_done_old = tx_ring->tx_stats.tx_done_old;
+ u32 tx_pending = ixgbevf_get_tx_pending(tx_ring);
+
+ clear_check_for_tx_hang(tx_ring);
+
+ /* Check for a hung queue, but be thorough. This verifies
+ * that a transmit has been completed since the previous
+ * check AND there is at least one packet pending. The
+ * ARMED bit is set to indicate a potential hang.
+ */
+ if ((tx_done_old == tx_done) && tx_pending) {
+ /* make sure it is true for two checks in a row */
+ return test_and_set_bit(__IXGBEVF_HANG_CHECK_ARMED,
+ &tx_ring->state);
+ }
+ /* reset the countdown */
+ clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &tx_ring->state);
+
+ /* update completed stats and continue */
+ tx_ring->tx_stats.tx_done_old = tx_done;
+
+ return false;
+}
+
+static void ixgbevf_tx_timeout_reset(struct ixgbevf_adapter *adapter)
+{
+ /* Do the reset outside of interrupt context */
+ if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) {
+ adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED;
+ ixgbevf_service_event_schedule(adapter);
+ }
+}
-/* Tx Descriptors needed, worst case */
-#define TXD_USE_COUNT(S) DIV_ROUND_UP((S), IXGBE_MAX_DATA_PER_TXD)
-#define DESC_NEEDED (MAX_SKB_FRAGS + 4)
+/**
+ * ixgbevf_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ **/
+static void ixgbevf_tx_timeout(struct net_device *netdev)
+{
+ struct ixgbevf_adapter *adapter = netdev_priv(netdev);
-static void ixgbevf_tx_timeout(struct net_device *netdev);
+ ixgbevf_tx_timeout_reset(adapter);
+}
/**
* ixgbevf_clean_tx_irq - Reclaim resources after transmit completes
@@ -311,6 +386,37 @@ static bool ixgbevf_clean_tx_irq(struct ixgbevf_q_vector *q_vector,
q_vector->tx.total_bytes += total_bytes;
q_vector->tx.total_packets += total_packets;
+ if (check_for_tx_hang(tx_ring) && ixgbevf_check_tx_hang(tx_ring)) {
+ struct ixgbe_hw *hw = &adapter->hw;
+ union ixgbe_adv_tx_desc *eop_desc;
+
+ eop_desc = tx_ring->tx_buffer_info[i].next_to_watch;
+
+ pr_err("Detected Tx Unit Hang\n"
+ " Tx Queue <%d>\n"
+ " TDH, TDT <%x>, <%x>\n"
+ " next_to_use <%x>\n"
+ " next_to_clean <%x>\n"
+ "tx_buffer_info[next_to_clean]\n"
+ " next_to_watch <%p>\n"
+ " eop_desc->wb.status <%x>\n"
+ " time_stamp <%lx>\n"
+ " jiffies <%lx>\n",
+ tx_ring->queue_index,
+ IXGBE_READ_REG(hw, IXGBE_VFTDH(tx_ring->reg_idx)),
+ IXGBE_READ_REG(hw, IXGBE_VFTDT(tx_ring->reg_idx)),
+ tx_ring->next_to_use, i,
+ eop_desc, (eop_desc ? eop_desc->wb.status : 0),
+ tx_ring->tx_buffer_info[i].time_stamp, jiffies);
+
+ netif_stop_subqueue(tx_ring->netdev, tx_ring->queue_index);
+
+ /* schedule immediate reset if we believe we hung */
+ ixgbevf_tx_timeout_reset(adapter);
+
+ return true;
+ }
+
#define TX_WAKE_THRESHOLD (DESC_NEEDED * 2)
if (unlikely(total_packets && netif_carrier_ok(tx_ring->netdev) &&
(ixgbevf_desc_unused(tx_ring) >= TX_WAKE_THRESHOLD))) {
@@ -1158,9 +1264,7 @@ static irqreturn_t ixgbevf_msix_other(int irq, void *data)
hw->mac.get_link_status = 1;
- if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
- !test_bit(__IXGBEVF_REMOVING, &adapter->state))
- mod_timer(&adapter->watchdog_timer, jiffies);
+ ixgbevf_service_event_schedule(adapter);
IXGBE_WRITE_REG(hw, IXGBE_VTEIMS, adapter->eims_other);
@@ -1479,6 +1583,8 @@ static void ixgbevf_configure_tx_ring(struct ixgbevf_adapter *adapter,
txdctl |= (1 << 8) | /* HTHRESH = 1 */
32; /* PTHRESH = 32 */
+ clear_bit(__IXGBEVF_HANG_CHECK_ARMED, &ring->state);
+
IXGBE_WRITE_REG(hw, IXGBE_VFTXDCTL(reg_idx), txdctl);
/* poll to verify queue is enabled */
@@ -1584,6 +1690,39 @@ static void ixgbevf_rx_desc_queue_enable(struct ixgbevf_adapter *adapter,
reg_idx);
}
+static void ixgbevf_setup_vfmrqc(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 vfmrqc = 0, vfreta = 0;
+ u32 rss_key[10];
+ u16 rss_i = adapter->num_rx_queues;
+ int i, j;
+
+ /* Fill out hash function seeds */
+ netdev_rss_key_fill(rss_key, sizeof(rss_key));
+ for (i = 0; i < 10; i++)
+ IXGBE_WRITE_REG(hw, IXGBE_VFRSSRK(i), rss_key[i]);
+
+ /* Fill out redirection table */
+ for (i = 0, j = 0; i < 64; i++, j++) {
+ if (j == rss_i)
+ j = 0;
+ vfreta = (vfreta << 8) | (j * 0x1);
+ if ((i & 3) == 3)
+ IXGBE_WRITE_REG(hw, IXGBE_VFRETA(i >> 2), vfreta);
+ }
+
+ /* Perform hash on these packet types */
+ vfmrqc |= IXGBE_VFMRQC_RSS_FIELD_IPV4 |
+ IXGBE_VFMRQC_RSS_FIELD_IPV4_TCP |
+ IXGBE_VFMRQC_RSS_FIELD_IPV6 |
+ IXGBE_VFMRQC_RSS_FIELD_IPV6_TCP;
+
+ vfmrqc |= IXGBE_VFMRQC_RSSEN;
+
+ IXGBE_WRITE_REG(hw, IXGBE_VFMRQC, vfmrqc);
+}
+
static void ixgbevf_configure_rx_ring(struct ixgbevf_adapter *adapter,
struct ixgbevf_ring *ring)
{
@@ -1640,6 +1779,8 @@ static void ixgbevf_configure_rx(struct ixgbevf_adapter *adapter)
struct net_device *netdev = adapter->netdev;
ixgbevf_setup_psrtype(adapter);
+ if (hw->mac.type >= ixgbe_mac_X550_vf)
+ ixgbevf_setup_vfmrqc(adapter);
/* notify the PF of our intent to use this size of frame */
ixgbevf_rlpml_set_vf(hw, netdev->mtu + ETH_HLEN + ETH_FCS_LEN);
@@ -1794,7 +1935,8 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
unsigned int def_q = 0;
unsigned int num_tcs = 0;
- unsigned int num_rx_queues = 1;
+ unsigned int num_rx_queues = adapter->num_rx_queues;
+ unsigned int num_tx_queues = adapter->num_tx_queues;
int err;
spin_lock_bh(&adapter->mbx_lock);
@@ -1808,6 +1950,9 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter)
return err;
if (num_tcs > 1) {
+ /* we need only one Tx queue */
+ num_tx_queues = 1;
+
/* update default Tx ring register index */
adapter->tx_ring[0]->reg_idx = def_q;
@@ -1816,7 +1961,8 @@ static int ixgbevf_configure_dcb(struct ixgbevf_adapter *adapter)
}
/* if we have a bad config abort request queue reset */
- if (adapter->num_rx_queues != num_rx_queues) {
+ if ((adapter->num_rx_queues != num_rx_queues) ||
+ (adapter->num_tx_queues != num_tx_queues)) {
/* force mailbox timeout to prevent further messages */
hw->mbx.timeout = 0;
@@ -1917,6 +2063,10 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
clear_bit(__IXGBEVF_DOWN, &adapter->state);
ixgbevf_napi_enable_all(adapter);
+ /* clear any pending interrupts, may auto mask */
+ IXGBE_READ_REG(hw, IXGBE_VTEICR);
+ ixgbevf_irq_enable(adapter);
+
/* enable transmits */
netif_tx_start_all_queues(netdev);
@@ -1924,21 +2074,14 @@ static void ixgbevf_up_complete(struct ixgbevf_adapter *adapter)
ixgbevf_init_last_counter_stats(adapter);
hw->mac.get_link_status = 1;
- mod_timer(&adapter->watchdog_timer, jiffies);
+ mod_timer(&adapter->service_timer, jiffies);
}
void ixgbevf_up(struct ixgbevf_adapter *adapter)
{
- struct ixgbe_hw *hw = &adapter->hw;
-
ixgbevf_configure(adapter);
ixgbevf_up_complete(adapter);
-
- /* clear any pending interrupts, may auto mask */
- IXGBE_READ_REG(hw, IXGBE_VTEICR);
-
- ixgbevf_irq_enable(adapter);
}
/**
@@ -2045,22 +2188,19 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter)
for (i = 0; i < adapter->num_rx_queues; i++)
ixgbevf_disable_rx_queue(adapter, adapter->rx_ring[i]);
- netif_tx_disable(netdev);
-
- msleep(10);
+ usleep_range(10000, 20000);
netif_tx_stop_all_queues(netdev);
+ /* call carrier off first to avoid false dev_watchdog timeouts */
+ netif_carrier_off(netdev);
+ netif_tx_disable(netdev);
+
ixgbevf_irq_disable(adapter);
ixgbevf_napi_disable_all(adapter);
- del_timer_sync(&adapter->watchdog_timer);
- /* can't call flush scheduled work here because it can deadlock
- * if linkwatch_event tries to acquire the rtnl_lock which we are
- * holding */
- while (adapter->flags & IXGBE_FLAG_IN_WATCHDOG_TASK)
- msleep(1);
+ del_timer_sync(&adapter->service_timer);
/* disable transmits in the hardware now that interrupts are off */
for (i = 0; i < adapter->num_tx_queues; i++) {
@@ -2070,8 +2210,6 @@ void ixgbevf_down(struct ixgbevf_adapter *adapter)
IXGBE_TXDCTL_SWFLSH);
}
- netif_carrier_off(netdev);
-
if (!pci_channel_offline(adapter->pdev))
ixgbevf_reset(adapter);
@@ -2110,6 +2248,8 @@ void ixgbevf_reset(struct ixgbevf_adapter *adapter)
memcpy(netdev->perm_addr, adapter->hw.mac.addr,
netdev->addr_len);
}
+
+ adapter->last_reset = jiffies;
}
static int ixgbevf_acquire_msix_vectors(struct ixgbevf_adapter *adapter,
@@ -2181,8 +2321,19 @@ static void ixgbevf_set_num_queues(struct ixgbevf_adapter *adapter)
return;
/* we need as many queues as traffic classes */
- if (num_tcs > 1)
+ if (num_tcs > 1) {
adapter->num_rx_queues = num_tcs;
+ } else {
+ u16 rss = min_t(u16, num_online_cpus(), IXGBEVF_MAX_RSS_QUEUES);
+
+ switch (hw->api_version) {
+ case ixgbe_mbox_api_11:
+ adapter->num_rx_queues = rss;
+ adapter->num_tx_queues = rss;
+ default:
+ break;
+ }
+ }
}
/**
@@ -2552,7 +2703,8 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
struct ixgbe_hw *hw = &adapter->hw;
int i;
- if (!adapter->link_up)
+ if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+ test_bit(__IXGBEVF_RESETTING, &adapter->state))
return;
UPDATE_VF_COUNTER_32bit(IXGBE_VFGPRC, adapter->stats.last_vfgprc,
@@ -2576,79 +2728,176 @@ void ixgbevf_update_stats(struct ixgbevf_adapter *adapter)
}
/**
- * ixgbevf_watchdog - Timer Call-back
+ * ixgbevf_service_timer - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
**/
-static void ixgbevf_watchdog(unsigned long data)
+static void ixgbevf_service_timer(unsigned long data)
{
struct ixgbevf_adapter *adapter = (struct ixgbevf_adapter *)data;
+
+ /* Reset the timer */
+ mod_timer(&adapter->service_timer, (HZ * 2) + jiffies);
+
+ ixgbevf_service_event_schedule(adapter);
+}
+
+static void ixgbevf_reset_subtask(struct ixgbevf_adapter *adapter)
+{
+ if (!(adapter->flags & IXGBEVF_FLAG_RESET_REQUESTED))
+ return;
+
+ adapter->flags &= ~IXGBEVF_FLAG_RESET_REQUESTED;
+
+ /* If we're already down or resetting, just bail */
+ if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+ test_bit(__IXGBEVF_RESETTING, &adapter->state))
+ return;
+
+ adapter->tx_timeout_count++;
+
+ ixgbevf_reinit_locked(adapter);
+}
+
+/* ixgbevf_check_hang_subtask - check for hung queues and dropped interrupts
+ * @adapter - pointer to the device adapter structure
+ *
+ * This function serves two purposes. First it strobes the interrupt lines
+ * in order to make certain interrupts are occurring. Secondly it sets the
+ * bits needed to check for TX hangs. As a result we should immediately
+ * determine if a hang has occurred.
+ */
+static void ixgbevf_check_hang_subtask(struct ixgbevf_adapter *adapter)
+{
struct ixgbe_hw *hw = &adapter->hw;
u32 eics = 0;
int i;
- /*
- * Do the watchdog outside of interrupt context due to the lovely
- * delays that some of the newer hardware requires
- */
+ /* If we're down or resetting, just bail */
+ if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
+ test_bit(__IXGBEVF_RESETTING, &adapter->state))
+ return;
- if (test_bit(__IXGBEVF_DOWN, &adapter->state))
- goto watchdog_short_circuit;
+ /* Force detection of hung controller */
+ if (netif_carrier_ok(adapter->netdev)) {
+ for (i = 0; i < adapter->num_tx_queues; i++)
+ set_check_for_tx_hang(adapter->tx_ring[i]);
+ }
/* get one bit for every active tx/rx interrupt vector */
for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
struct ixgbevf_q_vector *qv = adapter->q_vector[i];
+
if (qv->rx.ring || qv->tx.ring)
eics |= 1 << i;
}
+ /* Cause software interrupt to ensure rings are cleaned */
IXGBE_WRITE_REG(hw, IXGBE_VTEICS, eics);
+}
-watchdog_short_circuit:
- schedule_work(&adapter->watchdog_task);
+/**
+ * ixgbevf_watchdog_update_link - update the link status
+ * @adapter - pointer to the device adapter structure
+ **/
+static void ixgbevf_watchdog_update_link(struct ixgbevf_adapter *adapter)
+{
+ struct ixgbe_hw *hw = &adapter->hw;
+ u32 link_speed = adapter->link_speed;
+ bool link_up = adapter->link_up;
+ s32 err;
+
+ spin_lock_bh(&adapter->mbx_lock);
+
+ err = hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
+
+ spin_unlock_bh(&adapter->mbx_lock);
+
+ /* if check for link returns error we will need to reset */
+ if (err && time_after(jiffies, adapter->last_reset + (10 * HZ))) {
+ adapter->flags |= IXGBEVF_FLAG_RESET_REQUESTED;
+ link_up = false;
+ }
+
+ adapter->link_up = link_up;
+ adapter->link_speed = link_speed;
}
/**
- * ixgbevf_tx_timeout - Respond to a Tx Hang
- * @netdev: network interface device structure
+ * ixgbevf_watchdog_link_is_up - update netif_carrier status and
+ * print link up message
+ * @adapter - pointer to the device adapter structure
**/
-static void ixgbevf_tx_timeout(struct net_device *netdev)
+static void ixgbevf_watchdog_link_is_up(struct ixgbevf_adapter *adapter)
{
- struct ixgbevf_adapter *adapter = netdev_priv(netdev);
+ struct net_device *netdev = adapter->netdev;
- /* Do the reset outside of interrupt context */
- schedule_work(&adapter->reset_task);
+ /* only continue if link was previously down */
+ if (netif_carrier_ok(netdev))
+ return;
+
+ dev_info(&adapter->pdev->dev, "NIC Link is Up %s\n",
+ (adapter->link_speed == IXGBE_LINK_SPEED_10GB_FULL) ?
+ "10 Gbps" :
+ (adapter->link_speed == IXGBE_LINK_SPEED_1GB_FULL) ?
+ "1 Gbps" :
+ (adapter->link_speed == IXGBE_LINK_SPEED_100_FULL) ?
+ "100 Mbps" :
+ "unknown speed");
+
+ netif_carrier_on(netdev);
}
-static void ixgbevf_reset_task(struct work_struct *work)
+/**
+ * ixgbevf_watchdog_link_is_down - update netif_carrier status and
+ * print link down message
+ * @adapter - pointer to the adapter structure
+ **/
+static void ixgbevf_watchdog_link_is_down(struct ixgbevf_adapter *adapter)
{
- struct ixgbevf_adapter *adapter;
- adapter = container_of(work, struct ixgbevf_adapter, reset_task);
+ struct net_device *netdev = adapter->netdev;
- /* If we're already down or resetting, just bail */
+ adapter->link_speed = 0;
+
+ /* only continue if link was up previously */
+ if (!netif_carrier_ok(netdev))
+ return;
+
+ dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
+
+ netif_carrier_off(netdev);
+}
+
+/**
+ * ixgbevf_watchdog_subtask - worker thread to bring link up
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbevf_watchdog_subtask(struct ixgbevf_adapter *adapter)
+{
+ /* if interface is down do nothing */
if (test_bit(__IXGBEVF_DOWN, &adapter->state) ||
- test_bit(__IXGBEVF_REMOVING, &adapter->state) ||
test_bit(__IXGBEVF_RESETTING, &adapter->state))
return;
- adapter->tx_timeout_count++;
+ ixgbevf_watchdog_update_link(adapter);
- ixgbevf_reinit_locked(adapter);
+ if (adapter->link_up)
+ ixgbevf_watchdog_link_is_up(adapter);
+ else
+ ixgbevf_watchdog_link_is_down(adapter);
+
+ ixgbevf_update_stats(adapter);
}
/**
- * ixgbevf_watchdog_task - worker thread to bring link up
+ * ixgbevf_service_task - manages and runs subtasks
* @work: pointer to work_struct containing our data
**/
-static void ixgbevf_watchdog_task(struct work_struct *work)
+static void ixgbevf_service_task(struct work_struct *work)
{
struct ixgbevf_adapter *adapter = container_of(work,
struct ixgbevf_adapter,
- watchdog_task);
- struct net_device *netdev = adapter->netdev;
+ service_task);
struct ixgbe_hw *hw = &adapter->hw;
- u32 link_speed = adapter->link_speed;
- bool link_up = adapter->link_up;
- s32 need_reset;
if (IXGBE_REMOVED(hw->hw_addr)) {
if (!test_bit(__IXGBEVF_DOWN, &adapter->state)) {
@@ -2658,73 +2907,13 @@ static void ixgbevf_watchdog_task(struct work_struct *work)
}
return;
}
- ixgbevf_queue_reset_subtask(adapter);
-
- adapter->flags |= IXGBE_FLAG_IN_WATCHDOG_TASK;
-
- /*
- * Always check the link on the watchdog because we have
- * no LSC interrupt
- */
- spin_lock_bh(&adapter->mbx_lock);
-
- need_reset = hw->mac.ops.check_link(hw, &link_speed, &link_up, false);
-
- spin_unlock_bh(&adapter->mbx_lock);
-
- if (need_reset) {
- adapter->link_up = link_up;
- adapter->link_speed = link_speed;
- netif_carrier_off(netdev);
- netif_tx_stop_all_queues(netdev);
- schedule_work(&adapter->reset_task);
- goto pf_has_reset;
- }
- adapter->link_up = link_up;
- adapter->link_speed = link_speed;
-
- if (link_up) {
- if (!netif_carrier_ok(netdev)) {
- char *link_speed_string;
- switch (link_speed) {
- case IXGBE_LINK_SPEED_10GB_FULL:
- link_speed_string = "10 Gbps";
- break;
- case IXGBE_LINK_SPEED_1GB_FULL:
- link_speed_string = "1 Gbps";
- break;
- case IXGBE_LINK_SPEED_100_FULL:
- link_speed_string = "100 Mbps";
- break;
- default:
- link_speed_string = "unknown speed";
- break;
- }
- dev_info(&adapter->pdev->dev,
- "NIC Link is Up, %s\n", link_speed_string);
- netif_carrier_on(netdev);
- netif_tx_wake_all_queues(netdev);
- }
- } else {
- adapter->link_up = false;
- adapter->link_speed = 0;
- if (netif_carrier_ok(netdev)) {
- dev_info(&adapter->pdev->dev, "NIC Link is Down\n");
- netif_carrier_off(netdev);
- netif_tx_stop_all_queues(netdev);
- }
- }
- ixgbevf_update_stats(adapter);
-
-pf_has_reset:
- /* Reset the timer */
- if (!test_bit(__IXGBEVF_DOWN, &adapter->state) &&
- !test_bit(__IXGBEVF_REMOVING, &adapter->state))
- mod_timer(&adapter->watchdog_timer,
- round_jiffies(jiffies + (2 * HZ)));
+ ixgbevf_queue_reset_subtask(adapter);
+ ixgbevf_reset_subtask(adapter);
+ ixgbevf_watchdog_subtask(adapter);
+ ixgbevf_check_hang_subtask(adapter);
- adapter->flags &= ~IXGBE_FLAG_IN_WATCHDOG_TASK;
+ ixgbevf_service_event_complete(adapter);
}
/**
@@ -2944,10 +3133,6 @@ static int ixgbevf_open(struct net_device *netdev)
if (!adapter->num_msix_vectors)
return -ENOMEM;
- /* disallow open during test */
- if (test_bit(__IXGBEVF_TESTING, &adapter->state))
- return -EBUSY;
-
if (hw->adapter_stopped) {
ixgbevf_reset(adapter);
/* if adapter is still stopped then PF isn't up and
@@ -2960,6 +3145,12 @@ static int ixgbevf_open(struct net_device *netdev)
}
}
+ /* disallow open during test */
+ if (test_bit(__IXGBEVF_TESTING, &adapter->state))
+ return -EBUSY;
+
+ netif_carrier_off(netdev);
+
/* allocate transmit descriptors */
err = ixgbevf_setup_all_tx_resources(adapter);
if (err)
@@ -2979,15 +3170,11 @@ static int ixgbevf_open(struct net_device *netdev)
*/
ixgbevf_map_rings_to_vectors(adapter);
- ixgbevf_up_complete(adapter);
-
- /* clear any pending interrupts, may auto mask */
- IXGBE_READ_REG(hw, IXGBE_VTEICR);
err = ixgbevf_request_irq(adapter);
if (err)
goto err_req_irq;
- ixgbevf_irq_enable(adapter);
+ ixgbevf_up_complete(adapter);
return 0;
@@ -3099,7 +3286,7 @@ static int ixgbevf_tso(struct ixgbevf_ring *tx_ring,
/* ADV DTYP TUCMD MKRLOC/ISCSIHEDLEN */
type_tucmd = IXGBE_ADVTXD_TUCMD_L4T_TCP;
- if (skb->protocol == htons(ETH_P_IP)) {
+ if (first->protocol == htons(ETH_P_IP)) {
struct iphdr *iph = ip_hdr(skb);
iph->tot_len = 0;
iph->check = 0;
@@ -3156,7 +3343,7 @@ static void ixgbevf_tx_csum(struct ixgbevf_ring *tx_ring,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
u8 l4_hdr = 0;
- switch (skb->protocol) {
+ switch (first->protocol) {
case htons(ETH_P_IP):
vlan_macip_lens |= skb_network_header_len(skb);
type_tucmd |= IXGBE_ADVTXD_TUCMD_IPV4;
@@ -3452,8 +3639,8 @@ static int ixgbevf_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
first->bytecount = skb->len;
first->gso_segs = 1;
- if (vlan_tx_tag_present(skb)) {
- tx_flags |= vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb)) {
+ tx_flags |= skb_vlan_tag_get(skb);
tx_flags <<= IXGBE_TX_FLAGS_VLAN_SHIFT;
tx_flags |= IXGBE_TX_FLAGS_VLAN;
}
@@ -3822,28 +4009,28 @@ static int ixgbevf_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
NETIF_F_HW_VLAN_CTAG_RX |
NETIF_F_HW_VLAN_CTAG_FILTER;
- netdev->vlan_features |= NETIF_F_TSO;
- netdev->vlan_features |= NETIF_F_TSO6;
- netdev->vlan_features |= NETIF_F_IP_CSUM;
- netdev->vlan_features |= NETIF_F_IPV6_CSUM;
- netdev->vlan_features |= NETIF_F_SG;
+ netdev->vlan_features |= NETIF_F_TSO |
+ NETIF_F_TSO6 |
+ NETIF_F_IP_CSUM |
+ NETIF_F_IPV6_CSUM |
+ NETIF_F_SG;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;
netdev->priv_flags |= IFF_UNICAST_FLT;
- init_timer(&adapter->watchdog_timer);
- adapter->watchdog_timer.function = ixgbevf_watchdog;
- adapter->watchdog_timer.data = (unsigned long)adapter;
-
if (IXGBE_REMOVED(hw->hw_addr)) {
err = -EIO;
goto err_sw_init;
}
- INIT_WORK(&adapter->reset_task, ixgbevf_reset_task);
- INIT_WORK(&adapter->watchdog_task, ixgbevf_watchdog_task);
- set_bit(__IXGBEVF_WORK_INIT, &adapter->state);
+
+ setup_timer(&adapter->service_timer, &ixgbevf_service_timer,
+ (unsigned long)adapter);
+
+ INIT_WORK(&adapter->service_task, ixgbevf_service_task);
+ set_bit(__IXGBEVF_SERVICE_INITED, &adapter->state);
+ clear_bit(__IXGBEVF_SERVICE_SCHED, &adapter->state);
err = ixgbevf_init_interrupt_scheme(adapter);
if (err)
@@ -3917,11 +4104,7 @@ static void ixgbevf_remove(struct pci_dev *pdev)
adapter = netdev_priv(netdev);
set_bit(__IXGBEVF_REMOVING, &adapter->state);
-
- del_timer_sync(&adapter->watchdog_timer);
-
- cancel_work_sync(&adapter->reset_task);
- cancel_work_sync(&adapter->watchdog_task);
+ cancel_work_sync(&adapter->service_task);
if (netdev->reg_state == NETREG_REGISTERED)
unregister_netdev(netdev);
@@ -3955,7 +4138,7 @@ static pci_ers_result_t ixgbevf_io_error_detected(struct pci_dev *pdev,
struct net_device *netdev = pci_get_drvdata(pdev);
struct ixgbevf_adapter *adapter = netdev_priv(netdev);
- if (!test_bit(__IXGBEVF_WORK_INIT, &adapter->state))
+ if (!test_bit(__IXGBEVF_SERVICE_INITED, &adapter->state))
return PCI_ERS_RESULT_DISCONNECT;
rtnl_lock();
diff --git a/drivers/net/ethernet/intel/ixgbevf/regs.h b/drivers/net/ethernet/intel/ixgbevf/regs.h
index 09dd8f698bea..3e712fd6e695 100644
--- a/drivers/net/ethernet/intel/ixgbevf/regs.h
+++ b/drivers/net/ethernet/intel/ixgbevf/regs.h
@@ -69,6 +69,16 @@
#define IXGBE_VFGOTC_LSB 0x02020
#define IXGBE_VFGOTC_MSB 0x02024
#define IXGBE_VFMPRC 0x01034
+#define IXGBE_VFMRQC 0x3000
+#define IXGBE_VFRSSRK(x) (0x3100 + ((x) * 4))
+#define IXGBE_VFRETA(x) (0x3200 + ((x) * 4))
+
+/* VFMRQC bits */
+#define IXGBE_VFMRQC_RSSEN 0x00000001 /* RSS Enable */
+#define IXGBE_VFMRQC_RSS_FIELD_IPV4_TCP 0x00010000
+#define IXGBE_VFMRQC_RSS_FIELD_IPV4 0x00020000
+#define IXGBE_VFMRQC_RSS_FIELD_IPV6 0x00100000
+#define IXGBE_VFMRQC_RSS_FIELD_IPV6_TCP 0x00200000
#define IXGBE_WRITE_FLUSH(a) (IXGBE_READ_REG(a, IXGBE_VFSTATUS))
diff --git a/drivers/net/ethernet/jme.c b/drivers/net/ethernet/jme.c
index 44ce7d88f554..6e9a792097d3 100644
--- a/drivers/net/ethernet/jme.c
+++ b/drivers/net/ethernet/jme.c
@@ -2154,9 +2154,9 @@ jme_tx_csum(struct jme_adapter *jme, struct sk_buff *skb, u8 *flags)
static inline void
jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
{
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
*flags |= TXFLAG_TAGON;
- *vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+ *vlan = cpu_to_le16(skb_vlan_tag_get(skb));
}
}
diff --git a/drivers/net/ethernet/marvell/sky2.c b/drivers/net/ethernet/marvell/sky2.c
index 867a6a3ef81f..d9f4498832a1 100644
--- a/drivers/net/ethernet/marvell/sky2.c
+++ b/drivers/net/ethernet/marvell/sky2.c
@@ -1895,14 +1895,14 @@ static netdev_tx_t sky2_xmit_frame(struct sk_buff *skb,
ctrl = 0;
/* Add VLAN tag, can piggyback on LRGLEN or ADDR64 */
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
if (!le) {
le = get_tx_le(sky2, &slot);
le->addr = 0;
le->opcode = OP_VLAN|HW_OWNER;
} else
le->opcode |= OP_VLAN;
- le->length = cpu_to_be16(vlan_tx_tag_get(skb));
+ le->length = cpu_to_be16(skb_vlan_tag_get(skb));
ctrl |= INS_VLAN;
}
@@ -2594,7 +2594,7 @@ static struct sk_buff *sky2_receive(struct net_device *dev,
sky2->rx_next = (sky2->rx_next + 1) % sky2->rx_pending;
prefetch(sky2->rx_ring + sky2->rx_next);
- if (vlan_tx_tag_present(re->skb))
+ if (skb_vlan_tag_present(re->skb))
count -= VLAN_HLEN; /* Account for vlan tag */
/* This chip has hardware problems that generates bogus status.
diff --git a/drivers/net/ethernet/mellanox/mlx4/alloc.c b/drivers/net/ethernet/mellanox/mlx4/alloc.c
index 963dd7e6d547..0c51c69f802f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/alloc.c
+++ b/drivers/net/ethernet/mellanox/mlx4/alloc.c
@@ -592,7 +592,7 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
buf->nbufs = 1;
buf->npages = 1;
buf->page_shift = get_order(size) + PAGE_SHIFT;
- buf->direct.buf = dma_alloc_coherent(&dev->pdev->dev,
+ buf->direct.buf = dma_alloc_coherent(&dev->persist->pdev->dev,
size, &t, gfp);
if (!buf->direct.buf)
return -ENOMEM;
@@ -619,7 +619,8 @@ int mlx4_buf_alloc(struct mlx4_dev *dev, int size, int max_direct,
for (i = 0; i < buf->nbufs; ++i) {
buf->page_list[i].buf =
- dma_alloc_coherent(&dev->pdev->dev, PAGE_SIZE,
+ dma_alloc_coherent(&dev->persist->pdev->dev,
+ PAGE_SIZE,
&t, gfp);
if (!buf->page_list[i].buf)
goto err_free;
@@ -657,15 +658,17 @@ void mlx4_buf_free(struct mlx4_dev *dev, int size, struct mlx4_buf *buf)
int i;
if (buf->nbufs == 1)
- dma_free_coherent(&dev->pdev->dev, size, buf->direct.buf,
+ dma_free_coherent(&dev->persist->pdev->dev, size,
+ buf->direct.buf,
buf->direct.map);
else {
- if (BITS_PER_LONG == 64 && buf->direct.buf)
+ if (BITS_PER_LONG == 64)
vunmap(buf->direct.buf);
for (i = 0; i < buf->nbufs; ++i)
if (buf->page_list[i].buf)
- dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ dma_free_coherent(&dev->persist->pdev->dev,
+ PAGE_SIZE,
buf->page_list[i].buf,
buf->page_list[i].map);
kfree(buf->page_list);
@@ -738,7 +741,7 @@ int mlx4_db_alloc(struct mlx4_dev *dev, struct mlx4_db *db, int order, gfp_t gfp
if (!mlx4_alloc_db_from_pgdir(pgdir, db, order))
goto out;
- pgdir = mlx4_alloc_db_pgdir(&(dev->pdev->dev), gfp);
+ pgdir = mlx4_alloc_db_pgdir(&dev->persist->pdev->dev, gfp);
if (!pgdir) {
ret = -ENOMEM;
goto out;
@@ -775,7 +778,7 @@ void mlx4_db_free(struct mlx4_dev *dev, struct mlx4_db *db)
set_bit(i, db->u.pgdir->bits[o]);
if (bitmap_full(db->u.pgdir->order1, MLX4_DB_PER_PAGE / 2)) {
- dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
+ dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
db->u.pgdir->db_page, db->u.pgdir->db_dma);
list_del(&db->u.pgdir->list);
kfree(db->u.pgdir);
diff --git a/drivers/net/ethernet/mellanox/mlx4/catas.c b/drivers/net/ethernet/mellanox/mlx4/catas.c
index 9c656fe4983d..715de8affcc9 100644
--- a/drivers/net/ethernet/mellanox/mlx4/catas.c
+++ b/drivers/net/ethernet/mellanox/mlx4/catas.c
@@ -40,16 +40,177 @@ enum {
MLX4_CATAS_POLL_INTERVAL = 5 * HZ,
};
-static DEFINE_SPINLOCK(catas_lock);
-static LIST_HEAD(catas_list);
-static struct work_struct catas_work;
-static int internal_err_reset = 1;
-module_param(internal_err_reset, int, 0644);
+int mlx4_internal_err_reset = 1;
+module_param_named(internal_err_reset, mlx4_internal_err_reset, int, 0644);
MODULE_PARM_DESC(internal_err_reset,
- "Reset device on internal errors if non-zero"
- " (default 1, in SRIOV mode default is 0)");
+ "Reset device on internal errors if non-zero (default 1)");
+
+static int read_vendor_id(struct mlx4_dev *dev)
+{
+ u16 vendor_id = 0;
+ int ret;
+
+ ret = pci_read_config_word(dev->persist->pdev, 0, &vendor_id);
+ if (ret) {
+ mlx4_err(dev, "Failed to read vendor ID, ret=%d\n", ret);
+ return ret;
+ }
+
+ if (vendor_id == 0xffff) {
+ mlx4_err(dev, "PCI can't be accessed to read vendor id\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int mlx4_reset_master(struct mlx4_dev *dev)
+{
+ int err = 0;
+
+ if (mlx4_is_master(dev))
+ mlx4_report_internal_err_comm_event(dev);
+
+ if (!pci_channel_offline(dev->persist->pdev)) {
+ err = read_vendor_id(dev);
+ /* If PCI can't be accessed to read vendor ID we assume that its
+ * link was disabled and chip was already reset.
+ */
+ if (err)
+ return 0;
+
+ err = mlx4_reset(dev);
+ if (err)
+ mlx4_err(dev, "Fail to reset HCA\n");
+ }
+
+ return err;
+}
+
+static int mlx4_reset_slave(struct mlx4_dev *dev)
+{
+#define COM_CHAN_RST_REQ_OFFSET 0x10
+#define COM_CHAN_RST_ACK_OFFSET 0x08
+
+ u32 comm_flags;
+ u32 rst_req;
+ u32 rst_ack;
+ unsigned long end;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ if (pci_channel_offline(dev->persist->pdev))
+ return 0;
+
+ comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm +
+ MLX4_COMM_CHAN_FLAGS));
+ if (comm_flags == 0xffffffff) {
+ mlx4_err(dev, "VF reset is not needed\n");
+ return 0;
+ }
+
+ if (!(dev->caps.vf_caps & MLX4_VF_CAP_FLAG_RESET)) {
+ mlx4_err(dev, "VF reset is not supported\n");
+ return -EOPNOTSUPP;
+ }
+
+ rst_req = (comm_flags & (u32)(1 << COM_CHAN_RST_REQ_OFFSET)) >>
+ COM_CHAN_RST_REQ_OFFSET;
+ rst_ack = (comm_flags & (u32)(1 << COM_CHAN_RST_ACK_OFFSET)) >>
+ COM_CHAN_RST_ACK_OFFSET;
+ if (rst_req != rst_ack) {
+ mlx4_err(dev, "Communication channel isn't sync, fail to send reset\n");
+ return -EIO;
+ }
+
+ rst_req ^= 1;
+ mlx4_warn(dev, "VF is sending reset request to Firmware\n");
+ comm_flags = rst_req << COM_CHAN_RST_REQ_OFFSET;
+ __raw_writel((__force u32)cpu_to_be32(comm_flags),
+ (__iomem char *)priv->mfunc.comm + MLX4_COMM_CHAN_FLAGS);
+ /* Make sure that our comm channel write doesn't
+ * get mixed in with writes from another CPU.
+ */
+ mmiowb();
+
+ end = msecs_to_jiffies(MLX4_COMM_TIME) + jiffies;
+ while (time_before(jiffies, end)) {
+ comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm +
+ MLX4_COMM_CHAN_FLAGS));
+ rst_ack = (comm_flags & (u32)(1 << COM_CHAN_RST_ACK_OFFSET)) >>
+ COM_CHAN_RST_ACK_OFFSET;
+
+ /* Reading rst_req again since the communication channel can
+ * be reset at any time by the PF and all its bits will be
+ * set to zero.
+ */
+ rst_req = (comm_flags & (u32)(1 << COM_CHAN_RST_REQ_OFFSET)) >>
+ COM_CHAN_RST_REQ_OFFSET;
+
+ if (rst_ack == rst_req) {
+ mlx4_warn(dev, "VF Reset succeed\n");
+ return 0;
+ }
+ cond_resched();
+ }
+ mlx4_err(dev, "Fail to send reset over the communication channel\n");
+ return -ETIMEDOUT;
+}
+
+static int mlx4_comm_internal_err(u32 slave_read)
+{
+ return (u32)COMM_CHAN_EVENT_INTERNAL_ERR ==
+ (slave_read & (u32)COMM_CHAN_EVENT_INTERNAL_ERR) ? 1 : 0;
+}
+
+void mlx4_enter_error_state(struct mlx4_dev_persistent *persist)
+{
+ int err;
+ struct mlx4_dev *dev;
+
+ if (!mlx4_internal_err_reset)
+ return;
+
+ mutex_lock(&persist->device_state_mutex);
+ if (persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ goto out;
+
+ dev = persist->dev;
+ mlx4_err(dev, "device is going to be reset\n");
+ if (mlx4_is_slave(dev))
+ err = mlx4_reset_slave(dev);
+ else
+ err = mlx4_reset_master(dev);
+ BUG_ON(err != 0);
+
+ dev->persist->state |= MLX4_DEVICE_STATE_INTERNAL_ERROR;
+ mlx4_err(dev, "device was reset successfully\n");
+ mutex_unlock(&persist->device_state_mutex);
+
+ /* At that step HW was already reset, now notify clients */
+ mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
+ mlx4_cmd_wake_completions(dev);
+ return;
+
+out:
+ mutex_unlock(&persist->device_state_mutex);
+}
+
+static void mlx4_handle_error_state(struct mlx4_dev_persistent *persist)
+{
+ int err = 0;
+
+ mlx4_enter_error_state(persist);
+ mutex_lock(&persist->interface_state_mutex);
+ if (persist->interface_state & MLX4_INTERFACE_STATE_UP &&
+ !(persist->interface_state & MLX4_INTERFACE_STATE_DELETION)) {
+ err = mlx4_restart_one(persist->pdev);
+ mlx4_info(persist->dev, "mlx4_restart_one was ended, ret=%d\n",
+ err);
+ }
+ mutex_unlock(&persist->interface_state_mutex);
+}
static void dump_err_buf(struct mlx4_dev *dev)
{
@@ -67,58 +228,40 @@ static void poll_catas(unsigned long dev_ptr)
{
struct mlx4_dev *dev = (struct mlx4_dev *) dev_ptr;
struct mlx4_priv *priv = mlx4_priv(dev);
+ u32 slave_read;
- if (readl(priv->catas_err.map)) {
- /* If the device is off-line, we cannot try to recover it */
- if (pci_channel_offline(dev->pdev))
- mod_timer(&priv->catas_err.timer,
- round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
- else {
- dump_err_buf(dev);
- mlx4_dispatch_event(dev, MLX4_DEV_EVENT_CATASTROPHIC_ERROR, 0);
-
- if (internal_err_reset) {
- spin_lock(&catas_lock);
- list_add(&priv->catas_err.list, &catas_list);
- spin_unlock(&catas_lock);
-
- queue_work(mlx4_wq, &catas_work);
- }
+ if (mlx4_is_slave(dev)) {
+ slave_read = swab32(readl(&priv->mfunc.comm->slave_read));
+ if (mlx4_comm_internal_err(slave_read)) {
+ mlx4_warn(dev, "Internal error detected on the communication channel\n");
+ goto internal_err;
}
- } else
- mod_timer(&priv->catas_err.timer,
- round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
+ } else if (readl(priv->catas_err.map)) {
+ dump_err_buf(dev);
+ goto internal_err;
+ }
+
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ mlx4_warn(dev, "Internal error mark was detected on device\n");
+ goto internal_err;
+ }
+
+ mod_timer(&priv->catas_err.timer,
+ round_jiffies(jiffies + MLX4_CATAS_POLL_INTERVAL));
+ return;
+
+internal_err:
+ if (mlx4_internal_err_reset)
+ queue_work(dev->persist->catas_wq, &dev->persist->catas_work);
}
static void catas_reset(struct work_struct *work)
{
- struct mlx4_priv *priv, *tmppriv;
- struct mlx4_dev *dev;
+ struct mlx4_dev_persistent *persist =
+ container_of(work, struct mlx4_dev_persistent,
+ catas_work);
- LIST_HEAD(tlist);
- int ret;
-
- spin_lock_irq(&catas_lock);
- list_splice_init(&catas_list, &tlist);
- spin_unlock_irq(&catas_lock);
-
- list_for_each_entry_safe(priv, tmppriv, &tlist, catas_err.list) {
- struct pci_dev *pdev = priv->dev.pdev;
-
- /* If the device is off-line, we cannot reset it */
- if (pci_channel_offline(pdev))
- continue;
-
- ret = mlx4_restart_one(priv->dev.pdev);
- /* 'priv' now is not valid */
- if (ret)
- pr_err("mlx4 %s: Reset failed (%d)\n",
- pci_name(pdev), ret);
- else {
- dev = pci_get_drvdata(pdev);
- mlx4_dbg(dev, "Reset succeeded\n");
- }
- }
+ mlx4_handle_error_state(persist);
}
void mlx4_start_catas_poll(struct mlx4_dev *dev)
@@ -126,22 +269,21 @@ void mlx4_start_catas_poll(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
phys_addr_t addr;
- /*If we are in SRIOV the default of the module param must be 0*/
- if (mlx4_is_mfunc(dev))
- internal_err_reset = 0;
-
INIT_LIST_HEAD(&priv->catas_err.list);
init_timer(&priv->catas_err.timer);
priv->catas_err.map = NULL;
- addr = pci_resource_start(dev->pdev, priv->fw.catas_bar) +
- priv->fw.catas_offset;
+ if (!mlx4_is_slave(dev)) {
+ addr = pci_resource_start(dev->persist->pdev,
+ priv->fw.catas_bar) +
+ priv->fw.catas_offset;
- priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
- if (!priv->catas_err.map) {
- mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n",
- (unsigned long long) addr);
- return;
+ priv->catas_err.map = ioremap(addr, priv->fw.catas_size * 4);
+ if (!priv->catas_err.map) {
+ mlx4_warn(dev, "Failed to map internal error buffer at 0x%llx\n",
+ (unsigned long long)addr);
+ return;
+ }
}
priv->catas_err.timer.data = (unsigned long) dev;
@@ -157,15 +299,29 @@ void mlx4_stop_catas_poll(struct mlx4_dev *dev)
del_timer_sync(&priv->catas_err.timer);
- if (priv->catas_err.map)
+ if (priv->catas_err.map) {
iounmap(priv->catas_err.map);
+ priv->catas_err.map = NULL;
+ }
- spin_lock_irq(&catas_lock);
- list_del(&priv->catas_err.list);
- spin_unlock_irq(&catas_lock);
+ if (dev->persist->interface_state & MLX4_INTERFACE_STATE_DELETION)
+ flush_workqueue(dev->persist->catas_wq);
}
-void __init mlx4_catas_init(void)
+int mlx4_catas_init(struct mlx4_dev *dev)
{
- INIT_WORK(&catas_work, catas_reset);
+ INIT_WORK(&dev->persist->catas_work, catas_reset);
+ dev->persist->catas_wq = create_singlethread_workqueue("mlx4_health");
+ if (!dev->persist->catas_wq)
+ return -ENOMEM;
+
+ return 0;
+}
+
+void mlx4_catas_end(struct mlx4_dev *dev)
+{
+ if (dev->persist->catas_wq) {
+ destroy_workqueue(dev->persist->catas_wq);
+ dev->persist->catas_wq = NULL;
+ }
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/cmd.c b/drivers/net/ethernet/mellanox/mlx4/cmd.c
index 5c93d1451c44..a681d7c0bb9f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/cmd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/cmd.c
@@ -42,6 +42,7 @@
#include <linux/mlx4/device.h>
#include <linux/semaphore.h>
#include <rdma/ib_smi.h>
+#include <linux/delay.h>
#include <asm/io.h>
@@ -182,6 +183,72 @@ static u8 mlx4_errno_to_status(int errno)
}
}
+static int mlx4_internal_err_ret_value(struct mlx4_dev *dev, u16 op,
+ u8 op_modifier)
+{
+ switch (op) {
+ case MLX4_CMD_UNMAP_ICM:
+ case MLX4_CMD_UNMAP_ICM_AUX:
+ case MLX4_CMD_UNMAP_FA:
+ case MLX4_CMD_2RST_QP:
+ case MLX4_CMD_HW2SW_EQ:
+ case MLX4_CMD_HW2SW_CQ:
+ case MLX4_CMD_HW2SW_SRQ:
+ case MLX4_CMD_HW2SW_MPT:
+ case MLX4_CMD_CLOSE_HCA:
+ case MLX4_QP_FLOW_STEERING_DETACH:
+ case MLX4_CMD_FREE_RES:
+ case MLX4_CMD_CLOSE_PORT:
+ return CMD_STAT_OK;
+
+ case MLX4_CMD_QP_ATTACH:
+ /* On Detach case return success */
+ if (op_modifier == 0)
+ return CMD_STAT_OK;
+ return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+
+ default:
+ return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+ }
+}
+
+static int mlx4_closing_cmd_fatal_error(u16 op, u8 fw_status)
+{
+ /* Any error during the closing commands below is considered fatal */
+ if (op == MLX4_CMD_CLOSE_HCA ||
+ op == MLX4_CMD_HW2SW_EQ ||
+ op == MLX4_CMD_HW2SW_CQ ||
+ op == MLX4_CMD_2RST_QP ||
+ op == MLX4_CMD_HW2SW_SRQ ||
+ op == MLX4_CMD_SYNC_TPT ||
+ op == MLX4_CMD_UNMAP_ICM ||
+ op == MLX4_CMD_UNMAP_ICM_AUX ||
+ op == MLX4_CMD_UNMAP_FA)
+ return 1;
+ /* Error on MLX4_CMD_HW2SW_MPT is fatal except when fw status equals
+ * CMD_STAT_REG_BOUND.
+ * This status indicates that memory region has memory windows bound to it
+ * which may result from invalid user space usage and is not fatal.
+ */
+ if (op == MLX4_CMD_HW2SW_MPT && fw_status != CMD_STAT_REG_BOUND)
+ return 1;
+ return 0;
+}
+
+static int mlx4_cmd_reset_flow(struct mlx4_dev *dev, u16 op, u8 op_modifier,
+ int err)
+{
+ /* Only if reset flow is really active return code is based on
+ * command, otherwise current error code is returned.
+ */
+ if (mlx4_internal_err_reset) {
+ mlx4_enter_error_state(dev->persist);
+ err = mlx4_internal_err_ret_value(dev, op, op_modifier);
+ }
+
+ return err;
+}
+
static int comm_pending(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -190,16 +257,30 @@ static int comm_pending(struct mlx4_dev *dev)
return (swab32(status) >> 31) != priv->cmd.comm_toggle;
}
-static void mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param)
+static int mlx4_comm_cmd_post(struct mlx4_dev *dev, u8 cmd, u16 param)
{
struct mlx4_priv *priv = mlx4_priv(dev);
u32 val;
+ /* To avoid writing to unknown addresses after the device state was
+ * changed to internal error and the function was rest,
+ * check the INTERNAL_ERROR flag which is updated under
+ * device_state_mutex lock.
+ */
+ mutex_lock(&dev->persist->device_state_mutex);
+
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ mutex_unlock(&dev->persist->device_state_mutex);
+ return -EIO;
+ }
+
priv->cmd.comm_toggle ^= 1;
val = param | (cmd << 16) | (priv->cmd.comm_toggle << 31);
__raw_writel((__force u32) cpu_to_be32(val),
&priv->mfunc.comm->slave_write);
mmiowb();
+ mutex_unlock(&dev->persist->device_state_mutex);
+ return 0;
}
static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
@@ -219,7 +300,13 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
/* Write command */
down(&priv->cmd.poll_sem);
- mlx4_comm_cmd_post(dev, cmd, param);
+ if (mlx4_comm_cmd_post(dev, cmd, param)) {
+ /* Only in case the device state is INTERNAL_ERROR,
+ * mlx4_comm_cmd_post returns with an error
+ */
+ err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+ goto out;
+ }
end = msecs_to_jiffies(timeout) + jiffies;
while (comm_pending(dev) && time_before(jiffies, end))
@@ -231,18 +318,23 @@ static int mlx4_comm_cmd_poll(struct mlx4_dev *dev, u8 cmd, u16 param,
* is MLX4_DELAY_RESET_SLAVE*/
if ((MLX4_COMM_CMD_RESET == cmd)) {
err = MLX4_DELAY_RESET_SLAVE;
+ goto out;
} else {
- mlx4_warn(dev, "Communication channel timed out\n");
- err = -ETIMEDOUT;
+ mlx4_warn(dev, "Communication channel command 0x%x timed out\n",
+ cmd);
+ err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
}
}
+ if (err)
+ mlx4_enter_error_state(dev->persist);
+out:
up(&priv->cmd.poll_sem);
return err;
}
-static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op,
- u16 param, unsigned long timeout)
+static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 vhcr_cmd,
+ u16 param, u16 op, unsigned long timeout)
{
struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
struct mlx4_cmd_context *context;
@@ -258,34 +350,49 @@ static int mlx4_comm_cmd_wait(struct mlx4_dev *dev, u8 op,
cmd->free_head = context->next;
spin_unlock(&cmd->context_lock);
- init_completion(&context->done);
+ reinit_completion(&context->done);
- mlx4_comm_cmd_post(dev, op, param);
+ if (mlx4_comm_cmd_post(dev, vhcr_cmd, param)) {
+ /* Only in case the device state is INTERNAL_ERROR,
+ * mlx4_comm_cmd_post returns with an error
+ */
+ err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+ goto out;
+ }
if (!wait_for_completion_timeout(&context->done,
msecs_to_jiffies(timeout))) {
- mlx4_warn(dev, "communication channel command 0x%x timed out\n",
- op);
- err = -EBUSY;
- goto out;
+ mlx4_warn(dev, "communication channel command 0x%x (op=0x%x) timed out\n",
+ vhcr_cmd, op);
+ goto out_reset;
}
err = context->result;
if (err && context->fw_status != CMD_STAT_MULTI_FUNC_REQ) {
mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
- op, context->fw_status);
- goto out;
+ vhcr_cmd, context->fw_status);
+ if (mlx4_closing_cmd_fatal_error(op, context->fw_status))
+ goto out_reset;
}
-out:
/* wait for comm channel ready
* this is necessary for prevention the race
* when switching between event to polling mode
+ * Skipping this section in case the device is in FATAL_ERROR state,
+ * In this state, no commands are sent via the comm channel until
+ * the device has returned from reset.
*/
- end = msecs_to_jiffies(timeout) + jiffies;
- while (comm_pending(dev) && time_before(jiffies, end))
- cond_resched();
+ if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
+ end = msecs_to_jiffies(timeout) + jiffies;
+ while (comm_pending(dev) && time_before(jiffies, end))
+ cond_resched();
+ }
+ goto out;
+out_reset:
+ err = mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+ mlx4_enter_error_state(dev->persist);
+out:
spin_lock(&cmd->context_lock);
context->next = cmd->free_head;
cmd->free_head = context - cmd->context;
@@ -296,10 +403,13 @@ out:
}
int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
- unsigned long timeout)
+ u16 op, unsigned long timeout)
{
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ return mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+
if (mlx4_priv(dev)->cmd.use_events)
- return mlx4_comm_cmd_wait(dev, cmd, param, timeout);
+ return mlx4_comm_cmd_wait(dev, cmd, param, op, timeout);
return mlx4_comm_cmd_poll(dev, cmd, param, timeout);
}
@@ -307,7 +417,7 @@ static int cmd_pending(struct mlx4_dev *dev)
{
u32 status;
- if (pci_channel_offline(dev->pdev))
+ if (pci_channel_offline(dev->persist->pdev))
return -EIO;
status = readl(mlx4_priv(dev)->cmd.hcr + HCR_STATUS_OFFSET);
@@ -323,17 +433,21 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
{
struct mlx4_cmd *cmd = &mlx4_priv(dev)->cmd;
u32 __iomem *hcr = cmd->hcr;
- int ret = -EAGAIN;
+ int ret = -EIO;
unsigned long end;
- mutex_lock(&cmd->hcr_mutex);
-
- if (pci_channel_offline(dev->pdev)) {
+ mutex_lock(&dev->persist->device_state_mutex);
+ /* To avoid writing to unknown addresses after the device state was
+ * changed to internal error and the chip was reset,
+ * check the INTERNAL_ERROR flag which is updated under
+ * device_state_mutex lock.
+ */
+ if (pci_channel_offline(dev->persist->pdev) ||
+ (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)) {
/*
* Device is going through error recovery
* and cannot accept commands.
*/
- ret = -EIO;
goto out;
}
@@ -342,12 +456,11 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
end += msecs_to_jiffies(GO_BIT_TIMEOUT_MSECS);
while (cmd_pending(dev)) {
- if (pci_channel_offline(dev->pdev)) {
+ if (pci_channel_offline(dev->persist->pdev)) {
/*
* Device is going through error recovery
* and cannot accept commands.
*/
- ret = -EIO;
goto out;
}
@@ -391,7 +504,11 @@ static int mlx4_cmd_post(struct mlx4_dev *dev, u64 in_param, u64 out_param,
ret = 0;
out:
- mutex_unlock(&cmd->hcr_mutex);
+ if (ret)
+ mlx4_warn(dev, "Could not post command 0x%x: ret=%d, in_param=0x%llx, in_mod=0x%x, op_mod=0x%x\n",
+ op, ret, in_param, in_modifier, op_modifier);
+ mutex_unlock(&dev->persist->device_state_mutex);
+
return ret;
}
@@ -428,8 +545,11 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
}
ret = mlx4_status_to_errno(vhcr->status);
}
+ if (ret &&
+ dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ ret = mlx4_internal_err_ret_value(dev, op, op_modifier);
} else {
- ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0,
+ ret = mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_POST, 0, op,
MLX4_COMM_TIME + timeout);
if (!ret) {
if (out_is_imm) {
@@ -443,9 +563,14 @@ static int mlx4_slave_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
}
}
ret = mlx4_status_to_errno(vhcr->status);
- } else
- mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n",
- op);
+ } else {
+ if (dev->persist->state &
+ MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ ret = mlx4_internal_err_ret_value(dev, op,
+ op_modifier);
+ else
+ mlx4_err(dev, "failed execution of VHCR_POST command opcode 0x%x\n", op);
+ }
}
mutex_unlock(&priv->cmd.slave_cmd_mutex);
@@ -464,12 +589,12 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
down(&priv->cmd.poll_sem);
- if (pci_channel_offline(dev->pdev)) {
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
/*
* Device is going through error recovery
* and cannot accept commands.
*/
- err = -EIO;
+ err = mlx4_internal_err_ret_value(dev, op, op_modifier);
goto out;
}
@@ -483,16 +608,21 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
in_modifier, op_modifier, op, CMD_POLL_TOKEN, 0);
if (err)
- goto out;
+ goto out_reset;
end = msecs_to_jiffies(timeout) + jiffies;
while (cmd_pending(dev) && time_before(jiffies, end)) {
- if (pci_channel_offline(dev->pdev)) {
+ if (pci_channel_offline(dev->persist->pdev)) {
/*
* Device is going through error recovery
* and cannot accept commands.
*/
err = -EIO;
+ goto out_reset;
+ }
+
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR) {
+ err = mlx4_internal_err_ret_value(dev, op, op_modifier);
goto out;
}
@@ -502,8 +632,8 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
if (cmd_pending(dev)) {
mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
op);
- err = -ETIMEDOUT;
- goto out;
+ err = -EIO;
+ goto out_reset;
}
if (out_is_imm)
@@ -515,10 +645,17 @@ static int mlx4_cmd_poll(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
stat = be32_to_cpu((__force __be32)
__raw_readl(hcr + HCR_STATUS_OFFSET)) >> 24;
err = mlx4_status_to_errno(stat);
- if (err)
+ if (err) {
mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
op, stat);
+ if (mlx4_closing_cmd_fatal_error(op, stat))
+ goto out_reset;
+ goto out;
+ }
+out_reset:
+ if (err)
+ err = mlx4_cmd_reset_flow(dev, op, op_modifier, err);
out:
up(&priv->cmd.poll_sem);
return err;
@@ -565,17 +702,19 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
goto out;
}
- init_completion(&context->done);
+ reinit_completion(&context->done);
- mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
- in_modifier, op_modifier, op, context->token, 1);
+ err = mlx4_cmd_post(dev, in_param, out_param ? *out_param : 0,
+ in_modifier, op_modifier, op, context->token, 1);
+ if (err)
+ goto out_reset;
if (!wait_for_completion_timeout(&context->done,
msecs_to_jiffies(timeout))) {
mlx4_warn(dev, "command 0x%x timed out (go bit not cleared)\n",
op);
- err = -EBUSY;
- goto out;
+ err = -EIO;
+ goto out_reset;
}
err = context->result;
@@ -592,12 +731,20 @@ static int mlx4_cmd_wait(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
else
mlx4_err(dev, "command 0x%x failed: fw status = 0x%x\n",
op, context->fw_status);
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ err = mlx4_internal_err_ret_value(dev, op, op_modifier);
+ else if (mlx4_closing_cmd_fatal_error(op, context->fw_status))
+ goto out_reset;
+
goto out;
}
if (out_is_imm)
*out_param = context->out_param;
+out_reset:
+ if (err)
+ err = mlx4_cmd_reset_flow(dev, op, op_modifier, err);
out:
spin_lock(&cmd->context_lock);
context->next = cmd->free_head;
@@ -612,10 +759,13 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
int out_is_imm, u32 in_modifier, u8 op_modifier,
u16 op, unsigned long timeout, int native)
{
- if (pci_channel_offline(dev->pdev))
- return -EIO;
+ if (pci_channel_offline(dev->persist->pdev))
+ return mlx4_cmd_reset_flow(dev, op, op_modifier, -EIO);
if (!mlx4_is_mfunc(dev) || (native && mlx4_is_master(dev))) {
+ if (dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ return mlx4_internal_err_ret_value(dev, op,
+ op_modifier);
if (mlx4_priv(dev)->cmd.use_events)
return mlx4_cmd_wait(dev, in_param, out_param,
out_is_imm, in_modifier,
@@ -631,7 +781,7 @@ int __mlx4_cmd(struct mlx4_dev *dev, u64 in_param, u64 *out_param,
EXPORT_SYMBOL_GPL(__mlx4_cmd);
-static int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev)
+int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev)
{
return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_ARM_COMM_CHANNEL,
MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
@@ -751,7 +901,9 @@ static int mlx4_MAD_IFC_wrapper(struct mlx4_dev *dev, int slave,
index = be32_to_cpu(smp->attr_mod);
if (port < 1 || port > dev->caps.num_ports)
return -EINVAL;
- table = kcalloc(dev->caps.pkey_table_len[port], sizeof *table, GFP_KERNEL);
+ table = kcalloc((dev->caps.pkey_table_len[port] / 32) + 1,
+ sizeof(*table) * 32, GFP_KERNEL);
+
if (!table)
return -ENOMEM;
/* need to get the full pkey table because the paravirtualized
@@ -1071,7 +1223,7 @@ static struct mlx4_cmd_info cmd_info[] = {
{
.opcode = MLX4_CMD_HW2SW_EQ,
.has_inbox = false,
- .has_outbox = true,
+ .has_outbox = false,
.out_is_imm = false,
.encode_slave_id = true,
.verify = NULL,
@@ -1431,6 +1583,15 @@ static struct mlx4_cmd_info cmd_info[] = {
.verify = NULL,
.wrapper = mlx4_CMD_EPERM_wrapper
},
+ {
+ .opcode = MLX4_CMD_VIRT_PORT_MAP,
+ .has_inbox = false,
+ .has_outbox = false,
+ .out_is_imm = false,
+ .encode_slave_id = false,
+ .verify = NULL,
+ .wrapper = mlx4_CMD_EPERM_wrapper
+ },
};
static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
@@ -1460,8 +1621,10 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
ALIGN(sizeof(struct mlx4_vhcr_cmd),
MLX4_ACCESS_MEM_ALIGN), 1);
if (ret) {
- mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n",
- __func__, ret);
+ if (!(dev->persist->state &
+ MLX4_DEVICE_STATE_INTERNAL_ERROR))
+ mlx4_err(dev, "%s: Failed reading vhcr ret: 0x%x\n",
+ __func__, ret);
kfree(vhcr);
return ret;
}
@@ -1500,11 +1663,14 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
goto out_status;
}
- if (mlx4_ACCESS_MEM(dev, inbox->dma, slave,
- vhcr->in_param,
- MLX4_MAILBOX_SIZE, 1)) {
- mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n",
- __func__, cmd->opcode);
+ ret = mlx4_ACCESS_MEM(dev, inbox->dma, slave,
+ vhcr->in_param,
+ MLX4_MAILBOX_SIZE, 1);
+ if (ret) {
+ if (!(dev->persist->state &
+ MLX4_DEVICE_STATE_INTERNAL_ERROR))
+ mlx4_err(dev, "%s: Failed reading inbox (cmd:0x%x)\n",
+ __func__, cmd->opcode);
vhcr_cmd->status = CMD_STAT_INTERNAL_ERR;
goto out_status;
}
@@ -1552,8 +1718,9 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
}
if (err) {
- mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n",
- vhcr->op, slave, vhcr->errno, err);
+ if (!(dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR))
+ mlx4_warn(dev, "vhcr command:0x%x slave:%d failed with error:%d, status %d\n",
+ vhcr->op, slave, vhcr->errno, err);
vhcr_cmd->status = mlx4_errno_to_status(err);
goto out_status;
}
@@ -1568,7 +1735,9 @@ static int mlx4_master_process_vhcr(struct mlx4_dev *dev, int slave,
/* If we failed to write back the outbox after the
*command was successfully executed, we must fail this
* slave, as it is now in undefined state */
- mlx4_err(dev, "%s:Failed writing outbox\n", __func__);
+ if (!(dev->persist->state &
+ MLX4_DEVICE_STATE_INTERNAL_ERROR))
+ mlx4_err(dev, "%s:Failed writing outbox\n", __func__);
goto out;
}
}
@@ -1847,8 +2016,11 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
break;
case MLX4_COMM_CMD_VHCR_POST:
if ((slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_EN) &&
- (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST))
+ (slave_state[slave].last_cmd != MLX4_COMM_CMD_VHCR_POST)) {
+ mlx4_warn(dev, "slave:%d is out of sync, cmd=0x%x, last command=0x%x, reset is needed\n",
+ slave, cmd, slave_state[slave].last_cmd);
goto reset_slave;
+ }
mutex_lock(&priv->cmd.slave_cmd_mutex);
if (mlx4_master_process_vhcr(dev, slave, NULL)) {
@@ -1882,7 +2054,18 @@ static void mlx4_master_do_cmd(struct mlx4_dev *dev, int slave, u8 cmd,
reset_slave:
/* cleanup any slave resources */
- mlx4_delete_all_resources_for_slave(dev, slave);
+ if (dev->persist->interface_state & MLX4_INTERFACE_STATE_UP)
+ mlx4_delete_all_resources_for_slave(dev, slave);
+
+ if (cmd != MLX4_COMM_CMD_RESET) {
+ mlx4_warn(dev, "Turn on internal error to force reset, slave=%d, cmd=0x%x\n",
+ slave, cmd);
+ /* Turn on internal error letting slave reset itself immeditaly,
+ * otherwise it might take till timeout on command is passed
+ */
+ reply |= ((u32)COMM_CHAN_EVENT_INTERNAL_ERR);
+ }
+
spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
if (!slave_state[slave].is_slave_going_down)
slave_state[slave].last_cmd = MLX4_COMM_CMD_RESET;
@@ -1958,17 +2141,28 @@ void mlx4_master_comm_channel(struct work_struct *work)
static int sync_toggles(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- int wr_toggle;
- int rd_toggle;
+ u32 wr_toggle;
+ u32 rd_toggle;
unsigned long end;
- wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write)) >> 31;
- end = jiffies + msecs_to_jiffies(5000);
+ wr_toggle = swab32(readl(&priv->mfunc.comm->slave_write));
+ if (wr_toggle == 0xffffffff)
+ end = jiffies + msecs_to_jiffies(30000);
+ else
+ end = jiffies + msecs_to_jiffies(5000);
while (time_before(jiffies, end)) {
- rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read)) >> 31;
- if (rd_toggle == wr_toggle) {
- priv->cmd.comm_toggle = rd_toggle;
+ rd_toggle = swab32(readl(&priv->mfunc.comm->slave_read));
+ if (wr_toggle == 0xffffffff || rd_toggle == 0xffffffff) {
+ /* PCI might be offline */
+ msleep(100);
+ wr_toggle = swab32(readl(&priv->mfunc.comm->
+ slave_write));
+ continue;
+ }
+
+ if (rd_toggle >> 31 == wr_toggle >> 31) {
+ priv->cmd.comm_toggle = rd_toggle >> 31;
return 0;
}
@@ -1997,11 +2191,12 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
if (mlx4_is_master(dev))
priv->mfunc.comm =
- ioremap(pci_resource_start(dev->pdev, priv->fw.comm_bar) +
+ ioremap(pci_resource_start(dev->persist->pdev,
+ priv->fw.comm_bar) +
priv->fw.comm_base, MLX4_COMM_PAGESIZE);
else
priv->mfunc.comm =
- ioremap(pci_resource_start(dev->pdev, 2) +
+ ioremap(pci_resource_start(dev->persist->pdev, 2) +
MLX4_SLAVE_COMM_BASE, MLX4_COMM_PAGESIZE);
if (!priv->mfunc.comm) {
mlx4_err(dev, "Couldn't map communication vector\n");
@@ -2073,13 +2268,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
if (mlx4_init_resource_tracker(dev))
goto err_thread;
- err = mlx4_ARM_COMM_CHANNEL(dev);
- if (err) {
- mlx4_err(dev, " Failed to arm comm channel eq: %x\n",
- err);
- goto err_resource;
- }
-
} else {
err = sync_toggles(dev);
if (err) {
@@ -2089,8 +2277,6 @@ int mlx4_multi_func_init(struct mlx4_dev *dev)
}
return 0;
-err_resource:
- mlx4_free_resource_tracker(dev, RES_TR_FREE_ALL);
err_thread:
flush_workqueue(priv->mfunc.master.comm_wq);
destroy_workqueue(priv->mfunc.master.comm_wq);
@@ -2107,9 +2293,9 @@ err_comm_admin:
err_comm:
iounmap(priv->mfunc.comm);
err_vhcr:
- dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
- priv->mfunc.vhcr,
- priv->mfunc.vhcr_dma);
+ dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
+ priv->mfunc.vhcr,
+ priv->mfunc.vhcr_dma);
priv->mfunc.vhcr = NULL;
return -ENOMEM;
}
@@ -2120,7 +2306,6 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
int flags = 0;
if (!priv->cmd.initialized) {
- mutex_init(&priv->cmd.hcr_mutex);
mutex_init(&priv->cmd.slave_cmd_mutex);
sema_init(&priv->cmd.poll_sem, 1);
priv->cmd.use_events = 0;
@@ -2130,8 +2315,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
}
if (!mlx4_is_slave(dev) && !priv->cmd.hcr) {
- priv->cmd.hcr = ioremap(pci_resource_start(dev->pdev, 0) +
- MLX4_HCR_BASE, MLX4_HCR_SIZE);
+ priv->cmd.hcr = ioremap(pci_resource_start(dev->persist->pdev,
+ 0) + MLX4_HCR_BASE, MLX4_HCR_SIZE);
if (!priv->cmd.hcr) {
mlx4_err(dev, "Couldn't map command register\n");
goto err;
@@ -2140,7 +2325,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
}
if (mlx4_is_mfunc(dev) && !priv->mfunc.vhcr) {
- priv->mfunc.vhcr = dma_alloc_coherent(&(dev->pdev->dev), PAGE_SIZE,
+ priv->mfunc.vhcr = dma_alloc_coherent(&dev->persist->pdev->dev,
+ PAGE_SIZE,
&priv->mfunc.vhcr_dma,
GFP_KERNEL);
if (!priv->mfunc.vhcr)
@@ -2150,7 +2336,8 @@ int mlx4_cmd_init(struct mlx4_dev *dev)
}
if (!priv->cmd.pool) {
- priv->cmd.pool = pci_pool_create("mlx4_cmd", dev->pdev,
+ priv->cmd.pool = pci_pool_create("mlx4_cmd",
+ dev->persist->pdev,
MLX4_MAILBOX_SIZE,
MLX4_MAILBOX_SIZE, 0);
if (!priv->cmd.pool)
@@ -2166,6 +2353,27 @@ err:
return -ENOMEM;
}
+void mlx4_report_internal_err_comm_event(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int slave;
+ u32 slave_read;
+
+ /* Report an internal error event to all
+ * communication channels.
+ */
+ for (slave = 0; slave < dev->num_slaves; slave++) {
+ slave_read = swab32(readl(&priv->mfunc.comm[slave].slave_read));
+ slave_read |= (u32)COMM_CHAN_EVENT_INTERNAL_ERR;
+ __raw_writel((__force u32)cpu_to_be32(slave_read),
+ &priv->mfunc.comm[slave].slave_read);
+ /* Make sure that our comm channel write doesn't
+ * get mixed in with writes from another CPU.
+ */
+ mmiowb();
+ }
+}
+
void mlx4_multi_func_cleanup(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -2181,6 +2389,7 @@ void mlx4_multi_func_cleanup(struct mlx4_dev *dev)
kfree(priv->mfunc.master.slave_state);
kfree(priv->mfunc.master.vf_admin);
kfree(priv->mfunc.master.vf_oper);
+ dev->num_slaves = 0;
}
iounmap(priv->mfunc.comm);
@@ -2202,7 +2411,7 @@ void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask)
}
if (mlx4_is_mfunc(dev) && priv->mfunc.vhcr &&
(cleanup_mask & MLX4_CMD_CLEANUP_VHCR)) {
- dma_free_coherent(&(dev->pdev->dev), PAGE_SIZE,
+ dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
priv->mfunc.vhcr, priv->mfunc.vhcr_dma);
priv->mfunc.vhcr = NULL;
}
@@ -2229,6 +2438,11 @@ int mlx4_cmd_use_events(struct mlx4_dev *dev)
for (i = 0; i < priv->cmd.max_cmds; ++i) {
priv->cmd.context[i].token = i;
priv->cmd.context[i].next = i + 1;
+ /* To support fatal error flow, initialize all
+ * cmd contexts to allow simulating completions
+ * with complete() at any time.
+ */
+ init_completion(&priv->cmd.context[i].done);
}
priv->cmd.context[priv->cmd.max_cmds - 1].next = -1;
@@ -2306,8 +2520,9 @@ u32 mlx4_comm_get_version(void)
static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
{
- if ((vf < 0) || (vf >= dev->num_vfs)) {
- mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n", vf, dev->num_vfs);
+ if ((vf < 0) || (vf >= dev->persist->num_vfs)) {
+ mlx4_err(dev, "Bad vf number:%d (number of activated vf: %d)\n",
+ vf, dev->persist->num_vfs);
return -EINVAL;
}
@@ -2316,7 +2531,7 @@ static int mlx4_get_slave_indx(struct mlx4_dev *dev, int vf)
int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave)
{
- if (slave < 1 || slave > dev->num_vfs) {
+ if (slave < 1 || slave > dev->persist->num_vfs) {
mlx4_err(dev,
"Bad slave number:%d (number of activated slaves: %lu)\n",
slave, dev->num_slaves);
@@ -2325,6 +2540,25 @@ int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave)
return slave - 1;
}
+void mlx4_cmd_wake_completions(struct mlx4_dev *dev)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_cmd_context *context;
+ int i;
+
+ spin_lock(&priv->cmd.context_lock);
+ if (priv->cmd.context) {
+ for (i = 0; i < priv->cmd.max_cmds; ++i) {
+ context = &priv->cmd.context[i];
+ context->fw_status = CMD_STAT_INTERNAL_ERR;
+ context->result =
+ mlx4_status_to_errno(CMD_STAT_INTERNAL_ERR);
+ complete(&context->done);
+ }
+ }
+ spin_unlock(&priv->cmd.context_lock);
+}
+
struct mlx4_active_ports mlx4_get_active_ports(struct mlx4_dev *dev, int slave)
{
struct mlx4_active_ports actv_ports;
@@ -2388,7 +2622,7 @@ struct mlx4_slaves_pport mlx4_phys_to_slaves_pport(struct mlx4_dev *dev,
if (port <= 0 || port > dev->caps.num_ports)
return slaves_pport;
- for (i = 0; i < dev->num_vfs + 1; i++) {
+ for (i = 0; i < dev->persist->num_vfs + 1; i++) {
struct mlx4_active_ports actv_ports =
mlx4_get_active_ports(dev, i);
if (test_bit(port - 1, actv_ports.ports))
@@ -2408,7 +2642,7 @@ struct mlx4_slaves_pport mlx4_phys_to_slaves_pport_actv(
bitmap_zero(slaves_pport.slaves, MLX4_MFUNC_MAX);
- for (i = 0; i < dev->num_vfs + 1; i++) {
+ for (i = 0; i < dev->persist->num_vfs + 1; i++) {
struct mlx4_active_ports actv_ports =
mlx4_get_active_ports(dev, i);
if (bitmap_equal(crit_ports->ports, actv_ports.ports,
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_clock.c b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
index 999014413b1a..90b5309cdb5c 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_clock.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_clock.c
@@ -32,6 +32,7 @@
*/
#include <linux/mlx4/device.h>
+#include <linux/clocksource.h>
#include "mlx4_en.h"
@@ -147,12 +148,9 @@ static int mlx4_en_phc_adjtime(struct ptp_clock_info *ptp, s64 delta)
struct mlx4_en_dev *mdev = container_of(ptp, struct mlx4_en_dev,
ptp_clock_info);
unsigned long flags;
- s64 now;
write_lock_irqsave(&mdev->clock_lock, flags);
- now = timecounter_read(&mdev->clock);
- now += delta;
- timecounter_init(&mdev->clock, &mdev->cycles, now);
+ timecounter_adjtime(&mdev->clock, delta);
write_unlock_irqrestore(&mdev->clock_lock, flags);
return 0;
@@ -243,7 +241,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
{
struct mlx4_dev *dev = mdev->dev;
unsigned long flags;
- u64 ns;
+ u64 ns, zero = 0;
rwlock_init(&mdev->clock_lock);
@@ -268,7 +266,7 @@ void mlx4_en_init_timestamp(struct mlx4_en_dev *mdev)
/* Calculate period in seconds to call the overflow watchdog - to make
* sure counter is checked at least once every wrap around.
*/
- ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask);
+ ns = cyclecounter_cyc2ns(&mdev->cycles, mdev->cycles.mask, zero, &zero);
do_div(ns, NSEC_PER_SEC / 2 / HZ);
mdev->overflow_period = ns;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_cq.c b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
index 82322b1c8411..22da4d0d0f05 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_cq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_cq.c
@@ -70,10 +70,10 @@ int mlx4_en_create_cq(struct mlx4_en_priv *priv,
/* Allocate HW buffers on provided NUMA node.
* dev->numa_node is used in mtt range allocation flow.
*/
- set_dev_node(&mdev->dev->pdev->dev, node);
+ set_dev_node(&mdev->dev->persist->pdev->dev, node);
err = mlx4_alloc_hwq_res(mdev->dev, &cq->wqres,
cq->buf_size, 2 * PAGE_SIZE);
- set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node);
+ set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node);
if (err)
goto err_cq;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
index 90e0f045a6bc..a7b58ba8492b 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_ethtool.c
@@ -92,7 +92,7 @@ mlx4_en_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *drvinfo)
(u16) (mdev->dev->caps.fw_ver >> 32),
(u16) ((mdev->dev->caps.fw_ver >> 16) & 0xffff),
(u16) (mdev->dev->caps.fw_ver & 0xffff));
- strlcpy(drvinfo->bus_info, pci_name(mdev->dev->pdev),
+ strlcpy(drvinfo->bus_info, pci_name(mdev->dev->persist->pdev),
sizeof(drvinfo->bus_info));
drvinfo->n_stats = 0;
drvinfo->regdump_len = 0;
@@ -770,22 +770,20 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return 0;
}
- proto_admin = cpu_to_be32(ptys_adv);
- if (speed >= 0 && speed != priv->port_state.link_speed)
- /* If speed was set then speed decides :-) */
- proto_admin = speed_set_ptys_admin(priv, speed,
- ptys_reg.eth_proto_cap);
+ proto_admin = cmd->autoneg == AUTONEG_ENABLE ?
+ cpu_to_be32(ptys_adv) :
+ speed_set_ptys_admin(priv, speed,
+ ptys_reg.eth_proto_cap);
proto_admin &= ptys_reg.eth_proto_cap;
-
- if (proto_admin == ptys_reg.eth_proto_admin)
- return 0; /* Nothing to change */
-
if (!proto_admin) {
en_warn(priv, "Not supported link mode(s) requested, check supported link modes.\n");
return -EINVAL; /* nothing to change due to bad input */
}
+ if (proto_admin == ptys_reg.eth_proto_admin)
+ return 0; /* Nothing to change */
+
en_dbg(DRV, priv, "mlx4_ACCESS_PTYS_REG SET: ptys_reg.eth_proto_admin = 0x%x\n",
be32_to_cpu(proto_admin));
@@ -798,9 +796,9 @@ static int mlx4_en_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
return ret;
}
- en_warn(priv, "Port link mode changed, restarting port...\n");
mutex_lock(&priv->mdev->state_lock);
if (priv->port_up) {
+ en_warn(priv, "Port link mode changed, restarting port...\n");
mlx4_en_stop_port(dev, 1);
if (mlx4_en_start_port(dev))
en_err(priv, "Failed restarting port %d\n", priv->port);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_main.c b/drivers/net/ethernet/mellanox/mlx4/en_main.c
index 9f16f754137b..58d5a07d0ff4 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_main.c
@@ -214,6 +214,8 @@ static void mlx4_en_remove(struct mlx4_dev *dev, void *endev_ptr)
iounmap(mdev->uar_map);
mlx4_uar_free(dev, &mdev->priv_uar);
mlx4_pd_free(dev, mdev->priv_pdn);
+ if (mdev->nb.notifier_call)
+ unregister_netdevice_notifier(&mdev->nb);
kfree(mdev);
}
@@ -241,8 +243,8 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
spin_lock_init(&mdev->uar_lock);
mdev->dev = dev;
- mdev->dma_device = &(dev->pdev->dev);
- mdev->pdev = dev->pdev;
+ mdev->dma_device = &dev->persist->pdev->dev;
+ mdev->pdev = dev->persist->pdev;
mdev->device_up = false;
mdev->LSO_support = !!(dev->caps.flags & (1 << 15));
@@ -298,6 +300,12 @@ static void *mlx4_en_add(struct mlx4_dev *dev)
if (mlx4_en_init_netdev(mdev, i, &mdev->profile.prof[i]))
mdev->pndev[i] = NULL;
}
+ /* register notifier */
+ mdev->nb.notifier_call = mlx4_en_netdev_event;
+ if (register_netdevice_notifier(&mdev->nb)) {
+ mdev->nb.notifier_call = NULL;
+ mlx4_err(mdev, "Failed to create notifier\n");
+ }
return mdev;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
index ac6a8f1eea6c..2a210c4efb89 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_netdev.c
@@ -2062,6 +2062,7 @@ void mlx4_en_destroy_netdev(struct net_device *dev)
/* Detach the netdev so tasks would not attempt to access it */
mutex_lock(&mdev->state_lock);
mdev->pndev[priv->port] = NULL;
+ mdev->upper[priv->port] = NULL;
mutex_unlock(&mdev->state_lock);
mlx4_en_free_resources(priv);
@@ -2201,6 +2202,10 @@ static int mlx4_en_set_features(struct net_device *netdev,
return ret;
}
+ if (DEV_FEATURE_CHANGED(netdev, features, NETIF_F_HW_VLAN_CTAG_TX))
+ en_info(priv, "Turn %s TX vlan strip offload\n",
+ (features & NETIF_F_HW_VLAN_CTAG_TX) ? "ON" : "OFF");
+
if (features & NETIF_F_LOOPBACK)
priv->ctrl_flags |= cpu_to_be32(MLX4_WQE_CTRL_FORCE_LOOPBACK);
else
@@ -2441,6 +2446,180 @@ static const struct net_device_ops mlx4_netdev_ops_master = {
#endif
};
+struct mlx4_en_bond {
+ struct work_struct work;
+ struct mlx4_en_priv *priv;
+ int is_bonded;
+ struct mlx4_port_map port_map;
+};
+
+static void mlx4_en_bond_work(struct work_struct *work)
+{
+ struct mlx4_en_bond *bond = container_of(work,
+ struct mlx4_en_bond,
+ work);
+ int err = 0;
+ struct mlx4_dev *dev = bond->priv->mdev->dev;
+
+ if (bond->is_bonded) {
+ if (!mlx4_is_bonded(dev)) {
+ err = mlx4_bond(dev);
+ if (err)
+ en_err(bond->priv, "Fail to bond device\n");
+ }
+ if (!err) {
+ err = mlx4_port_map_set(dev, &bond->port_map);
+ if (err)
+ en_err(bond->priv, "Fail to set port map [%d][%d]: %d\n",
+ bond->port_map.port1,
+ bond->port_map.port2,
+ err);
+ }
+ } else if (mlx4_is_bonded(dev)) {
+ err = mlx4_unbond(dev);
+ if (err)
+ en_err(bond->priv, "Fail to unbond device\n");
+ }
+ dev_put(bond->priv->dev);
+ kfree(bond);
+}
+
+static int mlx4_en_queue_bond_work(struct mlx4_en_priv *priv, int is_bonded,
+ u8 v2p_p1, u8 v2p_p2)
+{
+ struct mlx4_en_bond *bond = NULL;
+
+ bond = kzalloc(sizeof(*bond), GFP_ATOMIC);
+ if (!bond)
+ return -ENOMEM;
+
+ INIT_WORK(&bond->work, mlx4_en_bond_work);
+ bond->priv = priv;
+ bond->is_bonded = is_bonded;
+ bond->port_map.port1 = v2p_p1;
+ bond->port_map.port2 = v2p_p2;
+ dev_hold(priv->dev);
+ queue_work(priv->mdev->workqueue, &bond->work);
+ return 0;
+}
+
+int mlx4_en_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr)
+{
+ struct net_device *ndev = netdev_notifier_info_to_dev(ptr);
+ u8 port = 0;
+ struct mlx4_en_dev *mdev;
+ struct mlx4_dev *dev;
+ int i, num_eth_ports = 0;
+ bool do_bond = true;
+ struct mlx4_en_priv *priv;
+ u8 v2p_port1 = 0;
+ u8 v2p_port2 = 0;
+
+ if (!net_eq(dev_net(ndev), &init_net))
+ return NOTIFY_DONE;
+
+ mdev = container_of(this, struct mlx4_en_dev, nb);
+ dev = mdev->dev;
+
+ /* Go into this mode only when two network devices set on two ports
+ * of the same mlx4 device are slaves of the same bonding master
+ */
+ mlx4_foreach_port(i, dev, MLX4_PORT_TYPE_ETH) {
+ ++num_eth_ports;
+ if (!port && (mdev->pndev[i] == ndev))
+ port = i;
+ mdev->upper[i] = mdev->pndev[i] ?
+ netdev_master_upper_dev_get(mdev->pndev[i]) : NULL;
+ /* condition not met: network device is a slave */
+ if (!mdev->upper[i])
+ do_bond = false;
+ if (num_eth_ports < 2)
+ continue;
+ /* condition not met: same master */
+ if (mdev->upper[i] != mdev->upper[i-1])
+ do_bond = false;
+ }
+ /* condition not met: 2 salves */
+ do_bond = (num_eth_ports == 2) ? do_bond : false;
+
+ /* handle only events that come with enough info */
+ if ((do_bond && (event != NETDEV_BONDING_INFO)) || !port)
+ return NOTIFY_DONE;
+
+ priv = netdev_priv(ndev);
+ if (do_bond) {
+ struct netdev_notifier_bonding_info *notifier_info = ptr;
+ struct netdev_bonding_info *bonding_info =
+ &notifier_info->bonding_info;
+
+ /* required mode 1, 2 or 4 */
+ if ((bonding_info->master.bond_mode != BOND_MODE_ACTIVEBACKUP) &&
+ (bonding_info->master.bond_mode != BOND_MODE_XOR) &&
+ (bonding_info->master.bond_mode != BOND_MODE_8023AD))
+ do_bond = false;
+
+ /* require exactly 2 slaves */
+ if (bonding_info->master.num_slaves != 2)
+ do_bond = false;
+
+ /* calc v2p */
+ if (do_bond) {
+ if (bonding_info->master.bond_mode ==
+ BOND_MODE_ACTIVEBACKUP) {
+ /* in active-backup mode virtual ports are
+ * mapped to the physical port of the active
+ * slave */
+ if (bonding_info->slave.state ==
+ BOND_STATE_BACKUP) {
+ if (port == 1) {
+ v2p_port1 = 2;
+ v2p_port2 = 2;
+ } else {
+ v2p_port1 = 1;
+ v2p_port2 = 1;
+ }
+ } else { /* BOND_STATE_ACTIVE */
+ if (port == 1) {
+ v2p_port1 = 1;
+ v2p_port2 = 1;
+ } else {
+ v2p_port1 = 2;
+ v2p_port2 = 2;
+ }
+ }
+ } else { /* Active-Active */
+ /* in active-active mode a virtual port is
+ * mapped to the native physical port if and only
+ * if the physical port is up */
+ __s8 link = bonding_info->slave.link;
+
+ if (port == 1)
+ v2p_port2 = 2;
+ else
+ v2p_port1 = 1;
+ if ((link == BOND_LINK_UP) ||
+ (link == BOND_LINK_FAIL)) {
+ if (port == 1)
+ v2p_port1 = 1;
+ else
+ v2p_port2 = 2;
+ } else { /* BOND_LINK_DOWN || BOND_LINK_BACK */
+ if (port == 1)
+ v2p_port1 = 2;
+ else
+ v2p_port2 = 1;
+ }
+ }
+ }
+ }
+
+ mlx4_en_queue_bond_work(priv, do_bond,
+ v2p_port1, v2p_port2);
+
+ return NOTIFY_DONE;
+}
+
int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
struct mlx4_en_port_profile *prof)
{
@@ -2458,7 +2637,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
netif_set_real_num_tx_queues(dev, prof->tx_ring_num);
netif_set_real_num_rx_queues(dev, prof->rx_ring_num);
- SET_NETDEV_DEV(dev, &mdev->dev->pdev->dev);
+ SET_NETDEV_DEV(dev, &mdev->dev->persist->pdev->dev);
dev->dev_port = port - 1;
/*
@@ -2623,6 +2802,7 @@ int mlx4_en_init_netdev(struct mlx4_en_dev *mdev, int port,
}
mdev->pndev[port] = dev;
+ mdev->upper[port] = NULL;
netif_carrier_off(dev);
mlx4_en_set_default_moderation(priv);
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_resources.c b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
index f1a5500ff72d..34f2fdf4fe5d 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_resources.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_resources.c
@@ -50,10 +50,14 @@ void mlx4_en_fill_qp_context(struct mlx4_en_priv *priv, int size, int stride,
context->mtu_msgmax = 0xff;
if (!is_tx && !rss)
context->rq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4);
- if (is_tx)
+ if (is_tx) {
context->sq_size_stride = ilog2(size) << 3 | (ilog2(stride) - 4);
- else
+ if (mdev->dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP)
+ context->params2 |= MLX4_QP_BIT_FPP;
+
+ } else {
context->sq_size_stride = ilog2(TXBB_SIZE) - 4;
+ }
context->usr_page = cpu_to_be32(mdev->priv_uar.index);
context->local_qpn = cpu_to_be32(qpn);
context->pri_path.ackto = 1 & 0x07;
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_rx.c b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
index a0474eb94aa3..698d60de1255 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_rx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_rx.c
@@ -162,6 +162,10 @@ static int mlx4_en_init_allocator(struct mlx4_en_priv *priv,
if (mlx4_alloc_pages(priv, &ring->page_alloc[i],
frag_info, GFP_KERNEL | __GFP_COLD))
goto out;
+
+ en_dbg(DRV, priv, " frag %d allocator: - size:%d frags:%d\n",
+ i, ring->page_alloc[i].page_size,
+ atomic_read(&ring->page_alloc[i].page->_count));
}
return 0;
@@ -387,10 +391,10 @@ int mlx4_en_create_rx_ring(struct mlx4_en_priv *priv,
ring->rx_info, tmp);
/* Allocate HW buffers on provided NUMA node */
- set_dev_node(&mdev->dev->pdev->dev, node);
+ set_dev_node(&mdev->dev->persist->pdev->dev, node);
err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres,
ring->buf_size, 2 * PAGE_SIZE);
- set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node);
+ set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node);
if (err)
goto err_info;
@@ -1059,8 +1063,9 @@ void mlx4_en_calc_rx_buf(struct net_device *dev)
(eff_mtu > buf_size + frag_sizes[i]) ?
frag_sizes[i] : eff_mtu - buf_size;
priv->frag_info[i].frag_prefix_size = buf_size;
- priv->frag_info[i].frag_stride = ALIGN(frag_sizes[i],
- SMP_CACHE_BYTES);
+ priv->frag_info[i].frag_stride =
+ ALIGN(priv->frag_info[i].frag_size,
+ SMP_CACHE_BYTES);
buf_size += priv->frag_info[i].frag_size;
i++;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/en_tx.c b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
index e3357bf523df..55f9f5c5344e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/en_tx.c
+++ b/drivers/net/ethernet/mellanox/mlx4/en_tx.c
@@ -91,10 +91,10 @@ int mlx4_en_create_tx_ring(struct mlx4_en_priv *priv,
ring->buf_size = ALIGN(size * ring->stride, MLX4_EN_PAGE_SIZE);
/* Allocate HW buffers on provided NUMA node */
- set_dev_node(&mdev->dev->pdev->dev, node);
+ set_dev_node(&mdev->dev->persist->pdev->dev, node);
err = mlx4_alloc_hwq_res(mdev->dev, &ring->wqres, ring->buf_size,
2 * PAGE_SIZE);
- set_dev_node(&mdev->dev->pdev->dev, mdev->dev->numa_node);
+ set_dev_node(&mdev->dev->persist->pdev->dev, mdev->dev->numa_node);
if (err) {
en_err(priv, "Failed allocating hwq resources\n");
goto err_bounce;
@@ -682,8 +682,8 @@ u16 mlx4_en_select_queue(struct net_device *dev, struct sk_buff *skb,
if (dev->num_tc)
return skb_tx_hash(dev, skb);
- if (vlan_tx_tag_present(skb))
- up = vlan_tx_tag_get(skb) >> VLAN_PRIO_SHIFT;
+ if (skb_vlan_tag_present(skb))
+ up = skb_vlan_tag_get(skb) >> VLAN_PRIO_SHIFT;
return fallback(dev, skb) % rings_p_up + up * rings_p_up;
}
@@ -742,8 +742,8 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
goto tx_drop;
}
- if (vlan_tx_tag_present(skb))
- vlan_tag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb))
+ vlan_tag = skb_vlan_tag_get(skb);
netdev_txq_bql_enqueue_prefetchw(ring->tx_queue);
@@ -930,7 +930,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
real_size = (real_size / 16) & 0x3f;
if (ring->bf_enabled && desc_size <= MAX_BF && !bounce &&
- !vlan_tx_tag_present(skb) && send_doorbell) {
+ !skb_vlan_tag_present(skb) && send_doorbell) {
tx_desc->ctrl.bf_qpn = ring->doorbell_qpn |
cpu_to_be32(real_size);
@@ -952,7 +952,7 @@ netdev_tx_t mlx4_en_xmit(struct sk_buff *skb, struct net_device *dev)
} else {
tx_desc->ctrl.vlan_tag = cpu_to_be16(vlan_tag);
tx_desc->ctrl.ins_vlan = MLX4_WQE_CTRL_INS_VLAN *
- !!vlan_tx_tag_present(skb);
+ !!skb_vlan_tag_present(skb);
tx_desc->ctrl.fence_size = real_size;
/* Ensure new descriptor hits memory
diff --git a/drivers/net/ethernet/mellanox/mlx4/eq.c b/drivers/net/ethernet/mellanox/mlx4/eq.c
index 3d275fbaf0eb..264bc15c1ff2 100644
--- a/drivers/net/ethernet/mellanox/mlx4/eq.c
+++ b/drivers/net/ethernet/mellanox/mlx4/eq.c
@@ -88,6 +88,8 @@ static u64 get_async_ev_mask(struct mlx4_dev *dev)
u64 async_ev_mask = MLX4_ASYNC_EVENT_MASK;
if (dev->caps.flags & MLX4_DEV_CAP_FLAG_PORT_MNG_CHG_EV)
async_ev_mask |= (1ull << MLX4_EVENT_TYPE_PORT_MNG_CHG_EVENT);
+ if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT)
+ async_ev_mask |= (1ull << MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT);
return async_ev_mask;
}
@@ -237,7 +239,7 @@ int mlx4_gen_guid_change_eqe(struct mlx4_dev *dev, int slave, u8 port)
struct mlx4_eqe eqe;
/*don't send if we don't have the that slave */
- if (dev->num_vfs < slave)
+ if (dev->persist->num_vfs < slave)
return 0;
memset(&eqe, 0, sizeof eqe);
@@ -255,7 +257,7 @@ int mlx4_gen_port_state_change_eqe(struct mlx4_dev *dev, int slave, u8 port,
struct mlx4_eqe eqe;
/*don't send if we don't have the that slave */
- if (dev->num_vfs < slave)
+ if (dev->persist->num_vfs < slave)
return 0;
memset(&eqe, 0, sizeof eqe);
@@ -310,7 +312,7 @@ static void set_all_slave_state(struct mlx4_dev *dev, u8 port, int event)
struct mlx4_slaves_pport slaves_pport = mlx4_phys_to_slaves_pport(dev,
port);
- for (i = 0; i < dev->num_vfs + 1; i++)
+ for (i = 0; i < dev->persist->num_vfs + 1; i++)
if (test_bit(i, slaves_pport.slaves))
set_and_calc_slave_port_state(dev, i, port,
event, &gen_event);
@@ -429,8 +431,14 @@ void mlx4_master_handle_slave_flr(struct work_struct *work)
if (MLX4_COMM_CMD_FLR == slave_state[i].last_cmd) {
mlx4_dbg(dev, "mlx4_handle_slave_flr: clean slave: %d\n",
i);
-
- mlx4_delete_all_resources_for_slave(dev, i);
+ /* In case of 'Reset flow' FLR can be generated for
+ * a slave before mlx4_load_one is done.
+ * make sure interface is up before trying to delete
+ * slave resources which weren't allocated yet.
+ */
+ if (dev->persist->interface_state &
+ MLX4_INTERFACE_STATE_UP)
+ mlx4_delete_all_resources_for_slave(dev, i);
/*return the slave to running mode*/
spin_lock_irqsave(&priv->mfunc.master.slave_state_lock, flags);
slave_state[i].last_cmd = MLX4_COMM_CMD_RESET;
@@ -560,7 +568,8 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
mlx4_priv(dev)->sense.do_sense_port[port] = 1;
if (!mlx4_is_master(dev))
break;
- for (i = 0; i < dev->num_vfs + 1; i++) {
+ for (i = 0; i < dev->persist->num_vfs + 1;
+ i++) {
if (!test_bit(i, slaves_port.slaves))
continue;
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH) {
@@ -596,7 +605,9 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
if (!mlx4_is_master(dev))
break;
if (dev->caps.port_type[port] == MLX4_PORT_TYPE_ETH)
- for (i = 0; i < dev->num_vfs + 1; i++) {
+ for (i = 0;
+ i < dev->persist->num_vfs + 1;
+ i++) {
if (!test_bit(i, slaves_port.slaves))
continue;
if (i == mlx4_master_func_num(dev))
@@ -727,6 +738,26 @@ static int mlx4_eq_int(struct mlx4_dev *dev, struct mlx4_eq *eq)
(unsigned long) eqe);
break;
+ case MLX4_EVENT_TYPE_RECOVERABLE_ERROR_EVENT:
+ switch (eqe->subtype) {
+ case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_BAD_CABLE:
+ mlx4_warn(dev, "Bad cable detected on port %u\n",
+ eqe->event.bad_cable.port);
+ break;
+ case MLX4_RECOVERABLE_ERROR_EVENT_SUBTYPE_UNSUPPORTED_CABLE:
+ mlx4_warn(dev, "Unsupported cable detected\n");
+ break;
+ default:
+ mlx4_dbg(dev,
+ "Unhandled recoverable error event detected: %02x(%02x) on EQ %d at index %u. owner=%x, nent=0x%x, ownership=%s\n",
+ eqe->type, eqe->subtype, eq->eqn,
+ eq->cons_index, eqe->owner, eq->nent,
+ !!(eqe->owner & 0x80) ^
+ !!(eq->cons_index & eq->nent) ? "HW" : "SW");
+ break;
+ }
+ break;
+
case MLX4_EVENT_TYPE_EEC_CATAS_ERROR:
case MLX4_EVENT_TYPE_ECC_DETECT:
default:
@@ -837,12 +868,10 @@ static int mlx4_SW2HW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
MLX4_CMD_WRAPPED);
}
-static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, struct mlx4_cmd_mailbox *mailbox,
- int eq_num)
+static int mlx4_HW2SW_EQ(struct mlx4_dev *dev, int eq_num)
{
- return mlx4_cmd_box(dev, 0, mailbox->dma, eq_num,
- 0, MLX4_CMD_HW2SW_EQ, MLX4_CMD_TIME_CLASS_A,
- MLX4_CMD_WRAPPED);
+ return mlx4_cmd(dev, 0, eq_num, 1, MLX4_CMD_HW2SW_EQ,
+ MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
}
static int mlx4_num_eq_uar(struct mlx4_dev *dev)
@@ -865,7 +894,7 @@ static void __iomem *mlx4_get_eq_uar(struct mlx4_dev *dev, struct mlx4_eq *eq)
if (!priv->eq_table.uar_map[index]) {
priv->eq_table.uar_map[index] =
- ioremap(pci_resource_start(dev->pdev, 2) +
+ ioremap(pci_resource_start(dev->persist->pdev, 2) +
((eq->eqn / 4) << PAGE_SHIFT),
PAGE_SIZE);
if (!priv->eq_table.uar_map[index]) {
@@ -928,8 +957,10 @@ static int mlx4_create_eq(struct mlx4_dev *dev, int nent,
eq_context = mailbox->buf;
for (i = 0; i < npages; ++i) {
- eq->page_list[i].buf = dma_alloc_coherent(&dev->pdev->dev,
- PAGE_SIZE, &t, GFP_KERNEL);
+ eq->page_list[i].buf = dma_alloc_coherent(&dev->persist->
+ pdev->dev,
+ PAGE_SIZE, &t,
+ GFP_KERNEL);
if (!eq->page_list[i].buf)
goto err_out_free_pages;
@@ -995,7 +1026,7 @@ err_out_free_eq:
err_out_free_pages:
for (i = 0; i < npages; ++i)
if (eq->page_list[i].buf)
- dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
+ dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
eq->page_list[i].buf,
eq->page_list[i].map);
@@ -1013,7 +1044,6 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
struct mlx4_eq *eq)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- struct mlx4_cmd_mailbox *mailbox;
int err;
int i;
/* CX3 is capable of extending the CQE/EQE from 32 to 64 bytes, with
@@ -1021,36 +1051,21 @@ static void mlx4_free_eq(struct mlx4_dev *dev,
*/
int npages = PAGE_ALIGN(dev->caps.eqe_size * eq->nent) / PAGE_SIZE;
- mailbox = mlx4_alloc_cmd_mailbox(dev);
- if (IS_ERR(mailbox))
- return;
-
- err = mlx4_HW2SW_EQ(dev, mailbox, eq->eqn);
+ err = mlx4_HW2SW_EQ(dev, eq->eqn);
if (err)
mlx4_warn(dev, "HW2SW_EQ failed (%d)\n", err);
- if (0) {
- mlx4_dbg(dev, "Dumping EQ context %02x:\n", eq->eqn);
- for (i = 0; i < sizeof (struct mlx4_eq_context) / 4; ++i) {
- if (i % 4 == 0)
- pr_cont("[%02x] ", i * 4);
- pr_cont(" %08x", be32_to_cpup(mailbox->buf + i * 4));
- if ((i + 1) % 4 == 0)
- pr_cont("\n");
- }
- }
synchronize_irq(eq->irq);
tasklet_disable(&eq->tasklet_ctx.task);
mlx4_mtt_cleanup(dev, &eq->mtt);
for (i = 0; i < npages; ++i)
- dma_free_coherent(&dev->pdev->dev, PAGE_SIZE,
- eq->page_list[i].buf,
- eq->page_list[i].map);
+ dma_free_coherent(&dev->persist->pdev->dev, PAGE_SIZE,
+ eq->page_list[i].buf,
+ eq->page_list[i].map);
kfree(eq->page_list);
mlx4_bitmap_free(&priv->eq_table.bitmap, eq->eqn, MLX4_USE_RR);
- mlx4_free_cmd_mailbox(dev, mailbox);
}
static void mlx4_free_irqs(struct mlx4_dev *dev)
@@ -1060,7 +1075,7 @@ static void mlx4_free_irqs(struct mlx4_dev *dev)
int i, vec;
if (eq_table->have_irq)
- free_irq(dev->pdev->irq, dev);
+ free_irq(dev->persist->pdev->irq, dev);
for (i = 0; i < dev->caps.num_comp_vectors + 1; ++i)
if (eq_table->eq[i].have_irq) {
@@ -1089,7 +1104,8 @@ static int mlx4_map_clr_int(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
- priv->clr_base = ioremap(pci_resource_start(dev->pdev, priv->fw.clr_int_bar) +
+ priv->clr_base = ioremap(pci_resource_start(dev->persist->pdev,
+ priv->fw.clr_int_bar) +
priv->fw.clr_int_base, MLX4_CLR_INT_SIZE);
if (!priv->clr_base) {
mlx4_err(dev, "Couldn't map interrupt clear register, aborting\n");
@@ -1212,13 +1228,13 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
i * MLX4_IRQNAME_SIZE,
MLX4_IRQNAME_SIZE,
"mlx4-comp-%d@pci:%s", i,
- pci_name(dev->pdev));
+ pci_name(dev->persist->pdev));
} else {
snprintf(priv->eq_table.irq_names +
i * MLX4_IRQNAME_SIZE,
MLX4_IRQNAME_SIZE,
"mlx4-async@pci:%s",
- pci_name(dev->pdev));
+ pci_name(dev->persist->pdev));
}
eq_name = priv->eq_table.irq_names +
@@ -1235,8 +1251,8 @@ int mlx4_init_eq_table(struct mlx4_dev *dev)
snprintf(priv->eq_table.irq_names,
MLX4_IRQNAME_SIZE,
DRV_NAME "@pci:%s",
- pci_name(dev->pdev));
- err = request_irq(dev->pdev->irq, mlx4_interrupt,
+ pci_name(dev->persist->pdev));
+ err = request_irq(dev->persist->pdev->irq, mlx4_interrupt,
IRQF_SHARED, priv->eq_table.irq_names, dev);
if (err)
goto err_out_async;
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.c b/drivers/net/ethernet/mellanox/mlx4/fw.c
index 982861d1df44..5a21e5dc94cb 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.c
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.c
@@ -84,13 +84,10 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
[ 1] = "UC transport",
[ 2] = "UD transport",
[ 3] = "XRC transport",
- [ 4] = "reliable multicast",
- [ 5] = "FCoIB support",
[ 6] = "SRQ support",
[ 7] = "IPoIB checksum offload",
[ 8] = "P_Key violation counter",
[ 9] = "Q_Key violation counter",
- [10] = "VMM",
[12] = "Dual Port Different Protocol (DPDP) support",
[15] = "Big LSO headers",
[16] = "MW support",
@@ -99,12 +96,11 @@ static void dump_dev_cap_flags(struct mlx4_dev *dev, u64 flags)
[19] = "Raw multicast support",
[20] = "Address vector port checking support",
[21] = "UD multicast support",
- [24] = "Demand paging support",
- [25] = "Router support",
[30] = "IBoE support",
[32] = "Unicast loopback support",
[34] = "FCS header control",
- [38] = "Wake On LAN support",
+ [37] = "Wake On LAN (port1) support",
+ [38] = "Wake On LAN (port2) support",
[40] = "UDP RSS support",
[41] = "Unicast VEP steering support",
[42] = "Multicast VEP steering support",
@@ -145,7 +141,9 @@ static void dump_dev_cap_flags2(struct mlx4_dev *dev, u64 flags)
[16] = "CONFIG DEV support",
[17] = "Asymmetric EQs support",
[18] = "More than 80 VFs support",
- [19] = "Performance optimized for limited rule configuration flow steering support"
+ [19] = "Performance optimized for limited rule configuration flow steering support",
+ [20] = "Recoverable error events support",
+ [21] = "Port Remap support"
};
int i;
@@ -259,6 +257,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
#define QUERY_FUNC_CAP_MCG_QUOTA_OFFSET_DEP 0x28
#define QUERY_FUNC_CAP_MAX_EQ_OFFSET 0x2c
#define QUERY_FUNC_CAP_RESERVED_EQ_OFFSET 0x30
+#define QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET 0x48
#define QUERY_FUNC_CAP_QP_QUOTA_OFFSET 0x50
#define QUERY_FUNC_CAP_CQ_QUOTA_OFFSET 0x54
@@ -273,6 +272,7 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
#define QUERY_FUNC_CAP_FLAG_RDMA 0x40
#define QUERY_FUNC_CAP_FLAG_ETH 0x80
#define QUERY_FUNC_CAP_FLAG_QUOTAS 0x10
+#define QUERY_FUNC_CAP_FLAG_RESD_LKEY 0x08
#define QUERY_FUNC_CAP_FLAG_VALID_MAILBOX 0x04
#define QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG (1UL << 31)
@@ -344,9 +344,12 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
} else if (vhcr->op_modifier == 0) {
struct mlx4_active_ports actv_ports =
mlx4_get_active_ports(dev, slave);
- /* enable rdma and ethernet interfaces, and new quota locations */
+ /* enable rdma and ethernet interfaces, new quota locations,
+ * and reserved lkey
+ */
field = (QUERY_FUNC_CAP_FLAG_ETH | QUERY_FUNC_CAP_FLAG_RDMA |
- QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX);
+ QUERY_FUNC_CAP_FLAG_QUOTAS | QUERY_FUNC_CAP_FLAG_VALID_MAILBOX |
+ QUERY_FUNC_CAP_FLAG_RESD_LKEY);
MLX4_PUT(outbox->buf, field, QUERY_FUNC_CAP_FLAGS_OFFSET);
field = min(
@@ -411,6 +414,9 @@ int mlx4_QUERY_FUNC_CAP_wrapper(struct mlx4_dev *dev, int slave,
size = QUERY_FUNC_CAP_EXTRA_FLAGS_BF_QP_ALLOC_FLAG |
QUERY_FUNC_CAP_EXTRA_FLAGS_A0_QP_ALLOC_FLAG;
MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_EXTRA_FLAGS_OFFSET);
+
+ size = dev->caps.reserved_lkey + ((slave << 8) & 0xFF00);
+ MLX4_PUT(outbox->buf, size, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET);
} else
err = -EINVAL;
@@ -503,6 +509,13 @@ int mlx4_QUERY_FUNC_CAP(struct mlx4_dev *dev, u8 gen_or_port,
MLX4_GET(size, outbox, QUERY_FUNC_CAP_RESERVED_EQ_OFFSET);
func_cap->reserved_eq = size & 0xFFFFFF;
+ if (func_cap->flags & QUERY_FUNC_CAP_FLAG_RESD_LKEY) {
+ MLX4_GET(size, outbox, QUERY_FUNC_CAP_QP_RESD_LKEY_OFFSET);
+ func_cap->reserved_lkey = size;
+ } else {
+ func_cap->reserved_lkey = 0;
+ }
+
func_cap->extra_flags = 0;
/* Mailbox data from 0x6c and onward should only be treated if
@@ -851,6 +864,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_EQE_STRIDE;
MLX4_GET(dev_cap->bmme_flags, outbox,
QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
+ if (dev_cap->bmme_flags & MLX4_FLAG_PORT_REMAP)
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_PORT_REMAP;
MLX4_GET(field, outbox, QUERY_DEV_CAP_CONFIG_DEV_OFFSET);
if (field & 0x20)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_CONFIG_DEV;
@@ -859,6 +874,8 @@ int mlx4_QUERY_DEV_CAP(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
MLX4_GET(field32, outbox, QUERY_DEV_CAP_ETH_BACKPL_OFFSET);
if (field32 & (1 << 0))
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_ETH_BACKPL_AN_REP;
+ if (field32 & (1 << 7))
+ dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT;
MLX4_GET(field, outbox, QUERY_DEV_CAP_FW_REASSIGN_MAC);
if (field & 1<<6)
dev_cap->flags2 |= MLX4_DEV_CAP_FLAG2_REASSIGN_MAC_EN;
@@ -1106,9 +1123,10 @@ int mlx4_QUERY_DEV_CAP_wrapper(struct mlx4_dev *dev, int slave,
field &= 0x7f;
MLX4_PUT(outbox->buf, field, QUERY_DEV_CAP_BF_OFFSET);
- /* For guests, disable mw type 2 */
+ /* For guests, disable mw type 2 and port remap*/
MLX4_GET(bmme_flags, outbox->buf, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
bmme_flags &= ~MLX4_BMME_FLAG_TYPE_2_WIN;
+ bmme_flags &= ~MLX4_FLAG_PORT_REMAP;
MLX4_PUT(outbox->buf, bmme_flags, QUERY_DEV_CAP_BMME_FLAGS_OFFSET);
/* turn off device-managed steering capability if not enabled */
@@ -1562,6 +1580,7 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
#define INIT_HCA_VXLAN_OFFSET 0x0c
#define INIT_HCA_CACHELINE_SZ_OFFSET 0x0e
#define INIT_HCA_FLAGS_OFFSET 0x014
+#define INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET 0x018
#define INIT_HCA_QPC_OFFSET 0x020
#define INIT_HCA_QPC_BASE_OFFSET (INIT_HCA_QPC_OFFSET + 0x10)
#define INIT_HCA_LOG_QP_OFFSET (INIT_HCA_QPC_OFFSET + 0x17)
@@ -1668,6 +1687,9 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
dev->caps.userspace_caps |= MLX4_USER_DEV_CAP_LARGE_CQE;
}
+ if (dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_RECOVERABLE_ERROR_EVENT)
+ *(inbox + INIT_HCA_RECOVERABLE_ERROR_EVENT_OFFSET / 4) |= cpu_to_be32(1 << 31);
+
/* QPC/EEC/CQC/EQC/RDMARC attributes */
MLX4_PUT(inbox, param->qpc_base, INIT_HCA_QPC_BASE_OFFSET);
@@ -1752,8 +1774,8 @@ int mlx4_INIT_HCA(struct mlx4_dev *dev, struct mlx4_init_hca_param *param)
MLX4_PUT(inbox, parser_params, INIT_HCA_VXLAN_OFFSET);
}
- err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA, 10000,
- MLX4_CMD_NATIVE);
+ err = mlx4_cmd(dev, mailbox->dma, 0, 0, MLX4_CMD_INIT_HCA,
+ MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
if (err)
mlx4_err(dev, "INIT_HCA returns %d\n", err);
@@ -1879,6 +1901,36 @@ out:
return err;
}
+static int mlx4_hca_core_clock_update(struct mlx4_dev *dev)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ __be32 *outbox;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox)) {
+ mlx4_warn(dev, "hca_core_clock mailbox allocation failed\n");
+ return PTR_ERR(mailbox);
+ }
+ outbox = mailbox->buf;
+
+ err = mlx4_cmd_box(dev, 0, mailbox->dma, 0, 0,
+ MLX4_CMD_QUERY_HCA,
+ MLX4_CMD_TIME_CLASS_B,
+ !mlx4_is_slave(dev));
+ if (err) {
+ mlx4_warn(dev, "hca_core_clock update failed\n");
+ goto out;
+ }
+
+ MLX4_GET(dev->caps.hca_core_clock, outbox, QUERY_HCA_CORE_CLOCK_OFFSET);
+
+out:
+ mlx4_free_cmd_mailbox(dev, mailbox);
+
+ return err;
+}
+
/* for IB-type ports only in SRIOV mode. Checks that both proxy QP0
* and real QP0 are active, so that the paravirtualized QP0 is ready
* to operate */
@@ -1983,6 +2035,9 @@ int mlx4_INIT_PORT(struct mlx4_dev *dev, int port)
err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_INIT_PORT,
MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
+ if (!err)
+ mlx4_hca_core_clock_update(dev);
+
return err;
}
EXPORT_SYMBOL_GPL(mlx4_INIT_PORT);
@@ -2007,7 +2062,7 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
if (dev->caps.port_mask[port] != MLX4_PORT_TYPE_IB) {
if (priv->mfunc.master.init_port_ref[port] == 1) {
err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
- 1000, MLX4_CMD_NATIVE);
+ MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
if (err)
return err;
}
@@ -2018,7 +2073,7 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
if (!priv->mfunc.master.qp0_state[port].qp0_active &&
priv->mfunc.master.qp0_state[port].port_active) {
err = mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
- 1000, MLX4_CMD_NATIVE);
+ MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
if (err)
return err;
priv->mfunc.master.slave_state[slave].init_port_mask &= ~(1 << port);
@@ -2033,15 +2088,15 @@ int mlx4_CLOSE_PORT_wrapper(struct mlx4_dev *dev, int slave,
int mlx4_CLOSE_PORT(struct mlx4_dev *dev, int port)
{
- return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT, 1000,
- MLX4_CMD_WRAPPED);
+ return mlx4_cmd(dev, 0, port, 0, MLX4_CMD_CLOSE_PORT,
+ MLX4_CMD_TIME_CLASS_A, MLX4_CMD_WRAPPED);
}
EXPORT_SYMBOL_GPL(mlx4_CLOSE_PORT);
int mlx4_CLOSE_HCA(struct mlx4_dev *dev, int panic)
{
- return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA, 1000,
- MLX4_CMD_NATIVE);
+ return mlx4_cmd(dev, 0, 0, panic, MLX4_CMD_CLOSE_HCA,
+ MLX4_CMD_TIME_CLASS_C, MLX4_CMD_NATIVE);
}
struct mlx4_config_dev {
@@ -2049,13 +2104,16 @@ struct mlx4_config_dev {
__be32 rsvd1[3];
__be16 vxlan_udp_dport;
__be16 rsvd2;
- __be32 rsvd3[27];
- __be16 rsvd4;
- u8 rsvd5;
+ __be32 rsvd3;
+ __be32 roce_flags;
+ __be32 rsvd4[25];
+ __be16 rsvd5;
+ u8 rsvd6;
u8 rx_checksum_val;
};
#define MLX4_VXLAN_UDP_DPORT (1 << 0)
+#define MLX4_DISABLE_RX_PORT BIT(18)
static int mlx4_CONFIG_DEV_set(struct mlx4_dev *dev, struct mlx4_config_dev *config_dev)
{
@@ -2111,7 +2169,7 @@ static const u8 config_dev_csum_flags[] = {
int mlx4_config_dev_retrieval(struct mlx4_dev *dev,
struct mlx4_config_dev_params *params)
{
- struct mlx4_config_dev config_dev;
+ struct mlx4_config_dev config_dev = {0};
int err;
u8 csum_mask;
@@ -2158,6 +2216,45 @@ int mlx4_config_vxlan_port(struct mlx4_dev *dev, __be16 udp_port)
}
EXPORT_SYMBOL_GPL(mlx4_config_vxlan_port);
+#define CONFIG_DISABLE_RX_PORT BIT(15)
+int mlx4_disable_rx_port_check(struct mlx4_dev *dev, bool dis)
+{
+ struct mlx4_config_dev config_dev;
+
+ memset(&config_dev, 0, sizeof(config_dev));
+ config_dev.update_flags = cpu_to_be32(MLX4_DISABLE_RX_PORT);
+ if (dis)
+ config_dev.roce_flags =
+ cpu_to_be32(CONFIG_DISABLE_RX_PORT);
+
+ return mlx4_CONFIG_DEV_set(dev, &config_dev);
+}
+
+int mlx4_virt2phy_port_map(struct mlx4_dev *dev, u32 port1, u32 port2)
+{
+ struct mlx4_cmd_mailbox *mailbox;
+ struct {
+ __be32 v_port1;
+ __be32 v_port2;
+ } *v2p;
+ int err;
+
+ mailbox = mlx4_alloc_cmd_mailbox(dev);
+ if (IS_ERR(mailbox))
+ return -ENOMEM;
+
+ v2p = mailbox->buf;
+ v2p->v_port1 = cpu_to_be32(port1);
+ v2p->v_port2 = cpu_to_be32(port2);
+
+ err = mlx4_cmd(dev, mailbox->dma, 0,
+ MLX4_SET_PORT_VIRT2PHY, MLX4_CMD_VIRT_PORT_MAP,
+ MLX4_CMD_TIME_CLASS_B, MLX4_CMD_NATIVE);
+
+ mlx4_free_cmd_mailbox(dev, mailbox);
+ return err;
+}
+
int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
{
@@ -2180,7 +2277,8 @@ int mlx4_SET_ICM_SIZE(struct mlx4_dev *dev, u64 icm_size, u64 *aux_pages)
int mlx4_NOP(struct mlx4_dev *dev)
{
/* Input modifier of 0x1f means "finish as soon as possible." */
- return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, 100, MLX4_CMD_NATIVE);
+ return mlx4_cmd(dev, 0, 0x1f, 0, MLX4_CMD_NOP, MLX4_CMD_TIME_CLASS_A,
+ MLX4_CMD_NATIVE);
}
int mlx4_get_phys_port_id(struct mlx4_dev *dev)
diff --git a/drivers/net/ethernet/mellanox/mlx4/fw.h b/drivers/net/ethernet/mellanox/mlx4/fw.h
index 62562b60fa87..f44f7f6017ed 100644
--- a/drivers/net/ethernet/mellanox/mlx4/fw.h
+++ b/drivers/net/ethernet/mellanox/mlx4/fw.h
@@ -147,6 +147,7 @@ struct mlx4_func_cap {
u32 qp0_proxy_qpn;
u32 qp1_tunnel_qpn;
u32 qp1_proxy_qpn;
+ u32 reserved_lkey;
u8 physical_port;
u8 port_flags;
u8 flags1;
diff --git a/drivers/net/ethernet/mellanox/mlx4/icm.c b/drivers/net/ethernet/mellanox/mlx4/icm.c
index 97c9b1db1d27..2a9dd460a95f 100644
--- a/drivers/net/ethernet/mellanox/mlx4/icm.c
+++ b/drivers/net/ethernet/mellanox/mlx4/icm.c
@@ -56,7 +56,7 @@ static void mlx4_free_icm_pages(struct mlx4_dev *dev, struct mlx4_icm_chunk *chu
int i;
if (chunk->nsg > 0)
- pci_unmap_sg(dev->pdev, chunk->mem, chunk->npages,
+ pci_unmap_sg(dev->persist->pdev, chunk->mem, chunk->npages,
PCI_DMA_BIDIRECTIONAL);
for (i = 0; i < chunk->npages; ++i)
@@ -69,7 +69,8 @@ static void mlx4_free_icm_coherent(struct mlx4_dev *dev, struct mlx4_icm_chunk *
int i;
for (i = 0; i < chunk->npages; ++i)
- dma_free_coherent(&dev->pdev->dev, chunk->mem[i].length,
+ dma_free_coherent(&dev->persist->pdev->dev,
+ chunk->mem[i].length,
lowmem_page_address(sg_page(&chunk->mem[i])),
sg_dma_address(&chunk->mem[i]));
}
@@ -173,7 +174,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
--cur_order;
if (coherent)
- ret = mlx4_alloc_icm_coherent(&dev->pdev->dev,
+ ret = mlx4_alloc_icm_coherent(&dev->persist->pdev->dev,
&chunk->mem[chunk->npages],
cur_order, gfp_mask);
else
@@ -193,7 +194,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
if (coherent)
++chunk->nsg;
else if (chunk->npages == MLX4_ICM_CHUNK_LEN) {
- chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
+ chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
@@ -208,7 +209,7 @@ struct mlx4_icm *mlx4_alloc_icm(struct mlx4_dev *dev, int npages,
}
if (!coherent && chunk) {
- chunk->nsg = pci_map_sg(dev->pdev, chunk->mem,
+ chunk->nsg = pci_map_sg(dev->persist->pdev, chunk->mem,
chunk->npages,
PCI_DMA_BIDIRECTIONAL);
diff --git a/drivers/net/ethernet/mellanox/mlx4/intf.c b/drivers/net/ethernet/mellanox/mlx4/intf.c
index 116895ac8b35..6fce58718837 100644
--- a/drivers/net/ethernet/mellanox/mlx4/intf.c
+++ b/drivers/net/ethernet/mellanox/mlx4/intf.c
@@ -33,11 +33,13 @@
#include <linux/slab.h>
#include <linux/export.h>
+#include <linux/errno.h>
#include "mlx4.h"
struct mlx4_device_context {
struct list_head list;
+ struct list_head bond_list;
struct mlx4_interface *intf;
void *context;
};
@@ -115,6 +117,58 @@ void mlx4_unregister_interface(struct mlx4_interface *intf)
}
EXPORT_SYMBOL_GPL(mlx4_unregister_interface);
+int mlx4_do_bond(struct mlx4_dev *dev, bool enable)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ struct mlx4_device_context *dev_ctx = NULL, *temp_dev_ctx;
+ unsigned long flags;
+ int ret;
+ LIST_HEAD(bond_list);
+
+ if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP))
+ return -ENOTSUPP;
+
+ ret = mlx4_disable_rx_port_check(dev, enable);
+ if (ret) {
+ mlx4_err(dev, "Fail to %s rx port check\n",
+ enable ? "enable" : "disable");
+ return ret;
+ }
+ if (enable) {
+ dev->flags |= MLX4_FLAG_BONDED;
+ } else {
+ ret = mlx4_virt2phy_port_map(dev, 1, 2);
+ if (ret) {
+ mlx4_err(dev, "Fail to reset port map\n");
+ return ret;
+ }
+ dev->flags &= ~MLX4_FLAG_BONDED;
+ }
+
+ spin_lock_irqsave(&priv->ctx_lock, flags);
+ list_for_each_entry_safe(dev_ctx, temp_dev_ctx, &priv->ctx_list, list) {
+ if (dev_ctx->intf->flags & MLX4_INTFF_BONDING) {
+ list_add_tail(&dev_ctx->bond_list, &bond_list);
+ list_del(&dev_ctx->list);
+ }
+ }
+ spin_unlock_irqrestore(&priv->ctx_lock, flags);
+
+ list_for_each_entry(dev_ctx, &bond_list, bond_list) {
+ dev_ctx->intf->remove(dev, dev_ctx->context);
+ dev_ctx->context = dev_ctx->intf->add(dev);
+
+ spin_lock_irqsave(&priv->ctx_lock, flags);
+ list_add_tail(&dev_ctx->list, &priv->ctx_list);
+ spin_unlock_irqrestore(&priv->ctx_lock, flags);
+
+ mlx4_dbg(dev, "Inrerface for protocol %d restarted with when bonded mode is %s\n",
+ dev_ctx->intf->protocol, enable ?
+ "enabled" : "disabled");
+ }
+ return 0;
+}
+
void mlx4_dispatch_event(struct mlx4_dev *dev, enum mlx4_dev_event type,
unsigned long param)
{
@@ -138,13 +192,13 @@ int mlx4_register_device(struct mlx4_dev *dev)
mutex_lock(&intf_mutex);
+ dev->persist->interface_state |= MLX4_INTERFACE_STATE_UP;
list_add_tail(&priv->dev_list, &dev_list);
list_for_each_entry(intf, &intf_list, list)
mlx4_add_device(intf, priv);
mutex_unlock(&intf_mutex);
- if (!mlx4_is_slave(dev))
- mlx4_start_catas_poll(dev);
+ mlx4_start_catas_poll(dev);
return 0;
}
@@ -154,14 +208,14 @@ void mlx4_unregister_device(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
struct mlx4_interface *intf;
- if (!mlx4_is_slave(dev))
- mlx4_stop_catas_poll(dev);
+ mlx4_stop_catas_poll(dev);
mutex_lock(&intf_mutex);
list_for_each_entry(intf, &intf_list, list)
mlx4_remove_device(intf, priv);
list_del(&priv->dev_list);
+ dev->persist->interface_state &= ~MLX4_INTERFACE_STATE_UP;
mutex_unlock(&intf_mutex);
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/main.c b/drivers/net/ethernet/mellanox/mlx4/main.c
index 6e08352ec994..7e487223489a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/main.c
+++ b/drivers/net/ethernet/mellanox/mlx4/main.c
@@ -108,6 +108,8 @@ MODULE_PARM_DESC(enable_64b_cqe_eqe,
MLX4_FUNC_CAP_EQE_CQE_STRIDE | \
MLX4_FUNC_CAP_DMFS_A0_STATIC)
+#define RESET_PERSIST_MASK_FLAGS (MLX4_FLAG_SRIOV)
+
static char mlx4_version[] =
DRV_NAME ": Mellanox ConnectX core driver v"
DRV_VERSION " (" DRV_RELDATE ")\n";
@@ -249,7 +251,8 @@ static void mlx4_enable_cqe_eqe_stride(struct mlx4_dev *dev)
if (mlx4_is_master(dev))
dev_cap->function_caps |= MLX4_FUNC_CAP_EQE_CQE_STRIDE;
} else {
- mlx4_dbg(dev, "Disabling CQE stride cacheLine unsupported\n");
+ if (cache_line_size() != 32 && cache_line_size() != 64)
+ mlx4_dbg(dev, "Disabling CQE stride, cacheLine size unsupported\n");
dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_CQE_STRIDE;
dev_cap->flags2 &= ~MLX4_DEV_CAP_FLAG2_EQE_STRIDE;
}
@@ -318,10 +321,11 @@ static int mlx4_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap)
return -ENODEV;
}
- if (dev_cap->uar_size > pci_resource_len(dev->pdev, 2)) {
+ if (dev_cap->uar_size > pci_resource_len(dev->persist->pdev, 2)) {
mlx4_err(dev, "HCA reported UAR size of 0x%x bigger than PCI resource 2 size of 0x%llx, aborting\n",
dev_cap->uar_size,
- (unsigned long long) pci_resource_len(dev->pdev, 2));
+ (unsigned long long)
+ pci_resource_len(dev->persist->pdev, 2));
return -ENODEV;
}
@@ -541,8 +545,10 @@ static int mlx4_get_pcie_dev_link_caps(struct mlx4_dev *dev,
*speed = PCI_SPEED_UNKNOWN;
*width = PCIE_LNK_WIDTH_UNKNOWN;
- err1 = pcie_capability_read_dword(dev->pdev, PCI_EXP_LNKCAP, &lnkcap1);
- err2 = pcie_capability_read_dword(dev->pdev, PCI_EXP_LNKCAP2, &lnkcap2);
+ err1 = pcie_capability_read_dword(dev->persist->pdev, PCI_EXP_LNKCAP,
+ &lnkcap1);
+ err2 = pcie_capability_read_dword(dev->persist->pdev, PCI_EXP_LNKCAP2,
+ &lnkcap2);
if (!err2 && lnkcap2) { /* PCIe r3.0-compliant */
if (lnkcap2 & PCI_EXP_LNKCAP2_SLS_8_0GB)
*speed = PCIE_SPEED_8_0GT;
@@ -587,7 +593,7 @@ static void mlx4_check_pcie_caps(struct mlx4_dev *dev)
return;
}
- err = pcie_get_minimum_link(dev->pdev, &speed, &width);
+ err = pcie_get_minimum_link(dev->persist->pdev, &speed, &width);
if (err || speed == PCI_SPEED_UNKNOWN ||
width == PCIE_LNK_WIDTH_UNKNOWN) {
mlx4_warn(dev,
@@ -792,6 +798,7 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
dev->caps.num_mpts = 1 << hca_param.log_mpt_sz;
dev->caps.num_eqs = func_cap.max_eq;
dev->caps.reserved_eqs = func_cap.reserved_eq;
+ dev->caps.reserved_lkey = func_cap.reserved_lkey;
dev->caps.num_pds = MLX4_NUM_PDS;
dev->caps.num_mgms = 0;
dev->caps.num_amgms = 0;
@@ -837,10 +844,12 @@ static int mlx4_slave_cap(struct mlx4_dev *dev)
if (dev->caps.uar_page_size * (dev->caps.num_uars -
dev->caps.reserved_uars) >
- pci_resource_len(dev->pdev, 2)) {
+ pci_resource_len(dev->persist->pdev,
+ 2)) {
mlx4_err(dev, "HCA reported UAR region size of 0x%x bigger than PCI resource 2 size of 0x%llx, aborting\n",
dev->caps.uar_page_size * dev->caps.num_uars,
- (unsigned long long) pci_resource_len(dev->pdev, 2));
+ (unsigned long long)
+ pci_resource_len(dev->persist->pdev, 2));
goto err_mem;
}
@@ -1152,6 +1161,91 @@ err_set_port:
return err ? err : count;
}
+int mlx4_bond(struct mlx4_dev *dev)
+{
+ int ret = 0;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ mutex_lock(&priv->bond_mutex);
+
+ if (!mlx4_is_bonded(dev))
+ ret = mlx4_do_bond(dev, true);
+ else
+ ret = 0;
+
+ mutex_unlock(&priv->bond_mutex);
+ if (ret)
+ mlx4_err(dev, "Failed to bond device: %d\n", ret);
+ else
+ mlx4_dbg(dev, "Device is bonded\n");
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mlx4_bond);
+
+int mlx4_unbond(struct mlx4_dev *dev)
+{
+ int ret = 0;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ mutex_lock(&priv->bond_mutex);
+
+ if (mlx4_is_bonded(dev))
+ ret = mlx4_do_bond(dev, false);
+
+ mutex_unlock(&priv->bond_mutex);
+ if (ret)
+ mlx4_err(dev, "Failed to unbond device: %d\n", ret);
+ else
+ mlx4_dbg(dev, "Device is unbonded\n");
+ return ret;
+}
+EXPORT_SYMBOL_GPL(mlx4_unbond);
+
+
+int mlx4_port_map_set(struct mlx4_dev *dev, struct mlx4_port_map *v2p)
+{
+ u8 port1 = v2p->port1;
+ u8 port2 = v2p->port2;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int err;
+
+ if (!(dev->caps.flags2 & MLX4_DEV_CAP_FLAG2_PORT_REMAP))
+ return -ENOTSUPP;
+
+ mutex_lock(&priv->bond_mutex);
+
+ /* zero means keep current mapping for this port */
+ if (port1 == 0)
+ port1 = priv->v2p.port1;
+ if (port2 == 0)
+ port2 = priv->v2p.port2;
+
+ if ((port1 < 1) || (port1 > MLX4_MAX_PORTS) ||
+ (port2 < 1) || (port2 > MLX4_MAX_PORTS) ||
+ (port1 == 2 && port2 == 1)) {
+ /* besides boundary checks cross mapping makes
+ * no sense and therefore not allowed */
+ err = -EINVAL;
+ } else if ((port1 == priv->v2p.port1) &&
+ (port2 == priv->v2p.port2)) {
+ err = 0;
+ } else {
+ err = mlx4_virt2phy_port_map(dev, port1, port2);
+ if (!err) {
+ mlx4_dbg(dev, "port map changed: [%d][%d]\n",
+ port1, port2);
+ priv->v2p.port1 = port1;
+ priv->v2p.port2 = port2;
+ } else {
+ mlx4_err(dev, "Failed to change port mape: %d\n", err);
+ }
+ }
+
+ mutex_unlock(&priv->bond_mutex);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mlx4_port_map_set);
+
static int mlx4_load_fw(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -1477,7 +1571,8 @@ static void mlx4_slave_exit(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
mutex_lock(&priv->cmd.slave_cmd_mutex);
- if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_TIME))
+ if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_CMD_NA_OP,
+ MLX4_COMM_TIME))
mlx4_warn(dev, "Failed to close slave function\n");
mutex_unlock(&priv->cmd.slave_cmd_mutex);
}
@@ -1492,9 +1587,9 @@ static int map_bf_area(struct mlx4_dev *dev)
if (!dev->caps.bf_reg_size)
return -ENXIO;
- bf_start = pci_resource_start(dev->pdev, 2) +
+ bf_start = pci_resource_start(dev->persist->pdev, 2) +
(dev->caps.num_uars << PAGE_SHIFT);
- bf_len = pci_resource_len(dev->pdev, 2) -
+ bf_len = pci_resource_len(dev->persist->pdev, 2) -
(dev->caps.num_uars << PAGE_SHIFT);
priv->bf_mapping = io_mapping_create_wc(bf_start, bf_len);
if (!priv->bf_mapping)
@@ -1536,7 +1631,8 @@ static int map_internal_clock(struct mlx4_dev *dev)
struct mlx4_priv *priv = mlx4_priv(dev);
priv->clock_mapping =
- ioremap(pci_resource_start(dev->pdev, priv->fw.clock_bar) +
+ ioremap(pci_resource_start(dev->persist->pdev,
+ priv->fw.clock_bar) +
priv->fw.clock_offset, MLX4_CLOCK_SIZE);
if (!priv->clock_mapping)
@@ -1573,6 +1669,50 @@ static void mlx4_close_fw(struct mlx4_dev *dev)
}
}
+static int mlx4_comm_check_offline(struct mlx4_dev *dev)
+{
+#define COMM_CHAN_OFFLINE_OFFSET 0x09
+
+ u32 comm_flags;
+ u32 offline_bit;
+ unsigned long end;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+
+ end = msecs_to_jiffies(MLX4_COMM_OFFLINE_TIME_OUT) + jiffies;
+ while (time_before(jiffies, end)) {
+ comm_flags = swab32(readl((__iomem char *)priv->mfunc.comm +
+ MLX4_COMM_CHAN_FLAGS));
+ offline_bit = (comm_flags &
+ (u32)(1 << COMM_CHAN_OFFLINE_OFFSET));
+ if (!offline_bit)
+ return 0;
+ /* There are cases as part of AER/Reset flow that PF needs
+ * around 100 msec to load. We therefore sleep for 100 msec
+ * to allow other tasks to make use of that CPU during this
+ * time interval.
+ */
+ msleep(100);
+ }
+ mlx4_err(dev, "Communication channel is offline.\n");
+ return -EIO;
+}
+
+static void mlx4_reset_vf_support(struct mlx4_dev *dev)
+{
+#define COMM_CHAN_RST_OFFSET 0x1e
+
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ u32 comm_rst;
+ u32 comm_caps;
+
+ comm_caps = swab32(readl((__iomem char *)priv->mfunc.comm +
+ MLX4_COMM_CHAN_CAPS));
+ comm_rst = (comm_caps & (u32)(1 << COMM_CHAN_RST_OFFSET));
+
+ if (comm_rst)
+ dev->caps.vf_caps |= MLX4_VF_CAP_FLAG_RESET;
+}
+
static int mlx4_init_slave(struct mlx4_dev *dev)
{
struct mlx4_priv *priv = mlx4_priv(dev);
@@ -1588,9 +1728,15 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
mutex_lock(&priv->cmd.slave_cmd_mutex);
priv->cmd.max_cmds = 1;
+ if (mlx4_comm_check_offline(dev)) {
+ mlx4_err(dev, "PF is not responsive, skipping initialization\n");
+ goto err_offline;
+ }
+
+ mlx4_reset_vf_support(dev);
mlx4_warn(dev, "Sending reset\n");
ret_from_reset = mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0,
- MLX4_COMM_TIME);
+ MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME);
/* if we are in the middle of flr the slave will try
* NUM_OF_RESET_RETRIES times before leaving.*/
if (ret_from_reset) {
@@ -1615,22 +1761,24 @@ static int mlx4_init_slave(struct mlx4_dev *dev)
mlx4_warn(dev, "Sending vhcr0\n");
if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR0, dma >> 48,
- MLX4_COMM_TIME))
+ MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME))
goto err;
if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR1, dma >> 32,
- MLX4_COMM_TIME))
+ MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME))
goto err;
if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR2, dma >> 16,
- MLX4_COMM_TIME))
+ MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME))
goto err;
- if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma, MLX4_COMM_TIME))
+ if (mlx4_comm_cmd(dev, MLX4_COMM_CMD_VHCR_EN, dma,
+ MLX4_COMM_CMD_NA_OP, MLX4_COMM_TIME))
goto err;
mutex_unlock(&priv->cmd.slave_cmd_mutex);
return 0;
err:
- mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, 0);
+ mlx4_comm_cmd(dev, MLX4_COMM_CMD_RESET, 0, MLX4_COMM_CMD_NA_OP, 0);
+err_offline:
mutex_unlock(&priv->cmd.slave_cmd_mutex);
return -EIO;
}
@@ -1705,7 +1853,8 @@ static void choose_steering_mode(struct mlx4_dev *dev,
if (mlx4_log_num_mgm_entry_size <= 0 &&
dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_FS_EN &&
(!mlx4_is_mfunc(dev) ||
- (dev_cap->fs_max_num_qp_per_entry >= (dev->num_vfs + 1))) &&
+ (dev_cap->fs_max_num_qp_per_entry >=
+ (dev->persist->num_vfs + 1))) &&
choose_log_fs_mgm_entry_size(dev_cap->fs_max_num_qp_per_entry) >=
MLX4_MIN_MGM_LOG_ENTRY_SIZE) {
dev->oper_log_mgm_entry_size =
@@ -2287,7 +2436,8 @@ static void mlx4_enable_msi_x(struct mlx4_dev *dev)
for (i = 0; i < nreq; ++i)
entries[i].entry = i;
- nreq = pci_enable_msix_range(dev->pdev, entries, 2, nreq);
+ nreq = pci_enable_msix_range(dev->persist->pdev, entries, 2,
+ nreq);
if (nreq < 0) {
kfree(entries);
@@ -2315,7 +2465,7 @@ no_msi:
dev->caps.comp_pool = 0;
for (i = 0; i < 2; ++i)
- priv->eq_table.eq[i].irq = dev->pdev->irq;
+ priv->eq_table.eq[i].irq = dev->persist->pdev->irq;
}
static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
@@ -2343,7 +2493,7 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
info->port_attr.show = show_port_type;
sysfs_attr_init(&info->port_attr.attr);
- err = device_create_file(&dev->pdev->dev, &info->port_attr);
+ err = device_create_file(&dev->persist->pdev->dev, &info->port_attr);
if (err) {
mlx4_err(dev, "Failed to create file for port %d\n", port);
info->port = -1;
@@ -2360,10 +2510,12 @@ static int mlx4_init_port_info(struct mlx4_dev *dev, int port)
info->port_mtu_attr.show = show_port_ib_mtu;
sysfs_attr_init(&info->port_mtu_attr.attr);
- err = device_create_file(&dev->pdev->dev, &info->port_mtu_attr);
+ err = device_create_file(&dev->persist->pdev->dev,
+ &info->port_mtu_attr);
if (err) {
mlx4_err(dev, "Failed to create mtu file for port %d\n", port);
- device_remove_file(&info->dev->pdev->dev, &info->port_attr);
+ device_remove_file(&info->dev->persist->pdev->dev,
+ &info->port_attr);
info->port = -1;
}
@@ -2375,8 +2527,9 @@ static void mlx4_cleanup_port_info(struct mlx4_port_info *info)
if (info->port < 0)
return;
- device_remove_file(&info->dev->pdev->dev, &info->port_attr);
- device_remove_file(&info->dev->pdev->dev, &info->port_mtu_attr);
+ device_remove_file(&info->dev->persist->pdev->dev, &info->port_attr);
+ device_remove_file(&info->dev->persist->pdev->dev,
+ &info->port_mtu_attr);
}
static int mlx4_init_steering(struct mlx4_dev *dev)
@@ -2443,10 +2596,11 @@ static int mlx4_get_ownership(struct mlx4_dev *dev)
void __iomem *owner;
u32 ret;
- if (pci_channel_offline(dev->pdev))
+ if (pci_channel_offline(dev->persist->pdev))
return -EIO;
- owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE,
+ owner = ioremap(pci_resource_start(dev->persist->pdev, 0) +
+ MLX4_OWNER_BASE,
MLX4_OWNER_SIZE);
if (!owner) {
mlx4_err(dev, "Failed to obtain ownership bit\n");
@@ -2462,10 +2616,11 @@ static void mlx4_free_ownership(struct mlx4_dev *dev)
{
void __iomem *owner;
- if (pci_channel_offline(dev->pdev))
+ if (pci_channel_offline(dev->persist->pdev))
return;
- owner = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_OWNER_BASE,
+ owner = ioremap(pci_resource_start(dev->persist->pdev, 0) +
+ MLX4_OWNER_BASE,
MLX4_OWNER_SIZE);
if (!owner) {
mlx4_err(dev, "Failed to obtain ownership bit\n");
@@ -2480,11 +2635,19 @@ static void mlx4_free_ownership(struct mlx4_dev *dev)
!!((flags) & MLX4_FLAG_MASTER))
static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev,
- u8 total_vfs, int existing_vfs)
+ u8 total_vfs, int existing_vfs, int reset_flow)
{
u64 dev_flags = dev->flags;
int err = 0;
+ if (reset_flow) {
+ dev->dev_vfs = kcalloc(total_vfs, sizeof(*dev->dev_vfs),
+ GFP_KERNEL);
+ if (!dev->dev_vfs)
+ goto free_mem;
+ return dev_flags;
+ }
+
atomic_inc(&pf_loading);
if (dev->flags & MLX4_FLAG_SRIOV) {
if (existing_vfs != total_vfs) {
@@ -2513,13 +2676,14 @@ static u64 mlx4_enable_sriov(struct mlx4_dev *dev, struct pci_dev *pdev,
dev_flags |= MLX4_FLAG_SRIOV |
MLX4_FLAG_MASTER;
dev_flags &= ~MLX4_FLAG_SLAVE;
- dev->num_vfs = total_vfs;
+ dev->persist->num_vfs = total_vfs;
}
return dev_flags;
disable_sriov:
atomic_dec(&pf_loading);
- dev->num_vfs = 0;
+free_mem:
+ dev->persist->num_vfs = 0;
kfree(dev->dev_vfs);
return dev_flags & ~MLX4_FLAG_MASTER;
}
@@ -2543,7 +2707,8 @@ static int mlx4_check_dev_cap(struct mlx4_dev *dev, struct mlx4_dev_cap *dev_cap
}
static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
- int total_vfs, int *nvfs, struct mlx4_priv *priv)
+ int total_vfs, int *nvfs, struct mlx4_priv *priv,
+ int reset_flow)
{
struct mlx4_dev *dev;
unsigned sum = 0;
@@ -2559,6 +2724,7 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
spin_lock_init(&priv->ctx_lock);
mutex_init(&priv->port_mutex);
+ mutex_init(&priv->bond_mutex);
INIT_LIST_HEAD(&priv->pgdir_list);
mutex_init(&priv->pgdir_mutex);
@@ -2606,10 +2772,15 @@ static int mlx4_load_one(struct pci_dev *pdev, int pci_dev_data,
existing_vfs = pci_num_vf(pdev);
if (existing_vfs)
dev->flags |= MLX4_FLAG_SRIOV;
- dev->num_vfs = total_vfs;
+ dev->persist->num_vfs = total_vfs;
}
}
+ /* on load remove any previous indication of internal error,
+ * device is up.
+ */
+ dev->persist->state = MLX4_DEVICE_STATE_UP;
+
slave_start:
err = mlx4_cmd_init(dev);
if (err) {
@@ -2660,8 +2831,10 @@ slave_start:
goto err_fw;
if (!(dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) {
- u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs,
- existing_vfs);
+ u64 dev_flags = mlx4_enable_sriov(dev, pdev,
+ total_vfs,
+ existing_vfs,
+ reset_flow);
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
dev->flags = dev_flags;
@@ -2703,7 +2876,7 @@ slave_start:
if (dev->flags & MLX4_FLAG_SRIOV) {
if (!existing_vfs)
pci_disable_sriov(pdev);
- if (mlx4_is_master(dev))
+ if (mlx4_is_master(dev) && !reset_flow)
atomic_dec(&pf_loading);
dev->flags &= ~MLX4_FLAG_SRIOV;
}
@@ -2717,7 +2890,8 @@ slave_start:
}
if (mlx4_is_master(dev) && (dev_cap->flags2 & MLX4_DEV_CAP_FLAG2_SYS_EQS)) {
- u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs, existing_vfs);
+ u64 dev_flags = mlx4_enable_sriov(dev, pdev, total_vfs,
+ existing_vfs, reset_flow);
if ((dev->flags ^ dev_flags) & (MLX4_FLAG_MASTER | MLX4_FLAG_SLAVE)) {
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_VHCR);
@@ -2770,12 +2944,14 @@ slave_start:
dev->caps.num_ports);
goto err_close;
}
- memcpy(dev->nvfs, nvfs, sizeof(dev->nvfs));
+ memcpy(dev->persist->nvfs, nvfs, sizeof(dev->persist->nvfs));
- for (i = 0; i < sizeof(dev->nvfs)/sizeof(dev->nvfs[0]); i++) {
+ for (i = 0;
+ i < sizeof(dev->persist->nvfs)/
+ sizeof(dev->persist->nvfs[0]); i++) {
unsigned j;
- for (j = 0; j < dev->nvfs[i]; ++sum, ++j) {
+ for (j = 0; j < dev->persist->nvfs[i]; ++sum, ++j) {
dev->dev_vfs[sum].min_port = i < 2 ? i + 1 : 1;
dev->dev_vfs[sum].n_ports = i < 2 ? 1 :
dev->caps.num_ports;
@@ -2827,6 +3003,17 @@ slave_start:
goto err_steer;
mlx4_init_quotas(dev);
+ /* When PF resources are ready arm its comm channel to enable
+ * getting commands
+ */
+ if (mlx4_is_master(dev)) {
+ err = mlx4_ARM_COMM_CHANNEL(dev);
+ if (err) {
+ mlx4_err(dev, " Failed to arm comm channel eq: %x\n",
+ err);
+ goto err_steer;
+ }
+ }
for (port = 1; port <= dev->caps.num_ports; port++) {
err = mlx4_init_port_info(dev, port);
@@ -2834,6 +3021,9 @@ slave_start:
goto err_port;
}
+ priv->v2p.port1 = 1;
+ priv->v2p.port2 = 2;
+
err = mlx4_register_device(dev);
if (err)
goto err_port;
@@ -2845,7 +3035,7 @@ slave_start:
priv->removed = 0;
- if (mlx4_is_master(dev) && dev->num_vfs)
+ if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow)
atomic_dec(&pf_loading);
kfree(dev_cap);
@@ -2879,8 +3069,10 @@ err_free_eq:
mlx4_free_eq_table(dev);
err_master_mfunc:
- if (mlx4_is_master(dev))
+ if (mlx4_is_master(dev)) {
+ mlx4_free_resource_tracker(dev, RES_TR_FREE_STRUCTS_ONLY);
mlx4_multi_func_cleanup(dev);
+ }
if (mlx4_is_slave(dev)) {
kfree(dev->caps.qp0_qkey);
@@ -2904,10 +3096,12 @@ err_cmd:
mlx4_cmd_cleanup(dev, MLX4_CMD_CLEANUP_ALL);
err_sriov:
- if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs)
+ if (dev->flags & MLX4_FLAG_SRIOV && !existing_vfs) {
pci_disable_sriov(pdev);
+ dev->flags &= ~MLX4_FLAG_SRIOV;
+ }
- if (mlx4_is_master(dev) && dev->num_vfs)
+ if (mlx4_is_master(dev) && dev->persist->num_vfs && !reset_flow)
atomic_dec(&pf_loading);
kfree(priv->dev.dev_vfs);
@@ -3048,11 +3242,19 @@ static int __mlx4_init_one(struct pci_dev *pdev, int pci_dev_data,
}
}
- err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv);
+ err = mlx4_catas_init(&priv->dev);
if (err)
goto err_release_regions;
+
+ err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 0);
+ if (err)
+ goto err_catas;
+
return 0;
+err_catas:
+ mlx4_catas_end(&priv->dev);
+
err_release_regions:
pci_release_regions(pdev);
@@ -3075,38 +3277,60 @@ static int mlx4_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
return -ENOMEM;
dev = &priv->dev;
- dev->pdev = pdev;
- pci_set_drvdata(pdev, dev);
+ dev->persist = kzalloc(sizeof(*dev->persist), GFP_KERNEL);
+ if (!dev->persist) {
+ kfree(priv);
+ return -ENOMEM;
+ }
+ dev->persist->pdev = pdev;
+ dev->persist->dev = dev;
+ pci_set_drvdata(pdev, dev->persist);
priv->pci_dev_data = id->driver_data;
+ mutex_init(&dev->persist->device_state_mutex);
+ mutex_init(&dev->persist->interface_state_mutex);
ret = __mlx4_init_one(pdev, id->driver_data, priv);
- if (ret)
+ if (ret) {
+ kfree(dev->persist);
kfree(priv);
+ } else {
+ pci_save_state(pdev);
+ }
return ret;
}
+static void mlx4_clean_dev(struct mlx4_dev *dev)
+{
+ struct mlx4_dev_persistent *persist = dev->persist;
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ unsigned long flags = (dev->flags & RESET_PERSIST_MASK_FLAGS);
+
+ memset(priv, 0, sizeof(*priv));
+ priv->dev.persist = persist;
+ priv->dev.flags = flags;
+}
+
static void mlx4_unload_one(struct pci_dev *pdev)
{
- struct mlx4_dev *dev = pci_get_drvdata(pdev);
+ struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+ struct mlx4_dev *dev = persist->dev;
struct mlx4_priv *priv = mlx4_priv(dev);
int pci_dev_data;
- int p;
- int active_vfs = 0;
+ int p, i;
if (priv->removed)
return;
+ /* saving current ports type for further use */
+ for (i = 0; i < dev->caps.num_ports; i++) {
+ dev->persist->curr_port_type[i] = dev->caps.port_type[i + 1];
+ dev->persist->curr_port_poss_type[i] = dev->caps.
+ possible_type[i + 1];
+ }
+
pci_dev_data = priv->pci_dev_data;
- /* Disabling SR-IOV is not allowed while there are active vf's */
- if (mlx4_is_master(dev)) {
- active_vfs = mlx4_how_many_lives_vf(dev);
- if (active_vfs) {
- pr_warn("Removing PF when there are active VF's !!\n");
- pr_warn("Will not disable SR-IOV.\n");
- }
- }
mlx4_stop_sense(dev);
mlx4_unregister_device(dev);
@@ -3150,12 +3374,6 @@ static void mlx4_unload_one(struct pci_dev *pdev)
if (dev->flags & MLX4_FLAG_MSI_X)
pci_disable_msix(pdev);
- if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) {
- mlx4_warn(dev, "Disabling SR-IOV\n");
- pci_disable_sriov(pdev);
- dev->flags &= ~MLX4_FLAG_SRIOV;
- dev->num_vfs = 0;
- }
if (!mlx4_is_slave(dev))
mlx4_free_ownership(dev);
@@ -3167,42 +3385,96 @@ static void mlx4_unload_one(struct pci_dev *pdev)
kfree(dev->caps.qp1_proxy);
kfree(dev->dev_vfs);
- memset(priv, 0, sizeof(*priv));
+ mlx4_clean_dev(dev);
priv->pci_dev_data = pci_dev_data;
priv->removed = 1;
}
static void mlx4_remove_one(struct pci_dev *pdev)
{
- struct mlx4_dev *dev = pci_get_drvdata(pdev);
+ struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+ struct mlx4_dev *dev = persist->dev;
struct mlx4_priv *priv = mlx4_priv(dev);
+ int active_vfs = 0;
+
+ mutex_lock(&persist->interface_state_mutex);
+ persist->interface_state |= MLX4_INTERFACE_STATE_DELETION;
+ mutex_unlock(&persist->interface_state_mutex);
+
+ /* Disabling SR-IOV is not allowed while there are active vf's */
+ if (mlx4_is_master(dev) && dev->flags & MLX4_FLAG_SRIOV) {
+ active_vfs = mlx4_how_many_lives_vf(dev);
+ if (active_vfs) {
+ pr_warn("Removing PF when there are active VF's !!\n");
+ pr_warn("Will not disable SR-IOV.\n");
+ }
+ }
+
+ /* device marked to be under deletion running now without the lock
+ * letting other tasks to be terminated
+ */
+ if (persist->interface_state & MLX4_INTERFACE_STATE_UP)
+ mlx4_unload_one(pdev);
+ else
+ mlx4_info(dev, "%s: interface is down\n", __func__);
+ mlx4_catas_end(dev);
+ if (dev->flags & MLX4_FLAG_SRIOV && !active_vfs) {
+ mlx4_warn(dev, "Disabling SR-IOV\n");
+ pci_disable_sriov(pdev);
+ }
- mlx4_unload_one(pdev);
pci_release_regions(pdev);
pci_disable_device(pdev);
+ kfree(dev->persist);
kfree(priv);
pci_set_drvdata(pdev, NULL);
}
+static int restore_current_port_types(struct mlx4_dev *dev,
+ enum mlx4_port_type *types,
+ enum mlx4_port_type *poss_types)
+{
+ struct mlx4_priv *priv = mlx4_priv(dev);
+ int err, i;
+
+ mlx4_stop_sense(dev);
+
+ mutex_lock(&priv->port_mutex);
+ for (i = 0; i < dev->caps.num_ports; i++)
+ dev->caps.possible_type[i + 1] = poss_types[i];
+ err = mlx4_change_port_types(dev, types);
+ mlx4_start_sense(dev);
+ mutex_unlock(&priv->port_mutex);
+
+ return err;
+}
+
int mlx4_restart_one(struct pci_dev *pdev)
{
- struct mlx4_dev *dev = pci_get_drvdata(pdev);
+ struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+ struct mlx4_dev *dev = persist->dev;
struct mlx4_priv *priv = mlx4_priv(dev);
int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0};
int pci_dev_data, err, total_vfs;
pci_dev_data = priv->pci_dev_data;
- total_vfs = dev->num_vfs;
- memcpy(nvfs, dev->nvfs, sizeof(dev->nvfs));
+ total_vfs = dev->persist->num_vfs;
+ memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs));
mlx4_unload_one(pdev);
- err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv);
+ err = mlx4_load_one(pdev, pci_dev_data, total_vfs, nvfs, priv, 1);
if (err) {
mlx4_err(dev, "%s: ERROR: mlx4_load_one failed, pci_name=%s, err=%d\n",
__func__, pci_name(pdev), err);
return err;
}
+ err = restore_current_port_types(dev, dev->persist->curr_port_type,
+ dev->persist->curr_port_poss_type);
+ if (err)
+ mlx4_err(dev, "could not restore original port types (%d)\n",
+ err);
+
return err;
}
@@ -3257,23 +3529,79 @@ MODULE_DEVICE_TABLE(pci, mlx4_pci_table);
static pci_ers_result_t mlx4_pci_err_detected(struct pci_dev *pdev,
pci_channel_state_t state)
{
- mlx4_unload_one(pdev);
+ struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+
+ mlx4_err(persist->dev, "mlx4_pci_err_detected was called\n");
+ mlx4_enter_error_state(persist);
- return state == pci_channel_io_perm_failure ?
- PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_NEED_RESET;
+ mutex_lock(&persist->interface_state_mutex);
+ if (persist->interface_state & MLX4_INTERFACE_STATE_UP)
+ mlx4_unload_one(pdev);
+
+ mutex_unlock(&persist->interface_state_mutex);
+ if (state == pci_channel_io_perm_failure)
+ return PCI_ERS_RESULT_DISCONNECT;
+
+ pci_disable_device(pdev);
+ return PCI_ERS_RESULT_NEED_RESET;
}
static pci_ers_result_t mlx4_pci_slot_reset(struct pci_dev *pdev)
{
- struct mlx4_dev *dev = pci_get_drvdata(pdev);
+ struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+ struct mlx4_dev *dev = persist->dev;
struct mlx4_priv *priv = mlx4_priv(dev);
int ret;
+ int nvfs[MLX4_MAX_PORTS + 1] = {0, 0, 0};
+ int total_vfs;
- ret = __mlx4_init_one(pdev, priv->pci_dev_data, priv);
+ mlx4_err(dev, "mlx4_pci_slot_reset was called\n");
+ ret = pci_enable_device(pdev);
+ if (ret) {
+ mlx4_err(dev, "Can not re-enable device, ret=%d\n", ret);
+ return PCI_ERS_RESULT_DISCONNECT;
+ }
+
+ pci_set_master(pdev);
+ pci_restore_state(pdev);
+ pci_save_state(pdev);
+
+ total_vfs = dev->persist->num_vfs;
+ memcpy(nvfs, dev->persist->nvfs, sizeof(dev->persist->nvfs));
+
+ mutex_lock(&persist->interface_state_mutex);
+ if (!(persist->interface_state & MLX4_INTERFACE_STATE_UP)) {
+ ret = mlx4_load_one(pdev, priv->pci_dev_data, total_vfs, nvfs,
+ priv, 1);
+ if (ret) {
+ mlx4_err(dev, "%s: mlx4_load_one failed, ret=%d\n",
+ __func__, ret);
+ goto end;
+ }
+
+ ret = restore_current_port_types(dev, dev->persist->
+ curr_port_type, dev->persist->
+ curr_port_poss_type);
+ if (ret)
+ mlx4_err(dev, "could not restore original port types (%d)\n", ret);
+ }
+end:
+ mutex_unlock(&persist->interface_state_mutex);
return ret ? PCI_ERS_RESULT_DISCONNECT : PCI_ERS_RESULT_RECOVERED;
}
+static void mlx4_shutdown(struct pci_dev *pdev)
+{
+ struct mlx4_dev_persistent *persist = pci_get_drvdata(pdev);
+
+ mlx4_info(persist->dev, "mlx4_shutdown was called\n");
+ mutex_lock(&persist->interface_state_mutex);
+ if (persist->interface_state & MLX4_INTERFACE_STATE_UP)
+ mlx4_unload_one(pdev);
+ mutex_unlock(&persist->interface_state_mutex);
+}
+
static const struct pci_error_handlers mlx4_err_handler = {
.error_detected = mlx4_pci_err_detected,
.slot_reset = mlx4_pci_slot_reset,
@@ -3283,7 +3611,7 @@ static struct pci_driver mlx4_driver = {
.name = DRV_NAME,
.id_table = mlx4_pci_table,
.probe = mlx4_init_one,
- .shutdown = mlx4_unload_one,
+ .shutdown = mlx4_shutdown,
.remove = mlx4_remove_one,
.err_handler = &mlx4_err_handler,
};
@@ -3335,7 +3663,6 @@ static int __init mlx4_init(void)
if (mlx4_verify_params())
return -EINVAL;
- mlx4_catas_init();
mlx4_wq = create_singlethread_workqueue("mlx4");
if (!mlx4_wq)
diff --git a/drivers/net/ethernet/mellanox/mlx4/mcg.c b/drivers/net/ethernet/mellanox/mlx4/mcg.c
index a3867e7ef885..bd9ea0d01aae 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mcg.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mcg.c
@@ -1318,6 +1318,9 @@ out:
mutex_unlock(&priv->mcg_table.mutex);
mlx4_free_cmd_mailbox(dev, mailbox);
+ if (err && dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ /* In case device is under an error, return success as a closing command */
+ err = 0;
return err;
}
@@ -1347,6 +1350,9 @@ static int mlx4_QP_ATTACH(struct mlx4_dev *dev, struct mlx4_qp *qp,
MLX4_CMD_WRAPPED);
mlx4_free_cmd_mailbox(dev, mailbox);
+ if (err && !attach &&
+ dev->persist->state & MLX4_DEVICE_STATE_INTERNAL_ERROR)
+ err = 0;
return err;
}
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4.h b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
index bdd4eea2247c..1409d0cd6143 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4.h
@@ -85,7 +85,9 @@ enum {
MLX4_CLR_INT_SIZE = 0x00008,
MLX4_SLAVE_COMM_BASE = 0x0,
MLX4_COMM_PAGESIZE = 0x1000,
- MLX4_CLOCK_SIZE = 0x00008
+ MLX4_CLOCK_SIZE = 0x00008,
+ MLX4_COMM_CHAN_CAPS = 0x8,
+ MLX4_COMM_CHAN_FLAGS = 0xc
};
enum {
@@ -120,6 +122,10 @@ enum mlx4_mpt_state {
};
#define MLX4_COMM_TIME 10000
+#define MLX4_COMM_OFFLINE_TIME_OUT 30000
+#define MLX4_COMM_CMD_NA_OP 0x0
+
+
enum {
MLX4_COMM_CMD_RESET,
MLX4_COMM_CMD_VHCR0,
@@ -190,6 +196,7 @@ struct mlx4_vhcr {
struct mlx4_vhcr_cmd {
__be64 in_param;
__be32 in_modifier;
+ u32 reserved1;
__be64 out_param;
__be16 token;
u16 reserved;
@@ -221,21 +228,24 @@ extern int mlx4_debug_level;
#define mlx4_dbg(mdev, format, ...) \
do { \
if (mlx4_debug_level) \
- dev_printk(KERN_DEBUG, &(mdev)->pdev->dev, format, \
+ dev_printk(KERN_DEBUG, \
+ &(mdev)->persist->pdev->dev, format, \
##__VA_ARGS__); \
} while (0)
#define mlx4_err(mdev, format, ...) \
- dev_err(&(mdev)->pdev->dev, format, ##__VA_ARGS__)
+ dev_err(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__)
#define mlx4_info(mdev, format, ...) \
- dev_info(&(mdev)->pdev->dev, format, ##__VA_ARGS__)
+ dev_info(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__)
#define mlx4_warn(mdev, format, ...) \
- dev_warn(&(mdev)->pdev->dev, format, ##__VA_ARGS__)
+ dev_warn(&(mdev)->persist->pdev->dev, format, ##__VA_ARGS__)
extern int mlx4_log_num_mgm_entry_size;
extern int log_mtts_per_seg;
+extern int mlx4_internal_err_reset;
-#define MLX4_MAX_NUM_SLAVES (MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF)
+#define MLX4_MAX_NUM_SLAVES (min(MLX4_MAX_NUM_PF + MLX4_MAX_NUM_VF, \
+ MLX4_MFUNC_MAX))
#define ALL_SLAVES 0xff
struct mlx4_bitmap {
@@ -606,7 +616,6 @@ struct mlx4_mgm {
struct mlx4_cmd {
struct pci_pool *pool;
void __iomem *hcr;
- struct mutex hcr_mutex;
struct mutex slave_cmd_mutex;
struct semaphore poll_sem;
struct semaphore event_sem;
@@ -877,6 +886,8 @@ struct mlx4_priv {
int reserved_mtts;
int fs_hash_mode;
u8 virt2phys_pkey[MLX4_MFUNC_MAX][MLX4_MAX_PORTS][MLX4_MAX_PORT_PKEYS];
+ struct mlx4_port_map v2p; /* cached port mapping configuration */
+ struct mutex bond_mutex; /* for bond mode */
__be64 slave_node_guids[MLX4_MFUNC_MAX];
atomic_t opreq_count;
@@ -994,7 +1005,8 @@ void __mlx4_xrcd_free(struct mlx4_dev *dev, u32 xrcdn);
void mlx4_start_catas_poll(struct mlx4_dev *dev);
void mlx4_stop_catas_poll(struct mlx4_dev *dev);
-void mlx4_catas_init(void);
+int mlx4_catas_init(struct mlx4_dev *dev);
+void mlx4_catas_end(struct mlx4_dev *dev);
int mlx4_restart_one(struct pci_dev *pdev);
int mlx4_register_device(struct mlx4_dev *dev);
void mlx4_unregister_device(struct mlx4_dev *dev);
@@ -1160,13 +1172,14 @@ enum {
int mlx4_cmd_init(struct mlx4_dev *dev);
void mlx4_cmd_cleanup(struct mlx4_dev *dev, int cleanup_mask);
int mlx4_multi_func_init(struct mlx4_dev *dev);
+int mlx4_ARM_COMM_CHANNEL(struct mlx4_dev *dev);
void mlx4_multi_func_cleanup(struct mlx4_dev *dev);
void mlx4_cmd_event(struct mlx4_dev *dev, u16 token, u8 status, u64 out_param);
int mlx4_cmd_use_events(struct mlx4_dev *dev);
void mlx4_cmd_use_polling(struct mlx4_dev *dev);
int mlx4_comm_cmd(struct mlx4_dev *dev, u8 cmd, u16 param,
- unsigned long timeout);
+ u16 op, unsigned long timeout);
void mlx4_cq_tasklet_cb(unsigned long data);
void mlx4_cq_completion(struct mlx4_dev *dev, u32 cqn);
@@ -1176,7 +1189,7 @@ void mlx4_qp_event(struct mlx4_dev *dev, u32 qpn, int event_type);
void mlx4_srq_event(struct mlx4_dev *dev, u32 srqn, int event_type);
-void mlx4_handle_catas_err(struct mlx4_dev *dev);
+void mlx4_enter_error_state(struct mlx4_dev_persistent *persist);
int mlx4_SENSE_PORT(struct mlx4_dev *dev, int port,
enum mlx4_port_type *type);
@@ -1354,6 +1367,7 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port);
/* Returns the VF index of slave */
int mlx4_get_vf_indx(struct mlx4_dev *dev, int slave);
int mlx4_config_mad_demux(struct mlx4_dev *dev);
+int mlx4_do_bond(struct mlx4_dev *dev, bool enable);
enum mlx4_zone_flags {
MLX4_ZONE_ALLOW_ALLOC_FROM_LOWER_PRIO = 1UL << 0,
diff --git a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
index 944a112dff37..2a8268e6be15 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
+++ b/drivers/net/ethernet/mellanox/mlx4/mlx4_en.h
@@ -390,6 +390,7 @@ struct mlx4_en_dev {
struct pci_dev *pdev;
struct mutex state_lock;
struct net_device *pndev[MLX4_MAX_PORTS + 1];
+ struct net_device *upper[MLX4_MAX_PORTS + 1];
u32 port_cnt;
bool device_up;
struct mlx4_en_profile profile;
@@ -410,6 +411,7 @@ struct mlx4_en_dev {
unsigned long overflow_period;
struct ptp_clock *ptp_clock;
struct ptp_clock_info ptp_clock_info;
+ struct notifier_block nb;
};
@@ -845,6 +847,9 @@ int mlx4_en_reset_config(struct net_device *dev,
struct hwtstamp_config ts_config,
netdev_features_t new_features);
+int mlx4_en_netdev_event(struct notifier_block *this,
+ unsigned long event, void *ptr);
+
/*
* Functions for time stamping
*/
diff --git a/drivers/net/ethernet/mellanox/mlx4/mr.c b/drivers/net/ethernet/mellanox/mlx4/mr.c
index 7094a9c70fd5..78f51e103880 100644
--- a/drivers/net/ethernet/mellanox/mlx4/mr.c
+++ b/drivers/net/ethernet/mellanox/mlx4/mr.c
@@ -598,14 +598,11 @@ int mlx4_mr_rereg_mem_write(struct mlx4_dev *dev, struct mlx4_mr *mr,
if (err)
return err;
- mpt_entry->start = cpu_to_be64(mr->iova);
- mpt_entry->length = cpu_to_be64(mr->size);
- mpt_entry->entity_size = cpu_to_be32(mr->mtt.page_shift);
-
- mpt_entry->pd_flags &= cpu_to_be32(MLX4_MPT_PD_MASK |
- MLX4_MPT_PD_FLAG_EN_INV);
- mpt_entry->flags &= cpu_to_be32(MLX4_MPT_FLAG_FREE |
- MLX4_MPT_FLAG_SW_OWNS);
+ mpt_entry->start = cpu_to_be64(iova);
+ mpt_entry->length = cpu_to_be64(size);
+ mpt_entry->entity_size = cpu_to_be32(page_shift);
+ mpt_entry->flags &= ~(cpu_to_be32(MLX4_MPT_FLAG_FREE |
+ MLX4_MPT_FLAG_SW_OWNS));
if (mr->mtt.order < 0) {
mpt_entry->flags |= cpu_to_be32(MLX4_MPT_FLAG_PHYSICAL);
mpt_entry->mtt_addr = 0;
@@ -708,13 +705,13 @@ static int mlx4_write_mtt_chunk(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
if (!mtts)
return -ENOMEM;
- dma_sync_single_for_cpu(&dev->pdev->dev, dma_handle,
+ dma_sync_single_for_cpu(&dev->persist->pdev->dev, dma_handle,
npages * sizeof (u64), DMA_TO_DEVICE);
for (i = 0; i < npages; ++i)
mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
- dma_sync_single_for_device(&dev->pdev->dev, dma_handle,
+ dma_sync_single_for_device(&dev->persist->pdev->dev, dma_handle,
npages * sizeof (u64), DMA_TO_DEVICE);
return 0;
@@ -1020,13 +1017,13 @@ int mlx4_map_phys_fmr(struct mlx4_dev *dev, struct mlx4_fmr *fmr, u64 *page_list
/* Make sure MPT status is visible before writing MTT entries */
wmb();
- dma_sync_single_for_cpu(&dev->pdev->dev, fmr->dma_handle,
+ dma_sync_single_for_cpu(&dev->persist->pdev->dev, fmr->dma_handle,
npages * sizeof(u64), DMA_TO_DEVICE);
for (i = 0; i < npages; ++i)
fmr->mtts[i] = cpu_to_be64(page_list[i] | MLX4_MTT_FLAG_PRESENT);
- dma_sync_single_for_device(&dev->pdev->dev, fmr->dma_handle,
+ dma_sync_single_for_device(&dev->persist->pdev->dev, fmr->dma_handle,
npages * sizeof(u64), DMA_TO_DEVICE);
fmr->mpt->key = cpu_to_be32(key);
@@ -1155,7 +1152,7 @@ EXPORT_SYMBOL_GPL(mlx4_fmr_free);
int mlx4_SYNC_TPT(struct mlx4_dev *dev)
{
- return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT, 1000,
- MLX4_CMD_NATIVE);
+ return mlx4_cmd(dev, 0, 0, 0, MLX4_CMD_SYNC_TPT,
+ MLX4_CMD_TIME_CLASS_A, MLX4_CMD_NATIVE);
}
EXPORT_SYMBOL_GPL(mlx4_SYNC_TPT);
diff --git a/drivers/net/ethernet/mellanox/mlx4/pd.c b/drivers/net/ethernet/mellanox/mlx4/pd.c
index 74216071201f..609c59dc854e 100644
--- a/drivers/net/ethernet/mellanox/mlx4/pd.c
+++ b/drivers/net/ethernet/mellanox/mlx4/pd.c
@@ -151,11 +151,13 @@ int mlx4_uar_alloc(struct mlx4_dev *dev, struct mlx4_uar *uar)
return -ENOMEM;
if (mlx4_is_slave(dev))
- offset = uar->index % ((int) pci_resource_len(dev->pdev, 2) /
+ offset = uar->index % ((int)pci_resource_len(dev->persist->pdev,
+ 2) /
dev->caps.uar_page_size);
else
offset = uar->index;
- uar->pfn = (pci_resource_start(dev->pdev, 2) >> PAGE_SHIFT) + offset;
+ uar->pfn = (pci_resource_start(dev->persist->pdev, 2) >> PAGE_SHIFT)
+ + offset;
uar->map = NULL;
return 0;
}
@@ -212,7 +214,6 @@ int mlx4_bf_alloc(struct mlx4_dev *dev, struct mlx4_bf *bf, int node)
list_add(&uar->bf_list, &priv->bf_list);
}
- bf->uar = uar;
idx = ffz(uar->free_bf_bmap);
uar->free_bf_bmap |= 1 << idx;
bf->uar = uar;
diff --git a/drivers/net/ethernet/mellanox/mlx4/port.c b/drivers/net/ethernet/mellanox/mlx4/port.c
index 30eb1ead0fe6..9f268f05290a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/port.c
+++ b/drivers/net/ethernet/mellanox/mlx4/port.c
@@ -553,9 +553,9 @@ int mlx4_get_slave_num_gids(struct mlx4_dev *dev, int slave, int port)
slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
dev, &exclusive_ports);
slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
- dev->num_vfs + 1);
+ dev->persist->num_vfs + 1);
}
- vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+ vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
if (slave_gid <= ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) % vfs))
return ((MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs) + 1;
return (MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS) / vfs;
@@ -590,10 +590,10 @@ int mlx4_get_base_gid_ix(struct mlx4_dev *dev, int slave, int port)
slaves_pport_actv = mlx4_phys_to_slaves_pport_actv(
dev, &exclusive_ports);
slave_gid -= bitmap_weight(slaves_pport_actv.slaves,
- dev->num_vfs + 1);
+ dev->persist->num_vfs + 1);
}
gids = MLX4_ROCE_MAX_GIDS - MLX4_ROCE_PF_GIDS;
- vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+ vfs = bitmap_weight(slaves_pport.slaves, dev->persist->num_vfs + 1) - 1;
if (slave_gid <= gids % vfs)
return MLX4_ROCE_PF_GIDS + ((gids / vfs) + 1) * (slave_gid - 1);
@@ -644,7 +644,7 @@ void mlx4_reset_roce_gids(struct mlx4_dev *dev, int slave)
int num_eth_ports, err;
int i;
- if (slave < 0 || slave > dev->num_vfs)
+ if (slave < 0 || slave > dev->persist->num_vfs)
return;
actv_ports = mlx4_get_active_ports(dev, slave);
@@ -1214,7 +1214,8 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
return -EINVAL;
slaves_pport = mlx4_phys_to_slaves_pport(dev, port);
- num_vfs = bitmap_weight(slaves_pport.slaves, dev->num_vfs + 1) - 1;
+ num_vfs = bitmap_weight(slaves_pport.slaves,
+ dev->persist->num_vfs + 1) - 1;
for (i = 0; i < MLX4_ROCE_MAX_GIDS; i++) {
if (!memcmp(priv->port[port].gid_table.roce_gids[i].raw, gid,
@@ -1258,7 +1259,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
dev, &exclusive_ports);
num_vfs_before += bitmap_weight(
slaves_pport_actv.slaves,
- dev->num_vfs + 1);
+ dev->persist->num_vfs + 1);
}
/* candidate_slave_gid isn't necessarily the correct slave, but
@@ -1288,7 +1289,7 @@ int mlx4_get_slave_from_roce_gid(struct mlx4_dev *dev, int port, u8 *gid,
dev, &exclusive_ports);
slave_gid += bitmap_weight(
slaves_pport_actv.slaves,
- dev->num_vfs + 1);
+ dev->persist->num_vfs + 1);
}
}
*slave_id = slave_gid;
diff --git a/drivers/net/ethernet/mellanox/mlx4/qp.c b/drivers/net/ethernet/mellanox/mlx4/qp.c
index 1586ecce13c7..2bb8553bd905 100644
--- a/drivers/net/ethernet/mellanox/mlx4/qp.c
+++ b/drivers/net/ethernet/mellanox/mlx4/qp.c
@@ -882,6 +882,8 @@ int mlx4_qp_to_ready(struct mlx4_dev *dev, struct mlx4_mtt *mtt,
for (i = 0; i < ARRAY_SIZE(states) - 1; i++) {
context->flags &= cpu_to_be32(~(0xf << 28));
context->flags |= cpu_to_be32(states[i + 1] << 28);
+ if (states[i + 1] != MLX4_QP_STATE_RTR)
+ context->params2 &= ~MLX4_QP_BIT_FPP;
err = mlx4_qp_modify(dev, mtt, states[i], states[i + 1],
context, 0, 0, qp);
if (err) {
diff --git a/drivers/net/ethernet/mellanox/mlx4/reset.c b/drivers/net/ethernet/mellanox/mlx4/reset.c
index ea1c6d092145..0076d88587ca 100644
--- a/drivers/net/ethernet/mellanox/mlx4/reset.c
+++ b/drivers/net/ethernet/mellanox/mlx4/reset.c
@@ -76,19 +76,21 @@ int mlx4_reset(struct mlx4_dev *dev)
goto out;
}
- pcie_cap = pci_pcie_cap(dev->pdev);
+ pcie_cap = pci_pcie_cap(dev->persist->pdev);
for (i = 0; i < 64; ++i) {
if (i == 22 || i == 23)
continue;
- if (pci_read_config_dword(dev->pdev, i * 4, hca_header + i)) {
+ if (pci_read_config_dword(dev->persist->pdev, i * 4,
+ hca_header + i)) {
err = -ENODEV;
mlx4_err(dev, "Couldn't save HCA PCI header, aborting\n");
goto out;
}
}
- reset = ioremap(pci_resource_start(dev->pdev, 0) + MLX4_RESET_BASE,
+ reset = ioremap(pci_resource_start(dev->persist->pdev, 0) +
+ MLX4_RESET_BASE,
MLX4_RESET_SIZE);
if (!reset) {
err = -ENOMEM;
@@ -122,8 +124,8 @@ int mlx4_reset(struct mlx4_dev *dev)
end = jiffies + MLX4_RESET_TIMEOUT_JIFFIES;
do {
- if (!pci_read_config_word(dev->pdev, PCI_VENDOR_ID, &vendor) &&
- vendor != 0xffff)
+ if (!pci_read_config_word(dev->persist->pdev, PCI_VENDOR_ID,
+ &vendor) && vendor != 0xffff)
break;
msleep(1);
@@ -138,14 +140,16 @@ int mlx4_reset(struct mlx4_dev *dev)
/* Now restore the PCI headers */
if (pcie_cap) {
devctl = hca_header[(pcie_cap + PCI_EXP_DEVCTL) / 4];
- if (pcie_capability_write_word(dev->pdev, PCI_EXP_DEVCTL,
+ if (pcie_capability_write_word(dev->persist->pdev,
+ PCI_EXP_DEVCTL,
devctl)) {
err = -ENODEV;
mlx4_err(dev, "Couldn't restore HCA PCI Express Device Control register, aborting\n");
goto out;
}
linkctl = hca_header[(pcie_cap + PCI_EXP_LNKCTL) / 4];
- if (pcie_capability_write_word(dev->pdev, PCI_EXP_LNKCTL,
+ if (pcie_capability_write_word(dev->persist->pdev,
+ PCI_EXP_LNKCTL,
linkctl)) {
err = -ENODEV;
mlx4_err(dev, "Couldn't restore HCA PCI Express Link control register, aborting\n");
@@ -157,7 +161,8 @@ int mlx4_reset(struct mlx4_dev *dev)
if (i * 4 == PCI_COMMAND)
continue;
- if (pci_write_config_dword(dev->pdev, i * 4, hca_header[i])) {
+ if (pci_write_config_dword(dev->persist->pdev, i * 4,
+ hca_header[i])) {
err = -ENODEV;
mlx4_err(dev, "Couldn't restore HCA reg %x, aborting\n",
i);
@@ -165,7 +170,7 @@ int mlx4_reset(struct mlx4_dev *dev)
}
}
- if (pci_write_config_dword(dev->pdev, PCI_COMMAND,
+ if (pci_write_config_dword(dev->persist->pdev, PCI_COMMAND,
hca_header[PCI_COMMAND / 4])) {
err = -ENODEV;
mlx4_err(dev, "Couldn't restore HCA COMMAND, aborting\n");
diff --git a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
index 4efbd1eca611..486e3d26cd4a 100644
--- a/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
+++ b/drivers/net/ethernet/mellanox/mlx4/resource_tracker.c
@@ -309,12 +309,13 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
int allocated, free, reserved, guaranteed, from_free;
int from_rsvd;
- if (slave > dev->num_vfs)
+ if (slave > dev->persist->num_vfs)
return -EINVAL;
spin_lock(&res_alloc->alloc_lock);
allocated = (port > 0) ?
- res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] :
+ res_alloc->allocated[(port - 1) *
+ (dev->persist->num_vfs + 1) + slave] :
res_alloc->allocated[slave];
free = (port > 0) ? res_alloc->res_port_free[port - 1] :
res_alloc->res_free;
@@ -352,7 +353,8 @@ static inline int mlx4_grant_resource(struct mlx4_dev *dev, int slave,
if (!err) {
/* grant the request */
if (port > 0) {
- res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] += count;
+ res_alloc->allocated[(port - 1) *
+ (dev->persist->num_vfs + 1) + slave] += count;
res_alloc->res_port_free[port - 1] -= count;
res_alloc->res_port_rsvd[port - 1] -= from_rsvd;
} else {
@@ -376,13 +378,14 @@ static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
&priv->mfunc.master.res_tracker.res_alloc[res_type];
int allocated, guaranteed, from_rsvd;
- if (slave > dev->num_vfs)
+ if (slave > dev->persist->num_vfs)
return;
spin_lock(&res_alloc->alloc_lock);
allocated = (port > 0) ?
- res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] :
+ res_alloc->allocated[(port - 1) *
+ (dev->persist->num_vfs + 1) + slave] :
res_alloc->allocated[slave];
guaranteed = res_alloc->guaranteed[slave];
@@ -397,7 +400,8 @@ static inline void mlx4_release_resource(struct mlx4_dev *dev, int slave,
}
if (port > 0) {
- res_alloc->allocated[(port - 1) * (dev->num_vfs + 1) + slave] -= count;
+ res_alloc->allocated[(port - 1) *
+ (dev->persist->num_vfs + 1) + slave] -= count;
res_alloc->res_port_free[port - 1] += count;
res_alloc->res_port_rsvd[port - 1] += from_rsvd;
} else {
@@ -415,7 +419,8 @@ static inline void initialize_res_quotas(struct mlx4_dev *dev,
enum mlx4_resource res_type,
int vf, int num_instances)
{
- res_alloc->guaranteed[vf] = num_instances / (2 * (dev->num_vfs + 1));
+ res_alloc->guaranteed[vf] = num_instances /
+ (2 * (dev->persist->num_vfs + 1));
res_alloc->quota[vf] = (num_instances / 2) + res_alloc->guaranteed[vf];
if (vf == mlx4_master_func_num(dev)) {
res_alloc->res_free = num_instances;
@@ -486,21 +491,26 @@ int mlx4_init_resource_tracker(struct mlx4_dev *dev)
for (i = 0; i < MLX4_NUM_OF_RESOURCE_TYPE; i++) {
struct resource_allocator *res_alloc =
&priv->mfunc.master.res_tracker.res_alloc[i];
- res_alloc->quota = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL);
- res_alloc->guaranteed = kmalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL);
+ res_alloc->quota = kmalloc((dev->persist->num_vfs + 1) *
+ sizeof(int), GFP_KERNEL);
+ res_alloc->guaranteed = kmalloc((dev->persist->num_vfs + 1) *
+ sizeof(int), GFP_KERNEL);
if (i == RES_MAC || i == RES_VLAN)
res_alloc->allocated = kzalloc(MLX4_MAX_PORTS *
- (dev->num_vfs + 1) * sizeof(int),
- GFP_KERNEL);
+ (dev->persist->num_vfs
+ + 1) *
+ sizeof(int), GFP_KERNEL);
else
- res_alloc->allocated = kzalloc((dev->num_vfs + 1) * sizeof(int), GFP_KERNEL);
+ res_alloc->allocated = kzalloc((dev->persist->
+ num_vfs + 1) *
+ sizeof(int), GFP_KERNEL);
if (!res_alloc->quota || !res_alloc->guaranteed ||
!res_alloc->allocated)
goto no_mem_err;
spin_lock_init(&res_alloc->alloc_lock);
- for (t = 0; t < dev->num_vfs + 1; t++) {
+ for (t = 0; t < dev->persist->num_vfs + 1; t++) {
struct mlx4_active_ports actv_ports =
mlx4_get_active_ports(dev, t);
switch (i) {
@@ -2531,7 +2541,7 @@ int mlx4_SW2HW_MPT_wrapper(struct mlx4_dev *dev, int slave,
/* Make sure that the PD bits related to the slave id are zeros. */
pd = mr_get_pd(inbox->buf);
pd_slave = (pd >> 17) & 0x7f;
- if (pd_slave != 0 && pd_slave != slave) {
+ if (pd_slave != 0 && --pd_slave != slave) {
err = -EPERM;
goto ex_abort;
}
@@ -2934,6 +2944,9 @@ static int verify_qp_parameters(struct mlx4_dev *dev,
qp_type = (be32_to_cpu(qp_ctx->flags) >> 16) & 0xff;
optpar = be32_to_cpu(*(__be32 *) inbox->buf);
+ if (slave != mlx4_master_func_num(dev))
+ qp_ctx->params2 &= ~MLX4_QP_BIT_FPP;
+
switch (qp_type) {
case MLX4_QP_ST_RC:
case MLX4_QP_ST_XRC:
@@ -4667,7 +4680,6 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave)
int state;
LIST_HEAD(tlist);
int eqn;
- struct mlx4_cmd_mailbox *mailbox;
err = move_all_busy(dev, slave, RES_EQ);
if (err)
@@ -4693,20 +4705,13 @@ static void rem_slave_eqs(struct mlx4_dev *dev, int slave)
break;
case RES_EQ_HW:
- mailbox = mlx4_alloc_cmd_mailbox(dev);
- if (IS_ERR(mailbox)) {
- cond_resched();
- continue;
- }
- err = mlx4_cmd_box(dev, slave, 0,
- eqn & 0xff, 0,
- MLX4_CMD_HW2SW_EQ,
- MLX4_CMD_TIME_CLASS_A,
- MLX4_CMD_NATIVE);
+ err = mlx4_cmd(dev, slave, eqn & 0xff,
+ 1, MLX4_CMD_HW2SW_EQ,
+ MLX4_CMD_TIME_CLASS_A,
+ MLX4_CMD_NATIVE);
if (err)
mlx4_dbg(dev, "rem_slave_eqs: failed to move slave %d eqs %d to SW ownership\n",
slave, eqn);
- mlx4_free_cmd_mailbox(dev, mailbox);
atomic_dec(&eq->mtt->ref_count);
state = RES_EQ_RESERVED;
break;
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
index 56779c1c7811..201ca6d76ce5 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/alloc.c
@@ -121,7 +121,7 @@ void mlx5_buf_free(struct mlx5_core_dev *dev, struct mlx5_buf *buf)
dma_free_coherent(&dev->pdev->dev, buf->size, buf->direct.buf,
buf->direct.map);
else {
- if (BITS_PER_LONG == 64 && buf->direct.buf)
+ if (BITS_PER_LONG == 64)
vunmap(buf->direct.buf);
for (i = 0; i < buf->nbufs; i++)
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
index 10e1f1a18255..4878025e231c 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/debugfs.c
@@ -300,11 +300,11 @@ static u64 qp_read_field(struct mlx5_core_dev *dev, struct mlx5_core_qp *qp,
param = qp->pid;
break;
case QP_STATE:
- param = (u64)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28);
+ param = (unsigned long)mlx5_qp_state_str(be32_to_cpu(ctx->flags) >> 28);
*is_str = 1;
break;
case QP_XPORT:
- param = (u64)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff);
+ param = (unsigned long)mlx5_qp_type_str((be32_to_cpu(ctx->flags) >> 16) & 0xff);
*is_str = 1;
break;
case QP_MTU:
@@ -464,7 +464,7 @@ static ssize_t dbg_read(struct file *filp, char __user *buf, size_t count,
if (is_str)
- ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)field);
+ ret = snprintf(tbuf, sizeof(tbuf), "%s\n", (const char *)(unsigned long)field);
else
ret = snprintf(tbuf, sizeof(tbuf), "0x%llx\n", field);
diff --git a/drivers/net/ethernet/mellanox/mlx5/core/main.c b/drivers/net/ethernet/mellanox/mlx5/core/main.c
index 3f4525619a07..5394a8486558 100644
--- a/drivers/net/ethernet/mellanox/mlx5/core/main.c
+++ b/drivers/net/ethernet/mellanox/mlx5/core/main.c
@@ -291,6 +291,7 @@ static void copy_rw_fields(void *to, struct mlx5_caps *from)
MLX5_SET(cmd_hca_cap, to, log_max_ra_req_dc, from->gen.log_max_ra_req_dc);
MLX5_SET(cmd_hca_cap, to, log_max_ra_res_dc, from->gen.log_max_ra_res_dc);
MLX5_SET(cmd_hca_cap, to, pkey_table_size, to_fw_pkey_sz(from->gen.pkey_table_size));
+ MLX5_SET(cmd_hca_cap, to, log_uar_page_sz, PAGE_SHIFT - 12);
v64 = from->gen.flags & MLX5_CAP_BITS_RW_MASK;
*flags_off = cpu_to_be64(v64);
}
@@ -903,12 +904,12 @@ static void remove_one(struct pci_dev *pdev)
}
static const struct pci_device_id mlx5_core_pci_table[] = {
- { PCI_VDEVICE(MELLANOX, 4113) }, /* Connect-IB */
- { PCI_VDEVICE(MELLANOX, 4114) }, /* Connect-IB VF */
- { PCI_VDEVICE(MELLANOX, 4115) }, /* ConnectX-4 */
- { PCI_VDEVICE(MELLANOX, 4116) }, /* ConnectX-4 VF */
- { PCI_VDEVICE(MELLANOX, 4117) }, /* ConnectX-4LX */
- { PCI_VDEVICE(MELLANOX, 4118) }, /* ConnectX-4LX VF */
+ { PCI_VDEVICE(MELLANOX, 0x1011) }, /* Connect-IB */
+ { PCI_VDEVICE(MELLANOX, 0x1012) }, /* Connect-IB VF */
+ { PCI_VDEVICE(MELLANOX, 0x1013) }, /* ConnectX-4 */
+ { PCI_VDEVICE(MELLANOX, 0x1014) }, /* ConnectX-4 VF */
+ { PCI_VDEVICE(MELLANOX, 0x1015) }, /* ConnectX-4LX */
+ { PCI_VDEVICE(MELLANOX, 0x1016) }, /* ConnectX-4LX VF */
{ 0, }
};
diff --git a/drivers/net/ethernet/micrel/ksz884x.c b/drivers/net/ethernet/micrel/ksz884x.c
index 2fa6ae026e4f..10988fbf47eb 100644
--- a/drivers/net/ethernet/micrel/ksz884x.c
+++ b/drivers/net/ethernet/micrel/ksz884x.c
@@ -4342,9 +4342,7 @@ static void ksz_init_timer(struct ksz_timer_info *info, int period,
{
info->max = 0;
info->period = period;
- init_timer(&info->timer);
- info->timer.function = function;
- info->timer.data = (unsigned long) data;
+ setup_timer(&info->timer, function, (unsigned long)data);
}
static void ksz_update_timer(struct ksz_timer_info *info)
diff --git a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
index 71af98bb72cb..1412f5af05ec 100644
--- a/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
+++ b/drivers/net/ethernet/myricom/myri10ge/myri10ge.c
@@ -4226,8 +4226,7 @@ static void myri10ge_remove(struct pci_dev *pdev)
mtrr_del(mgp->mtrr, mgp->iomem_base, mgp->board_span);
#endif
myri10ge_free_slices(mgp);
- if (mgp->msix_vectors != NULL)
- kfree(mgp->msix_vectors);
+ kfree(mgp->msix_vectors);
dma_free_coherent(&pdev->dev, sizeof(*mgp->cmd),
mgp->cmd, mgp->cmd_bus);
diff --git a/drivers/net/ethernet/natsemi/ns83820.c b/drivers/net/ethernet/natsemi/ns83820.c
index 2552e550a78c..eb807b0dc72a 100644
--- a/drivers/net/ethernet/natsemi/ns83820.c
+++ b/drivers/net/ethernet/natsemi/ns83820.c
@@ -1122,12 +1122,12 @@ again:
}
#ifdef NS83820_VLAN_ACCEL_SUPPORT
- if(vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
/* fetch the vlan tag info out of the
* ancillary data if the vlan code
* is using hw vlan acceleration
*/
- short tag = vlan_tx_tag_get(skb);
+ short tag = skb_vlan_tag_get(skb);
extsts |= (EXTSTS_VPKT | htons(tag));
}
#endif
diff --git a/drivers/net/ethernet/neterion/s2io.c b/drivers/net/ethernet/neterion/s2io.c
index db0c7a9aee60..a4cdf2f8041a 100644
--- a/drivers/net/ethernet/neterion/s2io.c
+++ b/drivers/net/ethernet/neterion/s2io.c
@@ -4045,8 +4045,8 @@ static netdev_tx_t s2io_xmit(struct sk_buff *skb, struct net_device *dev)
}
queue = 0;
- if (vlan_tx_tag_present(skb))
- vlan_tag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb))
+ vlan_tag = skb_vlan_tag_get(skb);
if (sp->config.tx_steering_type == TX_DEFAULT_STEERING) {
if (skb->protocol == htons(ETH_P_IP)) {
struct iphdr *ip;
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-config.c b/drivers/net/ethernet/neterion/vxge/vxge-config.c
index 2bbd01fcb9b0..6223930a8155 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-config.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-config.c
@@ -4637,7 +4637,7 @@ static void __vxge_hw_vp_terminate(struct __vxge_hw_device *hldev, u32 vp_id)
vpath->ringh = NULL;
vpath->fifoh = NULL;
memset(&vpath->vpath_handles, 0, sizeof(struct list_head));
- vpath->stats_block = 0;
+ vpath->stats_block = NULL;
vpath->hw_stats = NULL;
vpath->hw_stats_sav = NULL;
vpath->sw_stats = NULL;
diff --git a/drivers/net/ethernet/neterion/vxge/vxge-main.c b/drivers/net/ethernet/neterion/vxge/vxge-main.c
index cc0485e3c621..50d5604833ed 100644
--- a/drivers/net/ethernet/neterion/vxge/vxge-main.c
+++ b/drivers/net/ethernet/neterion/vxge/vxge-main.c
@@ -890,8 +890,8 @@ vxge_xmit(struct sk_buff *skb, struct net_device *dev)
dev->name, __func__, __LINE__,
fifo_hw, dtr, dtr_priv);
- if (vlan_tx_tag_present(skb)) {
- u16 vlan_tag = vlan_tx_tag_get(skb);
+ if (skb_vlan_tag_present(skb)) {
+ u16 vlan_tag = skb_vlan_tag_get(skb);
vxge_hw_fifo_txdl_vlan_set(dtr, vlan_tag);
}
diff --git a/drivers/net/ethernet/nvidia/forcedeth.c b/drivers/net/ethernet/nvidia/forcedeth.c
index f39cae620f61..a41bb5e6b954 100644
--- a/drivers/net/ethernet/nvidia/forcedeth.c
+++ b/drivers/net/ethernet/nvidia/forcedeth.c
@@ -2462,9 +2462,9 @@ static netdev_tx_t nv_start_xmit_optimized(struct sk_buff *skb,
NV_TX2_CHECKSUM_L3 | NV_TX2_CHECKSUM_L4 : 0;
/* vlan tag */
- if (vlan_tx_tag_present(skb))
+ if (skb_vlan_tag_present(skb))
start_tx->txvlan = cpu_to_le32(NV_TX3_VLAN_TAG_PRESENT |
- vlan_tx_tag_get(skb));
+ skb_vlan_tag_get(skb));
else
start_tx->txvlan = 0;
diff --git a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
index c531c8ae1be4..e0c31e3947d1 100644
--- a/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
+++ b/drivers/net/ethernet/qlogic/netxen/netxen_nic_main.c
@@ -176,9 +176,7 @@ netxen_alloc_sds_rings(struct netxen_recv_context *recv_ctx, int count)
static void
netxen_free_sds_rings(struct netxen_recv_context *recv_ctx)
{
- if (recv_ctx->sds_rings != NULL)
- kfree(recv_ctx->sds_rings);
-
+ kfree(recv_ctx->sds_rings);
recv_ctx->sds_rings = NULL;
}
@@ -1893,9 +1891,9 @@ netxen_tso_check(struct net_device *netdev,
protocol = vh->h_vlan_encapsulated_proto;
flags = FLAGS_VLAN_TAGGED;
- } else if (vlan_tx_tag_present(skb)) {
+ } else if (skb_vlan_tag_present(skb)) {
flags = FLAGS_VLAN_OOB;
- vid = vlan_tx_tag_get(skb);
+ vid = skb_vlan_tag_get(skb);
netxen_set_tx_vlan_tci(first_desc, vid);
vlan_oob = 1;
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index e56c1bb36141..fa4317611fd6 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -848,10 +848,17 @@ struct qlcnic_cardrsp_tx_ctx {
#define QLCNIC_MAC_VLAN_ADD 3
#define QLCNIC_MAC_VLAN_DEL 4
+enum qlcnic_mac_type {
+ QLCNIC_UNICAST_MAC,
+ QLCNIC_MULTICAST_MAC,
+ QLCNIC_BROADCAST_MAC,
+};
+
struct qlcnic_mac_vlan_list {
struct list_head list;
uint8_t mac_addr[ETH_ALEN+2];
u16 vlan_id;
+ enum qlcnic_mac_type mac_type;
};
/* MAC Learn */
@@ -1615,7 +1622,9 @@ void qlcnic_watchdog_task(struct work_struct *work);
void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
struct qlcnic_host_rds_ring *rds_ring, u8 ring_id);
void qlcnic_set_multi(struct net_device *netdev);
-int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16);
+void qlcnic_flush_mcast_mac(struct qlcnic_adapter *);
+int qlcnic_nic_add_mac(struct qlcnic_adapter *, const u8 *, u16,
+ enum qlcnic_mac_type);
int qlcnic_nic_del_mac(struct qlcnic_adapter *, const u8 *);
void qlcnic_82xx_free_mac_list(struct qlcnic_adapter *adapter);
int qlcnic_82xx_read_phys_port_id(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index 69b46c051cc0..3e0f705a4311 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -487,7 +487,8 @@ int qlcnic_nic_del_mac(struct qlcnic_adapter *adapter, const u8 *addr)
return err;
}
-int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
+int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan,
+ enum qlcnic_mac_type mac_type)
{
struct qlcnic_mac_vlan_list *cur;
struct list_head *head;
@@ -513,10 +514,29 @@ int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr, u16 vlan)
}
cur->vlan_id = vlan;
+ cur->mac_type = mac_type;
+
list_add_tail(&cur->list, &adapter->mac_list);
return 0;
}
+void qlcnic_flush_mcast_mac(struct qlcnic_adapter *adapter)
+{
+ struct qlcnic_mac_vlan_list *cur;
+ struct list_head *head, *tmp;
+
+ list_for_each_safe(head, tmp, &adapter->mac_list) {
+ cur = list_entry(head, struct qlcnic_mac_vlan_list, list);
+ if (cur->mac_type != QLCNIC_MULTICAST_MAC)
+ continue;
+
+ qlcnic_sre_macaddr_change(adapter, cur->mac_addr,
+ cur->vlan_id, QLCNIC_MAC_DEL);
+ list_del(&cur->list);
+ kfree(cur);
+ }
+}
+
static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -530,8 +550,9 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state))
return;
- qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan);
- qlcnic_nic_add_mac(adapter, bcast_addr, vlan);
+ qlcnic_nic_add_mac(adapter, adapter->mac_addr, vlan,
+ QLCNIC_UNICAST_MAC);
+ qlcnic_nic_add_mac(adapter, bcast_addr, vlan, QLCNIC_BROADCAST_MAC);
if (netdev->flags & IFF_PROMISC) {
if (!(adapter->flags & QLCNIC_PROMISC_DISABLED))
@@ -540,8 +561,10 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else if (!netdev_mc_empty(netdev)) {
+ qlcnic_flush_mcast_mac(adapter);
netdev_for_each_mc_addr(ha, netdev)
- qlcnic_nic_add_mac(adapter, ha->addr, vlan);
+ qlcnic_nic_add_mac(adapter, ha->addr, vlan,
+ QLCNIC_MULTICAST_MAC);
}
/* configure unicast MAC address, if there is not sufficient space
@@ -551,7 +574,8 @@ static void __qlcnic_set_multi(struct net_device *netdev, u16 vlan)
mode = VPORT_MISS_MODE_ACCEPT_ALL;
} else if (!netdev_uc_empty(netdev)) {
netdev_for_each_uc_addr(ha, netdev)
- qlcnic_nic_add_mac(adapter, ha->addr, vlan);
+ qlcnic_nic_add_mac(adapter, ha->addr, vlan,
+ QLCNIC_UNICAST_MAC);
}
if (mode == VPORT_MISS_MODE_ACCEPT_ALL &&
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 18e5de72e9b4..d4b5085a21fa 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -10,6 +10,7 @@
#include <net/ip.h>
#include <linux/ipv6.h>
#include <net/checksum.h>
+#include <linux/printk.h>
#include "qlcnic.h"
@@ -320,8 +321,8 @@ static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
if (protocol == ETH_P_8021Q) {
vh = (struct vlan_ethhdr *)skb->data;
vlan_id = ntohs(vh->h_vlan_TCI);
- } else if (vlan_tx_tag_present(skb)) {
- vlan_id = vlan_tx_tag_get(skb);
+ } else if (skb_vlan_tag_present(skb)) {
+ vlan_id = skb_vlan_tag_get(skb);
}
}
@@ -472,9 +473,9 @@ static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
flags = QLCNIC_FLAGS_VLAN_TAGGED;
vlan_tci = ntohs(vh->h_vlan_TCI);
protocol = ntohs(vh->h_vlan_encapsulated_proto);
- } else if (vlan_tx_tag_present(skb)) {
+ } else if (skb_vlan_tag_present(skb)) {
flags = QLCNIC_FLAGS_VLAN_OOB;
- vlan_tci = vlan_tx_tag_get(skb);
+ vlan_tci = skb_vlan_tag_get(skb);
}
if (unlikely(adapter->tx_pvid)) {
if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
@@ -967,7 +968,12 @@ static int qlcnic_poll(struct napi_struct *napi, int budget)
tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring,
budget);
work_done = qlcnic_process_rcv_ring(sds_ring, budget);
- if ((work_done < budget) && tx_complete) {
+
+ /* Check if we need a repoll */
+ if (!tx_complete)
+ work_done = budget;
+
+ if (work_done < budget) {
napi_complete(&sds_ring->napi);
if (test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
qlcnic_enable_sds_intr(adapter, sds_ring);
@@ -992,6 +998,9 @@ static int qlcnic_tx_poll(struct napi_struct *napi, int budget)
napi_complete(&tx_ring->napi);
if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
qlcnic_enable_tx_intr(adapter, tx_ring);
+ } else {
+ /* As qlcnic_process_cmd_ring() returned 0, we need a repoll*/
+ work_done = budget;
}
return work_done;
@@ -1465,14 +1474,14 @@ void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
{
- int i;
- unsigned char *data = skb->data;
+ if (adapter->ahw->msg_enable & NETIF_MSG_DRV) {
+ char prefix[30];
+
+ scnprintf(prefix, sizeof(prefix), "%s: %s: ",
+ dev_name(&adapter->pdev->dev), __func__);
- pr_info(KERN_INFO "\n");
- for (i = 0; i < skb->len; i++) {
- QLCDB(adapter, DRV, "%02x ", data[i]);
- if ((i & 0x0f) == 8)
- pr_info(KERN_INFO "\n");
+ print_hex_dump_debug(prefix, DUMP_PREFIX_NONE, 16, 1,
+ skb->data, skb->len, true);
}
}
@@ -1950,7 +1959,12 @@ static int qlcnic_83xx_msix_sriov_vf_poll(struct napi_struct *napi, int budget)
tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
- if ((work_done < budget) && tx_complete) {
+
+ /* Check if we need a repoll */
+ if (!tx_complete)
+ work_done = budget;
+
+ if (work_done < budget) {
napi_complete(&sds_ring->napi);
qlcnic_enable_sds_intr(adapter, sds_ring);
}
@@ -1973,7 +1987,12 @@ static int qlcnic_83xx_poll(struct napi_struct *napi, int budget)
tx_complete = qlcnic_process_cmd_ring(adapter, tx_ring, budget);
work_done = qlcnic_83xx_process_rcv_ring(sds_ring, budget);
- if ((work_done < budget) && tx_complete) {
+
+ /* Check if we need a repoll */
+ if (!tx_complete)
+ work_done = budget;
+
+ if (work_done < budget) {
napi_complete(&sds_ring->napi);
qlcnic_enable_sds_intr(adapter, sds_ring);
}
@@ -1995,6 +2014,9 @@ static int qlcnic_83xx_msix_tx_poll(struct napi_struct *napi, int budget)
napi_complete(&tx_ring->napi);
if (test_bit(__QLCNIC_DEV_UP , &adapter->state))
qlcnic_enable_tx_intr(adapter, tx_ring);
+ } else {
+ /* need a repoll */
+ work_done = budget;
}
return work_done;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 2528c3fb6b90..a430a34a4434 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -294,9 +294,7 @@ int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
{
- if (recv_ctx->sds_rings != NULL)
- kfree(recv_ctx->sds_rings);
-
+ kfree(recv_ctx->sds_rings);
recv_ctx->sds_rings = NULL;
}
@@ -1257,8 +1255,7 @@ qlcnic_check_options(struct qlcnic_adapter *adapter)
if (ahw->op_mode != QLCNIC_NON_PRIV_FUNC) {
if (fw_dump->tmpl_hdr == NULL ||
adapter->fw_version > prev_fw_version) {
- if (fw_dump->tmpl_hdr)
- vfree(fw_dump->tmpl_hdr);
+ vfree(fw_dump->tmpl_hdr);
if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
dev_info(&pdev->dev,
"Supports FW dump capability\n");
@@ -2374,13 +2371,12 @@ void qlcnic_free_tx_rings(struct qlcnic_adapter *adapter)
for (ring = 0; ring < adapter->drv_tx_rings; ring++) {
tx_ring = &adapter->tx_ring[ring];
- if (tx_ring && tx_ring->cmd_buf_arr != NULL) {
+ if (tx_ring) {
vfree(tx_ring->cmd_buf_arr);
tx_ring->cmd_buf_arr = NULL;
}
}
- if (adapter->tx_ring != NULL)
- kfree(adapter->tx_ring);
+ kfree(adapter->tx_ring);
}
int qlcnic_alloc_tx_rings(struct qlcnic_adapter *adapter,
@@ -2758,13 +2754,9 @@ static void qlcnic_remove(struct pci_dev *pdev)
}
qlcnic_dcb_free(adapter->dcb);
-
qlcnic_detach(adapter);
-
- if (adapter->npars != NULL)
- kfree(adapter->npars);
- if (adapter->eswitch != NULL)
- kfree(adapter->eswitch);
+ kfree(adapter->npars);
+ kfree(adapter->eswitch);
if (qlcnic_82xx_check(adapter))
qlcnic_clr_all_drv_state(adapter, 0);
@@ -2932,13 +2924,13 @@ void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
{
- if (adapter->fhash.fmax && adapter->fhash.fhead)
+ if (adapter->fhash.fmax)
kfree(adapter->fhash.fhead);
adapter->fhash.fhead = NULL;
adapter->fhash.fmax = 0;
- if (adapter->rx_fhash.fmax && adapter->rx_fhash.fhead)
+ if (adapter->rx_fhash.fmax)
kfree(adapter->rx_fhash.fhead);
adapter->rx_fhash.fmax = 0;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index c9f57fb84b9e..332bb8a3f430 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -1407,8 +1407,7 @@ void qlcnic_83xx_get_minidump_template(struct qlcnic_adapter *adapter)
current_version = qlcnic_83xx_get_fw_version(adapter);
if (fw_dump->tmpl_hdr == NULL || current_version > prev_version) {
- if (fw_dump->tmpl_hdr)
- vfree(fw_dump->tmpl_hdr);
+ vfree(fw_dump->tmpl_hdr);
if (!qlcnic_fw_cmd_get_minidump_temp(adapter))
dev_info(&pdev->dev, "Supports FW dump capability\n");
}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
index 1659c804f1d5..e6312465fe45 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sriov_common.c
@@ -1489,7 +1489,8 @@ out:
return ret;
}
-static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac)
+static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac,
+ enum qlcnic_mac_type mac_type)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_sriov *sriov = adapter->ahw->sriov;
@@ -1500,17 +1501,18 @@ static void qlcnic_vf_add_mc_list(struct net_device *netdev, const u8 *mac)
vf = &adapter->ahw->sriov->vf_info[0];
if (!qlcnic_sriov_check_any_vlan(vf)) {
- qlcnic_nic_add_mac(adapter, mac, 0);
+ qlcnic_nic_add_mac(adapter, mac, 0, mac_type);
} else {
spin_lock(&vf->vlan_list_lock);
for (i = 0; i < sriov->num_allowed_vlans; i++) {
vlan_id = vf->sriov_vlans[i];
if (vlan_id)
- qlcnic_nic_add_mac(adapter, mac, vlan_id);
+ qlcnic_nic_add_mac(adapter, mac, vlan_id,
+ mac_type);
}
spin_unlock(&vf->vlan_list_lock);
if (qlcnic_84xx_check(adapter))
- qlcnic_nic_add_mac(adapter, mac, 0);
+ qlcnic_nic_add_mac(adapter, mac, 0, mac_type);
}
}
@@ -1549,10 +1551,12 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
(netdev_mc_count(netdev) > ahw->max_mc_count)) {
mode = VPORT_MISS_MODE_ACCEPT_MULTI;
} else {
- qlcnic_vf_add_mc_list(netdev, bcast_addr);
+ qlcnic_vf_add_mc_list(netdev, bcast_addr, QLCNIC_BROADCAST_MAC);
if (!netdev_mc_empty(netdev)) {
+ qlcnic_flush_mcast_mac(adapter);
netdev_for_each_mc_addr(ha, netdev)
- qlcnic_vf_add_mc_list(netdev, ha->addr);
+ qlcnic_vf_add_mc_list(netdev, ha->addr,
+ QLCNIC_MULTICAST_MAC);
}
}
@@ -1563,7 +1567,8 @@ void qlcnic_sriov_vf_set_multi(struct net_device *netdev)
mode = VPORT_MISS_MODE_ACCEPT_ALL;
} else if (!netdev_uc_empty(netdev)) {
netdev_for_each_uc_addr(ha, netdev)
- qlcnic_vf_add_mc_list(netdev, ha->addr);
+ qlcnic_vf_add_mc_list(netdev, ha->addr,
+ QLCNIC_UNICAST_MAC);
}
if (adapter->pdev->is_virtfn) {
diff --git a/drivers/net/ethernet/qlogic/qlge/qlge_main.c b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
index 6c904a6cad2a..8011ef3e7707 100644
--- a/drivers/net/ethernet/qlogic/qlge/qlge_main.c
+++ b/drivers/net/ethernet/qlogic/qlge/qlge_main.c
@@ -2351,23 +2351,29 @@ static int qlge_update_hw_vlan_features(struct net_device *ndev,
{
struct ql_adapter *qdev = netdev_priv(ndev);
int status = 0;
+ bool need_restart = netif_running(ndev);
- status = ql_adapter_down(qdev);
- if (status) {
- netif_err(qdev, link, qdev->ndev,
- "Failed to bring down the adapter\n");
- return status;
+ if (need_restart) {
+ status = ql_adapter_down(qdev);
+ if (status) {
+ netif_err(qdev, link, qdev->ndev,
+ "Failed to bring down the adapter\n");
+ return status;
+ }
}
/* update the features with resent change */
ndev->features = features;
- status = ql_adapter_up(qdev);
- if (status) {
- netif_err(qdev, link, qdev->ndev,
- "Failed to bring up the adapter\n");
- return status;
+ if (need_restart) {
+ status = ql_adapter_up(qdev);
+ if (status) {
+ netif_err(qdev, link, qdev->ndev,
+ "Failed to bring up the adapter\n");
+ return status;
+ }
}
+
return status;
}
@@ -2660,11 +2666,11 @@ static netdev_tx_t qlge_send(struct sk_buff *skb, struct net_device *ndev)
mac_iocb_ptr->frame_len = cpu_to_le16((u16) skb->len);
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
netif_printk(qdev, tx_queued, KERN_DEBUG, qdev->ndev,
- "Adding a vlan tag %d.\n", vlan_tx_tag_get(skb));
+ "Adding a vlan tag %d.\n", skb_vlan_tag_get(skb));
mac_iocb_ptr->flags3 |= OB_MAC_IOCB_V;
- mac_iocb_ptr->vlan_tci = cpu_to_le16(vlan_tx_tag_get(skb));
+ mac_iocb_ptr->vlan_tci = cpu_to_le16(skb_vlan_tag_get(skb));
}
tso = ql_tso(skb, (struct ob_mac_tso_iocb_req *)mac_iocb_ptr);
if (tso < 0) {
diff --git a/drivers/net/ethernet/realtek/8139cp.c b/drivers/net/ethernet/realtek/8139cp.c
index 9c31e46d1eee..d79e33b3c191 100644
--- a/drivers/net/ethernet/realtek/8139cp.c
+++ b/drivers/net/ethernet/realtek/8139cp.c
@@ -708,8 +708,8 @@ static void cp_tx (struct cp_private *cp)
static inline u32 cp_tx_vlan_tag(struct sk_buff *skb)
{
- return vlan_tx_tag_present(skb) ?
- TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
+ return skb_vlan_tag_present(skb) ?
+ TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
}
static void unwind_tx_frag_mapping(struct cp_private *cp, struct sk_buff *skb,
diff --git a/drivers/net/ethernet/realtek/r8169.c b/drivers/net/ethernet/realtek/r8169.c
index 14a1c5cec3a5..ad0020af2193 100644
--- a/drivers/net/ethernet/realtek/r8169.c
+++ b/drivers/net/ethernet/realtek/r8169.c
@@ -2073,8 +2073,8 @@ static int rtl8169_set_features(struct net_device *dev,
static inline u32 rtl8169_tx_vlan_tag(struct sk_buff *skb)
{
- return (vlan_tx_tag_present(skb)) ?
- TxVlanTag | swab16(vlan_tx_tag_get(skb)) : 0x00;
+ return (skb_vlan_tag_present(skb)) ?
+ TxVlanTag | swab16(skb_vlan_tag_get(skb)) : 0x00;
}
static void rtl8169_rx_vlan_tag(struct RxDesc *desc, struct sk_buff *skb)
@@ -4915,7 +4915,7 @@ static void r8168c_hw_jumbo_enable(struct rtl8169_private *tp)
RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
RTL_W8(Config4, RTL_R8(Config4) | Jumbo_En1);
- rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
+ rtl_tx_performance_tweak(tp->pci_dev, PCI_EXP_DEVCTL_READRQ_512B);
}
static void r8168c_hw_jumbo_disable(struct rtl8169_private *tp)
@@ -4948,7 +4948,7 @@ static void r8168e_hw_jumbo_enable(struct rtl8169_private *tp)
RTL_W8(MaxTxPacketSize, 0x3f);
RTL_W8(Config3, RTL_R8(Config3) | Jumbo_En0);
RTL_W8(Config4, RTL_R8(Config4) | 0x01);
- rtl_tx_performance_tweak(tp->pci_dev, 0x2 << MAX_READ_REQUEST_SHIFT);
+ rtl_tx_performance_tweak(tp->pci_dev, PCI_EXP_DEVCTL_READRQ_512B);
}
static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
@@ -4964,7 +4964,7 @@ static void r8168e_hw_jumbo_disable(struct rtl8169_private *tp)
static void r8168b_0_hw_jumbo_enable(struct rtl8169_private *tp)
{
rtl_tx_performance_tweak(tp->pci_dev,
- (0x2 << MAX_READ_REQUEST_SHIFT) | PCI_EXP_DEVCTL_NOSNOOP_EN);
+ PCI_EXP_DEVCTL_READRQ_512B | PCI_EXP_DEVCTL_NOSNOOP_EN);
}
static void r8168b_0_hw_jumbo_disable(struct rtl8169_private *tp)
@@ -7049,6 +7049,7 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
u32 status, len;
u32 opts[2];
int frags;
+ bool stop_queue;
if (unlikely(!TX_FRAGS_READY_FOR(tp, skb_shinfo(skb)->nr_frags))) {
netif_err(tp, drv, dev, "BUG! Tx Ring full when queue awake!\n");
@@ -7105,11 +7106,16 @@ static netdev_tx_t rtl8169_start_xmit(struct sk_buff *skb,
tp->cur_tx += frags + 1;
- RTL_W8(TxPoll, NPQ);
+ stop_queue = !TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS);
- mmiowb();
+ if (!skb->xmit_more || stop_queue ||
+ netif_xmit_stopped(netdev_get_tx_queue(dev, 0))) {
+ RTL_W8(TxPoll, NPQ);
+
+ mmiowb();
+ }
- if (!TX_FRAGS_READY_FOR(tp, MAX_SKB_FRAGS)) {
+ if (stop_queue) {
/* Avoid wrongly optimistic queue wake-up: rtl_tx thread must
* not miss a ring update when it notices a stopped queue.
*/
diff --git a/drivers/net/ethernet/renesas/sh_eth.c b/drivers/net/ethernet/renesas/sh_eth.c
index 04283fe0e6a7..4da8bd263997 100644
--- a/drivers/net/ethernet/renesas/sh_eth.c
+++ b/drivers/net/ethernet/renesas/sh_eth.c
@@ -597,7 +597,7 @@ static struct sh_eth_cpu_data sh7757_data = {
static void sh_eth_chip_reset_giga(struct net_device *ndev)
{
int i;
- unsigned long mahr[2], malr[2];
+ u32 mahr[2], malr[2];
/* save MAHR and MALR */
for (i = 0; i < 2; i++) {
@@ -991,7 +991,7 @@ static void read_mac_address(struct net_device *ndev, unsigned char *mac)
}
}
-static unsigned long sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
+static u32 sh_eth_get_edtrr_trns(struct sh_eth_private *mdp)
{
if (sh_eth_is_gether(mdp) || sh_eth_is_rz_fast_ether(mdp))
return EDTRR_TRNS_GETHER;
@@ -1565,7 +1565,7 @@ static void sh_eth_rcv_snd_enable(struct net_device *ndev)
}
/* error control function */
-static void sh_eth_error(struct net_device *ndev, int intr_status)
+static void sh_eth_error(struct net_device *ndev, u32 intr_status)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
u32 felic_stat;
@@ -1678,7 +1678,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
struct sh_eth_private *mdp = netdev_priv(ndev);
struct sh_eth_cpu_data *cd = mdp->cd;
irqreturn_t ret = IRQ_NONE;
- unsigned long intr_status, intr_enable;
+ u32 intr_status, intr_enable;
spin_lock(&mdp->lock);
@@ -1709,7 +1709,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
__napi_schedule(&mdp->napi);
} else {
netdev_warn(ndev,
- "ignoring interrupt, status 0x%08lx, mask 0x%08lx.\n",
+ "ignoring interrupt, status 0x%08x, mask 0x%08x.\n",
intr_status, intr_enable);
}
}
@@ -1742,7 +1742,7 @@ static int sh_eth_poll(struct napi_struct *napi, int budget)
napi);
struct net_device *ndev = napi->dev;
int quota = budget;
- unsigned long intr_status;
+ u32 intr_status;
for (;;) {
intr_status = sh_eth_read(ndev, EESR);
@@ -2133,7 +2133,7 @@ static void sh_eth_tx_timeout(struct net_device *ndev)
netif_err(mdp, timer, ndev,
"transmit timed out, status %8.8x, resetting...\n",
- (int)sh_eth_read(ndev, EESR));
+ sh_eth_read(ndev, EESR));
/* tx_errors count up */
ndev->stats.tx_errors++;
@@ -3019,6 +3019,36 @@ static int sh_eth_drv_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
+static int sh_eth_suspend(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (netif_running(ndev)) {
+ netif_device_detach(ndev);
+ ret = sh_eth_close(ndev);
+ }
+
+ return ret;
+}
+
+static int sh_eth_resume(struct device *dev)
+{
+ struct net_device *ndev = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (netif_running(ndev)) {
+ ret = sh_eth_open(ndev);
+ if (ret < 0)
+ return ret;
+ netif_device_attach(ndev);
+ }
+
+ return ret;
+}
+#endif
+
static int sh_eth_runtime_nop(struct device *dev)
{
/* Runtime PM callback shared between ->runtime_suspend()
@@ -3032,8 +3062,8 @@ static int sh_eth_runtime_nop(struct device *dev)
}
static const struct dev_pm_ops sh_eth_dev_pm_ops = {
- .runtime_suspend = sh_eth_runtime_nop,
- .runtime_resume = sh_eth_runtime_nop,
+ SET_SYSTEM_SLEEP_PM_OPS(sh_eth_suspend, sh_eth_resume)
+ SET_RUNTIME_PM_OPS(sh_eth_runtime_nop, sh_eth_runtime_nop, NULL)
};
#define SH_ETH_PM_OPS (&sh_eth_dev_pm_ops)
#else
diff --git a/drivers/net/ethernet/renesas/sh_eth.h b/drivers/net/ethernet/renesas/sh_eth.h
index 332d3c16d483..259d03f353e1 100644
--- a/drivers/net/ethernet/renesas/sh_eth.h
+++ b/drivers/net/ethernet/renesas/sh_eth.h
@@ -459,21 +459,21 @@ struct sh_eth_cpu_data {
/* mandatory initialize value */
int register_type;
- unsigned long eesipr_value;
+ u32 eesipr_value;
/* optional initialize value */
- unsigned long ecsr_value;
- unsigned long ecsipr_value;
- unsigned long fdr_value;
- unsigned long fcftr_value;
- unsigned long rpadir_value;
+ u32 ecsr_value;
+ u32 ecsipr_value;
+ u32 fdr_value;
+ u32 fcftr_value;
+ u32 rpadir_value;
/* interrupt checking mask */
- unsigned long tx_check;
- unsigned long eesr_err_check;
+ u32 tx_check;
+ u32 eesr_err_check;
/* Error mask */
- unsigned long trscer_err_mask;
+ u32 trscer_err_mask;
/* hardware features */
unsigned long irq_flags; /* IRQ configuration flags */
@@ -543,7 +543,7 @@ static inline void sh_eth_soft_swap(char *src, int len)
#endif
}
-static inline void sh_eth_write(struct net_device *ndev, unsigned long data,
+static inline void sh_eth_write(struct net_device *ndev, u32 data,
int enum_index)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -551,8 +551,7 @@ static inline void sh_eth_write(struct net_device *ndev, unsigned long data,
iowrite32(data, mdp->addr + mdp->reg_offset[enum_index]);
}
-static inline unsigned long sh_eth_read(struct net_device *ndev,
- int enum_index)
+static inline u32 sh_eth_read(struct net_device *ndev, int enum_index)
{
struct sh_eth_private *mdp = netdev_priv(ndev);
@@ -565,14 +564,13 @@ static inline void *sh_eth_tsu_get_offset(struct sh_eth_private *mdp,
return mdp->tsu_addr + mdp->reg_offset[enum_index];
}
-static inline void sh_eth_tsu_write(struct sh_eth_private *mdp,
- unsigned long data, int enum_index)
+static inline void sh_eth_tsu_write(struct sh_eth_private *mdp, u32 data,
+ int enum_index)
{
iowrite32(data, mdp->tsu_addr + mdp->reg_offset[enum_index]);
}
-static inline unsigned long sh_eth_tsu_read(struct sh_eth_private *mdp,
- int enum_index)
+static inline u32 sh_eth_tsu_read(struct sh_eth_private *mdp, int enum_index)
{
return ioread32(mdp->tsu_addr + mdp->reg_offset[enum_index]);
}
diff --git a/drivers/net/ethernet/rocker/rocker.c b/drivers/net/ethernet/rocker/rocker.c
index 2f398fa4b9e6..34389b6aa67c 100644
--- a/drivers/net/ethernet/rocker/rocker.c
+++ b/drivers/net/ethernet/rocker/rocker.c
@@ -806,13 +806,13 @@ static bool rocker_desc_gen(struct rocker_desc_info *desc_info)
static void *rocker_desc_cookie_ptr_get(struct rocker_desc_info *desc_info)
{
- return (void *) desc_info->desc->cookie;
+ return (void *)(uintptr_t)desc_info->desc->cookie;
}
static void rocker_desc_cookie_ptr_set(struct rocker_desc_info *desc_info,
void *ptr)
{
- desc_info->desc->cookie = (long) ptr;
+ desc_info->desc->cookie = (uintptr_t) ptr;
}
static struct rocker_desc_info *
@@ -3026,11 +3026,17 @@ static void rocker_port_fdb_learn_work(struct work_struct *work)
container_of(work, struct rocker_fdb_learn_work, work);
bool removing = (lw->flags & ROCKER_OP_FLAG_REMOVE);
bool learned = (lw->flags & ROCKER_OP_FLAG_LEARNED);
+ struct netdev_switch_notifier_fdb_info info;
+
+ info.addr = lw->addr;
+ info.vid = lw->vid;
if (learned && removing)
- br_fdb_external_learn_del(lw->dev, lw->addr, lw->vid);
+ call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_DEL,
+ lw->dev, &info.info);
else if (learned && !removing)
- br_fdb_external_learn_add(lw->dev, lw->addr, lw->vid);
+ call_netdev_switch_notifiers(NETDEV_SWITCH_FDB_ADD,
+ lw->dev, &info.info);
kfree(work);
}
@@ -3565,6 +3571,8 @@ nest_cancel:
rocker_tlv_nest_cancel(desc_info, frags);
out:
dev_kfree_skb(skb);
+ dev->stats.tx_dropped++;
+
return NETDEV_TX_OK;
}
@@ -3668,7 +3676,8 @@ static int rocker_fdb_fill_info(struct sk_buff *skb,
if (vid && nla_put_u16(skb, NDA_VLAN, vid))
goto nla_put_failure;
- return nlmsg_end(skb, nlh);
+ nlmsg_end(skb, nlh);
+ return 0;
nla_put_failure:
nlmsg_cancel(skb, nlh);
@@ -3713,7 +3722,7 @@ skip:
}
static int rocker_port_bridge_setlink(struct net_device *dev,
- struct nlmsghdr *nlh)
+ struct nlmsghdr *nlh, u16 flags)
{
struct rocker_port *rocker_port = netdev_priv(dev);
struct nlattr *protinfo;
@@ -3824,11 +3833,145 @@ static void rocker_port_get_drvinfo(struct net_device *dev,
strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
}
+static struct rocker_port_stats {
+ char str[ETH_GSTRING_LEN];
+ int type;
+} rocker_port_stats[] = {
+ { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, },
+ { "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, },
+ { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, },
+ { "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, },
+
+ { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, },
+ { "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, },
+ { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, },
+ { "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, },
+};
+
+#define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats)
+
+static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,
+ u8 *data)
+{
+ u8 *p = data;
+ int i;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
+ memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN);
+ p += ETH_GSTRING_LEN;
+ }
+ break;
+ }
+}
+
+static int
+rocker_cmd_get_port_stats_prep(struct rocker *rocker,
+ struct rocker_port *rocker_port,
+ struct rocker_desc_info *desc_info,
+ void *priv)
+{
+ struct rocker_tlv *cmd_stats;
+
+ if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
+ ROCKER_TLV_CMD_TYPE_GET_PORT_STATS))
+ return -EMSGSIZE;
+
+ cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
+ if (!cmd_stats)
+ return -EMSGSIZE;
+
+ if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_LPORT,
+ rocker_port->lport))
+ return -EMSGSIZE;
+
+ rocker_tlv_nest_end(desc_info, cmd_stats);
+
+ return 0;
+}
+
+static int
+rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker,
+ struct rocker_port *rocker_port,
+ struct rocker_desc_info *desc_info,
+ void *priv)
+{
+ struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
+ struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
+ struct rocker_tlv *pattr;
+ u32 lport;
+ u64 *data = priv;
+ int i;
+
+ rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);
+
+ if (!attrs[ROCKER_TLV_CMD_INFO])
+ return -EIO;
+
+ rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX,
+ attrs[ROCKER_TLV_CMD_INFO]);
+
+ if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT])
+ return -EIO;
+
+ lport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]);
+ if (lport != rocker_port->lport)
+ return -EIO;
+
+ for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
+ pattr = stats_attrs[rocker_port_stats[i].type];
+ if (!pattr)
+ continue;
+
+ data[i] = rocker_tlv_get_u64(pattr);
+ }
+
+ return 0;
+}
+
+static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
+ void *priv)
+{
+ return rocker_cmd_exec(rocker_port->rocker, rocker_port,
+ rocker_cmd_get_port_stats_prep, NULL,
+ rocker_cmd_get_port_stats_ethtool_proc,
+ priv, false);
+}
+
+static void rocker_port_get_stats(struct net_device *dev,
+ struct ethtool_stats *stats, u64 *data)
+{
+ struct rocker_port *rocker_port = netdev_priv(dev);
+
+ if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) {
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)
+ data[i] = 0;
+ }
+
+ return;
+}
+
+static int rocker_port_get_sset_count(struct net_device *netdev, int sset)
+{
+ switch (sset) {
+ case ETH_SS_STATS:
+ return ROCKER_PORT_STATS_LEN;
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const struct ethtool_ops rocker_port_ethtool_ops = {
.get_settings = rocker_port_get_settings,
.set_settings = rocker_port_set_settings,
.get_drvinfo = rocker_port_get_drvinfo,
.get_link = ethtool_op_get_link,
+ .get_strings = rocker_port_get_strings,
+ .get_ethtool_stats = rocker_port_get_stats,
+ .get_sset_count = rocker_port_get_sset_count,
};
/*****************
@@ -3850,12 +3993,22 @@ static int rocker_port_poll_tx(struct napi_struct *napi, int budget)
/* Cleanup tx descriptors */
while ((desc_info = rocker_desc_tail_get(&rocker_port->tx_ring))) {
+ struct sk_buff *skb;
+
err = rocker_desc_err(desc_info);
if (err && net_ratelimit())
netdev_err(rocker_port->dev, "tx desc received with err %d\n",
err);
rocker_tx_desc_frags_unmap(rocker_port, desc_info);
- dev_kfree_skb_any(rocker_desc_cookie_ptr_get(desc_info));
+
+ skb = rocker_desc_cookie_ptr_get(desc_info);
+ if (err == 0) {
+ rocker_port->dev->stats.tx_packets++;
+ rocker_port->dev->stats.tx_bytes += skb->len;
+ } else
+ rocker_port->dev->stats.tx_errors++;
+
+ dev_kfree_skb_any(skb);
credits++;
}
@@ -3888,6 +4041,10 @@ static int rocker_port_rx_proc(struct rocker *rocker,
rx_len = rocker_tlv_get_u16(attrs[ROCKER_TLV_RX_FRAG_LEN]);
skb_put(skb, rx_len);
skb->protocol = eth_type_trans(skb, rocker_port->dev);
+
+ rocker_port->dev->stats.rx_packets++;
+ rocker_port->dev->stats.rx_bytes += skb->len;
+
netif_receive_skb(skb);
return rocker_dma_rx_ring_skb_alloc(rocker, rocker_port, desc_info);
@@ -3921,6 +4078,9 @@ static int rocker_port_poll_rx(struct napi_struct *napi, int budget)
netdev_err(rocker_port->dev, "rx processing failed with err %d\n",
err);
}
+ if (err)
+ rocker_port->dev->stats.rx_errors++;
+
rocker_desc_gen_clear(desc_info);
rocker_desc_head_set(rocker, &rocker_port->rx_ring, desc_info);
credits++;
@@ -4004,7 +4164,8 @@ static int rocker_probe_port(struct rocker *rocker, unsigned int port_number)
NAPI_POLL_WEIGHT);
rocker_carrier_init(rocker_port);
- dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+ dev->features |= NETIF_F_HW_VLAN_CTAG_FILTER |
+ NETIF_F_HW_SWITCH_OFFLOAD;
err = register_netdev(dev);
if (err) {
diff --git a/drivers/net/ethernet/rocker/rocker.h b/drivers/net/ethernet/rocker/rocker.h
index 8d2865ba634c..a5bc432feada 100644
--- a/drivers/net/ethernet/rocker/rocker.h
+++ b/drivers/net/ethernet/rocker/rocker.h
@@ -127,6 +127,9 @@ enum {
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,
+ ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS,
+ ROCKER_TLV_CMD_TYPE_GET_PORT_STATS,
+
__ROCKER_TLV_CMD_TYPE_MAX,
ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
};
@@ -146,6 +149,24 @@ enum {
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
};
+enum {
+ ROCKER_TLV_CMD_PORT_STATS_UNSPEC,
+ ROCKER_TLV_CMD_PORT_STATS_LPORT, /* u32 */
+
+ ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, /* u64 */
+ ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, /* u64 */
+ ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, /* u64 */
+ ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, /* u64 */
+
+ ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, /* u64 */
+ ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, /* u64 */
+ ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, /* u64 */
+ ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, /* u64 */
+
+ __ROCKER_TLV_CMD_PORT_STATS_MAX,
+ ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1,
+};
+
enum rocker_port_mode {
ROCKER_PORT_MODE_OF_DPA,
};
diff --git a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
index b1a271853d85..c8a01ee4d25e 100644
--- a/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
+++ b/drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c
@@ -133,9 +133,8 @@ bool sxgbe_eee_init(struct sxgbe_priv_data * const priv)
return false;
priv->eee_active = 1;
- init_timer(&priv->eee_ctrl_timer);
- priv->eee_ctrl_timer.function = sxgbe_eee_ctrl_timer;
- priv->eee_ctrl_timer.data = (unsigned long)priv;
+ setup_timer(&priv->eee_ctrl_timer, sxgbe_eee_ctrl_timer,
+ (unsigned long)priv);
priv->eee_ctrl_timer.expires = SXGBE_LPI_TIMER(eee_timer);
add_timer(&priv->eee_ctrl_timer);
@@ -365,6 +364,26 @@ static int sxgbe_init_rx_buffers(struct net_device *dev,
return 0;
}
+
+/**
+ * sxgbe_free_rx_buffers - free what sxgbe_init_rx_buffers() allocated
+ * @dev: net device structure
+ * @rx_ring: ring to be freed
+ * @rx_rsize: ring size
+ * Description: this function initializes the DMA RX descriptor
+ */
+static void sxgbe_free_rx_buffers(struct net_device *dev,
+ struct sxgbe_rx_norm_desc *p, int i,
+ unsigned int dma_buf_sz,
+ struct sxgbe_rx_queue *rx_ring)
+{
+ struct sxgbe_priv_data *priv = netdev_priv(dev);
+
+ kfree_skb(rx_ring->rx_skbuff[i]);
+ dma_unmap_single(priv->device, rx_ring->rx_skbuff_dma[i],
+ dma_buf_sz, DMA_FROM_DEVICE);
+}
+
/**
* init_tx_ring - init the TX descriptor ring
* @dev: net device structure
@@ -457,7 +476,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,
/* RX ring is not allcoated */
if (rx_ring == NULL) {
netdev_err(dev, "No memory for RX queue\n");
- goto error;
+ return -ENOMEM;
}
/* assign queue number */
@@ -469,23 +488,21 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,
&rx_ring->dma_rx_phy, GFP_KERNEL);
if (rx_ring->dma_rx == NULL)
- goto error;
+ return -ENOMEM;
/* allocate memory for RX skbuff array */
rx_ring->rx_skbuff_dma = kmalloc_array(rx_rsize,
sizeof(dma_addr_t), GFP_KERNEL);
if (!rx_ring->rx_skbuff_dma) {
- dma_free_coherent(priv->device,
- rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
- rx_ring->dma_rx, rx_ring->dma_rx_phy);
- goto error;
+ ret = -ENOMEM;
+ goto err_free_dma_rx;
}
rx_ring->rx_skbuff = kmalloc_array(rx_rsize,
sizeof(struct sk_buff *), GFP_KERNEL);
if (!rx_ring->rx_skbuff) {
- kfree(rx_ring->rx_skbuff_dma);
- goto error;
+ ret = -ENOMEM;
+ goto err_free_skbuff_dma;
}
/* initialise the buffers */
@@ -495,7 +512,7 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,
ret = sxgbe_init_rx_buffers(dev, p, desc_index,
bfsize, rx_ring);
if (ret)
- goto err_init_rx_buffers;
+ goto err_free_rx_buffers;
}
/* initalise counters */
@@ -505,11 +522,22 @@ static int init_rx_ring(struct net_device *dev, u8 queue_no,
return 0;
-err_init_rx_buffers:
- while (--desc_index >= 0)
- free_rx_ring(priv->device, rx_ring, desc_index);
-error:
- return -ENOMEM;
+err_free_rx_buffers:
+ while (--desc_index >= 0) {
+ struct sxgbe_rx_norm_desc *p;
+
+ p = rx_ring->dma_rx + desc_index;
+ sxgbe_free_rx_buffers(dev, p, desc_index, bfsize, rx_ring);
+ }
+ kfree(rx_ring->rx_skbuff);
+err_free_skbuff_dma:
+ kfree(rx_ring->rx_skbuff_dma);
+err_free_dma_rx:
+ dma_free_coherent(priv->device,
+ rx_rsize * sizeof(struct sxgbe_rx_norm_desc),
+ rx_ring->dma_rx, rx_ring->dma_rx_phy);
+
+ return ret;
}
/**
* free_tx_ring - free the TX descriptor ring
@@ -1008,10 +1036,9 @@ static void sxgbe_tx_init_coalesce(struct sxgbe_priv_data *priv)
struct sxgbe_tx_queue *p = priv->txq[queue_num];
p->tx_coal_frames = SXGBE_TX_FRAMES;
p->tx_coal_timer = SXGBE_COAL_TX_TIMER;
- init_timer(&p->txtimer);
+ setup_timer(&p->txtimer, sxgbe_tx_timer,
+ (unsigned long)&priv->txq[queue_num]);
p->txtimer.expires = SXGBE_COAL_TIMER(p->tx_coal_timer);
- p->txtimer.data = (unsigned long)&priv->txq[queue_num];
- p->txtimer.function = sxgbe_tx_timer;
add_timer(&p->txtimer);
}
}
@@ -1273,7 +1300,7 @@ static netdev_tx_t sxgbe_xmit(struct sk_buff *skb, struct net_device *dev)
if (unlikely(skb_is_gso(skb) && tqueue->prev_mss != cur_mss))
ctxt_desc_req = 1;
- if (unlikely(vlan_tx_tag_present(skb) ||
+ if (unlikely(skb_vlan_tag_present(skb) ||
((skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP) &&
tqueue->hwts_tx_en)))
ctxt_desc_req = 1;
diff --git a/drivers/net/ethernet/smsc/Kconfig b/drivers/net/ethernet/smsc/Kconfig
index 9468e64e6007..3e97a8b43147 100644
--- a/drivers/net/ethernet/smsc/Kconfig
+++ b/drivers/net/ethernet/smsc/Kconfig
@@ -5,8 +5,9 @@
config NET_VENDOR_SMSC
bool "SMC (SMSC)/Western Digital devices"
default y
- depends on ARM || ISA || MAC || ARM64 || MIPS || M32R || SUPERH || \
- BLACKFIN || MN10300 || COLDFIRE || XTENSA || NIOS2 || PCI || PCMCIA
+ depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \
+ ISA || M32R || MAC || MIPS || MN10300 || NIOS2 || PCI || \
+ PCMCIA || SUPERH || XTENSA
---help---
If you have a network (Ethernet) card belonging to this class, say Y
and read the Ethernet-HOWTO, available from
@@ -38,8 +39,9 @@ config SMC91X
tristate "SMC 91C9x/91C1xxx support"
select CRC32
select MII
- depends on (ARM || M32R || SUPERH || MIPS || BLACKFIN || \
- MN10300 || COLDFIRE || ARM64 || XTENSA || NIOS2) && (!OF || GPIOLIB)
+ depends on !OF || GPIOLIB
+ depends on ARM || ARM64 || ATARI_ETHERNAT || BLACKFIN || COLDFIRE || \
+ M32R || MIPS || MN10300 || NIOS2 || SUPERH || XTENSA
---help---
This is a driver for SMC's 91x series of Ethernet chipsets,
including the SMC91C94 and the SMC91C111. Say Y if you want it
diff --git a/drivers/net/ethernet/smsc/smc91x.h b/drivers/net/ethernet/smsc/smc91x.h
index 2a38dacbbd27..be67baf5f677 100644
--- a/drivers/net/ethernet/smsc/smc91x.h
+++ b/drivers/net/ethernet/smsc/smc91x.h
@@ -216,6 +216,27 @@ SMC_outw(u16 val, void __iomem *ioaddr, int reg)
#include <unit/smc91111.h>
+#elif defined(CONFIG_ATARI)
+
+#define SMC_CAN_USE_8BIT 1
+#define SMC_CAN_USE_16BIT 1
+#define SMC_CAN_USE_32BIT 1
+#define SMC_NOWAIT 1
+
+#define SMC_inb(a, r) readb((a) + (r))
+#define SMC_inw(a, r) readw((a) + (r))
+#define SMC_inl(a, r) readl((a) + (r))
+#define SMC_outb(v, a, r) writeb(v, (a) + (r))
+#define SMC_outw(v, a, r) writew(v, (a) + (r))
+#define SMC_outl(v, a, r) writel(v, (a) + (r))
+#define SMC_insw(a, r, p, l) readsw((a) + (r), p, l)
+#define SMC_outsw(a, r, p, l) writesw((a) + (r), p, l)
+#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
+#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
+
+#define RPC_LSA_DEFAULT RPC_LED_100_10
+#define RPC_LSB_DEFAULT RPC_LED_TX_RX
+
#elif defined(CONFIG_ARCH_MSM)
#define SMC_CAN_USE_8BIT 0
diff --git a/drivers/net/ethernet/stmicro/stmmac/Makefile b/drivers/net/ethernet/stmicro/stmmac/Makefile
index ac4d5629d905..73c2715a27f3 100644
--- a/drivers/net/ethernet/stmicro/stmmac/Makefile
+++ b/drivers/net/ethernet/stmicro/stmmac/Makefile
@@ -6,7 +6,7 @@ stmmac-objs:= stmmac_main.o stmmac_ethtool.o stmmac_mdio.o ring_mode.o \
obj-$(CONFIG_STMMAC_PLATFORM) += stmmac-platform.o
stmmac-platform-objs:= stmmac_platform.o dwmac-meson.o dwmac-sunxi.o \
- dwmac-sti.o dwmac-socfpga.o
+ dwmac-sti.o dwmac-socfpga.o dwmac-rk.o
obj-$(CONFIG_STMMAC_PCI) += stmmac-pci.o
stmmac-pci-objs:= stmmac_pci.o
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
new file mode 100644
index 000000000000..6249a4ec08f0
--- /dev/null
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-rk.c
@@ -0,0 +1,437 @@
+/**
+ * dwmac-rk.c - Rockchip RK3288 DWMAC specific glue layer
+ *
+ * Copyright (C) 2014 Chen-Zhi (Roger Chen)
+ *
+ * Chen-Zhi (Roger Chen) <roger.chen@rock-chips.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/stmmac.h>
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/phy.h>
+#include <linux/of_net.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/of_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/delay.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+struct rk_priv_data {
+ struct platform_device *pdev;
+ int phy_iface;
+ struct regulator *regulator;
+
+ bool clk_enabled;
+ bool clock_input;
+
+ struct clk *clk_mac;
+ struct clk *clk_mac_pll;
+ struct clk *gmac_clkin;
+ struct clk *mac_clk_rx;
+ struct clk *mac_clk_tx;
+ struct clk *clk_mac_ref;
+ struct clk *clk_mac_refout;
+ struct clk *aclk_mac;
+ struct clk *pclk_mac;
+
+ int tx_delay;
+ int rx_delay;
+
+ struct regmap *grf;
+};
+
+#define HIWORD_UPDATE(val, mask, shift) \
+ ((val) << (shift) | (mask) << ((shift) + 16))
+
+#define GRF_BIT(nr) (BIT(nr) | BIT(nr+16))
+#define GRF_CLR_BIT(nr) (BIT(nr+16))
+
+#define RK3288_GRF_SOC_CON1 0x0248
+#define RK3288_GRF_SOC_CON3 0x0250
+#define RK3288_GRF_GPIO3D_E 0x01ec
+#define RK3288_GRF_GPIO4A_E 0x01f0
+#define RK3288_GRF_GPIO4B_E 0x01f4
+
+/*RK3288_GRF_SOC_CON1*/
+#define GMAC_PHY_INTF_SEL_RGMII (GRF_BIT(6) | GRF_CLR_BIT(7) | GRF_CLR_BIT(8))
+#define GMAC_PHY_INTF_SEL_RMII (GRF_CLR_BIT(6) | GRF_CLR_BIT(7) | GRF_BIT(8))
+#define GMAC_FLOW_CTRL GRF_BIT(9)
+#define GMAC_FLOW_CTRL_CLR GRF_CLR_BIT(9)
+#define GMAC_SPEED_10M GRF_CLR_BIT(10)
+#define GMAC_SPEED_100M GRF_BIT(10)
+#define GMAC_RMII_CLK_25M GRF_BIT(11)
+#define GMAC_RMII_CLK_2_5M GRF_CLR_BIT(11)
+#define GMAC_CLK_125M (GRF_CLR_BIT(12) | GRF_CLR_BIT(13))
+#define GMAC_CLK_25M (GRF_BIT(12) | GRF_BIT(13))
+#define GMAC_CLK_2_5M (GRF_CLR_BIT(12) | GRF_BIT(13))
+#define GMAC_RMII_MODE GRF_BIT(14)
+#define GMAC_RMII_MODE_CLR GRF_CLR_BIT(14)
+
+/*RK3288_GRF_SOC_CON3*/
+#define GMAC_TXCLK_DLY_ENABLE GRF_BIT(14)
+#define GMAC_TXCLK_DLY_DISABLE GRF_CLR_BIT(14)
+#define GMAC_RXCLK_DLY_ENABLE GRF_BIT(15)
+#define GMAC_RXCLK_DLY_DISABLE GRF_CLR_BIT(15)
+#define GMAC_CLK_RX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 7)
+#define GMAC_CLK_TX_DL_CFG(val) HIWORD_UPDATE(val, 0x7F, 0)
+
+static void set_to_rgmii(struct rk_priv_data *bsp_priv,
+ int tx_delay, int rx_delay)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ GMAC_PHY_INTF_SEL_RGMII | GMAC_RMII_MODE_CLR);
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON3,
+ GMAC_RXCLK_DLY_ENABLE | GMAC_TXCLK_DLY_ENABLE |
+ GMAC_CLK_RX_DL_CFG(rx_delay) |
+ GMAC_CLK_TX_DL_CFG(tx_delay));
+}
+
+static void set_to_rmii(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ GMAC_PHY_INTF_SEL_RMII | GMAC_RMII_MODE);
+}
+
+static void set_rgmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10)
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_2_5M);
+ else if (speed == 100)
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_25M);
+ else if (speed == 1000)
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1, GMAC_CLK_125M);
+ else
+ dev_err(dev, "unknown speed value for RGMII! speed=%d", speed);
+}
+
+static void set_rmii_speed(struct rk_priv_data *bsp_priv, int speed)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (IS_ERR(bsp_priv->grf)) {
+ dev_err(dev, "%s: Missing rockchip,grf property\n", __func__);
+ return;
+ }
+
+ if (speed == 10) {
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ GMAC_RMII_CLK_2_5M | GMAC_SPEED_10M);
+ } else if (speed == 100) {
+ regmap_write(bsp_priv->grf, RK3288_GRF_SOC_CON1,
+ GMAC_RMII_CLK_25M | GMAC_SPEED_100M);
+ } else {
+ dev_err(dev, "unknown speed value for RMII! speed=%d", speed);
+ }
+}
+
+static int gmac_clk_init(struct rk_priv_data *bsp_priv)
+{
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ bsp_priv->clk_enabled = false;
+
+ bsp_priv->mac_clk_rx = devm_clk_get(dev, "mac_clk_rx");
+ if (IS_ERR(bsp_priv->mac_clk_rx))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "mac_clk_rx");
+
+ bsp_priv->mac_clk_tx = devm_clk_get(dev, "mac_clk_tx");
+ if (IS_ERR(bsp_priv->mac_clk_tx))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "mac_clk_tx");
+
+ bsp_priv->aclk_mac = devm_clk_get(dev, "aclk_mac");
+ if (IS_ERR(bsp_priv->aclk_mac))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "aclk_mac");
+
+ bsp_priv->pclk_mac = devm_clk_get(dev, "pclk_mac");
+ if (IS_ERR(bsp_priv->pclk_mac))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "pclk_mac");
+
+ bsp_priv->clk_mac = devm_clk_get(dev, "stmmaceth");
+ if (IS_ERR(bsp_priv->clk_mac))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "stmmaceth");
+
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+ bsp_priv->clk_mac_ref = devm_clk_get(dev, "clk_mac_ref");
+ if (IS_ERR(bsp_priv->clk_mac_ref))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "clk_mac_ref");
+
+ if (!bsp_priv->clock_input) {
+ bsp_priv->clk_mac_refout =
+ devm_clk_get(dev, "clk_mac_refout");
+ if (IS_ERR(bsp_priv->clk_mac_refout))
+ dev_err(dev, "%s: cannot get clock %s\n",
+ __func__, "clk_mac_refout");
+ }
+ }
+
+ if (bsp_priv->clock_input) {
+ dev_info(dev, "%s: clock input from PHY\n", __func__);
+ } else {
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+ clk_set_rate(bsp_priv->clk_mac_pll, 50000000);
+ }
+
+ return 0;
+}
+
+static int gmac_clk_enable(struct rk_priv_data *bsp_priv, bool enable)
+{
+ int phy_iface = phy_iface = bsp_priv->phy_iface;
+
+ if (enable) {
+ if (!bsp_priv->clk_enabled) {
+ if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+ if (!IS_ERR(bsp_priv->mac_clk_rx))
+ clk_prepare_enable(
+ bsp_priv->mac_clk_rx);
+
+ if (!IS_ERR(bsp_priv->clk_mac_ref))
+ clk_prepare_enable(
+ bsp_priv->clk_mac_ref);
+
+ if (!IS_ERR(bsp_priv->clk_mac_refout))
+ clk_prepare_enable(
+ bsp_priv->clk_mac_refout);
+ }
+
+ if (!IS_ERR(bsp_priv->aclk_mac))
+ clk_prepare_enable(bsp_priv->aclk_mac);
+
+ if (!IS_ERR(bsp_priv->pclk_mac))
+ clk_prepare_enable(bsp_priv->pclk_mac);
+
+ if (!IS_ERR(bsp_priv->mac_clk_tx))
+ clk_prepare_enable(bsp_priv->mac_clk_tx);
+
+ /**
+ * if (!IS_ERR(bsp_priv->clk_mac))
+ * clk_prepare_enable(bsp_priv->clk_mac);
+ */
+ mdelay(5);
+ bsp_priv->clk_enabled = true;
+ }
+ } else {
+ if (bsp_priv->clk_enabled) {
+ if (phy_iface == PHY_INTERFACE_MODE_RMII) {
+ if (!IS_ERR(bsp_priv->mac_clk_rx))
+ clk_disable_unprepare(
+ bsp_priv->mac_clk_rx);
+
+ if (!IS_ERR(bsp_priv->clk_mac_ref))
+ clk_disable_unprepare(
+ bsp_priv->clk_mac_ref);
+
+ if (!IS_ERR(bsp_priv->clk_mac_refout))
+ clk_disable_unprepare(
+ bsp_priv->clk_mac_refout);
+ }
+
+ if (!IS_ERR(bsp_priv->aclk_mac))
+ clk_disable_unprepare(bsp_priv->aclk_mac);
+
+ if (!IS_ERR(bsp_priv->pclk_mac))
+ clk_disable_unprepare(bsp_priv->pclk_mac);
+
+ if (!IS_ERR(bsp_priv->mac_clk_tx))
+ clk_disable_unprepare(bsp_priv->mac_clk_tx);
+ /**
+ * if (!IS_ERR(bsp_priv->clk_mac))
+ * clk_disable_unprepare(bsp_priv->clk_mac);
+ */
+ bsp_priv->clk_enabled = false;
+ }
+ }
+
+ return 0;
+}
+
+static int phy_power_on(struct rk_priv_data *bsp_priv, bool enable)
+{
+ struct regulator *ldo = bsp_priv->regulator;
+ int ret;
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (!ldo) {
+ dev_err(dev, "%s: no regulator found\n", __func__);
+ return -1;
+ }
+
+ if (enable) {
+ ret = regulator_enable(ldo);
+ if (ret)
+ dev_err(dev, "%s: fail to enable phy-supply\n",
+ __func__);
+ } else {
+ ret = regulator_disable(ldo);
+ if (ret)
+ dev_err(dev, "%s: fail to disable phy-supply\n",
+ __func__);
+ }
+
+ return 0;
+}
+
+static void *rk_gmac_setup(struct platform_device *pdev)
+{
+ struct rk_priv_data *bsp_priv;
+ struct device *dev = &pdev->dev;
+ int ret;
+ const char *strings = NULL;
+ int value;
+
+ bsp_priv = devm_kzalloc(dev, sizeof(*bsp_priv), GFP_KERNEL);
+ if (!bsp_priv)
+ return ERR_PTR(-ENOMEM);
+
+ bsp_priv->phy_iface = of_get_phy_mode(dev->of_node);
+
+ bsp_priv->regulator = devm_regulator_get_optional(dev, "phy");
+ if (IS_ERR(bsp_priv->regulator)) {
+ if (PTR_ERR(bsp_priv->regulator) == -EPROBE_DEFER) {
+ dev_err(dev, "phy regulator is not available yet, deferred probing\n");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+ dev_err(dev, "no regulator found\n");
+ bsp_priv->regulator = NULL;
+ }
+
+ ret = of_property_read_string(dev->of_node, "clock_in_out", &strings);
+ if (ret) {
+ dev_err(dev, "%s: Can not read property: clock_in_out.\n",
+ __func__);
+ bsp_priv->clock_input = true;
+ } else {
+ dev_info(dev, "%s: clock input or output? (%s).\n",
+ __func__, strings);
+ if (!strcmp(strings, "input"))
+ bsp_priv->clock_input = true;
+ else
+ bsp_priv->clock_input = false;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "tx_delay", &value);
+ if (ret) {
+ bsp_priv->tx_delay = 0x30;
+ dev_err(dev, "%s: Can not read property: tx_delay.", __func__);
+ dev_err(dev, "%s: set tx_delay to 0x%x\n",
+ __func__, bsp_priv->tx_delay);
+ } else {
+ dev_info(dev, "%s: TX delay(0x%x).\n", __func__, value);
+ bsp_priv->tx_delay = value;
+ }
+
+ ret = of_property_read_u32(dev->of_node, "rx_delay", &value);
+ if (ret) {
+ bsp_priv->rx_delay = 0x10;
+ dev_err(dev, "%s: Can not read property: rx_delay.", __func__);
+ dev_err(dev, "%s: set rx_delay to 0x%x\n",
+ __func__, bsp_priv->rx_delay);
+ } else {
+ dev_info(dev, "%s: RX delay(0x%x).\n", __func__, value);
+ bsp_priv->rx_delay = value;
+ }
+
+ bsp_priv->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+ "rockchip,grf");
+ bsp_priv->pdev = pdev;
+
+ /*rmii or rgmii*/
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII) {
+ dev_info(dev, "%s: init for RGMII\n", __func__);
+ set_to_rgmii(bsp_priv, bsp_priv->tx_delay, bsp_priv->rx_delay);
+ } else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII) {
+ dev_info(dev, "%s: init for RMII\n", __func__);
+ set_to_rmii(bsp_priv);
+ } else {
+ dev_err(dev, "%s: NO interface defined!\n", __func__);
+ }
+
+ gmac_clk_init(bsp_priv);
+
+ return bsp_priv;
+}
+
+static int rk_gmac_init(struct platform_device *pdev, void *priv)
+{
+ struct rk_priv_data *bsp_priv = priv;
+ int ret;
+
+ ret = phy_power_on(bsp_priv, true);
+ if (ret)
+ return ret;
+
+ ret = gmac_clk_enable(bsp_priv, true);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static void rk_gmac_exit(struct platform_device *pdev, void *priv)
+{
+ struct rk_priv_data *gmac = priv;
+
+ phy_power_on(gmac, false);
+ gmac_clk_enable(gmac, false);
+}
+
+static void rk_fix_speed(void *priv, unsigned int speed)
+{
+ struct rk_priv_data *bsp_priv = priv;
+ struct device *dev = &bsp_priv->pdev->dev;
+
+ if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RGMII)
+ set_rgmii_speed(bsp_priv, speed);
+ else if (bsp_priv->phy_iface == PHY_INTERFACE_MODE_RMII)
+ set_rmii_speed(bsp_priv, speed);
+ else
+ dev_err(dev, "unsupported interface %d", bsp_priv->phy_iface);
+}
+
+const struct stmmac_of_data rk3288_gmac_data = {
+ .has_gmac = 1,
+ .fix_mac_speed = rk_fix_speed,
+ .setup = rk_gmac_setup,
+ .init = rk_gmac_init,
+ .exit = rk_gmac_exit,
+};
diff --git a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
index 056b358b4a72..bb6e2dc61bec 100644
--- a/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
+++ b/drivers/net/ethernet/stmicro/stmmac/dwmac-sti.c
@@ -122,7 +122,7 @@ struct sti_dwmac {
bool ext_phyclk; /* Clock from external PHY */
u32 tx_retime_src; /* TXCLK Retiming*/
struct clk *clk; /* PHY clock */
- int ctrl_reg; /* GMAC glue-logic control register */
+ u32 ctrl_reg; /* GMAC glue-logic control register */
int clk_sel_reg; /* GMAC ext clk selection register */
struct device *dev;
struct regmap *regmap;
@@ -285,11 +285,6 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
if (!np)
return -EINVAL;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-ethconf");
- if (!res)
- return -ENODATA;
- dwmac->ctrl_reg = res->start;
-
/* clk selection from extra syscfg register */
dwmac->clk_sel_reg = -ENXIO;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "sti-clkconf");
@@ -300,6 +295,12 @@ static int sti_dwmac_parse_data(struct sti_dwmac *dwmac,
if (IS_ERR(regmap))
return PTR_ERR(regmap);
+ err = of_property_read_u32_index(np, "st,syscon", 1, &dwmac->ctrl_reg);
+ if (err) {
+ dev_err(dev, "Can't get sysconfig ctrl offset (%d)\n", err);
+ return err;
+ }
+
dwmac->dev = dev;
dwmac->interface = of_get_phy_mode(np);
dwmac->regmap = regmap;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
index cf62ff4c8c56..55e89b3838f1 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_main.c
@@ -1097,6 +1097,7 @@ static int init_dma_desc_rings(struct net_device *dev, gfp_t flags)
priv->dirty_tx = 0;
priv->cur_tx = 0;
+ netdev_reset_queue(priv->dev);
stmmac_clear_descriptors(priv);
@@ -1287,7 +1288,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
* that needs to not insert csum in the TDES.
*/
priv->hw->dma->dma_mode(priv->ioaddr, SF_DMA_MODE, SF_DMA_MODE);
- tc = SF_DMA_MODE;
+ priv->xstats.threshold = SF_DMA_MODE;
} else
priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
}
@@ -1300,6 +1301,7 @@ static void stmmac_dma_operation_mode(struct stmmac_priv *priv)
static void stmmac_tx_clean(struct stmmac_priv *priv)
{
unsigned int txsize = priv->dma_tx_size;
+ unsigned int bytes_compl = 0, pkts_compl = 0;
spin_lock(&priv->tx_lock);
@@ -1356,6 +1358,8 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
priv->hw->mode->clean_desc3(priv, p);
if (likely(skb != NULL)) {
+ pkts_compl++;
+ bytes_compl += skb->len;
dev_consume_skb_any(skb);
priv->tx_skbuff[entry] = NULL;
}
@@ -1364,6 +1368,9 @@ static void stmmac_tx_clean(struct stmmac_priv *priv)
priv->dirty_tx++;
}
+
+ netdev_completed_queue(priv->dev, pkts_compl, bytes_compl);
+
if (unlikely(netif_queue_stopped(priv->dev) &&
stmmac_tx_avail(priv) > STMMAC_TX_THRESH(priv))) {
netif_tx_lock(priv->dev);
@@ -1418,6 +1425,7 @@ static void stmmac_tx_err(struct stmmac_priv *priv)
(i == txsize - 1));
priv->dirty_tx = 0;
priv->cur_tx = 0;
+ netdev_reset_queue(priv->dev);
priv->hw->dma->start_tx(priv->ioaddr);
priv->dev->stats.tx_errors++;
@@ -1444,9 +1452,14 @@ static void stmmac_dma_interrupt(struct stmmac_priv *priv)
}
if (unlikely(status & tx_hard_error_bump_tc)) {
/* Try to bump up the dma threshold on this failure */
- if (unlikely(tc != SF_DMA_MODE) && (tc <= 256)) {
+ if (unlikely(priv->xstats.threshold != SF_DMA_MODE) &&
+ (tc <= 256)) {
tc += 64;
- priv->hw->dma->dma_mode(priv->ioaddr, tc, SF_DMA_MODE);
+ if (priv->plat->force_thresh_dma_mode)
+ priv->hw->dma->dma_mode(priv->ioaddr, tc, tc);
+ else
+ priv->hw->dma->dma_mode(priv->ioaddr, tc,
+ SF_DMA_MODE);
priv->xstats.threshold = tc;
}
} else if (unlikely(status == tx_hard_error))
@@ -2050,6 +2063,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
if (!priv->hwts_tx_en)
skb_tx_timestamp(skb);
+ netdev_sent_queue(dev, skb->len);
priv->hw->dma->enable_dma_transmission(priv->ioaddr);
spin_unlock(&priv->tx_lock);
@@ -2742,7 +2756,11 @@ static int stmmac_hw_init(struct stmmac_priv *priv)
priv->plat->enh_desc = priv->dma_cap.enh_desc;
priv->plat->pmt = priv->dma_cap.pmt_remote_wake_up;
- priv->plat->tx_coe = priv->dma_cap.tx_coe;
+ /* TXCOE doesn't work in thresh DMA mode */
+ if (priv->plat->force_thresh_dma_mode)
+ priv->plat->tx_coe = 0;
+ else
+ priv->plat->tx_coe = priv->dma_cap.tx_coe;
if (priv->dma_cap.rx_coe_type2)
priv->plat->rx_coe = STMMAC_RX_COE_TYPE2;
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
index 054520d67de4..3bca908716e2 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_pci.c
@@ -24,8 +24,50 @@
*******************************************************************************/
#include <linux/pci.h>
+#include <linux/dmi.h>
+
#include "stmmac.h"
+/*
+ * This struct is used to associate PCI Function of MAC controller on a board,
+ * discovered via DMI, with the address of PHY connected to the MAC. The
+ * negative value of the address means that MAC controller is not connected
+ * with PHY.
+ */
+struct stmmac_pci_dmi_data {
+ const char *name;
+ unsigned int func;
+ int phy_addr;
+};
+
+struct stmmac_pci_info {
+ struct pci_dev *pdev;
+ int (*setup)(struct plat_stmmacenet_data *plat,
+ struct stmmac_pci_info *info);
+ struct stmmac_pci_dmi_data *dmi;
+};
+
+static int stmmac_pci_find_phy_addr(struct stmmac_pci_info *info)
+{
+ const char *name = dmi_get_system_info(DMI_BOARD_NAME);
+ unsigned int func = PCI_FUNC(info->pdev->devfn);
+ struct stmmac_pci_dmi_data *dmi;
+
+ /*
+ * Galileo boards with old firmware don't support DMI. We always return
+ * 1 here, so at least first found MAC controller would be probed.
+ */
+ if (!name)
+ return 1;
+
+ for (dmi = info->dmi; dmi->name && *dmi->name; dmi++) {
+ if (!strcmp(dmi->name, name) && dmi->func == func)
+ return dmi->phy_addr;
+ }
+
+ return -ENODEV;
+}
+
static void stmmac_default_data(struct plat_stmmacenet_data *plat)
{
plat->bus_id = 1;
@@ -48,6 +90,62 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
plat->unicast_filter_entries = 1;
}
+static int quark_default_data(struct plat_stmmacenet_data *plat,
+ struct stmmac_pci_info *info)
+{
+ struct pci_dev *pdev = info->pdev;
+ int ret;
+
+ /*
+ * Refuse to load the driver and register net device if MAC controller
+ * does not connect to any PHY interface.
+ */
+ ret = stmmac_pci_find_phy_addr(info);
+ if (ret < 0)
+ return ret;
+
+ plat->bus_id = PCI_DEVID(pdev->bus->number, pdev->devfn);
+ plat->phy_addr = ret;
+ plat->interface = PHY_INTERFACE_MODE_RMII;
+ plat->clk_csr = 2;
+ plat->has_gmac = 1;
+ plat->force_sf_dma_mode = 1;
+
+ plat->mdio_bus_data->phy_reset = NULL;
+ plat->mdio_bus_data->phy_mask = 0;
+
+ plat->dma_cfg->pbl = 16;
+ plat->dma_cfg->burst_len = DMA_AXI_BLEN_256;
+ plat->dma_cfg->fixed_burst = 1;
+
+ /* Set default value for multicast hash bins */
+ plat->multicast_filter_bins = HASH_TABLE_SIZE;
+
+ /* Set default value for unicast filter entries */
+ plat->unicast_filter_entries = 1;
+
+ return 0;
+}
+
+static struct stmmac_pci_dmi_data quark_pci_dmi_data[] = {
+ {
+ .name = "Galileo",
+ .func = 6,
+ .phy_addr = 1,
+ },
+ {
+ .name = "GalileoGen2",
+ .func = 6,
+ .phy_addr = 1,
+ },
+ {}
+};
+
+static struct stmmac_pci_info quark_pci_info = {
+ .setup = quark_default_data,
+ .dmi = quark_pci_dmi_data,
+};
+
/**
* stmmac_pci_probe
*
@@ -63,6 +161,7 @@ static void stmmac_default_data(struct plat_stmmacenet_data *plat)
static int stmmac_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
+ struct stmmac_pci_info *info = (struct stmmac_pci_info *)id->driver_data;
struct plat_stmmacenet_data *plat;
struct stmmac_priv *priv;
int i;
@@ -103,7 +202,17 @@ static int stmmac_pci_probe(struct pci_dev *pdev,
pci_set_master(pdev);
- stmmac_default_data(plat);
+ if (info) {
+ info->pdev = pdev;
+ if (info->setup) {
+ ret = info->setup(plat, info);
+ if (ret)
+ return ret;
+ }
+ } else
+ stmmac_default_data(plat);
+
+ pci_enable_msi(pdev);
priv = stmmac_dvr_probe(&pdev->dev, plat, pcim_iomap_table(pdev)[i]);
if (IS_ERR(priv)) {
@@ -155,11 +264,13 @@ static int stmmac_pci_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(stmmac_pm_ops, stmmac_pci_suspend, stmmac_pci_resume);
#define STMMAC_VENDOR_ID 0x700
+#define STMMAC_QUARK_ID 0x0937
#define STMMAC_DEVICE_ID 0x1108
static const struct pci_device_id stmmac_id_table[] = {
{PCI_DEVICE(STMMAC_VENDOR_ID, STMMAC_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_STMICRO, PCI_DEVICE_ID_STMICRO_MAC)},
+ {PCI_VDEVICE(INTEL, STMMAC_QUARK_ID), (kernel_ulong_t)&quark_pci_info},
{}
};
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
index 3039de2465ba..fb846ebba1d9 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.c
@@ -33,6 +33,7 @@
static const struct of_device_id stmmac_dt_ids[] = {
/* SoC specific glue layers should come before generic bindings */
+ { .compatible = "rockchip,rk3288-gmac", .data = &rk3288_gmac_data},
{ .compatible = "amlogic,meson6-dwmac", .data = &meson6_dwmac_data},
{ .compatible = "allwinner,sun7i-a20-gmac", .data = &sun7i_gmac_data},
{ .compatible = "st,stih415-dwmac", .data = &stih4xx_dwmac_data},
@@ -234,6 +235,9 @@ static int stmmac_probe_config_dt(struct platform_device *pdev,
of_property_read_bool(np, "snps,fixed-burst");
dma_cfg->mixed_burst =
of_property_read_bool(np, "snps,mixed-burst");
+ of_property_read_u32(np, "snps,burst_len", &dma_cfg->burst_len);
+ if (dma_cfg->burst_len < 0 || dma_cfg->burst_len > 256)
+ dma_cfg->burst_len = 0;
}
plat->force_thresh_dma_mode = of_property_read_bool(np, "snps,force_thresh_dma_mode");
if (plat->force_thresh_dma_mode) {
diff --git a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
index 25dd1f7ace02..093eb99e5ffd 100644
--- a/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
+++ b/drivers/net/ethernet/stmicro/stmmac/stmmac_platform.h
@@ -24,5 +24,6 @@ extern const struct stmmac_of_data sun7i_gmac_data;
extern const struct stmmac_of_data stih4xx_dwmac_data;
extern const struct stmmac_of_data stid127_dwmac_data;
extern const struct stmmac_of_data socfpga_gmac_data;
+extern const struct stmmac_of_data rk3288_gmac_data;
#endif /* __STMMAC_PLATFORM_H__ */
diff --git a/drivers/net/ethernet/sun/niu.c b/drivers/net/ethernet/sun/niu.c
index 0c6416213837..4b51f903fb73 100644
--- a/drivers/net/ethernet/sun/niu.c
+++ b/drivers/net/ethernet/sun/niu.c
@@ -3341,8 +3341,7 @@ static int niu_rbr_add_page(struct niu *np, struct rx_ring_info *rp,
niu_hash_page(rp, page, addr);
if (rp->rbr_blocks_per_page > 1)
- atomic_add(rp->rbr_blocks_per_page - 1,
- &compound_head(page)->_count);
+ atomic_add(rp->rbr_blocks_per_page - 1, &page->_count);
for (i = 0; i < rp->rbr_blocks_per_page; i++) {
__le32 *rbr = &rp->rbr[start_index + i];
diff --git a/drivers/net/ethernet/sun/sunvnet.c b/drivers/net/ethernet/sun/sunvnet.c
index d2835bf7b4fb..22e0cad1b4b5 100644
--- a/drivers/net/ethernet/sun/sunvnet.c
+++ b/drivers/net/ethernet/sun/sunvnet.c
@@ -50,6 +50,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
#define VNET_MAX_RETRIES 10
static int __vnet_tx_trigger(struct vnet_port *port, u32 start);
+static void vnet_port_reset(struct vnet_port *port);
/* Ordered from largest major to lowest */
static struct vio_version vnet_versions[] = {
@@ -351,10 +352,15 @@ static int vnet_rx_one(struct vnet_port *port, struct vio_net_desc *desc)
unsigned int len = desc->size;
unsigned int copy_len;
struct sk_buff *skb;
+ int maxlen;
int err;
err = -EMSGSIZE;
- if (unlikely(len < ETH_ZLEN || len > port->rmtu)) {
+ if (port->tso && port->tsolen > port->rmtu)
+ maxlen = port->tsolen;
+ else
+ maxlen = port->rmtu;
+ if (unlikely(len < ETH_ZLEN || len > maxlen)) {
dev->stats.rx_length_errors++;
goto out_dropped;
}
@@ -731,9 +737,7 @@ ldc_ctrl:
vio_link_state_change(vio, event);
if (event == LDC_EVENT_RESET) {
- port->rmtu = 0;
- port->tso = true;
- port->tsolen = 0;
+ vnet_port_reset(port);
vio_port_up(vio);
}
port->rx_event = 0;
@@ -929,36 +933,36 @@ static struct sk_buff *vnet_clean_tx_ring(struct vnet_port *port,
*pending = 0;
- txi = dr->prod-1;
- if (txi < 0)
- txi = VNET_TX_RING_SIZE-1;
-
+ txi = dr->prod;
for (i = 0; i < VNET_TX_RING_SIZE; ++i) {
struct vio_net_desc *d;
- d = vio_dring_entry(dr, txi);
-
- if (d->hdr.state == VIO_DESC_DONE) {
- if (port->tx_bufs[txi].skb) {
- BUG_ON(port->tx_bufs[txi].skb->next);
+ --txi;
+ if (txi < 0)
+ txi = VNET_TX_RING_SIZE-1;
- port->tx_bufs[txi].skb->next = skb;
- skb = port->tx_bufs[txi].skb;
- port->tx_bufs[txi].skb = NULL;
+ d = vio_dring_entry(dr, txi);
- ldc_unmap(port->vio.lp,
- port->tx_bufs[txi].cookies,
- port->tx_bufs[txi].ncookies);
- }
- d->hdr.state = VIO_DESC_FREE;
- } else if (d->hdr.state == VIO_DESC_READY) {
+ if (d->hdr.state == VIO_DESC_READY) {
(*pending)++;
- } else if (d->hdr.state == VIO_DESC_FREE) {
- break;
+ continue;
}
- --txi;
- if (txi < 0)
- txi = VNET_TX_RING_SIZE-1;
+ if (port->tx_bufs[txi].skb) {
+ if (d->hdr.state != VIO_DESC_DONE)
+ pr_notice("invalid ring buffer state %d\n",
+ d->hdr.state);
+ BUG_ON(port->tx_bufs[txi].skb->next);
+
+ port->tx_bufs[txi].skb->next = skb;
+ skb = port->tx_bufs[txi].skb;
+ port->tx_bufs[txi].skb = NULL;
+
+ ldc_unmap(port->vio.lp,
+ port->tx_bufs[txi].cookies,
+ port->tx_bufs[txi].ncookies);
+ } else if (d->hdr.state == VIO_DESC_FREE)
+ break;
+ d->hdr.state = VIO_DESC_FREE;
}
return skb;
}
@@ -1119,6 +1123,7 @@ static inline struct sk_buff *vnet_skb_shape(struct sk_buff *skb, int ncookies)
skb_shinfo(nskb)->gso_size = skb_shinfo(skb)->gso_size;
skb_shinfo(nskb)->gso_type = skb_shinfo(skb)->gso_type;
}
+ nskb->queue_mapping = skb->queue_mapping;
dev_kfree_skb(skb);
skb = nskb;
}
@@ -1187,23 +1192,16 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb)
skb_pull(skb, maclen);
if (port->tso && gso_size < datalen) {
+ if (skb_unclone(skb, GFP_ATOMIC))
+ goto out_dropped;
+
/* segment to TSO size */
skb_shinfo(skb)->gso_size = datalen;
skb_shinfo(skb)->gso_segs = gso_segs;
-
- segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
-
- /* restore gso_size & gso_segs */
- skb_shinfo(skb)->gso_size = gso_size;
- skb_shinfo(skb)->gso_segs = DIV_ROUND_UP(skb->len - hlen,
- gso_size);
- } else
- segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
- if (IS_ERR(segs)) {
- dev->stats.tx_dropped++;
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
}
+ segs = skb_gso_segment(skb, dev->features & ~NETIF_F_TSO);
+ if (IS_ERR(segs))
+ goto out_dropped;
skb_push(skb, maclen);
skb_reset_mac_header(skb);
@@ -1241,6 +1239,10 @@ static int vnet_handle_offloads(struct vnet_port *port, struct sk_buff *skb)
if (!(status & NETDEV_TX_MASK))
dev_kfree_skb_any(skb);
return status;
+out_dropped:
+ dev->stats.tx_dropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
}
static int vnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -1632,16 +1634,9 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port)
int i;
dr = &port->vio.drings[VIO_DRIVER_TX_RING];
- if (dr->base) {
- ldc_free_exp_dring(port->vio.lp, dr->base,
- (dr->entry_size * dr->num_entries),
- dr->cookies, dr->ncookies);
- dr->base = NULL;
- dr->entry_size = 0;
- dr->num_entries = 0;
- dr->pending = 0;
- dr->ncookies = 0;
- }
+
+ if (dr->base == NULL)
+ return;
for (i = 0; i < VNET_TX_RING_SIZE; i++) {
struct vio_net_desc *d;
@@ -1651,8 +1646,6 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port)
continue;
d = vio_dring_entry(dr, i);
- if (d->hdr.state == VIO_DESC_READY)
- pr_warn("active transmit buffers freed\n");
ldc_unmap(port->vio.lp,
port->tx_bufs[i].cookies,
@@ -1661,6 +1654,23 @@ static void vnet_port_free_tx_bufs(struct vnet_port *port)
port->tx_bufs[i].skb = NULL;
d->hdr.state = VIO_DESC_FREE;
}
+ ldc_free_exp_dring(port->vio.lp, dr->base,
+ (dr->entry_size * dr->num_entries),
+ dr->cookies, dr->ncookies);
+ dr->base = NULL;
+ dr->entry_size = 0;
+ dr->num_entries = 0;
+ dr->pending = 0;
+ dr->ncookies = 0;
+}
+
+static void vnet_port_reset(struct vnet_port *port)
+{
+ del_timer(&port->clean_timer);
+ vnet_port_free_tx_bufs(port);
+ port->rmtu = 0;
+ port->tso = true;
+ port->tsolen = 0;
}
static int vnet_port_alloc_tx_ring(struct vnet_port *port)
diff --git a/drivers/net/ethernet/tehuti/tehuti.c b/drivers/net/ethernet/tehuti/tehuti.c
index 6ab36d9ff2ab..a9cac8413e49 100644
--- a/drivers/net/ethernet/tehuti/tehuti.c
+++ b/drivers/net/ethernet/tehuti/tehuti.c
@@ -1650,9 +1650,9 @@ static netdev_tx_t bdx_tx_transmit(struct sk_buff *skb,
txd_mss);
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
/*Cut VLAN ID to 12 bits */
- txd_vlan_id = vlan_tx_tag_get(skb) & BITS_MASK(12);
+ txd_vlan_id = skb_vlan_tag_get(skb) & BITS_MASK(12);
txd_vtag = 1;
}
diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig
index 605dd909bcc3..f6a71092e135 100644
--- a/drivers/net/ethernet/ti/Kconfig
+++ b/drivers/net/ethernet/ti/Kconfig
@@ -50,18 +50,24 @@ config TI_DAVINCI_CPDMA
will be called davinci_cpdma. This is recommended.
config TI_CPSW_PHY_SEL
- boolean "TI CPSW Switch Phy sel Support"
+ bool "TI CPSW Switch Phy sel Support"
depends on TI_CPSW
---help---
This driver supports configuring of the phy mode connected to
the CPSW.
+config TI_CPSW_ALE
+ tristate "TI CPSW ALE Support"
+ ---help---
+ This driver supports TI's CPSW ALE module.
+
config TI_CPSW
tristate "TI CPSW Switch Support"
depends on ARCH_DAVINCI || ARCH_OMAP2PLUS
select TI_DAVINCI_CPDMA
select TI_DAVINCI_MDIO
select TI_CPSW_PHY_SEL
+ select TI_CPSW_ALE
select MFD_SYSCON
select REGMAP
---help---
@@ -71,7 +77,7 @@ config TI_CPSW
will be called cpsw.
config TI_CPTS
- boolean "TI Common Platform Time Sync (CPTS) Support"
+ bool "TI Common Platform Time Sync (CPTS) Support"
depends on TI_CPSW
select PTP_1588_CLOCK
---help---
@@ -79,6 +85,25 @@ config TI_CPTS
the CPSW Ethernet Switch. The unit can time stamp PTP UDP/IPv4
and Layer 2 packets, and the driver offers a PTP Hardware Clock.
+config TI_KEYSTONE_NETCP
+ tristate "TI Keystone NETCP Core Support"
+ select TI_CPSW_ALE
+ depends on OF
+ depends on KEYSTONE_NAVIGATOR_DMA && KEYSTONE_NAVIGATOR_QMSS
+ ---help---
+ This driver supports TI's Keystone NETCP Core.
+
+ To compile this driver as a module, choose M here: the module
+ will be called keystone_netcp.
+
+config TI_KEYSTONE_NETCP_ETHSS
+ depends on TI_KEYSTONE_NETCP
+ tristate "TI Keystone NETCP Ethernet subsystem Support"
+ ---help---
+
+ To compile this driver as a module, choose M here: the module
+ will be called keystone_netcp_ethss.
+
config TLAN
tristate "TI ThunderLAN support"
depends on (PCI || EISA)
diff --git a/drivers/net/ethernet/ti/Makefile b/drivers/net/ethernet/ti/Makefile
index 9cfaab8152be..d420d9413e4a 100644
--- a/drivers/net/ethernet/ti/Makefile
+++ b/drivers/net/ethernet/ti/Makefile
@@ -2,11 +2,20 @@
# Makefile for the TI network device drivers.
#
+obj-$(CONFIG_TI_CPSW) += cpsw-common.o
+obj-$(CONFIG_TI_DAVINCI_EMAC) += cpsw-common.o
+
obj-$(CONFIG_TLAN) += tlan.o
obj-$(CONFIG_CPMAC) += cpmac.o
obj-$(CONFIG_TI_DAVINCI_EMAC) += davinci_emac.o
obj-$(CONFIG_TI_DAVINCI_MDIO) += davinci_mdio.o
obj-$(CONFIG_TI_DAVINCI_CPDMA) += davinci_cpdma.o
obj-$(CONFIG_TI_CPSW_PHY_SEL) += cpsw-phy-sel.o
+obj-$(CONFIG_TI_CPSW_ALE) += cpsw_ale.o
obj-$(CONFIG_TI_CPSW) += ti_cpsw.o
-ti_cpsw-y := cpsw_ale.o cpsw.o cpts.o
+ti_cpsw-y := cpsw.o cpts.o
+
+obj-$(CONFIG_TI_KEYSTONE_NETCP) += keystone_netcp.o
+keystone_netcp-y := netcp_core.o
+obj-$(CONFIG_TI_KEYSTONE_NETCP_ETHSS) += keystone_netcp_ethss.o
+keystone_netcp_ethss-y := netcp_ethss.o netcp_sgmii.o netcp_xgbepcsr.o
diff --git a/drivers/net/ethernet/ti/cpsw-common.c b/drivers/net/ethernet/ti/cpsw-common.c
new file mode 100644
index 000000000000..f59509486113
--- /dev/null
+++ b/drivers/net/ethernet/ti/cpsw-common.c
@@ -0,0 +1,55 @@
+/*
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#include "cpsw.h"
+
+#define AM33XX_CTRL_MAC_LO_REG(offset, id) ((offset) + 0x8 * (id))
+#define AM33XX_CTRL_MAC_HI_REG(offset, id) ((offset) + 0x8 * (id) + 0x4)
+
+int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave,
+ u8 *mac_addr)
+{
+ u32 macid_lo;
+ u32 macid_hi;
+ struct regmap *syscon;
+
+ syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+ if (IS_ERR(syscon)) {
+ if (PTR_ERR(syscon) == -ENODEV)
+ return 0;
+ return PTR_ERR(syscon);
+ }
+
+ regmap_read(syscon, AM33XX_CTRL_MAC_LO_REG(offset, slave),
+ &macid_lo);
+ regmap_read(syscon, AM33XX_CTRL_MAC_HI_REG(offset, slave),
+ &macid_hi);
+
+ mac_addr[5] = (macid_lo >> 8) & 0xff;
+ mac_addr[4] = macid_lo & 0xff;
+ mac_addr[3] = (macid_hi >> 24) & 0xff;
+ mac_addr[2] = (macid_hi >> 16) & 0xff;
+ mac_addr[1] = (macid_hi >> 8) & 0xff;
+ mac_addr[0] = macid_hi & 0xff;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cpsw_am33xx_cm_get_macid);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index a39131f494ec..7d8dd0d2182e 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -33,8 +33,6 @@
#include <linux/of_net.h>
#include <linux/of_device.h>
#include <linux/if_vlan.h>
-#include <linux/mfd/syscon.h>
-#include <linux/regmap.h>
#include <linux/pinctrl/consumer.h>
@@ -761,17 +759,25 @@ requeue:
dev_kfree_skb_any(new_skb);
}
-static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
+static irqreturn_t cpsw_tx_interrupt(int irq, void *dev_id)
{
struct cpsw_priv *priv = dev_id;
- int value = irq - priv->irqs_table[0];
- /* NOTICE: Ending IRQ here. The trick with the 'value' variable above
- * is to make sure we will always write the correct value to the EOI
- * register. Namely 0 for RX_THRESH Interrupt, 1 for RX Interrupt, 2
- * for TX Interrupt and 3 for MISC Interrupt.
- */
- cpdma_ctlr_eoi(priv->dma, value);
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX);
+ cpdma_chan_process(priv->txch, 128);
+
+ priv = cpsw_get_slave_priv(priv, 1);
+ if (priv)
+ cpdma_chan_process(priv->txch, 128);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t cpsw_rx_interrupt(int irq, void *dev_id)
+{
+ struct cpsw_priv *priv = dev_id;
+
+ cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX);
cpsw_intr_disable(priv);
if (priv->irq_enabled == true) {
@@ -1624,7 +1630,8 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev)
cpsw_intr_disable(priv);
cpdma_ctlr_int_ctrl(priv->dma, false);
- cpsw_interrupt(ndev->irq, priv);
+ cpsw_rx_interrupt(priv->irqs_table[0], priv);
+ cpsw_tx_interrupt(priv->irqs_table[1], priv);
cpdma_ctlr_int_ctrl(priv->dma, true);
cpsw_intr_enable(priv);
}
@@ -1927,36 +1934,6 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv,
slave->port_vlan = data->dual_emac_res_vlan;
}
-#define AM33XX_CTRL_MAC_LO_REG(id) (0x630 + 0x8 * id)
-#define AM33XX_CTRL_MAC_HI_REG(id) (0x630 + 0x8 * id + 0x4)
-
-static int cpsw_am33xx_cm_get_macid(struct device *dev, int slave,
- u8 *mac_addr)
-{
- u32 macid_lo;
- u32 macid_hi;
- struct regmap *syscon;
-
- syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
- if (IS_ERR(syscon)) {
- if (PTR_ERR(syscon) == -ENODEV)
- return 0;
- return PTR_ERR(syscon);
- }
-
- regmap_read(syscon, AM33XX_CTRL_MAC_LO_REG(slave), &macid_lo);
- regmap_read(syscon, AM33XX_CTRL_MAC_HI_REG(slave), &macid_hi);
-
- mac_addr[5] = (macid_lo >> 8) & 0xff;
- mac_addr[4] = macid_lo & 0xff;
- mac_addr[3] = (macid_hi >> 24) & 0xff;
- mac_addr[2] = (macid_hi >> 16) & 0xff;
- mac_addr[1] = (macid_hi >> 8) & 0xff;
- mac_addr[0] = macid_hi & 0xff;
-
- return 0;
-}
-
static int cpsw_probe_dt(struct cpsw_platform_data *data,
struct platform_device *pdev)
{
@@ -2081,7 +2058,8 @@ no_phy_slave:
memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN);
} else {
if (of_machine_is_compatible("ti,am33xx")) {
- ret = cpsw_am33xx_cm_get_macid(&pdev->dev, i,
+ ret = cpsw_am33xx_cm_get_macid(&pdev->dev,
+ 0x630, i,
slave_data->mac_addr);
if (ret)
return ret;
@@ -2192,7 +2170,8 @@ static int cpsw_probe(struct platform_device *pdev)
void __iomem *ss_regs;
struct resource *res, *ss_res;
u32 slave_offset, sliver_offset, slave_size;
- int ret = 0, i, k = 0;
+ int ret = 0, i;
+ int irq;
ndev = alloc_etherdev(sizeof(struct cpsw_priv));
if (!ndev) {
@@ -2374,31 +2353,47 @@ static int cpsw_probe(struct platform_device *pdev)
goto clean_dma_ret;
}
- ndev->irq = platform_get_irq(pdev, 0);
+ ndev->irq = platform_get_irq(pdev, 1);
if (ndev->irq < 0) {
dev_err(priv->dev, "error getting irq resource\n");
ret = -ENOENT;
goto clean_ale_ret;
}
- while ((res = platform_get_resource(priv->pdev, IORESOURCE_IRQ, k))) {
- if (k >= ARRAY_SIZE(priv->irqs_table)) {
- ret = -EINVAL;
- goto clean_ale_ret;
- }
+ /* Grab RX and TX IRQs. Note that we also have RX_THRESHOLD and
+ * MISC IRQs which are always kept disabled with this driver so
+ * we will not request them.
+ *
+ * If anyone wants to implement support for those, make sure to
+ * first request and append them to irqs_table array.
+ */
- ret = devm_request_irq(&pdev->dev, res->start, cpsw_interrupt,
- 0, dev_name(&pdev->dev), priv);
- if (ret < 0) {
- dev_err(priv->dev, "error attaching irq (%d)\n", ret);
- goto clean_ale_ret;
- }
+ /* RX IRQ */
+ irq = platform_get_irq(pdev, 1);
+ if (irq < 0)
+ goto clean_ale_ret;
- priv->irqs_table[k] = res->start;
- k++;
+ priv->irqs_table[0] = irq;
+ ret = devm_request_irq(&pdev->dev, irq, cpsw_rx_interrupt,
+ 0, dev_name(&pdev->dev), priv);
+ if (ret < 0) {
+ dev_err(priv->dev, "error attaching irq (%d)\n", ret);
+ goto clean_ale_ret;
}
- priv->num_irqs = k;
+ /* TX IRQ */
+ irq = platform_get_irq(pdev, 2);
+ if (irq < 0)
+ goto clean_ale_ret;
+
+ priv->irqs_table[1] = irq;
+ ret = devm_request_irq(&pdev->dev, irq, cpsw_tx_interrupt,
+ 0, dev_name(&pdev->dev), priv);
+ if (ret < 0) {
+ dev_err(priv->dev, "error attaching irq (%d)\n", ret);
+ goto clean_ale_ret;
+ }
+ priv->num_irqs = 2;
ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
diff --git a/drivers/net/ethernet/ti/cpsw.h b/drivers/net/ethernet/ti/cpsw.h
index 1b710674630c..ca90efafd156 100644
--- a/drivers/net/ethernet/ti/cpsw.h
+++ b/drivers/net/ethernet/ti/cpsw.h
@@ -41,5 +41,7 @@ struct cpsw_platform_data {
};
void cpsw_phy_sel(struct device *dev, phy_interface_t phy_mode, int slave);
+int cpsw_am33xx_cm_get_macid(struct device *dev, u16 offset, int slave,
+ u8 *mac_addr);
#endif /* __CPSW_H__ */
diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c
index 5246b3a18ff8..6e927b4583aa 100644
--- a/drivers/net/ethernet/ti/cpsw_ale.c
+++ b/drivers/net/ethernet/ti/cpsw_ale.c
@@ -13,6 +13,7 @@
* GNU General Public License for more details.
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/seq_file.h>
#include <linux/slab.h>
@@ -146,7 +147,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry)
return idx;
}
-int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
+static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx;
@@ -167,7 +168,7 @@ int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid)
return -ENOENT;
}
-int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
+static int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid)
{
u32 ale_entry[ALE_ENTRY_WORDS];
int type, idx;
@@ -265,6 +266,7 @@ int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask, int vid)
}
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_flush_multicast);
static void cpsw_ale_flush_ucast(struct cpsw_ale *ale, u32 *ale_entry,
int port_mask)
@@ -297,6 +299,7 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask)
}
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_flush);
static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry,
int flags, u16 vid)
@@ -334,6 +337,7 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_add_ucast);
int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
int flags, u16 vid)
@@ -349,6 +353,7 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_del_ucast);
int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
int flags, u16 vid, int mcast_state)
@@ -380,6 +385,7 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_add_mcast);
int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
int flags, u16 vid)
@@ -401,6 +407,7 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_del_mcast);
int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
int reg_mcast, int unreg_mcast)
@@ -430,6 +437,7 @@ int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag,
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_add_vlan);
int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
{
@@ -450,6 +458,7 @@ int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask)
cpsw_ale_write(ale, idx, ale_entry);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_del_vlan);
void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
{
@@ -479,6 +488,7 @@ void cpsw_ale_set_allmulti(struct cpsw_ale *ale, int allmulti)
cpsw_ale_write(ale, idx, ale_entry);
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_set_allmulti);
struct ale_control_info {
const char *name;
@@ -704,6 +714,7 @@ int cpsw_ale_control_set(struct cpsw_ale *ale, int port, int control,
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_control_set);
int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
{
@@ -727,6 +738,7 @@ int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control)
tmp = __raw_readl(ale->params.ale_regs + offset) >> shift;
return tmp & BITMASK(info->bits);
}
+EXPORT_SYMBOL_GPL(cpsw_ale_control_get);
static void cpsw_ale_timer(unsigned long arg)
{
@@ -750,6 +762,7 @@ int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout)
}
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_set_ageout);
void cpsw_ale_start(struct cpsw_ale *ale)
{
@@ -769,11 +782,13 @@ void cpsw_ale_start(struct cpsw_ale *ale)
add_timer(&ale->timer);
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_start);
void cpsw_ale_stop(struct cpsw_ale *ale)
{
del_timer_sync(&ale->timer);
}
+EXPORT_SYMBOL_GPL(cpsw_ale_stop);
struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
{
@@ -788,6 +803,7 @@ struct cpsw_ale *cpsw_ale_create(struct cpsw_ale_params *params)
return ale;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_create);
int cpsw_ale_destroy(struct cpsw_ale *ale)
{
@@ -797,6 +813,7 @@ int cpsw_ale_destroy(struct cpsw_ale *ale)
kfree(ale);
return 0;
}
+EXPORT_SYMBOL_GPL(cpsw_ale_destroy);
void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
{
@@ -807,3 +824,8 @@ void cpsw_ale_dump(struct cpsw_ale *ale, u32 *data)
data += ALE_ENTRY_WORDS;
}
}
+EXPORT_SYMBOL_GPL(cpsw_ale_dump);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI CPSW ALE driver");
+MODULE_AUTHOR("Texas Instruments");
diff --git a/drivers/net/ethernet/ti/cpts.c b/drivers/net/ethernet/ti/cpts.c
index 4a4388b813ac..fbe42cb107ec 100644
--- a/drivers/net/ethernet/ti/cpts.c
+++ b/drivers/net/ethernet/ti/cpts.c
@@ -157,14 +157,11 @@ static int cpts_ptp_adjfreq(struct ptp_clock_info *ptp, s32 ppb)
static int cpts_ptp_adjtime(struct ptp_clock_info *ptp, s64 delta)
{
- s64 now;
unsigned long flags;
struct cpts *cpts = container_of(ptp, struct cpts, info);
spin_lock_irqsave(&cpts->lock, flags);
- now = timecounter_read(&cpts->tc);
- now += delta;
- timecounter_init(&cpts->tc, &cpts->cc, now);
+ timecounter_adjtime(&cpts->tc, delta);
spin_unlock_irqrestore(&cpts->lock, flags);
return 0;
diff --git a/drivers/net/ethernet/ti/cpts.h b/drivers/net/ethernet/ti/cpts.h
index 1a581ef7eee8..69a46b92c7d6 100644
--- a/drivers/net/ethernet/ti/cpts.h
+++ b/drivers/net/ethernet/ti/cpts.h
@@ -27,6 +27,7 @@
#include <linux/list.h>
#include <linux/ptp_clock_kernel.h>
#include <linux/skbuff.h>
+#include <linux/timecounter.h>
struct cpsw_cpts {
u32 idver; /* Identification and version */
diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c
index 5fae4354722c..aeebc0a7bf47 100644
--- a/drivers/net/ethernet/ti/davinci_emac.c
+++ b/drivers/net/ethernet/ti/davinci_emac.c
@@ -52,6 +52,7 @@
#include <linux/dma-mapping.h>
#include <linux/clk.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/semaphore.h>
#include <linux/phy.h>
#include <linux/bitops.h>
@@ -65,10 +66,12 @@
#include <linux/of_mdio.h>
#include <linux/of_irq.h>
#include <linux/of_net.h>
+#include <linux/mfd/syscon.h>
#include <asm/irq.h>
#include <asm/page.h>
+#include "cpsw.h"
#include "davinci_cpdma.h"
static int debug_level;
@@ -1838,7 +1841,7 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)
if (!is_valid_ether_addr(pdata->mac_addr)) {
mac_addr = of_get_mac_address(np);
if (mac_addr)
- memcpy(pdata->mac_addr, mac_addr, ETH_ALEN);
+ ether_addr_copy(pdata->mac_addr, mac_addr);
}
of_property_read_u32(np, "ti,davinci-ctrl-reg-offset",
@@ -1879,6 +1882,53 @@ davinci_emac_of_get_pdata(struct platform_device *pdev, struct emac_priv *priv)
return pdata;
}
+static int davinci_emac_3517_get_macid(struct device *dev, u16 offset,
+ int slave, u8 *mac_addr)
+{
+ u32 macid_lsb;
+ u32 macid_msb;
+ struct regmap *syscon;
+
+ syscon = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+ if (IS_ERR(syscon)) {
+ if (PTR_ERR(syscon) == -ENODEV)
+ return 0;
+ return PTR_ERR(syscon);
+ }
+
+ regmap_read(syscon, offset, &macid_lsb);
+ regmap_read(syscon, offset + 4, &macid_msb);
+
+ mac_addr[0] = (macid_msb >> 16) & 0xff;
+ mac_addr[1] = (macid_msb >> 8) & 0xff;
+ mac_addr[2] = macid_msb & 0xff;
+ mac_addr[3] = (macid_lsb >> 16) & 0xff;
+ mac_addr[4] = (macid_lsb >> 8) & 0xff;
+ mac_addr[5] = macid_lsb & 0xff;
+
+ return 0;
+}
+
+static int davinci_emac_try_get_mac(struct platform_device *pdev,
+ int instance, u8 *mac_addr)
+{
+ int error = -EINVAL;
+
+ if (!pdev->dev.of_node)
+ return error;
+
+ if (of_device_is_compatible(pdev->dev.of_node, "ti,am3517-emac"))
+ error = davinci_emac_3517_get_macid(&pdev->dev, 0x110,
+ 0, mac_addr);
+ else if (of_device_is_compatible(pdev->dev.of_node,
+ "ti,dm816-emac"))
+ error = cpsw_am33xx_cm_get_macid(&pdev->dev, 0x30,
+ instance,
+ mac_addr);
+
+ return error;
+}
+
/**
* davinci_emac_probe - EMAC device probe
* @pdev: The DaVinci EMAC device that we are removing
@@ -2009,6 +2059,10 @@ static int davinci_emac_probe(struct platform_device *pdev)
}
ndev->irq = res->start;
+ rc = davinci_emac_try_get_mac(pdev, res_ctrl ? 0 : 1, priv->mac_addr);
+ if (!rc)
+ ether_addr_copy(ndev->dev_addr, priv->mac_addr);
+
if (!is_valid_ether_addr(priv->mac_addr)) {
/* Use random MAC if none passed */
eth_hw_addr_random(ndev);
diff --git a/drivers/net/ethernet/ti/netcp.h b/drivers/net/ethernet/ti/netcp.h
new file mode 100644
index 000000000000..906e9bc412f5
--- /dev/null
+++ b/drivers/net/ethernet/ti/netcp.h
@@ -0,0 +1,229 @@
+/*
+ * NetCP driver local header
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors: Sandeep Nair <sandeep_n@ti.com>
+ * Sandeep Paulraj <s-paulraj@ti.com>
+ * Cyril Chemparathy <cyril@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Wingman Kwok <w-kwok2@ti.com>
+ * Murali Karicheri <m-karicheri2@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+#ifndef __NETCP_H__
+#define __NETCP_H__
+
+#include <linux/netdevice.h>
+#include <linux/soc/ti/knav_dma.h>
+
+/* Maximum Ethernet frame size supported by Keystone switch */
+#define NETCP_MAX_FRAME_SIZE 9504
+
+#define SGMII_LINK_MAC_MAC_AUTONEG 0
+#define SGMII_LINK_MAC_PHY 1
+#define SGMII_LINK_MAC_MAC_FORCED 2
+#define SGMII_LINK_MAC_FIBER 3
+#define SGMII_LINK_MAC_PHY_NO_MDIO 4
+#define XGMII_LINK_MAC_PHY 10
+#define XGMII_LINK_MAC_MAC_FORCED 11
+
+struct netcp_device;
+
+struct netcp_tx_pipe {
+ struct netcp_device *netcp_device;
+ void *dma_queue;
+ unsigned int dma_queue_id;
+ u8 dma_psflags;
+ void *dma_channel;
+ const char *dma_chan_name;
+};
+
+#define ADDR_NEW BIT(0)
+#define ADDR_VALID BIT(1)
+
+enum netcp_addr_type {
+ ADDR_ANY,
+ ADDR_DEV,
+ ADDR_UCAST,
+ ADDR_MCAST,
+ ADDR_BCAST
+};
+
+struct netcp_addr {
+ struct netcp_intf *netcp;
+ unsigned char addr[ETH_ALEN];
+ enum netcp_addr_type type;
+ unsigned int flags;
+ struct list_head node;
+};
+
+struct netcp_intf {
+ struct device *dev;
+ struct device *ndev_dev;
+ struct net_device *ndev;
+ bool big_endian;
+ unsigned int tx_compl_qid;
+ void *tx_pool;
+ struct list_head txhook_list_head;
+ unsigned int tx_pause_threshold;
+ void *tx_compl_q;
+
+ unsigned int tx_resume_threshold;
+ void *rx_queue;
+ void *rx_pool;
+ struct list_head rxhook_list_head;
+ unsigned int rx_queue_id;
+ void *rx_fdq[KNAV_DMA_FDQ_PER_CHAN];
+ u32 rx_buffer_sizes[KNAV_DMA_FDQ_PER_CHAN];
+ struct napi_struct rx_napi;
+ struct napi_struct tx_napi;
+
+ void *rx_channel;
+ const char *dma_chan_name;
+ u32 rx_pool_size;
+ u32 rx_pool_region_id;
+ u32 tx_pool_size;
+ u32 tx_pool_region_id;
+ struct list_head module_head;
+ struct list_head interface_list;
+ struct list_head addr_list;
+ bool netdev_registered;
+ bool primary_module_attached;
+
+ /* Lock used for protecting Rx/Tx hook list management */
+ spinlock_t lock;
+ struct netcp_device *netcp_device;
+ struct device_node *node_interface;
+
+ /* DMA configuration data */
+ u32 msg_enable;
+ u32 rx_queue_depths[KNAV_DMA_FDQ_PER_CHAN];
+};
+
+#define NETCP_PSDATA_LEN KNAV_DMA_NUM_PS_WORDS
+struct netcp_packet {
+ struct sk_buff *skb;
+ u32 *epib;
+ u32 *psdata;
+ unsigned int psdata_len;
+ struct netcp_intf *netcp;
+ struct netcp_tx_pipe *tx_pipe;
+ bool rxtstamp_complete;
+ void *ts_context;
+
+ int (*txtstamp_complete)(void *ctx, struct netcp_packet *pkt);
+};
+
+static inline u32 *netcp_push_psdata(struct netcp_packet *p_info,
+ unsigned int bytes)
+{
+ u32 *buf;
+ unsigned int words;
+
+ if ((bytes & 0x03) != 0)
+ return NULL;
+ words = bytes >> 2;
+
+ if ((p_info->psdata_len + words) > NETCP_PSDATA_LEN)
+ return NULL;
+
+ p_info->psdata_len += words;
+ buf = &p_info->psdata[NETCP_PSDATA_LEN - p_info->psdata_len];
+ return buf;
+}
+
+static inline int netcp_align_psdata(struct netcp_packet *p_info,
+ unsigned int byte_align)
+{
+ int padding;
+
+ switch (byte_align) {
+ case 0:
+ padding = -EINVAL;
+ break;
+ case 1:
+ case 2:
+ case 4:
+ padding = 0;
+ break;
+ case 8:
+ padding = (p_info->psdata_len << 2) % 8;
+ break;
+ case 16:
+ padding = (p_info->psdata_len << 2) % 16;
+ break;
+ default:
+ padding = (p_info->psdata_len << 2) % byte_align;
+ break;
+ }
+ return padding;
+}
+
+struct netcp_module {
+ const char *name;
+ struct module *owner;
+ bool primary;
+
+ /* probe/remove: called once per NETCP instance */
+ int (*probe)(struct netcp_device *netcp_device,
+ struct device *device, struct device_node *node,
+ void **inst_priv);
+ int (*remove)(struct netcp_device *netcp_device, void *inst_priv);
+
+ /* attach/release: called once per network interface */
+ int (*attach)(void *inst_priv, struct net_device *ndev,
+ struct device_node *node, void **intf_priv);
+ int (*release)(void *intf_priv);
+ int (*open)(void *intf_priv, struct net_device *ndev);
+ int (*close)(void *intf_priv, struct net_device *ndev);
+ int (*add_addr)(void *intf_priv, struct netcp_addr *naddr);
+ int (*del_addr)(void *intf_priv, struct netcp_addr *naddr);
+ int (*add_vid)(void *intf_priv, int vid);
+ int (*del_vid)(void *intf_priv, int vid);
+ int (*ioctl)(void *intf_priv, struct ifreq *req, int cmd);
+
+ /* used internally */
+ struct list_head module_list;
+ struct list_head interface_list;
+};
+
+int netcp_register_module(struct netcp_module *module);
+void netcp_unregister_module(struct netcp_module *module);
+void *netcp_module_get_intf_data(struct netcp_module *module,
+ struct netcp_intf *intf);
+
+int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe,
+ struct netcp_device *netcp_device,
+ const char *dma_chan_name, unsigned int dma_queue_id);
+int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe);
+int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe);
+
+typedef int netcp_hook_rtn(int order, void *data, struct netcp_packet *packet);
+int netcp_register_txhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data);
+int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data);
+int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data);
+int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data);
+void *netcp_device_find_module(struct netcp_device *netcp_device,
+ const char *name);
+
+/* SGMII functions */
+int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port);
+int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port);
+int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface);
+
+/* XGBE SERDES init functions */
+int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs);
+
+#endif /* __NETCP_H__ */
diff --git a/drivers/net/ethernet/ti/netcp_core.c b/drivers/net/ethernet/ti/netcp_core.c
new file mode 100644
index 000000000000..a31a8c3c8e7c
--- /dev/null
+++ b/drivers/net/ethernet/ti/netcp_core.c
@@ -0,0 +1,2149 @@
+/*
+ * Keystone NetCP Core driver
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors: Sandeep Nair <sandeep_n@ti.com>
+ * Sandeep Paulraj <s-paulraj@ti.com>
+ * Cyril Chemparathy <cyril@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Murali Karicheri <m-karicheri2@ti.com>
+ * Wingman Kwok <w-kwok2@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/io.h>
+#include <linux/module.h>
+#include <linux/of_net.h>
+#include <linux/of_address.h>
+#include <linux/if_vlan.h>
+#include <linux/pm_runtime.h>
+#include <linux/platform_device.h>
+#include <linux/soc/ti/knav_qmss.h>
+#include <linux/soc/ti/knav_dma.h>
+
+#include "netcp.h"
+
+#define NETCP_SOP_OFFSET (NET_IP_ALIGN + NET_SKB_PAD)
+#define NETCP_NAPI_WEIGHT 64
+#define NETCP_TX_TIMEOUT (5 * HZ)
+#define NETCP_MIN_PACKET_SIZE ETH_ZLEN
+#define NETCP_MAX_MCAST_ADDR 16
+
+#define NETCP_EFUSE_REG_INDEX 0
+
+#define NETCP_MOD_PROBE_SKIPPED 1
+#define NETCP_MOD_PROBE_FAILED 2
+
+#define NETCP_DEBUG (NETIF_MSG_HW | NETIF_MSG_WOL | \
+ NETIF_MSG_DRV | NETIF_MSG_LINK | \
+ NETIF_MSG_IFUP | NETIF_MSG_INTR | \
+ NETIF_MSG_PROBE | NETIF_MSG_TIMER | \
+ NETIF_MSG_IFDOWN | NETIF_MSG_RX_ERR | \
+ NETIF_MSG_TX_ERR | NETIF_MSG_TX_DONE | \
+ NETIF_MSG_PKTDATA | NETIF_MSG_TX_QUEUED | \
+ NETIF_MSG_RX_STATUS)
+
+#define knav_queue_get_id(q) knav_queue_device_control(q, \
+ KNAV_QUEUE_GET_ID, (unsigned long)NULL)
+
+#define knav_queue_enable_notify(q) knav_queue_device_control(q, \
+ KNAV_QUEUE_ENABLE_NOTIFY, \
+ (unsigned long)NULL)
+
+#define knav_queue_disable_notify(q) knav_queue_device_control(q, \
+ KNAV_QUEUE_DISABLE_NOTIFY, \
+ (unsigned long)NULL)
+
+#define knav_queue_get_count(q) knav_queue_device_control(q, \
+ KNAV_QUEUE_GET_COUNT, (unsigned long)NULL)
+
+#define for_each_netcp_module(module) \
+ list_for_each_entry(module, &netcp_modules, module_list)
+
+#define for_each_netcp_device_module(netcp_device, inst_modpriv) \
+ list_for_each_entry(inst_modpriv, \
+ &((netcp_device)->modpriv_head), inst_list)
+
+#define for_each_module(netcp, intf_modpriv) \
+ list_for_each_entry(intf_modpriv, &netcp->module_head, intf_list)
+
+/* Module management structures */
+struct netcp_device {
+ struct list_head device_list;
+ struct list_head interface_head;
+ struct list_head modpriv_head;
+ struct device *device;
+};
+
+struct netcp_inst_modpriv {
+ struct netcp_device *netcp_device;
+ struct netcp_module *netcp_module;
+ struct list_head inst_list;
+ void *module_priv;
+};
+
+struct netcp_intf_modpriv {
+ struct netcp_intf *netcp_priv;
+ struct netcp_module *netcp_module;
+ struct list_head intf_list;
+ void *module_priv;
+};
+
+static LIST_HEAD(netcp_devices);
+static LIST_HEAD(netcp_modules);
+static DEFINE_MUTEX(netcp_modules_lock);
+
+static int netcp_debug_level = -1;
+module_param(netcp_debug_level, int, 0);
+MODULE_PARM_DESC(netcp_debug_level, "Netcp debug level (NETIF_MSG bits) (0=none,...,16=all)");
+
+/* Helper functions - Get/Set */
+static void get_pkt_info(u32 *buff, u32 *buff_len, u32 *ndesc,
+ struct knav_dma_desc *desc)
+{
+ *buff_len = desc->buff_len;
+ *buff = desc->buff;
+ *ndesc = desc->next_desc;
+}
+
+static void get_pad_info(u32 *pad0, u32 *pad1, struct knav_dma_desc *desc)
+{
+ *pad0 = desc->pad[0];
+ *pad1 = desc->pad[1];
+}
+
+static void get_org_pkt_info(u32 *buff, u32 *buff_len,
+ struct knav_dma_desc *desc)
+{
+ *buff = desc->orig_buff;
+ *buff_len = desc->orig_len;
+}
+
+static void get_words(u32 *words, int num_words, u32 *desc)
+{
+ int i;
+
+ for (i = 0; i < num_words; i++)
+ words[i] = desc[i];
+}
+
+static void set_pkt_info(u32 buff, u32 buff_len, u32 ndesc,
+ struct knav_dma_desc *desc)
+{
+ desc->buff_len = buff_len;
+ desc->buff = buff;
+ desc->next_desc = ndesc;
+}
+
+static void set_desc_info(u32 desc_info, u32 pkt_info,
+ struct knav_dma_desc *desc)
+{
+ desc->desc_info = desc_info;
+ desc->packet_info = pkt_info;
+}
+
+static void set_pad_info(u32 pad0, u32 pad1, struct knav_dma_desc *desc)
+{
+ desc->pad[0] = pad0;
+ desc->pad[1] = pad1;
+}
+
+static void set_org_pkt_info(u32 buff, u32 buff_len,
+ struct knav_dma_desc *desc)
+{
+ desc->orig_buff = buff;
+ desc->orig_len = buff_len;
+}
+
+static void set_words(u32 *words, int num_words, u32 *desc)
+{
+ int i;
+
+ for (i = 0; i < num_words; i++)
+ desc[i] = words[i];
+}
+
+/* Read the e-fuse value as 32 bit values to be endian independent */
+static int emac_arch_get_mac_addr(char *x, void __iomem *efuse_mac)
+{
+ unsigned int addr0, addr1;
+
+ addr1 = readl(efuse_mac + 4);
+ addr0 = readl(efuse_mac);
+
+ x[0] = (addr1 & 0x0000ff00) >> 8;
+ x[1] = addr1 & 0x000000ff;
+ x[2] = (addr0 & 0xff000000) >> 24;
+ x[3] = (addr0 & 0x00ff0000) >> 16;
+ x[4] = (addr0 & 0x0000ff00) >> 8;
+ x[5] = addr0 & 0x000000ff;
+
+ return 0;
+}
+
+static const char *netcp_node_name(struct device_node *node)
+{
+ const char *name;
+
+ if (of_property_read_string(node, "label", &name) < 0)
+ name = node->name;
+ if (!name)
+ name = "unknown";
+ return name;
+}
+
+/* Module management routines */
+static int netcp_register_interface(struct netcp_intf *netcp)
+{
+ int ret;
+
+ ret = register_netdev(netcp->ndev);
+ if (!ret)
+ netcp->netdev_registered = true;
+ return ret;
+}
+
+static int netcp_module_probe(struct netcp_device *netcp_device,
+ struct netcp_module *module)
+{
+ struct device *dev = netcp_device->device;
+ struct device_node *devices, *interface, *node = dev->of_node;
+ struct device_node *child;
+ struct netcp_inst_modpriv *inst_modpriv;
+ struct netcp_intf *netcp_intf;
+ struct netcp_module *tmp;
+ bool primary_module_registered = false;
+ int ret;
+
+ /* Find this module in the sub-tree for this device */
+ devices = of_get_child_by_name(node, "netcp-devices");
+ if (!devices) {
+ dev_err(dev, "could not find netcp-devices node\n");
+ return NETCP_MOD_PROBE_SKIPPED;
+ }
+
+ for_each_available_child_of_node(devices, child) {
+ const char *name = netcp_node_name(child);
+
+ if (!strcasecmp(module->name, name))
+ break;
+ }
+
+ of_node_put(devices);
+ /* If module not used for this device, skip it */
+ if (!child) {
+ dev_warn(dev, "module(%s) not used for device\n", module->name);
+ return NETCP_MOD_PROBE_SKIPPED;
+ }
+
+ inst_modpriv = devm_kzalloc(dev, sizeof(*inst_modpriv), GFP_KERNEL);
+ if (!inst_modpriv) {
+ of_node_put(child);
+ return -ENOMEM;
+ }
+
+ inst_modpriv->netcp_device = netcp_device;
+ inst_modpriv->netcp_module = module;
+ list_add_tail(&inst_modpriv->inst_list, &netcp_device->modpriv_head);
+
+ ret = module->probe(netcp_device, dev, child,
+ &inst_modpriv->module_priv);
+ of_node_put(child);
+ if (ret) {
+ dev_err(dev, "Probe of module(%s) failed with %d\n",
+ module->name, ret);
+ list_del(&inst_modpriv->inst_list);
+ devm_kfree(dev, inst_modpriv);
+ return NETCP_MOD_PROBE_FAILED;
+ }
+
+ /* Attach modules only if the primary module is probed */
+ for_each_netcp_module(tmp) {
+ if (tmp->primary)
+ primary_module_registered = true;
+ }
+
+ if (!primary_module_registered)
+ return 0;
+
+ /* Attach module to interfaces */
+ list_for_each_entry(netcp_intf, &netcp_device->interface_head,
+ interface_list) {
+ struct netcp_intf_modpriv *intf_modpriv;
+
+ /* If interface not registered then register now */
+ if (!netcp_intf->netdev_registered)
+ ret = netcp_register_interface(netcp_intf);
+
+ if (ret)
+ return -ENODEV;
+
+ intf_modpriv = devm_kzalloc(dev, sizeof(*intf_modpriv),
+ GFP_KERNEL);
+ if (!intf_modpriv)
+ return -ENOMEM;
+
+ interface = of_parse_phandle(netcp_intf->node_interface,
+ module->name, 0);
+
+ intf_modpriv->netcp_priv = netcp_intf;
+ intf_modpriv->netcp_module = module;
+ list_add_tail(&intf_modpriv->intf_list,
+ &netcp_intf->module_head);
+
+ ret = module->attach(inst_modpriv->module_priv,
+ netcp_intf->ndev, interface,
+ &intf_modpriv->module_priv);
+ of_node_put(interface);
+ if (ret) {
+ dev_dbg(dev, "Attach of module %s declined with %d\n",
+ module->name, ret);
+ list_del(&intf_modpriv->intf_list);
+ devm_kfree(dev, intf_modpriv);
+ continue;
+ }
+ }
+ return 0;
+}
+
+int netcp_register_module(struct netcp_module *module)
+{
+ struct netcp_device *netcp_device;
+ struct netcp_module *tmp;
+ int ret;
+
+ if (!module->name) {
+ WARN(1, "error registering netcp module: no name\n");
+ return -EINVAL;
+ }
+
+ if (!module->probe) {
+ WARN(1, "error registering netcp module: no probe\n");
+ return -EINVAL;
+ }
+
+ mutex_lock(&netcp_modules_lock);
+
+ for_each_netcp_module(tmp) {
+ if (!strcasecmp(tmp->name, module->name)) {
+ mutex_unlock(&netcp_modules_lock);
+ return -EEXIST;
+ }
+ }
+ list_add_tail(&module->module_list, &netcp_modules);
+
+ list_for_each_entry(netcp_device, &netcp_devices, device_list) {
+ ret = netcp_module_probe(netcp_device, module);
+ if (ret < 0)
+ goto fail;
+ }
+
+ mutex_unlock(&netcp_modules_lock);
+ return 0;
+
+fail:
+ mutex_unlock(&netcp_modules_lock);
+ netcp_unregister_module(module);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(netcp_register_module);
+
+static void netcp_release_module(struct netcp_device *netcp_device,
+ struct netcp_module *module)
+{
+ struct netcp_inst_modpriv *inst_modpriv, *inst_tmp;
+ struct netcp_intf *netcp_intf, *netcp_tmp;
+ struct device *dev = netcp_device->device;
+
+ /* Release the module from each interface */
+ list_for_each_entry_safe(netcp_intf, netcp_tmp,
+ &netcp_device->interface_head,
+ interface_list) {
+ struct netcp_intf_modpriv *intf_modpriv, *intf_tmp;
+
+ list_for_each_entry_safe(intf_modpriv, intf_tmp,
+ &netcp_intf->module_head,
+ intf_list) {
+ if (intf_modpriv->netcp_module == module) {
+ module->release(intf_modpriv->module_priv);
+ list_del(&intf_modpriv->intf_list);
+ devm_kfree(dev, intf_modpriv);
+ break;
+ }
+ }
+ }
+
+ /* Remove the module from each instance */
+ list_for_each_entry_safe(inst_modpriv, inst_tmp,
+ &netcp_device->modpriv_head, inst_list) {
+ if (inst_modpriv->netcp_module == module) {
+ module->remove(netcp_device,
+ inst_modpriv->module_priv);
+ list_del(&inst_modpriv->inst_list);
+ devm_kfree(dev, inst_modpriv);
+ break;
+ }
+ }
+}
+
+void netcp_unregister_module(struct netcp_module *module)
+{
+ struct netcp_device *netcp_device;
+ struct netcp_module *module_tmp;
+
+ mutex_lock(&netcp_modules_lock);
+
+ list_for_each_entry(netcp_device, &netcp_devices, device_list) {
+ netcp_release_module(netcp_device, module);
+ }
+
+ /* Remove the module from the module list */
+ for_each_netcp_module(module_tmp) {
+ if (module == module_tmp) {
+ list_del(&module->module_list);
+ break;
+ }
+ }
+
+ mutex_unlock(&netcp_modules_lock);
+}
+EXPORT_SYMBOL_GPL(netcp_unregister_module);
+
+void *netcp_module_get_intf_data(struct netcp_module *module,
+ struct netcp_intf *intf)
+{
+ struct netcp_intf_modpriv *intf_modpriv;
+
+ list_for_each_entry(intf_modpriv, &intf->module_head, intf_list)
+ if (intf_modpriv->netcp_module == module)
+ return intf_modpriv->module_priv;
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(netcp_module_get_intf_data);
+
+/* Module TX and RX Hook management */
+struct netcp_hook_list {
+ struct list_head list;
+ netcp_hook_rtn *hook_rtn;
+ void *hook_data;
+ int order;
+};
+
+int netcp_register_txhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data)
+{
+ struct netcp_hook_list *entry;
+ struct netcp_hook_list *next;
+ unsigned long flags;
+
+ entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->hook_rtn = hook_rtn;
+ entry->hook_data = hook_data;
+ entry->order = order;
+
+ spin_lock_irqsave(&netcp_priv->lock, flags);
+ list_for_each_entry(next, &netcp_priv->txhook_list_head, list) {
+ if (next->order > order)
+ break;
+ }
+ __list_add(&entry->list, next->list.prev, &next->list);
+ spin_unlock_irqrestore(&netcp_priv->lock, flags);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(netcp_register_txhook);
+
+int netcp_unregister_txhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data)
+{
+ struct netcp_hook_list *next, *n;
+ unsigned long flags;
+
+ spin_lock_irqsave(&netcp_priv->lock, flags);
+ list_for_each_entry_safe(next, n, &netcp_priv->txhook_list_head, list) {
+ if ((next->order == order) &&
+ (next->hook_rtn == hook_rtn) &&
+ (next->hook_data == hook_data)) {
+ list_del(&next->list);
+ spin_unlock_irqrestore(&netcp_priv->lock, flags);
+ devm_kfree(netcp_priv->dev, next);
+ return 0;
+ }
+ }
+ spin_unlock_irqrestore(&netcp_priv->lock, flags);
+ return -ENOENT;
+}
+EXPORT_SYMBOL_GPL(netcp_unregister_txhook);
+
+int netcp_register_rxhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data)
+{
+ struct netcp_hook_list *entry;
+ struct netcp_hook_list *next;
+ unsigned long flags;
+
+ entry = devm_kzalloc(netcp_priv->dev, sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->hook_rtn = hook_rtn;
+ entry->hook_data = hook_data;
+ entry->order = order;
+
+ spin_lock_irqsave(&netcp_priv->lock, flags);
+ list_for_each_entry(next, &netcp_priv->rxhook_list_head, list) {
+ if (next->order > order)
+ break;
+ }
+ __list_add(&entry->list, next->list.prev, &next->list);
+ spin_unlock_irqrestore(&netcp_priv->lock, flags);
+
+ return 0;
+}
+
+int netcp_unregister_rxhook(struct netcp_intf *netcp_priv, int order,
+ netcp_hook_rtn *hook_rtn, void *hook_data)
+{
+ struct netcp_hook_list *next, *n;
+ unsigned long flags;
+
+ spin_lock_irqsave(&netcp_priv->lock, flags);
+ list_for_each_entry_safe(next, n, &netcp_priv->rxhook_list_head, list) {
+ if ((next->order == order) &&
+ (next->hook_rtn == hook_rtn) &&
+ (next->hook_data == hook_data)) {
+ list_del(&next->list);
+ spin_unlock_irqrestore(&netcp_priv->lock, flags);
+ devm_kfree(netcp_priv->dev, next);
+ return 0;
+ }
+ }
+ spin_unlock_irqrestore(&netcp_priv->lock, flags);
+
+ return -ENOENT;
+}
+
+static void netcp_frag_free(bool is_frag, void *ptr)
+{
+ if (is_frag)
+ put_page(virt_to_head_page(ptr));
+ else
+ kfree(ptr);
+}
+
+static void netcp_free_rx_desc_chain(struct netcp_intf *netcp,
+ struct knav_dma_desc *desc)
+{
+ struct knav_dma_desc *ndesc;
+ dma_addr_t dma_desc, dma_buf;
+ unsigned int buf_len, dma_sz = sizeof(*ndesc);
+ void *buf_ptr;
+ u32 tmp;
+
+ get_words(&dma_desc, 1, &desc->next_desc);
+
+ while (dma_desc) {
+ ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz);
+ if (unlikely(!ndesc)) {
+ dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n");
+ break;
+ }
+ get_pkt_info(&dma_buf, &tmp, &dma_desc, ndesc);
+ get_pad_info((u32 *)&buf_ptr, &tmp, ndesc);
+ dma_unmap_page(netcp->dev, dma_buf, PAGE_SIZE, DMA_FROM_DEVICE);
+ __free_page(buf_ptr);
+ knav_pool_desc_put(netcp->rx_pool, desc);
+ }
+
+ get_pad_info((u32 *)&buf_ptr, &buf_len, desc);
+ if (buf_ptr)
+ netcp_frag_free(buf_len <= PAGE_SIZE, buf_ptr);
+ knav_pool_desc_put(netcp->rx_pool, desc);
+}
+
+static void netcp_empty_rx_queue(struct netcp_intf *netcp)
+{
+ struct knav_dma_desc *desc;
+ unsigned int dma_sz;
+ dma_addr_t dma;
+
+ for (; ;) {
+ dma = knav_queue_pop(netcp->rx_queue, &dma_sz);
+ if (!dma)
+ break;
+
+ desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz);
+ if (unlikely(!desc)) {
+ dev_err(netcp->ndev_dev, "%s: failed to unmap Rx desc\n",
+ __func__);
+ netcp->ndev->stats.rx_errors++;
+ continue;
+ }
+ netcp_free_rx_desc_chain(netcp, desc);
+ netcp->ndev->stats.rx_dropped++;
+ }
+}
+
+static int netcp_process_one_rx_packet(struct netcp_intf *netcp)
+{
+ unsigned int dma_sz, buf_len, org_buf_len;
+ struct knav_dma_desc *desc, *ndesc;
+ unsigned int pkt_sz = 0, accum_sz;
+ struct netcp_hook_list *rx_hook;
+ dma_addr_t dma_desc, dma_buff;
+ struct netcp_packet p_info;
+ struct sk_buff *skb;
+ void *org_buf_ptr;
+ u32 tmp;
+
+ dma_desc = knav_queue_pop(netcp->rx_queue, &dma_sz);
+ if (!dma_desc)
+ return -1;
+
+ desc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz);
+ if (unlikely(!desc)) {
+ dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n");
+ return 0;
+ }
+
+ get_pkt_info(&dma_buff, &buf_len, &dma_desc, desc);
+ get_pad_info((u32 *)&org_buf_ptr, &org_buf_len, desc);
+
+ if (unlikely(!org_buf_ptr)) {
+ dev_err(netcp->ndev_dev, "NULL bufptr in desc\n");
+ goto free_desc;
+ }
+
+ pkt_sz &= KNAV_DMA_DESC_PKT_LEN_MASK;
+ accum_sz = buf_len;
+ dma_unmap_single(netcp->dev, dma_buff, buf_len, DMA_FROM_DEVICE);
+
+ /* Build a new sk_buff for the primary buffer */
+ skb = build_skb(org_buf_ptr, org_buf_len);
+ if (unlikely(!skb)) {
+ dev_err(netcp->ndev_dev, "build_skb() failed\n");
+ goto free_desc;
+ }
+
+ /* update data, tail and len */
+ skb_reserve(skb, NETCP_SOP_OFFSET);
+ __skb_put(skb, buf_len);
+
+ /* Fill in the page fragment list */
+ while (dma_desc) {
+ struct page *page;
+
+ ndesc = knav_pool_desc_unmap(netcp->rx_pool, dma_desc, dma_sz);
+ if (unlikely(!ndesc)) {
+ dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n");
+ goto free_desc;
+ }
+
+ get_pkt_info(&dma_buff, &buf_len, &dma_desc, ndesc);
+ get_pad_info((u32 *)&page, &tmp, ndesc);
+
+ if (likely(dma_buff && buf_len && page)) {
+ dma_unmap_page(netcp->dev, dma_buff, PAGE_SIZE,
+ DMA_FROM_DEVICE);
+ } else {
+ dev_err(netcp->ndev_dev, "Bad Rx desc dma_buff(%p), len(%d), page(%p)\n",
+ (void *)dma_buff, buf_len, page);
+ goto free_desc;
+ }
+
+ skb_add_rx_frag(skb, skb_shinfo(skb)->nr_frags, page,
+ offset_in_page(dma_buff), buf_len, PAGE_SIZE);
+ accum_sz += buf_len;
+
+ /* Free the descriptor */
+ knav_pool_desc_put(netcp->rx_pool, ndesc);
+ }
+
+ /* Free the primary descriptor */
+ knav_pool_desc_put(netcp->rx_pool, desc);
+
+ /* check for packet len and warn */
+ if (unlikely(pkt_sz != accum_sz))
+ dev_dbg(netcp->ndev_dev, "mismatch in packet size(%d) & sum of fragments(%d)\n",
+ pkt_sz, accum_sz);
+
+ /* Remove ethernet FCS from the packet */
+ __pskb_trim(skb, skb->len - ETH_FCS_LEN);
+
+ /* Call each of the RX hooks */
+ p_info.skb = skb;
+ p_info.rxtstamp_complete = false;
+ list_for_each_entry(rx_hook, &netcp->rxhook_list_head, list) {
+ int ret;
+
+ ret = rx_hook->hook_rtn(rx_hook->order, rx_hook->hook_data,
+ &p_info);
+ if (unlikely(ret)) {
+ dev_err(netcp->ndev_dev, "RX hook %d failed: %d\n",
+ rx_hook->order, ret);
+ netcp->ndev->stats.rx_errors++;
+ dev_kfree_skb(skb);
+ return 0;
+ }
+ }
+
+ netcp->ndev->last_rx = jiffies;
+ netcp->ndev->stats.rx_packets++;
+ netcp->ndev->stats.rx_bytes += skb->len;
+
+ /* push skb up the stack */
+ skb->protocol = eth_type_trans(skb, netcp->ndev);
+ netif_receive_skb(skb);
+ return 0;
+
+free_desc:
+ netcp_free_rx_desc_chain(netcp, desc);
+ netcp->ndev->stats.rx_errors++;
+ return 0;
+}
+
+static int netcp_process_rx_packets(struct netcp_intf *netcp,
+ unsigned int budget)
+{
+ int i;
+
+ for (i = 0; (i < budget) && !netcp_process_one_rx_packet(netcp); i++)
+ ;
+ return i;
+}
+
+/* Release descriptors and attached buffers from Rx FDQ */
+static void netcp_free_rx_buf(struct netcp_intf *netcp, int fdq)
+{
+ struct knav_dma_desc *desc;
+ unsigned int buf_len, dma_sz;
+ dma_addr_t dma;
+ void *buf_ptr;
+ u32 tmp;
+
+ /* Allocate descriptor */
+ while ((dma = knav_queue_pop(netcp->rx_fdq[fdq], &dma_sz))) {
+ desc = knav_pool_desc_unmap(netcp->rx_pool, dma, dma_sz);
+ if (unlikely(!desc)) {
+ dev_err(netcp->ndev_dev, "failed to unmap Rx desc\n");
+ continue;
+ }
+
+ get_org_pkt_info(&dma, &buf_len, desc);
+ get_pad_info((u32 *)&buf_ptr, &tmp, desc);
+
+ if (unlikely(!dma)) {
+ dev_err(netcp->ndev_dev, "NULL orig_buff in desc\n");
+ knav_pool_desc_put(netcp->rx_pool, desc);
+ continue;
+ }
+
+ if (unlikely(!buf_ptr)) {
+ dev_err(netcp->ndev_dev, "NULL bufptr in desc\n");
+ knav_pool_desc_put(netcp->rx_pool, desc);
+ continue;
+ }
+
+ if (fdq == 0) {
+ dma_unmap_single(netcp->dev, dma, buf_len,
+ DMA_FROM_DEVICE);
+ netcp_frag_free((buf_len <= PAGE_SIZE), buf_ptr);
+ } else {
+ dma_unmap_page(netcp->dev, dma, buf_len,
+ DMA_FROM_DEVICE);
+ __free_page(buf_ptr);
+ }
+
+ knav_pool_desc_put(netcp->rx_pool, desc);
+ }
+}
+
+static void netcp_rxpool_free(struct netcp_intf *netcp)
+{
+ int i;
+
+ for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN &&
+ !IS_ERR_OR_NULL(netcp->rx_fdq[i]); i++)
+ netcp_free_rx_buf(netcp, i);
+
+ if (knav_pool_count(netcp->rx_pool) != netcp->rx_pool_size)
+ dev_err(netcp->ndev_dev, "Lost Rx (%d) descriptors\n",
+ netcp->rx_pool_size - knav_pool_count(netcp->rx_pool));
+
+ knav_pool_destroy(netcp->rx_pool);
+ netcp->rx_pool = NULL;
+}
+
+static void netcp_allocate_rx_buf(struct netcp_intf *netcp, int fdq)
+{
+ struct knav_dma_desc *hwdesc;
+ unsigned int buf_len, dma_sz;
+ u32 desc_info, pkt_info;
+ struct page *page;
+ dma_addr_t dma;
+ void *bufptr;
+ u32 pad[2];
+
+ /* Allocate descriptor */
+ hwdesc = knav_pool_desc_get(netcp->rx_pool);
+ if (IS_ERR_OR_NULL(hwdesc)) {
+ dev_dbg(netcp->ndev_dev, "out of rx pool desc\n");
+ return;
+ }
+
+ if (likely(fdq == 0)) {
+ unsigned int primary_buf_len;
+ /* Allocate a primary receive queue entry */
+ buf_len = netcp->rx_buffer_sizes[0] + NETCP_SOP_OFFSET;
+ primary_buf_len = SKB_DATA_ALIGN(buf_len) +
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info));
+
+ if (primary_buf_len <= PAGE_SIZE) {
+ bufptr = netdev_alloc_frag(primary_buf_len);
+ pad[1] = primary_buf_len;
+ } else {
+ bufptr = kmalloc(primary_buf_len, GFP_ATOMIC |
+ GFP_DMA32 | __GFP_COLD);
+ pad[1] = 0;
+ }
+
+ if (unlikely(!bufptr)) {
+ dev_warn_ratelimited(netcp->ndev_dev, "Primary RX buffer alloc failed\n");
+ goto fail;
+ }
+ dma = dma_map_single(netcp->dev, bufptr, buf_len,
+ DMA_TO_DEVICE);
+ pad[0] = (u32)bufptr;
+
+ } else {
+ /* Allocate a secondary receive queue entry */
+ page = alloc_page(GFP_ATOMIC | GFP_DMA32 | __GFP_COLD);
+ if (unlikely(!page)) {
+ dev_warn_ratelimited(netcp->ndev_dev, "Secondary page alloc failed\n");
+ goto fail;
+ }
+ buf_len = PAGE_SIZE;
+ dma = dma_map_page(netcp->dev, page, 0, buf_len, DMA_TO_DEVICE);
+ pad[0] = (u32)page;
+ pad[1] = 0;
+ }
+
+ desc_info = KNAV_DMA_DESC_PS_INFO_IN_DESC;
+ desc_info |= buf_len & KNAV_DMA_DESC_PKT_LEN_MASK;
+ pkt_info = KNAV_DMA_DESC_HAS_EPIB;
+ pkt_info |= KNAV_DMA_NUM_PS_WORDS << KNAV_DMA_DESC_PSLEN_SHIFT;
+ pkt_info |= (netcp->rx_queue_id & KNAV_DMA_DESC_RETQ_MASK) <<
+ KNAV_DMA_DESC_RETQ_SHIFT;
+ set_org_pkt_info(dma, buf_len, hwdesc);
+ set_pad_info(pad[0], pad[1], hwdesc);
+ set_desc_info(desc_info, pkt_info, hwdesc);
+
+ /* Push to FDQs */
+ knav_pool_desc_map(netcp->rx_pool, hwdesc, sizeof(*hwdesc), &dma,
+ &dma_sz);
+ knav_queue_push(netcp->rx_fdq[fdq], dma, sizeof(*hwdesc), 0);
+ return;
+
+fail:
+ knav_pool_desc_put(netcp->rx_pool, hwdesc);
+}
+
+/* Refill Rx FDQ with descriptors & attached buffers */
+static void netcp_rxpool_refill(struct netcp_intf *netcp)
+{
+ u32 fdq_deficit[KNAV_DMA_FDQ_PER_CHAN] = {0};
+ int i;
+
+ /* Calculate the FDQ deficit and refill */
+ for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN && netcp->rx_fdq[i]; i++) {
+ fdq_deficit[i] = netcp->rx_queue_depths[i] -
+ knav_queue_get_count(netcp->rx_fdq[i]);
+
+ while (fdq_deficit[i]--)
+ netcp_allocate_rx_buf(netcp, i);
+ } /* end for fdqs */
+}
+
+/* NAPI poll */
+static int netcp_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct netcp_intf *netcp = container_of(napi, struct netcp_intf,
+ rx_napi);
+ unsigned int packets;
+
+ packets = netcp_process_rx_packets(netcp, budget);
+
+ if (packets < budget) {
+ napi_complete(&netcp->rx_napi);
+ knav_queue_enable_notify(netcp->rx_queue);
+ }
+
+ netcp_rxpool_refill(netcp);
+ return packets;
+}
+
+static void netcp_rx_notify(void *arg)
+{
+ struct netcp_intf *netcp = arg;
+
+ knav_queue_disable_notify(netcp->rx_queue);
+ napi_schedule(&netcp->rx_napi);
+}
+
+static void netcp_free_tx_desc_chain(struct netcp_intf *netcp,
+ struct knav_dma_desc *desc,
+ unsigned int desc_sz)
+{
+ struct knav_dma_desc *ndesc = desc;
+ dma_addr_t dma_desc, dma_buf;
+ unsigned int buf_len;
+
+ while (ndesc) {
+ get_pkt_info(&dma_buf, &buf_len, &dma_desc, ndesc);
+
+ if (dma_buf && buf_len)
+ dma_unmap_single(netcp->dev, dma_buf, buf_len,
+ DMA_TO_DEVICE);
+ else
+ dev_warn(netcp->ndev_dev, "bad Tx desc buf(%p), len(%d)\n",
+ (void *)dma_buf, buf_len);
+
+ knav_pool_desc_put(netcp->tx_pool, ndesc);
+ ndesc = NULL;
+ if (dma_desc) {
+ ndesc = knav_pool_desc_unmap(netcp->tx_pool, dma_desc,
+ desc_sz);
+ if (!ndesc)
+ dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n");
+ }
+ }
+}
+
+static int netcp_process_tx_compl_packets(struct netcp_intf *netcp,
+ unsigned int budget)
+{
+ struct knav_dma_desc *desc;
+ struct sk_buff *skb;
+ unsigned int dma_sz;
+ dma_addr_t dma;
+ int pkts = 0;
+ u32 tmp;
+
+ while (budget--) {
+ dma = knav_queue_pop(netcp->tx_compl_q, &dma_sz);
+ if (!dma)
+ break;
+ desc = knav_pool_desc_unmap(netcp->tx_pool, dma, dma_sz);
+ if (unlikely(!desc)) {
+ dev_err(netcp->ndev_dev, "failed to unmap Tx desc\n");
+ netcp->ndev->stats.tx_errors++;
+ continue;
+ }
+
+ get_pad_info((u32 *)&skb, &tmp, desc);
+ netcp_free_tx_desc_chain(netcp, desc, dma_sz);
+ if (!skb) {
+ dev_err(netcp->ndev_dev, "No skb in Tx desc\n");
+ netcp->ndev->stats.tx_errors++;
+ continue;
+ }
+
+ if (netif_subqueue_stopped(netcp->ndev, skb) &&
+ netif_running(netcp->ndev) &&
+ (knav_pool_count(netcp->tx_pool) >
+ netcp->tx_resume_threshold)) {
+ u16 subqueue = skb_get_queue_mapping(skb);
+
+ netif_wake_subqueue(netcp->ndev, subqueue);
+ }
+
+ netcp->ndev->stats.tx_packets++;
+ netcp->ndev->stats.tx_bytes += skb->len;
+ dev_kfree_skb(skb);
+ pkts++;
+ }
+ return pkts;
+}
+
+static int netcp_tx_poll(struct napi_struct *napi, int budget)
+{
+ int packets;
+ struct netcp_intf *netcp = container_of(napi, struct netcp_intf,
+ tx_napi);
+
+ packets = netcp_process_tx_compl_packets(netcp, budget);
+ if (packets < budget) {
+ napi_complete(&netcp->tx_napi);
+ knav_queue_enable_notify(netcp->tx_compl_q);
+ }
+
+ return packets;
+}
+
+static void netcp_tx_notify(void *arg)
+{
+ struct netcp_intf *netcp = arg;
+
+ knav_queue_disable_notify(netcp->tx_compl_q);
+ napi_schedule(&netcp->tx_napi);
+}
+
+static struct knav_dma_desc*
+netcp_tx_map_skb(struct sk_buff *skb, struct netcp_intf *netcp)
+{
+ struct knav_dma_desc *desc, *ndesc, *pdesc;
+ unsigned int pkt_len = skb_headlen(skb);
+ struct device *dev = netcp->dev;
+ dma_addr_t dma_addr;
+ unsigned int dma_sz;
+ int i;
+
+ /* Map the linear buffer */
+ dma_addr = dma_map_single(dev, skb->data, pkt_len, DMA_TO_DEVICE);
+ if (unlikely(!dma_addr)) {
+ dev_err(netcp->ndev_dev, "Failed to map skb buffer\n");
+ return NULL;
+ }
+
+ desc = knav_pool_desc_get(netcp->tx_pool);
+ if (unlikely(IS_ERR_OR_NULL(desc))) {
+ dev_err(netcp->ndev_dev, "out of TX desc\n");
+ dma_unmap_single(dev, dma_addr, pkt_len, DMA_TO_DEVICE);
+ return NULL;
+ }
+
+ set_pkt_info(dma_addr, pkt_len, 0, desc);
+ if (skb_is_nonlinear(skb)) {
+ prefetchw(skb_shinfo(skb));
+ } else {
+ desc->next_desc = 0;
+ goto upd_pkt_len;
+ }
+
+ pdesc = desc;
+
+ /* Handle the case where skb is fragmented in pages */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ struct page *page = skb_frag_page(frag);
+ u32 page_offset = frag->page_offset;
+ u32 buf_len = skb_frag_size(frag);
+ dma_addr_t desc_dma;
+ u32 pkt_info;
+
+ dma_addr = dma_map_page(dev, page, page_offset, buf_len,
+ DMA_TO_DEVICE);
+ if (unlikely(!dma_addr)) {
+ dev_err(netcp->ndev_dev, "Failed to map skb page\n");
+ goto free_descs;
+ }
+
+ ndesc = knav_pool_desc_get(netcp->tx_pool);
+ if (unlikely(IS_ERR_OR_NULL(ndesc))) {
+ dev_err(netcp->ndev_dev, "out of TX desc for frags\n");
+ dma_unmap_page(dev, dma_addr, buf_len, DMA_TO_DEVICE);
+ goto free_descs;
+ }
+
+ desc_dma = knav_pool_desc_virt_to_dma(netcp->tx_pool,
+ (void *)ndesc);
+ pkt_info =
+ (netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) <<
+ KNAV_DMA_DESC_RETQ_SHIFT;
+ set_pkt_info(dma_addr, buf_len, 0, ndesc);
+ set_words(&desc_dma, 1, &pdesc->next_desc);
+ pkt_len += buf_len;
+ if (pdesc != desc)
+ knav_pool_desc_map(netcp->tx_pool, pdesc,
+ sizeof(*pdesc), &desc_dma, &dma_sz);
+ pdesc = ndesc;
+ }
+ if (pdesc != desc)
+ knav_pool_desc_map(netcp->tx_pool, pdesc, sizeof(*pdesc),
+ &dma_addr, &dma_sz);
+
+ /* frag list based linkage is not supported for now. */
+ if (skb_shinfo(skb)->frag_list) {
+ dev_err_ratelimited(netcp->ndev_dev, "NETIF_F_FRAGLIST not supported\n");
+ goto free_descs;
+ }
+
+upd_pkt_len:
+ WARN_ON(pkt_len != skb->len);
+
+ pkt_len &= KNAV_DMA_DESC_PKT_LEN_MASK;
+ set_words(&pkt_len, 1, &desc->desc_info);
+ return desc;
+
+free_descs:
+ netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc));
+ return NULL;
+}
+
+static int netcp_tx_submit_skb(struct netcp_intf *netcp,
+ struct sk_buff *skb,
+ struct knav_dma_desc *desc)
+{
+ struct netcp_tx_pipe *tx_pipe = NULL;
+ struct netcp_hook_list *tx_hook;
+ struct netcp_packet p_info;
+ u32 packet_info = 0;
+ unsigned int dma_sz;
+ dma_addr_t dma;
+ int ret = 0;
+
+ p_info.netcp = netcp;
+ p_info.skb = skb;
+ p_info.tx_pipe = NULL;
+ p_info.psdata_len = 0;
+ p_info.ts_context = NULL;
+ p_info.txtstamp_complete = NULL;
+ p_info.epib = desc->epib;
+ p_info.psdata = desc->psdata;
+ memset(p_info.epib, 0, KNAV_DMA_NUM_EPIB_WORDS * sizeof(u32));
+
+ /* Find out where to inject the packet for transmission */
+ list_for_each_entry(tx_hook, &netcp->txhook_list_head, list) {
+ ret = tx_hook->hook_rtn(tx_hook->order, tx_hook->hook_data,
+ &p_info);
+ if (unlikely(ret != 0)) {
+ dev_err(netcp->ndev_dev, "TX hook %d rejected the packet with reason(%d)\n",
+ tx_hook->order, ret);
+ ret = (ret < 0) ? ret : NETDEV_TX_OK;
+ goto out;
+ }
+ }
+
+ /* Make sure some TX hook claimed the packet */
+ tx_pipe = p_info.tx_pipe;
+ if (!tx_pipe) {
+ dev_err(netcp->ndev_dev, "No TX hook claimed the packet!\n");
+ ret = -ENXIO;
+ goto out;
+ }
+
+ /* update descriptor */
+ if (p_info.psdata_len) {
+ u32 *psdata = p_info.psdata;
+
+ memmove(p_info.psdata, p_info.psdata + p_info.psdata_len,
+ p_info.psdata_len);
+ set_words(psdata, p_info.psdata_len, psdata);
+ packet_info |=
+ (p_info.psdata_len & KNAV_DMA_DESC_PSLEN_MASK) <<
+ KNAV_DMA_DESC_PSLEN_SHIFT;
+ }
+
+ packet_info |= KNAV_DMA_DESC_HAS_EPIB |
+ ((netcp->tx_compl_qid & KNAV_DMA_DESC_RETQ_MASK) <<
+ KNAV_DMA_DESC_RETQ_SHIFT) |
+ ((tx_pipe->dma_psflags & KNAV_DMA_DESC_PSFLAG_MASK) <<
+ KNAV_DMA_DESC_PSFLAG_SHIFT);
+
+ set_words(&packet_info, 1, &desc->packet_info);
+ set_words((u32 *)&skb, 1, &desc->pad[0]);
+
+ /* submit packet descriptor */
+ ret = knav_pool_desc_map(netcp->tx_pool, desc, sizeof(*desc), &dma,
+ &dma_sz);
+ if (unlikely(ret)) {
+ dev_err(netcp->ndev_dev, "%s() failed to map desc\n", __func__);
+ ret = -ENOMEM;
+ goto out;
+ }
+ skb_tx_timestamp(skb);
+ knav_queue_push(tx_pipe->dma_queue, dma, dma_sz, 0);
+
+out:
+ return ret;
+}
+
+/* Submit the packet */
+static int netcp_ndo_start_xmit(struct sk_buff *skb, struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ int subqueue = skb_get_queue_mapping(skb);
+ struct knav_dma_desc *desc;
+ int desc_count, ret = 0;
+
+ if (unlikely(skb->len <= 0)) {
+ dev_kfree_skb(skb);
+ return NETDEV_TX_OK;
+ }
+
+ if (unlikely(skb->len < NETCP_MIN_PACKET_SIZE)) {
+ ret = skb_padto(skb, NETCP_MIN_PACKET_SIZE);
+ if (ret < 0) {
+ /* If we get here, the skb has already been dropped */
+ dev_warn(netcp->ndev_dev, "padding failed (%d), packet dropped\n",
+ ret);
+ ndev->stats.tx_dropped++;
+ return ret;
+ }
+ skb->len = NETCP_MIN_PACKET_SIZE;
+ }
+
+ desc = netcp_tx_map_skb(skb, netcp);
+ if (unlikely(!desc)) {
+ netif_stop_subqueue(ndev, subqueue);
+ ret = -ENOBUFS;
+ goto drop;
+ }
+
+ ret = netcp_tx_submit_skb(netcp, skb, desc);
+ if (ret)
+ goto drop;
+
+ ndev->trans_start = jiffies;
+
+ /* Check Tx pool count & stop subqueue if needed */
+ desc_count = knav_pool_count(netcp->tx_pool);
+ if (desc_count < netcp->tx_pause_threshold) {
+ dev_dbg(netcp->ndev_dev, "pausing tx, count(%d)\n", desc_count);
+ netif_stop_subqueue(ndev, subqueue);
+ }
+ return NETDEV_TX_OK;
+
+drop:
+ ndev->stats.tx_dropped++;
+ if (desc)
+ netcp_free_tx_desc_chain(netcp, desc, sizeof(*desc));
+ dev_kfree_skb(skb);
+ return ret;
+}
+
+int netcp_txpipe_close(struct netcp_tx_pipe *tx_pipe)
+{
+ if (tx_pipe->dma_channel) {
+ knav_dma_close_channel(tx_pipe->dma_channel);
+ tx_pipe->dma_channel = NULL;
+ }
+ return 0;
+}
+EXPORT_SYMBOL_GPL(netcp_txpipe_close);
+
+int netcp_txpipe_open(struct netcp_tx_pipe *tx_pipe)
+{
+ struct device *dev = tx_pipe->netcp_device->device;
+ struct knav_dma_cfg config;
+ int ret = 0;
+ u8 name[16];
+
+ memset(&config, 0, sizeof(config));
+ config.direction = DMA_MEM_TO_DEV;
+ config.u.tx.filt_einfo = false;
+ config.u.tx.filt_pswords = false;
+ config.u.tx.priority = DMA_PRIO_MED_L;
+
+ tx_pipe->dma_channel = knav_dma_open_channel(dev,
+ tx_pipe->dma_chan_name, &config);
+ if (IS_ERR_OR_NULL(tx_pipe->dma_channel)) {
+ dev_err(dev, "failed opening tx chan(%s)\n",
+ tx_pipe->dma_chan_name);
+ goto err;
+ }
+
+ snprintf(name, sizeof(name), "tx-pipe-%s", dev_name(dev));
+ tx_pipe->dma_queue = knav_queue_open(name, tx_pipe->dma_queue_id,
+ KNAV_QUEUE_SHARED);
+ if (IS_ERR(tx_pipe->dma_queue)) {
+ dev_err(dev, "Could not open DMA queue for channel \"%s\": %d\n",
+ name, ret);
+ ret = PTR_ERR(tx_pipe->dma_queue);
+ goto err;
+ }
+
+ dev_dbg(dev, "opened tx pipe %s\n", name);
+ return 0;
+
+err:
+ if (!IS_ERR_OR_NULL(tx_pipe->dma_channel))
+ knav_dma_close_channel(tx_pipe->dma_channel);
+ tx_pipe->dma_channel = NULL;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(netcp_txpipe_open);
+
+int netcp_txpipe_init(struct netcp_tx_pipe *tx_pipe,
+ struct netcp_device *netcp_device,
+ const char *dma_chan_name, unsigned int dma_queue_id)
+{
+ memset(tx_pipe, 0, sizeof(*tx_pipe));
+ tx_pipe->netcp_device = netcp_device;
+ tx_pipe->dma_chan_name = dma_chan_name;
+ tx_pipe->dma_queue_id = dma_queue_id;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(netcp_txpipe_init);
+
+static struct netcp_addr *netcp_addr_find(struct netcp_intf *netcp,
+ const u8 *addr,
+ enum netcp_addr_type type)
+{
+ struct netcp_addr *naddr;
+
+ list_for_each_entry(naddr, &netcp->addr_list, node) {
+ if (naddr->type != type)
+ continue;
+ if (addr && memcmp(addr, naddr->addr, ETH_ALEN))
+ continue;
+ return naddr;
+ }
+
+ return NULL;
+}
+
+static struct netcp_addr *netcp_addr_add(struct netcp_intf *netcp,
+ const u8 *addr,
+ enum netcp_addr_type type)
+{
+ struct netcp_addr *naddr;
+
+ naddr = devm_kmalloc(netcp->dev, sizeof(*naddr), GFP_ATOMIC);
+ if (!naddr)
+ return NULL;
+
+ naddr->type = type;
+ naddr->flags = 0;
+ naddr->netcp = netcp;
+ if (addr)
+ ether_addr_copy(naddr->addr, addr);
+ else
+ memset(naddr->addr, 0, ETH_ALEN);
+ list_add_tail(&naddr->node, &netcp->addr_list);
+
+ return naddr;
+}
+
+static void netcp_addr_del(struct netcp_intf *netcp, struct netcp_addr *naddr)
+{
+ list_del(&naddr->node);
+ devm_kfree(netcp->dev, naddr);
+}
+
+static void netcp_addr_clear_mark(struct netcp_intf *netcp)
+{
+ struct netcp_addr *naddr;
+
+ list_for_each_entry(naddr, &netcp->addr_list, node)
+ naddr->flags = 0;
+}
+
+static void netcp_addr_add_mark(struct netcp_intf *netcp, const u8 *addr,
+ enum netcp_addr_type type)
+{
+ struct netcp_addr *naddr;
+
+ naddr = netcp_addr_find(netcp, addr, type);
+ if (naddr) {
+ naddr->flags |= ADDR_VALID;
+ return;
+ }
+
+ naddr = netcp_addr_add(netcp, addr, type);
+ if (!WARN_ON(!naddr))
+ naddr->flags |= ADDR_NEW;
+}
+
+static void netcp_addr_sweep_del(struct netcp_intf *netcp)
+{
+ struct netcp_addr *naddr, *tmp;
+ struct netcp_intf_modpriv *priv;
+ struct netcp_module *module;
+ int error;
+
+ list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) {
+ if (naddr->flags & (ADDR_VALID | ADDR_NEW))
+ continue;
+ dev_dbg(netcp->ndev_dev, "deleting address %pM, type %x\n",
+ naddr->addr, naddr->type);
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, priv) {
+ module = priv->netcp_module;
+ if (!module->del_addr)
+ continue;
+ error = module->del_addr(priv->module_priv,
+ naddr);
+ WARN_ON(error);
+ }
+ mutex_unlock(&netcp_modules_lock);
+ netcp_addr_del(netcp, naddr);
+ }
+}
+
+static void netcp_addr_sweep_add(struct netcp_intf *netcp)
+{
+ struct netcp_addr *naddr, *tmp;
+ struct netcp_intf_modpriv *priv;
+ struct netcp_module *module;
+ int error;
+
+ list_for_each_entry_safe(naddr, tmp, &netcp->addr_list, node) {
+ if (!(naddr->flags & ADDR_NEW))
+ continue;
+ dev_dbg(netcp->ndev_dev, "adding address %pM, type %x\n",
+ naddr->addr, naddr->type);
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, priv) {
+ module = priv->netcp_module;
+ if (!module->add_addr)
+ continue;
+ error = module->add_addr(priv->module_priv, naddr);
+ WARN_ON(error);
+ }
+ mutex_unlock(&netcp_modules_lock);
+ }
+}
+
+static void netcp_set_rx_mode(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netdev_hw_addr *ndev_addr;
+ bool promisc;
+
+ promisc = (ndev->flags & IFF_PROMISC ||
+ ndev->flags & IFF_ALLMULTI ||
+ netdev_mc_count(ndev) > NETCP_MAX_MCAST_ADDR);
+
+ /* first clear all marks */
+ netcp_addr_clear_mark(netcp);
+
+ /* next add new entries, mark existing ones */
+ netcp_addr_add_mark(netcp, ndev->broadcast, ADDR_BCAST);
+ for_each_dev_addr(ndev, ndev_addr)
+ netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_DEV);
+ netdev_for_each_uc_addr(ndev_addr, ndev)
+ netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_UCAST);
+ netdev_for_each_mc_addr(ndev_addr, ndev)
+ netcp_addr_add_mark(netcp, ndev_addr->addr, ADDR_MCAST);
+
+ if (promisc)
+ netcp_addr_add_mark(netcp, NULL, ADDR_ANY);
+
+ /* finally sweep and callout into modules */
+ netcp_addr_sweep_del(netcp);
+ netcp_addr_sweep_add(netcp);
+}
+
+static void netcp_free_navigator_resources(struct netcp_intf *netcp)
+{
+ int i;
+
+ if (netcp->rx_channel) {
+ knav_dma_close_channel(netcp->rx_channel);
+ netcp->rx_channel = NULL;
+ }
+
+ if (!IS_ERR_OR_NULL(netcp->rx_pool))
+ netcp_rxpool_free(netcp);
+
+ if (!IS_ERR_OR_NULL(netcp->rx_queue)) {
+ knav_queue_close(netcp->rx_queue);
+ netcp->rx_queue = NULL;
+ }
+
+ for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN &&
+ !IS_ERR_OR_NULL(netcp->rx_fdq[i]) ; ++i) {
+ knav_queue_close(netcp->rx_fdq[i]);
+ netcp->rx_fdq[i] = NULL;
+ }
+
+ if (!IS_ERR_OR_NULL(netcp->tx_compl_q)) {
+ knav_queue_close(netcp->tx_compl_q);
+ netcp->tx_compl_q = NULL;
+ }
+
+ if (!IS_ERR_OR_NULL(netcp->tx_pool)) {
+ knav_pool_destroy(netcp->tx_pool);
+ netcp->tx_pool = NULL;
+ }
+}
+
+static int netcp_setup_navigator_resources(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct knav_queue_notify_config notify_cfg;
+ struct knav_dma_cfg config;
+ u32 last_fdq = 0;
+ u8 name[16];
+ int ret;
+ int i;
+
+ /* Create Rx/Tx descriptor pools */
+ snprintf(name, sizeof(name), "rx-pool-%s", ndev->name);
+ netcp->rx_pool = knav_pool_create(name, netcp->rx_pool_size,
+ netcp->rx_pool_region_id);
+ if (IS_ERR_OR_NULL(netcp->rx_pool)) {
+ dev_err(netcp->ndev_dev, "Couldn't create rx pool\n");
+ ret = PTR_ERR(netcp->rx_pool);
+ goto fail;
+ }
+
+ snprintf(name, sizeof(name), "tx-pool-%s", ndev->name);
+ netcp->tx_pool = knav_pool_create(name, netcp->tx_pool_size,
+ netcp->tx_pool_region_id);
+ if (IS_ERR_OR_NULL(netcp->tx_pool)) {
+ dev_err(netcp->ndev_dev, "Couldn't create tx pool\n");
+ ret = PTR_ERR(netcp->tx_pool);
+ goto fail;
+ }
+
+ /* open Tx completion queue */
+ snprintf(name, sizeof(name), "tx-compl-%s", ndev->name);
+ netcp->tx_compl_q = knav_queue_open(name, netcp->tx_compl_qid, 0);
+ if (IS_ERR_OR_NULL(netcp->tx_compl_q)) {
+ ret = PTR_ERR(netcp->tx_compl_q);
+ goto fail;
+ }
+ netcp->tx_compl_qid = knav_queue_get_id(netcp->tx_compl_q);
+
+ /* Set notification for Tx completion */
+ notify_cfg.fn = netcp_tx_notify;
+ notify_cfg.fn_arg = netcp;
+ ret = knav_queue_device_control(netcp->tx_compl_q,
+ KNAV_QUEUE_SET_NOTIFIER,
+ (unsigned long)&notify_cfg);
+ if (ret)
+ goto fail;
+
+ knav_queue_disable_notify(netcp->tx_compl_q);
+
+ /* open Rx completion queue */
+ snprintf(name, sizeof(name), "rx-compl-%s", ndev->name);
+ netcp->rx_queue = knav_queue_open(name, netcp->rx_queue_id, 0);
+ if (IS_ERR_OR_NULL(netcp->rx_queue)) {
+ ret = PTR_ERR(netcp->rx_queue);
+ goto fail;
+ }
+ netcp->rx_queue_id = knav_queue_get_id(netcp->rx_queue);
+
+ /* Set notification for Rx completion */
+ notify_cfg.fn = netcp_rx_notify;
+ notify_cfg.fn_arg = netcp;
+ ret = knav_queue_device_control(netcp->rx_queue,
+ KNAV_QUEUE_SET_NOTIFIER,
+ (unsigned long)&notify_cfg);
+ if (ret)
+ goto fail;
+
+ knav_queue_disable_notify(netcp->rx_queue);
+
+ /* open Rx FDQs */
+ for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN &&
+ netcp->rx_queue_depths[i] && netcp->rx_buffer_sizes[i]; ++i) {
+ snprintf(name, sizeof(name), "rx-fdq-%s-%d", ndev->name, i);
+ netcp->rx_fdq[i] = knav_queue_open(name, KNAV_QUEUE_GP, 0);
+ if (IS_ERR_OR_NULL(netcp->rx_fdq[i])) {
+ ret = PTR_ERR(netcp->rx_fdq[i]);
+ goto fail;
+ }
+ }
+
+ memset(&config, 0, sizeof(config));
+ config.direction = DMA_DEV_TO_MEM;
+ config.u.rx.einfo_present = true;
+ config.u.rx.psinfo_present = true;
+ config.u.rx.err_mode = DMA_DROP;
+ config.u.rx.desc_type = DMA_DESC_HOST;
+ config.u.rx.psinfo_at_sop = false;
+ config.u.rx.sop_offset = NETCP_SOP_OFFSET;
+ config.u.rx.dst_q = netcp->rx_queue_id;
+ config.u.rx.thresh = DMA_THRESH_NONE;
+
+ for (i = 0; i < KNAV_DMA_FDQ_PER_CHAN; ++i) {
+ if (netcp->rx_fdq[i])
+ last_fdq = knav_queue_get_id(netcp->rx_fdq[i]);
+ config.u.rx.fdq[i] = last_fdq;
+ }
+
+ netcp->rx_channel = knav_dma_open_channel(netcp->netcp_device->device,
+ netcp->dma_chan_name, &config);
+ if (IS_ERR_OR_NULL(netcp->rx_channel)) {
+ dev_err(netcp->ndev_dev, "failed opening rx chan(%s\n",
+ netcp->dma_chan_name);
+ goto fail;
+ }
+
+ dev_dbg(netcp->ndev_dev, "opened RX channel: %p\n", netcp->rx_channel);
+ return 0;
+
+fail:
+ netcp_free_navigator_resources(netcp);
+ return ret;
+}
+
+/* Open the device */
+static int netcp_ndo_open(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_intf_modpriv *intf_modpriv;
+ struct netcp_module *module;
+ int ret;
+
+ netif_carrier_off(ndev);
+ ret = netcp_setup_navigator_resources(ndev);
+ if (ret) {
+ dev_err(netcp->ndev_dev, "Failed to setup navigator resources\n");
+ goto fail;
+ }
+
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, intf_modpriv) {
+ module = intf_modpriv->netcp_module;
+ if (module->open) {
+ ret = module->open(intf_modpriv->module_priv, ndev);
+ if (ret != 0) {
+ dev_err(netcp->ndev_dev, "module open failed\n");
+ goto fail_open;
+ }
+ }
+ }
+ mutex_unlock(&netcp_modules_lock);
+
+ netcp_rxpool_refill(netcp);
+ napi_enable(&netcp->rx_napi);
+ napi_enable(&netcp->tx_napi);
+ knav_queue_enable_notify(netcp->tx_compl_q);
+ knav_queue_enable_notify(netcp->rx_queue);
+ netif_tx_wake_all_queues(ndev);
+ dev_dbg(netcp->ndev_dev, "netcp device %s opened\n", ndev->name);
+ return 0;
+
+fail_open:
+ for_each_module(netcp, intf_modpriv) {
+ module = intf_modpriv->netcp_module;
+ if (module->close)
+ module->close(intf_modpriv->module_priv, ndev);
+ }
+ mutex_unlock(&netcp_modules_lock);
+
+fail:
+ netcp_free_navigator_resources(netcp);
+ return ret;
+}
+
+/* Close the device */
+static int netcp_ndo_stop(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_intf_modpriv *intf_modpriv;
+ struct netcp_module *module;
+ int err = 0;
+
+ netif_tx_stop_all_queues(ndev);
+ netif_carrier_off(ndev);
+ netcp_addr_clear_mark(netcp);
+ netcp_addr_sweep_del(netcp);
+ knav_queue_disable_notify(netcp->rx_queue);
+ knav_queue_disable_notify(netcp->tx_compl_q);
+ napi_disable(&netcp->rx_napi);
+ napi_disable(&netcp->tx_napi);
+
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, intf_modpriv) {
+ module = intf_modpriv->netcp_module;
+ if (module->close) {
+ err = module->close(intf_modpriv->module_priv, ndev);
+ if (err != 0)
+ dev_err(netcp->ndev_dev, "Close failed\n");
+ }
+ }
+ mutex_unlock(&netcp_modules_lock);
+
+ /* Recycle Rx descriptors from completion queue */
+ netcp_empty_rx_queue(netcp);
+
+ /* Recycle Tx descriptors from completion queue */
+ netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size);
+
+ if (knav_pool_count(netcp->tx_pool) != netcp->tx_pool_size)
+ dev_err(netcp->ndev_dev, "Lost (%d) Tx descs\n",
+ netcp->tx_pool_size - knav_pool_count(netcp->tx_pool));
+
+ netcp_free_navigator_resources(netcp);
+ dev_dbg(netcp->ndev_dev, "netcp device %s stopped\n", ndev->name);
+ return 0;
+}
+
+static int netcp_ndo_ioctl(struct net_device *ndev,
+ struct ifreq *req, int cmd)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_intf_modpriv *intf_modpriv;
+ struct netcp_module *module;
+ int ret = -1, err = -EOPNOTSUPP;
+
+ if (!netif_running(ndev))
+ return -EINVAL;
+
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, intf_modpriv) {
+ module = intf_modpriv->netcp_module;
+ if (!module->ioctl)
+ continue;
+
+ err = module->ioctl(intf_modpriv->module_priv, req, cmd);
+ if ((err < 0) && (err != -EOPNOTSUPP)) {
+ ret = err;
+ goto out;
+ }
+ if (err == 0)
+ ret = err;
+ }
+
+out:
+ mutex_unlock(&netcp_modules_lock);
+ return (ret == 0) ? 0 : err;
+}
+
+static int netcp_ndo_change_mtu(struct net_device *ndev, int new_mtu)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+
+ /* MTU < 68 is an error for IPv4 traffic */
+ if ((new_mtu < 68) ||
+ (new_mtu > (NETCP_MAX_FRAME_SIZE - ETH_HLEN - ETH_FCS_LEN))) {
+ dev_err(netcp->ndev_dev, "Invalid mtu size = %d\n", new_mtu);
+ return -EINVAL;
+ }
+
+ ndev->mtu = new_mtu;
+ return 0;
+}
+
+static void netcp_ndo_tx_timeout(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ unsigned int descs = knav_pool_count(netcp->tx_pool);
+
+ dev_err(netcp->ndev_dev, "transmit timed out tx descs(%d)\n", descs);
+ netcp_process_tx_compl_packets(netcp, netcp->tx_pool_size);
+ ndev->trans_start = jiffies;
+ netif_tx_wake_all_queues(ndev);
+}
+
+static int netcp_rx_add_vid(struct net_device *ndev, __be16 proto, u16 vid)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_intf_modpriv *intf_modpriv;
+ struct netcp_module *module;
+ int err = 0;
+
+ dev_dbg(netcp->ndev_dev, "adding rx vlan id: %d\n", vid);
+
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, intf_modpriv) {
+ module = intf_modpriv->netcp_module;
+ if ((module->add_vid) && (vid != 0)) {
+ err = module->add_vid(intf_modpriv->module_priv, vid);
+ if (err != 0) {
+ dev_err(netcp->ndev_dev, "Could not add vlan id = %d\n",
+ vid);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&netcp_modules_lock);
+ return err;
+}
+
+static int netcp_rx_kill_vid(struct net_device *ndev, __be16 proto, u16 vid)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_intf_modpriv *intf_modpriv;
+ struct netcp_module *module;
+ int err = 0;
+
+ dev_dbg(netcp->ndev_dev, "removing rx vlan id: %d\n", vid);
+
+ mutex_lock(&netcp_modules_lock);
+ for_each_module(netcp, intf_modpriv) {
+ module = intf_modpriv->netcp_module;
+ if (module->del_vid) {
+ err = module->del_vid(intf_modpriv->module_priv, vid);
+ if (err != 0) {
+ dev_err(netcp->ndev_dev, "Could not delete vlan id = %d\n",
+ vid);
+ break;
+ }
+ }
+ }
+ mutex_unlock(&netcp_modules_lock);
+ return err;
+}
+
+static u16 netcp_select_queue(struct net_device *dev, struct sk_buff *skb,
+ void *accel_priv,
+ select_queue_fallback_t fallback)
+{
+ return 0;
+}
+
+static int netcp_setup_tc(struct net_device *dev, u8 num_tc)
+{
+ int i;
+
+ /* setup tc must be called under rtnl lock */
+ ASSERT_RTNL();
+
+ /* Sanity-check the number of traffic classes requested */
+ if ((dev->real_num_tx_queues <= 1) ||
+ (dev->real_num_tx_queues < num_tc))
+ return -EINVAL;
+
+ /* Configure traffic class to queue mappings */
+ if (num_tc) {
+ netdev_set_num_tc(dev, num_tc);
+ for (i = 0; i < num_tc; i++)
+ netdev_set_tc_queue(dev, i, 1, i);
+ } else {
+ netdev_reset_tc(dev);
+ }
+
+ return 0;
+}
+
+static const struct net_device_ops netcp_netdev_ops = {
+ .ndo_open = netcp_ndo_open,
+ .ndo_stop = netcp_ndo_stop,
+ .ndo_start_xmit = netcp_ndo_start_xmit,
+ .ndo_set_rx_mode = netcp_set_rx_mode,
+ .ndo_do_ioctl = netcp_ndo_ioctl,
+ .ndo_change_mtu = netcp_ndo_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_vlan_rx_add_vid = netcp_rx_add_vid,
+ .ndo_vlan_rx_kill_vid = netcp_rx_kill_vid,
+ .ndo_tx_timeout = netcp_ndo_tx_timeout,
+ .ndo_select_queue = netcp_select_queue,
+ .ndo_setup_tc = netcp_setup_tc,
+};
+
+static int netcp_create_interface(struct netcp_device *netcp_device,
+ struct device_node *node_interface)
+{
+ struct device *dev = netcp_device->device;
+ struct device_node *node = dev->of_node;
+ struct netcp_intf *netcp;
+ struct net_device *ndev;
+ resource_size_t size;
+ struct resource res;
+ void __iomem *efuse = NULL;
+ u32 efuse_mac = 0;
+ const void *mac_addr;
+ u8 efuse_mac_addr[6];
+ u32 temp[2];
+ int ret = 0;
+
+ ndev = alloc_etherdev_mqs(sizeof(*netcp), 1, 1);
+ if (!ndev) {
+ dev_err(dev, "Error allocating netdev\n");
+ return -ENOMEM;
+ }
+
+ ndev->features |= NETIF_F_SG;
+ ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER;
+ ndev->hw_features = ndev->features;
+ ndev->vlan_features |= NETIF_F_SG;
+
+ netcp = netdev_priv(ndev);
+ spin_lock_init(&netcp->lock);
+ INIT_LIST_HEAD(&netcp->module_head);
+ INIT_LIST_HEAD(&netcp->txhook_list_head);
+ INIT_LIST_HEAD(&netcp->rxhook_list_head);
+ INIT_LIST_HEAD(&netcp->addr_list);
+ netcp->netcp_device = netcp_device;
+ netcp->dev = netcp_device->device;
+ netcp->ndev = ndev;
+ netcp->ndev_dev = &ndev->dev;
+ netcp->msg_enable = netif_msg_init(netcp_debug_level, NETCP_DEBUG);
+ netcp->tx_pause_threshold = MAX_SKB_FRAGS;
+ netcp->tx_resume_threshold = netcp->tx_pause_threshold;
+ netcp->node_interface = node_interface;
+
+ ret = of_property_read_u32(node_interface, "efuse-mac", &efuse_mac);
+ if (efuse_mac) {
+ if (of_address_to_resource(node, NETCP_EFUSE_REG_INDEX, &res)) {
+ dev_err(dev, "could not find efuse-mac reg resource\n");
+ ret = -ENODEV;
+ goto quit;
+ }
+ size = resource_size(&res);
+
+ if (!devm_request_mem_region(dev, res.start, size,
+ dev_name(dev))) {
+ dev_err(dev, "could not reserve resource\n");
+ ret = -ENOMEM;
+ goto quit;
+ }
+
+ efuse = devm_ioremap_nocache(dev, res.start, size);
+ if (!efuse) {
+ dev_err(dev, "could not map resource\n");
+ devm_release_mem_region(dev, res.start, size);
+ ret = -ENOMEM;
+ goto quit;
+ }
+
+ emac_arch_get_mac_addr(efuse_mac_addr, efuse);
+ if (is_valid_ether_addr(efuse_mac_addr))
+ ether_addr_copy(ndev->dev_addr, efuse_mac_addr);
+ else
+ random_ether_addr(ndev->dev_addr);
+
+ devm_iounmap(dev, efuse);
+ devm_release_mem_region(dev, res.start, size);
+ } else {
+ mac_addr = of_get_mac_address(node_interface);
+ if (mac_addr)
+ ether_addr_copy(ndev->dev_addr, mac_addr);
+ else
+ random_ether_addr(ndev->dev_addr);
+ }
+
+ ret = of_property_read_string(node_interface, "rx-channel",
+ &netcp->dma_chan_name);
+ if (ret < 0) {
+ dev_err(dev, "missing \"rx-channel\" parameter\n");
+ ret = -ENODEV;
+ goto quit;
+ }
+
+ ret = of_property_read_u32(node_interface, "rx-queue",
+ &netcp->rx_queue_id);
+ if (ret < 0) {
+ dev_warn(dev, "missing \"rx-queue\" parameter\n");
+ netcp->rx_queue_id = KNAV_QUEUE_QPEND;
+ }
+
+ ret = of_property_read_u32_array(node_interface, "rx-queue-depth",
+ netcp->rx_queue_depths,
+ KNAV_DMA_FDQ_PER_CHAN);
+ if (ret < 0) {
+ dev_err(dev, "missing \"rx-queue-depth\" parameter\n");
+ netcp->rx_queue_depths[0] = 128;
+ }
+
+ ret = of_property_read_u32_array(node_interface, "rx-buffer-size",
+ netcp->rx_buffer_sizes,
+ KNAV_DMA_FDQ_PER_CHAN);
+ if (ret) {
+ dev_err(dev, "missing \"rx-buffer-size\" parameter\n");
+ netcp->rx_buffer_sizes[0] = 1536;
+ }
+
+ ret = of_property_read_u32_array(node_interface, "rx-pool", temp, 2);
+ if (ret < 0) {
+ dev_err(dev, "missing \"rx-pool\" parameter\n");
+ ret = -ENODEV;
+ goto quit;
+ }
+ netcp->rx_pool_size = temp[0];
+ netcp->rx_pool_region_id = temp[1];
+
+ ret = of_property_read_u32_array(node_interface, "tx-pool", temp, 2);
+ if (ret < 0) {
+ dev_err(dev, "missing \"tx-pool\" parameter\n");
+ ret = -ENODEV;
+ goto quit;
+ }
+ netcp->tx_pool_size = temp[0];
+ netcp->tx_pool_region_id = temp[1];
+
+ if (netcp->tx_pool_size < MAX_SKB_FRAGS) {
+ dev_err(dev, "tx-pool size too small, must be atleast(%ld)\n",
+ MAX_SKB_FRAGS);
+ ret = -ENODEV;
+ goto quit;
+ }
+
+ ret = of_property_read_u32(node_interface, "tx-completion-queue",
+ &netcp->tx_compl_qid);
+ if (ret < 0) {
+ dev_warn(dev, "missing \"tx-completion-queue\" parameter\n");
+ netcp->tx_compl_qid = KNAV_QUEUE_QPEND;
+ }
+
+ /* NAPI register */
+ netif_napi_add(ndev, &netcp->rx_napi, netcp_rx_poll, NETCP_NAPI_WEIGHT);
+ netif_napi_add(ndev, &netcp->tx_napi, netcp_tx_poll, NETCP_NAPI_WEIGHT);
+
+ /* Register the network device */
+ ndev->dev_id = 0;
+ ndev->watchdog_timeo = NETCP_TX_TIMEOUT;
+ ndev->netdev_ops = &netcp_netdev_ops;
+ SET_NETDEV_DEV(ndev, dev);
+
+ list_add_tail(&netcp->interface_list, &netcp_device->interface_head);
+ return 0;
+
+quit:
+ free_netdev(ndev);
+ return ret;
+}
+
+static void netcp_delete_interface(struct netcp_device *netcp_device,
+ struct net_device *ndev)
+{
+ struct netcp_intf_modpriv *intf_modpriv, *tmp;
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct netcp_module *module;
+
+ dev_dbg(netcp_device->device, "Removing interface \"%s\"\n",
+ ndev->name);
+
+ /* Notify each of the modules that the interface is going away */
+ list_for_each_entry_safe(intf_modpriv, tmp, &netcp->module_head,
+ intf_list) {
+ module = intf_modpriv->netcp_module;
+ dev_dbg(netcp_device->device, "Releasing module \"%s\"\n",
+ module->name);
+ if (module->release)
+ module->release(intf_modpriv->module_priv);
+ list_del(&intf_modpriv->intf_list);
+ kfree(intf_modpriv);
+ }
+ WARN(!list_empty(&netcp->module_head), "%s interface module list is not empty!\n",
+ ndev->name);
+
+ list_del(&netcp->interface_list);
+
+ of_node_put(netcp->node_interface);
+ unregister_netdev(ndev);
+ netif_napi_del(&netcp->rx_napi);
+ free_netdev(ndev);
+}
+
+static int netcp_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct netcp_intf *netcp_intf, *netcp_tmp;
+ struct device_node *child, *interfaces;
+ struct netcp_device *netcp_device;
+ struct device *dev = &pdev->dev;
+ struct netcp_module *module;
+ int ret;
+
+ if (!node) {
+ dev_err(dev, "could not find device info\n");
+ return -ENODEV;
+ }
+
+ /* Allocate a new NETCP device instance */
+ netcp_device = devm_kzalloc(dev, sizeof(*netcp_device), GFP_KERNEL);
+ if (!netcp_device)
+ return -ENOMEM;
+
+ pm_runtime_enable(&pdev->dev);
+ ret = pm_runtime_get_sync(&pdev->dev);
+ if (ret < 0) {
+ dev_err(dev, "Failed to enable NETCP power-domain\n");
+ pm_runtime_disable(&pdev->dev);
+ return ret;
+ }
+
+ /* Initialize the NETCP device instance */
+ INIT_LIST_HEAD(&netcp_device->interface_head);
+ INIT_LIST_HEAD(&netcp_device->modpriv_head);
+ netcp_device->device = dev;
+ platform_set_drvdata(pdev, netcp_device);
+
+ /* create interfaces */
+ interfaces = of_get_child_by_name(node, "netcp-interfaces");
+ if (!interfaces) {
+ dev_err(dev, "could not find netcp-interfaces node\n");
+ ret = -ENODEV;
+ goto probe_quit;
+ }
+
+ for_each_available_child_of_node(interfaces, child) {
+ ret = netcp_create_interface(netcp_device, child);
+ if (ret) {
+ dev_err(dev, "could not create interface(%s)\n",
+ child->name);
+ goto probe_quit_interface;
+ }
+ }
+
+ /* Add the device instance to the list */
+ list_add_tail(&netcp_device->device_list, &netcp_devices);
+
+ /* Probe & attach any modules already registered */
+ mutex_lock(&netcp_modules_lock);
+ for_each_netcp_module(module) {
+ ret = netcp_module_probe(netcp_device, module);
+ if (ret < 0)
+ dev_err(dev, "module(%s) probe failed\n", module->name);
+ }
+ mutex_unlock(&netcp_modules_lock);
+ return 0;
+
+probe_quit_interface:
+ list_for_each_entry_safe(netcp_intf, netcp_tmp,
+ &netcp_device->interface_head,
+ interface_list) {
+ netcp_delete_interface(netcp_device, netcp_intf->ndev);
+ }
+
+probe_quit:
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ return ret;
+}
+
+static int netcp_remove(struct platform_device *pdev)
+{
+ struct netcp_device *netcp_device = platform_get_drvdata(pdev);
+ struct netcp_inst_modpriv *inst_modpriv, *tmp;
+ struct netcp_module *module;
+
+ list_for_each_entry_safe(inst_modpriv, tmp, &netcp_device->modpriv_head,
+ inst_list) {
+ module = inst_modpriv->netcp_module;
+ dev_dbg(&pdev->dev, "Removing module \"%s\"\n", module->name);
+ module->remove(netcp_device, inst_modpriv->module_priv);
+ list_del(&inst_modpriv->inst_list);
+ kfree(inst_modpriv);
+ }
+ WARN(!list_empty(&netcp_device->interface_head), "%s interface list not empty!\n",
+ pdev->name);
+
+ devm_kfree(&pdev->dev, netcp_device);
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct of_device_id of_match[] = {
+ { .compatible = "ti,netcp-1.0", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_match);
+
+static struct platform_driver netcp_driver = {
+ .driver = {
+ .name = "netcp-1.0",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match,
+ },
+ .probe = netcp_probe,
+ .remove = netcp_remove,
+};
+module_platform_driver(netcp_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI NETCP driver for Keystone SOCs");
+MODULE_AUTHOR("Sandeep Nair <sandeep_n@ti.com");
diff --git a/drivers/net/ethernet/ti/netcp_ethss.c b/drivers/net/ethernet/ti/netcp_ethss.c
new file mode 100644
index 000000000000..84f5ce525750
--- /dev/null
+++ b/drivers/net/ethernet/ti/netcp_ethss.c
@@ -0,0 +1,2159 @@
+/*
+ * Keystone GBE and XGBE subsystem code
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors: Sandeep Nair <sandeep_n@ti.com>
+ * Sandeep Paulraj <s-paulraj@ti.com>
+ * Cyril Chemparathy <cyril@ti.com>
+ * Santosh Shilimkar <santosh.shilimkar@ti.com>
+ * Wingman Kwok <w-kwok2@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/io.h>
+#include <linux/module.h>
+#include <linux/of_mdio.h>
+#include <linux/of_address.h>
+#include <linux/if_vlan.h>
+#include <linux/ethtool.h>
+
+#include "cpsw_ale.h"
+#include "netcp.h"
+
+#define NETCP_DRIVER_NAME "TI KeyStone Ethernet Driver"
+#define NETCP_DRIVER_VERSION "v1.0"
+
+#define GBE_IDENT(reg) ((reg >> 16) & 0xffff)
+#define GBE_MAJOR_VERSION(reg) (reg >> 8 & 0x7)
+#define GBE_MINOR_VERSION(reg) (reg & 0xff)
+#define GBE_RTL_VERSION(reg) ((reg >> 11) & 0x1f)
+
+/* 1G Ethernet SS defines */
+#define GBE_MODULE_NAME "netcp-gbe"
+#define GBE_SS_VERSION_14 0x4ed21104
+
+#define GBE13_SGMII_MODULE_OFFSET 0x100
+#define GBE13_SGMII34_MODULE_OFFSET 0x400
+#define GBE13_SWITCH_MODULE_OFFSET 0x800
+#define GBE13_HOST_PORT_OFFSET 0x834
+#define GBE13_SLAVE_PORT_OFFSET 0x860
+#define GBE13_EMAC_OFFSET 0x900
+#define GBE13_SLAVE_PORT2_OFFSET 0xa00
+#define GBE13_HW_STATS_OFFSET 0xb00
+#define GBE13_ALE_OFFSET 0xe00
+#define GBE13_HOST_PORT_NUM 0
+#define GBE13_NUM_SLAVES 4
+#define GBE13_NUM_ALE_PORTS (GBE13_NUM_SLAVES + 1)
+#define GBE13_NUM_ALE_ENTRIES 1024
+
+/* 10G Ethernet SS defines */
+#define XGBE_MODULE_NAME "netcp-xgbe"
+#define XGBE_SS_VERSION_10 0x4ee42100
+
+#define XGBE_SERDES_REG_INDEX 1
+#define XGBE10_SGMII_MODULE_OFFSET 0x100
+#define XGBE10_SWITCH_MODULE_OFFSET 0x1000
+#define XGBE10_HOST_PORT_OFFSET 0x1034
+#define XGBE10_SLAVE_PORT_OFFSET 0x1064
+#define XGBE10_EMAC_OFFSET 0x1400
+#define XGBE10_ALE_OFFSET 0x1700
+#define XGBE10_HW_STATS_OFFSET 0x1800
+#define XGBE10_HOST_PORT_NUM 0
+#define XGBE10_NUM_SLAVES 2
+#define XGBE10_NUM_ALE_PORTS (XGBE10_NUM_SLAVES + 1)
+#define XGBE10_NUM_ALE_ENTRIES 1024
+
+#define GBE_TIMER_INTERVAL (HZ / 2)
+
+/* Soft reset register values */
+#define SOFT_RESET_MASK BIT(0)
+#define SOFT_RESET BIT(0)
+#define DEVICE_EMACSL_RESET_POLL_COUNT 100
+#define GMACSL_RET_WARN_RESET_INCOMPLETE -2
+
+#define MACSL_RX_ENABLE_CSF BIT(23)
+#define MACSL_ENABLE_EXT_CTL BIT(18)
+#define MACSL_XGMII_ENABLE BIT(13)
+#define MACSL_XGIG_MODE BIT(8)
+#define MACSL_GIG_MODE BIT(7)
+#define MACSL_GMII_ENABLE BIT(5)
+#define MACSL_FULLDUPLEX BIT(0)
+
+#define GBE_CTL_P0_ENABLE BIT(2)
+#define GBE_REG_VAL_STAT_ENABLE_ALL 0xff
+#define XGBE_REG_VAL_STAT_ENABLE_ALL 0xf
+#define GBE_STATS_CD_SEL BIT(28)
+
+#define GBE_PORT_MASK(x) (BIT(x) - 1)
+#define GBE_MASK_NO_PORTS 0
+
+#define GBE_DEF_1G_MAC_CONTROL \
+ (MACSL_GIG_MODE | MACSL_GMII_ENABLE | \
+ MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF)
+
+#define GBE_DEF_10G_MAC_CONTROL \
+ (MACSL_XGIG_MODE | MACSL_XGMII_ENABLE | \
+ MACSL_ENABLE_EXT_CTL | MACSL_RX_ENABLE_CSF)
+
+#define GBE_STATSA_MODULE 0
+#define GBE_STATSB_MODULE 1
+#define GBE_STATSC_MODULE 2
+#define GBE_STATSD_MODULE 3
+
+#define XGBE_STATS0_MODULE 0
+#define XGBE_STATS1_MODULE 1
+#define XGBE_STATS2_MODULE 2
+
+#define MAX_SLAVES GBE13_NUM_SLAVES
+/* s: 0-based slave_port */
+#define SGMII_BASE(s) \
+ (((s) < 2) ? gbe_dev->sgmii_port_regs : gbe_dev->sgmii_port34_regs)
+
+#define GBE_TX_QUEUE 648
+#define GBE_TXHOOK_ORDER 0
+#define GBE_DEFAULT_ALE_AGEOUT 30
+#define SLAVE_LINK_IS_XGMII(s) ((s)->link_interface >= XGMII_LINK_MAC_PHY)
+#define NETCP_LINK_STATE_INVALID -1
+
+#define GBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \
+ offsetof(struct gbe##_##rb, rn)
+#define XGBE_SET_REG_OFS(p, rb, rn) p->rb##_ofs.rn = \
+ offsetof(struct xgbe##_##rb, rn)
+#define GBE_REG_ADDR(p, rb, rn) (p->rb + p->rb##_ofs.rn)
+
+struct xgbe_ss_regs {
+ u32 id_ver;
+ u32 synce_count;
+ u32 synce_mux;
+ u32 control;
+};
+
+struct xgbe_switch_regs {
+ u32 id_ver;
+ u32 control;
+ u32 emcontrol;
+ u32 stat_port_en;
+ u32 ptype;
+ u32 soft_idle;
+ u32 thru_rate;
+ u32 gap_thresh;
+ u32 tx_start_wds;
+ u32 flow_control;
+ u32 cppi_thresh;
+};
+
+struct xgbe_port_regs {
+ u32 blk_cnt;
+ u32 port_vlan;
+ u32 tx_pri_map;
+ u32 sa_lo;
+ u32 sa_hi;
+ u32 ts_ctl;
+ u32 ts_seq_ltype;
+ u32 ts_vlan;
+ u32 ts_ctl_ltype2;
+ u32 ts_ctl2;
+ u32 control;
+};
+
+struct xgbe_host_port_regs {
+ u32 blk_cnt;
+ u32 port_vlan;
+ u32 tx_pri_map;
+ u32 src_id;
+ u32 rx_pri_map;
+ u32 rx_maxlen;
+};
+
+struct xgbe_emac_regs {
+ u32 id_ver;
+ u32 mac_control;
+ u32 mac_status;
+ u32 soft_reset;
+ u32 rx_maxlen;
+ u32 __reserved_0;
+ u32 rx_pause;
+ u32 tx_pause;
+ u32 em_control;
+ u32 __reserved_1;
+ u32 tx_gap;
+ u32 rsvd[4];
+};
+
+struct xgbe_host_hw_stats {
+ u32 rx_good_frames;
+ u32 rx_broadcast_frames;
+ u32 rx_multicast_frames;
+ u32 __rsvd_0[3];
+ u32 rx_oversized_frames;
+ u32 __rsvd_1;
+ u32 rx_undersized_frames;
+ u32 __rsvd_2;
+ u32 overrun_type4;
+ u32 overrun_type5;
+ u32 rx_bytes;
+ u32 tx_good_frames;
+ u32 tx_broadcast_frames;
+ u32 tx_multicast_frames;
+ u32 __rsvd_3[9];
+ u32 tx_bytes;
+ u32 tx_64byte_frames;
+ u32 tx_65_to_127byte_frames;
+ u32 tx_128_to_255byte_frames;
+ u32 tx_256_to_511byte_frames;
+ u32 tx_512_to_1023byte_frames;
+ u32 tx_1024byte_frames;
+ u32 net_bytes;
+ u32 rx_sof_overruns;
+ u32 rx_mof_overruns;
+ u32 rx_dma_overruns;
+};
+
+struct xgbe_hw_stats {
+ u32 rx_good_frames;
+ u32 rx_broadcast_frames;
+ u32 rx_multicast_frames;
+ u32 rx_pause_frames;
+ u32 rx_crc_errors;
+ u32 rx_align_code_errors;
+ u32 rx_oversized_frames;
+ u32 rx_jabber_frames;
+ u32 rx_undersized_frames;
+ u32 rx_fragments;
+ u32 overrun_type4;
+ u32 overrun_type5;
+ u32 rx_bytes;
+ u32 tx_good_frames;
+ u32 tx_broadcast_frames;
+ u32 tx_multicast_frames;
+ u32 tx_pause_frames;
+ u32 tx_deferred_frames;
+ u32 tx_collision_frames;
+ u32 tx_single_coll_frames;
+ u32 tx_mult_coll_frames;
+ u32 tx_excessive_collisions;
+ u32 tx_late_collisions;
+ u32 tx_underrun;
+ u32 tx_carrier_sense_errors;
+ u32 tx_bytes;
+ u32 tx_64byte_frames;
+ u32 tx_65_to_127byte_frames;
+ u32 tx_128_to_255byte_frames;
+ u32 tx_256_to_511byte_frames;
+ u32 tx_512_to_1023byte_frames;
+ u32 tx_1024byte_frames;
+ u32 net_bytes;
+ u32 rx_sof_overruns;
+ u32 rx_mof_overruns;
+ u32 rx_dma_overruns;
+};
+
+#define XGBE10_NUM_STAT_ENTRIES (sizeof(struct xgbe_hw_stats)/sizeof(u32))
+
+struct gbe_ss_regs {
+ u32 id_ver;
+ u32 synce_count;
+ u32 synce_mux;
+};
+
+struct gbe_ss_regs_ofs {
+ u16 id_ver;
+ u16 control;
+};
+
+struct gbe_switch_regs {
+ u32 id_ver;
+ u32 control;
+ u32 soft_reset;
+ u32 stat_port_en;
+ u32 ptype;
+ u32 soft_idle;
+ u32 thru_rate;
+ u32 gap_thresh;
+ u32 tx_start_wds;
+ u32 flow_control;
+};
+
+struct gbe_switch_regs_ofs {
+ u16 id_ver;
+ u16 control;
+ u16 soft_reset;
+ u16 emcontrol;
+ u16 stat_port_en;
+ u16 ptype;
+ u16 flow_control;
+};
+
+struct gbe_port_regs {
+ u32 max_blks;
+ u32 blk_cnt;
+ u32 port_vlan;
+ u32 tx_pri_map;
+ u32 sa_lo;
+ u32 sa_hi;
+ u32 ts_ctl;
+ u32 ts_seq_ltype;
+ u32 ts_vlan;
+ u32 ts_ctl_ltype2;
+ u32 ts_ctl2;
+};
+
+struct gbe_port_regs_ofs {
+ u16 port_vlan;
+ u16 tx_pri_map;
+ u16 sa_lo;
+ u16 sa_hi;
+ u16 ts_ctl;
+ u16 ts_seq_ltype;
+ u16 ts_vlan;
+ u16 ts_ctl_ltype2;
+ u16 ts_ctl2;
+};
+
+struct gbe_host_port_regs {
+ u32 src_id;
+ u32 port_vlan;
+ u32 rx_pri_map;
+ u32 rx_maxlen;
+};
+
+struct gbe_host_port_regs_ofs {
+ u16 port_vlan;
+ u16 tx_pri_map;
+ u16 rx_maxlen;
+};
+
+struct gbe_emac_regs {
+ u32 id_ver;
+ u32 mac_control;
+ u32 mac_status;
+ u32 soft_reset;
+ u32 rx_maxlen;
+ u32 __reserved_0;
+ u32 rx_pause;
+ u32 tx_pause;
+ u32 __reserved_1;
+ u32 rx_pri_map;
+ u32 rsvd[6];
+};
+
+struct gbe_emac_regs_ofs {
+ u16 mac_control;
+ u16 soft_reset;
+ u16 rx_maxlen;
+};
+
+struct gbe_hw_stats {
+ u32 rx_good_frames;
+ u32 rx_broadcast_frames;
+ u32 rx_multicast_frames;
+ u32 rx_pause_frames;
+ u32 rx_crc_errors;
+ u32 rx_align_code_errors;
+ u32 rx_oversized_frames;
+ u32 rx_jabber_frames;
+ u32 rx_undersized_frames;
+ u32 rx_fragments;
+ u32 __pad_0[2];
+ u32 rx_bytes;
+ u32 tx_good_frames;
+ u32 tx_broadcast_frames;
+ u32 tx_multicast_frames;
+ u32 tx_pause_frames;
+ u32 tx_deferred_frames;
+ u32 tx_collision_frames;
+ u32 tx_single_coll_frames;
+ u32 tx_mult_coll_frames;
+ u32 tx_excessive_collisions;
+ u32 tx_late_collisions;
+ u32 tx_underrun;
+ u32 tx_carrier_sense_errors;
+ u32 tx_bytes;
+ u32 tx_64byte_frames;
+ u32 tx_65_to_127byte_frames;
+ u32 tx_128_to_255byte_frames;
+ u32 tx_256_to_511byte_frames;
+ u32 tx_512_to_1023byte_frames;
+ u32 tx_1024byte_frames;
+ u32 net_bytes;
+ u32 rx_sof_overruns;
+ u32 rx_mof_overruns;
+ u32 rx_dma_overruns;
+};
+
+#define GBE13_NUM_HW_STAT_ENTRIES (sizeof(struct gbe_hw_stats)/sizeof(u32))
+#define GBE13_NUM_HW_STATS_MOD 2
+#define XGBE10_NUM_HW_STATS_MOD 3
+#define GBE_MAX_HW_STAT_MODS 3
+#define GBE_HW_STATS_REG_MAP_SZ 0x100
+
+struct gbe_slave {
+ void __iomem *port_regs;
+ void __iomem *emac_regs;
+ struct gbe_port_regs_ofs port_regs_ofs;
+ struct gbe_emac_regs_ofs emac_regs_ofs;
+ int slave_num; /* 0 based logical number */
+ int port_num; /* actual port number */
+ atomic_t link_state;
+ bool open;
+ struct phy_device *phy;
+ u32 link_interface;
+ u32 mac_control;
+ u8 phy_port_t;
+ struct device_node *phy_node;
+ struct list_head slave_list;
+};
+
+struct gbe_priv {
+ struct device *dev;
+ struct netcp_device *netcp_device;
+ struct timer_list timer;
+ u32 num_slaves;
+ u32 ale_entries;
+ u32 ale_ports;
+ bool enable_ale;
+ struct netcp_tx_pipe tx_pipe;
+
+ int host_port;
+ u32 rx_packet_max;
+ u32 ss_version;
+
+ void __iomem *ss_regs;
+ void __iomem *switch_regs;
+ void __iomem *host_port_regs;
+ void __iomem *ale_reg;
+ void __iomem *sgmii_port_regs;
+ void __iomem *sgmii_port34_regs;
+ void __iomem *xgbe_serdes_regs;
+ void __iomem *hw_stats_regs[GBE_MAX_HW_STAT_MODS];
+
+ struct gbe_ss_regs_ofs ss_regs_ofs;
+ struct gbe_switch_regs_ofs switch_regs_ofs;
+ struct gbe_host_port_regs_ofs host_port_regs_ofs;
+
+ struct cpsw_ale *ale;
+ unsigned int tx_queue_id;
+ const char *dma_chan_name;
+
+ struct list_head gbe_intf_head;
+ struct list_head secondary_slaves;
+ struct net_device *dummy_ndev;
+
+ u64 *hw_stats;
+ const struct netcp_ethtool_stat *et_stats;
+ int num_et_stats;
+ /* Lock for updating the hwstats */
+ spinlock_t hw_stats_lock;
+};
+
+struct gbe_intf {
+ struct net_device *ndev;
+ struct device *dev;
+ struct gbe_priv *gbe_dev;
+ struct netcp_tx_pipe tx_pipe;
+ struct gbe_slave *slave;
+ struct list_head gbe_intf_list;
+ unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+};
+
+static struct netcp_module gbe_module;
+static struct netcp_module xgbe_module;
+
+/* Statistic management */
+struct netcp_ethtool_stat {
+ char desc[ETH_GSTRING_LEN];
+ int type;
+ u32 size;
+ int offset;
+};
+
+#define GBE_STATSA_INFO(field) "GBE_A:"#field, GBE_STATSA_MODULE,\
+ FIELD_SIZEOF(struct gbe_hw_stats, field), \
+ offsetof(struct gbe_hw_stats, field)
+
+#define GBE_STATSB_INFO(field) "GBE_B:"#field, GBE_STATSB_MODULE,\
+ FIELD_SIZEOF(struct gbe_hw_stats, field), \
+ offsetof(struct gbe_hw_stats, field)
+
+#define GBE_STATSC_INFO(field) "GBE_C:"#field, GBE_STATSC_MODULE,\
+ FIELD_SIZEOF(struct gbe_hw_stats, field), \
+ offsetof(struct gbe_hw_stats, field)
+
+#define GBE_STATSD_INFO(field) "GBE_D:"#field, GBE_STATSD_MODULE,\
+ FIELD_SIZEOF(struct gbe_hw_stats, field), \
+ offsetof(struct gbe_hw_stats, field)
+
+static const struct netcp_ethtool_stat gbe13_et_stats[] = {
+ /* GBE module A */
+ {GBE_STATSA_INFO(rx_good_frames)},
+ {GBE_STATSA_INFO(rx_broadcast_frames)},
+ {GBE_STATSA_INFO(rx_multicast_frames)},
+ {GBE_STATSA_INFO(rx_pause_frames)},
+ {GBE_STATSA_INFO(rx_crc_errors)},
+ {GBE_STATSA_INFO(rx_align_code_errors)},
+ {GBE_STATSA_INFO(rx_oversized_frames)},
+ {GBE_STATSA_INFO(rx_jabber_frames)},
+ {GBE_STATSA_INFO(rx_undersized_frames)},
+ {GBE_STATSA_INFO(rx_fragments)},
+ {GBE_STATSA_INFO(rx_bytes)},
+ {GBE_STATSA_INFO(tx_good_frames)},
+ {GBE_STATSA_INFO(tx_broadcast_frames)},
+ {GBE_STATSA_INFO(tx_multicast_frames)},
+ {GBE_STATSA_INFO(tx_pause_frames)},
+ {GBE_STATSA_INFO(tx_deferred_frames)},
+ {GBE_STATSA_INFO(tx_collision_frames)},
+ {GBE_STATSA_INFO(tx_single_coll_frames)},
+ {GBE_STATSA_INFO(tx_mult_coll_frames)},
+ {GBE_STATSA_INFO(tx_excessive_collisions)},
+ {GBE_STATSA_INFO(tx_late_collisions)},
+ {GBE_STATSA_INFO(tx_underrun)},
+ {GBE_STATSA_INFO(tx_carrier_sense_errors)},
+ {GBE_STATSA_INFO(tx_bytes)},
+ {GBE_STATSA_INFO(tx_64byte_frames)},
+ {GBE_STATSA_INFO(tx_65_to_127byte_frames)},
+ {GBE_STATSA_INFO(tx_128_to_255byte_frames)},
+ {GBE_STATSA_INFO(tx_256_to_511byte_frames)},
+ {GBE_STATSA_INFO(tx_512_to_1023byte_frames)},
+ {GBE_STATSA_INFO(tx_1024byte_frames)},
+ {GBE_STATSA_INFO(net_bytes)},
+ {GBE_STATSA_INFO(rx_sof_overruns)},
+ {GBE_STATSA_INFO(rx_mof_overruns)},
+ {GBE_STATSA_INFO(rx_dma_overruns)},
+ /* GBE module B */
+ {GBE_STATSB_INFO(rx_good_frames)},
+ {GBE_STATSB_INFO(rx_broadcast_frames)},
+ {GBE_STATSB_INFO(rx_multicast_frames)},
+ {GBE_STATSB_INFO(rx_pause_frames)},
+ {GBE_STATSB_INFO(rx_crc_errors)},
+ {GBE_STATSB_INFO(rx_align_code_errors)},
+ {GBE_STATSB_INFO(rx_oversized_frames)},
+ {GBE_STATSB_INFO(rx_jabber_frames)},
+ {GBE_STATSB_INFO(rx_undersized_frames)},
+ {GBE_STATSB_INFO(rx_fragments)},
+ {GBE_STATSB_INFO(rx_bytes)},
+ {GBE_STATSB_INFO(tx_good_frames)},
+ {GBE_STATSB_INFO(tx_broadcast_frames)},
+ {GBE_STATSB_INFO(tx_multicast_frames)},
+ {GBE_STATSB_INFO(tx_pause_frames)},
+ {GBE_STATSB_INFO(tx_deferred_frames)},
+ {GBE_STATSB_INFO(tx_collision_frames)},
+ {GBE_STATSB_INFO(tx_single_coll_frames)},
+ {GBE_STATSB_INFO(tx_mult_coll_frames)},
+ {GBE_STATSB_INFO(tx_excessive_collisions)},
+ {GBE_STATSB_INFO(tx_late_collisions)},
+ {GBE_STATSB_INFO(tx_underrun)},
+ {GBE_STATSB_INFO(tx_carrier_sense_errors)},
+ {GBE_STATSB_INFO(tx_bytes)},
+ {GBE_STATSB_INFO(tx_64byte_frames)},
+ {GBE_STATSB_INFO(tx_65_to_127byte_frames)},
+ {GBE_STATSB_INFO(tx_128_to_255byte_frames)},
+ {GBE_STATSB_INFO(tx_256_to_511byte_frames)},
+ {GBE_STATSB_INFO(tx_512_to_1023byte_frames)},
+ {GBE_STATSB_INFO(tx_1024byte_frames)},
+ {GBE_STATSB_INFO(net_bytes)},
+ {GBE_STATSB_INFO(rx_sof_overruns)},
+ {GBE_STATSB_INFO(rx_mof_overruns)},
+ {GBE_STATSB_INFO(rx_dma_overruns)},
+ /* GBE module C */
+ {GBE_STATSC_INFO(rx_good_frames)},
+ {GBE_STATSC_INFO(rx_broadcast_frames)},
+ {GBE_STATSC_INFO(rx_multicast_frames)},
+ {GBE_STATSC_INFO(rx_pause_frames)},
+ {GBE_STATSC_INFO(rx_crc_errors)},
+ {GBE_STATSC_INFO(rx_align_code_errors)},
+ {GBE_STATSC_INFO(rx_oversized_frames)},
+ {GBE_STATSC_INFO(rx_jabber_frames)},
+ {GBE_STATSC_INFO(rx_undersized_frames)},
+ {GBE_STATSC_INFO(rx_fragments)},
+ {GBE_STATSC_INFO(rx_bytes)},
+ {GBE_STATSC_INFO(tx_good_frames)},
+ {GBE_STATSC_INFO(tx_broadcast_frames)},
+ {GBE_STATSC_INFO(tx_multicast_frames)},
+ {GBE_STATSC_INFO(tx_pause_frames)},
+ {GBE_STATSC_INFO(tx_deferred_frames)},
+ {GBE_STATSC_INFO(tx_collision_frames)},
+ {GBE_STATSC_INFO(tx_single_coll_frames)},
+ {GBE_STATSC_INFO(tx_mult_coll_frames)},
+ {GBE_STATSC_INFO(tx_excessive_collisions)},
+ {GBE_STATSC_INFO(tx_late_collisions)},
+ {GBE_STATSC_INFO(tx_underrun)},
+ {GBE_STATSC_INFO(tx_carrier_sense_errors)},
+ {GBE_STATSC_INFO(tx_bytes)},
+ {GBE_STATSC_INFO(tx_64byte_frames)},
+ {GBE_STATSC_INFO(tx_65_to_127byte_frames)},
+ {GBE_STATSC_INFO(tx_128_to_255byte_frames)},
+ {GBE_STATSC_INFO(tx_256_to_511byte_frames)},
+ {GBE_STATSC_INFO(tx_512_to_1023byte_frames)},
+ {GBE_STATSC_INFO(tx_1024byte_frames)},
+ {GBE_STATSC_INFO(net_bytes)},
+ {GBE_STATSC_INFO(rx_sof_overruns)},
+ {GBE_STATSC_INFO(rx_mof_overruns)},
+ {GBE_STATSC_INFO(rx_dma_overruns)},
+ /* GBE module D */
+ {GBE_STATSD_INFO(rx_good_frames)},
+ {GBE_STATSD_INFO(rx_broadcast_frames)},
+ {GBE_STATSD_INFO(rx_multicast_frames)},
+ {GBE_STATSD_INFO(rx_pause_frames)},
+ {GBE_STATSD_INFO(rx_crc_errors)},
+ {GBE_STATSD_INFO(rx_align_code_errors)},
+ {GBE_STATSD_INFO(rx_oversized_frames)},
+ {GBE_STATSD_INFO(rx_jabber_frames)},
+ {GBE_STATSD_INFO(rx_undersized_frames)},
+ {GBE_STATSD_INFO(rx_fragments)},
+ {GBE_STATSD_INFO(rx_bytes)},
+ {GBE_STATSD_INFO(tx_good_frames)},
+ {GBE_STATSD_INFO(tx_broadcast_frames)},
+ {GBE_STATSD_INFO(tx_multicast_frames)},
+ {GBE_STATSD_INFO(tx_pause_frames)},
+ {GBE_STATSD_INFO(tx_deferred_frames)},
+ {GBE_STATSD_INFO(tx_collision_frames)},
+ {GBE_STATSD_INFO(tx_single_coll_frames)},
+ {GBE_STATSD_INFO(tx_mult_coll_frames)},
+ {GBE_STATSD_INFO(tx_excessive_collisions)},
+ {GBE_STATSD_INFO(tx_late_collisions)},
+ {GBE_STATSD_INFO(tx_underrun)},
+ {GBE_STATSD_INFO(tx_carrier_sense_errors)},
+ {GBE_STATSD_INFO(tx_bytes)},
+ {GBE_STATSD_INFO(tx_64byte_frames)},
+ {GBE_STATSD_INFO(tx_65_to_127byte_frames)},
+ {GBE_STATSD_INFO(tx_128_to_255byte_frames)},
+ {GBE_STATSD_INFO(tx_256_to_511byte_frames)},
+ {GBE_STATSD_INFO(tx_512_to_1023byte_frames)},
+ {GBE_STATSD_INFO(tx_1024byte_frames)},
+ {GBE_STATSD_INFO(net_bytes)},
+ {GBE_STATSD_INFO(rx_sof_overruns)},
+ {GBE_STATSD_INFO(rx_mof_overruns)},
+ {GBE_STATSD_INFO(rx_dma_overruns)},
+};
+
+#define XGBE_STATS0_INFO(field) "GBE_0:"#field, XGBE_STATS0_MODULE, \
+ FIELD_SIZEOF(struct xgbe_hw_stats, field), \
+ offsetof(struct xgbe_hw_stats, field)
+
+#define XGBE_STATS1_INFO(field) "GBE_1:"#field, XGBE_STATS1_MODULE, \
+ FIELD_SIZEOF(struct xgbe_hw_stats, field), \
+ offsetof(struct xgbe_hw_stats, field)
+
+#define XGBE_STATS2_INFO(field) "GBE_2:"#field, XGBE_STATS2_MODULE, \
+ FIELD_SIZEOF(struct xgbe_hw_stats, field), \
+ offsetof(struct xgbe_hw_stats, field)
+
+static const struct netcp_ethtool_stat xgbe10_et_stats[] = {
+ /* GBE module 0 */
+ {XGBE_STATS0_INFO(rx_good_frames)},
+ {XGBE_STATS0_INFO(rx_broadcast_frames)},
+ {XGBE_STATS0_INFO(rx_multicast_frames)},
+ {XGBE_STATS0_INFO(rx_oversized_frames)},
+ {XGBE_STATS0_INFO(rx_undersized_frames)},
+ {XGBE_STATS0_INFO(overrun_type4)},
+ {XGBE_STATS0_INFO(overrun_type5)},
+ {XGBE_STATS0_INFO(rx_bytes)},
+ {XGBE_STATS0_INFO(tx_good_frames)},
+ {XGBE_STATS0_INFO(tx_broadcast_frames)},
+ {XGBE_STATS0_INFO(tx_multicast_frames)},
+ {XGBE_STATS0_INFO(tx_bytes)},
+ {XGBE_STATS0_INFO(tx_64byte_frames)},
+ {XGBE_STATS0_INFO(tx_65_to_127byte_frames)},
+ {XGBE_STATS0_INFO(tx_128_to_255byte_frames)},
+ {XGBE_STATS0_INFO(tx_256_to_511byte_frames)},
+ {XGBE_STATS0_INFO(tx_512_to_1023byte_frames)},
+ {XGBE_STATS0_INFO(tx_1024byte_frames)},
+ {XGBE_STATS0_INFO(net_bytes)},
+ {XGBE_STATS0_INFO(rx_sof_overruns)},
+ {XGBE_STATS0_INFO(rx_mof_overruns)},
+ {XGBE_STATS0_INFO(rx_dma_overruns)},
+ /* XGBE module 1 */
+ {XGBE_STATS1_INFO(rx_good_frames)},
+ {XGBE_STATS1_INFO(rx_broadcast_frames)},
+ {XGBE_STATS1_INFO(rx_multicast_frames)},
+ {XGBE_STATS1_INFO(rx_pause_frames)},
+ {XGBE_STATS1_INFO(rx_crc_errors)},
+ {XGBE_STATS1_INFO(rx_align_code_errors)},
+ {XGBE_STATS1_INFO(rx_oversized_frames)},
+ {XGBE_STATS1_INFO(rx_jabber_frames)},
+ {XGBE_STATS1_INFO(rx_undersized_frames)},
+ {XGBE_STATS1_INFO(rx_fragments)},
+ {XGBE_STATS1_INFO(overrun_type4)},
+ {XGBE_STATS1_INFO(overrun_type5)},
+ {XGBE_STATS1_INFO(rx_bytes)},
+ {XGBE_STATS1_INFO(tx_good_frames)},
+ {XGBE_STATS1_INFO(tx_broadcast_frames)},
+ {XGBE_STATS1_INFO(tx_multicast_frames)},
+ {XGBE_STATS1_INFO(tx_pause_frames)},
+ {XGBE_STATS1_INFO(tx_deferred_frames)},
+ {XGBE_STATS1_INFO(tx_collision_frames)},
+ {XGBE_STATS1_INFO(tx_single_coll_frames)},
+ {XGBE_STATS1_INFO(tx_mult_coll_frames)},
+ {XGBE_STATS1_INFO(tx_excessive_collisions)},
+ {XGBE_STATS1_INFO(tx_late_collisions)},
+ {XGBE_STATS1_INFO(tx_underrun)},
+ {XGBE_STATS1_INFO(tx_carrier_sense_errors)},
+ {XGBE_STATS1_INFO(tx_bytes)},
+ {XGBE_STATS1_INFO(tx_64byte_frames)},
+ {XGBE_STATS1_INFO(tx_65_to_127byte_frames)},
+ {XGBE_STATS1_INFO(tx_128_to_255byte_frames)},
+ {XGBE_STATS1_INFO(tx_256_to_511byte_frames)},
+ {XGBE_STATS1_INFO(tx_512_to_1023byte_frames)},
+ {XGBE_STATS1_INFO(tx_1024byte_frames)},
+ {XGBE_STATS1_INFO(net_bytes)},
+ {XGBE_STATS1_INFO(rx_sof_overruns)},
+ {XGBE_STATS1_INFO(rx_mof_overruns)},
+ {XGBE_STATS1_INFO(rx_dma_overruns)},
+ /* XGBE module 2 */
+ {XGBE_STATS2_INFO(rx_good_frames)},
+ {XGBE_STATS2_INFO(rx_broadcast_frames)},
+ {XGBE_STATS2_INFO(rx_multicast_frames)},
+ {XGBE_STATS2_INFO(rx_pause_frames)},
+ {XGBE_STATS2_INFO(rx_crc_errors)},
+ {XGBE_STATS2_INFO(rx_align_code_errors)},
+ {XGBE_STATS2_INFO(rx_oversized_frames)},
+ {XGBE_STATS2_INFO(rx_jabber_frames)},
+ {XGBE_STATS2_INFO(rx_undersized_frames)},
+ {XGBE_STATS2_INFO(rx_fragments)},
+ {XGBE_STATS2_INFO(overrun_type4)},
+ {XGBE_STATS2_INFO(overrun_type5)},
+ {XGBE_STATS2_INFO(rx_bytes)},
+ {XGBE_STATS2_INFO(tx_good_frames)},
+ {XGBE_STATS2_INFO(tx_broadcast_frames)},
+ {XGBE_STATS2_INFO(tx_multicast_frames)},
+ {XGBE_STATS2_INFO(tx_pause_frames)},
+ {XGBE_STATS2_INFO(tx_deferred_frames)},
+ {XGBE_STATS2_INFO(tx_collision_frames)},
+ {XGBE_STATS2_INFO(tx_single_coll_frames)},
+ {XGBE_STATS2_INFO(tx_mult_coll_frames)},
+ {XGBE_STATS2_INFO(tx_excessive_collisions)},
+ {XGBE_STATS2_INFO(tx_late_collisions)},
+ {XGBE_STATS2_INFO(tx_underrun)},
+ {XGBE_STATS2_INFO(tx_carrier_sense_errors)},
+ {XGBE_STATS2_INFO(tx_bytes)},
+ {XGBE_STATS2_INFO(tx_64byte_frames)},
+ {XGBE_STATS2_INFO(tx_65_to_127byte_frames)},
+ {XGBE_STATS2_INFO(tx_128_to_255byte_frames)},
+ {XGBE_STATS2_INFO(tx_256_to_511byte_frames)},
+ {XGBE_STATS2_INFO(tx_512_to_1023byte_frames)},
+ {XGBE_STATS2_INFO(tx_1024byte_frames)},
+ {XGBE_STATS2_INFO(net_bytes)},
+ {XGBE_STATS2_INFO(rx_sof_overruns)},
+ {XGBE_STATS2_INFO(rx_mof_overruns)},
+ {XGBE_STATS2_INFO(rx_dma_overruns)},
+};
+
+#define for_each_intf(i, priv) \
+ list_for_each_entry((i), &(priv)->gbe_intf_head, gbe_intf_list)
+
+#define for_each_sec_slave(slave, priv) \
+ list_for_each_entry((slave), &(priv)->secondary_slaves, slave_list)
+
+#define first_sec_slave(priv) \
+ list_first_entry(&priv->secondary_slaves, \
+ struct gbe_slave, slave_list)
+
+static void keystone_get_drvinfo(struct net_device *ndev,
+ struct ethtool_drvinfo *info)
+{
+ strncpy(info->driver, NETCP_DRIVER_NAME, sizeof(info->driver));
+ strncpy(info->version, NETCP_DRIVER_VERSION, sizeof(info->version));
+}
+
+static u32 keystone_get_msglevel(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+
+ return netcp->msg_enable;
+}
+
+static void keystone_set_msglevel(struct net_device *ndev, u32 value)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+
+ netcp->msg_enable = value;
+}
+
+static void keystone_get_stat_strings(struct net_device *ndev,
+ uint32_t stringset, uint8_t *data)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct gbe_intf *gbe_intf;
+ struct gbe_priv *gbe_dev;
+ int i;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ return;
+ gbe_dev = gbe_intf->gbe_dev;
+
+ switch (stringset) {
+ case ETH_SS_STATS:
+ for (i = 0; i < gbe_dev->num_et_stats; i++) {
+ memcpy(data, gbe_dev->et_stats[i].desc,
+ ETH_GSTRING_LEN);
+ data += ETH_GSTRING_LEN;
+ }
+ break;
+ case ETH_SS_TEST:
+ break;
+ }
+}
+
+static int keystone_get_sset_count(struct net_device *ndev, int stringset)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct gbe_intf *gbe_intf;
+ struct gbe_priv *gbe_dev;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ return -EINVAL;
+ gbe_dev = gbe_intf->gbe_dev;
+
+ switch (stringset) {
+ case ETH_SS_TEST:
+ return 0;
+ case ETH_SS_STATS:
+ return gbe_dev->num_et_stats;
+ default:
+ return -EINVAL;
+ }
+}
+
+static void gbe_update_stats(struct gbe_priv *gbe_dev, uint64_t *data)
+{
+ void __iomem *base = NULL;
+ u32 __iomem *p;
+ u32 tmp = 0;
+ int i;
+
+ for (i = 0; i < gbe_dev->num_et_stats; i++) {
+ base = gbe_dev->hw_stats_regs[gbe_dev->et_stats[i].type];
+ p = base + gbe_dev->et_stats[i].offset;
+ tmp = readl(p);
+ gbe_dev->hw_stats[i] = gbe_dev->hw_stats[i] + tmp;
+ if (data)
+ data[i] = gbe_dev->hw_stats[i];
+ /* write-to-decrement:
+ * new register value = old register value - write value
+ */
+ writel(tmp, p);
+ }
+}
+
+static void gbe_update_stats_ver14(struct gbe_priv *gbe_dev, uint64_t *data)
+{
+ void __iomem *gbe_statsa = gbe_dev->hw_stats_regs[0];
+ void __iomem *gbe_statsb = gbe_dev->hw_stats_regs[1];
+ u64 *hw_stats = &gbe_dev->hw_stats[0];
+ void __iomem *base = NULL;
+ u32 __iomem *p;
+ u32 tmp = 0, val, pair_size = (gbe_dev->num_et_stats / 2);
+ int i, j, pair;
+
+ for (pair = 0; pair < 2; pair++) {
+ val = readl(GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en));
+
+ if (pair == 0)
+ val &= ~GBE_STATS_CD_SEL;
+ else
+ val |= GBE_STATS_CD_SEL;
+
+ /* make the stat modules visible */
+ writel(val, GBE_REG_ADDR(gbe_dev, switch_regs, stat_port_en));
+
+ for (i = 0; i < pair_size; i++) {
+ j = pair * pair_size + i;
+ switch (gbe_dev->et_stats[j].type) {
+ case GBE_STATSA_MODULE:
+ case GBE_STATSC_MODULE:
+ base = gbe_statsa;
+ break;
+ case GBE_STATSB_MODULE:
+ case GBE_STATSD_MODULE:
+ base = gbe_statsb;
+ break;
+ }
+
+ p = base + gbe_dev->et_stats[j].offset;
+ tmp = readl(p);
+ hw_stats[j] += tmp;
+ if (data)
+ data[j] = hw_stats[j];
+ /* write-to-decrement:
+ * new register value = old register value - write value
+ */
+ writel(tmp, p);
+ }
+ }
+}
+
+static void keystone_get_ethtool_stats(struct net_device *ndev,
+ struct ethtool_stats *stats,
+ uint64_t *data)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct gbe_intf *gbe_intf;
+ struct gbe_priv *gbe_dev;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ return;
+
+ gbe_dev = gbe_intf->gbe_dev;
+ spin_lock_bh(&gbe_dev->hw_stats_lock);
+ if (gbe_dev->ss_version == GBE_SS_VERSION_14)
+ gbe_update_stats_ver14(gbe_dev, data);
+ else
+ gbe_update_stats(gbe_dev, data);
+ spin_unlock_bh(&gbe_dev->hw_stats_lock);
+}
+
+static int keystone_get_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct phy_device *phy = ndev->phydev;
+ struct gbe_intf *gbe_intf;
+ int ret;
+
+ if (!phy)
+ return -EINVAL;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ return -EINVAL;
+
+ if (!gbe_intf->slave)
+ return -EINVAL;
+
+ ret = phy_ethtool_gset(phy, cmd);
+ if (!ret)
+ cmd->port = gbe_intf->slave->phy_port_t;
+
+ return ret;
+}
+
+static int keystone_set_settings(struct net_device *ndev,
+ struct ethtool_cmd *cmd)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct phy_device *phy = ndev->phydev;
+ struct gbe_intf *gbe_intf;
+ u32 features = cmd->advertising & cmd->supported;
+
+ if (!phy)
+ return -EINVAL;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ return -EINVAL;
+
+ if (!gbe_intf->slave)
+ return -EINVAL;
+
+ if (cmd->port != gbe_intf->slave->phy_port_t) {
+ if ((cmd->port == PORT_TP) && !(features & ADVERTISED_TP))
+ return -EINVAL;
+
+ if ((cmd->port == PORT_AUI) && !(features & ADVERTISED_AUI))
+ return -EINVAL;
+
+ if ((cmd->port == PORT_BNC) && !(features & ADVERTISED_BNC))
+ return -EINVAL;
+
+ if ((cmd->port == PORT_MII) && !(features & ADVERTISED_MII))
+ return -EINVAL;
+
+ if ((cmd->port == PORT_FIBRE) && !(features & ADVERTISED_FIBRE))
+ return -EINVAL;
+ }
+
+ gbe_intf->slave->phy_port_t = cmd->port;
+ return phy_ethtool_sset(phy, cmd);
+}
+
+static const struct ethtool_ops keystone_ethtool_ops = {
+ .get_drvinfo = keystone_get_drvinfo,
+ .get_link = ethtool_op_get_link,
+ .get_msglevel = keystone_get_msglevel,
+ .set_msglevel = keystone_set_msglevel,
+ .get_strings = keystone_get_stat_strings,
+ .get_sset_count = keystone_get_sset_count,
+ .get_ethtool_stats = keystone_get_ethtool_stats,
+ .get_settings = keystone_get_settings,
+ .set_settings = keystone_set_settings,
+};
+
+#define mac_hi(mac) (((mac)[0] << 0) | ((mac)[1] << 8) | \
+ ((mac)[2] << 16) | ((mac)[3] << 24))
+#define mac_lo(mac) (((mac)[4] << 0) | ((mac)[5] << 8))
+
+static void gbe_set_slave_mac(struct gbe_slave *slave,
+ struct gbe_intf *gbe_intf)
+{
+ struct net_device *ndev = gbe_intf->ndev;
+
+ writel(mac_hi(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_hi));
+ writel(mac_lo(ndev->dev_addr), GBE_REG_ADDR(slave, port_regs, sa_lo));
+}
+
+static int gbe_get_slave_port(struct gbe_priv *priv, u32 slave_num)
+{
+ if (priv->host_port == 0)
+ return slave_num + 1;
+
+ return slave_num;
+}
+
+static void netcp_ethss_link_state_action(struct gbe_priv *gbe_dev,
+ struct net_device *ndev,
+ struct gbe_slave *slave,
+ int up)
+{
+ struct phy_device *phy = slave->phy;
+ u32 mac_control = 0;
+
+ if (up) {
+ mac_control = slave->mac_control;
+ if (phy && (phy->speed == SPEED_1000)) {
+ mac_control |= MACSL_GIG_MODE;
+ mac_control &= ~MACSL_XGIG_MODE;
+ } else if (phy && (phy->speed == SPEED_10000)) {
+ mac_control |= MACSL_XGIG_MODE;
+ mac_control &= ~MACSL_GIG_MODE;
+ }
+
+ writel(mac_control, GBE_REG_ADDR(slave, emac_regs,
+ mac_control));
+
+ cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
+ ALE_PORT_STATE,
+ ALE_PORT_STATE_FORWARD);
+
+ if (ndev && slave->open)
+ netif_carrier_on(ndev);
+ } else {
+ writel(mac_control, GBE_REG_ADDR(slave, emac_regs,
+ mac_control));
+ cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
+ ALE_PORT_STATE,
+ ALE_PORT_STATE_DISABLE);
+ if (ndev)
+ netif_carrier_off(ndev);
+ }
+
+ if (phy)
+ phy_print_status(phy);
+}
+
+static bool gbe_phy_link_status(struct gbe_slave *slave)
+{
+ return !slave->phy || slave->phy->link;
+}
+
+static void netcp_ethss_update_link_state(struct gbe_priv *gbe_dev,
+ struct gbe_slave *slave,
+ struct net_device *ndev)
+{
+ int sp = slave->slave_num;
+ int phy_link_state, sgmii_link_state = 1, link_state;
+
+ if (!slave->open)
+ return;
+
+ if (!SLAVE_LINK_IS_XGMII(slave))
+ sgmii_link_state = netcp_sgmii_get_port_link(SGMII_BASE(sp),
+ sp);
+ phy_link_state = gbe_phy_link_status(slave);
+ link_state = phy_link_state & sgmii_link_state;
+
+ if (atomic_xchg(&slave->link_state, link_state) != link_state)
+ netcp_ethss_link_state_action(gbe_dev, ndev, slave,
+ link_state);
+}
+
+static void xgbe_adjust_link(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct gbe_intf *gbe_intf;
+
+ gbe_intf = netcp_module_get_intf_data(&xgbe_module, netcp);
+ if (!gbe_intf)
+ return;
+
+ netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave,
+ ndev);
+}
+
+static void gbe_adjust_link(struct net_device *ndev)
+{
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct gbe_intf *gbe_intf;
+
+ gbe_intf = netcp_module_get_intf_data(&gbe_module, netcp);
+ if (!gbe_intf)
+ return;
+
+ netcp_ethss_update_link_state(gbe_intf->gbe_dev, gbe_intf->slave,
+ ndev);
+}
+
+static void gbe_adjust_link_sec_slaves(struct net_device *ndev)
+{
+ struct gbe_priv *gbe_dev = netdev_priv(ndev);
+ struct gbe_slave *slave;
+
+ for_each_sec_slave(slave, gbe_dev)
+ netcp_ethss_update_link_state(gbe_dev, slave, NULL);
+}
+
+/* Reset EMAC
+ * Soft reset is set and polled until clear, or until a timeout occurs
+ */
+static int gbe_port_reset(struct gbe_slave *slave)
+{
+ u32 i, v;
+
+ /* Set the soft reset bit */
+ writel(SOFT_RESET, GBE_REG_ADDR(slave, emac_regs, soft_reset));
+
+ /* Wait for the bit to clear */
+ for (i = 0; i < DEVICE_EMACSL_RESET_POLL_COUNT; i++) {
+ v = readl(GBE_REG_ADDR(slave, emac_regs, soft_reset));
+ if ((v & SOFT_RESET_MASK) != SOFT_RESET)
+ return 0;
+ }
+
+ /* Timeout on the reset */
+ return GMACSL_RET_WARN_RESET_INCOMPLETE;
+}
+
+/* Configure EMAC */
+static void gbe_port_config(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
+ int max_rx_len)
+{
+ u32 xgmii_mode;
+
+ if (max_rx_len > NETCP_MAX_FRAME_SIZE)
+ max_rx_len = NETCP_MAX_FRAME_SIZE;
+
+ /* Enable correct MII mode at SS level */
+ if ((gbe_dev->ss_version == XGBE_SS_VERSION_10) &&
+ (slave->link_interface >= XGMII_LINK_MAC_PHY)) {
+ xgmii_mode = readl(GBE_REG_ADDR(gbe_dev, ss_regs, control));
+ xgmii_mode |= (1 << slave->slave_num);
+ writel(xgmii_mode, GBE_REG_ADDR(gbe_dev, ss_regs, control));
+ }
+
+ writel(max_rx_len, GBE_REG_ADDR(slave, emac_regs, rx_maxlen));
+ writel(slave->mac_control, GBE_REG_ADDR(slave, emac_regs, mac_control));
+}
+
+static void gbe_slave_stop(struct gbe_intf *intf)
+{
+ struct gbe_priv *gbe_dev = intf->gbe_dev;
+ struct gbe_slave *slave = intf->slave;
+
+ gbe_port_reset(slave);
+ /* Disable forwarding */
+ cpsw_ale_control_set(gbe_dev->ale, slave->port_num,
+ ALE_PORT_STATE, ALE_PORT_STATE_DISABLE);
+ cpsw_ale_del_mcast(gbe_dev->ale, intf->ndev->broadcast,
+ 1 << slave->port_num, 0, 0);
+
+ if (!slave->phy)
+ return;
+
+ phy_stop(slave->phy);
+ phy_disconnect(slave->phy);
+ slave->phy = NULL;
+}
+
+static void gbe_sgmii_config(struct gbe_priv *priv, struct gbe_slave *slave)
+{
+ void __iomem *sgmii_port_regs;
+
+ sgmii_port_regs = priv->sgmii_port_regs;
+ if ((priv->ss_version == GBE_SS_VERSION_14) && (slave->slave_num >= 2))
+ sgmii_port_regs = priv->sgmii_port34_regs;
+
+ if (!SLAVE_LINK_IS_XGMII(slave)) {
+ netcp_sgmii_reset(sgmii_port_regs, slave->slave_num);
+ netcp_sgmii_config(sgmii_port_regs, slave->slave_num,
+ slave->link_interface);
+ }
+}
+
+static int gbe_slave_open(struct gbe_intf *gbe_intf)
+{
+ struct gbe_priv *priv = gbe_intf->gbe_dev;
+ struct gbe_slave *slave = gbe_intf->slave;
+ phy_interface_t phy_mode;
+ bool has_phy = false;
+
+ void (*hndlr)(struct net_device *) = gbe_adjust_link;
+
+ gbe_sgmii_config(priv, slave);
+ gbe_port_reset(slave);
+ gbe_port_config(priv, slave, priv->rx_packet_max);
+ gbe_set_slave_mac(slave, gbe_intf);
+ /* enable forwarding */
+ cpsw_ale_control_set(priv->ale, slave->port_num,
+ ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
+ cpsw_ale_add_mcast(priv->ale, gbe_intf->ndev->broadcast,
+ 1 << slave->port_num, 0, 0, ALE_MCAST_FWD_2);
+
+ if (slave->link_interface == SGMII_LINK_MAC_PHY) {
+ has_phy = true;
+ phy_mode = PHY_INTERFACE_MODE_SGMII;
+ slave->phy_port_t = PORT_MII;
+ } else if (slave->link_interface == XGMII_LINK_MAC_PHY) {
+ has_phy = true;
+ phy_mode = PHY_INTERFACE_MODE_NA;
+ slave->phy_port_t = PORT_FIBRE;
+ }
+
+ if (has_phy) {
+ if (priv->ss_version == XGBE_SS_VERSION_10)
+ hndlr = xgbe_adjust_link;
+
+ slave->phy = of_phy_connect(gbe_intf->ndev,
+ slave->phy_node,
+ hndlr, 0,
+ phy_mode);
+ if (!slave->phy) {
+ dev_err(priv->dev, "phy not found on slave %d\n",
+ slave->slave_num);
+ return -ENODEV;
+ }
+ dev_dbg(priv->dev, "phy found: id is: 0x%s\n",
+ dev_name(&slave->phy->dev));
+ phy_start(slave->phy);
+ phy_read_status(slave->phy);
+ }
+ return 0;
+}
+
+static void gbe_init_host_port(struct gbe_priv *priv)
+{
+ int bypass_en = 1;
+ /* Max length register */
+ writel(NETCP_MAX_FRAME_SIZE, GBE_REG_ADDR(priv, host_port_regs,
+ rx_maxlen));
+
+ cpsw_ale_start(priv->ale);
+
+ if (priv->enable_ale)
+ bypass_en = 0;
+
+ cpsw_ale_control_set(priv->ale, 0, ALE_BYPASS, bypass_en);
+
+ cpsw_ale_control_set(priv->ale, 0, ALE_NO_PORT_VLAN, 1);
+
+ cpsw_ale_control_set(priv->ale, priv->host_port,
+ ALE_PORT_STATE, ALE_PORT_STATE_FORWARD);
+
+ cpsw_ale_control_set(priv->ale, 0,
+ ALE_PORT_UNKNOWN_VLAN_MEMBER,
+ GBE_PORT_MASK(priv->ale_ports));
+
+ cpsw_ale_control_set(priv->ale, 0,
+ ALE_PORT_UNKNOWN_MCAST_FLOOD,
+ GBE_PORT_MASK(priv->ale_ports - 1));
+
+ cpsw_ale_control_set(priv->ale, 0,
+ ALE_PORT_UNKNOWN_REG_MCAST_FLOOD,
+ GBE_PORT_MASK(priv->ale_ports));
+
+ cpsw_ale_control_set(priv->ale, 0,
+ ALE_PORT_UNTAGGED_EGRESS,
+ GBE_PORT_MASK(priv->ale_ports));
+}
+
+static void gbe_add_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr)
+{
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+ u16 vlan_id;
+
+ cpsw_ale_add_mcast(gbe_dev->ale, addr,
+ GBE_PORT_MASK(gbe_dev->ale_ports), 0, 0,
+ ALE_MCAST_FWD_2);
+ for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) {
+ cpsw_ale_add_mcast(gbe_dev->ale, addr,
+ GBE_PORT_MASK(gbe_dev->ale_ports),
+ ALE_VLAN, vlan_id, ALE_MCAST_FWD_2);
+ }
+}
+
+static void gbe_add_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr)
+{
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+ u16 vlan_id;
+
+ cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0);
+
+ for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID)
+ cpsw_ale_add_ucast(gbe_dev->ale, addr, gbe_dev->host_port,
+ ALE_VLAN, vlan_id);
+}
+
+static void gbe_del_mcast_addr(struct gbe_intf *gbe_intf, u8 *addr)
+{
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+ u16 vlan_id;
+
+ cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, 0, 0);
+
+ for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) {
+ cpsw_ale_del_mcast(gbe_dev->ale, addr, 0, ALE_VLAN, vlan_id);
+ }
+}
+
+static void gbe_del_ucast_addr(struct gbe_intf *gbe_intf, u8 *addr)
+{
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+ u16 vlan_id;
+
+ cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port, 0, 0);
+
+ for_each_set_bit(vlan_id, gbe_intf->active_vlans, VLAN_N_VID) {
+ cpsw_ale_del_ucast(gbe_dev->ale, addr, gbe_dev->host_port,
+ ALE_VLAN, vlan_id);
+ }
+}
+
+static int gbe_add_addr(void *intf_priv, struct netcp_addr *naddr)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+
+ dev_dbg(gbe_dev->dev, "ethss adding address %pM, type %d\n",
+ naddr->addr, naddr->type);
+
+ switch (naddr->type) {
+ case ADDR_MCAST:
+ case ADDR_BCAST:
+ gbe_add_mcast_addr(gbe_intf, naddr->addr);
+ break;
+ case ADDR_UCAST:
+ case ADDR_DEV:
+ gbe_add_ucast_addr(gbe_intf, naddr->addr);
+ break;
+ case ADDR_ANY:
+ /* nothing to do for promiscuous */
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int gbe_del_addr(void *intf_priv, struct netcp_addr *naddr)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+
+ dev_dbg(gbe_dev->dev, "ethss deleting address %pM, type %d\n",
+ naddr->addr, naddr->type);
+
+ switch (naddr->type) {
+ case ADDR_MCAST:
+ case ADDR_BCAST:
+ gbe_del_mcast_addr(gbe_intf, naddr->addr);
+ break;
+ case ADDR_UCAST:
+ case ADDR_DEV:
+ gbe_del_ucast_addr(gbe_intf, naddr->addr);
+ break;
+ case ADDR_ANY:
+ /* nothing to do for promiscuous */
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int gbe_add_vid(void *intf_priv, int vid)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+
+ set_bit(vid, gbe_intf->active_vlans);
+
+ cpsw_ale_add_vlan(gbe_dev->ale, vid,
+ GBE_PORT_MASK(gbe_dev->ale_ports),
+ GBE_MASK_NO_PORTS,
+ GBE_PORT_MASK(gbe_dev->ale_ports),
+ GBE_PORT_MASK(gbe_dev->ale_ports - 1));
+
+ return 0;
+}
+
+static int gbe_del_vid(void *intf_priv, int vid)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+
+ cpsw_ale_del_vlan(gbe_dev->ale, vid, 0);
+ clear_bit(vid, gbe_intf->active_vlans);
+ return 0;
+}
+
+static int gbe_ioctl(void *intf_priv, struct ifreq *req, int cmd)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct phy_device *phy = gbe_intf->slave->phy;
+ int ret = -EOPNOTSUPP;
+
+ if (phy)
+ ret = phy_mii_ioctl(phy, req, cmd);
+
+ return ret;
+}
+
+static void netcp_ethss_timer(unsigned long arg)
+{
+ struct gbe_priv *gbe_dev = (struct gbe_priv *)arg;
+ struct gbe_intf *gbe_intf;
+ struct gbe_slave *slave;
+
+ /* Check & update SGMII link state of interfaces */
+ for_each_intf(gbe_intf, gbe_dev) {
+ if (!gbe_intf->slave->open)
+ continue;
+ netcp_ethss_update_link_state(gbe_dev, gbe_intf->slave,
+ gbe_intf->ndev);
+ }
+
+ /* Check & update SGMII link state of secondary ports */
+ for_each_sec_slave(slave, gbe_dev) {
+ netcp_ethss_update_link_state(gbe_dev, slave, NULL);
+ }
+
+ spin_lock_bh(&gbe_dev->hw_stats_lock);
+
+ if (gbe_dev->ss_version == GBE_SS_VERSION_14)
+ gbe_update_stats_ver14(gbe_dev, NULL);
+ else
+ gbe_update_stats(gbe_dev, NULL);
+
+ spin_unlock_bh(&gbe_dev->hw_stats_lock);
+
+ gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL;
+ add_timer(&gbe_dev->timer);
+}
+
+static int gbe_tx_hook(int order, void *data, struct netcp_packet *p_info)
+{
+ struct gbe_intf *gbe_intf = data;
+
+ p_info->tx_pipe = &gbe_intf->tx_pipe;
+ return 0;
+}
+
+static int gbe_open(void *intf_priv, struct net_device *ndev)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct gbe_priv *gbe_dev = gbe_intf->gbe_dev;
+ struct netcp_intf *netcp = netdev_priv(ndev);
+ struct gbe_slave *slave = gbe_intf->slave;
+ int port_num = slave->port_num;
+ u32 reg;
+ int ret;
+
+ reg = readl(GBE_REG_ADDR(gbe_dev, switch_regs, id_ver));
+ dev_dbg(gbe_dev->dev, "initializing gbe version %d.%d (%d) GBE identification value 0x%x\n",
+ GBE_MAJOR_VERSION(reg), GBE_MINOR_VERSION(reg),
+ GBE_RTL_VERSION(reg), GBE_IDENT(reg));
+
+ if (gbe_dev->enable_ale)
+ gbe_intf->tx_pipe.dma_psflags = 0;
+ else
+ gbe_intf->tx_pipe.dma_psflags = port_num;
+
+ dev_dbg(gbe_dev->dev, "opened TX channel %s: %p with psflags %d\n",
+ gbe_intf->tx_pipe.dma_chan_name,
+ gbe_intf->tx_pipe.dma_channel,
+ gbe_intf->tx_pipe.dma_psflags);
+
+ gbe_slave_stop(gbe_intf);
+
+ /* disable priority elevation and enable statistics on all ports */
+ writel(0, GBE_REG_ADDR(gbe_dev, switch_regs, ptype));
+
+ /* Control register */
+ writel(GBE_CTL_P0_ENABLE, GBE_REG_ADDR(gbe_dev, switch_regs, control));
+
+ /* All statistics enabled and STAT AB visible by default */
+ writel(GBE_REG_VAL_STAT_ENABLE_ALL, GBE_REG_ADDR(gbe_dev, switch_regs,
+ stat_port_en));
+
+ ret = gbe_slave_open(gbe_intf);
+ if (ret)
+ goto fail;
+
+ netcp_register_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook,
+ gbe_intf);
+
+ slave->open = true;
+ netcp_ethss_update_link_state(gbe_dev, slave, ndev);
+ return 0;
+
+fail:
+ gbe_slave_stop(gbe_intf);
+ return ret;
+}
+
+static int gbe_close(void *intf_priv, struct net_device *ndev)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+ struct netcp_intf *netcp = netdev_priv(ndev);
+
+ gbe_slave_stop(gbe_intf);
+ netcp_unregister_txhook(netcp, GBE_TXHOOK_ORDER, gbe_tx_hook,
+ gbe_intf);
+
+ gbe_intf->slave->open = false;
+ atomic_set(&gbe_intf->slave->link_state, NETCP_LINK_STATE_INVALID);
+ return 0;
+}
+
+static int init_slave(struct gbe_priv *gbe_dev, struct gbe_slave *slave,
+ struct device_node *node)
+{
+ int port_reg_num;
+ u32 port_reg_ofs, emac_reg_ofs;
+
+ if (of_property_read_u32(node, "slave-port", &slave->slave_num)) {
+ dev_err(gbe_dev->dev, "missing slave-port parameter\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(node, "link-interface",
+ &slave->link_interface)) {
+ dev_warn(gbe_dev->dev,
+ "missing link-interface value defaulting to 1G mac-phy link\n");
+ slave->link_interface = SGMII_LINK_MAC_PHY;
+ }
+
+ slave->open = false;
+ slave->phy_node = of_parse_phandle(node, "phy-handle", 0);
+ slave->port_num = gbe_get_slave_port(gbe_dev, slave->slave_num);
+
+ if (slave->link_interface >= XGMII_LINK_MAC_PHY)
+ slave->mac_control = GBE_DEF_10G_MAC_CONTROL;
+ else
+ slave->mac_control = GBE_DEF_1G_MAC_CONTROL;
+
+ /* Emac regs memmap are contiguous but port regs are not */
+ port_reg_num = slave->slave_num;
+ if (gbe_dev->ss_version == GBE_SS_VERSION_14) {
+ if (slave->slave_num > 1) {
+ port_reg_ofs = GBE13_SLAVE_PORT2_OFFSET;
+ port_reg_num -= 2;
+ } else {
+ port_reg_ofs = GBE13_SLAVE_PORT_OFFSET;
+ }
+ } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) {
+ port_reg_ofs = XGBE10_SLAVE_PORT_OFFSET;
+ } else {
+ dev_err(gbe_dev->dev, "unknown ethss(0x%x)\n",
+ gbe_dev->ss_version);
+ return -EINVAL;
+ }
+
+ if (gbe_dev->ss_version == GBE_SS_VERSION_14)
+ emac_reg_ofs = GBE13_EMAC_OFFSET;
+ else if (gbe_dev->ss_version == XGBE_SS_VERSION_10)
+ emac_reg_ofs = XGBE10_EMAC_OFFSET;
+
+ slave->port_regs = gbe_dev->ss_regs + port_reg_ofs +
+ (0x30 * port_reg_num);
+ slave->emac_regs = gbe_dev->ss_regs + emac_reg_ofs +
+ (0x40 * slave->slave_num);
+
+ if (gbe_dev->ss_version == GBE_SS_VERSION_14) {
+ /* Initialize slave port register offsets */
+ GBE_SET_REG_OFS(slave, port_regs, port_vlan);
+ GBE_SET_REG_OFS(slave, port_regs, tx_pri_map);
+ GBE_SET_REG_OFS(slave, port_regs, sa_lo);
+ GBE_SET_REG_OFS(slave, port_regs, sa_hi);
+ GBE_SET_REG_OFS(slave, port_regs, ts_ctl);
+ GBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype);
+ GBE_SET_REG_OFS(slave, port_regs, ts_vlan);
+ GBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2);
+ GBE_SET_REG_OFS(slave, port_regs, ts_ctl2);
+
+ /* Initialize EMAC register offsets */
+ GBE_SET_REG_OFS(slave, emac_regs, mac_control);
+ GBE_SET_REG_OFS(slave, emac_regs, soft_reset);
+ GBE_SET_REG_OFS(slave, emac_regs, rx_maxlen);
+
+ } else if (gbe_dev->ss_version == XGBE_SS_VERSION_10) {
+ /* Initialize slave port register offsets */
+ XGBE_SET_REG_OFS(slave, port_regs, port_vlan);
+ XGBE_SET_REG_OFS(slave, port_regs, tx_pri_map);
+ XGBE_SET_REG_OFS(slave, port_regs, sa_lo);
+ XGBE_SET_REG_OFS(slave, port_regs, sa_hi);
+ XGBE_SET_REG_OFS(slave, port_regs, ts_ctl);
+ XGBE_SET_REG_OFS(slave, port_regs, ts_seq_ltype);
+ XGBE_SET_REG_OFS(slave, port_regs, ts_vlan);
+ XGBE_SET_REG_OFS(slave, port_regs, ts_ctl_ltype2);
+ XGBE_SET_REG_OFS(slave, port_regs, ts_ctl2);
+
+ /* Initialize EMAC register offsets */
+ XGBE_SET_REG_OFS(slave, emac_regs, mac_control);
+ XGBE_SET_REG_OFS(slave, emac_regs, soft_reset);
+ XGBE_SET_REG_OFS(slave, emac_regs, rx_maxlen);
+ }
+
+ atomic_set(&slave->link_state, NETCP_LINK_STATE_INVALID);
+ return 0;
+}
+
+static void init_secondary_ports(struct gbe_priv *gbe_dev,
+ struct device_node *node)
+{
+ struct device *dev = gbe_dev->dev;
+ phy_interface_t phy_mode;
+ struct gbe_priv **priv;
+ struct device_node *port;
+ struct gbe_slave *slave;
+ bool mac_phy_link = false;
+
+ for_each_child_of_node(node, port) {
+ slave = devm_kzalloc(dev, sizeof(*slave), GFP_KERNEL);
+ if (!slave) {
+ dev_err(dev,
+ "memomry alloc failed for secondary port(%s), skipping...\n",
+ port->name);
+ continue;
+ }
+
+ if (init_slave(gbe_dev, slave, port)) {
+ dev_err(dev,
+ "Failed to initialize secondary port(%s), skipping...\n",
+ port->name);
+ devm_kfree(dev, slave);
+ continue;
+ }
+
+ gbe_sgmii_config(gbe_dev, slave);
+ gbe_port_reset(slave);
+ gbe_port_config(gbe_dev, slave, gbe_dev->rx_packet_max);
+ list_add_tail(&slave->slave_list, &gbe_dev->secondary_slaves);
+ gbe_dev->num_slaves++;
+ if ((slave->link_interface == SGMII_LINK_MAC_PHY) ||
+ (slave->link_interface == XGMII_LINK_MAC_PHY))
+ mac_phy_link = true;
+
+ slave->open = true;
+ }
+
+ /* of_phy_connect() is needed only for MAC-PHY interface */
+ if (!mac_phy_link)
+ return;
+
+ /* Allocate dummy netdev device for attaching to phy device */
+ gbe_dev->dummy_ndev = alloc_netdev(sizeof(gbe_dev), "dummy",
+ NET_NAME_UNKNOWN, ether_setup);
+ if (!gbe_dev->dummy_ndev) {
+ dev_err(dev,
+ "Failed to allocate dummy netdev for secondary ports, skipping phy_connect()...\n");
+ return;
+ }
+ priv = netdev_priv(gbe_dev->dummy_ndev);
+ *priv = gbe_dev;
+
+ if (slave->link_interface == SGMII_LINK_MAC_PHY) {
+ phy_mode = PHY_INTERFACE_MODE_SGMII;
+ slave->phy_port_t = PORT_MII;
+ } else {
+ phy_mode = PHY_INTERFACE_MODE_NA;
+ slave->phy_port_t = PORT_FIBRE;
+ }
+
+ for_each_sec_slave(slave, gbe_dev) {
+ if ((slave->link_interface != SGMII_LINK_MAC_PHY) &&
+ (slave->link_interface != XGMII_LINK_MAC_PHY))
+ continue;
+ slave->phy =
+ of_phy_connect(gbe_dev->dummy_ndev,
+ slave->phy_node,
+ gbe_adjust_link_sec_slaves,
+ 0, phy_mode);
+ if (!slave->phy) {
+ dev_err(dev, "phy not found for slave %d\n",
+ slave->slave_num);
+ slave->phy = NULL;
+ } else {
+ dev_dbg(dev, "phy found: id is: 0x%s\n",
+ dev_name(&slave->phy->dev));
+ phy_start(slave->phy);
+ phy_read_status(slave->phy);
+ }
+ }
+}
+
+static void free_secondary_ports(struct gbe_priv *gbe_dev)
+{
+ struct gbe_slave *slave;
+
+ for (;;) {
+ slave = first_sec_slave(gbe_dev);
+ if (!slave)
+ break;
+ if (slave->phy)
+ phy_disconnect(slave->phy);
+ list_del(&slave->slave_list);
+ }
+ if (gbe_dev->dummy_ndev)
+ free_netdev(gbe_dev->dummy_ndev);
+}
+
+static int set_xgbe_ethss10_priv(struct gbe_priv *gbe_dev,
+ struct device_node *node)
+{
+ struct resource res;
+ void __iomem *regs;
+ int ret, i;
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe subsystem regs\n",
+ node->name);
+ return ret;
+ }
+
+ regs = devm_ioremap_resource(gbe_dev->dev, &res);
+ if (IS_ERR(regs)) {
+ dev_err(gbe_dev->dev, "Failed to map xgbe register base\n");
+ return PTR_ERR(regs);
+ }
+ gbe_dev->ss_regs = regs;
+
+ ret = of_address_to_resource(node, XGBE_SERDES_REG_INDEX, &res);
+ if (ret) {
+ dev_err(gbe_dev->dev, "Can't translate of node(%s) address for xgbe serdes regs\n",
+ node->name);
+ return ret;
+ }
+
+ regs = devm_ioremap_resource(gbe_dev->dev, &res);
+ if (IS_ERR(regs)) {
+ dev_err(gbe_dev->dev, "Failed to map xgbe serdes register base\n");
+ return PTR_ERR(regs);
+ }
+ gbe_dev->xgbe_serdes_regs = regs;
+
+ gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev,
+ XGBE10_NUM_STAT_ENTRIES *
+ (XGBE10_NUM_SLAVES + 1) * sizeof(u64),
+ GFP_KERNEL);
+ if (!gbe_dev->hw_stats) {
+ dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ gbe_dev->ss_version = XGBE_SS_VERSION_10;
+ gbe_dev->sgmii_port_regs = gbe_dev->ss_regs +
+ XGBE10_SGMII_MODULE_OFFSET;
+ gbe_dev->switch_regs = gbe_dev->ss_regs + XGBE10_SWITCH_MODULE_OFFSET;
+ gbe_dev->host_port_regs = gbe_dev->ss_regs + XGBE10_HOST_PORT_OFFSET;
+
+ for (i = 0; i < XGBE10_NUM_HW_STATS_MOD; i++)
+ gbe_dev->hw_stats_regs[i] = gbe_dev->ss_regs +
+ XGBE10_HW_STATS_OFFSET + (GBE_HW_STATS_REG_MAP_SZ * i);
+
+ gbe_dev->ale_reg = gbe_dev->ss_regs + XGBE10_ALE_OFFSET;
+ gbe_dev->ale_ports = XGBE10_NUM_ALE_PORTS;
+ gbe_dev->host_port = XGBE10_HOST_PORT_NUM;
+ gbe_dev->ale_entries = XGBE10_NUM_ALE_ENTRIES;
+ gbe_dev->et_stats = xgbe10_et_stats;
+ gbe_dev->num_et_stats = ARRAY_SIZE(xgbe10_et_stats);
+
+ /* Subsystem registers */
+ XGBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver);
+ XGBE_SET_REG_OFS(gbe_dev, ss_regs, control);
+
+ /* Switch module registers */
+ XGBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver);
+ XGBE_SET_REG_OFS(gbe_dev, switch_regs, control);
+ XGBE_SET_REG_OFS(gbe_dev, switch_regs, ptype);
+ XGBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en);
+ XGBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control);
+
+ /* Host port registers */
+ XGBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan);
+ XGBE_SET_REG_OFS(gbe_dev, host_port_regs, tx_pri_map);
+ XGBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen);
+ return 0;
+}
+
+static int get_gbe_resource_version(struct gbe_priv *gbe_dev,
+ struct device_node *node)
+{
+ struct resource res;
+ void __iomem *regs;
+ int ret;
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(gbe_dev->dev, "Can't translate of node(%s) address\n",
+ node->name);
+ return ret;
+ }
+
+ regs = devm_ioremap_resource(gbe_dev->dev, &res);
+ if (IS_ERR(regs)) {
+ dev_err(gbe_dev->dev, "Failed to map gbe register base\n");
+ return PTR_ERR(regs);
+ }
+ gbe_dev->ss_regs = regs;
+ gbe_dev->ss_version = readl(gbe_dev->ss_regs);
+ return 0;
+}
+
+static int set_gbe_ethss14_priv(struct gbe_priv *gbe_dev,
+ struct device_node *node)
+{
+ void __iomem *regs;
+ int i;
+
+ gbe_dev->hw_stats = devm_kzalloc(gbe_dev->dev,
+ GBE13_NUM_HW_STAT_ENTRIES *
+ GBE13_NUM_SLAVES * sizeof(u64),
+ GFP_KERNEL);
+ if (!gbe_dev->hw_stats) {
+ dev_err(gbe_dev->dev, "hw_stats memory allocation failed\n");
+ return -ENOMEM;
+ }
+
+ regs = gbe_dev->ss_regs;
+ gbe_dev->sgmii_port_regs = regs + GBE13_SGMII_MODULE_OFFSET;
+ gbe_dev->sgmii_port34_regs = regs + GBE13_SGMII34_MODULE_OFFSET;
+ gbe_dev->switch_regs = regs + GBE13_SWITCH_MODULE_OFFSET;
+ gbe_dev->host_port_regs = regs + GBE13_HOST_PORT_OFFSET;
+
+ for (i = 0; i < GBE13_NUM_HW_STATS_MOD; i++)
+ gbe_dev->hw_stats_regs[i] = regs + GBE13_HW_STATS_OFFSET +
+ (GBE_HW_STATS_REG_MAP_SZ * i);
+
+ gbe_dev->ale_reg = regs + GBE13_ALE_OFFSET;
+ gbe_dev->ale_ports = GBE13_NUM_ALE_PORTS;
+ gbe_dev->host_port = GBE13_HOST_PORT_NUM;
+ gbe_dev->ale_entries = GBE13_NUM_ALE_ENTRIES;
+ gbe_dev->et_stats = gbe13_et_stats;
+ gbe_dev->num_et_stats = ARRAY_SIZE(gbe13_et_stats);
+
+ /* Subsystem registers */
+ GBE_SET_REG_OFS(gbe_dev, ss_regs, id_ver);
+
+ /* Switch module registers */
+ GBE_SET_REG_OFS(gbe_dev, switch_regs, id_ver);
+ GBE_SET_REG_OFS(gbe_dev, switch_regs, control);
+ GBE_SET_REG_OFS(gbe_dev, switch_regs, soft_reset);
+ GBE_SET_REG_OFS(gbe_dev, switch_regs, stat_port_en);
+ GBE_SET_REG_OFS(gbe_dev, switch_regs, ptype);
+ GBE_SET_REG_OFS(gbe_dev, switch_regs, flow_control);
+
+ /* Host port registers */
+ GBE_SET_REG_OFS(gbe_dev, host_port_regs, port_vlan);
+ GBE_SET_REG_OFS(gbe_dev, host_port_regs, rx_maxlen);
+ return 0;
+}
+
+static int gbe_probe(struct netcp_device *netcp_device, struct device *dev,
+ struct device_node *node, void **inst_priv)
+{
+ struct device_node *interfaces, *interface;
+ struct device_node *secondary_ports;
+ struct cpsw_ale_params ale_params;
+ struct gbe_priv *gbe_dev;
+ u32 slave_num;
+ int ret = 0;
+
+ if (!node) {
+ dev_err(dev, "device tree info unavailable\n");
+ return -ENODEV;
+ }
+
+ gbe_dev = devm_kzalloc(dev, sizeof(struct gbe_priv), GFP_KERNEL);
+ if (!gbe_dev)
+ return -ENOMEM;
+
+ gbe_dev->dev = dev;
+ gbe_dev->netcp_device = netcp_device;
+ gbe_dev->rx_packet_max = NETCP_MAX_FRAME_SIZE;
+
+ /* init the hw stats lock */
+ spin_lock_init(&gbe_dev->hw_stats_lock);
+
+ if (of_find_property(node, "enable-ale", NULL)) {
+ gbe_dev->enable_ale = true;
+ dev_info(dev, "ALE enabled\n");
+ } else {
+ gbe_dev->enable_ale = false;
+ dev_dbg(dev, "ALE bypass enabled*\n");
+ }
+
+ ret = of_property_read_u32(node, "tx-queue",
+ &gbe_dev->tx_queue_id);
+ if (ret < 0) {
+ dev_err(dev, "missing tx_queue parameter\n");
+ gbe_dev->tx_queue_id = GBE_TX_QUEUE;
+ }
+
+ ret = of_property_read_string(node, "tx-channel",
+ &gbe_dev->dma_chan_name);
+ if (ret < 0) {
+ dev_err(dev, "missing \"tx-channel\" parameter\n");
+ ret = -ENODEV;
+ goto quit;
+ }
+
+ if (!strcmp(node->name, "gbe")) {
+ ret = get_gbe_resource_version(gbe_dev, node);
+ if (ret)
+ goto quit;
+
+ ret = set_gbe_ethss14_priv(gbe_dev, node);
+ if (ret)
+ goto quit;
+ } else if (!strcmp(node->name, "xgbe")) {
+ ret = set_xgbe_ethss10_priv(gbe_dev, node);
+ if (ret)
+ goto quit;
+ ret = netcp_xgbe_serdes_init(gbe_dev->xgbe_serdes_regs,
+ gbe_dev->ss_regs);
+ if (ret)
+ goto quit;
+ } else {
+ dev_err(dev, "unknown GBE node(%s)\n", node->name);
+ ret = -ENODEV;
+ goto quit;
+ }
+
+ interfaces = of_get_child_by_name(node, "interfaces");
+ if (!interfaces)
+ dev_err(dev, "could not find interfaces\n");
+
+ ret = netcp_txpipe_init(&gbe_dev->tx_pipe, netcp_device,
+ gbe_dev->dma_chan_name, gbe_dev->tx_queue_id);
+ if (ret)
+ goto quit;
+
+ ret = netcp_txpipe_open(&gbe_dev->tx_pipe);
+ if (ret)
+ goto quit;
+
+ /* Create network interfaces */
+ INIT_LIST_HEAD(&gbe_dev->gbe_intf_head);
+ for_each_child_of_node(interfaces, interface) {
+ ret = of_property_read_u32(interface, "slave-port", &slave_num);
+ if (ret) {
+ dev_err(dev, "missing slave-port parameter, skipping interface configuration for %s\n",
+ interface->name);
+ continue;
+ }
+ gbe_dev->num_slaves++;
+ }
+
+ if (!gbe_dev->num_slaves)
+ dev_warn(dev, "No network interface configured\n");
+
+ /* Initialize Secondary slave ports */
+ secondary_ports = of_get_child_by_name(node, "secondary-slave-ports");
+ INIT_LIST_HEAD(&gbe_dev->secondary_slaves);
+ if (secondary_ports)
+ init_secondary_ports(gbe_dev, secondary_ports);
+ of_node_put(secondary_ports);
+
+ if (!gbe_dev->num_slaves) {
+ dev_err(dev, "No network interface or secondary ports configured\n");
+ ret = -ENODEV;
+ goto quit;
+ }
+
+ memset(&ale_params, 0, sizeof(ale_params));
+ ale_params.dev = gbe_dev->dev;
+ ale_params.ale_regs = gbe_dev->ale_reg;
+ ale_params.ale_ageout = GBE_DEFAULT_ALE_AGEOUT;
+ ale_params.ale_entries = gbe_dev->ale_entries;
+ ale_params.ale_ports = gbe_dev->ale_ports;
+
+ gbe_dev->ale = cpsw_ale_create(&ale_params);
+ if (!gbe_dev->ale) {
+ dev_err(gbe_dev->dev, "error initializing ale engine\n");
+ ret = -ENODEV;
+ goto quit;
+ } else {
+ dev_dbg(gbe_dev->dev, "Created a gbe ale engine\n");
+ }
+
+ /* initialize host port */
+ gbe_init_host_port(gbe_dev);
+
+ init_timer(&gbe_dev->timer);
+ gbe_dev->timer.data = (unsigned long)gbe_dev;
+ gbe_dev->timer.function = netcp_ethss_timer;
+ gbe_dev->timer.expires = jiffies + GBE_TIMER_INTERVAL;
+ add_timer(&gbe_dev->timer);
+ *inst_priv = gbe_dev;
+ return 0;
+
+quit:
+ if (gbe_dev->hw_stats)
+ devm_kfree(dev, gbe_dev->hw_stats);
+ cpsw_ale_destroy(gbe_dev->ale);
+ if (gbe_dev->ss_regs)
+ devm_iounmap(dev, gbe_dev->ss_regs);
+ of_node_put(interfaces);
+ devm_kfree(dev, gbe_dev);
+ return ret;
+}
+
+static int gbe_attach(void *inst_priv, struct net_device *ndev,
+ struct device_node *node, void **intf_priv)
+{
+ struct gbe_priv *gbe_dev = inst_priv;
+ struct gbe_intf *gbe_intf;
+ int ret;
+
+ if (!node) {
+ dev_err(gbe_dev->dev, "interface node not available\n");
+ return -ENODEV;
+ }
+
+ gbe_intf = devm_kzalloc(gbe_dev->dev, sizeof(*gbe_intf), GFP_KERNEL);
+ if (!gbe_intf)
+ return -ENOMEM;
+
+ gbe_intf->ndev = ndev;
+ gbe_intf->dev = gbe_dev->dev;
+ gbe_intf->gbe_dev = gbe_dev;
+
+ gbe_intf->slave = devm_kzalloc(gbe_dev->dev,
+ sizeof(*gbe_intf->slave),
+ GFP_KERNEL);
+ if (!gbe_intf->slave) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ if (init_slave(gbe_dev, gbe_intf->slave, node)) {
+ ret = -ENODEV;
+ goto fail;
+ }
+
+ gbe_intf->tx_pipe = gbe_dev->tx_pipe;
+ ndev->ethtool_ops = &keystone_ethtool_ops;
+ list_add_tail(&gbe_intf->gbe_intf_list, &gbe_dev->gbe_intf_head);
+ *intf_priv = gbe_intf;
+ return 0;
+
+fail:
+ if (gbe_intf->slave)
+ devm_kfree(gbe_dev->dev, gbe_intf->slave);
+ if (gbe_intf)
+ devm_kfree(gbe_dev->dev, gbe_intf);
+ return ret;
+}
+
+static int gbe_release(void *intf_priv)
+{
+ struct gbe_intf *gbe_intf = intf_priv;
+
+ gbe_intf->ndev->ethtool_ops = NULL;
+ list_del(&gbe_intf->gbe_intf_list);
+ devm_kfree(gbe_intf->dev, gbe_intf->slave);
+ devm_kfree(gbe_intf->dev, gbe_intf);
+ return 0;
+}
+
+static int gbe_remove(struct netcp_device *netcp_device, void *inst_priv)
+{
+ struct gbe_priv *gbe_dev = inst_priv;
+
+ del_timer_sync(&gbe_dev->timer);
+ cpsw_ale_stop(gbe_dev->ale);
+ cpsw_ale_destroy(gbe_dev->ale);
+ netcp_txpipe_close(&gbe_dev->tx_pipe);
+ free_secondary_ports(gbe_dev);
+
+ if (!list_empty(&gbe_dev->gbe_intf_head))
+ dev_alert(gbe_dev->dev, "unreleased ethss interfaces present\n");
+
+ devm_kfree(gbe_dev->dev, gbe_dev->hw_stats);
+ devm_iounmap(gbe_dev->dev, gbe_dev->ss_regs);
+ memset(gbe_dev, 0x00, sizeof(*gbe_dev));
+ devm_kfree(gbe_dev->dev, gbe_dev);
+ return 0;
+}
+
+static struct netcp_module gbe_module = {
+ .name = GBE_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .primary = true,
+ .probe = gbe_probe,
+ .open = gbe_open,
+ .close = gbe_close,
+ .remove = gbe_remove,
+ .attach = gbe_attach,
+ .release = gbe_release,
+ .add_addr = gbe_add_addr,
+ .del_addr = gbe_del_addr,
+ .add_vid = gbe_add_vid,
+ .del_vid = gbe_del_vid,
+ .ioctl = gbe_ioctl,
+};
+
+static struct netcp_module xgbe_module = {
+ .name = XGBE_MODULE_NAME,
+ .owner = THIS_MODULE,
+ .primary = true,
+ .probe = gbe_probe,
+ .open = gbe_open,
+ .close = gbe_close,
+ .remove = gbe_remove,
+ .attach = gbe_attach,
+ .release = gbe_release,
+ .add_addr = gbe_add_addr,
+ .del_addr = gbe_del_addr,
+ .add_vid = gbe_add_vid,
+ .del_vid = gbe_del_vid,
+ .ioctl = gbe_ioctl,
+};
+
+static int __init keystone_gbe_init(void)
+{
+ int ret;
+
+ ret = netcp_register_module(&gbe_module);
+ if (ret)
+ return ret;
+
+ ret = netcp_register_module(&xgbe_module);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+module_init(keystone_gbe_init);
+
+static void __exit keystone_gbe_exit(void)
+{
+ netcp_unregister_module(&gbe_module);
+ netcp_unregister_module(&xgbe_module);
+}
+module_exit(keystone_gbe_exit);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("TI NETCP ETHSS driver for Keystone SOCs");
+MODULE_AUTHOR("Sandeep Nair <sandeep_n@ti.com");
diff --git a/drivers/net/ethernet/ti/netcp_sgmii.c b/drivers/net/ethernet/ti/netcp_sgmii.c
new file mode 100644
index 000000000000..dbeb14266e2f
--- /dev/null
+++ b/drivers/net/ethernet/ti/netcp_sgmii.c
@@ -0,0 +1,131 @@
+/*
+ * SGMI module initialisation
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors: Sandeep Nair <sandeep_n@ti.com>
+ * Sandeep Paulraj <s-paulraj@ti.com>
+ * Wingman Kwok <w-kwok2@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 "netcp.h"
+
+#define SGMII_REG_STATUS_LOCK BIT(4)
+#define SGMII_REG_STATUS_LINK BIT(0)
+#define SGMII_REG_STATUS_AUTONEG BIT(2)
+#define SGMII_REG_CONTROL_AUTONEG BIT(0)
+
+#define SGMII23_OFFSET(x) ((x - 2) * 0x100)
+#define SGMII_OFFSET(x) ((x <= 1) ? (x * 0x100) : (SGMII23_OFFSET(x)))
+
+/* SGMII registers */
+#define SGMII_SRESET_REG(x) (SGMII_OFFSET(x) + 0x004)
+#define SGMII_CTL_REG(x) (SGMII_OFFSET(x) + 0x010)
+#define SGMII_STATUS_REG(x) (SGMII_OFFSET(x) + 0x014)
+#define SGMII_MRADV_REG(x) (SGMII_OFFSET(x) + 0x018)
+
+static void sgmii_write_reg(void __iomem *base, int reg, u32 val)
+{
+ writel(val, base + reg);
+}
+
+static u32 sgmii_read_reg(void __iomem *base, int reg)
+{
+ return readl(base + reg);
+}
+
+static void sgmii_write_reg_bit(void __iomem *base, int reg, u32 val)
+{
+ writel((readl(base + reg) | val), base + reg);
+}
+
+/* port is 0 based */
+int netcp_sgmii_reset(void __iomem *sgmii_ofs, int port)
+{
+ /* Soft reset */
+ sgmii_write_reg_bit(sgmii_ofs, SGMII_SRESET_REG(port), 0x1);
+ while (sgmii_read_reg(sgmii_ofs, SGMII_SRESET_REG(port)) != 0x0)
+ ;
+ return 0;
+}
+
+int netcp_sgmii_get_port_link(void __iomem *sgmii_ofs, int port)
+{
+ u32 status = 0, link = 0;
+
+ status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
+ if ((status & SGMII_REG_STATUS_LINK) != 0)
+ link = 1;
+ return link;
+}
+
+int netcp_sgmii_config(void __iomem *sgmii_ofs, int port, u32 interface)
+{
+ unsigned int i, status, mask;
+ u32 mr_adv_ability;
+ u32 control;
+
+ switch (interface) {
+ case SGMII_LINK_MAC_MAC_AUTONEG:
+ mr_adv_ability = 0x9801;
+ control = 0x21;
+ break;
+
+ case SGMII_LINK_MAC_PHY:
+ case SGMII_LINK_MAC_PHY_NO_MDIO:
+ mr_adv_ability = 1;
+ control = 1;
+ break;
+
+ case SGMII_LINK_MAC_MAC_FORCED:
+ mr_adv_ability = 0x9801;
+ control = 0x20;
+ break;
+
+ case SGMII_LINK_MAC_FIBER:
+ mr_adv_ability = 0x20;
+ control = 0x1;
+ break;
+
+ default:
+ WARN_ONCE(1, "Invalid sgmii interface: %d\n", interface);
+ return -EINVAL;
+ }
+
+ sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), 0);
+
+ /* Wait for the SerDes pll to lock */
+ for (i = 0; i < 1000; i++) {
+ usleep_range(1000, 2000);
+ status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
+ if ((status & SGMII_REG_STATUS_LOCK) != 0)
+ break;
+ }
+
+ if ((status & SGMII_REG_STATUS_LOCK) == 0)
+ pr_err("serdes PLL not locked\n");
+
+ sgmii_write_reg(sgmii_ofs, SGMII_MRADV_REG(port), mr_adv_ability);
+ sgmii_write_reg(sgmii_ofs, SGMII_CTL_REG(port), control);
+
+ mask = SGMII_REG_STATUS_LINK;
+ if (control & SGMII_REG_CONTROL_AUTONEG)
+ mask |= SGMII_REG_STATUS_AUTONEG;
+
+ for (i = 0; i < 1000; i++) {
+ usleep_range(200, 500);
+ status = sgmii_read_reg(sgmii_ofs, SGMII_STATUS_REG(port));
+ if ((status & mask) == mask)
+ break;
+ }
+
+ return 0;
+}
diff --git a/drivers/net/ethernet/ti/netcp_xgbepcsr.c b/drivers/net/ethernet/ti/netcp_xgbepcsr.c
new file mode 100644
index 000000000000..33571acc52b6
--- /dev/null
+++ b/drivers/net/ethernet/ti/netcp_xgbepcsr.c
@@ -0,0 +1,501 @@
+/*
+ * XGE PCSR module initialisation
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ * Authors: Sandeep Nair <sandeep_n@ti.com>
+ * WingMan Kwok <w-kwok2@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 "netcp.h"
+
+/* XGBE registers */
+#define XGBE_CTRL_OFFSET 0x0c
+#define XGBE_SGMII_1_OFFSET 0x0114
+#define XGBE_SGMII_2_OFFSET 0x0214
+
+/* PCS-R registers */
+#define PCSR_CPU_CTRL_OFFSET 0x1fd0
+#define POR_EN BIT(29)
+
+#define reg_rmw(addr, value, mask) \
+ writel(((readl(addr) & (~(mask))) | \
+ (value & (mask))), (addr))
+
+/* bit mask of width w at offset s */
+#define MASK_WID_SH(w, s) (((1 << w) - 1) << s)
+
+/* shift value v to offset s */
+#define VAL_SH(v, s) (v << s)
+
+#define PHY_A(serdes) 0
+
+struct serdes_cfg {
+ u32 ofs;
+ u32 val;
+ u32 mask;
+};
+
+static struct serdes_cfg cfg_phyb_1p25g_156p25mhz_cmu0[] = {
+ {0x0000, 0x00800002, 0x00ff00ff},
+ {0x0014, 0x00003838, 0x0000ffff},
+ {0x0060, 0x1c44e438, 0xffffffff},
+ {0x0064, 0x00c18400, 0x00ffffff},
+ {0x0068, 0x17078200, 0xffffff00},
+ {0x006c, 0x00000014, 0x000000ff},
+ {0x0078, 0x0000c000, 0x0000ff00},
+ {0x0000, 0x00000003, 0x000000ff},
+};
+
+static struct serdes_cfg cfg_phyb_10p3125g_156p25mhz_cmu1[] = {
+ {0x0c00, 0x00030002, 0x00ff00ff},
+ {0x0c14, 0x00005252, 0x0000ffff},
+ {0x0c28, 0x80000000, 0xff000000},
+ {0x0c2c, 0x000000f6, 0x000000ff},
+ {0x0c3c, 0x04000405, 0xff00ffff},
+ {0x0c40, 0xc0800000, 0xffff0000},
+ {0x0c44, 0x5a202062, 0xffffffff},
+ {0x0c48, 0x40040424, 0xffffffff},
+ {0x0c4c, 0x00004002, 0x0000ffff},
+ {0x0c50, 0x19001c00, 0xff00ff00},
+ {0x0c54, 0x00002100, 0x0000ff00},
+ {0x0c58, 0x00000060, 0x000000ff},
+ {0x0c60, 0x80131e7c, 0xffffffff},
+ {0x0c64, 0x8400cb02, 0xff00ffff},
+ {0x0c68, 0x17078200, 0xffffff00},
+ {0x0c6c, 0x00000016, 0x000000ff},
+ {0x0c74, 0x00000400, 0x0000ff00},
+ {0x0c78, 0x0000c000, 0x0000ff00},
+ {0x0c00, 0x00000003, 0x000000ff},
+};
+
+static struct serdes_cfg cfg_phyb_10p3125g_16bit_lane[] = {
+ {0x0204, 0x00000080, 0x000000ff},
+ {0x0208, 0x0000920d, 0x0000ffff},
+ {0x0204, 0xfc000000, 0xff000000},
+ {0x0208, 0x00009104, 0x0000ffff},
+ {0x0210, 0x1a000000, 0xff000000},
+ {0x0214, 0x00006b58, 0x00ffffff},
+ {0x0218, 0x75800084, 0xffff00ff},
+ {0x022c, 0x00300000, 0x00ff0000},
+ {0x0230, 0x00003800, 0x0000ff00},
+ {0x024c, 0x008f0000, 0x00ff0000},
+ {0x0250, 0x30000000, 0xff000000},
+ {0x0260, 0x00000002, 0x000000ff},
+ {0x0264, 0x00000057, 0x000000ff},
+ {0x0268, 0x00575700, 0x00ffff00},
+ {0x0278, 0xff000000, 0xff000000},
+ {0x0280, 0x00500050, 0x00ff00ff},
+ {0x0284, 0x00001f15, 0x0000ffff},
+ {0x028c, 0x00006f00, 0x0000ff00},
+ {0x0294, 0x00000000, 0xffffff00},
+ {0x0298, 0x00002640, 0xff00ffff},
+ {0x029c, 0x00000003, 0x000000ff},
+ {0x02a4, 0x00000f13, 0x0000ffff},
+ {0x02a8, 0x0001b600, 0x00ffff00},
+ {0x0380, 0x00000030, 0x000000ff},
+ {0x03c0, 0x00000200, 0x0000ff00},
+ {0x03cc, 0x00000018, 0x000000ff},
+ {0x03cc, 0x00000000, 0x000000ff},
+};
+
+static struct serdes_cfg cfg_phyb_10p3125g_comlane[] = {
+ {0x0a00, 0x00000800, 0x0000ff00},
+ {0x0a84, 0x00000000, 0x000000ff},
+ {0x0a8c, 0x00130000, 0x00ff0000},
+ {0x0a90, 0x77a00000, 0xffff0000},
+ {0x0a94, 0x00007777, 0x0000ffff},
+ {0x0b08, 0x000f0000, 0xffff0000},
+ {0x0b0c, 0x000f0000, 0x00ffffff},
+ {0x0b10, 0xbe000000, 0xff000000},
+ {0x0b14, 0x000000ff, 0x000000ff},
+ {0x0b18, 0x00000014, 0x000000ff},
+ {0x0b5c, 0x981b0000, 0xffff0000},
+ {0x0b64, 0x00001100, 0x0000ff00},
+ {0x0b78, 0x00000c00, 0x0000ff00},
+ {0x0abc, 0xff000000, 0xff000000},
+ {0x0ac0, 0x0000008b, 0x000000ff},
+};
+
+static struct serdes_cfg cfg_cm_c1_c2[] = {
+ {0x0208, 0x00000000, 0x00000f00},
+ {0x0208, 0x00000000, 0x0000001f},
+ {0x0204, 0x00000000, 0x00040000},
+ {0x0208, 0x000000a0, 0x000000e0},
+};
+
+static void netcp_xgbe_serdes_cmu_init(void __iomem *serdes_regs)
+{
+ int i;
+
+ /* cmu0 setup */
+ for (i = 0; i < ARRAY_SIZE(cfg_phyb_1p25g_156p25mhz_cmu0); i++) {
+ reg_rmw(serdes_regs + cfg_phyb_1p25g_156p25mhz_cmu0[i].ofs,
+ cfg_phyb_1p25g_156p25mhz_cmu0[i].val,
+ cfg_phyb_1p25g_156p25mhz_cmu0[i].mask);
+ }
+
+ /* cmu1 setup */
+ for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_156p25mhz_cmu1); i++) {
+ reg_rmw(serdes_regs + cfg_phyb_10p3125g_156p25mhz_cmu1[i].ofs,
+ cfg_phyb_10p3125g_156p25mhz_cmu1[i].val,
+ cfg_phyb_10p3125g_156p25mhz_cmu1[i].mask);
+ }
+}
+
+/* lane is 0 based */
+static void netcp_xgbe_serdes_lane_config(
+ void __iomem *serdes_regs, int lane)
+{
+ int i;
+
+ /* lane setup */
+ for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_16bit_lane); i++) {
+ reg_rmw(serdes_regs +
+ cfg_phyb_10p3125g_16bit_lane[i].ofs +
+ (0x200 * lane),
+ cfg_phyb_10p3125g_16bit_lane[i].val,
+ cfg_phyb_10p3125g_16bit_lane[i].mask);
+ }
+
+ /* disable auto negotiation*/
+ reg_rmw(serdes_regs + (0x200 * lane) + 0x0380,
+ 0x00000000, 0x00000010);
+
+ /* disable link training */
+ reg_rmw(serdes_regs + (0x200 * lane) + 0x03c0,
+ 0x00000000, 0x00000200);
+}
+
+static void netcp_xgbe_serdes_com_enable(void __iomem *serdes_regs)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cfg_phyb_10p3125g_comlane); i++) {
+ reg_rmw(serdes_regs + cfg_phyb_10p3125g_comlane[i].ofs,
+ cfg_phyb_10p3125g_comlane[i].val,
+ cfg_phyb_10p3125g_comlane[i].mask);
+ }
+}
+
+static void netcp_xgbe_serdes_lane_enable(
+ void __iomem *serdes_regs, int lane)
+{
+ /* Set Lane Control Rate */
+ writel(0xe0e9e038, serdes_regs + 0x1fe0 + (4 * lane));
+}
+
+static void netcp_xgbe_serdes_phyb_rst_clr(void __iomem *serdes_regs)
+{
+ reg_rmw(serdes_regs + 0x0a00, 0x0000001f, 0x000000ff);
+}
+
+static void netcp_xgbe_serdes_pll_disable(void __iomem *serdes_regs)
+{
+ writel(0x88000000, serdes_regs + 0x1ff4);
+}
+
+static void netcp_xgbe_serdes_pll_enable(void __iomem *serdes_regs)
+{
+ netcp_xgbe_serdes_phyb_rst_clr(serdes_regs);
+ writel(0xee000000, serdes_regs + 0x1ff4);
+}
+
+static int netcp_xgbe_wait_pll_locked(void __iomem *sw_regs)
+{
+ unsigned long timeout;
+ int ret = 0;
+ u32 val_1, val_0;
+
+ timeout = jiffies + msecs_to_jiffies(500);
+ do {
+ val_0 = (readl(sw_regs + XGBE_SGMII_1_OFFSET) & BIT(4));
+ val_1 = (readl(sw_regs + XGBE_SGMII_2_OFFSET) & BIT(4));
+
+ if (val_1 && val_0)
+ return 0;
+
+ if (time_after(jiffies, timeout)) {
+ ret = -ETIMEDOUT;
+ break;
+ }
+
+ cpu_relax();
+ } while (true);
+
+ pr_err("XGBE serdes not locked: time out.\n");
+ return ret;
+}
+
+static void netcp_xgbe_serdes_enable_xgmii_port(void __iomem *sw_regs)
+{
+ writel(0x03, sw_regs + XGBE_CTRL_OFFSET);
+}
+
+static u32 netcp_xgbe_serdes_read_tbus_val(void __iomem *serdes_regs)
+{
+ u32 tmp;
+
+ if (PHY_A(serdes_regs)) {
+ tmp = (readl(serdes_regs + 0x0ec) >> 24) & 0x0ff;
+ tmp |= ((readl(serdes_regs + 0x0fc) >> 16) & 0x00f00);
+ } else {
+ tmp = (readl(serdes_regs + 0x0f8) >> 16) & 0x0fff;
+ }
+
+ return tmp;
+}
+
+static void netcp_xgbe_serdes_write_tbus_addr(void __iomem *serdes_regs,
+ int select, int ofs)
+{
+ if (PHY_A(serdes_regs)) {
+ reg_rmw(serdes_regs + 0x0008, ((select << 5) + ofs) << 24,
+ ~0x00ffffff);
+ return;
+ }
+
+ /* For 2 lane Phy-B, lane0 is actually lane1 */
+ switch (select) {
+ case 1:
+ select = 2;
+ break;
+ case 2:
+ select = 3;
+ break;
+ default:
+ return;
+ }
+
+ reg_rmw(serdes_regs + 0x00fc, ((select << 8) + ofs) << 16, ~0xf800ffff);
+}
+
+static u32 netcp_xgbe_serdes_read_select_tbus(void __iomem *serdes_regs,
+ int select, int ofs)
+{
+ /* Set tbus address */
+ netcp_xgbe_serdes_write_tbus_addr(serdes_regs, select, ofs);
+ /* Get TBUS Value */
+ return netcp_xgbe_serdes_read_tbus_val(serdes_regs);
+}
+
+static void netcp_xgbe_serdes_reset_cdr(void __iomem *serdes_regs,
+ void __iomem *sig_detect_reg, int lane)
+{
+ u32 tmp, dlpf, tbus;
+
+ /*Get the DLPF values */
+ tmp = netcp_xgbe_serdes_read_select_tbus(
+ serdes_regs, lane + 1, 5);
+
+ dlpf = tmp >> 2;
+
+ if (dlpf < 400 || dlpf > 700) {
+ reg_rmw(sig_detect_reg, VAL_SH(2, 1), MASK_WID_SH(2, 1));
+ mdelay(1);
+ reg_rmw(sig_detect_reg, VAL_SH(0, 1), MASK_WID_SH(2, 1));
+ } else {
+ tbus = netcp_xgbe_serdes_read_select_tbus(serdes_regs, lane +
+ 1, 0xe);
+
+ pr_debug("XGBE: CDR centered, DLPF: %4d,%d,%d.\n",
+ tmp >> 2, tmp & 3, (tbus >> 2) & 3);
+ }
+}
+
+/* Call every 100 ms */
+static int netcp_xgbe_check_link_status(void __iomem *serdes_regs,
+ void __iomem *sw_regs, u32 lanes,
+ u32 *current_state, u32 *lane_down)
+{
+ void __iomem *pcsr_base = sw_regs + 0x0600;
+ void __iomem *sig_detect_reg;
+ u32 pcsr_rx_stat, blk_lock, blk_errs;
+ int loss, i, status = 1;
+
+ for (i = 0; i < lanes; i++) {
+ /* Get the Loss bit */
+ loss = readl(serdes_regs + 0x1fc0 + 0x20 + (i * 0x04)) & 0x1;
+
+ /* Get Block Errors and Block Lock bits */
+ pcsr_rx_stat = readl(pcsr_base + 0x0c + (i * 0x80));
+ blk_lock = (pcsr_rx_stat >> 30) & 0x1;
+ blk_errs = (pcsr_rx_stat >> 16) & 0x0ff;
+
+ /* Get Signal Detect Overlay Address */
+ sig_detect_reg = serdes_regs + (i * 0x200) + 0x200 + 0x04;
+
+ /* If Block errors maxed out, attempt recovery! */
+ if (blk_errs == 0x0ff)
+ blk_lock = 0;
+
+ switch (current_state[i]) {
+ case 0:
+ /* if good link lock the signal detect ON! */
+ if (!loss && blk_lock) {
+ pr_debug("XGBE PCSR Linked Lane: %d\n", i);
+ reg_rmw(sig_detect_reg, VAL_SH(3, 1),
+ MASK_WID_SH(2, 1));
+ current_state[i] = 1;
+ } else if (!blk_lock) {
+ /* if no lock, then reset CDR */
+ pr_debug("XGBE PCSR Recover Lane: %d\n", i);
+ netcp_xgbe_serdes_reset_cdr(serdes_regs,
+ sig_detect_reg, i);
+ }
+ break;
+
+ case 1:
+ if (!blk_lock) {
+ /* Link Lost? */
+ lane_down[i] = 1;
+ current_state[i] = 2;
+ }
+ break;
+
+ case 2:
+ if (blk_lock)
+ /* Nope just noise */
+ current_state[i] = 1;
+ else {
+ /* Lost the block lock, reset CDR if it is
+ * not centered and go back to sync state
+ */
+ netcp_xgbe_serdes_reset_cdr(serdes_regs,
+ sig_detect_reg, i);
+ current_state[i] = 0;
+ }
+ break;
+
+ default:
+ pr_err("XGBE: unknown current_state[%d] %d\n",
+ i, current_state[i]);
+ break;
+ }
+
+ if (blk_errs > 0) {
+ /* Reset the Error counts! */
+ reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x19, 0),
+ MASK_WID_SH(8, 0));
+
+ reg_rmw(pcsr_base + 0x08 + (i * 0x80), VAL_SH(0x00, 0),
+ MASK_WID_SH(8, 0));
+ }
+
+ status &= (current_state[i] == 1);
+ }
+
+ return status;
+}
+
+static int netcp_xgbe_serdes_check_lane(void __iomem *serdes_regs,
+ void __iomem *sw_regs)
+{
+ u32 current_state[2] = {0, 0};
+ int retries = 0, link_up;
+ u32 lane_down[2];
+
+ do {
+ lane_down[0] = 0;
+ lane_down[1] = 0;
+
+ link_up = netcp_xgbe_check_link_status(serdes_regs, sw_regs, 2,
+ current_state,
+ lane_down);
+
+ /* if we did not get link up then wait 100ms before calling
+ * it again
+ */
+ if (link_up)
+ break;
+
+ if (lane_down[0])
+ pr_debug("XGBE: detected link down on lane 0\n");
+
+ if (lane_down[1])
+ pr_debug("XGBE: detected link down on lane 1\n");
+
+ if (++retries > 1) {
+ pr_debug("XGBE: timeout waiting for serdes link up\n");
+ return -ETIMEDOUT;
+ }
+ mdelay(100);
+ } while (!link_up);
+
+ pr_debug("XGBE: PCSR link is up\n");
+ return 0;
+}
+
+static void netcp_xgbe_serdes_setup_cm_c1_c2(void __iomem *serdes_regs,
+ int lane, int cm, int c1, int c2)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(cfg_cm_c1_c2); i++) {
+ reg_rmw(serdes_regs + cfg_cm_c1_c2[i].ofs + (0x200 * lane),
+ cfg_cm_c1_c2[i].val,
+ cfg_cm_c1_c2[i].mask);
+ }
+}
+
+static void netcp_xgbe_reset_serdes(void __iomem *serdes_regs)
+{
+ /* Toggle the POR_EN bit in CONFIG.CPU_CTRL */
+ /* enable POR_EN bit */
+ reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, POR_EN, POR_EN);
+ usleep_range(10, 100);
+
+ /* disable POR_EN bit */
+ reg_rmw(serdes_regs + PCSR_CPU_CTRL_OFFSET, 0, POR_EN);
+ usleep_range(10, 100);
+}
+
+static int netcp_xgbe_serdes_config(void __iomem *serdes_regs,
+ void __iomem *sw_regs)
+{
+ u32 ret, i;
+
+ netcp_xgbe_serdes_pll_disable(serdes_regs);
+ netcp_xgbe_serdes_cmu_init(serdes_regs);
+
+ for (i = 0; i < 2; i++)
+ netcp_xgbe_serdes_lane_config(serdes_regs, i);
+
+ netcp_xgbe_serdes_com_enable(serdes_regs);
+ /* This is EVM + RTM-BOC specific */
+ for (i = 0; i < 2; i++)
+ netcp_xgbe_serdes_setup_cm_c1_c2(serdes_regs, i, 0, 0, 5);
+
+ netcp_xgbe_serdes_pll_enable(serdes_regs);
+ for (i = 0; i < 2; i++)
+ netcp_xgbe_serdes_lane_enable(serdes_regs, i);
+
+ /* SB PLL Status Poll */
+ ret = netcp_xgbe_wait_pll_locked(sw_regs);
+ if (ret)
+ return ret;
+
+ netcp_xgbe_serdes_enable_xgmii_port(sw_regs);
+ netcp_xgbe_serdes_check_lane(serdes_regs, sw_regs);
+ return ret;
+}
+
+int netcp_xgbe_serdes_init(void __iomem *serdes_regs, void __iomem *xgbe_regs)
+{
+ u32 val;
+
+ /* read COMLANE bits 4:0 */
+ val = readl(serdes_regs + 0xa00);
+ if (val & 0x1f) {
+ pr_debug("XGBE: serdes already in operation - reset\n");
+ netcp_xgbe_reset_serdes(serdes_regs);
+ }
+ return netcp_xgbe_serdes_config(serdes_regs, xgbe_regs);
+}
diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c
index f2ff0074aac9..691ec936e88d 100644
--- a/drivers/net/ethernet/ti/tlan.c
+++ b/drivers/net/ethernet/ti/tlan.c
@@ -2540,7 +2540,7 @@ static void tlan_phy_power_down(struct net_device *dev)
* This is abitrary. It is intended to make sure the
* transceiver settles.
*/
- tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_PUP);
+ tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_PUP);
}
@@ -2561,7 +2561,7 @@ static void tlan_phy_power_up(struct net_device *dev)
* transceiver. The TLAN docs say both 50 ms and
* 500 ms, so do the longer, just in case.
*/
- tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_RESET);
+ tlan_set_timer(dev, msecs_to_jiffies(500), TLAN_TIMER_PHY_RESET);
}
@@ -2593,7 +2593,7 @@ static void tlan_phy_reset(struct net_device *dev)
* I don't remember why I wait this long.
* I've changed this to 50ms, as it seems long enough.
*/
- tlan_set_timer(dev, (HZ/20), TLAN_TIMER_PHY_START_LINK);
+ tlan_set_timer(dev, msecs_to_jiffies(50), TLAN_TIMER_PHY_START_LINK);
}
@@ -2658,7 +2658,7 @@ static void tlan_phy_start_link(struct net_device *dev)
data = TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN
| TLAN_NET_CFG_PHY_EN;
tlan_dio_write16(dev->base_addr, TLAN_NET_CONFIG, data);
- tlan_set_timer(dev, (40*HZ/1000), TLAN_TIMER_PHY_PDOWN);
+ tlan_set_timer(dev, msecs_to_jiffies(40), TLAN_TIMER_PHY_PDOWN);
return;
} else if (priv->phy_num == 0) {
control = 0;
@@ -2725,7 +2725,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev)
(priv->adapter->flags & TLAN_ADAPTER_USE_INTERN_10) &&
(priv->phy_num != 0)) {
priv->phy_num = 0;
- tlan_set_timer(dev, (400*HZ/1000), TLAN_TIMER_PHY_PDOWN);
+ tlan_set_timer(dev, msecs_to_jiffies(400), TLAN_TIMER_PHY_PDOWN);
return;
}
@@ -2744,7 +2744,7 @@ static void tlan_phy_finish_auto_neg(struct net_device *dev)
/* Wait for 100 ms. No reason in partiticular.
*/
- tlan_set_timer(dev, (HZ/10), TLAN_TIMER_FINISH_RESET);
+ tlan_set_timer(dev, msecs_to_jiffies(100), TLAN_TIMER_FINISH_RESET);
}
@@ -2796,7 +2796,7 @@ static void tlan_phy_monitor(unsigned long data)
/* set to external PHY */
priv->phy_num = 1;
/* restart autonegotiation */
- tlan_set_timer(dev, 4 * HZ / 10,
+ tlan_set_timer(dev, msecs_to_jiffies(400),
TLAN_TIMER_PHY_PDOWN);
return;
}
diff --git a/drivers/net/ethernet/tile/tilegx.c b/drivers/net/ethernet/tile/tilegx.c
index 049747f558c9..bea8cd2bb56c 100644
--- a/drivers/net/ethernet/tile/tilegx.c
+++ b/drivers/net/ethernet/tile/tilegx.c
@@ -292,7 +292,6 @@ static inline int mpipe_instance(struct net_device *dev)
*/
static bool network_cpus_init(void)
{
- char buf[1024];
int rc;
if (network_cpus_string == NULL)
@@ -314,8 +313,8 @@ static bool network_cpus_init(void)
return false;
}
- cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
- pr_info("Linux network CPUs: %s\n", buf);
+ pr_info("Linux network CPUs: %*pbl\n",
+ cpumask_pr_args(&network_cpus_map));
return true;
}
diff --git a/drivers/net/ethernet/tile/tilepro.c b/drivers/net/ethernet/tile/tilepro.c
index fb12d31cfcf6..3d8f60d9643e 100644
--- a/drivers/net/ethernet/tile/tilepro.c
+++ b/drivers/net/ethernet/tile/tilepro.c
@@ -2410,9 +2410,8 @@ static int __init network_cpus_setup(char *str)
if (cpumask_empty(&network_cpus_map)) {
pr_warn("Ignoring network_cpus='%s'\n", str);
} else {
- char buf[1024];
- cpulist_scnprintf(buf, sizeof(buf), &network_cpus_map);
- pr_info("Linux network CPUs: %s\n", buf);
+ pr_info("Linux network CPUs: %*pbl\n",
+ cpumask_pr_args(&network_cpus_map));
network_cpus_used = true;
}
}
diff --git a/drivers/net/ethernet/via/via-rhine.c b/drivers/net/ethernet/via/via-rhine.c
index a191afc23b56..17e276651601 100644
--- a/drivers/net/ethernet/via/via-rhine.c
+++ b/drivers/net/ethernet/via/via-rhine.c
@@ -1326,7 +1326,8 @@ static void rhine_check_media(struct net_device *dev, unsigned int init_media)
struct rhine_private *rp = netdev_priv(dev);
void __iomem *ioaddr = rp->base;
- mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media);
+ if (!rp->mii_if.force_media)
+ mii_check_media(&rp->mii_if, netif_msg_link(rp), init_media);
if (rp->mii_if.full_duplex)
iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1FDuplex,
@@ -1781,8 +1782,8 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
rp->tx_ring[entry].desc_length =
cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
- if (unlikely(vlan_tx_tag_present(skb))) {
- u16 vid_pcp = vlan_tx_tag_get(skb);
+ if (unlikely(skb_vlan_tag_present(skb))) {
+ u16 vid_pcp = skb_vlan_tag_get(skb);
/* drop CFI/DEI bit, register needs VID and PCP */
vid_pcp = (vid_pcp & VLAN_VID_MASK) |
@@ -1803,7 +1804,7 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
/* Non-x86 Todo: explicitly flush cache lines here. */
- if (vlan_tx_tag_present(skb))
+ if (skb_vlan_tag_present(skb))
/* Tx queues are bits 7-0 (first Tx queue: bit 7) */
BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
diff --git a/drivers/net/ethernet/via/via-velocity.c b/drivers/net/ethernet/via/via-velocity.c
index 282f83a63b67..c20206f83cc1 100644
--- a/drivers/net/ethernet/via/via-velocity.c
+++ b/drivers/net/ethernet/via/via-velocity.c
@@ -2611,8 +2611,8 @@ static netdev_tx_t velocity_xmit(struct sk_buff *skb,
td_ptr->tdesc1.cmd = TCPLS_NORMAL + (tdinfo->nskb_dma + 1) * 16;
- if (vlan_tx_tag_present(skb)) {
- td_ptr->tdesc1.vlan = cpu_to_le16(vlan_tx_tag_get(skb));
+ if (skb_vlan_tag_present(skb)) {
+ td_ptr->tdesc1.vlan = cpu_to_le16(skb_vlan_tag_get(skb));
td_ptr->tdesc1.TCR |= TCR0_VETAG;
}
diff --git a/drivers/net/fddi/skfp/smt.c b/drivers/net/fddi/skfp/smt.c
index 9edada85ed02..cd78b7cacc75 100644
--- a/drivers/net/fddi/skfp/smt.c
+++ b/drivers/net/fddi/skfp/smt.c
@@ -1736,18 +1736,6 @@ char *addr_to_string(struct fddi_addr *addr)
}
#endif
-#ifdef AM29K
-int smt_ifconfig(int argc, char *argv[])
-{
- if (argc >= 2 && !strcmp(argv[0],"opt_bypass") &&
- !strcmp(argv[1],"yes")) {
- smc->mib.fddiSMTBypassPresent = 1 ;
- return 0;
- }
- return amdfddi_config(0, argc, argv);
-}
-#endif
-
/*
* return static mac index
*/
diff --git a/drivers/net/hyperv/netvsc.c b/drivers/net/hyperv/netvsc.c
index 9f49c0129a78..208eb05446ba 100644
--- a/drivers/net/hyperv/netvsc.c
+++ b/drivers/net/hyperv/netvsc.c
@@ -217,7 +217,7 @@ static int netvsc_destroy_buf(struct netvsc_device *net_device)
static int netvsc_init_buf(struct hv_device *device)
{
int ret = 0;
- int t;
+ unsigned long t;
struct netvsc_device *net_device;
struct nvsp_message *init_packet;
struct net_device *ndev;
@@ -409,7 +409,8 @@ static int negotiate_nvsp_ver(struct hv_device *device,
struct nvsp_message *init_packet,
u32 nvsp_ver)
{
- int ret, t;
+ int ret;
+ unsigned long t;
memset(init_packet, 0, sizeof(struct nvsp_message));
init_packet->hdr.msg_type = NVSP_MSG_TYPE_INIT;
@@ -684,9 +685,9 @@ static u32 netvsc_get_next_send_section(struct netvsc_device *net_device)
return ret_val;
}
-u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
- unsigned int section_index,
- struct hv_netvsc_packet *packet)
+static u32 netvsc_copy_to_send_buf(struct netvsc_device *net_device,
+ unsigned int section_index,
+ struct hv_netvsc_packet *packet)
{
char *start = net_device->send_buf;
char *dest = (start + (section_index * net_device->send_section_size));
@@ -716,7 +717,7 @@ int netvsc_send(struct hv_device *device,
u64 req_id;
unsigned int section_index = NETVSC_INVALID_INDEX;
u32 msg_size = 0;
- struct sk_buff *skb;
+ struct sk_buff *skb = NULL;
u16 q_idx = packet->q_idx;
@@ -743,8 +744,6 @@ int netvsc_send(struct hv_device *device,
packet);
skb = (struct sk_buff *)
(unsigned long)packet->send_completion_tid;
- if (skb)
- dev_kfree_skb_any(skb);
packet->page_buf_cnt = 0;
}
}
@@ -810,6 +809,13 @@ int netvsc_send(struct hv_device *device,
packet, ret);
}
+ if (ret != 0) {
+ if (section_index != NETVSC_INVALID_INDEX)
+ netvsc_free_send_slot(net_device, section_index);
+ } else if (skb) {
+ dev_kfree_skb_any(skb);
+ }
+
return ret;
}
diff --git a/drivers/net/hyperv/rndis_filter.c b/drivers/net/hyperv/rndis_filter.c
index ec0c40a8f653..7816d98bdddc 100644
--- a/drivers/net/hyperv/rndis_filter.c
+++ b/drivers/net/hyperv/rndis_filter.c
@@ -470,7 +470,7 @@ static int rndis_filter_query_device(struct rndis_device *dev, u32 oid,
struct rndis_query_request *query;
struct rndis_query_complete *query_complete;
int ret = 0;
- int t;
+ unsigned long t;
if (!result)
return -EINVAL;
@@ -560,7 +560,8 @@ int rndis_filter_set_device_mac(struct hv_device *hdev, char *mac)
char macstr[2*ETH_ALEN+1];
u32 extlen = sizeof(struct rndis_config_parameter_info) +
2*NWADR_STRLEN + 4*ETH_ALEN;
- int ret, t;
+ int ret;
+ unsigned long t;
request = get_rndis_request(rdev, RNDIS_MSG_SET,
RNDIS_MESSAGE_SIZE(struct rndis_set_request) + extlen);
@@ -623,7 +624,8 @@ cleanup:
return ret;
}
-int rndis_filter_set_offload_params(struct hv_device *hdev,
+static int
+rndis_filter_set_offload_params(struct hv_device *hdev,
struct ndis_offload_params *req_offloads)
{
struct netvsc_device *nvdev = hv_get_drvdata(hdev);
@@ -634,7 +636,8 @@ int rndis_filter_set_offload_params(struct hv_device *hdev,
struct ndis_offload_params *offload_params;
struct rndis_set_complete *set_complete;
u32 extlen = sizeof(struct ndis_offload_params);
- int ret, t;
+ int ret;
+ unsigned long t;
u32 vsp_version = nvdev->nvsp_version;
if (vsp_version <= NVSP_PROTOCOL_VERSION_4) {
@@ -697,7 +700,7 @@ u8 netvsc_hash_key[HASH_KEYLEN] = {
0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa
};
-int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
+static int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
{
struct net_device *ndev = rdev->net_dev->ndev;
struct rndis_request *request;
@@ -708,7 +711,8 @@ int rndis_filter_set_rss_param(struct rndis_device *rdev, int num_queue)
struct ndis_recv_scale_param *rssp;
u32 *itab;
u8 *keyp;
- int i, t, ret;
+ int i, ret;
+ unsigned long t;
request = get_rndis_request(
rdev, RNDIS_MSG_SET,
@@ -792,7 +796,8 @@ int rndis_filter_set_packet_filter(struct rndis_device *dev, u32 new_filter)
struct rndis_set_request *set;
struct rndis_set_complete *set_complete;
u32 status;
- int ret, t;
+ int ret;
+ unsigned long t;
struct net_device *ndev;
ndev = dev->net_dev->ndev;
@@ -848,7 +853,8 @@ static int rndis_filter_init_device(struct rndis_device *dev)
struct rndis_initialize_request *init;
struct rndis_initialize_complete *init_complete;
u32 status;
- int ret, t;
+ int ret;
+ unsigned long t;
request = get_rndis_request(dev, RNDIS_MSG_INIT,
RNDIS_MESSAGE_SIZE(struct rndis_initialize_request));
@@ -998,7 +1004,7 @@ int rndis_filter_device_add(struct hv_device *dev,
struct netvsc_device_info *device_info = additional_info;
struct ndis_offload_params offloads;
struct nvsp_message *init_packet;
- int t;
+ unsigned long t;
struct ndis_recv_scale_cap rsscap;
u32 rsscap_size = sizeof(struct ndis_recv_scale_cap);
u32 mtu, size;
diff --git a/drivers/net/ieee802154/at86rf230.c b/drivers/net/ieee802154/at86rf230.c
index 1c0135620c62..7b051eacb7f1 100644
--- a/drivers/net/ieee802154/at86rf230.c
+++ b/drivers/net/ieee802154/at86rf230.c
@@ -427,7 +427,7 @@ at86rf230_reg_precious(struct device *dev, unsigned int reg)
}
}
-static struct regmap_config at86rf230_regmap_spi_config = {
+static const struct regmap_config at86rf230_regmap_spi_config = {
.reg_bits = 8,
.val_bits = 8,
.write_flag_mask = CMD_REG | CMD_WRITE,
@@ -450,7 +450,7 @@ at86rf230_async_error_recover(void *context)
ieee802154_wake_queue(lp->hw);
}
-static void
+static inline void
at86rf230_async_error(struct at86rf230_local *lp,
struct at86rf230_state_change *ctx, int rc)
{
@@ -524,7 +524,6 @@ at86rf230_async_state_assert(void *context)
}
}
-
dev_warn(&lp->spi->dev, "unexcept state change from 0x%02x to 0x%02x. Actual state: 0x%02x\n",
ctx->from_state, ctx->to_state, trx_state);
}
@@ -655,7 +654,7 @@ at86rf230_async_state_change_start(void *context)
if (ctx->irq_enable)
enable_irq(lp->spi->irq);
- at86rf230_async_error(lp, &lp->state, rc);
+ at86rf230_async_error(lp, ctx, rc);
}
}
@@ -715,10 +714,7 @@ at86rf230_tx_complete(void *context)
enable_irq(lp->spi->irq);
- if (lp->max_frame_retries <= 0)
- ieee802154_xmit_complete(lp->hw, skb, true);
- else
- ieee802154_xmit_complete(lp->hw, skb, false);
+ ieee802154_xmit_complete(lp->hw, skb, !lp->tx_aret);
}
static void
@@ -753,16 +749,13 @@ at86rf230_tx_trac_check(void *context)
* to STATE_FORCE_TRX_OFF then STATE_TX_ON to recover the transceiver
* state to TX_ON.
*/
- if (trac) {
+ if (trac)
at86rf230_async_state_change(lp, ctx, STATE_FORCE_TRX_OFF,
at86rf230_tx_trac_error, true);
- return;
- }
-
- at86rf230_tx_on(context);
+ else
+ at86rf230_tx_on(context);
}
-
static void
at86rf230_tx_trac_status(void *context)
{
@@ -1082,7 +1075,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
u16 addr = le16_to_cpu(filt->short_addr);
dev_vdbg(&lp->spi->dev,
- "at86rf230_set_hw_addr_filt called for saddr\n");
+ "at86rf230_set_hw_addr_filt called for saddr\n");
__at86rf230_write(lp, RG_SHORT_ADDR_0, addr);
__at86rf230_write(lp, RG_SHORT_ADDR_1, addr >> 8);
}
@@ -1091,7 +1084,7 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
u16 pan = le16_to_cpu(filt->pan_id);
dev_vdbg(&lp->spi->dev,
- "at86rf230_set_hw_addr_filt called for pan id\n");
+ "at86rf230_set_hw_addr_filt called for pan id\n");
__at86rf230_write(lp, RG_PAN_ID_0, pan);
__at86rf230_write(lp, RG_PAN_ID_1, pan >> 8);
}
@@ -1101,14 +1094,14 @@ at86rf230_set_hw_addr_filt(struct ieee802154_hw *hw,
memcpy(addr, &filt->ieee_addr, 8);
dev_vdbg(&lp->spi->dev,
- "at86rf230_set_hw_addr_filt called for IEEE addr\n");
+ "at86rf230_set_hw_addr_filt called for IEEE addr\n");
for (i = 0; i < 8; i++)
__at86rf230_write(lp, RG_IEEE_ADDR_0 + i, addr[i]);
}
if (changed & IEEE802154_AFILT_PANC_CHANGED) {
dev_vdbg(&lp->spi->dev,
- "at86rf230_set_hw_addr_filt called for panc change\n");
+ "at86rf230_set_hw_addr_filt called for panc change\n");
if (filt->pan_coord)
at86rf230_write_subreg(lp, SR_AACK_I_AM_COORD, 1);
else
@@ -1146,11 +1139,37 @@ at86rf230_set_lbt(struct ieee802154_hw *hw, bool on)
}
static int
-at86rf230_set_cca_mode(struct ieee802154_hw *hw, u8 mode)
+at86rf230_set_cca_mode(struct ieee802154_hw *hw,
+ const struct wpan_phy_cca *cca)
{
struct at86rf230_local *lp = hw->priv;
+ u8 val;
+
+ /* mapping 802.15.4 to driver spec */
+ switch (cca->mode) {
+ case NL802154_CCA_ENERGY:
+ val = 1;
+ break;
+ case NL802154_CCA_CARRIER:
+ val = 2;
+ break;
+ case NL802154_CCA_ENERGY_CARRIER:
+ switch (cca->opt) {
+ case NL802154_CCA_OPT_ENERGY_CARRIER_AND:
+ val = 3;
+ break;
+ case NL802154_CCA_OPT_ENERGY_CARRIER_OR:
+ val = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
- return at86rf230_write_subreg(lp, SR_CCA_MODE, mode);
+ return at86rf230_write_subreg(lp, SR_CCA_MODE, val);
}
static int
@@ -1400,7 +1419,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
if (rc)
return rc;
- rc = __at86rf230_read(lp, RG_PART_NUM, &version);
+ rc = __at86rf230_read(lp, RG_VERSION_NUM, &version);
if (rc)
return rc;
@@ -1410,11 +1429,12 @@ at86rf230_detect_device(struct at86rf230_local *lp)
return -EINVAL;
}
- lp->hw->extra_tx_headroom = 0;
lp->hw->flags = IEEE802154_HW_TX_OMIT_CKSUM | IEEE802154_HW_AACK |
IEEE802154_HW_TXPOWER | IEEE802154_HW_ARET |
IEEE802154_HW_AFILT | IEEE802154_HW_PROMISCUOUS;
+ lp->hw->phy->cca.mode = NL802154_CCA_ENERGY;
+
switch (part) {
case 2:
chip = "at86rf230";
@@ -1429,16 +1449,12 @@ at86rf230_detect_device(struct at86rf230_local *lp)
break;
case 7:
chip = "at86rf212";
- if (version == 1) {
- lp->data = &at86rf212_data;
- lp->hw->flags |= IEEE802154_HW_LBT;
- lp->hw->phy->channels_supported[0] = 0x00007FF;
- lp->hw->phy->channels_supported[2] = 0x00007FF;
- lp->hw->phy->current_channel = 5;
- lp->hw->phy->symbol_duration = 25;
- } else {
- rc = -ENOTSUPP;
- }
+ lp->data = &at86rf212_data;
+ lp->hw->flags |= IEEE802154_HW_LBT;
+ lp->hw->phy->channels_supported[0] = 0x00007FF;
+ lp->hw->phy->channels_supported[2] = 0x00007FF;
+ lp->hw->phy->current_channel = 5;
+ lp->hw->phy->symbol_duration = 25;
break;
case 11:
chip = "at86rf233";
@@ -1448,7 +1464,7 @@ at86rf230_detect_device(struct at86rf230_local *lp)
lp->hw->phy->symbol_duration = 16;
break;
default:
- chip = "unkown";
+ chip = "unknown";
rc = -ENOTSUPP;
break;
}
diff --git a/drivers/net/ieee802154/cc2520.c b/drivers/net/ieee802154/cc2520.c
index f9df9fa86d5f..181b349b060e 100644
--- a/drivers/net/ieee802154/cc2520.c
+++ b/drivers/net/ieee802154/cc2520.c
@@ -19,7 +19,6 @@
#include <linux/workqueue.h>
#include <linux/interrupt.h>
#include <linux/skbuff.h>
-#include <linux/pinctrl/consumer.h>
#include <linux/of_gpio.h>
#include <linux/ieee802154.h>
@@ -45,9 +44,9 @@
#define CC2520_FREG_MASK 0x3F
/* status byte values */
-#define CC2520_STATUS_XOSC32M_STABLE (1 << 7)
-#define CC2520_STATUS_RSSI_VALID (1 << 6)
-#define CC2520_STATUS_TX_UNDERFLOW (1 << 3)
+#define CC2520_STATUS_XOSC32M_STABLE BIT(7)
+#define CC2520_STATUS_RSSI_VALID BIT(6)
+#define CC2520_STATUS_TX_UNDERFLOW BIT(3)
/* IEEE-802.15.4 defined constants (2.4 GHz logical channels) */
#define CC2520_MINCHANNEL 11
@@ -513,7 +512,6 @@ err_tx:
return rc;
}
-
static int cc2520_rx(struct cc2520_private *priv)
{
u8 len = 0, lqi = 0, bytes = 1;
@@ -551,14 +549,14 @@ cc2520_ed(struct ieee802154_hw *hw, u8 *level)
u8 rssi;
int ret;
- ret = cc2520_read_register(priv , CC2520_RSSISTAT, &status);
+ ret = cc2520_read_register(priv, CC2520_RSSISTAT, &status);
if (ret)
return ret;
if (status != RSSI_VALID)
return -EINVAL;
- ret = cc2520_read_register(priv , CC2520_RSSI, &rssi);
+ ret = cc2520_read_register(priv, CC2520_RSSI, &rssi);
if (ret)
return ret;
@@ -652,6 +650,7 @@ static int cc2520_register(struct cc2520_private *priv)
priv->hw->parent = &priv->spi->dev;
priv->hw->extra_tx_headroom = 0;
priv->hw->vif_data_size = sizeof(*priv);
+ ieee802154_random_extended_addr(&priv->hw->phy->perm_extended_addr);
/* We do support only 2.4 Ghz */
priv->hw->phy->channels_supported[0] = 0x7FFF800;
@@ -842,24 +841,15 @@ done:
static int cc2520_probe(struct spi_device *spi)
{
struct cc2520_private *priv;
- struct pinctrl *pinctrl;
struct cc2520_platform_data *pdata;
int ret;
- priv = devm_kzalloc(&spi->dev,
- sizeof(struct cc2520_private), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto err_ret;
- }
+ priv = devm_kzalloc(&spi->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
spi_set_drvdata(spi, priv);
- pinctrl = devm_pinctrl_get_select_default(&spi->dev);
- if (IS_ERR(pinctrl))
- dev_warn(&spi->dev,
- "pinctrl pins are not configured\n");
-
pdata = cc2520_get_platform_data(spi);
if (!pdata) {
dev_err(&spi->dev, "no platform data\n");
@@ -870,10 +860,8 @@ static int cc2520_probe(struct spi_device *spi)
priv->buf = devm_kzalloc(&spi->dev,
SPI_COMMAND_BUFFER, GFP_KERNEL);
- if (!priv->buf) {
- ret = -ENOMEM;
- goto err_ret;
- }
+ if (!priv->buf)
+ return -ENOMEM;
mutex_init(&priv->buffer_mutex);
INIT_WORK(&priv->fifop_irqwork, cc2520_fifop_irqwork);
@@ -947,7 +935,6 @@ static int cc2520_probe(struct spi_device *spi)
if (ret)
goto err_hw_init;
-
gpio_set_value(pdata->vreg, HIGH);
usleep_range(100, 150);
@@ -991,8 +978,6 @@ static int cc2520_probe(struct spi_device *spi)
err_hw_init:
mutex_destroy(&priv->buffer_mutex);
flush_work(&priv->fifop_irqwork);
-
-err_ret:
return ret;
}
diff --git a/drivers/net/ieee802154/mrf24j40.c b/drivers/net/ieee802154/mrf24j40.c
index a200fa16beae..fba2dfd910f7 100644
--- a/drivers/net/ieee802154/mrf24j40.c
+++ b/drivers/net/ieee802154/mrf24j40.c
@@ -289,7 +289,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec,
goto out;
/* Range check the RX FIFO length, accounting for the one-byte
- * length field at the begining. */
+ * length field at the beginning. */
if (rx_len > RX_FIFO_SIZE-1) {
dev_err(printdev(devrec), "Invalid length read from device. Performing short read.\n");
rx_len = RX_FIFO_SIZE-1;
@@ -323,7 +323,7 @@ static int mrf24j40_read_rx_buf(struct mrf24j40 *devrec,
#ifdef DEBUG
print_hex_dump(KERN_DEBUG, "mrf24j40 rx: ",
- DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0);
+ DUMP_PREFIX_OFFSET, 16, 1, data, *len, 0);
pr_debug("mrf24j40 rx: lqi: %02hhx rssi: %02hhx\n",
lqi_rssi[0], lqi_rssi[1]);
#endif
@@ -521,7 +521,7 @@ static int mrf24j40_filter(struct ieee802154_hw *hw,
*/
dev_dbg(printdev(devrec), "Set Pan Coord to %s\n",
- filt->pan_coord ? "on" : "off");
+ filt->pan_coord ? "on" : "off");
}
return 0;
diff --git a/drivers/net/ipvlan/ipvlan.h b/drivers/net/ipvlan/ipvlan.h
index 2729f64b3e7e..924ea98bd531 100644
--- a/drivers/net/ipvlan/ipvlan.h
+++ b/drivers/net/ipvlan/ipvlan.h
@@ -67,7 +67,7 @@ struct ipvl_dev {
struct list_head addrs;
int ipv4cnt;
int ipv6cnt;
- struct ipvl_pcpu_stats *pcpu_stats;
+ struct ipvl_pcpu_stats __percpu *pcpu_stats;
DECLARE_BITMAP(mac_filters, IPVLAN_MAC_FILTER_SIZE);
netdev_features_t sfeatures;
u32 msg_enable;
diff --git a/drivers/net/ipvlan/ipvlan_core.c b/drivers/net/ipvlan/ipvlan_core.c
index 2e195289ddf4..2a175006028b 100644
--- a/drivers/net/ipvlan/ipvlan_core.c
+++ b/drivers/net/ipvlan/ipvlan_core.c
@@ -9,7 +9,7 @@
#include "ipvlan.h"
-static u32 ipvlan_jhash_secret;
+static u32 ipvlan_jhash_secret __read_mostly;
void ipvlan_init_secret(void)
{
diff --git a/drivers/net/irda/ali-ircc.c b/drivers/net/irda/ali-ircc.c
index 58f98f4de773..58ae11a14bb6 100644
--- a/drivers/net/irda/ali-ircc.c
+++ b/drivers/net/irda/ali-ircc.c
@@ -1462,17 +1462,12 @@ static netdev_tx_t ali_ircc_fir_hard_xmit(struct sk_buff *skb,
if (mtt)
{
/* Check how much time we have used already */
- do_gettimeofday(&self->now);
-
- diff = self->now.tv_usec - self->stamp.tv_usec;
+ diff = ktime_us_delta(ktime_get(), self->stamp);
/* self->stamp is set from ali_ircc_dma_receive_complete() */
pr_debug("%s(), ******* diff = %d *******\n",
__func__, diff);
-
- if (diff < 0)
- diff += 1000000;
-
+
/* Check if the mtt is larger than the time we have
* already used by all the protocol processing
*/
@@ -1884,7 +1879,7 @@ static int ali_ircc_dma_receive_complete(struct ali_ircc_cb *self)
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- do_gettimeofday(&self->stamp);
+ self->stamp = ktime_get();
skb = dev_alloc_skb(len+1);
if (skb == NULL)
diff --git a/drivers/net/irda/ali-ircc.h b/drivers/net/irda/ali-ircc.h
index 0c8edb41bd0a..c2d9747a5108 100644
--- a/drivers/net/irda/ali-ircc.h
+++ b/drivers/net/irda/ali-ircc.h
@@ -22,7 +22,7 @@
#ifndef ALI_IRCC_H
#define ALI_IRCC_H
-#include <linux/time.h>
+#include <linux/ktime.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
@@ -209,8 +209,7 @@ struct ali_ircc_cb {
unsigned char rcvFramesOverflow;
- struct timeval stamp;
- struct timeval now;
+ ktime_t stamp;
spinlock_t lock; /* For serializing operations */
diff --git a/drivers/net/irda/au1k_ir.c b/drivers/net/irda/au1k_ir.c
index e151205281e2..44e4f386a5dc 100644
--- a/drivers/net/irda/au1k_ir.c
+++ b/drivers/net/irda/au1k_ir.c
@@ -24,7 +24,6 @@
#include <linux/interrupt.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
-#include <linux/time.h>
#include <linux/types.h>
#include <linux/ioport.h>
@@ -163,8 +162,6 @@ struct au1k_private {
iobuff_t rx_buff;
struct net_device *netdev;
- struct timeval stamp;
- struct timeval now;
struct qos_info qos;
struct irlap_cb *irlap;
diff --git a/drivers/net/irda/irda-usb.c b/drivers/net/irda/irda-usb.c
index 48b2f9a321b7..f6c916312577 100644
--- a/drivers/net/irda/irda-usb.c
+++ b/drivers/net/irda/irda-usb.c
@@ -495,18 +495,12 @@ static netdev_tx_t irda_usb_hard_xmit(struct sk_buff *skb,
mtt = irda_get_mtt(skb);
if (mtt) {
int diff;
- do_gettimeofday(&self->now);
- diff = self->now.tv_usec - self->stamp.tv_usec;
+ diff = ktime_us_delta(ktime_get(), self->stamp);
#ifdef IU_USB_MIN_RTT
/* Factor in USB delays -> Get rid of udelay() that
* would be lost in the noise - Jean II */
diff += IU_USB_MIN_RTT;
#endif /* IU_USB_MIN_RTT */
- /* If the usec counter did wraparound, the diff will
- * go negative (tv_usec is a long), so we need to
- * correct it by one second. Jean II */
- if (diff < 0)
- diff += 1000000;
/* Check if the mtt is larger than the time we have
* already used by all the protocol processing
@@ -869,7 +863,7 @@ static void irda_usb_receive(struct urb *urb)
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- do_gettimeofday(&self->stamp);
+ self->stamp = ktime_get();
/* Check if we need to copy the data to a new skb or not.
* For most frames, we use ZeroCopy and pass the already
diff --git a/drivers/net/irda/irda-usb.h b/drivers/net/irda/irda-usb.h
index 58ddb5214916..8ac389fa9348 100644
--- a/drivers/net/irda/irda-usb.h
+++ b/drivers/net/irda/irda-usb.h
@@ -29,7 +29,7 @@
*
*****************************************************************************/
-#include <linux/time.h>
+#include <linux/ktime.h>
#include <net/irda/irda.h>
#include <net/irda/irda_device.h> /* struct irlap_cb */
@@ -157,8 +157,7 @@ struct irda_usb_cb {
char *speed_buff; /* Buffer for speed changes */
char *tx_buff;
- struct timeval stamp;
- struct timeval now;
+ ktime_t stamp;
spinlock_t lock; /* For serializing Tx operations */
diff --git a/drivers/net/irda/kingsun-sir.c b/drivers/net/irda/kingsun-sir.c
index e638893e98a9..fb5d162ec7d2 100644
--- a/drivers/net/irda/kingsun-sir.c
+++ b/drivers/net/irda/kingsun-sir.c
@@ -114,7 +114,6 @@ struct kingsun_cb {
(usually 8) */
iobuff_t rx_buff; /* receive unwrap state machine */
- struct timeval rx_time;
spinlock_t lock;
int receiving;
@@ -235,7 +234,6 @@ static void kingsun_rcv_irq(struct urb *urb)
&kingsun->netdev->stats,
&kingsun->rx_buff, bytes[i]);
}
- do_gettimeofday(&kingsun->rx_time);
kingsun->receiving =
(kingsun->rx_buff.state != OUTSIDE_FRAME)
? 1 : 0;
@@ -273,7 +271,6 @@ static int kingsun_net_open(struct net_device *netdev)
skb_reserve(kingsun->rx_buff.skb, 1);
kingsun->rx_buff.head = kingsun->rx_buff.skb->data;
- do_gettimeofday(&kingsun->rx_time);
kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->rx_urb)
diff --git a/drivers/net/irda/ks959-sir.c b/drivers/net/irda/ks959-sir.c
index e6b3804edacd..8e6e0edf2440 100644
--- a/drivers/net/irda/ks959-sir.c
+++ b/drivers/net/irda/ks959-sir.c
@@ -187,7 +187,6 @@ struct ks959_cb {
__u8 *rx_buf;
__u8 rx_variable_xormask;
iobuff_t rx_unwrap_buff;
- struct timeval rx_time;
struct usb_ctrlrequest *speed_setuprequest;
struct urb *speed_urb;
@@ -476,7 +475,6 @@ static void ks959_rcv_irq(struct urb *urb)
bytes[i]);
}
}
- do_gettimeofday(&kingsun->rx_time);
kingsun->receiving =
(kingsun->rx_unwrap_buff.state != OUTSIDE_FRAME) ? 1 : 0;
}
@@ -514,7 +512,6 @@ static int ks959_net_open(struct net_device *netdev)
skb_reserve(kingsun->rx_unwrap_buff.skb, 1);
kingsun->rx_unwrap_buff.head = kingsun->rx_unwrap_buff.skb->data;
- do_gettimeofday(&kingsun->rx_time);
kingsun->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!kingsun->rx_urb)
diff --git a/drivers/net/irda/mcs7780.c b/drivers/net/irda/mcs7780.c
index e4d678fbeb2f..bca6a1e72d1d 100644
--- a/drivers/net/irda/mcs7780.c
+++ b/drivers/net/irda/mcs7780.c
@@ -722,7 +722,6 @@ static int mcs_net_open(struct net_device *netdev)
skb_reserve(mcs->rx_buff.skb, 1);
mcs->rx_buff.head = mcs->rx_buff.skb->data;
- do_gettimeofday(&mcs->rx_time);
/*
* Now that everything should be initialized properly,
@@ -799,7 +798,6 @@ static void mcs_receive_irq(struct urb *urb)
mcs_unwrap_fir(mcs, urb->transfer_buffer,
urb->actual_length);
}
- do_gettimeofday(&mcs->rx_time);
}
ret = usb_submit_urb(urb, GFP_ATOMIC);
diff --git a/drivers/net/irda/mcs7780.h b/drivers/net/irda/mcs7780.h
index b10689b2887c..a6e8f7dbafc9 100644
--- a/drivers/net/irda/mcs7780.h
+++ b/drivers/net/irda/mcs7780.h
@@ -116,7 +116,6 @@ struct mcs_cb {
__u8 *fifo_status;
iobuff_t rx_buff; /* receive unwrap state machine */
- struct timeval rx_time;
spinlock_t lock;
int receiving;
diff --git a/drivers/net/irda/nsc-ircc.c b/drivers/net/irda/nsc-ircc.c
index e7317b104bfb..dc0dbd8dd0b5 100644
--- a/drivers/net/irda/nsc-ircc.c
+++ b/drivers/net/irda/nsc-ircc.c
@@ -1501,10 +1501,7 @@ static netdev_tx_t nsc_ircc_hard_xmit_fir(struct sk_buff *skb,
mtt = irda_get_mtt(skb);
if (mtt) {
/* Check how much time we have used already */
- do_gettimeofday(&self->now);
- diff = self->now.tv_usec - self->stamp.tv_usec;
- if (diff < 0)
- diff += 1000000;
+ diff = ktime_us_delta(ktime_get(), self->stamp);
/* Check if the mtt is larger than the time we have
* already used by all the protocol processing
@@ -1867,7 +1864,7 @@ static int nsc_ircc_dma_receive_complete(struct nsc_ircc_cb *self, int iobase)
* reduce the min turn time a bit since we will know
* how much time we have used for protocol processing
*/
- do_gettimeofday(&self->stamp);
+ self->stamp = ktime_get();
skb = dev_alloc_skb(len+1);
if (skb == NULL) {
diff --git a/drivers/net/irda/nsc-ircc.h b/drivers/net/irda/nsc-ircc.h
index 32fa58211fad..7be5acb56532 100644
--- a/drivers/net/irda/nsc-ircc.h
+++ b/drivers/net/irda/nsc-ircc.h
@@ -28,7 +28,7 @@
#ifndef NSC_IRCC_H
#define NSC_IRCC_H
-#include <linux/time.h>
+#include <linux/ktime.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
@@ -263,8 +263,7 @@ struct nsc_ircc_cb {
__u8 ier; /* Interrupt enable register */
- struct timeval stamp;
- struct timeval now;
+ ktime_t stamp;
spinlock_t lock; /* For serializing operations */
diff --git a/drivers/net/irda/sa1100_ir.c b/drivers/net/irda/sa1100_ir.c
index 7b17fa2114e1..b6e44ff4e373 100644
--- a/drivers/net/irda/sa1100_ir.c
+++ b/drivers/net/irda/sa1100_ir.c
@@ -38,7 +38,7 @@
#include <net/irda/irda_device.h>
#include <mach/hardware.h>
-#include <asm/mach/irda.h>
+#include <linux/platform_data/irda-sa11x0.h>
static int power_level = 3;
static int tx_lpm;
diff --git a/drivers/net/irda/stir4200.c b/drivers/net/irda/stir4200.c
index dd1bd1060ec9..83cc48a01802 100644
--- a/drivers/net/irda/stir4200.c
+++ b/drivers/net/irda/stir4200.c
@@ -40,6 +40,7 @@
#include <linux/moduleparam.h>
#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/types.h>
#include <linux/time.h>
#include <linux/skbuff.h>
@@ -174,7 +175,7 @@ struct stir_cb {
__u8 *fifo_status;
iobuff_t rx_buff; /* receive unwrap state machine */
- struct timeval rx_time;
+ ktime_t rx_time;
int receiving;
struct urb *rx_urb;
};
@@ -650,15 +651,12 @@ static int fifo_txwait(struct stir_cb *stir, int space)
static void turnaround_delay(const struct stir_cb *stir, long us)
{
long ticks;
- struct timeval now;
if (us <= 0)
return;
- do_gettimeofday(&now);
- if (now.tv_sec - stir->rx_time.tv_sec > 0)
- us -= USEC_PER_SEC;
- us -= now.tv_usec - stir->rx_time.tv_usec;
+ us -= ktime_us_delta(ktime_get(), stir->rx_time);
+
if (us < 10)
return;
@@ -823,8 +821,8 @@ static void stir_rcv_irq(struct urb *urb)
pr_debug("receive %d\n", urb->actual_length);
unwrap_chars(stir, urb->transfer_buffer,
urb->actual_length);
-
- do_gettimeofday(&stir->rx_time);
+
+ stir->rx_time = ktime_get();
}
/* kernel thread is stopping receiver don't resubmit */
@@ -876,7 +874,7 @@ static int stir_net_open(struct net_device *netdev)
skb_reserve(stir->rx_buff.skb, 1);
stir->rx_buff.head = stir->rx_buff.skb->data;
- do_gettimeofday(&stir->rx_time);
+ stir->rx_time = ktime_get();
stir->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!stir->rx_urb)
diff --git a/drivers/net/irda/via-ircc.h b/drivers/net/irda/via-ircc.h
index 7ce820ecc361..ac1525573398 100644
--- a/drivers/net/irda/via-ircc.h
+++ b/drivers/net/irda/via-ircc.h
@@ -29,7 +29,6 @@ this program; if not, see <http://www.gnu.org/licenses/>.
********************************************************************/
#ifndef via_IRCC_H
#define via_IRCC_H
-#include <linux/time.h>
#include <linux/spinlock.h>
#include <linux/pm.h>
#include <linux/types.h>
@@ -106,9 +105,6 @@ struct via_ircc_cb {
__u8 ier; /* Interrupt enable register */
- struct timeval stamp;
- struct timeval now;
-
spinlock_t lock; /* For serializing operations */
__u32 flags; /* Interface flags */
diff --git a/drivers/net/irda/vlsi_ir.c b/drivers/net/irda/vlsi_ir.c
index ac39d9f33d5f..a0849f49bbec 100644
--- a/drivers/net/irda/vlsi_ir.c
+++ b/drivers/net/irda/vlsi_ir.c
@@ -33,6 +33,7 @@ MODULE_LICENSE("GPL");
/********************************************************/
#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/pci.h>
@@ -40,9 +41,9 @@ MODULE_LICENSE("GPL");
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/delay.h>
-#include <linux/time.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
+#include <linux/math64.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
#include <asm/byteorder.h>
@@ -180,8 +181,7 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev)
vlsi_irda_dev_t *idev = netdev_priv(ndev);
u8 byte;
u16 word;
- unsigned delta1, delta2;
- struct timeval now;
+ s32 sec, usec;
unsigned iobase = ndev->base_addr;
seq_printf(seq, "\n%s link state: %s / %s / %s / %s\n", ndev->name,
@@ -277,17 +277,9 @@ static void vlsi_proc_ndev(struct seq_file *seq, struct net_device *ndev)
seq_printf(seq, "\nsw-state:\n");
seq_printf(seq, "IrPHY setup: %d baud - %s encoding\n", idev->baud,
(idev->mode==IFF_SIR)?"SIR":((idev->mode==IFF_MIR)?"MIR":"FIR"));
- do_gettimeofday(&now);
- if (now.tv_usec >= idev->last_rx.tv_usec) {
- delta2 = now.tv_usec - idev->last_rx.tv_usec;
- delta1 = 0;
- }
- else {
- delta2 = 1000000 + now.tv_usec - idev->last_rx.tv_usec;
- delta1 = 1;
- }
- seq_printf(seq, "last rx: %lu.%06u sec\n",
- now.tv_sec - idev->last_rx.tv_sec - delta1, delta2);
+ sec = div_s64_rem(ktime_us_delta(ktime_get(), idev->last_rx),
+ USEC_PER_SEC, &usec);
+ seq_printf(seq, "last rx: %ul.%06u sec\n", sec, usec);
seq_printf(seq, "RX: packets=%lu / bytes=%lu / errors=%lu / dropped=%lu",
ndev->stats.rx_packets, ndev->stats.rx_bytes, ndev->stats.rx_errors,
@@ -661,7 +653,7 @@ static void vlsi_rx_interrupt(struct net_device *ndev)
}
}
- do_gettimeofday(&idev->last_rx); /* remember "now" for later mtt delay */
+ idev->last_rx = ktime_get(); /* remember "now" for later mtt delay */
vlsi_fill_rx(r);
@@ -858,9 +850,8 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb,
unsigned iobase = ndev->base_addr;
u8 status;
u16 config;
- int mtt;
+ int mtt, diff;
int len, speed;
- struct timeval now, ready;
char *msg = NULL;
speed = irda_get_next_speed(skb);
@@ -940,21 +931,10 @@ static netdev_tx_t vlsi_hard_start_xmit(struct sk_buff *skb,
spin_unlock_irqrestore(&idev->lock, flags);
if ((mtt = irda_get_mtt(skb)) > 0) {
-
- ready.tv_usec = idev->last_rx.tv_usec + mtt;
- ready.tv_sec = idev->last_rx.tv_sec;
- if (ready.tv_usec >= 1000000) {
- ready.tv_usec -= 1000000;
- ready.tv_sec++; /* IrLAP 1.1: mtt always < 1 sec */
- }
- for(;;) {
- do_gettimeofday(&now);
- if (now.tv_sec > ready.tv_sec ||
- (now.tv_sec==ready.tv_sec && now.tv_usec>=ready.tv_usec))
- break;
- udelay(100);
+ diff = ktime_us_delta(ktime_get(), idev->last_rx);
+ if (mtt > diff)
+ udelay(mtt - diff);
/* must not sleep here - called under netif_tx_lock! */
- }
}
/* tx buffer already owned by CPU due to pci_dma_sync_single_for_cpu()
@@ -1333,7 +1313,7 @@ static int vlsi_start_hw(vlsi_irda_dev_t *idev)
vlsi_fill_rx(idev->rx_ring);
- do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */
+ idev->last_rx = ktime_get(); /* first mtt may start from now on */
outw(0, iobase+VLSI_PIO_PROMPT); /* kick hw state machine */
@@ -1520,7 +1500,7 @@ static int vlsi_open(struct net_device *ndev)
if (!idev->irlap)
goto errout_free_ring;
- do_gettimeofday(&idev->last_rx); /* first mtt may start from now on */
+ idev->last_rx = ktime_get(); /* first mtt may start from now on */
idev->new_baud = 9600; /* start with IrPHY using 9600(SIR) mode */
diff --git a/drivers/net/irda/vlsi_ir.h b/drivers/net/irda/vlsi_ir.h
index f9119c6d2a09..f9db2ce4c5c6 100644
--- a/drivers/net/irda/vlsi_ir.h
+++ b/drivers/net/irda/vlsi_ir.h
@@ -723,7 +723,7 @@ typedef struct vlsi_irda_dev {
void *virtaddr;
struct vlsi_ring *tx_ring, *rx_ring;
- struct timeval last_rx;
+ ktime_t last_rx;
spinlock_t lock;
struct mutex mtx;
diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 612e0731142d..1df38bdae2ee 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -1471,11 +1471,17 @@ int macvlan_link_register(struct rtnl_link_ops *ops)
};
EXPORT_SYMBOL_GPL(macvlan_link_register);
+static struct net *macvlan_get_link_net(const struct net_device *dev)
+{
+ return dev_net(macvlan_dev_real_dev(dev));
+}
+
static struct rtnl_link_ops macvlan_link_ops = {
.kind = "macvlan",
.setup = macvlan_setup,
.newlink = macvlan_newlink,
.dellink = macvlan_dellink,
+ .get_link_net = macvlan_get_link_net,
};
static int macvlan_device_event(struct notifier_block *unused,
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 7df221788cd4..e40fdfccc9c1 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -17,7 +17,6 @@
#include <linux/fs.h>
#include <linux/uio.h>
-#include <net/ipv6.h>
#include <net/net_namespace.h>
#include <net/rtnetlink.h>
#include <net/sock.h>
@@ -81,7 +80,7 @@ static struct cdev macvtap_cdev;
static const struct proto_ops macvtap_socket_ops;
#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
- NETIF_F_TSO6)
+ NETIF_F_TSO6 | NETIF_F_UFO)
#define RX_OFFLOADS (NETIF_F_GRO | NETIF_F_LRO)
#define TAP_FEATURES (NETIF_F_GSO | NETIF_F_SG)
@@ -586,11 +585,7 @@ static int macvtap_skb_from_vnet_hdr(struct macvtap_queue *q,
gso_type = SKB_GSO_TCPV6;
break;
case VIRTIO_NET_HDR_GSO_UDP:
- pr_warn_once("macvtap: %s: using disabled UFO feature; please fix this program\n",
- current->comm);
gso_type = SKB_GSO_UDP;
- if (skb->protocol == htons(ETH_P_IPV6))
- ipv6_proxy_select_ident(skb);
break;
default:
return -EINVAL;
@@ -636,6 +631,8 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (sinfo->gso_type & SKB_GSO_TCP_ECN)
@@ -645,7 +642,7 @@ static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- if (vlan_tx_tag_present(skb))
+ if (skb_vlan_tag_present(skb))
vnet_hdr->csum_start = cpu_to_macvtap16(q,
skb_checksum_start_offset(skb) + VLAN_HLEN);
else
@@ -821,13 +818,13 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
total = vnet_hdr_len;
total += skb->len;
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
struct {
__be16 h_vlan_proto;
__be16 h_vlan_TCI;
} veth;
veth.h_vlan_proto = skb->vlan_proto;
- veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
+ veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb));
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
total += VLAN_HLEN;
@@ -965,6 +962,9 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
if (arg & TUN_F_TSO6)
feature_mask |= NETIF_F_TSO6;
}
+
+ if (arg & TUN_F_UFO)
+ feature_mask |= NETIF_F_UFO;
}
/* tun/tap driver inverts the usage for TSO offloads, where
@@ -975,7 +975,7 @@ static int set_offload(struct macvtap_queue *q, unsigned long arg)
* When user space turns off TSO, we turn off GSO/LRO so that
* user-space will not receive TSO frames.
*/
- if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6))
+ if (feature_mask & (NETIF_F_TSO | NETIF_F_TSO6 | NETIF_F_UFO))
features |= RX_OFFLOADS;
else
features &= ~RX_OFFLOADS;
@@ -1090,7 +1090,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
case TUNSETOFFLOAD:
/* let the user check for future flags */
if (arg & ~(TUN_F_CSUM | TUN_F_TSO4 | TUN_F_TSO6 |
- TUN_F_TSO_ECN))
+ TUN_F_TSO_ECN | TUN_F_UFO))
return -EINVAL;
rtnl_lock();
diff --git a/drivers/net/mii.c b/drivers/net/mii.c
index 4a99c3919037..993570b1e2ae 100644
--- a/drivers/net/mii.c
+++ b/drivers/net/mii.c
@@ -302,7 +302,7 @@ void mii_check_link (struct mii_if_info *mii)
}
/**
- * mii_check_media - check the MII interface for a duplex change
+ * mii_check_media - check the MII interface for a carrier/speed/duplex change
* @mii: the MII interface
* @ok_to_print: OK to print link up/down messages
* @init_media: OK to save duplex mode in @mii
@@ -318,10 +318,6 @@ unsigned int mii_check_media (struct mii_if_info *mii,
int advertise, lpa, media, duplex;
int lpa2 = 0;
- /* if forced media, go no further */
- if (mii->force_media)
- return 0; /* duplex did not change */
-
/* check current and old link status */
old_carrier = netif_carrier_ok(mii->dev) ? 1 : 0;
new_carrier = (unsigned int) mii_link_ok(mii);
@@ -345,6 +341,12 @@ unsigned int mii_check_media (struct mii_if_info *mii,
*/
netif_carrier_on(mii->dev);
+ if (mii->force_media) {
+ if (ok_to_print)
+ netdev_info(mii->dev, "link up\n");
+ return 0; /* duplex did not change */
+ }
+
/* get MII advertise and LPA values */
if ((!init_media) && (mii->advertising))
advertise = mii->advertising;
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index a3c251b79f38..16adbc481772 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -26,7 +26,7 @@ config AMD_PHY
config AMD_XGBE_PHY
tristate "Driver for the AMD 10GbE (amd-xgbe) PHYs"
- depends on OF && HAS_IOMEM
+ depends on (OF || ACPI) && HAS_IOMEM
---help---
Currently supports the AMD 10GbE PHY
diff --git a/drivers/net/phy/amd-xgbe-phy.c b/drivers/net/phy/amd-xgbe-phy.c
index 903dc3dc9ea7..9e3af54c9010 100644
--- a/drivers/net/phy/amd-xgbe-phy.c
+++ b/drivers/net/phy/amd-xgbe-phy.c
@@ -60,6 +60,7 @@
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <linux/workqueue.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
@@ -74,6 +75,9 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/property.h>
+#include <linux/acpi.h>
MODULE_AUTHOR("Tom Lendacky <thomas.lendacky@amd.com>");
MODULE_LICENSE("Dual BSD/GPL");
@@ -84,22 +88,43 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define XGBE_PHY_MASK 0xfffffff0
#define XGBE_PHY_SPEEDSET_PROPERTY "amd,speed-set"
+#define XGBE_PHY_BLWC_PROPERTY "amd,serdes-blwc"
+#define XGBE_PHY_CDR_RATE_PROPERTY "amd,serdes-cdr-rate"
+#define XGBE_PHY_PQ_SKEW_PROPERTY "amd,serdes-pq-skew"
+#define XGBE_PHY_TX_AMP_PROPERTY "amd,serdes-tx-amp"
+
+#define XGBE_PHY_SPEEDS 3
+#define XGBE_PHY_SPEED_1000 0
+#define XGBE_PHY_SPEED_2500 1
+#define XGBE_PHY_SPEED_10000 2
#define XGBE_AN_INT_CMPLT 0x01
#define XGBE_AN_INC_LINK 0x02
#define XGBE_AN_PG_RCV 0x04
+#define XGBE_AN_INT_MASK 0x07
#define XNP_MCF_NULL_MESSAGE 0x001
-#define XNP_ACK_PROCESSED (1 << 12)
-#define XNP_MP_FORMATTED (1 << 13)
-#define XNP_NP_EXCHANGE (1 << 15)
+#define XNP_ACK_PROCESSED BIT(12)
+#define XNP_MP_FORMATTED BIT(13)
+#define XNP_NP_EXCHANGE BIT(15)
#define XGBE_PHY_RATECHANGE_COUNT 500
+#define XGBE_PHY_KR_TRAINING_START 0x01
+#define XGBE_PHY_KR_TRAINING_ENABLE 0x02
+
+#define XGBE_PHY_FEC_ENABLE 0x01
+#define XGBE_PHY_FEC_FORWARD 0x02
+#define XGBE_PHY_FEC_MASK 0x03
+
#ifndef MDIO_PMA_10GBR_PMD_CTRL
#define MDIO_PMA_10GBR_PMD_CTRL 0x0096
#endif
+#ifndef MDIO_PMA_10GBR_FEC_ABILITY
+#define MDIO_PMA_10GBR_FEC_ABILITY 0x00aa
+#endif
+
#ifndef MDIO_PMA_10GBR_FEC_CTRL
#define MDIO_PMA_10GBR_FEC_CTRL 0x00ab
#endif
@@ -108,6 +133,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define MDIO_AN_XNP 0x0016
#endif
+#ifndef MDIO_AN_LPX
+#define MDIO_AN_LPX 0x0019
+#endif
+
#ifndef MDIO_AN_INTMASK
#define MDIO_AN_INTMASK 0x8001
#endif
@@ -116,18 +145,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define MDIO_AN_INT 0x8002
#endif
-#ifndef MDIO_AN_KR_CTRL
-#define MDIO_AN_KR_CTRL 0x8003
-#endif
-
#ifndef MDIO_CTRL1_SPEED1G
#define MDIO_CTRL1_SPEED1G (MDIO_CTRL1_SPEED10G & ~BMCR_SPEED100)
#endif
-#ifndef MDIO_KR_CTRL_PDETECT
-#define MDIO_KR_CTRL_PDETECT 0x01
-#endif
-
/* SerDes integration register offsets */
#define SIR0_KR_RT_1 0x002c
#define SIR0_STATUS 0x0040
@@ -140,10 +161,10 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define SIR0_STATUS_RX_READY_WIDTH 1
#define SIR0_STATUS_TX_READY_INDEX 8
#define SIR0_STATUS_TX_READY_WIDTH 1
+#define SIR1_SPEED_CDR_RATE_INDEX 12
+#define SIR1_SPEED_CDR_RATE_WIDTH 4
#define SIR1_SPEED_DATARATE_INDEX 4
#define SIR1_SPEED_DATARATE_WIDTH 2
-#define SIR1_SPEED_PI_SPD_SEL_INDEX 12
-#define SIR1_SPEED_PI_SPD_SEL_WIDTH 4
#define SIR1_SPEED_PLLSEL_INDEX 3
#define SIR1_SPEED_PLLSEL_WIDTH 1
#define SIR1_SPEED_RATECHANGE_INDEX 6
@@ -153,20 +174,26 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define SIR1_SPEED_WORDMODE_INDEX 0
#define SIR1_SPEED_WORDMODE_WIDTH 3
+#define SPEED_10000_BLWC 0
#define SPEED_10000_CDR 0x7
#define SPEED_10000_PLL 0x1
+#define SPEED_10000_PQ 0x1e
#define SPEED_10000_RATE 0x0
#define SPEED_10000_TXAMP 0xa
#define SPEED_10000_WORD 0x7
+#define SPEED_2500_BLWC 1
#define SPEED_2500_CDR 0x2
#define SPEED_2500_PLL 0x0
+#define SPEED_2500_PQ 0xa
#define SPEED_2500_RATE 0x1
#define SPEED_2500_TXAMP 0xf
#define SPEED_2500_WORD 0x1
+#define SPEED_1000_BLWC 1
#define SPEED_1000_CDR 0x2
#define SPEED_1000_PLL 0x0
+#define SPEED_1000_PQ 0xa
#define SPEED_1000_RATE 0x3
#define SPEED_1000_TXAMP 0xf
#define SPEED_1000_WORD 0x1
@@ -181,15 +208,6 @@ MODULE_DESCRIPTION("AMD 10GbE (amd-xgbe) PHY driver");
#define RXTX_REG114_PQ_REG_INDEX 9
#define RXTX_REG114_PQ_REG_WIDTH 7
-#define RXTX_10000_BLWC 0
-#define RXTX_10000_PQ 0x1e
-
-#define RXTX_2500_BLWC 1
-#define RXTX_2500_PQ 0xa
-
-#define RXTX_1000_BLWC 1
-#define RXTX_1000_PQ 0xa
-
/* Bit setting and getting macros
* The get macro will extract the current bit field value from within
* the variable
@@ -291,23 +309,44 @@ do { \
XRXTX_IOWRITE((_priv), _reg, reg_val); \
} while (0)
+static const u32 amd_xgbe_phy_serdes_blwc[] = {
+ SPEED_1000_BLWC,
+ SPEED_2500_BLWC,
+ SPEED_10000_BLWC,
+};
+
+static const u32 amd_xgbe_phy_serdes_cdr_rate[] = {
+ SPEED_1000_CDR,
+ SPEED_2500_CDR,
+ SPEED_10000_CDR,
+};
+
+static const u32 amd_xgbe_phy_serdes_pq_skew[] = {
+ SPEED_1000_PQ,
+ SPEED_2500_PQ,
+ SPEED_10000_PQ,
+};
+
+static const u32 amd_xgbe_phy_serdes_tx_amp[] = {
+ SPEED_1000_TXAMP,
+ SPEED_2500_TXAMP,
+ SPEED_10000_TXAMP,
+};
+
enum amd_xgbe_phy_an {
AMD_XGBE_AN_READY = 0,
- AMD_XGBE_AN_START,
- AMD_XGBE_AN_EVENT,
AMD_XGBE_AN_PAGE_RECEIVED,
AMD_XGBE_AN_INCOMPAT_LINK,
AMD_XGBE_AN_COMPLETE,
AMD_XGBE_AN_NO_LINK,
- AMD_XGBE_AN_EXIT,
AMD_XGBE_AN_ERROR,
};
enum amd_xgbe_phy_rx {
- AMD_XGBE_RX_READY = 0,
- AMD_XGBE_RX_BPA,
+ AMD_XGBE_RX_BPA = 0,
AMD_XGBE_RX_XNP,
AMD_XGBE_RX_COMPLETE,
+ AMD_XGBE_RX_ERROR,
};
enum amd_xgbe_phy_mode {
@@ -316,12 +355,13 @@ enum amd_xgbe_phy_mode {
};
enum amd_xgbe_phy_speedset {
- AMD_XGBE_PHY_SPEEDSET_1000_10000,
+ AMD_XGBE_PHY_SPEEDSET_1000_10000 = 0,
AMD_XGBE_PHY_SPEEDSET_2500_10000,
};
struct amd_xgbe_phy_priv {
struct platform_device *pdev;
+ struct acpi_device *adev;
struct device *dev;
struct phy_device *phydev;
@@ -336,10 +376,24 @@ struct amd_xgbe_phy_priv {
void __iomem *sir0_regs; /* SerDes integration registers (1/2) */
void __iomem *sir1_regs; /* SerDes integration registers (2/2) */
- /* Maintain link status for re-starting auto-negotiation */
- unsigned int link;
+ int an_irq;
+ char an_irq_name[IFNAMSIZ + 32];
+ struct work_struct an_irq_work;
+ unsigned int an_irq_allocated;
+
unsigned int speed_set;
+ /* SerDes UEFI configurable settings.
+ * Switching between modes/speeds requires new values for some
+ * SerDes settings. The values can be supplied as device
+ * properties in array format. The first array entry is for
+ * 1GbE, second for 2.5GbE and third for 10GbE
+ */
+ u32 serdes_blwc[XGBE_PHY_SPEEDS];
+ u32 serdes_cdr_rate[XGBE_PHY_SPEEDS];
+ u32 serdes_pq_skew[XGBE_PHY_SPEEDS];
+ u32 serdes_tx_amp[XGBE_PHY_SPEEDS];
+
/* Auto-negotiation state machine support */
struct mutex an_mutex;
enum amd_xgbe_phy_an an_result;
@@ -348,7 +402,11 @@ struct amd_xgbe_phy_priv {
enum amd_xgbe_phy_rx kx_state;
struct work_struct an_work;
struct workqueue_struct *an_workqueue;
+ unsigned int an_supported;
unsigned int parallel_detect;
+ unsigned int fec_ability;
+
+ unsigned int lpm_ctrl; /* CTRL1 for resume */
};
static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
@@ -359,7 +417,7 @@ static int amd_xgbe_an_enable_kr_training(struct phy_device *phydev)
if (ret < 0)
return ret;
- ret |= 0x02;
+ ret |= XGBE_PHY_KR_TRAINING_ENABLE;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
return 0;
@@ -373,7 +431,7 @@ static int amd_xgbe_an_disable_kr_training(struct phy_device *phydev)
if (ret < 0)
return ret;
- ret &= ~0x02;
+ ret &= ~XGBE_PHY_KR_TRAINING_ENABLE;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
return 0;
@@ -466,12 +524,16 @@ static int amd_xgbe_phy_xgmii_mode(struct phy_device *phydev)
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_10000_RATE);
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_10000_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_10000_TXAMP);
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_10000_PLL);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_10000_CDR);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_10000_BLWC);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_10000_PQ);
+ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE,
+ priv->serdes_cdr_rate[XGBE_PHY_SPEED_10000]);
+ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP,
+ priv->serdes_tx_amp[XGBE_PHY_SPEED_10000]);
+ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA,
+ priv->serdes_blwc[XGBE_PHY_SPEED_10000]);
+ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
+ priv->serdes_pq_skew[XGBE_PHY_SPEED_10000]);
amd_xgbe_phy_serdes_complete_ratechange(phydev);
@@ -514,12 +576,16 @@ static int amd_xgbe_phy_gmii_2500_mode(struct phy_device *phydev)
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_2500_RATE);
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_2500_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_2500_TXAMP);
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_2500_PLL);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_2500_CDR);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_2500_BLWC);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_2500_PQ);
+ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE,
+ priv->serdes_cdr_rate[XGBE_PHY_SPEED_2500]);
+ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP,
+ priv->serdes_tx_amp[XGBE_PHY_SPEED_2500]);
+ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA,
+ priv->serdes_blwc[XGBE_PHY_SPEED_2500]);
+ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
+ priv->serdes_pq_skew[XGBE_PHY_SPEED_2500]);
amd_xgbe_phy_serdes_complete_ratechange(phydev);
@@ -562,12 +628,16 @@ static int amd_xgbe_phy_gmii_mode(struct phy_device *phydev)
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, DATARATE, SPEED_1000_RATE);
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, WORDMODE, SPEED_1000_WORD);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP, SPEED_1000_TXAMP);
XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PLLSEL, SPEED_1000_PLL);
- XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, PI_SPD_SEL, SPEED_1000_CDR);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA, RXTX_1000_BLWC);
- XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG, RXTX_1000_PQ);
+ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, CDR_RATE,
+ priv->serdes_cdr_rate[XGBE_PHY_SPEED_1000]);
+ XSIR1_IOWRITE_BITS(priv, SIR1_SPEED, TXAMP,
+ priv->serdes_tx_amp[XGBE_PHY_SPEED_1000]);
+ XRXTX_IOWRITE_BITS(priv, RXTX_REG20, BLWC_ENA,
+ priv->serdes_blwc[XGBE_PHY_SPEED_1000]);
+ XRXTX_IOWRITE_BITS(priv, RXTX_REG114, PQ_REG,
+ priv->serdes_pq_skew[XGBE_PHY_SPEED_1000]);
amd_xgbe_phy_serdes_complete_ratechange(phydev);
@@ -635,6 +705,38 @@ static int amd_xgbe_phy_set_mode(struct phy_device *phydev,
return ret;
}
+static int amd_xgbe_phy_set_an(struct phy_device *phydev, bool enable,
+ bool restart)
+{
+ int ret;
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
+ if (ret < 0)
+ return ret;
+
+ ret &= ~MDIO_AN_CTRL1_ENABLE;
+
+ if (enable)
+ ret |= MDIO_AN_CTRL1_ENABLE;
+
+ if (restart)
+ ret |= MDIO_AN_CTRL1_RESTART;
+
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret);
+
+ return 0;
+}
+
+static int amd_xgbe_phy_restart_an(struct phy_device *phydev)
+{
+ return amd_xgbe_phy_set_an(phydev, true, true);
+}
+
+static int amd_xgbe_phy_disable_an(struct phy_device *phydev)
+{
+ return amd_xgbe_phy_set_an(phydev, false, false);
+}
+
static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
enum amd_xgbe_phy_rx *state)
{
@@ -645,7 +747,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
/* If we're not in KR mode then we're done */
if (!amd_xgbe_phy_in_kr_mode(phydev))
- return AMD_XGBE_AN_EVENT;
+ return AMD_XGBE_AN_PAGE_RECEIVED;
/* Enable/Disable FEC */
ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
@@ -660,10 +762,9 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
if (ret < 0)
return AMD_XGBE_AN_ERROR;
+ ret &= ~XGBE_PHY_FEC_MASK;
if ((ad_reg & 0xc000) && (lp_reg & 0xc000))
- ret |= 0x01;
- else
- ret &= ~0x01;
+ ret |= priv->fec_ability;
phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_CTRL, ret);
@@ -672,14 +773,17 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_training(struct phy_device *phydev,
if (ret < 0)
return AMD_XGBE_AN_ERROR;
- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1);
+ if (ret & XGBE_PHY_KR_TRAINING_ENABLE) {
+ XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 1);
- ret |= 0x01;
- phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL, ret);
+ ret |= XGBE_PHY_KR_TRAINING_START;
+ phy_write_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_PMD_CTRL,
+ ret);
- XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0);
+ XSIR0_IOWRITE_BITS(priv, SIR0_KR_RT_1, RESET, 0);
+ }
- return AMD_XGBE_AN_EVENT;
+ return AMD_XGBE_AN_PAGE_RECEIVED;
}
static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
@@ -696,7 +800,7 @@ static enum amd_xgbe_phy_an amd_xgbe_an_tx_xnp(struct phy_device *phydev,
phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP + 1, 0);
phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP, msg);
- return AMD_XGBE_AN_EVENT;
+ return AMD_XGBE_AN_PAGE_RECEIVED;
}
static enum amd_xgbe_phy_an amd_xgbe_an_rx_bpa(struct phy_device *phydev,
@@ -735,11 +839,11 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev,
int ad_reg, lp_reg;
/* Check Extended Next Page support */
- ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ ad_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_XNP);
if (ad_reg < 0)
return AMD_XGBE_AN_ERROR;
- lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPA);
+ lp_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_LPX);
if (lp_reg < 0)
return AMD_XGBE_AN_ERROR;
@@ -748,226 +852,255 @@ static enum amd_xgbe_phy_an amd_xgbe_an_rx_xnp(struct phy_device *phydev,
amd_xgbe_an_tx_training(phydev, state);
}
-static enum amd_xgbe_phy_an amd_xgbe_an_start(struct phy_device *phydev)
+static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
+{
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
+ enum amd_xgbe_phy_rx *state;
+ int ret;
+
+ state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state
+ : &priv->kx_state;
+
+ switch (*state) {
+ case AMD_XGBE_RX_BPA:
+ ret = amd_xgbe_an_rx_bpa(phydev, state);
+ break;
+
+ case AMD_XGBE_RX_XNP:
+ ret = amd_xgbe_an_rx_xnp(phydev, state);
+ break;
+
+ default:
+ ret = AMD_XGBE_AN_ERROR;
+ }
+
+ return ret;
+}
+
+static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
{
struct amd_xgbe_phy_priv *priv = phydev->priv;
int ret;
/* Be sure we aren't looping trying to negotiate */
if (amd_xgbe_phy_in_kr_mode(phydev)) {
- if (priv->kr_state != AMD_XGBE_RX_READY)
+ priv->kr_state = AMD_XGBE_RX_ERROR;
+
+ if (!(phydev->supported & SUPPORTED_1000baseKX_Full) &&
+ !(phydev->supported & SUPPORTED_2500baseX_Full))
+ return AMD_XGBE_AN_NO_LINK;
+
+ if (priv->kx_state != AMD_XGBE_RX_BPA)
return AMD_XGBE_AN_NO_LINK;
- priv->kr_state = AMD_XGBE_RX_BPA;
} else {
- if (priv->kx_state != AMD_XGBE_RX_READY)
+ priv->kx_state = AMD_XGBE_RX_ERROR;
+
+ if (!(phydev->supported & SUPPORTED_10000baseKR_Full))
+ return AMD_XGBE_AN_NO_LINK;
+
+ if (priv->kr_state != AMD_XGBE_RX_BPA)
return AMD_XGBE_AN_NO_LINK;
- priv->kx_state = AMD_XGBE_RX_BPA;
}
- /* Set up Advertisement register 3 first */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
- if (ret < 0)
+ ret = amd_xgbe_phy_disable_an(phydev);
+ if (ret)
return AMD_XGBE_AN_ERROR;
- if (phydev->supported & SUPPORTED_10000baseR_FEC)
- ret |= 0xc000;
- else
- ret &= ~0xc000;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret);
-
- /* Set up Advertisement register 2 next */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
- if (ret < 0)
+ ret = amd_xgbe_phy_switch_mode(phydev);
+ if (ret)
return AMD_XGBE_AN_ERROR;
- if (phydev->supported & SUPPORTED_10000baseKR_Full)
- ret |= 0x80;
- else
- ret &= ~0x80;
-
- if ((phydev->supported & SUPPORTED_1000baseKX_Full) ||
- (phydev->supported & SUPPORTED_2500baseX_Full))
- ret |= 0x20;
- else
- ret &= ~0x20;
-
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret);
-
- /* Set up Advertisement register 1 last */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
- if (ret < 0)
+ ret = amd_xgbe_phy_restart_an(phydev);
+ if (ret)
return AMD_XGBE_AN_ERROR;
- if (phydev->supported & SUPPORTED_Pause)
- ret |= 0x400;
- else
- ret &= ~0x400;
+ return AMD_XGBE_AN_INCOMPAT_LINK;
+}
- if (phydev->supported & SUPPORTED_Asym_Pause)
- ret |= 0x800;
- else
- ret &= ~0x800;
+static irqreturn_t amd_xgbe_an_isr(int irq, void *data)
+{
+ struct amd_xgbe_phy_priv *priv = (struct amd_xgbe_phy_priv *)data;
- /* We don't intend to perform XNP */
- ret &= ~XNP_NP_EXCHANGE;
+ /* Interrupt reason must be read and cleared outside of IRQ context */
+ disable_irq_nosync(priv->an_irq);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret);
+ queue_work(priv->an_workqueue, &priv->an_irq_work);
- /* Enable and start auto-negotiation */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ return IRQ_HANDLED;
+}
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
+static void amd_xgbe_an_irq_work(struct work_struct *work)
+{
+ struct amd_xgbe_phy_priv *priv = container_of(work,
+ struct amd_xgbe_phy_priv,
+ an_irq_work);
- ret |= MDIO_KR_CTRL_PDETECT;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_KR_CTRL, ret);
+ /* Avoid a race between enabling the IRQ and exiting the work by
+ * waiting for the work to finish and then queueing it
+ */
+ flush_work(&priv->an_work);
+ queue_work(priv->an_workqueue, &priv->an_work);
+}
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
+static void amd_xgbe_an_state_machine(struct work_struct *work)
+{
+ struct amd_xgbe_phy_priv *priv = container_of(work,
+ struct amd_xgbe_phy_priv,
+ an_work);
+ struct phy_device *phydev = priv->phydev;
+ enum amd_xgbe_phy_an cur_state = priv->an_state;
+ int int_reg, int_mask;
- ret |= MDIO_AN_CTRL1_ENABLE;
- ret |= MDIO_AN_CTRL1_RESTART;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret);
+ mutex_lock(&priv->an_mutex);
- return AMD_XGBE_AN_EVENT;
-}
+ /* Read the interrupt */
+ int_reg = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT);
+ if (!int_reg)
+ goto out;
-static enum amd_xgbe_phy_an amd_xgbe_an_event(struct phy_device *phydev)
-{
- enum amd_xgbe_phy_an new_state;
- int ret;
+next_int:
+ if (int_reg < 0) {
+ priv->an_state = AMD_XGBE_AN_ERROR;
+ int_mask = XGBE_AN_INT_MASK;
+ } else if (int_reg & XGBE_AN_PG_RCV) {
+ priv->an_state = AMD_XGBE_AN_PAGE_RECEIVED;
+ int_mask = XGBE_AN_PG_RCV;
+ } else if (int_reg & XGBE_AN_INC_LINK) {
+ priv->an_state = AMD_XGBE_AN_INCOMPAT_LINK;
+ int_mask = XGBE_AN_INC_LINK;
+ } else if (int_reg & XGBE_AN_INT_CMPLT) {
+ priv->an_state = AMD_XGBE_AN_COMPLETE;
+ int_mask = XGBE_AN_INT_CMPLT;
+ } else {
+ priv->an_state = AMD_XGBE_AN_ERROR;
+ int_mask = 0;
+ }
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT);
- if (ret < 0)
- return AMD_XGBE_AN_ERROR;
+ /* Clear the interrupt to be processed */
+ int_reg &= ~int_mask;
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, int_reg);
- new_state = AMD_XGBE_AN_EVENT;
- if (ret & XGBE_AN_PG_RCV)
- new_state = AMD_XGBE_AN_PAGE_RECEIVED;
- else if (ret & XGBE_AN_INC_LINK)
- new_state = AMD_XGBE_AN_INCOMPAT_LINK;
- else if (ret & XGBE_AN_INT_CMPLT)
- new_state = AMD_XGBE_AN_COMPLETE;
+ priv->an_result = priv->an_state;
- if (new_state != AMD_XGBE_AN_EVENT)
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+again:
+ cur_state = priv->an_state;
- return new_state;
-}
+ switch (priv->an_state) {
+ case AMD_XGBE_AN_READY:
+ priv->an_supported = 0;
+ break;
-static enum amd_xgbe_phy_an amd_xgbe_an_page_received(struct phy_device *phydev)
-{
- struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_rx *state;
- int ret;
+ case AMD_XGBE_AN_PAGE_RECEIVED:
+ priv->an_state = amd_xgbe_an_page_received(phydev);
+ priv->an_supported++;
+ break;
- state = amd_xgbe_phy_in_kr_mode(phydev) ? &priv->kr_state
- : &priv->kx_state;
+ case AMD_XGBE_AN_INCOMPAT_LINK:
+ priv->an_supported = 0;
+ priv->parallel_detect = 0;
+ priv->an_state = amd_xgbe_an_incompat_link(phydev);
+ break;
- switch (*state) {
- case AMD_XGBE_RX_BPA:
- ret = amd_xgbe_an_rx_bpa(phydev, state);
+ case AMD_XGBE_AN_COMPLETE:
+ priv->parallel_detect = priv->an_supported ? 0 : 1;
+ netdev_dbg(phydev->attached_dev, "%s successful\n",
+ priv->an_supported ? "Auto negotiation"
+ : "Parallel detection");
break;
- case AMD_XGBE_RX_XNP:
- ret = amd_xgbe_an_rx_xnp(phydev, state);
+ case AMD_XGBE_AN_NO_LINK:
break;
default:
- ret = AMD_XGBE_AN_ERROR;
+ priv->an_state = AMD_XGBE_AN_ERROR;
}
- return ret;
-}
+ if (priv->an_state == AMD_XGBE_AN_NO_LINK) {
+ int_reg = 0;
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ } else if (priv->an_state == AMD_XGBE_AN_ERROR) {
+ netdev_err(phydev->attached_dev,
+ "error during auto-negotiation, state=%u\n",
+ cur_state);
-static enum amd_xgbe_phy_an amd_xgbe_an_incompat_link(struct phy_device *phydev)
-{
- int ret;
+ int_reg = 0;
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ }
- ret = amd_xgbe_phy_switch_mode(phydev);
- if (ret)
- return AMD_XGBE_AN_ERROR;
+ if (priv->an_state >= AMD_XGBE_AN_COMPLETE) {
+ priv->an_result = priv->an_state;
+ priv->an_state = AMD_XGBE_AN_READY;
+ priv->kr_state = AMD_XGBE_RX_BPA;
+ priv->kx_state = AMD_XGBE_RX_BPA;
+ }
- return AMD_XGBE_AN_START;
-}
+ if (cur_state != priv->an_state)
+ goto again;
-static void amd_xgbe_an_state_machine(struct work_struct *work)
-{
- struct amd_xgbe_phy_priv *priv = container_of(work,
- struct amd_xgbe_phy_priv,
- an_work);
- struct phy_device *phydev = priv->phydev;
- enum amd_xgbe_phy_an cur_state;
- int sleep;
- unsigned int an_supported = 0;
+ if (int_reg)
+ goto next_int;
- /* Start in KX mode */
- if (amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX))
- priv->an_state = AMD_XGBE_AN_ERROR;
+out:
+ enable_irq(priv->an_irq);
- while (1) {
- mutex_lock(&priv->an_mutex);
+ mutex_unlock(&priv->an_mutex);
+}
- cur_state = priv->an_state;
+static int amd_xgbe_an_init(struct phy_device *phydev)
+{
+ int ret;
- switch (priv->an_state) {
- case AMD_XGBE_AN_START:
- an_supported = 0;
- priv->parallel_detect = 0;
- priv->an_state = amd_xgbe_an_start(phydev);
- break;
+ /* Set up Advertisement register 3 first */
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2);
+ if (ret < 0)
+ return ret;
- case AMD_XGBE_AN_EVENT:
- priv->an_state = amd_xgbe_an_event(phydev);
- break;
+ if (phydev->supported & SUPPORTED_10000baseR_FEC)
+ ret |= 0xc000;
+ else
+ ret &= ~0xc000;
- case AMD_XGBE_AN_PAGE_RECEIVED:
- priv->an_state = amd_xgbe_an_page_received(phydev);
- an_supported++;
- break;
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 2, ret);
- case AMD_XGBE_AN_INCOMPAT_LINK:
- priv->an_state = amd_xgbe_an_incompat_link(phydev);
- break;
+ /* Set up Advertisement register 2 next */
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1);
+ if (ret < 0)
+ return ret;
- case AMD_XGBE_AN_COMPLETE:
- priv->parallel_detect = an_supported ? 0 : 1;
- netdev_info(phydev->attached_dev, "%s successful\n",
- an_supported ? "Auto negotiation"
- : "Parallel detection");
- /* fall through */
+ if (phydev->supported & SUPPORTED_10000baseKR_Full)
+ ret |= 0x80;
+ else
+ ret &= ~0x80;
- case AMD_XGBE_AN_NO_LINK:
- case AMD_XGBE_AN_EXIT:
- goto exit_unlock;
+ if ((phydev->supported & SUPPORTED_1000baseKX_Full) ||
+ (phydev->supported & SUPPORTED_2500baseX_Full))
+ ret |= 0x20;
+ else
+ ret &= ~0x20;
- default:
- priv->an_state = AMD_XGBE_AN_ERROR;
- }
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE + 1, ret);
- if (priv->an_state == AMD_XGBE_AN_ERROR) {
- netdev_err(phydev->attached_dev,
- "error during auto-negotiation, state=%u\n",
- cur_state);
- goto exit_unlock;
- }
+ /* Set up Advertisement register 1 last */
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE);
+ if (ret < 0)
+ return ret;
- sleep = (priv->an_state == AMD_XGBE_AN_EVENT) ? 1 : 0;
+ if (phydev->supported & SUPPORTED_Pause)
+ ret |= 0x400;
+ else
+ ret &= ~0x400;
- mutex_unlock(&priv->an_mutex);
+ if (phydev->supported & SUPPORTED_Asym_Pause)
+ ret |= 0x800;
+ else
+ ret &= ~0x800;
- if (sleep)
- usleep_range(20, 50);
- }
+ /* We don't intend to perform XNP */
+ ret &= ~XNP_NP_EXCHANGE;
-exit_unlock:
- priv->an_result = priv->an_state;
- priv->an_state = AMD_XGBE_AN_READY;
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_ADVERTISE, ret);
- mutex_unlock(&priv->an_mutex);
+ return 0;
}
static int amd_xgbe_phy_soft_reset(struct phy_device *phydev)
@@ -992,20 +1125,57 @@ static int amd_xgbe_phy_soft_reset(struct phy_device *phydev)
if (ret & MDIO_CTRL1_RESET)
return -ETIMEDOUT;
- /* Make sure the XPCS and SerDes are in compatible states */
- return amd_xgbe_phy_xgmii_mode(phydev);
+ /* Disable auto-negotiation for now */
+ ret = amd_xgbe_phy_disable_an(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* Clear auto-negotiation interrupts */
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
+ return 0;
}
static int amd_xgbe_phy_config_init(struct phy_device *phydev)
{
struct amd_xgbe_phy_priv *priv = phydev->priv;
+ struct net_device *netdev = phydev->attached_dev;
+ int ret;
+
+ if (!priv->an_irq_allocated) {
+ /* Allocate the auto-negotiation workqueue and interrupt */
+ snprintf(priv->an_irq_name, sizeof(priv->an_irq_name) - 1,
+ "%s-pcs", netdev_name(netdev));
+
+ priv->an_workqueue =
+ create_singlethread_workqueue(priv->an_irq_name);
+ if (!priv->an_workqueue) {
+ netdev_err(netdev, "phy workqueue creation failed\n");
+ return -ENOMEM;
+ }
+
+ ret = devm_request_irq(priv->dev, priv->an_irq,
+ amd_xgbe_an_isr, 0, priv->an_irq_name,
+ priv);
+ if (ret) {
+ netdev_err(netdev, "phy irq request failed\n");
+ destroy_workqueue(priv->an_workqueue);
+ return ret;
+ }
+
+ priv->an_irq_allocated = 1;
+ }
+
+ ret = phy_read_mmd(phydev, MDIO_MMD_PMAPMD, MDIO_PMA_10GBR_FEC_ABILITY);
+ if (ret < 0)
+ return ret;
+ priv->fec_ability = ret & XGBE_PHY_FEC_MASK;
/* Initialize supported features */
phydev->supported = SUPPORTED_Autoneg;
phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
phydev->supported |= SUPPORTED_Backplane;
- phydev->supported |= SUPPORTED_10000baseKR_Full |
- SUPPORTED_10000baseR_FEC;
+ phydev->supported |= SUPPORTED_10000baseKR_Full;
switch (priv->speed_set) {
case AMD_XGBE_PHY_SPEEDSET_1000_10000:
phydev->supported |= SUPPORTED_1000baseKX_Full;
@@ -1014,11 +1184,33 @@ static int amd_xgbe_phy_config_init(struct phy_device *phydev)
phydev->supported |= SUPPORTED_2500baseX_Full;
break;
}
+
+ if (priv->fec_ability & XGBE_PHY_FEC_ENABLE)
+ phydev->supported |= SUPPORTED_10000baseR_FEC;
+
phydev->advertising = phydev->supported;
- /* Turn off and clear interrupts */
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0);
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+ /* Set initial mode - call the mode setting routines
+ * directly to insure we are properly configured
+ */
+ if (phydev->supported & SUPPORTED_10000baseKR_Full)
+ ret = amd_xgbe_phy_xgmii_mode(phydev);
+ else if (phydev->supported & SUPPORTED_1000baseKX_Full)
+ ret = amd_xgbe_phy_gmii_mode(phydev);
+ else if (phydev->supported & SUPPORTED_2500baseX_Full)
+ ret = amd_xgbe_phy_gmii_2500_mode(phydev);
+ else
+ ret = -EINVAL;
+ if (ret < 0)
+ return ret;
+
+ /* Set up advertisement registers based on current settings */
+ ret = amd_xgbe_an_init(phydev);
+ if (ret)
+ return ret;
+
+ /* Enable auto-negotiation interrupts */
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INTMASK, 0x07);
return 0;
}
@@ -1028,25 +1220,19 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev)
int ret;
/* Disable auto-negotiation */
- ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
+ ret = amd_xgbe_phy_disable_an(phydev);
if (ret < 0)
return ret;
- ret &= ~MDIO_AN_CTRL1_ENABLE;
- phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1, ret);
-
/* Validate/Set specified speed */
switch (phydev->speed) {
case SPEED_10000:
- ret = amd_xgbe_phy_xgmii_mode(phydev);
+ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
break;
case SPEED_2500:
- ret = amd_xgbe_phy_gmii_2500_mode(phydev);
- break;
-
case SPEED_1000:
- ret = amd_xgbe_phy_gmii_mode(phydev);
+ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
break;
default:
@@ -1066,10 +1252,11 @@ static int amd_xgbe_phy_setup_forced(struct phy_device *phydev)
return 0;
}
-static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
+static int __amd_xgbe_phy_config_aneg(struct phy_device *phydev)
{
struct amd_xgbe_phy_priv *priv = phydev->priv;
u32 mmd_mask = phydev->c45_ids.devices_in_package;
+ int ret;
if (phydev->autoneg != AUTONEG_ENABLE)
return amd_xgbe_phy_setup_forced(phydev);
@@ -1078,56 +1265,79 @@ static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
if (!(mmd_mask & MDIO_DEVS_AN))
return -EINVAL;
- /* Start/Restart the auto-negotiation state machine */
- mutex_lock(&priv->an_mutex);
+ /* Disable auto-negotiation interrupt */
+ disable_irq(priv->an_irq);
+
+ /* Start auto-negotiation in a supported mode */
+ if (phydev->supported & SUPPORTED_10000baseKR_Full)
+ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KR);
+ else if ((phydev->supported & SUPPORTED_1000baseKX_Full) ||
+ (phydev->supported & SUPPORTED_2500baseX_Full))
+ ret = amd_xgbe_phy_set_mode(phydev, AMD_XGBE_MODE_KX);
+ else
+ ret = -EINVAL;
+ if (ret < 0) {
+ enable_irq(priv->an_irq);
+ return ret;
+ }
+
+ /* Disable and stop any in progress auto-negotiation */
+ ret = amd_xgbe_phy_disable_an(phydev);
+ if (ret < 0)
+ return ret;
+
+ /* Clear any auto-negotitation interrupts */
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_INT, 0);
+
priv->an_result = AMD_XGBE_AN_READY;
- priv->an_state = AMD_XGBE_AN_START;
- priv->kr_state = AMD_XGBE_RX_READY;
- priv->kx_state = AMD_XGBE_RX_READY;
- mutex_unlock(&priv->an_mutex);
+ priv->an_state = AMD_XGBE_AN_READY;
+ priv->kr_state = AMD_XGBE_RX_BPA;
+ priv->kx_state = AMD_XGBE_RX_BPA;
- queue_work(priv->an_workqueue, &priv->an_work);
+ /* Re-enable auto-negotiation interrupt */
+ enable_irq(priv->an_irq);
- return 0;
+ /* Set up advertisement registers based on current settings */
+ ret = amd_xgbe_an_init(phydev);
+ if (ret)
+ return ret;
+
+ /* Enable and start auto-negotiation */
+ return amd_xgbe_phy_restart_an(phydev);
}
-static int amd_xgbe_phy_aneg_done(struct phy_device *phydev)
+static int amd_xgbe_phy_config_aneg(struct phy_device *phydev)
{
struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_an state;
+ int ret;
mutex_lock(&priv->an_mutex);
- state = priv->an_result;
+
+ ret = __amd_xgbe_phy_config_aneg(phydev);
+
mutex_unlock(&priv->an_mutex);
- return (state == AMD_XGBE_AN_COMPLETE);
+ return ret;
+}
+
+static int amd_xgbe_phy_aneg_done(struct phy_device *phydev)
+{
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
+
+ return (priv->an_result == AMD_XGBE_AN_COMPLETE);
}
static int amd_xgbe_phy_update_link(struct phy_device *phydev)
{
struct amd_xgbe_phy_priv *priv = phydev->priv;
- enum amd_xgbe_phy_an state;
- unsigned int check_again, autoneg;
int ret;
/* If we're doing auto-negotiation don't report link down */
- mutex_lock(&priv->an_mutex);
- state = priv->an_state;
- mutex_unlock(&priv->an_mutex);
-
- if (state != AMD_XGBE_AN_READY) {
+ if (priv->an_state != AMD_XGBE_AN_READY) {
phydev->link = 1;
return 0;
}
- /* Since the device can be in the wrong mode when a link is
- * (re-)established (cable connected after the interface is
- * up, etc.), the link status may report no link. If there
- * is no link, try switching modes and checking the status
- * again if auto negotiation is enabled.
- */
- check_again = (phydev->autoneg == AUTONEG_ENABLE) ? 1 : 0;
-again:
/* Link status is latched low, so read once to clear
* and then read again to get current state
*/
@@ -1141,25 +1351,6 @@ again:
phydev->link = (ret & MDIO_STAT1_LSTATUS) ? 1 : 0;
- if (!phydev->link) {
- if (check_again) {
- ret = amd_xgbe_phy_switch_mode(phydev);
- if (ret < 0)
- return ret;
- check_again = 0;
- goto again;
- }
- }
-
- autoneg = (phydev->link && !priv->link) ? 1 : 0;
- priv->link = phydev->link;
- if (autoneg) {
- /* Link is (back) up, re-start auto-negotiation */
- ret = amd_xgbe_phy_config_aneg(phydev);
- if (ret < 0)
- return ret;
- }
-
return 0;
}
@@ -1249,6 +1440,7 @@ static int amd_xgbe_phy_read_status(struct phy_device *phydev)
static int amd_xgbe_phy_suspend(struct phy_device *phydev)
{
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
int ret;
mutex_lock(&phydev->lock);
@@ -1257,6 +1449,8 @@ static int amd_xgbe_phy_suspend(struct phy_device *phydev)
if (ret < 0)
goto unlock;
+ priv->lpm_ctrl = ret;
+
ret |= MDIO_CTRL1_LPOWER;
phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
@@ -1270,69 +1464,106 @@ unlock:
static int amd_xgbe_phy_resume(struct phy_device *phydev)
{
- int ret;
+ struct amd_xgbe_phy_priv *priv = phydev->priv;
mutex_lock(&phydev->lock);
- ret = phy_read_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1);
- if (ret < 0)
- goto unlock;
+ priv->lpm_ctrl &= ~MDIO_CTRL1_LPOWER;
+ phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, priv->lpm_ctrl);
- ret &= ~MDIO_CTRL1_LPOWER;
- phy_write_mmd(phydev, MDIO_MMD_PCS, MDIO_CTRL1, ret);
+ mutex_unlock(&phydev->lock);
- ret = 0;
+ return 0;
+}
-unlock:
- mutex_unlock(&phydev->lock);
+static unsigned int amd_xgbe_phy_resource_count(struct platform_device *pdev,
+ unsigned int type)
+{
+ unsigned int count;
+ int i;
- return ret;
+ for (i = 0, count = 0; i < pdev->num_resources; i++) {
+ struct resource *r = &pdev->resource[i];
+
+ if (type == resource_type(r))
+ count++;
+ }
+
+ return count;
}
static int amd_xgbe_phy_probe(struct phy_device *phydev)
{
struct amd_xgbe_phy_priv *priv;
- struct platform_device *pdev;
- struct device *dev;
- char *wq_name;
- const __be32 *property;
- unsigned int speed_set;
+ struct platform_device *phy_pdev;
+ struct device *dev, *phy_dev;
+ unsigned int phy_resnum, phy_irqnum;
int ret;
- if (!phydev->dev.of_node)
+ if (!phydev->bus || !phydev->bus->parent)
return -EINVAL;
- pdev = of_find_device_by_node(phydev->dev.of_node);
- if (!pdev)
- return -EINVAL;
- dev = &pdev->dev;
-
- wq_name = kasprintf(GFP_KERNEL, "%s-amd-xgbe-phy", phydev->bus->name);
- if (!wq_name) {
- ret = -ENOMEM;
- goto err_pdev;
- }
+ dev = phydev->bus->parent;
priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
- if (!priv) {
- ret = -ENOMEM;
- goto err_name;
- }
+ if (!priv)
+ return -ENOMEM;
- priv->pdev = pdev;
+ priv->pdev = to_platform_device(dev);
+ priv->adev = ACPI_COMPANION(dev);
priv->dev = dev;
priv->phydev = phydev;
+ mutex_init(&priv->an_mutex);
+ INIT_WORK(&priv->an_irq_work, amd_xgbe_an_irq_work);
+ INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
+
+ if (!priv->adev || acpi_disabled) {
+ struct device_node *bus_node;
+ struct device_node *phy_node;
+
+ bus_node = priv->dev->of_node;
+ phy_node = of_parse_phandle(bus_node, "phy-handle", 0);
+ if (!phy_node) {
+ dev_err(dev, "unable to parse phy-handle\n");
+ ret = -EINVAL;
+ goto err_priv;
+ }
+
+ phy_pdev = of_find_device_by_node(phy_node);
+ of_node_put(phy_node);
+
+ if (!phy_pdev) {
+ dev_err(dev, "unable to obtain phy device\n");
+ ret = -EINVAL;
+ goto err_priv;
+ }
+
+ phy_resnum = 0;
+ phy_irqnum = 0;
+ } else {
+ /* In ACPI, the XGBE and PHY resources are the grouped
+ * together with the PHY resources at the end
+ */
+ phy_pdev = priv->pdev;
+ phy_resnum = amd_xgbe_phy_resource_count(phy_pdev,
+ IORESOURCE_MEM) - 3;
+ phy_irqnum = amd_xgbe_phy_resource_count(phy_pdev,
+ IORESOURCE_IRQ) - 1;
+ }
+ phy_dev = &phy_pdev->dev;
/* Get the device mmio areas */
- priv->rxtx_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ priv->rxtx_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
+ phy_resnum++);
priv->rxtx_regs = devm_ioremap_resource(dev, priv->rxtx_res);
if (IS_ERR(priv->rxtx_regs)) {
dev_err(dev, "rxtx ioremap failed\n");
ret = PTR_ERR(priv->rxtx_regs);
- goto err_priv;
+ goto err_put;
}
- priv->sir0_res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ priv->sir0_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
+ phy_resnum++);
priv->sir0_regs = devm_ioremap_resource(dev, priv->sir0_res);
if (IS_ERR(priv->sir0_regs)) {
dev_err(dev, "sir0 ioremap failed\n");
@@ -1340,7 +1571,8 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
goto err_rxtx;
}
- priv->sir1_res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ priv->sir1_res = platform_get_resource(phy_pdev, IORESOURCE_MEM,
+ phy_resnum++);
priv->sir1_regs = devm_ioremap_resource(dev, priv->sir1_res);
if (IS_ERR(priv->sir1_regs)) {
dev_err(dev, "sir1 ioremap failed\n");
@@ -1348,40 +1580,98 @@ static int amd_xgbe_phy_probe(struct phy_device *phydev)
goto err_sir0;
}
+ /* Get the auto-negotiation interrupt */
+ ret = platform_get_irq(phy_pdev, phy_irqnum);
+ if (ret < 0) {
+ dev_err(dev, "platform_get_irq failed\n");
+ goto err_sir1;
+ }
+ priv->an_irq = ret;
+
/* Get the device speed set property */
- speed_set = 0;
- property = of_get_property(dev->of_node, XGBE_PHY_SPEEDSET_PROPERTY,
- NULL);
- if (property)
- speed_set = be32_to_cpu(*property);
-
- switch (speed_set) {
- case 0:
- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_1000_10000;
- break;
- case 1:
- priv->speed_set = AMD_XGBE_PHY_SPEEDSET_2500_10000;
+ ret = device_property_read_u32(phy_dev, XGBE_PHY_SPEEDSET_PROPERTY,
+ &priv->speed_set);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PHY_SPEEDSET_PROPERTY);
+ goto err_sir1;
+ }
+
+ switch (priv->speed_set) {
+ case AMD_XGBE_PHY_SPEEDSET_1000_10000:
+ case AMD_XGBE_PHY_SPEEDSET_2500_10000:
break;
default:
- dev_err(dev, "invalid amd,speed-set property\n");
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PHY_SPEEDSET_PROPERTY);
ret = -EINVAL;
goto err_sir1;
}
- priv->link = 1;
+ if (device_property_present(phy_dev, XGBE_PHY_BLWC_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_PHY_BLWC_PROPERTY,
+ priv->serdes_blwc,
+ XGBE_PHY_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PHY_BLWC_PROPERTY);
+ goto err_sir1;
+ }
+ } else {
+ memcpy(priv->serdes_blwc, amd_xgbe_phy_serdes_blwc,
+ sizeof(priv->serdes_blwc));
+ }
- mutex_init(&priv->an_mutex);
- INIT_WORK(&priv->an_work, amd_xgbe_an_state_machine);
- priv->an_workqueue = create_singlethread_workqueue(wq_name);
- if (!priv->an_workqueue) {
- ret = -ENOMEM;
- goto err_sir1;
+ if (device_property_present(phy_dev, XGBE_PHY_CDR_RATE_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_PHY_CDR_RATE_PROPERTY,
+ priv->serdes_cdr_rate,
+ XGBE_PHY_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PHY_CDR_RATE_PROPERTY);
+ goto err_sir1;
+ }
+ } else {
+ memcpy(priv->serdes_cdr_rate, amd_xgbe_phy_serdes_cdr_rate,
+ sizeof(priv->serdes_cdr_rate));
+ }
+
+ if (device_property_present(phy_dev, XGBE_PHY_PQ_SKEW_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_PHY_PQ_SKEW_PROPERTY,
+ priv->serdes_pq_skew,
+ XGBE_PHY_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PHY_PQ_SKEW_PROPERTY);
+ goto err_sir1;
+ }
+ } else {
+ memcpy(priv->serdes_pq_skew, amd_xgbe_phy_serdes_pq_skew,
+ sizeof(priv->serdes_pq_skew));
+ }
+
+ if (device_property_present(phy_dev, XGBE_PHY_TX_AMP_PROPERTY)) {
+ ret = device_property_read_u32_array(phy_dev,
+ XGBE_PHY_TX_AMP_PROPERTY,
+ priv->serdes_tx_amp,
+ XGBE_PHY_SPEEDS);
+ if (ret) {
+ dev_err(dev, "invalid %s property\n",
+ XGBE_PHY_TX_AMP_PROPERTY);
+ goto err_sir1;
+ }
+ } else {
+ memcpy(priv->serdes_tx_amp, amd_xgbe_phy_serdes_tx_amp,
+ sizeof(priv->serdes_tx_amp));
}
phydev->priv = priv;
- kfree(wq_name);
- of_dev_put(pdev);
+ if (!priv->adev || acpi_disabled)
+ platform_device_put(phy_pdev);
return 0;
@@ -1400,15 +1690,13 @@ err_rxtx:
devm_release_mem_region(dev, priv->rxtx_res->start,
resource_size(priv->rxtx_res));
+err_put:
+ if (!priv->adev || acpi_disabled)
+ platform_device_put(phy_pdev);
+
err_priv:
devm_kfree(dev, priv);
-err_name:
- kfree(wq_name);
-
-err_pdev:
- of_dev_put(pdev);
-
return ret;
}
@@ -1417,13 +1705,12 @@ static void amd_xgbe_phy_remove(struct phy_device *phydev)
struct amd_xgbe_phy_priv *priv = phydev->priv;
struct device *dev = priv->dev;
- /* Stop any in process auto-negotiation */
- mutex_lock(&priv->an_mutex);
- priv->an_state = AMD_XGBE_AN_EXIT;
- mutex_unlock(&priv->an_mutex);
+ if (priv->an_irq_allocated) {
+ devm_free_irq(dev, priv->an_irq, priv);
- flush_workqueue(priv->an_workqueue);
- destroy_workqueue(priv->an_workqueue);
+ flush_workqueue(priv->an_workqueue);
+ destroy_workqueue(priv->an_workqueue);
+ }
/* Release resources */
devm_iounmap(dev, priv->sir1_regs);
diff --git a/drivers/net/phy/fixed_phy.c b/drivers/net/phy/fixed_phy.c
index 3ad0e6e16c39..a08a3c78ba97 100644
--- a/drivers/net/phy/fixed_phy.c
+++ b/drivers/net/phy/fixed_phy.c
@@ -168,7 +168,7 @@ int fixed_phy_set_link_update(struct phy_device *phydev,
struct fixed_mdio_bus *fmb = &platform_fmb;
struct fixed_phy *fp;
- if (!link_update || !phydev || !phydev->bus)
+ if (!phydev || !phydev->bus)
return -EINVAL;
list_for_each_entry(fp, &fmb->phys, node) {
diff --git a/drivers/net/phy/mdio_bus.c b/drivers/net/phy/mdio_bus.c
index 50051f271b10..095ef3fe369a 100644
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -443,9 +443,13 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
if (!drv || !phydrv->suspend)
return false;
- /* PHY not attached? May suspend. */
+ /* PHY not attached? May suspend if the PHY has not already been
+ * suspended as part of a prior call to phy_disconnect() ->
+ * phy_detach() -> phy_suspend() because the parent netdev might be the
+ * MDIO bus driver and clock gated at this point.
+ */
if (!netdev)
- return true;
+ return !phydev->suspended;
/* Don't suspend PHY if the attched netdev parent may wakeup.
* The parent may point to a PCI device, as in tg3 driver.
@@ -465,7 +469,6 @@ static bool mdio_bus_phy_may_suspend(struct phy_device *phydev)
static int mdio_bus_suspend(struct device *dev)
{
- struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
/* We must stop the state machine manually, otherwise it stops out of
@@ -479,19 +482,18 @@ static int mdio_bus_suspend(struct device *dev)
if (!mdio_bus_phy_may_suspend(phydev))
return 0;
- return phydrv->suspend(phydev);
+ return phy_suspend(phydev);
}
static int mdio_bus_resume(struct device *dev)
{
- struct phy_driver *phydrv = to_phy_driver(dev->driver);
struct phy_device *phydev = to_phy_device(dev);
int ret;
if (!mdio_bus_phy_may_suspend(phydev))
goto no_resume;
- ret = phydrv->resume(phydev);
+ ret = phy_resume(phydev);
if (ret < 0)
return ret;
diff --git a/drivers/net/phy/micrel.c b/drivers/net/phy/micrel.c
index 3ad8ca76196d..1190fd8f0088 100644
--- a/drivers/net/phy/micrel.c
+++ b/drivers/net/phy/micrel.c
@@ -32,6 +32,7 @@
/* Operation Mode Strap Override */
#define MII_KSZPHY_OMSO 0x16
#define KSZPHY_OMSO_B_CAST_OFF BIT(9)
+#define KSZPHY_OMSO_NAND_TREE_ON BIT(5)
#define KSZPHY_OMSO_RMII_OVERRIDE BIT(1)
#define KSZPHY_OMSO_MII_OVERRIDE BIT(0)
@@ -76,6 +77,7 @@ struct kszphy_type {
u32 led_mode_reg;
u16 interrupt_level_mask;
bool has_broadcast_disable;
+ bool has_nand_tree_disable;
bool has_rmii_ref_clk_sel;
};
@@ -89,6 +91,7 @@ struct kszphy_priv {
static const struct kszphy_type ksz8021_type = {
.led_mode_reg = MII_KSZPHY_CTRL_2,
.has_broadcast_disable = true,
+ .has_nand_tree_disable = true,
.has_rmii_ref_clk_sel = true,
};
@@ -98,11 +101,13 @@ static const struct kszphy_type ksz8041_type = {
static const struct kszphy_type ksz8051_type = {
.led_mode_reg = MII_KSZPHY_CTRL_2,
+ .has_nand_tree_disable = true,
};
static const struct kszphy_type ksz8081_type = {
.led_mode_reg = MII_KSZPHY_CTRL_2,
.has_broadcast_disable = true,
+ .has_nand_tree_disable = true,
.has_rmii_ref_clk_sel = true,
};
@@ -231,6 +236,26 @@ out:
return ret;
}
+static int kszphy_nand_tree_disable(struct phy_device *phydev)
+{
+ int ret;
+
+ ret = phy_read(phydev, MII_KSZPHY_OMSO);
+ if (ret < 0)
+ goto out;
+
+ if (!(ret & KSZPHY_OMSO_NAND_TREE_ON))
+ return 0;
+
+ ret = phy_write(phydev, MII_KSZPHY_OMSO,
+ ret & ~KSZPHY_OMSO_NAND_TREE_ON);
+out:
+ if (ret)
+ dev_err(&phydev->dev, "failed to disable NAND tree mode\n");
+
+ return ret;
+}
+
static int kszphy_config_init(struct phy_device *phydev)
{
struct kszphy_priv *priv = phydev->priv;
@@ -245,6 +270,9 @@ static int kszphy_config_init(struct phy_device *phydev)
if (type->has_broadcast_disable)
kszphy_broadcast_disable(phydev);
+ if (type->has_nand_tree_disable)
+ kszphy_nand_tree_disable(phydev);
+
if (priv->rmii_ref_clk_sel) {
ret = kszphy_rmii_clk_sel(phydev, priv->rmii_ref_clk_sel_val);
if (ret) {
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
index 767cd110f496..cdcac6aa4260 100644
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -439,6 +439,9 @@ int phy_start_aneg(struct phy_device *phydev)
if (AUTONEG_DISABLE == phydev->autoneg)
phy_sanitize_settings(phydev);
+ /* Invalidate LP advertising flags */
+ phydev->lp_advertising = 0;
+
err = phydev->drv->config_aneg(phydev);
if (err < 0)
goto out_unlock;
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
index 3fc91e89f5a5..bdfe51fc3a65 100644
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -699,6 +699,7 @@ int phy_suspend(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
+ int ret = 0;
/* If the device has WOL enabled, we cannot suspend the PHY */
phy_ethtool_get_wol(phydev, &wol);
@@ -706,18 +707,31 @@ int phy_suspend(struct phy_device *phydev)
return -EBUSY;
if (phydrv->suspend)
- return phydrv->suspend(phydev);
- return 0;
+ ret = phydrv->suspend(phydev);
+
+ if (ret)
+ return ret;
+
+ phydev->suspended = true;
+
+ return ret;
}
EXPORT_SYMBOL(phy_suspend);
int phy_resume(struct phy_device *phydev)
{
struct phy_driver *phydrv = to_phy_driver(phydev->dev.driver);
+ int ret = 0;
if (phydrv->resume)
- return phydrv->resume(phydev);
- return 0;
+ ret = phydrv->resume(phydev);
+
+ if (ret)
+ return ret;
+
+ phydev->suspended = false;
+
+ return ret;
}
EXPORT_SYMBOL(phy_resume);
diff --git a/drivers/net/ppp/ppp_deflate.c b/drivers/net/ppp/ppp_deflate.c
index 602c625d95d5..b5edc7f96a39 100644
--- a/drivers/net/ppp/ppp_deflate.c
+++ b/drivers/net/ppp/ppp_deflate.c
@@ -246,7 +246,7 @@ static int z_compress(void *arg, unsigned char *rptr, unsigned char *obuf,
/*
* See if we managed to reduce the size of the packet.
*/
- if (olen < isize) {
+ if (olen < isize && olen <= osize) {
state->stats.comp_bytes += olen;
state->stats.comp_packets++;
} else {
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index f7ff493f1e73..0e62274e884a 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -28,6 +28,7 @@
#include <net/genetlink.h>
#include <net/netlink.h>
#include <net/sch_generic.h>
+#include <net/switchdev.h>
#include <generated/utsrelease.h>
#include <linux/if_team.h>
@@ -176,7 +177,6 @@ static int __team_option_inst_add(struct team *team, struct team_option *option,
static int __team_option_inst_add_option(struct team *team,
struct team_option *option)
{
- struct team_port *port;
int err;
if (!option->per_port) {
@@ -184,12 +184,6 @@ static int __team_option_inst_add_option(struct team *team,
if (err)
goto inst_del_option;
}
-
- list_for_each_entry(port, &team->port_list, list) {
- err = __team_option_inst_add(team, option, port);
- if (err)
- goto inst_del_option;
- }
return 0;
inst_del_option:
@@ -1932,7 +1926,7 @@ static netdev_features_t team_fix_features(struct net_device *dev,
struct team *team = netdev_priv(dev);
netdev_features_t mask;
- mask = features;
+ mask = features | NETIF_F_HW_SWITCH_OFFLOAD;
features &= ~NETIF_F_ONE_FOR_ALL;
features |= NETIF_F_ALL_FOR_ALL;
@@ -1982,6 +1976,8 @@ static const struct net_device_ops team_netdev_ops = {
.ndo_del_slave = team_del_slave,
.ndo_fix_features = team_fix_features,
.ndo_change_carrier = team_change_carrier,
+ .ndo_bridge_setlink = ndo_dflt_netdev_switch_port_bridge_setlink,
+ .ndo_bridge_dellink = ndo_dflt_netdev_switch_port_bridge_dellink,
};
/***********************
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index 8c8dc16839a7..857dca47bf80 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -65,7 +65,6 @@
#include <linux/nsproxy.h>
#include <linux/virtio_net.h>
#include <linux/rcupdate.h>
-#include <net/ipv6.h>
#include <net/net_namespace.h>
#include <net/netns/generic.h>
#include <net/rtnetlink.h>
@@ -124,10 +123,9 @@ struct tap_filter {
unsigned char addr[FLT_EXACT_COUNT][ETH_ALEN];
};
-/* DEFAULT_MAX_NUM_RSS_QUEUES were chosen to let the rx/tx queues allocated for
- * the netdevice to be fit in one page. So we can make sure the success of
- * memory allocation. TODO: increase the limit. */
-#define MAX_TAP_QUEUES DEFAULT_MAX_NUM_RSS_QUEUES
+/* MAX_TAP_QUEUES 256 is chosen to allow rx/tx queues to be equal
+ * to max number of VCPUs in guest. */
+#define MAX_TAP_QUEUES 256
#define MAX_TAP_FLOWS 4096
#define TUN_FLOW_EXPIRE (3 * HZ)
@@ -187,7 +185,7 @@ struct tun_struct {
struct net_device *dev;
netdev_features_t set_features;
#define TUN_USER_FEATURES (NETIF_F_HW_CSUM|NETIF_F_TSO_ECN|NETIF_F_TSO| \
- NETIF_F_TSO6)
+ NETIF_F_TSO6|NETIF_F_UFO)
int vnet_hdr_sz;
int sndbuf;
@@ -258,7 +256,6 @@ static void tun_flow_delete(struct tun_struct *tun, struct tun_flow_entry *e)
{
tun_debug(KERN_INFO, tun, "delete flow: hash %u index %u\n",
e->rxhash, e->queue_index);
- sock_rps_reset_flow_hash(e->rps_rxhash);
hlist_del_rcu(&e->hash_link);
kfree_rcu(e, rcu);
--tun->flow_count;
@@ -375,10 +372,8 @@ unlock:
*/
static inline void tun_flow_save_rps_rxhash(struct tun_flow_entry *e, u32 hash)
{
- if (unlikely(e->rps_rxhash != hash)) {
- sock_rps_reset_flow_hash(e->rps_rxhash);
+ if (unlikely(e->rps_rxhash != hash))
e->rps_rxhash = hash;
- }
}
/* We try to identify a flow through its rxhash first. The reason that
@@ -1167,8 +1162,6 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
break;
}
- skb_reset_network_header(skb);
-
if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
pr_debug("GSO!\n");
switch (gso.gso_type & ~VIRTIO_NET_HDR_GSO_ECN) {
@@ -1179,20 +1172,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
case VIRTIO_NET_HDR_GSO_UDP:
- {
- static bool warned;
-
- if (!warned) {
- warned = true;
- netdev_warn(tun->dev,
- "%s: using disabled UFO feature; please fix this program\n",
- current->comm);
- }
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
- if (skb->protocol == htons(ETH_P_IPV6))
- ipv6_proxy_select_ident(skb);
break;
- }
default:
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
@@ -1221,6 +1202,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb_shinfo(skb)->tx_flags |= SKBTX_SHARED_FRAG;
}
+ skb_reset_network_header(skb);
skb_probe_transport_header(skb, 0);
rxhash = skb_get_hash(skb);
@@ -1261,7 +1243,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
int vlan_hlen = 0;
int vnet_hdr_sz = 0;
- if (vlan_tx_tag_present(skb))
+ if (skb_vlan_tag_present(skb))
vlan_hlen = VLAN_HLEN;
if (tun->flags & IFF_VNET_HDR)
@@ -1298,6 +1280,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (sinfo->gso_type & SKB_GSO_UDP)
+ gso.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else {
pr_err("unexpected GSO type: "
"0x%x, gso_size %d, hdr_len %d\n",
@@ -1338,7 +1322,7 @@ static ssize_t tun_put_user(struct tun_struct *tun,
} veth;
veth.h_vlan_proto = skb->vlan_proto;
- veth.h_vlan_TCI = htons(vlan_tx_tag_get(skb));
+ veth.h_vlan_TCI = htons(skb_vlan_tag_get(skb));
vlan_offset = offsetof(struct vlan_ethhdr, h_vlan_proto);
@@ -1380,7 +1364,7 @@ static ssize_t tun_do_read(struct tun_struct *tun, struct tun_file *tfile,
skb = __skb_recv_datagram(tfile->socket.sk, noblock ? MSG_DONTWAIT : 0,
&peeked, &off, &err);
if (!skb)
- return 0;
+ return err;
ret = tun_put_user(tun, tfile, skb, to);
if (unlikely(ret < 0))
@@ -1501,7 +1485,7 @@ static int tun_recvmsg(struct kiocb *iocb, struct socket *sock,
goto out;
}
ret = tun_do_read(tun, tfile, &m->msg_iter, flags & MSG_DONTWAIT);
- if (ret > total_len) {
+ if (ret > (ssize_t)total_len) {
m->msg_flags |= MSG_TRUNC;
ret = flags & MSG_TRUNC ? ret : total_len;
}
@@ -1566,6 +1550,17 @@ static DEVICE_ATTR(tun_flags, 0444, tun_show_flags, NULL);
static DEVICE_ATTR(owner, 0444, tun_show_owner, NULL);
static DEVICE_ATTR(group, 0444, tun_show_group, NULL);
+static struct attribute *tun_dev_attrs[] = {
+ &dev_attr_tun_flags.attr,
+ &dev_attr_owner.attr,
+ &dev_attr_group.attr,
+ NULL
+};
+
+static const struct attribute_group tun_attr_group = {
+ .attrs = tun_dev_attrs
+};
+
static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
{
struct tun_struct *tun;
@@ -1646,6 +1641,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
dev_net_set(dev, net);
dev->rtnl_link_ops = &tun_link_ops;
dev->ifindex = tfile->ifindex;
+ dev->sysfs_groups[0] = &tun_attr_group;
tun = netdev_priv(dev);
tun->dev = dev;
@@ -1681,11 +1677,6 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
err = register_netdevice(tun->dev);
if (err < 0)
goto err_detach;
-
- if (device_create_file(&tun->dev->dev, &dev_attr_tun_flags) ||
- device_create_file(&tun->dev->dev, &dev_attr_owner) ||
- device_create_file(&tun->dev->dev, &dev_attr_group))
- pr_err("Failed to create tun sysfs files\n");
}
netif_carrier_on(tun->dev);
@@ -1746,6 +1737,11 @@ static int set_offload(struct tun_struct *tun, unsigned long arg)
features |= NETIF_F_TSO6;
arg &= ~(TUN_F_TSO4|TUN_F_TSO6);
}
+
+ if (arg & TUN_F_UFO) {
+ features |= NETIF_F_UFO;
+ arg &= ~TUN_F_UFO;
+ }
}
/* This gives the user a way to test for new features in future by
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 37eed4d84e9c..3bd9678315ad 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -397,14 +397,14 @@ config USB_NET_CDC_SUBSET
not generally have permanently assigned Ethernet addresses.
config USB_ALI_M5632
- boolean "ALi M5632 based 'USB 2.0 Data Link' cables"
+ bool "ALi M5632 based 'USB 2.0 Data Link' cables"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
based on this design, which supports USB 2.0 high speed.
config USB_AN2720
- boolean "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
+ bool "AnchorChips 2720 based cables (Xircom PGUNET, ...)"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
@@ -412,7 +412,7 @@ config USB_AN2720
Cypress brand.
config USB_BELKIN
- boolean "eTEK based host-to-host cables (Advance, Belkin, ...)"
+ bool "eTEK based host-to-host cables (Advance, Belkin, ...)"
depends on USB_NET_CDC_SUBSET
default y
help
@@ -421,7 +421,7 @@ config USB_BELKIN
microcontroller, with LEDs that indicate traffic.
config USB_ARMLINUX
- boolean "Embedded ARM Linux links (iPaq, ...)"
+ bool "Embedded ARM Linux links (iPaq, ...)"
depends on USB_NET_CDC_SUBSET
default y
help
@@ -438,14 +438,14 @@ config USB_ARMLINUX
this simpler protocol by installing a different kernel.
config USB_EPSON2888
- boolean "Epson 2888 based firmware (DEVELOPMENT)"
+ bool "Epson 2888 based firmware (DEVELOPMENT)"
depends on USB_NET_CDC_SUBSET
help
Choose this option to support the usb networking links used
by some sample firmware from Epson.
config USB_KC2190
- boolean "KT Technology KC2190 based cables (InstaNet)"
+ bool "KT Technology KC2190 based cables (InstaNet)"
depends on USB_NET_CDC_SUBSET
help
Choose this option if you're using a host-to-host cable
diff --git a/drivers/net/usb/hso.c b/drivers/net/usb/hso.c
index 9c5aa922a9f4..9cdfb3fe9c15 100644
--- a/drivers/net/usb/hso.c
+++ b/drivers/net/usb/hso.c
@@ -58,7 +58,6 @@
#include <linux/module.h>
#include <linux/ethtool.h>
#include <linux/usb.h>
-#include <linux/timer.h>
#include <linux/tty.h>
#include <linux/tty_driver.h>
#include <linux/tty_flip.h>
@@ -154,6 +153,7 @@ struct hso_net {
struct hso_device *parent;
struct net_device *net;
struct rfkill *rfkill;
+ char name[24];
struct usb_endpoint_descriptor *in_endp;
struct usb_endpoint_descriptor *out_endp;
@@ -274,7 +274,6 @@ struct hso_device {
u8 usb_gone;
struct work_struct async_get_intf;
struct work_struct async_put_intf;
- struct work_struct reset_device;
struct usb_device *usb;
struct usb_interface *interface;
@@ -340,7 +339,6 @@ static void async_put_intf(struct work_struct *data);
static int hso_put_activity(struct hso_device *hso_dev);
static int hso_get_activity(struct hso_device *hso_dev);
static void tiocmget_intr_callback(struct urb *urb);
-static void reset_device(struct work_struct *data);
/*****************************************************************************/
/* Helping functions */
/*****************************************************************************/
@@ -533,6 +531,13 @@ static ssize_t hso_sysfs_show_porttype(struct device *dev,
}
static DEVICE_ATTR(hsotype, S_IRUGO, hso_sysfs_show_porttype, NULL);
+static struct attribute *hso_serial_dev_attrs[] = {
+ &dev_attr_hsotype.attr,
+ NULL
+};
+
+ATTRIBUTE_GROUPS(hso_serial_dev);
+
static int hso_urb_to_index(struct hso_serial *serial, struct urb *urb)
{
int idx;
@@ -696,7 +701,7 @@ static void handle_usb_error(int status, const char *function,
case -ETIMEDOUT:
explanation = "protocol error";
if (hso_dev)
- schedule_work(&hso_dev->reset_device);
+ usb_queue_reset_device(hso_dev->interface);
break;
default:
explanation = "unknown status";
@@ -909,7 +914,7 @@ static void packetizeRx(struct hso_net *odev, unsigned char *ip_pkt,
/* We got no receive buffer. */
D1("could not allocate memory");
odev->rx_parse_state = WAIT_SYNC;
- return;
+ continue;
}
/* Copy what we got so far. make room for iphdr
@@ -1271,7 +1276,6 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
goto err_out;
D1("Opening %d", serial->minor);
- kref_get(&serial->parent->ref);
/* setup */
tty->driver_data = serial;
@@ -1290,7 +1294,8 @@ static int hso_serial_open(struct tty_struct *tty, struct file *filp)
if (result) {
hso_stop_serial_device(serial->parent);
serial->port.count--;
- kref_put(&serial->parent->ref, hso_serial_ref_free);
+ } else {
+ kref_get(&serial->parent->ref);
}
} else {
D1("Port was already open");
@@ -1340,8 +1345,6 @@ static void hso_serial_close(struct tty_struct *tty, struct file *filp)
usb_autopm_put_interface(serial->parent->interface);
mutex_unlock(&serial->parent->mutex);
-
- kref_put(&serial->parent->ref, hso_serial_ref_free);
}
/* close the requested serial port */
@@ -1392,6 +1395,16 @@ static int hso_serial_write_room(struct tty_struct *tty)
return room;
}
+static void hso_serial_cleanup(struct tty_struct *tty)
+{
+ struct hso_serial *serial = tty->driver_data;
+
+ if (!serial)
+ return;
+
+ kref_put(&serial->parent->ref, hso_serial_ref_free);
+}
+
/* setup the term */
static void hso_serial_set_termios(struct tty_struct *tty, struct ktermios *old)
{
@@ -2198,8 +2211,8 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
for (i = 0; i < serial->num_rx_urbs; i++) {
if (serial->rx_urb[i]) {
- usb_kill_urb(serial->rx_urb[i]);
- serial->rx_urb_filled[i] = 0;
+ usb_kill_urb(serial->rx_urb[i]);
+ serial->rx_urb_filled[i] = 0;
}
}
serial->curr_rx_urb_idx = 0;
@@ -2228,15 +2241,15 @@ static int hso_stop_serial_device(struct hso_device *hso_dev)
return 0;
}
+static void hso_serial_tty_unregister(struct hso_serial *serial)
+{
+ tty_unregister_device(tty_drv, serial->minor);
+}
+
static void hso_serial_common_free(struct hso_serial *serial)
{
int i;
- if (serial->parent->dev)
- device_remove_file(serial->parent->dev, &dev_attr_hsotype);
-
- tty_unregister_device(tty_drv, serial->minor);
-
for (i = 0; i < serial->num_rx_urbs; i++) {
/* unlink and free RX URB */
usb_free_urb(serial->rx_urb[i]);
@@ -2246,6 +2259,7 @@ static void hso_serial_common_free(struct hso_serial *serial)
/* unlink and free TX URB */
usb_free_urb(serial->tx_urb);
+ kfree(serial->tx_buffer);
kfree(serial->tx_data);
tty_port_destroy(&serial->port);
}
@@ -2264,11 +2278,10 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
goto exit;
/* register our minor number */
- serial->parent->dev = tty_port_register_device(&serial->port, tty_drv,
- minor, &serial->parent->interface->dev);
+ serial->parent->dev = tty_port_register_device_attr(&serial->port,
+ tty_drv, minor, &serial->parent->interface->dev,
+ serial->parent, hso_serial_dev_groups);
dev = serial->parent->dev;
- dev_set_drvdata(dev, serial->parent);
- i = device_create_file(dev, &dev_attr_hsotype);
/* fill in specific data for later use */
serial->minor = minor;
@@ -2316,6 +2329,7 @@ static int hso_serial_common_create(struct hso_serial *serial, int num_urbs,
return 0;
exit:
+ hso_serial_tty_unregister(serial);
hso_serial_common_free(serial);
return -1;
}
@@ -2338,7 +2352,6 @@ static struct hso_device *hso_create_device(struct usb_interface *intf,
INIT_WORK(&hso_dev->async_get_intf, async_get_intf);
INIT_WORK(&hso_dev->async_put_intf, async_put_intf);
- INIT_WORK(&hso_dev->reset_device, reset_device);
return hso_dev;
}
@@ -2459,27 +2472,21 @@ static void hso_create_rfkill(struct hso_device *hso_dev,
{
struct hso_net *hso_net = dev2net(hso_dev);
struct device *dev = &hso_net->net->dev;
- char *rfkn;
+ static u32 rfkill_counter;
- rfkn = kzalloc(20, GFP_KERNEL);
- if (!rfkn)
- dev_err(dev, "%s - Out of memory\n", __func__);
-
- snprintf(rfkn, 20, "hso-%d",
- interface->altsetting->desc.bInterfaceNumber);
+ snprintf(hso_net->name, sizeof(hso_net->name), "hso-%d",
+ rfkill_counter++);
- hso_net->rfkill = rfkill_alloc(rfkn,
+ hso_net->rfkill = rfkill_alloc(hso_net->name,
&interface_to_usbdev(interface)->dev,
RFKILL_TYPE_WWAN,
&hso_rfkill_ops, hso_dev);
if (!hso_net->rfkill) {
dev_err(dev, "%s - Out of memory\n", __func__);
- kfree(rfkn);
return;
}
if (rfkill_register(hso_net->rfkill) < 0) {
rfkill_destroy(hso_net->rfkill);
- kfree(rfkn);
hso_net->rfkill = NULL;
dev_err(dev, "%s - Failed to register rfkill\n", __func__);
return;
@@ -2594,7 +2601,6 @@ static void hso_free_serial_device(struct hso_device *hso_dev)
if (!serial)
return;
- set_serial_by_index(serial->minor, NULL);
hso_serial_common_free(serial);
@@ -2684,6 +2690,7 @@ static struct hso_device *hso_create_bulk_serial_device(
return hso_dev;
exit2:
+ hso_serial_tty_unregister(serial);
hso_serial_common_free(serial);
exit:
hso_free_tiomget(serial);
@@ -3083,26 +3090,6 @@ out:
return result;
}
-static void reset_device(struct work_struct *data)
-{
- struct hso_device *hso_dev =
- container_of(data, struct hso_device, reset_device);
- struct usb_device *usb = hso_dev->usb;
- int result;
-
- if (hso_dev->usb_gone) {
- D1("No reset during disconnect\n");
- } else {
- result = usb_lock_device_for_reset(usb, hso_dev->interface);
- if (result < 0)
- D1("unable to lock device for reset: %d\n", result);
- else {
- usb_reset_device(usb);
- usb_unlock_device(usb);
- }
- }
-}
-
static void hso_serial_ref_free(struct kref *ref)
{
struct hso_device *hso_dev = container_of(ref, struct hso_device, ref);
@@ -3112,18 +3099,22 @@ static void hso_serial_ref_free(struct kref *ref)
static void hso_free_interface(struct usb_interface *interface)
{
- struct hso_serial *hso_dev;
+ struct hso_serial *serial;
int i;
for (i = 0; i < HSO_SERIAL_TTY_MINORS; i++) {
if (serial_table[i] &&
(serial_table[i]->interface == interface)) {
- hso_dev = dev2ser(serial_table[i]);
- tty_port_tty_hangup(&hso_dev->port, false);
- mutex_lock(&hso_dev->parent->mutex);
- hso_dev->parent->usb_gone = 1;
- mutex_unlock(&hso_dev->parent->mutex);
+ serial = dev2ser(serial_table[i]);
+ tty_port_tty_hangup(&serial->port, false);
+ mutex_lock(&serial->parent->mutex);
+ serial->parent->usb_gone = 1;
+ mutex_unlock(&serial->parent->mutex);
+ cancel_work_sync(&serial_table[i]->async_put_intf);
+ cancel_work_sync(&serial_table[i]->async_get_intf);
+ hso_serial_tty_unregister(serial);
kref_put(&serial_table[i]->ref, hso_serial_ref_free);
+ set_serial_by_index(i, NULL);
}
}
@@ -3215,6 +3206,7 @@ static const struct tty_operations hso_serial_ops = {
.close = hso_serial_close,
.write = hso_serial_write,
.write_room = hso_serial_write_room,
+ .cleanup = hso_serial_cleanup,
.ioctl = hso_serial_ioctl,
.set_termios = hso_serial_set_termios,
.chars_in_buffer = hso_serial_chars_in_buffer,
diff --git a/drivers/net/usb/r8152.c b/drivers/net/usb/r8152.c
index bf405f134d3a..438fc6bcaef1 100644
--- a/drivers/net/usb/r8152.c
+++ b/drivers/net/usb/r8152.c
@@ -27,7 +27,7 @@
#include <linux/usb/cdc.h>
/* Version Information */
-#define DRIVER_VERSION "v1.07.0 (2014/10/09)"
+#define DRIVER_VERSION "v1.08.0 (2015/01/13)"
#define DRIVER_AUTHOR "Realtek linux nic maintainers <nic_swsd@realtek.com>"
#define DRIVER_DESC "Realtek RTL8152/RTL8153 Based USB Ethernet Adapters"
#define MODULENAME "r8152"
@@ -40,6 +40,7 @@
#define PLA_RXFIFO_CTRL0 0xc0a0
#define PLA_RXFIFO_CTRL1 0xc0a4
#define PLA_RXFIFO_CTRL2 0xc0a8
+#define PLA_DMY_REG0 0xc0b0
#define PLA_FMC 0xc0b4
#define PLA_CFG_WOL 0xc0b6
#define PLA_TEREDO_CFG 0xc0bc
@@ -90,8 +91,14 @@
#define PLA_BP_7 0xfc36
#define PLA_BP_EN 0xfc38
+#define USB_USB2PHY 0xb41e
+#define USB_SSPHYLINK2 0xb428
#define USB_U2P3_CTRL 0xb460
+#define USB_CSR_DUMMY1 0xb464
+#define USB_CSR_DUMMY2 0xb466
#define USB_DEV_STAT 0xb808
+#define USB_CONNECT_TIMER 0xcbf8
+#define USB_BURST_SIZE 0xcfc0
#define USB_USB_CTRL 0xd406
#define USB_PHY_CTRL 0xd408
#define USB_TX_AGG 0xd40a
@@ -170,6 +177,9 @@
#define TXFIFO_THR_NORMAL 0x00400008
#define TXFIFO_THR_NORMAL2 0x01000008
+/* PLA_DMY_REG0 */
+#define ECM_ALDPS 0x0002
+
/* PLA_FMC */
#define FMC_FCR_MCU_EN 0x0001
@@ -289,6 +299,20 @@
/* PLA_BOOT_CTRL */
#define AUTOLOAD_DONE 0x0002
+/* USB_USB2PHY */
+#define USB2PHY_SUSPEND 0x0001
+#define USB2PHY_L1 0x0002
+
+/* USB_SSPHYLINK2 */
+#define pwd_dn_scale_mask 0x3ffe
+#define pwd_dn_scale(x) ((x) << 1)
+
+/* USB_CSR_DUMMY1 */
+#define DYNAMIC_BURST 0x0001
+
+/* USB_CSR_DUMMY2 */
+#define EP4_FULL_FC 0x0001
+
/* USB_DEV_STAT */
#define STAT_SPEED_MASK 0x0006
#define STAT_SPEED_HIGH 0x0000
@@ -334,9 +358,13 @@
#define TIMER11_EN 0x0001
/* USB_LPM_CTRL */
+/* bit 4 ~ 5: fifo empty boundary */
+#define FIFO_EMPTY_1FB 0x30 /* 0x1fb * 64 = 32448 bytes */
+/* bit 2 ~ 3: LMP timer */
#define LPM_TIMER_MASK 0x0c
#define LPM_TIMER_500MS 0x04 /* 500 ms */
#define LPM_TIMER_500US 0x0c /* 500 us */
+#define ROK_EXIT_LPM 0x02
/* USB_AFE_CTRL2 */
#define SEN_VAL_MASK 0xf800
@@ -448,6 +476,7 @@ enum rtl_register_content {
#define RTL8152_RMS (VLAN_ETH_FRAME_LEN + VLAN_HLEN)
#define RTL8153_RMS RTL8153_MAX_PACKET
#define RTL8152_TX_TIMEOUT (5 * HZ)
+#define RTL8152_NAPI_WEIGHT 64
/* rtl8152 flags */
enum rtl8152_flags {
@@ -457,7 +486,7 @@ enum rtl8152_flags {
RTL8152_LINK_CHG,
SELECTIVE_SUSPEND,
PHY_RESET,
- SCHEDULE_TASKLET,
+ SCHEDULE_NAPI,
};
/* Define these values to match your device */
@@ -488,16 +517,16 @@ struct rx_desc {
#define RX_LEN_MASK 0x7fff
__le32 opts2;
-#define RD_UDP_CS (1 << 23)
-#define RD_TCP_CS (1 << 22)
-#define RD_IPV6_CS (1 << 20)
-#define RD_IPV4_CS (1 << 19)
+#define RD_UDP_CS BIT(23)
+#define RD_TCP_CS BIT(22)
+#define RD_IPV6_CS BIT(20)
+#define RD_IPV4_CS BIT(19)
__le32 opts3;
-#define IPF (1 << 23) /* IP checksum fail */
-#define UDPF (1 << 22) /* UDP checksum fail */
-#define TCPF (1 << 21) /* TCP checksum fail */
-#define RX_VLAN_TAG (1 << 16)
+#define IPF BIT(23) /* IP checksum fail */
+#define UDPF BIT(22) /* UDP checksum fail */
+#define TCPF BIT(21) /* TCP checksum fail */
+#define RX_VLAN_TAG BIT(16)
__le32 opts4;
__le32 opts5;
@@ -506,24 +535,24 @@ struct rx_desc {
struct tx_desc {
__le32 opts1;
-#define TX_FS (1 << 31) /* First segment of a packet */
-#define TX_LS (1 << 30) /* Final segment of a packet */
-#define GTSENDV4 (1 << 28)
-#define GTSENDV6 (1 << 27)
+#define TX_FS BIT(31) /* First segment of a packet */
+#define TX_LS BIT(30) /* Final segment of a packet */
+#define GTSENDV4 BIT(28)
+#define GTSENDV6 BIT(27)
#define GTTCPHO_SHIFT 18
#define GTTCPHO_MAX 0x7fU
#define TX_LEN_MAX 0x3ffffU
__le32 opts2;
-#define UDP_CS (1 << 31) /* Calculate UDP/IP checksum */
-#define TCP_CS (1 << 30) /* Calculate TCP/IP checksum */
-#define IPV4_CS (1 << 29) /* Calculate IPv4 checksum */
-#define IPV6_CS (1 << 28) /* Calculate IPv6 checksum */
+#define UDP_CS BIT(31) /* Calculate UDP/IP checksum */
+#define TCP_CS BIT(30) /* Calculate TCP/IP checksum */
+#define IPV4_CS BIT(29) /* Calculate IPv4 checksum */
+#define IPV6_CS BIT(28) /* Calculate IPv6 checksum */
#define MSS_SHIFT 17
#define MSS_MAX 0x7ffU
#define TCPHO_SHIFT 17
#define TCPHO_MAX 0x7ffU
-#define TX_VLAN_TAG (1 << 16)
+#define TX_VLAN_TAG BIT(16)
};
struct r8152;
@@ -549,14 +578,14 @@ struct tx_agg {
struct r8152 {
unsigned long flags;
struct usb_device *udev;
- struct tasklet_struct tl;
+ struct napi_struct napi;
struct usb_interface *intf;
struct net_device *netdev;
struct urb *intr_urb;
struct tx_agg tx_info[RTL8152_MAX_TX];
struct rx_agg rx_info[RTL8152_MAX_RX];
struct list_head rx_done, tx_free;
- struct sk_buff_head tx_queue;
+ struct sk_buff_head tx_queue, rx_queue;
spinlock_t rx_lock, tx_lock;
struct delayed_work schedule;
struct mii_if_info mii;
@@ -580,7 +609,6 @@ struct r8152 {
u16 ocp_base;
u8 *intr_buff;
u8 version;
- u8 speed;
};
enum rtl_version {
@@ -1050,7 +1078,7 @@ static void read_bulk_callback(struct urb *urb)
spin_lock(&tp->rx_lock);
list_add_tail(&agg->list, &tp->rx_done);
spin_unlock(&tp->rx_lock);
- tasklet_schedule(&tp->tl);
+ napi_schedule(&tp->napi);
return;
case -ESHUTDOWN:
set_bit(RTL8152_UNPLUG, &tp->flags);
@@ -1114,7 +1142,7 @@ static void write_bulk_callback(struct urb *urb)
return;
if (!skb_queue_empty(&tp->tx_queue))
- tasklet_schedule(&tp->tl);
+ napi_schedule(&tp->napi);
}
static void intr_callback(struct urb *urb)
@@ -1156,12 +1184,12 @@ static void intr_callback(struct urb *urb)
d = urb->transfer_buffer;
if (INTR_LINK & __le16_to_cpu(d[0])) {
- if (!(tp->speed & LINK_STATUS)) {
+ if (!netif_carrier_ok(tp->netdev)) {
set_bit(RTL8152_LINK_CHG, &tp->flags);
schedule_delayed_work(&tp->schedule, 0);
}
} else {
- if (tp->speed & LINK_STATUS) {
+ if (netif_carrier_ok(tp->netdev)) {
set_bit(RTL8152_LINK_CHG, &tp->flags);
schedule_delayed_work(&tp->schedule, 0);
}
@@ -1233,6 +1261,7 @@ static int alloc_all_mem(struct r8152 *tp)
spin_lock_init(&tp->tx_lock);
INIT_LIST_HEAD(&tp->tx_free);
skb_queue_head_init(&tp->tx_queue);
+ skb_queue_head_init(&tp->rx_queue);
for (i = 0; i < RTL8152_MAX_RX; i++) {
buf = kmalloc_node(agg_buf_sz, GFP_KERNEL, node);
@@ -1329,18 +1358,6 @@ static struct tx_agg *r8152_get_tx_agg(struct r8152 *tp)
return agg;
}
-static inline __be16 get_protocol(struct sk_buff *skb)
-{
- __be16 protocol;
-
- if (skb->protocol == htons(ETH_P_8021Q))
- protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
- else
- protocol = skb->protocol;
-
- return protocol;
-}
-
/* r8152_csum_workaround()
* The hw limites the value the transport offset. When the offset is out of the
* range, calculate the checksum by sw.
@@ -1409,10 +1426,10 @@ static int msdn_giant_send_check(struct sk_buff *skb)
static inline void rtl_tx_vlan_tag(struct tx_desc *desc, struct sk_buff *skb)
{
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
u32 opts2;
- opts2 = TX_VLAN_TAG | swab16(vlan_tx_tag_get(skb));
+ opts2 = TX_VLAN_TAG | swab16(skb_vlan_tag_get(skb));
desc->opts2 |= cpu_to_le32(opts2);
}
}
@@ -1446,7 +1463,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
goto unavailable;
}
- switch (get_protocol(skb)) {
+ switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
opts1 |= GTSENDV4;
break;
@@ -1477,7 +1494,7 @@ static int r8152_tx_csum(struct r8152 *tp, struct tx_desc *desc,
goto unavailable;
}
- switch (get_protocol(skb)) {
+ switch (vlan_get_protocol(skb)) {
case htons(ETH_P_IP):
opts2 |= IPV4_CS;
ip_protocol = ip_hdr(skb)->protocol;
@@ -1637,13 +1654,32 @@ return_result:
return checksum;
}
-static void rx_bottom(struct r8152 *tp)
+static int rx_bottom(struct r8152 *tp, int budget)
{
unsigned long flags;
struct list_head *cursor, *next, rx_queue;
+ int ret = 0, work_done = 0;
+
+ if (!skb_queue_empty(&tp->rx_queue)) {
+ while (work_done < budget) {
+ struct sk_buff *skb = __skb_dequeue(&tp->rx_queue);
+ struct net_device *netdev = tp->netdev;
+ struct net_device_stats *stats = &netdev->stats;
+ unsigned int pkt_len;
+
+ if (!skb)
+ break;
+
+ pkt_len = skb->len;
+ napi_gro_receive(&tp->napi, skb);
+ work_done++;
+ stats->rx_packets++;
+ stats->rx_bytes += pkt_len;
+ }
+ }
if (list_empty(&tp->rx_done))
- return;
+ goto out1;
INIT_LIST_HEAD(&rx_queue);
spin_lock_irqsave(&tp->rx_lock, flags);
@@ -1696,9 +1732,14 @@ static void rx_bottom(struct r8152 *tp)
skb_put(skb, pkt_len);
skb->protocol = eth_type_trans(skb, netdev);
rtl_rx_vlan_tag(rx_desc, skb);
- netif_receive_skb(skb);
- stats->rx_packets++;
- stats->rx_bytes += pkt_len;
+ if (work_done < budget) {
+ napi_gro_receive(&tp->napi, skb);
+ work_done++;
+ stats->rx_packets++;
+ stats->rx_bytes += pkt_len;
+ } else {
+ __skb_queue_tail(&tp->rx_queue, skb);
+ }
find_next_rx:
rx_data = rx_agg_align(rx_data + pkt_len + CRC_SIZE);
@@ -1708,8 +1749,22 @@ find_next_rx:
}
submit:
- r8152_submit_rx(tp, agg, GFP_ATOMIC);
+ if (!ret) {
+ ret = r8152_submit_rx(tp, agg, GFP_ATOMIC);
+ } else {
+ urb->actual_length = 0;
+ list_add_tail(&agg->list, next);
+ }
}
+
+ if (!list_empty(&rx_queue)) {
+ spin_lock_irqsave(&tp->rx_lock, flags);
+ list_splice_tail(&rx_queue, &tp->rx_done);
+ spin_unlock_irqrestore(&tp->rx_lock, flags);
+ }
+
+out1:
+ return work_done;
}
static void tx_bottom(struct r8152 *tp)
@@ -1749,12 +1804,8 @@ static void tx_bottom(struct r8152 *tp)
} while (res == 0);
}
-static void bottom_half(unsigned long data)
+static void bottom_half(struct r8152 *tp)
{
- struct r8152 *tp;
-
- tp = (struct r8152 *)data;
-
if (test_bit(RTL8152_UNPLUG, &tp->flags))
return;
@@ -1766,17 +1817,38 @@ static void bottom_half(unsigned long data)
if (!netif_carrier_ok(tp->netdev))
return;
- clear_bit(SCHEDULE_TASKLET, &tp->flags);
+ clear_bit(SCHEDULE_NAPI, &tp->flags);
- rx_bottom(tp);
tx_bottom(tp);
}
+static int r8152_poll(struct napi_struct *napi, int budget)
+{
+ struct r8152 *tp = container_of(napi, struct r8152, napi);
+ int work_done;
+
+ work_done = rx_bottom(tp, budget);
+ bottom_half(tp);
+
+ if (work_done < budget) {
+ napi_complete(napi);
+ if (!list_empty(&tp->rx_done))
+ napi_schedule(napi);
+ }
+
+ return work_done;
+}
+
static
int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
{
int ret;
+ /* The rx would be stopped, so skip submitting */
+ if (test_bit(RTL8152_UNPLUG, &tp->flags) ||
+ !test_bit(WORK_ENABLE, &tp->flags) || !netif_carrier_ok(tp->netdev))
+ return 0;
+
usb_fill_bulk_urb(agg->urb, tp->udev, usb_rcvbulkpipe(tp->udev, 1),
agg->head, agg_buf_sz,
(usb_complete_t)read_bulk_callback, agg);
@@ -1793,7 +1865,11 @@ int r8152_submit_rx(struct r8152 *tp, struct rx_agg *agg, gfp_t mem_flags)
spin_lock_irqsave(&tp->rx_lock, flags);
list_add_tail(&agg->list, &tp->rx_done);
spin_unlock_irqrestore(&tp->rx_lock, flags);
- tasklet_schedule(&tp->tl);
+
+ netif_err(tp, rx_err, tp->netdev,
+ "Couldn't submit rx[%p], ret = %d\n", agg, ret);
+
+ napi_schedule(&tp->napi);
}
return ret;
@@ -1833,7 +1909,7 @@ static void rtl8152_set_rx_mode(struct net_device *netdev)
{
struct r8152 *tp = netdev_priv(netdev);
- if (tp->speed & LINK_STATUS) {
+ if (netif_carrier_ok(netdev)) {
set_bit(RTL8152_SET_RX_MODE, &tp->flags);
schedule_delayed_work(&tp->schedule, 0);
}
@@ -1912,11 +1988,11 @@ static netdev_tx_t rtl8152_start_xmit(struct sk_buff *skb,
if (!list_empty(&tp->tx_free)) {
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
- set_bit(SCHEDULE_TASKLET, &tp->flags);
+ set_bit(SCHEDULE_NAPI, &tp->flags);
schedule_delayed_work(&tp->schedule, 0);
} else {
usb_mark_last_busy(tp->udev);
- tasklet_schedule(&tp->tl);
+ napi_schedule(&tp->napi);
}
} else if (skb_queue_len(&tp->tx_queue) > tp->tx_qlen) {
netif_stop_queue(netdev);
@@ -1995,6 +2071,7 @@ static int rtl_start_rx(struct r8152 *tp)
{
int i, ret = 0;
+ napi_disable(&tp->napi);
INIT_LIST_HEAD(&tp->rx_done);
for (i = 0; i < RTL8152_MAX_RX; i++) {
INIT_LIST_HEAD(&tp->rx_info[i].list);
@@ -2002,6 +2079,7 @@ static int rtl_start_rx(struct r8152 *tp)
if (ret)
break;
}
+ napi_enable(&tp->napi);
if (ret && ++i < RTL8152_MAX_RX) {
struct list_head rx_queue;
@@ -2032,6 +2110,9 @@ static int rtl_stop_rx(struct r8152 *tp)
for (i = 0; i < RTL8152_MAX_RX; i++)
usb_kill_urb(tp->rx_info[i].urb);
+ while (!skb_queue_empty(&tp->rx_queue))
+ dev_kfree_skb(__skb_dequeue(&tp->rx_queue));
+
return 0;
}
@@ -2047,7 +2128,7 @@ static int rtl_enable(struct r8152 *tp)
rxdy_gated_en(tp, false);
- return rtl_start_rx(tp);
+ return 0;
}
static int rtl8152_enable(struct r8152 *tp)
@@ -2852,20 +2933,20 @@ static void set_carrier(struct r8152 *tp)
speed = rtl8152_get_speed(tp);
if (speed & LINK_STATUS) {
- if (!(tp->speed & LINK_STATUS)) {
+ if (!netif_carrier_ok(netdev)) {
tp->rtl_ops.enable(tp);
set_bit(RTL8152_SET_RX_MODE, &tp->flags);
netif_carrier_on(netdev);
+ rtl_start_rx(tp);
}
} else {
- if (tp->speed & LINK_STATUS) {
+ if (netif_carrier_ok(netdev)) {
netif_carrier_off(netdev);
- tasklet_disable(&tp->tl);
+ napi_disable(&tp->napi);
tp->rtl_ops.disable(tp);
- tasklet_enable(&tp->tl);
+ napi_enable(&tp->napi);
}
}
- tp->speed = speed;
}
static void rtl_work_func_t(struct work_struct *work)
@@ -2895,10 +2976,11 @@ static void rtl_work_func_t(struct work_struct *work)
if (test_bit(RTL8152_SET_RX_MODE, &tp->flags))
_rtl8152_set_rx_mode(tp->netdev);
- if (test_bit(SCHEDULE_TASKLET, &tp->flags) &&
- (tp->speed & LINK_STATUS)) {
- clear_bit(SCHEDULE_TASKLET, &tp->flags);
- tasklet_schedule(&tp->tl);
+ /* don't schedule napi before linking */
+ if (test_bit(SCHEDULE_NAPI, &tp->flags) &&
+ netif_carrier_ok(tp->netdev)) {
+ clear_bit(SCHEDULE_NAPI, &tp->flags);
+ napi_schedule(&tp->napi);
}
if (test_bit(PHY_RESET, &tp->flags))
@@ -2919,8 +3001,7 @@ static int rtl8152_open(struct net_device *netdev)
if (res)
goto out;
- /* set speed to 0 to avoid autoresume try to submit rx */
- tp->speed = 0;
+ netif_carrier_off(netdev);
res = usb_autopm_get_interface(tp->intf);
if (res < 0) {
@@ -2937,7 +3018,7 @@ static int rtl8152_open(struct net_device *netdev)
cancel_delayed_work_sync(&tp->schedule);
/* disable the tx/rx, if the workqueue has enabled them. */
- if (tp->speed & LINK_STATUS)
+ if (netif_carrier_ok(netdev))
tp->rtl_ops.disable(tp);
}
@@ -2946,7 +3027,6 @@ static int rtl8152_open(struct net_device *netdev)
rtl8152_set_speed(tp, AUTONEG_ENABLE,
tp->mii.supports_gmii ? SPEED_1000 : SPEED_100,
DUPLEX_FULL);
- tp->speed = 0;
netif_carrier_off(netdev);
netif_start_queue(netdev);
set_bit(WORK_ENABLE, &tp->flags);
@@ -2959,7 +3039,7 @@ static int rtl8152_open(struct net_device *netdev)
res);
free_all_mem(tp);
} else {
- tasklet_enable(&tp->tl);
+ napi_enable(&tp->napi);
}
mutex_unlock(&tp->control);
@@ -2975,15 +3055,16 @@ static int rtl8152_close(struct net_device *netdev)
struct r8152 *tp = netdev_priv(netdev);
int res = 0;
- tasklet_disable(&tp->tl);
+ napi_disable(&tp->napi);
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
cancel_delayed_work_sync(&tp->schedule);
netif_stop_queue(netdev);
res = usb_autopm_get_interface(tp->intf);
- if (res < 0) {
+ if (res < 0 || test_bit(RTL8152_UNPLUG, &tp->flags)) {
rtl_drop_queued_tx(tp);
+ rtl_stop_rx(tp);
} else {
mutex_lock(&tp->control);
@@ -3177,6 +3258,32 @@ static void r8153_init(struct r8152 *tp)
r8153_u2p3en(tp, false);
+ if (tp->version == RTL_VER_04) {
+ ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2);
+ ocp_data &= ~pwd_dn_scale_mask;
+ ocp_data |= pwd_dn_scale(96);
+ ocp_write_word(tp, MCU_TYPE_USB, USB_SSPHYLINK2, ocp_data);
+
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_USB2PHY);
+ ocp_data |= USB2PHY_L1 | USB2PHY_SUSPEND;
+ ocp_write_byte(tp, MCU_TYPE_USB, USB_USB2PHY, ocp_data);
+ } else if (tp->version == RTL_VER_05) {
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0);
+ ocp_data &= ~ECM_ALDPS;
+ ocp_write_byte(tp, MCU_TYPE_PLA, PLA_DMY_REG0, ocp_data);
+
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1);
+ if (ocp_read_word(tp, MCU_TYPE_USB, USB_BURST_SIZE) == 0)
+ ocp_data &= ~DYNAMIC_BURST;
+ else
+ ocp_data |= DYNAMIC_BURST;
+ ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY1, ocp_data);
+ }
+
+ ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2);
+ ocp_data |= EP4_FULL_FC;
+ ocp_write_byte(tp, MCU_TYPE_USB, USB_CSR_DUMMY2, ocp_data);
+
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL);
ocp_data &= ~TIMER11_EN;
ocp_write_word(tp, MCU_TYPE_USB, USB_WDT11_CTRL, ocp_data);
@@ -3185,12 +3292,11 @@ static void r8153_init(struct r8152 *tp)
ocp_data &= ~LED_MODE_MASK;
ocp_write_word(tp, MCU_TYPE_PLA, PLA_LED_FEATURE, ocp_data);
- ocp_data = ocp_read_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL);
- ocp_data &= ~LPM_TIMER_MASK;
- if (tp->udev->speed == USB_SPEED_SUPER)
- ocp_data |= LPM_TIMER_500US;
- else
+ ocp_data = FIFO_EMPTY_1FB | ROK_EXIT_LPM;
+ if (tp->version == RTL_VER_04 && tp->udev->speed != USB_SPEED_SUPER)
ocp_data |= LPM_TIMER_500MS;
+ else
+ ocp_data |= LPM_TIMER_500US;
ocp_write_byte(tp, MCU_TYPE_USB, USB_LPM_CTRL, ocp_data);
ocp_data = ocp_read_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2);
@@ -3198,6 +3304,8 @@ static void r8153_init(struct r8152 *tp)
ocp_data |= SEN_VAL_NORMAL | SEL_RXIDLE;
ocp_write_word(tp, MCU_TYPE_USB, USB_AFE_CTRL2, ocp_data);
+ ocp_write_word(tp, MCU_TYPE_USB, USB_CONNECT_TIMER, 0x0001);
+
r8153_power_cut_en(tp, false);
r8153_u1u2en(tp, true);
@@ -3239,7 +3347,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
if (netif_running(netdev) && test_bit(WORK_ENABLE, &tp->flags)) {
clear_bit(WORK_ENABLE, &tp->flags);
usb_kill_urb(tp->intr_urb);
- tasklet_disable(&tp->tl);
+ napi_disable(&tp->napi);
if (test_bit(SELECTIVE_SUSPEND, &tp->flags)) {
rtl_stop_rx(tp);
rtl_runtime_suspend_enable(tp, true);
@@ -3247,7 +3355,7 @@ static int rtl8152_suspend(struct usb_interface *intf, pm_message_t message)
cancel_delayed_work_sync(&tp->schedule);
tp->rtl_ops.down(tp);
}
- tasklet_enable(&tp->tl);
+ napi_enable(&tp->napi);
}
out1:
mutex_unlock(&tp->control);
@@ -3271,7 +3379,7 @@ static int rtl8152_resume(struct usb_interface *intf)
rtl_runtime_suspend_enable(tp, false);
clear_bit(SELECTIVE_SUSPEND, &tp->flags);
set_bit(WORK_ENABLE, &tp->flags);
- if (tp->speed & LINK_STATUS)
+ if (netif_carrier_ok(tp->netdev))
rtl_start_rx(tp);
} else {
tp->rtl_ops.up(tp);
@@ -3279,7 +3387,6 @@ static int rtl8152_resume(struct usb_interface *intf)
tp->mii.supports_gmii ?
SPEED_1000 : SPEED_100,
DUPLEX_FULL);
- tp->speed = 0;
netif_carrier_off(tp->netdev);
set_bit(WORK_ENABLE, &tp->flags);
}
@@ -3831,7 +3938,6 @@ static int rtl8152_probe(struct usb_interface *intf,
if (ret)
goto out;
- tasklet_init(&tp->tl, bottom_half, (unsigned long)tp);
mutex_init(&tp->control);
INIT_DELAYED_WORK(&tp->schedule, rtl_work_func_t);
@@ -3845,8 +3951,7 @@ static int rtl8152_probe(struct usb_interface *intf,
netdev->hw_features = NETIF_F_RXCSUM | NETIF_F_IP_CSUM | NETIF_F_SG |
NETIF_F_TSO | NETIF_F_FRAGLIST |
NETIF_F_IPV6_CSUM | NETIF_F_TSO6 |
- NETIF_F_HW_VLAN_CTAG_RX |
- NETIF_F_HW_VLAN_CTAG_TX;
+ NETIF_F_HW_VLAN_CTAG_RX | NETIF_F_HW_VLAN_CTAG_TX;
netdev->vlan_features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO |
NETIF_F_HIGHDMA | NETIF_F_FRAGLIST |
NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
@@ -3867,6 +3972,7 @@ static int rtl8152_probe(struct usb_interface *intf,
set_ethernet_addr(tp);
usb_set_intfdata(intf, tp);
+ netif_napi_add(netdev, &tp->napi, r8152_poll, RTL8152_NAPI_WEIGHT);
ret = register_netdev(netdev);
if (ret != 0) {
@@ -3880,15 +3986,13 @@ static int rtl8152_probe(struct usb_interface *intf,
else
device_set_wakeup_enable(&udev->dev, false);
- tasklet_disable(&tp->tl);
-
netif_info(tp, probe, netdev, "%s\n", DRIVER_VERSION);
return 0;
out1:
+ netif_napi_del(&tp->napi);
usb_set_intfdata(intf, NULL);
- tasklet_kill(&tp->tl);
out:
free_netdev(netdev);
return ret;
@@ -3905,7 +4009,7 @@ static void rtl8152_disconnect(struct usb_interface *intf)
if (udev->state == USB_STATE_NOTATTACHED)
set_bit(RTL8152_UNPLUG, &tp->flags);
- tasklet_kill(&tp->tl);
+ netif_napi_del(&tp->napi);
unregister_netdev(tp->netdev);
tp->rtl_ops.unload(tp);
free_netdev(tp->netdev);
diff --git a/drivers/net/usb/sr9700.c b/drivers/net/usb/sr9700.c
index 99b69af14274..4a1e9c489f1f 100644
--- a/drivers/net/usb/sr9700.c
+++ b/drivers/net/usb/sr9700.c
@@ -77,7 +77,7 @@ static int wait_phy_eeprom_ready(struct usbnet *dev, int phy)
int ret;
udelay(1);
- ret = sr_read_reg(dev, EPCR, &tmp);
+ ret = sr_read_reg(dev, SR_EPCR, &tmp);
if (ret < 0)
return ret;
@@ -98,15 +98,15 @@ static int sr_share_read_word(struct usbnet *dev, int phy, u8 reg,
mutex_lock(&dev->phy_mutex);
- sr_write_reg(dev, EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
- sr_write_reg(dev, EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
+ sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
+ sr_write_reg(dev, SR_EPCR, phy ? (EPCR_EPOS | EPCR_ERPRR) : EPCR_ERPRR);
ret = wait_phy_eeprom_ready(dev, phy);
if (ret < 0)
goto out_unlock;
- sr_write_reg(dev, EPCR, 0x0);
- ret = sr_read(dev, EPDR, 2, value);
+ sr_write_reg(dev, SR_EPCR, 0x0);
+ ret = sr_read(dev, SR_EPDR, 2, value);
netdev_dbg(dev->net, "read shared %d 0x%02x returned 0x%04x, %d\n",
phy, reg, *value, ret);
@@ -123,19 +123,19 @@ static int sr_share_write_word(struct usbnet *dev, int phy, u8 reg,
mutex_lock(&dev->phy_mutex);
- ret = sr_write(dev, EPDR, 2, &value);
+ ret = sr_write(dev, SR_EPDR, 2, &value);
if (ret < 0)
goto out_unlock;
- sr_write_reg(dev, EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
- sr_write_reg(dev, EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) :
+ sr_write_reg(dev, SR_EPAR, phy ? (reg | EPAR_PHY_ADR) : reg);
+ sr_write_reg(dev, SR_EPCR, phy ? (EPCR_WEP | EPCR_EPOS | EPCR_ERPRW) :
(EPCR_WEP | EPCR_ERPRW));
ret = wait_phy_eeprom_ready(dev, phy);
if (ret < 0)
goto out_unlock;
- sr_write_reg(dev, EPCR, 0x0);
+ sr_write_reg(dev, SR_EPCR, 0x0);
out_unlock:
mutex_unlock(&dev->phy_mutex);
@@ -188,7 +188,7 @@ static int sr_mdio_read(struct net_device *netdev, int phy_id, int loc)
if (loc == MII_BMSR) {
u8 value;
- sr_read_reg(dev, NSR, &value);
+ sr_read_reg(dev, SR_NSR, &value);
if (value & NSR_LINKST)
rc = 1;
}
@@ -228,7 +228,7 @@ static u32 sr9700_get_link(struct net_device *netdev)
int rc = 0;
/* Get the Link Status directly */
- sr_read_reg(dev, NSR, &value);
+ sr_read_reg(dev, SR_NSR, &value);
if (value & NSR_LINKST)
rc = 1;
@@ -281,8 +281,8 @@ static void sr9700_set_multicast(struct net_device *netdev)
}
}
- sr_write_async(dev, MAR, SR_MCAST_SIZE, hashes);
- sr_write_reg_async(dev, RCR, rx_ctl);
+ sr_write_async(dev, SR_MAR, SR_MCAST_SIZE, hashes);
+ sr_write_reg_async(dev, SR_RCR, rx_ctl);
}
static int sr9700_set_mac_address(struct net_device *netdev, void *p)
@@ -297,7 +297,7 @@ static int sr9700_set_mac_address(struct net_device *netdev, void *p)
}
memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
- sr_write_async(dev, PAR, 6, netdev->dev_addr);
+ sr_write_async(dev, SR_PAR, 6, netdev->dev_addr);
return 0;
}
@@ -340,7 +340,7 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
mii->phy_id_mask = 0x1f;
mii->reg_num_mask = 0x1f;
- sr_write_reg(dev, NCR, NCR_RST);
+ sr_write_reg(dev, SR_NCR, NCR_RST);
udelay(20);
/* read MAC
@@ -348,17 +348,17 @@ static int sr9700_bind(struct usbnet *dev, struct usb_interface *intf)
* EEPROM automatically to PAR. In case there is no EEPROM externally,
* a default MAC address is stored in PAR for making chip work properly.
*/
- if (sr_read(dev, PAR, ETH_ALEN, netdev->dev_addr) < 0) {
+ if (sr_read(dev, SR_PAR, ETH_ALEN, netdev->dev_addr) < 0) {
netdev_err(netdev, "Error reading MAC address\n");
ret = -ENODEV;
goto out;
}
/* power up and reset phy */
- sr_write_reg(dev, PRR, PRR_PHY_RST);
+ sr_write_reg(dev, SR_PRR, PRR_PHY_RST);
/* at least 10ms, here 20ms for safe */
mdelay(20);
- sr_write_reg(dev, PRR, 0);
+ sr_write_reg(dev, SR_PRR, 0);
/* at least 1ms, here 2ms for reading right register */
udelay(2 * 1000);
diff --git a/drivers/net/usb/sr9700.h b/drivers/net/usb/sr9700.h
index fd687c575e74..258b030277e7 100644
--- a/drivers/net/usb/sr9700.h
+++ b/drivers/net/usb/sr9700.h
@@ -14,13 +14,13 @@
/* sr9700 spec. register table on Linux platform */
/* Network Control Reg */
-#define NCR 0x00
+#define SR_NCR 0x00
#define NCR_RST (1 << 0)
#define NCR_LBK (3 << 1)
#define NCR_FDX (1 << 3)
#define NCR_WAKEEN (1 << 6)
/* Network Status Reg */
-#define NSR 0x01
+#define SR_NSR 0x01
#define NSR_RXRDY (1 << 0)
#define NSR_RXOV (1 << 1)
#define NSR_TX1END (1 << 2)
@@ -30,7 +30,7 @@
#define NSR_LINKST (1 << 6)
#define NSR_SPEED (1 << 7)
/* Tx Control Reg */
-#define TCR 0x02
+#define SR_TCR 0x02
#define TCR_CRC_DIS (1 << 1)
#define TCR_PAD_DIS (1 << 2)
#define TCR_LC_CARE (1 << 3)
@@ -38,7 +38,7 @@
#define TCR_EXCECM (1 << 5)
#define TCR_LF_EN (1 << 6)
/* Tx Status Reg for Packet Index 1 */
-#define TSR1 0x03
+#define SR_TSR1 0x03
#define TSR1_EC (1 << 2)
#define TSR1_COL (1 << 3)
#define TSR1_LC (1 << 4)
@@ -46,7 +46,7 @@
#define TSR1_LOC (1 << 6)
#define TSR1_TLF (1 << 7)
/* Tx Status Reg for Packet Index 2 */
-#define TSR2 0x04
+#define SR_TSR2 0x04
#define TSR2_EC (1 << 2)
#define TSR2_COL (1 << 3)
#define TSR2_LC (1 << 4)
@@ -54,7 +54,7 @@
#define TSR2_LOC (1 << 6)
#define TSR2_TLF (1 << 7)
/* Rx Control Reg*/
-#define RCR 0x05
+#define SR_RCR 0x05
#define RCR_RXEN (1 << 0)
#define RCR_PRMSC (1 << 1)
#define RCR_RUNT (1 << 2)
@@ -62,87 +62,87 @@
#define RCR_DIS_CRC (1 << 4)
#define RCR_DIS_LONG (1 << 5)
/* Rx Status Reg */
-#define RSR 0x06
+#define SR_RSR 0x06
#define RSR_AE (1 << 2)
#define RSR_MF (1 << 6)
#define RSR_RF (1 << 7)
/* Rx Overflow Counter Reg */
-#define ROCR 0x07
+#define SR_ROCR 0x07
#define ROCR_ROC (0x7F << 0)
#define ROCR_RXFU (1 << 7)
/* Back Pressure Threshold Reg */
-#define BPTR 0x08
+#define SR_BPTR 0x08
#define BPTR_JPT (0x0F << 0)
#define BPTR_BPHW (0x0F << 4)
/* Flow Control Threshold Reg */
-#define FCTR 0x09
+#define SR_FCTR 0x09
#define FCTR_LWOT (0x0F << 0)
#define FCTR_HWOT (0x0F << 4)
/* rx/tx Flow Control Reg */
-#define FCR 0x0A
+#define SR_FCR 0x0A
#define FCR_FLCE (1 << 0)
#define FCR_BKPA (1 << 4)
#define FCR_TXPEN (1 << 5)
#define FCR_TXPF (1 << 6)
#define FCR_TXP0 (1 << 7)
/* Eeprom & Phy Control Reg */
-#define EPCR 0x0B
+#define SR_EPCR 0x0B
#define EPCR_ERRE (1 << 0)
#define EPCR_ERPRW (1 << 1)
#define EPCR_ERPRR (1 << 2)
#define EPCR_EPOS (1 << 3)
#define EPCR_WEP (1 << 4)
/* Eeprom & Phy Address Reg */
-#define EPAR 0x0C
+#define SR_EPAR 0x0C
#define EPAR_EROA (0x3F << 0)
#define EPAR_PHY_ADR_MASK (0x03 << 6)
#define EPAR_PHY_ADR (0x01 << 6)
/* Eeprom & Phy Data Reg */
-#define EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */
+#define SR_EPDR 0x0D /* 0x0D ~ 0x0E for Data Reg Low & High */
/* Wakeup Control Reg */
-#define WCR 0x0F
+#define SR_WCR 0x0F
#define WCR_MAGICST (1 << 0)
#define WCR_LINKST (1 << 2)
#define WCR_MAGICEN (1 << 3)
#define WCR_LINKEN (1 << 5)
/* Physical Address Reg */
-#define PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */
+#define SR_PAR 0x10 /* 0x10 ~ 0x15 6 bytes for PAR */
/* Multicast Address Reg */
-#define MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */
+#define SR_MAR 0x16 /* 0x16 ~ 0x1D 8 bytes for MAR */
/* 0x1e unused */
/* Phy Reset Reg */
-#define PRR 0x1F
+#define SR_PRR 0x1F
#define PRR_PHY_RST (1 << 0)
/* Tx sdram Write Pointer Address Low */
-#define TWPAL 0x20
+#define SR_TWPAL 0x20
/* Tx sdram Write Pointer Address High */
-#define TWPAH 0x21
+#define SR_TWPAH 0x21
/* Tx sdram Read Pointer Address Low */
-#define TRPAL 0x22
+#define SR_TRPAL 0x22
/* Tx sdram Read Pointer Address High */
-#define TRPAH 0x23
+#define SR_TRPAH 0x23
/* Rx sdram Write Pointer Address Low */
-#define RWPAL 0x24
+#define SR_RWPAL 0x24
/* Rx sdram Write Pointer Address High */
-#define RWPAH 0x25
+#define SR_RWPAH 0x25
/* Rx sdram Read Pointer Address Low */
-#define RRPAL 0x26
+#define SR_RRPAL 0x26
/* Rx sdram Read Pointer Address High */
-#define RRPAH 0x27
+#define SR_RRPAH 0x27
/* Vendor ID register */
-#define VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */
+#define SR_VID 0x28 /* 0x28 ~ 0x29 2 bytes for VID */
/* Product ID register */
-#define PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */
+#define SR_PID 0x2A /* 0x2A ~ 0x2B 2 bytes for PID */
/* CHIP Revision register */
-#define CHIPR 0x2C
+#define SR_CHIPR 0x2C
/* 0x2D --> 0xEF unused */
/* USB Device Address */
-#define USBDA 0xF0
+#define SR_USBDA 0xF0
#define USBDA_USBFA (0x7F << 0)
/* RX packet Counter Reg */
-#define RXC 0xF1
+#define SR_RXC 0xF1
/* Tx packet Counter & USB Status Reg */
-#define TXC_USBS 0xF2
+#define SR_TXC_USBS 0xF2
#define TXC_USBS_TXC0 (1 << 0)
#define TXC_USBS_TXC1 (1 << 1)
#define TXC_USBS_TXC2 (1 << 2)
@@ -150,7 +150,7 @@
#define TXC_USBS_SUSFLAG (1 << 6)
#define TXC_USBS_RXFAULT (1 << 7)
/* USB Control register */
-#define USBC 0xF4
+#define SR_USBC 0xF4
#define USBC_EP3NAK (1 << 4)
#define USBC_EP3ACK (1 << 5)
diff --git a/drivers/net/usb/usbnet.c b/drivers/net/usb/usbnet.c
index 3a6770a65d78..449835f4331e 100644
--- a/drivers/net/usb/usbnet.c
+++ b/drivers/net/usb/usbnet.c
@@ -160,20 +160,19 @@ EXPORT_SYMBOL_GPL(usbnet_get_endpoints);
int usbnet_get_ethernet_addr(struct usbnet *dev, int iMACAddress)
{
- int tmp, i;
+ int tmp = -1, ret;
unsigned char buf [13];
- tmp = usb_string(dev->udev, iMACAddress, buf, sizeof buf);
- if (tmp != 12) {
+ ret = usb_string(dev->udev, iMACAddress, buf, sizeof buf);
+ if (ret == 12)
+ tmp = hex2bin(dev->net->dev_addr, buf, 6);
+ if (tmp < 0) {
dev_dbg(&dev->udev->dev,
"bad MAC string %d fetch, %d\n", iMACAddress, tmp);
- if (tmp >= 0)
- tmp = -EINVAL;
- return tmp;
+ if (ret >= 0)
+ ret = -EINVAL;
+ return ret;
}
- for (i = tmp = 0; i < 6; i++, tmp += 2)
- dev->net->dev_addr [i] =
- (hex_to_bin(buf[tmp]) << 4) + hex_to_bin(buf[tmp + 1]);
return 0;
}
EXPORT_SYMBOL_GPL(usbnet_get_ethernet_addr);
diff --git a/drivers/net/veth.c b/drivers/net/veth.c
index 8ad596573d17..4cca36ebc4fb 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth.c
@@ -469,6 +469,14 @@ static const struct nla_policy veth_policy[VETH_INFO_MAX + 1] = {
[VETH_INFO_PEER] = { .len = sizeof(struct ifinfomsg) },
};
+static struct net *veth_get_link_net(const struct net_device *dev)
+{
+ struct veth_priv *priv = netdev_priv(dev);
+ struct net_device *peer = rtnl_dereference(priv->peer);
+
+ return peer ? dev_net(peer) : dev_net(dev);
+}
+
static struct rtnl_link_ops veth_link_ops = {
.kind = DRV_NAME,
.priv_size = sizeof(struct veth_priv),
@@ -478,6 +486,7 @@ static struct rtnl_link_ops veth_link_ops = {
.dellink = veth_dellink,
.policy = veth_policy,
.maxtype = VETH_INFO_MAX,
+ .get_link_net = veth_get_link_net,
};
/*
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index 5ca97713bfb3..f1ff3666f090 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -490,17 +490,8 @@ static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV4;
break;
case VIRTIO_NET_HDR_GSO_UDP:
- {
- static bool warned;
-
- if (!warned) {
- warned = true;
- netdev_warn(dev,
- "host using disabled UFO feature; please fix it\n");
- }
skb_shinfo(skb)->gso_type = SKB_GSO_UDP;
break;
- }
case VIRTIO_NET_HDR_GSO_TCPV6:
skb_shinfo(skb)->gso_type = SKB_GSO_TCPV6;
break;
@@ -888,6 +879,8 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV6;
+ else if (skb_shinfo(skb)->gso_type & SKB_GSO_UDP)
+ hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_UDP;
else
BUG();
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCP_ECN)
@@ -925,6 +918,9 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
/* Free up any pending old buffers before queueing new ones. */
free_old_xmit_skbs(sq);
+ /* timestamp packet in software */
+ skb_tx_timestamp(skb);
+
/* Try to transmit */
err = xmit_skb(sq, skb);
@@ -1376,6 +1372,7 @@ static const struct ethtool_ops virtnet_ethtool_ops = {
.get_ringparam = virtnet_get_ringparam,
.set_channels = virtnet_set_channels,
.get_channels = virtnet_get_channels,
+ .get_ts_info = ethtool_op_get_ts_info,
};
#define MIN_MTU 68
@@ -1713,6 +1710,12 @@ static int virtnet_probe(struct virtio_device *vdev)
struct virtnet_info *vi;
u16 max_queue_pairs;
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
if (!virtnet_validate_features(vdev))
return -EINVAL;
@@ -1748,7 +1751,7 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->features |= NETIF_F_HW_CSUM|NETIF_F_SG|NETIF_F_FRAGLIST;
if (virtio_has_feature(vdev, VIRTIO_NET_F_GSO)) {
- dev->hw_features |= NETIF_F_TSO
+ dev->hw_features |= NETIF_F_TSO | NETIF_F_UFO
| NETIF_F_TSO_ECN | NETIF_F_TSO6;
}
/* Individual feature bits: what can host handle? */
@@ -1758,9 +1761,13 @@ static int virtnet_probe(struct virtio_device *vdev)
dev->hw_features |= NETIF_F_TSO6;
if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_ECN))
dev->hw_features |= NETIF_F_TSO_ECN;
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_HOST_UFO))
+ dev->hw_features |= NETIF_F_UFO;
+
+ dev->features |= NETIF_F_GSO_ROBUST;
if (gso)
- dev->features |= dev->hw_features & NETIF_F_ALL_TSO;
+ dev->features |= dev->hw_features & (NETIF_F_ALL_TSO|NETIF_F_UFO);
/* (!csum && gso) case will be fixed by register_netdev() */
}
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_CSUM))
@@ -1798,7 +1805,8 @@ static int virtnet_probe(struct virtio_device *vdev)
/* If we can receive ANY GSO packets, we must allocate large ones. */
if (virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO4) ||
virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_TSO6) ||
- virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN))
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_ECN) ||
+ virtio_has_feature(vdev, VIRTIO_NET_F_GUEST_UFO))
vi->big_packets = true;
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
@@ -1994,9 +2002,9 @@ static struct virtio_device_id id_table[] = {
static unsigned int features[] = {
VIRTIO_NET_F_CSUM, VIRTIO_NET_F_GUEST_CSUM,
VIRTIO_NET_F_GSO, VIRTIO_NET_F_MAC,
- VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6,
+ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_HOST_TSO6,
VIRTIO_NET_F_HOST_ECN, VIRTIO_NET_F_GUEST_TSO4, VIRTIO_NET_F_GUEST_TSO6,
- VIRTIO_NET_F_GUEST_ECN,
+ VIRTIO_NET_F_GUEST_ECN, VIRTIO_NET_F_GUEST_UFO,
VIRTIO_NET_F_MRG_RXBUF, VIRTIO_NET_F_STATUS, VIRTIO_NET_F_CTRL_VQ,
VIRTIO_NET_F_CTRL_RX, VIRTIO_NET_F_CTRL_VLAN,
VIRTIO_NET_F_GUEST_ANNOUNCE, VIRTIO_NET_F_MQ,
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index 4d84912c99ba..3718d024f638 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -342,6 +342,7 @@ union Vmxnet3_GenericDesc {
#define VMXNET3_TX_RING_MAX_SIZE 4096
#define VMXNET3_TC_RING_MAX_SIZE 4096
#define VMXNET3_RX_RING_MAX_SIZE 4096
+#define VMXNET3_RX_RING2_MAX_SIZE 2048
#define VMXNET3_RC_RING_MAX_SIZE 8192
/* a list of reasons for queue stop */
@@ -392,7 +393,7 @@ struct Vmxnet3_DriverInfo {
};
-#define VMXNET3_REV1_MAGIC 0xbabefee1
+#define VMXNET3_REV1_MAGIC 3133079265u
/*
* QueueDescPA must be 128 bytes aligned. It points to an array of
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index afd295348ddb..294214c15292 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -1038,9 +1038,9 @@ vmxnet3_tq_xmit(struct sk_buff *skb, struct vmxnet3_tx_queue *tq,
le32_add_cpu(&tq->shared->txNumDeferred, 1);
}
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
gdesc->txd.ti = 1;
- gdesc->txd.tci = vlan_tx_tag_get(skb);
+ gdesc->txd.tci = skb_vlan_tag_get(skb);
}
/* finally flips the GEN bit of the SOP desc. */
@@ -2505,6 +2505,9 @@ vmxnet3_adjust_rx_ring_size(struct vmxnet3_adapter *adapter)
ring0_size = min_t(u32, ring0_size, VMXNET3_RX_RING_MAX_SIZE /
sz * sz);
ring1_size = adapter->rx_queue[0].rx_ring[1].size;
+ ring1_size = (ring1_size + sz - 1) / sz * sz;
+ ring1_size = min_t(u32, ring1_size, VMXNET3_RX_RING2_MAX_SIZE /
+ sz * sz);
comp_size = ring0_size + ring1_size;
for (i = 0; i < adapter->num_rx_queues; i++) {
@@ -2585,7 +2588,7 @@ vmxnet3_open(struct net_device *netdev)
err = vmxnet3_create_queues(adapter, adapter->tx_ring_size,
adapter->rx_ring_size,
- VMXNET3_DEF_RX_RING_SIZE);
+ adapter->rx_ring2_size);
if (err)
goto queue_err;
@@ -2964,6 +2967,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
adapter->tx_ring_size = VMXNET3_DEF_TX_RING_SIZE;
adapter->rx_ring_size = VMXNET3_DEF_RX_RING_SIZE;
+ adapter->rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE;
spin_lock_init(&adapter->cmd_lock);
adapter->adapter_pa = dma_map_single(&adapter->pdev->dev, adapter,
@@ -3286,27 +3290,15 @@ skip_arp:
static int
vmxnet3_resume(struct device *device)
{
- int err, i = 0;
+ int err;
unsigned long flags;
struct pci_dev *pdev = to_pci_dev(device);
struct net_device *netdev = pci_get_drvdata(pdev);
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- struct Vmxnet3_PMConf *pmConf;
if (!netif_running(netdev))
return 0;
- /* Destroy wake-up filters. */
- pmConf = adapter->pm_conf;
- memset(pmConf, 0, sizeof(*pmConf));
-
- adapter->shared->devRead.pmConfDesc.confVer = cpu_to_le32(1);
- adapter->shared->devRead.pmConfDesc.confLen = cpu_to_le32(sizeof(
- *pmConf));
- adapter->shared->devRead.pmConfDesc.confPA =
- cpu_to_le64(adapter->pm_conf_pa);
-
- netif_device_attach(netdev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
err = pci_enable_device_mem(pdev);
@@ -3315,15 +3307,31 @@ vmxnet3_resume(struct device *device)
pci_enable_wake(pdev, PCI_D0, 0);
+ vmxnet3_alloc_intr_resources(adapter);
+
+ /* During hibernate and suspend, device has to be reinitialized as the
+ * device state need not be preserved.
+ */
+
+ /* Need not check adapter state as other reset tasks cannot run during
+ * device resume.
+ */
spin_lock_irqsave(&adapter->cmd_lock, flags);
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD,
- VMXNET3_CMD_UPDATE_PMCFG);
+ VMXNET3_CMD_QUIESCE_DEV);
spin_unlock_irqrestore(&adapter->cmd_lock, flags);
- vmxnet3_alloc_intr_resources(adapter);
- vmxnet3_request_irqs(adapter);
- for (i = 0; i < adapter->num_rx_queues; i++)
- napi_enable(&adapter->rx_queue[i].napi);
- vmxnet3_enable_all_intrs(adapter);
+ vmxnet3_tq_cleanup_all(adapter);
+ vmxnet3_rq_cleanup_all(adapter);
+
+ vmxnet3_reset_dev(adapter);
+ err = vmxnet3_activate_dev(adapter);
+ if (err != 0) {
+ netdev_err(netdev,
+ "failed to re-activate on resume, error: %d", err);
+ vmxnet3_force_close(adapter);
+ return err;
+ }
+ netif_device_attach(netdev);
return 0;
}
@@ -3331,6 +3339,8 @@ vmxnet3_resume(struct device *device)
static const struct dev_pm_ops vmxnet3_pm_ops = {
.suspend = vmxnet3_suspend,
.resume = vmxnet3_resume,
+ .freeze = vmxnet3_suspend,
+ .restore = vmxnet3_resume,
};
#endif
diff --git a/drivers/net/vmxnet3/vmxnet3_ethtool.c b/drivers/net/vmxnet3/vmxnet3_ethtool.c
index b7b53329d575..4c8a944d58b4 100644
--- a/drivers/net/vmxnet3/vmxnet3_ethtool.c
+++ b/drivers/net/vmxnet3/vmxnet3_ethtool.c
@@ -323,7 +323,7 @@ vmxnet3_get_ethtool_stats(struct net_device *netdev,
vmxnet3_tq_driver_stats[i].offset);
}
- for (j = 0; j < adapter->num_tx_queues; j++) {
+ for (j = 0; j < adapter->num_rx_queues; j++) {
base = (u8 *)&adapter->rqd_start[j].stats;
*buf++ = (u64) j;
for (i = 1; i < ARRAY_SIZE(vmxnet3_rq_dev_stats); i++)
@@ -447,12 +447,12 @@ vmxnet3_get_ringparam(struct net_device *netdev,
param->rx_max_pending = VMXNET3_RX_RING_MAX_SIZE;
param->tx_max_pending = VMXNET3_TX_RING_MAX_SIZE;
param->rx_mini_max_pending = 0;
- param->rx_jumbo_max_pending = 0;
+ param->rx_jumbo_max_pending = VMXNET3_RX_RING2_MAX_SIZE;
param->rx_pending = adapter->rx_ring_size;
param->tx_pending = adapter->tx_ring_size;
param->rx_mini_pending = 0;
- param->rx_jumbo_pending = 0;
+ param->rx_jumbo_pending = adapter->rx_ring2_size;
}
@@ -461,7 +461,7 @@ vmxnet3_set_ringparam(struct net_device *netdev,
struct ethtool_ringparam *param)
{
struct vmxnet3_adapter *adapter = netdev_priv(netdev);
- u32 new_tx_ring_size, new_rx_ring_size;
+ u32 new_tx_ring_size, new_rx_ring_size, new_rx_ring2_size;
u32 sz;
int err = 0;
@@ -473,6 +473,10 @@ vmxnet3_set_ringparam(struct net_device *netdev,
VMXNET3_RX_RING_MAX_SIZE)
return -EINVAL;
+ if (param->rx_jumbo_pending == 0 ||
+ param->rx_jumbo_pending > VMXNET3_RX_RING2_MAX_SIZE)
+ return -EINVAL;
+
/* if adapter not yet initialized, do nothing */
if (adapter->rx_buf_per_pkt == 0) {
netdev_err(netdev, "adapter not completely initialized, "
@@ -500,8 +504,15 @@ vmxnet3_set_ringparam(struct net_device *netdev,
sz) != 0)
return -EINVAL;
- if (new_tx_ring_size == adapter->tx_queue[0].tx_ring.size &&
- new_rx_ring_size == adapter->rx_queue[0].rx_ring[0].size) {
+ /* ring2 has to be a multiple of VMXNET3_RING_SIZE_ALIGN */
+ new_rx_ring2_size = (param->rx_jumbo_pending + VMXNET3_RING_SIZE_MASK) &
+ ~VMXNET3_RING_SIZE_MASK;
+ new_rx_ring2_size = min_t(u32, new_rx_ring2_size,
+ VMXNET3_RX_RING2_MAX_SIZE);
+
+ if (new_tx_ring_size == adapter->tx_ring_size &&
+ new_rx_ring_size == adapter->rx_ring_size &&
+ new_rx_ring2_size == adapter->rx_ring2_size) {
return 0;
}
@@ -522,7 +533,7 @@ vmxnet3_set_ringparam(struct net_device *netdev,
vmxnet3_rq_destroy_all(adapter);
err = vmxnet3_create_queues(adapter, new_tx_ring_size,
- new_rx_ring_size, VMXNET3_DEF_RX_RING_SIZE);
+ new_rx_ring_size, new_rx_ring2_size);
if (err) {
/* failed, most likely because of OOM, try default
@@ -530,11 +541,12 @@ vmxnet3_set_ringparam(struct net_device *netdev,
netdev_err(netdev, "failed to apply new sizes, "
"try the default ones\n");
new_rx_ring_size = VMXNET3_DEF_RX_RING_SIZE;
+ new_rx_ring2_size = VMXNET3_DEF_RX_RING2_SIZE;
new_tx_ring_size = VMXNET3_DEF_TX_RING_SIZE;
err = vmxnet3_create_queues(adapter,
new_tx_ring_size,
new_rx_ring_size,
- VMXNET3_DEF_RX_RING_SIZE);
+ new_rx_ring2_size);
if (err) {
netdev_err(netdev, "failed to create queues "
"with default sizes. Closing it\n");
@@ -549,6 +561,7 @@ vmxnet3_set_ringparam(struct net_device *netdev,
}
adapter->tx_ring_size = new_tx_ring_size;
adapter->rx_ring_size = new_rx_ring_size;
+ adapter->rx_ring2_size = new_rx_ring2_size;
out:
clear_bit(VMXNET3_STATE_BIT_RESETTING, &adapter->state);
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 5f0199f6c31e..cd71c77f78f2 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -69,10 +69,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.2.1.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.3.4.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01020100
+#define VMXNET3_DRIVER_VERSION_NUM 0x01030400
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
@@ -352,6 +352,7 @@ struct vmxnet3_adapter {
/* Ring sizes */
u32 tx_ring_size;
u32 rx_ring_size;
+ u32 rx_ring2_size;
struct work_struct work;
@@ -384,6 +385,7 @@ struct vmxnet3_adapter {
/* must be a multiple of VMXNET3_RING_SIZE_ALIGN */
#define VMXNET3_DEF_TX_RING_SIZE 512
#define VMXNET3_DEF_RX_RING_SIZE 256
+#define VMXNET3_DEF_RX_RING2_SIZE 128
#define VMXNET3_MAX_ETH_HDR_SIZE 22
#define VMXNET3_MAX_SKB_BUF_SIZE (3*1024)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 7fbd89fbe107..1e0a775ea882 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -61,12 +61,6 @@
#define FDB_AGE_DEFAULT 300 /* 5 min */
#define FDB_AGE_INTERVAL (10 * HZ) /* rescan interval */
-#define VXLAN_N_VID (1u << 24)
-#define VXLAN_VID_MASK (VXLAN_N_VID - 1)
-#define VXLAN_HLEN (sizeof(struct udphdr) + sizeof(struct vxlanhdr))
-
-#define VXLAN_FLAGS 0x08000000 /* struct vxlanhdr.vx_flags required value. */
-
/* UDP port for VXLAN traffic.
* The IANA assigned port is 4789, but the Linux default is 8472
* for compatibility with early adopters.
@@ -269,15 +263,20 @@ static inline struct vxlan_rdst *first_remote_rtnl(struct vxlan_fdb *fdb)
return list_first_entry(&fdb->remotes, struct vxlan_rdst, list);
}
-/* Find VXLAN socket based on network namespace, address family and UDP port */
-static struct vxlan_sock *vxlan_find_sock(struct net *net,
- sa_family_t family, __be16 port)
+/* Find VXLAN socket based on network namespace, address family and UDP port
+ * and enabled unshareable flags.
+ */
+static struct vxlan_sock *vxlan_find_sock(struct net *net, sa_family_t family,
+ __be16 port, u32 flags)
{
struct vxlan_sock *vs;
+ flags &= VXLAN_F_RCV_FLAGS;
+
hlist_for_each_entry_rcu(vs, vs_head(net, port), hlist) {
if (inet_sk(vs->sock->sk)->inet_sport == port &&
- inet_sk(vs->sock->sk)->sk.sk_family == family)
+ inet_sk(vs->sock->sk)->sk.sk_family == family &&
+ vs->flags == flags)
return vs;
}
return NULL;
@@ -297,11 +296,12 @@ static struct vxlan_dev *vxlan_vs_find_vni(struct vxlan_sock *vs, u32 id)
/* Look up VNI in a per net namespace table */
static struct vxlan_dev *vxlan_find_vni(struct net *net, u32 id,
- sa_family_t family, __be16 port)
+ sa_family_t family, __be16 port,
+ u32 flags)
{
struct vxlan_sock *vs;
- vs = vxlan_find_sock(net, family, port);
+ vs = vxlan_find_sock(net, family, port, flags);
if (!vs)
return NULL;
@@ -340,6 +340,11 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
ndm->ndm_flags = fdb->flags;
ndm->ndm_type = RTN_UNICAST;
+ if (!net_eq(dev_net(vxlan->dev), vxlan->net) &&
+ nla_put_s32(skb, NDA_LINK_NETNSID,
+ peernet2id(dev_net(vxlan->dev), vxlan->net)))
+ goto nla_put_failure;
+
if (send_eth && nla_put(skb, NDA_LLADDR, ETH_ALEN, &fdb->eth_addr))
goto nla_put_failure;
@@ -364,7 +369,8 @@ static int vxlan_fdb_info(struct sk_buff *skb, struct vxlan_dev *vxlan,
if (nla_put(skb, NDA_CACHEINFO, sizeof(ci), &ci))
goto nla_put_failure;
- return nlmsg_end(skb, nlh);
+ nlmsg_end(skb, nlh);
+ return 0;
nla_put_failure:
nlmsg_cancel(skb, nlh);
@@ -379,6 +385,7 @@ static inline size_t vxlan_nlmsg_size(void)
+ nla_total_size(sizeof(__be16)) /* NDA_PORT */
+ nla_total_size(sizeof(__be32)) /* NDA_VNI */
+ nla_total_size(sizeof(__u32)) /* NDA_IFINDEX */
+ + nla_total_size(sizeof(__s32)) /* NDA_LINK_NETNSID */
+ nla_total_size(sizeof(struct nda_cacheinfo));
}
@@ -545,15 +552,56 @@ static int vxlan_fdb_append(struct vxlan_fdb *f,
return 1;
}
-static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff *skb)
+static struct vxlanhdr *vxlan_gro_remcsum(struct sk_buff *skb,
+ unsigned int off,
+ struct vxlanhdr *vh, size_t hdrlen,
+ u32 data, struct gro_remcsum *grc,
+ bool nopartial)
+{
+ size_t start, offset, plen;
+
+ if (skb->remcsum_offload)
+ return NULL;
+
+ if (!NAPI_GRO_CB(skb)->csum_valid)
+ return NULL;
+
+ start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
+ offset = start + ((data & VXLAN_RCO_UDP) ?
+ offsetof(struct udphdr, check) :
+ offsetof(struct tcphdr, check));
+
+ plen = hdrlen + offset + sizeof(u16);
+
+ /* Pull checksum that will be written */
+ if (skb_gro_header_hard(skb, off + plen)) {
+ vh = skb_gro_header_slow(skb, off + plen, off);
+ if (!vh)
+ return NULL;
+ }
+
+ skb_gro_remcsum_process(skb, (void *)vh + hdrlen,
+ start, offset, grc, nopartial);
+
+ skb->remcsum_offload = 1;
+
+ return vh;
+}
+
+static struct sk_buff **vxlan_gro_receive(struct sk_buff **head,
+ struct sk_buff *skb,
+ struct udp_offload *uoff)
{
struct sk_buff *p, **pp = NULL;
struct vxlanhdr *vh, *vh2;
- struct ethhdr *eh, *eh2;
- unsigned int hlen, off_vx, off_eth;
- const struct packet_offload *ptype;
- __be16 type;
+ unsigned int hlen, off_vx;
int flush = 1;
+ struct vxlan_sock *vs = container_of(uoff, struct vxlan_sock,
+ udp_offloads);
+ u32 flags;
+ struct gro_remcsum grc;
+
+ skb_gro_remcsum_init(&grc);
off_vx = skb_gro_offset(skb);
hlen = off_vx + sizeof(*vh);
@@ -563,15 +611,19 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
if (unlikely(!vh))
goto out;
}
+
skb_gro_pull(skb, sizeof(struct vxlanhdr)); /* pull vxlan header */
skb_gro_postpull_rcsum(skb, vh, sizeof(struct vxlanhdr));
- off_eth = skb_gro_offset(skb);
- hlen = off_eth + sizeof(*eh);
- eh = skb_gro_header_fast(skb, off_eth);
- if (skb_gro_header_hard(skb, hlen)) {
- eh = skb_gro_header_slow(skb, hlen, off_eth);
- if (unlikely(!eh))
+ flags = ntohl(vh->vx_flags);
+
+ if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
+ vh = vxlan_gro_remcsum(skb, off_vx, vh, sizeof(struct vxlanhdr),
+ ntohl(vh->vx_vni), &grc,
+ !!(vs->flags &
+ VXLAN_F_REMCSUM_NOPARTIAL));
+
+ if (!vh)
goto out;
}
@@ -582,54 +634,28 @@ static struct sk_buff **vxlan_gro_receive(struct sk_buff **head, struct sk_buff
continue;
vh2 = (struct vxlanhdr *)(p->data + off_vx);
- eh2 = (struct ethhdr *)(p->data + off_eth);
- if (vh->vx_vni != vh2->vx_vni || compare_ether_header(eh, eh2)) {
+ if (vh->vx_flags != vh2->vx_flags ||
+ vh->vx_vni != vh2->vx_vni) {
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
}
- type = eh->h_proto;
+ pp = eth_gro_receive(head, skb);
- rcu_read_lock();
- ptype = gro_find_receive_by_type(type);
- if (ptype == NULL) {
- flush = 1;
- goto out_unlock;
- }
-
- skb_gro_pull(skb, sizeof(*eh)); /* pull inner eth header */
- skb_gro_postpull_rcsum(skb, eh, sizeof(*eh));
- pp = ptype->callbacks.gro_receive(head, skb);
-
-out_unlock:
- rcu_read_unlock();
out:
+ skb_gro_remcsum_cleanup(skb, &grc);
NAPI_GRO_CB(skb)->flush |= flush;
return pp;
}
-static int vxlan_gro_complete(struct sk_buff *skb, int nhoff)
+static int vxlan_gro_complete(struct sk_buff *skb, int nhoff,
+ struct udp_offload *uoff)
{
- struct ethhdr *eh;
- struct packet_offload *ptype;
- __be16 type;
- int vxlan_len = sizeof(struct vxlanhdr) + sizeof(struct ethhdr);
- int err = -ENOSYS;
-
udp_tunnel_gro_complete(skb, nhoff);
- eh = (struct ethhdr *)(skb->data + nhoff + sizeof(struct vxlanhdr));
- type = eh->h_proto;
-
- rcu_read_lock();
- ptype = gro_find_complete_by_type(type);
- if (ptype != NULL)
- err = ptype->callbacks.gro_complete(skb, nhoff + vxlan_len);
-
- rcu_read_unlock();
- return err;
+ return eth_gro_complete(skb, nhoff + sizeof(struct vxlanhdr));
}
/* Notify netdevs that UDP port started listening */
@@ -991,7 +1017,7 @@ static bool vxlan_snoop(struct net_device *dev,
if (net_ratelimit())
netdev_info(dev,
"%pM migrated from %pIS to %pIS\n",
- src_mac, &rdst->remote_ip, &src_ip);
+ src_mac, &rdst->remote_ip.sa, &src_ip->sa);
rdst->remote_ip = *src_ip;
f->updated = jiffies;
@@ -1131,33 +1157,103 @@ static void vxlan_igmp_leave(struct work_struct *work)
dev_put(vxlan->dev);
}
+static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh,
+ size_t hdrlen, u32 data, bool nopartial)
+{
+ size_t start, offset, plen;
+
+ start = (data & VXLAN_RCO_MASK) << VXLAN_RCO_SHIFT;
+ offset = start + ((data & VXLAN_RCO_UDP) ?
+ offsetof(struct udphdr, check) :
+ offsetof(struct tcphdr, check));
+
+ plen = hdrlen + offset + sizeof(u16);
+
+ if (!pskb_may_pull(skb, plen))
+ return NULL;
+
+ vh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
+
+ skb_remcsum_process(skb, (void *)vh + hdrlen, start, offset,
+ nopartial);
+
+ return vh;
+}
+
/* Callback from net/ipv4/udp.c to receive packets */
static int vxlan_udp_encap_recv(struct sock *sk, struct sk_buff *skb)
{
struct vxlan_sock *vs;
struct vxlanhdr *vxh;
+ u32 flags, vni;
+ struct vxlan_metadata md = {0};
/* Need Vxlan and inner Ethernet header to be present */
if (!pskb_may_pull(skb, VXLAN_HLEN))
goto error;
- /* Return packets with reserved bits set */
vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
- if (vxh->vx_flags != htonl(VXLAN_FLAGS) ||
- (vxh->vx_vni & htonl(0xff))) {
- netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
- ntohl(vxh->vx_flags), ntohl(vxh->vx_vni));
- goto error;
+ flags = ntohl(vxh->vx_flags);
+ vni = ntohl(vxh->vx_vni);
+
+ if (flags & VXLAN_HF_VNI) {
+ flags &= ~VXLAN_HF_VNI;
+ } else {
+ /* VNI flag always required to be set */
+ goto bad_flags;
}
if (iptunnel_pull_header(skb, VXLAN_HLEN, htons(ETH_P_TEB)))
goto drop;
+ vxh = (struct vxlanhdr *)(udp_hdr(skb) + 1);
vs = rcu_dereference_sk_user_data(sk);
if (!vs)
goto drop;
- vs->rcv(vs, skb, vxh->vx_vni);
+ if ((flags & VXLAN_HF_RCO) && (vs->flags & VXLAN_F_REMCSUM_RX)) {
+ vxh = vxlan_remcsum(skb, vxh, sizeof(struct vxlanhdr), vni,
+ !!(vs->flags & VXLAN_F_REMCSUM_NOPARTIAL));
+ if (!vxh)
+ goto drop;
+
+ flags &= ~VXLAN_HF_RCO;
+ vni &= VXLAN_VID_MASK;
+ }
+
+ /* For backwards compatibility, only allow reserved fields to be
+ * used by VXLAN extensions if explicitly requested.
+ */
+ if ((flags & VXLAN_HF_GBP) && (vs->flags & VXLAN_F_GBP)) {
+ struct vxlanhdr_gbp *gbp;
+
+ gbp = (struct vxlanhdr_gbp *)vxh;
+ md.gbp = ntohs(gbp->policy_id);
+
+ if (gbp->dont_learn)
+ md.gbp |= VXLAN_GBP_DONT_LEARN;
+
+ if (gbp->policy_applied)
+ md.gbp |= VXLAN_GBP_POLICY_APPLIED;
+
+ flags &= ~VXLAN_GBP_USED_BITS;
+ }
+
+ if (flags || (vni & ~VXLAN_VID_MASK)) {
+ /* If there are any unprocessed flags remaining treat
+ * this as a malformed packet. This behavior diverges from
+ * VXLAN RFC (RFC7348) which stipulates that bits in reserved
+ * in reserved fields are to be ignored. The approach here
+ * maintains compatbility with previous stack code, and also
+ * is more robust and provides a little more security in
+ * adding extensions to VXLAN.
+ */
+
+ goto bad_flags;
+ }
+
+ md.vni = vxh->vx_vni;
+ vs->rcv(vs, skb, &md);
return 0;
drop:
@@ -1165,13 +1261,17 @@ drop:
kfree_skb(skb);
return 0;
+bad_flags:
+ netdev_dbg(skb->dev, "invalid vxlan flags=%#x vni=%#x\n",
+ ntohl(vxh->vx_flags), ntohl(vxh->vx_vni));
+
error:
/* Return non vxlan pkt */
return 1;
}
-static void vxlan_rcv(struct vxlan_sock *vs,
- struct sk_buff *skb, __be32 vx_vni)
+static void vxlan_rcv(struct vxlan_sock *vs, struct sk_buff *skb,
+ struct vxlan_metadata *md)
{
struct iphdr *oip = NULL;
struct ipv6hdr *oip6 = NULL;
@@ -1182,7 +1282,7 @@ static void vxlan_rcv(struct vxlan_sock *vs,
int err = 0;
union vxlan_addr *remote_ip;
- vni = ntohl(vx_vni) >> 8;
+ vni = ntohl(md->vni) >> 8;
/* Is this VNI defined? */
vxlan = vxlan_vs_find_vni(vs, vni);
if (!vxlan)
@@ -1216,6 +1316,7 @@ static void vxlan_rcv(struct vxlan_sock *vs,
goto drop;
skb_reset_network_header(skb);
+ skb->mark = md->gbp;
if (oip6)
err = IP6_ECN_decapsulate(oip6, skb);
@@ -1565,20 +1666,54 @@ static bool route_shortcircuit(struct net_device *dev, struct sk_buff *skb)
return false;
}
+static void vxlan_build_gbp_hdr(struct vxlanhdr *vxh, u32 vxflags,
+ struct vxlan_metadata *md)
+{
+ struct vxlanhdr_gbp *gbp;
+
+ if (!md->gbp)
+ return;
+
+ gbp = (struct vxlanhdr_gbp *)vxh;
+ vxh->vx_flags |= htonl(VXLAN_HF_GBP);
+
+ if (md->gbp & VXLAN_GBP_DONT_LEARN)
+ gbp->dont_learn = 1;
+
+ if (md->gbp & VXLAN_GBP_POLICY_APPLIED)
+ gbp->policy_applied = 1;
+
+ gbp->policy_id = htons(md->gbp & VXLAN_GBP_ID_MASK);
+}
+
#if IS_ENABLED(CONFIG_IPV6)
-static int vxlan6_xmit_skb(struct vxlan_sock *vs,
- struct dst_entry *dst, struct sk_buff *skb,
+static int vxlan6_xmit_skb(struct dst_entry *dst, struct sk_buff *skb,
struct net_device *dev, struct in6_addr *saddr,
struct in6_addr *daddr, __u8 prio, __u8 ttl,
- __be16 src_port, __be16 dst_port, __be32 vni,
- bool xnet)
+ __be16 src_port, __be16 dst_port,
+ struct vxlan_metadata *md, bool xnet, u32 vxflags)
{
struct vxlanhdr *vxh;
int min_headroom;
int err;
- bool udp_sum = !udp_get_no_check6_tx(vs->sock->sk);
+ bool udp_sum = !(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX);
+ int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
+ u16 hdrlen = sizeof(struct vxlanhdr);
+
+ if ((vxflags & VXLAN_F_REMCSUM_TX) &&
+ skb->ip_summed == CHECKSUM_PARTIAL) {
+ int csum_start = skb_checksum_start_offset(skb);
+
+ if (csum_start <= VXLAN_MAX_REMCSUM_START &&
+ !(csum_start & VXLAN_RCO_SHIFT_MASK) &&
+ (skb->csum_offset == offsetof(struct udphdr, check) ||
+ skb->csum_offset == offsetof(struct tcphdr, check))) {
+ udp_sum = false;
+ type |= SKB_GSO_TUNNEL_REMCSUM;
+ }
+ }
- skb = udp_tunnel_handle_offloads(skb, udp_sum);
+ skb = iptunnel_handle_offloads(skb, udp_sum, type);
if (IS_ERR(skb)) {
err = -EINVAL;
goto err;
@@ -1588,7 +1723,7 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
min_headroom = LL_RESERVED_SPACE(dst->dev) + dst->header_len
+ VXLAN_HLEN + sizeof(struct ipv6hdr)
- + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
+ + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
/* Need space for new headers (invalidates iph ptr) */
err = skb_cow_head(skb, min_headroom);
@@ -1604,13 +1739,33 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
}
vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
- vxh->vx_flags = htonl(VXLAN_FLAGS);
- vxh->vx_vni = vni;
+ vxh->vx_flags = htonl(VXLAN_HF_VNI);
+ vxh->vx_vni = md->vni;
+
+ if (type & SKB_GSO_TUNNEL_REMCSUM) {
+ u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
+ VXLAN_RCO_SHIFT;
+
+ if (skb->csum_offset == offsetof(struct udphdr, check))
+ data |= VXLAN_RCO_UDP;
+
+ vxh->vx_vni |= htonl(data);
+ vxh->vx_flags |= htonl(VXLAN_HF_RCO);
+
+ if (!skb_is_gso(skb)) {
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->encapsulation = 0;
+ }
+ }
+
+ if (vxflags & VXLAN_F_GBP)
+ vxlan_build_gbp_hdr(vxh, vxflags, md);
skb_set_inner_protocol(skb, htons(ETH_P_TEB));
- udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
- ttl, src_port, dst_port);
+ udp_tunnel6_xmit_skb(dst, skb, dev, saddr, daddr, prio,
+ ttl, src_port, dst_port,
+ !!(vxflags & VXLAN_F_UDP_ZERO_CSUM6_TX));
return 0;
err:
dst_release(dst);
@@ -1618,23 +1773,38 @@ err:
}
#endif
-int vxlan_xmit_skb(struct vxlan_sock *vs,
- struct rtable *rt, struct sk_buff *skb,
+int vxlan_xmit_skb(struct rtable *rt, struct sk_buff *skb,
__be32 src, __be32 dst, __u8 tos, __u8 ttl, __be16 df,
- __be16 src_port, __be16 dst_port, __be32 vni, bool xnet)
+ __be16 src_port, __be16 dst_port,
+ struct vxlan_metadata *md, bool xnet, u32 vxflags)
{
struct vxlanhdr *vxh;
int min_headroom;
int err;
- bool udp_sum = !vs->sock->sk->sk_no_check_tx;
+ bool udp_sum = !!(vxflags & VXLAN_F_UDP_CSUM);
+ int type = udp_sum ? SKB_GSO_UDP_TUNNEL_CSUM : SKB_GSO_UDP_TUNNEL;
+ u16 hdrlen = sizeof(struct vxlanhdr);
+
+ if ((vxflags & VXLAN_F_REMCSUM_TX) &&
+ skb->ip_summed == CHECKSUM_PARTIAL) {
+ int csum_start = skb_checksum_start_offset(skb);
+
+ if (csum_start <= VXLAN_MAX_REMCSUM_START &&
+ !(csum_start & VXLAN_RCO_SHIFT_MASK) &&
+ (skb->csum_offset == offsetof(struct udphdr, check) ||
+ skb->csum_offset == offsetof(struct tcphdr, check))) {
+ udp_sum = false;
+ type |= SKB_GSO_TUNNEL_REMCSUM;
+ }
+ }
- skb = udp_tunnel_handle_offloads(skb, udp_sum);
+ skb = iptunnel_handle_offloads(skb, udp_sum, type);
if (IS_ERR(skb))
return PTR_ERR(skb);
min_headroom = LL_RESERVED_SPACE(rt->dst.dev) + rt->dst.header_len
+ VXLAN_HLEN + sizeof(struct iphdr)
- + (vlan_tx_tag_present(skb) ? VLAN_HLEN : 0);
+ + (skb_vlan_tag_present(skb) ? VLAN_HLEN : 0);
/* Need space for new headers (invalidates iph ptr) */
err = skb_cow_head(skb, min_headroom);
@@ -1648,13 +1818,33 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
return -ENOMEM;
vxh = (struct vxlanhdr *) __skb_push(skb, sizeof(*vxh));
- vxh->vx_flags = htonl(VXLAN_FLAGS);
- vxh->vx_vni = vni;
+ vxh->vx_flags = htonl(VXLAN_HF_VNI);
+ vxh->vx_vni = md->vni;
+
+ if (type & SKB_GSO_TUNNEL_REMCSUM) {
+ u32 data = (skb_checksum_start_offset(skb) - hdrlen) >>
+ VXLAN_RCO_SHIFT;
+
+ if (skb->csum_offset == offsetof(struct udphdr, check))
+ data |= VXLAN_RCO_UDP;
+
+ vxh->vx_vni |= htonl(data);
+ vxh->vx_flags |= htonl(VXLAN_HF_RCO);
+
+ if (!skb_is_gso(skb)) {
+ skb->ip_summed = CHECKSUM_NONE;
+ skb->encapsulation = 0;
+ }
+ }
+
+ if (vxflags & VXLAN_F_GBP)
+ vxlan_build_gbp_hdr(vxh, vxflags, md);
skb_set_inner_protocol(skb, htons(ETH_P_TEB));
- return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos,
- ttl, df, src_port, dst_port, xnet);
+ return udp_tunnel_xmit_skb(rt, skb, src, dst, tos,
+ ttl, df, src_port, dst_port, xnet,
+ !(vxflags & VXLAN_F_UDP_CSUM));
}
EXPORT_SYMBOL_GPL(vxlan_xmit_skb);
@@ -1711,6 +1901,7 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
const struct iphdr *old_iph;
struct flowi4 fl4;
union vxlan_addr *dst;
+ struct vxlan_metadata md;
__be16 src_port = 0, dst_port;
u32 vni;
__be16 df = 0;
@@ -1772,7 +1963,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
ip_rt_put(rt);
dst_vxlan = vxlan_find_vni(vxlan->net, vni,
- dst->sa.sa_family, dst_port);
+ dst->sa.sa_family, dst_port,
+ vxlan->flags);
if (!dst_vxlan)
goto tx_error;
vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -1781,12 +1973,14 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
tos = ip_tunnel_ecn_encap(tos, old_iph, skb);
ttl = ttl ? : ip4_dst_hoplimit(&rt->dst);
-
- err = vxlan_xmit_skb(vxlan->vn_sock, rt, skb,
- fl4.saddr, dst->sin.sin_addr.s_addr,
- tos, ttl, df, src_port, dst_port,
- htonl(vni << 8),
- !net_eq(vxlan->net, dev_net(vxlan->dev)));
+ md.vni = htonl(vni << 8);
+ md.gbp = skb->mark;
+
+ err = vxlan_xmit_skb(rt, skb, fl4.saddr,
+ dst->sin.sin_addr.s_addr, tos, ttl, df,
+ src_port, dst_port, &md,
+ !net_eq(vxlan->net, dev_net(vxlan->dev)),
+ vxlan->flags);
if (err < 0) {
/* skb is already freed. */
skb = NULL;
@@ -1830,7 +2024,8 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
dst_release(ndst);
dst_vxlan = vxlan_find_vni(vxlan->net, vni,
- dst->sa.sa_family, dst_port);
+ dst->sa.sa_family, dst_port,
+ vxlan->flags);
if (!dst_vxlan)
goto tx_error;
vxlan_encap_bypass(skb, vxlan, dst_vxlan);
@@ -1838,11 +2033,13 @@ static void vxlan_xmit_one(struct sk_buff *skb, struct net_device *dev,
}
ttl = ttl ? : ip6_dst_hoplimit(ndst);
+ md.vni = htonl(vni << 8);
+ md.gbp = skb->mark;
- err = vxlan6_xmit_skb(vxlan->vn_sock, ndst, skb,
- dev, &fl6.saddr, &fl6.daddr, 0, ttl,
- src_port, dst_port, htonl(vni << 8),
- !net_eq(vxlan->net, dev_net(vxlan->dev)));
+ err = vxlan6_xmit_skb(ndst, skb, dev, &fl6.saddr, &fl6.daddr,
+ 0, ttl, src_port, dst_port, &md,
+ !net_eq(vxlan->net, dev_net(vxlan->dev)),
+ vxlan->flags);
#endif
}
@@ -1998,7 +2195,7 @@ static int vxlan_init(struct net_device *dev)
spin_lock(&vn->sock_lock);
vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
- vxlan->dst_port);
+ vxlan->dst_port, vxlan->flags);
if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) {
/* If we have a socket with same port already, reuse it */
vxlan_vs_add_dev(vs, vxlan);
@@ -2242,6 +2439,10 @@ static const struct nla_policy vxlan_policy[IFLA_VXLAN_MAX + 1] = {
[IFLA_VXLAN_UDP_CSUM] = { .type = NLA_U8 },
[IFLA_VXLAN_UDP_ZERO_CSUM6_TX] = { .type = NLA_U8 },
[IFLA_VXLAN_UDP_ZERO_CSUM6_RX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_REMCSUM_TX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_REMCSUM_RX] = { .type = NLA_U8 },
+ [IFLA_VXLAN_GBP] = { .type = NLA_FLAG, },
+ [IFLA_VXLAN_REMCSUM_NOPARTIAL] = { .type = NLA_FLAG },
};
static int vxlan_validate(struct nlattr *tb[], struct nlattr *data[])
@@ -2311,15 +2512,11 @@ static struct socket *vxlan_create_sock(struct net *net, bool ipv6,
if (ipv6) {
udp_conf.family = AF_INET6;
- udp_conf.use_udp6_tx_checksums =
- !(flags & VXLAN_F_UDP_ZERO_CSUM6_TX);
udp_conf.use_udp6_rx_checksums =
!(flags & VXLAN_F_UDP_ZERO_CSUM6_RX);
} else {
udp_conf.family = AF_INET;
udp_conf.local_ip.s_addr = INADDR_ANY;
- udp_conf.use_udp_checksums =
- !!(flags & VXLAN_F_UDP_CSUM);
}
udp_conf.local_udp_port = port;
@@ -2363,6 +2560,7 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
atomic_set(&vs->refcnt, 1);
vs->rcv = rcv;
vs->data = data;
+ vs->flags = (flags & VXLAN_F_RCV_FLAGS);
/* Initialize the vxlan udp offloads structure */
vs->udp_offloads.port = port;
@@ -2401,7 +2599,7 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
return vs;
spin_lock(&vn->sock_lock);
- vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port);
+ vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags);
if (vs && ((vs->rcv != rcv) ||
!atomic_add_unless(&vs->refcnt, 1, 0)))
vs = ERR_PTR(-EBUSY);
@@ -2432,10 +2630,10 @@ static void vxlan_sock_work(struct work_struct *work)
dev_put(vxlan->dev);
}
-static int vxlan_newlink(struct net *net, struct net_device *dev,
+static int vxlan_newlink(struct net *src_net, struct net_device *dev,
struct nlattr *tb[], struct nlattr *data[])
{
- struct vxlan_net *vn = net_generic(net, vxlan_net_id);
+ struct vxlan_net *vn = net_generic(src_net, vxlan_net_id);
struct vxlan_dev *vxlan = netdev_priv(dev);
struct vxlan_rdst *dst = &vxlan->default_dst;
__u32 vni;
@@ -2445,7 +2643,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
if (!data[IFLA_VXLAN_ID])
return -EINVAL;
- vxlan->net = dev_net(dev);
+ vxlan->net = src_net;
vni = nla_get_u32(data[IFLA_VXLAN_ID]);
dst->remote_vni = vni;
@@ -2481,7 +2679,7 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
if (data[IFLA_VXLAN_LINK] &&
(dst->remote_ifindex = nla_get_u32(data[IFLA_VXLAN_LINK]))) {
struct net_device *lowerdev
- = __dev_get_by_index(net, dst->remote_ifindex);
+ = __dev_get_by_index(src_net, dst->remote_ifindex);
if (!lowerdev) {
pr_info("ifindex %d does not exist\n", dst->remote_ifindex);
@@ -2557,8 +2755,22 @@ static int vxlan_newlink(struct net *net, struct net_device *dev,
nla_get_u8(data[IFLA_VXLAN_UDP_ZERO_CSUM6_RX]))
vxlan->flags |= VXLAN_F_UDP_ZERO_CSUM6_RX;
- if (vxlan_find_vni(net, vni, use_ipv6 ? AF_INET6 : AF_INET,
- vxlan->dst_port)) {
+ if (data[IFLA_VXLAN_REMCSUM_TX] &&
+ nla_get_u8(data[IFLA_VXLAN_REMCSUM_TX]))
+ vxlan->flags |= VXLAN_F_REMCSUM_TX;
+
+ if (data[IFLA_VXLAN_REMCSUM_RX] &&
+ nla_get_u8(data[IFLA_VXLAN_REMCSUM_RX]))
+ vxlan->flags |= VXLAN_F_REMCSUM_RX;
+
+ if (data[IFLA_VXLAN_GBP])
+ vxlan->flags |= VXLAN_F_GBP;
+
+ if (data[IFLA_VXLAN_REMCSUM_NOPARTIAL])
+ vxlan->flags |= VXLAN_F_REMCSUM_NOPARTIAL;
+
+ if (vxlan_find_vni(src_net, vni, use_ipv6 ? AF_INET6 : AF_INET,
+ vxlan->dst_port, vxlan->flags)) {
pr_info("duplicate VNI %u\n", vni);
return -EEXIST;
}
@@ -2625,6 +2837,8 @@ static size_t vxlan_get_size(const struct net_device *dev)
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_CSUM */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_TX */
nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_UDP_ZERO_CSUM6_RX */
+ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_TX */
+ nla_total_size(sizeof(__u8)) + /* IFLA_VXLAN_REMCSUM_RX */
0;
}
@@ -2690,18 +2904,37 @@ static int vxlan_fill_info(struct sk_buff *skb, const struct net_device *dev)
nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_TX,
!!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_TX)) ||
nla_put_u8(skb, IFLA_VXLAN_UDP_ZERO_CSUM6_RX,
- !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)))
+ !!(vxlan->flags & VXLAN_F_UDP_ZERO_CSUM6_RX)) ||
+ nla_put_u8(skb, IFLA_VXLAN_REMCSUM_TX,
+ !!(vxlan->flags & VXLAN_F_REMCSUM_TX)) ||
+ nla_put_u8(skb, IFLA_VXLAN_REMCSUM_RX,
+ !!(vxlan->flags & VXLAN_F_REMCSUM_RX)))
goto nla_put_failure;
if (nla_put(skb, IFLA_VXLAN_PORT_RANGE, sizeof(ports), &ports))
goto nla_put_failure;
+ if (vxlan->flags & VXLAN_F_GBP &&
+ nla_put_flag(skb, IFLA_VXLAN_GBP))
+ goto nla_put_failure;
+
+ if (vxlan->flags & VXLAN_F_REMCSUM_NOPARTIAL &&
+ nla_put_flag(skb, IFLA_VXLAN_REMCSUM_NOPARTIAL))
+ goto nla_put_failure;
+
return 0;
nla_put_failure:
return -EMSGSIZE;
}
+static struct net *vxlan_get_link_net(const struct net_device *dev)
+{
+ struct vxlan_dev *vxlan = netdev_priv(dev);
+
+ return vxlan->net;
+}
+
static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
.kind = "vxlan",
.maxtype = IFLA_VXLAN_MAX,
@@ -2713,6 +2946,7 @@ static struct rtnl_link_ops vxlan_link_ops __read_mostly = {
.dellink = vxlan_dellink,
.get_size = vxlan_get_size,
.fill_info = vxlan_fill_info,
+ .get_link_net = vxlan_get_link_net,
};
static void vxlan_handle_lowerdev_unregister(struct vxlan_net *vn,
diff --git a/drivers/net/wan/Kconfig b/drivers/net/wan/Kconfig
index 94e234975c61..a2fdd15f285a 100644
--- a/drivers/net/wan/Kconfig
+++ b/drivers/net/wan/Kconfig
@@ -25,7 +25,7 @@ if WAN
# There is no way to detect a comtrol sv11 - force it modular for now.
config HOSTESS_SV11
tristate "Comtrol Hostess SV-11 support"
- depends on ISA && m && ISA_DMA_API && INET && HDLC
+ depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS
help
Driver for Comtrol Hostess SV-11 network card which
operates on low speed synchronous serial links at up to
@@ -37,7 +37,7 @@ config HOSTESS_SV11
# The COSA/SRP driver has not been tested as non-modular yet.
config COSA
tristate "COSA/SRP sync serial boards support"
- depends on ISA && m && ISA_DMA_API && HDLC
+ depends on ISA && m && ISA_DMA_API && HDLC && VIRT_TO_BUS
---help---
Driver for COSA and SRP synchronous serial boards.
@@ -87,7 +87,7 @@ config LANMEDIA
# There is no way to detect a Sealevel board. Force it modular
config SEALEVEL_4021
tristate "Sealevel Systems 4021 support"
- depends on ISA && m && ISA_DMA_API && INET && HDLC
+ depends on ISA && m && ISA_DMA_API && INET && HDLC && VIRT_TO_BUS
help
This is a driver for the Sealevel Systems ACB 56 serial I/O adapter.
diff --git a/drivers/net/wireless/adm8211.c b/drivers/net/wireless/adm8211.c
index 17fcaabb2687..f07a61899545 100644
--- a/drivers/net/wireless/adm8211.c
+++ b/drivers/net/wireless/adm8211.c
@@ -1837,6 +1837,7 @@ static int adm8211_probe(struct pci_dev *pdev,
if (!priv->map) {
printk(KERN_ERR "%s (adm8211): Cannot map device memory\n",
pci_name(pdev));
+ err = -ENOMEM;
goto err_free_dev;
}
diff --git a/drivers/net/wireless/ath/ath.h b/drivers/net/wireless/ath/ath.h
index ccba4fea7269..1eebe2ea3dfb 100644
--- a/drivers/net/wireless/ath/ath.h
+++ b/drivers/net/wireless/ath/ath.h
@@ -64,6 +64,7 @@ enum ath_op_flags {
ATH_OP_HW_RESET,
ATH_OP_SCANNING,
ATH_OP_MULTI_CHANNEL,
+ ATH_OP_WOW_ENABLED,
};
enum ath_bus_type {
diff --git a/drivers/net/wireless/ath/ath10k/Makefile b/drivers/net/wireless/ath/ath10k/Makefile
index 8b1b1adb477a..f4dbb3e93bf8 100644
--- a/drivers/net/wireless/ath/ath10k/Makefile
+++ b/drivers/net/wireless/ath/ath10k/Makefile
@@ -8,11 +8,15 @@ ath10k_core-y += mac.o \
htt_tx.o \
txrx.o \
wmi.o \
- bmi.o
+ wmi-tlv.o \
+ bmi.o \
+ hw.o
ath10k_core-$(CONFIG_ATH10K_DEBUGFS) += spectral.o
ath10k_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
ath10k_core-$(CONFIG_ATH10K_TRACING) += trace.o
+ath10k_core-$(CONFIG_THERMAL) += thermal.o
+ath10k_core-$(CONFIG_MAC80211_DEBUGFS) += debugfs_sta.o
obj-$(CONFIG_ATH10K_PCI) += ath10k_pci.o
ath10k_pci-y += pci.o \
diff --git a/drivers/net/wireless/ath/ath10k/ce.c b/drivers/net/wireless/ath/ath10k/ce.c
index a156e6e48708..e508c65b6ba8 100644
--- a/drivers/net/wireless/ath/ath10k/ce.c
+++ b/drivers/net/wireless/ath/ath10k/ce.c
@@ -803,7 +803,7 @@ int ath10k_ce_disable_interrupts(struct ath10k *ar)
int ce_id;
for (ce_id = 0; ce_id < CE_COUNT; ce_id++) {
- u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
ath10k_ce_copy_complete_intr_disable(ar, ctrl_addr);
ath10k_ce_error_intr_disable(ar, ctrl_addr);
@@ -832,7 +832,7 @@ static int ath10k_ce_init_src_ring(struct ath10k *ar,
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
struct ath10k_ce_ring *src_ring = ce_state->src_ring;
- u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
+ u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id);
nentries = roundup_pow_of_two(attr->src_nentries);
@@ -869,7 +869,7 @@ static int ath10k_ce_init_dest_ring(struct ath10k *ar,
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
struct ath10k_ce_pipe *ce_state = &ar_pci->ce_states[ce_id];
struct ath10k_ce_ring *dest_ring = ce_state->dest_ring;
- u32 nentries, ctrl_addr = ath10k_ce_base_address(ce_id);
+ u32 nentries, ctrl_addr = ath10k_ce_base_address(ar, ce_id);
nentries = roundup_pow_of_two(attr->dest_nentries);
@@ -1051,7 +1051,7 @@ int ath10k_ce_init_pipe(struct ath10k *ar, unsigned int ce_id,
static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
{
- u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
ath10k_ce_src_ring_base_addr_set(ar, ctrl_addr, 0);
ath10k_ce_src_ring_size_set(ar, ctrl_addr, 0);
@@ -1061,7 +1061,7 @@ static void ath10k_ce_deinit_src_ring(struct ath10k *ar, unsigned int ce_id)
static void ath10k_ce_deinit_dest_ring(struct ath10k *ar, unsigned int ce_id)
{
- u32 ctrl_addr = ath10k_ce_base_address(ce_id);
+ u32 ctrl_addr = ath10k_ce_base_address(ar, ce_id);
ath10k_ce_dest_ring_base_addr_set(ar, ctrl_addr, 0);
ath10k_ce_dest_ring_size_set(ar, ctrl_addr, 0);
@@ -1093,10 +1093,12 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
(CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
+ BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC >
+ (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
ce_state->ar = ar;
ce_state->id = ce_id;
- ce_state->ctrl_addr = ath10k_ce_base_address(ce_id);
+ ce_state->ctrl_addr = ath10k_ce_base_address(ar, ce_id);
ce_state->attr_flags = attr->flags;
ce_state->src_sz_max = attr->src_sz_max;
diff --git a/drivers/net/wireless/ath/ath10k/ce.h b/drivers/net/wireless/ath/ath10k/ce.h
index 617a151e8ce4..c18647b87f71 100644
--- a/drivers/net/wireless/ath/ath10k/ce.h
+++ b/drivers/net/wireless/ath/ath10k/ce.h
@@ -394,7 +394,7 @@ struct ce_attr {
#define DST_WATERMARK_HIGH_RESET 0
#define DST_WATERMARK_ADDRESS 0x0050
-static inline u32 ath10k_ce_base_address(unsigned int ce_id)
+static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
{
return CE0_BASE_ADDRESS + (CE1_BASE_ADDRESS - CE0_BASE_ADDRESS) * ce_id;
}
diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c
index 7762061a1944..310e12bc078a 100644
--- a/drivers/net/wireless/ath/ath10k/core.c
+++ b/drivers/net/wireless/ath/ath10k/core.c
@@ -17,6 +17,7 @@
#include <linux/module.h>
#include <linux/firmware.h>
+#include <linux/of.h>
#include "core.h"
#include "mac.h"
@@ -27,20 +28,18 @@
#include "debug.h"
#include "htt.h"
#include "testmode.h"
+#include "wmi-ops.h"
unsigned int ath10k_debug_mask;
static bool uart_print;
-static unsigned int ath10k_p2p;
static bool skip_otp;
module_param_named(debug_mask, ath10k_debug_mask, uint, 0644);
module_param(uart_print, bool, 0644);
-module_param_named(p2p, ath10k_p2p, uint, 0644);
module_param(skip_otp, bool, 0644);
MODULE_PARM_DESC(debug_mask, "Debugging mask");
MODULE_PARM_DESC(uart_print, "Uart target debugging");
-MODULE_PARM_DESC(p2p, "Enable ath10k P2P support");
MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
static const struct ath10k_hw_params ath10k_hw_params_list[] = {
@@ -48,11 +47,57 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
.id = QCA988X_HW_2_0_VERSION,
.name = "qca988x hw2.0",
.patch_load_addr = QCA988X_HW_2_0_PATCH_LOAD_ADDR,
+ .uart_pin = 7,
.fw = {
.dir = QCA988X_HW_2_0_FW_DIR,
.fw = QCA988X_HW_2_0_FW_FILE,
.otp = QCA988X_HW_2_0_OTP_FILE,
.board = QCA988X_HW_2_0_BOARD_DATA_FILE,
+ .board_size = QCA988X_BOARD_DATA_SZ,
+ .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
+ },
+ },
+ {
+ .id = QCA6174_HW_2_1_VERSION,
+ .name = "qca6174 hw2.1",
+ .patch_load_addr = QCA6174_HW_2_1_PATCH_LOAD_ADDR,
+ .uart_pin = 6,
+ .fw = {
+ .dir = QCA6174_HW_2_1_FW_DIR,
+ .fw = QCA6174_HW_2_1_FW_FILE,
+ .otp = QCA6174_HW_2_1_OTP_FILE,
+ .board = QCA6174_HW_2_1_BOARD_DATA_FILE,
+ .board_size = QCA6174_BOARD_DATA_SZ,
+ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
+ },
+ },
+ {
+ .id = QCA6174_HW_3_0_VERSION,
+ .name = "qca6174 hw3.0",
+ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
+ .uart_pin = 6,
+ .fw = {
+ .dir = QCA6174_HW_3_0_FW_DIR,
+ .fw = QCA6174_HW_3_0_FW_FILE,
+ .otp = QCA6174_HW_3_0_OTP_FILE,
+ .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
+ .board_size = QCA6174_BOARD_DATA_SZ,
+ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
+ },
+ },
+ {
+ .id = QCA6174_HW_3_2_VERSION,
+ .name = "qca6174 hw3.2",
+ .patch_load_addr = QCA6174_HW_3_0_PATCH_LOAD_ADDR,
+ .uart_pin = 6,
+ .fw = {
+ /* uses same binaries as hw3.0 */
+ .dir = QCA6174_HW_3_0_FW_DIR,
+ .fw = QCA6174_HW_3_0_FW_FILE,
+ .otp = QCA6174_HW_3_0_OTP_FILE,
+ .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
+ .board_size = QCA6174_BOARD_DATA_SZ,
+ .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
},
},
};
@@ -146,8 +191,8 @@ static const struct firmware *ath10k_fetch_fw_file(struct ath10k *ar,
static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
size_t data_len)
{
- u32 board_data_size = QCA988X_BOARD_DATA_SZ;
- u32 board_ext_data_size = QCA988X_BOARD_EXT_DATA_SZ;
+ u32 board_data_size = ar->hw_params.fw.board_size;
+ u32 board_ext_data_size = ar->hw_params.fw.board_ext_size;
u32 board_ext_data_addr;
int ret;
@@ -193,7 +238,7 @@ static int ath10k_push_board_ext_data(struct ath10k *ar, const void *data,
static int ath10k_download_board_data(struct ath10k *ar, const void *data,
size_t data_len)
{
- u32 board_data_size = QCA988X_BOARD_DATA_SZ;
+ u32 board_data_size = ar->hw_params.fw.board_size;
u32 address;
int ret;
@@ -249,6 +294,63 @@ static int ath10k_download_cal_file(struct ath10k *ar)
return 0;
}
+static int ath10k_download_cal_dt(struct ath10k *ar)
+{
+ struct device_node *node;
+ int data_len;
+ void *data;
+ int ret;
+
+ node = ar->dev->of_node;
+ if (!node)
+ /* Device Tree is optional, don't print any warnings if
+ * there's no node for ath10k.
+ */
+ return -ENOENT;
+
+ if (!of_get_property(node, "qcom,ath10k-calibration-data",
+ &data_len)) {
+ /* The calibration data node is optional */
+ return -ENOENT;
+ }
+
+ if (data_len != QCA988X_CAL_DATA_LEN) {
+ ath10k_warn(ar, "invalid calibration data length in DT: %d\n",
+ data_len);
+ ret = -EMSGSIZE;
+ goto out;
+ }
+
+ data = kmalloc(data_len, GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = of_property_read_u8_array(node, "qcom,ath10k-calibration-data",
+ data, data_len);
+ if (ret) {
+ ath10k_warn(ar, "failed to read calibration data from DT: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ ret = ath10k_download_board_data(ar, data, data_len);
+ if (ret) {
+ ath10k_warn(ar, "failed to download calibration data from Device Tree: %d\n",
+ ret);
+ goto out_free;
+ }
+
+ ret = 0;
+
+out_free:
+ kfree(data);
+
+out:
+ return ret;
+}
+
static int ath10k_download_and_run_otp(struct ath10k *ar)
{
u32 result, address = ar->hw_params.patch_load_addr;
@@ -447,7 +549,7 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
int ie_id, i, index, bit, ret;
struct ath10k_fw_ie *hdr;
const u8 *data;
- __le32 *timestamp;
+ __le32 *timestamp, *version;
/* first fetch the firmware file (firmware-*.bin) */
ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
@@ -562,6 +664,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
ar->otp_len = ie_len;
break;
+ case ATH10K_FW_IE_WMI_OP_VERSION:
+ if (ie_len != sizeof(u32))
+ break;
+
+ version = (__le32 *)data;
+
+ ar->wmi.op_version = le32_to_cpup(version);
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",
+ ar->wmi.op_version);
+ break;
default:
ath10k_warn(ar, "Unknown FW IE: %u\n",
le32_to_cpu(hdr->id));
@@ -582,13 +695,6 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
goto err;
}
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
- !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
- ret = -EINVAL;
- goto err;
- }
-
/* now fetch the board file */
if (ar->hw_params.fw.board == NULL) {
ath10k_err(ar, "board data file not defined");
@@ -624,6 +730,13 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
/* calibration file is optional, don't check for any errors */
ath10k_fetch_cal_file(ar);
+ ar->fw_api = 4;
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
+
+ ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE);
+ if (ret == 0)
+ goto success;
+
ar->fw_api = 3;
ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
@@ -662,7 +775,17 @@ static int ath10k_download_cal_data(struct ath10k *ar)
}
ath10k_dbg(ar, ATH10K_DBG_BOOT,
- "boot did not find a calibration file, try OTP next: %d\n",
+ "boot did not find a calibration file, try DT next: %d\n",
+ ret);
+
+ ret = ath10k_download_cal_dt(ar);
+ if (ret == 0) {
+ ar->cal_mode = ATH10K_CAL_MODE_DT;
+ goto done;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT,
+ "boot did not find DT entry, try OTP next: %d\n",
ret);
ret = ath10k_download_and_run_otp(ar);
@@ -696,7 +819,7 @@ static int ath10k_init_uart(struct ath10k *ar)
if (!uart_print)
return 0;
- ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, 7);
+ ret = ath10k_bmi_write32(ar, hi_dbg_uart_txpin, ar->hw_params.uart_pin);
if (ret) {
ath10k_warn(ar, "could not enable UART prints (%d)\n", ret);
return ret;
@@ -764,6 +887,7 @@ static void ath10k_core_restart(struct work_struct *work)
complete_all(&ar->offchan_tx_completed);
complete_all(&ar->install_key_done);
complete_all(&ar->vdev_setup_done);
+ complete_all(&ar->thermal.wmi_sync);
wake_up(&ar->htt.empty_tx_wq);
wake_up(&ar->wmi.tx_credits_wq);
wake_up(&ar->peer_mapping_wq);
@@ -799,15 +923,63 @@ static void ath10k_core_restart(struct work_struct *work)
mutex_unlock(&ar->conf_mutex);
}
-static void ath10k_core_init_max_sta_count(struct ath10k *ar)
+static int ath10k_core_init_firmware_features(struct ath10k *ar)
{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ar->max_num_peers = TARGET_10X_NUM_PEERS;
- ar->max_num_stations = TARGET_10X_NUM_STATIONS;
- } else {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
+ !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
+ return -EINVAL;
+ }
+
+ if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) {
+ ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n",
+ ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version);
+ return -EINVAL;
+ }
+
+ /* Backwards compatibility for firmwares without
+ * ATH10K_FW_IE_WMI_OP_VERSION.
+ */
+ if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+ if (test_bit(ATH10K_FW_FEATURE_WMI_10_2,
+ ar->fw_features))
+ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2;
+ else
+ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
+ } else {
+ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN;
+ }
+ }
+
+ switch (ar->wmi.op_version) {
+ case ATH10K_FW_WMI_OP_VERSION_MAIN:
ar->max_num_peers = TARGET_NUM_PEERS;
ar->max_num_stations = TARGET_NUM_STATIONS;
+ ar->max_num_vdevs = TARGET_NUM_VDEVS;
+ ar->htt.max_num_pending_tx = TARGET_NUM_MSDU_DESC;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_10_1:
+ case ATH10K_FW_WMI_OP_VERSION_10_2:
+ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ ar->max_num_peers = TARGET_10X_NUM_PEERS;
+ ar->max_num_stations = TARGET_10X_NUM_STATIONS;
+ ar->max_num_vdevs = TARGET_10X_NUM_VDEVS;
+ ar->htt.max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
+ ar->max_num_peers = TARGET_TLV_NUM_PEERS;
+ ar->max_num_stations = TARGET_TLV_NUM_STATIONS;
+ ar->max_num_vdevs = TARGET_TLV_NUM_VDEVS;
+ ar->htt.max_num_pending_tx = TARGET_TLV_NUM_MSDU_DESC;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_UNSET:
+ case ATH10K_FW_WMI_OP_VERSION_MAX:
+ WARN_ON(1);
+ return -EINVAL;
}
+
+ return 0;
}
int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
@@ -932,6 +1104,18 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
goto err_hif_stop;
}
+ /* If firmware indicates Full Rx Reorder support it must be used in a
+ * slightly different manner. Let HTT code know.
+ */
+ ar->htt.rx_ring.in_ord_rx = !!(test_bit(WMI_SERVICE_RX_FULL_REORDER,
+ ar->wmi.svc_map));
+
+ status = ath10k_htt_rx_ring_refill(ar);
+ if (status) {
+ ath10k_err(ar, "failed to refill htt rx ring: %d\n", status);
+ goto err_hif_stop;
+ }
+
/* we don't care about HTT in UTF mode */
if (mode == ATH10K_FIRMWARE_MODE_NORMAL) {
status = ath10k_htt_setup(&ar->htt);
@@ -945,10 +1129,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
if (status)
goto err_hif_stop;
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- ar->free_vdev_map = (1LL << TARGET_10X_NUM_VDEVS) - 1;
- else
- ar->free_vdev_map = (1LL << TARGET_NUM_VDEVS) - 1;
+ ar->free_vdev_map = (1LL << ar->max_num_vdevs) - 1;
INIT_LIST_HEAD(&ar->arvifs);
@@ -1025,8 +1206,7 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_bmi_get_target_info(ar, &target_info);
if (ret) {
ath10k_err(ar, "could not get target info (%d)\n", ret);
- ath10k_hif_power_down(ar);
- return ret;
+ goto err_power_down;
}
ar->target_version = target_info.version;
@@ -1035,28 +1215,28 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ret = ath10k_init_hw_params(ar);
if (ret) {
ath10k_err(ar, "could not get hw params (%d)\n", ret);
- ath10k_hif_power_down(ar);
- return ret;
+ goto err_power_down;
}
ret = ath10k_core_fetch_firmware_files(ar);
if (ret) {
ath10k_err(ar, "could not fetch firmware files (%d)\n", ret);
- ath10k_hif_power_down(ar);
- return ret;
+ goto err_power_down;
}
- ath10k_core_init_max_sta_count(ar);
+ ret = ath10k_core_init_firmware_features(ar);
+ if (ret) {
+ ath10k_err(ar, "fatal problem with firmware features: %d\n",
+ ret);
+ goto err_free_firmware_files;
+ }
mutex_lock(&ar->conf_mutex);
ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
if (ret) {
ath10k_err(ar, "could not init core (%d)\n", ret);
- ath10k_core_free_firmware_files(ar);
- ath10k_hif_power_down(ar);
- mutex_unlock(&ar->conf_mutex);
- return ret;
+ goto err_unlock;
}
ath10k_print_driver_info(ar);
@@ -1066,34 +1246,17 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
ath10k_hif_power_down(ar);
return 0;
-}
-
-static int ath10k_core_check_chip_id(struct ath10k *ar)
-{
- u32 hw_revision = MS(ar->chip_id, SOC_CHIP_ID_REV);
-
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip_id 0x%08x hw_revision 0x%x\n",
- ar->chip_id, hw_revision);
- /* Check that we are not using hw1.0 (some of them have same pci id
- * as hw2.0) before doing anything else as ath10k crashes horribly
- * due to missing hw1.0 workarounds. */
- switch (hw_revision) {
- case QCA988X_HW_1_0_CHIP_ID_REV:
- ath10k_err(ar, "ERROR: qca988x hw1.0 is not supported\n");
- return -EOPNOTSUPP;
+err_unlock:
+ mutex_unlock(&ar->conf_mutex);
- case QCA988X_HW_2_0_CHIP_ID_REV:
- /* known hardware revision, continue normally */
- return 0;
+err_free_firmware_files:
+ ath10k_core_free_firmware_files(ar);
- default:
- ath10k_warn(ar, "Warning: hardware revision unknown (0x%x), expect problems\n",
- ar->chip_id);
- return 0;
- }
+err_power_down:
+ ath10k_hif_power_down(ar);
- return 0;
+ return ret;
}
static void ath10k_core_register_work(struct work_struct *work)
@@ -1125,9 +1288,18 @@ static void ath10k_core_register_work(struct work_struct *work)
goto err_debug_destroy;
}
+ status = ath10k_thermal_register(ar);
+ if (status) {
+ ath10k_err(ar, "could not register thermal device: %d\n",
+ status);
+ goto err_spectral_destroy;
+ }
+
set_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags);
return;
+err_spectral_destroy:
+ ath10k_spectral_destroy(ar);
err_debug_destroy:
ath10k_debug_destroy(ar);
err_unregister_mac:
@@ -1143,16 +1315,7 @@ err:
int ath10k_core_register(struct ath10k *ar, u32 chip_id)
{
- int status;
-
ar->chip_id = chip_id;
-
- status = ath10k_core_check_chip_id(ar);
- if (status) {
- ath10k_err(ar, "Unsupported chip id 0x%08x\n", ar->chip_id);
- return status;
- }
-
queue_work(ar->workqueue, &ar->register_work);
return 0;
@@ -1166,6 +1329,7 @@ void ath10k_core_unregister(struct ath10k *ar)
if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
return;
+ ath10k_thermal_unregister(ar);
/* Stop spectral before unregistering from mac80211 to remove the
* relayfs debugfs file cleanly. Otherwise the parent debugfs tree
* would be already be free'd recursively, leading to a double free.
@@ -1187,6 +1351,7 @@ EXPORT_SYMBOL(ath10k_core_unregister);
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
enum ath10k_bus bus,
+ enum ath10k_hw_rev hw_rev,
const struct ath10k_hif_ops *hif_ops)
{
struct ath10k *ar;
@@ -1198,13 +1363,25 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
ar->ath_common.priv = ar;
ar->ath_common.hw = ar->hw;
-
- ar->p2p = !!ath10k_p2p;
ar->dev = dev;
-
+ ar->hw_rev = hw_rev;
ar->hif.ops = hif_ops;
ar->hif.bus = bus;
+ switch (hw_rev) {
+ case ATH10K_HW_QCA988X:
+ ar->regs = &qca988x_regs;
+ break;
+ case ATH10K_HW_QCA6174:
+ ar->regs = &qca6174_regs;
+ break;
+ default:
+ ath10k_err(ar, "unsupported core hardware revision %d\n",
+ hw_rev);
+ ret = -ENOTSUPP;
+ goto err_free_mac;
+ }
+
init_completion(&ar->scan.started);
init_completion(&ar->scan.completed);
init_completion(&ar->scan.on_channel);
@@ -1212,6 +1389,7 @@ struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
init_completion(&ar->install_key_done);
init_completion(&ar->vdev_setup_done);
+ init_completion(&ar->thermal.wmi_sync);
INIT_DELAYED_WORK(&ar->scan.timeout, ath10k_scan_timeout_work);
diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h
index 514c219263a5..d60e46fe6d19 100644
--- a/drivers/net/wireless/ath/ath10k/core.h
+++ b/drivers/net/wireless/ath/ath10k/core.h
@@ -34,6 +34,7 @@
#include "../regd.h"
#include "../dfs_pattern_detector.h"
#include "spectral.h"
+#include "thermal.h"
#define MS(_v, _f) (((_v) & _f##_MASK) >> _f##_LSB)
#define SM(_v, _f) (((_v) << _f##_LSB) & _f##_MASK)
@@ -96,6 +97,11 @@ struct ath10k_skb_cb {
} bcn;
} __packed;
+struct ath10k_skb_rxcb {
+ dma_addr_t paddr;
+ struct hlist_node hlist;
+};
+
static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
{
BUILD_BUG_ON(sizeof(struct ath10k_skb_cb) >
@@ -103,6 +109,15 @@ static inline struct ath10k_skb_cb *ATH10K_SKB_CB(struct sk_buff *skb)
return (struct ath10k_skb_cb *)&IEEE80211_SKB_CB(skb)->driver_data;
}
+static inline struct ath10k_skb_rxcb *ATH10K_SKB_RXCB(struct sk_buff *skb)
+{
+ BUILD_BUG_ON(sizeof(struct ath10k_skb_rxcb) > sizeof(skb->cb));
+ return (struct ath10k_skb_rxcb *)skb->cb;
+}
+
+#define ATH10K_RXCB_SKB(rxcb) \
+ container_of((void *)rxcb, struct sk_buff, cb)
+
static inline u32 host_interest_item_address(u32 item_offset)
{
return QCA988X_HOST_INTEREST_ADDRESS + item_offset;
@@ -120,6 +135,7 @@ struct ath10k_mem_chunk {
};
struct ath10k_wmi {
+ enum ath10k_fw_wmi_op_version op_version;
enum ath10k_htc_ep_id eid;
struct completion service_ready;
struct completion unified_ready;
@@ -128,6 +144,7 @@ struct ath10k_wmi {
struct wmi_cmd_map *cmd;
struct wmi_vdev_param_map *vdev_param;
struct wmi_pdev_param_map *pdev_param;
+ const struct wmi_ops *ops;
u32 num_mem_chunks;
struct ath10k_mem_chunk mem_chunks[WMI_MAX_MEM_REQS];
@@ -236,10 +253,21 @@ struct ath10k_sta {
u32 smps;
struct work_struct update_wk;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+ /* protected by conf_mutex */
+ bool aggr_mode;
+#endif
};
#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
+enum ath10k_beacon_state {
+ ATH10K_BEACON_SCHEDULED = 0,
+ ATH10K_BEACON_SENDING,
+ ATH10K_BEACON_SENT,
+};
+
struct ath10k_vif {
struct list_head list;
@@ -250,7 +278,7 @@ struct ath10k_vif {
u32 dtim_period;
struct sk_buff *beacon;
/* protected by data_lock */
- bool beacon_sent;
+ enum ath10k_beacon_state beacon_state;
void *beacon_buf;
dma_addr_t beacon_paddr;
@@ -263,10 +291,8 @@ struct ath10k_vif {
u32 aid;
u8 bssid[ETH_ALEN];
- struct work_struct wep_key_work;
struct ieee80211_key_conf *wep_keys[WMI_MAX_KEY_INDEX + 1];
- u8 def_wep_key_idx;
- u8 def_wep_key_newidx;
+ s8 def_wep_key_idx;
u16 tx_seq_no;
@@ -293,6 +319,7 @@ struct ath10k_vif {
bool use_cts_prot;
int num_legacy_stations;
int txpower;
+ struct wmi_wmm_params_all_arg wmm_params;
};
struct ath10k_vif_iter {
@@ -323,8 +350,10 @@ struct ath10k_debug {
/* protected by conf_mutex */
u32 fw_dbglog_mask;
+ u32 fw_dbglog_level;
u32 pktlog_filter;
u32 reg_addr;
+ u32 nf_cal_period;
u8 htt_max_amsdu;
u8 htt_max_ampdu;
@@ -369,7 +398,7 @@ enum ath10k_fw_features {
/* wmi_mgmt_rx_hdr contains extra RSSI information */
ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX = 0,
- /* firmware from 10X branch */
+ /* Firmware from 10X branch. Deprecated, don't use in new code. */
ATH10K_FW_FEATURE_WMI_10X = 1,
/* firmware support tx frame management over WMI, otherwise it's HTT */
@@ -378,8 +407,9 @@ enum ath10k_fw_features {
/* Firmware does not support P2P */
ATH10K_FW_FEATURE_NO_P2P = 3,
- /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature bit
- * is required to be set as well.
+ /* Firmware 10.2 feature bit. The ATH10K_FW_FEATURE_WMI_10X feature
+ * bit is required to be set as well. Deprecated, don't use in new
+ * code.
*/
ATH10K_FW_FEATURE_WMI_10_2 = 4,
@@ -401,6 +431,7 @@ enum ath10k_dev_flags {
enum ath10k_cal_mode {
ATH10K_CAL_MODE_FILE,
ATH10K_CAL_MODE_OTP,
+ ATH10K_CAL_MODE_DT,
};
static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
@@ -410,6 +441,8 @@ static inline const char *ath10k_cal_mode_str(enum ath10k_cal_mode mode)
return "file";
case ATH10K_CAL_MODE_OTP:
return "otp";
+ case ATH10K_CAL_MODE_DT:
+ return "dt";
}
return "unknown";
@@ -444,6 +477,7 @@ struct ath10k {
struct device *dev;
u8 mac_addr[ETH_ALEN];
+ enum ath10k_hw_rev hw_rev;
u32 chip_id;
u32 target_version;
u8 fw_version_major;
@@ -459,9 +493,6 @@ struct ath10k {
DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
- struct targetdef *targetdef;
- struct hostdef *hostdef;
-
bool p2p;
struct {
@@ -471,6 +502,7 @@ struct ath10k {
struct completion target_suspend;
+ const struct ath10k_hw_regs *regs;
struct ath10k_bmi bmi;
struct ath10k_wmi wmi;
struct ath10k_htc htc;
@@ -480,12 +512,15 @@ struct ath10k {
u32 id;
const char *name;
u32 patch_load_addr;
+ int uart_pin;
struct ath10k_hw_params_fw {
const char *dir;
const char *fw;
const char *otp;
const char *board;
+ size_t board_size;
+ size_t board_ext_size;
} fw;
} hw_params;
@@ -548,7 +583,6 @@ struct ath10k {
u8 cfg_tx_chainmask;
u8 cfg_rx_chainmask;
- struct wmi_pdev_set_wmm_params_arg wmm_params;
struct completion install_key_done;
struct completion vdev_setup_done;
@@ -571,6 +605,7 @@ struct ath10k {
int max_num_peers;
int max_num_stations;
+ int max_num_vdevs;
struct work_struct offchan_tx_work;
struct sk_buff_head offchan_tx_queue;
@@ -610,6 +645,7 @@ struct ath10k {
/* protected by conf_mutex */
const struct firmware *utf;
DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
+ enum ath10k_fw_wmi_op_version orig_wmi_op_version;
/* protected by data_lock */
bool utf_monitor;
@@ -622,12 +658,15 @@ struct ath10k {
u32 fw_cold_reset_counter;
} stats;
+ struct ath10k_thermal thermal;
+
/* must be last */
u8 drv_priv[0] __aligned(sizeof(void *));
};
struct ath10k *ath10k_core_create(size_t priv_size, struct device *dev,
enum ath10k_bus bus,
+ enum ath10k_hw_rev hw_rev,
const struct ath10k_hif_ops *hif_ops);
void ath10k_core_destroy(struct ath10k *ar);
diff --git a/drivers/net/wireless/ath/ath10k/debug.c b/drivers/net/wireless/ath/ath10k/debug.c
index a716758f14b0..d2281e5c2ffe 100644
--- a/drivers/net/wireless/ath/ath10k/debug.c
+++ b/drivers/net/wireless/ath/ath10k/debug.c
@@ -23,6 +23,7 @@
#include "core.h"
#include "debug.h"
#include "hif.h"
+#include "wmi-ops.h"
/* ms */
#define ATH10K_DEBUG_HTT_STATS_INTERVAL 1000
@@ -123,7 +124,7 @@ EXPORT_SYMBOL(ath10k_info);
void ath10k_print_driver_info(struct ath10k *ar)
{
- ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d.%d.%d.%d cal %s max_sta %d\n",
+ ath10k_info(ar, "%s (0x%08x, 0x%08x) fw %s api %d htt %d.%d wmi %d cal %s max_sta %d\n",
ar->hw_params.name,
ar->target_version,
ar->chip_id,
@@ -131,10 +132,7 @@ void ath10k_print_driver_info(struct ath10k *ar)
ar->fw_api,
ar->htt.target_version_major,
ar->htt.target_version_minor,
- ar->fw_version_major,
- ar->fw_version_minor,
- ar->fw_version_release,
- ar->fw_version_build,
+ ar->wmi.op_version,
ath10k_cal_mode_str(ar->cal_mode),
ar->max_num_stations);
ath10k_info(ar, "debug %d debugfs %d tracing %d dfs %d testmode %d\n",
@@ -373,7 +371,7 @@ static int ath10k_debug_fw_stats_request(struct ath10k *ar)
ret = wait_for_completion_timeout(&ar->debug.fw_stats_complete,
1*HZ);
- if (ret <= 0)
+ if (ret == 0)
return -ETIMEDOUT;
spin_lock_bh(&ar->data_lock);
@@ -1320,10 +1318,10 @@ static ssize_t ath10k_read_fw_dbglog(struct file *file,
{
struct ath10k *ar = file->private_data;
unsigned int len;
- char buf[32];
+ char buf[64];
- len = scnprintf(buf, sizeof(buf), "0x%08x\n",
- ar->debug.fw_dbglog_mask);
+ len = scnprintf(buf, sizeof(buf), "0x%08x %u\n",
+ ar->debug.fw_dbglog_mask, ar->debug.fw_dbglog_level);
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
@@ -1333,19 +1331,32 @@ static ssize_t ath10k_write_fw_dbglog(struct file *file,
size_t count, loff_t *ppos)
{
struct ath10k *ar = file->private_data;
- unsigned long mask;
int ret;
+ char buf[64];
+ unsigned int log_level, mask;
- ret = kstrtoul_from_user(user_buf, count, 0, &mask);
- if (ret)
- return ret;
+ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+
+ /* make sure that buf is null terminated */
+ buf[sizeof(buf) - 1] = 0;
+
+ ret = sscanf(buf, "%x %u", &mask, &log_level);
+
+ if (!ret)
+ return -EINVAL;
+
+ if (ret == 1)
+ /* default if user did not specify */
+ log_level = ATH10K_DBGLOG_LEVEL_WARN;
mutex_lock(&ar->conf_mutex);
ar->debug.fw_dbglog_mask = mask;
+ ar->debug.fw_dbglog_level = log_level;
if (ar->state == ATH10K_STATE_ON) {
- ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
+ ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
+ ar->debug.fw_dbglog_level);
if (ret) {
ath10k_warn(ar, "dbglog cfg failed from debugfs: %d\n",
ret);
@@ -1607,6 +1618,73 @@ static const struct file_operations fops_cal_data = {
.llseek = default_llseek,
};
+static ssize_t ath10k_read_nf_cal_period(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned int len;
+ char buf[32];
+
+ len = scnprintf(buf, sizeof(buf), "%d\n",
+ ar->debug.nf_cal_period);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_write_nf_cal_period(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath10k *ar = file->private_data;
+ unsigned long period;
+ int ret;
+
+ ret = kstrtoul_from_user(user_buf, count, 0, &period);
+ if (ret)
+ return ret;
+
+ if (period > WMI_PDEV_PARAM_CAL_PERIOD_MAX)
+ return -EINVAL;
+
+ /* there's no way to switch back to the firmware default */
+ if (period == 0)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+
+ ar->debug.nf_cal_period = period;
+
+ if (ar->state != ATH10K_STATE_ON) {
+ /* firmware is not running, nothing else to do */
+ ret = count;
+ goto exit;
+ }
+
+ ret = ath10k_wmi_pdev_set_param(ar, ar->wmi.pdev_param->cal_period,
+ ar->debug.nf_cal_period);
+ if (ret) {
+ ath10k_warn(ar, "cal period cfg failed from debugfs: %d\n",
+ ret);
+ goto exit;
+ }
+
+ ret = count;
+
+exit:
+ mutex_unlock(&ar->conf_mutex);
+
+ return ret;
+}
+
+static const struct file_operations fops_nf_cal_period = {
+ .read = ath10k_read_nf_cal_period,
+ .write = ath10k_write_nf_cal_period,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
int ath10k_debug_start(struct ath10k *ar)
{
int ret;
@@ -1620,7 +1698,8 @@ int ath10k_debug_start(struct ath10k *ar)
ret);
if (ar->debug.fw_dbglog_mask) {
- ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask);
+ ret = ath10k_wmi_dbglog_cfg(ar, ar->debug.fw_dbglog_mask,
+ ATH10K_DBGLOG_LEVEL_WARN);
if (ret)
/* not serious */
ath10k_warn(ar, "failed to enable dbglog during start: %d",
@@ -1642,6 +1721,16 @@ int ath10k_debug_start(struct ath10k *ar)
ath10k_warn(ar, "failed to disable pktlog: %d\n", ret);
}
+ if (ar->debug.nf_cal_period) {
+ ret = ath10k_wmi_pdev_set_param(ar,
+ ar->wmi.pdev_param->cal_period,
+ ar->debug.nf_cal_period);
+ if (ret)
+ /* not serious */
+ ath10k_warn(ar, "cal period cfg failed from debug start: %d\n",
+ ret);
+ }
+
return ret;
}
@@ -1880,6 +1969,9 @@ int ath10k_debug_register(struct ath10k *ar)
debugfs_create_file("cal_data", S_IRUSR, ar->debug.debugfs_phy,
ar, &fops_cal_data);
+ debugfs_create_file("nf_cal_period", S_IRUSR | S_IWUSR,
+ ar->debug.debugfs_phy, ar, &fops_nf_cal_period);
+
if (config_enabled(CONFIG_ATH10K_DFS_CERTIFIED)) {
debugfs_create_file("dfs_simulate_radar", S_IWUSR,
ar->debug.debugfs_phy, ar,
diff --git a/drivers/net/wireless/ath/ath10k/debug.h b/drivers/net/wireless/ath/ath10k/debug.h
index 1b87a5dbec53..a12b8323f9f1 100644
--- a/drivers/net/wireless/ath/ath10k/debug.h
+++ b/drivers/net/wireless/ath/ath10k/debug.h
@@ -48,6 +48,12 @@ enum ath10k_pktlog_filter {
ATH10K_PKTLOG_ANY = 0x00000001f,
};
+enum ath10k_dbg_aggr_mode {
+ ATH10K_DBG_AGGR_MODE_AUTO,
+ ATH10K_DBG_AGGR_MODE_MANUAL,
+ ATH10K_DBG_AGGR_MODE_MAX,
+};
+
extern unsigned int ath10k_debug_mask;
__printf(2, 3) void ath10k_info(struct ath10k *ar, const char *fmt, ...);
@@ -77,7 +83,6 @@ int ath10k_debug_get_et_sset_count(struct ieee80211_hw *hw,
void ath10k_debug_get_et_stats(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ethtool_stats *stats, u64 *data);
-
#else
static inline int ath10k_debug_start(struct ath10k *ar)
{
@@ -129,6 +134,10 @@ ath10k_debug_get_new_fw_crash_data(struct ath10k *ar)
#define ath10k_debug_get_et_stats NULL
#endif /* CONFIG_ATH10K_DEBUGFS */
+#ifdef CONFIG_MAC80211_DEBUGFS
+void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct dentry *dir);
+#endif /* CONFIG_MAC80211_DEBUGFS */
#ifdef CONFIG_ATH10K_DEBUG
__printf(3, 4) void ath10k_dbg(struct ath10k *ar,
diff --git a/drivers/net/wireless/ath/ath10k/debugfs_sta.c b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
new file mode 100644
index 000000000000..95b5c49374e0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/debugfs_sta.c
@@ -0,0 +1,243 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "wmi-ops.h"
+#include "debug.h"
+
+static ssize_t ath10k_dbg_sta_read_aggr_mode(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ char buf[32];
+ int len = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ len = scnprintf(buf, sizeof(buf) - len, "aggregation mode: %s\n",
+ (arsta->aggr_mode == ATH10K_DBG_AGGR_MODE_AUTO) ?
+ "auto" : "manual");
+ mutex_unlock(&ar->conf_mutex);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t ath10k_dbg_sta_write_aggr_mode(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ u32 aggr_mode;
+ int ret;
+
+ if (kstrtouint_from_user(user_buf, count, 0, &aggr_mode))
+ return -EINVAL;
+
+ if (aggr_mode >= ATH10K_DBG_AGGR_MODE_MAX)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ if ((ar->state != ATH10K_STATE_ON) ||
+ (aggr_mode == arsta->aggr_mode)) {
+ ret = count;
+ goto out;
+ }
+
+ ret = ath10k_wmi_addba_clear_resp(ar, arsta->arvif->vdev_id, sta->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to clear addba session ret: %d\n", ret);
+ goto out;
+ }
+
+ arsta->aggr_mode = aggr_mode;
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static const struct file_operations fops_aggr_mode = {
+ .read = ath10k_dbg_sta_read_aggr_mode,
+ .write = ath10k_dbg_sta_write_aggr_mode,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath10k_dbg_sta_write_addba(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ u32 tid, buf_size;
+ int ret;
+ char buf[64];
+
+ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+
+ /* make sure that buf is null terminated */
+ buf[sizeof(buf) - 1] = '\0';
+
+ ret = sscanf(buf, "%u %u", &tid, &buf_size);
+ if (ret != 2)
+ return -EINVAL;
+
+ /* Valid TID values are 0 through 15 */
+ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ if ((ar->state != ATH10K_STATE_ON) ||
+ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
+ ret = count;
+ goto out;
+ }
+
+ ret = ath10k_wmi_addba_send(ar, arsta->arvif->vdev_id, sta->addr,
+ tid, buf_size);
+ if (ret) {
+ ath10k_warn(ar, "failed to send addba request: vdev_id %u peer %pM tid %u buf_size %u\n",
+ arsta->arvif->vdev_id, sta->addr, tid, buf_size);
+ }
+
+ ret = count;
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static const struct file_operations fops_addba = {
+ .write = ath10k_dbg_sta_write_addba,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath10k_dbg_sta_write_addba_resp(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ u32 tid, status;
+ int ret;
+ char buf[64];
+
+ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+
+ /* make sure that buf is null terminated */
+ buf[sizeof(buf) - 1] = '\0';
+
+ ret = sscanf(buf, "%u %u", &tid, &status);
+ if (ret != 2)
+ return -EINVAL;
+
+ /* Valid TID values are 0 through 15 */
+ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ if ((ar->state != ATH10K_STATE_ON) ||
+ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
+ ret = count;
+ goto out;
+ }
+
+ ret = ath10k_wmi_addba_set_resp(ar, arsta->arvif->vdev_id, sta->addr,
+ tid, status);
+ if (ret) {
+ ath10k_warn(ar, "failed to send addba response: vdev_id %u peer %pM tid %u status%u\n",
+ arsta->arvif->vdev_id, sta->addr, tid, status);
+ }
+ ret = count;
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static const struct file_operations fops_addba_resp = {
+ .write = ath10k_dbg_sta_write_addba_resp,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+static ssize_t ath10k_dbg_sta_write_delba(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_sta *sta = file->private_data;
+ struct ath10k_sta *arsta = (struct ath10k_sta *)sta->drv_priv;
+ struct ath10k *ar = arsta->arvif->ar;
+ u32 tid, initiator, reason;
+ int ret;
+ char buf[64];
+
+ simple_write_to_buffer(buf, sizeof(buf) - 1, ppos, user_buf, count);
+
+ /* make sure that buf is null terminated */
+ buf[sizeof(buf) - 1] = '\0';
+
+ ret = sscanf(buf, "%u %u %u", &tid, &initiator, &reason);
+ if (ret != 3)
+ return -EINVAL;
+
+ /* Valid TID values are 0 through 15 */
+ if (tid > HTT_DATA_TX_EXT_TID_MGMT - 2)
+ return -EINVAL;
+
+ mutex_lock(&ar->conf_mutex);
+ if ((ar->state != ATH10K_STATE_ON) ||
+ (arsta->aggr_mode != ATH10K_DBG_AGGR_MODE_MANUAL)) {
+ ret = count;
+ goto out;
+ }
+
+ ret = ath10k_wmi_delba_send(ar, arsta->arvif->vdev_id, sta->addr,
+ tid, initiator, reason);
+ if (ret) {
+ ath10k_warn(ar, "failed to send delba: vdev_id %u peer %pM tid %u initiator %u reason %u\n",
+ arsta->arvif->vdev_id, sta->addr, tid, initiator,
+ reason);
+ }
+ ret = count;
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static const struct file_operations fops_delba = {
+ .write = ath10k_dbg_sta_write_delba,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+void ath10k_sta_add_debugfs(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta, struct dentry *dir)
+{
+ debugfs_create_file("aggr_mode", S_IRUGO | S_IWUSR, dir, sta,
+ &fops_aggr_mode);
+ debugfs_create_file("addba", S_IWUSR, dir, sta, &fops_addba);
+ debugfs_create_file("addba_resp", S_IWUSR, dir, sta, &fops_addba_resp);
+ debugfs_create_file("delba", S_IWUSR, dir, sta, &fops_delba);
+}
diff --git a/drivers/net/wireless/ath/ath10k/htc.c b/drivers/net/wireless/ath/ath10k/htc.c
index f1946a6be442..2fd9e180272b 100644
--- a/drivers/net/wireless/ath/ath10k/htc.c
+++ b/drivers/net/wireless/ath/ath10k/htc.c
@@ -703,11 +703,9 @@ int ath10k_htc_connect_service(struct ath10k_htc *htc,
/* wait for response */
status = wait_for_completion_timeout(&htc->ctl_resp,
ATH10K_HTC_CONN_SVC_TIMEOUT_HZ);
- if (status <= 0) {
- if (status == 0)
- status = -ETIMEDOUT;
+ if (status == 0) {
ath10k_err(ar, "Service connect timeout: %d\n", status);
- return status;
+ return -ETIMEDOUT;
}
/* we controlled the buffer creation, it's aligned */
diff --git a/drivers/net/wireless/ath/ath10k/htt.c b/drivers/net/wireless/ath/ath10k/htt.c
index 56cb4aceb383..4f59ab923e48 100644
--- a/drivers/net/wireless/ath/ath10k/htt.c
+++ b/drivers/net/wireless/ath/ath10k/htt.c
@@ -53,7 +53,6 @@ int ath10k_htt_init(struct ath10k *ar)
struct ath10k_htt *htt = &ar->htt;
htt->ar = ar;
- htt->max_throughput_mbps = 800;
/*
* Prefetch enough data to satisfy target
@@ -102,7 +101,7 @@ int ath10k_htt_setup(struct ath10k_htt *htt)
status = wait_for_completion_timeout(&htt->target_version_received,
HTT_TARGET_VERSION_TIMEOUT_HZ);
- if (status <= 0) {
+ if (status == 0) {
ath10k_warn(ar, "htt version request timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h
index 1bd5545af903..874bf44ff7a2 100644
--- a/drivers/net/wireless/ath/ath10k/htt.h
+++ b/drivers/net/wireless/ath/ath10k/htt.h
@@ -21,6 +21,7 @@
#include <linux/bug.h>
#include <linux/interrupt.h>
#include <linux/dmapool.h>
+#include <linux/hashtable.h>
#include <net/mac80211.h>
#include "htc.h"
@@ -286,7 +287,19 @@ enum htt_t2h_msg_type {
HTT_T2H_MSG_TYPE_RC_UPDATE_IND = 0xc,
HTT_T2H_MSG_TYPE_TX_INSPECT_IND = 0xd,
HTT_T2H_MSG_TYPE_MGMT_TX_COMPLETION = 0xe,
+ HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND = 0xf,
+ HTT_T2H_MSG_TYPE_RX_PN_IND = 0x10,
+ HTT_T2H_MSG_TYPE_RX_OFFLOAD_DELIVER_IND = 0x11,
+ HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND = 0x12,
+ /* 0x13 reservd */
+ HTT_T2H_MSG_TYPE_WDI_IPA_OP_RESPONSE = 0x14,
+
+ /* FIXME: Do not depend on this event id. Numbering of this event id is
+ * broken across different firmware revisions and HTT version fails to
+ * indicate this.
+ */
HTT_T2H_MSG_TYPE_TEST,
+
/* keep this last */
HTT_T2H_NUM_MSGS
};
@@ -655,6 +668,53 @@ struct htt_rx_fragment_indication {
#define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_MASK 0x00000FC0
#define HTT_RX_FRAG_IND_INFO1_FLUSH_SEQ_NUM_END_LSB 6
+struct htt_rx_pn_ind {
+ __le16 peer_id;
+ u8 tid;
+ u8 seqno_start;
+ u8 seqno_end;
+ u8 pn_ie_count;
+ u8 reserved;
+ u8 pn_ies[0];
+} __packed;
+
+struct htt_rx_offload_msdu {
+ __le16 msdu_len;
+ __le16 peer_id;
+ u8 vdev_id;
+ u8 tid;
+ u8 fw_desc;
+ u8 payload[0];
+} __packed;
+
+struct htt_rx_offload_ind {
+ u8 reserved;
+ __le16 msdu_count;
+} __packed;
+
+struct htt_rx_in_ord_msdu_desc {
+ __le32 msdu_paddr;
+ __le16 msdu_len;
+ u8 fw_desc;
+ u8 reserved;
+} __packed;
+
+struct htt_rx_in_ord_ind {
+ u8 info;
+ __le16 peer_id;
+ u8 vdev_id;
+ u8 reserved;
+ __le16 msdu_count;
+ struct htt_rx_in_ord_msdu_desc msdu_descs[0];
+} __packed;
+
+#define HTT_RX_IN_ORD_IND_INFO_TID_MASK 0x0000001f
+#define HTT_RX_IN_ORD_IND_INFO_TID_LSB 0
+#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK 0x00000020
+#define HTT_RX_IN_ORD_IND_INFO_OFFLOAD_LSB 5
+#define HTT_RX_IN_ORD_IND_INFO_FRAG_MASK 0x00000040
+#define HTT_RX_IN_ORD_IND_INFO_FRAG_LSB 6
+
/*
* target -> host test message definition
*
@@ -1150,6 +1210,9 @@ struct htt_resp {
struct htt_rx_test rx_test;
struct htt_pktlog_msg pktlog_msg;
struct htt_stats_conf stats_conf;
+ struct htt_rx_pn_ind rx_pn_ind;
+ struct htt_rx_offload_ind rx_offload_ind;
+ struct htt_rx_in_ord_ind rx_in_ord_ind;
};
} __packed;
@@ -1182,7 +1245,6 @@ struct ath10k_htt {
struct ath10k *ar;
enum ath10k_htc_ep_id eid;
- int max_throughput_mbps;
u8 target_version_major;
u8 target_version_minor;
struct completion target_version_received;
@@ -1198,6 +1260,20 @@ struct ath10k_htt {
* filled.
*/
struct sk_buff **netbufs_ring;
+
+ /* This is used only with firmware supporting IN_ORD_IND.
+ *
+ * With Full Rx Reorder the HTT Rx Ring is more of a temporary
+ * buffer ring from which buffer addresses are copied by the
+ * firmware to MAC Rx ring. Firmware then delivers IN_ORD_IND
+ * pointing to specific (re-ordered) buffers.
+ *
+ * FIXME: With kernel generic hashing functions there's a lot
+ * of hash collisions for sk_buffs.
+ */
+ bool in_ord_rx;
+ DECLARE_HASHTABLE(skb_table, 4);
+
/*
* Ring of buffer addresses -
* This ring holds the "physical" device address of the
@@ -1252,12 +1328,11 @@ struct ath10k_htt {
unsigned int prefetch_len;
- /* Protects access to %pending_tx, %used_msdu_ids */
+ /* Protects access to pending_tx, num_pending_tx */
spinlock_t tx_lock;
int max_num_pending_tx;
int num_pending_tx;
- struct sk_buff **pending_tx;
- unsigned long *used_msdu_ids; /* bitmap */
+ struct idr pending_tx;
wait_queue_head_t empty_tx_wq;
struct dma_pool *tx_pool;
@@ -1271,6 +1346,7 @@ struct ath10k_htt {
struct tasklet_struct txrx_compl_task;
struct sk_buff_head tx_compl_q;
struct sk_buff_head rx_compl_q;
+ struct sk_buff_head rx_in_ord_compl_q;
/* rx_status template */
struct ieee80211_rx_status rx_status;
@@ -1334,6 +1410,7 @@ int ath10k_htt_tx_alloc(struct ath10k_htt *htt);
void ath10k_htt_tx_free(struct ath10k_htt *htt);
int ath10k_htt_rx_alloc(struct ath10k_htt *htt);
+int ath10k_htt_rx_ring_refill(struct ath10k *ar);
void ath10k_htt_rx_free(struct ath10k_htt *htt);
void ath10k_htt_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb);
@@ -1346,7 +1423,7 @@ int ath10k_htt_h2t_aggr_cfg_msg(struct ath10k_htt *htt,
u8 max_subfrms_amsdu);
void __ath10k_htt_tx_dec_pending(struct ath10k_htt *htt);
-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt);
+int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb);
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id);
int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *);
int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *);
diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c
index 9c782a42665e..c1da44f65a4d 100644
--- a/drivers/net/wireless/ath/ath10k/htt_rx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_rx.c
@@ -25,8 +25,8 @@
#include <linux/log2.h>
-#define HTT_RX_RING_SIZE 1024
-#define HTT_RX_RING_FILL_LEVEL 1000
+#define HTT_RX_RING_SIZE HTT_RX_RING_SIZE_MAX
+#define HTT_RX_RING_FILL_LEVEL (((HTT_RX_RING_SIZE) / 2) - 1)
/* when under memory pressure rx ring refill may fail and needs a retry */
#define HTT_RX_RING_REFILL_RETRY_MS 50
@@ -34,31 +34,70 @@
static int ath10k_htt_rx_get_csum_state(struct sk_buff *skb);
static void ath10k_htt_txrx_compl_task(unsigned long ptr);
+static struct sk_buff *
+ath10k_htt_rx_find_skb_paddr(struct ath10k *ar, u32 paddr)
+{
+ struct ath10k_skb_rxcb *rxcb;
+
+ hash_for_each_possible(ar->htt.rx_ring.skb_table, rxcb, hlist, paddr)
+ if (rxcb->paddr == paddr)
+ return ATH10K_RXCB_SKB(rxcb);
+
+ WARN_ON_ONCE(1);
+ return NULL;
+}
+
static void ath10k_htt_rx_ring_free(struct ath10k_htt *htt)
{
struct sk_buff *skb;
- struct ath10k_skb_cb *cb;
+ struct ath10k_skb_rxcb *rxcb;
+ struct hlist_node *n;
int i;
- for (i = 0; i < htt->rx_ring.fill_cnt; i++) {
- skb = htt->rx_ring.netbufs_ring[i];
- cb = ATH10K_SKB_CB(skb);
- dma_unmap_single(htt->ar->dev, cb->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
- dev_kfree_skb_any(skb);
+ if (htt->rx_ring.in_ord_rx) {
+ hash_for_each_safe(htt->rx_ring.skb_table, i, n, rxcb, hlist) {
+ skb = ATH10K_RXCB_SKB(rxcb);
+ dma_unmap_single(htt->ar->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+ hash_del(&rxcb->hlist);
+ dev_kfree_skb_any(skb);
+ }
+ } else {
+ for (i = 0; i < htt->rx_ring.size; i++) {
+ skb = htt->rx_ring.netbufs_ring[i];
+ if (!skb)
+ continue;
+
+ rxcb = ATH10K_SKB_RXCB(skb);
+ dma_unmap_single(htt->ar->dev, rxcb->paddr,
+ skb->len + skb_tailroom(skb),
+ DMA_FROM_DEVICE);
+ dev_kfree_skb_any(skb);
+ }
}
htt->rx_ring.fill_cnt = 0;
+ hash_init(htt->rx_ring.skb_table);
+ memset(htt->rx_ring.netbufs_ring, 0,
+ htt->rx_ring.size * sizeof(htt->rx_ring.netbufs_ring[0]));
}
static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
{
struct htt_rx_desc *rx_desc;
+ struct ath10k_skb_rxcb *rxcb;
struct sk_buff *skb;
dma_addr_t paddr;
int ret = 0, idx;
+ /* The Full Rx Reorder firmware has no way of telling the host
+ * implicitly when it copied HTT Rx Ring buffers to MAC Rx Ring.
+ * To keep things simple make sure ring is always half empty. This
+ * guarantees there'll be no replenishment overruns possible.
+ */
+ BUILD_BUG_ON(HTT_RX_RING_FILL_LEVEL >= HTT_RX_RING_SIZE / 2);
+
idx = __le32_to_cpu(*htt->rx_ring.alloc_idx.vaddr);
while (num > 0) {
skb = dev_alloc_skb(HTT_RX_BUF_SIZE + HTT_RX_DESC_ALIGN);
@@ -86,17 +125,29 @@ static int __ath10k_htt_rx_ring_fill_n(struct ath10k_htt *htt, int num)
goto fail;
}
- ATH10K_SKB_CB(skb)->paddr = paddr;
+ rxcb = ATH10K_SKB_RXCB(skb);
+ rxcb->paddr = paddr;
htt->rx_ring.netbufs_ring[idx] = skb;
htt->rx_ring.paddrs_ring[idx] = __cpu_to_le32(paddr);
htt->rx_ring.fill_cnt++;
+ if (htt->rx_ring.in_ord_rx) {
+ hash_add(htt->rx_ring.skb_table,
+ &ATH10K_SKB_RXCB(skb)->hlist,
+ (u32)paddr);
+ }
+
num--;
idx++;
idx &= htt->rx_ring.size_mask;
}
fail:
+ /*
+ * Make sure the rx buffer is updated before available buffer
+ * index to avoid any potential rx ring corruption.
+ */
+ mb();
*htt->rx_ring.alloc_idx.vaddr = __cpu_to_le32(idx);
return ret;
}
@@ -153,22 +204,20 @@ static void ath10k_htt_rx_ring_refill_retry(unsigned long arg)
ath10k_htt_rx_msdu_buff_replenish(htt);
}
-static void ath10k_htt_rx_ring_clean_up(struct ath10k_htt *htt)
+int ath10k_htt_rx_ring_refill(struct ath10k *ar)
{
- struct sk_buff *skb;
- int i;
+ struct ath10k_htt *htt = &ar->htt;
+ int ret;
- for (i = 0; i < htt->rx_ring.size; i++) {
- skb = htt->rx_ring.netbufs_ring[i];
- if (!skb)
- continue;
+ spin_lock_bh(&htt->rx_ring.lock);
+ ret = ath10k_htt_rx_ring_fill_n(htt, (htt->rx_ring.fill_level -
+ htt->rx_ring.fill_cnt));
+ spin_unlock_bh(&htt->rx_ring.lock);
- dma_unmap_single(htt->ar->dev, ATH10K_SKB_CB(skb)->paddr,
- skb->len + skb_tailroom(skb),
- DMA_FROM_DEVICE);
- dev_kfree_skb_any(skb);
- htt->rx_ring.netbufs_ring[i] = NULL;
- }
+ if (ret)
+ ath10k_htt_rx_ring_free(htt);
+
+ return ret;
}
void ath10k_htt_rx_free(struct ath10k_htt *htt)
@@ -179,8 +228,9 @@ void ath10k_htt_rx_free(struct ath10k_htt *htt)
skb_queue_purge(&htt->tx_compl_q);
skb_queue_purge(&htt->rx_compl_q);
+ skb_queue_purge(&htt->rx_in_ord_compl_q);
- ath10k_htt_rx_ring_clean_up(htt);
+ ath10k_htt_rx_ring_free(htt);
dma_free_coherent(htt->ar->dev,
(htt->rx_ring.size *
@@ -212,6 +262,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
idx = htt->rx_ring.sw_rd_idx.msdu_payld;
msdu = htt->rx_ring.netbufs_ring[idx];
htt->rx_ring.netbufs_ring[idx] = NULL;
+ htt->rx_ring.paddrs_ring[idx] = 0;
idx++;
idx &= htt->rx_ring.size_mask;
@@ -219,7 +270,7 @@ static inline struct sk_buff *ath10k_htt_rx_netbuf_pop(struct ath10k_htt *htt)
htt->rx_ring.fill_cnt--;
dma_unmap_single(htt->ar->dev,
- ATH10K_SKB_CB(msdu)->paddr,
+ ATH10K_SKB_RXCB(msdu)->paddr,
msdu->len + skb_tailroom(msdu),
DMA_FROM_DEVICE);
ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ",
@@ -379,6 +430,82 @@ static void ath10k_htt_rx_replenish_task(unsigned long ptr)
ath10k_htt_rx_msdu_buff_replenish(htt);
}
+static struct sk_buff *ath10k_htt_rx_pop_paddr(struct ath10k_htt *htt,
+ u32 paddr)
+{
+ struct ath10k *ar = htt->ar;
+ struct ath10k_skb_rxcb *rxcb;
+ struct sk_buff *msdu;
+
+ lockdep_assert_held(&htt->rx_ring.lock);
+
+ msdu = ath10k_htt_rx_find_skb_paddr(ar, paddr);
+ if (!msdu)
+ return NULL;
+
+ rxcb = ATH10K_SKB_RXCB(msdu);
+ hash_del(&rxcb->hlist);
+ htt->rx_ring.fill_cnt--;
+
+ dma_unmap_single(htt->ar->dev, rxcb->paddr,
+ msdu->len + skb_tailroom(msdu),
+ DMA_FROM_DEVICE);
+ ath10k_dbg_dump(ar, ATH10K_DBG_HTT_DUMP, NULL, "htt rx netbuf pop: ",
+ msdu->data, msdu->len + skb_tailroom(msdu));
+
+ return msdu;
+}
+
+static int ath10k_htt_rx_pop_paddr_list(struct ath10k_htt *htt,
+ struct htt_rx_in_ord_ind *ev,
+ struct sk_buff_head *list)
+{
+ struct ath10k *ar = htt->ar;
+ struct htt_rx_in_ord_msdu_desc *msdu_desc = ev->msdu_descs;
+ struct htt_rx_desc *rxd;
+ struct sk_buff *msdu;
+ int msdu_count;
+ bool is_offload;
+ u32 paddr;
+
+ lockdep_assert_held(&htt->rx_ring.lock);
+
+ msdu_count = __le16_to_cpu(ev->msdu_count);
+ is_offload = !!(ev->info & HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK);
+
+ while (msdu_count--) {
+ paddr = __le32_to_cpu(msdu_desc->msdu_paddr);
+
+ msdu = ath10k_htt_rx_pop_paddr(htt, paddr);
+ if (!msdu) {
+ __skb_queue_purge(list);
+ return -ENOENT;
+ }
+
+ __skb_queue_tail(list, msdu);
+
+ if (!is_offload) {
+ rxd = (void *)msdu->data;
+
+ trace_ath10k_htt_rx_desc(ar, rxd, sizeof(*rxd));
+
+ skb_put(msdu, sizeof(*rxd));
+ skb_pull(msdu, sizeof(*rxd));
+ skb_put(msdu, __le16_to_cpu(msdu_desc->msdu_len));
+
+ if (!(__le32_to_cpu(rxd->attention.flags) &
+ RX_ATTENTION_FLAGS_MSDU_DONE)) {
+ ath10k_warn(htt->ar, "tried to pop an incomplete frame, oops!\n");
+ return -EIO;
+ }
+ }
+
+ msdu_desc++;
+ }
+
+ return 0;
+}
+
int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
@@ -424,7 +551,7 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
htt->rx_ring.alloc_idx.vaddr = vaddr;
htt->rx_ring.alloc_idx.paddr = paddr;
- htt->rx_ring.sw_rd_idx.msdu_payld = 0;
+ htt->rx_ring.sw_rd_idx.msdu_payld = htt->rx_ring.size_mask;
*htt->rx_ring.alloc_idx.vaddr = 0;
/* Initialize the Rx refill retry timer */
@@ -433,14 +560,15 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
spin_lock_init(&htt->rx_ring.lock);
htt->rx_ring.fill_cnt = 0;
- if (__ath10k_htt_rx_ring_fill_n(htt, htt->rx_ring.fill_level))
- goto err_fill_ring;
+ htt->rx_ring.sw_rd_idx.msdu_payld = 0;
+ hash_init(htt->rx_ring.skb_table);
tasklet_init(&htt->rx_replenish_task, ath10k_htt_rx_replenish_task,
(unsigned long)htt);
skb_queue_head_init(&htt->tx_compl_q);
skb_queue_head_init(&htt->rx_compl_q);
+ skb_queue_head_init(&htt->rx_in_ord_compl_q);
tasklet_init(&htt->txrx_compl_task, ath10k_htt_txrx_compl_task,
(unsigned long)htt);
@@ -449,12 +577,6 @@ int ath10k_htt_rx_alloc(struct ath10k_htt *htt)
htt->rx_ring.size, htt->rx_ring.fill_level);
return 0;
-err_fill_ring:
- ath10k_htt_rx_ring_free(htt);
- dma_free_coherent(htt->ar->dev,
- sizeof(*htt->rx_ring.alloc_idx.vaddr),
- htt->rx_ring.alloc_idx.vaddr,
- htt->rx_ring.alloc_idx.paddr);
err_dma_idx:
dma_free_coherent(htt->ar->dev,
(htt->rx_ring.size *
@@ -691,7 +813,7 @@ static void ath10k_htt_rx_h_mactime(struct ath10k *ar,
*
* FIXME: Can we get/compute 64bit TSF?
*/
- status->mactime = __le32_to_cpu(rxd->ppdu_end.tsf_timestamp);
+ status->mactime = __le32_to_cpu(rxd->ppdu_end.common.tsf_timestamp);
status->flag |= RX_FLAG_MACTIME_END;
}
@@ -1578,6 +1700,194 @@ static void ath10k_htt_rx_delba(struct ath10k *ar, struct htt_resp *resp)
spin_unlock_bh(&ar->data_lock);
}
+static int ath10k_htt_rx_extract_amsdu(struct sk_buff_head *list,
+ struct sk_buff_head *amsdu)
+{
+ struct sk_buff *msdu;
+ struct htt_rx_desc *rxd;
+
+ if (skb_queue_empty(list))
+ return -ENOBUFS;
+
+ if (WARN_ON(!skb_queue_empty(amsdu)))
+ return -EINVAL;
+
+ while ((msdu = __skb_dequeue(list))) {
+ __skb_queue_tail(amsdu, msdu);
+
+ rxd = (void *)msdu->data - sizeof(*rxd);
+ if (rxd->msdu_end.info0 &
+ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))
+ break;
+ }
+
+ msdu = skb_peek_tail(amsdu);
+ rxd = (void *)msdu->data - sizeof(*rxd);
+ if (!(rxd->msdu_end.info0 &
+ __cpu_to_le32(RX_MSDU_END_INFO0_LAST_MSDU))) {
+ skb_queue_splice_init(amsdu, list);
+ return -EAGAIN;
+ }
+
+ return 0;
+}
+
+static void ath10k_htt_rx_h_rx_offload_prot(struct ieee80211_rx_status *status,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+
+ if (!ieee80211_has_protected(hdr->frame_control))
+ return;
+
+ /* Offloaded frames are already decrypted but firmware insists they are
+ * protected in the 802.11 header. Strip the flag. Otherwise mac80211
+ * will drop the frame.
+ */
+
+ hdr->frame_control &= ~__cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+ status->flag |= RX_FLAG_DECRYPTED |
+ RX_FLAG_IV_STRIPPED |
+ RX_FLAG_MMIC_STRIPPED;
+}
+
+static void ath10k_htt_rx_h_rx_offload(struct ath10k *ar,
+ struct sk_buff_head *list)
+{
+ struct ath10k_htt *htt = &ar->htt;
+ struct ieee80211_rx_status *status = &htt->rx_status;
+ struct htt_rx_offload_msdu *rx;
+ struct sk_buff *msdu;
+ size_t offset;
+
+ while ((msdu = __skb_dequeue(list))) {
+ /* Offloaded frames don't have Rx descriptor. Instead they have
+ * a short meta information header.
+ */
+
+ rx = (void *)msdu->data;
+
+ skb_put(msdu, sizeof(*rx));
+ skb_pull(msdu, sizeof(*rx));
+
+ if (skb_tailroom(msdu) < __le16_to_cpu(rx->msdu_len)) {
+ ath10k_warn(ar, "dropping frame: offloaded rx msdu is too long!\n");
+ dev_kfree_skb_any(msdu);
+ continue;
+ }
+
+ skb_put(msdu, __le16_to_cpu(rx->msdu_len));
+
+ /* Offloaded rx header length isn't multiple of 2 nor 4 so the
+ * actual payload is unaligned. Align the frame. Otherwise
+ * mac80211 complains. This shouldn't reduce performance much
+ * because these offloaded frames are rare.
+ */
+ offset = 4 - ((unsigned long)msdu->data & 3);
+ skb_put(msdu, offset);
+ memmove(msdu->data + offset, msdu->data, msdu->len);
+ skb_pull(msdu, offset);
+
+ /* FIXME: The frame is NWifi. Re-construct QoS Control
+ * if possible later.
+ */
+
+ memset(status, 0, sizeof(*status));
+ status->flag |= RX_FLAG_NO_SIGNAL_VAL;
+
+ ath10k_htt_rx_h_rx_offload_prot(status, msdu);
+ ath10k_htt_rx_h_channel(ar, status);
+ ath10k_process_rx(ar, status, msdu);
+ }
+}
+
+static void ath10k_htt_rx_in_ord_ind(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct ath10k_htt *htt = &ar->htt;
+ struct htt_resp *resp = (void *)skb->data;
+ struct ieee80211_rx_status *status = &htt->rx_status;
+ struct sk_buff_head list;
+ struct sk_buff_head amsdu;
+ u16 peer_id;
+ u16 msdu_count;
+ u8 vdev_id;
+ u8 tid;
+ bool offload;
+ bool frag;
+ int ret;
+
+ lockdep_assert_held(&htt->rx_ring.lock);
+
+ if (htt->rx_confused)
+ return;
+
+ skb_pull(skb, sizeof(resp->hdr));
+ skb_pull(skb, sizeof(resp->rx_in_ord_ind));
+
+ peer_id = __le16_to_cpu(resp->rx_in_ord_ind.peer_id);
+ msdu_count = __le16_to_cpu(resp->rx_in_ord_ind.msdu_count);
+ vdev_id = resp->rx_in_ord_ind.vdev_id;
+ tid = SM(resp->rx_in_ord_ind.info, HTT_RX_IN_ORD_IND_INFO_TID);
+ offload = !!(resp->rx_in_ord_ind.info &
+ HTT_RX_IN_ORD_IND_INFO_OFFLOAD_MASK);
+ frag = !!(resp->rx_in_ord_ind.info & HTT_RX_IN_ORD_IND_INFO_FRAG_MASK);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT,
+ "htt rx in ord vdev %i peer %i tid %i offload %i frag %i msdu count %i\n",
+ vdev_id, peer_id, tid, offload, frag, msdu_count);
+
+ if (skb->len < msdu_count * sizeof(*resp->rx_in_ord_ind.msdu_descs)) {
+ ath10k_warn(ar, "dropping invalid in order rx indication\n");
+ return;
+ }
+
+ /* The event can deliver more than 1 A-MSDU. Each A-MSDU is later
+ * extracted and processed.
+ */
+ __skb_queue_head_init(&list);
+ ret = ath10k_htt_rx_pop_paddr_list(htt, &resp->rx_in_ord_ind, &list);
+ if (ret < 0) {
+ ath10k_warn(ar, "failed to pop paddr list: %d\n", ret);
+ htt->rx_confused = true;
+ return;
+ }
+
+ /* Offloaded frames are very different and need to be handled
+ * separately.
+ */
+ if (offload)
+ ath10k_htt_rx_h_rx_offload(ar, &list);
+
+ while (!skb_queue_empty(&list)) {
+ __skb_queue_head_init(&amsdu);
+ ret = ath10k_htt_rx_extract_amsdu(&list, &amsdu);
+ switch (ret) {
+ case 0:
+ /* Note: The in-order indication may report interleaved
+ * frames from different PPDUs meaning reported rx rate
+ * to mac80211 isn't accurate/reliable. It's still
+ * better to report something than nothing though. This
+ * should still give an idea about rx rate to the user.
+ */
+ ath10k_htt_rx_h_ppdu(ar, &amsdu, status);
+ ath10k_htt_rx_h_filter(ar, &amsdu, status);
+ ath10k_htt_rx_h_mpdu(ar, &amsdu, status);
+ ath10k_htt_rx_h_deliver(ar, &amsdu, status);
+ break;
+ case -EAGAIN:
+ /* fall through */
+ default:
+ /* Should not happen. */
+ ath10k_warn(ar, "failed to extract amsdu: %d\n", ret);
+ htt->rx_confused = true;
+ __skb_queue_purge(&list);
+ return;
+ }
+ }
+
+ tasklet_schedule(&htt->rx_replenish_task);
+}
+
void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
{
struct ath10k_htt *htt = &ar->htt;
@@ -1700,6 +2010,20 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
*/
break;
}
+ case HTT_T2H_MSG_TYPE_RX_IN_ORD_PADDR_IND: {
+ spin_lock_bh(&htt->rx_ring.lock);
+ __skb_queue_tail(&htt->rx_in_ord_compl_q, skb);
+ spin_unlock_bh(&htt->rx_ring.lock);
+ tasklet_schedule(&htt->txrx_compl_task);
+ return;
+ }
+ case HTT_T2H_MSG_TYPE_TX_CREDIT_UPDATE_IND:
+ /* FIXME: This WMI-TLV event is overlapping with 10.2
+ * CHAN_CHANGE - both being 0xF. Neither is being used in
+ * practice so no immediate action is necessary. Nevertheless
+ * HTT may need an abstraction layer like WMI has one day.
+ */
+ break;
default:
ath10k_warn(ar, "htt event (%d) not handled\n",
resp->hdr.msg_type);
@@ -1715,6 +2039,7 @@ void ath10k_htt_t2h_msg_handler(struct ath10k *ar, struct sk_buff *skb)
static void ath10k_htt_txrx_compl_task(unsigned long ptr)
{
struct ath10k_htt *htt = (struct ath10k_htt *)ptr;
+ struct ath10k *ar = htt->ar;
struct htt_resp *resp;
struct sk_buff *skb;
@@ -1731,5 +2056,10 @@ static void ath10k_htt_txrx_compl_task(unsigned long ptr)
ath10k_htt_rx_handler(htt, &resp->rx_ind);
dev_kfree_skb_any(skb);
}
+
+ while ((skb = __skb_dequeue(&htt->rx_in_ord_compl_q))) {
+ ath10k_htt_rx_in_ord_ind(ar, skb);
+ dev_kfree_skb_any(skb);
+ }
spin_unlock_bh(&htt->rx_ring.lock);
}
diff --git a/drivers/net/wireless/ath/ath10k/htt_tx.c b/drivers/net/wireless/ath/ath10k/htt_tx.c
index 4bc51d8a14a3..cbd2bc9e6202 100644
--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
@@ -56,21 +56,18 @@ exit:
return ret;
}
-int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt)
+int ath10k_htt_tx_alloc_msdu_id(struct ath10k_htt *htt, struct sk_buff *skb)
{
struct ath10k *ar = htt->ar;
- int msdu_id;
+ int ret;
lockdep_assert_held(&htt->tx_lock);
- msdu_id = find_first_zero_bit(htt->used_msdu_ids,
- htt->max_num_pending_tx);
- if (msdu_id == htt->max_num_pending_tx)
- return -ENOBUFS;
+ ret = idr_alloc(&htt->pending_tx, skb, 0, 0x10000, GFP_ATOMIC);
+
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", ret);
- ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx alloc msdu_id %d\n", msdu_id);
- __set_bit(msdu_id, htt->used_msdu_ids);
- return msdu_id;
+ return ret;
}
void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
@@ -79,79 +76,53 @@ void ath10k_htt_tx_free_msdu_id(struct ath10k_htt *htt, u16 msdu_id)
lockdep_assert_held(&htt->tx_lock);
- if (!test_bit(msdu_id, htt->used_msdu_ids))
- ath10k_warn(ar, "trying to free unallocated msdu_id %d\n",
- msdu_id);
-
ath10k_dbg(ar, ATH10K_DBG_HTT, "htt tx free msdu_id %hu\n", msdu_id);
- __clear_bit(msdu_id, htt->used_msdu_ids);
+
+ idr_remove(&htt->pending_tx, msdu_id);
}
int ath10k_htt_tx_alloc(struct ath10k_htt *htt)
{
struct ath10k *ar = htt->ar;
- spin_lock_init(&htt->tx_lock);
-
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, htt->ar->fw_features))
- htt->max_num_pending_tx = TARGET_10X_NUM_MSDU_DESC;
- else
- htt->max_num_pending_tx = TARGET_NUM_MSDU_DESC;
-
ath10k_dbg(ar, ATH10K_DBG_BOOT, "htt tx max num pending tx %d\n",
htt->max_num_pending_tx);
- htt->pending_tx = kzalloc(sizeof(*htt->pending_tx) *
- htt->max_num_pending_tx, GFP_KERNEL);
- if (!htt->pending_tx)
- return -ENOMEM;
-
- htt->used_msdu_ids = kzalloc(sizeof(unsigned long) *
- BITS_TO_LONGS(htt->max_num_pending_tx),
- GFP_KERNEL);
- if (!htt->used_msdu_ids) {
- kfree(htt->pending_tx);
- return -ENOMEM;
- }
+ spin_lock_init(&htt->tx_lock);
+ idr_init(&htt->pending_tx);
htt->tx_pool = dma_pool_create("ath10k htt tx pool", htt->ar->dev,
sizeof(struct ath10k_htt_txbuf), 4, 0);
if (!htt->tx_pool) {
- kfree(htt->used_msdu_ids);
- kfree(htt->pending_tx);
+ idr_destroy(&htt->pending_tx);
return -ENOMEM;
}
return 0;
}
-static void ath10k_htt_tx_free_pending(struct ath10k_htt *htt)
+static int ath10k_htt_tx_clean_up_pending(int msdu_id, void *skb, void *ctx)
{
- struct ath10k *ar = htt->ar;
+ struct ath10k *ar = ctx;
+ struct ath10k_htt *htt = &ar->htt;
struct htt_tx_done tx_done = {0};
- int msdu_id;
-
- spin_lock_bh(&htt->tx_lock);
- for (msdu_id = 0; msdu_id < htt->max_num_pending_tx; msdu_id++) {
- if (!test_bit(msdu_id, htt->used_msdu_ids))
- continue;
- ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n",
- msdu_id);
+ ath10k_dbg(ar, ATH10K_DBG_HTT, "force cleanup msdu_id %hu\n", msdu_id);
- tx_done.discard = 1;
- tx_done.msdu_id = msdu_id;
+ tx_done.discard = 1;
+ tx_done.msdu_id = msdu_id;
- ath10k_txrx_tx_unref(htt, &tx_done);
- }
+ spin_lock_bh(&htt->tx_lock);
+ ath10k_txrx_tx_unref(htt, &tx_done);
spin_unlock_bh(&htt->tx_lock);
+
+ return 0;
}
void ath10k_htt_tx_free(struct ath10k_htt *htt)
{
- ath10k_htt_tx_free_pending(htt);
- kfree(htt->pending_tx);
- kfree(htt->used_msdu_ids);
+ idr_for_each(&htt->pending_tx, ath10k_htt_tx_clean_up_pending, htt->ar);
+ idr_destroy(&htt->pending_tx);
dma_pool_destroy(htt->tx_pool);
}
@@ -383,13 +354,12 @@ int ath10k_htt_mgmt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
len += sizeof(cmd->mgmt_tx);
spin_lock_bh(&htt->tx_lock);
- res = ath10k_htt_tx_alloc_msdu_id(htt);
+ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
if (res < 0) {
spin_unlock_bh(&htt->tx_lock);
goto err_tx_dec;
}
msdu_id = res;
- htt->pending_tx[msdu_id] = msdu;
spin_unlock_bh(&htt->tx_lock);
txdesc = ath10k_htc_alloc_skb(ar, len);
@@ -428,7 +398,6 @@ err_free_txdesc:
dev_kfree_skb_any(txdesc);
err_free_msdu_id:
spin_lock_bh(&htt->tx_lock);
- htt->pending_tx[msdu_id] = NULL;
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
spin_unlock_bh(&htt->tx_lock);
err_tx_dec:
@@ -460,13 +429,12 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
goto err;
spin_lock_bh(&htt->tx_lock);
- res = ath10k_htt_tx_alloc_msdu_id(htt);
+ res = ath10k_htt_tx_alloc_msdu_id(htt, msdu);
if (res < 0) {
spin_unlock_bh(&htt->tx_lock);
goto err_tx_dec;
}
msdu_id = res;
- htt->pending_tx[msdu_id] = msdu;
spin_unlock_bh(&htt->tx_lock);
prefetch_len = min(htt->prefetch_len, msdu->len);
@@ -480,10 +448,18 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
skb_cb->htt.txbuf = dma_pool_alloc(htt->tx_pool, GFP_ATOMIC,
&paddr);
- if (!skb_cb->htt.txbuf)
+ if (!skb_cb->htt.txbuf) {
+ res = -ENOMEM;
goto err_free_msdu_id;
+ }
skb_cb->htt.txbuf_paddr = paddr;
+ if ((ieee80211_is_action(hdr->frame_control) ||
+ ieee80211_is_deauth(hdr->frame_control) ||
+ ieee80211_is_disassoc(hdr->frame_control)) &&
+ ieee80211_has_protected(hdr->frame_control))
+ skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+
skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
DMA_TO_DEVICE);
res = dma_mapping_error(dev, skb_cb->paddr);
@@ -539,8 +515,10 @@ int ath10k_htt_tx(struct ath10k_htt *htt, struct sk_buff *msdu)
flags1 |= SM((u16)vdev_id, HTT_DATA_TX_DESC_FLAGS1_VDEV_ID);
flags1 |= SM((u16)tid, HTT_DATA_TX_DESC_FLAGS1_EXT_TID);
- flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
- flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
+ if (msdu->ip_summed == CHECKSUM_PARTIAL) {
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L3_OFFLOAD;
+ flags1 |= HTT_DATA_TX_DESC_FLAGS1_CKSUM_L4_OFFLOAD;
+ }
/* Prevent firmware from sending up tx inspection requests. There's
* nothing ath10k can do with frames requested for inspection so force
@@ -598,7 +576,6 @@ err_free_txbuf:
skb_cb->htt.txbuf_paddr);
err_free_msdu_id:
spin_lock_bh(&htt->tx_lock);
- htt->pending_tx[msdu_id] = NULL;
ath10k_htt_tx_free_msdu_id(htt, msdu_id);
spin_unlock_bh(&htt->tx_lock);
err_tx_dec:
diff --git a/drivers/net/wireless/ath/ath10k/hw.c b/drivers/net/wireless/ath/ath10k/hw.c
new file mode 100644
index 000000000000..839a8791fb9e
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/hw.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/types.h>
+#include "hw.h"
+
+const struct ath10k_hw_regs qca988x_regs = {
+ .rtc_state_cold_reset_mask = 0x00000400,
+ .rtc_soc_base_address = 0x00004000,
+ .rtc_wmac_base_address = 0x00005000,
+ .soc_core_base_address = 0x00009000,
+ .ce_wrapper_base_address = 0x00057000,
+ .ce0_base_address = 0x00057400,
+ .ce1_base_address = 0x00057800,
+ .ce2_base_address = 0x00057c00,
+ .ce3_base_address = 0x00058000,
+ .ce4_base_address = 0x00058400,
+ .ce5_base_address = 0x00058800,
+ .ce6_base_address = 0x00058c00,
+ .ce7_base_address = 0x00059000,
+ .soc_reset_control_si0_rst_mask = 0x00000001,
+ .soc_reset_control_ce_rst_mask = 0x00040000,
+ .soc_chip_id_address = 0x00ec,
+ .scratch_3_address = 0x0030,
+};
+
+const struct ath10k_hw_regs qca6174_regs = {
+ .rtc_state_cold_reset_mask = 0x00002000,
+ .rtc_soc_base_address = 0x00000800,
+ .rtc_wmac_base_address = 0x00001000,
+ .soc_core_base_address = 0x0003a000,
+ .ce_wrapper_base_address = 0x00034000,
+ .ce0_base_address = 0x00034400,
+ .ce1_base_address = 0x00034800,
+ .ce2_base_address = 0x00034c00,
+ .ce3_base_address = 0x00035000,
+ .ce4_base_address = 0x00035400,
+ .ce5_base_address = 0x00035800,
+ .ce6_base_address = 0x00035c00,
+ .ce7_base_address = 0x00036000,
+ .soc_reset_control_si0_rst_mask = 0x00000000,
+ .soc_reset_control_ce_rst_mask = 0x00000001,
+ .soc_chip_id_address = 0x000f0,
+ .scratch_3_address = 0x0028,
+};
diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h
index dfedfd0e0f34..460771fcfe9e 100644
--- a/drivers/net/wireless/ath/ath10k/hw.h
+++ b/drivers/net/wireless/ath/ath10k/hw.h
@@ -34,9 +34,50 @@
#define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
#define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
+/* QCA6174 target BMI version signatures */
+#define QCA6174_HW_1_0_VERSION 0x05000000
+#define QCA6174_HW_1_1_VERSION 0x05000001
+#define QCA6174_HW_1_3_VERSION 0x05000003
+#define QCA6174_HW_2_1_VERSION 0x05010000
+#define QCA6174_HW_3_0_VERSION 0x05020000
+#define QCA6174_HW_3_2_VERSION 0x05030000
+
+enum qca6174_pci_rev {
+ QCA6174_PCI_REV_1_1 = 0x11,
+ QCA6174_PCI_REV_1_3 = 0x13,
+ QCA6174_PCI_REV_2_0 = 0x20,
+ QCA6174_PCI_REV_3_0 = 0x30,
+};
+
+enum qca6174_chip_id_rev {
+ QCA6174_HW_1_0_CHIP_ID_REV = 0,
+ QCA6174_HW_1_1_CHIP_ID_REV = 1,
+ QCA6174_HW_1_3_CHIP_ID_REV = 2,
+ QCA6174_HW_2_1_CHIP_ID_REV = 4,
+ QCA6174_HW_2_2_CHIP_ID_REV = 5,
+ QCA6174_HW_3_0_CHIP_ID_REV = 8,
+ QCA6174_HW_3_1_CHIP_ID_REV = 9,
+ QCA6174_HW_3_2_CHIP_ID_REV = 10,
+};
+
+#define QCA6174_HW_2_1_FW_DIR "ath10k/QCA6174/hw2.1"
+#define QCA6174_HW_2_1_FW_FILE "firmware.bin"
+#define QCA6174_HW_2_1_OTP_FILE "otp.bin"
+#define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin"
+#define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234
+
+#define QCA6174_HW_3_0_FW_DIR "ath10k/QCA6174/hw3.0"
+#define QCA6174_HW_3_0_FW_FILE "firmware.bin"
+#define QCA6174_HW_3_0_OTP_FILE "otp.bin"
+#define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin"
+#define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234
+
#define ATH10K_FW_API2_FILE "firmware-2.bin"
#define ATH10K_FW_API3_FILE "firmware-3.bin"
+/* added support for ATH10K_FW_IE_WMI_OP_VERSION */
+#define ATH10K_FW_API4_FILE "firmware-4.bin"
+
#define ATH10K_FW_UTF_FILE "utf.bin"
/* includes also the null byte */
@@ -58,8 +99,57 @@ enum ath10k_fw_ie_type {
ATH10K_FW_IE_FEATURES = 2,
ATH10K_FW_IE_FW_IMAGE = 3,
ATH10K_FW_IE_OTP_IMAGE = 4,
+
+ /* WMI "operations" interface version, 32 bit value. Supported from
+ * FW API 4 and above.
+ */
+ ATH10K_FW_IE_WMI_OP_VERSION = 5,
+};
+
+enum ath10k_fw_wmi_op_version {
+ ATH10K_FW_WMI_OP_VERSION_UNSET = 0,
+
+ ATH10K_FW_WMI_OP_VERSION_MAIN = 1,
+ ATH10K_FW_WMI_OP_VERSION_10_1 = 2,
+ ATH10K_FW_WMI_OP_VERSION_10_2 = 3,
+ ATH10K_FW_WMI_OP_VERSION_TLV = 4,
+ ATH10K_FW_WMI_OP_VERSION_10_2_4 = 5,
+
+ /* keep last */
+ ATH10K_FW_WMI_OP_VERSION_MAX,
+};
+
+enum ath10k_hw_rev {
+ ATH10K_HW_QCA988X,
+ ATH10K_HW_QCA6174,
+};
+
+struct ath10k_hw_regs {
+ u32 rtc_state_cold_reset_mask;
+ u32 rtc_soc_base_address;
+ u32 rtc_wmac_base_address;
+ u32 soc_core_base_address;
+ u32 ce_wrapper_base_address;
+ u32 ce0_base_address;
+ u32 ce1_base_address;
+ u32 ce2_base_address;
+ u32 ce3_base_address;
+ u32 ce4_base_address;
+ u32 ce5_base_address;
+ u32 ce6_base_address;
+ u32 ce7_base_address;
+ u32 soc_reset_control_si0_rst_mask;
+ u32 soc_reset_control_ce_rst_mask;
+ u32 soc_chip_id_address;
+ u32 scratch_3_address;
};
+extern const struct ath10k_hw_regs qca988x_regs;
+extern const struct ath10k_hw_regs qca6174_regs;
+
+#define QCA_REV_988X(ar) ((ar)->hw_rev == ATH10K_HW_QCA988X)
+#define QCA_REV_6174(ar) ((ar)->hw_rev == ATH10K_HW_QCA6174)
+
/* Known pecularities:
* - current FW doesn't support raw rx mode (last tested v599)
* - current FW dumps upon raw tx mode (last tested v599)
@@ -162,6 +252,18 @@ struct ath10k_pktlog_hdr {
#define TARGET_10X_NUM_MSDU_DESC (1024 + 400)
#define TARGET_10X_MAX_FRAG_ENTRIES 0
+/* 10.2 parameters */
+#define TARGET_10_2_DMA_BURST_SIZE 1
+
+/* Target specific defines for WMI-TLV firmware */
+#define TARGET_TLV_NUM_VDEVS 3
+#define TARGET_TLV_NUM_STATIONS 32
+#define TARGET_TLV_NUM_PEERS ((TARGET_TLV_NUM_STATIONS) + \
+ (TARGET_TLV_NUM_VDEVS) + \
+ 2)
+#define TARGET_TLV_NUM_TIDS ((TARGET_TLV_NUM_PEERS) * 2)
+#define TARGET_TLV_NUM_MSDU_DESC (1024 + 32)
+
/* Number of Copy Engines supported */
#define CE_COUNT 8
@@ -192,7 +294,7 @@ struct ath10k_pktlog_hdr {
/* as of IP3.7.1 */
#define RTC_STATE_V_ON 3
-#define RTC_STATE_COLD_RESET_MASK 0x00000400
+#define RTC_STATE_COLD_RESET_MASK ar->regs->rtc_state_cold_reset_mask
#define RTC_STATE_V_LSB 0
#define RTC_STATE_V_MASK 0x00000007
#define RTC_STATE_ADDRESS 0x0000
@@ -201,12 +303,12 @@ struct ath10k_pktlog_hdr {
#define PCIE_SOC_WAKE_RESET 0x00000000
#define SOC_GLOBAL_RESET_ADDRESS 0x0008
-#define RTC_SOC_BASE_ADDRESS 0x00004000
-#define RTC_WMAC_BASE_ADDRESS 0x00005000
+#define RTC_SOC_BASE_ADDRESS ar->regs->rtc_soc_base_address
+#define RTC_WMAC_BASE_ADDRESS ar->regs->rtc_wmac_base_address
#define MAC_COEX_BASE_ADDRESS 0x00006000
#define BT_COEX_BASE_ADDRESS 0x00007000
#define SOC_PCIE_BASE_ADDRESS 0x00008000
-#define SOC_CORE_BASE_ADDRESS 0x00009000
+#define SOC_CORE_BASE_ADDRESS ar->regs->soc_core_base_address
#define WLAN_UART_BASE_ADDRESS 0x0000c000
#define WLAN_SI_BASE_ADDRESS 0x00010000
#define WLAN_GPIO_BASE_ADDRESS 0x00014000
@@ -215,23 +317,23 @@ struct ath10k_pktlog_hdr {
#define EFUSE_BASE_ADDRESS 0x00030000
#define FPGA_REG_BASE_ADDRESS 0x00039000
#define WLAN_UART2_BASE_ADDRESS 0x00054c00
-#define CE_WRAPPER_BASE_ADDRESS 0x00057000
-#define CE0_BASE_ADDRESS 0x00057400
-#define CE1_BASE_ADDRESS 0x00057800
-#define CE2_BASE_ADDRESS 0x00057c00
-#define CE3_BASE_ADDRESS 0x00058000
-#define CE4_BASE_ADDRESS 0x00058400
-#define CE5_BASE_ADDRESS 0x00058800
-#define CE6_BASE_ADDRESS 0x00058c00
-#define CE7_BASE_ADDRESS 0x00059000
+#define CE_WRAPPER_BASE_ADDRESS ar->regs->ce_wrapper_base_address
+#define CE0_BASE_ADDRESS ar->regs->ce0_base_address
+#define CE1_BASE_ADDRESS ar->regs->ce1_base_address
+#define CE2_BASE_ADDRESS ar->regs->ce2_base_address
+#define CE3_BASE_ADDRESS ar->regs->ce3_base_address
+#define CE4_BASE_ADDRESS ar->regs->ce4_base_address
+#define CE5_BASE_ADDRESS ar->regs->ce5_base_address
+#define CE6_BASE_ADDRESS ar->regs->ce6_base_address
+#define CE7_BASE_ADDRESS ar->regs->ce7_base_address
#define DBI_BASE_ADDRESS 0x00060000
#define WLAN_ANALOG_INTF_PCIE_BASE_ADDRESS 0x0006c000
#define PCIE_LOCAL_BASE_ADDRESS 0x00080000
#define SOC_RESET_CONTROL_ADDRESS 0x00000000
#define SOC_RESET_CONTROL_OFFSET 0x00000000
-#define SOC_RESET_CONTROL_SI0_RST_MASK 0x00000001
-#define SOC_RESET_CONTROL_CE_RST_MASK 0x00040000
+#define SOC_RESET_CONTROL_SI0_RST_MASK ar->regs->soc_reset_control_si0_rst_mask
+#define SOC_RESET_CONTROL_CE_RST_MASK ar->regs->soc_reset_control_ce_rst_mask
#define SOC_RESET_CONTROL_CPU_WARM_RST_MASK 0x00000040
#define SOC_CPU_CLOCK_OFFSET 0x00000020
#define SOC_CPU_CLOCK_STANDARD_LSB 0
@@ -245,7 +347,7 @@ struct ath10k_pktlog_hdr {
#define SOC_LF_TIMER_CONTROL0_ADDRESS 0x00000050
#define SOC_LF_TIMER_CONTROL0_ENABLE_MASK 0x00000004
-#define SOC_CHIP_ID_ADDRESS 0x000000ec
+#define SOC_CHIP_ID_ADDRESS ar->regs->soc_chip_id_address
#define SOC_CHIP_ID_REV_LSB 8
#define SOC_CHIP_ID_REV_MASK 0x00000f00
@@ -301,7 +403,7 @@ struct ath10k_pktlog_hdr {
#define PCIE_INTR_ENABLE_ADDRESS 0x0008
#define PCIE_INTR_CAUSE_ADDRESS 0x000c
#define PCIE_INTR_CLR_ADDRESS 0x0014
-#define SCRATCH_3_ADDRESS 0x0030
+#define SCRATCH_3_ADDRESS ar->regs->scratch_3_address
#define CPU_INTR_ADDRESS 0x0010
/* Firmware indications to the Host via SCRATCH_3 register. */
diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index c4005670cba2..d6d2f0f00caa 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -27,6 +27,8 @@
#include "htt.h"
#include "txrx.h"
#include "testmode.h"
+#include "wmi.h"
+#include "wmi-ops.h"
/**********/
/* Crypto */
@@ -35,7 +37,7 @@
static int ath10k_send_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr)
+ const u8 *macaddr, bool def_idx)
{
struct ath10k *ar = arvif->ar;
struct wmi_vdev_install_key_arg arg = {
@@ -56,10 +58,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
switch (key->cipher) {
case WLAN_CIPHER_SUITE_CCMP:
arg.key_cipher = WMI_CIPHER_AES_CCM;
- if (arvif->vdev_type == WMI_VDEV_TYPE_AP)
- key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
- else
- key->flags |= IEEE80211_KEY_FLAG_SW_MGMT_TX;
+ key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV_MGMT;
break;
case WLAN_CIPHER_SUITE_TKIP:
arg.key_cipher = WMI_CIPHER_TKIP;
@@ -73,7 +72,13 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
* Otherwise pairwise key must be set */
if (memcmp(macaddr, arvif->vif->addr, ETH_ALEN))
arg.key_flags = WMI_KEY_PAIRWISE;
+
+ if (def_idx)
+ arg.key_flags |= WMI_KEY_TX_USAGE;
break;
+ case WLAN_CIPHER_SUITE_AES_CMAC:
+ /* this one needs to be done in software */
+ return 1;
default:
ath10k_warn(ar, "cipher %d is not supported\n", key->cipher);
return -EOPNOTSUPP;
@@ -90,7 +95,7 @@ static int ath10k_send_key(struct ath10k_vif *arvif,
static int ath10k_install_key(struct ath10k_vif *arvif,
struct ieee80211_key_conf *key,
enum set_key_cmd cmd,
- const u8 *macaddr)
+ const u8 *macaddr, bool def_idx)
{
struct ath10k *ar = arvif->ar;
int ret;
@@ -99,7 +104,7 @@ static int ath10k_install_key(struct ath10k_vif *arvif,
reinit_completion(&ar->install_key_done);
- ret = ath10k_send_key(arvif, key, cmd, macaddr);
+ ret = ath10k_send_key(arvif, key, cmd, macaddr, def_idx);
if (ret)
return ret;
@@ -117,6 +122,7 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
struct ath10k_peer *peer;
int ret;
int i;
+ bool def_idx;
lockdep_assert_held(&ar->conf_mutex);
@@ -130,9 +136,14 @@ static int ath10k_install_peer_wep_keys(struct ath10k_vif *arvif,
for (i = 0; i < ARRAY_SIZE(arvif->wep_keys); i++) {
if (arvif->wep_keys[i] == NULL)
continue;
+ /* set TX_USAGE flag for default key id */
+ if (arvif->def_wep_key_idx == i)
+ def_idx = true;
+ else
+ def_idx = false;
ret = ath10k_install_key(arvif, arvif->wep_keys[i], SET_KEY,
- addr);
+ addr, def_idx);
if (ret)
return ret;
@@ -166,8 +177,9 @@ static int ath10k_clear_peer_keys(struct ath10k_vif *arvif,
if (peer->keys[i] == NULL)
continue;
+ /* key flags are not required to delete the key */
ret = ath10k_install_key(arvif, peer->keys[i],
- DISABLE_KEY, addr);
+ DISABLE_KEY, addr, false);
if (ret && first_errno == 0)
first_errno = ret;
@@ -241,8 +253,8 @@ static int ath10k_clear_vdev_key(struct ath10k_vif *arvif,
if (i == ARRAY_SIZE(peer->keys))
break;
-
- ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr);
+ /* key flags are not required to delete the key */
+ ret = ath10k_install_key(arvif, key, DISABLE_KEY, addr, false);
if (ret && first_errno == 0)
first_errno = ret;
@@ -267,7 +279,10 @@ chan_to_phymode(const struct cfg80211_chan_def *chandef)
case IEEE80211_BAND_2GHZ:
switch (chandef->width) {
case NL80211_CHAN_WIDTH_20_NOHT:
- phymode = MODE_11G;
+ if (chandef->chan->flags & IEEE80211_CHAN_NO_OFDM)
+ phymode = MODE_11B;
+ else
+ phymode = MODE_11G;
break;
case NL80211_CHAN_WIDTH_20:
phymode = MODE_11NG_HT20;
@@ -519,10 +534,14 @@ void ath10k_mac_vif_beacon_free(struct ath10k_vif *arvif)
dma_unmap_single(ar->dev, ATH10K_SKB_CB(arvif->beacon)->paddr,
arvif->beacon->len, DMA_TO_DEVICE);
+ if (WARN_ON(arvif->beacon_state != ATH10K_BEACON_SCHEDULED &&
+ arvif->beacon_state != ATH10K_BEACON_SENT))
+ return;
+
dev_kfree_skb_any(arvif->beacon);
arvif->beacon = NULL;
- arvif->beacon_sent = false;
+ arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
}
static void ath10k_mac_vif_beacon_cleanup(struct ath10k_vif *arvif)
@@ -962,6 +981,143 @@ static int ath10k_vdev_stop(struct ath10k_vif *arvif)
return ret;
}
+static int ath10k_mac_setup_bcn_p2p_ie(struct ath10k_vif *arvif,
+ struct sk_buff *bcn)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_mgmt *mgmt;
+ const u8 *p2p_ie;
+ int ret;
+
+ if (arvif->vdev_type != WMI_VDEV_TYPE_AP)
+ return 0;
+
+ if (arvif->vdev_subtype != WMI_VDEV_SUBTYPE_P2P_GO)
+ return 0;
+
+ mgmt = (void *)bcn->data;
+ p2p_ie = cfg80211_find_vendor_ie(WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+ mgmt->u.beacon.variable,
+ bcn->len - (mgmt->u.beacon.variable -
+ bcn->data));
+ if (!p2p_ie)
+ return -ENOENT;
+
+ ret = ath10k_wmi_p2p_go_bcn_ie(ar, arvif->vdev_id, p2p_ie);
+ if (ret) {
+ ath10k_warn(ar, "failed to submit p2p go bcn ie for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath10k_mac_remove_vendor_ie(struct sk_buff *skb, unsigned int oui,
+ u8 oui_type, size_t ie_offset)
+{
+ size_t len;
+ const u8 *next;
+ const u8 *end;
+ u8 *ie;
+
+ if (WARN_ON(skb->len < ie_offset))
+ return -EINVAL;
+
+ ie = (u8 *)cfg80211_find_vendor_ie(oui, oui_type,
+ skb->data + ie_offset,
+ skb->len - ie_offset);
+ if (!ie)
+ return -ENOENT;
+
+ len = ie[1] + 2;
+ end = skb->data + skb->len;
+ next = ie + len;
+
+ if (WARN_ON(next > end))
+ return -EINVAL;
+
+ memmove(ie, next, end - next);
+ skb_trim(skb, skb->len - len);
+
+ return 0;
+}
+
+static int ath10k_mac_setup_bcn_tmpl(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_hw *hw = ar->hw;
+ struct ieee80211_vif *vif = arvif->vif;
+ struct ieee80211_mutable_offsets offs = {};
+ struct sk_buff *bcn;
+ int ret;
+
+ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
+ return 0;
+
+ bcn = ieee80211_beacon_get_template(hw, vif, &offs);
+ if (!bcn) {
+ ath10k_warn(ar, "failed to get beacon template from mac80211\n");
+ return -EPERM;
+ }
+
+ ret = ath10k_mac_setup_bcn_p2p_ie(arvif, bcn);
+ if (ret) {
+ ath10k_warn(ar, "failed to setup p2p go bcn ie: %d\n", ret);
+ kfree_skb(bcn);
+ return ret;
+ }
+
+ /* P2P IE is inserted by firmware automatically (as configured above)
+ * so remove it from the base beacon template to avoid duplicate P2P
+ * IEs in beacon frames.
+ */
+ ath10k_mac_remove_vendor_ie(bcn, WLAN_OUI_WFA, WLAN_OUI_TYPE_WFA_P2P,
+ offsetof(struct ieee80211_mgmt,
+ u.beacon.variable));
+
+ ret = ath10k_wmi_bcn_tmpl(ar, arvif->vdev_id, offs.tim_offset, bcn, 0,
+ 0, NULL, 0);
+ kfree_skb(bcn);
+
+ if (ret) {
+ ath10k_warn(ar, "failed to submit beacon template command: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath10k_mac_setup_prb_tmpl(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct ieee80211_hw *hw = ar->hw;
+ struct ieee80211_vif *vif = arvif->vif;
+ struct sk_buff *prb;
+ int ret;
+
+ if (!test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map))
+ return 0;
+
+ prb = ieee80211_proberesp_get(hw, vif);
+ if (!prb) {
+ ath10k_warn(ar, "failed to get probe resp template from mac80211\n");
+ return -EPERM;
+ }
+
+ ret = ath10k_wmi_prb_tmpl(ar, arvif->vdev_id, prb);
+ kfree_skb(prb);
+
+ if (ret) {
+ ath10k_warn(ar, "failed to submit probe resp template command: %d\n",
+ ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static void ath10k_control_beaconing(struct ath10k_vif *arvif,
struct ieee80211_bss_conf *info)
{
@@ -1046,28 +1202,85 @@ static void ath10k_control_ibss(struct ath10k_vif *arvif,
arvif->vdev_id, ret);
}
-/*
- * Review this when mac80211 gains per-interface powersave support.
- */
+static int ath10k_mac_vif_recalc_ps_wake_threshold(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ u32 param;
+ u32 value;
+ int ret;
+
+ lockdep_assert_held(&arvif->ar->conf_mutex);
+
+ if (arvif->u.sta.uapsd)
+ value = WMI_STA_PS_TX_WAKE_THRESHOLD_NEVER;
+ else
+ value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
+
+ param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
+ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param, value);
+ if (ret) {
+ ath10k_warn(ar, "failed to submit ps wake threshold %u on vdev %i: %d\n",
+ value, arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ath10k_mac_vif_recalc_ps_poll_count(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ u32 param;
+ u32 value;
+ int ret;
+
+ lockdep_assert_held(&arvif->ar->conf_mutex);
+
+ if (arvif->u.sta.uapsd)
+ value = WMI_STA_PS_PSPOLL_COUNT_UAPSD;
+ else
+ value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
+
+ param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
+ ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
+ param, value);
+ if (ret) {
+ ath10k_warn(ar, "failed to submit ps poll count %u on vdev %i: %d\n",
+ value, arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
{
struct ath10k *ar = arvif->ar;
+ struct ieee80211_vif *vif = arvif->vif;
struct ieee80211_conf *conf = &ar->hw->conf;
enum wmi_sta_powersave_param param;
enum wmi_sta_ps_mode psmode;
int ret;
+ int ps_timeout;
lockdep_assert_held(&arvif->ar->conf_mutex);
if (arvif->vif->type != NL80211_IFTYPE_STATION)
return 0;
- if (conf->flags & IEEE80211_CONF_PS) {
+ if (vif->bss_conf.ps) {
psmode = WMI_STA_PS_MODE_ENABLED;
param = WMI_STA_PS_PARAM_INACTIVITY_TIME;
+ ps_timeout = conf->dynamic_ps_timeout;
+ if (ps_timeout == 0) {
+ /* Firmware doesn't like 0 */
+ ps_timeout = ieee80211_tu_to_usec(
+ vif->bss_conf.beacon_int) / 1000;
+ }
+
ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id, param,
- conf->dynamic_ps_timeout);
+ ps_timeout);
if (ret) {
ath10k_warn(ar, "failed to set inactivity time for vdev %d: %i\n",
arvif->vdev_id, ret);
@@ -1090,6 +1303,38 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
return 0;
}
+static int ath10k_mac_vif_disable_keepalive(struct ath10k_vif *arvif)
+{
+ struct ath10k *ar = arvif->ar;
+ struct wmi_sta_keepalive_arg arg = {};
+ int ret;
+
+ lockdep_assert_held(&arvif->ar->conf_mutex);
+
+ if (arvif->vdev_type != WMI_VDEV_TYPE_STA)
+ return 0;
+
+ if (!test_bit(WMI_SERVICE_STA_KEEP_ALIVE, ar->wmi.svc_map))
+ return 0;
+
+ /* Some firmware revisions have a bug and ignore the `enabled` field.
+ * Instead use the interval to disable the keepalive.
+ */
+ arg.vdev_id = arvif->vdev_id;
+ arg.enabled = 1;
+ arg.method = WMI_STA_KEEPALIVE_METHOD_NULL_FRAME;
+ arg.interval = WMI_STA_KEEPALIVE_INTERVAL_DISABLE;
+
+ ret = ath10k_wmi_sta_keepalive(ar, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to submit keepalive on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ return 0;
+}
+
/**********************/
/* Station management */
/**********************/
@@ -1358,6 +1603,10 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar,
return;
arg->peer_flags |= WMI_PEER_VHT;
+
+ if (ar->hw->conf.chandef.chan->band == IEEE80211_BAND_2GHZ)
+ arg->peer_flags |= WMI_PEER_VHT_2G;
+
arg->peer_vht_caps = vht_cap->cap;
ampdu_factor = (vht_cap->cap &
@@ -1409,9 +1658,22 @@ static void ath10k_peer_assoc_h_qos(struct ath10k *ar,
if (vif->bss_conf.qos)
arg->peer_flags |= WMI_PEER_QOS;
break;
+ case WMI_VDEV_TYPE_IBSS:
+ if (sta->wme)
+ arg->peer_flags |= WMI_PEER_QOS;
+ break;
default:
break;
}
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac peer %pM qos %d\n",
+ sta->addr, !!(arg->peer_flags & WMI_PEER_QOS));
+}
+
+static bool ath10k_mac_sta_has_11g_rates(struct ieee80211_sta *sta)
+{
+ /* First 4 rates in ath10k_rates are CCK (11b) rates. */
+ return sta->supp_rates[IEEE80211_BAND_2GHZ] >> 4;
}
static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
@@ -1423,13 +1685,20 @@ static void ath10k_peer_assoc_h_phymode(struct ath10k *ar,
switch (ar->hw->conf.chandef.chan->band) {
case IEEE80211_BAND_2GHZ:
- if (sta->ht_cap.ht_supported) {
+ if (sta->vht_cap.vht_supported) {
+ if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
+ phymode = MODE_11AC_VHT40;
+ else
+ phymode = MODE_11AC_VHT20;
+ } else if (sta->ht_cap.ht_supported) {
if (sta->bandwidth == IEEE80211_STA_RX_BW_40)
phymode = MODE_11NG_HT40;
else
phymode = MODE_11NG_HT20;
- } else {
+ } else if (ath10k_mac_sta_has_11g_rates(sta)) {
phymode = MODE_11G;
+ } else {
+ phymode = MODE_11B;
}
break;
@@ -1603,7 +1872,8 @@ static void ath10k_bss_disassoc(struct ieee80211_hw *hw,
ath10k_warn(ar, "faield to down vdev %i: %d\n",
arvif->vdev_id, ret);
- arvif->def_wep_key_idx = 0;
+ arvif->def_wep_key_idx = -1;
+
arvif->is_up = false;
}
@@ -1662,11 +1932,14 @@ static int ath10k_station_assoc(struct ath10k *ar,
}
}
- ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
- if (ret) {
- ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
- arvif->vdev_id, ret);
- return ret;
+ /* Plumb cached keys only for static WEP */
+ if (arvif->def_wep_key_idx != -1) {
+ ret = ath10k_install_peer_wep_keys(arvif, sta->addr);
+ if (ret) {
+ ath10k_warn(ar, "failed to install peer wep keys for vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
}
}
@@ -1931,75 +2204,13 @@ static void ath10k_tx_h_nwifi(struct ieee80211_hw *hw, struct sk_buff *skb)
* used only for CQM purposes (e.g. hostapd station keepalive ping) so
* it is safe to downgrade to NullFunc.
*/
+ hdr = (void *)skb->data;
if (ieee80211_is_qos_nullfunc(hdr->frame_control)) {
hdr->frame_control &= ~__cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
cb->htt.tid = HTT_DATA_TX_EXT_TID_NON_QOS_MCAST_BCAST;
}
}
-static void ath10k_tx_wep_key_work(struct work_struct *work)
-{
- struct ath10k_vif *arvif = container_of(work, struct ath10k_vif,
- wep_key_work);
- struct ath10k *ar = arvif->ar;
- int ret, keyidx = arvif->def_wep_key_newidx;
-
- mutex_lock(&arvif->ar->conf_mutex);
-
- if (arvif->ar->state != ATH10K_STATE_ON)
- goto unlock;
-
- if (arvif->def_wep_key_idx == keyidx)
- goto unlock;
-
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
- arvif->vdev_id, keyidx);
-
- ret = ath10k_wmi_vdev_set_param(arvif->ar,
- arvif->vdev_id,
- arvif->ar->wmi.vdev_param->def_keyid,
- keyidx);
- if (ret) {
- ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
- arvif->vdev_id,
- ret);
- goto unlock;
- }
-
- arvif->def_wep_key_idx = keyidx;
-
-unlock:
- mutex_unlock(&arvif->ar->conf_mutex);
-}
-
-static void ath10k_tx_h_update_wep_key(struct ieee80211_vif *vif,
- struct ieee80211_key_conf *key,
- struct sk_buff *skb)
-{
- struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
- struct ath10k *ar = arvif->ar;
- struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-
- if (!ieee80211_has_protected(hdr->frame_control))
- return;
-
- if (!key)
- return;
-
- if (key->cipher != WLAN_CIPHER_SUITE_WEP40 &&
- key->cipher != WLAN_CIPHER_SUITE_WEP104)
- return;
-
- if (key->keyidx == arvif->def_wep_key_idx)
- return;
-
- /* FIXME: Most likely a few frames will be TXed with an old key. Simply
- * queueing frames until key index is updated is not an option because
- * sk_buff may need more processing to be done, e.g. offchannel */
- arvif->def_wep_key_newidx = key->keyidx;
- ieee80211_queue_work(ar->hw, &arvif->wep_key_work);
-}
-
static void ath10k_tx_h_add_p2p_noa_ie(struct ath10k *ar,
struct ieee80211_vif *vif,
struct sk_buff *skb)
@@ -2151,7 +2362,7 @@ void ath10k_offchan_tx_work(struct work_struct *work)
ret = wait_for_completion_timeout(&ar->offchan_tx_completed,
3 * HZ);
- if (ret <= 0)
+ if (ret == 0)
ath10k_warn(ar, "timed out waiting for offchannel skb %p\n",
skb);
@@ -2213,6 +2424,7 @@ void __ath10k_scan_finish(struct ath10k *ar)
case ATH10K_SCAN_RUNNING:
if (ar->scan.is_roc)
ieee80211_remain_on_channel_expired(ar->hw);
+ /* fall through */
case ATH10K_SCAN_ABORTING:
if (!ar->scan.is_roc)
ieee80211_scan_completed(ar->hw,
@@ -2359,7 +2571,6 @@ static void ath10k_tx(struct ieee80211_hw *hw,
struct ath10k *ar = hw->priv;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
struct ieee80211_vif *vif = info->control.vif;
- struct ieee80211_key_conf *key = info->control.hw_key;
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
/* We should disable CCK RATE due to P2P */
@@ -2373,7 +2584,6 @@ static void ath10k_tx(struct ieee80211_hw *hw,
/* it makes no sense to process injected frames like that */
if (vif && vif->type != NL80211_IFTYPE_MONITOR) {
ath10k_tx_h_nwifi(hw, skb);
- ath10k_tx_h_update_wep_key(vif, key, skb);
ath10k_tx_h_add_p2p_noa_ie(ar, vif, skb);
ath10k_tx_h_seq_no(vif, skb);
}
@@ -2871,6 +3081,8 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
int bit;
u32 vdev_param;
+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+
mutex_lock(&ar->conf_mutex);
memset(arvif, 0, sizeof(*arvif));
@@ -2878,7 +3090,6 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->ar = ar;
arvif->vif = vif;
- INIT_WORK(&arvif->wep_key_work, ath10k_tx_wep_key_work);
INIT_LIST_HEAD(&arvif->list);
if (ar->free_vdev_map == 0) {
@@ -2894,10 +3105,11 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
arvif->vdev_id = bit;
arvif->vdev_subtype = WMI_VDEV_SUBTYPE_NONE;
- if (ar->p2p)
- arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
-
switch (vif->type) {
+ case NL80211_IFTYPE_P2P_DEVICE:
+ arvif->vdev_type = WMI_VDEV_TYPE_STA;
+ arvif->vdev_subtype = WMI_VDEV_SUBTYPE_P2P_DEVICE;
+ break;
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
arvif->vdev_type = WMI_VDEV_TYPE_STA;
@@ -2966,15 +3178,18 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
ar->free_vdev_map &= ~(1LL << arvif->vdev_id);
list_add(&arvif->list, &ar->arvifs);
- vdev_param = ar->wmi.vdev_param->def_keyid;
- ret = ath10k_wmi_vdev_set_param(ar, 0, vdev_param,
- arvif->def_wep_key_idx);
+ /* It makes no sense to have firmware do keepalives. mac80211 already
+ * takes care of this with idle connection polling.
+ */
+ ret = ath10k_mac_vif_disable_keepalive(arvif);
if (ret) {
- ath10k_warn(ar, "failed to set vdev %i default key id: %d\n",
+ ath10k_warn(ar, "failed to disable keepalive on vdev %i: %d\n",
arvif->vdev_id, ret);
goto err_vdev_delete;
}
+ arvif->def_wep_key_idx = -1;
+
vdev_param = ar->wmi.vdev_param->tx_encap_type;
ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
ATH10K_HW_TXRX_NATIVE_WIFI);
@@ -3026,22 +3241,16 @@ static int ath10k_add_interface(struct ieee80211_hw *hw,
goto err_peer_delete;
}
- param = WMI_STA_PS_PARAM_TX_WAKE_THRESHOLD;
- value = WMI_STA_PS_TX_WAKE_THRESHOLD_ALWAYS;
- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
- param, value);
+ ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif);
if (ret) {
- ath10k_warn(ar, "failed to set vdev %i TX wake thresh: %d\n",
+ ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
- param = WMI_STA_PS_PARAM_PSPOLL_COUNT;
- value = WMI_STA_PS_PSPOLL_COUNT_NO_MAX;
- ret = ath10k_wmi_set_sta_ps_param(ar, arvif->vdev_id,
- param, value);
+ ret = ath10k_mac_vif_recalc_ps_poll_count(arvif);
if (ret) {
- ath10k_warn(ar, "failed to set vdev %i PSPOLL count: %d\n",
+ ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n",
arvif->vdev_id, ret);
goto err_peer_delete;
}
@@ -3099,8 +3308,6 @@ static void ath10k_remove_interface(struct ieee80211_hw *hw,
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
int ret;
- cancel_work_sync(&arvif->wep_key_work);
-
mutex_lock(&ar->conf_mutex);
spin_lock_bh(&ar->data_lock);
@@ -3211,9 +3418,21 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
if (ret)
ath10k_warn(ar, "failed to set beacon mode for vdev %d: %i\n",
arvif->vdev_id, ret);
+
+ ret = ath10k_mac_setup_bcn_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to update beacon template: %d\n",
+ ret);
}
- if (changed & BSS_CHANGED_BEACON_INFO) {
+ if (changed & BSS_CHANGED_AP_PROBE_RESP) {
+ ret = ath10k_mac_setup_prb_tmpl(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to setup probe resp template on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ }
+
+ if (changed & (BSS_CHANGED_BEACON_INFO | BSS_CHANGED_BEACON)) {
arvif->dtim_period = info->dtim_period;
ath10k_dbg(ar, ATH10K_DBG_MAC,
@@ -3314,6 +3533,13 @@ static void ath10k_bss_info_changed(struct ieee80211_hw *hw,
ath10k_warn(ar, "failed to recalc tx power: %d\n", ret);
}
+ if (changed & BSS_CHANGED_PS) {
+ ret = ath10k_mac_vif_setup_ps(arvif);
+ if (ret)
+ ath10k_warn(ar, "failed to setup ps on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ }
+
mutex_unlock(&ar->conf_mutex);
}
@@ -3453,6 +3679,7 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
const u8 *peer_addr;
bool is_wep = key->cipher == WLAN_CIPHER_SUITE_WEP40 ||
key->cipher == WLAN_CIPHER_SUITE_WEP104;
+ bool def_idx = false;
int ret = 0;
if (key->keyidx > WMI_MAX_KEY_INDEX)
@@ -3498,7 +3725,14 @@ static int ath10k_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
ath10k_clear_vdev_key(arvif, key);
}
- ret = ath10k_install_key(arvif, key, cmd, peer_addr);
+ /* set TX_USAGE flag for all the keys incase of dot1x-WEP. For
+ * static WEP, do not set this flag for the keys whose key id
+ * is greater than default key id.
+ */
+ if (arvif->def_wep_key_idx == -1)
+ def_idx = true;
+
+ ret = ath10k_install_key(arvif, key, cmd, peer_addr, def_idx);
if (ret) {
ath10k_warn(ar, "failed to install key for vdev %i peer %pM: %d\n",
arvif->vdev_id, peer_addr, ret);
@@ -3523,6 +3757,39 @@ exit:
return ret;
}
+static void ath10k_set_default_unicast_key(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ int keyidx)
+{
+ struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ int ret;
+
+ mutex_lock(&arvif->ar->conf_mutex);
+
+ if (arvif->ar->state != ATH10K_STATE_ON)
+ goto unlock;
+
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d set keyidx %d\n",
+ arvif->vdev_id, keyidx);
+
+ ret = ath10k_wmi_vdev_set_param(arvif->ar,
+ arvif->vdev_id,
+ arvif->ar->wmi.vdev_param->def_keyid,
+ keyidx);
+
+ if (ret) {
+ ath10k_warn(ar, "failed to update wep key index for vdev %d: %d\n",
+ arvif->vdev_id,
+ ret);
+ goto unlock;
+ }
+
+ arvif->def_wep_key_idx = keyidx;
+unlock:
+ mutex_unlock(&arvif->ar->conf_mutex);
+}
+
static void ath10k_sta_rc_update_wk(struct work_struct *wk)
{
struct ath10k *ar;
@@ -3583,8 +3850,9 @@ static void ath10k_sta_rc_update_wk(struct work_struct *wk)
sta->addr, smps, err);
}
- if (changed & IEEE80211_RC_SUPP_RATES_CHANGED) {
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates\n",
+ if (changed & IEEE80211_RC_SUPP_RATES_CHANGED ||
+ changed & IEEE80211_RC_NSS_CHANGED) {
+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac update sta %pM supp rates/nss\n",
sta->addr);
err = ath10k_station_assoc(ar, arvif->vif, sta, true);
@@ -3757,6 +4025,8 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
u16 ac, bool enable)
{
struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+ struct wmi_sta_uapsd_auto_trig_arg arg = {};
+ u32 prio = 0, acc = 0;
u32 value = 0;
int ret = 0;
@@ -3769,18 +4039,26 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
case IEEE80211_AC_VO:
value = WMI_STA_PS_UAPSD_AC3_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC3_TRIGGER_EN;
+ prio = 7;
+ acc = 3;
break;
case IEEE80211_AC_VI:
value = WMI_STA_PS_UAPSD_AC2_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC2_TRIGGER_EN;
+ prio = 5;
+ acc = 2;
break;
case IEEE80211_AC_BE:
value = WMI_STA_PS_UAPSD_AC1_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC1_TRIGGER_EN;
+ prio = 2;
+ acc = 1;
break;
case IEEE80211_AC_BK:
value = WMI_STA_PS_UAPSD_AC0_DELIVERY_EN |
WMI_STA_PS_UAPSD_AC0_TRIGGER_EN;
+ prio = 0;
+ acc = 0;
break;
}
@@ -3808,6 +4086,43 @@ static int ath10k_conf_tx_uapsd(struct ath10k *ar, struct ieee80211_vif *vif,
if (ret)
ath10k_warn(ar, "failed to set rx wake param: %d\n", ret);
+ ret = ath10k_mac_vif_recalc_ps_wake_threshold(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to recalc ps wake threshold on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ ret = ath10k_mac_vif_recalc_ps_poll_count(arvif);
+ if (ret) {
+ ath10k_warn(ar, "failed to recalc ps poll count on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ return ret;
+ }
+
+ if (test_bit(WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, ar->wmi.svc_map) ||
+ test_bit(WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, ar->wmi.svc_map)) {
+ /* Only userspace can make an educated decision when to send
+ * trigger frame. The following effectively disables u-UAPSD
+ * autotrigger in firmware (which is enabled by default
+ * provided the autotrigger service is available).
+ */
+
+ arg.wmm_ac = acc;
+ arg.user_priority = prio;
+ arg.service_interval = 0;
+ arg.suspend_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC;
+ arg.delay_interval = WMI_STA_UAPSD_MAX_INTERVAL_MSEC;
+
+ ret = ath10k_wmi_vdev_sta_uapsd(ar, arvif->vdev_id,
+ arvif->bssid, &arg, 1);
+ if (ret) {
+ ath10k_warn(ar, "failed to set uapsd auto trigger %d\n",
+ ret);
+ return ret;
+ }
+ }
+
exit:
return ret;
}
@@ -3817,6 +4132,7 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
const struct ieee80211_tx_queue_params *params)
{
struct ath10k *ar = hw->priv;
+ struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
struct wmi_wmm_params_arg *p = NULL;
int ret;
@@ -3824,16 +4140,16 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
switch (ac) {
case IEEE80211_AC_VO:
- p = &ar->wmm_params.ac_vo;
+ p = &arvif->wmm_params.ac_vo;
break;
case IEEE80211_AC_VI:
- p = &ar->wmm_params.ac_vi;
+ p = &arvif->wmm_params.ac_vi;
break;
case IEEE80211_AC_BE:
- p = &ar->wmm_params.ac_be;
+ p = &arvif->wmm_params.ac_be;
break;
case IEEE80211_AC_BK:
- p = &ar->wmm_params.ac_bk;
+ p = &arvif->wmm_params.ac_bk;
break;
}
@@ -3853,11 +4169,23 @@ static int ath10k_conf_tx(struct ieee80211_hw *hw,
*/
p->txop = params->txop * 32;
- /* FIXME: FW accepts wmm params per hw, not per vif */
- ret = ath10k_wmi_pdev_set_wmm_params(ar, &ar->wmm_params);
- if (ret) {
- ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
- goto exit;
+ if (ar->wmi.ops->gen_vdev_wmm_conf) {
+ ret = ath10k_wmi_vdev_wmm_conf(ar, arvif->vdev_id,
+ &arvif->wmm_params);
+ if (ret) {
+ ath10k_warn(ar, "failed to set vdev wmm params on vdev %i: %d\n",
+ arvif->vdev_id, ret);
+ goto exit;
+ }
+ } else {
+ /* This won't work well with multi-interface cases but it's
+ * better than nothing.
+ */
+ ret = ath10k_wmi_pdev_set_wmm_params(ar, &arvif->wmm_params);
+ if (ret) {
+ ath10k_warn(ar, "failed to set wmm params: %d\n", ret);
+ goto exit;
+ }
}
ret = ath10k_conf_tx_uapsd(ar, vif, ac, params->uapsd);
@@ -3989,29 +4317,6 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
return ret;
}
-static int ath10k_set_frag_threshold(struct ieee80211_hw *hw, u32 value)
-{
- struct ath10k *ar = hw->priv;
- struct ath10k_vif *arvif;
- int ret = 0;
-
- mutex_lock(&ar->conf_mutex);
- list_for_each_entry(arvif, &ar->arvifs, list) {
- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vdev %d fragmentation threshold %d\n",
- arvif->vdev_id, value);
-
- ret = ath10k_mac_set_frag(arvif, value);
- if (ret) {
- ath10k_warn(ar, "failed to set fragmentation threshold for vdev %d: %d\n",
- arvif->vdev_id, ret);
- break;
- }
- }
- mutex_unlock(&ar->conf_mutex);
-
- return ret;
-}
-
static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
@@ -4650,12 +4955,12 @@ static const struct ieee80211_ops ath10k_ops = {
.hw_scan = ath10k_hw_scan,
.cancel_hw_scan = ath10k_cancel_hw_scan,
.set_key = ath10k_set_key,
+ .set_default_unicast_key = ath10k_set_default_unicast_key,
.sta_state = ath10k_sta_state,
.conf_tx = ath10k_conf_tx,
.remain_on_channel = ath10k_remain_on_channel,
.cancel_remain_on_channel = ath10k_cancel_remain_on_channel,
.set_rts_threshold = ath10k_set_rts_threshold,
- .set_frag_threshold = ath10k_set_frag_threshold,
.flush = ath10k_flush,
.tx_last_beacon = ath10k_tx_last_beacon,
.set_antenna = ath10k_set_antenna,
@@ -4676,6 +4981,9 @@ static const struct ieee80211_ops ath10k_ops = {
.suspend = ath10k_suspend,
.resume = ath10k_resume,
#endif
+#ifdef CONFIG_MAC80211_DEBUGFS
+ .sta_add_debugfs = ath10k_sta_add_debugfs,
+#endif
};
#define RATETAB_ENT(_rate, _rateid, _flags) { \
@@ -4746,6 +5054,9 @@ static const struct ieee80211_channel ath10k_5ghz_channels[] = {
CHAN5G(165, 5825, 0),
};
+/* Note: Be careful if you re-order these. There is code which depends on this
+ * ordering.
+ */
static struct ieee80211_rate ath10k_rates[] = {
/* CCK */
RATETAB_ENT(10, 0x82, 0),
@@ -4799,6 +5110,10 @@ static const struct ieee80211_iface_limit ath10k_if_limits[] = {
.types = BIT(NL80211_IFTYPE_P2P_GO)
},
{
+ .max = 1,
+ .types = BIT(NL80211_IFTYPE_P2P_DEVICE)
+ },
+ {
.max = 7,
.types = BIT(NL80211_IFTYPE_AP)
},
@@ -4956,6 +5271,13 @@ struct ath10k_vif *ath10k_get_arvif(struct ath10k *ar, u32 vdev_id)
int ath10k_mac_register(struct ath10k *ar)
{
+ static const u32 cipher_suites[] = {
+ WLAN_CIPHER_SUITE_WEP40,
+ WLAN_CIPHER_SUITE_WEP104,
+ WLAN_CIPHER_SUITE_TKIP,
+ WLAN_CIPHER_SUITE_CCMP,
+ WLAN_CIPHER_SUITE_AES_CMAC,
+ };
struct ieee80211_supported_band *band;
struct ieee80211_sta_vht_cap vht_cap;
struct ieee80211_sta_ht_cap ht_cap;
@@ -4985,7 +5307,8 @@ int ath10k_mac_register(struct ath10k *ar)
band->bitrates = ath10k_g_rates;
band->ht_cap = ht_cap;
- /* vht is not supported in 2.4 GHz */
+ /* Enable the VHT support at 2.4 GHz */
+ band->vht_cap = vht_cap;
ar->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = band;
}
@@ -5018,18 +5341,19 @@ int ath10k_mac_register(struct ath10k *ar)
if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
ar->hw->wiphy->interface_modes |=
+ BIT(NL80211_IFTYPE_P2P_DEVICE) |
BIT(NL80211_IFTYPE_P2P_CLIENT) |
BIT(NL80211_IFTYPE_P2P_GO);
ar->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_MFP_CAPABLE |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_AP_LINK_PS |
- IEEE80211_HW_SPECTRUM_MGMT;
+ IEEE80211_HW_SPECTRUM_MGMT |
+ IEEE80211_HW_SW_CRYPTO_CONTROL;
ar->hw->wiphy->features |= NL80211_FEATURE_STATIC_SMPS;
@@ -5049,6 +5373,19 @@ int ath10k_mac_register(struct ath10k *ar)
ar->hw->max_listen_interval = ATH10K_MAX_HW_LISTEN_INTERVAL;
+ if (test_bit(WMI_SERVICE_BEACON_OFFLOAD, ar->wmi.svc_map)) {
+ ar->hw->wiphy->flags |= WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+
+ /* Firmware delivers WPS/P2P Probe Requests frames to driver so
+ * that userspace (e.g. wpa_supplicant/hostapd) can generate
+ * correct Probe Responses. This is more of a hack advert..
+ */
+ ar->hw->wiphy->probe_resp_offload |=
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+ NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
+ }
+
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
ar->hw->wiphy->max_remain_on_channel_duration = 5000;
@@ -5062,16 +5399,26 @@ int ath10k_mac_register(struct ath10k *ar)
*/
ar->hw->queues = 4;
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
- ar->hw->wiphy->n_iface_combinations =
- ARRAY_SIZE(ath10k_10x_if_comb);
- } else {
+ switch (ar->wmi.op_version) {
+ case ATH10K_FW_WMI_OP_VERSION_MAIN:
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
ar->hw->wiphy->iface_combinations = ath10k_if_comb;
ar->hw->wiphy->n_iface_combinations =
ARRAY_SIZE(ath10k_if_comb);
-
ar->hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_ADHOC);
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_10_1:
+ case ATH10K_FW_WMI_OP_VERSION_10_2:
+ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ ar->hw->wiphy->iface_combinations = ath10k_10x_if_comb;
+ ar->hw->wiphy->n_iface_combinations =
+ ARRAY_SIZE(ath10k_10x_if_comb);
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_UNSET:
+ case ATH10K_FW_WMI_OP_VERSION_MAX:
+ WARN_ON(1);
+ ret = -EINVAL;
+ goto err_free;
}
ar->hw->netdev_features = NETIF_F_HW_CSUM;
@@ -5093,6 +5440,9 @@ int ath10k_mac_register(struct ath10k *ar)
goto err_free;
}
+ ar->hw->wiphy->cipher_suites = cipher_suites;
+ ar->hw->wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
+
ret = ieee80211_register_hw(ar->hw);
if (ret) {
ath10k_err(ar, "failed to register ieee80211: %d\n", ret);
diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c
index 7abb8367119a..e6972b09333e 100644
--- a/drivers/net/wireless/ath/ath10k/pci.c
+++ b/drivers/net/wireless/ath/ath10k/pci.c
@@ -58,12 +58,27 @@ MODULE_PARM_DESC(reset_mode, "0: auto, 1: warm only (default: 0)");
#define ATH10K_PCI_NUM_WARM_RESET_ATTEMPTS 3
#define QCA988X_2_0_DEVICE_ID (0x003c)
+#define QCA6174_2_1_DEVICE_ID (0x003e)
static const struct pci_device_id ath10k_pci_id_table[] = {
{ PCI_VDEVICE(ATHEROS, QCA988X_2_0_DEVICE_ID) }, /* PCI-E QCA988X V2 */
+ { PCI_VDEVICE(ATHEROS, QCA6174_2_1_DEVICE_ID) }, /* PCI-E QCA6174 V2.1 */
{0}
};
+static const struct ath10k_pci_supp_chip ath10k_pci_supp_chips[] = {
+ /* QCA988X pre 2.0 chips are not supported because they need some nasty
+ * hacks. ath10k doesn't have them and these devices crash horribly
+ * because of that.
+ */
+ { QCA988X_2_0_DEVICE_ID, QCA988X_HW_2_0_CHIP_ID_REV },
+ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_1_CHIP_ID_REV },
+ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_2_2_CHIP_ID_REV },
+ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_0_CHIP_ID_REV },
+ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_1_CHIP_ID_REV },
+ { QCA6174_2_1_DEVICE_ID, QCA6174_HW_3_2_CHIP_ID_REV },
+};
+
static void ath10k_pci_buffer_cleanup(struct ath10k *ar);
static int ath10k_pci_cold_reset(struct ath10k *ar);
static int ath10k_pci_warm_reset(struct ath10k *ar);
@@ -395,7 +410,7 @@ static int __ath10k_pci_rx_post_buf(struct ath10k_pci_pipe *pipe)
return -EIO;
}
- ATH10K_SKB_CB(skb)->paddr = paddr;
+ ATH10K_SKB_RXCB(skb)->paddr = paddr;
ret = __ath10k_ce_rx_post_buf(ce_pipe, skb, paddr);
if (ret) {
@@ -864,7 +879,7 @@ static void ath10k_pci_ce_recv_data(struct ath10k_ce_pipe *ce_state)
&flags) == 0) {
skb = transfer_context;
max_nbytes = skb->len + skb_tailroom(skb);
- dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
+ dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
max_nbytes, DMA_FROM_DEVICE);
if (unlikely(max_nbytes < nbytes)) {
@@ -1230,7 +1245,7 @@ static void ath10k_pci_rx_pipe_cleanup(struct ath10k_pci_pipe *pci_pipe)
ce_ring->per_transfer_context[i] = NULL;
- dma_unmap_single(ar->dev, ATH10K_SKB_CB(skb)->paddr,
+ dma_unmap_single(ar->dev, ATH10K_SKB_RXCB(skb)->paddr,
skb->len + skb_tailroom(skb),
DMA_FROM_DEVICE);
dev_kfree_skb_any(skb);
@@ -1498,6 +1513,35 @@ static int ath10k_pci_wake_target_cpu(struct ath10k *ar)
return 0;
}
+static int ath10k_pci_get_num_banks(struct ath10k *ar)
+{
+ struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
+
+ switch (ar_pci->pdev->device) {
+ case QCA988X_2_0_DEVICE_ID:
+ return 1;
+ case QCA6174_2_1_DEVICE_ID:
+ switch (MS(ar->chip_id, SOC_CHIP_ID_REV)) {
+ case QCA6174_HW_1_0_CHIP_ID_REV:
+ case QCA6174_HW_1_1_CHIP_ID_REV:
+ return 3;
+ case QCA6174_HW_1_3_CHIP_ID_REV:
+ return 2;
+ case QCA6174_HW_2_1_CHIP_ID_REV:
+ case QCA6174_HW_2_2_CHIP_ID_REV:
+ return 6;
+ case QCA6174_HW_3_0_CHIP_ID_REV:
+ case QCA6174_HW_3_1_CHIP_ID_REV:
+ case QCA6174_HW_3_2_CHIP_ID_REV:
+ return 9;
+ }
+ break;
+ }
+
+ ath10k_warn(ar, "unknown number of banks, assuming 1\n");
+ return 1;
+}
+
static int ath10k_pci_init_config(struct ath10k *ar)
{
u32 interconnect_targ_addr;
@@ -1608,7 +1652,8 @@ static int ath10k_pci_init_config(struct ath10k *ar)
/* first bank is switched to IRAM */
ealloc_value |= ((HI_EARLY_ALLOC_MAGIC << HI_EARLY_ALLOC_MAGIC_SHIFT) &
HI_EARLY_ALLOC_MAGIC_MASK);
- ealloc_value |= ((1 << HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
+ ealloc_value |= ((ath10k_pci_get_num_banks(ar) <<
+ HI_EARLY_ALLOC_IRAM_BANKS_SHIFT) &
HI_EARLY_ALLOC_IRAM_BANKS_MASK);
ret = ath10k_pci_diag_write32(ar, ealloc_targ_addr, ealloc_value);
@@ -1804,12 +1849,12 @@ static int ath10k_pci_warm_reset(struct ath10k *ar)
return 0;
}
-static int ath10k_pci_chip_reset(struct ath10k *ar)
+static int ath10k_pci_qca988x_chip_reset(struct ath10k *ar)
{
int i, ret;
u32 val;
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot 988x chip reset\n");
/* Some hardware revisions (e.g. CUS223v2) has issues with cold reset.
* It is thus preferred to use warm reset which is safer but may not be
@@ -1873,11 +1918,53 @@ static int ath10k_pci_chip_reset(struct ath10k *ar)
return ret;
}
- ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot chip reset complete (cold)\n");
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca988x chip reset complete (cold)\n");
+
+ return 0;
+}
+
+static int ath10k_pci_qca6174_chip_reset(struct ath10k *ar)
+{
+ int ret;
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset\n");
+
+ /* FIXME: QCA6174 requires cold + warm reset to work. */
+
+ ret = ath10k_pci_cold_reset(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to cold reset: %d\n", ret);
+ return ret;
+ }
+
+ ret = ath10k_pci_wait_for_target_init(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to wait for target after cold reset: %d\n",
+ ret);
+ return ret;
+ }
+
+ ret = ath10k_pci_warm_reset(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to warm reset: %d\n", ret);
+ return ret;
+ }
+
+ ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot qca6174 chip reset complete (cold)\n");
return 0;
}
+static int ath10k_pci_chip_reset(struct ath10k *ar)
+{
+ if (QCA_REV_988X(ar))
+ return ath10k_pci_qca988x_chip_reset(ar);
+ else if (QCA_REV_6174(ar))
+ return ath10k_pci_qca6174_chip_reset(ar);
+ else
+ return -ENOTSUPP;
+}
+
static int ath10k_pci_hif_power_up(struct ath10k *ar)
{
int ret;
@@ -1902,6 +1989,12 @@ static int ath10k_pci_hif_power_up(struct ath10k *ar)
*/
ret = ath10k_pci_chip_reset(ar);
if (ret) {
+ if (ath10k_pci_has_fw_crashed(ar)) {
+ ath10k_warn(ar, "firmware crashed during chip reset\n");
+ ath10k_pci_fw_crashed_clear(ar);
+ ath10k_pci_fw_crashed_dump(ar);
+ }
+
ath10k_err(ar, "failed to reset chip: %d\n", ret);
goto err_sleep;
}
@@ -2033,6 +2126,7 @@ static void ath10k_msi_err_tasklet(unsigned long data)
return;
}
+ ath10k_pci_irq_disable(ar);
ath10k_pci_fw_crashed_clear(ar);
ath10k_pci_fw_crashed_dump(ar);
}
@@ -2102,6 +2196,7 @@ static void ath10k_pci_tasklet(unsigned long data)
struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
if (ath10k_pci_has_fw_crashed(ar)) {
+ ath10k_pci_irq_disable(ar);
ath10k_pci_fw_crashed_clear(ar);
ath10k_pci_fw_crashed_dump(ar);
return;
@@ -2344,8 +2439,6 @@ static int ath10k_pci_wait_for_target_init(struct ath10k *ar)
if (val & FW_IND_EVENT_PENDING) {
ath10k_warn(ar, "device has crashed during init\n");
- ath10k_pci_fw_crashed_clear(ar);
- ath10k_pci_fw_crashed_dump(ar);
return -ECOMM;
}
@@ -2476,17 +2569,46 @@ static void ath10k_pci_release(struct ath10k *ar)
pci_disable_device(pdev);
}
+static bool ath10k_pci_chip_is_supported(u32 dev_id, u32 chip_id)
+{
+ const struct ath10k_pci_supp_chip *supp_chip;
+ int i;
+ u32 rev_id = MS(chip_id, SOC_CHIP_ID_REV);
+
+ for (i = 0; i < ARRAY_SIZE(ath10k_pci_supp_chips); i++) {
+ supp_chip = &ath10k_pci_supp_chips[i];
+
+ if (supp_chip->dev_id == dev_id &&
+ supp_chip->rev_id == rev_id)
+ return true;
+ }
+
+ return false;
+}
+
static int ath10k_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *pci_dev)
{
int ret = 0;
struct ath10k *ar;
struct ath10k_pci *ar_pci;
+ enum ath10k_hw_rev hw_rev;
u32 chip_id;
- ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev,
- ATH10K_BUS_PCI,
- &ath10k_pci_hif_ops);
+ switch (pci_dev->device) {
+ case QCA988X_2_0_DEVICE_ID:
+ hw_rev = ATH10K_HW_QCA988X;
+ break;
+ case QCA6174_2_1_DEVICE_ID:
+ hw_rev = ATH10K_HW_QCA6174;
+ break;
+ default:
+ WARN_ON(1);
+ return -ENOTSUPP;
+ }
+
+ ar = ath10k_core_create(sizeof(*ar_pci), &pdev->dev, ATH10K_BUS_PCI,
+ hw_rev, &ath10k_pci_hif_ops);
if (!ar) {
dev_err(&pdev->dev, "failed to allocate core\n");
return -ENOMEM;
@@ -2515,12 +2637,6 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_release;
}
- chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
- if (chip_id == 0xffffffff) {
- ath10k_err(ar, "failed to get chip id\n");
- goto err_sleep;
- }
-
ret = ath10k_pci_alloc_pipes(ar);
if (ret) {
ath10k_err(ar, "failed to allocate copy engine pipes: %d\n",
@@ -2547,6 +2663,24 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
goto err_deinit_irq;
}
+ ret = ath10k_pci_chip_reset(ar);
+ if (ret) {
+ ath10k_err(ar, "failed to reset chip: %d\n", ret);
+ goto err_free_irq;
+ }
+
+ chip_id = ath10k_pci_soc_read32(ar, SOC_CHIP_ID_ADDRESS);
+ if (chip_id == 0xffffffff) {
+ ath10k_err(ar, "failed to get chip id\n");
+ goto err_free_irq;
+ }
+
+ if (!ath10k_pci_chip_is_supported(pdev->device, chip_id)) {
+ ath10k_err(ar, "device %04x with chip_id %08x isn't supported\n",
+ pdev->device, chip_id);
+ goto err_sleep;
+ }
+
ath10k_pci_sleep(ar);
ret = ath10k_core_register(ar, chip_id);
diff --git a/drivers/net/wireless/ath/ath10k/pci.h b/drivers/net/wireless/ath/ath10k/pci.h
index cf36511c7f4d..bddf54320160 100644
--- a/drivers/net/wireless/ath/ath10k/pci.h
+++ b/drivers/net/wireless/ath/ath10k/pci.h
@@ -152,6 +152,11 @@ struct ath10k_pci_pipe {
struct tasklet_struct intr;
};
+struct ath10k_pci_supp_chip {
+ u32 dev_id;
+ u32 rev_id;
+};
+
struct ath10k_pci {
struct pci_dev *pdev;
struct device *dev;
@@ -189,7 +194,7 @@ static inline struct ath10k_pci *ath10k_pci_priv(struct ath10k *ar)
#define ATH10K_PCI_RX_POST_RETRY_MS 50
#define ATH_PCI_RESET_WAIT_MAX 10 /* ms */
-#define PCIE_WAKE_TIMEOUT 5000 /* 5ms */
+#define PCIE_WAKE_TIMEOUT 10000 /* 10ms */
#define BAR_NUM 0
diff --git a/drivers/net/wireless/ath/ath10k/rx_desc.h b/drivers/net/wireless/ath/ath10k/rx_desc.h
index e1ffdd57a18c..e9cc7787bf5f 100644
--- a/drivers/net/wireless/ath/ath10k/rx_desc.h
+++ b/drivers/net/wireless/ath/ath10k/rx_desc.h
@@ -850,7 +850,7 @@ struct rx_ppdu_start {
#define RX_PPDU_END_INFO1_PPDU_DONE (1 << 15)
-struct rx_ppdu_end {
+struct rx_ppdu_end_common {
__le32 evm_p0;
__le32 evm_p1;
__le32 evm_p2;
@@ -873,10 +873,33 @@ struct rx_ppdu_end {
u8 phy_err_code;
__le16 flags; /* %RX_PPDU_END_FLAGS_ */
__le32 info0; /* %RX_PPDU_END_INFO0_ */
+} __packed;
+
+struct rx_ppdu_end_qca988x {
__le16 bb_length;
__le16 info1; /* %RX_PPDU_END_INFO1_ */
} __packed;
+#define RX_PPDU_END_RTT_CORRELATION_VALUE_MASK 0x00ffffff
+#define RX_PPDU_END_RTT_CORRELATION_VALUE_LSB 0
+#define RX_PPDU_END_RTT_UNUSED_MASK 0x7f000000
+#define RX_PPDU_END_RTT_UNUSED_LSB 24
+#define RX_PPDU_END_RTT_NORMAL_MODE BIT(31)
+
+struct rx_ppdu_end_qca6174 {
+ __le32 rtt; /* %RX_PPDU_END_RTT_ */
+ __le16 bb_length;
+ __le16 info1; /* %RX_PPDU_END_INFO1_ */
+} __packed;
+
+struct rx_ppdu_end {
+ struct rx_ppdu_end_common common;
+ union {
+ struct rx_ppdu_end_qca988x qca988x;
+ struct rx_ppdu_end_qca6174 qca6174;
+ } __packed;
+} __packed;
+
/*
* evm_p0
* EVM for pilot 0. Contain EVM for streams: 0, 1, 2 and 3.
diff --git a/drivers/net/wireless/ath/ath10k/spectral.c b/drivers/net/wireless/ath/ath10k/spectral.c
index 63ce61fcdac8..d22addf6118b 100644
--- a/drivers/net/wireless/ath/ath10k/spectral.c
+++ b/drivers/net/wireless/ath/ath10k/spectral.c
@@ -17,6 +17,7 @@
#include <linux/relay.h>
#include "core.h"
#include "debug.h"
+#include "wmi-ops.h"
static void send_fft_sample(struct ath10k *ar,
const struct fft_sample_tlv *fft_sample_tlv)
diff --git a/drivers/net/wireless/ath/ath10k/targaddrs.h b/drivers/net/wireless/ath/ath10k/targaddrs.h
index 9d0ae30f9ff1..a417aae52623 100644
--- a/drivers/net/wireless/ath/ath10k/targaddrs.h
+++ b/drivers/net/wireless/ath/ath10k/targaddrs.h
@@ -18,6 +18,8 @@
#ifndef __TARGADDRS_H__
#define __TARGADDRS_H__
+#include "hw.h"
+
/*
* xxx_HOST_INTEREST_ADDRESS is the address in Target RAM of the
* host_interest structure. It must match the address of the _host_interest
@@ -445,4 +447,7 @@ Fw Mode/SubMode Mask
#define QCA988X_BOARD_DATA_SZ 7168
#define QCA988X_BOARD_EXT_DATA_SZ 0
+#define QCA6174_BOARD_DATA_SZ 8192
+#define QCA6174_BOARD_EXT_DATA_SZ 0
+
#endif /* __TARGADDRS_H__ */
diff --git a/drivers/net/wireless/ath/ath10k/testmode.c b/drivers/net/wireless/ath/ath10k/testmode.c
index 483db9cb8c96..b084f88da102 100644
--- a/drivers/net/wireless/ath/ath10k/testmode.c
+++ b/drivers/net/wireless/ath/ath10k/testmode.c
@@ -187,13 +187,14 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
memcpy(ar->testmode.orig_fw_features, ar->fw_features,
sizeof(ar->fw_features));
+ ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
/* utf.bin firmware image does not advertise firmware features. Do
* an ugly hack where we force the firmware features so that wmi.c
* will use the correct WMI interface.
*/
memset(ar->fw_features, 0, sizeof(ar->fw_features));
- __set_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features);
+ ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
ret = ath10k_hif_power_up(ar);
if (ret) {
@@ -224,6 +225,7 @@ err_fw_features:
/* return the original firmware features */
memcpy(ar->fw_features, ar->testmode.orig_fw_features,
sizeof(ar->fw_features));
+ ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
release_firmware(ar->testmode.utf);
ar->testmode.utf = NULL;
@@ -250,6 +252,7 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
/* return the original firmware features */
memcpy(ar->fw_features, ar->testmode.orig_fw_features,
sizeof(ar->fw_features));
+ ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
release_firmware(ar->testmode.utf);
ar->testmode.utf = NULL;
diff --git a/drivers/net/wireless/ath/ath10k/thermal.c b/drivers/net/wireless/ath/ath10k/thermal.c
new file mode 100644
index 000000000000..aede750809fe
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/thermal.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <linux/device.h>
+#include <linux/sysfs.h>
+#include <linux/thermal.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include "core.h"
+#include "debug.h"
+#include "wmi-ops.h"
+
+static int ath10k_thermal_get_active_vifs(struct ath10k *ar,
+ enum wmi_vdev_type type)
+{
+ struct ath10k_vif *arvif;
+ int count = 0;
+
+ lockdep_assert_held(&ar->conf_mutex);
+
+ list_for_each_entry(arvif, &ar->arvifs, list) {
+ if (!arvif->is_started)
+ continue;
+
+ if (!arvif->is_up)
+ continue;
+
+ if (arvif->vdev_type != type)
+ continue;
+
+ count++;
+ }
+ return count;
+}
+
+static int ath10k_thermal_get_max_dutycycle(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ *state = ATH10K_QUIET_DUTY_CYCLE_MAX;
+
+ return 0;
+}
+
+static int ath10k_thermal_get_cur_dutycycle(struct thermal_cooling_device *cdev,
+ unsigned long *state)
+{
+ struct ath10k *ar = cdev->devdata;
+
+ mutex_lock(&ar->conf_mutex);
+ *state = ar->thermal.duty_cycle;
+ mutex_unlock(&ar->conf_mutex);
+
+ return 0;
+}
+
+static int ath10k_thermal_set_cur_dutycycle(struct thermal_cooling_device *cdev,
+ unsigned long duty_cycle)
+{
+ struct ath10k *ar = cdev->devdata;
+ u32 period, duration, enabled;
+ int num_bss, ret = 0;
+
+ mutex_lock(&ar->conf_mutex);
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto out;
+ }
+
+ if (duty_cycle > ATH10K_QUIET_DUTY_CYCLE_MAX) {
+ ath10k_warn(ar, "duty cycle %ld is exceeding the limit %d\n",
+ duty_cycle, ATH10K_QUIET_DUTY_CYCLE_MAX);
+ ret = -EINVAL;
+ goto out;
+ }
+ /* TODO: Right now, thermal mitigation is handled only for single/multi
+ * vif AP mode. Since quiet param is not validated in STA mode, it needs
+ * to be investigated further to handle multi STA and multi-vif (AP+STA)
+ * mode properly.
+ */
+ num_bss = ath10k_thermal_get_active_vifs(ar, WMI_VDEV_TYPE_AP);
+ if (!num_bss) {
+ ath10k_warn(ar, "no active AP interfaces\n");
+ ret = -ENETDOWN;
+ goto out;
+ }
+ period = max(ATH10K_QUIET_PERIOD_MIN,
+ (ATH10K_QUIET_PERIOD_DEFAULT / num_bss));
+ duration = (period * duty_cycle) / 100;
+ enabled = duration ? 1 : 0;
+
+ ret = ath10k_wmi_pdev_set_quiet_mode(ar, period, duration,
+ ATH10K_QUIET_START_OFFSET,
+ enabled);
+ if (ret) {
+ ath10k_warn(ar, "failed to set quiet mode period %u duarion %u enabled %u ret %d\n",
+ period, duration, enabled, ret);
+ goto out;
+ }
+ ar->thermal.duty_cycle = duty_cycle;
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+static struct thermal_cooling_device_ops ath10k_thermal_ops = {
+ .get_max_state = ath10k_thermal_get_max_dutycycle,
+ .get_cur_state = ath10k_thermal_get_cur_dutycycle,
+ .set_cur_state = ath10k_thermal_set_cur_dutycycle,
+};
+
+static ssize_t ath10k_thermal_show_temp(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct ath10k *ar = dev_get_drvdata(dev);
+ int ret, temperature;
+
+ mutex_lock(&ar->conf_mutex);
+
+ /* Can't get temperature when the card is off */
+ if (ar->state != ATH10K_STATE_ON) {
+ ret = -ENETDOWN;
+ goto out;
+ }
+
+ reinit_completion(&ar->thermal.wmi_sync);
+ ret = ath10k_wmi_pdev_get_temperature(ar);
+ if (ret) {
+ ath10k_warn(ar, "failed to read temperature %d\n", ret);
+ goto out;
+ }
+
+ if (test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags)) {
+ ret = -ESHUTDOWN;
+ goto out;
+ }
+
+ ret = wait_for_completion_timeout(&ar->thermal.wmi_sync,
+ ATH10K_THERMAL_SYNC_TIMEOUT_HZ);
+ if (ret == 0) {
+ ath10k_warn(ar, "failed to synchronize thermal read\n");
+ ret = -ETIMEDOUT;
+ goto out;
+ }
+
+ spin_lock_bh(&ar->data_lock);
+ temperature = ar->thermal.temperature;
+ spin_unlock_bh(&ar->data_lock);
+
+ /* display in millidegree celcius */
+ ret = snprintf(buf, PAGE_SIZE, "%d\n", temperature * 1000);
+out:
+ mutex_unlock(&ar->conf_mutex);
+ return ret;
+}
+
+void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature)
+{
+ spin_lock_bh(&ar->data_lock);
+ ar->thermal.temperature = temperature;
+ spin_unlock_bh(&ar->data_lock);
+ complete(&ar->thermal.wmi_sync);
+}
+
+static SENSOR_DEVICE_ATTR(temp1_input, S_IRUGO, ath10k_thermal_show_temp,
+ NULL, 0);
+
+static struct attribute *ath10k_hwmon_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ NULL,
+};
+ATTRIBUTE_GROUPS(ath10k_hwmon);
+
+int ath10k_thermal_register(struct ath10k *ar)
+{
+ struct thermal_cooling_device *cdev;
+ struct device *hwmon_dev;
+ int ret;
+
+ cdev = thermal_cooling_device_register("ath10k_thermal", ar,
+ &ath10k_thermal_ops);
+
+ if (IS_ERR(cdev)) {
+ ath10k_err(ar, "failed to setup thermal device result: %ld\n",
+ PTR_ERR(cdev));
+ return -EINVAL;
+ }
+
+ ret = sysfs_create_link(&ar->dev->kobj, &cdev->device.kobj,
+ "cooling_device");
+ if (ret) {
+ ath10k_err(ar, "failed to create thermal symlink\n");
+ goto err_cooling_destroy;
+ }
+
+ ar->thermal.cdev = cdev;
+
+ /* Do not register hwmon device when temperature reading is not
+ * supported by firmware
+ */
+ if (ar->wmi.op_version != ATH10K_FW_WMI_OP_VERSION_10_2_4)
+ return 0;
+
+ /* Avoid linking error on devm_hwmon_device_register_with_groups, I
+ * guess linux/hwmon.h is missing proper stubs. */
+ if (!config_enabled(CONFIG_HWMON))
+ return 0;
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(ar->dev,
+ "ath10k_hwmon", ar,
+ ath10k_hwmon_groups);
+ if (IS_ERR(hwmon_dev)) {
+ ath10k_err(ar, "failed to register hwmon device: %ld\n",
+ PTR_ERR(hwmon_dev));
+ ret = -EINVAL;
+ goto err_remove_link;
+ }
+ return 0;
+
+err_remove_link:
+ sysfs_remove_link(&ar->dev->kobj, "thermal_sensor");
+err_cooling_destroy:
+ thermal_cooling_device_unregister(cdev);
+ return ret;
+}
+
+void ath10k_thermal_unregister(struct ath10k *ar)
+{
+ thermal_cooling_device_unregister(ar->thermal.cdev);
+ sysfs_remove_link(&ar->dev->kobj, "cooling_device");
+}
diff --git a/drivers/net/wireless/ath/ath10k/thermal.h b/drivers/net/wireless/ath/ath10k/thermal.h
new file mode 100644
index 000000000000..bccc17ae0fde
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/thermal.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _THERMAL_
+#define _THERMAL_
+
+#define ATH10K_QUIET_PERIOD_DEFAULT 100
+#define ATH10K_QUIET_PERIOD_MIN 25
+#define ATH10K_QUIET_START_OFFSET 10
+#define ATH10K_QUIET_DUTY_CYCLE_MAX 70
+#define ATH10K_HWMON_NAME_LEN 15
+#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
+
+struct ath10k_thermal {
+ struct thermal_cooling_device *cdev;
+ struct completion wmi_sync;
+
+ /* protected by conf_mutex */
+ u32 duty_cycle;
+ /* temperature value in Celcius degree
+ * protected by data_lock
+ */
+ int temperature;
+};
+
+#ifdef CONFIG_THERMAL
+int ath10k_thermal_register(struct ath10k *ar);
+void ath10k_thermal_unregister(struct ath10k *ar);
+void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
+#else
+static inline int ath10k_thermal_register(struct ath10k *ar)
+{
+ return 0;
+}
+
+static inline void ath10k_thermal_unregister(struct ath10k *ar)
+{
+}
+
+static inline void ath10k_thermal_event_temperature(struct ath10k *ar,
+ int temperature)
+{
+}
+
+#endif
+#endif /* _THERMAL_ */
diff --git a/drivers/net/wireless/ath/ath10k/trace.h b/drivers/net/wireless/ath/ath10k/trace.h
index b289378b6e3e..5407887380ab 100644
--- a/drivers/net/wireless/ath/ath10k/trace.h
+++ b/drivers/net/wireless/ath/ath10k/trace.h
@@ -453,6 +453,74 @@ TRACE_EVENT(ath10k_htt_rx_desc,
)
);
+TRACE_EVENT(ath10k_wmi_diag_container,
+ TP_PROTO(struct ath10k *ar,
+ u8 type,
+ u32 timestamp,
+ u32 code,
+ u16 len,
+ const void *data),
+
+ TP_ARGS(ar, type, timestamp, code, len, data),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(u8, type)
+ __field(u32, timestamp)
+ __field(u32, code)
+ __field(u16, len)
+ __dynamic_array(u8, data, len)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->type = type;
+ __entry->timestamp = timestamp;
+ __entry->code = code;
+ __entry->len = len;
+ memcpy(__get_dynamic_array(data), data, len);
+ ),
+
+ TP_printk(
+ "%s %s diag container type %hhu timestamp %u code %u len %d",
+ __get_str(driver),
+ __get_str(device),
+ __entry->type,
+ __entry->timestamp,
+ __entry->code,
+ __entry->len
+ )
+);
+
+TRACE_EVENT(ath10k_wmi_diag,
+ TP_PROTO(struct ath10k *ar, const void *data, size_t len),
+
+ TP_ARGS(ar, data, len),
+
+ TP_STRUCT__entry(
+ __string(device, dev_name(ar->dev))
+ __string(driver, dev_driver_string(ar->dev))
+ __field(u16, len)
+ __dynamic_array(u8, data, len)
+ ),
+
+ TP_fast_assign(
+ __assign_str(device, dev_name(ar->dev));
+ __assign_str(driver, dev_driver_string(ar->dev));
+ __entry->len = len;
+ memcpy(__get_dynamic_array(data), data, len);
+ ),
+
+ TP_printk(
+ "%s %s tlv diag len %d",
+ __get_str(driver),
+ __get_str(device),
+ __entry->len
+ )
+);
+
#endif /* _TRACE_H_ || TRACE_HEADER_MULTI_READ*/
/* we don't want to use include/trace/events */
diff --git a/drivers/net/wireless/ath/ath10k/txrx.c b/drivers/net/wireless/ath/ath10k/txrx.c
index 7579de8e7a8c..3f00cec8aef5 100644
--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++ b/drivers/net/wireless/ath/ath10k/txrx.c
@@ -64,7 +64,13 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
return;
}
- msdu = htt->pending_tx[tx_done->msdu_id];
+ msdu = idr_find(&htt->pending_tx, tx_done->msdu_id);
+ if (!msdu) {
+ ath10k_warn(ar, "received tx completion for invalid msdu_id: %d\n",
+ tx_done->msdu_id);
+ return;
+ }
+
skb_cb = ATH10K_SKB_CB(msdu);
dma_unmap_single(dev, skb_cb->paddr, msdu->len, DMA_TO_DEVICE);
@@ -95,7 +101,6 @@ void ath10k_txrx_tx_unref(struct ath10k_htt *htt,
/* we do not own the msdu anymore */
exit:
- htt->pending_tx[tx_done->msdu_id] = NULL;
ath10k_htt_tx_free_msdu_id(htt, tx_done->msdu_id);
__ath10k_htt_tx_dec_pending(htt);
if (htt->num_pending_tx == 0)
diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h
new file mode 100644
index 000000000000..04dc4b9db04e
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h
@@ -0,0 +1,1064 @@
+/*
+ * Copyright (c) 2005-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _WMI_OPS_H_
+#define _WMI_OPS_H_
+
+struct ath10k;
+struct sk_buff;
+
+struct wmi_ops {
+ void (*rx)(struct ath10k *ar, struct sk_buff *skb);
+ void (*map_svc)(const __le32 *in, unsigned long *out, size_t len);
+
+ int (*pull_scan)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_scan_ev_arg *arg);
+ int (*pull_mgmt_rx)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_mgmt_rx_ev_arg *arg);
+ int (*pull_ch_info)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_ch_info_ev_arg *arg);
+ int (*pull_vdev_start)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_vdev_start_ev_arg *arg);
+ int (*pull_peer_kick)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_peer_kick_ev_arg *arg);
+ int (*pull_swba)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_swba_ev_arg *arg);
+ int (*pull_phyerr)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_phyerr_ev_arg *arg);
+ int (*pull_svc_rdy)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg);
+ int (*pull_rdy)(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_rdy_ev_arg *arg);
+ int (*pull_fw_stats)(struct ath10k *ar, struct sk_buff *skb,
+ struct ath10k_fw_stats *stats);
+
+ struct sk_buff *(*gen_pdev_suspend)(struct ath10k *ar, u32 suspend_opt);
+ struct sk_buff *(*gen_pdev_resume)(struct ath10k *ar);
+ struct sk_buff *(*gen_pdev_set_rd)(struct ath10k *ar, u16 rd, u16 rd2g,
+ u16 rd5g, u16 ctl2g, u16 ctl5g,
+ enum wmi_dfs_region dfs_reg);
+ struct sk_buff *(*gen_pdev_set_param)(struct ath10k *ar, u32 id,
+ u32 value);
+ struct sk_buff *(*gen_init)(struct ath10k *ar);
+ struct sk_buff *(*gen_start_scan)(struct ath10k *ar,
+ const struct wmi_start_scan_arg *arg);
+ struct sk_buff *(*gen_stop_scan)(struct ath10k *ar,
+ const struct wmi_stop_scan_arg *arg);
+ struct sk_buff *(*gen_vdev_create)(struct ath10k *ar, u32 vdev_id,
+ enum wmi_vdev_type type,
+ enum wmi_vdev_subtype subtype,
+ const u8 macaddr[ETH_ALEN]);
+ struct sk_buff *(*gen_vdev_delete)(struct ath10k *ar, u32 vdev_id);
+ struct sk_buff *(*gen_vdev_start)(struct ath10k *ar,
+ const struct wmi_vdev_start_request_arg *arg,
+ bool restart);
+ struct sk_buff *(*gen_vdev_stop)(struct ath10k *ar, u32 vdev_id);
+ struct sk_buff *(*gen_vdev_up)(struct ath10k *ar, u32 vdev_id, u32 aid,
+ const u8 *bssid);
+ struct sk_buff *(*gen_vdev_down)(struct ath10k *ar, u32 vdev_id);
+ struct sk_buff *(*gen_vdev_set_param)(struct ath10k *ar, u32 vdev_id,
+ u32 param_id, u32 param_value);
+ struct sk_buff *(*gen_vdev_install_key)(struct ath10k *ar,
+ const struct wmi_vdev_install_key_arg *arg);
+ struct sk_buff *(*gen_vdev_spectral_conf)(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg);
+ struct sk_buff *(*gen_vdev_spectral_enable)(struct ath10k *ar, u32 vdev_id,
+ u32 trigger, u32 enable);
+ struct sk_buff *(*gen_vdev_wmm_conf)(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_wmm_params_all_arg *arg);
+ struct sk_buff *(*gen_peer_create)(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN]);
+ struct sk_buff *(*gen_peer_delete)(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN]);
+ struct sk_buff *(*gen_peer_flush)(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN],
+ u32 tid_bitmap);
+ struct sk_buff *(*gen_peer_set_param)(struct ath10k *ar, u32 vdev_id,
+ const u8 *peer_addr,
+ enum wmi_peer_param param_id,
+ u32 param_value);
+ struct sk_buff *(*gen_peer_assoc)(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg);
+ struct sk_buff *(*gen_set_psmode)(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_ps_mode psmode);
+ struct sk_buff *(*gen_set_sta_ps)(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_powersave_param param_id,
+ u32 value);
+ struct sk_buff *(*gen_set_ap_ps)(struct ath10k *ar, u32 vdev_id,
+ const u8 *mac,
+ enum wmi_ap_ps_peer_param param_id,
+ u32 value);
+ struct sk_buff *(*gen_scan_chan_list)(struct ath10k *ar,
+ const struct wmi_scan_chan_list_arg *arg);
+ struct sk_buff *(*gen_beacon_dma)(struct ath10k *ar, u32 vdev_id,
+ const void *bcn, size_t bcn_len,
+ u32 bcn_paddr, bool dtim_zero,
+ bool deliver_cab);
+ struct sk_buff *(*gen_pdev_set_wmm)(struct ath10k *ar,
+ const struct wmi_wmm_params_all_arg *arg);
+ struct sk_buff *(*gen_request_stats)(struct ath10k *ar,
+ enum wmi_stats_id stats_id);
+ struct sk_buff *(*gen_force_fw_hang)(struct ath10k *ar,
+ enum wmi_force_fw_hang_type type,
+ u32 delay_ms);
+ struct sk_buff *(*gen_mgmt_tx)(struct ath10k *ar, struct sk_buff *skb);
+ struct sk_buff *(*gen_dbglog_cfg)(struct ath10k *ar, u32 module_enable,
+ u32 log_level);
+ struct sk_buff *(*gen_pktlog_enable)(struct ath10k *ar, u32 filter);
+ struct sk_buff *(*gen_pktlog_disable)(struct ath10k *ar);
+ struct sk_buff *(*gen_pdev_set_quiet_mode)(struct ath10k *ar,
+ u32 period, u32 duration,
+ u32 next_offset,
+ u32 enabled);
+ struct sk_buff *(*gen_pdev_get_temperature)(struct ath10k *ar);
+ struct sk_buff *(*gen_addba_clear_resp)(struct ath10k *ar, u32 vdev_id,
+ const u8 *mac);
+ struct sk_buff *(*gen_addba_send)(struct ath10k *ar, u32 vdev_id,
+ const u8 *mac, u32 tid, u32 buf_size);
+ struct sk_buff *(*gen_addba_set_resp)(struct ath10k *ar, u32 vdev_id,
+ const u8 *mac, u32 tid,
+ u32 status);
+ struct sk_buff *(*gen_delba_send)(struct ath10k *ar, u32 vdev_id,
+ const u8 *mac, u32 tid, u32 initiator,
+ u32 reason);
+ struct sk_buff *(*gen_bcn_tmpl)(struct ath10k *ar, u32 vdev_id,
+ u32 tim_ie_offset, struct sk_buff *bcn,
+ u32 prb_caps, u32 prb_erp,
+ void *prb_ies, size_t prb_ies_len);
+ struct sk_buff *(*gen_prb_tmpl)(struct ath10k *ar, u32 vdev_id,
+ struct sk_buff *bcn);
+ struct sk_buff *(*gen_p2p_go_bcn_ie)(struct ath10k *ar, u32 vdev_id,
+ const u8 *p2p_ie);
+ struct sk_buff *(*gen_vdev_sta_uapsd)(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN],
+ const struct wmi_sta_uapsd_auto_trig_arg *args,
+ u32 num_ac);
+ struct sk_buff *(*gen_sta_keepalive)(struct ath10k *ar,
+ const struct wmi_sta_keepalive_arg *arg);
+};
+
+int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
+
+static inline int
+ath10k_wmi_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+ if (WARN_ON_ONCE(!ar->wmi.ops->rx))
+ return -EOPNOTSUPP;
+
+ ar->wmi.ops->rx(ar, skb);
+ return 0;
+}
+
+static inline int
+ath10k_wmi_map_svc(struct ath10k *ar, const __le32 *in, unsigned long *out,
+ size_t len)
+{
+ if (!ar->wmi.ops->map_svc)
+ return -EOPNOTSUPP;
+
+ ar->wmi.ops->map_svc(in, out, len);
+ return 0;
+}
+
+static inline int
+ath10k_wmi_pull_scan(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_scan_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_scan)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_scan(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_mgmt_rx(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_mgmt_rx_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_mgmt_rx)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_mgmt_rx(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_ch_info(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_ch_info_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_ch_info)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_ch_info(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_vdev_start(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_vdev_start_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_vdev_start)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_vdev_start(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_peer_kick(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_peer_kick_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_peer_kick)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_peer_kick(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_swba(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_swba_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_swba)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_swba(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_phyerr(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_phyerr_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_phyerr)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_phyerr(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_svc_rdy(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_svc_rdy)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_svc_rdy(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_rdy(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_rdy_ev_arg *arg)
+{
+ if (!ar->wmi.ops->pull_rdy)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_rdy(ar, skb, arg);
+}
+
+static inline int
+ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ if (!ar->wmi.ops->pull_fw_stats)
+ return -EOPNOTSUPP;
+
+ return ar->wmi.ops->pull_fw_stats(ar, skb, stats);
+}
+
+static inline int
+ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
+{
+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
+ struct sk_buff *skb;
+ int ret;
+
+ if (!ar->wmi.ops->gen_mgmt_tx)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_mgmt_tx(ar, msdu);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ret = ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->mgmt_tx_cmdid);
+ if (ret)
+ return ret;
+
+ /* FIXME There's no ACK event for Management Tx. This probably
+ * shouldn't be called here either. */
+ info->flags |= IEEE80211_TX_STAT_ACK;
+ ieee80211_tx_status_irqsafe(ar->hw, msdu);
+
+ return 0;
+}
+
+static inline int
+ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g,
+ u16 ctl2g, u16 ctl5g,
+ enum wmi_dfs_region dfs_reg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_set_rd)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_set_rd(ar, rd, rd2g, rd5g, ctl2g, ctl5g,
+ dfs_reg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_set_regdomain_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_suspend)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_suspend(ar, suspend_opt);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_resume_target(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_resume)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_resume(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_set_param)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_set_param(ar, id, value);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_cmd_init(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_init)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_init(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->init_cmdid);
+}
+
+static inline int
+ath10k_wmi_start_scan(struct ath10k *ar,
+ const struct wmi_start_scan_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_start_scan)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_start_scan(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
+}
+
+static inline int
+ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_stop_scan)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_stop_scan(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
+ enum wmi_vdev_type type,
+ enum wmi_vdev_subtype subtype,
+ const u8 macaddr[ETH_ALEN])
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_create)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_create(ar, vdev_id, type, subtype, macaddr);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_delete)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_delete(ar, vdev_id);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_start(struct ath10k *ar,
+ const struct wmi_vdev_start_request_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_start)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_start(ar, arg, false);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->vdev_start_request_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_restart(struct ath10k *ar,
+ const struct wmi_vdev_start_request_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_start)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_start(ar, arg, true);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->vdev_restart_request_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_stop)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_stop(ar, vdev_id);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_up)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_up(ar, vdev_id, aid, bssid);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_down)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_down(ar, vdev_id);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id, u32 param_id,
+ u32 param_value)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_set_param)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_set_param(ar, vdev_id, param_id,
+ param_value);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_install_key(struct ath10k *ar,
+ const struct wmi_vdev_install_key_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_vdev_install_key)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_install_key(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->vdev_install_key_cmdid);
+}
+
+static inline int
+ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ skb = ar->wmi.ops->gen_vdev_spectral_conf(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
+ u32 enable)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ skb = ar->wmi.ops->gen_vdev_spectral_enable(ar, vdev_id, trigger,
+ enable);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN],
+ const struct wmi_sta_uapsd_auto_trig_arg *args,
+ u32 num_ac)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_vdev_sta_uapsd)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_vdev_sta_uapsd(ar, vdev_id, peer_addr, args,
+ num_ac);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->sta_uapsd_auto_trig_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_wmm_params_all_arg *arg)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ skb = ar->wmi.ops->gen_vdev_wmm_conf(ar, vdev_id, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->vdev_set_wmm_params_cmdid;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+static inline int
+ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN])
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_peer_create)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_peer_create(ar, vdev_id, peer_addr);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN])
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_peer_delete)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_peer_delete(ar, vdev_id, peer_addr);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_peer_flush)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_peer_flush(ar, vdev_id, peer_addr, tid_bitmap);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id, const u8 *peer_addr,
+ enum wmi_peer_param param_id, u32 param_value)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_peer_set_param)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_peer_set_param(ar, vdev_id, peer_addr, param_id,
+ param_value);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_ps_mode psmode)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_set_psmode)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_set_psmode(ar, vdev_id, psmode);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->sta_powersave_mode_cmdid);
+}
+
+static inline int
+ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_powersave_param param_id, u32 value)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_set_sta_ps)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_set_sta_ps(ar, vdev_id, param_id, value);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->sta_powersave_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ enum wmi_ap_ps_peer_param param_id, u32 value)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_set_ap_ps)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_set_ap_ps(ar, vdev_id, mac, param_id, value);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->ap_ps_peer_param_cmdid);
+}
+
+static inline int
+ath10k_wmi_scan_chan_list(struct ath10k *ar,
+ const struct wmi_scan_chan_list_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_scan_chan_list)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_scan_chan_list(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
+}
+
+static inline int
+ath10k_wmi_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_peer_assoc)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_peer_assoc(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
+}
+
+static inline int
+ath10k_wmi_beacon_send_ref_nowait(struct ath10k *ar, u32 vdev_id,
+ const void *bcn, size_t bcn_len,
+ u32 bcn_paddr, bool dtim_zero,
+ bool deliver_cab)
+{
+ struct sk_buff *skb;
+ int ret;
+
+ if (!ar->wmi.ops->gen_beacon_dma)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_beacon_dma(ar, vdev_id, bcn, bcn_len, bcn_paddr,
+ dtim_zero, deliver_cab);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ ret = ath10k_wmi_cmd_send_nowait(ar, skb,
+ ar->wmi.cmd->pdev_send_bcn_cmdid);
+ if (ret) {
+ dev_kfree_skb(skb);
+ return ret;
+ }
+
+ return 0;
+}
+
+static inline int
+ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
+ const struct wmi_wmm_params_all_arg *arg)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_set_wmm)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_set_wmm(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_set_wmm_params_cmdid);
+}
+
+static inline int
+ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_request_stats)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_request_stats(ar, stats_id);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
+}
+
+static inline int
+ath10k_wmi_force_fw_hang(struct ath10k *ar,
+ enum wmi_force_fw_hang_type type, u32 delay_ms)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_force_fw_hang)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_force_fw_hang(ar, type, delay_ms);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
+}
+
+static inline int
+ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable, u32 log_level)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_dbglog_cfg)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_dbglog_cfg(ar, module_enable, log_level);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 filter)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pktlog_enable)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pktlog_enable(ar, filter);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_pktlog_enable_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pktlog_disable)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pktlog_disable(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_pktlog_disable_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_set_quiet_mode(struct ath10k *ar, u32 period, u32 duration,
+ u32 next_offset, u32 enabled)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_set_quiet_mode)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_set_quiet_mode(ar, period, duration,
+ next_offset, enabled);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_set_quiet_mode_cmdid);
+}
+
+static inline int
+ath10k_wmi_pdev_get_temperature(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_pdev_get_temperature)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_pdev_get_temperature(ar);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->pdev_get_temperature_cmdid);
+}
+
+static inline int
+ath10k_wmi_addba_clear_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_addba_clear_resp)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_addba_clear_resp(ar, vdev_id, mac);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->addba_clear_resp_cmdid);
+}
+
+static inline int
+ath10k_wmi_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ u32 tid, u32 buf_size)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_addba_send)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_addba_send(ar, vdev_id, mac, tid, buf_size);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->addba_send_cmdid);
+}
+
+static inline int
+ath10k_wmi_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ u32 tid, u32 status)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_addba_set_resp)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_addba_set_resp(ar, vdev_id, mac, tid, status);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->addba_set_resp_cmdid);
+}
+
+static inline int
+ath10k_wmi_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ u32 tid, u32 initiator, u32 reason)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_delba_send)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_delba_send(ar, vdev_id, mac, tid, initiator,
+ reason);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb,
+ ar->wmi.cmd->delba_send_cmdid);
+}
+
+static inline int
+ath10k_wmi_bcn_tmpl(struct ath10k *ar, u32 vdev_id, u32 tim_ie_offset,
+ struct sk_buff *bcn, u32 prb_caps, u32 prb_erp,
+ void *prb_ies, size_t prb_ies_len)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_bcn_tmpl)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_bcn_tmpl(ar, vdev_id, tim_ie_offset, bcn,
+ prb_caps, prb_erp, prb_ies,
+ prb_ies_len);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->bcn_tmpl_cmdid);
+}
+
+static inline int
+ath10k_wmi_prb_tmpl(struct ath10k *ar, u32 vdev_id, struct sk_buff *prb)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_prb_tmpl)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_prb_tmpl(ar, vdev_id, prb);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->prb_tmpl_cmdid);
+}
+
+static inline int
+ath10k_wmi_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id, const u8 *p2p_ie)
+{
+ struct sk_buff *skb;
+
+ if (!ar->wmi.ops->gen_p2p_go_bcn_ie)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_p2p_go_bcn_ie(ar, vdev_id, p2p_ie);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->p2p_go_set_beacon_ie);
+}
+
+static inline int
+ath10k_wmi_sta_keepalive(struct ath10k *ar,
+ const struct wmi_sta_keepalive_arg *arg)
+{
+ struct sk_buff *skb;
+ u32 cmd_id;
+
+ if (!ar->wmi.ops->gen_sta_keepalive)
+ return -EOPNOTSUPP;
+
+ skb = ar->wmi.ops->gen_sta_keepalive(ar, arg);
+ if (IS_ERR(skb))
+ return PTR_ERR(skb);
+
+ cmd_id = ar->wmi.cmd->sta_keepalive_cmd;
+ return ath10k_wmi_cmd_send(ar, skb, cmd_id);
+}
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
new file mode 100644
index 000000000000..71614ba1b145
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c
@@ -0,0 +1,2696 @@
+/*
+ * Copyright (c) 2005-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include "core.h"
+#include "debug.h"
+#include "hw.h"
+#include "wmi.h"
+#include "wmi-ops.h"
+#include "wmi-tlv.h"
+
+/***************/
+/* TLV helpers */
+/**************/
+
+struct wmi_tlv_policy {
+ size_t min_len;
+};
+
+static const struct wmi_tlv_policy wmi_tlv_policies[] = {
+ [WMI_TLV_TAG_ARRAY_BYTE]
+ = { .min_len = sizeof(u8) },
+ [WMI_TLV_TAG_ARRAY_UINT32]
+ = { .min_len = sizeof(u32) },
+ [WMI_TLV_TAG_STRUCT_SCAN_EVENT]
+ = { .min_len = sizeof(struct wmi_scan_event) },
+ [WMI_TLV_TAG_STRUCT_MGMT_RX_HDR]
+ = { .min_len = sizeof(struct wmi_tlv_mgmt_rx_ev) },
+ [WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT]
+ = { .min_len = sizeof(struct wmi_chan_info_event) },
+ [WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT]
+ = { .min_len = sizeof(struct wmi_vdev_start_response_event) },
+ [WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT]
+ = { .min_len = sizeof(struct wmi_peer_sta_kickout_event) },
+ [WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT]
+ = { .min_len = sizeof(struct wmi_host_swba_event) },
+ [WMI_TLV_TAG_STRUCT_TIM_INFO]
+ = { .min_len = sizeof(struct wmi_tim_info) },
+ [WMI_TLV_TAG_STRUCT_P2P_NOA_INFO]
+ = { .min_len = sizeof(struct wmi_p2p_noa_info) },
+ [WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_svc_rdy_ev) },
+ [WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES]
+ = { .min_len = sizeof(struct hal_reg_capabilities) },
+ [WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ]
+ = { .min_len = sizeof(struct wlan_host_mem_req) },
+ [WMI_TLV_TAG_STRUCT_READY_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_rdy_ev) },
+ [WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_bcn_tx_status_ev) },
+ [WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT]
+ = { .min_len = sizeof(struct wmi_tlv_diag_data_ev) },
+};
+
+static int
+ath10k_wmi_tlv_iter(struct ath10k *ar, const void *ptr, size_t len,
+ int (*iter)(struct ath10k *ar, u16 tag, u16 len,
+ const void *ptr, void *data),
+ void *data)
+{
+ const void *begin = ptr;
+ const struct wmi_tlv *tlv;
+ u16 tlv_tag, tlv_len;
+ int ret;
+
+ while (len > 0) {
+ if (len < sizeof(*tlv)) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv parse failure at byte %zd (%zu bytes left, %zu expected)\n",
+ ptr - begin, len, sizeof(*tlv));
+ return -EINVAL;
+ }
+
+ tlv = ptr;
+ tlv_tag = __le16_to_cpu(tlv->tag);
+ tlv_len = __le16_to_cpu(tlv->len);
+ ptr += sizeof(*tlv);
+ len -= sizeof(*tlv);
+
+ if (tlv_len > len) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv parse failure of tag %hhu at byte %zd (%zu bytes left, %hhu expected)\n",
+ tlv_tag, ptr - begin, len, tlv_len);
+ return -EINVAL;
+ }
+
+ if (tlv_tag < ARRAY_SIZE(wmi_tlv_policies) &&
+ wmi_tlv_policies[tlv_tag].min_len &&
+ wmi_tlv_policies[tlv_tag].min_len > tlv_len) {
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv parse failure of tag %hhu at byte %zd (%hhu bytes is less than min length %zu)\n",
+ tlv_tag, ptr - begin, tlv_len,
+ wmi_tlv_policies[tlv_tag].min_len);
+ return -EINVAL;
+ }
+
+ ret = iter(ar, tlv_tag, tlv_len, ptr, data);
+ if (ret)
+ return ret;
+
+ ptr += tlv_len;
+ len -= tlv_len;
+ }
+
+ return 0;
+}
+
+static int ath10k_wmi_tlv_iter_parse(struct ath10k *ar, u16 tag, u16 len,
+ const void *ptr, void *data)
+{
+ const void **tb = data;
+
+ if (tag < WMI_TLV_TAG_MAX)
+ tb[tag] = ptr;
+
+ return 0;
+}
+
+static int ath10k_wmi_tlv_parse(struct ath10k *ar, const void **tb,
+ const void *ptr, size_t len)
+{
+ return ath10k_wmi_tlv_iter(ar, ptr, len, ath10k_wmi_tlv_iter_parse,
+ (void *)tb);
+}
+
+static const void **
+ath10k_wmi_tlv_parse_alloc(struct ath10k *ar, const void *ptr,
+ size_t len, gfp_t gfp)
+{
+ const void **tb;
+ int ret;
+
+ tb = kzalloc(sizeof(*tb) * WMI_TLV_TAG_MAX, gfp);
+ if (!tb)
+ return ERR_PTR(-ENOMEM);
+
+ ret = ath10k_wmi_tlv_parse(ar, tb, ptr, len);
+ if (ret) {
+ kfree(tb);
+ return ERR_PTR(ret);
+ }
+
+ return tb;
+}
+
+static u16 ath10k_wmi_tlv_len(const void *ptr)
+{
+ return __le16_to_cpu((((const struct wmi_tlv *)ptr) - 1)->len);
+}
+
+/**************/
+/* TLV events */
+/**************/
+static int ath10k_wmi_tlv_event_bcn_tx_status(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const struct wmi_tlv_bcn_tx_status_ev *ev;
+ u32 vdev_id, tx_status;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ tx_status = __le32_to_cpu(ev->tx_status);
+ vdev_id = __le32_to_cpu(ev->vdev_id);
+
+ switch (tx_status) {
+ case WMI_TLV_BCN_TX_STATUS_OK:
+ break;
+ case WMI_TLV_BCN_TX_STATUS_XRETRY:
+ case WMI_TLV_BCN_TX_STATUS_DROP:
+ case WMI_TLV_BCN_TX_STATUS_FILTERED:
+ /* FIXME: It's probably worth telling mac80211 to stop the
+ * interface as it is crippled.
+ */
+ ath10k_warn(ar, "received bcn tmpl tx status on vdev %i: %d",
+ vdev_id, tx_status);
+ break;
+ }
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_event_diag_data(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const struct wmi_tlv_diag_data_ev *ev;
+ const struct wmi_tlv_diag_item *item;
+ const void *data;
+ int ret, num_items, len;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT];
+ data = tb[WMI_TLV_TAG_ARRAY_BYTE];
+ if (!ev || !data) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ num_items = __le32_to_cpu(ev->num_items);
+ len = ath10k_wmi_tlv_len(data);
+
+ while (num_items--) {
+ if (len == 0)
+ break;
+ if (len < sizeof(*item)) {
+ ath10k_warn(ar, "failed to parse diag data: can't fit item header\n");
+ break;
+ }
+
+ item = data;
+
+ if (len < sizeof(*item) + __le16_to_cpu(item->len)) {
+ ath10k_warn(ar, "failed to parse diag data: item is too long\n");
+ break;
+ }
+
+ trace_ath10k_wmi_diag_container(ar,
+ item->type,
+ __le32_to_cpu(item->timestamp),
+ __le32_to_cpu(item->code),
+ __le16_to_cpu(item->len),
+ item->payload);
+
+ len -= sizeof(*item);
+ len -= roundup(__le16_to_cpu(item->len), 4);
+
+ data += sizeof(*item);
+ data += roundup(__le16_to_cpu(item->len), 4);
+ }
+
+ if (num_items != -1 || len != 0)
+ ath10k_warn(ar, "failed to parse diag data event: num_items %d len %d\n",
+ num_items, len);
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_event_diag(struct ath10k *ar,
+ struct sk_buff *skb)
+{
+ const void **tb;
+ const void *data;
+ int ret, len;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ data = tb[WMI_TLV_TAG_ARRAY_BYTE];
+ if (!data) {
+ kfree(tb);
+ return -EPROTO;
+ }
+ len = ath10k_wmi_tlv_len(data);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv diag event len %d\n", len);
+ trace_ath10k_wmi_diag(ar, data, len);
+
+ kfree(tb);
+ return 0;
+}
+
+/***********/
+/* TLV ops */
+/***********/
+
+static void ath10k_wmi_tlv_op_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_cmd_hdr *cmd_hdr;
+ enum wmi_tlv_event_id id;
+
+ cmd_hdr = (struct wmi_cmd_hdr *)skb->data;
+ id = MS(__le32_to_cpu(cmd_hdr->cmd_id), WMI_CMD_HDR_CMD_ID);
+
+ if (skb_pull(skb, sizeof(struct wmi_cmd_hdr)) == NULL)
+ return;
+
+ trace_ath10k_wmi_event(ar, id, skb->data, skb->len);
+
+ switch (id) {
+ case WMI_TLV_MGMT_RX_EVENTID:
+ ath10k_wmi_event_mgmt_rx(ar, skb);
+ /* mgmt_rx() owns the skb now! */
+ return;
+ case WMI_TLV_SCAN_EVENTID:
+ ath10k_wmi_event_scan(ar, skb);
+ break;
+ case WMI_TLV_CHAN_INFO_EVENTID:
+ ath10k_wmi_event_chan_info(ar, skb);
+ break;
+ case WMI_TLV_ECHO_EVENTID:
+ ath10k_wmi_event_echo(ar, skb);
+ break;
+ case WMI_TLV_DEBUG_MESG_EVENTID:
+ ath10k_wmi_event_debug_mesg(ar, skb);
+ break;
+ case WMI_TLV_UPDATE_STATS_EVENTID:
+ ath10k_wmi_event_update_stats(ar, skb);
+ break;
+ case WMI_TLV_VDEV_START_RESP_EVENTID:
+ ath10k_wmi_event_vdev_start_resp(ar, skb);
+ break;
+ case WMI_TLV_VDEV_STOPPED_EVENTID:
+ ath10k_wmi_event_vdev_stopped(ar, skb);
+ break;
+ case WMI_TLV_PEER_STA_KICKOUT_EVENTID:
+ ath10k_wmi_event_peer_sta_kickout(ar, skb);
+ break;
+ case WMI_TLV_HOST_SWBA_EVENTID:
+ ath10k_wmi_event_host_swba(ar, skb);
+ break;
+ case WMI_TLV_TBTTOFFSET_UPDATE_EVENTID:
+ ath10k_wmi_event_tbttoffset_update(ar, skb);
+ break;
+ case WMI_TLV_PHYERR_EVENTID:
+ ath10k_wmi_event_phyerr(ar, skb);
+ break;
+ case WMI_TLV_ROAM_EVENTID:
+ ath10k_wmi_event_roam(ar, skb);
+ break;
+ case WMI_TLV_PROFILE_MATCH:
+ ath10k_wmi_event_profile_match(ar, skb);
+ break;
+ case WMI_TLV_DEBUG_PRINT_EVENTID:
+ ath10k_wmi_event_debug_print(ar, skb);
+ break;
+ case WMI_TLV_PDEV_QVIT_EVENTID:
+ ath10k_wmi_event_pdev_qvit(ar, skb);
+ break;
+ case WMI_TLV_WLAN_PROFILE_DATA_EVENTID:
+ ath10k_wmi_event_wlan_profile_data(ar, skb);
+ break;
+ case WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID:
+ ath10k_wmi_event_rtt_measurement_report(ar, skb);
+ break;
+ case WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID:
+ ath10k_wmi_event_tsf_measurement_report(ar, skb);
+ break;
+ case WMI_TLV_RTT_ERROR_REPORT_EVENTID:
+ ath10k_wmi_event_rtt_error_report(ar, skb);
+ break;
+ case WMI_TLV_WOW_WAKEUP_HOST_EVENTID:
+ ath10k_wmi_event_wow_wakeup_host(ar, skb);
+ break;
+ case WMI_TLV_DCS_INTERFERENCE_EVENTID:
+ ath10k_wmi_event_dcs_interference(ar, skb);
+ break;
+ case WMI_TLV_PDEV_TPC_CONFIG_EVENTID:
+ ath10k_wmi_event_pdev_tpc_config(ar, skb);
+ break;
+ case WMI_TLV_PDEV_FTM_INTG_EVENTID:
+ ath10k_wmi_event_pdev_ftm_intg(ar, skb);
+ break;
+ case WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID:
+ ath10k_wmi_event_gtk_offload_status(ar, skb);
+ break;
+ case WMI_TLV_GTK_REKEY_FAIL_EVENTID:
+ ath10k_wmi_event_gtk_rekey_fail(ar, skb);
+ break;
+ case WMI_TLV_TX_DELBA_COMPLETE_EVENTID:
+ ath10k_wmi_event_delba_complete(ar, skb);
+ break;
+ case WMI_TLV_TX_ADDBA_COMPLETE_EVENTID:
+ ath10k_wmi_event_addba_complete(ar, skb);
+ break;
+ case WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID:
+ ath10k_wmi_event_vdev_install_key_complete(ar, skb);
+ break;
+ case WMI_TLV_SERVICE_READY_EVENTID:
+ ath10k_wmi_event_service_ready(ar, skb);
+ break;
+ case WMI_TLV_READY_EVENTID:
+ ath10k_wmi_event_ready(ar, skb);
+ break;
+ case WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID:
+ ath10k_wmi_tlv_event_bcn_tx_status(ar, skb);
+ break;
+ case WMI_TLV_DIAG_DATA_CONTAINER_EVENTID:
+ ath10k_wmi_tlv_event_diag_data(ar, skb);
+ break;
+ case WMI_TLV_DIAG_EVENTID:
+ ath10k_wmi_tlv_event_diag(ar, skb);
+ break;
+ default:
+ ath10k_warn(ar, "Unknown eventid: %d\n", id);
+ break;
+ }
+
+ dev_kfree_skb(skb);
+}
+
+static int ath10k_wmi_tlv_op_pull_scan_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_scan_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_scan_event *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_SCAN_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->event_type = ev->event_type;
+ arg->reason = ev->reason;
+ arg->channel_freq = ev->channel_freq;
+ arg->scan_req_id = ev->scan_req_id;
+ arg->scan_id = ev->scan_id;
+ arg->vdev_id = ev->vdev_id;
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_mgmt_rx_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_mgmt_rx_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_mgmt_rx_ev *ev;
+ const u8 *frame;
+ u32 msdu_len;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_MGMT_RX_HDR];
+ frame = tb[WMI_TLV_TAG_ARRAY_BYTE];
+
+ if (!ev || !frame) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->channel = ev->channel;
+ arg->buf_len = ev->buf_len;
+ arg->status = ev->status;
+ arg->snr = ev->snr;
+ arg->phy_mode = ev->phy_mode;
+ arg->rate = ev->rate;
+
+ msdu_len = __le32_to_cpu(arg->buf_len);
+
+ if (skb->len < (frame - skb->data) + msdu_len) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ /* shift the sk_buff to point to `frame` */
+ skb_trim(skb, 0);
+ skb_put(skb, frame - skb->data);
+ skb_pull(skb, frame - skb->data);
+ skb_put(skb, msdu_len);
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_ch_info_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_ch_info_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_chan_info_event *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->err_code = ev->err_code;
+ arg->freq = ev->freq;
+ arg->cmd_flags = ev->cmd_flags;
+ arg->noise_floor = ev->noise_floor;
+ arg->rx_clear_count = ev->rx_clear_count;
+ arg->cycle_count = ev->cycle_count;
+
+ kfree(tb);
+ return 0;
+}
+
+static int
+ath10k_wmi_tlv_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_vdev_start_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_vdev_start_response_event *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ skb_pull(skb, sizeof(*ev));
+ arg->vdev_id = ev->vdev_id;
+ arg->req_id = ev->req_id;
+ arg->resp_type = ev->resp_type;
+ arg->status = ev->status;
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_peer_kick_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_peer_kick_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_peer_sta_kickout_event *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->mac_addr = ev->peer_macaddr.addr;
+
+ kfree(tb);
+ return 0;
+}
+
+struct wmi_tlv_swba_parse {
+ const struct wmi_host_swba_event *ev;
+ bool tim_done;
+ bool noa_done;
+ size_t n_tim;
+ size_t n_noa;
+ struct wmi_swba_ev_arg *arg;
+};
+
+static int ath10k_wmi_tlv_swba_tim_parse(struct ath10k *ar, u16 tag, u16 len,
+ const void *ptr, void *data)
+{
+ struct wmi_tlv_swba_parse *swba = data;
+
+ if (tag != WMI_TLV_TAG_STRUCT_TIM_INFO)
+ return -EPROTO;
+
+ if (swba->n_tim >= ARRAY_SIZE(swba->arg->tim_info))
+ return -ENOBUFS;
+
+ swba->arg->tim_info[swba->n_tim++] = ptr;
+ return 0;
+}
+
+static int ath10k_wmi_tlv_swba_noa_parse(struct ath10k *ar, u16 tag, u16 len,
+ const void *ptr, void *data)
+{
+ struct wmi_tlv_swba_parse *swba = data;
+
+ if (tag != WMI_TLV_TAG_STRUCT_P2P_NOA_INFO)
+ return -EPROTO;
+
+ if (swba->n_noa >= ARRAY_SIZE(swba->arg->noa_info))
+ return -ENOBUFS;
+
+ swba->arg->noa_info[swba->n_noa++] = ptr;
+ return 0;
+}
+
+static int ath10k_wmi_tlv_swba_parse(struct ath10k *ar, u16 tag, u16 len,
+ const void *ptr, void *data)
+{
+ struct wmi_tlv_swba_parse *swba = data;
+ int ret;
+
+ switch (tag) {
+ case WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT:
+ swba->ev = ptr;
+ break;
+ case WMI_TLV_TAG_ARRAY_STRUCT:
+ if (!swba->tim_done) {
+ swba->tim_done = true;
+ ret = ath10k_wmi_tlv_iter(ar, ptr, len,
+ ath10k_wmi_tlv_swba_tim_parse,
+ swba);
+ if (ret)
+ return ret;
+ } else if (!swba->noa_done) {
+ swba->noa_done = true;
+ ret = ath10k_wmi_tlv_iter(ar, ptr, len,
+ ath10k_wmi_tlv_swba_noa_parse,
+ swba);
+ if (ret)
+ return ret;
+ }
+ break;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_swba_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_swba_ev_arg *arg)
+{
+ struct wmi_tlv_swba_parse swba = { .arg = arg };
+ u32 map;
+ size_t n_vdevs;
+ int ret;
+
+ ret = ath10k_wmi_tlv_iter(ar, skb->data, skb->len,
+ ath10k_wmi_tlv_swba_parse, &swba);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ if (!swba.ev)
+ return -EPROTO;
+
+ arg->vdev_map = swba.ev->vdev_map;
+
+ for (map = __le32_to_cpu(arg->vdev_map), n_vdevs = 0; map; map >>= 1)
+ if (map & BIT(0))
+ n_vdevs++;
+
+ if (n_vdevs != swba.n_tim ||
+ n_vdevs != swba.n_noa)
+ return -EPROTO;
+
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_phyerr_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_phyerr_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_phyerr_ev *ev;
+ const void *phyerrs;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR];
+ phyerrs = tb[WMI_TLV_TAG_ARRAY_BYTE];
+
+ if (!ev || !phyerrs) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->num_phyerrs = ev->num_phyerrs;
+ arg->tsf_l32 = ev->tsf_l32;
+ arg->tsf_u32 = ev->tsf_u32;
+ arg->buf_len = ev->buf_len;
+ arg->phyerrs = phyerrs;
+
+ kfree(tb);
+ return 0;
+}
+
+#define WMI_TLV_ABI_VER_NS0 0x5F414351
+#define WMI_TLV_ABI_VER_NS1 0x00004C4D
+#define WMI_TLV_ABI_VER_NS2 0x00000000
+#define WMI_TLV_ABI_VER_NS3 0x00000000
+
+#define WMI_TLV_ABI_VER0_MAJOR 1
+#define WMI_TLV_ABI_VER0_MINOR 0
+#define WMI_TLV_ABI_VER0 ((((WMI_TLV_ABI_VER0_MAJOR) << 24) & 0xFF000000) | \
+ (((WMI_TLV_ABI_VER0_MINOR) << 0) & 0x00FFFFFF))
+#define WMI_TLV_ABI_VER1 53
+
+static int
+ath10k_wmi_tlv_parse_mem_reqs(struct ath10k *ar, u16 tag, u16 len,
+ const void *ptr, void *data)
+{
+ struct wmi_svc_rdy_ev_arg *arg = data;
+ int i;
+
+ if (tag != WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ)
+ return -EPROTO;
+
+ for (i = 0; i < ARRAY_SIZE(arg->mem_reqs); i++) {
+ if (!arg->mem_reqs[i]) {
+ arg->mem_reqs[i] = ptr;
+ return 0;
+ }
+ }
+
+ return -ENOMEM;
+}
+
+static int ath10k_wmi_tlv_op_pull_svc_rdy_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg)
+{
+ const void **tb;
+ const struct hal_reg_capabilities *reg;
+ const struct wmi_tlv_svc_rdy_ev *ev;
+ const __le32 *svc_bmap;
+ const struct wlan_host_mem_req *mem_reqs;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT];
+ reg = tb[WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES];
+ svc_bmap = tb[WMI_TLV_TAG_ARRAY_UINT32];
+ mem_reqs = tb[WMI_TLV_TAG_ARRAY_STRUCT];
+
+ if (!ev || !reg || !svc_bmap || !mem_reqs) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ /* This is an internal ABI compatibility check for WMI TLV so check it
+ * here instead of the generic WMI code.
+ */
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv abi 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x, 0x%08x ?= 0x%08x\n",
+ __le32_to_cpu(ev->abi.abi_ver0), WMI_TLV_ABI_VER0,
+ __le32_to_cpu(ev->abi.abi_ver_ns0), WMI_TLV_ABI_VER_NS0,
+ __le32_to_cpu(ev->abi.abi_ver_ns1), WMI_TLV_ABI_VER_NS1,
+ __le32_to_cpu(ev->abi.abi_ver_ns2), WMI_TLV_ABI_VER_NS2,
+ __le32_to_cpu(ev->abi.abi_ver_ns3), WMI_TLV_ABI_VER_NS3);
+
+ if (__le32_to_cpu(ev->abi.abi_ver0) != WMI_TLV_ABI_VER0 ||
+ __le32_to_cpu(ev->abi.abi_ver_ns0) != WMI_TLV_ABI_VER_NS0 ||
+ __le32_to_cpu(ev->abi.abi_ver_ns1) != WMI_TLV_ABI_VER_NS1 ||
+ __le32_to_cpu(ev->abi.abi_ver_ns2) != WMI_TLV_ABI_VER_NS2 ||
+ __le32_to_cpu(ev->abi.abi_ver_ns3) != WMI_TLV_ABI_VER_NS3) {
+ kfree(tb);
+ return -ENOTSUPP;
+ }
+
+ arg->min_tx_power = ev->hw_min_tx_power;
+ arg->max_tx_power = ev->hw_max_tx_power;
+ arg->ht_cap = ev->ht_cap_info;
+ arg->vht_cap = ev->vht_cap_info;
+ arg->sw_ver0 = ev->abi.abi_ver0;
+ arg->sw_ver1 = ev->abi.abi_ver1;
+ arg->fw_build = ev->fw_build_vers;
+ arg->phy_capab = ev->phy_capability;
+ arg->num_rf_chains = ev->num_rf_chains;
+ arg->eeprom_rd = reg->eeprom_rd;
+ arg->num_mem_reqs = ev->num_mem_reqs;
+ arg->service_map = svc_bmap;
+ arg->service_map_len = ath10k_wmi_tlv_len(svc_bmap);
+
+ ret = ath10k_wmi_tlv_iter(ar, mem_reqs, ath10k_wmi_tlv_len(mem_reqs),
+ ath10k_wmi_tlv_parse_mem_reqs, arg);
+ if (ret) {
+ kfree(tb);
+ ath10k_warn(ar, "failed to parse mem_reqs tlv: %d\n", ret);
+ return ret;
+ }
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_rdy_ev(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct wmi_rdy_ev_arg *arg)
+{
+ const void **tb;
+ const struct wmi_tlv_rdy_ev *ev;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_READY_EVENT];
+ if (!ev) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ arg->sw_version = ev->abi.abi_ver0;
+ arg->abi_version = ev->abi.abi_ver1;
+ arg->status = ev->status;
+ arg->mac_addr = ev->mac_addr.addr;
+
+ kfree(tb);
+ return 0;
+}
+
+static int ath10k_wmi_tlv_op_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ const void **tb;
+ const struct wmi_stats_event *ev;
+ const void *data;
+ u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
+ size_t data_len;
+ int ret;
+
+ tb = ath10k_wmi_tlv_parse_alloc(ar, skb->data, skb->len, GFP_ATOMIC);
+ if (IS_ERR(tb)) {
+ ret = PTR_ERR(tb);
+ ath10k_warn(ar, "failed to parse tlv: %d\n", ret);
+ return ret;
+ }
+
+ ev = tb[WMI_TLV_TAG_STRUCT_STATS_EVENT];
+ data = tb[WMI_TLV_TAG_ARRAY_BYTE];
+
+ if (!ev || !data) {
+ kfree(tb);
+ return -EPROTO;
+ }
+
+ data_len = ath10k_wmi_tlv_len(data);
+ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+ WARN_ON(1); /* FIXME: not implemented yet */
+
+ kfree(tb);
+ return 0;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_suspend(struct ath10k *ar, u32 opt)
+{
+ struct wmi_tlv_pdev_suspend *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->opt = __cpu_to_le32(opt);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev suspend\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_resume(struct ath10k *ar)
+{
+ struct wmi_tlv_resume_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->reserved = __cpu_to_le32(0);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev resume\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_set_rd(struct ath10k *ar,
+ u16 rd, u16 rd2g, u16 rd5g,
+ u16 ctl2g, u16 ctl5g,
+ enum wmi_dfs_region dfs_reg)
+{
+ struct wmi_tlv_pdev_set_rd_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->regd = __cpu_to_le32(rd);
+ cmd->regd_2ghz = __cpu_to_le32(rd2g);
+ cmd->regd_5ghz = __cpu_to_le32(rd5g);
+ cmd->conform_limit_2ghz = __cpu_to_le32(rd2g);
+ cmd->conform_limit_5ghz = __cpu_to_le32(rd5g);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set rd\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_set_param(struct ath10k *ar, u32 param_id,
+ u32 param_value)
+{
+ struct wmi_tlv_pdev_set_param_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->param_id = __cpu_to_le32(param_id);
+ cmd->param_value = __cpu_to_le32(param_value);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set param\n");
+ return skb;
+}
+
+static struct sk_buff *ath10k_wmi_tlv_op_gen_init(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+ struct wmi_tlv *tlv;
+ struct wmi_tlv_init_cmd *cmd;
+ struct wmi_tlv_resource_config *cfg;
+ struct wmi_host_mem_chunks *chunks;
+ size_t len, chunks_len;
+ void *ptr;
+
+ chunks_len = ar->wmi.num_mem_chunks * sizeof(struct host_memory_chunk);
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (sizeof(*tlv) + sizeof(*cfg)) +
+ (sizeof(*tlv) + chunks_len);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = skb->data;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_INIT_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG);
+ tlv->len = __cpu_to_le16(sizeof(*cfg));
+ cfg = (void *)tlv->value;
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cfg);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(chunks_len);
+ chunks = (void *)tlv->value;
+
+ ptr += sizeof(*tlv);
+ ptr += chunks_len;
+
+ cmd->abi.abi_ver0 = __cpu_to_le32(WMI_TLV_ABI_VER0);
+ cmd->abi.abi_ver1 = __cpu_to_le32(WMI_TLV_ABI_VER1);
+ cmd->abi.abi_ver_ns0 = __cpu_to_le32(WMI_TLV_ABI_VER_NS0);
+ cmd->abi.abi_ver_ns1 = __cpu_to_le32(WMI_TLV_ABI_VER_NS1);
+ cmd->abi.abi_ver_ns2 = __cpu_to_le32(WMI_TLV_ABI_VER_NS2);
+ cmd->abi.abi_ver_ns3 = __cpu_to_le32(WMI_TLV_ABI_VER_NS3);
+ cmd->num_host_mem_chunks = __cpu_to_le32(ar->wmi.num_mem_chunks);
+
+ cfg->num_vdevs = __cpu_to_le32(TARGET_TLV_NUM_VDEVS);
+ cfg->num_peers = __cpu_to_le32(TARGET_TLV_NUM_PEERS);
+
+ if (test_bit(WMI_SERVICE_RX_FULL_REORDER, ar->wmi.svc_map)) {
+ cfg->num_offload_peers = __cpu_to_le32(3);
+ cfg->num_offload_reorder_bufs = __cpu_to_le32(3);
+ } else {
+ cfg->num_offload_peers = __cpu_to_le32(0);
+ cfg->num_offload_reorder_bufs = __cpu_to_le32(0);
+ }
+
+ cfg->num_peer_keys = __cpu_to_le32(2);
+ cfg->num_tids = __cpu_to_le32(TARGET_TLV_NUM_TIDS);
+ cfg->ast_skid_limit = __cpu_to_le32(0x10);
+ cfg->tx_chain_mask = __cpu_to_le32(0x7);
+ cfg->rx_chain_mask = __cpu_to_le32(0x7);
+ cfg->rx_timeout_pri[0] = __cpu_to_le32(0x64);
+ cfg->rx_timeout_pri[1] = __cpu_to_le32(0x64);
+ cfg->rx_timeout_pri[2] = __cpu_to_le32(0x64);
+ cfg->rx_timeout_pri[3] = __cpu_to_le32(0x28);
+ cfg->rx_decap_mode = __cpu_to_le32(1);
+ cfg->scan_max_pending_reqs = __cpu_to_le32(4);
+ cfg->bmiss_offload_max_vdev = __cpu_to_le32(3);
+ cfg->roam_offload_max_vdev = __cpu_to_le32(3);
+ cfg->roam_offload_max_ap_profiles = __cpu_to_le32(8);
+ cfg->num_mcast_groups = __cpu_to_le32(0);
+ cfg->num_mcast_table_elems = __cpu_to_le32(0);
+ cfg->mcast2ucast_mode = __cpu_to_le32(0);
+ cfg->tx_dbg_log_size = __cpu_to_le32(0x400);
+ cfg->num_wds_entries = __cpu_to_le32(0x20);
+ cfg->dma_burst_size = __cpu_to_le32(0);
+ cfg->mac_aggr_delim = __cpu_to_le32(0);
+ cfg->rx_skip_defrag_timeout_dup_detection_check = __cpu_to_le32(0);
+ cfg->vow_config = __cpu_to_le32(0);
+ cfg->gtk_offload_max_vdev = __cpu_to_le32(2);
+ cfg->num_msdu_desc = __cpu_to_le32(TARGET_TLV_NUM_MSDU_DESC);
+ cfg->max_frag_entries = __cpu_to_le32(2);
+ cfg->num_tdls_vdevs = __cpu_to_le32(1);
+ cfg->num_tdls_conn_table_entries = __cpu_to_le32(0x20);
+ cfg->beacon_tx_offload_max_vdev = __cpu_to_le32(2);
+ cfg->num_multicast_filter_entries = __cpu_to_le32(5);
+ cfg->num_wow_filters = __cpu_to_le32(0x16);
+ cfg->num_keep_alive_pattern = __cpu_to_le32(6);
+ cfg->keep_alive_pattern_size = __cpu_to_le32(0);
+ cfg->max_tdls_concurrent_sleep_sta = __cpu_to_le32(1);
+ cfg->max_tdls_concurrent_buffer_sta = __cpu_to_le32(1);
+
+ ath10k_wmi_put_host_mem_chunks(ar, chunks);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv init\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_start_scan(struct ath10k *ar,
+ const struct wmi_start_scan_arg *arg)
+{
+ struct wmi_tlv_start_scan_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len, chan_len, ssid_len, bssid_len, ie_len;
+ __le32 *chans;
+ struct wmi_ssid *ssids;
+ struct wmi_mac_addr *addrs;
+ void *ptr;
+ int i, ret;
+
+ ret = ath10k_wmi_start_scan_verify(arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ chan_len = arg->n_channels * sizeof(__le32);
+ ssid_len = arg->n_ssids * sizeof(struct wmi_ssid);
+ bssid_len = arg->n_bssids * sizeof(struct wmi_mac_addr);
+ ie_len = roundup(arg->ie_len, 4);
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (arg->n_channels ? sizeof(*tlv) + chan_len : 0) +
+ (arg->n_ssids ? sizeof(*tlv) + ssid_len : 0) +
+ (arg->n_bssids ? sizeof(*tlv) + bssid_len : 0) +
+ (arg->ie_len ? sizeof(*tlv) + ie_len : 0);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_START_SCAN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+ cmd->burst_duration_ms = __cpu_to_le32(0);
+ cmd->num_channels = __cpu_to_le32(arg->n_channels);
+ cmd->num_ssids = __cpu_to_le32(arg->n_ssids);
+ cmd->num_bssids = __cpu_to_le32(arg->n_bssids);
+ cmd->ie_len = __cpu_to_le32(arg->ie_len);
+ cmd->num_probes = __cpu_to_le32(3);
+
+ /* FIXME: There are some scan flag inconsistencies across firmwares,
+ * e.g. WMI-TLV inverts the logic behind the following flag.
+ */
+ cmd->common.scan_ctrl_flags ^= __cpu_to_le32(WMI_SCAN_FILTER_PROBE_REQ);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(chan_len);
+ chans = (void *)tlv->value;
+ for (i = 0; i < arg->n_channels; i++)
+ chans[i] = __cpu_to_le32(arg->channels[i]);
+
+ ptr += sizeof(*tlv);
+ ptr += chan_len;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT);
+ tlv->len = __cpu_to_le16(ssid_len);
+ ssids = (void *)tlv->value;
+ for (i = 0; i < arg->n_ssids; i++) {
+ ssids[i].ssid_len = __cpu_to_le32(arg->ssids[i].len);
+ memcpy(ssids[i].ssid, arg->ssids[i].ssid, arg->ssids[i].len);
+ }
+
+ ptr += sizeof(*tlv);
+ ptr += ssid_len;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_FIXED_STRUCT);
+ tlv->len = __cpu_to_le16(bssid_len);
+ addrs = (void *)tlv->value;
+ for (i = 0; i < arg->n_bssids; i++)
+ ether_addr_copy(addrs[i].addr, arg->bssids[i].bssid);
+
+ ptr += sizeof(*tlv);
+ ptr += bssid_len;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(ie_len);
+ memcpy(tlv->value, arg->ie, arg->ie_len);
+
+ ptr += sizeof(*tlv);
+ ptr += ie_len;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv start scan\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_stop_scan(struct ath10k *ar,
+ const struct wmi_stop_scan_arg *arg)
+{
+ struct wmi_stop_scan_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ u32 scan_id;
+ u32 req_id;
+
+ if (arg->req_id > 0xFFF)
+ return ERR_PTR(-EINVAL);
+ if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
+ return ERR_PTR(-EINVAL);
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ scan_id = arg->u.scan_id;
+ scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX;
+
+ req_id = arg->req_id;
+ req_id |= WMI_HOST_SCAN_REQUESTOR_ID_PREFIX;
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->req_type = __cpu_to_le32(arg->req_type);
+ cmd->vdev_id = __cpu_to_le32(arg->u.vdev_id);
+ cmd->scan_id = __cpu_to_le32(scan_id);
+ cmd->scan_req_id = __cpu_to_le32(req_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv stop scan\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_create(struct ath10k *ar,
+ u32 vdev_id,
+ enum wmi_vdev_type vdev_type,
+ enum wmi_vdev_subtype vdev_subtype,
+ const u8 mac_addr[ETH_ALEN])
+{
+ struct wmi_vdev_create_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->vdev_type = __cpu_to_le32(vdev_type);
+ cmd->vdev_subtype = __cpu_to_le32(vdev_subtype);
+ ether_addr_copy(cmd->vdev_macaddr.addr, mac_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev create\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id)
+{
+ struct wmi_vdev_delete_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev delete\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_start(struct ath10k *ar,
+ const struct wmi_vdev_start_request_arg *arg,
+ bool restart)
+{
+ struct wmi_tlv_vdev_start_cmd *cmd;
+ struct wmi_channel *ch;
+ struct wmi_p2p_noa_descriptor *noa;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+ void *ptr;
+ u32 flags = 0;
+
+ if (WARN_ON(arg->ssid && arg->ssid_len == 0))
+ return ERR_PTR(-EINVAL);
+ if (WARN_ON(arg->hidden_ssid && !arg->ssid))
+ return ERR_PTR(-EINVAL);
+ if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
+ return ERR_PTR(-EINVAL);
+
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (sizeof(*tlv) + sizeof(*ch)) +
+ (sizeof(*tlv) + 0);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ if (arg->hidden_ssid)
+ flags |= WMI_VDEV_START_HIDDEN_SSID;
+ if (arg->pmf_enabled)
+ flags |= WMI_VDEV_START_PMF_ENABLED;
+
+ ptr = (void *)skb->data;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmd->bcn_intval = __cpu_to_le32(arg->bcn_intval);
+ cmd->dtim_period = __cpu_to_le32(arg->dtim_period);
+ cmd->flags = __cpu_to_le32(flags);
+ cmd->bcn_tx_rate = __cpu_to_le32(arg->bcn_tx_rate);
+ cmd->bcn_tx_power = __cpu_to_le32(arg->bcn_tx_power);
+ cmd->disable_hw_ack = __cpu_to_le32(arg->disable_hw_ack);
+
+ if (arg->ssid) {
+ cmd->ssid.ssid_len = __cpu_to_le32(arg->ssid_len);
+ memcpy(cmd->ssid.ssid, arg->ssid, arg->ssid_len);
+ }
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+ tlv->len = __cpu_to_le16(sizeof(*ch));
+ ch = (void *)tlv->value;
+ ath10k_wmi_put_wmi_channel(ch, &arg->channel);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*ch);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = 0;
+ noa = (void *)tlv->value;
+
+ /* Note: This is a nested TLV containing:
+ * [wmi_tlv][wmi_p2p_noa_descriptor][wmi_tlv]..
+ */
+
+ ptr += sizeof(*tlv);
+ ptr += 0;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev start\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
+{
+ struct wmi_vdev_stop_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev stop\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
+ const u8 *bssid)
+
+{
+ struct wmi_vdev_up_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_UP_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->vdev_assoc_id = __cpu_to_le32(aid);
+ ether_addr_copy(cmd->vdev_bssid.addr, bssid);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev up\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id)
+{
+ struct wmi_vdev_down_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev down\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id,
+ u32 param_id, u32 param_value)
+{
+ struct wmi_vdev_set_param_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->param_id = __cpu_to_le32(param_id);
+ cmd->param_value = __cpu_to_le32(param_value);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev set param\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_install_key(struct ath10k *ar,
+ const struct wmi_vdev_install_key_arg *arg)
+{
+ struct wmi_vdev_install_key_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+ void *ptr;
+
+ if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL)
+ return ERR_PTR(-EINVAL);
+ if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
+ return ERR_PTR(-EINVAL);
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + roundup(arg->key_len, sizeof(__le32));
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmd->key_idx = __cpu_to_le32(arg->key_idx);
+ cmd->key_flags = __cpu_to_le32(arg->key_flags);
+ cmd->key_cipher = __cpu_to_le32(arg->key_cipher);
+ cmd->key_len = __cpu_to_le32(arg->key_len);
+ cmd->key_txmic_len = __cpu_to_le32(arg->key_txmic_len);
+ cmd->key_rxmic_len = __cpu_to_le32(arg->key_rxmic_len);
+
+ if (arg->macaddr)
+ ether_addr_copy(cmd->peer_macaddr.addr, arg->macaddr);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(roundup(arg->key_len, sizeof(__le32)));
+ if (arg->key_data)
+ memcpy(tlv->value, arg->key_data, arg->key_len);
+
+ ptr += sizeof(*tlv);
+ ptr += roundup(arg->key_len, sizeof(__le32));
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev install key\n");
+ return skb;
+}
+
+static void *ath10k_wmi_tlv_put_uapsd_ac(struct ath10k *ar, void *ptr,
+ const struct wmi_sta_uapsd_auto_trig_arg *arg)
+{
+ struct wmi_sta_uapsd_auto_trig_param *ac;
+ struct wmi_tlv *tlv;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM);
+ tlv->len = __cpu_to_le16(sizeof(*ac));
+ ac = (void *)tlv->value;
+
+ ac->wmm_ac = __cpu_to_le32(arg->wmm_ac);
+ ac->user_priority = __cpu_to_le32(arg->user_priority);
+ ac->service_interval = __cpu_to_le32(arg->service_interval);
+ ac->suspend_interval = __cpu_to_le32(arg->suspend_interval);
+ ac->delay_interval = __cpu_to_le32(arg->delay_interval);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi tlv vdev sta uapsd auto trigger ac %d prio %d svc int %d susp int %d delay int %d\n",
+ ac->wmm_ac, ac->user_priority, ac->service_interval,
+ ac->suspend_interval, ac->delay_interval);
+
+ return ptr + sizeof(*tlv) + sizeof(*ac);
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_sta_uapsd(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN],
+ const struct wmi_sta_uapsd_auto_trig_arg *args,
+ u32 num_ac)
+{
+ struct wmi_sta_uapsd_auto_trig_cmd_fixed_param *cmd;
+ struct wmi_sta_uapsd_auto_trig_param *ac;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+ size_t ac_tlv_len;
+ void *ptr;
+ int i;
+
+ ac_tlv_len = num_ac * (sizeof(*tlv) + sizeof(*ac));
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + ac_tlv_len;
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->num_ac = __cpu_to_le32(num_ac);
+ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(ac_tlv_len);
+ ac = (void *)tlv->value;
+
+ ptr += sizeof(*tlv);
+ for (i = 0; i < num_ac; i++)
+ ptr = ath10k_wmi_tlv_put_uapsd_ac(ar, ptr, &args[i]);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev sta uapsd auto trigger\n");
+ return skb;
+}
+
+static void *ath10k_wmi_tlv_put_wmm(void *ptr,
+ const struct wmi_wmm_params_arg *arg)
+{
+ struct wmi_wmm_params *wmm;
+ struct wmi_tlv *tlv;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_WMM_PARAMS);
+ tlv->len = __cpu_to_le16(sizeof(*wmm));
+ wmm = (void *)tlv->value;
+ ath10k_wmi_set_wmm_param(wmm, arg);
+
+ return ptr + sizeof(*tlv) + sizeof(*wmm);
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_vdev_wmm_conf(struct ath10k *ar, u32 vdev_id,
+ const struct wmi_wmm_params_all_arg *arg)
+{
+ struct wmi_tlv_vdev_set_wmm_cmd *cmd;
+ struct wmi_wmm_params *wmm;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+ void *ptr;
+
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (4 * (sizeof(*tlv) + sizeof(*wmm)));
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be);
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk);
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi);
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv vdev wmm conf\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_sta_keepalive(struct ath10k *ar,
+ const struct wmi_sta_keepalive_arg *arg)
+{
+ struct wmi_tlv_sta_keepalive_cmd *cmd;
+ struct wmi_sta_keepalive_arp_resp *arp;
+ struct sk_buff *skb;
+ struct wmi_tlv *tlv;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + sizeof(*arp);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmd->enabled = __cpu_to_le32(arg->enabled);
+ cmd->method = __cpu_to_le32(arg->method);
+ cmd->interval = __cpu_to_le32(arg->interval);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE);
+ tlv->len = __cpu_to_le16(sizeof(*arp));
+ arp = (void *)tlv->value;
+
+ arp->src_ip4_addr = arg->src_ip4_addr;
+ arp->dest_ip4_addr = arg->dest_ip4_addr;
+ ether_addr_copy(arp->dest_mac_addr.addr, arg->dest_mac_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv sta keepalive vdev %d enabled %d method %d inverval %d\n",
+ arg->vdev_id, arg->enabled, arg->method, arg->interval);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN])
+{
+ struct wmi_tlv_peer_create_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->peer_type = __cpu_to_le32(WMI_TLV_PEER_TYPE_DEFAULT); /* FIXME */
+ ether_addr_copy(cmd->peer_addr.addr, peer_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer create\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN])
+{
+ struct wmi_peer_delete_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer delete\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
+{
+ struct wmi_peer_flush_tids_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->peer_tid_bitmap = __cpu_to_le32(tid_bitmap);
+ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer flush\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id,
+ const u8 *peer_addr,
+ enum wmi_peer_param param_id,
+ u32 param_value)
+{
+ struct wmi_peer_set_param_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->param_id = __cpu_to_le32(param_id);
+ cmd->param_value = __cpu_to_le32(param_value);
+ ether_addr_copy(cmd->peer_macaddr.addr, peer_addr);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer set param\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ struct wmi_tlv_peer_assoc_cmd *cmd;
+ struct wmi_vht_rate_set *vht_rate;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len, legacy_rate_len, ht_rate_len;
+ void *ptr;
+
+ if (arg->peer_mpdu_density > 16)
+ return ERR_PTR(-EINVAL);
+ if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
+ return ERR_PTR(-EINVAL);
+ if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
+ return ERR_PTR(-EINVAL);
+
+ legacy_rate_len = roundup(arg->peer_legacy_rates.num_rates,
+ sizeof(__le32));
+ ht_rate_len = roundup(arg->peer_ht_rates.num_rates, sizeof(__le32));
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (sizeof(*tlv) + legacy_rate_len) +
+ (sizeof(*tlv) + ht_rate_len) +
+ (sizeof(*tlv) + sizeof(*vht_rate));
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
+ cmd->new_assoc = __cpu_to_le32(arg->peer_reassoc ? 0 : 1);
+ cmd->assoc_id = __cpu_to_le32(arg->peer_aid);
+ cmd->flags = __cpu_to_le32(arg->peer_flags);
+ cmd->caps = __cpu_to_le32(arg->peer_caps);
+ cmd->listen_intval = __cpu_to_le32(arg->peer_listen_intval);
+ cmd->ht_caps = __cpu_to_le32(arg->peer_ht_caps);
+ cmd->max_mpdu = __cpu_to_le32(arg->peer_max_mpdu);
+ cmd->mpdu_density = __cpu_to_le32(arg->peer_mpdu_density);
+ cmd->rate_caps = __cpu_to_le32(arg->peer_rate_caps);
+ cmd->nss = __cpu_to_le32(arg->peer_num_spatial_streams);
+ cmd->vht_caps = __cpu_to_le32(arg->peer_vht_caps);
+ cmd->phy_mode = __cpu_to_le32(arg->peer_phymode);
+ cmd->num_legacy_rates = __cpu_to_le32(arg->peer_legacy_rates.num_rates);
+ cmd->num_ht_rates = __cpu_to_le32(arg->peer_ht_rates.num_rates);
+ ether_addr_copy(cmd->mac_addr.addr, arg->addr);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(legacy_rate_len);
+ memcpy(tlv->value, arg->peer_legacy_rates.rates,
+ arg->peer_legacy_rates.num_rates);
+
+ ptr += sizeof(*tlv);
+ ptr += legacy_rate_len;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(ht_rate_len);
+ memcpy(tlv->value, arg->peer_ht_rates.rates,
+ arg->peer_ht_rates.num_rates);
+
+ ptr += sizeof(*tlv);
+ ptr += ht_rate_len;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_VHT_RATE_SET);
+ tlv->len = __cpu_to_le16(sizeof(*vht_rate));
+ vht_rate = (void *)tlv->value;
+
+ vht_rate->rx_max_rate = __cpu_to_le32(arg->peer_vht_rates.rx_max_rate);
+ vht_rate->rx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.rx_mcs_set);
+ vht_rate->tx_max_rate = __cpu_to_le32(arg->peer_vht_rates.tx_max_rate);
+ vht_rate->tx_mcs_set = __cpu_to_le32(arg->peer_vht_rates.tx_mcs_set);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*vht_rate);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv peer assoc\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_ps_mode psmode)
+{
+ struct wmi_sta_powersave_mode_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->sta_ps_mode = __cpu_to_le32(psmode);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set psmode\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_powersave_param param_id,
+ u32 param_value)
+{
+ struct wmi_sta_powersave_param_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->param_id = __cpu_to_le32(param_id);
+ cmd->param_value = __cpu_to_le32(param_value);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv set sta ps\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ enum wmi_ap_ps_peer_param param_id, u32 value)
+{
+ struct wmi_ap_ps_peer_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ if (!mac)
+ return ERR_PTR(-EINVAL);
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->param_id = __cpu_to_le32(param_id);
+ cmd->param_value = __cpu_to_le32(value);
+ ether_addr_copy(cmd->peer_macaddr.addr, mac);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv ap ps param\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_scan_chan_list(struct ath10k *ar,
+ const struct wmi_scan_chan_list_arg *arg)
+{
+ struct wmi_tlv_scan_chan_list_cmd *cmd;
+ struct wmi_channel *ci;
+ struct wmi_channel_arg *ch;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t chans_len, len;
+ int i;
+ void *ptr, *chans;
+
+ chans_len = arg->n_channels * (sizeof(*tlv) + sizeof(*ci));
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (sizeof(*tlv) + chans_len);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_STRUCT);
+ tlv->len = __cpu_to_le16(chans_len);
+ chans = (void *)tlv->value;
+
+ for (i = 0; i < arg->n_channels; i++) {
+ ch = &arg->channels[i];
+
+ tlv = chans;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_CHANNEL);
+ tlv->len = __cpu_to_le16(sizeof(*ci));
+ ci = (void *)tlv->value;
+
+ ath10k_wmi_put_wmi_channel(ci, ch);
+
+ chans += sizeof(*tlv);
+ chans += sizeof(*ci);
+ }
+
+ ptr += sizeof(*tlv);
+ ptr += chans_len;
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv scan chan list\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id,
+ const void *bcn, size_t bcn_len,
+ u32 bcn_paddr, bool dtim_zero,
+ bool deliver_cab)
+
+{
+ struct wmi_bcn_tx_ref_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ hdr = (struct ieee80211_hdr *)bcn;
+ fc = le16_to_cpu(hdr->frame_control);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->data_len = __cpu_to_le32(bcn_len);
+ cmd->data_ptr = __cpu_to_le32(bcn_paddr);
+ cmd->msdu_id = 0;
+ cmd->frame_control = __cpu_to_le32(fc);
+ cmd->flags = 0;
+
+ if (dtim_zero)
+ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
+
+ if (deliver_cab)
+ cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv beacon dma\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pdev_set_wmm(struct ath10k *ar,
+ const struct wmi_wmm_params_all_arg *arg)
+{
+ struct wmi_tlv_pdev_set_wmm_cmd *cmd;
+ struct wmi_wmm_params *wmm;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len;
+ void *ptr;
+
+ len = (sizeof(*tlv) + sizeof(*cmd)) +
+ (4 * (sizeof(*tlv) + sizeof(*wmm)));
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ /* nothing to set here */
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_be);
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_bk);
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vi);
+ ptr = ath10k_wmi_tlv_put_wmm(ptr, &arg->ac_vo);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pdev set wmm\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_request_stats(struct ath10k *ar,
+ enum wmi_stats_id stats_id)
+{
+ struct wmi_request_stats_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->stats_id = __cpu_to_le32(stats_id);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv request stats\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_force_fw_hang(struct ath10k *ar,
+ enum wmi_force_fw_hang_type type,
+ u32 delay_ms)
+{
+ struct wmi_force_fw_hang_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*tlv) + sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ tlv = (void *)skb->data;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->type = __cpu_to_le32(type);
+ cmd->delay_ms = __cpu_to_le32(delay_ms);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv force fw hang\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable,
+ u32 log_level) {
+ struct wmi_tlv_dbglog_cmd *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ size_t len, bmap_len;
+ u32 value;
+ void *ptr;
+
+ if (module_enable) {
+ value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(
+ module_enable,
+ WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE);
+ } else {
+ value = WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(
+ WMI_TLV_DBGLOG_ALL_MODULES,
+ WMI_TLV_DBGLOG_LOG_LEVEL_WARN);
+ }
+
+ bmap_len = 0;
+ len = sizeof(*tlv) + sizeof(*cmd) + sizeof(*tlv) + bmap_len;
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->param = __cpu_to_le32(WMI_TLV_DBGLOG_PARAM_LOG_LEVEL);
+ cmd->value = __cpu_to_le32(value);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_UINT32);
+ tlv->len = __cpu_to_le16(bmap_len);
+
+ /* nothing to do here */
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(bmap_len);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv dbglog value 0x%08x\n", value);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pktlog_enable(struct ath10k *ar, u32 filter)
+{
+ struct wmi_tlv_pktlog_enable *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->filter = __cpu_to_le32(filter);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog enable filter 0x%08x\n",
+ filter);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_pktlog_disable(struct ath10k *ar)
+{
+ struct wmi_tlv_pktlog_disable *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv pktlog disable\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_bcn_tmpl(struct ath10k *ar, u32 vdev_id,
+ u32 tim_ie_offset, struct sk_buff *bcn,
+ u32 prb_caps, u32 prb_erp, void *prb_ies,
+ size_t prb_ies_len)
+{
+ struct wmi_tlv_bcn_tmpl_cmd *cmd;
+ struct wmi_tlv_bcn_prb_info *info;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ if (WARN_ON(prb_ies_len > 0 && !prb_ies))
+ return ERR_PTR(-EINVAL);
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + sizeof(*info) + prb_ies_len +
+ sizeof(*tlv) + roundup(bcn->len, 4);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->tim_ie_offset = __cpu_to_le32(tim_ie_offset);
+ cmd->buf_len = __cpu_to_le32(bcn->len);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ /* FIXME: prb_ies_len should be probably aligned to 4byte boundary but
+ * then it is then impossible to pass original ie len.
+ * This chunk is not used yet so if setting probe resp template yields
+ * problems with beaconing or crashes firmware look here.
+ */
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO);
+ tlv->len = __cpu_to_le16(sizeof(*info) + prb_ies_len);
+ info = (void *)tlv->value;
+ info->caps = __cpu_to_le32(prb_caps);
+ info->erp = __cpu_to_le32(prb_erp);
+ memcpy(info->ies, prb_ies, prb_ies_len);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*info);
+ ptr += prb_ies_len;
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(roundup(bcn->len, 4));
+ memcpy(tlv->value, bcn->data, bcn->len);
+
+ /* FIXME: Adjust TSF? */
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv bcn tmpl vdev_id %i\n",
+ vdev_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_prb_tmpl(struct ath10k *ar, u32 vdev_id,
+ struct sk_buff *prb)
+{
+ struct wmi_tlv_prb_tmpl_cmd *cmd;
+ struct wmi_tlv_bcn_prb_info *info;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + sizeof(*info) +
+ sizeof(*tlv) + roundup(prb->len, 4);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->buf_len = __cpu_to_le32(prb->len);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_BCN_PRB_INFO);
+ tlv->len = __cpu_to_le16(sizeof(*info));
+ info = (void *)tlv->value;
+ info->caps = 0;
+ info->erp = 0;
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*info);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(roundup(prb->len, 4));
+ memcpy(tlv->value, prb->data, prb->len);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv prb tmpl vdev_id %i\n",
+ vdev_id);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie(struct ath10k *ar, u32 vdev_id,
+ const u8 *p2p_ie)
+{
+ struct wmi_tlv_p2p_go_bcn_ie *cmd;
+ struct wmi_tlv *tlv;
+ struct sk_buff *skb;
+ void *ptr;
+ size_t len;
+
+ len = sizeof(*tlv) + sizeof(*cmd) +
+ sizeof(*tlv) + roundup(p2p_ie[1] + 2, 4);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ptr = (void *)skb->data;
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE);
+ tlv->len = __cpu_to_le16(sizeof(*cmd));
+ cmd = (void *)tlv->value;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->ie_len = __cpu_to_le32(p2p_ie[1] + 2);
+
+ ptr += sizeof(*tlv);
+ ptr += sizeof(*cmd);
+
+ tlv = ptr;
+ tlv->tag = __cpu_to_le16(WMI_TLV_TAG_ARRAY_BYTE);
+ tlv->len = __cpu_to_le16(roundup(p2p_ie[1] + 2, 4));
+ memcpy(tlv->value, p2p_ie, p2p_ie[1] + 2);
+
+ ptr += sizeof(*tlv);
+ ptr += roundup(p2p_ie[1] + 2, 4);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi tlv p2p go bcn ie for vdev %i\n",
+ vdev_id);
+ return skb;
+}
+
+/****************/
+/* TLV mappings */
+/****************/
+
+static struct wmi_cmd_map wmi_tlv_cmd_map = {
+ .init_cmdid = WMI_TLV_INIT_CMDID,
+ .start_scan_cmdid = WMI_TLV_START_SCAN_CMDID,
+ .stop_scan_cmdid = WMI_TLV_STOP_SCAN_CMDID,
+ .scan_chan_list_cmdid = WMI_TLV_SCAN_CHAN_LIST_CMDID,
+ .scan_sch_prio_tbl_cmdid = WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID,
+ .pdev_set_regdomain_cmdid = WMI_TLV_PDEV_SET_REGDOMAIN_CMDID,
+ .pdev_set_channel_cmdid = WMI_TLV_PDEV_SET_CHANNEL_CMDID,
+ .pdev_set_param_cmdid = WMI_TLV_PDEV_SET_PARAM_CMDID,
+ .pdev_pktlog_enable_cmdid = WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID,
+ .pdev_pktlog_disable_cmdid = WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID,
+ .pdev_set_wmm_params_cmdid = WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID,
+ .pdev_set_ht_cap_ie_cmdid = WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID,
+ .pdev_set_vht_cap_ie_cmdid = WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID,
+ .pdev_set_dscp_tid_map_cmdid = WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID,
+ .pdev_set_quiet_mode_cmdid = WMI_TLV_PDEV_SET_QUIET_MODE_CMDID,
+ .pdev_green_ap_ps_enable_cmdid = WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ .pdev_get_tpc_config_cmdid = WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID,
+ .pdev_set_base_macaddr_cmdid = WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID,
+ .vdev_create_cmdid = WMI_TLV_VDEV_CREATE_CMDID,
+ .vdev_delete_cmdid = WMI_TLV_VDEV_DELETE_CMDID,
+ .vdev_start_request_cmdid = WMI_TLV_VDEV_START_REQUEST_CMDID,
+ .vdev_restart_request_cmdid = WMI_TLV_VDEV_RESTART_REQUEST_CMDID,
+ .vdev_up_cmdid = WMI_TLV_VDEV_UP_CMDID,
+ .vdev_stop_cmdid = WMI_TLV_VDEV_STOP_CMDID,
+ .vdev_down_cmdid = WMI_TLV_VDEV_DOWN_CMDID,
+ .vdev_set_param_cmdid = WMI_TLV_VDEV_SET_PARAM_CMDID,
+ .vdev_install_key_cmdid = WMI_TLV_VDEV_INSTALL_KEY_CMDID,
+ .peer_create_cmdid = WMI_TLV_PEER_CREATE_CMDID,
+ .peer_delete_cmdid = WMI_TLV_PEER_DELETE_CMDID,
+ .peer_flush_tids_cmdid = WMI_TLV_PEER_FLUSH_TIDS_CMDID,
+ .peer_set_param_cmdid = WMI_TLV_PEER_SET_PARAM_CMDID,
+ .peer_assoc_cmdid = WMI_TLV_PEER_ASSOC_CMDID,
+ .peer_add_wds_entry_cmdid = WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID,
+ .peer_remove_wds_entry_cmdid = WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID,
+ .peer_mcast_group_cmdid = WMI_TLV_PEER_MCAST_GROUP_CMDID,
+ .bcn_tx_cmdid = WMI_TLV_BCN_TX_CMDID,
+ .pdev_send_bcn_cmdid = WMI_TLV_PDEV_SEND_BCN_CMDID,
+ .bcn_tmpl_cmdid = WMI_TLV_BCN_TMPL_CMDID,
+ .bcn_filter_rx_cmdid = WMI_TLV_BCN_FILTER_RX_CMDID,
+ .prb_req_filter_rx_cmdid = WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
+ .mgmt_tx_cmdid = WMI_TLV_MGMT_TX_CMDID,
+ .prb_tmpl_cmdid = WMI_TLV_PRB_TMPL_CMDID,
+ .addba_clear_resp_cmdid = WMI_TLV_ADDBA_CLEAR_RESP_CMDID,
+ .addba_send_cmdid = WMI_TLV_ADDBA_SEND_CMDID,
+ .addba_status_cmdid = WMI_TLV_ADDBA_STATUS_CMDID,
+ .delba_send_cmdid = WMI_TLV_DELBA_SEND_CMDID,
+ .addba_set_resp_cmdid = WMI_TLV_ADDBA_SET_RESP_CMDID,
+ .send_singleamsdu_cmdid = WMI_TLV_SEND_SINGLEAMSDU_CMDID,
+ .sta_powersave_mode_cmdid = WMI_TLV_STA_POWERSAVE_MODE_CMDID,
+ .sta_powersave_param_cmdid = WMI_TLV_STA_POWERSAVE_PARAM_CMDID,
+ .sta_mimo_ps_mode_cmdid = WMI_TLV_STA_MIMO_PS_MODE_CMDID,
+ .pdev_dfs_enable_cmdid = WMI_TLV_PDEV_DFS_ENABLE_CMDID,
+ .pdev_dfs_disable_cmdid = WMI_TLV_PDEV_DFS_DISABLE_CMDID,
+ .roam_scan_mode = WMI_TLV_ROAM_SCAN_MODE,
+ .roam_scan_rssi_threshold = WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD,
+ .roam_scan_period = WMI_TLV_ROAM_SCAN_PERIOD,
+ .roam_scan_rssi_change_threshold =
+ WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ .roam_ap_profile = WMI_TLV_ROAM_AP_PROFILE,
+ .ofl_scan_add_ap_profile = WMI_TLV_ROAM_AP_PROFILE,
+ .ofl_scan_remove_ap_profile = WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE,
+ .ofl_scan_period = WMI_TLV_OFL_SCAN_PERIOD,
+ .p2p_dev_set_device_info = WMI_TLV_P2P_DEV_SET_DEVICE_INFO,
+ .p2p_dev_set_discoverability = WMI_TLV_P2P_DEV_SET_DISCOVERABILITY,
+ .p2p_go_set_beacon_ie = WMI_TLV_P2P_GO_SET_BEACON_IE,
+ .p2p_go_set_probe_resp_ie = WMI_TLV_P2P_GO_SET_PROBE_RESP_IE,
+ .p2p_set_vendor_ie_data_cmdid = WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID,
+ .ap_ps_peer_param_cmdid = WMI_TLV_AP_PS_PEER_PARAM_CMDID,
+ .ap_ps_peer_uapsd_coex_cmdid = WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID,
+ .peer_rate_retry_sched_cmdid = WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID,
+ .wlan_profile_trigger_cmdid = WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID,
+ .wlan_profile_set_hist_intvl_cmdid =
+ WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ .wlan_profile_get_profile_data_cmdid =
+ WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ .wlan_profile_enable_profile_id_cmdid =
+ WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ .wlan_profile_list_profile_id_cmdid =
+ WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ .pdev_suspend_cmdid = WMI_TLV_PDEV_SUSPEND_CMDID,
+ .pdev_resume_cmdid = WMI_TLV_PDEV_RESUME_CMDID,
+ .add_bcn_filter_cmdid = WMI_TLV_ADD_BCN_FILTER_CMDID,
+ .rmv_bcn_filter_cmdid = WMI_TLV_RMV_BCN_FILTER_CMDID,
+ .wow_add_wake_pattern_cmdid = WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID,
+ .wow_del_wake_pattern_cmdid = WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID,
+ .wow_enable_disable_wake_event_cmdid =
+ WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ .wow_enable_cmdid = WMI_TLV_WOW_ENABLE_CMDID,
+ .wow_hostwakeup_from_sleep_cmdid =
+ WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ .rtt_measreq_cmdid = WMI_TLV_RTT_MEASREQ_CMDID,
+ .rtt_tsf_cmdid = WMI_TLV_RTT_TSF_CMDID,
+ .vdev_spectral_scan_configure_cmdid = WMI_TLV_SPECTRAL_SCAN_CONF_CMDID,
+ .vdev_spectral_scan_enable_cmdid = WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
+ .request_stats_cmdid = WMI_TLV_REQUEST_STATS_CMDID,
+ .set_arp_ns_offload_cmdid = WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID,
+ .network_list_offload_config_cmdid =
+ WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID,
+ .gtk_offload_cmdid = WMI_TLV_GTK_OFFLOAD_CMDID,
+ .csa_offload_enable_cmdid = WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID,
+ .csa_offload_chanswitch_cmdid = WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID,
+ .chatter_set_mode_cmdid = WMI_TLV_CHATTER_SET_MODE_CMDID,
+ .peer_tid_addba_cmdid = WMI_TLV_PEER_TID_ADDBA_CMDID,
+ .peer_tid_delba_cmdid = WMI_TLV_PEER_TID_DELBA_CMDID,
+ .sta_dtim_ps_method_cmdid = WMI_TLV_STA_DTIM_PS_METHOD_CMDID,
+ .sta_uapsd_auto_trig_cmdid = WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID,
+ .sta_keepalive_cmd = WMI_TLV_STA_KEEPALIVE_CMDID,
+ .echo_cmdid = WMI_TLV_ECHO_CMDID,
+ .pdev_utf_cmdid = WMI_TLV_PDEV_UTF_CMDID,
+ .dbglog_cfg_cmdid = WMI_TLV_DBGLOG_CFG_CMDID,
+ .pdev_qvit_cmdid = WMI_TLV_PDEV_QVIT_CMDID,
+ .pdev_ftm_intg_cmdid = WMI_TLV_PDEV_FTM_INTG_CMDID,
+ .vdev_set_keepalive_cmdid = WMI_TLV_VDEV_SET_KEEPALIVE_CMDID,
+ .vdev_get_keepalive_cmdid = WMI_TLV_VDEV_GET_KEEPALIVE_CMDID,
+ .force_fw_hang_cmdid = WMI_TLV_FORCE_FW_HANG_CMDID,
+ .gpio_config_cmdid = WMI_TLV_GPIO_CONFIG_CMDID,
+ .gpio_output_cmdid = WMI_TLV_GPIO_OUTPUT_CMDID,
+ .pdev_get_temperature_cmdid = WMI_TLV_CMD_UNSUPPORTED,
+ .vdev_set_wmm_params_cmdid = WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+};
+
+static struct wmi_pdev_param_map wmi_tlv_pdev_param_map = {
+ .tx_chain_mask = WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK,
+ .rx_chain_mask = WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK,
+ .txpower_limit2g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G,
+ .txpower_limit5g = WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G,
+ .txpower_scale = WMI_TLV_PDEV_PARAM_TXPOWER_SCALE,
+ .beacon_gen_mode = WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE,
+ .beacon_tx_mode = WMI_TLV_PDEV_PARAM_BEACON_TX_MODE,
+ .resmgr_offchan_mode = WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
+ .protection_mode = WMI_TLV_PDEV_PARAM_PROTECTION_MODE,
+ .dynamic_bw = WMI_TLV_PDEV_PARAM_DYNAMIC_BW,
+ .non_agg_sw_retry_th = WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
+ .agg_sw_retry_th = WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH,
+ .sta_kickout_th = WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH,
+ .ac_aggrsize_scaling = WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING,
+ .ltr_enable = WMI_TLV_PDEV_PARAM_LTR_ENABLE,
+ .ltr_ac_latency_be = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE,
+ .ltr_ac_latency_bk = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK,
+ .ltr_ac_latency_vi = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI,
+ .ltr_ac_latency_vo = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO,
+ .ltr_ac_latency_timeout = WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
+ .ltr_sleep_override = WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
+ .ltr_rx_override = WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE,
+ .ltr_tx_activity_timeout = WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
+ .l1ss_enable = WMI_TLV_PDEV_PARAM_L1SS_ENABLE,
+ .dsleep_enable = WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE,
+ .pcielp_txbuf_flush = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
+ .pcielp_txbuf_watermark = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+ .pcielp_txbuf_tmo_en = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+ .pcielp_txbuf_tmo_value = WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
+ .pdev_stats_update_period = WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
+ .vdev_stats_update_period = WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
+ .peer_stats_update_period = WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
+ .bcnflt_stats_update_period =
+ WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
+ .pmf_qos = WMI_TLV_PDEV_PARAM_PMF_QOS,
+ .arp_ac_override = WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE,
+ .dcs = WMI_TLV_PDEV_PARAM_DCS,
+ .ani_enable = WMI_TLV_PDEV_PARAM_ANI_ENABLE,
+ .ani_poll_period = WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD,
+ .ani_listen_period = WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD,
+ .ani_ofdm_level = WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL,
+ .ani_cck_level = WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL,
+ .dyntxchain = WMI_TLV_PDEV_PARAM_DYNTXCHAIN,
+ .proxy_sta = WMI_TLV_PDEV_PARAM_PROXY_STA,
+ .idle_ps_config = WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG,
+ .power_gating_sleep = WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP,
+ .fast_channel_reset = WMI_TLV_PDEV_PARAM_UNSUPPORTED,
+ .burst_dur = WMI_TLV_PDEV_PARAM_BURST_DUR,
+ .burst_enable = WMI_TLV_PDEV_PARAM_BURST_ENABLE,
+ .cal_period = WMI_PDEV_PARAM_UNSUPPORTED,
+};
+
+static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {
+ .rts_threshold = WMI_TLV_VDEV_PARAM_RTS_THRESHOLD,
+ .fragmentation_threshold = WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
+ .beacon_interval = WMI_TLV_VDEV_PARAM_BEACON_INTERVAL,
+ .listen_interval = WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL,
+ .multicast_rate = WMI_TLV_VDEV_PARAM_MULTICAST_RATE,
+ .mgmt_tx_rate = WMI_TLV_VDEV_PARAM_MGMT_TX_RATE,
+ .slot_time = WMI_TLV_VDEV_PARAM_SLOT_TIME,
+ .preamble = WMI_TLV_VDEV_PARAM_PREAMBLE,
+ .swba_time = WMI_TLV_VDEV_PARAM_SWBA_TIME,
+ .wmi_vdev_stats_update_period = WMI_TLV_VDEV_STATS_UPDATE_PERIOD,
+ .wmi_vdev_pwrsave_ageout_time = WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME,
+ .wmi_vdev_host_swba_interval = WMI_TLV_VDEV_HOST_SWBA_INTERVAL,
+ .dtim_period = WMI_TLV_VDEV_PARAM_DTIM_PERIOD,
+ .wmi_vdev_oc_scheduler_air_time_limit =
+ WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
+ .wds = WMI_TLV_VDEV_PARAM_WDS,
+ .atim_window = WMI_TLV_VDEV_PARAM_ATIM_WINDOW,
+ .bmiss_count_max = WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX,
+ .bmiss_first_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT,
+ .bmiss_final_bcnt = WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT,
+ .feature_wmm = WMI_TLV_VDEV_PARAM_FEATURE_WMM,
+ .chwidth = WMI_TLV_VDEV_PARAM_CHWIDTH,
+ .chextoffset = WMI_TLV_VDEV_PARAM_CHEXTOFFSET,
+ .disable_htprotection = WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION,
+ .sta_quickkickout = WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT,
+ .mgmt_rate = WMI_TLV_VDEV_PARAM_MGMT_RATE,
+ .protection_mode = WMI_TLV_VDEV_PARAM_PROTECTION_MODE,
+ .fixed_rate = WMI_TLV_VDEV_PARAM_FIXED_RATE,
+ .sgi = WMI_TLV_VDEV_PARAM_SGI,
+ .ldpc = WMI_TLV_VDEV_PARAM_LDPC,
+ .tx_stbc = WMI_TLV_VDEV_PARAM_TX_STBC,
+ .rx_stbc = WMI_TLV_VDEV_PARAM_RX_STBC,
+ .intra_bss_fwd = WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD,
+ .def_keyid = WMI_TLV_VDEV_PARAM_DEF_KEYID,
+ .nss = WMI_TLV_VDEV_PARAM_NSS,
+ .bcast_data_rate = WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE,
+ .mcast_data_rate = WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE,
+ .mcast_indicate = WMI_TLV_VDEV_PARAM_MCAST_INDICATE,
+ .dhcp_indicate = WMI_TLV_VDEV_PARAM_DHCP_INDICATE,
+ .unknown_dest_indicate = WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
+ .ap_keepalive_min_idle_inactive_time_secs =
+ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
+ .ap_keepalive_max_idle_inactive_time_secs =
+ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
+ .ap_keepalive_max_unresponsive_time_secs =
+ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
+ .ap_enable_nawds = WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS,
+ .mcast2ucast_set = WMI_TLV_VDEV_PARAM_UNSUPPORTED,
+ .enable_rtscts = WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS,
+ .txbf = WMI_TLV_VDEV_PARAM_TXBF,
+ .packet_powersave = WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE,
+ .drop_unencry = WMI_TLV_VDEV_PARAM_DROP_UNENCRY,
+ .tx_encap_type = WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,
+ .ap_detect_out_of_sync_sleeping_sta_time_secs =
+ WMI_TLV_VDEV_PARAM_UNSUPPORTED,
+};
+
+static const struct wmi_ops wmi_tlv_ops = {
+ .rx = ath10k_wmi_tlv_op_rx,
+ .map_svc = wmi_tlv_svc_map,
+
+ .pull_scan = ath10k_wmi_tlv_op_pull_scan_ev,
+ .pull_mgmt_rx = ath10k_wmi_tlv_op_pull_mgmt_rx_ev,
+ .pull_ch_info = ath10k_wmi_tlv_op_pull_ch_info_ev,
+ .pull_vdev_start = ath10k_wmi_tlv_op_pull_vdev_start_ev,
+ .pull_peer_kick = ath10k_wmi_tlv_op_pull_peer_kick_ev,
+ .pull_swba = ath10k_wmi_tlv_op_pull_swba_ev,
+ .pull_phyerr = ath10k_wmi_tlv_op_pull_phyerr_ev,
+ .pull_svc_rdy = ath10k_wmi_tlv_op_pull_svc_rdy_ev,
+ .pull_rdy = ath10k_wmi_tlv_op_pull_rdy_ev,
+ .pull_fw_stats = ath10k_wmi_tlv_op_pull_fw_stats,
+
+ .gen_pdev_suspend = ath10k_wmi_tlv_op_gen_pdev_suspend,
+ .gen_pdev_resume = ath10k_wmi_tlv_op_gen_pdev_resume,
+ .gen_pdev_set_rd = ath10k_wmi_tlv_op_gen_pdev_set_rd,
+ .gen_pdev_set_param = ath10k_wmi_tlv_op_gen_pdev_set_param,
+ .gen_init = ath10k_wmi_tlv_op_gen_init,
+ .gen_start_scan = ath10k_wmi_tlv_op_gen_start_scan,
+ .gen_stop_scan = ath10k_wmi_tlv_op_gen_stop_scan,
+ .gen_vdev_create = ath10k_wmi_tlv_op_gen_vdev_create,
+ .gen_vdev_delete = ath10k_wmi_tlv_op_gen_vdev_delete,
+ .gen_vdev_start = ath10k_wmi_tlv_op_gen_vdev_start,
+ .gen_vdev_stop = ath10k_wmi_tlv_op_gen_vdev_stop,
+ .gen_vdev_up = ath10k_wmi_tlv_op_gen_vdev_up,
+ .gen_vdev_down = ath10k_wmi_tlv_op_gen_vdev_down,
+ .gen_vdev_set_param = ath10k_wmi_tlv_op_gen_vdev_set_param,
+ .gen_vdev_install_key = ath10k_wmi_tlv_op_gen_vdev_install_key,
+ .gen_vdev_wmm_conf = ath10k_wmi_tlv_op_gen_vdev_wmm_conf,
+ .gen_peer_create = ath10k_wmi_tlv_op_gen_peer_create,
+ .gen_peer_delete = ath10k_wmi_tlv_op_gen_peer_delete,
+ .gen_peer_flush = ath10k_wmi_tlv_op_gen_peer_flush,
+ .gen_peer_set_param = ath10k_wmi_tlv_op_gen_peer_set_param,
+ .gen_peer_assoc = ath10k_wmi_tlv_op_gen_peer_assoc,
+ .gen_set_psmode = ath10k_wmi_tlv_op_gen_set_psmode,
+ .gen_set_sta_ps = ath10k_wmi_tlv_op_gen_set_sta_ps,
+ .gen_set_ap_ps = ath10k_wmi_tlv_op_gen_set_ap_ps,
+ .gen_scan_chan_list = ath10k_wmi_tlv_op_gen_scan_chan_list,
+ .gen_beacon_dma = ath10k_wmi_tlv_op_gen_beacon_dma,
+ .gen_pdev_set_wmm = ath10k_wmi_tlv_op_gen_pdev_set_wmm,
+ .gen_request_stats = ath10k_wmi_tlv_op_gen_request_stats,
+ .gen_force_fw_hang = ath10k_wmi_tlv_op_gen_force_fw_hang,
+ /* .gen_mgmt_tx = not implemented; HTT is used */
+ .gen_dbglog_cfg = ath10k_wmi_tlv_op_gen_dbglog_cfg,
+ .gen_pktlog_enable = ath10k_wmi_tlv_op_gen_pktlog_enable,
+ .gen_pktlog_disable = ath10k_wmi_tlv_op_gen_pktlog_disable,
+ /* .gen_pdev_set_quiet_mode not implemented */
+ /* .gen_pdev_get_temperature not implemented */
+ /* .gen_addba_clear_resp not implemented */
+ /* .gen_addba_send not implemented */
+ /* .gen_addba_set_resp not implemented */
+ /* .gen_delba_send not implemented */
+ .gen_bcn_tmpl = ath10k_wmi_tlv_op_gen_bcn_tmpl,
+ .gen_prb_tmpl = ath10k_wmi_tlv_op_gen_prb_tmpl,
+ .gen_p2p_go_bcn_ie = ath10k_wmi_tlv_op_gen_p2p_go_bcn_ie,
+ .gen_vdev_sta_uapsd = ath10k_wmi_tlv_op_gen_vdev_sta_uapsd,
+ .gen_sta_keepalive = ath10k_wmi_tlv_op_gen_sta_keepalive,
+};
+
+/************/
+/* TLV init */
+/************/
+
+void ath10k_wmi_tlv_attach(struct ath10k *ar)
+{
+ ar->wmi.cmd = &wmi_tlv_cmd_map;
+ ar->wmi.vdev_param = &wmi_tlv_vdev_param_map;
+ ar->wmi.pdev_param = &wmi_tlv_pdev_param_map;
+ ar->wmi.ops = &wmi_tlv_ops;
+}
diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.h b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
new file mode 100644
index 000000000000..de68fe76eae6
--- /dev/null
+++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.h
@@ -0,0 +1,1444 @@
+/*
+ * Copyright (c) 2005-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2014 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef _WMI_TLV_H
+#define _WMI_TLV_H
+
+#define WMI_TLV_CMD(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_TLV_EV(grp_id) (((grp_id) << 12) | 0x1)
+#define WMI_TLV_CMD_UNSUPPORTED 0
+#define WMI_TLV_PDEV_PARAM_UNSUPPORTED 0
+#define WMI_TLV_VDEV_PARAM_UNSUPPORTED 0
+
+enum wmi_tlv_grp_id {
+ WMI_TLV_GRP_START = 0x3,
+ WMI_TLV_GRP_SCAN = WMI_TLV_GRP_START,
+ WMI_TLV_GRP_PDEV,
+ WMI_TLV_GRP_VDEV,
+ WMI_TLV_GRP_PEER,
+ WMI_TLV_GRP_MGMT,
+ WMI_TLV_GRP_BA_NEG,
+ WMI_TLV_GRP_STA_PS,
+ WMI_TLV_GRP_DFS,
+ WMI_TLV_GRP_ROAM,
+ WMI_TLV_GRP_OFL_SCAN,
+ WMI_TLV_GRP_P2P,
+ WMI_TLV_GRP_AP_PS,
+ WMI_TLV_GRP_RATECTL,
+ WMI_TLV_GRP_PROFILE,
+ WMI_TLV_GRP_SUSPEND,
+ WMI_TLV_GRP_BCN_FILTER,
+ WMI_TLV_GRP_WOW,
+ WMI_TLV_GRP_RTT,
+ WMI_TLV_GRP_SPECTRAL,
+ WMI_TLV_GRP_STATS,
+ WMI_TLV_GRP_ARP_NS_OFL,
+ WMI_TLV_GRP_NLO_OFL,
+ WMI_TLV_GRP_GTK_OFL,
+ WMI_TLV_GRP_CSA_OFL,
+ WMI_TLV_GRP_CHATTER,
+ WMI_TLV_GRP_TID_ADDBA,
+ WMI_TLV_GRP_MISC,
+ WMI_TLV_GRP_GPIO,
+ WMI_TLV_GRP_FWTEST,
+ WMI_TLV_GRP_TDLS,
+ WMI_TLV_GRP_RESMGR,
+ WMI_TLV_GRP_STA_SMPS,
+ WMI_TLV_GRP_WLAN_HB,
+ WMI_TLV_GRP_RMC,
+ WMI_TLV_GRP_MHF_OFL,
+ WMI_TLV_GRP_LOCATION_SCAN,
+ WMI_TLV_GRP_OEM,
+ WMI_TLV_GRP_NAN,
+ WMI_TLV_GRP_COEX,
+ WMI_TLV_GRP_OBSS_OFL,
+ WMI_TLV_GRP_LPI,
+ WMI_TLV_GRP_EXTSCAN,
+ WMI_TLV_GRP_DHCP_OFL,
+ WMI_TLV_GRP_IPA,
+ WMI_TLV_GRP_MDNS_OFL,
+ WMI_TLV_GRP_SAP_OFL,
+};
+
+enum wmi_tlv_cmd_id {
+ WMI_TLV_INIT_CMDID = 0x1,
+ WMI_TLV_START_SCAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SCAN),
+ WMI_TLV_STOP_SCAN_CMDID,
+ WMI_TLV_SCAN_CHAN_LIST_CMDID,
+ WMI_TLV_SCAN_SCH_PRIO_TBL_CMDID,
+ WMI_TLV_SCAN_UPDATE_REQUEST_CMDID,
+ WMI_TLV_SCAN_PROB_REQ_OUI_CMDID,
+ WMI_TLV_PDEV_SET_REGDOMAIN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PDEV),
+ WMI_TLV_PDEV_SET_CHANNEL_CMDID,
+ WMI_TLV_PDEV_SET_PARAM_CMDID,
+ WMI_TLV_PDEV_PKTLOG_ENABLE_CMDID,
+ WMI_TLV_PDEV_PKTLOG_DISABLE_CMDID,
+ WMI_TLV_PDEV_SET_WMM_PARAMS_CMDID,
+ WMI_TLV_PDEV_SET_HT_CAP_IE_CMDID,
+ WMI_TLV_PDEV_SET_VHT_CAP_IE_CMDID,
+ WMI_TLV_PDEV_SET_DSCP_TID_MAP_CMDID,
+ WMI_TLV_PDEV_SET_QUIET_MODE_CMDID,
+ WMI_TLV_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ WMI_TLV_PDEV_GET_TPC_CONFIG_CMDID,
+ WMI_TLV_PDEV_SET_BASE_MACADDR_CMDID,
+ WMI_TLV_PDEV_DUMP_CMDID,
+ WMI_TLV_PDEV_SET_LED_CONFIG_CMDID,
+ WMI_TLV_PDEV_GET_TEMPERATURE_CMDID,
+ WMI_TLV_PDEV_SET_LED_FLASHING_CMDID,
+ WMI_TLV_VDEV_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_VDEV),
+ WMI_TLV_VDEV_DELETE_CMDID,
+ WMI_TLV_VDEV_START_REQUEST_CMDID,
+ WMI_TLV_VDEV_RESTART_REQUEST_CMDID,
+ WMI_TLV_VDEV_UP_CMDID,
+ WMI_TLV_VDEV_STOP_CMDID,
+ WMI_TLV_VDEV_DOWN_CMDID,
+ WMI_TLV_VDEV_SET_PARAM_CMDID,
+ WMI_TLV_VDEV_INSTALL_KEY_CMDID,
+ WMI_TLV_VDEV_WNM_SLEEPMODE_CMDID,
+ WMI_TLV_VDEV_WMM_ADDTS_CMDID,
+ WMI_TLV_VDEV_WMM_DELTS_CMDID,
+ WMI_TLV_VDEV_SET_WMM_PARAMS_CMDID,
+ WMI_TLV_VDEV_SET_GTX_PARAMS_CMDID,
+ WMI_TLV_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMDID,
+ WMI_TLV_VDEV_PLMREQ_START_CMDID,
+ WMI_TLV_VDEV_PLMREQ_STOP_CMDID,
+ WMI_TLV_PEER_CREATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PEER),
+ WMI_TLV_PEER_DELETE_CMDID,
+ WMI_TLV_PEER_FLUSH_TIDS_CMDID,
+ WMI_TLV_PEER_SET_PARAM_CMDID,
+ WMI_TLV_PEER_ASSOC_CMDID,
+ WMI_TLV_PEER_ADD_WDS_ENTRY_CMDID,
+ WMI_TLV_PEER_REMOVE_WDS_ENTRY_CMDID,
+ WMI_TLV_PEER_MCAST_GROUP_CMDID,
+ WMI_TLV_PEER_INFO_REQ_CMDID,
+ WMI_TLV_PEER_GET_ESTIMATED_LINKSPEED_CMDID,
+ WMI_TLV_BCN_TX_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MGMT),
+ WMI_TLV_PDEV_SEND_BCN_CMDID,
+ WMI_TLV_BCN_TMPL_CMDID,
+ WMI_TLV_BCN_FILTER_RX_CMDID,
+ WMI_TLV_PRB_REQ_FILTER_RX_CMDID,
+ WMI_TLV_MGMT_TX_CMDID,
+ WMI_TLV_PRB_TMPL_CMDID,
+ WMI_TLV_ADDBA_CLEAR_RESP_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BA_NEG),
+ WMI_TLV_ADDBA_SEND_CMDID,
+ WMI_TLV_ADDBA_STATUS_CMDID,
+ WMI_TLV_DELBA_SEND_CMDID,
+ WMI_TLV_ADDBA_SET_RESP_CMDID,
+ WMI_TLV_SEND_SINGLEAMSDU_CMDID,
+ WMI_TLV_STA_POWERSAVE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_PS),
+ WMI_TLV_STA_POWERSAVE_PARAM_CMDID,
+ WMI_TLV_STA_MIMO_PS_MODE_CMDID,
+ WMI_TLV_PDEV_DFS_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_DFS),
+ WMI_TLV_PDEV_DFS_DISABLE_CMDID,
+ WMI_TLV_DFS_PHYERR_FILTER_ENA_CMDID,
+ WMI_TLV_DFS_PHYERR_FILTER_DIS_CMDID,
+ WMI_TLV_ROAM_SCAN_MODE = WMI_TLV_CMD(WMI_TLV_GRP_ROAM),
+ WMI_TLV_ROAM_SCAN_RSSI_THRESHOLD,
+ WMI_TLV_ROAM_SCAN_PERIOD,
+ WMI_TLV_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ WMI_TLV_ROAM_AP_PROFILE,
+ WMI_TLV_ROAM_CHAN_LIST,
+ WMI_TLV_ROAM_SCAN_CMD,
+ WMI_TLV_ROAM_SYNCH_COMPLETE,
+ WMI_TLV_ROAM_SET_RIC_REQUEST_CMDID,
+ WMI_TLV_ROAM_INVOKE_CMDID,
+ WMI_TLV_OFL_SCAN_ADD_AP_PROFILE = WMI_TLV_CMD(WMI_TLV_GRP_OFL_SCAN),
+ WMI_TLV_OFL_SCAN_REMOVE_AP_PROFILE,
+ WMI_TLV_OFL_SCAN_PERIOD,
+ WMI_TLV_P2P_DEV_SET_DEVICE_INFO = WMI_TLV_CMD(WMI_TLV_GRP_P2P),
+ WMI_TLV_P2P_DEV_SET_DISCOVERABILITY,
+ WMI_TLV_P2P_GO_SET_BEACON_IE,
+ WMI_TLV_P2P_GO_SET_PROBE_RESP_IE,
+ WMI_TLV_P2P_SET_VENDOR_IE_DATA_CMDID,
+ WMI_TLV_P2P_DISC_OFFLOAD_CONFIG_CMDID,
+ WMI_TLV_P2P_DISC_OFFLOAD_APPIE_CMDID,
+ WMI_TLV_P2P_DISC_OFFLOAD_PATTERN_CMDID,
+ WMI_TLV_P2P_SET_OPPPS_PARAM_CMDID,
+ WMI_TLV_AP_PS_PEER_PARAM_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_AP_PS),
+ WMI_TLV_AP_PS_PEER_UAPSD_COEX_CMDID,
+ WMI_TLV_PEER_RATE_RETRY_SCHED_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RATECTL),
+ WMI_TLV_WLAN_PROFILE_TRIGGER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_PROFILE),
+ WMI_TLV_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ WMI_TLV_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ WMI_TLV_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ WMI_TLV_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ WMI_TLV_PDEV_SUSPEND_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SUSPEND),
+ WMI_TLV_PDEV_RESUME_CMDID,
+ WMI_TLV_ADD_BCN_FILTER_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_BCN_FILTER),
+ WMI_TLV_RMV_BCN_FILTER_CMDID,
+ WMI_TLV_WOW_ADD_WAKE_PATTERN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WOW),
+ WMI_TLV_WOW_DEL_WAKE_PATTERN_CMDID,
+ WMI_TLV_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ WMI_TLV_WOW_ENABLE_CMDID,
+ WMI_TLV_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ WMI_TLV_WOW_ACER_IOAC_ADD_KEEPALIVE_CMDID,
+ WMI_TLV_WOW_ACER_IOAC_DEL_KEEPALIVE_CMDID,
+ WMI_TLV_WOW_ACER_IOAC_ADD_WAKE_PATTERN_CMDID,
+ WMI_TLV_WOW_ACER_IOAC_DEL_WAKE_PATTERN_CMDID,
+ WMI_TLV_D0_WOW_ENABLE_DISABLE_CMDID,
+ WMI_TLV_EXTWOW_ENABLE_CMDID,
+ WMI_TLV_EXTWOW_SET_APP_TYPE1_PARAMS_CMDID,
+ WMI_TLV_EXTWOW_SET_APP_TYPE2_PARAMS_CMDID,
+ WMI_TLV_RTT_MEASREQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RTT),
+ WMI_TLV_RTT_TSF_CMDID,
+ WMI_TLV_SPECTRAL_SCAN_CONF_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SPECTRAL),
+ WMI_TLV_SPECTRAL_SCAN_ENABLE_CMDID,
+ WMI_TLV_REQUEST_STATS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STATS),
+ WMI_TLV_MCC_SCHED_TRAFFIC_STATS_CMDID,
+ WMI_TLV_REQUEST_STATS_EXT_CMDID,
+ WMI_TLV_REQUEST_LINK_STATS_CMDID,
+ WMI_TLV_START_LINK_STATS_CMDID,
+ WMI_TLV_CLEAR_LINK_STATS_CMDID,
+ WMI_TLV_SET_ARP_NS_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_ARP_NS_OFL),
+ WMI_TLV_ADD_PROACTIVE_ARP_RSP_PATTERN_CMDID,
+ WMI_TLV_DEL_PROACTIVE_ARP_RSP_PATTERN_CMDID,
+ WMI_TLV_NETWORK_LIST_OFFLOAD_CONFIG_CMDID =
+ WMI_TLV_CMD(WMI_TLV_GRP_NLO_OFL),
+ WMI_TLV_APFIND_CMDID,
+ WMI_TLV_GTK_OFFLOAD_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GTK_OFL),
+ WMI_TLV_CSA_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CSA_OFL),
+ WMI_TLV_CSA_OFFLOAD_CHANSWITCH_CMDID,
+ WMI_TLV_CHATTER_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_CHATTER),
+ WMI_TLV_CHATTER_ADD_COALESCING_FILTER_CMDID,
+ WMI_TLV_CHATTER_DELETE_COALESCING_FILTER_CMDID,
+ WMI_TLV_CHATTER_COALESCING_QUERY_CMDID,
+ WMI_TLV_PEER_TID_ADDBA_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TID_ADDBA),
+ WMI_TLV_PEER_TID_DELBA_CMDID,
+ WMI_TLV_STA_DTIM_PS_METHOD_CMDID,
+ WMI_TLV_STA_UAPSD_AUTO_TRIG_CMDID,
+ WMI_TLV_STA_KEEPALIVE_CMDID,
+ WMI_TLV_BA_REQ_SSN_CMDID,
+ WMI_TLV_ECHO_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MISC),
+ WMI_TLV_PDEV_UTF_CMDID,
+ WMI_TLV_DBGLOG_CFG_CMDID,
+ WMI_TLV_PDEV_QVIT_CMDID,
+ WMI_TLV_PDEV_FTM_INTG_CMDID,
+ WMI_TLV_VDEV_SET_KEEPALIVE_CMDID,
+ WMI_TLV_VDEV_GET_KEEPALIVE_CMDID,
+ WMI_TLV_FORCE_FW_HANG_CMDID,
+ WMI_TLV_SET_MCASTBCAST_FILTER_CMDID,
+ WMI_TLV_THERMAL_MGMT_CMDID,
+ WMI_TLV_HOST_AUTO_SHUTDOWN_CFG_CMDID,
+ WMI_TLV_TPC_CHAINMASK_CONFIG_CMDID,
+ WMI_TLV_SET_ANTENNA_DIVERSITY_CMDID,
+ WMI_TLV_GPIO_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_GPIO),
+ WMI_TLV_GPIO_OUTPUT_CMDID,
+ WMI_TLV_TXBF_CMDID,
+ WMI_TLV_FWTEST_VDEV_MCC_SET_TBTT_MODE_CMDID =
+ WMI_TLV_CMD(WMI_TLV_GRP_FWTEST),
+ WMI_TLV_FWTEST_P2P_SET_NOA_PARAM_CMDID,
+ WMI_TLV_UNIT_TEST_CMDID,
+ WMI_TLV_TDLS_SET_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_TDLS),
+ WMI_TLV_TDLS_PEER_UPDATE_CMDID,
+ WMI_TLV_TDLS_SET_OFFCHAN_MODE_CMDID,
+ WMI_TLV_RESMGR_ADAPTIVE_OCS_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RESMGR),
+ WMI_TLV_RESMGR_SET_CHAN_TIME_QUOTA_CMDID,
+ WMI_TLV_RESMGR_SET_CHAN_LATENCY_CMDID,
+ WMI_TLV_STA_SMPS_FORCE_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_STA_SMPS),
+ WMI_TLV_STA_SMPS_PARAM_CMDID,
+ WMI_TLV_HB_SET_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_WLAN_HB),
+ WMI_TLV_HB_SET_TCP_PARAMS_CMDID,
+ WMI_TLV_HB_SET_TCP_PKT_FILTER_CMDID,
+ WMI_TLV_HB_SET_UDP_PARAMS_CMDID,
+ WMI_TLV_HB_SET_UDP_PKT_FILTER_CMDID,
+ WMI_TLV_RMC_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_RMC),
+ WMI_TLV_RMC_SET_ACTION_PERIOD_CMDID,
+ WMI_TLV_RMC_CONFIG_CMDID,
+ WMI_TLV_MHF_OFFLOAD_SET_MODE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MHF_OFL),
+ WMI_TLV_MHF_OFFLOAD_PLUMB_ROUTING_TBL_CMDID,
+ WMI_TLV_BATCH_SCAN_ENABLE_CMDID =
+ WMI_TLV_CMD(WMI_TLV_GRP_LOCATION_SCAN),
+ WMI_TLV_BATCH_SCAN_DISABLE_CMDID,
+ WMI_TLV_BATCH_SCAN_TRIGGER_RESULT_CMDID,
+ WMI_TLV_OEM_REQ_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OEM),
+ WMI_TLV_NAN_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_NAN),
+ WMI_TLV_MODEM_POWER_STATE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_COEX),
+ WMI_TLV_CHAN_AVOID_UPDATE_CMDID,
+ WMI_TLV_OBSS_SCAN_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_OBSS_OFL),
+ WMI_TLV_OBSS_SCAN_DISABLE_CMDID,
+ WMI_TLV_LPI_MGMT_SNOOPING_CONFIG_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_LPI),
+ WMI_TLV_LPI_START_SCAN_CMDID,
+ WMI_TLV_LPI_STOP_SCAN_CMDID,
+ WMI_TLV_EXTSCAN_START_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_EXTSCAN),
+ WMI_TLV_EXTSCAN_STOP_CMDID,
+ WMI_TLV_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMDID,
+ WMI_TLV_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMDID,
+ WMI_TLV_EXTSCAN_GET_CACHED_RESULTS_CMDID,
+ WMI_TLV_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMDID,
+ WMI_TLV_EXTSCAN_SET_CAPABILITIES_CMDID,
+ WMI_TLV_EXTSCAN_GET_CAPABILITIES_CMDID,
+ WMI_TLV_SET_DHCP_SERVER_OFFLOAD_CMDID =
+ WMI_TLV_CMD(WMI_TLV_GRP_DHCP_OFL),
+ WMI_TLV_IPA_OFFLOAD_ENABLE_DISABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_IPA),
+ WMI_TLV_MDNS_OFFLOAD_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_MDNS_OFL),
+ WMI_TLV_MDNS_SET_FQDN_CMDID,
+ WMI_TLV_MDNS_SET_RESPONSE_CMDID,
+ WMI_TLV_MDNS_GET_STATS_CMDID,
+ WMI_TLV_SAP_OFL_ENABLE_CMDID = WMI_TLV_CMD(WMI_TLV_GRP_SAP_OFL),
+};
+
+enum wmi_tlv_event_id {
+ WMI_TLV_SERVICE_READY_EVENTID = 0x1,
+ WMI_TLV_READY_EVENTID,
+ WMI_TLV_SCAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SCAN),
+ WMI_TLV_PDEV_TPC_CONFIG_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PDEV),
+ WMI_TLV_CHAN_INFO_EVENTID,
+ WMI_TLV_PHYERR_EVENTID,
+ WMI_TLV_PDEV_DUMP_EVENTID,
+ WMI_TLV_TX_PAUSE_EVENTID,
+ WMI_TLV_DFS_RADAR_EVENTID,
+ WMI_TLV_PDEV_L1SS_TRACK_EVENTID,
+ WMI_TLV_PDEV_TEMPERATURE_EVENTID,
+ WMI_TLV_VDEV_START_RESP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_VDEV),
+ WMI_TLV_VDEV_STOPPED_EVENTID,
+ WMI_TLV_VDEV_INSTALL_KEY_COMPLETE_EVENTID,
+ WMI_TLV_VDEV_MCC_BCN_INTERVAL_CHANGE_REQ_EVENTID,
+ WMI_TLV_PEER_STA_KICKOUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_PEER),
+ WMI_TLV_PEER_INFO_EVENTID,
+ WMI_TLV_PEER_TX_FAIL_CNT_THR_EVENTID,
+ WMI_TLV_PEER_ESTIMATED_LINKSPEED_EVENTID,
+ WMI_TLV_PEER_STATE_EVENTID,
+ WMI_TLV_MGMT_RX_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MGMT),
+ WMI_TLV_HOST_SWBA_EVENTID,
+ WMI_TLV_TBTTOFFSET_UPDATE_EVENTID,
+ WMI_TLV_OFFLOAD_BCN_TX_STATUS_EVENTID,
+ WMI_TLV_OFFLOAD_PROB_RESP_TX_STATUS_EVENTID,
+ WMI_TLV_TX_DELBA_COMPLETE_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_BA_NEG),
+ WMI_TLV_TX_ADDBA_COMPLETE_EVENTID,
+ WMI_TLV_BA_RSP_SSN_EVENTID,
+ WMI_TLV_AGGR_STATE_TRIG_EVENTID,
+ WMI_TLV_ROAM_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_ROAM),
+ WMI_TLV_PROFILE_MATCH,
+ WMI_TLV_ROAM_SYNCH_EVENTID,
+ WMI_TLV_P2P_DISC_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_P2P),
+ WMI_TLV_P2P_NOA_EVENTID,
+ WMI_TLV_PDEV_RESUME_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SUSPEND),
+ WMI_TLV_WOW_WAKEUP_HOST_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_WOW),
+ WMI_TLV_D0_WOW_DISABLE_ACK_EVENTID,
+ WMI_TLV_RTT_MEASUREMENT_REPORT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_RTT),
+ WMI_TLV_TSF_MEASUREMENT_REPORT_EVENTID,
+ WMI_TLV_RTT_ERROR_REPORT_EVENTID,
+ WMI_TLV_STATS_EXT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_STATS),
+ WMI_TLV_IFACE_LINK_STATS_EVENTID,
+ WMI_TLV_PEER_LINK_STATS_EVENTID,
+ WMI_TLV_RADIO_LINK_STATS_EVENTID,
+ WMI_TLV_NLO_MATCH_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NLO_OFL),
+ WMI_TLV_NLO_SCAN_COMPLETE_EVENTID,
+ WMI_TLV_APFIND_EVENTID,
+ WMI_TLV_GTK_OFFLOAD_STATUS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GTK_OFL),
+ WMI_TLV_GTK_REKEY_FAIL_EVENTID,
+ WMI_TLV_CSA_HANDLING_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CSA_OFL),
+ WMI_TLV_CHATTER_PC_QUERY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_CHATTER),
+ WMI_TLV_ECHO_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MISC),
+ WMI_TLV_PDEV_UTF_EVENTID,
+ WMI_TLV_DEBUG_MESG_EVENTID,
+ WMI_TLV_UPDATE_STATS_EVENTID,
+ WMI_TLV_DEBUG_PRINT_EVENTID,
+ WMI_TLV_DCS_INTERFERENCE_EVENTID,
+ WMI_TLV_PDEV_QVIT_EVENTID,
+ WMI_TLV_WLAN_PROFILE_DATA_EVENTID,
+ WMI_TLV_PDEV_FTM_INTG_EVENTID,
+ WMI_TLV_WLAN_FREQ_AVOID_EVENTID,
+ WMI_TLV_VDEV_GET_KEEPALIVE_EVENTID,
+ WMI_TLV_THERMAL_MGMT_EVENTID,
+ WMI_TLV_DIAG_DATA_CONTAINER_EVENTID,
+ WMI_TLV_HOST_AUTO_SHUTDOWN_EVENTID,
+ WMI_TLV_UPDATE_WHAL_MIB_STATS_EVENTID,
+ WMI_TLV_UPDATE_VDEV_RATE_STATS_EVENTID,
+ WMI_TLV_DIAG_EVENTID,
+ WMI_TLV_GPIO_INPUT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_GPIO),
+ WMI_TLV_UPLOADH_EVENTID,
+ WMI_TLV_CAPTUREH_EVENTID,
+ WMI_TLV_RFKILL_STATE_CHANGE_EVENTID,
+ WMI_TLV_TDLS_PEER_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_TDLS),
+ WMI_TLV_BATCH_SCAN_ENABLED_EVENTID =
+ WMI_TLV_EV(WMI_TLV_GRP_LOCATION_SCAN),
+ WMI_TLV_BATCH_SCAN_RESULT_EVENTID,
+ WMI_TLV_OEM_CAPABILITY_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_OEM),
+ WMI_TLV_OEM_MEASUREMENT_REPORT_EVENTID,
+ WMI_TLV_OEM_ERROR_REPORT_EVENTID,
+ WMI_TLV_NAN_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_NAN),
+ WMI_TLV_LPI_RESULT_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_LPI),
+ WMI_TLV_LPI_STATUS_EVENTID,
+ WMI_TLV_LPI_HANDOFF_EVENTID,
+ WMI_TLV_EXTSCAN_START_STOP_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_EXTSCAN),
+ WMI_TLV_EXTSCAN_OPERATION_EVENTID,
+ WMI_TLV_EXTSCAN_TABLE_USAGE_EVENTID,
+ WMI_TLV_EXTSCAN_CACHED_RESULTS_EVENTID,
+ WMI_TLV_EXTSCAN_WLAN_CHANGE_RESULTS_EVENTID,
+ WMI_TLV_EXTSCAN_HOTLIST_MATCH_EVENTID,
+ WMI_TLV_EXTSCAN_CAPABILITIES_EVENTID,
+ WMI_TLV_MDNS_STATS_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_MDNS_OFL),
+ WMI_TLV_SAP_OFL_ADD_STA_EVENTID = WMI_TLV_EV(WMI_TLV_GRP_SAP_OFL),
+ WMI_TLV_SAP_OFL_DEL_STA_EVENTID,
+};
+
+enum wmi_tlv_pdev_param {
+ WMI_TLV_PDEV_PARAM_TX_CHAIN_MASK = 0x1,
+ WMI_TLV_PDEV_PARAM_RX_CHAIN_MASK,
+ WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT2G,
+ WMI_TLV_PDEV_PARAM_TXPOWER_LIMIT5G,
+ WMI_TLV_PDEV_PARAM_TXPOWER_SCALE,
+ WMI_TLV_PDEV_PARAM_BEACON_GEN_MODE,
+ WMI_TLV_PDEV_PARAM_BEACON_TX_MODE,
+ WMI_TLV_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
+ WMI_TLV_PDEV_PARAM_PROTECTION_MODE,
+ WMI_TLV_PDEV_PARAM_DYNAMIC_BW,
+ WMI_TLV_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
+ WMI_TLV_PDEV_PARAM_AGG_SW_RETRY_TH,
+ WMI_TLV_PDEV_PARAM_STA_KICKOUT_TH,
+ WMI_TLV_PDEV_PARAM_AC_AGGRSIZE_SCALING,
+ WMI_TLV_PDEV_PARAM_LTR_ENABLE,
+ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BE,
+ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_BK,
+ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VI,
+ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_VO,
+ WMI_TLV_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
+ WMI_TLV_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
+ WMI_TLV_PDEV_PARAM_LTR_RX_OVERRIDE,
+ WMI_TLV_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
+ WMI_TLV_PDEV_PARAM_L1SS_ENABLE,
+ WMI_TLV_PDEV_PARAM_DSLEEP_ENABLE,
+ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_FLUSH,
+ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_WATERMARK,
+ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_EN,
+ WMI_TLV_PDEV_PARAM_PCIELP_TXBUF_TMO_VALUE,
+ WMI_TLV_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
+ WMI_TLV_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
+ WMI_TLV_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
+ WMI_TLV_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
+ WMI_TLV_PDEV_PARAM_PMF_QOS,
+ WMI_TLV_PDEV_PARAM_ARP_AC_OVERRIDE,
+ WMI_TLV_PDEV_PARAM_DCS,
+ WMI_TLV_PDEV_PARAM_ANI_ENABLE,
+ WMI_TLV_PDEV_PARAM_ANI_POLL_PERIOD,
+ WMI_TLV_PDEV_PARAM_ANI_LISTEN_PERIOD,
+ WMI_TLV_PDEV_PARAM_ANI_OFDM_LEVEL,
+ WMI_TLV_PDEV_PARAM_ANI_CCK_LEVEL,
+ WMI_TLV_PDEV_PARAM_DYNTXCHAIN,
+ WMI_TLV_PDEV_PARAM_PROXY_STA,
+ WMI_TLV_PDEV_PARAM_IDLE_PS_CONFIG,
+ WMI_TLV_PDEV_PARAM_POWER_GATING_SLEEP,
+ WMI_TLV_PDEV_PARAM_RFKILL_ENABLE,
+ WMI_TLV_PDEV_PARAM_BURST_DUR,
+ WMI_TLV_PDEV_PARAM_BURST_ENABLE,
+ WMI_TLV_PDEV_PARAM_HW_RFKILL_CONFIG,
+ WMI_TLV_PDEV_PARAM_LOW_POWER_RF_ENABLE,
+ WMI_TLV_PDEV_PARAM_L1SS_TRACK,
+ WMI_TLV_PDEV_PARAM_HYST_EN,
+ WMI_TLV_PDEV_PARAM_POWER_COLLAPSE_ENABLE,
+ WMI_TLV_PDEV_PARAM_LED_SYS_STATE,
+ WMI_TLV_PDEV_PARAM_LED_ENABLE,
+ WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_LATENCY,
+ WMI_TLV_PDEV_PARAM_AUDIO_OVER_WLAN_ENABLE,
+ WMI_TLV_PDEV_PARAM_WHAL_MIB_STATS_UPDATE_ENABLE,
+ WMI_TLV_PDEV_PARAM_VDEV_RATE_STATS_UPDATE_PERIOD,
+ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_NONE,
+ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_SAR,
+ WMI_TLV_PDEV_PARAM_TXPOWER_REASON_MAX,
+};
+
+enum wmi_tlv_vdev_param {
+ WMI_TLV_VDEV_PARAM_RTS_THRESHOLD = 0x1,
+ WMI_TLV_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
+ WMI_TLV_VDEV_PARAM_BEACON_INTERVAL,
+ WMI_TLV_VDEV_PARAM_LISTEN_INTERVAL,
+ WMI_TLV_VDEV_PARAM_MULTICAST_RATE,
+ WMI_TLV_VDEV_PARAM_MGMT_TX_RATE,
+ WMI_TLV_VDEV_PARAM_SLOT_TIME,
+ WMI_TLV_VDEV_PARAM_PREAMBLE,
+ WMI_TLV_VDEV_PARAM_SWBA_TIME,
+ WMI_TLV_VDEV_STATS_UPDATE_PERIOD,
+ WMI_TLV_VDEV_PWRSAVE_AGEOUT_TIME,
+ WMI_TLV_VDEV_HOST_SWBA_INTERVAL,
+ WMI_TLV_VDEV_PARAM_DTIM_PERIOD,
+ WMI_TLV_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
+ WMI_TLV_VDEV_PARAM_WDS,
+ WMI_TLV_VDEV_PARAM_ATIM_WINDOW,
+ WMI_TLV_VDEV_PARAM_BMISS_COUNT_MAX,
+ WMI_TLV_VDEV_PARAM_BMISS_FIRST_BCNT,
+ WMI_TLV_VDEV_PARAM_BMISS_FINAL_BCNT,
+ WMI_TLV_VDEV_PARAM_FEATURE_WMM,
+ WMI_TLV_VDEV_PARAM_CHWIDTH,
+ WMI_TLV_VDEV_PARAM_CHEXTOFFSET,
+ WMI_TLV_VDEV_PARAM_DISABLE_HTPROTECTION,
+ WMI_TLV_VDEV_PARAM_STA_QUICKKICKOUT,
+ WMI_TLV_VDEV_PARAM_MGMT_RATE,
+ WMI_TLV_VDEV_PARAM_PROTECTION_MODE,
+ WMI_TLV_VDEV_PARAM_FIXED_RATE,
+ WMI_TLV_VDEV_PARAM_SGI,
+ WMI_TLV_VDEV_PARAM_LDPC,
+ WMI_TLV_VDEV_PARAM_TX_STBC,
+ WMI_TLV_VDEV_PARAM_RX_STBC,
+ WMI_TLV_VDEV_PARAM_INTRA_BSS_FWD,
+ WMI_TLV_VDEV_PARAM_DEF_KEYID,
+ WMI_TLV_VDEV_PARAM_NSS,
+ WMI_TLV_VDEV_PARAM_BCAST_DATA_RATE,
+ WMI_TLV_VDEV_PARAM_MCAST_DATA_RATE,
+ WMI_TLV_VDEV_PARAM_MCAST_INDICATE,
+ WMI_TLV_VDEV_PARAM_DHCP_INDICATE,
+ WMI_TLV_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
+ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
+ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
+ WMI_TLV_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
+ WMI_TLV_VDEV_PARAM_AP_ENABLE_NAWDS,
+ WMI_TLV_VDEV_PARAM_ENABLE_RTSCTS,
+ WMI_TLV_VDEV_PARAM_TXBF,
+ WMI_TLV_VDEV_PARAM_PACKET_POWERSAVE,
+ WMI_TLV_VDEV_PARAM_DROP_UNENCRY,
+ WMI_TLV_VDEV_PARAM_TX_ENCAP_TYPE,
+ WMI_TLV_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_ENABLE,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_TGT_BMISS_NUM,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_BMISS_SAMPLE_CYCLE,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_SLOP_STEP,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_INIT_SLOP,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_ADJUST_PAUSE,
+ WMI_TLV_VDEV_PARAM_TX_PWRLIMIT,
+ WMI_TLV_VDEV_PARAM_SNR_NUM_FOR_CAL,
+ WMI_TLV_VDEV_PARAM_ROAM_FW_OFFLOAD,
+ WMI_TLV_VDEV_PARAM_ENABLE_RMC,
+ WMI_TLV_VDEV_PARAM_IBSS_MAX_BCN_LOST_MS,
+ WMI_TLV_VDEV_PARAM_MAX_RATE,
+ WMI_TLV_VDEV_PARAM_EARLY_RX_DRIFT_SAMPLE,
+ WMI_TLV_VDEV_PARAM_SET_IBSS_TX_FAIL_CNT_THR,
+ WMI_TLV_VDEV_PARAM_EBT_RESYNC_TIMEOUT,
+ WMI_TLV_VDEV_PARAM_AGGR_TRIG_EVENT_ENABLE,
+ WMI_TLV_VDEV_PARAM_IS_IBSS_POWER_SAVE_ALLOWED,
+ WMI_TLV_VDEV_PARAM_IS_POWER_COLLAPSE_ALLOWED,
+ WMI_TLV_VDEV_PARAM_IS_AWAKE_ON_TXRX_ENABLED,
+ WMI_TLV_VDEV_PARAM_INACTIVITY_CNT,
+ WMI_TLV_VDEV_PARAM_TXSP_END_INACTIVITY_TIME_MS,
+ WMI_TLV_VDEV_PARAM_DTIM_POLICY,
+ WMI_TLV_VDEV_PARAM_IBSS_PS_WARMUP_TIME_SECS,
+ WMI_TLV_VDEV_PARAM_IBSS_PS_1RX_CHAIN_IN_ATIM_WINDOW_ENABLE,
+};
+
+enum wmi_tlv_tag {
+ WMI_TLV_TAG_LAST_RESERVED = 15,
+
+ WMI_TLV_TAG_FIRST_ARRAY_ENUM,
+ WMI_TLV_TAG_ARRAY_UINT32 = WMI_TLV_TAG_FIRST_ARRAY_ENUM,
+ WMI_TLV_TAG_ARRAY_BYTE,
+ WMI_TLV_TAG_ARRAY_STRUCT,
+ WMI_TLV_TAG_ARRAY_FIXED_STRUCT,
+ WMI_TLV_TAG_LAST_ARRAY_ENUM = 31,
+
+ WMI_TLV_TAG_STRUCT_SERVICE_READY_EVENT,
+ WMI_TLV_TAG_STRUCT_HAL_REG_CAPABILITIES,
+ WMI_TLV_TAG_STRUCT_WLAN_HOST_MEM_REQ,
+ WMI_TLV_TAG_STRUCT_READY_EVENT,
+ WMI_TLV_TAG_STRUCT_SCAN_EVENT,
+ WMI_TLV_TAG_STRUCT_PDEV_TPC_CONFIG_EVENT,
+ WMI_TLV_TAG_STRUCT_CHAN_INFO_EVENT,
+ WMI_TLV_TAG_STRUCT_COMB_PHYERR_RX_HDR,
+ WMI_TLV_TAG_STRUCT_VDEV_START_RESPONSE_EVENT,
+ WMI_TLV_TAG_STRUCT_VDEV_STOPPED_EVENT,
+ WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_COMPLETE_EVENT,
+ WMI_TLV_TAG_STRUCT_PEER_STA_KICKOUT_EVENT,
+ WMI_TLV_TAG_STRUCT_MGMT_RX_HDR,
+ WMI_TLV_TAG_STRUCT_TBTT_OFFSET_EVENT,
+ WMI_TLV_TAG_STRUCT_TX_DELBA_COMPLETE_EVENT,
+ WMI_TLV_TAG_STRUCT_TX_ADDBA_COMPLETE_EVENT,
+ WMI_TLV_TAG_STRUCT_ROAM_EVENT,
+ WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO,
+ WMI_TLV_TAG_STRUCT_WOW_EVENT_INFO_SECTION_BITMAP,
+ WMI_TLV_TAG_STRUCT_RTT_EVENT_HEADER,
+ WMI_TLV_TAG_STRUCT_RTT_ERROR_REPORT_EVENT,
+ WMI_TLV_TAG_STRUCT_RTT_MEAS_EVENT,
+ WMI_TLV_TAG_STRUCT_ECHO_EVENT,
+ WMI_TLV_TAG_STRUCT_FTM_INTG_EVENT,
+ WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_EVENT,
+ WMI_TLV_TAG_STRUCT_GPIO_INPUT_EVENT,
+ WMI_TLV_TAG_STRUCT_CSA_EVENT,
+ WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_STATUS_EVENT,
+ WMI_TLV_TAG_STRUCT_IGTK_INFO,
+ WMI_TLV_TAG_STRUCT_DCS_INTERFERENCE_EVENT,
+ WMI_TLV_TAG_STRUCT_ATH_DCS_CW_INT,
+ WMI_TLV_TAG_STRUCT_ATH_DCS_WLAN_INT_STAT,
+ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_CTX_T,
+ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_T,
+ WMI_TLV_TAG_STRUCT_PDEV_QVIT_EVENT,
+ WMI_TLV_TAG_STRUCT_HOST_SWBA_EVENT,
+ WMI_TLV_TAG_STRUCT_TIM_INFO,
+ WMI_TLV_TAG_STRUCT_P2P_NOA_INFO,
+ WMI_TLV_TAG_STRUCT_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGES_EVENT,
+ WMI_TLV_TAG_STRUCT_AVOID_FREQ_RANGE_DESC,
+ WMI_TLV_TAG_STRUCT_GTK_REKEY_FAIL_EVENT,
+ WMI_TLV_TAG_STRUCT_INIT_CMD,
+ WMI_TLV_TAG_STRUCT_RESOURCE_CONFIG,
+ WMI_TLV_TAG_STRUCT_WLAN_HOST_MEMORY_CHUNK,
+ WMI_TLV_TAG_STRUCT_START_SCAN_CMD,
+ WMI_TLV_TAG_STRUCT_STOP_SCAN_CMD,
+ WMI_TLV_TAG_STRUCT_SCAN_CHAN_LIST_CMD,
+ WMI_TLV_TAG_STRUCT_CHANNEL,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_REGDOMAIN_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_PARAM_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_WMM_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_WMM_PARAMS,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_QUIET_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_CREATE_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_DELETE_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_START_REQUEST_CMD,
+ WMI_TLV_TAG_STRUCT_P2P_NOA_DESCRIPTOR,
+ WMI_TLV_TAG_STRUCT_P2P_GO_SET_BEACON_IE,
+ WMI_TLV_TAG_STRUCT_GTK_OFFLOAD_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_UP_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_STOP_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_DOWN_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_SET_PARAM_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_INSTALL_KEY_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_CREATE_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_DELETE_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_FLUSH_TIDS_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_SET_PARAM_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_ASSOC_COMPLETE_CMD,
+ WMI_TLV_TAG_STRUCT_VHT_RATE_SET,
+ WMI_TLV_TAG_STRUCT_BCN_TMPL_CMD,
+ WMI_TLV_TAG_STRUCT_PRB_TMPL_CMD,
+ WMI_TLV_TAG_STRUCT_BCN_PRB_INFO,
+ WMI_TLV_TAG_STRUCT_PEER_TID_ADDBA_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_TID_DELBA_CMD,
+ WMI_TLV_TAG_STRUCT_STA_POWERSAVE_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_STA_POWERSAVE_PARAM_CMD,
+ WMI_TLV_TAG_STRUCT_STA_DTIM_PS_METHOD_CMD,
+ WMI_TLV_TAG_STRUCT_ROAM_SCAN_MODE,
+ WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_THRESHOLD,
+ WMI_TLV_TAG_STRUCT_ROAM_SCAN_PERIOD,
+ WMI_TLV_TAG_STRUCT_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ WMI_TLV_TAG_STRUCT_PDEV_SUSPEND_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_RESUME_CMD,
+ WMI_TLV_TAG_STRUCT_ADD_BCN_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_RMV_BCN_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_HOSTWAKEUP_FROM_SLEEP_CMD,
+ WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_CMD,
+ WMI_TLV_TAG_STRUCT_STA_UAPSD_AUTO_TRIG_PARAM,
+ WMI_TLV_TAG_STRUCT_SET_ARP_NS_OFFLOAD_CMD,
+ WMI_TLV_TAG_STRUCT_ARP_OFFLOAD_TUPLE,
+ WMI_TLV_TAG_STRUCT_NS_OFFLOAD_TUPLE,
+ WMI_TLV_TAG_STRUCT_FTM_INTG_CMD,
+ WMI_TLV_TAG_STRUCT_STA_KEEPALIVE_CMD,
+ WMI_TLV_TAG_STRUCT_STA_KEEPALVE_ARP_RESPONSE,
+ WMI_TLV_TAG_STRUCT_P2P_SET_VENDOR_IE_DATA_CMD,
+ WMI_TLV_TAG_STRUCT_AP_PS_PEER_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_RATE_RETRY_SCHED_CMD,
+ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_TRIGGER_CMD,
+ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_SET_HIST_INTVL_CMD,
+ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_GET_PROF_DATA_CMD,
+ WMI_TLV_TAG_STRUCT_WLAN_PROFILE_ENABLE_PROFILE_ID_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_DEL_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_ADD_DEL_EVT_CMD,
+ WMI_TLV_TAG_STRUCT_RTT_MEASREQ_HEAD,
+ WMI_TLV_TAG_STRUCT_RTT_MEASREQ_BODY,
+ WMI_TLV_TAG_STRUCT_RTT_TSF_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_CONFIGURE_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_SPECTRAL_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_REQUEST_STATS_CMD,
+ WMI_TLV_TAG_STRUCT_NLO_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_NLO_CONFIGURED_PARAMETERS,
+ WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_CSA_OFFLOAD_CHANSWITCH_CMD,
+ WMI_TLV_TAG_STRUCT_CHATTER_SET_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_ECHO_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_SET_KEEPALIVE_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_GET_KEEPALIVE_CMD,
+ WMI_TLV_TAG_STRUCT_FORCE_FW_HANG_CMD,
+ WMI_TLV_TAG_STRUCT_GPIO_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_GPIO_OUTPUT_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_ADD_WDS_ENTRY_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_REMOVE_WDS_ENTRY_CMD,
+ WMI_TLV_TAG_STRUCT_BCN_TX_HDR,
+ WMI_TLV_TAG_STRUCT_BCN_SEND_FROM_HOST_CMD,
+ WMI_TLV_TAG_STRUCT_MGMT_TX_HDR,
+ WMI_TLV_TAG_STRUCT_ADDBA_CLEAR_RESP_CMD,
+ WMI_TLV_TAG_STRUCT_ADDBA_SEND_CMD,
+ WMI_TLV_TAG_STRUCT_DELBA_SEND_CMD,
+ WMI_TLV_TAG_STRUCT_ADDBA_SETRESPONSE_CMD,
+ WMI_TLV_TAG_STRUCT_SEND_SINGLEAMSDU_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_PKTLOG_DISABLE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_HT_IE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_VHT_IE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_DSCP_TID_MAP_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_GREEN_AP_PS_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_GET_TPC_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_BASE_MACADDR_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_MCAST_GROUP_CMD,
+ WMI_TLV_TAG_STRUCT_ROAM_AP_PROFILE,
+ WMI_TLV_TAG_STRUCT_AP_PROFILE,
+ WMI_TLV_TAG_STRUCT_SCAN_SCH_PRIORITY_TABLE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_DFS_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_DFS_DISABLE_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_ADD_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_BITMAP_PATTERN_T,
+ WMI_TLV_TAG_STRUCT_WOW_IPV4_SYNC_PATTERN_T,
+ WMI_TLV_TAG_STRUCT_WOW_IPV6_SYNC_PATTERN_T,
+ WMI_TLV_TAG_STRUCT_WOW_MAGIC_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_SCAN_UPDATE_REQUEST_CMD,
+ WMI_TLV_TAG_STRUCT_CHATTER_PKT_COALESCING_FILTER,
+ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_ADD_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_DELETE_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_CHATTER_COALESCING_QUERY_CMD,
+ WMI_TLV_TAG_STRUCT_TXBF_CMD,
+ WMI_TLV_TAG_STRUCT_DEBUG_LOG_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_NLO_EVENT,
+ WMI_TLV_TAG_STRUCT_CHATTER_QUERY_REPLY_EVENT,
+ WMI_TLV_TAG_STRUCT_UPLOAD_H_HDR,
+ WMI_TLV_TAG_STRUCT_CAPTURE_H_EVENT_HDR,
+ WMI_TLV_TAG_STRUCT_VDEV_WNM_SLEEPMODE_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_IPSEC_NATKEEPALIVE_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_WMM_ADDTS_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_WMM_DELTS_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_SET_WMM_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_TDLS_SET_STATE_CMD,
+ WMI_TLV_TAG_STRUCT_TDLS_PEER_UPDATE_CMD,
+ WMI_TLV_TAG_STRUCT_TDLS_PEER_EVENT,
+ WMI_TLV_TAG_STRUCT_TDLS_PEER_CAPABILITIES,
+ WMI_TLV_TAG_STRUCT_VDEV_MCC_SET_TBTT_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_ROAM_CHAN_LIST,
+ WMI_TLV_TAG_STRUCT_VDEV_MCC_BCN_INTVL_CHANGE_EVENT,
+ WMI_TLV_TAG_STRUCT_RESMGR_ADAPTIVE_OCS_CMD,
+ WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_TIME_QUOTA_CMD,
+ WMI_TLV_TAG_STRUCT_RESMGR_SET_CHAN_LATENCY_CMD,
+ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD,
+ WMI_TLV_TAG_STRUCT_BA_RSP_SSN_EVENT,
+ WMI_TLV_TAG_STRUCT_STA_SMPS_FORCE_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_SET_MCASTBCAST_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_P2P_SET_OPPPS_CMD,
+ WMI_TLV_TAG_STRUCT_P2P_SET_NOA_CMD,
+ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_CMD_SUB_STRUCT_PARAM,
+ WMI_TLV_TAG_STRUCT_BA_REQ_SSN_EVENT_SUB_STRUCT_PARAM,
+ WMI_TLV_TAG_STRUCT_STA_SMPS_PARAM_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_SET_GTX_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_MCC_SCHED_TRAFFIC_STATS_CMD,
+ WMI_TLV_TAG_STRUCT_MCC_SCHED_STA_TRAFFIC_STATS,
+ WMI_TLV_TAG_STRUCT_OFFLOAD_BCN_TX_STATUS_EVENT,
+ WMI_TLV_TAG_STRUCT_P2P_NOA_EVENT,
+ WMI_TLV_TAG_STRUCT_HB_SET_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_HB_SET_TCP_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_HB_SET_TCP_PKT_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_HB_SET_UDP_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_HB_SET_UDP_PKT_FILTER_CMD,
+ WMI_TLV_TAG_STRUCT_HB_IND_EVENT,
+ WMI_TLV_TAG_STRUCT_TX_PAUSE_EVENT,
+ WMI_TLV_TAG_STRUCT_RFKILL_EVENT,
+ WMI_TLV_TAG_STRUCT_DFS_RADAR_EVENT,
+ WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_ENA_CMD,
+ WMI_TLV_TAG_STRUCT_DFS_PHYERR_FILTER_DIS_CMD,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_SCAN_LIST,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_NETWORK_INFO,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_DISABLE_CMD,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_TRIGGER_RESULT_CMD,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_ENABLED_EVENT,
+ WMI_TLV_TAG_STRUCT_BATCH_SCAN_RESULT_EVENT,
+ WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_START_CMD,
+ WMI_TLV_TAG_STRUCT_VDEV_PLMREQ_STOP_CMD,
+ WMI_TLV_TAG_STRUCT_THERMAL_MGMT_CMD,
+ WMI_TLV_TAG_STRUCT_THERMAL_MGMT_EVENT,
+ WMI_TLV_TAG_STRUCT_PEER_INFO_REQ_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_INFO_EVENT,
+ WMI_TLV_TAG_STRUCT_PEER_INFO,
+ WMI_TLV_TAG_STRUCT_PEER_TX_FAIL_CNT_THR_EVENT,
+ WMI_TLV_TAG_STRUCT_RMC_SET_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_RMC_SET_ACTION_PERIOD_CMD,
+ WMI_TLV_TAG_STRUCT_RMC_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_SET_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_PLUMB_ROUTING_TABLE_CMD,
+ WMI_TLV_TAG_STRUCT_ADD_PROACTIVE_ARP_RSP_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_DEL_PROACTIVE_ARP_RSP_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_NAN_CMD_PARAM,
+ WMI_TLV_TAG_STRUCT_NAN_EVENT_HDR,
+ WMI_TLV_TAG_STRUCT_PDEV_L1SS_TRACK_EVENT,
+ WMI_TLV_TAG_STRUCT_DIAG_DATA_CONTAINER_EVENT,
+ WMI_TLV_TAG_STRUCT_MODEM_POWER_STATE_CMD_PARAM,
+ WMI_TLV_TAG_STRUCT_PEER_GET_ESTIMATED_LINKSPEED_CMD,
+ WMI_TLV_TAG_STRUCT_PEER_ESTIMATED_LINKSPEED_EVENT,
+ WMI_TLV_TAG_STRUCT_AGGR_STATE_TRIG_EVENT,
+ WMI_TLV_TAG_STRUCT_MHF_OFFLOAD_ROUTING_TABLE_ENTRY,
+ WMI_TLV_TAG_STRUCT_ROAM_SCAN_CMD,
+ WMI_TLV_TAG_STRUCT_REQ_STATS_EXT_CMD,
+ WMI_TLV_TAG_STRUCT_STATS_EXT_EVENT,
+ WMI_TLV_TAG_STRUCT_OBSS_SCAN_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_OBSS_SCAN_DISABLE_CMD,
+ WMI_TLV_TAG_STRUCT_OFFLOAD_PRB_RSP_TX_STATUS_EVENT,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_LED_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_CFG_CMD,
+ WMI_TLV_TAG_STRUCT_HOST_AUTO_SHUTDOWN_EVENT,
+ WMI_TLV_TAG_STRUCT_UPDATE_WHAL_MIB_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_CHAN_AVOID_UPDATE_CMD_PARAM,
+ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_PKT_PATTERN_T,
+ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_TMR_PATTERN_T,
+ WMI_TLV_TAG_STRUCT_WOW_IOAC_ADD_KEEPALIVE_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_IOAC_DEL_KEEPALIVE_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_IOAC_KEEPALIVE_T,
+ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_ADD_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_WOW_ACER_IOAC_DEL_PATTERN_CMD,
+ WMI_TLV_TAG_STRUCT_START_LINK_STATS_CMD,
+ WMI_TLV_TAG_STRUCT_CLEAR_LINK_STATS_CMD,
+ WMI_TLV_TAG_STRUCT_REQUEST_LINK_STATS_CMD,
+ WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_PEER_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_CHANNEL_STATS,
+ WMI_TLV_TAG_STRUCT_RADIO_LINK_STATS,
+ WMI_TLV_TAG_STRUCT_RATE_STATS,
+ WMI_TLV_TAG_STRUCT_PEER_LINK_STATS,
+ WMI_TLV_TAG_STRUCT_WMM_AC_STATS,
+ WMI_TLV_TAG_STRUCT_IFACE_LINK_STATS,
+ WMI_TLV_TAG_STRUCT_LPI_MGMT_SNOOPING_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_LPI_START_SCAN_CMD,
+ WMI_TLV_TAG_STRUCT_LPI_STOP_SCAN_CMD,
+ WMI_TLV_TAG_STRUCT_LPI_RESULT_EVENT,
+ WMI_TLV_TAG_STRUCT_PEER_STATE_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_BUCKET_CHANNEL_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_START_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_STOP_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_WLAN_CHANGE_MONITOR_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_BSSID_PARAM_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_CONFIGURE_HOTLIST_MONITOR_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CACHED_RESULTS_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_WLAN_CHANGE_RESULTS_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_SET_CAPABILITIES_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_GET_CAPABILITIES_CMD,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_OPERATION_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_START_STOP_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_TABLE_USAGE_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_DESCRIPTOR_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_RSSI_INFO_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_CACHED_RESULTS_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULTS_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_RESULT_BSSID_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MATCH_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_CAPABILITIES_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_CACHE_CAPABILITIES_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_WLAN_CHANGE_MONITOR_CAPABILITIES_EVENT,
+ WMI_TLV_TAG_STRUCT_EXTSCAN_HOTLIST_MONITOR_CAPABILITIES_EVENT,
+ WMI_TLV_TAG_STRUCT_D0_WOW_ENABLE_DISABLE_CMD,
+ WMI_TLV_TAG_STRUCT_D0_WOW_DISABLE_ACK_EVENT,
+ WMI_TLV_TAG_STRUCT_UNIT_TEST_CMD,
+ WMI_TLV_TAG_STRUCT_ROAM_OFFLOAD_TLV_PARAM,
+ WMI_TLV_TAG_STRUCT_ROAM_11I_OFFLOAD_TLV_PARAM,
+ WMI_TLV_TAG_STRUCT_ROAM_11R_OFFLOAD_TLV_PARAM,
+ WMI_TLV_TAG_STRUCT_ROAM_ESE_OFFLOAD_TLV_PARAM,
+ WMI_TLV_TAG_STRUCT_ROAM_SYNCH_EVENT,
+ WMI_TLV_TAG_STRUCT_ROAM_SYNCH_COMPLETE,
+ WMI_TLV_TAG_STRUCT_EXTWOW_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE1_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_EXTWOW_SET_APP_TYPE2_PARAMS_CMD,
+ WMI_TLV_TAG_STRUCT_LPI_STATUS_EVENT,
+ WMI_TLV_TAG_STRUCT_LPI_HANDOFF_EVENT,
+ WMI_TLV_TAG_STRUCT_VDEV_RATE_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_VDEV_RATE_HT_INFO,
+ WMI_TLV_TAG_STRUCT_RIC_REQUEST,
+ WMI_TLV_TAG_STRUCT_PDEV_GET_TEMPERATURE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_TEMPERATURE_EVENT,
+ WMI_TLV_TAG_STRUCT_SET_DHCP_SERVER_OFFLOAD_CMD,
+ WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG_CMD,
+ WMI_TLV_TAG_STRUCT_RIC_TSPEC,
+ WMI_TLV_TAG_STRUCT_TPC_CHAINMASK_CONFIG,
+ WMI_TLV_TAG_STRUCT_IPA_OFFLOAD_CMD,
+ WMI_TLV_TAG_STRUCT_SCAN_PROB_REQ_OUI_CMD,
+ WMI_TLV_TAG_STRUCT_KEY_MATERIAL,
+ WMI_TLV_TAG_STRUCT_TDLS_SET_OFFCHAN_MODE_CMD,
+ WMI_TLV_TAG_STRUCT_SET_LED_FLASHING_CMD,
+ WMI_TLV_TAG_STRUCT_MDNS_OFFLOAD_CMD,
+ WMI_TLV_TAG_STRUCT_MDNS_SET_FQDN_CMD,
+ WMI_TLV_TAG_STRUCT_MDNS_SET_RESP_CMD,
+ WMI_TLV_TAG_STRUCT_MDNS_GET_STATS_CMD,
+ WMI_TLV_TAG_STRUCT_MDNS_STATS_EVENT,
+ WMI_TLV_TAG_STRUCT_ROAM_INVOKE_CMD,
+ WMI_TLV_TAG_STRUCT_PDEV_RESUME_EVENT,
+ WMI_TLV_TAG_STRUCT_PDEV_SET_ANTENNA_DIVERSITY_CMD,
+ WMI_TLV_TAG_STRUCT_SAP_OFL_ENABLE_CMD,
+ WMI_TLV_TAG_STRUCT_SAP_OFL_ADD_STA_EVENT,
+ WMI_TLV_TAG_STRUCT_SAP_OFL_DEL_STA_EVENT,
+ WMI_TLV_TAG_STRUCT_APFIND_CMD_PARAM,
+ WMI_TLV_TAG_STRUCT_APFIND_EVENT_HDR,
+
+ WMI_TLV_TAG_MAX
+};
+
+enum wmi_tlv_service {
+ WMI_TLV_SERVICE_BEACON_OFFLOAD = 0,
+ WMI_TLV_SERVICE_SCAN_OFFLOAD,
+ WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD,
+ WMI_TLV_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_TLV_SERVICE_STA_PWRSAVE,
+ WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_TLV_SERVICE_AP_UAPSD,
+ WMI_TLV_SERVICE_AP_DFS,
+ WMI_TLV_SERVICE_11AC,
+ WMI_TLV_SERVICE_BLOCKACK,
+ WMI_TLV_SERVICE_PHYERR,
+ WMI_TLV_SERVICE_BCN_FILTER,
+ WMI_TLV_SERVICE_RTT,
+ WMI_TLV_SERVICE_WOW,
+ WMI_TLV_SERVICE_RATECTRL_CACHE,
+ WMI_TLV_SERVICE_IRAM_TIDS,
+ WMI_TLV_SERVICE_ARPNS_OFFLOAD,
+ WMI_TLV_SERVICE_NLO,
+ WMI_TLV_SERVICE_GTK_OFFLOAD,
+ WMI_TLV_SERVICE_SCAN_SCH,
+ WMI_TLV_SERVICE_CSA_OFFLOAD,
+ WMI_TLV_SERVICE_CHATTER,
+ WMI_TLV_SERVICE_COEX_FREQAVOID,
+ WMI_TLV_SERVICE_PACKET_POWER_SAVE,
+ WMI_TLV_SERVICE_FORCE_FW_HANG,
+ WMI_TLV_SERVICE_GPIO,
+ WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_TLV_SERVICE_STA_KEEP_ALIVE,
+ WMI_TLV_SERVICE_TX_ENCAP,
+ WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
+ WMI_TLV_SERVICE_EARLY_RX,
+ WMI_TLV_SERVICE_STA_SMPS,
+ WMI_TLV_SERVICE_FWTEST,
+ WMI_TLV_SERVICE_STA_WMMAC,
+ WMI_TLV_SERVICE_TDLS,
+ WMI_TLV_SERVICE_BURST,
+ WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE,
+ WMI_TLV_SERVICE_ADAPTIVE_OCS,
+ WMI_TLV_SERVICE_BA_SSN_SUPPORT,
+ WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
+ WMI_TLV_SERVICE_WLAN_HB,
+ WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT,
+ WMI_TLV_SERVICE_BATCH_SCAN,
+ WMI_TLV_SERVICE_QPOWER,
+ WMI_TLV_SERVICE_PLMREQ,
+ WMI_TLV_SERVICE_THERMAL_MGMT,
+ WMI_TLV_SERVICE_RMC,
+ WMI_TLV_SERVICE_MHF_OFFLOAD,
+ WMI_TLV_SERVICE_COEX_SAR,
+ WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE,
+ WMI_TLV_SERVICE_NAN,
+ WMI_TLV_SERVICE_L1SS_STAT,
+ WMI_TLV_SERVICE_ESTIMATE_LINKSPEED,
+ WMI_TLV_SERVICE_OBSS_SCAN,
+ WMI_TLV_SERVICE_TDLS_OFFCHAN,
+ WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA,
+ WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA,
+ WMI_TLV_SERVICE_IBSS_PWRSAVE,
+ WMI_TLV_SERVICE_LPASS,
+ WMI_TLV_SERVICE_EXTSCAN,
+ WMI_TLV_SERVICE_D0WOW,
+ WMI_TLV_SERVICE_HSOFFLOAD,
+ WMI_TLV_SERVICE_ROAM_HO_OFFLOAD,
+ WMI_TLV_SERVICE_RX_FULL_REORDER,
+ WMI_TLV_SERVICE_DHCP_OFFLOAD,
+ WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
+ WMI_TLV_SERVICE_MDNS_OFFLOAD,
+ WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
+};
+
+#define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
+ ((svc_id) < (len) && \
+ __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
+ BIT((svc_id)%(sizeof(u32))))
+
+#define SVCMAP(x, y, len) \
+ do { \
+ if (WMI_SERVICE_IS_ENABLED((in), (x), (len))) \
+ __set_bit(y, out); \
+ } while (0)
+
+static inline void
+wmi_tlv_svc_map(const __le32 *in, unsigned long *out, size_t len)
+{
+ SVCMAP(WMI_TLV_SERVICE_BEACON_OFFLOAD,
+ WMI_SERVICE_BEACON_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_SCAN_OFFLOAD,
+ WMI_SERVICE_SCAN_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_ROAM_SCAN_OFFLOAD,
+ WMI_SERVICE_ROAM_SCAN_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_BCN_MISS_OFFLOAD,
+ WMI_SERVICE_BCN_MISS_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_PWRSAVE,
+ WMI_SERVICE_STA_PWRSAVE, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_ADVANCED_PWRSAVE,
+ WMI_SERVICE_STA_ADVANCED_PWRSAVE, len);
+ SVCMAP(WMI_TLV_SERVICE_AP_UAPSD,
+ WMI_SERVICE_AP_UAPSD, len);
+ SVCMAP(WMI_TLV_SERVICE_AP_DFS,
+ WMI_SERVICE_AP_DFS, len);
+ SVCMAP(WMI_TLV_SERVICE_11AC,
+ WMI_SERVICE_11AC, len);
+ SVCMAP(WMI_TLV_SERVICE_BLOCKACK,
+ WMI_SERVICE_BLOCKACK, len);
+ SVCMAP(WMI_TLV_SERVICE_PHYERR,
+ WMI_SERVICE_PHYERR, len);
+ SVCMAP(WMI_TLV_SERVICE_BCN_FILTER,
+ WMI_SERVICE_BCN_FILTER, len);
+ SVCMAP(WMI_TLV_SERVICE_RTT,
+ WMI_SERVICE_RTT, len);
+ SVCMAP(WMI_TLV_SERVICE_WOW,
+ WMI_SERVICE_WOW, len);
+ SVCMAP(WMI_TLV_SERVICE_RATECTRL_CACHE,
+ WMI_SERVICE_RATECTRL_CACHE, len);
+ SVCMAP(WMI_TLV_SERVICE_IRAM_TIDS,
+ WMI_SERVICE_IRAM_TIDS, len);
+ SVCMAP(WMI_TLV_SERVICE_ARPNS_OFFLOAD,
+ WMI_SERVICE_ARPNS_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_NLO,
+ WMI_SERVICE_NLO, len);
+ SVCMAP(WMI_TLV_SERVICE_GTK_OFFLOAD,
+ WMI_SERVICE_GTK_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_SCAN_SCH,
+ WMI_SERVICE_SCAN_SCH, len);
+ SVCMAP(WMI_TLV_SERVICE_CSA_OFFLOAD,
+ WMI_SERVICE_CSA_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_CHATTER,
+ WMI_SERVICE_CHATTER, len);
+ SVCMAP(WMI_TLV_SERVICE_COEX_FREQAVOID,
+ WMI_SERVICE_COEX_FREQAVOID, len);
+ SVCMAP(WMI_TLV_SERVICE_PACKET_POWER_SAVE,
+ WMI_SERVICE_PACKET_POWER_SAVE, len);
+ SVCMAP(WMI_TLV_SERVICE_FORCE_FW_HANG,
+ WMI_SERVICE_FORCE_FW_HANG, len);
+ SVCMAP(WMI_TLV_SERVICE_GPIO,
+ WMI_SERVICE_GPIO, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_DTIM_PS_MODULATED_DTIM,
+ WMI_SERVICE_STA_DTIM_PS_MODULATED_DTIM, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_BASIC_AUTO_TRIG, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_UAPSD_VAR_AUTO_TRIG,
+ WMI_SERVICE_STA_UAPSD_VAR_AUTO_TRIG, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_KEEP_ALIVE,
+ WMI_SERVICE_STA_KEEP_ALIVE, len);
+ SVCMAP(WMI_TLV_SERVICE_TX_ENCAP,
+ WMI_SERVICE_TX_ENCAP, len);
+ SVCMAP(WMI_TLV_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
+ WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC, len);
+ SVCMAP(WMI_TLV_SERVICE_EARLY_RX,
+ WMI_SERVICE_EARLY_RX, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_SMPS,
+ WMI_SERVICE_STA_SMPS, len);
+ SVCMAP(WMI_TLV_SERVICE_FWTEST,
+ WMI_SERVICE_FWTEST, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_WMMAC,
+ WMI_SERVICE_STA_WMMAC, len);
+ SVCMAP(WMI_TLV_SERVICE_TDLS,
+ WMI_SERVICE_TDLS, len);
+ SVCMAP(WMI_TLV_SERVICE_BURST,
+ WMI_SERVICE_BURST, len);
+ SVCMAP(WMI_TLV_SERVICE_MCC_BCN_INTERVAL_CHANGE,
+ WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE, len);
+ SVCMAP(WMI_TLV_SERVICE_ADAPTIVE_OCS,
+ WMI_SERVICE_ADAPTIVE_OCS, len);
+ SVCMAP(WMI_TLV_SERVICE_BA_SSN_SUPPORT,
+ WMI_SERVICE_BA_SSN_SUPPORT, len);
+ SVCMAP(WMI_TLV_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
+ WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE, len);
+ SVCMAP(WMI_TLV_SERVICE_WLAN_HB,
+ WMI_SERVICE_WLAN_HB, len);
+ SVCMAP(WMI_TLV_SERVICE_LTE_ANT_SHARE_SUPPORT,
+ WMI_SERVICE_LTE_ANT_SHARE_SUPPORT, len);
+ SVCMAP(WMI_TLV_SERVICE_BATCH_SCAN,
+ WMI_SERVICE_BATCH_SCAN, len);
+ SVCMAP(WMI_TLV_SERVICE_QPOWER,
+ WMI_SERVICE_QPOWER, len);
+ SVCMAP(WMI_TLV_SERVICE_PLMREQ,
+ WMI_SERVICE_PLMREQ, len);
+ SVCMAP(WMI_TLV_SERVICE_THERMAL_MGMT,
+ WMI_SERVICE_THERMAL_MGMT, len);
+ SVCMAP(WMI_TLV_SERVICE_RMC,
+ WMI_SERVICE_RMC, len);
+ SVCMAP(WMI_TLV_SERVICE_MHF_OFFLOAD,
+ WMI_SERVICE_MHF_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_COEX_SAR,
+ WMI_SERVICE_COEX_SAR, len);
+ SVCMAP(WMI_TLV_SERVICE_BCN_TXRATE_OVERRIDE,
+ WMI_SERVICE_BCN_TXRATE_OVERRIDE, len);
+ SVCMAP(WMI_TLV_SERVICE_NAN,
+ WMI_SERVICE_NAN, len);
+ SVCMAP(WMI_TLV_SERVICE_L1SS_STAT,
+ WMI_SERVICE_L1SS_STAT, len);
+ SVCMAP(WMI_TLV_SERVICE_ESTIMATE_LINKSPEED,
+ WMI_SERVICE_ESTIMATE_LINKSPEED, len);
+ SVCMAP(WMI_TLV_SERVICE_OBSS_SCAN,
+ WMI_SERVICE_OBSS_SCAN, len);
+ SVCMAP(WMI_TLV_SERVICE_TDLS_OFFCHAN,
+ WMI_SERVICE_TDLS_OFFCHAN, len);
+ SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_BUFFER_STA,
+ WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, len);
+ SVCMAP(WMI_TLV_SERVICE_TDLS_UAPSD_SLEEP_STA,
+ WMI_SERVICE_TDLS_UAPSD_SLEEP_STA, len);
+ SVCMAP(WMI_TLV_SERVICE_IBSS_PWRSAVE,
+ WMI_SERVICE_IBSS_PWRSAVE, len);
+ SVCMAP(WMI_TLV_SERVICE_LPASS,
+ WMI_SERVICE_LPASS, len);
+ SVCMAP(WMI_TLV_SERVICE_EXTSCAN,
+ WMI_SERVICE_EXTSCAN, len);
+ SVCMAP(WMI_TLV_SERVICE_D0WOW,
+ WMI_SERVICE_D0WOW, len);
+ SVCMAP(WMI_TLV_SERVICE_HSOFFLOAD,
+ WMI_SERVICE_HSOFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_ROAM_HO_OFFLOAD,
+ WMI_SERVICE_ROAM_HO_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_RX_FULL_REORDER,
+ WMI_SERVICE_RX_FULL_REORDER, len);
+ SVCMAP(WMI_TLV_SERVICE_DHCP_OFFLOAD,
+ WMI_SERVICE_DHCP_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
+ WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT, len);
+ SVCMAP(WMI_TLV_SERVICE_MDNS_OFFLOAD,
+ WMI_SERVICE_MDNS_OFFLOAD, len);
+ SVCMAP(WMI_TLV_SERVICE_SAP_AUTH_OFFLOAD,
+ WMI_SERVICE_SAP_AUTH_OFFLOAD, len);
+}
+
+#undef SVCMAP
+
+struct wmi_tlv {
+ __le16 len;
+ __le16 tag;
+ u8 value[0];
+} __packed;
+
+#define WMI_TLV_MGMT_RX_NUM_RSSI 4
+
+struct wmi_tlv_mgmt_rx_ev {
+ __le32 channel;
+ __le32 snr;
+ __le32 rate;
+ __le32 phy_mode;
+ __le32 buf_len;
+ __le32 status;
+ __le32 rssi[WMI_TLV_MGMT_RX_NUM_RSSI];
+} __packed;
+
+struct wmi_tlv_abi_version {
+ __le32 abi_ver0;
+ __le32 abi_ver1;
+ __le32 abi_ver_ns0;
+ __le32 abi_ver_ns1;
+ __le32 abi_ver_ns2;
+ __le32 abi_ver_ns3;
+} __packed;
+
+enum wmi_tlv_hw_bd_id {
+ WMI_TLV_HW_BD_LEGACY = 0,
+ WMI_TLV_HW_BD_QCA6174 = 1,
+ WMI_TLV_HW_BD_QCA2582 = 2,
+};
+
+struct wmi_tlv_hw_bd_info {
+ u8 rev;
+ u8 project_id;
+ u8 custom_id;
+ u8 reference_design_id;
+} __packed;
+
+struct wmi_tlv_svc_rdy_ev {
+ __le32 fw_build_vers;
+ struct wmi_tlv_abi_version abi;
+ __le32 phy_capability;
+ __le32 max_frag_entry;
+ __le32 num_rf_chains;
+ __le32 ht_cap_info;
+ __le32 vht_cap_info;
+ __le32 vht_supp_mcs;
+ __le32 hw_min_tx_power;
+ __le32 hw_max_tx_power;
+ __le32 sys_cap_info;
+ __le32 min_pkt_size_enable;
+ __le32 max_bcn_ie_size;
+ __le32 num_mem_reqs;
+ __le32 max_num_scan_chans;
+ __le32 hw_bd_id; /* 0 means hw_bd_info is invalid */
+ struct wmi_tlv_hw_bd_info hw_bd_info[5];
+} __packed;
+
+struct wmi_tlv_rdy_ev {
+ struct wmi_tlv_abi_version abi;
+ struct wmi_mac_addr mac_addr;
+ __le32 status;
+} __packed;
+
+struct wmi_tlv_resource_config {
+ __le32 num_vdevs;
+ __le32 num_peers;
+ __le32 num_offload_peers;
+ __le32 num_offload_reorder_bufs;
+ __le32 num_peer_keys;
+ __le32 num_tids;
+ __le32 ast_skid_limit;
+ __le32 tx_chain_mask;
+ __le32 rx_chain_mask;
+ __le32 rx_timeout_pri[4];
+ __le32 rx_decap_mode;
+ __le32 scan_max_pending_reqs;
+ __le32 bmiss_offload_max_vdev;
+ __le32 roam_offload_max_vdev;
+ __le32 roam_offload_max_ap_profiles;
+ __le32 num_mcast_groups;
+ __le32 num_mcast_table_elems;
+ __le32 mcast2ucast_mode;
+ __le32 tx_dbg_log_size;
+ __le32 num_wds_entries;
+ __le32 dma_burst_size;
+ __le32 mac_aggr_delim;
+ __le32 rx_skip_defrag_timeout_dup_detection_check;
+ __le32 vow_config;
+ __le32 gtk_offload_max_vdev;
+ __le32 num_msdu_desc;
+ __le32 max_frag_entries;
+ __le32 num_tdls_vdevs;
+ __le32 num_tdls_conn_table_entries;
+ __le32 beacon_tx_offload_max_vdev;
+ __le32 num_multicast_filter_entries;
+ __le32 num_wow_filters;
+ __le32 num_keep_alive_pattern;
+ __le32 keep_alive_pattern_size;
+ __le32 max_tdls_concurrent_sleep_sta;
+ __le32 max_tdls_concurrent_buffer_sta;
+} __packed;
+
+struct wmi_tlv_init_cmd {
+ struct wmi_tlv_abi_version abi;
+ __le32 num_host_mem_chunks;
+} __packed;
+
+struct wmi_tlv_pdev_set_param_cmd {
+ __le32 pdev_id; /* not used yet */
+ __le32 param_id;
+ __le32 param_value;
+} __packed;
+
+struct wmi_tlv_pdev_set_rd_cmd {
+ __le32 pdev_id; /* not used yet */
+ __le32 regd;
+ __le32 regd_2ghz;
+ __le32 regd_5ghz;
+ __le32 conform_limit_2ghz;
+ __le32 conform_limit_5ghz;
+} __packed;
+
+struct wmi_tlv_scan_chan_list_cmd {
+ __le32 num_scan_chans;
+} __packed;
+
+struct wmi_tlv_start_scan_cmd {
+ struct wmi_start_scan_common common;
+ __le32 burst_duration_ms;
+ __le32 num_channels;
+ __le32 num_bssids;
+ __le32 num_ssids;
+ __le32 ie_len;
+ __le32 num_probes;
+} __packed;
+
+struct wmi_tlv_vdev_start_cmd {
+ __le32 vdev_id;
+ __le32 requestor_id;
+ __le32 bcn_intval;
+ __le32 dtim_period;
+ __le32 flags;
+ struct wmi_ssid ssid;
+ __le32 bcn_tx_rate;
+ __le32 bcn_tx_power;
+ __le32 num_noa_descr;
+ __le32 disable_hw_ack;
+} __packed;
+
+enum {
+ WMI_TLV_PEER_TYPE_DEFAULT = 0, /* generic / non-BSS / self-peer */
+ WMI_TLV_PEER_TYPE_BSS = 1,
+ WMI_TLV_PEER_TYPE_TDLS = 2,
+ WMI_TLV_PEER_TYPE_HOST_MAX = 127,
+ WMI_TLV_PEER_TYPE_ROAMOFFLOAD_TMP = 128,
+};
+
+struct wmi_tlv_peer_create_cmd {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_addr;
+ __le32 peer_type;
+} __packed;
+
+struct wmi_tlv_peer_assoc_cmd {
+ struct wmi_mac_addr mac_addr;
+ __le32 vdev_id;
+ __le32 new_assoc;
+ __le32 assoc_id;
+ __le32 flags;
+ __le32 caps;
+ __le32 listen_intval;
+ __le32 ht_caps;
+ __le32 max_mpdu;
+ __le32 mpdu_density;
+ __le32 rate_caps;
+ __le32 nss;
+ __le32 vht_caps;
+ __le32 phy_mode;
+ __le32 ht_info[2];
+ __le32 num_legacy_rates;
+ __le32 num_ht_rates;
+} __packed;
+
+struct wmi_tlv_pdev_suspend {
+ __le32 pdev_id; /* not used yet */
+ __le32 opt;
+} __packed;
+
+struct wmi_tlv_pdev_set_wmm_cmd {
+ __le32 pdev_id; /* not used yet */
+ __le32 dg_type; /* no idea.. */
+} __packed;
+
+struct wmi_tlv_vdev_set_wmm_cmd {
+ __le32 vdev_id;
+} __packed;
+
+struct wmi_tlv_phyerr_ev {
+ __le32 num_phyerrs;
+ __le32 tsf_l32;
+ __le32 tsf_u32;
+ __le32 buf_len;
+} __packed;
+
+enum wmi_tlv_dbglog_param {
+ WMI_TLV_DBGLOG_PARAM_LOG_LEVEL = 1,
+ WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE,
+ WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE,
+ WMI_TLV_DBGLOG_PARAM_VDEV_ENABLE_BITMAP,
+ WMI_TLV_DBGLOG_PARAM_VDEV_DISABLE_BITMAP,
+};
+
+enum wmi_tlv_dbglog_log_level {
+ WMI_TLV_DBGLOG_LOG_LEVEL_VERBOSE = 0,
+ WMI_TLV_DBGLOG_LOG_LEVEL_INFO,
+ WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_1,
+ WMI_TLV_DBGLOG_LOG_LEVEL_INFO_LVL_2,
+ WMI_TLV_DBGLOG_LOG_LEVEL_WARN,
+ WMI_TLV_DBGLOG_LOG_LEVEL_ERR,
+};
+
+#define WMI_TLV_DBGLOG_BITMAP_MAX_IDS 512
+#define WMI_TLV_DBGLOG_BITMAP_MAX_WORDS (WMI_TLV_DBGLOG_BITMAP_MAX_IDS / \
+ sizeof(__le32))
+#define WMI_TLV_DBGLOG_ALL_MODULES 0xffff
+#define WMI_TLV_DBGLOG_LOG_LEVEL_VALUE(module_id, log_level) \
+ (((module_id << 16) & 0xffff0000) | \
+ ((log_level << 0) & 0x000000ff))
+
+struct wmi_tlv_dbglog_cmd {
+ __le32 param;
+ __le32 value;
+} __packed;
+
+struct wmi_tlv_resume_cmd {
+ __le32 reserved;
+} __packed;
+
+struct wmi_tlv_req_stats_cmd {
+ __le32 stats_id; /* wmi_stats_id */
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_macaddr;
+} __packed;
+
+struct wmi_tlv_vdev_stats {
+ __le32 vdev_id;
+ __le32 beacon_snr;
+ __le32 data_snr;
+ __le32 num_tx_frames[4]; /* per-AC */
+ __le32 num_rx_frames;
+ __le32 num_tx_frames_retries[4];
+ __le32 num_tx_frames_failures[4];
+ __le32 num_rts_fail;
+ __le32 num_rts_success;
+ __le32 num_rx_err;
+ __le32 num_rx_discard;
+ __le32 num_tx_not_acked;
+ __le32 tx_rate_history[10];
+ __le32 beacon_rssi_history[10];
+} __packed;
+
+struct wmi_tlv_pktlog_enable {
+ __le32 reserved;
+ __le32 filter;
+} __packed;
+
+struct wmi_tlv_pktlog_disable {
+ __le32 reserved;
+} __packed;
+
+enum wmi_tlv_bcn_tx_status {
+ WMI_TLV_BCN_TX_STATUS_OK,
+ WMI_TLV_BCN_TX_STATUS_XRETRY,
+ WMI_TLV_BCN_TX_STATUS_DROP,
+ WMI_TLV_BCN_TX_STATUS_FILTERED,
+};
+
+struct wmi_tlv_bcn_tx_status_ev {
+ __le32 vdev_id;
+ __le32 tx_status;
+} __packed;
+
+struct wmi_tlv_bcn_prb_info {
+ __le32 caps;
+ __le32 erp;
+ u8 ies[0];
+} __packed;
+
+struct wmi_tlv_bcn_tmpl_cmd {
+ __le32 vdev_id;
+ __le32 tim_ie_offset;
+ __le32 buf_len;
+} __packed;
+
+struct wmi_tlv_prb_tmpl_cmd {
+ __le32 vdev_id;
+ __le32 buf_len;
+} __packed;
+
+struct wmi_tlv_p2p_go_bcn_ie {
+ __le32 vdev_id;
+ __le32 ie_len;
+} __packed;
+
+enum wmi_tlv_diag_item_type {
+ WMI_TLV_DIAG_ITEM_TYPE_FW_EVENT,
+ WMI_TLV_DIAG_ITEM_TYPE_FW_LOG,
+ WMI_TLV_DIAG_ITEM_TYPE_FW_DEBUG_MSG,
+};
+
+struct wmi_tlv_diag_item {
+ u8 type;
+ u8 reserved;
+ __le16 len;
+ __le32 timestamp;
+ __le32 code;
+ u8 payload[0];
+} __packed;
+
+struct wmi_tlv_diag_data_ev {
+ __le32 num_items;
+} __packed;
+
+struct wmi_tlv_sta_keepalive_cmd {
+ __le32 vdev_id;
+ __le32 enabled;
+ __le32 method; /* WMI_STA_KEEPALIVE_METHOD_ */
+ __le32 interval; /* in seconds */
+} __packed;
+
+void ath10k_wmi_tlv_attach(struct ath10k *ar);
+
+#endif
diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c
index c0f3e4d09263..aeea1c793943 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.c
+++ b/drivers/net/wireless/ath/ath10k/wmi.c
@@ -22,8 +22,10 @@
#include "htc.h"
#include "debug.h"
#include "wmi.h"
+#include "wmi-tlv.h"
#include "mac.h"
#include "testmode.h"
+#include "wmi-ops.h"
/* MAIN WMI cmd track */
static struct wmi_cmd_map wmi_cmd_map = {
@@ -143,6 +145,7 @@ static struct wmi_cmd_map wmi_cmd_map = {
.force_fw_hang_cmdid = WMI_FORCE_FW_HANG_CMDID,
.gpio_config_cmdid = WMI_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_GPIO_OUTPUT_CMDID,
+ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
};
/* 10.X WMI cmd track */
@@ -265,6 +268,129 @@ static struct wmi_cmd_map wmi_10x_cmd_map = {
.force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
.gpio_config_cmdid = WMI_10X_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_10X_GPIO_OUTPUT_CMDID,
+ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
+};
+
+/* 10.2.4 WMI cmd track */
+static struct wmi_cmd_map wmi_10_2_4_cmd_map = {
+ .init_cmdid = WMI_10_2_INIT_CMDID,
+ .start_scan_cmdid = WMI_10_2_START_SCAN_CMDID,
+ .stop_scan_cmdid = WMI_10_2_STOP_SCAN_CMDID,
+ .scan_chan_list_cmdid = WMI_10_2_SCAN_CHAN_LIST_CMDID,
+ .scan_sch_prio_tbl_cmdid = WMI_CMD_UNSUPPORTED,
+ .pdev_set_regdomain_cmdid = WMI_10_2_PDEV_SET_REGDOMAIN_CMDID,
+ .pdev_set_channel_cmdid = WMI_10_2_PDEV_SET_CHANNEL_CMDID,
+ .pdev_set_param_cmdid = WMI_10_2_PDEV_SET_PARAM_CMDID,
+ .pdev_pktlog_enable_cmdid = WMI_10_2_PDEV_PKTLOG_ENABLE_CMDID,
+ .pdev_pktlog_disable_cmdid = WMI_10_2_PDEV_PKTLOG_DISABLE_CMDID,
+ .pdev_set_wmm_params_cmdid = WMI_10_2_PDEV_SET_WMM_PARAMS_CMDID,
+ .pdev_set_ht_cap_ie_cmdid = WMI_10_2_PDEV_SET_HT_CAP_IE_CMDID,
+ .pdev_set_vht_cap_ie_cmdid = WMI_10_2_PDEV_SET_VHT_CAP_IE_CMDID,
+ .pdev_set_quiet_mode_cmdid = WMI_10_2_PDEV_SET_QUIET_MODE_CMDID,
+ .pdev_green_ap_ps_enable_cmdid = WMI_10_2_PDEV_GREEN_AP_PS_ENABLE_CMDID,
+ .pdev_get_tpc_config_cmdid = WMI_10_2_PDEV_GET_TPC_CONFIG_CMDID,
+ .pdev_set_base_macaddr_cmdid = WMI_10_2_PDEV_SET_BASE_MACADDR_CMDID,
+ .vdev_create_cmdid = WMI_10_2_VDEV_CREATE_CMDID,
+ .vdev_delete_cmdid = WMI_10_2_VDEV_DELETE_CMDID,
+ .vdev_start_request_cmdid = WMI_10_2_VDEV_START_REQUEST_CMDID,
+ .vdev_restart_request_cmdid = WMI_10_2_VDEV_RESTART_REQUEST_CMDID,
+ .vdev_up_cmdid = WMI_10_2_VDEV_UP_CMDID,
+ .vdev_stop_cmdid = WMI_10_2_VDEV_STOP_CMDID,
+ .vdev_down_cmdid = WMI_10_2_VDEV_DOWN_CMDID,
+ .vdev_set_param_cmdid = WMI_10_2_VDEV_SET_PARAM_CMDID,
+ .vdev_install_key_cmdid = WMI_10_2_VDEV_INSTALL_KEY_CMDID,
+ .peer_create_cmdid = WMI_10_2_PEER_CREATE_CMDID,
+ .peer_delete_cmdid = WMI_10_2_PEER_DELETE_CMDID,
+ .peer_flush_tids_cmdid = WMI_10_2_PEER_FLUSH_TIDS_CMDID,
+ .peer_set_param_cmdid = WMI_10_2_PEER_SET_PARAM_CMDID,
+ .peer_assoc_cmdid = WMI_10_2_PEER_ASSOC_CMDID,
+ .peer_add_wds_entry_cmdid = WMI_10_2_PEER_ADD_WDS_ENTRY_CMDID,
+ .peer_remove_wds_entry_cmdid = WMI_10_2_PEER_REMOVE_WDS_ENTRY_CMDID,
+ .peer_mcast_group_cmdid = WMI_10_2_PEER_MCAST_GROUP_CMDID,
+ .bcn_tx_cmdid = WMI_10_2_BCN_TX_CMDID,
+ .pdev_send_bcn_cmdid = WMI_10_2_PDEV_SEND_BCN_CMDID,
+ .bcn_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+ .bcn_filter_rx_cmdid = WMI_10_2_BCN_FILTER_RX_CMDID,
+ .prb_req_filter_rx_cmdid = WMI_10_2_PRB_REQ_FILTER_RX_CMDID,
+ .mgmt_tx_cmdid = WMI_10_2_MGMT_TX_CMDID,
+ .prb_tmpl_cmdid = WMI_CMD_UNSUPPORTED,
+ .addba_clear_resp_cmdid = WMI_10_2_ADDBA_CLEAR_RESP_CMDID,
+ .addba_send_cmdid = WMI_10_2_ADDBA_SEND_CMDID,
+ .addba_status_cmdid = WMI_10_2_ADDBA_STATUS_CMDID,
+ .delba_send_cmdid = WMI_10_2_DELBA_SEND_CMDID,
+ .addba_set_resp_cmdid = WMI_10_2_ADDBA_SET_RESP_CMDID,
+ .send_singleamsdu_cmdid = WMI_10_2_SEND_SINGLEAMSDU_CMDID,
+ .sta_powersave_mode_cmdid = WMI_10_2_STA_POWERSAVE_MODE_CMDID,
+ .sta_powersave_param_cmdid = WMI_10_2_STA_POWERSAVE_PARAM_CMDID,
+ .sta_mimo_ps_mode_cmdid = WMI_10_2_STA_MIMO_PS_MODE_CMDID,
+ .pdev_dfs_enable_cmdid = WMI_10_2_PDEV_DFS_ENABLE_CMDID,
+ .pdev_dfs_disable_cmdid = WMI_10_2_PDEV_DFS_DISABLE_CMDID,
+ .roam_scan_mode = WMI_10_2_ROAM_SCAN_MODE,
+ .roam_scan_rssi_threshold = WMI_10_2_ROAM_SCAN_RSSI_THRESHOLD,
+ .roam_scan_period = WMI_10_2_ROAM_SCAN_PERIOD,
+ .roam_scan_rssi_change_threshold =
+ WMI_10_2_ROAM_SCAN_RSSI_CHANGE_THRESHOLD,
+ .roam_ap_profile = WMI_10_2_ROAM_AP_PROFILE,
+ .ofl_scan_add_ap_profile = WMI_10_2_OFL_SCAN_ADD_AP_PROFILE,
+ .ofl_scan_remove_ap_profile = WMI_10_2_OFL_SCAN_REMOVE_AP_PROFILE,
+ .ofl_scan_period = WMI_10_2_OFL_SCAN_PERIOD,
+ .p2p_dev_set_device_info = WMI_10_2_P2P_DEV_SET_DEVICE_INFO,
+ .p2p_dev_set_discoverability = WMI_10_2_P2P_DEV_SET_DISCOVERABILITY,
+ .p2p_go_set_beacon_ie = WMI_10_2_P2P_GO_SET_BEACON_IE,
+ .p2p_go_set_probe_resp_ie = WMI_10_2_P2P_GO_SET_PROBE_RESP_IE,
+ .p2p_set_vendor_ie_data_cmdid = WMI_CMD_UNSUPPORTED,
+ .ap_ps_peer_param_cmdid = WMI_10_2_AP_PS_PEER_PARAM_CMDID,
+ .ap_ps_peer_uapsd_coex_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_rate_retry_sched_cmdid = WMI_10_2_PEER_RATE_RETRY_SCHED_CMDID,
+ .wlan_profile_trigger_cmdid = WMI_10_2_WLAN_PROFILE_TRIGGER_CMDID,
+ .wlan_profile_set_hist_intvl_cmdid =
+ WMI_10_2_WLAN_PROFILE_SET_HIST_INTVL_CMDID,
+ .wlan_profile_get_profile_data_cmdid =
+ WMI_10_2_WLAN_PROFILE_GET_PROFILE_DATA_CMDID,
+ .wlan_profile_enable_profile_id_cmdid =
+ WMI_10_2_WLAN_PROFILE_ENABLE_PROFILE_ID_CMDID,
+ .wlan_profile_list_profile_id_cmdid =
+ WMI_10_2_WLAN_PROFILE_LIST_PROFILE_ID_CMDID,
+ .pdev_suspend_cmdid = WMI_10_2_PDEV_SUSPEND_CMDID,
+ .pdev_resume_cmdid = WMI_10_2_PDEV_RESUME_CMDID,
+ .add_bcn_filter_cmdid = WMI_10_2_ADD_BCN_FILTER_CMDID,
+ .rmv_bcn_filter_cmdid = WMI_10_2_RMV_BCN_FILTER_CMDID,
+ .wow_add_wake_pattern_cmdid = WMI_10_2_WOW_ADD_WAKE_PATTERN_CMDID,
+ .wow_del_wake_pattern_cmdid = WMI_10_2_WOW_DEL_WAKE_PATTERN_CMDID,
+ .wow_enable_disable_wake_event_cmdid =
+ WMI_10_2_WOW_ENABLE_DISABLE_WAKE_EVENT_CMDID,
+ .wow_enable_cmdid = WMI_10_2_WOW_ENABLE_CMDID,
+ .wow_hostwakeup_from_sleep_cmdid =
+ WMI_10_2_WOW_HOSTWAKEUP_FROM_SLEEP_CMDID,
+ .rtt_measreq_cmdid = WMI_10_2_RTT_MEASREQ_CMDID,
+ .rtt_tsf_cmdid = WMI_10_2_RTT_TSF_CMDID,
+ .vdev_spectral_scan_configure_cmdid =
+ WMI_10_2_VDEV_SPECTRAL_SCAN_CONFIGURE_CMDID,
+ .vdev_spectral_scan_enable_cmdid =
+ WMI_10_2_VDEV_SPECTRAL_SCAN_ENABLE_CMDID,
+ .request_stats_cmdid = WMI_10_2_REQUEST_STATS_CMDID,
+ .set_arp_ns_offload_cmdid = WMI_CMD_UNSUPPORTED,
+ .network_list_offload_config_cmdid = WMI_CMD_UNSUPPORTED,
+ .gtk_offload_cmdid = WMI_CMD_UNSUPPORTED,
+ .csa_offload_enable_cmdid = WMI_CMD_UNSUPPORTED,
+ .csa_offload_chanswitch_cmdid = WMI_CMD_UNSUPPORTED,
+ .chatter_set_mode_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_tid_addba_cmdid = WMI_CMD_UNSUPPORTED,
+ .peer_tid_delba_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_dtim_ps_method_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_uapsd_auto_trig_cmdid = WMI_CMD_UNSUPPORTED,
+ .sta_keepalive_cmd = WMI_CMD_UNSUPPORTED,
+ .echo_cmdid = WMI_10_2_ECHO_CMDID,
+ .pdev_utf_cmdid = WMI_10_2_PDEV_UTF_CMDID,
+ .dbglog_cfg_cmdid = WMI_10_2_DBGLOG_CFG_CMDID,
+ .pdev_qvit_cmdid = WMI_10_2_PDEV_QVIT_CMDID,
+ .pdev_ftm_intg_cmdid = WMI_CMD_UNSUPPORTED,
+ .vdev_set_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+ .vdev_get_keepalive_cmdid = WMI_CMD_UNSUPPORTED,
+ .force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
+ .gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
+ .gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
+ .pdev_get_temperature_cmdid = WMI_10_2_PDEV_GET_TEMPERATURE_CMDID,
};
/* MAIN WMI VDEV param map */
@@ -385,6 +511,64 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = {
WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
};
+static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {
+ .rts_threshold = WMI_10X_VDEV_PARAM_RTS_THRESHOLD,
+ .fragmentation_threshold = WMI_10X_VDEV_PARAM_FRAGMENTATION_THRESHOLD,
+ .beacon_interval = WMI_10X_VDEV_PARAM_BEACON_INTERVAL,
+ .listen_interval = WMI_10X_VDEV_PARAM_LISTEN_INTERVAL,
+ .multicast_rate = WMI_10X_VDEV_PARAM_MULTICAST_RATE,
+ .mgmt_tx_rate = WMI_10X_VDEV_PARAM_MGMT_TX_RATE,
+ .slot_time = WMI_10X_VDEV_PARAM_SLOT_TIME,
+ .preamble = WMI_10X_VDEV_PARAM_PREAMBLE,
+ .swba_time = WMI_10X_VDEV_PARAM_SWBA_TIME,
+ .wmi_vdev_stats_update_period = WMI_10X_VDEV_STATS_UPDATE_PERIOD,
+ .wmi_vdev_pwrsave_ageout_time = WMI_10X_VDEV_PWRSAVE_AGEOUT_TIME,
+ .wmi_vdev_host_swba_interval = WMI_10X_VDEV_HOST_SWBA_INTERVAL,
+ .dtim_period = WMI_10X_VDEV_PARAM_DTIM_PERIOD,
+ .wmi_vdev_oc_scheduler_air_time_limit =
+ WMI_10X_VDEV_OC_SCHEDULER_AIR_TIME_LIMIT,
+ .wds = WMI_10X_VDEV_PARAM_WDS,
+ .atim_window = WMI_10X_VDEV_PARAM_ATIM_WINDOW,
+ .bmiss_count_max = WMI_10X_VDEV_PARAM_BMISS_COUNT_MAX,
+ .bmiss_first_bcnt = WMI_VDEV_PARAM_UNSUPPORTED,
+ .bmiss_final_bcnt = WMI_VDEV_PARAM_UNSUPPORTED,
+ .feature_wmm = WMI_10X_VDEV_PARAM_FEATURE_WMM,
+ .chwidth = WMI_10X_VDEV_PARAM_CHWIDTH,
+ .chextoffset = WMI_10X_VDEV_PARAM_CHEXTOFFSET,
+ .disable_htprotection = WMI_10X_VDEV_PARAM_DISABLE_HTPROTECTION,
+ .sta_quickkickout = WMI_10X_VDEV_PARAM_STA_QUICKKICKOUT,
+ .mgmt_rate = WMI_10X_VDEV_PARAM_MGMT_RATE,
+ .protection_mode = WMI_10X_VDEV_PARAM_PROTECTION_MODE,
+ .fixed_rate = WMI_10X_VDEV_PARAM_FIXED_RATE,
+ .sgi = WMI_10X_VDEV_PARAM_SGI,
+ .ldpc = WMI_10X_VDEV_PARAM_LDPC,
+ .tx_stbc = WMI_10X_VDEV_PARAM_TX_STBC,
+ .rx_stbc = WMI_10X_VDEV_PARAM_RX_STBC,
+ .intra_bss_fwd = WMI_10X_VDEV_PARAM_INTRA_BSS_FWD,
+ .def_keyid = WMI_10X_VDEV_PARAM_DEF_KEYID,
+ .nss = WMI_10X_VDEV_PARAM_NSS,
+ .bcast_data_rate = WMI_10X_VDEV_PARAM_BCAST_DATA_RATE,
+ .mcast_data_rate = WMI_10X_VDEV_PARAM_MCAST_DATA_RATE,
+ .mcast_indicate = WMI_10X_VDEV_PARAM_MCAST_INDICATE,
+ .dhcp_indicate = WMI_10X_VDEV_PARAM_DHCP_INDICATE,
+ .unknown_dest_indicate = WMI_10X_VDEV_PARAM_UNKNOWN_DEST_INDICATE,
+ .ap_keepalive_min_idle_inactive_time_secs =
+ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MIN_IDLE_INACTIVE_TIME_SECS,
+ .ap_keepalive_max_idle_inactive_time_secs =
+ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_IDLE_INACTIVE_TIME_SECS,
+ .ap_keepalive_max_unresponsive_time_secs =
+ WMI_10X_VDEV_PARAM_AP_KEEPALIVE_MAX_UNRESPONSIVE_TIME_SECS,
+ .ap_enable_nawds = WMI_10X_VDEV_PARAM_AP_ENABLE_NAWDS,
+ .mcast2ucast_set = WMI_10X_VDEV_PARAM_MCAST2UCAST_SET,
+ .enable_rtscts = WMI_10X_VDEV_PARAM_ENABLE_RTSCTS,
+ .txbf = WMI_VDEV_PARAM_UNSUPPORTED,
+ .packet_powersave = WMI_VDEV_PARAM_UNSUPPORTED,
+ .drop_unencry = WMI_VDEV_PARAM_UNSUPPORTED,
+ .tx_encap_type = WMI_VDEV_PARAM_UNSUPPORTED,
+ .ap_detect_out_of_sync_sleeping_sta_time_secs =
+ WMI_10X_VDEV_PARAM_AP_DETECT_OUT_OF_SYNC_SLEEPING_STA_TIME_SECS,
+};
+
static struct wmi_pdev_param_map wmi_pdev_param_map = {
.tx_chain_mask = WMI_PDEV_PARAM_TX_CHAIN_MASK,
.rx_chain_mask = WMI_PDEV_PARAM_RX_CHAIN_MASK,
@@ -434,6 +618,7 @@ static struct wmi_pdev_param_map wmi_pdev_param_map = {
.fast_channel_reset = WMI_PDEV_PARAM_UNSUPPORTED,
.burst_dur = WMI_PDEV_PARAM_UNSUPPORTED,
.burst_enable = WMI_PDEV_PARAM_UNSUPPORTED,
+ .cal_period = WMI_PDEV_PARAM_UNSUPPORTED,
};
static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
@@ -486,6 +671,60 @@ static struct wmi_pdev_param_map wmi_10x_pdev_param_map = {
.fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET,
.burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,
.burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
+ .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD,
+};
+
+static struct wmi_pdev_param_map wmi_10_2_4_pdev_param_map = {
+ .tx_chain_mask = WMI_10X_PDEV_PARAM_TX_CHAIN_MASK,
+ .rx_chain_mask = WMI_10X_PDEV_PARAM_RX_CHAIN_MASK,
+ .txpower_limit2g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT2G,
+ .txpower_limit5g = WMI_10X_PDEV_PARAM_TXPOWER_LIMIT5G,
+ .txpower_scale = WMI_10X_PDEV_PARAM_TXPOWER_SCALE,
+ .beacon_gen_mode = WMI_10X_PDEV_PARAM_BEACON_GEN_MODE,
+ .beacon_tx_mode = WMI_10X_PDEV_PARAM_BEACON_TX_MODE,
+ .resmgr_offchan_mode = WMI_10X_PDEV_PARAM_RESMGR_OFFCHAN_MODE,
+ .protection_mode = WMI_10X_PDEV_PARAM_PROTECTION_MODE,
+ .dynamic_bw = WMI_10X_PDEV_PARAM_DYNAMIC_BW,
+ .non_agg_sw_retry_th = WMI_10X_PDEV_PARAM_NON_AGG_SW_RETRY_TH,
+ .agg_sw_retry_th = WMI_10X_PDEV_PARAM_AGG_SW_RETRY_TH,
+ .sta_kickout_th = WMI_10X_PDEV_PARAM_STA_KICKOUT_TH,
+ .ac_aggrsize_scaling = WMI_10X_PDEV_PARAM_AC_AGGRSIZE_SCALING,
+ .ltr_enable = WMI_10X_PDEV_PARAM_LTR_ENABLE,
+ .ltr_ac_latency_be = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BE,
+ .ltr_ac_latency_bk = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_BK,
+ .ltr_ac_latency_vi = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VI,
+ .ltr_ac_latency_vo = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_VO,
+ .ltr_ac_latency_timeout = WMI_10X_PDEV_PARAM_LTR_AC_LATENCY_TIMEOUT,
+ .ltr_sleep_override = WMI_10X_PDEV_PARAM_LTR_SLEEP_OVERRIDE,
+ .ltr_rx_override = WMI_10X_PDEV_PARAM_LTR_RX_OVERRIDE,
+ .ltr_tx_activity_timeout = WMI_10X_PDEV_PARAM_LTR_TX_ACTIVITY_TIMEOUT,
+ .l1ss_enable = WMI_10X_PDEV_PARAM_L1SS_ENABLE,
+ .dsleep_enable = WMI_10X_PDEV_PARAM_DSLEEP_ENABLE,
+ .pcielp_txbuf_flush = WMI_PDEV_PARAM_UNSUPPORTED,
+ .pcielp_txbuf_watermark = WMI_PDEV_PARAM_UNSUPPORTED,
+ .pcielp_txbuf_tmo_en = WMI_PDEV_PARAM_UNSUPPORTED,
+ .pcielp_txbuf_tmo_value = WMI_PDEV_PARAM_UNSUPPORTED,
+ .pdev_stats_update_period = WMI_10X_PDEV_PARAM_PDEV_STATS_UPDATE_PERIOD,
+ .vdev_stats_update_period = WMI_10X_PDEV_PARAM_VDEV_STATS_UPDATE_PERIOD,
+ .peer_stats_update_period = WMI_10X_PDEV_PARAM_PEER_STATS_UPDATE_PERIOD,
+ .bcnflt_stats_update_period =
+ WMI_10X_PDEV_PARAM_BCNFLT_STATS_UPDATE_PERIOD,
+ .pmf_qos = WMI_10X_PDEV_PARAM_PMF_QOS,
+ .arp_ac_override = WMI_10X_PDEV_PARAM_ARPDHCP_AC_OVERRIDE,
+ .dcs = WMI_10X_PDEV_PARAM_DCS,
+ .ani_enable = WMI_10X_PDEV_PARAM_ANI_ENABLE,
+ .ani_poll_period = WMI_10X_PDEV_PARAM_ANI_POLL_PERIOD,
+ .ani_listen_period = WMI_10X_PDEV_PARAM_ANI_LISTEN_PERIOD,
+ .ani_ofdm_level = WMI_10X_PDEV_PARAM_ANI_OFDM_LEVEL,
+ .ani_cck_level = WMI_10X_PDEV_PARAM_ANI_CCK_LEVEL,
+ .dyntxchain = WMI_10X_PDEV_PARAM_DYNTXCHAIN,
+ .proxy_sta = WMI_PDEV_PARAM_UNSUPPORTED,
+ .idle_ps_config = WMI_PDEV_PARAM_UNSUPPORTED,
+ .power_gating_sleep = WMI_PDEV_PARAM_UNSUPPORTED,
+ .fast_channel_reset = WMI_10X_PDEV_PARAM_FAST_CHANNEL_RESET,
+ .burst_dur = WMI_10X_PDEV_PARAM_BURST_DUR,
+ .burst_enable = WMI_10X_PDEV_PARAM_BURST_ENABLE,
+ .cal_period = WMI_10X_PDEV_PARAM_CAL_PERIOD,
};
/* firmware 10.2 specific mappings */
@@ -607,11 +846,11 @@ static struct wmi_cmd_map wmi_10_2_cmd_map = {
.force_fw_hang_cmdid = WMI_CMD_UNSUPPORTED,
.gpio_config_cmdid = WMI_10_2_GPIO_CONFIG_CMDID,
.gpio_output_cmdid = WMI_10_2_GPIO_OUTPUT_CMDID,
+ .pdev_get_temperature_cmdid = WMI_CMD_UNSUPPORTED,
};
-static void
-ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
- const struct wmi_channel_arg *arg)
+void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+ const struct wmi_channel_arg *arg)
{
u32 flags = 0;
@@ -685,8 +924,8 @@ static void ath10k_wmi_htc_tx_complete(struct ath10k *ar, struct sk_buff *skb)
dev_kfree_skb(skb);
}
-static int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
- u32 cmd_id)
+int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
+ u32 cmd_id)
{
struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
struct wmi_cmd_hdr *cmd_hdr;
@@ -717,23 +956,45 @@ err_pull:
static void ath10k_wmi_tx_beacon_nowait(struct ath10k_vif *arvif)
{
+ struct ath10k *ar = arvif->ar;
+ struct ath10k_skb_cb *cb;
+ struct sk_buff *bcn;
int ret;
- lockdep_assert_held(&arvif->ar->data_lock);
+ spin_lock_bh(&ar->data_lock);
- if (arvif->beacon == NULL)
- return;
+ bcn = arvif->beacon;
- if (arvif->beacon_sent)
- return;
+ if (!bcn)
+ goto unlock;
- ret = ath10k_wmi_beacon_send_ref_nowait(arvif);
- if (ret)
- return;
+ cb = ATH10K_SKB_CB(bcn);
+
+ switch (arvif->beacon_state) {
+ case ATH10K_BEACON_SENDING:
+ case ATH10K_BEACON_SENT:
+ break;
+ case ATH10K_BEACON_SCHEDULED:
+ arvif->beacon_state = ATH10K_BEACON_SENDING;
+ spin_unlock_bh(&ar->data_lock);
+
+ ret = ath10k_wmi_beacon_send_ref_nowait(arvif->ar,
+ arvif->vdev_id,
+ bcn->data, bcn->len,
+ cb->paddr,
+ cb->bcn.dtim_zero,
+ cb->bcn.deliver_cab);
+
+ spin_lock_bh(&ar->data_lock);
+
+ if (ret == 0)
+ arvif->beacon_state = ATH10K_BEACON_SENT;
+ else
+ arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
+ }
- /* We need to retain the arvif->beacon reference for DMA unmapping and
- * freeing the skbuff later. */
- arvif->beacon_sent = true;
+unlock:
+ spin_unlock_bh(&ar->data_lock);
}
static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
@@ -746,12 +1007,10 @@ static void ath10k_wmi_tx_beacons_iter(void *data, u8 *mac,
static void ath10k_wmi_tx_beacons_nowait(struct ath10k *ar)
{
- spin_lock_bh(&ar->data_lock);
ieee80211_iterate_active_interfaces_atomic(ar->hw,
IEEE80211_IFACE_ITER_NORMAL,
ath10k_wmi_tx_beacons_iter,
NULL);
- spin_unlock_bh(&ar->data_lock);
}
static void ath10k_wmi_op_ep_tx_credits(struct ath10k *ar)
@@ -792,24 +1051,23 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
return ret;
}
-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
+static struct sk_buff *
+ath10k_wmi_op_gen_mgmt_tx(struct ath10k *ar, struct sk_buff *msdu)
{
- int ret = 0;
struct wmi_mgmt_tx_cmd *cmd;
struct ieee80211_hdr *hdr;
- struct sk_buff *wmi_skb;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+ struct sk_buff *skb;
int len;
- u32 buf_len = skb->len;
+ u32 buf_len = msdu->len;
u16 fc;
- hdr = (struct ieee80211_hdr *)skb->data;
+ hdr = (struct ieee80211_hdr *)msdu->data;
fc = le16_to_cpu(hdr->frame_control);
if (WARN_ON_ONCE(!ieee80211_is_mgmt(hdr->frame_control)))
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
- len = sizeof(cmd->hdr) + skb->len;
+ len = sizeof(cmd->hdr) + msdu->len;
if ((ieee80211_is_action(hdr->frame_control) ||
ieee80211_is_deauth(hdr->frame_control) ||
@@ -821,36 +1079,27 @@ int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb)
len = round_up(len, 4);
- wmi_skb = ath10k_wmi_alloc_skb(ar, len);
- if (!wmi_skb)
- return -ENOMEM;
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
- cmd = (struct wmi_mgmt_tx_cmd *)wmi_skb->data;
+ cmd = (struct wmi_mgmt_tx_cmd *)skb->data;
- cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(skb)->vdev_id);
+ cmd->hdr.vdev_id = __cpu_to_le32(ATH10K_SKB_CB(msdu)->vdev_id);
cmd->hdr.tx_rate = 0;
cmd->hdr.tx_power = 0;
cmd->hdr.buf_len = __cpu_to_le32(buf_len);
ether_addr_copy(cmd->hdr.peer_macaddr.addr, ieee80211_get_DA(hdr));
- memcpy(cmd->buf, skb->data, skb->len);
+ memcpy(cmd->buf, msdu->data, msdu->len);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi mgmt tx skb %p len %d ftype %02x stype %02x\n",
- wmi_skb, wmi_skb->len, fc & IEEE80211_FCTL_FTYPE,
+ msdu, skb->len, fc & IEEE80211_FCTL_FTYPE,
fc & IEEE80211_FCTL_STYPE);
trace_ath10k_tx_hdr(ar, skb->data, skb->len);
trace_ath10k_tx_payload(ar, skb->data, skb->len);
- /* Send the management frame buffer to the target */
- ret = ath10k_wmi_cmd_send(ar, wmi_skb, ar->wmi.cmd->mgmt_tx_cmdid);
- if (ret)
- return ret;
-
- /* TODO: report tx status to mac80211 - temporary just ACK */
- info->flags |= IEEE80211_TX_STAT_ACK;
- ieee80211_tx_status_irqsafe(ar->hw, skb);
-
- return ret;
+ return skb;
}
static void ath10k_wmi_event_scan_started(struct ath10k *ar)
@@ -977,22 +1226,48 @@ ath10k_wmi_event_scan_type_str(enum wmi_scan_event_type type,
}
}
-static int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_op_pull_scan_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_scan_ev_arg *arg)
{
- struct wmi_scan_event *event = (struct wmi_scan_event *)skb->data;
+ struct wmi_scan_event *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->event_type = ev->event_type;
+ arg->reason = ev->reason;
+ arg->channel_freq = ev->channel_freq;
+ arg->scan_req_id = ev->scan_req_id;
+ arg->scan_id = ev->scan_id;
+ arg->vdev_id = ev->vdev_id;
+
+ return 0;
+}
+
+int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_scan_ev_arg arg = {};
enum wmi_scan_event_type event_type;
enum wmi_scan_completion_reason reason;
u32 freq;
u32 req_id;
u32 scan_id;
u32 vdev_id;
+ int ret;
+
+ ret = ath10k_wmi_pull_scan(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse scan event: %d\n", ret);
+ return ret;
+ }
- event_type = __le32_to_cpu(event->event_type);
- reason = __le32_to_cpu(event->reason);
- freq = __le32_to_cpu(event->channel_freq);
- req_id = __le32_to_cpu(event->scan_req_id);
- scan_id = __le32_to_cpu(event->scan_id);
- vdev_id = __le32_to_cpu(event->vdev_id);
+ event_type = __le32_to_cpu(arg.event_type);
+ reason = __le32_to_cpu(arg.reason);
+ freq = __le32_to_cpu(arg.channel_freq);
+ req_id = __le32_to_cpu(arg.scan_req_id);
+ scan_id = __le32_to_cpu(arg.scan_id);
+ vdev_id = __le32_to_cpu(arg.vdev_id);
spin_lock_bh(&ar->data_lock);
@@ -1147,11 +1422,51 @@ static void ath10k_wmi_handle_wep_reauth(struct ath10k *ar,
}
}
-static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_mgmt_rx_ev_arg *arg)
{
struct wmi_mgmt_rx_event_v1 *ev_v1;
struct wmi_mgmt_rx_event_v2 *ev_v2;
struct wmi_mgmt_rx_hdr_v1 *ev_hdr;
+ size_t pull_len;
+ u32 msdu_len;
+
+ if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
+ ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
+ ev_hdr = &ev_v2->hdr.v1;
+ pull_len = sizeof(*ev_v2);
+ } else {
+ ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
+ ev_hdr = &ev_v1->hdr;
+ pull_len = sizeof(*ev_v1);
+ }
+
+ if (skb->len < pull_len)
+ return -EPROTO;
+
+ skb_pull(skb, pull_len);
+ arg->channel = ev_hdr->channel;
+ arg->buf_len = ev_hdr->buf_len;
+ arg->status = ev_hdr->status;
+ arg->snr = ev_hdr->snr;
+ arg->phy_mode = ev_hdr->phy_mode;
+ arg->rate = ev_hdr->rate;
+
+ msdu_len = __le32_to_cpu(arg->buf_len);
+ if (skb->len < msdu_len)
+ return -EPROTO;
+
+ /* the WMI buffer might've ended up being padded to 4 bytes due to HTC
+ * trailer with credit update. Trim the excess garbage.
+ */
+ skb_trim(skb, msdu_len);
+
+ return 0;
+}
+
+int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_mgmt_rx_ev_arg arg = {};
struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
struct ieee80211_hdr *hdr;
u32 rx_status;
@@ -1161,24 +1476,20 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
u32 rate;
u32 buf_len;
u16 fc;
- int pull_len;
+ int ret;
- if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
- ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
- ev_hdr = &ev_v2->hdr.v1;
- pull_len = sizeof(*ev_v2);
- } else {
- ev_v1 = (struct wmi_mgmt_rx_event_v1 *)skb->data;
- ev_hdr = &ev_v1->hdr;
- pull_len = sizeof(*ev_v1);
+ ret = ath10k_wmi_pull_mgmt_rx(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse mgmt rx event: %d\n", ret);
+ return ret;
}
- channel = __le32_to_cpu(ev_hdr->channel);
- buf_len = __le32_to_cpu(ev_hdr->buf_len);
- rx_status = __le32_to_cpu(ev_hdr->status);
- snr = __le32_to_cpu(ev_hdr->snr);
- phy_mode = __le32_to_cpu(ev_hdr->phy_mode);
- rate = __le32_to_cpu(ev_hdr->rate);
+ channel = __le32_to_cpu(arg.channel);
+ buf_len = __le32_to_cpu(arg.buf_len);
+ rx_status = __le32_to_cpu(arg.status);
+ snr = __le32_to_cpu(arg.snr);
+ phy_mode = __le32_to_cpu(arg.phy_mode);
+ rate = __le32_to_cpu(arg.rate);
memset(status, 0, sizeof(*status));
@@ -1232,8 +1543,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
status->signal = snr + ATH10K_DEFAULT_NOISE_FLOOR;
status->rate_idx = get_rate_idx(rate, status->band);
- skb_pull(skb, pull_len);
-
hdr = (struct ieee80211_hdr *)skb->data;
fc = le16_to_cpu(hdr->frame_control);
@@ -1266,12 +1575,6 @@ static int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb)
status->freq, status->band, status->signal,
status->rate_idx);
- /*
- * packets from HTC come aligned to 4byte boundaries
- * because they can originally come in along with a trailer
- */
- skb_trim(skb, buf_len);
-
ieee80211_rx(ar->hw, skb);
return 0;
}
@@ -1295,21 +1598,44 @@ exit:
return idx;
}
-static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_op_pull_ch_info_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_ch_info_ev_arg *arg)
{
- struct wmi_chan_info_event *ev;
+ struct wmi_chan_info_event *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->err_code = ev->err_code;
+ arg->freq = ev->freq;
+ arg->cmd_flags = ev->cmd_flags;
+ arg->noise_floor = ev->noise_floor;
+ arg->rx_clear_count = ev->rx_clear_count;
+ arg->cycle_count = ev->cycle_count;
+
+ return 0;
+}
+
+void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_ch_info_ev_arg arg = {};
struct survey_info *survey;
u32 err_code, freq, cmd_flags, noise_floor, rx_clear_count, cycle_count;
- int idx;
+ int idx, ret;
- ev = (struct wmi_chan_info_event *)skb->data;
+ ret = ath10k_wmi_pull_ch_info(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse chan info event: %d\n", ret);
+ return;
+ }
- err_code = __le32_to_cpu(ev->err_code);
- freq = __le32_to_cpu(ev->freq);
- cmd_flags = __le32_to_cpu(ev->cmd_flags);
- noise_floor = __le32_to_cpu(ev->noise_floor);
- rx_clear_count = __le32_to_cpu(ev->rx_clear_count);
- cycle_count = __le32_to_cpu(ev->cycle_count);
+ err_code = __le32_to_cpu(arg.err_code);
+ freq = __le32_to_cpu(arg.freq);
+ cmd_flags = __le32_to_cpu(arg.cmd_flags);
+ noise_floor = __le32_to_cpu(arg.noise_floor);
+ rx_clear_count = __le32_to_cpu(arg.rx_clear_count);
+ cycle_count = __le32_to_cpu(arg.cycle_count);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"chan info err_code %d freq %d cmd_flags %d noise_floor %d rx_clear_count %d cycle_count %d\n",
@@ -1344,11 +1670,11 @@ static void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb)
rx_clear_count -= ar->survey_last_rx_clear_count;
survey = &ar->survey[idx];
- survey->channel_time = WMI_CHAN_INFO_MSEC(cycle_count);
- survey->channel_time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
+ survey->time = WMI_CHAN_INFO_MSEC(cycle_count);
+ survey->time_rx = WMI_CHAN_INFO_MSEC(rx_clear_count);
survey->noise = noise_floor;
- survey->filled = SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_RX |
+ survey->filled = SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_RX |
SURVEY_INFO_NOISE_DBM;
}
@@ -1359,12 +1685,12 @@ exit:
spin_unlock_bh(&ar->data_lock);
}
-static void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ECHO_EVENTID\n");
}
-static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
+int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event debug mesg len %d\n",
skb->len);
@@ -1374,12 +1700,9 @@ static int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb)
return 0;
}
-static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
- struct ath10k_fw_stats_pdev *dst)
+void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
+ struct ath10k_fw_stats_pdev *dst)
{
- const struct wal_dbg_tx_stats *tx = &src->wal.tx;
- const struct wal_dbg_rx_stats *rx = &src->wal.rx;
-
dst->ch_noise_floor = __le32_to_cpu(src->chan_nf);
dst->tx_frame_count = __le32_to_cpu(src->tx_frame_count);
dst->rx_frame_count = __le32_to_cpu(src->rx_frame_count);
@@ -1387,57 +1710,76 @@ static void ath10k_wmi_pull_pdev_stats(const struct wmi_pdev_stats *src,
dst->cycle_count = __le32_to_cpu(src->cycle_count);
dst->phy_err_count = __le32_to_cpu(src->phy_err_count);
dst->chan_tx_power = __le32_to_cpu(src->chan_tx_pwr);
+}
- dst->comp_queued = __le32_to_cpu(tx->comp_queued);
- dst->comp_delivered = __le32_to_cpu(tx->comp_delivered);
- dst->msdu_enqued = __le32_to_cpu(tx->msdu_enqued);
- dst->mpdu_enqued = __le32_to_cpu(tx->mpdu_enqued);
- dst->wmm_drop = __le32_to_cpu(tx->wmm_drop);
- dst->local_enqued = __le32_to_cpu(tx->local_enqued);
- dst->local_freed = __le32_to_cpu(tx->local_freed);
- dst->hw_queued = __le32_to_cpu(tx->hw_queued);
- dst->hw_reaped = __le32_to_cpu(tx->hw_reaped);
- dst->underrun = __le32_to_cpu(tx->underrun);
- dst->tx_abort = __le32_to_cpu(tx->tx_abort);
- dst->mpdus_requed = __le32_to_cpu(tx->mpdus_requed);
- dst->tx_ko = __le32_to_cpu(tx->tx_ko);
- dst->data_rc = __le32_to_cpu(tx->data_rc);
- dst->self_triggers = __le32_to_cpu(tx->self_triggers);
- dst->sw_retry_failure = __le32_to_cpu(tx->sw_retry_failure);
- dst->illgl_rate_phy_err = __le32_to_cpu(tx->illgl_rate_phy_err);
- dst->pdev_cont_xretry = __le32_to_cpu(tx->pdev_cont_xretry);
- dst->pdev_tx_timeout = __le32_to_cpu(tx->pdev_tx_timeout);
- dst->pdev_resets = __le32_to_cpu(tx->pdev_resets);
- dst->phy_underrun = __le32_to_cpu(tx->phy_underrun);
- dst->txop_ovf = __le32_to_cpu(tx->txop_ovf);
-
- dst->mid_ppdu_route_change = __le32_to_cpu(rx->mid_ppdu_route_change);
- dst->status_rcvd = __le32_to_cpu(rx->status_rcvd);
- dst->r0_frags = __le32_to_cpu(rx->r0_frags);
- dst->r1_frags = __le32_to_cpu(rx->r1_frags);
- dst->r2_frags = __le32_to_cpu(rx->r2_frags);
- dst->r3_frags = __le32_to_cpu(rx->r3_frags);
- dst->htt_msdus = __le32_to_cpu(rx->htt_msdus);
- dst->htt_mpdus = __le32_to_cpu(rx->htt_mpdus);
- dst->loc_msdus = __le32_to_cpu(rx->loc_msdus);
- dst->loc_mpdus = __le32_to_cpu(rx->loc_mpdus);
- dst->oversize_amsdu = __le32_to_cpu(rx->oversize_amsdu);
- dst->phy_errs = __le32_to_cpu(rx->phy_errs);
- dst->phy_err_drop = __le32_to_cpu(rx->phy_err_drop);
- dst->mpdu_errs = __le32_to_cpu(rx->mpdu_errs);
-}
-
-static void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
- struct ath10k_fw_stats_peer *dst)
+void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
+ struct ath10k_fw_stats_pdev *dst)
+{
+ dst->comp_queued = __le32_to_cpu(src->comp_queued);
+ dst->comp_delivered = __le32_to_cpu(src->comp_delivered);
+ dst->msdu_enqued = __le32_to_cpu(src->msdu_enqued);
+ dst->mpdu_enqued = __le32_to_cpu(src->mpdu_enqued);
+ dst->wmm_drop = __le32_to_cpu(src->wmm_drop);
+ dst->local_enqued = __le32_to_cpu(src->local_enqued);
+ dst->local_freed = __le32_to_cpu(src->local_freed);
+ dst->hw_queued = __le32_to_cpu(src->hw_queued);
+ dst->hw_reaped = __le32_to_cpu(src->hw_reaped);
+ dst->underrun = __le32_to_cpu(src->underrun);
+ dst->tx_abort = __le32_to_cpu(src->tx_abort);
+ dst->mpdus_requed = __le32_to_cpu(src->mpdus_requed);
+ dst->tx_ko = __le32_to_cpu(src->tx_ko);
+ dst->data_rc = __le32_to_cpu(src->data_rc);
+ dst->self_triggers = __le32_to_cpu(src->self_triggers);
+ dst->sw_retry_failure = __le32_to_cpu(src->sw_retry_failure);
+ dst->illgl_rate_phy_err = __le32_to_cpu(src->illgl_rate_phy_err);
+ dst->pdev_cont_xretry = __le32_to_cpu(src->pdev_cont_xretry);
+ dst->pdev_tx_timeout = __le32_to_cpu(src->pdev_tx_timeout);
+ dst->pdev_resets = __le32_to_cpu(src->pdev_resets);
+ dst->phy_underrun = __le32_to_cpu(src->phy_underrun);
+ dst->txop_ovf = __le32_to_cpu(src->txop_ovf);
+}
+
+void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src,
+ struct ath10k_fw_stats_pdev *dst)
+{
+ dst->mid_ppdu_route_change = __le32_to_cpu(src->mid_ppdu_route_change);
+ dst->status_rcvd = __le32_to_cpu(src->status_rcvd);
+ dst->r0_frags = __le32_to_cpu(src->r0_frags);
+ dst->r1_frags = __le32_to_cpu(src->r1_frags);
+ dst->r2_frags = __le32_to_cpu(src->r2_frags);
+ dst->r3_frags = __le32_to_cpu(src->r3_frags);
+ dst->htt_msdus = __le32_to_cpu(src->htt_msdus);
+ dst->htt_mpdus = __le32_to_cpu(src->htt_mpdus);
+ dst->loc_msdus = __le32_to_cpu(src->loc_msdus);
+ dst->loc_mpdus = __le32_to_cpu(src->loc_mpdus);
+ dst->oversize_amsdu = __le32_to_cpu(src->oversize_amsdu);
+ dst->phy_errs = __le32_to_cpu(src->phy_errs);
+ dst->phy_err_drop = __le32_to_cpu(src->phy_err_drop);
+ dst->mpdu_errs = __le32_to_cpu(src->mpdu_errs);
+}
+
+void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src,
+ struct ath10k_fw_stats_pdev *dst)
+{
+ dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad);
+ dst->rts_bad = __le32_to_cpu(src->rts_bad);
+ dst->rts_good = __le32_to_cpu(src->rts_good);
+ dst->fcs_bad = __le32_to_cpu(src->fcs_bad);
+ dst->no_beacons = __le32_to_cpu(src->no_beacons);
+ dst->mib_int_count = __le32_to_cpu(src->mib_int_count);
+}
+
+void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
+ struct ath10k_fw_stats_peer *dst)
{
ether_addr_copy(dst->peer_macaddr, src->peer_macaddr.addr);
dst->peer_rssi = __le32_to_cpu(src->peer_rssi);
dst->peer_tx_rate = __le32_to_cpu(src->peer_tx_rate);
}
-static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
- struct sk_buff *skb,
- struct ath10k_fw_stats *stats)
+static int ath10k_wmi_main_op_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
{
const struct wmi_stats_event *ev = (void *)skb->data;
u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
@@ -1462,7 +1804,10 @@ static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
if (!dst)
continue;
- ath10k_wmi_pull_pdev_stats(src, dst);
+ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
+ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
+ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+
list_add_tail(&dst->list, &stats->pdevs);
}
@@ -1487,9 +1832,9 @@ static int ath10k_wmi_main_pull_fw_stats(struct ath10k *ar,
return 0;
}
-static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
- struct sk_buff *skb,
- struct ath10k_fw_stats *stats)
+static int ath10k_wmi_10x_op_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
{
const struct wmi_stats_event *ev = (void *)skb->data;
u32 num_pdev_stats, num_vdev_stats, num_peer_stats;
@@ -1514,14 +1859,10 @@ static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
if (!dst)
continue;
- ath10k_wmi_pull_pdev_stats(&src->old, dst);
-
- dst->ack_rx_bad = __le32_to_cpu(src->ack_rx_bad);
- dst->rts_bad = __le32_to_cpu(src->rts_bad);
- dst->rts_good = __le32_to_cpu(src->rts_good);
- dst->fcs_bad = __le32_to_cpu(src->fcs_bad);
- dst->no_beacons = __le32_to_cpu(src->no_beacons);
- dst->mib_int_count = __le32_to_cpu(src->mib_int_count);
+ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
+ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
+ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
list_add_tail(&dst->list, &stats->pdevs);
}
@@ -1550,61 +1891,250 @@ static int ath10k_wmi_10x_pull_fw_stats(struct ath10k *ar,
return 0;
}
-int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
- struct ath10k_fw_stats *stats)
+static int ath10k_wmi_10_2_op_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- return ath10k_wmi_10x_pull_fw_stats(ar, skb, stats);
- else
- return ath10k_wmi_main_pull_fw_stats(ar, skb, stats);
+ const struct wmi_10_2_stats_event *ev = (void *)skb->data;
+ u32 num_pdev_stats;
+ u32 num_pdev_ext_stats;
+ u32 num_vdev_stats;
+ u32 num_peer_stats;
+ int i;
+
+ if (!skb_pull(skb, sizeof(*ev)))
+ return -EPROTO;
+
+ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
+ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+ for (i = 0; i < num_pdev_stats; i++) {
+ const struct wmi_10_2_pdev_stats *src;
+ struct ath10k_fw_stats_pdev *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
+ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
+ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
+ /* FIXME: expose 10.2 specific values */
+
+ list_add_tail(&dst->list, &stats->pdevs);
+ }
+
+ for (i = 0; i < num_pdev_ext_stats; i++) {
+ const struct wmi_10_2_pdev_ext_stats *src;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ /* FIXME: expose values to userspace
+ *
+ * Note: Even though this loop seems to do nothing it is
+ * required to parse following sub-structures properly.
+ */
+ }
+
+ /* fw doesn't implement vdev stats */
+
+ for (i = 0; i < num_peer_stats; i++) {
+ const struct wmi_10_2_peer_stats *src;
+ struct ath10k_fw_stats_peer *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_peer_stats(&src->old, dst);
+
+ dst->peer_rx_rate = __le32_to_cpu(src->peer_rx_rate);
+ /* FIXME: expose 10.2 specific values */
+
+ list_add_tail(&dst->list, &stats->peers);
+ }
+
+ return 0;
+}
+
+static int ath10k_wmi_10_2_4_op_pull_fw_stats(struct ath10k *ar,
+ struct sk_buff *skb,
+ struct ath10k_fw_stats *stats)
+{
+ const struct wmi_10_2_stats_event *ev = (void *)skb->data;
+ u32 num_pdev_stats;
+ u32 num_pdev_ext_stats;
+ u32 num_vdev_stats;
+ u32 num_peer_stats;
+ int i;
+
+ if (!skb_pull(skb, sizeof(*ev)))
+ return -EPROTO;
+
+ num_pdev_stats = __le32_to_cpu(ev->num_pdev_stats);
+ num_pdev_ext_stats = __le32_to_cpu(ev->num_pdev_ext_stats);
+ num_vdev_stats = __le32_to_cpu(ev->num_vdev_stats);
+ num_peer_stats = __le32_to_cpu(ev->num_peer_stats);
+
+ for (i = 0; i < num_pdev_stats; i++) {
+ const struct wmi_10_2_pdev_stats *src;
+ struct ath10k_fw_stats_pdev *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_pdev_stats_base(&src->base, dst);
+ ath10k_wmi_pull_pdev_stats_tx(&src->tx, dst);
+ ath10k_wmi_pull_pdev_stats_rx(&src->rx, dst);
+ ath10k_wmi_pull_pdev_stats_extra(&src->extra, dst);
+ /* FIXME: expose 10.2 specific values */
+
+ list_add_tail(&dst->list, &stats->pdevs);
+ }
+
+ for (i = 0; i < num_pdev_ext_stats; i++) {
+ const struct wmi_10_2_pdev_ext_stats *src;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ /* FIXME: expose values to userspace
+ *
+ * Note: Even though this loop seems to do nothing it is
+ * required to parse following sub-structures properly.
+ */
+ }
+
+ /* fw doesn't implement vdev stats */
+
+ for (i = 0; i < num_peer_stats; i++) {
+ const struct wmi_10_2_4_peer_stats *src;
+ struct ath10k_fw_stats_peer *dst;
+
+ src = (void *)skb->data;
+ if (!skb_pull(skb, sizeof(*src)))
+ return -EPROTO;
+
+ dst = kzalloc(sizeof(*dst), GFP_ATOMIC);
+ if (!dst)
+ continue;
+
+ ath10k_wmi_pull_peer_stats(&src->common.old, dst);
+
+ dst->peer_rx_rate = __le32_to_cpu(src->common.peer_rx_rate);
+ /* FIXME: expose 10.2 specific values */
+
+ list_add_tail(&dst->list, &stats->peers);
+ }
+
+ return 0;
}
-static void ath10k_wmi_event_update_stats(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_UPDATE_STATS_EVENTID\n");
ath10k_debug_fw_stats_process(ar, skb);
}
-static void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar,
- struct sk_buff *skb)
+static int
+ath10k_wmi_op_pull_vdev_start_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_vdev_start_ev_arg *arg)
+{
+ struct wmi_vdev_start_response_event *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->vdev_id = ev->vdev_id;
+ arg->req_id = ev->req_id;
+ arg->resp_type = ev->resp_type;
+ arg->status = ev->status;
+
+ return 0;
+}
+
+void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb)
{
- struct wmi_vdev_start_response_event *ev;
+ struct wmi_vdev_start_ev_arg arg = {};
+ int ret;
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_START_RESP_EVENTID\n");
- ev = (struct wmi_vdev_start_response_event *)skb->data;
+ ret = ath10k_wmi_pull_vdev_start(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse vdev start event: %d\n", ret);
+ return;
+ }
- if (WARN_ON(__le32_to_cpu(ev->status)))
+ if (WARN_ON(__le32_to_cpu(arg.status)))
return;
complete(&ar->vdev_setup_done);
}
-static void ath10k_wmi_event_vdev_stopped(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STOPPED_EVENTID\n");
complete(&ar->vdev_setup_done);
}
-static void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar,
- struct sk_buff *skb)
+static int
+ath10k_wmi_op_pull_peer_kick_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_peer_kick_ev_arg *arg)
{
- struct wmi_peer_sta_kickout_event *ev;
+ struct wmi_peer_sta_kickout_event *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->mac_addr = ev->peer_macaddr.addr;
+
+ return 0;
+}
+
+void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_peer_kick_ev_arg arg = {};
struct ieee80211_sta *sta;
+ int ret;
- ev = (struct wmi_peer_sta_kickout_event *)skb->data;
+ ret = ath10k_wmi_pull_peer_kick(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse peer kickout event: %d\n",
+ ret);
+ return;
+ }
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi event peer sta kickout %pM\n",
- ev->peer_macaddr.addr);
+ arg.mac_addr);
rcu_read_lock();
- sta = ieee80211_find_sta_by_ifaddr(ar->hw, ev->peer_macaddr.addr, NULL);
+ sta = ieee80211_find_sta_by_ifaddr(ar->hw, arg.mac_addr, NULL);
if (!sta) {
ath10k_warn(ar, "Spurious quick kickout for STA %pM\n",
- ev->peer_macaddr.addr);
+ arg.mac_addr);
goto exit;
}
@@ -1641,7 +2171,7 @@ exit:
static void ath10k_wmi_update_tim(struct ath10k *ar,
struct ath10k_vif *arvif,
struct sk_buff *bcn,
- struct wmi_bcn_info *bcn_info)
+ const struct wmi_tim_info *tim_info)
{
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)bcn->data;
struct ieee80211_tim_ie *tim;
@@ -1652,14 +2182,14 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
/* if next SWBA has no tim_changed the tim_bitmap is garbage.
* we must copy the bitmap upon change and reuse it later */
- if (__le32_to_cpu(bcn_info->tim_info.tim_changed)) {
+ if (__le32_to_cpu(tim_info->tim_changed)) {
int i;
BUILD_BUG_ON(sizeof(arvif->u.ap.tim_bitmap) !=
- sizeof(bcn_info->tim_info.tim_bitmap));
+ sizeof(tim_info->tim_bitmap));
for (i = 0; i < sizeof(arvif->u.ap.tim_bitmap); i++) {
- t = bcn_info->tim_info.tim_bitmap[i / 4];
+ t = tim_info->tim_bitmap[i / 4];
v = __le32_to_cpu(t);
arvif->u.ap.tim_bitmap[i] = (v >> ((i % 4) * 8)) & 0xFF;
}
@@ -1711,13 +2241,13 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
return;
}
- tim->bitmap_ctrl = !!__le32_to_cpu(bcn_info->tim_info.tim_mcast);
+ tim->bitmap_ctrl = !!__le32_to_cpu(tim_info->tim_mcast);
memcpy(tim->virtual_map, arvif->u.ap.tim_bitmap, pvm_len);
if (tim->dtim_count == 0) {
ATH10K_SKB_CB(bcn)->bcn.dtim_zero = true;
- if (__le32_to_cpu(bcn_info->tim_info.tim_mcast) == 1)
+ if (__le32_to_cpu(tim_info->tim_mcast) == 1)
ATH10K_SKB_CB(bcn)->bcn.deliver_cab = true;
}
@@ -1727,7 +2257,7 @@ static void ath10k_wmi_update_tim(struct ath10k *ar,
}
static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
- struct wmi_p2p_noa_info *noa)
+ const struct wmi_p2p_noa_info *noa)
{
struct ieee80211_p2p_noa_attr *noa_attr;
u8 ctwindow_oppps = noa->ctwindow_oppps;
@@ -1769,7 +2299,7 @@ static void ath10k_p2p_fill_noa_ie(u8 *data, u32 len,
*noa_attr_len = __cpu_to_le16(attr_len);
}
-static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa)
+static u32 ath10k_p2p_calc_noa_ie_len(const struct wmi_p2p_noa_info *noa)
{
u32 len = 0;
u8 noa_descriptors = noa->num_descriptors;
@@ -1789,9 +2319,8 @@ static u32 ath10k_p2p_calc_noa_ie_len(struct wmi_p2p_noa_info *noa)
static void ath10k_wmi_update_noa(struct ath10k *ar, struct ath10k_vif *arvif,
struct sk_buff *bcn,
- struct wmi_bcn_info *bcn_info)
+ const struct wmi_p2p_noa_info *noa)
{
- struct wmi_p2p_noa_info *noa = &bcn_info->p2p_noa_info;
u8 *new_data, *old_data = arvif->u.ap.noa_data;
u32 new_len;
@@ -1832,22 +2361,59 @@ cleanup:
kfree(old_data);
}
-static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_op_pull_swba_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_swba_ev_arg *arg)
{
- struct wmi_host_swba_event *ev;
+ struct wmi_host_swba_event *ev = (void *)skb->data;
+ u32 map;
+ size_t i;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ skb_pull(skb, sizeof(*ev));
+ arg->vdev_map = ev->vdev_map;
+
+ for (i = 0, map = __le32_to_cpu(ev->vdev_map); map; map >>= 1) {
+ if (!(map & BIT(0)))
+ continue;
+
+ /* If this happens there were some changes in firmware and
+ * ath10k should update the max size of tim_info array.
+ */
+ if (WARN_ON_ONCE(i == ARRAY_SIZE(arg->tim_info)))
+ break;
+
+ arg->tim_info[i] = &ev->bcn_info[i].tim_info;
+ arg->noa_info[i] = &ev->bcn_info[i].p2p_noa_info;
+ i++;
+ }
+
+ return 0;
+}
+
+void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_swba_ev_arg arg = {};
u32 map;
int i = -1;
- struct wmi_bcn_info *bcn_info;
+ const struct wmi_tim_info *tim_info;
+ const struct wmi_p2p_noa_info *noa_info;
struct ath10k_vif *arvif;
struct sk_buff *bcn;
dma_addr_t paddr;
int ret, vdev_id = 0;
- ev = (struct wmi_host_swba_event *)skb->data;
- map = __le32_to_cpu(ev->vdev_map);
+ ret = ath10k_wmi_pull_swba(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse swba event: %d\n", ret);
+ return;
+ }
+
+ map = __le32_to_cpu(arg.vdev_map);
ath10k_dbg(ar, ATH10K_DBG_MGMT, "mgmt swba vdev_map 0x%x\n",
- ev->vdev_map);
+ map);
for (; map; map >>= 1, vdev_id++) {
if (!(map & 0x1))
@@ -1860,19 +2426,20 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
break;
}
- bcn_info = &ev->bcn_info[i];
+ tim_info = arg.tim_info[i];
+ noa_info = arg.noa_info[i];
ath10k_dbg(ar, ATH10K_DBG_MGMT,
"mgmt event bcn_info %d tim_len %d mcast %d changed %d num_ps_pending %d bitmap 0x%08x%08x%08x%08x\n",
i,
- __le32_to_cpu(bcn_info->tim_info.tim_len),
- __le32_to_cpu(bcn_info->tim_info.tim_mcast),
- __le32_to_cpu(bcn_info->tim_info.tim_changed),
- __le32_to_cpu(bcn_info->tim_info.tim_num_ps_pending),
- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[3]),
- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[2]),
- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[1]),
- __le32_to_cpu(bcn_info->tim_info.tim_bitmap[0]));
+ __le32_to_cpu(tim_info->tim_len),
+ __le32_to_cpu(tim_info->tim_mcast),
+ __le32_to_cpu(tim_info->tim_changed),
+ __le32_to_cpu(tim_info->tim_num_ps_pending),
+ __le32_to_cpu(tim_info->tim_bitmap[3]),
+ __le32_to_cpu(tim_info->tim_bitmap[2]),
+ __le32_to_cpu(tim_info->tim_bitmap[1]),
+ __le32_to_cpu(tim_info->tim_bitmap[0]));
arvif = ath10k_get_arvif(ar, vdev_id);
if (arvif == NULL) {
@@ -1899,15 +2466,25 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
}
ath10k_tx_h_seq_no(arvif->vif, bcn);
- ath10k_wmi_update_tim(ar, arvif, bcn, bcn_info);
- ath10k_wmi_update_noa(ar, arvif, bcn, bcn_info);
+ ath10k_wmi_update_tim(ar, arvif, bcn, tim_info);
+ ath10k_wmi_update_noa(ar, arvif, bcn, noa_info);
spin_lock_bh(&ar->data_lock);
if (arvif->beacon) {
- if (!arvif->beacon_sent)
- ath10k_warn(ar, "SWBA overrun on vdev %d\n",
+ switch (arvif->beacon_state) {
+ case ATH10K_BEACON_SENT:
+ break;
+ case ATH10K_BEACON_SCHEDULED:
+ ath10k_warn(ar, "SWBA overrun on vdev %d, skipped old beacon\n",
+ arvif->vdev_id);
+ break;
+ case ATH10K_BEACON_SENDING:
+ ath10k_warn(ar, "SWBA overrun on vdev %d, skipped new beacon\n",
arvif->vdev_id);
+ dev_kfree_skb(bcn);
+ goto skip;
+ }
ath10k_mac_vif_beacon_free(arvif);
}
@@ -1935,19 +2512,19 @@ static void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb)
}
arvif->beacon = bcn;
- arvif->beacon_sent = false;
+ arvif->beacon_state = ATH10K_BEACON_SCHEDULED;
trace_ath10k_tx_hdr(ar, bcn->data, bcn->len);
trace_ath10k_tx_payload(ar, bcn->data, bcn->len);
- ath10k_wmi_tx_beacon_nowait(arvif);
skip:
spin_unlock_bh(&ar->data_lock);
}
+
+ ath10k_wmi_tx_beacons_nowait(ar);
}
-static void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TBTTOFFSET_UPDATE_EVENTID\n");
}
@@ -2068,9 +2645,9 @@ static int ath10k_dfs_fft_report(struct ath10k *ar,
return 0;
}
-static void ath10k_wmi_event_dfs(struct ath10k *ar,
- const struct wmi_phyerr *phyerr,
- u64 tsf)
+void ath10k_wmi_event_dfs(struct ath10k *ar,
+ const struct wmi_phyerr *phyerr,
+ u64 tsf)
{
int buf_len, tlv_len, res, i = 0;
const struct phyerr_tlv *tlv;
@@ -2133,10 +2710,9 @@ static void ath10k_wmi_event_dfs(struct ath10k *ar,
}
}
-static void
-ath10k_wmi_event_spectral_scan(struct ath10k *ar,
- const struct wmi_phyerr *phyerr,
- u64 tsf)
+void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
+ const struct wmi_phyerr *phyerr,
+ u64 tsf)
{
int buf_len, tlv_len, res, i = 0;
struct phyerr_tlv *tlv;
@@ -2188,37 +2764,53 @@ ath10k_wmi_event_spectral_scan(struct ath10k *ar,
}
}
-static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_op_pull_phyerr_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_phyerr_ev_arg *arg)
{
- const struct wmi_phyerr_event *ev;
+ struct wmi_phyerr_event *ev = (void *)skb->data;
+
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
+
+ arg->num_phyerrs = ev->num_phyerrs;
+ arg->tsf_l32 = ev->tsf_l32;
+ arg->tsf_u32 = ev->tsf_u32;
+ arg->buf_len = __cpu_to_le32(skb->len - sizeof(*ev));
+ arg->phyerrs = ev->phyerrs;
+
+ return 0;
+}
+
+void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_phyerr_ev_arg arg = {};
const struct wmi_phyerr *phyerr;
u32 count, i, buf_len, phy_err_code;
u64 tsf;
- int left_len = skb->len;
+ int left_len, ret;
ATH10K_DFS_STAT_INC(ar, phy_errors);
- /* Check if combined event available */
- if (left_len < sizeof(*ev)) {
- ath10k_warn(ar, "wmi phyerr combined event wrong len\n");
+ ret = ath10k_wmi_pull_phyerr(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse phyerr event: %d\n", ret);
return;
}
- left_len -= sizeof(*ev);
+ left_len = __le32_to_cpu(arg.buf_len);
/* Check number of included events */
- ev = (const struct wmi_phyerr_event *)skb->data;
- count = __le32_to_cpu(ev->num_phyerrs);
+ count = __le32_to_cpu(arg.num_phyerrs);
- tsf = __le32_to_cpu(ev->tsf_u32);
+ tsf = __le32_to_cpu(arg.tsf_u32);
tsf <<= 32;
- tsf |= __le32_to_cpu(ev->tsf_l32);
+ tsf |= __le32_to_cpu(arg.tsf_l32);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi event phyerr count %d tsf64 0x%llX\n",
count, tsf);
- phyerr = ev->phyerrs;
+ phyerr = arg.phyerrs;
for (i = 0; i < count; i++) {
/* Check if we can read event header */
if (left_len < sizeof(*phyerr)) {
@@ -2258,19 +2850,17 @@ static void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb)
}
}
-static void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_ROAM_EVENTID\n");
}
-static void ath10k_wmi_event_profile_match(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PROFILE_MATCH\n");
}
-static void ath10k_wmi_event_debug_print(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb)
{
char buf[101], c;
int i;
@@ -2303,103 +2893,90 @@ static void ath10k_wmi_event_debug_print(struct ath10k *ar,
ath10k_dbg(ar, ATH10K_DBG_WMI_PRINT, "wmi print '%s'\n", buf);
}
-static void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
+void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_QVIT_EVENTID\n");
}
-static void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WLAN_PROFILE_DATA_EVENTID\n");
}
-static void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
+ struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_MEASUREMENT_REPORT_EVENTID\n");
}
-static void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
+ struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TSF_MEASUREMENT_REPORT_EVENTID\n");
}
-static void ath10k_wmi_event_rtt_error_report(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_RTT_ERROR_REPORT_EVENTID\n");
}
-static void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_WOW_WAKEUP_HOST_EVENTID\n");
}
-static void ath10k_wmi_event_dcs_interference(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_DCS_INTERFERENCE_EVENTID\n");
}
-static void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_TPC_CONFIG_EVENTID\n");
}
-static void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_PDEV_FTM_INTG_EVENTID\n");
}
-static void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_OFFLOAD_STATUS_EVENTID\n");
}
-static void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_GTK_REKEY_FAIL_EVENTID\n");
}
-static void ath10k_wmi_event_delba_complete(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_DELBA_COMPLETE_EVENTID\n");
}
-static void ath10k_wmi_event_addba_complete(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_TX_ADDBA_COMPLETE_EVENTID\n");
}
-static void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
+ struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_INSTALL_KEY_COMPLETE_EVENTID\n");
}
-static void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_INST_RSSI_STATS_EVENTID\n");
}
-static void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_STANDBY_REQ_EVENTID\n");
}
-static void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb)
{
ath10k_dbg(ar, ATH10K_DBG_WMI, "WMI_VDEV_RESUME_REQ_EVENTID\n");
}
@@ -2435,8 +3012,9 @@ static int ath10k_wmi_alloc_host_mem(struct ath10k *ar, u32 req_id,
return 0;
}
-static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
- struct wmi_svc_rdy_ev_arg *arg)
+static int
+ath10k_wmi_main_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg)
{
struct wmi_service_ready_event *ev;
size_t i, n;
@@ -2471,8 +3049,9 @@ static int ath10k_wmi_main_pull_svc_rdy_ev(struct sk_buff *skb,
return 0;
}
-static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
- struct wmi_svc_rdy_ev_arg *arg)
+static int
+ath10k_wmi_10x_op_pull_svc_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_svc_rdy_ev_arg *arg)
{
struct wmi_10x_service_ready_event *ev;
int i, n;
@@ -2506,30 +3085,22 @@ static int ath10k_wmi_10x_pull_svc_rdy_ev(struct sk_buff *skb,
return 0;
}
-static void ath10k_wmi_event_service_ready(struct ath10k *ar,
- struct sk_buff *skb)
+void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_svc_rdy_ev_arg arg = {};
u32 num_units, req_id, unit_size, num_mem_reqs, num_unit_info, i;
int ret;
- memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
-
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- ret = ath10k_wmi_10x_pull_svc_rdy_ev(skb, &arg);
- wmi_10x_svc_map(arg.service_map, ar->wmi.svc_map,
- arg.service_map_len);
- } else {
- ret = ath10k_wmi_main_pull_svc_rdy_ev(skb, &arg);
- wmi_main_svc_map(arg.service_map, ar->wmi.svc_map,
- arg.service_map_len);
- }
-
+ ret = ath10k_wmi_pull_svc_rdy(ar, skb, &arg);
if (ret) {
ath10k_warn(ar, "failed to parse service ready: %d\n", ret);
return;
}
+ memset(&ar->wmi.svc_map, 0, sizeof(ar->wmi.svc_map));
+ ath10k_wmi_map_svc(ar, arg.service_map, ar->wmi.svc_map,
+ arg.service_map_len);
+
ar->hw_min_tx_power = __le32_to_cpu(arg.min_tx_power);
ar->hw_max_tx_power = __le32_to_cpu(arg.max_tx_power);
ar->ht_cap_info = __le32_to_cpu(arg.ht_cap);
@@ -2607,13 +3178,14 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
}
ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
+ "wmi event service ready min_tx_power 0x%08x max_tx_power 0x%08x ht_cap 0x%08x vht_cap 0x%08x sw_ver0 0x%08x sw_ver1 0x%08x fw_build 0x%08x phy_capab 0x%08x num_rf_chains 0x%08x eeprom_rd 0x%08x num_mem_reqs 0x%08x\n",
__le32_to_cpu(arg.min_tx_power),
__le32_to_cpu(arg.max_tx_power),
__le32_to_cpu(arg.ht_cap),
__le32_to_cpu(arg.vht_cap),
__le32_to_cpu(arg.sw_ver0),
__le32_to_cpu(arg.sw_ver1),
+ __le32_to_cpu(arg.fw_build),
__le32_to_cpu(arg.phy_capab),
__le32_to_cpu(arg.num_rf_chains),
__le32_to_cpu(arg.eeprom_rd),
@@ -2622,27 +3194,59 @@ static void ath10k_wmi_event_service_ready(struct ath10k *ar,
complete(&ar->wmi.service_ready);
}
-static int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_op_pull_rdy_ev(struct ath10k *ar, struct sk_buff *skb,
+ struct wmi_rdy_ev_arg *arg)
{
- struct wmi_ready_event *ev = (struct wmi_ready_event *)skb->data;
+ struct wmi_ready_event *ev = (void *)skb->data;
- if (WARN_ON(skb->len < sizeof(*ev)))
- return -EINVAL;
+ if (skb->len < sizeof(*ev))
+ return -EPROTO;
- ether_addr_copy(ar->mac_addr, ev->mac_addr.addr);
+ skb_pull(skb, sizeof(*ev));
+ arg->sw_version = ev->sw_version;
+ arg->abi_version = ev->abi_version;
+ arg->status = ev->status;
+ arg->mac_addr = ev->mac_addr.addr;
+
+ return 0;
+}
+
+int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb)
+{
+ struct wmi_rdy_ev_arg arg = {};
+ int ret;
+
+ ret = ath10k_wmi_pull_rdy(ar, skb, &arg);
+ if (ret) {
+ ath10k_warn(ar, "failed to parse ready event: %d\n", ret);
+ return ret;
+ }
ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d skb->len %i ev-sz %zu\n",
- __le32_to_cpu(ev->sw_version),
- __le32_to_cpu(ev->abi_version),
- ev->mac_addr.addr,
- __le32_to_cpu(ev->status), skb->len, sizeof(*ev));
+ "wmi event ready sw_version %u abi_version %u mac_addr %pM status %d\n",
+ __le32_to_cpu(arg.sw_version),
+ __le32_to_cpu(arg.abi_version),
+ arg.mac_addr,
+ __le32_to_cpu(arg.status));
+ ether_addr_copy(ar->mac_addr, arg.mac_addr);
complete(&ar->wmi.unified_ready);
return 0;
}
-static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
+static int ath10k_wmi_event_temperature(struct ath10k *ar, struct sk_buff *skb)
+{
+ const struct wmi_pdev_temperature_event *ev;
+
+ ev = (struct wmi_pdev_temperature_event *)skb->data;
+ if (WARN_ON(skb->len < sizeof(*ev)))
+ return -EPROTO;
+
+ ath10k_thermal_event_temperature(ar, __le32_to_cpu(ev->temperature));
+ return 0;
+}
+
+static void ath10k_wmi_op_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
enum wmi_event_id id;
@@ -2758,7 +3362,7 @@ static void ath10k_wmi_main_process_rx(struct ath10k *ar, struct sk_buff *skb)
dev_kfree_skb(skb);
}
-static void ath10k_wmi_10x_process_rx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_wmi_10_1_op_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
enum wmi_10x_event_id id;
@@ -2882,7 +3486,7 @@ out:
dev_kfree_skb(skb);
}
-static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
+static void ath10k_wmi_10_2_op_rx(struct ath10k *ar, struct sk_buff *skb)
{
struct wmi_cmd_hdr *cmd_hdr;
enum wmi_10_2_event_id id;
@@ -2981,6 +3585,9 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
case WMI_10_2_READY_EVENTID:
ath10k_wmi_event_ready(ar, skb);
break;
+ case WMI_10_2_PDEV_TEMPERATURE_EVENTID:
+ ath10k_wmi_event_temperature(ar, skb);
+ break;
case WMI_10_2_RTT_KEEPALIVE_EVENTID:
case WMI_10_2_GPIO_INPUT_EVENTID:
case WMI_10_2_PEER_RATECODE_LIST_EVENTID:
@@ -3001,14 +3608,11 @@ static void ath10k_wmi_10_2_process_rx(struct ath10k *ar, struct sk_buff *skb)
static void ath10k_wmi_process_rx(struct ath10k *ar, struct sk_buff *skb)
{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
- ath10k_wmi_10_2_process_rx(ar, skb);
- else
- ath10k_wmi_10x_process_rx(ar, skb);
- } else {
- ath10k_wmi_main_process_rx(ar, skb);
- }
+ int ret;
+
+ ret = ath10k_wmi_rx(ar, skb);
+ if (ret)
+ ath10k_warn(ar, "failed to process wmi rx: %d\n", ret);
}
int ath10k_wmi_connect(struct ath10k *ar)
@@ -3039,16 +3643,17 @@ int ath10k_wmi_connect(struct ath10k *ar)
return 0;
}
-static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
- u16 rd2g, u16 rd5g, u16 ctl2g,
- u16 ctl5g)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16 rd5g,
+ u16 ctl2g, u16 ctl5g,
+ enum wmi_dfs_region dfs_reg)
{
struct wmi_pdev_set_regdomain_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_set_regdomain_cmd *)skb->data;
cmd->reg_domain = __cpu_to_le32(rd);
@@ -3060,22 +3665,20 @@ static int ath10k_wmi_main_pdev_set_regdomain(struct ath10k *ar, u16 rd,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x\n",
rd, rd2g, rd5g, ctl2g, ctl5g);
-
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->pdev_set_regdomain_cmdid);
+ return skb;
}
-static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
- u16 rd2g, u16 rd5g,
- u16 ctl2g, u16 ctl5g,
- enum wmi_dfs_region dfs_reg)
+static struct sk_buff *
+ath10k_wmi_10x_op_gen_pdev_set_rd(struct ath10k *ar, u16 rd, u16 rd2g, u16
+ rd5g, u16 ctl2g, u16 ctl5g,
+ enum wmi_dfs_region dfs_reg)
{
struct wmi_pdev_set_regdomain_cmd_10x *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_set_regdomain_cmd_10x *)skb->data;
cmd->reg_domain = __cpu_to_le32(rd);
@@ -3088,50 +3691,39 @@ static int ath10k_wmi_10x_pdev_set_regdomain(struct ath10k *ar, u16 rd,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi pdev regdomain rd %x rd2g %x rd5g %x ctl2g %x ctl5g %x dfs_region %x\n",
rd, rd2g, rd5g, ctl2g, ctl5g, dfs_reg);
-
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->pdev_set_regdomain_cmdid);
-}
-
-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
- u16 rd5g, u16 ctl2g, u16 ctl5g,
- enum wmi_dfs_region dfs_reg)
-{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- return ath10k_wmi_10x_pdev_set_regdomain(ar, rd, rd2g, rd5g,
- ctl2g, ctl5g, dfs_reg);
- else
- return ath10k_wmi_main_pdev_set_regdomain(ar, rd, rd2g, rd5g,
- ctl2g, ctl5g);
+ return skb;
}
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_suspend(struct ath10k *ar, u32 suspend_opt)
{
struct wmi_pdev_suspend_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_suspend_cmd *)skb->data;
cmd->suspend_opt = __cpu_to_le32(suspend_opt);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_suspend_cmdid);
+ return skb;
}
-int ath10k_wmi_pdev_resume_target(struct ath10k *ar)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_resume(struct ath10k *ar)
{
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, 0);
- if (skb == NULL)
- return -ENOMEM;
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_resume_cmdid);
+ return skb;
}
-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
{
struct wmi_pdev_set_param_cmd *cmd;
struct sk_buff *skb;
@@ -3139,12 +3731,12 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
if (id == WMI_PDEV_PARAM_UNSUPPORTED) {
ath10k_warn(ar, "pdev param %d not supported by firmware\n",
id);
- return -EOPNOTSUPP;
+ return ERR_PTR(-EOPNOTSUPP);
}
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_set_param_cmd *)skb->data;
cmd->param_id = __cpu_to_le32(id);
@@ -3152,11 +3744,11 @@ int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value)
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set param %d value %d\n",
id, value);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->pdev_set_param_cmdid);
+ return skb;
}
-static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
- struct wmi_host_mem_chunks *chunks)
+void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+ struct wmi_host_mem_chunks *chunks)
{
struct host_memory_chunk *chunk;
int i;
@@ -3177,7 +3769,7 @@ static void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
}
}
-static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
+static struct sk_buff *ath10k_wmi_op_gen_init(struct ath10k *ar)
{
struct wmi_init_cmd *cmd;
struct sk_buff *buf;
@@ -3240,7 +3832,7 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_init_cmd *)buf->data;
@@ -3248,10 +3840,10 @@ static int ath10k_wmi_main_cmd_init(struct ath10k *ar)
ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init\n");
- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+ return buf;
}
-static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
+static struct sk_buff *ath10k_wmi_10_1_op_gen_init(struct ath10k *ar)
{
struct wmi_init_cmd_10x *cmd;
struct sk_buff *buf;
@@ -3306,7 +3898,7 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_init_cmd_10x *)buf->data;
@@ -3314,15 +3906,15 @@ static int ath10k_wmi_10x_cmd_init(struct ath10k *ar)
ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10x\n");
- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+ return buf;
}
-static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
+static struct sk_buff *ath10k_wmi_10_2_op_gen_init(struct ath10k *ar)
{
struct wmi_init_cmd_10_2 *cmd;
struct sk_buff *buf;
struct wmi_resource_config_10x config = {};
- u32 len, val;
+ u32 len, val, features;
config.num_vdevs = __cpu_to_le32(TARGET_10X_NUM_VDEVS);
config.num_peers = __cpu_to_le32(TARGET_10X_NUM_PEERS);
@@ -3356,7 +3948,7 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
config.mcast2ucast_mode = __cpu_to_le32(TARGET_10X_MCAST2UCAST_MODE);
config.tx_dbg_log_size = __cpu_to_le32(TARGET_10X_TX_DBG_LOG_SIZE);
config.num_wds_entries = __cpu_to_le32(TARGET_10X_NUM_WDS_ENTRIES);
- config.dma_burst_size = __cpu_to_le32(TARGET_10X_DMA_BURST_SIZE);
+ config.dma_burst_size = __cpu_to_le32(TARGET_10_2_DMA_BURST_SIZE);
config.mac_aggr_delim = __cpu_to_le32(TARGET_10X_MAC_AGGR_DELIM);
val = TARGET_10X_RX_SKIP_DEFRAG_TIMEOUT_DUP_DETECTION_CHECK;
@@ -3372,34 +3964,21 @@ static int ath10k_wmi_10_2_cmd_init(struct ath10k *ar)
buf = ath10k_wmi_alloc_skb(ar, len);
if (!buf)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_init_cmd_10_2 *)buf->data;
+ features = WMI_10_2_RX_BATCH_MODE;
+ cmd->resource_config.feature_mask = __cpu_to_le32(features);
+
memcpy(&cmd->resource_config.common, &config, sizeof(config));
ath10k_wmi_put_host_mem_chunks(ar, &cmd->mem_chunks);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi init 10.2\n");
- return ath10k_wmi_cmd_send(ar, buf, ar->wmi.cmd->init_cmdid);
+ return buf;
}
-int ath10k_wmi_cmd_init(struct ath10k *ar)
-{
- int ret;
-
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
- ret = ath10k_wmi_10_2_cmd_init(ar);
- else
- ret = ath10k_wmi_10x_cmd_init(ar);
- } else {
- ret = ath10k_wmi_main_cmd_init(ar);
- }
-
- return ret;
-}
-
-static int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
+int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg)
{
if (arg->ie_len && !arg->ie)
return -EINVAL;
@@ -3450,9 +4029,8 @@ ath10k_wmi_start_scan_tlvs_len(const struct wmi_start_scan_arg *arg)
return len;
}
-static void
-ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
- const struct wmi_start_scan_arg *arg)
+void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+ const struct wmi_start_scan_arg *arg)
{
u32 scan_id;
u32 scan_req_id;
@@ -3546,46 +4124,60 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
}
}
-int ath10k_wmi_start_scan(struct ath10k *ar,
- const struct wmi_start_scan_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_start_scan(struct ath10k *ar,
+ const struct wmi_start_scan_arg *arg)
{
+ struct wmi_start_scan_cmd *cmd;
struct sk_buff *skb;
size_t len;
int ret;
ret = ath10k_wmi_start_scan_verify(arg);
if (ret)
- return ret;
-
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features))
- len = sizeof(struct wmi_10x_start_scan_cmd) +
- ath10k_wmi_start_scan_tlvs_len(arg);
- else
- len = sizeof(struct wmi_start_scan_cmd) +
- ath10k_wmi_start_scan_tlvs_len(arg);
+ return ERR_PTR(ret);
+ len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg);
skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
- return -ENOMEM;
-
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- struct wmi_10x_start_scan_cmd *cmd;
+ return ERR_PTR(-ENOMEM);
- cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
- ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
- } else {
- struct wmi_start_scan_cmd *cmd;
+ cmd = (struct wmi_start_scan_cmd *)skb->data;
- cmd = (struct wmi_start_scan_cmd *)skb->data;
- cmd->burst_duration_ms = __cpu_to_le32(0);
+ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
- ath10k_wmi_put_start_scan_common(&cmd->common, arg);
- ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
- }
+ cmd->burst_duration_ms = __cpu_to_le32(0);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi start scan\n");
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->start_scan_cmdid);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10x_op_gen_start_scan(struct ath10k *ar,
+ const struct wmi_start_scan_arg *arg)
+{
+ struct wmi_10x_start_scan_cmd *cmd;
+ struct sk_buff *skb;
+ size_t len;
+ int ret;
+
+ ret = ath10k_wmi_start_scan_verify(arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ len = sizeof(*cmd) + ath10k_wmi_start_scan_tlvs_len(arg);
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_10x_start_scan_cmd *)skb->data;
+
+ ath10k_wmi_put_start_scan_common(&cmd->common, arg);
+ ath10k_wmi_put_start_scan_tlvs(&cmd->tlvs, arg);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi 10x start scan\n");
+ return skb;
}
void ath10k_wmi_start_scan_init(struct ath10k *ar,
@@ -3614,7 +4206,9 @@ void ath10k_wmi_start_scan_init(struct ath10k *ar,
arg->bssids[0].bssid = "\xFF\xFF\xFF\xFF\xFF\xFF";
}
-int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_stop_scan(struct ath10k *ar,
+ const struct wmi_stop_scan_arg *arg)
{
struct wmi_stop_scan_cmd *cmd;
struct sk_buff *skb;
@@ -3622,13 +4216,13 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
u32 req_id;
if (arg->req_id > 0xFFF)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
if (arg->req_type == WMI_SCAN_STOP_ONE && arg->u.scan_id > 0xFFF)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
scan_id = arg->u.scan_id;
scan_id |= WMI_HOST_SCAN_REQ_ID_PREFIX;
@@ -3645,20 +4239,21 @@ int ath10k_wmi_stop_scan(struct ath10k *ar, const struct wmi_stop_scan_arg *arg)
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi stop scan reqid %d req_type %d vdev/scan_id %d\n",
arg->req_id, arg->req_type, arg->u.scan_id);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->stop_scan_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
- enum wmi_vdev_type type,
- enum wmi_vdev_subtype subtype,
- const u8 macaddr[ETH_ALEN])
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_create(struct ath10k *ar, u32 vdev_id,
+ enum wmi_vdev_type type,
+ enum wmi_vdev_subtype subtype,
+ const u8 macaddr[ETH_ALEN])
{
struct wmi_vdev_create_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_create_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -3669,58 +4264,52 @@ int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"WMI vdev create: id %d type %d subtype %d macaddr %pM\n",
vdev_id, type, subtype, macaddr);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_create_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_delete(struct ath10k *ar, u32 vdev_id)
{
struct wmi_vdev_delete_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_delete_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"WMI vdev delete id %d\n", vdev_id);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_delete_cmdid);
+ return skb;
}
-static int
-ath10k_wmi_vdev_start_restart(struct ath10k *ar,
- const struct wmi_vdev_start_request_arg *arg,
- u32 cmd_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_start(struct ath10k *ar,
+ const struct wmi_vdev_start_request_arg *arg,
+ bool restart)
{
struct wmi_vdev_start_request_cmd *cmd;
struct sk_buff *skb;
const char *cmdname;
u32 flags = 0;
- if (cmd_id != ar->wmi.cmd->vdev_start_request_cmdid &&
- cmd_id != ar->wmi.cmd->vdev_restart_request_cmdid)
- return -EINVAL;
if (WARN_ON(arg->ssid && arg->ssid_len == 0))
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
if (WARN_ON(arg->hidden_ssid && !arg->ssid))
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
if (WARN_ON(arg->ssid_len > sizeof(cmd->ssid.ssid)))
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
- if (cmd_id == ar->wmi.cmd->vdev_start_request_cmdid)
- cmdname = "start";
- else if (cmd_id == ar->wmi.cmd->vdev_restart_request_cmdid)
+ if (restart)
cmdname = "restart";
else
- return -EINVAL; /* should not happen, we already check cmd_id */
+ cmdname = "start";
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
if (arg->hidden_ssid)
flags |= WMI_VDEV_START_HIDDEN_SSID;
@@ -3749,50 +4338,36 @@ ath10k_wmi_vdev_start_restart(struct ath10k *ar,
flags, arg->channel.freq, arg->channel.mode,
cmd->chan.flags, arg->channel.max_power);
- return ath10k_wmi_cmd_send(ar, skb, cmd_id);
-}
-
-int ath10k_wmi_vdev_start(struct ath10k *ar,
- const struct wmi_vdev_start_request_arg *arg)
-{
- u32 cmd_id = ar->wmi.cmd->vdev_start_request_cmdid;
-
- return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);
-}
-
-int ath10k_wmi_vdev_restart(struct ath10k *ar,
- const struct wmi_vdev_start_request_arg *arg)
-{
- u32 cmd_id = ar->wmi.cmd->vdev_restart_request_cmdid;
-
- return ath10k_wmi_vdev_start_restart(ar, arg, cmd_id);
+ return skb;
}
-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_stop(struct ath10k *ar, u32 vdev_id)
{
struct wmi_vdev_stop_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_stop_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi vdev stop id 0x%x\n", vdev_id);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_stop_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
+ const u8 *bssid)
{
struct wmi_vdev_up_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_up_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -3802,30 +4377,30 @@ int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid, const u8 *bssid)
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mgmt vdev up id 0x%x assoc id %d bssid %pM\n",
vdev_id, aid, bssid);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_up_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_down(struct ath10k *ar, u32 vdev_id)
{
struct wmi_vdev_down_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_down_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi mgmt vdev down id 0x%x\n", vdev_id);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_down_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
- u32 param_id, u32 param_value)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_set_param(struct ath10k *ar, u32 vdev_id,
+ u32 param_id, u32 param_value)
{
struct wmi_vdev_set_param_cmd *cmd;
struct sk_buff *skb;
@@ -3834,12 +4409,12 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"vdev param %d not supported by firmware\n",
param_id);
- return -EOPNOTSUPP;
+ return ERR_PTR(-EOPNOTSUPP);
}
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_set_param_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -3849,24 +4424,24 @@ int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev id 0x%x set param %d value %d\n",
vdev_id, param_id, param_value);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->vdev_set_param_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_install_key(struct ath10k *ar,
- const struct wmi_vdev_install_key_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_install_key(struct ath10k *ar,
+ const struct wmi_vdev_install_key_arg *arg)
{
struct wmi_vdev_install_key_cmd *cmd;
struct sk_buff *skb;
if (arg->key_cipher == WMI_CIPHER_NONE && arg->key_data != NULL)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
if (arg->key_cipher != WMI_CIPHER_NONE && arg->key_data == NULL)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd) + arg->key_len);
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_install_key_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
@@ -3885,20 +4460,19 @@ int ath10k_wmi_vdev_install_key(struct ath10k *ar,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev install key idx %d cipher %d len %d\n",
arg->key_idx, arg->key_cipher, arg->key_len);
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->vdev_install_key_cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
- const struct wmi_vdev_spectral_conf_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_spectral_conf(struct ath10k *ar,
+ const struct wmi_vdev_spectral_conf_arg *arg)
{
struct wmi_vdev_spectral_conf_cmd *cmd;
struct sk_buff *skb;
- u32 cmdid;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_spectral_conf_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(arg->vdev_id);
@@ -3921,39 +4495,38 @@ int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
cmd->scan_dbm_adj = __cpu_to_le32(arg->scan_dbm_adj);
cmd->scan_chn_mask = __cpu_to_le32(arg->scan_chn_mask);
- cmdid = ar->wmi.cmd->vdev_spectral_scan_configure_cmdid;
- return ath10k_wmi_cmd_send(ar, skb, cmdid);
+ return skb;
}
-int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
- u32 enable)
+static struct sk_buff *
+ath10k_wmi_op_gen_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id,
+ u32 trigger, u32 enable)
{
struct wmi_vdev_spectral_enable_cmd *cmd;
struct sk_buff *skb;
- u32 cmdid;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_vdev_spectral_enable_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
cmd->trigger_cmd = __cpu_to_le32(trigger);
cmd->enable_cmd = __cpu_to_le32(enable);
- cmdid = ar->wmi.cmd->vdev_spectral_scan_enable_cmdid;
- return ath10k_wmi_cmd_send(ar, skb, cmdid);
+ return skb;
}
-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_create(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN])
{
struct wmi_peer_create_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_peer_create_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -3962,18 +4535,19 @@ int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer create vdev_id %d peer_addr %pM\n",
vdev_id, peer_addr);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_create_cmdid);
+ return skb;
}
-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN])
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_delete(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN])
{
struct wmi_peer_delete_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_peer_delete_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -3982,18 +4556,19 @@ int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer delete vdev_id %d peer_addr %pM\n",
vdev_id, peer_addr);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_delete_cmdid);
+ return skb;
}
-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_flush(struct ath10k *ar, u32 vdev_id,
+ const u8 peer_addr[ETH_ALEN], u32 tid_bitmap)
{
struct wmi_peer_flush_tids_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_peer_flush_tids_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4003,19 +4578,21 @@ int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer flush vdev_id %d peer_addr %pM tids %08x\n",
vdev_id, peer_addr, tid_bitmap);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_flush_tids_cmdid);
+ return skb;
}
-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
- const u8 *peer_addr, enum wmi_peer_param param_id,
- u32 param_value)
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id,
+ const u8 *peer_addr,
+ enum wmi_peer_param param_id,
+ u32 param_value)
{
struct wmi_peer_set_param_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_peer_set_param_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4026,19 +4603,19 @@ int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi vdev %d peer 0x%pM set param %d value %d\n",
vdev_id, peer_addr, param_id, param_value);
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_set_param_cmdid);
+ return skb;
}
-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
- enum wmi_sta_ps_mode psmode)
+static struct sk_buff *
+ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_ps_mode psmode)
{
struct wmi_sta_powersave_mode_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_sta_powersave_mode_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4047,21 +4624,20 @@ int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi set powersave id 0x%x mode %d\n",
vdev_id, psmode);
-
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->sta_powersave_mode_cmdid);
+ return skb;
}
-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
- enum wmi_sta_powersave_param param_id,
- u32 value)
+static struct sk_buff *
+ath10k_wmi_op_gen_set_sta_ps(struct ath10k *ar, u32 vdev_id,
+ enum wmi_sta_powersave_param param_id,
+ u32 value)
{
struct wmi_sta_powersave_param_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_sta_powersave_param_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4071,22 +4647,22 @@ int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi sta ps param vdev_id 0x%x param %d value %d\n",
vdev_id, param_id, value);
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->sta_powersave_param_cmdid);
+ return skb;
}
-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- enum wmi_ap_ps_peer_param param_id, u32 value)
+static struct sk_buff *
+ath10k_wmi_op_gen_set_ap_ps(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ enum wmi_ap_ps_peer_param param_id, u32 value)
{
struct wmi_ap_ps_peer_cmd *cmd;
struct sk_buff *skb;
if (!mac)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_ap_ps_peer_cmd *)skb->data;
cmd->vdev_id = __cpu_to_le32(vdev_id);
@@ -4097,13 +4673,12 @@ int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi ap ps param vdev_id 0x%X param %d value %d mac_addr %pM\n",
vdev_id, param_id, value, mac);
-
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->ap_ps_peer_param_cmdid);
+ return skb;
}
-int ath10k_wmi_scan_chan_list(struct ath10k *ar,
- const struct wmi_scan_chan_list_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_scan_chan_list(struct ath10k *ar,
+ const struct wmi_scan_chan_list_arg *arg)
{
struct wmi_scan_chan_list_cmd *cmd;
struct sk_buff *skb;
@@ -4116,7 +4691,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
- return -EINVAL;
+ return ERR_PTR(-EINVAL);
cmd = (struct wmi_scan_chan_list_cmd *)skb->data;
cmd->num_scan_chans = __cpu_to_le32(arg->n_channels);
@@ -4128,7 +4703,7 @@ int ath10k_wmi_scan_chan_list(struct ath10k *ar,
ath10k_wmi_put_wmi_channel(ci, ch);
}
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->scan_chan_list_cmdid);
+ return skb;
}
static void
@@ -4209,12 +4784,9 @@ ath10k_wmi_peer_assoc_fill_10_2(struct ath10k *ar, void *buf,
cmd->info0 = __cpu_to_le32(info0);
}
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
- const struct wmi_peer_assoc_complete_arg *arg)
+static int
+ath10k_wmi_peer_assoc_check_arg(const struct wmi_peer_assoc_complete_arg *arg)
{
- struct sk_buff *skb;
- int len;
-
if (arg->peer_mpdu_density > 16)
return -EINVAL;
if (arg->peer_legacy_rates.num_rates > MAX_SUPPORTED_RATES)
@@ -4222,79 +4794,135 @@ int ath10k_wmi_peer_assoc(struct ath10k *ar,
if (arg->peer_ht_rates.num_rates > MAX_SUPPORTED_RATES)
return -EINVAL;
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
- len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
- else
- len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
- } else {
- len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
- }
+ return 0;
+}
+
+static struct sk_buff *
+ath10k_wmi_op_gen_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ size_t len = sizeof(struct wmi_main_peer_assoc_complete_cmd);
+ struct sk_buff *skb;
+ int ret;
+
+ ret = ath10k_wmi_peer_assoc_check_arg(arg);
+ if (ret)
+ return ERR_PTR(ret);
skb = ath10k_wmi_alloc_skb(ar, len);
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
- ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
- else
- ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
- } else {
- ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
- }
+ ath10k_wmi_peer_assoc_fill_main(ar, skb->data, arg);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi peer assoc vdev %d addr %pM (%s)\n",
+ arg->vdev_id, arg->addr,
+ arg->peer_reassoc ? "reassociate" : "new");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10_1_op_gen_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ size_t len = sizeof(struct wmi_10_1_peer_assoc_complete_cmd);
+ struct sk_buff *skb;
+ int ret;
+
+ ret = ath10k_wmi_peer_assoc_check_arg(arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ath10k_wmi_peer_assoc_fill_10_1(ar, skb->data, arg);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi peer assoc vdev %d addr %pM (%s)\n",
+ arg->vdev_id, arg->addr,
+ arg->peer_reassoc ? "reassociate" : "new");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10_2_op_gen_peer_assoc(struct ath10k *ar,
+ const struct wmi_peer_assoc_complete_arg *arg)
+{
+ size_t len = sizeof(struct wmi_10_2_peer_assoc_complete_cmd);
+ struct sk_buff *skb;
+ int ret;
+
+ ret = ath10k_wmi_peer_assoc_check_arg(arg);
+ if (ret)
+ return ERR_PTR(ret);
+
+ skb = ath10k_wmi_alloc_skb(ar, len);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ath10k_wmi_peer_assoc_fill_10_2(ar, skb->data, arg);
ath10k_dbg(ar, ATH10K_DBG_WMI,
"wmi peer assoc vdev %d addr %pM (%s)\n",
arg->vdev_id, arg->addr,
arg->peer_reassoc ? "reassociate" : "new");
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->peer_assoc_cmdid);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_10_2_op_gen_pdev_get_temperature(struct ath10k *ar)
+{
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, 0);
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev get temperature\n");
+ return skb;
}
/* This function assumes the beacon is already DMA mapped */
-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif)
+static struct sk_buff *
+ath10k_wmi_op_gen_beacon_dma(struct ath10k *ar, u32 vdev_id, const void *bcn,
+ size_t bcn_len, u32 bcn_paddr, bool dtim_zero,
+ bool deliver_cab)
{
struct wmi_bcn_tx_ref_cmd *cmd;
struct sk_buff *skb;
- struct sk_buff *beacon = arvif->beacon;
- struct ath10k *ar = arvif->ar;
struct ieee80211_hdr *hdr;
- int ret;
u16 fc;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
- hdr = (struct ieee80211_hdr *)beacon->data;
+ hdr = (struct ieee80211_hdr *)bcn;
fc = le16_to_cpu(hdr->frame_control);
cmd = (struct wmi_bcn_tx_ref_cmd *)skb->data;
- cmd->vdev_id = __cpu_to_le32(arvif->vdev_id);
- cmd->data_len = __cpu_to_le32(beacon->len);
- cmd->data_ptr = __cpu_to_le32(ATH10K_SKB_CB(beacon)->paddr);
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ cmd->data_len = __cpu_to_le32(bcn_len);
+ cmd->data_ptr = __cpu_to_le32(bcn_paddr);
cmd->msdu_id = 0;
cmd->frame_control = __cpu_to_le32(fc);
cmd->flags = 0;
cmd->antenna_mask = __cpu_to_le32(WMI_BCN_TX_REF_DEF_ANTENNA);
- if (ATH10K_SKB_CB(beacon)->bcn.dtim_zero)
+ if (dtim_zero)
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DTIM_ZERO);
- if (ATH10K_SKB_CB(beacon)->bcn.deliver_cab)
+ if (deliver_cab)
cmd->flags |= __cpu_to_le32(WMI_BCN_TX_REF_FLAG_DELIVER_CAB);
- ret = ath10k_wmi_cmd_send_nowait(ar, skb,
- ar->wmi.cmd->pdev_send_bcn_cmdid);
-
- if (ret)
- dev_kfree_skb(skb);
-
- return ret;
+ return skb;
}
-static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
- const struct wmi_wmm_params_arg *arg)
+void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params,
+ const struct wmi_wmm_params_arg *arg)
{
params->cwmin = __cpu_to_le32(arg->cwmin);
params->cwmax = __cpu_to_le32(arg->cwmax);
@@ -4304,52 +4932,54 @@ static void ath10k_wmi_pdev_set_wmm_param(struct wmi_wmm_params *params,
params->no_ack = __cpu_to_le32(arg->no_ack);
}
-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
- const struct wmi_pdev_set_wmm_params_arg *arg)
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_wmm(struct ath10k *ar,
+ const struct wmi_wmm_params_all_arg *arg)
{
struct wmi_pdev_set_wmm_params *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_pdev_set_wmm_params *)skb->data;
- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_be, &arg->ac_be);
- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_bk, &arg->ac_bk);
- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
- ath10k_wmi_pdev_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
+ ath10k_wmi_set_wmm_param(&cmd->ac_be, &arg->ac_be);
+ ath10k_wmi_set_wmm_param(&cmd->ac_bk, &arg->ac_bk);
+ ath10k_wmi_set_wmm_param(&cmd->ac_vi, &arg->ac_vi);
+ ath10k_wmi_set_wmm_param(&cmd->ac_vo, &arg->ac_vo);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi pdev set wmm params\n");
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->pdev_set_wmm_params_cmdid);
+ return skb;
}
-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
+static struct sk_buff *
+ath10k_wmi_op_gen_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id)
{
struct wmi_request_stats_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_request_stats_cmd *)skb->data;
cmd->stats_id = __cpu_to_le32(stats_id);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi request stats %d\n", (int)stats_id);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->request_stats_cmdid);
+ return skb;
}
-int ath10k_wmi_force_fw_hang(struct ath10k *ar,
- enum wmi_force_fw_hang_type type, u32 delay_ms)
+static struct sk_buff *
+ath10k_wmi_op_gen_force_fw_hang(struct ath10k *ar,
+ enum wmi_force_fw_hang_type type, u32 delay_ms)
{
struct wmi_force_fw_hang_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_force_fw_hang_cmd *)skb->data;
cmd->type = __cpu_to_le32(type);
@@ -4357,10 +4987,12 @@ int ath10k_wmi_force_fw_hang(struct ath10k *ar,
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi force fw hang %d delay %d\n",
type, delay_ms);
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid);
+ return skb;
}
-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
+static struct sk_buff *
+ath10k_wmi_op_gen_dbglog_cfg(struct ath10k *ar, u32 module_enable,
+ u32 log_level)
{
struct wmi_dbglog_cfg_cmd *cmd;
struct sk_buff *skb;
@@ -4368,12 +5000,12 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
cmd = (struct wmi_dbglog_cfg_cmd *)skb->data;
if (module_enable) {
- cfg = SM(ATH10K_DBGLOG_LEVEL_VERBOSE,
+ cfg = SM(log_level,
ATH10K_DBGLOG_CFG_LOG_LVL);
} else {
/* set back defaults, all modules with WARN level */
@@ -4393,57 +5025,449 @@ int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable)
__le32_to_cpu(cmd->module_valid),
__le32_to_cpu(cmd->config_enable),
__le32_to_cpu(cmd->config_valid));
-
- return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->dbglog_cfg_cmdid);
+ return skb;
}
-int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
+static struct sk_buff *
+ath10k_wmi_op_gen_pktlog_enable(struct ath10k *ar, u32 ev_bitmap)
{
struct wmi_pdev_pktlog_enable_cmd *cmd;
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
ev_bitmap &= ATH10K_PKTLOG_ANY;
- ath10k_dbg(ar, ATH10K_DBG_WMI,
- "wmi enable pktlog filter:%x\n", ev_bitmap);
cmd = (struct wmi_pdev_pktlog_enable_cmd *)skb->data;
cmd->ev_bitmap = __cpu_to_le32(ev_bitmap);
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->pdev_pktlog_enable_cmdid);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi enable pktlog filter 0x%08x\n",
+ ev_bitmap);
+ return skb;
}
-int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar)
+static struct sk_buff *
+ath10k_wmi_op_gen_pktlog_disable(struct ath10k *ar)
{
struct sk_buff *skb;
skb = ath10k_wmi_alloc_skb(ar, 0);
if (!skb)
- return -ENOMEM;
+ return ERR_PTR(-ENOMEM);
ath10k_dbg(ar, ATH10K_DBG_WMI, "wmi disable pktlog\n");
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_op_gen_pdev_set_quiet_mode(struct ath10k *ar, u32 period,
+ u32 duration, u32 next_offset,
+ u32 enabled)
+{
+ struct wmi_pdev_set_quiet_cmd *cmd;
+ struct sk_buff *skb;
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_pdev_set_quiet_cmd *)skb->data;
+ cmd->period = __cpu_to_le32(period);
+ cmd->duration = __cpu_to_le32(duration);
+ cmd->next_start = __cpu_to_le32(next_offset);
+ cmd->enabled = __cpu_to_le32(enabled);
- return ath10k_wmi_cmd_send(ar, skb,
- ar->wmi.cmd->pdev_pktlog_disable_cmdid);
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi quiet param: period %u duration %u enabled %d\n",
+ period, duration, enabled);
+ return skb;
}
-int ath10k_wmi_attach(struct ath10k *ar)
+static struct sk_buff *
+ath10k_wmi_op_gen_addba_clear_resp(struct ath10k *ar, u32 vdev_id,
+ const u8 *mac)
{
- if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
- if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features))
- ar->wmi.cmd = &wmi_10_2_cmd_map;
- else
- ar->wmi.cmd = &wmi_10x_cmd_map;
+ struct wmi_addba_clear_resp_cmd *cmd;
+ struct sk_buff *skb;
+
+ if (!mac)
+ return ERR_PTR(-EINVAL);
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_addba_clear_resp_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, mac);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi addba clear resp vdev_id 0x%X mac_addr %pM\n",
+ vdev_id, mac);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_op_gen_addba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ u32 tid, u32 buf_size)
+{
+ struct wmi_addba_send_cmd *cmd;
+ struct sk_buff *skb;
+
+ if (!mac)
+ return ERR_PTR(-EINVAL);
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_addba_send_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, mac);
+ cmd->tid = __cpu_to_le32(tid);
+ cmd->buffersize = __cpu_to_le32(buf_size);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi addba send vdev_id 0x%X mac_addr %pM tid %u bufsize %u\n",
+ vdev_id, mac, tid, buf_size);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_op_gen_addba_set_resp(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ u32 tid, u32 status)
+{
+ struct wmi_addba_setresponse_cmd *cmd;
+ struct sk_buff *skb;
+
+ if (!mac)
+ return ERR_PTR(-EINVAL);
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_addba_setresponse_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, mac);
+ cmd->tid = __cpu_to_le32(tid);
+ cmd->statuscode = __cpu_to_le32(status);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi addba set resp vdev_id 0x%X mac_addr %pM tid %u status %u\n",
+ vdev_id, mac, tid, status);
+ return skb;
+}
+
+static struct sk_buff *
+ath10k_wmi_op_gen_delba_send(struct ath10k *ar, u32 vdev_id, const u8 *mac,
+ u32 tid, u32 initiator, u32 reason)
+{
+ struct wmi_delba_send_cmd *cmd;
+ struct sk_buff *skb;
+
+ if (!mac)
+ return ERR_PTR(-EINVAL);
+
+ skb = ath10k_wmi_alloc_skb(ar, sizeof(*cmd));
+ if (!skb)
+ return ERR_PTR(-ENOMEM);
+
+ cmd = (struct wmi_delba_send_cmd *)skb->data;
+ cmd->vdev_id = __cpu_to_le32(vdev_id);
+ ether_addr_copy(cmd->peer_macaddr.addr, mac);
+ cmd->tid = __cpu_to_le32(tid);
+ cmd->initiator = __cpu_to_le32(initiator);
+ cmd->reasoncode = __cpu_to_le32(reason);
+
+ ath10k_dbg(ar, ATH10K_DBG_WMI,
+ "wmi delba send vdev_id 0x%X mac_addr %pM tid %u initiator %u reason %u\n",
+ vdev_id, mac, tid, initiator, reason);
+ return skb;
+}
+
+static const struct wmi_ops wmi_ops = {
+ .rx = ath10k_wmi_op_rx,
+ .map_svc = wmi_main_svc_map,
+
+ .pull_scan = ath10k_wmi_op_pull_scan_ev,
+ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+ .pull_swba = ath10k_wmi_op_pull_swba_ev,
+ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+ .pull_svc_rdy = ath10k_wmi_main_op_pull_svc_rdy_ev,
+ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+ .pull_fw_stats = ath10k_wmi_main_op_pull_fw_stats,
+
+ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+ .gen_pdev_set_rd = ath10k_wmi_op_gen_pdev_set_rd,
+ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+ .gen_init = ath10k_wmi_op_gen_init,
+ .gen_start_scan = ath10k_wmi_op_gen_start_scan,
+ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+ /* .gen_vdev_wmm_conf not implemented */
+ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
+ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+ .gen_peer_assoc = ath10k_wmi_op_gen_peer_assoc,
+ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
+ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
+ /* .gen_pdev_get_temperature not implemented */
+ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
+ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
+ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
+ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
+ /* .gen_bcn_tmpl not implemented */
+ /* .gen_prb_tmpl not implemented */
+ /* .gen_p2p_go_bcn_ie not implemented */
+};
+
+static const struct wmi_ops wmi_10_1_ops = {
+ .rx = ath10k_wmi_10_1_op_rx,
+ .map_svc = wmi_10x_svc_map,
+ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
+ .pull_fw_stats = ath10k_wmi_10x_op_pull_fw_stats,
+ .gen_init = ath10k_wmi_10_1_op_gen_init,
+ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
+ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+ .gen_peer_assoc = ath10k_wmi_10_1_op_gen_peer_assoc,
+ /* .gen_pdev_get_temperature not implemented */
+
+ /* shared with main branch */
+ .pull_scan = ath10k_wmi_op_pull_scan_ev,
+ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+ .pull_swba = ath10k_wmi_op_pull_swba_ev,
+ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+
+ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+ /* .gen_vdev_wmm_conf not implemented */
+ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
+ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
+ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
+ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
+ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
+ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
+ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
+ /* .gen_bcn_tmpl not implemented */
+ /* .gen_prb_tmpl not implemented */
+ /* .gen_p2p_go_bcn_ie not implemented */
+};
+
+static const struct wmi_ops wmi_10_2_ops = {
+ .rx = ath10k_wmi_10_2_op_rx,
+ .pull_fw_stats = ath10k_wmi_10_2_op_pull_fw_stats,
+ .gen_init = ath10k_wmi_10_2_op_gen_init,
+ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
+ /* .gen_pdev_get_temperature not implemented */
+
+ /* shared with 10.1 */
+ .map_svc = wmi_10x_svc_map,
+ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
+ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
+ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+
+ .pull_scan = ath10k_wmi_op_pull_scan_ev,
+ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+ .pull_swba = ath10k_wmi_op_pull_swba_ev,
+ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+
+ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+ /* .gen_vdev_wmm_conf not implemented */
+ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
+ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
+ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
+ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
+ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
+ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
+ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
+};
+static const struct wmi_ops wmi_10_2_4_ops = {
+ .rx = ath10k_wmi_10_2_op_rx,
+ .pull_fw_stats = ath10k_wmi_10_2_4_op_pull_fw_stats,
+ .gen_init = ath10k_wmi_10_2_op_gen_init,
+ .gen_peer_assoc = ath10k_wmi_10_2_op_gen_peer_assoc,
+ .gen_pdev_get_temperature = ath10k_wmi_10_2_op_gen_pdev_get_temperature,
+
+ /* shared with 10.1 */
+ .map_svc = wmi_10x_svc_map,
+ .pull_svc_rdy = ath10k_wmi_10x_op_pull_svc_rdy_ev,
+ .gen_pdev_set_rd = ath10k_wmi_10x_op_gen_pdev_set_rd,
+ .gen_start_scan = ath10k_wmi_10x_op_gen_start_scan,
+
+ .pull_scan = ath10k_wmi_op_pull_scan_ev,
+ .pull_mgmt_rx = ath10k_wmi_op_pull_mgmt_rx_ev,
+ .pull_ch_info = ath10k_wmi_op_pull_ch_info_ev,
+ .pull_vdev_start = ath10k_wmi_op_pull_vdev_start_ev,
+ .pull_peer_kick = ath10k_wmi_op_pull_peer_kick_ev,
+ .pull_swba = ath10k_wmi_op_pull_swba_ev,
+ .pull_phyerr = ath10k_wmi_op_pull_phyerr_ev,
+ .pull_rdy = ath10k_wmi_op_pull_rdy_ev,
+
+ .gen_pdev_suspend = ath10k_wmi_op_gen_pdev_suspend,
+ .gen_pdev_resume = ath10k_wmi_op_gen_pdev_resume,
+ .gen_pdev_set_param = ath10k_wmi_op_gen_pdev_set_param,
+ .gen_stop_scan = ath10k_wmi_op_gen_stop_scan,
+ .gen_vdev_create = ath10k_wmi_op_gen_vdev_create,
+ .gen_vdev_delete = ath10k_wmi_op_gen_vdev_delete,
+ .gen_vdev_start = ath10k_wmi_op_gen_vdev_start,
+ .gen_vdev_stop = ath10k_wmi_op_gen_vdev_stop,
+ .gen_vdev_up = ath10k_wmi_op_gen_vdev_up,
+ .gen_vdev_down = ath10k_wmi_op_gen_vdev_down,
+ .gen_vdev_set_param = ath10k_wmi_op_gen_vdev_set_param,
+ .gen_vdev_install_key = ath10k_wmi_op_gen_vdev_install_key,
+ .gen_vdev_spectral_conf = ath10k_wmi_op_gen_vdev_spectral_conf,
+ .gen_vdev_spectral_enable = ath10k_wmi_op_gen_vdev_spectral_enable,
+ .gen_peer_create = ath10k_wmi_op_gen_peer_create,
+ .gen_peer_delete = ath10k_wmi_op_gen_peer_delete,
+ .gen_peer_flush = ath10k_wmi_op_gen_peer_flush,
+ .gen_peer_set_param = ath10k_wmi_op_gen_peer_set_param,
+ .gen_set_psmode = ath10k_wmi_op_gen_set_psmode,
+ .gen_set_sta_ps = ath10k_wmi_op_gen_set_sta_ps,
+ .gen_set_ap_ps = ath10k_wmi_op_gen_set_ap_ps,
+ .gen_scan_chan_list = ath10k_wmi_op_gen_scan_chan_list,
+ .gen_beacon_dma = ath10k_wmi_op_gen_beacon_dma,
+ .gen_pdev_set_wmm = ath10k_wmi_op_gen_pdev_set_wmm,
+ .gen_request_stats = ath10k_wmi_op_gen_request_stats,
+ .gen_force_fw_hang = ath10k_wmi_op_gen_force_fw_hang,
+ .gen_mgmt_tx = ath10k_wmi_op_gen_mgmt_tx,
+ .gen_dbglog_cfg = ath10k_wmi_op_gen_dbglog_cfg,
+ .gen_pktlog_enable = ath10k_wmi_op_gen_pktlog_enable,
+ .gen_pktlog_disable = ath10k_wmi_op_gen_pktlog_disable,
+ .gen_pdev_set_quiet_mode = ath10k_wmi_op_gen_pdev_set_quiet_mode,
+ .gen_addba_clear_resp = ath10k_wmi_op_gen_addba_clear_resp,
+ .gen_addba_send = ath10k_wmi_op_gen_addba_send,
+ .gen_addba_set_resp = ath10k_wmi_op_gen_addba_set_resp,
+ .gen_delba_send = ath10k_wmi_op_gen_delba_send,
+ /* .gen_bcn_tmpl not implemented */
+ /* .gen_prb_tmpl not implemented */
+ /* .gen_p2p_go_bcn_ie not implemented */
+};
+
+int ath10k_wmi_attach(struct ath10k *ar)
+{
+ switch (ar->wmi.op_version) {
+ case ATH10K_FW_WMI_OP_VERSION_10_2_4:
+ ar->wmi.cmd = &wmi_10_2_4_cmd_map;
+ ar->wmi.ops = &wmi_10_2_4_ops;
+ ar->wmi.vdev_param = &wmi_10_2_4_vdev_param_map;
+ ar->wmi.pdev_param = &wmi_10_2_4_pdev_param_map;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_10_2:
+ ar->wmi.cmd = &wmi_10_2_cmd_map;
+ ar->wmi.ops = &wmi_10_2_ops;
ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
- } else {
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_10_1:
+ ar->wmi.cmd = &wmi_10x_cmd_map;
+ ar->wmi.ops = &wmi_10_1_ops;
+ ar->wmi.vdev_param = &wmi_10x_vdev_param_map;
+ ar->wmi.pdev_param = &wmi_10x_pdev_param_map;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_MAIN:
ar->wmi.cmd = &wmi_cmd_map;
+ ar->wmi.ops = &wmi_ops;
ar->wmi.vdev_param = &wmi_vdev_param_map;
ar->wmi.pdev_param = &wmi_pdev_param_map;
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_TLV:
+ ath10k_wmi_tlv_attach(ar);
+ break;
+ case ATH10K_FW_WMI_OP_VERSION_UNSET:
+ case ATH10K_FW_WMI_OP_VERSION_MAX:
+ ath10k_err(ar, "unsupported WMI op version: %d\n",
+ ar->wmi.op_version);
+ return -EINVAL;
}
init_completion(&ar->wmi.service_ready);
diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h
index 21391929d318..20ce3603e64b 100644
--- a/drivers/net/wireless/ath/ath10k/wmi.h
+++ b/drivers/net/wireless/ath/ath10k/wmi.h
@@ -109,6 +109,45 @@ enum wmi_service {
WMI_SERVICE_BURST,
WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT,
WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT,
+ WMI_SERVICE_ROAM_SCAN_OFFLOAD,
+ WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC,
+ WMI_SERVICE_EARLY_RX,
+ WMI_SERVICE_STA_SMPS,
+ WMI_SERVICE_FWTEST,
+ WMI_SERVICE_STA_WMMAC,
+ WMI_SERVICE_TDLS,
+ WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE,
+ WMI_SERVICE_ADAPTIVE_OCS,
+ WMI_SERVICE_BA_SSN_SUPPORT,
+ WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE,
+ WMI_SERVICE_WLAN_HB,
+ WMI_SERVICE_LTE_ANT_SHARE_SUPPORT,
+ WMI_SERVICE_BATCH_SCAN,
+ WMI_SERVICE_QPOWER,
+ WMI_SERVICE_PLMREQ,
+ WMI_SERVICE_THERMAL_MGMT,
+ WMI_SERVICE_RMC,
+ WMI_SERVICE_MHF_OFFLOAD,
+ WMI_SERVICE_COEX_SAR,
+ WMI_SERVICE_BCN_TXRATE_OVERRIDE,
+ WMI_SERVICE_NAN,
+ WMI_SERVICE_L1SS_STAT,
+ WMI_SERVICE_ESTIMATE_LINKSPEED,
+ WMI_SERVICE_OBSS_SCAN,
+ WMI_SERVICE_TDLS_OFFCHAN,
+ WMI_SERVICE_TDLS_UAPSD_BUFFER_STA,
+ WMI_SERVICE_TDLS_UAPSD_SLEEP_STA,
+ WMI_SERVICE_IBSS_PWRSAVE,
+ WMI_SERVICE_LPASS,
+ WMI_SERVICE_EXTSCAN,
+ WMI_SERVICE_D0WOW,
+ WMI_SERVICE_HSOFFLOAD,
+ WMI_SERVICE_ROAM_HO_OFFLOAD,
+ WMI_SERVICE_RX_FULL_REORDER,
+ WMI_SERVICE_DHCP_OFFLOAD,
+ WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT,
+ WMI_SERVICE_MDNS_OFFLOAD,
+ WMI_SERVICE_SAP_AUTH_OFFLOAD,
/* keep last */
WMI_SERVICE_MAX,
@@ -215,6 +254,45 @@ static inline char *wmi_service_name(int service_id)
SVCSTR(WMI_SERVICE_BURST);
SVCSTR(WMI_SERVICE_SMART_ANTENNA_SW_SUPPORT);
SVCSTR(WMI_SERVICE_SMART_ANTENNA_HW_SUPPORT);
+ SVCSTR(WMI_SERVICE_ROAM_SCAN_OFFLOAD);
+ SVCSTR(WMI_SERVICE_AP_PS_DETECT_OUT_OF_SYNC);
+ SVCSTR(WMI_SERVICE_EARLY_RX);
+ SVCSTR(WMI_SERVICE_STA_SMPS);
+ SVCSTR(WMI_SERVICE_FWTEST);
+ SVCSTR(WMI_SERVICE_STA_WMMAC);
+ SVCSTR(WMI_SERVICE_TDLS);
+ SVCSTR(WMI_SERVICE_MCC_BCN_INTERVAL_CHANGE);
+ SVCSTR(WMI_SERVICE_ADAPTIVE_OCS);
+ SVCSTR(WMI_SERVICE_BA_SSN_SUPPORT);
+ SVCSTR(WMI_SERVICE_FILTER_IPSEC_NATKEEPALIVE);
+ SVCSTR(WMI_SERVICE_WLAN_HB);
+ SVCSTR(WMI_SERVICE_LTE_ANT_SHARE_SUPPORT);
+ SVCSTR(WMI_SERVICE_BATCH_SCAN);
+ SVCSTR(WMI_SERVICE_QPOWER);
+ SVCSTR(WMI_SERVICE_PLMREQ);
+ SVCSTR(WMI_SERVICE_THERMAL_MGMT);
+ SVCSTR(WMI_SERVICE_RMC);
+ SVCSTR(WMI_SERVICE_MHF_OFFLOAD);
+ SVCSTR(WMI_SERVICE_COEX_SAR);
+ SVCSTR(WMI_SERVICE_BCN_TXRATE_OVERRIDE);
+ SVCSTR(WMI_SERVICE_NAN);
+ SVCSTR(WMI_SERVICE_L1SS_STAT);
+ SVCSTR(WMI_SERVICE_ESTIMATE_LINKSPEED);
+ SVCSTR(WMI_SERVICE_OBSS_SCAN);
+ SVCSTR(WMI_SERVICE_TDLS_OFFCHAN);
+ SVCSTR(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA);
+ SVCSTR(WMI_SERVICE_TDLS_UAPSD_SLEEP_STA);
+ SVCSTR(WMI_SERVICE_IBSS_PWRSAVE);
+ SVCSTR(WMI_SERVICE_LPASS);
+ SVCSTR(WMI_SERVICE_EXTSCAN);
+ SVCSTR(WMI_SERVICE_D0WOW);
+ SVCSTR(WMI_SERVICE_HSOFFLOAD);
+ SVCSTR(WMI_SERVICE_ROAM_HO_OFFLOAD);
+ SVCSTR(WMI_SERVICE_RX_FULL_REORDER);
+ SVCSTR(WMI_SERVICE_DHCP_OFFLOAD);
+ SVCSTR(WMI_SERVICE_STA_RX_IPA_OFFLOAD_SUPPORT);
+ SVCSTR(WMI_SERVICE_MDNS_OFFLOAD);
+ SVCSTR(WMI_SERVICE_SAP_AUTH_OFFLOAD);
default:
return NULL;
}
@@ -472,6 +550,8 @@ struct wmi_cmd_map {
u32 force_fw_hang_cmdid;
u32 gpio_config_cmdid;
u32 gpio_output_cmdid;
+ u32 pdev_get_temperature_cmdid;
+ u32 vdev_set_wmm_params_cmdid;
};
/*
@@ -1076,6 +1156,11 @@ enum wmi_10_2_cmd_id {
WMI_10_2_PDEV_SET_MIMOGAIN_TABLE_CMDID,
WMI_10_2_PDEV_RATEPWR_TABLE_CMDID,
WMI_10_2_PDEV_RATEPWR_CHAINMSK_TABLE_CMDID,
+ WMI_10_2_PDEV_GET_INFO,
+ WMI_10_2_VDEV_GET_INFO,
+ WMI_10_2_VDEV_ATF_REQUEST_CMDID,
+ WMI_10_2_PEER_ATF_REQUEST_CMDID,
+ WMI_10_2_PDEV_GET_TEMPERATURE_CMDID,
WMI_10_2_PDEV_UTF_CMDID = WMI_10_2_END_CMDID - 1,
};
@@ -1117,6 +1202,8 @@ enum wmi_10_2_event_id {
WMI_10_2_MCAST_BUF_RELEASE_EVENTID,
WMI_10_2_MCAST_LIST_AGEOUT_EVENTID,
WMI_10_2_WDS_PEER_EVENTID,
+ WMI_10_2_PEER_STA_PS_STATECHG_EVENTID,
+ WMI_10_2_PDEV_TEMPERATURE_EVENTID,
WMI_10_2_PDEV_UTF_EVENTID = WMI_10_2_END_EVENTID - 1,
};
@@ -1862,6 +1949,11 @@ struct wmi_resource_config_10x {
__le32 max_frag_entries;
} __packed;
+enum wmi_10_2_feature_mask {
+ WMI_10_2_RX_BATCH_MODE = BIT(0),
+ WMI_10_2_ATF_CONFIG = BIT(1),
+};
+
struct wmi_resource_config_10_2 {
struct wmi_resource_config_10x common;
__le32 max_peer_ext_stats;
@@ -1870,7 +1962,7 @@ struct wmi_resource_config_10_2 {
__le32 be_min_free;
__le32 vi_min_free;
__le32 vo_min_free;
- __le32 rx_batchmode; /* 0-disable, 1-enable */
+ __le32 feature_mask;
} __packed;
#define NUM_UNITS_IS_NUM_VDEVS 0x1
@@ -2505,6 +2597,7 @@ struct wmi_pdev_param_map {
u32 fast_channel_reset;
u32 burst_dur;
u32 burst_enable;
+ u32 cal_period;
};
#define WMI_PDEV_PARAM_UNSUPPORTED 0
@@ -2715,6 +2808,9 @@ enum wmi_10x_pdev_param {
WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_MODE,
WMI_10X_PDEV_PARAM_SET_MCAST2UCAST_BUFFER,
WMI_10X_PDEV_PARAM_REMOVE_MCAST2UCAST_BUFFER,
+ WMI_10X_PDEV_PARAM_PEER_STA_PS_STATECHG_ENABLE,
+ WMI_10X_PDEV_PARAM_RTS_FIXED_RATE,
+ WMI_10X_PDEV_PARAM_CAL_PERIOD
};
struct wmi_pdev_set_param_cmd {
@@ -2722,6 +2818,9 @@ struct wmi_pdev_set_param_cmd {
__le32 param_value;
} __packed;
+/* valid period is 1 ~ 60000ms, unit in millisecond */
+#define WMI_PDEV_PARAM_CAL_PERIOD_MAX 60000
+
struct wmi_pdev_get_tpc_config_cmd {
/* parameter */
__le32 param;
@@ -2841,14 +2940,14 @@ struct wmi_wmm_params_arg {
u32 no_ack;
};
-struct wmi_pdev_set_wmm_params_arg {
+struct wmi_wmm_params_all_arg {
struct wmi_wmm_params_arg ac_be;
struct wmi_wmm_params_arg ac_bk;
struct wmi_wmm_params_arg ac_vi;
struct wmi_wmm_params_arg ac_vo;
};
-struct wal_dbg_tx_stats {
+struct wmi_pdev_stats_tx {
/* Num HTT cookies queued to dispatch list */
__le32 comp_queued;
@@ -2918,7 +3017,7 @@ struct wal_dbg_tx_stats {
__le32 txop_ovf;
} __packed;
-struct wal_dbg_rx_stats {
+struct wmi_pdev_stats_rx {
/* Cnts any change in ring routing mid-ppdu */
__le32 mid_ppdu_route_change;
@@ -2952,17 +3051,11 @@ struct wal_dbg_rx_stats {
__le32 mpdu_errs;
} __packed;
-struct wal_dbg_peer_stats {
+struct wmi_pdev_stats_peer {
/* REMOVE THIS ONCE REAL PEER STAT COUNTERS ARE ADDED */
__le32 dummy;
} __packed;
-struct wal_dbg_stats {
- struct wal_dbg_tx_stats tx;
- struct wal_dbg_rx_stats rx;
- struct wal_dbg_peer_stats peer;
-} __packed;
-
enum wmi_stats_id {
WMI_REQUEST_PEER_STAT = 0x01,
WMI_REQUEST_AP_STAT = 0x02
@@ -3029,23 +3122,38 @@ struct wmi_stats_event {
u8 data[0];
} __packed;
+struct wmi_10_2_stats_event {
+ __le32 stats_id; /* %WMI_REQUEST_ */
+ __le32 num_pdev_stats;
+ __le32 num_pdev_ext_stats;
+ __le32 num_vdev_stats;
+ __le32 num_peer_stats;
+ __le32 num_bcnflt_stats;
+ u8 data[0];
+} __packed;
+
/*
* PDEV statistics
* TODO: add all PDEV stats here
*/
+struct wmi_pdev_stats_base {
+ __le32 chan_nf;
+ __le32 tx_frame_count;
+ __le32 rx_frame_count;
+ __le32 rx_clear_count;
+ __le32 cycle_count;
+ __le32 phy_err_count;
+ __le32 chan_tx_pwr;
+} __packed;
+
struct wmi_pdev_stats {
- __le32 chan_nf; /* Channel noise floor */
- __le32 tx_frame_count; /* TX frame count */
- __le32 rx_frame_count; /* RX frame count */
- __le32 rx_clear_count; /* rx clear count */
- __le32 cycle_count; /* cycle count */
- __le32 phy_err_count; /* Phy error count */
- __le32 chan_tx_pwr; /* channel tx power */
- struct wal_dbg_stats wal; /* WAL dbg stats */
+ struct wmi_pdev_stats_base base;
+ struct wmi_pdev_stats_tx tx;
+ struct wmi_pdev_stats_rx rx;
+ struct wmi_pdev_stats_peer peer;
} __packed;
-struct wmi_10x_pdev_stats {
- struct wmi_pdev_stats old;
+struct wmi_pdev_stats_extra {
__le32 ack_rx_bad;
__le32 rts_bad;
__le32 rts_good;
@@ -3054,6 +3162,30 @@ struct wmi_10x_pdev_stats {
__le32 mib_int_count;
} __packed;
+struct wmi_10x_pdev_stats {
+ struct wmi_pdev_stats_base base;
+ struct wmi_pdev_stats_tx tx;
+ struct wmi_pdev_stats_rx rx;
+ struct wmi_pdev_stats_peer peer;
+ struct wmi_pdev_stats_extra extra;
+} __packed;
+
+struct wmi_pdev_stats_mem {
+ __le32 dram_free;
+ __le32 iram_free;
+} __packed;
+
+struct wmi_10_2_pdev_stats {
+ struct wmi_pdev_stats_base base;
+ struct wmi_pdev_stats_tx tx;
+ __le32 mc_drop;
+ struct wmi_pdev_stats_rx rx;
+ __le32 pdev_rx_timeout;
+ struct wmi_pdev_stats_mem mem;
+ struct wmi_pdev_stats_peer peer;
+ struct wmi_pdev_stats_extra extra;
+} __packed;
+
/*
* VDEV statistics
* TODO: add all VDEV stats here
@@ -3077,6 +3209,32 @@ struct wmi_10x_peer_stats {
__le32 peer_rx_rate;
} __packed;
+struct wmi_10_2_peer_stats {
+ struct wmi_peer_stats old;
+ __le32 peer_rx_rate;
+ __le32 current_per;
+ __le32 retries;
+ __le32 tx_rate_count;
+ __le32 max_4ms_frame_len;
+ __le32 total_sub_frames;
+ __le32 tx_bytes;
+ __le32 num_pkt_loss_overflow[4];
+ __le32 num_pkt_loss_excess_retry[4];
+} __packed;
+
+struct wmi_10_2_4_peer_stats {
+ struct wmi_10_2_peer_stats common;
+ __le32 unknown_value; /* FIXME: what is this word? */
+} __packed;
+
+struct wmi_10_2_pdev_ext_stats {
+ __le32 rx_rssi_comb;
+ __le32 rx_rssi[4];
+ __le32 rx_mcs[10];
+ __le32 tx_mcs[10];
+ __le32 ack_rssi;
+} __packed;
+
struct wmi_vdev_create_cmd {
__le32 vdev_id;
__le32 vdev_type;
@@ -3930,6 +4088,13 @@ enum wmi_sta_ps_param_pspoll_count {
* Values greater than 0 indicate the maximum numer of PS-Poll frames
* FW will send before waking up.
*/
+
+ /* When u-APSD is enabled the firmware will be very reluctant to exit
+ * STA PS. This could result in very poor Rx performance with STA doing
+ * PS-Poll for each and every buffered frame. This value is a bit
+ * arbitrary.
+ */
+ WMI_STA_PS_PSPOLL_COUNT_UAPSD = 3,
};
/*
@@ -3955,6 +4120,30 @@ enum wmi_sta_ps_param_uapsd {
WMI_STA_PS_UAPSD_AC3_TRIGGER_EN = (1 << 7),
};
+#define WMI_STA_UAPSD_MAX_INTERVAL_MSEC UINT_MAX
+
+struct wmi_sta_uapsd_auto_trig_param {
+ __le32 wmm_ac;
+ __le32 user_priority;
+ __le32 service_interval;
+ __le32 suspend_interval;
+ __le32 delay_interval;
+};
+
+struct wmi_sta_uapsd_auto_trig_cmd_fixed_param {
+ __le32 vdev_id;
+ struct wmi_mac_addr peer_macaddr;
+ __le32 num_ac;
+};
+
+struct wmi_sta_uapsd_auto_trig_arg {
+ u32 wmm_ac;
+ u32 user_priority;
+ u32 service_interval;
+ u32 suspend_interval;
+ u32 delay_interval;
+};
+
enum wmi_sta_powersave_param {
/*
* Controls how frames are retrievd from AP while STA is sleeping
@@ -4120,7 +4309,7 @@ struct wmi_bcn_info {
struct wmi_host_swba_event {
__le32 vdev_map;
- struct wmi_bcn_info bcn_info[1];
+ struct wmi_bcn_info bcn_info[0];
} __packed;
#define WMI_MAX_AP_VDEV 16
@@ -4325,7 +4514,7 @@ struct wmi_peer_set_q_empty_callback_cmd {
#define WMI_PEER_SPATIAL_MUX 0x00200000
#define WMI_PEER_VHT 0x02000000
#define WMI_PEER_80MHZ 0x04000000
-#define WMI_PEER_PMF 0x08000000
+#define WMI_PEER_VHT_2G 0x08000000
/*
* Peer rate capabilities.
@@ -4476,6 +4665,11 @@ enum wmi_sta_keepalive_method {
WMI_STA_KEEPALIVE_METHOD_UNSOLICITATED_ARP_RESPONSE = 2,
};
+#define WMI_STA_KEEPALIVE_INTERVAL_DISABLE 0
+
+/* Firmware crashes if keepalive interval exceeds this limit */
+#define WMI_STA_KEEPALIVE_INTERVAL_MAX_SECONDS 0xffff
+
/* note: ip4 addresses are in network byte order, i.e. big endian */
struct wmi_sta_keepalive_arp_resp {
__be32 src_ip4_addr;
@@ -4491,6 +4685,16 @@ struct wmi_sta_keepalive_cmd {
struct wmi_sta_keepalive_arp_resp arp_resp;
} __packed;
+struct wmi_sta_keepalive_arg {
+ u32 vdev_id;
+ u32 enabled;
+ u32 method;
+ u32 interval;
+ __be32 src_ip4_addr;
+ __be32 dest_ip4_addr;
+ const u8 dest_mac_addr[ETH_ALEN];
+};
+
enum wmi_force_fw_hang_type {
WMI_FORCE_FW_HANG_ASSERT = 1,
WMI_FORCE_FW_HANG_NO_DETECT,
@@ -4567,6 +4771,58 @@ struct wmi_dbglog_cfg_cmd {
#define WMI_MAX_MEM_REQS 16
+struct wmi_scan_ev_arg {
+ __le32 event_type; /* %WMI_SCAN_EVENT_ */
+ __le32 reason; /* %WMI_SCAN_REASON_ */
+ __le32 channel_freq; /* only valid for WMI_SCAN_EVENT_FOREIGN_CHANNEL */
+ __le32 scan_req_id;
+ __le32 scan_id;
+ __le32 vdev_id;
+};
+
+struct wmi_mgmt_rx_ev_arg {
+ __le32 channel;
+ __le32 snr;
+ __le32 rate;
+ __le32 phy_mode;
+ __le32 buf_len;
+ __le32 status; /* %WMI_RX_STATUS_ */
+};
+
+struct wmi_ch_info_ev_arg {
+ __le32 err_code;
+ __le32 freq;
+ __le32 cmd_flags;
+ __le32 noise_floor;
+ __le32 rx_clear_count;
+ __le32 cycle_count;
+};
+
+struct wmi_vdev_start_ev_arg {
+ __le32 vdev_id;
+ __le32 req_id;
+ __le32 resp_type; /* %WMI_VDEV_RESP_ */
+ __le32 status;
+};
+
+struct wmi_peer_kick_ev_arg {
+ const u8 *mac_addr;
+};
+
+struct wmi_swba_ev_arg {
+ __le32 vdev_map;
+ const struct wmi_tim_info *tim_info[WMI_MAX_AP_VDEV];
+ const struct wmi_p2p_noa_info *noa_info[WMI_MAX_AP_VDEV];
+};
+
+struct wmi_phyerr_ev_arg {
+ __le32 num_phyerrs;
+ __le32 tsf_l32;
+ __le32 tsf_u32;
+ __le32 buf_len;
+ const struct wmi_phyerr *phyerrs;
+};
+
struct wmi_svc_rdy_ev_arg {
__le32 min_tx_power;
__le32 max_tx_power;
@@ -4574,6 +4830,7 @@ struct wmi_svc_rdy_ev_arg {
__le32 vht_cap;
__le32 sw_ver0;
__le32 sw_ver1;
+ __le32 fw_build;
__le32 phy_capab;
__le32 num_rf_chains;
__le32 eeprom_rd;
@@ -4583,83 +4840,99 @@ struct wmi_svc_rdy_ev_arg {
const struct wlan_host_mem_req *mem_reqs[WMI_MAX_MEM_REQS];
};
+struct wmi_rdy_ev_arg {
+ __le32 sw_version;
+ __le32 abi_version;
+ __le32 status;
+ const u8 *mac_addr;
+};
+
+struct wmi_pdev_temperature_event {
+ /* temperature value in Celcius degree */
+ __le32 temperature;
+} __packed;
+
struct ath10k;
struct ath10k_vif;
-struct ath10k_fw_stats;
+struct ath10k_fw_stats_pdev;
+struct ath10k_fw_stats_peer;
int ath10k_wmi_attach(struct ath10k *ar);
void ath10k_wmi_detach(struct ath10k *ar);
int ath10k_wmi_wait_for_service_ready(struct ath10k *ar);
int ath10k_wmi_wait_for_unified_ready(struct ath10k *ar);
+struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
int ath10k_wmi_connect(struct ath10k *ar);
struct sk_buff *ath10k_wmi_alloc_skb(struct ath10k *ar, u32 len);
int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id);
-
-int ath10k_wmi_pdev_suspend_target(struct ath10k *ar, u32 suspend_opt);
-int ath10k_wmi_pdev_resume_target(struct ath10k *ar);
-int ath10k_wmi_pdev_set_regdomain(struct ath10k *ar, u16 rd, u16 rd2g,
- u16 rd5g, u16 ctl2g, u16 ctl5g,
- enum wmi_dfs_region dfs_reg);
-int ath10k_wmi_pdev_set_param(struct ath10k *ar, u32 id, u32 value);
-int ath10k_wmi_cmd_init(struct ath10k *ar);
-int ath10k_wmi_start_scan(struct ath10k *ar, const struct wmi_start_scan_arg *);
+int ath10k_wmi_cmd_send_nowait(struct ath10k *ar, struct sk_buff *skb,
+ u32 cmd_id);
void ath10k_wmi_start_scan_init(struct ath10k *ar, struct wmi_start_scan_arg *);
-int ath10k_wmi_stop_scan(struct ath10k *ar,
- const struct wmi_stop_scan_arg *arg);
-int ath10k_wmi_vdev_create(struct ath10k *ar, u32 vdev_id,
- enum wmi_vdev_type type,
- enum wmi_vdev_subtype subtype,
- const u8 macaddr[ETH_ALEN]);
-int ath10k_wmi_vdev_delete(struct ath10k *ar, u32 vdev_id);
-int ath10k_wmi_vdev_start(struct ath10k *ar,
- const struct wmi_vdev_start_request_arg *);
-int ath10k_wmi_vdev_restart(struct ath10k *ar,
- const struct wmi_vdev_start_request_arg *);
-int ath10k_wmi_vdev_stop(struct ath10k *ar, u32 vdev_id);
-int ath10k_wmi_vdev_up(struct ath10k *ar, u32 vdev_id, u32 aid,
- const u8 *bssid);
-int ath10k_wmi_vdev_down(struct ath10k *ar, u32 vdev_id);
-int ath10k_wmi_vdev_set_param(struct ath10k *ar, u32 vdev_id,
- u32 param_id, u32 param_value);
-int ath10k_wmi_vdev_install_key(struct ath10k *ar,
- const struct wmi_vdev_install_key_arg *arg);
-int ath10k_wmi_vdev_spectral_conf(struct ath10k *ar,
- const struct wmi_vdev_spectral_conf_arg *arg);
-int ath10k_wmi_vdev_spectral_enable(struct ath10k *ar, u32 vdev_id, u32 trigger,
- u32 enable);
-int ath10k_wmi_peer_create(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN]);
-int ath10k_wmi_peer_delete(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN]);
-int ath10k_wmi_peer_flush(struct ath10k *ar, u32 vdev_id,
- const u8 peer_addr[ETH_ALEN], u32 tid_bitmap);
-int ath10k_wmi_peer_set_param(struct ath10k *ar, u32 vdev_id,
- const u8 *peer_addr,
- enum wmi_peer_param param_id, u32 param_value);
-int ath10k_wmi_peer_assoc(struct ath10k *ar,
- const struct wmi_peer_assoc_complete_arg *arg);
-int ath10k_wmi_set_psmode(struct ath10k *ar, u32 vdev_id,
- enum wmi_sta_ps_mode psmode);
-int ath10k_wmi_set_sta_ps_param(struct ath10k *ar, u32 vdev_id,
- enum wmi_sta_powersave_param param_id,
- u32 value);
-int ath10k_wmi_set_ap_ps_param(struct ath10k *ar, u32 vdev_id, const u8 *mac,
- enum wmi_ap_ps_peer_param param_id, u32 value);
-int ath10k_wmi_scan_chan_list(struct ath10k *ar,
- const struct wmi_scan_chan_list_arg *arg);
-int ath10k_wmi_beacon_send_ref_nowait(struct ath10k_vif *arvif);
-int ath10k_wmi_pdev_set_wmm_params(struct ath10k *ar,
- const struct wmi_pdev_set_wmm_params_arg *arg);
-int ath10k_wmi_request_stats(struct ath10k *ar, enum wmi_stats_id stats_id);
-int ath10k_wmi_force_fw_hang(struct ath10k *ar,
- enum wmi_force_fw_hang_type type, u32 delay_ms);
-int ath10k_wmi_mgmt_tx(struct ath10k *ar, struct sk_buff *skb);
-int ath10k_wmi_dbglog_cfg(struct ath10k *ar, u32 module_enable);
-int ath10k_wmi_pull_fw_stats(struct ath10k *ar, struct sk_buff *skb,
- struct ath10k_fw_stats *stats);
-int ath10k_wmi_pdev_pktlog_enable(struct ath10k *ar, u32 ev_list);
-int ath10k_wmi_pdev_pktlog_disable(struct ath10k *ar);
+
+void ath10k_wmi_pull_pdev_stats_base(const struct wmi_pdev_stats_base *src,
+ struct ath10k_fw_stats_pdev *dst);
+void ath10k_wmi_pull_pdev_stats_tx(const struct wmi_pdev_stats_tx *src,
+ struct ath10k_fw_stats_pdev *dst);
+void ath10k_wmi_pull_pdev_stats_rx(const struct wmi_pdev_stats_rx *src,
+ struct ath10k_fw_stats_pdev *dst);
+void ath10k_wmi_pull_pdev_stats_extra(const struct wmi_pdev_stats_extra *src,
+ struct ath10k_fw_stats_pdev *dst);
+void ath10k_wmi_pull_peer_stats(const struct wmi_peer_stats *src,
+ struct ath10k_fw_stats_peer *dst);
+void ath10k_wmi_put_host_mem_chunks(struct ath10k *ar,
+ struct wmi_host_mem_chunks *chunks);
+void ath10k_wmi_put_start_scan_common(struct wmi_start_scan_common *cmn,
+ const struct wmi_start_scan_arg *arg);
+void ath10k_wmi_set_wmm_param(struct wmi_wmm_params *params,
+ const struct wmi_wmm_params_arg *arg);
+void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch,
+ const struct wmi_channel_arg *arg);
+int ath10k_wmi_start_scan_verify(const struct wmi_start_scan_arg *arg);
+
+int ath10k_wmi_event_scan(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_event_mgmt_rx(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_chan_info(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_echo(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_event_debug_mesg(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_update_stats(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_start_resp(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_stopped(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_peer_sta_kickout(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_host_swba(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_tbttoffset_update(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_dfs(struct ath10k *ar,
+ const struct wmi_phyerr *phyerr, u64 tsf);
+void ath10k_wmi_event_spectral_scan(struct ath10k *ar,
+ const struct wmi_phyerr *phyerr,
+ u64 tsf);
+void ath10k_wmi_event_phyerr(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_roam(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_profile_match(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_debug_print(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_pdev_qvit(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_wlan_profile_data(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_rtt_measurement_report(struct ath10k *ar,
+ struct sk_buff *skb);
+void ath10k_wmi_event_tsf_measurement_report(struct ath10k *ar,
+ struct sk_buff *skb);
+void ath10k_wmi_event_rtt_error_report(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_wow_wakeup_host(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_dcs_interference(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_pdev_tpc_config(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_pdev_ftm_intg(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_gtk_offload_status(struct ath10k *ar,
+ struct sk_buff *skb);
+void ath10k_wmi_event_gtk_rekey_fail(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_delba_complete(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_addba_complete(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_install_key_complete(struct ath10k *ar,
+ struct sk_buff *skb);
+void ath10k_wmi_event_inst_rssi_stats(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_standby_req(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_vdev_resume_req(struct ath10k *ar, struct sk_buff *skb);
+void ath10k_wmi_event_service_ready(struct ath10k *ar, struct sk_buff *skb);
+int ath10k_wmi_event_ready(struct ath10k *ar, struct sk_buff *skb);
#endif /* _WMI_H_ */
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
index 8f387cf67340..2ca88b593e4c 100644
--- a/drivers/net/wireless/ath/ath5k/ahb.c
+++ b/drivers/net/wireless/ath/ath5k/ahb.c
@@ -227,7 +227,6 @@ static struct platform_driver ath_ahb_driver = {
.remove = ath_ahb_remove,
.driver = {
.name = "ar231x-wmac",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/net/wireless/ath/ath5k/mac80211-ops.c b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
index 19eab2a69ad5..3b4a6463d87a 100644
--- a/drivers/net/wireless/ath/ath5k/mac80211-ops.c
+++ b/drivers/net/wireless/ath/ath5k/mac80211-ops.c
@@ -672,10 +672,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
spin_lock_bh(&common->cc_lock);
ath_hw_cycle_counters_update(common);
if (cc->cycles > 0) {
- ah->survey.channel_time += cc->cycles / div;
- ah->survey.channel_time_busy += cc->rx_busy / div;
- ah->survey.channel_time_rx += cc->rx_frame / div;
- ah->survey.channel_time_tx += cc->tx_frame / div;
+ ah->survey.time += cc->cycles / div;
+ ah->survey.time_busy += cc->rx_busy / div;
+ ah->survey.time_rx += cc->rx_frame / div;
+ ah->survey.time_tx += cc->tx_frame / div;
}
memset(cc, 0, sizeof(*cc));
spin_unlock_bh(&common->cc_lock);
@@ -686,10 +686,10 @@ ath5k_get_survey(struct ieee80211_hw *hw, int idx, struct survey_info *survey)
survey->noise = ah->ah_noise_floor;
survey->filled = SURVEY_INFO_NOISE_DBM |
SURVEY_INFO_IN_USE |
- SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX |
- SURVEY_INFO_CHANNEL_TIME_TX;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_RX |
+ SURVEY_INFO_TIME_TX;
return 0;
}
diff --git a/drivers/net/wireless/ath/ath5k/pcu.c b/drivers/net/wireless/ath/ath5k/pcu.c
index c60d36aa13e2..bf29da5e90da 100644
--- a/drivers/net/wireless/ath/ath5k/pcu.c
+++ b/drivers/net/wireless/ath/ath5k/pcu.c
@@ -912,6 +912,7 @@ ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
| (ah->ah_version == AR5K_AR5210 ?
AR5K_STA_ID1_PWR_SV : 0);
+ /* fall through */
case NL80211_IFTYPE_MONITOR:
pcu_reg |= AR5K_STA_ID1_KEYSRCH_MODE
| (ah->ah_version == AR5K_AR5210 ?
diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c
index a3399c4f13a9..b9b651ea9851 100644
--- a/drivers/net/wireless/ath/ath5k/reset.c
+++ b/drivers/net/wireless/ath/ath5k/reset.c
@@ -478,7 +478,7 @@ ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
regval = ioread32(reg);
iowrite32(regval | val, reg);
regval = ioread32(reg);
- usleep_range(100, 150);
+ udelay(100); /* NB: should be atomic */
/* Bring BB/MAC out of reset */
iowrite32(regval & ~val, reg);
diff --git a/drivers/net/wireless/ath/ath6kl/cfg80211.c b/drivers/net/wireless/ath/ath6kl/cfg80211.c
index 7a5337877a0c..85da63a67faf 100644
--- a/drivers/net/wireless/ath/ath6kl/cfg80211.c
+++ b/drivers/net/wireless/ath/ath6kl/cfg80211.c
@@ -1799,20 +1799,20 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
if (vif->target_stats.rx_byte) {
sinfo->rx_bytes = vif->target_stats.rx_byte;
- sinfo->filled |= STATION_INFO_RX_BYTES64;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
sinfo->rx_packets = vif->target_stats.rx_pkt;
- sinfo->filled |= STATION_INFO_RX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
}
if (vif->target_stats.tx_byte) {
sinfo->tx_bytes = vif->target_stats.tx_byte;
- sinfo->filled |= STATION_INFO_TX_BYTES64;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES64);
sinfo->tx_packets = vif->target_stats.tx_pkt;
- sinfo->filled |= STATION_INFO_TX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
}
sinfo->signal = vif->target_stats.cs_rssi;
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
rate = vif->target_stats.tx_ucast_rate;
@@ -1827,6 +1827,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
}
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
+ sinfo->txrate.bw = RATE_INFO_BW_20;
} else if (is_rate_ht40(rate, &mcs, &sgi)) {
if (sgi) {
sinfo->txrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
@@ -1835,7 +1836,7 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
sinfo->txrate.mcs = mcs;
}
- sinfo->txrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ sinfo->txrate.bw = RATE_INFO_BW_40;
sinfo->txrate.flags |= RATE_INFO_FLAGS_MCS;
} else {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
@@ -1844,12 +1845,12 @@ static int ath6kl_get_station(struct wiphy *wiphy, struct net_device *dev,
return 0;
}
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
if (test_bit(CONNECTED, &vif->flags) &&
test_bit(DTIM_PERIOD_AVAIL, &vif->flags) &&
vif->nw_type == INFRA_NETWORK) {
- sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
sinfo->bss_param.flags = 0;
sinfo->bss_param.dtim_period = vif->assoc_bss_dtim_period;
sinfo->bss_param.beacon_interval = vif->assoc_bss_beacon_int;
diff --git a/drivers/net/wireless/ath/ath6kl/main.c b/drivers/net/wireless/ath/ath6kl/main.c
index 933aef025698..b42ba46b5030 100644
--- a/drivers/net/wireless/ath/ath6kl/main.c
+++ b/drivers/net/wireless/ath/ath6kl/main.c
@@ -488,7 +488,6 @@ void ath6kl_connect_ap_mode_sta(struct ath6kl_vif *vif, u16 aid, u8 *mac_addr,
sinfo.assoc_req_ies = ies;
sinfo.assoc_req_ies_len = ies_len;
- sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
cfg80211_new_sta(vif->ndev, mac_addr, &sinfo, GFP_KERNEL);
diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c
index e000c4c27881..bd4a1a655f42 100644
--- a/drivers/net/wireless/ath/ath9k/ahb.c
+++ b/drivers/net/wireless/ath/ath9k/ahb.c
@@ -43,6 +43,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = {
.name = "qca953x_wmac",
.driver_data = AR9300_DEVID_AR953X,
},
+ {
+ .name = "qca956x_wmac",
+ .driver_data = AR9300_DEVID_QCA956X,
+ },
{},
};
diff --git a/drivers/net/wireless/ath/ath9k/ani.c b/drivers/net/wireless/ath/ath9k/ani.c
index ba502a2d199b..ca01d17d130f 100644
--- a/drivers/net/wireless/ath/ath9k/ani.c
+++ b/drivers/net/wireless/ath/ath9k/ani.c
@@ -259,7 +259,8 @@ static void ath9k_hw_set_cck_nil(struct ath_hw *ah, u_int8_t immunityLevel,
entry_cck->fir_step_level);
/* Skip MRC CCK for pre AR9003 families */
- if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) || AR_SREV_9565(ah))
+ if (!AR_SREV_9300_20_OR_LATER(ah) || AR_SREV_9485(ah) ||
+ AR_SREV_9565(ah) || AR_SREV_9561(ah))
return;
if (aniState->mrcCCK != entry_cck->mrc_cck_on)
diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
index 5829074208fa..f273427fdd29 100644
--- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c
@@ -22,6 +22,21 @@
/* All code below is for AR5008, AR9001, AR9002 */
+#define AR5008_OFDM_RATES 8
+#define AR5008_HT_SS_RATES 8
+#define AR5008_HT_DS_RATES 8
+
+#define AR5008_HT20_SHIFT 16
+#define AR5008_HT40_SHIFT 24
+
+#define AR5008_11NA_OFDM_SHIFT 0
+#define AR5008_11NA_HT_SS_SHIFT 8
+#define AR5008_11NA_HT_DS_SHIFT 16
+
+#define AR5008_11NG_OFDM_SHIFT 4
+#define AR5008_11NG_HT_SS_SHIFT 12
+#define AR5008_11NG_HT_DS_SHIFT 20
+
static const int firstep_table[] =
/* level: 0 1 2 3 4 5 6 7 8 */
{ -4, -2, 0, 2, 4, 6, 8, 10, 12 }; /* lvl 0-8, default 2 */
@@ -1235,6 +1250,71 @@ static void ar5008_hw_set_radar_conf(struct ath_hw *ah)
conf->radar_inband = 8;
}
+static void ar5008_hw_init_txpower_cck(struct ath_hw *ah, int16_t *rate_array)
+{
+#define CCK_DELTA(x) ((OLC_FOR_AR9280_20_LATER) ? max((x) - 2, 0) : (x))
+ ah->tx_power[0] = CCK_DELTA(rate_array[rate1l]);
+ ah->tx_power[1] = CCK_DELTA(min(rate_array[rate2l],
+ rate_array[rate2s]));
+ ah->tx_power[2] = CCK_DELTA(min(rate_array[rate5_5l],
+ rate_array[rate5_5s]));
+ ah->tx_power[3] = CCK_DELTA(min(rate_array[rate11l],
+ rate_array[rate11s]));
+#undef CCK_DELTA
+}
+
+static void ar5008_hw_init_txpower_ofdm(struct ath_hw *ah, int16_t *rate_array,
+ int offset)
+{
+ int i, idx = 0;
+
+ for (i = offset; i < offset + AR5008_OFDM_RATES; i++) {
+ ah->tx_power[i] = rate_array[idx];
+ idx++;
+ }
+}
+
+static void ar5008_hw_init_txpower_ht(struct ath_hw *ah, int16_t *rate_array,
+ int ss_offset, int ds_offset,
+ bool is_40, int ht40_delta)
+{
+ int i, mcs_idx = (is_40) ? AR5008_HT40_SHIFT : AR5008_HT20_SHIFT;
+
+ for (i = ss_offset; i < ss_offset + AR5008_HT_SS_RATES; i++) {
+ ah->tx_power[i] = rate_array[mcs_idx] + ht40_delta;
+ mcs_idx++;
+ }
+ memcpy(&ah->tx_power[ds_offset], &ah->tx_power[ss_offset],
+ AR5008_HT_SS_RATES);
+}
+
+void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
+ struct ath9k_channel *chan, int ht40_delta)
+{
+ if (IS_CHAN_5GHZ(chan)) {
+ ar5008_hw_init_txpower_ofdm(ah, rate_array,
+ AR5008_11NA_OFDM_SHIFT);
+ if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
+ ar5008_hw_init_txpower_ht(ah, rate_array,
+ AR5008_11NA_HT_SS_SHIFT,
+ AR5008_11NA_HT_DS_SHIFT,
+ IS_CHAN_HT40(chan),
+ ht40_delta);
+ }
+ } else {
+ ar5008_hw_init_txpower_cck(ah, rate_array);
+ ar5008_hw_init_txpower_ofdm(ah, rate_array,
+ AR5008_11NG_OFDM_SHIFT);
+ if (IS_CHAN_HT20(chan) || IS_CHAN_HT40(chan)) {
+ ar5008_hw_init_txpower_ht(ah, rate_array,
+ AR5008_11NG_HT_SS_SHIFT,
+ AR5008_11NG_HT_DS_SHIFT,
+ IS_CHAN_HT40(chan),
+ ht40_delta);
+ }
+ }
+}
+
int ar5008_hw_attach_phy_ops(struct ath_hw *ah)
{
struct ath_hw_private_ops *priv_ops = ath9k_hw_private_ops(ah);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_calib.c b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
index 06ab71db6e80..174442beb952 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_calib.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_calib.c
@@ -1203,24 +1203,41 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
{
int offset[8] = {0}, total = 0, test;
- int agc_out, i;
+ int agc_out, i, peak_detect_threshold;
+ if (AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ peak_detect_threshold = 8;
+ else
+ peak_detect_threshold = 0;
+
+ /*
+ * Turn off LNA/SW.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);
- if (is_2g)
- REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
- AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
- else
- REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
- AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
+ if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9330_11(ah)) {
+ if (is_2g)
+ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+ AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
+ else
+ REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+ AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
+ }
+
+ /*
+ * Turn off RXON.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON, 0x0);
+ /*
+ * Turn on AGC for cal.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
@@ -1228,16 +1245,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);
- if (AR_SREV_9330_11(ah)) {
+ if (AR_SREV_9330_11(ah))
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, 0x0);
- } else {
+
+ if (AR_SREV_9003_PCOEM(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
if (is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
- AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0);
+ AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR,
+ peak_detect_threshold);
else
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
- AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0);
+ AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR,
+ peak_detect_threshold);
}
for (i = 6; i > 0; i--) {
@@ -1266,10 +1286,19 @@ static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);
+ /*
+ * Turn on LNA.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);
+ /*
+ * Turn off RXON.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
AR_PHY_65NM_RXTX2_RXON_OVR, 0);
+ /*
+ * Turn off peak detect calibration.
+ */
REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
}
@@ -1611,8 +1640,14 @@ static bool ar9003_hw_init_cal_soc(struct ath_hw *ah,
skip_tx_iqcal:
if (run_agc_cal || !(ah->ah_flags & AH_FASTCC)) {
- if (AR_SREV_9330_11(ah))
- ar9003_hw_manual_peak_cal(ah, 0, IS_CHAN_2GHZ(chan));
+ if (AR_SREV_9330_11(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+ for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+ if (!(ah->rxchainmask & (1 << i)))
+ continue;
+ ar9003_hw_manual_peak_cal(ah, i,
+ IS_CHAN_2GHZ(chan));
+ }
+ }
/*
* For non-AR9550 chips, we just trigger AGC calibration
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
index 08225a0067c2..8b4561e8ce1a 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
@@ -3536,7 +3536,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
int bias = ar9003_modal_header(ah, is2ghz)->xpaBiasLvl;
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
- AR_SREV_9531(ah))
+ AR_SREV_9531(ah) || AR_SREV_9561(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
else if (AR_SREV_9462(ah) || AR_SREV_9550(ah) || AR_SREV_9565(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
@@ -3599,7 +3599,7 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_AR9462_ALL, value);
- } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_AR9550_ALL, value);
} else
@@ -3929,9 +3929,13 @@ void ar9003_hw_internal_regulator_apply(struct ath_hw *ah)
REG_WRITE(ah, AR_PHY_PMU2, reg_pmu_set);
if (!is_pmu_set(ah, AR_PHY_PMU2, reg_pmu_set))
return;
- } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+ } else if (AR_SREV_9462(ah) || AR_SREV_9565(ah) ||
+ AR_SREV_9561(ah)) {
reg_val = le32_to_cpu(pBase->swreg);
REG_WRITE(ah, AR_PHY_PMU1, reg_val);
+
+ if (AR_SREV_9561(ah))
+ REG_WRITE(ah, AR_PHY_PMU2, 0x10200000);
} else {
/* Internal regulator is ON. Write swreg register. */
reg_val = le32_to_cpu(pBase->swreg);
@@ -4034,7 +4038,8 @@ static void ar9003_hw_xpa_timing_control_apply(struct ath_hw *ah, bool is2ghz)
if (!AR_SREV_9300(ah) &&
!AR_SREV_9340(ah) &&
!AR_SREV_9580(ah) &&
- !AR_SREV_9531(ah))
+ !AR_SREV_9531(ah) &&
+ !AR_SREV_9561(ah))
return;
xpa_ctl = ar9003_modal_header(ah, is2ghz)->txFrameToXpaOn;
@@ -4812,7 +4817,7 @@ static void ar9003_hw_power_control_override(struct ath_hw *ah,
}
tempslope:
- if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
u8 txmask = (eep->baseEepHeader.txrxMask & 0xf0) >> 4;
/*
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_hw.c b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
index 06ad2172030e..4335ccbe7d7e 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_hw.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_hw.c
@@ -29,6 +29,7 @@
#include "ar9565_1p0_initvals.h"
#include "ar9565_1p1_initvals.h"
#include "ar953x_initvals.h"
+#include "ar956x_initvals.h"
/* General hardware code for the AR9003 hadware family */
@@ -358,6 +359,40 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->iniModesFastClock,
qca953x_1p0_modes_fast_clock);
+ } else if (AR_SREV_9561(ah)) {
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
+ qca956x_1p0_mac_core);
+ INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
+ qca956x_1p0_mac_postamble);
+
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
+ qca956x_1p0_baseband_core);
+ INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
+ qca956x_1p0_baseband_postamble);
+
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
+ qca956x_1p0_radio_core);
+ INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
+ qca956x_1p0_radio_postamble);
+
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
+ qca956x_1p0_soc_preamble);
+ INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
+ qca956x_1p0_soc_postamble);
+
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ qca956x_1p0_common_wo_xlna_rx_gain_table);
+ INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+ qca956x_1p0_common_wo_xlna_rx_gain_bounds);
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_tx_gain_table);
+
+ INIT_INI_ARRAY(&ah->ini_dfs,
+ qca956x_1p0_baseband_postamble_dfs_channel);
+ INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+ qca956x_1p0_baseband_core_txfir_coeff_japan_2484);
+ INIT_INI_ARRAY(&ah->iniModesFastClock,
+ qca956x_1p0_modes_fast_clock);
} else if (AR_SREV_9580(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -544,6 +579,9 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
else if (AR_SREV_9531_20(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
qca953x_2p0_modes_xpa_tx_gain_table);
+ else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_xpa_tx_gain_table);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_lowest_ob_db_tx_gain_table);
@@ -594,7 +632,10 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
else
INIT_INI_ARRAY(&ah->iniModesTxGain,
qca953x_1p0_modes_no_xpa_tx_gain_table);
- } else if (AR_SREV_9462_21(ah))
+ } else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_tx_gain_table);
+ else if (AR_SREV_9462_21(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9462_2p1_modes_high_ob_db_tx_gain);
else if (AR_SREV_9462_20(ah))
@@ -628,6 +669,9 @@ static void ar9003_tx_gain_table_mode2(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_low_ob_db_tx_gain_table);
+ else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table);
else if (AR_SREV_9565_11(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9565_1p1_modes_low_ob_db_tx_gain_table);
@@ -699,6 +743,9 @@ static void ar9003_tx_gain_table_mode5(struct ath_hw *ah)
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_type5_tx_gain_table);
+ else if (AR_SREV_9561(ah))
+ INIT_INI_ARRAY(&ah->iniModesTxGain,
+ qca956x_1p0_modes_no_xpa_green_tx_gain_table);
else if (AR_SREV_9300_22(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9300Modes_type5_tx_gain_table_2p2);
@@ -770,6 +817,13 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
qca953x_1p0_common_rx_gain_table);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
qca953x_1p0_common_rx_gain_bounds);
+ } else if (AR_SREV_9561(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ qca956x_1p0_common_rx_gain_table);
+ INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+ qca956x_1p0_common_rx_gain_bounds);
+ INIT_INI_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
+ qca956x_1p0_xlna_only);
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_rx_gain_table);
@@ -825,6 +879,11 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
qca953x_2p0_common_wo_xlna_rx_gain_table);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
qca953x_2p0_common_wo_xlna_rx_gain_bounds);
+ } else if (AR_SREV_9561(ah)) {
+ INIT_INI_ARRAY(&ah->iniModesRxGain,
+ qca956x_1p0_common_wo_xlna_rx_gain_table);
+ INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
+ qca956x_1p0_common_wo_xlna_rx_gain_bounds);
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_wo_xlna_rx_gain_table);
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.c b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
index ae6cde273414..1ad66b76749b 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.c
@@ -183,7 +183,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
} else {
channelSel = CHANSEL_2G(freq) >> 1;
}
- } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ } else if (AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) {
if (ah->is_clk_25mhz)
div = 75;
else
@@ -198,7 +199,8 @@ static int ar9003_hw_set_channel(struct ath_hw *ah, struct ath9k_channel *chan)
/* Set to 2G mode */
bMode = 1;
} else {
- if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) &&
+ if ((AR_SREV_9340(ah) || AR_SREV_9550(ah) ||
+ AR_SREV_9531(ah) || AR_SREV_9561(ah)) &&
ah->is_clk_25mhz) {
channelSel = freq / 75;
chan_frac = ((freq % 75) * 0x20000) / 75;
@@ -265,7 +267,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
*/
if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) ||
- AR_SREV_9550(ah)) {
+ AR_SREV_9550(ah) || AR_SREV_9561(ah)) {
if (spur_fbin_ptr[0] == 0) /* No spur */
return;
max_spur_cnts = 5;
@@ -292,7 +294,7 @@ static void ar9003_hw_spur_mitigate_mrc_cck(struct ath_hw *ah,
negative = 0;
if (AR_SREV_9485(ah) || AR_SREV_9340(ah) || AR_SREV_9330(ah) ||
- AR_SREV_9550(ah))
+ AR_SREV_9550(ah) || AR_SREV_9561(ah))
cur_bb_spur = ath9k_hw_fbin2freq(spur_fbin_ptr[i],
IS_CHAN_2GHZ(chan));
else
@@ -641,8 +643,10 @@ static void ar9003_hw_set_channel_regs(struct ath_hw *ah,
(REG_READ(ah, AR_PHY_GEN_CTRL) & AR_PHY_GC_ENABLE_DAC_FIFO);
/* Enable 11n HT, 20 MHz */
- phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SINGLE_HT_LTF1 |
- AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
+ phymode = AR_PHY_GC_HT_EN | AR_PHY_GC_SHORT_GI_40 | enableDacFifo;
+
+ if (!AR_SREV_9561(ah))
+ phymode |= AR_PHY_GC_SINGLE_HT_LTF1;
/* Configure baseband for dynamic 20/40 operation */
if (IS_CHAN_HT40(chan)) {
@@ -745,7 +749,8 @@ static void ar9003_hw_override_ini(struct ath_hw *ah)
else
ah->enabled_cals &= ~TX_CL_CAL;
- if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah)) {
+ if (AR_SREV_9340(ah) || AR_SREV_9531(ah) || AR_SREV_9550(ah) ||
+ AR_SREV_9561(ah)) {
if (ah->is_clk_25mhz) {
REG_WRITE(ah, AR_RTC_DERIVED_CLK, 0x17c << 1);
REG_WRITE(ah, AR_SLP32_MODE, 0x0010f3d7);
@@ -812,6 +817,19 @@ static int ar9550_hw_get_modes_txgain_index(struct ath_hw *ah,
return ret;
}
+static int ar9561_hw_get_modes_txgain_index(struct ath_hw *ah,
+ struct ath9k_channel *chan)
+{
+ if (IS_CHAN_2GHZ(chan)) {
+ if (IS_CHAN_HT40(chan))
+ return 1;
+ else
+ return 2;
+ }
+
+ return 0;
+}
+
static void ar9003_doubler_fix(struct ath_hw *ah)
{
if (AR_SREV_9300(ah) || AR_SREV_9580(ah) || AR_SREV_9550(ah)) {
@@ -911,21 +929,29 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
modesIndex, regWrites);
}
+
+ if (AR_SREV_9561(ah) && (ar9003_hw_get_rx_gain_idx(ah) == 0))
+ REG_WRITE_ARRAY(&ah->ini_modes_rxgain_5g_xlna,
+ modesIndex, regWrites);
}
- if (AR_SREV_9550(ah))
+ if (AR_SREV_9550(ah) || AR_SREV_9561(ah))
REG_WRITE_ARRAY(&ah->ini_modes_rx_gain_bounds, modesIndex,
regWrites);
/*
* TXGAIN initvals.
*/
- if (AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ if (AR_SREV_9550(ah) || AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
int modes_txgain_index = 1;
if (AR_SREV_9550(ah))
modes_txgain_index = ar9550_hw_get_modes_txgain_index(ah, chan);
+ if (AR_SREV_9561(ah))
+ modes_txgain_index =
+ ar9561_hw_get_modes_txgain_index(ah, chan);
+
if (modes_txgain_index < 0)
return -EINVAL;
@@ -1989,7 +2015,8 @@ void ar9003_hw_attach_phy_ops(struct ath_hw *ah)
priv_ops->rf_set_freq = ar9003_hw_set_channel;
priv_ops->spur_mitigate_freq = ar9003_hw_spur_mitigate;
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
priv_ops->compute_pll_control = ar9003_hw_compute_pll_control_soc;
else
priv_ops->compute_pll_control = ar9003_hw_compute_pll_control;
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
index fd090b1f2d0f..c311b2bfdb00 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
@@ -454,7 +454,7 @@
#define AR_PHY_GEN_CTRL (AR_SM_BASE + 0x4)
#define AR_PHY_MODE (AR_SM_BASE + 0x8)
#define AR_PHY_ACTIVE (AR_SM_BASE + 0xc)
-#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + 0x20)
+#define AR_PHY_SPUR_MASK_A (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x18 : 0x20))
#define AR_PHY_SPUR_MASK_B (AR_SM_BASE + 0x24)
#define AR_PHY_SPECTRAL_SCAN (AR_SM_BASE + 0x28)
#define AR_PHY_RADAR_BW_FILTER (AR_SM_BASE + 0x2c)
@@ -506,7 +506,7 @@
#define AR_PHY_TEST_CHAIN_SEL 0xC0000000
#define AR_PHY_TEST_CHAIN_SEL_S 30
-#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + 0x164)
+#define AR_PHY_TEST_CTL_STATUS (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x160 : 0x164))
#define AR_PHY_TEST_CTL_TSTDAC_EN 0x1
#define AR_PHY_TEST_CTL_TSTDAC_EN_S 0
#define AR_PHY_TEST_CTL_TX_OBS_SEL 0x1C
@@ -525,7 +525,7 @@
#define AR_PHY_CHAN_STATUS (AR_SM_BASE + 0x16c)
-#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + 0x170)
+#define AR_PHY_CHAN_INFO_MEMORY (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x16c : 0x170))
#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ 0x00000008
#define AR_PHY_CHAN_INFO_MEMORY_CHANINFOMEM_S2_READ_S 3
@@ -536,7 +536,7 @@
#define AR_PHY_SCRAMBLER_SEED (AR_SM_BASE + 0x190)
#define AR_PHY_CCK_TX_CTRL (AR_SM_BASE + 0x194)
-#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + 0x1a4)
+#define AR_PHY_HEAVYCLIP_CTL (AR_SM_BASE + (AR_SREV_9561(ah) ? 0x198 : 0x1a4))
#define AR_PHY_HEAVYCLIP_20 (AR_SM_BASE + 0x1a8)
#define AR_PHY_HEAVYCLIP_40 (AR_SM_BASE + 0x1ac)
#define AR_PHY_ILLEGAL_TXRATE (AR_SM_BASE + 0x1b0)
@@ -726,21 +726,24 @@
#define AR_CH0_TOP2 (AR_SREV_9300(ah) ? 0x1628c : \
(AR_SREV_9462(ah) ? 0x16290 : 0x16284))
-#define AR_CH0_TOP2_XPABIASLVL 0xf000
+#define AR_CH0_TOP2_XPABIASLVL (AR_SREV_9561(ah) ? 0x1e00 : 0xf000)
#define AR_CH0_TOP2_XPABIASLVL_S 12
#define AR_CH0_XTAL (AR_SREV_9300(ah) ? 0x16294 : \
- ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : 0x16290))
+ ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : \
+ (AR_SREV_9561(ah) ? 0x162c0 : 0x16290)))
#define AR_CH0_XTAL_CAPINDAC 0x7f000000
#define AR_CH0_XTAL_CAPINDAC_S 24
#define AR_CH0_XTAL_CAPOUTDAC 0x00fe0000
#define AR_CH0_XTAL_CAPOUTDAC_S 17
-#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : 0x16c40)
+#define AR_PHY_PMU1 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16340 : \
+ (AR_SREV_9561(ah) ? 0x16cc0 : 0x16c40))
#define AR_PHY_PMU1_PWD 0x1
#define AR_PHY_PMU1_PWD_S 0
-#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : 0x16c44)
+#define AR_PHY_PMU2 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16344 : \
+ (AR_SREV_9561(ah) ? 0x16cc4 : 0x16c44))
#define AR_PHY_PMU2_PGM 0x00200000
#define AR_PHY_PMU2_PGM_S 21
diff --git a/drivers/net/wireless/ath/ath9k/ar9003_wow.c b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
index 81c88dd606dc..86bfc9604dca 100644
--- a/drivers/net/wireless/ath/ath9k/ar9003_wow.c
+++ b/drivers/net/wireless/ath/ath9k/ar9003_wow.c
@@ -17,23 +17,9 @@
#include <linux/export.h>
#include "ath9k.h"
#include "reg.h"
+#include "reg_wow.h"
#include "hw-ops.h"
-const char *ath9k_hw_wow_event_to_string(u32 wow_event)
-{
- if (wow_event & AH_WOW_MAGIC_PATTERN_EN)
- return "Magic pattern";
- if (wow_event & AH_WOW_USER_PATTERN_EN)
- return "User pattern";
- if (wow_event & AH_WOW_LINK_CHANGE)
- return "Link change";
- if (wow_event & AH_WOW_BEACON_MISS)
- return "Beacon miss";
-
- return "unknown reason";
-}
-EXPORT_SYMBOL(ath9k_hw_wow_event_to_string);
-
static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
{
struct ath_common *common = ath9k_hw_common(ah);
@@ -49,6 +35,15 @@ static void ath9k_hw_set_powermode_wow_sleep(struct ath_hw *ah)
return;
}
+ if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+ if (!REG_READ(ah, AR_MAC_PCU_GEN_TIMER_TSF_SEL))
+ REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE);
+ } else if (AR_SREV_9485(ah)){
+ if (!(REG_READ(ah, AR_NDP2_TIMER_MODE) &
+ AR_GEN_TIMERS2_MODE_ENABLE_MASK))
+ REG_CLR_BIT(ah, AR_DIRECT_CONNECT, AR_DC_TSF2_ENABLE);
+ }
+
REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_ON_INT);
}
@@ -67,11 +62,15 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
/* set the transmit buffer */
ctl[0] = (KAL_FRAME_LEN | (MAX_RATE_POWER << 16));
ctl[1] = 0;
- ctl[3] = 0xb; /* OFDM_6M hardware value for this rate */
ctl[4] = 0;
ctl[7] = (ah->txchainmask) << 2;
ctl[2] = 0xf << 16; /* tx_tries 0 */
+ if (IS_CHAN_2GHZ(ah->curchan))
+ ctl[3] = 0x1b; /* CCK_1M */
+ else
+ ctl[3] = 0xb; /* OFDM_6M */
+
for (i = 0; i < KAL_NUM_DESC_WORDS; i++)
REG_WRITE(ah, (AR_WOW_KA_DESC_WORD2 + i * 4), ctl[i]);
@@ -103,21 +102,22 @@ static void ath9k_wow_create_keep_alive_pattern(struct ath_hw *ah)
}
-void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
- u8 *user_mask, int pattern_count,
- int pattern_len)
+int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
+ u8 *user_mask, int pattern_count,
+ int pattern_len)
{
int i;
u32 pattern_val, mask_val;
u32 set, clr;
- /* FIXME: should check count by querying the hardware capability */
- if (pattern_count >= MAX_NUM_PATTERN)
- return;
+ if (pattern_count >= ah->wow.max_patterns)
+ return -ENOSPC;
- REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
+ if (pattern_count < MAX_NUM_PATTERN_LEGACY)
+ REG_SET_BIT(ah, AR_WOW_PATTERN, BIT(pattern_count));
+ else
+ REG_SET_BIT(ah, AR_MAC_PCU_WOW4, BIT(pattern_count - 8));
- /* set the registers for pattern */
for (i = 0; i < MAX_PATTERN_SIZE; i += 4) {
memcpy(&pattern_val, user_pattern, 4);
REG_WRITE(ah, (AR_WOW_TB_PATTERN(pattern_count) + i),
@@ -125,49 +125,42 @@ void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
user_pattern += 4;
}
- /* set the registers for mask */
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i += 4) {
memcpy(&mask_val, user_mask, 4);
REG_WRITE(ah, (AR_WOW_TB_MASK(pattern_count) + i), mask_val);
user_mask += 4;
}
- /* set the pattern length to be matched
- *
- * AR_WOW_LENGTH1_REG1
- * bit 31:24 pattern 0 length
- * bit 23:16 pattern 1 length
- * bit 15:8 pattern 2 length
- * bit 7:0 pattern 3 length
- *
- * AR_WOW_LENGTH1_REG2
- * bit 31:24 pattern 4 length
- * bit 23:16 pattern 5 length
- * bit 15:8 pattern 6 length
- * bit 7:0 pattern 7 length
- *
- * the below logic writes out the new
- * pattern length for the corresponding
- * pattern_count, while masking out the
- * other fields
- */
-
- ah->wow_event_mask |= BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
+ if (pattern_count < MAX_NUM_PATTERN_LEGACY)
+ ah->wow.wow_event_mask |=
+ BIT(pattern_count + AR_WOW_PAT_FOUND_SHIFT);
+ else
+ ah->wow.wow_event_mask2 |=
+ BIT((pattern_count - 8) + AR_WOW_PAT_FOUND_SHIFT);
if (pattern_count < 4) {
- /* Pattern 0-3 uses AR_WOW_LENGTH1 register */
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN1_SHIFT(pattern_count);
clr = AR_WOW_LENGTH1_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH1, set, clr);
- } else {
- /* Pattern 4-7 uses AR_WOW_LENGTH2 register */
+ } else if (pattern_count < 8) {
set = (pattern_len & AR_WOW_LENGTH_MAX) <<
AR_WOW_LEN2_SHIFT(pattern_count);
clr = AR_WOW_LENGTH2_MASK(pattern_count);
REG_RMW(ah, AR_WOW_LENGTH2, set, clr);
+ } else if (pattern_count < 12) {
+ set = (pattern_len & AR_WOW_LENGTH_MAX) <<
+ AR_WOW_LEN3_SHIFT(pattern_count);
+ clr = AR_WOW_LENGTH3_MASK(pattern_count);
+ REG_RMW(ah, AR_WOW_LENGTH3, set, clr);
+ } else if (pattern_count < MAX_NUM_PATTERN) {
+ set = (pattern_len & AR_WOW_LENGTH_MAX) <<
+ AR_WOW_LEN4_SHIFT(pattern_count);
+ clr = AR_WOW_LENGTH4_MASK(pattern_count);
+ REG_RMW(ah, AR_WOW_LENGTH4, set, clr);
}
+ return 0;
}
EXPORT_SYMBOL(ath9k_hw_wow_apply_pattern);
@@ -189,7 +182,7 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
* register. This mask will clean it up.
*/
- val &= ah->wow_event_mask;
+ val &= ah->wow.wow_event_mask;
if (val) {
if (val & AR_WOW_MAGIC_PAT_FOUND)
@@ -233,190 +226,192 @@ u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
if (ah->is_pciexpress)
ath9k_hw_configpcipowersave(ah, false);
- ah->wow_event_mask = 0;
+ ah->wow.wow_event_mask = 0;
return wow_status;
}
EXPORT_SYMBOL(ath9k_hw_wow_wakeup);
-void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
+static void ath9k_hw_wow_set_arwr_reg(struct ath_hw *ah)
{
- u32 wow_event_mask;
- u32 set, clr;
+ u32 wa_reg;
- /*
- * wow_event_mask is a mask to the AR_WOW_PATTERN register to
- * indicate which WoW events we have enabled. The WoW events
- * are from the 'pattern_enable' in this function and
- * 'pattern_count' of ath9k_hw_wow_apply_pattern()
- */
- wow_event_mask = ah->wow_event_mask;
+ if (!ah->is_pciexpress)
+ return;
/*
- * Untie Power-on-Reset from the PCI-E-Reset. When we are in
- * WOW sleep, we do want the Reset from the PCI-E to disturb
- * our hw state
+ * We need to untie the internal POR (power-on-reset)
+ * to the external PCI-E reset. We also need to tie
+ * the PCI-E Phy reset to the PCI-E reset.
*/
- if (ah->is_pciexpress) {
- /*
- * we need to untie the internal POR (power-on-reset)
- * to the external PCI-E reset. We also need to tie
- * the PCI-E Phy reset to the PCI-E reset.
- */
- set = AR_WA_RESET_EN | AR_WA_POR_SHORT;
- clr = AR_WA_UNTIE_RESET_EN | AR_WA_D3_L1_DISABLE;
- REG_RMW(ah, AR_WA, set, clr);
- }
+ wa_reg = REG_READ(ah, AR_WA);
+ wa_reg &= ~AR_WA_UNTIE_RESET_EN;
+ wa_reg |= AR_WA_RESET_EN;
+ wa_reg |= AR_WA_POR_SHORT;
- /*
- * set the power states appropriately and enable PME
- */
- set = AR_PMCTRL_HOST_PME_EN | AR_PMCTRL_PWR_PM_CTRL_ENA |
- AR_PMCTRL_AUX_PWR_DET | AR_PMCTRL_WOW_PME_CLR;
+ REG_WRITE(ah, AR_WA, wa_reg);
+}
+
+void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable)
+{
+ u32 wow_event_mask;
+ u32 keep_alive, magic_pattern, host_pm_ctrl;
+
+ wow_event_mask = ah->wow.wow_event_mask;
/*
- * set and clear WOW_PME_CLEAR registers for the chip
+ * AR_PMCTRL_HOST_PME_EN - Override PME enable in configuration
+ * space and allow MAC to generate WoW anyway.
+ *
+ * AR_PMCTRL_PWR_PM_CTRL_ENA - ???
+ *
+ * AR_PMCTRL_AUX_PWR_DET - PCI core SYS_AUX_PWR_DET signal,
+ * needs to be set for WoW in PCI mode.
+ *
+ * AR_PMCTRL_WOW_PME_CLR - WoW Clear Signal going to the MAC.
+ *
+ * Set the power states appropriately and enable PME.
+ *
+ * Set and clear WOW_PME_CLEAR for the chip
* to generate next wow signal.
*/
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
- clr = AR_PMCTRL_WOW_PME_CLR;
- REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+ REG_SET_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_HOST_PME_EN |
+ AR_PMCTRL_PWR_PM_CTRL_ENA |
+ AR_PMCTRL_AUX_PWR_DET |
+ AR_PMCTRL_WOW_PME_CLR);
+ REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, AR_PMCTRL_WOW_PME_CLR);
/*
- * Setup for:
- * - beacon misses
- * - magic pattern
- * - keep alive timeout
- * - pattern matching
+ * Random Backoff.
+ *
+ * 31:28 in AR_WOW_PATTERN : Indicates the number of bits used in the
+ * contention window. For value N,
+ * the random backoff will be selected between
+ * 0 and (2 ^ N) - 1.
*/
+ REG_SET_BIT(ah, AR_WOW_PATTERN,
+ AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF));
/*
- * Program default values for pattern backoff, aifs/slot/KAL count,
- * beacon miss timeout, KAL timeout, etc.
+ * AIFS time, Slot time, Keep Alive count.
+ */
+ REG_SET_BIT(ah, AR_WOW_COUNT, AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
+ AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
+ AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT));
+ /*
+ * Beacon timeout.
*/
- set = AR_WOW_BACK_OFF_SHIFT(AR_WOW_PAT_BACKOFF);
- REG_SET_BIT(ah, AR_WOW_PATTERN, set);
-
- set = AR_WOW_AIFS_CNT(AR_WOW_CNT_AIFS_CNT) |
- AR_WOW_SLOT_CNT(AR_WOW_CNT_SLOT_CNT) |
- AR_WOW_KEEP_ALIVE_CNT(AR_WOW_CNT_KA_CNT);
- REG_SET_BIT(ah, AR_WOW_COUNT, set);
-
if (pattern_enable & AH_WOW_BEACON_MISS)
- set = AR_WOW_BEACON_TIMO;
- /* We are not using beacon miss, program a large value */
+ REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO);
else
- set = AR_WOW_BEACON_TIMO_MAX;
-
- REG_WRITE(ah, AR_WOW_BCN_TIMO, set);
+ REG_WRITE(ah, AR_WOW_BCN_TIMO, AR_WOW_BEACON_TIMO_MAX);
/*
- * Keep alive timo in ms except AR9280
+ * Keep alive timeout in ms.
*/
if (!pattern_enable)
- set = AR_WOW_KEEP_ALIVE_NEVER;
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, AR_WOW_KEEP_ALIVE_NEVER);
else
- set = KAL_TIMEOUT * 32;
-
- REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, set);
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_TIMO, KAL_TIMEOUT * 32);
/*
- * Keep alive delay in us. based on 'power on clock',
- * therefore in usec
+ * Keep alive delay in us.
*/
- set = KAL_DELAY * 1000;
- REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, set);
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE_DELAY, KAL_DELAY * 1000);
/*
- * Create keep alive pattern to respond to beacons
+ * Create keep alive pattern to respond to beacons.
*/
ath9k_wow_create_keep_alive_pattern(ah);
/*
- * Configure MAC WoW Registers
+ * Configure keep alive register.
*/
- set = 0;
+ keep_alive = REG_READ(ah, AR_WOW_KEEP_ALIVE);
+
/* Send keep alive timeouts anyway */
- clr = AR_WOW_KEEP_ALIVE_AUTO_DIS;
+ keep_alive &= ~AR_WOW_KEEP_ALIVE_AUTO_DIS;
- if (pattern_enable & AH_WOW_LINK_CHANGE)
+ if (pattern_enable & AH_WOW_LINK_CHANGE) {
+ keep_alive &= ~AR_WOW_KEEP_ALIVE_FAIL_DIS;
wow_event_mask |= AR_WOW_KEEP_ALIVE_FAIL;
- else
- set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
+ } else {
+ keep_alive |= AR_WOW_KEEP_ALIVE_FAIL_DIS;
+ }
- set = AR_WOW_KEEP_ALIVE_FAIL_DIS;
- REG_RMW(ah, AR_WOW_KEEP_ALIVE, set, clr);
+ REG_WRITE(ah, AR_WOW_KEEP_ALIVE, keep_alive);
/*
- * we are relying on a bmiss failure. ensure we have
- * enough threshold to prevent false positives
+ * We are relying on a bmiss failure, ensure we have
+ * enough threshold to prevent false positives.
*/
REG_RMW_FIELD(ah, AR_RSSI_THR, AR_RSSI_THR_BM_THR,
AR_WOW_BMISSTHRESHOLD);
- set = 0;
- clr = 0;
-
if (pattern_enable & AH_WOW_BEACON_MISS) {
- set = AR_WOW_BEACON_FAIL_EN;
wow_event_mask |= AR_WOW_BEACON_FAIL;
+ REG_SET_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN);
} else {
- clr = AR_WOW_BEACON_FAIL_EN;
+ REG_CLR_BIT(ah, AR_WOW_BCN_EN, AR_WOW_BEACON_FAIL_EN);
}
- REG_RMW(ah, AR_WOW_BCN_EN, set, clr);
-
- set = 0;
- clr = 0;
/*
- * Enable the magic packet registers
+ * Enable the magic packet registers.
*/
+ magic_pattern = REG_READ(ah, AR_WOW_PATTERN);
+ magic_pattern |= AR_WOW_MAC_INTR_EN;
+
if (pattern_enable & AH_WOW_MAGIC_PATTERN_EN) {
- set = AR_WOW_MAGIC_EN;
+ magic_pattern |= AR_WOW_MAGIC_EN;
wow_event_mask |= AR_WOW_MAGIC_PAT_FOUND;
} else {
- clr = AR_WOW_MAGIC_EN;
+ magic_pattern &= ~AR_WOW_MAGIC_EN;
}
- set |= AR_WOW_MAC_INTR_EN;
- REG_RMW(ah, AR_WOW_PATTERN, set, clr);
+ REG_WRITE(ah, AR_WOW_PATTERN, magic_pattern);
+
+ /*
+ * Enable pattern matching for packets which are less
+ * than 256 bytes.
+ */
REG_WRITE(ah, AR_WOW_PATTERN_MATCH_LT_256B,
AR_WOW_PATTERN_SUPPORTED);
/*
- * Set the power states appropriately and enable PME
+ * Set the power states appropriately and enable PME.
*/
- clr = 0;
- set = AR_PMCTRL_PWR_STATE_D1D3 | AR_PMCTRL_HOST_PME_EN |
- AR_PMCTRL_PWR_PM_CTRL_ENA;
+ host_pm_ctrl = REG_READ(ah, AR_PCIE_PM_CTRL);
+ host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3 |
+ AR_PMCTRL_HOST_PME_EN |
+ AR_PMCTRL_PWR_PM_CTRL_ENA;
+ host_pm_ctrl &= ~AR_PCIE_PM_CTRL_ENA;
- clr = AR_PCIE_PM_CTRL_ENA;
- REG_RMW(ah, AR_PCIE_PM_CTRL, set, clr);
+ if (AR_SREV_9462(ah)) {
+ /*
+ * This is needed to prevent the chip waking up
+ * the host within 3-4 seconds with certain
+ * platform/BIOS.
+ */
+ host_pm_ctrl &= ~AR_PMCTRL_PWR_STATE_D1D3;
+ host_pm_ctrl |= AR_PMCTRL_PWR_STATE_D1D3_REAL;
+ }
+
+ REG_WRITE(ah, AR_PCIE_PM_CTRL, host_pm_ctrl);
/*
- * this is needed to prevent the chip waking up
- * the host within 3-4 seconds with certain
- * platform/BIOS. The fix is to enable
- * D1 & D3 to match original definition and
- * also match the OTP value. Anyway this
- * is more related to SW WOW.
+ * Enable sequence number generation when asleep.
*/
- clr = AR_PMCTRL_PWR_STATE_D1D3;
- REG_CLR_BIT(ah, AR_PCIE_PM_CTRL, clr);
+ REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
- set = AR_PMCTRL_PWR_STATE_D1D3_REAL;
- REG_SET_BIT(ah, AR_PCIE_PM_CTRL, set);
+ /* To bring down WOW power low margin */
+ REG_SET_BIT(ah, AR_PCIE_PHY_REG3, BIT(13));
- REG_CLR_BIT(ah, AR_STA_ID1, AR_STA_ID1_PRESERVE_SEQNUM);
+ ath9k_hw_wow_set_arwr_reg(ah);
- /* to bring down WOW power low margin */
- set = BIT(13);
- REG_SET_BIT(ah, AR_PCIE_PHY_REG3, set);
/* HW WoW */
- clr = BIT(5);
- REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, clr);
+ REG_CLR_BIT(ah, AR_PCU_MISC_MODE3, BIT(5));
ath9k_hw_set_powermode_wow_sleep(ah);
- ah->wow_event_mask = wow_event_mask;
+ ah->wow.wow_event_mask = wow_event_mask;
}
EXPORT_SYMBOL(ath9k_hw_wow_enable);
diff --git a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
index 159cc6fd2362..6fc0d07e5ec6 100644
--- a/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar953x_initvals.h
@@ -358,7 +358,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = {
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
- {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822},
+ {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820},
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -378,7 +378,7 @@ static const u32 qca953x_1p0_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
diff --git a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
index fd6a84ccd49e..148562addd38 100644
--- a/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
+++ b/drivers/net/wireless/ath/ath9k/ar955x_1p0_initvals.h
@@ -63,7 +63,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
{0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
{0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
{0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
- {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10822, 0xcfa10822},
+ {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcfa10820, 0xcfa10820},
{0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
{0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
{0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
@@ -83,7 +83,7 @@ static const u32 ar955x_1p0_baseband_postamble[][5] = {
{0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
{0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
{0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
- {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+ {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00058d18, 0x00058d18},
{0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
{0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
{0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
diff --git a/drivers/net/wireless/ath/ath9k/ar956x_initvals.h b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h
new file mode 100644
index 000000000000..c3a47eaaf0c0
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/ar956x_initvals.h
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (c) 2010-2011 Atheros Communications Inc.
+ * Copyright (c) 2011-2012 Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INITVALS_956X_H
+#define INITVALS_956X_H
+
+#define qca956x_1p0_mac_core ar955x_1p0_mac_core
+
+#define qca956x_1p0_mac_postamble ar9331_1p1_mac_postamble
+
+#define qca956x_1p0_soc_preamble ar955x_1p0_soc_preamble
+
+#define qca956x_1p0_soc_postamble ar9300_2p2_soc_postamble
+
+#define qca956x_1p0_common_wo_xlna_rx_gain_table ar9300Common_wo_xlna_rx_gain_table_2p2
+
+#define qca956x_1p0_baseband_postamble_dfs_channel ar9300_2p2_baseband_postamble_dfs_channel
+
+#define qca956x_1p0_common_wo_xlna_rx_gain_bounds ar955x_1p0_common_wo_xlna_rx_gain_bounds
+
+#define qca956x_1p0_common_rx_gain_bounds ar955x_1p0_common_rx_gain_bounds
+
+#define qca956x_1p0_modes_fast_clock ar9462_2p0_modes_fast_clock
+
+static const u32 qca956x_1p0_baseband_core[][2] = {
+ /* Addr allmodes */
+ {0x00009800, 0xafe68e30},
+ {0x00009804, 0xfd14e000},
+ {0x00009808, 0x9c0a9f6b},
+ {0x0000980c, 0x04900000},
+ {0x00009814, 0x0280c00a},
+ {0x00009818, 0x00000000},
+ {0x0000981c, 0x00020028},
+ {0x00009834, 0x6400a190},
+ {0x00009838, 0x0108ecff},
+ {0x0000983c, 0x14000600},
+ {0x00009880, 0x201fff00},
+ {0x00009884, 0x00001042},
+ {0x000098a4, 0x00200400},
+ {0x000098b0, 0x32840cbf},
+ {0x000098bc, 0x00000002},
+ {0x000098d0, 0x004b6a8e},
+ {0x000098d4, 0x00000820},
+ {0x000098dc, 0x00000000},
+ {0x000098f0, 0x00000000},
+ {0x000098f4, 0x00000000},
+ {0x00009c04, 0xff55ff55},
+ {0x00009c08, 0x0320ff55},
+ {0x00009c0c, 0x00000000},
+ {0x00009c10, 0x00000000},
+ {0x00009c14, 0x00046384},
+ {0x00009c18, 0x05b6b440},
+ {0x00009c1c, 0x00b6b440},
+ {0x00009d00, 0xc080a333},
+ {0x00009d04, 0x40206c10},
+ {0x00009d08, 0x009c4060},
+ {0x00009d0c, 0x9883800a},
+ {0x00009d10, 0x01834061},
+ {0x00009d14, 0x00c0040b},
+ {0x00009d18, 0x00000000},
+ {0x00009e08, 0x0038230c},
+ {0x00009e24, 0x990bb514},
+ {0x00009e28, 0x0c6f0000},
+ {0x00009e30, 0x06336f77},
+ {0x00009e34, 0x6af6532f},
+ {0x00009e38, 0x0cc80c00},
+ {0x00009e40, 0x0d261820},
+ {0x00009e4c, 0x00001004},
+ {0x00009e50, 0x00ff03f1},
+ {0x00009fc0, 0x813e4789},
+ {0x00009fc4, 0x0001efb5},
+ {0x00009fcc, 0x40000014},
+ {0x00009fd0, 0x02993b93},
+ {0x0000a20c, 0x00000000},
+ {0x0000a218, 0x00000000},
+ {0x0000a21c, 0x00000000},
+ {0x0000a228, 0x10002310},
+ {0x0000a23c, 0x00000000},
+ {0x0000a244, 0x0c000000},
+ {0x0000a248, 0x00000140},
+ {0x0000a2a0, 0x00000007},
+ {0x0000a2c0, 0x00000007},
+ {0x0000a2c8, 0x00000000},
+ {0x0000a2d4, 0x00000000},
+ {0x0000a2ec, 0x00000000},
+ {0x0000a2f0, 0x00000000},
+ {0x0000a2f4, 0x00000000},
+ {0x0000a2f8, 0x00000000},
+ {0x0000a344, 0x00000000},
+ {0x0000a34c, 0x00000000},
+ {0x0000a350, 0x0000a000},
+ {0x0000a360, 0x00000000},
+ {0x0000a36c, 0x00000000},
+ {0x0000a384, 0x00000001},
+ {0x0000a388, 0x00000444},
+ {0x0000a38c, 0x00000000},
+ {0x0000a390, 0x210d0401},
+ {0x0000a394, 0xab9a7144},
+ {0x0000a398, 0x00000201},
+ {0x0000a39c, 0x42424848},
+ {0x0000a3a0, 0x3c466478},
+ {0x0000a3a4, 0x3a363600},
+ {0x0000a3a8, 0x0000003a},
+ {0x0000a3ac, 0x00000000},
+ {0x0000a3b0, 0x009011fe},
+ {0x0000a3b4, 0x00000034},
+ {0x0000a3b8, 0x00b3ec0a},
+ {0x0000a3bc, 0x00000036},
+ {0x0000a3c0, 0x20202020},
+ {0x0000a3c4, 0x22222220},
+ {0x0000a3c8, 0x20200020},
+ {0x0000a3cc, 0x20202020},
+ {0x0000a3d0, 0x20202020},
+ {0x0000a3d4, 0x20202020},
+ {0x0000a3d8, 0x20202020},
+ {0x0000a3dc, 0x20202020},
+ {0x0000a3e0, 0x20202020},
+ {0x0000a3e4, 0x20202020},
+ {0x0000a3e8, 0x20202020},
+ {0x0000a3ec, 0x20202020},
+ {0x0000a3f0, 0x00000000},
+ {0x0000a3f4, 0x00000000},
+ {0x0000a3f8, 0x0c9bd380},
+ {0x0000a3fc, 0x000f0f01},
+ {0x0000a400, 0x8fa91f01},
+ {0x0000a404, 0x00000000},
+ {0x0000a408, 0x0e79e5c6},
+ {0x0000a40c, 0x00820820},
+ {0x0000a414, 0x1ce739ce},
+ {0x0000a418, 0x2d0019ce},
+ {0x0000a41c, 0x1ce739ce},
+ {0x0000a420, 0x000001ce},
+ {0x0000a424, 0x1ce739ce},
+ {0x0000a428, 0x000001ce},
+ {0x0000a42c, 0x1ce739ce},
+ {0x0000a430, 0x1ce739ce},
+ {0x0000a434, 0x00000000},
+ {0x0000a438, 0x00001801},
+ {0x0000a43c, 0x00100000},
+ {0x0000a444, 0x00000000},
+ {0x0000a448, 0x05000080},
+ {0x0000a44c, 0x00000001},
+ {0x0000a450, 0x00010000},
+ {0x0000a454, 0x05000000},
+ {0x0000a458, 0x00000000},
+ {0x0000a644, 0xbfad9fee},
+ {0x0000a648, 0x0048660d},
+ {0x0000a64c, 0x00003c37},
+ {0x0000a670, 0x03020100},
+ {0x0000a674, 0x21200504},
+ {0x0000a678, 0x61602322},
+ {0x0000a67c, 0x65646362},
+ {0x0000a680, 0x6b6a6968},
+ {0x0000a684, 0xe2706d6c},
+ {0x0000a688, 0x000000e3},
+ {0x0000a690, 0x00000838},
+ {0x0000a7cc, 0x00000000},
+ {0x0000a7d0, 0x00000000},
+ {0x0000a7d4, 0x00000004},
+ {0x0000a7dc, 0x00000000},
+ {0x0000a8d0, 0x004b6a8e},
+ {0x0000a8d4, 0x00000820},
+ {0x0000a8dc, 0x00000000},
+ {0x0000a8f0, 0x00000000},
+ {0x0000a8f4, 0x00000000},
+ {0x0000b2d0, 0x00000080},
+ {0x0000b2d4, 0x00000000},
+ {0x0000b2ec, 0x00000000},
+ {0x0000b2f0, 0x00000000},
+ {0x0000b2f4, 0x00000000},
+ {0x0000b2f8, 0x00000000},
+ {0x0000b408, 0x0e79e5c0},
+ {0x0000b40c, 0x00820820},
+ {0x0000b420, 0x00000000},
+ {0x0000b8d0, 0x004b6a8e},
+ {0x0000b8d4, 0x00000820},
+ {0x0000b8dc, 0x00000000},
+ {0x0000b8f0, 0x00000000},
+ {0x0000b8f4, 0x00000000},
+ {0x0000c2d0, 0x00000080},
+ {0x0000c2d4, 0x00000000},
+ {0x0000c2ec, 0x00000000},
+ {0x0000c2f0, 0x00000000},
+ {0x0000c2f4, 0x00000000},
+ {0x0000c2f8, 0x00000000},
+ {0x0000c408, 0x0e79e5c0},
+ {0x0000c40c, 0x00820820},
+ {0x0000c420, 0x00000000},
+};
+
+static const u32 qca956x_1p0_baseband_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009810, 0xd00a8005, 0xd00a8005, 0xd00a8011, 0xd00a8011},
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1},
+ {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881},
+ {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
+ {0x00009830, 0x0000059c, 0x0000059c, 0x0000119c, 0x0000119c},
+ {0x00009c00, 0x000000c4, 0x000000c4, 0x000000c4, 0x000000c4},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x037216a0},
+ {0x00009e04, 0x001c2020, 0x001c2020, 0x001c2020, 0x001c2020},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000de},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec84d2e, 0x7ec86d2e},
+ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x337d605e, 0x337d5d5e},
+ {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003a6, 0x000003a6},
+ {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
+ {0x00009e3c, 0xcfa10820, 0xcfa10820, 0xcf946222, 0xcf946222},
+ {0x00009e44, 0xfe321e27, 0xfe321e27, 0xfe291e27, 0xfe291e27},
+ {0x00009e48, 0x5030201a, 0x5030201a, 0x50302012, 0x50302012},
+ {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
+ {0x0000a204, 0x005c0ec0, 0x005c0ec4, 0x045c0cc4, 0x045c0cc0},
+ {0x0000a208, 0x00000104, 0x00000104, 0x00000004, 0x00000004},
+ {0x0000a22c, 0x07e26a2f, 0x07e26a2f, 0x01026a2f, 0x01026a2f},
+ {0x0000a230, 0x0000400a, 0x00004014, 0x00004016, 0x0000400b},
+ {0x0000a234, 0x00000fff, 0x10000fff, 0x10000fff, 0x00000fff},
+ {0x0000a238, 0xffb01018, 0xffb01018, 0xffb01018, 0xffb01018},
+ {0x0000a250, 0x00000000, 0x00000000, 0x00000210, 0x00000108},
+ {0x0000a254, 0x000007d0, 0x00000fa0, 0x00001130, 0x00000898},
+ {0x0000a258, 0x02020002, 0x02020002, 0x02020002, 0x02020002},
+ {0x0000a25c, 0x01000e0e, 0x01000e0e, 0x01010e0e, 0x01010e0e},
+ {0x0000a260, 0x0a021501, 0x0a021501, 0x3a021501, 0x3a021501},
+ {0x0000a264, 0x00000e0e, 0x00000e0e, 0x01000e0e, 0x01000e0e},
+ {0x0000a280, 0x00000007, 0x00000007, 0x0000000b, 0x0000000b},
+ {0x0000a284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+ {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
+ {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
+ {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
+ {0x0000a2cc, 0x18c50033, 0x18c43433, 0x18c41033, 0x18c44c33},
+ {0x0000a2d0, 0x00041982, 0x00041982, 0x00041982, 0x00041982},
+ {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
+ {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000a830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000ae1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6},
+ {0x0000b284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+ {0x0000b830, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be04, 0x001c0000, 0x001c0000, 0x001c0000, 0x001c0000},
+ {0x0000be18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+ {0x0000be1c, 0x0000019c, 0x0000019c, 0x0000019c, 0x0000019c},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001a6, 0x000001a6},
+ {0x0000c284, 0x00000000, 0x00000000, 0x00000010, 0x00000010},
+};
+
+static const u32 qca956x_1p0_radio_core[][2] = {
+ /* Addr allmodes */
+ {0x00016000, 0x36db6db6},
+ {0x00016004, 0x6db6db40},
+ {0x00016008, 0x73f00000},
+ {0x0001600c, 0x00000000},
+ {0x00016040, 0x3f80fff8},
+ {0x0001604c, 0x000f0278},
+ {0x00016050, 0x8036db6c},
+ {0x00016054, 0x6db60000},
+ {0x00016080, 0x00080000},
+ {0x00016084, 0x0e48048c},
+ {0x00016088, 0x14214514},
+ {0x0001608c, 0x119f080a},
+ {0x00016090, 0x24926490},
+ {0x00016094, 0x00000000},
+ {0x000160a0, 0xc2108ffe},
+ {0x000160a4, 0x812fc370},
+ {0x000160a8, 0x423c8000},
+ {0x000160b4, 0x92480000},
+ {0x000160c0, 0x006db6d8},
+ {0x000160c4, 0x24b6db6c},
+ {0x000160c8, 0x6db6db6c},
+ {0x000160cc, 0x6db6fb7c},
+ {0x000160d0, 0x6db6da44},
+ {0x00016100, 0x07ff8001},
+ {0x00016108, 0x00080010},
+ {0x00016144, 0x01884080},
+ {0x00016148, 0x00008058},
+ {0x00016288, 0x001c6000},
+ {0x0001628c, 0x50000000},
+ {0x000162c0, 0x4b962100},
+ {0x000162c4, 0x00000480},
+ {0x000162c8, 0x04000144},
+ {0x00016380, 0x00000000},
+ {0x00016384, 0x00000000},
+ {0x00016388, 0x00800700},
+ {0x0001638c, 0x00800700},
+ {0x00016390, 0x00800700},
+ {0x00016394, 0x00000000},
+ {0x00016398, 0x00000000},
+ {0x0001639c, 0x00000000},
+ {0x000163a0, 0x00000001},
+ {0x000163a4, 0x00000001},
+ {0x000163a8, 0x00000000},
+ {0x000163ac, 0x00000000},
+ {0x000163b0, 0x00000000},
+ {0x000163b4, 0x00000000},
+ {0x000163b8, 0x00000000},
+ {0x000163bc, 0x00000000},
+ {0x000163c0, 0x000000a0},
+ {0x000163c4, 0x000c0000},
+ {0x000163c8, 0x14021402},
+ {0x000163cc, 0x00001402},
+ {0x000163d0, 0x00000000},
+ {0x000163d4, 0x00000000},
+ {0x00016400, 0x36db6db6},
+ {0x00016404, 0x6db6db40},
+ {0x00016408, 0x73f00000},
+ {0x0001640c, 0x00000000},
+ {0x00016440, 0x3f80fff8},
+ {0x0001644c, 0x000f0278},
+ {0x00016450, 0x8036db6c},
+ {0x00016454, 0x6db60000},
+ {0x00016500, 0x07ff8001},
+ {0x00016508, 0x00080010},
+ {0x00016544, 0x01884080},
+ {0x00016548, 0x00008058},
+ {0x00016780, 0x00000000},
+ {0x00016784, 0x00000000},
+ {0x00016788, 0x00800700},
+ {0x0001678c, 0x00800700},
+ {0x00016790, 0x00800700},
+ {0x00016794, 0x00000000},
+ {0x00016798, 0x00000000},
+ {0x0001679c, 0x00000000},
+ {0x000167a0, 0x00000001},
+ {0x000167a4, 0x00000001},
+ {0x000167a8, 0x00000000},
+ {0x000167ac, 0x00000000},
+ {0x000167b0, 0x00000000},
+ {0x000167b4, 0x00000000},
+ {0x000167b8, 0x00000000},
+ {0x000167bc, 0x00000000},
+ {0x000167c0, 0x000000a0},
+ {0x000167c4, 0x000c0000},
+ {0x000167c8, 0x14021402},
+ {0x000167cc, 0x00001402},
+ {0x000167d0, 0x00000000},
+ {0x000167d4, 0x00000000},
+ {0x00016800, 0x36db6db6},
+ {0x00016804, 0x6db6db40},
+ {0x00016808, 0x73f00000},
+ {0x0001680c, 0x00000000},
+ {0x00016840, 0x3f80fff8},
+ {0x0001684c, 0x000f0278},
+ {0x00016850, 0x8036db6c},
+ {0x00016854, 0x6db60000},
+ {0x00016900, 0x07ff8001},
+ {0x00016908, 0x00080010},
+ {0x00016944, 0x01884080},
+ {0x00016948, 0x00008058},
+ {0x00016b80, 0x00000000},
+ {0x00016b84, 0x00000000},
+ {0x00016b88, 0x00800700},
+ {0x00016b8c, 0x00800700},
+ {0x00016b90, 0x00800700},
+ {0x00016b94, 0x00000000},
+ {0x00016b98, 0x00000000},
+ {0x00016b9c, 0x00000000},
+ {0x00016ba0, 0x00000001},
+ {0x00016ba4, 0x00000001},
+ {0x00016ba8, 0x00000000},
+ {0x00016bac, 0x00000000},
+ {0x00016bb0, 0x00000000},
+ {0x00016bb4, 0x00000000},
+ {0x00016bb8, 0x00000000},
+ {0x00016bbc, 0x00000000},
+ {0x00016bc0, 0x000000a0},
+ {0x00016bc4, 0x000c0000},
+ {0x00016bc8, 0x14021402},
+ {0x00016bcc, 0x00001402},
+ {0x00016bd0, 0x00000000},
+ {0x00016bd4, 0x00000000},
+};
+
+static const u32 qca956x_1p0_radio_postamble[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00016098, 0xd2dd5554, 0xd2dd5554, 0xc4128f5c, 0xc4128f5c},
+ {0x0001609c, 0x0a566f3a, 0x0a566f3a, 0x0fd08f25, 0x0fd08f25},
+ {0x000160ac, 0xa4647c00, 0xa4647c00, 0x24646800, 0x24646800},
+ {0x000160b0, 0x01885f52, 0x01885f52, 0x00fe7f46, 0x00fe7f46},
+ {0x00016104, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001},
+ {0x0001610c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+ {0x00016140, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+ {0x00016504, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001},
+ {0x0001650c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+ {0x00016540, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+ {0x00016904, 0xb7a00000, 0xb7a00000, 0xfff80001, 0xfff80001},
+ {0x0001690c, 0xc0000000, 0xc0000000, 0x00000000, 0x00000000},
+ {0x00016940, 0x10804008, 0x10804008, 0x50804000, 0x50804000},
+};
+
+static const u32 qca956x_1p0_baseband_core_txfir_coeff_japan_2484[][2] = {
+ /* Addr allmodes */
+ {0x0000a38c, 0x00000000},
+ {0x0000a390, 0x6f7f0301},
+ {0x0000a394, 0xca9228ee},
+};
+
+static const u32 qca956x_1p0_modes_no_xpa_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x0000a2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000a2e0, 0xff323118, 0xff323118},
+ {0x0000a2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000a2e8, 0xffc00000, 0xffc00000},
+ {0x0000a39c, 0x42424242, 0x42424242},
+ {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00},
+ {0x0000a3b0, 0x00a01404, 0x00a01404},
+ {0x0000a3b4, 0x00000034, 0x00000034},
+ {0x0000a3b8, 0x00800408, 0x00800408},
+ {0x0000a3bc, 0x00000036, 0x00000036},
+ {0x0000a410, 0x000050dc, 0x000050dc},
+ {0x0000a500, 0x09000040, 0x09000040},
+ {0x0000a504, 0x0b000041, 0x0b000041},
+ {0x0000a508, 0x0d000042, 0x0d000042},
+ {0x0000a50c, 0x11000044, 0x11000044},
+ {0x0000a510, 0x15000046, 0x15000046},
+ {0x0000a514, 0x1d000440, 0x1d000440},
+ {0x0000a518, 0x1f000441, 0x1f000441},
+ {0x0000a51c, 0x23000443, 0x23000443},
+ {0x0000a520, 0x25000444, 0x25000444},
+ {0x0000a524, 0x280004e0, 0x280004e0},
+ {0x0000a528, 0x2c0004e2, 0x2c0004e2},
+ {0x0000a52c, 0x2e0004e3, 0x2e0004e3},
+ {0x0000a530, 0x300004e4, 0x300004e4},
+ {0x0000a534, 0x340004e6, 0x340004e6},
+ {0x0000a538, 0x37000ce0, 0x37000ce0},
+ {0x0000a53c, 0x3b000ce2, 0x3b000ce2},
+ {0x0000a540, 0x3d000ce3, 0x3d000ce3},
+ {0x0000a544, 0x3f000ce4, 0x3f000ce4},
+ {0x0000a548, 0x45001ee0, 0x45001ee0},
+ {0x0000a54c, 0x49001ee2, 0x49001ee2},
+ {0x0000a550, 0x4d001ee4, 0x4d001ee4},
+ {0x0000a554, 0x51001ee6, 0x51001ee6},
+ {0x0000a558, 0x55001eea, 0x55001eea},
+ {0x0000a55c, 0x59001eec, 0x59001eec},
+ {0x0000a560, 0x5d001ef0, 0x5d001ef0},
+ {0x0000a564, 0x5f001ef1, 0x5f001ef1},
+ {0x0000a568, 0x60001ef2, 0x60001ef2},
+ {0x0000a56c, 0x61001ef3, 0x61001ef3},
+ {0x0000a570, 0x62001ef4, 0x62001ef4},
+ {0x0000a574, 0x63001ef5, 0x63001ef5},
+ {0x0000a578, 0x64001ffc, 0x64001ffc},
+ {0x0000a57c, 0x64001ffc, 0x64001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00804000, 0x00804000},
+ {0x0000a614, 0x00804201, 0x00804201},
+ {0x0000a618, 0x00804201, 0x00804201},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000b2e0, 0xff323118, 0xff323118},
+ {0x0000b2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000b2e8, 0xffc00000, 0xffc00000},
+ {0x0000c2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000c2e0, 0xff323118, 0xff323118},
+ {0x0000c2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000c2e8, 0xffc00000, 0xffc00000},
+ {0x00016044, 0x049242db, 0x049242db},
+ {0x00016048, 0x64925a70, 0x64925a70},
+ {0x00016148, 0x00008050, 0x00008050},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a6000, 0x453a6000},
+ {0x00016444, 0x049242db, 0x049242db},
+ {0x00016448, 0x6c925a70, 0x6c925a70},
+ {0x00016548, 0x00008050, 0x00008050},
+ {0x00016844, 0x049242db, 0x049242db},
+ {0x00016848, 0x6c925a70, 0x6c925a70},
+ {0x00016948, 0x00008050, 0x00008050},
+};
+
+static const u32 qca956x_1p0_modes_xpa_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x0000a2dc, 0xcc69ac94, 0xcc69ac94},
+ {0x0000a2e0, 0xf0b23118, 0xf0b23118},
+ {0x0000a2e4, 0xffffc000, 0xffffc000},
+ {0x0000a2e8, 0xc0000000, 0xc0000000},
+ {0x0000a410, 0x000050d2, 0x000050d2},
+ {0x0000a500, 0x0a000040, 0x0a000040},
+ {0x0000a504, 0x0c000041, 0x0c000041},
+ {0x0000a508, 0x0e000042, 0x0e000042},
+ {0x0000a50c, 0x12000044, 0x12000044},
+ {0x0000a510, 0x16000046, 0x16000046},
+ {0x0000a514, 0x1d000440, 0x1d000440},
+ {0x0000a518, 0x1f000441, 0x1f000441},
+ {0x0000a51c, 0x23000443, 0x23000443},
+ {0x0000a520, 0x25000444, 0x25000444},
+ {0x0000a524, 0x29000a40, 0x29000a40},
+ {0x0000a528, 0x2d000a42, 0x2d000a42},
+ {0x0000a52c, 0x2f000a43, 0x2f000a43},
+ {0x0000a530, 0x31000a44, 0x31000a44},
+ {0x0000a534, 0x35000a46, 0x35000a46},
+ {0x0000a538, 0x38000ce0, 0x38000ce0},
+ {0x0000a53c, 0x3c000ce2, 0x3c000ce2},
+ {0x0000a540, 0x3e000ce3, 0x3e000ce3},
+ {0x0000a544, 0x40000ce4, 0x40000ce4},
+ {0x0000a548, 0x46001ee0, 0x46001ee0},
+ {0x0000a54c, 0x4a001ee2, 0x4a001ee2},
+ {0x0000a550, 0x4e001ee4, 0x4e001ee4},
+ {0x0000a554, 0x52001ee6, 0x52001ee6},
+ {0x0000a558, 0x56001eea, 0x56001eea},
+ {0x0000a55c, 0x5a001eec, 0x5a001eec},
+ {0x0000a560, 0x5e001ef0, 0x5e001ef0},
+ {0x0000a564, 0x60001ef1, 0x60001ef1},
+ {0x0000a568, 0x61001ef2, 0x61001ef2},
+ {0x0000a56c, 0x62001ef3, 0x62001ef3},
+ {0x0000a570, 0x63001ef4, 0x63001ef4},
+ {0x0000a574, 0x64001ef5, 0x64001ef5},
+ {0x0000a578, 0x65001ffc, 0x65001ffc},
+ {0x0000a57c, 0x65001ffc, 0x65001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00000000, 0x00000000},
+ {0x0000a614, 0x00000000, 0x00000000},
+ {0x0000a618, 0x00000000, 0x00000000},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xcc69ac94, 0xcc69ac94},
+ {0x0000b2e0, 0xf0b23118, 0xf0b23118},
+ {0x0000b2e4, 0xffffc000, 0xffffc000},
+ {0x0000b2e8, 0xc0000000, 0xc0000000},
+ {0x0000c2dc, 0xcc69ac94, 0xcc69ac94},
+ {0x0000c2e0, 0xf0b23118, 0xf0b23118},
+ {0x0000c2e4, 0xffffc000, 0xffffc000},
+ {0x0000c2e8, 0xc0000000, 0xc0000000},
+ {0x00016044, 0x012492db, 0x012492db},
+ {0x00016048, 0x6c927a70, 0x6c927a70},
+ {0x00016050, 0x8036d36c, 0x8036d36c},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a7e00, 0x453a7e00},
+ {0x00016444, 0x012492db, 0x012492db},
+ {0x00016448, 0x6c927a70, 0x6c927a70},
+ {0x00016450, 0x8036d36c, 0x8036d36c},
+ {0x00016844, 0x012492db, 0x012492db},
+ {0x00016848, 0x6c927a70, 0x6c927a70},
+ {0x00016850, 0x8036d36c, 0x8036d36c},
+};
+
+static const u32 qca956x_1p0_modes_no_xpa_low_ob_db_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x0000a2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000a2e0, 0xff323118, 0xff323118},
+ {0x0000a2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000a2e8, 0xffc00000, 0xffc00000},
+ {0x0000a39c, 0x42424242, 0x42424242},
+ {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00},
+ {0x0000a3b0, 0x00a01404, 0x00a01404},
+ {0x0000a3b4, 0x00000034, 0x00000034},
+ {0x0000a3b8, 0x00800408, 0x00800408},
+ {0x0000a3bc, 0x00000036, 0x00000036},
+ {0x0000a410, 0x000050dc, 0x000050dc},
+ {0x0000a414, 0x16b739ce, 0x16b739ce},
+ {0x0000a418, 0x2d00198b, 0x2d00198b},
+ {0x0000a41c, 0x16b5adce, 0x16b5adce},
+ {0x0000a420, 0x0000014a, 0x0000014a},
+ {0x0000a424, 0x14a525cc, 0x14a525cc},
+ {0x0000a428, 0x0000012a, 0x0000012a},
+ {0x0000a42c, 0x14a5294a, 0x14a5294a},
+ {0x0000a430, 0x1294a929, 0x1294a929},
+ {0x0000a500, 0x09000040, 0x09000040},
+ {0x0000a504, 0x0b000041, 0x0b000041},
+ {0x0000a508, 0x0d000042, 0x0d000042},
+ {0x0000a50c, 0x11000044, 0x11000044},
+ {0x0000a510, 0x15000046, 0x15000046},
+ {0x0000a514, 0x1d000440, 0x1d000440},
+ {0x0000a518, 0x1f000441, 0x1f000441},
+ {0x0000a51c, 0x23000443, 0x23000443},
+ {0x0000a520, 0x25000444, 0x25000444},
+ {0x0000a524, 0x280004e0, 0x280004e0},
+ {0x0000a528, 0x2c0004e2, 0x2c0004e2},
+ {0x0000a52c, 0x2e0004e3, 0x2e0004e3},
+ {0x0000a530, 0x300004e4, 0x300004e4},
+ {0x0000a534, 0x340004e6, 0x340004e6},
+ {0x0000a538, 0x37000ce0, 0x37000ce0},
+ {0x0000a53c, 0x3b000ce2, 0x3b000ce2},
+ {0x0000a540, 0x3d000ce3, 0x3d000ce3},
+ {0x0000a544, 0x3f000ce4, 0x3f000ce4},
+ {0x0000a548, 0x45001ee0, 0x45001ee0},
+ {0x0000a54c, 0x49001ee2, 0x49001ee2},
+ {0x0000a550, 0x4d001ee4, 0x4d001ee4},
+ {0x0000a554, 0x51001ee6, 0x51001ee6},
+ {0x0000a558, 0x55001eea, 0x55001eea},
+ {0x0000a55c, 0x59001eec, 0x59001eec},
+ {0x0000a560, 0x5d001ef0, 0x5d001ef0},
+ {0x0000a564, 0x5f001ef1, 0x5f001ef1},
+ {0x0000a568, 0x60001ef2, 0x60001ef2},
+ {0x0000a56c, 0x61001ef3, 0x61001ef3},
+ {0x0000a570, 0x62001ef4, 0x62001ef4},
+ {0x0000a574, 0x63001ef5, 0x63001ef5},
+ {0x0000a578, 0x64001ffc, 0x64001ffc},
+ {0x0000a57c, 0x64001ffc, 0x64001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00804000, 0x00804000},
+ {0x0000a614, 0x00804201, 0x00804201},
+ {0x0000a618, 0x00804201, 0x00804201},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000b2e0, 0xff323118, 0xff323118},
+ {0x0000b2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000b2e8, 0xffc00000, 0xffc00000},
+ {0x0000c2dc, 0xffa9ac94, 0xffa9ac94},
+ {0x0000c2e0, 0xff323118, 0xff323118},
+ {0x0000c2e4, 0xff3ffe00, 0xff3ffe00},
+ {0x0000c2e8, 0xffc00000, 0xffc00000},
+ {0x00016044, 0x046e42db, 0x046e42db},
+ {0x00016048, 0x64925a70, 0x64925a70},
+ {0x00016148, 0x00008050, 0x00008050},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a6000, 0x453a6000},
+ {0x00016444, 0x046e42db, 0x046e42db},
+ {0x00016448, 0x6c925a70, 0x6c925a70},
+ {0x00016548, 0x00008050, 0x00008050},
+ {0x00016844, 0x046e42db, 0x046e42db},
+ {0x00016848, 0x6c925a70, 0x6c925a70},
+ {0x00016948, 0x00008050, 0x00008050},
+};
+
+static const u32 qca956x_1p0_modes_no_xpa_green_tx_gain_table[][3] = {
+ /* Addr 5G 2G */
+ {0x000098bc, 0x00000001, 0x00000001},
+ {0x0000a2dc, 0xd3555284, 0xd3555284},
+ {0x0000a2e0, 0x1c666318, 0x1c666318},
+ {0x0000a2e4, 0xe07bbc00, 0xe07bbc00},
+ {0x0000a2e8, 0xff800000, 0xff800000},
+ {0x0000a3a4, 0x3a3e3e00, 0x3a3e3e00},
+ {0x0000a410, 0x000050dc, 0x000050dc},
+ {0x0000a500, 0x02000040, 0x02000040},
+ {0x0000a504, 0x04000041, 0x04000041},
+ {0x0000a508, 0x06000042, 0x06000042},
+ {0x0000a50c, 0x0a000044, 0x0a000044},
+ {0x0000a510, 0x0c000045, 0x0c000045},
+ {0x0000a514, 0x13000440, 0x13000440},
+ {0x0000a518, 0x15000441, 0x15000441},
+ {0x0000a51c, 0x19000443, 0x19000443},
+ {0x0000a520, 0x1b000444, 0x1b000444},
+ {0x0000a524, 0x1e0004e0, 0x1e0004e0},
+ {0x0000a528, 0x220004e2, 0x220004e2},
+ {0x0000a52c, 0x240004e3, 0x240004e3},
+ {0x0000a530, 0x260004e4, 0x260004e4},
+ {0x0000a534, 0x2a0004e6, 0x2a0004e6},
+ {0x0000a538, 0x32000ce0, 0x32000ce0},
+ {0x0000a53c, 0x36000ce2, 0x36000ce2},
+ {0x0000a540, 0x3a000ce4, 0x3a000ce4},
+ {0x0000a544, 0x3e000ce6, 0x3e000ce6},
+ {0x0000a548, 0x45001ee0, 0x45001ee0},
+ {0x0000a54c, 0x49001ee2, 0x49001ee2},
+ {0x0000a550, 0x4d001ee4, 0x4d001ee4},
+ {0x0000a554, 0x51001ee6, 0x51001ee6},
+ {0x0000a558, 0x55001eea, 0x55001eea},
+ {0x0000a55c, 0x59001eec, 0x59001eec},
+ {0x0000a560, 0x5d001ef0, 0x5d001ef0},
+ {0x0000a564, 0x5f001ef1, 0x5f001ef1},
+ {0x0000a568, 0x60001ef2, 0x60001ef2},
+ {0x0000a56c, 0x61001ef3, 0x61001ef3},
+ {0x0000a570, 0x62001ef4, 0x62001ef4},
+ {0x0000a574, 0x63001ff5, 0x63001ff5},
+ {0x0000a578, 0x64001ffc, 0x64001ffc},
+ {0x0000a57c, 0x64001ffc, 0x64001ffc},
+ {0x0000a600, 0x00000000, 0x00000000},
+ {0x0000a604, 0x00000000, 0x00000000},
+ {0x0000a608, 0x00000000, 0x00000000},
+ {0x0000a60c, 0x00000000, 0x00000000},
+ {0x0000a610, 0x00804000, 0x00804000},
+ {0x0000a614, 0x00804201, 0x00804201},
+ {0x0000a618, 0x00804201, 0x00804201},
+ {0x0000a61c, 0x00804201, 0x00804201},
+ {0x0000a620, 0x00804201, 0x00804201},
+ {0x0000a624, 0x00804201, 0x00804201},
+ {0x0000a628, 0x00804201, 0x00804201},
+ {0x0000a62c, 0x02808a02, 0x02808a02},
+ {0x0000a630, 0x0340cd03, 0x0340cd03},
+ {0x0000a634, 0x0340cd03, 0x0340cd03},
+ {0x0000a638, 0x0340cd03, 0x0340cd03},
+ {0x0000a63c, 0x05011404, 0x05011404},
+ {0x0000b2dc, 0xd3555284, 0xd3555284},
+ {0x0000b2e0, 0x1c666318, 0x1c666318},
+ {0x0000b2e4, 0xe07bbc00, 0xe07bbc00},
+ {0x0000b2e8, 0xff800000, 0xff800000},
+ {0x0000c2dc, 0xd3555284, 0xd3555284},
+ {0x0000c2e0, 0x1c666318, 0x1c666318},
+ {0x0000c2e4, 0xe07bbc00, 0xe07bbc00},
+ {0x0000c2e8, 0xff800000, 0xff800000},
+ {0x00016044, 0x849242db, 0x849242db},
+ {0x00016048, 0x64925a70, 0x64925a70},
+ {0x00016280, 0x41110005, 0x41110005},
+ {0x00016284, 0x453a6000, 0x453a6000},
+ {0x00016444, 0x849242db, 0x849242db},
+ {0x00016448, 0x6c925a70, 0x6c925a70},
+ {0x00016844, 0x849242db, 0x849242db},
+ {0x00016848, 0x6c925a70, 0x6c925a70},
+ {0x0000a7f0, 0x800002cc, 0x800002cc},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000018, 0x00000018},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000028, 0x00000028},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+ {0x0000a7f4, 0x00000048, 0x00000048},
+};
+
+static const u32 qca956x_1p0_common_rx_gain_table[][2] = {
+ /* Addr allmodes */
+ {0x0000a000, 0x00010000},
+ {0x0000a004, 0x00030002},
+ {0x0000a008, 0x00050004},
+ {0x0000a00c, 0x00810080},
+ {0x0000a010, 0x00830082},
+ {0x0000a014, 0x01810180},
+ {0x0000a018, 0x01830182},
+ {0x0000a01c, 0x01850184},
+ {0x0000a020, 0x01890188},
+ {0x0000a024, 0x018b018a},
+ {0x0000a028, 0x018d018c},
+ {0x0000a02c, 0x01910190},
+ {0x0000a030, 0x01930192},
+ {0x0000a034, 0x01950194},
+ {0x0000a038, 0x038a0196},
+ {0x0000a03c, 0x038c038b},
+ {0x0000a040, 0x0390038d},
+ {0x0000a044, 0x03920391},
+ {0x0000a048, 0x03940393},
+ {0x0000a04c, 0x03960395},
+ {0x0000a050, 0x00000000},
+ {0x0000a054, 0x00000000},
+ {0x0000a058, 0x00000000},
+ {0x0000a05c, 0x00000000},
+ {0x0000a060, 0x00000000},
+ {0x0000a064, 0x00000000},
+ {0x0000a068, 0x00000000},
+ {0x0000a06c, 0x00000000},
+ {0x0000a070, 0x00000000},
+ {0x0000a074, 0x00000000},
+ {0x0000a078, 0x00000000},
+ {0x0000a07c, 0x00000000},
+ {0x0000a080, 0x22222222},
+ {0x0000a084, 0x1d1d1d1d},
+ {0x0000a088, 0x1d1d1d1d},
+ {0x0000a08c, 0x1d1d1d1d},
+ {0x0000a090, 0x17171717},
+ {0x0000a094, 0x11111717},
+ {0x0000a098, 0x00030311},
+ {0x0000a09c, 0x00000000},
+ {0x0000a0a0, 0x00000000},
+ {0x0000a0a4, 0x00000000},
+ {0x0000a0a8, 0x00000000},
+ {0x0000a0ac, 0x00000000},
+ {0x0000a0b0, 0x00000000},
+ {0x0000a0b4, 0x00000000},
+ {0x0000a0b8, 0x00000000},
+ {0x0000a0bc, 0x00000000},
+ {0x0000a0c0, 0x001f0000},
+ {0x0000a0c4, 0x01000101},
+ {0x0000a0c8, 0x011e011f},
+ {0x0000a0cc, 0x011c011d},
+ {0x0000a0d0, 0x02030204},
+ {0x0000a0d4, 0x02010202},
+ {0x0000a0d8, 0x021f0200},
+ {0x0000a0dc, 0x0302021e},
+ {0x0000a0e0, 0x03000301},
+ {0x0000a0e4, 0x031e031f},
+ {0x0000a0e8, 0x0402031d},
+ {0x0000a0ec, 0x04000401},
+ {0x0000a0f0, 0x041e041f},
+ {0x0000a0f4, 0x0502041d},
+ {0x0000a0f8, 0x05000501},
+ {0x0000a0fc, 0x051e051f},
+ {0x0000a100, 0x06010602},
+ {0x0000a104, 0x061f0600},
+ {0x0000a108, 0x061d061e},
+ {0x0000a10c, 0x07020703},
+ {0x0000a110, 0x07000701},
+ {0x0000a114, 0x00000000},
+ {0x0000a118, 0x00000000},
+ {0x0000a11c, 0x00000000},
+ {0x0000a120, 0x00000000},
+ {0x0000a124, 0x00000000},
+ {0x0000a128, 0x00000000},
+ {0x0000a12c, 0x00000000},
+ {0x0000a130, 0x00000000},
+ {0x0000a134, 0x00000000},
+ {0x0000a138, 0x00000000},
+ {0x0000a13c, 0x00000000},
+ {0x0000a140, 0x001f0000},
+ {0x0000a144, 0x01000101},
+ {0x0000a148, 0x011e011f},
+ {0x0000a14c, 0x011c011d},
+ {0x0000a150, 0x02030204},
+ {0x0000a154, 0x02010202},
+ {0x0000a158, 0x021f0200},
+ {0x0000a15c, 0x0302021e},
+ {0x0000a160, 0x03000301},
+ {0x0000a164, 0x031e031f},
+ {0x0000a168, 0x0402031d},
+ {0x0000a16c, 0x04000401},
+ {0x0000a170, 0x041e041f},
+ {0x0000a174, 0x0502041d},
+ {0x0000a178, 0x05000501},
+ {0x0000a17c, 0x051e051f},
+ {0x0000a180, 0x06010602},
+ {0x0000a184, 0x061f0600},
+ {0x0000a188, 0x061d061e},
+ {0x0000a18c, 0x07020703},
+ {0x0000a190, 0x07000701},
+ {0x0000a194, 0x00000000},
+ {0x0000a198, 0x00000000},
+ {0x0000a19c, 0x00000000},
+ {0x0000a1a0, 0x00000000},
+ {0x0000a1a4, 0x00000000},
+ {0x0000a1a8, 0x00000000},
+ {0x0000a1ac, 0x00000000},
+ {0x0000a1b0, 0x00000000},
+ {0x0000a1b4, 0x00000000},
+ {0x0000a1b8, 0x00000000},
+ {0x0000a1bc, 0x00000000},
+ {0x0000a1c0, 0x00000000},
+ {0x0000a1c4, 0x00000000},
+ {0x0000a1c8, 0x00000000},
+ {0x0000a1cc, 0x00000000},
+ {0x0000a1d0, 0x00000000},
+ {0x0000a1d4, 0x00000000},
+ {0x0000a1d8, 0x00000000},
+ {0x0000a1dc, 0x00000000},
+ {0x0000a1e0, 0x00000000},
+ {0x0000a1e4, 0x00000000},
+ {0x0000a1e8, 0x00000000},
+ {0x0000a1ec, 0x00000000},
+ {0x0000a1f0, 0x00000396},
+ {0x0000a1f4, 0x00000396},
+ {0x0000a1f8, 0x00000396},
+ {0x0000a1fc, 0x00000196},
+ {0x0000b000, 0x00010000},
+ {0x0000b004, 0x00030002},
+ {0x0000b008, 0x00050004},
+ {0x0000b00c, 0x00810080},
+ {0x0000b010, 0x00830082},
+ {0x0000b014, 0x01810180},
+ {0x0000b018, 0x01830182},
+ {0x0000b01c, 0x01850184},
+ {0x0000b020, 0x02810280},
+ {0x0000b024, 0x02830282},
+ {0x0000b028, 0x02850284},
+ {0x0000b02c, 0x02890288},
+ {0x0000b030, 0x028b028a},
+ {0x0000b034, 0x0388028c},
+ {0x0000b038, 0x038a0389},
+ {0x0000b03c, 0x038c038b},
+ {0x0000b040, 0x0390038d},
+ {0x0000b044, 0x03920391},
+ {0x0000b048, 0x03940393},
+ {0x0000b04c, 0x03960395},
+ {0x0000b050, 0x00000000},
+ {0x0000b054, 0x00000000},
+ {0x0000b058, 0x00000000},
+ {0x0000b05c, 0x00000000},
+ {0x0000b060, 0x00000000},
+ {0x0000b064, 0x00000000},
+ {0x0000b068, 0x00000000},
+ {0x0000b06c, 0x00000000},
+ {0x0000b070, 0x00000000},
+ {0x0000b074, 0x00000000},
+ {0x0000b078, 0x00000000},
+ {0x0000b07c, 0x00000000},
+ {0x0000b080, 0x23232323},
+ {0x0000b084, 0x21232323},
+ {0x0000b088, 0x19191c1e},
+ {0x0000b08c, 0x12141417},
+ {0x0000b090, 0x07070e0e},
+ {0x0000b094, 0x03030305},
+ {0x0000b098, 0x00000003},
+ {0x0000b09c, 0x00000000},
+ {0x0000b0a0, 0x00000000},
+ {0x0000b0a4, 0x00000000},
+ {0x0000b0a8, 0x00000000},
+ {0x0000b0ac, 0x00000000},
+ {0x0000b0b0, 0x00000000},
+ {0x0000b0b4, 0x00000000},
+ {0x0000b0b8, 0x00000000},
+ {0x0000b0bc, 0x00000000},
+ {0x0000b0c0, 0x003f0020},
+ {0x0000b0c4, 0x00400041},
+ {0x0000b0c8, 0x0140005f},
+ {0x0000b0cc, 0x0160015f},
+ {0x0000b0d0, 0x017e017f},
+ {0x0000b0d4, 0x02410242},
+ {0x0000b0d8, 0x025f0240},
+ {0x0000b0dc, 0x027f0260},
+ {0x0000b0e0, 0x0341027e},
+ {0x0000b0e4, 0x035f0340},
+ {0x0000b0e8, 0x037f0360},
+ {0x0000b0ec, 0x04400441},
+ {0x0000b0f0, 0x0460045f},
+ {0x0000b0f4, 0x0541047f},
+ {0x0000b0f8, 0x055f0540},
+ {0x0000b0fc, 0x057f0560},
+ {0x0000b100, 0x06400641},
+ {0x0000b104, 0x0660065f},
+ {0x0000b108, 0x067e067f},
+ {0x0000b10c, 0x07410742},
+ {0x0000b110, 0x075f0740},
+ {0x0000b114, 0x077f0760},
+ {0x0000b118, 0x07800781},
+ {0x0000b11c, 0x07a0079f},
+ {0x0000b120, 0x07c107bf},
+ {0x0000b124, 0x000007c0},
+ {0x0000b128, 0x00000000},
+ {0x0000b12c, 0x00000000},
+ {0x0000b130, 0x00000000},
+ {0x0000b134, 0x00000000},
+ {0x0000b138, 0x00000000},
+ {0x0000b13c, 0x00000000},
+ {0x0000b140, 0x003f0020},
+ {0x0000b144, 0x00400041},
+ {0x0000b148, 0x0140005f},
+ {0x0000b14c, 0x0160015f},
+ {0x0000b150, 0x017e017f},
+ {0x0000b154, 0x02410242},
+ {0x0000b158, 0x025f0240},
+ {0x0000b15c, 0x027f0260},
+ {0x0000b160, 0x0341027e},
+ {0x0000b164, 0x035f0340},
+ {0x0000b168, 0x037f0360},
+ {0x0000b16c, 0x04400441},
+ {0x0000b170, 0x0460045f},
+ {0x0000b174, 0x0541047f},
+ {0x0000b178, 0x055f0540},
+ {0x0000b17c, 0x057f0560},
+ {0x0000b180, 0x06400641},
+ {0x0000b184, 0x0660065f},
+ {0x0000b188, 0x067e067f},
+ {0x0000b18c, 0x07410742},
+ {0x0000b190, 0x075f0740},
+ {0x0000b194, 0x077f0760},
+ {0x0000b198, 0x07800781},
+ {0x0000b19c, 0x07a0079f},
+ {0x0000b1a0, 0x07c107bf},
+ {0x0000b1a4, 0x000007c0},
+ {0x0000b1a8, 0x00000000},
+ {0x0000b1ac, 0x00000000},
+ {0x0000b1b0, 0x00000000},
+ {0x0000b1b4, 0x00000000},
+ {0x0000b1b8, 0x00000000},
+ {0x0000b1bc, 0x00000000},
+ {0x0000b1c0, 0x00000000},
+ {0x0000b1c4, 0x00000000},
+ {0x0000b1c8, 0x00000000},
+ {0x0000b1cc, 0x00000000},
+ {0x0000b1d0, 0x00000000},
+ {0x0000b1d4, 0x00000000},
+ {0x0000b1d8, 0x00000000},
+ {0x0000b1dc, 0x00000000},
+ {0x0000b1e0, 0x00000000},
+ {0x0000b1e4, 0x00000000},
+ {0x0000b1e8, 0x00000000},
+ {0x0000b1ec, 0x00000000},
+ {0x0000b1f0, 0x00000396},
+ {0x0000b1f4, 0x00000396},
+ {0x0000b1f8, 0x00000396},
+ {0x0000b1fc, 0x00000196},
+};
+
+static const u32 qca956x_1p0_xlna_only[][5] = {
+ /* Addr 5G_HT20 5G_HT40 2G_HT40 2G_HT20 */
+ {0x00009820, 0x206a022e, 0x206a022e, 0x206a01ae, 0x206a01ae},
+ {0x00009824, 0x5ac640d0, 0x5ac640d0, 0x5ac621f1, 0x5ac621f1},
+ {0x00009828, 0x06903081, 0x06903081, 0x07d43881, 0x07d43881},
+ {0x00009e00, 0x0372111a, 0x0372111a, 0x037216a0, 0x03721720},
+ {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000de, 0x6c4000da},
+ {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec86d2e, 0x7ec8ad2e},
+ {0x00009e14, 0x37b95d5e, 0x37b9605e, 0x317a6062, 0x317a5ae2},
+ {0x00009e18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000},
+ {0x00009e20, 0x000003b5, 0x000003b5, 0x000003b2, 0x000003b2},
+ {0x00009fc0, 0x813e4788, 0x813e4788, 0x813e4789, 0x813e4789},
+ {0x0000ae18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000},
+ {0x0000ae20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2},
+ {0x0000be18, 0x00000000, 0x00000000, 0x03c00000, 0x03c00000},
+ {0x0000be20, 0x000001b5, 0x000001b5, 0x000001b2, 0x000001b2},
+};
+
+#endif /* INITVALS_956X_H */
diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h
index 1a9fe0983a6b..0f8e9464e4ab 100644
--- a/drivers/net/wireless/ath/ath9k/ath9k.h
+++ b/drivers/net/wireless/ath/ath9k/ath9k.h
@@ -34,7 +34,7 @@ struct ath_vif;
extern struct ieee80211_ops ath9k_ops;
extern int ath9k_modparam_nohwcrypt;
-extern int led_blink;
+extern int ath9k_led_blink;
extern bool is_ath9k_unloaded;
extern int ath9k_use_chanctx;
@@ -830,14 +830,9 @@ static inline void ath_fill_led_pin(struct ath_softc *sc)
/* Wake on Wireless LAN */
/************************/
-struct ath9k_wow_pattern {
- u8 pattern_bytes[MAX_PATTERN_SIZE];
- u8 mask_bytes[MAX_PATTERN_SIZE];
- u32 pattern_len;
-};
-
#ifdef CONFIG_ATH9K_WOW
void ath9k_init_wow(struct ieee80211_hw *hw);
+void ath9k_deinit_wow(struct ieee80211_hw *hw);
int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan);
int ath9k_resume(struct ieee80211_hw *hw);
@@ -846,6 +841,9 @@ void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled);
static inline void ath9k_init_wow(struct ieee80211_hw *hw)
{
}
+static inline void ath9k_deinit_wow(struct ieee80211_hw *hw)
+{
+}
static inline int ath9k_suspend(struct ieee80211_hw *hw,
struct cfg80211_wowlan *wowlan)
{
@@ -1039,9 +1037,8 @@ struct ath_softc {
s16 tx99_power;
#ifdef CONFIG_ATH9K_WOW
- atomic_t wow_got_bmiss_intr;
- atomic_t wow_sleep_proc_intr; /* in the middle of WoW sleep ? */
u32 wow_intr_before_sleep;
+ bool force_wow;
#endif
};
diff --git a/drivers/net/wireless/ath/ath9k/common-spectral.c b/drivers/net/wireless/ath/ath9k/common-spectral.c
index ec93ddf0863a..5cee231cca1f 100644
--- a/drivers/net/wireless/ath/ath9k/common-spectral.c
+++ b/drivers/net/wireless/ath/ath9k/common-spectral.c
@@ -582,7 +582,7 @@ static struct rchan_callbacks rfs_spec_scan_cb = {
void ath9k_cmn_spectral_deinit_debug(struct ath_spec_scan_priv *spec_priv)
{
- if (config_enabled(CONFIG_ATH9K_DEBUGFS) && spec_priv->rfs_chan_spec_scan) {
+ if (config_enabled(CONFIG_ATH9K_DEBUGFS)) {
relay_close(spec_priv->rfs_chan_spec_scan);
spec_priv->rfs_chan_spec_scan = NULL;
}
diff --git a/drivers/net/wireless/ath/ath9k/debug.c b/drivers/net/wireless/ath/ath9k/debug.c
index 871e969409bf..50a2e0ac3b8b 100644
--- a/drivers/net/wireless/ath/ath9k/debug.c
+++ b/drivers/net/wireless/ath/ath9k/debug.c
@@ -403,7 +403,8 @@ static const struct file_operations fops_antenna_diversity = {
static int read_file_dma(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
u32 val[ATH9K_NUM_DMA_DEBUG_REGS];
int i, qcuOffset = 0, dcuOffset = 0;
@@ -470,20 +471,6 @@ static int read_file_dma(struct seq_file *file, void *data)
return 0;
}
-static int open_file_dma(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_dma, inode->i_private);
-}
-
-static const struct file_operations fops_dma = {
- .open = open_file_dma,
- .read = seq_read,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-
void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
{
if (status)
@@ -539,7 +526,8 @@ void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status)
static int read_file_interrupt(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
#define PR_IS(a, s) \
do { \
@@ -600,22 +588,10 @@ static int read_file_interrupt(struct seq_file *file, void *data)
return 0;
}
-static int open_file_interrupt(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_interrupt, inode->i_private);
-}
-
-static const struct file_operations fops_interrupt = {
- .read = seq_read,
- .open = open_file_interrupt,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
static int read_file_xmit(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
seq_printf(file, "%30s %10s%10s%10s\n\n", "BE", "BK", "VI", "VO");
@@ -661,7 +637,8 @@ static void print_queue(struct ath_softc *sc, struct ath_txq *txq,
static int read_file_queues(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_txq *txq;
int i;
static const char *qname[4] = {
@@ -682,7 +659,8 @@ static int read_file_queues(struct seq_file *file, void *data)
static int read_file_misc(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_common *common = ath9k_hw_common(sc->sc_ah);
struct ath9k_vif_iter_data iter_data;
struct ath_chanctx *ctx;
@@ -773,7 +751,8 @@ static int read_file_misc(struct seq_file *file, void *data)
static int read_file_reset(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
static const char * const reset_cause[__RESET_TYPE_MAX] = {
[RESET_TYPE_BB_HANG] = "Baseband Hang",
[RESET_TYPE_BB_WATCHDOG] = "Baseband Watchdog",
@@ -837,58 +816,6 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
TX_STAT_INC(qnum, delim_underrun);
}
-static int open_file_xmit(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_xmit, inode->i_private);
-}
-
-static const struct file_operations fops_xmit = {
- .read = seq_read,
- .open = open_file_xmit,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int open_file_queues(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_queues, inode->i_private);
-}
-
-static const struct file_operations fops_queues = {
- .read = seq_read,
- .open = open_file_queues,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int open_file_misc(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_misc, inode->i_private);
-}
-
-static const struct file_operations fops_misc = {
- .read = seq_read,
- .open = open_file_misc,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int open_file_reset(struct inode *inode, struct file *f)
-{
- return single_open(f, read_file_reset, inode->i_private);
-}
-
-static const struct file_operations fops_reset = {
- .read = seq_read,
- .open = open_file_reset,
- .owner = THIS_MODULE,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
void ath_debug_stat_rx(struct ath_softc *sc, struct ath_rx_status *rs)
{
ath9k_cmn_debug_stat_rx(&sc->debug.stats.rxstats, rs);
@@ -1018,7 +945,8 @@ static const struct file_operations fops_regdump = {
static int read_file_dump_nfcal(struct seq_file *file, void *data)
{
- struct ath_softc *sc = file->private;
+ struct ieee80211_hw *hw = dev_get_drvdata(file->private);
+ struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath9k_nfcal_hist *h = sc->cur_chan->caldata.nfCalHist;
struct ath_common *common = ath9k_hw_common(ah);
@@ -1115,6 +1043,133 @@ static const struct file_operations fops_ackto = {
};
#endif
+#ifdef CONFIG_ATH9K_WOW
+
+static ssize_t read_file_wow(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned int len = 0, size = 32;
+ ssize_t retval;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += scnprintf(buf + len, size - len, "WOW: %s\n",
+ sc->force_wow ? "ENABLED" : "DISABLED");
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static ssize_t write_file_wow(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val != 1)
+ return -EINVAL;
+
+ if (!sc->force_wow) {
+ sc->force_wow = true;
+ ath9k_init_wow(sc->hw);
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_wow = {
+ .read = read_file_wow,
+ .write = write_file_wow,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
+#endif
+
+static ssize_t read_file_tpc(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hw *ah = sc->sc_ah;
+ unsigned int len = 0, size = 32;
+ ssize_t retval;
+ char *buf;
+
+ buf = kzalloc(size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ len += scnprintf(buf + len, size - len, "%s\n",
+ ah->tpc_enabled ? "ENABLED" : "DISABLED");
+
+ if (len > size)
+ len = size;
+
+ retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
+ kfree(buf);
+
+ return retval;
+}
+
+static ssize_t write_file_tpc(struct file *file, const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ath_softc *sc = file->private_data;
+ struct ath_hw *ah = sc->sc_ah;
+ unsigned long val;
+ char buf[32];
+ ssize_t len;
+ bool tpc_enabled;
+
+ len = min(count, sizeof(buf) - 1);
+ if (copy_from_user(buf, user_buf, len))
+ return -EFAULT;
+
+ buf[len] = '\0';
+ if (kstrtoul(buf, 0, &val))
+ return -EINVAL;
+
+ if (val < 0 || val > 1)
+ return -EINVAL;
+
+ tpc_enabled = !!val;
+
+ if (tpc_enabled != ah->tpc_enabled) {
+ ah->tpc_enabled = tpc_enabled;
+ ath9k_hw_set_txpowerlimit(ah, sc->cur_chan->txpower, false);
+ }
+
+ return count;
+}
+
+static const struct file_operations fops_tpc = {
+ .read = read_file_tpc,
+ .write = write_file_tpc,
+ .open = simple_open,
+ .owner = THIS_MODULE,
+ .llseek = default_llseek,
+};
+
/* Ethtool support for get-stats */
#define AMKSTR(nm) #nm "_BE", #nm "_BK", #nm "_VI", #nm "_VO"
@@ -1260,14 +1315,14 @@ int ath9k_init_debug(struct ath_hw *ah)
ath9k_tx99_init_debug(sc);
ath9k_cmn_spectral_init_debug(&sc->spec_priv, sc->debug.debugfs_phy);
- debugfs_create_file("dma", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_dma);
- debugfs_create_file("interrupt", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_interrupt);
- debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_xmit);
- debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_queues);
+ debugfs_create_devm_seqfile(sc->dev, "dma", sc->debug.debugfs_phy,
+ read_file_dma);
+ debugfs_create_devm_seqfile(sc->dev, "interrupt", sc->debug.debugfs_phy,
+ read_file_interrupt);
+ debugfs_create_devm_seqfile(sc->dev, "xmit", sc->debug.debugfs_phy,
+ read_file_xmit);
+ debugfs_create_devm_seqfile(sc->dev, "queues", sc->debug.debugfs_phy,
+ read_file_queues);
debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[IEEE80211_AC_BK]);
debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
@@ -1276,10 +1331,10 @@ int ath9k_init_debug(struct ath_hw *ah)
&sc->tx.txq_max_pending[IEEE80211_AC_VI]);
debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
&sc->tx.txq_max_pending[IEEE80211_AC_VO]);
- debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_misc);
- debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_reset);
+ debugfs_create_devm_seqfile(sc->dev, "misc", sc->debug.debugfs_phy,
+ read_file_misc);
+ debugfs_create_devm_seqfile(sc->dev, "reset", sc->debug.debugfs_phy,
+ read_file_reset);
ath9k_cmn_debug_recv(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
ath9k_cmn_debug_phy_err(sc->debug.debugfs_phy, &sc->debug.stats.rxstats);
@@ -1301,8 +1356,9 @@ int ath9k_init_debug(struct ath_hw *ah)
&ah->config.cwm_ignore_extcca);
debugfs_create_file("regdump", S_IRUSR, sc->debug.debugfs_phy, sc,
&fops_regdump);
- debugfs_create_file("dump_nfcal", S_IRUSR, sc->debug.debugfs_phy, sc,
- &fops_dump_nfcal);
+ debugfs_create_devm_seqfile(sc->dev, "dump_nfcal",
+ sc->debug.debugfs_phy,
+ read_file_dump_nfcal);
ath9k_cmn_debug_base_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
ath9k_cmn_debug_modal_eeprom(sc->debug.debugfs_phy, sc->sc_ah);
@@ -1320,10 +1376,17 @@ int ath9k_init_debug(struct ath_hw *ah)
&fops_btcoex);
#endif
+#ifdef CONFIG_ATH9K_WOW
+ debugfs_create_file("wow", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_wow);
+#endif
+
#ifdef CONFIG_ATH9K_DYNACK
debugfs_create_file("ack_to", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
sc, &fops_ackto);
#endif
+ debugfs_create_file("tpc", S_IRUSR | S_IWUSR,
+ sc->debug.debugfs_phy, sc, &fops_tpc);
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_4k.c b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
index 07b806c56c56..e5a78d4fd66e 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_4k.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_4k.c
@@ -748,6 +748,20 @@ static void ath9k_hw_4k_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
+ /* TPC initializations */
+ if (ah->tpc_enabled) {
+ int ht40_delta;
+
+ ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
+ ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
+ /* Enable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
+ MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+ } else {
+ /* Disable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
+ }
+
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_9287.c b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
index 5ba1385c9838..6ca33dfde1fd 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_9287.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_9287.c
@@ -886,6 +886,21 @@ static void ath9k_hw_ar9287_set_txpower(struct ath_hw *ah,
| ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
| ATH9K_POW_SM(ratesArray[rateDupCck], 0));
}
+
+ /* TPC initializations */
+ if (ah->tpc_enabled) {
+ int ht40_delta;
+
+ ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
+ ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
+ /* Enable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
+ MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+ } else {
+ /* Disable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
+ }
+
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/eeprom_def.c b/drivers/net/wireless/ath/ath9k/eeprom_def.c
index 122b846b8ec0..098059039351 100644
--- a/drivers/net/wireless/ath/ath9k/eeprom_def.c
+++ b/drivers/net/wireless/ath/ath9k/eeprom_def.c
@@ -1332,6 +1332,20 @@ static void ath9k_hw_def_set_txpower(struct ath_hw *ah,
ATH9K_POW_SM(pModal->pwrDecreaseFor3Chain, 6)
| ATH9K_POW_SM(pModal->pwrDecreaseFor2Chain, 0));
+ /* TPC initializations */
+ if (ah->tpc_enabled) {
+ int ht40_delta;
+
+ ht40_delta = (IS_CHAN_HT40(chan)) ? ht40PowerIncForPdadc : 0;
+ ar5008_hw_init_rate_txpower(ah, ratesArray, chan, ht40_delta);
+ /* Enable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX,
+ MAX_RATE_POWER | AR_PHY_POWER_TX_RATE_MAX_TPC_ENABLE);
+ } else {
+ /* Disable TPC */
+ REG_WRITE(ah, AR_PHY_POWER_TX_RATE_MAX, MAX_RATE_POWER);
+ }
+
REGWRITE_BUFFER_FLUSH(ah);
}
diff --git a/drivers/net/wireless/ath/ath9k/gpio.c b/drivers/net/wireless/ath/ath9k/gpio.c
index 2fef7a480fec..da344b27326c 100644
--- a/drivers/net/wireless/ath/ath9k/gpio.c
+++ b/drivers/net/wireless/ath/ath9k/gpio.c
@@ -49,7 +49,7 @@ void ath_init_leds(struct ath_softc *sc)
if (AR_SREV_9100(sc->sc_ah))
return;
- if (!led_blink)
+ if (!ath9k_led_blink)
sc->led_cdev.default_trigger =
ieee80211_get_radio_led_name(sc->hw);
diff --git a/drivers/net/wireless/ath/ath9k/htc.h b/drivers/net/wireless/ath/ath9k/htc.h
index 9dde265d3f84..300d3671d0ef 100644
--- a/drivers/net/wireless/ath/ath9k/htc.h
+++ b/drivers/net/wireless/ath/ath9k/htc.h
@@ -44,6 +44,9 @@
extern struct ieee80211_ops ath9k_htc_ops;
extern int htc_modparam_nohwcrypt;
+#ifdef CONFIG_MAC80211_LEDS
+extern int ath9k_htc_led_blink;
+#endif
enum htc_phymode {
HTC_MODE_11NA = 0,
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
index 8cef1edcc621..dc79afd7e151 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_debug.c
@@ -291,26 +291,15 @@ static ssize_t read_file_slot(struct file *file, char __user *user_buf,
{
struct ath9k_htc_priv *priv = file->private_data;
char buf[512];
- unsigned int len = 0;
+ unsigned int len;
spin_lock_bh(&priv->tx.tx_lock);
-
- len += scnprintf(buf + len, sizeof(buf) - len, "TX slot bitmap : ");
-
- len += bitmap_scnprintf(buf + len, sizeof(buf) - len,
- priv->tx.tx_slot, MAX_TX_BUF_NUM);
-
- len += scnprintf(buf + len, sizeof(buf) - len, "\n");
-
- len += scnprintf(buf + len, sizeof(buf) - len,
- "Used slots : %d\n",
- bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
-
+ len = scnprintf(buf, sizeof(buf),
+ "TX slot bitmap : %*pb\n"
+ "Used slots : %d\n",
+ MAX_TX_BUF_NUM, priv->tx.tx_slot,
+ bitmap_weight(priv->tx.tx_slot, MAX_TX_BUF_NUM));
spin_unlock_bh(&priv->tx.tx_lock);
-
- if (len > sizeof(buf))
- len = sizeof(buf);
-
return simple_read_from_buffer(user_buf, count, ppos, buf, len);
}
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
index 50f74a2a4cf8..2aabcbdaba4e 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
@@ -279,6 +279,10 @@ void ath9k_init_leds(struct ath9k_htc_priv *priv)
else
priv->ah->led_pin = ATH_LED_PIN_DEF;
+ if (!ath9k_htc_led_blink)
+ priv->led_cdev.default_trigger =
+ ieee80211_get_radio_led_name(priv->hw);
+
ath9k_configure_leds(priv);
snprintf(priv->led_name, sizeof(priv->led_name),
diff --git a/drivers/net/wireless/ath/ath9k/htc_drv_init.c b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
index e8fa9448da24..fd229409f676 100644
--- a/drivers/net/wireless/ath/ath9k/htc_drv_init.c
+++ b/drivers/net/wireless/ath/ath9k/htc_drv_init.c
@@ -39,6 +39,10 @@ module_param_named(ps_enable, ath9k_ps_enable, int, 0444);
MODULE_PARM_DESC(ps_enable, "Enable WLAN PowerSave");
#ifdef CONFIG_MAC80211_LEDS
+int ath9k_htc_led_blink = 1;
+module_param_named(blink, ath9k_htc_led_blink, int, 0444);
+MODULE_PARM_DESC(blink, "Enable LED blink on activity");
+
static const struct ieee80211_tpt_blink ath9k_htc_tpt_blink[] = {
{ .throughput = 0 * 1024, .blink_time = 334 },
{ .throughput = 1 * 1024, .blink_time = 260 },
diff --git a/drivers/net/wireless/ath/ath9k/htc_hst.c b/drivers/net/wireless/ath/ath9k/htc_hst.c
index a0ff5b637054..d2408da38c1c 100644
--- a/drivers/net/wireless/ath/ath9k/htc_hst.c
+++ b/drivers/net/wireless/ath/ath9k/htc_hst.c
@@ -351,11 +351,7 @@ void ath9k_htc_txcompletion_cb(struct htc_target *htc_handle,
return;
ret:
- /* HTC-generated packets are freed here. */
- if (htc_hdr && htc_hdr->endpoint_id != ENDPOINT0)
- dev_kfree_skb_any(skb);
- else
- kfree_skb(skb);
+ kfree_skb(skb);
}
static void ath9k_htc_fw_panic_report(struct htc_target *htc_handle,
diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c
index 6d4b273469b1..60aa8d71e753 100644
--- a/drivers/net/wireless/ath/ath9k/hw.c
+++ b/drivers/net/wireless/ath/ath9k/hw.c
@@ -246,6 +246,8 @@ static void ath9k_hw_read_revisions(struct ath_hw *ah)
case AR9300_DEVID_AR953X:
ah->hw_version.macVersion = AR_SREV_VERSION_9531;
return;
+ case AR9300_DEVID_QCA956X:
+ ah->hw_version.macVersion = AR_SREV_VERSION_9561;
}
val = REG_READ(ah, AR_SREV) & AR_SREV_ID;
@@ -422,6 +424,8 @@ static void ath9k_hw_init_defaults(struct ath_hw *ah)
ah->power_mode = ATH9K_PM_UNDEFINED;
ah->htc_reset_init = true;
+ ah->tpc_enabled = true;
+
ah->ani_function = ATH9K_ANI_ALL;
if (!AR_SREV_9300_20_OR_LATER(ah))
ah->ani_function &= ~ATH9K_ANI_MRC_CCK;
@@ -536,6 +540,7 @@ static int __ath9k_hw_init(struct ath_hw *ah)
case AR_SREV_VERSION_9550:
case AR_SREV_VERSION_9565:
case AR_SREV_VERSION_9531:
+ case AR_SREV_VERSION_9561:
break;
default:
ath_err(common,
@@ -636,6 +641,7 @@ int ath9k_hw_init(struct ath_hw *ah)
case AR9485_DEVID_AR1111:
case AR9300_DEVID_AR9565:
case AR9300_DEVID_AR953X:
+ case AR9300_DEVID_QCA956X:
break;
default:
if (common->bus_ops->ath_bus_type == ATH_USB)
@@ -776,7 +782,8 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
/* program BB PLL phase_shift */
REG_RMW_FIELD(ah, AR_CH0_BB_DPLL3,
AR_CH0_BB_DPLL3_PHASE_SHIFT, 0x1);
- } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah)) {
+ } else if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) {
u32 regval, pll2_divint, pll2_divfrac, refdiv;
REG_WRITE(ah, AR_RTC_PLL_CONTROL,
@@ -787,7 +794,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
udelay(100);
if (ah->is_clk_25mhz) {
- if (AR_SREV_9531(ah)) {
+ if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
pll2_divint = 0x1c;
pll2_divfrac = 0xa3d2;
refdiv = 1;
@@ -803,14 +810,15 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
refdiv = 5;
} else {
pll2_divint = 0x11;
- pll2_divfrac =
- AR_SREV_9531(ah) ? 0x26665 : 0x26666;
+ pll2_divfrac = (AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah)) ?
+ 0x26665 : 0x26666;
refdiv = 1;
}
}
regval = REG_READ(ah, AR_PHY_PLL_MODE);
- if (AR_SREV_9531(ah))
+ if (AR_SREV_9531(ah) || AR_SREV_9561(ah))
regval |= (0x1 << 22);
else
regval |= (0x1 << 16);
@@ -828,14 +836,16 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
(0x1 << 13) |
(0x4 << 26) |
(0x18 << 19);
- else if (AR_SREV_9531(ah))
+ else if (AR_SREV_9531(ah) || AR_SREV_9561(ah)) {
regval = (regval & 0x01c00fff) |
(0x1 << 31) |
(0x2 << 29) |
(0xa << 25) |
- (0x1 << 19) |
- (0x6 << 12);
- else
+ (0x1 << 19);
+
+ if (AR_SREV_9531(ah))
+ regval |= (0x6 << 12);
+ } else
regval = (regval & 0x80071fff) |
(0x3 << 30) |
(0x1 << 13) |
@@ -843,7 +853,7 @@ static void ath9k_hw_init_pll(struct ath_hw *ah,
(0x60 << 19);
REG_WRITE(ah, AR_PHY_PLL_MODE, regval);
- if (AR_SREV_9531(ah))
+ if (AR_SREV_9531(ah) || AR_SREV_9561(ah))
REG_WRITE(ah, AR_PHY_PLL_MODE,
REG_READ(ah, AR_PHY_PLL_MODE) & 0xffbfffff);
else
@@ -882,7 +892,8 @@ static void ath9k_hw_init_interrupt_masks(struct ath_hw *ah,
AR_IMR_RXORN |
AR_IMR_BCNMISC;
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
if (AR_SREV_9300_20_OR_LATER(ah)) {
@@ -1671,7 +1682,8 @@ static void ath9k_hw_init_desc(struct ath_hw *ah)
}
#ifdef __BIG_ENDIAN
else if (AR_SREV_9330(ah) || AR_SREV_9340(ah) ||
- AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
REG_RMW(ah, AR_CFG, AR_CFG_SWRB | AR_CFG_SWTB, 0);
else
REG_WRITE(ah, AR_CFG, AR_CFG_SWTD | AR_CFG_SWRD);
@@ -2459,7 +2471,8 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah)) {
pCap->hw_caps |= ATH9K_HW_CAP_EDMA | ATH9K_HW_CAP_FASTCLOCK;
- if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) && !AR_SREV_9565(ah))
+ if (!AR_SREV_9330(ah) && !AR_SREV_9485(ah) &&
+ !AR_SREV_9561(ah) && !AR_SREV_9565(ah))
pCap->hw_caps |= ATH9K_HW_CAP_LDPC;
pCap->rx_hp_qdepth = ATH9K_HW_RX_HP_QDEPTH;
@@ -2476,7 +2489,9 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
if (AR_SREV_9300_20_OR_LATER(ah))
pCap->hw_caps |= ATH9K_HW_CAP_RAC_SUPPORTED;
- if (AR_SREV_9300_20_OR_LATER(ah))
+ if (AR_SREV_9561(ah))
+ ah->ent_mode = 0x3BDA000;
+ else if (AR_SREV_9300_20_OR_LATER(ah))
ah->ent_mode = REG_READ(ah, AR_ENT_OTP);
if (AR_SREV_9287_11_OR_LATER(ah) || AR_SREV_9271(ah))
@@ -2529,13 +2544,17 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
pCap->hw_caps |= ATH9K_HW_CAP_RTT;
}
- if (AR_SREV_9462(ah))
- pCap->hw_caps |= ATH9K_HW_WOW_DEVICE_CAPABLE;
-
if (AR_SREV_9300_20_OR_LATER(ah) &&
ah->eep_ops->get_eeprom(ah, EEP_PAPRD))
pCap->hw_caps |= ATH9K_HW_CAP_PAPRD;
+#ifdef CONFIG_ATH9K_WOW
+ if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah))
+ ah->wow.max_patterns = MAX_NUM_PATTERN;
+ else
+ ah->wow.max_patterns = MAX_NUM_PATTERN_LEGACY;
+#endif
+
return 0;
}
diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h
index 1cbd33551513..e82e570de330 100644
--- a/drivers/net/wireless/ath/ath9k/hw.h
+++ b/drivers/net/wireless/ath/ath9k/hw.h
@@ -54,6 +54,7 @@
#define AR9485_DEVID_AR1111 0x0037
#define AR9300_DEVID_AR9565 0x0036
#define AR9300_DEVID_AR953X 0x003d
+#define AR9300_DEVID_QCA956X 0x003f
#define AR5416_AR9100_DEVID 0x000b
@@ -198,12 +199,13 @@
#define KAL_NUM_DESC_WORDS 12
#define KAL_ANTENNA_MODE 1
#define KAL_TO_DS 1
-#define KAL_DELAY 4 /*delay of 4ms between 2 KAL frames */
+#define KAL_DELAY 4 /* delay of 4ms between 2 KAL frames */
#define KAL_TIMEOUT 900
#define MAX_PATTERN_SIZE 256
#define MAX_PATTERN_MASK_SIZE 32
-#define MAX_NUM_PATTERN 8
+#define MAX_NUM_PATTERN 16
+#define MAX_NUM_PATTERN_LEGACY 8
#define MAX_NUM_USER_PATTERN 6 /* deducting the disassociate and
deauthenticate packets */
@@ -247,12 +249,10 @@ enum ath9k_hw_caps {
#ifdef CONFIG_ATH9K_PCOEM
ATH9K_HW_CAP_RTT = BIT(14),
ATH9K_HW_CAP_MCI = BIT(15),
- ATH9K_HW_WOW_DEVICE_CAPABLE = BIT(16),
ATH9K_HW_CAP_BT_ANT_DIV = BIT(17),
#else
ATH9K_HW_CAP_RTT = 0,
ATH9K_HW_CAP_MCI = 0,
- ATH9K_HW_WOW_DEVICE_CAPABLE = 0,
ATH9K_HW_CAP_BT_ANT_DIV = 0,
#endif
ATH9K_HW_CAP_DFS = BIT(18),
@@ -271,6 +271,12 @@ enum ath9k_hw_caps {
* of those types.
*/
+struct ath9k_hw_wow {
+ u32 wow_event_mask;
+ u32 wow_event_mask2;
+ u8 max_patterns;
+};
+
struct ath9k_hw_capabilities {
u32 hw_caps; /* ATH9K_HW_CAP_* from ath9k_hw_caps */
u16 rts_aggr_limit;
@@ -929,7 +935,7 @@ struct ath_hw {
u32 ent_mode;
#ifdef CONFIG_ATH9K_WOW
- u32 wow_event_mask;
+ struct ath9k_hw_wow wow;
#endif
bool is_clk_25mhz;
int (*get_mac_revision)(void);
@@ -1086,6 +1092,8 @@ bool ar9003_is_paprd_enabled(struct ath_hw *ah);
void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx);
void ar9003_hw_init_rate_txpower(struct ath_hw *ah, u8 *rate_array,
struct ath9k_channel *chan);
+void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array,
+ struct ath9k_channel *chan, int ht40_delta);
/* Hardware family op attach helpers */
int ar5008_hw_attach_phy_ops(struct ath_hw *ah);
@@ -1145,23 +1153,19 @@ ath9k_hw_get_btcoex_scheme(struct ath_hw *ah)
#ifdef CONFIG_ATH9K_WOW
-const char *ath9k_hw_wow_event_to_string(u32 wow_event);
-void ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
- u8 *user_mask, int pattern_count,
- int pattern_len);
+int ath9k_hw_wow_apply_pattern(struct ath_hw *ah, u8 *user_pattern,
+ u8 *user_mask, int pattern_count,
+ int pattern_len);
u32 ath9k_hw_wow_wakeup(struct ath_hw *ah);
void ath9k_hw_wow_enable(struct ath_hw *ah, u32 pattern_enable);
#else
-static inline const char *ath9k_hw_wow_event_to_string(u32 wow_event)
-{
- return NULL;
-}
-static inline void ath9k_hw_wow_apply_pattern(struct ath_hw *ah,
- u8 *user_pattern,
- u8 *user_mask,
- int pattern_count,
- int pattern_len)
+static inline int ath9k_hw_wow_apply_pattern(struct ath_hw *ah,
+ u8 *user_pattern,
+ u8 *user_mask,
+ int pattern_count,
+ int pattern_len)
{
+ return 0;
}
static inline u32 ath9k_hw_wow_wakeup(struct ath_hw *ah)
{
diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c
index d1c39346b264..6c6e88495394 100644
--- a/drivers/net/wireless/ath/ath9k/init.c
+++ b/drivers/net/wireless/ath/ath9k/init.c
@@ -45,8 +45,8 @@ int ath9k_modparam_nohwcrypt;
module_param_named(nohwcrypt, ath9k_modparam_nohwcrypt, int, 0444);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
-int led_blink;
-module_param_named(blink, led_blink, int, 0444);
+int ath9k_led_blink;
+module_param_named(blink, ath9k_led_blink, int, 0444);
MODULE_PARM_DESC(blink, "Enable LED blink on activity");
static int ath9k_btcoex_enable;
@@ -996,6 +996,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
ath9k_ps_restore(sc);
ath9k_deinit_debug(sc);
+ ath9k_deinit_wow(hw);
ieee80211_unregister_hw(hw);
ath_rx_cleanup(sc);
ath9k_deinit_softc(sc);
diff --git a/drivers/net/wireless/ath/ath9k/link.c b/drivers/net/wireless/ath/ath9k/link.c
index b829263e3d0a..90631d768a60 100644
--- a/drivers/net/wireless/ath/ath9k/link.c
+++ b/drivers/net/wireless/ath/ath9k/link.c
@@ -516,14 +516,14 @@ int ath_update_survey_stats(struct ath_softc *sc)
ath_hw_cycle_counters_update(common);
if (cc->cycles > 0) {
- survey->filled |= SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX |
- SURVEY_INFO_CHANNEL_TIME_TX;
- survey->channel_time += cc->cycles / div;
- survey->channel_time_busy += cc->rx_busy / div;
- survey->channel_time_rx += cc->rx_frame / div;
- survey->channel_time_tx += cc->tx_frame / div;
+ survey->filled |= SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_RX |
+ SURVEY_INFO_TIME_TX;
+ survey->time += cc->cycles / div;
+ survey->time_busy += cc->rx_busy / div;
+ survey->time_rx += cc->rx_frame / div;
+ survey->time_tx += cc->tx_frame / div;
}
if (cc->cycles < div)
diff --git a/drivers/net/wireless/ath/ath9k/mac.c b/drivers/net/wireless/ath/ath9k/mac.c
index 3e58bfa0c1fd..bba85d1a6cd1 100644
--- a/drivers/net/wireless/ath/ath9k/mac.c
+++ b/drivers/net/wireless/ath/ath9k/mac.c
@@ -820,7 +820,8 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
return;
}
- if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah))
+ if (AR_SREV_9340(ah) || AR_SREV_9550(ah) || AR_SREV_9531(ah) ||
+ AR_SREV_9561(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
async_mask = AR_INTR_MAC_IRQ;
diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c
index 62b0bf4fdf6b..9ede991b8d76 100644
--- a/drivers/net/wireless/ath/ath9k/main.c
+++ b/drivers/net/wireless/ath/ath9k/main.c
@@ -555,15 +555,6 @@ irqreturn_t ath_isr(int irq, void *dev)
(status & ATH9K_INT_BB_WATCHDOG))
goto chip_reset;
-#ifdef CONFIG_ATH9K_WOW
- if (status & ATH9K_INT_BMISS) {
- if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
- atomic_inc(&sc->wow_got_bmiss_intr);
- atomic_dec(&sc->wow_sleep_proc_intr);
- }
- }
-#endif
-
if (status & ATH9K_INT_SWBA)
tasklet_schedule(&sc->bcon_tasklet);
diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c
index f009b5b57e5e..e6fef1be9977 100644
--- a/drivers/net/wireless/ath/ath9k/pci.c
+++ b/drivers/net/wireless/ath/ath9k/pci.c
@@ -427,6 +427,11 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x11AD, /* LITEON */
+ 0x1842),
+ .driver_data = ATH9K_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
0x6671),
.driver_data = ATH9K_PCI_AR9565_1ANT },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -446,9 +451,19 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_1ANT },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ 0x1B9A, /* XAVI */
+ 0x28A3),
+ .driver_data = ATH9K_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_AZWAVE,
0x218A),
.driver_data = ATH9K_PCI_AR9565_1ANT },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2F8A),
+ .driver_data = ATH9K_PCI_AR9565_1ANT },
/* WB335 1-ANT / Antenna Diversity */
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
@@ -508,6 +523,11 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x213C),
+ .driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_HP,
0x18E3),
.driver_data = ATH9K_PCI_AR9565_1ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -555,6 +575,16 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x4129),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_SAMSUNG,
+ 0x412A),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_ATHEROS,
0x3027),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -586,10 +616,25 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x11AD, /* LITEON */
+ 0x1832),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
0x0692),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ 0x11AD, /* LITEON */
+ 0x0803),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x11AD, /* LITEON */
+ 0x0813),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_AZWAVE,
0x2130),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -605,6 +650,21 @@ static const struct pci_device_id ath_pci_id_table[] = {
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x218B),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x218C),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_AZWAVE,
+ 0x2F82),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
0x144F, /* ASKEY */
0x7202),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -616,10 +676,20 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
0x1B9A, /* XAVI */
+ 0x2813),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ 0x1B9A, /* XAVI */
0x28A2),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ 0x1B9A, /* XAVI */
+ 0x28A4),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
0x185F, /* WNC */
0x3027),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -636,10 +706,25 @@ static const struct pci_device_id ath_pci_id_table[] = {
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
PCI_VENDOR_ID_FOXCONN,
+ 0xE08F),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
0xE081),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
{ PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE091),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
+ PCI_VENDOR_ID_FOXCONN,
+ 0xE099),
+ .driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+ 0x0036,
PCI_VENDOR_ID_LENOVO,
0x3026),
.driver_data = ATH9K_PCI_AR9565_2ANT | ATH9K_PCI_BT_ANT_DIV },
@@ -913,9 +998,12 @@ static int ath_pci_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct ieee80211_hw *hw = pci_get_drvdata(pdev);
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
- if (sc->wow_enabled)
+ if (test_bit(ATH_OP_WOW_ENABLED, &common->op_flags)) {
+ dev_info(&pdev->dev, "WOW is enabled, bypassing PCI suspend\n");
return 0;
+ }
/* The device has to be moved to FULLSLEEP forcibly.
* Otherwise the chip never moved to full sleep,
diff --git a/drivers/net/wireless/ath/ath9k/recv.c b/drivers/net/wireless/ath/ath9k/recv.c
index 7395afbc5124..6fb40ef86fd6 100644
--- a/drivers/net/wireless/ath/ath9k/recv.c
+++ b/drivers/net/wireless/ath/ath9k/recv.c
@@ -425,7 +425,8 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
}
- if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah))
+ if (AR_SREV_9550(sc->sc_ah) || AR_SREV_9531(sc->sc_ah) ||
+ AR_SREV_9561(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
if (ath9k_is_chanctx_enabled() &&
diff --git a/drivers/net/wireless/ath/ath9k/reg.h b/drivers/net/wireless/ath/ath9k/reg.h
index fb11a9172f38..9587ec655680 100644
--- a/drivers/net/wireless/ath/ath9k/reg.h
+++ b/drivers/net/wireless/ath/ath9k/reg.h
@@ -814,6 +814,7 @@
#define AR_SREV_REVISION_9531_10 0
#define AR_SREV_REVISION_9531_11 1
#define AR_SREV_REVISION_9531_20 2
+#define AR_SREV_VERSION_9561 0x600
#define AR_SREV_5416(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
@@ -899,10 +900,13 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9485))
#define AR_SREV_9565(_ah) \
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9565))
+#define AR_SREV_9003_PCOEM(_ah) \
+ (AR_SREV_9462(_ah) || AR_SREV_9485(_ah) || AR_SREV_9565(_ah))
#else
#define AR_SREV_9462(_ah) 0
#define AR_SREV_9485(_ah) 0
#define AR_SREV_9565(_ah) 0
+#define AR_SREV_9003_PCOEM(_ah) 0
#endif
#define AR_SREV_9485_11_OR_LATER(_ah) \
@@ -974,6 +978,9 @@
(((_ah)->hw_version.macVersion == AR_SREV_VERSION_9531) && \
((_ah)->hw_version.macRev == AR_SREV_REVISION_9531_20))
+#define AR_SREV_9561(_ah) \
+ (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9561))
+
/* NOTE: When adding chips newer than Peacock, add chip check here */
#define AR_SREV_9580_10_OR_LATER(_ah) \
(AR_SREV_9580(_ah))
@@ -1876,6 +1883,7 @@ enum {
#define AR_FIRST_NDP_TIMER 7
#define AR_NDP2_PERIOD 0x81a0
#define AR_NDP2_TIMER_MODE 0x81c0
+#define AR_GEN_TIMERS2_MODE_ENABLE_MASK 0x000000FF
#define AR_GEN_TIMERS(_i) (0x8200 + ((_i) << 2))
#define AR_NEXT_TBTT_TIMER AR_GEN_TIMERS(0)
@@ -1971,6 +1979,7 @@ enum {
#define AR_DIRECT_CONNECT 0x83a0
#define AR_DC_AP_STA_EN 0x00000001
+#define AR_DC_TSF2_ENABLE 0x00000001
#define AR_AES_MUTE_MASK0 0x805c
#define AR_AES_MUTE_MASK0_FC 0x0000FFFF
@@ -2003,126 +2012,6 @@ enum {
#define AR_WOW_BEACON_TIMO_MAX 0xffffffff
-/*
- * MAC WoW Registers
- */
-
-#define AR_WOW_PATTERN 0x825C
-#define AR_WOW_COUNT 0x8260
-#define AR_WOW_BCN_EN 0x8270
-#define AR_WOW_BCN_TIMO 0x8274
-#define AR_WOW_KEEP_ALIVE_TIMO 0x8278
-#define AR_WOW_KEEP_ALIVE 0x827c
-#define AR_WOW_US_SCALAR 0x8284
-#define AR_WOW_KEEP_ALIVE_DELAY 0x8288
-#define AR_WOW_PATTERN_MATCH 0x828c
-#define AR_WOW_PATTERN_OFF1 0x8290 /* pattern bytes 0 -> 3 */
-#define AR_WOW_PATTERN_OFF2 0x8294 /* pattern bytes 4 -> 7 */
-
-/* for AR9285 or later version of chips */
-#define AR_WOW_EXACT 0x829c
-#define AR_WOW_LENGTH1 0x8360
-#define AR_WOW_LENGTH2 0X8364
-/* register to enable match for less than 256 bytes packets */
-#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368
-
-#define AR_SW_WOW_CONTROL 0x20018
-#define AR_SW_WOW_ENABLE 0x1
-#define AR_SWITCH_TO_REFCLK 0x2
-#define AR_RESET_CONTROL 0x4
-#define AR_RESET_VALUE_MASK 0x8
-#define AR_HW_WOW_DISABLE 0x10
-#define AR_CLR_MAC_INTERRUPT 0x20
-#define AR_CLR_KA_INTERRUPT 0x40
-
-/* AR_WOW_PATTERN register values */
-#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 28) /* in usecs */
-#define AR_WOW_MAC_INTR_EN 0x00040000
-#define AR_WOW_MAGIC_EN 0x00010000
-#define AR_WOW_PATTERN_EN(x) (x & 0xff)
-#define AR_WOW_PAT_FOUND_SHIFT 8
-#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT))
-#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT)
-#define AR_WOW_MAGIC_PAT_FOUND 0x00020000
-#define AR_WOW_MAC_INTR 0x00080000
-#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000
-#define AR_WOW_BEACON_FAIL 0x00200000
-
-#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \
- AR_WOW_MAGIC_PAT_FOUND | \
- AR_WOW_KEEP_ALIVE_FAIL | \
- AR_WOW_BEACON_FAIL))
-#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \
- AR_WOW_MAGIC_EN | \
- AR_WOW_MAC_INTR_EN | \
- AR_WOW_BEACON_FAIL | \
- AR_WOW_KEEP_ALIVE_FAIL))
-
-/* AR_WOW_COUNT register values */
-#define AR_WOW_AIFS_CNT(x) (x & 0xff)
-#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8)
-#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16)
-
-/* AR_WOW_BCN_EN register */
-#define AR_WOW_BEACON_FAIL_EN 0x00000001
-
-/* AR_WOW_BCN_TIMO rgister */
-#define AR_WOW_BEACON_TIMO 0x40000000 /* valid if BCN_EN is set */
-
-/* AR_WOW_KEEP_ALIVE_TIMO register */
-#define AR_WOW_KEEP_ALIVE_TIMO_VALUE
-#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff
-
-/* AR_WOW_KEEP_ALIVE register */
-#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001
-#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002
-
-/* AR_WOW_KEEP_ALIVE_DELAY register */
-#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */
-
-
-/*
- * keep it long for beacon workaround - ensure no false alarm
- */
-#define AR_WOW_BMISSTHRESHOLD 0x20
-
-/* AR_WOW_PATTERN_MATCH register */
-#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf)
-#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8)
-
-/*
- * default values for Wow Configuration for backoff, aifs, slot, keep-alive
- * to be programmed into various registers.
- */
-#define AR_WOW_PAT_BACKOFF 0x00000004 /* AR_WOW_PATTERN_REG */
-#define AR_WOW_CNT_AIFS_CNT 0x00000022 /* AR_WOW_COUNT_REG */
-#define AR_WOW_CNT_SLOT_CNT 0x00000009 /* AR_WOW_COUNT_REG */
-/*
- * Keepalive count applicable for AR9280 2.0 and above.
- */
-#define AR_WOW_CNT_KA_CNT 0x00000008 /* AR_WOW_COUNT register */
-
-/* WoW - Transmit buffer for keep alive frames */
-#define AR_WOW_TRANSMIT_BUFFER 0xe000 /* E000 - EFFC */
-
-#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2))
-
-#define AR_WOW_KA_DESC_WORD2 0xe000
-
-#define AR_WOW_KA_DATA_WORD0 0xe030
-
-/* WoW Transmit Buffer for patterns */
-#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8))
-#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5))
-
-/* Currently Pattern 0-7 are supported - so bit 0-7 are set */
-#define AR_WOW_PATTERN_SUPPORTED 0xff
-#define AR_WOW_LENGTH_MAX 0xff
-#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3)
-#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i))
-#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3)
-#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i))
-
#define AR9271_CORE_CLOCK 117 /* clock to 117Mhz */
#define AR9271_TARGET_BAUD_RATE 19200 /* 115200 */
diff --git a/drivers/net/wireless/ath/ath9k/reg_wow.h b/drivers/net/wireless/ath/ath9k/reg_wow.h
new file mode 100644
index 000000000000..3abfca56ca58
--- /dev/null
+++ b/drivers/net/wireless/ath/ath9k/reg_wow.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2015 Qualcomm Atheros Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef REG_WOW_H
+#define REG_WOW_H
+
+#define AR_WOW_PATTERN 0x825C
+#define AR_WOW_COUNT 0x8260
+#define AR_WOW_BCN_EN 0x8270
+#define AR_WOW_BCN_TIMO 0x8274
+#define AR_WOW_KEEP_ALIVE_TIMO 0x8278
+#define AR_WOW_KEEP_ALIVE 0x827c
+#define AR_WOW_KEEP_ALIVE_DELAY 0x8288
+#define AR_WOW_PATTERN_MATCH 0x828c
+
+/*
+ * AR_WOW_LENGTH1
+ * bit 31:24 pattern 0 length
+ * bit 23:16 pattern 1 length
+ * bit 15:8 pattern 2 length
+ * bit 7:0 pattern 3 length
+ *
+ * AR_WOW_LENGTH2
+ * bit 31:24 pattern 4 length
+ * bit 23:16 pattern 5 length
+ * bit 15:8 pattern 6 length
+ * bit 7:0 pattern 7 length
+ *
+ * AR_WOW_LENGTH3
+ * bit 31:24 pattern 8 length
+ * bit 23:16 pattern 9 length
+ * bit 15:8 pattern 10 length
+ * bit 7:0 pattern 11 length
+ *
+ * AR_WOW_LENGTH4
+ * bit 31:24 pattern 12 length
+ * bit 23:16 pattern 13 length
+ * bit 15:8 pattern 14 length
+ * bit 7:0 pattern 15 length
+ */
+#define AR_WOW_LENGTH1 0x8360
+#define AR_WOW_LENGTH2 0X8364
+#define AR_WOW_LENGTH3 0X8380
+#define AR_WOW_LENGTH4 0X8384
+
+#define AR_WOW_PATTERN_MATCH_LT_256B 0x8368
+#define AR_MAC_PCU_WOW4 0x8370
+
+#define AR_SW_WOW_CONTROL 0x20018
+#define AR_SW_WOW_ENABLE 0x1
+#define AR_SWITCH_TO_REFCLK 0x2
+#define AR_RESET_CONTROL 0x4
+#define AR_RESET_VALUE_MASK 0x8
+#define AR_HW_WOW_DISABLE 0x10
+#define AR_CLR_MAC_INTERRUPT 0x20
+#define AR_CLR_KA_INTERRUPT 0x40
+
+#define AR_WOW_BACK_OFF_SHIFT(x) ((x & 0xf) << 27) /* in usecs */
+#define AR_WOW_MAC_INTR_EN 0x00040000
+#define AR_WOW_MAGIC_EN 0x00010000
+#define AR_WOW_PATTERN_EN(x) (x & 0xff)
+#define AR_WOW_PAT_FOUND_SHIFT 8
+#define AR_WOW_PATTERN_FOUND(x) (x & (0xff << AR_WOW_PAT_FOUND_SHIFT))
+#define AR_WOW_PATTERN_FOUND_MASK ((0xff) << AR_WOW_PAT_FOUND_SHIFT)
+#define AR_WOW_MAGIC_PAT_FOUND 0x00020000
+#define AR_WOW_MAC_INTR 0x00080000
+#define AR_WOW_KEEP_ALIVE_FAIL 0x00100000
+#define AR_WOW_BEACON_FAIL 0x00200000
+
+#define AR_WOW_STATUS(x) (x & (AR_WOW_PATTERN_FOUND_MASK | \
+ AR_WOW_MAGIC_PAT_FOUND | \
+ AR_WOW_KEEP_ALIVE_FAIL | \
+ AR_WOW_BEACON_FAIL))
+#define AR_WOW_CLEAR_EVENTS(x) (x & ~(AR_WOW_PATTERN_EN(0xff) | \
+ AR_WOW_MAGIC_EN | \
+ AR_WOW_MAC_INTR_EN | \
+ AR_WOW_BEACON_FAIL | \
+ AR_WOW_KEEP_ALIVE_FAIL))
+
+#define AR_WOW_AIFS_CNT(x) (x & 0xff)
+#define AR_WOW_SLOT_CNT(x) ((x & 0xff) << 8)
+#define AR_WOW_KEEP_ALIVE_CNT(x) ((x & 0xff) << 16)
+
+#define AR_WOW_BEACON_FAIL_EN 0x00000001
+#define AR_WOW_BEACON_TIMO 0x40000000
+#define AR_WOW_KEEP_ALIVE_NEVER 0xffffffff
+#define AR_WOW_KEEP_ALIVE_AUTO_DIS 0x00000001
+#define AR_WOW_KEEP_ALIVE_FAIL_DIS 0x00000002
+#define AR_WOW_KEEP_ALIVE_DELAY_VALUE 0x000003e8 /* 1 msec */
+#define AR_WOW_BMISSTHRESHOLD 0x20
+#define AR_WOW_PAT_END_OF_PKT(x) (x & 0xf)
+#define AR_WOW_PAT_OFF_MATCH(x) ((x & 0xf) << 8)
+#define AR_WOW_PAT_BACKOFF 0x00000004
+#define AR_WOW_CNT_AIFS_CNT 0x00000022
+#define AR_WOW_CNT_SLOT_CNT 0x00000009
+#define AR_WOW_CNT_KA_CNT 0x00000008
+
+#define AR_WOW_TRANSMIT_BUFFER 0xe000
+#define AR_WOW_TXBUF(i) (AR_WOW_TRANSMIT_BUFFER + ((i) << 2))
+#define AR_WOW_KA_DESC_WORD2 0xe000
+#define AR_WOW_TB_PATTERN(i) (0xe100 + (i << 8))
+#define AR_WOW_TB_MASK(i) (0xec00 + (i << 5))
+#define AR_WOW_PATTERN_SUPPORTED_LEGACY 0xff
+#define AR_WOW_PATTERN_SUPPORTED 0xffff
+#define AR_WOW_LENGTH_MAX 0xff
+#define AR_WOW_LEN1_SHIFT(_i) ((0x3 - ((_i) & 0x3)) << 0x3)
+#define AR_WOW_LENGTH1_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN1_SHIFT(_i))
+#define AR_WOW_LEN2_SHIFT(_i) ((0x7 - ((_i) & 0x7)) << 0x3)
+#define AR_WOW_LENGTH2_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN2_SHIFT(_i))
+#define AR_WOW_LEN3_SHIFT(_i) ((0xb - ((_i) & 0xb)) << 0x3)
+#define AR_WOW_LENGTH3_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN3_SHIFT(_i))
+#define AR_WOW_LEN4_SHIFT(_i) ((0xf - ((_i) & 0xf)) << 0x3)
+#define AR_WOW_LENGTH4_MASK(_i) (AR_WOW_LENGTH_MAX << AR_WOW_LEN4_SHIFT(_i))
+
+#endif /* REG_WOW_H */
diff --git a/drivers/net/wireless/ath/ath9k/wow.c b/drivers/net/wireless/ath/ath9k/wow.c
index 5f30e580d942..8d0b1730a9d5 100644
--- a/drivers/net/wireless/ath/ath9k/wow.c
+++ b/drivers/net/wireless/ath/ath9k/wow.c
@@ -16,36 +16,43 @@
#include "ath9k.h"
-static const struct wiphy_wowlan_support ath9k_wowlan_support = {
+static const struct wiphy_wowlan_support ath9k_wowlan_support_legacy = {
.flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = MAX_NUM_USER_PATTERN,
.pattern_min_len = 1,
.pattern_max_len = MAX_PATTERN_SIZE,
};
-static void ath9k_wow_map_triggers(struct ath_softc *sc,
- struct cfg80211_wowlan *wowlan,
- u32 *wow_triggers)
+static const struct wiphy_wowlan_support ath9k_wowlan_support = {
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
+ .n_patterns = MAX_NUM_PATTERN - 2,
+ .pattern_min_len = 1,
+ .pattern_max_len = MAX_PATTERN_SIZE,
+};
+
+static u8 ath9k_wow_map_triggers(struct ath_softc *sc,
+ struct cfg80211_wowlan *wowlan)
{
+ u8 wow_triggers = 0;
+
if (wowlan->disconnect)
- *wow_triggers |= AH_WOW_LINK_CHANGE |
- AH_WOW_BEACON_MISS;
+ wow_triggers |= AH_WOW_LINK_CHANGE |
+ AH_WOW_BEACON_MISS;
if (wowlan->magic_pkt)
- *wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
+ wow_triggers |= AH_WOW_MAGIC_PATTERN_EN;
if (wowlan->n_patterns)
- *wow_triggers |= AH_WOW_USER_PATTERN_EN;
-
- sc->wow_enabled = *wow_triggers;
+ wow_triggers |= AH_WOW_USER_PATTERN_EN;
+ return wow_triggers;
}
-static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
+static int ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
{
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
int pattern_count = 0;
- int i, byte_cnt;
+ int ret, i, byte_cnt = 0;
u8 dis_deauth_pattern[MAX_PATTERN_SIZE];
u8 dis_deauth_mask[MAX_PATTERN_SIZE];
@@ -80,12 +87,7 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
* | x:x:x:x:x:x -- 22 bytes
*/
- /* Create Disassociate Pattern first */
-
- byte_cnt = 0;
-
/* Fill out the mask with all FF's */
-
for (i = 0; i < MAX_PATTERN_MASK_SIZE; i++)
dis_deauth_mask[i] = 0xff;
@@ -108,19 +110,17 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
byte_cnt += 6;
/* copy the bssid, its same as the source mac address */
-
memcpy((dis_deauth_pattern + byte_cnt), common->curbssid, ETH_ALEN);
/* Create Disassociate pattern mask */
-
dis_deauth_mask[0] = 0xfe;
dis_deauth_mask[1] = 0x03;
dis_deauth_mask[2] = 0xc0;
- ath_dbg(common, WOW, "Adding disassoc/deauth patterns for WoW\n");
-
- ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
- pattern_count, byte_cnt);
+ ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
+ pattern_count, byte_cnt);
+ if (ret)
+ goto exit;
pattern_count++;
/*
@@ -129,59 +129,39 @@ static void ath9k_wow_add_disassoc_deauth_pattern(struct ath_softc *sc)
*/
dis_deauth_pattern[0] = 0xC0;
- ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
- pattern_count, byte_cnt);
-
+ ret = ath9k_hw_wow_apply_pattern(ah, dis_deauth_pattern, dis_deauth_mask,
+ pattern_count, byte_cnt);
+exit:
+ return ret;
}
-static void ath9k_wow_add_pattern(struct ath_softc *sc,
- struct cfg80211_wowlan *wowlan)
+static int ath9k_wow_add_pattern(struct ath_softc *sc,
+ struct cfg80211_wowlan *wowlan)
{
struct ath_hw *ah = sc->sc_ah;
- struct ath9k_wow_pattern *wow_pattern = NULL;
struct cfg80211_pkt_pattern *patterns = wowlan->patterns;
- int mask_len;
+ u8 wow_pattern[MAX_PATTERN_SIZE];
+ u8 wow_mask[MAX_PATTERN_SIZE];
+ int mask_len, ret = 0;
s8 i = 0;
- if (!wowlan->n_patterns)
- return;
-
- /*
- * Add the new user configured patterns
- */
for (i = 0; i < wowlan->n_patterns; i++) {
-
- wow_pattern = kzalloc(sizeof(*wow_pattern), GFP_KERNEL);
-
- if (!wow_pattern)
- return;
-
- /*
- * TODO: convert the generic user space pattern to
- * appropriate chip specific/802.11 pattern.
- */
-
- mask_len = DIV_ROUND_UP(wowlan->patterns[i].pattern_len, 8);
- memset(wow_pattern->pattern_bytes, 0, MAX_PATTERN_SIZE);
- memset(wow_pattern->mask_bytes, 0, MAX_PATTERN_SIZE);
- memcpy(wow_pattern->pattern_bytes, patterns[i].pattern,
- patterns[i].pattern_len);
- memcpy(wow_pattern->mask_bytes, patterns[i].mask, mask_len);
- wow_pattern->pattern_len = patterns[i].pattern_len;
-
- /*
- * just need to take care of deauth and disssoc pattern,
- * make sure we don't overwrite them.
- */
-
- ath9k_hw_wow_apply_pattern(ah, wow_pattern->pattern_bytes,
- wow_pattern->mask_bytes,
- i + 2,
- wow_pattern->pattern_len);
- kfree(wow_pattern);
-
+ mask_len = DIV_ROUND_UP(patterns[i].pattern_len, 8);
+ memset(wow_pattern, 0, MAX_PATTERN_SIZE);
+ memset(wow_mask, 0, MAX_PATTERN_SIZE);
+ memcpy(wow_pattern, patterns[i].pattern, patterns[i].pattern_len);
+ memcpy(wow_mask, patterns[i].mask, mask_len);
+
+ ret = ath9k_hw_wow_apply_pattern(ah,
+ wow_pattern,
+ wow_mask,
+ i + 2,
+ patterns[i].pattern_len);
+ if (ret)
+ break;
}
+ return ret;
}
int ath9k_suspend(struct ieee80211_hw *hw,
@@ -190,41 +170,39 @@ int ath9k_suspend(struct ieee80211_hw *hw,
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- u32 wow_triggers_enabled = 0;
+ u8 triggers;
int ret = 0;
ath9k_deinit_channel_context(sc);
mutex_lock(&sc->mutex);
- ath_cancel_work(sc);
- ath_stop_ani(sc);
-
if (test_bit(ATH_OP_INVALID, &common->op_flags)) {
- ath_dbg(common, ANY, "Device not present\n");
- ret = -EINVAL;
+ ath_err(common, "Device not present\n");
+ ret = -ENODEV;
goto fail_wow;
}
if (WARN_ON(!wowlan)) {
- ath_dbg(common, WOW, "None of the WoW triggers enabled\n");
+ ath_err(common, "None of the WoW triggers enabled\n");
ret = -EINVAL;
goto fail_wow;
}
- if (!device_can_wakeup(sc->dev)) {
- ath_dbg(common, WOW, "device_can_wakeup failed, WoW is not enabled\n");
+ if (sc->cur_chan->nvifs > 1) {
+ ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
ret = 1;
goto fail_wow;
}
- /*
- * none of the sta vifs are associated
- * and we are not currently handling multivif
- * cases, for instance we have to seperately
- * configure 'keep alive frame' for each
- * STA.
- */
+ if (ath9k_is_chanctx_enabled()) {
+ if (test_bit(ATH_OP_MULTI_CHANNEL, &common->op_flags)) {
+ ath_dbg(common, WOW,
+ "Multi-channel WOW is not supported\n");
+ ret = 1;
+ goto fail_wow;
+ }
+ }
if (!test_bit(ATH_OP_PRIM_STA_VIF, &common->op_flags)) {
ath_dbg(common, WOW, "None of the STA vifs are associated\n");
@@ -232,16 +210,15 @@ int ath9k_suspend(struct ieee80211_hw *hw,
goto fail_wow;
}
- if (sc->cur_chan->nvifs > 1) {
- ath_dbg(common, WOW, "WoW for multivif is not yet supported\n");
+ triggers = ath9k_wow_map_triggers(sc, wowlan);
+ if (!triggers) {
+ ath_dbg(common, WOW, "No valid WoW triggers\n");
ret = 1;
goto fail_wow;
}
- ath9k_wow_map_triggers(sc, wowlan, &wow_triggers_enabled);
-
- ath_dbg(common, WOW, "WoW triggers enabled 0x%x\n",
- wow_triggers_enabled);
+ ath_cancel_work(sc);
+ ath_stop_ani(sc);
ath9k_ps_wakeup(sc);
@@ -251,10 +228,21 @@ int ath9k_suspend(struct ieee80211_hw *hw,
* Enable wake up on recieving disassoc/deauth
* frame by default.
*/
- ath9k_wow_add_disassoc_deauth_pattern(sc);
+ ret = ath9k_wow_add_disassoc_deauth_pattern(sc);
+ if (ret) {
+ ath_err(common,
+ "Unable to add disassoc/deauth pattern: %d\n", ret);
+ goto fail_wow;
+ }
- if (wow_triggers_enabled & AH_WOW_USER_PATTERN_EN)
- ath9k_wow_add_pattern(sc, wowlan);
+ if (triggers & AH_WOW_USER_PATTERN_EN) {
+ ret = ath9k_wow_add_pattern(sc, wowlan);
+ if (ret) {
+ ath_err(common,
+ "Unable to add user pattern: %d\n", ret);
+ goto fail_wow;
+ }
+ }
spin_lock_bh(&sc->sc_pcu_lock);
/*
@@ -278,12 +266,12 @@ int ath9k_suspend(struct ieee80211_hw *hw,
synchronize_irq(sc->irq);
tasklet_kill(&sc->intr_tq);
- ath9k_hw_wow_enable(ah, wow_triggers_enabled);
+ ath9k_hw_wow_enable(ah, triggers);
ath9k_ps_restore(sc);
- ath_dbg(common, ANY, "WoW enabled in ath9k\n");
- atomic_inc(&sc->wow_sleep_proc_intr);
+ ath_dbg(common, WOW, "Suspend with WoW triggers: 0x%x\n", triggers);
+ set_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
fail_wow:
mutex_unlock(&sc->mutex);
return ret;
@@ -294,7 +282,7 @@ int ath9k_resume(struct ieee80211_hw *hw)
struct ath_softc *sc = hw->priv;
struct ath_hw *ah = sc->sc_ah;
struct ath_common *common = ath9k_hw_common(ah);
- u32 wow_status;
+ u8 status;
mutex_lock(&sc->mutex);
@@ -309,29 +297,14 @@ int ath9k_resume(struct ieee80211_hw *hw)
spin_unlock_bh(&sc->sc_pcu_lock);
- wow_status = ath9k_hw_wow_wakeup(ah);
-
- if (atomic_read(&sc->wow_got_bmiss_intr) == 0) {
- /*
- * some devices may not pick beacon miss
- * as the reason they woke up so we add
- * that here for that shortcoming.
- */
- wow_status |= AH_WOW_BEACON_MISS;
- atomic_dec(&sc->wow_got_bmiss_intr);
- ath_dbg(common, ANY, "Beacon miss interrupt picked up during WoW sleep\n");
- }
-
- atomic_dec(&sc->wow_sleep_proc_intr);
-
- if (wow_status) {
- ath_dbg(common, ANY, "Waking up due to WoW triggers %s with WoW status = %x\n",
- ath9k_hw_wow_event_to_string(wow_status), wow_status);
- }
+ status = ath9k_hw_wow_wakeup(ah);
+ ath_dbg(common, WOW, "Resume with WoW status: 0x%x\n", status);
ath_restart_work(sc);
ath9k_start_btcoex(sc);
+ clear_bit(ATH_OP_WOW_ENABLED, &common->op_flags);
+
ath9k_ps_restore(sc);
mutex_unlock(&sc->mutex);
@@ -341,22 +314,35 @@ int ath9k_resume(struct ieee80211_hw *hw)
void ath9k_set_wakeup(struct ieee80211_hw *hw, bool enabled)
{
struct ath_softc *sc = hw->priv;
+ struct ath_common *common = ath9k_hw_common(sc->sc_ah);
mutex_lock(&sc->mutex);
- device_init_wakeup(sc->dev, 1);
device_set_wakeup_enable(sc->dev, enabled);
mutex_unlock(&sc->mutex);
+
+ ath_dbg(common, WOW, "WoW wakeup source is %s\n",
+ (enabled) ? "enabled" : "disabled");
}
void ath9k_init_wow(struct ieee80211_hw *hw)
{
struct ath_softc *sc = hw->priv;
+ struct ath_hw *ah = sc->sc_ah;
+
+ if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow) {
+ if (AR_SREV_9462_20_OR_LATER(ah) || AR_SREV_9565_11_OR_LATER(ah))
+ hw->wiphy->wowlan = &ath9k_wowlan_support;
+ else
+ hw->wiphy->wowlan = &ath9k_wowlan_support_legacy;
- if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_WOW_DEVICE_CAPABLE) &&
- (sc->driver_data & ATH9K_PCI_WOW) &&
- device_can_wakeup(sc->dev))
- hw->wiphy->wowlan = &ath9k_wowlan_support;
+ device_init_wakeup(sc->dev, 1);
+ }
+}
+
+void ath9k_deinit_wow(struct ieee80211_hw *hw)
+{
+ struct ath_softc *sc = hw->priv;
- atomic_set(&sc->wow_sleep_proc_intr, -1);
- atomic_set(&sc->wow_got_bmiss_intr, -1);
+ if ((sc->driver_data & ATH9K_PCI_WOW) || sc->force_wow)
+ device_init_wakeup(sc->dev, 0);
}
diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c
index e9bd02c2e844..1b8e75c4d2c2 100644
--- a/drivers/net/wireless/ath/ath9k/xmit.c
+++ b/drivers/net/wireless/ath/ath9k/xmit.c
@@ -1097,24 +1097,65 @@ void ath_update_max_aggr_framelen(struct ath_softc *sc, int queue, int txop)
}
static u8 ath_get_rate_txpower(struct ath_softc *sc, struct ath_buf *bf,
- u8 rateidx)
+ u8 rateidx, bool is_40, bool is_cck)
{
u8 max_power;
+ struct sk_buff *skb;
+ struct ath_frame_info *fi;
+ struct ieee80211_tx_info *info;
struct ath_hw *ah = sc->sc_ah;
- if (sc->tx99_state)
+ if (sc->tx99_state || !ah->tpc_enabled)
return MAX_RATE_POWER;
+ skb = bf->bf_mpdu;
+ fi = get_frame_info(skb);
+ info = IEEE80211_SKB_CB(skb);
+
if (!AR_SREV_9300_20_OR_LATER(ah)) {
- /* ar9002 is not sipported for the moment */
- return MAX_RATE_POWER;
- }
+ int txpower = fi->tx_power;
- if (!bf->bf_state.bfs_paprd) {
- struct sk_buff *skb = bf->bf_mpdu;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ath_frame_info *fi = get_frame_info(skb);
+ if (is_40) {
+ u8 power_ht40delta;
+ struct ar5416_eeprom_def *eep = &ah->eeprom.def;
+
+ if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_2) {
+ bool is_2ghz;
+ struct modal_eep_header *pmodal;
+ is_2ghz = info->band == IEEE80211_BAND_2GHZ;
+ pmodal = &eep->modalHeader[is_2ghz];
+ power_ht40delta = pmodal->ht40PowerIncForPdadc;
+ } else {
+ power_ht40delta = 2;
+ }
+ txpower += power_ht40delta;
+ }
+
+ if (AR_SREV_9287(ah) || AR_SREV_9285(ah) ||
+ AR_SREV_9271(ah)) {
+ txpower -= 2 * AR9287_PWR_TABLE_OFFSET_DB;
+ } else if (AR_SREV_9280_20_OR_LATER(ah)) {
+ s8 power_offset;
+
+ power_offset = ah->eep_ops->get_eeprom(ah,
+ EEP_PWR_TABLE_OFFSET);
+ txpower -= 2 * power_offset;
+ }
+
+ if (OLC_FOR_AR9280_20_LATER && is_cck)
+ txpower -= 2;
+
+ txpower = max(txpower, 0);
+ max_power = min_t(u8, ah->tx_power[rateidx], txpower);
+
+ /* XXX: clamp minimum TX power at 1 for AR9160 since if
+ * max_power is set to 0, frames are transmitted at max
+ * TX power
+ */
+ if (!max_power && !AR_SREV_9280_20_OR_LATER(ah))
+ max_power = 1;
+ } else if (!bf->bf_state.bfs_paprd) {
if (rateidx < 8 && (info->flags & IEEE80211_TX_CTL_STBC))
max_power = min(ah->tx_power_stbc[rateidx],
fi->tx_power);
@@ -1152,7 +1193,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
info->rtscts_rate = fi->rtscts_rate;
for (i = 0; i < ARRAY_SIZE(bf->rates); i++) {
- bool is_40, is_sgi, is_sp;
+ bool is_40, is_sgi, is_sp, is_cck;
int phy;
if (!rates[i].count || (rates[i].idx < 0))
@@ -1198,7 +1239,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC;
- info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
+ info->txpower[i] = ath_get_rate_txpower(sc, bf, rix,
+ is_40, false);
continue;
}
@@ -1227,7 +1269,9 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf,
info->rates[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
phy, rate->bitrate * 100, len, rix, is_sp);
- info->txpower[i] = ath_get_rate_txpower(sc, bf, rix);
+ is_cck = IS_CCK_RATE(info->rates[i].Rate);
+ info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, false,
+ is_cck);
}
/* For AR5416 - RTS cannot be followed by a frame larger than 8K */
@@ -2259,7 +2303,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
struct ath_txq *txq = txctl->txq;
struct ath_atx_tid *tid = NULL;
struct ath_buf *bf;
- bool queue, skip_uapsd = false;
+ bool queue, skip_uapsd = false, ps_resp;
int q, ret;
if (vif)
@@ -2268,6 +2312,8 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (info->flags & IEEE80211_TX_CTL_TX_OFFCHAN)
txctl->force_channel = true;
+ ps_resp = !!(info->control.flags & IEEE80211_TX_CTRL_PS_RESPONSE);
+
ret = ath_tx_prepare(hw, skb, txctl);
if (ret)
return ret;
@@ -2310,7 +2356,7 @@ int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
if (txctl->an && queue)
tid = ath_get_skb_tid(sc, txctl->an, skb);
- if (!skip_uapsd && (info->flags & IEEE80211_TX_CTL_PS_RESPONSE)) {
+ if (!skip_uapsd && ps_resp) {
ath_txq_unlock(sc, txq);
txq = sc->tx.uapsdq;
ath_txq_lock(sc, txq);
@@ -2443,9 +2489,12 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
if (sc->sc_ah->caldata)
set_bit(PAPRD_PACKET_SENT, &sc->sc_ah->caldata->cal_flags);
- if (!(tx_flags & ATH_TX_ERROR))
- /* Frame was ACKed */
- tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ if (!(tx_flags & ATH_TX_ERROR)) {
+ if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK)
+ tx_info->flags |= IEEE80211_TX_STAT_NOACK_TRANSMITTED;
+ else
+ tx_info->flags |= IEEE80211_TX_STAT_ACK;
+ }
padpos = ieee80211_hdrlen(hdr->frame_control);
padsize = padpos & 3;
diff --git a/drivers/net/wireless/ath/carl9170/cmd.c b/drivers/net/wireless/ath/carl9170/cmd.c
index 39a63874b275..f2b4f537e4c1 100644
--- a/drivers/net/wireless/ath/carl9170/cmd.c
+++ b/drivers/net/wireless/ath/carl9170/cmd.c
@@ -188,12 +188,12 @@ int carl9170_collect_tally(struct ar9170 *ar)
if (ar->channel) {
info = &ar->survey[ar->channel->hw_value];
- info->channel_time = ar->tally.active;
- info->channel_time_busy = ar->tally.cca;
- info->channel_time_tx = ar->tally.tx_time;
- do_div(info->channel_time, 1000);
- do_div(info->channel_time_busy, 1000);
- do_div(info->channel_time_tx, 1000);
+ info->time = ar->tally.active;
+ info->time_busy = ar->tally.cca;
+ info->time_tx = ar->tally.tx_time;
+ do_div(info->time, 1000);
+ do_div(info->time_busy, 1000);
+ do_div(info->time_tx, 1000);
}
}
return 0;
diff --git a/drivers/net/wireless/ath/carl9170/debug.c b/drivers/net/wireless/ath/carl9170/debug.c
index 1c0af9cd9a85..6808db433283 100644
--- a/drivers/net/wireless/ath/carl9170/debug.c
+++ b/drivers/net/wireless/ath/carl9170/debug.c
@@ -214,14 +214,10 @@ DEBUGFS_DECLARE_RO_FILE(name, _read_bufsize)
static char *carl9170_debugfs_mem_usage_read(struct ar9170 *ar, char *buf,
size_t bufsize, ssize_t *len)
{
- ADD(buf, *len, bufsize, "jar: [");
-
spin_lock_bh(&ar->mem_lock);
- *len += bitmap_scnprintf(&buf[*len], bufsize - *len,
- ar->mem_bitmap, ar->fw.mem_blocks);
-
- ADD(buf, *len, bufsize, "]\n");
+ ADD(buf, *len, bufsize, "jar: [%*pb]\n",
+ ar->fw.mem_blocks, ar->mem_bitmap);
ADD(buf, *len, bufsize, "cookies: used:%3d / total:%3d, allocs:%d\n",
bitmap_weight(ar->mem_bitmap, ar->fw.mem_blocks),
@@ -316,17 +312,13 @@ static char *carl9170_debugfs_ampdu_state_read(struct ar9170 *ar, char *buf,
cnt, iter->tid, iter->bsn, iter->snx, iter->hsn,
iter->max, iter->state, iter->counter);
- ADD(buf, *len, bufsize, "\tWindow: [");
-
- *len += bitmap_scnprintf(&buf[*len], bufsize - *len,
- iter->bitmap, CARL9170_BAW_BITS);
+ ADD(buf, *len, bufsize, "\tWindow: [%*pb,W]\n",
+ CARL9170_BAW_BITS, iter->bitmap);
#define BM_STR_OFF(offset) \
((CARL9170_BAW_BITS - (offset) - 1) / 4 + \
(CARL9170_BAW_BITS - (offset) - 1) / 32 + 1)
- ADD(buf, *len, bufsize, ",W]\n");
-
offset = BM_STR_OFF(0);
ADD(buf, *len, bufsize, "\tBase Seq: %*s\n", offset, "T");
@@ -448,12 +440,8 @@ static char *carl9170_debugfs_vif_dump_read(struct ar9170 *ar, char *buf,
ADD(buf, *len, bufsize, "registered VIFs:%d \\ %d\n",
ar->vifs, ar->fw.vif_num);
- ADD(buf, *len, bufsize, "VIF bitmap: [");
-
- *len += bitmap_scnprintf(&buf[*len], bufsize - *len,
- &ar->vif_bitmap, ar->fw.vif_num);
-
- ADD(buf, *len, bufsize, "]\n");
+ ADD(buf, *len, bufsize, "VIF bitmap: [%*pb]\n",
+ ar->fw.vif_num, &ar->vif_bitmap);
rcu_read_lock();
list_for_each_entry_rcu(iter, &ar->vif_list, list) {
diff --git a/drivers/net/wireless/ath/carl9170/main.c b/drivers/net/wireless/ath/carl9170/main.c
index ef5b6dc7b7f1..f1455a04cb62 100644
--- a/drivers/net/wireless/ath/carl9170/main.c
+++ b/drivers/net/wireless/ath/carl9170/main.c
@@ -1690,9 +1690,9 @@ found:
survey->filled |= SURVEY_INFO_IN_USE;
if (ar->fw.hw_counters) {
- survey->filled |= SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_TX;
+ survey->filled |= SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_TX;
}
return 0;
diff --git a/drivers/net/wireless/ath/dfs_pattern_detector.c b/drivers/net/wireless/ath/dfs_pattern_detector.c
index cfd0554cf140..3d57f8772389 100644
--- a/drivers/net/wireless/ath/dfs_pattern_detector.c
+++ b/drivers/net/wireless/ath/dfs_pattern_detector.c
@@ -86,7 +86,7 @@ static const struct radar_detector_specs fcc_radar_ref_types[] = {
FCC_PATTERN(1, 0, 5, 150, 230, 1, 23),
FCC_PATTERN(2, 6, 10, 200, 500, 1, 16),
FCC_PATTERN(3, 11, 20, 200, 500, 1, 12),
- FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 20),
+ FCC_PATTERN(4, 50, 100, 1000, 2000, 1, 1),
FCC_PATTERN(5, 0, 1, 333, 333, 1, 9),
};
diff --git a/drivers/net/wireless/ath/wcn36xx/dxe.c b/drivers/net/wireless/ath/wcn36xx/dxe.c
index 73f12f196f14..086549b732b9 100644
--- a/drivers/net/wireless/ath/wcn36xx/dxe.c
+++ b/drivers/net/wireless/ath/wcn36xx/dxe.c
@@ -84,6 +84,7 @@ static int wcn36xx_dxe_allocate_ctl_block(struct wcn36xx_dxe_ch *ch)
if (!cur_ctl)
goto out_fail;
+ spin_lock_init(&cur_ctl->skb_lock);
cur_ctl->ctl_blk_order = i;
if (i == 0) {
ch->head_blk_ctl = cur_ctl;
@@ -354,6 +355,8 @@ static void reap_tx_dxes(struct wcn36xx *wcn, struct wcn36xx_dxe_ch *ch)
* and while-do will not make any cycles.
*/
do {
+ if (ctl->desc->ctrl & WCN36XX_DXE_CTRL_VALID_MASK)
+ break;
if (ctl->skb) {
dma_unmap_single(NULL, ctl->desc->src_addr_l,
ctl->skb->len, DMA_TO_DEVICE);
diff --git a/drivers/net/wireless/ath/wcn36xx/main.c b/drivers/net/wireless/ath/wcn36xx/main.c
index 7dd8873f757e..0783d2ed8238 100644
--- a/drivers/net/wireless/ath/wcn36xx/main.c
+++ b/drivers/net/wireless/ath/wcn36xx/main.c
@@ -298,6 +298,8 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
wcn36xx_debugfs_init(wcn);
INIT_LIST_HEAD(&wcn->vif_list);
+ spin_lock_init(&wcn->dxe_lock);
+
return 0;
out_smd_stop:
@@ -795,6 +797,7 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
vif, sta->addr);
+ spin_lock_init(&sta_priv->ampdu_lock);
vif_priv->sta = sta_priv;
sta_priv->vif = vif_priv;
/*
@@ -873,21 +876,32 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
get_sta_index(vif, sta_priv));
wcn36xx_smd_add_ba(wcn);
wcn36xx_smd_trigger_ba(wcn, get_sta_index(vif, sta_priv));
- ieee80211_start_tx_ba_session(sta, tid, 0);
break;
case IEEE80211_AMPDU_RX_STOP:
wcn36xx_smd_del_ba(wcn, tid, get_sta_index(vif, sta_priv));
break;
case IEEE80211_AMPDU_TX_START:
+ spin_lock_bh(&sta_priv->ampdu_lock);
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
+ spin_unlock_bh(&sta_priv->ampdu_lock);
+
ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
case IEEE80211_AMPDU_TX_OPERATIONAL:
+ spin_lock_bh(&sta_priv->ampdu_lock);
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_OPERATIONAL;
+ spin_unlock_bh(&sta_priv->ampdu_lock);
+
wcn36xx_smd_add_ba_session(wcn, sta, tid, ssn, 1,
get_sta_index(vif, sta_priv));
break;
case IEEE80211_AMPDU_TX_STOP_FLUSH:
case IEEE80211_AMPDU_TX_STOP_FLUSH_CONT:
case IEEE80211_AMPDU_TX_STOP_CONT:
+ spin_lock_bh(&sta_priv->ampdu_lock);
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_NONE;
+ spin_unlock_bh(&sta_priv->ampdu_lock);
+
ieee80211_stop_tx_ba_cb_irqsafe(vif, sta->addr, tid);
break;
default:
diff --git a/drivers/net/wireless/ath/wcn36xx/smd.c b/drivers/net/wireless/ath/wcn36xx/smd.c
index 63986931829e..69ed39731902 100644
--- a/drivers/net/wireless/ath/wcn36xx/smd.c
+++ b/drivers/net/wireless/ath/wcn36xx/smd.c
@@ -21,6 +21,61 @@
#include <linux/bitops.h>
#include "smd.h"
+struct wcn36xx_cfg_val {
+ u32 cfg_id;
+ u32 value;
+};
+
+#define WCN36XX_CFG_VAL(id, val) \
+{ \
+ .cfg_id = WCN36XX_HAL_CFG_ ## id, \
+ .value = val \
+}
+
+static struct wcn36xx_cfg_val wcn36xx_cfg_vals[] = {
+ WCN36XX_CFG_VAL(CURRENT_TX_ANTENNA, 1),
+ WCN36XX_CFG_VAL(CURRENT_RX_ANTENNA, 1),
+ WCN36XX_CFG_VAL(LOW_GAIN_OVERRIDE, 0),
+ WCN36XX_CFG_VAL(POWER_STATE_PER_CHAIN, 785),
+ WCN36XX_CFG_VAL(CAL_PERIOD, 5),
+ WCN36XX_CFG_VAL(CAL_CONTROL, 1),
+ WCN36XX_CFG_VAL(PROXIMITY, 0),
+ WCN36XX_CFG_VAL(NETWORK_DENSITY, 3),
+ WCN36XX_CFG_VAL(MAX_MEDIUM_TIME, 6000),
+ WCN36XX_CFG_VAL(MAX_MPDUS_IN_AMPDU, 64),
+ WCN36XX_CFG_VAL(RTS_THRESHOLD, 2347),
+ WCN36XX_CFG_VAL(SHORT_RETRY_LIMIT, 6),
+ WCN36XX_CFG_VAL(LONG_RETRY_LIMIT, 6),
+ WCN36XX_CFG_VAL(FRAGMENTATION_THRESHOLD, 8000),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ZERO, 5),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_ONE, 10),
+ WCN36XX_CFG_VAL(DYNAMIC_THRESHOLD_TWO, 15),
+ WCN36XX_CFG_VAL(FIXED_RATE, 0),
+ WCN36XX_CFG_VAL(RETRYRATE_POLICY, 4),
+ WCN36XX_CFG_VAL(RETRYRATE_SECONDARY, 0),
+ WCN36XX_CFG_VAL(RETRYRATE_TERTIARY, 0),
+ WCN36XX_CFG_VAL(FORCE_POLICY_PROTECTION, 5),
+ WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_24GHZ, 1),
+ WCN36XX_CFG_VAL(FIXED_RATE_MULTICAST_5GHZ, 5),
+ WCN36XX_CFG_VAL(DEFAULT_RATE_INDEX_5GHZ, 5),
+ WCN36XX_CFG_VAL(MAX_BA_SESSIONS, 40),
+ WCN36XX_CFG_VAL(PS_DATA_INACTIVITY_TIMEOUT, 200),
+ WCN36XX_CFG_VAL(PS_ENABLE_BCN_FILTER, 1),
+ WCN36XX_CFG_VAL(PS_ENABLE_RSSI_MONITOR, 1),
+ WCN36XX_CFG_VAL(NUM_BEACON_PER_RSSI_AVERAGE, 20),
+ WCN36XX_CFG_VAL(STATS_PERIOD, 10),
+ WCN36XX_CFG_VAL(CFP_MAX_DURATION, 30000),
+ WCN36XX_CFG_VAL(FRAME_TRANS_ENABLED, 0),
+ WCN36XX_CFG_VAL(BA_THRESHOLD_HIGH, 128),
+ WCN36XX_CFG_VAL(MAX_BA_BUFFERS, 2560),
+ WCN36XX_CFG_VAL(DYNAMIC_PS_POLL_VALUE, 0),
+ WCN36XX_CFG_VAL(TX_PWR_CTRL_ENABLE, 1),
+ WCN36XX_CFG_VAL(ENABLE_CLOSE_LOOP, 1),
+ WCN36XX_CFG_VAL(ENABLE_LPWR_IMG_TRANSITION, 0),
+ WCN36XX_CFG_VAL(MAX_ASSOC_LIMIT, 10),
+ WCN36XX_CFG_VAL(ENABLE_MCC_ADAPTIVE_SCHEDULER, 0),
+};
+
static int put_cfg_tlv_u32(struct wcn36xx *wcn, size_t *len, u32 id, u32 value)
{
struct wcn36xx_hal_cfg *entry;
@@ -357,8 +412,10 @@ static int wcn36xx_smd_start_rsp(struct wcn36xx *wcn, void *buf, size_t len)
int wcn36xx_smd_start(struct wcn36xx *wcn)
{
- struct wcn36xx_hal_mac_start_req_msg msg_body;
+ struct wcn36xx_hal_mac_start_req_msg msg_body, *body;
int ret = 0;
+ int i;
+ size_t len;
mutex_lock(&wcn->hal_mutex);
INIT_HAL_MSG(msg_body, WCN36XX_HAL_START_REQ);
@@ -368,10 +425,22 @@ int wcn36xx_smd_start(struct wcn36xx *wcn)
PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
+ body = (struct wcn36xx_hal_mac_start_req_msg *)wcn->hal_buf;
+ len = body->header.len;
+
+ for (i = 0; i < ARRAY_SIZE(wcn36xx_cfg_vals); i++) {
+ ret = put_cfg_tlv_u32(wcn, &len, wcn36xx_cfg_vals[i].cfg_id,
+ wcn36xx_cfg_vals[i].value);
+ if (ret)
+ goto out;
+ }
+ body->header.len = len;
+ body->params.len = len - sizeof(*body);
+
wcn36xx_dbg(WCN36XX_DBG_HAL, "hal start type %d\n",
msg_body.params.type);
- ret = wcn36xx_smd_send_and_wait(wcn, msg_body.header.len);
+ ret = wcn36xx_smd_send_and_wait(wcn, body->header.len);
if (ret) {
wcn36xx_err("Sending hal_start failed\n");
goto out;
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.c b/drivers/net/wireless/ath/wcn36xx/txrx.c
index 32bb26a0db2a..9bec8237231d 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.c
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.c
@@ -93,6 +93,7 @@ static void wcn36xx_set_tx_pdu(struct wcn36xx_tx_bd *bd,
bd->pdu.mpdu_header_off;
bd->pdu.mpdu_len = len;
bd->pdu.tid = tid;
+ bd->pdu.bd_ssn = WCN36XX_TXBD_SSN_FILL_DPU_QOS;
}
static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
@@ -110,15 +111,54 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
wcn36xx_warn("vif %pM not found\n", addr);
return NULL;
}
+
+static void wcn36xx_tx_start_ampdu(struct wcn36xx *wcn,
+ struct wcn36xx_sta *sta_priv,
+ struct sk_buff *skb)
+{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+ struct ieee80211_sta *sta;
+ u8 *qc, tid;
+
+ if (!conf_is_ht(&wcn->hw->conf))
+ return;
+
+ sta = wcn36xx_priv_to_sta(sta_priv);
+
+ if (WARN_ON(!ieee80211_is_data_qos(hdr->frame_control)))
+ return;
+
+ if (skb_get_queue_mapping(skb) == IEEE80211_AC_VO)
+ return;
+
+ qc = ieee80211_get_qos_ctl(hdr);
+ tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+
+ spin_lock(&sta_priv->ampdu_lock);
+ if (sta_priv->ampdu_state[tid] != WCN36XX_AMPDU_NONE)
+ goto out_unlock;
+
+ if (sta_priv->non_agg_frame_ct++ >= WCN36XX_AMPDU_START_THRESH) {
+ sta_priv->ampdu_state[tid] = WCN36XX_AMPDU_START;
+ sta_priv->non_agg_frame_ct = 0;
+ ieee80211_start_tx_ba_session(sta, tid, 0);
+ }
+out_unlock:
+ spin_unlock(&sta_priv->ampdu_lock);
+}
+
static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
struct wcn36xx *wcn,
struct wcn36xx_vif **vif_priv,
struct wcn36xx_sta *sta_priv,
- struct ieee80211_hdr *hdr,
+ struct sk_buff *skb,
bool bcast)
{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct ieee80211_vif *vif = NULL;
struct wcn36xx_vif *__vif_priv = NULL;
+ bool is_data_qos;
+
bd->bd_rate = WCN36XX_BD_RATE_DATA;
/*
@@ -157,14 +197,26 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
bd->ack_policy = 1;
}
*vif_priv = __vif_priv;
+
+ is_data_qos = ieee80211_is_data_qos(hdr->frame_control);
+
+ wcn36xx_set_tx_pdu(bd,
+ is_data_qos ?
+ sizeof(struct ieee80211_qos_hdr) :
+ sizeof(struct ieee80211_hdr_3addr),
+ skb->len, sta_priv ? sta_priv->tid : 0);
+
+ if (sta_priv && is_data_qos)
+ wcn36xx_tx_start_ampdu(wcn, sta_priv, skb);
}
static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
struct wcn36xx *wcn,
struct wcn36xx_vif **vif_priv,
- struct ieee80211_hdr *hdr,
+ struct sk_buff *skb,
bool bcast)
{
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
struct wcn36xx_vif *__vif_priv =
get_vif_by_addr(wcn, hdr->addr2);
bd->sta_index = __vif_priv->self_sta_index;
@@ -198,6 +250,12 @@ static void wcn36xx_set_tx_mgmt(struct wcn36xx_tx_bd *bd,
} else
bd->queue_id = WCN36XX_TX_U_WQ_ID;
*vif_priv = __vif_priv;
+
+ wcn36xx_set_tx_pdu(bd,
+ ieee80211_is_data_qos(hdr->frame_control) ?
+ sizeof(struct ieee80211_qos_hdr) :
+ sizeof(struct ieee80211_hdr_3addr),
+ skb->len, WCN36XX_TID);
}
int wcn36xx_start_tx(struct wcn36xx *wcn,
@@ -237,7 +295,7 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
bd->dpu_rf = WCN36XX_BMU_WQ_TX;
- bd->tx_comp = info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS;
+ bd->tx_comp = !!(info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS);
if (bd->tx_comp) {
wcn36xx_dbg(WCN36XX_DBG_DXE, "TX_ACK status requested\n");
spin_lock_irqsave(&wcn->dxe_lock, flags);
@@ -259,22 +317,11 @@ int wcn36xx_start_tx(struct wcn36xx *wcn,
}
/* Data frames served first*/
- if (is_low) {
- wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, hdr, bcast);
- wcn36xx_set_tx_pdu(bd,
- ieee80211_is_data_qos(hdr->frame_control) ?
- sizeof(struct ieee80211_qos_hdr) :
- sizeof(struct ieee80211_hdr_3addr),
- skb->len, sta_priv ? sta_priv->tid : 0);
- } else {
+ if (is_low)
+ wcn36xx_set_tx_data(bd, wcn, &vif_priv, sta_priv, skb, bcast);
+ else
/* MGMT and CTRL frames are handeld here*/
- wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, hdr, bcast);
- wcn36xx_set_tx_pdu(bd,
- ieee80211_is_data_qos(hdr->frame_control) ?
- sizeof(struct ieee80211_qos_hdr) :
- sizeof(struct ieee80211_hdr_3addr),
- skb->len, WCN36XX_TID);
- }
+ wcn36xx_set_tx_mgmt(bd, wcn, &vif_priv, skb, bcast);
buff_to_be((u32 *)bd, sizeof(*bd)/sizeof(u32));
bd->tx_bd_sign = 0xbdbdbdbd;
diff --git a/drivers/net/wireless/ath/wcn36xx/txrx.h b/drivers/net/wireless/ath/wcn36xx/txrx.h
index bbfbcf808c77..032216e82b2b 100644
--- a/drivers/net/wireless/ath/wcn36xx/txrx.h
+++ b/drivers/net/wireless/ath/wcn36xx/txrx.h
@@ -32,6 +32,12 @@
#define WCN36XX_BD_RATE_MGMT 2
#define WCN36XX_BD_RATE_CTRL 3
+enum wcn36xx_txbd_ssn_type {
+ WCN36XX_TXBD_SSN_FILL_HOST = 0,
+ WCN36XX_TXBD_SSN_FILL_DPU_NON_QOS = 1,
+ WCN36XX_TXBD_SSN_FILL_DPU_QOS = 2,
+};
+
struct wcn36xx_pdu {
u32 dpu_fb:8;
u32 adu_fb:8;
@@ -50,7 +56,8 @@ struct wcn36xx_pdu {
/* 0x0c*/
u32 reserved4:8;
u32 tid:4;
- u32 reserved3:4;
+ u32 bd_ssn:2;
+ u32 reserved3:2;
u32 mpdu_len:16;
};
diff --git a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
index f0fb81dfd17b..7b41e833e18c 100644
--- a/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
+++ b/drivers/net/wireless/ath/wcn36xx/wcn36xx.h
@@ -32,6 +32,9 @@
#define WLAN_NV_FILE "wlan/prima/WCNSS_qcom_wlan_nv.bin"
#define WCN36XX_AGGR_BUFFER_SIZE 64
+/* How many frames until we start a-mpdu TX session */
+#define WCN36XX_AMPDU_START_THRESH 20
+
extern unsigned int wcn36xx_dbg_mask;
enum wcn36xx_debug_mask {
@@ -74,6 +77,13 @@ enum wcn36xx_debug_mask {
buf, len, false); \
} while (0)
+enum wcn36xx_ampdu_state {
+ WCN36XX_AMPDU_NONE,
+ WCN36XX_AMPDU_INIT,
+ WCN36XX_AMPDU_START,
+ WCN36XX_AMPDU_OPERATIONAL,
+};
+
#define WCN36XX_HW_CHANNEL(__wcn) (__wcn->hw->conf.chandef.chan->hw_value)
#define WCN36XX_BAND(__wcn) (__wcn->hw->conf.chandef.chan->band)
#define WCN36XX_CENTER_FREQ(__wcn) (__wcn->hw->conf.chandef.chan->center_freq)
@@ -165,6 +175,10 @@ struct wcn36xx_sta {
bool is_data_encrypted;
/* Rates */
struct wcn36xx_hal_supported_rates supported_rates;
+
+ spinlock_t ampdu_lock; /* protects next two fields */
+ enum wcn36xx_ampdu_state ampdu_state[16];
+ int non_agg_frame_ct;
};
struct wcn36xx_dxe_ch;
struct wcn36xx {
@@ -243,4 +257,10 @@ static inline bool wcn36xx_is_fw_version(struct wcn36xx *wcn,
}
void wcn36xx_set_default_rates(struct wcn36xx_hal_supported_rates *rates);
+static inline
+struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
+{
+ return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv);
+}
+
#endif /* _WCN36XX_H_ */
diff --git a/drivers/net/wireless/ath/wil6210/Kconfig b/drivers/net/wireless/ath/wil6210/Kconfig
index 481680a3aa55..ce8c0381825e 100644
--- a/drivers/net/wireless/ath/wil6210/Kconfig
+++ b/drivers/net/wireless/ath/wil6210/Kconfig
@@ -39,12 +39,3 @@ config WIL6210_TRACING
option if you are interested in debugging the driver.
If unsure, say Y to make it easier to debug problems.
-
-config WIL6210_PLATFORM_MSM
- bool "wil6210 MSM platform specific support"
- depends on WIL6210
- depends on ARCH_MSM
- default y
- ---help---
- Say Y here to enable wil6210 driver support for MSM
- platform specific features
diff --git a/drivers/net/wireless/ath/wil6210/Makefile b/drivers/net/wireless/ath/wil6210/Makefile
index 8ad4b5f97e04..caa717bf52f3 100644
--- a/drivers/net/wireless/ath/wil6210/Makefile
+++ b/drivers/net/wireless/ath/wil6210/Makefile
@@ -14,7 +14,6 @@ wil6210-y += ioctl.o
wil6210-y += fw.o
wil6210-$(CONFIG_WIL6210_TRACING) += trace.o
wil6210-y += wil_platform.o
-wil6210-$(CONFIG_WIL6210_PLATFORM_MSM) += wil_platform_msm.o
wil6210-y += ethtool.o
# for tracing framework to find trace.h
diff --git a/drivers/net/wireless/ath/wil6210/cfg80211.c b/drivers/net/wireless/ath/wil6210/cfg80211.c
index 38332a6dfb3a..2d5ea21be47e 100644
--- a/drivers/net/wireless/ath/wil6210/cfg80211.c
+++ b/drivers/net/wireless/ath/wil6210/cfg80211.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -142,14 +142,14 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
sinfo->generation = wil->sinfo_gen;
- sinfo->filled = STATION_INFO_RX_BYTES |
- STATION_INFO_TX_BYTES |
- STATION_INFO_RX_PACKETS |
- STATION_INFO_TX_PACKETS |
- STATION_INFO_RX_BITRATE |
- STATION_INFO_TX_BITRATE |
- STATION_INFO_RX_DROP_MISC |
- STATION_INFO_TX_FAILED;
+ sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) |
+ BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS) |
+ BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_RX_BITRATE) |
+ BIT(NL80211_STA_INFO_TX_BITRATE) |
+ BIT(NL80211_STA_INFO_RX_DROP_MISC) |
+ BIT(NL80211_STA_INFO_TX_FAILED);
sinfo->txrate.flags = RATE_INFO_FLAGS_MCS | RATE_INFO_FLAGS_60G;
sinfo->txrate.mcs = le16_to_cpu(reply.evt.bf_mcs);
@@ -162,8 +162,8 @@ int wil_cid_fill_sinfo(struct wil6210_priv *wil, int cid,
sinfo->tx_packets = stats->tx_packets;
sinfo->tx_failed = stats->tx_errors;
- if (test_bit(wil_status_fwconnected, &wil->status)) {
- sinfo->filled |= STATION_INFO_SIGNAL;
+ if (test_bit(wil_status_fwconnected, wil->status)) {
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
sinfo->signal = reply.evt.sqi;
}
@@ -282,7 +282,7 @@ static int wil_cfg80211_scan(struct wiphy *wiphy,
}
/* FW don't support scan after connection attempt */
- if (test_bit(wil_status_dontscan, &wil->status)) {
+ if (test_bit(wil_status_dontscan, wil->status)) {
wil_err(wil, "Can't scan now\n");
return -EBUSY;
}
@@ -334,6 +334,30 @@ out:
return rc;
}
+static void wil_print_crypto(struct wil6210_priv *wil,
+ struct cfg80211_crypto_settings *c)
+{
+ int i, n;
+
+ wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n",
+ c->wpa_versions, c->cipher_group);
+ wil_dbg_misc(wil, "Pairwise ciphers [%d] {\n", c->n_ciphers_pairwise);
+ n = min_t(int, c->n_ciphers_pairwise, ARRAY_SIZE(c->ciphers_pairwise));
+ for (i = 0; i < n; i++)
+ wil_dbg_misc(wil, " [%d] = 0x%08x\n", i,
+ c->ciphers_pairwise[i]);
+ wil_dbg_misc(wil, "}\n");
+ wil_dbg_misc(wil, "AKM suites [%d] {\n", c->n_akm_suites);
+ n = min_t(int, c->n_akm_suites, ARRAY_SIZE(c->akm_suites));
+ for (i = 0; i < n; i++)
+ wil_dbg_misc(wil, " [%d] = 0x%08x\n", i,
+ c->akm_suites[i]);
+ wil_dbg_misc(wil, "}\n");
+ wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n",
+ c->control_port, be16_to_cpu(c->control_port_ethertype),
+ c->control_port_no_encrypt);
+}
+
static void wil_print_connect_params(struct wil6210_priv *wil,
struct cfg80211_connect_params *sme)
{
@@ -348,6 +372,7 @@ static void wil_print_connect_params(struct wil6210_priv *wil,
print_hex_dump(KERN_INFO, " SSID: ", DUMP_PREFIX_OFFSET,
16, 1, sme->ssid, sme->ssid_len, true);
wil_info(wil, " Privacy: %s\n", sme->privacy ? "secure" : "open");
+ wil_print_crypto(wil, &sme->crypto);
}
static int wil_cfg80211_connect(struct wiphy *wiphy,
@@ -362,8 +387,8 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
int ch;
int rc = 0;
- if (test_bit(wil_status_fwconnecting, &wil->status) ||
- test_bit(wil_status_fwconnected, &wil->status))
+ if (test_bit(wil_status_fwconnecting, wil->status) ||
+ test_bit(wil_status_fwconnected, wil->status))
return -EALREADY;
wil_print_connect_params(wil, sme);
@@ -450,15 +475,16 @@ static int wil_cfg80211_connect(struct wiphy *wiphy,
memcpy(conn.bssid, bss->bssid, ETH_ALEN);
memcpy(conn.dst_mac, bss->bssid, ETH_ALEN);
- set_bit(wil_status_fwconnecting, &wil->status);
+ set_bit(wil_status_fwconnecting, wil->status);
rc = wmi_send(wil, WMI_CONNECT_CMDID, &conn, sizeof(conn));
if (rc == 0) {
+ netif_carrier_on(ndev);
/* Connect can take lots of time */
mod_timer(&wil->connect_timer,
jiffies + msecs_to_jiffies(2000));
} else {
- clear_bit(wil_status_fwconnecting, &wil->status);
+ clear_bit(wil_status_fwconnecting, wil->status);
}
out:
@@ -618,18 +644,6 @@ static void wil_print_bcon_data(struct cfg80211_beacon_data *b)
b->assocresp_ies, b->assocresp_ies_len);
}
-static void wil_print_crypto(struct wil6210_priv *wil,
- struct cfg80211_crypto_settings *c)
-{
- wil_dbg_misc(wil, "WPA versions: 0x%08x cipher group 0x%08x\n",
- c->wpa_versions, c->cipher_group);
- wil_dbg_misc(wil, "Pairwise ciphers [%d]\n", c->n_ciphers_pairwise);
- wil_dbg_misc(wil, "AKM suites [%d]\n", c->n_akm_suites);
- wil_dbg_misc(wil, "Control port : %d, eth_type 0x%04x no_encrypt %d\n",
- c->control_port, be16_to_cpu(c->control_port_ethertype),
- c->control_port_no_encrypt);
-}
-
static int wil_fix_bcon(struct wil6210_priv *wil,
struct cfg80211_beacon_data *bcon)
{
@@ -757,12 +771,12 @@ static int wil_cfg80211_start_ap(struct wiphy *wiphy,
wil->secure_pcp = info->privacy;
+ netif_carrier_on(ndev);
+
rc = wmi_pcp_start(wil, info->beacon_interval, wmi_nettype,
channel->hw_value);
if (rc)
- goto out;
-
- netif_carrier_on(ndev);
+ netif_carrier_off(ndev);
out:
mutex_unlock(&wil->mutex);
@@ -772,23 +786,26 @@ out:
static int wil_cfg80211_stop_ap(struct wiphy *wiphy,
struct net_device *ndev)
{
- int rc, rc1;
struct wil6210_priv *wil = wiphy_to_wil(wiphy);
wil_dbg_misc(wil, "%s()\n", __func__);
+ netif_carrier_off(ndev);
wil_set_recovery_state(wil, fw_recovery_idle);
mutex_lock(&wil->mutex);
- rc = wmi_pcp_stop(wil);
+ wmi_pcp_stop(wil);
__wil_down(wil);
- rc1 = __wil_up(wil);
+ __wil_up(wil);
mutex_unlock(&wil->mutex);
- return min(rc, rc1);
+ /* some functions above might fail (e.g. __wil_up). Nevertheless, we
+ * return success because AP has stopped
+ */
+ return 0;
}
static int wil_cfg80211_del_station(struct wiphy *wiphy,
@@ -804,6 +821,96 @@ static int wil_cfg80211_del_station(struct wiphy *wiphy,
return 0;
}
+/* probe_client handling */
+static void wil_probe_client_handle(struct wil6210_priv *wil,
+ struct wil_probe_client_req *req)
+{
+ struct net_device *ndev = wil_to_ndev(wil);
+ struct wil_sta_info *sta = &wil->sta[req->cid];
+ /* assume STA is alive if it is still connected,
+ * else FW will disconnect it
+ */
+ bool alive = (sta->status == wil_sta_connected);
+
+ cfg80211_probe_status(ndev, sta->addr, req->cookie, alive, GFP_KERNEL);
+}
+
+static struct list_head *next_probe_client(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->probe_client_mutex);
+
+ if (!list_empty(&wil->probe_client_pending)) {
+ ret = wil->probe_client_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->probe_client_mutex);
+
+ return ret;
+}
+
+void wil_probe_client_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ probe_client_worker);
+ struct wil_probe_client_req *req;
+ struct list_head *lh;
+
+ while ((lh = next_probe_client(wil)) != NULL) {
+ req = list_entry(lh, struct wil_probe_client_req, list);
+
+ wil_probe_client_handle(wil, req);
+ kfree(req);
+ }
+}
+
+void wil_probe_client_flush(struct wil6210_priv *wil)
+{
+ struct wil_probe_client_req *req, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->probe_client_mutex);
+
+ list_for_each_entry_safe(req, t, &wil->probe_client_pending, list) {
+ list_del(&req->list);
+ kfree(req);
+ }
+
+ mutex_unlock(&wil->probe_client_mutex);
+}
+
+static int wil_cfg80211_probe_client(struct wiphy *wiphy,
+ struct net_device *dev,
+ const u8 *peer, u64 *cookie)
+{
+ struct wil6210_priv *wil = wiphy_to_wil(wiphy);
+ struct wil_probe_client_req *req;
+ int cid = wil_find_cid(wil, peer);
+
+ wil_dbg_misc(wil, "%s(%pM => CID %d)\n", __func__, peer, cid);
+
+ if (cid < 0)
+ return -ENOLINK;
+
+ req = kzalloc(sizeof(*req), GFP_KERNEL);
+ if (!req)
+ return -ENOMEM;
+
+ req->cid = cid;
+ req->cookie = cid;
+
+ mutex_lock(&wil->probe_client_mutex);
+ list_add_tail(&req->list, &wil->probe_client_pending);
+ mutex_unlock(&wil->probe_client_mutex);
+
+ *cookie = req->cookie;
+ queue_work(wil->wq_service, &wil->probe_client_worker);
+ return 0;
+}
+
static struct cfg80211_ops wil_cfg80211_ops = {
.scan = wil_cfg80211_scan,
.connect = wil_cfg80211_connect,
@@ -823,6 +930,7 @@ static struct cfg80211_ops wil_cfg80211_ops = {
.start_ap = wil_cfg80211_start_ap,
.stop_ap = wil_cfg80211_stop_ap,
.del_station = wil_cfg80211_del_station,
+ .probe_client = wil_cfg80211_probe_client,
};
static void wil_wiphy_init(struct wiphy *wiphy)
@@ -854,6 +962,7 @@ static void wil_wiphy_init(struct wiphy *wiphy)
wiphy->cipher_suites = wil_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(wil_cipher_suites);
wiphy->mgmt_stypes = wil_mgmt_stypes;
+ wiphy->features |= NL80211_FEATURE_SK_TX_STATUS;
}
struct wireless_dev *wil_cfg80211_init(struct device *dev)
diff --git a/drivers/net/wireless/ath/wil6210/debugfs.c b/drivers/net/wireless/ath/wil6210/debugfs.c
index 4e6e14501c2f..45c3558ec804 100644
--- a/drivers/net/wireless/ath/wil6210/debugfs.c
+++ b/drivers/net/wireless/ath/wil6210/debugfs.c
@@ -50,6 +50,7 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
char _s, char _h)
{
void __iomem *x = wmi_addr(wil, vring->hwtail);
+ u32 v;
seq_printf(s, "VRING %s = {\n", name);
seq_printf(s, " pa = %pad\n", &vring->pa);
@@ -58,10 +59,12 @@ static void wil_print_vring(struct seq_file *s, struct wil6210_priv *wil,
seq_printf(s, " swtail = %d\n", vring->swtail);
seq_printf(s, " swhead = %d\n", vring->swhead);
seq_printf(s, " hwtail = [0x%08x] -> ", vring->hwtail);
- if (x)
- seq_printf(s, "0x%08x\n", ioread32(x));
- else
+ if (x) {
+ v = ioread32(x);
+ seq_printf(s, "0x%08x = %d\n", v, v);
+ } else {
seq_puts(s, "???\n");
+ }
if (vring->va && (vring->size < 1025)) {
uint i;
@@ -101,8 +104,8 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
char name[10];
/* performance monitoring */
cycles_t now = get_cycles();
- cycles_t idle = txdata->idle * 100;
- cycles_t total = now - txdata->begin;
+ uint64_t idle = txdata->idle * 100;
+ uint64_t total = now - txdata->begin;
do_div(idle, total);
txdata->begin = now;
@@ -110,9 +113,12 @@ static int wil_vring_debugfs_show(struct seq_file *s, void *data)
snprintf(name, sizeof(name), "tx_%2d", i);
- seq_printf(s, "\n%pM CID %d TID %d [%3d|%3d] idle %3d%%\n",
- wil->sta[cid].addr, cid, tid, used, avail,
- (int)idle);
+ seq_printf(s,
+ "\n%pM CID %d TID %d BACK([%d] %d TU A%s) [%3d|%3d] idle %3d%%\n",
+ wil->sta[cid].addr, cid, tid,
+ txdata->agg_wsize, txdata->agg_timeout,
+ txdata->agg_amsdu ? "+" : "-",
+ used, avail, (int)idle);
wil_print_vring(s, wil, name, vring, '_', 'H');
}
@@ -384,24 +390,67 @@ static int wil6210_debugfs_create_pseudo_ISR(struct wil6210_priv *wil,
return 0;
}
-static const struct dbg_off itr_cnt_off[] = {
+static const struct dbg_off lgc_itr_cnt_off[] = {
{"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_TRSH), doff_io32},
{"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_DATA), doff_io32},
{"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_CNT_CRL), doff_io32},
{},
};
+static const struct dbg_off tx_itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH),
+ doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_DATA),
+ doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL),
+ doff_io32},
+ {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_TRSH),
+ doff_io32},
+ {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_DATA),
+ doff_io32},
+ {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_TX_IDL_CNT_CTL),
+ doff_io32},
+ {},
+};
+
+static const struct dbg_off rx_itr_cnt_off[] = {
+ {"TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH),
+ doff_io32},
+ {"DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_DATA),
+ doff_io32},
+ {"CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL),
+ doff_io32},
+ {"IDL_TRSH", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_TRSH),
+ doff_io32},
+ {"IDL_DATA", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_DATA),
+ doff_io32},
+ {"IDL_CTL", S_IRUGO | S_IWUSR, HOSTADDR(RGF_DMA_ITR_RX_IDL_CNT_CTL),
+ doff_io32},
+ {},
+};
+
static int wil6210_debugfs_create_ITR_CNT(struct wil6210_priv *wil,
struct dentry *parent)
{
- struct dentry *d = debugfs_create_dir("ITR_CNT", parent);
+ struct dentry *d, *dtx, *drx;
+ d = debugfs_create_dir("ITR_CNT", parent);
if (IS_ERR_OR_NULL(d))
return -ENODEV;
+ dtx = debugfs_create_dir("TX", d);
+ drx = debugfs_create_dir("RX", d);
+ if (IS_ERR_OR_NULL(dtx) || IS_ERR_OR_NULL(drx))
+ return -ENODEV;
+
wil6210_debugfs_init_offset(wil, d, (void * __force)wil->csr,
- itr_cnt_off);
+ lgc_itr_cnt_off);
+
+ wil6210_debugfs_init_offset(wil, dtx, (void * __force)wil->csr,
+ tx_itr_cnt_off);
+ wil6210_debugfs_init_offset(wil, drx, (void * __force)wil->csr,
+ rx_itr_cnt_off);
return 0;
}
@@ -558,6 +607,87 @@ static const struct file_operations fops_rxon = {
.open = simple_open,
};
+/* block ack control, write:
+ * - "add <ringid> <agg_size> <timeout>" to trigger ADDBA
+ * - "del_tx <ringid> <reason>" to trigger DELBA for Tx side
+ * - "del_rx <CID> <TID> <reason>" to trigger DELBA for Rx side
+ */
+static ssize_t wil_write_back(struct file *file, const char __user *buf,
+ size_t len, loff_t *ppos)
+{
+ struct wil6210_priv *wil = file->private_data;
+ int rc;
+ char *kbuf = kmalloc(len + 1, GFP_KERNEL);
+ char cmd[8];
+ int p1, p2, p3;
+
+ if (!kbuf)
+ return -ENOMEM;
+
+ rc = simple_write_to_buffer(kbuf, len, ppos, buf, len);
+ if (rc != len) {
+ kfree(kbuf);
+ return rc >= 0 ? -EIO : rc;
+ }
+
+ kbuf[len] = '\0';
+ rc = sscanf(kbuf, "%8s %d %d %d", cmd, &p1, &p2, &p3);
+ kfree(kbuf);
+
+ if (rc < 0)
+ return rc;
+ if (rc < 2)
+ return -EINVAL;
+
+ if (0 == strcmp(cmd, "add")) {
+ if (rc < 3) {
+ wil_err(wil, "BACK: add require at least 2 params\n");
+ return -EINVAL;
+ }
+ if (rc < 4)
+ p3 = 0;
+ wmi_addba(wil, p1, p2, p3);
+ } else if (0 == strcmp(cmd, "del_tx")) {
+ if (rc < 3)
+ p2 = WLAN_REASON_QSTA_LEAVE_QBSS;
+ wmi_delba_tx(wil, p1, p2);
+ } else if (0 == strcmp(cmd, "del_rx")) {
+ if (rc < 3) {
+ wil_err(wil,
+ "BACK: del_rx require at least 2 params\n");
+ return -EINVAL;
+ }
+ if (rc < 4)
+ p3 = WLAN_REASON_QSTA_LEAVE_QBSS;
+ wmi_delba_rx(wil, mk_cidxtid(p1, p2), p3);
+ } else {
+ wil_err(wil, "BACK: Unrecognized command \"%s\"\n", cmd);
+ return -EINVAL;
+ }
+
+ return len;
+}
+
+static ssize_t wil_read_back(struct file *file, char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ static const char text[] = "block ack control, write:\n"
+ " - \"add <ringid> <agg_size> <timeout>\" to trigger ADDBA\n"
+ "If missing, <timeout> defaults to 0\n"
+ " - \"del_tx <ringid> <reason>\" to trigger DELBA for Tx side\n"
+ " - \"del_rx <CID> <TID> <reason>\" to trigger DELBA for Rx side\n"
+ "If missing, <reason> set to \"STA_LEAVING\" (36)\n";
+
+ return simple_read_from_buffer(user_buf, count, ppos, text,
+ sizeof(text));
+}
+
+static const struct file_operations fops_back = {
+ .read = wil_read_back,
+ .write = wil_write_back,
+ .open = simple_open,
+};
+
/*---tx_mgmt---*/
/* Write mgmt frame to this file to send it */
static ssize_t wil_write_file_txmgmt(struct file *file, const char __user *buf,
@@ -1116,7 +1246,8 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
int i;
u16 index = ((r->head_seq_num - r->ssn) & 0xfff) % r->buf_size;
- seq_printf(s, "0x%03x [", r->head_seq_num);
+ seq_printf(s, "([%2d] %3d TU) 0x%03x [", r->buf_size, r->timeout,
+ r->head_seq_num);
for (i = 0; i < r->buf_size; i++) {
if (i == index)
seq_printf(s, "%c", r->reorder_buf[i] ? 'O' : '|');
@@ -1127,10 +1258,10 @@ static void wil_print_rxtid(struct seq_file *s, struct wil_tid_ampdu_rx *r)
}
static int wil_sta_debugfs_show(struct seq_file *s, void *data)
+__acquires(&p->tid_rx_lock) __releases(&p->tid_rx_lock)
{
struct wil6210_priv *wil = s->private;
int i, tid;
- unsigned long flags;
for (i = 0; i < ARRAY_SIZE(wil->sta); i++) {
struct wil_sta_info *p = &wil->sta[i];
@@ -1151,7 +1282,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
(p->data_port_open ? " data_port_open" : ""));
if (p->status == wil_sta_connected) {
- spin_lock_irqsave(&p->tid_rx_lock, flags);
+ spin_lock_bh(&p->tid_rx_lock);
for (tid = 0; tid < WIL_STA_TID_NUM; tid++) {
struct wil_tid_ampdu_rx *r = p->tid_rx[tid];
@@ -1160,7 +1291,7 @@ static int wil_sta_debugfs_show(struct seq_file *s, void *data)
wil_print_rxtid(s, r);
}
}
- spin_unlock_irqrestore(&p->tid_rx_lock, flags);
+ spin_unlock_bh(&p->tid_rx_lock);
}
}
@@ -1217,6 +1348,7 @@ static const struct {
{"rxon", S_IWUSR, &fops_rxon},
{"tx_mgmt", S_IWUSR, &fops_txmgmt},
{"wmi_send", S_IWUSR, &fops_wmi},
+ {"back", S_IRUGO | S_IWUSR, &fops_back},
{"temp", S_IRUGO, &fops_temp},
{"freq", S_IRUGO, &fops_freq},
{"link", S_IRUGO, &fops_link},
@@ -1261,7 +1393,7 @@ static void wil6210_debugfs_init_isr(struct wil6210_priv *wil,
/* fields in struct wil6210_priv */
static const struct dbg_off dbg_wil_off[] = {
WIL_FIELD(secure_pcp, S_IRUGO | S_IWUSR, doff_u32),
- WIL_FIELD(status, S_IRUGO | S_IWUSR, doff_ulong),
+ WIL_FIELD(status[0], S_IRUGO | S_IWUSR, doff_ulong),
WIL_FIELD(fw_version, S_IRUGO, doff_u32),
WIL_FIELD(hw_version, S_IRUGO, doff_x32),
WIL_FIELD(recovery_count, S_IRUGO, doff_u32),
diff --git a/drivers/net/wireless/ath/wil6210/ethtool.c b/drivers/net/wireless/ath/wil6210/ethtool.c
index d686638972be..4c44a82c34d7 100644
--- a/drivers/net/wireless/ath/wil6210/ethtool.c
+++ b/drivers/net/wireless/ath/wil6210/ethtool.c
@@ -45,16 +45,35 @@ static int wil_ethtoolops_get_coalesce(struct net_device *ndev,
struct ethtool_coalesce *cp)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- u32 itr_en, itr_val = 0;
+ u32 tx_itr_en, tx_itr_val = 0;
+ u32 rx_itr_en, rx_itr_val = 0;
wil_dbg_misc(wil, "%s()\n", __func__);
- itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
- if (itr_en & BIT_DMA_ITR_CNT_CRL_EN)
- itr_val = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
-
- cp->rx_coalesce_usecs = itr_val;
+ if (test_bit(hw_capability_advanced_itr_moderation,
+ wil->hw_capabilities)) {
+ tx_itr_en = ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_TX_CNT_CTL));
+ if (tx_itr_en & BIT_DMA_ITR_TX_CNT_CTL_EN)
+ tx_itr_val =
+ ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_TX_CNT_TRSH));
+
+ rx_itr_en = ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_RX_CNT_CTL));
+ if (rx_itr_en & BIT_DMA_ITR_RX_CNT_CTL_EN)
+ rx_itr_val =
+ ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_RX_CNT_TRSH));
+ } else {
+ rx_itr_en = ioread32(wil->csr + HOSTADDR(RGF_DMA_ITR_CNT_CRL));
+ if (rx_itr_en & BIT_DMA_ITR_CNT_CRL_EN)
+ rx_itr_val = ioread32(wil->csr +
+ HOSTADDR(RGF_DMA_ITR_CNT_TRSH));
+ }
+ cp->tx_coalesce_usecs = tx_itr_val;
+ cp->rx_coalesce_usecs = rx_itr_val;
return 0;
}
@@ -63,22 +82,25 @@ static int wil_ethtoolops_set_coalesce(struct net_device *ndev,
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
- wil_dbg_misc(wil, "%s(%d usec)\n", __func__, cp->rx_coalesce_usecs);
+ wil_dbg_misc(wil, "%s(rx %d usec, tx %d usec)\n", __func__,
+ cp->rx_coalesce_usecs, cp->tx_coalesce_usecs);
if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR) {
wil_dbg_misc(wil, "No IRQ coalescing in monitor mode\n");
return -EINVAL;
}
- /* only @rx_coalesce_usecs supported, ignore
- * other parameters
+ /* only @rx_coalesce_usecs and @tx_coalesce_usecs supported,
+ * ignore other parameters
*/
- if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
+ if (cp->rx_coalesce_usecs > WIL6210_ITR_TRSH_MAX ||
+ cp->tx_coalesce_usecs > WIL6210_ITR_TRSH_MAX)
goto out_bad;
- wil->itr_trsh = cp->rx_coalesce_usecs;
- wil_set_itr_trsh(wil);
+ wil->tx_max_burst_duration = cp->tx_coalesce_usecs;
+ wil->rx_max_burst_duration = cp->rx_coalesce_usecs;
+ wil_configure_interrupt_moderation(wil);
return 0;
diff --git a/drivers/net/wireless/ath/wil6210/interrupt.c b/drivers/net/wireless/ath/wil6210/interrupt.c
index 4bcbd6297b3e..a6f923086f31 100644
--- a/drivers/net/wireless/ath/wil6210/interrupt.c
+++ b/drivers/net/wireless/ath/wil6210/interrupt.c
@@ -102,7 +102,7 @@ static void wil6210_mask_irq_pseudo(struct wil6210_priv *wil)
iowrite32(WIL6210_IRQ_DISABLE, wil->csr +
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
- clear_bit(wil_status_irqen, &wil->status);
+ clear_bit(wil_status_irqen, wil->status);
}
void wil6210_unmask_irq_tx(struct wil6210_priv *wil)
@@ -130,7 +130,7 @@ static void wil6210_unmask_irq_pseudo(struct wil6210_priv *wil)
{
wil_dbg_irq(wil, "%s()\n", __func__);
- set_bit(wil_status_irqen, &wil->status);
+ set_bit(wil_status_irqen, wil->status);
iowrite32(WIL6210_IRQ_PSEUDO_MASK, wil->csr +
HOSTADDR(RGF_DMA_PSEUDO_CAUSE_MASK_SW));
@@ -157,15 +157,91 @@ void wil_unmask_irq(struct wil6210_priv *wil)
iowrite32(WIL_ICR_ICC_VALUE, wil->csr + HOSTADDR(RGF_DMA_EP_MISC_ICR) +
offsetof(struct RGF_ICR, ICC));
- /* interrupt moderation parameters */
- wil_set_itr_trsh(wil);
-
wil6210_unmask_irq_pseudo(wil);
wil6210_unmask_irq_tx(wil);
wil6210_unmask_irq_rx(wil);
wil6210_unmask_irq_misc(wil);
}
+/* target write operation */
+#define W(a, v) do { iowrite32(v, wil->csr + HOSTADDR(a)); wmb(); } while (0)
+
+static
+void wil_configure_interrupt_moderation_new(struct wil6210_priv *wil)
+{
+ /* Disable and clear tx counter before (re)configuration */
+ W(RGF_DMA_ITR_TX_CNT_CTL, BIT_DMA_ITR_TX_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_TX_CNT_TRSH, wil->tx_max_burst_duration);
+ wil_info(wil, "set ITR_TX_CNT_TRSH = %d usec\n",
+ wil->tx_max_burst_duration);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_TX_CNT_CTL,
+ BIT_DMA_ITR_TX_CNT_CTL_EN | BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL);
+
+ /* Disable and clear tx idle counter before (re)configuration */
+ W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_TX_IDL_CNT_TRSH, wil->tx_interframe_timeout);
+ wil_info(wil, "set ITR_TX_IDL_CNT_TRSH = %d usec\n",
+ wil->tx_interframe_timeout);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_TX_IDL_CNT_CTL, BIT_DMA_ITR_TX_IDL_CNT_CTL_EN |
+ BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL);
+
+ /* Disable and clear rx counter before (re)configuration */
+ W(RGF_DMA_ITR_RX_CNT_CTL, BIT_DMA_ITR_RX_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_RX_CNT_TRSH, wil->rx_max_burst_duration);
+ wil_info(wil, "set ITR_RX_CNT_TRSH = %d usec\n",
+ wil->rx_max_burst_duration);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_RX_CNT_CTL,
+ BIT_DMA_ITR_RX_CNT_CTL_EN | BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL);
+
+ /* Disable and clear rx idle counter before (re)configuration */
+ W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR);
+ W(RGF_DMA_ITR_RX_IDL_CNT_TRSH, wil->rx_interframe_timeout);
+ wil_info(wil, "set ITR_RX_IDL_CNT_TRSH = %d usec\n",
+ wil->rx_interframe_timeout);
+ /* Configure TX max burst duration timer to use usec units */
+ W(RGF_DMA_ITR_RX_IDL_CNT_CTL, BIT_DMA_ITR_RX_IDL_CNT_CTL_EN |
+ BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL);
+}
+
+static
+void wil_configure_interrupt_moderation_lgc(struct wil6210_priv *wil)
+{
+ /* disable, use usec resolution */
+ W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_CLR);
+
+ wil_info(wil, "set ITR_TRSH = %d usec\n", wil->rx_max_burst_duration);
+ W(RGF_DMA_ITR_CNT_TRSH, wil->rx_max_burst_duration);
+ /* start it */
+ W(RGF_DMA_ITR_CNT_CRL,
+ BIT_DMA_ITR_CNT_CRL_EN | BIT_DMA_ITR_CNT_CRL_EXT_TICK);
+}
+
+#undef W
+
+void wil_configure_interrupt_moderation(struct wil6210_priv *wil)
+{
+ wil_dbg_irq(wil, "%s()\n", __func__);
+
+ /* disable interrupt moderation for monitor
+ * to get better timestamp precision
+ */
+ if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
+ return;
+
+ if (test_bit(hw_capability_advanced_itr_moderation,
+ wil->hw_capabilities))
+ wil_configure_interrupt_moderation_new(wil);
+ else {
+ /* Advanced interrupt moderation is not available before
+ * Sparrow v2. Will use legacy interrupt moderation
+ */
+ wil_configure_interrupt_moderation_lgc(wil);
+ }
+}
+
static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
{
struct wil6210_priv *wil = cookie;
@@ -194,18 +270,19 @@ static irqreturn_t wil6210_irq_rx(int irq, void *cookie)
wil_dbg_irq(wil, "RX done\n");
if (isr & BIT_DMA_EP_RX_ICR_RX_HTRSH)
- wil_err_ratelimited(wil, "Received \"Rx buffer is in risk "
- "of overflow\" interrupt\n");
+ wil_err_ratelimited(wil,
+ "Received \"Rx buffer is in risk of overflow\" interrupt\n");
- isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE | BIT_DMA_EP_RX_ICR_RX_HTRSH);
- if (test_bit(wil_status_reset_done, &wil->status)) {
- if (test_bit(wil_status_napi_en, &wil->status)) {
+ isr &= ~(BIT_DMA_EP_RX_ICR_RX_DONE |
+ BIT_DMA_EP_RX_ICR_RX_HTRSH);
+ if (test_bit(wil_status_reset_done, wil->status)) {
+ if (test_bit(wil_status_napi_en, wil->status)) {
wil_dbg_txrx(wil, "NAPI(Rx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_rx);
} else {
- wil_err(wil, "Got Rx interrupt while "
- "stopping interface\n");
+ wil_err(wil,
+ "Got Rx interrupt while stopping interface\n");
}
} else {
wil_err(wil, "Got Rx interrupt while in reset\n");
@@ -248,7 +325,7 @@ static irqreturn_t wil6210_irq_tx(int irq, void *cookie)
isr &= ~BIT_DMA_EP_TX_ICR_TX_DONE;
/* clear also all VRING interrupts */
isr &= ~(BIT(25) - 1UL);
- if (test_bit(wil_status_reset_done, &wil->status)) {
+ if (test_bit(wil_status_reset_done, wil->status)) {
wil_dbg_txrx(wil, "NAPI(Tx) schedule\n");
need_unmask = false;
napi_schedule(&wil->napi_tx);
@@ -310,7 +387,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
if (isr & ISR_MISC_FW_ERROR) {
wil_err(wil, "Firmware error detected\n");
- clear_bit(wil_status_fwready, &wil->status);
+ clear_bit(wil_status_fwready, wil->status);
/*
* do not clear @isr here - we do 2-nd part in thread
* there, user space get notified, and it should be done
@@ -321,7 +398,7 @@ static irqreturn_t wil6210_irq_misc(int irq, void *cookie)
if (isr & ISR_MISC_FW_READY) {
wil_dbg_irq(wil, "IRQ: FW ready\n");
wil_cache_mbox_regs(wil);
- set_bit(wil_status_reset_done, &wil->status);
+ set_bit(wil_status_reset_done, wil->status);
/**
* Actual FW ready indicated by the
* WMI_FW_READY_EVENTID
@@ -394,7 +471,7 @@ static irqreturn_t wil6210_thread_irq(int irq, void *cookie)
*/
static int wil6210_debug_irq_mask(struct wil6210_priv *wil, u32 pseudo_cause)
{
- if (!test_bit(wil_status_irqen, &wil->status)) {
+ if (!test_bit(wil_status_irqen, wil->status)) {
u32 icm_rx = wil_ioread32_and_clear(wil->csr +
HOSTADDR(RGF_DMA_EP_RX_ICR) +
offsetof(struct RGF_ICR, ICM));
diff --git a/drivers/net/wireless/ath/wil6210/main.c b/drivers/net/wireless/ath/wil6210/main.c
index 8ff3fe34fe05..b04e0afdcb21 100644
--- a/drivers/net/wireless/ath/wil6210/main.c
+++ b/drivers/net/wireless/ath/wil6210/main.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -33,15 +33,18 @@ static bool no_fw_load = true;
module_param(no_fw_load, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(no_fw_load, " do not download FW, use one in on-card flash.");
-static unsigned int itr_trsh = WIL6210_ITR_TRSH_DEFAULT;
-
-module_param(itr_trsh, uint, S_IRUGO);
-MODULE_PARM_DESC(itr_trsh, " Interrupt moderation threshold, usecs.");
+/* if not set via modparam, will be set to default value of 1/8 of
+ * rx ring size during init flow
+ */
+unsigned short rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_INIT;
+module_param(rx_ring_overflow_thrsh, ushort, S_IRUGO);
+MODULE_PARM_DESC(rx_ring_overflow_thrsh,
+ " RX ring overflow threshold in descriptors.");
/* We allow allocation of more than 1 page buffers to support large packets.
* It is suboptimal behavior performance wise in case MTU above page size.
*/
-unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - ETH_HLEN;
+unsigned int mtu_max = TXRX_BUF_LEN_DEFAULT - WIL_MAX_MPDU_OVERHEAD;
static int mtu_max_set(const char *val, const struct kernel_param *kp)
{
int ret;
@@ -53,7 +56,7 @@ static int mtu_max_set(const char *val, const struct kernel_param *kp)
if (ret)
return ret;
- if (mtu_max < 68 || mtu_max > IEEE80211_MAX_DATA_LEN_DMG)
+ if (mtu_max < 68 || mtu_max > WIL_MAX_ETH_MTU)
ret = -EINVAL;
return ret;
@@ -135,12 +138,14 @@ void wil_memcpy_toio_32(volatile void __iomem *dst, const void *src,
static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
u16 reason_code, bool from_event)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
uint i;
struct net_device *ndev = wil_to_ndev(wil);
struct wireless_dev *wdev = wil->wdev;
struct wil_sta_info *sta = &wil->sta[cid];
+ might_sleep();
wil_dbg_misc(wil, "%s(CID %d, status %d)\n", __func__, cid,
sta->status);
@@ -163,15 +168,14 @@ static void wil_disconnect_cid(struct wil6210_priv *wil, int cid,
for (i = 0; i < WIL_STA_TID_NUM; i++) {
struct wil_tid_ampdu_rx *r;
- unsigned long flags;
- spin_lock_irqsave(&sta->tid_rx_lock, flags);
+ spin_lock_bh(&sta->tid_rx_lock);
r = sta->tid_rx[i];
sta->tid_rx[i] = NULL;
wil_tid_ampdu_rx_free(wil, r);
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+ spin_unlock_bh(&sta->tid_rx_lock);
}
for (i = 0; i < ARRAY_SIZE(wil->vring_tx); i++) {
if (wil->vring2cid_tid[i][0] == cid)
@@ -188,34 +192,47 @@ static void _wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
struct wireless_dev *wdev = wil->wdev;
might_sleep();
- if (bssid) {
+ wil_dbg_misc(wil, "%s(bssid=%pM, reason=%d, ev%s)\n", __func__, bssid,
+ reason_code, from_event ? "+" : "-");
+
+ /* Cases are:
+ * - disconnect single STA, still connected
+ * - disconnect single STA, already disconnected
+ * - disconnect all
+ *
+ * For "disconnect all", there are 2 options:
+ * - bssid == NULL
+ * - bssid is our MAC address
+ */
+ if (bssid && memcmp(ndev->dev_addr, bssid, ETH_ALEN)) {
cid = wil_find_cid(wil, bssid);
- wil_dbg_misc(wil, "%s(%pM, CID %d)\n", __func__, bssid, cid);
- } else {
- wil_dbg_misc(wil, "%s(all)\n", __func__);
- }
-
- if (cid >= 0) /* disconnect 1 peer */
- wil_disconnect_cid(wil, cid, reason_code, from_event);
- else /* disconnect all */
+ wil_dbg_misc(wil, "Disconnect %pM, CID=%d, reason=%d\n",
+ bssid, cid, reason_code);
+ if (cid >= 0) /* disconnect 1 peer */
+ wil_disconnect_cid(wil, cid, reason_code, from_event);
+ } else { /* all */
+ wil_dbg_misc(wil, "Disconnect all\n");
for (cid = 0; cid < WIL6210_MAX_CID; cid++)
wil_disconnect_cid(wil, cid, reason_code, from_event);
+ }
/* link state */
switch (wdev->iftype) {
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_P2P_CLIENT:
- wil_link_off(wil);
- if (test_bit(wil_status_fwconnected, &wil->status)) {
- clear_bit(wil_status_fwconnected, &wil->status);
+ netif_tx_stop_all_queues(ndev);
+ netif_carrier_off(ndev);
+
+ if (test_bit(wil_status_fwconnected, wil->status)) {
+ clear_bit(wil_status_fwconnected, wil->status);
cfg80211_disconnected(ndev, reason_code,
NULL, 0, GFP_KERNEL);
- } else if (test_bit(wil_status_fwconnecting, &wil->status)) {
+ } else if (test_bit(wil_status_fwconnecting, wil->status)) {
cfg80211_connect_result(ndev, bssid, NULL, 0, NULL, 0,
WLAN_STATUS_UNSPECIFIED_FAILURE,
GFP_KERNEL);
}
- clear_bit(wil_status_fwconnecting, &wil->status);
+ clear_bit(wil_status_fwconnecting, wil->status);
break;
default:
break;
@@ -248,7 +265,7 @@ static void wil_scan_timer_fn(ulong x)
{
struct wil6210_priv *wil = (void *)x;
- clear_bit(wil_status_fwready, &wil->status);
+ clear_bit(wil_status_fwready, wil->status);
wil_err(wil, "Scan timeout detected, start fw error recovery\n");
wil->recovery_state = fw_recovery_pending;
schedule_work(&wil->fw_error_worker);
@@ -352,6 +369,8 @@ static void wil_connect_worker(struct work_struct *work)
int rc;
struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
connect_worker);
+ struct net_device *ndev = wil_to_ndev(wil);
+
int cid = wil->pending_connect_cid;
int ringid = wil_find_free_vring(wil);
@@ -366,7 +385,7 @@ static void wil_connect_worker(struct work_struct *work)
wil->pending_connect_cid = -1;
if (rc == 0) {
wil->sta[cid].status = wil_sta_connected;
- wil_link_on(wil);
+ netif_tx_wake_all_queues(ndev);
} else {
wil->sta[cid].status = wil_sta_unused;
}
@@ -384,6 +403,9 @@ int wil_priv_init(struct wil6210_priv *wil)
mutex_init(&wil->mutex);
mutex_init(&wil->wmi_mutex);
+ mutex_init(&wil->back_rx_mutex);
+ mutex_init(&wil->back_tx_mutex);
+ mutex_init(&wil->probe_client_mutex);
init_completion(&wil->wmi_ready);
init_completion(&wil->wmi_call);
@@ -396,25 +418,39 @@ int wil_priv_init(struct wil6210_priv *wil)
INIT_WORK(&wil->disconnect_worker, wil_disconnect_worker);
INIT_WORK(&wil->wmi_event_worker, wmi_event_worker);
INIT_WORK(&wil->fw_error_worker, wil_fw_error_worker);
+ INIT_WORK(&wil->back_rx_worker, wil_back_rx_worker);
+ INIT_WORK(&wil->back_tx_worker, wil_back_tx_worker);
+ INIT_WORK(&wil->probe_client_worker, wil_probe_client_worker);
INIT_LIST_HEAD(&wil->pending_wmi_ev);
+ INIT_LIST_HEAD(&wil->back_rx_pending);
+ INIT_LIST_HEAD(&wil->back_tx_pending);
+ INIT_LIST_HEAD(&wil->probe_client_pending);
spin_lock_init(&wil->wmi_ev_lock);
init_waitqueue_head(&wil->wq);
- wil->wmi_wq = create_singlethread_workqueue(WIL_NAME"_wmi");
+ wil->wmi_wq = create_singlethread_workqueue(WIL_NAME "_wmi");
if (!wil->wmi_wq)
return -EAGAIN;
- wil->wmi_wq_conn = create_singlethread_workqueue(WIL_NAME"_connect");
- if (!wil->wmi_wq_conn) {
- destroy_workqueue(wil->wmi_wq);
- return -EAGAIN;
- }
+ wil->wq_service = create_singlethread_workqueue(WIL_NAME "_service");
+ if (!wil->wq_service)
+ goto out_wmi_wq;
wil->last_fw_recovery = jiffies;
- wil->itr_trsh = itr_trsh;
+ wil->tx_interframe_timeout = WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT;
+ wil->rx_interframe_timeout = WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT;
+ wil->tx_max_burst_duration = WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT;
+ wil->rx_max_burst_duration = WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT;
+ if (rx_ring_overflow_thrsh == WIL6210_RX_HIGH_TRSH_INIT)
+ rx_ring_overflow_thrsh = WIL6210_RX_HIGH_TRSH_DEFAULT;
return 0;
+
+out_wmi_wq:
+ destroy_workqueue(wil->wmi_wq);
+
+ return -EAGAIN;
}
/**
@@ -448,7 +484,13 @@ void wil_priv_deinit(struct wil6210_priv *wil)
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
mutex_unlock(&wil->mutex);
wmi_event_flush(wil);
- destroy_workqueue(wil->wmi_wq_conn);
+ wil_back_rx_flush(wil);
+ cancel_work_sync(&wil->back_rx_worker);
+ wil_back_tx_flush(wil);
+ cancel_work_sync(&wil->back_tx_worker);
+ wil_probe_client_flush(wil);
+ cancel_work_sync(&wil->probe_client_worker);
+ destroy_workqueue(wil->wq_service);
destroy_workqueue(wil->wmi_wq);
}
@@ -478,13 +520,10 @@ static int wil_target_reset(struct wil6210_priv *wil)
{
int delay = 0;
u32 x;
- u32 rev_id;
- bool is_sparrow = (wil->board->board == WIL_BOARD_SPARROW);
+ bool is_reset_v2 = test_bit(hw_capability_reset_v2,
+ wil->hw_capabilities);
- wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->board->name);
-
- wil->hw_version = R(RGF_USER_FW_REV_ID);
- rev_id = wil->hw_version & 0xff;
+ wil_dbg_misc(wil, "Resetting \"%s\"...\n", wil->hw_name);
/* Clear MAC link up */
S(RGF_HP_CTRL, BIT(15));
@@ -496,7 +535,7 @@ static int wil_target_reset(struct wil6210_priv *wil)
/* Clear Fw Download notification */
C(RGF_USER_USAGE_6, BIT(0));
- if (is_sparrow) {
+ if (is_reset_v2) {
S(RGF_CAF_OSC_CONTROL, BIT_CAF_OSC_XTAL_EN);
/* XTAL stabilization should take about 3ms */
usleep_range(5000, 7000);
@@ -517,10 +556,11 @@ static int wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0xFE000000);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0x0000003F);
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, is_sparrow ? 0x000000f0 : 0x00000170);
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_3,
+ is_reset_v2 ? 0x000000f0 : 0x00000170);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0xFFE7FE00);
- if (is_sparrow) {
+ if (is_reset_v2) {
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_0, 0x0);
W(RGF_USER_CLKS_CTL_EXT_SW_RST_VEC_1, 0x0);
}
@@ -530,19 +570,14 @@ static int wil_target_reset(struct wil6210_priv *wil)
W(RGF_USER_CLKS_CTL_SW_RST_VEC_1, 0);
W(RGF_USER_CLKS_CTL_SW_RST_VEC_0, 0);
- if (is_sparrow) {
+ if (is_reset_v2) {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000003);
/* reset A2 PCIE AHB */
W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
} else {
W(RGF_USER_CLKS_CTL_SW_RST_VEC_3, 0x00000001);
- if (rev_id == 1) {
- /* reset A1 BOTH PCIE AHB & PCIE RGF */
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00000080);
- } else {
- W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
- W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
- }
+ W(RGF_PCIE_LOS_COUNTER_CTL, BIT(6) | BIT(8));
+ W(RGF_USER_CLKS_CTL_SW_RST_VEC_2, 0x00008000);
}
/* TODO: check order here!!! Erez code is different */
@@ -559,8 +594,7 @@ static int wil_target_reset(struct wil6210_priv *wil)
}
} while (x != HW_MACHINE_BOOT_DONE);
- /* TODO: Erez check rev_id != 1 */
- if (!is_sparrow && (rev_id != 1))
+ if (!is_reset_v2)
W(RGF_PCIE_LOS_COUNTER_CTL, BIT(8));
C(RGF_USER_CLKS_CTL_0, BIT_USER_CLKS_RST_PWGD);
@@ -569,26 +603,6 @@ static int wil_target_reset(struct wil6210_priv *wil)
return 0;
}
-/**
- * wil_set_itr_trsh: - apply interrupt coalescing params
- */
-void wil_set_itr_trsh(struct wil6210_priv *wil)
-{
- /* disable, use usec resolution */
- W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EXT_TICK);
-
- /* disable interrupt moderation for monitor
- * to get better timestamp precision
- */
- if (wil->wdev->iftype == NL80211_IFTYPE_MONITOR)
- return;
-
- wil_info(wil, "set ITR_TRSH = %d usec\n", wil->itr_trsh);
- W(RGF_DMA_ITR_CNT_TRSH, wil->itr_trsh);
- W(RGF_DMA_ITR_CNT_CRL, BIT_DMA_ITR_CNT_CRL_EN |
- BIT_DMA_ITR_CNT_CRL_EXT_TICK); /* start it */
-}
-
#undef R
#undef W
#undef S
@@ -629,13 +643,17 @@ int wil_reset(struct wil6210_priv *wil)
wil_dbg_misc(wil, "%s()\n", __func__);
+ if (wil->hw_version == HW_VER_UNKNOWN)
+ return -ENODEV;
+
WARN_ON(!mutex_is_locked(&wil->mutex));
- WARN_ON(test_bit(wil_status_napi_en, &wil->status));
+ WARN_ON(test_bit(wil_status_napi_en, wil->status));
cancel_work_sync(&wil->disconnect_worker);
wil6210_disconnect(wil, NULL, WLAN_REASON_DEAUTH_LEAVING, false);
- wil->status = 0; /* prevent NAPI from being scheduled */
+ /* prevent NAPI from being scheduled */
+ bitmap_zero(wil->status, wil_status_last);
if (wil->scan_request) {
wil_dbg_misc(wil, "Abort scan_request 0x%p\n",
@@ -649,7 +667,7 @@ int wil_reset(struct wil6210_priv *wil)
wmi_event_flush(wil);
- flush_workqueue(wil->wmi_wq_conn);
+ flush_workqueue(wil->wq_service);
flush_workqueue(wil->wmi_wq);
rc = wil_target_reset(wil);
@@ -688,6 +706,7 @@ int wil_reset(struct wil6210_priv *wil)
reinit_completion(&wil->wmi_ready);
reinit_completion(&wil->wmi_call);
+ wil_configure_interrupt_moderation(wil);
wil_unmask_irq(wil);
/* we just started MAC, wait for FW ready */
@@ -703,28 +722,6 @@ void wil_fw_error_recovery(struct wil6210_priv *wil)
schedule_work(&wil->fw_error_worker);
}
-void wil_link_on(struct wil6210_priv *wil)
-{
- struct net_device *ndev = wil_to_ndev(wil);
-
- wil_dbg_misc(wil, "%s()\n", __func__);
-
- netif_carrier_on(ndev);
- wil_dbg_misc(wil, "netif_tx_wake : link on\n");
- netif_tx_wake_all_queues(ndev);
-}
-
-void wil_link_off(struct wil6210_priv *wil)
-{
- struct net_device *ndev = wil_to_ndev(wil);
-
- wil_dbg_misc(wil, "%s()\n", __func__);
-
- netif_tx_stop_all_queues(ndev);
- wil_dbg_misc(wil, "netif_tx_stop : link off\n");
- netif_carrier_off(ndev);
-}
-
int __wil_up(struct wil6210_priv *wil)
{
struct net_device *ndev = wil_to_ndev(wil);
@@ -774,7 +771,7 @@ int __wil_up(struct wil6210_priv *wil)
wil_dbg_misc(wil, "NAPI enable\n");
napi_enable(&wil->napi_rx);
napi_enable(&wil->napi_tx);
- set_bit(wil_status_napi_en, &wil->status);
+ set_bit(wil_status_napi_en, wil->status);
if (wil->platform_ops.bus_request)
wil->platform_ops.bus_request(wil->platform_handle,
@@ -807,7 +804,7 @@ int __wil_down(struct wil6210_priv *wil)
wil->platform_ops.bus_request(wil->platform_handle, 0);
wil_disable_irq(wil);
- if (test_and_clear_bit(wil_status_napi_en, &wil->status)) {
+ if (test_and_clear_bit(wil_status_napi_en, wil->status)) {
napi_disable(&wil->napi_rx);
napi_disable(&wil->napi_tx);
wil_dbg_misc(wil, "NAPI disable\n");
@@ -822,15 +819,15 @@ int __wil_down(struct wil6210_priv *wil)
wil->scan_request = NULL;
}
- if (test_bit(wil_status_fwconnected, &wil->status) ||
- test_bit(wil_status_fwconnecting, &wil->status))
+ if (test_bit(wil_status_fwconnected, wil->status) ||
+ test_bit(wil_status_fwconnecting, wil->status))
wmi_send(wil, WMI_DISCONNECT_CMDID, NULL, 0);
/* make sure wil is idle (not connected) */
mutex_unlock(&wil->mutex);
while (iter--) {
- int idle = !test_bit(wil_status_fwconnected, &wil->status) &&
- !test_bit(wil_status_fwconnecting, &wil->status);
+ int idle = !test_bit(wil_status_fwconnected, wil->status) &&
+ !test_bit(wil_status_fwconnecting, wil->status);
if (idle)
break;
msleep(WAIT_FOR_DISCONNECT_INTERVAL_MS);
diff --git a/drivers/net/wireless/ath/wil6210/netdev.c b/drivers/net/wireless/ath/wil6210/netdev.c
index e81703ca7701..ace30c1b5c64 100644
--- a/drivers/net/wireless/ath/wil6210/netdev.c
+++ b/drivers/net/wireless/ath/wil6210/netdev.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -15,7 +15,6 @@
*/
#include <linux/etherdevice.h>
-
#include "wil6210.h"
#include "txrx.h"
@@ -122,6 +121,12 @@ static int wil6210_netdev_poll_tx(struct napi_struct *napi, int budget)
return min(tx_done, budget);
}
+static void wil_dev_setup(struct net_device *dev)
+{
+ ether_setup(dev);
+ dev->tx_queue_len = WIL_TX_Q_LEN_DEFAULT;
+}
+
void *wil_if_alloc(struct device *dev, void __iomem *csr)
{
struct net_device *ndev;
@@ -153,7 +158,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
ch = wdev->wiphy->bands[IEEE80211_BAND_60GHZ]->channels;
cfg80211_chandef_create(&wdev->preset_chandef, ch, NL80211_CHAN_NO_HT);
- ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, ether_setup);
+ ndev = alloc_netdev(0, "wlan%d", NET_NAME_UNKNOWN, wil_dev_setup);
if (!ndev) {
dev_err(dev, "alloc_netdev_mqs failed\n");
rc = -ENOMEM;
@@ -174,7 +179,7 @@ void *wil_if_alloc(struct device *dev, void __iomem *csr)
netif_napi_add(ndev, &wil->napi_tx, wil6210_netdev_poll_tx,
WIL6210_NAPI_BUDGET);
- wil_link_off(wil);
+ netif_tx_stop_all_queues(ndev);
return wil;
@@ -217,8 +222,6 @@ int wil_if_add(struct wil6210_priv *wil)
return rc;
}
- wil_link_off(wil);
-
return 0;
}
diff --git a/drivers/net/wireless/ath/wil6210/pcie_bus.c b/drivers/net/wireless/ath/wil6210/pcie_bus.c
index 66626a8ee728..3dd26709ccb2 100644
--- a/drivers/net/wireless/ath/wil6210/pcie_bus.c
+++ b/drivers/net/wireless/ath/wil6210/pcie_bus.c
@@ -31,6 +31,46 @@ static bool debug_fw; /* = false; */
module_param(debug_fw, bool, S_IRUGO);
MODULE_PARM_DESC(debug_fw, " load driver if FW not ready. For FW debug");
+static
+void wil_set_capabilities(struct wil6210_priv *wil)
+{
+ u32 rev_id = ioread32(wil->csr + HOSTADDR(RGF_USER_JTAG_DEV_ID));
+
+ bitmap_zero(wil->hw_capabilities, hw_capability_last);
+
+ switch (rev_id) {
+ case JTAG_DEV_ID_MARLON_B0:
+ wil->hw_name = "Marlon B0";
+ wil->hw_version = HW_VER_MARLON_B0;
+ break;
+ case JTAG_DEV_ID_SPARROW_A0:
+ wil->hw_name = "Sparrow A0";
+ wil->hw_version = HW_VER_SPARROW_A0;
+ break;
+ case JTAG_DEV_ID_SPARROW_A1:
+ wil->hw_name = "Sparrow A1";
+ wil->hw_version = HW_VER_SPARROW_A1;
+ break;
+ case JTAG_DEV_ID_SPARROW_B0:
+ wil->hw_name = "Sparrow B0";
+ wil->hw_version = HW_VER_SPARROW_B0;
+ break;
+ default:
+ wil_err(wil, "Unknown board hardware 0x%08x\n", rev_id);
+ wil->hw_name = "Unknown";
+ wil->hw_version = HW_VER_UNKNOWN;
+ }
+
+ wil_info(wil, "Board hardware is %s\n", wil->hw_name);
+
+ if (wil->hw_version >= HW_VER_SPARROW_A0)
+ set_bit(hw_capability_reset_v2, wil->hw_capabilities);
+
+ if (wil->hw_version >= HW_VER_SPARROW_B0)
+ set_bit(hw_capability_advanced_itr_moderation,
+ wil->hw_capabilities);
+}
+
void wil_disable_irq(struct wil6210_priv *wil)
{
int irq = wil->pdev->irq;
@@ -149,12 +189,11 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
struct wil6210_priv *wil;
struct device *dev = &pdev->dev;
void __iomem *csr;
- struct wil_board *board = (struct wil_board *)id->driver_data;
int rc;
/* check HW */
dev_info(&pdev->dev, WIL_NAME
- " \"%s\" device found [%04x:%04x] (rev %x)\n", board->name,
+ " device found [%04x:%04x] (rev %x)\n",
(int)pdev->vendor, (int)pdev->device, (int)pdev->revision);
if (pci_resource_len(pdev, 0) != WIL6210_MEM_SIZE) {
@@ -204,8 +243,7 @@ static int wil_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_set_drvdata(pdev, wil);
wil->pdev = pdev;
- wil->board = board;
-
+ wil_set_capabilities(wil);
wil6210_clear_irq(wil);
wil->platform_handle =
@@ -266,23 +304,10 @@ static void wil_pcie_remove(struct pci_dev *pdev)
pci_disable_device(pdev);
}
-static const struct wil_board wil_board_marlon = {
- .board = WIL_BOARD_MARLON,
- .name = "marlon",
-};
-
-static const struct wil_board wil_board_sparrow = {
- .board = WIL_BOARD_SPARROW,
- .name = "sparrow",
-};
-
static const struct pci_device_id wil6210_pcie_ids[] = {
- { PCI_DEVICE(0x1ae9, 0x0301),
- .driver_data = (kernel_ulong_t)&wil_board_marlon },
- { PCI_DEVICE(0x1ae9, 0x0310),
- .driver_data = (kernel_ulong_t)&wil_board_sparrow },
- { PCI_DEVICE(0x1ae9, 0x0302), /* same as above, firmware broken */
- .driver_data = (kernel_ulong_t)&wil_board_sparrow },
+ { PCI_DEVICE(0x1ae9, 0x0301) },
+ { PCI_DEVICE(0x1ae9, 0x0310) },
+ { PCI_DEVICE(0x1ae9, 0x0302) }, /* same as above, firmware broken */
{ /* end: all zeroes */ },
};
MODULE_DEVICE_TABLE(pci, wil6210_pcie_ids);
diff --git a/drivers/net/wireless/ath/wil6210/rx_reorder.c b/drivers/net/wireless/ath/wil6210/rx_reorder.c
index 489cb73d139b..ca10dcf0986e 100644
--- a/drivers/net/wireless/ath/wil6210/rx_reorder.c
+++ b/drivers/net/wireless/ath/wil6210/rx_reorder.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -89,7 +89,9 @@ static void wil_reorder_release(struct wil6210_priv *wil,
}
}
+/* called in NAPI context */
void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
{
struct net_device *ndev = wil_to_ndev(wil);
struct vring_rx_desc *d = wil_skb_rxdesc(skb);
@@ -97,22 +99,26 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
int cid = wil_rxdesc_cid(d);
int mid = wil_rxdesc_mid(d);
u16 seq = wil_rxdesc_seq(d);
+ int mcast = wil_rxdesc_mcast(d);
struct wil_sta_info *sta = &wil->sta[cid];
struct wil_tid_ampdu_rx *r;
u16 hseq;
int index;
- unsigned long flags;
- wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x\n",
- mid, cid, tid, seq);
+ wil_dbg_txrx(wil, "MID %d CID %d TID %d Seq 0x%03x mcast %01x\n",
+ mid, cid, tid, seq, mcast);
- spin_lock_irqsave(&sta->tid_rx_lock, flags);
+ if (unlikely(mcast)) {
+ wil_netif_rx_any(skb, ndev);
+ return;
+ }
+
+ spin_lock(&sta->tid_rx_lock);
r = sta->tid_rx[tid];
if (!r) {
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
wil_netif_rx_any(skb, ndev);
- return;
+ goto out;
}
hseq = r->head_seq_num;
@@ -121,13 +127,24 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
* reported, and data Rx, few packets may be pass up before reorder
* buffer get allocated. Catch up by pretending SSN is what we
* see in the 1-st Rx packet
+ *
+ * Another scenario, Rx get delayed and we got packet from before
+ * BACK. Pass it to the stack and wait.
*/
if (r->first_time) {
r->first_time = false;
if (seq != r->head_seq_num) {
- wil_err(wil, "Error: 1-st frame with wrong sequence"
- " %d, should be %d. Fixing...\n", seq,
- r->head_seq_num);
+ if (seq_less(seq, r->head_seq_num)) {
+ wil_err(wil,
+ "Error: frame with early sequence 0x%03x, should be 0x%03x. Waiting...\n",
+ seq, r->head_seq_num);
+ r->first_time = true;
+ wil_netif_rx_any(skb, ndev);
+ goto out;
+ }
+ wil_err(wil,
+ "Error: 1-st frame with wrong sequence 0x%03x, should be 0x%03x. Fixing...\n",
+ seq, r->head_seq_num);
r->head_seq_num = seq;
r->ssn = seq;
}
@@ -179,7 +196,7 @@ void wil_rx_reorder(struct wil6210_priv *wil, struct sk_buff *skb)
wil_reorder_release(wil, r);
out:
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+ spin_unlock(&sta->tid_rx_lock);
}
struct wil_tid_ampdu_rx *wil_tid_ampdu_rx_alloc(struct wil6210_priv *wil,
@@ -219,3 +236,241 @@ void wil_tid_ampdu_rx_free(struct wil6210_priv *wil,
kfree(r->reorder_time);
kfree(r);
}
+
+/* ADDBA processing */
+static u16 wil_agg_size(struct wil6210_priv *wil, u16 req_agg_wsize)
+{
+ u16 max_agg_size = min_t(u16, WIL_MAX_AGG_WSIZE, WIL_MAX_AMPDU_SIZE /
+ (mtu_max + WIL_MAX_MPDU_OVERHEAD));
+
+ if (!req_agg_wsize)
+ return max_agg_size;
+
+ return min(max_agg_size, req_agg_wsize);
+}
+
+/* Block Ack - Rx side (recipient */
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
+ u8 dialog_token, __le16 ba_param_set,
+ __le16 ba_timeout, __le16 ba_seq_ctrl)
+{
+ struct wil_back_rx *req = kzalloc(sizeof(*req), GFP_KERNEL);
+
+ if (!req)
+ return -ENOMEM;
+
+ req->cidxtid = cidxtid;
+ req->dialog_token = dialog_token;
+ req->ba_param_set = le16_to_cpu(ba_param_set);
+ req->ba_timeout = le16_to_cpu(ba_timeout);
+ req->ba_seq_ctrl = le16_to_cpu(ba_seq_ctrl);
+
+ mutex_lock(&wil->back_rx_mutex);
+ list_add_tail(&req->list, &wil->back_rx_pending);
+ mutex_unlock(&wil->back_rx_mutex);
+
+ queue_work(wil->wq_service, &wil->back_rx_worker);
+
+ return 0;
+}
+
+static void wil_back_rx_handle(struct wil6210_priv *wil,
+ struct wil_back_rx *req)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
+{
+ struct wil_sta_info *sta;
+ u8 cid, tid;
+ u16 agg_wsize = 0;
+ /* bit 0: A-MSDU supported
+ * bit 1: policy (should be 0 for us)
+ * bits 2..5: TID
+ * bits 6..15: buffer size
+ */
+ u16 req_agg_wsize = WIL_GET_BITS(req->ba_param_set, 6, 15);
+ bool agg_amsdu = !!(req->ba_param_set & BIT(0));
+ int ba_policy = req->ba_param_set & BIT(1);
+ u16 agg_timeout = req->ba_timeout;
+ u16 status = WLAN_STATUS_SUCCESS;
+ u16 ssn = req->ba_seq_ctrl >> 4;
+ struct wil_tid_ampdu_rx *r;
+ int rc;
+
+ might_sleep();
+ parse_cidxtid(req->cidxtid, &cid, &tid);
+
+ /* sanity checks */
+ if (cid >= WIL6210_MAX_CID) {
+ wil_err(wil, "BACK: invalid CID %d\n", cid);
+ return;
+ }
+
+ sta = &wil->sta[cid];
+ if (sta->status != wil_sta_connected) {
+ wil_err(wil, "BACK: CID %d not connected\n", cid);
+ return;
+ }
+
+ wil_dbg_wmi(wil,
+ "ADDBA request for CID %d %pM TID %d size %d timeout %d AMSDU%s policy %d token %d SSN 0x%03x\n",
+ cid, sta->addr, tid, req_agg_wsize, req->ba_timeout,
+ agg_amsdu ? "+" : "-", !!ba_policy, req->dialog_token, ssn);
+
+ /* apply policies */
+ if (ba_policy) {
+ wil_err(wil, "BACK requested unsupported ba_policy == 1\n");
+ status = WLAN_STATUS_INVALID_QOS_PARAM;
+ }
+ if (status == WLAN_STATUS_SUCCESS)
+ agg_wsize = wil_agg_size(wil, req_agg_wsize);
+
+ rc = wmi_addba_rx_resp(wil, cid, tid, req->dialog_token, status,
+ agg_amsdu, agg_wsize, agg_timeout);
+ if (rc || (status != WLAN_STATUS_SUCCESS))
+ return;
+
+ /* apply */
+ r = wil_tid_ampdu_rx_alloc(wil, agg_wsize, ssn);
+ spin_lock_bh(&sta->tid_rx_lock);
+ wil_tid_ampdu_rx_free(wil, sta->tid_rx[tid]);
+ sta->tid_rx[tid] = r;
+ spin_unlock_bh(&sta->tid_rx_lock);
+}
+
+void wil_back_rx_flush(struct wil6210_priv *wil)
+{
+ struct wil_back_rx *evt, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->back_rx_mutex);
+
+ list_for_each_entry_safe(evt, t, &wil->back_rx_pending, list) {
+ list_del(&evt->list);
+ kfree(evt);
+ }
+
+ mutex_unlock(&wil->back_rx_mutex);
+}
+
+/* Retrieve next ADDBA request from the pending list */
+static struct list_head *next_back_rx(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->back_rx_mutex);
+
+ if (!list_empty(&wil->back_rx_pending)) {
+ ret = wil->back_rx_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->back_rx_mutex);
+
+ return ret;
+}
+
+void wil_back_rx_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ back_rx_worker);
+ struct wil_back_rx *evt;
+ struct list_head *lh;
+
+ while ((lh = next_back_rx(wil)) != NULL) {
+ evt = list_entry(lh, struct wil_back_rx, list);
+
+ wil_back_rx_handle(wil, evt);
+ kfree(evt);
+ }
+}
+
+/* BACK - Tx (originator) side */
+static void wil_back_tx_handle(struct wil6210_priv *wil,
+ struct wil_back_tx *req)
+{
+ struct vring_tx_data *txdata = &wil->vring_tx_data[req->ringid];
+ int rc;
+
+ if (txdata->addba_in_progress) {
+ wil_dbg_misc(wil, "ADDBA for vring[%d] already in progress\n",
+ req->ringid);
+ return;
+ }
+ if (txdata->agg_wsize) {
+ wil_dbg_misc(wil,
+ "ADDBA for vring[%d] already established wsize %d\n",
+ req->ringid, txdata->agg_wsize);
+ return;
+ }
+ txdata->addba_in_progress = true;
+ rc = wmi_addba(wil, req->ringid, req->agg_wsize, req->agg_timeout);
+ if (rc)
+ txdata->addba_in_progress = false;
+}
+
+static struct list_head *next_back_tx(struct wil6210_priv *wil)
+{
+ struct list_head *ret = NULL;
+
+ mutex_lock(&wil->back_tx_mutex);
+
+ if (!list_empty(&wil->back_tx_pending)) {
+ ret = wil->back_tx_pending.next;
+ list_del(ret);
+ }
+
+ mutex_unlock(&wil->back_tx_mutex);
+
+ return ret;
+}
+
+void wil_back_tx_worker(struct work_struct *work)
+{
+ struct wil6210_priv *wil = container_of(work, struct wil6210_priv,
+ back_tx_worker);
+ struct wil_back_tx *evt;
+ struct list_head *lh;
+
+ while ((lh = next_back_tx(wil)) != NULL) {
+ evt = list_entry(lh, struct wil_back_tx, list);
+
+ wil_back_tx_handle(wil, evt);
+ kfree(evt);
+ }
+}
+
+void wil_back_tx_flush(struct wil6210_priv *wil)
+{
+ struct wil_back_tx *evt, *t;
+
+ wil_dbg_misc(wil, "%s()\n", __func__);
+
+ mutex_lock(&wil->back_tx_mutex);
+
+ list_for_each_entry_safe(evt, t, &wil->back_tx_pending, list) {
+ list_del(&evt->list);
+ kfree(evt);
+ }
+
+ mutex_unlock(&wil->back_tx_mutex);
+}
+
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize)
+{
+ struct wil_back_tx *req = kzalloc(sizeof(*req), GFP_KERNEL);
+
+ if (!req)
+ return -ENOMEM;
+
+ req->ringid = ringid;
+ req->agg_wsize = wil_agg_size(wil, wsize);
+ req->agg_timeout = 0;
+
+ mutex_lock(&wil->back_tx_mutex);
+ list_add_tail(&req->list, &wil->back_tx_pending);
+ mutex_unlock(&wil->back_tx_mutex);
+
+ queue_work(wil->wq_service, &wil->back_tx_worker);
+
+ return 0;
+}
diff --git a/drivers/net/wireless/ath/wil6210/txrx.c b/drivers/net/wireless/ath/wil6210/txrx.c
index e3f8bdce5abc..8439f65db259 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.c
+++ b/drivers/net/wireless/ath/wil6210/txrx.c
@@ -463,7 +463,7 @@ static struct sk_buff *wil_vring_reap_rx(struct wil6210_priv *wil,
* and in case of error drop the packet
* higher stack layers will handle retransmission (if required)
*/
- if (d->dma.status & RX_DMA_STATUS_L4_IDENT) {
+ if (d->dma.status & RX_DMA_STATUS_L4I) {
/* L4 protocol identified, csum calculated */
if ((d->dma.error & RX_DMA_ERROR_L4_ERR) == 0)
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -581,14 +581,8 @@ void wil_rx_handle(struct wil6210_priv *wil, int *quota)
skb->protocol = htons(ETH_P_802_2);
wil_netif_rx_any(skb, ndev);
} else {
- struct ethhdr *eth = (void *)skb->data;
-
skb->protocol = eth_type_trans(skb, ndev);
-
- if (is_unicast_ether_addr(eth->h_dest))
- wil_rx_reorder(wil, skb);
- else
- wil_netif_rx_any(skb, ndev);
+ wil_rx_reorder(wil, skb);
}
}
wil_rx_refill(wil, v->size);
@@ -645,7 +639,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.vring_cfg = {
.tx_sw_ring = {
.max_mpdu_size =
- cpu_to_le16(mtu_max + ETH_HLEN),
+ cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.ring_size = cpu_to_le16(size),
},
.ringid = id,
@@ -653,7 +647,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
.encap_trans_type = WMI_VRING_ENC_TYPE_802_3,
.mac_ctrl = 0,
.to_resolution = 0,
- .agg_max_wsize = 16,
+ .agg_max_wsize = 0,
.schd_params = {
.priority = cpu_to_le16(0),
.timeslot_us = cpu_to_le16(0xfff),
@@ -677,6 +671,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
}
memset(txdata, 0, sizeof(*txdata));
+ spin_lock_init(&txdata->lock);
vring->size = size;
rc = wil_vring_alloc(wil, vring);
if (rc)
@@ -701,6 +696,8 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
vring->hwtail = le32_to_cpu(reply.cmd.tx_vring_tail_ptr);
txdata->enabled = 1;
+ if (wil->sta[cid].data_port_open && (agg_wsize >= 0))
+ wil_addba_tx_request(wil, id, agg_wsize);
return 0;
out_free:
@@ -713,6 +710,7 @@ int wil_vring_init_tx(struct wil6210_priv *wil, int id, int size,
void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
{
struct vring *vring = &wil->vring_tx[id];
+ struct vring_tx_data *txdata = &wil->vring_tx_data[id];
WARN_ON(!mutex_is_locked(&wil->mutex));
@@ -721,12 +719,15 @@ void wil_vring_fini_tx(struct wil6210_priv *wil, int id)
wil_dbg_misc(wil, "%s() id=%d\n", __func__, id);
+ spin_lock_bh(&txdata->lock);
+ txdata->enabled = 0; /* no Tx can be in progress or start anew */
+ spin_unlock_bh(&txdata->lock);
/* make sure NAPI won't touch this vring */
- wil->vring_tx_data[id].enabled = 0;
- if (test_bit(wil_status_napi_en, &wil->status))
+ if (test_bit(wil_status_napi_en, wil->status))
napi_synchronize(&wil->napi_tx);
wil_vring_free(wil, vring, 1);
+ memset(txdata, 0, sizeof(*txdata));
}
static struct vring *wil_find_tx_vring(struct wil6210_priv *wil,
@@ -773,6 +774,38 @@ static void wil_set_da_for_vring(struct wil6210_priv *wil,
static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
struct sk_buff *skb);
+
+static struct vring *wil_find_tx_vring_sta(struct wil6210_priv *wil,
+ struct sk_buff *skb)
+{
+ struct vring *v;
+ int i;
+ u8 cid;
+
+ /* In the STA mode, it is expected to have only 1 VRING
+ * for the AP we connected to.
+ * find 1-st vring and see whether it is eligible for data
+ */
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ v = &wil->vring_tx[i];
+ if (!v->va)
+ continue;
+
+ cid = wil->vring2cid_tid[i][0];
+ if (!wil->sta[cid].data_port_open &&
+ (skb->protocol != cpu_to_be16(ETH_P_PAE)))
+ break;
+
+ wil_dbg_txrx(wil, "Tx -> ring %d\n", i);
+
+ return v;
+ }
+
+ wil_dbg_txrx(wil, "Tx while no vrings active?\n");
+
+ return NULL;
+}
+
/*
* Find 1-st vring and return it; set dest address for this vring in skb
* duplicate skb and send it to other active vrings
@@ -843,9 +876,6 @@ static int wil_tx_desc_map(struct vring_tx_desc *d, dma_addr_t pa, u32 len,
d->mac.d[1] = 0;
d->mac.d[2] = 0;
d->mac.ucode_cmd = 0;
- /* use dst index 0 */
- d->mac.d[1] |= BIT(MAC_CFG_DESC_TX_1_DST_INDEX_EN_POS) |
- (0 << MAC_CFG_DESC_TX_1_DST_INDEX_POS);
/* translation type: 0 - bypass; 1 - 802.3; 2 - native wifi */
d->mac.d[2] = BIT(MAC_CFG_DESC_TX_2_SNAP_HDR_INSERTION_EN_POS) |
(1 << MAC_CFG_DESC_TX_2_L2_TRANSLATION_TYPE_POS);
@@ -908,8 +938,8 @@ static int wil_tx_desc_offload_cksum_set(struct wil6210_priv *wil,
return 0;
}
-static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
- struct sk_buff *skb)
+static int __wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+ struct sk_buff *skb)
{
struct device *dev = wil_to_dev(wil);
struct vring_tx_desc dd, *d = &dd;
@@ -925,18 +955,21 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_dbg_txrx(wil, "%s()\n", __func__);
+ if (unlikely(!txdata->enabled))
+ return -EINVAL;
+
if (avail < 1 + nr_frags) {
wil_err_ratelimited(wil,
- "Tx ring full. No space for %d fragments\n",
- 1 + nr_frags);
+ "Tx ring[%2d] full. No space for %d fragments\n",
+ vring_index, 1 + nr_frags);
return -ENOMEM;
}
_d = &vring->va[i].tx;
pa = dma_map_single(dev, skb->data, skb_headlen(skb), DMA_TO_DEVICE);
- wil_dbg_txrx(wil, "Tx skb %d bytes 0x%p -> %pad\n", skb_headlen(skb),
- skb->data, &pa);
+ wil_dbg_txrx(wil, "Tx[%2d] skb %d bytes 0x%p -> %pad\n", vring_index,
+ skb_headlen(skb), skb->data, &pa);
wil_hex_dump_txrx("Tx ", DUMP_PREFIX_OFFSET, 16, 1,
skb->data, skb_headlen(skb), false);
@@ -947,15 +980,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
wil_tx_desc_map(d, pa, skb_headlen(skb), vring_index);
/* Process TCP/UDP checksum offloading */
if (wil_tx_desc_offload_cksum_set(wil, d, skb)) {
- wil_err(wil, "VRING #%d Failed to set cksum, drop packet\n",
+ wil_err(wil, "Tx[%2d] Failed to set cksum, drop packet\n",
vring_index);
goto dma_error;
}
vring->ctx[i].nr_frags = nr_frags;
wil_tx_desc_set_nr_frags(d, nr_frags);
- if (nr_frags)
- *_d = *d;
/* middle segments */
for (; f < nr_frags; f++) {
@@ -963,6 +994,10 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
&skb_shinfo(skb)->frags[f];
int len = skb_frag_size(frag);
+ *_d = *d;
+ wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i);
+ wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4,
+ (const void *)d, sizeof(*d), false);
i = (swhead + f + 1) % vring->size;
_d = &vring->va[i].tx;
pa = skb_frag_dma_map(dev, frag, 0, skb_frag_size(frag),
@@ -976,13 +1011,15 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
* it will succeed here too
*/
wil_tx_desc_offload_cksum_set(wil, d, skb);
- *_d = *d;
}
/* for the last seg only */
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_EOP_POS);
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_MARK_WB_POS);
d->dma.d0 |= BIT(DMA_CFG_DESC_TX_0_CMD_DMA_IT_POS);
*_d = *d;
+ wil_dbg_txrx(wil, "Tx[%2d] desc[%4d]\n", vring_index, i);
+ wil_hex_dump_txrx("TxD ", DUMP_PREFIX_NONE, 32, 4,
+ (const void *)d, sizeof(*d), false);
/* hold reference to skb
* to prevent skb release before accounting
@@ -990,15 +1027,13 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
*/
vring->ctx[i].skb = skb_get(skb);
- wil_hex_dump_txrx("Tx ", DUMP_PREFIX_NONE, 32, 4,
- (const void *)d, sizeof(*d), false);
-
if (wil_vring_is_empty(vring)) /* performance monitoring */
txdata->idle += get_cycles() - txdata->last_idle;
/* advance swhead */
wil_vring_advance_head(vring, nr_frags + 1);
- wil_dbg_txrx(wil, "Tx swhead %d -> %d\n", swhead, vring->swhead);
+ wil_dbg_txrx(wil, "Tx[%2d] swhead %d -> %d\n", vring_index, swhead,
+ vring->swhead);
trace_wil6210_tx(vring_index, swhead, skb->len, nr_frags);
iowrite32(vring->swhead, wil->csr + HOSTADDR(vring->hwtail));
@@ -1025,6 +1060,19 @@ static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
return -EINVAL;
}
+static int wil_tx_vring(struct wil6210_priv *wil, struct vring *vring,
+ struct sk_buff *skb)
+{
+ int vring_index = vring - wil->vring_tx;
+ struct vring_tx_data *txdata = &wil->vring_tx_data[vring_index];
+ int rc;
+
+ spin_lock(&txdata->lock);
+ rc = __wil_tx_vring(wil, vring, skb);
+ spin_unlock(&txdata->lock);
+ return rc;
+}
+
netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
{
struct wil6210_priv *wil = ndev_to_wil(ndev);
@@ -1034,14 +1082,14 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
int rc;
wil_dbg_txrx(wil, "%s()\n", __func__);
- if (!test_bit(wil_status_fwready, &wil->status)) {
+ if (!test_bit(wil_status_fwready, wil->status)) {
if (!pr_once_fw) {
wil_err(wil, "FW not ready\n");
pr_once_fw = true;
}
goto drop;
}
- if (!test_bit(wil_status_fwconnected, &wil->status)) {
+ if (!test_bit(wil_status_fwconnected, wil->status)) {
wil_err(wil, "FW not connected\n");
goto drop;
}
@@ -1052,15 +1100,19 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
pr_once_fw = false;
/* find vring */
- if (is_unicast_ether_addr(eth->h_dest))
- vring = wil_find_tx_vring(wil, skb);
- else
- vring = wil_tx_bcast(wil, skb);
+ if (wil->wdev->iftype == NL80211_IFTYPE_STATION) {
+ /* in STA mode (ESS), all to same VRING */
+ vring = wil_find_tx_vring_sta(wil, skb);
+ } else { /* direct communication, find matching VRING */
+ if (is_unicast_ether_addr(eth->h_dest))
+ vring = wil_find_tx_vring(wil, skb);
+ else
+ vring = wil_tx_bcast(wil, skb);
+ }
if (!vring) {
wil_dbg_txrx(wil, "No Tx VRING found for %pM\n", eth->h_dest);
goto drop;
}
-
/* set up vring entry */
rc = wil_tx_vring(wil, vring, skb);
@@ -1087,6 +1139,22 @@ netdev_tx_t wil_start_xmit(struct sk_buff *skb, struct net_device *ndev)
return NET_XMIT_DROP;
}
+static inline bool wil_need_txstat(struct sk_buff *skb)
+{
+ struct ethhdr *eth = (void *)skb->data;
+
+ return is_unicast_ether_addr(eth->h_dest) && skb->sk &&
+ (skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS);
+}
+
+static inline void wil_consume_skb(struct sk_buff *skb, bool acked)
+{
+ if (unlikely(wil_need_txstat(skb)))
+ skb_complete_wifi_ack(skb, acked);
+ else
+ acked ? dev_consume_skb_any(skb) : dev_kfree_skb_any(skb);
+}
+
/**
* Clean up transmitted skb's from the Tx VRING
*
@@ -1147,10 +1215,10 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
trace_wil6210_tx_done(ringid, vring->swtail, dmalen,
d->dma.error);
wil_dbg_txrx(wil,
- "Tx[%3d] : %d bytes, status 0x%02x err 0x%02x\n",
- vring->swtail, dmalen, d->dma.status,
- d->dma.error);
- wil_hex_dump_txrx("TxC ", DUMP_PREFIX_NONE, 32, 4,
+ "TxC[%2d][%3d] : %d bytes, status 0x%02x err 0x%02x\n",
+ ringid, vring->swtail, dmalen,
+ d->dma.status, d->dma.error);
+ wil_hex_dump_txrx("TxCD ", DUMP_PREFIX_NONE, 32, 4,
(const void *)d, sizeof(*d), false);
wil_txdesc_unmap(dev, d, ctx);
@@ -1165,8 +1233,7 @@ int wil_tx_complete(struct wil6210_priv *wil, int ringid)
ndev->stats.tx_errors++;
stats->tx_errors++;
}
-
- dev_kfree_skb_any(skb);
+ wil_consume_skb(skb, d->dma.error == 0);
}
memset(ctx, 0, sizeof(*ctx));
/* There is no need to touch HW descriptor:
diff --git a/drivers/net/wireless/ath/wil6210/txrx.h b/drivers/net/wireless/ath/wil6210/txrx.h
index 630aeb5fa7f4..d90c8aa20c15 100644
--- a/drivers/net/wireless/ath/wil6210/txrx.h
+++ b/drivers/net/wireless/ath/wil6210/txrx.h
@@ -20,17 +20,15 @@
#define BUF_SW_OWNED (1)
#define BUF_HW_OWNED (0)
-/* size of max. Tx/Rx buffers, as supported by FW */
-#define TXRX_BUF_LEN_DEFAULT (2242)
+/* default size of MAC Tx/Rx buffers */
+#define TXRX_BUF_LEN_DEFAULT (2048)
/* how many bytes to reserve for rtap header? */
#define WIL6210_RTAP_SIZE (128)
/* Tx/Rx path */
-/*
- * Common representation of physical address in Vring
- */
+/* Common representation of physical address in Vring */
struct vring_dma_addr {
__le32 addr_low;
__le16 addr_high;
@@ -49,11 +47,10 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
addr->addr_high = cpu_to_le16((u16)upper_32_bits(pa));
}
-/*
- * Tx descriptor - MAC part
+/* Tx descriptor - MAC part
* [dword 0]
* bit 0.. 9 : lifetime_expiry_value:10
- * bit 10 : interrup_en:1
+ * bit 10 : interrupt_en:1
* bit 11 : status_en:1
* bit 12..13 : txss_override:2
* bit 14 : timestamp_insertion:1
@@ -61,15 +58,12 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* bit 16..21 : reserved0:6
* bit 22..26 : mcs_index:5
* bit 27 : mcs_en:1
- * bit 28..29 : reserved1:2
- * bit 30 : reserved2:1
+ * bit 28..30 : reserved1:3
* bit 31 : sn_preserved:1
* [dword 1]
* bit 0.. 3 : pkt_mode:4
* bit 4 : pkt_mode_en:1
- * bit 5.. 7 : reserved0:3
- * bit 8..13 : reserved1:6
- * bit 14 : reserved2:1
+ * bit 5..14 : reserved0:10
* bit 15 : ack_policy_en:1
* bit 16..19 : dst_index:4
* bit 20 : dst_index_en:1
@@ -80,7 +74,7 @@ static inline void wil_desc_addr_set(struct vring_dma_addr *addr,
* [dword 2]
* bit 0.. 7 : num_of_descriptors:8
* bit 8..17 : reserved:10
- * bit 18..19 : l2_translation_type:2
+ * bit 18..19 : l2_translation_type:2 00 - bypass, 01 - 802.3, 10 - 802.11
* bit 20 : snap_hdr_insertion_en:1
* bit 21 : vlan_removal_en:1
* bit 22..31 : reserved0:10
@@ -247,6 +241,46 @@ struct vring_tx_mac {
#define TX_DMA_STATUS_DU BIT(0)
+/* Tx descriptor - DMA part
+ * [dword 0]
+ * bit 0.. 7 : l4_length:8 layer 4 length
+ * bit 8 : cmd_eop:1 This descriptor is the last one in the packet
+ * bit 9 : reserved
+ * bit 10 : cmd_dma_it:1 immediate interrupt
+ * bit 11..12 : SBD - Segment Buffer Details
+ * 00 - Header Segment
+ * 01 - First Data Segment
+ * 10 - Medium Data Segment
+ * 11 - Last Data Segment
+ * bit 13 : TSE - TCP Segmentation Enable
+ * bit 14 : IIC - Directs the HW to Insert IPv4 Checksum
+ * bit 15 : ITC - Directs the HW to Insert TCP/UDP Checksum
+ * bit 16..20 : QID - The target QID that the packet should be stored
+ * in the MAC.
+ * bit 21 : PO - Pseudo header Offload:
+ * 0 - Use the pseudo header value from the TCP checksum field
+ * 1- Calculate Pseudo header Checksum
+ * bit 22 : NC - No UDP Checksum
+ * bit 23..29 : reserved
+ * bit 30..31 : L4T - Layer 4 Type: 00 - UDP , 10 - TCP , 10, 11 - Reserved
+ * If L4Len equal 0, no L4 at all
+ * [dword 1]
+ * bit 0..31 : addr_low:32 The payload buffer low address
+ * [dword 2]
+ * bit 0..15 : addr_high:16 The payload buffer high address
+ * bit 16..23 : ip_length:8 The IP header length for the TX IP checksum
+ * offload feature
+ * bit 24..30 : mac_length:7
+ * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6
+ * [dword 3]
+ * [byte 12] error
+ * bit 0 2 : mac_status:3
+ * bit 3 7 : reserved:5
+ * [byte 13] status
+ * bit 0 : DU:1 Descriptor Used
+ * bit 1 7 : reserved:7
+ * [word 7] length
+ */
struct vring_tx_dma {
u32 d0;
struct vring_dma_addr addr;
@@ -257,45 +291,45 @@ struct vring_tx_dma {
__le16 length;
} __packed;
-/*
- * Rx descriptor - MAC part
+/* Rx descriptor - MAC part
* [dword 0]
* bit 0.. 3 : tid:4 The QoS (b3-0) TID Field
- * bit 4.. 6 : connection_id:3 :The Source index that was found during
- * Parsing the TA. This field is used to define the source of the packet
+ * bit 4.. 6 : cid:3 The Source index that was found during parsing the TA.
+ * This field is used to define the source of the packet
* bit 7 : reserved:1
- * bit 8.. 9 : mac_id:2 : The MAC virtual Ring number (always zero)
- * bit 10..11 : frame_type:2 : The FC Control (b3-2) - MPDU Type
- * (management, data, control and extension)
- * bit 12..15 : frame_subtype:4 : The FC Control (b7-4) - Frame Subtype
+ * bit 8.. 9 : mid:2 The MAC virtual number
+ * bit 10..11 : frame_type:2 : The FC (b3-2) - MPDU Type
+ * (management, data, control and extension)
+ * bit 12..15 : frame_subtype:4 : The FC (b7-4) - Frame Subtype
* bit 16..27 : seq_number:12 The received Sequence number field
* bit 28..31 : extended:4 extended subtype
* [dword 1]
* bit 0.. 3 : reserved
* bit 4.. 5 : key_id:2
* bit 6 : decrypt_bypass:1
- * bit 7 : security:1
- * bit 8.. 9 : ds_bits:2
- * bit 10 : a_msdu_present:1 from qos header
- * bit 11 : a_msdu_type:1 from qos header
+ * bit 7 : security:1 FC (b14)
+ * bit 8.. 9 : ds_bits:2 FC (b9-8)
+ * bit 10 : a_msdu_present:1 QoS (b7)
+ * bit 11 : a_msdu_type:1 QoS (b8)
* bit 12 : a_mpdu:1 part of AMPDU aggregation
* bit 13 : broadcast:1
* bit 14 : mutlicast:1
* bit 15 : reserved:1
- * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
- * is received from
+ * bit 16..20 : rx_mac_qid:5 The Queue Identifier that the packet
+ * is received from
* bit 21..24 : mcs:4
- * bit 25..28 : mic_icr:4
+ * bit 25..28 : mic_icr:4 this signal tells the DMA to assert an interrupt
+ * after it writes the packet
* bit 29..31 : reserved:3
* [dword 2]
* bit 0.. 2 : time_slot:3 The timeslot that the MPDU is received
- * bit 3 : fc_protocol_ver:1 The FC Control (b0) - Protocol Version
- * bit 4 : fc_order:1 The FC Control (b15) -Order
- * bit 5.. 7 : qos_ack_policy:3 The QoS (b6-5) ack policy Field
+ * bit 3.. 4 : fc_protocol_ver:1 The FC (b1-0) - Protocol Version
+ * bit 5 : fc_order:1 The FC Control (b15) -Order
+ * bit 6.. 7 : qos_ack_policy:2 The QoS (b6-5) ack policy Field
* bit 8 : esop:1 The QoS (b4) ESOP field
- * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
- * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
- * bit 15 : qos_ac_constraint:1
+ * bit 9 : qos_rdg_more_ppdu:1 The QoS (b9) RDG field
+ * bit 10..14 : qos_reserved:5 The QoS (b14-10) Reserved field
+ * bit 15 : qos_ac_constraint:1 QoS (b15)
* bit 16..31 : pn_15_0:16 low 2 bytes of PN
* [dword 3]
* bit 0..31 : pn_47_16:32 high 4 bytes of PN
@@ -308,35 +342,46 @@ struct vring_rx_mac {
u32 pn_47_16;
} __packed;
-/*
- * Rx descriptor - DMA part
+/* Rx descriptor - DMA part
* [dword 0]
- * bit 0.. 7 : l4_length:8 layer 4 length
- * bit 8.. 9 : reserved:2
- * bit 10 : cmd_dma_it:1
+ * bit 0.. 7 : l4_length:8 layer 4 length. The field is only valid if
+ * L4I bit is set
+ * bit 8 : cmd_eop:1 set to 1
+ * bit 9 : cmd_rt:1 set to 1
+ * bit 10 : cmd_dma_it:1 immediate interrupt
* bit 11..15 : reserved:5
- * bit 16..29 : phy_info_length:14
+ * bit 16..29 : phy_info_length:14 It is valid when the PII is set.
+ * When the FFM bit is set bits 29-27 are used for for
+ * Flex Filter Match. Matching Index to one of the L2
+ * EtherType Flex Filter
* bit 30..31 : l4_type:2 valid if the L4I bit is set in the status field
+ * 00 - UDP, 01 - TCP, 10, 11 - reserved
* [dword 1]
* bit 0..31 : addr_low:32 The payload buffer low address
* [dword 2]
* bit 0..15 : addr_high:16 The payload buffer high address
- * bit 16..23 : ip_length:8
+ * bit 16..23 : ip_length:8 The filed is valid only if the L3I bit is set
* bit 24..30 : mac_length:7
- * bit 31 : ip_version:1
+ * bit 31 : ip_version:1 1 - IPv4, 0 - IPv6
* [dword 3]
* [byte 12] error
+ * bit 0 : FCS:1
+ * bit 1 : MIC:1
+ * bit 2 : Key miss:1
+ * bit 3 : Replay:1
+ * bit 4 : L3:1 IPv4 checksum
+ * bit 5 : L4:1 TCP/UDP checksum
+ * bit 6 7 : reserved:2
* [byte 13] status
- * bit 0 : du:1
- * bit 1 : eop:1
+ * bit 0 : DU:1 Descriptor Used
+ * bit 1 : EOP:1 The descriptor indicates the End of Packet
* bit 2 : error:1
- * bit 3 : mi:1
- * bit 4 : l3_identified:1
- * bit 5 : l4_identified:1
- * bit 6 : phy_info_included:1
- * bit 7 : reserved:1
+ * bit 3 : MI:1 MAC Interrupt is asserted (according to parser decision)
+ * bit 4 : L3I:1 L3 identified and checksum calculated
+ * bit 5 : L4I:1 L4 identified and checksum calculated
+ * bit 6 : PII:1 PHY Info Included in the packet
+ * bit 7 : FFM:1 EtherType Flex Filter Match
* [word 7] length
- *
*/
#define RX_DMA_D0_CMD_DMA_IT BIT(10)
@@ -349,9 +394,9 @@ struct vring_rx_mac {
#define RX_DMA_STATUS_DU BIT(0)
#define RX_DMA_STATUS_ERROR BIT(2)
-#define RX_DMA_STATUS_L3_IDENT BIT(4)
-#define RX_DMA_STATUS_L4_IDENT BIT(5)
-#define RX_DMA_STATUS_PHY_INFO BIT(6)
+#define RX_DMA_STATUS_L3I BIT(4)
+#define RX_DMA_STATUS_L4I BIT(5)
+#define RX_DMA_STATUS_PHY_INFO BIT(6)
struct vring_rx_dma {
u32 d0;
@@ -423,6 +468,11 @@ static inline int wil_rxdesc_mcs(struct vring_rx_desc *d)
return WIL_GET_BITS(d->mac.d1, 21, 24);
}
+static inline int wil_rxdesc_mcast(struct vring_rx_desc *d)
+{
+ return WIL_GET_BITS(d->mac.d1, 13, 14);
+}
+
static inline int wil_rxdesc_phy_length(struct vring_rx_desc *d)
{
return WIL_GET_BITS(d->dma.d0, 16, 29);
diff --git a/drivers/net/wireless/ath/wil6210/wil6210.h b/drivers/net/wireless/ath/wil6210/wil6210.h
index c6ec5b99ac7d..94611568fc9a 100644
--- a/drivers/net/wireless/ath/wil6210/wil6210.h
+++ b/drivers/net/wireless/ath/wil6210/wil6210.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2014 Qualcomm Atheros, Inc.
+ * Copyright (c) 2012-2015 Qualcomm Atheros, Inc.
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
@@ -25,19 +25,14 @@
extern bool no_fw_recovery;
extern unsigned int mtu_max;
+extern unsigned short rx_ring_overflow_thrsh;
+extern int agg_wsize;
#define WIL_NAME "wil6210"
#define WIL_FW_NAME "wil6210.fw"
#define WIL_MAX_BUS_REQUEST_KBPS 800000 /* ~6.1Gbps */
-struct wil_board {
- int board;
-#define WIL_BOARD_MARLON (1)
-#define WIL_BOARD_SPARROW (2)
- const char * const name;
-};
-
/**
* extract bits [@b0:@b1] (inclusive) from the value @x
* it should be @b0 <= @b1, or result is incorrect
@@ -49,21 +44,50 @@ static inline u32 WIL_GET_BITS(u32 x, int b0, int b1)
#define WIL6210_MEM_SIZE (2*1024*1024UL)
-#define WIL_RX_RING_SIZE_ORDER_DEFAULT (9)
-#define WIL_TX_RING_SIZE_ORDER_DEFAULT (9)
+#define WIL_TX_Q_LEN_DEFAULT (4000)
+#define WIL_RX_RING_SIZE_ORDER_DEFAULT (10)
+#define WIL_TX_RING_SIZE_ORDER_DEFAULT (10)
/* limit ring size in range [32..32k] */
#define WIL_RING_SIZE_ORDER_MIN (5)
#define WIL_RING_SIZE_ORDER_MAX (15)
#define WIL6210_MAX_TX_RINGS (24) /* HW limit */
#define WIL6210_MAX_CID (8) /* HW limit */
#define WIL6210_NAPI_BUDGET (16) /* arbitrary */
+#define WIL_MAX_AMPDU_SIZE (64 * 1024) /* FW/HW limit */
+#define WIL_MAX_AGG_WSIZE (32) /* FW/HW limit */
+/* Hardware offload block adds the following:
+ * 26 bytes - 3-address QoS data header
+ * 8 bytes - IV + EIV (for GCMP)
+ * 8 bytes - SNAP
+ * 16 bytes - MIC (for GCMP)
+ * 4 bytes - CRC
+ */
+#define WIL_MAX_MPDU_OVERHEAD (62)
+
+/* Calculate MAC buffer size for the firmware. It includes all overhead,
+ * as it will go over the air, and need to be 8 byte aligned
+ */
+static inline u32 wil_mtu2macbuf(u32 mtu)
+{
+ return ALIGN(mtu + WIL_MAX_MPDU_OVERHEAD, 8);
+}
+
+/* MTU for Ethernet need to take into account 8-byte SNAP header
+ * to be added when encapsulating Ethernet frame into 802.11
+ */
+#define WIL_MAX_ETH_MTU (IEEE80211_MAX_DATA_LEN_DMG - 8)
/* Max supported by wil6210 value for interrupt threshold is 5sec. */
#define WIL6210_ITR_TRSH_MAX (5000000)
-#define WIL6210_ITR_TRSH_DEFAULT (300) /* usec */
+#define WIL6210_ITR_TX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */
+#define WIL6210_ITR_RX_INTERFRAME_TIMEOUT_DEFAULT (13) /* usec */
+#define WIL6210_ITR_TX_MAX_BURST_DURATION_DEFAULT (500) /* usec */
+#define WIL6210_ITR_RX_MAX_BURST_DURATION_DEFAULT (500) /* usec */
#define WIL6210_FW_RECOVERY_RETRIES (5) /* try to recover this many times */
#define WIL6210_FW_RECOVERY_TO msecs_to_jiffies(5000)
#define WIL6210_SCAN_TO msecs_to_jiffies(10000)
-
+#define WIL6210_RX_HIGH_TRSH_INIT (0)
+#define WIL6210_RX_HIGH_TRSH_DEFAULT \
+ (1 << (WIL_RX_RING_SIZE_ORDER_DEFAULT - 3))
/* Hardware definitions begin */
/*
@@ -135,7 +159,7 @@ struct RGF_ICR {
#define BIT_DMA_EP_MISC_ICR_TX_NO_ACT BIT(1)
#define BIT_DMA_EP_MISC_ICR_FW_INT(n) BIT(28+n) /* n = [0..3] */
-/* Interrupt moderation control */
+/* Legacy interrupt moderation control (before Sparrow v2)*/
#define RGF_DMA_ITR_CNT_TRSH (0x881c5c)
#define RGF_DMA_ITR_CNT_DATA (0x881c60)
#define RGF_DMA_ITR_CNT_CRL (0x881c64)
@@ -145,6 +169,46 @@ struct RGF_ICR {
#define BIT_DMA_ITR_CNT_CRL_CLR BIT(3)
#define BIT_DMA_ITR_CNT_CRL_REACH_TRSH BIT(4)
+/* New (sparrow v2+) interrupt moderation control */
+#define RGF_DMA_ITR_TX_DESQ_NO_MOD (0x881d40)
+#define RGF_DMA_ITR_TX_CNT_TRSH (0x881d34)
+#define RGF_DMA_ITR_TX_CNT_DATA (0x881d38)
+#define RGF_DMA_ITR_TX_CNT_CTL (0x881d3c)
+ #define BIT_DMA_ITR_TX_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_TX_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_TX_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_TX_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_TX_CNT_CTL_REACHED_TRESH BIT(4)
+ #define BIT_DMA_ITR_TX_CNT_CTL_CROSS_EN BIT(5)
+ #define BIT_DMA_ITR_TX_CNT_CTL_FREE_RUNNIG BIT(6)
+#define RGF_DMA_ITR_TX_IDL_CNT_TRSH (0x881d60)
+#define RGF_DMA_ITR_TX_IDL_CNT_DATA (0x881d64)
+#define RGF_DMA_ITR_TX_IDL_CNT_CTL (0x881d68)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_TX_IDL_CNT_CTL_REACHED_TRESH BIT(4)
+#define RGF_DMA_ITR_RX_DESQ_NO_MOD (0x881d50)
+#define RGF_DMA_ITR_RX_CNT_TRSH (0x881d44)
+#define RGF_DMA_ITR_RX_CNT_DATA (0x881d48)
+#define RGF_DMA_ITR_RX_CNT_CTL (0x881d4c)
+ #define BIT_DMA_ITR_RX_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_RX_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_RX_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_RX_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_RX_CNT_CTL_REACHED_TRESH BIT(4)
+ #define BIT_DMA_ITR_RX_CNT_CTL_CROSS_EN BIT(5)
+ #define BIT_DMA_ITR_RX_CNT_CTL_FREE_RUNNIG BIT(6)
+#define RGF_DMA_ITR_RX_IDL_CNT_TRSH (0x881d54)
+#define RGF_DMA_ITR_RX_IDL_CNT_DATA (0x881d58)
+#define RGF_DMA_ITR_RX_IDL_CNT_CTL (0x881d5c)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EN BIT(0)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_EXT_TIC_SEL BIT(1)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_FOREVER BIT(2)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_CLR BIT(3)
+ #define BIT_DMA_ITR_RX_IDL_CNT_CTL_REACHED_TRESH BIT(4)
+
#define RGF_DMA_PSEUDO_CAUSE (0x881c68)
#define RGF_DMA_PSEUDO_CAUSE_MASK_SW (0x881c6c)
#define RGF_DMA_PSEUDO_CAUSE_MASK_FW (0x881c70)
@@ -164,6 +228,20 @@ struct RGF_ICR {
#define RGF_CAF_PLL_LOCK_STATUS (0x88afec)
#define BIT_CAF_OSC_DIG_XTAL_STABLE BIT(0)
+#define RGF_USER_JTAG_DEV_ID (0x880b34) /* device ID */
+ #define JTAG_DEV_ID_MARLON_B0 (0x0612072f)
+ #define JTAG_DEV_ID_SPARROW_A0 (0x0632072f)
+ #define JTAG_DEV_ID_SPARROW_A1 (0x1632072f)
+ #define JTAG_DEV_ID_SPARROW_B0 (0x2632072f)
+
+enum {
+ HW_VER_UNKNOWN,
+ HW_VER_MARLON_B0, /* JTAG_DEV_ID_MARLON_B0 */
+ HW_VER_SPARROW_A0, /* JTAG_DEV_ID_SPARROW_A0 */
+ HW_VER_SPARROW_A1, /* JTAG_DEV_ID_SPARROW_A1 */
+ HW_VER_SPARROW_B0, /* JTAG_DEV_ID_SPARROW_B0 */
+};
+
/* popular locations */
#define HOST_MBOX HOSTADDR(RGF_USER_USER_SCRATCH_PAD)
#define HOST_SW_INT (HOSTADDR(RGF_USER_USER_ICR) + \
@@ -303,6 +381,11 @@ struct vring {
struct vring_tx_data {
int enabled;
cycles_t idle, last_idle, begin;
+ u8 agg_wsize; /* agreed aggregation window, 0 - no agg */
+ u16 agg_timeout;
+ u8 agg_amsdu;
+ bool addba_in_progress; /* if set, agg_xxx is for request in progress */
+ spinlock_t lock;
};
enum { /* for wil6210_priv.status */
@@ -313,6 +396,7 @@ enum { /* for wil6210_priv.status */
wil_status_reset_done,
wil_status_irqen, /* FIXME: interrupts enabled - for debug */
wil_status_napi_en, /* NAPI enabled protected by wil->mutex */
+ wil_status_last /* keep last */
};
struct pci_dev;
@@ -397,15 +481,46 @@ enum {
fw_recovery_running = 2,
};
+enum {
+ hw_capability_reset_v2 = 0,
+ hw_capability_advanced_itr_moderation = 1,
+ hw_capability_last
+};
+
+struct wil_back_rx {
+ struct list_head list;
+ /* request params, converted to CPU byte order - what we asked for */
+ u8 cidxtid;
+ u8 dialog_token;
+ u16 ba_param_set;
+ u16 ba_timeout;
+ u16 ba_seq_ctrl;
+};
+
+struct wil_back_tx {
+ struct list_head list;
+ /* request params, converted to CPU byte order - what we asked for */
+ u8 ringid;
+ u8 agg_wsize;
+ u16 agg_timeout;
+};
+
+struct wil_probe_client_req {
+ struct list_head list;
+ u64 cookie;
+ u8 cid;
+};
+
struct wil6210_priv {
struct pci_dev *pdev;
int n_msi;
struct wireless_dev *wdev;
void __iomem *csr;
- ulong status;
+ DECLARE_BITMAP(status, wil_status_last);
u32 fw_version;
u32 hw_version;
- struct wil_board *board;
+ const char *hw_name;
+ DECLARE_BITMAP(hw_capabilities, hw_capability_last);
u8 n_mids; /* number of additional MIDs as reported by FW */
u32 recovery_count; /* num of FW recovery attempts in a short time */
u32 recovery_state; /* FW recovery state machine */
@@ -415,7 +530,11 @@ struct wil6210_priv {
u32 monitor_flags;
u32 secure_pcp; /* create secure PCP? */
int sinfo_gen;
- u32 itr_trsh;
+ /* interrupt moderation */
+ u32 tx_max_burst_duration;
+ u32 tx_interframe_timeout;
+ u32 rx_max_burst_duration;
+ u32 rx_interframe_timeout;
/* cached ISR registers */
u32 isr_misc;
/* mailbox related */
@@ -429,7 +548,7 @@ struct wil6210_priv {
u16 reply_size;
struct workqueue_struct *wmi_wq; /* for deferred calls */
struct work_struct wmi_event_worker;
- struct workqueue_struct *wmi_wq_conn; /* for connect worker */
+ struct workqueue_struct *wq_service;
struct work_struct connect_worker;
struct work_struct disconnect_worker;
struct work_struct fw_error_worker; /* for FW error recovery */
@@ -445,6 +564,17 @@ struct wil6210_priv {
spinlock_t wmi_ev_lock;
struct napi_struct napi_rx;
struct napi_struct napi_tx;
+ /* BACK */
+ struct list_head back_rx_pending;
+ struct mutex back_rx_mutex; /* protect @back_rx_pending */
+ struct work_struct back_rx_worker;
+ struct list_head back_tx_pending;
+ struct mutex back_tx_mutex; /* protect @back_tx_pending */
+ struct work_struct back_tx_worker;
+ /* keep alive */
+ struct list_head probe_client_pending;
+ struct mutex probe_client_mutex; /* protect @probe_client_pending */
+ struct work_struct probe_client_worker;
/* DMA related */
struct vring vring_rx;
struct vring vring_tx[WIL6210_MAX_TX_RINGS];
@@ -529,11 +659,8 @@ void wil_if_remove(struct wil6210_priv *wil);
int wil_priv_init(struct wil6210_priv *wil);
void wil_priv_deinit(struct wil6210_priv *wil);
int wil_reset(struct wil6210_priv *wil);
-void wil_set_itr_trsh(struct wil6210_priv *wil);
void wil_fw_error_recovery(struct wil6210_priv *wil);
void wil_set_recovery_state(struct wil6210_priv *wil, int state);
-void wil_link_on(struct wil6210_priv *wil);
-void wil_link_off(struct wil6210_priv *wil);
int wil_up(struct wil6210_priv *wil);
int __wil_up(struct wil6210_priv *wil);
int wil_down(struct wil6210_priv *wil);
@@ -567,12 +694,26 @@ int wmi_p2p_cfg(struct wil6210_priv *wil, int channel);
int wmi_rxon(struct wil6210_priv *wil, bool on);
int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r);
int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason);
+int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout);
+int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason);
+int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason);
+int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+ u16 status, bool amsdu, u16 agg_wsize, u16 timeout);
+int wil_addba_rx_request(struct wil6210_priv *wil, u8 cidxtid,
+ u8 dialog_token, __le16 ba_param_set,
+ __le16 ba_timeout, __le16 ba_seq_ctrl);
+void wil_back_rx_worker(struct work_struct *work);
+void wil_back_rx_flush(struct wil6210_priv *wil);
+int wil_addba_tx_request(struct wil6210_priv *wil, u8 ringid, u16 wsize);
+void wil_back_tx_worker(struct work_struct *work);
+void wil_back_tx_flush(struct wil6210_priv *wil);
void wil6210_clear_irq(struct wil6210_priv *wil);
int wil6210_init_irq(struct wil6210_priv *wil, int irq);
void wil6210_fini_irq(struct wil6210_priv *wil, int irq);
void wil_mask_irq(struct wil6210_priv *wil);
void wil_unmask_irq(struct wil6210_priv *wil);
+void wil_configure_interrupt_moderation(struct wil6210_priv *wil);
void wil_disable_irq(struct wil6210_priv *wil);
void wil_enable_irq(struct wil6210_priv *wil);
int wil_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
@@ -592,6 +733,8 @@ int wmi_pcp_start(struct wil6210_priv *wil, int bi, u8 wmi_nettype, u8 chan);
int wmi_pcp_stop(struct wil6210_priv *wil);
void wil6210_disconnect(struct wil6210_priv *wil, const u8 *bssid,
u16 reason_code, bool from_event);
+void wil_probe_client_flush(struct wil6210_priv *wil);
+void wil_probe_client_worker(struct work_struct *work);
int wil_rx_init(struct wil6210_priv *wil, u16 size);
void wil_rx_fini(struct wil6210_priv *wil);
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform.c b/drivers/net/wireless/ath/wil6210/wil_platform.c
index 8f1d78f8a74d..976a071ba74e 100644
--- a/drivers/net/wireless/ath/wil6210/wil_platform.c
+++ b/drivers/net/wireless/ath/wil6210/wil_platform.c
@@ -17,10 +17,6 @@
#include "linux/device.h"
#include "wil_platform.h"
-#ifdef CONFIG_WIL6210_PLATFORM_MSM
-#include "wil_platform_msm.h"
-#endif
-
/**
* wil_platform_init() - wil6210 platform module init
*
@@ -37,13 +33,7 @@ void *wil_platform_init(struct device *dev, struct wil_platform_ops *ops)
return NULL;
}
-#ifdef CONFIG_WIL6210_PLATFORM_MSM
- handle = wil_platform_msm_init(dev, ops);
- if (handle)
- return handle;
-#endif
-
- /* other platform specific init functions should be called here */
+ /* platform specific init functions should be called here */
return handle;
}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c b/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
deleted file mode 100644
index b354a743240d..000000000000
--- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.c
+++ /dev/null
@@ -1,257 +0,0 @@
-/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <linux/of.h>
-#include <linux/slab.h>
-#include <linux/msm-bus.h>
-
-#include "wil_platform.h"
-#include "wil_platform_msm.h"
-
-/**
- * struct wil_platform_msm - wil6210 msm platform module info
- *
- * @dev: device object
- * @msm_bus_handle: handle for using msm_bus API
- * @pdata: bus scale info retrieved from DT
- */
-struct wil_platform_msm {
- struct device *dev;
- uint32_t msm_bus_handle;
- struct msm_bus_scale_pdata *pdata;
-};
-
-#define KBTOB(a) (a * 1000ULL)
-
-/**
- * wil_platform_get_pdata() - Generate bus client data from device tree
- * provided by clients.
- *
- * dev: device object
- * of_node: Device tree node to extract information from
- *
- * The function returns a valid pointer to the allocated bus-scale-pdata
- * if the vectors were correctly read from the client's device node.
- * Any error in reading or parsing the device node will return NULL
- * to the caller.
- */
-static struct msm_bus_scale_pdata *wil_platform_get_pdata(
- struct device *dev,
- struct device_node *of_node)
-{
- struct msm_bus_scale_pdata *pdata;
- struct msm_bus_paths *usecase;
- int i, j, ret, len;
- unsigned int num_usecases, num_paths, mem_size;
- const uint32_t *vec_arr;
- struct msm_bus_vectors *vectors;
-
- /* first read num_usecases and num_paths so we can calculate
- * amount of memory to allocate
- */
- ret = of_property_read_u32(of_node, "qcom,msm-bus,num-cases",
- &num_usecases);
- if (ret) {
- dev_err(dev, "Error: num-usecases not found\n");
- return NULL;
- }
-
- ret = of_property_read_u32(of_node, "qcom,msm-bus,num-paths",
- &num_paths);
- if (ret) {
- dev_err(dev, "Error: num_paths not found\n");
- return NULL;
- }
-
- /* pdata memory layout:
- * msm_bus_scale_pdata
- * msm_bus_paths[num_usecases]
- * msm_bus_vectors[num_usecases][num_paths]
- */
- mem_size = sizeof(struct msm_bus_scale_pdata) +
- sizeof(struct msm_bus_paths) * num_usecases +
- sizeof(struct msm_bus_vectors) * num_usecases * num_paths;
-
- pdata = kzalloc(mem_size, GFP_KERNEL);
- if (!pdata)
- return NULL;
-
- ret = of_property_read_string(of_node, "qcom,msm-bus,name",
- &pdata->name);
- if (ret) {
- dev_err(dev, "Error: Client name not found\n");
- goto err;
- }
-
- if (of_property_read_bool(of_node, "qcom,msm-bus,active-only")) {
- pdata->active_only = 1;
- } else {
- dev_info(dev, "active_only flag absent.\n");
- dev_info(dev, "Using dual context by default\n");
- }
-
- pdata->num_usecases = num_usecases;
- pdata->usecase = (struct msm_bus_paths *)(pdata + 1);
-
- vec_arr = of_get_property(of_node, "qcom,msm-bus,vectors-KBps", &len);
- if (vec_arr == NULL) {
- dev_err(dev, "Error: Vector array not found\n");
- goto err;
- }
-
- if (len != num_usecases * num_paths * sizeof(uint32_t) * 4) {
- dev_err(dev, "Error: Length-error on getting vectors\n");
- goto err;
- }
-
- vectors = (struct msm_bus_vectors *)(pdata->usecase + num_usecases);
- for (i = 0; i < num_usecases; i++) {
- usecase = &pdata->usecase[i];
- usecase->num_paths = num_paths;
- usecase->vectors = &vectors[i];
-
- for (j = 0; j < num_paths; j++) {
- int index = ((i * num_paths) + j) * 4;
-
- usecase->vectors[j].src = be32_to_cpu(vec_arr[index]);
- usecase->vectors[j].dst =
- be32_to_cpu(vec_arr[index + 1]);
- usecase->vectors[j].ab = (uint64_t)
- KBTOB(be32_to_cpu(vec_arr[index + 2]));
- usecase->vectors[j].ib = (uint64_t)
- KBTOB(be32_to_cpu(vec_arr[index + 3]));
- }
- }
-
- return pdata;
-
-err:
- kfree(pdata);
-
- return NULL;
-}
-
-/* wil_platform API (callbacks) */
-
-static int wil_platform_bus_request(void *handle,
- uint32_t kbps /* KBytes/Sec */)
-{
- int rc, i;
- struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
- int vote = 0; /* vote 0 in case requested kbps cannot be satisfied */
- struct msm_bus_paths *usecase;
- uint32_t usecase_kbps;
- uint32_t min_kbps = ~0;
-
- /* find the lowest usecase that is bigger than requested kbps */
- for (i = 0; i < msm->pdata->num_usecases; i++) {
- usecase = &msm->pdata->usecase[i];
- /* assume we have single path (vectors[0]). If we ever
- * have multiple paths, need to define the behavior */
- usecase_kbps = div64_u64(usecase->vectors[0].ib, 1000);
- if (usecase_kbps >= kbps && usecase_kbps < min_kbps) {
- min_kbps = usecase_kbps;
- vote = i;
- }
- }
-
- rc = msm_bus_scale_client_update_request(msm->msm_bus_handle, vote);
- if (rc)
- dev_err(msm->dev, "Failed msm_bus voting. kbps=%d vote=%d, rc=%d\n",
- kbps, vote, rc);
- else
- /* TOOD: remove */
- dev_info(msm->dev, "msm_bus_scale_client_update_request succeeded. kbps=%d vote=%d\n",
- kbps, vote);
-
- return rc;
-}
-
-static void wil_platform_uninit(void *handle)
-{
- struct wil_platform_msm *msm = (struct wil_platform_msm *)handle;
-
- dev_info(msm->dev, "wil_platform_uninit\n");
-
- if (msm->msm_bus_handle)
- msm_bus_scale_unregister_client(msm->msm_bus_handle);
-
- kfree(msm->pdata);
- kfree(msm);
-}
-
-static int wil_platform_msm_bus_register(struct wil_platform_msm *msm,
- struct device_node *node)
-{
- msm->pdata = wil_platform_get_pdata(msm->dev, node);
- if (!msm->pdata) {
- dev_err(msm->dev, "Failed getting DT info\n");
- return -EINVAL;
- }
-
- msm->msm_bus_handle = msm_bus_scale_register_client(msm->pdata);
- if (!msm->msm_bus_handle) {
- dev_err(msm->dev, "Failed msm_bus registration\n");
- return -EINVAL;
- }
-
- dev_info(msm->dev, "msm_bus registration succeeded! handle 0x%x\n",
- msm->msm_bus_handle);
-
- return 0;
-}
-
-/**
- * wil_platform_msm_init() - wil6210 msm platform module init
- *
- * The function must be called before all other functions in this module.
- * It returns a handle which is used with the rest of the API
- *
- */
-void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops)
-{
- struct device_node *of_node;
- struct wil_platform_msm *msm;
- int rc;
-
- of_node = of_find_compatible_node(NULL, NULL, "qcom,wil6210");
- if (!of_node) {
- /* this could mean non-msm platform */
- dev_err(dev, "DT node not found\n");
- return NULL;
- }
-
- msm = kzalloc(sizeof(*msm), GFP_KERNEL);
- if (!msm)
- return NULL;
-
- msm->dev = dev;
-
- /* register with msm_bus module for scaling requests */
- rc = wil_platform_msm_bus_register(msm, of_node);
- if (rc)
- goto cleanup;
-
- memset(ops, 0, sizeof(*ops));
- ops->bus_request = wil_platform_bus_request;
- ops->uninit = wil_platform_uninit;
-
- return (void *)msm;
-
-cleanup:
- kfree(msm);
- return NULL;
-}
diff --git a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h b/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
deleted file mode 100644
index 2f2229edb498..000000000000
--- a/drivers/net/wireless/ath/wil6210/wil_platform_msm.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (c) 2014 Qualcomm Atheros, Inc.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef __WIL_PLATFORM__MSM_H__
-#define __WIL_PLATFORM_MSM_H__
-
-#include "wil_platform.h"
-
-void *wil_platform_msm_init(struct device *dev, struct wil_platform_ops *ops);
-
-#endif /* __WIL_PLATFORM__MSM_H__ */
diff --git a/drivers/net/wireless/ath/wil6210/wmi.c b/drivers/net/wireless/ath/wil6210/wmi.c
index 63476c86cd0e..0f3e4334c8e3 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.c
+++ b/drivers/net/wireless/ath/wil6210/wmi.c
@@ -23,10 +23,15 @@
#include "wmi.h"
#include "trace.h"
-static uint max_assoc_sta = 1;
+static uint max_assoc_sta = WIL6210_MAX_CID;
module_param(max_assoc_sta, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_assoc_sta, " Max number of stations associated to the AP");
+int agg_wsize; /* = 0; */
+module_param(agg_wsize, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(agg_wsize, " Window size for Tx Block Ack after connect;"
+ " 0 - use default; < 0 - don't auto-establish");
+
/**
* WMI event receiving - theory of operations
*
@@ -197,7 +202,7 @@ static int __wmi_send(struct wil6210_priv *wil, u16 cmdid, void *buf, u16 len)
might_sleep();
- if (!test_bit(wil_status_fwready, &wil->status)) {
+ if (!test_bit(wil_status_fwready, wil->status)) {
wil_err(wil, "WMI: cannot send command while FW not ready\n");
return -EAGAIN;
}
@@ -300,7 +305,7 @@ static void wmi_evt_fw_ready(struct wil6210_priv *wil, int id, void *d,
wil_dbg_wmi(wil, "WMI: got FW ready event\n");
wil_set_recovery_state(wil, fw_recovery_idle);
- set_bit(wil_status_fwready, &wil->status);
+ set_bit(wil_status_fwready, wil->status);
/* let the reset sequence continue */
complete(&wil->wmi_ready);
}
@@ -438,7 +443,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if ((wdev->iftype == NL80211_IFTYPE_STATION) ||
(wdev->iftype == NL80211_IFTYPE_P2P_CLIENT)) {
- if (!test_bit(wil_status_fwconnecting, &wil->status)) {
+ if (!test_bit(wil_status_fwconnecting, wil->status)) {
wil_err(wil, "Not in connecting state\n");
return;
}
@@ -457,13 +462,12 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
if (assoc_req_ie) {
sinfo.assoc_req_ies = assoc_req_ie;
sinfo.assoc_req_ies_len = assoc_req_ielen;
- sinfo.filled |= STATION_INFO_ASSOC_REQ_IES;
}
cfg80211_new_sta(ndev, evt->bssid, &sinfo, GFP_KERNEL);
}
- clear_bit(wil_status_fwconnecting, &wil->status);
- set_bit(wil_status_fwconnected, &wil->status);
+ clear_bit(wil_status_fwconnecting, wil->status);
+ set_bit(wil_status_fwconnected, wil->status);
/* FIXME FW can transmit only ucast frames to peer */
/* FIXME real ring_id instead of hard coded 0 */
@@ -471,7 +475,7 @@ static void wmi_evt_connect(struct wil6210_priv *wil, int id, void *d, int len)
wil->sta[evt->cid].status = wil_sta_conn_pending;
wil->pending_connect_cid = evt->cid;
- queue_work(wil->wmi_wq_conn, &wil->connect_worker);
+ queue_work(wil->wq_service, &wil->connect_worker);
}
static void wmi_evt_disconnect(struct wil6210_priv *wil, int id,
@@ -544,9 +548,24 @@ static void wmi_evt_eapol_rx(struct wil6210_priv *wil, int id,
}
}
+static void wil_addba_tx_cid(struct wil6210_priv *wil, u8 cid, u16 wsize)
+{
+ struct vring_tx_data *t;
+ int i;
+
+ for (i = 0; i < WIL6210_MAX_TX_RINGS; i++) {
+ if (cid != wil->vring2cid_tid[i][0])
+ continue;
+ t = &wil->vring_tx_data[i];
+ if (!t->enabled)
+ continue;
+
+ wil_addba_tx_request(wil, i, wsize);
+ }
+}
+
static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
{
- struct net_device *ndev = wil_to_ndev(wil);
struct wmi_data_port_open_event *evt = d;
u8 cid = evt->cid;
@@ -558,7 +577,8 @@ static void wmi_evt_linkup(struct wil6210_priv *wil, int id, void *d, int len)
}
wil->sta[cid].data_port_open = true;
- netif_carrier_on(ndev);
+ if (agg_wsize >= 0)
+ wil_addba_tx_cid(wil, cid, agg_wsize);
}
static void wmi_evt_linkdown(struct wil6210_priv *wil, int id, void *d, int len)
@@ -583,55 +603,89 @@ static void wmi_evt_ba_status(struct wil6210_priv *wil, int id, void *d,
int len)
{
struct wmi_vring_ba_status_event *evt = d;
- struct wil_sta_info *sta;
- uint i, cid;
+ struct vring_tx_data *txdata;
- /* TODO: use Rx BA status, not Tx one */
-
- wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d\n",
+ wil_dbg_wmi(wil, "BACK[%d] %s {%d} timeout %d AMSDU%s\n",
evt->ringid,
evt->status == WMI_BA_AGREED ? "OK" : "N/A",
- evt->agg_wsize, __le16_to_cpu(evt->ba_timeout));
+ evt->agg_wsize, __le16_to_cpu(evt->ba_timeout),
+ evt->amsdu ? "+" : "-");
if (evt->ringid >= WIL6210_MAX_TX_RINGS) {
wil_err(wil, "invalid ring id %d\n", evt->ringid);
return;
}
- mutex_lock(&wil->mutex);
-
- cid = wil->vring2cid_tid[evt->ringid][0];
- if (cid >= WIL6210_MAX_CID) {
- wil_err(wil, "invalid CID %d for vring %d\n", cid, evt->ringid);
- goto out;
+ if (evt->status != WMI_BA_AGREED) {
+ evt->ba_timeout = 0;
+ evt->agg_wsize = 0;
+ evt->amsdu = 0;
}
- sta = &wil->sta[cid];
- if (sta->status == wil_sta_unused) {
- wil_err(wil, "CID %d unused\n", cid);
- goto out;
- }
+ txdata = &wil->vring_tx_data[evt->ringid];
- wil_dbg_wmi(wil, "BACK for CID %d %pM\n", cid, sta->addr);
- for (i = 0; i < WIL_STA_TID_NUM; i++) {
- struct wil_tid_ampdu_rx *r;
- unsigned long flags;
+ txdata->agg_timeout = le16_to_cpu(evt->ba_timeout);
+ txdata->agg_wsize = evt->agg_wsize;
+ txdata->agg_amsdu = evt->amsdu;
+ txdata->addba_in_progress = false;
+}
- spin_lock_irqsave(&sta->tid_rx_lock, flags);
+static void wmi_evt_addba_rx_req(struct wil6210_priv *wil, int id, void *d,
+ int len)
+{
+ struct wmi_rcp_addba_req_event *evt = d;
- r = sta->tid_rx[i];
- sta->tid_rx[i] = NULL;
- wil_tid_ampdu_rx_free(wil, r);
+ wil_addba_rx_request(wil, evt->cidxtid, evt->dialog_token,
+ evt->ba_param_set, evt->ba_timeout,
+ evt->ba_seq_ctrl);
+}
- spin_unlock_irqrestore(&sta->tid_rx_lock, flags);
+static void wmi_evt_delba(struct wil6210_priv *wil, int id, void *d, int len)
+__acquires(&sta->tid_rx_lock) __releases(&sta->tid_rx_lock)
+{
+ struct wmi_delba_event *evt = d;
+ u8 cid, tid;
+ u16 reason = __le16_to_cpu(evt->reason);
+ struct wil_sta_info *sta;
+ struct wil_tid_ampdu_rx *r;
- if ((evt->status == WMI_BA_AGREED) && evt->agg_wsize)
- sta->tid_rx[i] = wil_tid_ampdu_rx_alloc(wil,
- evt->agg_wsize, 0);
+ might_sleep();
+ parse_cidxtid(evt->cidxtid, &cid, &tid);
+ wil_dbg_wmi(wil, "DELBA CID %d TID %d from %s reason %d\n",
+ cid, tid,
+ evt->from_initiator ? "originator" : "recipient",
+ reason);
+ if (!evt->from_initiator) {
+ int i;
+ /* find Tx vring it belongs to */
+ for (i = 0; i < ARRAY_SIZE(wil->vring2cid_tid); i++) {
+ if ((wil->vring2cid_tid[i][0] == cid) &&
+ (wil->vring2cid_tid[i][1] == tid)) {
+ struct vring_tx_data *txdata =
+ &wil->vring_tx_data[i];
+
+ wil_dbg_wmi(wil, "DELBA Tx vring %d\n", i);
+ txdata->agg_timeout = 0;
+ txdata->agg_wsize = 0;
+ txdata->addba_in_progress = false;
+
+ break; /* max. 1 matching ring */
+ }
+ }
+ if (i >= ARRAY_SIZE(wil->vring2cid_tid))
+ wil_err(wil, "DELBA: unable to find Tx vring\n");
+ return;
}
-out:
- mutex_unlock(&wil->mutex);
+ sta = &wil->sta[cid];
+
+ spin_lock_bh(&sta->tid_rx_lock);
+
+ r = sta->tid_rx[tid];
+ sta->tid_rx[tid] = NULL;
+ wil_tid_ampdu_rx_free(wil, r);
+
+ spin_unlock_bh(&sta->tid_rx_lock);
}
static const struct {
@@ -649,6 +703,8 @@ static const struct {
{WMI_DATA_PORT_OPEN_EVENTID, wmi_evt_linkup},
{WMI_WBE_LINKDOWN_EVENTID, wmi_evt_linkdown},
{WMI_BA_STATUS_EVENTID, wmi_evt_ba_status},
+ {WMI_RCP_ADDBA_REQ_EVENTID, wmi_evt_addba_rx_req},
+ {WMI_DELBA_EVENTID, wmi_evt_delba},
};
/*
@@ -668,7 +724,7 @@ void wmi_recv_cmd(struct wil6210_priv *wil)
ulong flags;
unsigned n;
- if (!test_bit(wil_status_reset_done, &wil->status)) {
+ if (!test_bit(wil_status_reset_done, wil->status)) {
wil_err(wil, "Reset in progress. Cannot handle WMI event\n");
return;
}
@@ -1025,13 +1081,14 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
struct wmi_cfg_rx_chain_cmd cmd = {
.action = WMI_RX_CHAIN_ADD,
.rx_sw_ring = {
- .max_mpdu_size = cpu_to_le16(mtu_max + ETH_HLEN),
+ .max_mpdu_size = cpu_to_le16(wil_mtu2macbuf(mtu_max)),
.ring_mem_base = cpu_to_le64(vring->pa),
.ring_size = cpu_to_le16(vring->size),
},
.mid = 0, /* TODO - what is it? */
.decap_trans_type = WMI_DECAP_TYPE_802_3,
.reorder_type = WMI_RX_SW_REORDER,
+ .host_thrsh = cpu_to_le16(rx_ring_overflow_thrsh),
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -1074,12 +1131,13 @@ int wmi_rx_chain_add(struct wil6210_priv *wil, struct vring *vring)
return rc;
}
-int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
+int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_bb, u32 *t_rf)
{
int rc;
struct wmi_temp_sense_cmd cmd = {
- .measure_marlon_m_en = cpu_to_le32(!!t_m),
- .measure_marlon_r_en = cpu_to_le32(!!t_r),
+ .measure_baseband_en = cpu_to_le32(!!t_bb),
+ .measure_rf_en = cpu_to_le32(!!t_rf),
+ .measure_mode = cpu_to_le32(TEMPERATURE_MEASURE_NOW),
};
struct {
struct wil6210_mbox_hdr_wmi wmi;
@@ -1091,10 +1149,10 @@ int wmi_get_temperature(struct wil6210_priv *wil, u32 *t_m, u32 *t_r)
if (rc)
return rc;
- if (t_m)
- *t_m = le32_to_cpu(reply.evt.marlon_m_t1000);
- if (t_r)
- *t_r = le32_to_cpu(reply.evt.marlon_r_t1000);
+ if (t_bb)
+ *t_bb = le32_to_cpu(reply.evt.baseband_t1000);
+ if (t_rf)
+ *t_rf = le32_to_cpu(reply.evt.rf_t1000);
return 0;
}
@@ -1111,6 +1169,87 @@ int wmi_disconnect_sta(struct wil6210_priv *wil, const u8 *mac, u16 reason)
return wmi_send(wil, WMI_DISCONNECT_STA_CMDID, &cmd, sizeof(cmd));
}
+int wmi_addba(struct wil6210_priv *wil, u8 ringid, u8 size, u16 timeout)
+{
+ struct wmi_vring_ba_en_cmd cmd = {
+ .ringid = ringid,
+ .agg_max_wsize = size,
+ .ba_timeout = cpu_to_le16(timeout),
+ .amsdu = 0,
+ };
+
+ wil_dbg_wmi(wil, "%s(ring %d size %d timeout %d)\n", __func__,
+ ringid, size, timeout);
+
+ return wmi_send(wil, WMI_VRING_BA_EN_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_delba_tx(struct wil6210_priv *wil, u8 ringid, u16 reason)
+{
+ struct wmi_vring_ba_dis_cmd cmd = {
+ .ringid = ringid,
+ .reason = cpu_to_le16(reason),
+ };
+
+ wil_dbg_wmi(wil, "%s(ring %d reason %d)\n", __func__,
+ ringid, reason);
+
+ return wmi_send(wil, WMI_VRING_BA_DIS_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_delba_rx(struct wil6210_priv *wil, u8 cidxtid, u16 reason)
+{
+ struct wmi_rcp_delba_cmd cmd = {
+ .cidxtid = cidxtid,
+ .reason = cpu_to_le16(reason),
+ };
+
+ wil_dbg_wmi(wil, "%s(CID %d TID %d reason %d)\n", __func__,
+ cidxtid & 0xf, (cidxtid >> 4) & 0xf, reason);
+
+ return wmi_send(wil, WMI_RCP_DELBA_CMDID, &cmd, sizeof(cmd));
+}
+
+int wmi_addba_rx_resp(struct wil6210_priv *wil, u8 cid, u8 tid, u8 token,
+ u16 status, bool amsdu, u16 agg_wsize, u16 timeout)
+{
+ int rc;
+ struct wmi_rcp_addba_resp_cmd cmd = {
+ .cidxtid = mk_cidxtid(cid, tid),
+ .dialog_token = token,
+ .status_code = cpu_to_le16(status),
+ /* bit 0: A-MSDU supported
+ * bit 1: policy (should be 0 for us)
+ * bits 2..5: TID
+ * bits 6..15: buffer size
+ */
+ .ba_param_set = cpu_to_le16((amsdu ? 1 : 0) | (tid << 2) |
+ (agg_wsize << 6)),
+ .ba_timeout = cpu_to_le16(timeout),
+ };
+ struct {
+ struct wil6210_mbox_hdr_wmi wmi;
+ struct wmi_rcp_addba_resp_sent_event evt;
+ } __packed reply;
+
+ wil_dbg_wmi(wil,
+ "ADDBA response for CID %d TID %d size %d timeout %d status %d AMSDU%s\n",
+ cid, tid, agg_wsize, timeout, status, amsdu ? "+" : "-");
+
+ rc = wmi_call(wil, WMI_RCP_ADDBA_RESP_CMDID, &cmd, sizeof(cmd),
+ WMI_ADDBA_RESP_SENT_EVENTID, &reply, sizeof(reply), 100);
+ if (rc)
+ return rc;
+
+ if (reply.evt.status) {
+ wil_err(wil, "ADDBA response failed with status %d\n",
+ le16_to_cpu(reply.evt.status));
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
void wmi_event_flush(struct wil6210_priv *wil)
{
struct pending_wmi_event *evt, *t;
diff --git a/drivers/net/wireless/ath/wil6210/wmi.h b/drivers/net/wireless/ath/wil6210/wmi.h
index 27b97432d1c2..8a4af613e191 100644
--- a/drivers/net/wireless/ath/wil6210/wmi.h
+++ b/drivers/net/wireless/ath/wil6210/wmi.h
@@ -29,8 +29,10 @@
/* General */
#define WILOCITY_MAX_ASSOC_STA (8)
+#define WILOCITY_DEFAULT_ASSOC_STA (1)
#define WMI_MAC_LEN (6)
#define WMI_PROX_RANGE_NUM (3)
+#define WMI_MAX_LOSS_DMG_BEACONS (32)
/* List of Commands */
enum wmi_command_id {
@@ -48,7 +50,7 @@ enum wmi_command_id {
WMI_SET_WSC_STATUS_CMDID = 0x0041,
WMI_PXMT_RANGE_CFG_CMDID = 0x0042,
WMI_PXMT_SNR2_RANGE_CFG_CMDID = 0x0043,
- WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300,
+/* WMI_FAST_MEM_ACC_MODE_CMDID = 0x0300, */
WMI_MEM_READ_CMDID = 0x0800,
WMI_MEM_WR_CMDID = 0x0801,
WMI_ECHO_CMDID = 0x0803,
@@ -102,6 +104,8 @@ enum wmi_command_id {
WMI_MAINTAIN_RESUME_CMDID = 0x0851,
WMI_RS_MGMT_CMDID = 0x0852,
WMI_RF_MGMT_CMDID = 0x0853,
+ WMI_THERMAL_THROTTLING_CTRL_CMDID = 0x0854,
+ WMI_THERMAL_THROTTLING_GET_STATUS_CMDID = 0x0855,
/* Performance monitoring commands */
WMI_BF_CTRL_CMDID = 0x0862,
WMI_NOTIFY_REQ_CMDID = 0x0863,
@@ -136,6 +140,7 @@ enum wmi_command_id {
WMI_EAPOL_TX_CMDID = 0xf04c,
WMI_MAC_ADDR_REQ_CMDID = 0xf04d,
WMI_FW_VER_CMDID = 0xf04e,
+ WMI_PMC_CMDID = 0xf04f,
};
/*
@@ -283,8 +288,8 @@ enum wmi_scan_type {
WMI_LONG_SCAN = 0,
WMI_SHORT_SCAN = 1,
WMI_PBC_SCAN = 2,
- WMI_ACTIVE_SCAN = 3,
- WMI_DIRECT_SCAN = 4,
+ WMI_DIRECT_SCAN = 3,
+ WMI_ACTIVE_SCAN = 4,
};
struct wmi_start_scan_cmd {
@@ -375,6 +380,17 @@ struct wmi_rf_mgmt_cmd {
} __packed;
/*
+ * WMI_THERMAL_THROTTLING_CTRL_CMDID
+ */
+#define THERMAL_THROTTLING_USE_DEFAULT_MAX_TXOP_LENGTH (0xFFFFFFFF)
+
+struct wmi_thermal_throttling_ctrl_cmd {
+ __le32 time_on_usec;
+ __le32 time_off_usec;
+ __le32 max_txop_length_usec;
+} __packed;
+
+/*
* WMI_RF_RX_TEST_CMDID
*/
struct wmi_rf_rx_test_cmd {
@@ -586,6 +602,7 @@ struct wmi_vring_ba_en_cmd {
u8 ringid;
u8 agg_max_wsize;
__le16 ba_timeout;
+ u8 amsdu;
} __packed;
/*
@@ -647,6 +664,7 @@ enum wmi_cfg_rx_chain_cmd_action {
enum wmi_cfg_rx_chain_cmd_decap_trans_type {
WMI_DECAP_TYPE_802_3 = 0,
WMI_DECAP_TYPE_NATIVE_WIFI = 1,
+ WMI_DECAP_TYPE_NONE = 2,
};
enum wmi_cfg_rx_chain_cmd_nwifi_ds_trans_type {
@@ -784,9 +802,17 @@ struct wmi_echo_cmd {
*
* Measure MAC and radio temperatures
*/
+
+/* Possible modes for temperature measurement */
+enum wmi_temperature_measure_mode {
+ TEMPERATURE_USE_OLD_VALUE = 0x1,
+ TEMPERATURE_MEASURE_NOW = 0x2,
+};
+
struct wmi_temp_sense_cmd {
- __le32 measure_marlon_m_en;
- __le32 measure_marlon_r_en;
+ __le32 measure_baseband_en;
+ __le32 measure_rf_en;
+ __le32 measure_mode;
} __packed;
/*
@@ -842,6 +868,7 @@ enum wmi_event_id {
WMI_BF_RXSS_MGMT_DONE_EVENTID = 0x1839,
WMI_RS_MGMT_DONE_EVENTID = 0x1852,
WMI_RF_MGMT_STATUS_EVENTID = 0x1853,
+ WMI_THERMAL_THROTTLING_STATUS_EVENTID = 0x1855,
WMI_BF_SM_MGMT_DONE_EVENTID = 0x1838,
WMI_RX_MGMT_PACKET_EVENTID = 0x1840,
WMI_TX_MGMT_PACKET_EVENTID = 0x1841,
@@ -858,6 +885,7 @@ enum wmi_event_id {
WMI_FLASH_READ_DONE_EVENTID = 0x1902,
WMI_FLASH_WRITE_DONE_EVENTID = 0x1903,
/*P2P*/
+ WMI_P2P_CFG_DONE_EVENTID = 0x1910,
WMI_PORT_ALLOCATED_EVENTID = 0x1911,
WMI_PORT_DELETED_EVENTID = 0x1912,
WMI_LISTEN_STARTED_EVENTID = 0x1914,
@@ -898,6 +926,15 @@ struct wmi_rf_mgmt_status_event {
} __packed;
/*
+ * WMI_THERMAL_THROTTLING_STATUS_EVENTID
+ */
+struct wmi_thermal_throttling_status_event {
+ __le32 time_on_usec;
+ __le32 time_off_usec;
+ __le32 max_txop_length_usec;
+} __packed;
+
+/*
* WMI_GET_STATUS_DONE_EVENTID
*/
struct wmi_get_status_done_event {
@@ -1052,14 +1089,23 @@ struct wmi_scan_complete_event {
enum wmi_vring_ba_status {
WMI_BA_AGREED = 0,
WMI_BA_NON_AGREED = 1,
+ /* BA_EN in middle of teardown flow */
+ WMI_BA_TD_WIP = 2,
+ /* BA_DIS or BA_EN in middle of BA SETUP flow */
+ WMI_BA_SETUP_WIP = 3,
+ /* BA_EN when the BA session is already active */
+ WMI_BA_SESSION_ACTIVE = 4,
+ /* BA_DIS when the BA session is not active */
+ WMI_BA_SESSION_NOT_ACTIVE = 5,
};
struct wmi_vring_ba_status_event {
- __le16 status;
+ __le16 status; /* enum wmi_vring_ba_status */
u8 reserved[2];
u8 ringid;
u8 agg_wsize;
__le16 ba_timeout;
+ u8 amsdu;
} __packed;
/*
@@ -1145,6 +1191,14 @@ struct wmi_get_pcp_channel_event {
} __packed;
/*
+ * WMI_P2P_CFG_DONE_EVENTID
+ */
+struct wmi_p2p_cfg_done_event {
+ u8 status; /* wmi_fw_status */
+ u8 reserved[3];
+} __packed;
+
+/*
* WMI_PORT_ALLOCATED_EVENTID
*/
struct wmi_port_allocated_event {
@@ -1272,8 +1326,8 @@ struct wmi_echo_event {
* Measure MAC and radio temperatures
*/
struct wmi_temp_sense_done_event {
- __le32 marlon_m_t1000;
- __le32 marlon_r_t1000;
+ __le32 baseband_t1000;
+ __le32 rf_t1000;
} __packed;
#endif /* __WILOCITY_WMI_H__ */
diff --git a/drivers/net/wireless/atmel.c b/drivers/net/wireless/atmel.c
index 9183f1cf89a7..55db9f03eb2a 100644
--- a/drivers/net/wireless/atmel.c
+++ b/drivers/net/wireless/atmel.c
@@ -45,7 +45,6 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
-#include <linux/ctype.h>
#include <linux/timer.h>
#include <asm/byteorder.h>
#include <asm/io.h>
@@ -2699,16 +2698,7 @@ static int atmel_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
domain[REGDOMAINSZ] = 0;
rc = -EINVAL;
for (i = 0; i < ARRAY_SIZE(channel_table); i++) {
- /* strcasecmp doesn't exist in the library */
- char *a = channel_table[i].name;
- char *b = domain;
- while (*a) {
- char c1 = *a++;
- char c2 = *b++;
- if (tolower(c1) != tolower(c2))
- break;
- }
- if (!*a && !*b) {
+ if (!strcasecmp(channel_table[i].name, domain)) {
priv->config_reg_domain = channel_table[i].reg_domain;
rc = 0;
}
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig
index 64a5b672e30a..759fb8d41fc9 100644
--- a/drivers/net/wireless/b43/Kconfig
+++ b/drivers/net/wireless/b43/Kconfig
@@ -166,6 +166,15 @@ config B43_PHY_LCN
Say N, this is BROKEN and crashes driver.
+config B43_PHY_AC
+ bool "Support for AC-PHY (802.11ac) devices (BROKEN)"
+ depends on B43 && B43_BCMA && BROKEN
+ ---help---
+ This PHY type can be found in the following chipsets:
+ PCI: BCM4352, BCM4360
+
+ Say N, this is BROKEN and crashes driver.
+
# This config option automatically enables b43 LEDS support,
# if it's possible.
config B43_LEDS
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile
index 9f7965aae93d..c624d4d90e4f 100644
--- a/drivers/net/wireless/b43/Makefile
+++ b/drivers/net/wireless/b43/Makefile
@@ -13,6 +13,7 @@ b43-$(CONFIG_B43_PHY_HT) += phy_ht.o
b43-$(CONFIG_B43_PHY_HT) += tables_phy_ht.o
b43-$(CONFIG_B43_PHY_HT) += radio_2059.o
b43-$(CONFIG_B43_PHY_LCN) += phy_lcn.o tables_phy_lcn.o
+b43-$(CONFIG_B43_PHY_AC) += phy_ac.o
b43-y += sysfs.o
b43-y += xmit.o
b43-y += dma.o
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h
index bb12586cd7cd..036552439816 100644
--- a/drivers/net/wireless/b43/b43.h
+++ b/drivers/net/wireless/b43/b43.h
@@ -500,6 +500,8 @@ enum {
#define B43_BCMA_IOCTL_PHY_BW_10MHZ 0x00000000 /* 10 MHz bandwidth, 40 MHz PHY */
#define B43_BCMA_IOCTL_PHY_BW_20MHZ 0x00000040 /* 20 MHz bandwidth, 80 MHz PHY */
#define B43_BCMA_IOCTL_PHY_BW_40MHZ 0x00000080 /* 40 MHz bandwidth, 160 MHz PHY */
+#define B43_BCMA_IOCTL_PHY_BW_80MHZ 0x000000C0 /* 80 MHz bandwidth */
+#define B43_BCMA_IOCTL_DAC 0x00000300 /* Highspeed DAC mode control field */
#define B43_BCMA_IOCTL_GMODE 0x00002000 /* G Mode Enable */
/* BCMA 802.11 core specific IO status (BCMA_IOST) flags */
@@ -941,6 +943,7 @@ struct b43_wl {
bool beacon1_uploaded;
bool beacon_templates_virgin; /* Never wrote the templates? */
struct work_struct beacon_update_trigger;
+ spinlock_t beacon_lock;
/* The current QOS parameters for the 4 queues. */
struct b43_qos_params qos_params[B43_QOS_QUEUE_NUM];
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c
index 47731cb0d815..ccbdb05b28cd 100644
--- a/drivers/net/wireless/b43/main.c
+++ b/drivers/net/wireless/b43/main.c
@@ -127,7 +127,7 @@ static const struct bcma_device_id b43_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1E, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x28, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x2A, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
+ {},
};
MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
#endif
@@ -144,7 +144,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
- SSB_DEVTABLE_END
+ {},
};
MODULE_DEVICE_TABLE(ssb, b43_ssb_tbl);
#endif
@@ -1262,6 +1262,23 @@ static void b43_bcma_wireless_core_reset(struct b43_wldev *dev, bool gmode)
flags |= B43_BCMA_IOCTL_GMODE;
b43_device_enable(dev, flags);
+ if (dev->phy.type == B43_PHYTYPE_AC) {
+ u16 tmp;
+
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ tmp &= ~B43_BCMA_IOCTL_DAC;
+ tmp |= 0x100;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ tmp &= ~B43_BCMA_IOCTL_PHY_CLKEN;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+
+ tmp = bcma_aread32(dev->dev->bdev, BCMA_IOCTL);
+ tmp |= B43_BCMA_IOCTL_PHY_CLKEN;
+ bcma_awrite32(dev->dev->bdev, BCMA_IOCTL, tmp);
+ }
+
bcma_core_set_clockmode(dev->dev->bdev, BCMA_CLKMODE_FAST);
b43_bcma_phy_reset(dev);
bcma_core_pll_ctl(dev->dev->bdev, req, status, true);
@@ -1601,12 +1618,26 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
unsigned int rate;
u16 ctl;
int antenna;
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(dev->wl->current_beacon);
+ struct ieee80211_tx_info *info;
+ unsigned long flags;
+ struct sk_buff *beacon_skb;
- bcn = (const struct ieee80211_mgmt *)(dev->wl->current_beacon->data);
- len = min_t(size_t, dev->wl->current_beacon->len,
- 0x200 - sizeof(struct b43_plcp_hdr6));
+ spin_lock_irqsave(&dev->wl->beacon_lock, flags);
+ info = IEEE80211_SKB_CB(dev->wl->current_beacon);
rate = ieee80211_get_tx_rate(dev->wl->hw, info)->hw_value;
+ /* Clone the beacon, so it cannot go away, while we write it to hw. */
+ beacon_skb = skb_clone(dev->wl->current_beacon, GFP_ATOMIC);
+ spin_unlock_irqrestore(&dev->wl->beacon_lock, flags);
+
+ if (!beacon_skb) {
+ b43dbg(dev->wl, "Could not upload beacon. "
+ "Failed to clone beacon skb.");
+ return;
+ }
+
+ bcn = (const struct ieee80211_mgmt *)(beacon_skb->data);
+ len = min_t(size_t, beacon_skb->len,
+ 0x200 - sizeof(struct b43_plcp_hdr6));
b43_write_template_common(dev, (const u8 *)bcn,
len, ram_offset, shm_size_offset, rate);
@@ -1674,6 +1705,8 @@ static void b43_write_beacon_template(struct b43_wldev *dev,
B43_SHM_SH_DTIMPER, 0);
}
b43dbg(dev->wl, "Updated beacon template at 0x%x\n", ram_offset);
+
+ dev_kfree_skb_any(beacon_skb);
}
static void b43_upload_beacon0(struct b43_wldev *dev)
@@ -1790,13 +1823,13 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
mutex_unlock(&wl->mutex);
}
-/* Asynchronously update the packet templates in template RAM.
- * Locking: Requires wl->mutex to be locked. */
+/* Asynchronously update the packet templates in template RAM. */
static void b43_update_templates(struct b43_wl *wl)
{
- struct sk_buff *beacon;
+ struct sk_buff *beacon, *old_beacon;
+ unsigned long flags;
- /* This is the top half of the ansynchronous beacon update.
+ /* This is the top half of the asynchronous beacon update.
* The bottom half is the beacon IRQ.
* Beacon update must be asynchronous to avoid sending an
* invalid beacon. This can happen for example, if the firmware
@@ -1810,12 +1843,17 @@ static void b43_update_templates(struct b43_wl *wl)
if (unlikely(!beacon))
return;
- if (wl->current_beacon)
- dev_kfree_skb_any(wl->current_beacon);
+ spin_lock_irqsave(&wl->beacon_lock, flags);
+ old_beacon = wl->current_beacon;
wl->current_beacon = beacon;
wl->beacon0_uploaded = false;
wl->beacon1_uploaded = false;
+ spin_unlock_irqrestore(&wl->beacon_lock, flags);
+
ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
+
+ if (old_beacon)
+ dev_kfree_skb_any(old_beacon);
}
static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
@@ -4318,6 +4356,7 @@ redo:
mutex_unlock(&wl->mutex);
cancel_delayed_work_sync(&dev->periodic_work);
cancel_work_sync(&wl->tx_work);
+ b43_leds_stop(dev);
mutex_lock(&wl->mutex);
dev = wl->current_dev;
if (!dev || b43_status(dev) < B43_STAT_STARTED) {
@@ -4505,6 +4544,12 @@ static int b43_phy_versioning(struct b43_wldev *dev)
unsupported = 1;
break;
#endif
+#ifdef CONFIG_B43_PHY_AC
+ case B43_PHYTYPE_AC:
+ if (phy_rev > 1)
+ unsupported = 1;
+ break;
+#endif
default:
unsupported = 1;
}
@@ -4601,6 +4646,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
if (radio_id != 0x2064)
unsupported = 1;
break;
+ case B43_PHYTYPE_AC:
+ if (radio_id != 0x2069)
+ unsupported = 1;
+ break;
default:
B43_WARN_ON(1);
}
@@ -5094,7 +5143,6 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
{
struct b43_wl *wl = hw_to_b43_wl(hw);
- /* FIXME: add locking */
b43_update_templates(wl);
return 0;
@@ -5584,6 +5632,7 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev)
wl->hw = hw;
mutex_init(&wl->mutex);
spin_lock_init(&wl->hardirq_lock);
+ spin_lock_init(&wl->beacon_lock);
INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
INIT_WORK(&wl->tx_work, b43_tx_work);
diff --git a/drivers/net/wireless/b43/phy_ac.c b/drivers/net/wireless/b43/phy_ac.c
new file mode 100644
index 000000000000..e75633d67938
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_ac.c
@@ -0,0 +1,92 @@
+/*
+ * Broadcom B43 wireless driver
+ * IEEE 802.11ac AC-PHY support
+ *
+ * Copyright (c) 2015 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include "b43.h"
+#include "phy_ac.h"
+
+/**************************************************
+ * Basic PHY ops
+ **************************************************/
+
+static int b43_phy_ac_op_allocate(struct b43_wldev *dev)
+{
+ struct b43_phy_ac *phy_ac;
+
+ phy_ac = kzalloc(sizeof(*phy_ac), GFP_KERNEL);
+ if (!phy_ac)
+ return -ENOMEM;
+ dev->phy.ac = phy_ac;
+
+ return 0;
+}
+
+static void b43_phy_ac_op_free(struct b43_wldev *dev)
+{
+ struct b43_phy *phy = &dev->phy;
+ struct b43_phy_ac *phy_ac = phy->ac;
+
+ kfree(phy_ac);
+ phy->ac = NULL;
+}
+
+static void b43_phy_ac_op_maskset(struct b43_wldev *dev, u16 reg, u16 mask,
+ u16 set)
+{
+ b43_write16f(dev, B43_MMIO_PHY_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_PHY_DATA,
+ (b43_read16(dev, B43_MMIO_PHY_DATA) & mask) | set);
+}
+
+static u16 b43_phy_ac_op_radio_read(struct b43_wldev *dev, u16 reg)
+{
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ return b43_read16(dev, B43_MMIO_RADIO24_DATA);
+}
+
+static void b43_phy_ac_op_radio_write(struct b43_wldev *dev, u16 reg,
+ u16 value)
+{
+ b43_write16f(dev, B43_MMIO_RADIO24_CONTROL, reg);
+ b43_write16(dev, B43_MMIO_RADIO24_DATA, value);
+}
+
+static unsigned int b43_phy_ac_op_get_default_chan(struct b43_wldev *dev)
+{
+ if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+ return 11;
+ return 36;
+}
+
+static enum b43_txpwr_result
+b43_phy_ac_op_recalc_txpower(struct b43_wldev *dev, bool ignore_tssi)
+{
+ return B43_TXPWR_RES_DONE;
+}
+
+static void b43_phy_ac_op_adjust_txpower(struct b43_wldev *dev)
+{
+}
+
+/**************************************************
+ * PHY ops struct
+ **************************************************/
+
+const struct b43_phy_operations b43_phyops_ac = {
+ .allocate = b43_phy_ac_op_allocate,
+ .free = b43_phy_ac_op_free,
+ .phy_maskset = b43_phy_ac_op_maskset,
+ .radio_read = b43_phy_ac_op_radio_read,
+ .radio_write = b43_phy_ac_op_radio_write,
+ .get_default_chan = b43_phy_ac_op_get_default_chan,
+ .recalc_txpower = b43_phy_ac_op_recalc_txpower,
+ .adjust_txpower = b43_phy_ac_op_adjust_txpower,
+};
diff --git a/drivers/net/wireless/b43/phy_ac.h b/drivers/net/wireless/b43/phy_ac.h
new file mode 100644
index 000000000000..d1ca79e0eb24
--- /dev/null
+++ b/drivers/net/wireless/b43/phy_ac.h
@@ -0,0 +1,38 @@
+#ifndef B43_PHY_AC_H_
+#define B43_PHY_AC_H_
+
+#include "phy_common.h"
+
+#define B43_PHY_AC_BBCFG 0x001
+#define B43_PHY_AC_BBCFG_RSTCCA 0x4000 /* Reset CCA */
+#define B43_PHY_AC_BANDCTL 0x003 /* Band control */
+#define B43_PHY_AC_BANDCTL_5GHZ 0x0001
+#define B43_PHY_AC_TABLE_ID 0x00d
+#define B43_PHY_AC_TABLE_OFFSET 0x00e
+#define B43_PHY_AC_TABLE_DATA1 0x00f
+#define B43_PHY_AC_TABLE_DATA2 0x010
+#define B43_PHY_AC_TABLE_DATA3 0x011
+#define B43_PHY_AC_CLASSCTL 0x140 /* Classifier control */
+#define B43_PHY_AC_CLASSCTL_CCKEN 0x0001 /* CCK enable */
+#define B43_PHY_AC_CLASSCTL_OFDMEN 0x0002 /* OFDM enable */
+#define B43_PHY_AC_CLASSCTL_WAITEDEN 0x0004 /* Waited enable */
+#define B43_PHY_AC_BW1A 0x371
+#define B43_PHY_AC_BW2 0x372
+#define B43_PHY_AC_BW3 0x373
+#define B43_PHY_AC_BW4 0x374
+#define B43_PHY_AC_BW5 0x375
+#define B43_PHY_AC_BW6 0x376
+#define B43_PHY_AC_RFCTL_CMD 0x408
+#define B43_PHY_AC_C1_CLIP 0x6d4
+#define B43_PHY_AC_C1_CLIP_DIS 0x4000
+#define B43_PHY_AC_C2_CLIP 0x8d4
+#define B43_PHY_AC_C2_CLIP_DIS 0x4000
+#define B43_PHY_AC_C3_CLIP 0xad4
+#define B43_PHY_AC_C3_CLIP_DIS 0x4000
+
+struct b43_phy_ac {
+};
+
+extern const struct b43_phy_operations b43_phyops_ac;
+
+#endif /* B43_PHY_AC_H_ */
diff --git a/drivers/net/wireless/b43/phy_common.c b/drivers/net/wireless/b43/phy_common.c
index ee27b06074e1..ec2b9c577b90 100644
--- a/drivers/net/wireless/b43/phy_common.c
+++ b/drivers/net/wireless/b43/phy_common.c
@@ -33,6 +33,7 @@
#include "phy_lp.h"
#include "phy_ht.h"
#include "phy_lcn.h"
+#include "phy_ac.h"
#include "b43.h"
#include "main.h"
@@ -70,6 +71,11 @@ int b43_phy_allocate(struct b43_wldev *dev)
phy->ops = &b43_phyops_lcn;
#endif
break;
+ case B43_PHYTYPE_AC:
+#ifdef CONFIG_B43_PHY_AC
+ phy->ops = &b43_phyops_ac;
+#endif
+ break;
}
if (B43_WARN_ON(!phy->ops))
return -ENODEV;
@@ -572,7 +578,8 @@ void b43_phy_force_clock(struct b43_wldev *dev, bool force)
u32 tmp;
WARN_ON(dev->phy.type != B43_PHYTYPE_N &&
- dev->phy.type != B43_PHYTYPE_HT);
+ dev->phy.type != B43_PHYTYPE_HT &&
+ dev->phy.type != B43_PHYTYPE_AC);
switch (dev->dev->bus_type) {
#ifdef CONFIG_B43_BCMA
diff --git a/drivers/net/wireless/b43/phy_common.h b/drivers/net/wireless/b43/phy_common.h
index 3912274f71e3..78d86526799e 100644
--- a/drivers/net/wireless/b43/phy_common.h
+++ b/drivers/net/wireless/b43/phy_common.h
@@ -222,6 +222,8 @@ struct b43_phy {
struct b43_phy_ht *ht;
/* LCN-PHY specific information */
struct b43_phy_lcn *lcn;
+ /* AC-PHY specific information */
+ struct b43_phy_ac *ac;
};
/* Band support flags. */
diff --git a/drivers/net/wireless/b43legacy/main.c b/drivers/net/wireless/b43legacy/main.c
index 1aec2146a2bf..4e58c0069830 100644
--- a/drivers/net/wireless/b43legacy/main.c
+++ b/drivers/net/wireless/b43legacy/main.c
@@ -86,7 +86,7 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
static const struct ssb_device_id b43legacy_ssb_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 4),
- SSB_DEVTABLE_END
+ {},
};
MODULE_DEVICE_TABLE(ssb, b43legacy_ssb_tbl);
diff --git a/drivers/net/wireless/b43legacy/radio.c b/drivers/net/wireless/b43legacy/radio.c
index 896177690394..9501420340a9 100644
--- a/drivers/net/wireless/b43legacy/radio.c
+++ b/drivers/net/wireless/b43legacy/radio.c
@@ -1743,25 +1743,6 @@ u16 freq_r3A_value(u16 frequency)
return value;
}
-void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev)
-{
- static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 };
- static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A };
- u16 tmp = b43legacy_radio_read16(dev, 0x001E);
- int i;
- int j;
-
- for (i = 0; i < 5; i++) {
- for (j = 0; j < 5; j++) {
- if (tmp == (data_high[i] | data_low[j])) {
- b43legacy_phy_write(dev, 0x0069, (i - j) << 8 |
- 0x00C0);
- return;
- }
- }
- }
-}
-
int b43legacy_radio_selectchannel(struct b43legacy_wldev *dev,
u8 channel,
int synthetic_pu_workaround)
diff --git a/drivers/net/wireless/b43legacy/radio.h b/drivers/net/wireless/b43legacy/radio.h
index bccb3d7da682..dd2976d1d561 100644
--- a/drivers/net/wireless/b43legacy/radio.h
+++ b/drivers/net/wireless/b43legacy/radio.h
@@ -92,7 +92,6 @@ void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val);
void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val);
void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev);
-void b43legacy_radio_set_tx_iq(struct b43legacy_wldev *dev);
u16 b43legacy_radio_calibrationvalue(struct b43legacy_wldev *dev);
#endif /* B43legacy_RADIO_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
index 9880dae2a569..7944224e3fc9 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
@@ -97,25 +97,6 @@ static void brcmf_sdiod_dummy_irqhandler(struct sdio_func *func)
{
}
-static bool brcmf_sdiod_pm_resume_error(struct brcmf_sdio_dev *sdiodev)
-{
- bool is_err = false;
-#ifdef CONFIG_PM_SLEEP
- is_err = atomic_read(&sdiodev->suspend);
-#endif
- return is_err;
-}
-
-static void brcmf_sdiod_pm_resume_wait(struct brcmf_sdio_dev *sdiodev,
- wait_queue_head_t *wq)
-{
-#ifdef CONFIG_PM_SLEEP
- int retry = 0;
- while (atomic_read(&sdiodev->suspend) && retry++ != 30)
- wait_event_timeout(*wq, false, HZ/100);
-#endif
-}
-
int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev)
{
int ret = 0;
@@ -244,10 +225,6 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
brcmf_dbg(SDIO, "rw=%d, func=%d, addr=0x%05x, nbytes=%d\n",
write, fn, addr, regsz);
- brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_word_wait);
- if (brcmf_sdiod_pm_resume_error(sdiodev))
- return -EIO;
-
/* only allow byte access on F0 */
if (WARN_ON(regsz > 1 && !fn))
return -EINVAL;
@@ -292,6 +269,12 @@ static int brcmf_sdiod_request_data(struct brcmf_sdio_dev *sdiodev, u8 fn,
return ret;
}
+static void brcmf_sdiod_nomedium_state(struct brcmf_sdio_dev *sdiodev)
+{
+ sdiodev->state = BRCMF_STATE_NOMEDIUM;
+ brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_DOWN);
+}
+
static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 regsz, void *data, bool write)
{
@@ -299,7 +282,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
s32 retry = 0;
int ret;
- if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+ if (sdiodev->state == BRCMF_STATE_NOMEDIUM)
return -ENOMEDIUM;
/*
@@ -325,7 +308,7 @@ static int brcmf_sdiod_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
if (ret == -ENOMEDIUM)
- brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+ brcmf_sdiod_nomedium_state(sdiodev);
else if (ret != 0) {
/*
* SleepCSR register access can fail when
@@ -348,7 +331,7 @@ brcmf_sdiod_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
int err = 0, i;
u8 addr[3];
- if (sdiodev->bus_if->state == BRCMF_BUS_NOMEDIUM)
+ if (sdiodev->state == BRCMF_STATE_NOMEDIUM)
return -ENOMEDIUM;
addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
@@ -462,10 +445,6 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
unsigned int req_sz;
int err;
- brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
- if (brcmf_sdiod_pm_resume_error(sdiodev))
- return -EIO;
-
/* Single skb use the standard mmc interface */
req_sz = pkt->len + 3;
req_sz &= (uint)~3;
@@ -481,7 +460,7 @@ static int brcmf_sdiod_buffrw(struct brcmf_sdio_dev *sdiodev, uint fn,
err = sdio_readsb(sdiodev->func[fn], ((u8 *)(pkt->data)), addr,
req_sz);
if (err == -ENOMEDIUM)
- brcmf_bus_change_state(sdiodev->bus_if, BRCMF_BUS_NOMEDIUM);
+ brcmf_sdiod_nomedium_state(sdiodev);
return err;
}
@@ -516,10 +495,6 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
if (!pktlist->qlen)
return -EINVAL;
- brcmf_sdiod_pm_resume_wait(sdiodev, &sdiodev->request_buffer_wait);
- if (brcmf_sdiod_pm_resume_error(sdiodev))
- return -EIO;
-
target_list = pktlist;
/* for host with broken sg support, prepare a page aligned list */
__skb_queue_head_init(&local_list);
@@ -620,8 +595,7 @@ static int brcmf_sdiod_sglist_rw(struct brcmf_sdio_dev *sdiodev, uint fn,
ret = mmc_cmd.error ? mmc_cmd.error : mmc_dat.error;
if (ret == -ENOMEDIUM) {
- brcmf_bus_change_state(sdiodev->bus_if,
- BRCMF_BUS_NOMEDIUM);
+ brcmf_sdiod_nomedium_state(sdiodev);
break;
} else if (ret != 0) {
brcmf_err("CMD53 sg block %s failed %d\n",
@@ -996,18 +970,20 @@ out:
}
#define BRCMF_SDIO_DEVICE(dev_id) \
- {SDIO_DEVICE(BRCM_SDIO_VENDOR_ID_BROADCOM, dev_id)}
+ {SDIO_DEVICE(SDIO_VENDOR_ID_BROADCOM, dev_id)}
/* devices we support, null terminated */
static const struct sdio_device_id brcmf_sdmmc_ids[] = {
- BRCMF_SDIO_DEVICE(BRCM_SDIO_43143_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_43241_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_4329_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_4330_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_4334_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_43362_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_4335_4339_DEVICE_ID),
- BRCMF_SDIO_DEVICE(BRCM_SDIO_4354_DEVICE_ID),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43143),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43241),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4329),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4330),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4334),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43340),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43341),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43362),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4335_4339),
+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354),
{ /* end: all zeroes */ }
};
MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids);
@@ -1074,9 +1050,9 @@ static int brcmf_ops_sdio_probe(struct sdio_func *func,
bus_if->wowl_supported = true;
#endif
+ sdiodev->sleeping = false;
atomic_set(&sdiodev->suspend, false);
- init_waitqueue_head(&sdiodev->request_word_wait);
- init_waitqueue_head(&sdiodev->request_buffer_wait);
+ init_waitqueue_head(&sdiodev->idle_wait);
brcmf_dbg(SDIO, "F2 found, calling brcmf_sdiod_probe...\n");
err = brcmf_sdiod_probe(sdiodev);
@@ -1138,12 +1114,23 @@ void brcmf_sdio_wowl_config(struct device *dev, bool enabled)
#ifdef CONFIG_PM_SLEEP
static int brcmf_ops_sdio_suspend(struct device *dev)
{
- struct brcmf_bus *bus_if = dev_get_drvdata(dev);
- struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
+ struct brcmf_bus *bus_if;
+ struct brcmf_sdio_dev *sdiodev;
mmc_pm_flag_t sdio_flags;
brcmf_dbg(SDIO, "Enter\n");
+ bus_if = dev_get_drvdata(dev);
+ sdiodev = bus_if->bus_priv.sdio;
+
+ /* wait for watchdog to go idle */
+ if (wait_event_timeout(sdiodev->idle_wait, sdiodev->sleeping,
+ msecs_to_jiffies(3 * BRCMF_WD_POLL_MS)) == 0) {
+ brcmf_err("bus still active\n");
+ return -EBUSY;
+ }
+ /* disable watchdog */
+ brcmf_sdio_wd_timer(sdiodev->bus, 0);
atomic_set(&sdiodev->suspend, true);
if (sdiodev->wowl_enabled) {
@@ -1155,9 +1142,6 @@ static int brcmf_ops_sdio_suspend(struct device *dev)
if (sdio_set_host_pm_flags(sdiodev->func[1], sdio_flags))
brcmf_err("Failed to set pm_flags %x\n", sdio_flags);
}
-
- brcmf_sdio_wd_timer(sdiodev->bus, 0);
-
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/bus.h b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
index ef344e47218a..89e6a4dc105e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/bus.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/bus.h
@@ -33,11 +33,8 @@
/* The level of bus communication with the dongle */
enum brcmf_bus_state {
- BRCMF_BUS_UNKNOWN, /* Not determined yet */
- BRCMF_BUS_NOMEDIUM, /* No medium access to dongle */
BRCMF_BUS_DOWN, /* Not ready for frame transfers */
- BRCMF_BUS_LOAD, /* Download access only (CPU reset) */
- BRCMF_BUS_DATA /* Ready for frame transfers */
+ BRCMF_BUS_UP /* Ready for frame transfers */
};
/* The level of bus communication with the dongle */
@@ -188,22 +185,6 @@ void brcmf_bus_wowl_config(struct brcmf_bus *bus, bool enabled)
bus->ops->wowl_config(bus->dev, enabled);
}
-static inline bool brcmf_bus_ready(struct brcmf_bus *bus)
-{
- return bus->state == BRCMF_BUS_LOAD || bus->state == BRCMF_BUS_DATA;
-}
-
-static inline void brcmf_bus_change_state(struct brcmf_bus *bus,
- enum brcmf_bus_state new_state)
-{
- /* NOMEDIUM is permanent */
- if (bus->state == BRCMF_BUS_NOMEDIUM)
- return;
-
- brcmf_dbg(TRACE, "%d -> %d\n", bus->state, new_state);
- bus->state = new_state;
-}
-
/*
* interface functions from common layer
*/
@@ -226,6 +207,9 @@ void brcmf_txflowblock(struct device *dev, bool state);
/* Notify the bus has transferred the tx packet to firmware */
void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success);
+/* Configure the "global" bus state used by upper layers */
+void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state);
+
int brcmf_bus_start(struct device *dev);
s32 brcmf_iovar_data_set(struct device *dev, char *name, void *data, u32 len);
void brcmf_bus_add_txhdrlen(struct device *dev, uint len);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
index 3aecc5f48719..b59b8c6c42ab 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.c
@@ -38,6 +38,7 @@
#include "proto.h"
#include "vendor.h"
#include "bus.h"
+#include "common.h"
#define BRCMF_SCAN_IE_LEN_MAX 2048
#define BRCMF_PNO_VERSION 2
@@ -452,16 +453,16 @@ static void convert_key_from_CPU(struct brcmf_wsec_key *key,
}
static int
-send_key_to_dongle(struct net_device *ndev, struct brcmf_wsec_key *key)
+send_key_to_dongle(struct brcmf_if *ifp, struct brcmf_wsec_key *key)
{
int err;
struct brcmf_wsec_key_le key_le;
convert_key_from_CPU(key, &key_le);
- brcmf_netdev_wait_pend8021x(ndev);
+ brcmf_netdev_wait_pend8021x(ifp);
- err = brcmf_fil_bsscfg_data_set(netdev_priv(ndev), "wsec_key", &key_le,
+ err = brcmf_fil_bsscfg_data_set(ifp, "wsec_key", &key_le,
sizeof(key_le));
if (err)
@@ -1228,7 +1229,25 @@ static void brcmf_init_prof(struct brcmf_cfg80211_profile *prof)
memset(prof, 0, sizeof(*prof));
}
-static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
+static u16 brcmf_map_fw_linkdown_reason(const struct brcmf_event_msg *e)
+{
+ u16 reason;
+
+ switch (e->event_code) {
+ case BRCMF_E_DEAUTH:
+ case BRCMF_E_DEAUTH_IND:
+ case BRCMF_E_DISASSOC_IND:
+ reason = e->reason;
+ break;
+ case BRCMF_E_LINK:
+ default:
+ reason = 0;
+ break;
+ }
+ return reason;
+}
+
+static void brcmf_link_down(struct brcmf_cfg80211_vif *vif, u16 reason)
{
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(vif->wdev.wiphy);
s32 err = 0;
@@ -1243,7 +1262,8 @@ static void brcmf_link_down(struct brcmf_cfg80211_vif *vif)
brcmf_err("WLC_DISASSOC failed (%d)\n", err);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTED, &vif->sme_state);
- cfg80211_disconnected(vif->wdev.netdev, 0, NULL, 0, GFP_KERNEL);
+ cfg80211_disconnected(vif->wdev.netdev, reason, NULL, 0,
+ GFP_KERNEL);
}
clear_bit(BRCMF_VIF_STATUS_CONNECTING, &vif->sme_state);
@@ -1413,7 +1433,7 @@ brcmf_cfg80211_leave_ibss(struct wiphy *wiphy, struct net_device *ndev)
if (!check_vif_up(ifp->vif))
return -EIO;
- brcmf_link_down(ifp->vif);
+ brcmf_link_down(ifp->vif, WLAN_REASON_DEAUTH_LEAVING);
brcmf_dbg(TRACE, "Exit\n");
@@ -1670,7 +1690,7 @@ brcmf_set_sharedkey(struct net_device *ndev,
brcmf_dbg(CONN, "key length (%d) key index (%d) algo (%d)\n",
key.len, key.index, key.algo);
brcmf_dbg(CONN, "key \"%s\"\n", key.data);
- err = send_key_to_dongle(ndev, &key);
+ err = send_key_to_dongle(netdev_priv(ndev), &key);
if (err)
return err;
@@ -2052,7 +2072,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
/* check for key index change */
if (key.len == 0) {
/* key delete */
- err = send_key_to_dongle(ndev, &key);
+ err = send_key_to_dongle(ifp, &key);
if (err)
brcmf_err("key delete error (%d)\n", err);
} else {
@@ -2108,7 +2128,7 @@ brcmf_add_keyext(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("Invalid cipher (0x%x)\n", params->cipher);
return -EINVAL;
}
- err = send_key_to_dongle(ndev, &key);
+ err = send_key_to_dongle(ifp, &key);
if (err)
brcmf_err("wsec_key error (%d)\n", err);
}
@@ -2121,7 +2141,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
struct key_params *params)
{
struct brcmf_if *ifp = netdev_priv(ndev);
- struct brcmf_wsec_key key;
+ struct brcmf_wsec_key *key;
s32 val;
s32 wsec;
s32 err = 0;
@@ -2132,54 +2152,62 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
if (!check_vif_up(ifp->vif))
return -EIO;
+ if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
+ /* we ignore this key index in this case */
+ brcmf_err("invalid key index (%d)\n", key_idx);
+ return -EINVAL;
+ }
+
if (mac_addr &&
(params->cipher != WLAN_CIPHER_SUITE_WEP40) &&
(params->cipher != WLAN_CIPHER_SUITE_WEP104)) {
brcmf_dbg(TRACE, "Exit");
return brcmf_add_keyext(wiphy, ndev, key_idx, mac_addr, params);
}
- memset(&key, 0, sizeof(key));
- key.len = (u32) params->key_len;
- key.index = (u32) key_idx;
+ key = &ifp->vif->profile.key[key_idx];
+ memset(key, 0, sizeof(*key));
- if (key.len > sizeof(key.data)) {
- brcmf_err("Too long key length (%u)\n", key.len);
+ if (params->key_len > sizeof(key->data)) {
+ brcmf_err("Too long key length (%u)\n", params->key_len);
err = -EINVAL;
goto done;
}
- memcpy(key.data, params->key, key.len);
+ key->len = params->key_len;
+ key->index = key_idx;
- key.flags = BRCMF_PRIMARY_KEY;
+ memcpy(key->data, params->key, key->len);
+
+ key->flags = BRCMF_PRIMARY_KEY;
switch (params->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
- key.algo = CRYPTO_ALGO_WEP1;
+ key->algo = CRYPTO_ALGO_WEP1;
val = WEP_ENABLED;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP40\n");
break;
case WLAN_CIPHER_SUITE_WEP104:
- key.algo = CRYPTO_ALGO_WEP128;
+ key->algo = CRYPTO_ALGO_WEP128;
val = WEP_ENABLED;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_WEP104\n");
break;
case WLAN_CIPHER_SUITE_TKIP:
if (!brcmf_is_apmode(ifp->vif)) {
brcmf_dbg(CONN, "Swapping RX/TX MIC key\n");
- memcpy(keybuf, &key.data[24], sizeof(keybuf));
- memcpy(&key.data[24], &key.data[16], sizeof(keybuf));
- memcpy(&key.data[16], keybuf, sizeof(keybuf));
+ memcpy(keybuf, &key->data[24], sizeof(keybuf));
+ memcpy(&key->data[24], &key->data[16], sizeof(keybuf));
+ memcpy(&key->data[16], keybuf, sizeof(keybuf));
}
- key.algo = CRYPTO_ALGO_TKIP;
+ key->algo = CRYPTO_ALGO_TKIP;
val = TKIP_ENABLED;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_TKIP\n");
break;
case WLAN_CIPHER_SUITE_AES_CMAC:
- key.algo = CRYPTO_ALGO_AES_CCM;
+ key->algo = CRYPTO_ALGO_AES_CCM;
val = AES_ENABLED;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_AES_CMAC\n");
break;
case WLAN_CIPHER_SUITE_CCMP:
- key.algo = CRYPTO_ALGO_AES_CCM;
+ key->algo = CRYPTO_ALGO_AES_CCM;
val = AES_ENABLED;
brcmf_dbg(CONN, "WLAN_CIPHER_SUITE_CCMP\n");
break;
@@ -2189,7 +2217,7 @@ brcmf_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
goto done;
}
- err = send_key_to_dongle(ndev, &key);
+ err = send_key_to_dongle(ifp, key);
if (err)
goto done;
@@ -2222,7 +2250,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
if (!check_vif_up(ifp->vif))
return -EIO;
- if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
+ if (key_idx >= BRCMF_MAX_DEFAULT_KEYS) {
/* we ignore this key index in this case */
brcmf_err("invalid key index (%d)\n", key_idx);
return -EINVAL;
@@ -2237,7 +2265,7 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "key index (%d)\n", key_idx);
/* Set the new key/index */
- err = send_key_to_dongle(ndev, &key);
+ err = send_key_to_dongle(ifp, &key);
brcmf_dbg(TRACE, "Exit\n");
return err;
@@ -2305,6 +2333,39 @@ brcmf_cfg80211_config_default_mgmt_key(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
+static void
+brcmf_cfg80211_reconfigure_wep(struct brcmf_if *ifp)
+{
+ s32 err;
+ u8 key_idx;
+ struct brcmf_wsec_key *key;
+ s32 wsec;
+
+ for (key_idx = 0; key_idx < BRCMF_MAX_DEFAULT_KEYS; key_idx++) {
+ key = &ifp->vif->profile.key[key_idx];
+ if ((key->algo == CRYPTO_ALGO_WEP1) ||
+ (key->algo == CRYPTO_ALGO_WEP128))
+ break;
+ }
+ if (key_idx == BRCMF_MAX_DEFAULT_KEYS)
+ return;
+
+ err = send_key_to_dongle(ifp, key);
+ if (err) {
+ brcmf_err("Setting WEP key failed (%d)\n", err);
+ return;
+ }
+ err = brcmf_fil_bsscfg_int_get(ifp, "wsec", &wsec);
+ if (err) {
+ brcmf_err("get wsec error (%d)\n", err);
+ return;
+ }
+ wsec |= WEP_ENABLED;
+ err = brcmf_fil_bsscfg_int_set(ifp, "wsec", wsec);
+ if (err)
+ brcmf_err("set wsec error (%d)\n", err);
+}
+
static s32
brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
const u8 *mac, struct station_info *sinfo)
@@ -2333,10 +2394,10 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("GET STA INFO failed, %d\n", err);
goto done;
}
- sinfo->filled = STATION_INFO_INACTIVE_TIME;
+ sinfo->filled = BIT(NL80211_STA_INFO_INACTIVE_TIME);
sinfo->inactive_time = le32_to_cpu(sta_info_le.idle) * 1000;
if (le32_to_cpu(sta_info_le.flags) & BRCMF_STA_ASSOC) {
- sinfo->filled |= STATION_INFO_CONNECTED_TIME;
+ sinfo->filled |= BIT(NL80211_STA_INFO_CONNECTED_TIME);
sinfo->connected_time = le32_to_cpu(sta_info_le.in);
}
brcmf_dbg(TRACE, "STA idle time : %d ms, connected time :%d sec\n",
@@ -2354,7 +2415,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("Could not get rate (%d)\n", err);
goto done;
} else {
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
sinfo->txrate.legacy = rate * 5;
brcmf_dbg(CONN, "Rate %d Mbps\n", rate / 2);
}
@@ -2369,7 +2430,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
goto done;
} else {
rssi = le32_to_cpu(scb_val.val);
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
sinfo->signal = rssi;
brcmf_dbg(CONN, "RSSI %d dBm\n", rssi);
}
@@ -2396,7 +2457,7 @@ brcmf_cfg80211_get_station(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(CONN, "DTIM peroid %d\n",
dtim_period);
}
- sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
}
} else
err = -EPERM;
@@ -2999,7 +3060,7 @@ static s32 brcmf_cfg80211_suspend(struct wiphy *wiphy,
* disassociate from AP to save power while system is
* in suspended state
*/
- brcmf_link_down(vif);
+ brcmf_link_down(vif, WLAN_REASON_UNSPECIFIED);
/* Make sure WPA_Supplicant receives all the event
* generated due to DISASSOC call to the fw to keep
* the state fw and WPA_Supplicant state consistent
@@ -3695,17 +3756,12 @@ static u32
brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
{
- __le32 iecount_le;
- __le32 pktflag_le;
-
strncpy(iebuf, add_del_cmd, VNDR_IE_CMD_LEN - 1);
iebuf[VNDR_IE_CMD_LEN - 1] = '\0';
- iecount_le = cpu_to_le32(1);
- memcpy(&iebuf[VNDR_IE_COUNT_OFFSET], &iecount_le, sizeof(iecount_le));
+ put_unaligned_le32(1, &iebuf[VNDR_IE_COUNT_OFFSET]);
- pktflag_le = cpu_to_le32(pktflag);
- memcpy(&iebuf[VNDR_IE_PKTFLAG_OFFSET], &pktflag_le, sizeof(pktflag_le));
+ put_unaligned_le32(pktflag, &iebuf[VNDR_IE_PKTFLAG_OFFSET]);
memcpy(&iebuf[VNDR_IE_VSIE_OFFSET], ie_ptr, ie_len);
@@ -3924,6 +3980,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
struct brcmf_if *ifp = netdev_priv(ndev);
const struct brcmf_tlv *ssid_ie;
+ const struct brcmf_tlv *country_ie;
struct brcmf_ssid_le ssid_le;
s32 err = -EPERM;
const struct brcmf_tlv *rsn_ie;
@@ -3933,6 +3990,7 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
struct brcmf_fil_bss_enable_le bss_enable;
u16 chanspec;
bool mbss;
+ int is_11d;
brcmf_dbg(TRACE, "ctrlchn=%d, center=%d, bw=%d, beacon_interval=%d, dtim_period=%d,\n",
settings->chandef.chan->hw_value,
@@ -3941,10 +3999,16 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_dbg(TRACE, "ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
settings->ssid, settings->ssid_len, settings->auth_type,
settings->inactivity_timeout);
-
dev_role = ifp->vif->wdev.iftype;
mbss = ifp->vif->mbss;
+ /* store current 11d setting */
+ brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_REGULATORY, &ifp->vif->is_11d);
+ country_ie = brcmf_parse_tlvs((u8 *)settings->beacon.tail,
+ settings->beacon.tail_len,
+ WLAN_EID_COUNTRY);
+ is_11d = country_ie ? 1 : 0;
+
memset(&ssid_le, 0, sizeof(ssid_le));
if (settings->ssid == NULL || settings->ssid_len == 0) {
ie_offset = DOT11_MGMT_HDR_LEN + DOT11_BCN_PRB_FIXED_LEN;
@@ -4010,6 +4074,14 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
goto exit;
}
+ if (is_11d != ifp->vif->is_11d) {
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
+ is_11d);
+ if (err < 0) {
+ brcmf_err("Regulatory Set Error, %d\n", err);
+ goto exit;
+ }
+ }
if (settings->beacon_interval) {
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD,
settings->beacon_interval);
@@ -4042,6 +4114,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("SET INFRA error %d\n", err);
goto exit;
}
+ } else if (WARN_ON(is_11d != ifp->vif->is_11d)) {
+ /* Multiple-BSS should use same 11d configuration */
+ err = -EINVAL;
+ goto exit;
}
if (dev_role == NL80211_IFTYPE_AP) {
if ((brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) && (!mbss))
@@ -4057,6 +4133,10 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
brcmf_err("BRCMF_C_UP error (%d)\n", err);
goto exit;
}
+ /* On DOWN the firmware removes the WEP keys, reconfigure
+ * them if they were set.
+ */
+ brcmf_cfg80211_reconfigure_wep(ifp);
memset(&join_params, 0, sizeof(join_params));
/* join parameters starts with ssid */
@@ -4133,6 +4213,11 @@ static int brcmf_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *ndev)
brcmf_err("setting INFRA mode failed %d\n", err);
if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS))
brcmf_fil_iovar_int_set(ifp, "mbss", 0);
+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_REGULATORY,
+ ifp->vif->is_11d);
+ if (err < 0)
+ brcmf_err("restoring REGULATORY setting failed %d\n",
+ err);
/* Bring device back up so it can be used again */
err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 1);
if (err < 0)
@@ -4197,6 +4282,34 @@ brcmf_cfg80211_del_station(struct wiphy *wiphy, struct net_device *ndev,
return err;
}
+static int
+brcmf_cfg80211_change_station(struct wiphy *wiphy, struct net_device *ndev,
+ const u8 *mac, struct station_parameters *params)
+{
+ struct brcmf_if *ifp = netdev_priv(ndev);
+ s32 err;
+
+ brcmf_dbg(TRACE, "Enter, MAC %pM, mask 0x%04x set 0x%04x\n", mac,
+ params->sta_flags_mask, params->sta_flags_set);
+
+ /* Ignore all 00 MAC */
+ if (is_zero_ether_addr(mac))
+ return 0;
+
+ if (!(params->sta_flags_mask & BIT(NL80211_STA_FLAG_AUTHORIZED)))
+ return 0;
+
+ if (params->sta_flags_set & BIT(NL80211_STA_FLAG_AUTHORIZED))
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_AUTHORIZE,
+ (void *)mac, ETH_ALEN);
+ else
+ err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_SCB_DEAUTHORIZE,
+ (void *)mac, ETH_ALEN);
+ if (err < 0)
+ brcmf_err("Setting SCB (de-)authorize failed, %d\n", err);
+
+ return err;
+}
static void
brcmf_cfg80211_mgmt_frame_register(struct wiphy *wiphy,
@@ -4471,6 +4584,7 @@ static struct cfg80211_ops wl_cfg80211_ops = {
.stop_ap = brcmf_cfg80211_stop_ap,
.change_beacon = brcmf_cfg80211_change_beacon,
.del_station = brcmf_cfg80211_del_station,
+ .change_station = brcmf_cfg80211_change_station,
.sched_scan_start = brcmf_cfg80211_sched_scan_start,
.sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
.mgmt_frame_register = brcmf_cfg80211_mgmt_frame_register,
@@ -4778,7 +4892,6 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
if (((event == BRCMF_E_ASSOC_IND) || (event == BRCMF_E_REASSOC_IND)) &&
(reason == BRCMF_E_STATUS_SUCCESS)) {
memset(&sinfo, 0, sizeof(sinfo));
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
if (!data) {
brcmf_err("No IEs present in ASSOC/REASSOC_IND");
return -EINVAL;
@@ -4833,7 +4946,7 @@ brcmf_notify_connect_status(struct brcmf_if *ifp,
if (!brcmf_is_ibssmode(ifp->vif)) {
brcmf_bss_connect_done(cfg, ndev, e, false);
}
- brcmf_link_down(ifp->vif);
+ brcmf_link_down(ifp->vif, brcmf_map_fw_linkdown_reason(e));
brcmf_init_prof(ndev_to_prof(ndev));
if (ndev != cfg_to_ndev(cfg))
complete(&cfg->vif_disabled);
@@ -5774,7 +5887,7 @@ static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
* from AP to save power
*/
if (check_vif_up(ifp->vif)) {
- brcmf_link_down(ifp->vif);
+ brcmf_link_down(ifp->vif, WLAN_REASON_UNSPECIFIED);
/* Make sure WPA_Supplicant receives all the event
generated due to DISASSOC call to the fw to keep
@@ -5876,6 +5989,29 @@ int brcmf_cfg80211_wait_vif_event_timeout(struct brcmf_cfg80211_info *cfg,
vif_event_equals(event, action), timeout);
}
+static void brcmf_cfg80211_reg_notifier(struct wiphy *wiphy,
+ struct regulatory_request *req)
+{
+ struct brcmf_cfg80211_info *cfg = wiphy_priv(wiphy);
+ struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
+ struct brcmf_fil_country_le ccreq;
+ int i;
+
+ brcmf_dbg(TRACE, "enter: initiator=%d, alpha=%c%c\n", req->initiator,
+ req->alpha2[0], req->alpha2[1]);
+
+ /* ignore non-ISO3166 country codes */
+ for (i = 0; i < sizeof(req->alpha2); i++)
+ if (req->alpha2[i] < 'A' || req->alpha2[i] > 'Z') {
+ brcmf_err("not a ISO3166 code\n");
+ return;
+ }
+ memset(&ccreq, 0, sizeof(ccreq));
+ ccreq.rev = cpu_to_le32(-1);
+ memcpy(ccreq.ccode, req->alpha2, sizeof(req->alpha2));
+ brcmf_fil_iovar_data_set(ifp, "country", &ccreq, sizeof(ccreq));
+}
+
static void brcmf_free_wiphy(struct wiphy *wiphy)
{
kfree(wiphy->iface_combinations);
@@ -5952,6 +6088,7 @@ struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr,
goto priv_out;
brcmf_dbg(INFO, "Registering custom regulatory\n");
+ wiphy->reg_notifier = brcmf_cfg80211_reg_notifier;
wiphy->regulatory_flags |= REGULATORY_CUSTOM_REG;
wiphy_apply_custom_regulatory(wiphy, &brcmf_regdom);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
index 9e98b8d52757..d9e6d01b2b69 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/cfg80211.h
@@ -75,6 +75,8 @@
#define BRCMF_VNDR_IE_P2PAF_SHIFT 12
+#define BRCMF_MAX_DEFAULT_KEYS 4
+
/**
* enum brcmf_scan_status - scan engine status
@@ -125,11 +127,13 @@ struct brcmf_cfg80211_security {
* @ssid: ssid of associated/associating ap.
* @bssid: bssid of joined/joining ibss.
* @sec: security information.
+ * @key: key information
*/
struct brcmf_cfg80211_profile {
struct brcmf_ssid ssid;
u8 bssid[ETH_ALEN];
struct brcmf_cfg80211_security sec;
+ struct brcmf_wsec_key key[BRCMF_MAX_DEFAULT_KEYS];
};
/**
@@ -196,6 +200,7 @@ struct brcmf_cfg80211_vif {
struct list_head list;
u16 mgmt_rx_reg;
bool mbss;
+ int is_11d;
};
/* association inform */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
index ddae0b5e56ec..04d2ca0d87d6 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/chip.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/chip.c
@@ -101,14 +101,7 @@
/* ARM Cortex M3 core, ID 0x82a */
#define BCM4329_CORE_ARM_BASE 0x18002000
#define BCM4329_RAMSIZE 0x48000
-
/* bcm43143 */
-/* SDIO device core */
-#define BCM43143_CORE_BUS_BASE 0x18002000
-/* internal memory core */
-#define BCM43143_CORE_SOCRAM_BASE 0x18004000
-/* ARM Cortex M3 core, ID 0x82a */
-#define BCM43143_CORE_ARM_BASE 0x18003000
#define BCM43143_RAMSIZE 0x70000
#define CORE_SB(base, field) \
@@ -164,13 +157,6 @@ struct brcmf_core_priv {
struct brcmf_chip_priv *chip;
};
-/* ARM CR4 core specific control flag bits */
-#define ARMCR4_BCMA_IOCTL_CPUHALT 0x0020
-
-/* D11 core specific control flag bits */
-#define D11_BCMA_IOCTL_PHYCLOCKEN 0x0004
-#define D11_BCMA_IOCTL_PHYRESET 0x0008
-
struct brcmf_chip_priv {
struct brcmf_chip pub;
const struct brcmf_buscore_ops *ops;
@@ -495,6 +481,7 @@ static void brcmf_chip_get_raminfo(struct brcmf_chip_priv *ci)
ci->pub.ramsize = 0x48000;
break;
case BRCM_CC_4334_CHIP_ID:
+ case BRCM_CC_43340_CHIP_ID:
ci->pub.ramsize = 0x80000;
break;
case BRCM_CC_4335_CHIP_ID:
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.c b/drivers/net/wireless/brcm80211/brcmfmac/common.c
index 1861a13e8d03..fe54844c75e0 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/common.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/common.c
@@ -25,6 +25,9 @@
#include "fwil.h"
#include "fwil_types.h"
#include "tracepoint.h"
+#include "common.h"
+
+const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
#define BRCMF_DEFAULT_BCN_TIMEOUT 3
#define BRCMF_DEFAULT_SCAN_CHANNEL_TIME 40
@@ -38,6 +41,8 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
s8 eventmask[BRCMF_EVENTING_MASK_LEN];
u8 buf[BRCMF_DCMD_SMLEN];
struct brcmf_join_pref_params join_pref_params[2];
+ struct brcmf_rev_info_le revinfo;
+ struct brcmf_rev_info *ri;
char *ptr;
s32 err;
@@ -45,12 +50,37 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
sizeof(ifp->mac_addr));
if (err < 0) {
- brcmf_err("Retreiving cur_etheraddr failed, %d\n",
- err);
+ brcmf_err("Retreiving cur_etheraddr failed, %d\n", err);
goto done;
}
memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
+ err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_REVINFO,
+ &revinfo, sizeof(revinfo));
+ ri = &ifp->drvr->revinfo;
+ if (err < 0) {
+ brcmf_err("retrieving revision info failed, %d\n", err);
+ } else {
+ ri->vendorid = le32_to_cpu(revinfo.vendorid);
+ ri->deviceid = le32_to_cpu(revinfo.deviceid);
+ ri->radiorev = le32_to_cpu(revinfo.radiorev);
+ ri->chiprev = le32_to_cpu(revinfo.chiprev);
+ ri->corerev = le32_to_cpu(revinfo.corerev);
+ ri->boardid = le32_to_cpu(revinfo.boardid);
+ ri->boardvendor = le32_to_cpu(revinfo.boardvendor);
+ ri->boardrev = le32_to_cpu(revinfo.boardrev);
+ ri->driverrev = le32_to_cpu(revinfo.driverrev);
+ ri->ucoderev = le32_to_cpu(revinfo.ucoderev);
+ ri->bus = le32_to_cpu(revinfo.bus);
+ ri->chipnum = le32_to_cpu(revinfo.chipnum);
+ ri->phytype = le32_to_cpu(revinfo.phytype);
+ ri->phyrev = le32_to_cpu(revinfo.phyrev);
+ ri->anarev = le32_to_cpu(revinfo.anarev);
+ ri->chippkg = le32_to_cpu(revinfo.chippkg);
+ ri->nvramrev = le32_to_cpu(revinfo.nvramrev);
+ }
+ ri->result = err;
+
/* query for 'ver' to get version info from firmware */
memset(buf, 0, sizeof(buf));
strcpy(buf, "ver");
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/common.h b/drivers/net/wireless/brcm80211/brcmfmac/common.h
new file mode 100644
index 000000000000..0d39d80cee28
--- /dev/null
+++ b/drivers/net/wireless/brcm80211/brcmfmac/common.h
@@ -0,0 +1,20 @@
+/* Copyright (c) 2014 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef BRCMFMAC_COMMON_H
+#define BRCMFMAC_COMMON_H
+
+extern const u8 ALLFFMAC[ETH_ALEN];
+
+#endif /* BRCMFMAC_COMMON_H */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
index 002336e35764..3d404016a92e 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/commonring.h
@@ -37,6 +37,8 @@ struct brcmf_commonring {
unsigned long flags;
bool inited;
bool was_full;
+
+ atomic_t outstanding_tx;
};
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.c b/drivers/net/wireless/brcm80211/brcmfmac/core.c
index effe6d7831d9..2d6e2cc1b12c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.c
@@ -197,7 +197,7 @@ static netdev_tx_t brcmf_netdev_start_xmit(struct sk_buff *skb,
brcmf_dbg(DATA, "Enter, idx=%d\n", ifp->bssidx);
/* Can the device send data? */
- if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+ if (drvr->bus_if->state != BRCMF_BUS_UP) {
brcmf_err("xmit rejected state=%d\n", drvr->bus_if->state);
netif_stop_queue(ndev);
dev_kfree_skb(skb);
@@ -601,9 +601,12 @@ static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
{
struct brcmf_if *ifp = netdev_priv(ndev);
struct brcmf_pub *drvr = ifp->drvr;
+ char drev[BRCMU_DOTREV_LEN] = "n/a";
+ if (drvr->revinfo.result == 0)
+ brcmu_dotrev_str(drvr->revinfo.driverrev, drev);
strlcpy(info->driver, KBUILD_MODNAME, sizeof(info->driver));
- snprintf(info->version, sizeof(info->version), "n/a");
+ strlcpy(info->version, drev, sizeof(info->version));
strlcpy(info->fw_version, drvr->fwver, sizeof(info->fw_version));
strlcpy(info->bus_info, dev_name(drvr->bus_if->dev),
sizeof(info->bus_info));
@@ -637,7 +640,7 @@ static int brcmf_netdev_open(struct net_device *ndev)
brcmf_dbg(TRACE, "Enter, idx=%d\n", ifp->bssidx);
/* If bus is not ready, can't continue */
- if (bus_if->state != BRCMF_BUS_DATA) {
+ if (bus_if->state != BRCMF_BUS_UP) {
brcmf_err("failed bus is not ready\n");
return -EAGAIN;
}
@@ -964,13 +967,20 @@ int brcmf_bus_start(struct device *dev)
p2p_ifp = NULL;
/* signal bus ready */
- brcmf_bus_change_state(bus_if, BRCMF_BUS_DATA);
+ brcmf_bus_change_state(bus_if, BRCMF_BUS_UP);
/* Bus is ready, do any initialization */
ret = brcmf_c_preinit_dcmds(ifp);
if (ret < 0)
goto fail;
+ /* assure we have chipid before feature attach */
+ if (!bus_if->chip) {
+ bus_if->chip = drvr->revinfo.chipnum;
+ bus_if->chiprev = drvr->revinfo.chiprev;
+ brcmf_dbg(INFO, "firmware revinfo: chip %x (%d) rev %d\n",
+ bus_if->chip, bus_if->chip, bus_if->chiprev);
+ }
brcmf_feat_attach(drvr);
ret = brcmf_fws_init(drvr);
@@ -1093,9 +1103,8 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_if *ifp)
return atomic_read(&ifp->pend_8021x_cnt);
}
-int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
+int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp)
{
- struct brcmf_if *ifp = netdev_priv(ndev);
int err;
err = wait_event_timeout(ifp->pend_8021x_wait,
@@ -1107,6 +1116,27 @@ int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
return !err;
}
+void brcmf_bus_change_state(struct brcmf_bus *bus, enum brcmf_bus_state state)
+{
+ struct brcmf_pub *drvr = bus->drvr;
+ struct net_device *ndev;
+ int ifidx;
+
+ brcmf_dbg(TRACE, "%d -> %d\n", bus->state, state);
+ bus->state = state;
+
+ if (state == BRCMF_BUS_UP) {
+ for (ifidx = 0; ifidx < BRCMF_MAX_IFS; ifidx++) {
+ if ((drvr->iflist[ifidx]) &&
+ (drvr->iflist[ifidx]->ndev)) {
+ ndev = drvr->iflist[ifidx]->ndev;
+ if (netif_queue_stopped(ndev))
+ netif_wake_queue(ndev);
+ }
+ }
+ }
+}
+
static void brcmf_driver_register(struct work_struct *work)
{
#ifdef CONFIG_BRCMFMAC_SDIO
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/core.h b/drivers/net/wireless/brcm80211/brcmfmac/core.h
index 23f74b139cc8..fd74a9c6e9ac 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/core.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/core.h
@@ -29,8 +29,6 @@
/* For supporting multiple interfaces */
#define BRCMF_MAX_IFS 16
-#define DOT11_MAX_DEFAULT_KEYS 4
-
/* Small, medium and maximum buffer size for dcmd
*/
#define BRCMF_DCMD_SMLEN 256
@@ -73,6 +71,35 @@ struct brcmf_proto; /* device communication protocol info */
struct brcmf_cfg80211_dev; /* cfg80211 device info */
struct brcmf_fws_info; /* firmware signalling info */
+/*
+ * struct brcmf_rev_info
+ *
+ * The result field stores the error code of the
+ * revision info request from firmware. For the
+ * other fields see struct brcmf_rev_info_le in
+ * fwil_types.h
+ */
+struct brcmf_rev_info {
+ int result;
+ u32 vendorid;
+ u32 deviceid;
+ u32 radiorev;
+ u32 chiprev;
+ u32 corerev;
+ u32 boardid;
+ u32 boardvendor;
+ u32 boardrev;
+ u32 driverrev;
+ u32 ucoderev;
+ u32 bus;
+ u32 chipnum;
+ u32 phytype;
+ u32 phyrev;
+ u32 anarev;
+ u32 chippkg;
+ u32 nvramrev;
+};
+
/* Common structure for module and instance linkage */
struct brcmf_pub {
/* Linkage ponters */
@@ -106,6 +133,7 @@ struct brcmf_pub {
u32 feat_flags;
u32 chip_quirks;
+ struct brcmf_rev_info revinfo;
#ifdef DEBUG
struct dentry *dbgfs_dir;
#endif
@@ -167,7 +195,7 @@ struct brcmf_skb_reorder_data {
u8 *reorder;
};
-int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
+int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
/* Return pointer to interface name */
char *brcmf_ifname(struct brcmf_pub *drvr, int idx);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
index 1ff787d1a36b..9cb99152ad17 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/firmware.c
@@ -103,7 +103,11 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
c = nvp->fwnv->data[nvp->pos];
if (c == '=') {
- st = VALUE;
+ /* ignore RAW1 by treating as comment */
+ if (strncmp(&nvp->fwnv->data[nvp->entry], "RAW1", 4) == 0)
+ st = COMMENT;
+ else
+ st = VALUE;
} else if (!is_nvram_char(c)) {
brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
nvp->line, nvp->column);
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
index 44f3a84d1999..910fbb561469 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/flowring.c
@@ -25,6 +25,7 @@
#include "proto.h"
#include "flowring.h"
#include "msgbuf.h"
+#include "common.h"
#define BRCMF_FLOWRING_HIGH 1024
@@ -34,9 +35,6 @@
#define BRCMF_FLOWRING_HASH_AP(da, fifo, ifidx) (da[5] + fifo + ifidx * 16)
#define BRCMF_FLOWRING_HASH_STA(fifo, ifidx) (fifo + ifidx * 16)
-static const u8 ALLZEROMAC[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
-static const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-
static const u8 brcmf_flowring_prio2fifo[] = {
1,
0,
@@ -137,7 +135,7 @@ u32 brcmf_flowring_create(struct brcmf_flowring *flow, u8 da[ETH_ALEN],
hash = flow->hash;
for (i = 0; i < BRCMF_FLOWRING_HASHSIZE; i++) {
if ((hash[hash_idx].ifidx == BRCMF_FLOWRING_INVALID_IFIDX) &&
- (memcmp(hash[hash_idx].mac, ALLZEROMAC, ETH_ALEN) == 0)) {
+ (is_zero_ether_addr(hash[hash_idx].mac))) {
found = true;
break;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
index 03f2c406a17b..dcfa0bb149ce 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.c
@@ -109,7 +109,7 @@ brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
struct brcmf_pub *drvr = ifp->drvr;
s32 err;
- if (drvr->bus_if->state != BRCMF_BUS_DATA) {
+ if (drvr->bus_if->state != BRCMF_BUS_UP) {
brcmf_err("bus is down. we have nothing to do.\n");
return -EIO;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
index a30be683f4a1..5434dcf64f7d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil.h
@@ -43,6 +43,8 @@
#define BRCMF_C_SET_RADIO 38
#define BRCMF_C_GET_PHYTYPE 39
#define BRCMF_C_SET_KEY 45
+#define BRCMF_C_GET_REGULATORY 46
+#define BRCMF_C_SET_REGULATORY 47
#define BRCMF_C_SET_PASSIVE_SCAN 49
#define BRCMF_C_SCAN 50
#define BRCMF_C_SCAN_RESULTS 51
@@ -57,9 +59,12 @@
#define BRCMF_C_SET_COUNTRY 84
#define BRCMF_C_GET_PM 85
#define BRCMF_C_SET_PM 86
+#define BRCMF_C_GET_REVINFO 98
#define BRCMF_C_GET_CURR_RATESET 114
#define BRCMF_C_GET_AP 117
#define BRCMF_C_SET_AP 118
+#define BRCMF_C_SET_SCB_AUTHORIZE 121
+#define BRCMF_C_SET_SCB_DEAUTHORIZE 122
#define BRCMF_C_GET_RSSI 127
#define BRCMF_C_GET_WSEC 133
#define BRCMF_C_SET_WSEC 134
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
index 50891c02c4c1..374920965108 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/fwil_types.h
@@ -112,6 +112,7 @@
#define BRCMF_WOWL_MAXPATTERNS 8
#define BRCMF_WOWL_MAXPATTERNSIZE 128
+#define BRCMF_COUNTRY_BUF_SZ 4
/* join preference types for join_pref iovar */
enum brcmf_join_pref_types {
@@ -525,4 +526,58 @@ struct brcmf_mbss_ssid_le {
unsigned char SSID[32];
};
+/**
+ * struct brcmf_fil_country_le - country configuration structure.
+ *
+ * @country_abbrev: null-terminated country code used in the country IE.
+ * @rev: revision specifier for ccode. on set, -1 indicates unspecified.
+ * @ccode: null-terminated built-in country code.
+ */
+struct brcmf_fil_country_le {
+ char country_abbrev[BRCMF_COUNTRY_BUF_SZ];
+ __le32 rev;
+ char ccode[BRCMF_COUNTRY_BUF_SZ];
+};
+
+/**
+ * struct brcmf_rev_info_le - device revision info.
+ *
+ * @vendorid: PCI vendor id.
+ * @deviceid: device id of chip.
+ * @radiorev: radio revision.
+ * @chiprev: chip revision.
+ * @corerev: core revision.
+ * @boardid: board identifier (usu. PCI sub-device id).
+ * @boardvendor: board vendor (usu. PCI sub-vendor id).
+ * @boardrev: board revision.
+ * @driverrev: driver version.
+ * @ucoderev: microcode version.
+ * @bus: bus type.
+ * @chipnum: chip number.
+ * @phytype: phy type.
+ * @phyrev: phy revision.
+ * @anarev: anacore rev.
+ * @chippkg: chip package info.
+ * @nvramrev: nvram revision number.
+ */
+struct brcmf_rev_info_le {
+ __le32 vendorid;
+ __le32 deviceid;
+ __le32 radiorev;
+ __le32 chiprev;
+ __le32 corerev;
+ __le32 boardid;
+ __le32 boardvendor;
+ __le32 boardrev;
+ __le32 driverrev;
+ __le32 ucoderev;
+ __le32 bus;
+ __le32 chipnum;
+ __le32 phytype;
+ __le32 phyrev;
+ __le32 anarev;
+ __le32 chippkg;
+ __le32 nvramrev;
+};
+
#endif /* FWIL_TYPES_H_ */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
index 456944a6a2db..6262612dec45 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/msgbuf.c
@@ -73,6 +73,8 @@
#define BRCMF_MSGBUF_TX_FLUSH_CNT1 32
#define BRCMF_MSGBUF_TX_FLUSH_CNT2 96
+#define BRCMF_MSGBUF_DELAY_TXWORKER_THRS 64
+#define BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS 32
struct msgbuf_common_hdr {
u8 msgtype;
@@ -583,7 +585,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf,
u32 flowid;
void *dma_buf;
u32 dma_sz;
- long long address;
+ u64 address;
int err;
flowid = work->flowid;
@@ -620,7 +622,7 @@ brcmf_msgbuf_flowring_create_worker(struct brcmf_msgbuf *msgbuf,
BRCMF_NROF_H2D_COMMON_MSGRINGS);
memcpy(create->sa, work->sa, ETH_ALEN);
memcpy(create->da, work->da, ETH_ALEN);
- address = (long long)(long)msgbuf->flowring_dma_handle[flowid];
+ address = (u64)msgbuf->flowring_dma_handle[flowid];
create->flow_ring_addr.high_addr = cpu_to_le32(address >> 32);
create->flow_ring_addr.low_addr = cpu_to_le32(address & 0xffffffff);
create->max_items = cpu_to_le16(BRCMF_H2D_TXFLOWRING_MAX_ITEM);
@@ -698,7 +700,7 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
dma_addr_t physaddr;
u32 pktid;
struct msgbuf_tx_msghdr *tx_msghdr;
- long long address;
+ u64 address;
commonring = msgbuf->flowrings[flowid];
if (!brcmf_commonring_write_available(commonring))
@@ -742,13 +744,14 @@ static void brcmf_msgbuf_txflow(struct brcmf_msgbuf *msgbuf, u8 flowid)
tx_msghdr->seg_cnt = 1;
memcpy(tx_msghdr->txhdr, skb->data, ETH_HLEN);
tx_msghdr->data_len = cpu_to_le16(skb->len - ETH_HLEN);
- address = (long long)(long)physaddr;
+ address = (u64)physaddr;
tx_msghdr->data_buf_addr.high_addr = cpu_to_le32(address >> 32);
tx_msghdr->data_buf_addr.low_addr =
cpu_to_le32(address & 0xffffffff);
tx_msghdr->metadata_buf_len = 0;
tx_msghdr->metadata_buf_addr.high_addr = 0;
tx_msghdr->metadata_buf_addr.low_addr = 0;
+ atomic_inc(&commonring->outstanding_tx);
if (count >= BRCMF_MSGBUF_TX_FLUSH_CNT2) {
brcmf_commonring_write_complete(commonring);
count = 0;
@@ -773,10 +776,16 @@ static void brcmf_msgbuf_txflow_worker(struct work_struct *worker)
}
-static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid)
+static int brcmf_msgbuf_schedule_txdata(struct brcmf_msgbuf *msgbuf, u32 flowid,
+ bool force)
{
+ struct brcmf_commonring *commonring;
+
set_bit(flowid, msgbuf->flow_map);
- queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
+ commonring = msgbuf->flowrings[flowid];
+ if ((force) || (atomic_read(&commonring->outstanding_tx) <
+ BRCMF_MSGBUF_DELAY_TXWORKER_THRS))
+ queue_work(msgbuf->txflow_wq, &msgbuf->txflow_work);
return 0;
}
@@ -797,7 +806,7 @@ static int brcmf_msgbuf_txdata(struct brcmf_pub *drvr, int ifidx,
return -ENOMEM;
}
brcmf_flowring_enqueue(flow, flowid, skb);
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, false);
return 0;
}
@@ -854,6 +863,7 @@ brcmf_msgbuf_process_ioctl_complete(struct brcmf_msgbuf *msgbuf, void *buf)
static void
brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
{
+ struct brcmf_commonring *commonring;
struct msgbuf_tx_status *tx_status;
u32 idx;
struct sk_buff *skb;
@@ -871,6 +881,8 @@ brcmf_msgbuf_process_txstatus(struct brcmf_msgbuf *msgbuf, void *buf)
}
set_bit(flowid, msgbuf->txstatus_done_map);
+ commonring = msgbuf->flowrings[flowid];
+ atomic_dec(&commonring->outstanding_tx);
brcmf_txfinalize(msgbuf->drvr, skb, tx_status->msg.ifidx, true);
}
@@ -885,7 +897,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)
u32 pktlen;
dma_addr_t physaddr;
struct msgbuf_rx_bufpost *rx_bufpost;
- long long address;
+ u64 address;
u32 pktid;
u32 i;
@@ -894,7 +906,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)
count,
&alloced);
if (!ret_ptr) {
- brcmf_err("Failed to reserve space in commonring\n");
+ brcmf_dbg(MSGBUF, "Failed to reserve space in commonring\n");
return 0;
}
@@ -921,7 +933,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)
}
if (msgbuf->rx_metadata_offset) {
- address = (long long)(long)physaddr;
+ address = (u64)physaddr;
rx_bufpost->metadata_buf_len =
cpu_to_le16(msgbuf->rx_metadata_offset);
rx_bufpost->metadata_buf_addr.high_addr =
@@ -936,7 +948,7 @@ static u32 brcmf_msgbuf_rxbuf_data_post(struct brcmf_msgbuf *msgbuf, u32 count)
rx_bufpost->msg.msgtype = MSGBUF_TYPE_RXBUF_POST;
rx_bufpost->msg.request_id = cpu_to_le32(pktid);
- address = (long long)(long)physaddr;
+ address = (u64)physaddr;
rx_bufpost->data_buf_len = cpu_to_le16((u16)pktlen);
rx_bufpost->data_buf_addr.high_addr =
cpu_to_le32(address >> 32);
@@ -992,7 +1004,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf,
u32 pktlen;
dma_addr_t physaddr;
struct msgbuf_rx_ioctl_resp_or_event *rx_bufpost;
- long long address;
+ u64 address;
u32 pktid;
u32 i;
@@ -1035,7 +1047,7 @@ brcmf_msgbuf_rxbuf_ctrl_post(struct brcmf_msgbuf *msgbuf, bool event_buf,
MSGBUF_TYPE_IOCTLRESP_BUF_POST;
rx_bufpost->msg.request_id = cpu_to_le32(pktid);
- address = (long long)(long)physaddr;
+ address = (u64)physaddr;
rx_bufpost->host_buf_len = cpu_to_le16((u16)pktlen);
rx_bufpost->host_buf_addr.high_addr =
cpu_to_le32(address >> 32);
@@ -1181,7 +1193,7 @@ brcmf_msgbuf_process_flow_ring_create_response(struct brcmf_msgbuf *msgbuf,
brcmf_flowring_open(msgbuf->flow, flowid);
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);
}
@@ -1280,8 +1292,10 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_pub *drvr = bus_if->drvr;
struct brcmf_msgbuf *msgbuf = (struct brcmf_msgbuf *)drvr->proto->pd;
+ struct brcmf_commonring *commonring;
void *buf;
u32 flowid;
+ int qlen;
buf = msgbuf->commonrings[BRCMF_D2H_MSGRING_RX_COMPLETE];
brcmf_msgbuf_process_rx(msgbuf, buf);
@@ -1293,8 +1307,12 @@ int brcmf_proto_msgbuf_rx_trigger(struct device *dev)
for_each_set_bit(flowid, msgbuf->txstatus_done_map,
msgbuf->nrof_flowrings) {
clear_bit(flowid, msgbuf->txstatus_done_map);
- if (brcmf_flowring_qlen(msgbuf->flow, flowid))
- brcmf_msgbuf_schedule_txdata(msgbuf, flowid);
+ commonring = msgbuf->flowrings[flowid];
+ qlen = brcmf_flowring_qlen(msgbuf->flow, flowid);
+ if ((qlen > BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS) ||
+ ((qlen) && (atomic_read(&commonring->outstanding_tx) <
+ BRCMF_MSGBUF_TRICKLE_TXWORKER_THRS)))
+ brcmf_msgbuf_schedule_txdata(msgbuf, flowid, true);
}
return 0;
@@ -1348,7 +1366,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
{
struct brcmf_bus_msgbuf *if_msgbuf;
struct brcmf_msgbuf *msgbuf;
- long long address;
+ u64 address;
u32 count;
if_msgbuf = drvr->bus_if->msgbuf;
@@ -1379,7 +1397,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
GFP_KERNEL);
if (!msgbuf->ioctbuf)
goto fail;
- address = (long long)(long)msgbuf->ioctbuf_handle;
+ address = (u64)msgbuf->ioctbuf_handle;
msgbuf->ioctbuf_phys_hi = address >> 32;
msgbuf->ioctbuf_phys_lo = address & 0xffffffff;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
index 905991fdb7b1..61c053a729be 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/pcie.c
@@ -959,14 +959,14 @@ brcmf_pcie_init_dmabuffer_for_device(struct brcmf_pciedev_info *devinfo,
dma_addr_t *dma_handle)
{
void *ring;
- long long address;
+ u64 address;
ring = dma_alloc_coherent(&devinfo->pdev->dev, size, dma_handle,
GFP_KERNEL);
if (!ring)
return NULL;
- address = (long long)(long)*dma_handle;
+ address = (u64)*dma_handle;
brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr,
address & 0xffffffff);
brcmf_pcie_write_tcm32(devinfo, tcm_dma_phys_addr + 4, address >> 32);
@@ -1166,7 +1166,7 @@ brcmf_pcie_release_scratchbuffers(struct brcmf_pciedev_info *devinfo)
static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
{
- long long address;
+ u64 address;
u32 addr;
devinfo->shared.scratch = dma_alloc_coherent(&devinfo->pdev->dev,
@@ -1180,7 +1180,7 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
addr = devinfo->shared.tcm_base_address +
BRCMF_SHARED_DMA_SCRATCH_ADDR_OFFSET;
- address = (long long)(long)devinfo->shared.scratch_dmahandle;
+ address = (u64)devinfo->shared.scratch_dmahandle;
brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
addr = devinfo->shared.tcm_base_address +
@@ -1198,7 +1198,7 @@ static int brcmf_pcie_init_scratchbuffers(struct brcmf_pciedev_info *devinfo)
addr = devinfo->shared.tcm_base_address +
BRCMF_SHARED_DMA_RINGUPD_ADDR_OFFSET;
- address = (long long)(long)devinfo->shared.ringupd_dmahandle;
+ address = (u64)devinfo->shared.ringupd_dmahandle;
brcmf_pcie_write_tcm32(devinfo, addr, address & 0xffffffff);
brcmf_pcie_write_tcm32(devinfo, addr + 4, address >> 32);
addr = devinfo->shared.tcm_base_address +
@@ -1828,7 +1828,7 @@ static int brcmf_pcie_resume(struct pci_dev *pdev)
goto cleanup;
brcmf_dbg(PCIE, "Hot resume, continue....\n");
brcmf_pcie_select_core(devinfo, BCMA_CORE_PCIE2);
- brcmf_bus_change_state(bus, BRCMF_BUS_DATA);
+ brcmf_bus_change_state(bus, BRCMF_BUS_UP);
brcmf_pcie_intr_enable(devinfo);
return 0;
}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
index 0b0d51a61060..faec35c899ec 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.c
@@ -44,7 +44,8 @@
#include "chip.h"
#include "firmware.h"
-#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
+#define DCMD_RESP_TIMEOUT 2000 /* In milli second */
+#define CTL_DONE_TIMEOUT 2000 /* In milli second */
#ifdef DEBUG
@@ -495,9 +496,9 @@ struct brcmf_sdio {
u8 *ctrl_frame_buf;
u16 ctrl_frame_len;
bool ctrl_frame_stat;
+ int ctrl_frame_err;
spinlock_t txq_lock; /* protect bus->txq */
- struct semaphore tx_seq_lock; /* protect bus->tx_seq */
wait_queue_head_t ctrl_wait;
wait_queue_head_t dcmd_resp_wait;
@@ -514,7 +515,6 @@ struct brcmf_sdio {
bool txoff; /* Transmit flow-controlled */
struct brcmf_sdio_count sdcnt;
bool sr_enabled; /* SaveRestore enabled */
- bool sleeping; /* SDIO bus sleeping */
u8 tx_hdrlen; /* sdio bus header length for tx packet */
bool txglom; /* host tx glomming enable flag */
@@ -608,6 +608,8 @@ static const struct sdiod_drive_str sdiod_drvstr_tab2_3v3[] = {
#define BCM4330_NVRAM_NAME "brcm/brcmfmac4330-sdio.txt"
#define BCM4334_FIRMWARE_NAME "brcm/brcmfmac4334-sdio.bin"
#define BCM4334_NVRAM_NAME "brcm/brcmfmac4334-sdio.txt"
+#define BCM43340_FIRMWARE_NAME "brcm/brcmfmac43340-sdio.bin"
+#define BCM43340_NVRAM_NAME "brcm/brcmfmac43340-sdio.txt"
#define BCM4335_FIRMWARE_NAME "brcm/brcmfmac4335-sdio.bin"
#define BCM4335_NVRAM_NAME "brcm/brcmfmac4335-sdio.txt"
#define BCM43362_FIRMWARE_NAME "brcm/brcmfmac43362-sdio.bin"
@@ -629,6 +631,8 @@ MODULE_FIRMWARE(BCM4330_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4330_NVRAM_NAME);
MODULE_FIRMWARE(BCM4334_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4334_NVRAM_NAME);
+MODULE_FIRMWARE(BCM43340_FIRMWARE_NAME);
+MODULE_FIRMWARE(BCM43340_NVRAM_NAME);
MODULE_FIRMWARE(BCM4335_FIRMWARE_NAME);
MODULE_FIRMWARE(BCM4335_NVRAM_NAME);
MODULE_FIRMWARE(BCM43362_FIRMWARE_NAME);
@@ -660,6 +664,7 @@ static const struct brcmf_firmware_names brcmf_fwname_data[] = {
{ BRCM_CC_4329_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4329) },
{ BRCM_CC_4330_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4330) },
{ BRCM_CC_4334_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4334) },
+ { BRCM_CC_43340_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM43340) },
{ BRCM_CC_4335_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4335) },
{ BRCM_CC_43362_CHIP_ID, 0xFFFFFFFE, BRCMF_FIRMWARE_NVRAM(BCM43362) },
{ BRCM_CC_4339_CHIP_ID, 0xFFFFFFFF, BRCMF_FIRMWARE_NVRAM(BCM4339) },
@@ -1008,12 +1013,12 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
brcmf_dbg(SDIO, "Enter: request %s currently %s\n",
(sleep ? "SLEEP" : "WAKE"),
- (bus->sleeping ? "SLEEP" : "WAKE"));
+ (bus->sdiodev->sleeping ? "SLEEP" : "WAKE"));
/* If SR is enabled control bus state with KSO */
if (bus->sr_enabled) {
/* Done if we're already in the requested state */
- if (sleep == bus->sleeping)
+ if (sleep == bus->sdiodev->sleeping)
goto end;
/* Going to sleep */
@@ -1045,12 +1050,7 @@ brcmf_sdio_bus_sleep(struct brcmf_sdio *bus, bool sleep, bool pendok)
bus->idlecount = 0;
err = brcmf_sdio_kso_control(bus, true);
}
- if (!err) {
- /* Change state */
- bus->sleeping = sleep;
- brcmf_dbg(SDIO, "new state %s\n",
- (sleep ? "SLEEP" : "WAKE"));
- } else {
+ if (err) {
brcmf_err("error while changing bus sleep state %d\n",
err);
goto done;
@@ -1065,6 +1065,11 @@ end:
} else {
brcmf_sdio_clkctl(bus, CLK_AVAIL, pendok);
}
+ bus->sdiodev->sleeping = sleep;
+ if (sleep)
+ wake_up(&bus->sdiodev->idle_wait);
+ brcmf_dbg(SDIO, "new state %s\n",
+ (sleep ? "SLEEP" : "WAKE"));
done:
brcmf_dbg(SDIO, "Exit: err=%d\n", err);
return err;
@@ -1904,7 +1909,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
bus->rxpending = true;
for (rd->seq_num = bus->rx_seq, rxleft = maxframes;
- !bus->rxskip && rxleft && brcmf_bus_ready(bus->sdiodev->bus_if);
+ !bus->rxskip && rxleft && bus->sdiodev->state == BRCMF_STATE_DATA;
rd->seq_num++, rxleft--) {
/* Handle glomming separately */
@@ -2371,8 +2376,6 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* Send frames until the limit or some other event */
for (cnt = 0; (cnt < maxframes) && data_ok(bus);) {
pkt_num = 1;
- if (down_interruptible(&bus->tx_seq_lock))
- return cnt;
if (bus->txglom)
pkt_num = min_t(u8, bus->tx_max - bus->tx_seq,
bus->sdiodev->txglomsz);
@@ -2388,13 +2391,10 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
__skb_queue_tail(&pktq, pkt);
}
spin_unlock_bh(&bus->txq_lock);
- if (i == 0) {
- up(&bus->tx_seq_lock);
+ if (i == 0)
break;
- }
ret = brcmf_sdio_txpkt(bus, &pktq, SDPCM_DATA_CHANNEL);
- up(&bus->tx_seq_lock);
cnt += i;
@@ -2415,7 +2415,7 @@ static uint brcmf_sdio_sendfromq(struct brcmf_sdio *bus, uint maxframes)
}
/* Deflow-control stack if needed */
- if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DATA) &&
+ if ((bus->sdiodev->state == BRCMF_STATE_DATA) &&
bus->txoff && (pktq_len(&bus->txq) < TXLOW)) {
bus->txoff = false;
brcmf_txflowblock(bus->sdiodev->dev, false);
@@ -2503,7 +2503,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
bus->watchdog_tsk = NULL;
}
- if (bus_if->state == BRCMF_BUS_DOWN) {
+ if (sdiodev->state != BRCMF_STATE_NOMEDIUM) {
sdio_claim_host(sdiodev->func[1]);
/* Enable clock for device interrupts */
@@ -2538,8 +2538,7 @@ static void brcmf_sdio_bus_stop(struct device *dev)
brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
/* Clear any held glomming stuff */
- if (bus->glomd)
- brcmu_pkt_buf_free_skb(bus->glomd);
+ brcmu_pkt_buf_free_skb(bus->glomd);
brcmf_sdio_free_glom(bus);
/* Clear rx control and wake any waiters */
@@ -2604,6 +2603,21 @@ static int brcmf_sdio_intr_rstatus(struct brcmf_sdio *bus)
return ret;
}
+static int brcmf_sdio_pm_resume_wait(struct brcmf_sdio_dev *sdiodev)
+{
+#ifdef CONFIG_PM_SLEEP
+ int retry;
+
+ /* Wait for possible resume to complete */
+ retry = 0;
+ while ((atomic_read(&sdiodev->suspend)) && (retry++ != 50))
+ msleep(20);
+ if (atomic_read(&sdiodev->suspend))
+ return -EIO;
+#endif
+ return 0;
+}
+
static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
{
u32 newstatus = 0;
@@ -2614,6 +2628,9 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
+ if (brcmf_sdio_pm_resume_wait(bus->sdiodev))
+ return;
+
sdio_claim_host(bus->sdiodev->func[1]);
/* If waiting for HTAVAIL, check status */
@@ -2720,17 +2737,14 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_sdio_clrintr(bus);
if (bus->ctrl_frame_stat && (bus->clkstate == CLK_AVAIL) &&
- (down_interruptible(&bus->tx_seq_lock) == 0)) {
- if (data_ok(bus)) {
- sdio_claim_host(bus->sdiodev->func[1]);
- err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
- bus->ctrl_frame_len);
- sdio_release_host(bus->sdiodev->func[1]);
-
- bus->ctrl_frame_stat = false;
- brcmf_sdio_wait_event_wakeup(bus);
- }
- up(&bus->tx_seq_lock);
+ data_ok(bus)) {
+ sdio_claim_host(bus->sdiodev->func[1]);
+ err = brcmf_sdio_tx_ctrlframe(bus, bus->ctrl_frame_buf,
+ bus->ctrl_frame_len);
+ sdio_release_host(bus->sdiodev->func[1]);
+ bus->ctrl_frame_err = err;
+ bus->ctrl_frame_stat = false;
+ brcmf_sdio_wait_event_wakeup(bus);
}
/* Send queued frames (limit 1 if rx may still be pending) */
if ((bus->clkstate == CLK_AVAIL) && !atomic_read(&bus->fcstate) &&
@@ -2741,7 +2755,7 @@ static void brcmf_sdio_dpc(struct brcmf_sdio *bus)
brcmf_sdio_sendfromq(bus, framecnt);
}
- if (!brcmf_bus_ready(bus->sdiodev->bus_if) || (err != 0)) {
+ if ((bus->sdiodev->state != BRCMF_STATE_DATA) || (err != 0)) {
brcmf_err("failed backplane access over SDIO, halting operation\n");
atomic_set(&bus->intstatus, 0);
} else if (atomic_read(&bus->intstatus) ||
@@ -2942,43 +2956,30 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
- int ret = -1;
+ int ret;
brcmf_dbg(TRACE, "Enter\n");
- if (down_interruptible(&bus->tx_seq_lock))
- return -EINTR;
-
- if (!data_ok(bus)) {
- brcmf_dbg(INFO, "No bus credit bus->tx_max %d, bus->tx_seq %d\n",
- bus->tx_max, bus->tx_seq);
- up(&bus->tx_seq_lock);
- /* Send from dpc */
- bus->ctrl_frame_buf = msg;
- bus->ctrl_frame_len = msglen;
- bus->ctrl_frame_stat = true;
-
- wait_event_interruptible_timeout(bus->ctrl_wait,
- !bus->ctrl_frame_stat,
- msecs_to_jiffies(2000));
-
- if (!bus->ctrl_frame_stat) {
- brcmf_dbg(SDIO, "ctrl_frame_stat == false\n");
- ret = 0;
- } else {
- brcmf_dbg(SDIO, "ctrl_frame_stat == true\n");
- bus->ctrl_frame_stat = false;
- if (down_interruptible(&bus->tx_seq_lock))
- return -EINTR;
- ret = -1;
- }
+ /* Send from dpc */
+ bus->ctrl_frame_buf = msg;
+ bus->ctrl_frame_len = msglen;
+ bus->ctrl_frame_stat = true;
+ if (atomic_read(&bus->dpc_tskcnt) == 0) {
+ atomic_inc(&bus->dpc_tskcnt);
+ queue_work(bus->brcmf_wq, &bus->datawork);
}
- if (ret == -1) {
- sdio_claim_host(bus->sdiodev->func[1]);
- brcmf_sdio_bus_sleep(bus, false, false);
- ret = brcmf_sdio_tx_ctrlframe(bus, msg, msglen);
- sdio_release_host(bus->sdiodev->func[1]);
- up(&bus->tx_seq_lock);
+
+ wait_event_interruptible_timeout(bus->ctrl_wait, !bus->ctrl_frame_stat,
+ msecs_to_jiffies(CTL_DONE_TIMEOUT));
+
+ if (!bus->ctrl_frame_stat) {
+ brcmf_dbg(SDIO, "ctrl_frame complete, err=%d\n",
+ bus->ctrl_frame_err);
+ ret = bus->ctrl_frame_err;
+ } else {
+ brcmf_dbg(SDIO, "ctrl_frame timeout\n");
+ bus->ctrl_frame_stat = false;
+ ret = -ETIMEDOUT;
}
if (ret)
@@ -2986,7 +2987,7 @@ brcmf_sdio_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
else
bus->sdcnt.tx_ctlpkts++;
- return ret ? -EIO : 0;
+ return ret;
}
#ifdef DEBUG
@@ -3409,8 +3410,8 @@ static int brcmf_sdio_download_firmware(struct brcmf_sdio *bus,
goto err;
}
- /* Allow HT Clock now that the ARM is running. */
- brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_LOAD);
+ /* Allow full data communication using DPC from now on. */
+ bus->sdiodev->state = BRCMF_STATE_DATA;
bcmerror = 0;
err:
@@ -3556,7 +3557,7 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
return;
}
- if (!brcmf_bus_ready(bus->sdiodev->bus_if)) {
+ if (bus->sdiodev->state != BRCMF_STATE_DATA) {
brcmf_err("bus is down. we have nothing to do\n");
return;
}
@@ -3579,10 +3580,6 @@ void brcmf_sdio_isr(struct brcmf_sdio *bus)
static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
{
-#ifdef DEBUG
- struct brcmf_bus *bus_if = dev_get_drvdata(bus->sdiodev->dev);
-#endif /* DEBUG */
-
brcmf_dbg(TIMER, "Enter\n");
/* Poll period: check device if appropriate. */
@@ -3626,7 +3623,7 @@ static bool brcmf_sdio_bus_watchdog(struct brcmf_sdio *bus)
}
#ifdef DEBUG
/* Poll for console output periodically */
- if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
+ if (bus->sdiodev->state == BRCMF_STATE_DATA &&
bus->console_interval != 0) {
bus->console.count += BRCMF_WD_POLL_MS;
if (bus->console.count >= bus->console_interval) {
@@ -3811,7 +3808,7 @@ static u32 brcmf_sdio_buscore_read32(void *ctx, u32 addr)
u32 val, rev;
val = brcmf_sdiod_regrl(sdiodev, addr, NULL);
- if (sdiodev->func[0]->device == BRCM_SDIO_4335_4339_DEVICE_ID &&
+ if (sdiodev->func[0]->device == SDIO_DEVICE_ID_BROADCOM_4335_4339 &&
addr == CORE_CC_REG(SI_ENUM_BASE, chipid)) {
rev = (val & CID_REV_MASK) >> CID_REV_SHIFT;
if (rev >= 2) {
@@ -3867,11 +3864,6 @@ brcmf_sdio_probe_attach(struct brcmf_sdio *bus)
goto fail;
}
- /* SDIO register access works so moving
- * state from UNKNOWN to DOWN.
- */
- brcmf_bus_change_state(bus->sdiodev->bus_if, BRCMF_BUS_DOWN);
-
bus->ci = brcmf_chip_attach(bus->sdiodev, &brcmf_sdio_buscore_ops);
if (IS_ERR(bus->ci)) {
brcmf_err("brcmf_chip_attach failed!\n");
@@ -4005,18 +3997,16 @@ static void brcmf_sdio_firmware_callback(struct device *dev,
brcmf_dbg(TRACE, "Enter: dev=%s\n", dev_name(dev));
- /* try to download image and nvram to the dongle */
- if (bus_if->state == BRCMF_BUS_DOWN) {
- bus->alp_only = true;
- err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
- if (err)
- goto fail;
- bus->alp_only = false;
- }
-
if (!bus_if->drvr)
return;
+ /* try to download image and nvram to the dongle */
+ bus->alp_only = true;
+ err = brcmf_sdio_download_firmware(bus, code, nvram, nvram_len);
+ if (err)
+ goto fail;
+ bus->alp_only = false;
+
/* Start the watchdog timer */
bus->sdcnt.tickcnt = 0;
brcmf_sdio_wd_timer(bus, BRCMF_WD_POLL_MS);
@@ -4142,7 +4132,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
spin_lock_init(&bus->rxctl_lock);
spin_lock_init(&bus->txq_lock);
- sema_init(&bus->tx_seq_lock, 1);
init_waitqueue_head(&bus->ctrl_wait);
init_waitqueue_head(&bus->dcmd_resp_wait);
@@ -4213,7 +4202,6 @@ struct brcmf_sdio *brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
bus->idleclock = BRCMF_IDLE_ACTIVE;
/* SR state */
- bus->sleeping = false;
bus->sr_enabled = false;
brcmf_sdio_debugfs_create(bus);
@@ -4254,7 +4242,7 @@ void brcmf_sdio_remove(struct brcmf_sdio *bus)
destroy_workqueue(bus->brcmf_wq);
if (bus->ci) {
- if (bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) {
+ if (bus->sdiodev->state != BRCMF_STATE_NOMEDIUM) {
sdio_claim_host(bus->sdiodev->func[1]);
brcmf_sdio_clkctl(bus, CLK_AVAIL, false);
/* Leave the device in state where it is
@@ -4289,7 +4277,7 @@ void brcmf_sdio_wd_timer(struct brcmf_sdio *bus, uint wdtick)
}
/* don't start the wd until fw is loaded */
- if (bus->sdiodev->bus_if->state != BRCMF_BUS_DATA)
+ if (bus->sdiodev->state != BRCMF_STATE_DATA)
return;
if (wdtick) {
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
index 8eb42620129c..ec2586a8425c 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
+++ b/drivers/net/wireless/brcm80211/brcmfmac/sdio.h
@@ -155,6 +155,13 @@
/* watchdog polling interval in ms */
#define BRCMF_WD_POLL_MS 10
+/* The state of the bus */
+enum brcmf_sdio_state {
+ BRCMF_STATE_DOWN, /* Device available, still initialising */
+ BRCMF_STATE_DATA, /* Ready for data transfers, DPC enabled */
+ BRCMF_STATE_NOMEDIUM /* No medium access to dongle possible */
+};
+
struct brcmf_sdreg {
int func;
int offset;
@@ -169,8 +176,8 @@ struct brcmf_sdio_dev {
u32 sbwad; /* Save backplane window address */
struct brcmf_sdio *bus;
atomic_t suspend; /* suspend flag */
- wait_queue_head_t request_word_wait;
- wait_queue_head_t request_buffer_wait;
+ bool sleeping;
+ wait_queue_head_t idle_wait;
struct device *dev;
struct brcmf_bus *bus_if;
struct brcmfmac_sdio_platform_data *pdata;
@@ -187,6 +194,7 @@ struct brcmf_sdio_dev {
char fw_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
char nvram_name[BRCMF_FW_PATH_LEN + BRCMF_FW_NAME_LEN];
bool wowl_enabled;
+ enum brcmf_sdio_state state;
};
/* sdio core registers */
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/usb.c b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
index 4572defc280f..5df6aa72cc2d 100644
--- a/drivers/net/wireless/brcm80211/brcmfmac/usb.c
+++ b/drivers/net/wireless/brcm80211/brcmfmac/usb.c
@@ -421,7 +421,7 @@ fail:
brcmf_err("fail!\n");
while (!list_empty(q)) {
req = list_entry(q->next, struct brcmf_usbreq, list);
- if (req && req->urb)
+ if (req)
usb_free_urb(req->urb);
list_del(q->next);
}
@@ -576,7 +576,7 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DOWN);
} else if (state == BRCMFMAC_USB_STATE_UP) {
brcmf_dbg(USB, "DBUS is up\n");
- brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_DATA);
+ brcmf_bus_change_state(bcmf_bus, BRCMF_BUS_UP);
} else {
brcmf_dbg(USB, "DBUS current state=%d\n", state);
}
@@ -1263,6 +1263,8 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
ret = brcmf_usb_bus_setup(devinfo);
if (ret)
goto fail;
+ /* we are done */
+ return 0;
}
bus->chip = bus_pub->devid;
bus->chiprev = bus_pub->chiprev;
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
index c9a8b9360ab1..7a1fbb2e3a71 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/debug.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
@@ -78,7 +78,7 @@ int brcms_debugfs_hardware_read(struct seq_file *s, void *data)
struct brcms_hardware *hw = drvr->wlc->hw;
struct bcma_device *core = hw->d11core;
struct bcma_bus *bus = core->bus;
- char boardrev[10];
+ char boardrev[BRCMU_BOARDREV_LEN];
seq_printf(s, "chipnum 0x%x\n"
"chiprev 0x%x\n"
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
index f95b52442281..48135063347e 100644
--- a/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
+++ b/drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
@@ -99,7 +99,7 @@ static struct bcma_device_id brcms_coreid_table[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 17, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 23, BCMA_ANY_CLASS),
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 24, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
+ {},
};
MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
diff --git a/drivers/net/wireless/brcm80211/brcmutil/utils.c b/drivers/net/wireless/brcm80211/brcmutil/utils.c
index 906e89ddf319..0543607002fd 100644
--- a/drivers/net/wireless/brcm80211/brcmutil/utils.c
+++ b/drivers/net/wireless/brcm80211/brcmutil/utils.c
@@ -267,15 +267,43 @@ char *brcmu_boardrev_str(u32 brev, char *buf)
char c;
if (brev < 0x100) {
- snprintf(buf, 8, "%d.%d", (brev & 0xf0) >> 4, brev & 0xf);
+ snprintf(buf, BRCMU_BOARDREV_LEN, "%d.%d",
+ (brev & 0xf0) >> 4, brev & 0xf);
} else {
c = (brev & 0xf000) == 0x1000 ? 'P' : 'A';
- snprintf(buf, 8, "%c%03x", c, brev & 0xfff);
+ snprintf(buf, BRCMU_BOARDREV_LEN, "%c%03x", c, brev & 0xfff);
}
return buf;
}
EXPORT_SYMBOL(brcmu_boardrev_str);
+char *brcmu_dotrev_str(u32 dotrev, char *buf)
+{
+ u8 dotval[4];
+
+ if (!dotrev) {
+ snprintf(buf, BRCMU_DOTREV_LEN, "unknown");
+ return buf;
+ }
+ dotval[0] = (dotrev >> 24) & 0xFF;
+ dotval[1] = (dotrev >> 16) & 0xFF;
+ dotval[2] = (dotrev >> 8) & 0xFF;
+ dotval[3] = dotrev & 0xFF;
+
+ if (dotval[3])
+ snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d.%d", dotval[0],
+ dotval[1], dotval[2], dotval[3]);
+ else if (dotval[2])
+ snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d.%d", dotval[0],
+ dotval[1], dotval[2]);
+ else
+ snprintf(buf, BRCMU_DOTREV_LEN, "%d.%d", dotval[0],
+ dotval[1]);
+
+ return buf;
+}
+EXPORT_SYMBOL(brcmu_dotrev_str);
+
#if defined(DEBUG)
/* pretty hex print a pkt buffer chain */
void brcmu_prpkt(const char *msg, struct sk_buff *p0)
diff --git a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
index 6996fcc144cf..2124a17d0bfd 100644
--- a/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
+++ b/drivers/net/wireless/brcm80211/include/brcm_hw_ids.h
@@ -22,7 +22,6 @@
#define BRCM_USB_VENDOR_ID_BROADCOM 0x0a5c
#define BRCM_PCIE_VENDOR_ID_BROADCOM PCI_VENDOR_ID_BROADCOM
-#define BRCM_SDIO_VENDOR_ID_BROADCOM SDIO_VENDOR_ID_BROADCOM
/* Chipcommon Core Chip IDs */
#define BRCM_CC_43143_CHIP_ID 43143
@@ -34,6 +33,7 @@
#define BRCM_CC_4329_CHIP_ID 0x4329
#define BRCM_CC_4330_CHIP_ID 0x4330
#define BRCM_CC_4334_CHIP_ID 0x4334
+#define BRCM_CC_43340_CHIP_ID 43340
#define BRCM_CC_43362_CHIP_ID 43362
#define BRCM_CC_4335_CHIP_ID 0x4335
#define BRCM_CC_4339_CHIP_ID 0x4339
@@ -45,16 +45,6 @@
#define BRCM_CC_43570_CHIP_ID 43570
#define BRCM_CC_43602_CHIP_ID 43602
-/* SDIO Device IDs */
-#define BRCM_SDIO_43143_DEVICE_ID BRCM_CC_43143_CHIP_ID
-#define BRCM_SDIO_43241_DEVICE_ID BRCM_CC_43241_CHIP_ID
-#define BRCM_SDIO_4329_DEVICE_ID BRCM_CC_4329_CHIP_ID
-#define BRCM_SDIO_4330_DEVICE_ID BRCM_CC_4330_CHIP_ID
-#define BRCM_SDIO_4334_DEVICE_ID BRCM_CC_4334_CHIP_ID
-#define BRCM_SDIO_43362_DEVICE_ID BRCM_CC_43362_CHIP_ID
-#define BRCM_SDIO_4335_4339_DEVICE_ID BRCM_CC_4335_CHIP_ID
-#define BRCM_SDIO_4354_DEVICE_ID BRCM_CC_4354_CHIP_ID
-
/* USB Device IDs */
#define BRCM_USB_43143_DEVICE_ID 0xbd1e
#define BRCM_USB_43236_DEVICE_ID 0xbd17
diff --git a/drivers/net/wireless/brcm80211/include/brcmu_utils.h b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
index a043e29f07e2..41969527b459 100644
--- a/drivers/net/wireless/brcm80211/include/brcmu_utils.h
+++ b/drivers/net/wireless/brcm80211/include/brcmu_utils.h
@@ -218,6 +218,10 @@ void brcmu_dbg_hex_dump(const void *data, size_t size, const char *fmt, ...)
}
#endif
+#define BRCMU_BOARDREV_LEN 8
+#define BRCMU_DOTREV_LEN 16
+
char *brcmu_boardrev_str(u32 brev, char *buf);
+char *brcmu_dotrev_str(u32 dotrev, char *buf);
#endif /* _BRCMU_UTILS_H_ */
diff --git a/drivers/net/wireless/cw1200/fwio.c b/drivers/net/wireless/cw1200/fwio.c
index 6f1b9aace8b3..30e7646d04af 100644
--- a/drivers/net/wireless/cw1200/fwio.c
+++ b/drivers/net/wireless/cw1200/fwio.c
@@ -66,25 +66,31 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
do { \
ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \
if (ret < 0) \
- goto error; \
+ goto exit; \
+ } while (0)
+#define APB_WRITE2(reg, val) \
+ do { \
+ ret = cw1200_apb_write_32(priv, CW1200_APB(reg), (val)); \
+ if (ret < 0) \
+ goto free_buffer; \
} while (0)
#define APB_READ(reg, val) \
do { \
ret = cw1200_apb_read_32(priv, CW1200_APB(reg), &(val)); \
if (ret < 0) \
- goto error; \
+ goto free_buffer; \
} while (0)
#define REG_WRITE(reg, val) \
do { \
ret = cw1200_reg_write_32(priv, (reg), (val)); \
if (ret < 0) \
- goto error; \
+ goto exit; \
} while (0)
#define REG_READ(reg, val) \
do { \
ret = cw1200_reg_read_32(priv, (reg), &(val)); \
if (ret < 0) \
- goto error; \
+ goto exit; \
} while (0)
switch (priv->hw_revision) {
@@ -142,14 +148,14 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
ret = request_firmware(&firmware, fw_path, priv->pdev);
if (ret) {
pr_err("Can't load firmware file %s.\n", fw_path);
- goto error;
+ goto exit;
}
buf = kmalloc(DOWNLOAD_BLOCK_SIZE, GFP_KERNEL | GFP_DMA);
if (!buf) {
pr_err("Can't allocate firmware load buffer.\n");
ret = -ENOMEM;
- goto error;
+ goto firmware_release;
}
/* Check if the bootloader is ready */
@@ -163,7 +169,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (val32 != DOWNLOAD_I_AM_HERE) {
pr_err("Bootloader is not ready.\n");
ret = -ETIMEDOUT;
- goto error;
+ goto free_buffer;
}
/* Calculcate number of download blocks */
@@ -171,7 +177,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
/* Updating the length in Download Ctrl Area */
val32 = firmware->size; /* Explicit cast from size_t to u32 */
- APB_WRITE(DOWNLOAD_IMAGE_SIZE_REG, val32);
+ APB_WRITE2(DOWNLOAD_IMAGE_SIZE_REG, val32);
/* Firmware downloading loop */
for (block = 0; block < num_blocks; block++) {
@@ -183,7 +189,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (val32 != DOWNLOAD_PENDING) {
pr_err("Bootloader reported error %d.\n", val32);
ret = -EIO;
- goto error;
+ goto free_buffer;
}
/* loop until put - get <= 24K */
@@ -198,7 +204,7 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if ((put - get) > (DOWNLOAD_FIFO_SIZE - DOWNLOAD_BLOCK_SIZE)) {
pr_err("Timeout waiting for FIFO.\n");
ret = -ETIMEDOUT;
- goto error;
+ goto free_buffer;
}
/* calculate the block size */
@@ -220,12 +226,12 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (ret < 0) {
pr_err("Can't write firmware block @ %d!\n",
put & (DOWNLOAD_FIFO_SIZE - 1));
- goto error;
+ goto free_buffer;
}
/* update the put register */
put += block_size;
- APB_WRITE(DOWNLOAD_PUT_REG, put);
+ APB_WRITE2(DOWNLOAD_PUT_REG, put);
} /* End of firmware download loop */
/* Wait for the download completion */
@@ -238,19 +244,21 @@ static int cw1200_load_firmware_cw1200(struct cw1200_common *priv)
if (val32 != DOWNLOAD_SUCCESS) {
pr_err("Wait for download completion failed: 0x%.8X\n", val32);
ret = -ETIMEDOUT;
- goto error;
+ goto free_buffer;
} else {
pr_info("Firmware download completed.\n");
ret = 0;
}
-error:
+free_buffer:
kfree(buf);
- if (firmware)
- release_firmware(firmware);
+firmware_release:
+ release_firmware(firmware);
+exit:
return ret;
#undef APB_WRITE
+#undef APB_WRITE2
#undef APB_READ
#undef REG_WRITE
#undef REG_READ
diff --git a/drivers/net/wireless/cw1200/main.c b/drivers/net/wireless/cw1200/main.c
index 3e78cc3ccb78..3689dbbd10bd 100644
--- a/drivers/net/wireless/cw1200/main.c
+++ b/drivers/net/wireless/cw1200/main.c
@@ -282,7 +282,6 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
- IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_AMPDU_AGGREGATION |
IEEE80211_HW_TX_AMPDU_SETUP_IN_HW |
@@ -374,9 +373,8 @@ static struct ieee80211_hw *cw1200_init_common(const u8 *macaddr,
INIT_WORK(&priv->update_filtering_work, cw1200_update_filtering_work);
INIT_WORK(&priv->set_beacon_wakeup_period_work,
cw1200_set_beacon_wakeup_period_work);
- init_timer(&priv->mcast_timeout);
- priv->mcast_timeout.data = (unsigned long)priv;
- priv->mcast_timeout.function = cw1200_mcast_timeout;
+ setup_timer(&priv->mcast_timeout, cw1200_mcast_timeout,
+ (unsigned long)priv);
if (cw1200_queue_stats_init(&priv->tx_queue_stats,
CW1200_LINK_ID_MAX,
diff --git a/drivers/net/wireless/cw1200/pm.c b/drivers/net/wireless/cw1200/pm.c
index 6907c8fd4578..d2202ae92bdd 100644
--- a/drivers/net/wireless/cw1200/pm.c
+++ b/drivers/net/wireless/cw1200/pm.c
@@ -101,9 +101,8 @@ int cw1200_pm_init(struct cw1200_pm_state *pm,
{
spin_lock_init(&pm->lock);
- init_timer(&pm->stay_awake);
- pm->stay_awake.data = (unsigned long)pm;
- pm->stay_awake.function = cw1200_pm_stay_awake_tmo;
+ setup_timer(&pm->stay_awake, cw1200_pm_stay_awake_tmo,
+ (unsigned long)pm);
return 0;
}
diff --git a/drivers/net/wireless/cw1200/queue.c b/drivers/net/wireless/cw1200/queue.c
index 9c3925f58d79..0ba5ef9b3e7b 100644
--- a/drivers/net/wireless/cw1200/queue.c
+++ b/drivers/net/wireless/cw1200/queue.c
@@ -179,9 +179,7 @@ int cw1200_queue_init(struct cw1200_queue *queue,
INIT_LIST_HEAD(&queue->pending);
INIT_LIST_HEAD(&queue->free_pool);
spin_lock_init(&queue->lock);
- init_timer(&queue->gc);
- queue->gc.data = (unsigned long)queue;
- queue->gc.function = cw1200_queue_gc;
+ setup_timer(&queue->gc, cw1200_queue_gc, (unsigned long)queue);
queue->pool = kzalloc(sizeof(struct cw1200_queue_item) * capacity,
GFP_KERNEL);
diff --git a/drivers/net/wireless/cw1200/scan.c b/drivers/net/wireless/cw1200/scan.c
index f2e276faca70..bff81b8d4164 100644
--- a/drivers/net/wireless/cw1200/scan.c
+++ b/drivers/net/wireless/cw1200/scan.c
@@ -39,9 +39,9 @@ static int cw1200_scan_start(struct cw1200_common *priv, struct wsm_scan *scan)
cancel_delayed_work_sync(&priv->clear_recent_scan_work);
atomic_set(&priv->scan.in_progress, 1);
atomic_set(&priv->recent_scan, 1);
- cw1200_pm_stay_awake(&priv->pm_state, tmo * HZ / 1000);
+ cw1200_pm_stay_awake(&priv->pm_state, msecs_to_jiffies(tmo));
queue_delayed_work(priv->workqueue, &priv->scan.timeout,
- tmo * HZ / 1000);
+ msecs_to_jiffies(tmo));
ret = wsm_scan(priv, scan);
if (ret) {
atomic_set(&priv->scan.in_progress, 0);
@@ -386,8 +386,8 @@ void cw1200_probe_work(struct work_struct *work)
if (down_trylock(&priv->scan.lock)) {
/* Scan is already in progress. Requeue self. */
schedule();
- queue_delayed_work(priv->workqueue,
- &priv->scan.probe_work, HZ / 10);
+ queue_delayed_work(priv->workqueue, &priv->scan.probe_work,
+ msecs_to_jiffies(100));
mutex_unlock(&priv->conf_mutex);
return;
}
diff --git a/drivers/net/wireless/cw1200/sta.c b/drivers/net/wireless/cw1200/sta.c
index 5b84664db13b..4a47c7f8a246 100644
--- a/drivers/net/wireless/cw1200/sta.c
+++ b/drivers/net/wireless/cw1200/sta.c
@@ -213,6 +213,7 @@ int cw1200_add_interface(struct ieee80211_hw *dev,
/* __le32 auto_calibration_mode = __cpu_to_le32(1); */
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_UAPSD |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
mutex_lock(&priv->conf_mutex);
@@ -708,7 +709,8 @@ int cw1200_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
if (sta)
peer_addr = sta->addr;
- key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE;
+ key->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE |
+ IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
switch (key->cipher) {
case WLAN_CIPHER_SUITE_WEP40:
diff --git a/drivers/net/wireless/hostap/hostap_ap.c b/drivers/net/wireless/hostap/hostap_ap.c
index 596525528f50..fd8d83dd4f62 100644
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -145,7 +145,7 @@ static void ap_free_sta(struct ap_data *ap, struct sta_info *sta)
if (sta->aid > 0)
ap->sta_aid[sta->aid - 1] = NULL;
- if (!sta->ap && sta->u.sta.challenge)
+ if (!sta->ap)
kfree(sta->u.sta.challenge);
del_timer_sync(&sta->timer);
#endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
diff --git a/drivers/net/wireless/iwlegacy/3945-mac.c b/drivers/net/wireless/iwlegacy/3945-mac.c
index dc1d20cf64ee..e5665804d986 100644
--- a/drivers/net/wireless/iwlegacy/3945-mac.c
+++ b/drivers/net/wireless/iwlegacy/3945-mac.c
@@ -3429,9 +3429,7 @@ il3945_setup_deferred_work(struct il_priv *il)
il3945_hw_setup_deferred_work(il);
- init_timer(&il->watchdog);
- il->watchdog.data = (unsigned long)il;
- il->watchdog.function = il_bg_watchdog;
+ setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il);
tasklet_init(&il->irq_tasklet,
(void (*)(unsigned long))il3945_irq_tasklet,
diff --git a/drivers/net/wireless/iwlegacy/4965-mac.c b/drivers/net/wireless/iwlegacy/4965-mac.c
index 2748fde4b90c..976f65fe9c38 100644
--- a/drivers/net/wireless/iwlegacy/4965-mac.c
+++ b/drivers/net/wireless/iwlegacy/4965-mac.c
@@ -6247,13 +6247,10 @@ il4965_setup_deferred_work(struct il_priv *il)
INIT_WORK(&il->txpower_work, il4965_bg_txpower_work);
- init_timer(&il->stats_periodic);
- il->stats_periodic.data = (unsigned long)il;
- il->stats_periodic.function = il4965_bg_stats_periodic;
+ setup_timer(&il->stats_periodic, il4965_bg_stats_periodic,
+ (unsigned long)il);
- init_timer(&il->watchdog);
- il->watchdog.data = (unsigned long)il;
- il->watchdog.function = il_bg_watchdog;
+ setup_timer(&il->watchdog, il_bg_watchdog, (unsigned long)il);
tasklet_init(&il->irq_tasklet,
(void (*)(unsigned long))il4965_irq_tasklet,
diff --git a/drivers/net/wireless/iwlwifi/dvm/main.c b/drivers/net/wireless/iwlwifi/dvm/main.c
index 0b7f46f0b079..c4d6dd7402d9 100644
--- a/drivers/net/wireless/iwlwifi/dvm/main.c
+++ b/drivers/net/wireless/iwlwifi/dvm/main.c
@@ -64,22 +64,8 @@
*
******************************************************************************/
-/*
- * module name, copyright, version, etc.
- */
#define DRV_DESCRIPTION "Intel(R) Wireless WiFi Link AGN driver for Linux"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#define DRV_VERSION IWLWIFI_VERSION VD
-
-
MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -1011,13 +997,11 @@ static void iwl_setup_deferred_work(struct iwl_priv *priv)
if (priv->lib->bt_params)
iwlagn_bt_setup_deferred_work(priv);
- init_timer(&priv->statistics_periodic);
- priv->statistics_periodic.data = (unsigned long)priv;
- priv->statistics_periodic.function = iwl_bg_statistics_periodic;
+ setup_timer(&priv->statistics_periodic, iwl_bg_statistics_periodic,
+ (unsigned long)priv);
- init_timer(&priv->ucode_trace);
- priv->ucode_trace.data = (unsigned long)priv;
- priv->ucode_trace.function = iwl_bg_ucode_trace;
+ setup_timer(&priv->ucode_trace, iwl_bg_ucode_trace,
+ (unsigned long)priv);
}
void iwl_cancel_deferred_work(struct iwl_priv *priv)
@@ -1244,11 +1228,8 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
trans_cfg.no_reclaim_cmds = no_reclaim_cmds;
trans_cfg.n_no_reclaim_cmds = ARRAY_SIZE(no_reclaim_cmds);
trans_cfg.rx_buf_size_8k = iwlwifi_mod_params.amsdu_size_8K;
- if (!iwlwifi_mod_params.wd_disable)
- trans_cfg.queue_watchdog_timeout =
- priv->cfg->base_params->wd_timeout;
- else
- trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
+ trans_cfg.cmd_q_wdg_timeout = IWL_WATCHDOG_DISABLED;
+
trans_cfg.command_names = iwl_dvm_cmd_strings;
trans_cfg.cmd_fifo = IWLAGN_CMD_FIFO_NUM;
diff --git a/drivers/net/wireless/iwlwifi/dvm/tt.c b/drivers/net/wireless/iwlwifi/dvm/tt.c
index acb981a0a0aa..c4736c8834c5 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tt.c
@@ -612,15 +612,10 @@ void iwl_tt_initialize(struct iwl_priv *priv)
memset(tt, 0, sizeof(struct iwl_tt_mgmt));
tt->state = IWL_TI_0;
- init_timer(&priv->thermal_throttle.ct_kill_exit_tm);
- priv->thermal_throttle.ct_kill_exit_tm.data = (unsigned long)priv;
- priv->thermal_throttle.ct_kill_exit_tm.function =
- iwl_tt_check_exit_ct_kill;
- init_timer(&priv->thermal_throttle.ct_kill_waiting_tm);
- priv->thermal_throttle.ct_kill_waiting_tm.data =
- (unsigned long)priv;
- priv->thermal_throttle.ct_kill_waiting_tm.function =
- iwl_tt_ready_for_ct_kill;
+ setup_timer(&priv->thermal_throttle.ct_kill_exit_tm,
+ iwl_tt_check_exit_ct_kill, (unsigned long)priv);
+ setup_timer(&priv->thermal_throttle.ct_kill_waiting_tm,
+ iwl_tt_ready_for_ct_kill, (unsigned long)priv);
/* setup deferred ct kill work */
INIT_WORK(&priv->tt_work, iwl_bg_tt_work);
INIT_WORK(&priv->ct_enter, iwl_bg_ct_enter);
diff --git a/drivers/net/wireless/iwlwifi/dvm/tx.c b/drivers/net/wireless/iwlwifi/dvm/tx.c
index d1ce3ce13591..1e40a12de077 100644
--- a/drivers/net/wireless/iwlwifi/dvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/dvm/tx.c
@@ -715,7 +715,7 @@ int iwlagn_tx_agg_oper(struct iwl_priv *priv, struct ieee80211_vif *vif,
fifo = ctx->ac_to_fifo[tid_to_ac[tid]];
iwl_trans_txq_enable(priv->trans, q, fifo, sta_priv->sta_id, tid,
- buf_size, ssn);
+ buf_size, ssn, 0);
/*
* If the limit is 0, then it wasn't initialised yet,
diff --git a/drivers/net/wireless/iwlwifi/dvm/ucode.c b/drivers/net/wireless/iwlwifi/dvm/ucode.c
index d5cee1530597..4dbef7e58c2e 100644
--- a/drivers/net/wireless/iwlwifi/dvm/ucode.c
+++ b/drivers/net/wireless/iwlwifi/dvm/ucode.c
@@ -267,7 +267,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)
for (i = 0; i < n_queues; i++)
if (queue_to_txf[i] != IWL_TX_FIFO_UNUSED)
iwl_trans_ac_txq_enable(priv->trans, i,
- queue_to_txf[i]);
+ queue_to_txf[i], 0);
priv->passive_no_rx = false;
priv->transport_queue_stop = 0;
diff --git a/drivers/net/wireless/iwlwifi/iwl-7000.c b/drivers/net/wireless/iwlwifi/iwl-7000.c
index a5f9198d5747..97e38d2e2983 100644
--- a/drivers/net/wireless/iwlwifi/iwl-7000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-7000.c
@@ -92,6 +92,12 @@
#define IWL7265D_NVM_VERSION 0x0c11
#define IWL7265_TX_POWER_VERSION 0xffff /* meaningless */
+/* DCCM offsets and lengths */
+#define IWL7000_DCCM_OFFSET 0x800000
+#define IWL7260_DCCM_LEN 0x14000
+#define IWL3160_DCCM_LEN 0x10000
+#define IWL7265_DCCM_LEN 0x17A00
+
#define IWL7260_FW_PRE "iwlwifi-7260-"
#define IWL7260_MODULE_FIRMWARE(api) IWL7260_FW_PRE __stringify(api) ".ucode"
@@ -138,7 +144,8 @@ static const struct iwl_ht_params iwl7000_ht_params = {
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_7000, \
.non_shared_ant = ANT_A, \
- .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K, \
+ .dccm_offset = IWL7000_DCCM_OFFSET
const struct iwl_cfg iwl7260_2ac_cfg = {
.name = "Intel(R) Dual Band Wireless AC 7260",
@@ -149,6 +156,7 @@ const struct iwl_cfg iwl7260_2ac_cfg = {
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
.lp_xtal_workaround = true,
+ .dccm_len = IWL7260_DCCM_LEN,
};
const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
@@ -161,6 +169,7 @@ const struct iwl_cfg iwl7260_2ac_cfg_high_temp = {
.high_temp = true,
.host_interrupt_operation_mode = true,
.lp_xtal_workaround = true,
+ .dccm_len = IWL7260_DCCM_LEN,
};
const struct iwl_cfg iwl7260_2n_cfg = {
@@ -172,6 +181,7 @@ const struct iwl_cfg iwl7260_2n_cfg = {
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
.lp_xtal_workaround = true,
+ .dccm_len = IWL7260_DCCM_LEN,
};
const struct iwl_cfg iwl7260_n_cfg = {
@@ -183,6 +193,7 @@ const struct iwl_cfg iwl7260_n_cfg = {
.nvm_calib_ver = IWL7260_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
.lp_xtal_workaround = true,
+ .dccm_len = IWL7260_DCCM_LEN,
};
const struct iwl_cfg iwl3160_2ac_cfg = {
@@ -193,6 +204,7 @@ const struct iwl_cfg iwl3160_2ac_cfg = {
.nvm_ver = IWL3160_NVM_VERSION,
.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
+ .dccm_len = IWL3160_DCCM_LEN,
};
const struct iwl_cfg iwl3160_2n_cfg = {
@@ -203,6 +215,7 @@ const struct iwl_cfg iwl3160_2n_cfg = {
.nvm_ver = IWL3160_NVM_VERSION,
.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
+ .dccm_len = IWL3160_DCCM_LEN,
};
const struct iwl_cfg iwl3160_n_cfg = {
@@ -213,6 +226,7 @@ const struct iwl_cfg iwl3160_n_cfg = {
.nvm_ver = IWL3160_NVM_VERSION,
.nvm_calib_ver = IWL3160_TX_POWER_VERSION,
.host_interrupt_operation_mode = true,
+ .dccm_len = IWL3160_DCCM_LEN,
};
static const struct iwl_pwr_tx_backoff iwl7265_pwr_tx_backoffs[] = {
@@ -240,6 +254,7 @@ const struct iwl_cfg iwl3165_2ac_cfg = {
.nvm_ver = IWL3165_NVM_VERSION,
.nvm_calib_ver = IWL3165_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
const struct iwl_cfg iwl7265_2ac_cfg = {
@@ -250,6 +265,7 @@ const struct iwl_cfg iwl7265_2ac_cfg = {
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
const struct iwl_cfg iwl7265_2n_cfg = {
@@ -260,6 +276,7 @@ const struct iwl_cfg iwl7265_2n_cfg = {
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
const struct iwl_cfg iwl7265_n_cfg = {
@@ -270,6 +287,7 @@ const struct iwl_cfg iwl7265_n_cfg = {
.nvm_ver = IWL7265_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
const struct iwl_cfg iwl7265d_2ac_cfg = {
@@ -280,6 +298,7 @@ const struct iwl_cfg iwl7265d_2ac_cfg = {
.nvm_ver = IWL7265D_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
const struct iwl_cfg iwl7265d_2n_cfg = {
@@ -290,6 +309,7 @@ const struct iwl_cfg iwl7265d_2n_cfg = {
.nvm_ver = IWL7265D_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
const struct iwl_cfg iwl7265d_n_cfg = {
@@ -300,6 +320,7 @@ const struct iwl_cfg iwl7265d_n_cfg = {
.nvm_ver = IWL7265D_NVM_VERSION,
.nvm_calib_ver = IWL7265_TX_POWER_VERSION,
.pwr_tx_backoffs = iwl7265_pwr_tx_backoffs,
+ .dccm_len = IWL7265_DCCM_LEN,
};
MODULE_FIRMWARE(IWL7260_MODULE_FIRMWARE(IWL7260_UCODE_API_OK));
diff --git a/drivers/net/wireless/iwlwifi/iwl-8000.c b/drivers/net/wireless/iwlwifi/iwl-8000.c
index 3668fc57e770..2f7fe8167dc9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-8000.c
+++ b/drivers/net/wireless/iwlwifi/iwl-8000.c
@@ -81,12 +81,21 @@
#define IWL8000_NVM_VERSION 0x0a1d
#define IWL8000_TX_POWER_VERSION 0xffff /* meaningless */
+/* Memory offsets and lengths */
+#define IWL8260_DCCM_OFFSET 0x800000
+#define IWL8260_DCCM_LEN 0x18000
+#define IWL8260_DCCM2_OFFSET 0x880000
+#define IWL8260_DCCM2_LEN 0x8000
+#define IWL8260_SMEM_OFFSET 0x400000
+#define IWL8260_SMEM_LEN 0x68000
+
#define IWL8000_FW_PRE "iwlwifi-8000"
#define IWL8000_MODULE_FIRMWARE(api) \
IWL8000_FW_PRE "-" __stringify(api) ".ucode"
#define NVM_HW_SECTION_NUM_FAMILY_8000 10
-#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000.bin"
+#define DEFAULT_NVM_FILE_FAMILY_8000A "iwl_nvm_8000.bin"
+#define DEFAULT_NVM_FILE_FAMILY_8000 "iwl_nvm_8000B.bin"
/* Max SDIO RX aggregation size of the ADDBA request/response */
#define MAX_RX_AGG_SIZE_8260_SDIO 28
@@ -124,7 +133,13 @@ static const struct iwl_ht_params iwl8000_ht_params = {
.led_mode = IWL_LED_RF_STATE, \
.nvm_hw_section_num = NVM_HW_SECTION_NUM_FAMILY_8000, \
.d0i3 = true, \
- .non_shared_ant = ANT_A
+ .non_shared_ant = ANT_A, \
+ .dccm_offset = IWL8260_DCCM_OFFSET, \
+ .dccm_len = IWL8260_DCCM_LEN, \
+ .dccm2_offset = IWL8260_DCCM2_OFFSET, \
+ .dccm2_len = IWL8260_DCCM2_LEN, \
+ .smem_offset = IWL8260_SMEM_OFFSET, \
+ .smem_len = IWL8260_SMEM_LEN
const struct iwl_cfg iwl8260_2n_cfg = {
.name = "Intel(R) Dual Band Wireless N 8260",
@@ -145,6 +160,16 @@ const struct iwl_cfg iwl8260_2ac_cfg = {
.max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
};
+const struct iwl_cfg iwl4165_2ac_cfg = {
+ .name = "Intel(R) Dual Band Wireless AC 4165",
+ .fw_name_pre = IWL8000_FW_PRE,
+ IWL_DEVICE_8000,
+ .ht_params = &iwl8000_ht_params,
+ .nvm_ver = IWL8000_NVM_VERSION,
+ .nvm_calib_ver = IWL8000_TX_POWER_VERSION,
+ .max_ht_ampdu_exponent = IEEE80211_HT_MAX_AMPDU_64K,
+};
+
const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.name = "Intel(R) Dual Band Wireless-AC 8260",
.fw_name_pre = IWL8000_FW_PRE,
@@ -153,6 +178,7 @@ const struct iwl_cfg iwl8260_2ac_sdio_cfg = {
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
+ .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.disable_dummy_notification = true,
.max_ht_ampdu_exponent = MAX_HT_AMPDU_EXPONENT_8260_SDIO,
@@ -167,6 +193,7 @@ const struct iwl_cfg iwl4165_2ac_sdio_cfg = {
.nvm_ver = IWL8000_NVM_VERSION,
.nvm_calib_ver = IWL8000_TX_POWER_VERSION,
.default_nvm_file = DEFAULT_NVM_FILE_FAMILY_8000,
+ .default_nvm_file_8000A = DEFAULT_NVM_FILE_FAMILY_8000A,
.max_rx_agg_size = MAX_RX_AGG_SIZE_8260_SDIO,
.bt_shared_single_ant = true,
.disable_dummy_notification = true,
diff --git a/drivers/net/wireless/iwlwifi/iwl-config.h b/drivers/net/wireless/iwlwifi/iwl-config.h
index 3a4b9c7fc083..4b190d98a1ec 100644
--- a/drivers/net/wireless/iwlwifi/iwl-config.h
+++ b/drivers/net/wireless/iwlwifi/iwl-config.h
@@ -126,7 +126,7 @@ enum iwl_led_mode {
/* TX queue watchdog timeouts in mSecs */
#define IWL_WATCHDOG_DISABLED 0
-#define IWL_DEF_WD_TIMEOUT 2000
+#define IWL_DEF_WD_TIMEOUT 2500
#define IWL_LONG_WD_TIMEOUT 10000
#define IWL_MAX_WD_TIMEOUT 120000
@@ -261,6 +261,12 @@ struct iwl_pwr_tx_backoff {
* station can receive in HT
* @max_vht_ampdu_exponent: the exponent of the max length of A-MPDU that the
* station can receive in VHT
+ * @dccm_offset: offset from which DCCM begins
+ * @dccm_len: length of DCCM (including runtime stack CCM)
+ * @dccm2_offset: offset from which the second DCCM begins
+ * @dccm2_len: length of the second DCCM
+ * @smem_offset: offset from which the SMEM begins
+ * @smem_len: the length of SMEM
*
* We enable the driver to be backward compatible wrt. hardware features.
* API differences in uCode shouldn't be handled here but through TLVs
@@ -298,11 +304,18 @@ struct iwl_cfg {
const struct iwl_pwr_tx_backoff *pwr_tx_backoffs;
bool no_power_up_nic_in_init;
const char *default_nvm_file;
+ const char *default_nvm_file_8000A;
unsigned int max_rx_agg_size;
bool disable_dummy_notification;
unsigned int max_tx_agg_size;
unsigned int max_ht_ampdu_exponent;
unsigned int max_vht_ampdu_exponent;
+ const u32 dccm_offset;
+ const u32 dccm_len;
+ const u32 dccm2_offset;
+ const u32 dccm2_len;
+ const u32 smem_offset;
+ const u32 smem_len;
};
/*
@@ -369,8 +382,8 @@ extern const struct iwl_cfg iwl7265d_2n_cfg;
extern const struct iwl_cfg iwl7265d_n_cfg;
extern const struct iwl_cfg iwl8260_2n_cfg;
extern const struct iwl_cfg iwl8260_2ac_cfg;
+extern const struct iwl_cfg iwl4165_2ac_cfg;
extern const struct iwl_cfg iwl8260_2ac_sdio_cfg;
-extern const struct iwl_cfg iwl4265_2ac_sdio_cfg;
extern const struct iwl_cfg iwl4165_2ac_sdio_cfg;
#endif /* CONFIG_IWLMVM */
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index aff63c3f5bf8..faa17f2e352a 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -184,6 +184,7 @@
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_READY (0x00400000) /* PCI_OWN_SEM */
#define CSR_HW_IF_CONFIG_REG_BIT_NIC_PREPARE_DONE (0x02000000) /* ME_OWN */
#define CSR_HW_IF_CONFIG_REG_PREPARE (0x08000000) /* WAKE_ME */
+#define CSR_HW_IF_CONFIG_REG_ENABLE_PME (0x10000000)
#define CSR_HW_IF_CONFIG_REG_PERSIST_MODE (0x40000000) /* PERSISTENCE */
#define CSR_MBOX_SET_REG_OS_ALIVE BIT(5)
@@ -306,6 +307,7 @@
enum {
SILICON_A_STEP = 0,
SILICON_B_STEP,
+ SILICON_C_STEP,
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.c b/drivers/net/wireless/iwlwifi/iwl-drv.c
index 850b85a47806..996e7f16adf9 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.c
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.c
@@ -84,21 +84,8 @@
*
******************************************************************************/
-/*
- * module name, copyright, version, etc.
- */
#define DRV_DESCRIPTION "Intel(R) Wireless WiFi driver for Linux"
-
-#ifdef CONFIG_IWLWIFI_DEBUG
-#define VD "d"
-#else
-#define VD
-#endif
-
-#define DRV_VERSION IWLWIFI_VERSION VD
-
MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -250,9 +237,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
/*
* Starting 8000B - FW name format has changed. This overwrites the
* previous name and uses the new format.
- *
- * TODO:
- * Once there is only one supported step for 8000 family - delete this!
*/
if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) {
char rev_step[2] = {
@@ -263,13 +247,6 @@ static int iwl_request_firmware(struct iwl_drv *drv, bool first)
if (CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP)
rev_step[0] = 0;
- /*
- * If hw_rev wasn't set yet - default as B-step. If it IS A-step
- * we'll reload that FW later instead.
- */
- if (drv->trans->hw_rev == 0)
- rev_step[0] = 'B';
-
snprintf(drv->firmware_name, sizeof(drv->firmware_name),
"%s%s-%s.ucode", name_pre, rev_step, tag);
}
@@ -926,6 +903,12 @@ static int iwl_parse_tlv_firmware(struct iwl_drv *drv,
IWL_UCODE_REGULAR_USNIFFER,
tlv_len);
break;
+ case IWL_UCODE_TLV_SDIO_ADMA_ADDR:
+ if (tlv_len != sizeof(u32))
+ goto invalid_tlv_len;
+ drv->fw.sdio_adma_addr =
+ le32_to_cpup((__le32 *)tlv_data);
+ break;
default:
IWL_DEBUG_INFO(drv, "unknown TLV: %d\n", tlv_type);
break;
@@ -1082,7 +1065,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
u32 api_ver;
int i;
bool load_module = false;
- u32 hw_rev = drv->trans->hw_rev;
fw->ucode_capa.max_probe_length = IWL_DEFAULT_MAX_PROBE_LENGTH;
fw->ucode_capa.standard_phy_calibration_size =
@@ -1275,50 +1257,6 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
op->name, err);
#endif
}
-
- /*
- * We may have loaded the wrong FW file in 8000 HW family if it is an
- * A-step card, and if drv->trans->hw_rev wasn't properly read when
- * the FW file had been loaded. (This might happen in SDIO.) In such a
- * case - unload and reload the correct file.
- *
- * TODO:
- * Once there is only one supported step for 8000 family - delete this!
- */
- if (drv->trans->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
- CSR_HW_REV_STEP(drv->trans->hw_rev) == SILICON_A_STEP &&
- drv->trans->hw_rev != hw_rev) {
- char firmware_name[32];
-
- /* Free previous FW resources */
- if (drv->op_mode)
- _iwl_op_mode_stop(drv);
- iwl_dealloc_ucode(drv);
-
- /* Build name of correct-step FW */
- snprintf(firmware_name, sizeof(firmware_name),
- strrchr(drv->firmware_name, '-'));
- snprintf(drv->firmware_name, sizeof(drv->firmware_name),
- "%s%s", drv->cfg->fw_name_pre, firmware_name);
-
- /* Clear data before loading correct FW */
- list_del(&drv->list);
-
- /* Request correct FW file this time */
- IWL_DEBUG_INFO(drv, "attempting to load A-step FW %s\n",
- drv->firmware_name);
- err = request_firmware(&ucode_raw, drv->firmware_name,
- drv->trans->dev);
- if (err) {
- IWL_ERR(drv, "Failed swapping FW!\n");
- goto out_unbind;
- }
-
- /* Redo callback function - this time with right FW */
- iwl_req_fw_callback(ucode_raw, context);
- }
-
- kfree(pieces);
return;
try_again:
@@ -1429,7 +1367,7 @@ struct iwl_mod_params iwlwifi_mod_params = {
.restart_fw = true,
.bt_coex_active = true,
.power_level = IWL_POWER_INDEX_1,
- .wd_disable = true,
+ .d0i3_disable = true,
#ifndef CONFIG_IWLWIFI_UAPSD
.uapsd_disable = true,
#endif /* CONFIG_IWLWIFI_UAPSD */
@@ -1492,7 +1430,7 @@ static int __init iwl_drv_init(void)
for (i = 0; i < ARRAY_SIZE(iwlwifi_opmode_table); i++)
INIT_LIST_HEAD(&iwlwifi_opmode_table[i].drv);
- pr_info(DRV_DESCRIPTION ", " DRV_VERSION "\n");
+ pr_info(DRV_DESCRIPTION "\n");
pr_info(DRV_COPYRIGHT "\n");
#ifdef CONFIG_IWLWIFI_DEBUGFS
@@ -1539,15 +1477,15 @@ module_param_named(antenna_coupling, iwlwifi_mod_params.ant_coupling,
MODULE_PARM_DESC(antenna_coupling,
"specify antenna coupling in dB (default: 0 dB)");
-module_param_named(wd_disable, iwlwifi_mod_params.wd_disable, int, S_IRUGO);
-MODULE_PARM_DESC(wd_disable,
- "Disable stuck queue watchdog timer 0=system default, 1=disable (default: 1)");
-
module_param_named(nvm_file, iwlwifi_mod_params.nvm_file, charp, S_IRUGO);
MODULE_PARM_DESC(nvm_file, "NVM file name");
-module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
+module_param_named(d0i3_disable, iwlwifi_mod_params.d0i3_disable,
bool, S_IRUGO);
+MODULE_PARM_DESC(d0i3_disable, "disable d0i3 functionality (default: Y)");
+
+module_param_named(uapsd_disable, iwlwifi_mod_params.uapsd_disable,
+ bool, S_IRUGO | S_IWUSR);
#ifdef CONFIG_IWLWIFI_UAPSD
MODULE_PARM_DESC(uapsd_disable, "disable U-APSD functionality (default: N)");
#else
diff --git a/drivers/net/wireless/iwlwifi/iwl-drv.h b/drivers/net/wireless/iwlwifi/iwl-drv.h
index be4f8972241a..adf522c756e6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-drv.h
+++ b/drivers/net/wireless/iwlwifi/iwl-drv.h
@@ -68,7 +68,6 @@
/* for all modules */
#define DRV_NAME "iwlwifi"
-#define IWLWIFI_VERSION "in-tree:"
#define DRV_COPYRIGHT "Copyright(c) 2003- 2014 Intel Corporation"
#define DRV_AUTHOR "<ilw@linux.intel.com>"
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
index 20a8a64c9fe3..919a2548a92c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-error-dump.h
@@ -71,7 +71,6 @@
/**
* enum iwl_fw_error_dump_type - types of data in the dump file
- * @IWL_FW_ERROR_DUMP_SRAM:
* @IWL_FW_ERROR_DUMP_CSR: Control Status Registers - from offset 0
* @IWL_FW_ERROR_DUMP_RXF:
* @IWL_FW_ERROR_DUMP_TXCMD: last TX command data, structured as
@@ -82,9 +81,10 @@
* @IWL_FW_ERROR_DUMP_PRPH: range of periphery registers - there can be several
* sections like this in a single file.
* @IWL_FW_ERROR_DUMP_FH_REGS: range of FH registers
+ * @IWL_FW_ERROR_DUMP_MEM: chunk of memory
*/
enum iwl_fw_error_dump_type {
- IWL_FW_ERROR_DUMP_SRAM = 0,
+ /* 0 is deprecated */
IWL_FW_ERROR_DUMP_CSR = 1,
IWL_FW_ERROR_DUMP_RXF = 2,
IWL_FW_ERROR_DUMP_TXCMD = 3,
@@ -93,6 +93,7 @@ enum iwl_fw_error_dump_type {
IWL_FW_ERROR_DUMP_PRPH = 6,
IWL_FW_ERROR_DUMP_TXF = 7,
IWL_FW_ERROR_DUMP_FH_REGS = 8,
+ IWL_FW_ERROR_DUMP_MEM = 9,
IWL_FW_ERROR_DUMP_MAX,
};
@@ -133,6 +134,27 @@ struct iwl_fw_error_dump_txcmd {
u8 data[];
} __packed;
+/**
+ * struct iwl_fw_error_dump_fifo - RX/TX FIFO data
+ * @fifo_num: number of FIFO (starting from 0)
+ * @available_bytes: num of bytes available in FIFO (may be less than FIFO size)
+ * @wr_ptr: position of write pointer
+ * @rd_ptr: position of read pointer
+ * @fence_ptr: position of fence pointer
+ * @fence_mode: the current mode of the fence (before locking) -
+ * 0=follow RD pointer ; 1 = freeze
+ * @data: all of the FIFO's data
+ */
+struct iwl_fw_error_dump_fifo {
+ __le32 fifo_num;
+ __le32 available_bytes;
+ __le32 wr_ptr;
+ __le32 rd_ptr;
+ __le32 fence_ptr;
+ __le32 fence_mode;
+ u8 data[];
+} __packed;
+
enum iwl_fw_error_dump_family {
IWL_FW_ERROR_DUMP_FAMILY_7 = 7,
IWL_FW_ERROR_DUMP_FAMILY_8 = 8,
@@ -180,6 +202,23 @@ struct iwl_fw_error_dump_prph {
__le32 data[];
};
+enum iwl_fw_error_dump_mem_type {
+ IWL_FW_ERROR_DUMP_MEM_SRAM,
+ IWL_FW_ERROR_DUMP_MEM_SMEM,
+};
+
+/**
+ * struct iwl_fw_error_dump_mem - chunk of memory
+ * @type: %enum iwl_fw_error_dump_mem_type
+ * @offset: the offset from which the memory was read
+ * @data: the content of the memory
+ */
+struct iwl_fw_error_dump_mem {
+ __le32 type;
+ __le32 offset;
+ u8 data[];
+};
+
/**
* iwl_fw_error_next_data - advance fw error dump data pointer
* @data: previous data block
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw-file.h b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
index 660ddb1b7d8a..016d91384681 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw-file.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw-file.h
@@ -132,6 +132,7 @@ enum iwl_ucode_tlv_type {
IWL_UCODE_TLV_ENABLED_CAPABILITIES = 30,
IWL_UCODE_TLV_N_SCAN_CHANNELS = 31,
IWL_UCODE_TLV_SEC_RT_USNIFFER = 34,
+ IWL_UCODE_TLV_SDIO_ADMA_ADDR = 35,
IWL_UCODE_TLV_FW_DBG_DEST = 38,
IWL_UCODE_TLV_FW_DBG_CONF = 39,
};
@@ -234,31 +235,34 @@ enum iwl_ucode_tlv_flag {
/**
* enum iwl_ucode_tlv_api - ucode api
- * @IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID: wowlan config includes tid field.
- * @IWL_UCODE_TLV_CAPA_EXTENDED_BEACON: Support Extended beacon notification
* @IWL_UCODE_TLV_API_BT_COEX_SPLIT: new API for BT Coex
- * @IWL_UCODE_TLV_API_CSA_FLOW: ucode can do unbind-bind flow for CSA.
* @IWL_UCODE_TLV_API_DISABLE_STA_TX: ucode supports tx_disable bit.
* @IWL_UCODE_TLV_API_LMAC_SCAN: This ucode uses LMAC unified scan API.
* @IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF: ucode supports disabling dummy notif.
* @IWL_UCODE_TLV_API_FRAGMENTED_SCAN: This ucode supports active dwell time
* longer than the passive one, which is essential for fragmented scan.
+ * IWL_UCODE_TLV_API_HDC_PHASE_0: ucode supports finer configuration of LTR
* @IWL_UCODE_TLV_API_BASIC_DWELL: use only basic dwell time in scan command,
* regardless of the band or the number of the probes. FW will calculate
* the actual dwell time.
+ * @IWL_UCODE_TLV_API_SCD_CFG: This firmware can configure the scheduler
+ * through the dedicated host command.
* @IWL_UCODE_TLV_API_SINGLE_SCAN_EBS: EBS is supported for single scans too.
+ * @IWL_UCODE_TLV_API_ASYNC_DTM: Async temperature notifications are supported.
+ * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
*/
enum iwl_ucode_tlv_api {
- IWL_UCODE_TLV_API_WOWLAN_CONFIG_TID = BIT(0),
- IWL_UCODE_TLV_CAPA_EXTENDED_BEACON = BIT(1),
IWL_UCODE_TLV_API_BT_COEX_SPLIT = BIT(3),
- IWL_UCODE_TLV_API_CSA_FLOW = BIT(4),
IWL_UCODE_TLV_API_DISABLE_STA_TX = BIT(5),
IWL_UCODE_TLV_API_LMAC_SCAN = BIT(6),
IWL_UCODE_TLV_API_SF_NO_DUMMY_NOTIF = BIT(7),
IWL_UCODE_TLV_API_FRAGMENTED_SCAN = BIT(8),
+ IWL_UCODE_TLV_API_HDC_PHASE_0 = BIT(10),
IWL_UCODE_TLV_API_BASIC_DWELL = BIT(13),
+ IWL_UCODE_TLV_API_SCD_CFG = BIT(15),
IWL_UCODE_TLV_API_SINGLE_SCAN_EBS = BIT(16),
+ IWL_UCODE_TLV_API_ASYNC_DTM = BIT(17),
+ IWL_UCODE_TLV_API_LQ_SS_PARAMS = BIT(18),
};
/**
@@ -266,6 +270,7 @@ enum iwl_ucode_tlv_api {
* @IWL_UCODE_TLV_CAPA_D0I3_SUPPORT: supports D0i3
* @IWL_UCODE_TLV_CAPA_LAR_SUPPORT: supports Location Aware Regulatory
* @IWL_UCODE_TLV_CAPA_UMAC_SCAN: supports UMAC scan.
+ * @IWL_UCODE_TLV_CAPA_BEAMFORMER: supports Beamformer
* @IWL_UCODE_TLV_CAPA_TDLS_SUPPORT: support basic TDLS functionality
* @IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT: supports insertion of current
* tx power value into TPC Report action frame and Link Measurement Report
@@ -284,6 +289,7 @@ enum iwl_ucode_tlv_capa {
IWL_UCODE_TLV_CAPA_D0I3_SUPPORT = BIT(0),
IWL_UCODE_TLV_CAPA_LAR_SUPPORT = BIT(1),
IWL_UCODE_TLV_CAPA_UMAC_SCAN = BIT(2),
+ IWL_UCODE_TLV_CAPA_BEAMFORMER = BIT(3),
IWL_UCODE_TLV_CAPA_TDLS_SUPPORT = BIT(6),
IWL_UCODE_TLV_CAPA_TXPOWER_INSERTION_SUPPORT = BIT(8),
IWL_UCODE_TLV_CAPA_DS_PARAM_SET_IE_SUPPORT = BIT(9),
diff --git a/drivers/net/wireless/iwlwifi/iwl-fw.h b/drivers/net/wireless/iwlwifi/iwl-fw.h
index e6dc3b870949..ffd785cc67d6 100644
--- a/drivers/net/wireless/iwlwifi/iwl-fw.h
+++ b/drivers/net/wireless/iwlwifi/iwl-fw.h
@@ -152,6 +152,8 @@ struct iwl_fw_cscheme_list {
* @mvm_fw: indicates this is MVM firmware
* @cipher_scheme: optional external cipher scheme.
* @human_readable: human readable version
+ * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
+ * we get the ALIVE from the uCode
* @dbg_dest_tlv: points to the destination TLV for debug
* @dbg_conf_tlv: array of pointers to configuration TLVs for debug
* @dbg_conf_tlv_len: lengths of the @dbg_conf_tlv entries
@@ -181,6 +183,8 @@ struct iwl_fw {
struct ieee80211_cipher_scheme cs[IWL_UCODE_MAX_CS];
u8 human_readable[FW_VER_HUMAN_READABLE_SZ];
+ u32 sdio_adma_addr;
+
struct iwl_fw_dbg_dest_tlv *dbg_dest_tlv;
struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
size_t dbg_conf_tlv_len[FW_DBG_MAX];
diff --git a/drivers/net/wireless/iwlwifi/iwl-io.c b/drivers/net/wireless/iwlwifi/iwl-io.c
index 7a2cbf6f90db..03250a45272e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-io.c
+++ b/drivers/net/wireless/iwlwifi/iwl-io.c
@@ -193,11 +193,15 @@ void iwl_force_nmi(struct iwl_trans *trans)
* DEVICE_SET_NMI_8000B_REG - is used.
*/
if ((trans->cfg->device_family != IWL_DEVICE_FAMILY_8000) ||
- (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
- iwl_write_prph(trans, DEVICE_SET_NMI_REG, DEVICE_SET_NMI_VAL);
- else
+ (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP)) {
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG,
+ DEVICE_SET_NMI_VAL_DRV);
+ iwl_write_prph(trans, DEVICE_SET_NMI_REG,
+ DEVICE_SET_NMI_VAL_HW);
+ } else {
iwl_write_prph(trans, DEVICE_SET_NMI_8000B_REG,
DEVICE_SET_NMI_8000B_VAL);
+ }
}
IWL_EXPORT_SYMBOL(iwl_force_nmi);
diff --git a/drivers/net/wireless/iwlwifi/iwl-modparams.h b/drivers/net/wireless/iwlwifi/iwl-modparams.h
index 71507cf490e6..e8eabd21ccfe 100644
--- a/drivers/net/wireless/iwlwifi/iwl-modparams.h
+++ b/drivers/net/wireless/iwlwifi/iwl-modparams.h
@@ -96,13 +96,13 @@ enum iwl_disable_11n {
* use IWL_[DIS,EN]ABLE_HT_* constants
* @amsdu_size_8K: enable 8K amsdu size, default = 0
* @restart_fw: restart firmware, default = 1
- * @wd_disable: disable stuck queue check, default = 1
* @bt_coex_active: enable bt coex, default = true
* @led_mode: system default, default = 0
* @power_save: enable power save, default = false
* @power_level: power level, default = 1
* @debug_level: levels are IWL_DL_*
* @ant_coupling: antenna coupling in dB, default = 0
+ * @d0i3_disable: disable d0i3, default = 1,
* @fw_monitor: allow to use firmware monitor
*/
struct iwl_mod_params {
@@ -110,7 +110,6 @@ struct iwl_mod_params {
unsigned int disable_11n;
int amsdu_size_8K;
bool restart_fw;
- int wd_disable;
bool bt_coex_active;
int led_mode;
bool power_save;
@@ -121,6 +120,7 @@ struct iwl_mod_params {
int ant_coupling;
char *nvm_file;
bool uapsd_disable;
+ bool d0i3_disable;
bool fw_monitor;
};
diff --git a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
index 06e02fcd6f7b..c74f1a4edf23 100644
--- a/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
+++ b/drivers/net/wireless/iwlwifi/iwl-nvm-parse.c
@@ -468,6 +468,8 @@ static void iwl_set_radio_cfg(const struct iwl_cfg *cfg,
data->radio_cfg_step = NVM_RF_CFG_STEP_MSK_FAMILY_8000(radio_cfg);
data->radio_cfg_dash = NVM_RF_CFG_DASH_MSK_FAMILY_8000(radio_cfg);
data->radio_cfg_pnum = NVM_RF_CFG_FLAVOR_MSK_FAMILY_8000(radio_cfg);
+ data->valid_tx_ant = NVM_RF_CFG_TX_ANT_MSK_FAMILY_8000(radio_cfg);
+ data->valid_rx_ant = NVM_RF_CFG_RX_ANT_MSK_FAMILY_8000(radio_cfg);
}
static void iwl_set_hw_address(const struct iwl_cfg *cfg,
@@ -592,6 +594,10 @@ iwl_parse_nvm_data(struct device *dev, const struct iwl_cfg *cfg,
radio_cfg = iwl_get_radio_cfg(cfg, nvm_sw);
iwl_set_radio_cfg(cfg, data, radio_cfg);
+ if (data->valid_tx_ant)
+ tx_chains &= data->valid_tx_ant;
+ if (data->valid_rx_ant)
+ rx_chains &= data->valid_rx_ant;
sku = iwl_get_sku(cfg, nvm_sw);
data->sku_cap_band_24GHz_enable = sku & NVM_SKU_CAP_BAND_24GHZ;
diff --git a/drivers/net/wireless/iwlwifi/iwl-prph.h b/drivers/net/wireless/iwlwifi/iwl-prph.h
index 2df51eab1348..6221e4dfc64f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-prph.h
+++ b/drivers/net/wireless/iwlwifi/iwl-prph.h
@@ -99,6 +99,7 @@
#define APMG_PCIDEV_STT_VAL_PERSIST_DIS (0x00000200)
#define APMG_PCIDEV_STT_VAL_L1_ACT_DIS (0x00000800)
+#define APMG_PCIDEV_STT_VAL_WAKE_ME (0x00004000)
#define APMG_RTC_INT_STT_RFKILL (0x10000000)
@@ -107,7 +108,8 @@
/* Device NMI register */
#define DEVICE_SET_NMI_REG 0x00a01c30
-#define DEVICE_SET_NMI_VAL 0x1
+#define DEVICE_SET_NMI_VAL_HW BIT(0)
+#define DEVICE_SET_NMI_VAL_DRV BIT(7)
#define DEVICE_SET_NMI_8000B_REG 0x00a01c24
#define DEVICE_SET_NMI_8000B_VAL 0x1000000
@@ -250,6 +252,7 @@
#define SCD_QUEUE_CTX_REG2_WIN_SIZE_MSK (0x0000007F)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_POS (16)
#define SCD_QUEUE_CTX_REG2_FRAME_LIMIT_MSK (0x007F0000)
+#define SCD_GP_CTRL_ENABLE_31_QUEUES BIT(0)
/* Context Data */
#define SCD_CONTEXT_MEM_LOWER_BOUND (SCD_MEM_LOWER_BOUND + 0x600)
@@ -283,32 +286,9 @@
#define SCD_CHAINEXT_EN (SCD_BASE + 0x244)
#define SCD_AGGR_SEL (SCD_BASE + 0x248)
#define SCD_INTERRUPT_MASK (SCD_BASE + 0x108)
+#define SCD_GP_CTRL (SCD_BASE + 0x1a8)
#define SCD_EN_CTRL (SCD_BASE + 0x254)
-static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
-{
- if (chnl < 20)
- return SCD_BASE + 0x18 + chnl * 4;
- WARN_ON_ONCE(chnl >= 32);
- return SCD_BASE + 0x284 + (chnl - 20) * 4;
-}
-
-static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl)
-{
- if (chnl < 20)
- return SCD_BASE + 0x68 + chnl * 4;
- WARN_ON_ONCE(chnl >= 32);
- return SCD_BASE + 0x2B4 + (chnl - 20) * 4;
-}
-
-static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
-{
- if (chnl < 20)
- return SCD_BASE + 0x10c + chnl * 4;
- WARN_ON_ONCE(chnl >= 32);
- return SCD_BASE + 0x384 + (chnl - 20) * 4;
-}
-
/*********************** END TX SCHEDULER *************************************/
/* Oscillator clock */
@@ -358,18 +338,40 @@ enum secure_load_status_reg {
/* Rx FIFO */
#define RXF_SIZE_ADDR (0xa00c88)
+#define RXF_RD_D_SPACE (0xa00c40)
+#define RXF_RD_WR_PTR (0xa00c50)
+#define RXF_RD_RD_PTR (0xa00c54)
+#define RXF_RD_FENCE_PTR (0xa00c4c)
+#define RXF_SET_FENCE_MODE (0xa00c14)
+#define RXF_LD_WR2FENCE (0xa00c1c)
+#define RXF_FIFO_RD_FENCE_INC (0xa00c68)
#define RXF_SIZE_BYTE_CND_POS (7)
#define RXF_SIZE_BYTE_CNT_MSK (0x3ff << RXF_SIZE_BYTE_CND_POS)
+#define RXF_DIFF_FROM_PREV (0x200)
#define RXF_LD_FENCE_OFFSET_ADDR (0xa00c10)
#define RXF_FIFO_RD_FENCE_ADDR (0xa00c0c)
+/* Tx FIFO */
+#define TXF_FIFO_ITEM_CNT (0xa00438)
+#define TXF_WR_PTR (0xa00414)
+#define TXF_RD_PTR (0xa00410)
+#define TXF_FENCE_PTR (0xa00418)
+#define TXF_LOCK_FENCE (0xa00424)
+#define TXF_LARC_NUM (0xa0043c)
+#define TXF_READ_MODIFY_DATA (0xa00448)
+#define TXF_READ_MODIFY_ADDR (0xa0044c)
+
/* FW monitor */
+#define MON_BUFF_SAMPLE_CTL (0xa03c00)
#define MON_BUFF_BASE_ADDR (0xa03c3c)
#define MON_BUFF_END_ADDR (0xa03c40)
#define MON_BUFF_WRPTR (0xa03c44)
#define MON_BUFF_CYCLE_CNT (0xa03c48)
+#define DBGC_IN_SAMPLE (0xa03c00)
+#define DBGC_OUT_CTRL (0xa03c0c)
+
/* FW chicken bits */
#define LMPM_CHICK 0xA01FF8
enum {
diff --git a/drivers/net/wireless/iwlwifi/iwl-scd.h b/drivers/net/wireless/iwlwifi/iwl-scd.h
index 6c622b21bba7..f2353ebf2666 100644
--- a/drivers/net/wireless/iwlwifi/iwl-scd.h
+++ b/drivers/net/wireless/iwlwifi/iwl-scd.h
@@ -69,14 +69,6 @@
#include "iwl-prph.h"
-static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
- u16 txq_id)
-{
- iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
- (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
- (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
-}
-
static inline void iwl_scd_txq_set_chain(struct iwl_trans *trans,
u16 txq_id)
{
@@ -115,4 +107,37 @@ static inline void iwl_scd_enable_set_active(struct iwl_trans *trans,
{
iwl_write_prph(trans, SCD_EN_CTRL, value);
}
+
+static inline unsigned int SCD_QUEUE_WRPTR(unsigned int chnl)
+{
+ if (chnl < 20)
+ return SCD_BASE + 0x18 + chnl * 4;
+ WARN_ON_ONCE(chnl >= 32);
+ return SCD_BASE + 0x284 + (chnl - 20) * 4;
+}
+
+static inline unsigned int SCD_QUEUE_RDPTR(unsigned int chnl)
+{
+ if (chnl < 20)
+ return SCD_BASE + 0x68 + chnl * 4;
+ WARN_ON_ONCE(chnl >= 32);
+ return SCD_BASE + 0x2B4 + chnl * 4;
+}
+
+static inline unsigned int SCD_QUEUE_STATUS_BITS(unsigned int chnl)
+{
+ if (chnl < 20)
+ return SCD_BASE + 0x10c + chnl * 4;
+ WARN_ON_ONCE(chnl >= 32);
+ return SCD_BASE + 0x334 + chnl * 4;
+}
+
+static inline void iwl_scd_txq_set_inactive(struct iwl_trans *trans,
+ u16 txq_id)
+{
+ iwl_write_prph(trans, SCD_QUEUE_STATUS_BITS(txq_id),
+ (0 << SCD_QUEUE_STTS_REG_POS_ACTIVE)|
+ (1 << SCD_QUEUE_STTS_REG_POS_SCD_ACT_EN));
+}
+
#endif
diff --git a/drivers/net/wireless/iwlwifi/iwl-trans.h b/drivers/net/wireless/iwlwifi/iwl-trans.h
index 028408a6ecba..a96bd8db6ceb 100644
--- a/drivers/net/wireless/iwlwifi/iwl-trans.h
+++ b/drivers/net/wireless/iwlwifi/iwl-trans.h
@@ -368,6 +368,7 @@ enum iwl_trans_status {
* @cmd_queue: the index of the command queue.
* Must be set before start_fw.
* @cmd_fifo: the fifo for host commands
+ * @cmd_q_wdg_timeout: the timeout of the watchdog timer for the command queue.
* @no_reclaim_cmds: Some devices erroneously don't set the
* SEQ_RX_FRAME bit on some notifications, this is the
* list of such notifications to filter. Max length is
@@ -378,24 +379,26 @@ enum iwl_trans_status {
* @bc_table_dword: set to true if the BC table expects the byte count to be
* in DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
- * @queue_watchdog_timeout: time (in ms) after which queues
- * are considered stuck and will trigger device restart
* @command_names: array of command names, must be 256 entries
* (one for each command); for debugging only
+ * @sdio_adma_addr: the default address to set for the ADMA in SDIO mode until
+ * we get the ALIVE from the uCode
*/
struct iwl_trans_config {
struct iwl_op_mode *op_mode;
u8 cmd_queue;
u8 cmd_fifo;
+ unsigned int cmd_q_wdg_timeout;
const u8 *no_reclaim_cmds;
unsigned int n_no_reclaim_cmds;
bool rx_buf_size_8k;
bool bc_table_dword;
bool scd_set_active;
- unsigned int queue_watchdog_timeout;
const char *const *command_names;
+
+ u32 sdio_adma_addr;
};
struct iwl_trans_dump_data {
@@ -507,7 +510,8 @@ struct iwl_trans_ops {
struct sk_buff_head *skbs);
void (*txq_enable)(struct iwl_trans *trans, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg);
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int queue_wdg_timeout);
void (*txq_disable)(struct iwl_trans *trans, int queue,
bool configure_scd);
@@ -552,6 +556,21 @@ enum iwl_trans_state {
};
/**
+ * enum iwl_d0i3_mode - d0i3 mode
+ *
+ * @IWL_D0I3_MODE_OFF - d0i3 is disabled
+ * @IWL_D0I3_MODE_ON_IDLE - enter d0i3 when device is idle
+ * (e.g. no active references)
+ * @IWL_D0I3_MODE_ON_SUSPEND - enter d0i3 only on suspend
+ * (in case of 'any' trigger)
+ */
+enum iwl_d0i3_mode {
+ IWL_D0I3_MODE_OFF = 0,
+ IWL_D0I3_MODE_ON_IDLE,
+ IWL_D0I3_MODE_ON_SUSPEND,
+};
+
+/**
* struct iwl_trans - transport common data
*
* @ops - pointer to iwl_trans_ops
@@ -612,6 +631,8 @@ struct iwl_trans {
const struct iwl_fw_dbg_conf_tlv *dbg_conf_tlv[FW_DBG_MAX];
u8 dbg_dest_reg_num;
+ enum iwl_d0i3_mode d0i3_mode;
+
/* pointer to trans specific struct */
/*Ensure that this pointer will always be aligned to sizeof pointer */
char trans_specific[0] __aligned(sizeof(void *));
@@ -808,19 +829,21 @@ static inline void iwl_trans_txq_disable(struct iwl_trans *trans, int queue,
static inline void
iwl_trans_txq_enable_cfg(struct iwl_trans *trans, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg)
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int queue_wdg_timeout)
{
might_sleep();
if (unlikely((trans->state != IWL_TRANS_FW_ALIVE)))
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
- trans->ops->txq_enable(trans, queue, ssn, cfg);
+ trans->ops->txq_enable(trans, queue, ssn, cfg, queue_wdg_timeout);
}
static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
int fifo, int sta_id, int tid,
- int frame_limit, u16 ssn)
+ int frame_limit, u16 ssn,
+ unsigned int queue_wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -830,11 +853,12 @@ static inline void iwl_trans_txq_enable(struct iwl_trans *trans, int queue,
.aggregate = sta_id >= 0,
};
- iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg);
+ iwl_trans_txq_enable_cfg(trans, queue, ssn, &cfg, queue_wdg_timeout);
}
-static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
- int fifo)
+static inline
+void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue, int fifo,
+ unsigned int queue_wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -844,16 +868,16 @@ static inline void iwl_trans_ac_txq_enable(struct iwl_trans *trans, int queue,
.aggregate = false,
};
- iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg);
+ iwl_trans_txq_enable_cfg(trans, queue, 0, &cfg, queue_wdg_timeout);
}
static inline int iwl_trans_wait_tx_queue_empty(struct iwl_trans *trans,
- u32 txq_bm)
+ u32 txqs)
{
if (unlikely(trans->state != IWL_TRANS_FW_ALIVE))
IWL_ERR(trans, "%s bad state = %d\n", __func__, trans->state);
- return trans->ops->wait_tx_queue_empty(trans, txq_bm);
+ return trans->ops->wait_tx_queue_empty(trans, txqs);
}
static inline int iwl_trans_dbgfs_register(struct iwl_trans *trans,
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex.c b/drivers/net/wireless/iwlwifi/mvm/coex.c
index a3bfda45d9e6..1ec4d55155f7 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex.c
@@ -342,7 +342,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 12,
.lut20 = {
- cpu_to_le32(0x00000001), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -363,7 +363,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 20,
.lut20 = {
- cpu_to_le32(0x00000002), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -384,7 +384,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 21,
.lut20 = {
- cpu_to_le32(0x00000003), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -405,7 +405,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 23,
.lut20 = {
- cpu_to_le32(0x00000004), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -426,7 +426,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 27,
.lut20 = {
- cpu_to_le32(0x00000005), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -447,7 +447,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 30,
.lut20 = {
- cpu_to_le32(0x00000006), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -468,7 +468,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 32,
.lut20 = {
- cpu_to_le32(0x00000007), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -489,7 +489,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 33,
.lut20 = {
- cpu_to_le32(0x00000008), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -989,7 +989,7 @@ int iwl_mvm_rx_bt_coex_notif(struct iwl_mvm *mvm,
static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
@@ -1025,7 +1025,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
void iwl_mvm_bt_rssi_event(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event)
{
- struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data data = {
.mvm = mvm,
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
index b3210cfbecc8..d530ef3da107 100644
--- a/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
+++ b/drivers/net/wireless/iwlwifi/mvm/coex_legacy.c
@@ -330,7 +330,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 12,
.lut20 = {
- cpu_to_le32(0x00000001), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -351,7 +351,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 20,
.lut20 = {
- cpu_to_le32(0x00000002), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -372,7 +372,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 21,
.lut20 = {
- cpu_to_le32(0x00000003), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -393,7 +393,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 23,
.lut20 = {
- cpu_to_le32(0x00000004), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -414,7 +414,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 27,
.lut20 = {
- cpu_to_le32(0x00000005), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -435,7 +435,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 30,
.lut20 = {
- cpu_to_le32(0x00000006), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -456,7 +456,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 32,
.lut20 = {
- cpu_to_le32(0x00000007), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -477,7 +477,7 @@ static const struct corunning_block_luts antenna_coupling_ranges[] = {
{
.range = 33,
.lut20 = {
- cpu_to_le32(0x00000008), cpu_to_le32(0x00000000),
+ cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
cpu_to_le32(0x00000000), cpu_to_le32(0x00000000),
@@ -1034,7 +1034,7 @@ int iwl_mvm_rx_bt_coex_notif_old(struct iwl_mvm *mvm,
static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
struct ieee80211_vif *vif)
{
- struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data *data = _data;
struct iwl_mvm *mvm = data->mvm;
@@ -1070,7 +1070,7 @@ static void iwl_mvm_bt_rssi_iterator(void *_data, u8 *mac,
void iwl_mvm_bt_rssi_event_old(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
enum ieee80211_rssi_event rssi_event)
{
- struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
struct iwl_bt_iterator_data data = {
.mvm = mvm,
};
diff --git a/drivers/net/wireless/iwlwifi/mvm/constants.h b/drivers/net/wireless/iwlwifi/mvm/constants.h
index 3bd93476ec1c..beba375489f1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/constants.h
+++ b/drivers/net/wireless/iwlwifi/mvm/constants.h
@@ -94,13 +94,42 @@
#define IWL_MVM_BT_COEX_MPLUT 1
#define IWL_MVM_BT_COEX_RRC 1
#define IWL_MVM_BT_COEX_TTC 1
-#define IWL_MVM_BT_COEX_MPLUT_REG0 0x28412201
+#define IWL_MVM_BT_COEX_MPLUT_REG0 0x22002200
#define IWL_MVM_BT_COEX_MPLUT_REG1 0x11118451
#define IWL_MVM_BT_COEX_ANTENNA_COUPLING_THRS 30
#define IWL_MVM_FW_MCAST_FILTER_PASS_ALL 0
#define IWL_MVM_FW_BCAST_FILTER_PASS_ALL 0
-#define IWL_MVM_QUOTA_THRESHOLD 8
+#define IWL_MVM_QUOTA_THRESHOLD 4
#define IWL_MVM_RS_RSSI_BASED_INIT_RATE 0
-#define IWL_MVM_RS_DISABLE_MIMO 0
+#define IWL_MVM_RS_DISABLE_P2P_MIMO 0
+#define IWL_MVM_RS_NUM_TRY_BEFORE_ANT_TOGGLE 1
+#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE 2
+#define IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE_TW 1
+#define IWL_MVM_RS_INITIAL_MIMO_NUM_RATES 3
+#define IWL_MVM_RS_INITIAL_SISO_NUM_RATES 3
+#define IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES 2
+#define IWL_MVM_RS_INITIAL_LEGACY_RETRIES 2
+#define IWL_MVM_RS_SECONDARY_LEGACY_RETRIES 1
+#define IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES 16
+#define IWL_MVM_RS_SECONDARY_SISO_NUM_RATES 3
+#define IWL_MVM_RS_SECONDARY_SISO_RETRIES 1
+#define IWL_MVM_RS_RATE_MIN_FAILURE_TH 3
+#define IWL_MVM_RS_RATE_MIN_SUCCESS_TH 8
+#define IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT 5 /* Seconds */
+#define IWL_MVM_RS_IDLE_TIMEOUT 5 /* Seconds */
+#define IWL_MVM_RS_MISSED_RATE_MAX 15
+#define IWL_MVM_RS_LEGACY_FAILURE_LIMIT 160
+#define IWL_MVM_RS_LEGACY_SUCCESS_LIMIT 480
+#define IWL_MVM_RS_LEGACY_TABLE_COUNT 160
+#define IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT 400
+#define IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT 4500
+#define IWL_MVM_RS_NON_LEGACY_TABLE_COUNT 1500
+#define IWL_MVM_RS_SR_FORCE_DECREASE 15 /* percent */
+#define IWL_MVM_RS_SR_NO_DECREASE 85 /* percent */
+#define IWL_MVM_RS_AGG_TIME_LIMIT 4000 /* 4 msecs. valid 100-8000 */
+#define IWL_MVM_RS_AGG_DISABLE_START 3
+#define IWL_MVM_RS_TPC_SR_FORCE_INCREASE 75 /* percent */
+#define IWL_MVM_RS_TPC_SR_NO_INCREASE 85 /* percent */
+#define IWL_MVM_RS_TPC_TX_POWER_STEP 3
#endif /* __MVM_CONSTANTS_H */
diff --git a/drivers/net/wireless/iwlwifi/mvm/d3.c b/drivers/net/wireless/iwlwifi/mvm/d3.c
index 744de262373e..14e8fd661889 100644
--- a/drivers/net/wireless/iwlwifi/mvm/d3.c
+++ b/drivers/net/wireless/iwlwifi/mvm/d3.c
@@ -793,7 +793,7 @@ iwl_mvm_get_wowlan_config(struct iwl_mvm *mvm,
struct ieee80211_sta *ap_sta)
{
int ret;
- struct iwl_mvm_sta *mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+ struct iwl_mvm_sta *mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
/* TODO: wowlan_config_cmd->wowlan_ba_teardown_tids */
@@ -1137,12 +1137,43 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
return ret;
}
+static int iwl_mvm_enter_d0i3_sync(struct iwl_mvm *mvm)
+{
+ struct iwl_notification_wait wait_d3;
+ static const u8 d3_notif[] = { D3_CONFIG_CMD };
+ int ret;
+
+ iwl_init_notification_wait(&mvm->notif_wait, &wait_d3,
+ d3_notif, ARRAY_SIZE(d3_notif),
+ NULL, NULL);
+
+ ret = iwl_mvm_enter_d0i3(mvm->hw->priv);
+ if (ret)
+ goto remove_notif;
+
+ ret = iwl_wait_notification(&mvm->notif_wait, &wait_d3, HZ);
+ WARN_ON_ONCE(ret);
+ return ret;
+
+remove_notif:
+ iwl_remove_notification(&mvm->notif_wait, &wait_d3);
+ return ret;
+}
+
int iwl_mvm_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
iwl_trans_suspend(mvm->trans);
- if (iwl_mvm_is_d0i3_supported(mvm)) {
+ if (wowlan->any) {
+ /* 'any' trigger means d0i3 usage */
+ if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
+ int ret = iwl_mvm_enter_d0i3_sync(mvm);
+
+ if (ret)
+ return ret;
+ }
+
mutex_lock(&mvm->d0i3_suspend_mutex);
__set_bit(D0I3_DEFER_WAKEUP, &mvm->d0i3_suspend_flags);
mutex_unlock(&mvm->d0i3_suspend_mutex);
@@ -1626,7 +1657,7 @@ static bool iwl_mvm_query_wakeup_reasons(struct iwl_mvm *mvm,
if (IS_ERR_OR_NULL(ap_sta))
goto out_free;
- mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
+ mvm_ap_sta = iwl_mvm_sta_from_mac80211(ap_sta);
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
u16 seq = status.qos_seq_ctr[i];
/* firmware stores last-used value, we store next value */
@@ -1876,8 +1907,20 @@ int iwl_mvm_resume(struct ieee80211_hw *hw)
iwl_trans_resume(mvm->trans);
- if (iwl_mvm_is_d0i3_supported(mvm))
+ if (mvm->hw->wiphy->wowlan_config->any) {
+ /* 'any' trigger means d0i3 usage */
+ if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND) {
+ int ret = iwl_mvm_exit_d0i3(hw->priv);
+
+ if (ret)
+ return ret;
+ /*
+ * d0i3 exit will be deferred until reconfig_complete.
+ * make sure there we are out of d0i3.
+ */
+ }
return 0;
+ }
return __iwl_mvm_resume(mvm, false);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
index 9aa2311a776c..5fe14591e1c4 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs-vif.c
@@ -268,7 +268,7 @@ static ssize_t iwl_dbgfs_mac_params_read(struct file *file,
sta = rcu_dereference_protected(mvm->fw_id_to_mac_id[ap_sta_id],
lockdep_is_held(&mvm->mutex));
if (!IS_ERR_OR_NULL(sta)) {
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
pos += scnprintf(buf+pos, bufsz-pos,
"ap_sta_id %d - reduced Tx power %d\n",
@@ -517,6 +517,34 @@ static ssize_t iwl_dbgfs_low_latency_read(struct file *file,
return simple_read_from_buffer(user_buf, count, ppos, buf, sizeof(buf));
}
+static ssize_t iwl_dbgfs_uapsd_misbehaving_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct ieee80211_vif *vif = file->private_data;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ char buf[20];
+ int len;
+
+ len = sprintf(buf, "%pM\n", mvmvif->uapsd_misbehaving_bssid);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t iwl_dbgfs_uapsd_misbehaving_write(struct ieee80211_vif *vif,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+ struct iwl_mvm *mvm = mvmvif->mvm;
+ bool ret;
+
+ mutex_lock(&mvm->mutex);
+ ret = mac_pton(buf, mvmvif->uapsd_misbehaving_bssid);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ? count : -EINVAL;
+}
+
#define MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz) \
_MVM_DEBUGFS_WRITE_FILE_OPS(name, bufsz, struct ieee80211_vif)
#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
@@ -531,6 +559,7 @@ MVM_DEBUGFS_READ_FILE_OPS(mac_params);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(pm_params, 32);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bf_params, 256);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(low_latency, 10);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(uapsd_misbehaving, 20);
void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
@@ -564,6 +593,8 @@ void iwl_mvm_vif_dbgfs_register(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
MVM_DEBUGFS_ADD_FILE_VIF(mac_params, mvmvif->dbgfs_dir, S_IRUSR);
MVM_DEBUGFS_ADD_FILE_VIF(low_latency, mvmvif->dbgfs_dir,
S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE_VIF(uapsd_misbehaving, mvmvif->dbgfs_dir,
+ S_IRUSR | S_IWUSR);
if (vif->type == NL80211_IFTYPE_STATION && !vif->p2p &&
mvmvif == mvm->bf_allowed_vif)
diff --git a/drivers/net/wireless/iwlwifi/mvm/debugfs.c b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
index 33bf915cd7ea..82c09d86af8c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/debugfs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/debugfs.c
@@ -654,10 +654,10 @@ out:
return ret ?: count;
}
-#define PRINT_STATS_LE32(_str, _val) \
+#define PRINT_STATS_LE32(_struct, _memb) \
pos += scnprintf(buf + pos, bufsz - pos, \
- fmt_table, _str, \
- le32_to_cpu(_val))
+ fmt_table, #_memb, \
+ le32_to_cpu(_struct->_memb))
static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
char __user *user_buf, size_t count,
@@ -692,97 +692,89 @@ static ssize_t iwl_dbgfs_fw_rx_stats_read(struct file *file,
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - OFDM");
- PRINT_STATS_LE32("ina_cnt", ofdm->ina_cnt);
- PRINT_STATS_LE32("fina_cnt", ofdm->fina_cnt);
- PRINT_STATS_LE32("plcp_err", ofdm->plcp_err);
- PRINT_STATS_LE32("crc32_err", ofdm->crc32_err);
- PRINT_STATS_LE32("overrun_err", ofdm->overrun_err);
- PRINT_STATS_LE32("early_overrun_err", ofdm->early_overrun_err);
- PRINT_STATS_LE32("crc32_good", ofdm->crc32_good);
- PRINT_STATS_LE32("false_alarm_cnt", ofdm->false_alarm_cnt);
- PRINT_STATS_LE32("fina_sync_err_cnt", ofdm->fina_sync_err_cnt);
- PRINT_STATS_LE32("sfd_timeout", ofdm->sfd_timeout);
- PRINT_STATS_LE32("fina_timeout", ofdm->fina_timeout);
- PRINT_STATS_LE32("unresponded_rts", ofdm->unresponded_rts);
- PRINT_STATS_LE32("rxe_frame_lmt_overrun",
- ofdm->rxe_frame_limit_overrun);
- PRINT_STATS_LE32("sent_ack_cnt", ofdm->sent_ack_cnt);
- PRINT_STATS_LE32("sent_cts_cnt", ofdm->sent_cts_cnt);
- PRINT_STATS_LE32("sent_ba_rsp_cnt", ofdm->sent_ba_rsp_cnt);
- PRINT_STATS_LE32("dsp_self_kill", ofdm->dsp_self_kill);
- PRINT_STATS_LE32("mh_format_err", ofdm->mh_format_err);
- PRINT_STATS_LE32("re_acq_main_rssi_sum", ofdm->re_acq_main_rssi_sum);
- PRINT_STATS_LE32("reserved", ofdm->reserved);
+ PRINT_STATS_LE32(ofdm, ina_cnt);
+ PRINT_STATS_LE32(ofdm, fina_cnt);
+ PRINT_STATS_LE32(ofdm, plcp_err);
+ PRINT_STATS_LE32(ofdm, crc32_err);
+ PRINT_STATS_LE32(ofdm, overrun_err);
+ PRINT_STATS_LE32(ofdm, early_overrun_err);
+ PRINT_STATS_LE32(ofdm, crc32_good);
+ PRINT_STATS_LE32(ofdm, false_alarm_cnt);
+ PRINT_STATS_LE32(ofdm, fina_sync_err_cnt);
+ PRINT_STATS_LE32(ofdm, sfd_timeout);
+ PRINT_STATS_LE32(ofdm, fina_timeout);
+ PRINT_STATS_LE32(ofdm, unresponded_rts);
+ PRINT_STATS_LE32(ofdm, rxe_frame_lmt_overrun);
+ PRINT_STATS_LE32(ofdm, sent_ack_cnt);
+ PRINT_STATS_LE32(ofdm, sent_cts_cnt);
+ PRINT_STATS_LE32(ofdm, sent_ba_rsp_cnt);
+ PRINT_STATS_LE32(ofdm, dsp_self_kill);
+ PRINT_STATS_LE32(ofdm, mh_format_err);
+ PRINT_STATS_LE32(ofdm, re_acq_main_rssi_sum);
+ PRINT_STATS_LE32(ofdm, reserved);
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - CCK");
- PRINT_STATS_LE32("ina_cnt", cck->ina_cnt);
- PRINT_STATS_LE32("fina_cnt", cck->fina_cnt);
- PRINT_STATS_LE32("plcp_err", cck->plcp_err);
- PRINT_STATS_LE32("crc32_err", cck->crc32_err);
- PRINT_STATS_LE32("overrun_err", cck->overrun_err);
- PRINT_STATS_LE32("early_overrun_err", cck->early_overrun_err);
- PRINT_STATS_LE32("crc32_good", cck->crc32_good);
- PRINT_STATS_LE32("false_alarm_cnt", cck->false_alarm_cnt);
- PRINT_STATS_LE32("fina_sync_err_cnt", cck->fina_sync_err_cnt);
- PRINT_STATS_LE32("sfd_timeout", cck->sfd_timeout);
- PRINT_STATS_LE32("fina_timeout", cck->fina_timeout);
- PRINT_STATS_LE32("unresponded_rts", cck->unresponded_rts);
- PRINT_STATS_LE32("rxe_frame_lmt_overrun",
- cck->rxe_frame_limit_overrun);
- PRINT_STATS_LE32("sent_ack_cnt", cck->sent_ack_cnt);
- PRINT_STATS_LE32("sent_cts_cnt", cck->sent_cts_cnt);
- PRINT_STATS_LE32("sent_ba_rsp_cnt", cck->sent_ba_rsp_cnt);
- PRINT_STATS_LE32("dsp_self_kill", cck->dsp_self_kill);
- PRINT_STATS_LE32("mh_format_err", cck->mh_format_err);
- PRINT_STATS_LE32("re_acq_main_rssi_sum", cck->re_acq_main_rssi_sum);
- PRINT_STATS_LE32("reserved", cck->reserved);
+ PRINT_STATS_LE32(cck, ina_cnt);
+ PRINT_STATS_LE32(cck, fina_cnt);
+ PRINT_STATS_LE32(cck, plcp_err);
+ PRINT_STATS_LE32(cck, crc32_err);
+ PRINT_STATS_LE32(cck, overrun_err);
+ PRINT_STATS_LE32(cck, early_overrun_err);
+ PRINT_STATS_LE32(cck, crc32_good);
+ PRINT_STATS_LE32(cck, false_alarm_cnt);
+ PRINT_STATS_LE32(cck, fina_sync_err_cnt);
+ PRINT_STATS_LE32(cck, sfd_timeout);
+ PRINT_STATS_LE32(cck, fina_timeout);
+ PRINT_STATS_LE32(cck, unresponded_rts);
+ PRINT_STATS_LE32(cck, rxe_frame_lmt_overrun);
+ PRINT_STATS_LE32(cck, sent_ack_cnt);
+ PRINT_STATS_LE32(cck, sent_cts_cnt);
+ PRINT_STATS_LE32(cck, sent_ba_rsp_cnt);
+ PRINT_STATS_LE32(cck, dsp_self_kill);
+ PRINT_STATS_LE32(cck, mh_format_err);
+ PRINT_STATS_LE32(cck, re_acq_main_rssi_sum);
+ PRINT_STATS_LE32(cck, reserved);
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - GENERAL");
- PRINT_STATS_LE32("bogus_cts", general->bogus_cts);
- PRINT_STATS_LE32("bogus_ack", general->bogus_ack);
- PRINT_STATS_LE32("non_bssid_frames", general->non_bssid_frames);
- PRINT_STATS_LE32("filtered_frames", general->filtered_frames);
- PRINT_STATS_LE32("non_channel_beacons", general->non_channel_beacons);
- PRINT_STATS_LE32("channel_beacons", general->channel_beacons);
- PRINT_STATS_LE32("num_missed_bcon", general->num_missed_bcon);
- PRINT_STATS_LE32("adc_rx_saturation_time",
- general->adc_rx_saturation_time);
- PRINT_STATS_LE32("ina_detection_search_time",
- general->ina_detection_search_time);
- PRINT_STATS_LE32("beacon_silence_rssi_a",
- general->beacon_silence_rssi_a);
- PRINT_STATS_LE32("beacon_silence_rssi_b",
- general->beacon_silence_rssi_b);
- PRINT_STATS_LE32("beacon_silence_rssi_c",
- general->beacon_silence_rssi_c);
- PRINT_STATS_LE32("interference_data_flag",
- general->interference_data_flag);
- PRINT_STATS_LE32("channel_load", general->channel_load);
- PRINT_STATS_LE32("dsp_false_alarms", general->dsp_false_alarms);
- PRINT_STATS_LE32("beacon_rssi_a", general->beacon_rssi_a);
- PRINT_STATS_LE32("beacon_rssi_b", general->beacon_rssi_b);
- PRINT_STATS_LE32("beacon_rssi_c", general->beacon_rssi_c);
- PRINT_STATS_LE32("beacon_energy_a", general->beacon_energy_a);
- PRINT_STATS_LE32("beacon_energy_b", general->beacon_energy_b);
- PRINT_STATS_LE32("beacon_energy_c", general->beacon_energy_c);
- PRINT_STATS_LE32("num_bt_kills", general->num_bt_kills);
- PRINT_STATS_LE32("mac_id", general->mac_id);
- PRINT_STATS_LE32("directed_data_mpdu", general->directed_data_mpdu);
+ PRINT_STATS_LE32(general, bogus_cts);
+ PRINT_STATS_LE32(general, bogus_ack);
+ PRINT_STATS_LE32(general, non_bssid_frames);
+ PRINT_STATS_LE32(general, filtered_frames);
+ PRINT_STATS_LE32(general, non_channel_beacons);
+ PRINT_STATS_LE32(general, channel_beacons);
+ PRINT_STATS_LE32(general, num_missed_bcon);
+ PRINT_STATS_LE32(general, adc_rx_saturation_time);
+ PRINT_STATS_LE32(general, ina_detection_search_time);
+ PRINT_STATS_LE32(general, beacon_silence_rssi_a);
+ PRINT_STATS_LE32(general, beacon_silence_rssi_b);
+ PRINT_STATS_LE32(general, beacon_silence_rssi_c);
+ PRINT_STATS_LE32(general, interference_data_flag);
+ PRINT_STATS_LE32(general, channel_load);
+ PRINT_STATS_LE32(general, dsp_false_alarms);
+ PRINT_STATS_LE32(general, beacon_rssi_a);
+ PRINT_STATS_LE32(general, beacon_rssi_b);
+ PRINT_STATS_LE32(general, beacon_rssi_c);
+ PRINT_STATS_LE32(general, beacon_energy_a);
+ PRINT_STATS_LE32(general, beacon_energy_b);
+ PRINT_STATS_LE32(general, beacon_energy_c);
+ PRINT_STATS_LE32(general, num_bt_kills);
+ PRINT_STATS_LE32(general, mac_id);
+ PRINT_STATS_LE32(general, directed_data_mpdu);
pos += scnprintf(buf + pos, bufsz - pos, fmt_header,
"Statistics_Rx - HT");
- PRINT_STATS_LE32("plcp_err", ht->plcp_err);
- PRINT_STATS_LE32("overrun_err", ht->overrun_err);
- PRINT_STATS_LE32("early_overrun_err", ht->early_overrun_err);
- PRINT_STATS_LE32("crc32_good", ht->crc32_good);
- PRINT_STATS_LE32("crc32_err", ht->crc32_err);
- PRINT_STATS_LE32("mh_format_err", ht->mh_format_err);
- PRINT_STATS_LE32("agg_crc32_good", ht->agg_crc32_good);
- PRINT_STATS_LE32("agg_mpdu_cnt", ht->agg_mpdu_cnt);
- PRINT_STATS_LE32("agg_cnt", ht->agg_cnt);
- PRINT_STATS_LE32("unsupport_mcs", ht->unsupport_mcs);
+ PRINT_STATS_LE32(ht, plcp_err);
+ PRINT_STATS_LE32(ht, overrun_err);
+ PRINT_STATS_LE32(ht, early_overrun_err);
+ PRINT_STATS_LE32(ht, crc32_good);
+ PRINT_STATS_LE32(ht, crc32_err);
+ PRINT_STATS_LE32(ht, mh_format_err);
+ PRINT_STATS_LE32(ht, agg_crc32_good);
+ PRINT_STATS_LE32(ht, agg_mpdu_cnt);
+ PRINT_STATS_LE32(ht, agg_cnt);
+ PRINT_STATS_LE32(ht, unsupport_mcs);
mutex_unlock(&mvm->mutex);
@@ -933,7 +925,7 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
return -EINVAL;
if (scan_rx_ant > ANT_ABC)
return -EINVAL;
- if (scan_rx_ant & ~mvm->fw->valid_rx_ant)
+ if (scan_rx_ant & ~(iwl_mvm_get_valid_rx_ant(mvm)))
return -EINVAL;
if (mvm->scan_rx_ant != scan_rx_ant) {
@@ -945,6 +937,61 @@ iwl_dbgfs_scan_ant_rxchain_write(struct iwl_mvm *mvm, char *buf,
return count;
}
+static ssize_t iwl_dbgfs_fw_dbg_conf_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = file->private_data;
+ enum iwl_fw_dbg_conf conf;
+ char buf[8];
+ const size_t bufsz = sizeof(buf);
+ int pos = 0;
+
+ mutex_lock(&mvm->mutex);
+ conf = mvm->fw_dbg_conf;
+ mutex_unlock(&mvm->mutex);
+
+ pos += scnprintf(buf + pos, bufsz - pos, "%d\n", conf);
+
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_fw_dbg_conf_write(struct iwl_mvm *mvm,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ int ret, conf_id;
+
+ ret = kstrtoint(buf, 0, &conf_id);
+ if (ret)
+ return ret;
+
+ if (WARN_ON(conf_id >= FW_DBG_MAX))
+ return -EINVAL;
+
+ mutex_lock(&mvm->mutex);
+ ret = iwl_mvm_start_fw_dbg_conf(mvm, conf_id);
+ mutex_unlock(&mvm->mutex);
+
+ return ret ?: count;
+}
+
+static ssize_t iwl_dbgfs_fw_dbg_collect_write(struct iwl_mvm *mvm,
+ char *buf, size_t count,
+ loff_t *ppos)
+{
+ int ret = iwl_mvm_ref_sync(mvm, IWL_MVM_REF_PRPH_WRITE);
+
+ if (ret)
+ return ret;
+
+ iwl_mvm_fw_dbg_collect(mvm);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_PRPH_WRITE);
+
+ return count;
+}
+
#define ADD_TEXT(...) pos += scnprintf(buf + pos, bufsz - pos, __VA_ARGS__)
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
static ssize_t iwl_dbgfs_bcast_filters_read(struct file *file,
@@ -1340,6 +1387,7 @@ static ssize_t iwl_dbgfs_d0i3_refs_read(struct file *file,
PRINT_MVM_REF(IWL_MVM_REF_TM_CMD);
PRINT_MVM_REF(IWL_MVM_REF_EXIT_WORK);
PRINT_MVM_REF(IWL_MVM_REF_PROTECT_CSA);
+ PRINT_MVM_REF(IWL_MVM_REF_FW_DBG_COLLECT);
return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
}
@@ -1439,6 +1487,26 @@ out:
return count;
}
+static ssize_t iwl_dbgfs_enable_scan_iteration_notif_write(struct iwl_mvm *mvm,
+ char *buf,
+ size_t count,
+ loff_t *ppos)
+{
+ int val;
+
+ mutex_lock(&mvm->mutex);
+
+ if (kstrtoint(buf, 10, &val)) {
+ mutex_unlock(&mvm->mutex);
+ return -EINVAL;
+ }
+
+ mvm->scan_iter_notif_enabled = val;
+ mutex_unlock(&mvm->mutex);
+
+ return count;
+}
+
MVM_DEBUGFS_READ_WRITE_FILE_OPS(prph_reg, 64);
/* Device wide debugfs entries */
@@ -1459,6 +1527,9 @@ MVM_DEBUGFS_WRITE_FILE_OPS(bt_tx_prio, 10);
MVM_DEBUGFS_WRITE_FILE_OPS(bt_force_ant, 10);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(scan_ant_rxchain, 8);
MVM_DEBUGFS_READ_WRITE_FILE_OPS(d0i3_refs, 8);
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(fw_dbg_conf, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(fw_dbg_collect, 8);
+MVM_DEBUGFS_WRITE_FILE_OPS(enable_scan_iteration_notif, 8);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
MVM_DEBUGFS_READ_WRITE_FILE_OPS(bcast_filters, 256);
@@ -1500,6 +1571,10 @@ int iwl_mvm_dbgfs_register(struct iwl_mvm *mvm, struct dentry *dbgfs_dir)
S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(prph_reg, mvm->debugfs_dir, S_IWUSR | S_IRUSR);
MVM_DEBUGFS_ADD_FILE(d0i3_refs, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(fw_dbg_conf, mvm->debugfs_dir, S_IRUSR | S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(fw_dbg_collect, mvm->debugfs_dir, S_IWUSR);
+ MVM_DEBUGFS_ADD_FILE(enable_scan_iteration_notif, mvm->debugfs_dir,
+ S_IWUSR);
#ifdef CONFIG_IWLWIFI_BCAST_FILTERING
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_BCAST_FILTERING) {
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
index 430020047b77..4fc0938b3fb6 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-power.h
@@ -92,14 +92,32 @@ enum iwl_ltr_config_flags {
};
/**
+ * struct iwl_ltr_config_cmd_v1 - configures the LTR
+ * @flags: See %enum iwl_ltr_config_flags
+ */
+struct iwl_ltr_config_cmd_v1 {
+ __le32 flags;
+ __le32 static_long;
+ __le32 static_short;
+} __packed; /* LTR_CAPABLE_API_S_VER_1 */
+
+#define LTR_VALID_STATES_NUM 4
+
+/**
* struct iwl_ltr_config_cmd - configures the LTR
* @flags: See %enum iwl_ltr_config_flags
+ * @static_long:
+ * @static_short:
+ * @ltr_cfg_values:
+ * @ltr_short_idle_timeout:
*/
struct iwl_ltr_config_cmd {
__le32 flags;
__le32 static_long;
__le32 static_short;
-} __packed;
+ __le32 ltr_cfg_values[LTR_VALID_STATES_NUM];
+ __le32 ltr_short_idle_timeout;
+} __packed; /* LTR_CAPABLE_API_S_VER_2 */
/* Radio LP RX Energy Threshold measured in dBm */
#define POWER_LPRX_RSSI_THRESHOLD 75
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
index 8bb5b94bf963..0f1ea80a55ef 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-rs.h
@@ -308,6 +308,42 @@ enum {
#define LQ_FLAG_DYNAMIC_BW_POS 6
#define LQ_FLAG_DYNAMIC_BW_MSK (1 << LQ_FLAG_DYNAMIC_BW_POS)
+/* Single Stream Tx Parameters (lq_cmd->ss_params)
+ * Flags to control a smart FW decision about whether BFER/STBC/SISO will be
+ * used for single stream Tx.
+ */
+
+/* Bit 0-1: Max STBC streams allowed. Can be 0-3.
+ * (0) - No STBC allowed
+ * (1) - 2x1 STBC allowed (HT/VHT)
+ * (2) - 4x2 STBC allowed (HT/VHT)
+ * (3) - 3x2 STBC allowed (HT only)
+ * All our chips are at most 2 antennas so only (1) is valid for now.
+ */
+#define LQ_SS_STBC_ALLOWED_POS 0
+#define LQ_SS_STBC_ALLOWED_MSK (3 << LQ_SS_STBC_ALLOWED_MSK)
+
+/* 2x1 STBC is allowed */
+#define LQ_SS_STBC_1SS_ALLOWED (1 << LQ_SS_STBC_ALLOWED_POS)
+
+/* Bit 2: Beamformer (VHT only) is allowed */
+#define LQ_SS_BFER_ALLOWED_POS 2
+#define LQ_SS_BFER_ALLOWED (1 << LQ_SS_BFER_ALLOWED_POS)
+
+/* Bit 3: Force BFER or STBC for testing
+ * If this is set:
+ * If BFER is allowed then force the ucode to choose BFER else
+ * If STBC is allowed then force the ucode to choose STBC over SISO
+ */
+#define LQ_SS_FORCE_POS 3
+#define LQ_SS_FORCE (1 << LQ_SS_FORCE_POS)
+
+/* Bit 31: ss_params field is valid. Used for FW backward compatibility
+ * with other drivers which don't support the ss_params API yet
+ */
+#define LQ_SS_PARAMS_VALID_POS 31
+#define LQ_SS_PARAMS_VALID (1 << LQ_SS_PARAMS_VALID_POS)
+
/**
* struct iwl_lq_cmd - link quality command
* @sta_id: station to update
@@ -330,7 +366,7 @@ enum {
* 2 - 0x3f: maximal number of frames (up to 3f == 63)
* @rs_table: array of rates for each TX try, each is rate_n_flags,
* meaning it is a combination of RATE_MCS_* and IWL_RATE_*_PLCP
- * @bf_params: beam forming params, currently not used
+ * @ss_params: single stream features. declare whether STBC or BFER are allowed.
*/
struct iwl_lq_cmd {
u8 sta_id;
@@ -348,6 +384,6 @@ struct iwl_lq_cmd {
u8 agg_frame_cnt_limit;
__le32 reserved2;
__le32 rs_table[LQ_MAX_RETRY_NUM];
- __le32 bf_params;
+ __le32 ss_params;
}; /* LINK_QUALITY_CMD_API_S_VER_1 */
#endif /* __fw_api_rs_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
new file mode 100644
index 000000000000..928168b18346
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-stats.h
@@ -0,0 +1,277 @@
+/******************************************************************************
+ *
+ * This file is provided under a dual BSD/GPLv2 license. When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * 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,
+ * USA
+ *
+ * The full GNU General Public License is included in this distribution
+ * in the file called COPYING.
+ *
+ * Contact Information:
+ * Intel Linux Wireless <ilw@linux.intel.com>
+ * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2012 - 2014 Intel Corporation. All rights reserved.
+ * Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * 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 Intel Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *****************************************************************************/
+
+#ifndef __fw_api_stats_h__
+#define __fw_api_stats_h__
+
+struct mvm_statistics_dbg {
+ __le32 burst_check;
+ __le32 burst_count;
+ __le32 wait_for_silence_timeout_cnt;
+ __le32 reserved[3];
+} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */
+
+struct mvm_statistics_div {
+ __le32 tx_on_a;
+ __le32 tx_on_b;
+ __le32 exec_time;
+ __le32 probe_time;
+ __le32 rssi_ant;
+ __le32 reserved2;
+} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */
+
+struct mvm_statistics_rx_non_phy {
+ __le32 bogus_cts; /* CTS received when not expecting CTS */
+ __le32 bogus_ack; /* ACK received when not expecting ACK */
+ __le32 non_bssid_frames; /* number of frames with BSSID that
+ * doesn't belong to the STA BSSID */
+ __le32 filtered_frames; /* count frames that were dumped in the
+ * filtering process */
+ __le32 non_channel_beacons; /* beacons with our bss id but not on
+ * our serving channel */
+ __le32 channel_beacons; /* beacons with our bss id and in our
+ * serving channel */
+ __le32 num_missed_bcon; /* number of missed beacons */
+ __le32 adc_rx_saturation_time; /* count in 0.8us units the time the
+ * ADC was in saturation */
+ __le32 ina_detection_search_time;/* total time (in 0.8us) searched
+ * for INA */
+ __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
+ __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
+ __le32 interference_data_flag; /* flag for interference data
+ * availability. 1 when data is
+ * available. */
+ __le32 channel_load; /* counts RX Enable time in uSec */
+ __le32 dsp_false_alarms; /* DSP false alarm (both OFDM
+ * and CCK) counter */
+ __le32 beacon_rssi_a;
+ __le32 beacon_rssi_b;
+ __le32 beacon_rssi_c;
+ __le32 beacon_energy_a;
+ __le32 beacon_energy_b;
+ __le32 beacon_energy_c;
+ __le32 num_bt_kills;
+ __le32 mac_id;
+ __le32 directed_data_mpdu;
+} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */
+
+struct mvm_statistics_rx_phy {
+ __le32 ina_cnt;
+ __le32 fina_cnt;
+ __le32 plcp_err;
+ __le32 crc32_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 false_alarm_cnt;
+ __le32 fina_sync_err_cnt;
+ __le32 sfd_timeout;
+ __le32 fina_timeout;
+ __le32 unresponded_rts;
+ __le32 rxe_frame_lmt_overrun;
+ __le32 sent_ack_cnt;
+ __le32 sent_cts_cnt;
+ __le32 sent_ba_rsp_cnt;
+ __le32 dsp_self_kill;
+ __le32 mh_format_err;
+ __le32 re_acq_main_rssi_sum;
+ __le32 reserved;
+} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */
+
+struct mvm_statistics_rx_ht_phy {
+ __le32 plcp_err;
+ __le32 overrun_err;
+ __le32 early_overrun_err;
+ __le32 crc32_good;
+ __le32 crc32_err;
+ __le32 mh_format_err;
+ __le32 agg_crc32_good;
+ __le32 agg_mpdu_cnt;
+ __le32 agg_cnt;
+ __le32 unsupport_mcs;
+} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */
+
+struct mvm_statistics_tx_non_phy {
+ __le32 preamble_cnt;
+ __le32 rx_detected_cnt;
+ __le32 bt_prio_defer_cnt;
+ __le32 bt_prio_kill_cnt;
+ __le32 few_bytes_cnt;
+ __le32 cts_timeout;
+ __le32 ack_timeout;
+ __le32 expected_ack_cnt;
+ __le32 actual_ack_cnt;
+ __le32 dump_msdu_cnt;
+ __le32 burst_abort_next_frame_mismatch_cnt;
+ __le32 burst_abort_missing_next_frame_cnt;
+ __le32 cts_timeout_collision;
+ __le32 ack_or_ba_timeout_collision;
+} __packed; /* STATISTICS_TX_NON_PHY_API_S_VER_3 */
+
+#define MAX_CHAINS 3
+
+struct mvm_statistics_tx_non_phy_agg {
+ __le32 ba_timeout;
+ __le32 ba_reschedule_frames;
+ __le32 scd_query_agg_frame_cnt;
+ __le32 scd_query_no_agg;
+ __le32 scd_query_agg;
+ __le32 scd_query_mismatch;
+ __le32 frame_not_ready;
+ __le32 underrun;
+ __le32 bt_prio_kill;
+ __le32 rx_ba_rsp_cnt;
+ __s8 txpower[MAX_CHAINS];
+ __s8 reserved;
+ __le32 reserved2;
+} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */
+
+struct mvm_statistics_tx_channel_width {
+ __le32 ext_cca_narrow_ch20[1];
+ __le32 ext_cca_narrow_ch40[2];
+ __le32 ext_cca_narrow_ch80[3];
+ __le32 ext_cca_narrow_ch160[4];
+ __le32 last_tx_ch_width_indx;
+ __le32 rx_detected_per_ch_width[4];
+ __le32 success_per_ch_width[4];
+ __le32 fail_per_ch_width[4];
+}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */
+
+struct mvm_statistics_tx {
+ struct mvm_statistics_tx_non_phy general;
+ struct mvm_statistics_tx_non_phy_agg agg;
+ struct mvm_statistics_tx_channel_width channel_width;
+} __packed; /* STATISTICS_TX_API_S_VER_4 */
+
+
+struct mvm_statistics_bt_activity {
+ __le32 hi_priority_tx_req_cnt;
+ __le32 hi_priority_tx_denied_cnt;
+ __le32 lo_priority_tx_req_cnt;
+ __le32 lo_priority_tx_denied_cnt;
+ __le32 hi_priority_rx_req_cnt;
+ __le32 hi_priority_rx_denied_cnt;
+ __le32 lo_priority_rx_req_cnt;
+ __le32 lo_priority_rx_denied_cnt;
+} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */
+
+struct mvm_statistics_general {
+ __le32 radio_temperature;
+ __le32 radio_voltage;
+ struct mvm_statistics_dbg dbg;
+ __le32 sleep_time;
+ __le32 slots_out;
+ __le32 slots_idle;
+ __le32 ttl_timestamp;
+ struct mvm_statistics_div slow_div;
+ __le32 rx_enable_counter;
+ /*
+ * num_of_sos_states:
+ * count the number of times we have to re-tune
+ * in order to get out of bad PHY status
+ */
+ __le32 num_of_sos_states;
+ __le32 beacon_filtered;
+ __le32 missed_beacons;
+ __s8 beacon_filter_average_energy;
+ __s8 beacon_filter_reason;
+ __s8 beacon_filter_current_energy;
+ __s8 beacon_filter_reserved;
+ __le32 beacon_filter_delta_time;
+ struct mvm_statistics_bt_activity bt_activity;
+} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
+
+struct mvm_statistics_rx {
+ struct mvm_statistics_rx_phy ofdm;
+ struct mvm_statistics_rx_phy cck;
+ struct mvm_statistics_rx_non_phy general;
+ struct mvm_statistics_rx_ht_phy ofdm_ht;
+} __packed; /* STATISTICS_RX_API_S_VER_3 */
+
+/*
+ * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
+ *
+ * By default, uCode issues this notification after receiving a beacon
+ * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
+ * REPLY_STATISTICS_CMD 0x9c, above.
+ *
+ * Statistics counters continue to increment beacon after beacon, but are
+ * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
+ * 0x9c with CLEAR_STATS bit set (see above).
+ *
+ * uCode also issues this notification during scans. uCode clears statistics
+ * appropriately so that each notification contains statistics for only the
+ * one channel that has just been scanned.
+ */
+
+struct iwl_notif_statistics {
+ __le32 flag;
+ struct mvm_statistics_rx rx;
+ struct mvm_statistics_tx tx;
+ struct mvm_statistics_general general;
+} __packed; /* STATISTICS_NTFY_API_S_VER_8 */
+
+#endif /* __fw_api_stats_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
index 5bca1f8bfebf..81c4ea3c6958 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api-tx.h
@@ -592,4 +592,43 @@ static inline u32 iwl_mvm_get_scd_ssn(struct iwl_mvm_tx_resp *tx_resp)
tx_resp->frame_count) & 0xfff;
}
+/**
+ * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
+ * @token:
+ * @sta_id: station id
+ * @tid:
+ * @scd_queue: scheduler queue to confiug
+ * @enable: 1 queue enable, 0 queue disable
+ * @aggregate: 1 aggregated queue, 0 otherwise
+ * @tx_fifo: %enum iwl_mvm_tx_fifo
+ * @window: BA window size
+ * @ssn: SSN for the BA agreement
+ */
+struct iwl_scd_txq_cfg_cmd {
+ u8 token;
+ u8 sta_id;
+ u8 tid;
+ u8 scd_queue;
+ u8 enable;
+ u8 aggregate;
+ u8 tx_fifo;
+ u8 window;
+ __le16 ssn;
+ __le16 reserved;
+} __packed; /* SCD_QUEUE_CFG_CMD_API_S_VER_1 */
+
+/**
+ * struct iwl_scd_txq_cfg_rsp
+ * @token: taken from the command
+ * @sta_id: station id from the command
+ * @tid: tid from the command
+ * @scd_queue: scd_queue from the command
+ */
+struct iwl_scd_txq_cfg_rsp {
+ u8 token;
+ u8 sta_id;
+ u8 tid;
+ u8 scd_queue;
+} __packed; /* SCD_QUEUE_CFG_RSP_API_S_VER_1 */
+
#endif /* __fw_api_tx_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw-api.h b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
index 88af6dd2ceaa..b56154fe8ec5 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw-api.h
+++ b/drivers/net/wireless/iwlwifi/mvm/fw-api.h
@@ -74,6 +74,7 @@
#include "fw-api-d3.h"
#include "fw-api-coex.h"
#include "fw-api-scan.h"
+#include "fw-api-stats.h"
/* Tx queue numbers */
enum {
@@ -128,6 +129,9 @@ enum {
/* global key */
WEP_KEY = 0x20,
+ /* Memory */
+ SHARED_MEM_CFG = 0x25,
+
/* TDLS */
TDLS_CHANNEL_SWITCH_CMD = 0x27,
TDLS_CHANNEL_SWITCH_NOTIFICATION = 0xaa,
@@ -1381,214 +1385,6 @@ struct iwl_mvm_marker {
__le32 metadata[0];
} __packed; /* MARKER_API_S_VER_1 */
-struct mvm_statistics_dbg {
- __le32 burst_check;
- __le32 burst_count;
- __le32 wait_for_silence_timeout_cnt;
- __le32 reserved[3];
-} __packed; /* STATISTICS_DEBUG_API_S_VER_2 */
-
-struct mvm_statistics_div {
- __le32 tx_on_a;
- __le32 tx_on_b;
- __le32 exec_time;
- __le32 probe_time;
- __le32 rssi_ant;
- __le32 reserved2;
-} __packed; /* STATISTICS_SLOW_DIV_API_S_VER_2 */
-
-struct mvm_statistics_general_common {
- __le32 temperature; /* radio temperature */
- __le32 temperature_m; /* radio voltage */
- struct mvm_statistics_dbg dbg;
- __le32 sleep_time;
- __le32 slots_out;
- __le32 slots_idle;
- __le32 ttl_timestamp;
- struct mvm_statistics_div div;
- __le32 rx_enable_counter;
- /*
- * num_of_sos_states:
- * count the number of times we have to re-tune
- * in order to get out of bad PHY status
- */
- __le32 num_of_sos_states;
-} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
-
-struct mvm_statistics_rx_non_phy {
- __le32 bogus_cts; /* CTS received when not expecting CTS */
- __le32 bogus_ack; /* ACK received when not expecting ACK */
- __le32 non_bssid_frames; /* number of frames with BSSID that
- * doesn't belong to the STA BSSID */
- __le32 filtered_frames; /* count frames that were dumped in the
- * filtering process */
- __le32 non_channel_beacons; /* beacons with our bss id but not on
- * our serving channel */
- __le32 channel_beacons; /* beacons with our bss id and in our
- * serving channel */
- __le32 num_missed_bcon; /* number of missed beacons */
- __le32 adc_rx_saturation_time; /* count in 0.8us units the time the
- * ADC was in saturation */
- __le32 ina_detection_search_time;/* total time (in 0.8us) searched
- * for INA */
- __le32 beacon_silence_rssi_a; /* RSSI silence after beacon frame */
- __le32 beacon_silence_rssi_b; /* RSSI silence after beacon frame */
- __le32 beacon_silence_rssi_c; /* RSSI silence after beacon frame */
- __le32 interference_data_flag; /* flag for interference data
- * availability. 1 when data is
- * available. */
- __le32 channel_load; /* counts RX Enable time in uSec */
- __le32 dsp_false_alarms; /* DSP false alarm (both OFDM
- * and CCK) counter */
- __le32 beacon_rssi_a;
- __le32 beacon_rssi_b;
- __le32 beacon_rssi_c;
- __le32 beacon_energy_a;
- __le32 beacon_energy_b;
- __le32 beacon_energy_c;
- __le32 num_bt_kills;
- __le32 mac_id;
- __le32 directed_data_mpdu;
-} __packed; /* STATISTICS_RX_NON_PHY_API_S_VER_3 */
-
-struct mvm_statistics_rx_phy {
- __le32 ina_cnt;
- __le32 fina_cnt;
- __le32 plcp_err;
- __le32 crc32_err;
- __le32 overrun_err;
- __le32 early_overrun_err;
- __le32 crc32_good;
- __le32 false_alarm_cnt;
- __le32 fina_sync_err_cnt;
- __le32 sfd_timeout;
- __le32 fina_timeout;
- __le32 unresponded_rts;
- __le32 rxe_frame_limit_overrun;
- __le32 sent_ack_cnt;
- __le32 sent_cts_cnt;
- __le32 sent_ba_rsp_cnt;
- __le32 dsp_self_kill;
- __le32 mh_format_err;
- __le32 re_acq_main_rssi_sum;
- __le32 reserved;
-} __packed; /* STATISTICS_RX_PHY_API_S_VER_2 */
-
-struct mvm_statistics_rx_ht_phy {
- __le32 plcp_err;
- __le32 overrun_err;
- __le32 early_overrun_err;
- __le32 crc32_good;
- __le32 crc32_err;
- __le32 mh_format_err;
- __le32 agg_crc32_good;
- __le32 agg_mpdu_cnt;
- __le32 agg_cnt;
- __le32 unsupport_mcs;
-} __packed; /* STATISTICS_HT_RX_PHY_API_S_VER_1 */
-
-#define MAX_CHAINS 3
-
-struct mvm_statistics_tx_non_phy_agg {
- __le32 ba_timeout;
- __le32 ba_reschedule_frames;
- __le32 scd_query_agg_frame_cnt;
- __le32 scd_query_no_agg;
- __le32 scd_query_agg;
- __le32 scd_query_mismatch;
- __le32 frame_not_ready;
- __le32 underrun;
- __le32 bt_prio_kill;
- __le32 rx_ba_rsp_cnt;
- __s8 txpower[MAX_CHAINS];
- __s8 reserved;
- __le32 reserved2;
-} __packed; /* STATISTICS_TX_NON_PHY_AGG_API_S_VER_1 */
-
-struct mvm_statistics_tx_channel_width {
- __le32 ext_cca_narrow_ch20[1];
- __le32 ext_cca_narrow_ch40[2];
- __le32 ext_cca_narrow_ch80[3];
- __le32 ext_cca_narrow_ch160[4];
- __le32 last_tx_ch_width_indx;
- __le32 rx_detected_per_ch_width[4];
- __le32 success_per_ch_width[4];
- __le32 fail_per_ch_width[4];
-}; /* STATISTICS_TX_CHANNEL_WIDTH_API_S_VER_1 */
-
-struct mvm_statistics_tx {
- __le32 preamble_cnt;
- __le32 rx_detected_cnt;
- __le32 bt_prio_defer_cnt;
- __le32 bt_prio_kill_cnt;
- __le32 few_bytes_cnt;
- __le32 cts_timeout;
- __le32 ack_timeout;
- __le32 expected_ack_cnt;
- __le32 actual_ack_cnt;
- __le32 dump_msdu_cnt;
- __le32 burst_abort_next_frame_mismatch_cnt;
- __le32 burst_abort_missing_next_frame_cnt;
- __le32 cts_timeout_collision;
- __le32 ack_or_ba_timeout_collision;
- struct mvm_statistics_tx_non_phy_agg agg;
- struct mvm_statistics_tx_channel_width channel_width;
-} __packed; /* STATISTICS_TX_API_S_VER_4 */
-
-
-struct mvm_statistics_bt_activity {
- __le32 hi_priority_tx_req_cnt;
- __le32 hi_priority_tx_denied_cnt;
- __le32 lo_priority_tx_req_cnt;
- __le32 lo_priority_tx_denied_cnt;
- __le32 hi_priority_rx_req_cnt;
- __le32 hi_priority_rx_denied_cnt;
- __le32 lo_priority_rx_req_cnt;
- __le32 lo_priority_rx_denied_cnt;
-} __packed; /* STATISTICS_BT_ACTIVITY_API_S_VER_1 */
-
-struct mvm_statistics_general {
- struct mvm_statistics_general_common common;
- __le32 beacon_filtered;
- __le32 missed_beacons;
- __s8 beacon_filter_average_energy;
- __s8 beacon_filter_reason;
- __s8 beacon_filter_current_energy;
- __s8 beacon_filter_reserved;
- __le32 beacon_filter_delta_time;
- struct mvm_statistics_bt_activity bt_activity;
-} __packed; /* STATISTICS_GENERAL_API_S_VER_5 */
-
-struct mvm_statistics_rx {
- struct mvm_statistics_rx_phy ofdm;
- struct mvm_statistics_rx_phy cck;
- struct mvm_statistics_rx_non_phy general;
- struct mvm_statistics_rx_ht_phy ofdm_ht;
-} __packed; /* STATISTICS_RX_API_S_VER_3 */
-
-/*
- * STATISTICS_NOTIFICATION = 0x9d (notification only, not a command)
- *
- * By default, uCode issues this notification after receiving a beacon
- * while associated. To disable this behavior, set DISABLE_NOTIF flag in the
- * REPLY_STATISTICS_CMD 0x9c, above.
- *
- * Statistics counters continue to increment beacon after beacon, but are
- * cleared when changing channels or when driver issues REPLY_STATISTICS_CMD
- * 0x9c with CLEAR_STATS bit set (see above).
- *
- * uCode also issues this notification during scans. uCode clears statistics
- * appropriately so that each notification contains statistics for only the
- * one channel that has just been scanned.
- */
-
-struct iwl_notif_statistics { /* STATISTICS_NTFY_API_S_VER_8 */
- __le32 flag;
- struct mvm_statistics_rx rx;
- struct mvm_statistics_tx tx;
- struct mvm_statistics_general general;
-} __packed;
-
/***********************************
* Smart Fifo API
***********************************/
@@ -1680,63 +1476,6 @@ struct iwl_dts_measurement_notif {
__le32 voltage;
} __packed; /* TEMPERATURE_MEASUREMENT_TRIGGER_NTFY_S */
-/**
- * enum iwl_scd_control - scheduler config command control flags
- * @IWL_SCD_CONTROL_RM_TID: remove TID from this queue
- * @IWL_SCD_CONTROL_SET_SSN: use the SSN and program it into HW
- */
-enum iwl_scd_control {
- IWL_SCD_CONTROL_RM_TID = BIT(4),
- IWL_SCD_CONTROL_SET_SSN = BIT(5),
-};
-
-/**
- * enum iwl_scd_flags - scheduler config command flags
- * @IWL_SCD_FLAGS_SHARE_TID: multiple TIDs map to this queue
- * @IWL_SCD_FLAGS_SHARE_RA: multiple RAs map to this queue
- * @IWL_SCD_FLAGS_DQA_ENABLED: DQA is enabled
- */
-enum iwl_scd_flags {
- IWL_SCD_FLAGS_SHARE_TID = BIT(0),
- IWL_SCD_FLAGS_SHARE_RA = BIT(1),
- IWL_SCD_FLAGS_DQA_ENABLED = BIT(2),
-};
-
-#define IWL_SCDQ_INVALID_STA 0xff
-
-/**
- * struct iwl_scd_txq_cfg_cmd - New txq hw scheduler config command
- * @token: dialog token addba - unused legacy
- * @sta_id: station id 4-bit
- * @tid: TID 0..7
- * @scd_queue: TFD queue num 0 .. 31
- * @enable: 1 queue enable, 0 queue disable
- * @aggregate: 1 aggregated queue, 0 otherwise
- * @tx_fifo: tx fifo num 0..7
- * @window: up to 64
- * @ssn: starting seq num 12-bit
- * @control: command control flags
- * @flags: flags - see &enum iwl_scd_flags
- *
- * Note that every time the command is sent, all parameters must
- * be filled with the exception of
- * - the SSN, which is only used with @IWL_SCD_CONTROL_SET_SSN
- * - the window, which is only relevant when starting aggregation
- */
-struct iwl_scd_txq_cfg_cmd {
- u8 token;
- u8 sta_id;
- u8 tid;
- u8 scd_queue;
- u8 enable;
- u8 aggregate;
- u8 tx_fifo;
- u8 window;
- __le16 ssn;
- u8 control;
- u8 flags;
-} __packed;
-
/***********************************
* TDLS API
***********************************/
@@ -1878,4 +1617,36 @@ struct iwl_tdls_config_res {
struct iwl_tdls_config_sta_info_res sta_info[IWL_MVM_TDLS_STA_COUNT];
} __packed; /* TDLS_CONFIG_RSP_API_S_VER_1 */
+#define TX_FIFO_MAX_NUM 8
+#define RX_FIFO_MAX_NUM 2
+
+/**
+ * Shared memory configuration information from the FW
+ *
+ * @shared_mem_addr: shared memory addr (pre 8000 HW set to 0x0 as MARBH is not
+ * accessible)
+ * @shared_mem_size: shared memory size
+ * @sample_buff_addr: internal sample (mon/adc) buff addr (pre 8000 HW set to
+ * 0x0 as accessible only via DBGM RDAT)
+ * @sample_buff_size: internal sample buff size
+ * @txfifo_addr: start addr of TXF0 (excluding the context table 0.5KB), (pre
+ * 8000 HW set to 0x0 as not accessible)
+ * @txfifo_size: size of TXF0 ... TXF7
+ * @rxfifo_size: RXF1, RXF2 sizes. If there is no RXF2, it'll have a value of 0
+ * @page_buff_addr: used by UMAC and performance debug (page miss analysis),
+ * when paging is not supported this should be 0
+ * @page_buff_size: size of %page_buff_addr
+ */
+struct iwl_shared_mem_cfg {
+ __le32 shared_mem_addr;
+ __le32 shared_mem_size;
+ __le32 sample_buff_addr;
+ __le32 sample_buff_size;
+ __le32 txfifo_addr;
+ __le32 txfifo_size[TX_FIFO_MAX_NUM];
+ __le32 rxfifo_size[RX_FIFO_MAX_NUM];
+ __le32 page_buff_addr;
+ __le32 page_buff_size;
+} __packed; /* SHARED_MEM_ALLOC_API_S_VER_1 */
+
#endif /* __fw_api_h__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/fw.c b/drivers/net/wireless/iwlwifi/mvm/fw.c
index d0fa6e9ed590..ca38e9817374 100644
--- a/drivers/net/wireless/iwlwifi/mvm/fw.c
+++ b/drivers/net/wireless/iwlwifi/mvm/fw.c
@@ -70,6 +70,7 @@
#include "iwl-debug.h"
#include "iwl-csr.h" /* for iwl_mvm_rx_card_state_notif */
#include "iwl-io.h" /* for iwl_mvm_rx_card_state_notif */
+#include "iwl-prph.h"
#include "iwl-eeprom-parse.h"
#include "mvm.h"
@@ -269,7 +270,7 @@ static int iwl_send_phy_cfg_cmd(struct iwl_mvm *mvm)
enum iwl_ucode_type ucode_type = mvm->cur_ucode;
/* Set parameters */
- phy_cfg_cmd.phy_cfg = cpu_to_le32(mvm->fw->phy_config);
+ phy_cfg_cmd.phy_cfg = cpu_to_le32(iwl_mvm_get_phy_config(mvm));
phy_cfg_cmd.calib_control.event_trigger =
mvm->fw->default_calib[ucode_type].event_trigger;
phy_cfg_cmd.calib_control.flow_trigger =
@@ -346,7 +347,7 @@ int iwl_run_init_mvm_ucode(struct iwl_mvm *mvm, bool read_nvm)
mvm->calibrating = true;
/* Send TX valid antennas before triggering calibrations */
- ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
if (ret)
goto error;
@@ -399,8 +400,71 @@ out:
return ret;
}
-static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm,
- enum iwl_fw_dbg_conf conf_id)
+static void iwl_mvm_get_shared_mem_conf(struct iwl_mvm *mvm)
+{
+ struct iwl_host_cmd cmd = {
+ .id = SHARED_MEM_CFG,
+ .flags = CMD_WANT_SKB,
+ .data = { NULL, },
+ .len = { 0, },
+ };
+ struct iwl_rx_packet *pkt;
+ struct iwl_shared_mem_cfg *mem_cfg;
+ u32 i;
+
+ lockdep_assert_held(&mvm->mutex);
+
+ if (WARN_ON(iwl_mvm_send_cmd(mvm, &cmd)))
+ return;
+
+ pkt = cmd.resp_pkt;
+ if (pkt->hdr.flags & IWL_CMD_FAILED_MSK) {
+ IWL_ERR(mvm, "Bad return from SHARED_MEM_CFG (0x%08X)\n",
+ pkt->hdr.flags);
+ goto exit;
+ }
+
+ mem_cfg = (void *)pkt->data;
+
+ mvm->shared_mem_cfg.shared_mem_addr =
+ le32_to_cpu(mem_cfg->shared_mem_addr);
+ mvm->shared_mem_cfg.shared_mem_size =
+ le32_to_cpu(mem_cfg->shared_mem_size);
+ mvm->shared_mem_cfg.sample_buff_addr =
+ le32_to_cpu(mem_cfg->sample_buff_addr);
+ mvm->shared_mem_cfg.sample_buff_size =
+ le32_to_cpu(mem_cfg->sample_buff_size);
+ mvm->shared_mem_cfg.txfifo_addr = le32_to_cpu(mem_cfg->txfifo_addr);
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++)
+ mvm->shared_mem_cfg.txfifo_size[i] =
+ le32_to_cpu(mem_cfg->txfifo_size[i]);
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++)
+ mvm->shared_mem_cfg.rxfifo_size[i] =
+ le32_to_cpu(mem_cfg->rxfifo_size[i]);
+ mvm->shared_mem_cfg.page_buff_addr =
+ le32_to_cpu(mem_cfg->page_buff_addr);
+ mvm->shared_mem_cfg.page_buff_size =
+ le32_to_cpu(mem_cfg->page_buff_size);
+ IWL_DEBUG_INFO(mvm, "SHARED MEM CFG: got memory offsets/sizes\n");
+
+exit:
+ iwl_free_resp(&cmd);
+}
+
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm)
+{
+ /* stop recording */
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000) {
+ iwl_set_bits_prph(mvm->trans, MON_BUFF_SAMPLE_CTL, 0x100);
+ } else {
+ iwl_write_prph(mvm->trans, DBGC_IN_SAMPLE, 0);
+ iwl_write_prph(mvm->trans, DBGC_OUT_CTRL, 0);
+ }
+
+ schedule_work(&mvm->fw_error_dump_wk);
+}
+
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf conf_id)
{
u8 *ptr;
int ret;
@@ -435,6 +499,35 @@ static int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm,
return ret;
}
+static int iwl_mvm_config_ltr_v1(struct iwl_mvm *mvm)
+{
+ struct iwl_ltr_config_cmd_v1 cmd_v1 = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ if (!mvm->trans->ltr_enabled)
+ return 0;
+
+ return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd_v1), &cmd_v1);
+}
+
+static int iwl_mvm_config_ltr(struct iwl_mvm *mvm)
+{
+ struct iwl_ltr_config_cmd cmd = {
+ .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
+ };
+
+ if (!mvm->trans->ltr_enabled)
+ return 0;
+
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_HDC_PHASE_0))
+ return iwl_mvm_config_ltr_v1(mvm);
+
+ return iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
+ sizeof(cmd), &cmd);
+}
+
int iwl_mvm_up(struct iwl_mvm *mvm)
{
int ret, i;
@@ -482,6 +575,9 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
goto error;
}
+ if (IWL_UCODE_API(mvm->fw->ucode_ver) >= 10)
+ iwl_mvm_get_shared_mem_conf(mvm);
+
ret = iwl_mvm_sf_update(mvm, NULL, false);
if (ret)
IWL_ERR(mvm, "Failed to initialize Smart Fifo\n");
@@ -489,7 +585,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
mvm->fw_dbg_conf = FW_DBG_INVALID;
iwl_mvm_start_fw_dbg_conf(mvm, FW_DBG_CUSTOM);
- ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
if (ret)
goto error;
@@ -538,14 +634,7 @@ int iwl_mvm_up(struct iwl_mvm *mvm)
/* Initialize tx backoffs to the minimal possible */
iwl_mvm_tt_tx_backoff(mvm, 0);
- if (mvm->trans->ltr_enabled) {
- struct iwl_ltr_config_cmd cmd = {
- .flags = cpu_to_le32(LTR_CFG_FLAG_FEATURE_ENABLE),
- };
-
- WARN_ON(iwl_mvm_send_cmd_pdu(mvm, LTR_CONFIG, 0,
- sizeof(cmd), &cmd));
- }
+ WARN_ON(iwl_mvm_config_ltr(mvm));
ret = iwl_mvm_power_update_device(mvm);
if (ret)
@@ -584,7 +673,7 @@ int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm)
goto error;
}
- ret = iwl_send_tx_ant_cfg(mvm, mvm->fw->valid_tx_ant);
+ ret = iwl_send_tx_ant_cfg(mvm, iwl_mvm_get_valid_tx_ant(mvm));
if (ret)
goto error;
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
index f6d86ccce6a8..7bdc6220743f 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac-ctxt.c
@@ -208,8 +208,10 @@ u32 iwl_mvm_mac_get_queues_mask(struct ieee80211_vif *vif)
if (vif->type == NL80211_IFTYPE_P2P_DEVICE)
return BIT(IWL_MVM_OFFCHANNEL_QUEUE);
- for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- qmask |= BIT(vif->hw_queue[ac]);
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
+ if (vif->hw_queue[ac] != IEEE80211_INVAL_HW_QUEUE)
+ qmask |= BIT(vif->hw_queue[ac]);
+ }
if (vif->type == NL80211_IFTYPE_AP)
qmask |= BIT(vif->cab_queue);
@@ -460,6 +462,9 @@ exit_fail:
int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
{
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
u32 ac;
int ret;
@@ -472,16 +477,17 @@ int iwl_mvm_mac_ctxt_init(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
iwl_mvm_enable_ac_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE,
- IWL_MVM_TX_FIFO_VO);
+ IWL_MVM_TX_FIFO_VO, wdg_timeout);
break;
case NL80211_IFTYPE_AP:
iwl_mvm_enable_ac_txq(mvm, vif->cab_queue,
- IWL_MVM_TX_FIFO_MCAST);
+ IWL_MVM_TX_FIFO_MCAST, wdg_timeout);
/* fall through */
default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
iwl_mvm_enable_ac_txq(mvm, vif->hw_queue[ac],
- iwl_mvm_ac_to_tx_fifo[ac]);
+ iwl_mvm_ac_to_tx_fifo[ac],
+ wdg_timeout);
break;
}
@@ -496,14 +502,14 @@ void iwl_mvm_mac_ctxt_release(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_P2P_DEVICE:
- iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE);
+ iwl_mvm_disable_txq(mvm, IWL_MVM_OFFCHANNEL_QUEUE, 0);
break;
case NL80211_IFTYPE_AP:
- iwl_mvm_disable_txq(mvm, vif->cab_queue);
+ iwl_mvm_disable_txq(mvm, vif->cab_queue, 0);
/* fall through */
default:
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
- iwl_mvm_disable_txq(mvm, vif->hw_queue[ac]);
+ iwl_mvm_disable_txq(mvm, vif->hw_queue[ac], 0);
}
}
@@ -975,7 +981,7 @@ static int iwl_mvm_mac_ctxt_send_beacon(struct iwl_mvm *mvm,
beacon_cmd.tx.tx_flags = cpu_to_le32(tx_flags);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
mvm->mgmt_last_antenna_idx);
beacon_cmd.tx.rate_n_flags =
diff --git a/drivers/net/wireless/iwlwifi/mvm/mac80211.c b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
index 20915587c820..1ff7ec08532d 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mac80211.c
+++ b/drivers/net/wireless/iwlwifi/mvm/mac80211.c
@@ -85,6 +85,7 @@
#include "testmode.h"
#include "iwl-fw-error-dump.h"
#include "iwl-prph.h"
+#include "iwl-csr.h"
static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
{
@@ -105,7 +106,7 @@ static const struct ieee80211_iface_limit iwl_mvm_limits[] = {
static const struct ieee80211_iface_combination iwl_mvm_iface_combinations[] = {
{
- .num_different_channels = 1,
+ .num_different_channels = 2,
.max_interfaces = 3,
.limits = iwl_mvm_limits,
.n_limits = ARRAY_SIZE(iwl_mvm_limits),
@@ -326,6 +327,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->radiotap_vht_details |= IEEE80211_RADIOTAP_VHT_KNOWN_STBC |
IEEE80211_RADIOTAP_VHT_KNOWN_BEAMFORMED;
hw->rate_control_algorithm = "iwl-mvm-rs";
+ hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
+ hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
/*
* Enable 11w if advertised by firmware and software crypto
@@ -336,13 +339,6 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
!iwlwifi_mod_params.sw_crypto)
hw->flags |= IEEE80211_HW_MFP_CAPABLE;
- if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT &&
- !iwlwifi_mod_params.uapsd_disable) {
- hw->flags |= IEEE80211_HW_SUPPORTS_UAPSD;
- hw->uapsd_queues = IWL_MVM_UAPSD_QUEUES;
- hw->uapsd_max_sp_len = IWL_UAPSD_MAX_SP;
- }
-
if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LMAC_SCAN ||
mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_UMAC_SCAN) {
hw->flags |= IEEE80211_SINGLE_HW_SCAN_ON_ALL_BANDS;
@@ -377,6 +373,8 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
hw->wiphy->max_remain_on_channel_duration = 10000;
hw->max_listen_interval = IWL_CONN_MAX_LISTEN_INTERVAL;
+ /* we can compensate an offset of up to 3 channels = 15 MHz */
+ hw->wiphy->max_adj_channel_rssi_comp = 3 * 5;
/* Extract MAC address */
memcpy(mvm->addresses[0].addr, mvm->nvm_data->hw_addr, ETH_ALEN);
@@ -403,10 +401,15 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
if (mvm->nvm_data->bands[IEEE80211_BAND_2GHZ].n_channels)
hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
- if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels)
+ if (mvm->nvm_data->bands[IEEE80211_BAND_5GHZ].n_channels) {
hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
&mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
+ if (mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER)
+ hw->wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap.cap |=
+ IEEE80211_VHT_CAP_SU_BEAMFORMER_CAPABLE;
+ }
+
hw->wiphy->hw_version = mvm->trans->hw_id;
if (iwlmvm_mod_params.power_scheme != IWL_POWER_SCHEME_CAM)
@@ -459,15 +462,17 @@ int iwl_mvm_mac_setup_register(struct iwl_mvm *mvm)
device_can_wakeup(mvm->trans->dev)) {
mvm->wowlan.flags = WIPHY_WOWLAN_ANY;
hw->wiphy->wowlan = &mvm->wowlan;
- } else if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
+ }
+
+ if (mvm->fw->img[IWL_UCODE_WOWLAN].sec[0].len &&
mvm->trans->ops->d3_suspend &&
mvm->trans->ops->d3_resume &&
device_can_wakeup(mvm->trans->dev)) {
- mvm->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
- WIPHY_WOWLAN_DISCONNECT |
- WIPHY_WOWLAN_EAP_IDENTITY_REQ |
- WIPHY_WOWLAN_RFKILL_RELEASE |
- WIPHY_WOWLAN_NET_DETECT;
+ mvm->wowlan.flags |= WIPHY_WOWLAN_MAGIC_PKT |
+ WIPHY_WOWLAN_DISCONNECT |
+ WIPHY_WOWLAN_EAP_IDENTITY_REQ |
+ WIPHY_WOWLAN_RFKILL_RELEASE |
+ WIPHY_WOWLAN_NET_DETECT;
if (!iwlwifi_mod_params.sw_crypto)
mvm->wowlan.flags |= WIPHY_WOWLAN_SUPPORTS_GTK_REKEY |
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
@@ -707,9 +712,6 @@ static void iwl_mvm_cleanup_iterator(void *data, u8 *mac,
mvmvif->uploaded = false;
mvmvif->ap_sta_id = IWL_MVM_STATION_COUNT;
- /* does this make sense at all? */
- mvmvif->color++;
-
spin_lock_bh(&mvm->time_event_lock);
iwl_mvm_te_clear_data(mvm, &mvmvif->time_event_data);
spin_unlock_bh(&mvm->time_event_lock);
@@ -761,41 +763,215 @@ static void iwl_mvm_free_coredump(const void *data)
kfree(fw_error_dump);
}
+static void iwl_mvm_dump_fifos(struct iwl_mvm *mvm,
+ struct iwl_fw_error_dump_data **dump_data)
+{
+ struct iwl_fw_error_dump_fifo *fifo_hdr;
+ u32 *fifo_data;
+ u32 fifo_len;
+ unsigned long flags;
+ int i, j;
+
+ if (!iwl_trans_grab_nic_access(mvm->trans, false, &flags))
+ return;
+
+ /* Pull RXF data from all RXFs */
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.rxfifo_size); i++) {
+ /*
+ * Keep aside the additional offset that might be needed for
+ * next RXF
+ */
+ u32 offset_diff = RXF_DIFF_FROM_PREV * i;
+
+ fifo_hdr = (void *)(*dump_data)->data;
+ fifo_data = (void *)fifo_hdr->data;
+ fifo_len = mvm->shared_mem_cfg.rxfifo_size[i];
+
+ /* No need to try to read the data if the length is 0 */
+ if (fifo_len == 0)
+ continue;
+
+ /* Add a TLV for the RXF */
+ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
+ (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
+
+ fifo_hdr->fifo_num = cpu_to_le32(i);
+ fifo_hdr->available_bytes =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_D_SPACE +
+ offset_diff));
+ fifo_hdr->wr_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_WR_PTR +
+ offset_diff));
+ fifo_hdr->rd_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_RD_PTR +
+ offset_diff));
+ fifo_hdr->fence_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_RD_FENCE_PTR +
+ offset_diff));
+ fifo_hdr->fence_mode =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ RXF_SET_FENCE_MODE +
+ offset_diff));
+
+ /* Lock fence */
+ iwl_trans_write_prph(mvm->trans,
+ RXF_SET_FENCE_MODE + offset_diff, 0x1);
+ /* Set fence pointer to the same place like WR pointer */
+ iwl_trans_write_prph(mvm->trans,
+ RXF_LD_WR2FENCE + offset_diff, 0x1);
+ /* Set fence offset */
+ iwl_trans_write_prph(mvm->trans,
+ RXF_LD_FENCE_OFFSET_ADDR + offset_diff,
+ 0x0);
+
+ /* Read FIFO */
+ fifo_len /= sizeof(u32); /* Size in DWORDS */
+ for (j = 0; j < fifo_len; j++)
+ fifo_data[j] = iwl_trans_read_prph(mvm->trans,
+ RXF_FIFO_RD_FENCE_INC +
+ offset_diff);
+ *dump_data = iwl_fw_error_next_data(*dump_data);
+ }
+
+ /* Pull TXF data from all TXFs */
+ for (i = 0; i < ARRAY_SIZE(mvm->shared_mem_cfg.txfifo_size); i++) {
+ /* Mark the number of TXF we're pulling now */
+ iwl_trans_write_prph(mvm->trans, TXF_LARC_NUM, i);
+
+ fifo_hdr = (void *)(*dump_data)->data;
+ fifo_data = (void *)fifo_hdr->data;
+ fifo_len = mvm->shared_mem_cfg.txfifo_size[i];
+
+ /* No need to try to read the data if the length is 0 */
+ if (fifo_len == 0)
+ continue;
+
+ /* Add a TLV for the FIFO */
+ (*dump_data)->type = cpu_to_le32(IWL_FW_ERROR_DUMP_TXF);
+ (*dump_data)->len = cpu_to_le32(fifo_len + sizeof(*fifo_hdr));
+
+ fifo_hdr->fifo_num = cpu_to_le32(i);
+ fifo_hdr->available_bytes =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_FIFO_ITEM_CNT));
+ fifo_hdr->wr_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_WR_PTR));
+ fifo_hdr->rd_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_RD_PTR));
+ fifo_hdr->fence_ptr =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_FENCE_PTR));
+ fifo_hdr->fence_mode =
+ cpu_to_le32(iwl_trans_read_prph(mvm->trans,
+ TXF_LOCK_FENCE));
+
+ /* Set the TXF_READ_MODIFY_ADDR to TXF_WR_PTR */
+ iwl_trans_write_prph(mvm->trans, TXF_READ_MODIFY_ADDR,
+ TXF_WR_PTR);
+
+ /* Dummy-read to advance the read pointer to the head */
+ iwl_trans_read_prph(mvm->trans, TXF_READ_MODIFY_DATA);
+
+ /* Read FIFO */
+ fifo_len /= sizeof(u32); /* Size in DWORDS */
+ for (j = 0; j < fifo_len; j++)
+ fifo_data[j] = iwl_trans_read_prph(mvm->trans,
+ TXF_READ_MODIFY_DATA);
+ *dump_data = iwl_fw_error_next_data(*dump_data);
+ }
+
+ iwl_trans_release_nic_access(mvm->trans, &flags);
+}
+
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
{
struct iwl_fw_error_dump_file *dump_file;
struct iwl_fw_error_dump_data *dump_data;
struct iwl_fw_error_dump_info *dump_info;
+ struct iwl_fw_error_dump_mem *dump_mem;
struct iwl_mvm_dump_ptrs *fw_error_dump;
- const struct fw_img *img;
u32 sram_len, sram_ofs;
- u32 file_len, rxf_len;
- unsigned long flags;
- int reg_val;
+ u32 file_len, fifo_data_len = 0;
+ u32 smem_len = mvm->cfg->smem_len;
+ u32 sram2_len = mvm->cfg->dccm2_len;
lockdep_assert_held(&mvm->mutex);
+ /* W/A for 8000 HW family A-step */
+ if (mvm->cfg->device_family == IWL_DEVICE_FAMILY_8000 &&
+ CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP) {
+ if (smem_len)
+ smem_len = 0x38000;
+
+ if (sram2_len)
+ sram2_len = 0x10000;
+ }
+
fw_error_dump = kzalloc(sizeof(*fw_error_dump), GFP_KERNEL);
if (!fw_error_dump)
return;
- img = &mvm->fw->img[mvm->cur_ucode];
- sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
- sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+ /* SRAM - include stack CCM if driver knows the values for it */
+ if (!mvm->cfg->dccm_offset || !mvm->cfg->dccm_len) {
+ const struct fw_img *img;
+
+ img = &mvm->fw->img[mvm->cur_ucode];
+ sram_ofs = img->sec[IWL_UCODE_SECTION_DATA].offset;
+ sram_len = img->sec[IWL_UCODE_SECTION_DATA].len;
+ } else {
+ sram_ofs = mvm->cfg->dccm_offset;
+ sram_len = mvm->cfg->dccm_len;
+ }
+
+ /* reading RXF/TXF sizes */
+ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status)) {
+ struct iwl_mvm_shared_mem_cfg *mem_cfg = &mvm->shared_mem_cfg;
+ int i;
+
+ fifo_data_len = 0;
+
+ /* Count RXF size */
+ for (i = 0; i < ARRAY_SIZE(mem_cfg->rxfifo_size); i++) {
+ if (!mem_cfg->rxfifo_size[i])
+ continue;
+
+ /* Add header info */
+ fifo_data_len += mem_cfg->rxfifo_size[i] +
+ sizeof(*dump_data) +
+ sizeof(struct iwl_fw_error_dump_fifo);
+ }
- /* reading buffer size */
- reg_val = iwl_trans_read_prph(mvm->trans, RXF_SIZE_ADDR);
- rxf_len = (reg_val & RXF_SIZE_BYTE_CNT_MSK) >> RXF_SIZE_BYTE_CND_POS;
+ for (i = 0; i < ARRAY_SIZE(mem_cfg->txfifo_size); i++) {
+ if (!mem_cfg->txfifo_size[i])
+ continue;
- /* the register holds the value divided by 128 */
- rxf_len = rxf_len << 7;
+ /* Add header info */
+ fifo_data_len += mem_cfg->txfifo_size[i] +
+ sizeof(*dump_data) +
+ sizeof(struct iwl_fw_error_dump_fifo);
+ }
+ }
file_len = sizeof(*dump_file) +
- sizeof(*dump_data) * 3 +
- sram_len +
- rxf_len +
+ sizeof(*dump_data) * 2 +
+ sram_len + sizeof(*dump_mem) +
+ fifo_data_len +
sizeof(*dump_info);
+ /* Make room for the SMEM, if it exists */
+ if (smem_len)
+ file_len += sizeof(*dump_data) + sizeof(*dump_mem) + smem_len;
+
+ /* Make room for the secondary SRAM, if it exists */
+ if (sram2_len)
+ file_len += sizeof(*dump_data) + sizeof(*dump_mem) + sram2_len;
+
dump_file = vzalloc(file_len);
if (!dump_file) {
kfree(fw_error_dump);
@@ -814,6 +990,7 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
mvm->cfg->device_family == IWL_DEVICE_FAMILY_7000 ?
cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_7) :
cpu_to_le32(IWL_FW_ERROR_DUMP_FAMILY_8);
+ dump_info->hw_step = cpu_to_le32(CSR_HW_REV_STEP(mvm->trans->hw_rev));
memcpy(dump_info->fw_human_readable, mvm->fw->human_readable,
sizeof(dump_info->fw_human_readable));
strncpy(dump_info->dev_human_readable, mvm->cfg->name,
@@ -822,28 +999,39 @@ void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm)
sizeof(dump_info->bus_human_readable));
dump_data = iwl_fw_error_next_data(dump_data);
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_RXF);
- dump_data->len = cpu_to_le32(rxf_len);
-
- if (iwl_trans_grab_nic_access(mvm->trans, false, &flags)) {
- u32 *rxf = (void *)dump_data->data;
- int i;
+ /* We only dump the FIFOs if the FW is in error state */
+ if (test_bit(STATUS_FW_ERROR, &mvm->trans->status))
+ iwl_mvm_dump_fifos(mvm, &dump_data);
+
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+ dump_data->len = cpu_to_le32(sram_len + sizeof(*dump_mem));
+ dump_mem = (void *)dump_data->data;
+ dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
+ dump_mem->offset = cpu_to_le32(sram_ofs);
+ iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_mem->data,
+ sram_len);
- for (i = 0; i < (rxf_len / sizeof(u32)); i++) {
- iwl_trans_write_prph(mvm->trans,
- RXF_LD_FENCE_OFFSET_ADDR,
- i * sizeof(u32));
- rxf[i] = iwl_trans_read_prph(mvm->trans,
- RXF_FIFO_RD_FENCE_ADDR);
- }
- iwl_trans_release_nic_access(mvm->trans, &flags);
+ if (smem_len) {
+ dump_data = iwl_fw_error_next_data(dump_data);
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+ dump_data->len = cpu_to_le32(smem_len + sizeof(*dump_mem));
+ dump_mem = (void *)dump_data->data;
+ dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SMEM);
+ dump_mem->offset = cpu_to_le32(mvm->cfg->smem_offset);
+ iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->smem_offset,
+ dump_mem->data, smem_len);
}
- dump_data = iwl_fw_error_next_data(dump_data);
- dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_SRAM);
- dump_data->len = cpu_to_le32(sram_len);
- iwl_trans_read_mem_bytes(mvm->trans, sram_ofs, dump_data->data,
- sram_len);
+ if (sram2_len) {
+ dump_data = iwl_fw_error_next_data(dump_data);
+ dump_data->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM);
+ dump_data->len = cpu_to_le32(sram2_len + sizeof(*dump_mem));
+ dump_mem = (void *)dump_data->data;
+ dump_mem->type = cpu_to_le32(IWL_FW_ERROR_DUMP_MEM_SRAM);
+ dump_mem->offset = cpu_to_le32(mvm->cfg->dccm2_offset);
+ iwl_trans_read_mem_bytes(mvm->trans, mvm->cfg->dccm2_offset,
+ dump_mem->data, sram2_len);
+ }
fw_error_dump->trans_ptr = iwl_trans_dump_data(mvm->trans);
fw_error_dump->op_mode_len = file_len;
@@ -864,6 +1052,11 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
if (!test_and_clear_bit(IWL_MVM_STATUS_D3_RECONFIG, &mvm->status))
iwl_mvm_fw_error_dump(mvm);
+ /* cleanup all stale references (scan, roc), but keep the
+ * ucode_down ref until reconfig is complete
+ */
+ iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
+
iwl_trans_stop_device(mvm->trans);
mvm->scan_status = IWL_MVM_SCAN_NONE;
@@ -893,10 +1086,6 @@ static void iwl_mvm_restart_cleanup(struct iwl_mvm *mvm)
ieee80211_wake_queues(mvm->hw);
- /* cleanup all stale references (scan, roc), but keep the
- * ucode_down ref until reconfig is complete */
- iwl_mvm_unref_all_except(mvm, IWL_MVM_REF_UCODE_DOWN);
-
/* clear any stale d0i3 state */
clear_bit(IWL_MVM_STATUS_IN_D0I3, &mvm->status);
@@ -933,6 +1122,19 @@ static int iwl_mvm_mac_start(struct ieee80211_hw *hw)
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
int ret;
+ /* Some hw restart cleanups must not hold the mutex */
+ if (test_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ /*
+ * Make sure we are out of d0i3. This is needed
+ * to make sure the reference accounting is correct
+ * (and there is no stale d0i3_exit_work).
+ */
+ wait_event_timeout(mvm->d0i3_exit_waitq,
+ !test_bit(IWL_MVM_STATUS_IN_D0I3,
+ &mvm->status),
+ HZ);
+ }
+
mutex_lock(&mvm->mutex);
ret = __iwl_mvm_mac_start(mvm);
mutex_unlock(&mvm->mutex);
@@ -982,6 +1184,13 @@ static void iwl_mvm_resume_complete(struct iwl_mvm *mvm)
IWL_DEBUG_RPM(mvm, "Run deferred d0i3 exit\n");
_iwl_mvm_exit_d0i3(mvm);
}
+
+ if (mvm->trans->d0i3_mode == IWL_D0I3_MODE_ON_SUSPEND)
+ if (!wait_event_timeout(mvm->d0i3_exit_waitq,
+ !test_bit(IWL_MVM_STATUS_IN_D0I3,
+ &mvm->status),
+ HZ))
+ WARN_ONCE(1, "D0i3 exit on resume timed out\n");
}
static void
@@ -1146,7 +1355,7 @@ static int iwl_mvm_mac_add_interface(struct ieee80211_hw *hw,
ret = iwl_mvm_power_update_mac(mvm);
if (ret)
- goto out_release;
+ goto out_remove_mac;
/* beacon filtering */
ret = iwl_mvm_disable_beacon_filter(mvm, vif, 0);
@@ -2088,7 +2297,7 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
struct ieee80211_sta *sta)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
/*
* This is called before mac80211 does RCU synchronisation,
@@ -2105,6 +2314,20 @@ static void iwl_mvm_sta_pre_rcu_remove(struct ieee80211_hw *hw,
mutex_unlock(&mvm->mutex);
}
+static void iwl_mvm_check_uapsd(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+ const u8 *bssid)
+{
+ if (!(mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_UAPSD_SUPPORT))
+ return;
+
+ if (iwlwifi_mod_params.uapsd_disable) {
+ vif->driver_flags &= ~IEEE80211_VIF_SUPPORTS_UAPSD;
+ return;
+ }
+
+ vif->driver_flags |= IEEE80211_VIF_SUPPORTS_UAPSD;
+}
+
static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta,
@@ -2164,6 +2387,7 @@ static int iwl_mvm_mac_sta_state(struct ieee80211_hw *hw,
* Reset EBS status here assuming environment has been changed.
*/
mvm->last_ebs_successful = true;
+ iwl_mvm_check_uapsd(mvm, vif, sta->addr);
ret = 0;
} else if (old_state == IEEE80211_STA_AUTH &&
new_state == IEEE80211_STA_ASSOC) {
@@ -3103,7 +3327,7 @@ static int iwl_mvm_set_tim(struct ieee80211_hw *hw,
bool set)
{
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
if (!mvm_sta || !mvm_sta->vif) {
IWL_ERR(mvm, "Station is not associated to a vif\n");
@@ -3343,16 +3567,18 @@ static void iwl_mvm_mac_flush(struct ieee80211_hw *hw,
msk |= mvmsta->tfd_queue_msk;
}
- msk &= ~BIT(vif->hw_queue[IEEE80211_AC_VO]);
-
- if (iwl_mvm_flush_tx_path(mvm, msk, true))
- IWL_ERR(mvm, "flush request fail\n");
- mutex_unlock(&mvm->mutex);
+ if (drop) {
+ if (iwl_mvm_flush_tx_path(mvm, msk, true))
+ IWL_ERR(mvm, "flush request fail\n");
+ mutex_unlock(&mvm->mutex);
+ } else {
+ mutex_unlock(&mvm->mutex);
- /* this can take a while, and we may need/want other operations
- * to succeed while doing this, so do it without the mutex held
- */
- iwl_trans_wait_tx_queue_empty(mvm->trans, msk);
+ /* this can take a while, and we may need/want other operations
+ * to succeed while doing this, so do it without the mutex held
+ */
+ iwl_trans_wait_tx_queue_empty(mvm->trans, msk);
+ }
}
const struct ieee80211_ops iwl_mvm_hw_ops = {
diff --git a/drivers/net/wireless/iwlwifi/mvm/mvm.h b/drivers/net/wireless/iwlwifi/mvm/mvm.h
index d24660fb4ef2..6c69d0584f6c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/mvm.h
+++ b/drivers/net/wireless/iwlwifi/mvm/mvm.h
@@ -119,11 +119,13 @@ extern const struct ieee80211_ops iwl_mvm_hw_ops;
* We will register to mac80211 to have testmode working. The NIC must not
* be up'ed after the INIT fw asserted. This is useful to be able to use
* proprietary tools over testmode to debug the INIT fw.
+ * @tfd_q_hang_detect: enabled the detection of hung transmit queues
* @power_scheme: CAM(Continuous Active Mode)-1, BPS(Balanced Power
* Save)-2(default), LP(Low Power)-3
*/
struct iwl_mvm_mod_params {
bool init_dbg;
+ bool tfd_q_hang_detect;
int power_scheme;
};
extern struct iwl_mvm_mod_params iwlmvm_mod_params;
@@ -276,6 +278,7 @@ enum iwl_mvm_ref_type {
IWL_MVM_REF_TM_CMD,
IWL_MVM_REF_EXIT_WORK,
IWL_MVM_REF_PROTECT_CSA,
+ IWL_MVM_REF_FW_DBG_COLLECT,
/* update debugfs.c when changing this */
@@ -531,10 +534,23 @@ enum {
enum iwl_mvm_tdls_cs_state {
IWL_MVM_TDLS_SW_IDLE = 0,
IWL_MVM_TDLS_SW_REQ_SENT,
+ IWL_MVM_TDLS_SW_RESP_RCVD,
IWL_MVM_TDLS_SW_REQ_RCVD,
IWL_MVM_TDLS_SW_ACTIVE,
};
+struct iwl_mvm_shared_mem_cfg {
+ u32 shared_mem_addr;
+ u32 shared_mem_size;
+ u32 sample_buff_addr;
+ u32 sample_buff_size;
+ u32 txfifo_addr;
+ u32 txfifo_size[TX_FIFO_MAX_NUM];
+ u32 rxfifo_size[RX_FIFO_MAX_NUM];
+ u32 page_buff_addr;
+ u32 page_buff_size;
+};
+
struct iwl_mvm {
/* for logger access */
struct device *dev;
@@ -641,6 +657,8 @@ struct iwl_mvm {
bool disable_power_off;
bool disable_power_off_d3;
+ bool scan_iter_notif_enabled;
+
struct debugfs_blob_wrapper nvm_hw_blob;
struct debugfs_blob_wrapper nvm_sw_blob;
struct debugfs_blob_wrapper nvm_calib_blob;
@@ -782,8 +800,13 @@ struct iwl_mvm {
struct cfg80211_chan_def chandef;
struct sk_buff *skb; /* ch sw template */
u32 ch_sw_tm_ie;
+
+ /* timestamp of last ch-sw request sent (GP2 time) */
+ u32 sent_timestamp;
} peer;
} tdls_cs;
+
+ struct iwl_mvm_shared_mem_cfg shared_mem_cfg;
};
/* Extract MVM priv from op_mode and _hw */
@@ -850,12 +873,14 @@ iwl_mvm_sta_from_staid_protected(struct iwl_mvm *mvm, u8 sta_id)
static inline bool iwl_mvm_is_d0i3_supported(struct iwl_mvm *mvm)
{
return mvm->trans->cfg->d0i3 &&
+ mvm->trans->d0i3_mode != IWL_D0I3_MODE_OFF &&
+ !iwlwifi_mod_params.d0i3_disable &&
(mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_D0I3_SUPPORT);
}
-static inline bool iwl_mvm_is_dqa_supported(struct iwl_mvm *mvm)
+static inline bool iwl_mvm_is_scd_cfg_supported(struct iwl_mvm *mvm)
{
- return mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_DQA_SUPPORT;
+ return mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SCD_CFG;
}
extern const u8 iwl_mvm_ac_to_tx_fifo[];
@@ -937,6 +962,33 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic);
int iwl_mvm_load_nvm_to_nic(struct iwl_mvm *mvm);
+static inline u8 iwl_mvm_get_valid_tx_ant(struct iwl_mvm *mvm)
+{
+ return mvm->nvm_data && mvm->nvm_data->valid_tx_ant ?
+ mvm->fw->valid_tx_ant & mvm->nvm_data->valid_tx_ant :
+ mvm->fw->valid_tx_ant;
+}
+
+static inline u8 iwl_mvm_get_valid_rx_ant(struct iwl_mvm *mvm)
+{
+ return mvm->nvm_data && mvm->nvm_data->valid_rx_ant ?
+ mvm->fw->valid_rx_ant & mvm->nvm_data->valid_rx_ant :
+ mvm->fw->valid_rx_ant;
+}
+
+static inline u32 iwl_mvm_get_phy_config(struct iwl_mvm *mvm)
+{
+ u32 phy_config = ~(FW_PHY_CFG_TX_CHAIN |
+ FW_PHY_CFG_RX_CHAIN);
+ u32 valid_rx_ant = iwl_mvm_get_valid_rx_ant(mvm);
+ u32 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
+
+ phy_config |= valid_tx_ant << FW_PHY_CFG_TX_CHAIN_POS |
+ valid_rx_ant << FW_PHY_CFG_RX_CHAIN_POS;
+
+ return mvm->fw->phy_config & phy_config;
+}
+
int iwl_mvm_up(struct iwl_mvm *mvm);
int iwl_mvm_load_d3_fw(struct iwl_mvm *mvm);
@@ -970,6 +1022,9 @@ int iwl_mvm_rx_radio_ver(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
int iwl_mvm_rx_mfuart_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_shared_mem_cfg_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
/* MVM PHY */
int iwl_mvm_phy_ctxt_add(struct iwl_mvm *mvm, struct iwl_mvm_phy_ctxt *ctxt,
@@ -1031,6 +1086,9 @@ int iwl_mvm_max_scan_ie_len(struct iwl_mvm *mvm, bool is_sched_scan);
int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd);
+int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd);
int iwl_mvm_config_sched_scan(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct cfg80211_sched_scan_request *req,
@@ -1091,9 +1149,7 @@ iwl_mvm_vif_dbgfs_clean(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
/* rate scaling */
int iwl_mvm_send_lq_cmd(struct iwl_mvm *mvm, struct iwl_lq_cmd *lq, bool init);
-void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
- struct iwl_mvm_frame_stats *stats,
- u32 rate, bool agg);
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg);
int rs_pretty_print_rate(char *buf, const u32 rate);
void rs_update_last_rssi(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta,
@@ -1159,6 +1215,8 @@ void iwl_mvm_unref(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
int iwl_mvm_ref_sync(struct iwl_mvm *mvm, enum iwl_mvm_ref_type ref_type);
bool iwl_mvm_ref_taken(struct iwl_mvm *mvm);
void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq);
+int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode);
+int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode);
int _iwl_mvm_exit_d0i3(struct iwl_mvm *mvm);
/* BT Coex */
@@ -1260,11 +1318,13 @@ static inline bool iwl_mvm_vif_low_latency(struct iwl_mvm_vif *mvmvif)
/* hw scheduler queue config */
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg);
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue);
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout);
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags);
-static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
- u8 fifo)
+static inline
+void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
+ u8 fifo, unsigned int wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -1273,12 +1333,13 @@ static inline void iwl_mvm_enable_ac_txq(struct iwl_mvm *mvm, int queue,
.frame_limit = IWL_FRAME_LIMIT,
};
- iwl_mvm_enable_txq(mvm, queue, 0, &cfg);
+ iwl_mvm_enable_txq(mvm, queue, 0, &cfg, wdg_timeout);
}
static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
int fifo, int sta_id, int tid,
- int frame_limit, u16 ssn)
+ int frame_limit, u16 ssn,
+ unsigned int wdg_timeout)
{
struct iwl_trans_txq_scd_cfg cfg = {
.fifo = fifo,
@@ -1288,7 +1349,7 @@ static inline void iwl_mvm_enable_agg_txq(struct iwl_mvm *mvm, int queue,
.aggregate = true,
};
- iwl_mvm_enable_txq(mvm, queue, ssn, &cfg);
+ iwl_mvm_enable_txq(mvm, queue, ssn, &cfg, wdg_timeout);
}
/* Assoc status */
@@ -1344,4 +1405,7 @@ struct ieee80211_vif *iwl_mvm_get_bss_vif(struct iwl_mvm *mvm);
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error);
void iwl_mvm_fw_error_dump(struct iwl_mvm *mvm);
+int iwl_mvm_start_fw_dbg_conf(struct iwl_mvm *mvm, enum iwl_fw_dbg_conf id);
+void iwl_mvm_fw_dbg_collect(struct iwl_mvm *mvm);
+
#endif /* __IWL_MVM_H__ */
diff --git a/drivers/net/wireless/iwlwifi/mvm/nvm.c b/drivers/net/wireless/iwlwifi/mvm/nvm.c
index d55fd8e3654c..5383429d96c1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/nvm.c
+++ b/drivers/net/wireless/iwlwifi/mvm/nvm.c
@@ -356,7 +356,7 @@ static int iwl_mvm_read_external_nvm(struct iwl_mvm *mvm)
max_section_size = IWL_MAX_NVM_SECTION_SIZE;
else if (CSR_HW_REV_STEP(mvm->trans->hw_rev) == SILICON_A_STEP)
max_section_size = IWL_MAX_NVM_8000A_SECTION_SIZE;
- else /* Family 8000 B-step */
+ else /* Family 8000 B-step or C-step */
max_section_size = IWL_MAX_NVM_8000B_SECTION_SIZE;
/*
@@ -565,6 +565,8 @@ int iwl_nvm_init(struct iwl_mvm *mvm, bool read_nvm_from_nic)
mvm->nvm_data = iwl_parse_nvm_sections(mvm);
if (!mvm->nvm_data)
return -ENODATA;
+ IWL_DEBUG_EEPROM(mvm->trans->dev, "nvm version = %x\n",
+ mvm->nvm_data->nvm_version);
return 0;
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/ops.c b/drivers/net/wireless/iwlwifi/mvm/ops.c
index 97dfba50c682..2dffc3600ed3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/ops.c
+++ b/drivers/net/wireless/iwlwifi/mvm/ops.c
@@ -84,15 +84,8 @@
#include "time-event.h"
#include "iwl-fw-error-dump.h"
-/*
- * module name, copyright, version, etc.
- */
#define DRV_DESCRIPTION "The new Intel(R) wireless AGN driver for Linux"
-
-#define DRV_VERSION IWLWIFI_VERSION
-
MODULE_DESCRIPTION(DRV_DESCRIPTION);
-MODULE_VERSION(DRV_VERSION);
MODULE_AUTHOR(DRV_COPYRIGHT " " DRV_AUTHOR);
MODULE_LICENSE("GPL");
@@ -100,6 +93,7 @@ static const struct iwl_op_mode_ops iwl_mvm_ops;
struct iwl_mvm_mod_params iwlmvm_mod_params = {
.power_scheme = IWL_POWER_SCHEME_BPS,
+ .tfd_q_hang_detect = true
/* rest of fields are 0 by default */
};
@@ -109,6 +103,10 @@ MODULE_PARM_DESC(init_dbg,
module_param_named(power_scheme, iwlmvm_mod_params.power_scheme, int, S_IRUGO);
MODULE_PARM_DESC(power_scheme,
"power management scheme: 1-active, 2-balanced, 3-low power, default: 2");
+module_param_named(tfd_q_hang_detect, iwlmvm_mod_params.tfd_q_hang_detect,
+ bool, S_IRUGO);
+MODULE_PARM_DESC(tfd_q_hang_detect,
+ "TFD queues hang detection (default: true");
/*
* module init and exit functions
@@ -146,13 +144,14 @@ static void iwl_mvm_nic_config(struct iwl_op_mode *op_mode)
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u8 radio_cfg_type, radio_cfg_step, radio_cfg_dash;
u32 reg_val = 0;
+ u32 phy_config = iwl_mvm_get_phy_config(mvm);
- radio_cfg_type = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_TYPE) >>
- FW_PHY_CFG_RADIO_TYPE_POS;
- radio_cfg_step = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_STEP) >>
- FW_PHY_CFG_RADIO_STEP_POS;
- radio_cfg_dash = (mvm->fw->phy_config & FW_PHY_CFG_RADIO_DASH) >>
- FW_PHY_CFG_RADIO_DASH_POS;
+ radio_cfg_type = (phy_config & FW_PHY_CFG_RADIO_TYPE) >>
+ FW_PHY_CFG_RADIO_TYPE_POS;
+ radio_cfg_step = (phy_config & FW_PHY_CFG_RADIO_STEP) >>
+ FW_PHY_CFG_RADIO_STEP_POS;
+ radio_cfg_dash = (phy_config & FW_PHY_CFG_RADIO_DASH) >>
+ FW_PHY_CFG_RADIO_DASH_POS;
/* SKU control */
reg_val |= CSR_HW_REV_STEP(mvm->trans->hw_rev) <<
@@ -240,6 +239,8 @@ static const struct iwl_rx_handlers iwl_mvm_rx_handlers[] = {
RX_HANDLER(SCAN_REQUEST_CMD, iwl_mvm_rx_scan_response, false),
RX_HANDLER(SCAN_COMPLETE_NOTIFICATION, iwl_mvm_rx_scan_complete, true),
+ RX_HANDLER(SCAN_ITERATION_COMPLETE,
+ iwl_mvm_rx_scan_offload_iter_complete_notif, false),
RX_HANDLER(SCAN_OFFLOAD_COMPLETE,
iwl_mvm_rx_scan_offload_complete_notif, true),
RX_HANDLER(MATCH_FOUND_NOTIFICATION, iwl_mvm_rx_scan_offload_results,
@@ -274,6 +275,7 @@ static const char *const iwl_mvm_cmd_strings[REPLY_MAX] = {
CMD(MGMT_MCAST_KEY),
CMD(TX_CMD),
CMD(TXPATH_FLUSH),
+ CMD(SHARED_MEM_CFG),
CMD(MAC_CONTEXT_CMD),
CMD(TIME_EVENT_CMD),
CMD(TIME_EVENT_NOTIFICATION),
@@ -476,17 +478,19 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (mvm->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_DW_BC_TABLE)
trans_cfg.bc_table_dword = true;
- if (!iwlwifi_mod_params.wd_disable)
- trans_cfg.queue_watchdog_timeout = cfg->base_params->wd_timeout;
- else
- trans_cfg.queue_watchdog_timeout = IWL_WATCHDOG_DISABLED;
-
trans_cfg.command_names = iwl_mvm_cmd_strings;
trans_cfg.cmd_queue = IWL_MVM_CMD_QUEUE;
trans_cfg.cmd_fifo = IWL_MVM_TX_FIFO_CMD;
trans_cfg.scd_set_active = true;
+ trans_cfg.sdio_adma_addr = fw->sdio_adma_addr;
+
+ /* Set a short watchdog for the command queue */
+ trans_cfg.cmd_q_wdg_timeout =
+ iwlmvm_mod_params.tfd_q_hang_detect ? IWL_DEF_WD_TIMEOUT :
+ IWL_WATCHDOG_DISABLED;
+
snprintf(mvm->hw->wiphy->fw_version,
sizeof(mvm->hw->wiphy->fw_version),
"%s", fw->fw_version);
@@ -517,10 +521,15 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
min_backoff = calc_min_backoff(trans, cfg);
iwl_mvm_tt_initialize(mvm, min_backoff);
/* set the nvm_file_name according to priority */
- if (iwlwifi_mod_params.nvm_file)
+ if (iwlwifi_mod_params.nvm_file) {
mvm->nvm_file_name = iwlwifi_mod_params.nvm_file;
- else
- mvm->nvm_file_name = mvm->cfg->default_nvm_file;
+ } else {
+ if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) &&
+ (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_A_STEP))
+ mvm->nvm_file_name = mvm->cfg->default_nvm_file_8000A;
+ else
+ mvm->nvm_file_name = mvm->cfg->default_nvm_file;
+ }
if (WARN(cfg->no_power_up_nic_in_init && !mvm->nvm_file_name,
"not allowing power-up and not having nvm_file\n"))
@@ -559,6 +568,9 @@ iwl_op_mode_mvm_start(struct iwl_trans *trans, const struct iwl_cfg *cfg,
if (!mvm->scan_cmd)
goto out_free;
+ /* Set EBS as successful as long as not stated otherwise by the FW. */
+ mvm->last_ebs_successful = true;
+
err = iwl_mvm_mac_setup_register(mvm);
if (err)
goto out_free;
@@ -817,9 +829,20 @@ static void iwl_mvm_fw_error_dump_wk(struct work_struct *work)
struct iwl_mvm *mvm =
container_of(work, struct iwl_mvm, fw_error_dump_wk);
+ if (iwl_mvm_ref_sync(mvm, IWL_MVM_REF_FW_DBG_COLLECT))
+ return;
+
mutex_lock(&mvm->mutex);
iwl_mvm_fw_error_dump(mvm);
+
+ /* start recording again if the firmware is not crashed */
+ WARN_ON_ONCE((!test_bit(STATUS_FW_ERROR, &mvm->trans->status)) &&
+ mvm->fw->dbg_dest_tlv &&
+ iwl_mvm_start_fw_dbg_conf(mvm, mvm->fw_dbg_conf));
+
mutex_unlock(&mvm->mutex);
+
+ iwl_mvm_unref(mvm, IWL_MVM_REF_FW_DBG_COLLECT);
}
void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
@@ -855,7 +878,10 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
* If WoWLAN fw asserted, don't restart either, mac80211
* can't recover this since we're already half suspended.
*/
- if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART, &mvm->status)) {
+ if (!mvm->restart_fw && fw_error) {
+ schedule_work(&mvm->fw_error_dump_wk);
+ } else if (test_and_set_bit(IWL_MVM_STATUS_IN_HW_RESTART,
+ &mvm->status)) {
struct iwl_mvm_reprobe *reprobe;
IWL_ERR(mvm,
@@ -879,16 +905,13 @@ void iwl_mvm_nic_restart(struct iwl_mvm *mvm, bool fw_error)
reprobe->dev = mvm->trans->dev;
INIT_WORK(&reprobe->work, iwl_mvm_reprobe_wk);
schedule_work(&reprobe->work);
- } else if (mvm->cur_ucode == IWL_UCODE_REGULAR &&
- (!fw_error || mvm->restart_fw)) {
+ } else if (mvm->cur_ucode == IWL_UCODE_REGULAR) {
/* don't let the transport/FW power down */
iwl_mvm_ref(mvm, IWL_MVM_REF_UCODE_DOWN);
if (fw_error && mvm->restart_fw > 0)
mvm->restart_fw--;
ieee80211_restart_hw(mvm->hw);
- } else if (fw_error) {
- schedule_work(&mvm->fw_error_dump_wk);
}
}
@@ -1031,7 +1054,8 @@ static void iwl_mvm_set_wowlan_data(struct iwl_mvm *mvm,
out:
rcu_read_unlock();
}
-static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
+
+int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
u32 flags = CMD_ASYNC | CMD_HIGH_PRIO | CMD_SEND_IN_IDLE;
@@ -1047,6 +1071,7 @@ static int iwl_mvm_enter_d0i3(struct iwl_op_mode *op_mode)
};
struct iwl_d3_manager_config d3_cfg_cmd = {
.min_sleep_time = cpu_to_le32(1000),
+ .wakeup_flags = cpu_to_le32(IWL_WAKEUP_D3_CONFIG_FW_ERROR),
};
IWL_DEBUG_RPM(mvm, "MVM entering D0i3\n");
@@ -1146,7 +1171,7 @@ void iwl_mvm_d0i3_enable_tx(struct iwl_mvm *mvm, __le16 *qos_seq)
if (mvm->d0i3_offloading && qos_seq) {
/* update qos seq numbers if offloading was enabled */
- mvm_ap_sta = (struct iwl_mvm_sta *)sta->drv_priv;
+ mvm_ap_sta = iwl_mvm_sta_from_mac80211(sta);
for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
u16 seq = le16_to_cpu(qos_seq[i]);
/* firmware stores last-used one, we store next one */
@@ -1245,7 +1270,7 @@ out:
return ret;
}
-static int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
+int iwl_mvm_exit_d0i3(struct iwl_op_mode *op_mode)
{
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
diff --git a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
index 1c0d4a45c1a8..5b43616eeb06 100644
--- a/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/phy-ctxt.c
@@ -170,13 +170,13 @@ static void iwl_mvm_phy_ctxt_cmd_data(struct iwl_mvm *mvm,
active_cnt = 2;
}
- cmd->rxchain_info = cpu_to_le32(mvm->fw->valid_rx_ant <<
+ cmd->rxchain_info = cpu_to_le32(iwl_mvm_get_valid_rx_ant(mvm) <<
PHY_RX_CHAIN_VALID_POS);
cmd->rxchain_info |= cpu_to_le32(idle_cnt << PHY_RX_CHAIN_CNT_POS);
cmd->rxchain_info |= cpu_to_le32(active_cnt <<
PHY_RX_CHAIN_MIMO_CNT_POS);
- cmd->txchain_info = cpu_to_le32(mvm->fw->valid_tx_ant);
+ cmd->txchain_info = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
}
/*
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.c b/drivers/net/wireless/iwlwifi/mvm/rs.c
index 30ceb67ed7a7..194bd1f939ca 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.c
@@ -39,28 +39,16 @@
#include "sta.h"
#include "iwl-op-mode.h"
#include "mvm.h"
+#include "debugfs.h"
#define RS_NAME "iwl-mvm-rs"
-#define NUM_TRY_BEFORE_ANT_TOGGLE 1
-#define RS_LEGACY_RETRIES_PER_RATE 1
-#define RS_HT_VHT_RETRIES_PER_RATE 2
-#define RS_HT_VHT_RETRIES_PER_RATE_TW 1
-#define RS_INITIAL_MIMO_NUM_RATES 3
-#define RS_INITIAL_SISO_NUM_RATES 3
-#define RS_INITIAL_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM
-#define RS_SECONDARY_LEGACY_NUM_RATES LINK_QUAL_MAX_RETRY_NUM
-#define RS_SECONDARY_SISO_NUM_RATES 3
-#define RS_SECONDARY_SISO_RETRIES 1
-
#define IWL_RATE_MAX_WINDOW 62 /* # tx in history window */
-#define IWL_RATE_MIN_FAILURE_TH 3 /* min failures to calc tpt */
-#define IWL_RATE_MIN_SUCCESS_TH 8 /* min successes to calc tpt */
-/* max allowed rate miss before sync LQ cmd */
-#define IWL_MISSED_RATE_MAX 15
-#define RS_STAY_IN_COLUMN_TIMEOUT (5*HZ)
-#define RS_IDLE_TIMEOUT (5*HZ)
+/* Calculations of success ratio are done in fixed point where 12800 is 100%.
+ * Use this macro when dealing with thresholds consts set as a percentage
+ */
+#define RS_PERCENT(x) (128 * x)
static u8 rs_ht_to_legacy[] = {
[IWL_RATE_MCS_0_INDEX] = IWL_RATE_6M_INDEX,
@@ -173,7 +161,7 @@ static bool rs_mimo_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
if (sta->smps_mode == IEEE80211_SMPS_STATIC)
return false;
- if (num_of_ant(mvm->fw->valid_tx_ant) < 2)
+ if (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) < 2)
return false;
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -613,7 +601,8 @@ static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
* at this rate. window->data contains the bitmask of successful
* packets.
*/
-static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
+static int _rs_collect_tx_data(struct iwl_mvm *mvm,
+ struct iwl_scale_tbl_info *tbl,
int scale_index, int attempts, int successes,
struct iwl_rate_scale_data *window)
{
@@ -668,8 +657,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
fail_count = window->counter - window->success_counter;
/* Calculate average throughput, if we have enough history. */
- if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
- (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
+ if ((fail_count >= IWL_MVM_RS_RATE_MIN_FAILURE_TH) ||
+ (window->success_counter >= IWL_MVM_RS_RATE_MIN_SUCCESS_TH))
window->average_tpt = (window->success_ratio * tpt + 64) / 128;
else
window->average_tpt = IWL_INVALID_VALUE;
@@ -677,7 +666,8 @@ static int _rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
return 0;
}
-static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
+static int rs_collect_tx_data(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl,
int scale_index, int attempts, int successes,
u8 reduced_txp)
@@ -698,7 +688,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
/* Select window for current tx bit rate */
window = &(tbl->win[scale_index]);
- ret = _rs_collect_tx_data(tbl, scale_index, attempts, successes,
+ ret = _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
window);
if (ret)
return ret;
@@ -707,7 +697,7 @@ static int rs_collect_tx_data(struct iwl_lq_sta *lq_sta,
return -EINVAL;
window = &tbl->tpc_win[reduced_txp];
- return _rs_collect_tx_data(tbl, scale_index, attempts, successes,
+ return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
window);
}
@@ -928,7 +918,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
break;
if (rate_mask & (1 << low))
break;
- IWL_DEBUG_RATE(mvm, "Skipping masked lower rate: %d\n", low);
}
high = index;
@@ -938,7 +927,6 @@ static u16 rs_get_adjacent_rate(struct iwl_mvm *mvm, u8 index, u16 rate_mask,
break;
if (rate_mask & (1 << high))
break;
- IWL_DEBUG_RATE(mvm, "Skipping masked higher rate: %d\n", high);
}
return (high << 8) | low;
@@ -1004,7 +992,7 @@ static void rs_get_lower_rate_down_column(struct iwl_lq_sta *lq_sta,
}
if (num_of_ant(rate->ant) > 1)
- rate->ant = first_antenna(mvm->fw->valid_tx_ant);
+ rate->ant = first_antenna(iwl_mvm_get_valid_tx_ant(mvm));
/* Relevant in both switching to SISO or Legacy */
rate->sgi = false;
@@ -1125,7 +1113,8 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
}
if (time_after(jiffies,
- (unsigned long)(lq_sta->last_tx + RS_IDLE_TIMEOUT))) {
+ (unsigned long)(lq_sta->last_tx +
+ (IWL_MVM_RS_IDLE_TIMEOUT * HZ)))) {
int t;
IWL_DEBUG_RATE(mvm, "Tx idle for too long. reinit rs\n");
@@ -1158,7 +1147,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
* ... driver.
*/
lq_sta->missed_rate_counter++;
- if (lq_sta->missed_rate_counter > IWL_MISSED_RATE_MAX) {
+ if (lq_sta->missed_rate_counter > IWL_MVM_RS_MISSED_RATE_MAX) {
lq_sta->missed_rate_counter = 0;
IWL_DEBUG_RATE(mvm,
"Too many rates mismatch. Send sync LQ. rs_state %d\n",
@@ -1213,7 +1202,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
ucode_rate = le32_to_cpu(table->rs_table[0]);
rs_rate_from_ucode_rate(ucode_rate, info->band, &rate);
- rs_collect_tx_data(lq_sta, curr_tbl, rate.index,
+ rs_collect_tx_data(mvm, lq_sta, curr_tbl, rate.index,
info->status.ampdu_len,
info->status.ampdu_ack_len,
reduced_txp);
@@ -1249,7 +1238,7 @@ void iwl_mvm_rs_tx_status(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
else
continue;
- rs_collect_tx_data(lq_sta, tmp_tbl, rate.index, 1,
+ rs_collect_tx_data(mvm, lq_sta, tmp_tbl, rate.index, 1,
i < retries ? 0 : legacy_success,
reduced_txp);
}
@@ -1303,13 +1292,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
IWL_DEBUG_RATE(mvm, "Moving to RS_STATE_STAY_IN_COLUMN\n");
lq_sta->rs_state = RS_STATE_STAY_IN_COLUMN;
if (is_legacy) {
- lq_sta->table_count_limit = IWL_LEGACY_TABLE_COUNT;
- lq_sta->max_failure_limit = IWL_LEGACY_FAILURE_LIMIT;
- lq_sta->max_success_limit = IWL_LEGACY_SUCCESS_LIMIT;
+ lq_sta->table_count_limit = IWL_MVM_RS_LEGACY_TABLE_COUNT;
+ lq_sta->max_failure_limit = IWL_MVM_RS_LEGACY_FAILURE_LIMIT;
+ lq_sta->max_success_limit = IWL_MVM_RS_LEGACY_SUCCESS_LIMIT;
} else {
- lq_sta->table_count_limit = IWL_NONE_LEGACY_TABLE_COUNT;
- lq_sta->max_failure_limit = IWL_NONE_LEGACY_FAILURE_LIMIT;
- lq_sta->max_success_limit = IWL_NONE_LEGACY_SUCCESS_LIMIT;
+ lq_sta->table_count_limit = IWL_MVM_RS_NON_LEGACY_TABLE_COUNT;
+ lq_sta->max_failure_limit = IWL_MVM_RS_NON_LEGACY_FAILURE_LIMIT;
+ lq_sta->max_success_limit = IWL_MVM_RS_NON_LEGACY_SUCCESS_LIMIT;
}
lq_sta->table_count = 0;
lq_sta->total_failed = 0;
@@ -1318,6 +1307,13 @@ static void rs_set_stay_in_table(struct iwl_mvm *mvm, u8 is_legacy,
lq_sta->visited_columns = 0;
}
+static inline int rs_get_max_rate_from_mask(unsigned long rate_mask)
+{
+ if (rate_mask)
+ return find_last_bit(&rate_mask, BITS_PER_LONG);
+ return IWL_RATE_INVALID;
+}
+
static int rs_get_max_allowed_rate(struct iwl_lq_sta *lq_sta,
const struct rs_tx_column *column)
{
@@ -1420,7 +1416,7 @@ static s32 rs_get_best_rate(struct iwl_mvm *mvm,
u32 target_tpt;
int rate_idx;
- if (success_ratio > RS_SR_NO_DECREASE) {
+ if (success_ratio > IWL_MVM_RS_SR_NO_DECREASE) {
target_tpt = 100 * expected_current_tpt;
IWL_DEBUG_RATE(mvm,
"SR %d high. Find rate exceeding EXPECTED_CURRENT %d\n",
@@ -1488,7 +1484,7 @@ static void rs_stay_in_table(struct iwl_lq_sta *lq_sta, bool force_search)
flush_interval_passed =
time_after(jiffies,
(unsigned long)(lq_sta->flush_timer +
- RS_STAY_IN_COLUMN_TIMEOUT));
+ (IWL_MVM_RS_STAY_IN_COLUMN_TIMEOUT * HZ)));
/*
* Check if we should allow search for new modulation mode.
@@ -1567,7 +1563,7 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
const struct rs_tx_column *curr_col = &rs_tx_columns[tbl->column];
const struct rs_tx_column *next_col;
allow_column_func_t allow_func;
- u8 valid_ants = mvm->fw->valid_tx_ant;
+ u8 valid_ants = iwl_mvm_get_valid_tx_ant(mvm);
const u16 *expected_tpt_tbl;
u16 tpt, max_expected_tpt;
@@ -1613,8 +1609,12 @@ static enum rs_column rs_get_next_column(struct iwl_mvm *mvm,
continue;
max_rate = rs_get_max_allowed_rate(lq_sta, next_col);
- if (WARN_ON_ONCE(max_rate == IWL_RATE_INVALID))
+ if (max_rate == IWL_RATE_INVALID) {
+ IWL_DEBUG_RATE(mvm,
+ "Skip column %d: no rate is allowed in this column\n",
+ next_col_id);
continue;
+ }
max_expected_tpt = expected_tpt_tbl[max_rate];
if (tpt >= max_expected_tpt) {
@@ -1724,7 +1724,8 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
{
enum rs_action action = RS_ACTION_STAY;
- if ((sr <= RS_SR_FORCE_DECREASE) || (current_tpt == 0)) {
+ if ((sr <= RS_PERCENT(IWL_MVM_RS_SR_FORCE_DECREASE)) ||
+ (current_tpt == 0)) {
IWL_DEBUG_RATE(mvm,
"Decrease rate because of low SR\n");
return RS_ACTION_DOWNSCALE;
@@ -1783,7 +1784,7 @@ static enum rs_action rs_get_rate_action(struct iwl_mvm *mvm,
out:
if ((action == RS_ACTION_DOWNSCALE) && (low != IWL_RATE_INVALID)) {
- if (sr >= RS_SR_NO_DECREASE) {
+ if (sr >= RS_PERCENT(IWL_MVM_RS_SR_NO_DECREASE)) {
IWL_DEBUG_RATE(mvm,
"SR is above NO DECREASE. Avoid downscale\n");
action = RS_ACTION_STAY;
@@ -1802,18 +1803,10 @@ out:
static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta)
{
- struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
- struct ieee80211_vif *vif = mvmsta->vif;
- bool sta_ps_disabled = (vif->type == NL80211_IFTYPE_STATION &&
- !vif->bss_conf.ps);
-
/* Our chip supports Tx STBC and the peer is an HT/VHT STA which
* supports STBC of at least 1*SS
*/
- if (!lq_sta->stbc)
- return false;
-
- if (!mvm->ps_disabled && !sta_ps_disabled)
+ if (!lq_sta->stbc_capable)
return false;
if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
@@ -1825,11 +1818,11 @@ static bool rs_stbc_allow(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
static void rs_get_adjacent_txp(struct iwl_mvm *mvm, int index,
int *weaker, int *stronger)
{
- *weaker = index + TPC_TX_POWER_STEP;
+ *weaker = index + IWL_MVM_RS_TPC_TX_POWER_STEP;
if (*weaker > TPC_MAX_REDUCTION)
*weaker = TPC_INVALID;
- *stronger = index - TPC_TX_POWER_STEP;
+ *stronger = index - IWL_MVM_RS_TPC_TX_POWER_STEP;
if (*stronger < 0)
*stronger = TPC_INVALID;
}
@@ -1885,7 +1878,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
}
/* Too many failures, increase txp */
- if (sr <= TPC_SR_FORCE_INCREASE || current_tpt == 0) {
+ if (sr <= RS_PERCENT(IWL_MVM_RS_TPC_SR_FORCE_INCREASE) ||
+ current_tpt == 0) {
IWL_DEBUG_RATE(mvm, "increase txp because of weak SR\n");
return TPC_ACTION_NO_RESTIRCTION;
}
@@ -1908,7 +1902,8 @@ static enum tpc_action rs_get_tpc_action(struct iwl_mvm *mvm,
}
/* next, increase if needed */
- if (sr < TPC_SR_NO_INCREASE && strong != TPC_INVALID) {
+ if (sr < RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) &&
+ strong != TPC_INVALID) {
if (weak_tpt == IWL_INVALID_VALUE &&
strong_tpt != IWL_INVALID_VALUE &&
current_tpt < strong_tpt) {
@@ -1935,7 +1930,7 @@ static bool rs_tpc_perform(struct iwl_mvm *mvm,
struct iwl_lq_sta *lq_sta,
struct iwl_scale_tbl_info *tbl)
{
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
struct ieee80211_vif *vif = mvm_sta->vif;
struct ieee80211_chanctx_conf *chanctx_conf;
enum ieee80211_band band;
@@ -2044,7 +2039,7 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
u16 high_low;
s32 sr;
u8 prev_agg = lq_sta->is_agg;
- struct iwl_mvm_sta *sta_priv = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_tid_data *tid_data;
struct rs_rate *rate;
@@ -2106,8 +2101,8 @@ static void rs_rate_scale_perform(struct iwl_mvm *mvm,
* in current association (use new rate found above).
*/
fail_count = window->counter - window->success_counter;
- if ((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
- (window->success_counter < IWL_RATE_MIN_SUCCESS_TH)) {
+ if ((fail_count < IWL_MVM_RS_RATE_MIN_FAILURE_TH) &&
+ (window->success_counter < IWL_MVM_RS_RATE_MIN_SUCCESS_TH)) {
IWL_DEBUG_RATE(mvm,
"(%s: %d): Test Window: succ %d total %d\n",
rs_pretty_lq_type(rate->type),
@@ -2385,7 +2380,7 @@ static void rs_get_initial_rate(struct iwl_mvm *mvm,
int i, nentries;
s8 best_rssi = S8_MIN;
u8 best_ant = ANT_NONE;
- u8 valid_tx_ant = mvm->fw->valid_tx_ant;
+ u8 valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
const struct rs_init_rate_info *initial_rates;
for (i = 0; i < ARRAY_SIZE(lq_sta->pers.chain_signal); i++) {
@@ -2530,7 +2525,7 @@ static void rs_get_rate(void *mvm_r, struct ieee80211_sta *sta, void *mvm_sta,
static void *rs_alloc_sta(void *mvm_rate, struct ieee80211_sta *sta,
gfp_t gfp)
{
- struct iwl_mvm_sta *sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
+ struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
struct iwl_op_mode *op_mode = (struct iwl_op_mode *)mvm_rate;
struct iwl_mvm *mvm = IWL_OP_MODE_GET_MVM(op_mode);
struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta;
@@ -2606,68 +2601,121 @@ static void rs_vht_set_enabled_rates(struct ieee80211_sta *sta,
}
}
+static void rs_ht_init(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta_ht_cap *ht_cap)
+{
+ /* active_siso_rate mask includes 9 MBits (bit 5),
+ * and CCK (bits 0-3), supp_rates[] does not;
+ * shift to convert format, force 9 MBits off.
+ */
+ lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
+ lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
+ lq_sta->active_siso_rate &= ~((u16)0x2);
+ lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
+
+ lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
+ lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
+ lq_sta->active_mimo2_rate &= ~((u16)0x2);
+ lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
+
+ if (mvm->cfg->ht_params->ldpc &&
+ (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
+ lq_sta->ldpc = true;
+
+ if (mvm->cfg->ht_params->stbc &&
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
+ (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
+ lq_sta->stbc_capable = true;
+
+ lq_sta->is_vht = false;
+}
+
+static void rs_vht_init(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ struct ieee80211_sta_vht_cap *vht_cap)
+{
+ rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
+
+ if (mvm->cfg->ht_params->ldpc &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
+ lq_sta->ldpc = true;
+
+ if (mvm->cfg->ht_params->stbc &&
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
+ lq_sta->stbc_capable = true;
+
+ if ((mvm->fw->ucode_capa.capa[0] & IWL_UCODE_TLV_CAPA_BEAMFORMER) &&
+ (num_of_ant(iwl_mvm_get_valid_tx_ant(mvm)) > 1) &&
+ (vht_cap->cap & IEEE80211_VHT_CAP_SU_BEAMFORMEE_CAPABLE))
+ lq_sta->bfer_capable = true;
+
+ lq_sta->is_vht = true;
+}
+
#ifdef CONFIG_IWLWIFI_DEBUGFS
-static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm,
- struct iwl_mvm_frame_stats *stats)
+static void iwl_mvm_reset_frame_stats(struct iwl_mvm *mvm)
{
spin_lock_bh(&mvm->drv_stats_lock);
- memset(stats, 0, sizeof(*stats));
+ memset(&mvm->drv_rx_stats, 0, sizeof(mvm->drv_rx_stats));
spin_unlock_bh(&mvm->drv_stats_lock);
}
-void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm,
- struct iwl_mvm_frame_stats *stats,
- u32 rate, bool agg)
+void iwl_mvm_update_frame_stats(struct iwl_mvm *mvm, u32 rate, bool agg)
{
u8 nss = 0, mcs = 0;
spin_lock(&mvm->drv_stats_lock);
if (agg)
- stats->agg_frames++;
+ mvm->drv_rx_stats.agg_frames++;
- stats->success_frames++;
+ mvm->drv_rx_stats.success_frames++;
switch (rate & RATE_MCS_CHAN_WIDTH_MSK) {
case RATE_MCS_CHAN_WIDTH_20:
- stats->bw_20_frames++;
+ mvm->drv_rx_stats.bw_20_frames++;
break;
case RATE_MCS_CHAN_WIDTH_40:
- stats->bw_40_frames++;
+ mvm->drv_rx_stats.bw_40_frames++;
break;
case RATE_MCS_CHAN_WIDTH_80:
- stats->bw_80_frames++;
+ mvm->drv_rx_stats.bw_80_frames++;
break;
default:
WARN_ONCE(1, "bad BW. rate 0x%x", rate);
}
if (rate & RATE_MCS_HT_MSK) {
- stats->ht_frames++;
+ mvm->drv_rx_stats.ht_frames++;
mcs = rate & RATE_HT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_HT_MCS_NSS_MSK) >> RATE_HT_MCS_NSS_POS) + 1;
} else if (rate & RATE_MCS_VHT_MSK) {
- stats->vht_frames++;
+ mvm->drv_rx_stats.vht_frames++;
mcs = rate & RATE_VHT_MCS_RATE_CODE_MSK;
nss = ((rate & RATE_VHT_MCS_NSS_MSK) >>
RATE_VHT_MCS_NSS_POS) + 1;
} else {
- stats->legacy_frames++;
+ mvm->drv_rx_stats.legacy_frames++;
}
if (nss == 1)
- stats->siso_frames++;
+ mvm->drv_rx_stats.siso_frames++;
else if (nss == 2)
- stats->mimo2_frames++;
+ mvm->drv_rx_stats.mimo2_frames++;
if (rate & RATE_MCS_SGI_MSK)
- stats->sgi_frames++;
+ mvm->drv_rx_stats.sgi_frames++;
else
- stats->ngi_frames++;
+ mvm->drv_rx_stats.ngi_frames++;
- stats->last_rates[stats->last_frame_idx] = rate;
- stats->last_frame_idx = (stats->last_frame_idx + 1) %
- ARRAY_SIZE(stats->last_rates);
+ mvm->drv_rx_stats.last_rates[mvm->drv_rx_stats.last_frame_idx] = rate;
+ mvm->drv_rx_stats.last_frame_idx =
+ (mvm->drv_rx_stats.last_frame_idx + 1) %
+ ARRAY_SIZE(mvm->drv_rx_stats.last_rates);
spin_unlock(&mvm->drv_stats_lock);
}
@@ -2683,14 +2731,11 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
struct ieee80211_hw *hw = mvm->hw;
struct ieee80211_sta_ht_cap *ht_cap = &sta->ht_cap;
struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap;
- struct iwl_mvm_sta *sta_priv;
- struct iwl_lq_sta *lq_sta;
+ struct iwl_mvm_sta *sta_priv = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_lq_sta *lq_sta = &sta_priv->lq_sta;
struct ieee80211_supported_band *sband;
unsigned long supp; /* must be unsigned long for for_each_set_bit */
- sta_priv = (struct iwl_mvm_sta *)sta->drv_priv;
- lq_sta = &sta_priv->lq_sta;
-
/* clear all non-persistent lq data */
memset(lq_sta, 0, offsetof(typeof(*lq_sta), pers));
@@ -2712,7 +2757,7 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
* previous packets? Need to have IEEE 802.1X auth succeed immediately
* after assoc.. */
- lq_sta->missed_rate_counter = IWL_MISSED_RATE_MAX;
+ lq_sta->missed_rate_counter = IWL_MVM_RS_MISSED_RATE_MAX;
lq_sta->band = sband->band;
/*
* active legacy rates as per supported rates bitmap
@@ -2723,61 +2768,28 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
lq_sta->active_legacy_rate |= BIT(sband->bitrates[i].hw_value);
/* TODO: should probably account for rx_highest for both HT/VHT */
- if (!vht_cap || !vht_cap->vht_supported) {
- /* active_siso_rate mask includes 9 MBits (bit 5),
- * and CCK (bits 0-3), supp_rates[] does not;
- * shift to convert format, force 9 MBits off.
- */
- lq_sta->active_siso_rate = ht_cap->mcs.rx_mask[0] << 1;
- lq_sta->active_siso_rate |= ht_cap->mcs.rx_mask[0] & 0x1;
- lq_sta->active_siso_rate &= ~((u16)0x2);
- lq_sta->active_siso_rate <<= IWL_FIRST_OFDM_RATE;
-
- /* Same here */
- lq_sta->active_mimo2_rate = ht_cap->mcs.rx_mask[1] << 1;
- lq_sta->active_mimo2_rate |= ht_cap->mcs.rx_mask[1] & 0x1;
- lq_sta->active_mimo2_rate &= ~((u16)0x2);
- lq_sta->active_mimo2_rate <<= IWL_FIRST_OFDM_RATE;
-
- lq_sta->is_vht = false;
- if (mvm->cfg->ht_params->ldpc &&
- (ht_cap->cap & IEEE80211_HT_CAP_LDPC_CODING))
- lq_sta->ldpc = true;
-
- if (mvm->cfg->ht_params->stbc &&
- (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
- (ht_cap->cap & IEEE80211_HT_CAP_RX_STBC))
- lq_sta->stbc = true;
- } else {
- rs_vht_set_enabled_rates(sta, vht_cap, lq_sta);
- lq_sta->is_vht = true;
-
- if (mvm->cfg->ht_params->ldpc &&
- (vht_cap->cap & IEEE80211_VHT_CAP_RXLDPC))
- lq_sta->ldpc = true;
-
- if (mvm->cfg->ht_params->stbc &&
- (num_of_ant(mvm->fw->valid_tx_ant) > 1) &&
- (vht_cap->cap & IEEE80211_VHT_CAP_RXSTBC_MASK))
- lq_sta->stbc = true;
- }
+ if (!vht_cap || !vht_cap->vht_supported)
+ rs_ht_init(mvm, sta, lq_sta, ht_cap);
+ else
+ rs_vht_init(mvm, sta, lq_sta, vht_cap);
- if (IWL_MVM_RS_DISABLE_MIMO)
+ if (IWL_MVM_RS_DISABLE_P2P_MIMO && sta_priv->vif->p2p)
lq_sta->active_mimo2_rate = 0;
- lq_sta->max_legacy_rate_idx = find_last_bit(&lq_sta->active_legacy_rate,
- BITS_PER_LONG);
- lq_sta->max_siso_rate_idx = find_last_bit(&lq_sta->active_siso_rate,
- BITS_PER_LONG);
- lq_sta->max_mimo2_rate_idx = find_last_bit(&lq_sta->active_mimo2_rate,
- BITS_PER_LONG);
+ lq_sta->max_legacy_rate_idx =
+ rs_get_max_rate_from_mask(lq_sta->active_legacy_rate);
+ lq_sta->max_siso_rate_idx =
+ rs_get_max_rate_from_mask(lq_sta->active_siso_rate);
+ lq_sta->max_mimo2_rate_idx =
+ rs_get_max_rate_from_mask(lq_sta->active_mimo2_rate);
IWL_DEBUG_RATE(mvm,
- "RATE MASK: LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC%d\n",
+ "LEGACY=%lX SISO=%lX MIMO2=%lX VHT=%d LDPC=%d STBC=%d BFER=%d\n",
lq_sta->active_legacy_rate,
lq_sta->active_siso_rate,
lq_sta->active_mimo2_rate,
- lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc);
+ lq_sta->is_vht, lq_sta->ldpc, lq_sta->stbc_capable,
+ lq_sta->bfer_capable);
IWL_DEBUG_RATE(mvm, "MAX RATE: LEGACY=%d SISO=%d MIMO2=%d\n",
lq_sta->max_legacy_rate_idx,
lq_sta->max_siso_rate_idx,
@@ -2785,14 +2797,14 @@ void iwl_mvm_rs_rate_init(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
/* These values will be overridden later */
lq_sta->lq.single_stream_ant_msk =
- first_antenna(mvm->fw->valid_tx_ant);
+ first_antenna(iwl_mvm_get_valid_tx_ant(mvm));
lq_sta->lq.dual_stream_ant_msk = ANT_AB;
/* as default allow aggregation for all tids */
lq_sta->tx_agg_tid_en = IWL_AGG_ALL_TID;
lq_sta->is_agg = 0;
#ifdef CONFIG_IWLWIFI_DEBUGFS
- iwl_mvm_reset_frame_stats(mvm, &mvm->drv_rx_stats);
+ iwl_mvm_reset_frame_stats(mvm);
#endif
rs_initialize_lq(mvm, sta, lq_sta, band, init);
}
@@ -2861,12 +2873,13 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
int index = *rs_table_index;
for (i = 0; i < num_rates && index < end; i++) {
- ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm, rate));
- for (j = 0; j < num_retries && index < end; j++, index++)
+ for (j = 0; j < num_retries && index < end; j++, index++) {
+ ucode_rate = cpu_to_le32(ucode_rate_from_rs_rate(mvm,
+ rate));
rs_table[index] = ucode_rate;
-
- if (toggle_ant)
- rs_toggle_antenna(valid_tx_ant, rate);
+ if (toggle_ant)
+ rs_toggle_antenna(valid_tx_ant, rate);
+ }
prev_rate_idx = rate->index;
bottom_reached = rs_get_lower_rate_in_column(lq_sta, rate);
@@ -2874,7 +2887,7 @@ static void rs_fill_rates_for_column(struct iwl_mvm *mvm,
break;
}
- if (!bottom_reached)
+ if (!bottom_reached && !is_legacy(rate))
rate->index = prev_rate_idx;
*rs_table_index = index;
@@ -2913,18 +2926,22 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
memcpy(&rate, initial_rate, sizeof(rate));
- valid_tx_ant = mvm->fw->valid_tx_ant;
- rate.stbc = rs_stbc_allow(mvm, sta, lq_sta);
+ valid_tx_ant = iwl_mvm_get_valid_tx_ant(mvm);
+
+ /* TODO: remove old API when min FW API hits 14 */
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS) &&
+ rs_stbc_allow(mvm, sta, lq_sta))
+ rate.stbc = true;
if (is_siso(&rate)) {
- num_rates = RS_INITIAL_SISO_NUM_RATES;
- num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+ num_rates = IWL_MVM_RS_INITIAL_SISO_NUM_RATES;
+ num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE;
} else if (is_mimo(&rate)) {
- num_rates = RS_INITIAL_MIMO_NUM_RATES;
- num_retries = RS_HT_VHT_RETRIES_PER_RATE;
+ num_rates = IWL_MVM_RS_INITIAL_MIMO_NUM_RATES;
+ num_retries = IWL_MVM_RS_HT_VHT_RETRIES_PER_RATE;
} else {
- num_rates = RS_INITIAL_LEGACY_NUM_RATES;
- num_retries = RS_LEGACY_RETRIES_PER_RATE;
+ num_rates = IWL_MVM_RS_INITIAL_LEGACY_NUM_RATES;
+ num_retries = IWL_MVM_RS_INITIAL_LEGACY_RETRIES;
toggle_ant = true;
}
@@ -2935,12 +2952,12 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
rs_get_lower_rate_down_column(lq_sta, &rate);
if (is_siso(&rate)) {
- num_rates = RS_SECONDARY_SISO_NUM_RATES;
- num_retries = RS_SECONDARY_SISO_RETRIES;
+ num_rates = IWL_MVM_RS_SECONDARY_SISO_NUM_RATES;
+ num_retries = IWL_MVM_RS_SECONDARY_SISO_RETRIES;
lq_cmd->mimo_delim = index;
} else if (is_legacy(&rate)) {
- num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
- num_retries = RS_LEGACY_RETRIES_PER_RATE;
+ num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES;
+ num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES;
} else {
WARN_ON_ONCE(1);
}
@@ -2953,8 +2970,8 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
rs_get_lower_rate_down_column(lq_sta, &rate);
- num_rates = RS_SECONDARY_LEGACY_NUM_RATES;
- num_retries = RS_LEGACY_RETRIES_PER_RATE;
+ num_rates = IWL_MVM_RS_SECONDARY_LEGACY_NUM_RATES;
+ num_retries = IWL_MVM_RS_SECONDARY_LEGACY_RETRIES;
rs_fill_rates_for_column(mvm, lq_sta, &rate, lq_cmd->rs_table, &index,
num_rates, num_retries, valid_tx_ant,
@@ -2962,6 +2979,142 @@ static void rs_build_rates_table(struct iwl_mvm *mvm,
}
+struct rs_bfer_active_iter_data {
+ struct ieee80211_sta *exclude_sta;
+ struct iwl_mvm_sta *bfer_mvmsta;
+};
+
+static void rs_bfer_active_iter(void *_data,
+ struct ieee80211_sta *sta)
+{
+ struct rs_bfer_active_iter_data *data = _data;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct iwl_lq_cmd *lq_cmd = &mvmsta->lq_sta.lq;
+ u32 ss_params = le32_to_cpu(lq_cmd->ss_params);
+
+ if (sta == data->exclude_sta)
+ return;
+
+ /* The current sta has BFER allowed */
+ if (ss_params & LQ_SS_BFER_ALLOWED) {
+ WARN_ON_ONCE(data->bfer_mvmsta != NULL);
+
+ data->bfer_mvmsta = mvmsta;
+ }
+}
+
+static int rs_bfer_priority(struct iwl_mvm_sta *sta)
+{
+ int prio = -1;
+ enum nl80211_iftype viftype = ieee80211_vif_type_p2p(sta->vif);
+
+ switch (viftype) {
+ case NL80211_IFTYPE_AP:
+ case NL80211_IFTYPE_P2P_GO:
+ prio = 3;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ prio = 2;
+ break;
+ case NL80211_IFTYPE_STATION:
+ prio = 1;
+ break;
+ default:
+ WARN_ONCE(true, "viftype %d sta_id %d", viftype, sta->sta_id);
+ prio = -1;
+ }
+
+ return prio;
+}
+
+/* Returns >0 if sta1 has a higher BFER priority compared to sta2 */
+static int rs_bfer_priority_cmp(struct iwl_mvm_sta *sta1,
+ struct iwl_mvm_sta *sta2)
+{
+ int prio1 = rs_bfer_priority(sta1);
+ int prio2 = rs_bfer_priority(sta2);
+
+ if (prio1 > prio2)
+ return 1;
+ if (prio1 < prio2)
+ return -1;
+ return 0;
+}
+
+static void rs_set_lq_ss_params(struct iwl_mvm *mvm,
+ struct ieee80211_sta *sta,
+ struct iwl_lq_sta *lq_sta,
+ const struct rs_rate *initial_rate)
+{
+ struct iwl_lq_cmd *lq_cmd = &lq_sta->lq;
+ struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ struct rs_bfer_active_iter_data data = {
+ .exclude_sta = sta,
+ .bfer_mvmsta = NULL,
+ };
+ struct iwl_mvm_sta *bfer_mvmsta = NULL;
+ u32 ss_params = LQ_SS_PARAMS_VALID;
+
+ if (!iwl_mvm_bt_coex_is_mimo_allowed(mvm, sta))
+ goto out;
+
+ /* Check if forcing the decision is configured.
+ * Note that SISO is forced by not allowing STBC or BFER
+ */
+ if (lq_sta->ss_force == RS_SS_FORCE_STBC)
+ ss_params |= (LQ_SS_STBC_1SS_ALLOWED | LQ_SS_FORCE);
+ else if (lq_sta->ss_force == RS_SS_FORCE_BFER)
+ ss_params |= (LQ_SS_BFER_ALLOWED | LQ_SS_FORCE);
+
+ if (lq_sta->ss_force != RS_SS_FORCE_NONE) {
+ IWL_DEBUG_RATE(mvm, "Forcing single stream Tx decision %d\n",
+ lq_sta->ss_force);
+ goto out;
+ }
+
+ if (lq_sta->stbc_capable)
+ ss_params |= LQ_SS_STBC_1SS_ALLOWED;
+
+ if (!lq_sta->bfer_capable)
+ goto out;
+
+ ieee80211_iterate_stations_atomic(mvm->hw,
+ rs_bfer_active_iter,
+ &data);
+ bfer_mvmsta = data.bfer_mvmsta;
+
+ /* This code is safe as it doesn't run concurrently for different
+ * stations. This is guaranteed by the fact that calls to
+ * ieee80211_tx_status wouldn't run concurrently for a single HW.
+ */
+ if (!bfer_mvmsta) {
+ IWL_DEBUG_RATE(mvm, "No sta with BFER allowed found. Allow\n");
+
+ ss_params |= LQ_SS_BFER_ALLOWED;
+ goto out;
+ }
+
+ IWL_DEBUG_RATE(mvm, "Found existing sta %d with BFER activated\n",
+ bfer_mvmsta->sta_id);
+
+ /* Disallow BFER on another STA if active and we're a higher priority */
+ if (rs_bfer_priority_cmp(mvmsta, bfer_mvmsta) > 0) {
+ struct iwl_lq_cmd *bfersta_lq_cmd = &bfer_mvmsta->lq_sta.lq;
+ u32 bfersta_ss_params = le32_to_cpu(bfersta_lq_cmd->ss_params);
+
+ bfersta_ss_params &= ~LQ_SS_BFER_ALLOWED;
+ bfersta_lq_cmd->ss_params = cpu_to_le32(bfersta_ss_params);
+ iwl_mvm_send_lq_cmd(mvm, bfersta_lq_cmd, false);
+
+ ss_params |= LQ_SS_BFER_ALLOWED;
+ IWL_DEBUG_RATE(mvm,
+ "Lower priority BFER sta found (%d). Switch BFER\n",
+ bfer_mvmsta->sta_id);
+ }
+out:
+ lq_cmd->ss_params = cpu_to_le32(ss_params);
+}
+
static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
struct ieee80211_sta *sta,
struct iwl_lq_sta *lq_sta,
@@ -2971,9 +3124,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
struct iwl_mvm_sta *mvmsta;
struct iwl_mvm_vif *mvmvif;
- lq_cmd->agg_disable_start_th = LINK_QUAL_AGG_DISABLE_START_DEF;
+ lq_cmd->agg_disable_start_th = IWL_MVM_RS_AGG_DISABLE_START;
lq_cmd->agg_time_limit =
- cpu_to_le16(LINK_QUAL_AGG_TIME_LIMIT_DEF);
+ cpu_to_le16(IWL_MVM_RS_AGG_TIME_LIMIT);
#ifdef CONFIG_MAC80211_DEBUGFS
if (lq_sta->pers.dbg_fixed_rate) {
@@ -2988,6 +3141,9 @@ static void rs_fill_lq_cmd(struct iwl_mvm *mvm,
rs_build_rates_table(mvm, sta, lq_sta, initial_rate);
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_LQ_SS_PARAMS)
+ rs_set_lq_ss_params(mvm, sta, lq_sta, initial_rate);
+
if (num_of_ant(initial_rate->ant) == 1)
lq_cmd->single_stream_ant_msk = initial_rate->ant;
@@ -3167,9 +3323,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
desc += sprintf(buff+desc, "fixed rate 0x%X\n",
lq_sta->pers.dbg_fixed_rate);
desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
- (mvm->fw->valid_tx_ant & ANT_A) ? "ANT_A," : "",
- (mvm->fw->valid_tx_ant & ANT_B) ? "ANT_B," : "",
- (mvm->fw->valid_tx_ant & ANT_C) ? "ANT_C" : "");
+ (iwl_mvm_get_valid_tx_ant(mvm) & ANT_A) ? "ANT_A," : "",
+ (iwl_mvm_get_valid_tx_ant(mvm) & ANT_B) ? "ANT_B," : "",
+ (iwl_mvm_get_valid_tx_ant(mvm) & ANT_C) ? "ANT_C" : "");
desc += sprintf(buff+desc, "lq type %s\n",
(is_legacy(rate)) ? "legacy" :
is_vht(rate) ? "VHT" : "HT");
@@ -3361,9 +3517,73 @@ static const struct file_operations rs_sta_dbgfs_drv_tx_stats_ops = {
.llseek = default_llseek,
};
+static ssize_t iwl_dbgfs_ss_force_read(struct file *file,
+ char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_lq_sta *lq_sta = file->private_data;
+ char buf[12];
+ int bufsz = sizeof(buf);
+ int pos = 0;
+ static const char * const ss_force_name[] = {
+ [RS_SS_FORCE_NONE] = "none",
+ [RS_SS_FORCE_STBC] = "stbc",
+ [RS_SS_FORCE_BFER] = "bfer",
+ [RS_SS_FORCE_SISO] = "siso",
+ };
+
+ pos += scnprintf(buf+pos, bufsz-pos, "%s\n",
+ ss_force_name[lq_sta->ss_force]);
+ return simple_read_from_buffer(user_buf, count, ppos, buf, pos);
+}
+
+static ssize_t iwl_dbgfs_ss_force_write(struct iwl_lq_sta *lq_sta, char *buf,
+ size_t count, loff_t *ppos)
+{
+ struct iwl_mvm *mvm = lq_sta->pers.drv;
+ int ret = 0;
+
+ if (!strncmp("none", buf, 4)) {
+ lq_sta->ss_force = RS_SS_FORCE_NONE;
+ } else if (!strncmp("siso", buf, 4)) {
+ lq_sta->ss_force = RS_SS_FORCE_SISO;
+ } else if (!strncmp("stbc", buf, 4)) {
+ if (lq_sta->stbc_capable) {
+ lq_sta->ss_force = RS_SS_FORCE_STBC;
+ } else {
+ IWL_ERR(mvm,
+ "can't force STBC. peer doesn't support\n");
+ ret = -EINVAL;
+ }
+ } else if (!strncmp("bfer", buf, 4)) {
+ if (lq_sta->bfer_capable) {
+ lq_sta->ss_force = RS_SS_FORCE_BFER;
+ } else {
+ IWL_ERR(mvm,
+ "can't force BFER. peer doesn't support\n");
+ ret = -EINVAL;
+ }
+ } else {
+ IWL_ERR(mvm, "valid values none|siso|stbc|bfer\n");
+ ret = -EINVAL;
+ }
+ return ret ?: count;
+}
+
+#define MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz) \
+ _MVM_DEBUGFS_READ_WRITE_FILE_OPS(name, bufsz, struct iwl_lq_sta)
+#define MVM_DEBUGFS_ADD_FILE_RS(name, parent, mode) do { \
+ if (!debugfs_create_file(#name, mode, parent, lq_sta, \
+ &iwl_dbgfs_##name##_ops)) \
+ goto err; \
+ } while (0)
+
+MVM_DEBUGFS_READ_WRITE_FILE_OPS(ss_force, 32);
+
static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
{
struct iwl_lq_sta *lq_sta = mvm_sta;
+
debugfs_create_file("rate_scale_table", S_IRUSR | S_IWUSR, dir,
lq_sta, &rs_sta_dbgfs_scale_table_ops);
debugfs_create_file("rate_stats_table", S_IRUSR, dir,
@@ -3374,6 +3594,11 @@ static void rs_add_debugfs(void *mvm, void *mvm_sta, struct dentry *dir)
&lq_sta->tx_agg_tid_en);
debugfs_create_u8("reduced_tpc", S_IRUSR | S_IWUSR, dir,
&lq_sta->pers.dbg_fixed_txp_reduction);
+
+ MVM_DEBUGFS_ADD_FILE_RS(ss_force, dir, S_IRUSR | S_IWUSR);
+ return;
+err:
+ IWL_ERR((struct iwl_mvm *)mvm, "Can't create debugfs entity\n");
}
static void rs_remove_debugfs(void *mvm, void *mvm_sta)
diff --git a/drivers/net/wireless/iwlwifi/mvm/rs.h b/drivers/net/wireless/iwlwifi/mvm/rs.h
index defd70a6d9e6..dc4ef3dfafe1 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rs.h
+++ b/drivers/net/wireless/iwlwifi/mvm/rs.h
@@ -137,42 +137,10 @@ enum {
#define IWL_INVALID_VALUE -1
-#define IWL_MIN_RSSI_VAL -100
-#define IWL_MAX_RSSI_VAL 0
-
-/* These values specify how many Tx frame attempts before
- * searching for a new modulation mode */
-#define IWL_LEGACY_FAILURE_LIMIT 160
-#define IWL_LEGACY_SUCCESS_LIMIT 480
-#define IWL_LEGACY_TABLE_COUNT 160
-
-#define IWL_NONE_LEGACY_FAILURE_LIMIT 400
-#define IWL_NONE_LEGACY_SUCCESS_LIMIT 4500
-#define IWL_NONE_LEGACY_TABLE_COUNT 1500
-
-/* Success ratio (ACKed / attempted tx frames) values (perfect is 128 * 100) */
-#define IWL_RS_GOOD_RATIO 12800 /* 100% */
-#define IWL_RATE_SCALE_SWITCH 10880 /* 85% */
-#define IWL_RATE_HIGH_TH 10880 /* 85% */
-#define IWL_RATE_INCREASE_TH 6400 /* 50% */
-#define RS_SR_FORCE_DECREASE 1920 /* 15% */
-#define RS_SR_NO_DECREASE 10880 /* 85% */
-
-#define TPC_SR_FORCE_INCREASE 9600 /* 75% */
-#define TPC_SR_NO_INCREASE 10880 /* 85% */
-#define TPC_TX_POWER_STEP 3
#define TPC_MAX_REDUCTION 15
#define TPC_NO_REDUCTION 0
#define TPC_INVALID 0xff
-#define LINK_QUAL_AGG_TIME_LIMIT_DEF (4000) /* 4 milliseconds */
-#define LINK_QUAL_AGG_TIME_LIMIT_MAX (8000)
-#define LINK_QUAL_AGG_TIME_LIMIT_MIN (100)
-
-#define LINK_QUAL_AGG_DISABLE_START_DEF (3)
-#define LINK_QUAL_AGG_DISABLE_START_MAX (255)
-#define LINK_QUAL_AGG_DISABLE_START_MIN (0)
-
#define LINK_QUAL_AGG_FRAME_LIMIT_DEF (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MAX (63)
#define LINK_QUAL_AGG_FRAME_LIMIT_MIN (0)
@@ -181,14 +149,7 @@ enum {
/* load per tid defines for A-MPDU activation */
#define IWL_AGG_TPT_THREHOLD 0
-#define IWL_AGG_LOAD_THRESHOLD 10
#define IWL_AGG_ALL_TID 0xff
-#define TID_QUEUE_CELL_SPACING 50 /*mS */
-#define TID_QUEUE_MAX_SIZE 20
-#define TID_ROUND_VALUE 5 /* mS */
-
-#define TID_MAX_TIME_DIFF ((TID_QUEUE_MAX_SIZE - 1) * TID_QUEUE_CELL_SPACING)
-#define TIME_WRAP_AROUND(x, y) (((y) > (x)) ? (y) - (x) : (0-(x)) + (y))
enum iwl_table_type {
LQ_NONE,
@@ -279,6 +240,13 @@ enum rs_column {
RS_COLUMN_INVALID,
};
+enum rs_ss_force_opt {
+ RS_SS_FORCE_NONE = 0,
+ RS_SS_FORCE_STBC,
+ RS_SS_FORCE_BFER,
+ RS_SS_FORCE_SISO,
+};
+
/* Packet stats per rate */
struct rs_rate_stats {
u64 success;
@@ -332,7 +300,9 @@ struct iwl_lq_sta {
u64 last_tx;
bool is_vht;
bool ldpc; /* LDPC Rx is supported by the STA */
- bool stbc; /* Tx STBC is supported by chip and Rx by STA */
+ bool stbc_capable; /* Tx STBC is supported by chip and Rx by STA */
+ bool bfer_capable; /* Remote supports beamformee and we BFer */
+
enum ieee80211_band band;
/* The following are bitmaps of rates; IWL_RATE_6M_MASK, etc. */
@@ -361,6 +331,9 @@ struct iwl_lq_sta {
/* tx power reduce for this sta */
int tpc_reduce;
+ /* force STBC/BFER/SISO for testing */
+ enum rs_ss_force_opt ss_force;
+
/* persistent fields - initialized only once - keep last! */
struct lq_sta_pers {
#ifdef CONFIG_MAC80211_DEBUGFS
diff --git a/drivers/net/wireless/iwlwifi/mvm/rx.c b/drivers/net/wireless/iwlwifi/mvm/rx.c
index 94b6e7297a1e..f922131b4eab 100644
--- a/drivers/net/wireless/iwlwifi/mvm/rx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/rx.c
@@ -407,7 +407,7 @@ int iwl_mvm_rx_rx_mpdu(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
}
#ifdef CONFIG_IWLWIFI_DEBUGFS
- iwl_mvm_update_frame_stats(mvm, &mvm->drv_rx_stats, rate_n_flags,
+ iwl_mvm_update_frame_stats(mvm, rate_n_flags,
rx_status->flag & RX_FLAG_AMPDU_DETAILS);
#endif
iwl_mvm_pass_packet_to_mac80211(mvm, skb, hdr, len, ampdu_status,
@@ -511,13 +511,17 @@ int iwl_mvm_rx_statistics(struct iwl_mvm *mvm,
{
struct iwl_rx_packet *pkt = rxb_addr(rxb);
struct iwl_notif_statistics *stats = (void *)&pkt->data;
- struct mvm_statistics_general_common *common = &stats->general.common;
struct iwl_mvm_stat_data data = {
.stats = stats,
.mvm = mvm,
};
- iwl_mvm_tt_temp_changed(mvm, le32_to_cpu(common->temperature));
+ /* Only handle rx statistics temperature changes if async temp
+ * notifications are not supported
+ */
+ if (!(mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_ASYNC_DTM))
+ iwl_mvm_tt_temp_changed(mvm,
+ le32_to_cpu(stats->general.radio_temperature));
iwl_mvm_update_rx_statistics(mvm, stats);
diff --git a/drivers/net/wireless/iwlwifi/mvm/scan.c b/drivers/net/wireless/iwlwifi/mvm/scan.c
index 844bf7c4c8de..7e9aa3cb3254 100644
--- a/drivers/net/wireless/iwlwifi/mvm/scan.c
+++ b/drivers/net/wireless/iwlwifi/mvm/scan.c
@@ -99,7 +99,7 @@ static u8 iwl_mvm_scan_rx_ant(struct iwl_mvm *mvm)
{
if (mvm->scan_rx_ant != ANT_NONE)
return mvm->scan_rx_ant;
- return mvm->fw->valid_rx_ant;
+ return iwl_mvm_get_valid_rx_ant(mvm);
}
static inline __le16 iwl_mvm_scan_rx_chain(struct iwl_mvm *mvm)
@@ -130,7 +130,7 @@ iwl_mvm_scan_rate_n_flags(struct iwl_mvm *mvm, enum ieee80211_band band,
u32 tx_ant;
mvm->scan_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
mvm->scan_last_antenna_idx);
tx_ant = BIT(mvm->scan_last_antenna_idx) << RATE_MCS_ANT_POS;
@@ -290,11 +290,11 @@ static void iwl_mvm_scan_condition_iterator(void *data, u8 *mac,
struct ieee80211_vif *vif)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- bool *global_bound = data;
+ int *global_cnt = data;
if (vif->type != NL80211_IFTYPE_P2P_DEVICE && mvmvif->phy_ctxt &&
mvmvif->phy_ctxt->id < MAX_PHYS)
- *global_bound = true;
+ *global_cnt += 1;
}
static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
@@ -302,27 +302,31 @@ static void iwl_mvm_scan_calc_params(struct iwl_mvm *mvm,
int n_ssids, u32 flags,
struct iwl_mvm_scan_params *params)
{
- bool global_bound = false;
+ int global_cnt = 0;
enum ieee80211_band band;
u8 frag_passive_dwell = 0;
ieee80211_iterate_active_interfaces_atomic(mvm->hw,
IEEE80211_IFACE_ITER_NORMAL,
iwl_mvm_scan_condition_iterator,
- &global_bound);
+ &global_cnt);
- if (!global_bound)
+ if (!global_cnt)
goto not_bound;
params->suspend_time = 30;
- params->max_out_time = 170;
+ params->max_out_time = 120;
if (iwl_mvm_low_latency(mvm)) {
if (mvm->fw->ucode_capa.api[0] &
IWL_UCODE_TLV_API_FRAGMENTED_SCAN) {
params->suspend_time = 105;
- params->max_out_time = 70;
- frag_passive_dwell = 20;
+ /*
+ * If there is more than one active interface make
+ * passive scan more fragmented.
+ */
+ frag_passive_dwell = (global_cnt < 2) ? 40 : 20;
+ params->max_out_time = frag_passive_dwell;
} else {
params->suspend_time = 120;
params->max_out_time = 120;
@@ -539,6 +543,19 @@ int iwl_mvm_rx_scan_response(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
return 0;
}
+int iwl_mvm_rx_scan_offload_iter_complete_notif(struct iwl_mvm *mvm,
+ struct iwl_rx_cmd_buffer *rxb,
+ struct iwl_device_cmd *cmd)
+{
+ struct iwl_rx_packet *pkt = rxb_addr(rxb);
+ struct iwl_scan_complete_notif *notif = (void *)pkt->data;
+
+ IWL_DEBUG_SCAN(mvm,
+ "Scan offload iteration complete: status=0x%x scanned channels=%d\n",
+ notif->status, notif->scanned_channels);
+ return 0;
+}
+
int iwl_mvm_rx_scan_complete(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
struct iwl_device_cmd *cmd)
{
@@ -687,7 +704,8 @@ int iwl_mvm_rx_scan_offload_complete_notif(struct iwl_mvm *mvm,
iwl_mvm_unref(mvm, IWL_MVM_REF_SCAN);
}
- mvm->last_ebs_successful = !ebs_status;
+ if (ebs_status)
+ mvm->last_ebs_successful = false;
return 0;
}
@@ -1480,6 +1498,11 @@ int iwl_mvm_unified_sched_scan_lmac(struct iwl_mvm *mvm,
if (req->n_ssids == 0)
flags |= IWL_MVM_LMAC_SCAN_FLAG_PASSIVE;
+#ifdef CONFIG_IWLWIFI_DEBUGFS
+ if (mvm->scan_iter_notif_enabled)
+ flags |= IWL_MVM_LMAC_SCAN_FLAG_ITER_COMPLETE;
+#endif
+
cmd->scan_flags |= cpu_to_le32(flags);
cmd->flags = iwl_mvm_scan_rxon_flags(req->channels[0]->band);
@@ -1641,7 +1664,7 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
SCAN_CONFIG_FLAG_SET_MAC_ADDR |
SCAN_CONFIG_FLAG_SET_CHANNEL_FLAGS|
SCAN_CONFIG_N_CHANNELS(num_channels));
- scan_config->tx_chains = cpu_to_le32(mvm->fw->valid_tx_ant);
+ scan_config->tx_chains = cpu_to_le32(iwl_mvm_get_valid_tx_ant(mvm));
scan_config->rx_chains = cpu_to_le32(iwl_mvm_scan_rx_ant(mvm));
scan_config->legacy_rates = iwl_mvm_scan_config_rates(mvm);
scan_config->out_of_channel_time = cpu_to_le32(170);
@@ -1660,10 +1683,10 @@ int iwl_mvm_config_scan(struct iwl_mvm *mvm)
band = &mvm->nvm_data->bands[IEEE80211_BAND_2GHZ];
for (i = 0; i < band->n_channels; i++, j++)
- scan_config->channel_array[j] = band->channels[i].center_freq;
+ scan_config->channel_array[j] = band->channels[i].hw_value;
band = &mvm->nvm_data->bands[IEEE80211_BAND_5GHZ];
for (i = 0; i < band->n_channels; i++, j++)
- scan_config->channel_array[j] = band->channels[i].center_freq;
+ scan_config->channel_array[j] = band->channels[i].hw_value;
cmd.data[0] = scan_config;
cmd.len[0] = cmd_size;
@@ -1840,6 +1863,13 @@ int iwl_mvm_scan_umac(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
flags |= IWL_UMAC_SCAN_GEN_FLAGS_PASS_ALL;
cmd->general_flags = cpu_to_le32(flags);
+
+ if (mvm->fw->ucode_capa.api[0] & IWL_UCODE_TLV_API_SINGLE_SCAN_EBS &&
+ mvm->last_ebs_successful)
+ cmd->channel_flags = IWL_SCAN_CHANNEL_FLAG_EBS |
+ IWL_SCAN_CHANNEL_FLAG_EBS_ACCURATE |
+ IWL_SCAN_CHANNEL_FLAG_CACHE_ADD;
+
cmd->n_channels = req->req.n_channels;
for (i = 0; i < req->req.n_ssids; i++)
@@ -2003,7 +2033,9 @@ int iwl_mvm_rx_umac_scan_complete_notif(struct iwl_mvm *mvm,
notif->ebs_status == IWL_SCAN_EBS_SUCCESS ?
"success" : "failed");
- mvm->last_ebs_successful = !notif->ebs_status;
+ if (notif->ebs_status)
+ mvm->last_ebs_successful = false;
+
mvm->scan_uid[uid_idx] = 0;
if (!sched) {
@@ -2036,10 +2068,14 @@ static bool iwl_scan_umac_done_check(struct iwl_notif_wait_data *notif_wait,
/*
* Clear scan uid of scans that was aborted from above and completed
- * in FW so the RX handler does nothing.
+ * in FW so the RX handler does nothing. Set last_ebs_successful here if
+ * needed.
*/
scan_done->mvm->scan_uid[uid_idx] = 0;
+ if (notif->ebs_status)
+ scan_done->mvm->last_ebs_successful = false;
+
return !iwl_mvm_find_scan_type(scan_done->mvm, scan_done->type);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/sta.c b/drivers/net/wireless/iwlwifi/mvm/sta.c
index d86fe432e51f..5c23cddaaae3 100644
--- a/drivers/net/wireless/iwlwifi/mvm/sta.c
+++ b/drivers/net/wireless/iwlwifi/mvm/sta.c
@@ -99,7 +99,7 @@ static int iwl_mvm_find_free_sta_id(struct iwl_mvm *mvm,
int iwl_mvm_sta_send_to_fw(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
bool update)
{
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_add_sta_cmd add_sta_cmd = {
.sta_id = mvm_sta->sta_id,
.mac_id_n_color = cpu_to_le32(mvm_sta->mac_id_n_color),
@@ -209,6 +209,9 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
{
unsigned long used_hw_queues;
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
u32 ac;
lockdep_assert_held(&mvm->mutex);
@@ -232,7 +235,7 @@ static int iwl_mvm_tdls_sta_init(struct iwl_mvm *mvm,
/* Found a place for all queues - enable them */
for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
iwl_mvm_enable_ac_txq(mvm, mvmsta->hw_queue[ac],
- iwl_mvm_ac_to_tx_fifo[ac]);
+ iwl_mvm_ac_to_tx_fifo[ac], wdg_timeout);
mvmsta->tfd_queue_msk |= BIT(mvmsta->hw_queue[ac]);
}
@@ -250,8 +253,8 @@ static void iwl_mvm_tdls_sta_deinit(struct iwl_mvm *mvm,
/* disable the TDLS STA-specific queues */
sta_msk = mvmsta->tfd_queue_msk;
- for_each_set_bit(i, &sta_msk, sizeof(sta_msk))
- iwl_mvm_disable_txq(mvm, i);
+ for_each_set_bit(i, &sta_msk, sizeof(sta_msk) * BITS_PER_BYTE)
+ iwl_mvm_disable_txq(mvm, i, 0);
}
int iwl_mvm_add_sta(struct iwl_mvm *mvm,
@@ -259,7 +262,7 @@ int iwl_mvm_add_sta(struct iwl_mvm *mvm,
struct ieee80211_sta *sta)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
int i, ret, sta_id;
lockdep_assert_held(&mvm->mutex);
@@ -464,8 +467,8 @@ void iwl_mvm_sta_drained_wk(struct work_struct *wk)
if (mvm->tfd_drained[sta_id]) {
unsigned long i, msk = mvm->tfd_drained[sta_id];
- for_each_set_bit(i, &msk, sizeof(msk))
- iwl_mvm_disable_txq(mvm, i);
+ for_each_set_bit(i, &msk, sizeof(msk) * BITS_PER_BYTE)
+ iwl_mvm_disable_txq(mvm, i, 0);
mvm->tfd_drained[sta_id] = 0;
IWL_DEBUG_TDLS(mvm, "Drained sta %d, with queues %ld\n",
@@ -481,7 +484,7 @@ int iwl_mvm_rm_sta(struct iwl_mvm *mvm,
struct ieee80211_sta *sta)
{
struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
int ret;
lockdep_assert_held(&mvm->mutex);
@@ -626,13 +629,16 @@ static int iwl_mvm_add_int_sta_common(struct iwl_mvm *mvm,
int iwl_mvm_add_aux_sta(struct iwl_mvm *mvm)
{
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
int ret;
lockdep_assert_held(&mvm->mutex);
/* Map Aux queue to fifo - needs to happen before adding Aux station */
iwl_mvm_enable_ac_txq(mvm, mvm->aux_queue,
- IWL_MVM_TX_FIFO_MCAST);
+ IWL_MVM_TX_FIFO_MCAST, wdg_timeout);
/* Allocate aux station and assign to it the aux queue */
ret = iwl_mvm_allocate_int_sta(mvm, &mvm->aux_sta, BIT(mvm->aux_queue),
@@ -774,7 +780,7 @@ int iwl_mvm_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int tid, u16 ssn, bool start)
{
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_add_sta_cmd cmd = {};
int ret;
u32 status;
@@ -834,7 +840,7 @@ int iwl_mvm_sta_rx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
static int iwl_mvm_sta_tx_agg(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
int tid, u8 queue, bool start)
{
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_add_sta_cmd cmd = {};
int ret;
u32 status;
@@ -965,6 +971,9 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
{
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
struct iwl_mvm_tid_data *tid_data = &mvmsta->tid_data[tid];
+ unsigned int wdg_timeout = iwlmvm_mod_params.tfd_q_hang_detect ?
+ mvm->cfg->base_params->wd_timeout :
+ IWL_WATCHDOG_DISABLED;
int queue, fifo, ret;
u16 ssn;
@@ -988,7 +997,7 @@ int iwl_mvm_sta_tx_agg_oper(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
return -EIO;
iwl_mvm_enable_agg_txq(mvm, queue, fifo, mvmsta->sta_id, tid,
- buf_size, ssn);
+ buf_size, ssn, wdg_timeout);
/*
* Even though in theory the peer could have different
@@ -1058,7 +1067,7 @@ int iwl_mvm_sta_tx_agg_stop(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
- iwl_mvm_disable_txq(mvm, txq_id);
+ iwl_mvm_disable_txq(mvm, txq_id, 0);
return 0;
case IWL_AGG_STARTING:
case IWL_EMPTYING_HW_QUEUE_ADDBA:
@@ -1116,7 +1125,7 @@ int iwl_mvm_sta_tx_agg_flush(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
iwl_mvm_sta_tx_agg(mvm, sta, tid, txq_id, false);
- iwl_mvm_disable_txq(mvm, tid_data->txq_id);
+ iwl_mvm_disable_txq(mvm, tid_data->txq_id, 0);
}
mvm->queue_to_mac80211[tid_data->txq_id] =
@@ -1144,10 +1153,10 @@ static int iwl_mvm_set_fw_key_idx(struct iwl_mvm *mvm)
static u8 iwl_mvm_get_key_sta_id(struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (sta) {
- struct iwl_mvm_sta *mvm_sta = (void *)sta->drv_priv;
+ struct iwl_mvm_sta *mvm_sta = iwl_mvm_sta_from_mac80211(sta);
return mvm_sta->sta_id;
}
@@ -1196,6 +1205,7 @@ static int iwl_mvm_send_sta_key(struct iwl_mvm *mvm,
break;
case WLAN_CIPHER_SUITE_WEP104:
key_flags |= cpu_to_le16(STA_KEY_FLG_WEP_13BYTES);
+ /* fall through */
case WLAN_CIPHER_SUITE_WEP40:
key_flags |= cpu_to_le16(STA_KEY_FLG_WEP);
memcpy(cmd.key + 3, keyconf->key, keyconf->keylen);
@@ -1280,7 +1290,7 @@ static inline u8 *iwl_mvm_get_mac_addr(struct iwl_mvm *mvm,
struct ieee80211_vif *vif,
struct ieee80211_sta *sta)
{
- struct iwl_mvm_vif *mvmvif = (void *)vif->drv_priv;
+ struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
if (sta)
return sta->addr;
diff --git a/drivers/net/wireless/iwlwifi/mvm/tdls.c b/drivers/net/wireless/iwlwifi/mvm/tdls.c
index c0e00bae5bd0..a87b506c8c72 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tdls.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tdls.c
@@ -64,6 +64,8 @@
#include <linux/etherdevice.h>
#include "mvm.h"
#include "time-event.h"
+#include "iwl-io.h"
+#include "iwl-prph.h"
#define TU_TO_US(x) (x * 1024)
#define TU_TO_MS(x) (TU_TO_US(x) / 1000)
@@ -228,6 +230,8 @@ iwl_mvm_tdls_cs_state_str(enum iwl_mvm_tdls_cs_state state)
return "IDLE";
case IWL_MVM_TDLS_SW_REQ_SENT:
return "REQ SENT";
+ case IWL_MVM_TDLS_SW_RESP_RCVD:
+ return "RESP RECEIVED";
case IWL_MVM_TDLS_SW_REQ_RCVD:
return "REQ RECEIVED";
case IWL_MVM_TDLS_SW_ACTIVE:
@@ -248,6 +252,11 @@ static void iwl_mvm_tdls_update_cs_state(struct iwl_mvm *mvm,
iwl_mvm_tdls_cs_state_str(state));
mvm->tdls_cs.state = state;
+ /* we only send requests to our switching peer - update sent time */
+ if (state == IWL_MVM_TDLS_SW_REQ_SENT)
+ mvm->tdls_cs.peer.sent_timestamp =
+ iwl_read_prph(mvm->trans, DEVICE_SYSTEM_TIME_REG);
+
if (state == IWL_MVM_TDLS_SW_IDLE)
mvm->tdls_cs.cur_sta_id = IWL_MVM_STATION_COUNT;
}
@@ -300,7 +309,7 @@ out:
static int
iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
enum iwl_tdls_channel_switch_type type,
- const u8 *peer, bool peer_initiator)
+ const u8 *peer, bool peer_initiator, u32 timestamp)
{
bool same_peer = false;
int ret = 0;
@@ -325,17 +334,30 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
ret = -EINVAL;
break;
case IWL_MVM_TDLS_SW_REQ_SENT:
+ /* only allow requests from the same peer */
+ if (!same_peer)
+ ret = -EBUSY;
+ else if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH &&
+ !peer_initiator)
+ /*
+ * We received a ch-switch request while an outgoing
+ * one is pending. Allow it if the peer is the link
+ * initiator.
+ */
+ ret = -EBUSY;
+ else if (type == TDLS_SEND_CHAN_SW_REQ)
+ /* wait for idle before sending another request */
+ ret = -EBUSY;
+ else if (timestamp <= mvm->tdls_cs.peer.sent_timestamp)
+ /* we got a stale response - ignore it */
+ ret = -EINVAL;
+ break;
+ case IWL_MVM_TDLS_SW_RESP_RCVD:
/*
- * We received a ch-switch request while an outgoing one is
- * pending. Allow it to proceed if the other peer is the same
- * one we sent to, and we are not the link initiator.
+ * we are waiting for the FW to give an "active" notification,
+ * so ignore requests in the meantime
*/
- if (type == TDLS_SEND_CHAN_SW_RESP_AND_MOVE_CH) {
- if (!same_peer)
- ret = -EBUSY;
- else if (!peer_initiator) /* we are the initiator */
- ret = -EBUSY;
- }
+ ret = -EBUSY;
break;
case IWL_MVM_TDLS_SW_REQ_RCVD:
/* as above, allow the link initiator to proceed */
@@ -349,9 +371,12 @@ iwl_mvm_tdls_check_action(struct iwl_mvm *mvm,
}
break;
case IWL_MVM_TDLS_SW_ACTIVE:
- /* we don't allow initiations during active channel switch */
- if (type == TDLS_SEND_CHAN_SW_REQ)
- ret = -EINVAL;
+ /*
+ * the only valid request when active is a request to return
+ * to the base channel by the current off-channel peer
+ */
+ if (type != TDLS_MOVE_CH || !same_peer)
+ ret = -EBUSY;
break;
}
@@ -384,7 +409,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
lockdep_assert_held(&mvm->mutex);
- ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator);
+ ret = iwl_mvm_tdls_check_action(mvm, type, peer, peer_initiator,
+ timestamp);
if (ret)
return ret;
@@ -473,6 +499,8 @@ iwl_mvm_tdls_config_channel_switch(struct iwl_mvm *mvm,
type == TDLS_SEND_CHAN_SW_REQ ?
IWL_MVM_TDLS_SW_REQ_SENT :
IWL_MVM_TDLS_SW_REQ_RCVD);
+ } else {
+ iwl_mvm_tdls_update_cs_state(mvm, IWL_MVM_TDLS_SW_RESP_RCVD);
}
out:
@@ -657,12 +685,15 @@ iwl_mvm_tdls_recv_channel_switch(struct ieee80211_hw *hw,
struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
enum iwl_tdls_channel_switch_type type;
unsigned int delay;
+ const char *action_str =
+ params->action_code == WLAN_TDLS_CHANNEL_SWITCH_REQUEST ?
+ "REQ" : "RESP";
mutex_lock(&mvm->mutex);
IWL_DEBUG_TDLS(mvm,
- "Received TDLS ch switch action %d from %pM status %d\n",
- params->action_code, params->sta->addr, params->status);
+ "Received TDLS ch switch action %s from %pM status %d\n",
+ action_str, params->sta->addr, params->status);
/*
* we got a non-zero status from a peer we were switching to - move to
diff --git a/drivers/net/wireless/iwlwifi/mvm/tt.c b/drivers/net/wireless/iwlwifi/mvm/tt.c
index 2b1e61fac34a..ba615ad2176c 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tt.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tt.c
@@ -69,6 +69,7 @@
static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
{
+ struct iwl_mvm_tt_mgmt *tt = &mvm->thermal_throttle;
u32 duration = mvm->thermal_throttle.params->ct_kill_duration;
if (test_bit(IWL_MVM_STATUS_HW_CTKILL, &mvm->status))
@@ -77,12 +78,15 @@ static void iwl_mvm_enter_ctkill(struct iwl_mvm *mvm)
IWL_ERR(mvm, "Enter CT Kill\n");
iwl_mvm_set_hw_ctkill_state(mvm, true);
+ tt->throttle = false;
+ tt->dynamic_smps = false;
+
/* Don't schedule an exit work if we're in test mode, since
* the temperature will not change unless we manually set it
* again (or disable testing).
*/
if (!mvm->temperature_test)
- schedule_delayed_work(&mvm->thermal_throttle.ct_kill_exit,
+ schedule_delayed_work(&tt->ct_kill_exit,
round_jiffies_relative(duration * HZ));
}
@@ -452,6 +456,7 @@ void iwl_mvm_tt_initialize(struct iwl_mvm *mvm, u32 min_backoff)
tt->params = &iwl7000_tt_params;
tt->throttle = false;
+ tt->dynamic_smps = false;
tt->min_backoff = min_backoff;
INIT_DELAYED_WORK(&tt->ct_kill_exit, check_exit_ctkill);
}
diff --git a/drivers/net/wireless/iwlwifi/mvm/tx.c b/drivers/net/wireless/iwlwifi/mvm/tx.c
index c59d07567d90..07304e1fd64a 100644
--- a/drivers/net/wireless/iwlwifi/mvm/tx.c
+++ b/drivers/net/wireless/iwlwifi/mvm/tx.c
@@ -220,7 +220,7 @@ void iwl_mvm_set_tx_cmd_rate(struct iwl_mvm *mvm, struct iwl_tx_cmd *tx_cmd,
rate_plcp = iwl_mvm_mac80211_idx_to_hwrate(rate_idx);
mvm->mgmt_last_antenna_idx =
- iwl_mvm_next_antenna(mvm, mvm->fw->valid_tx_ant,
+ iwl_mvm_next_antenna(mvm, iwl_mvm_get_valid_tx_ant(mvm),
mvm->mgmt_last_antenna_idx);
if (info->band == IEEE80211_BAND_2GHZ &&
@@ -507,7 +507,7 @@ static void iwl_mvm_check_ratid_empty(struct iwl_mvm *mvm,
IWL_DEBUG_TX_QUEUES(mvm,
"Can continue DELBA flow ssn = next_recl = %d\n",
tid_data->next_reclaimed);
- iwl_mvm_disable_txq(mvm, tid_data->txq_id);
+ iwl_mvm_disable_txq(mvm, tid_data->txq_id, CMD_ASYNC);
tid_data->state = IWL_AGG_OFF;
/*
* we can't hold the mutex - but since we are after a sequence
@@ -667,7 +667,8 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
/* Single frame failure in an AMPDU queue => send BAR */
if (txq_id >= mvm->first_agg_queue &&
- !(info->flags & IEEE80211_TX_STAT_ACK))
+ !(info->flags & IEEE80211_TX_STAT_ACK) &&
+ !(info->flags & IEEE80211_TX_STAT_TX_FILTERED))
info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
/* W/A FW bug: seq_ctl is wrong when the status isn't success */
@@ -930,6 +931,11 @@ int iwl_mvm_rx_ba_notif(struct iwl_mvm *mvm, struct iwl_rx_cmd_buffer *rxb,
sta_id = ba_notif->sta_id;
tid = ba_notif->tid;
+ if (WARN_ONCE(sta_id >= IWL_MVM_STATION_COUNT ||
+ tid >= IWL_MAX_TID_COUNT,
+ "sta_id %d tid %d", sta_id, tid))
+ return 0;
+
rcu_read_lock();
sta = rcu_dereference(mvm->fw_id_to_mac_id[sta_id]);
diff --git a/drivers/net/wireless/iwlwifi/mvm/utils.c b/drivers/net/wireless/iwlwifi/mvm/utils.c
index 917431e30f74..8decf9953229 100644
--- a/drivers/net/wireless/iwlwifi/mvm/utils.c
+++ b/drivers/net/wireless/iwlwifi/mvm/utils.c
@@ -432,7 +432,7 @@ static void iwl_mvm_dump_umac_error_log(struct iwl_mvm *mvm)
mvm->status, table.valid);
}
- IWL_ERR(mvm, "0x%08X | %-28s\n", table.error_id,
+ IWL_ERR(mvm, "0x%08X | %s\n", table.error_id,
desc_lookup(table.error_id));
IWL_ERR(mvm, "0x%08X | umac branchlink1\n", table.blink1);
IWL_ERR(mvm, "0x%08X | umac branchlink2\n", table.blink2);
@@ -531,49 +531,50 @@ void iwl_mvm_dump_nic_error_log(struct iwl_mvm *mvm)
}
void iwl_mvm_enable_txq(struct iwl_mvm *mvm, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg)
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout)
{
- if (iwl_mvm_is_dqa_supported(mvm)) {
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .enable = 1,
- .window = cfg->frame_limit,
- .sta_id = cfg->sta_id,
- .ssn = cpu_to_le16(ssn),
- .tx_fifo = cfg->fifo,
- .aggregate = cfg->aggregate,
- .flags = IWL_SCD_FLAGS_DQA_ENABLED,
- .tid = cfg->tid,
- .control = IWL_SCD_CONTROL_SET_SSN,
- };
- int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0,
- sizeof(cmd), &cmd);
- if (ret)
- IWL_ERR(mvm,
- "Failed to configure queue %d on FIFO %d\n",
- queue, cfg->fifo);
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .enable = 1,
+ .window = cfg->frame_limit,
+ .sta_id = cfg->sta_id,
+ .ssn = cpu_to_le16(ssn),
+ .tx_fifo = cfg->fifo,
+ .aggregate = cfg->aggregate,
+ .tid = cfg->tid,
+ };
+
+ if (!iwl_mvm_is_scd_cfg_supported(mvm)) {
+ iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, cfg,
+ wdg_timeout);
+ return;
}
- iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn,
- iwl_mvm_is_dqa_supported(mvm) ? NULL : cfg);
+ iwl_trans_txq_enable_cfg(mvm->trans, queue, ssn, NULL, wdg_timeout);
+ WARN(iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, 0, sizeof(cmd), &cmd),
+ "Failed to configure queue %d on FIFO %d\n", queue, cfg->fifo);
}
-void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue)
+void iwl_mvm_disable_txq(struct iwl_mvm *mvm, int queue, u8 flags)
{
- iwl_trans_txq_disable(mvm->trans, queue,
- !iwl_mvm_is_dqa_supported(mvm));
-
- if (iwl_mvm_is_dqa_supported(mvm)) {
- struct iwl_scd_txq_cfg_cmd cmd = {
- .scd_queue = queue,
- .enable = 0,
- };
- int ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, CMD_ASYNC,
- sizeof(cmd), &cmd);
- if (ret)
- IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
- queue, ret);
+ struct iwl_scd_txq_cfg_cmd cmd = {
+ .scd_queue = queue,
+ .enable = 0,
+ };
+ int ret;
+
+ if (!iwl_mvm_is_scd_cfg_supported(mvm)) {
+ iwl_trans_txq_disable(mvm->trans, queue, true);
+ return;
}
+
+ iwl_trans_txq_disable(mvm->trans, queue, false);
+ ret = iwl_mvm_send_cmd_pdu(mvm, SCD_QUEUE_CFG, flags,
+ sizeof(cmd), &cmd);
+ if (ret)
+ IWL_ERR(mvm, "Failed to disable queue %d (ret=%d)\n",
+ queue, ret);
}
/**
@@ -620,7 +621,7 @@ void iwl_mvm_update_smps(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
lockdep_assert_held(&mvm->mutex);
/* SMPS is irrelevant for NICs that don't have at least 2 RX antenna */
- if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
+ if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
return;
if (vif->type == NL80211_IFTYPE_AP)
@@ -662,7 +663,7 @@ bool iwl_mvm_rx_diversity_allowed(struct iwl_mvm *mvm)
lockdep_assert_held(&mvm->mutex);
- if (num_of_ant(mvm->fw->valid_rx_ant) == 1)
+ if (num_of_ant(iwl_mvm_get_valid_rx_ant(mvm)) == 1)
return false;
if (mvm->cfg->rx_with_siso_diversity)
diff --git a/drivers/net/wireless/iwlwifi/pcie/drv.c b/drivers/net/wireless/iwlwifi/pcie/drv.c
index d5aadb00dd9e..dbd6bcf52205 100644
--- a/drivers/net/wireless/iwlwifi/pcie/drv.c
+++ b/drivers/net/wireless/iwlwifi/pcie/drv.c
@@ -415,6 +415,8 @@ static const struct pci_device_id iwl_hw_card_ids[] = {
{IWL_PCI_DEVICE(0x24F3, 0x0010, iwl8260_2ac_cfg)},
{IWL_PCI_DEVICE(0x24F3, 0x0004, iwl8260_2n_cfg)},
{IWL_PCI_DEVICE(0x24F4, 0x0030, iwl8260_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F5, 0x0010, iwl4165_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24F6, 0x0030, iwl4165_2ac_cfg)},
#endif /* CONFIG_IWLMVM */
{0}
diff --git a/drivers/net/wireless/iwlwifi/pcie/internal.h b/drivers/net/wireless/iwlwifi/pcie/internal.h
index 1aea6b66c594..cae0eb8835ce 100644
--- a/drivers/net/wireless/iwlwifi/pcie/internal.h
+++ b/drivers/net/wireless/iwlwifi/pcie/internal.h
@@ -216,6 +216,7 @@ struct iwl_pcie_txq_scratch_buf {
* @need_update: indicates need to update read/write index
* @active: stores if queue is active
* @ampdu: true if this queue is an ampdu queue for an specific RA/TID
+ * @wd_timeout: queue watchdog timeout (jiffies) - per queue
*
* A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
* descriptors) and required locking structures.
@@ -232,6 +233,7 @@ struct iwl_txq {
bool need_update;
u8 active;
bool ampdu;
+ unsigned long wd_timeout;
};
static inline dma_addr_t
@@ -259,7 +261,6 @@ iwl_pcie_get_scratchbuf_dma(struct iwl_txq *txq, int idx)
* @bc_table_dword: true if the BC table expects DWORD (as opposed to bytes)
* @scd_set_active: should the transport configure the SCD for HCMD queue
* @rx_page_order: page order for receive buffer size
- * @wd_timeout: queue watchdog timeout (jiffies)
* @reg_lock: protect hw register access
* @cmd_in_flight: true when we have a host command in flight
* @fw_mon_phys: physical address of the buffer for the firmware monitor
@@ -302,6 +303,7 @@ struct iwl_trans_pcie {
u8 cmd_queue;
u8 cmd_fifo;
+ unsigned int cmd_q_wdg_timeout;
u8 n_no_reclaim_cmds;
u8 no_reclaim_cmds[MAX_NO_RECLAIM_CMDS];
@@ -312,12 +314,14 @@ struct iwl_trans_pcie {
const char *const *command_names;
- /* queue watchdog */
- unsigned long wd_timeout;
-
/*protect hw register */
spinlock_t reg_lock;
bool cmd_in_flight;
+ bool ref_cmd_in_flight;
+
+ /* protect ref counter */
+ spinlock_t ref_lock;
+ u32 ref_count;
dma_addr_t fw_mon_phys;
struct page *fw_mon_page;
@@ -368,7 +372,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
int iwl_pcie_tx_stop(struct iwl_trans *trans);
void iwl_pcie_tx_free(struct iwl_trans *trans);
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int queue, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg);
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout);
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue,
bool configure_scd);
int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
@@ -381,6 +386,9 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
struct sk_buff_head *skbs);
void iwl_trans_pcie_tx_reset(struct iwl_trans *trans);
+void iwl_trans_pcie_ref(struct iwl_trans *trans);
+void iwl_trans_pcie_unref(struct iwl_trans *trans);
+
static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
{
struct iwl_tfd_tb *tb = &tfd->tbs[idx];
diff --git a/drivers/net/wireless/iwlwifi/pcie/trans.c b/drivers/net/wireless/iwlwifi/pcie/trans.c
index 523fe0c88dcb..69935aa5a1b3 100644
--- a/drivers/net/wireless/iwlwifi/pcie/trans.c
+++ b/drivers/net/wireless/iwlwifi/pcie/trans.c
@@ -75,6 +75,7 @@
#include "iwl-trans.h"
#include "iwl-csr.h"
#include "iwl-prph.h"
+#include "iwl-scd.h"
#include "iwl-agn-hw.h"
#include "iwl-fw-error-dump.h"
#include "internal.h"
@@ -443,10 +444,25 @@ static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
return ret;
}
-static void iwl_pcie_apm_stop(struct iwl_trans *trans)
+static void iwl_pcie_apm_stop(struct iwl_trans *trans, bool op_mode_leave)
{
IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
+ if (op_mode_leave) {
+ if (!test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+ iwl_pcie_apm_init(trans);
+
+ /* inform ME that we are leaving */
+ if (trans->cfg->device_family == IWL_DEVICE_FAMILY_7000)
+ iwl_set_bits_prph(trans, APMG_PCIDEV_STT_REG,
+ APMG_PCIDEV_STT_VAL_WAKE_ME);
+ else if (trans->cfg->device_family == IWL_DEVICE_FAMILY_8000)
+ iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
+ CSR_HW_IF_CONFIG_REG_PREPARE |
+ CSR_HW_IF_CONFIG_REG_ENABLE_PME);
+ mdelay(5);
+ }
+
clear_bit(STATUS_DEVICE_ENABLED, &trans->status);
/* Stop device's DMA activity */
@@ -707,6 +723,11 @@ static int iwl_pcie_load_cpu_sections_8000b(struct iwl_trans *trans,
*first_ucode_section = last_read_idx;
+ if (cpu == 1)
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFF);
+ else
+ iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
+
return 0;
}
@@ -893,8 +914,8 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
if (ret)
return ret;
- /* Notify FW loading is done */
- iwl_write_direct32(trans, FH_UCODE_LOAD_STATUS, 0xFFFFFFFF);
+ if (trans->dbg_dest_tlv)
+ iwl_pcie_apply_destination(trans);
/* wait for image verification to complete */
ret = iwl_poll_prph_bit(trans, LMPM_SECURE_BOOT_CPU1_STATUS_ADDR_B0,
@@ -916,6 +937,7 @@ static int iwl_pcie_load_given_ucode_8000b(struct iwl_trans *trans,
static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
const struct fw_img *fw, bool run_in_rfkill)
{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
bool hw_rfkill;
@@ -945,6 +967,9 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
return ret;
}
+ /* init ref_count to 1 (should be cleared when ucode is loaded) */
+ trans_pcie->ref_count = 1;
+
/* make sure rfkill handshake bits are cleared */
iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR,
@@ -960,7 +985,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
/* Load the given image to the HW */
if ((trans->cfg->device_family == IWL_DEVICE_FAMILY_8000) &&
- (CSR_HW_REV_STEP(trans->hw_rev) == SILICON_B_STEP))
+ (CSR_HW_REV_STEP(trans->hw_rev) != SILICON_A_STEP))
return iwl_pcie_load_given_ucode_8000b(trans, fw);
else
return iwl_pcie_load_given_ucode(trans, fw);
@@ -1010,7 +1035,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
/* Stop the device, and put it in low power state */
- iwl_pcie_apm_stop(trans);
+ iwl_pcie_apm_stop(trans, false);
/* stop and reset the on-board processor */
iwl_write32(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
@@ -1192,7 +1217,7 @@ static void iwl_trans_pcie_op_mode_leave(struct iwl_trans *trans)
iwl_disable_interrupts(trans);
spin_unlock(&trans_pcie->irq_lock);
- iwl_pcie_apm_stop(trans);
+ iwl_pcie_apm_stop(trans, true);
spin_lock(&trans_pcie->irq_lock);
iwl_disable_interrupts(trans);
@@ -1244,6 +1269,7 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
trans_pcie->cmd_queue = trans_cfg->cmd_queue;
trans_pcie->cmd_fifo = trans_cfg->cmd_fifo;
+ trans_pcie->cmd_q_wdg_timeout = trans_cfg->cmd_q_wdg_timeout;
if (WARN_ON(trans_cfg->n_no_reclaim_cmds > MAX_NO_RECLAIM_CMDS))
trans_pcie->n_no_reclaim_cmds = 0;
else
@@ -1258,9 +1284,6 @@ static void iwl_trans_pcie_configure(struct iwl_trans *trans,
else
trans_pcie->rx_page_order = get_order(4 * 1024);
- trans_pcie->wd_timeout =
- msecs_to_jiffies(trans_cfg->queue_watchdog_timeout);
-
trans_pcie->command_names = trans_cfg->command_names;
trans_pcie->bc_table_dword = trans_cfg->bc_table_dword;
trans_pcie->scd_set_active = trans_cfg->scd_set_active;
@@ -1540,6 +1563,38 @@ static void iwl_trans_pcie_set_bits_mask(struct iwl_trans *trans, u32 reg,
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
}
+void iwl_trans_pcie_ref(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ unsigned long flags;
+
+ if (iwlwifi_mod_params.d0i3_disable)
+ return;
+
+ spin_lock_irqsave(&trans_pcie->ref_lock, flags);
+ IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
+ trans_pcie->ref_count++;
+ spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
+}
+
+void iwl_trans_pcie_unref(struct iwl_trans *trans)
+{
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ unsigned long flags;
+
+ if (iwlwifi_mod_params.d0i3_disable)
+ return;
+
+ spin_lock_irqsave(&trans_pcie->ref_lock, flags);
+ IWL_DEBUG_RPM(trans, "ref_counter: %d\n", trans_pcie->ref_count);
+ if (WARN_ON_ONCE(trans_pcie->ref_count == 0)) {
+ spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
+ return;
+ }
+ trans_pcie->ref_count--;
+ spin_unlock_irqrestore(&trans_pcie->ref_lock, flags);
+}
+
static const char *get_csr_string(int cmd)
{
#define IWL_CMD(x) case x: return #x
@@ -2264,6 +2319,9 @@ static const struct iwl_trans_ops trans_ops_pcie = {
.release_nic_access = iwl_trans_pcie_release_nic_access,
.set_bits_mask = iwl_trans_pcie_set_bits_mask,
+ .ref = iwl_trans_pcie_ref,
+ .unref = iwl_trans_pcie_unref,
+
.dump_data = iwl_trans_pcie_dump_data,
};
@@ -2291,6 +2349,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
trans_pcie->trans = trans;
spin_lock_init(&trans_pcie->irq_lock);
spin_lock_init(&trans_pcie->reg_lock);
+ spin_lock_init(&trans_pcie->ref_lock);
init_waitqueue_head(&trans_pcie->ucode_write_waitq);
err = pci_enable_device(pdev);
@@ -2404,6 +2463,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
}
trans_pcie->inta_mask = CSR_INI_SET_MASK;
+ trans->d0i3_mode = IWL_D0I3_MODE_ON_SUSPEND;
return trans;
diff --git a/drivers/net/wireless/iwlwifi/pcie/tx.c b/drivers/net/wireless/iwlwifi/pcie/tx.c
index 8a6c7a084aa1..af0bce736358 100644
--- a/drivers/net/wireless/iwlwifi/pcie/tx.c
+++ b/drivers/net/wireless/iwlwifi/pcie/tx.c
@@ -147,7 +147,6 @@ static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans,
static void iwl_pcie_txq_stuck_timer(unsigned long data)
{
struct iwl_txq *txq = (void *)data;
- struct iwl_queue *q = &txq->q;
struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
u32 scd_sram_addr = trans_pcie->scd_base_addr +
@@ -164,7 +163,7 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
spin_unlock(&txq->lock);
IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
- jiffies_to_msecs(trans_pcie->wd_timeout));
+ jiffies_to_msecs(txq->wd_timeout));
IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
txq->q.read_ptr, txq->q.write_ptr);
@@ -198,11 +197,6 @@ static void iwl_pcie_txq_stuck_timer(unsigned long data)
iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
}
- for (i = q->read_ptr; i != q->write_ptr;
- i = iwl_queue_inc_wrap(i))
- IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
- le32_to_cpu(txq->scratchbufs[i].scratch));
-
iwl_force_nmi(trans);
}
@@ -680,7 +674,8 @@ void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue,
- trans_pcie->cmd_fifo);
+ trans_pcie->cmd_fifo,
+ trans_pcie->cmd_q_wdg_timeout);
/* Activate all Tx DMA/FIFO channels */
iwl_scd_activate_fifos(trans);
@@ -722,7 +717,12 @@ void iwl_trans_pcie_tx_reset(struct iwl_trans *trans)
iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
trans_pcie->kw.dma >> 4);
- iwl_pcie_tx_start(trans, trans_pcie->scd_base_addr);
+ /*
+ * Send 0 as the scd_base_addr since the device may have be reset
+ * while we were in WoWLAN in which case SCD_SRAM_BASE_ADDR will
+ * contain garbage.
+ */
+ iwl_pcie_tx_start(trans, 0);
}
/*
@@ -898,6 +898,10 @@ int iwl_pcie_tx_init(struct iwl_trans *trans)
}
}
+ if (trans->cfg->base_params->num_of_queues > 20)
+ iwl_set_bits_prph(trans, SCD_GP_CTRL,
+ SCD_GP_CTRL_ENABLE_31_QUEUES);
+
return 0;
error:
/*Upon error, free only if we allocated something */
@@ -906,10 +910,9 @@ error:
return ret;
}
-static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie,
- struct iwl_txq *txq)
+static inline void iwl_pcie_txq_progress(struct iwl_txq *txq)
{
- if (!trans_pcie->wd_timeout)
+ if (!txq->wd_timeout)
return;
/*
@@ -919,7 +922,7 @@ static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie,
if (txq->q.read_ptr == txq->q.write_ptr)
del_timer(&txq->stuck_timer);
else
- mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+ mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
}
/* Frees buffers until index _not_ inclusive */
@@ -981,21 +984,35 @@ void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
iwl_pcie_txq_free_tfd(trans, txq);
}
- iwl_pcie_txq_progress(trans_pcie, txq);
+ iwl_pcie_txq_progress(txq);
if (iwl_queue_space(&txq->q) > txq->q.low_mark)
iwl_wake_queue(trans, txq);
+
+ if (q->read_ptr == q->write_ptr) {
+ IWL_DEBUG_RPM(trans, "Q %d - last tx reclaimed\n", q->id);
+ iwl_trans_pcie_unref(trans);
+ }
+
out:
spin_unlock_bh(&txq->lock);
}
-static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans)
+static int iwl_pcie_set_cmd_in_flight(struct iwl_trans *trans,
+ const struct iwl_host_cmd *cmd)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
int ret;
lockdep_assert_held(&trans_pcie->reg_lock);
+ if (!(cmd->flags & CMD_SEND_IN_IDLE) &&
+ !trans_pcie->ref_cmd_in_flight) {
+ trans_pcie->ref_cmd_in_flight = true;
+ IWL_DEBUG_RPM(trans, "set ref_cmd_in_flight - ref\n");
+ iwl_trans_pcie_ref(trans);
+ }
+
if (trans_pcie->cmd_in_flight)
return 0;
@@ -1036,6 +1053,12 @@ static int iwl_pcie_clear_cmd_in_flight(struct iwl_trans *trans)
lockdep_assert_held(&trans_pcie->reg_lock);
+ if (trans_pcie->ref_cmd_in_flight) {
+ trans_pcie->ref_cmd_in_flight = false;
+ IWL_DEBUG_RPM(trans, "clear ref_cmd_in_flight - unref\n");
+ iwl_trans_pcie_unref(trans);
+ }
+
if (WARN_ON(!trans_pcie->cmd_in_flight))
return 0;
@@ -1089,7 +1112,7 @@ static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
}
- iwl_pcie_txq_progress(trans_pcie, txq);
+ iwl_pcie_txq_progress(txq);
}
static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
@@ -1122,14 +1145,18 @@ static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
#define BUILD_RAxTID(sta_id, tid) (((sta_id) << 4) + (tid))
void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
- const struct iwl_trans_txq_scd_cfg *cfg)
+ const struct iwl_trans_txq_scd_cfg *cfg,
+ unsigned int wdg_timeout)
{
struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ struct iwl_txq *txq = &trans_pcie->txq[txq_id];
int fifo = -1;
if (test_and_set_bit(txq_id, trans_pcie->queue_used))
WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
+ txq->wd_timeout = msecs_to_jiffies(wdg_timeout);
+
if (cfg) {
fifo = cfg->fifo;
@@ -1153,7 +1180,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
/* enable aggregations for the queue */
iwl_scd_txq_enable_agg(trans, txq_id);
- trans_pcie->txq[txq_id].ampdu = true;
+ txq->ampdu = true;
} else {
/*
* disable aggregations for the queue, this will also
@@ -1162,20 +1189,20 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
*/
iwl_scd_txq_disable_agg(trans, txq_id);
- ssn = trans_pcie->txq[txq_id].q.read_ptr;
+ ssn = txq->q.read_ptr;
}
}
/* Place first TFD at index corresponding to start sequence number.
* Assumes that ssn_idx is valid (!= 0xFFF) */
- trans_pcie->txq[txq_id].q.read_ptr = (ssn & 0xff);
- trans_pcie->txq[txq_id].q.write_ptr = (ssn & 0xff);
+ txq->q.read_ptr = (ssn & 0xff);
+ txq->q.write_ptr = (ssn & 0xff);
+ iwl_write_direct32(trans, HBUS_TARG_WRPTR,
+ (ssn & 0xff) | (txq_id << 8));
if (cfg) {
u8 frame_limit = cfg->frame_limit;
- iwl_write_direct32(trans, HBUS_TARG_WRPTR,
- (ssn & 0xff) | (txq_id << 8));
iwl_write_prph(trans, SCD_QUEUE_RDPTR(txq_id), ssn);
/* Set up Tx window size and frame limit for this queue */
@@ -1200,11 +1227,17 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, u16 ssn,
if (txq_id == trans_pcie->cmd_queue &&
trans_pcie->scd_set_active)
iwl_scd_enable_set_active(trans, BIT(txq_id));
+
+ IWL_DEBUG_TX_QUEUES(trans,
+ "Activate queue %d on FIFO %d WrPtr: %d\n",
+ txq_id, fifo, ssn & 0xff);
+ } else {
+ IWL_DEBUG_TX_QUEUES(trans,
+ "Activate queue %d WrPtr: %d\n",
+ txq_id, ssn & 0xff);
}
- trans_pcie->txq[txq_id].active = true;
- IWL_DEBUG_TX_QUEUES(trans, "Activate queue %d on FIFO %d WrPtr: %d\n",
- txq_id, fifo, ssn & 0xff);
+ txq->active = true;
}
void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id,
@@ -1469,11 +1502,11 @@ static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
trace_iwlwifi_dev_hcmd(trans->dev, cmd, cmd_size, &out_cmd->hdr);
/* start timer if queue currently empty */
- if (q->read_ptr == q->write_ptr && trans_pcie->wd_timeout)
- mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+ if (q->read_ptr == q->write_ptr && txq->wd_timeout)
+ mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
spin_lock_irqsave(&trans_pcie->reg_lock, flags);
- ret = iwl_pcie_set_cmd_in_flight(trans);
+ ret = iwl_pcie_set_cmd_in_flight(trans, cmd);
if (ret < 0) {
idx = ret;
spin_unlock_irqrestore(&trans_pcie->reg_lock, flags);
@@ -1819,9 +1852,12 @@ int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
wait_write_ptr = ieee80211_has_morefrags(fc);
/* start timer if queue currently empty */
- if (txq->need_update && q->read_ptr == q->write_ptr &&
- trans_pcie->wd_timeout)
- mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+ if (q->read_ptr == q->write_ptr) {
+ if (txq->wd_timeout)
+ mod_timer(&txq->stuck_timer, jiffies + txq->wd_timeout);
+ IWL_DEBUG_RPM(trans, "Q: %d first tx - take ref\n", q->id);
+ iwl_trans_pcie_ref(trans);
+ }
/* Tell device the write index *just past* this latest filled TFD */
q->write_ptr = iwl_queue_inc_wrap(q->write_ptr);
diff --git a/drivers/net/wireless/libertas/cfg.c b/drivers/net/wireless/libertas/cfg.c
index 34f09ef90bb3..a92985a6ea21 100644
--- a/drivers/net/wireless/libertas/cfg.c
+++ b/drivers/net/wireless/libertas/cfg.c
@@ -1616,10 +1616,10 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
lbs_deb_enter(LBS_DEB_CFG80211);
- sinfo->filled |= STATION_INFO_TX_BYTES |
- STATION_INFO_TX_PACKETS |
- STATION_INFO_RX_BYTES |
- STATION_INFO_RX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_RX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS);
sinfo->tx_bytes = priv->dev->stats.tx_bytes;
sinfo->tx_packets = priv->dev->stats.tx_packets;
sinfo->rx_bytes = priv->dev->stats.rx_bytes;
@@ -1629,14 +1629,14 @@ static int lbs_cfg_get_station(struct wiphy *wiphy, struct net_device *dev,
ret = lbs_get_rssi(priv, &signal, &noise);
if (ret == 0) {
sinfo->signal = signal;
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}
/* Convert priv->cur_rate from hw_value to NL80211 value */
for (i = 0; i < ARRAY_SIZE(lbs_rates); i++) {
if (priv->cur_rate == lbs_rates[i].hw_value) {
sinfo->txrate.legacy = lbs_rates[i].bitrate;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
break;
}
}
diff --git a/drivers/net/wireless/mac80211_hwsim.c b/drivers/net/wireless/mac80211_hwsim.c
index ef58a8862d91..4a4c6586a8d2 100644
--- a/drivers/net/wireless/mac80211_hwsim.c
+++ b/drivers/net/wireless/mac80211_hwsim.c
@@ -625,22 +625,22 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
old_ps = data->ps;
data->ps = val;
+ local_bh_disable();
if (val == PS_MANUAL_POLL) {
- ieee80211_iterate_active_interfaces(data->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- hwsim_send_ps_poll, data);
+ ieee80211_iterate_active_interfaces_atomic(
+ data->hw, IEEE80211_IFACE_ITER_NORMAL,
+ hwsim_send_ps_poll, data);
data->ps_poll_pending = true;
} else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
- ieee80211_iterate_active_interfaces(data->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- hwsim_send_nullfunc_ps,
- data);
+ ieee80211_iterate_active_interfaces_atomic(
+ data->hw, IEEE80211_IFACE_ITER_NORMAL,
+ hwsim_send_nullfunc_ps, data);
} else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
- ieee80211_iterate_active_interfaces(data->hw,
- IEEE80211_IFACE_ITER_NORMAL,
- hwsim_send_nullfunc_no_ps,
- data);
+ ieee80211_iterate_active_interfaces_atomic(
+ data->hw, IEEE80211_IFACE_ITER_NORMAL,
+ hwsim_send_nullfunc_no_ps, data);
}
+ local_bh_enable();
return 0;
}
@@ -2149,14 +2149,14 @@ static int append_radio_msg(struct sk_buff *skb, int id,
if (param->regd) {
int i;
- for (i = 0; hwsim_world_regdom_custom[i] != param->regd &&
- i < ARRAY_SIZE(hwsim_world_regdom_custom); i++)
- ;
+ for (i = 0; i < ARRAY_SIZE(hwsim_world_regdom_custom); i++) {
+ if (hwsim_world_regdom_custom[i] != param->regd)
+ continue;
- if (i < ARRAY_SIZE(hwsim_world_regdom_custom)) {
ret = nla_put_u32(skb, HWSIM_ATTR_REG_CUSTOM_REG, i);
if (ret < 0)
return ret;
+ break;
}
}
@@ -2557,7 +2557,8 @@ static int mac80211_hwsim_get_radio(struct sk_buff *skb,
if (res < 0)
goto out_err;
- return genlmsg_end(skb, hdr);
+ genlmsg_end(skb, hdr);
+ return 0;
out_err:
genlmsg_cancel(skb, hdr);
diff --git a/drivers/net/wireless/mwifiex/11h.c b/drivers/net/wireless/mwifiex/11h.c
index 2668e83afbb6..3ab87a855122 100644
--- a/drivers/net/wireless/mwifiex/11h.c
+++ b/drivers/net/wireless/mwifiex/11h.c
@@ -21,6 +21,16 @@
#include "fw.h"
+void mwifiex_init_11h_params(struct mwifiex_private *priv)
+{
+ priv->state_11h.is_11h_enabled = true;
+ priv->state_11h.is_11h_active = false;
+}
+
+inline int mwifiex_is_11h_active(struct mwifiex_private *priv)
+{
+ return priv->state_11h.is_11h_active;
+}
/* This function appends 11h info to a buffer while joining an
* infrastructure BSS
*/
@@ -39,7 +49,7 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
return;
radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- sband = priv->wdev->wiphy->bands[radio_type];
+ sband = priv->wdev.wiphy->bands[radio_type];
cap = (struct mwifiex_ie_types_pwr_capability *)*buffer;
cap->header.type = cpu_to_le16(WLAN_EID_PWR_CAPABILITY);
@@ -69,10 +79,14 @@ mwifiex_11h_process_infra_join(struct mwifiex_private *priv, u8 **buffer,
}
/* Enable or disable the 11h extensions in the firmware */
-static int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
+int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag)
{
u32 enable = flag;
+ /* enable master mode radar detection on AP interface */
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && enable)
+ enable |= MWIFIEX_MASTER_RADAR_DET_MASK;
+
return mwifiex_send_cmd(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11H_I, &enable, true);
}
@@ -91,11 +105,191 @@ void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
* bit
*/
mwifiex_11h_activate(priv, true);
+ priv->state_11h.is_11h_active = true;
bss_desc->cap_info_bitmap |= WLAN_CAPABILITY_SPECTRUM_MGMT;
mwifiex_11h_process_infra_join(priv, buffer, bss_desc);
} else {
/* Deactivate 11h functions in the firmware */
mwifiex_11h_activate(priv, false);
+ priv->state_11h.is_11h_active = false;
bss_desc->cap_info_bitmap &= ~WLAN_CAPABILITY_SPECTRUM_MGMT;
}
}
+
+/* This is DFS CAC work queue function.
+ * This delayed work emits CAC finished event for cfg80211 if
+ * CAC was started earlier.
+ */
+void mwifiex_dfs_cac_work_queue(struct work_struct *work)
+{
+ struct cfg80211_chan_def chandef;
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct mwifiex_private *priv =
+ container_of(delayed_work, struct mwifiex_private,
+ dfs_cac_work);
+
+ if (WARN_ON(!priv))
+ return;
+
+ chandef = priv->dfs_chandef;
+ if (priv->wdev.cac_started) {
+ dev_dbg(priv->adapter->dev,
+ "CAC timer finished; No radar detected\n");
+ cfg80211_cac_event(priv->netdev, &chandef,
+ NL80211_RADAR_CAC_FINISHED,
+ GFP_KERNEL);
+ }
+}
+
+/* This function prepares channel report request command to FW for
+ * starting radar detection.
+ */
+int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf)
+{
+ struct host_cmd_ds_chan_rpt_req *cr_req = &cmd->params.chan_rpt_req;
+ struct mwifiex_radar_params *radar_params = (void *)data_buf;
+
+ cmd->command = cpu_to_le16(HostCmd_CMD_CHAN_REPORT_REQUEST);
+ cmd->size = cpu_to_le16(S_DS_GEN);
+ le16_add_cpu(&cmd->size, sizeof(struct host_cmd_ds_chan_rpt_req));
+
+ cr_req->chan_desc.start_freq = cpu_to_le16(MWIFIEX_A_BAND_START_FREQ);
+ cr_req->chan_desc.chan_num = radar_params->chandef->chan->hw_value;
+ cr_req->chan_desc.chan_width = radar_params->chandef->width;
+ cr_req->msec_dwell_time = cpu_to_le32(radar_params->cac_time_ms);
+
+ dev_dbg(priv->adapter->dev,
+ "11h: issuing DFS Radar check for channel=%d\n",
+ radar_params->chandef->chan->hw_value);
+
+ return 0;
+}
+
+/* This function is to abort ongoing CAC upon stopping AP operations
+ * or during unload.
+ */
+void mwifiex_abort_cac(struct mwifiex_private *priv)
+{
+ if (priv->wdev.cac_started) {
+ dev_dbg(priv->adapter->dev,
+ "Aborting delayed work for CAC.\n");
+ cancel_delayed_work_sync(&priv->dfs_cac_work);
+ cfg80211_cac_event(priv->netdev, &priv->dfs_chandef,
+ NL80211_RADAR_CAC_ABORTED, GFP_KERNEL);
+ }
+}
+
+/* This function handles channel report event from FW during CAC period.
+ * If radar is detected during CAC, driver indicates the same to cfg80211
+ * and also cancels ongoing delayed work.
+ */
+int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct host_cmd_ds_chan_rpt_event *rpt_event;
+ struct mwifiex_ie_types_chan_rpt_data *rpt;
+ u8 *evt_buf;
+ u16 event_len, tlv_len;
+
+ rpt_event = (void *)(skb->data + sizeof(u32));
+ event_len = skb->len - (sizeof(struct host_cmd_ds_chan_rpt_event)+
+ sizeof(u32));
+
+ if (le32_to_cpu(rpt_event->result) != HostCmd_RESULT_OK) {
+ dev_err(priv->adapter->dev, "Error in channel report event\n");
+ return -1;
+ }
+
+ evt_buf = (void *)&rpt_event->tlvbuf;
+
+ while (event_len >= sizeof(struct mwifiex_ie_types_header)) {
+ rpt = (void *)&rpt_event->tlvbuf;
+ tlv_len = le16_to_cpu(rpt->header.len);
+
+ switch (le16_to_cpu(rpt->header.type)) {
+ case TLV_TYPE_CHANRPT_11H_BASIC:
+ if (rpt->map.radar) {
+ dev_notice(priv->adapter->dev,
+ "RADAR Detected on channel %d!\n",
+ priv->dfs_chandef.chan->hw_value);
+ cancel_delayed_work_sync(&priv->dfs_cac_work);
+ cfg80211_cac_event(priv->netdev,
+ &priv->dfs_chandef,
+ NL80211_RADAR_DETECTED,
+ GFP_KERNEL);
+ }
+ break;
+ default:
+ break;
+ }
+
+ evt_buf += (tlv_len + sizeof(rpt->header));
+ event_len -= (tlv_len + sizeof(rpt->header));
+ }
+
+ return 0;
+}
+
+/* Handler for radar detected event from FW.*/
+int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
+ struct sk_buff *skb)
+{
+ struct mwifiex_radar_det_event *rdr_event;
+
+ rdr_event = (void *)(skb->data + sizeof(u32));
+
+ if (le32_to_cpu(rdr_event->passed)) {
+ dev_notice(priv->adapter->dev,
+ "radar detected; indicating kernel\n");
+ cfg80211_radar_event(priv->adapter->wiphy, &priv->dfs_chandef,
+ GFP_KERNEL);
+ dev_dbg(priv->adapter->dev, "regdomain: %d\n",
+ rdr_event->reg_domain);
+ dev_dbg(priv->adapter->dev, "radar detection type: %d\n",
+ rdr_event->det_type);
+ } else {
+ dev_dbg(priv->adapter->dev, "false radar detection event!\n");
+ }
+
+ return 0;
+}
+
+/* This is work queue function for channel switch handling.
+ * This function takes care of updating new channel definitin to
+ * bss config structure, restart AP and indicate channel switch success
+ * to cfg80211.
+ */
+void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work)
+{
+ struct mwifiex_uap_bss_param *bss_cfg;
+ struct delayed_work *delayed_work =
+ container_of(work, struct delayed_work, work);
+ struct mwifiex_private *priv =
+ container_of(delayed_work, struct mwifiex_private,
+ dfs_chan_sw_work);
+
+ if (WARN_ON(!priv))
+ return;
+
+ bss_cfg = &priv->bss_cfg;
+ if (!bss_cfg->beacon_period) {
+ dev_err(priv->adapter->dev,
+ "channel switch: AP already stopped\n");
+ return;
+ }
+
+ mwifiex_uap_set_channel(bss_cfg, priv->dfs_chandef);
+
+ if (mwifiex_config_start_uap(priv, bss_cfg)) {
+ dev_dbg(priv->adapter->dev,
+ "Failed to start AP after channel switch\n");
+ return;
+ }
+
+ dev_notice(priv->adapter->dev,
+ "indicating channel switch completion to kernel\n");
+ cfg80211_ch_switch_notify(priv->netdev, &priv->dfs_chandef);
+}
diff --git a/drivers/net/wireless/mwifiex/11n.c b/drivers/net/wireless/mwifiex/11n.c
index 9d4786e7ddff..543148d27b01 100644
--- a/drivers/net/wireless/mwifiex/11n.c
+++ b/drivers/net/wireless/mwifiex/11n.c
@@ -39,7 +39,7 @@ int mwifiex_fill_cap_info(struct mwifiex_private *priv, u8 radio_type,
{
uint16_t ht_ext_cap = le16_to_cpu(ht_cap->extended_ht_cap_info);
struct ieee80211_supported_band *sband =
- priv->wdev->wiphy->bands[radio_type];
+ priv->wdev.wiphy->bands[radio_type];
if (WARN_ON_ONCE(!sband)) {
dev_err(priv->adapter->dev, "Invalid radio type!\n");
@@ -314,7 +314,7 @@ mwifiex_cmd_append_11n_tlv(struct mwifiex_private *priv,
return ret_len;
radio_type = mwifiex_band_to_radio_type((u8) bss_desc->bss_band);
- sband = priv->wdev->wiphy->bands[radio_type];
+ sband = priv->wdev.wiphy->bands[radio_type];
if (bss_desc->bcn_ht_cap) {
ht_cap = (struct mwifiex_ie_types_htcap *) *buffer;
@@ -558,10 +558,10 @@ int mwifiex_send_addba(struct mwifiex_private *priv, int tid, u8 *peer_mac)
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
sta_ptr = mwifiex_get_sta_entry(priv, peer_mac);
if (!sta_ptr) {
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
dev_warn(priv->adapter->dev,
"BA setup with unknown TDLS peer %pM!\n",
peer_mac);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return -1;
}
if (sta_ptr->is_11ac_enabled)
diff --git a/drivers/net/wireless/mwifiex/11n.h b/drivers/net/wireless/mwifiex/11n.h
index f275675cdbd3..8e2e39422ad8 100644
--- a/drivers/net/wireless/mwifiex/11n.h
+++ b/drivers/net/wireless/mwifiex/11n.h
@@ -130,7 +130,9 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream(
{
struct mwifiex_private *priv;
u8 i;
- u32 ba_stream_num = 0;
+ u32 ba_stream_num = 0, ba_stream_max;
+
+ ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED;
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
@@ -139,8 +141,14 @@ static inline u8 mwifiex_space_avail_for_new_ba_stream(
&priv->tx_ba_stream_tbl_ptr);
}
- return ((ba_stream_num <
- MWIFIEX_MAX_TX_BASTREAM_SUPPORTED) ? true : false);
+ if (adapter->fw_api_ver == MWIFIEX_FW_V15) {
+ ba_stream_max =
+ GETSUPP_TXBASTREAMS(adapter->hw_dot_11n_dev_cap);
+ if (!ba_stream_max)
+ ba_stream_max = MWIFIEX_MAX_TX_BASTREAM_SUPPORTED;
+ }
+
+ return ((ba_stream_num < ba_stream_max) ? true : false);
}
/*
diff --git a/drivers/net/wireless/mwifiex/11n_aggr.c b/drivers/net/wireless/mwifiex/11n_aggr.c
index 8720a3d3c755..9b983b5cebbd 100644
--- a/drivers/net/wireless/mwifiex/11n_aggr.c
+++ b/drivers/net/wireless/mwifiex/11n_aggr.c
@@ -101,6 +101,13 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
{
struct txpd *local_tx_pd;
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
+ unsigned int pad;
+ int headroom = (priv->adapter->iface_type ==
+ MWIFIEX_USB) ? 0 : INTF_HEADER_LEN;
+
+ pad = ((void *)skb->data - sizeof(*local_tx_pd) -
+ headroom - NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1);
+ skb_push(skb, pad);
skb_push(skb, sizeof(*local_tx_pd));
@@ -114,10 +121,12 @@ mwifiex_11n_form_amsdu_txpd(struct mwifiex_private *priv,
local_tx_pd->bss_num = priv->bss_num;
local_tx_pd->bss_type = priv->bss_type;
/* Always zero as the data is followed by struct txpd */
- local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd));
+ local_tx_pd->tx_pkt_offset = cpu_to_le16(sizeof(struct txpd) +
+ pad);
local_tx_pd->tx_pkt_type = cpu_to_le16(PKT_TYPE_AMSDU);
local_tx_pd->tx_pkt_length = cpu_to_le16(skb->len -
- sizeof(*local_tx_pd));
+ sizeof(*local_tx_pd) -
+ pad);
if (tx_info->flags & MWIFIEX_BUF_FLAG_TDLS_PKT)
local_tx_pd->flags |= MWIFIEX_TXPD_FLAGS_TDLS_PACKET;
@@ -182,7 +191,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
ra_list_flags);
return -1;
}
- skb_reserve(skb_aggr, headroom + sizeof(struct txpd));
+ skb_reserve(skb_aggr, MWIFIEX_MIN_DATA_HEADER_LEN);
tx_info_aggr = MWIFIEX_SKB_TXCB(skb_aggr);
memset(tx_info_aggr, 0, sizeof(*tx_info_aggr));
diff --git a/drivers/net/wireless/mwifiex/11n_rxreorder.c b/drivers/net/wireless/mwifiex/11n_rxreorder.c
index d73fda312c87..a2e8817b56d8 100644
--- a/drivers/net/wireless/mwifiex/11n_rxreorder.c
+++ b/drivers/net/wireless/mwifiex/11n_rxreorder.c
@@ -45,7 +45,7 @@ static int mwifiex_11n_dispatch_amsdu_pkt(struct mwifiex_private *priv,
skb_trim(skb, le16_to_cpu(local_rx_pd->rx_pkt_length));
ieee80211_amsdu_to_8023s(skb, &list, priv->curr_addr,
- priv->wdev->iftype, 0, false);
+ priv->wdev.iftype, 0, false);
while (!skb_queue_empty(&list)) {
rx_skb = __skb_dequeue(&list);
@@ -353,9 +353,6 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
spin_lock_irqsave(&priv->sta_list_spinlock, flags);
if (mwifiex_queuing_ra_based(priv)) {
- dev_dbg(priv->adapter->dev,
- "info: AP/ADHOC:last_seq=%d start_win=%d\n",
- last_seq, new_node->start_win);
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP) {
node = mwifiex_get_sta_entry(priv, ta);
if (node)
@@ -370,6 +367,9 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
}
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+ dev_dbg(priv->adapter->dev, "info: last_seq=%d start_win=%d\n",
+ last_seq, new_node->start_win);
+
if (last_seq != MWIFIEX_DEF_11N_RX_SEQ_NUM &&
last_seq >= new_node->start_win) {
new_node->start_win = last_seq + 1;
@@ -391,10 +391,8 @@ mwifiex_11n_create_rx_reorder_tbl(struct mwifiex_private *priv, u8 *ta,
new_node->timer_context.priv = priv;
new_node->timer_context.timer_is_set = false;
- init_timer(&new_node->timer_context.timer);
- new_node->timer_context.timer.function = mwifiex_flush_data;
- new_node->timer_context.timer.data =
- (unsigned long) &new_node->timer_context;
+ setup_timer(&new_node->timer_context.timer, mwifiex_flush_data,
+ (unsigned long)&new_node->timer_context);
for (i = 0; i < win_size; ++i)
new_node->rx_reorder_ptr[i] = NULL;
@@ -468,10 +466,10 @@ int mwifiex_cmd_11n_addba_rsp_gen(struct mwifiex_private *priv,
sta_ptr = mwifiex_get_sta_entry(priv,
cmd_addba_req->peer_mac_addr);
if (!sta_ptr) {
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
dev_warn(priv->adapter->dev,
"BA setup with unknown TDLS peer %pM!\n",
cmd_addba_req->peer_mac_addr);
- spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return -1;
}
if (sta_ptr->is_11ac_enabled)
diff --git a/drivers/net/wireless/mwifiex/Makefile b/drivers/net/wireless/mwifiex/Makefile
index 9487d728ac20..fdfd9bf15ed4 100644
--- a/drivers/net/wireless/mwifiex/Makefile
+++ b/drivers/net/wireless/mwifiex/Makefile
@@ -53,3 +53,5 @@ obj-$(CONFIG_MWIFIEX_PCIE) += mwifiex_pcie.o
mwifiex_usb-y += usb.o
obj-$(CONFIG_MWIFIEX_USB) += mwifiex_usb.o
+
+ccflags-y += -D__CHECK_ENDIAN
diff --git a/drivers/net/wireless/mwifiex/cfg80211.c b/drivers/net/wireless/mwifiex/cfg80211.c
index 4a66a6555366..41c8e25df954 100644
--- a/drivers/net/wireless/mwifiex/cfg80211.c
+++ b/drivers/net/wireless/mwifiex/cfg80211.c
@@ -590,77 +590,62 @@ mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_uap_bss_param *bss_cfg;
- int ret, bss_started, i;
-
- for (i = 0; i < adapter->priv_num; i++) {
- priv = adapter->priv[i];
-
- switch (priv->bss_role) {
- case MWIFIEX_BSS_ROLE_UAP:
- bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param),
- GFP_KERNEL);
- if (!bss_cfg)
- return -ENOMEM;
-
- mwifiex_set_sys_config_invalid_data(bss_cfg);
-
- if (changed & WIPHY_PARAM_RTS_THRESHOLD)
- bss_cfg->rts_threshold = wiphy->rts_threshold;
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
- bss_cfg->frag_threshold = wiphy->frag_threshold;
- if (changed & WIPHY_PARAM_RETRY_LONG)
- bss_cfg->retry_limit = wiphy->retry_long;
-
- bss_started = priv->bss_started;
-
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0,
- NULL, true);
- if (ret) {
- wiphy_err(wiphy, "Failed to stop the BSS\n");
- kfree(bss_cfg);
- return ret;
- }
+ int ret;
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_BSS_PARAMS_I, bss_cfg,
- false);
+ priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
- kfree(bss_cfg);
+ switch (priv->bss_role) {
+ case MWIFIEX_BSS_ROLE_UAP:
+ if (priv->bss_started) {
+ dev_err(adapter->dev,
+ "cannot change wiphy params when bss started");
+ return -EINVAL;
+ }
- if (ret) {
- wiphy_err(wiphy, "Failed to set bss config\n");
- return ret;
- }
+ bss_cfg = kzalloc(sizeof(*bss_cfg), GFP_KERNEL);
+ if (!bss_cfg)
+ return -ENOMEM;
- if (!bss_started)
- break;
+ mwifiex_set_sys_config_invalid_data(bss_cfg);
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
- HostCmd_ACT_GEN_SET, 0,
- NULL, false);
- if (ret) {
- wiphy_err(wiphy, "Failed to start BSS\n");
- return ret;
- }
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD)
+ bss_cfg->rts_threshold = wiphy->rts_threshold;
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
+ bss_cfg->frag_threshold = wiphy->frag_threshold;
+ if (changed & WIPHY_PARAM_RETRY_LONG)
+ bss_cfg->retry_limit = wiphy->retry_long;
+
+ ret = mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg,
+ false);
+
+ kfree(bss_cfg);
+ if (ret) {
+ wiphy_err(wiphy, "Failed to set wiphy phy params\n");
+ return ret;
+ }
+ break;
- break;
case MWIFIEX_BSS_ROLE_STA:
- if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
- ret = mwifiex_set_rts(priv,
- wiphy->rts_threshold);
- if (ret)
- return ret;
- }
- if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
- ret = mwifiex_set_frag(priv,
- wiphy->frag_threshold);
- if (ret)
- return ret;
- }
- break;
+ if (priv->media_connected) {
+ dev_err(adapter->dev,
+ "cannot change wiphy params when connected");
+ return -EINVAL;
}
+ if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
+ ret = mwifiex_set_rts(priv,
+ wiphy->rts_threshold);
+ if (ret)
+ return ret;
+ }
+ if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
+ ret = mwifiex_set_frag(priv,
+ wiphy->frag_threshold);
+ if (ret)
+ return ret;
+ }
+ break;
}
return 0;
@@ -671,9 +656,6 @@ mwifiex_cfg80211_deinit_p2p(struct mwifiex_private *priv)
{
u16 mode = P2P_MODE_DISABLE;
- if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA)
- mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_STA);
-
if (mwifiex_send_cmd(priv, HostCmd_CMD_P2P_MODE_CFG,
HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
@@ -730,12 +712,249 @@ mwifiex_cfg80211_init_p2p_go(struct mwifiex_private *priv)
HostCmd_ACT_GEN_SET, 0, &mode, true))
return -1;
- if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
- mwifiex_set_bss_role(priv, MWIFIEX_BSS_ROLE_UAP);
+ return 0;
+}
+
+static int mwifiex_deinit_priv_params(struct mwifiex_private *priv)
+{
+ priv->mgmt_frame_mask = 0;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MGMT_FRAME_REG,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->mgmt_frame_mask, false)) {
+ dev_warn(priv->adapter->dev,
+ "could not unregister mgmt frame rx\n");
+ return -1;
+ }
+
+ mwifiex_deauthenticate(priv, NULL);
+ mwifiex_free_priv(priv);
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
+
+ return 0;
+}
+
+static int
+mwifiex_init_new_priv_params(struct mwifiex_private *priv,
+ struct net_device *dev,
+ enum nl80211_iftype type)
+{
+ mwifiex_init_priv(priv);
+
+ priv->bss_mode = type;
+ priv->wdev.iftype = type;
+
+ mwifiex_init_priv_params(priv, priv->netdev);
+ priv->bss_started = 0;
+
+ switch (type) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
+ priv->bss_type = MWIFIEX_BSS_TYPE_STA;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ priv->bss_role = MWIFIEX_BSS_ROLE_STA;
+ priv->bss_type = MWIFIEX_BSS_TYPE_P2P;
+ break;
+ case NL80211_IFTYPE_AP:
+ priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
+ priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
return 0;
}
+static int
+mwifiex_change_vif_to_p2p(struct net_device *dev,
+ enum nl80211_iftype curr_iftype,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter;
+
+ priv = mwifiex_netdev_get_priv(dev);
+
+ if (!priv)
+ return -1;
+
+ adapter = priv->adapter;
+
+ if (adapter->curr_iface_comb.p2p_intf ==
+ adapter->iface_limit.p2p_intf) {
+ dev_err(adapter->dev,
+ "cannot create multiple P2P ifaces\n");
+ return -1;
+ }
+
+ dev_dbg(priv->adapter->dev, "%s: changing role to p2p\n", dev->name);
+
+ if (mwifiex_deinit_priv_params(priv))
+ return -1;
+ if (mwifiex_init_new_priv_params(priv, dev, type))
+ return -1;
+
+ switch (type) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ if (mwifiex_cfg80211_init_p2p_client(priv))
+ return -EFAULT;
+ break;
+ case NL80211_IFTYPE_P2P_GO:
+ if (mwifiex_cfg80211_init_p2p_go(priv))
+ return -EFAULT;
+ break;
+ default:
+ dev_err(priv->adapter->dev,
+ "%s: changing to %d not supported\n",
+ dev->name, type);
+ return -EOPNOTSUPP;
+ }
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true))
+ return -1;
+
+ if (mwifiex_sta_init_cmd(priv, false, false))
+ return -1;
+
+ switch (curr_iftype) {
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf--;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf--;
+ break;
+ default:
+ break;
+ }
+
+ adapter->curr_iface_comb.p2p_intf++;
+ dev->ieee80211_ptr->iftype = type;
+
+ return 0;
+}
+
+static int
+mwifiex_change_vif_to_sta_adhoc(struct net_device *dev,
+ enum nl80211_iftype curr_iftype,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter;
+
+ priv = mwifiex_netdev_get_priv(dev);
+
+ if (!priv)
+ return -1;
+
+ adapter = priv->adapter;
+
+ if ((curr_iftype != NL80211_IFTYPE_P2P_CLIENT &&
+ curr_iftype != NL80211_IFTYPE_P2P_GO) &&
+ (adapter->curr_iface_comb.sta_intf ==
+ adapter->iface_limit.sta_intf)) {
+ dev_err(adapter->dev,
+ "cannot create multiple station/adhoc ifaces\n");
+ return -1;
+ }
+
+ if (type == NL80211_IFTYPE_STATION)
+ dev_notice(adapter->dev,
+ "%s: changing role to station\n", dev->name);
+ else
+ dev_notice(adapter->dev,
+ "%s: changing role to adhoc\n", dev->name);
+
+ if (mwifiex_deinit_priv_params(priv))
+ return -1;
+ if (mwifiex_init_new_priv_params(priv, dev, type))
+ return -1;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true))
+ return -1;
+ if (mwifiex_sta_init_cmd(priv, false, false))
+ return -1;
+
+ switch (curr_iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ adapter->curr_iface_comb.p2p_intf--;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf--;
+ break;
+ default:
+ break;
+ }
+
+ adapter->curr_iface_comb.sta_intf++;
+ dev->ieee80211_ptr->iftype = type;
+ return 0;
+}
+
+static int
+mwifiex_change_vif_to_ap(struct net_device *dev,
+ enum nl80211_iftype curr_iftype,
+ enum nl80211_iftype type, u32 *flags,
+ struct vif_params *params)
+{
+ struct mwifiex_private *priv;
+ struct mwifiex_adapter *adapter;
+
+ priv = mwifiex_netdev_get_priv(dev);
+
+ if (!priv)
+ return -1;
+
+ adapter = priv->adapter;
+
+ if (adapter->curr_iface_comb.uap_intf ==
+ adapter->iface_limit.uap_intf) {
+ dev_err(adapter->dev,
+ "cannot create multiple AP ifaces\n");
+ return -1;
+ }
+
+ dev_notice(adapter->dev, "%s: changing role to AP\n", dev->name);
+
+ if (mwifiex_deinit_priv_params(priv))
+ return -1;
+ if (mwifiex_init_new_priv_params(priv, dev, type))
+ return -1;
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL, true))
+ return -1;
+ if (mwifiex_sta_init_cmd(priv, false, false))
+ return -1;
+
+ switch (curr_iftype) {
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ adapter->curr_iface_comb.p2p_intf--;
+ break;
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf--;
+ break;
+ default:
+ break;
+ }
+
+ adapter->curr_iface_comb.uap_intf++;
+ dev->ieee80211_ptr->iftype = type;
+ return 0;
+}
/*
* CFG802.11 operation handler to change interface type.
*/
@@ -745,19 +964,32 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
enum nl80211_iftype type, u32 *flags,
struct vif_params *params)
{
- int ret;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ enum nl80211_iftype curr_iftype = dev->ieee80211_ptr->iftype;
- switch (dev->ieee80211_ptr->iftype) {
+ switch (curr_iftype) {
case NL80211_IFTYPE_ADHOC:
switch (type) {
case NL80211_IFTYPE_STATION:
- break;
+ priv->bss_mode = type;
+ priv->sec_info.authentication_mode =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
+ dev->ieee80211_ptr->iftype = type;
+ mwifiex_deauthenticate(priv, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL,
+ true);
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ return mwifiex_change_vif_to_p2p(dev, curr_iftype,
+ type, flags, params);
+ case NL80211_IFTYPE_AP:
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name);
case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
return 0;
- case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
@@ -767,22 +999,25 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_STATION:
switch (type) {
case NL80211_IFTYPE_ADHOC:
- break;
- case NL80211_IFTYPE_P2P_CLIENT:
- if (mwifiex_cfg80211_init_p2p_client(priv))
- return -EFAULT;
+ priv->bss_mode = type;
+ priv->sec_info.authentication_mode =
+ NL80211_AUTHTYPE_OPEN_SYSTEM;
dev->ieee80211_ptr->iftype = type;
- return 0;
+ mwifiex_deauthenticate(priv, NULL);
+ return mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
+ HostCmd_ACT_GEN_SET, 0, NULL,
+ true);
+ case NL80211_IFTYPE_P2P_CLIENT:
case NL80211_IFTYPE_P2P_GO:
- if (mwifiex_cfg80211_init_p2p_go(priv))
- return -EFAULT;
- dev->ieee80211_ptr->iftype = type;
- return 0;
+ return mwifiex_change_vif_to_p2p(dev, curr_iftype,
+ type, flags, params);
+ case NL80211_IFTYPE_AP:
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
return 0;
- case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
@@ -791,12 +1026,20 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
break;
case NL80211_IFTYPE_AP:
switch (type) {
+ case NL80211_IFTYPE_ADHOC:
+ case NL80211_IFTYPE_STATION:
+ return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
+ type, flags,
+ params);
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ return mwifiex_change_vif_to_p2p(dev, curr_iftype,
+ type, flags, params);
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name);
case NL80211_IFTYPE_AP: /* This shouldn't happen */
return 0;
- case NL80211_IFTYPE_ADHOC:
- case NL80211_IFTYPE_STATION:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
@@ -807,11 +1050,30 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_P2P_GO:
switch (type) {
case NL80211_IFTYPE_STATION:
- if (mwifiex_cfg80211_deinit_p2p(priv))
+ if (mwifiex_cfg80211_init_p2p_client(priv))
return -EFAULT;
dev->ieee80211_ptr->iftype = type;
+ break;
+ case NL80211_IFTYPE_ADHOC:
+ if (mwifiex_cfg80211_deinit_p2p(priv))
+ return -EFAULT;
+ return mwifiex_change_vif_to_sta_adhoc(dev, curr_iftype,
+ type, flags,
+ params);
+ break;
+ case NL80211_IFTYPE_AP:
+ if (mwifiex_cfg80211_deinit_p2p(priv))
+ return -EFAULT;
+ return mwifiex_change_vif_to_ap(dev, curr_iftype, type,
+ flags, params);
+ case NL80211_IFTYPE_UNSPECIFIED:
+ wiphy_warn(wiphy, "%s: kept type as P2P\n", dev->name);
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
return 0;
default:
+ wiphy_err(wiphy, "%s: changing to %d not supported\n",
+ dev->name, type);
return -EOPNOTSUPP;
}
break;
@@ -821,16 +1083,8 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
return -EOPNOTSUPP;
}
- dev->ieee80211_ptr->iftype = type;
- priv->bss_mode = type;
- mwifiex_deauthenticate(priv, NULL);
-
- priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
-
- ret = mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
- HostCmd_ACT_GEN_SET, 0, NULL, true);
- return ret;
+ return 0;
}
static void
@@ -856,16 +1110,16 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
/* HT or VHT */
switch (tx_htinfo & (BIT(3) | BIT(2))) {
case 0:
- /* This will be 20MHz */
+ rate->bw = RATE_INFO_BW_20;
break;
case (BIT(2)):
- rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_40;
break;
case (BIT(3)):
- rate->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_80;
break;
case (BIT(3) | BIT(2)):
- rate->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_160;
break;
}
@@ -885,8 +1139,9 @@ mwifiex_parse_htinfo(struct mwifiex_private *priv, u8 tx_htinfo,
if ((tx_htinfo & BIT(0)) && (priv->tx_rate < 16)) {
rate->mcs = priv->tx_rate;
rate->flags |= RATE_INFO_FLAGS_MCS;
+ rate->bw = RATE_INFO_BW_20;
if (tx_htinfo & BIT(1))
- rate->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+ rate->bw = RATE_INFO_BW_40;
if (tx_htinfo & BIT(2))
rate->flags |= RATE_INFO_FLAGS_SHORT_GI;
}
@@ -910,10 +1165,10 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
{
u32 rate;
- sinfo->filled = STATION_INFO_RX_BYTES | STATION_INFO_TX_BYTES |
- STATION_INFO_RX_PACKETS | STATION_INFO_TX_PACKETS |
- STATION_INFO_TX_BITRATE |
- STATION_INFO_SIGNAL | STATION_INFO_SIGNAL_AVG;
+ sinfo->filled = BIT(NL80211_STA_INFO_RX_BYTES) | BIT(NL80211_STA_INFO_TX_BYTES) |
+ BIT(NL80211_STA_INFO_RX_PACKETS) | BIT(NL80211_STA_INFO_TX_PACKETS) |
+ BIT(NL80211_STA_INFO_TX_BITRATE) |
+ BIT(NL80211_STA_INFO_SIGNAL) | BIT(NL80211_STA_INFO_SIGNAL_AVG);
/* Get signal information from the firmware */
if (mwifiex_send_cmd(priv, HostCmd_CMD_RSSI_INFO,
@@ -944,7 +1199,7 @@ mwifiex_dump_station_info(struct mwifiex_private *priv,
sinfo->txrate.legacy = rate * 5;
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
- sinfo->filled |= STATION_INFO_BSS_PARAM;
+ sinfo->filled |= BIT(NL80211_STA_INFO_BSS_PARAM);
sinfo->bss_param.flags = 0;
if (priv->curr_bss_params.bss_descriptor.cap_info_bitmap &
WLAN_CAPABILITY_SHORT_PREAMBLE)
@@ -1037,10 +1292,11 @@ mwifiex_cfg80211_dump_survey(struct wiphy *wiphy, struct net_device *dev,
survey->channel = ieee80211_get_channel(wiphy,
ieee80211_channel_to_frequency(pchan_stats[idx].chan_num, band));
survey->filled = SURVEY_INFO_NOISE_DBM |
- SURVEY_INFO_CHANNEL_TIME | SURVEY_INFO_CHANNEL_TIME_BUSY;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY;
survey->noise = pchan_stats[idx].noise;
- survey->channel_time = pchan_stats[idx].cca_scan_dur;
- survey->channel_time_busy = pchan_stats[idx].cca_busy_dur;
+ survey->time = pchan_stats[idx].cca_scan_dur;
+ survey->time_busy = pchan_stats[idx].cca_busy_dur;
return 0;
}
@@ -1395,10 +1651,13 @@ static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ mwifiex_abort_cac(priv);
+
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
priv->ap_11n_enabled = 0;
+ memset(&priv->bss_cfg, 0, sizeof(priv->bss_cfg));
if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL, true)) {
@@ -1420,12 +1679,9 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
{
struct mwifiex_uap_bss_param *bss_cfg;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
- u8 config_bands = 0;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_UAP)
return -1;
- if (mwifiex_set_mgmt_ies(priv, &params->beacon))
- return -1;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
if (!bss_cfg)
@@ -1442,6 +1698,11 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len);
bss_cfg->ssid.ssid_len = params->ssid_len;
}
+ if (params->inactivity_timeout > 0) {
+ /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
+ bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout;
+ bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
+ }
switch (params->hidden_ssid) {
case NL80211_HIDDEN_SSID_NOT_IN_USE:
@@ -1457,33 +1718,8 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
return -EINVAL;
}
- bss_cfg->channel = ieee80211_frequency_to_channel(
- params->chandef.chan->center_freq);
-
- /* Set appropriate bands */
- if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
- bss_cfg->band_cfg = BAND_CONFIG_BG;
- config_bands = BAND_B | BAND_G;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
- config_bands |= BAND_GN;
- } else {
- bss_cfg->band_cfg = BAND_CONFIG_A;
- config_bands = BAND_A;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
- config_bands |= BAND_AN;
-
- if (params->chandef.width > NL80211_CHAN_WIDTH_40)
- config_bands |= BAND_AAC;
- }
-
- if (!((config_bands | priv->adapter->fw_bands) &
- ~priv->adapter->fw_bands))
- priv->adapter->config_bands = config_bands;
-
+ mwifiex_uap_set_channel(bss_cfg, params->chandef);
mwifiex_set_uap_rates(bss_cfg, params);
- mwifiex_send_domain_info_cmd_fw(wiphy);
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
@@ -1506,45 +1742,29 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
mwifiex_set_wmm_params(priv, bss_cfg, params);
- if (params->inactivity_timeout > 0) {
- /* sta_ao_timer/ps_sta_ao_timer is in unit of 100ms */
- bss_cfg->sta_ao_timer = 10 * params->inactivity_timeout;
- bss_cfg->ps_sta_ao_timer = 10 * params->inactivity_timeout;
+ if (mwifiex_is_11h_active(priv) &&
+ !cfg80211_chandef_dfs_required(wiphy, &params->chandef,
+ priv->bss_mode)) {
+ dev_dbg(priv->adapter->dev, "Disable 11h extensions in FW\n");
+ if (mwifiex_11h_activate(priv, false)) {
+ dev_err(priv->adapter->dev,
+ "Failed to disable 11h extensions!!");
+ return -1;
+ }
+ priv->state_11h.is_11h_active = true;
}
- if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
- HostCmd_ACT_GEN_SET, 0, NULL, true)) {
- wiphy_err(wiphy, "Failed to stop the BSS\n");
+ if (mwifiex_config_start_uap(priv, bss_cfg)) {
+ wiphy_err(wiphy, "Failed to start AP\n");
kfree(bss_cfg);
return -1;
}
- if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
- HostCmd_ACT_GEN_SET,
- UAP_BSS_PARAMS_I, bss_cfg, false)) {
- wiphy_err(wiphy, "Failed to set the SSID\n");
- kfree(bss_cfg);
+ if (mwifiex_set_mgmt_ies(priv, &params->beacon))
return -1;
- }
+ memcpy(&priv->bss_cfg, bss_cfg, sizeof(priv->bss_cfg));
kfree(bss_cfg);
-
- if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
- HostCmd_ACT_GEN_SET, 0, NULL, false)) {
- wiphy_err(wiphy, "Failed to start the BSS\n");
- return -1;
- }
-
- if (priv->sec_info.wep_enabled)
- priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
- else
- priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
-
- if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
- HostCmd_ACT_GEN_SET, 0,
- &priv->curr_pkt_filter, true))
- return -1;
-
return 0;
}
@@ -1603,15 +1823,15 @@ static int mwifiex_cfg80211_inform_ibss_bss(struct mwifiex_private *priv)
ie_len = ie_buf[1] + sizeof(struct ieee_types_header);
band = mwifiex_band_to_radio_type(priv->curr_bss_params.band);
- chan = __ieee80211_get_channel(priv->wdev->wiphy,
+ chan = __ieee80211_get_channel(priv->wdev.wiphy,
ieee80211_channel_to_frequency(bss_info.bss_chan,
band));
- bss = cfg80211_inform_bss(priv->wdev->wiphy, chan,
+ bss = cfg80211_inform_bss(priv->wdev.wiphy, chan,
CFG80211_BSS_FTYPE_UNKNOWN,
bss_info.bssid, 0, WLAN_CAPABILITY_IBSS,
0, ie_buf, ie_len, 0, GFP_KERNEL);
- cfg80211_put_bss(priv->wdev->wiphy, bss);
+ cfg80211_put_bss(priv->wdev.wiphy, bss);
memcpy(priv->cfg_bssid, bss_info.bssid, ETH_ALEN);
return 0;
@@ -1732,12 +1952,12 @@ done:
/* Find the BSS we want using available scan results */
if (mode == NL80211_IFTYPE_ADHOC)
- bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+ bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
WLAN_CAPABILITY_IBSS,
WLAN_CAPABILITY_IBSS);
else
- bss = cfg80211_get_bss(priv->wdev->wiphy, channel,
+ bss = cfg80211_get_bss(priv->wdev.wiphy, channel,
bssid, ssid, ssid_len,
WLAN_CAPABILITY_ESS,
WLAN_CAPABILITY_ESS);
@@ -1784,6 +2004,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
struct cfg80211_connect_params *sme)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_adapter *adapter = priv->adapter;
int ret;
if (GET_BSS_ROLE(priv) != MWIFIEX_BSS_ROLE_STA) {
@@ -1793,11 +2014,18 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
return -EINVAL;
}
- if (priv->wdev && priv->wdev->current_bss) {
+ if (priv->wdev.current_bss) {
wiphy_warn(wiphy, "%s: already connected\n", dev->name);
return -EALREADY;
}
+ if (adapter->surprise_removed || adapter->is_cmd_timedout) {
+ wiphy_err(wiphy,
+ "%s: Ignore connection. Card removed or FW in bad state\n",
+ dev->name);
+ return -EFAULT;
+ }
+
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
@@ -1844,7 +2072,7 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
struct cfg80211_ibss_params *params)
{
- struct wiphy *wiphy = priv->wdev->wiphy;
+ struct wiphy *wiphy = priv->wdev.wiphy;
struct mwifiex_adapter *adapter = priv->adapter;
int index = 0, i;
u8 config_bands = 0;
@@ -2169,6 +2397,7 @@ mwifiex_setup_ht_caps(struct ieee80211_sta_ht_cap *ht_info,
ht_info->mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
}
+#define MWIFIEX_MAX_WQ_LEN 30
/*
* create a new virtual interface with the given name
*/
@@ -2182,7 +2411,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
struct mwifiex_private *priv;
struct net_device *dev;
void *mdev_priv;
- struct wireless_dev *wdev;
+ char dfs_cac_str[MWIFIEX_MAX_WQ_LEN], dfs_chsw_str[MWIFIEX_MAX_WQ_LEN];
if (!adapter)
return ERR_PTR(-EFAULT);
@@ -2191,20 +2420,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
- priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
- if (priv->bss_mode) {
+ if (adapter->curr_iface_comb.sta_intf ==
+ adapter->iface_limit.sta_intf) {
wiphy_err(wiphy,
"cannot create multiple sta/adhoc ifaces\n");
return ERR_PTR(-EINVAL);
}
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
+ priv = mwifiex_get_unused_priv(adapter);
+ if (!priv) {
+ wiphy_err(wiphy,
+ "could not get free private struct\n");
+ return ERR_PTR(-EFAULT);
+ }
- wdev->wiphy = wiphy;
- priv->wdev = wdev;
- wdev->iftype = NL80211_IFTYPE_STATION;
+ priv->wdev.wiphy = wiphy;
+ priv->wdev.iftype = NL80211_IFTYPE_STATION;
if (type == NL80211_IFTYPE_UNSPECIFIED)
priv->bss_mode = NL80211_IFTYPE_STATION;
@@ -2219,20 +2450,22 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
break;
case NL80211_IFTYPE_AP:
- priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP];
-
- if (priv->bss_mode) {
- wiphy_err(wiphy, "Can't create multiple AP interfaces");
+ if (adapter->curr_iface_comb.uap_intf ==
+ adapter->iface_limit.uap_intf) {
+ wiphy_err(wiphy,
+ "cannot create multiple AP ifaces\n");
return ERR_PTR(-EINVAL);
}
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
+ priv = mwifiex_get_unused_priv(adapter);
+ if (!priv) {
+ wiphy_err(wiphy,
+ "could not get free private struct\n");
+ return ERR_PTR(-EFAULT);
+ }
- priv->wdev = wdev;
- wdev->wiphy = wiphy;
- wdev->iftype = NL80211_IFTYPE_AP;
+ priv->wdev.wiphy = wiphy;
+ priv->wdev.iftype = NL80211_IFTYPE_AP;
priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
@@ -2244,24 +2477,25 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
break;
case NL80211_IFTYPE_P2P_CLIENT:
- priv = adapter->priv[MWIFIEX_BSS_TYPE_P2P];
-
- if (priv->bss_mode) {
- wiphy_err(wiphy, "Can't create multiple P2P ifaces");
+ if (adapter->curr_iface_comb.p2p_intf ==
+ adapter->iface_limit.p2p_intf) {
+ wiphy_err(wiphy,
+ "cannot create multiple P2P ifaces\n");
return ERR_PTR(-EINVAL);
}
- wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
- if (!wdev)
- return ERR_PTR(-ENOMEM);
-
- priv->wdev = wdev;
- wdev->wiphy = wiphy;
+ priv = mwifiex_get_unused_priv(adapter);
+ if (!priv) {
+ wiphy_err(wiphy,
+ "could not get free private struct\n");
+ return ERR_PTR(-EFAULT);
+ }
+ priv->wdev.wiphy = wiphy;
/* At start-up, wpa_supplicant tries to change the interface
* to NL80211_IFTYPE_STATION if it is not managed mode.
*/
- wdev->iftype = NL80211_IFTYPE_P2P_CLIENT;
+ priv->wdev.iftype = NL80211_IFTYPE_P2P_CLIENT;
priv->bss_mode = NL80211_IFTYPE_P2P_CLIENT;
/* Setting bss_type to P2P tells firmware that this interface
@@ -2277,8 +2511,9 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_num = 0;
if (mwifiex_cfg80211_init_p2p_client(priv)) {
- wdev = ERR_PTR(-EFAULT);
- goto done;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-EFAULT);
}
break;
@@ -2292,9 +2527,10 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
IEEE80211_NUM_ACS, 1);
if (!dev) {
wiphy_err(wiphy, "no memory available for netdevice\n");
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
- wdev = ERR_PTR(-ENOMEM);
- goto done;
+ return ERR_PTR(-ENOMEM);
}
mwifiex_init_priv_params(priv, dev);
@@ -2314,7 +2550,7 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
&wiphy->bands[IEEE80211_BAND_5GHZ]->vht_cap, priv);
dev_net_set(dev, wiphy_net(wiphy));
- dev->ieee80211_ptr = priv->wdev;
+ dev->ieee80211_ptr = &priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
memcpy(dev->dev_addr, wiphy->perm_addr, ETH_ALEN);
SET_NETDEV_DEV(dev, wiphy_dev(wiphy));
@@ -2335,10 +2571,47 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
free_netdev(dev);
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
priv->netdev = NULL;
- wdev = ERR_PTR(-EFAULT);
- goto done;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-EFAULT);
+ }
+
+ strcpy(dfs_cac_str, "MWIFIEX_DFS_CAC");
+ strcat(dfs_cac_str, name);
+ priv->dfs_cac_workqueue = alloc_workqueue(dfs_cac_str,
+ WQ_HIGHPRI |
+ WQ_MEM_RECLAIM |
+ WQ_UNBOUND, 1);
+ if (!priv->dfs_cac_workqueue) {
+ wiphy_err(wiphy, "cannot register virtual network device\n");
+ free_netdev(dev);
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->netdev = NULL;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-ENOMEM);
}
+ INIT_DELAYED_WORK(&priv->dfs_cac_work, mwifiex_dfs_cac_work_queue);
+
+ strcpy(dfs_chsw_str, "MWIFIEX_DFS_CHSW");
+ strcat(dfs_chsw_str, name);
+ priv->dfs_chan_sw_workqueue = alloc_workqueue(dfs_chsw_str,
+ WQ_HIGHPRI | WQ_UNBOUND |
+ WQ_MEM_RECLAIM, 1);
+ if (!priv->dfs_chan_sw_workqueue) {
+ wiphy_err(wiphy, "cannot register virtual network device\n");
+ free_netdev(dev);
+ priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ priv->netdev = NULL;
+ memset(&priv->wdev, 0, sizeof(priv->wdev));
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
+ return ERR_PTR(-ENOMEM);
+ }
+
+ INIT_DELAYED_WORK(&priv->dfs_chan_sw_work,
+ mwifiex_dfs_chan_sw_work_queue);
+
sema_init(&priv->async_sem, 1);
dev_dbg(adapter->dev, "info: %s: Marvell 802.11 Adapter\n", dev->name);
@@ -2347,13 +2620,24 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
mwifiex_dev_debugfs_init(priv);
#endif
-done:
- if (IS_ERR(wdev)) {
- kfree(priv->wdev);
- priv->wdev = NULL;
+ switch (type) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf++;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf++;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ adapter->curr_iface_comb.p2p_intf++;
+ break;
+ default:
+ wiphy_err(wiphy, "type not supported\n");
+ return ERR_PTR(-EINVAL);
}
- return wdev;
+ return &priv->wdev;
}
EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
@@ -2363,12 +2647,13 @@ EXPORT_SYMBOL_GPL(mwifiex_add_virtual_intf);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
+ struct mwifiex_adapter *adapter = priv->adapter;
#ifdef CONFIG_DEBUG_FS
mwifiex_dev_debugfs_remove(priv);
#endif
- mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+ mwifiex_stop_net_dev_queue(priv->netdev, adapter);
if (netif_carrier_ok(priv->netdev))
netif_carrier_off(priv->netdev);
@@ -2376,16 +2661,48 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
if (wdev->netdev->reg_state == NETREG_REGISTERED)
unregister_netdevice(wdev->netdev);
+ if (priv->dfs_cac_workqueue) {
+ flush_workqueue(priv->dfs_cac_workqueue);
+ destroy_workqueue(priv->dfs_cac_workqueue);
+ priv->dfs_cac_workqueue = NULL;
+ }
+
+ if (priv->dfs_chan_sw_workqueue) {
+ flush_workqueue(priv->dfs_chan_sw_workqueue);
+ destroy_workqueue(priv->dfs_chan_sw_workqueue);
+ priv->dfs_chan_sw_workqueue = NULL;
+ }
/* Clear the priv in adapter */
priv->netdev->ieee80211_ptr = NULL;
priv->netdev = NULL;
- kfree(wdev);
- priv->wdev = NULL;
+ priv->wdev.iftype = NL80211_IFTYPE_UNSPECIFIED;
priv->media_connected = false;
+ switch (priv->bss_mode) {
+ case NL80211_IFTYPE_UNSPECIFIED:
+ case NL80211_IFTYPE_STATION:
+ case NL80211_IFTYPE_ADHOC:
+ adapter->curr_iface_comb.sta_intf++;
+ break;
+ case NL80211_IFTYPE_AP:
+ adapter->curr_iface_comb.uap_intf++;
+ break;
+ case NL80211_IFTYPE_P2P_CLIENT:
+ case NL80211_IFTYPE_P2P_GO:
+ adapter->curr_iface_comb.p2p_intf++;
+ break;
+ default:
+ dev_err(adapter->dev, "del_virtual_intf: type not supported\n");
+ break;
+ }
+
priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
+ GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
+ kfree(priv->hist_data);
+
return 0;
}
EXPORT_SYMBOL_GPL(mwifiex_del_virtual_intf);
@@ -2421,30 +2738,16 @@ mwifiex_is_pattern_supported(struct cfg80211_pkt_pattern *pat, s8 *byte_seq,
}
#ifdef CONFIG_PM
-static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
- struct cfg80211_wowlan *wowlan)
+static int mwifiex_set_mef_filter(struct mwifiex_private *priv,
+ struct cfg80211_wowlan *wowlan)
{
- struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
- struct mwifiex_ds_mef_cfg mef_cfg;
- struct mwifiex_mef_entry *mef_entry;
- int i, filt_num = 0, ret;
+ int i, filt_num = 0, ret = 0;
bool first_pat = true;
u8 byte_seq[MWIFIEX_MEF_MAX_BYTESEQ + 1];
const u8 ipv4_mc_mac[] = {0x33, 0x33};
const u8 ipv6_mc_mac[] = {0x01, 0x00, 0x5e};
- struct mwifiex_private *priv =
- mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
-
- if (!wowlan) {
- dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
- return 0;
- }
-
- if (!priv->media_connected) {
- dev_warn(adapter->dev,
- "Can not configure WOWLAN in disconnected state\n");
- return 0;
- }
+ struct mwifiex_ds_mef_cfg mef_cfg;
+ struct mwifiex_mef_entry *mef_entry;
mef_entry = kzalloc(sizeof(*mef_entry), GFP_KERNEL);
if (!mef_entry)
@@ -2459,9 +2762,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
for (i = 0; i < wowlan->n_patterns; i++) {
memset(byte_seq, 0, sizeof(byte_seq));
if (!mwifiex_is_pattern_supported(&wowlan->patterns[i],
- byte_seq,
- MWIFIEX_MEF_MAX_BYTESEQ)) {
- wiphy_err(wiphy, "Pattern not supported\n");
+ byte_seq,
+ MWIFIEX_MEF_MAX_BYTESEQ)) {
+ dev_err(priv->adapter->dev, "Pattern not supported\n");
kfree(mef_entry);
return -EOPNOTSUPP;
}
@@ -2485,9 +2788,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
mef_entry->filter[filt_num].repeat = 1;
mef_entry->filter[filt_num].offset =
- wowlan->patterns[i].pkt_offset;
+ wowlan->patterns[i].pkt_offset;
memcpy(mef_entry->filter[filt_num].byte_seq, byte_seq,
- sizeof(byte_seq));
+ sizeof(byte_seq));
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
if (first_pat)
@@ -2502,9 +2805,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
mef_cfg.criteria |= MWIFIEX_CRITERIA_UNICAST;
mef_entry->filter[filt_num].repeat = 16;
memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
- ETH_ALEN);
+ ETH_ALEN);
mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] =
- ETH_ALEN;
+ ETH_ALEN;
mef_entry->filter[filt_num].offset = 28;
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
if (filt_num)
@@ -2513,9 +2816,9 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
filt_num++;
mef_entry->filter[filt_num].repeat = 16;
memcpy(mef_entry->filter[filt_num].byte_seq, priv->curr_addr,
- ETH_ALEN);
+ ETH_ALEN);
mef_entry->filter[filt_num].byte_seq[MWIFIEX_MEF_MAX_BYTESEQ] =
- ETH_ALEN;
+ ETH_ALEN;
mef_entry->filter[filt_num].offset = 56;
mef_entry->filter[filt_num].filt_type = TYPE_EQ;
mef_entry->filter[filt_num].filt_action = TYPE_OR;
@@ -2523,16 +2826,61 @@ static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
if (!mef_cfg.criteria)
mef_cfg.criteria = MWIFIEX_CRITERIA_BROADCAST |
- MWIFIEX_CRITERIA_UNICAST |
- MWIFIEX_CRITERIA_MULTICAST;
+ MWIFIEX_CRITERIA_UNICAST |
+ MWIFIEX_CRITERIA_MULTICAST;
ret = mwifiex_send_cmd(priv, HostCmd_CMD_MEF_CFG,
- HostCmd_ACT_GEN_SET, 0, &mef_cfg, true);
+ HostCmd_ACT_GEN_SET, 0, &mef_cfg, true);
kfree(mef_entry);
return ret;
}
+static int mwifiex_cfg80211_suspend(struct wiphy *wiphy,
+ struct cfg80211_wowlan *wowlan)
+{
+ struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
+ struct mwifiex_ds_hs_cfg hs_cfg;
+ int ret = 0;
+ struct mwifiex_private *priv =
+ mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
+
+ if (!wowlan) {
+ dev_warn(adapter->dev, "None of the WOWLAN triggers enabled\n");
+ return 0;
+ }
+
+ if (!priv->media_connected) {
+ dev_warn(adapter->dev,
+ "Can not configure WOWLAN in disconnected state\n");
+ return 0;
+ }
+
+ if (wowlan->n_patterns || wowlan->magic_pkt) {
+ ret = mwifiex_set_mef_filter(priv, wowlan);
+ if (ret) {
+ dev_err(adapter->dev, "Failed to set MEF filter\n");
+ return ret;
+ }
+ }
+
+ if (wowlan->disconnect) {
+ memset(&hs_cfg, 0, sizeof(hs_cfg));
+ hs_cfg.is_invoke_hostcmd = false;
+ hs_cfg.conditions = HS_CFG_COND_MAC_EVENT;
+ hs_cfg.gpio = HS_CFG_GPIO_DEF;
+ hs_cfg.gap = HS_CFG_GAP_DEF;
+ ret = mwifiex_set_hs_params(priv, HostCmd_ACT_GEN_SET,
+ MWIFIEX_SYNC_CMD, &hs_cfg);
+ if (ret) {
+ dev_err(adapter->dev, "Failed to set HS params\n");
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
{
return 0;
@@ -2803,6 +3151,102 @@ mwifiex_cfg80211_add_station(struct wiphy *wiphy, struct net_device *dev,
}
static int
+mwifiex_cfg80211_channel_switch(struct wiphy *wiphy, struct net_device *dev,
+ struct cfg80211_csa_settings *params)
+{
+ struct ieee_types_header *chsw_ie;
+ struct ieee80211_channel_sw_ie *channel_sw;
+ int chsw_msec;
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+
+ if (priv->adapter->scan_processing) {
+ dev_err(priv->adapter->dev,
+ "radar detection: scan in process...\n");
+ return -EBUSY;
+ }
+
+ if (priv->wdev.cac_started)
+ return -EBUSY;
+
+ if (cfg80211_chandef_identical(&params->chandef,
+ &priv->dfs_chandef))
+ return -EINVAL;
+
+ chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
+ params->beacon_csa.tail,
+ params->beacon_csa.tail_len);
+ if (!chsw_ie) {
+ dev_err(priv->adapter->dev,
+ "Could not parse channel switch announcement IE\n");
+ return -EINVAL;
+ }
+
+ channel_sw = (void *)(chsw_ie + 1);
+ if (channel_sw->mode) {
+ if (netif_carrier_ok(priv->netdev))
+ netif_carrier_off(priv->netdev);
+ mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
+ }
+
+ if (mwifiex_del_mgmt_ies(priv))
+ wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
+
+ if (mwifiex_set_mgmt_ies(priv, &params->beacon_csa)) {
+ wiphy_err(wiphy, "%s: setting mgmt ies failed\n", __func__);
+ return -EFAULT;
+ }
+
+ memcpy(&priv->dfs_chandef, &params->chandef, sizeof(priv->dfs_chandef));
+ memcpy(&priv->beacon_after, &params->beacon_after,
+ sizeof(priv->beacon_after));
+
+ chsw_msec = max(channel_sw->count * priv->bss_cfg.beacon_period, 100);
+ queue_delayed_work(priv->dfs_chan_sw_workqueue, &priv->dfs_chan_sw_work,
+ msecs_to_jiffies(chsw_msec));
+ return 0;
+}
+
+static int
+mwifiex_cfg80211_start_radar_detection(struct wiphy *wiphy,
+ struct net_device *dev,
+ struct cfg80211_chan_def *chandef,
+ u32 cac_time_ms)
+{
+ struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
+ struct mwifiex_radar_params radar_params;
+
+ if (priv->adapter->scan_processing) {
+ dev_err(priv->adapter->dev,
+ "radar detection: scan already in process...\n");
+ return -EBUSY;
+ }
+
+ if (!mwifiex_is_11h_active(priv)) {
+ dev_dbg(priv->adapter->dev, "Enable 11h extensions in FW\n");
+ if (mwifiex_11h_activate(priv, true)) {
+ dev_err(priv->adapter->dev,
+ "Failed to activate 11h extensions!!");
+ return -1;
+ }
+ priv->state_11h.is_11h_active = true;
+ }
+
+ memset(&radar_params, 0, sizeof(struct mwifiex_radar_params));
+ radar_params.chandef = chandef;
+ radar_params.cac_time_ms = cac_time_ms;
+
+ memcpy(&priv->dfs_chandef, chandef, sizeof(priv->dfs_chandef));
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_CHAN_REPORT_REQUEST,
+ HostCmd_ACT_GEN_SET, 0, &radar_params, true))
+ return -1;
+
+ queue_delayed_work(priv->dfs_cac_workqueue, &priv->dfs_cac_work,
+ msecs_to_jiffies(cac_time_ms));
+ return 0;
+}
+
+static int
mwifiex_cfg80211_change_station(struct wiphy *wiphy, struct net_device *dev,
const u8 *mac,
struct station_parameters *params)
@@ -2866,11 +3310,13 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.tdls_oper = mwifiex_cfg80211_tdls_oper,
.add_station = mwifiex_cfg80211_add_station,
.change_station = mwifiex_cfg80211_change_station,
+ .start_radar_detection = mwifiex_cfg80211_start_radar_detection,
+ .channel_switch = mwifiex_cfg80211_channel_switch,
};
#ifdef CONFIG_PM
static const struct wiphy_wowlan_support mwifiex_wowlan_support = {
- .flags = WIPHY_WOWLAN_MAGIC_PKT,
+ .flags = WIPHY_WOWLAN_MAGIC_PKT | WIPHY_WOWLAN_DISCONNECT,
.n_patterns = MWIFIEX_MEF_MAX_FILTERS,
.pattern_min_len = 1,
.pattern_max_len = MWIFIEX_MAX_PATTERN_LEN,
@@ -2964,12 +3410,13 @@ int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
wiphy->cipher_suites = mwifiex_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
- memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
+ ether_addr_copy(wiphy->perm_addr, adapter->perm_addr);
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME |
WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD |
WIPHY_FLAG_AP_UAPSD |
- WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+ WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
if (ISSUPP_TDLS_ENABLED(adapter->fw_cap_info))
wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
diff --git a/drivers/net/wireless/mwifiex/cfp.c b/drivers/net/wireless/mwifiex/cfp.c
index b8242eb2be6f..e9df8826f124 100644
--- a/drivers/net/wireless/mwifiex/cfp.c
+++ b/drivers/net/wireless/mwifiex/cfp.c
@@ -322,9 +322,9 @@ mwifiex_get_cfp(struct mwifiex_private *priv, u8 band, u16 channel, u32 freq)
return cfp;
if (mwifiex_band_to_radio_type(band) == HostCmd_SCAN_RADIO_TYPE_BG)
- sband = priv->wdev->wiphy->bands[IEEE80211_BAND_2GHZ];
+ sband = priv->wdev.wiphy->bands[IEEE80211_BAND_2GHZ];
else
- sband = priv->wdev->wiphy->bands[IEEE80211_BAND_5GHZ];
+ sband = priv->wdev.wiphy->bands[IEEE80211_BAND_5GHZ];
if (!sband) {
dev_err(priv->adapter->dev, "%s: cannot find cfp by band %d\n",
@@ -509,3 +509,21 @@ u32 mwifiex_get_supported_rates(struct mwifiex_private *priv, u8 *rates)
return k;
}
+
+u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
+ u8 rx_rate, u8 rate_info)
+{
+ u8 rate_index = 0;
+
+ /* HT40 */
+ if ((rate_info & BIT(0)) && (rate_info & BIT(1)))
+ rate_index = MWIFIEX_RATE_INDEX_MCS0 +
+ MWIFIEX_BW20_MCS_NUM + rx_rate;
+ else if (rate_info & BIT(0)) /* HT20 */
+ rate_index = MWIFIEX_RATE_INDEX_MCS0 + rx_rate;
+ else
+ rate_index = (rx_rate > MWIFIEX_RATE_INDEX_OFDM0) ?
+ rx_rate - 1 : rx_rate;
+
+ return rate_index;
+}
diff --git a/drivers/net/wireless/mwifiex/cmdevt.c b/drivers/net/wireless/mwifiex/cmdevt.c
index 85597200badc..c5a14ff7eb82 100644
--- a/drivers/net/wireless/mwifiex/cmdevt.c
+++ b/drivers/net/wireless/mwifiex/cmdevt.c
@@ -315,22 +315,19 @@ static int mwifiex_dnld_sleep_confirm_cmd(struct mwifiex_adapter *adapter)
adapter->dbg.num_cmd_sleep_cfm_host_to_card_failure++;
return -1;
}
- if (GET_BSS_ROLE(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY))
- == MWIFIEX_BSS_ROLE_STA) {
- if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl))
- /* Response is not needed for sleep
- confirm command */
- adapter->ps_state = PS_STATE_SLEEP;
- else
- adapter->ps_state = PS_STATE_SLEEP_CFM;
-
- if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) &&
- (adapter->is_hs_configured &&
- !adapter->sleep_period.period)) {
- adapter->pm_wakeup_card_req = true;
- mwifiex_hs_activated_event(mwifiex_get_priv
- (adapter, MWIFIEX_BSS_ROLE_STA), true);
- }
+
+ if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl))
+ /* Response is not needed for sleep confirm command */
+ adapter->ps_state = PS_STATE_SLEEP;
+ else
+ adapter->ps_state = PS_STATE_SLEEP_CFM;
+
+ if (!le16_to_cpu(sleep_cfm_buf->resp_ctrl) &&
+ (adapter->is_hs_configured &&
+ !adapter->sleep_period.period)) {
+ adapter->pm_wakeup_card_req = true;
+ mwifiex_hs_activated_event(mwifiex_get_priv
+ (adapter, MWIFIEX_BSS_ROLE_ANY), true);
}
return ret;
@@ -450,6 +447,7 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
EVENT_GET_BSS_TYPE(eventcause));
if (!priv)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
+
/* Clear BSS_NO_BITS from event */
eventcause &= EVENT_ID_MASK;
adapter->event_cause = eventcause;
@@ -462,12 +460,6 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
}
dev_dbg(adapter->dev, "EVENT: cause: %#x\n", eventcause);
- if (eventcause == EVENT_PS_SLEEP || eventcause == EVENT_PS_AWAKE) {
- /* Handle PS_SLEEP/AWAKE events on STA */
- priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
- if (!priv)
- priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
- }
if (priv->bss_role == MWIFIEX_BSS_ROLE_UAP)
ret = mwifiex_process_uap_event(priv);
@@ -1008,11 +1000,9 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
cmd_node->wait_q_enabled = false;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
- spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
@@ -1070,12 +1060,8 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
list_for_each_entry_safe(cmd_node, tmp_node,
&adapter->scan_pending_q, list) {
list_del(&cmd_node->list);
- spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
- scan_pending_q_flags);
cmd_node->wait_q_enabled = false;
mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
- spin_lock_irqsave(&adapter->scan_pending_q_lock,
- scan_pending_q_flags);
}
spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
scan_pending_q_flags);
@@ -1588,9 +1574,7 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
le16_to_cpu(hw_spec->hw_if_version),
le16_to_cpu(hw_spec->version));
- if (priv->curr_addr[0] == 0xff)
- memmove(priv->curr_addr, hw_spec->permanent_addr, ETH_ALEN);
-
+ ether_addr_copy(priv->adapter->perm_addr, hw_spec->permanent_addr);
adapter->region_code = le16_to_cpu(hw_spec->region_code);
for (i = 0; i < MWIFIEX_MAX_REGION_CODE; i++)
diff --git a/drivers/net/wireless/mwifiex/debugfs.c b/drivers/net/wireless/mwifiex/debugfs.c
index 2713f7acd35e..1fb329dc6744 100644
--- a/drivers/net/wireless/mwifiex/debugfs.c
+++ b/drivers/net/wireless/mwifiex/debugfs.c
@@ -39,111 +39,6 @@ static char *bss_modes[] = {
"P2P_DEVICE",
};
-/* size/addr for mwifiex_debug_info */
-#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n))
-#define item_addr(n) (offsetof(struct mwifiex_debug_info, n))
-
-/* size/addr for struct mwifiex_adapter */
-#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n))
-#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n))
-
-struct mwifiex_debug_data {
- char name[32]; /* variable/array name */
- u32 size; /* size of the variable/array */
- size_t addr; /* address of the variable/array */
- int num; /* number of variables in an array */
-};
-
-static struct mwifiex_debug_data items[] = {
- {"int_counter", item_size(int_counter),
- item_addr(int_counter), 1},
- {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
- item_addr(packets_out[WMM_AC_VO]), 1},
- {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
- item_addr(packets_out[WMM_AC_VI]), 1},
- {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
- item_addr(packets_out[WMM_AC_BE]), 1},
- {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
- item_addr(packets_out[WMM_AC_BK]), 1},
- {"tx_buf_size", item_size(tx_buf_size),
- item_addr(tx_buf_size), 1},
- {"curr_tx_buf_size", item_size(curr_tx_buf_size),
- item_addr(curr_tx_buf_size), 1},
- {"ps_mode", item_size(ps_mode),
- item_addr(ps_mode), 1},
- {"ps_state", item_size(ps_state),
- item_addr(ps_state), 1},
- {"is_deep_sleep", item_size(is_deep_sleep),
- item_addr(is_deep_sleep), 1},
- {"wakeup_dev_req", item_size(pm_wakeup_card_req),
- item_addr(pm_wakeup_card_req), 1},
- {"wakeup_tries", item_size(pm_wakeup_fw_try),
- item_addr(pm_wakeup_fw_try), 1},
- {"hs_configured", item_size(is_hs_configured),
- item_addr(is_hs_configured), 1},
- {"hs_activated", item_size(hs_activated),
- item_addr(hs_activated), 1},
- {"num_tx_timeout", item_size(num_tx_timeout),
- item_addr(num_tx_timeout), 1},
- {"is_cmd_timedout", item_size(is_cmd_timedout),
- item_addr(is_cmd_timedout), 1},
- {"timeout_cmd_id", item_size(timeout_cmd_id),
- item_addr(timeout_cmd_id), 1},
- {"timeout_cmd_act", item_size(timeout_cmd_act),
- item_addr(timeout_cmd_act), 1},
- {"last_cmd_id", item_size(last_cmd_id),
- item_addr(last_cmd_id), DBG_CMD_NUM},
- {"last_cmd_act", item_size(last_cmd_act),
- item_addr(last_cmd_act), DBG_CMD_NUM},
- {"last_cmd_index", item_size(last_cmd_index),
- item_addr(last_cmd_index), 1},
- {"last_cmd_resp_id", item_size(last_cmd_resp_id),
- item_addr(last_cmd_resp_id), DBG_CMD_NUM},
- {"last_cmd_resp_index", item_size(last_cmd_resp_index),
- item_addr(last_cmd_resp_index), 1},
- {"last_event", item_size(last_event),
- item_addr(last_event), DBG_CMD_NUM},
- {"last_event_index", item_size(last_event_index),
- item_addr(last_event_index), 1},
- {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
- item_addr(num_cmd_host_to_card_failure), 1},
- {"num_cmd_sleep_cfm_fail",
- item_size(num_cmd_sleep_cfm_host_to_card_failure),
- item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
- {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
- item_addr(num_tx_host_to_card_failure), 1},
- {"num_evt_deauth", item_size(num_event_deauth),
- item_addr(num_event_deauth), 1},
- {"num_evt_disassoc", item_size(num_event_disassoc),
- item_addr(num_event_disassoc), 1},
- {"num_evt_link_lost", item_size(num_event_link_lost),
- item_addr(num_event_link_lost), 1},
- {"num_cmd_deauth", item_size(num_cmd_deauth),
- item_addr(num_cmd_deauth), 1},
- {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
- item_addr(num_cmd_assoc_success), 1},
- {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
- item_addr(num_cmd_assoc_failure), 1},
- {"cmd_sent", item_size(cmd_sent),
- item_addr(cmd_sent), 1},
- {"data_sent", item_size(data_sent),
- item_addr(data_sent), 1},
- {"cmd_resp_received", item_size(cmd_resp_received),
- item_addr(cmd_resp_received), 1},
- {"event_received", item_size(event_received),
- item_addr(event_received), 1},
-
- /* variables defined in struct mwifiex_adapter */
- {"cmd_pending", adapter_item_size(cmd_pending),
- adapter_item_addr(cmd_pending), 1},
- {"tx_pending", adapter_item_size(tx_pending),
- adapter_item_addr(tx_pending), 1},
- {"rx_pending", adapter_item_size(rx_pending),
- adapter_item_addr(rx_pending), 1},
-};
-
-static int num_of_items = ARRAY_SIZE(items);
-
/*
* Proc info file read handler.
*
@@ -297,6 +192,8 @@ mwifiex_fw_dump_read(struct file *file, char __user *ubuf,
* - Number of FCS errors
* - Number of Tx frames
* - WEP ICV error counts
+ * - Number of received beacons
+ * - Number of missed beacons
*/
static ssize_t
mwifiex_getlog_read(struct file *file, char __user *ubuf,
@@ -333,7 +230,9 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf,
"wepicverrcnt-1 %u\n"
"wepicverrcnt-2 %u\n"
"wepicverrcnt-3 %u\n"
- "wepicverrcnt-4 %u\n",
+ "wepicverrcnt-4 %u\n"
+ "bcn_rcv_cnt %u\n"
+ "bcn_miss_cnt %u\n",
stats.mcast_tx_frame,
stats.failed,
stats.retry,
@@ -349,7 +248,9 @@ mwifiex_getlog_read(struct file *file, char __user *ubuf,
stats.wep_icv_error[0],
stats.wep_icv_error[1],
stats.wep_icv_error[2],
- stats.wep_icv_error[3]);
+ stats.wep_icv_error[3],
+ stats.bcn_rcv_cnt,
+ stats.bcn_miss_cnt);
ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
@@ -360,6 +261,103 @@ free_and_exit:
return ret;
}
+/* Sysfs histogram file read handler.
+ *
+ * This function is called when the 'histogram' file is opened for reading
+ * It prints the following histogram information -
+ * - Number of histogram samples
+ * - Receive packet number of each rx_rate
+ * - Receive packet number of each snr
+ * - Receive packet number of each nosie_flr
+ * - Receive packet number of each signal streath
+ */
+static ssize_t
+mwifiex_histogram_read(struct file *file, char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv =
+ (struct mwifiex_private *)file->private_data;
+ ssize_t ret;
+ struct mwifiex_histogram_data *phist_data;
+ int i, value;
+ unsigned long page = get_zeroed_page(GFP_KERNEL);
+ char *p = (char *)page;
+
+ if (!p)
+ return -ENOMEM;
+
+ if (!priv || !priv->hist_data)
+ return -EFAULT;
+ phist_data = priv->hist_data;
+
+ p += sprintf(p, "\n"
+ "total samples = %d\n",
+ atomic_read(&phist_data->num_samples));
+
+ p += sprintf(p, "rx rates (in Mbps): 0=1M 1=2M");
+ p += sprintf(p, "2=5.5M 3=11M 4=6M 5=9M 6=12M\n");
+ p += sprintf(p, "7=18M 8=24M 9=36M 10=48M 11=54M");
+ p += sprintf(p, "12-27=MCS0-15(BW20) 28-43=MCS0-15(BW40)\n");
+
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
+ p += sprintf(p, "44-53=MCS0-9(VHT:BW20)");
+ p += sprintf(p, "54-63=MCS0-9(VHT:BW40)");
+ p += sprintf(p, "64-73=MCS0-9(VHT:BW80)\n\n");
+ } else {
+ p += sprintf(p, "\n");
+ }
+
+ for (i = 0; i < MWIFIEX_MAX_RX_RATES; i++) {
+ value = atomic_read(&phist_data->rx_rate[i]);
+ if (value)
+ p += sprintf(p, "rx_rate[%02d] = %d\n", i, value);
+ }
+
+ if (ISSUPP_11ACENABLED(priv->adapter->fw_cap_info)) {
+ for (i = MWIFIEX_MAX_RX_RATES; i < MWIFIEX_MAX_AC_RX_RATES;
+ i++) {
+ value = atomic_read(&phist_data->rx_rate[i]);
+ if (value)
+ p += sprintf(p, "rx_rate[%02d] = %d\n",
+ i, value);
+ }
+ }
+
+ for (i = 0; i < MWIFIEX_MAX_SNR; i++) {
+ value = atomic_read(&phist_data->snr[i]);
+ if (value)
+ p += sprintf(p, "snr[%02ddB] = %d\n", i, value);
+ }
+ for (i = 0; i < MWIFIEX_MAX_NOISE_FLR; i++) {
+ value = atomic_read(&phist_data->noise_flr[i]);
+ if (value)
+ p += sprintf(p, "noise_flr[-%02ddBm] = %d\n",
+ (int)(i-128), value);
+ }
+ for (i = 0; i < MWIFIEX_MAX_SIG_STRENGTH; i++) {
+ value = atomic_read(&phist_data->sig_str[i]);
+ if (value)
+ p += sprintf(p, "sig_strength[-%02ddBm] = %d\n",
+ i, value);
+ }
+
+ ret = simple_read_from_buffer(ubuf, count, ppos, (char *)page,
+ (unsigned long)p - page);
+
+ return ret;
+}
+
+static ssize_t
+mwifiex_histogram_write(struct file *file, const char __user *ubuf,
+ size_t count, loff_t *ppos)
+{
+ struct mwifiex_private *priv = (void *)file->private_data;
+
+ if (priv && priv->hist_data)
+ mwifiex_hist_data_reset(priv);
+ return 0;
+}
+
static struct mwifiex_debug_info info;
/*
@@ -415,13 +413,9 @@ mwifiex_debug_read(struct file *file, char __user *ubuf,
{
struct mwifiex_private *priv =
(struct mwifiex_private *) file->private_data;
- struct mwifiex_debug_data *d = &items[0];
unsigned long page = get_zeroed_page(GFP_KERNEL);
char *p = (char *) page;
ssize_t ret;
- size_t size, addr;
- long val;
- int i, j;
if (!p)
return -ENOMEM;
@@ -430,68 +424,7 @@ mwifiex_debug_read(struct file *file, char __user *ubuf,
if (ret)
goto free_and_exit;
- for (i = 0; i < num_of_items; i++) {
- p += sprintf(p, "%s=", d[i].name);
-
- size = d[i].size / d[i].num;
-
- if (i < (num_of_items - 3))
- addr = d[i].addr + (size_t) &info;
- else /* The last 3 items are struct mwifiex_adapter variables */
- addr = d[i].addr + (size_t) priv->adapter;
-
- for (j = 0; j < d[i].num; j++) {
- switch (size) {
- case 1:
- val = *((u8 *) addr);
- break;
- case 2:
- val = *((u16 *) addr);
- break;
- case 4:
- val = *((u32 *) addr);
- break;
- case 8:
- val = *((long long *) addr);
- break;
- default:
- val = -1;
- break;
- }
-
- p += sprintf(p, "%#lx ", val);
- addr += size;
- }
-
- p += sprintf(p, "\n");
- }
-
- if (info.tx_tbl_num) {
- p += sprintf(p, "Tx BA stream table:\n");
- for (i = 0; i < info.tx_tbl_num; i++)
- p += sprintf(p, "tid = %d, ra = %pM\n",
- info.tx_tbl[i].tid, info.tx_tbl[i].ra);
- }
-
- if (info.rx_tbl_num) {
- p += sprintf(p, "Rx reorder table:\n");
- for (i = 0; i < info.rx_tbl_num; i++) {
- p += sprintf(p, "tid = %d, ta = %pM, "
- "start_win = %d, "
- "win_size = %d, buffer: ",
- info.rx_tbl[i].tid,
- info.rx_tbl[i].ta,
- info.rx_tbl[i].start_win,
- info.rx_tbl[i].win_size);
-
- for (j = 0; j < info.rx_tbl[i].win_size; j++)
- p += sprintf(p, "%c ",
- info.rx_tbl[i].buffer[j] ?
- '1' : '0');
-
- p += sprintf(p, "\n");
- }
- }
+ p += mwifiex_debug_info_to_buffer(priv, p, &info);
ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
(unsigned long) p - page);
@@ -817,6 +750,7 @@ MWIFIEX_DFS_FILE_READ_OPS(fw_dump);
MWIFIEX_DFS_FILE_OPS(regrdwr);
MWIFIEX_DFS_FILE_OPS(rdeeprom);
MWIFIEX_DFS_FILE_OPS(hscfg);
+MWIFIEX_DFS_FILE_OPS(histogram);
/*
* This function creates the debug FS directory structure and the files.
@@ -840,6 +774,7 @@ mwifiex_dev_debugfs_init(struct mwifiex_private *priv)
MWIFIEX_DFS_ADD_FILE(rdeeprom);
MWIFIEX_DFS_ADD_FILE(fw_dump);
MWIFIEX_DFS_ADD_FILE(hscfg);
+ MWIFIEX_DFS_ADD_FILE(histogram);
}
/*
diff --git a/drivers/net/wireless/mwifiex/decl.h b/drivers/net/wireless/mwifiex/decl.h
index 2269acf41ad8..88d0eade6bb1 100644
--- a/drivers/net/wireless/mwifiex/decl.h
+++ b/drivers/net/wireless/mwifiex/decl.h
@@ -32,15 +32,19 @@
#define MWIFIEX_MAX_BSS_NUM (3)
-#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
- * + 4 byte alignment
- */
+#define MWIFIEX_DMA_ALIGN_SZ 64
+#define MAX_TXPD_SZ 32
+#define INTF_HDR_ALIGN 4
+
+#define MWIFIEX_MIN_DATA_HEADER_LEN (MWIFIEX_DMA_ALIGN_SZ + INTF_HDR_ALIGN + \
+ MAX_TXPD_SZ)
#define MWIFIEX_MGMT_FRAME_HEADER_SIZE 8 /* sizeof(pkt_type)
* + sizeof(tx_control)
*/
#define MWIFIEX_MAX_TX_BASTREAM_SUPPORTED 2
#define MWIFIEX_MAX_RX_BASTREAM_SUPPORTED 16
+#define MWIFIEX_MAX_TDLS_PEER_SUPPORTED 8
#define MWIFIEX_STA_AMPDU_DEF_TXWINSIZE 64
#define MWIFIEX_STA_AMPDU_DEF_RXWINSIZE 64
@@ -92,6 +96,20 @@
#define MWIFIEX_TDLS_MAX_FAIL_COUNT 4
#define MWIFIEX_AUTO_TDLS_IDLE_TIME 10
+/* 54M rates, index from 0 to 11 */
+#define MWIFIEX_RATE_INDEX_MCS0 12
+/* 12-27=MCS0-15(BW20) */
+#define MWIFIEX_BW20_MCS_NUM 15
+
+/* Rate index for OFDM 0 */
+#define MWIFIEX_RATE_INDEX_OFDM0 4
+
+#define MWIFIEX_MAX_STA_NUM 1
+#define MWIFIEX_MAX_UAP_NUM 1
+#define MWIFIEX_MAX_P2P_NUM 1
+
+#define MWIFIEX_A_BAND_START_FREQ 5000
+
enum mwifiex_bss_type {
MWIFIEX_BSS_TYPE_STA = 0,
MWIFIEX_BSS_TYPE_UAP = 1,
@@ -204,4 +222,35 @@ struct mwifiex_chan_stats {
u16 cca_scan_dur;
u16 cca_busy_dur;
} __packed;
+
+#define MWIFIEX_HIST_MAX_SAMPLES 1048576
+#define MWIFIEX_MAX_RX_RATES 44
+#define MWIFIEX_MAX_AC_RX_RATES 74
+#define MWIFIEX_MAX_SNR 256
+#define MWIFIEX_MAX_NOISE_FLR 256
+#define MWIFIEX_MAX_SIG_STRENGTH 256
+
+struct mwifiex_histogram_data {
+ atomic_t rx_rate[MWIFIEX_MAX_AC_RX_RATES];
+ atomic_t snr[MWIFIEX_MAX_SNR];
+ atomic_t noise_flr[MWIFIEX_MAX_NOISE_FLR];
+ atomic_t sig_str[MWIFIEX_MAX_SIG_STRENGTH];
+ atomic_t num_samples;
+};
+
+struct mwifiex_iface_comb {
+ u8 sta_intf;
+ u8 uap_intf;
+ u8 p2p_intf;
+};
+
+struct mwifiex_radar_params {
+ struct cfg80211_chan_def *chandef;
+ u32 cac_time_ms;
+} __packed;
+
+struct mwifiex_11h_intf_state {
+ bool is_11h_enabled;
+ bool is_11h_active;
+} __packed;
#endif /* !_MWIFIEX_DECL_H_ */
diff --git a/drivers/net/wireless/mwifiex/ethtool.c b/drivers/net/wireless/mwifiex/ethtool.c
index 04e56b5fc535..65d8d6d4b6ba 100644
--- a/drivers/net/wireless/mwifiex/ethtool.c
+++ b/drivers/net/wireless/mwifiex/ethtool.c
@@ -76,7 +76,9 @@ mwifiex_get_dump_flag(struct net_device *dev, struct ethtool_dump *dump)
dump->flag = adapter->curr_mem_idx;
dump->version = 1;
- if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
+ if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
+ dump->len = adapter->drv_info_size;
+ } else if (adapter->curr_mem_idx != MWIFIEX_FW_DUMP_IDX) {
entry = &adapter->mem_type_mapping_tbl[adapter->curr_mem_idx];
dump->len = entry->mem_size;
} else {
@@ -98,6 +100,13 @@ mwifiex_get_dump_data(struct net_device *dev, struct ethtool_dump *dump,
if (!adapter->if_ops.fw_dump)
return -ENOTSUPP;
+ if (adapter->curr_mem_idx == MWIFIEX_DRV_INFO_IDX) {
+ if (!adapter->drv_info_dump)
+ return -EFAULT;
+ memcpy(p, adapter->drv_info_dump, adapter->drv_info_size);
+ return 0;
+ }
+
if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
dev_err(adapter->dev, "firmware dump in progress!!\n");
return -EBUSY;
@@ -125,6 +134,11 @@ static int mwifiex_set_dump(struct net_device *dev, struct ethtool_dump *val)
if (!adapter->if_ops.fw_dump)
return -ENOTSUPP;
+ if (val->flag == MWIFIEX_DRV_INFO_IDX) {
+ adapter->curr_mem_idx = MWIFIEX_DRV_INFO_IDX;
+ return 0;
+ }
+
if (adapter->curr_mem_idx == MWIFIEX_FW_DUMP_IDX) {
dev_err(adapter->dev, "firmware dump in progress!!\n");
return -EBUSY;
diff --git a/drivers/net/wireless/mwifiex/fw.h b/drivers/net/wireless/mwifiex/fw.h
index fb5936eb82e3..df553e86a0ad 100644
--- a/drivers/net/wireless/mwifiex/fw.h
+++ b/drivers/net/wireless/mwifiex/fw.h
@@ -158,6 +158,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
#define TLV_TYPE_BSS_SCAN_RSP (PROPRIETARY_TLV_BASE_ID + 86)
#define TLV_TYPE_BSS_SCAN_INFO (PROPRIETARY_TLV_BASE_ID + 87)
+#define TLV_TYPE_CHANRPT_11H_BASIC (PROPRIETARY_TLV_BASE_ID + 91)
#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104)
@@ -233,6 +234,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define ISSUPP_RXLDPC(Dot11nDevCap) (Dot11nDevCap & BIT(22))
#define ISSUPP_BEAMFORMING(Dot11nDevCap) (Dot11nDevCap & BIT(30))
#define ISALLOWED_CHANWIDTH40(ht_param) (ht_param & BIT(2))
+#define GETSUPP_TXBASTREAMS(Dot11nDevCap) ((Dot11nDevCap >> 18) & 0xF)
/* httxcfg bitmap
* 0 reserved
@@ -335,6 +337,7 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
#define HostCmd_CMD_11N_DELBA 0x00d0
#define HostCmd_CMD_RECONFIGURE_TX_BUFF 0x00d9
+#define HostCmd_CMD_CHAN_REPORT_REQUEST 0x00dd
#define HostCmd_CMD_AMSDU_AGGR_CTRL 0x00df
#define HostCmd_CMD_TXPWR_CFG 0x00d1
#define HostCmd_CMD_TX_RATE_CFG 0x00d6
@@ -492,6 +495,8 @@ enum P2P_MODES {
#define EVENT_HOSTWAKE_STAIE 0x0000004d
#define EVENT_CHANNEL_SWITCH_ANN 0x00000050
#define EVENT_TDLS_GENERIC_EVENT 0x00000052
+#define EVENT_RADAR_DETECTED 0x00000053
+#define EVENT_CHANNEL_REPORT_RDY 0x00000054
#define EVENT_EXT_SCAN_REPORT 0x00000058
#define EVENT_REMAIN_ON_CHAN_EXPIRED 0x0000005f
#define EVENT_TX_STATUS_REPORT 0x00000074
@@ -529,6 +534,8 @@ enum P2P_MODES {
#define MWIFIEX_FW_V15 15
+#define MWIFIEX_MASTER_RADAR_DET_MASK BIT(1)
+
struct mwifiex_ie_types_header {
__le16 type;
__le16 len;
@@ -1076,6 +1083,8 @@ struct host_cmd_ds_802_11_get_log {
__le32 tx_frame;
__le32 reserved;
__le32 wep_icv_err_cnt[4];
+ __le32 bcn_rcv_cnt;
+ __le32 bcn_miss_cnt;
};
/* Enumeration for rate format */
@@ -1213,6 +1222,24 @@ struct host_cmd_ds_tdls_oper {
u8 peer_mac[ETH_ALEN];
} __packed;
+struct mwifiex_chan_desc {
+ __le16 start_freq;
+ u8 chan_width;
+ u8 chan_num;
+} __packed;
+
+struct host_cmd_ds_chan_rpt_req {
+ struct mwifiex_chan_desc chan_desc;
+ __le32 msec_dwell_time;
+} __packed;
+
+struct host_cmd_ds_chan_rpt_event {
+ __le32 result;
+ __le64 start_tsf;
+ __le32 duration;
+ u8 tlvbuf[0];
+} __packed;
+
struct mwifiex_fixed_bcn_param {
__le64 timestamp;
__le16 beacon_period;
@@ -1789,6 +1816,39 @@ struct mwifiex_ie_types_rssi_threshold {
u8 evt_freq;
} __packed;
+#define MWIFIEX_DFS_REC_HDR_LEN 8
+#define MWIFIEX_DFS_REC_HDR_NUM 10
+#define MWIFIEX_BIN_COUNTER_LEN 7
+
+struct mwifiex_radar_det_event {
+ __le32 detect_count;
+ u8 reg_domain; /*1=fcc, 2=etsi, 3=mic*/
+ u8 det_type; /*0=none, 1=pw(chirp), 2=pri(radar)*/
+ __le16 pw_chirp_type;
+ u8 pw_chirp_idx;
+ u8 pw_value;
+ u8 pri_radar_type;
+ u8 pri_bincnt;
+ u8 bin_counter[MWIFIEX_BIN_COUNTER_LEN];
+ u8 num_dfs_records;
+ u8 dfs_record_hdr[MWIFIEX_DFS_REC_HDR_NUM][MWIFIEX_DFS_REC_HDR_LEN];
+ __le32 passed;
+} __packed;
+
+struct meas_rpt_map {
+ u8 rssi:3;
+ u8 unmeasured:1;
+ u8 radar:1;
+ u8 unidentified_sig:1;
+ u8 ofdm_preamble:1;
+ u8 bss:1;
+} __packed;
+
+struct mwifiex_ie_types_chan_rpt_data {
+ struct mwifiex_ie_types_header header;
+ struct meas_rpt_map map;
+} __packed;
+
struct host_cmd_ds_802_11_subsc_evt {
__le16 action;
__le16 events;
@@ -1901,6 +1961,7 @@ struct host_cmd_ds_command {
struct host_cmd_11ac_vht_cfg vht_cfg;
struct host_cmd_ds_coalesce_cfg coalesce_cfg;
struct host_cmd_ds_tdls_oper tdls_oper;
+ struct host_cmd_ds_chan_rpt_req chan_rpt_req;
} params;
} __packed;
diff --git a/drivers/net/wireless/mwifiex/ie.c b/drivers/net/wireless/mwifiex/ie.c
index b933794758b7..f3b6ed249403 100644
--- a/drivers/net/wireless/mwifiex/ie.c
+++ b/drivers/net/wireless/mwifiex/ie.c
@@ -317,27 +317,27 @@ done:
return ret;
}
-/* This function parses different IEs-tail IEs, beacon IEs, probe response IEs,
- * association response IEs from cfg80211_ap_settings function and sets these IE
- * to FW.
+/* This function parses head and tail IEs, from cfg80211_beacon_data and sets
+ * these IE to FW.
*/
-int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
- struct cfg80211_beacon_data *info)
+static int mwifiex_uap_set_head_tail_ies(struct mwifiex_private *priv,
+ struct cfg80211_beacon_data *info)
{
struct mwifiex_ie *gen_ie;
- struct ieee_types_header *rsn_ie, *wpa_ie = NULL;
- u16 rsn_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
+ struct ieee_types_header *rsn_ie = NULL, *wpa_ie = NULL;
+ struct ieee_types_header *chsw_ie = NULL;
+ u16 gen_idx = MWIFIEX_AUTO_IDX_MASK, ie_len = 0;
const u8 *vendor_ie;
- if (info->tail && info->tail_len) {
- gen_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
- if (!gen_ie)
- return -ENOMEM;
- gen_ie->ie_index = cpu_to_le16(rsn_idx);
- gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
- MGMT_MASK_PROBE_RESP |
- MGMT_MASK_ASSOC_RESP);
+ gen_ie = kzalloc(sizeof(*gen_ie), GFP_KERNEL);
+ if (!gen_ie)
+ return -ENOMEM;
+ gen_ie->ie_index = cpu_to_le16(gen_idx);
+ gen_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON |
+ MGMT_MASK_PROBE_RESP |
+ MGMT_MASK_ASSOC_RESP);
+ if (info->tail && info->tail_len) {
rsn_ie = (void *)cfg80211_find_ie(WLAN_EID_RSN,
info->tail, info->tail_len);
if (rsn_ie) {
@@ -358,19 +358,41 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
gen_ie->ie_length = cpu_to_le16(ie_len);
}
- if (rsn_ie || wpa_ie) {
- if (mwifiex_update_uap_custom_ie(priv, gen_ie, &rsn_idx,
- NULL, NULL,
- NULL, NULL)) {
- kfree(gen_ie);
- return -1;
- }
- priv->rsn_idx = rsn_idx;
+ chsw_ie = (void *)cfg80211_find_ie(WLAN_EID_CHANNEL_SWITCH,
+ info->tail, info->tail_len);
+ if (chsw_ie) {
+ memcpy(gen_ie->ie_buffer + ie_len,
+ chsw_ie, chsw_ie->len + 2);
+ ie_len += chsw_ie->len + 2;
+ gen_ie->ie_length = cpu_to_le16(ie_len);
}
+ }
- kfree(gen_ie);
+ if (rsn_ie || wpa_ie || chsw_ie) {
+ if (mwifiex_update_uap_custom_ie(priv, gen_ie, &gen_idx, NULL,
+ NULL, NULL, NULL)) {
+ kfree(gen_ie);
+ return -1;
+ }
+ priv->gen_idx = gen_idx;
}
+ kfree(gen_ie);
+ return 0;
+}
+
+/* This function parses different IEs-head & tail IEs, beacon IEs,
+ * probe response IEs, association response IEs from cfg80211_ap_settings
+ * function and sets these IE to FW.
+ */
+int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
+ struct cfg80211_beacon_data *info)
+{
+ int ret;
+
+ ret = mwifiex_uap_set_head_tail_ies(priv, info);
+ return ret;
+
return mwifiex_set_mgmt_beacon_data_ies(priv, info);
}
@@ -378,25 +400,25 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
{
struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
- struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
+ struct mwifiex_ie *ar_ie = NULL, *gen_ie = NULL;
int ret = 0;
- if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) {
- rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
- if (!rsn_ie)
+ if (priv->gen_idx != MWIFIEX_AUTO_IDX_MASK) {
+ gen_ie = kmalloc(sizeof(*gen_ie), GFP_KERNEL);
+ if (!gen_ie)
return -ENOMEM;
- rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx);
- rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
- rsn_ie->ie_length = 0;
- if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx,
+ gen_ie->ie_index = cpu_to_le16(priv->gen_idx);
+ gen_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
+ gen_ie->ie_length = 0;
+ if (mwifiex_update_uap_custom_ie(priv, gen_ie, &priv->gen_idx,
NULL, &priv->proberesp_idx,
NULL, &priv->assocresp_idx)) {
ret = -1;
goto done;
}
- priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
}
if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
@@ -440,7 +462,6 @@ done:
kfree(beacon_ie);
kfree(pr_ie);
kfree(ar_ie);
- kfree(rsn_ie);
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/init.c b/drivers/net/wireless/mwifiex/init.c
index 520ad4a3018b..b77ba743e1c4 100644
--- a/drivers/net/wireless/mwifiex/init.c
+++ b/drivers/net/wireless/mwifiex/init.c
@@ -52,6 +52,18 @@ static int mwifiex_add_bss_prio_tbl(struct mwifiex_private *priv)
return 0;
}
+static void wakeup_timer_fn(unsigned long data)
+{
+ struct mwifiex_adapter *adapter = (struct mwifiex_adapter *)data;
+
+ dev_err(adapter->dev, "Firmware wakeup failed\n");
+ adapter->hw_status = MWIFIEX_HW_STATUS_RESET;
+ mwifiex_cancel_all_pending_cmd(adapter);
+
+ if (adapter->if_ops.card_reset)
+ adapter->if_ops.card_reset(adapter);
+}
+
/*
* This function initializes the private structure and sets default
* values to the members.
@@ -140,6 +152,8 @@ int mwifiex_init_priv(struct mwifiex_private *priv)
priv->check_tdls_tx = false;
memcpy(priv->tos_to_tid_inv, tos_to_tid_inv, MAX_NUM_TID);
+ mwifiex_init_11h_params(priv);
+
return mwifiex_add_bss_prio_tbl(priv);
}
@@ -282,9 +296,16 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
- adapter->ext_scan = true;
+ adapter->ext_scan = false;
adapter->key_api_major_ver = 0;
adapter->key_api_minor_ver = 0;
+ memset(adapter->perm_addr, 0xff, ETH_ALEN);
+ adapter->iface_limit.sta_intf = MWIFIEX_MAX_STA_NUM;
+ adapter->iface_limit.uap_intf = MWIFIEX_MAX_UAP_NUM;
+ adapter->iface_limit.p2p_intf = MWIFIEX_MAX_P2P_NUM;
+
+ setup_timer(&adapter->wakeup_timer, wakeup_timer_fn,
+ (unsigned long)adapter);
}
/*
@@ -391,7 +412,10 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
return;
}
+ del_timer(&adapter->wakeup_timer);
mwifiex_cancel_all_pending_cmd(adapter);
+ wake_up_interruptible(&adapter->cmd_wait_q.wait);
+ wake_up_interruptible(&adapter->hs_activate_wait_q);
/* Free lock variables */
mwifiex_free_lock_list(adapter);
@@ -411,6 +435,11 @@ mwifiex_adapter_cleanup(struct mwifiex_adapter *adapter)
entry->mem_size = 0;
}
+ if (adapter->drv_info_dump) {
+ vfree(adapter->drv_info_dump);
+ adapter->drv_info_size = 0;
+ }
+
if (adapter->sleep_cfm)
dev_kfree_skb_any(adapter->sleep_cfm);
}
@@ -528,7 +557,8 @@ int mwifiex_init_fw(struct mwifiex_adapter *adapter)
for (i = 0; i < adapter->priv_num; i++) {
if (adapter->priv[i]) {
- ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta);
+ ret = mwifiex_sta_init_cmd(adapter->priv[i], first_sta,
+ true);
if (ret == -1)
return -1;
@@ -653,6 +683,7 @@ mwifiex_shutdown_drv(struct mwifiex_adapter *adapter)
priv = adapter->priv[i];
mwifiex_clean_auto_tdls(priv);
+ mwifiex_abort_cac(priv);
mwifiex_clean_txrx(priv);
mwifiex_delete_bss_prio_tbl(priv);
}
diff --git a/drivers/net/wireless/mwifiex/ioctl.h b/drivers/net/wireless/mwifiex/ioctl.h
index 0847f3e07ab7..d2b05c3a96da 100644
--- a/drivers/net/wireless/mwifiex/ioctl.h
+++ b/drivers/net/wireless/mwifiex/ioctl.h
@@ -137,6 +137,8 @@ struct mwifiex_ds_get_stats {
u32 fcs_error;
u32 tx_frame;
u32 wep_icv_error[4];
+ u32 bcn_rcv_cnt;
+ u32 bcn_miss_cnt;
};
#define MWIFIEX_MAX_VER_STR_LEN 128
@@ -180,7 +182,11 @@ struct mwifiex_ds_tx_ba_stream_tbl {
u8 amsdu;
};
-#define DBG_CMD_NUM 5
+#define DBG_CMD_NUM 5
+
+struct tdls_peer_info {
+ u8 peer_addr[ETH_ALEN];
+};
struct mwifiex_debug_info {
u32 int_counter;
@@ -193,6 +199,9 @@ struct mwifiex_debug_info {
u32 rx_tbl_num;
struct mwifiex_ds_rx_reorder_tbl rx_tbl
[MWIFIEX_MAX_RX_BASTREAM_SUPPORTED];
+ u32 tdls_peer_num;
+ struct tdls_peer_info tdls_list
+ [MWIFIEX_MAX_TDLS_PEER_SUPPORTED];
u16 ps_mode;
u32 ps_state;
u8 is_deep_sleep;
diff --git a/drivers/net/wireless/mwifiex/main.c b/drivers/net/wireless/mwifiex/main.c
index d4d2223d1f31..7e74b4fccddd 100644
--- a/drivers/net/wireless/mwifiex/main.c
+++ b/drivers/net/wireless/mwifiex/main.c
@@ -83,9 +83,8 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
}
mwifiex_init_lock_list(adapter);
- init_timer(&adapter->cmd_timer);
- adapter->cmd_timer.function = mwifiex_cmd_timeout_func;
- adapter->cmd_timer.data = (unsigned long) adapter;
+ setup_timer(&adapter->cmd_timer, mwifiex_cmd_timeout_func,
+ (unsigned long)adapter);
return 0;
@@ -237,6 +236,7 @@ process_start:
(is_command_pending(adapter) ||
!mwifiex_wmm_lists_empty(adapter))) {
adapter->pm_wakeup_fw_try = true;
+ mod_timer(&adapter->wakeup_timer, jiffies + (HZ*3));
adapter->if_ops.wakeup(adapter);
continue;
}
@@ -244,6 +244,7 @@ process_start:
if (IS_CARD_RX_RCVD(adapter)) {
adapter->data_received = false;
adapter->pm_wakeup_fw_try = false;
+ del_timer_sync(&adapter->wakeup_timer);
if (adapter->ps_state == PS_STATE_SLEEP)
adapter->ps_state = PS_STATE_AWAKE;
} else {
@@ -511,8 +512,7 @@ err_dnld_fw:
if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter);
- if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
- (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) {
pr_debug("info: %s: shutdown mwifiex\n", __func__);
adapter->init_wait_q_woken = false;
@@ -562,7 +562,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
static int
mwifiex_open(struct net_device *dev)
{
- netif_tx_start_all_queues(dev);
+ netif_carrier_off(dev);
+
return 0;
}
@@ -801,6 +802,114 @@ mwifiex_tx_timeout(struct net_device *dev)
}
}
+void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter)
+{
+ void *p;
+ char drv_version[64];
+ struct usb_card_rec *cardp;
+ struct sdio_mmc_card *sdio_card;
+ struct mwifiex_private *priv;
+ int i, idx;
+ struct netdev_queue *txq;
+ struct mwifiex_debug_info *debug_info;
+
+ if (adapter->drv_info_dump) {
+ vfree(adapter->drv_info_dump);
+ adapter->drv_info_size = 0;
+ }
+
+ dev_info(adapter->dev, "=== DRIVER INFO DUMP START===\n");
+
+ adapter->drv_info_dump = vzalloc(MWIFIEX_DRV_INFO_SIZE_MAX);
+
+ if (!adapter->drv_info_dump)
+ return;
+
+ p = (char *)(adapter->drv_info_dump);
+ p += sprintf(p, "driver_name = " "\"mwifiex\"\n");
+
+ mwifiex_drv_get_driver_version(adapter, drv_version,
+ sizeof(drv_version) - 1);
+ p += sprintf(p, "driver_version = %s\n", drv_version);
+
+ if (adapter->iface_type == MWIFIEX_USB) {
+ cardp = (struct usb_card_rec *)adapter->card;
+ p += sprintf(p, "tx_cmd_urb_pending = %d\n",
+ atomic_read(&cardp->tx_cmd_urb_pending));
+ p += sprintf(p, "tx_data_urb_pending = %d\n",
+ atomic_read(&cardp->tx_data_urb_pending));
+ p += sprintf(p, "rx_cmd_urb_pending = %d\n",
+ atomic_read(&cardp->rx_cmd_urb_pending));
+ p += sprintf(p, "rx_data_urb_pending = %d\n",
+ atomic_read(&cardp->rx_data_urb_pending));
+ }
+
+ p += sprintf(p, "tx_pending = %d\n",
+ atomic_read(&adapter->tx_pending));
+ p += sprintf(p, "rx_pending = %d\n",
+ atomic_read(&adapter->rx_pending));
+
+ if (adapter->iface_type == MWIFIEX_SDIO) {
+ sdio_card = (struct sdio_mmc_card *)adapter->card;
+ p += sprintf(p, "\nmp_rd_bitmap=0x%x curr_rd_port=0x%x\n",
+ sdio_card->mp_rd_bitmap, sdio_card->curr_rd_port);
+ p += sprintf(p, "mp_wr_bitmap=0x%x curr_wr_port=0x%x\n",
+ sdio_card->mp_wr_bitmap, sdio_card->curr_wr_port);
+ }
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i] || !adapter->priv[i]->netdev)
+ continue;
+ priv = adapter->priv[i];
+ p += sprintf(p, "\n[interface : \"%s\"]\n",
+ priv->netdev->name);
+ p += sprintf(p, "wmm_tx_pending[0] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[0]));
+ p += sprintf(p, "wmm_tx_pending[1] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[1]));
+ p += sprintf(p, "wmm_tx_pending[2] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[2]));
+ p += sprintf(p, "wmm_tx_pending[3] = %d\n",
+ atomic_read(&priv->wmm_tx_pending[3]));
+ p += sprintf(p, "media_state=\"%s\"\n", !priv->media_connected ?
+ "Disconnected" : "Connected");
+ p += sprintf(p, "carrier %s\n", (netif_carrier_ok(priv->netdev)
+ ? "on" : "off"));
+ for (idx = 0; idx < priv->netdev->num_tx_queues; idx++) {
+ txq = netdev_get_tx_queue(priv->netdev, idx);
+ p += sprintf(p, "tx queue %d:%s ", idx,
+ netif_tx_queue_stopped(txq) ?
+ "stopped" : "started");
+ }
+ p += sprintf(p, "\n%s: num_tx_timeout = %d\n",
+ priv->netdev->name, priv->num_tx_timeout);
+ }
+
+ if (adapter->iface_type == MWIFIEX_SDIO) {
+ p += sprintf(p, "\n=== SDIO register DUMP===\n");
+ if (adapter->if_ops.reg_dump)
+ p += adapter->if_ops.reg_dump(adapter, p);
+ }
+
+ p += sprintf(p, "\n=== MORE DEBUG INFORMATION\n");
+ debug_info = kzalloc(sizeof(*debug_info), GFP_KERNEL);
+ if (debug_info) {
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (!adapter->priv[i] || !adapter->priv[i]->netdev)
+ continue;
+ priv = adapter->priv[i];
+ mwifiex_get_debug_info(priv, debug_info);
+ p += mwifiex_debug_info_to_buffer(priv, p, debug_info);
+ break;
+ }
+ kfree(debug_info);
+ }
+
+ adapter->drv_info_size = p - adapter->drv_info_dump;
+ dev_info(adapter->dev, "=== DRIVER INFO DUMP END===\n");
+}
+EXPORT_SYMBOL_GPL(mwifiex_dump_drv_info);
+
/*
* CFG802.11 network device handler for statistics retrieval.
*/
@@ -847,26 +956,34 @@ static const struct net_device_ops mwifiex_netdev_ops = {
* - Nick name : Set to null
* - Number of Tx timeout : Set to 0
* - Device address : Set to current address
+ * - Rx histogram statistc : Set to 0
*
* In addition, the CFG80211 work queue is also created.
*/
void mwifiex_init_priv_params(struct mwifiex_private *priv,
- struct net_device *dev)
+ struct net_device *dev)
{
dev->netdev_ops = &mwifiex_netdev_ops;
dev->destructor = free_netdev;
/* Initialize private structure */
priv->current_key_index = 0;
priv->media_connected = false;
- memset(&priv->nick_name, 0, sizeof(priv->nick_name));
memset(priv->mgmt_ie, 0,
sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
- priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
+ priv->gen_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0;
+ ether_addr_copy(priv->curr_addr, priv->adapter->perm_addr);
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
+
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
+ GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ priv->hist_data = kmalloc(sizeof(*priv->hist_data), GFP_KERNEL);
+ if (priv->hist_data)
+ mwifiex_hist_data_reset(priv);
+ }
}
/*
@@ -1000,8 +1117,7 @@ err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
if (adapter->if_ops.unregister_dev)
adapter->if_ops.unregister_dev(adapter);
- if ((adapter->hw_status == MWIFIEX_HW_STATUS_FW_READY) ||
- (adapter->hw_status == MWIFIEX_HW_STATUS_READY)) {
+ if (adapter->hw_status == MWIFIEX_HW_STATUS_READY) {
pr_debug("info: %s: shutdown mwifiex\n", __func__);
adapter->init_wait_q_woken = false;
@@ -1052,6 +1168,8 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
adapter->surprise_removed = true;
+ mwifiex_terminate_workqueue(adapter);
+
/* Stop data */
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
@@ -1086,16 +1204,15 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
continue;
rtnl_lock();
- if (priv->wdev && priv->netdev)
- mwifiex_del_virtual_intf(adapter->wiphy, priv->wdev);
+ if (priv->netdev &&
+ priv->wdev.iftype != NL80211_IFTYPE_UNSPECIFIED)
+ mwifiex_del_virtual_intf(adapter->wiphy, &priv->wdev);
rtnl_unlock();
}
wiphy_unregister(adapter->wiphy);
wiphy_free(adapter->wiphy);
- mwifiex_terminate_workqueue(adapter);
-
/* Unregister device */
dev_dbg(adapter->dev, "info: unregister device\n");
if (adapter->if_ops.unregister_dev)
diff --git a/drivers/net/wireless/mwifiex/main.h b/drivers/net/wireless/mwifiex/main.h
index e66993cb5daf..f0a6af179af0 100644
--- a/drivers/net/wireless/mwifiex/main.h
+++ b/drivers/net/wireless/mwifiex/main.h
@@ -41,6 +41,8 @@
#include "util.h"
#include "fw.h"
#include "pcie.h"
+#include "usb.h"
+#include "sdio.h"
extern const char driver_version[];
@@ -136,6 +138,8 @@ enum {
/* Threshold for tx_timeout_cnt before we trigger a card reset */
#define TX_TIMEOUT_THRESHOLD 6
+#define MWIFIEX_DRV_INFO_SIZE_MAX 0x40000
+
struct mwifiex_dbg {
u32 num_cmd_host_to_card_failure;
u32 num_cmd_sleep_cfm_host_to_card_failure;
@@ -161,7 +165,6 @@ struct mwifiex_dbg {
enum MWIFIEX_HARDWARE_STATUS {
MWIFIEX_HW_STATUS_READY,
MWIFIEX_HW_STATUS_INITIALIZING,
- MWIFIEX_HW_STATUS_FW_READY,
MWIFIEX_HW_STATUS_INIT_DONE,
MWIFIEX_HW_STATUS_RESET,
MWIFIEX_HW_STATUS_CLOSING,
@@ -413,6 +416,7 @@ struct mwifiex_roc_cfg {
};
#define MWIFIEX_FW_DUMP_IDX 0xff
+#define MWIFIEX_DRV_INFO_IDX 20
#define FW_DUMP_MAX_NAME_LEN 8
#define FW_DUMP_HOST_READY 0xEE
#define FW_DUMP_DONE 0xFF
@@ -543,13 +547,12 @@ struct mwifiex_private {
u32 curr_bcn_size;
/* spin lock for beacon buffer */
spinlock_t curr_bcn_buf_lock;
- struct wireless_dev *wdev;
+ struct wireless_dev wdev;
struct mwifiex_chan_freq_power cfp;
char version_str[128];
#ifdef CONFIG_DEBUG_FS
struct dentry *dfs_dev_dir;
#endif
- u8 nick_name[16];
u16 current_key_index;
struct semaphore async_sem;
struct cfg80211_scan_request *scan_request;
@@ -564,7 +567,7 @@ struct mwifiex_private {
u16 beacon_idx;
u16 proberesp_idx;
u16 assocresp_idx;
- u16 rsn_idx;
+ u16 gen_idx;
u8 ap_11n_enabled;
u8 ap_11ac_enabled;
u32 mgmt_frame_mask;
@@ -574,6 +577,7 @@ struct mwifiex_private {
unsigned long csa_expire_time;
u8 del_list_idx;
bool hs2_enabled;
+ struct mwifiex_uap_bss_param bss_cfg;
struct station_parameters *sta_params;
struct sk_buff_head tdls_txq;
u8 check_tdls_tx;
@@ -582,6 +586,16 @@ struct mwifiex_private {
struct idr ack_status_frames;
/* spin lock for ack status */
spinlock_t ack_status_lock;
+ /** rx histogram data */
+ struct mwifiex_histogram_data *hist_data;
+ struct cfg80211_chan_def dfs_chandef;
+ struct workqueue_struct *dfs_cac_workqueue;
+ struct delayed_work dfs_cac_work;
+ struct timer_list dfs_chan_switch_timer;
+ struct workqueue_struct *dfs_chan_sw_workqueue;
+ struct delayed_work dfs_chan_sw_work;
+ struct cfg80211_beacon_data beacon_after;
+ struct mwifiex_11h_intf_state state_11h;
};
enum mwifiex_ba_status {
@@ -717,6 +731,7 @@ struct mwifiex_if_ops {
int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
void (*card_reset) (struct mwifiex_adapter *);
void (*fw_dump)(struct mwifiex_adapter *);
+ int (*reg_dump)(struct mwifiex_adapter *, char *);
int (*clean_pcie_ring) (struct mwifiex_adapter *adapter);
void (*iface_work)(struct work_struct *work);
void (*submit_rem_rx_urbs)(struct mwifiex_adapter *adapter);
@@ -724,6 +739,8 @@ struct mwifiex_if_ops {
struct mwifiex_adapter {
u8 iface_type;
+ struct mwifiex_iface_comb iface_limit;
+ struct mwifiex_iface_comb curr_iface_comb;
struct mwifiex_private *priv[MWIFIEX_MAX_BSS_NUM];
u8 priv_num;
const struct firmware *firmware;
@@ -731,6 +748,7 @@ struct mwifiex_adapter {
int winner;
struct device *dev;
struct wiphy *wiphy;
+ u8 perm_addr[ETH_ALEN];
bool surprise_removed;
u32 fw_release_number;
u16 init_wait_q_woken;
@@ -744,6 +762,8 @@ struct mwifiex_adapter {
struct work_struct main_work;
struct workqueue_struct *rx_workqueue;
struct work_struct rx_work;
+ struct workqueue_struct *dfs_workqueue;
+ struct work_struct dfs_work;
bool rx_work_enabled;
bool rx_processing;
bool delay_main_work;
@@ -823,6 +843,7 @@ struct mwifiex_adapter {
u16 gen_null_pkt;
u16 pps_uapsd_mode;
u32 pm_wakeup_fw_try;
+ struct timer_list wakeup_timer;
u8 is_hs_configured;
struct mwifiex_hs_config_param hs_cfg;
u8 hs_activated;
@@ -865,6 +886,8 @@ struct mwifiex_adapter {
struct memory_type_mapping *mem_type_mapping_tbl;
u8 num_mem_types;
u8 curr_mem_idx;
+ void *drv_info_dump;
+ u32 drv_info_size;
bool scan_chan_gap_enabled;
struct sk_buff_head rx_data_q;
struct mwifiex_chan_stats *chan_stats;
@@ -979,7 +1002,7 @@ void mwifiex_wmm_del_peer_ra_list(struct mwifiex_private *priv,
const u8 *ra_addr);
void *mwifiex_process_sta_txpd(struct mwifiex_private *, struct sk_buff *skb);
void *mwifiex_process_uap_txpd(struct mwifiex_private *, struct sk_buff *skb);
-int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta);
+int mwifiex_sta_init_cmd(struct mwifiex_private *, u8 first_sta, bool init);
int mwifiex_cmd_802_11_scan(struct host_cmd_ds_command *cmd,
struct mwifiex_scan_cmd_config *scan_cfg);
void mwifiex_queue_scan_cmd(struct mwifiex_private *priv,
@@ -1140,6 +1163,25 @@ mwifiex_get_priv(struct mwifiex_adapter *adapter,
}
/*
+ * This function returns the first available unused private structure pointer.
+ */
+static inline struct mwifiex_private *
+mwifiex_get_unused_priv(struct mwifiex_adapter *adapter)
+{
+ int i;
+
+ for (i = 0; i < adapter->priv_num; i++) {
+ if (adapter->priv[i]) {
+ if (adapter->priv[i]->bss_mode ==
+ NL80211_IFTYPE_UNSPECIFIED)
+ break;
+ }
+ }
+
+ return ((i < adapter->priv_num) ? adapter->priv[i] : NULL);
+}
+
+/*
* This function returns the driver private structure of a network device.
*/
static inline struct mwifiex_private *
@@ -1230,8 +1272,6 @@ int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
struct ieee80211_channel *chan,
unsigned int duration);
-int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role);
-
int mwifiex_get_stats_info(struct mwifiex_private *priv,
struct mwifiex_ds_get_stats *log);
@@ -1291,9 +1331,17 @@ int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_beacon_data *data);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
+void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_chan_def chandef);
+int mwifiex_config_start_uap(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg);
void mwifiex_uap_del_sta_data(struct mwifiex_private *priv,
struct mwifiex_sta_node *node);
+void mwifiex_init_11h_params(struct mwifiex_private *priv);
+int mwifiex_is_11h_active(struct mwifiex_private *priv);
+int mwifiex_11h_activate(struct mwifiex_private *priv, bool flag);
+
void mwifiex_11h_process_join(struct mwifiex_private *priv, u8 **buffer,
struct mwifiex_bssdescriptor *bss_desc);
int mwifiex_11h_handle_event_chanswann(struct mwifiex_private *priv);
@@ -1324,6 +1372,8 @@ void mwifiex_process_tdls_action_frame(struct mwifiex_private *priv,
u8 *buf, int len);
int mwifiex_tdls_oper(struct mwifiex_private *priv, const u8 *peer, u8 action);
int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac);
+int mwifiex_get_tdls_list(struct mwifiex_private *priv,
+ struct tdls_peer_info *buf);
void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv);
bool mwifiex_is_bss_in_11ac_mode(struct mwifiex_private *priv);
u8 mwifiex_get_center_freq_index(struct mwifiex_private *priv, u8 band,
@@ -1340,6 +1390,11 @@ void mwifiex_check_auto_tdls(unsigned long context);
void mwifiex_add_auto_tdls_peer(struct mwifiex_private *priv, const u8 *mac);
void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv);
void mwifiex_clean_auto_tdls(struct mwifiex_private *priv);
+int mwifiex_cmd_issue_chan_report_request(struct mwifiex_private *priv,
+ struct host_cmd_ds_command *cmd,
+ void *data_buf);
+int mwifiex_11h_handle_chanrpt_ready(struct mwifiex_private *priv,
+ struct sk_buff *skb);
void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
void *event_body);
@@ -1347,6 +1402,21 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
struct sk_buff *
mwifiex_clone_skb_for_tx_status(struct mwifiex_private *priv,
struct sk_buff *skb, u8 flag, u64 *cookie);
+void mwifiex_dfs_cac_work_queue(struct work_struct *work);
+void mwifiex_dfs_chan_sw_work_queue(struct work_struct *work);
+void mwifiex_abort_cac(struct mwifiex_private *priv);
+int mwifiex_11h_handle_radar_detected(struct mwifiex_private *priv,
+ struct sk_buff *skb);
+
+void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
+ s8 nflr);
+void mwifiex_hist_data_reset(struct mwifiex_private *priv);
+void mwifiex_hist_data_add(struct mwifiex_private *priv,
+ u8 rx_rate, s8 snr, s8 nflr);
+u8 mwifiex_adjust_data_rate(struct mwifiex_private *priv,
+ u8 rx_rate, u8 ht_info);
+
+void mwifiex_dump_drv_info(struct mwifiex_adapter *adapter);
#ifdef CONFIG_DEBUG_FS
void mwifiex_debugfs_init(void);
diff --git a/drivers/net/wireless/mwifiex/pcie.c b/drivers/net/wireless/mwifiex/pcie.c
index c3a20f94f3c9..a5828da59365 100644
--- a/drivers/net/wireless/mwifiex/pcie.c
+++ b/drivers/net/wireless/mwifiex/pcie.c
@@ -204,6 +204,7 @@ static int mwifiex_pcie_probe(struct pci_dev *pdev,
card->pcie.blksz_fw_dl = data->blksz_fw_dl;
card->pcie.tx_buf_size = data->tx_buf_size;
card->pcie.supports_fw_dump = data->supports_fw_dump;
+ card->pcie.can_ext_scan = data->can_ext_scan;
}
if (mwifiex_add_card(card, &add_remove_card_sem, &pcie_ops,
@@ -1952,8 +1953,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
offset += txlen;
} while (true);
- dev_dbg(adapter->dev, "info:\nFW download over, size %d bytes\n",
- offset);
+ dev_notice(adapter->dev,
+ "info: FW download over, size %d bytes\n", offset);
ret = 0;
@@ -2064,6 +2065,7 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
* state until cookie is set */
adapter->ps_state = PS_STATE_AWAKE;
adapter->pm_wakeup_fw_try = false;
+ del_timer(&adapter->wakeup_timer);
}
}
}
@@ -2562,6 +2564,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
adapter->mem_type_mapping_tbl = mem_type_mapping_tbl;
adapter->num_mem_types = ARRAY_SIZE(mem_type_mapping_tbl);
strcpy(adapter->fw_name, card->pcie.firmware);
+ adapter->ext_scan = card->pcie.can_ext_scan;
return 0;
}
diff --git a/drivers/net/wireless/mwifiex/pcie.h b/drivers/net/wireless/mwifiex/pcie.h
index 200e8b0cb582..666d40e9dbc3 100644
--- a/drivers/net/wireless/mwifiex/pcie.h
+++ b/drivers/net/wireless/mwifiex/pcie.h
@@ -206,6 +206,7 @@ struct mwifiex_pcie_device {
u16 blksz_fw_dl;
u16 tx_buf_size;
bool supports_fw_dump;
+ bool can_ext_scan;
};
static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
@@ -214,6 +215,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8766 = {
.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
.supports_fw_dump = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
@@ -222,6 +224,7 @@ static const struct mwifiex_pcie_device mwifiex_pcie8897 = {
.blksz_fw_dl = MWIFIEX_PCIE_BLOCK_SIZE_FW_DNLD,
.tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K,
.supports_fw_dump = true,
+ .can_ext_scan = true,
};
struct mwifiex_evt_buf_desc {
diff --git a/drivers/net/wireless/mwifiex/scan.c b/drivers/net/wireless/mwifiex/scan.c
index 984a7a4fa93b..0ffdb7c5afd2 100644
--- a/drivers/net/wireless/mwifiex/scan.c
+++ b/drivers/net/wireless/mwifiex/scan.c
@@ -496,10 +496,10 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
for (band = 0; (band < IEEE80211_NUM_BANDS) ; band++) {
- if (!priv->wdev->wiphy->bands[band])
+ if (!priv->wdev.wiphy->bands[band])
continue;
- sband = priv->wdev->wiphy->bands[band];
+ sband = priv->wdev.wiphy->bands[band];
for (i = 0; (i < sband->n_channels) ; i++) {
ch = &sband->channels[i];
@@ -1429,6 +1429,12 @@ int mwifiex_scan_networks(struct mwifiex_private *priv,
return -EBUSY;
}
+ if (adapter->surprise_removed || adapter->is_cmd_timedout) {
+ dev_err(adapter->dev,
+ "Ignore scan. Card removed or firmware in bad state\n");
+ return -EFAULT;
+ }
+
spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
adapter->scan_processing = true;
spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -1727,10 +1733,10 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
freq = cfp ? cfp->freq : 0;
- chan = ieee80211_get_channel(priv->wdev->wiphy, freq);
+ chan = ieee80211_get_channel(priv->wdev.wiphy, freq);
if (chan && !(chan->flags & IEEE80211_CHAN_DISABLED)) {
- bss = cfg80211_inform_bss(priv->wdev->wiphy,
+ bss = cfg80211_inform_bss(priv->wdev.wiphy,
chan, CFG80211_BSS_FTYPE_UNKNOWN,
bssid, timestamp,
cap_info_bitmap, beacon_period,
@@ -1742,7 +1748,7 @@ mwifiex_parse_single_response_buf(struct mwifiex_private *priv, u8 **bss_info,
!memcmp(bssid, priv->curr_bss_params.bss_descriptor
.mac_address, ETH_ALEN))
mwifiex_update_curr_bss_params(priv, bss);
- cfg80211_put_bss(priv->wdev->wiphy, bss);
+ cfg80211_put_bss(priv->wdev.wiphy, bss);
}
} else {
dev_dbg(adapter->dev, "missing BSS channel IE\n");
diff --git a/drivers/net/wireless/mwifiex/sdio.c b/drivers/net/wireless/mwifiex/sdio.c
index 933dae137850..91e36cda9543 100644
--- a/drivers/net/wireless/mwifiex/sdio.c
+++ b/drivers/net/wireless/mwifiex/sdio.c
@@ -107,6 +107,7 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
card->mp_rx_agg_buf_size = data->mp_rx_agg_buf_size;
card->supports_fw_dump = data->supports_fw_dump;
card->auto_tdls = data->auto_tdls;
+ card->can_ext_scan = data->can_ext_scan;
}
sdio_claim_host(func);
@@ -282,6 +283,9 @@ static int mwifiex_sdio_suspend(struct device *dev)
#define SDIO_DEVICE_ID_MARVELL_8897 (0x912d)
/* Device ID for SD8887 */
#define SDIO_DEVICE_ID_MARVELL_8887 (0x9135)
+/* Device ID for SD8801 */
+#define SDIO_DEVICE_ID_MARVELL_8801 (0x9139)
+
/* WLAN IDs */
static const struct sdio_device_id mwifiex_ids[] = {
@@ -295,6 +299,8 @@ static const struct sdio_device_id mwifiex_ids[] = {
.driver_data = (unsigned long) &mwifiex_sdio_sd8897},
{SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8887),
.driver_data = (unsigned long)&mwifiex_sdio_sd8887},
+ {SDIO_DEVICE(SDIO_VENDOR_ID_MARVELL, SDIO_DEVICE_ID_MARVELL_8801),
+ .driver_data = (unsigned long)&mwifiex_sdio_sd8801},
{},
};
@@ -986,8 +992,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
offset += txlen;
} while (true);
- dev_dbg(adapter->dev, "info: FW download over, size %d bytes\n",
- offset);
+ dev_notice(adapter->dev,
+ "info: FW download over, size %d bytes\n", offset);
ret = 0;
done:
@@ -1882,6 +1888,7 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
}
adapter->auto_tdls = card->auto_tdls;
+ adapter->ext_scan = card->can_ext_scan;
return ret;
}
@@ -1958,8 +1965,8 @@ static void mwifiex_sdio_card_reset_work(struct mwifiex_adapter *adapter)
pr_err("Resetting card...\n");
mmc_remove_host(target);
- /* 20ms delay is based on experiment with sdhci controller */
- mdelay(20);
+ /* 200ms delay is based on experiment with sdhci controller */
+ mdelay(200);
target->rescan_entered = 0; /* rescan non-removable cards */
mmc_add_host(target);
}
@@ -2023,6 +2030,8 @@ static void mwifiex_sdio_fw_dump_work(struct work_struct *work)
u32 memory_size;
static char *env[] = { "DRIVER=mwifiex_sdio", "EVENT=fw_dump", NULL };
+ mwifiex_dump_drv_info(adapter);
+
if (!card->supports_fw_dump)
return;
@@ -2166,6 +2175,99 @@ static void mwifiex_sdio_fw_dump(struct mwifiex_adapter *adapter)
schedule_work(&adapter->iface_work);
}
+/* Function to dump SDIO function registers and SDIO scratch registers in case
+ * of FW crash
+ */
+static int
+mwifiex_sdio_reg_dump(struct mwifiex_adapter *adapter, char *drv_buf)
+{
+ char *p = drv_buf;
+ struct sdio_mmc_card *cardp = adapter->card;
+ int ret = 0;
+ u8 count, func, data, index = 0, size = 0;
+ u8 reg, reg_start, reg_end;
+ char buf[256], *ptr;
+
+ if (!p)
+ return 0;
+
+ dev_info(adapter->dev, "SDIO register DUMP START\n");
+
+ mwifiex_pm_wakeup_card(adapter);
+
+ sdio_claim_host(cardp->func);
+
+ for (count = 0; count < 5; count++) {
+ memset(buf, 0, sizeof(buf));
+ ptr = buf;
+
+ switch (count) {
+ case 0:
+ /* Read the registers of SDIO function0 */
+ func = count;
+ reg_start = 0;
+ reg_end = 9;
+ break;
+ case 1:
+ /* Read the registers of SDIO function1 */
+ func = count;
+ reg_start = cardp->reg->func1_dump_reg_start;
+ reg_end = cardp->reg->func1_dump_reg_end;
+ break;
+ case 2:
+ index = 0;
+ func = 1;
+ reg_start = cardp->reg->func1_spec_reg_table[index++];
+ size = cardp->reg->func1_spec_reg_num;
+ reg_end = cardp->reg->func1_spec_reg_table[size-1];
+ break;
+ default:
+ /* Read the scratch registers of SDIO function1 */
+ if (count == 4)
+ mdelay(100);
+ func = 1;
+ reg_start = cardp->reg->func1_scratch_reg;
+ reg_end = reg_start + MWIFIEX_SDIO_SCRATCH_SIZE;
+ }
+
+ if (count != 2)
+ ptr += sprintf(ptr, "SDIO Func%d (%#x-%#x): ",
+ func, reg_start, reg_end);
+ else
+ ptr += sprintf(ptr, "SDIO Func%d: ", func);
+
+ for (reg = reg_start; reg <= reg_end;) {
+ if (func == 0)
+ data = sdio_f0_readb(cardp->func, reg, &ret);
+ else
+ data = sdio_readb(cardp->func, reg, &ret);
+
+ if (count == 2)
+ ptr += sprintf(ptr, "(%#x) ", reg);
+ if (!ret) {
+ ptr += sprintf(ptr, "%02x ", data);
+ } else {
+ ptr += sprintf(ptr, "ERR");
+ break;
+ }
+
+ if (count == 2 && reg < reg_end)
+ reg = cardp->reg->func1_spec_reg_table[index++];
+ else
+ reg++;
+ }
+
+ dev_info(adapter->dev, "%s\n", buf);
+ p += sprintf(p, "%s\n", buf);
+ }
+
+ sdio_release_host(cardp->func);
+
+ dev_info(adapter->dev, "SDIO register DUMP END\n");
+
+ return p - drv_buf;
+}
+
static struct mwifiex_if_ops sdio_ops = {
.init_if = mwifiex_init_sdio,
.cleanup_if = mwifiex_cleanup_sdio,
@@ -2188,6 +2290,7 @@ static struct mwifiex_if_ops sdio_ops = {
.card_reset = mwifiex_sdio_card_reset,
.iface_work = mwifiex_sdio_work,
.fw_dump = mwifiex_sdio_fw_dump,
+ .reg_dump = mwifiex_sdio_reg_dump,
};
/*
diff --git a/drivers/net/wireless/mwifiex/sdio.h b/drivers/net/wireless/mwifiex/sdio.h
index 54c07156dd78..957cca246618 100644
--- a/drivers/net/wireless/mwifiex/sdio.h
+++ b/drivers/net/wireless/mwifiex/sdio.h
@@ -34,6 +34,7 @@
#define SD8797_DEFAULT_FW_NAME "mrvl/sd8797_uapsta.bin"
#define SD8897_DEFAULT_FW_NAME "mrvl/sd8897_uapsta.bin"
#define SD8887_DEFAULT_FW_NAME "mrvl/sd8887_uapsta.bin"
+#define SD8801_DEFAULT_FW_NAME "mrvl/sd8801_uapsta.bin"
#define BLOCK_MODE 1
#define BYTE_MODE 0
@@ -44,6 +45,9 @@
#define MWIFIEX_SDIO_BYTE_MODE_MASK 0x80000000
+#define MWIFIEX_MAX_FUNC2_REG_NUM 13
+#define MWIFIEX_SDIO_SCRATCH_SIZE 10
+
#define SDIO_MPA_ADDR_BASE 0x1000
#define CTRL_PORT 0
#define CTRL_PORT_MASK 0x0001
@@ -219,6 +223,11 @@ struct mwifiex_sdio_card_reg {
u8 fw_dump_ctrl;
u8 fw_dump_start;
u8 fw_dump_end;
+ u8 func1_dump_reg_start;
+ u8 func1_dump_reg_end;
+ u8 func1_scratch_reg;
+ u8 func1_spec_reg_num;
+ u8 func1_spec_reg_table[MWIFIEX_MAX_FUNC2_REG_NUM];
};
struct sdio_mmc_card {
@@ -247,6 +256,7 @@ struct sdio_mmc_card {
u8 *mp_regs;
u8 auto_tdls;
+ bool can_ext_scan;
struct mwifiex_sdio_mpa_tx mpa_tx;
struct mwifiex_sdio_mpa_rx mpa_rx;
@@ -264,6 +274,7 @@ struct mwifiex_sdio_device {
u32 mp_tx_agg_buf_size;
u32 mp_rx_agg_buf_size;
u8 auto_tdls;
+ bool can_ext_scan;
};
static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
@@ -291,6 +302,11 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd87xx = {
.rd_len_p0_l = 0x08,
.rd_len_p0_u = 0x09,
.card_misc_cfg_reg = 0x6c,
+ .func1_dump_reg_start = 0x0,
+ .func1_dump_reg_end = 0x9,
+ .func1_scratch_reg = 0x60,
+ .func1_spec_reg_num = 5,
+ .func1_spec_reg_table = {0x28, 0x30, 0x34, 0x38, 0x3c},
};
static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {
@@ -335,6 +351,12 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8897 = {
.fw_dump_ctrl = 0xe2,
.fw_dump_start = 0xe3,
.fw_dump_end = 0xea,
+ .func1_dump_reg_start = 0x0,
+ .func1_dump_reg_end = 0xb,
+ .func1_scratch_reg = 0xc0,
+ .func1_spec_reg_num = 8,
+ .func1_spec_reg_table = {0x4C, 0x50, 0x54, 0x55, 0x58,
+ 0x59, 0x5c, 0x5d},
};
static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = {
@@ -376,6 +398,13 @@ static const struct mwifiex_sdio_card_reg mwifiex_reg_sd8887 = {
.cmd_cfg_1 = 0xc5,
.cmd_cfg_2 = 0xc6,
.cmd_cfg_3 = 0xc7,
+ .func1_dump_reg_start = 0x10,
+ .func1_dump_reg_end = 0x17,
+ .func1_scratch_reg = 0x90,
+ .func1_spec_reg_num = 13,
+ .func1_spec_reg_table = {0x08, 0x58, 0x5C, 0x5D, 0x60,
+ 0x61, 0x62, 0x64, 0x65, 0x66,
+ 0x68, 0x69, 0x6a},
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
@@ -390,6 +419,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8786 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
.supports_fw_dump = false,
.auto_tdls = false,
+ .can_ext_scan = false,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
@@ -404,6 +434,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8787 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
.supports_fw_dump = false,
.auto_tdls = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
@@ -418,6 +449,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8797 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
.supports_fw_dump = false,
.auto_tdls = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
@@ -432,6 +464,7 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8897 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
.supports_fw_dump = true,
.auto_tdls = false,
+ .can_ext_scan = true,
};
static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
@@ -446,6 +479,22 @@ static const struct mwifiex_sdio_device mwifiex_sdio_sd8887 = {
.mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_32K,
.supports_fw_dump = false,
.auto_tdls = true,
+ .can_ext_scan = true,
+};
+
+static const struct mwifiex_sdio_device mwifiex_sdio_sd8801 = {
+ .firmware = SD8801_DEFAULT_FW_NAME,
+ .reg = &mwifiex_reg_sd87xx,
+ .max_ports = 16,
+ .mp_agg_pkt_limit = 8,
+ .supports_sdio_new_mode = false,
+ .has_control_mask = true,
+ .tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K,
+ .mp_tx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+ .mp_rx_agg_buf_size = MWIFIEX_MP_AGGR_BUF_SIZE_16K,
+ .supports_fw_dump = false,
+ .auto_tdls = false,
+ .can_ext_scan = true,
};
/*
diff --git a/drivers/net/wireless/mwifiex/sta_cmd.c b/drivers/net/wireless/mwifiex/sta_cmd.c
index 1c2ca291d1f5..f7d204ffd6e9 100644
--- a/drivers/net/wireless/mwifiex/sta_cmd.c
+++ b/drivers/net/wireless/mwifiex/sta_cmd.c
@@ -26,6 +26,10 @@
#include "11n.h"
#include "11ac.h"
+static bool disable_auto_ds;
+module_param(disable_auto_ds, bool, 0);
+MODULE_PARM_DESC(disable_auto_ds,
+ "deepsleep enabled=0(default), deepsleep disabled=1");
/*
* This function prepares command to set/get RSSI information.
*
@@ -1893,6 +1897,10 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_cmd_tdls_oper(priv, cmd_ptr, data_buf);
break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ ret = mwifiex_cmd_issue_chan_report_request(priv, cmd_ptr,
+ data_buf);
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd- %#x\n", cmd_no);
@@ -1907,6 +1915,8 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
*
* This is called after firmware download to bring the card to
* working state.
+ * Function is also called during reinitialization of virtual
+ * interfaces.
*
* The following commands are issued sequentially -
* - Set PCI-Express host buffer configuration (PCIE only)
@@ -1921,7 +1931,7 @@ int mwifiex_sta_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
* - Set 11d control
* - Set MAC control (this must be the last command to initialize firmware)
*/
-int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
+int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
{
struct mwifiex_adapter *adapter = priv->adapter;
int ret;
@@ -2031,7 +2041,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
- if (first_sta && priv->adapter->iface_type != MWIFIEX_USB &&
+ if (!disable_auto_ds &&
+ first_sta && priv->adapter->iface_type != MWIFIEX_USB &&
priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable auto deep sleep */
auto_ds.auto_ds = DEEP_SLEEP_ON;
@@ -2054,9 +2065,6 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
"11D: failed to enable 11D\n");
}
- /* set last_init_cmd before sending the command */
- priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
-
/* Send cmd to FW to configure 11n specific configuration
* (Short GI, Channel BW, Green field support etc.) for transmit
*/
@@ -2064,7 +2072,11 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
ret = mwifiex_send_cmd(priv, HostCmd_CMD_11N_CFG,
HostCmd_ACT_GEN_SET, 0, &tx_cfg, true);
- ret = -EINPROGRESS;
+ if (init) {
+ /* set last_init_cmd before sending the command */
+ priv->adapter->last_init_cmd = HostCmd_CMD_11N_CFG;
+ ret = -EINPROGRESS;
+ }
return ret;
}
diff --git a/drivers/net/wireless/mwifiex/sta_cmdresp.c b/drivers/net/wireless/mwifiex/sta_cmdresp.c
index b65e1014b0fc..5f8da5924666 100644
--- a/drivers/net/wireless/mwifiex/sta_cmdresp.c
+++ b/drivers/net/wireless/mwifiex/sta_cmdresp.c
@@ -248,6 +248,8 @@ static int mwifiex_ret_get_log(struct mwifiex_private *priv,
le32_to_cpu(get_log->wep_icv_err_cnt[2]);
stats->wep_icv_error[3] =
le32_to_cpu(get_log->wep_icv_err_cnt[3]);
+ stats->bcn_rcv_cnt = le32_to_cpu(get_log->bcn_rcv_cnt);
+ stats->bcn_miss_cnt = le32_to_cpu(get_log->bcn_miss_cnt);
}
return 0;
@@ -1103,6 +1105,9 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_UAP_SYS_CONFIG:
break;
case HostCmd_CMD_UAP_BSS_START:
+ adapter->tx_lock_flag = false;
+ adapter->pps_uapsd_mode = false;
+ adapter->delay_null_pkt = false;
priv->bss_started = 1;
break;
case HostCmd_CMD_UAP_BSS_STOP:
@@ -1117,6 +1122,8 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_TDLS_OPER:
ret = mwifiex_ret_tdls_oper(priv, resp);
break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);
diff --git a/drivers/net/wireless/mwifiex/sta_event.c b/drivers/net/wireless/mwifiex/sta_event.c
index b8c171df6223..80ffe7412496 100644
--- a/drivers/net/wireless/mwifiex/sta_event.c
+++ b/drivers/net/wireless/mwifiex/sta_event.c
@@ -90,6 +90,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
priv->is_data_rate_auto = true;
priv->data_rate = 0;
+ if ((GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
+ GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) && priv->hist_data)
+ mwifiex_hist_data_reset(priv);
+
if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
priv->adhoc_state = ADHOC_IDLE;
priv->adhoc_is_link_sensed = false;
@@ -308,6 +312,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
adapter->ps_state = PS_STATE_AWAKE;
adapter->pm_wakeup_card_req = false;
adapter->pm_wakeup_fw_try = false;
+ del_timer_sync(&adapter->wakeup_timer);
break;
}
if (!mwifiex_send_null_packet
@@ -322,6 +327,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
adapter->ps_state = PS_STATE_AWAKE;
adapter->pm_wakeup_card_req = false;
adapter->pm_wakeup_fw_try = false;
+ del_timer_sync(&adapter->wakeup_timer);
break;
@@ -480,7 +486,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_REMAIN_ON_CHAN_EXPIRED:
dev_dbg(adapter->dev, "event: Remain on channel expired\n");
- cfg80211_remain_on_channel_expired(priv->wdev,
+ cfg80211_remain_on_channel_expired(&priv->wdev,
priv->roc_cfg.cookie,
&priv->roc_cfg.chan,
GFP_ATOMIC);
@@ -509,6 +515,16 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
+ case EVENT_CHANNEL_REPORT_RDY:
+ dev_dbg(adapter->dev, "event: Channel Report\n");
+ ret = mwifiex_11h_handle_chanrpt_ready(priv,
+ adapter->event_skb);
+ break;
+ case EVENT_RADAR_DETECTED:
+ dev_dbg(adapter->dev, "event: Radar detected\n");
+ ret = mwifiex_11h_handle_radar_detected(priv,
+ adapter->event_skb);
+ break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/sta_ioctl.c b/drivers/net/wireless/mwifiex/sta_ioctl.c
index 1626868a4b5c..0599e41e253c 100644
--- a/drivers/net/wireless/mwifiex/sta_ioctl.c
+++ b/drivers/net/wireless/mwifiex/sta_ioctl.c
@@ -219,7 +219,7 @@ static int mwifiex_process_country_ie(struct mwifiex_private *priv,
if (!strncmp(priv->adapter->country_code, &country_ie[2], 2)) {
rcu_read_unlock();
- wiphy_dbg(priv->wdev->wiphy,
+ wiphy_dbg(priv->wdev.wiphy,
"11D: skip setting domain info in FW\n");
return 0;
}
@@ -902,9 +902,12 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
if (wep_key->key_length) {
void *enc_key;
- if (encrypt_key->key_disable)
+ if (encrypt_key->key_disable) {
memset(&priv->wep_key[index], 0,
sizeof(struct mwifiex_wep_key));
+ if (wep_key->key_length)
+ goto done;
+ }
if (adapter->key_api_major_ver == KEY_API_VER_MAJOR_V2)
enc_key = encrypt_key;
@@ -918,6 +921,7 @@ static int mwifiex_sec_ioctl_set_wep_key(struct mwifiex_private *priv,
return ret;
}
+done:
if (priv->sec_info.wep_enabled)
priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
else
@@ -1131,36 +1135,6 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
return roc_cfg.status;
}
-int
-mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role)
-{
- if (GET_BSS_ROLE(priv) == bss_role) {
- dev_dbg(priv->adapter->dev,
- "info: already in the desired role.\n");
- return 0;
- }
-
- mwifiex_free_priv(priv);
- mwifiex_init_priv(priv);
-
- priv->bss_role = bss_role;
- switch (bss_role) {
- case MWIFIEX_BSS_ROLE_UAP:
- priv->bss_mode = NL80211_IFTYPE_AP;
- break;
- case MWIFIEX_BSS_ROLE_STA:
- case MWIFIEX_BSS_ROLE_ANY:
- default:
- priv->bss_mode = NL80211_IFTYPE_STATION;
- break;
- }
-
- mwifiex_send_cmd(priv, HostCmd_CMD_SET_BSS_MODE,
- HostCmd_ACT_GEN_SET, 0, NULL, true);
-
- return mwifiex_sta_init_cmd(priv, false);
-}
-
/*
* Sends IOCTL request to get statistics information.
*
diff --git a/drivers/net/wireless/mwifiex/sta_rx.c b/drivers/net/wireless/mwifiex/sta_rx.c
index c2ad3b63ae70..b8729c9394e9 100644
--- a/drivers/net/wireless/mwifiex/sta_rx.c
+++ b/drivers/net/wireless/mwifiex/sta_rx.c
@@ -90,6 +90,7 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
struct ethhdr *eth;
u16 rx_pkt_off, rx_pkt_len;
u8 *offset;
+ u8 adj_rx_rate = 0;
local_rx_pd = (struct rxpd *) (skb->data);
@@ -155,6 +156,14 @@ int mwifiex_process_rx_packet(struct mwifiex_private *priv,
priv->rxpd_htinfo = local_rx_pd->ht_info;
+ if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA ||
+ GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP) {
+ adj_rx_rate = mwifiex_adjust_data_rate(priv, priv->rxpd_rate,
+ priv->rxpd_htinfo);
+ mwifiex_hist_data_add(priv, adj_rx_rate, local_rx_pd->snr,
+ local_rx_pd->nf);
+ }
+
ret = mwifiex_recv_packet(priv, skb);
if (ret == -1)
dev_err(priv->adapter->dev, "recv packet failed\n");
diff --git a/drivers/net/wireless/mwifiex/sta_tx.c b/drivers/net/wireless/mwifiex/sta_tx.c
index b896d7375b52..5ce2d9a4f919 100644
--- a/drivers/net/wireless/mwifiex/sta_tx.c
+++ b/drivers/net/wireless/mwifiex/sta_tx.c
@@ -47,8 +47,10 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
struct txpd *local_tx_pd;
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
- u8 pad;
+ unsigned int pad;
u16 pkt_type, pkt_offset;
+ int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 :
+ INTF_HEADER_LEN;
if (!skb->len) {
dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
@@ -56,13 +58,12 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
return skb->data;
}
- pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
+ BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN);
- /* If skb->data is not aligned; add padding */
- pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;
+ pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
- BUG_ON(skb_headroom(skb) < (sizeof(*local_tx_pd) + INTF_HEADER_LEN
- + pad));
+ pad = ((void *)skb->data - (sizeof(*local_tx_pd) + hroom)-
+ NULL) & (MWIFIEX_DMA_ALIGN_SZ - 1);
skb_push(skb, sizeof(*local_tx_pd) + pad);
local_tx_pd = (struct txpd *) skb->data;
@@ -70,8 +71,8 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
local_tx_pd->bss_num = priv->bss_num;
local_tx_pd->bss_type = priv->bss_type;
local_tx_pd->tx_pkt_length = cpu_to_le16((u16)(skb->len -
- (sizeof(struct txpd)
- + pad)));
+ (sizeof(struct txpd) +
+ pad)));
local_tx_pd->priority = (u8) skb->priority;
local_tx_pd->pkt_delay_2ms =
@@ -115,7 +116,7 @@ void *mwifiex_process_sta_txpd(struct mwifiex_private *priv,
local_tx_pd->tx_pkt_offset = cpu_to_le16(pkt_offset);
/* make space for INTF_HEADER_LEN */
- skb_push(skb, INTF_HEADER_LEN);
+ skb_push(skb, hroom);
if (!local_tx_pd->tx_control)
/* TxCtrl set by user or default */
@@ -182,9 +183,13 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
}
switch (ret) {
case -EBUSY:
- adapter->data_sent = true;
- /* Fall through FAILURE handling */
+ dev_kfree_skb_any(skb);
+ dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
+ __func__, ret);
+ adapter->dbg.num_tx_host_to_card_failure++;
+ break;
case -1:
+ adapter->data_sent = false;
dev_kfree_skb_any(skb);
dev_err(adapter->dev, "%s: host_to_card failed: ret=%d\n",
__func__, ret);
@@ -197,6 +202,7 @@ int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags)
adapter->tx_lock_flag = true;
break;
case -EINPROGRESS:
+ adapter->tx_lock_flag = true;
break;
default:
break;
diff --git a/drivers/net/wireless/mwifiex/tdls.c b/drivers/net/wireless/mwifiex/tdls.c
index 22884b429be7..087d84762cd3 100644
--- a/drivers/net/wireless/mwifiex/tdls.c
+++ b/drivers/net/wireless/mwifiex/tdls.c
@@ -1123,6 +1123,36 @@ int mwifiex_get_tdls_link_status(struct mwifiex_private *priv, const u8 *mac)
return TDLS_NOT_SETUP;
}
+int mwifiex_get_tdls_list(struct mwifiex_private *priv,
+ struct tdls_peer_info *buf)
+{
+ struct mwifiex_sta_node *sta_ptr;
+ struct tdls_peer_info *peer = buf;
+ int count = 0;
+ unsigned long flags;
+
+ if (!ISSUPP_TDLS_ENABLED(priv->adapter->fw_cap_info))
+ return 0;
+
+ /* make sure we are in station mode and connected */
+ if (!(priv->bss_type == MWIFIEX_BSS_TYPE_STA && priv->media_connected))
+ return 0;
+
+ spin_lock_irqsave(&priv->sta_list_spinlock, flags);
+ list_for_each_entry(sta_ptr, &priv->sta_list, list) {
+ if (sta_ptr->tdls_status == TDLS_SETUP_COMPLETE) {
+ ether_addr_copy(peer->peer_addr, sta_ptr->mac_addr);
+ peer++;
+ count++;
+ if (count >= MWIFIEX_MAX_TDLS_PEER_SUPPORTED)
+ break;
+ }
+ }
+ spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
+
+ return count;
+}
+
void mwifiex_disable_all_tdls_links(struct mwifiex_private *priv)
{
struct mwifiex_sta_node *sta_ptr;
@@ -1367,9 +1397,8 @@ void mwifiex_check_auto_tdls(unsigned long context)
void mwifiex_setup_auto_tdls_timer(struct mwifiex_private *priv)
{
- init_timer(&priv->auto_tdls_timer);
- priv->auto_tdls_timer.function = mwifiex_check_auto_tdls;
- priv->auto_tdls_timer.data = (unsigned long)priv;
+ setup_timer(&priv->auto_tdls_timer, mwifiex_check_auto_tdls,
+ (unsigned long)priv);
priv->auto_tdls_timer_active = true;
mod_timer(&priv->auto_tdls_timer,
jiffies + msecs_to_jiffies(MWIFIEX_TIMER_10S));
diff --git a/drivers/net/wireless/mwifiex/txrx.c b/drivers/net/wireless/mwifiex/txrx.c
index 6ae133333363..ac93557cbdc9 100644
--- a/drivers/net/wireless/mwifiex/txrx.c
+++ b/drivers/net/wireless/mwifiex/txrx.c
@@ -227,7 +227,7 @@ void mwifiex_parse_tx_status_event(struct mwifiex_private *priv,
/* consumes ack_skb */
skb_complete_wifi_ack(ack_skb, !tx_status->status);
} else {
- cfg80211_mgmt_tx_status(priv->wdev, tx_info->cookie,
+ cfg80211_mgmt_tx_status(&priv->wdev, tx_info->cookie,
ack_skb->data, ack_skb->len,
!tx_status->status, GFP_ATOMIC);
dev_kfree_skb_any(ack_skb);
diff --git a/drivers/net/wireless/mwifiex/uap_cmd.c b/drivers/net/wireless/mwifiex/uap_cmd.c
index 0f347fdefa0a..f5c2af01ba0a 100644
--- a/drivers/net/wireless/mwifiex/uap_cmd.c
+++ b/drivers/net/wireless/mwifiex/uap_cmd.c
@@ -761,6 +761,11 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
if (mwifiex_cmd_uap_sta_deauth(priv, cmd, data_buf))
return -1;
break;
+ case HostCmd_CMD_CHAN_REPORT_REQUEST:
+ if (mwifiex_cmd_issue_chan_report_request(priv, cmd_buf,
+ data_buf))
+ return -1;
+ break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd %#x\n", cmd_no);
@@ -769,3 +774,68 @@ int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
return 0;
}
+
+void mwifiex_uap_set_channel(struct mwifiex_uap_bss_param *bss_cfg,
+ struct cfg80211_chan_def chandef)
+{
+ u8 config_bands = 0;
+
+ bss_cfg->channel = ieee80211_frequency_to_channel(
+ chandef.chan->center_freq);
+
+ /* Set appropriate bands */
+ if (chandef.chan->band == IEEE80211_BAND_2GHZ) {
+ bss_cfg->band_cfg = BAND_CONFIG_BG;
+ config_bands = BAND_B | BAND_G;
+
+ if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+ config_bands |= BAND_GN;
+ } else {
+ bss_cfg->band_cfg = BAND_CONFIG_A;
+ config_bands = BAND_A;
+
+ if (chandef.width > NL80211_CHAN_WIDTH_20_NOHT)
+ config_bands |= BAND_AN;
+
+ if (chandef.width > NL80211_CHAN_WIDTH_40)
+ config_bands |= BAND_AAC;
+ }
+}
+
+int mwifiex_config_start_uap(struct mwifiex_private *priv,
+ struct mwifiex_uap_bss_param *bss_cfg)
+{
+ if (mwifiex_del_mgmt_ies(priv))
+ dev_err(priv->adapter->dev, "Failed to delete mgmt IEs!\n");
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_STOP,
+ HostCmd_ACT_GEN_SET, 0, NULL, true)) {
+ dev_err(priv->adapter->dev, "Failed to stop the BSS\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_SYS_CONFIG,
+ HostCmd_ACT_GEN_SET,
+ UAP_BSS_PARAMS_I, bss_cfg, false)) {
+ dev_err(priv->adapter->dev, "Failed to set the SSID\n");
+ return -1;
+ }
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_UAP_BSS_START,
+ HostCmd_ACT_GEN_SET, 0, NULL, false)) {
+ dev_err(priv->adapter->dev, "Failed to start the BSS\n");
+ return -1;
+ }
+
+ if (priv->sec_info.wep_enabled)
+ priv->curr_pkt_filter |= HostCmd_ACT_MAC_WEP_ENABLE;
+ else
+ priv->curr_pkt_filter &= ~HostCmd_ACT_MAC_WEP_ENABLE;
+
+ if (mwifiex_send_cmd(priv, HostCmd_CMD_MAC_CONTROL,
+ HostCmd_ACT_GEN_SET, 0,
+ &priv->curr_pkt_filter, true))
+ return -1;
+
+ return 0;
+}
diff --git a/drivers/net/wireless/mwifiex/uap_event.c b/drivers/net/wireless/mwifiex/uap_event.c
index c54a537e31fb..f4794cdc36d2 100644
--- a/drivers/net/wireless/mwifiex/uap_event.c
+++ b/drivers/net/wireless/mwifiex/uap_event.c
@@ -68,7 +68,6 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
len = ETH_ALEN;
if (len != -1) {
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
sinfo.assoc_req_ies = &event->data[len];
len = (u8 *)sinfo.assoc_req_ies -
(u8 *)&event->frame_control;
@@ -132,6 +131,8 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body + 2,
ETH_ALEN);
+ if (priv->hist_data)
+ mwifiex_hist_data_reset(priv);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
@@ -177,6 +178,53 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
dev_dbg(adapter->dev, "event: TX_STATUS Report\n");
mwifiex_parse_tx_status_event(priv, adapter->event_body);
break;
+ case EVENT_PS_SLEEP:
+ dev_dbg(adapter->dev, "info: EVENT: SLEEP\n");
+
+ adapter->ps_state = PS_STATE_PRE_SLEEP;
+
+ mwifiex_check_ps_cond(adapter);
+ break;
+
+ case EVENT_PS_AWAKE:
+ dev_dbg(adapter->dev, "info: EVENT: AWAKE\n");
+ if (!adapter->pps_uapsd_mode &&
+ priv->media_connected && adapter->sleep_period.period) {
+ adapter->pps_uapsd_mode = true;
+ dev_dbg(adapter->dev,
+ "event: PPS/UAPSD mode activated\n");
+ }
+ adapter->tx_lock_flag = false;
+ if (adapter->pps_uapsd_mode && adapter->gen_null_pkt) {
+ if (mwifiex_check_last_packet_indication(priv)) {
+ if (adapter->data_sent) {
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_card_req = false;
+ adapter->pm_wakeup_fw_try = false;
+ break;
+ }
+ if (!mwifiex_send_null_packet
+ (priv,
+ MWIFIEX_TxPD_POWER_MGMT_NULL_PACKET |
+ MWIFIEX_TxPD_POWER_MGMT_LAST_PACKET))
+ adapter->ps_state =
+ PS_STATE_SLEEP;
+ return 0;
+ }
+ }
+ adapter->ps_state = PS_STATE_AWAKE;
+ adapter->pm_wakeup_card_req = false;
+ adapter->pm_wakeup_fw_try = false;
+ break;
+
+ case EVENT_CHANNEL_REPORT_RDY:
+ dev_dbg(adapter->dev, "event: Channel Report\n");
+ mwifiex_11h_handle_chanrpt_ready(priv, adapter->event_skb);
+ break;
+ case EVENT_RADAR_DETECTED:
+ dev_dbg(adapter->dev, "event: Radar detected\n");
+ mwifiex_11h_handle_radar_detected(priv, adapter->event_skb);
+ break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);
diff --git a/drivers/net/wireless/mwifiex/uap_txrx.c b/drivers/net/wireless/mwifiex/uap_txrx.c
index be3a203a529b..38ac4d74c486 100644
--- a/drivers/net/wireless/mwifiex/uap_txrx.c
+++ b/drivers/net/wireless/mwifiex/uap_txrx.c
@@ -348,8 +348,10 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
struct mwifiex_adapter *adapter = priv->adapter;
struct uap_txpd *txpd;
struct mwifiex_txinfo *tx_info = MWIFIEX_SKB_TXCB(skb);
- int pad, len;
- u16 pkt_type;
+ int pad;
+ u16 pkt_type, pkt_offset;
+ int hroom = (priv->adapter->iface_type == MWIFIEX_USB) ? 0 :
+ INTF_HEADER_LEN;
if (!skb->len) {
dev_err(adapter->dev, "Tx: bad packet length: %d\n", skb->len);
@@ -357,22 +359,21 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
return skb->data;
}
- pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
-
- /* If skb->data is not aligned, add padding */
- pad = (4 - (((void *)skb->data - NULL) & 0x3)) % 4;
+ BUG_ON(skb_headroom(skb) < MWIFIEX_MIN_DATA_HEADER_LEN);
- len = sizeof(*txpd) + pad;
+ pkt_type = mwifiex_is_skb_mgmt_frame(skb) ? PKT_TYPE_MGMT : 0;
- BUG_ON(skb_headroom(skb) < len + INTF_HEADER_LEN);
+ pad = ((void *)skb->data - (sizeof(*txpd) + hroom) - NULL) &
+ (MWIFIEX_DMA_ALIGN_SZ - 1);
- skb_push(skb, len);
+ skb_push(skb, sizeof(*txpd) + pad);
txpd = (struct uap_txpd *)skb->data;
memset(txpd, 0, sizeof(*txpd));
txpd->bss_num = priv->bss_num;
txpd->bss_type = priv->bss_type;
- txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - len));
+ txpd->tx_pkt_length = cpu_to_le16((u16)(skb->len - (sizeof(*txpd) +
+ pad)));
txpd->priority = (u8)skb->priority;
txpd->pkt_delay_2ms = mwifiex_wmm_compute_drv_pkt_delay(priv, skb);
@@ -392,16 +393,17 @@ void *mwifiex_process_uap_txpd(struct mwifiex_private *priv,
cpu_to_le32(priv->wmm.user_pri_pkt_tx_ctrl[txpd->priority]);
/* Offset of actual data */
+ pkt_offset = sizeof(*txpd) + pad;
if (pkt_type == PKT_TYPE_MGMT) {
/* Set the packet type and add header for management frame */
txpd->tx_pkt_type = cpu_to_le16(pkt_type);
- len += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
+ pkt_offset += MWIFIEX_MGMT_FRAME_HEADER_SIZE;
}
- txpd->tx_pkt_offset = cpu_to_le16(len);
+ txpd->tx_pkt_offset = cpu_to_le16(pkt_offset);
/* make space for INTF_HEADER_LEN */
- skb_push(skb, INTF_HEADER_LEN);
+ skb_push(skb, hroom);
if (!txpd->tx_control)
/* TxCtrl set by user or default */
diff --git a/drivers/net/wireless/mwifiex/usb.c b/drivers/net/wireless/mwifiex/usb.c
index 1b56495ec872..223873022ffe 100644
--- a/drivers/net/wireless/mwifiex/usb.c
+++ b/drivers/net/wireless/mwifiex/usb.c
@@ -37,6 +37,11 @@ static struct usb_device_id mwifiex_usb_table[] = {
{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8797_PID_2,
USB_CLASS_VENDOR_SPEC,
USB_SUBCLASS_VENDOR_SPEC, 0xff)},
+ /* 8801 */
+ {USB_DEVICE(USB8XXX_VID, USB8801_PID_1)},
+ {USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8801_PID_2,
+ USB_CLASS_VENDOR_SPEC,
+ USB_SUBCLASS_VENDOR_SPEC, 0xff)},
/* 8897 */
{USB_DEVICE(USB8XXX_VID, USB8897_PID_1)},
{USB_DEVICE_AND_INTERFACE_INFO(USB8XXX_VID, USB8897_PID_2,
@@ -361,11 +366,13 @@ static int mwifiex_usb_probe(struct usb_interface *intf,
switch (id_product) {
case USB8766_PID_1:
case USB8797_PID_1:
+ case USB8801_PID_1:
case USB8897_PID_1:
card->usb_boot_state = USB8XXX_FW_DNLD;
break;
case USB8766_PID_2:
case USB8797_PID_2:
+ case USB8801_PID_2:
case USB8897_PID_2:
card->usb_boot_state = USB8XXX_FW_READY;
break;
@@ -792,11 +799,19 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
case USB8897_PID_2:
adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_4K;
strcpy(adapter->fw_name, USB8897_DEFAULT_FW_NAME);
+ adapter->ext_scan = true;
break;
case USB8766_PID_1:
case USB8766_PID_2:
adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
strcpy(adapter->fw_name, USB8766_DEFAULT_FW_NAME);
+ adapter->ext_scan = true;
+ break;
+ case USB8801_PID_1:
+ case USB8801_PID_2:
+ adapter->tx_buf_size = MWIFIEX_TX_DATA_BUF_SIZE_2K;
+ strcpy(adapter->fw_name, USB8801_DEFAULT_FW_NAME);
+ adapter->ext_scan = false;
break;
case USB8797_PID_1:
case USB8797_PID_2:
@@ -930,7 +945,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
} while ((dnld_cmd != FW_HAS_LAST_BLOCK) && retries);
cleanup:
- dev_dbg(adapter->dev, "%s: %d bytes downloaded\n", __func__, tlen);
+ dev_notice(adapter->dev,
+ "info: FW download over, size %d bytes\n", tlen);
kfree(recv_buff);
kfree(fwdata);
@@ -990,6 +1006,7 @@ static int mwifiex_pm_wakeup_card(struct mwifiex_adapter *adapter)
{
/* Simulation of HS_AWAKE event */
adapter->pm_wakeup_fw_try = false;
+ del_timer_sync(&adapter->wakeup_timer);
adapter->pm_wakeup_card_req = false;
adapter->ps_state = PS_STATE_AWAKE;
@@ -1010,6 +1027,13 @@ static void mwifiex_usb_submit_rem_rx_urbs(struct mwifiex_adapter *adapter)
}
}
+/* This function is called after the card has woken up. */
+static inline int
+mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
+{
+ return 0;
+}
+
static struct mwifiex_if_ops usb_ops = {
.register_dev = mwifiex_register_dev,
.unregister_dev = mwifiex_unregister_dev,
@@ -1074,4 +1098,5 @@ MODULE_VERSION(USB_VERSION);
MODULE_LICENSE("GPL v2");
MODULE_FIRMWARE(USB8766_DEFAULT_FW_NAME);
MODULE_FIRMWARE(USB8797_DEFAULT_FW_NAME);
+MODULE_FIRMWARE(USB8801_DEFAULT_FW_NAME);
MODULE_FIRMWARE(USB8897_DEFAULT_FW_NAME);
diff --git a/drivers/net/wireless/mwifiex/usb.h b/drivers/net/wireless/mwifiex/usb.h
index a7cbba1355af..57e1a5736318 100644
--- a/drivers/net/wireless/mwifiex/usb.h
+++ b/drivers/net/wireless/mwifiex/usb.h
@@ -30,6 +30,9 @@
#define USB8797_PID_2 0x2044
#define USB8897_PID_1 0x2045
#define USB8897_PID_2 0x2046
+#define USB8801_PID_1 0x2049
+#define USB8801_PID_2 0x204a
+
#define USB8XXX_FW_DNLD 1
#define USB8XXX_FW_READY 2
@@ -41,6 +44,7 @@
#define USB8766_DEFAULT_FW_NAME "mrvl/usb8766_uapsta.bin"
#define USB8797_DEFAULT_FW_NAME "mrvl/usb8797_uapsta.bin"
+#define USB8801_DEFAULT_FW_NAME "mrvl/usb8801_uapsta.bin"
#define USB8897_DEFAULT_FW_NAME "mrvl/usb8897_uapsta.bin"
#define FW_DNLD_TX_BUF_SIZE 620
@@ -96,11 +100,4 @@ struct fw_data {
u8 data[1];
};
-/* This function is called after the card has woken up. */
-static inline int
-mwifiex_pm_wakeup_card_complete(struct mwifiex_adapter *adapter)
-{
- return 0;
-}
-
#endif /*_MWIFIEX_USB_H */
diff --git a/drivers/net/wireless/mwifiex/util.c b/drivers/net/wireless/mwifiex/util.c
index b1768fbf98f2..308550611f22 100644
--- a/drivers/net/wireless/mwifiex/util.c
+++ b/drivers/net/wireless/mwifiex/util.c
@@ -25,6 +25,96 @@
#include "wmm.h"
#include "11n.h"
+static struct mwifiex_debug_data items[] = {
+ {"int_counter", item_size(int_counter),
+ item_addr(int_counter), 1},
+ {"wmm_ac_vo", item_size(packets_out[WMM_AC_VO]),
+ item_addr(packets_out[WMM_AC_VO]), 1},
+ {"wmm_ac_vi", item_size(packets_out[WMM_AC_VI]),
+ item_addr(packets_out[WMM_AC_VI]), 1},
+ {"wmm_ac_be", item_size(packets_out[WMM_AC_BE]),
+ item_addr(packets_out[WMM_AC_BE]), 1},
+ {"wmm_ac_bk", item_size(packets_out[WMM_AC_BK]),
+ item_addr(packets_out[WMM_AC_BK]), 1},
+ {"tx_buf_size", item_size(tx_buf_size),
+ item_addr(tx_buf_size), 1},
+ {"curr_tx_buf_size", item_size(curr_tx_buf_size),
+ item_addr(curr_tx_buf_size), 1},
+ {"ps_mode", item_size(ps_mode),
+ item_addr(ps_mode), 1},
+ {"ps_state", item_size(ps_state),
+ item_addr(ps_state), 1},
+ {"is_deep_sleep", item_size(is_deep_sleep),
+ item_addr(is_deep_sleep), 1},
+ {"wakeup_dev_req", item_size(pm_wakeup_card_req),
+ item_addr(pm_wakeup_card_req), 1},
+ {"wakeup_tries", item_size(pm_wakeup_fw_try),
+ item_addr(pm_wakeup_fw_try), 1},
+ {"hs_configured", item_size(is_hs_configured),
+ item_addr(is_hs_configured), 1},
+ {"hs_activated", item_size(hs_activated),
+ item_addr(hs_activated), 1},
+ {"num_tx_timeout", item_size(num_tx_timeout),
+ item_addr(num_tx_timeout), 1},
+ {"is_cmd_timedout", item_size(is_cmd_timedout),
+ item_addr(is_cmd_timedout), 1},
+ {"timeout_cmd_id", item_size(timeout_cmd_id),
+ item_addr(timeout_cmd_id), 1},
+ {"timeout_cmd_act", item_size(timeout_cmd_act),
+ item_addr(timeout_cmd_act), 1},
+ {"last_cmd_id", item_size(last_cmd_id),
+ item_addr(last_cmd_id), DBG_CMD_NUM},
+ {"last_cmd_act", item_size(last_cmd_act),
+ item_addr(last_cmd_act), DBG_CMD_NUM},
+ {"last_cmd_index", item_size(last_cmd_index),
+ item_addr(last_cmd_index), 1},
+ {"last_cmd_resp_id", item_size(last_cmd_resp_id),
+ item_addr(last_cmd_resp_id), DBG_CMD_NUM},
+ {"last_cmd_resp_index", item_size(last_cmd_resp_index),
+ item_addr(last_cmd_resp_index), 1},
+ {"last_event", item_size(last_event),
+ item_addr(last_event), DBG_CMD_NUM},
+ {"last_event_index", item_size(last_event_index),
+ item_addr(last_event_index), 1},
+ {"num_cmd_h2c_fail", item_size(num_cmd_host_to_card_failure),
+ item_addr(num_cmd_host_to_card_failure), 1},
+ {"num_cmd_sleep_cfm_fail",
+ item_size(num_cmd_sleep_cfm_host_to_card_failure),
+ item_addr(num_cmd_sleep_cfm_host_to_card_failure), 1},
+ {"num_tx_h2c_fail", item_size(num_tx_host_to_card_failure),
+ item_addr(num_tx_host_to_card_failure), 1},
+ {"num_evt_deauth", item_size(num_event_deauth),
+ item_addr(num_event_deauth), 1},
+ {"num_evt_disassoc", item_size(num_event_disassoc),
+ item_addr(num_event_disassoc), 1},
+ {"num_evt_link_lost", item_size(num_event_link_lost),
+ item_addr(num_event_link_lost), 1},
+ {"num_cmd_deauth", item_size(num_cmd_deauth),
+ item_addr(num_cmd_deauth), 1},
+ {"num_cmd_assoc_ok", item_size(num_cmd_assoc_success),
+ item_addr(num_cmd_assoc_success), 1},
+ {"num_cmd_assoc_fail", item_size(num_cmd_assoc_failure),
+ item_addr(num_cmd_assoc_failure), 1},
+ {"cmd_sent", item_size(cmd_sent),
+ item_addr(cmd_sent), 1},
+ {"data_sent", item_size(data_sent),
+ item_addr(data_sent), 1},
+ {"cmd_resp_received", item_size(cmd_resp_received),
+ item_addr(cmd_resp_received), 1},
+ {"event_received", item_size(event_received),
+ item_addr(event_received), 1},
+
+ /* variables defined in struct mwifiex_adapter */
+ {"cmd_pending", adapter_item_size(cmd_pending),
+ adapter_item_addr(cmd_pending), 1},
+ {"tx_pending", adapter_item_size(tx_pending),
+ adapter_item_addr(tx_pending), 1},
+ {"rx_pending", adapter_item_size(rx_pending),
+ adapter_item_addr(rx_pending), 1},
+};
+
+static int num_of_items = ARRAY_SIZE(items);
+
/*
* Firmware initialization complete callback handler.
*
@@ -97,6 +187,8 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
info->rx_tbl);
info->tx_tbl_num = mwifiex_get_tx_ba_stream_tbl(priv,
info->tx_tbl);
+ info->tdls_peer_num = mwifiex_get_tdls_list(priv,
+ info->tdls_list);
info->ps_mode = adapter->ps_mode;
info->ps_state = adapter->ps_state;
info->is_deep_sleep = adapter->is_deep_sleep;
@@ -141,6 +233,93 @@ int mwifiex_get_debug_info(struct mwifiex_private *priv,
return 0;
}
+int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf,
+ struct mwifiex_debug_info *info)
+{
+ char *p = buf;
+ struct mwifiex_debug_data *d = &items[0];
+ size_t size, addr;
+ long val;
+ int i, j;
+
+ if (!info)
+ return 0;
+
+ for (i = 0; i < num_of_items; i++) {
+ p += sprintf(p, "%s=", d[i].name);
+
+ size = d[i].size / d[i].num;
+
+ if (i < (num_of_items - 3))
+ addr = d[i].addr + (size_t)info;
+ else /* The last 3 items are struct mwifiex_adapter variables */
+ addr = d[i].addr + (size_t)priv->adapter;
+
+ for (j = 0; j < d[i].num; j++) {
+ switch (size) {
+ case 1:
+ val = *((u8 *)addr);
+ break;
+ case 2:
+ val = *((u16 *)addr);
+ break;
+ case 4:
+ val = *((u32 *)addr);
+ break;
+ case 8:
+ val = *((long long *)addr);
+ break;
+ default:
+ val = -1;
+ break;
+ }
+
+ p += sprintf(p, "%#lx ", val);
+ addr += size;
+ }
+
+ p += sprintf(p, "\n");
+ }
+
+ if (info->tx_tbl_num) {
+ p += sprintf(p, "Tx BA stream table:\n");
+ for (i = 0; i < info->tx_tbl_num; i++)
+ p += sprintf(p, "tid = %d, ra = %pM\n",
+ info->tx_tbl[i].tid, info->tx_tbl[i].ra);
+ }
+
+ if (info->rx_tbl_num) {
+ p += sprintf(p, "Rx reorder table:\n");
+ for (i = 0; i < info->rx_tbl_num; i++) {
+ p += sprintf(p, "tid = %d, ta = %pM, ",
+ info->rx_tbl[i].tid,
+ info->rx_tbl[i].ta);
+ p += sprintf(p, "start_win = %d, ",
+ info->rx_tbl[i].start_win);
+ p += sprintf(p, "win_size = %d, buffer: ",
+ info->rx_tbl[i].win_size);
+
+ for (j = 0; j < info->rx_tbl[i].win_size; j++)
+ p += sprintf(p, "%c ",
+ info->rx_tbl[i].buffer[j] ?
+ '1' : '0');
+
+ p += sprintf(p, "\n");
+ }
+ }
+
+ if (info->tdls_peer_num) {
+ p += sprintf(p, "TDLS peer table:\n");
+ for (i = 0; i < info->tdls_peer_num; i++) {
+ p += sprintf(p, "peer = %pM",
+ info->tdls_list[i].peer_addr);
+ p += sprintf(p, "\n");
+ }
+ }
+
+ return p - buf;
+}
+
static int
mwifiex_parse_mgmt_packet(struct mwifiex_private *priv, u8 *payload, u16 len,
struct rxpd *rx_pd)
@@ -208,7 +387,7 @@ mwifiex_process_mgmt_packet(struct mwifiex_private *priv,
pkt_len -= ETH_ALEN + sizeof(pkt_len);
rx_pd->rx_pkt_length = cpu_to_le16(pkt_len);
- cfg80211_rx_mgmt(priv->wdev, priv->roc_cfg.chan.center_freq,
+ cfg80211_rx_mgmt(&priv->wdev, priv->roc_cfg.chan.center_freq,
CAL_RSSI(rx_pd->snr, rx_pd->nf), skb->data, pkt_len,
0);
@@ -404,3 +583,44 @@ void mwifiex_del_all_sta_list(struct mwifiex_private *priv)
spin_unlock_irqrestore(&priv->sta_list_spinlock, flags);
return;
}
+
+/* This function adds histogram data to histogram array*/
+void mwifiex_hist_data_add(struct mwifiex_private *priv,
+ u8 rx_rate, s8 snr, s8 nflr)
+{
+ struct mwifiex_histogram_data *phist_data = priv->hist_data;
+
+ if (atomic_read(&phist_data->num_samples) > MWIFIEX_HIST_MAX_SAMPLES)
+ mwifiex_hist_data_reset(priv);
+ mwifiex_hist_data_set(priv, rx_rate, snr, nflr);
+}
+
+/* function to add histogram record */
+void mwifiex_hist_data_set(struct mwifiex_private *priv, u8 rx_rate, s8 snr,
+ s8 nflr)
+{
+ struct mwifiex_histogram_data *phist_data = priv->hist_data;
+
+ atomic_inc(&phist_data->num_samples);
+ atomic_inc(&phist_data->rx_rate[rx_rate]);
+ atomic_inc(&phist_data->snr[snr]);
+ atomic_inc(&phist_data->noise_flr[128 + nflr]);
+ atomic_inc(&phist_data->sig_str[nflr - snr]);
+}
+
+/* function to reset histogram data during init/reset */
+void mwifiex_hist_data_reset(struct mwifiex_private *priv)
+{
+ int ix;
+ struct mwifiex_histogram_data *phist_data = priv->hist_data;
+
+ atomic_set(&phist_data->num_samples, 0);
+ for (ix = 0; ix < MWIFIEX_MAX_AC_RX_RATES; ix++)
+ atomic_set(&phist_data->rx_rate[ix], 0);
+ for (ix = 0; ix < MWIFIEX_MAX_SNR; ix++)
+ atomic_set(&phist_data->snr[ix], 0);
+ for (ix = 0; ix < MWIFIEX_MAX_NOISE_FLR; ix++)
+ atomic_set(&phist_data->noise_flr[ix], 0);
+ for (ix = 0; ix < MWIFIEX_MAX_SIG_STRENGTH; ix++)
+ atomic_set(&phist_data->sig_str[ix], 0);
+}
diff --git a/drivers/net/wireless/mwifiex/util.h b/drivers/net/wireless/mwifiex/util.h
index 40296cb4a3f1..b541d66c01eb 100644
--- a/drivers/net/wireless/mwifiex/util.h
+++ b/drivers/net/wireless/mwifiex/util.h
@@ -20,6 +20,8 @@
#ifndef _MWIFIEX_UTIL_H_
#define _MWIFIEX_UTIL_H_
+struct mwifiex_private;
+
struct mwifiex_dma_mapping {
dma_addr_t addr;
size_t len;
@@ -33,6 +35,21 @@ struct mwifiex_cb {
};
};
+/* size/addr for mwifiex_debug_info */
+#define item_size(n) (FIELD_SIZEOF(struct mwifiex_debug_info, n))
+#define item_addr(n) (offsetof(struct mwifiex_debug_info, n))
+
+/* size/addr for struct mwifiex_adapter */
+#define adapter_item_size(n) (FIELD_SIZEOF(struct mwifiex_adapter, n))
+#define adapter_item_addr(n) (offsetof(struct mwifiex_adapter, n))
+
+struct mwifiex_debug_data {
+ char name[32]; /* variable/array name */
+ u32 size; /* size of the variable/array */
+ size_t addr; /* address of the variable/array */
+ int num; /* number of variables in an array */
+};
+
static inline struct mwifiex_rxinfo *MWIFIEX_SKB_RXCB(struct sk_buff *skb)
{
struct mwifiex_cb *cb = (struct mwifiex_cb *)skb->cb;
@@ -73,4 +90,7 @@ static inline dma_addr_t MWIFIEX_SKB_DMA_ADDR(struct sk_buff *skb)
return mapping.addr;
}
+int mwifiex_debug_info_to_buffer(struct mwifiex_private *priv, char *buf,
+ struct mwifiex_debug_info *info);
+
#endif /* !_MWIFIEX_UTIL_H_ */
diff --git a/drivers/net/wireless/mwifiex/wmm.c b/drivers/net/wireless/mwifiex/wmm.c
index ffffd2c5a76e..ef717acec8b7 100644
--- a/drivers/net/wireless/mwifiex/wmm.c
+++ b/drivers/net/wireless/mwifiex/wmm.c
@@ -1228,6 +1228,9 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
case -EINPROGRESS:
if (adapter->iface_type != MWIFIEX_PCIE)
adapter->data_sent = false;
+ break;
+ case 0:
+ mwifiex_write_data_complete(adapter, skb, 0, ret);
default:
break;
}
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
index b8d1e04aa9b9..f9b1218c761a 100644
--- a/drivers/net/wireless/mwl8k.c
+++ b/drivers/net/wireless/mwl8k.c
@@ -3098,14 +3098,14 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv,
cca_cnt = ioread32(priv->regs + NOK_CCA_CNT_REG);
cca_cnt /= 1000; /* uSecs to mSecs */
- survey->channel_time_busy = (u64) cca_cnt;
+ survey->time_busy = (u64) cca_cnt;
rx_rdy = ioread32(priv->regs + BBU_RXRDY_CNT_REG);
rx_rdy /= 1000; /* uSecs to mSecs */
- survey->channel_time_rx = (u64) rx_rdy;
+ survey->time_rx = (u64) rx_rdy;
priv->channel_time = jiffies - priv->channel_time;
- survey->channel_time = jiffies_to_msecs(priv->channel_time);
+ survey->time = jiffies_to_msecs(priv->channel_time);
survey->channel = channel;
@@ -3115,9 +3115,9 @@ static void mwl8k_update_survey(struct mwl8k_priv *priv,
survey->noise = nf * -1;
survey->filled = SURVEY_INFO_NOISE_DBM |
- SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_RX;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_RX;
}
/*
diff --git a/drivers/net/wireless/orinoco/Kconfig b/drivers/net/wireless/orinoco/Kconfig
index 60698b020851..6d831d4d1b5f 100644
--- a/drivers/net/wireless/orinoco/Kconfig
+++ b/drivers/net/wireless/orinoco/Kconfig
@@ -1,7 +1,8 @@
config HERMES
tristate "Hermes chipset 802.11b support (Orinoco/Prism2/Symbol)"
depends on (PPC_PMAC || PCI || PCMCIA)
- depends on CFG80211 && CFG80211_WEXT
+ depends on CFG80211
+ select CFG80211_WEXT
select WIRELESS_EXT
select WEXT_SPY
select WEXT_PRIV
diff --git a/drivers/net/wireless/orinoco/main.c b/drivers/net/wireless/orinoco/main.c
index 38ec8d19ac29..c410180479e6 100644
--- a/drivers/net/wireless/orinoco/main.c
+++ b/drivers/net/wireless/orinoco/main.c
@@ -2342,7 +2342,7 @@ void free_orinocodev(struct orinoco_private *priv)
list_for_each_entry_safe(sd, sdtemp, &priv->scan_list, list) {
list_del(&sd->list);
- if ((sd->len > 0) && sd->buf)
+ if (sd->len > 0)
kfree(sd->buf);
kfree(sd);
}
diff --git a/drivers/net/wireless/orinoco/orinoco_pci.c b/drivers/net/wireless/orinoco/orinoco_pci.c
index b6bdad632842..74219d59d7e1 100644
--- a/drivers/net/wireless/orinoco/orinoco_pci.c
+++ b/drivers/net/wireless/orinoco/orinoco_pci.c
@@ -94,7 +94,7 @@ static int orinoco_pci_cor_reset(struct orinoco_private *priv)
mdelay(HERMES_PCI_COR_OFFT);
/* The card is ready when it's no longer busy */
- timeout = jiffies + (HERMES_PCI_COR_BUSYT * HZ / 1000);
+ timeout = jiffies + msecs_to_jiffies(HERMES_PCI_COR_BUSYT);
reg = hermes_read_regn(hw, CMD);
while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
mdelay(1);
diff --git a/drivers/net/wireless/orinoco/orinoco_plx.c b/drivers/net/wireless/orinoco/orinoco_plx.c
index b8f6e5c431ae..8b045236b6e0 100644
--- a/drivers/net/wireless/orinoco/orinoco_plx.c
+++ b/drivers/net/wireless/orinoco/orinoco_plx.c
@@ -121,7 +121,7 @@ static int orinoco_plx_cor_reset(struct orinoco_private *priv)
mdelay(1);
/* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + (PLX_RESET_TIME * HZ / 1000);
+ timeout = jiffies + msecs_to_jiffies(PLX_RESET_TIME);
reg = hermes_read_regn(hw, CMD);
while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
mdelay(1);
diff --git a/drivers/net/wireless/orinoco/orinoco_tmd.c b/drivers/net/wireless/orinoco/orinoco_tmd.c
index 79d0e33b625e..20ce569b8a43 100644
--- a/drivers/net/wireless/orinoco/orinoco_tmd.c
+++ b/drivers/net/wireless/orinoco/orinoco_tmd.c
@@ -71,7 +71,7 @@ static int orinoco_tmd_cor_reset(struct orinoco_private *priv)
mdelay(1);
/* Just in case, wait more until the card is no longer busy */
- timeout = jiffies + (TMD_RESET_TIME * HZ / 1000);
+ timeout = jiffies + msecs_to_jiffies(TMD_RESET_TIME);
reg = hermes_read_regn(hw, CMD);
while (time_before(jiffies, timeout) && (reg & HERMES_CMD_BUSY)) {
mdelay(1);
diff --git a/drivers/net/wireless/orinoco/orinoco_usb.c b/drivers/net/wireless/orinoco/orinoco_usb.c
index 995846422dc0..91f05442de28 100644
--- a/drivers/net/wireless/orinoco/orinoco_usb.c
+++ b/drivers/net/wireless/orinoco/orinoco_usb.c
@@ -364,9 +364,7 @@ static struct request_context *ezusb_alloc_ctx(struct ezusb_priv *upriv,
atomic_set(&ctx->refcount, 1);
init_completion(&ctx->done);
- init_timer(&ctx->timer);
- ctx->timer.function = ezusb_request_timerfn;
- ctx->timer.data = (u_long) ctx;
+ setup_timer(&ctx->timer, ezusb_request_timerfn, (u_long)ctx);
return ctx;
}
diff --git a/drivers/net/wireless/p54/eeprom.c b/drivers/net/wireless/p54/eeprom.c
index 0fe67d2da208..2fe713eda7ad 100644
--- a/drivers/net/wireless/p54/eeprom.c
+++ b/drivers/net/wireless/p54/eeprom.c
@@ -196,9 +196,9 @@ static int p54_generate_band(struct ieee80211_hw *dev,
dest->max_power = chan->max_power;
priv->survey[*chan_num].channel = &tmp->channels[j];
priv->survey[*chan_num].filled = SURVEY_INFO_NOISE_DBM |
- SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_TX;
+ SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_TX;
dest->hw_value = (*chan_num);
j++;
(*chan_num)++;
diff --git a/drivers/net/wireless/p54/fwio.c b/drivers/net/wireless/p54/fwio.c
index bc065e8e348b..5367d510b22d 100644
--- a/drivers/net/wireless/p54/fwio.c
+++ b/drivers/net/wireless/p54/fwio.c
@@ -220,6 +220,7 @@ int p54_download_eeprom(struct p54_common *priv, void *buf,
struct sk_buff *skb;
size_t eeprom_hdr_size;
int ret = 0;
+ long timeout;
if (priv->fw_var >= 0x509)
eeprom_hdr_size = sizeof(*eeprom_hdr);
@@ -249,9 +250,11 @@ int p54_download_eeprom(struct p54_common *priv, void *buf,
p54_tx(priv, skb);
- if (!wait_for_completion_interruptible_timeout(
- &priv->eeprom_comp, HZ)) {
- wiphy_err(priv->hw->wiphy, "device does not respond!\n");
+ timeout = wait_for_completion_interruptible_timeout(
+ &priv->eeprom_comp, HZ);
+ if (timeout <= 0) {
+ wiphy_err(priv->hw->wiphy,
+ "device does not respond or signal received!\n");
ret = -EBUSY;
}
priv->eeprom = NULL;
diff --git a/drivers/net/wireless/p54/main.c b/drivers/net/wireless/p54/main.c
index 97aeff0edb84..b9250d75d253 100644
--- a/drivers/net/wireless/p54/main.c
+++ b/drivers/net/wireless/p54/main.c
@@ -305,9 +305,9 @@ static void p54_reset_stats(struct p54_common *priv)
struct survey_info *info = &priv->survey[chan->hw_value];
/* only reset channel statistics, don't touch .filled, etc. */
- info->channel_time = 0;
- info->channel_time_busy = 0;
- info->channel_time_tx = 0;
+ info->time = 0;
+ info->time_busy = 0;
+ info->time_tx = 0;
}
priv->update_stats = true;
@@ -575,6 +575,8 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
key->hw_key_idx = 0xff;
goto out_unlock;
}
+
+ key->flags |= IEEE80211_KEY_FLAG_RESERVE_TAILROOM;
} else {
slot = key->hw_key_idx;
@@ -634,7 +636,7 @@ static int p54_get_survey(struct ieee80211_hw *dev, int idx,
if (in_use) {
/* test if the reported statistics are valid. */
- if (survey->channel_time != 0) {
+ if (survey->time != 0) {
survey->filled |= SURVEY_INFO_IN_USE;
} else {
/*
diff --git a/drivers/net/wireless/p54/p54pci.c b/drivers/net/wireless/p54/p54pci.c
index d4aee64fb5ea..27a49068d32d 100644
--- a/drivers/net/wireless/p54/p54pci.c
+++ b/drivers/net/wireless/p54/p54pci.c
@@ -431,6 +431,7 @@ static int p54p_open(struct ieee80211_hw *dev)
{
struct p54p_priv *priv = dev->priv;
int err;
+ long timeout;
init_completion(&priv->boot_comp);
err = request_irq(priv->pdev->irq, p54p_interrupt,
@@ -468,10 +469,12 @@ static int p54p_open(struct ieee80211_hw *dev)
P54P_WRITE(dev_int, cpu_to_le32(ISL38XX_DEV_INT_RESET));
P54P_READ(dev_int);
- if (!wait_for_completion_interruptible_timeout(&priv->boot_comp, HZ)) {
+ timeout = wait_for_completion_interruptible_timeout(
+ &priv->boot_comp, HZ);
+ if (timeout <= 0) {
wiphy_err(dev->wiphy, "Cannot boot firmware!\n");
p54p_stop(dev);
- return -ETIMEDOUT;
+ return timeout ? -ERESTARTSYS : -ETIMEDOUT;
}
P54P_WRITE(int_enable, cpu_to_le32(ISL38XX_INT_IDENT_UPDATE));
diff --git a/drivers/net/wireless/p54/txrx.c b/drivers/net/wireless/p54/txrx.c
index 153c61539ec8..24e5ff9a9272 100644
--- a/drivers/net/wireless/p54/txrx.c
+++ b/drivers/net/wireless/p54/txrx.c
@@ -587,13 +587,13 @@ static void p54_rx_stats(struct p54_common *priv, struct sk_buff *skb)
if (chan) {
struct survey_info *survey = &priv->survey[chan->hw_value];
survey->noise = clamp(priv->noise, -128, 127);
- survey->channel_time = priv->survey_raw.active;
- survey->channel_time_tx = priv->survey_raw.tx;
- survey->channel_time_busy = priv->survey_raw.tx +
+ survey->time = priv->survey_raw.active;
+ survey->time_tx = priv->survey_raw.tx;
+ survey->time_busy = priv->survey_raw.tx +
priv->survey_raw.cca;
- do_div(survey->channel_time, 1024);
- do_div(survey->channel_time_tx, 1024);
- do_div(survey->channel_time_busy, 1024);
+ do_div(survey->time, 1024);
+ do_div(survey->time_tx, 1024);
+ do_div(survey->time_busy, 1024);
}
tmp = p54_find_and_unlink_skb(priv, hdr->req_id);
diff --git a/drivers/net/wireless/rndis_wlan.c b/drivers/net/wireless/rndis_wlan.c
index 1a4facd1fbf3..60d44ce9c017 100644
--- a/drivers/net/wireless/rndis_wlan.c
+++ b/drivers/net/wireless/rndis_wlan.c
@@ -2478,7 +2478,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev,
ret = rndis_query_oid(usbdev, RNDIS_OID_GEN_LINK_SPEED, &linkspeed, &len);
if (ret == 0) {
sinfo->txrate.legacy = le32_to_cpu(linkspeed) / 1000;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
}
len = sizeof(rssi);
@@ -2486,7 +2486,7 @@ static void rndis_fill_station_info(struct usbnet *usbdev,
&rssi, &len);
if (ret == 0) {
sinfo->signal = level_to_qual(le32_to_cpu(rssi));
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}
}
diff --git a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
index 4834a9abc171..b6cc9ff47fc2 100644
--- a/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
+++ b/drivers/net/wireless/rsi/rsi_91x_sdio_ops.c
@@ -172,7 +172,6 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
(struct rsi_91x_sdiodev *)adapter->rsi_dev;
u32 len;
u32 num_blocks;
- const u8 *fw;
const struct firmware *fw_entry = NULL;
u32 block_size = dev->tx_blk_size;
int status = 0;
@@ -201,7 +200,6 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
return status;
}
- fw = kmemdup(fw_entry->data, fw_entry->size, GFP_KERNEL);
len = fw_entry->size;
if (len % 4)
@@ -212,7 +210,7 @@ static int rsi_load_ta_instructions(struct rsi_common *common)
rsi_dbg(INIT_ZONE, "%s: Instruction size:%d\n", __func__, len);
rsi_dbg(INIT_ZONE, "%s: num blocks: %d\n", __func__, num_blocks);
- status = rsi_copy_to_card(common, fw, len, num_blocks);
+ status = rsi_copy_to_card(common, fw_entry->data, len, num_blocks);
release_firmware(fw_entry);
return status;
}
diff --git a/drivers/net/wireless/rt2x00/Kconfig b/drivers/net/wireless/rt2x00/Kconfig
index 006b8bcb2e31..2b4ef256c6b9 100644
--- a/drivers/net/wireless/rt2x00/Kconfig
+++ b/drivers/net/wireless/rt2x00/Kconfig
@@ -243,14 +243,14 @@ config RT2X00_LIB
select AVERAGE
config RT2X00_LIB_FIRMWARE
- boolean
+ bool
select FW_LOADER
config RT2X00_LIB_CRYPTO
- boolean
+ bool
config RT2X00_LIB_LEDS
- boolean
+ bool
default y if (RT2X00_LIB=y && LEDS_CLASS=y) || (RT2X00_LIB=m && LEDS_CLASS!=n)
config RT2X00_LIB_DEBUGFS
diff --git a/drivers/net/wireless/rt2x00/rt2800lib.c b/drivers/net/wireless/rt2x00/rt2800lib.c
index 81ee481487cf..be2d54f257b1 100644
--- a/drivers/net/wireless/rt2x00/rt2800lib.c
+++ b/drivers/net/wireless/rt2x00/rt2800lib.c
@@ -8020,13 +8020,13 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx,
rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC, &busy_ext);
if (idle || busy) {
- survey->filled = SURVEY_INFO_CHANNEL_TIME |
- SURVEY_INFO_CHANNEL_TIME_BUSY |
- SURVEY_INFO_CHANNEL_TIME_EXT_BUSY;
+ survey->filled = SURVEY_INFO_TIME |
+ SURVEY_INFO_TIME_BUSY |
+ SURVEY_INFO_TIME_EXT_BUSY;
- survey->channel_time = (idle + busy) / 1000;
- survey->channel_time_busy = busy / 1000;
- survey->channel_time_ext_busy = busy_ext / 1000;
+ survey->time = (idle + busy) / 1000;
+ survey->time_busy = busy / 1000;
+ survey->time_ext_busy = busy_ext / 1000;
}
if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL))
diff --git a/drivers/net/wireless/rt2x00/rt2x00config.c b/drivers/net/wireless/rt2x00/rt2x00config.c
index 1122dc44c9fd..48a2cad29477 100644
--- a/drivers/net/wireless/rt2x00/rt2x00config.c
+++ b/drivers/net/wireless/rt2x00/rt2x00config.c
@@ -240,7 +240,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
rt2x00dev->rf_channel = libconf.rf.channel;
}
- if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) &&
(ieee80211_flags & IEEE80211_CONF_CHANGE_PS))
cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
@@ -257,7 +257,7 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
rt2x00link_reset_tuner(rt2x00dev, false);
if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
- test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+ rt2x00_has_cap_flag(rt2x00dev, REQUIRE_PS_AUTOWAKE) &&
(ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
(conf->flags & IEEE80211_CONF_PS)) {
beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
diff --git a/drivers/net/wireless/rt2x00/rt2x00dev.c b/drivers/net/wireless/rt2x00/rt2x00dev.c
index 9967a1d9f0ec..5639ed816813 100644
--- a/drivers/net/wireless/rt2x00/rt2x00dev.c
+++ b/drivers/net/wireless/rt2x00/rt2x00dev.c
@@ -351,7 +351,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
/*
* Remove L2 padding which was added during
*/
- if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_L2PAD))
rt2x00queue_remove_l2pad(entry->skb, header_length);
/*
@@ -460,7 +460,7 @@ void rt2x00lib_txdone(struct queue_entry *entry,
* send the status report back.
*/
if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
- if (test_bit(REQUIRE_TASKLET_CONTEXT, &rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TASKLET_CONTEXT))
ieee80211_tx_status(rt2x00dev->hw, entry->skb);
else
ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
@@ -1056,9 +1056,9 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Take TX headroom required for alignment into account.
*/
- if (test_bit(REQUIRE_L2PAD, &rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_L2PAD))
rt2x00dev->hw->extra_tx_headroom += RT2X00_L2PAD_SIZE;
- else if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags))
+ else if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA))
rt2x00dev->hw->extra_tx_headroom += RT2X00_ALIGN_SIZE;
/*
@@ -1069,7 +1069,7 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
/*
* Allocate tx status FIFO for driver use.
*/
- if (test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags)) {
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO)) {
/*
* Allocate the txstatus fifo. In the worst case the tx
* status fifo has to hold the tx status of all entries
@@ -1131,7 +1131,7 @@ static void rt2x00lib_uninitialize(struct rt2x00_dev *rt2x00dev)
/*
* Stop rfkill polling.
*/
- if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL))
rt2x00rfkill_unregister(rt2x00dev);
/*
@@ -1173,7 +1173,7 @@ static int rt2x00lib_initialize(struct rt2x00_dev *rt2x00dev)
/*
* Start rfkill polling.
*/
- if (test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL))
rt2x00rfkill_register(rt2x00dev);
return 0;
@@ -1389,7 +1389,7 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
/*
* Start rfkill polling.
*/
- if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL))
rt2x00rfkill_register(rt2x00dev);
return 0;
@@ -1408,7 +1408,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
/*
* Stop rfkill polling.
*/
- if (!test_bit(REQUIRE_DELAYED_RFKILL, &rt2x00dev->cap_flags))
+ if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DELAYED_RFKILL))
rt2x00rfkill_unregister(rt2x00dev);
/*
diff --git a/drivers/net/wireless/rt2x00/rt2x00firmware.c b/drivers/net/wireless/rt2x00/rt2x00firmware.c
index fbae2799e3ee..5813300f68a2 100644
--- a/drivers/net/wireless/rt2x00/rt2x00firmware.c
+++ b/drivers/net/wireless/rt2x00/rt2x00firmware.c
@@ -96,7 +96,7 @@ int rt2x00lib_load_firmware(struct rt2x00_dev *rt2x00dev)
{
int retval;
- if (!test_bit(REQUIRE_FIRMWARE, &rt2x00dev->cap_flags))
+ if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_FIRMWARE))
return 0;
if (!rt2x00dev->fw) {
diff --git a/drivers/net/wireless/rt2x00/rt2x00mac.c b/drivers/net/wireless/rt2x00/rt2x00mac.c
index cb40245a0695..300876df056f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00mac.c
+++ b/drivers/net/wireless/rt2x00/rt2x00mac.c
@@ -119,7 +119,7 @@ void rt2x00mac_tx(struct ieee80211_hw *hw,
* Use the ATIM queue if appropriate and present.
*/
if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM &&
- test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags))
+ rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE))
qid = QID_ATIM;
queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
diff --git a/drivers/net/wireless/rt2x00/rt2x00queue.c b/drivers/net/wireless/rt2x00/rt2x00queue.c
index 66ff36447b94..68b620b2462f 100644
--- a/drivers/net/wireless/rt2x00/rt2x00queue.c
+++ b/drivers/net/wireless/rt2x00/rt2x00queue.c
@@ -85,7 +85,7 @@ struct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
memset(skbdesc, 0, sizeof(*skbdesc));
skbdesc->entry = entry;
- if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags)) {
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA)) {
dma_addr_t skb_dma;
skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
@@ -198,7 +198,7 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
- if (!test_bit(REQUIRE_SW_SEQNO, &rt2x00dev->cap_flags)) {
+ if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_SW_SEQNO)) {
/*
* rt2800 has a H/W (or F/W) bug, device incorrectly increase
* seqno on retransmited data (non-QOS) frames. To workaround
@@ -484,7 +484,7 @@ static void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc);
rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc);
- if (test_bit(REQUIRE_HT_TX_DESC, &rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_HT_TX_DESC))
rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc,
sta, hwrate);
else
@@ -526,7 +526,7 @@ static int rt2x00queue_write_tx_data(struct queue_entry *entry,
/*
* Map the skb to DMA.
*/
- if (test_bit(REQUIRE_DMA, &rt2x00dev->cap_flags) &&
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA) &&
rt2x00queue_map_txskb(entry))
return -ENOMEM;
@@ -646,7 +646,7 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
*/
if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
!test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
- if (test_bit(REQUIRE_COPY_IV, &queue->rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_COPY_IV))
rt2x00crypto_tx_copy_iv(skb, &txdesc);
else
rt2x00crypto_tx_remove_iv(skb, &txdesc);
@@ -660,9 +660,9 @@ int rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
* PCI and USB devices, while header alignment only is valid
* for PCI devices.
*/
- if (test_bit(REQUIRE_L2PAD, &queue->rt2x00dev->cap_flags))
+ if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_L2PAD))
rt2x00queue_insert_l2pad(skb, txdesc.header_length);
- else if (test_bit(REQUIRE_DMA, &queue->rt2x00dev->cap_flags))
+ else if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_DMA))
rt2x00queue_align_frame(skb);
/*
@@ -1178,7 +1178,7 @@ int rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
if (status)
goto exit;
- if (test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags)) {
+ if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) {
status = rt2x00queue_alloc_entries(rt2x00dev->atim);
if (status)
goto exit;
@@ -1234,7 +1234,7 @@ int rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
struct data_queue *queue;
enum data_queue_qid qid;
unsigned int req_atim =
- !!test_bit(REQUIRE_ATIM_QUEUE, &rt2x00dev->cap_flags);
+ rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE);
/*
* We need the following queues:
diff --git a/drivers/net/wireless/rt2x00/rt2x00usb.c b/drivers/net/wireless/rt2x00/rt2x00usb.c
index 892270dd3e7b..7627af6098eb 100644
--- a/drivers/net/wireless/rt2x00/rt2x00usb.c
+++ b/drivers/net/wireless/rt2x00/rt2x00usb.c
@@ -274,7 +274,7 @@ static void rt2x00usb_interrupt_txdone(struct urb *urb)
* Schedule the delayed work for reading the TX status
* from the device.
*/
- if (!test_bit(REQUIRE_TXSTATUS_FIFO, &rt2x00dev->cap_flags) ||
+ if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_TXSTATUS_FIFO) ||
!kfifo_is_empty(&rt2x00dev->txstatus_fifo))
queue_work(rt2x00dev->workqueue, &rt2x00dev->txdone_work);
}
@@ -456,7 +456,7 @@ static bool rt2x00usb_flush_entry(struct queue_entry *entry, void *data)
* Kill guardian urb (if required by driver).
*/
if ((entry->queue->qid == QID_BEACON) &&
- (test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags)))
+ (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD)))
usb_kill_urb(bcn_priv->guardian_urb);
return false;
@@ -655,7 +655,7 @@ static int rt2x00usb_alloc_entries(struct data_queue *queue)
* then we are done.
*/
if (queue->qid != QID_BEACON ||
- !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))
+ !rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD))
return 0;
for (i = 0; i < queue->limit; i++) {
@@ -690,7 +690,7 @@ static void rt2x00usb_free_entries(struct data_queue *queue)
* then we are done.
*/
if (queue->qid != QID_BEACON ||
- !test_bit(REQUIRE_BEACON_GUARD, &rt2x00dev->cap_flags))
+ !rt2x00_has_cap_flag(rt2x00dev, REQUIRE_BEACON_GUARD))
return;
for (i = 0; i < queue->limit; i++) {
diff --git a/drivers/net/wireless/rtlwifi/base.c b/drivers/net/wireless/rtlwifi/base.c
index 40b6d1d006d7..1d4677460711 100644
--- a/drivers/net/wireless/rtlwifi/base.c
+++ b/drivers/net/wireless/rtlwifi/base.c
@@ -867,63 +867,135 @@ static u8 _rtl_get_highest_n_rate(struct ieee80211_hw *hw,
*
* B/G rate:
* (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92_RATE1M-->DESC92_RATE54M ==> idx is 0-->11,
+ * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11,
*
* N rate:
* (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15
+ * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
*
* 5G band:rx_status->band == IEEE80211_BAND_5GHZ
* A rate:
* (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92_RATE6M-->DESC92_RATE54M ==> idx is 0-->7,
+ * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7,
*
* N rate:
* (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92_RATEMCS0-->DESC92_RATEMCS15 ==> idx is 0-->15
+ * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
+ *
+ * VHT rates:
+ * DESC_RATEVHT1SS_MCS0-->DESC_RATEVHT1SS_MCS9 ==> idx is 0-->9
+ * DESC_RATEVHT2SS_MCS0-->DESC_RATEVHT2SS_MCS9 ==> idx is 0-->9
*/
-int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
- bool isht, u8 desc_rate, bool first_ampdu)
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht, bool isvht,
+ u8 desc_rate)
{
int rate_idx;
+ if (isvht) {
+ switch (desc_rate) {
+ case DESC_RATEVHT1SS_MCS0:
+ rate_idx = 0;
+ break;
+ case DESC_RATEVHT1SS_MCS1:
+ rate_idx = 1;
+ break;
+ case DESC_RATEVHT1SS_MCS2:
+ rate_idx = 2;
+ break;
+ case DESC_RATEVHT1SS_MCS3:
+ rate_idx = 3;
+ break;
+ case DESC_RATEVHT1SS_MCS4:
+ rate_idx = 4;
+ break;
+ case DESC_RATEVHT1SS_MCS5:
+ rate_idx = 5;
+ break;
+ case DESC_RATEVHT1SS_MCS6:
+ rate_idx = 6;
+ break;
+ case DESC_RATEVHT1SS_MCS7:
+ rate_idx = 7;
+ break;
+ case DESC_RATEVHT1SS_MCS8:
+ rate_idx = 8;
+ break;
+ case DESC_RATEVHT1SS_MCS9:
+ rate_idx = 9;
+ break;
+ case DESC_RATEVHT2SS_MCS0:
+ rate_idx = 0;
+ break;
+ case DESC_RATEVHT2SS_MCS1:
+ rate_idx = 1;
+ break;
+ case DESC_RATEVHT2SS_MCS2:
+ rate_idx = 2;
+ break;
+ case DESC_RATEVHT2SS_MCS3:
+ rate_idx = 3;
+ break;
+ case DESC_RATEVHT2SS_MCS4:
+ rate_idx = 4;
+ break;
+ case DESC_RATEVHT2SS_MCS5:
+ rate_idx = 5;
+ break;
+ case DESC_RATEVHT2SS_MCS6:
+ rate_idx = 6;
+ break;
+ case DESC_RATEVHT2SS_MCS7:
+ rate_idx = 7;
+ break;
+ case DESC_RATEVHT2SS_MCS8:
+ rate_idx = 8;
+ break;
+ case DESC_RATEVHT2SS_MCS9:
+ rate_idx = 9;
+ break;
+ default:
+ rate_idx = 0;
+ break;
+ }
+ return rate_idx;
+ }
if (false == isht) {
if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
switch (desc_rate) {
- case DESC92_RATE1M:
+ case DESC_RATE1M:
rate_idx = 0;
break;
- case DESC92_RATE2M:
+ case DESC_RATE2M:
rate_idx = 1;
break;
- case DESC92_RATE5_5M:
+ case DESC_RATE5_5M:
rate_idx = 2;
break;
- case DESC92_RATE11M:
+ case DESC_RATE11M:
rate_idx = 3;
break;
- case DESC92_RATE6M:
+ case DESC_RATE6M:
rate_idx = 4;
break;
- case DESC92_RATE9M:
+ case DESC_RATE9M:
rate_idx = 5;
break;
- case DESC92_RATE12M:
+ case DESC_RATE12M:
rate_idx = 6;
break;
- case DESC92_RATE18M:
+ case DESC_RATE18M:
rate_idx = 7;
break;
- case DESC92_RATE24M:
+ case DESC_RATE24M:
rate_idx = 8;
break;
- case DESC92_RATE36M:
+ case DESC_RATE36M:
rate_idx = 9;
break;
- case DESC92_RATE48M:
+ case DESC_RATE48M:
rate_idx = 10;
break;
- case DESC92_RATE54M:
+ case DESC_RATE54M:
rate_idx = 11;
break;
default:
@@ -932,28 +1004,28 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
}
} else {
switch (desc_rate) {
- case DESC92_RATE6M:
+ case DESC_RATE6M:
rate_idx = 0;
break;
- case DESC92_RATE9M:
+ case DESC_RATE9M:
rate_idx = 1;
break;
- case DESC92_RATE12M:
+ case DESC_RATE12M:
rate_idx = 2;
break;
- case DESC92_RATE18M:
+ case DESC_RATE18M:
rate_idx = 3;
break;
- case DESC92_RATE24M:
+ case DESC_RATE24M:
rate_idx = 4;
break;
- case DESC92_RATE36M:
+ case DESC_RATE36M:
rate_idx = 5;
break;
- case DESC92_RATE48M:
+ case DESC_RATE48M:
rate_idx = 6;
break;
- case DESC92_RATE54M:
+ case DESC_RATE54M:
rate_idx = 7;
break;
default:
@@ -963,52 +1035,52 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
}
} else {
switch (desc_rate) {
- case DESC92_RATEMCS0:
+ case DESC_RATEMCS0:
rate_idx = 0;
break;
- case DESC92_RATEMCS1:
+ case DESC_RATEMCS1:
rate_idx = 1;
break;
- case DESC92_RATEMCS2:
+ case DESC_RATEMCS2:
rate_idx = 2;
break;
- case DESC92_RATEMCS3:
+ case DESC_RATEMCS3:
rate_idx = 3;
break;
- case DESC92_RATEMCS4:
+ case DESC_RATEMCS4:
rate_idx = 4;
break;
- case DESC92_RATEMCS5:
+ case DESC_RATEMCS5:
rate_idx = 5;
break;
- case DESC92_RATEMCS6:
+ case DESC_RATEMCS6:
rate_idx = 6;
break;
- case DESC92_RATEMCS7:
+ case DESC_RATEMCS7:
rate_idx = 7;
break;
- case DESC92_RATEMCS8:
+ case DESC_RATEMCS8:
rate_idx = 8;
break;
- case DESC92_RATEMCS9:
+ case DESC_RATEMCS9:
rate_idx = 9;
break;
- case DESC92_RATEMCS10:
+ case DESC_RATEMCS10:
rate_idx = 10;
break;
- case DESC92_RATEMCS11:
+ case DESC_RATEMCS11:
rate_idx = 11;
break;
- case DESC92_RATEMCS12:
+ case DESC_RATEMCS12:
rate_idx = 12;
break;
- case DESC92_RATEMCS13:
+ case DESC_RATEMCS13:
rate_idx = 13;
break;
- case DESC92_RATEMCS14:
+ case DESC_RATEMCS14:
rate_idx = 14;
break;
- case DESC92_RATEMCS15:
+ case DESC_RATEMCS15:
rate_idx = 15;
break;
default:
diff --git a/drivers/net/wireless/rtlwifi/base.h b/drivers/net/wireless/rtlwifi/base.h
index 982f2450feea..c6cb49c3ee32 100644
--- a/drivers/net/wireless/rtlwifi/base.h
+++ b/drivers/net/wireless/rtlwifi/base.h
@@ -123,8 +123,8 @@ void rtl_watch_dog_timer_callback(unsigned long data);
void rtl_deinit_deferred_work(struct ieee80211_hw *hw);
bool rtl_action_proc(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
-int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
- bool isht, u8 desc_rate, bool first_ampdu);
+int rtlwifi_rate_mapping(struct ieee80211_hw *hw, bool isht,
+ bool isvht, u8 desc_rate);
bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
u8 rtl_is_special_data(struct ieee80211_hw *hw, struct sk_buff *skb, u8 is_tx);
diff --git a/drivers/net/wireless/rtlwifi/core.c b/drivers/net/wireless/rtlwifi/core.c
index 5fc6f52641bd..a31a12775f1a 100644
--- a/drivers/net/wireless/rtlwifi/core.c
+++ b/drivers/net/wireless/rtlwifi/core.c
@@ -95,7 +95,8 @@ void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data)
}
EXPORT_SYMBOL(rtl_bb_delay);
-void rtl_fw_cb(const struct firmware *firmware, void *context)
+static void rtl_fw_do_work(const struct firmware *firmware, void *context,
+ bool is_wow)
{
struct ieee80211_hw *hw = context;
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -125,12 +126,31 @@ found_alt:
release_firmware(firmware);
return;
}
- memcpy(rtlpriv->rtlhal.pfirmware, firmware->data, firmware->size);
+ if (!is_wow) {
+ memcpy(rtlpriv->rtlhal.pfirmware, firmware->data,
+ firmware->size);
+ rtlpriv->rtlhal.fwsize = firmware->size;
+ } else {
+ memcpy(rtlpriv->rtlhal.wowlan_firmware, firmware->data,
+ firmware->size);
+ rtlpriv->rtlhal.wowlan_fwsize = firmware->size;
+ }
rtlpriv->rtlhal.fwsize = firmware->size;
release_firmware(firmware);
}
+
+void rtl_fw_cb(const struct firmware *firmware, void *context)
+{
+ rtl_fw_do_work(firmware, context, false);
+}
EXPORT_SYMBOL(rtl_fw_cb);
+void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context)
+{
+ rtl_fw_do_work(firmware, context, true);
+}
+EXPORT_SYMBOL(rtl_wowlan_fw_cb);
+
/*mutex for start & stop is must here. */
static int rtl_op_start(struct ieee80211_hw *hw)
{
@@ -990,6 +1010,16 @@ static int rtl_op_conf_tx(struct ieee80211_hw *hw,
return 0;
}
+static void send_beacon_frame(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct sk_buff *skb = ieee80211_beacon_get(hw, vif);
+
+ if (skb)
+ rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, NULL);
+}
+
static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
struct ieee80211_vif *vif,
struct ieee80211_bss_conf *bss_conf,
@@ -1020,6 +1050,7 @@ static void rtl_op_bss_info_changed(struct ieee80211_hw *hw,
if (rtlpriv->cfg->ops->linked_set_reg)
rtlpriv->cfg->ops->linked_set_reg(hw);
+ send_beacon_frame(hw, vif);
}
}
if ((changed & BSS_CHANGED_BEACON_ENABLED &&
@@ -1851,3 +1882,40 @@ bool rtl_btc_status_false(void)
return false;
}
EXPORT_SYMBOL_GPL(rtl_btc_status_false);
+
+void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igvalue)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+ dm_digtable->dig_enable_flag = true;
+ dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+ dm_digtable->cur_igvalue = cur_igvalue;
+ dm_digtable->pre_igvalue = 0;
+ dm_digtable->cur_sta_cstate = DIG_STA_DISCONNECT;
+ dm_digtable->presta_cstate = DIG_STA_DISCONNECT;
+ dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
+ dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
+ dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
+ dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+ dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+ dm_digtable->rx_gain_max = DM_DIG_MAX;
+ dm_digtable->rx_gain_min = DM_DIG_MIN;
+ dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+ dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+ dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
+ dm_digtable->pre_cck_cca_thres = 0xff;
+ dm_digtable->cur_cck_cca_thres = 0x83;
+ dm_digtable->forbidden_igi = DM_DIG_MIN;
+ dm_digtable->large_fa_hit = 0;
+ dm_digtable->recover_cnt = 0;
+ dm_digtable->dig_min_0 = 0x25;
+ dm_digtable->dig_min_1 = 0x25;
+ dm_digtable->media_connect_0 = false;
+ dm_digtable->media_connect_1 = false;
+ rtlpriv->dm.dm_initialgain_enable = true;
+ dm_digtable->bt30_cur_igi = 0x32;
+ dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
+ dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LOWRSSI;
+}
+EXPORT_SYMBOL(rtl_dm_diginit);
diff --git a/drivers/net/wireless/rtlwifi/core.h b/drivers/net/wireless/rtlwifi/core.h
index 624e1dc16d31..7b64e34f421e 100644
--- a/drivers/net/wireless/rtlwifi/core.h
+++ b/drivers/net/wireless/rtlwifi/core.h
@@ -35,13 +35,55 @@
#define RTL_SUPPORTED_CTRL_FILTER 0xFF
+#define DM_DIG_THRESH_HIGH 40
+#define DM_DIG_THRESH_LOW 35
+#define DM_FALSEALARM_THRESH_LOW 400
+#define DM_FALSEALARM_THRESH_HIGH 1000
+
+#define DM_DIG_MAX 0x3e
+#define DM_DIG_MIN 0x1e
+#define DM_DIG_MAX_AP 0x32
+#define DM_DIG_BACKOFF_MAX 12
+#define DM_DIG_BACKOFF_MIN -4
+#define DM_DIG_BACKOFF_DEFAULT 10
+
+enum cck_packet_detection_threshold {
+ CCK_PD_STAGE_LOWRSSI = 0,
+ CCK_PD_STAGE_HIGHRSSI = 1,
+ CCK_FA_STAGE_LOW = 2,
+ CCK_FA_STAGE_HIGH = 3,
+ CCK_PD_STAGE_MAX = 4,
+};
+
+enum dm_dig_ext_port_alg_e {
+ DIG_EXT_PORT_STAGE_0 = 0,
+ DIG_EXT_PORT_STAGE_1 = 1,
+ DIG_EXT_PORT_STAGE_2 = 2,
+ DIG_EXT_PORT_STAGE_3 = 3,
+ DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+ DIG_STA_DISCONNECT,
+ DIG_STA_CONNECT,
+ DIG_STA_BEFORE_CONNECT,
+ DIG_MULTISTA_DISCONNECT,
+ DIG_MULTISTA_CONNECT,
+ DIG_AP_DISCONNECT,
+ DIG_AP_CONNECT,
+ DIG_AP_ADD_STATION,
+ DIG_CONNECT_MAX
+};
+
extern const struct ieee80211_ops rtl_ops;
void rtl_fw_cb(const struct firmware *firmware, void *context);
+void rtl_wowlan_fw_cb(const struct firmware *firmware, void *context);
void rtl_addr_delay(u32 addr);
void rtl_rfreg_delay(struct ieee80211_hw *hw, enum radio_path rfpath, u32 addr,
u32 mask, u32 data);
void rtl_bb_delay(struct ieee80211_hw *hw, u32 addr, u32 data);
bool rtl_cmd_send_packet(struct ieee80211_hw *hw, struct sk_buff *skb);
bool rtl_btc_status_false(void);
+void rtl_dm_diginit(struct ieee80211_hw *hw, u32 cur_igval);
#endif
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index c70efb9a6e78..a62170ea0481 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -578,6 +578,13 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
else
entry = (u8 *)(&ring->desc[ring->idx]);
+ if (rtlpriv->cfg->ops->get_available_desc &&
+ rtlpriv->cfg->ops->get_available_desc(hw, prio) <= 1) {
+ RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_DMESG,
+ "no available desc!\n");
+ return;
+ }
+
if (!rtlpriv->cfg->ops->is_tx_desc_closed(hw, prio, ring->idx))
return;
ring->idx = (ring->idx + 1) % ring->entries;
@@ -641,10 +648,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
ieee80211_tx_status_irqsafe(hw, skb);
- if ((ring->entries - skb_queue_len(&ring->queue))
- == 2) {
+ if ((ring->entries - skb_queue_len(&ring->queue)) <= 4) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_DMESG,
"more desc left, wake skb_queue@%d, ring->idx = %d, skb_queue_len = 0x%x\n",
prio, ring->idx,
skb_queue_len(&ring->queue));
@@ -793,7 +799,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rx_remained_cnt =
rtlpriv->cfg->ops->rx_desc_buff_remained_cnt(hw,
hw_queue);
- if (rx_remained_cnt < 1)
+ if (rx_remained_cnt == 0)
return;
} else { /* rx descriptor */
@@ -816,11 +822,8 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
/* get a new skb - if fail, old one will be reused */
new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
- if (unlikely(!new_skb)) {
- pr_err("Allocation of new skb failed in %s\n",
- __func__);
+ if (unlikely(!new_skb))
goto no_new;
- }
if (rtlpriv->use_new_trx_flow) {
buffer_desc =
&rtlpci->rx_ring[rxring_idx].buffer_desc
@@ -848,18 +851,18 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
else
skb_reserve(skb, stats.rx_drvinfo_size +
stats.rx_bufshift);
-
} else {
RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
"skb->end - skb->tail = %d, len is %d\n",
skb->end - skb->tail, len);
- break;
+ dev_kfree_skb_any(skb);
+ goto new_trx_end;
}
/* handle command packet here */
if (rtlpriv->cfg->ops->rx_command_packet &&
rtlpriv->cfg->ops->rx_command_packet(hw, stats, skb)) {
dev_kfree_skb_any(skb);
- goto end;
+ goto new_trx_end;
}
/*
@@ -909,6 +912,7 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
} else {
dev_kfree_skb_any(skb);
}
+new_trx_end:
if (rtlpriv->use_new_trx_flow) {
rtlpci->rx_ring[hw_queue].next_rx_rp += 1;
rtlpci->rx_ring[hw_queue].next_rx_rp %=
@@ -924,7 +928,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
rtlpriv->enter_ps = false;
schedule_work(&rtlpriv->works.lps_change_work);
}
-end:
skb = new_skb;
no_new:
if (rtlpriv->use_new_trx_flow) {
@@ -1688,6 +1691,15 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
}
}
+ if (rtlpriv->cfg->ops->get_available_desc &&
+ rtlpriv->cfg->ops->get_available_desc(hw, hw_queue) == 0) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "get_available_desc fail\n");
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+ flags);
+ return skb->len;
+ }
+
if (ieee80211_is_data_qos(fc)) {
tid = rtl_get_tid(skb);
if (sta) {
diff --git a/drivers/net/wireless/rtlwifi/pci.h b/drivers/net/wireless/rtlwifi/pci.h
index 5e832306dba9..d4567d12e07e 100644
--- a/drivers/net/wireless/rtlwifi/pci.h
+++ b/drivers/net/wireless/rtlwifi/pci.h
@@ -325,4 +325,11 @@ static inline void pci_write32_async(struct rtl_priv *rtlpriv,
writel(val, (u8 __iomem *) rtlpriv->io.pci_mem_start + addr);
}
+static inline u16 calc_fifo_space(u16 rp, u16 wp)
+{
+ if (rp <= wp)
+ return RTL_PCI_MAX_RX_COUNT - 1 + rp - wp;
+ return rp - wp - 1;
+}
+
#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
index 2aa34d9055f0..d930c1f78721 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.c
@@ -26,6 +26,7 @@
#include "../wifi.h"
#include "../base.h"
#include "../pci.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -341,38 +342,6 @@ static void dm_tx_pwr_track_set_pwr(struct ieee80211_hw *hw,
}
}
-static void rtl88e_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *dm_dig = &rtlpriv->dm_digtable;
-
- dm_dig->dig_enable_flag = true;
- dm_dig->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
- dm_dig->pre_igvalue = 0;
- dm_dig->cur_sta_cstate = DIG_STA_DISCONNECT;
- dm_dig->presta_cstate = DIG_STA_DISCONNECT;
- dm_dig->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
- dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW;
- dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH;
- dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_dig->rx_gain_max = DM_DIG_MAX;
- dm_dig->rx_gain_min = DM_DIG_MIN;
- dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT;
- dm_dig->back_range_max = DM_DIG_BACKOFF_MAX;
- dm_dig->back_range_min = DM_DIG_BACKOFF_MIN;
- dm_dig->pre_cck_cca_thres = 0xff;
- dm_dig->cur_cck_cca_thres = 0x83;
- dm_dig->forbidden_igi = DM_DIG_MIN;
- dm_dig->large_fa_hit = 0;
- dm_dig->recover_cnt = 0;
- dm_dig->dig_min_0 = 0x25;
- dm_dig->dig_min_1 = 0x25;
- dm_dig->media_connect_0 = false;
- dm_dig->media_connect_1 = false;
- rtlpriv->dm.dm_initialgain_enable = true;
-}
-
static u8 rtl88e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1796,9 +1765,10 @@ static void rtl88e_dm_antenna_diversity(struct ieee80211_hw *hw)
void rtl88e_dm_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
- rtl88e_dm_diginit(hw);
+ rtl_dm_diginit(hw, cur_igvalue);
rtl88e_dm_init_dynamic_txpower(hw);
rtl88e_dm_init_edca_turbo(hw);
rtl88e_dm_init_rate_adaptive_mask(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
index 64f1f3ea9807..071ccee69eae 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/dm.h
@@ -186,28 +186,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
-#define DM_DIG_MAX_AP 0x32
-#define DM_DIG_MIN_AP 0x20
-
#define DM_DIG_FA_UPPER 0x3e
#define DM_DIG_FA_LOWER 0x1e
#define DM_DIG_FA_TH0 0x200
#define DM_DIG_FA_TH1 0x300
#define DM_DIG_FA_TH2 0x400
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_W 30
#define RXPATHSELECTION_DIFF_TH 18
@@ -262,14 +246,6 @@ enum tag_dynamic_init_gain_operation_type_definition {
DIG_OP_TYPE_MAX
};
-enum tag_cck_packet_detection_threshold_type_definition {
- CCK_PD_STAGE_LOWRSSI = 0,
- CCK_PD_STAGE_HIGHRSSI = 1,
- CCK_FA_STAGE_LOW = 2,
- CCK_FA_STAGE_HIGH = 3,
- CCK_PD_STAGE_MAX = 4,
-};
-
enum dm_1r_cca_e {
CCA_1R = 0,
CCA_2R = 1,
@@ -288,23 +264,6 @@ enum dm_sw_ant_switch_e {
ANS_ANTENNA_MAX = 3,
};
-enum dm_dig_ext_port_alg_e {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect_e {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_MULTISTA_DISCONNECT = 3,
- DIG_MULTISTA_CONNECT = 4,
- DIG_CONNECT_MAX
-};
-
enum pwr_track_control_method {
BBSWING,
TXAGC
diff --git a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
index df549c96adef..791efbe6b18c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8188ee/trx.c
@@ -47,164 +47,6 @@ static u8 _rtl88ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-/* mac80211's rate_idx is like this:
- *
- * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
- *
- * B/G rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- *
- * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
- * A rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- */
-static int _rtl88ee_rate_mapping(struct ieee80211_hw *hw,
- bool isht, u8 desc_rate)
-{
- int rate_idx;
-
- if (!isht) {
- if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATE6M:
- rate_idx = 0;
- break;
- case DESC92C_RATE9M:
- rate_idx = 1;
- break;
- case DESC92C_RATE12M:
- rate_idx = 2;
- break;
- case DESC92C_RATE18M:
- rate_idx = 3;
- break;
- case DESC92C_RATE24M:
- rate_idx = 4;
- break;
- case DESC92C_RATE36M:
- rate_idx = 5;
- break;
- case DESC92C_RATE48M:
- rate_idx = 6;
- break;
- case DESC92C_RATE54M:
- rate_idx = 7;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATEMCS0:
- rate_idx = 0;
- break;
- case DESC92C_RATEMCS1:
- rate_idx = 1;
- break;
- case DESC92C_RATEMCS2:
- rate_idx = 2;
- break;
- case DESC92C_RATEMCS3:
- rate_idx = 3;
- break;
- case DESC92C_RATEMCS4:
- rate_idx = 4;
- break;
- case DESC92C_RATEMCS5:
- rate_idx = 5;
- break;
- case DESC92C_RATEMCS6:
- rate_idx = 6;
- break;
- case DESC92C_RATEMCS7:
- rate_idx = 7;
- break;
- case DESC92C_RATEMCS8:
- rate_idx = 8;
- break;
- case DESC92C_RATEMCS9:
- rate_idx = 9;
- break;
- case DESC92C_RATEMCS10:
- rate_idx = 10;
- break;
- case DESC92C_RATEMCS11:
- rate_idx = 11;
- break;
- case DESC92C_RATEMCS12:
- rate_idx = 12;
- break;
- case DESC92C_RATEMCS13:
- rate_idx = 13;
- break;
- case DESC92C_RATEMCS14:
- rate_idx = 14;
- break;
- case DESC92C_RATEMCS15:
- rate_idx = 15;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- return rate_idx;
-}
-
static void _rtl88ee_query_rxphystatus(struct ieee80211_hw *hw,
struct rtl_stats *pstatus, u8 *pdesc,
struct rx_fwinfo_88e *p_drvinfo,
@@ -630,8 +472,8 @@ bool rtl88ee_rx_query_desc(struct ieee80211_hw *hw,
* are use (RX_FLAG_HT)
* Notice: this is diff with windows define
*/
- rx_status->rate_idx = _rtl88ee_rate_mapping(hw,
- status->is_ht, status->rate);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ false, status->rate);
rx_status->mactime = status->timestamp_low;
if (phystatus == true) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
index f6cb5aedfdd1..f5ee67cda73a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.c
@@ -32,6 +32,7 @@
#include "phy_common.h"
#include "../pci.h"
#include "../base.h"
+#include "../core.h"
#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1)
#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1)
@@ -194,36 +195,6 @@ void dm_savepowerindex(struct ieee80211_hw *hw)
}
EXPORT_SYMBOL_GPL(dm_savepowerindex);
-static void rtl92c_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
-
- dm_digtable->dig_enable_flag = true;
- dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
- dm_digtable->cur_igvalue = 0x20;
- dm_digtable->pre_igvalue = 0x0;
- dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
- dm_digtable->presta_cstate = DIG_STA_DISCONNECT;
- dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
- dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
- dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
- dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_max = DM_DIG_MAX;
- dm_digtable->rx_gain_min = DM_DIG_MIN;
- dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
- dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
- dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
- dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
- dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_LowRssi;
-
- dm_digtable->forbidden_igi = DM_DIG_MIN;
- dm_digtable->large_fa_hit = 0;
- dm_digtable->recover_cnt = 0;
- dm_digtable->dig_dynamic_min = 0x25;
-}
-
static u8 rtl92c_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -507,27 +478,27 @@ static void rtl92c_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
if (dm_digtable->rssi_val_min > 100)
dm_digtable->rssi_val_min = 100;
- if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+ if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
if (dm_digtable->rssi_val_min <= 25)
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_LowRssi;
+ CCK_PD_STAGE_LOWRSSI;
else
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_HighRssi;
+ CCK_PD_STAGE_HIGHRSSI;
} else {
if (dm_digtable->rssi_val_min <= 20)
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_LowRssi;
+ CCK_PD_STAGE_LOWRSSI;
else
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_HighRssi;
+ CCK_PD_STAGE_HIGHRSSI;
}
} else {
dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
}
if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) {
- if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) ||
+ if ((dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) ||
(dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_MAX))
rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0x83);
else
@@ -1374,7 +1345,7 @@ void rtl92c_dm_init(struct ieee80211_hw *hw)
rtlpriv->dm.undec_sm_pwdb = -1;
rtlpriv->dm.undec_sm_cck = -1;
rtlpriv->dm.dm_initialgain_enable = true;
- rtl92c_dm_diginit(hw);
+ rtl_dm_diginit(hw, 0x20);
rtlpriv->dm.dm_flag |= HAL_DM_HIPWR_DISABLE;
rtl92c_dm_init_dynamic_txpower(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
index 4f232a063636..4422e31fedd9 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/dm_common.h
@@ -47,25 +47,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
#define DM_DIG_FA_UPPER 0x32
#define DM_DIG_FA_LOWER 0x20
#define DM_DIG_FA_TH0 0x20
#define DM_DIG_FA_TH1 0x100
#define DM_DIG_FA_TH2 0x200
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_lOW 30
#define RXPATHSELECTION_DIFF_TH 18
@@ -123,14 +110,6 @@ enum tag_dynamic_init_gain_operation_type_definition {
DIG_OP_TYPE_MAX
};
-enum tag_cck_packet_detection_threshold_type_definition {
- CCK_PD_STAGE_LowRssi = 0,
- CCK_PD_STAGE_HighRssi = 1,
- CCK_FA_STAGE_Low = 2,
- CCK_FA_STAGE_High = 3,
- CCK_PD_STAGE_MAX = 4,
-};
-
enum dm_1r_cca_e {
CCA_1R = 0,
CCA_2R = 1,
@@ -149,23 +128,6 @@ enum dm_sw_ant_switch_e {
ANS_ANTENNA_MAX = 3,
};
-enum dm_dig_ext_port_alg_e {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect_e {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_MULTISTA_DISCONNECT = 3,
- DIG_MULTISTA_CONNECT = 4,
- DIG_CONNECT_MAX
-};
-
void rtl92c_dm_init(struct ieee80211_hw *hw);
void rtl92c_dm_watchdog(struct ieee80211_hw *hw);
void rtl92c_dm_write_dig(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
index b64ae45dc674..e9f4281f5067 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192c/fw_common.h
@@ -37,6 +37,7 @@
#define FW_8192C_POLLING_DELAY 5
#define FW_8192C_POLLING_TIMEOUT_COUNT 100
#define NORMAL_CHIP BIT(4)
+#define H2C_92C_KEEP_ALIVE_CTRL 48
#define IS_FW_HEADER_EXIST(_pfwhdr) \
((le16_to_cpu(_pfwhdr->signature)&0xFFF0) == 0x92C0 ||\
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
index 74f9c083b80d..09898cf2e07a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.c
@@ -30,6 +30,7 @@
#include "../wifi.h"
#include "../base.h"
#include "../pci.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
index 9c5311c299fd..38ba707015f5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/dm.h
@@ -42,25 +42,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
#define DM_DIG_FA_UPPER 0x32
#define DM_DIG_FA_LOWER 0x20
#define DM_DIG_FA_TH0 0x20
#define DM_DIG_FA_TH1 0x100
#define DM_DIG_FA_TH2 0x200
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_lOW 30
#define RXPATHSELECTION_DIFF_TH 18
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
index 5c646d5f7bb8..303b299376c9 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
@@ -544,8 +544,13 @@ void rtl92ce_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
(u8 *)(&fw_current_inps));
}
break; }
- case HW_VAR_KEEP_ALIVE:
- break;
+ case HW_VAR_KEEP_ALIVE: {
+ u8 array[2];
+
+ array[0] = 0xff;
+ array[1] = *((u8 *)val);
+ rtl92c_fill_h2c_cmd(hw, H2C_92C_KEEP_ALIVE_CTRL, 2, array);
+ break; }
default:
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
"switch case %d not processed\n", variable);
@@ -1156,47 +1161,35 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
struct rtl_priv *rtlpriv = rtl_priv(hw);
u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
- bt_msr &= 0xfc;
+ u8 mode = MSR_NOLINK;
- if (type == NL80211_IFTYPE_UNSPECIFIED ||
- type == NL80211_IFTYPE_STATION) {
- _rtl92ce_stop_tx_beacon(hw);
- _rtl92ce_enable_bcn_sub_func(hw);
- } else if (type == NL80211_IFTYPE_ADHOC || type == NL80211_IFTYPE_AP ||
- type == NL80211_IFTYPE_MESH_POINT) {
- _rtl92ce_resume_tx_beacon(hw);
- _rtl92ce_disable_bcn_sub_func(hw);
- } else {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
- "Set HW_VAR_MEDIA_STATUS: No such media status(%x)\n",
- type);
- }
+ bt_msr &= 0xfc;
switch (type) {
case NL80211_IFTYPE_UNSPECIFIED:
- bt_msr |= MSR_NOLINK;
- ledaction = LED_CTL_LINK;
+ mode = MSR_NOLINK;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to NO LINK!\n");
break;
case NL80211_IFTYPE_ADHOC:
- bt_msr |= MSR_ADHOC;
+ mode = MSR_ADHOC;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to Ad Hoc!\n");
break;
case NL80211_IFTYPE_STATION:
- bt_msr |= MSR_INFRA;
+ mode = MSR_INFRA;
ledaction = LED_CTL_LINK;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to STA!\n");
break;
case NL80211_IFTYPE_AP:
- bt_msr |= MSR_AP;
+ mode = MSR_AP;
+ ledaction = LED_CTL_LINK;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to AP!\n");
break;
case NL80211_IFTYPE_MESH_POINT:
- bt_msr |= MSR_ADHOC;
+ mode = MSR_ADHOC;
RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
"Set Network type to Mesh Point!\n");
break;
@@ -1207,9 +1200,32 @@ static int _rtl92ce_set_media_status(struct ieee80211_hw *hw,
}
- rtl_write_byte(rtlpriv, (MSR), bt_msr);
+ /* MSR_INFRA == Link in infrastructure network;
+ * MSR_ADHOC == Link in ad hoc network;
+ * Therefore, check link state is necessary.
+ *
+ * MSR_AP == AP mode; link state does not matter here.
+ */
+ if (mode != MSR_AP &&
+ rtlpriv->mac80211.link_state < MAC80211_LINKED) {
+ mode = MSR_NOLINK;
+ ledaction = LED_CTL_NO_LINK;
+ }
+ if (mode == MSR_NOLINK || mode == MSR_INFRA) {
+ _rtl92ce_stop_tx_beacon(hw);
+ _rtl92ce_enable_bcn_sub_func(hw);
+ } else if (mode == MSR_ADHOC || mode == MSR_AP) {
+ _rtl92ce_resume_tx_beacon(hw);
+ _rtl92ce_disable_bcn_sub_func(hw);
+ } else {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+ "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+ mode);
+ }
+ rtl_write_byte(rtlpriv, MSR, bt_msr | mode);
+
rtlpriv->cfg->ops->led_control(hw, ledaction);
- if ((bt_msr & MSR_MASK) == MSR_AP)
+ if (mode == MSR_AP)
rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
else
rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
@@ -1833,7 +1849,6 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
u32 ratr_value;
u8 ratr_index = 0;
u8 nmode = mac->ht_enable;
- u8 mimo_ps = IEEE80211_SMPS_OFF;
u16 shortgi_rate;
u32 tmp_ratr_value;
u8 curtxbw_40mhz = mac->bw_40;
@@ -1842,6 +1857,7 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
1 : 0;
enum wireless_mode wirelessmode = mac->mode;
+ u32 ratr_mask;
if (rtlhal->current_bandtype == BAND_ON_5G)
ratr_value = sta->supp_rates[1] << 4;
@@ -1865,19 +1881,13 @@ static void rtl92ce_update_hal_rate_table(struct ieee80211_hw *hw,
case WIRELESS_MODE_N_24G:
case WIRELESS_MODE_N_5G:
nmode = 1;
- if (mimo_ps == IEEE80211_SMPS_STATIC) {
- ratr_value &= 0x0007F005;
- } else {
- u32 ratr_mask;
-
- if (get_rf_type(rtlphy) == RF_1T2R ||
- get_rf_type(rtlphy) == RF_1T1R)
- ratr_mask = 0x000ff005;
- else
- ratr_mask = 0x0f0ff005;
+ if (get_rf_type(rtlphy) == RF_1T2R ||
+ get_rf_type(rtlphy) == RF_1T1R)
+ ratr_mask = 0x000ff005;
+ else
+ ratr_mask = 0x0f0ff005;
- ratr_value &= ratr_mask;
- }
+ ratr_value &= ratr_mask;
break;
default:
if (rtlphy->rf_type == RF_1T2R)
@@ -1930,17 +1940,16 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
struct rtl_sta_info *sta_entry = NULL;
u32 ratr_bitmap;
u8 ratr_index;
- u8 curtxbw_40mhz = (sta->bandwidth >= IEEE80211_STA_RX_BW_40) ? 1 : 0;
- u8 curshortgi_40mhz = curtxbw_40mhz &&
- (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
- 1 : 0;
+ u8 curtxbw_40mhz = (sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SUP_WIDTH_20_40) ? 1 : 0;
+ u8 curshortgi_40mhz = (sta->ht_cap.cap &
+ IEEE80211_HT_CAP_SGI_40) ? 1 : 0;
u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
1 : 0;
enum wireless_mode wirelessmode = 0;
bool shortgi = false;
u8 rate_mask[5];
u8 macid = 0;
- u8 mimo_ps = IEEE80211_SMPS_OFF;
sta_entry = (struct rtl_sta_info *) sta->drv_priv;
wirelessmode = sta_entry->wireless_mode;
@@ -1985,47 +1994,38 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
case WIRELESS_MODE_N_5G:
ratr_index = RATR_INX_WIRELESS_NGB;
- if (mimo_ps == IEEE80211_SMPS_STATIC) {
- if (rssi_level == 1)
- ratr_bitmap &= 0x00070000;
- else if (rssi_level == 2)
- ratr_bitmap &= 0x0007f000;
- else
- ratr_bitmap &= 0x0007f005;
+ if (rtlphy->rf_type == RF_1T2R ||
+ rtlphy->rf_type == RF_1T1R) {
+ if (curtxbw_40mhz) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff015;
+ } else {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x000f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x000ff000;
+ else
+ ratr_bitmap &= 0x000ff005;
+ }
} else {
- if (rtlphy->rf_type == RF_1T2R ||
- rtlphy->rf_type == RF_1T1R) {
- if (curtxbw_40mhz) {
- if (rssi_level == 1)
- ratr_bitmap &= 0x000f0000;
- else if (rssi_level == 2)
- ratr_bitmap &= 0x000ff000;
- else
- ratr_bitmap &= 0x000ff015;
- } else {
- if (rssi_level == 1)
- ratr_bitmap &= 0x000f0000;
- else if (rssi_level == 2)
- ratr_bitmap &= 0x000ff000;
- else
- ratr_bitmap &= 0x000ff005;
- }
+ if (curtxbw_40mhz) {
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x0f0f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0f0ff000;
+ else
+ ratr_bitmap &= 0x0f0ff015;
} else {
- if (curtxbw_40mhz) {
- if (rssi_level == 1)
- ratr_bitmap &= 0x0f0f0000;
- else if (rssi_level == 2)
- ratr_bitmap &= 0x0f0ff000;
- else
- ratr_bitmap &= 0x0f0ff015;
- } else {
- if (rssi_level == 1)
- ratr_bitmap &= 0x0f0f0000;
- else if (rssi_level == 2)
- ratr_bitmap &= 0x0f0ff000;
- else
- ratr_bitmap &= 0x0f0ff005;
- }
+ if (rssi_level == 1)
+ ratr_bitmap &= 0x0f0f0000;
+ else if (rssi_level == 2)
+ ratr_bitmap &= 0x0f0ff000;
+ else
+ ratr_bitmap &= 0x0f0ff005;
}
}
@@ -2058,9 +2058,6 @@ static void rtl92ce_update_hal_rate_mask(struct ieee80211_hw *hw,
"Rate_index:%x, ratr_val:%x, %5phC\n",
ratr_index, ratr_bitmap, rate_mask);
rtl92c_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
-
- if (macid != 0)
- sta_entry->ratr_index = ratr_index;
}
void rtl92ce_update_hal_rate_tbl(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
index bc5ca989b915..1ee5a6ae9960 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
@@ -518,11 +518,12 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
}
case ERFSLEEP:{
if (ppsc->rfpwr_state == ERFOFF)
- return false;
+ break;
for (queue_id = 0, i = 0;
queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
ring = &pcipriv->dev.tx_ring[queue_id];
- if (skb_queue_len(&ring->queue) == 0) {
+ if (queue_id == BEACON_QUEUE ||
+ skb_queue_len(&ring->queue) == 0) {
queue_id++;
continue;
} else {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
index dd5aa089126a..de6cb6c3a48c 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/sw.c
@@ -334,21 +334,21 @@ static struct rtl_hal_cfg rtl92ce_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
-
- .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15,
};
static const struct pci_device_id rtl92ce_pci_ids[] = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
index e88dcd0e0af1..84ddd4d07a1d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
@@ -257,8 +257,8 @@ static void _rtl92ce_query_rxphystatus(struct ieee80211_hw *hw,
pstats->recvsignalpower = rx_pwr_all;
/* (3)EVM of HT rate */
- if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 &&
- pstats->rate <= DESC92_RATEMCS15)
+ if (pstats->is_ht && pstats->rate >= DESC_RATEMCS8 &&
+ pstats->rate <= DESC_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -400,9 +400,8 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
* are use (RX_FLAG_HT)
* Notice: this is diff with windows define
*/
- rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- stats->is_ht, stats->rate,
- stats->isfirst_ampdu);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht,
+ false, stats->rate);
rx_status->mactime = stats->timestamp_low;
if (phystatus) {
@@ -501,7 +500,7 @@ void rtl92ce_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_BW(pdesc, 0);
SET_TX_DESC_RTS_SC(pdesc, tcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc,
- ((tcb_desc->rts_rate <= DESC92_RATE54M) ?
+ ((tcb_desc->rts_rate <= DESC_RATE54M) ?
(tcb_desc->rts_use_shortpreamble ? 1 : 0)
: (tcb_desc->rts_use_shortgi ? 1 : 0)));
@@ -624,7 +623,7 @@ void rtl92ce_tx_fill_cmddesc(struct ieee80211_hw *hw,
if (firstseg)
SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
- SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M);
SET_TX_DESC_SEQ(pdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
index 551321728ae0..fe4b699a12f5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/hw.c
@@ -1000,6 +1000,7 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
local_save_flags(flags);
local_irq_enable();
+ rtlhal->fw_ready = false;
rtlhal->hw_type = HARDWARE_TYPE_RTL8192CU;
err = _rtl92cu_init_mac(hw);
if (err) {
@@ -1013,6 +1014,8 @@ int rtl92cu_hw_init(struct ieee80211_hw *hw)
err = 1;
goto exit;
}
+
+ rtlhal->fw_ready = true;
rtlhal->last_hmeboxnum = 0; /* h2c */
_rtl92cu_phy_param_tab_init(hw);
rtl92cu_phy_mac_config(hw);
@@ -1509,6 +1512,7 @@ void rtl92cu_set_beacon_related_registers(struct ieee80211_hw *hw)
/* TODO: Modify later (Find the right parameters)
* NOTE: Fix test chip's bug (about contention windows's randomness) */
if ((mac->opmode == NL80211_IFTYPE_ADHOC) ||
+ (mac->opmode == NL80211_IFTYPE_MESH_POINT) ||
(mac->opmode == NL80211_IFTYPE_AP)) {
rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x50);
rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x50);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
index c2d8ec6afcda..133e395b7401 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
@@ -880,8 +880,8 @@ static void _rtl92c_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
if (GET_RX_DESC_RX_MCS(pdesc) &&
- GET_RX_DESC_RX_MCS(pdesc) >= DESC92_RATEMCS8 &&
- GET_RX_DESC_RX_MCS(pdesc) <= DESC92_RATEMCS15)
+ GET_RX_DESC_RX_MCS(pdesc) >= DESC_RATEMCS8 &&
+ GET_RX_DESC_RX_MCS(pdesc) <= DESC_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
index e06bafee37f9..90a714c189a8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/sw.c
@@ -257,20 +257,20 @@ static struct rtl_hal_cfg rtl92cu_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
- .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M,
+ .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15,
};
#define USB_VENDER_ID_REALTEK 0x0bda
diff --git a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
index f383d5f1fed5..cbead007171f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
@@ -325,6 +325,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ stats->is_ht = (bool)GET_RX_DESC_RX_HT(pdesc);
rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->band = hw->conf.chandef.chan->band;
if (GET_RX_DESC_CRC32(pdesc))
@@ -338,10 +339,8 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
rx_status->flag |= RX_FLAG_MACTIME_START;
if (stats->decrypted)
rx_status->flag |= RX_FLAG_DECRYPTED;
- rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- (bool)GET_RX_DESC_RX_HT(pdesc),
- (u8)GET_RX_DESC_RX_MCS(pdesc),
- (bool)GET_RX_DESC_PAGGR(pdesc));
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht,
+ false, stats->rate);
rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
if (phystatus) {
p_drvinfo = (struct rx_fwinfo_92c *)(skb->data +
@@ -393,6 +392,7 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
&& (GET_RX_DESC_FAGGR(rxdesc) == 1));
stats.timestamp_low = GET_RX_DESC_TSFL(rxdesc);
stats.rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(rxdesc);
+ stats.is_ht = (bool)GET_RX_DESC_RX_HT(rxdesc);
/* TODO: is center_freq changed when doing scan? */
/* TODO: Shall we add protection or just skip those two step? */
rx_status->freq = hw->conf.chandef.chan->center_freq;
@@ -406,10 +406,8 @@ static void _rtl_rx_process(struct ieee80211_hw *hw, struct sk_buff *skb)
if (GET_RX_DESC_RX_HT(rxdesc))
rx_status->flag |= RX_FLAG_HT;
/* Data rate */
- rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- (bool)GET_RX_DESC_RX_HT(rxdesc),
- (u8)GET_RX_DESC_RX_MCS(rxdesc),
- (bool)GET_RX_DESC_PAGGR(rxdesc));
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats.is_ht,
+ false, stats.rate);
/* There is a phy status after this rx descriptor. */
if (GET_RX_DESC_PHY_STATUS(rxdesc)) {
p_drvinfo = (struct rx_fwinfo_92c *)(rxdesc + RTL_RX_DESC_SIZE);
@@ -545,7 +543,7 @@ void rtl92cu_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_BW(txdesc, 0);
SET_TX_DESC_RTS_SC(txdesc, tcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(txdesc,
- ((tcb_desc->rts_rate <= DESC92_RATE54M) ?
+ ((tcb_desc->rts_rate <= DESC_RATE54M) ?
(tcb_desc->rts_use_shortpreamble ? 1 : 0)
: (tcb_desc->rts_use_shortgi ? 1 : 0)));
if (mac->bw_40) {
@@ -644,7 +642,7 @@ void rtl92cu_fill_fake_txdesc(struct ieee80211_hw *hw, u8 * pDesc,
}
SET_TX_DESC_USE_RATE(pDesc, 1); /* use data rate which is set by Sw */
SET_TX_DESC_OWN(pDesc, 1);
- SET_TX_DESC_TX_RATE(pDesc, DESC92_RATE1M);
+ SET_TX_DESC_TX_RATE(pDesc, DESC_RATE1M);
_rtl_tx_desc_checksum(pDesc);
}
@@ -660,7 +658,7 @@ void rtl92cu_tx_fill_cmddesc(struct ieee80211_hw *hw,
memset((void *)pdesc, 0, RTL_TX_HEADER_SIZE);
if (firstseg)
SET_TX_DESC_OFFSET(pdesc, RTL_TX_HEADER_SIZE);
- SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M);
SET_TX_DESC_SEQ(pdesc, 0);
SET_TX_DESC_LINIP(pdesc, 0);
SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
index 304c443b89b2..a1be5a68edfb 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.c
@@ -29,6 +29,7 @@
#include "../wifi.h"
#include "../base.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -155,34 +156,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */
};
-static void rtl92d_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *de_digtable = &rtlpriv->dm_digtable;
-
- de_digtable->dig_enable_flag = true;
- de_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
- de_digtable->cur_igvalue = 0x20;
- de_digtable->pre_igvalue = 0x0;
- de_digtable->cursta_cstate = DIG_STA_DISCONNECT;
- de_digtable->presta_cstate = DIG_STA_DISCONNECT;
- de_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
- de_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
- de_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
- de_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- de_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- de_digtable->rx_gain_max = DM_DIG_FA_UPPER;
- de_digtable->rx_gain_min = DM_DIG_FA_LOWER;
- de_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
- de_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
- de_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
- de_digtable->pre_cck_pd_state = CCK_PD_STAGE_LOWRSSI;
- de_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
- de_digtable->large_fa_hit = 0;
- de_digtable->recover_cnt = 0;
- de_digtable->forbidden_igi = DM_DIG_FA_LOWER;
-}
-
static void rtl92d_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
{
u32 ret_value;
@@ -1305,7 +1278,9 @@ void rtl92d_dm_init(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
- rtl92d_dm_diginit(hw);
+ rtl_dm_diginit(hw, 0x20);
+ rtlpriv->dm_digtable.rx_gain_max = DM_DIG_FA_UPPER;
+ rtlpriv->dm_digtable.rx_gain_min = DM_DIG_FA_LOWER;
rtl92d_dm_init_dynamic_txpower(hw);
rtl92d_dm_init_edca_turbo(hw);
rtl92d_dm_init_rate_adaptive_mask(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h
index 3fea0c11c24a..f2d318ceeb28 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/dm.h
@@ -42,25 +42,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1c
-
#define DM_DIG_FA_UPPER 0x32
#define DM_DIG_FA_LOWER 0x20
#define DM_DIG_FA_TH0 0x100
#define DM_DIG_FA_TH1 0x400
#define DM_DIG_FA_TH2 0x600
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_lOW 30
#define RXPATHSELECTION_DIFF_TH 18
@@ -108,14 +95,6 @@ enum tag_dynamic_init_gain_operation_type_definition {
DIG_OP_TYPE_MAX
};
-enum tag_cck_packet_detection_threshold_type_definition {
- CCK_PD_STAGE_LOWRSSI = 0,
- CCK_PD_STAGE_HIGHRSSI = 1,
- CCK_FA_STAGE_LOW = 2,
- CCK_FA_STAGE_HIGH = 3,
- CCK_PD_STAGE_MAX = 4,
-};
-
enum dm_1r_cca {
CCA_1R = 0,
CCA_2R = 1,
@@ -134,23 +113,6 @@ enum dm_sw_ant_switch {
ANS_ANTENNA_MAX = 3,
};
-enum dm_dig_ext_port_alg {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_MULTISTA_DISCONNECT = 3,
- DIG_MULTISTA_CONNECT = 4,
- DIG_CONNECT_MAX
-};
-
void rtl92d_dm_init(struct ieee80211_hw *hw);
void rtl92d_dm_watchdog(struct ieee80211_hw *hw);
void rtl92d_dm_init_edca_turbo(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
index 23177076b97f..62ef8209718f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.c
@@ -540,23 +540,6 @@ void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw,
return;
}
-void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- u8 u1_h2c_set_pwrmode[3] = { 0 };
- struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-
- RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
- SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
- SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
- SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
- ppsc->reg_max_lps_awakeintvl);
- RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
- "rtl92d_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode",
- u1_h2c_set_pwrmode, 3);
- rtl92d_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
-}
-
static bool _rtl92d_cmd_send_packet(struct ieee80211_hw *hw,
struct sk_buff *skb)
{
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h
index a55a803a0b4d..1646e7c3d0f8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/fw.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/fw.h
@@ -136,7 +136,6 @@ int rtl92d_download_fw(struct ieee80211_hw *hw);
void rtl92d_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
u32 cmd_len, u8 *p_cmdbuffer);
void rtl92d_firmware_selfreset(struct ieee80211_hw *hw);
-void rtl92d_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
void rtl92d_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
void rtl92d_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
index 280c3da42993..01bcc2d218dc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/hw.c
@@ -546,7 +546,7 @@ static bool _rtl92de_llt_table_init(struct ieee80211_hw *hw)
txpktbuf_bndy = 246;
value8 = 0;
value32 = 0x80bf0d29;
- } else if (rtlpriv->rtlhal.macphymode != SINGLEMAC_SINGLEPHY) {
+ } else {
maxPage = 127;
txpktbuf_bndy = 123;
value8 = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
index a0aba088259a..b19d0398215f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/sw.c
@@ -337,21 +337,21 @@ static struct rtl_hal_cfg rtl92de_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
-
- .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15,
};
static struct pci_device_id rtl92de_pci_ids[] = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
index 8efbcc7af250..1feaa629dd4f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192de/trx.c
@@ -235,8 +235,8 @@ static void _rtl92de_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rx_pwdb_all = pwdb_all;
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (pdesc->rxht && pdesc->rxmcs >= DESC92_RATEMCS8 &&
- pdesc->rxmcs <= DESC92_RATEMCS15)
+ if (pdesc->rxht && pdesc->rxmcs >= DESC_RATEMCS8 &&
+ pdesc->rxmcs <= DESC_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -499,6 +499,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
&& (GET_RX_DESC_FAGGR(pdesc) == 1));
stats->timestamp_low = GET_RX_DESC_TSFL(pdesc);
stats->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+ stats->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
rx_status->freq = hw->conf.chandef.chan->center_freq;
rx_status->band = hw->conf.chandef.chan->band;
if (GET_RX_DESC_CRC32(pdesc))
@@ -512,10 +513,8 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
rx_status->flag |= RX_FLAG_MACTIME_START;
if (stats->decrypted)
rx_status->flag |= RX_FLAG_DECRYPTED;
- rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- (bool)GET_RX_DESC_RXHT(pdesc),
- (u8)GET_RX_DESC_RXMCS(pdesc),
- (bool)GET_RX_DESC_PAGGR(pdesc));
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht,
+ false, stats->rate);
rx_status->mactime = GET_RX_DESC_TSFL(pdesc);
if (phystatus) {
p_drvinfo = (struct rx_fwinfo_92d *)(skb->data +
@@ -612,14 +611,14 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
}
/* 5G have no CCK rate */
if (rtlhal->current_bandtype == BAND_ON_5G)
- if (ptcb_desc->hw_rate < DESC92_RATE6M)
- ptcb_desc->hw_rate = DESC92_RATE6M;
+ if (ptcb_desc->hw_rate < DESC_RATE6M)
+ ptcb_desc->hw_rate = DESC_RATE6M;
SET_TX_DESC_TX_RATE(pdesc, ptcb_desc->hw_rate);
if (ptcb_desc->use_shortgi || ptcb_desc->use_shortpreamble)
SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
if (rtlhal->macphymode == DUALMAC_DUALPHY &&
- ptcb_desc->hw_rate == DESC92_RATEMCS7)
+ ptcb_desc->hw_rate == DESC_RATEMCS7)
SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
if (info->flags & IEEE80211_TX_CTL_AMPDU) {
@@ -635,13 +634,13 @@ void rtl92de_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_STBC(pdesc, ((ptcb_desc->rts_stbc) ? 1 : 0));
/* 5G have no CCK rate */
if (rtlhal->current_bandtype == BAND_ON_5G)
- if (ptcb_desc->rts_rate < DESC92_RATE6M)
- ptcb_desc->rts_rate = DESC92_RATE6M;
+ if (ptcb_desc->rts_rate < DESC_RATE6M)
+ ptcb_desc->rts_rate = DESC_RATE6M;
SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
SET_TX_DESC_RTS_BW(pdesc, 0);
SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
- DESC92_RATE54M) ?
+ DESC_RATE54M) ?
(ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
(ptcb_desc->rts_use_shortgi ? 1 : 0)));
if (bw_40) {
@@ -756,9 +755,9 @@ void rtl92de_tx_fill_cmddesc(struct ieee80211_hw *hw,
* The braces are needed no matter what checkpatch says
*/
if (rtlhal->current_bandtype == BAND_ON_5G) {
- SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE6M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC_RATE6M);
} else {
- SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M);
}
SET_TX_DESC_SEQ(pdesc, 0);
SET_TX_DESC_LINIP(pdesc, 0);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c
index 77deedf79d1d..459f3d0efa2f 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.c
@@ -26,6 +26,7 @@
#include "../wifi.h"
#include "../base.h"
#include "../pci.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -151,35 +152,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00} /* 32, -16.0dB */
};
-static void rtl92ee_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *dm_dig = &rtlpriv->dm_digtable;
-
- dm_dig->cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N,
- DM_BIT_IGI_11N);
- dm_dig->rssi_lowthresh = DM_DIG_THRESH_LOW;
- dm_dig->rssi_highthresh = DM_DIG_THRESH_HIGH;
- dm_dig->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- dm_dig->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_dig->rx_gain_max = DM_DIG_MAX;
- dm_dig->rx_gain_min = DM_DIG_MIN;
- dm_dig->back_val = DM_DIG_BACKOFF_DEFAULT;
- dm_dig->back_range_max = DM_DIG_BACKOFF_MAX;
- dm_dig->back_range_min = DM_DIG_BACKOFF_MIN;
- dm_dig->pre_cck_cca_thres = 0xff;
- dm_dig->cur_cck_cca_thres = 0x83;
- dm_dig->forbidden_igi = DM_DIG_MIN;
- dm_dig->large_fa_hit = 0;
- dm_dig->recover_cnt = 0;
- dm_dig->dig_dynamic_min = DM_DIG_MIN;
- dm_dig->dig_dynamic_min_1 = DM_DIG_MIN;
- dm_dig->media_connect_0 = false;
- dm_dig->media_connect_1 = false;
- rtlpriv->dm.dm_initialgain_enable = true;
- dm_dig->bt30_cur_igi = 0x32;
-}
-
static void rtl92ee_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
{
u32 ret_value;
@@ -298,7 +270,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct dig_t *dm_dig = &rtlpriv->dm_digtable;
- u8 dig_dynamic_min , dig_maxofmin;
+ u8 dig_min_0, dig_maxofmin;
bool bfirstconnect , bfirstdisconnect;
u8 dm_dig_max, dm_dig_min;
u8 current_igi = dm_dig->cur_igvalue;
@@ -308,7 +280,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw)
if (mac->act_scanning)
return;
- dig_dynamic_min = dm_dig->dig_dynamic_min;
+ dig_min_0 = dm_dig->dig_min_0;
bfirstconnect = (mac->link_state >= MAC80211_LINKED) &&
!dm_dig->media_connect_0;
bfirstdisconnect = (mac->link_state < MAC80211_LINKED) &&
@@ -329,19 +301,19 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw)
if (rtlpriv->dm.one_entry_only) {
offset = 0;
if (dm_dig->rssi_val_min - offset < dm_dig_min)
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
else if (dm_dig->rssi_val_min - offset >
dig_maxofmin)
- dig_dynamic_min = dig_maxofmin;
+ dig_min_0 = dig_maxofmin;
else
- dig_dynamic_min = dm_dig->rssi_val_min - offset;
+ dig_min_0 = dm_dig->rssi_val_min - offset;
} else {
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
}
} else {
dm_dig->rx_gain_max = dm_dig_max;
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
}
@@ -368,10 +340,10 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw)
} else {
if (dm_dig->large_fa_hit < 3) {
if ((dm_dig->forbidden_igi - 1) <
- dig_dynamic_min) {
- dm_dig->forbidden_igi = dig_dynamic_min;
+ dig_min_0) {
+ dm_dig->forbidden_igi = dig_min_0;
dm_dig->rx_gain_min =
- dig_dynamic_min;
+ dig_min_0;
} else {
dm_dig->forbidden_igi--;
dm_dig->rx_gain_min =
@@ -430,7 +402,7 @@ static void rtl92ee_dm_dig(struct ieee80211_hw *hw)
rtl92ee_dm_write_dig(hw , current_igi);
dm_dig->media_connect_0 = ((mac->link_state >= MAC80211_LINKED) ?
true : false);
- dm_dig->dig_dynamic_min = dig_dynamic_min;
+ dm_dig->dig_min_0 = dig_min_0;
}
void rtl92ee_dm_write_cck_cca_thres(struct ieee80211_hw *hw, u8 cur_thres)
@@ -1088,10 +1060,11 @@ static void rtl92ee_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
void rtl92ee_dm_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 cur_igvalue = rtl_get_bbreg(hw, DM_REG_IGI_A_11N, DM_BIT_IGI_11N);
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
- rtl92ee_dm_diginit(hw);
+ rtl_dm_diginit(hw, cur_igvalue);
rtl92ee_dm_init_rate_adaptive_mask(hw);
rtl92ee_dm_init_primary_cca_check(hw);
rtl92ee_dm_init_edca_turbo(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h
index 881db7d6fef7..107d5a488fa8 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/dm.h
@@ -189,28 +189,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
-#define DM_DIG_MAX_AP 0x32
-#define DM_DIG_MIN_AP 0x20
-
#define DM_DIG_FA_UPPER 0x3e
#define DM_DIG_FA_LOWER 0x1e
#define DM_DIG_FA_TH0 0x200
#define DM_DIG_FA_TH1 0x300
#define DM_DIG_FA_TH2 0x400
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_LOW 30
#define RXPATHSELECTION_DIFF_TH 18
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
index 45c128b91f7f..c5d4b8013cde 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/fw.c
@@ -666,7 +666,6 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
struct sk_buff *skb = NULL;
u32 totalpacketlen;
- bool rtstatus;
u8 u1rsvdpageloc[5] = { 0 };
bool b_dlok = false;
@@ -728,10 +727,7 @@ void rtl92ee_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished)
memcpy((u8 *)skb_put(skb, totalpacketlen),
&reserved_page_packet, totalpacketlen);
- rtstatus = rtl_cmd_send_packet(hw, skb);
-
- if (rtstatus)
- b_dlok = true;
+ b_dlok = true;
if (b_dlok) {
RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD ,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
index 1a87edca2c3f..b461b3128da5 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/hw.c
@@ -85,29 +85,6 @@ static void _rtl92ee_enable_bcn_sub_func(struct ieee80211_hw *hw)
_rtl92ee_set_bcn_ctrl_reg(hw, 0, BIT(1));
}
-static void _rtl92ee_return_beacon_queue_skb(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
- struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
- unsigned long flags;
-
- spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
- while (skb_queue_len(&ring->queue)) {
- struct rtl_tx_buffer_desc *entry =
- &ring->buffer_desc[ring->idx];
- struct sk_buff *skb = __skb_dequeue(&ring->queue);
-
- pci_unmap_single(rtlpci->pdev,
- rtlpriv->cfg->ops->get_desc(
- (u8 *)entry, true, HW_DESC_TXBUFF_ADDR),
- skb->len, PCI_DMA_TODEVICE);
- kfree_skb(skb);
- ring->idx = (ring->idx + 1) % ring->entries;
- }
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-}
-
static void _rtl92ee_disable_bcn_sub_func(struct ieee80211_hw *hw)
{
_rtl92ee_set_bcn_ctrl_reg(hw, BIT(1), 0);
@@ -403,9 +380,6 @@ static void _rtl92ee_download_rsvd_page(struct ieee80211_hw *hw)
rtl_write_byte(rtlpriv, REG_DWBCN0_CTRL + 2,
bcnvalid_reg | BIT(0));
- /* Return Beacon TCB */
- _rtl92ee_return_beacon_queue_skb(hw);
-
/* download rsvd page */
rtl92ee_set_fw_rsvdpagepkt(hw, false);
@@ -1163,6 +1137,139 @@ void rtl92ee_enable_hw_security_config(struct ieee80211_hw *hw)
rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
}
+static bool _rtl8192ee_check_pcie_dma_hang(struct rtl_priv *rtlpriv)
+{
+ u8 tmp;
+
+ /* write reg 0x350 Bit[26]=1. Enable debug port. */
+ tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3);
+ if (!(tmp & BIT(2))) {
+ rtl_write_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3,
+ tmp | BIT(2));
+ mdelay(100); /* Suggested by DD Justin_tsai. */
+ }
+
+ /* read reg 0x350 Bit[25] if 1 : RX hang
+ * read reg 0x350 Bit[24] if 1 : TX hang
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_BACKDOOR_DBI_DATA + 3);
+ if ((tmp & BIT(0)) || (tmp & BIT(1))) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "CheckPcieDMAHang8192EE(): true!!\n");
+ return true;
+ }
+ return false;
+}
+
+static void _rtl8192ee_reset_pcie_interface_dma(struct rtl_priv *rtlpriv,
+ bool mac_power_on)
+{
+ u8 tmp;
+ bool release_mac_rx_pause;
+ u8 backup_pcie_dma_pause;
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "ResetPcieInterfaceDMA8192EE()\n");
+
+ /* Revise Note: Follow the document "PCIe RX DMA Hang Reset Flow_v03"
+ * released by SD1 Alan.
+ */
+
+ /* 1. disable register write lock
+ * write 0x1C bit[1:0] = 2'h0
+ * write 0xCC bit[2] = 1'b1
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL);
+ tmp &= ~(BIT(1) | BIT(0));
+ rtl_write_byte(rtlpriv, REG_RSV_CTRL, tmp);
+ tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+ tmp |= BIT(2);
+ rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+
+ /* 2. Check and pause TRX DMA
+ * write 0x284 bit[18] = 1'b1
+ * write 0x301 = 0xFF
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ if (tmp & BIT(2)) {
+ /* Already pause before the function for another reason. */
+ release_mac_rx_pause = false;
+ } else {
+ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL, (tmp | BIT(2)));
+ release_mac_rx_pause = true;
+ }
+
+ backup_pcie_dma_pause = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG + 1);
+ if (backup_pcie_dma_pause != 0xFF)
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1, 0xFF);
+
+ if (mac_power_on) {
+ /* 3. reset TRX function
+ * write 0x100 = 0x00
+ */
+ rtl_write_byte(rtlpriv, REG_CR, 0);
+ }
+
+ /* 4. Reset PCIe DMA
+ * write 0x003 bit[0] = 0
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmp &= ~(BIT(0));
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+ /* 5. Enable PCIe DMA
+ * write 0x003 bit[0] = 1
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+ tmp |= BIT(0);
+ rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp);
+
+ if (mac_power_on) {
+ /* 6. enable TRX function
+ * write 0x100 = 0xFF
+ */
+ rtl_write_byte(rtlpriv, REG_CR, 0xFF);
+
+ /* We should init LLT & RQPN and
+ * prepare Tx/Rx descrptor address later
+ * because MAC function is reset.
+ */
+ }
+
+ /* 7. Restore PCIe autoload down bit
+ * write 0xF8 bit[17] = 1'b1
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2);
+ tmp |= BIT(1);
+ rtl_write_byte(rtlpriv, REG_MAC_PHY_CTRL_NORMAL + 2, tmp);
+
+ /* In MAC power on state, BB and RF maybe in ON state,
+ * if we release TRx DMA here
+ * it will cause packets to be started to Tx/Rx,
+ * so we release Tx/Rx DMA later.
+ */
+ if (!mac_power_on) {
+ /* 8. release TRX DMA
+ * write 0x284 bit[18] = 1'b0
+ * write 0x301 = 0x00
+ */
+ if (release_mac_rx_pause) {
+ tmp = rtl_read_byte(rtlpriv, REG_RXDMA_CONTROL);
+ rtl_write_byte(rtlpriv, REG_RXDMA_CONTROL,
+ (tmp & (~BIT(2))));
+ }
+ rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 1,
+ backup_pcie_dma_pause);
+ }
+
+ /* 9. lock system register
+ * write 0xCC bit[2] = 1'b0
+ */
+ tmp = rtl_read_byte(rtlpriv, REG_PMC_DBG_CTRL2);
+ tmp &= ~(BIT(2));
+ rtl_write_byte(rtlpriv, REG_PMC_DBG_CTRL2, tmp);
+}
+
int rtl92ee_hw_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1188,6 +1295,13 @@ int rtl92ee_hw_init(struct ieee80211_hw *hw)
rtlhal->fw_ps_state = FW_PS_STATE_ALL_ON_92E;
}
+ if (_rtl8192ee_check_pcie_dma_hang(rtlpriv)) {
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "92ee dma hang!\n");
+ _rtl8192ee_reset_pcie_interface_dma(rtlpriv,
+ rtlhal->mac_func_enable);
+ rtlhal->mac_func_enable = false;
+ }
+
rtstatus = _rtl92ee_init_mac(hw);
rtl_write_byte(rtlpriv, 0x577, 0x03);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
index 3f2a9596e7cd..1eaa1fab550d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/reg.h
@@ -77,9 +77,11 @@
#define REG_HIMRE 0x00B8
#define REG_HISRE 0x00BC
+#define REG_PMC_DBG_CTRL2 0x00CC
#define REG_EFUSE_ACCESS 0x00CF
#define REG_HPON_FSM 0x00EC
#define REG_SYS_CFG1 0x00F0
+#define REG_MAC_PHY_CTRL_NORMAL 0x00F8
#define REG_SYS_CFG2 0x00FC
#define REG_CR 0x0100
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
index 9b5a7d5be121..c31c6bfb536d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/sw.c
@@ -113,8 +113,6 @@ int rtl92ee_init_sw_vars(struct ieee80211_hw *hw)
RCR_HTC_LOC_CTRL |
RCR_AMF |
RCR_ACF |
- RCR_ADF |
- RCR_AICV |
RCR_ACRC32 |
RCR_AB |
RCR_AM |
@@ -241,6 +239,7 @@ static struct rtl_hal_ops rtl8192ee_hal_ops = {
.set_desc = rtl92ee_set_desc,
.get_desc = rtl92ee_get_desc,
.is_tx_desc_closed = rtl92ee_is_tx_desc_closed,
+ .get_available_desc = rtl92ee_get_available_desc,
.tx_polling = rtl92ee_tx_polling,
.enable_hw_sec = rtl92ee_enable_hw_security_config,
.set_key = rtl92ee_set_key,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
index 2fcbef1d029f..d39ee67f6113 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.c
@@ -47,164 +47,6 @@ static u8 _rtl92ee_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-/* mac80211's rate_idx is like this:
- *
- * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
- *
- * B/G rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- *
- * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
- * A rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- */
-static int _rtl92ee_rate_mapping(struct ieee80211_hw *hw,
- bool isht, u8 desc_rate)
-{
- int rate_idx;
-
- if (!isht) {
- if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATE6M:
- rate_idx = 0;
- break;
- case DESC92C_RATE9M:
- rate_idx = 1;
- break;
- case DESC92C_RATE12M:
- rate_idx = 2;
- break;
- case DESC92C_RATE18M:
- rate_idx = 3;
- break;
- case DESC92C_RATE24M:
- rate_idx = 4;
- break;
- case DESC92C_RATE36M:
- rate_idx = 5;
- break;
- case DESC92C_RATE48M:
- rate_idx = 6;
- break;
- case DESC92C_RATE54M:
- rate_idx = 7;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATEMCS0:
- rate_idx = 0;
- break;
- case DESC92C_RATEMCS1:
- rate_idx = 1;
- break;
- case DESC92C_RATEMCS2:
- rate_idx = 2;
- break;
- case DESC92C_RATEMCS3:
- rate_idx = 3;
- break;
- case DESC92C_RATEMCS4:
- rate_idx = 4;
- break;
- case DESC92C_RATEMCS5:
- rate_idx = 5;
- break;
- case DESC92C_RATEMCS6:
- rate_idx = 6;
- break;
- case DESC92C_RATEMCS7:
- rate_idx = 7;
- break;
- case DESC92C_RATEMCS8:
- rate_idx = 8;
- break;
- case DESC92C_RATEMCS9:
- rate_idx = 9;
- break;
- case DESC92C_RATEMCS10:
- rate_idx = 10;
- break;
- case DESC92C_RATEMCS11:
- rate_idx = 11;
- break;
- case DESC92C_RATEMCS12:
- rate_idx = 12;
- break;
- case DESC92C_RATEMCS13:
- rate_idx = 13;
- break;
- case DESC92C_RATEMCS14:
- rate_idx = 14;
- break;
- case DESC92C_RATEMCS15:
- rate_idx = 15;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- return rate_idx;
-}
-
static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw,
struct rtl_stats *pstatus, u8 *pdesc,
struct rx_fwinfo *p_drvinfo,
@@ -345,8 +187,8 @@ static void _rtl92ee_query_rxphystatus(struct ieee80211_hw *hw,
pstatus->recvsignalpower = rx_pwr_all;
/* (3)EVM of HT rate */
- if (pstatus->rate >= DESC92C_RATEMCS8 &&
- pstatus->rate <= DESC92C_RATEMCS15)
+ if (pstatus->rate >= DESC_RATEMCS8 &&
+ pstatus->rate <= DESC_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -512,6 +354,10 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw,
struct ieee80211_hdr *hdr;
u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+ if (GET_RX_STATUS_DESC_RPT_SEL(pdesc) == 0)
+ status->packet_report_type = NORMAL_RX;
+ else
+ status->packet_report_type = C2H_PACKET;
status->length = (u16)GET_RX_DESC_PKT_LEN(pdesc);
status->rx_drvinfo_size = (u8)GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
RX_DRV_INFO_SIZE_UNIT;
@@ -576,9 +422,8 @@ bool rtl92ee_rx_query_desc(struct ieee80211_hw *hw,
* are use (RX_FLAG_HT)
* Notice: this is diff with windows define
*/
- rx_status->rate_idx = _rtl92ee_rate_mapping(hw,
- status->is_ht,
- status->rate);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ false, status->rate);
rx_status->mactime = status->timestamp_low;
if (phystatus) {
@@ -654,14 +499,7 @@ u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw, u8 queue_index)
if (!start_rx)
return 0;
- if ((last_read_point > (RX_DESC_NUM_92E / 2)) &&
- (read_point <= (RX_DESC_NUM_92E / 2))) {
- remind_cnt = RX_DESC_NUM_92E - write_point;
- } else {
- remind_cnt = (read_point >= write_point) ?
- (read_point - write_point) :
- (RX_DESC_NUM_92E - write_point + read_point);
- }
+ remind_cnt = calc_fifo_space(read_point, write_point);
if (remind_cnt == 0)
return 0;
@@ -710,7 +548,7 @@ static u16 get_desc_addr_fr_q_idx(u16 queue_index)
return desc_address;
}
-void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
+u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
{
struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -723,12 +561,11 @@ void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 q_idx)
current_tx_read_point = (u16)((tmp_4byte >> 16) & 0x0fff);
current_tx_write_point = (u16)((tmp_4byte) & 0x0fff);
- point_diff = ((current_tx_read_point > current_tx_write_point) ?
- (current_tx_read_point - current_tx_write_point) :
- (TX_DESC_NUM_92E - current_tx_write_point +
- current_tx_read_point));
+ point_diff = calc_fifo_space(current_tx_read_point,
+ current_tx_write_point);
rtlpci->tx_ring[q_idx].avl_desc = point_diff;
+ return point_diff;
}
void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
@@ -901,13 +738,13 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw,
} else {
if (rtlpriv->ra.is_special_data) {
ptcb_desc->use_driver_rate = true;
- SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE11M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC_RATE11M);
} else {
ptcb_desc->use_driver_rate = false;
}
}
- if (ptcb_desc->hw_rate > DESC92C_RATEMCS0)
+ if (ptcb_desc->hw_rate > DESC_RATEMCS0)
short_gi = (ptcb_desc->use_shortgi) ? 1 : 0;
else
short_gi = (ptcb_desc->use_shortpreamble) ? 1 : 0;
@@ -927,7 +764,7 @@ void rtl92ee_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_RATE(pdesc, ptcb_desc->rts_rate);
SET_TX_DESC_RTS_SC(pdesc, ptcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc,
- ((ptcb_desc->rts_rate <= DESC92C_RATE54M) ?
+ ((ptcb_desc->rts_rate <= DESC_RATE54M) ?
(ptcb_desc->rts_use_shortpreamble ? 1 : 0) :
(ptcb_desc->rts_use_shortgi ? 1 : 0)));
@@ -1038,7 +875,7 @@ void rtl92ee_tx_fill_cmddesc(struct ieee80211_hw *hw,
if (firstseg)
SET_TX_DESC_OFFSET(pdesc, txdesc_len);
- SET_TX_DESC_TX_RATE(pdesc, DESC92C_RATE1M);
+ SET_TX_DESC_TX_RATE(pdesc, DESC_RATE1M);
SET_TX_DESC_SEQ(pdesc, 0);
@@ -1207,8 +1044,7 @@ bool rtl92ee_is_tx_desc_closed(struct ieee80211_hw *hw, u8 hw_queue, u16 index)
static u8 stop_report_cnt;
struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
- /*checking Read/Write Point each interrupt wastes CPU */
- if (stop_report_cnt > 15 || !rtlpriv->link_info.busytraffic) {
+ {
u16 point_diff = 0;
u16 cur_tx_rp, cur_tx_wp;
u32 tmpu32 = 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
index 6f9be1c7515c..8f78ac9e6040 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192ee/trx.h
@@ -542,6 +542,8 @@
LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
#define GET_RX_DESC_RX_IS_QOS(__pdesc) \
LE_BITS_TO_4BYTE(__pdesc+8, 16, 1)
+#define GET_RX_STATUS_DESC_RPT_SEL(__pdesc) \
+ LE_BITS_TO_4BYTE(__pdesc+8, 28, 1)
#define GET_RX_DESC_RXMCS(__pdesc) \
LE_BITS_TO_4BYTE(__pdesc+12, 0, 7)
@@ -591,10 +593,10 @@ do { \
} while (0)
#define RTL92EE_RX_HAL_IS_CCK_RATE(rxmcs)\
- (rxmcs == DESC92C_RATE1M ||\
- rxmcs == DESC92C_RATE2M ||\
- rxmcs == DESC92C_RATE5_5M ||\
- rxmcs == DESC92C_RATE11M)
+ (rxmcs == DESC_RATE1M ||\
+ rxmcs == DESC_RATE2M ||\
+ rxmcs == DESC_RATE5_5M ||\
+ rxmcs == DESC_RATE11M)
#define IS_LITTLE_ENDIAN 1
@@ -829,7 +831,7 @@ void rtl92ee_rx_check_dma_ok(struct ieee80211_hw *hw, u8 *header_desc,
u8 queue_index);
u16 rtl92ee_rx_desc_buff_remained_cnt(struct ieee80211_hw *hw,
u8 queue_index);
-void rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index);
+u16 rtl92ee_get_available_desc(struct ieee80211_hw *hw, u8 queue_index);
void rtl92ee_pre_fill_tx_bd_desc(struct ieee80211_hw *hw,
u8 *tx_bd_desc, u8 *desc, u8 queue_index,
struct sk_buff *skb, dma_addr_t addr);
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/def.h b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
index 6e7a70b43949..ef87c09b77d0 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/def.h
@@ -450,10 +450,10 @@
SHIFT_AND_MASK_LE(__pdesc + 24, 0, 32)
#define SE_RX_HAL_IS_CCK_RATE(_pdesc)\
- (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE1M || \
- GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE2M || \
- GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE5_5M ||\
- GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC92_RATE11M)
+ (GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE1M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE2M || \
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE5_5M ||\
+ GET_RX_STATUS_DESC_RX_MCS(_pdesc) == DESC_RATE11M)
enum rf_optype {
RF_OP_BY_SW_3WIRE = 0,
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
index b3a2d5ec59e6..575980b88658 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.c
@@ -29,6 +29,7 @@
#include "../wifi.h"
#include "../base.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -469,7 +470,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
if (digtable->backoff_enable_flag)
rtl92s_backoff_enable_flag(hw);
else
- digtable->back_val = DM_DIG_BACKOFF;
+ digtable->back_val = DM_DIG_BACKOFF_MAX;
if ((digtable->rssi_val + 10 - digtable->back_val) >
digtable->rx_gain_max)
@@ -503,7 +504,7 @@ static void _rtl92s_dm_initial_gain_sta_beforeconnect(struct ieee80211_hw *hw)
digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
rtl92s_phy_set_fw_cmd(hw, FW_CMD_DIG_ENABLE);
- digtable->back_val = DM_DIG_BACKOFF;
+ digtable->back_val = DM_DIG_BACKOFF_MAX;
digtable->cur_igvalue = rtlpriv->phy.default_initialgain[0];
digtable->pre_igvalue = 0;
return;
@@ -691,7 +692,7 @@ static void _rtl92s_dm_init_dig(struct ieee80211_hw *hw)
/* for dig debug rssi value */
digtable->rssi_val = 50;
- digtable->back_val = DM_DIG_BACKOFF;
+ digtable->back_val = DM_DIG_BACKOFF_MAX;
digtable->rx_gain_max = DM_DIG_MAX;
digtable->rx_gain_min = DM_DIG_MIN;
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
index 2e9052c8fe4b..de6ac796c74d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/dm.h
@@ -54,24 +54,6 @@ enum dm_dig_sta {
DM_STA_DIG_MAX
};
-enum dm_dig_connect {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_AP_DISCONNECT = 3,
- DIG_AP_CONNECT = 4,
- DIG_AP_ADD_STATION = 5,
- DIG_CONNECT_MAX
-};
-
-enum dm_dig_ext_port_alg {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
enum dm_ratr_sta {
DM_RATR_STA_HIGH = 0,
DM_RATR_STA_MIDDLEHIGH = 1,
@@ -99,22 +81,12 @@ enum dm_ratr_sta {
#define TX_POWER_NEAR_FIELD_THRESH_LVL2 74
#define TX_POWER_NEAR_FIELD_THRESH_LVL1 67
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-#define DM_FALSEALARM_THRESH_LOW 40
-#define DM_FALSEALARM_THRESH_HIGH 1000
#define DM_DIG_HIGH_PWR_THRESH_HIGH 75
#define DM_DIG_HIGH_PWR_THRESH_LOW 70
-#define DM_DIG_BACKOFF 12
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1c
#define DM_DIG_MIN_Netcore 0x12
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
void rtl92s_dm_watchdog(struct ieee80211_hw *hw);
void rtl92s_dm_init(struct ieee80211_hw *hw);
void rtl92s_dm_init_edca_turbo(struct ieee80211_hw *hw);
#endif
-
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
index fb003868bdef..e1fd27c888bf 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/sw.c
@@ -383,21 +383,21 @@ static struct rtl_hal_cfg rtl92se_hal_cfg = {
.maps[RTL_IMR_ROK] = IMR_ROK,
.maps[RTL_IBSS_INT_MASKS] = (IMR_BCNINT | IMR_TBDOK | IMR_TBDER),
- .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
- .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
- .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
- .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
- .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
- .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
- .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
- .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
- .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
- .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
- .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
- .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
-
- .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
- .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
+ .maps[RTL_RC_CCK_RATE1M] = DESC_RATE1M,
+ .maps[RTL_RC_CCK_RATE2M] = DESC_RATE2M,
+ .maps[RTL_RC_CCK_RATE5_5M] = DESC_RATE5_5M,
+ .maps[RTL_RC_CCK_RATE11M] = DESC_RATE11M,
+ .maps[RTL_RC_OFDM_RATE6M] = DESC_RATE6M,
+ .maps[RTL_RC_OFDM_RATE9M] = DESC_RATE9M,
+ .maps[RTL_RC_OFDM_RATE12M] = DESC_RATE12M,
+ .maps[RTL_RC_OFDM_RATE18M] = DESC_RATE18M,
+ .maps[RTL_RC_OFDM_RATE24M] = DESC_RATE24M,
+ .maps[RTL_RC_OFDM_RATE36M] = DESC_RATE36M,
+ .maps[RTL_RC_OFDM_RATE48M] = DESC_RATE48M,
+ .maps[RTL_RC_OFDM_RATE54M] = DESC_RATE54M,
+
+ .maps[RTL_RC_HT_RATEMCS7] = DESC_RATEMCS7,
+ .maps[RTL_RC_HT_RATEMCS15] = DESC_RATEMCS15,
};
static struct pci_device_id rtl92se_pci_ids[] = {
diff --git a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
index 672fd3b02835..125b29bd2f93 100644
--- a/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8192se/trx.c
@@ -191,8 +191,8 @@ static void _rtl92se_query_rxphystatus(struct ieee80211_hw *hw,
pstats->rxpower = rx_pwr_all;
pstats->recvsignalpower = rx_pwr_all;
- if (pstats->is_ht && pstats->rate >= DESC92_RATEMCS8 &&
- pstats->rate <= DESC92_RATEMCS15)
+ if (pstats->is_ht && pstats->rate >= DESC_RATEMCS8 &&
+ pstats->rate <= DESC_RATEMCS15)
max_spatial_stream = 2;
else
max_spatial_stream = 1;
@@ -264,7 +264,6 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
struct rx_fwinfo *p_drvinfo;
u32 phystatus = (u32)GET_RX_STATUS_DESC_PHY_STATUS(pdesc);
struct ieee80211_hdr *hdr;
- bool first_ampdu = false;
stats->length = (u16)GET_RX_STATUS_DESC_PKT_LEN(pdesc);
stats->rx_drvinfo_size = (u8)GET_RX_STATUS_DESC_DRVINFO_SIZE(pdesc) * 8;
@@ -319,8 +318,8 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
rx_status->flag |= RX_FLAG_DECRYPTED;
}
- rx_status->rate_idx = rtlwifi_rate_mapping(hw,
- stats->is_ht, stats->rate, first_ampdu);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, stats->is_ht,
+ false, stats->rate);
rx_status->mactime = stats->timestamp_low;
if (phystatus) {
@@ -394,14 +393,14 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RSVD_MACID(pdesc, reserved_macid);
SET_TX_DESC_TXHT(pdesc, ((ptcb_desc->hw_rate >=
- DESC92_RATEMCS0) ? 1 : 0));
+ DESC_RATEMCS0) ? 1 : 0));
if (rtlhal->version == VERSION_8192S_ACUT) {
- if (ptcb_desc->hw_rate == DESC92_RATE1M ||
- ptcb_desc->hw_rate == DESC92_RATE2M ||
- ptcb_desc->hw_rate == DESC92_RATE5_5M ||
- ptcb_desc->hw_rate == DESC92_RATE11M) {
- ptcb_desc->hw_rate = DESC92_RATE12M;
+ if (ptcb_desc->hw_rate == DESC_RATE1M ||
+ ptcb_desc->hw_rate == DESC_RATE2M ||
+ ptcb_desc->hw_rate == DESC_RATE5_5M ||
+ ptcb_desc->hw_rate == DESC_RATE11M) {
+ ptcb_desc->hw_rate = DESC_RATE12M;
}
}
@@ -430,7 +429,7 @@ void rtl92se_tx_fill_desc(struct ieee80211_hw *hw,
SET_TX_DESC_RTS_BANDWIDTH(pdesc, 0);
SET_TX_DESC_RTS_SUB_CARRIER(pdesc, ptcb_desc->rts_sc);
SET_TX_DESC_RTS_SHORT(pdesc, ((ptcb_desc->rts_rate <=
- DESC92_RATE54M) ?
+ DESC_RATE54M) ?
(ptcb_desc->rts_use_shortpreamble ? 1 : 0)
: (ptcb_desc->rts_use_shortgi ? 1 : 0)));
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
index a0e86922780a..4c1c96c96a5a 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
@@ -26,6 +26,7 @@
#include "../wifi.h"
#include "../base.h"
#include "../pci.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -146,31 +147,6 @@ static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
{0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}
};
-static void rtl8723e_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
-
- dm_digtable->dig_enable_flag = true;
- dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
- dm_digtable->cur_igvalue = 0x20;
- dm_digtable->pre_igvalue = 0x0;
- dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
- dm_digtable->presta_cstate = DIG_STA_DISCONNECT;
- dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
- dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
- dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
- dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_max = DM_DIG_MAX;
- dm_digtable->rx_gain_min = DM_DIG_MIN;
- dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
- dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
- dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
- dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
- dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
-}
-
static u8 rtl8723e_dm_initial_gain_min_pwdb(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -395,30 +371,30 @@ static void rtl8723e_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
dm_digtable->rssi_val_min = rtl8723e_dm_initial_gain_min_pwdb(hw);
- if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+ if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
if (dm_digtable->rssi_val_min <= 25)
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_LowRssi;
+ CCK_PD_STAGE_LOWRSSI;
else
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_HighRssi;
+ CCK_PD_STAGE_HIGHRSSI;
} else {
if (dm_digtable->rssi_val_min <= 20)
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_LowRssi;
+ CCK_PD_STAGE_LOWRSSI;
else
dm_digtable->cur_cck_pd_state =
- CCK_PD_STAGE_HighRssi;
+ CCK_PD_STAGE_HIGHRSSI;
}
} else {
dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
}
if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) {
- if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+ if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LOWRSSI) {
if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800)
dm_digtable->cur_cck_fa_state =
- CCK_FA_STAGE_High;
+ CCK_FA_STAGE_HIGH;
else
dm_digtable->cur_cck_fa_state =
CCK_FA_STAGE_LOW;
@@ -818,7 +794,7 @@ void rtl8723e_dm_init(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
- rtl8723e_dm_diginit(hw);
+ rtl_dm_diginit(hw, 0x20);
rtl8723_dm_init_dynamic_txpower(hw);
rtl8723_dm_init_edca_turbo(hw);
rtl8723e_dm_init_rate_adaptive_mask(hw);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
index 6fa0feb05f6d..57111052e86b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
@@ -42,25 +42,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
#define DM_DIG_FA_UPPER 0x32
#define DM_DIG_FA_LOWER 0x20
#define DM_DIG_FA_TH0 0x20
#define DM_DIG_FA_TH1 0x100
#define DM_DIG_FA_TH2 0x200
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_LOW 30
#define RXPATHSELECTION_DIFF_TH 18
@@ -108,14 +95,6 @@ enum tag_dynamic_init_gain_operation_type_definition {
DIG_OP_TYPE_MAX
};
-enum tag_cck_packet_detection_threshold_type_definition {
- CCK_PD_STAGE_LowRssi = 0,
- CCK_PD_STAGE_HighRssi = 1,
- CCK_FA_STAGE_LOW = 2,
- CCK_FA_STAGE_High = 3,
- CCK_PD_STAGE_MAX = 4,
-};
-
enum dm_1r_cca_e {
CCA_1R = 0,
CCA_2R = 1,
@@ -134,23 +113,6 @@ enum dm_sw_ant_switch_e {
ANS_ANTENNA_MAX = 3,
};
-enum dm_dig_ext_port_alg_e {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect_e {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_MULTISTA_DISCONNECT = 3,
- DIG_MULTISTA_CONNECT = 4,
- DIG_CONNECT_MAX
-};
-
#define BT_RSSI_STATE_NORMAL_POWER BIT_OFFSET_LEN_MASK_32(0, 1)
#define BT_RSSI_STATE_AMDPU_OFF BIT_OFFSET_LEN_MASK_32(1, 1)
#define BT_RSSI_STATE_SPECIAL_LOW BIT_OFFSET_LEN_MASK_32(2, 1)
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
index d372ccaf3465..2f7c144d7980 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
@@ -45,164 +45,6 @@ static u8 _rtl8723e_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-/* mac80211's rate_idx is like this:
- *
- * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
- *
- * B/G rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- *
- * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
- * A rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- */
-static int _rtl8723e_rate_mapping(struct ieee80211_hw *hw,
- bool isht, u8 desc_rate)
-{
- int rate_idx;
-
- if (!isht) {
- if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATE6M:
- rate_idx = 0;
- break;
- case DESC92C_RATE9M:
- rate_idx = 1;
- break;
- case DESC92C_RATE12M:
- rate_idx = 2;
- break;
- case DESC92C_RATE18M:
- rate_idx = 3;
- break;
- case DESC92C_RATE24M:
- rate_idx = 4;
- break;
- case DESC92C_RATE36M:
- rate_idx = 5;
- break;
- case DESC92C_RATE48M:
- rate_idx = 6;
- break;
- case DESC92C_RATE54M:
- rate_idx = 7;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATEMCS0:
- rate_idx = 0;
- break;
- case DESC92C_RATEMCS1:
- rate_idx = 1;
- break;
- case DESC92C_RATEMCS2:
- rate_idx = 2;
- break;
- case DESC92C_RATEMCS3:
- rate_idx = 3;
- break;
- case DESC92C_RATEMCS4:
- rate_idx = 4;
- break;
- case DESC92C_RATEMCS5:
- rate_idx = 5;
- break;
- case DESC92C_RATEMCS6:
- rate_idx = 6;
- break;
- case DESC92C_RATEMCS7:
- rate_idx = 7;
- break;
- case DESC92C_RATEMCS8:
- rate_idx = 8;
- break;
- case DESC92C_RATEMCS9:
- rate_idx = 9;
- break;
- case DESC92C_RATEMCS10:
- rate_idx = 10;
- break;
- case DESC92C_RATEMCS11:
- rate_idx = 11;
- break;
- case DESC92C_RATEMCS12:
- rate_idx = 12;
- break;
- case DESC92C_RATEMCS13:
- rate_idx = 13;
- break;
- case DESC92C_RATEMCS14:
- rate_idx = 14;
- break;
- case DESC92C_RATEMCS15:
- rate_idx = 15;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- return rate_idx;
-}
-
static void _rtl8723e_query_rxphystatus(struct ieee80211_hw *hw,
struct rtl_stats *pstatus, u8 *pdesc,
struct rx_fwinfo_8723e *p_drvinfo,
@@ -503,8 +345,8 @@ bool rtl8723e_rx_query_desc(struct ieee80211_hw *hw,
* are use (RX_FLAG_HT)
* Notice: this is diff with windows define
*/
- rx_status->rate_idx = _rtl8723e_rate_mapping(hw,
- status->is_ht, status->rate);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ false, status->rate);
rx_status->mactime = status->timestamp_low;
if (phystatus == true) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
index dd7eb4371f49..2367e8f47a5b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.c
@@ -26,6 +26,7 @@
#include "../wifi.h"
#include "../base.h"
#include "../pci.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -211,35 +212,6 @@ void rtl8723be_dm_txpower_track_adjust(struct ieee80211_hw *hw, u8 type,
(pwr_val << 16) | (pwr_val << 24);
}
-static void rtl8723be_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
-
- dm_digtable->dig_enable_flag = true;
- dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
- dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
- dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
- dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_max = DM_DIG_MAX;
- dm_digtable->rx_gain_min = DM_DIG_MIN;
- dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
- dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
- dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
- dm_digtable->pre_cck_cca_thres = 0xff;
- dm_digtable->cur_cck_cca_thres = 0x83;
- dm_digtable->forbidden_igi = DM_DIG_MIN;
- dm_digtable->large_fa_hit = 0;
- dm_digtable->recover_cnt = 0;
- dm_digtable->dig_dynamic_min = DM_DIG_MIN;
- dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN;
- dm_digtable->media_connect_0 = false;
- dm_digtable->media_connect_1 = false;
- rtlpriv->dm.dm_initialgain_enable = true;
- dm_digtable->bt30_cur_igi = 0x32;
-}
-
void rtl8723be_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -293,9 +265,10 @@ static void rtl8723be_dm_init_dynamic_atc_switch(struct ieee80211_hw *hw)
void rtl8723be_dm_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
+ u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
- rtl8723be_dm_diginit(hw);
+ rtl_dm_diginit(hw, cur_igvalue);
rtl8723be_dm_init_rate_adaptive_mask(hw);
rtl8723_dm_init_edca_turbo(hw);
rtl8723_dm_init_dynamic_bb_powersaving(hw);
@@ -424,7 +397,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
- u8 dig_dynamic_min, dig_maxofmin;
+ u8 dig_min_0, dig_maxofmin;
bool bfirstconnect, bfirstdisconnect;
u8 dm_dig_max, dm_dig_min;
u8 current_igi = dm_digtable->cur_igvalue;
@@ -434,7 +407,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
if (mac->act_scanning)
return;
- dig_dynamic_min = dm_digtable->dig_dynamic_min;
+ dig_min_0 = dm_digtable->dig_min_0;
bfirstconnect = (mac->link_state >= MAC80211_LINKED) &&
!dm_digtable->media_connect_0;
bfirstdisconnect = (mac->link_state < MAC80211_LINKED) &&
@@ -456,20 +429,20 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
if (rtlpriv->dm.one_entry_only) {
offset = 12;
if (dm_digtable->rssi_val_min - offset < dm_dig_min)
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
else if (dm_digtable->rssi_val_min - offset >
dig_maxofmin)
- dig_dynamic_min = dig_maxofmin;
+ dig_min_0 = dig_maxofmin;
else
- dig_dynamic_min =
+ dig_min_0 =
dm_digtable->rssi_val_min - offset;
} else {
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
}
} else {
dm_digtable->rx_gain_max = dm_dig_max;
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD, "no link\n");
}
@@ -497,11 +470,11 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
} else {
if (dm_digtable->large_fa_hit < 3) {
if ((dm_digtable->forbidden_igi - 1) <
- dig_dynamic_min) {
+ dig_min_0) {
dm_digtable->forbidden_igi =
- dig_dynamic_min;
+ dig_min_0;
dm_digtable->rx_gain_min =
- dig_dynamic_min;
+ dig_min_0;
} else {
dm_digtable->forbidden_igi--;
dm_digtable->rx_gain_min =
@@ -552,7 +525,7 @@ static void rtl8723be_dm_dig(struct ieee80211_hw *hw)
rtl8723be_dm_write_dig(hw, current_igi);
dm_digtable->media_connect_0 =
((mac->link_state >= MAC80211_LINKED) ? true : false);
- dm_digtable->dig_dynamic_min = dig_dynamic_min;
+ dm_digtable->dig_min_0 = dig_min_0;
}
static void rtl8723be_dm_false_alarm_counter_statistics(
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
index e4c0e8ae6f47..f752a2cad63d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/dm.h
@@ -180,28 +180,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
-#define DM_DIG_MAX_AP 0x32
-#define DM_DIG_MIN_AP 0x20
-
#define DM_DIG_FA_UPPER 0x3e
#define DM_DIG_FA_LOWER 0x1e
#define DM_DIG_FA_TH0 0x200
#define DM_DIG_FA_TH1 0x300
#define DM_DIG_FA_TH2 0x400
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_LOW 30
#define RXPATHSELECTION_DIFF_TH 18
@@ -252,23 +236,6 @@ enum dm_sw_ant_switch_e {
ANS_ANTENNA_MAX = 3,
};
-enum dm_dig_ext_port_alg_e {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect_e {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_MULTISTA_DISCONNECT = 3,
- DIG_MULTISTA_CONNECT = 4,
- DIG_CONNECT_MAX
-};
-
enum pwr_track_control_method {
BBSWING,
TXAGC
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
index 20dcc25c506c..b7b73cbe346d 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.c
@@ -874,31 +874,6 @@ void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
ROFDM0_RXDETECTOR3, rtlphy->framesync);
}
-void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct rtl_phy *rtlphy = &rtlpriv->phy;
- u8 txpwr_level;
- long txpwr_dbm;
-
- txpwr_level = rtlphy->cur_cck_txpwridx;
- txpwr_dbm = rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B,
- txpwr_level);
- txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
- if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) >
- txpwr_dbm)
- txpwr_dbm =
- rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
- txpwr_level);
- txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
- if (rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
- txpwr_level) > txpwr_dbm)
- txpwr_dbm =
- rtl8723_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
- txpwr_level);
- *powerlevel = txpwr_dbm;
-}
-
static u8 _rtl8723be_phy_get_ratesection_intxpower_byrate(enum radio_path path,
u8 rate)
{
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
index 6339738a0e33..9021d4745ab7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/phy.h
@@ -114,8 +114,6 @@ bool rtl8723be_phy_mac_config(struct ieee80211_hw *hw);
bool rtl8723be_phy_bb_config(struct ieee80211_hw *hw);
bool rtl8723be_phy_rf_config(struct ieee80211_hw *hw);
void rtl8723be_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
-void rtl8723be_phy_get_txpower_level(struct ieee80211_hw *hw,
- long *powerlevel);
void rtl8723be_phy_set_txpower_level(struct ieee80211_hw *hw,
u8 channel);
void rtl8723be_phy_scan_operation_backup(struct ieee80211_hw *hw,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
index 223eb42992bd..1017f02d7bf7 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/sw.c
@@ -387,12 +387,14 @@ module_param_named(swlps, rtl8723be_mod_params.swctrl_lps, bool, 0444);
module_param_named(fwlps, rtl8723be_mod_params.fwctrl_lps, bool, 0444);
module_param_named(disable_watchdog, rtl8723be_mod_params.disable_watchdog,
bool, 0444);
-MODULE_PARM_DESC(swenc, "using hardware crypto (default 0 [hardware])\n");
-MODULE_PARM_DESC(ips, "using no link power save (default 1 is open)\n");
-MODULE_PARM_DESC(fwlps, "using linked fw control power save (default 1 is open)\n");
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 0)\n");
MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
-MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n");
+MODULE_PARM_DESC(disable_watchdog,
+ "Set to 1 to disable the watchdog (default 0)\n");
static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
index d6a1c70cb657..338ec9a9d09b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8723be/trx.c
@@ -47,164 +47,6 @@ static u8 _rtl8723be_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-/* mac80211's rate_idx is like this:
- *
- * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
- *
- * B/G rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE1M-->DESC92C_RATE54M ==> idx is 0-->11,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- *
- * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
- * A rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC92C_RATE6M-->DESC92C_RATE54M ==> idx is 0-->7,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC92C_RATEMCS0-->DESC92C_RATEMCS15 ==> idx is 0-->15
- */
-static int _rtl8723be_rate_mapping(struct ieee80211_hw *hw,
- bool isht, u8 desc_rate)
-{
- int rate_idx;
-
- if (!isht) {
- if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
- switch (desc_rate) {
- case DESC92C_RATE1M:
- rate_idx = 0;
- break;
- case DESC92C_RATE2M:
- rate_idx = 1;
- break;
- case DESC92C_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC92C_RATE11M:
- rate_idx = 3;
- break;
- case DESC92C_RATE6M:
- rate_idx = 4;
- break;
- case DESC92C_RATE9M:
- rate_idx = 5;
- break;
- case DESC92C_RATE12M:
- rate_idx = 6;
- break;
- case DESC92C_RATE18M:
- rate_idx = 7;
- break;
- case DESC92C_RATE24M:
- rate_idx = 8;
- break;
- case DESC92C_RATE36M:
- rate_idx = 9;
- break;
- case DESC92C_RATE48M:
- rate_idx = 10;
- break;
- case DESC92C_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATE6M:
- rate_idx = 0;
- break;
- case DESC92C_RATE9M:
- rate_idx = 1;
- break;
- case DESC92C_RATE12M:
- rate_idx = 2;
- break;
- case DESC92C_RATE18M:
- rate_idx = 3;
- break;
- case DESC92C_RATE24M:
- rate_idx = 4;
- break;
- case DESC92C_RATE36M:
- rate_idx = 5;
- break;
- case DESC92C_RATE48M:
- rate_idx = 6;
- break;
- case DESC92C_RATE54M:
- rate_idx = 7;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- } else {
- switch (desc_rate) {
- case DESC92C_RATEMCS0:
- rate_idx = 0;
- break;
- case DESC92C_RATEMCS1:
- rate_idx = 1;
- break;
- case DESC92C_RATEMCS2:
- rate_idx = 2;
- break;
- case DESC92C_RATEMCS3:
- rate_idx = 3;
- break;
- case DESC92C_RATEMCS4:
- rate_idx = 4;
- break;
- case DESC92C_RATEMCS5:
- rate_idx = 5;
- break;
- case DESC92C_RATEMCS6:
- rate_idx = 6;
- break;
- case DESC92C_RATEMCS7:
- rate_idx = 7;
- break;
- case DESC92C_RATEMCS8:
- rate_idx = 8;
- break;
- case DESC92C_RATEMCS9:
- rate_idx = 9;
- break;
- case DESC92C_RATEMCS10:
- rate_idx = 10;
- break;
- case DESC92C_RATEMCS11:
- rate_idx = 11;
- break;
- case DESC92C_RATEMCS12:
- rate_idx = 12;
- break;
- case DESC92C_RATEMCS13:
- rate_idx = 13;
- break;
- case DESC92C_RATEMCS14:
- rate_idx = 14;
- break;
- case DESC92C_RATEMCS15:
- rate_idx = 15;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- return rate_idx;
-}
-
static void _rtl8723be_query_rxphystatus(struct ieee80211_hw *hw,
struct rtl_stats *pstatus, u8 *pdesc,
struct rx_fwinfo_8723be *p_drvinfo,
@@ -558,8 +400,8 @@ bool rtl8723be_rx_query_desc(struct ieee80211_hw *hw,
* supported rates or MCS index if HT rates
* are use (RX_FLAG_HT)
*/
- rx_status->rate_idx = _rtl8723be_rate_mapping(hw, status->is_ht,
- status->rate);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ false, status->rate);
rx_status->mactime = status->timestamp_low;
if (phystatus) {
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h
index a730985ae81d..ee7c208bd070 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/def.h
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/def.h
@@ -373,60 +373,6 @@ enum rtl_desc_qsel {
QSLT_CMD = 0x13,
};
-enum rtl_desc8821ae_rate {
- DESC_RATE1M = 0x00,
- DESC_RATE2M = 0x01,
- DESC_RATE5_5M = 0x02,
- DESC_RATE11M = 0x03,
-
- DESC_RATE6M = 0x04,
- DESC_RATE9M = 0x05,
- DESC_RATE12M = 0x06,
- DESC_RATE18M = 0x07,
- DESC_RATE24M = 0x08,
- DESC_RATE36M = 0x09,
- DESC_RATE48M = 0x0a,
- DESC_RATE54M = 0x0b,
-
- DESC_RATEMCS0 = 0x0c,
- DESC_RATEMCS1 = 0x0d,
- DESC_RATEMCS2 = 0x0e,
- DESC_RATEMCS3 = 0x0f,
- DESC_RATEMCS4 = 0x10,
- DESC_RATEMCS5 = 0x11,
- DESC_RATEMCS6 = 0x12,
- DESC_RATEMCS7 = 0x13,
- DESC_RATEMCS8 = 0x14,
- DESC_RATEMCS9 = 0x15,
- DESC_RATEMCS10 = 0x16,
- DESC_RATEMCS11 = 0x17,
- DESC_RATEMCS12 = 0x18,
- DESC_RATEMCS13 = 0x19,
- DESC_RATEMCS14 = 0x1a,
- DESC_RATEMCS15 = 0x1b,
-
- DESC_RATEVHT1SS_MCS0 = 0x2c,
- DESC_RATEVHT1SS_MCS1 = 0x2d,
- DESC_RATEVHT1SS_MCS2 = 0x2e,
- DESC_RATEVHT1SS_MCS3 = 0x2f,
- DESC_RATEVHT1SS_MCS4 = 0x30,
- DESC_RATEVHT1SS_MCS5 = 0x31,
- DESC_RATEVHT1SS_MCS6 = 0x32,
- DESC_RATEVHT1SS_MCS7 = 0x33,
- DESC_RATEVHT1SS_MCS8 = 0x34,
- DESC_RATEVHT1SS_MCS9 = 0x35,
- DESC_RATEVHT2SS_MCS0 = 0x36,
- DESC_RATEVHT2SS_MCS1 = 0x37,
- DESC_RATEVHT2SS_MCS2 = 0x38,
- DESC_RATEVHT2SS_MCS3 = 0x39,
- DESC_RATEVHT2SS_MCS4 = 0x3a,
- DESC_RATEVHT2SS_MCS5 = 0x3b,
- DESC_RATEVHT2SS_MCS6 = 0x3c,
- DESC_RATEVHT2SS_MCS7 = 0x3d,
- DESC_RATEVHT2SS_MCS8 = 0x3e,
- DESC_RATEVHT2SS_MCS9 = 0x3f,
-};
-
enum rx_packet_type {
NORMAL_RX,
TX_REPORT1,
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
index ba30b0d250fd..0b2082dc48f1 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.c
@@ -26,6 +26,7 @@
#include "../wifi.h"
#include "../base.h"
#include "../pci.h"
+#include "../core.h"
#include "reg.h"
#include "def.h"
#include "phy.h"
@@ -519,34 +520,6 @@ void rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(
}
}
-static void rtl8821ae_dm_diginit(struct ieee80211_hw *hw)
-{
- struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
-
- dm_digtable->cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
- dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
- dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
- dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
- dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
- dm_digtable->rx_gain_max = DM_DIG_MAX;
- dm_digtable->rx_gain_min = DM_DIG_MIN;
- dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
- dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
- dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
- dm_digtable->pre_cck_cca_thres = 0xff;
- dm_digtable->cur_cck_cca_thres = 0x83;
- dm_digtable->forbidden_igi = DM_DIG_MIN;
- dm_digtable->large_fa_hit = 0;
- dm_digtable->recover_cnt = 0;
- dm_digtable->dig_dynamic_min = DM_DIG_MIN;
- dm_digtable->dig_dynamic_min_1 = DM_DIG_MIN;
- dm_digtable->media_connect_0 = false;
- dm_digtable->media_connect_1 = false;
- rtlpriv->dm.dm_initialgain_enable = true;
- dm_digtable->bt30_cur_igi = 0x32;
-}
-
void rtl8821ae_dm_init_edca_turbo(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -606,6 +579,7 @@ void rtl8821ae_dm_init(struct ieee80211_hw *hw)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_phy *rtlphy = &rtlpriv->phy;
+ u32 cur_igvalue = rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f);
spin_lock(&rtlpriv->locks.iqk_lock);
rtlphy->lck_inprogress = false;
@@ -613,7 +587,7 @@ void rtl8821ae_dm_init(struct ieee80211_hw *hw)
rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
rtl8821ae_dm_common_info_self_init(hw);
- rtl8821ae_dm_diginit(hw);
+ rtl_dm_diginit(hw, cur_igvalue);
rtl8821ae_dm_init_rate_adaptive_mask(hw);
rtl8821ae_dm_init_edca_turbo(hw);
rtl8821ae_dm_initialize_txpower_tracking_thermalmeter(hw);
@@ -822,7 +796,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
- u8 dig_dynamic_min;
+ u8 dig_min_0;
u8 dig_max_of_min;
bool first_connect, first_disconnect;
u8 dm_dig_max, dm_dig_min, offset;
@@ -837,7 +811,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
}
/*add by Neil Chen to avoid PSD is processing*/
- dig_dynamic_min = dm_digtable->dig_dynamic_min;
+ dig_min_0 = dm_digtable->dig_min_0;
first_connect = (mac->link_state >= MAC80211_LINKED) &&
(!dm_digtable->media_connect_0);
first_disconnect = (mac->link_state < MAC80211_LINKED) &&
@@ -876,23 +850,23 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
offset = 0;
if (dm_digtable->rssi_val_min - offset < dm_dig_min)
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
else if (dm_digtable->rssi_val_min -
offset > dig_max_of_min)
- dig_dynamic_min = dig_max_of_min;
+ dig_min_0 = dig_max_of_min;
else
- dig_dynamic_min =
+ dig_min_0 =
dm_digtable->rssi_val_min - offset;
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
- "bOneEntryOnly=TRUE, dig_dynamic_min=0x%x\n",
- dig_dynamic_min);
+ "bOneEntryOnly=TRUE, dig_min_0=0x%x\n",
+ dig_min_0);
} else {
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
}
} else {
dm_digtable->rx_gain_max = dm_dig_max;
- dig_dynamic_min = dm_dig_min;
+ dig_min_0 = dm_dig_min;
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
"No Link\n");
}
@@ -925,11 +899,11 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
} else {
if (dm_digtable->large_fa_hit < 3) {
if ((dm_digtable->forbidden_igi - 1) <
- dig_dynamic_min) {
+ dig_min_0) {
dm_digtable->forbidden_igi =
- dig_dynamic_min;
+ dig_min_0;
dm_digtable->rx_gain_min =
- dig_dynamic_min;
+ dig_min_0;
RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
"Normal Case: At Lower Bound\n");
} else {
@@ -1024,7 +998,7 @@ static void rtl8821ae_dm_dig(struct ieee80211_hw *hw)
rtl8821ae_dm_write_dig(hw, current_igi);
dm_digtable->media_connect_0 =
((mac->link_state >= MAC80211_LINKED) ? true : false);
- dm_digtable->dig_dynamic_min = dig_dynamic_min;
+ dm_digtable->dig_min_0 = dig_min_0;
}
static void rtl8821ae_dm_common_info_self_update(struct ieee80211_hw *hw)
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h
index 9dd40dd316c1..625a6bbb21fc 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/dm.h
@@ -187,28 +187,12 @@
#define BW_AUTO_SWITCH_HIGH_LOW 25
#define BW_AUTO_SWITCH_LOW_HIGH 30
-#define DM_DIG_THRESH_HIGH 40
-#define DM_DIG_THRESH_LOW 35
-
-#define DM_FALSEALARM_THRESH_LOW 400
-#define DM_FALSEALARM_THRESH_HIGH 1000
-
-#define DM_DIG_MAX 0x3e
-#define DM_DIG_MIN 0x1e
-
-#define DM_DIG_MAX_AP 0x32
-#define DM_DIG_MIN_AP 0x20
-
#define DM_DIG_FA_UPPER 0x3e
#define DM_DIG_FA_LOWER 0x1e
#define DM_DIG_FA_TH0 200
#define DM_DIG_FA_TH1 0x300
#define DM_DIG_FA_TH2 0x400
-#define DM_DIG_BACKOFF_MAX 12
-#define DM_DIG_BACKOFF_MIN -4
-#define DM_DIG_BACKOFF_DEFAULT 10
-
#define RXPATHSELECTION_SS_TH_LOW 30
#define RXPATHSELECTION_DIFF_TH 18
@@ -262,14 +246,6 @@ enum tag_dynamic_init_gain_operation_type_definition {
DIG_OP_TYPE_MAX
};
-enum tag_cck_packet_detection_threshold_type_definition {
- CCK_PD_STAGE_LOWRSSI = 0,
- CCK_PD_STAGE_HIGHRSSI = 1,
- CCK_FA_STAGE_LOW = 2,
- CCK_FA_STAGE_HIGH = 3,
- CCK_PD_STAGE_MAX = 4,
-};
-
enum dm_1r_cca_e {
CCA_1R = 0,
CCA_2R = 1,
@@ -288,23 +264,6 @@ enum dm_sw_ant_switch_e {
ANS_ANTENNA_MAX = 3,
};
-enum dm_dig_ext_port_alg_e {
- DIG_EXT_PORT_STAGE_0 = 0,
- DIG_EXT_PORT_STAGE_1 = 1,
- DIG_EXT_PORT_STAGE_2 = 2,
- DIG_EXT_PORT_STAGE_3 = 3,
- DIG_EXT_PORT_STAGE_MAX = 4,
-};
-
-enum dm_dig_connect_e {
- DIG_STA_DISCONNECT = 0,
- DIG_STA_CONNECT = 1,
- DIG_STA_BEFORE_CONNECT = 2,
- DIG_MULTISTA_DISCONNECT = 3,
- DIG_MULTISTA_CONNECT = 4,
- DIG_CONNECT_MAX
-};
-
enum pwr_track_control_method {
BBSWING,
TXAGC,
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h
index bf0b0ce9519c..36b3e91d996e 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/pwrseq.h
@@ -93,9 +93,9 @@
#define RTL8812_TRANS_CARDEMU_TO_SUS \
{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,\
- PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xcc}, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xc0}, \
{0x0042, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,\
- PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xEC}, \
+ PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xF0, 0xE0}, \
{0x0043, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,\
PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x07 \
/* gpio11 input mode, gpio10~8 output mode */}, \
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c
index fc92dd6a0d07..a4988121e1ab 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c
@@ -85,52 +85,6 @@ static void rtl8821ae_init_aspm_vars(struct ieee80211_hw *hw)
rtlpci->const_support_pciaspm = 1;
}
-static void load_wowlan_fw(struct rtl_priv *rtlpriv)
-{
- /* callback routine to load wowlan firmware after main fw has
- * been loaded
- */
- const struct firmware *wowlan_firmware;
- char *fw_name = NULL;
- int err;
-
- /* for wowlan firmware buf */
- rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000);
- if (!rtlpriv->rtlhal.wowlan_firmware) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Can't alloc buffer for wowlan fw.\n");
- return;
- }
-
- if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8821AE)
- fw_name = "rtlwifi/rtl8821aefw_wowlan.bin";
- else
- fw_name = "rtlwifi/rtl8812aefw_wowlan.bin";
- err = request_firmware(&wowlan_firmware, fw_name, rtlpriv->io.dev);
- if (err) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Failed to request wowlan firmware!\n");
- goto error;
- }
-
- if (wowlan_firmware->size > 0x8000) {
- RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Wowlan Firmware is too big!\n");
- goto error;
- }
-
- memcpy(rtlpriv->rtlhal.wowlan_firmware, wowlan_firmware->data,
- wowlan_firmware->size);
- rtlpriv->rtlhal.wowlan_fwsize = wowlan_firmware->size;
- release_firmware(wowlan_firmware);
-
- RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "WOWLAN FirmwareDownload OK\n");
- return;
-error:
- release_firmware(wowlan_firmware);
- vfree(rtlpriv->rtlhal.wowlan_firmware);
-}
-
/*InitializeVariables8812E*/
int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
{
@@ -231,7 +185,6 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
else if (rtlpriv->psc.reg_fwctrl_lps == 3)
rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
- rtlpriv->rtl_fw_second_cb = load_wowlan_fw;
/* for firmware buf */
rtlpriv->rtlhal.pfirmware = vzalloc(0x8000);
if (!rtlpriv->rtlhal.pfirmware) {
@@ -239,20 +192,41 @@ int rtl8821ae_init_sw_vars(struct ieee80211_hw *hw)
"Can't alloc buffer for fw.\n");
return 1;
}
+ rtlpriv->rtlhal.wowlan_firmware = vzalloc(0x8000);
+ if (!rtlpriv->rtlhal.wowlan_firmware) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Can't alloc buffer for wowlan fw.\n");
+ return 1;
+ }
- if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE)
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8812AE) {
rtlpriv->cfg->fw_name = "rtlwifi/rtl8812aefw.bin";
- else
+ rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8812aefw_wowlan.bin";
+ } else {
rtlpriv->cfg->fw_name = "rtlwifi/rtl8821aefw.bin";
+ rtlpriv->cfg->wowlan_fw_name = "rtlwifi/rtl8821aefw_wowlan.bin";
+ }
rtlpriv->max_fw_size = 0x8000;
+ /*load normal firmware*/
pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
rtlpriv->io.dev, GFP_KERNEL, hw,
rtl_fw_cb);
if (err) {
RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
- "Failed to request firmware!\n");
+ "Failed to request normal firmware!\n");
+ return 1;
+ }
+ /*load wowlan firmware*/
+ pr_info("Using firmware %s\n", rtlpriv->cfg->wowlan_fw_name);
+ err = request_firmware_nowait(THIS_MODULE, 1,
+ rtlpriv->cfg->wowlan_fw_name,
+ rtlpriv->io.dev, GFP_KERNEL, hw,
+ rtl_wowlan_fw_cb);
+ if (err) {
+ RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+ "Failed to request wowlan firmware!\n");
return 1;
}
return 0;
diff --git a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c
index 383b86b05cba..72af4b9ee32b 100644
--- a/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c
+++ b/drivers/net/wireless/rtlwifi/rtl8821ae/trx.c
@@ -48,232 +48,6 @@ static u8 _rtl8821ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
return skb->priority;
}
-/* mac80211's rate_idx is like this:
- *
- * 2.4G band:rx_status->band == IEEE80211_BAND_2GHZ
- *
- * B/G rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC_RATE1M-->DESC_RATE54M ==> idx is 0-->11,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
- *
- * 5G band:rx_status->band == IEEE80211_BAND_5GHZ
- * A rate:
- * (rx_status->flag & RX_FLAG_HT) = 0,
- * DESC_RATE6M-->DESC_RATE54M ==> idx is 0-->7,
- *
- * N rate:
- * (rx_status->flag & RX_FLAG_HT) = 1,
- * DESC_RATEMCS0-->DESC_RATEMCS15 ==> idx is 0-->15
- */
-static int _rtl8821ae_rate_mapping(struct ieee80211_hw *hw,
- bool isht, bool isvht, u8 desc_rate)
-{
- int rate_idx;
-
- if (!isht) {
- if (IEEE80211_BAND_2GHZ == hw->conf.chandef.chan->band) {
- switch (desc_rate) {
- case DESC_RATE1M:
- rate_idx = 0;
- break;
- case DESC_RATE2M:
- rate_idx = 1;
- break;
- case DESC_RATE5_5M:
- rate_idx = 2;
- break;
- case DESC_RATE11M:
- rate_idx = 3;
- break;
- case DESC_RATE6M:
- rate_idx = 4;
- break;
- case DESC_RATE9M:
- rate_idx = 5;
- break;
- case DESC_RATE12M:
- rate_idx = 6;
- break;
- case DESC_RATE18M:
- rate_idx = 7;
- break;
- case DESC_RATE24M:
- rate_idx = 8;
- break;
- case DESC_RATE36M:
- rate_idx = 9;
- break;
- case DESC_RATE48M:
- rate_idx = 10;
- break;
- case DESC_RATE54M:
- rate_idx = 11;
- break;
- default:
- rate_idx = 0;
- break;
- }
- } else {
- switch (desc_rate) {
- case DESC_RATE6M:
- rate_idx = 0;
- break;
- case DESC_RATE9M:
- rate_idx = 1;
- break;
- case DESC_RATE12M:
- rate_idx = 2;
- break;
- case DESC_RATE18M:
- rate_idx = 3;
- break;
- case DESC_RATE24M:
- rate_idx = 4;
- break;
- case DESC_RATE36M:
- rate_idx = 5;
- break;
- case DESC_RATE48M:
- rate_idx = 6;
- break;
- case DESC_RATE54M:
- rate_idx = 7;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- } else {
- switch (desc_rate) {
- case DESC_RATEMCS0:
- rate_idx = 0;
- break;
- case DESC_RATEMCS1:
- rate_idx = 1;
- break;
- case DESC_RATEMCS2:
- rate_idx = 2;
- break;
- case DESC_RATEMCS3:
- rate_idx = 3;
- break;
- case DESC_RATEMCS4:
- rate_idx = 4;
- break;
- case DESC_RATEMCS5:
- rate_idx = 5;
- break;
- case DESC_RATEMCS6:
- rate_idx = 6;
- break;
- case DESC_RATEMCS7:
- rate_idx = 7;
- break;
- case DESC_RATEMCS8:
- rate_idx = 8;
- break;
- case DESC_RATEMCS9:
- rate_idx = 9;
- break;
- case DESC_RATEMCS10:
- rate_idx = 10;
- break;
- case DESC_RATEMCS11:
- rate_idx = 11;
- break;
- case DESC_RATEMCS12:
- rate_idx = 12;
- break;
- case DESC_RATEMCS13:
- rate_idx = 13;
- break;
- case DESC_RATEMCS14:
- rate_idx = 14;
- break;
- case DESC_RATEMCS15:
- rate_idx = 15;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
-
- if (isvht) {
- switch (desc_rate) {
- case DESC_RATEVHT1SS_MCS0:
- rate_idx = 0;
- break;
- case DESC_RATEVHT1SS_MCS1:
- rate_idx = 1;
- break;
- case DESC_RATEVHT1SS_MCS2:
- rate_idx = 2;
- break;
- case DESC_RATEVHT1SS_MCS3:
- rate_idx = 3;
- break;
- case DESC_RATEVHT1SS_MCS4:
- rate_idx = 4;
- break;
- case DESC_RATEVHT1SS_MCS5:
- rate_idx = 5;
- break;
- case DESC_RATEVHT1SS_MCS6:
- rate_idx = 6;
- break;
- case DESC_RATEVHT1SS_MCS7:
- rate_idx = 7;
- break;
- case DESC_RATEVHT1SS_MCS8:
- rate_idx = 8;
- break;
- case DESC_RATEVHT1SS_MCS9:
- rate_idx = 9;
- break;
- case DESC_RATEVHT2SS_MCS0:
- rate_idx = 0;
- break;
- case DESC_RATEVHT2SS_MCS1:
- rate_idx = 1;
- break;
- case DESC_RATEVHT2SS_MCS2:
- rate_idx = 2;
- break;
- case DESC_RATEVHT2SS_MCS3:
- rate_idx = 3;
- break;
- case DESC_RATEVHT2SS_MCS4:
- rate_idx = 4;
- break;
- case DESC_RATEVHT2SS_MCS5:
- rate_idx = 5;
- break;
- case DESC_RATEVHT2SS_MCS6:
- rate_idx = 6;
- break;
- case DESC_RATEVHT2SS_MCS7:
- rate_idx = 7;
- break;
- case DESC_RATEVHT2SS_MCS8:
- rate_idx = 8;
- break;
- case DESC_RATEVHT2SS_MCS9:
- rate_idx = 9;
- break;
- default:
- rate_idx = 0;
- break;
- }
- }
- return rate_idx;
-}
-
static u16 odm_cfo(char value)
{
int ret_val;
@@ -766,9 +540,9 @@ bool rtl8821ae_rx_query_desc(struct ieee80211_hw *hw,
* supported rates or MCS index if HT rates
* are use (RX_FLAG_HT)
*/
- rx_status->rate_idx =
- _rtl8821ae_rate_mapping(hw, status->is_ht,
- status->is_vht, status->rate);
+ rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+ status->is_vht,
+ status->rate);
rx_status->mactime = status->timestamp_low;
if (phystatus) {
diff --git a/drivers/net/wireless/rtlwifi/wifi.h b/drivers/net/wireless/rtlwifi/wifi.h
index 6866dcf24340..51572912c53d 100644
--- a/drivers/net/wireless/rtlwifi/wifi.h
+++ b/drivers/net/wireless/rtlwifi/wifi.h
@@ -331,10 +331,10 @@ enum hardware_type {
(IS_HARDWARE_TYPE_8723E(rtlhal) || IS_HARDWARE_TYPE_8723U(rtlhal))
#define RX_HAL_IS_CCK_RATE(rxmcs) \
- ((rxmcs) == DESC92_RATE1M || \
- (rxmcs) == DESC92_RATE2M || \
- (rxmcs) == DESC92_RATE5_5M || \
- (rxmcs) == DESC92_RATE11M)
+ ((rxmcs) == DESC_RATE1M || \
+ (rxmcs) == DESC_RATE2M || \
+ (rxmcs) == DESC_RATE5_5M || \
+ (rxmcs) == DESC_RATE11M)
enum scan_operation_backup_opt {
SCAN_OPT_BACKUP = 0,
@@ -579,38 +579,59 @@ enum rtl_hal_state {
};
enum rtl_desc92_rate {
- DESC92_RATE1M = 0x00,
- DESC92_RATE2M = 0x01,
- DESC92_RATE5_5M = 0x02,
- DESC92_RATE11M = 0x03,
-
- DESC92_RATE6M = 0x04,
- DESC92_RATE9M = 0x05,
- DESC92_RATE12M = 0x06,
- DESC92_RATE18M = 0x07,
- DESC92_RATE24M = 0x08,
- DESC92_RATE36M = 0x09,
- DESC92_RATE48M = 0x0a,
- DESC92_RATE54M = 0x0b,
-
- DESC92_RATEMCS0 = 0x0c,
- DESC92_RATEMCS1 = 0x0d,
- DESC92_RATEMCS2 = 0x0e,
- DESC92_RATEMCS3 = 0x0f,
- DESC92_RATEMCS4 = 0x10,
- DESC92_RATEMCS5 = 0x11,
- DESC92_RATEMCS6 = 0x12,
- DESC92_RATEMCS7 = 0x13,
- DESC92_RATEMCS8 = 0x14,
- DESC92_RATEMCS9 = 0x15,
- DESC92_RATEMCS10 = 0x16,
- DESC92_RATEMCS11 = 0x17,
- DESC92_RATEMCS12 = 0x18,
- DESC92_RATEMCS13 = 0x19,
- DESC92_RATEMCS14 = 0x1a,
- DESC92_RATEMCS15 = 0x1b,
- DESC92_RATEMCS15_SG = 0x1c,
- DESC92_RATEMCS32 = 0x20,
+ DESC_RATE1M = 0x00,
+ DESC_RATE2M = 0x01,
+ DESC_RATE5_5M = 0x02,
+ DESC_RATE11M = 0x03,
+
+ DESC_RATE6M = 0x04,
+ DESC_RATE9M = 0x05,
+ DESC_RATE12M = 0x06,
+ DESC_RATE18M = 0x07,
+ DESC_RATE24M = 0x08,
+ DESC_RATE36M = 0x09,
+ DESC_RATE48M = 0x0a,
+ DESC_RATE54M = 0x0b,
+
+ DESC_RATEMCS0 = 0x0c,
+ DESC_RATEMCS1 = 0x0d,
+ DESC_RATEMCS2 = 0x0e,
+ DESC_RATEMCS3 = 0x0f,
+ DESC_RATEMCS4 = 0x10,
+ DESC_RATEMCS5 = 0x11,
+ DESC_RATEMCS6 = 0x12,
+ DESC_RATEMCS7 = 0x13,
+ DESC_RATEMCS8 = 0x14,
+ DESC_RATEMCS9 = 0x15,
+ DESC_RATEMCS10 = 0x16,
+ DESC_RATEMCS11 = 0x17,
+ DESC_RATEMCS12 = 0x18,
+ DESC_RATEMCS13 = 0x19,
+ DESC_RATEMCS14 = 0x1a,
+ DESC_RATEMCS15 = 0x1b,
+ DESC_RATEMCS15_SG = 0x1c,
+ DESC_RATEMCS32 = 0x20,
+
+ DESC_RATEVHT1SS_MCS0 = 0x2c,
+ DESC_RATEVHT1SS_MCS1 = 0x2d,
+ DESC_RATEVHT1SS_MCS2 = 0x2e,
+ DESC_RATEVHT1SS_MCS3 = 0x2f,
+ DESC_RATEVHT1SS_MCS4 = 0x30,
+ DESC_RATEVHT1SS_MCS5 = 0x31,
+ DESC_RATEVHT1SS_MCS6 = 0x32,
+ DESC_RATEVHT1SS_MCS7 = 0x33,
+ DESC_RATEVHT1SS_MCS8 = 0x34,
+ DESC_RATEVHT1SS_MCS9 = 0x35,
+ DESC_RATEVHT2SS_MCS0 = 0x36,
+ DESC_RATEVHT2SS_MCS1 = 0x37,
+ DESC_RATEVHT2SS_MCS2 = 0x38,
+ DESC_RATEVHT2SS_MCS3 = 0x39,
+ DESC_RATEVHT2SS_MCS4 = 0x3a,
+ DESC_RATEVHT2SS_MCS5 = 0x3b,
+ DESC_RATEVHT2SS_MCS6 = 0x3c,
+ DESC_RATEVHT2SS_MCS7 = 0x3d,
+ DESC_RATEVHT2SS_MCS8 = 0x3e,
+ DESC_RATEVHT2SS_MCS9 = 0x3f,
};
enum rtl_var_map {
@@ -2161,6 +2182,7 @@ struct rtl_hal_ops {
void (*add_wowlan_pattern)(struct ieee80211_hw *hw,
struct rtl_wow_pattern *rtl_pattern,
u8 index);
+ u16 (*get_available_desc)(struct ieee80211_hw *hw, u8 q_idx);
};
struct rtl_intf_ops {
@@ -2242,6 +2264,7 @@ struct rtl_hal_cfg {
char *name;
char *fw_name;
char *alt_fw_name;
+ char *wowlan_fw_name;
struct rtl_hal_ops *ops;
struct rtl_mod_params *mod_params;
struct rtl_hal_usbint_cfg *usb_interface_cfg;
@@ -2390,8 +2413,6 @@ struct dig_t {
u8 pre_ccastate;
u8 cur_ccasate;
u8 large_fa_hit;
- u8 dig_dynamic_min;
- u8 dig_dynamic_min_1;
u8 forbidden_igi;
u8 dig_state;
u8 dig_highpwrstate;
@@ -2518,8 +2539,6 @@ struct proxim {
struct rtl_priv {
struct ieee80211_hw *hw;
- /* Used to load a second firmware */
- void (*rtl_fw_second_cb)(struct rtl_priv *rtlpriv);
struct completion firmware_loading_complete;
struct list_head list;
struct rtl_priv *buddy_priv;
diff --git a/drivers/net/wireless/ti/wl1251/main.c b/drivers/net/wireless/ti/wl1251/main.c
index 0b30a7b4d663..d4ba009ac9aa 100644
--- a/drivers/net/wireless/ti/wl1251/main.c
+++ b/drivers/net/wireless/ti/wl1251/main.c
@@ -500,6 +500,7 @@ static int wl1251_op_add_interface(struct ieee80211_hw *hw,
int ret = 0;
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_UAPSD |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
wl1251_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -1480,9 +1481,7 @@ int wl1251_init_ieee80211(struct wl1251 *wl)
/* unit us */
/* FIXME: find a proper value */
- wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
- IEEE80211_HW_SUPPORTS_PS |
- IEEE80211_HW_SUPPORTS_UAPSD;
+ wl->hw->flags = IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_SUPPORTS_PS;
wl->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
diff --git a/drivers/net/wireless/ti/wl12xx/main.c b/drivers/net/wireless/ti/wl12xx/main.c
index d6d0d6d9c7a8..144d1f8ba473 100644
--- a/drivers/net/wireless/ti/wl12xx/main.c
+++ b/drivers/net/wireless/ti/wl12xx/main.c
@@ -250,6 +250,7 @@ static struct wlcore_conf wl12xx_conf = {
.keep_alive_interval = 55000,
.max_listen_interval = 20,
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
+ .suspend_rx_ba_activity = 0,
},
.itrim = {
.enable = false,
@@ -1728,6 +1729,9 @@ static struct wlcore_ops wl12xx_ops = {
.convert_hwaddr = wl12xx_convert_hwaddr,
.lnk_high_prio = wl12xx_lnk_high_prio,
.lnk_low_prio = wl12xx_lnk_low_prio,
+ .interrupt_notify = NULL,
+ .rx_ba_filter = NULL,
+ .ap_sleep = NULL,
};
static struct ieee80211_sta_ht_cap wl12xx_ht_cap = {
diff --git a/drivers/net/wireless/ti/wl18xx/acx.c b/drivers/net/wireless/ti/wl18xx/acx.c
index a169bb5a5dbf..67f2a0eec854 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.c
+++ b/drivers/net/wireless/ti/wl18xx/acx.c
@@ -24,6 +24,7 @@
#include "../wlcore/acx.h"
#include "acx.h"
+#include "wl18xx.h"
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
@@ -194,3 +195,90 @@ out:
kfree(acx);
return ret;
}
+
+/*
+ * When the host is suspended, we don't want to get any fast-link/PSM
+ * notifications
+ */
+int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl,
+ bool action)
+{
+ struct wl18xx_acx_interrupt_notify *acx;
+ int ret = 0;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = action;
+ ret = wl1271_cmd_configure(wl, ACX_INTERRUPT_NOTIFY, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx interrupt notify setting failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+/*
+ * When the host is suspended, we can configure the FW to disable RX BA
+ * notifications.
+ */
+int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action)
+{
+ struct wl18xx_acx_rx_ba_filter *acx;
+ int ret = 0;
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->enable = (u32)action;
+ ret = wl1271_cmd_configure(wl, ACX_RX_BA_FILTER, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx rx ba activity filter setting failed: %d",
+ ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
+
+int wl18xx_acx_ap_sleep(struct wl1271 *wl)
+{
+ struct wl18xx_priv *priv = wl->priv;
+ struct acx_ap_sleep_cfg *acx;
+ struct conf_ap_sleep_settings *conf = &priv->conf.ap_sleep;
+ int ret;
+
+ wl1271_debug(DEBUG_ACX, "acx config ap sleep");
+
+ acx = kzalloc(sizeof(*acx), GFP_KERNEL);
+ if (!acx) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ acx->idle_duty_cycle = conf->idle_duty_cycle;
+ acx->connected_duty_cycle = conf->connected_duty_cycle;
+ acx->max_stations_thresh = conf->max_stations_thresh;
+ acx->idle_conn_thresh = conf->idle_conn_thresh;
+
+ ret = wl1271_cmd_configure(wl, ACX_AP_SLEEP_CFG, acx, sizeof(*acx));
+ if (ret < 0) {
+ wl1271_warning("acx config ap-sleep failed: %d", ret);
+ goto out;
+ }
+
+out:
+ kfree(acx);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/acx.h b/drivers/net/wireless/ti/wl18xx/acx.h
index 0e636def1217..4afccd4b9467 100644
--- a/drivers/net/wireless/ti/wl18xx/acx.h
+++ b/drivers/net/wireless/ti/wl18xx/acx.h
@@ -32,7 +32,10 @@ enum {
ACX_SIM_CONFIG = 0x0053,
ACX_CLEAR_STATISTICS = 0x0054,
ACX_AUTO_RX_STREAMING = 0x0055,
- ACX_PEER_CAP = 0x0056
+ ACX_PEER_CAP = 0x0056,
+ ACX_INTERRUPT_NOTIFY = 0x0057,
+ ACX_RX_BA_FILTER = 0x0058,
+ ACX_AP_SLEEP_CFG = 0x0059
};
/* numbers of bits the length field takes (add 1 for the actual number) */
@@ -326,6 +329,44 @@ struct wlcore_acx_peer_cap {
u8 padding;
} __packed;
+/*
+ * ACX_INTERRUPT_NOTIFY
+ * enable/disable fast-link/PSM notification from FW
+ */
+struct wl18xx_acx_interrupt_notify {
+ struct acx_header header;
+ u32 enable;
+};
+
+/*
+ * ACX_RX_BA_FILTER
+ * enable/disable RX BA filtering in FW
+ */
+struct wl18xx_acx_rx_ba_filter {
+ struct acx_header header;
+ u32 enable;
+};
+
+struct acx_ap_sleep_cfg {
+ struct acx_header header;
+ /* Duty Cycle (20-80% of staying Awake) for IDLE AP
+ * (0: disable)
+ */
+ u8 idle_duty_cycle;
+ /* Duty Cycle (20-80% of staying Awake) for Connected AP
+ * (0: disable)
+ */
+ u8 connected_duty_cycle;
+ /* Maximum stations that are allowed to be connected to AP
+ * (255: no limit)
+ */
+ u8 max_stations_thresh;
+ /* Timeout till enabling the Sleep Mechanism after data stops
+ * [unit: 100 msec]
+ */
+ u8 idle_conn_thresh;
+} __packed;
+
int wl18xx_acx_host_if_cfg_bitmap(struct wl1271 *wl, u32 host_cfg_bitmap,
u32 sdio_blk_size, u32 extra_mem_blks,
u32 len_field_size);
@@ -336,5 +377,8 @@ int wl18xx_acx_set_peer_cap(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
u32 rate_set, u8 hlid);
+int wl18xx_acx_interrupt_notify_config(struct wl1271 *wl, bool action);
+int wl18xx_acx_rx_ba_filter(struct wl1271 *wl, bool action);
+int wl18xx_acx_ap_sleep(struct wl1271 *wl);
#endif /* __WL18XX_ACX_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.c b/drivers/net/wireless/ti/wl18xx/cmd.c
index 44f0b205b065..a8d176ddc73c 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.c
+++ b/drivers/net/wireless/ti/wl18xx/cmd.c
@@ -33,7 +33,8 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
u32 supported_rates;
int ret;
- wl1271_debug(DEBUG_ACX, "cmd channel switch");
+ wl1271_debug(DEBUG_ACX, "cmd channel switch (count=%d)",
+ ch_switch->count);
cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
if (!cmd) {
@@ -60,8 +61,12 @@ int wl18xx_cmd_channel_switch(struct wl1271 *wl,
goto out_free;
}
- supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES |
- wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+ supported_rates = CONF_TX_ENABLED_RATES | CONF_TX_MCS_RATES;
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS)
+ supported_rates |= wlcore_hw_sta_get_ap_rate_mask(wl, wlvif);
+ else
+ supported_rates |=
+ wlcore_hw_ap_get_mimo_wide_rate_mask(wl, wlvif);
if (wlvif->p2p)
supported_rates &= ~CONF_TX_CCK_RATES;
cmd->local_supported_rates = cpu_to_le32(supported_rates);
@@ -167,3 +172,85 @@ out_free:
out:
return ret;
}
+
+int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start)
+{
+ struct wlcore_cmd_cac_start *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd cac (channel %d) %s",
+ wlvif->channel, start ? "start" : "stop");
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->role_id = wlvif->role_id;
+ cmd->channel = wlvif->channel;
+ if (wlvif->band == IEEE80211_BAND_5GHZ)
+ cmd->band = WLCORE_BAND_5GHZ;
+ cmd->bandwidth = wlcore_get_native_channel_type(wlvif->channel_type);
+
+ ret = wl1271_cmd_send(wl,
+ start ? CMD_CAC_START : CMD_CAC_STOP,
+ cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send cac command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+ return ret;
+}
+
+int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel)
+{
+ struct wl18xx_cmd_dfs_radar_debug *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd radar detection debug (chan %d)",
+ channel);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->channel = channel;
+
+ ret = wl1271_cmd_send(wl, CMD_DFS_RADAR_DETECTION_DEBUG,
+ cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send radar detection debug command");
+ goto out_free;
+ }
+
+out_free:
+ kfree(cmd);
+ return ret;
+}
+
+int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ struct wl18xx_cmd_dfs_master_restart *cmd;
+ int ret = 0;
+
+ wl1271_debug(DEBUG_CMD, "cmd dfs master restart (role %d)",
+ wlvif->role_id);
+
+ cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+ if (!cmd)
+ return -ENOMEM;
+
+ cmd->role_id = wlvif->role_id;
+
+ ret = wl1271_cmd_send(wl, CMD_DFS_MASTER_RESTART,
+ cmd, sizeof(*cmd), 0);
+ if (ret < 0) {
+ wl1271_error("failed to send dfs master restart command");
+ goto out_free;
+ }
+out_free:
+ kfree(cmd);
+ return ret;
+}
diff --git a/drivers/net/wireless/ti/wl18xx/cmd.h b/drivers/net/wireless/ti/wl18xx/cmd.h
index 92499e2dfa83..7f9440a2bff8 100644
--- a/drivers/net/wireless/ti/wl18xx/cmd.h
+++ b/drivers/net/wireless/ti/wl18xx/cmd.h
@@ -59,6 +59,30 @@ struct wl18xx_cmd_smart_config_set_group_key {
u8 key[16];
} __packed;
+struct wl18xx_cmd_dfs_radar_debug {
+ struct wl1271_cmd_header header;
+
+ u8 channel;
+ u8 padding[3];
+} __packed;
+
+struct wl18xx_cmd_dfs_master_restart {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 padding[3];
+} __packed;
+
+/* cac_start and cac_stop share the same params */
+struct wlcore_cmd_cac_start {
+ struct wl1271_cmd_header header;
+
+ u8 role_id;
+ u8 channel;
+ u8 band;
+ u8 bandwidth;
+} __packed;
+
int wl18xx_cmd_channel_switch(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
@@ -66,4 +90,7 @@ int wl18xx_cmd_smart_config_start(struct wl1271 *wl, u32 group_bitmap);
int wl18xx_cmd_smart_config_stop(struct wl1271 *wl);
int wl18xx_cmd_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
u8 key_len, u8 *key);
+int wl18xx_cmd_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start);
+int wl18xx_cmd_radar_detection_debug(struct wl1271 *wl, u8 channel);
+int wl18xx_cmd_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif);
#endif
diff --git a/drivers/net/wireless/ti/wl18xx/conf.h b/drivers/net/wireless/ti/wl18xx/conf.h
index e34302e3b51d..71f1ec448ba5 100644
--- a/drivers/net/wireless/ti/wl18xx/conf.h
+++ b/drivers/net/wireless/ti/wl18xx/conf.h
@@ -23,7 +23,7 @@
#define __WL18XX_CONF_H__
#define WL18XX_CONF_MAGIC 0x10e100ca
-#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0006)
+#define WL18XX_CONF_VERSION (WLCORE_CONF_VERSION | 0x0007)
#define WL18XX_CONF_MASK 0x0000ffff
#define WL18XX_CONF_SIZE (WLCORE_CONF_SIZE + \
sizeof(struct wl18xx_priv_conf))
@@ -110,12 +110,33 @@ struct wl18xx_ht_settings {
u8 mode;
} __packed;
+struct conf_ap_sleep_settings {
+ /* Duty Cycle (20-80% of staying Awake) for IDLE AP
+ * (0: disable)
+ */
+ u8 idle_duty_cycle;
+ /* Duty Cycle (20-80% of staying Awake) for Connected AP
+ * (0: disable)
+ */
+ u8 connected_duty_cycle;
+ /* Maximum stations that are allowed to be connected to AP
+ * (255: no limit)
+ */
+ u8 max_stations_thresh;
+ /* Timeout till enabling the Sleep Mechanism after data stops
+ * [unit: 100 msec]
+ */
+ u8 idle_conn_thresh;
+} __packed;
+
struct wl18xx_priv_conf {
/* Module params structures */
struct wl18xx_ht_settings ht;
/* this structure is copied wholesale to FW */
struct wl18xx_mac_and_phy_params phy;
+
+ struct conf_ap_sleep_settings ap_sleep;
} __packed;
#endif /* __WL18XX_CONF_H__ */
diff --git a/drivers/net/wireless/ti/wl18xx/debugfs.c b/drivers/net/wireless/ti/wl18xx/debugfs.c
index 7f1669cdea09..c93fae95baac 100644
--- a/drivers/net/wireless/ti/wl18xx/debugfs.c
+++ b/drivers/net/wireless/ti/wl18xx/debugfs.c
@@ -22,9 +22,12 @@
#include "../wlcore/debugfs.h"
#include "../wlcore/wlcore.h"
+#include "../wlcore/debug.h"
+#include "../wlcore/ps.h"
#include "wl18xx.h"
#include "acx.h"
+#include "cmd.h"
#include "debugfs.h"
#define WL18XX_DEBUGFS_FWSTATS_FILE(a, b, c) \
@@ -239,6 +242,45 @@ static const struct file_operations clear_fw_stats_ops = {
.llseek = default_llseek,
};
+static ssize_t radar_detection_write(struct file *file,
+ const char __user *user_buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1271 *wl = file->private_data;
+ int ret;
+ u8 channel;
+
+ ret = kstrtou8_from_user(user_buf, count, 10, &channel);
+ if (ret < 0) {
+ wl1271_warning("illegal channel");
+ return -EINVAL;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl18xx_cmd_radar_detection_debug(wl, channel);
+ if (ret < 0)
+ count = ret;
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+ return count;
+}
+
+static const struct file_operations radar_detection_ops = {
+ .write = radar_detection_write,
+ .open = simple_open,
+ .llseek = default_llseek,
+};
+
int wl18xx_debugfs_add_files(struct wl1271 *wl,
struct dentry *rootdir)
{
@@ -390,6 +432,7 @@ int wl18xx_debugfs_add_files(struct wl1271 *wl,
DEBUGFS_FWSTATS_ADD(mem, fw_gen_free_mem_blks);
DEBUGFS_ADD(conf, moddir);
+ DEBUGFS_ADD(radar_detection, moddir);
return 0;
diff --git a/drivers/net/wireless/ti/wl18xx/event.c b/drivers/net/wireless/ti/wl18xx/event.c
index eb1848e08424..c28f06854195 100644
--- a/drivers/net/wireless/ti/wl18xx/event.c
+++ b/drivers/net/wireless/ti/wl18xx/event.c
@@ -47,6 +47,19 @@ int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
return wlcore_cmd_wait_for_event_or_timeout(wl, local_event, timeout);
}
+static const char *wl18xx_radar_type_decode(u8 radar_type)
+{
+ switch (radar_type) {
+ case RADAR_TYPE_REGULAR:
+ return "REGULAR";
+ case RADAR_TYPE_CHIRP:
+ return "CHIRP";
+ case RADAR_TYPE_NONE:
+ default:
+ return "N/A";
+ }
+}
+
static int wlcore_smart_config_sync_event(struct wl1271 *wl, u8 sync_channel,
u8 sync_band)
{
@@ -115,6 +128,14 @@ int wl18xx_process_mailbox_events(struct wl1271 *wl)
wl18xx_scan_completed(wl, wl->scan_wlvif);
}
+ if (vector & RADAR_DETECTED_EVENT_ID) {
+ wl1271_info("radar event: channel %d type %s",
+ mbox->radar_channel,
+ wl18xx_radar_type_decode(mbox->radar_type));
+
+ ieee80211_radar_detected(wl->hw);
+ }
+
if (vector & PERIODIC_SCAN_REPORT_EVENT_ID) {
wl1271_debug(DEBUG_EVENT,
"PERIODIC_SCAN_REPORT_EVENT (results %d)",
diff --git a/drivers/net/wireless/ti/wl18xx/event.h b/drivers/net/wireless/ti/wl18xx/event.h
index 0680312d4943..266ee87834e4 100644
--- a/drivers/net/wireless/ti/wl18xx/event.h
+++ b/drivers/net/wireless/ti/wl18xx/event.h
@@ -42,6 +42,12 @@ enum {
SMART_CONFIG_DECODE_EVENT_ID = BIT(23),
};
+enum wl18xx_radar_types {
+ RADAR_TYPE_NONE,
+ RADAR_TYPE_REGULAR,
+ RADAR_TYPE_CHIRP
+};
+
struct wl18xx_event_mailbox {
__le32 events_vector;
@@ -83,13 +89,19 @@ struct wl18xx_event_mailbox {
u8 sc_token_len;
u8 padding1;
u8 sc_ssid[32];
- u8 sc_pwd[32];
+ u8 sc_pwd[64];
u8 sc_token[32];
/* smart config sync channel */
u8 sc_sync_channel;
u8 sc_sync_band;
u8 padding2[2];
+
+ /* radar detect */
+ u8 radar_channel;
+ u8 radar_type;
+
+ u8 padding3[2];
} __packed;
int wl18xx_wait_for_event(struct wl1271 *wl, enum wlcore_wait_event event,
diff --git a/drivers/net/wireless/ti/wl18xx/main.c b/drivers/net/wireless/ti/wl18xx/main.c
index 8e562610bf16..717c4f5a02c2 100644
--- a/drivers/net/wireless/ti/wl18xx/main.c
+++ b/drivers/net/wireless/ti/wl18xx/main.c
@@ -378,6 +378,7 @@ static struct wlcore_conf wl18xx_conf = {
.keep_alive_interval = 55000,
.max_listen_interval = 20,
.sta_sleep_auth = WL1271_PSM_ILLEGAL,
+ .suspend_rx_ba_activity = 0,
},
.itrim = {
.enable = false,
@@ -567,6 +568,12 @@ static struct wl18xx_priv_conf wl18xx_default_priv_conf = {
.high_power_val_2nd = 0xff,
.tx_rf_margin = 1,
},
+ .ap_sleep = { /* disabled by default */
+ .idle_duty_cycle = 0,
+ .connected_duty_cycle = 0,
+ .max_stations_thresh = 0,
+ .idle_conn_thresh = 0,
+ },
};
static const struct wlcore_partition_set wl18xx_ptable[PART_TABLE_LEN] = {
@@ -648,7 +655,7 @@ static const struct wl18xx_clk_cfg wl18xx_clk_table[NUM_CLOCK_CONFIGS] = {
};
/* TODO: maybe move to a new header file? */
-#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-3.bin"
+#define WL18XX_FW_NAME "ti-connectivity/wl18xx-fw-4.bin"
static int wl18xx_identify_chip(struct wl1271 *wl)
{
@@ -983,6 +990,7 @@ static int wl18xx_boot(struct wl1271 *wl)
wl->event_mask = BSS_LOSS_EVENT_ID |
SCAN_COMPLETE_EVENT_ID |
+ RADAR_DETECTED_EVENT_ID |
RSSI_SNR_TRIGGER_0_EVENT_ID |
PERIODIC_SCAN_COMPLETE_EVENT_ID |
PERIODIC_SCAN_REPORT_EVENT_ID |
@@ -1559,26 +1567,19 @@ static u32 wl18xx_pre_pkt_send(struct wl1271 *wl,
}
static void wl18xx_sta_rc_update(struct wl1271 *wl,
- struct wl12xx_vif *wlvif,
- struct ieee80211_sta *sta,
- u32 changed)
+ struct wl12xx_vif *wlvif)
{
- bool wide = sta->bandwidth >= IEEE80211_STA_RX_BW_40;
+ bool wide = wlvif->rc_update_bw >= IEEE80211_STA_RX_BW_40;
wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update wide %d", wide);
- if (!(changed & IEEE80211_RC_BW_CHANGED))
- return;
-
- mutex_lock(&wl->mutex);
-
/* sanity */
if (WARN_ON(wlvif->bss_type != BSS_TYPE_STA_BSS))
- goto out;
+ return;
/* ignore the change before association */
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
- goto out;
+ return;
/*
* If we started out as wide, we can change the operation mode. If we
@@ -1589,9 +1590,6 @@ static void wl18xx_sta_rc_update(struct wl1271 *wl,
wl18xx_acx_peer_ht_operation_mode(wl, wlvif->sta.hlid, wide);
else
ieee80211_connection_loss(wl12xx_wlvif_to_vif(wlvif));
-
-out:
- mutex_unlock(&wl->mutex);
}
static int wl18xx_set_peer_cap(struct wl1271 *wl,
@@ -1703,6 +1701,11 @@ static struct wlcore_ops wl18xx_ops = {
.smart_config_start = wl18xx_cmd_smart_config_start,
.smart_config_stop = wl18xx_cmd_smart_config_stop,
.smart_config_set_group_key = wl18xx_cmd_smart_config_set_group_key,
+ .interrupt_notify = wl18xx_acx_interrupt_notify_config,
+ .rx_ba_filter = wl18xx_acx_rx_ba_filter,
+ .ap_sleep = wl18xx_acx_ap_sleep,
+ .set_cac = wl18xx_cmd_set_cac,
+ .dfs_master_restart = wl18xx_cmd_dfs_master_restart,
};
/* HT cap appropriate for wide channels in 2Ghz */
@@ -1796,6 +1799,10 @@ wl18xx_iface_combinations[] = {
.limits = wl18xx_iface_ap_limits,
.n_limits = ARRAY_SIZE(wl18xx_iface_ap_limits),
.num_different_channels = 1,
+ .radar_detect_widths = BIT(NL80211_CHAN_NO_HT) |
+ BIT(NL80211_CHAN_HT20) |
+ BIT(NL80211_CHAN_HT40MINUS) |
+ BIT(NL80211_CHAN_HT40PLUS),
}
};
diff --git a/drivers/net/wireless/ti/wl18xx/wl18xx.h b/drivers/net/wireless/ti/wl18xx/wl18xx.h
index 6a2b88030c1d..71e9e382ce80 100644
--- a/drivers/net/wireless/ti/wl18xx/wl18xx.h
+++ b/drivers/net/wireless/ti/wl18xx/wl18xx.h
@@ -26,10 +26,10 @@
/* minimum FW required for driver */
#define WL18XX_CHIP_VER 8
-#define WL18XX_IFTYPE_VER 8
+#define WL18XX_IFTYPE_VER 9
#define WL18XX_MAJOR_VER WLCORE_FW_VER_IGNORE
#define WL18XX_SUBTYPE_VER WLCORE_FW_VER_IGNORE
-#define WL18XX_MINOR_VER 13
+#define WL18XX_MINOR_VER 11
#define WL18XX_CMD_MAX_SIZE 740
diff --git a/drivers/net/wireless/ti/wlcore/acx.c b/drivers/net/wireless/ti/wlcore/acx.c
index b924ceadc02c..f28fa3b5029d 100644
--- a/drivers/net/wireless/ti/wlcore/acx.c
+++ b/drivers/net/wireless/ti/wlcore/acx.c
@@ -1725,7 +1725,7 @@ int wl12xx_acx_config_hangover(struct wl1271 *wl)
acx->decrease_delta = conf->decrease_delta;
acx->quiet_time = conf->quiet_time;
acx->increase_time = conf->increase_time;
- acx->window_size = acx->window_size;
+ acx->window_size = conf->window_size;
ret = wl1271_cmd_configure(wl, ACX_CONFIG_HANGOVER, acx,
sizeof(*acx));
diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c
index b82661962d33..c26fc2106e5b 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.c
+++ b/drivers/net/wireless/ti/wlcore/cmd.c
@@ -403,7 +403,7 @@ void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid)
WARN_ON_ONCE(wl->active_link_count < 0);
}
-static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
+u8 wlcore_get_native_channel_type(u8 nl_channel_type)
{
switch (nl_channel_type) {
case NL80211_CHAN_NO_HT:
@@ -419,6 +419,7 @@ static u8 wlcore_get_native_channel_type(u8 nl_channel_type)
return WLCORE_CHAN_NO_HT;
}
}
+EXPORT_SYMBOL_GPL(wlcore_get_native_channel_type);
static int wl12xx_cmd_role_start_dev(struct wl1271 *wl,
struct wl12xx_vif *wlvif,
@@ -1686,9 +1687,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
{
struct wl12xx_cmd_regdomain_dfs_config *cmd = NULL;
int ret = 0, i, b, ch_bit_idx;
- struct ieee80211_channel *channel;
u32 tmp_ch_bitmap[2];
- u16 ch;
struct wiphy *wiphy = wl->hw->wiphy;
struct ieee80211_supported_band *band;
bool timeout = false;
@@ -1703,12 +1702,16 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
for (b = IEEE80211_BAND_2GHZ; b <= IEEE80211_BAND_5GHZ; b++) {
band = wiphy->bands[b];
for (i = 0; i < band->n_channels; i++) {
- channel = &band->channels[i];
- ch = channel->hw_value;
+ struct ieee80211_channel *channel = &band->channels[i];
+ u16 ch = channel->hw_value;
+ u32 flags = channel->flags;
- if (channel->flags & (IEEE80211_CHAN_DISABLED |
- IEEE80211_CHAN_RADAR |
- IEEE80211_CHAN_NO_IR))
+ if (flags & (IEEE80211_CHAN_DISABLED |
+ IEEE80211_CHAN_NO_IR))
+ continue;
+
+ if ((flags & IEEE80211_CHAN_RADAR) &&
+ channel->dfs_state != NL80211_DFS_AVAILABLE)
continue;
ch_bit_idx = wlcore_get_reg_conf_ch_idx(b, ch);
@@ -1733,6 +1736,7 @@ int wlcore_cmd_regdomain_config_locked(struct wl1271 *wl)
cmd->ch_bit_map1 = cpu_to_le32(tmp_ch_bitmap[0]);
cmd->ch_bit_map2 = cpu_to_le32(tmp_ch_bitmap[1]);
+ cmd->dfs_region = wl->dfs_region;
wl1271_debug(DEBUG_CMD,
"cmd reg domain bitmap1: 0x%08x, bitmap2: 0x%08x",
diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h
index 453684a71d30..e14cd407a6ae 100644
--- a/drivers/net/wireless/ti/wlcore/cmd.h
+++ b/drivers/net/wireless/ti/wlcore/cmd.h
@@ -105,6 +105,7 @@ int wl12xx_allocate_link(struct wl1271 *wl, struct wl12xx_vif *wlvif,
void wl12xx_free_link(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 *hlid);
int wlcore_cmd_wait_for_event_or_timeout(struct wl1271 *wl,
u32 mask, bool *timeout);
+u8 wlcore_get_native_channel_type(u8 nl_channel_type);
enum wl1271_commands {
CMD_INTERROGATE = 1, /* use this to read information elements */
@@ -172,6 +173,11 @@ enum wl1271_commands {
CMD_SMART_CONFIG_STOP = 62,
CMD_SMART_CONFIG_SET_GROUP_KEY = 63,
+ CMD_CAC_START = 64,
+ CMD_CAC_STOP = 65,
+ CMD_DFS_MASTER_RESTART = 66,
+ CMD_DFS_RADAR_DETECTION_DEBUG = 67,
+
MAX_COMMAND_ID = 0xFFFF,
};
@@ -642,6 +648,8 @@ struct wl12xx_cmd_regdomain_dfs_config {
__le32 ch_bit_map1;
__le32 ch_bit_map2;
+ u8 dfs_region;
+ u8 padding[3];
} __packed;
struct wl12xx_cmd_config_fwlog {
diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h
index 40995c42bef8..166add00b50f 100644
--- a/drivers/net/wireless/ti/wlcore/conf.h
+++ b/drivers/net/wireless/ti/wlcore/conf.h
@@ -997,6 +997,11 @@ struct conf_conn_settings {
* whether we can go to ELP.
*/
u8 sta_sleep_auth;
+
+ /*
+ * Default RX BA Activity filter configuration
+ */
+ u8 suspend_rx_ba_activity;
} __packed;
enum {
@@ -1347,7 +1352,7 @@ struct conf_recovery_settings {
* version, the two LSB are the lower driver's private conf
* version.
*/
-#define WLCORE_CONF_VERSION (0x0005 << 16)
+#define WLCORE_CONF_VERSION (0x0006 << 16)
#define WLCORE_CONF_MASK 0xffff0000
#define WLCORE_CONF_SIZE (sizeof(struct wlcore_conf_header) + \
sizeof(struct wlcore_conf))
diff --git a/drivers/net/wireless/ti/wlcore/debugfs.c b/drivers/net/wireless/ti/wlcore/debugfs.c
index 0be21f62fcb0..68f3bf229b5a 100644
--- a/drivers/net/wireless/ti/wlcore/debugfs.c
+++ b/drivers/net/wireless/ti/wlcore/debugfs.c
@@ -929,17 +929,10 @@ static ssize_t beacon_filtering_write(struct file *file,
{
struct wl1271 *wl = file->private_data;
struct wl12xx_vif *wlvif;
- char buf[10];
- size_t len;
unsigned long value;
int ret;
- len = min(count, sizeof(buf) - 1);
- if (copy_from_user(buf, user_buf, len))
- return -EFAULT;
- buf[len] = '\0';
-
- ret = kstrtoul(buf, 0, &value);
+ ret = kstrtoul_from_user(user_buf, count, 0, &value);
if (ret < 0) {
wl1271_warning("illegal value for beacon_filtering!");
return -EINVAL;
diff --git a/drivers/net/wireless/ti/wlcore/event.c b/drivers/net/wireless/ti/wlcore/event.c
index 5153640f4532..c42e78955e7b 100644
--- a/drivers/net/wireless/ti/wlcore/event.c
+++ b/drivers/net/wireless/ti/wlcore/event.c
@@ -139,7 +139,7 @@ void wlcore_event_channel_switch(struct wl1271 *wl,
wl1271_debug(DEBUG_EVENT, "%s: roles=0x%lx success=%d",
__func__, roles_bitmap, success);
- wl12xx_for_each_wlvif_sta(wl, wlvif) {
+ wl12xx_for_each_wlvif(wl, wlvif) {
if (wlvif->role_id == WL12XX_INVALID_ROLE_ID ||
!test_bit(wlvif->role_id , &roles_bitmap))
continue;
@@ -150,8 +150,13 @@ void wlcore_event_channel_switch(struct wl1271 *wl,
vif = wl12xx_wlvif_to_vif(wlvif);
- ieee80211_chswitch_done(vif, success);
- cancel_delayed_work(&wlvif->channel_switch_work);
+ if (wlvif->bss_type == BSS_TYPE_STA_BSS) {
+ ieee80211_chswitch_done(vif, success);
+ cancel_delayed_work(&wlvif->channel_switch_work);
+ } else {
+ set_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags);
+ ieee80211_csa_finish(vif);
+ }
}
}
EXPORT_SYMBOL_GPL(wlcore_event_channel_switch);
diff --git a/drivers/net/wireless/ti/wlcore/hw_ops.h b/drivers/net/wireless/ti/wlcore/hw_ops.h
index aa9f82c72296..eec56935b1b6 100644
--- a/drivers/net/wireless/ti/wlcore/hw_ops.h
+++ b/drivers/net/wireless/ti/wlcore/hw_ops.h
@@ -211,11 +211,35 @@ wlcore_hw_pre_pkt_send(struct wl1271 *wl, u32 buf_offset, u32 last_len)
}
static inline void
-wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct ieee80211_sta *sta, u32 changed)
+wlcore_hw_sta_rc_update(struct wl1271 *wl, struct wl12xx_vif *wlvif)
{
if (wl->ops->sta_rc_update)
- wl->ops->sta_rc_update(wl, wlvif, sta, changed);
+ wl->ops->sta_rc_update(wl, wlvif);
+}
+
+static inline int
+wlcore_hw_interrupt_notify(struct wl1271 *wl, bool action)
+{
+ if (wl->ops->interrupt_notify)
+ return wl->ops->interrupt_notify(wl, action);
+ return 0;
+}
+
+static inline int
+wlcore_hw_rx_ba_filter(struct wl1271 *wl, bool action)
+{
+ if (wl->ops->rx_ba_filter)
+ return wl->ops->rx_ba_filter(wl, action);
+ return 0;
+}
+
+static inline int
+wlcore_hw_ap_sleep(struct wl1271 *wl)
+{
+ if (wl->ops->ap_sleep)
+ return wl->ops->ap_sleep(wl);
+
+ return 0;
}
static inline int
@@ -287,4 +311,22 @@ wlcore_smart_config_set_group_key(struct wl1271 *wl, u16 group_id,
return wl->ops->smart_config_set_group_key(wl, group_id, key_len, key);
}
+
+static inline int
+wlcore_hw_set_cac(struct wl1271 *wl, struct wl12xx_vif *wlvif, bool start)
+{
+ if (!wl->ops->set_cac)
+ return -EINVAL;
+
+ return wl->ops->set_cac(wl, wlvif, start);
+}
+
+static inline int
+wlcore_hw_dfs_master_restart(struct wl1271 *wl, struct wl12xx_vif *wlvif)
+{
+ if (!wl->ops->dfs_master_restart)
+ return -EINVAL;
+
+ return wl->ops->dfs_master_restart(wl, wlvif);
+}
#endif
diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c
index 199e94120864..5ca1fb161a50 100644
--- a/drivers/net/wireless/ti/wlcore/init.c
+++ b/drivers/net/wireless/ti/wlcore/init.c
@@ -392,6 +392,11 @@ static int wl1271_ap_hw_init(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if (ret < 0)
return ret;
+ /* configure AP sleep, if enabled */
+ ret = wlcore_hw_ap_sleep(wl);
+ if (ret < 0)
+ return ret;
+
return 0;
}
@@ -567,8 +572,7 @@ int wl1271_init_vif_specific(struct wl1271 *wl, struct ieee80211_vif *vif)
/* consider all existing roles before configuring psm. */
if (wl->ap_count == 0 && is_ap) { /* first AP */
- /* Configure for power always on */
- ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_CAM);
+ ret = wl1271_acx_sleep_auth(wl, WL1271_PSM_ELP);
if (ret < 0)
return ret;
diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c
index 6ad3fcedab9b..1e136993580f 100644
--- a/drivers/net/wireless/ti/wlcore/main.c
+++ b/drivers/net/wireless/ti/wlcore/main.c
@@ -79,22 +79,12 @@ static int wl12xx_set_authorized(struct wl1271 *wl, struct wl12xx_vif *wlvif)
static void wl1271_reg_notify(struct wiphy *wiphy,
struct regulatory_request *request)
{
- struct ieee80211_supported_band *band;
- struct ieee80211_channel *ch;
- int i;
struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
struct wl1271 *wl = hw->priv;
- band = wiphy->bands[IEEE80211_BAND_5GHZ];
- for (i = 0; i < band->n_channels; i++) {
- ch = &band->channels[i];
- if (ch->flags & IEEE80211_CHAN_DISABLED)
- continue;
-
- if (ch->flags & IEEE80211_CHAN_RADAR)
- ch->flags |= IEEE80211_CHAN_NO_IR;
-
- }
+ /* copy the current dfs region */
+ if (request)
+ wl->dfs_region = request->dfs_region;
wlcore_regdomain_config(wl);
}
@@ -226,6 +216,29 @@ void wl12xx_rearm_tx_watchdog_locked(struct wl1271 *wl)
msecs_to_jiffies(wl->conf.tx.tx_watchdog_timeout));
}
+static void wlcore_rc_update_work(struct work_struct *work)
+{
+ int ret;
+ struct wl12xx_vif *wlvif = container_of(work, struct wl12xx_vif,
+ rc_update_work);
+ struct wl1271 *wl = wlvif->wl;
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wlcore_hw_sta_rc_update(wl, wlvif);
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static void wl12xx_tx_watchdog_work(struct work_struct *work)
{
struct delayed_work *dwork;
@@ -1662,19 +1675,15 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (!test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
goto out;
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- goto out;
-
ret = wl1271_configure_wowlan(wl, wow);
if (ret < 0)
- goto out_sleep;
+ goto out;
if ((wl->conf.conn.suspend_wake_up_event ==
wl->conf.conn.wake_up_event) &&
(wl->conf.conn.suspend_listen_interval ==
wl->conf.conn.listen_interval))
- goto out_sleep;
+ goto out;
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.suspend_wake_up_event,
@@ -1682,29 +1691,28 @@ static int wl1271_configure_suspend_sta(struct wl1271 *wl,
if (ret < 0)
wl1271_error("suspend: set wake up conditions failed: %d", ret);
-
-out_sleep:
- wl1271_ps_elp_sleep(wl);
out:
return ret;
}
static int wl1271_configure_suspend_ap(struct wl1271 *wl,
- struct wl12xx_vif *wlvif)
+ struct wl12xx_vif *wlvif,
+ struct cfg80211_wowlan *wow)
{
int ret = 0;
if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
goto out;
- ret = wl1271_ps_elp_wakeup(wl);
+ ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
if (ret < 0)
goto out;
- ret = wl1271_acx_beacon_filter_opt(wl, wlvif, true);
+ ret = wl1271_configure_wowlan(wl, wow);
+ if (ret < 0)
+ goto out;
- wl1271_ps_elp_sleep(wl);
out:
return ret;
@@ -1717,7 +1725,7 @@ static int wl1271_configure_suspend(struct wl1271 *wl,
if (wlvif->bss_type == BSS_TYPE_STA_BSS)
return wl1271_configure_suspend_sta(wl, wlvif, wow);
if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- return wl1271_configure_suspend_ap(wl, wlvif);
+ return wl1271_configure_suspend_ap(wl, wlvif, wow);
return 0;
}
@@ -1730,21 +1738,18 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
if ((!is_ap) && (!is_sta))
return;
- if (is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags))
+ if ((is_sta && !test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags)) ||
+ (is_ap && !test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)))
return;
- ret = wl1271_ps_elp_wakeup(wl);
- if (ret < 0)
- return;
+ wl1271_configure_wowlan(wl, NULL);
if (is_sta) {
- wl1271_configure_wowlan(wl, NULL);
-
if ((wl->conf.conn.suspend_wake_up_event ==
wl->conf.conn.wake_up_event) &&
(wl->conf.conn.suspend_listen_interval ==
wl->conf.conn.listen_interval))
- goto out_sleep;
+ return;
ret = wl1271_acx_wake_up_conditions(wl, wlvif,
wl->conf.conn.wake_up_event,
@@ -1757,9 +1762,6 @@ static void wl1271_configure_resume(struct wl1271 *wl, struct wl12xx_vif *wlvif)
} else if (is_ap) {
ret = wl1271_acx_beacon_filter_opt(wl, wlvif, false);
}
-
-out_sleep:
- wl1271_ps_elp_sleep(wl);
}
static int wl1271_op_suspend(struct ieee80211_hw *hw,
@@ -1781,6 +1783,13 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
wl1271_tx_flush(wl);
mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0) {
+ mutex_unlock(&wl->mutex);
+ return ret;
+ }
+
wl->wow_enabled = true;
wl12xx_for_each_wlvif(wl, wlvif) {
ret = wl1271_configure_suspend(wl, wlvif, wow);
@@ -1790,7 +1799,27 @@ static int wl1271_op_suspend(struct ieee80211_hw *hw,
return ret;
}
}
+
+ /* disable fast link flow control notifications from FW */
+ ret = wlcore_hw_interrupt_notify(wl, false);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* if filtering is enabled, configure the FW to drop all RX BA frames */
+ ret = wlcore_hw_rx_ba_filter(wl,
+ !!wl->conf.conn.suspend_rx_ba_activity);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
mutex_unlock(&wl->mutex);
+
+ if (ret < 0) {
+ wl1271_warning("couldn't prepare device to suspend");
+ return ret;
+ }
+
/* flush any remaining work */
wl1271_debug(DEBUG_MAC80211, "flushing remaining works");
@@ -1864,13 +1893,29 @@ static int wl1271_op_resume(struct ieee80211_hw *hw)
if (pending_recovery) {
wl1271_warning("queuing forgotten recovery on resume");
ieee80211_queue_work(wl->hw, &wl->recovery_work);
- goto out;
+ goto out_sleep;
}
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
wl12xx_for_each_wlvif(wl, wlvif) {
wl1271_configure_resume(wl, wlvif);
}
+ ret = wlcore_hw_interrupt_notify(wl, true);
+ if (ret < 0)
+ goto out_sleep;
+
+ /* if filtering is enabled, configure the FW to drop all RX BA frames */
+ ret = wlcore_hw_rx_ba_filter(wl, false);
+ if (ret < 0)
+ goto out_sleep;
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+
out:
wl->wow_enabled = false;
@@ -2279,6 +2324,7 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif)
wl1271_rx_streaming_enable_work);
INIT_WORK(&wlvif->rx_streaming_disable_work,
wl1271_rx_streaming_disable_work);
+ INIT_WORK(&wlvif->rc_update_work, wlcore_rc_update_work);
INIT_DELAYED_WORK(&wlvif->channel_switch_work,
wlcore_channel_switch_work);
INIT_DELAYED_WORK(&wlvif->connection_loss_work,
@@ -2508,6 +2554,7 @@ static int wl1271_op_add_interface(struct ieee80211_hw *hw,
}
vif->driver_flags |= IEEE80211_VIF_BEACON_FILTER |
+ IEEE80211_VIF_SUPPORTS_UAPSD |
IEEE80211_VIF_SUPPORTS_CQM_RSSI;
wl1271_debug(DEBUG_MAC80211, "mac80211 add interface type %d mac %pM",
@@ -2723,6 +2770,7 @@ unlock:
del_timer_sync(&wlvif->rx_streaming_timer);
cancel_work_sync(&wlvif->rx_streaming_enable_work);
cancel_work_sync(&wlvif->rx_streaming_disable_work);
+ cancel_work_sync(&wlvif->rc_update_work);
cancel_delayed_work_sync(&wlvif->connection_loss_work);
cancel_delayed_work_sync(&wlvif->channel_switch_work);
cancel_delayed_work_sync(&wlvif->pending_auth_complete_work);
@@ -4072,8 +4120,14 @@ static int wl1271_bss_beacon_info_changed(struct wl1271 *wl,
ret = wlcore_set_beacon_template(wl, vif, is_ap);
if (ret < 0)
goto out;
- }
+ if (test_and_clear_bit(WLVIF_FLAG_BEACON_DISABLED,
+ &wlvif->flags)) {
+ ret = wlcore_hw_dfs_master_restart(wl, wlvif);
+ if (ret < 0)
+ goto out;
+ }
+ }
out:
if (ret != 0)
wl1271_error("beacon info change failed: %d", ret);
@@ -4574,10 +4628,46 @@ static void wlcore_op_change_chanctx(struct ieee80211_hw *hw,
struct ieee80211_chanctx_conf *ctx,
u32 changed)
{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif;
+ int ret;
+ int channel = ieee80211_frequency_to_channel(
+ ctx->def.chan->center_freq);
+
wl1271_debug(DEBUG_MAC80211,
"mac80211 change chanctx %d (type %d) changed 0x%x",
- ieee80211_frequency_to_channel(ctx->def.chan->center_freq),
- cfg80211_get_chandef_type(&ctx->def), changed);
+ channel, cfg80211_get_chandef_type(&ctx->def), changed);
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ wl12xx_for_each_wlvif(wl, wlvif) {
+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif);
+
+ rcu_read_lock();
+ if (rcu_access_pointer(vif->chanctx_conf) != ctx) {
+ rcu_read_unlock();
+ continue;
+ }
+ rcu_read_unlock();
+
+ /* start radar if needed */
+ if (changed & IEEE80211_CHANCTX_CHANGE_RADAR &&
+ wlvif->bss_type == BSS_TYPE_AP_BSS &&
+ ctx->radar_enabled && !wlvif->radar_enabled &&
+ ctx->def.chan->dfs_state == NL80211_DFS_USABLE) {
+ wl1271_debug(DEBUG_MAC80211, "Start radar detection");
+ wlcore_hw_set_cac(wl, wlvif, true);
+ wlvif->radar_enabled = true;
+ }
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
}
static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
@@ -4588,13 +4678,26 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
int channel = ieee80211_frequency_to_channel(
ctx->def.chan->center_freq);
+ int ret = -EINVAL;
wl1271_debug(DEBUG_MAC80211,
- "mac80211 assign chanctx (role %d) %d (type %d)",
- wlvif->role_id, channel, cfg80211_get_chandef_type(&ctx->def));
+ "mac80211 assign chanctx (role %d) %d (type %d) (radar %d dfs_state %d)",
+ wlvif->role_id, channel,
+ cfg80211_get_chandef_type(&ctx->def),
+ ctx->radar_enabled, ctx->def.chan->dfs_state);
mutex_lock(&wl->mutex);
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
wlvif->band = ctx->def.chan->band;
wlvif->channel = channel;
wlvif->channel_type = cfg80211_get_chandef_type(&ctx->def);
@@ -4602,6 +4705,15 @@ static int wlcore_op_assign_vif_chanctx(struct ieee80211_hw *hw,
/* update default rates according to the band */
wl1271_set_band_rate(wl, wlvif);
+ if (ctx->radar_enabled &&
+ ctx->def.chan->dfs_state == NL80211_DFS_USABLE) {
+ wl1271_debug(DEBUG_MAC80211, "Start radar detection");
+ wlcore_hw_set_cac(wl, wlvif, true);
+ wlvif->radar_enabled = true;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
mutex_unlock(&wl->mutex);
return 0;
@@ -4613,6 +4725,7 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ int ret;
wl1271_debug(DEBUG_MAC80211,
"mac80211 unassign chanctx (role %d) %d (type %d)",
@@ -4621,6 +4734,99 @@ static void wlcore_op_unassign_vif_chanctx(struct ieee80211_hw *hw,
cfg80211_get_chandef_type(&ctx->def));
wl1271_tx_flush(wl);
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON))
+ goto out;
+
+ if (unlikely(!test_bit(WLVIF_FLAG_INITIALIZED, &wlvif->flags)))
+ goto out;
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ if (wlvif->radar_enabled) {
+ wl1271_debug(DEBUG_MAC80211, "Stop radar detection");
+ wlcore_hw_set_cac(wl, wlvif, false);
+ wlvif->radar_enabled = false;
+ }
+
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
+static int __wlcore_switch_vif_chan(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ struct ieee80211_chanctx_conf *new_ctx)
+{
+ int channel = ieee80211_frequency_to_channel(
+ new_ctx->def.chan->center_freq);
+
+ wl1271_debug(DEBUG_MAC80211,
+ "switch vif (role %d) %d -> %d chan_type: %d",
+ wlvif->role_id, wlvif->channel, channel,
+ cfg80211_get_chandef_type(&new_ctx->def));
+
+ if (WARN_ON_ONCE(wlvif->bss_type != BSS_TYPE_AP_BSS))
+ return 0;
+
+ WARN_ON(!test_bit(WLVIF_FLAG_BEACON_DISABLED, &wlvif->flags));
+
+ if (wlvif->radar_enabled) {
+ wl1271_debug(DEBUG_MAC80211, "Stop radar detection");
+ wlcore_hw_set_cac(wl, wlvif, false);
+ wlvif->radar_enabled = false;
+ }
+
+ wlvif->band = new_ctx->def.chan->band;
+ wlvif->channel = channel;
+ wlvif->channel_type = cfg80211_get_chandef_type(&new_ctx->def);
+
+ /* start radar if needed */
+ if (new_ctx->radar_enabled) {
+ wl1271_debug(DEBUG_MAC80211, "Start radar detection");
+ wlcore_hw_set_cac(wl, wlvif, true);
+ wlvif->radar_enabled = true;
+ }
+
+ return 0;
+}
+
+static int
+wlcore_op_switch_vif_chanctx(struct ieee80211_hw *hw,
+ struct ieee80211_vif_chanctx_switch *vifs,
+ int n_vifs,
+ enum ieee80211_chanctx_switch_mode mode)
+{
+ struct wl1271 *wl = hw->priv;
+ int i, ret;
+
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 switch chanctx n_vifs %d mode %d",
+ n_vifs, mode);
+
+ mutex_lock(&wl->mutex);
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ for (i = 0; i < n_vifs; i++) {
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vifs[i].vif);
+
+ ret = __wlcore_switch_vif_chan(wl, wlvif, vifs[i].new_ctx);
+ if (ret)
+ goto out_sleep;
+ }
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+
+ return 0;
}
static int wl1271_op_conf_tx(struct ieee80211_hw *hw,
@@ -5228,6 +5434,83 @@ out:
mutex_unlock(&wl->mutex);
}
+static const void *wlcore_get_beacon_ie(struct wl1271 *wl,
+ struct wl12xx_vif *wlvif,
+ u8 eid)
+{
+ int ieoffset = offsetof(struct ieee80211_mgmt, u.beacon.variable);
+ struct sk_buff *beacon =
+ ieee80211_beacon_get(wl->hw, wl12xx_wlvif_to_vif(wlvif));
+
+ if (!beacon)
+ return NULL;
+
+ return cfg80211_find_ie(eid,
+ beacon->data + ieoffset,
+ beacon->len - ieoffset);
+}
+
+static int wlcore_get_csa_count(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ u8 *csa_count)
+{
+ const u8 *ie;
+ const struct ieee80211_channel_sw_ie *ie_csa;
+
+ ie = wlcore_get_beacon_ie(wl, wlvif, WLAN_EID_CHANNEL_SWITCH);
+ if (!ie)
+ return -EINVAL;
+
+ ie_csa = (struct ieee80211_channel_sw_ie *)&ie[2];
+ *csa_count = ie_csa->count;
+
+ return 0;
+}
+
+static void wlcore_op_channel_switch_beacon(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct cfg80211_chan_def *chandef)
+{
+ struct wl1271 *wl = hw->priv;
+ struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
+ struct ieee80211_channel_switch ch_switch = {
+ .block_tx = true,
+ .chandef = *chandef,
+ };
+ int ret;
+
+ wl1271_debug(DEBUG_MAC80211,
+ "mac80211 channel switch beacon (role %d)",
+ wlvif->role_id);
+
+ ret = wlcore_get_csa_count(wl, wlvif, &ch_switch.count);
+ if (ret < 0) {
+ wl1271_error("error getting beacon (for CSA counter)");
+ return;
+ }
+
+ mutex_lock(&wl->mutex);
+
+ if (unlikely(wl->state != WLCORE_STATE_ON)) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ ret = wl1271_ps_elp_wakeup(wl);
+ if (ret < 0)
+ goto out;
+
+ ret = wl->ops->channel_switch(wl, wlvif, &ch_switch);
+ if (ret)
+ goto out_sleep;
+
+ set_bit(WLVIF_FLAG_CS_PROGRESS, &wlvif->flags);
+
+out_sleep:
+ wl1271_ps_elp_sleep(wl);
+out:
+ mutex_unlock(&wl->mutex);
+}
+
static void wlcore_op_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
u32 queues, bool drop)
{
@@ -5370,19 +5653,26 @@ static void wlcore_op_sta_rc_update(struct ieee80211_hw *hw,
u32 changed)
{
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- struct wl1271 *wl = hw->priv;
- wlcore_hw_sta_rc_update(wl, wlvif, sta, changed);
+ wl1271_debug(DEBUG_MAC80211, "mac80211 sta_rc_update");
+
+ if (!(changed & IEEE80211_RC_BW_CHANGED))
+ return;
+
+ /* this callback is atomic, so schedule a new work */
+ wlvif->rc_update_bw = sta->bandwidth;
+ ieee80211_queue_work(hw, &wlvif->rc_update_work);
}
-static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
- struct ieee80211_vif *vif,
- struct ieee80211_sta *sta,
- s8 *rssi_dbm)
+static void wlcore_op_sta_statistics(struct ieee80211_hw *hw,
+ struct ieee80211_vif *vif,
+ struct ieee80211_sta *sta,
+ struct station_info *sinfo)
{
struct wl1271 *wl = hw->priv;
struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif);
- int ret = 0;
+ s8 rssi_dbm;
+ int ret;
wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi");
@@ -5395,17 +5685,18 @@ static int wlcore_op_get_rssi(struct ieee80211_hw *hw,
if (ret < 0)
goto out_sleep;
- ret = wlcore_acx_average_rssi(wl, wlvif, rssi_dbm);
+ ret = wlcore_acx_average_rssi(wl, wlvif, &rssi_dbm);
if (ret < 0)
goto out_sleep;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
+ sinfo->signal = rssi_dbm;
+
out_sleep:
wl1271_ps_elp_sleep(wl);
out:
mutex_unlock(&wl->mutex);
-
- return ret;
}
static bool wl1271_tx_frames_pending(struct ieee80211_hw *hw)
@@ -5596,6 +5887,7 @@ static const struct ieee80211_ops wl1271_ops = {
.set_bitrate_mask = wl12xx_set_bitrate_mask,
.set_default_unicast_key = wl1271_op_set_default_key_idx,
.channel_switch = wl12xx_op_channel_switch,
+ .channel_switch_beacon = wlcore_op_channel_switch_beacon,
.flush = wlcore_op_flush,
.remain_on_channel = wlcore_op_remain_on_channel,
.cancel_remain_on_channel = wlcore_op_cancel_remain_on_channel,
@@ -5604,8 +5896,9 @@ static const struct ieee80211_ops wl1271_ops = {
.change_chanctx = wlcore_op_change_chanctx,
.assign_vif_chanctx = wlcore_op_assign_vif_chanctx,
.unassign_vif_chanctx = wlcore_op_unassign_vif_chanctx,
+ .switch_vif_chanctx = wlcore_op_switch_vif_chanctx,
.sta_rc_update = wlcore_op_sta_rc_update,
- .get_rssi = wlcore_op_get_rssi,
+ .sta_statistics = wlcore_op_sta_statistics,
CFG80211_TESTMODE_CMD(wl1271_tm_cmd)
};
@@ -5776,7 +6069,6 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->flags = IEEE80211_HW_SIGNAL_DBM |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
- IEEE80211_HW_SUPPORTS_UAPSD |
IEEE80211_HW_HAS_RATE_CONTROL |
IEEE80211_HW_CONNECTION_MONITOR |
IEEE80211_HW_REPORTS_TX_ACK_STATUS |
@@ -5811,7 +6103,8 @@ static int wl1271_init_ieee80211(struct wl1271 *wl)
wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD |
WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
- WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+ WIPHY_FLAG_SUPPORTS_SCHED_SCAN |
+ WIPHY_FLAG_HAS_CHANNEL_SWITCH;
/* make sure all our channels fit in the scanned_ch bitmask */
BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) +
diff --git a/drivers/net/wireless/ti/wlcore/ps.c b/drivers/net/wireless/ti/wlcore/ps.c
index b52516eed7b2..4cd316e61466 100644
--- a/drivers/net/wireless/ti/wlcore/ps.c
+++ b/drivers/net/wireless/ti/wlcore/ps.c
@@ -56,9 +56,6 @@ void wl1271_elp_work(struct work_struct *work)
goto out;
wl12xx_for_each_wlvif(wl, wlvif) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- goto out;
-
if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
goto out;
@@ -95,9 +92,6 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
return;
wl12xx_for_each_wlvif(wl, wlvif) {
- if (wlvif->bss_type == BSS_TYPE_AP_BSS)
- return;
-
if (!test_bit(WLVIF_FLAG_IN_PS, &wlvif->flags) &&
test_bit(WLVIF_FLAG_IN_USE, &wlvif->flags))
return;
@@ -108,6 +102,7 @@ void wl1271_ps_elp_sleep(struct wl1271 *wl)
ieee80211_queue_delayed_work(wl->hw, &wl->elp_work,
msecs_to_jiffies(timeout));
}
+EXPORT_SYMBOL_GPL(wl1271_ps_elp_sleep);
int wl1271_ps_elp_wakeup(struct wl1271 *wl)
{
@@ -175,6 +170,7 @@ err:
out:
return 0;
}
+EXPORT_SYMBOL_GPL(wl1271_ps_elp_wakeup);
int wl1271_ps_set_mode(struct wl1271 *wl, struct wl12xx_vif *wlvif,
enum wl1271_cmd_ps_mode mode)
diff --git a/drivers/net/wireless/ti/wlcore/vendor_cmd.c b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
index ad86a48dcfcb..fd4e9ba176c9 100644
--- a/drivers/net/wireless/ti/wlcore/vendor_cmd.c
+++ b/drivers/net/wireless/ti/wlcore/vendor_cmd.c
@@ -21,7 +21,7 @@ static const
struct nla_policy wlcore_vendor_attr_policy[NUM_WLCORE_VENDOR_ATTR] = {
[WLCORE_VENDOR_ATTR_FREQ] = { .type = NLA_U32 },
[WLCORE_VENDOR_ATTR_GROUP_ID] = { .type = NLA_U32 },
- [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_U32,
+ [WLCORE_VENDOR_ATTR_GROUP_KEY] = { .type = NLA_BINARY,
.len = WLAN_MAX_KEY_LEN },
};
diff --git a/drivers/net/wireless/ti/wlcore/wlcore.h b/drivers/net/wireless/ti/wlcore/wlcore.h
index df78cf12ef15..d599c869e6e8 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore.h
@@ -106,8 +106,7 @@ struct wlcore_ops {
struct wl12xx_vif *wlvif,
struct ieee80211_channel_switch *ch_switch);
u32 (*pre_pkt_send)(struct wl1271 *wl, u32 buf_offset, u32 last_len);
- void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
- struct ieee80211_sta *sta, u32 changed);
+ void (*sta_rc_update)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
int (*set_peer_cap)(struct wl1271 *wl,
struct ieee80211_sta_ht_cap *ht_cap,
bool allow_ht_operation,
@@ -117,10 +116,16 @@ struct wlcore_ops {
struct wl1271_link *lnk);
bool (*lnk_low_prio)(struct wl1271 *wl, u8 hlid,
struct wl1271_link *lnk);
+ int (*interrupt_notify)(struct wl1271 *wl, bool action);
+ int (*rx_ba_filter)(struct wl1271 *wl, bool action);
+ int (*ap_sleep)(struct wl1271 *wl);
int (*smart_config_start)(struct wl1271 *wl, u32 group_bitmap);
int (*smart_config_stop)(struct wl1271 *wl);
int (*smart_config_set_group_key)(struct wl1271 *wl, u16 group_id,
u8 key_len, u8 *key);
+ int (*set_cac)(struct wl1271 *wl, struct wl12xx_vif *wlvif,
+ bool start);
+ int (*dfs_master_restart)(struct wl1271 *wl, struct wl12xx_vif *wlvif);
};
enum wlcore_partitions {
@@ -460,6 +465,9 @@ struct wl1271 {
/* HW HT (11n) capabilities */
struct ieee80211_sta_ht_cap ht_cap[WLCORE_NUM_BANDS];
+ /* the current dfs region */
+ enum nl80211_dfs_regions dfs_region;
+
/* size of the private FW status data */
size_t fw_status_len;
size_t fw_status_priv_len;
diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h
index 0e52556044d9..3396ce5a934d 100644
--- a/drivers/net/wireless/ti/wlcore/wlcore_i.h
+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h
@@ -251,6 +251,7 @@ enum wl12xx_vif_flags {
WLVIF_FLAG_AP_PROBE_RESP_SET,
WLVIF_FLAG_IN_USE,
WLVIF_FLAG_ACTIVE,
+ WLVIF_FLAG_BEACON_DISABLED,
};
struct wl12xx_vif;
@@ -434,6 +435,8 @@ struct wl12xx_vif {
bool wmm_enabled;
+ bool radar_enabled;
+
/* Rx Streaming */
struct work_struct rx_streaming_enable_work;
struct work_struct rx_streaming_disable_work;
@@ -463,6 +466,10 @@ struct wl12xx_vif {
/* work for canceling ROC after pending auth reply */
struct delayed_work pending_auth_complete_work;
+ /* update rate conrol */
+ enum ieee80211_sta_rx_bandwidth rc_update_bw;
+ struct work_struct rc_update_work;
+
/*
* total freed FW packets on the link.
* For STA this holds the PN of the link to the AP.
diff --git a/drivers/net/xen-netback/common.h b/drivers/net/xen-netback/common.h
index 5f1fda44882b..589fa256256b 100644
--- a/drivers/net/xen-netback/common.h
+++ b/drivers/net/xen-netback/common.h
@@ -251,7 +251,6 @@ struct xenvif {
struct xenvif_rx_cb {
unsigned long expires;
int meta_slots_used;
- bool full_coalesce;
};
#define XENVIF_RX_CB(skb) ((struct xenvif_rx_cb *)(skb)->cb)
diff --git a/drivers/net/xen-netback/interface.c b/drivers/net/xen-netback/interface.c
index 9259a732e8a4..f38227afe099 100644
--- a/drivers/net/xen-netback/interface.c
+++ b/drivers/net/xen-netback/interface.c
@@ -80,7 +80,7 @@ static irqreturn_t xenvif_tx_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-int xenvif_poll(struct napi_struct *napi, int budget)
+static int xenvif_poll(struct napi_struct *napi, int budget)
{
struct xenvif_queue *queue =
container_of(napi, struct xenvif_queue, napi);
@@ -483,9 +483,8 @@ int xenvif_init_queue(struct xenvif_queue *queue)
* better enable it. The long term solution would be to use just a
* bunch of valid page descriptors, without dependency on ballooning
*/
- err = alloc_xenballooned_pages(MAX_PENDING_REQS,
- queue->mmap_pages,
- false);
+ err = gnttab_alloc_pages(MAX_PENDING_REQS,
+ queue->mmap_pages);
if (err) {
netdev_err(queue->vif->dev, "Could not reserve mmap_pages\n");
return -ENOMEM;
@@ -578,6 +577,7 @@ int xenvif_connect(struct xenvif_queue *queue, unsigned long tx_ring_ref,
goto err_rx_unbind;
}
queue->task = task;
+ get_task_struct(task);
task = kthread_create(xenvif_dealloc_kthread,
(void *)queue, "%s-dealloc", queue->name);
@@ -634,6 +634,7 @@ void xenvif_disconnect(struct xenvif *vif)
if (queue->task) {
kthread_stop(queue->task);
+ put_task_struct(queue->task);
queue->task = NULL;
}
@@ -662,7 +663,7 @@ void xenvif_disconnect(struct xenvif *vif)
*/
void xenvif_deinit_queue(struct xenvif_queue *queue)
{
- free_xenballooned_pages(MAX_PENDING_REQS, queue->mmap_pages);
+ gnttab_free_pages(MAX_PENDING_REQS, queue->mmap_pages);
}
void xenvif_free(struct xenvif *vif)
diff --git a/drivers/net/xen-netback/netback.c b/drivers/net/xen-netback/netback.c
index 908e65e9b821..f7a31d2cb3f1 100644
--- a/drivers/net/xen-netback/netback.c
+++ b/drivers/net/xen-netback/netback.c
@@ -233,51 +233,6 @@ static void xenvif_rx_queue_drop_expired(struct xenvif_queue *queue)
}
}
-/*
- * Returns true if we should start a new receive buffer instead of
- * adding 'size' bytes to a buffer which currently contains 'offset'
- * bytes.
- */
-static bool start_new_rx_buffer(int offset, unsigned long size, int head,
- bool full_coalesce)
-{
- /* simple case: we have completely filled the current buffer. */
- if (offset == MAX_BUFFER_OFFSET)
- return true;
-
- /*
- * complex case: start a fresh buffer if the current frag
- * would overflow the current buffer but only if:
- * (i) this frag would fit completely in the next buffer
- * and (ii) there is already some data in the current buffer
- * and (iii) this is not the head buffer.
- * and (iv) there is no need to fully utilize the buffers
- *
- * Where:
- * - (i) stops us splitting a frag into two copies
- * unless the frag is too large for a single buffer.
- * - (ii) stops us from leaving a buffer pointlessly empty.
- * - (iii) stops us leaving the first buffer
- * empty. Strictly speaking this is already covered
- * by (ii) but is explicitly checked because
- * netfront relies on the first buffer being
- * non-empty and can crash otherwise.
- * - (iv) is needed for skbs which can use up more than MAX_SKB_FRAGS
- * slot
- *
- * This means we will effectively linearise small
- * frags but do not needlessly split large buffers
- * into multiple copies tend to give large frags their
- * own buffers as before.
- */
- BUG_ON(size > MAX_BUFFER_OFFSET);
- if ((offset + size > MAX_BUFFER_OFFSET) && offset && !head &&
- !full_coalesce)
- return true;
-
- return false;
-}
-
struct netrx_pending_operations {
unsigned copy_prod, copy_cons;
unsigned meta_prod, meta_cons;
@@ -314,9 +269,7 @@ static struct xenvif_rx_meta *get_next_rx_buffer(struct xenvif_queue *queue,
static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb,
struct netrx_pending_operations *npo,
struct page *page, unsigned long size,
- unsigned long offset, int *head,
- struct xenvif_queue *foreign_queue,
- grant_ref_t foreign_gref)
+ unsigned long offset, int *head)
{
struct gnttab_copy *copy_gop;
struct xenvif_rx_meta *meta;
@@ -333,27 +286,18 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb
offset &= ~PAGE_MASK;
while (size > 0) {
+ struct xen_page_foreign *foreign;
+
BUG_ON(offset >= PAGE_SIZE);
BUG_ON(npo->copy_off > MAX_BUFFER_OFFSET);
- bytes = PAGE_SIZE - offset;
+ if (npo->copy_off == MAX_BUFFER_OFFSET)
+ meta = get_next_rx_buffer(queue, npo);
+ bytes = PAGE_SIZE - offset;
if (bytes > size)
bytes = size;
- if (start_new_rx_buffer(npo->copy_off,
- bytes,
- *head,
- XENVIF_RX_CB(skb)->full_coalesce)) {
- /*
- * Netfront requires there to be some data in the head
- * buffer.
- */
- BUG_ON(*head);
-
- meta = get_next_rx_buffer(queue, npo);
- }
-
if (npo->copy_off + bytes > MAX_BUFFER_OFFSET)
bytes = MAX_BUFFER_OFFSET - npo->copy_off;
@@ -361,9 +305,10 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb
copy_gop->flags = GNTCOPY_dest_gref;
copy_gop->len = bytes;
- if (foreign_queue) {
- copy_gop->source.domid = foreign_queue->vif->domid;
- copy_gop->source.u.ref = foreign_gref;
+ foreign = xen_page_foreign(page);
+ if (foreign) {
+ copy_gop->source.domid = foreign->domid;
+ copy_gop->source.u.ref = foreign->gref;
copy_gop->flags |= GNTCOPY_source_gref;
} else {
copy_gop->source.domid = DOMID_SELF;
@@ -406,35 +351,6 @@ static void xenvif_gop_frag_copy(struct xenvif_queue *queue, struct sk_buff *skb
}
/*
- * Find the grant ref for a given frag in a chain of struct ubuf_info's
- * skb: the skb itself
- * i: the frag's number
- * ubuf: a pointer to an element in the chain. It should not be NULL
- *
- * Returns a pointer to the element in the chain where the page were found. If
- * not found, returns NULL.
- * See the definition of callback_struct in common.h for more details about
- * the chain.
- */
-static const struct ubuf_info *xenvif_find_gref(const struct sk_buff *const skb,
- const int i,
- const struct ubuf_info *ubuf)
-{
- struct xenvif_queue *foreign_queue = ubuf_to_queue(ubuf);
-
- do {
- u16 pending_idx = ubuf->desc;
-
- if (skb_shinfo(skb)->frags[i].page.p ==
- foreign_queue->mmap_pages[pending_idx])
- break;
- ubuf = (struct ubuf_info *) ubuf->ctx;
- } while (ubuf);
-
- return ubuf;
-}
-
-/*
* Prepare an SKB to be transmitted to the frontend.
*
* This function is responsible for allocating grant operations, meta
@@ -459,8 +375,6 @@ static int xenvif_gop_skb(struct sk_buff *skb,
int head = 1;
int old_meta_prod;
int gso_type;
- const struct ubuf_info *ubuf = skb_shinfo(skb)->destructor_arg;
- const struct ubuf_info *const head_ubuf = ubuf;
old_meta_prod = npo->meta_prod;
@@ -507,68 +421,16 @@ static int xenvif_gop_skb(struct sk_buff *skb,
len = skb_tail_pointer(skb) - data;
xenvif_gop_frag_copy(queue, skb, npo,
- virt_to_page(data), len, offset, &head,
- NULL,
- 0);
+ virt_to_page(data), len, offset, &head);
data += len;
}
for (i = 0; i < nr_frags; i++) {
- /* This variable also signals whether foreign_gref has a real
- * value or not.
- */
- struct xenvif_queue *foreign_queue = NULL;
- grant_ref_t foreign_gref;
-
- if ((skb_shinfo(skb)->tx_flags & SKBTX_DEV_ZEROCOPY) &&
- (ubuf->callback == &xenvif_zerocopy_callback)) {
- const struct ubuf_info *const startpoint = ubuf;
-
- /* Ideally ubuf points to the chain element which
- * belongs to this frag. Or if frags were removed from
- * the beginning, then shortly before it.
- */
- ubuf = xenvif_find_gref(skb, i, ubuf);
-
- /* Try again from the beginning of the list, if we
- * haven't tried from there. This only makes sense in
- * the unlikely event of reordering the original frags.
- * For injected local pages it's an unnecessary second
- * run.
- */
- if (unlikely(!ubuf) && startpoint != head_ubuf)
- ubuf = xenvif_find_gref(skb, i, head_ubuf);
-
- if (likely(ubuf)) {
- u16 pending_idx = ubuf->desc;
-
- foreign_queue = ubuf_to_queue(ubuf);
- foreign_gref =
- foreign_queue->pending_tx_info[pending_idx].req.gref;
- /* Just a safety measure. If this was the last
- * element on the list, the for loop will
- * iterate again if a local page were added to
- * the end. Using head_ubuf here prevents the
- * second search on the chain. Or the original
- * frags changed order, but that's less likely.
- * In any way, ubuf shouldn't be NULL.
- */
- ubuf = ubuf->ctx ?
- (struct ubuf_info *) ubuf->ctx :
- head_ubuf;
- } else
- /* This frag was a local page, added to the
- * array after the skb left netback.
- */
- ubuf = head_ubuf;
- }
xenvif_gop_frag_copy(queue, skb, npo,
skb_frag_page(&skb_shinfo(skb)->frags[i]),
skb_frag_size(&skb_shinfo(skb)->frags[i]),
skb_shinfo(skb)->frags[i].page_offset,
- &head,
- foreign_queue,
- foreign_queue ? foreign_gref : UINT_MAX);
+ &head);
}
return npo->meta_prod - old_meta_prod;
@@ -652,60 +514,15 @@ static void xenvif_rx_action(struct xenvif_queue *queue)
while (xenvif_rx_ring_slots_available(queue, XEN_NETBK_RX_SLOTS_MAX)
&& (skb = xenvif_rx_dequeue(queue)) != NULL) {
- RING_IDX max_slots_needed;
RING_IDX old_req_cons;
RING_IDX ring_slots_used;
- int i;
queue->last_rx_time = jiffies;
- /* We need a cheap worse case estimate for the number of
- * slots we'll use.
- */
-
- max_slots_needed = DIV_ROUND_UP(offset_in_page(skb->data) +
- skb_headlen(skb),
- PAGE_SIZE);
- for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
- unsigned int size;
- unsigned int offset;
-
- size = skb_frag_size(&skb_shinfo(skb)->frags[i]);
- offset = skb_shinfo(skb)->frags[i].page_offset;
-
- /* For a worse-case estimate we need to factor in
- * the fragment page offset as this will affect the
- * number of times xenvif_gop_frag_copy() will
- * call start_new_rx_buffer().
- */
- max_slots_needed += DIV_ROUND_UP(offset + size,
- PAGE_SIZE);
- }
-
- /* To avoid the estimate becoming too pessimal for some
- * frontends that limit posted rx requests, cap the estimate
- * at MAX_SKB_FRAGS. In this case netback will fully coalesce
- * the skb into the provided slots.
- */
- if (max_slots_needed > MAX_SKB_FRAGS) {
- max_slots_needed = MAX_SKB_FRAGS;
- XENVIF_RX_CB(skb)->full_coalesce = true;
- } else {
- XENVIF_RX_CB(skb)->full_coalesce = false;
- }
-
- /* We may need one more slot for GSO metadata */
- if (skb_is_gso(skb) &&
- (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4 ||
- skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6))
- max_slots_needed++;
-
old_req_cons = queue->rx.req_cons;
XENVIF_RX_CB(skb)->meta_slots_used = xenvif_gop_skb(skb, &npo, queue);
ring_slots_used = queue->rx.req_cons - old_req_cons;
- BUG_ON(ring_slots_used > max_slots_needed);
-
__skb_queue_tail(&rxq, skb);
}
@@ -1241,12 +1058,6 @@ static void xenvif_fill_frags(struct xenvif_queue *queue, struct sk_buff *skb)
/* Take an extra reference to offset network stack's put_page */
get_page(queue->mmap_pages[pending_idx]);
}
- /* FIXME: __skb_fill_page_desc set this to true because page->pfmemalloc
- * overlaps with "index", and "mapping" is not set. I think mapping
- * should be set. If delivered to local stack, it would drop this
- * skb in sk_filter unless the socket has the right to use it.
- */
- skb->pfmemalloc = false;
}
static int xenvif_get_extras(struct xenvif_queue *queue,
@@ -2109,8 +1920,7 @@ int xenvif_kthread_guest_rx(void *data)
*/
if (unlikely(vif->disabled && queue->id == 0)) {
xenvif_carrier_off(vif);
- xenvif_rx_queue_purge(queue);
- continue;
+ break;
}
if (!skb_queue_empty(&queue->rx_queue))
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d8c10764f130..e9b960f0ff32 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -142,10 +142,6 @@ struct netfront_queue {
struct sk_buff *rx_skbs[NET_RX_RING_SIZE];
grant_ref_t gref_rx_head;
grant_ref_t grant_rx_ref[NET_RX_RING_SIZE];
-
- unsigned long rx_pfn_array[NET_RX_RING_SIZE];
- struct multicall_entry rx_mcl[NET_RX_RING_SIZE+1];
- struct mmu_update rx_mmu[NET_RX_RING_SIZE];
};
struct netfront_info {
@@ -223,11 +219,7 @@ static grant_ref_t xennet_get_rx_ref(struct netfront_queue *queue,
}
#ifdef CONFIG_SYSFS
-static int xennet_sysfs_addif(struct net_device *netdev);
-static void xennet_sysfs_delif(struct net_device *netdev);
-#else /* !CONFIG_SYSFS */
-#define xennet_sysfs_addif(dev) (0)
-#define xennet_sysfs_delif(dev) do { } while (0)
+static const struct attribute_group xennet_dev_group;
#endif
static bool xennet_can_sg(struct net_device *dev)
@@ -424,109 +416,68 @@ static void xennet_tx_buf_gc(struct netfront_queue *queue)
xennet_maybe_wake_tx(queue);
}
-static void xennet_make_frags(struct sk_buff *skb, struct netfront_queue *queue,
- struct xen_netif_tx_request *tx)
+static struct xen_netif_tx_request *xennet_make_one_txreq(
+ struct netfront_queue *queue, struct sk_buff *skb,
+ struct page *page, unsigned int offset, unsigned int len)
{
- char *data = skb->data;
- unsigned long mfn;
- RING_IDX prod = queue->tx.req_prod_pvt;
- int frags = skb_shinfo(skb)->nr_frags;
- unsigned int offset = offset_in_page(data);
- unsigned int len = skb_headlen(skb);
unsigned int id;
+ struct xen_netif_tx_request *tx;
grant_ref_t ref;
- int i;
- /* While the header overlaps a page boundary (including being
- larger than a page), split it it into page-sized chunks. */
- while (len > PAGE_SIZE - offset) {
- tx->size = PAGE_SIZE - offset;
- tx->flags |= XEN_NETTXF_more_data;
- len -= tx->size;
- data += tx->size;
- offset = 0;
+ len = min_t(unsigned int, PAGE_SIZE - offset, len);
- id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
- queue->tx_skbs[id].skb = skb_get(skb);
- tx = RING_GET_REQUEST(&queue->tx, prod++);
- tx->id = id;
- ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
- BUG_ON((signed short)ref < 0);
+ id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
+ tx = RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++);
+ ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
+ BUG_ON((signed short)ref < 0);
- mfn = virt_to_mfn(data);
- gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id,
- mfn, GNTMAP_readonly);
+ gnttab_grant_foreign_access_ref(ref, queue->info->xbdev->otherend_id,
+ page_to_mfn(page), GNTMAP_readonly);
- queue->grant_tx_page[id] = virt_to_page(data);
- tx->gref = queue->grant_tx_ref[id] = ref;
- tx->offset = offset;
- tx->size = len;
- tx->flags = 0;
- }
+ queue->tx_skbs[id].skb = skb;
+ queue->grant_tx_page[id] = page;
+ queue->grant_tx_ref[id] = ref;
- /* Grant backend access to each skb fragment page. */
- for (i = 0; i < frags; i++) {
- skb_frag_t *frag = skb_shinfo(skb)->frags + i;
- struct page *page = skb_frag_page(frag);
+ tx->id = id;
+ tx->gref = ref;
+ tx->offset = offset;
+ tx->size = len;
+ tx->flags = 0;
- len = skb_frag_size(frag);
- offset = frag->page_offset;
+ return tx;
+}
- /* Skip unused frames from start of page */
- page += offset >> PAGE_SHIFT;
- offset &= ~PAGE_MASK;
+static struct xen_netif_tx_request *xennet_make_txreqs(
+ struct netfront_queue *queue, struct xen_netif_tx_request *tx,
+ struct sk_buff *skb, struct page *page,
+ unsigned int offset, unsigned int len)
+{
+ /* Skip unused frames from start of page */
+ page += offset >> PAGE_SHIFT;
+ offset &= ~PAGE_MASK;
- while (len > 0) {
- unsigned long bytes;
-
- bytes = PAGE_SIZE - offset;
- if (bytes > len)
- bytes = len;
-
- tx->flags |= XEN_NETTXF_more_data;
-
- id = get_id_from_freelist(&queue->tx_skb_freelist,
- queue->tx_skbs);
- queue->tx_skbs[id].skb = skb_get(skb);
- tx = RING_GET_REQUEST(&queue->tx, prod++);
- tx->id = id;
- ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
- BUG_ON((signed short)ref < 0);
-
- mfn = pfn_to_mfn(page_to_pfn(page));
- gnttab_grant_foreign_access_ref(ref,
- queue->info->xbdev->otherend_id,
- mfn, GNTMAP_readonly);
-
- queue->grant_tx_page[id] = page;
- tx->gref = queue->grant_tx_ref[id] = ref;
- tx->offset = offset;
- tx->size = bytes;
- tx->flags = 0;
-
- offset += bytes;
- len -= bytes;
-
- /* Next frame */
- if (offset == PAGE_SIZE && len) {
- BUG_ON(!PageCompound(page));
- page++;
- offset = 0;
- }
- }
+ while (len) {
+ tx->flags |= XEN_NETTXF_more_data;
+ tx = xennet_make_one_txreq(queue, skb_get(skb),
+ page, offset, len);
+ page++;
+ offset = 0;
+ len -= tx->size;
}
- queue->tx.req_prod_pvt = prod;
+ return tx;
}
/*
- * Count how many ring slots are required to send the frags of this
- * skb. Each frag might be a compound page.
+ * Count how many ring slots are required to send this skb. Each frag
+ * might be a compound page.
*/
-static int xennet_count_skb_frag_slots(struct sk_buff *skb)
+static int xennet_count_skb_slots(struct sk_buff *skb)
{
int i, frags = skb_shinfo(skb)->nr_frags;
- int pages = 0;
+ int pages;
+
+ pages = PFN_UP(offset_in_page(skb->data) + skb_headlen(skb));
for (i = 0; i < frags; i++) {
skb_frag_t *frag = skb_shinfo(skb)->frags + i;
@@ -562,18 +513,15 @@ static u16 xennet_select_queue(struct net_device *dev, struct sk_buff *skb,
static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- unsigned short id;
struct netfront_info *np = netdev_priv(dev);
struct netfront_stats *tx_stats = this_cpu_ptr(np->tx_stats);
- struct xen_netif_tx_request *tx;
- char *data = skb->data;
- RING_IDX i;
- grant_ref_t ref;
- unsigned long mfn;
+ struct xen_netif_tx_request *tx, *first_tx;
+ unsigned int i;
int notify;
int slots;
- unsigned int offset = offset_in_page(data);
- unsigned int len = skb_headlen(skb);
+ struct page *page;
+ unsigned int offset;
+ unsigned int len;
unsigned long flags;
struct netfront_queue *queue = NULL;
unsigned int num_queues = dev->real_num_tx_queues;
@@ -596,18 +544,18 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto drop;
}
- slots = DIV_ROUND_UP(offset + len, PAGE_SIZE) +
- xennet_count_skb_frag_slots(skb);
+ slots = xennet_count_skb_slots(skb);
if (unlikely(slots > MAX_SKB_FRAGS + 1)) {
net_dbg_ratelimited("xennet: skb rides the rocket: %d slots, %d bytes\n",
slots, skb->len);
if (skb_linearize(skb))
goto drop;
- data = skb->data;
- offset = offset_in_page(data);
- len = skb_headlen(skb);
}
+ page = virt_to_page(skb->data);
+ offset = offset_in_page(skb->data);
+ len = skb_headlen(skb);
+
spin_lock_irqsave(&queue->tx_lock, flags);
if (unlikely(!netif_carrier_ok(dev) ||
@@ -617,25 +565,13 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
goto drop;
}
- i = queue->tx.req_prod_pvt;
-
- id = get_id_from_freelist(&queue->tx_skb_freelist, queue->tx_skbs);
- queue->tx_skbs[id].skb = skb;
-
- tx = RING_GET_REQUEST(&queue->tx, i);
+ /* First request for the linear area. */
+ first_tx = tx = xennet_make_one_txreq(queue, skb,
+ page, offset, len);
+ page++;
+ offset = 0;
+ len -= tx->size;
- tx->id = id;
- ref = gnttab_claim_grant_reference(&queue->gref_tx_head);
- BUG_ON((signed short)ref < 0);
- mfn = virt_to_mfn(data);
- gnttab_grant_foreign_access_ref(
- ref, queue->info->xbdev->otherend_id, mfn, GNTMAP_readonly);
- queue->grant_tx_page[id] = virt_to_page(data);
- tx->gref = queue->grant_tx_ref[id] = ref;
- tx->offset = offset;
- tx->size = len;
-
- tx->flags = 0;
if (skb->ip_summed == CHECKSUM_PARTIAL)
/* local packet? */
tx->flags |= XEN_NETTXF_csum_blank | XEN_NETTXF_data_validated;
@@ -643,11 +579,12 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
/* remote but checksummed. */
tx->flags |= XEN_NETTXF_data_validated;
+ /* Optional extra info after the first request. */
if (skb_shinfo(skb)->gso_size) {
struct xen_netif_extra_info *gso;
gso = (struct xen_netif_extra_info *)
- RING_GET_REQUEST(&queue->tx, ++i);
+ RING_GET_REQUEST(&queue->tx, queue->tx.req_prod_pvt++);
tx->flags |= XEN_NETTXF_extra_info;
@@ -662,10 +599,19 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
gso->flags = 0;
}
- queue->tx.req_prod_pvt = i + 1;
+ /* Requests for the rest of the linear area. */
+ tx = xennet_make_txreqs(queue, tx, skb, page, offset, len);
+
+ /* Requests for all the frags. */
+ for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+ skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
+ tx = xennet_make_txreqs(queue, tx, skb,
+ skb_frag_page(frag), frag->page_offset,
+ skb_frag_size(frag));
+ }
- xennet_make_frags(skb, queue, tx);
- tx->size = skb->len;
+ /* First request has the packet length. */
+ first_tx->size = skb->len;
RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&queue->tx, notify);
if (notify)
@@ -1367,20 +1313,15 @@ static int netfront_probe(struct xenbus_device *dev,
info = netdev_priv(netdev);
dev_set_drvdata(&dev->dev, info);
-
+#ifdef CONFIG_SYSFS
+ info->netdev->sysfs_groups[0] = &xennet_dev_group;
+#endif
err = register_netdev(info->netdev);
if (err) {
pr_warn("%s: register_netdev err=%d\n", __func__, err);
goto fail;
}
- err = xennet_sysfs_addif(info->netdev);
- if (err) {
- unregister_netdev(info->netdev);
- pr_warn("%s: add sysfs failed err=%d\n", __func__, err);
- goto fail;
- }
-
return 0;
fail:
@@ -2144,39 +2085,20 @@ static ssize_t store_rxbuf(struct device *dev,
return len;
}
-static struct device_attribute xennet_attrs[] = {
- __ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf),
- __ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf),
- __ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL),
-};
-
-static int xennet_sysfs_addif(struct net_device *netdev)
-{
- int i;
- int err;
-
- for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++) {
- err = device_create_file(&netdev->dev,
- &xennet_attrs[i]);
- if (err)
- goto fail;
- }
- return 0;
-
- fail:
- while (--i >= 0)
- device_remove_file(&netdev->dev, &xennet_attrs[i]);
- return err;
-}
-
-static void xennet_sysfs_delif(struct net_device *netdev)
-{
- int i;
+static DEVICE_ATTR(rxbuf_min, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf);
+static DEVICE_ATTR(rxbuf_max, S_IRUGO|S_IWUSR, show_rxbuf, store_rxbuf);
+static DEVICE_ATTR(rxbuf_cur, S_IRUGO, show_rxbuf, NULL);
- for (i = 0; i < ARRAY_SIZE(xennet_attrs); i++)
- device_remove_file(&netdev->dev, &xennet_attrs[i]);
-}
+static struct attribute *xennet_dev_attrs[] = {
+ &dev_attr_rxbuf_min.attr,
+ &dev_attr_rxbuf_max.attr,
+ &dev_attr_rxbuf_cur.attr,
+ NULL
+};
+static const struct attribute_group xennet_dev_group = {
+ .attrs = xennet_dev_attrs
+};
#endif /* CONFIG_SYSFS */
static int xennet_remove(struct xenbus_device *dev)
@@ -2190,8 +2112,6 @@ static int xennet_remove(struct xenbus_device *dev)
xennet_disconnect_backend(info);
- xennet_sysfs_delif(info->netdev);
-
unregister_netdev(info->netdev);
for (i = 0; i < num_queues; ++i) {
diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c
index 963a4a5dc88e..f454dc68cc03 100644
--- a/drivers/nfc/microread/microread.c
+++ b/drivers/nfc/microread/microread.c
@@ -557,10 +557,11 @@ exit:
pr_err("Failed to handle discovered target err=%d\n", r);
}
-static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate,
+static int microread_event_received(struct nfc_hci_dev *hdev, u8 pipe,
u8 event, struct sk_buff *skb)
{
int r;
+ u8 gate = hdev->pipes[pipe].gate;
u8 mode;
pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c
index fc02e8d6a193..cdde745b96bd 100644
--- a/drivers/nfc/pn544/i2c.c
+++ b/drivers/nfc/pn544/i2c.c
@@ -24,11 +24,13 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
+#include <linux/acpi.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
#include <linux/firmware.h>
+#include <linux/gpio/consumer.h>
#include <linux/platform_data/pn544.h>
#include <asm/unaligned.h>
@@ -41,6 +43,11 @@
#define PN544_I2C_FRAME_HEADROOM 1
#define PN544_I2C_FRAME_TAILROOM 2
+/* GPIO names */
+#define PN544_GPIO_NAME_IRQ "pn544_irq"
+#define PN544_GPIO_NAME_FW "pn544_fw"
+#define PN544_GPIO_NAME_EN "pn544_en"
+
/* framing in HCI mode */
#define PN544_HCI_I2C_LLC_LEN 1
#define PN544_HCI_I2C_LLC_CRC 2
@@ -58,6 +65,13 @@ static struct i2c_device_id pn544_hci_i2c_id_table[] = {
MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
+static const struct acpi_device_id pn544_hci_i2c_acpi_match[] = {
+ {"NXP5440", 0},
+ {}
+};
+
+MODULE_DEVICE_TABLE(acpi, pn544_hci_i2c_acpi_match);
+
#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
/*
@@ -195,18 +209,19 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
/* Disable fw download */
- gpio_set_value(phy->gpio_fw, 0);
+ gpio_set_value_cansleep(phy->gpio_fw, 0);
for (polarity = 0; polarity < 2; polarity++) {
phy->en_polarity = polarity;
retry = 3;
while (retry--) {
/* power off */
- gpio_set_value(phy->gpio_en, !phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_en,
+ !phy->en_polarity);
usleep_range(10000, 15000);
/* power on */
- gpio_set_value(phy->gpio_en, phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
/* send reset */
@@ -225,13 +240,14 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
"Could not detect nfc_en polarity, fallback to active high\n");
out:
- gpio_set_value(phy->gpio_en, !phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
}
static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode)
{
- gpio_set_value(phy->gpio_fw, run_mode == PN544_FW_MODE ? 1 : 0);
- gpio_set_value(phy->gpio_en, phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_fw,
+ run_mode == PN544_FW_MODE ? 1 : 0);
+ gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
phy->run_mode = run_mode;
@@ -254,14 +270,14 @@ static void pn544_hci_i2c_disable(void *phy_id)
{
struct pn544_i2c_phy *phy = phy_id;
- gpio_set_value(phy->gpio_fw, 0);
- gpio_set_value(phy->gpio_en, !phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_fw, 0);
+ gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
usleep_range(10000, 15000);
- gpio_set_value(phy->gpio_en, phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
- gpio_set_value(phy->gpio_en, !phy->en_polarity);
+ gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
usleep_range(10000, 15000);
phy->powered = 0;
@@ -859,6 +875,90 @@ exit_state_wait_secure_write_answer:
}
}
+static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
+{
+ struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
+ const struct acpi_device_id *id;
+ struct gpio_desc *gpiod_en, *gpiod_irq, *gpiod_fw;
+ struct device *dev;
+ int ret;
+
+ if (!client)
+ return -EINVAL;
+
+ dev = &client->dev;
+
+ /* Match the struct device against a given list of ACPI IDs */
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+
+ if (!id)
+ return -ENODEV;
+
+ /* Get EN GPIO from ACPI */
+ gpiod_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1);
+ if (IS_ERR(gpiod_en)) {
+ nfc_err(dev,
+ "Unable to get EN GPIO\n");
+ return -ENODEV;
+ }
+
+ phy->gpio_en = desc_to_gpio(gpiod_en);
+
+ /* Configuration EN GPIO */
+ ret = gpiod_direction_output(gpiod_en, 0);
+ if (ret) {
+ nfc_err(dev, "Fail EN pin direction\n");
+ return ret;
+ }
+
+ /* Get FW GPIO from ACPI */
+ gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2);
+ if (IS_ERR(gpiod_fw)) {
+ nfc_err(dev,
+ "Unable to get FW GPIO\n");
+ return -ENODEV;
+ }
+
+ phy->gpio_fw = desc_to_gpio(gpiod_fw);
+
+ /* Configuration FW GPIO */
+ ret = gpiod_direction_output(gpiod_fw, 0);
+ if (ret) {
+ nfc_err(dev, "Fail FW pin direction\n");
+ return ret;
+ }
+
+ /* Get IRQ GPIO */
+ gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0);
+ if (IS_ERR(gpiod_irq)) {
+ nfc_err(dev,
+ "Unable to get IRQ GPIO\n");
+ return -ENODEV;
+ }
+
+ phy->gpio_irq = desc_to_gpio(gpiod_irq);
+
+ /* Configure IRQ GPIO */
+ ret = gpiod_direction_input(gpiod_irq);
+ if (ret) {
+ nfc_err(dev, "Fail IRQ pin direction\n");
+ return ret;
+ }
+
+ /* Map the pin to an IRQ */
+ ret = gpiod_to_irq(gpiod_irq);
+ if (ret < 0) {
+ nfc_err(dev, "Fail pin IRQ mapping\n");
+ return ret;
+ }
+
+ nfc_info(dev, "GPIO resource, no:%d irq:%d\n",
+ desc_to_gpio(gpiod_irq), ret);
+ client->irq = ret;
+
+ return 0;
+}
+
#ifdef CONFIG_OF
static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
@@ -884,7 +984,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
phy->gpio_en = ret;
/* Configuration of EN GPIO */
- ret = gpio_request(phy->gpio_en, "pn544_en");
+ ret = gpio_request(phy->gpio_en, PN544_GPIO_NAME_EN);
if (ret) {
nfc_err(&client->dev, "Fail EN pin\n");
goto err_dt;
@@ -906,7 +1006,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
phy->gpio_fw = ret;
/* Configuration of FW GPIO */
- ret = gpio_request(phy->gpio_fw, "pn544_fw");
+ ret = gpio_request(phy->gpio_fw, PN544_GPIO_NAME_FW);
if (ret) {
nfc_err(&client->dev, "Fail FW pin\n");
goto err_gpio_en;
@@ -1001,6 +1101,14 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ);
+ /* Using ACPI */
+ } else if (ACPI_HANDLE(&client->dev)) {
+ r = pn544_hci_i2c_acpi_request_resources(client);
+ if (r) {
+ nfc_err(&client->dev,
+ "Cannot get ACPI data\n");
+ return r;
+ }
} else {
nfc_err(&client->dev, "No platform data\n");
return -EINVAL;
@@ -1080,6 +1188,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
.name = PN544_HCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_pn544_i2c_match),
+ .acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match),
},
.probe = pn544_hci_i2c_probe,
.id_table = pn544_hci_i2c_id_table,
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index 9c8051d20cea..12e819ddf17a 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -724,10 +724,11 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
* <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing
*/
-static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
+static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb)
{
struct sk_buff *rgb_skb = NULL;
+ u8 gate = hdev->pipes[pipe].gate;
int r;
pr_debug("hci event %d\n", event);
diff --git a/drivers/nfc/st21nfca/Makefile b/drivers/nfc/st21nfca/Makefile
index 7d688f97aa27..97edab4bbdf8 100644
--- a/drivers/nfc/st21nfca/Makefile
+++ b/drivers/nfc/st21nfca/Makefile
@@ -2,7 +2,7 @@
# Makefile for ST21NFCA HCI based NFC driver
#
-st21nfca_hci-objs = st21nfca.o st21nfca_dep.o
+st21nfca_hci-objs = st21nfca.o st21nfca_dep.o st21nfca_se.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca_hci.o
st21nfca_i2c-objs = i2c.o
diff --git a/drivers/nfc/st21nfca/i2c.c b/drivers/nfc/st21nfca/i2c.c
index 05722085a59f..a32143951616 100644
--- a/drivers/nfc/st21nfca/i2c.c
+++ b/drivers/nfc/st21nfca/i2c.c
@@ -74,6 +74,8 @@ struct st21nfca_i2c_phy {
unsigned int gpio_ena;
unsigned int irq_polarity;
+ struct st21nfca_se_status se_status;
+
struct sk_buff *pending_skb;
int current_read_len;
/*
@@ -537,6 +539,11 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
phy->irq_polarity = irq_get_trigger_type(client->irq);
+ phy->se_status.is_ese_present =
+ of_property_read_bool(pp, "ese-present");
+ phy->se_status.is_uicc_present =
+ of_property_read_bool(pp, "uicc-present");
+
return 0;
}
#else
@@ -571,6 +578,9 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
}
}
+ phy->se_status.is_ese_present = pdata->is_ese_present;
+ phy->se_status.is_uicc_present = pdata->is_uicc_present;
+
return 0;
}
@@ -591,11 +601,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
phy = devm_kzalloc(&client->dev, sizeof(struct st21nfca_i2c_phy),
GFP_KERNEL);
- if (!phy) {
- nfc_err(&client->dev,
- "Cannot allocate memory for st21nfca i2c phy.\n");
+ if (!phy)
return -ENOMEM;
- }
phy->i2c_dev = client;
phy->pending_skb = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE * 2, GFP_KERNEL);
@@ -641,8 +648,11 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
}
return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
- ST21NFCA_FRAME_HEADROOM, ST21NFCA_FRAME_TAILROOM,
- ST21NFCA_HCI_LLC_MAX_PAYLOAD, &phy->hdev);
+ ST21NFCA_FRAME_HEADROOM,
+ ST21NFCA_FRAME_TAILROOM,
+ ST21NFCA_HCI_LLC_MAX_PAYLOAD,
+ &phy->hdev,
+ &phy->se_status);
}
static int st21nfca_hci_i2c_remove(struct i2c_client *client)
@@ -661,6 +671,7 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id of_st21nfca_i2c_match[] = {
+ { .compatible = "st,st21nfca-i2c", },
{ .compatible = "st,st21nfca_i2c", },
{}
};
diff --git a/drivers/nfc/st21nfca/st21nfca.c b/drivers/nfc/st21nfca/st21nfca.c
index f2596c8d68b0..24d3d240d5f4 100644
--- a/drivers/nfc/st21nfca/st21nfca.c
+++ b/drivers/nfc/st21nfca/st21nfca.c
@@ -23,6 +23,7 @@
#include "st21nfca.h"
#include "st21nfca_dep.h"
+#include "st21nfca_se.h"
#define DRIVER_DESC "HCI NFC driver for ST21NFCA"
@@ -62,7 +63,6 @@
#define ST21NFCA_RF_CARD_F_DATARATE 0x08
#define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01
-#define ST21NFCA_DEVICE_MGNT_GATE 0x01
#define ST21NFCA_DEVICE_MGNT_PIPE 0x02
#define ST21NFCA_DM_GETINFO 0x13
@@ -78,6 +78,11 @@
#define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/
+#define ST21NFCA_EVT_HOT_PLUG 0x03
+#define ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
+
+#define ST21NFCA_SE_TO_PIPES 2000
+
static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
static struct nfc_hci_gate st21nfca_gates[] = {
@@ -92,6 +97,10 @@ static struct nfc_hci_gate st21nfca_gates[] = {
{ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_RF_CARD_F_GATE, NFC_HCI_INVALID_PIPE},
+
+ /* Secure element pipes are created by secure element host */
+ {ST21NFCA_CONNECTIVITY_GATE, NFC_HCI_DO_NOT_CREATE_PIPE},
+ {ST21NFCA_APDU_READER_GATE, NFC_HCI_DO_NOT_CREATE_PIPE},
};
struct st21nfca_pipe_info {
@@ -118,18 +127,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
NFC_HCI_TERMINAL_HOST_ID, 0
};
- skb_pipe_list = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
- if (!skb_pipe_list) {
- r = -ENOMEM;
- goto free_list;
- }
-
- skb_pipe_info = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
- if (!skb_pipe_info) {
- r = -ENOMEM;
- goto free_info;
- }
-
/* On ST21NFCA device pipes number are dynamics
* A maximum of 16 pipes can be created at the same time
* If pipes are already created, hci_dev_up will fail.
@@ -148,7 +145,8 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
* Pipe can be closed and need to be open.
*/
r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
- ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE);
+ ST21NFCA_DEVICE_MGNT_GATE,
+ ST21NFCA_DEVICE_MGNT_PIPE);
if (r < 0)
goto free_info;
@@ -179,17 +177,28 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
* - destination gid (1byte)
*/
info = (struct st21nfca_pipe_info *) skb_pipe_info->data;
+ if (info->dst_gate_id == ST21NFCA_APDU_READER_GATE &&
+ info->src_host_id != ST21NFCA_ESE_HOST_ID) {
+ pr_err("Unexpected apdu_reader pipe on host %x\n",
+ info->src_host_id);
+ continue;
+ }
+
for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) &&
- (st21nfca_gates[j].gate != info->dst_gate_id);
- j++)
+ (st21nfca_gates[j].gate != info->dst_gate_id) ; j++)
;
if (j < ARRAY_SIZE(st21nfca_gates) &&
st21nfca_gates[j].gate == info->dst_gate_id &&
ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) {
st21nfca_gates[j].pipe = pipe_info[2];
+
hdev->gate2pipe[st21nfca_gates[j].gate] =
- st21nfca_gates[j].pipe;
+ st21nfca_gates[j].pipe;
+ hdev->pipes[st21nfca_gates[j].pipe].gate =
+ st21nfca_gates[j].gate;
+ hdev->pipes[st21nfca_gates[j].pipe].dest_host =
+ info->src_host_id;
}
}
@@ -199,7 +208,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
*/
if (skb_pipe_list->len + 3 < ARRAY_SIZE(st21nfca_gates)) {
for (i = skb_pipe_list->len + 3;
- i < ARRAY_SIZE(st21nfca_gates); i++) {
+ i < ARRAY_SIZE(st21nfca_gates) - 2; i++) {
r = nfc_hci_connect_gate(hdev,
NFC_HCI_HOST_CONTROLLER_ID,
st21nfca_gates[i].gate,
@@ -212,7 +221,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
free_info:
kfree_skb(skb_pipe_info);
-free_list:
kfree_skb(skb_pipe_list);
return r;
}
@@ -257,16 +265,33 @@ out:
static int st21nfca_hci_ready(struct nfc_hci_dev *hdev)
{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
struct sk_buff *skb;
u8 param;
+ u8 white_list[2];
+ int wl_size = 0;
int r;
- param = NFC_HCI_UICC_HOST_ID;
- r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
- NFC_HCI_ADMIN_WHITELIST, &param, 1);
- if (r < 0)
- return r;
+ if (info->se_status->is_ese_present &&
+ info->se_status->is_uicc_present) {
+ white_list[wl_size++] = NFC_HCI_UICC_HOST_ID;
+ white_list[wl_size++] = ST21NFCA_ESE_HOST_ID;
+ } else if (!info->se_status->is_ese_present &&
+ info->se_status->is_uicc_present) {
+ white_list[wl_size++] = NFC_HCI_UICC_HOST_ID;
+ } else if (info->se_status->is_ese_present &&
+ !info->se_status->is_uicc_present) {
+ white_list[wl_size++] = ST21NFCA_ESE_HOST_ID;
+ }
+
+ if (wl_size) {
+ r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
+ NFC_HCI_ADMIN_WHITELIST,
+ (u8 *) &white_list, wl_size);
+ if (r < 0)
+ return r;
+ }
/* Set NFC_MODE in device management gate to enable */
r = nfc_hci_get_param(hdev, ST21NFCA_DEVICE_MGNT_GATE,
@@ -274,8 +299,9 @@ static int st21nfca_hci_ready(struct nfc_hci_dev *hdev)
if (r < 0)
return r;
- if (skb->data[0] == 0) {
- kfree_skb(skb);
+ param = skb->data[0];
+ kfree_skb(skb);
+ if (param == 0) {
param = 1;
r = nfc_hci_set_param(hdev, ST21NFCA_DEVICE_MGNT_GATE,
@@ -417,9 +443,12 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev,
r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
ST21NFCA_RF_CARD_F_DATARATE,
param, 1);
- if (r < 0)
+ if (r < 0) {
+ kfree_skb(datarate_skb);
return r;
+ }
}
+ kfree_skb(datarate_skb);
/*
* Configure sens_res
@@ -673,15 +702,15 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
struct nfc_target *target)
{
int r;
- struct sk_buff *nfcid2_skb = NULL, *nfcid1_skb;
+ struct sk_buff *nfcid_skb = NULL;
if (gate == ST21NFCA_RF_READER_F_GATE) {
r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
- ST21NFCA_RF_READER_F_NFCID2, &nfcid2_skb);
+ ST21NFCA_RF_READER_F_NFCID2, &nfcid_skb);
if (r < 0)
goto exit;
- if (nfcid2_skb->len > NFC_SENSF_RES_MAXSIZE) {
+ if (nfcid_skb->len > NFC_SENSF_RES_MAXSIZE) {
r = -EPROTO;
goto exit;
}
@@ -693,11 +722,11 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
* - After the reception of SEL_RES with NFCIP-1 compliant bit
* set for type A frame NFCID1 will be updated
*/
- if (nfcid2_skb->len > 0) {
+ if (nfcid_skb->len > 0) {
/* P2P in type F */
- memcpy(target->sensf_res, nfcid2_skb->data,
- nfcid2_skb->len);
- target->sensf_res_len = nfcid2_skb->len;
+ memcpy(target->sensf_res, nfcid_skb->data,
+ nfcid_skb->len);
+ target->sensf_res_len = nfcid_skb->len;
/* NFC Forum Digital Protocol Table 44 */
if (target->sensf_res[0] == 0x01 &&
target->sensf_res[1] == 0xfe)
@@ -707,27 +736,28 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
target->supported_protocols =
NFC_PROTO_FELICA_MASK;
} else {
+ kfree_skb(nfcid_skb);
/* P2P in type A */
r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
ST21NFCA_RF_READER_F_NFCID1,
- &nfcid1_skb);
+ &nfcid_skb);
if (r < 0)
goto exit;
- if (nfcid1_skb->len > NFC_NFCID1_MAXSIZE) {
+ if (nfcid_skb->len > NFC_NFCID1_MAXSIZE) {
r = -EPROTO;
goto exit;
}
- memcpy(target->sensf_res, nfcid1_skb->data,
- nfcid1_skb->len);
- target->sensf_res_len = nfcid1_skb->len;
+ memcpy(target->sensf_res, nfcid_skb->data,
+ nfcid_skb->len);
+ target->sensf_res_len = nfcid_skb->len;
target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
}
target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE;
}
r = 1;
exit:
- kfree_skb(nfcid2_skb);
+ kfree_skb(nfcid_skb);
return r;
}
@@ -829,24 +859,82 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev,
}
}
+static void st21nfca_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
+ struct sk_buff *skb)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+ u8 gate = hdev->pipes[pipe].gate;
+
+ pr_debug("cmd: %x\n", cmd);
+
+ switch (cmd) {
+ case NFC_HCI_ANY_OPEN_PIPE:
+ if (gate != ST21NFCA_APDU_READER_GATE &&
+ hdev->pipes[pipe].dest_host != NFC_HCI_UICC_HOST_ID)
+ info->se_info.count_pipes++;
+
+ if (info->se_info.count_pipes == info->se_info.expected_pipes) {
+ del_timer_sync(&info->se_info.se_active_timer);
+ info->se_info.se_active = false;
+ info->se_info.count_pipes = 0;
+ complete(&info->se_info.req_completion);
+ }
+ break;
+ }
+}
+
+static int st21nfca_admin_event_received(struct nfc_hci_dev *hdev, u8 event,
+ struct sk_buff *skb)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ pr_debug("admin event: %x\n", event);
+
+ switch (event) {
+ case ST21NFCA_EVT_HOT_PLUG:
+ if (info->se_info.se_active) {
+ if (!ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
+ del_timer_sync(&info->se_info.se_active_timer);
+ info->se_info.se_active = false;
+ complete(&info->se_info.req_completion);
+ } else {
+ mod_timer(&info->se_info.se_active_timer,
+ jiffies +
+ msecs_to_jiffies(ST21NFCA_SE_TO_PIPES));
+ }
+ }
+ break;
+ }
+ kfree_skb(skb);
+ return 0;
+}
+
/*
* Returns:
* <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing
*/
-static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
+static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe,
u8 event, struct sk_buff *skb)
{
+ u8 gate = hdev->pipes[pipe].gate;
+ u8 host = hdev->pipes[pipe].dest_host;
+
pr_debug("hci event: %d gate: %x\n", event, gate);
switch (gate) {
+ case NFC_HCI_ADMIN_GATE:
+ return st21nfca_admin_event_received(hdev, event, skb);
case ST21NFCA_RF_CARD_F_GATE:
return st21nfca_dep_event_received(hdev, event, skb);
+ case ST21NFCA_CONNECTIVITY_GATE:
+ return st21nfca_connectivity_event_received(hdev, host,
+ event, skb);
+ case ST21NFCA_APDU_READER_GATE:
+ return st21nfca_apdu_reader_event_received(hdev, event, skb);
default:
return 1;
}
- kfree_skb(skb);
- return 0;
}
static struct nfc_hci_ops st21nfca_hci_ops = {
@@ -865,11 +953,17 @@ static struct nfc_hci_ops st21nfca_hci_ops = {
.tm_send = st21nfca_hci_tm_send,
.check_presence = st21nfca_hci_check_presence,
.event_received = st21nfca_hci_event_received,
+ .cmd_received = st21nfca_hci_cmd_received,
+ .discover_se = st21nfca_hci_discover_se,
+ .enable_se = st21nfca_hci_enable_se,
+ .disable_se = st21nfca_hci_disable_se,
+ .se_io = st21nfca_hci_se_io,
};
int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
char *llc_name, int phy_headroom, int phy_tailroom,
- int phy_payload, struct nfc_hci_dev **hdev)
+ int phy_payload, struct nfc_hci_dev **hdev,
+ struct st21nfca_se_status *se_status)
{
struct st21nfca_hci_info *info;
int r = 0;
@@ -929,6 +1023,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
goto err_alloc_hdev;
}
+ info->se_status = se_status;
+
nfc_hci_set_clientdata(info->hdev, info);
r = nfc_hci_register_device(info->hdev);
@@ -937,6 +1033,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
*hdev = info->hdev;
st21nfca_dep_init(info->hdev);
+ st21nfca_se_init(info->hdev);
return 0;
@@ -955,6 +1052,7 @@ void st21nfca_hci_remove(struct nfc_hci_dev *hdev)
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
st21nfca_dep_deinit(hdev);
+ st21nfca_se_deinit(hdev);
nfc_hci_unregister_device(hdev);
nfc_hci_free_device(hdev);
kfree(info);
diff --git a/drivers/nfc/st21nfca/st21nfca.h b/drivers/nfc/st21nfca/st21nfca.h
index 7c2a85292230..15a78d330a9f 100644
--- a/drivers/nfc/st21nfca/st21nfca.h
+++ b/drivers/nfc/st21nfca/st21nfca.h
@@ -20,6 +20,7 @@
#include <net/nfc/hci.h>
#include "st21nfca_dep.h"
+#include "st21nfca_se.h"
#define HCI_MODE 0
@@ -51,9 +52,15 @@
#define ST21NFCA_NUM_DEVICES 256
+struct st21nfca_se_status {
+ bool is_ese_present;
+ bool is_uicc_present;
+};
+
int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
char *llc_name, int phy_headroom, int phy_tailroom,
- int phy_payload, struct nfc_hci_dev **hdev);
+ int phy_payload, struct nfc_hci_dev **hdev,
+ struct st21nfca_se_status *se_status);
void st21nfca_hci_remove(struct nfc_hci_dev *hdev);
enum st21nfca_state {
@@ -66,6 +73,7 @@ struct st21nfca_hci_info {
void *phy_id;
struct nfc_hci_dev *hdev;
+ struct st21nfca_se_status *se_status;
enum st21nfca_state state;
@@ -76,13 +84,16 @@ struct st21nfca_hci_info {
void *async_cb_context;
struct st21nfca_dep_info dep_info;
+ struct st21nfca_se_info se_info;
};
/* Reader RF commands */
-#define ST21NFCA_WR_XCHG_DATA 0x10
-
-#define ST21NFCA_RF_READER_F_GATE 0x14
+#define ST21NFCA_WR_XCHG_DATA 0x10
-#define ST21NFCA_RF_CARD_F_GATE 0x24
+#define ST21NFCA_DEVICE_MGNT_GATE 0x01
+#define ST21NFCA_RF_READER_F_GATE 0x14
+#define ST21NFCA_RF_CARD_F_GATE 0x24
+#define ST21NFCA_APDU_READER_GATE 0xf0
+#define ST21NFCA_CONNECTIVITY_GATE 0x41
#endif /* __LOCAL_ST21NFCA_H_ */
diff --git a/drivers/nfc/st21nfca/st21nfca_se.c b/drivers/nfc/st21nfca/st21nfca_se.c
new file mode 100644
index 000000000000..bd13cac9c66a
--- /dev/null
+++ b/drivers/nfc/st21nfca/st21nfca_se.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics SAS. 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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 <net/nfc/hci.h>
+
+#include "st21nfca.h"
+#include "st21nfca_se.h"
+
+#define ST21NFCA_EVT_UICC_ACTIVATE 0x10
+#define ST21NFCA_EVT_UICC_DEACTIVATE 0x13
+#define ST21NFCA_EVT_SE_HARD_RESET 0x20
+#define ST21NFCA_EVT_SE_SOFT_RESET 0x11
+#define ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER 0x21
+#define ST21NFCA_EVT_SE_ACTIVATE 0x22
+#define ST21NFCA_EVT_SE_DEACTIVATE 0x23
+
+#define ST21NFCA_EVT_TRANSMIT_DATA 0x10
+#define ST21NFCA_EVT_WTX_REQUEST 0x11
+
+#define ST21NFCA_EVT_CONNECTIVITY 0x10
+#define ST21NFCA_EVT_TRANSACTION 0x12
+
+#define ST21NFCA_ESE_HOST_ID 0xc0
+
+#define ST21NFCA_SE_TO_HOT_PLUG 1000
+/* Connectivity pipe only */
+#define ST21NFCA_SE_COUNT_PIPE_UICC 0x01
+/* Connectivity + APDU Reader pipe */
+#define ST21NFCA_SE_COUNT_PIPE_EMBEDDED 0x02
+
+#define ST21NFCA_SE_MODE_OFF 0x00
+#define ST21NFCA_SE_MODE_ON 0x01
+
+#define ST21NFCA_PARAM_ATR 0x01
+#define ST21NFCA_ATR_DEFAULT_BWI 0x04
+
+/*
+ * WT = 2^BWI/10[s], convert into msecs and add a secure
+ * room by increasing by 2 this timeout
+ */
+#define ST21NFCA_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
+#define ST21NFCA_ATR_GET_Y_FROM_TD(x) (x >> 4)
+
+/* If TA is present bit 0 is set */
+#define ST21NFCA_ATR_TA_PRESENT(x) (x & 0x01)
+/* If TB is present bit 1 is set */
+#define ST21NFCA_ATR_TB_PRESENT(x) (x & 0x02)
+
+static u8 st21nfca_se_get_bwi(struct nfc_hci_dev *hdev)
+{
+ int i;
+ u8 td;
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */
+ for (i = 1; i < ST21NFCA_ESE_MAX_LENGTH; i++) {
+ td = ST21NFCA_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
+ if (ST21NFCA_ATR_TA_PRESENT(td))
+ i++;
+ if (ST21NFCA_ATR_TB_PRESENT(td)) {
+ i++;
+ return info->se_info.atr[i] >> 4;
+ }
+ }
+ return ST21NFCA_ATR_DEFAULT_BWI;
+}
+
+static void st21nfca_se_get_atr(struct nfc_hci_dev *hdev)
+{
+ int r;
+ struct sk_buff *skb;
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ r = nfc_hci_get_param(hdev, ST21NFCA_APDU_READER_GATE,
+ ST21NFCA_PARAM_ATR, &skb);
+ if (r < 0)
+ return;
+
+ if (skb->len <= ST21NFCA_ESE_MAX_LENGTH) {
+ memcpy(info->se_info.atr, skb->data, skb->len);
+ info->se_info.wt_timeout =
+ ST21NFCA_BWI_TO_TIMEOUT(st21nfca_se_get_bwi(hdev));
+ }
+ kfree_skb(skb);
+}
+
+static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx,
+ u8 state)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+ int r;
+ struct sk_buff *sk_host_list;
+ u8 se_event, host_id;
+
+ switch (se_idx) {
+ case NFC_HCI_UICC_HOST_ID:
+ se_event = (state == ST21NFCA_SE_MODE_ON ?
+ ST21NFCA_EVT_UICC_ACTIVATE :
+ ST21NFCA_EVT_UICC_DEACTIVATE);
+
+ info->se_info.count_pipes = 0;
+ info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_UICC;
+ break;
+ case ST21NFCA_ESE_HOST_ID:
+ se_event = (state == ST21NFCA_SE_MODE_ON ?
+ ST21NFCA_EVT_SE_ACTIVATE :
+ ST21NFCA_EVT_SE_DEACTIVATE);
+
+ info->se_info.count_pipes = 0;
+ info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_EMBEDDED;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Wait for an EVT_HOT_PLUG in order to
+ * retrieve a relevant host list.
+ */
+ reinit_completion(&info->se_info.req_completion);
+ r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, se_event,
+ NULL, 0);
+ if (r < 0)
+ return r;
+
+ mod_timer(&info->se_info.se_active_timer, jiffies +
+ msecs_to_jiffies(ST21NFCA_SE_TO_HOT_PLUG));
+ info->se_info.se_active = true;
+
+ /* Ignore return value and check in any case the host_list */
+ wait_for_completion_interruptible(&info->se_info.req_completion);
+
+ r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE,
+ NFC_HCI_ADMIN_HOST_LIST,
+ &sk_host_list);
+ if (r < 0)
+ return r;
+
+ host_id = sk_host_list->data[sk_host_list->len - 1];
+ kfree_skb(sk_host_list);
+
+ if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx)
+ return se_idx;
+ else if (state == ST21NFCA_SE_MODE_OFF && host_id != se_idx)
+ return se_idx;
+
+ return -1;
+}
+
+int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+ int se_count = 0;
+
+ if (info->se_status->is_uicc_present) {
+ nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC);
+ se_count++;
+ }
+
+ if (info->se_status->is_ese_present) {
+ nfc_add_se(hdev->ndev, ST21NFCA_ESE_HOST_ID, NFC_SE_EMBEDDED);
+ se_count++;
+ }
+
+ return !se_count;
+}
+EXPORT_SYMBOL(st21nfca_hci_discover_se);
+
+int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
+{
+ int r;
+
+ /*
+ * According to upper layer, se_idx == NFC_SE_UICC when
+ * info->se_status->is_uicc_enable is true should never happen.
+ * Same for eSE.
+ */
+ r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON);
+
+ if (r == ST21NFCA_ESE_HOST_ID) {
+ st21nfca_se_get_atr(hdev);
+ r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
+ ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0);
+ if (r < 0)
+ return r;
+ } else if (r < 0) {
+ /*
+ * The activation tentative failed, the secure element
+ * is not connected. Remove from the list.
+ */
+ nfc_remove_se(hdev->ndev, se_idx);
+ return r;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(st21nfca_hci_enable_se);
+
+int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
+{
+ int r;
+
+ /*
+ * According to upper layer, se_idx == NFC_SE_UICC when
+ * info->se_status->is_uicc_enable is true should never happen
+ * Same for eSE.
+ */
+ r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_OFF);
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+EXPORT_SYMBOL(st21nfca_hci_disable_se);
+
+int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
+ u8 *apdu, size_t apdu_length,
+ se_io_cb_t cb, void *cb_context)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ pr_debug("se_io %x\n", se_idx);
+
+ switch (se_idx) {
+ case ST21NFCA_ESE_HOST_ID:
+ info->se_info.cb = cb;
+ info->se_info.cb_context = cb_context;
+ mod_timer(&info->se_info.bwi_timer, jiffies +
+ msecs_to_jiffies(info->se_info.wt_timeout));
+ info->se_info.bwi_active = true;
+ return nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
+ ST21NFCA_EVT_TRANSMIT_DATA,
+ apdu, apdu_length);
+ default:
+ return -ENODEV;
+ }
+}
+EXPORT_SYMBOL(st21nfca_hci_se_io);
+
+static void st21nfca_se_wt_timeout(unsigned long data)
+{
+ /*
+ * No answer from the secure element
+ * within the defined timeout.
+ * Let's send a reset request as recovery procedure.
+ * According to the situation, we first try to send a software reset
+ * to the secure element. If the next command is still not
+ * answering in time, we send to the CLF a secure element hardware
+ * reset request.
+ */
+ /* hardware reset managed through VCC_UICC_OUT power supply */
+ u8 param = 0x01;
+ struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data;
+
+ pr_debug("\n");
+
+ info->se_info.bwi_active = false;
+
+ if (!info->se_info.xch_error) {
+ info->se_info.xch_error = true;
+ nfc_hci_send_event(info->hdev, ST21NFCA_APDU_READER_GATE,
+ ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0);
+ } else {
+ info->se_info.xch_error = false;
+ nfc_hci_send_event(info->hdev, ST21NFCA_DEVICE_MGNT_GATE,
+ ST21NFCA_EVT_SE_HARD_RESET, &param, 1);
+ }
+ info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
+}
+
+static void st21nfca_se_activation_timeout(unsigned long data)
+{
+ struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data;
+
+ pr_debug("\n");
+
+ info->se_info.se_active = false;
+
+ complete(&info->se_info.req_completion);
+}
+
+/*
+ * Returns:
+ * <= 0: driver handled the event, skb consumed
+ * 1: driver does not handle the event, please do standard processing
+ */
+int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
+ u8 event, struct sk_buff *skb)
+{
+ int r = 0;
+ struct device *dev = &hdev->ndev->dev;
+ struct nfc_evt_transaction *transaction;
+
+ pr_debug("connectivity gate event: %x\n", event);
+
+ switch (event) {
+ case ST21NFCA_EVT_CONNECTIVITY:
+ break;
+ case ST21NFCA_EVT_TRANSACTION:
+ if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
+ skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
+ return -EPROTO;
+
+ transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
+ skb->len - 2, GFP_KERNEL);
+
+ transaction->aid_len = skb->data[1];
+ memcpy(transaction->aid, &skb->data[2], skb->data[1]);
+
+ if (skb->data[transaction->aid_len + 2] !=
+ NFC_EVT_TRANSACTION_PARAMS_TAG)
+ return -EPROTO;
+
+ transaction->params_len = skb->data[transaction->aid_len + 3];
+ memcpy(transaction->params, skb->data +
+ transaction->aid_len + 4, transaction->params_len);
+
+ r = nfc_se_transaction(hdev->ndev, host, transaction);
+ break;
+ default:
+ return 1;
+ }
+ kfree_skb(skb);
+ return r;
+}
+EXPORT_SYMBOL(st21nfca_connectivity_event_received);
+
+int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
+ u8 event, struct sk_buff *skb)
+{
+ int r = 0;
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ pr_debug("apdu reader gate event: %x\n", event);
+
+ switch (event) {
+ case ST21NFCA_EVT_TRANSMIT_DATA:
+ del_timer_sync(&info->se_info.bwi_timer);
+ info->se_info.bwi_active = false;
+ r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE,
+ ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
+ if (r < 0)
+ goto exit;
+
+ info->se_info.cb(info->se_info.cb_context,
+ skb->data, skb->len, 0);
+ break;
+ case ST21NFCA_EVT_WTX_REQUEST:
+ mod_timer(&info->se_info.bwi_timer, jiffies +
+ msecs_to_jiffies(info->se_info.wt_timeout));
+ break;
+ }
+
+exit:
+ kfree_skb(skb);
+ return r;
+}
+EXPORT_SYMBOL(st21nfca_apdu_reader_event_received);
+
+void st21nfca_se_init(struct nfc_hci_dev *hdev)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ init_completion(&info->se_info.req_completion);
+ /* initialize timers */
+ init_timer(&info->se_info.bwi_timer);
+ info->se_info.bwi_timer.data = (unsigned long)info;
+ info->se_info.bwi_timer.function = st21nfca_se_wt_timeout;
+ info->se_info.bwi_active = false;
+
+ init_timer(&info->se_info.se_active_timer);
+ info->se_info.se_active_timer.data = (unsigned long)info;
+ info->se_info.se_active_timer.function = st21nfca_se_activation_timeout;
+ info->se_info.se_active = false;
+
+ info->se_info.count_pipes = 0;
+ info->se_info.expected_pipes = 0;
+
+ info->se_info.xch_error = false;
+
+ info->se_info.wt_timeout =
+ ST21NFCA_BWI_TO_TIMEOUT(ST21NFCA_ATR_DEFAULT_BWI);
+}
+EXPORT_SYMBOL(st21nfca_se_init);
+
+void st21nfca_se_deinit(struct nfc_hci_dev *hdev)
+{
+ struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+ if (info->se_info.bwi_active)
+ del_timer_sync(&info->se_info.bwi_timer);
+ if (info->se_info.se_active)
+ del_timer_sync(&info->se_info.se_active_timer);
+
+ info->se_info.bwi_active = false;
+ info->se_info.se_active = false;
+}
+EXPORT_SYMBOL(st21nfca_se_deinit);
diff --git a/drivers/nfc/st21nfca/st21nfca_se.h b/drivers/nfc/st21nfca/st21nfca_se.h
new file mode 100644
index 000000000000..b172cfcaeb90
--- /dev/null
+++ b/drivers/nfc/st21nfca/st21nfca_se.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics SAS. 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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 __ST21NFCA_SE_H
+#define __ST21NFCA_SE_H
+
+#include <linux/skbuff.h>
+#include <linux/workqueue.h>
+
+/*
+ * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
+ * sequence of at most 32 characters.
+ */
+#define ST21NFCA_ESE_MAX_LENGTH 33
+#define ST21NFCA_ESE_HOST_ID 0xc0
+
+struct st21nfca_se_info {
+ u8 atr[ST21NFCA_ESE_MAX_LENGTH];
+ struct completion req_completion;
+
+ struct timer_list bwi_timer;
+ int wt_timeout; /* in msecs */
+ bool bwi_active;
+
+ struct timer_list se_active_timer;
+ bool se_active;
+ int expected_pipes;
+ int count_pipes;
+
+ bool xch_error;
+
+ se_io_cb_t cb;
+ void *cb_context;
+};
+
+int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
+ u8 event, struct sk_buff *skb);
+int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
+ u8 event, struct sk_buff *skb);
+
+int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev);
+int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx);
+int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx);
+int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
+ u8 *apdu, size_t apdu_length,
+ se_io_cb_t cb, void *cb_context);
+
+void st21nfca_se_init(struct nfc_hci_dev *hdev);
+void st21nfca_se_deinit(struct nfc_hci_dev *hdev);
+#endif /* __ST21NFCA_SE_H */
diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile
index f4d835dd15f2..ce659a9e5a1a 100644
--- a/drivers/nfc/st21nfcb/Makefile
+++ b/drivers/nfc/st21nfcb/Makefile
@@ -2,7 +2,7 @@
# Makefile for ST21NFCB NCI based NFC driver
#
-st21nfcb_nci-objs = ndlc.o st21nfcb.o
+st21nfcb_nci-objs = ndlc.o st21nfcb.o st21nfcb_se.o
obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb_nci.o
st21nfcb_i2c-objs = i2c.o
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c
index 01ba865863ee..eb886932d972 100644
--- a/drivers/nfc/st21nfcb/i2c.c
+++ b/drivers/nfc/st21nfcb/i2c.c
@@ -199,7 +199,7 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
struct sk_buff *skb = NULL;
int r;
- if (!phy || irq != phy->i2c_dev->irq) {
+ if (!phy || !phy->ndlc || irq != phy->i2c_dev->irq) {
WARN_ON_ONCE(1);
return IRQ_NONE;
}
@@ -343,18 +343,22 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
return -ENODEV;
}
+ r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
+ ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM,
+ &phy->ndlc);
+ if (r < 0) {
+ nfc_err(&client->dev, "Unable to register ndlc layer\n");
+ return r;
+ }
+
r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
st21nfcb_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT,
ST21NFCB_NCI_DRIVER_NAME, phy);
- if (r < 0) {
+ if (r < 0)
nfc_err(&client->dev, "Unable to register IRQ handler\n");
- return r;
- }
- return ndlc_probe(phy, &i2c_phy_ops, &client->dev,
- ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM,
- &phy->ndlc);
+ return r;
}
static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
@@ -373,6 +377,7 @@ static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_OF
static const struct of_device_id of_st21nfcb_i2c_match[] = {
+ { .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", },
{}
};
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c
index bac50e805f1d..5fbf59d2138c 100644
--- a/drivers/nfc/st21nfcb/ndlc.c
+++ b/drivers/nfc/st21nfcb/ndlc.c
@@ -138,7 +138,7 @@ static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc)
default:
pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
kfree_skb(skb);
- break;
+ continue;
}
skb_queue_head(&ndlc->send_q, skb);
}
@@ -297,6 +297,5 @@ void ndlc_remove(struct llt_ndlc *ndlc)
skb_queue_purge(&ndlc->send_q);
st21nfcb_nci_remove(ndlc->ndev);
- kfree(ndlc);
}
EXPORT_SYMBOL(ndlc_remove);
diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c
index ea63d5877831..ca9871ab3fb3 100644
--- a/drivers/nfc/st21nfcb/st21nfcb.c
+++ b/drivers/nfc/st21nfcb/st21nfcb.c
@@ -22,6 +22,7 @@
#include <net/nfc/nci_core.h>
#include "st21nfcb.h"
+#include "st21nfcb_se.h"
#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
@@ -78,6 +79,13 @@ static struct nci_ops st21nfcb_nci_ops = {
.close = st21nfcb_nci_close,
.send = st21nfcb_nci_send,
.get_rfprotocol = st21nfcb_nci_get_rfprotocol,
+ .discover_se = st21nfcb_nci_discover_se,
+ .enable_se = st21nfcb_nci_enable_se,
+ .disable_se = st21nfcb_nci_disable_se,
+ .se_io = st21nfcb_nci_se_io,
+ .hci_load_session = st21nfcb_hci_load_session,
+ .hci_event_received = st21nfcb_hci_event_received,
+ .hci_cmd_received = st21nfcb_hci_cmd_received,
};
int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
@@ -114,9 +122,10 @@ int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
if (r) {
pr_err("Cannot register nfc device to nci core\n");
nci_free_device(ndlc->ndev);
+ return r;
}
- return r;
+ return st21nfcb_se_init(ndlc->ndev);
}
EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);
diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h
index ea58a56ad794..5ef8a58c9839 100644
--- a/drivers/nfc/st21nfcb/st21nfcb.h
+++ b/drivers/nfc/st21nfcb/st21nfcb.h
@@ -19,6 +19,7 @@
#ifndef __LOCAL_ST21NFCB_H_
#define __LOCAL_ST21NFCB_H_
+#include "st21nfcb_se.h"
#include "ndlc.h"
/* Define private flags: */
@@ -27,6 +28,7 @@
struct st21nfcb_nci_info {
struct llt_ndlc *ndlc;
unsigned long flags;
+ struct st21nfcb_se_info se_info;
};
void st21nfcb_nci_remove(struct nci_dev *ndev);
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.c b/drivers/nfc/st21nfcb/st21nfcb_se.c
new file mode 100644
index 000000000000..7c82e9d87a65
--- /dev/null
+++ b/drivers/nfc/st21nfcb/st21nfcb_se.c
@@ -0,0 +1,707 @@
+/*
+ * NCI based Driver for STMicroelectronics NFC Chip
+ *
+ * Copyright (C) 2014 STMicroelectronics SAS. 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <linux/delay.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+
+#include "st21nfcb.h"
+#include "st21nfcb_se.h"
+
+struct st21nfcb_pipe_info {
+ u8 pipe_state;
+ u8 src_host_id;
+ u8 src_gate_id;
+ u8 dst_host_id;
+ u8 dst_gate_id;
+} __packed;
+
+/* Hosts */
+#define ST21NFCB_HOST_CONTROLLER_ID 0x00
+#define ST21NFCB_TERMINAL_HOST_ID 0x01
+#define ST21NFCB_UICC_HOST_ID 0x02
+#define ST21NFCB_ESE_HOST_ID 0xc0
+
+/* Gates */
+#define ST21NFCB_DEVICE_MGNT_GATE 0x01
+#define ST21NFCB_APDU_READER_GATE 0xf0
+#define ST21NFCB_CONNECTIVITY_GATE 0x41
+
+/* Pipes */
+#define ST21NFCB_DEVICE_MGNT_PIPE 0x02
+
+/* Connectivity pipe only */
+#define ST21NFCB_SE_COUNT_PIPE_UICC 0x01
+/* Connectivity + APDU Reader pipe */
+#define ST21NFCB_SE_COUNT_PIPE_EMBEDDED 0x02
+
+#define ST21NFCB_SE_TO_HOT_PLUG 1000 /* msecs */
+#define ST21NFCB_SE_TO_PIPES 2000
+
+#define ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
+
+#define NCI_HCI_APDU_PARAM_ATR 0x01
+#define NCI_HCI_ADMIN_PARAM_SESSION_IDENTITY 0x01
+#define NCI_HCI_ADMIN_PARAM_WHITELIST 0x03
+#define NCI_HCI_ADMIN_PARAM_HOST_LIST 0x04
+
+#define ST21NFCB_EVT_SE_HARD_RESET 0x20
+#define ST21NFCB_EVT_TRANSMIT_DATA 0x10
+#define ST21NFCB_EVT_WTX_REQUEST 0x11
+#define ST21NFCB_EVT_SE_SOFT_RESET 0x11
+#define ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER 0x21
+#define ST21NFCB_EVT_HOT_PLUG 0x03
+
+#define ST21NFCB_SE_MODE_OFF 0x00
+#define ST21NFCB_SE_MODE_ON 0x01
+
+#define ST21NFCB_EVT_CONNECTIVITY 0x10
+#define ST21NFCB_EVT_TRANSACTION 0x12
+
+#define ST21NFCB_DM_GETINFO 0x13
+#define ST21NFCB_DM_GETINFO_PIPE_LIST 0x02
+#define ST21NFCB_DM_GETINFO_PIPE_INFO 0x01
+#define ST21NFCB_DM_PIPE_CREATED 0x02
+#define ST21NFCB_DM_PIPE_OPEN 0x04
+#define ST21NFCB_DM_RF_ACTIVE 0x80
+#define ST21NFCB_DM_DISCONNECT 0x30
+
+#define ST21NFCB_DM_IS_PIPE_OPEN(p) \
+ ((p & 0x0f) == (ST21NFCB_DM_PIPE_CREATED | ST21NFCB_DM_PIPE_OPEN))
+
+#define ST21NFCB_ATR_DEFAULT_BWI 0x04
+
+/*
+ * WT = 2^BWI/10[s], convert into msecs and add a secure
+ * room by increasing by 2 this timeout
+ */
+#define ST21NFCB_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
+#define ST21NFCB_ATR_GET_Y_FROM_TD(x) (x >> 4)
+
+/* If TA is present bit 0 is set */
+#define ST21NFCB_ATR_TA_PRESENT(x) (x & 0x01)
+/* If TB is present bit 1 is set */
+#define ST21NFCB_ATR_TB_PRESENT(x) (x & 0x02)
+
+#define ST21NFCB_NUM_DEVICES 256
+
+static DECLARE_BITMAP(dev_mask, ST21NFCB_NUM_DEVICES);
+
+/* Here are the mandatory pipe for st21nfcb */
+static struct nci_hci_gate st21nfcb_gates[] = {
+ {NCI_HCI_ADMIN_GATE, NCI_HCI_ADMIN_PIPE,
+ ST21NFCB_HOST_CONTROLLER_ID},
+ {NCI_HCI_LINK_MGMT_GATE, NCI_HCI_LINK_MGMT_PIPE,
+ ST21NFCB_HOST_CONTROLLER_ID},
+ {ST21NFCB_DEVICE_MGNT_GATE, ST21NFCB_DEVICE_MGNT_PIPE,
+ ST21NFCB_HOST_CONTROLLER_ID},
+
+ /* Secure element pipes are created by secure element host */
+ {ST21NFCB_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
+ ST21NFCB_HOST_CONTROLLER_ID},
+ {ST21NFCB_APDU_READER_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
+ ST21NFCB_HOST_CONTROLLER_ID},
+};
+
+static u8 st21nfcb_se_get_bwi(struct nci_dev *ndev)
+{
+ int i;
+ u8 td;
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+
+ /* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */
+ for (i = 1; i < ST21NFCB_ESE_MAX_LENGTH; i++) {
+ td = ST21NFCB_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
+ if (ST21NFCB_ATR_TA_PRESENT(td))
+ i++;
+ if (ST21NFCB_ATR_TB_PRESENT(td)) {
+ i++;
+ return info->se_info.atr[i] >> 4;
+ }
+ }
+ return ST21NFCB_ATR_DEFAULT_BWI;
+}
+
+static void st21nfcb_se_get_atr(struct nci_dev *ndev)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ int r;
+ struct sk_buff *skb;
+
+ r = nci_hci_get_param(ndev, ST21NFCB_APDU_READER_GATE,
+ NCI_HCI_APDU_PARAM_ATR, &skb);
+ if (r < 0)
+ return;
+
+ if (skb->len <= ST21NFCB_ESE_MAX_LENGTH) {
+ memcpy(info->se_info.atr, skb->data, skb->len);
+
+ info->se_info.wt_timeout =
+ ST21NFCB_BWI_TO_TIMEOUT(st21nfcb_se_get_bwi(ndev));
+ }
+ kfree_skb(skb);
+}
+
+int st21nfcb_hci_load_session(struct nci_dev *ndev)
+{
+ int i, j, r;
+ struct sk_buff *skb_pipe_list, *skb_pipe_info;
+ struct st21nfcb_pipe_info *dm_pipe_info;
+ u8 pipe_list[] = { ST21NFCB_DM_GETINFO_PIPE_LIST,
+ ST21NFCB_TERMINAL_HOST_ID};
+ u8 pipe_info[] = { ST21NFCB_DM_GETINFO_PIPE_INFO,
+ ST21NFCB_TERMINAL_HOST_ID, 0};
+
+ /* On ST21NFCB device pipes number are dynamics
+ * If pipes are already created, hci_dev_up will fail.
+ * Doing a clear all pipe is a bad idea because:
+ * - It does useless EEPROM cycling
+ * - It might cause issue for secure elements support
+ * (such as removing connectivity or APDU reader pipe)
+ * A better approach on ST21NFCB is to:
+ * - get a pipe list for each host.
+ * (eg: ST21NFCB_HOST_CONTROLLER_ID for now).
+ * (TODO Later on UICC HOST and eSE HOST)
+ * - get pipe information
+ * - match retrieved pipe list in st21nfcb_gates
+ * ST21NFCB_DEVICE_MGNT_GATE is a proprietary gate
+ * with ST21NFCB_DEVICE_MGNT_PIPE.
+ * Pipe can be closed and need to be open.
+ */
+ r = nci_hci_connect_gate(ndev, ST21NFCB_HOST_CONTROLLER_ID,
+ ST21NFCB_DEVICE_MGNT_GATE,
+ ST21NFCB_DEVICE_MGNT_PIPE);
+ if (r < 0)
+ goto free_info;
+
+ /* Get pipe list */
+ r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE,
+ ST21NFCB_DM_GETINFO, pipe_list, sizeof(pipe_list),
+ &skb_pipe_list);
+ if (r < 0)
+ goto free_info;
+
+ /* Complete the existing gate_pipe table */
+ for (i = 0; i < skb_pipe_list->len; i++) {
+ pipe_info[2] = skb_pipe_list->data[i];
+ r = nci_hci_send_cmd(ndev, ST21NFCB_DEVICE_MGNT_GATE,
+ ST21NFCB_DM_GETINFO, pipe_info,
+ sizeof(pipe_info), &skb_pipe_info);
+
+ if (r)
+ continue;
+
+ /*
+ * Match pipe ID and gate ID
+ * Output format from ST21NFC_DM_GETINFO is:
+ * - pipe state (1byte)
+ * - source hid (1byte)
+ * - source gid (1byte)
+ * - destination hid (1byte)
+ * - destination gid (1byte)
+ */
+ dm_pipe_info = (struct st21nfcb_pipe_info *)skb_pipe_info->data;
+ if (dm_pipe_info->dst_gate_id == ST21NFCB_APDU_READER_GATE &&
+ dm_pipe_info->src_host_id != ST21NFCB_ESE_HOST_ID) {
+ pr_err("Unexpected apdu_reader pipe on host %x\n",
+ dm_pipe_info->src_host_id);
+ continue;
+ }
+
+ for (j = 0; (j < ARRAY_SIZE(st21nfcb_gates)) &&
+ (st21nfcb_gates[j].gate != dm_pipe_info->dst_gate_id); j++)
+ ;
+
+ if (j < ARRAY_SIZE(st21nfcb_gates) &&
+ st21nfcb_gates[j].gate == dm_pipe_info->dst_gate_id &&
+ ST21NFCB_DM_IS_PIPE_OPEN(dm_pipe_info->pipe_state)) {
+ st21nfcb_gates[j].pipe = pipe_info[2];
+
+ ndev->hci_dev->gate2pipe[st21nfcb_gates[j].gate] =
+ st21nfcb_gates[j].pipe;
+ ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].gate =
+ st21nfcb_gates[j].gate;
+ ndev->hci_dev->pipes[st21nfcb_gates[j].pipe].host =
+ dm_pipe_info->src_host_id;
+ }
+ }
+
+ memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
+ sizeof(st21nfcb_gates));
+
+free_info:
+ kfree_skb(skb_pipe_info);
+ kfree_skb(skb_pipe_list);
+ return r;
+}
+EXPORT_SYMBOL_GPL(st21nfcb_hci_load_session);
+
+static void st21nfcb_hci_admin_event_received(struct nci_dev *ndev,
+ u8 event, struct sk_buff *skb)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+
+ switch (event) {
+ case ST21NFCB_EVT_HOT_PLUG:
+ if (info->se_info.se_active) {
+ if (!ST21NFCB_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
+ del_timer_sync(&info->se_info.se_active_timer);
+ info->se_info.se_active = false;
+ complete(&info->se_info.req_completion);
+ } else {
+ mod_timer(&info->se_info.se_active_timer,
+ jiffies +
+ msecs_to_jiffies(ST21NFCB_SE_TO_PIPES));
+ }
+ }
+ break;
+ }
+}
+
+static int st21nfcb_hci_apdu_reader_event_received(struct nci_dev *ndev,
+ u8 event,
+ struct sk_buff *skb)
+{
+ int r = 0;
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+
+ pr_debug("apdu reader gate event: %x\n", event);
+
+ switch (event) {
+ case ST21NFCB_EVT_TRANSMIT_DATA:
+ del_timer_sync(&info->se_info.bwi_timer);
+ info->se_info.bwi_active = false;
+ info->se_info.cb(info->se_info.cb_context,
+ skb->data, skb->len, 0);
+ break;
+ case ST21NFCB_EVT_WTX_REQUEST:
+ mod_timer(&info->se_info.bwi_timer, jiffies +
+ msecs_to_jiffies(info->se_info.wt_timeout));
+ break;
+ }
+
+ kfree_skb(skb);
+ return r;
+}
+
+/*
+ * Returns:
+ * <= 0: driver handled the event, skb consumed
+ * 1: driver does not handle the event, please do standard processing
+ */
+static int st21nfcb_hci_connectivity_event_received(struct nci_dev *ndev,
+ u8 host, u8 event,
+ struct sk_buff *skb)
+{
+ int r = 0;
+ struct device *dev = &ndev->nfc_dev->dev;
+ struct nfc_evt_transaction *transaction;
+
+ pr_debug("connectivity gate event: %x\n", event);
+
+ switch (event) {
+ case ST21NFCB_EVT_CONNECTIVITY:
+
+ break;
+ case ST21NFCB_EVT_TRANSACTION:
+ if (skb->len < NFC_MIN_AID_LENGTH + 2 &&
+ skb->data[0] != NFC_EVT_TRANSACTION_AID_TAG)
+ return -EPROTO;
+
+ transaction = (struct nfc_evt_transaction *)devm_kzalloc(dev,
+ skb->len - 2, GFP_KERNEL);
+
+ transaction->aid_len = skb->data[1];
+ memcpy(transaction->aid, &skb->data[2], skb->data[1]);
+
+ if (skb->data[transaction->aid_len + 2] !=
+ NFC_EVT_TRANSACTION_PARAMS_TAG)
+ return -EPROTO;
+
+ transaction->params_len = skb->data[transaction->aid_len + 3];
+ memcpy(transaction->params, skb->data +
+ transaction->aid_len + 4, transaction->params_len);
+
+ r = nfc_se_transaction(ndev->nfc_dev, host, transaction);
+ default:
+ return 1;
+ }
+ kfree_skb(skb);
+ return r;
+}
+
+void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
+ u8 event, struct sk_buff *skb)
+{
+ u8 gate = ndev->hci_dev->pipes[pipe].gate;
+ u8 host = ndev->hci_dev->pipes[pipe].host;
+
+ switch (gate) {
+ case NCI_HCI_ADMIN_GATE:
+ st21nfcb_hci_admin_event_received(ndev, event, skb);
+ break;
+ case ST21NFCB_APDU_READER_GATE:
+ st21nfcb_hci_apdu_reader_event_received(ndev, event, skb);
+ break;
+ case ST21NFCB_CONNECTIVITY_GATE:
+ st21nfcb_hci_connectivity_event_received(ndev, host, event,
+ skb);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(st21nfcb_hci_event_received);
+
+
+void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
+ struct sk_buff *skb)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ u8 gate = ndev->hci_dev->pipes[pipe].gate;
+
+ pr_debug("cmd: %x\n", cmd);
+
+ switch (cmd) {
+ case NCI_HCI_ANY_OPEN_PIPE:
+ if (gate != ST21NFCB_APDU_READER_GATE &&
+ ndev->hci_dev->pipes[pipe].host != ST21NFCB_UICC_HOST_ID)
+ ndev->hci_dev->count_pipes++;
+
+ if (ndev->hci_dev->count_pipes ==
+ ndev->hci_dev->expected_pipes) {
+ del_timer_sync(&info->se_info.se_active_timer);
+ info->se_info.se_active = false;
+ ndev->hci_dev->count_pipes = 0;
+ complete(&info->se_info.req_completion);
+ }
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(st21nfcb_hci_cmd_received);
+
+/*
+ * Remarks: On some early st21nfcb firmware, nci_nfcee_mode_set(0)
+ * is rejected
+ */
+static int st21nfcb_nci_control_se(struct nci_dev *ndev, u8 se_idx,
+ u8 state)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+ int r;
+ struct sk_buff *sk_host_list;
+ u8 host_id;
+
+ switch (se_idx) {
+ case ST21NFCB_UICC_HOST_ID:
+ ndev->hci_dev->count_pipes = 0;
+ ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_UICC;
+ break;
+ case ST21NFCB_ESE_HOST_ID:
+ ndev->hci_dev->count_pipes = 0;
+ ndev->hci_dev->expected_pipes = ST21NFCB_SE_COUNT_PIPE_EMBEDDED;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * Wait for an EVT_HOT_PLUG in order to
+ * retrieve a relevant host list.
+ */
+ reinit_completion(&info->se_info.req_completion);
+ r = nci_nfcee_mode_set(ndev, se_idx, NCI_NFCEE_ENABLE);
+ if (r != NCI_STATUS_OK)
+ return r;
+
+ mod_timer(&info->se_info.se_active_timer, jiffies +
+ msecs_to_jiffies(ST21NFCB_SE_TO_HOT_PLUG));
+ info->se_info.se_active = true;
+
+ /* Ignore return value and check in any case the host_list */
+ wait_for_completion_interruptible(&info->se_info.req_completion);
+
+ /* There might be some "collision" after receiving a HOT_PLUG event
+ * This may cause the CLF to not answer to the next hci command.
+ * There is no possible synchronization to prevent this.
+ * Adding a small delay is the only way to solve the issue.
+ */
+ usleep_range(3000, 5000);
+
+ r = nci_hci_get_param(ndev, NCI_HCI_ADMIN_GATE,
+ NCI_HCI_ADMIN_PARAM_HOST_LIST, &sk_host_list);
+ if (r != NCI_HCI_ANY_OK)
+ return r;
+
+ host_id = sk_host_list->data[sk_host_list->len - 1];
+ kfree_skb(sk_host_list);
+ if (state == ST21NFCB_SE_MODE_ON && host_id == se_idx)
+ return se_idx;
+ else if (state == ST21NFCB_SE_MODE_OFF && host_id != se_idx)
+ return se_idx;
+
+ return -1;
+}
+
+int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx)
+{
+ int r;
+
+ pr_debug("st21nfcb_nci_disable_se\n");
+
+ if (se_idx == NFC_SE_EMBEDDED) {
+ r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
+ ST21NFCB_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(st21nfcb_nci_disable_se);
+
+int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
+{
+ int r;
+
+ pr_debug("st21nfcb_nci_enable_se\n");
+
+ if (se_idx == ST21NFCB_HCI_HOST_ID_ESE) {
+ r = nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
+ ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(st21nfcb_nci_enable_se);
+
+static int st21nfcb_hci_network_init(struct nci_dev *ndev)
+{
+ struct core_conn_create_dest_spec_params *dest_params;
+ struct dest_spec_params spec_params;
+ struct nci_conn_info *conn_info;
+ int r, dev_num;
+
+ dest_params =
+ kzalloc(sizeof(struct core_conn_create_dest_spec_params) +
+ sizeof(struct dest_spec_params), GFP_KERNEL);
+ if (dest_params == NULL) {
+ r = -ENOMEM;
+ goto exit;
+ }
+
+ dest_params->type = NCI_DESTINATION_SPECIFIC_PARAM_NFCEE_TYPE;
+ dest_params->length = sizeof(struct dest_spec_params);
+ spec_params.id = ndev->hci_dev->nfcee_id;
+ spec_params.protocol = NCI_NFCEE_INTERFACE_HCI_ACCESS;
+ memcpy(dest_params->value, &spec_params, sizeof(struct dest_spec_params));
+ r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCEE, 1,
+ sizeof(struct core_conn_create_dest_spec_params) +
+ sizeof(struct dest_spec_params),
+ dest_params);
+ if (r != NCI_STATUS_OK)
+ goto free_dest_params;
+
+ conn_info = ndev->hci_dev->conn_info;
+ if (!conn_info)
+ goto free_dest_params;
+
+ memcpy(ndev->hci_dev->init_data.gates, st21nfcb_gates,
+ sizeof(st21nfcb_gates));
+
+ /*
+ * Session id must include the driver name + i2c bus addr
+ * persistent info to discriminate 2 identical chips
+ */
+ dev_num = find_first_zero_bit(dev_mask, ST21NFCB_NUM_DEVICES);
+ if (dev_num >= ST21NFCB_NUM_DEVICES) {
+ r = -ENODEV;
+ goto free_dest_params;
+ }
+
+ scnprintf(ndev->hci_dev->init_data.session_id,
+ sizeof(ndev->hci_dev->init_data.session_id),
+ "%s%2x", "ST21BH", dev_num);
+
+ r = nci_hci_dev_session_init(ndev);
+ if (r != NCI_HCI_ANY_OK)
+ goto exit;
+
+ r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id,
+ NCI_NFCEE_ENABLE);
+ if (r != NCI_STATUS_OK)
+ goto exit;
+
+ return 0;
+
+free_dest_params:
+ kfree(dest_params);
+
+exit:
+ return r;
+}
+
+int st21nfcb_nci_discover_se(struct nci_dev *ndev)
+{
+ u8 param[2];
+ int r;
+ int se_count = 0;
+
+ pr_debug("st21nfcb_nci_discover_se\n");
+
+ r = st21nfcb_hci_network_init(ndev);
+ if (r != 0)
+ return r;
+
+ param[0] = ST21NFCB_UICC_HOST_ID;
+ param[1] = ST21NFCB_HCI_HOST_ID_ESE;
+ r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
+ NCI_HCI_ADMIN_PARAM_WHITELIST,
+ param, sizeof(param));
+ if (r != NCI_HCI_ANY_OK)
+ return r;
+
+ r = st21nfcb_nci_control_se(ndev, ST21NFCB_UICC_HOST_ID,
+ ST21NFCB_SE_MODE_ON);
+ if (r == ST21NFCB_UICC_HOST_ID) {
+ nfc_add_se(ndev->nfc_dev, ST21NFCB_UICC_HOST_ID, NFC_SE_UICC);
+ se_count++;
+ }
+
+ /* Try to enable eSE in order to check availability */
+ r = st21nfcb_nci_control_se(ndev, ST21NFCB_HCI_HOST_ID_ESE,
+ ST21NFCB_SE_MODE_ON);
+ if (r == ST21NFCB_HCI_HOST_ID_ESE) {
+ nfc_add_se(ndev->nfc_dev, ST21NFCB_HCI_HOST_ID_ESE,
+ NFC_SE_EMBEDDED);
+ se_count++;
+ st21nfcb_se_get_atr(ndev);
+ }
+
+ return !se_count;
+}
+EXPORT_SYMBOL_GPL(st21nfcb_nci_discover_se);
+
+int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx,
+ u8 *apdu, size_t apdu_length,
+ se_io_cb_t cb, void *cb_context)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+
+ pr_debug("\n");
+
+ switch (se_idx) {
+ case ST21NFCB_HCI_HOST_ID_ESE:
+ info->se_info.cb = cb;
+ info->se_info.cb_context = cb_context;
+ mod_timer(&info->se_info.bwi_timer, jiffies +
+ msecs_to_jiffies(info->se_info.wt_timeout));
+ info->se_info.bwi_active = true;
+ return nci_hci_send_event(ndev, ST21NFCB_APDU_READER_GATE,
+ ST21NFCB_EVT_TRANSMIT_DATA, apdu,
+ apdu_length);
+ default:
+ return -ENODEV;
+ }
+}
+EXPORT_SYMBOL(st21nfcb_nci_se_io);
+
+static void st21nfcb_se_wt_timeout(unsigned long data)
+{
+ /*
+ * No answer from the secure element
+ * within the defined timeout.
+ * Let's send a reset request as recovery procedure.
+ * According to the situation, we first try to send a software reset
+ * to the secure element. If the next command is still not
+ * answering in time, we send to the CLF a secure element hardware
+ * reset request.
+ */
+ /* hardware reset managed through VCC_UICC_OUT power supply */
+ u8 param = 0x01;
+ struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data;
+
+ pr_debug("\n");
+
+ info->se_info.bwi_active = false;
+
+ if (!info->se_info.xch_error) {
+ info->se_info.xch_error = true;
+ nci_hci_send_event(info->ndlc->ndev, ST21NFCB_APDU_READER_GATE,
+ ST21NFCB_EVT_SE_SOFT_RESET, NULL, 0);
+ } else {
+ info->se_info.xch_error = false;
+ nci_hci_send_event(info->ndlc->ndev, ST21NFCB_DEVICE_MGNT_GATE,
+ ST21NFCB_EVT_SE_HARD_RESET, &param, 1);
+ }
+ info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
+}
+
+static void st21nfcb_se_activation_timeout(unsigned long data)
+{
+ struct st21nfcb_nci_info *info = (struct st21nfcb_nci_info *) data;
+
+ pr_debug("\n");
+
+ info->se_info.se_active = false;
+
+ complete(&info->se_info.req_completion);
+}
+
+int st21nfcb_se_init(struct nci_dev *ndev)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+
+ init_completion(&info->se_info.req_completion);
+ /* initialize timers */
+ init_timer(&info->se_info.bwi_timer);
+ info->se_info.bwi_timer.data = (unsigned long)info;
+ info->se_info.bwi_timer.function = st21nfcb_se_wt_timeout;
+ info->se_info.bwi_active = false;
+
+ init_timer(&info->se_info.se_active_timer);
+ info->se_info.se_active_timer.data = (unsigned long)info;
+ info->se_info.se_active_timer.function =
+ st21nfcb_se_activation_timeout;
+ info->se_info.se_active = false;
+
+ info->se_info.xch_error = false;
+
+ info->se_info.wt_timeout =
+ ST21NFCB_BWI_TO_TIMEOUT(ST21NFCB_ATR_DEFAULT_BWI);
+
+ return 0;
+}
+EXPORT_SYMBOL(st21nfcb_se_init);
+
+void st21nfcb_se_deinit(struct nci_dev *ndev)
+{
+ struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
+
+ if (info->se_info.bwi_active)
+ del_timer_sync(&info->se_info.bwi_timer);
+ if (info->se_info.se_active)
+ del_timer_sync(&info->se_info.se_active_timer);
+
+ info->se_info.se_active = false;
+ info->se_info.bwi_active = false;
+}
+EXPORT_SYMBOL(st21nfcb_se_deinit);
+
diff --git a/drivers/nfc/st21nfcb/st21nfcb_se.h b/drivers/nfc/st21nfcb/st21nfcb_se.h
new file mode 100644
index 000000000000..52a323872bea
--- /dev/null
+++ b/drivers/nfc/st21nfcb/st21nfcb_se.h
@@ -0,0 +1,61 @@
+/*
+ * NCI based Driver for STMicroelectronics NFC Chip
+ *
+ * Copyright (C) 2014 STMicroelectronics SAS. 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 that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU 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 __LOCAL_ST21NFCB_SE_H_
+#define __LOCAL_ST21NFCB_SE_H_
+
+/*
+ * ref ISO7816-3 chap 8.1. the initial character TS is followed by a
+ * sequence of at most 32 characters.
+ */
+#define ST21NFCB_ESE_MAX_LENGTH 33
+#define ST21NFCB_HCI_HOST_ID_ESE 0xc0
+
+struct st21nfcb_se_info {
+ u8 atr[ST21NFCB_ESE_MAX_LENGTH];
+ struct completion req_completion;
+
+ struct timer_list bwi_timer;
+ int wt_timeout; /* in msecs */
+ bool bwi_active;
+
+ struct timer_list se_active_timer;
+ bool se_active;
+
+ bool xch_error;
+
+ se_io_cb_t cb;
+ void *cb_context;
+};
+
+int st21nfcb_se_init(struct nci_dev *ndev);
+void st21nfcb_se_deinit(struct nci_dev *ndev);
+
+int st21nfcb_nci_discover_se(struct nci_dev *ndev);
+int st21nfcb_nci_enable_se(struct nci_dev *ndev, u32 se_idx);
+int st21nfcb_nci_disable_se(struct nci_dev *ndev, u32 se_idx);
+int st21nfcb_nci_se_io(struct nci_dev *ndev, u32 se_idx,
+ u8 *apdu, size_t apdu_length,
+ se_io_cb_t cb, void *cb_context);
+int st21nfcb_hci_load_session(struct nci_dev *ndev);
+void st21nfcb_hci_event_received(struct nci_dev *ndev, u8 pipe,
+ u8 event, struct sk_buff *skb);
+void st21nfcb_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
+ struct sk_buff *skb);
+
+
+#endif /* __LOCAL_ST21NFCB_NCI_H_ */
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index b5e0c873d4e1..38d1c51f58b1 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -10,7 +10,6 @@ menu "Device Tree and Open Firmware support"
config OF_UNITTEST
bool "Device Tree runtime unit tests"
depends on OF_IRQ && OF_EARLY_FLATTREE
- select OF_DYNAMIC
select OF_RESOLVE
help
This option builds in test cases for the device tree infrastructure
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 36536b6a8834..0a8aeb8523fe 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -1303,6 +1303,7 @@ int of_property_read_u64_array(const struct device_node *np,
}
return 0;
}
+EXPORT_SYMBOL_GPL(of_property_read_u64_array);
/**
* of_property_read_string - Find and read a string from a property
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index 510074226d57..3a896c9aeb74 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -762,7 +762,7 @@ static inline void early_init_dt_check_for_initrd(unsigned long node)
#ifdef CONFIG_SERIAL_EARLYCON
extern struct of_device_id __earlycon_of_table[];
-int __init early_init_dt_scan_chosen_serial(void)
+static int __init early_init_dt_scan_chosen_serial(void)
{
int offset;
const char *p;
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 88471d3d98cd..62426d81a4d6 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -140,6 +140,7 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
unsigned char busno, unsigned char bus_max,
struct list_head *resources, resource_size_t *io_base)
{
+ struct resource_entry *window;
struct resource *res;
struct resource *bus_range;
struct of_pci_range range;
@@ -225,6 +226,8 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
conversion_failed:
kfree(res);
parse_failed:
+ resource_list_for_each_entry(window, resources)
+ kfree(window->res);
pci_free_resource_list(resources);
return err;
}
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c
index dc566b38645f..726ebe792813 100644
--- a/drivers/of/of_reserved_mem.c
+++ b/drivers/of/of_reserved_mem.c
@@ -265,6 +265,7 @@ int of_reserved_mem_device_init(struct device *dev)
return ret;
}
+EXPORT_SYMBOL_GPL(of_reserved_mem_device_init);
/**
* of_reserved_mem_device_release() - release reserved memory device structures
@@ -289,3 +290,4 @@ void of_reserved_mem_device_release(struct device *dev)
rmem->ops->device_release(rmem, dev);
}
+EXPORT_SYMBOL_GPL(of_reserved_mem_device_release);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index b0d50d70a8a1..b189733a1539 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -526,6 +526,7 @@ static int of_platform_device_destroy(struct device *dev, void *data)
amba_device_unregister(to_amba_device(dev));
#endif
+ of_dma_deconfigure(dev);
of_node_clear_flag(dev->of_node, OF_POPULATED);
of_node_clear_flag(dev->of_node, OF_POPULATED_BUS);
return 0;
diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
index a2b687d5f324..244226cbb5a3 100644
--- a/drivers/of/unittest-data/tests-overlay.dtsi
+++ b/drivers/of/unittest-data/tests-overlay.dtsi
@@ -68,6 +68,48 @@
status = "disabled";
reg = <8>;
};
+
+ i2c-test-bus {
+ compatible = "selftest-i2c-bus";
+ status = "okay";
+ reg = <50>;
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ test-selftest12 {
+ reg = <8>;
+ compatible = "selftest-i2c-dev";
+ status = "disabled";
+ };
+
+ test-selftest13 {
+ reg = <9>;
+ compatible = "selftest-i2c-dev";
+ status = "okay";
+ };
+
+ test-selftest14 {
+ reg = <10>;
+ compatible = "selftest-i2c-mux";
+ status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ test-mux-dev {
+ reg = <32>;
+ compatible = "selftest-i2c-dev";
+ status = "okay";
+ };
+ };
+ };
+ };
};
};
@@ -231,5 +273,57 @@
};
};
};
+
+ /* test enable using absolute target path (i2c) */
+ overlay12 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest12";
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+
+ /* test disable using absolute target path (i2c) */
+ overlay13 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus/test-selftest13";
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+ };
+
+ /* test mux overlay */
+ overlay15 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/i2c-test-bus";
+ __overlay__ {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ test-selftest15 {
+ reg = <11>;
+ compatible = "selftest-i2c-mux";
+ status = "okay";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ test-mux-dev {
+ reg = <32>;
+ compatible = "selftest-i2c-dev";
+ status = "okay";
+ };
+ };
+ };
+ };
+ };
+ };
+
};
};
diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
index 41a4a138f53b..0cf9a236d438 100644
--- a/drivers/of/unittest.c
+++ b/drivers/of/unittest.c
@@ -20,6 +20,9 @@
#include <linux/platform_device.h>
#include <linux/of_platform.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+
#include "of_private.h"
static struct selftest_results {
@@ -27,11 +30,6 @@ static struct selftest_results {
int failed;
} selftest_results;
-#define NO_OF_NODES 3
-static struct device_node *nodes[NO_OF_NODES];
-static int last_node_index;
-static bool selftest_live_tree;
-
#define selftest(result, fmt, ...) ({ \
bool failed = !(result); \
if (failed) { \
@@ -822,6 +820,7 @@ static void update_node_properties(struct device_node *np,
static int attach_node_and_children(struct device_node *np)
{
struct device_node *next, *dup, *child;
+ unsigned long flags;
dup = of_find_node_by_path(np->full_name);
if (dup) {
@@ -829,17 +828,19 @@ static int attach_node_and_children(struct device_node *np)
return 0;
}
- /* 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++] = np;
- }
-
child = np->child;
np->child = NULL;
- np->sibling = NULL;
- of_attach_node(np);
+
+ mutex_lock(&of_mutex);
+ raw_spin_lock_irqsave(&devtree_lock, flags);
+ np->sibling = np->parent->child;
+ np->parent->child = np;
+ of_node_clear_flag(np, OF_DETACHED);
+ raw_spin_unlock_irqrestore(&devtree_lock, flags);
+
+ __of_attach_node_sysfs(np);
+ mutex_unlock(&of_mutex);
+
while (child) {
next = child->sibling;
attach_node_and_children(child);
@@ -889,10 +890,7 @@ static int __init selftest_data_add(void)
}
if (!of_root) {
- /* enabling flag for removing nodes */
- selftest_live_tree = true;
of_root = selftest_data_node;
-
for_each_of_allnodes(np)
__of_attach_node_sysfs(np);
of_aliases = of_find_node_by_path("/aliases");
@@ -911,59 +909,6 @@ static int __init selftest_data_add(void)
return 0;
}
-/**
- * detach_node_and_children - detaches node
- * and its children from live tree
- *
- * @np: Node to detach from live tree
- */
-static void detach_node_and_children(struct device_node *np)
-{
- while (np->child)
- detach_node_and_children(np->child);
- of_detach_node(np);
-}
-
-/**
- * selftest_data_remove - removes the selftest data
- * nodes from the live tree
- */
-static void selftest_data_remove(void)
-{
- struct device_node *np;
- struct property *prop;
-
- if (selftest_live_tree) {
- of_node_put(of_aliases);
- of_node_put(of_chosen);
- of_aliases = NULL;
- of_chosen = NULL;
- for_each_child_of_node(of_root, np)
- detach_node_and_children(np);
- __of_detach_node_sysfs(of_root);
- of_root = NULL;
- return;
- }
-
- while (last_node_index-- > 0) {
- if (nodes[last_node_index]) {
- np = of_find_node_by_path(nodes[last_node_index]->full_name);
- if (np == nodes[last_node_index]) {
- if (of_aliases == np) {
- of_node_put(of_aliases);
- of_aliases = NULL;
- }
- detach_node_and_children(np);
- } else {
- for_each_property_of_node(np, prop) {
- if (strcmp(prop->name, "testcase-alias") == 0)
- of_remove_property(np, prop);
- }
- }
- }
- }
-}
-
#ifdef CONFIG_OF_OVERLAY
static int selftest_probe(struct platform_device *pdev)
@@ -1034,17 +979,94 @@ static int of_path_platform_device_exists(const char *path)
return pdev != NULL;
}
-static const char *selftest_path(int nr)
+#if IS_ENABLED(CONFIG_I2C)
+
+/* get the i2c client device instantiated at the path */
+static struct i2c_client *of_path_to_i2c_client(const char *path)
{
+ struct device_node *np;
+ struct i2c_client *client;
+
+ np = of_find_node_by_path(path);
+ if (np == NULL)
+ return NULL;
+
+ client = of_find_i2c_device_by_node(np);
+ of_node_put(np);
+
+ return client;
+}
+
+/* find out if a i2c client device exists at that path */
+static int of_path_i2c_client_exists(const char *path)
+{
+ struct i2c_client *client;
+
+ client = of_path_to_i2c_client(path);
+ if (client)
+ put_device(&client->dev);
+ return client != NULL;
+}
+#else
+static int of_path_i2c_client_exists(const char *path)
+{
+ return 0;
+}
+#endif
+
+enum overlay_type {
+ PDEV_OVERLAY,
+ I2C_OVERLAY
+};
+
+static int of_path_device_type_exists(const char *path,
+ enum overlay_type ovtype)
+{
+ switch (ovtype) {
+ case PDEV_OVERLAY:
+ return of_path_platform_device_exists(path);
+ case I2C_OVERLAY:
+ return of_path_i2c_client_exists(path);
+ }
+ return 0;
+}
+
+static const char *selftest_path(int nr, enum overlay_type ovtype)
+{
+ const char *base;
static char buf[256];
- snprintf(buf, sizeof(buf) - 1,
- "/testcase-data/overlay-node/test-bus/test-selftest%d", nr);
+ switch (ovtype) {
+ case PDEV_OVERLAY:
+ base = "/testcase-data/overlay-node/test-bus";
+ break;
+ case I2C_OVERLAY:
+ base = "/testcase-data/overlay-node/test-bus/i2c-test-bus";
+ break;
+ default:
+ buf[0] = '\0';
+ return buf;
+ }
+ snprintf(buf, sizeof(buf) - 1, "%s/test-selftest%d", base, nr);
buf[sizeof(buf) - 1] = '\0';
-
return buf;
}
+static int of_selftest_device_exists(int selftest_nr, enum overlay_type ovtype)
+{
+ const char *path;
+
+ path = selftest_path(selftest_nr, ovtype);
+
+ switch (ovtype) {
+ case PDEV_OVERLAY:
+ return of_path_platform_device_exists(path);
+ case I2C_OVERLAY:
+ return of_path_i2c_client_exists(path);
+ }
+ return 0;
+}
+
static const char *overlay_path(int nr)
{
static char buf[256];
@@ -1093,16 +1115,15 @@ out:
/* 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 before, int after, enum overlay_type ovtype)
{
int ret;
/* selftest device must not be in before state */
- if (of_path_platform_device_exists(selftest_path(selftest_nr))
- != before) {
+ if (of_selftest_device_exists(selftest_nr, ovtype) != before) {
selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
overlay_path(overlay_nr),
- selftest_path(selftest_nr),
+ selftest_path(selftest_nr, ovtype),
!before ? "enabled" : "disabled");
return -EINVAL;
}
@@ -1114,11 +1135,10 @@ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
}
/* selftest device must be to set to after state */
- if (of_path_platform_device_exists(selftest_path(selftest_nr))
- != after) {
+ if (of_selftest_device_exists(selftest_nr, ovtype) != after) {
selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
overlay_path(overlay_nr),
- selftest_path(selftest_nr),
+ selftest_path(selftest_nr, ovtype),
!after ? "enabled" : "disabled");
return -EINVAL;
}
@@ -1128,16 +1148,16 @@ static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
/* 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 selftest_nr, int before, int after,
+ enum overlay_type ovtype)
{
int ret, ov_id;
/* selftest device must be in before state */
- if (of_path_platform_device_exists(selftest_path(selftest_nr))
- != before) {
+ if (of_selftest_device_exists(selftest_nr, ovtype) != before) {
selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
overlay_path(overlay_nr),
- selftest_path(selftest_nr),
+ selftest_path(selftest_nr, ovtype),
!before ? "enabled" : "disabled");
return -EINVAL;
}
@@ -1150,11 +1170,10 @@ static int of_selftest_apply_revert_overlay_check(int overlay_nr,
}
/* selftest device must be in after state */
- if (of_path_platform_device_exists(selftest_path(selftest_nr))
- != after) {
+ if (of_selftest_device_exists(selftest_nr, ovtype) != after) {
selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
overlay_path(overlay_nr),
- selftest_path(selftest_nr),
+ selftest_path(selftest_nr, ovtype),
!after ? "enabled" : "disabled");
return -EINVAL;
}
@@ -1163,16 +1182,15 @@ static int of_selftest_apply_revert_overlay_check(int overlay_nr,
if (ret != 0) {
selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
overlay_path(overlay_nr),
- selftest_path(selftest_nr));
+ selftest_path(selftest_nr, ovtype));
return ret;
}
/* selftest device must be again in before state */
- if (of_path_platform_device_exists(selftest_path(selftest_nr))
- != before) {
+ if (of_selftest_device_exists(selftest_nr, PDEV_OVERLAY) != before) {
selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
overlay_path(overlay_nr),
- selftest_path(selftest_nr),
+ selftest_path(selftest_nr, ovtype),
!before ? "enabled" : "disabled");
return -EINVAL;
}
@@ -1186,7 +1204,7 @@ static void of_selftest_overlay_0(void)
int ret;
/* device should enable */
- ret = of_selftest_apply_overlay_check(0, 0, 0, 1);
+ ret = of_selftest_apply_overlay_check(0, 0, 0, 1, PDEV_OVERLAY);
if (ret != 0)
return;
@@ -1199,7 +1217,7 @@ static void of_selftest_overlay_1(void)
int ret;
/* device should disable */
- ret = of_selftest_apply_overlay_check(1, 1, 1, 0);
+ ret = of_selftest_apply_overlay_check(1, 1, 1, 0, PDEV_OVERLAY);
if (ret != 0)
return;
@@ -1212,7 +1230,7 @@ static void of_selftest_overlay_2(void)
int ret;
/* device should enable */
- ret = of_selftest_apply_overlay_check(2, 2, 0, 1);
+ ret = of_selftest_apply_overlay_check(2, 2, 0, 1, PDEV_OVERLAY);
if (ret != 0)
return;
@@ -1225,7 +1243,7 @@ static void of_selftest_overlay_3(void)
int ret;
/* device should disable */
- ret = of_selftest_apply_overlay_check(3, 3, 1, 0);
+ ret = of_selftest_apply_overlay_check(3, 3, 1, 0, PDEV_OVERLAY);
if (ret != 0)
return;
@@ -1238,7 +1256,7 @@ static void of_selftest_overlay_4(void)
int ret;
/* device should disable */
- ret = of_selftest_apply_overlay_check(4, 4, 0, 1);
+ ret = of_selftest_apply_overlay_check(4, 4, 0, 1, PDEV_OVERLAY);
if (ret != 0)
return;
@@ -1251,7 +1269,7 @@ static void of_selftest_overlay_5(void)
int ret;
/* device should disable */
- ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1);
+ ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1, PDEV_OVERLAY);
if (ret != 0)
return;
@@ -1268,12 +1286,12 @@ static void of_selftest_overlay_6(void)
/* selftest device must be in before state */
for (i = 0; i < 2; i++) {
- if (of_path_platform_device_exists(
- selftest_path(selftest_nr + i))
+ if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
!= before) {
selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
overlay_path(overlay_nr + i),
- selftest_path(selftest_nr + i),
+ selftest_path(selftest_nr + i,
+ PDEV_OVERLAY),
!before ? "enabled" : "disabled");
return;
}
@@ -1300,12 +1318,12 @@ static void of_selftest_overlay_6(void)
for (i = 0; i < 2; i++) {
/* selftest device must be in after state */
- if (of_path_platform_device_exists(
- selftest_path(selftest_nr + i))
+ if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
!= after) {
selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
overlay_path(overlay_nr + i),
- selftest_path(selftest_nr + i),
+ selftest_path(selftest_nr + i,
+ PDEV_OVERLAY),
!after ? "enabled" : "disabled");
return;
}
@@ -1316,19 +1334,20 @@ static void of_selftest_overlay_6(void)
if (ret != 0) {
selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
overlay_path(overlay_nr + i),
- selftest_path(selftest_nr + i));
+ selftest_path(selftest_nr + i,
+ PDEV_OVERLAY));
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))
+ if (of_selftest_device_exists(selftest_nr + i, PDEV_OVERLAY)
!= before) {
selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
overlay_path(overlay_nr + i),
- selftest_path(selftest_nr + i),
+ selftest_path(selftest_nr + i,
+ PDEV_OVERLAY),
!before ? "enabled" : "disabled");
return;
}
@@ -1370,7 +1389,8 @@ static void of_selftest_overlay_8(void)
if (ret == 0) {
selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
overlay_path(overlay_nr + 0),
- selftest_path(selftest_nr));
+ selftest_path(selftest_nr,
+ PDEV_OVERLAY));
return;
}
@@ -1380,7 +1400,8 @@ static void of_selftest_overlay_8(void)
if (ret != 0) {
selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
overlay_path(overlay_nr + i),
- selftest_path(selftest_nr));
+ selftest_path(selftest_nr,
+ PDEV_OVERLAY));
return;
}
}
@@ -1395,16 +1416,17 @@ static void of_selftest_overlay_10(void)
char *child_path;
/* device should disable */
- ret = of_selftest_apply_overlay_check(10, 10, 0, 1);
- if (selftest(ret == 0, "overlay test %d failed; overlay application\n", 10))
+ ret = of_selftest_apply_overlay_check(10, 10, 0, 1, PDEV_OVERLAY);
+ if (selftest(ret == 0,
+ "overlay test %d failed; overlay application\n", 10))
return;
child_path = kasprintf(GFP_KERNEL, "%s/test-selftest101",
- selftest_path(10));
+ selftest_path(10, PDEV_OVERLAY));
if (selftest(child_path, "overlay test %d failed; kasprintf\n", 10))
return;
- ret = of_path_platform_device_exists(child_path);
+ ret = of_path_device_type_exists(child_path, PDEV_OVERLAY);
kfree(child_path);
if (selftest(ret, "overlay test %d failed; no child device\n", 10))
return;
@@ -1416,11 +1438,331 @@ static void of_selftest_overlay_11(void)
int ret;
/* device should disable */
- ret = of_selftest_apply_revert_overlay_check(11, 11, 0, 1);
- if (selftest(ret == 0, "overlay test %d failed; overlay application\n", 11))
+ ret = of_selftest_apply_revert_overlay_check(11, 11, 0, 1,
+ PDEV_OVERLAY);
+ if (selftest(ret == 0,
+ "overlay test %d failed; overlay application\n", 11))
return;
}
+#if IS_ENABLED(CONFIG_I2C) && IS_ENABLED(CONFIG_OF_OVERLAY)
+
+struct selftest_i2c_bus_data {
+ struct platform_device *pdev;
+ struct i2c_adapter adap;
+};
+
+static int selftest_i2c_master_xfer(struct i2c_adapter *adap,
+ struct i2c_msg *msgs, int num)
+{
+ struct selftest_i2c_bus_data *std = i2c_get_adapdata(adap);
+
+ (void)std;
+
+ return num;
+}
+
+static u32 selftest_i2c_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
+}
+
+static const struct i2c_algorithm selftest_i2c_algo = {
+ .master_xfer = selftest_i2c_master_xfer,
+ .functionality = selftest_i2c_functionality,
+};
+
+static int selftest_i2c_bus_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct selftest_i2c_bus_data *std;
+ struct i2c_adapter *adap;
+ int ret;
+
+ 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);
+
+ std = devm_kzalloc(dev, sizeof(*std), GFP_KERNEL);
+ if (!std) {
+ dev_err(dev, "Failed to allocate selftest i2c data\n");
+ return -ENOMEM;
+ }
+
+ /* link them together */
+ std->pdev = pdev;
+ platform_set_drvdata(pdev, std);
+
+ adap = &std->adap;
+ i2c_set_adapdata(adap, std);
+ adap->nr = -1;
+ strlcpy(adap->name, pdev->name, sizeof(adap->name));
+ adap->class = I2C_CLASS_DEPRECATED;
+ adap->algo = &selftest_i2c_algo;
+ adap->dev.parent = dev;
+ adap->dev.of_node = dev->of_node;
+ adap->timeout = 5 * HZ;
+ adap->retries = 3;
+
+ ret = i2c_add_numbered_adapter(adap);
+ if (ret != 0) {
+ dev_err(dev, "Failed to add I2C adapter\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int selftest_i2c_bus_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+ struct selftest_i2c_bus_data *std = platform_get_drvdata(pdev);
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+ i2c_del_adapter(&std->adap);
+
+ return 0;
+}
+
+static struct of_device_id selftest_i2c_bus_match[] = {
+ { .compatible = "selftest-i2c-bus", },
+ {},
+};
+
+static struct platform_driver selftest_i2c_bus_driver = {
+ .probe = selftest_i2c_bus_probe,
+ .remove = selftest_i2c_bus_remove,
+ .driver = {
+ .name = "selftest-i2c-bus",
+ .of_match_table = of_match_ptr(selftest_i2c_bus_match),
+ },
+};
+
+static int selftest_i2c_dev_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np = client->dev.of_node;
+
+ if (!np) {
+ dev_err(dev, "No OF node\n");
+ return -EINVAL;
+ }
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+
+ return 0;
+};
+
+static int selftest_i2c_dev_remove(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np = client->dev.of_node;
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+ return 0;
+}
+
+static const struct i2c_device_id selftest_i2c_dev_id[] = {
+ { .name = "selftest-i2c-dev" },
+ { }
+};
+
+static struct i2c_driver selftest_i2c_dev_driver = {
+ .driver = {
+ .name = "selftest-i2c-dev",
+ .owner = THIS_MODULE,
+ },
+ .probe = selftest_i2c_dev_probe,
+ .remove = selftest_i2c_dev_remove,
+ .id_table = selftest_i2c_dev_id,
+};
+
+#if IS_ENABLED(CONFIG_I2C_MUX)
+
+struct selftest_i2c_mux_data {
+ int nchans;
+ struct i2c_adapter *adap[];
+};
+
+static int selftest_i2c_mux_select_chan(struct i2c_adapter *adap,
+ void *client, u32 chan)
+{
+ return 0;
+}
+
+static int selftest_i2c_mux_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ int ret, i, nchans, size;
+ struct device *dev = &client->dev;
+ struct i2c_adapter *adap = to_i2c_adapter(dev->parent);
+ struct device_node *np = client->dev.of_node, *child;
+ struct selftest_i2c_mux_data *stm;
+ u32 reg, max_reg;
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+
+ if (!np) {
+ dev_err(dev, "No OF node\n");
+ return -EINVAL;
+ }
+
+ max_reg = (u32)-1;
+ for_each_child_of_node(np, child) {
+ ret = of_property_read_u32(child, "reg", &reg);
+ if (ret)
+ continue;
+ if (max_reg == (u32)-1 || reg > max_reg)
+ max_reg = reg;
+ }
+ nchans = max_reg == (u32)-1 ? 0 : max_reg + 1;
+ if (nchans == 0) {
+ dev_err(dev, "No channels\n");
+ return -EINVAL;
+ }
+
+ size = offsetof(struct selftest_i2c_mux_data, adap[nchans]);
+ stm = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (!stm) {
+ dev_err(dev, "Out of memory\n");
+ return -ENOMEM;
+ }
+ stm->nchans = nchans;
+ for (i = 0; i < nchans; i++) {
+ stm->adap[i] = i2c_add_mux_adapter(adap, dev, client,
+ 0, i, 0, selftest_i2c_mux_select_chan, NULL);
+ if (!stm->adap[i]) {
+ dev_err(dev, "Failed to register mux #%d\n", i);
+ for (i--; i >= 0; i--)
+ i2c_del_mux_adapter(stm->adap[i]);
+ return -ENODEV;
+ }
+ }
+
+ i2c_set_clientdata(client, stm);
+
+ return 0;
+};
+
+static int selftest_i2c_mux_remove(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct device_node *np = client->dev.of_node;
+ struct selftest_i2c_mux_data *stm = i2c_get_clientdata(client);
+ int i;
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+ for (i = stm->nchans - 1; i >= 0; i--)
+ i2c_del_mux_adapter(stm->adap[i]);
+ return 0;
+}
+
+static const struct i2c_device_id selftest_i2c_mux_id[] = {
+ { .name = "selftest-i2c-mux" },
+ { }
+};
+
+static struct i2c_driver selftest_i2c_mux_driver = {
+ .driver = {
+ .name = "selftest-i2c-mux",
+ .owner = THIS_MODULE,
+ },
+ .probe = selftest_i2c_mux_probe,
+ .remove = selftest_i2c_mux_remove,
+ .id_table = selftest_i2c_mux_id,
+};
+
+#endif
+
+static int of_selftest_overlay_i2c_init(void)
+{
+ int ret;
+
+ ret = i2c_add_driver(&selftest_i2c_dev_driver);
+ if (selftest(ret == 0,
+ "could not register selftest i2c device driver\n"))
+ return ret;
+
+ ret = platform_driver_register(&selftest_i2c_bus_driver);
+ if (selftest(ret == 0,
+ "could not register selftest i2c bus driver\n"))
+ return ret;
+
+#if IS_ENABLED(CONFIG_I2C_MUX)
+ ret = i2c_add_driver(&selftest_i2c_mux_driver);
+ if (selftest(ret == 0,
+ "could not register selftest i2c mux driver\n"))
+ return ret;
+#endif
+
+ return 0;
+}
+
+static void of_selftest_overlay_i2c_cleanup(void)
+{
+#if IS_ENABLED(CONFIG_I2C_MUX)
+ i2c_del_driver(&selftest_i2c_mux_driver);
+#endif
+ platform_driver_unregister(&selftest_i2c_bus_driver);
+ i2c_del_driver(&selftest_i2c_dev_driver);
+}
+
+static void of_selftest_overlay_i2c_12(void)
+{
+ int ret;
+
+ /* device should enable */
+ ret = of_selftest_apply_overlay_check(12, 12, 0, 1, I2C_OVERLAY);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 12);
+}
+
+/* test deactivation of device */
+static void of_selftest_overlay_i2c_13(void)
+{
+ int ret;
+
+ /* device should disable */
+ ret = of_selftest_apply_overlay_check(13, 13, 1, 0, I2C_OVERLAY);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 13);
+}
+
+/* just check for i2c mux existence */
+static void of_selftest_overlay_i2c_14(void)
+{
+}
+
+static void of_selftest_overlay_i2c_15(void)
+{
+ int ret;
+
+ /* device should enable */
+ ret = of_selftest_apply_overlay_check(16, 15, 0, 1, I2C_OVERLAY);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 15);
+}
+
+#else
+
+static inline void of_selftest_overlay_i2c_14(void) { }
+static inline void of_selftest_overlay_i2c_15(void) { }
+
+#endif
+
static void __init of_selftest_overlay(void)
{
struct device_node *bus_np = NULL;
@@ -1445,15 +1787,15 @@ static void __init of_selftest_overlay(void)
goto out;
}
- if (!of_path_platform_device_exists(selftest_path(100))) {
+ if (!of_selftest_device_exists(100, PDEV_OVERLAY)) {
selftest(0, "could not find selftest0 @ \"%s\"\n",
- selftest_path(100));
+ selftest_path(100, PDEV_OVERLAY));
goto out;
}
- if (of_path_platform_device_exists(selftest_path(101))) {
+ if (of_selftest_device_exists(101, PDEV_OVERLAY)) {
selftest(0, "selftest1 @ \"%s\" should not exist\n",
- selftest_path(101));
+ selftest_path(101, PDEV_OVERLAY));
goto out;
}
@@ -1472,6 +1814,18 @@ static void __init of_selftest_overlay(void)
of_selftest_overlay_10();
of_selftest_overlay_11();
+#if IS_ENABLED(CONFIG_I2C)
+ if (selftest(of_selftest_overlay_i2c_init() == 0, "i2c init failed\n"))
+ goto out;
+
+ of_selftest_overlay_i2c_12();
+ of_selftest_overlay_i2c_13();
+ of_selftest_overlay_i2c_14();
+ of_selftest_overlay_i2c_15();
+
+ of_selftest_overlay_i2c_cleanup();
+#endif
+
out:
of_node_put(bus_np);
}
@@ -1514,9 +1868,6 @@ static int __init of_selftest(void)
of_selftest_platform_populate();
of_selftest_overlay();
- /* removing selftest data from live tree */
- selftest_data_remove();
-
/* Double check linkage after removing testcase data */
of_selftest_check_tree_linkage();
diff --git a/drivers/parport/parport_atari.c b/drivers/parport/parport_atari.c
index 7ad59ac68cf6..a81cd2a2747f 100644
--- a/drivers/parport/parport_atari.c
+++ b/drivers/parport/parport_atari.c
@@ -192,8 +192,8 @@ static int __init parport_atari_init(void)
&parport_atari_ops);
if (!p)
return -ENODEV;
- if (request_irq(IRQ_MFP_BUSY, parport_irq_handler,
- IRQ_TYPE_SLOW, p->name, p)) {
+ if (request_irq(IRQ_MFP_BUSY, parport_irq_handler, 0, p->name,
+ p)) {
parport_put_port (p);
return -ENODEV;
}
diff --git a/drivers/pci/access.c b/drivers/pci/access.c
index 49dd766852ba..d9b64a175990 100644
--- a/drivers/pci/access.c
+++ b/drivers/pci/access.c
@@ -67,6 +67,93 @@ EXPORT_SYMBOL(pci_bus_write_config_byte);
EXPORT_SYMBOL(pci_bus_write_config_word);
EXPORT_SYMBOL(pci_bus_write_config_dword);
+int pci_generic_config_read(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ void __iomem *addr;
+
+ addr = bus->ops->map_bus(bus, devfn, where);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ if (size == 1)
+ *val = readb(addr);
+ else if (size == 2)
+ *val = readw(addr);
+ else
+ *val = readl(addr);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+EXPORT_SYMBOL_GPL(pci_generic_config_read);
+
+int pci_generic_config_write(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ void __iomem *addr;
+
+ addr = bus->ops->map_bus(bus, devfn, where);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 1)
+ writeb(val, addr);
+ else if (size == 2)
+ writew(val, addr);
+ else
+ writel(val, addr);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+EXPORT_SYMBOL_GPL(pci_generic_config_write);
+
+int pci_generic_config_read32(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 *val)
+{
+ void __iomem *addr;
+
+ addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
+ if (!addr) {
+ *val = ~0;
+ return PCIBIOS_DEVICE_NOT_FOUND;
+ }
+
+ *val = readl(addr);
+
+ if (size <= 2)
+ *val = (*val >> (8 * (where & 3))) & ((1 << (size * 8)) - 1);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+EXPORT_SYMBOL_GPL(pci_generic_config_read32);
+
+int pci_generic_config_write32(struct pci_bus *bus, unsigned int devfn,
+ int where, int size, u32 val)
+{
+ void __iomem *addr;
+ u32 mask, tmp;
+
+ addr = bus->ops->map_bus(bus, devfn, where & ~0x3);
+ if (!addr)
+ return PCIBIOS_DEVICE_NOT_FOUND;
+
+ if (size == 4) {
+ writel(val, addr);
+ return PCIBIOS_SUCCESSFUL;
+ } else {
+ mask = ~(((1 << (size * 8)) - 1) << ((where & 0x3) * 8));
+ }
+
+ tmp = readl(addr) & mask;
+ tmp |= val << ((where & 0x3) * 8);
+ writel(tmp, addr);
+
+ return PCIBIOS_SUCCESSFUL;
+}
+EXPORT_SYMBOL_GPL(pci_generic_config_write32);
+
/**
* pci_bus_set_ops - Set raw operations of pci bus
* @bus: pci bus struct
diff --git a/drivers/pci/bus.c b/drivers/pci/bus.c
index 8fb16188cd82..90fa3a78fb7c 100644
--- a/drivers/pci/bus.c
+++ b/drivers/pci/bus.c
@@ -20,17 +20,16 @@
void pci_add_resource_offset(struct list_head *resources, struct resource *res,
resource_size_t offset)
{
- struct pci_host_bridge_window *window;
+ struct resource_entry *entry;
- window = kzalloc(sizeof(struct pci_host_bridge_window), GFP_KERNEL);
- if (!window) {
+ entry = resource_list_create_entry(res, 0);
+ if (!entry) {
printk(KERN_ERR "PCI: can't add host bridge window %pR\n", res);
return;
}
- window->res = res;
- window->offset = offset;
- list_add_tail(&window->list, resources);
+ entry->offset = offset;
+ resource_list_add_tail(entry, resources);
}
EXPORT_SYMBOL(pci_add_resource_offset);
@@ -42,12 +41,7 @@ EXPORT_SYMBOL(pci_add_resource);
void pci_free_resource_list(struct list_head *resources)
{
- struct pci_host_bridge_window *window, *tmp;
-
- list_for_each_entry_safe(window, tmp, resources, list) {
- list_del(&window->list);
- kfree(window);
- }
+ resource_list_free(resources);
}
EXPORT_SYMBOL(pci_free_resource_list);
diff --git a/drivers/pci/host-bridge.c b/drivers/pci/host-bridge.c
index 0e5f3c95af5b..39b2dbe585aa 100644
--- a/drivers/pci/host-bridge.c
+++ b/drivers/pci/host-bridge.c
@@ -35,10 +35,10 @@ void pcibios_resource_to_bus(struct pci_bus *bus, struct pci_bus_region *region,
struct resource *res)
{
struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
- struct pci_host_bridge_window *window;
+ struct resource_entry *window;
resource_size_t offset = 0;
- list_for_each_entry(window, &bridge->windows, list) {
+ resource_list_for_each_entry(window, &bridge->windows) {
if (resource_contains(window->res, res)) {
offset = window->offset;
break;
@@ -60,10 +60,10 @@ void pcibios_bus_to_resource(struct pci_bus *bus, struct resource *res,
struct pci_bus_region *region)
{
struct pci_host_bridge *bridge = find_pci_host_bridge(bus);
- struct pci_host_bridge_window *window;
+ struct resource_entry *window;
resource_size_t offset = 0;
- list_for_each_entry(window, &bridge->windows, list) {
+ resource_list_for_each_entry(window, &bridge->windows) {
struct pci_bus_region bus_region;
if (resource_type(res) != resource_type(window->res))
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index c4b6568e486d..7b892a9cc4fc 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -102,4 +102,8 @@ config PCI_LAYERSCAPE
help
Say Y here if you want PCIe controller support on Layerscape SoCs.
+config PCI_VERSATILE
+ bool "ARM Versatile PB PCI controller"
+ depends on ARCH_VERSATILE
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 44c26998027f..e61d91c92bf1 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -12,3 +12,4 @@ 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
+obj-$(CONFIG_PCI_VERSATILE) += pci-versatile.o
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 6eb1aa75bd37..ba46e581db99 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -76,55 +76,9 @@ static struct gen_pci_cfg_bus_ops gen_pci_cfg_ecam_bus_ops = {
.map_bus = gen_pci_map_cfg_bus_ecam,
};
-static int gen_pci_config_read(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *val)
-{
- void __iomem *addr;
- struct pci_sys_data *sys = bus->sysdata;
- struct gen_pci *pci = sys->private_data;
-
- addr = pci->cfg.ops->map_bus(bus, devfn, where);
-
- switch (size) {
- case 1:
- *val = readb(addr);
- break;
- case 2:
- *val = readw(addr);
- break;
- default:
- *val = readl(addr);
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int gen_pci_config_write(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 val)
-{
- void __iomem *addr;
- struct pci_sys_data *sys = bus->sysdata;
- struct gen_pci *pci = sys->private_data;
-
- addr = pci->cfg.ops->map_bus(bus, devfn, where);
-
- switch (size) {
- case 1:
- writeb(val, addr);
- break;
- case 2:
- writew(val, addr);
- break;
- default:
- writel(val, addr);
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
static struct pci_ops gen_pci_ops = {
- .read = gen_pci_config_read,
- .write = gen_pci_config_write,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
};
static const struct of_device_id gen_pci_of_match[] = {
@@ -149,14 +103,14 @@ static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
struct device *dev = pci->host.dev.parent;
struct device_node *np = dev->of_node;
resource_size_t iobase;
- struct pci_host_bridge_window *win;
+ struct resource_entry *win;
err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
&iobase);
if (err)
return err;
- list_for_each_entry(win, &pci->resources, list) {
+ resource_list_for_each_entry(win, &pci->resources) {
struct resource *parent, *res = win->res;
switch (resource_type(res)) {
@@ -287,6 +241,7 @@ static int gen_pci_probe(struct platform_device *pdev)
of_id = of_match_node(gen_pci_of_match, np);
pci->cfg.ops = of_id->data;
+ gen_pci_ops.map_bus = pci->cfg.ops->map_bus;
pci->host.dev.parent = dev;
INIT_LIST_HEAD(&pci->host.windows);
INIT_LIST_HEAD(&pci->resources);
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 78f79e31ac5c..75333b0c4f0a 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -119,7 +119,7 @@ static void ks_pcie_msi_irq_handler(unsigned int irq, struct irq_desc *desc)
struct pcie_port *pp = &ks_pcie->pp;
struct irq_chip *chip = irq_desc_get_chip(desc);
- dev_dbg(pp->dev, "ks_pci_msi_irq_handler, irq %d\n", irq);
+ dev_dbg(pp->dev, "%s, irq %d\n", __func__, irq);
/*
* The chained irq handler installation would have replaced normal
@@ -197,7 +197,7 @@ static int ks_pcie_get_irq_controller_info(struct keystone_pcie *ks_pcie,
*/
for (temp = 0; temp < max_host_irqs; temp++) {
host_irqs[temp] = irq_of_parse_and_map(*np_temp, temp);
- if (host_irqs[temp] < 0)
+ if (!host_irqs[temp])
break;
}
if (temp) {
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
index 6697b1a4d4fa..68c9e5e9b0a8 100644
--- a/drivers/pci/host/pci-layerscape.c
+++ b/drivers/pci/host/pci-layerscape.c
@@ -167,7 +167,6 @@ 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,
},
};
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index 1dd759596b0a..1309cfbaa719 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -101,9 +101,7 @@ struct mvebu_pcie {
struct mvebu_pcie_port *ports;
struct msi_controller *msi;
struct resource io;
- char io_name[30];
struct resource realio;
- char mem_name[30];
struct resource mem;
struct resource busn;
int nports;
@@ -723,18 +721,9 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
{
struct mvebu_pcie *pcie = sys_to_pcie(sys);
int i;
- int domain = 0;
-#ifdef CONFIG_PCI_DOMAINS
- domain = sys->domain;
-#endif
-
- snprintf(pcie->mem_name, sizeof(pcie->mem_name), "PCI MEM %04x",
- domain);
- pcie->mem.name = pcie->mem_name;
-
- snprintf(pcie->io_name, sizeof(pcie->io_name), "PCI I/O %04x", domain);
- pcie->realio.name = pcie->io_name;
+ pcie->mem.name = "PCI MEM";
+ pcie->realio.name = "PCI I/O";
if (request_resource(&iomem_resource, &pcie->mem))
return 0;
diff --git a/drivers/pci/host/pci-rcar-gen2.c b/drivers/pci/host/pci-rcar-gen2.c
index d9c042febb1a..dd6b84e6206c 100644
--- a/drivers/pci/host/pci-rcar-gen2.c
+++ b/drivers/pci/host/pci-rcar-gen2.c
@@ -131,52 +131,6 @@ static void __iomem *rcar_pci_cfg_base(struct pci_bus *bus, unsigned int devfn,
return priv->reg + (slot >> 1) * 0x100 + where;
}
-static int rcar_pci_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *val)
-{
- void __iomem *reg = rcar_pci_cfg_base(bus, devfn, where);
-
- if (!reg)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- switch (size) {
- case 1:
- *val = ioread8(reg);
- break;
- case 2:
- *val = ioread16(reg);
- break;
- default:
- *val = ioread32(reg);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int rcar_pci_write_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 val)
-{
- void __iomem *reg = rcar_pci_cfg_base(bus, devfn, where);
-
- if (!reg)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- switch (size) {
- case 1:
- iowrite8(val, reg);
- break;
- case 2:
- iowrite16(val, reg);
- break;
- default:
- iowrite32(val, reg);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
/* PCI interrupt mapping */
static int rcar_pci_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
{
@@ -325,8 +279,9 @@ static int rcar_pci_setup(int nr, struct pci_sys_data *sys)
}
static struct pci_ops rcar_pci_ops = {
- .read = rcar_pci_read_config,
- .write = rcar_pci_write_config,
+ .map_bus = rcar_pci_cfg_base,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
};
static int rcar_pci_probe(struct platform_device *pdev)
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index a800ae916394..00e92720d7f7 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -480,59 +480,10 @@ static void __iomem *tegra_pcie_conf_address(struct pci_bus *bus,
return addr;
}
-static int tegra_pcie_read_conf(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *value)
-{
- void __iomem *addr;
-
- addr = tegra_pcie_conf_address(bus, devfn, where);
- if (!addr) {
- *value = 0xffffffff;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- *value = readl(addr);
-
- if (size == 1)
- *value = (*value >> (8 * (where & 3))) & 0xff;
- else if (size == 2)
- *value = (*value >> (8 * (where & 3))) & 0xffff;
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int tegra_pcie_write_conf(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 value)
-{
- void __iomem *addr;
- u32 mask, tmp;
-
- addr = tegra_pcie_conf_address(bus, devfn, where);
- if (!addr)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- if (size == 4) {
- writel(value, addr);
- return PCIBIOS_SUCCESSFUL;
- }
-
- if (size == 2)
- mask = ~(0xffff << ((where & 0x3) * 8));
- else if (size == 1)
- mask = ~(0xff << ((where & 0x3) * 8));
- else
- return PCIBIOS_BAD_REGISTER_NUMBER;
-
- tmp = readl(addr) & mask;
- tmp |= value << ((where & 0x3) * 8);
- writel(tmp, addr);
-
- return PCIBIOS_SUCCESSFUL;
-}
-
static struct pci_ops tegra_pcie_ops = {
- .read = tegra_pcie_read_conf,
- .write = tegra_pcie_write_conf,
+ .map_bus = tegra_pcie_conf_address,
+ .read = pci_generic_config_read32,
+ .write = pci_generic_config_write32,
};
static unsigned long tegra_pcie_port_get_pex_ctrl(struct tegra_pcie_port *port)
@@ -625,19 +576,6 @@ static void tegra_pcie_port_free(struct tegra_pcie_port *port)
devm_kfree(pcie->dev, port);
}
-static void tegra_pcie_fixup_bridge(struct pci_dev *dev)
-{
- u16 reg;
-
- if ((dev->class >> 16) == PCI_BASE_CLASS_BRIDGE) {
- pci_read_config_word(dev, PCI_COMMAND, &reg);
- reg |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY |
- PCI_COMMAND_MASTER | PCI_COMMAND_SERR);
- pci_write_config_word(dev, PCI_COMMAND, reg);
- }
-}
-DECLARE_PCI_FIXUP_FINAL(PCI_ANY_ID, PCI_ANY_ID, tegra_pcie_fixup_bridge);
-
/* Tegra PCIE root complex wrongly reports device class */
static void tegra_pcie_fixup_class(struct pci_dev *dev)
{
diff --git a/drivers/pci/host/pci-versatile.c b/drivers/pci/host/pci-versatile.c
new file mode 100644
index 000000000000..1ec694a52379
--- /dev/null
+++ b/drivers/pci/host/pci-versatile.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2004 Koninklijke Philips Electronics NV
+ *
+ * Conversion to platform driver and DT:
+ * Copyright 2014 Linaro Ltd.
+ *
+ * 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.
+ *
+ * 14/04/2005 Initial version, colin.king@philips.com
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_address.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+
+static void __iomem *versatile_pci_base;
+static void __iomem *versatile_cfg_base[2];
+
+#define PCI_IMAP(m) (versatile_pci_base + ((m) * 4))
+#define PCI_SMAP(m) (versatile_pci_base + 0x14 + ((m) * 4))
+#define PCI_SELFID (versatile_pci_base + 0xc)
+
+#define VP_PCI_DEVICE_ID 0x030010ee
+#define VP_PCI_CLASS_ID 0x0b400000
+
+static u32 pci_slot_ignore;
+
+static int __init versatile_pci_slot_ignore(char *str)
+{
+ int retval;
+ int slot;
+
+ while ((retval = get_option(&str, &slot))) {
+ if ((slot < 0) || (slot > 31))
+ pr_err("Illegal slot value: %d\n", slot);
+ else
+ pci_slot_ignore |= (1 << slot);
+ }
+ return 1;
+}
+__setup("pci_slot_ignore=", versatile_pci_slot_ignore);
+
+
+static void __iomem *versatile_map_bus(struct pci_bus *bus,
+ unsigned int devfn, int offset)
+{
+ unsigned int busnr = bus->number;
+
+ if (pci_slot_ignore & (1 << PCI_SLOT(devfn)))
+ return NULL;
+
+ return versatile_cfg_base[1] + ((busnr << 16) | (devfn << 8) | offset);
+}
+
+static struct pci_ops pci_versatile_ops = {
+ .map_bus = versatile_map_bus,
+ .read = pci_generic_config_read32,
+ .write = pci_generic_config_write,
+};
+
+static int versatile_pci_parse_request_of_pci_ranges(struct device *dev,
+ struct list_head *res)
+{
+ int err, mem = 1, res_valid = 0;
+ struct device_node *np = dev->of_node;
+ resource_size_t iobase;
+ struct resource_entry *win;
+
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, res, &iobase);
+ if (err)
+ return err;
+
+ resource_list_for_each_entry(win, res, list) {
+ struct resource *parent, *res = win->res;
+
+ switch (resource_type(res)) {
+ case IORESOURCE_IO:
+ parent = &ioport_resource;
+ 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;
+ res_valid |= !(res->flags & IORESOURCE_PREFETCH);
+
+ writel(res->start >> 28, PCI_IMAP(mem));
+ writel(PHYS_OFFSET >> 28, PCI_SMAP(mem));
+ mem++;
+
+ break;
+ case IORESOURCE_BUS:
+ default:
+ continue;
+ }
+
+ err = devm_request_resource(dev, parent, res);
+ if (err)
+ goto out_release_res;
+ }
+
+ if (!res_valid) {
+ dev_err(dev, "non-prefetchable memory resource required\n");
+ err = -EINVAL;
+ goto out_release_res;
+ }
+
+ return 0;
+
+out_release_res:
+ pci_free_resource_list(res);
+ return err;
+}
+
+/* Unused, temporary to satisfy ARM arch code */
+struct pci_sys_data sys;
+
+static int versatile_pci_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ int ret, i, myslot = -1;
+ u32 val;
+ void __iomem *local_pci_cfg_base;
+ struct pci_bus *bus;
+ LIST_HEAD(pci_res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENODEV;
+ versatile_pci_base = devm_ioremap_resource(&pdev->dev, res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!res)
+ return -ENODEV;
+ versatile_cfg_base[0] = devm_ioremap_resource(&pdev->dev, res);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!res)
+ return -ENODEV;
+ versatile_cfg_base[1] = devm_ioremap_resource(&pdev->dev, res);
+
+ ret = versatile_pci_parse_request_of_pci_ranges(&pdev->dev, &pci_res);
+ if (ret)
+ return ret;
+
+ /*
+ * We need to discover the PCI core first to configure itself
+ * before the main PCI probing is performed
+ */
+ for (i = 0; i < 32; i++) {
+ if ((readl(versatile_cfg_base[0] + (i << 11) + PCI_VENDOR_ID) == VP_PCI_DEVICE_ID) &&
+ (readl(versatile_cfg_base[0] + (i << 11) + PCI_CLASS_REVISION) == VP_PCI_CLASS_ID)) {
+ myslot = i;
+ break;
+ }
+ }
+ if (myslot == -1) {
+ dev_err(&pdev->dev, "Cannot find PCI core!\n");
+ return -EIO;
+ }
+ /*
+ * Do not to map Versatile FPGA PCI device into memory space
+ */
+ pci_slot_ignore |= (1 << myslot);
+
+ dev_info(&pdev->dev, "PCI core found (slot %d)\n", myslot);
+
+ writel(myslot, PCI_SELFID);
+ local_pci_cfg_base = versatile_cfg_base[1] + (myslot << 11);
+
+ val = readl(local_pci_cfg_base + PCI_COMMAND);
+ val |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER | PCI_COMMAND_INVALIDATE;
+ writel(val, local_pci_cfg_base + PCI_COMMAND);
+
+ /*
+ * Configure the PCI inbound memory windows to be 1:1 mapped to SDRAM
+ */
+ writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_0);
+ writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_1);
+ writel(PHYS_OFFSET, local_pci_cfg_base + PCI_BASE_ADDRESS_2);
+
+ /*
+ * For many years the kernel and QEMU were symbiotically buggy
+ * in that they both assumed the same broken IRQ mapping.
+ * QEMU therefore attempts to auto-detect old broken kernels
+ * so that they still work on newer QEMU as they did on old
+ * QEMU. Since we now use the correct (ie matching-hardware)
+ * IRQ mapping we write a definitely different value to a
+ * PCI_INTERRUPT_LINE register to tell QEMU that we expect
+ * real hardware behaviour and it need not be backwards
+ * compatible for us. This write is harmless on real hardware.
+ */
+ writel(0, versatile_cfg_base[0] + PCI_INTERRUPT_LINE);
+
+ pci_add_flags(PCI_ENABLE_PROC_DOMAINS);
+ pci_add_flags(PCI_REASSIGN_ALL_BUS | PCI_REASSIGN_ALL_RSRC);
+
+ bus = pci_scan_root_bus(&pdev->dev, 0, &pci_versatile_ops, &sys, &pci_res);
+ if (!bus)
+ return -ENOMEM;
+
+ pci_fixup_irqs(pci_common_swizzle, of_irq_parse_and_map_pci);
+ pci_assign_unassigned_bus_resources(bus);
+
+ return 0;
+}
+
+static const struct of_device_id versatile_pci_of_match[] = {
+ { .compatible = "arm,versatile-pci", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, versatile_pci_of_match);
+
+static struct platform_driver versatile_pci_driver = {
+ .driver = {
+ .name = "versatile-pci",
+ .of_match_table = versatile_pci_of_match,
+ },
+ .probe = versatile_pci_probe,
+};
+module_platform_driver(versatile_pci_driver);
+
+MODULE_DESCRIPTION("Versatile PCI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-xgene.c b/drivers/pci/host/pci-xgene.c
index b1d0596457c5..aab55474dd0d 100644
--- a/drivers/pci/host/pci-xgene.c
+++ b/drivers/pci/host/pci-xgene.c
@@ -16,7 +16,7 @@
* GNU General Public License for more details.
*
*/
-#include <linux/clk-private.h>
+#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/jiffies.h>
@@ -74,92 +74,6 @@ static inline u32 pcie_bar_low_val(u32 addr, u32 flags)
return (addr & PCI_BASE_ADDRESS_MEM_MASK) | flags;
}
-/* PCIe Configuration Out/In */
-static inline void xgene_pcie_cfg_out32(void __iomem *addr, int offset, u32 val)
-{
- writel(val, addr + offset);
-}
-
-static inline void xgene_pcie_cfg_out16(void __iomem *addr, int offset, u16 val)
-{
- u32 val32 = readl(addr + (offset & ~0x3));
-
- switch (offset & 0x3) {
- case 2:
- val32 &= ~0xFFFF0000;
- val32 |= (u32)val << 16;
- break;
- case 0:
- default:
- val32 &= ~0xFFFF;
- val32 |= val;
- break;
- }
- writel(val32, addr + (offset & ~0x3));
-}
-
-static inline void xgene_pcie_cfg_out8(void __iomem *addr, int offset, u8 val)
-{
- u32 val32 = readl(addr + (offset & ~0x3));
-
- switch (offset & 0x3) {
- case 0:
- val32 &= ~0xFF;
- val32 |= val;
- break;
- case 1:
- val32 &= ~0xFF00;
- val32 |= (u32)val << 8;
- break;
- case 2:
- val32 &= ~0xFF0000;
- val32 |= (u32)val << 16;
- break;
- case 3:
- default:
- val32 &= ~0xFF000000;
- val32 |= (u32)val << 24;
- break;
- }
- writel(val32, addr + (offset & ~0x3));
-}
-
-static inline void xgene_pcie_cfg_in32(void __iomem *addr, int offset, u32 *val)
-{
- *val = readl(addr + offset);
-}
-
-static inline void xgene_pcie_cfg_in16(void __iomem *addr, int offset, u32 *val)
-{
- *val = readl(addr + (offset & ~0x3));
-
- switch (offset & 0x3) {
- case 2:
- *val >>= 16;
- break;
- }
-
- *val &= 0xFFFF;
-}
-
-static inline void xgene_pcie_cfg_in8(void __iomem *addr, int offset, u32 *val)
-{
- *val = readl(addr + (offset & ~0x3));
-
- switch (offset & 0x3) {
- case 3:
- *val = *val >> 24;
- break;
- case 2:
- *val = *val >> 16;
- break;
- case 1:
- *val = *val >> 8;
- break;
- }
- *val &= 0xFF;
-}
-
/*
* When the address bit [17:16] is 2'b01, the Configuration access will be
* treated as Type 1 and it will be forwarded to external PCIe device.
@@ -213,69 +127,23 @@ static bool xgene_pcie_hide_rc_bars(struct pci_bus *bus, int offset)
return false;
}
-static int xgene_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
- int offset, int len, u32 *val)
-{
- struct xgene_pcie_port *port = bus->sysdata;
- void __iomem *addr;
-
- if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- if (xgene_pcie_hide_rc_bars(bus, offset)) {
- *val = 0;
- return PCIBIOS_SUCCESSFUL;
- }
-
- xgene_pcie_set_rtdid_reg(bus, devfn);
- addr = xgene_pcie_get_cfg_base(bus);
- switch (len) {
- case 1:
- xgene_pcie_cfg_in8(addr, offset, val);
- break;
- case 2:
- xgene_pcie_cfg_in16(addr, offset, val);
- break;
- default:
- xgene_pcie_cfg_in32(addr, offset, val);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-static int xgene_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
- int offset, int len, u32 val)
+static int xgene_pcie_map_bus(struct pci_bus *bus, unsigned int devfn,
+ int offset)
{
struct xgene_pcie_port *port = bus->sysdata;
- void __iomem *addr;
- if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up)
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- if (xgene_pcie_hide_rc_bars(bus, offset))
- return PCIBIOS_SUCCESSFUL;
+ if ((pci_is_root_bus(bus) && devfn != 0) || !port->link_up ||
+ xgene_pcie_hide_rc_bars(bus, offset))
+ return NULL;
xgene_pcie_set_rtdid_reg(bus, devfn);
- addr = xgene_pcie_get_cfg_base(bus);
- switch (len) {
- case 1:
- xgene_pcie_cfg_out8(addr, offset, (u8)val);
- break;
- case 2:
- xgene_pcie_cfg_out16(addr, offset, (u16)val);
- break;
- default:
- xgene_pcie_cfg_out32(addr, offset, val);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
+ return xgene_pcie_get_cfg_base(bus);
}
static struct pci_ops xgene_pcie_ops = {
- .read = xgene_pcie_read_config,
- .write = xgene_pcie_write_config
+ .map_bus = xgene_pcie_map_bus,
+ .read = pci_generic_config_read32,
+ .write = pci_generic_config_write32,
};
static u64 xgene_pcie_set_ib_mask(void __iomem *csr_base, u32 addr,
@@ -401,11 +269,11 @@ static int xgene_pcie_map_ranges(struct xgene_pcie_port *port,
struct list_head *res,
resource_size_t io_base)
{
- struct pci_host_bridge_window *window;
+ struct resource_entry *window;
struct device *dev = port->dev;
int ret;
- list_for_each_entry(window, res, list) {
+ resource_list_for_each_entry(window, res) {
struct resource *res = window->res;
u64 restype = resource_type(res);
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index df781cdf13c1..1f4ea6f2d910 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -283,6 +283,9 @@ static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_msg msg;
struct pcie_port *pp = sys_to_pcie(pdev->bus->sysdata);
+ if (desc->msi_attrib.is_msix)
+ return -EINVAL;
+
irq = assign_irq(1, desc, &pos);
if (irq < 0)
return irq;
@@ -508,9 +511,6 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
dw_pci.private_data = (void **)&pp;
pci_common_init_dev(pp->dev, &dw_pci);
-#ifdef CONFIG_PCI_DOMAINS
- dw_pci.domain++;
-#endif
return 0;
}
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 748786c402fc..c57bd0ac39a0 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -397,9 +397,6 @@ static void rcar_pcie_enable(struct rcar_pcie *pcie)
#endif
pci_common_init_dev(&pdev->dev, &rcar_pci);
-#ifdef CONFIG_PCI_DOMAINS
- rcar_pci.domain++;
-#endif
}
static int phy_wait_for_ack(struct rcar_pcie *pcie)
@@ -757,7 +754,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev,
goto err_map_reg;
i = irq_of_parse_and_map(pdev->dev.of_node, 0);
- if (i < 0) {
+ if (!i) {
dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n");
err = -ENOENT;
goto err_map_reg;
@@ -765,7 +762,7 @@ static int rcar_pcie_get_resources(struct platform_device *pdev,
pcie->msi.irq1 = i;
i = irq_of_parse_and_map(pdev->dev.of_node, 1);
- if (i < 0) {
+ if (!i) {
dev_err(pcie->dev, "cannot get platform resources for msi interrupt\n");
err = -ENOENT;
goto err_map_reg;
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index ef3ebaf9a738..f1a06a091ccb 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -148,10 +148,10 @@ static inline bool xilinx_pcie_link_is_up(struct xilinx_pcie_port *port)
*/
static void xilinx_pcie_clear_err_interrupts(struct xilinx_pcie_port *port)
{
- u32 val = pcie_read(port, XILINX_PCIE_REG_RPEFR);
+ unsigned long val = pcie_read(port, XILINX_PCIE_REG_RPEFR);
if (val & XILINX_PCIE_RPEFR_ERR_VALID) {
- dev_dbg(port->dev, "Requester ID %d\n",
+ dev_dbg(port->dev, "Requester ID %lu\n",
val & XILINX_PCIE_RPEFR_REQ_ID);
pcie_write(port, XILINX_PCIE_RPEFR_ALL_MASK,
XILINX_PCIE_REG_RPEFR);
@@ -189,7 +189,7 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
}
/**
- * xilinx_pcie_config_base - Get configuration base
+ * xilinx_pcie_map_bus - Get configuration base
* @bus: PCI Bus structure
* @devfn: Device/function
* @where: Offset from base
@@ -197,96 +197,26 @@ static bool xilinx_pcie_valid_device(struct pci_bus *bus, unsigned int devfn)
* Return: Base address of the configuration space needed to be
* accessed.
*/
-static void __iomem *xilinx_pcie_config_base(struct pci_bus *bus,
- unsigned int devfn, int where)
+static void __iomem *xilinx_pcie_map_bus(struct pci_bus *bus,
+ unsigned int devfn, int where)
{
struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
int relbus;
+ if (!xilinx_pcie_valid_device(bus, devfn))
+ return NULL;
+
relbus = (bus->number << ECAM_BUS_NUM_SHIFT) |
(devfn << ECAM_DEV_NUM_SHIFT);
return port->reg_base + relbus + where;
}
-/**
- * xilinx_pcie_read_config - Read configuration space
- * @bus: PCI Bus structure
- * @devfn: Device/function
- * @where: Offset from base
- * @size: Byte/word/dword
- * @val: Value to be read
- *
- * Return: PCIBIOS_SUCCESSFUL on success
- * PCIBIOS_DEVICE_NOT_FOUND on failure
- */
-static int xilinx_pcie_read_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 *val)
-{
- void __iomem *addr;
-
- if (!xilinx_pcie_valid_device(bus, devfn)) {
- *val = 0xFFFFFFFF;
- return PCIBIOS_DEVICE_NOT_FOUND;
- }
-
- addr = xilinx_pcie_config_base(bus, devfn, where);
-
- switch (size) {
- case 1:
- *val = readb(addr);
- break;
- case 2:
- *val = readw(addr);
- break;
- default:
- *val = readl(addr);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
-/**
- * xilinx_pcie_write_config - Write configuration space
- * @bus: PCI Bus structure
- * @devfn: Device/function
- * @where: Offset from base
- * @size: Byte/word/dword
- * @val: Value to be written to device
- *
- * Return: PCIBIOS_SUCCESSFUL on success
- * PCIBIOS_DEVICE_NOT_FOUND on failure
- */
-static int xilinx_pcie_write_config(struct pci_bus *bus, unsigned int devfn,
- int where, int size, u32 val)
-{
- void __iomem *addr;
-
- if (!xilinx_pcie_valid_device(bus, devfn))
- return PCIBIOS_DEVICE_NOT_FOUND;
-
- addr = xilinx_pcie_config_base(bus, devfn, where);
-
- switch (size) {
- case 1:
- writeb(val, addr);
- break;
- case 2:
- writew(val, addr);
- break;
- default:
- writel(val, addr);
- break;
- }
-
- return PCIBIOS_SUCCESSFUL;
-}
-
/* PCIe operations */
static struct pci_ops xilinx_pcie_ops = {
- .read = xilinx_pcie_read_config,
- .write = xilinx_pcie_write_config,
+ .map_bus = xilinx_pcie_map_bus,
+ .read = pci_generic_config_read,
+ .write = pci_generic_config_write,
};
/* MSI functions */
@@ -737,7 +667,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port)
resource_size_t offset;
struct of_pci_range_parser parser;
struct of_pci_range range;
- struct pci_host_bridge_window *win;
+ struct resource_entry *win;
int err = 0, mem_resno = 0;
/* Get the ranges */
@@ -807,7 +737,7 @@ static int xilinx_pcie_parse_and_add_res(struct xilinx_pcie_port *port)
free_resources:
release_child_resources(&iomem_resource);
- list_for_each_entry(win, &port->resources, list)
+ resource_list_for_each_entry(win, &port->resources)
devm_kfree(dev, win->res);
pci_free_resource_list(&port->resources);
diff --git a/drivers/pci/hotplug/cpci_hotplug_core.c b/drivers/pci/hotplug/cpci_hotplug_core.c
index a5a7fd8332ac..46db29395a62 100644
--- a/drivers/pci/hotplug/cpci_hotplug_core.c
+++ b/drivers/pci/hotplug/cpci_hotplug_core.c
@@ -214,8 +214,7 @@ static void release_slot(struct hotplug_slot *hotplug_slot)
kfree(slot->hotplug_slot->info);
kfree(slot->hotplug_slot);
- if (slot->dev)
- pci_dev_put(slot->dev);
+ pci_dev_put(slot->dev);
kfree(slot);
}
diff --git a/drivers/pci/hotplug/pciehp_ctrl.c b/drivers/pci/hotplug/pciehp_ctrl.c
index ff32e85e1de6..f052e951b23e 100644
--- a/drivers/pci/hotplug/pciehp_ctrl.c
+++ b/drivers/pci/hotplug/pciehp_ctrl.c
@@ -532,8 +532,6 @@ static void interrupt_event_handler(struct work_struct *work)
pciehp_green_led_off(p_slot);
break;
case INT_PRESENCE_ON:
- if (!HP_SUPR_RM(ctrl))
- break;
ctrl_dbg(ctrl, "Surprise Insertion\n");
handle_surprise_event(p_slot);
break;
diff --git a/drivers/pci/hotplug/sgi_hotplug.c b/drivers/pci/hotplug/sgi_hotplug.c
index bada20999870..c32fb786d48e 100644
--- a/drivers/pci/hotplug/sgi_hotplug.c
+++ b/drivers/pci/hotplug/sgi_hotplug.c
@@ -475,7 +475,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
struct slot *slot = bss_hotplug_slot->private;
struct pci_dev *dev, *temp;
int rc;
- acpi_owner_id ssdt_id = 0;
+ acpi_handle ssdt_hdl = NULL;
/* Acquire update access to the bus */
mutex_lock(&sn_hotplug_mutex);
@@ -522,7 +522,7 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
if (ACPI_SUCCESS(ret) &&
(adr>>16) == (slot->device_num + 1)) {
/* retain the owner id */
- acpi_get_id(chandle, &ssdt_id);
+ ssdt_hdl = chandle;
ret = acpi_bus_get_device(chandle,
&device);
@@ -547,12 +547,13 @@ static int disable_slot(struct hotplug_slot *bss_hotplug_slot)
pci_unlock_rescan_remove();
/* Remove the SSDT for the slot from the ACPI namespace */
- if (SN_ACPI_BASE_SUPPORT() && ssdt_id) {
+ if (SN_ACPI_BASE_SUPPORT() && ssdt_hdl) {
acpi_status ret;
- ret = acpi_unload_table_id(ssdt_id);
+ ret = acpi_unload_parent_table(ssdt_hdl);
if (ACPI_FAILURE(ret)) {
- printk(KERN_ERR "%s: acpi_unload_table_id failed (0x%x) for id %d\n",
- __func__, ret, ssdt_id);
+ acpi_handle_err(ssdt_hdl,
+ "%s: acpi_unload_parent_table failed (0x%x)\n",
+ __func__, ret);
/* try to continue on */
}
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index fd60806d3fd0..c3e7dfcf9ff5 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -694,11 +694,16 @@ static void __iomem *msix_map_region(struct pci_dev *dev, unsigned nr_entries)
{
resource_size_t phys_addr;
u32 table_offset;
+ unsigned long flags;
u8 bir;
pci_read_config_dword(dev, dev->msix_cap + PCI_MSIX_TABLE,
&table_offset);
bir = (u8)(table_offset & PCI_MSIX_TABLE_BIR);
+ flags = pci_resource_flags(dev, bir);
+ if (!flags || (flags & IORESOURCE_UNSET))
+ return NULL;
+
table_offset &= PCI_MSIX_TABLE_OFFSET;
phys_addr = pci_resource_start(dev, bir) + table_offset;
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 3542150fc8a3..489063987325 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -501,12 +501,29 @@ static int acpi_pci_run_wake(struct pci_dev *dev, bool enable)
return 0;
}
+static bool acpi_pci_need_resume(struct pci_dev *dev)
+{
+ struct acpi_device *adev = ACPI_COMPANION(&dev->dev);
+
+ if (!adev || !acpi_device_power_manageable(adev))
+ return false;
+
+ if (device_may_wakeup(&dev->dev) != !!adev->wakeup.prepare_count)
+ return true;
+
+ if (acpi_target_system_state() == ACPI_STATE_S0)
+ return false;
+
+ return !!adev->power.flags.dsw_present;
+}
+
static struct pci_platform_pm_ops acpi_pci_platform_pm = {
.is_manageable = acpi_pci_power_manageable,
.set_state = acpi_pci_set_power_state,
.choose_state = acpi_pci_choose_state,
.sleep_wake = acpi_pci_sleep_wake,
.run_wake = acpi_pci_run_wake,
+ .need_resume = acpi_pci_need_resume,
};
void acpi_pci_add_bus(struct pci_bus *bus)
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 887e6bd95af7..3cb2210de553 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -653,7 +653,6 @@ static bool pci_has_legacy_pm_support(struct pci_dev *pci_dev)
static int pci_pm_prepare(struct device *dev)
{
struct device_driver *drv = dev->driver;
- int error = 0;
/*
* Devices having power.ignore_children set may still be necessary for
@@ -662,10 +661,12 @@ static int pci_pm_prepare(struct device *dev)
if (dev->power.ignore_children)
pm_runtime_resume(dev);
- if (drv && drv->pm && drv->pm->prepare)
- error = drv->pm->prepare(dev);
-
- return error;
+ if (drv && drv->pm && drv->pm->prepare) {
+ int error = drv->pm->prepare(dev);
+ if (error)
+ return error;
+ }
+ return pci_dev_keep_suspended(to_pci_dev(dev));
}
@@ -1383,7 +1384,7 @@ static int pci_uevent(struct device *dev, struct kobj_uevent_env *env)
if (add_uevent_var(env, "PCI_SLOT_NAME=%s", pci_name(pdev)))
return -ENOMEM;
- if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02x",
+ if (add_uevent_var(env, "MODALIAS=pci:v%08Xd%08Xsv%08Xsd%08Xbc%02Xsc%02Xi%02X",
pdev->vendor, pdev->device,
pdev->subsystem_vendor, pdev->subsystem_device,
(u8)(pdev->class >> 16), (u8)(pdev->class >> 8),
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index e9d4fd861ba1..81f06e8dcc04 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -10,6 +10,8 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/init.h>
+#include <linux/of.h>
+#include <linux/of_pci.h>
#include <linux/pci.h>
#include <linux/pm.h>
#include <linux/slab.h>
@@ -521,6 +523,11 @@ static inline int platform_pci_run_wake(struct pci_dev *dev, bool enable)
pci_platform_pm->run_wake(dev, enable) : -ENODEV;
}
+static inline bool platform_pci_need_resume(struct pci_dev *dev)
+{
+ return pci_platform_pm ? pci_platform_pm->need_resume(dev) : false;
+}
+
/**
* pci_raw_set_power_state - Use PCI PM registers to set the power state of
* given PCI device
@@ -1999,6 +2006,27 @@ bool pci_dev_run_wake(struct pci_dev *dev)
}
EXPORT_SYMBOL_GPL(pci_dev_run_wake);
+/**
+ * pci_dev_keep_suspended - Check if the device can stay in the suspended state.
+ * @pci_dev: Device to check.
+ *
+ * Return 'true' if the device is runtime-suspended, it doesn't have to be
+ * reconfigured due to wakeup settings difference between system and runtime
+ * suspend and the current power state of it is suitable for the upcoming
+ * (system) transition.
+ */
+bool pci_dev_keep_suspended(struct pci_dev *pci_dev)
+{
+ struct device *dev = &pci_dev->dev;
+
+ if (!pm_runtime_suspended(dev)
+ || (device_can_wakeup(dev) && !device_may_wakeup(dev))
+ || platform_pci_need_resume(pci_dev))
+ return false;
+
+ return pci_target_state(pci_dev) == pci_dev->current_state;
+}
+
void pci_config_pm_runtime_get(struct pci_dev *pdev)
{
struct device *dev = &pdev->dev;
@@ -3197,7 +3225,7 @@ static int pci_pm_reset(struct pci_dev *dev, int probe)
{
u16 csr;
- if (!dev->pm_cap)
+ if (!dev->pm_cap || dev->dev_flags & PCI_DEV_FLAGS_NO_PM_RESET)
return -ENOTTY;
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &csr);
@@ -4471,6 +4499,53 @@ int pci_get_new_domain_nr(void)
{
return atomic_inc_return(&__domain_nr);
}
+
+#ifdef CONFIG_PCI_DOMAINS_GENERIC
+void pci_bus_assign_domain_nr(struct pci_bus *bus, struct device *parent)
+{
+ static int use_dt_domains = -1;
+ int domain = of_get_pci_domain_nr(parent->of_node);
+
+ /*
+ * Check DT domain and use_dt_domains values.
+ *
+ * If DT domain property is valid (domain >= 0) and
+ * use_dt_domains != 0, the DT assignment is valid since this means
+ * we have not previously allocated a domain number by using
+ * pci_get_new_domain_nr(); we should also update use_dt_domains to
+ * 1, to indicate that we have just assigned a domain number from
+ * DT.
+ *
+ * If DT domain property value is not valid (ie domain < 0), and we
+ * have not previously assigned a domain number from DT
+ * (use_dt_domains != 1) we should assign a domain number by
+ * using the:
+ *
+ * pci_get_new_domain_nr()
+ *
+ * API and update the use_dt_domains value to keep track of method we
+ * are using to assign domain numbers (use_dt_domains = 0).
+ *
+ * All other combinations imply we have a platform that is trying
+ * to mix domain numbers obtained from DT and pci_get_new_domain_nr(),
+ * which is a recipe for domain mishandling and it is prevented by
+ * invalidating the domain value (domain = -1) and printing a
+ * corresponding error.
+ */
+ if (domain >= 0 && use_dt_domains) {
+ use_dt_domains = 1;
+ } else if (domain < 0 && use_dt_domains != 1) {
+ use_dt_domains = 0;
+ domain = pci_get_new_domain_nr();
+ } else {
+ dev_err(parent, "Node %s has inconsistent \"linux,pci-domain\" property in DT\n",
+ parent->of_node->full_name);
+ domain = -1;
+ }
+
+ bus->domain_nr = domain;
+}
+#endif
#endif
/**
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index d54632a1db43..4091f82239cd 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -50,6 +50,10 @@ int pci_probe_reset_function(struct pci_dev *dev);
* for given device (the device's wake-up capability has to be
* enabled by @sleep_wake for this feature to work)
*
+ * @need_resume: returns 'true' if the given device (which is currently
+ * suspended) needs to be resumed to be configured for system
+ * wakeup.
+ *
* If given platform is generally capable of power managing PCI devices, all of
* these callbacks are mandatory.
*/
@@ -59,6 +63,7 @@ struct pci_platform_pm_ops {
pci_power_t (*choose_state)(struct pci_dev *dev);
int (*sleep_wake)(struct pci_dev *dev, bool enable);
int (*run_wake)(struct pci_dev *dev, bool enable);
+ bool (*need_resume)(struct pci_dev *dev);
};
int pci_set_platform_pm(struct pci_platform_pm_ops *ops);
@@ -67,6 +72,7 @@ void pci_power_up(struct pci_dev *dev);
void pci_disable_enabled_device(struct pci_dev *dev);
int pci_finish_runtime_suspend(struct pci_dev *dev);
int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
+bool pci_dev_keep_suspended(struct pci_dev *dev);
void pci_config_pm_runtime_get(struct pci_dev *dev);
void pci_config_pm_runtime_put(struct pci_dev *dev);
void pci_pm_init(struct pci_dev *dev);
diff --git a/drivers/pci/pcie/aer/Kconfig b/drivers/pci/pcie/aer/Kconfig
index 389440228c1d..7d1437b01fdd 100644
--- a/drivers/pci/pcie/aer/Kconfig
+++ b/drivers/pci/pcie/aer/Kconfig
@@ -3,7 +3,7 @@
#
config PCIEAER
- boolean "Root Port Advanced Error Reporting support"
+ bool "Root Port Advanced Error Reporting support"
depends on PCIEPORTBUS
select RAS
default y
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index e1e7026b838d..820740a22e94 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -859,7 +859,10 @@ static ssize_t link_state_store(struct device *dev,
{
struct pci_dev *pdev = to_pci_dev(dev);
struct pcie_link_state *link, *root = pdev->link_state->root;
- u32 val = buf[0] - '0', state = 0;
+ u32 val, state = 0;
+
+ if (kstrtouint(buf, 10, &val))
+ return -EINVAL;
if (aspm_disabled)
return -EPERM;
@@ -900,15 +903,14 @@ static ssize_t clk_ctl_store(struct device *dev,
size_t n)
{
struct pci_dev *pdev = to_pci_dev(dev);
- int state;
+ bool state;
- if (n < 1)
+ if (strtobool(buf, &state))
return -EINVAL;
- state = buf[0]-'0';
down_read(&pci_bus_sem);
mutex_lock(&aspm_lock);
- pcie_set_clkpm_nocheck(pdev->link_state, !!state);
+ pcie_set_clkpm_nocheck(pdev->link_state, state);
mutex_unlock(&aspm_lock);
up_read(&pci_bus_sem);
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 23212f8ae09b..8d2f400e96cb 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -1895,7 +1895,7 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
int error;
struct pci_host_bridge *bridge;
struct pci_bus *b, *b2;
- struct pci_host_bridge_window *window, *n;
+ struct resource_entry *window, *n;
struct resource *res;
resource_size_t offset;
char bus_addr[64];
@@ -1959,8 +1959,8 @@ struct pci_bus *pci_create_root_bus(struct device *parent, int bus,
printk(KERN_INFO "PCI host bridge to bus %s\n", dev_name(&b->dev));
/* Add initial resources to the bus */
- list_for_each_entry_safe(window, n, resources, list) {
- list_move_tail(&window->list, &bridge->windows);
+ resource_list_for_each_entry_safe(window, n, resources) {
+ list_move_tail(&window->node, &bridge->windows);
res = window->res;
offset = window->offset;
if (res->flags & IORESOURCE_BUS)
@@ -2060,12 +2060,12 @@ void pci_bus_release_busn_res(struct pci_bus *b)
struct pci_bus *pci_scan_root_bus(struct device *parent, int bus,
struct pci_ops *ops, void *sysdata, struct list_head *resources)
{
- struct pci_host_bridge_window *window;
+ struct resource_entry *window;
bool found = false;
struct pci_bus *b;
int max;
- list_for_each_entry(window, resources, list)
+ resource_list_for_each_entry(window, resources)
if (window->res->flags & IORESOURCE_BUS) {
found = true;
break;
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
index e52356aa09b8..85f247e28a80 100644
--- a/drivers/pci/quirks.c
+++ b/drivers/pci/quirks.c
@@ -324,18 +324,52 @@ static void quirk_s3_64M(struct pci_dev *dev)
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_868, quirk_s3_64M);
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_968, quirk_s3_64M);
+static void quirk_io(struct pci_dev *dev, int pos, unsigned size,
+ const char *name)
+{
+ u32 region;
+ struct pci_bus_region bus_region;
+ struct resource *res = dev->resource + pos;
+
+ pci_read_config_dword(dev, PCI_BASE_ADDRESS_0 + (pos << 2), &region);
+
+ if (!region)
+ return;
+
+ res->name = pci_name(dev);
+ res->flags = region & ~PCI_BASE_ADDRESS_IO_MASK;
+ res->flags |=
+ (IORESOURCE_IO | IORESOURCE_PCI_FIXED | IORESOURCE_SIZEALIGN);
+ region &= ~(size - 1);
+
+ /* Convert from PCI bus to resource space */
+ bus_region.start = region;
+ bus_region.end = region + size - 1;
+ pcibios_bus_to_resource(dev->bus, res, &bus_region);
+
+ dev_info(&dev->dev, FW_BUG "%s quirk: reg 0x%x: %pR\n",
+ name, PCI_BASE_ADDRESS_0 + (pos << 2), res);
+}
+
/*
* Some CS5536 BIOSes (for example, the Soekris NET5501 board w/ comBIOS
* ver. 1.33 20070103) don't set the correct ISA PCI region header info.
* BAR0 should be 8 bytes; instead, it may be set to something like 8k
* (which conflicts w/ BAR1's memory range).
+ *
+ * CS553x's ISA PCI BARs may also be read-only (ref:
+ * https://bugzilla.kernel.org/show_bug.cgi?id=85991 - Comment #4 forward).
*/
static void quirk_cs5536_vsa(struct pci_dev *dev)
{
+ static char *name = "CS5536 ISA bridge";
+
if (pci_resource_len(dev, 0) != 8) {
- struct resource *res = &dev->resource[0];
- res->end = res->start + 8 - 1;
- dev_info(&dev->dev, "CS5536 ISA bridge bug detected (incorrect header); workaround applied\n");
+ quirk_io(dev, 0, 8, name); /* SMB */
+ quirk_io(dev, 1, 256, name); /* GPIO */
+ quirk_io(dev, 2, 64, name); /* MFGPT */
+ dev_info(&dev->dev, "%s bug detected (incorrect header); workaround applied\n",
+ name);
}
}
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_CS5536_ISA, quirk_cs5536_vsa);
@@ -3042,6 +3076,27 @@ static void quirk_no_bus_reset(struct pci_dev *dev)
*/
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ATHEROS, 0x0030, quirk_no_bus_reset);
+static void quirk_no_pm_reset(struct pci_dev *dev)
+{
+ /*
+ * We can't do a bus reset on root bus devices, but an ineffective
+ * PM reset may be better than nothing.
+ */
+ if (!pci_is_root_bus(dev->bus))
+ dev->dev_flags |= PCI_DEV_FLAGS_NO_PM_RESET;
+}
+
+/*
+ * Some AMD/ATI GPUS (HD8570 - Oland) report that a D3hot->D0 transition
+ * causes a reset (i.e., they advertise NoSoftRst-). This transition seems
+ * to have no effect on the device: it retains the framebuffer contents and
+ * monitor sync. Advertising this support makes other layers, like VFIO,
+ * assume pci_reset_function() is viable for this device. Mark it as
+ * unavailable to skip it when testing reset methods.
+ */
+DECLARE_PCI_FIXUP_CLASS_HEADER(PCI_VENDOR_ID_ATI, PCI_ANY_ID,
+ PCI_CLASS_DISPLAY_VGA, 8, quirk_no_pm_reset);
+
#ifdef CONFIG_ACPI
/*
* Apple: Shutdown Cactus Ridge Thunderbolt controller.
@@ -3542,6 +3597,44 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_JMICRON,
quirk_dma_func1_alias);
/*
+ * Some devices DMA with the wrong devfn, not just the wrong function.
+ * quirk_fixed_dma_alias() uses this table to create fixed aliases, where
+ * the alias is "fixed" and independent of the device devfn.
+ *
+ * For example, the Adaptec 3405 is a PCIe card with an Intel 80333 I/O
+ * processor. To software, this appears as a PCIe-to-PCI/X bridge with a
+ * single device on the secondary bus. In reality, the single exposed
+ * device at 0e.0 is the Address Translation Unit (ATU) of the controller
+ * that provides a bridge to the internal bus of the I/O processor. The
+ * controller supports private devices, which can be hidden from PCI config
+ * space. In the case of the Adaptec 3405, a private device at 01.0
+ * appears to be the DMA engine, which therefore needs to become a DMA
+ * alias for the device.
+ */
+static const struct pci_device_id fixed_dma_alias_tbl[] = {
+ { PCI_DEVICE_SUB(PCI_VENDOR_ID_ADAPTEC2, 0x0285,
+ PCI_VENDOR_ID_ADAPTEC2, 0x02bb), /* Adaptec 3405 */
+ .driver_data = PCI_DEVFN(1, 0) },
+ { 0 }
+};
+
+static void quirk_fixed_dma_alias(struct pci_dev *dev)
+{
+ const struct pci_device_id *id;
+
+ id = pci_match_id(fixed_dma_alias_tbl, dev);
+ if (id) {
+ dev->dma_alias_devfn = id->driver_data;
+ dev->dev_flags |= PCI_DEV_FLAGS_DMA_ALIAS_DEVFN;
+ dev_info(&dev->dev, "Enabling fixed DMA alias to %02x.%d\n",
+ PCI_SLOT(dev->dma_alias_devfn),
+ PCI_FUNC(dev->dma_alias_devfn));
+ }
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_ADAPTEC2, 0x0285, quirk_fixed_dma_alias);
+
+/*
* A few PCIe-to-PCI bridges fail to expose a PCIe capability, resulting in
* using the wrong DMA alias for the device. Some of these devices can be
* used as either forward or reverse bridges, so we need to test whether the
@@ -3644,6 +3737,9 @@ static const u16 pci_quirk_intel_pch_acs_ids[] = {
0x9c98, 0x9c99, 0x9c9a, 0x9c9b,
/* Patsburg (X79) PCH */
0x1d10, 0x1d12, 0x1d14, 0x1d16, 0x1d18, 0x1d1a, 0x1d1c, 0x1d1e,
+ /* Wellsburg (X99) PCH */
+ 0x8d10, 0x8d11, 0x8d12, 0x8d13, 0x8d14, 0x8d15, 0x8d16, 0x8d17,
+ 0x8d18, 0x8d19, 0x8d1a, 0x8d1b, 0x8d1c, 0x8d1d, 0x8d1e,
};
static bool pci_quirk_intel_pch_acs_match(struct pci_dev *dev)
@@ -3727,6 +3823,8 @@ static const struct pci_dev_acs_enabled {
{ PCI_VENDOR_ID_INTEL, 0x1551, pci_quirk_mf_endpoint_acs },
{ PCI_VENDOR_ID_INTEL, 0x1558, pci_quirk_mf_endpoint_acs },
{ PCI_VENDOR_ID_INTEL, PCI_ANY_ID, pci_quirk_intel_pch_acs },
+ { 0x19a2, 0x710, pci_quirk_mf_endpoint_acs }, /* Emulex BE3-R */
+ { 0x10df, 0x720, pci_quirk_mf_endpoint_acs }, /* Emulex Skyhawk-R */
{ 0 }
};
diff --git a/drivers/pci/rom.c b/drivers/pci/rom.c
index f955edb9bea7..eb0ad530dc43 100644
--- a/drivers/pci/rom.c
+++ b/drivers/pci/rom.c
@@ -71,6 +71,7 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
{
void __iomem *image;
int last_image;
+ unsigned length;
image = rom;
do {
@@ -93,9 +94,9 @@ size_t pci_get_rom_size(struct pci_dev *pdev, void __iomem *rom, size_t size)
if (readb(pds + 3) != 'R')
break;
last_image = readb(pds + 21) & 0x80;
- /* this length is reliable */
- image += readw(pds + 16) * 512;
- } while (!last_image);
+ length = readw(pds + 16);
+ image += length * 512;
+ } while (length && !last_image);
/* never return a size larger than the PCI resource window */
/* there are known ROMs that get the size wrong */
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig
index 910e90bf16c6..3bb49252a098 100644
--- a/drivers/pcmcia/Kconfig
+++ b/drivers/pcmcia/Kconfig
@@ -69,7 +69,8 @@ config YENTA
tristate "CardBus yenta-compatible bridge support"
depends on PCI
select CARDBUS if !EXPERT
- select PCCARD_NONSTATIC if PCMCIA != n
+ select PCCARD_NONSTATIC if PCMCIA != n && ISA
+ select PCCARD_PCI if PCMCIA !=n && !ISA
---help---
This option enables support for CardBus host bridges. Virtually
all modern PCMCIA bridges are CardBus compatible. A "bridge" is
@@ -109,7 +110,8 @@ config YENTA_TOSHIBA
config PD6729
tristate "Cirrus PD6729 compatible bridge support"
depends on PCMCIA && PCI
- select PCCARD_NONSTATIC
+ select PCCARD_NONSTATIC if PCMCIA != n && ISA
+ select PCCARD_PCI if PCMCIA !=n && !ISA
help
This provides support for the Cirrus PD6729 PCI-to-PCMCIA bridge
device, found in some older laptops and PCMCIA card readers.
@@ -117,7 +119,8 @@ config PD6729
config I82092
tristate "i82092 compatible bridge support"
depends on PCMCIA && PCI
- select PCCARD_NONSTATIC
+ select PCCARD_NONSTATIC if PCMCIA != n && ISA
+ select PCCARD_PCI if PCMCIA !=n && !ISA
help
This provides support for the Intel I82092AA PCI-to-PCMCIA bridge device,
found in some older laptops and more commonly in evaluation boards for the
@@ -276,6 +279,7 @@ config BFIN_CFPCMCIA
config AT91_CF
tristate "AT91 CompactFlash Controller"
depends on PCMCIA && ARCH_AT91
+ depends on !ARCH_MULTIPLATFORM
help
Say Y here to support the CompactFlash controller on AT91 chips.
Or choose M to compile the driver as a module named "at91_cf".
@@ -287,6 +291,9 @@ config ELECTRA_CF
Say Y here to support the CompactFlash controller on the
PA Semi Electra eval board.
+config PCCARD_PCI
+ bool
+
config PCCARD_NONSTATIC
bool
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile
index 27e94b30cf96..f1a7ca04d89e 100644
--- a/drivers/pcmcia/Makefile
+++ b/drivers/pcmcia/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_PCMCIA) += pcmcia.o
pcmcia_rsrc-y += rsrc_mgr.o
pcmcia_rsrc-$(CONFIG_PCCARD_NONSTATIC) += rsrc_nonstatic.o
pcmcia_rsrc-$(CONFIG_PCCARD_IODYN) += rsrc_iodyn.o
+pcmcia_rsrc-$(CONFIG_PCCARD_PCI) += rsrc_pci.o
obj-$(CONFIG_PCCARD) += pcmcia_rsrc.o
diff --git a/drivers/pcmcia/cistpl.c b/drivers/pcmcia/cistpl.c
index 884a984216fe..64d0515b76bd 100644
--- a/drivers/pcmcia/cistpl.c
+++ b/drivers/pcmcia/cistpl.c
@@ -168,9 +168,12 @@ int pcmcia_read_cis_mem(struct pcmcia_socket *s, int attr, u_int addr,
} else {
u_int inc = 1, card_offset, flags;
- if (addr > CISTPL_MAX_CIS_SIZE)
+ if (addr > CISTPL_MAX_CIS_SIZE) {
dev_dbg(&s->dev,
"attempt to read CIS mem at addr %#x", addr);
+ memset(ptr, 0xff, len);
+ return -1;
+ }
flags = MAP_ACTIVE | ((cis_width) ? MAP_16BIT : 0);
if (attr) {
@@ -1383,7 +1386,7 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
if (!s)
return -EINVAL;
- if (s->functions) {
+ if (s->functions || !(s->state & SOCKET_PRESENT)) {
WARN_ON(1);
return -EINVAL;
}
@@ -1448,10 +1451,26 @@ int pccard_validate_cis(struct pcmcia_socket *s, unsigned int *info)
done:
/* invalidate CIS cache on failure */
if (!dev_ok || !ident_ok || !count) {
- mutex_lock(&s->ops_mutex);
- destroy_cis_cache(s);
- mutex_unlock(&s->ops_mutex);
- ret = -EIO;
+#if defined(CONFIG_MTD_PCMCIA_ANONYMOUS)
+ /* Set up as an anonymous card. If we don't have anonymous
+ memory support then just error the card as there is no
+ point trying to second guess.
+
+ Note: some cards have just a device entry, it may be
+ worth extending support to cover these in future */
+ if (!dev_ok || !ident_ok) {
+ dev_info(&s->dev, "no CIS, assuming an anonymous memory card.\n");
+ pcmcia_replace_cis(s, "\xFF", 1);
+ count = 1;
+ ret = 0;
+ } else
+#endif
+ {
+ mutex_lock(&s->ops_mutex);
+ destroy_cis_cache(s);
+ mutex_unlock(&s->ops_mutex);
+ ret = -EIO;
+ }
}
if (info)
diff --git a/drivers/pcmcia/cs_internal.h b/drivers/pcmcia/cs_internal.h
index 7f1953f78b12..e86cd6b31773 100644
--- a/drivers/pcmcia/cs_internal.h
+++ b/drivers/pcmcia/cs_internal.h
@@ -80,9 +80,9 @@ struct pccard_resource_ops {
* Stuff internal to module "pcmcia_rsrc":
*/
extern int static_init(struct pcmcia_socket *s);
-extern struct resource *pcmcia_make_resource(unsigned long start,
- unsigned long end,
- int flags, const char *name);
+extern struct resource *pcmcia_make_resource(resource_size_t start,
+ resource_size_t end,
+ unsigned long flags, const char *name);
/*
* Stuff internal to module "pcmcia_core":
diff --git a/drivers/pcmcia/ds.c b/drivers/pcmcia/ds.c
index 757119b87146..d3baf0bfca9f 100644
--- a/drivers/pcmcia/ds.c
+++ b/drivers/pcmcia/ds.c
@@ -667,6 +667,9 @@ static void pcmcia_requery(struct pcmcia_socket *s)
{
int has_pfc;
+ if (!(s->state & SOCKET_PRESENT))
+ return;
+
if (s->functions == 0) {
pcmcia_card_add(s);
return;
diff --git a/drivers/pcmcia/rsrc_mgr.c b/drivers/pcmcia/rsrc_mgr.c
index aa628ed0e9f4..df2cb70aef5b 100644
--- a/drivers/pcmcia/rsrc_mgr.c
+++ b/drivers/pcmcia/rsrc_mgr.c
@@ -30,8 +30,9 @@ int static_init(struct pcmcia_socket *s)
return 0;
}
-struct resource *pcmcia_make_resource(unsigned long start, unsigned long end,
- int flags, const char *name)
+struct resource *pcmcia_make_resource(resource_size_t start,
+ resource_size_t end,
+ unsigned long flags, const char *name)
{
struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
diff --git a/drivers/pcmcia/rsrc_pci.c b/drivers/pcmcia/rsrc_pci.c
new file mode 100644
index 000000000000..1f67b3ba70fb
--- /dev/null
+++ b/drivers/pcmcia/rsrc_pci.c
@@ -0,0 +1,173 @@
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+
+#include <pcmcia/ss.h>
+#include <pcmcia/cistpl.h>
+#include "cs_internal.h"
+
+
+struct pcmcia_align_data {
+ unsigned long mask;
+ unsigned long offset;
+};
+
+static resource_size_t pcmcia_align(void *align_data,
+ const struct resource *res,
+ resource_size_t size, resource_size_t align)
+{
+ struct pcmcia_align_data *data = align_data;
+ resource_size_t start;
+
+ start = (res->start & ~data->mask) + data->offset;
+ if (start < res->start)
+ start += data->mask + 1;
+ return start;
+}
+
+static struct resource *find_io_region(struct pcmcia_socket *s,
+ unsigned long base, int num,
+ unsigned long align)
+{
+ struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_IO,
+ dev_name(&s->dev));
+ struct pcmcia_align_data data;
+ int ret;
+
+ data.mask = align - 1;
+ data.offset = base & data.mask;
+
+ ret = pci_bus_alloc_resource(s->cb_dev->bus, res, num, 1,
+ base, 0, pcmcia_align, &data);
+ if (ret != 0) {
+ kfree(res);
+ res = NULL;
+ }
+ return res;
+}
+
+static int res_pci_find_io(struct pcmcia_socket *s, unsigned int attr,
+ unsigned int *base, unsigned int num,
+ unsigned int align, struct resource **parent)
+{
+ int i, ret = 0;
+
+ /* Check for an already-allocated window that must conflict with
+ * what was asked for. It is a hack because it does not catch all
+ * potential conflicts, just the most obvious ones.
+ */
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ if (!s->io[i].res)
+ continue;
+
+ if (!*base)
+ continue;
+
+ if ((s->io[i].res->start & (align-1)) == *base)
+ return -EBUSY;
+ }
+
+ for (i = 0; i < MAX_IO_WIN; i++) {
+ struct resource *res = s->io[i].res;
+ unsigned int try;
+
+ if (res && (res->flags & IORESOURCE_BITS) !=
+ (attr & IORESOURCE_BITS))
+ continue;
+
+ if (!res) {
+ if (align == 0)
+ align = 0x10000;
+
+ res = s->io[i].res = find_io_region(s, *base, num,
+ align);
+ if (!res)
+ return -EINVAL;
+
+ *base = res->start;
+ s->io[i].res->flags =
+ ((res->flags & ~IORESOURCE_BITS) |
+ (attr & IORESOURCE_BITS));
+ s->io[i].InUse = num;
+ *parent = res;
+ return 0;
+ }
+
+ /* Try to extend top of window */
+ try = res->end + 1;
+ if ((*base == 0) || (*base == try)) {
+ ret = adjust_resource(s->io[i].res, res->start,
+ resource_size(res) + num);
+ if (ret)
+ continue;
+ *base = try;
+ s->io[i].InUse += num;
+ *parent = res;
+ return 0;
+ }
+
+ /* Try to extend bottom of window */
+ try = res->start - num;
+ if ((*base == 0) || (*base == try)) {
+ ret = adjust_resource(s->io[i].res,
+ res->start - num,
+ resource_size(res) + num);
+ if (ret)
+ continue;
+ *base = try;
+ s->io[i].InUse += num;
+ *parent = res;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static struct resource *res_pci_find_mem(u_long base, u_long num,
+ u_long align, int low, struct pcmcia_socket *s)
+{
+ struct resource *res = pcmcia_make_resource(0, num, IORESOURCE_MEM,
+ dev_name(&s->dev));
+ struct pcmcia_align_data data;
+ unsigned long min;
+ int ret;
+
+ if (align < 0x20000)
+ align = 0x20000;
+ data.mask = align - 1;
+ data.offset = base & data.mask;
+
+ min = 0;
+ if (!low)
+ min = 0x100000UL;
+
+ ret = pci_bus_alloc_resource(s->cb_dev->bus,
+ res, num, 1, min, 0,
+ pcmcia_align, &data);
+
+ if (ret != 0) {
+ kfree(res);
+ res = NULL;
+ }
+ return res;
+}
+
+
+static int res_pci_init(struct pcmcia_socket *s)
+{
+ if (!s->cb_dev || !(s->features & SS_CAP_PAGE_REGS)) {
+ dev_err(&s->dev, "not supported by res_pci\n");
+ return -EOPNOTSUPP;
+ }
+ return 0;
+}
+
+struct pccard_resource_ops pccard_nonstatic_ops = {
+ .validate_mem = NULL,
+ .find_io = res_pci_find_io,
+ .find_mem = res_pci_find_mem,
+ .init = res_pci_init,
+ .exit = NULL,
+};
+EXPORT_SYMBOL(pccard_nonstatic_ops);
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index ccad8809ecb1..2962de205ba7 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -239,6 +239,13 @@ config PHY_QCOM_IPQ806X_SATA
depends on OF
select GENERIC_PHY
+config PHY_ROCKCHIP_USB
+ tristate "Rockchip USB2 PHY Driver"
+ depends on ARCH_ROCKCHIP && OF
+ select GENERIC_PHY
+ help
+ Enable this to support the Rockchip USB 2.0 PHY.
+
config PHY_ST_SPEAR1310_MIPHY
tristate "ST SPEAR1310-MIPHY driver"
select GENERIC_PHY
@@ -277,4 +284,11 @@ config PHY_STIH41X_USB
Enable this to support the USB transceiver that is part of
STMicroelectronics STiH41x SoC series.
+config PHY_QCOM_UFS
+ tristate "Qualcomm UFS PHY driver"
+ depends on OF && ARCH_MSM
+ select GENERIC_PHY
+ help
+ Support for UFS PHY on QCOM chipsets.
+
endmenu
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index aa74f961e44e..f080e1bb2a74 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -28,9 +28,13 @@ phy-exynos-usb2-$(CONFIG_PHY_EXYNOS5250_USB2) += phy-exynos5250-usb2.o
phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2) += phy-s5pv210-usb2.o
obj-$(CONFIG_PHY_EXYNOS5_USBDRD) += phy-exynos5-usbdrd.o
obj-$(CONFIG_PHY_QCOM_APQ8064_SATA) += phy-qcom-apq8064-sata.o
+obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA) += phy-qcom-ipq806x-sata.o
obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY) += phy-spear1310-miphy.o
obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY) += phy-spear1340-miphy.o
obj-$(CONFIG_PHY_XGENE) += phy-xgene.o
obj-$(CONFIG_PHY_STIH407_USB) += phy-stih407-usb.o
obj-$(CONFIG_PHY_STIH41X_USB) += phy-stih41x-usb.o
+obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs.o
+obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-20nm.o
+obj-$(CONFIG_PHY_QCOM_UFS) += phy-qcom-ufs-qmp-14nm.o
diff --git a/drivers/phy/phy-armada375-usb2.c b/drivers/phy/phy-armada375-usb2.c
index ac7d99d01cb3..7c99ca256f05 100644
--- a/drivers/phy/phy-armada375-usb2.c
+++ b/drivers/phy/phy-armada375-usb2.c
@@ -118,8 +118,8 @@ static int armada375_usb_phy_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
usb_cluster_base = devm_ioremap_resource(&pdev->dev, res);
- if (!usb_cluster_base)
- return -ENOMEM;
+ if (IS_ERR(usb_cluster_base))
+ return PTR_ERR(usb_cluster_base);
phy = devm_phy_create(dev, NULL, &armada375_usb_phy_ops);
if (IS_ERR(phy)) {
diff --git a/drivers/phy/phy-exynos-mipi-video.c b/drivers/phy/phy-exynos-mipi-video.c
index 943e0f88a120..f017b2f2a54e 100644
--- a/drivers/phy/phy-exynos-mipi-video.c
+++ b/drivers/phy/phy-exynos-mipi-video.c
@@ -12,19 +12,18 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/mfd/syscon/exynos4-pmu.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/phy/phy.h>
#include <linux/platform_device.h>
+#include <linux/regmap.h>
#include <linux/spinlock.h>
+#include <linux/mfd/syscon.h>
-/* MIPI_PHYn_CONTROL register offset: n = 0..1 */
+/* MIPI_PHYn_CONTROL reg. offset (for base address from ioremap): n = 0..1 */
#define EXYNOS_MIPI_PHY_CONTROL(n) ((n) * 4)
-#define EXYNOS_MIPI_PHY_ENABLE (1 << 0)
-#define EXYNOS_MIPI_PHY_SRESETN (1 << 1)
-#define EXYNOS_MIPI_PHY_MRESETN (1 << 2)
-#define EXYNOS_MIPI_PHY_RESET_MASK (3 << 1)
enum exynos_mipi_phy_id {
EXYNOS_MIPI_PHY_ID_CSIS0,
@@ -38,43 +37,62 @@ enum exynos_mipi_phy_id {
((id) == EXYNOS_MIPI_PHY_ID_DSIM0 || (id) == EXYNOS_MIPI_PHY_ID_DSIM1)
struct exynos_mipi_video_phy {
- spinlock_t slock;
struct video_phy_desc {
struct phy *phy;
unsigned int index;
} phys[EXYNOS_MIPI_PHYS_NUM];
+ spinlock_t slock;
void __iomem *regs;
+ struct mutex mutex;
+ struct regmap *regmap;
};
static int __set_phy_state(struct exynos_mipi_video_phy *state,
enum exynos_mipi_phy_id id, unsigned int on)
{
+ const unsigned int offset = EXYNOS4_MIPI_PHY_CONTROL(id / 2);
void __iomem *addr;
- u32 reg, reset;
-
- addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
+ u32 val, reset;
if (is_mipi_dsim_phy_id(id))
- reset = EXYNOS_MIPI_PHY_MRESETN;
- else
- reset = EXYNOS_MIPI_PHY_SRESETN;
-
- spin_lock(&state->slock);
- reg = readl(addr);
- if (on)
- reg |= reset;
+ reset = EXYNOS4_MIPI_PHY_MRESETN;
else
- reg &= ~reset;
- writel(reg, addr);
-
- /* Clear ENABLE bit only if MRESETN, SRESETN bits are not set. */
- if (on)
- reg |= EXYNOS_MIPI_PHY_ENABLE;
- else if (!(reg & EXYNOS_MIPI_PHY_RESET_MASK))
- reg &= ~EXYNOS_MIPI_PHY_ENABLE;
+ reset = EXYNOS4_MIPI_PHY_SRESETN;
+
+ if (state->regmap) {
+ mutex_lock(&state->mutex);
+ regmap_read(state->regmap, offset, &val);
+ if (on)
+ val |= reset;
+ else
+ val &= ~reset;
+ regmap_write(state->regmap, offset, val);
+ if (on)
+ val |= EXYNOS4_MIPI_PHY_ENABLE;
+ else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
+ val &= ~EXYNOS4_MIPI_PHY_ENABLE;
+ regmap_write(state->regmap, offset, val);
+ mutex_unlock(&state->mutex);
+ } else {
+ addr = state->regs + EXYNOS_MIPI_PHY_CONTROL(id / 2);
+
+ spin_lock(&state->slock);
+ val = readl(addr);
+ if (on)
+ val |= reset;
+ else
+ val &= ~reset;
+ writel(val, addr);
+ /* Clear ENABLE bit only if MRESETN, SRESETN bits are not set */
+ if (on)
+ val |= EXYNOS4_MIPI_PHY_ENABLE;
+ else if (!(val & EXYNOS4_MIPI_PHY_RESET_MASK))
+ val &= ~EXYNOS4_MIPI_PHY_ENABLE;
+
+ writel(val, addr);
+ spin_unlock(&state->slock);
+ }
- writel(reg, addr);
- spin_unlock(&state->slock);
return 0;
}
@@ -118,7 +136,6 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
{
struct exynos_mipi_video_phy *state;
struct device *dev = &pdev->dev;
- struct resource *res;
struct phy_provider *phy_provider;
unsigned int i;
@@ -126,14 +143,22 @@ static int exynos_mipi_video_phy_probe(struct platform_device *pdev)
if (!state)
return -ENOMEM;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ state->regmap = syscon_regmap_lookup_by_phandle(dev->of_node, "syscon");
+ if (IS_ERR(state->regmap)) {
+ struct resource *res;
- state->regs = devm_ioremap_resource(dev, res);
- if (IS_ERR(state->regs))
- return PTR_ERR(state->regs);
+ dev_info(dev, "regmap lookup failed: %ld\n",
+ PTR_ERR(state->regmap));
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ state->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(state->regs))
+ return PTR_ERR(state->regs);
+ }
dev_set_drvdata(dev, state);
spin_lock_init(&state->slock);
+ mutex_init(&state->mutex);
for (i = 0; i < EXYNOS_MIPI_PHYS_NUM; i++) {
struct phy *phy = devm_phy_create(dev, NULL,
diff --git a/drivers/phy/phy-miphy28lp.c b/drivers/phy/phy-miphy28lp.c
index 27fa62ce6136..9b2848e6115d 100644
--- a/drivers/phy/phy-miphy28lp.c
+++ b/drivers/phy/phy-miphy28lp.c
@@ -194,6 +194,14 @@
#define MIPHY_SATA_BANK_NB 3
#define MIPHY_PCIE_BANK_NB 2
+enum {
+ SYSCFG_CTRL,
+ SYSCFG_STATUS,
+ SYSCFG_PCI,
+ SYSCFG_SATA,
+ SYSCFG_REG_MAX,
+};
+
struct miphy28lp_phy {
struct phy *phy;
struct miphy28lp_dev *phydev;
@@ -211,10 +219,7 @@ struct miphy28lp_phy {
u32 sata_gen;
/* Sysconfig registers offsets needed to configure the device */
- u32 syscfg_miphy_ctrl;
- u32 syscfg_miphy_status;
- u32 syscfg_pci;
- u32 syscfg_sata;
+ u32 syscfg_reg[SYSCFG_REG_MAX];
u8 type;
};
@@ -834,12 +839,12 @@ static int miphy_osc_is_ready(struct miphy28lp_phy *miphy_phy)
if (!miphy_phy->osc_rdy)
return 0;
- if (!miphy_phy->syscfg_miphy_status)
+ if (!miphy_phy->syscfg_reg[SYSCFG_STATUS])
return -EINVAL;
do {
- regmap_read(miphy_dev->regmap, miphy_phy->syscfg_miphy_status,
- &val);
+ regmap_read(miphy_dev->regmap,
+ miphy_phy->syscfg_reg[SYSCFG_STATUS], &val);
if ((val & MIPHY_OSC_RDY) != MIPHY_OSC_RDY)
cpu_relax();
@@ -888,7 +893,7 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
int err;
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
- if (!miphy_phy->syscfg_miphy_ctrl)
+ if (!miphy_phy->syscfg_reg[SYSCFG_CTRL])
return -EINVAL;
err = reset_control_assert(miphy_phy->miphy_rst);
@@ -900,7 +905,8 @@ static int miphy28lp_setup(struct miphy28lp_phy *miphy_phy, u32 miphy_val)
if (miphy_phy->osc_force_ext)
miphy_val |= MIPHY_OSC_FORCE_EXT;
- regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_miphy_ctrl,
+ regmap_update_bits(miphy_dev->regmap,
+ miphy_phy->syscfg_reg[SYSCFG_CTRL],
MIPHY_CTRL_MASK, miphy_val);
err = reset_control_deassert(miphy_phy->miphy_rst);
@@ -917,8 +923,9 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
int err, sata_conf = SATA_CTRL_SELECT_SATA;
- if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
- || (!miphy_phy->base))
+ if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
+ (!miphy_phy->syscfg_reg[SYSCFG_PCI]) ||
+ (!miphy_phy->base))
return -EINVAL;
dev_info(miphy_dev->dev, "sata-up mode, addr 0x%p\n", miphy_phy->base);
@@ -926,10 +933,11 @@ static int miphy28lp_init_sata(struct miphy28lp_phy *miphy_phy)
/* Configure the glue-logic */
sata_conf |= ((miphy_phy->sata_gen - SATA_GEN1) << SATA_SPDMODE);
- regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
+ regmap_update_bits(miphy_dev->regmap,
+ miphy_phy->syscfg_reg[SYSCFG_SATA],
SATA_CTRL_MASK, sata_conf);
- regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
PCIE_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
/* MiPHY path and clocking init */
@@ -951,17 +959,19 @@ static int miphy28lp_init_pcie(struct miphy28lp_phy *miphy_phy)
struct miphy28lp_dev *miphy_dev = miphy_phy->phydev;
int err;
- if ((!miphy_phy->syscfg_sata) || (!miphy_phy->syscfg_pci)
+ if ((!miphy_phy->syscfg_reg[SYSCFG_SATA]) ||
+ (!miphy_phy->syscfg_reg[SYSCFG_PCI])
|| (!miphy_phy->base) || (!miphy_phy->pipebase))
return -EINVAL;
dev_info(miphy_dev->dev, "pcie-up mode, addr 0x%p\n", miphy_phy->base);
/* Configure the glue-logic */
- regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_sata,
+ regmap_update_bits(miphy_dev->regmap,
+ miphy_phy->syscfg_reg[SYSCFG_SATA],
SATA_CTRL_MASK, SATA_CTRL_SELECT_PCIE);
- regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_pci,
+ regmap_update_bits(miphy_dev->regmap, miphy_phy->syscfg_reg[SYSCFG_PCI],
PCIE_CTRL_MASK, SYSCFG_PCIE_PCIE_VAL);
/* MiPHY path and clocking init */
@@ -1156,7 +1166,8 @@ static int miphy28lp_probe_resets(struct device_node *node,
static int miphy28lp_of_probe(struct device_node *np,
struct miphy28lp_phy *miphy_phy)
{
- struct resource res;
+ int i;
+ u32 ctrlreg;
miphy_phy->osc_force_ext =
of_property_read_bool(np, "st,osc-force-ext");
@@ -1175,18 +1186,10 @@ static int miphy28lp_of_probe(struct device_node *np,
if (!miphy_phy->sata_gen)
miphy_phy->sata_gen = SATA_GEN1;
- if (!miphy28lp_get_resource_byname(np, "miphy-ctrl-glue", &res))
- miphy_phy->syscfg_miphy_ctrl = res.start;
-
- if (!miphy28lp_get_resource_byname(np, "miphy-status-glue", &res))
- miphy_phy->syscfg_miphy_status = res.start;
-
- if (!miphy28lp_get_resource_byname(np, "pcie-glue", &res))
- miphy_phy->syscfg_pci = res.start;
-
- if (!miphy28lp_get_resource_byname(np, "sata-glue", &res))
- miphy_phy->syscfg_sata = res.start;
-
+ for (i = 0; i < SYSCFG_REG_MAX; i++) {
+ if (!of_property_read_u32_index(np, "st,syscfg", i, &ctrlreg))
+ miphy_phy->syscfg_reg[i] = ctrlreg;
+ }
return 0;
}
diff --git a/drivers/phy/phy-miphy365x.c b/drivers/phy/phy-miphy365x.c
index 6ab43a814ad2..6c80154e8bff 100644
--- a/drivers/phy/phy-miphy365x.c
+++ b/drivers/phy/phy-miphy365x.c
@@ -141,7 +141,7 @@ struct miphy365x_phy {
bool pcie_tx_pol_inv;
bool sata_tx_pol_inv;
u32 sata_gen;
- u64 ctrlreg;
+ u32 ctrlreg;
u8 type;
};
@@ -179,7 +179,7 @@ static int miphy365x_set_path(struct miphy365x_phy *miphy_phy,
bool sata = (miphy_phy->type == MIPHY_TYPE_SATA);
return regmap_update_bits(miphy_dev->regmap,
- (unsigned int)miphy_phy->ctrlreg,
+ miphy_phy->ctrlreg,
SYSCFG_SELECT_SATA_MASK,
sata << SYSCFG_SELECT_SATA_POS);
}
@@ -445,7 +445,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy,
{
struct device_node *phynode = miphy_phy->phy->dev.of_node;
const char *name;
- const __be32 *taddr;
int type = miphy_phy->type;
int ret;
@@ -455,22 +454,6 @@ int miphy365x_get_addr(struct device *dev, struct miphy365x_phy *miphy_phy,
return ret;
}
- if (!strncmp(name, "syscfg", 6)) {
- taddr = of_get_address(phynode, index, NULL, NULL);
- if (!taddr) {
- dev_err(dev, "failed to fetch syscfg address\n");
- return -EINVAL;
- }
-
- miphy_phy->ctrlreg = of_translate_address(phynode, taddr);
- if (miphy_phy->ctrlreg == OF_BAD_ADDR) {
- dev_err(dev, "failed to translate syscfg address\n");
- return -EINVAL;
- }
-
- return 0;
- }
-
if (!((!strncmp(name, "sata", 4) && type == MIPHY_TYPE_SATA) ||
(!strncmp(name, "pcie", 4) && type == MIPHY_TYPE_PCIE)))
return 0;
@@ -606,7 +589,15 @@ static int miphy365x_probe(struct platform_device *pdev)
return ret;
phy_set_drvdata(phy, miphy_dev->phys[port]);
+
port++;
+ /* sysconfig offsets are indexed from 1 */
+ ret = of_property_read_u32_index(np, "st,syscfg", port,
+ &miphy_phy->ctrlreg);
+ if (ret) {
+ dev_err(&pdev->dev, "No sysconfig offset found\n");
+ return ret;
+ }
}
provider = devm_of_phy_provider_register(&pdev->dev, miphy365x_xlate);
diff --git a/drivers/phy/phy-qcom-ufs-i.h b/drivers/phy/phy-qcom-ufs-i.h
new file mode 100644
index 000000000000..591a39175e8a
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-i.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UFS_QCOM_PHY_I_H_
+#define UFS_QCOM_PHY_I_H_
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/regulator/consumer.h>
+#include <linux/slab.h>
+#include <linux/phy/phy-qcom-ufs.h>
+#include <linux/platform_device.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+
+#define readl_poll_timeout(addr, val, cond, sleep_us, timeout_us) \
+({ \
+ ktime_t timeout = ktime_add_us(ktime_get(), timeout_us); \
+ might_sleep_if(timeout_us); \
+ for (;;) { \
+ (val) = readl(addr); \
+ if (cond) \
+ break; \
+ if (timeout_us && ktime_compare(ktime_get(), timeout) > 0) { \
+ (val) = readl(addr); \
+ break; \
+ } \
+ if (sleep_us) \
+ usleep_range(DIV_ROUND_UP(sleep_us, 4), sleep_us); \
+ } \
+ (cond) ? 0 : -ETIMEDOUT; \
+})
+
+#define UFS_QCOM_PHY_CAL_ENTRY(reg, val) \
+ { \
+ .reg_offset = reg, \
+ .cfg_value = val, \
+ }
+
+#define UFS_QCOM_PHY_NAME_LEN 30
+
+enum {
+ MASK_SERDES_START = 0x1,
+ MASK_PCS_READY = 0x1,
+};
+
+enum {
+ OFFSET_SERDES_START = 0x0,
+};
+
+struct ufs_qcom_phy_stored_attributes {
+ u32 att;
+ u32 value;
+};
+
+
+struct ufs_qcom_phy_calibration {
+ u32 reg_offset;
+ u32 cfg_value;
+};
+
+struct ufs_qcom_phy_vreg {
+ const char *name;
+ struct regulator *reg;
+ int max_uA;
+ int min_uV;
+ int max_uV;
+ bool enabled;
+ bool is_always_on;
+};
+
+struct ufs_qcom_phy {
+ struct list_head list;
+ struct device *dev;
+ void __iomem *mmio;
+ void __iomem *dev_ref_clk_ctrl_mmio;
+ struct clk *tx_iface_clk;
+ struct clk *rx_iface_clk;
+ bool is_iface_clk_enabled;
+ struct clk *ref_clk_src;
+ struct clk *ref_clk_parent;
+ struct clk *ref_clk;
+ bool is_ref_clk_enabled;
+ bool is_dev_ref_clk_enabled;
+ struct ufs_qcom_phy_vreg vdda_pll;
+ struct ufs_qcom_phy_vreg vdda_phy;
+ struct ufs_qcom_phy_vreg vddp_ref_clk;
+ unsigned int quirks;
+
+ /*
+ * If UFS link is put into Hibern8 and if UFS PHY analog hardware is
+ * power collapsed (by clearing UFS_PHY_POWER_DOWN_CONTROL), Hibern8
+ * exit might fail even after powering on UFS PHY analog hardware.
+ * Enabling this quirk will help to solve above issue by doing
+ * custom PHY settings just before PHY analog power collapse.
+ */
+ #define UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE BIT(0)
+
+ u8 host_ctrl_rev_major;
+ u16 host_ctrl_rev_minor;
+ u16 host_ctrl_rev_step;
+
+ char name[UFS_QCOM_PHY_NAME_LEN];
+ struct ufs_qcom_phy_calibration *cached_regs;
+ int cached_regs_table_size;
+ bool is_powered_on;
+ struct ufs_qcom_phy_specific_ops *phy_spec_ops;
+};
+
+/**
+ * struct ufs_qcom_phy_specific_ops - set of pointers to functions which have a
+ * specific implementation per phy. Each UFS phy, should implement
+ * those functions according to its spec and requirements
+ * @calibrate_phy: pointer to a function that calibrate the phy
+ * @start_serdes: pointer to a function that starts the serdes
+ * @is_physical_coding_sublayer_ready: pointer to a function that
+ * checks pcs readiness. returns 0 for success and non-zero for error.
+ * @set_tx_lane_enable: pointer to a function that enable tx lanes
+ * @power_control: pointer to a function that controls analog rail of phy
+ * and writes to QSERDES_RX_SIGDET_CNTRL attribute
+ */
+struct ufs_qcom_phy_specific_ops {
+ int (*calibrate_phy)(struct ufs_qcom_phy *phy, bool is_rate_B);
+ void (*start_serdes)(struct ufs_qcom_phy *phy);
+ int (*is_physical_coding_sublayer_ready)(struct ufs_qcom_phy *phy);
+ void (*set_tx_lane_enable)(struct ufs_qcom_phy *phy, u32 val);
+ void (*power_control)(struct ufs_qcom_phy *phy, bool val);
+};
+
+struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy);
+int ufs_qcom_phy_power_on(struct phy *generic_phy);
+int ufs_qcom_phy_power_off(struct phy *generic_phy);
+int ufs_qcom_phy_exit(struct phy *generic_phy);
+int ufs_qcom_phy_init_clks(struct phy *generic_phy,
+ struct ufs_qcom_phy *phy_common);
+int ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
+ struct ufs_qcom_phy *phy_common);
+int ufs_qcom_phy_remove(struct phy *generic_phy,
+ struct ufs_qcom_phy *ufs_qcom_phy);
+struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
+ struct ufs_qcom_phy *common_cfg,
+ struct phy_ops *ufs_qcom_phy_gen_ops,
+ struct ufs_qcom_phy_specific_ops *phy_spec_ops);
+int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+ struct ufs_qcom_phy_calibration *tbl_A, int tbl_size_A,
+ struct ufs_qcom_phy_calibration *tbl_B, int tbl_size_B,
+ bool is_rate_B);
+#endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.c b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
new file mode 100644
index 000000000000..f5fc50a9fce7
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.c
@@ -0,0 +1,201 @@
+/*
+ * Copyright (c) 2013-2015, 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 "phy-qcom-ufs-qmp-14nm.h"
+
+#define UFS_PHY_NAME "ufs_phy_qmp_14nm"
+#define UFS_PHY_VDDA_PHY_UV (925000)
+
+static
+int ufs_qcom_phy_qmp_14nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+ bool is_rate_B)
+{
+ int tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A);
+ int tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
+ int err;
+
+ err = ufs_qcom_phy_calibrate(ufs_qcom_phy, phy_cal_table_rate_A,
+ tbl_size_A, phy_cal_table_rate_B, tbl_size_B, is_rate_B);
+
+ if (err)
+ dev_err(ufs_qcom_phy->dev,
+ "%s: ufs_qcom_phy_calibrate() failed %d\n",
+ __func__, err);
+ return err;
+}
+
+static
+void ufs_qcom_phy_qmp_14nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
+{
+ phy_common->quirks =
+ UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
+}
+
+static int ufs_qcom_phy_qmp_14nm_init(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy_qmp_14nm *phy = phy_get_drvdata(generic_phy);
+ struct ufs_qcom_phy *phy_common = &phy->common_cfg;
+ int err;
+
+ err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+ phy_common->vdda_phy.max_uV = UFS_PHY_VDDA_PHY_UV;
+ phy_common->vdda_phy.min_uV = UFS_PHY_VDDA_PHY_UV;
+
+ ufs_qcom_phy_qmp_14nm_advertise_quirks(phy_common);
+
+out:
+ return err;
+}
+
+static
+void ufs_qcom_phy_qmp_14nm_power_control(struct ufs_qcom_phy *phy, bool val)
+{
+ writel_relaxed(val ? 0x1 : 0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+ /*
+ * Before any transactions involving PHY, ensure PHY knows
+ * that it's analog rail is powered ON (or OFF).
+ */
+ mb();
+}
+
+static inline
+void ufs_qcom_phy_qmp_14nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val)
+{
+ /*
+ * 14nm PHY does not have TX_LANE_ENABLE register.
+ * Implement this function so as not to propagate error to caller.
+ */
+}
+
+static inline void ufs_qcom_phy_qmp_14nm_start_serdes(struct ufs_qcom_phy *phy)
+{
+ u32 tmp;
+
+ tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
+ tmp &= ~MASK_SERDES_START;
+ tmp |= (1 << OFFSET_SERDES_START);
+ writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
+ /* Ensure register value is committed */
+ mb();
+}
+
+static int ufs_qcom_phy_qmp_14nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
+{
+ int err = 0;
+ u32 val;
+
+ err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
+ val, (val & MASK_PCS_READY), 10, 1000000);
+ if (err)
+ dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
+ __func__, err);
+ return err;
+}
+
+static struct phy_ops ufs_qcom_phy_qmp_14nm_phy_ops = {
+ .init = ufs_qcom_phy_qmp_14nm_init,
+ .exit = ufs_qcom_phy_exit,
+ .power_on = ufs_qcom_phy_power_on,
+ .power_off = ufs_qcom_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct ufs_qcom_phy_specific_ops phy_14nm_ops = {
+ .calibrate_phy = ufs_qcom_phy_qmp_14nm_phy_calibrate,
+ .start_serdes = ufs_qcom_phy_qmp_14nm_start_serdes,
+ .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_14nm_is_pcs_ready,
+ .set_tx_lane_enable = ufs_qcom_phy_qmp_14nm_set_tx_lane_enable,
+ .power_control = ufs_qcom_phy_qmp_14nm_power_control,
+};
+
+static int ufs_qcom_phy_qmp_14nm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy;
+ struct ufs_qcom_phy_qmp_14nm *phy;
+ int err = 0;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ dev_err(dev, "%s: failed to allocate phy\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
+ &ufs_qcom_phy_qmp_14nm_phy_ops, &phy_14nm_ops);
+
+ if (!generic_phy) {
+ dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
+ __func__);
+ err = -EIO;
+ goto out;
+ }
+
+ phy_set_drvdata(generic_phy, phy);
+
+ strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
+ sizeof(phy->common_cfg.name));
+
+out:
+ return err;
+}
+
+static int ufs_qcom_phy_qmp_14nm_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy = to_phy(dev);
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int err = 0;
+
+ err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
+ if (err)
+ dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
+ __func__, err);
+
+ return err;
+}
+
+static const struct of_device_id ufs_qcom_phy_qmp_14nm_of_match[] = {
+ {.compatible = "qcom,ufs-phy-qmp-14nm"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_14nm_of_match);
+
+static struct platform_driver ufs_qcom_phy_qmp_14nm_driver = {
+ .probe = ufs_qcom_phy_qmp_14nm_probe,
+ .remove = ufs_qcom_phy_qmp_14nm_remove,
+ .driver = {
+ .of_match_table = ufs_qcom_phy_qmp_14nm_of_match,
+ .name = "ufs_qcom_phy_qmp_14nm",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(ufs_qcom_phy_qmp_14nm_driver);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 14nm");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-ufs-qmp-14nm.h b/drivers/phy/phy-qcom-ufs-qmp-14nm.h
new file mode 100644
index 000000000000..3aefdbacbcd0
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-14nm.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UFS_QCOM_PHY_QMP_14NM_H_
+#define UFS_QCOM_PHY_QMP_14NM_H_
+
+#include "phy-qcom-ufs-i.h"
+
+/* QCOM UFS PHY control registers */
+#define COM_OFF(x) (0x000 + x)
+#define PHY_OFF(x) (0xC00 + x)
+#define TX_OFF(n, x) (0x400 + (0x400 * n) + x)
+#define RX_OFF(n, x) (0x600 + (0x400 * n) + x)
+
+/* UFS PHY QSERDES COM registers */
+#define QSERDES_COM_BG_TIMER COM_OFF(0x0C)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x34)
+#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x3C)
+#define QSERDES_COM_LOCK_CMP1_MODE0 COM_OFF(0x4C)
+#define QSERDES_COM_LOCK_CMP2_MODE0 COM_OFF(0x50)
+#define QSERDES_COM_LOCK_CMP3_MODE0 COM_OFF(0x54)
+#define QSERDES_COM_LOCK_CMP1_MODE1 COM_OFF(0x58)
+#define QSERDES_COM_LOCK_CMP2_MODE1 COM_OFF(0x5C)
+#define QSERDES_COM_LOCK_CMP3_MODE1 COM_OFF(0x60)
+#define QSERDES_COM_CP_CTRL_MODE0 COM_OFF(0x78)
+#define QSERDES_COM_CP_CTRL_MODE1 COM_OFF(0x7C)
+#define QSERDES_COM_PLL_RCTRL_MODE0 COM_OFF(0x84)
+#define QSERDES_COM_PLL_RCTRL_MODE1 COM_OFF(0x88)
+#define QSERDES_COM_PLL_CCTRL_MODE0 COM_OFF(0x90)
+#define QSERDES_COM_PLL_CCTRL_MODE1 COM_OFF(0x94)
+#define QSERDES_COM_SYSCLK_EN_SEL COM_OFF(0xAC)
+#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0xB4)
+#define QSERDES_COM_LOCK_CMP_EN COM_OFF(0xC8)
+#define QSERDES_COM_LOCK_CMP_CFG COM_OFF(0xCC)
+#define QSERDES_COM_DEC_START_MODE0 COM_OFF(0xD0)
+#define QSERDES_COM_DEC_START_MODE1 COM_OFF(0xD4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE0 COM_OFF(0xDC)
+#define QSERDES_COM_DIV_FRAC_START2_MODE0 COM_OFF(0xE0)
+#define QSERDES_COM_DIV_FRAC_START3_MODE0 COM_OFF(0xE4)
+#define QSERDES_COM_DIV_FRAC_START1_MODE1 COM_OFF(0xE8)
+#define QSERDES_COM_DIV_FRAC_START2_MODE1 COM_OFF(0xEC)
+#define QSERDES_COM_DIV_FRAC_START3_MODE1 COM_OFF(0xF0)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE0 COM_OFF(0x108)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE0 COM_OFF(0x10C)
+#define QSERDES_COM_INTEGLOOP_GAIN0_MODE1 COM_OFF(0x110)
+#define QSERDES_COM_INTEGLOOP_GAIN1_MODE1 COM_OFF(0x114)
+#define QSERDES_COM_VCO_TUNE_CTRL COM_OFF(0x124)
+#define QSERDES_COM_VCO_TUNE_MAP COM_OFF(0x128)
+#define QSERDES_COM_VCO_TUNE1_MODE0 COM_OFF(0x12C)
+#define QSERDES_COM_VCO_TUNE2_MODE0 COM_OFF(0x130)
+#define QSERDES_COM_VCO_TUNE1_MODE1 COM_OFF(0x134)
+#define QSERDES_COM_VCO_TUNE2_MODE1 COM_OFF(0x138)
+#define QSERDES_COM_VCO_TUNE_TIMER1 COM_OFF(0x144)
+#define QSERDES_COM_VCO_TUNE_TIMER2 COM_OFF(0x148)
+#define QSERDES_COM_CLK_SELECT COM_OFF(0x174)
+#define QSERDES_COM_HSCLK_SEL COM_OFF(0x178)
+#define QSERDES_COM_CORECLK_DIV COM_OFF(0x184)
+#define QSERDES_COM_CORE_CLK_EN COM_OFF(0x18C)
+#define QSERDES_COM_CMN_CONFIG COM_OFF(0x194)
+#define QSERDES_COM_SVS_MODE_CLK_SEL COM_OFF(0x19C)
+#define QSERDES_COM_CORECLK_DIV_MODE1 COM_OFF(0x1BC)
+
+/* UFS PHY registers */
+#define UFS_PHY_PHY_START PHY_OFF(0x00)
+#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x04)
+#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x168)
+
+/* UFS PHY TX registers */
+#define QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN TX_OFF(0, 0x68)
+#define QSERDES_TX_LANE_MODE TX_OFF(0, 0x94)
+
+/* UFS PHY RX registers */
+#define QSERDES_RX_UCDR_FASTLOCK_FO_GAIN RX_OFF(0, 0x40)
+#define QSERDES_RX_RX_TERM_BW RX_OFF(0, 0x90)
+#define QSERDES_RX_RX_EQ_GAIN1_LSB RX_OFF(0, 0xC4)
+#define QSERDES_RX_RX_EQ_GAIN1_MSB RX_OFF(0, 0xC8)
+#define QSERDES_RX_RX_EQ_GAIN2_LSB RX_OFF(0, 0xCC)
+#define QSERDES_RX_RX_EQ_GAIN2_MSB RX_OFF(0, 0xD0)
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2 RX_OFF(0, 0xD8)
+#define QSERDES_RX_SIGDET_CNTRL RX_OFF(0, 0x114)
+#define QSERDES_RX_SIGDET_LVL RX_OFF(0, 0x118)
+#define QSERDES_RX_SIGDET_DEGLITCH_CNTRL RX_OFF(0, 0x11C)
+#define QSERDES_RX_RX_INTERFACE_MODE RX_OFF(0, 0x12C)
+
+/*
+ * This structure represents the 14nm specific phy.
+ * common_cfg MUST remain the first field in this structure
+ * in case extra fields are added. This way, when calling
+ * get_ufs_qcom_phy() of generic phy, we can extract the
+ * common phy structure (struct ufs_qcom_phy) out of it
+ * regardless of the relevant specific phy.
+ */
+struct ufs_qcom_phy_qmp_14nm {
+ struct ufs_qcom_phy common_cfg;
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_A[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CMN_CONFIG, 0x0e),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL, 0xd7),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CLK_SELECT, 0x30),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYS_CLK_CTRL, 0x06),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BG_TIMER, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_HSCLK_SEL, 0x05),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORECLK_DIV_MODE1, 0x0a),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_EN, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_CTRL, 0x10),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x20),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CORE_CLK_EN, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP_CFG, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER1, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_TIMER2, 0x3f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x14),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SVS_MODE_CLK_SEL, 0x05),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE0, 0x82),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE0, 0x0b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE0, 0x16),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE0, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE0, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE0, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE0, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE0, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE0, 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE0, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START_MODE1, 0x98),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_CP_CTRL_MODE1, 0x0b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RCTRL_MODE1, 0x16),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CCTRL_MODE1, 0x28),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN0_MODE1, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_INTEGLOOP_GAIN1_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE1_MODE1, 0xd6),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE2_MODE1, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP1_MODE1, 0x32),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP2_MODE1, 0x0f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_LOCK_CMP3_MODE1, 0x00),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_HIGHZ_TRANSCEIVER_BIAS_DRVR_EN, 0x45),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE, 0x02),
+
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_LVL, 0x24),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_CNTRL, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_INTERFACE_MODE, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_SIGDET_DEGLITCH_CNTRL, 0x18),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_UCDR_FASTLOCK_FO_GAIN, 0x0B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_TERM_BW, 0x5B),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB, 0x3F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB, 0xFF),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB, 0x0F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2, 0x0E),
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_VCO_TUNE_MAP, 0x54),
+};
+
+#endif
diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.c b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
new file mode 100644
index 000000000000..8332f96b2c4a
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.c
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) 2013-2015, 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 "phy-qcom-ufs-qmp-20nm.h"
+
+#define UFS_PHY_NAME "ufs_phy_qmp_20nm"
+
+static
+int ufs_qcom_phy_qmp_20nm_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+ bool is_rate_B)
+{
+ struct ufs_qcom_phy_calibration *tbl_A, *tbl_B;
+ int tbl_size_A, tbl_size_B;
+ u8 major = ufs_qcom_phy->host_ctrl_rev_major;
+ u16 minor = ufs_qcom_phy->host_ctrl_rev_minor;
+ u16 step = ufs_qcom_phy->host_ctrl_rev_step;
+ int err;
+
+ if ((major == 0x1) && (minor == 0x002) && (step == 0x0000)) {
+ tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_2_0);
+ tbl_A = phy_cal_table_rate_A_1_2_0;
+ } else if ((major == 0x1) && (minor == 0x003) && (step == 0x0000)) {
+ tbl_size_A = ARRAY_SIZE(phy_cal_table_rate_A_1_3_0);
+ tbl_A = phy_cal_table_rate_A_1_3_0;
+ } else {
+ dev_err(ufs_qcom_phy->dev, "%s: Unknown UFS-PHY version, no calibration values\n",
+ __func__);
+ err = -ENODEV;
+ goto out;
+ }
+
+ tbl_size_B = ARRAY_SIZE(phy_cal_table_rate_B);
+ tbl_B = phy_cal_table_rate_B;
+
+ err = ufs_qcom_phy_calibrate(ufs_qcom_phy, tbl_A, tbl_size_A,
+ tbl_B, tbl_size_B, is_rate_B);
+
+ if (err)
+ dev_err(ufs_qcom_phy->dev, "%s: ufs_qcom_phy_calibrate() failed %d\n",
+ __func__, err);
+
+out:
+ return err;
+}
+
+static
+void ufs_qcom_phy_qmp_20nm_advertise_quirks(struct ufs_qcom_phy *phy_common)
+{
+ phy_common->quirks =
+ UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
+}
+
+static int ufs_qcom_phy_qmp_20nm_init(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy_qmp_20nm *phy = phy_get_drvdata(generic_phy);
+ struct ufs_qcom_phy *phy_common = &phy->common_cfg;
+ int err = 0;
+
+ err = ufs_qcom_phy_init_clks(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_clks() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ err = ufs_qcom_phy_init_vregulators(generic_phy, phy_common);
+ if (err) {
+ dev_err(phy_common->dev, "%s: ufs_qcom_phy_init_vregulators() failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ ufs_qcom_phy_qmp_20nm_advertise_quirks(phy_common);
+
+out:
+ return err;
+}
+
+static
+void ufs_qcom_phy_qmp_20nm_power_control(struct ufs_qcom_phy *phy, bool val)
+{
+ bool hibern8_exit_after_pwr_collapse = phy->quirks &
+ UFS_QCOM_PHY_QUIRK_HIBERN8_EXIT_AFTER_PHY_PWR_COLLAPSE;
+
+ if (val) {
+ writel_relaxed(0x1, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+ /*
+ * Before any transactions involving PHY, ensure PHY knows
+ * that it's analog rail is powered ON.
+ */
+ mb();
+
+ if (hibern8_exit_after_pwr_collapse) {
+ /*
+ * Give atleast 1us delay after restoring PHY analog
+ * power.
+ */
+ usleep_range(1, 2);
+ writel_relaxed(0x0A, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+ writel_relaxed(0x08, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+ /*
+ * Make sure workaround is deactivated before proceeding
+ * with normal PHY operations.
+ */
+ mb();
+ }
+ } else {
+ if (hibern8_exit_after_pwr_collapse) {
+ writel_relaxed(0x0A, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+ writel_relaxed(0x02, phy->mmio +
+ QSERDES_COM_SYSCLK_EN_SEL_TXBAND);
+ /*
+ * Make sure that above workaround is activated before
+ * PHY analog power collapse.
+ */
+ mb();
+ }
+
+ writel_relaxed(0x0, phy->mmio + UFS_PHY_POWER_DOWN_CONTROL);
+ /*
+ * ensure that PHY knows its PHY analog rail is going
+ * to be powered down
+ */
+ mb();
+ }
+}
+
+static
+void ufs_qcom_phy_qmp_20nm_set_tx_lane_enable(struct ufs_qcom_phy *phy, u32 val)
+{
+ writel_relaxed(val & UFS_PHY_TX_LANE_ENABLE_MASK,
+ phy->mmio + UFS_PHY_TX_LANE_ENABLE);
+ mb();
+}
+
+static inline void ufs_qcom_phy_qmp_20nm_start_serdes(struct ufs_qcom_phy *phy)
+{
+ u32 tmp;
+
+ tmp = readl_relaxed(phy->mmio + UFS_PHY_PHY_START);
+ tmp &= ~MASK_SERDES_START;
+ tmp |= (1 << OFFSET_SERDES_START);
+ writel_relaxed(tmp, phy->mmio + UFS_PHY_PHY_START);
+ mb();
+}
+
+static int ufs_qcom_phy_qmp_20nm_is_pcs_ready(struct ufs_qcom_phy *phy_common)
+{
+ int err = 0;
+ u32 val;
+
+ err = readl_poll_timeout(phy_common->mmio + UFS_PHY_PCS_READY_STATUS,
+ val, (val & MASK_PCS_READY), 10, 1000000);
+ if (err)
+ dev_err(phy_common->dev, "%s: poll for pcs failed err = %d\n",
+ __func__, err);
+ return err;
+}
+
+static struct phy_ops ufs_qcom_phy_qmp_20nm_phy_ops = {
+ .init = ufs_qcom_phy_qmp_20nm_init,
+ .exit = ufs_qcom_phy_exit,
+ .power_on = ufs_qcom_phy_power_on,
+ .power_off = ufs_qcom_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static struct ufs_qcom_phy_specific_ops phy_20nm_ops = {
+ .calibrate_phy = ufs_qcom_phy_qmp_20nm_phy_calibrate,
+ .start_serdes = ufs_qcom_phy_qmp_20nm_start_serdes,
+ .is_physical_coding_sublayer_ready = ufs_qcom_phy_qmp_20nm_is_pcs_ready,
+ .set_tx_lane_enable = ufs_qcom_phy_qmp_20nm_set_tx_lane_enable,
+ .power_control = ufs_qcom_phy_qmp_20nm_power_control,
+};
+
+static int ufs_qcom_phy_qmp_20nm_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy;
+ struct ufs_qcom_phy_qmp_20nm *phy;
+ int err = 0;
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy) {
+ dev_err(dev, "%s: failed to allocate phy\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ generic_phy = ufs_qcom_phy_generic_probe(pdev, &phy->common_cfg,
+ &ufs_qcom_phy_qmp_20nm_phy_ops, &phy_20nm_ops);
+
+ if (!generic_phy) {
+ dev_err(dev, "%s: ufs_qcom_phy_generic_probe() failed\n",
+ __func__);
+ err = -EIO;
+ goto out;
+ }
+
+ phy_set_drvdata(generic_phy, phy);
+
+ strlcpy(phy->common_cfg.name, UFS_PHY_NAME,
+ sizeof(phy->common_cfg.name));
+
+out:
+ return err;
+}
+
+static int ufs_qcom_phy_qmp_20nm_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy = to_phy(dev);
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int err = 0;
+
+ err = ufs_qcom_phy_remove(generic_phy, ufs_qcom_phy);
+ if (err)
+ dev_err(dev, "%s: ufs_qcom_phy_remove failed = %d\n",
+ __func__, err);
+
+ return err;
+}
+
+static const struct of_device_id ufs_qcom_phy_qmp_20nm_of_match[] = {
+ {.compatible = "qcom,ufs-phy-qmp-20nm"},
+ {},
+};
+MODULE_DEVICE_TABLE(of, ufs_qcom_phy_qmp_20nm_of_match);
+
+static struct platform_driver ufs_qcom_phy_qmp_20nm_driver = {
+ .probe = ufs_qcom_phy_qmp_20nm_probe,
+ .remove = ufs_qcom_phy_qmp_20nm_remove,
+ .driver = {
+ .of_match_table = ufs_qcom_phy_qmp_20nm_of_match,
+ .name = "ufs_qcom_phy_qmp_20nm",
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver(ufs_qcom_phy_qmp_20nm_driver);
+
+MODULE_DESCRIPTION("Universal Flash Storage (UFS) QCOM PHY QMP 20nm");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-qcom-ufs-qmp-20nm.h b/drivers/phy/phy-qcom-ufs-qmp-20nm.h
new file mode 100644
index 000000000000..4f3076bb3d71
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs-qmp-20nm.h
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2013-2015, Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UFS_QCOM_PHY_QMP_20NM_H_
+#define UFS_QCOM_PHY_QMP_20NM_H_
+
+#include "phy-qcom-ufs-i.h"
+
+/* QCOM UFS PHY control registers */
+
+#define COM_OFF(x) (0x000 + x)
+#define PHY_OFF(x) (0xC00 + x)
+#define TX_OFF(n, x) (0x400 + (0x400 * n) + x)
+#define RX_OFF(n, x) (0x600 + (0x400 * n) + x)
+
+/* UFS PHY PLL block registers */
+#define QSERDES_COM_SYS_CLK_CTRL COM_OFF(0x0)
+#define QSERDES_COM_PLL_VCOTAIL_EN COM_OFF(0x04)
+#define QSERDES_COM_PLL_CNTRL COM_OFF(0x14)
+#define QSERDES_COM_PLL_IP_SETI COM_OFF(0x24)
+#define QSERDES_COM_CORE_CLK_IN_SYNC_SEL COM_OFF(0x28)
+#define QSERDES_COM_BIAS_EN_CLKBUFLR_EN COM_OFF(0x30)
+#define QSERDES_COM_PLL_CP_SETI COM_OFF(0x34)
+#define QSERDES_COM_PLL_IP_SETP COM_OFF(0x38)
+#define QSERDES_COM_PLL_CP_SETP COM_OFF(0x3C)
+#define QSERDES_COM_SYSCLK_EN_SEL_TXBAND COM_OFF(0x48)
+#define QSERDES_COM_RESETSM_CNTRL COM_OFF(0x4C)
+#define QSERDES_COM_RESETSM_CNTRL2 COM_OFF(0x50)
+#define QSERDES_COM_PLLLOCK_CMP1 COM_OFF(0x90)
+#define QSERDES_COM_PLLLOCK_CMP2 COM_OFF(0x94)
+#define QSERDES_COM_PLLLOCK_CMP3 COM_OFF(0x98)
+#define QSERDES_COM_PLLLOCK_CMP_EN COM_OFF(0x9C)
+#define QSERDES_COM_BGTC COM_OFF(0xA0)
+#define QSERDES_COM_DEC_START1 COM_OFF(0xAC)
+#define QSERDES_COM_PLL_AMP_OS COM_OFF(0xB0)
+#define QSERDES_COM_RES_CODE_UP_OFFSET COM_OFF(0xD8)
+#define QSERDES_COM_RES_CODE_DN_OFFSET COM_OFF(0xDC)
+#define QSERDES_COM_DIV_FRAC_START1 COM_OFF(0x100)
+#define QSERDES_COM_DIV_FRAC_START2 COM_OFF(0x104)
+#define QSERDES_COM_DIV_FRAC_START3 COM_OFF(0x108)
+#define QSERDES_COM_DEC_START2 COM_OFF(0x10C)
+#define QSERDES_COM_PLL_RXTXEPCLK_EN COM_OFF(0x110)
+#define QSERDES_COM_PLL_CRCTRL COM_OFF(0x114)
+#define QSERDES_COM_PLL_CLKEPDIV COM_OFF(0x118)
+
+/* TX LANE n (0, 1) registers */
+#define QSERDES_TX_EMP_POST1_LVL(n) TX_OFF(n, 0x08)
+#define QSERDES_TX_DRV_LVL(n) TX_OFF(n, 0x0C)
+#define QSERDES_TX_LANE_MODE(n) TX_OFF(n, 0x54)
+
+/* RX LANE n (0, 1) registers */
+#define QSERDES_RX_CDR_CONTROL1(n) RX_OFF(n, 0x0)
+#define QSERDES_RX_CDR_CONTROL_HALF(n) RX_OFF(n, 0x8)
+#define QSERDES_RX_RX_EQ_GAIN1_LSB(n) RX_OFF(n, 0xA8)
+#define QSERDES_RX_RX_EQ_GAIN1_MSB(n) RX_OFF(n, 0xAC)
+#define QSERDES_RX_RX_EQ_GAIN2_LSB(n) RX_OFF(n, 0xB0)
+#define QSERDES_RX_RX_EQ_GAIN2_MSB(n) RX_OFF(n, 0xB4)
+#define QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(n) RX_OFF(n, 0xBC)
+#define QSERDES_RX_CDR_CONTROL_QUARTER(n) RX_OFF(n, 0xC)
+#define QSERDES_RX_SIGDET_CNTRL(n) RX_OFF(n, 0x100)
+
+/* UFS PHY registers */
+#define UFS_PHY_PHY_START PHY_OFF(0x00)
+#define UFS_PHY_POWER_DOWN_CONTROL PHY_OFF(0x4)
+#define UFS_PHY_TX_LANE_ENABLE PHY_OFF(0x44)
+#define UFS_PHY_PWM_G1_CLK_DIVIDER PHY_OFF(0x08)
+#define UFS_PHY_PWM_G2_CLK_DIVIDER PHY_OFF(0x0C)
+#define UFS_PHY_PWM_G3_CLK_DIVIDER PHY_OFF(0x10)
+#define UFS_PHY_PWM_G4_CLK_DIVIDER PHY_OFF(0x14)
+#define UFS_PHY_CORECLK_PWM_G1_CLK_DIVIDER PHY_OFF(0x34)
+#define UFS_PHY_CORECLK_PWM_G2_CLK_DIVIDER PHY_OFF(0x38)
+#define UFS_PHY_CORECLK_PWM_G3_CLK_DIVIDER PHY_OFF(0x3C)
+#define UFS_PHY_CORECLK_PWM_G4_CLK_DIVIDER PHY_OFF(0x40)
+#define UFS_PHY_OMC_STATUS_RDVAL PHY_OFF(0x68)
+#define UFS_PHY_LINE_RESET_TIME PHY_OFF(0x28)
+#define UFS_PHY_LINE_RESET_GRANULARITY PHY_OFF(0x2C)
+#define UFS_PHY_TSYNC_RSYNC_CNTL PHY_OFF(0x48)
+#define UFS_PHY_PLL_CNTL PHY_OFF(0x50)
+#define UFS_PHY_TX_LARGE_AMP_DRV_LVL PHY_OFF(0x54)
+#define UFS_PHY_TX_SMALL_AMP_DRV_LVL PHY_OFF(0x5C)
+#define UFS_PHY_TX_LARGE_AMP_POST_EMP_LVL PHY_OFF(0x58)
+#define UFS_PHY_TX_SMALL_AMP_POST_EMP_LVL PHY_OFF(0x60)
+#define UFS_PHY_CFG_CHANGE_CNT_VAL PHY_OFF(0x64)
+#define UFS_PHY_RX_SYNC_WAIT_TIME PHY_OFF(0x6C)
+#define UFS_PHY_TX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB4)
+#define UFS_PHY_RX_MIN_SLEEP_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE0)
+#define UFS_PHY_TX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xB8)
+#define UFS_PHY_RX_MIN_STALL_NOCONFIG_TIME_CAPABILITY PHY_OFF(0xE4)
+#define UFS_PHY_TX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xBC)
+#define UFS_PHY_RX_MIN_SAVE_CONFIG_TIME_CAPABILITY PHY_OFF(0xE8)
+#define UFS_PHY_RX_PWM_BURST_CLOSURE_LENGTH_CAPABILITY PHY_OFF(0xFC)
+#define UFS_PHY_RX_MIN_ACTIVATETIME_CAPABILITY PHY_OFF(0x100)
+#define UFS_PHY_RX_SIGDET_CTRL3 PHY_OFF(0x14c)
+#define UFS_PHY_RMMI_ATTR_CTRL PHY_OFF(0x160)
+#define UFS_PHY_RMMI_RX_CFGUPDT_L1 (1 << 7)
+#define UFS_PHY_RMMI_TX_CFGUPDT_L1 (1 << 6)
+#define UFS_PHY_RMMI_CFGWR_L1 (1 << 5)
+#define UFS_PHY_RMMI_CFGRD_L1 (1 << 4)
+#define UFS_PHY_RMMI_RX_CFGUPDT_L0 (1 << 3)
+#define UFS_PHY_RMMI_TX_CFGUPDT_L0 (1 << 2)
+#define UFS_PHY_RMMI_CFGWR_L0 (1 << 1)
+#define UFS_PHY_RMMI_CFGRD_L0 (1 << 0)
+#define UFS_PHY_RMMI_ATTRID PHY_OFF(0x164)
+#define UFS_PHY_RMMI_ATTRWRVAL PHY_OFF(0x168)
+#define UFS_PHY_RMMI_ATTRRDVAL_L0_STATUS PHY_OFF(0x16C)
+#define UFS_PHY_RMMI_ATTRRDVAL_L1_STATUS PHY_OFF(0x170)
+#define UFS_PHY_PCS_READY_STATUS PHY_OFF(0x174)
+
+#define UFS_PHY_TX_LANE_ENABLE_MASK 0x3
+
+/*
+ * This structure represents the 20nm specific phy.
+ * common_cfg MUST remain the first field in this structure
+ * in case extra fields are added. This way, when calling
+ * get_ufs_qcom_phy() of generic phy, we can extract the
+ * common phy structure (struct ufs_qcom_phy) out of it
+ * regardless of the relevant specific phy.
+ */
+struct ufs_qcom_phy_qmp_20nm {
+ struct ufs_qcom_phy common_cfg;
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_2_0[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x3f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x1b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x0f),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(0), 0x2F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(0), 0x20),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_EMP_POST1_LVL(1), 0x2F),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_DRV_LVL(1), 0x20),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3),
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_A_1_3_0[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_POWER_DOWN_CONTROL, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(UFS_PHY_RX_SIGDET_CTRL3, 0x0D),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_VCOTAIL_EN, 0xe1),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CRCTRL, 0xcc),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_SYSCLK_EN_SEL_TXBAND, 0x08),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CLKEPDIV, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_RXTXEPCLK_EN, 0x10),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x82),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START2, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START1, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START2, 0x80),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DIV_FRAC_START3, 0x40),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x19),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP3, 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP_EN, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL, 0x90),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RESETSM_CNTRL2, 0x03),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(0), 0xf2),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(0), 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(0), 0x12),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL1(1), 0xf2),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_HALF(1), 0x0c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_CDR_CONTROL_QUARTER(1), 0x12),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(0), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(0), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(0), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(0), 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_LSB(1), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN1_MSB(1), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_LSB(1), 0xff),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQ_GAIN2_MSB(1), 0x00),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETI, 0x2b),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETP, 0x38),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CP_SETP, 0x3c),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_UP_OFFSET, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_RES_CODE_DN_OFFSET, 0x02),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_IP_SETI, 0x01),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLL_CNTRL, 0x40),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(0), 0x68),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_TX_LANE_MODE(1), 0x68),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(1), 0xdc),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_RX_RX_EQU_ADAPTOR_CNTRL2(0), 0xdc),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_BIAS_EN_CLKBUFLR_EN, 0x3),
+};
+
+static struct ufs_qcom_phy_calibration phy_cal_table_rate_B[] = {
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_DEC_START1, 0x98),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP1, 0x65),
+ UFS_QCOM_PHY_CAL_ENTRY(QSERDES_COM_PLLLOCK_CMP2, 0x1e),
+};
+
+#endif
diff --git a/drivers/phy/phy-qcom-ufs.c b/drivers/phy/phy-qcom-ufs.c
new file mode 100644
index 000000000000..44ee983d57fe
--- /dev/null
+++ b/drivers/phy/phy-qcom-ufs.c
@@ -0,0 +1,745 @@
+/*
+ * Copyright (c) 2013-2015, 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 "phy-qcom-ufs-i.h"
+
+#define MAX_PROP_NAME 32
+#define VDDA_PHY_MIN_UV 1000000
+#define VDDA_PHY_MAX_UV 1000000
+#define VDDA_PLL_MIN_UV 1800000
+#define VDDA_PLL_MAX_UV 1800000
+#define VDDP_REF_CLK_MIN_UV 1200000
+#define VDDP_REF_CLK_MAX_UV 1200000
+
+static int __ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
+ const char *, bool);
+static int ufs_qcom_phy_init_vreg(struct phy *, struct ufs_qcom_phy_vreg *,
+ const char *);
+static int ufs_qcom_phy_base_init(struct platform_device *pdev,
+ struct ufs_qcom_phy *phy_common);
+
+int ufs_qcom_phy_calibrate(struct ufs_qcom_phy *ufs_qcom_phy,
+ struct ufs_qcom_phy_calibration *tbl_A,
+ int tbl_size_A,
+ struct ufs_qcom_phy_calibration *tbl_B,
+ int tbl_size_B, bool is_rate_B)
+{
+ int i;
+ int ret = 0;
+
+ if (!tbl_A) {
+ dev_err(ufs_qcom_phy->dev, "%s: tbl_A is NULL", __func__);
+ ret = EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < tbl_size_A; i++)
+ writel_relaxed(tbl_A[i].cfg_value,
+ ufs_qcom_phy->mmio + tbl_A[i].reg_offset);
+
+ /*
+ * In case we would like to work in rate B, we need
+ * to override a registers that were configured in rate A table
+ * with registers of rate B table.
+ * table.
+ */
+ if (is_rate_B) {
+ if (!tbl_B) {
+ dev_err(ufs_qcom_phy->dev, "%s: tbl_B is NULL",
+ __func__);
+ ret = EINVAL;
+ goto out;
+ }
+
+ for (i = 0; i < tbl_size_B; i++)
+ writel_relaxed(tbl_B[i].cfg_value,
+ ufs_qcom_phy->mmio + tbl_B[i].reg_offset);
+ }
+
+ /* flush buffered writes */
+ mb();
+
+out:
+ return ret;
+}
+
+struct phy *ufs_qcom_phy_generic_probe(struct platform_device *pdev,
+ struct ufs_qcom_phy *common_cfg,
+ struct phy_ops *ufs_qcom_phy_gen_ops,
+ struct ufs_qcom_phy_specific_ops *phy_spec_ops)
+{
+ int err;
+ struct device *dev = &pdev->dev;
+ struct phy *generic_phy = NULL;
+ struct phy_provider *phy_provider;
+
+ err = ufs_qcom_phy_base_init(pdev, common_cfg);
+ if (err) {
+ dev_err(dev, "%s: phy base init failed %d\n", __func__, err);
+ goto out;
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ if (IS_ERR(phy_provider)) {
+ err = PTR_ERR(phy_provider);
+ dev_err(dev, "%s: failed to register phy %d\n", __func__, err);
+ goto out;
+ }
+
+ generic_phy = devm_phy_create(dev, NULL, ufs_qcom_phy_gen_ops);
+ if (IS_ERR(generic_phy)) {
+ err = PTR_ERR(generic_phy);
+ dev_err(dev, "%s: failed to create phy %d\n", __func__, err);
+ goto out;
+ }
+
+ common_cfg->phy_spec_ops = phy_spec_ops;
+ common_cfg->dev = dev;
+
+out:
+ return generic_phy;
+}
+
+/*
+ * This assumes the embedded phy structure inside generic_phy is of type
+ * struct ufs_qcom_phy. In order to function properly it's crucial
+ * to keep the embedded struct "struct ufs_qcom_phy common_cfg"
+ * as the first inside generic_phy.
+ */
+struct ufs_qcom_phy *get_ufs_qcom_phy(struct phy *generic_phy)
+{
+ return (struct ufs_qcom_phy *)phy_get_drvdata(generic_phy);
+}
+
+static
+int ufs_qcom_phy_base_init(struct platform_device *pdev,
+ struct ufs_qcom_phy *phy_common)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int err = 0;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "phy_mem");
+ if (!res) {
+ dev_err(dev, "%s: phy_mem resource not found\n", __func__);
+ err = -ENOMEM;
+ goto out;
+ }
+
+ phy_common->mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR((void const *)phy_common->mmio)) {
+ err = PTR_ERR((void const *)phy_common->mmio);
+ phy_common->mmio = NULL;
+ dev_err(dev, "%s: ioremap for phy_mem resource failed %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /* "dev_ref_clk_ctrl_mem" is optional resource */
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ "dev_ref_clk_ctrl_mem");
+ if (!res) {
+ dev_dbg(dev, "%s: dev_ref_clk_ctrl_mem resource not found\n",
+ __func__);
+ goto out;
+ }
+
+ phy_common->dev_ref_clk_ctrl_mmio = devm_ioremap_resource(dev, res);
+ if (IS_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio)) {
+ err = PTR_ERR((void const *)phy_common->dev_ref_clk_ctrl_mmio);
+ phy_common->dev_ref_clk_ctrl_mmio = NULL;
+ dev_err(dev, "%s: ioremap for dev_ref_clk_ctrl_mem resource failed %d\n",
+ __func__, err);
+ }
+
+out:
+ return err;
+}
+
+static int __ufs_qcom_phy_clk_get(struct phy *phy,
+ const char *name, struct clk **clk_out, bool err_print)
+{
+ struct clk *clk;
+ int err = 0;
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
+ struct device *dev = ufs_qcom_phy->dev;
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk)) {
+ err = PTR_ERR(clk);
+ if (err_print)
+ dev_err(dev, "failed to get %s err %d", name, err);
+ } else {
+ *clk_out = clk;
+ }
+
+ return err;
+}
+
+static
+int ufs_qcom_phy_clk_get(struct phy *phy,
+ const char *name, struct clk **clk_out)
+{
+ return __ufs_qcom_phy_clk_get(phy, name, clk_out, true);
+}
+
+int
+ufs_qcom_phy_init_clks(struct phy *generic_phy,
+ struct ufs_qcom_phy *phy_common)
+{
+ int err;
+
+ err = ufs_qcom_phy_clk_get(generic_phy, "tx_iface_clk",
+ &phy_common->tx_iface_clk);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_phy_clk_get(generic_phy, "rx_iface_clk",
+ &phy_common->rx_iface_clk);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk_src",
+ &phy_common->ref_clk_src);
+ if (err)
+ goto out;
+
+ /*
+ * "ref_clk_parent" is optional hence don't abort init if it's not
+ * found.
+ */
+ __ufs_qcom_phy_clk_get(generic_phy, "ref_clk_parent",
+ &phy_common->ref_clk_parent, false);
+
+ err = ufs_qcom_phy_clk_get(generic_phy, "ref_clk",
+ &phy_common->ref_clk);
+
+out:
+ return err;
+}
+
+int
+ufs_qcom_phy_init_vregulators(struct phy *generic_phy,
+ struct ufs_qcom_phy *phy_common)
+{
+ int err;
+
+ err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_pll,
+ "vdda-pll");
+ if (err)
+ goto out;
+
+ err = ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vdda_phy,
+ "vdda-phy");
+
+ if (err)
+ goto out;
+
+ /* vddp-ref-clk-* properties are optional */
+ __ufs_qcom_phy_init_vreg(generic_phy, &phy_common->vddp_ref_clk,
+ "vddp-ref-clk", true);
+out:
+ return err;
+}
+
+static int __ufs_qcom_phy_init_vreg(struct phy *phy,
+ struct ufs_qcom_phy_vreg *vreg, const char *name, bool optional)
+{
+ int err = 0;
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
+ struct device *dev = ufs_qcom_phy->dev;
+
+ char prop_name[MAX_PROP_NAME];
+
+ vreg->name = kstrdup(name, GFP_KERNEL);
+ if (!vreg->name) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ vreg->reg = devm_regulator_get(dev, name);
+ if (IS_ERR(vreg->reg)) {
+ err = PTR_ERR(vreg->reg);
+ vreg->reg = NULL;
+ if (!optional)
+ dev_err(dev, "failed to get %s, %d\n", name, err);
+ goto out;
+ }
+
+ if (dev->of_node) {
+ snprintf(prop_name, MAX_PROP_NAME, "%s-max-microamp", name);
+ err = of_property_read_u32(dev->of_node,
+ prop_name, &vreg->max_uA);
+ if (err && err != -EINVAL) {
+ dev_err(dev, "%s: failed to read %s\n",
+ __func__, prop_name);
+ goto out;
+ } else if (err == -EINVAL || !vreg->max_uA) {
+ if (regulator_count_voltages(vreg->reg) > 0) {
+ dev_err(dev, "%s: %s is mandatory\n",
+ __func__, prop_name);
+ goto out;
+ }
+ err = 0;
+ }
+ snprintf(prop_name, MAX_PROP_NAME, "%s-always-on", name);
+ if (of_get_property(dev->of_node, prop_name, NULL))
+ vreg->is_always_on = true;
+ else
+ vreg->is_always_on = false;
+ }
+
+ if (!strcmp(name, "vdda-pll")) {
+ vreg->max_uV = VDDA_PLL_MAX_UV;
+ vreg->min_uV = VDDA_PLL_MIN_UV;
+ } else if (!strcmp(name, "vdda-phy")) {
+ vreg->max_uV = VDDA_PHY_MAX_UV;
+ vreg->min_uV = VDDA_PHY_MIN_UV;
+ } else if (!strcmp(name, "vddp-ref-clk")) {
+ vreg->max_uV = VDDP_REF_CLK_MAX_UV;
+ vreg->min_uV = VDDP_REF_CLK_MIN_UV;
+ }
+
+out:
+ if (err)
+ kfree(vreg->name);
+ return err;
+}
+
+static int ufs_qcom_phy_init_vreg(struct phy *phy,
+ struct ufs_qcom_phy_vreg *vreg, const char *name)
+{
+ return __ufs_qcom_phy_init_vreg(phy, vreg, name, false);
+}
+
+static
+int ufs_qcom_phy_cfg_vreg(struct phy *phy,
+ struct ufs_qcom_phy_vreg *vreg, bool on)
+{
+ int ret = 0;
+ struct regulator *reg = vreg->reg;
+ const char *name = vreg->name;
+ int min_uV;
+ int uA_load;
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
+ struct device *dev = ufs_qcom_phy->dev;
+
+ BUG_ON(!vreg);
+
+ if (regulator_count_voltages(reg) > 0) {
+ min_uV = on ? vreg->min_uV : 0;
+ ret = regulator_set_voltage(reg, min_uV, vreg->max_uV);
+ if (ret) {
+ dev_err(dev, "%s: %s set voltage failed, err=%d\n",
+ __func__, name, ret);
+ goto out;
+ }
+ uA_load = on ? vreg->max_uA : 0;
+ ret = regulator_set_optimum_mode(reg, uA_load);
+ if (ret >= 0) {
+ /*
+ * regulator_set_optimum_mode() returns new regulator
+ * mode upon success.
+ */
+ ret = 0;
+ } else {
+ dev_err(dev, "%s: %s set optimum mode(uA_load=%d) failed, err=%d\n",
+ __func__, name, uA_load, ret);
+ goto out;
+ }
+ }
+out:
+ return ret;
+}
+
+static
+int ufs_qcom_phy_enable_vreg(struct phy *phy,
+ struct ufs_qcom_phy_vreg *vreg)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
+ struct device *dev = ufs_qcom_phy->dev;
+ int ret = 0;
+
+ if (!vreg || vreg->enabled)
+ goto out;
+
+ ret = ufs_qcom_phy_cfg_vreg(phy, vreg, true);
+ if (ret) {
+ dev_err(dev, "%s: ufs_qcom_phy_cfg_vreg() failed, err=%d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ret = regulator_enable(vreg->reg);
+ if (ret) {
+ dev_err(dev, "%s: enable failed, err=%d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ vreg->enabled = true;
+out:
+ return ret;
+}
+
+int ufs_qcom_phy_enable_ref_clk(struct phy *generic_phy)
+{
+ int ret = 0;
+ struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
+
+ if (phy->is_ref_clk_enabled)
+ goto out;
+
+ /*
+ * reference clock is propagated in a daisy-chained manner from
+ * source to phy, so ungate them at each stage.
+ */
+ ret = clk_prepare_enable(phy->ref_clk_src);
+ if (ret) {
+ dev_err(phy->dev, "%s: ref_clk_src enable failed %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ /*
+ * "ref_clk_parent" is optional clock hence make sure that clk reference
+ * is available before trying to enable the clock.
+ */
+ if (phy->ref_clk_parent) {
+ ret = clk_prepare_enable(phy->ref_clk_parent);
+ if (ret) {
+ dev_err(phy->dev, "%s: ref_clk_parent enable failed %d\n",
+ __func__, ret);
+ goto out_disable_src;
+ }
+ }
+
+ ret = clk_prepare_enable(phy->ref_clk);
+ if (ret) {
+ dev_err(phy->dev, "%s: ref_clk enable failed %d\n",
+ __func__, ret);
+ goto out_disable_parent;
+ }
+
+ phy->is_ref_clk_enabled = true;
+ goto out;
+
+out_disable_parent:
+ if (phy->ref_clk_parent)
+ clk_disable_unprepare(phy->ref_clk_parent);
+out_disable_src:
+ clk_disable_unprepare(phy->ref_clk_src);
+out:
+ return ret;
+}
+
+static
+int ufs_qcom_phy_disable_vreg(struct phy *phy,
+ struct ufs_qcom_phy_vreg *vreg)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(phy);
+ struct device *dev = ufs_qcom_phy->dev;
+ int ret = 0;
+
+ if (!vreg || !vreg->enabled || vreg->is_always_on)
+ goto out;
+
+ ret = regulator_disable(vreg->reg);
+
+ if (!ret) {
+ /* ignore errors on applying disable config */
+ ufs_qcom_phy_cfg_vreg(phy, vreg, false);
+ vreg->enabled = false;
+ } else {
+ dev_err(dev, "%s: %s disable failed, err=%d\n",
+ __func__, vreg->name, ret);
+ }
+out:
+ return ret;
+}
+
+void ufs_qcom_phy_disable_ref_clk(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
+
+ if (phy->is_ref_clk_enabled) {
+ clk_disable_unprepare(phy->ref_clk);
+ /*
+ * "ref_clk_parent" is optional clock hence make sure that clk
+ * reference is available before trying to disable the clock.
+ */
+ if (phy->ref_clk_parent)
+ clk_disable_unprepare(phy->ref_clk_parent);
+ clk_disable_unprepare(phy->ref_clk_src);
+ phy->is_ref_clk_enabled = false;
+ }
+}
+
+#define UFS_REF_CLK_EN (1 << 5)
+
+static void ufs_qcom_phy_dev_ref_clk_ctrl(struct phy *generic_phy, bool enable)
+{
+ struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
+
+ if (phy->dev_ref_clk_ctrl_mmio &&
+ (enable ^ phy->is_dev_ref_clk_enabled)) {
+ u32 temp = readl_relaxed(phy->dev_ref_clk_ctrl_mmio);
+
+ if (enable)
+ temp |= UFS_REF_CLK_EN;
+ else
+ temp &= ~UFS_REF_CLK_EN;
+
+ /*
+ * If we are here to disable this clock immediately after
+ * entering into hibern8, we need to make sure that device
+ * ref_clk is active atleast 1us after the hibern8 enter.
+ */
+ if (!enable)
+ udelay(1);
+
+ writel_relaxed(temp, phy->dev_ref_clk_ctrl_mmio);
+ /* ensure that ref_clk is enabled/disabled before we return */
+ wmb();
+ /*
+ * If we call hibern8 exit after this, we need to make sure that
+ * device ref_clk is stable for atleast 1us before the hibern8
+ * exit command.
+ */
+ if (enable)
+ udelay(1);
+
+ phy->is_dev_ref_clk_enabled = enable;
+ }
+}
+
+void ufs_qcom_phy_enable_dev_ref_clk(struct phy *generic_phy)
+{
+ ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, true);
+}
+
+void ufs_qcom_phy_disable_dev_ref_clk(struct phy *generic_phy)
+{
+ ufs_qcom_phy_dev_ref_clk_ctrl(generic_phy, false);
+}
+
+/* Turn ON M-PHY RMMI interface clocks */
+int ufs_qcom_phy_enable_iface_clk(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
+ int ret = 0;
+
+ if (phy->is_iface_clk_enabled)
+ goto out;
+
+ ret = clk_prepare_enable(phy->tx_iface_clk);
+ if (ret) {
+ dev_err(phy->dev, "%s: tx_iface_clk enable failed %d\n",
+ __func__, ret);
+ goto out;
+ }
+ ret = clk_prepare_enable(phy->rx_iface_clk);
+ if (ret) {
+ clk_disable_unprepare(phy->tx_iface_clk);
+ dev_err(phy->dev, "%s: rx_iface_clk enable failed %d. disabling also tx_iface_clk\n",
+ __func__, ret);
+ goto out;
+ }
+ phy->is_iface_clk_enabled = true;
+
+out:
+ return ret;
+}
+
+/* Turn OFF M-PHY RMMI interface clocks */
+void ufs_qcom_phy_disable_iface_clk(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *phy = get_ufs_qcom_phy(generic_phy);
+
+ if (phy->is_iface_clk_enabled) {
+ clk_disable_unprepare(phy->tx_iface_clk);
+ clk_disable_unprepare(phy->rx_iface_clk);
+ phy->is_iface_clk_enabled = false;
+ }
+}
+
+int ufs_qcom_phy_start_serdes(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int ret = 0;
+
+ if (!ufs_qcom_phy->phy_spec_ops->start_serdes) {
+ dev_err(ufs_qcom_phy->dev, "%s: start_serdes() callback is not supported\n",
+ __func__);
+ ret = -ENOTSUPP;
+ } else {
+ ufs_qcom_phy->phy_spec_ops->start_serdes(ufs_qcom_phy);
+ }
+
+ return ret;
+}
+
+int ufs_qcom_phy_set_tx_lane_enable(struct phy *generic_phy, u32 tx_lanes)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int ret = 0;
+
+ if (!ufs_qcom_phy->phy_spec_ops->set_tx_lane_enable) {
+ dev_err(ufs_qcom_phy->dev, "%s: set_tx_lane_enable() callback is not supported\n",
+ __func__);
+ ret = -ENOTSUPP;
+ } else {
+ ufs_qcom_phy->phy_spec_ops->set_tx_lane_enable(ufs_qcom_phy,
+ tx_lanes);
+ }
+
+ return ret;
+}
+
+void ufs_qcom_phy_save_controller_version(struct phy *generic_phy,
+ u8 major, u16 minor, u16 step)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+
+ ufs_qcom_phy->host_ctrl_rev_major = major;
+ ufs_qcom_phy->host_ctrl_rev_minor = minor;
+ ufs_qcom_phy->host_ctrl_rev_step = step;
+}
+
+int ufs_qcom_phy_calibrate_phy(struct phy *generic_phy, bool is_rate_B)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+ int ret = 0;
+
+ if (!ufs_qcom_phy->phy_spec_ops->calibrate_phy) {
+ dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() callback is not supported\n",
+ __func__);
+ ret = -ENOTSUPP;
+ } else {
+ ret = ufs_qcom_phy->phy_spec_ops->
+ calibrate_phy(ufs_qcom_phy, is_rate_B);
+ if (ret)
+ dev_err(ufs_qcom_phy->dev, "%s: calibrate_phy() failed %d\n",
+ __func__, ret);
+ }
+
+ return ret;
+}
+
+int ufs_qcom_phy_remove(struct phy *generic_phy,
+ struct ufs_qcom_phy *ufs_qcom_phy)
+{
+ phy_power_off(generic_phy);
+
+ kfree(ufs_qcom_phy->vdda_pll.name);
+ kfree(ufs_qcom_phy->vdda_phy.name);
+
+ return 0;
+}
+
+int ufs_qcom_phy_exit(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+
+ if (ufs_qcom_phy->is_powered_on)
+ phy_power_off(generic_phy);
+
+ return 0;
+}
+
+int ufs_qcom_phy_is_pcs_ready(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *ufs_qcom_phy = get_ufs_qcom_phy(generic_phy);
+
+ if (!ufs_qcom_phy->phy_spec_ops->is_physical_coding_sublayer_ready) {
+ dev_err(ufs_qcom_phy->dev, "%s: is_physical_coding_sublayer_ready() callback is not supported\n",
+ __func__);
+ return -ENOTSUPP;
+ }
+
+ return ufs_qcom_phy->phy_spec_ops->
+ is_physical_coding_sublayer_ready(ufs_qcom_phy);
+}
+
+int ufs_qcom_phy_power_on(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
+ struct device *dev = phy_common->dev;
+ int err;
+
+ err = ufs_qcom_phy_enable_vreg(generic_phy, &phy_common->vdda_phy);
+ if (err) {
+ dev_err(dev, "%s enable vdda_phy failed, err=%d\n",
+ __func__, err);
+ goto out;
+ }
+
+ phy_common->phy_spec_ops->power_control(phy_common, true);
+
+ /* vdda_pll also enables ref clock LDOs so enable it first */
+ err = ufs_qcom_phy_enable_vreg(generic_phy, &phy_common->vdda_pll);
+ if (err) {
+ dev_err(dev, "%s enable vdda_pll failed, err=%d\n",
+ __func__, err);
+ goto out_disable_phy;
+ }
+
+ err = ufs_qcom_phy_enable_ref_clk(generic_phy);
+ if (err) {
+ dev_err(dev, "%s enable phy ref clock failed, err=%d\n",
+ __func__, err);
+ goto out_disable_pll;
+ }
+
+ /* enable device PHY ref_clk pad rail */
+ if (phy_common->vddp_ref_clk.reg) {
+ err = ufs_qcom_phy_enable_vreg(generic_phy,
+ &phy_common->vddp_ref_clk);
+ if (err) {
+ dev_err(dev, "%s enable vddp_ref_clk failed, err=%d\n",
+ __func__, err);
+ goto out_disable_ref_clk;
+ }
+ }
+
+ phy_common->is_powered_on = true;
+ goto out;
+
+out_disable_ref_clk:
+ ufs_qcom_phy_disable_ref_clk(generic_phy);
+out_disable_pll:
+ ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
+out_disable_phy:
+ ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_phy);
+out:
+ return err;
+}
+
+int ufs_qcom_phy_power_off(struct phy *generic_phy)
+{
+ struct ufs_qcom_phy *phy_common = get_ufs_qcom_phy(generic_phy);
+
+ phy_common->phy_spec_ops->power_control(phy_common, false);
+
+ if (phy_common->vddp_ref_clk.reg)
+ ufs_qcom_phy_disable_vreg(generic_phy,
+ &phy_common->vddp_ref_clk);
+ ufs_qcom_phy_disable_ref_clk(generic_phy);
+
+ ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_pll);
+ ufs_qcom_phy_disable_vreg(generic_phy, &phy_common->vdda_phy);
+ phy_common->is_powered_on = false;
+
+ return 0;
+}
diff --git a/drivers/phy/phy-rockchip-usb.c b/drivers/phy/phy-rockchip-usb.c
new file mode 100644
index 000000000000..22011c3b6a4b
--- /dev/null
+++ b/drivers/phy/phy-rockchip-usb.c
@@ -0,0 +1,158 @@
+/*
+ * Rockchip usb PHY driver
+ *
+ * Copyright (C) 2014 Yunzhi Li <lyz@rock-chips.com>
+ * Copyright (C) 2014 ROCKCHIP, 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+/*
+ * The higher 16-bit of this register is used for write protection
+ * only if BIT(13 + 16) set to 1 the BIT(13) can be written.
+ */
+#define SIDDQ_WRITE_ENA BIT(29)
+#define SIDDQ_ON BIT(13)
+#define SIDDQ_OFF (0 << 13)
+
+struct rockchip_usb_phy {
+ unsigned int reg_offset;
+ struct regmap *reg_base;
+ struct clk *clk;
+ struct phy *phy;
+};
+
+static int rockchip_usb_phy_power(struct rockchip_usb_phy *phy,
+ bool siddq)
+{
+ return regmap_write(phy->reg_base, phy->reg_offset,
+ SIDDQ_WRITE_ENA | (siddq ? SIDDQ_ON : SIDDQ_OFF));
+}
+
+static int rockchip_usb_phy_power_off(struct phy *_phy)
+{
+ struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+ int ret = 0;
+
+ /* Power down usb phy analog blocks by set siddq 1 */
+ ret = rockchip_usb_phy_power(phy, 1);
+ if (ret)
+ return ret;
+
+ clk_disable_unprepare(phy->clk);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int rockchip_usb_phy_power_on(struct phy *_phy)
+{
+ struct rockchip_usb_phy *phy = phy_get_drvdata(_phy);
+ int ret = 0;
+
+ ret = clk_prepare_enable(phy->clk);
+ if (ret)
+ return ret;
+
+ /* Power up usb phy analog blocks by set siddq 0 */
+ ret = rockchip_usb_phy_power(phy, 0);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static struct phy_ops ops = {
+ .power_on = rockchip_usb_phy_power_on,
+ .power_off = rockchip_usb_phy_power_off,
+ .owner = THIS_MODULE,
+};
+
+static int rockchip_usb_phy_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct rockchip_usb_phy *rk_phy;
+ struct phy_provider *phy_provider;
+ struct device_node *child;
+ struct regmap *grf;
+ unsigned int reg_offset;
+
+ grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf");
+ if (IS_ERR(grf)) {
+ dev_err(&pdev->dev, "Missing rockchip,grf property\n");
+ return PTR_ERR(grf);
+ }
+
+ for_each_available_child_of_node(dev->of_node, child) {
+ rk_phy = devm_kzalloc(dev, sizeof(*rk_phy), GFP_KERNEL);
+ if (!rk_phy)
+ return -ENOMEM;
+
+ if (of_property_read_u32(child, "reg", &reg_offset)) {
+ dev_err(dev, "missing reg property in node %s\n",
+ child->name);
+ return -EINVAL;
+ }
+
+ rk_phy->reg_offset = reg_offset;
+ rk_phy->reg_base = grf;
+
+ rk_phy->clk = of_clk_get_by_name(child, "phyclk");
+ if (IS_ERR(rk_phy->clk))
+ rk_phy->clk = NULL;
+
+ rk_phy->phy = devm_phy_create(dev, child, &ops);
+ if (IS_ERR(rk_phy->phy)) {
+ dev_err(dev, "failed to create PHY\n");
+ return PTR_ERR(rk_phy->phy);
+ }
+ phy_set_drvdata(rk_phy->phy, rk_phy);
+ }
+
+ phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+ return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static const struct of_device_id rockchip_usb_phy_dt_ids[] = {
+ { .compatible = "rockchip,rk3288-usb-phy" },
+ {}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_usb_phy_dt_ids);
+
+static struct platform_driver rockchip_usb_driver = {
+ .probe = rockchip_usb_phy_probe,
+ .driver = {
+ .name = "rockchip-usb-phy",
+ .owner = THIS_MODULE,
+ .of_match_table = rockchip_usb_phy_dt_ids,
+ },
+};
+
+module_platform_driver(rockchip_usb_driver);
+
+MODULE_AUTHOR("Yunzhi Li <lyz@rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip USB 2.0 PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/phy/phy-stih407-usb.c b/drivers/phy/phy-stih407-usb.c
index 74f0fab3cd8a..1d5ae5f8ef69 100644
--- a/drivers/phy/phy-stih407-usb.c
+++ b/drivers/phy/phy-stih407-usb.c
@@ -22,6 +22,9 @@
#include <linux/mfd/syscon.h>
#include <linux/phy/phy.h>
+#define PHYPARAM_REG 1
+#define PHYCTRL_REG 2
+
/* Default PHY_SEL and REFCLKSEL configuration */
#define STIH407_USB_PICOPHY_CTRL_PORT_CONF 0x6
#define STIH407_USB_PICOPHY_CTRL_PORT_MASK 0x1f
@@ -93,7 +96,7 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct phy_provider *phy_provider;
struct phy *phy;
- struct resource *res;
+ int ret;
phy_dev = devm_kzalloc(dev, sizeof(*phy_dev), GFP_KERNEL);
if (!phy_dev)
@@ -123,19 +126,19 @@ static int stih407_usb2_picophy_probe(struct platform_device *pdev)
return PTR_ERR(phy_dev->regmap);
}
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ctrl");
- if (!res) {
- dev_err(dev, "No ctrl reg found\n");
- return -ENXIO;
+ ret = of_property_read_u32_index(np, "st,syscfg", PHYPARAM_REG,
+ &phy_dev->param);
+ if (ret) {
+ dev_err(dev, "can't get phyparam offset (%d)\n", ret);
+ return ret;
}
- phy_dev->ctrl = res->start;
- res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "param");
- if (!res) {
- dev_err(dev, "No param reg found\n");
- return -ENXIO;
+ ret = of_property_read_u32_index(np, "st,syscfg", PHYCTRL_REG,
+ &phy_dev->ctrl);
+ if (ret) {
+ dev_err(dev, "can't get phyctrl offset (%d)\n", ret);
+ return ret;
}
- phy_dev->param = res->start;
phy = devm_phy_create(dev, NULL, &stih407_usb2_picophy_data);
if (IS_ERR(phy)) {
diff --git a/drivers/phy/phy-ti-pipe3.c b/drivers/phy/phy-ti-pipe3.c
index 465de2c800f2..95c88f929f27 100644
--- a/drivers/phy/phy-ti-pipe3.c
+++ b/drivers/phy/phy-ti-pipe3.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/phy/omap_control_phy.h>
#include <linux/of_platform.h>
+#include <linux/spinlock.h>
#define PLL_STATUS 0x00000004
#define PLL_GO 0x00000008
@@ -82,6 +83,10 @@ struct ti_pipe3 {
struct clk *refclk;
struct clk *div_clk;
struct pipe3_dpll_map *dpll_map;
+ bool enabled;
+ spinlock_t lock; /* serialize clock enable/disable */
+ /* the below flag is needed specifically for SATA */
+ bool refclk_enabled;
};
static struct pipe3_dpll_map dpll_map_usb[] = {
@@ -307,6 +312,7 @@ static int ti_pipe3_probe(struct platform_device *pdev)
return -ENOMEM;
phy->dev = &pdev->dev;
+ spin_lock_init(&phy->lock);
if (!of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
match = of_match_device(of_match_ptr(ti_pipe3_id_table),
@@ -333,21 +339,24 @@ static int ti_pipe3_probe(struct platform_device *pdev)
}
}
+ phy->refclk = devm_clk_get(phy->dev, "refclk");
+ if (IS_ERR(phy->refclk)) {
+ dev_err(&pdev->dev, "unable to get refclk\n");
+ /* older DTBs have missing refclk in SATA PHY
+ * so don't bail out in case of SATA PHY.
+ */
+ if (!of_device_is_compatible(node, "ti,phy-pipe3-sata"))
+ return PTR_ERR(phy->refclk);
+ }
+
if (!of_device_is_compatible(node, "ti,phy-pipe3-sata")) {
phy->wkupclk = devm_clk_get(phy->dev, "wkupclk");
if (IS_ERR(phy->wkupclk)) {
dev_err(&pdev->dev, "unable to get wkupclk\n");
return PTR_ERR(phy->wkupclk);
}
-
- phy->refclk = devm_clk_get(phy->dev, "refclk");
- if (IS_ERR(phy->refclk)) {
- dev_err(&pdev->dev, "unable to get refclk\n");
- return PTR_ERR(phy->refclk);
- }
} else {
phy->wkupclk = ERR_PTR(-ENODEV);
- phy->refclk = ERR_PTR(-ENODEV);
}
if (of_device_is_compatible(node, "ti,phy-pipe3-pcie")) {
@@ -426,33 +435,42 @@ static int ti_pipe3_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-
-static int ti_pipe3_runtime_suspend(struct device *dev)
+static int ti_pipe3_enable_refclk(struct ti_pipe3 *phy)
{
- struct ti_pipe3 *phy = dev_get_drvdata(dev);
+ if (!IS_ERR(phy->refclk) && !phy->refclk_enabled) {
+ int ret;
- if (!IS_ERR(phy->wkupclk))
- clk_disable_unprepare(phy->wkupclk);
+ ret = clk_prepare_enable(phy->refclk);
+ if (ret) {
+ dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
+ return ret;
+ }
+ phy->refclk_enabled = true;
+ }
+
+ return 0;
+}
+
+static void ti_pipe3_disable_refclk(struct ti_pipe3 *phy)
+{
if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk);
- if (!IS_ERR(phy->div_clk))
- clk_disable_unprepare(phy->div_clk);
- return 0;
+ phy->refclk_enabled = false;
}
-static int ti_pipe3_runtime_resume(struct device *dev)
+static int ti_pipe3_enable_clocks(struct ti_pipe3 *phy)
{
- u32 ret = 0;
- struct ti_pipe3 *phy = dev_get_drvdata(dev);
+ int ret = 0;
+ unsigned long flags;
- if (!IS_ERR(phy->refclk)) {
- ret = clk_prepare_enable(phy->refclk);
- if (ret) {
- dev_err(phy->dev, "Failed to enable refclk %d\n", ret);
- goto err1;
- }
- }
+ spin_lock_irqsave(&phy->lock, flags);
+ if (phy->enabled)
+ goto err1;
+
+ ret = ti_pipe3_enable_refclk(phy);
+ if (ret)
+ goto err1;
if (!IS_ERR(phy->wkupclk)) {
ret = clk_prepare_enable(phy->wkupclk);
@@ -469,6 +487,9 @@ static int ti_pipe3_runtime_resume(struct device *dev)
goto err3;
}
}
+
+ phy->enabled = true;
+ spin_unlock_irqrestore(&phy->lock, flags);
return 0;
err3:
@@ -479,20 +500,80 @@ err2:
if (!IS_ERR(phy->refclk))
clk_disable_unprepare(phy->refclk);
+ ti_pipe3_disable_refclk(phy);
err1:
+ spin_unlock_irqrestore(&phy->lock, flags);
return ret;
}
+static void ti_pipe3_disable_clocks(struct ti_pipe3 *phy)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&phy->lock, flags);
+ if (!phy->enabled) {
+ spin_unlock_irqrestore(&phy->lock, flags);
+ return;
+ }
+
+ if (!IS_ERR(phy->wkupclk))
+ clk_disable_unprepare(phy->wkupclk);
+ /* Don't disable refclk for SATA PHY due to Errata i783 */
+ if (!of_device_is_compatible(phy->dev->of_node, "ti,phy-pipe3-sata"))
+ ti_pipe3_disable_refclk(phy);
+ if (!IS_ERR(phy->div_clk))
+ clk_disable_unprepare(phy->div_clk);
+ phy->enabled = false;
+ spin_unlock_irqrestore(&phy->lock, flags);
+}
+
+static int ti_pipe3_runtime_suspend(struct device *dev)
+{
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+
+ ti_pipe3_disable_clocks(phy);
+ return 0;
+}
+
+static int ti_pipe3_runtime_resume(struct device *dev)
+{
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+ int ret = 0;
+
+ ret = ti_pipe3_enable_clocks(phy);
+ return ret;
+}
+
+static int ti_pipe3_suspend(struct device *dev)
+{
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+
+ ti_pipe3_disable_clocks(phy);
+ return 0;
+}
+
+static int ti_pipe3_resume(struct device *dev)
+{
+ struct ti_pipe3 *phy = dev_get_drvdata(dev);
+ int ret;
+
+ ret = ti_pipe3_enable_clocks(phy);
+ if (ret)
+ return ret;
+
+ pm_runtime_disable(dev);
+ pm_runtime_set_active(dev);
+ pm_runtime_enable(dev);
+ return 0;
+}
+#endif
+
static const struct dev_pm_ops ti_pipe3_pm_ops = {
SET_RUNTIME_PM_OPS(ti_pipe3_runtime_suspend,
ti_pipe3_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(ti_pipe3_suspend, ti_pipe3_resume)
};
-#define DEV_PM_OPS (&ti_pipe3_pm_ops)
-#else
-#define DEV_PM_OPS NULL
-#endif
-
#ifdef CONFIG_OF
static const struct of_device_id ti_pipe3_id_table[] = {
{
@@ -520,7 +601,7 @@ static struct platform_driver ti_pipe3_driver = {
.remove = ti_pipe3_remove,
.driver = {
.name = "ti-pipe3",
- .pm = DEV_PM_OPS,
+ .pm = &ti_pipe3_pm_ops,
.of_match_table = of_match_ptr(ti_pipe3_id_table),
},
};
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index d014f22f387a..ee9f44ad7f02 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -96,6 +96,14 @@ config PINCTRL_FALCON
depends on SOC_FALCON
depends on PINCTRL_LANTIQ
+config PINCTRL_MESON
+ bool
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select OF_GPIO
+ select REGMAP_MMIO
+
config PINCTRL_ROCKCHIP
bool
select PINMUX
@@ -113,7 +121,7 @@ config PINCTRL_SINGLE
This selects the device tree based generic pinctrl driver.
config PINCTRL_SIRF
- bool "CSR SiRFprimaII/SiRFmarco pin controller driver"
+ bool "CSR SiRFprimaII pin controller driver"
depends on ARCH_SIRF
select PINMUX
select GPIOLIB_IRQCHIP
@@ -191,6 +199,14 @@ config PINCTRL_PALMAS
open drain configuration for the Palmas series devices like
TPS65913, TPS80036 etc.
+config PINCTRL_ZYNQ
+ bool "Pinctrl driver for Xilinx Zynq"
+ depends on ARCH_ZYNQ
+ select PINMUX
+ select GENERIC_PINCONF
+ help
+ This selectes the pinctrl driver for Xilinx Zynq.
+
source "drivers/pinctrl/berlin/Kconfig"
source "drivers/pinctrl/freescale/Kconfig"
source "drivers/pinctrl/intel/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index c030b3db8034..0475206dd600 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -1,6 +1,6 @@
# generic pinmux support
-ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
+subdir-ccflags-$(CONFIG_DEBUG_PINCTRL) += -DDEBUG
obj-$(CONFIG_PINCTRL) += core.o pinctrl-utils.o
obj-$(CONFIG_PINMUX) += pinmux.o
@@ -17,6 +17,7 @@ obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
+obj-$(CONFIG_PINCTRL_MESON) += meson/
obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o
obj-$(CONFIG_PINCTRL_ROCKCHIP) += pinctrl-rockchip.o
obj-$(CONFIG_PINCTRL_SINGLE) += pinctrl-single.o
@@ -35,6 +36,7 @@ obj-$(CONFIG_PINCTRL_XWAY) += pinctrl-xway.o
obj-$(CONFIG_PINCTRL_LANTIQ) += pinctrl-lantiq.o
obj-$(CONFIG_PINCTRL_TB10X) += pinctrl-tb10x.o
obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
+obj-$(CONFIG_PINCTRL_ZYNQ) += pinctrl-zynq.o
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-y += freescale/
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index 52f2b9404fe0..448f10986c28 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -437,7 +437,7 @@ static void imx_pinconf_dbg_show(struct pinctrl_dev *pctldev,
const struct imx_pin_reg *pin_reg = &info->pin_regs[pin_id];
unsigned long config;
- if (!pin_reg || !pin_reg->conf_reg) {
+ if (!pin_reg || pin_reg->conf_reg == -1) {
seq_printf(s, "N/A");
return;
}
diff --git a/drivers/pinctrl/freescale/pinctrl-imx25.c b/drivers/pinctrl/freescale/pinctrl-imx25.c
index 8d1013a040c9..faf635654312 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx25.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx25.c
@@ -27,150 +27,148 @@
enum imx25_pads {
MX25_PAD_RESERVE0 = 1,
- MX25_PAD_RESERVE1 = 2,
- MX25_PAD_A10 = 3,
- MX25_PAD_A13 = 4,
- MX25_PAD_A14 = 5,
- MX25_PAD_A15 = 6,
- MX25_PAD_A16 = 7,
- MX25_PAD_A17 = 8,
- MX25_PAD_A18 = 9,
- MX25_PAD_A19 = 10,
- MX25_PAD_A20 = 11,
- MX25_PAD_A21 = 12,
- MX25_PAD_A22 = 13,
- MX25_PAD_A23 = 14,
- MX25_PAD_A24 = 15,
- MX25_PAD_A25 = 16,
- MX25_PAD_EB0 = 17,
- MX25_PAD_EB1 = 18,
- MX25_PAD_OE = 19,
- MX25_PAD_CS0 = 20,
- MX25_PAD_CS1 = 21,
- MX25_PAD_CS4 = 22,
- MX25_PAD_CS5 = 23,
- MX25_PAD_NF_CE0 = 24,
- MX25_PAD_ECB = 25,
- MX25_PAD_LBA = 26,
- MX25_PAD_BCLK = 27,
- MX25_PAD_RW = 28,
- MX25_PAD_NFWE_B = 29,
- MX25_PAD_NFRE_B = 30,
- MX25_PAD_NFALE = 31,
- MX25_PAD_NFCLE = 32,
- MX25_PAD_NFWP_B = 33,
- MX25_PAD_NFRB = 34,
- MX25_PAD_D15 = 35,
- MX25_PAD_D14 = 36,
- MX25_PAD_D13 = 37,
- MX25_PAD_D12 = 38,
- MX25_PAD_D11 = 39,
- MX25_PAD_D10 = 40,
- MX25_PAD_D9 = 41,
- MX25_PAD_D8 = 42,
- MX25_PAD_D7 = 43,
- MX25_PAD_D6 = 44,
- MX25_PAD_D5 = 45,
- MX25_PAD_D4 = 46,
- MX25_PAD_D3 = 47,
- MX25_PAD_D2 = 48,
- MX25_PAD_D1 = 49,
- MX25_PAD_D0 = 50,
- MX25_PAD_LD0 = 51,
- MX25_PAD_LD1 = 52,
- MX25_PAD_LD2 = 53,
- MX25_PAD_LD3 = 54,
- MX25_PAD_LD4 = 55,
- MX25_PAD_LD5 = 56,
- MX25_PAD_LD6 = 57,
- MX25_PAD_LD7 = 58,
- MX25_PAD_LD8 = 59,
- MX25_PAD_LD9 = 60,
- MX25_PAD_LD10 = 61,
- MX25_PAD_LD11 = 62,
- MX25_PAD_LD12 = 63,
- MX25_PAD_LD13 = 64,
- MX25_PAD_LD14 = 65,
- MX25_PAD_LD15 = 66,
- MX25_PAD_HSYNC = 67,
- MX25_PAD_VSYNC = 68,
- MX25_PAD_LSCLK = 69,
- MX25_PAD_OE_ACD = 70,
- MX25_PAD_CONTRAST = 71,
- MX25_PAD_PWM = 72,
- MX25_PAD_CSI_D2 = 73,
- MX25_PAD_CSI_D3 = 74,
- MX25_PAD_CSI_D4 = 75,
- MX25_PAD_CSI_D5 = 76,
- MX25_PAD_CSI_D6 = 77,
- MX25_PAD_CSI_D7 = 78,
- MX25_PAD_CSI_D8 = 79,
- MX25_PAD_CSI_D9 = 80,
- MX25_PAD_CSI_MCLK = 81,
- MX25_PAD_CSI_VSYNC = 82,
- MX25_PAD_CSI_HSYNC = 83,
- MX25_PAD_CSI_PIXCLK = 84,
- MX25_PAD_I2C1_CLK = 85,
- MX25_PAD_I2C1_DAT = 86,
- MX25_PAD_CSPI1_MOSI = 87,
- MX25_PAD_CSPI1_MISO = 88,
- MX25_PAD_CSPI1_SS0 = 89,
- MX25_PAD_CSPI1_SS1 = 90,
- MX25_PAD_CSPI1_SCLK = 91,
- MX25_PAD_CSPI1_RDY = 92,
- MX25_PAD_UART1_RXD = 93,
- MX25_PAD_UART1_TXD = 94,
- MX25_PAD_UART1_RTS = 95,
- MX25_PAD_UART1_CTS = 96,
- MX25_PAD_UART2_RXD = 97,
- MX25_PAD_UART2_TXD = 98,
- MX25_PAD_UART2_RTS = 99,
- MX25_PAD_UART2_CTS = 100,
- MX25_PAD_SD1_CMD = 101,
- MX25_PAD_SD1_CLK = 102,
- MX25_PAD_SD1_DATA0 = 103,
- MX25_PAD_SD1_DATA1 = 104,
- MX25_PAD_SD1_DATA2 = 105,
- MX25_PAD_SD1_DATA3 = 106,
- MX25_PAD_KPP_ROW0 = 107,
- MX25_PAD_KPP_ROW1 = 108,
- MX25_PAD_KPP_ROW2 = 109,
- MX25_PAD_KPP_ROW3 = 110,
- MX25_PAD_KPP_COL0 = 111,
- MX25_PAD_KPP_COL1 = 112,
- MX25_PAD_KPP_COL2 = 113,
- MX25_PAD_KPP_COL3 = 114,
- MX25_PAD_FEC_MDC = 115,
- MX25_PAD_FEC_MDIO = 116,
- MX25_PAD_FEC_TDATA0 = 117,
- MX25_PAD_FEC_TDATA1 = 118,
- MX25_PAD_FEC_TX_EN = 119,
- MX25_PAD_FEC_RDATA0 = 120,
- MX25_PAD_FEC_RDATA1 = 121,
- MX25_PAD_FEC_RX_DV = 122,
- MX25_PAD_FEC_TX_CLK = 123,
- MX25_PAD_RTCK = 124,
- MX25_PAD_DE_B = 125,
- MX25_PAD_GPIO_A = 126,
- MX25_PAD_GPIO_B = 127,
- MX25_PAD_GPIO_C = 128,
- MX25_PAD_GPIO_D = 129,
- MX25_PAD_GPIO_E = 130,
- MX25_PAD_GPIO_F = 131,
- MX25_PAD_EXT_ARMCLK = 132,
- MX25_PAD_UPLL_BYPCLK = 133,
- MX25_PAD_VSTBY_REQ = 134,
- MX25_PAD_VSTBY_ACK = 135,
- MX25_PAD_POWER_FAIL = 136,
- MX25_PAD_CLKO = 137,
- MX25_PAD_BOOT_MODE0 = 138,
- MX25_PAD_BOOT_MODE1 = 139,
+ MX25_PAD_A10 = 2,
+ MX25_PAD_A13 = 3,
+ MX25_PAD_A14 = 4,
+ MX25_PAD_A15 = 5,
+ MX25_PAD_A16 = 6,
+ MX25_PAD_A17 = 7,
+ MX25_PAD_A18 = 8,
+ MX25_PAD_A19 = 9,
+ MX25_PAD_A20 = 10,
+ MX25_PAD_A21 = 11,
+ MX25_PAD_A22 = 12,
+ MX25_PAD_A23 = 13,
+ MX25_PAD_A24 = 14,
+ MX25_PAD_A25 = 15,
+ MX25_PAD_EB0 = 16,
+ MX25_PAD_EB1 = 17,
+ MX25_PAD_OE = 18,
+ MX25_PAD_CS0 = 19,
+ MX25_PAD_CS1 = 20,
+ MX25_PAD_CS4 = 21,
+ MX25_PAD_CS5 = 22,
+ MX25_PAD_NF_CE0 = 23,
+ MX25_PAD_ECB = 24,
+ MX25_PAD_LBA = 25,
+ MX25_PAD_BCLK = 26,
+ MX25_PAD_RW = 27,
+ MX25_PAD_NFWE_B = 28,
+ MX25_PAD_NFRE_B = 29,
+ MX25_PAD_NFALE = 30,
+ MX25_PAD_NFCLE = 31,
+ MX25_PAD_NFWP_B = 32,
+ MX25_PAD_NFRB = 33,
+ MX25_PAD_D15 = 34,
+ MX25_PAD_D14 = 35,
+ MX25_PAD_D13 = 36,
+ MX25_PAD_D12 = 37,
+ MX25_PAD_D11 = 38,
+ MX25_PAD_D10 = 39,
+ MX25_PAD_D9 = 40,
+ MX25_PAD_D8 = 41,
+ MX25_PAD_D7 = 42,
+ MX25_PAD_D6 = 43,
+ MX25_PAD_D5 = 44,
+ MX25_PAD_D4 = 45,
+ MX25_PAD_D3 = 46,
+ MX25_PAD_D2 = 47,
+ MX25_PAD_D1 = 48,
+ MX25_PAD_D0 = 49,
+ MX25_PAD_LD0 = 50,
+ MX25_PAD_LD1 = 51,
+ MX25_PAD_LD2 = 52,
+ MX25_PAD_LD3 = 53,
+ MX25_PAD_LD4 = 54,
+ MX25_PAD_LD5 = 55,
+ MX25_PAD_LD6 = 56,
+ MX25_PAD_LD7 = 57,
+ MX25_PAD_LD8 = 58,
+ MX25_PAD_LD9 = 59,
+ MX25_PAD_LD10 = 60,
+ MX25_PAD_LD11 = 61,
+ MX25_PAD_LD12 = 62,
+ MX25_PAD_LD13 = 63,
+ MX25_PAD_LD14 = 64,
+ MX25_PAD_LD15 = 65,
+ MX25_PAD_HSYNC = 66,
+ MX25_PAD_VSYNC = 67,
+ MX25_PAD_LSCLK = 68,
+ MX25_PAD_OE_ACD = 69,
+ MX25_PAD_CONTRAST = 70,
+ MX25_PAD_PWM = 71,
+ MX25_PAD_CSI_D2 = 72,
+ MX25_PAD_CSI_D3 = 73,
+ MX25_PAD_CSI_D4 = 74,
+ MX25_PAD_CSI_D5 = 75,
+ MX25_PAD_CSI_D6 = 76,
+ MX25_PAD_CSI_D7 = 77,
+ MX25_PAD_CSI_D8 = 78,
+ MX25_PAD_CSI_D9 = 79,
+ MX25_PAD_CSI_MCLK = 80,
+ MX25_PAD_CSI_VSYNC = 81,
+ MX25_PAD_CSI_HSYNC = 82,
+ MX25_PAD_CSI_PIXCLK = 83,
+ MX25_PAD_I2C1_CLK = 84,
+ MX25_PAD_I2C1_DAT = 85,
+ MX25_PAD_CSPI1_MOSI = 86,
+ MX25_PAD_CSPI1_MISO = 87,
+ MX25_PAD_CSPI1_SS0 = 88,
+ MX25_PAD_CSPI1_SS1 = 89,
+ MX25_PAD_CSPI1_SCLK = 90,
+ MX25_PAD_CSPI1_RDY = 91,
+ MX25_PAD_UART1_RXD = 92,
+ MX25_PAD_UART1_TXD = 93,
+ MX25_PAD_UART1_RTS = 94,
+ MX25_PAD_UART1_CTS = 95,
+ MX25_PAD_UART2_RXD = 96,
+ MX25_PAD_UART2_TXD = 97,
+ MX25_PAD_UART2_RTS = 98,
+ MX25_PAD_UART2_CTS = 99,
+ MX25_PAD_SD1_CMD = 100,
+ MX25_PAD_SD1_CLK = 101,
+ MX25_PAD_SD1_DATA0 = 102,
+ MX25_PAD_SD1_DATA1 = 103,
+ MX25_PAD_SD1_DATA2 = 104,
+ MX25_PAD_SD1_DATA3 = 105,
+ MX25_PAD_KPP_ROW0 = 106,
+ MX25_PAD_KPP_ROW1 = 107,
+ MX25_PAD_KPP_ROW2 = 108,
+ MX25_PAD_KPP_ROW3 = 109,
+ MX25_PAD_KPP_COL0 = 110,
+ MX25_PAD_KPP_COL1 = 111,
+ MX25_PAD_KPP_COL2 = 112,
+ MX25_PAD_KPP_COL3 = 113,
+ MX25_PAD_FEC_MDC = 114,
+ MX25_PAD_FEC_MDIO = 115,
+ MX25_PAD_FEC_TDATA0 = 116,
+ MX25_PAD_FEC_TDATA1 = 117,
+ MX25_PAD_FEC_TX_EN = 118,
+ MX25_PAD_FEC_RDATA0 = 119,
+ MX25_PAD_FEC_RDATA1 = 120,
+ MX25_PAD_FEC_RX_DV = 121,
+ MX25_PAD_FEC_TX_CLK = 122,
+ MX25_PAD_RTCK = 123,
+ MX25_PAD_DE_B = 124,
+ MX25_PAD_GPIO_A = 125,
+ MX25_PAD_GPIO_B = 126,
+ MX25_PAD_GPIO_C = 127,
+ MX25_PAD_GPIO_D = 128,
+ MX25_PAD_GPIO_E = 129,
+ MX25_PAD_GPIO_F = 130,
+ MX25_PAD_EXT_ARMCLK = 131,
+ MX25_PAD_UPLL_BYPCLK = 132,
+ MX25_PAD_VSTBY_REQ = 133,
+ MX25_PAD_VSTBY_ACK = 134,
+ MX25_PAD_POWER_FAIL = 135,
+ MX25_PAD_CLKO = 136,
+ MX25_PAD_BOOT_MODE0 = 137,
+ MX25_PAD_BOOT_MODE1 = 138,
};
/* Pad names for the pinmux subsystem */
static const struct pinctrl_pin_desc imx25_pinctrl_pads[] = {
IMX_PINCTRL_PIN(MX25_PAD_RESERVE0),
- IMX_PINCTRL_PIN(MX25_PAD_RESERVE1),
IMX_PINCTRL_PIN(MX25_PAD_A10),
IMX_PINCTRL_PIN(MX25_PAD_A13),
IMX_PINCTRL_PIN(MX25_PAD_A14),
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
index e9f8b39d1a9f..3034fd03bced 100644
--- a/drivers/pinctrl/intel/pinctrl-cherryview.c
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -148,6 +148,11 @@ struct chv_community {
size_t ngpios;
};
+struct chv_pin_context {
+ u32 padctrl0;
+ u32 padctrl1;
+};
+
/**
* struct chv_pinctrl - CHV pinctrl private structure
* @dev: Pointer to the parent device
@@ -172,6 +177,8 @@ struct chv_pinctrl {
spinlock_t lock;
unsigned intr_lines[16];
const struct chv_community *community;
+ u32 saved_intmask;
+ struct chv_pin_context *saved_pin_context;
};
#define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip)
@@ -873,9 +880,22 @@ static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
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;
+ value = readl(reg);
+
+ /*
+ * If the pin is in HiZ mode (both TX and RX buffers are
+ * disabled) we turn it to be input now.
+ */
+ if ((value & CHV_PADCTRL0_GPIOCFG_MASK) ==
+ (CHV_PADCTRL0_GPIOCFG_HIZ << CHV_PADCTRL0_GPIOCFG_SHIFT)) {
+ value &= ~CHV_PADCTRL0_GPIOCFG_MASK;
+ value |= CHV_PADCTRL0_GPIOCFG_GPI <<
+ CHV_PADCTRL0_GPIOCFG_SHIFT;
+ }
+
+ /* Switch to a GPIO mode */
+ value |= CHV_PADCTRL0_GPIOEN;
chv_writel(value, reg);
}
@@ -1443,6 +1463,14 @@ static int chv_pinctrl_probe(struct platform_device *pdev)
spin_lock_init(&pctrl->lock);
pctrl->dev = &pdev->dev;
+#ifdef CONFIG_PM_SLEEP
+ pctrl->saved_pin_context = devm_kcalloc(pctrl->dev,
+ pctrl->community->npins, sizeof(*pctrl->saved_pin_context),
+ GFP_KERNEL);
+ if (!pctrl->saved_pin_context)
+ return -ENOMEM;
+#endif
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pctrl->regs))
@@ -1486,6 +1514,94 @@ static int chv_pinctrl_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int chv_pinctrl_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+ int i;
+
+ pctrl->saved_intmask = readl(pctrl->regs + CHV_INTMASK);
+
+ for (i = 0; i < pctrl->community->npins; i++) {
+ const struct pinctrl_pin_desc *desc;
+ struct chv_pin_context *ctx;
+ void __iomem *reg;
+
+ desc = &pctrl->community->pins[i];
+ if (chv_pad_locked(pctrl, desc->number))
+ continue;
+
+ ctx = &pctrl->saved_pin_context[i];
+
+ reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL0);
+ ctx->padctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIORXSTATE;
+
+ reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL1);
+ ctx->padctrl1 = readl(reg);
+ }
+
+ return 0;
+}
+
+static int chv_pinctrl_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+ int i;
+
+ /*
+ * Mask all interrupts before restoring per-pin configuration
+ * registers because we don't know in which state BIOS left them
+ * upon exiting suspend.
+ */
+ chv_writel(0, pctrl->regs + CHV_INTMASK);
+
+ for (i = 0; i < pctrl->community->npins; i++) {
+ const struct pinctrl_pin_desc *desc;
+ const struct chv_pin_context *ctx;
+ void __iomem *reg;
+ u32 val;
+
+ desc = &pctrl->community->pins[i];
+ if (chv_pad_locked(pctrl, desc->number))
+ continue;
+
+ ctx = &pctrl->saved_pin_context[i];
+
+ /* Only restore if our saved state differs from the current */
+ reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL0);
+ val = readl(reg) & ~CHV_PADCTRL0_GPIORXSTATE;
+ if (ctx->padctrl0 != val) {
+ chv_writel(ctx->padctrl0, reg);
+ dev_dbg(pctrl->dev, "restored pin %2u ctrl0 0x%08x\n",
+ desc->number, readl(reg));
+ }
+
+ reg = chv_padreg(pctrl, desc->number, CHV_PADCTRL1);
+ val = readl(reg);
+ if (ctx->padctrl1 != val) {
+ chv_writel(ctx->padctrl1, reg);
+ dev_dbg(pctrl->dev, "restored pin %2u ctrl1 0x%08x\n",
+ desc->number, readl(reg));
+ }
+ }
+
+ /*
+ * Now that all pins are restored to known state, we can restore
+ * the interrupt mask register as well.
+ */
+ chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);
+ chv_writel(pctrl->saved_intmask, pctrl->regs + CHV_INTMASK);
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops chv_pinctrl_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(chv_pinctrl_suspend, chv_pinctrl_resume)
+};
+
static const struct acpi_device_id chv_pinctrl_acpi_match[] = {
{ "INT33FF" },
{ }
@@ -1497,7 +1613,7 @@ static struct platform_driver chv_pinctrl_driver = {
.remove = chv_pinctrl_remove,
.driver = {
.name = "cherryview-pinctrl",
- .owner = THIS_MODULE,
+ .pm = &chv_pinctrl_pm_ops,
.acpi_match_table = chv_pinctrl_acpi_match,
},
};
diff --git a/drivers/pinctrl/meson/Makefile b/drivers/pinctrl/meson/Makefile
new file mode 100644
index 000000000000..eafc216067a4
--- /dev/null
+++ b/drivers/pinctrl/meson/Makefile
@@ -0,0 +1,2 @@
+obj-y += pinctrl-meson8.o
+obj-y += pinctrl-meson.o
diff --git a/drivers/pinctrl/meson/pinctrl-meson.c b/drivers/pinctrl/meson/pinctrl-meson.c
new file mode 100644
index 000000000000..a2bf49ce16e7
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson.c
@@ -0,0 +1,761 @@
+/*
+ * Pin controller and GPIO driver for Amlogic Meson SoCs
+ *
+ * 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/>.
+ */
+
+/*
+ * The available pins are organized in banks (A,B,C,D,E,X,Y,Z,AO,
+ * BOOT,CARD for meson6 and X,Y,DV,H,Z,AO,BOOT,CARD for meson8) and
+ * each bank has a variable number of pins.
+ *
+ * The AO bank is special because it belongs to the Always-On power
+ * domain which can't be powered off; the bank also uses a set of
+ * registers different from the other banks.
+ *
+ * For each of the two power domains (regular and always-on) there are
+ * 4 different register ranges that control the following properties
+ * of the pins:
+ * 1) pin muxing
+ * 2) pull enable/disable
+ * 3) pull up/down
+ * 4) GPIO direction, output value, input value
+ *
+ * In some cases the register ranges for pull enable and pull
+ * direction are the same and thus there are only 3 register ranges.
+ *
+ * Every pinmux group can be enabled by a specific bit in the first
+ * register range of the domain; when all groups for a given pin are
+ * disabled the pin acts as a GPIO.
+ *
+ * For the pull and GPIO configuration every bank uses a contiguous
+ * set of bits in the register sets described above; the same register
+ * can be shared by more banks with different offsets.
+ *
+ * In addition to this there are some registers shared between all
+ * banks that control the IRQ functionality. This feature is not
+ * supported at the moment by the driver.
+ */
+
+#include <linux/device.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/seq_file.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+#include "pinctrl-meson.h"
+
+/**
+ * meson_get_bank() - find the bank containing a given pin
+ *
+ * @domain: the domain containing the pin
+ * @pin: the pin number
+ * @bank: the found bank
+ *
+ * Return: 0 on success, a negative value on error
+ */
+static int meson_get_bank(struct meson_domain *domain, unsigned int pin,
+ struct meson_bank **bank)
+{
+ int i;
+
+ for (i = 0; i < domain->data->num_banks; i++) {
+ if (pin >= domain->data->banks[i].first &&
+ pin <= domain->data->banks[i].last) {
+ *bank = &domain->data->banks[i];
+ return 0;
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * meson_get_domain_and_bank() - find domain and bank containing a given pin
+ *
+ * @pc: Meson pin controller device
+ * @pin: the pin number
+ * @domain: the found domain
+ * @bank: the found bank
+ *
+ * Return: 0 on success, a negative value on error
+ */
+static int meson_get_domain_and_bank(struct meson_pinctrl *pc, unsigned int pin,
+ struct meson_domain **domain,
+ struct meson_bank **bank)
+{
+ struct meson_domain *d;
+ int i;
+
+ for (i = 0; i < pc->data->num_domains; i++) {
+ d = &pc->domains[i];
+ if (pin >= d->data->pin_base &&
+ pin < d->data->pin_base + d->data->num_pins) {
+ *domain = d;
+ return meson_get_bank(d, pin, bank);
+ }
+ }
+
+ return -EINVAL;
+}
+
+/**
+ * meson_calc_reg_and_bit() - calculate register and bit for a pin
+ *
+ * @bank: the bank containing the pin
+ * @pin: the pin number
+ * @reg_type: the type of register needed (pull-enable, pull, etc...)
+ * @reg: the computed register offset
+ * @bit: the computed bit
+ */
+static void meson_calc_reg_and_bit(struct meson_bank *bank, unsigned int pin,
+ enum meson_reg_type reg_type,
+ unsigned int *reg, unsigned int *bit)
+{
+ struct meson_reg_desc *desc = &bank->regs[reg_type];
+
+ *reg = desc->reg * 4;
+ *bit = desc->bit + pin - bank->first;
+}
+
+static int meson_get_groups_count(struct pinctrl_dev *pcdev)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->data->num_groups;
+}
+
+static const char *meson_get_group_name(struct pinctrl_dev *pcdev,
+ unsigned selector)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->data->groups[selector].name;
+}
+
+static int meson_get_group_pins(struct pinctrl_dev *pcdev, unsigned selector,
+ const unsigned **pins, unsigned *num_pins)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ *pins = pc->data->groups[selector].pins;
+ *num_pins = pc->data->groups[selector].num_pins;
+
+ return 0;
+}
+
+static void meson_pin_dbg_show(struct pinctrl_dev *pcdev, struct seq_file *s,
+ unsigned offset)
+{
+ seq_printf(s, " %s", dev_name(pcdev->dev));
+}
+
+static const struct pinctrl_ops meson_pctrl_ops = {
+ .get_groups_count = meson_get_groups_count,
+ .get_group_name = meson_get_group_name,
+ .get_group_pins = meson_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+ .pin_dbg_show = meson_pin_dbg_show,
+};
+
+/**
+ * meson_pmx_disable_other_groups() - disable other groups using a given pin
+ *
+ * @pc: meson pin controller device
+ * @pin: number of the pin
+ * @sel_group: index of the selected group, or -1 if none
+ *
+ * The function disables all pinmux groups using a pin except the
+ * selected one. If @sel_group is -1 all groups are disabled, leaving
+ * the pin in GPIO mode.
+ */
+static void meson_pmx_disable_other_groups(struct meson_pinctrl *pc,
+ unsigned int pin, int sel_group)
+{
+ struct meson_pmx_group *group;
+ struct meson_domain *domain;
+ int i, j;
+
+ for (i = 0; i < pc->data->num_groups; i++) {
+ group = &pc->data->groups[i];
+ if (group->is_gpio || i == sel_group)
+ continue;
+
+ for (j = 0; j < group->num_pins; j++) {
+ if (group->pins[j] == pin) {
+ /* We have found a group using the pin */
+ domain = &pc->domains[group->domain];
+ regmap_update_bits(domain->reg_mux,
+ group->reg * 4,
+ BIT(group->bit), 0);
+ }
+ }
+ }
+}
+
+static int meson_pmx_set_mux(struct pinctrl_dev *pcdev, unsigned func_num,
+ unsigned group_num)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ struct meson_pmx_func *func = &pc->data->funcs[func_num];
+ struct meson_pmx_group *group = &pc->data->groups[group_num];
+ struct meson_domain *domain = &pc->domains[group->domain];
+ int i, ret = 0;
+
+ dev_dbg(pc->dev, "enable function %s, group %s\n", func->name,
+ group->name);
+
+ /*
+ * Disable groups using the same pin.
+ * The selected group is not disabled to avoid glitches.
+ */
+ for (i = 0; i < group->num_pins; i++)
+ meson_pmx_disable_other_groups(pc, group->pins[i], group_num);
+
+ /* Function 0 (GPIO) doesn't need any additional setting */
+ if (func_num)
+ ret = regmap_update_bits(domain->reg_mux, group->reg * 4,
+ BIT(group->bit), BIT(group->bit));
+
+ return ret;
+}
+
+static int meson_pmx_request_gpio(struct pinctrl_dev *pcdev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ meson_pmx_disable_other_groups(pc, range->pin_base + offset, -1);
+
+ return 0;
+}
+
+static int meson_pmx_get_funcs_count(struct pinctrl_dev *pcdev)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->data->num_funcs;
+}
+
+static const char *meson_pmx_get_func_name(struct pinctrl_dev *pcdev,
+ unsigned selector)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ return pc->data->funcs[selector].name;
+}
+
+static int meson_pmx_get_groups(struct pinctrl_dev *pcdev, unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+
+ *groups = pc->data->funcs[selector].groups;
+ *num_groups = pc->data->funcs[selector].num_groups;
+
+ return 0;
+}
+
+static const struct pinmux_ops meson_pmx_ops = {
+ .set_mux = meson_pmx_set_mux,
+ .get_functions_count = meson_pmx_get_funcs_count,
+ .get_function_name = meson_pmx_get_func_name,
+ .get_function_groups = meson_pmx_get_groups,
+ .gpio_request_enable = meson_pmx_request_gpio,
+};
+
+static int meson_pinconf_set(struct pinctrl_dev *pcdev, unsigned int pin,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ struct meson_domain *domain;
+ struct meson_bank *bank;
+ enum pin_config_param param;
+ unsigned int reg, bit;
+ int i, ret;
+ u16 arg;
+
+ ret = meson_get_domain_and_bank(pc, pin, &domain, &bank);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < num_configs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ dev_dbg(pc->dev, "pin %u: disable bias\n", pin);
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
+ ret = regmap_update_bits(domain->reg_pull, reg,
+ BIT(bit), 0);
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ dev_dbg(pc->dev, "pin %u: enable pull-up\n", pin);
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
+ &reg, &bit);
+ ret = regmap_update_bits(domain->reg_pullen, reg,
+ BIT(bit), BIT(bit));
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
+ ret = regmap_update_bits(domain->reg_pull, reg,
+ BIT(bit), BIT(bit));
+ if (ret)
+ return ret;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ dev_dbg(pc->dev, "pin %u: enable pull-down\n", pin);
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN,
+ &reg, &bit);
+ ret = regmap_update_bits(domain->reg_pullen, reg,
+ BIT(bit), BIT(bit));
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
+ ret = regmap_update_bits(domain->reg_pull, reg,
+ BIT(bit), 0);
+ if (ret)
+ return ret;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+ }
+
+ return 0;
+}
+
+static int meson_pinconf_get_pull(struct meson_pinctrl *pc, unsigned int pin)
+{
+ struct meson_domain *domain;
+ struct meson_bank *bank;
+ unsigned int reg, bit, val;
+ int ret, conf;
+
+ ret = meson_get_domain_and_bank(pc, pin, &domain, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_PULLEN, &reg, &bit);
+
+ ret = regmap_read(domain->reg_pullen, reg, &val);
+ if (ret)
+ return ret;
+
+ if (!(val & BIT(bit))) {
+ conf = PIN_CONFIG_BIAS_DISABLE;
+ } else {
+ meson_calc_reg_and_bit(bank, pin, REG_PULL, &reg, &bit);
+
+ ret = regmap_read(domain->reg_pull, reg, &val);
+ if (ret)
+ return ret;
+
+ if (val & BIT(bit))
+ conf = PIN_CONFIG_BIAS_PULL_UP;
+ else
+ conf = PIN_CONFIG_BIAS_PULL_DOWN;
+ }
+
+ return conf;
+}
+
+static int meson_pinconf_get(struct pinctrl_dev *pcdev, unsigned int pin,
+ unsigned long *config)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ u16 arg;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (meson_pinconf_get_pull(pc, pin) == param)
+ arg = 1;
+ else
+ return -EINVAL;
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ dev_dbg(pc->dev, "pinconf for pin %u is %lu\n", pin, *config);
+
+ return 0;
+}
+
+static int meson_pinconf_group_set(struct pinctrl_dev *pcdev,
+ unsigned int num_group,
+ unsigned long *configs, unsigned num_configs)
+{
+ struct meson_pinctrl *pc = pinctrl_dev_get_drvdata(pcdev);
+ struct meson_pmx_group *group = &pc->data->groups[num_group];
+ int i;
+
+ dev_dbg(pc->dev, "set pinconf for group %s\n", group->name);
+
+ for (i = 0; i < group->num_pins; i++) {
+ meson_pinconf_set(pcdev, group->pins[i], configs,
+ num_configs);
+ }
+
+ return 0;
+}
+
+static int meson_pinconf_group_get(struct pinctrl_dev *pcdev,
+ unsigned int group, unsigned long *config)
+{
+ return -ENOSYS;
+}
+
+static const struct pinconf_ops meson_pinconf_ops = {
+ .pin_config_get = meson_pinconf_get,
+ .pin_config_set = meson_pinconf_set,
+ .pin_config_group_get = meson_pinconf_group_get,
+ .pin_config_group_set = meson_pinconf_group_set,
+ .is_generic = true,
+};
+
+static inline struct meson_domain *to_meson_domain(struct gpio_chip *chip)
+{
+ return container_of(chip, struct meson_domain, chip);
+}
+
+static int meson_gpio_request(struct gpio_chip *chip, unsigned gpio)
+{
+ return pinctrl_request_gpio(chip->base + gpio);
+}
+
+static void meson_gpio_free(struct gpio_chip *chip, unsigned gpio)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+
+ pinctrl_free_gpio(domain->data->pin_base + gpio);
+}
+
+static int meson_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ unsigned int reg, bit, pin;
+ struct meson_bank *bank;
+ int ret;
+
+ pin = domain->data->pin_base + gpio;
+ ret = meson_get_bank(domain, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_DIR, &reg, &bit);
+
+ return regmap_update_bits(domain->reg_gpio, reg, BIT(bit), BIT(bit));
+}
+
+static int meson_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
+ int value)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ unsigned int reg, bit, pin;
+ struct meson_bank *bank;
+ int ret;
+
+ pin = domain->data->pin_base + gpio;
+ ret = meson_get_bank(domain, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_DIR, &reg, &bit);
+ ret = regmap_update_bits(domain->reg_gpio, reg, BIT(bit), 0);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_OUT, &reg, &bit);
+ return regmap_update_bits(domain->reg_gpio, reg, BIT(bit),
+ value ? BIT(bit) : 0);
+}
+
+static void meson_gpio_set(struct gpio_chip *chip, unsigned gpio, int value)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ unsigned int reg, bit, pin;
+ struct meson_bank *bank;
+ int ret;
+
+ pin = domain->data->pin_base + gpio;
+ ret = meson_get_bank(domain, pin, &bank);
+ if (ret)
+ return;
+
+ meson_calc_reg_and_bit(bank, pin, REG_OUT, &reg, &bit);
+ regmap_update_bits(domain->reg_gpio, reg, BIT(bit),
+ value ? BIT(bit) : 0);
+}
+
+static int meson_gpio_get(struct gpio_chip *chip, unsigned gpio)
+{
+ struct meson_domain *domain = to_meson_domain(chip);
+ unsigned int reg, bit, val, pin;
+ struct meson_bank *bank;
+ int ret;
+
+ pin = domain->data->pin_base + gpio;
+ ret = meson_get_bank(domain, pin, &bank);
+ if (ret)
+ return ret;
+
+ meson_calc_reg_and_bit(bank, pin, REG_IN, &reg, &bit);
+ regmap_read(domain->reg_gpio, reg, &val);
+
+ return !!(val & BIT(bit));
+}
+
+static const struct of_device_id meson_pinctrl_dt_match[] = {
+ {
+ .compatible = "amlogic,meson8-pinctrl",
+ .data = &meson8_pinctrl_data,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, meson_pinctrl_dt_match);
+
+static int meson_gpiolib_register(struct meson_pinctrl *pc)
+{
+ struct meson_domain *domain;
+ int i, ret;
+
+ for (i = 0; i < pc->data->num_domains; i++) {
+ domain = &pc->domains[i];
+
+ domain->chip.label = domain->data->name;
+ domain->chip.dev = pc->dev;
+ domain->chip.request = meson_gpio_request;
+ domain->chip.free = meson_gpio_free;
+ domain->chip.direction_input = meson_gpio_direction_input;
+ domain->chip.direction_output = meson_gpio_direction_output;
+ domain->chip.get = meson_gpio_get;
+ domain->chip.set = meson_gpio_set;
+ domain->chip.base = -1;
+ domain->chip.ngpio = domain->data->num_pins;
+ domain->chip.can_sleep = false;
+ domain->chip.of_node = domain->of_node;
+ domain->chip.of_gpio_n_cells = 2;
+
+ ret = gpiochip_add(&domain->chip);
+ if (ret) {
+ dev_err(pc->dev, "can't add gpio chip %s\n",
+ domain->data->name);
+ goto fail;
+ }
+
+ ret = gpiochip_add_pin_range(&domain->chip, dev_name(pc->dev),
+ 0, domain->data->pin_base,
+ domain->chip.ngpio);
+ if (ret) {
+ dev_err(pc->dev, "can't add pin range\n");
+ goto fail;
+ }
+ }
+
+ return 0;
+fail:
+ for (i--; i >= 0; i--)
+ gpiochip_remove(&pc->domains[i].chip);
+
+ return ret;
+}
+
+static struct meson_domain_data *meson_get_domain_data(struct meson_pinctrl *pc,
+ struct device_node *np)
+{
+ int i;
+
+ for (i = 0; i < pc->data->num_domains; i++) {
+ if (!strcmp(np->name, pc->data->domain_data[i].name))
+ return &pc->data->domain_data[i];
+ }
+
+ return NULL;
+}
+
+static struct regmap_config meson_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static struct regmap *meson_map_resource(struct meson_pinctrl *pc,
+ struct device_node *node, char *name)
+{
+ struct resource res;
+ void __iomem *base;
+ int i;
+
+ i = of_property_match_string(node, "reg-names", name);
+ if (of_address_to_resource(node, i, &res))
+ return ERR_PTR(-ENOENT);
+
+ base = devm_ioremap_resource(pc->dev, &res);
+ if (IS_ERR(base))
+ return ERR_CAST(base);
+
+ meson_regmap_config.max_register = resource_size(&res) - 4;
+ meson_regmap_config.name = devm_kasprintf(pc->dev, GFP_KERNEL,
+ "%s-%s", node->name,
+ name);
+ if (!meson_regmap_config.name)
+ return ERR_PTR(-ENOMEM);
+
+ return devm_regmap_init_mmio(pc->dev, base, &meson_regmap_config);
+}
+
+static int meson_pinctrl_parse_dt(struct meson_pinctrl *pc,
+ struct device_node *node)
+{
+ struct device_node *np;
+ struct meson_domain *domain;
+ int i = 0, num_domains = 0;
+
+ for_each_child_of_node(node, np) {
+ if (!of_find_property(np, "gpio-controller", NULL))
+ continue;
+ num_domains++;
+ }
+
+ if (num_domains != pc->data->num_domains) {
+ dev_err(pc->dev, "wrong number of subnodes\n");
+ return -EINVAL;
+ }
+
+ pc->domains = devm_kzalloc(pc->dev, num_domains *
+ sizeof(struct meson_domain), GFP_KERNEL);
+ if (!pc->domains)
+ return -ENOMEM;
+
+ for_each_child_of_node(node, np) {
+ if (!of_find_property(np, "gpio-controller", NULL))
+ continue;
+
+ domain = &pc->domains[i];
+
+ domain->data = meson_get_domain_data(pc, np);
+ if (!domain->data) {
+ dev_err(pc->dev, "domain data not found for node %s\n",
+ np->name);
+ return -ENODEV;
+ }
+
+ domain->of_node = np;
+
+ domain->reg_mux = meson_map_resource(pc, np, "mux");
+ if (IS_ERR(domain->reg_mux)) {
+ dev_err(pc->dev, "mux registers not found\n");
+ return PTR_ERR(domain->reg_mux);
+ }
+
+ domain->reg_pull = meson_map_resource(pc, np, "pull");
+ if (IS_ERR(domain->reg_pull)) {
+ dev_err(pc->dev, "pull registers not found\n");
+ return PTR_ERR(domain->reg_pull);
+ }
+
+ domain->reg_pullen = meson_map_resource(pc, np, "pull-enable");
+ /* Use pull region if pull-enable one is not present */
+ if (IS_ERR(domain->reg_pullen))
+ domain->reg_pullen = domain->reg_pull;
+
+ domain->reg_gpio = meson_map_resource(pc, np, "gpio");
+ if (IS_ERR(domain->reg_gpio)) {
+ dev_err(pc->dev, "gpio registers not found\n");
+ return PTR_ERR(domain->reg_gpio);
+ }
+
+ i++;
+ }
+
+ return 0;
+}
+
+static int meson_pinctrl_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct meson_pinctrl *pc;
+ int ret;
+
+ pc = devm_kzalloc(dev, sizeof(struct meson_pinctrl), GFP_KERNEL);
+ if (!pc)
+ return -ENOMEM;
+
+ pc->dev = dev;
+ match = of_match_node(meson_pinctrl_dt_match, pdev->dev.of_node);
+ pc->data = (struct meson_pinctrl_data *)match->data;
+
+ ret = meson_pinctrl_parse_dt(pc, pdev->dev.of_node);
+ if (ret)
+ return ret;
+
+ pc->desc.name = "pinctrl-meson";
+ pc->desc.owner = THIS_MODULE;
+ pc->desc.pctlops = &meson_pctrl_ops;
+ pc->desc.pmxops = &meson_pmx_ops;
+ pc->desc.confops = &meson_pinconf_ops;
+ pc->desc.pins = pc->data->pins;
+ pc->desc.npins = pc->data->num_pins;
+
+ pc->pcdev = pinctrl_register(&pc->desc, pc->dev, pc);
+ if (!pc->pcdev) {
+ dev_err(pc->dev, "can't register pinctrl device");
+ return -EINVAL;
+ }
+
+ ret = meson_gpiolib_register(pc);
+ if (ret) {
+ pinctrl_unregister(pc->pcdev);
+ return ret;
+ }
+
+ return 0;
+}
+
+static struct platform_driver meson_pinctrl_driver = {
+ .probe = meson_pinctrl_probe,
+ .driver = {
+ .name = "meson-pinctrl",
+ .of_match_table = meson_pinctrl_dt_match,
+ },
+};
+module_platform_driver(meson_pinctrl_driver);
+
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_DESCRIPTION("Amlogic Meson pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/meson/pinctrl-meson.h b/drivers/pinctrl/meson/pinctrl-meson.h
new file mode 100644
index 000000000000..bfea8adc7953
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson.h
@@ -0,0 +1,209 @@
+/*
+ * Pin controller and GPIO driver for Amlogic Meson SoCs
+ *
+ * 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/gpio.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/regmap.h>
+#include <linux/types.h>
+
+/**
+ * struct meson_pmx_group - a pinmux group
+ *
+ * @name: group name
+ * @pins: pins in the group
+ * @num_pins: number of pins in the group
+ * @is_gpio: whether the group is a single GPIO group
+ * @reg: register offset for the group in the domain mux registers
+ * @bit bit index enabling the group
+ * @domain: index of the domain this group belongs to
+ */
+struct meson_pmx_group {
+ const char *name;
+ const unsigned int *pins;
+ unsigned int num_pins;
+ bool is_gpio;
+ unsigned int reg;
+ unsigned int bit;
+ unsigned int domain;
+};
+
+/**
+ * struct meson_pmx_func - a pinmux function
+ *
+ * @name: function name
+ * @groups: groups in the function
+ * @num_groups: number of groups in the function
+ */
+struct meson_pmx_func {
+ const char *name;
+ const char * const *groups;
+ unsigned int num_groups;
+};
+
+/**
+ * struct meson_reg_desc - a register descriptor
+ *
+ * @reg: register offset in the regmap
+ * @bit: bit index in register
+ *
+ * The structure describes the information needed to control pull,
+ * pull-enable, direction, etc. for a single pin
+ */
+struct meson_reg_desc {
+ unsigned int reg;
+ unsigned int bit;
+};
+
+/**
+ * enum meson_reg_type - type of registers encoded in @meson_reg_desc
+ */
+enum meson_reg_type {
+ REG_PULLEN,
+ REG_PULL,
+ REG_DIR,
+ REG_OUT,
+ REG_IN,
+ NUM_REG,
+};
+
+/**
+ * struct meson bank
+ *
+ * @name: bank name
+ * @first: first pin of the bank
+ * @last: last pin of the bank
+ * @regs: array of register descriptors
+ *
+ * A bank represents a set of pins controlled by a contiguous set of
+ * bits in the domain registers. The structure specifies which bits in
+ * the regmap control the different functionalities. Each member of
+ * the @regs array refers to the first pin of the bank.
+ */
+struct meson_bank {
+ const char *name;
+ unsigned int first;
+ unsigned int last;
+ struct meson_reg_desc regs[NUM_REG];
+};
+
+/**
+ * struct meson_domain_data - domain platform data
+ *
+ * @name: name of the domain
+ * @banks: set of banks belonging to the domain
+ * @num_banks: number of banks in the domain
+ */
+struct meson_domain_data {
+ const char *name;
+ struct meson_bank *banks;
+ unsigned int num_banks;
+ unsigned int pin_base;
+ unsigned int num_pins;
+};
+
+/**
+ * struct meson_domain
+ *
+ * @reg_mux: registers for mux settings
+ * @reg_pullen: registers for pull-enable settings
+ * @reg_pull: registers for pull settings
+ * @reg_gpio: registers for gpio settings
+ * @chip: gpio chip associated with the domain
+ * @data; platform data for the domain
+ * @node: device tree node for the domain
+ *
+ * A domain represents a set of banks controlled by the same set of
+ * registers.
+ */
+struct meson_domain {
+ struct regmap *reg_mux;
+ struct regmap *reg_pullen;
+ struct regmap *reg_pull;
+ struct regmap *reg_gpio;
+
+ struct gpio_chip chip;
+ struct meson_domain_data *data;
+ struct device_node *of_node;
+};
+
+struct meson_pinctrl_data {
+ const struct pinctrl_pin_desc *pins;
+ struct meson_pmx_group *groups;
+ struct meson_pmx_func *funcs;
+ struct meson_domain_data *domain_data;
+ unsigned int num_pins;
+ unsigned int num_groups;
+ unsigned int num_funcs;
+ unsigned int num_domains;
+};
+
+struct meson_pinctrl {
+ struct device *dev;
+ struct pinctrl_dev *pcdev;
+ struct pinctrl_desc desc;
+ struct meson_pinctrl_data *data;
+ struct meson_domain *domains;
+};
+
+#define GROUP(grp, r, b) \
+ { \
+ .name = #grp, \
+ .pins = grp ## _pins, \
+ .num_pins = ARRAY_SIZE(grp ## _pins), \
+ .reg = r, \
+ .bit = b, \
+ .domain = 0, \
+ }
+
+#define GPIO_GROUP(gpio) \
+ { \
+ .name = #gpio, \
+ .pins = (const unsigned int[]){ PIN_ ## gpio}, \
+ .num_pins = 1, \
+ .is_gpio = true, \
+ }
+
+#define GROUP_AO(grp, r, b) \
+ { \
+ .name = #grp, \
+ .pins = grp ## _pins, \
+ .num_pins = ARRAY_SIZE(grp ## _pins), \
+ .reg = r, \
+ .bit = b, \
+ .domain = 1, \
+ }
+
+#define FUNCTION(fn) \
+ { \
+ .name = #fn, \
+ .groups = fn ## _groups, \
+ .num_groups = ARRAY_SIZE(fn ## _groups), \
+ }
+
+#define BANK(n, f, l, per, peb, pr, pb, dr, db, or, ob, ir, ib) \
+ { \
+ .name = n, \
+ .first = f, \
+ .last = l, \
+ .regs = { \
+ [REG_PULLEN] = { per, peb }, \
+ [REG_PULL] = { pr, pb }, \
+ [REG_DIR] = { dr, db }, \
+ [REG_OUT] = { or, ob }, \
+ [REG_IN] = { ir, ib }, \
+ }, \
+ }
+
+#define MESON_PIN(x) PINCTRL_PIN(PIN_ ## x, #x)
+
+extern struct meson_pinctrl_data meson8_pinctrl_data;
diff --git a/drivers/pinctrl/meson/pinctrl-meson8.c b/drivers/pinctrl/meson/pinctrl-meson8.c
new file mode 100644
index 000000000000..f8aa3a281767
--- /dev/null
+++ b/drivers/pinctrl/meson/pinctrl-meson8.c
@@ -0,0 +1,1089 @@
+/*
+ * Pin controller and GPIO driver for Amlogic Meson8.
+ *
+ * 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 <dt-bindings/gpio/meson8-gpio.h>
+#include "pinctrl-meson.h"
+
+#define AO_OFFSET 120
+
+#define PIN_GPIOX_0 GPIOX_0
+#define PIN_GPIOX_1 GPIOX_1
+#define PIN_GPIOX_2 GPIOX_2
+#define PIN_GPIOX_3 GPIOX_3
+#define PIN_GPIOX_4 GPIOX_4
+#define PIN_GPIOX_5 GPIOX_5
+#define PIN_GPIOX_6 GPIOX_6
+#define PIN_GPIOX_7 GPIOX_7
+#define PIN_GPIOX_8 GPIOX_8
+#define PIN_GPIOX_9 GPIOX_9
+#define PIN_GPIOX_10 GPIOX_10
+#define PIN_GPIOX_11 GPIOX_11
+#define PIN_GPIOX_12 GPIOX_12
+#define PIN_GPIOX_13 GPIOX_13
+#define PIN_GPIOX_14 GPIOX_14
+#define PIN_GPIOX_15 GPIOX_15
+#define PIN_GPIOX_16 GPIOX_16
+#define PIN_GPIOX_17 GPIOX_17
+#define PIN_GPIOX_18 GPIOX_18
+#define PIN_GPIOX_19 GPIOX_19
+#define PIN_GPIOX_20 GPIOX_20
+#define PIN_GPIOX_21 GPIOX_21
+#define PIN_GPIOY_0 GPIOY_0
+#define PIN_GPIOY_1 GPIOY_1
+#define PIN_GPIOY_2 GPIOY_2
+#define PIN_GPIOY_3 GPIOY_3
+#define PIN_GPIOY_4 GPIOY_4
+#define PIN_GPIOY_5 GPIOY_5
+#define PIN_GPIOY_6 GPIOY_6
+#define PIN_GPIOY_7 GPIOY_7
+#define PIN_GPIOY_8 GPIOY_8
+#define PIN_GPIOY_9 GPIOY_9
+#define PIN_GPIOY_10 GPIOY_10
+#define PIN_GPIOY_11 GPIOY_11
+#define PIN_GPIOY_12 GPIOY_12
+#define PIN_GPIOY_13 GPIOY_13
+#define PIN_GPIOY_14 GPIOY_14
+#define PIN_GPIOY_15 GPIOY_15
+#define PIN_GPIOY_16 GPIOY_16
+#define PIN_GPIODV_0 GPIODV_0
+#define PIN_GPIODV_1 GPIODV_1
+#define PIN_GPIODV_2 GPIODV_2
+#define PIN_GPIODV_3 GPIODV_3
+#define PIN_GPIODV_4 GPIODV_4
+#define PIN_GPIODV_5 GPIODV_5
+#define PIN_GPIODV_6 GPIODV_6
+#define PIN_GPIODV_7 GPIODV_7
+#define PIN_GPIODV_8 GPIODV_8
+#define PIN_GPIODV_9 GPIODV_9
+#define PIN_GPIODV_10 GPIODV_10
+#define PIN_GPIODV_11 GPIODV_11
+#define PIN_GPIODV_12 GPIODV_12
+#define PIN_GPIODV_13 GPIODV_13
+#define PIN_GPIODV_14 GPIODV_14
+#define PIN_GPIODV_15 GPIODV_15
+#define PIN_GPIODV_16 GPIODV_16
+#define PIN_GPIODV_17 GPIODV_17
+#define PIN_GPIODV_18 GPIODV_18
+#define PIN_GPIODV_19 GPIODV_19
+#define PIN_GPIODV_20 GPIODV_20
+#define PIN_GPIODV_21 GPIODV_21
+#define PIN_GPIODV_22 GPIODV_22
+#define PIN_GPIODV_23 GPIODV_23
+#define PIN_GPIODV_24 GPIODV_24
+#define PIN_GPIODV_25 GPIODV_25
+#define PIN_GPIODV_26 GPIODV_26
+#define PIN_GPIODV_27 GPIODV_27
+#define PIN_GPIODV_28 GPIODV_28
+#define PIN_GPIODV_29 GPIODV_29
+#define PIN_GPIOH_0 GPIOH_0
+#define PIN_GPIOH_1 GPIOH_1
+#define PIN_GPIOH_2 GPIOH_2
+#define PIN_GPIOH_3 GPIOH_3
+#define PIN_GPIOH_4 GPIOH_4
+#define PIN_GPIOH_5 GPIOH_5
+#define PIN_GPIOH_6 GPIOH_6
+#define PIN_GPIOH_7 GPIOH_7
+#define PIN_GPIOH_8 GPIOH_8
+#define PIN_GPIOH_9 GPIOH_9
+#define PIN_GPIOZ_0 GPIOZ_0
+#define PIN_GPIOZ_1 GPIOZ_1
+#define PIN_GPIOZ_2 GPIOZ_2
+#define PIN_GPIOZ_3 GPIOZ_3
+#define PIN_GPIOZ_4 GPIOZ_4
+#define PIN_GPIOZ_5 GPIOZ_5
+#define PIN_GPIOZ_6 GPIOZ_6
+#define PIN_GPIOZ_7 GPIOZ_7
+#define PIN_GPIOZ_8 GPIOZ_8
+#define PIN_GPIOZ_9 GPIOZ_9
+#define PIN_GPIOZ_10 GPIOZ_10
+#define PIN_GPIOZ_11 GPIOZ_11
+#define PIN_GPIOZ_12 GPIOZ_12
+#define PIN_GPIOZ_13 GPIOZ_13
+#define PIN_GPIOZ_14 GPIOZ_14
+#define PIN_CARD_0 CARD_0
+#define PIN_CARD_1 CARD_1
+#define PIN_CARD_2 CARD_2
+#define PIN_CARD_3 CARD_3
+#define PIN_CARD_4 CARD_4
+#define PIN_CARD_5 CARD_5
+#define PIN_CARD_6 CARD_6
+#define PIN_BOOT_0 BOOT_0
+#define PIN_BOOT_1 BOOT_1
+#define PIN_BOOT_2 BOOT_2
+#define PIN_BOOT_3 BOOT_3
+#define PIN_BOOT_4 BOOT_4
+#define PIN_BOOT_5 BOOT_5
+#define PIN_BOOT_6 BOOT_6
+#define PIN_BOOT_7 BOOT_7
+#define PIN_BOOT_8 BOOT_8
+#define PIN_BOOT_9 BOOT_9
+#define PIN_BOOT_10 BOOT_10
+#define PIN_BOOT_11 BOOT_11
+#define PIN_BOOT_12 BOOT_12
+#define PIN_BOOT_13 BOOT_13
+#define PIN_BOOT_14 BOOT_14
+#define PIN_BOOT_15 BOOT_15
+#define PIN_BOOT_16 BOOT_16
+#define PIN_BOOT_17 BOOT_17
+#define PIN_BOOT_18 BOOT_18
+
+#define PIN_GPIOAO_0 (AO_OFFSET + GPIOAO_0)
+#define PIN_GPIOAO_1 (AO_OFFSET + GPIOAO_1)
+#define PIN_GPIOAO_2 (AO_OFFSET + GPIOAO_2)
+#define PIN_GPIOAO_3 (AO_OFFSET + GPIOAO_3)
+#define PIN_GPIOAO_4 (AO_OFFSET + GPIOAO_4)
+#define PIN_GPIOAO_5 (AO_OFFSET + GPIOAO_5)
+#define PIN_GPIOAO_6 (AO_OFFSET + GPIOAO_6)
+#define PIN_GPIOAO_7 (AO_OFFSET + GPIOAO_7)
+#define PIN_GPIOAO_8 (AO_OFFSET + GPIOAO_8)
+#define PIN_GPIOAO_9 (AO_OFFSET + GPIOAO_9)
+#define PIN_GPIOAO_10 (AO_OFFSET + GPIOAO_10)
+#define PIN_GPIOAO_11 (AO_OFFSET + GPIOAO_11)
+#define PIN_GPIOAO_12 (AO_OFFSET + GPIOAO_12)
+#define PIN_GPIOAO_13 (AO_OFFSET + GPIOAO_13)
+#define PIN_GPIO_BSD_EN (AO_OFFSET + GPIO_BSD_EN)
+#define PIN_GPIO_TEST_N (AO_OFFSET + GPIO_TEST_N)
+
+static const struct pinctrl_pin_desc meson8_pins[] = {
+ MESON_PIN(GPIOX_0),
+ MESON_PIN(GPIOX_1),
+ MESON_PIN(GPIOX_2),
+ MESON_PIN(GPIOX_3),
+ MESON_PIN(GPIOX_4),
+ MESON_PIN(GPIOX_5),
+ MESON_PIN(GPIOX_6),
+ MESON_PIN(GPIOX_7),
+ MESON_PIN(GPIOX_8),
+ MESON_PIN(GPIOX_9),
+ MESON_PIN(GPIOX_10),
+ MESON_PIN(GPIOX_11),
+ MESON_PIN(GPIOX_12),
+ MESON_PIN(GPIOX_13),
+ MESON_PIN(GPIOX_14),
+ MESON_PIN(GPIOX_15),
+ MESON_PIN(GPIOX_16),
+ MESON_PIN(GPIOX_17),
+ MESON_PIN(GPIOX_18),
+ MESON_PIN(GPIOX_19),
+ MESON_PIN(GPIOX_20),
+ MESON_PIN(GPIOX_21),
+ MESON_PIN(GPIOY_0),
+ MESON_PIN(GPIOY_1),
+ MESON_PIN(GPIOY_2),
+ MESON_PIN(GPIOY_3),
+ MESON_PIN(GPIOY_4),
+ MESON_PIN(GPIOY_5),
+ MESON_PIN(GPIOY_6),
+ MESON_PIN(GPIOY_7),
+ MESON_PIN(GPIOY_8),
+ MESON_PIN(GPIOY_9),
+ MESON_PIN(GPIOY_10),
+ MESON_PIN(GPIOY_11),
+ MESON_PIN(GPIOY_12),
+ MESON_PIN(GPIOY_13),
+ MESON_PIN(GPIOY_14),
+ MESON_PIN(GPIOY_15),
+ MESON_PIN(GPIOY_16),
+ MESON_PIN(GPIODV_0),
+ MESON_PIN(GPIODV_1),
+ MESON_PIN(GPIODV_2),
+ MESON_PIN(GPIODV_3),
+ MESON_PIN(GPIODV_4),
+ MESON_PIN(GPIODV_5),
+ MESON_PIN(GPIODV_6),
+ MESON_PIN(GPIODV_7),
+ MESON_PIN(GPIODV_8),
+ MESON_PIN(GPIODV_9),
+ MESON_PIN(GPIODV_10),
+ MESON_PIN(GPIODV_11),
+ MESON_PIN(GPIODV_12),
+ MESON_PIN(GPIODV_13),
+ MESON_PIN(GPIODV_14),
+ MESON_PIN(GPIODV_15),
+ MESON_PIN(GPIODV_16),
+ MESON_PIN(GPIODV_17),
+ MESON_PIN(GPIODV_18),
+ MESON_PIN(GPIODV_19),
+ MESON_PIN(GPIODV_20),
+ MESON_PIN(GPIODV_21),
+ MESON_PIN(GPIODV_22),
+ MESON_PIN(GPIODV_23),
+ MESON_PIN(GPIODV_24),
+ MESON_PIN(GPIODV_25),
+ MESON_PIN(GPIODV_26),
+ MESON_PIN(GPIODV_27),
+ MESON_PIN(GPIODV_28),
+ MESON_PIN(GPIODV_29),
+ MESON_PIN(GPIOH_0),
+ MESON_PIN(GPIOH_1),
+ MESON_PIN(GPIOH_2),
+ MESON_PIN(GPIOH_3),
+ MESON_PIN(GPIOH_4),
+ MESON_PIN(GPIOH_5),
+ MESON_PIN(GPIOH_6),
+ MESON_PIN(GPIOH_7),
+ MESON_PIN(GPIOH_8),
+ MESON_PIN(GPIOH_9),
+ MESON_PIN(GPIOZ_0),
+ MESON_PIN(GPIOZ_1),
+ MESON_PIN(GPIOZ_2),
+ MESON_PIN(GPIOZ_3),
+ MESON_PIN(GPIOZ_4),
+ MESON_PIN(GPIOZ_5),
+ MESON_PIN(GPIOZ_6),
+ MESON_PIN(GPIOZ_7),
+ MESON_PIN(GPIOZ_8),
+ MESON_PIN(GPIOZ_9),
+ MESON_PIN(GPIOZ_10),
+ MESON_PIN(GPIOZ_11),
+ MESON_PIN(GPIOZ_12),
+ MESON_PIN(GPIOZ_13),
+ MESON_PIN(GPIOZ_14),
+ MESON_PIN(CARD_0),
+ MESON_PIN(CARD_1),
+ MESON_PIN(CARD_2),
+ MESON_PIN(CARD_3),
+ MESON_PIN(CARD_4),
+ MESON_PIN(CARD_5),
+ MESON_PIN(CARD_6),
+ MESON_PIN(BOOT_0),
+ MESON_PIN(BOOT_1),
+ MESON_PIN(BOOT_2),
+ MESON_PIN(BOOT_3),
+ MESON_PIN(BOOT_4),
+ MESON_PIN(BOOT_5),
+ MESON_PIN(BOOT_6),
+ MESON_PIN(BOOT_7),
+ MESON_PIN(BOOT_8),
+ MESON_PIN(BOOT_9),
+ MESON_PIN(BOOT_10),
+ MESON_PIN(BOOT_11),
+ MESON_PIN(BOOT_12),
+ MESON_PIN(BOOT_13),
+ MESON_PIN(BOOT_14),
+ MESON_PIN(BOOT_15),
+ MESON_PIN(BOOT_16),
+ MESON_PIN(BOOT_17),
+ MESON_PIN(BOOT_18),
+ MESON_PIN(GPIOAO_0),
+ MESON_PIN(GPIOAO_1),
+ MESON_PIN(GPIOAO_2),
+ MESON_PIN(GPIOAO_3),
+ MESON_PIN(GPIOAO_4),
+ MESON_PIN(GPIOAO_5),
+ MESON_PIN(GPIOAO_6),
+ MESON_PIN(GPIOAO_7),
+ MESON_PIN(GPIOAO_8),
+ MESON_PIN(GPIOAO_9),
+ MESON_PIN(GPIOAO_10),
+ MESON_PIN(GPIOAO_11),
+ MESON_PIN(GPIOAO_12),
+ MESON_PIN(GPIOAO_13),
+ MESON_PIN(GPIO_BSD_EN),
+ MESON_PIN(GPIO_TEST_N),
+};
+
+/* bank X */
+static const unsigned int sd_d0_a_pins[] = { PIN_GPIOX_0 };
+static const unsigned int sd_d1_a_pins[] = { PIN_GPIOX_1 };
+static const unsigned int sd_d2_a_pins[] = { PIN_GPIOX_2 };
+static const unsigned int sd_d3_a_pins[] = { PIN_GPIOX_3 };
+static const unsigned int sd_clk_a_pins[] = { PIN_GPIOX_8 };
+static const unsigned int sd_cmd_a_pins[] = { PIN_GPIOX_9 };
+
+static const unsigned int sdxc_d0_a_pins[] = { PIN_GPIOX_0 };
+static const unsigned int sdxc_d13_a_pins[] = { PIN_GPIOX_1, PIN_GPIOX_2,
+ PIN_GPIOX_3 };
+static const unsigned int sdxc_d47_a_pins[] = { PIN_GPIOX_4, PIN_GPIOX_5,
+ PIN_GPIOX_6, PIN_GPIOX_7 };
+static const unsigned int sdxc_clk_a_pins[] = { PIN_GPIOX_8 };
+static const unsigned int sdxc_cmd_a_pins[] = { PIN_GPIOX_9 };
+
+static const unsigned int pcm_out_a_pins[] = { PIN_GPIOX_4 };
+static const unsigned int pcm_in_a_pins[] = { PIN_GPIOX_5 };
+static const unsigned int pcm_fs_a_pins[] = { PIN_GPIOX_6 };
+static const unsigned int pcm_clk_a_pins[] = { PIN_GPIOX_7 };
+
+static const unsigned int uart_tx_a0_pins[] = { PIN_GPIOX_4 };
+static const unsigned int uart_rx_a0_pins[] = { PIN_GPIOX_5 };
+static const unsigned int uart_cts_a0_pins[] = { PIN_GPIOX_6 };
+static const unsigned int uart_rts_a0_pins[] = { PIN_GPIOX_7 };
+
+static const unsigned int uart_tx_a1_pins[] = { PIN_GPIOX_12 };
+static const unsigned int uart_rx_a1_pins[] = { PIN_GPIOX_13 };
+static const unsigned int uart_cts_a1_pins[] = { PIN_GPIOX_14 };
+static const unsigned int uart_rts_a1_pins[] = { PIN_GPIOX_15 };
+
+static const unsigned int uart_tx_b0_pins[] = { PIN_GPIOX_16 };
+static const unsigned int uart_rx_b0_pins[] = { PIN_GPIOX_17 };
+static const unsigned int uart_cts_b0_pins[] = { PIN_GPIOX_18 };
+static const unsigned int uart_rts_b0_pins[] = { PIN_GPIOX_19 };
+
+static const unsigned int iso7816_det_pins[] = { PIN_GPIOX_16 };
+static const unsigned int iso7816_reset_pins[] = { PIN_GPIOX_17 };
+static const unsigned int iso7816_clk_pins[] = { PIN_GPIOX_18 };
+static const unsigned int iso7816_data_pins[] = { PIN_GPIOX_19 };
+
+static const unsigned int i2c_sda_d0_pins[] = { PIN_GPIOX_16 };
+static const unsigned int i2c_sck_d0_pins[] = { PIN_GPIOX_17 };
+
+static const unsigned int xtal_32k_out_pins[] = { PIN_GPIOX_10 };
+static const unsigned int xtal_24m_out_pins[] = { PIN_GPIOX_11 };
+
+/* bank Y */
+static const unsigned int uart_tx_c_pins[] = { PIN_GPIOY_0 };
+static const unsigned int uart_rx_c_pins[] = { PIN_GPIOY_1 };
+static const unsigned int uart_cts_c_pins[] = { PIN_GPIOY_2 };
+static const unsigned int uart_rts_c_pins[] = { PIN_GPIOY_3 };
+
+static const unsigned int pcm_out_b_pins[] = { PIN_GPIOY_4 };
+static const unsigned int pcm_in_b_pins[] = { PIN_GPIOY_5 };
+static const unsigned int pcm_fs_b_pins[] = { PIN_GPIOY_6 };
+static const unsigned int pcm_clk_b_pins[] = { PIN_GPIOY_7 };
+
+static const unsigned int i2c_sda_c0_pins[] = { PIN_GPIOY_0 };
+static const unsigned int i2c_sck_c0_pins[] = { PIN_GPIOY_1 };
+
+/* bank DV */
+static const unsigned int dvin_rgb_pins[] = { PIN_GPIODV_0, PIN_GPIODV_1,
+ PIN_GPIODV_2, PIN_GPIODV_3,
+ PIN_GPIODV_4, PIN_GPIODV_5,
+ PIN_GPIODV_6, PIN_GPIODV_7,
+ PIN_GPIODV_8, PIN_GPIODV_9,
+ PIN_GPIODV_10, PIN_GPIODV_11,
+ PIN_GPIODV_12, PIN_GPIODV_13,
+ PIN_GPIODV_14, PIN_GPIODV_15,
+ PIN_GPIODV_16, PIN_GPIODV_17,
+ PIN_GPIODV_18, PIN_GPIODV_19,
+ PIN_GPIODV_20, PIN_GPIODV_21,
+ PIN_GPIODV_22, PIN_GPIODV_23 };
+static const unsigned int dvin_vs_pins[] = { PIN_GPIODV_24 };
+static const unsigned int dvin_hs_pins[] = { PIN_GPIODV_25 };
+static const unsigned int dvin_clk_pins[] = { PIN_GPIODV_26 };
+static const unsigned int dvin_de_pins[] = { PIN_GPIODV_27 };
+
+static const unsigned int enc_0_pins[] = { PIN_GPIODV_0 };
+static const unsigned int enc_1_pins[] = { PIN_GPIODV_1 };
+static const unsigned int enc_2_pins[] = { PIN_GPIODV_2 };
+static const unsigned int enc_3_pins[] = { PIN_GPIODV_3 };
+static const unsigned int enc_4_pins[] = { PIN_GPIODV_4 };
+static const unsigned int enc_5_pins[] = { PIN_GPIODV_5 };
+static const unsigned int enc_6_pins[] = { PIN_GPIODV_6 };
+static const unsigned int enc_7_pins[] = { PIN_GPIODV_7 };
+static const unsigned int enc_8_pins[] = { PIN_GPIODV_8 };
+static const unsigned int enc_9_pins[] = { PIN_GPIODV_9 };
+static const unsigned int enc_10_pins[] = { PIN_GPIODV_10 };
+static const unsigned int enc_11_pins[] = { PIN_GPIODV_11 };
+static const unsigned int enc_12_pins[] = { PIN_GPIODV_12 };
+static const unsigned int enc_13_pins[] = { PIN_GPIODV_13 };
+static const unsigned int enc_14_pins[] = { PIN_GPIODV_14 };
+static const unsigned int enc_15_pins[] = { PIN_GPIODV_15 };
+static const unsigned int enc_16_pins[] = { PIN_GPIODV_16 };
+static const unsigned int enc_17_pins[] = { PIN_GPIODV_17 };
+
+static const unsigned int uart_tx_b1_pins[] = { PIN_GPIODV_24 };
+static const unsigned int uart_rx_b1_pins[] = { PIN_GPIODV_25 };
+static const unsigned int uart_cts_b1_pins[] = { PIN_GPIODV_26 };
+static const unsigned int uart_rts_b1_pins[] = { PIN_GPIODV_27 };
+
+static const unsigned int vga_vs_pins[] = { PIN_GPIODV_24 };
+static const unsigned int vga_hs_pins[] = { PIN_GPIODV_25 };
+
+/* bank H */
+static const unsigned int hdmi_hpd_pins[] = { PIN_GPIOH_0 };
+static const unsigned int hdmi_sda_pins[] = { PIN_GPIOH_1 };
+static const unsigned int hdmi_scl_pins[] = { PIN_GPIOH_2 };
+static const unsigned int hdmi_cec_pins[] = { PIN_GPIOH_3 };
+
+static const unsigned int spi_ss0_0_pins[] = { PIN_GPIOH_3 };
+static const unsigned int spi_miso_0_pins[] = { PIN_GPIOH_4 };
+static const unsigned int spi_mosi_0_pins[] = { PIN_GPIOH_5 };
+static const unsigned int spi_sclk_0_pins[] = { PIN_GPIOH_6 };
+
+static const unsigned int i2c_sda_d1_pins[] = { PIN_GPIOH_7 };
+static const unsigned int i2c_sck_d1_pins[] = { PIN_GPIOH_8 };
+
+/* bank Z */
+static const unsigned int spi_ss0_1_pins[] = { PIN_GPIOZ_9 };
+static const unsigned int spi_ss1_1_pins[] = { PIN_GPIOZ_10 };
+static const unsigned int spi_sclk_1_pins[] = { PIN_GPIOZ_11 };
+static const unsigned int spi_mosi_1_pins[] = { PIN_GPIOZ_12 };
+static const unsigned int spi_miso_1_pins[] = { PIN_GPIOZ_13 };
+static const unsigned int spi_ss2_1_pins[] = { PIN_GPIOZ_14 };
+
+static const unsigned int eth_tx_clk_50m_pins[] = { PIN_GPIOZ_4 };
+static const unsigned int eth_tx_en_pins[] = { PIN_GPIOZ_5 };
+static const unsigned int eth_txd1_pins[] = { PIN_GPIOZ_6 };
+static const unsigned int eth_txd0_pins[] = { PIN_GPIOZ_7 };
+static const unsigned int eth_rx_clk_in_pins[] = { PIN_GPIOZ_8 };
+static const unsigned int eth_rx_dv_pins[] = { PIN_GPIOZ_9 };
+static const unsigned int eth_rxd1_pins[] = { PIN_GPIOZ_10 };
+static const unsigned int eth_rxd0_pins[] = { PIN_GPIOZ_11 };
+static const unsigned int eth_mdio_pins[] = { PIN_GPIOZ_12 };
+static const unsigned int eth_mdc_pins[] = { PIN_GPIOZ_13 };
+
+static const unsigned int i2c_sda_a0_pins[] = { PIN_GPIOZ_0 };
+static const unsigned int i2c_sck_a0_pins[] = { PIN_GPIOZ_1 };
+
+static const unsigned int i2c_sda_b_pins[] = { PIN_GPIOZ_2 };
+static const unsigned int i2c_sck_b_pins[] = { PIN_GPIOZ_3 };
+
+static const unsigned int i2c_sda_c1_pins[] = { PIN_GPIOZ_4 };
+static const unsigned int i2c_sck_c1_pins[] = { PIN_GPIOZ_5 };
+
+static const unsigned int i2c_sda_a1_pins[] = { PIN_GPIOZ_0 };
+static const unsigned int i2c_sck_a1_pins[] = { PIN_GPIOZ_1 };
+
+static const unsigned int i2c_sda_a2_pins[] = { PIN_GPIOZ_0 };
+static const unsigned int i2c_sck_a2_pins[] = { PIN_GPIOZ_1 };
+
+/* bank BOOT */
+static const unsigned int sd_d0_c_pins[] = { PIN_BOOT_0 };
+static const unsigned int sd_d1_c_pins[] = { PIN_BOOT_1 };
+static const unsigned int sd_d2_c_pins[] = { PIN_BOOT_2 };
+static const unsigned int sd_d3_c_pins[] = { PIN_BOOT_3 };
+static const unsigned int sd_cmd_c_pins[] = { PIN_BOOT_16 };
+static const unsigned int sd_clk_c_pins[] = { PIN_BOOT_17 };
+
+static const unsigned int sdxc_d0_c_pins[] = { PIN_BOOT_0};
+static const unsigned int sdxc_d13_c_pins[] = { PIN_BOOT_1, PIN_BOOT_2,
+ PIN_BOOT_3 };
+static const unsigned int sdxc_d47_c_pins[] = { PIN_BOOT_4, PIN_BOOT_5,
+ PIN_BOOT_6, PIN_BOOT_7 };
+static const unsigned int sdxc_cmd_c_pins[] = { PIN_BOOT_16 };
+static const unsigned int sdxc_clk_c_pins[] = { PIN_BOOT_17 };
+
+static const unsigned int nand_io_pins[] = { PIN_BOOT_0, PIN_BOOT_1,
+ PIN_BOOT_2, PIN_BOOT_3,
+ PIN_BOOT_4, PIN_BOOT_5,
+ PIN_BOOT_6, PIN_BOOT_7 };
+static const unsigned int nand_io_ce0_pins[] = { PIN_BOOT_8 };
+static const unsigned int nand_io_ce1_pins[] = { PIN_BOOT_9 };
+static const unsigned int nand_io_rb0_pins[] = { PIN_BOOT_10 };
+static const unsigned int nand_ale_pins[] = { PIN_BOOT_11 };
+static const unsigned int nand_cle_pins[] = { PIN_BOOT_12 };
+static const unsigned int nand_wen_clk_pins[] = { PIN_BOOT_13 };
+static const unsigned int nand_ren_clk_pins[] = { PIN_BOOT_14 };
+static const unsigned int nand_dqs_pins[] = { PIN_BOOT_15 };
+static const unsigned int nand_ce2_pins[] = { PIN_BOOT_16 };
+static const unsigned int nand_ce3_pins[] = { PIN_BOOT_17 };
+
+static const unsigned int nor_d_pins[] = { PIN_BOOT_11 };
+static const unsigned int nor_q_pins[] = { PIN_BOOT_12 };
+static const unsigned int nor_c_pins[] = { PIN_BOOT_13 };
+static const unsigned int nor_cs_pins[] = { PIN_BOOT_18 };
+
+/* bank CARD */
+static const unsigned int sd_d1_b_pins[] = { PIN_CARD_0 };
+static const unsigned int sd_d0_b_pins[] = { PIN_CARD_1 };
+static const unsigned int sd_clk_b_pins[] = { PIN_CARD_2 };
+static const unsigned int sd_cmd_b_pins[] = { PIN_CARD_3 };
+static const unsigned int sd_d3_b_pins[] = { PIN_CARD_4 };
+static const unsigned int sd_d2_b_pins[] = { PIN_CARD_5 };
+
+static const unsigned int sdxc_d13_b_pins[] = { PIN_CARD_0, PIN_CARD_4,
+ PIN_CARD_5 };
+static const unsigned int sdxc_d0_b_pins[] = { PIN_CARD_1 };
+static const unsigned int sdxc_clk_b_pins[] = { PIN_CARD_2 };
+static const unsigned int sdxc_cmd_b_pins[] = { PIN_CARD_3 };
+
+/* bank AO */
+static const unsigned int uart_tx_ao_a_pins[] = { PIN_GPIOAO_0 };
+static const unsigned int uart_rx_ao_a_pins[] = { PIN_GPIOAO_1 };
+static const unsigned int uart_cts_ao_a_pins[] = { PIN_GPIOAO_2 };
+static const unsigned int uart_rts_ao_a_pins[] = { PIN_GPIOAO_3 };
+
+static const unsigned int remote_input_pins[] = { PIN_GPIOAO_7 };
+
+static const unsigned int i2c_slave_sck_ao_pins[] = { PIN_GPIOAO_4 };
+static const unsigned int i2c_slave_sda_ao_pins[] = { PIN_GPIOAO_5 };
+
+static const unsigned int uart_tx_ao_b0_pins[] = { PIN_GPIOAO_0 };
+static const unsigned int uart_rx_ao_b0_pins[] = { PIN_GPIOAO_1 };
+
+static const unsigned int uart_tx_ao_b1_pins[] = { PIN_GPIOAO_4 };
+static const unsigned int uart_rx_ao_b1_pins[] = { PIN_GPIOAO_5 };
+
+static const unsigned int i2c_mst_sck_ao_pins[] = { PIN_GPIOAO_4 };
+static const unsigned int i2c_mst_sda_ao_pins[] = { PIN_GPIOAO_5 };
+
+static struct meson_pmx_group meson8_groups[] = {
+ GPIO_GROUP(GPIOX_0),
+ GPIO_GROUP(GPIOX_1),
+ GPIO_GROUP(GPIOX_2),
+ GPIO_GROUP(GPIOX_3),
+ GPIO_GROUP(GPIOX_4),
+ GPIO_GROUP(GPIOX_5),
+ GPIO_GROUP(GPIOX_6),
+ GPIO_GROUP(GPIOX_7),
+ GPIO_GROUP(GPIOX_8),
+ GPIO_GROUP(GPIOX_9),
+ GPIO_GROUP(GPIOX_10),
+ GPIO_GROUP(GPIOX_11),
+ GPIO_GROUP(GPIOX_12),
+ GPIO_GROUP(GPIOX_13),
+ GPIO_GROUP(GPIOX_14),
+ GPIO_GROUP(GPIOX_15),
+ GPIO_GROUP(GPIOX_16),
+ GPIO_GROUP(GPIOX_17),
+ GPIO_GROUP(GPIOX_18),
+ GPIO_GROUP(GPIOX_19),
+ GPIO_GROUP(GPIOX_20),
+ GPIO_GROUP(GPIOX_21),
+ GPIO_GROUP(GPIOY_0),
+ GPIO_GROUP(GPIOY_1),
+ GPIO_GROUP(GPIOY_2),
+ GPIO_GROUP(GPIOY_3),
+ GPIO_GROUP(GPIOY_4),
+ GPIO_GROUP(GPIOY_5),
+ GPIO_GROUP(GPIOY_6),
+ GPIO_GROUP(GPIOY_7),
+ GPIO_GROUP(GPIOY_8),
+ GPIO_GROUP(GPIOY_9),
+ GPIO_GROUP(GPIOY_10),
+ GPIO_GROUP(GPIOY_11),
+ GPIO_GROUP(GPIOY_12),
+ GPIO_GROUP(GPIOY_13),
+ GPIO_GROUP(GPIOY_14),
+ GPIO_GROUP(GPIOY_15),
+ GPIO_GROUP(GPIOY_16),
+ GPIO_GROUP(GPIODV_0),
+ GPIO_GROUP(GPIODV_1),
+ GPIO_GROUP(GPIODV_2),
+ GPIO_GROUP(GPIODV_3),
+ GPIO_GROUP(GPIODV_4),
+ GPIO_GROUP(GPIODV_5),
+ GPIO_GROUP(GPIODV_6),
+ GPIO_GROUP(GPIODV_7),
+ GPIO_GROUP(GPIODV_8),
+ GPIO_GROUP(GPIODV_9),
+ GPIO_GROUP(GPIODV_10),
+ GPIO_GROUP(GPIODV_11),
+ GPIO_GROUP(GPIODV_12),
+ GPIO_GROUP(GPIODV_13),
+ GPIO_GROUP(GPIODV_14),
+ GPIO_GROUP(GPIODV_15),
+ GPIO_GROUP(GPIODV_16),
+ GPIO_GROUP(GPIODV_17),
+ GPIO_GROUP(GPIODV_18),
+ GPIO_GROUP(GPIODV_19),
+ GPIO_GROUP(GPIODV_20),
+ GPIO_GROUP(GPIODV_21),
+ GPIO_GROUP(GPIODV_22),
+ GPIO_GROUP(GPIODV_23),
+ GPIO_GROUP(GPIODV_24),
+ GPIO_GROUP(GPIODV_25),
+ GPIO_GROUP(GPIODV_26),
+ GPIO_GROUP(GPIODV_27),
+ GPIO_GROUP(GPIODV_28),
+ GPIO_GROUP(GPIODV_29),
+ GPIO_GROUP(GPIOH_0),
+ GPIO_GROUP(GPIOH_1),
+ GPIO_GROUP(GPIOH_2),
+ GPIO_GROUP(GPIOH_3),
+ GPIO_GROUP(GPIOH_4),
+ GPIO_GROUP(GPIOH_5),
+ GPIO_GROUP(GPIOH_6),
+ GPIO_GROUP(GPIOH_7),
+ GPIO_GROUP(GPIOH_8),
+ GPIO_GROUP(GPIOH_9),
+ GPIO_GROUP(GPIOZ_0),
+ GPIO_GROUP(GPIOZ_1),
+ GPIO_GROUP(GPIOZ_2),
+ GPIO_GROUP(GPIOZ_3),
+ GPIO_GROUP(GPIOZ_4),
+ GPIO_GROUP(GPIOZ_5),
+ GPIO_GROUP(GPIOZ_6),
+ GPIO_GROUP(GPIOZ_7),
+ GPIO_GROUP(GPIOZ_8),
+ GPIO_GROUP(GPIOZ_9),
+ GPIO_GROUP(GPIOZ_10),
+ GPIO_GROUP(GPIOZ_11),
+ GPIO_GROUP(GPIOZ_12),
+ GPIO_GROUP(GPIOZ_13),
+ GPIO_GROUP(GPIOZ_14),
+ GPIO_GROUP(GPIOAO_0),
+ GPIO_GROUP(GPIOAO_1),
+ GPIO_GROUP(GPIOAO_2),
+ GPIO_GROUP(GPIOAO_3),
+ GPIO_GROUP(GPIOAO_4),
+ GPIO_GROUP(GPIOAO_5),
+ GPIO_GROUP(GPIOAO_6),
+ GPIO_GROUP(GPIOAO_7),
+ GPIO_GROUP(GPIOAO_8),
+ GPIO_GROUP(GPIOAO_9),
+ GPIO_GROUP(GPIOAO_10),
+ GPIO_GROUP(GPIOAO_11),
+ GPIO_GROUP(GPIOAO_12),
+ GPIO_GROUP(GPIOAO_13),
+ GPIO_GROUP(GPIO_BSD_EN),
+ GPIO_GROUP(GPIO_TEST_N),
+
+ /* bank X */
+ GROUP(sd_d0_a, 8, 5),
+ GROUP(sd_d1_a, 8, 4),
+ GROUP(sd_d2_a, 8, 3),
+ GROUP(sd_d3_a, 8, 2),
+ GROUP(sd_clk_a, 8, 1),
+ GROUP(sd_cmd_a, 8, 0),
+
+ GROUP(sdxc_d0_a, 5, 14),
+ GROUP(sdxc_d13_a, 5, 13),
+ GROUP(sdxc_d47_a, 5, 12),
+ GROUP(sdxc_clk_a, 5, 11),
+ GROUP(sdxc_cmd_a, 5, 10),
+
+ GROUP(pcm_out_a, 3, 30),
+ GROUP(pcm_in_a, 3, 29),
+ GROUP(pcm_fs_a, 3, 28),
+ GROUP(pcm_clk_a, 3, 27),
+
+ GROUP(uart_tx_a0, 4, 17),
+ GROUP(uart_rx_a0, 4, 16),
+ GROUP(uart_cts_a0, 4, 15),
+ GROUP(uart_rts_a0, 4, 14),
+
+ GROUP(uart_tx_a1, 4, 13),
+ GROUP(uart_rx_a1, 4, 12),
+ GROUP(uart_cts_a1, 4, 11),
+ GROUP(uart_rts_a1, 4, 10),
+
+ GROUP(uart_tx_b0, 4, 9),
+ GROUP(uart_rx_b0, 4, 8),
+ GROUP(uart_cts_b0, 4, 7),
+ GROUP(uart_rts_b0, 4, 6),
+
+ GROUP(iso7816_det, 4, 21),
+ GROUP(iso7816_reset, 4, 20),
+ GROUP(iso7816_clk, 4, 19),
+ GROUP(iso7816_data, 4, 18),
+
+ GROUP(i2c_sda_d0, 4, 5),
+ GROUP(i2c_sck_d0, 4, 4),
+
+ GROUP(xtal_32k_out, 3, 22),
+ GROUP(xtal_24m_out, 3, 23),
+
+ /* bank Y */
+ GROUP(uart_tx_c, 1, 19),
+ GROUP(uart_rx_c, 1, 18),
+ GROUP(uart_cts_c, 1, 17),
+ GROUP(uart_rts_c, 1, 16),
+
+ GROUP(pcm_out_b, 4, 25),
+ GROUP(pcm_in_b, 4, 24),
+ GROUP(pcm_fs_b, 4, 23),
+ GROUP(pcm_clk_b, 4, 22),
+
+ GROUP(i2c_sda_c0, 1, 15),
+ GROUP(i2c_sck_c0, 1, 14),
+
+ /* bank DV */
+ GROUP(dvin_rgb, 0, 6),
+ GROUP(dvin_vs, 0, 9),
+ GROUP(dvin_hs, 0, 8),
+ GROUP(dvin_clk, 0, 7),
+ GROUP(dvin_de, 0, 10),
+
+ GROUP(enc_0, 7, 0),
+ GROUP(enc_1, 7, 1),
+ GROUP(enc_2, 7, 2),
+ GROUP(enc_3, 7, 3),
+ GROUP(enc_4, 7, 4),
+ GROUP(enc_5, 7, 5),
+ GROUP(enc_6, 7, 6),
+ GROUP(enc_7, 7, 7),
+ GROUP(enc_8, 7, 8),
+ GROUP(enc_9, 7, 9),
+ GROUP(enc_10, 7, 10),
+ GROUP(enc_11, 7, 11),
+ GROUP(enc_12, 7, 12),
+ GROUP(enc_13, 7, 13),
+ GROUP(enc_14, 7, 14),
+ GROUP(enc_15, 7, 15),
+ GROUP(enc_16, 7, 16),
+ GROUP(enc_17, 7, 17),
+
+ GROUP(uart_tx_b1, 6, 23),
+ GROUP(uart_rx_b1, 6, 22),
+ GROUP(uart_cts_b1, 6, 21),
+ GROUP(uart_rts_b1, 6, 20),
+
+ GROUP(vga_vs, 0, 21),
+ GROUP(vga_hs, 0, 20),
+
+ /* bank H */
+ GROUP(hdmi_hpd, 1, 26),
+ GROUP(hdmi_sda, 1, 25),
+ GROUP(hdmi_scl, 1, 24),
+ GROUP(hdmi_cec, 1, 23),
+
+ GROUP(spi_ss0_0, 9, 13),
+ GROUP(spi_miso_0, 9, 12),
+ GROUP(spi_mosi_0, 9, 11),
+ GROUP(spi_sclk_0, 9, 10),
+
+ GROUP(i2c_sda_d1, 4, 3),
+ GROUP(i2c_sck_d1, 4, 2),
+
+ /* bank Z */
+ GROUP(spi_ss0_1, 8, 16),
+ GROUP(spi_ss1_1, 8, 12),
+ GROUP(spi_sclk_1, 8, 15),
+ GROUP(spi_mosi_1, 8, 14),
+ GROUP(spi_miso_1, 8, 13),
+ GROUP(spi_ss2_1, 8, 17),
+
+ GROUP(eth_tx_clk_50m, 6, 15),
+ GROUP(eth_tx_en, 6, 14),
+ GROUP(eth_txd1, 6, 13),
+ GROUP(eth_txd0, 6, 12),
+ GROUP(eth_rx_clk_in, 6, 10),
+ GROUP(eth_rx_dv, 6, 11),
+ GROUP(eth_rxd1, 6, 8),
+ GROUP(eth_rxd0, 6, 7),
+ GROUP(eth_mdio, 6, 6),
+ GROUP(eth_mdc, 6, 5),
+
+ GROUP(i2c_sda_a0, 5, 31),
+ GROUP(i2c_sck_a0, 5, 30),
+
+ GROUP(i2c_sda_b, 5, 27),
+ GROUP(i2c_sck_b, 5, 26),
+
+ GROUP(i2c_sda_c1, 5, 25),
+ GROUP(i2c_sck_c1, 5, 24),
+
+ GROUP(i2c_sda_a1, 5, 9),
+ GROUP(i2c_sck_a1, 5, 8),
+
+ GROUP(i2c_sda_a2, 5, 7),
+ GROUP(i2c_sck_a2, 5, 6),
+
+ /* bank BOOT */
+ GROUP(sd_d0_c, 6, 29),
+ GROUP(sd_d1_c, 6, 28),
+ GROUP(sd_d2_c, 6, 27),
+ GROUP(sd_d3_c, 6, 26),
+ GROUP(sd_cmd_c, 6, 25),
+ GROUP(sd_clk_c, 6, 24),
+
+ GROUP(sdxc_d0_c, 4, 30),
+ GROUP(sdxc_d13_c, 4, 29),
+ GROUP(sdxc_d47_c, 4, 28),
+ GROUP(sdxc_cmd_c, 4, 27),
+ GROUP(sdxc_clk_c, 4, 26),
+
+ GROUP(nand_io, 2, 26),
+ GROUP(nand_io_ce0, 2, 25),
+ GROUP(nand_io_ce1, 2, 24),
+ GROUP(nand_io_rb0, 2, 17),
+ GROUP(nand_ale, 2, 21),
+ GROUP(nand_cle, 2, 20),
+ GROUP(nand_wen_clk, 2, 19),
+ GROUP(nand_ren_clk, 2, 18),
+ GROUP(nand_dqs, 2, 27),
+ GROUP(nand_ce2, 2, 23),
+ GROUP(nand_ce3, 2, 22),
+
+ GROUP(nor_d, 5, 1),
+ GROUP(nor_q, 5, 3),
+ GROUP(nor_c, 5, 2),
+ GROUP(nor_cs, 5, 0),
+
+ /* bank CARD */
+ GROUP(sd_d1_b, 2, 14),
+ GROUP(sd_d0_b, 2, 15),
+ GROUP(sd_clk_b, 2, 11),
+ GROUP(sd_cmd_b, 2, 10),
+ GROUP(sd_d3_b, 2, 12),
+ GROUP(sd_d2_b, 2, 13),
+
+ GROUP(sdxc_d13_b, 2, 6),
+ GROUP(sdxc_d0_b, 2, 7),
+ GROUP(sdxc_clk_b, 2, 5),
+ GROUP(sdxc_cmd_b, 2, 4),
+
+ /* bank AO */
+ GROUP_AO(uart_tx_ao_a, 0, 12),
+ GROUP_AO(uart_rx_ao_a, 0, 11),
+ GROUP_AO(uart_cts_ao_a, 0, 10),
+ GROUP_AO(uart_rts_ao_a, 0, 9),
+
+ GROUP_AO(remote_input, 0, 0),
+
+ GROUP_AO(i2c_slave_sck_ao, 0, 2),
+ GROUP_AO(i2c_slave_sda_ao, 0, 1),
+
+ GROUP_AO(uart_tx_ao_b0, 0, 26),
+ GROUP_AO(uart_rx_ao_b0, 0, 25),
+
+ GROUP_AO(uart_tx_ao_b1, 0, 24),
+ GROUP_AO(uart_rx_ao_b1, 0, 23),
+
+ GROUP_AO(i2c_mst_sck_ao, 0, 6),
+ GROUP_AO(i2c_mst_sda_ao, 0, 5),
+};
+
+static const char * const gpio_groups[] = {
+ "GPIOX_0", "GPIOX_1", "GPIOX_2", "GPIOX_3", "GPIOX_4",
+ "GPIOX_5", "GPIOX_6", "GPIOX_7", "GPIOX_8", "GPIOX_9",
+ "GPIOX_10", "GPIOX_11", "GPIOX_12", "GPIOX_13", "GPIOX_14",
+ "GPIOX_15", "GPIOX_16", "GPIOX_17", "GPIOX_18", "GPIOX_19",
+ "GPIOX_20", "GPIOX_21",
+
+ "GPIOY_0", "GPIOY_1", "GPIOY_2", "GPIOY_3", "GPIOY_4",
+ "GPIOY_5", "GPIOY_6", "GPIOY_7", "GPIOY_8", "GPIOY_9",
+ "GPIOY_10", "GPIOY_11", "GPIOY_12", "GPIOY_13", "GPIOY_14",
+ "GPIOY_15", "GPIOY_16",
+
+ "GPIODV_0", "GPIODV_1", "GPIODV_2", "GPIODV_3", "GPIODV_4",
+ "GPIODV_5", "GPIODV_6", "GPIODV_7", "GPIODV_8", "GPIODV_9",
+ "GPIODV_10", "GPIODV_11", "GPIODV_12", "GPIODV_13", "GPIODV_14",
+ "GPIODV_15", "GPIODV_16", "GPIODV_17", "GPIODV_18", "GPIODV_19",
+ "GPIODV_20", "GPIODV_21", "GPIODV_22", "GPIODV_23", "GPIODV_24",
+ "GPIODV_25", "GPIODV_26", "GPIODV_27", "GPIODV_28", "GPIODV_29",
+
+ "GPIOH_0", "GPIOH_1", "GPIOH_2", "GPIOH_3", "GPIOH_4",
+ "GPIOH_5", "GPIOH_6", "GPIOH_7", "GPIOH_8", "GPIOH_9",
+
+ "GPIOZ_0", "GPIOZ_1", "GPIOZ_2", "GPIOZ_3", "GPIOZ_4",
+ "GPIOZ_5", "GPIOZ_6", "GPIOZ_7", "GPIOZ_8", "GPIOZ_9",
+ "GPIOZ_10", "GPIOZ_11", "GPIOZ_12", "GPIOZ_13", "GPIOZ_14",
+
+ "CARD_0", "CARD_1", "CARD_2", "CARD_3", "CARD_4",
+ "CARD_5", "CARD_6",
+
+ "BOOT_0", "BOOT_1", "BOOT_2", "BOOT_3", "BOOT_4",
+ "BOOT_5", "BOOT_6", "BOOT_7", "BOOT_8", "BOOT_9",
+ "BOOT_10", "BOOT_11", "BOOT_12", "BOOT_13", "BOOT_14",
+ "BOOT_15", "BOOT_16", "BOOT_17", "BOOT_18",
+
+ "GPIOAO_0", "GPIOAO_1", "GPIOAO_2", "GPIOAO_3",
+ "GPIOAO_4", "GPIOAO_5", "GPIOAO_6", "GPIOAO_7",
+ "GPIOAO_8", "GPIOAO_9", "GPIOAO_10", "GPIOAO_11",
+ "GPIOAO_12", "GPIOAO_13", "GPIO_BSD_EN", "GPIO_TEST_N"
+};
+
+static const char * const sd_a_groups[] = {
+ "sd_d0_a", "sd_d1_a", "sd_d2_a", "sd_d3_a", "sd_clk_a", "sd_cmd_a"
+};
+
+static const char * const sdxc_a_groups[] = {
+ "sdxc_d0_a", "sdxc_d13_a", "sdxc_d47_a", "sdxc_clk_a", "sdxc_cmd_a"
+};
+
+static const char * const pcm_a_groups[] = {
+ "pcm_out_a", "pcm_in_a", "pcm_fs_a", "pcm_clk_a"
+};
+
+static const char * const uart_a_groups[] = {
+ "uart_tx_a0", "uart_rx_a0", "uart_cts_a0", "uart_rts_a0",
+ "uart_tx_a1", "uart_rx_a1", "uart_cts_a1", "uart_rts_a1"
+};
+
+static const char * const uart_b_groups[] = {
+ "uart_tx_b0", "uart_rx_b0", "uart_cts_b0", "uart_rts_b0",
+ "uart_tx_b1", "uart_rx_b1", "uart_cts_b1", "uart_rts_b1"
+};
+
+static const char * const iso7816_groups[] = {
+ "iso7816_det", "iso7816_reset", "iso7816_clk", "iso7816_data"
+};
+
+static const char * const i2c_d_groups[] = {
+ "i2c_sda_d0", "i2c_sck_d0", "i2c_sda_d1", "i2c_sck_d1"
+};
+
+static const char * const xtal_groups[] = {
+ "xtal_32k_out", "xtal_24m_out"
+};
+
+static const char * const uart_c_groups[] = {
+ "uart_tx_c", "uart_rx_c", "uart_cts_c", "uart_rts_c"
+};
+
+static const char * const pcm_b_groups[] = {
+ "pcm_out_b", "pcm_in_b", "pcm_fs_b", "pcm_clk_b"
+};
+
+static const char * const i2c_c_groups[] = {
+ "i2c_sda_c0", "i2c_sck_c0", "i2c_sda_c1", "i2c_sck_c1"
+};
+
+static const char * const dvin_groups[] = {
+ "dvin_rgb", "dvin_vs", "dvin_hs", "dvin_clk", "dvin_de"
+};
+
+static const char * const enc_groups[] = {
+ "enc_0", "enc_1", "enc_2", "enc_3", "enc_4", "enc_5",
+ "enc_6", "enc_7", "enc_8", "enc_9", "enc_10", "enc_11",
+ "enc_12", "enc_13", "enc_14", "enc_15", "enc_16", "enc_17"
+};
+
+static const char * const vga_groups[] = {
+ "vga_vs", "vga_hs"
+};
+
+static const char * const hdmi_groups[] = {
+ "hdmi_hpd", "hdmi_sda", "hdmi_scl", "hdmi_cec"
+};
+
+static const char * const spi_groups[] = {
+ "spi_ss0_0", "spi_miso_0", "spi_mosi_0", "spi_sclk_0",
+ "spi_ss0_1", "spi_ss1_1", "spi_sclk_1", "spi_mosi_1",
+ "spi_miso_1", "spi_ss2_1"
+};
+
+static const char * const ethernet_groups[] = {
+ "eth_tx_clk_50m", "eth_tx_en", "eth_txd1",
+ "eth_txd0", "eth_rx_clk_in", "eth_rx_dv",
+ "eth_rxd1", "eth_rxd0", "eth_mdio", "eth_mdc"
+};
+
+static const char * const i2c_a_groups[] = {
+ "i2c_sda_a0", "i2c_sck_a0", "i2c_sda_a1", "i2c_sck_a1",
+ "i2c_sda_a2", "i2c_sck_a2"
+};
+
+static const char * const i2c_b_groups[] = {
+ "i2c_sda_b", "i2c_sck_b"
+};
+
+static const char * const sd_c_groups[] = {
+ "sd_d0_c", "sd_d1_c", "sd_d2_c", "sd_d3_c",
+ "sd_cmd_c", "sd_clk_c"
+};
+
+static const char * const sdxc_c_groups[] = {
+ "sdxc_d0_c", "sdxc_d13_c", "sdxc_d47_c", "sdxc_cmd_c",
+ "sdxc_clk_c"
+};
+
+static const char * const nand_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"
+};
+
+static const char * const nor_groups[] = {
+ "nor_d", "nor_q", "nor_c", "nor_cs"
+};
+
+static const char * const sd_b_groups[] = {
+ "sd_d1_b", "sd_d0_b", "sd_clk_b", "sd_cmd_b",
+ "sd_d3_b", "sd_d2_b"
+};
+
+static const char * const sdxc_b_groups[] = {
+ "sdxc_d13_b", "sdxc_d0_b", "sdxc_clk_b", "sdxc_cmd_b"
+};
+
+static const char * const uart_ao_groups[] = {
+ "uart_tx_ao_a", "uart_rx_ao_a", "uart_cts_ao_a", "uart_rts_ao_a"
+};
+
+static const char * const remote_groups[] = {
+ "remote_input"
+};
+
+static const char * const i2c_slave_ao_groups[] = {
+ "i2c_slave_sck_ao", "i2c_slave_sda_ao"
+};
+
+static const char * const uart_ao_b_groups[] = {
+ "uart_tx_ao_b0", "uart_rx_ao_b0", "uart_tx_ao_b1", "uart_rx_ao_b1"
+};
+
+static const char * const i2c_mst_ao_groups[] = {
+ "i2c_mst_sck_ao", "i2c_mst_sda_ao"
+};
+
+static struct meson_pmx_func meson8_functions[] = {
+ FUNCTION(gpio),
+ FUNCTION(sd_a),
+ FUNCTION(sdxc_a),
+ FUNCTION(pcm_a),
+ FUNCTION(uart_a),
+ FUNCTION(uart_b),
+ FUNCTION(iso7816),
+ FUNCTION(i2c_d),
+ FUNCTION(xtal),
+ FUNCTION(uart_c),
+ FUNCTION(pcm_b),
+ FUNCTION(i2c_c),
+ FUNCTION(dvin),
+ FUNCTION(enc),
+ FUNCTION(vga),
+ FUNCTION(hdmi),
+ FUNCTION(spi),
+ FUNCTION(ethernet),
+ FUNCTION(i2c_a),
+ FUNCTION(i2c_b),
+ FUNCTION(sd_c),
+ FUNCTION(sdxc_c),
+ FUNCTION(nand),
+ FUNCTION(nor),
+ FUNCTION(sd_b),
+ FUNCTION(sdxc_b),
+ FUNCTION(uart_ao),
+ FUNCTION(remote),
+ FUNCTION(i2c_slave_ao),
+ FUNCTION(uart_ao_b),
+ FUNCTION(i2c_mst_ao),
+};
+
+static struct meson_bank meson8_banks[] = {
+ /* name first last pullen pull dir out in */
+ BANK("X", PIN_GPIOX_0, PIN_GPIOX_21, 4, 0, 4, 0, 0, 0, 1, 0, 2, 0),
+ BANK("Y", PIN_GPIOY_0, PIN_GPIOY_16, 3, 0, 3, 0, 3, 0, 4, 0, 5, 0),
+ BANK("DV", PIN_GPIODV_0, PIN_GPIODV_29, 0, 0, 0, 0, 7, 0, 8, 0, 9, 0),
+ BANK("H", PIN_GPIOH_0, PIN_GPIOH_9, 1, 16, 1, 16, 9, 19, 10, 19, 11, 19),
+ BANK("Z", PIN_GPIOZ_0, PIN_GPIOZ_14, 1, 0, 1, 0, 3, 17, 4, 17, 5, 17),
+ BANK("CARD", PIN_CARD_0, PIN_CARD_6, 2, 20, 2, 20, 0, 22, 1, 22, 2, 22),
+ BANK("BOOT", PIN_BOOT_0, PIN_BOOT_18, 2, 0, 2, 0, 9, 0, 10, 0, 11, 0),
+};
+
+static struct meson_bank meson8_ao_banks[] = {
+ /* name first last pullen pull dir out in */
+ BANK("AO", PIN_GPIOAO_0, PIN_GPIO_TEST_N, 0, 0, 0, 16, 0, 0, 0, 16, 1, 0),
+};
+
+static struct meson_domain_data meson8_domain_data[] = {
+ {
+ .name = "banks",
+ .banks = meson8_banks,
+ .num_banks = ARRAY_SIZE(meson8_banks),
+ .pin_base = 0,
+ .num_pins = 120,
+ },
+ {
+ .name = "ao-bank",
+ .banks = meson8_ao_banks,
+ .num_banks = ARRAY_SIZE(meson8_ao_banks),
+ .pin_base = 120,
+ .num_pins = 16,
+ },
+};
+
+struct meson_pinctrl_data meson8_pinctrl_data = {
+ .pins = meson8_pins,
+ .groups = meson8_groups,
+ .funcs = meson8_functions,
+ .domain_data = meson8_domain_data,
+ .num_pins = ARRAY_SIZE(meson8_pins),
+ .num_groups = ARRAY_SIZE(meson8_groups),
+ .num_funcs = ARRAY_SIZE(meson8_functions),
+ .num_domains = ARRAY_SIZE(meson8_domain_data),
+};
diff --git a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
index 224c6cff6aa2..7302f66f4f19 100644
--- a/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
+++ b/drivers/pinctrl/mvebu/pinctrl-armada-38x.c
@@ -145,14 +145,16 @@ static struct mvebu_mpp_mode armada_38x_mpp_modes[] = {
MPP_VAR_FUNCTION(2, "ptp", "event_req", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie0", "clkreq", V_88F6810_PLUS),
MPP_VAR_FUNCTION(4, "sata1", "prsnt", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "ua0", "cts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "rxd", V_88F6810_PLUS)),
MPP_MODE(20,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "ge0", "txclk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(2, "ptp", "clk", V_88F6810_PLUS),
MPP_VAR_FUNCTION(3, "pcie1", "rstout", V_88F6820_PLUS),
MPP_VAR_FUNCTION(4, "sata0", "prsnt", V_88F6810_PLUS),
- MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS)),
+ MPP_VAR_FUNCTION(5, "ua0", "rts", V_88F6810_PLUS),
+ MPP_VAR_FUNCTION(6, "ua1", "txd", V_88F6810_PLUS)),
MPP_MODE(21,
MPP_VAR_FUNCTION(0, "gpio", NULL, V_88F6810_PLUS),
MPP_VAR_FUNCTION(1, "spi0", "cs1", V_88F6810_PLUS),
diff --git a/drivers/pinctrl/mvebu/pinctrl-dove.c b/drivers/pinctrl/mvebu/pinctrl-dove.c
index 89a52e15f0ae..95bfd0653e8f 100644
--- a/drivers/pinctrl/mvebu/pinctrl-dove.c
+++ b/drivers/pinctrl/mvebu/pinctrl-dove.c
@@ -751,12 +751,12 @@ static struct mvebu_pinctrl_soc_info dove_pinctrl_info = {
static struct clk *clk;
-static struct of_device_id dove_pinctrl_of_match[] = {
+static const struct of_device_id dove_pinctrl_of_match[] = {
{ .compatible = "marvell,dove-pinctrl", .data = &dove_pinctrl_info },
{ }
};
-static struct regmap_config gc_regmap_config = {
+static const struct regmap_config gc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index 3d6d97228523..1806b24faa14 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -914,7 +914,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
}
}
- ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs);
+ ret = pinconf_generic_parse_dt_config(np, pctldev, &configs, &nconfigs);
if (nconfigs) {
const char *gpio_name;
const char *pin;
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index f78b416d7984..4db92f64b4de 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -27,17 +27,6 @@
#include "pinctrl-utils.h"
#ifdef CONFIG_DEBUG_FS
-
-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, d) { .param = a, .display = b, .format = c, \
- .has_arg = d }
-
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),
@@ -60,22 +49,25 @@ static const struct pin_config_item conf_items[] = {
PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true),
};
-void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
- struct seq_file *s, unsigned pin)
+static void pinconf_generic_dump_one(struct pinctrl_dev *pctldev,
+ struct seq_file *s, const char *gname,
+ unsigned pin,
+ const struct pin_config_item *items,
+ int nitems)
{
- const struct pinconf_ops *ops = pctldev->desc->confops;
int i;
- if (!ops->is_generic)
- return;
-
- for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
+ for (i = 0; i < nitems; i++) {
unsigned long config;
int ret;
/* We want to check out this parameter */
- config = pinconf_to_config_packed(conf_items[i].param, 0);
- ret = pin_config_get_for_pin(pctldev, pin, &config);
+ config = pinconf_to_config_packed(items[i].param, 0);
+ if (gname)
+ ret = pin_config_group_get(dev_name(pctldev->dev),
+ gname, &config);
+ else
+ ret = pin_config_get_for_pin(pctldev, pin, &config);
/* These are legal errors */
if (ret == -EINVAL || ret == -ENOTSUPP)
continue;
@@ -85,56 +77,47 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
}
/* Space between multiple configs */
seq_puts(s, " ");
- seq_puts(s, conf_items[i].display);
+ seq_puts(s, items[i].display);
/* Print unit if available */
- if (conf_items[i].has_arg) {
+ if (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);
+ if (items[i].format)
+ seq_printf(s, " %s)", items[i].format);
else
seq_puts(s, ")");
}
}
}
-void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
- struct seq_file *s, const char *gname)
+/**
+ * pinconf_generic_dump_pins - Print information about pin or group of pins
+ * @pctldev: Pincontrol device
+ * @s: File to print to
+ * @gname: Group name specifying pins
+ * @pin: Pin number specyfying pin
+ *
+ * Print the pinconf configuration for the requested pin(s) to @s. Pins can be
+ * specified either by pin using @pin or by group using @gname. Only one needs
+ * to be specified the other can be NULL/0.
+ */
+void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev, struct seq_file *s,
+ const char *gname, unsigned pin)
{
const struct pinconf_ops *ops = pctldev->desc->confops;
- int i;
if (!ops->is_generic)
return;
- for (i = 0; i < ARRAY_SIZE(conf_items); i++) {
- unsigned long config;
- int ret;
-
- /* We want to check out this parameter */
- config = pinconf_to_config_packed(conf_items[i].param, 0);
- ret = pin_config_group_get(dev_name(pctldev->dev), gname,
- &config);
- /* These are legal errors */
- if (ret == -EINVAL || ret == -ENOTSUPP)
- continue;
- if (ret) {
- seq_printf(s, "ERROR READING CONFIG SETTING %d ", i);
- continue;
- }
- /* Space between multiple configs */
- seq_puts(s, " ");
- seq_puts(s, conf_items[i].display);
- /* Print unit if available */
- 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, ")");
- }
- }
+ /* generic parameters */
+ pinconf_generic_dump_one(pctldev, s, gname, pin, conf_items,
+ ARRAY_SIZE(conf_items));
+ /* driver-specific parameters */
+ if (pctldev->desc->num_custom_params &&
+ pctldev->desc->custom_conf_items)
+ pinconf_generic_dump_one(pctldev, s, gname, pin,
+ pctldev->desc->custom_conf_items,
+ pctldev->desc->num_custom_params);
}
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
@@ -148,18 +131,25 @@ void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
seq_printf(s, "%s: 0x%x", conf_items[i].display,
pinconf_to_config_argument(config));
}
+
+ if (!pctldev->desc->num_custom_params ||
+ !pctldev->desc->custom_conf_items)
+ return;
+
+ for (i = 0; i < pctldev->desc->num_custom_params; i++) {
+ if (pinconf_to_config_param(config) !=
+ pctldev->desc->custom_conf_items[i].param)
+ continue;
+ seq_printf(s, "%s: 0x%x",
+ pctldev->desc->custom_conf_items[i].display,
+ pinconf_to_config_argument(config));
+ }
}
EXPORT_SYMBOL_GPL(pinconf_generic_dump_config);
#endif
#ifdef CONFIG_OF
-struct pinconf_generic_dt_params {
- const char * const property;
- enum pin_config_param param;
- u32 default_value;
-};
-
-static const struct pinconf_generic_dt_params dt_params[] = {
+static const struct pinconf_generic_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 },
@@ -184,6 +174,47 @@ static const struct pinconf_generic_dt_params dt_params[] = {
};
/**
+ * parse_dt_cfg() - Parse DT pinconf parameters
+ * @np: DT node
+ * @params: Array of describing generic parameters
+ * @count: Number of entries in @params
+ * @cfg: Array of parsed config options
+ * @ncfg: Number of entries in @cfg
+ *
+ * Parse the config options described in @params from @np and puts the result
+ * in @cfg. @cfg does not need to be empty, entries are added beggining at
+ * @ncfg. @ncfg is updated to reflect the number of entries after parsing. @cfg
+ * needs to have enough memory allocated to hold all possible entries.
+ */
+static void parse_dt_cfg(struct device_node *np,
+ const struct pinconf_generic_params *params,
+ unsigned int count, unsigned long *cfg,
+ unsigned int *ncfg)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ u32 val;
+ int ret;
+ const struct pinconf_generic_params *par = &params[i];
+
+ ret = of_property_read_u32(np, par->property, &val);
+
+ /* property not found */
+ if (ret == -EINVAL)
+ continue;
+
+ /* use default value, when no value is specified */
+ if (ret)
+ val = par->default_value;
+
+ pr_debug("found %s with value %u\n", par->property, val);
+ cfg[*ncfg] = pinconf_to_config_packed(par->param, val);
+ (*ncfg)++;
+ }
+}
+
+/**
* pinconf_generic_parse_dt_config()
* parse the config properties into generic pinconfig values.
* @np: node containing the pinconfig properties
@@ -191,39 +222,30 @@ static const struct pinconf_generic_dt_params dt_params[] = {
* @nconfigs: umber of configurations
*/
int pinconf_generic_parse_dt_config(struct device_node *np,
+ struct pinctrl_dev *pctldev,
unsigned long **configs,
unsigned int *nconfigs)
{
unsigned long *cfg;
- unsigned int ncfg = 0;
+ unsigned int max_cfg, ncfg = 0;
int ret;
- int i;
- u32 val;
if (!np)
return -EINVAL;
/* allocate a temporary array big enough to hold one of each option */
- cfg = kzalloc(sizeof(*cfg) * ARRAY_SIZE(dt_params), GFP_KERNEL);
+ max_cfg = ARRAY_SIZE(dt_params);
+ if (pctldev)
+ max_cfg += pctldev->desc->num_custom_params;
+ cfg = kcalloc(max_cfg, sizeof(*cfg), GFP_KERNEL);
if (!cfg)
return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(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 */
- if (ret == -EINVAL)
- continue;
-
- /* use default value, when no value is specified */
- if (ret)
- val = par->default_value;
-
- pr_debug("found %s with value %u\n", par->property, val);
- cfg[ncfg] = pinconf_to_config_packed(par->param, val);
- ncfg++;
- }
+ parse_dt_cfg(np, dt_params, ARRAY_SIZE(dt_params), cfg, &ncfg);
+ if (pctldev && pctldev->desc->num_custom_params &&
+ pctldev->desc->custom_params)
+ parse_dt_cfg(np, pctldev->desc->custom_params,
+ pctldev->desc->num_custom_params, cfg, &ncfg);
ret = 0;
@@ -264,6 +286,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
unsigned reserve;
struct property *prop;
const char *group;
+ const char *subnode_target_type = "pins";
ret = of_property_read_string(np, "function", &function);
if (ret < 0) {
@@ -273,7 +296,8 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
function = NULL;
}
- ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+ ret = pinconf_generic_parse_dt_config(np, pctldev, &configs,
+ &num_configs);
if (ret < 0) {
dev_err(dev, "could not parse node property\n");
return ret;
@@ -284,10 +308,20 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
reserve++;
if (num_configs)
reserve++;
+
ret = of_property_count_strings(np, "pins");
if (ret < 0) {
- dev_err(dev, "could not parse property pins\n");
- goto exit;
+ ret = of_property_count_strings(np, "groups");
+ if (ret < 0) {
+ dev_err(dev, "could not parse property pins/groups\n");
+ goto exit;
+ }
+ if (type == PIN_MAP_TYPE_INVALID)
+ type = PIN_MAP_TYPE_CONFIGS_GROUP;
+ subnode_target_type = "groups";
+ } else {
+ if (type == PIN_MAP_TYPE_INVALID)
+ type = PIN_MAP_TYPE_CONFIGS_PIN;
}
reserve *= ret;
@@ -296,7 +330,7 @@ int pinconf_generic_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (ret < 0)
goto exit;
- of_property_for_each_string(np, "pins", prop, group) {
+ of_property_for_each_string(np, subnode_target_type, prop, group) {
if (function) {
ret = pinctrl_utils_add_map_mux(pctldev, map,
reserved_maps, num_maps, group,
diff --git a/drivers/pinctrl/pinconf.c b/drivers/pinctrl/pinconf.c
index 8bfa0643e5dc..1fc09dc20199 100644
--- a/drivers/pinctrl/pinconf.c
+++ b/drivers/pinctrl/pinconf.c
@@ -288,7 +288,7 @@ static void pinconf_dump_pin(struct pinctrl_dev *pctldev,
const struct pinconf_ops *ops = pctldev->desc->confops;
/* no-op when not using generic pin config */
- pinconf_generic_dump_pin(pctldev, s, pin);
+ pinconf_generic_dump_pins(pctldev, s, NULL, pin);
if (ops && ops->pin_config_dbg_show)
ops->pin_config_dbg_show(pctldev, s, pin);
}
@@ -333,7 +333,7 @@ static void pinconf_dump_group(struct pinctrl_dev *pctldev,
const struct pinconf_ops *ops = pctldev->desc->confops;
/* no-op when not using generic pin config */
- pinconf_generic_dump_group(pctldev, s, gname);
+ pinconf_generic_dump_pins(pctldev, s, gname, 0);
if (ops && ops->pin_config_group_dbg_show)
ops->pin_config_group_dbg_show(pctldev, s, selector);
}
diff --git a/drivers/pinctrl/pinconf.h b/drivers/pinctrl/pinconf.h
index a4a5417e1413..55c75780b3b2 100644
--- a/drivers/pinctrl/pinconf.h
+++ b/drivers/pinctrl/pinconf.h
@@ -92,26 +92,17 @@ static inline void pinconf_init_device_debugfs(struct dentry *devroot,
#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_DEBUG_FS)
-void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
- struct seq_file *s, unsigned pin);
-
-void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
- struct seq_file *s, const char *gname);
+void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev,
+ struct seq_file *s, const char *gname,
+ unsigned pin);
void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
struct seq_file *s, unsigned long config);
#else
-static inline void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
- struct seq_file *s,
- unsigned pin)
-{
- return;
-}
-
-static inline void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
- struct seq_file *s,
- const char *gname)
+static inline void pinconf_generic_dump_pins(struct pinctrl_dev *pctldev,
+ struct seq_file *s,
+ const char *gname, unsigned pin)
{
return;
}
@@ -126,6 +117,7 @@ static inline void pinconf_generic_dump_config(struct pinctrl_dev *pctldev,
#if defined(CONFIG_GENERIC_PINCONF) && defined(CONFIG_OF)
int pinconf_generic_parse_dt_config(struct device_node *np,
+ struct pinctrl_dev *pctldev,
unsigned long **configs,
unsigned int *nconfigs);
#endif
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index dfd021e8268f..f4cd0b9b2438 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -177,7 +177,7 @@ struct at91_pinctrl {
struct device *dev;
struct pinctrl_dev *pctl;
- int nbanks;
+ int nactive_banks;
uint32_t *mux_mask;
int nmux;
@@ -653,12 +653,18 @@ static int pin_check_config(struct at91_pinctrl *info, const char *name,
int mux;
/* check if it's a valid config */
- if (pin->bank >= info->nbanks) {
+ if (pin->bank >= gpio_banks) {
dev_err(info->dev, "%s: pin conf %d bank_id %d >= nbanks %d\n",
- name, index, pin->bank, info->nbanks);
+ name, index, pin->bank, gpio_banks);
return -EINVAL;
}
+ if (!gpio_chips[pin->bank]) {
+ dev_err(info->dev, "%s: pin conf %d bank_id %d not enabled\n",
+ name, index, pin->bank);
+ return -ENXIO;
+ }
+
if (pin->pin >= MAX_NB_GPIO_PER_BANK) {
dev_err(info->dev, "%s: pin conf %d pin_bank_id %d >= %d\n",
name, index, pin->pin, MAX_NB_GPIO_PER_BANK);
@@ -981,7 +987,8 @@ static void at91_pinctrl_child_count(struct at91_pinctrl *info,
for_each_child_of_node(np, child) {
if (of_device_is_compatible(child, gpio_compat)) {
- info->nbanks++;
+ if (of_device_is_available(child))
+ info->nactive_banks++;
} else {
info->nfunctions++;
info->ngroups += of_get_child_count(child);
@@ -1003,11 +1010,11 @@ static int at91_pinctrl_mux_mask(struct at91_pinctrl *info,
}
size /= sizeof(*list);
- if (!size || size % info->nbanks) {
- dev_err(info->dev, "wrong mux mask array should be by %d\n", info->nbanks);
+ if (!size || size % gpio_banks) {
+ dev_err(info->dev, "wrong mux mask array should be by %d\n", gpio_banks);
return -EINVAL;
}
- info->nmux = size / info->nbanks;
+ info->nmux = size / gpio_banks;
info->mux_mask = devm_kzalloc(info->dev, sizeof(u32) * size, GFP_KERNEL);
if (!info->mux_mask) {
@@ -1131,7 +1138,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
of_match_device(at91_pinctrl_of_match, &pdev->dev)->data;
at91_pinctrl_child_count(info, np);
- if (info->nbanks < 1) {
+ if (gpio_banks < 1) {
dev_err(&pdev->dev, "you need to specify at least one gpio-controller\n");
return -EINVAL;
}
@@ -1144,7 +1151,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
dev_dbg(&pdev->dev, "mux-mask\n");
tmp = info->mux_mask;
- for (i = 0; i < info->nbanks; i++) {
+ for (i = 0; i < gpio_banks; i++) {
for (j = 0; j < info->nmux; j++, tmp++) {
dev_dbg(&pdev->dev, "%d:%d\t0x%x\n", i, j, tmp[0]);
}
@@ -1162,7 +1169,7 @@ static int at91_pinctrl_probe_dt(struct platform_device *pdev,
if (!info->groups)
return -ENOMEM;
- dev_dbg(&pdev->dev, "nbanks = %d\n", info->nbanks);
+ dev_dbg(&pdev->dev, "nbanks = %d\n", gpio_banks);
dev_dbg(&pdev->dev, "nfunctions = %d\n", info->nfunctions);
dev_dbg(&pdev->dev, "ngroups = %d\n", info->ngroups);
@@ -1185,7 +1192,7 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
{
struct at91_pinctrl *info;
struct pinctrl_pin_desc *pdesc;
- int ret, i, j, k;
+ int ret, i, j, k, ngpio_chips_enabled = 0;
info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
if (!info)
@@ -1200,23 +1207,27 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
* to obtain references to the struct gpio_chip * for them, and we
* need this to proceed.
*/
- for (i = 0; i < info->nbanks; i++) {
- if (!gpio_chips[i]) {
- dev_warn(&pdev->dev, "GPIO chip %d not registered yet\n", i);
- devm_kfree(&pdev->dev, info);
- return -EPROBE_DEFER;
- }
+ for (i = 0; i < gpio_banks; i++)
+ if (gpio_chips[i])
+ ngpio_chips_enabled++;
+
+ if (ngpio_chips_enabled < info->nactive_banks) {
+ dev_warn(&pdev->dev,
+ "All GPIO chips are not registered yet (%d/%d)\n",
+ ngpio_chips_enabled, info->nactive_banks);
+ devm_kfree(&pdev->dev, info);
+ return -EPROBE_DEFER;
}
at91_pinctrl_desc.name = dev_name(&pdev->dev);
- at91_pinctrl_desc.npins = info->nbanks * MAX_NB_GPIO_PER_BANK;
+ at91_pinctrl_desc.npins = gpio_banks * MAX_NB_GPIO_PER_BANK;
at91_pinctrl_desc.pins = pdesc =
devm_kzalloc(&pdev->dev, sizeof(*pdesc) * at91_pinctrl_desc.npins, GFP_KERNEL);
if (!at91_pinctrl_desc.pins)
return -ENOMEM;
- for (i = 0 , k = 0; i < info->nbanks; i++) {
+ for (i = 0, k = 0; i < gpio_banks; i++) {
for (j = 0; j < MAX_NB_GPIO_PER_BANK; j++, k++) {
pdesc->number = k;
pdesc->name = kasprintf(GFP_KERNEL, "pio%c%d", i + 'A', j);
@@ -1234,8 +1245,9 @@ static int at91_pinctrl_probe(struct platform_device *pdev)
}
/* We will handle a range of GPIO pins */
- for (i = 0; i < info->nbanks; i++)
- pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
+ for (i = 0; i < gpio_banks; i++)
+ if (gpio_chips[i])
+ pinctrl_add_gpio_range(info->pctl, &gpio_chips[i]->range);
dev_info(&pdev->dev, "initialized AT91 pinctrl driver\n");
@@ -1613,9 +1625,10 @@ static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
static int at91_gpio_of_irq_setup(struct platform_device *pdev,
struct at91_gpio_chip *at91_gpio)
{
+ struct gpio_chip *gpiochip_prev = NULL;
struct at91_gpio_chip *prev = NULL;
struct irq_data *d = irq_get_irq_data(at91_gpio->pioc_virq);
- int ret;
+ int ret, i;
at91_gpio->pioc_hwirq = irqd_to_hwirq(d);
@@ -1641,24 +1654,33 @@ static int at91_gpio_of_irq_setup(struct platform_device *pdev,
return ret;
}
- /* Setup chained handler */
- if (at91_gpio->pioc_idx)
- prev = gpio_chips[at91_gpio->pioc_idx - 1];
-
/* The top level handler handles one bank of GPIOs, except
* on some SoC it can handle up to three...
* We only set up the handler for the first of the list.
*/
- if (prev && prev->next == at91_gpio)
+ gpiochip_prev = irq_get_handler_data(at91_gpio->pioc_virq);
+ if (!gpiochip_prev) {
+ /* Then register the chain on the parent IRQ */
+ gpiochip_set_chained_irqchip(&at91_gpio->chip,
+ &gpio_irqchip,
+ at91_gpio->pioc_virq,
+ gpio_irq_handler);
return 0;
+ }
- /* Then register the chain on the parent IRQ */
- gpiochip_set_chained_irqchip(&at91_gpio->chip,
- &gpio_irqchip,
- at91_gpio->pioc_virq,
- gpio_irq_handler);
+ prev = container_of(gpiochip_prev, struct at91_gpio_chip, chip);
- return 0;
+ /* we can only have 2 banks before */
+ for (i = 0; i < 2; i++) {
+ if (prev->next) {
+ prev = prev->next;
+ } else {
+ prev->next = at91_gpio;
+ return 0;
+ }
+ }
+
+ return -EINVAL;
}
/* This structure is replicated for each GPIO block allocated at probe time */
@@ -1675,24 +1697,6 @@ static struct gpio_chip at91_gpio_template = {
.ngpio = MAX_NB_GPIO_PER_BANK,
};
-static void at91_gpio_probe_fixup(void)
-{
- unsigned i;
- struct at91_gpio_chip *at91_gpio, *last = NULL;
-
- for (i = 0; i < gpio_banks; i++) {
- at91_gpio = gpio_chips[i];
-
- /*
- * GPIO controller are grouped on some SoC:
- * PIOC, PIOD and PIOE can share the same IRQ line
- */
- if (last && last->pioc_virq == at91_gpio->pioc_virq)
- last->next = at91_gpio;
- last = at91_gpio;
- }
-}
-
static struct of_device_id at91_gpio_of_match[] = {
{ .compatible = "atmel,at91sam9x5-gpio", .data = &at91sam9x5_ops, },
{ .compatible = "atmel,at91rm9200-gpio", .data = &at91rm9200_ops },
@@ -1805,8 +1809,6 @@ static int at91_gpio_probe(struct platform_device *pdev)
gpio_chips[alias_idx] = at91_chip;
gpio_banks = max(gpio_banks, alias_idx + 1);
- at91_gpio_probe_fixup();
-
ret = at91_gpio_of_irq_setup(pdev, at91_chip);
if (ret)
goto irq_setup_err;
diff --git a/drivers/pinctrl/pinctrl-bcm281xx.c b/drivers/pinctrl/pinctrl-bcm281xx.c
index fa2a00f22ff1..b88cfe5ed55a 100644
--- a/drivers/pinctrl/pinctrl-bcm281xx.c
+++ b/drivers/pinctrl/pinctrl-bcm281xx.c
@@ -976,7 +976,7 @@ static inline void bcm281xx_pin_update(u32 *reg_val, u32 *reg_mask,
*reg_mask |= param_mask;
}
-static struct regmap_config bcm281xx_pinctrl_regmap_config = {
+static const struct regmap_config bcm281xx_pinctrl_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
.val_bits = 32,
@@ -1435,7 +1435,7 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev)
return 0;
}
-static struct of_device_id bcm281xx_pinctrl_of_match[] = {
+static const struct of_device_id bcm281xx_pinctrl_of_match[] = {
{ .compatible = "brcm,bcm11351-pinctrl", },
{ },
};
diff --git a/drivers/pinctrl/pinctrl-falcon.c b/drivers/pinctrl/pinctrl-falcon.c
index 1d21dc226920..0b0fc2eb48e0 100644
--- a/drivers/pinctrl/pinctrl-falcon.c
+++ b/drivers/pinctrl/pinctrl-falcon.c
@@ -101,6 +101,7 @@ static void lantiq_load_pin_desc(struct pinctrl_pin_desc *d, int bank, int len)
for (i = 0; i < len; i++) {
/* strlen("ioXYZ") + 1 = 6 */
char *name = kzalloc(6, GFP_KERNEL);
+
snprintf(name, 6, "io%d", base + i);
d[i].number = base + i;
d[i].name = name;
@@ -463,7 +464,7 @@ static int pinctrl_falcon_probe(struct platform_device *pdev)
&res);
if (IS_ERR(falcon_info.membase[*bank]))
return PTR_ERR(falcon_info.membase[*bank]);
-
+
avail = pad_r32(falcon_info.membase[*bank],
LTQ_PADC_AVAIL);
pins = fls(avail);
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 43eacc924b7e..dee7d5f06c60 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -89,7 +89,7 @@ struct rockchip_iomux {
* @reg_pull: optional separate register for additional pull settings
* @clk: clock of the gpio bank
* @irq: interrupt of the gpio bank
- * @saved_enables: Saved content of GPIO_INTEN at suspend time.
+ * @saved_masks: Saved content of GPIO_INTEN at suspend time.
* @pin_base: first pin number
* @nr_pins: number of pins in this bank
* @name: name of the bank
@@ -108,7 +108,7 @@ struct rockchip_pin_bank {
struct regmap *regmap_pull;
struct clk *clk;
int irq;
- u32 saved_enables;
+ u32 saved_masks;
u32 pin_base;
u8 nr_pins;
char *name;
@@ -1142,7 +1142,7 @@ static int rockchip_pinctrl_parse_groups(struct device_node *np,
return -EINVAL;
np_config = of_find_node_by_phandle(be32_to_cpup(phandle));
- ret = pinconf_generic_parse_dt_config(np_config,
+ ret = pinconf_generic_parse_dt_config(np_config, NULL,
&grp->data[j].configs, &grp->data[j].nconfigs);
if (ret)
return ret;
@@ -1545,8 +1545,8 @@ static void rockchip_irq_suspend(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct rockchip_pin_bank *bank = gc->private;
- bank->saved_enables = irq_reg_readl(gc, GPIO_INTEN);
- irq_reg_writel(gc, gc->wake_active, GPIO_INTEN);
+ bank->saved_masks = irq_reg_readl(gc, GPIO_INTMASK);
+ irq_reg_writel(gc, ~gc->wake_active, GPIO_INTMASK);
}
static void rockchip_irq_resume(struct irq_data *d)
@@ -1554,35 +1554,7 @@ static void rockchip_irq_resume(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct rockchip_pin_bank *bank = gc->private;
- irq_reg_writel(gc, bank->saved_enables, GPIO_INTEN);
-}
-
-static void rockchip_irq_disable(struct irq_data *d)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- u32 val;
-
- irq_gc_lock(gc);
-
- val = irq_reg_readl(gc, GPIO_INTEN);
- val &= ~d->mask;
- irq_reg_writel(gc, val, GPIO_INTEN);
-
- irq_gc_unlock(gc);
-}
-
-static void rockchip_irq_enable(struct irq_data *d)
-{
- struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- u32 val;
-
- irq_gc_lock(gc);
-
- val = irq_reg_readl(gc, GPIO_INTEN);
- val |= d->mask;
- irq_reg_writel(gc, val, GPIO_INTEN);
-
- irq_gc_unlock(gc);
+ irq_reg_writel(gc, bank->saved_masks, GPIO_INTMASK);
}
static int rockchip_interrupts_register(struct platform_device *pdev,
@@ -1620,6 +1592,14 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
continue;
}
+ /*
+ * Linux assumes that all interrupts start out disabled/masked.
+ * Our driver only uses the concept of masked and always keeps
+ * things enabled, so for us that's all masked and all enabled.
+ */
+ writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTMASK);
+ writel_relaxed(0xffffffff, bank->reg_base + GPIO_INTEN);
+
gc = irq_get_domain_generic_chip(bank->domain, 0);
gc->reg_base = bank->reg_base;
gc->private = bank;
@@ -1628,8 +1608,6 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
gc->chip_types[0].chip.irq_ack = irq_gc_ack_set_bit;
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_enable = rockchip_irq_enable;
- gc->chip_types[0].chip.irq_disable = rockchip_irq_disable;
gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
gc->chip_types[0].chip.irq_suspend = rockchip_irq_suspend;
gc->chip_types[0].chip.irq_resume = rockchip_irq_resume;
diff --git a/drivers/pinctrl/pinctrl-tz1090-pdc.c b/drivers/pinctrl/pinctrl-tz1090-pdc.c
index 146e48a9b839..fab6aafa6a9f 100644
--- a/drivers/pinctrl/pinctrl-tz1090-pdc.c
+++ b/drivers/pinctrl/pinctrl-tz1090-pdc.c
@@ -415,7 +415,7 @@ static int tz1090_pdc_pinctrl_dt_subnode_to_map(struct device *dev,
function = NULL;
}
- ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+ ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs);
if (ret)
return ret;
diff --git a/drivers/pinctrl/pinctrl-tz1090.c b/drivers/pinctrl/pinctrl-tz1090.c
index df8cb1e5b7b4..8bd73075f9dd 100644
--- a/drivers/pinctrl/pinctrl-tz1090.c
+++ b/drivers/pinctrl/pinctrl-tz1090.c
@@ -1131,7 +1131,7 @@ static int tz1090_pinctrl_dt_subnode_to_map(struct device *dev,
function = NULL;
}
- ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+ ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs);
if (ret)
return ret;
diff --git a/drivers/pinctrl/pinctrl-zynq.c b/drivers/pinctrl/pinctrl-zynq.c
new file mode 100644
index 000000000000..22280bddb9e2
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-zynq.c
@@ -0,0 +1,1180 @@
+/*
+ * Zynq pin controller
+ *
+ * Copyright (C) 2014 Xilinx
+ *
+ * Sören Brinkmann <soren.brinkmann@xilinx.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/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/regmap.h>
+#include "pinctrl-utils.h"
+#include "core.h"
+
+#define ZYNQ_NUM_MIOS 54
+
+#define ZYNQ_PCTRL_MIO_MST_TRI0 0x10c
+#define ZYNQ_PCTRL_MIO_MST_TRI1 0x110
+
+#define ZYNQ_PINMUX_MUX_SHIFT 1
+#define ZYNQ_PINMUX_MUX_MASK (0x7f << ZYNQ_PINMUX_MUX_SHIFT)
+
+/**
+ * struct zynq_pinctrl - driver data
+ * @pctrl: Pinctrl device
+ * @syscon: Syscon regmap
+ * @pctrl_offset: Offset for pinctrl into the @syscon space
+ * @groups: Pingroups
+ * @ngroupos: Number of @groups
+ * @funcs: Pinmux functions
+ * @nfuncs: Number of @funcs
+ */
+struct zynq_pinctrl {
+ struct pinctrl_dev *pctrl;
+ struct regmap *syscon;
+ u32 pctrl_offset;
+ const struct zynq_pctrl_group *groups;
+ unsigned int ngroups;
+ const struct zynq_pinmux_function *funcs;
+ unsigned int nfuncs;
+};
+
+struct zynq_pctrl_group {
+ const char *name;
+ const unsigned int *pins;
+ const unsigned npins;
+};
+
+/**
+ * struct zynq_pinmux_function - a pinmux function
+ * @name: Name of the pinmux function.
+ * @groups: List of pingroups for this function.
+ * @ngroups: Number of entries in @groups.
+ * @mux_val: Selector for this function
+ * @mux: Offset of function specific mux
+ * @mux_mask: Mask for function specific selector
+ * @mux_shift: Shift for function specific selector
+ */
+struct zynq_pinmux_function {
+ const char *name;
+ const char * const *groups;
+ unsigned int ngroups;
+ unsigned int mux_val;
+ u32 mux;
+ u32 mux_mask;
+ u8 mux_shift;
+};
+
+enum zynq_pinmux_functions {
+ ZYNQ_PMUX_can0,
+ ZYNQ_PMUX_can1,
+ ZYNQ_PMUX_ethernet0,
+ ZYNQ_PMUX_ethernet1,
+ ZYNQ_PMUX_gpio0,
+ ZYNQ_PMUX_i2c0,
+ ZYNQ_PMUX_i2c1,
+ ZYNQ_PMUX_mdio0,
+ ZYNQ_PMUX_mdio1,
+ ZYNQ_PMUX_qspi0,
+ ZYNQ_PMUX_qspi1,
+ ZYNQ_PMUX_qspi_fbclk,
+ ZYNQ_PMUX_qspi_cs1,
+ ZYNQ_PMUX_spi0,
+ ZYNQ_PMUX_spi1,
+ ZYNQ_PMUX_sdio0,
+ ZYNQ_PMUX_sdio0_pc,
+ ZYNQ_PMUX_sdio0_cd,
+ ZYNQ_PMUX_sdio0_wp,
+ ZYNQ_PMUX_sdio1,
+ ZYNQ_PMUX_sdio1_pc,
+ ZYNQ_PMUX_sdio1_cd,
+ ZYNQ_PMUX_sdio1_wp,
+ ZYNQ_PMUX_smc0_nor,
+ ZYNQ_PMUX_smc0_nor_cs1,
+ ZYNQ_PMUX_smc0_nor_addr25,
+ ZYNQ_PMUX_smc0_nand,
+ ZYNQ_PMUX_ttc0,
+ ZYNQ_PMUX_ttc1,
+ ZYNQ_PMUX_uart0,
+ ZYNQ_PMUX_uart1,
+ ZYNQ_PMUX_usb0,
+ ZYNQ_PMUX_usb1,
+ ZYNQ_PMUX_swdt0,
+ ZYNQ_PMUX_MAX_FUNC
+};
+
+const struct pinctrl_pin_desc zynq_pins[] = {
+ PINCTRL_PIN(0, "MIO0"),
+ PINCTRL_PIN(1, "MIO1"),
+ PINCTRL_PIN(2, "MIO2"),
+ PINCTRL_PIN(3, "MIO3"),
+ PINCTRL_PIN(4, "MIO4"),
+ PINCTRL_PIN(5, "MIO5"),
+ PINCTRL_PIN(6, "MIO6"),
+ PINCTRL_PIN(7, "MIO7"),
+ PINCTRL_PIN(8, "MIO8"),
+ PINCTRL_PIN(9, "MIO9"),
+ PINCTRL_PIN(10, "MIO10"),
+ PINCTRL_PIN(11, "MIO11"),
+ PINCTRL_PIN(12, "MIO12"),
+ PINCTRL_PIN(13, "MIO13"),
+ PINCTRL_PIN(14, "MIO14"),
+ PINCTRL_PIN(15, "MIO15"),
+ PINCTRL_PIN(16, "MIO16"),
+ PINCTRL_PIN(17, "MIO17"),
+ PINCTRL_PIN(18, "MIO18"),
+ PINCTRL_PIN(19, "MIO19"),
+ PINCTRL_PIN(20, "MIO20"),
+ PINCTRL_PIN(21, "MIO21"),
+ PINCTRL_PIN(22, "MIO22"),
+ PINCTRL_PIN(23, "MIO23"),
+ PINCTRL_PIN(24, "MIO24"),
+ PINCTRL_PIN(25, "MIO25"),
+ PINCTRL_PIN(26, "MIO26"),
+ PINCTRL_PIN(27, "MIO27"),
+ PINCTRL_PIN(28, "MIO28"),
+ PINCTRL_PIN(29, "MIO29"),
+ PINCTRL_PIN(30, "MIO30"),
+ PINCTRL_PIN(31, "MIO31"),
+ PINCTRL_PIN(32, "MIO32"),
+ PINCTRL_PIN(33, "MIO33"),
+ PINCTRL_PIN(34, "MIO34"),
+ PINCTRL_PIN(35, "MIO35"),
+ PINCTRL_PIN(36, "MIO36"),
+ PINCTRL_PIN(37, "MIO37"),
+ PINCTRL_PIN(38, "MIO38"),
+ PINCTRL_PIN(39, "MIO39"),
+ PINCTRL_PIN(40, "MIO40"),
+ PINCTRL_PIN(41, "MIO41"),
+ PINCTRL_PIN(42, "MIO42"),
+ PINCTRL_PIN(43, "MIO43"),
+ PINCTRL_PIN(44, "MIO44"),
+ PINCTRL_PIN(45, "MIO45"),
+ PINCTRL_PIN(46, "MIO46"),
+ PINCTRL_PIN(47, "MIO47"),
+ PINCTRL_PIN(48, "MIO48"),
+ PINCTRL_PIN(49, "MIO49"),
+ PINCTRL_PIN(50, "MIO50"),
+ PINCTRL_PIN(51, "MIO51"),
+ PINCTRL_PIN(52, "MIO52"),
+ PINCTRL_PIN(53, "MIO53"),
+ PINCTRL_PIN(54, "EMIO_SD0_WP"),
+ PINCTRL_PIN(55, "EMIO_SD0_CD"),
+ PINCTRL_PIN(56, "EMIO_SD1_WP"),
+ PINCTRL_PIN(57, "EMIO_SD1_CD"),
+};
+
+/* pin groups */
+static const unsigned int ethernet0_0_pins[] = {16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27};
+static const unsigned int ethernet1_0_pins[] = {28, 29, 30, 31, 32, 33, 34, 35,
+ 36, 37, 38, 39};
+static const unsigned int mdio0_0_pins[] = {52, 53};
+static const unsigned int mdio1_0_pins[] = {52, 53};
+static const unsigned int qspi0_0_pins[] = {1, 2, 3, 4, 5, 6};
+
+static const unsigned int qspi1_0_pins[] = {9, 10, 11, 12, 13};
+static const unsigned int qspi_cs1_pins[] = {0};
+static const unsigned int qspi_fbclk_pins[] = {8};
+static const unsigned int spi0_0_pins[] = {16, 17, 18, 19, 20, 21};
+static const unsigned int spi0_1_pins[] = {28, 29, 30, 31, 32, 33};
+static const unsigned int spi0_2_pins[] = {40, 41, 42, 43, 44, 45};
+static const unsigned int spi1_0_pins[] = {10, 11, 12, 13, 14, 15};
+static const unsigned int spi1_1_pins[] = {22, 23, 24, 25, 26, 27};
+static const unsigned int spi1_2_pins[] = {34, 35, 36, 37, 38, 39};
+static const unsigned int spi1_3_pins[] = {46, 47, 48, 49, 40, 51};
+static const unsigned int sdio0_0_pins[] = {16, 17, 18, 19, 20, 21};
+static const unsigned int sdio0_1_pins[] = {28, 29, 30, 31, 32, 33};
+static const unsigned int sdio0_2_pins[] = {40, 41, 42, 43, 44, 45};
+static const unsigned int sdio1_0_pins[] = {10, 11, 12, 13, 14, 15};
+static const unsigned int sdio1_1_pins[] = {22, 23, 24, 25, 26, 27};
+static const unsigned int sdio1_2_pins[] = {34, 35, 36, 37, 38, 39};
+static const unsigned int sdio1_3_pins[] = {46, 47, 48, 49, 40, 51};
+static const unsigned int sdio0_emio_wp_pins[] = {54};
+static const unsigned int sdio0_emio_cd_pins[] = {55};
+static const unsigned int sdio1_emio_wp_pins[] = {56};
+static const unsigned int sdio1_emio_cd_pins[] = {57};
+static const unsigned int smc0_nor_pins[] = {0, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 26, 27, 28, 29, 30, 31, 32,
+ 33, 34, 35, 36, 37, 38, 39};
+static const unsigned int smc0_nor_cs1_pins[] = {1};
+static const unsigned int smc0_nor_addr25_pins[] = {1};
+static const unsigned int smc0_nand_pins[] = {0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
+ 12, 13, 14, 16, 17, 18, 19, 20,
+ 21, 22, 23};
+/* Note: CAN MIO clock inputs are modeled in the clock framework */
+static const unsigned int can0_0_pins[] = {10, 11};
+static const unsigned int can0_1_pins[] = {14, 15};
+static const unsigned int can0_2_pins[] = {18, 19};
+static const unsigned int can0_3_pins[] = {22, 23};
+static const unsigned int can0_4_pins[] = {26, 27};
+static const unsigned int can0_5_pins[] = {30, 31};
+static const unsigned int can0_6_pins[] = {34, 35};
+static const unsigned int can0_7_pins[] = {38, 39};
+static const unsigned int can0_8_pins[] = {42, 43};
+static const unsigned int can0_9_pins[] = {46, 47};
+static const unsigned int can0_10_pins[] = {50, 51};
+static const unsigned int can1_0_pins[] = {8, 9};
+static const unsigned int can1_1_pins[] = {12, 13};
+static const unsigned int can1_2_pins[] = {16, 17};
+static const unsigned int can1_3_pins[] = {20, 21};
+static const unsigned int can1_4_pins[] = {24, 25};
+static const unsigned int can1_5_pins[] = {28, 29};
+static const unsigned int can1_6_pins[] = {32, 33};
+static const unsigned int can1_7_pins[] = {36, 37};
+static const unsigned int can1_8_pins[] = {40, 41};
+static const unsigned int can1_9_pins[] = {44, 45};
+static const unsigned int can1_10_pins[] = {48, 49};
+static const unsigned int can1_11_pins[] = {52, 53};
+static const unsigned int uart0_0_pins[] = {10, 11};
+static const unsigned int uart0_1_pins[] = {14, 15};
+static const unsigned int uart0_2_pins[] = {18, 19};
+static const unsigned int uart0_3_pins[] = {22, 23};
+static const unsigned int uart0_4_pins[] = {26, 27};
+static const unsigned int uart0_5_pins[] = {30, 31};
+static const unsigned int uart0_6_pins[] = {34, 35};
+static const unsigned int uart0_7_pins[] = {38, 39};
+static const unsigned int uart0_8_pins[] = {42, 43};
+static const unsigned int uart0_9_pins[] = {46, 47};
+static const unsigned int uart0_10_pins[] = {50, 51};
+static const unsigned int uart1_0_pins[] = {8, 9};
+static const unsigned int uart1_1_pins[] = {12, 13};
+static const unsigned int uart1_2_pins[] = {16, 17};
+static const unsigned int uart1_3_pins[] = {20, 21};
+static const unsigned int uart1_4_pins[] = {24, 25};
+static const unsigned int uart1_5_pins[] = {28, 29};
+static const unsigned int uart1_6_pins[] = {32, 33};
+static const unsigned int uart1_7_pins[] = {36, 37};
+static const unsigned int uart1_8_pins[] = {40, 41};
+static const unsigned int uart1_9_pins[] = {44, 45};
+static const unsigned int uart1_10_pins[] = {48, 49};
+static const unsigned int uart1_11_pins[] = {52, 53};
+static const unsigned int i2c0_0_pins[] = {10, 11};
+static const unsigned int i2c0_1_pins[] = {14, 15};
+static const unsigned int i2c0_2_pins[] = {18, 19};
+static const unsigned int i2c0_3_pins[] = {22, 23};
+static const unsigned int i2c0_4_pins[] = {26, 27};
+static const unsigned int i2c0_5_pins[] = {30, 31};
+static const unsigned int i2c0_6_pins[] = {34, 35};
+static const unsigned int i2c0_7_pins[] = {38, 39};
+static const unsigned int i2c0_8_pins[] = {42, 43};
+static const unsigned int i2c0_9_pins[] = {46, 47};
+static const unsigned int i2c0_10_pins[] = {50, 51};
+static const unsigned int i2c1_0_pins[] = {12, 13};
+static const unsigned int i2c1_1_pins[] = {16, 17};
+static const unsigned int i2c1_2_pins[] = {20, 21};
+static const unsigned int i2c1_3_pins[] = {24, 25};
+static const unsigned int i2c1_4_pins[] = {28, 29};
+static const unsigned int i2c1_5_pins[] = {32, 33};
+static const unsigned int i2c1_6_pins[] = {36, 37};
+static const unsigned int i2c1_7_pins[] = {40, 41};
+static const unsigned int i2c1_8_pins[] = {44, 45};
+static const unsigned int i2c1_9_pins[] = {48, 49};
+static const unsigned int i2c1_10_pins[] = {52, 53};
+static const unsigned int ttc0_0_pins[] = {18, 19};
+static const unsigned int ttc0_1_pins[] = {30, 31};
+static const unsigned int ttc0_2_pins[] = {42, 43};
+static const unsigned int ttc1_0_pins[] = {16, 17};
+static const unsigned int ttc1_1_pins[] = {28, 29};
+static const unsigned int ttc1_2_pins[] = {40, 41};
+static const unsigned int swdt0_0_pins[] = {14, 15};
+static const unsigned int swdt0_1_pins[] = {26, 27};
+static const unsigned int swdt0_2_pins[] = {38, 39};
+static const unsigned int swdt0_3_pins[] = {50, 51};
+static const unsigned int swdt0_4_pins[] = {52, 53};
+static const unsigned int gpio0_0_pins[] = {0};
+static const unsigned int gpio0_1_pins[] = {1};
+static const unsigned int gpio0_2_pins[] = {2};
+static const unsigned int gpio0_3_pins[] = {3};
+static const unsigned int gpio0_4_pins[] = {4};
+static const unsigned int gpio0_5_pins[] = {5};
+static const unsigned int gpio0_6_pins[] = {6};
+static const unsigned int gpio0_7_pins[] = {7};
+static const unsigned int gpio0_8_pins[] = {8};
+static const unsigned int gpio0_9_pins[] = {9};
+static const unsigned int gpio0_10_pins[] = {10};
+static const unsigned int gpio0_11_pins[] = {11};
+static const unsigned int gpio0_12_pins[] = {12};
+static const unsigned int gpio0_13_pins[] = {13};
+static const unsigned int gpio0_14_pins[] = {14};
+static const unsigned int gpio0_15_pins[] = {15};
+static const unsigned int gpio0_16_pins[] = {16};
+static const unsigned int gpio0_17_pins[] = {17};
+static const unsigned int gpio0_18_pins[] = {18};
+static const unsigned int gpio0_19_pins[] = {19};
+static const unsigned int gpio0_20_pins[] = {20};
+static const unsigned int gpio0_21_pins[] = {21};
+static const unsigned int gpio0_22_pins[] = {22};
+static const unsigned int gpio0_23_pins[] = {23};
+static const unsigned int gpio0_24_pins[] = {24};
+static const unsigned int gpio0_25_pins[] = {25};
+static const unsigned int gpio0_26_pins[] = {26};
+static const unsigned int gpio0_27_pins[] = {27};
+static const unsigned int gpio0_28_pins[] = {28};
+static const unsigned int gpio0_29_pins[] = {29};
+static const unsigned int gpio0_30_pins[] = {30};
+static const unsigned int gpio0_31_pins[] = {31};
+static const unsigned int gpio0_32_pins[] = {32};
+static const unsigned int gpio0_33_pins[] = {33};
+static const unsigned int gpio0_34_pins[] = {34};
+static const unsigned int gpio0_35_pins[] = {35};
+static const unsigned int gpio0_36_pins[] = {36};
+static const unsigned int gpio0_37_pins[] = {37};
+static const unsigned int gpio0_38_pins[] = {38};
+static const unsigned int gpio0_39_pins[] = {39};
+static const unsigned int gpio0_40_pins[] = {40};
+static const unsigned int gpio0_41_pins[] = {41};
+static const unsigned int gpio0_42_pins[] = {42};
+static const unsigned int gpio0_43_pins[] = {43};
+static const unsigned int gpio0_44_pins[] = {44};
+static const unsigned int gpio0_45_pins[] = {45};
+static const unsigned int gpio0_46_pins[] = {46};
+static const unsigned int gpio0_47_pins[] = {47};
+static const unsigned int gpio0_48_pins[] = {48};
+static const unsigned int gpio0_49_pins[] = {49};
+static const unsigned int gpio0_50_pins[] = {50};
+static const unsigned int gpio0_51_pins[] = {51};
+static const unsigned int gpio0_52_pins[] = {52};
+static const unsigned int gpio0_53_pins[] = {53};
+static const unsigned int usb0_0_pins[] = {28, 29, 30, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39};
+static const unsigned int usb1_0_pins[] = {40, 41, 42, 43, 44, 45, 46, 47, 48,
+ 49, 50, 51};
+
+#define DEFINE_ZYNQ_PINCTRL_GRP(nm) \
+ { \
+ .name = #nm "_grp", \
+ .pins = nm ## _pins, \
+ .npins = ARRAY_SIZE(nm ## _pins), \
+ }
+
+struct zynq_pctrl_group zynq_pctrl_groups[] = {
+ DEFINE_ZYNQ_PINCTRL_GRP(ethernet0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(ethernet1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(mdio0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(mdio1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(qspi0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(qspi1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(qspi_fbclk),
+ DEFINE_ZYNQ_PINCTRL_GRP(qspi_cs1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(spi1_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio1_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio0_emio_wp),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio0_emio_cd),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio1_emio_wp),
+ DEFINE_ZYNQ_PINCTRL_GRP(sdio1_emio_cd),
+ DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor),
+ DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor_cs1),
+ DEFINE_ZYNQ_PINCTRL_GRP(smc0_nor_addr25),
+ DEFINE_ZYNQ_PINCTRL_GRP(smc0_nand),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(can0_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(can1_11),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart0_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(uart1_11),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c0_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(i2c1_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(ttc0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(ttc0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(ttc0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(ttc1_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(ttc1_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(ttc1_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(swdt0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(swdt0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(swdt0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(swdt0_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(swdt0_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_1),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_2),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_3),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_4),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_5),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_6),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_7),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_8),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_9),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_10),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_11),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_12),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_13),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_14),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_15),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_16),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_17),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_18),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_19),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_20),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_21),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_22),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_23),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_24),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_25),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_26),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_27),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_28),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_29),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_30),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_31),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_32),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_33),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_34),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_35),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_36),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_37),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_38),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_39),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_40),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_41),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_42),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_43),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_44),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_45),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_46),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_47),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_48),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_49),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_50),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_51),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_52),
+ DEFINE_ZYNQ_PINCTRL_GRP(gpio0_53),
+ DEFINE_ZYNQ_PINCTRL_GRP(usb0_0),
+ DEFINE_ZYNQ_PINCTRL_GRP(usb1_0),
+};
+
+/* function groups */
+static const char * const ethernet0_groups[] = {"ethernet0_0_grp"};
+static const char * const ethernet1_groups[] = {"ethernet1_0_grp"};
+static const char * const usb0_groups[] = {"usb0_0_grp"};
+static const char * const usb1_groups[] = {"usb1_0_grp"};
+static const char * const mdio0_groups[] = {"mdio0_0_grp"};
+static const char * const mdio1_groups[] = {"mdio1_0_grp"};
+static const char * const qspi0_groups[] = {"qspi0_0_grp"};
+static const char * const qspi1_groups[] = {"qspi0_1_grp"};
+static const char * const qspi_fbclk_groups[] = {"qspi_fbclk_grp"};
+static const char * const qspi_cs1_groups[] = {"qspi_cs1_grp"};
+static const char * const spi0_groups[] = {"spi0_0_grp", "spi0_1_grp",
+ "spi0_2_grp"};
+static const char * const spi1_groups[] = {"spi1_0_grp", "spi1_1_grp",
+ "spi1_2_grp", "spi1_3_grp"};
+static const char * const sdio0_groups[] = {"sdio0_0_grp", "sdio0_1_grp",
+ "sdio0_2_grp"};
+static const char * const sdio1_groups[] = {"sdio1_0_grp", "sdio1_1_grp",
+ "sdio1_2_grp", "sdio1_3_grp"};
+static const char * const sdio0_pc_groups[] = {"gpio0_0_grp",
+ "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp",
+ "gpio0_8_grp", "gpio0_10_grp", "gpio0_12_grp",
+ "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp",
+ "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp",
+ "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp",
+ "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp",
+ "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp",
+ "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp",
+ "gpio0_50_grp", "gpio0_52_grp"};
+static const char * const sdio1_pc_groups[] = {"gpio0_1_grp",
+ "gpio0_3_grp", "gpio0_5_grp", "gpio0_7_grp",
+ "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp",
+ "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp",
+ "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp",
+ "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp",
+ "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp",
+ "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp",
+ "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp",
+ "gpio0_51_grp", "gpio0_53_grp"};
+static const char * const sdio0_cd_groups[] = {"gpio0_0_grp",
+ "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp",
+ "gpio0_10_grp", "gpio0_12_grp",
+ "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp",
+ "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp",
+ "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp",
+ "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp",
+ "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp",
+ "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp",
+ "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp",
+ "gpio0_3_grp", "gpio0_5_grp",
+ "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp",
+ "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp",
+ "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp",
+ "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp",
+ "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp",
+ "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp",
+ "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp",
+ "gpio0_51_grp", "gpio0_53_grp", "sdio0_emio_cd_grp"};
+static const char * const sdio0_wp_groups[] = {"gpio0_0_grp",
+ "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp",
+ "gpio0_10_grp", "gpio0_12_grp",
+ "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp",
+ "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp",
+ "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp",
+ "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp",
+ "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp",
+ "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp",
+ "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp",
+ "gpio0_3_grp", "gpio0_5_grp",
+ "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp",
+ "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp",
+ "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp",
+ "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp",
+ "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp",
+ "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp",
+ "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp",
+ "gpio0_51_grp", "gpio0_53_grp", "sdio0_emio_wp_grp"};
+static const char * const sdio1_cd_groups[] = {"gpio0_0_grp",
+ "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp",
+ "gpio0_10_grp", "gpio0_12_grp",
+ "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp",
+ "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp",
+ "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp",
+ "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp",
+ "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp",
+ "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp",
+ "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp",
+ "gpio0_3_grp", "gpio0_5_grp",
+ "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp",
+ "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp",
+ "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp",
+ "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp",
+ "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp",
+ "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp",
+ "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp",
+ "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_cd_grp"};
+static const char * const sdio1_wp_groups[] = {"gpio0_0_grp",
+ "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp",
+ "gpio0_10_grp", "gpio0_12_grp",
+ "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp",
+ "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp",
+ "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp",
+ "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp",
+ "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp",
+ "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp",
+ "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp",
+ "gpio0_3_grp", "gpio0_5_grp",
+ "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp",
+ "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp",
+ "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp",
+ "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp",
+ "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp",
+ "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp",
+ "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp",
+ "gpio0_51_grp", "gpio0_53_grp", "sdio1_emio_wp_grp"};
+static const char * const smc0_nor_groups[] = {"smc0_nor"};
+static const char * const smc0_nor_cs1_groups[] = {"smc0_nor_cs1_grp"};
+static const char * const smc0_nor_addr25_groups[] = {"smc0_nor_addr25_grp"};
+static const char * const smc0_nand_groups[] = {"smc0_nand"};
+static const char * const can0_groups[] = {"can0_0_grp", "can0_1_grp",
+ "can0_2_grp", "can0_3_grp", "can0_4_grp", "can0_5_grp",
+ "can0_6_grp", "can0_7_grp", "can0_8_grp", "can0_9_grp",
+ "can0_10_grp"};
+static const char * const can1_groups[] = {"can1_0_grp", "can1_1_grp",
+ "can1_2_grp", "can1_3_grp", "can1_4_grp", "can1_5_grp",
+ "can1_6_grp", "can1_7_grp", "can1_8_grp", "can1_9_grp",
+ "can1_10_grp", "can1_11_grp"};
+static const char * const uart0_groups[] = {"uart0_0_grp", "uart0_1_grp",
+ "uart0_2_grp", "uart0_3_grp", "uart0_4_grp", "uart0_5_grp",
+ "uart0_6_grp", "uart0_7_grp", "uart0_8_grp", "uart0_9_grp",
+ "uart0_10_grp"};
+static const char * const uart1_groups[] = {"uart1_0_grp", "uart1_1_grp",
+ "uart1_2_grp", "uart1_3_grp", "uart1_4_grp", "uart1_5_grp",
+ "uart1_6_grp", "uart1_7_grp", "uart1_8_grp", "uart1_9_grp",
+ "uart1_10_grp", "uart1_11_grp"};
+static const char * const i2c0_groups[] = {"i2c0_0_grp", "i2c0_1_grp",
+ "i2c0_2_grp", "i2c0_3_grp", "i2c0_4_grp", "i2c0_5_grp",
+ "i2c0_6_grp", "i2c0_7_grp", "i2c0_8_grp", "i2c0_9_grp",
+ "i2c0_10_grp"};
+static const char * const i2c1_groups[] = {"i2c1_0_grp", "i2c1_1_grp",
+ "i2c1_2_grp", "i2c1_3_grp", "i2c1_4_grp", "i2c1_5_grp",
+ "i2c1_6_grp", "i2c1_7_grp", "i2c1_8_grp", "i2c1_9_grp",
+ "i2c1_10_grp"};
+static const char * const ttc0_groups[] = {"ttc0_0_grp", "ttc0_1_grp",
+ "ttc0_2_grp"};
+static const char * const ttc1_groups[] = {"ttc1_0_grp", "ttc1_1_grp",
+ "ttc1_2_grp"};
+static const char * const swdt0_groups[] = {"swdt0_0_grp", "swdt0_1_grp",
+ "swdt0_2_grp", "swdt0_3_grp", "swdt0_4_grp"};
+static const char * const gpio0_groups[] = {"gpio0_0_grp",
+ "gpio0_2_grp", "gpio0_4_grp", "gpio0_6_grp",
+ "gpio0_8_grp", "gpio0_10_grp", "gpio0_12_grp",
+ "gpio0_14_grp", "gpio0_16_grp", "gpio0_18_grp",
+ "gpio0_20_grp", "gpio0_22_grp", "gpio0_24_grp",
+ "gpio0_26_grp", "gpio0_28_grp", "gpio0_30_grp",
+ "gpio0_32_grp", "gpio0_34_grp", "gpio0_36_grp",
+ "gpio0_38_grp", "gpio0_40_grp", "gpio0_42_grp",
+ "gpio0_44_grp", "gpio0_46_grp", "gpio0_48_grp",
+ "gpio0_50_grp", "gpio0_52_grp", "gpio0_1_grp",
+ "gpio0_3_grp", "gpio0_5_grp", "gpio0_7_grp",
+ "gpio0_9_grp", "gpio0_11_grp", "gpio0_13_grp",
+ "gpio0_15_grp", "gpio0_17_grp", "gpio0_19_grp",
+ "gpio0_21_grp", "gpio0_23_grp", "gpio0_25_grp",
+ "gpio0_27_grp", "gpio0_29_grp", "gpio0_31_grp",
+ "gpio0_33_grp", "gpio0_35_grp", "gpio0_37_grp",
+ "gpio0_39_grp", "gpio0_41_grp", "gpio0_43_grp",
+ "gpio0_45_grp", "gpio0_47_grp", "gpio0_49_grp",
+ "gpio0_51_grp", "gpio0_53_grp"};
+
+#define DEFINE_ZYNQ_PINMUX_FUNCTION(fname, mval) \
+ [ZYNQ_PMUX_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ .mux_val = mval, \
+ }
+
+#define DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(fname, mval, mux, mask, shift) \
+ [ZYNQ_PMUX_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ .mux_val = mval, \
+ .mux_mask = mask, \
+ .mux_shift = shift, \
+ }
+
+#define ZYNQ_SDIO_WP_SHIFT 0
+#define ZYNQ_SDIO_WP_MASK (0x3f << ZYNQ_SDIO_WP_SHIFT)
+#define ZYNQ_SDIO_CD_SHIFT 16
+#define ZYNQ_SDIO_CD_MASK (0x3f << ZYNQ_SDIO_CD_SHIFT)
+
+static const struct zynq_pinmux_function zynq_pmux_functions[] = {
+ DEFINE_ZYNQ_PINMUX_FUNCTION(ethernet0, 1),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(ethernet1, 1),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(usb0, 2),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(usb1, 2),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(mdio0, 0x40),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(mdio1, 0x50),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(qspi0, 1),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(qspi1, 1),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_fbclk, 1),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(qspi_cs1, 1),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(spi0, 0x50),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(spi1, 0x50),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0, 0x40),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(sdio0_pc, 0xc),
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_wp, 0, 130, ZYNQ_SDIO_WP_MASK,
+ ZYNQ_SDIO_WP_SHIFT),
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio0_cd, 0, 130, ZYNQ_SDIO_CD_MASK,
+ ZYNQ_SDIO_CD_SHIFT),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1, 0x40),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(sdio1_pc, 0xc),
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_wp, 0, 134, ZYNQ_SDIO_WP_MASK,
+ ZYNQ_SDIO_WP_SHIFT),
+ DEFINE_ZYNQ_PINMUX_FUNCTION_MUX(sdio1_cd, 0, 134, ZYNQ_SDIO_CD_MASK,
+ ZYNQ_SDIO_CD_SHIFT),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor, 4),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_cs1, 8),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nor_addr25, 4),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(smc0_nand, 8),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(can0, 0x10),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(can1, 0x10),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(uart0, 0x70),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(uart1, 0x70),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(i2c0, 0x20),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(i2c1, 0x20),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(ttc0, 0x60),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(ttc1, 0x60),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(swdt0, 0x30),
+ DEFINE_ZYNQ_PINMUX_FUNCTION(gpio0, 0),
+};
+
+
+/* pinctrl */
+static int zynq_pctrl_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->ngroups;
+}
+
+static const char *zynq_pctrl_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->groups[selector].name;
+}
+
+static int zynq_pctrl_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const unsigned **pins,
+ unsigned *num_pins)
+{
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = pctrl->groups[selector].pins;
+ *num_pins = pctrl->groups[selector].npins;
+
+ return 0;
+}
+
+static const struct pinctrl_ops zynq_pctrl_ops = {
+ .get_groups_count = zynq_pctrl_get_groups_count,
+ .get_group_name = zynq_pctrl_get_group_name,
+ .get_group_pins = zynq_pctrl_get_group_pins,
+ .dt_node_to_map = pinconf_generic_dt_node_to_map_all,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+/* pinmux */
+static int zynq_pmux_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->nfuncs;
+}
+
+static const char *zynq_pmux_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned selector)
+{
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->funcs[selector].name;
+}
+
+static int zynq_pmux_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ const char * const **groups,
+ unsigned * const num_groups)
+{
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctrl->funcs[selector].groups;
+ *num_groups = pctrl->funcs[selector].ngroups;
+ return 0;
+}
+
+static int zynq_pinmux_set_mux(struct pinctrl_dev *pctldev,
+ unsigned function,
+ unsigned group)
+{
+ int i, ret;
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct zynq_pctrl_group *pgrp = &pctrl->groups[group];
+ const struct zynq_pinmux_function *func = &pctrl->funcs[function];
+
+ /*
+ * SD WP & CD are special. They have dedicated registers
+ * to mux them in
+ */
+ if (function == ZYNQ_PMUX_sdio0_cd || function == ZYNQ_PMUX_sdio0_wp ||
+ function == ZYNQ_PMUX_sdio1_cd ||
+ function == ZYNQ_PMUX_sdio1_wp) {
+ u32 reg;
+
+ ret = regmap_read(pctrl->syscon,
+ pctrl->pctrl_offset + func->mux, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~func->mux_mask;
+ reg |= pgrp->pins[0] << func->mux_shift;
+ ret = regmap_write(pctrl->syscon,
+ pctrl->pctrl_offset + func->mux, reg);
+ if (ret)
+ return ret;
+ } else {
+ for (i = 0; i < pgrp->npins; i++) {
+ unsigned int pin = pgrp->pins[i];
+ u32 reg, addr = pctrl->pctrl_offset + (4 * pin);
+
+ ret = regmap_read(pctrl->syscon, addr, &reg);
+ if (ret)
+ return ret;
+
+ reg &= ~ZYNQ_PINMUX_MUX_MASK;
+ reg |= func->mux_val << ZYNQ_PINMUX_MUX_SHIFT;
+ ret = regmap_write(pctrl->syscon, addr, reg);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct pinmux_ops zynq_pinmux_ops = {
+ .get_functions_count = zynq_pmux_get_functions_count,
+ .get_function_name = zynq_pmux_get_function_name,
+ .get_function_groups = zynq_pmux_get_function_groups,
+ .set_mux = zynq_pinmux_set_mux,
+};
+
+/* pinconfig */
+#define ZYNQ_PINCONF_TRISTATE BIT(0)
+#define ZYNQ_PINCONF_SPEED BIT(8)
+#define ZYNQ_PINCONF_PULLUP BIT(12)
+#define ZYNQ_PINCONF_DISABLE_RECVR BIT(13)
+
+#define ZYNQ_PINCONF_IOTYPE_SHIFT 9
+#define ZYNQ_PINCONF_IOTYPE_MASK (7 << ZYNQ_PINCONF_IOTYPE_SHIFT)
+
+enum zynq_io_standards {
+ zynq_iostd_min,
+ zynq_iostd_lvcmos18,
+ zynq_iostd_lvcmos25,
+ zynq_iostd_lvcmos33,
+ zynq_iostd_hstl,
+ zynq_iostd_max
+};
+
+/**
+ * enum zynq_pin_config_param - possible pin configuration parameters
+ * @PIN_CONFIG_IOSTANDARD: if the pin can select an IO standard, the argument to
+ * this parameter (on a custom format) tells the driver which alternative
+ * IO standard to use.
+ */
+enum zynq_pin_config_param {
+ PIN_CONFIG_IOSTANDARD = PIN_CONFIG_END + 1,
+};
+
+static const struct pinconf_generic_params zynq_dt_params[] = {
+ {"io-standard", PIN_CONFIG_IOSTANDARD, zynq_iostd_lvcmos18},
+};
+
+#ifdef CONFIG_DEBUG_FS
+static const struct pin_config_item zynq_conf_items[ARRAY_SIZE(zynq_dt_params)] = {
+ PCONFDUMP(PIN_CONFIG_IOSTANDARD, "IO-standard", NULL, true),
+};
+#endif
+
+static unsigned int zynq_pinconf_iostd_get(u32 reg)
+{
+ return (reg & ZYNQ_PINCONF_IOTYPE_MASK) >> ZYNQ_PINCONF_IOTYPE_SHIFT;
+}
+
+static int zynq_pinconf_cfg_get(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *config)
+{
+ u32 reg;
+ int ret;
+ unsigned int arg = 0;
+ unsigned int param = pinconf_to_config_param(*config);
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ if (pin >= ZYNQ_NUM_MIOS)
+ return -ENOTSUPP;
+
+ ret = regmap_read(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), &reg);
+ if (ret)
+ return -EIO;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (!(reg & ZYNQ_PINCONF_PULLUP))
+ return -EINVAL;
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ if (!(reg & ZYNQ_PINCONF_TRISTATE))
+ return -EINVAL;
+ arg = 1;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (reg & ZYNQ_PINCONF_PULLUP || reg & ZYNQ_PINCONF_TRISTATE)
+ return -EINVAL;
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ arg = !!(reg & ZYNQ_PINCONF_SPEED);
+ break;
+ case PIN_CONFIG_LOW_POWER_MODE:
+ {
+ enum zynq_io_standards iostd = zynq_pinconf_iostd_get(reg);
+
+ if (iostd != zynq_iostd_hstl)
+ return -EINVAL;
+ if (!(reg & ZYNQ_PINCONF_DISABLE_RECVR))
+ return -EINVAL;
+ arg = !!(reg & ZYNQ_PINCONF_DISABLE_RECVR);
+ break;
+ }
+ case PIN_CONFIG_IOSTANDARD:
+ arg = zynq_pinconf_iostd_get(reg);
+ break;
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static int zynq_pinconf_cfg_set(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ unsigned long *configs,
+ unsigned num_configs)
+{
+ int i, ret;
+ u32 reg;
+ u32 pullup = 0;
+ u32 tristate = 0;
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ if (pin >= ZYNQ_NUM_MIOS)
+ return -ENOTSUPP;
+
+ ret = regmap_read(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), &reg);
+ if (ret)
+ return -EIO;
+
+ for (i = 0; i < num_configs; i++) {
+ unsigned int param = pinconf_to_config_param(configs[i]);
+ unsigned int arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_PULL_UP:
+ pullup = ZYNQ_PINCONF_PULLUP;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ tristate = ZYNQ_PINCONF_TRISTATE;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ reg &= ~(ZYNQ_PINCONF_PULLUP | ZYNQ_PINCONF_TRISTATE);
+ break;
+ case PIN_CONFIG_SLEW_RATE:
+ if (arg)
+ reg |= ZYNQ_PINCONF_SPEED;
+ else
+ reg &= ~ZYNQ_PINCONF_SPEED;
+
+ break;
+ case PIN_CONFIG_IOSTANDARD:
+ if (arg <= zynq_iostd_min || arg >= zynq_iostd_max) {
+ dev_warn(pctldev->dev,
+ "unsupported IO standard '%u'\n",
+ param);
+ break;
+ }
+ reg &= ~ZYNQ_PINCONF_IOTYPE_MASK;
+ reg |= arg << ZYNQ_PINCONF_IOTYPE_SHIFT;
+ break;
+ case PIN_CONFIG_LOW_POWER_MODE:
+ if (arg)
+ reg |= ZYNQ_PINCONF_DISABLE_RECVR;
+ else
+ reg &= ~ZYNQ_PINCONF_DISABLE_RECVR;
+
+ break;
+ default:
+ dev_warn(pctldev->dev,
+ "unsupported configuration parameter '%u'\n",
+ param);
+ continue;
+ }
+ }
+
+ if (tristate || pullup) {
+ reg &= ~(ZYNQ_PINCONF_PULLUP | ZYNQ_PINCONF_TRISTATE);
+ reg |= tristate | pullup;
+ }
+
+ ret = regmap_write(pctrl->syscon, pctrl->pctrl_offset + (4 * pin), reg);
+ if (ret)
+ return -EIO;
+
+ return 0;
+}
+
+static int zynq_pinconf_group_set(struct pinctrl_dev *pctldev,
+ unsigned selector,
+ unsigned long *configs,
+ unsigned num_configs)
+{
+ int i, ret;
+ struct zynq_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct zynq_pctrl_group *pgrp = &pctrl->groups[selector];
+
+ for (i = 0; i < pgrp->npins; i++) {
+ ret = zynq_pinconf_cfg_set(pctldev, pgrp->pins[i], configs,
+ num_configs);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops zynq_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_get = zynq_pinconf_cfg_get,
+ .pin_config_set = zynq_pinconf_cfg_set,
+ .pin_config_group_set = zynq_pinconf_group_set,
+};
+
+static struct pinctrl_desc zynq_desc = {
+ .name = "zynq_pinctrl",
+ .pins = zynq_pins,
+ .npins = ARRAY_SIZE(zynq_pins),
+ .pctlops = &zynq_pctrl_ops,
+ .pmxops = &zynq_pinmux_ops,
+ .confops = &zynq_pinconf_ops,
+ .num_custom_params = ARRAY_SIZE(zynq_dt_params),
+ .custom_params = zynq_dt_params,
+#ifdef CONFIG_DEBUG_FS
+ .custom_conf_items = zynq_conf_items,
+#endif
+ .owner = THIS_MODULE,
+};
+
+static int zynq_pinctrl_probe(struct platform_device *pdev)
+
+{
+ struct resource *res;
+ struct zynq_pinctrl *pctrl;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ pctrl->syscon = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "syscon");
+ if (IS_ERR(pctrl->syscon)) {
+ dev_err(&pdev->dev, "unable to get syscon\n");
+ return PTR_ERR(pctrl->syscon);
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "missing IO resource\n");
+ return -ENODEV;
+ }
+ pctrl->pctrl_offset = res->start;
+
+ pctrl->groups = zynq_pctrl_groups;
+ pctrl->ngroups = ARRAY_SIZE(zynq_pctrl_groups);
+ pctrl->funcs = zynq_pmux_functions;
+ pctrl->nfuncs = ARRAY_SIZE(zynq_pmux_functions);
+
+ pctrl->pctrl = pinctrl_register(&zynq_desc, &pdev->dev, pctrl);
+ if (!pctrl->pctrl)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, pctrl);
+
+ dev_info(&pdev->dev, "zynq pinctrl initialized\n");
+
+ return 0;
+}
+
+int zynq_pinctrl_remove(struct platform_device *pdev)
+{
+ struct zynq_pinctrl *pctrl = platform_get_drvdata(pdev);
+
+ pinctrl_unregister(pctrl->pctrl);
+
+ return 0;
+}
+
+static const struct of_device_id zynq_pinctrl_of_match[] = {
+ { .compatible = "xlnx,pinctrl-zynq" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, zynq_pinctrl_of_match);
+
+static struct platform_driver zynq_pinctrl_driver = {
+ .driver = {
+ .name = "zynq-pinctrl",
+ .of_match_table = zynq_pinctrl_of_match,
+ },
+ .probe = zynq_pinctrl_probe,
+ .remove = zynq_pinctrl_remove,
+};
+
+module_platform_driver(zynq_pinctrl_driver);
+
+MODULE_AUTHOR("Sören Brinkmann <soren.brinkmann@xilinx.com>");
+MODULE_DESCRIPTION("Xilinx Zynq pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 3cd243c26b7d..ea575f60f001 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -47,6 +47,14 @@ 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_MSM8916
+ tristate "Qualcomm 8916 pin controller driver"
+ depends on GPIOLIB && OF
+ select PINCTRL_MSM
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm TLMM block found on the Qualcomm 8916 platform.
+
config PINCTRL_QCOM_SPMI_PMIC
tristate "Qualcomm SPMI PMIC pin controller driver"
depends on GPIOLIB && OF && SPMI
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index bfd79af5f982..68958702917d 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -5,5 +5,6 @@ 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_MSM8916) += pinctrl-msm8916.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-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c
index ed7017df065d..a535f9c23678 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.c
+++ b/drivers/pinctrl/qcom/pinctrl-msm.c
@@ -204,21 +204,6 @@ static int msm_config_reg(struct msm_pinctrl *pctrl,
return 0;
}
-static int msm_config_get(struct pinctrl_dev *pctldev,
- unsigned int pin,
- unsigned long *config)
-{
- dev_err(pctldev->dev, "pin_config_set op not supported\n");
- return -ENOTSUPP;
-}
-
-static int msm_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
- unsigned long *configs, unsigned num_configs)
-{
- dev_err(pctldev->dev, "pin_config_set op not supported\n");
- return -ENOTSUPP;
-}
-
#define MSM_NO_PULL 0
#define MSM_PULL_DOWN 1
#define MSM_KEEPER 2
@@ -372,8 +357,6 @@ static int msm_config_group_set(struct pinctrl_dev *pctldev,
}
static const struct pinconf_ops msm_pinconf_ops = {
- .pin_config_get = msm_config_get,
- .pin_config_set = msm_config_set,
.pin_config_group_get = msm_config_group_get,
.pin_config_group_set = msm_config_group_set,
};
diff --git a/drivers/pinctrl/qcom/pinctrl-msm.h b/drivers/pinctrl/qcom/pinctrl-msm.h
index b952c4b4a8e9..54fdd04ce9d5 100644
--- a/drivers/pinctrl/qcom/pinctrl-msm.h
+++ b/drivers/pinctrl/qcom/pinctrl-msm.h
@@ -70,11 +70,11 @@ struct msm_pingroup {
unsigned *funcs;
unsigned nfuncs;
- s16 ctl_reg;
- s16 io_reg;
- s16 intr_cfg_reg;
- s16 intr_status_reg;
- s16 intr_target_reg;
+ u32 ctl_reg;
+ u32 io_reg;
+ u32 intr_cfg_reg;
+ u32 intr_status_reg;
+ u32 intr_target_reg;
unsigned mux_bit:5;
diff --git a/drivers/pinctrl/qcom/pinctrl-msm8916.c b/drivers/pinctrl/qcom/pinctrl-msm8916.c
new file mode 100644
index 000000000000..20ebf244e80d
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-msm8916.c
@@ -0,0 +1,1005 @@
+/*
+ * Copyright (c) 2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-msm.h"
+
+static const struct pinctrl_pin_desc msm8916_pins[] = {
+ PINCTRL_PIN(0, "GPIO_0"),
+ PINCTRL_PIN(1, "GPIO_1"),
+ PINCTRL_PIN(2, "GPIO_2"),
+ PINCTRL_PIN(3, "GPIO_3"),
+ PINCTRL_PIN(4, "GPIO_4"),
+ PINCTRL_PIN(5, "GPIO_5"),
+ PINCTRL_PIN(6, "GPIO_6"),
+ PINCTRL_PIN(7, "GPIO_7"),
+ PINCTRL_PIN(8, "GPIO_8"),
+ PINCTRL_PIN(9, "GPIO_9"),
+ PINCTRL_PIN(10, "GPIO_10"),
+ PINCTRL_PIN(11, "GPIO_11"),
+ PINCTRL_PIN(12, "GPIO_12"),
+ PINCTRL_PIN(13, "GPIO_13"),
+ PINCTRL_PIN(14, "GPIO_14"),
+ PINCTRL_PIN(15, "GPIO_15"),
+ PINCTRL_PIN(16, "GPIO_16"),
+ PINCTRL_PIN(17, "GPIO_17"),
+ PINCTRL_PIN(18, "GPIO_18"),
+ PINCTRL_PIN(19, "GPIO_19"),
+ PINCTRL_PIN(20, "GPIO_20"),
+ PINCTRL_PIN(21, "GPIO_21"),
+ PINCTRL_PIN(22, "GPIO_22"),
+ PINCTRL_PIN(23, "GPIO_23"),
+ PINCTRL_PIN(24, "GPIO_24"),
+ PINCTRL_PIN(25, "GPIO_25"),
+ PINCTRL_PIN(26, "GPIO_26"),
+ PINCTRL_PIN(27, "GPIO_27"),
+ PINCTRL_PIN(28, "GPIO_28"),
+ PINCTRL_PIN(29, "GPIO_29"),
+ PINCTRL_PIN(30, "GPIO_30"),
+ PINCTRL_PIN(31, "GPIO_31"),
+ PINCTRL_PIN(32, "GPIO_32"),
+ PINCTRL_PIN(33, "GPIO_33"),
+ PINCTRL_PIN(34, "GPIO_34"),
+ PINCTRL_PIN(35, "GPIO_35"),
+ PINCTRL_PIN(36, "GPIO_36"),
+ PINCTRL_PIN(37, "GPIO_37"),
+ PINCTRL_PIN(38, "GPIO_38"),
+ PINCTRL_PIN(39, "GPIO_39"),
+ PINCTRL_PIN(40, "GPIO_40"),
+ PINCTRL_PIN(41, "GPIO_41"),
+ PINCTRL_PIN(42, "GPIO_42"),
+ PINCTRL_PIN(43, "GPIO_43"),
+ PINCTRL_PIN(44, "GPIO_44"),
+ PINCTRL_PIN(45, "GPIO_45"),
+ PINCTRL_PIN(46, "GPIO_46"),
+ PINCTRL_PIN(47, "GPIO_47"),
+ PINCTRL_PIN(48, "GPIO_48"),
+ PINCTRL_PIN(49, "GPIO_49"),
+ PINCTRL_PIN(50, "GPIO_50"),
+ PINCTRL_PIN(51, "GPIO_51"),
+ PINCTRL_PIN(52, "GPIO_52"),
+ PINCTRL_PIN(53, "GPIO_53"),
+ PINCTRL_PIN(54, "GPIO_54"),
+ PINCTRL_PIN(55, "GPIO_55"),
+ PINCTRL_PIN(56, "GPIO_56"),
+ PINCTRL_PIN(57, "GPIO_57"),
+ PINCTRL_PIN(58, "GPIO_58"),
+ PINCTRL_PIN(59, "GPIO_59"),
+ PINCTRL_PIN(60, "GPIO_60"),
+ PINCTRL_PIN(61, "GPIO_61"),
+ PINCTRL_PIN(62, "GPIO_62"),
+ PINCTRL_PIN(63, "GPIO_63"),
+ PINCTRL_PIN(64, "GPIO_64"),
+ PINCTRL_PIN(65, "GPIO_65"),
+ PINCTRL_PIN(66, "GPIO_66"),
+ PINCTRL_PIN(67, "GPIO_67"),
+ PINCTRL_PIN(68, "GPIO_68"),
+ PINCTRL_PIN(69, "GPIO_69"),
+ PINCTRL_PIN(70, "GPIO_70"),
+ PINCTRL_PIN(71, "GPIO_71"),
+ PINCTRL_PIN(72, "GPIO_72"),
+ PINCTRL_PIN(73, "GPIO_73"),
+ PINCTRL_PIN(74, "GPIO_74"),
+ PINCTRL_PIN(75, "GPIO_75"),
+ PINCTRL_PIN(76, "GPIO_76"),
+ PINCTRL_PIN(77, "GPIO_77"),
+ PINCTRL_PIN(78, "GPIO_78"),
+ PINCTRL_PIN(79, "GPIO_79"),
+ PINCTRL_PIN(80, "GPIO_80"),
+ PINCTRL_PIN(81, "GPIO_81"),
+ PINCTRL_PIN(82, "GPIO_82"),
+ PINCTRL_PIN(83, "GPIO_83"),
+ PINCTRL_PIN(84, "GPIO_84"),
+ PINCTRL_PIN(85, "GPIO_85"),
+ PINCTRL_PIN(86, "GPIO_86"),
+ PINCTRL_PIN(87, "GPIO_87"),
+ PINCTRL_PIN(88, "GPIO_88"),
+ PINCTRL_PIN(89, "GPIO_89"),
+ PINCTRL_PIN(90, "GPIO_90"),
+ PINCTRL_PIN(91, "GPIO_91"),
+ PINCTRL_PIN(92, "GPIO_92"),
+ PINCTRL_PIN(93, "GPIO_93"),
+ PINCTRL_PIN(94, "GPIO_94"),
+ PINCTRL_PIN(95, "GPIO_95"),
+ PINCTRL_PIN(96, "GPIO_96"),
+ PINCTRL_PIN(97, "GPIO_97"),
+ PINCTRL_PIN(98, "GPIO_98"),
+ PINCTRL_PIN(99, "GPIO_99"),
+ PINCTRL_PIN(100, "GPIO_100"),
+ PINCTRL_PIN(101, "GPIO_101"),
+ PINCTRL_PIN(102, "GPIO_102"),
+ PINCTRL_PIN(103, "GPIO_103"),
+ PINCTRL_PIN(104, "GPIO_104"),
+ PINCTRL_PIN(105, "GPIO_105"),
+ PINCTRL_PIN(106, "GPIO_106"),
+ PINCTRL_PIN(107, "GPIO_107"),
+ PINCTRL_PIN(108, "GPIO_108"),
+ PINCTRL_PIN(109, "GPIO_109"),
+ PINCTRL_PIN(110, "GPIO_110"),
+ PINCTRL_PIN(111, "GPIO_111"),
+ PINCTRL_PIN(112, "GPIO_112"),
+ PINCTRL_PIN(113, "GPIO_113"),
+ PINCTRL_PIN(114, "GPIO_114"),
+ PINCTRL_PIN(115, "GPIO_115"),
+ PINCTRL_PIN(116, "GPIO_116"),
+ PINCTRL_PIN(117, "GPIO_117"),
+ PINCTRL_PIN(118, "GPIO_118"),
+ PINCTRL_PIN(119, "GPIO_119"),
+ PINCTRL_PIN(120, "GPIO_120"),
+ PINCTRL_PIN(121, "GPIO_121"),
+ PINCTRL_PIN(122, "SDC1_CLK"),
+ PINCTRL_PIN(123, "SDC1_CMD"),
+ PINCTRL_PIN(124, "SDC1_DATA"),
+ PINCTRL_PIN(125, "SDC2_CLK"),
+ PINCTRL_PIN(126, "SDC2_CMD"),
+ PINCTRL_PIN(127, "SDC2_DATA"),
+ PINCTRL_PIN(128, "QDSD_CLK"),
+ PINCTRL_PIN(129, "QDSD_CMD"),
+ PINCTRL_PIN(130, "QDSD_DATA0"),
+ PINCTRL_PIN(131, "QDSD_DATA1"),
+ PINCTRL_PIN(132, "QDSD_DATA2"),
+ PINCTRL_PIN(133, "QDSD_DATA3"),
+};
+
+#define DECLARE_MSM_GPIO_PINS(pin) \
+ static const unsigned int gpio##pin##_pins[] = { pin }
+
+DECLARE_MSM_GPIO_PINS(0);
+DECLARE_MSM_GPIO_PINS(1);
+DECLARE_MSM_GPIO_PINS(2);
+DECLARE_MSM_GPIO_PINS(3);
+DECLARE_MSM_GPIO_PINS(4);
+DECLARE_MSM_GPIO_PINS(5);
+DECLARE_MSM_GPIO_PINS(6);
+DECLARE_MSM_GPIO_PINS(7);
+DECLARE_MSM_GPIO_PINS(8);
+DECLARE_MSM_GPIO_PINS(9);
+DECLARE_MSM_GPIO_PINS(10);
+DECLARE_MSM_GPIO_PINS(11);
+DECLARE_MSM_GPIO_PINS(12);
+DECLARE_MSM_GPIO_PINS(13);
+DECLARE_MSM_GPIO_PINS(14);
+DECLARE_MSM_GPIO_PINS(15);
+DECLARE_MSM_GPIO_PINS(16);
+DECLARE_MSM_GPIO_PINS(17);
+DECLARE_MSM_GPIO_PINS(18);
+DECLARE_MSM_GPIO_PINS(19);
+DECLARE_MSM_GPIO_PINS(20);
+DECLARE_MSM_GPIO_PINS(21);
+DECLARE_MSM_GPIO_PINS(22);
+DECLARE_MSM_GPIO_PINS(23);
+DECLARE_MSM_GPIO_PINS(24);
+DECLARE_MSM_GPIO_PINS(25);
+DECLARE_MSM_GPIO_PINS(26);
+DECLARE_MSM_GPIO_PINS(27);
+DECLARE_MSM_GPIO_PINS(28);
+DECLARE_MSM_GPIO_PINS(29);
+DECLARE_MSM_GPIO_PINS(30);
+DECLARE_MSM_GPIO_PINS(31);
+DECLARE_MSM_GPIO_PINS(32);
+DECLARE_MSM_GPIO_PINS(33);
+DECLARE_MSM_GPIO_PINS(34);
+DECLARE_MSM_GPIO_PINS(35);
+DECLARE_MSM_GPIO_PINS(36);
+DECLARE_MSM_GPIO_PINS(37);
+DECLARE_MSM_GPIO_PINS(38);
+DECLARE_MSM_GPIO_PINS(39);
+DECLARE_MSM_GPIO_PINS(40);
+DECLARE_MSM_GPIO_PINS(41);
+DECLARE_MSM_GPIO_PINS(42);
+DECLARE_MSM_GPIO_PINS(43);
+DECLARE_MSM_GPIO_PINS(44);
+DECLARE_MSM_GPIO_PINS(45);
+DECLARE_MSM_GPIO_PINS(46);
+DECLARE_MSM_GPIO_PINS(47);
+DECLARE_MSM_GPIO_PINS(48);
+DECLARE_MSM_GPIO_PINS(49);
+DECLARE_MSM_GPIO_PINS(50);
+DECLARE_MSM_GPIO_PINS(51);
+DECLARE_MSM_GPIO_PINS(52);
+DECLARE_MSM_GPIO_PINS(53);
+DECLARE_MSM_GPIO_PINS(54);
+DECLARE_MSM_GPIO_PINS(55);
+DECLARE_MSM_GPIO_PINS(56);
+DECLARE_MSM_GPIO_PINS(57);
+DECLARE_MSM_GPIO_PINS(58);
+DECLARE_MSM_GPIO_PINS(59);
+DECLARE_MSM_GPIO_PINS(60);
+DECLARE_MSM_GPIO_PINS(61);
+DECLARE_MSM_GPIO_PINS(62);
+DECLARE_MSM_GPIO_PINS(63);
+DECLARE_MSM_GPIO_PINS(64);
+DECLARE_MSM_GPIO_PINS(65);
+DECLARE_MSM_GPIO_PINS(66);
+DECLARE_MSM_GPIO_PINS(67);
+DECLARE_MSM_GPIO_PINS(68);
+DECLARE_MSM_GPIO_PINS(69);
+DECLARE_MSM_GPIO_PINS(70);
+DECLARE_MSM_GPIO_PINS(71);
+DECLARE_MSM_GPIO_PINS(72);
+DECLARE_MSM_GPIO_PINS(73);
+DECLARE_MSM_GPIO_PINS(74);
+DECLARE_MSM_GPIO_PINS(75);
+DECLARE_MSM_GPIO_PINS(76);
+DECLARE_MSM_GPIO_PINS(77);
+DECLARE_MSM_GPIO_PINS(78);
+DECLARE_MSM_GPIO_PINS(79);
+DECLARE_MSM_GPIO_PINS(80);
+DECLARE_MSM_GPIO_PINS(81);
+DECLARE_MSM_GPIO_PINS(82);
+DECLARE_MSM_GPIO_PINS(83);
+DECLARE_MSM_GPIO_PINS(84);
+DECLARE_MSM_GPIO_PINS(85);
+DECLARE_MSM_GPIO_PINS(86);
+DECLARE_MSM_GPIO_PINS(87);
+DECLARE_MSM_GPIO_PINS(88);
+DECLARE_MSM_GPIO_PINS(89);
+DECLARE_MSM_GPIO_PINS(90);
+DECLARE_MSM_GPIO_PINS(91);
+DECLARE_MSM_GPIO_PINS(92);
+DECLARE_MSM_GPIO_PINS(93);
+DECLARE_MSM_GPIO_PINS(94);
+DECLARE_MSM_GPIO_PINS(95);
+DECLARE_MSM_GPIO_PINS(96);
+DECLARE_MSM_GPIO_PINS(97);
+DECLARE_MSM_GPIO_PINS(98);
+DECLARE_MSM_GPIO_PINS(99);
+DECLARE_MSM_GPIO_PINS(100);
+DECLARE_MSM_GPIO_PINS(101);
+DECLARE_MSM_GPIO_PINS(102);
+DECLARE_MSM_GPIO_PINS(103);
+DECLARE_MSM_GPIO_PINS(104);
+DECLARE_MSM_GPIO_PINS(105);
+DECLARE_MSM_GPIO_PINS(106);
+DECLARE_MSM_GPIO_PINS(107);
+DECLARE_MSM_GPIO_PINS(108);
+DECLARE_MSM_GPIO_PINS(109);
+DECLARE_MSM_GPIO_PINS(110);
+DECLARE_MSM_GPIO_PINS(111);
+DECLARE_MSM_GPIO_PINS(112);
+DECLARE_MSM_GPIO_PINS(113);
+DECLARE_MSM_GPIO_PINS(114);
+DECLARE_MSM_GPIO_PINS(115);
+DECLARE_MSM_GPIO_PINS(116);
+DECLARE_MSM_GPIO_PINS(117);
+DECLARE_MSM_GPIO_PINS(118);
+DECLARE_MSM_GPIO_PINS(119);
+DECLARE_MSM_GPIO_PINS(120);
+DECLARE_MSM_GPIO_PINS(121);
+
+static const unsigned int sdc1_clk_pins[] = { 122 };
+static const unsigned int sdc1_cmd_pins[] = { 123 };
+static const unsigned int sdc1_data_pins[] = { 124 };
+static const unsigned int sdc2_clk_pins[] = { 125 };
+static const unsigned int sdc2_cmd_pins[] = { 126 };
+static const unsigned int sdc2_data_pins[] = { 127 };
+static const unsigned int qdsd_clk_pins[] = { 128 };
+static const unsigned int qdsd_cmd_pins[] = { 129 };
+static const unsigned int qdsd_data0_pins[] = { 130 };
+static const unsigned int qdsd_data1_pins[] = { 131 };
+static const unsigned int qdsd_data2_pins[] = { 132 };
+static const unsigned int qdsd_data3_pins[] = { 133 };
+
+#define FUNCTION(fname) \
+ [MSM_MUX_##fname] = { \
+ .name = #fname, \
+ .groups = fname##_groups, \
+ .ngroups = ARRAY_SIZE(fname##_groups), \
+ }
+
+#define PINGROUP(id, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
+ { \
+ .name = "gpio" #id, \
+ .pins = gpio##id##_pins, \
+ .npins = ARRAY_SIZE(gpio##id##_pins), \
+ .funcs = (int[]){ \
+ MSM_MUX_gpio, \
+ MSM_MUX_##f1, \
+ MSM_MUX_##f2, \
+ MSM_MUX_##f3, \
+ MSM_MUX_##f4, \
+ MSM_MUX_##f5, \
+ MSM_MUX_##f6, \
+ MSM_MUX_##f7, \
+ MSM_MUX_##f8, \
+ MSM_MUX_##f9 \
+ }, \
+ .nfuncs = 10, \
+ .ctl_reg = 0x1000 * id, \
+ .io_reg = 0x4 + 0x1000 * id, \
+ .intr_cfg_reg = 0x8 + 0x1000 * id, \
+ .intr_status_reg = 0xc + 0x1000 * id, \
+ .intr_target_reg = 0x8 + 0x1000 * id, \
+ .mux_bit = 2, \
+ .pull_bit = 0, \
+ .drv_bit = 6, \
+ .oe_bit = 9, \
+ .in_bit = 0, \
+ .out_bit = 1, \
+ .intr_enable_bit = 0, \
+ .intr_status_bit = 0, \
+ .intr_target_bit = 5, \
+ .intr_target_kpss_val = 4, \
+ .intr_raw_status_bit = 4, \
+ .intr_polarity_bit = 1, \
+ .intr_detection_bit = 2, \
+ .intr_detection_width = 2, \
+ }
+
+#define SDC_PINGROUP(pg_name, ctl, pull, drv) \
+ { \
+ .name = #pg_name, \
+ .pins = pg_name##_pins, \
+ .npins = ARRAY_SIZE(pg_name##_pins), \
+ .ctl_reg = ctl, \
+ .io_reg = 0, \
+ .intr_cfg_reg = 0, \
+ .intr_status_reg = 0, \
+ .intr_target_reg = 0, \
+ .mux_bit = -1, \
+ .pull_bit = pull, \
+ .drv_bit = drv, \
+ .oe_bit = -1, \
+ .in_bit = -1, \
+ .out_bit = -1, \
+ .intr_enable_bit = -1, \
+ .intr_status_bit = -1, \
+ .intr_target_bit = -1, \
+ .intr_target_kpss_val = -1, \
+ .intr_raw_status_bit = -1, \
+ .intr_polarity_bit = -1, \
+ .intr_detection_bit = -1, \
+ .intr_detection_width = -1, \
+ }
+
+enum msm8916_functions {
+ MSM_MUX_adsp_ext,
+ MSM_MUX_alsp_int,
+ MSM_MUX_atest_bbrx0,
+ MSM_MUX_atest_bbrx1,
+ MSM_MUX_atest_char,
+ MSM_MUX_atest_char0,
+ MSM_MUX_atest_char1,
+ MSM_MUX_atest_char2,
+ MSM_MUX_atest_char3,
+ MSM_MUX_atest_combodac,
+ MSM_MUX_atest_gpsadc0,
+ MSM_MUX_atest_gpsadc1,
+ MSM_MUX_atest_tsens,
+ MSM_MUX_atest_wlan0,
+ MSM_MUX_atest_wlan1,
+ MSM_MUX_backlight_en,
+ MSM_MUX_bimc_dte0,
+ MSM_MUX_bimc_dte1,
+ MSM_MUX_blsp_i2c1,
+ MSM_MUX_blsp_i2c2,
+ MSM_MUX_blsp_i2c3,
+ MSM_MUX_blsp_i2c4,
+ MSM_MUX_blsp_i2c5,
+ MSM_MUX_blsp_i2c6,
+ MSM_MUX_blsp_spi1,
+ MSM_MUX_blsp_spi1_cs1,
+ MSM_MUX_blsp_spi1_cs2,
+ MSM_MUX_blsp_spi1_cs3,
+ MSM_MUX_blsp_spi2,
+ MSM_MUX_blsp_spi2_cs1,
+ MSM_MUX_blsp_spi2_cs2,
+ MSM_MUX_blsp_spi2_cs3,
+ MSM_MUX_blsp_spi3,
+ MSM_MUX_blsp_spi3_cs1,
+ MSM_MUX_blsp_spi3_cs2,
+ MSM_MUX_blsp_spi3_cs3,
+ MSM_MUX_blsp_spi4,
+ MSM_MUX_blsp_spi5,
+ MSM_MUX_blsp_spi6,
+ MSM_MUX_blsp_uart1,
+ MSM_MUX_blsp_uart2,
+ MSM_MUX_blsp_uim1,
+ MSM_MUX_blsp_uim2,
+ MSM_MUX_cam1_rst,
+ MSM_MUX_cam1_standby,
+ MSM_MUX_cam_mclk0,
+ MSM_MUX_cam_mclk1,
+ MSM_MUX_cci_async,
+ MSM_MUX_cci_i2c,
+ MSM_MUX_cci_timer0,
+ MSM_MUX_cci_timer1,
+ MSM_MUX_cci_timer2,
+ MSM_MUX_cdc_pdm0,
+ MSM_MUX_codec_mad,
+ MSM_MUX_dbg_out,
+ MSM_MUX_display_5v,
+ MSM_MUX_dmic0_clk,
+ MSM_MUX_dmic0_data,
+ MSM_MUX_dsi_rst,
+ MSM_MUX_ebi0_wrcdc,
+ MSM_MUX_euro_us,
+ MSM_MUX_ext_lpass,
+ MSM_MUX_flash_strobe,
+ MSM_MUX_gcc_gp1_clk_a,
+ MSM_MUX_gcc_gp1_clk_b,
+ MSM_MUX_gcc_gp2_clk_a,
+ MSM_MUX_gcc_gp2_clk_b,
+ MSM_MUX_gcc_gp3_clk_a,
+ MSM_MUX_gcc_gp3_clk_b,
+ MSM_MUX_gpio,
+ MSM_MUX_gsm0_tx0,
+ MSM_MUX_gsm0_tx1,
+ MSM_MUX_gsm1_tx0,
+ MSM_MUX_gsm1_tx1,
+ MSM_MUX_gyro_accl,
+ MSM_MUX_kpsns0,
+ MSM_MUX_kpsns1,
+ MSM_MUX_kpsns2,
+ MSM_MUX_ldo_en,
+ MSM_MUX_ldo_update,
+ MSM_MUX_mag_int,
+ MSM_MUX_mdp_vsync,
+ MSM_MUX_modem_tsync,
+ MSM_MUX_m_voc,
+ MSM_MUX_nav_pps,
+ MSM_MUX_nav_tsync,
+ MSM_MUX_pa_indicator,
+ MSM_MUX_pbs0,
+ MSM_MUX_pbs1,
+ MSM_MUX_pbs2,
+ MSM_MUX_pri_mi2s,
+ MSM_MUX_pri_mi2s_ws,
+ MSM_MUX_prng_rosc,
+ MSM_MUX_pwr_crypto_enabled_a,
+ MSM_MUX_pwr_crypto_enabled_b,
+ MSM_MUX_pwr_modem_enabled_a,
+ MSM_MUX_pwr_modem_enabled_b,
+ MSM_MUX_pwr_nav_enabled_a,
+ MSM_MUX_pwr_nav_enabled_b,
+ MSM_MUX_qdss_ctitrig_in_a0,
+ MSM_MUX_qdss_ctitrig_in_a1,
+ MSM_MUX_qdss_ctitrig_in_b0,
+ MSM_MUX_qdss_ctitrig_in_b1,
+ MSM_MUX_qdss_ctitrig_out_a0,
+ MSM_MUX_qdss_ctitrig_out_a1,
+ MSM_MUX_qdss_ctitrig_out_b0,
+ MSM_MUX_qdss_ctitrig_out_b1,
+ MSM_MUX_qdss_traceclk_a,
+ MSM_MUX_qdss_traceclk_b,
+ MSM_MUX_qdss_tracectl_a,
+ MSM_MUX_qdss_tracectl_b,
+ MSM_MUX_qdss_tracedata_a,
+ MSM_MUX_qdss_tracedata_b,
+ MSM_MUX_reset_n,
+ MSM_MUX_sd_card,
+ MSM_MUX_sd_write,
+ MSM_MUX_sec_mi2s,
+ MSM_MUX_smb_int,
+ MSM_MUX_ssbi_wtr0,
+ MSM_MUX_ssbi_wtr1,
+ MSM_MUX_uim1,
+ MSM_MUX_uim2,
+ MSM_MUX_uim3,
+ MSM_MUX_uim_batt,
+ MSM_MUX_wcss_bt,
+ MSM_MUX_wcss_fm,
+ MSM_MUX_wcss_wlan,
+ MSM_MUX_webcam1_rst,
+ MSM_MUX_NA,
+};
+
+static const char * const gpio_groups[] = {
+ "gpio0", "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", "gpio37", "gpio38", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio44", "gpio45", "gpio46", "gpio47", "gpio48", "gpio49",
+ "gpio50", "gpio51", "gpio52", "gpio53", "gpio54", "gpio55", "gpio56",
+ "gpio57", "gpio58", "gpio59", "gpio60", "gpio61", "gpio62", "gpio63",
+ "gpio64", "gpio65", "gpio66", "gpio67", "gpio68", "gpio69", "gpio70",
+ "gpio71", "gpio72", "gpio73", "gpio74", "gpio75", "gpio76", "gpio77",
+ "gpio78", "gpio79", "gpio80", "gpio81", "gpio82", "gpio83", "gpio84",
+ "gpio85", "gpio86", "gpio87", "gpio88", "gpio89", "gpio90", "gpio91",
+ "gpio92", "gpio93", "gpio94", "gpio95", "gpio96", "gpio97", "gpio98",
+ "gpio99", "gpio100", "gpio101", "gpio102", "gpio103", "gpio104",
+ "gpio105", "gpio106", "gpio107", "gpio108", "gpio109", "gpio110",
+ "gpio111", "gpio112", "gpio113", "gpio114", "gpio115", "gpio116",
+ "gpio117", "gpio118", "gpio119", "gpio120", "gpio121"
+};
+static const char * const adsp_ext_groups[] = { "gpio38" };
+static const char * const alsp_int_groups[] = { "gpio113" };
+static const char * const atest_bbrx0_groups[] = { "gpio17" };
+static const char * const atest_bbrx1_groups[] = { "gpio16" };
+static const char * const atest_char_groups[] = { "gpio62" };
+static const char * const atest_char0_groups[] = { "gpio60" };
+static const char * const atest_char1_groups[] = { "gpio59" };
+static const char * const atest_char2_groups[] = { "gpio58" };
+static const char * const atest_char3_groups[] = { "gpio57" };
+static const char * const atest_combodac_groups[] = {
+ "gpio4", "gpio12", "gpio13", "gpio20", "gpio21", "gpio28", "gpio29",
+ "gpio30", "gpio39", "gpio40", "gpio41", "gpio42", "gpio43", "gpio44",
+ "gpio45", "gpio46", "gpio47", "gpio48", "gpio69", "gpio107"
+};
+static const char * const atest_gpsadc0_groups[] = { "gpio7" };
+static const char * const atest_gpsadc1_groups[] = { "gpio18" };
+static const char * const atest_tsens_groups[] = { "gpio112" };
+static const char * const atest_wlan0_groups[] = { "gpio22" };
+static const char * const atest_wlan1_groups[] = { "gpio23" };
+static const char * const backlight_en_groups[] = { "gpio98" };
+static const char * const bimc_dte0_groups[] = { "gpio63", "gpio65" };
+static const char * const bimc_dte1_groups[] = { "gpio64", "gpio66" };
+static const char * const blsp_i2c1_groups[] = { "gpio2", "gpio3" };
+static const char * const blsp_i2c2_groups[] = { "gpio6", "gpio7" };
+static const char * const blsp_i2c3_groups[] = { "gpio10", "gpio11" };
+static const char * const blsp_i2c4_groups[] = { "gpio14", "gpio15" };
+static const char * const blsp_i2c5_groups[] = { "gpio18", "gpio19" };
+static const char * const blsp_i2c6_groups[] = { "gpio22", "gpio23" };
+static const char * const blsp_spi1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3"
+};
+static const char * const blsp_spi1_cs1_groups[] = { "gpio110" };
+static const char * const blsp_spi1_cs2_groups[] = { "gpio16" };
+static const char * const blsp_spi1_cs3_groups[] = { "gpio4" };
+static const char * const blsp_spi2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7"
+};
+static const char * const blsp_spi2_cs1_groups[] = { "gpio121" };
+static const char * const blsp_spi2_cs2_groups[] = { "gpio17" };
+static const char * const blsp_spi2_cs3_groups[] = { "gpio5" };
+static const char * const blsp_spi3_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio11"
+};
+static const char * const blsp_spi3_cs1_groups[] = { "gpio120" };
+static const char * const blsp_spi3_cs2_groups[] = { "gpio37" };
+static const char * const blsp_spi3_cs3_groups[] = { "gpio69" };
+static const char * const blsp_spi4_groups[] = {
+ "gpio12", "gpio13", "gpio14", "gpio15"
+};
+static const char * const blsp_spi5_groups[] = {
+ "gpio16", "gpio17", "gpio18", "gpio19"
+};
+static const char * const blsp_spi6_groups[] = {
+ "gpio20", "gpio21", "gpio22", "gpio23"
+};
+static const char * const blsp_uart1_groups[] = {
+ "gpio0", "gpio1", "gpio2", "gpio3"
+};
+static const char * const blsp_uart2_groups[] = {
+ "gpio4", "gpio5", "gpio6", "gpio7"
+};
+static const char * const blsp_uim1_groups[] = { "gpio0", "gpio1" };
+static const char * const blsp_uim2_groups[] = { "gpio4", "gpio5" };
+static const char * const cam1_rst_groups[] = { "gpio35" };
+static const char * const cam1_standby_groups[] = { "gpio34" };
+static const char * const cam_mclk0_groups[] = { "gpio26" };
+static const char * const cam_mclk1_groups[] = { "gpio27" };
+static const char * const cci_async_groups[] = { "gpio33" };
+static const char * const cci_i2c_groups[] = { "gpio29", "gpio30" };
+static const char * const cci_timer0_groups[] = { "gpio31" };
+static const char * const cci_timer1_groups[] = { "gpio32" };
+static const char * const cci_timer2_groups[] = { "gpio38" };
+static const char * const cdc_pdm0_groups[] = {
+ "gpio63", "gpio64", "gpio65", "gpio66", "gpio67", "gpio68"
+};
+static const char * const codec_mad_groups[] = { "gpio16" };
+static const char * const dbg_out_groups[] = { "gpio47" };
+static const char * const display_5v_groups[] = { "gpio97" };
+static const char * const dmic0_clk_groups[] = { "gpio0" };
+static const char * const dmic0_data_groups[] = { "gpio1" };
+static const char * const dsi_rst_groups[] = { "gpio25" };
+static const char * const ebi0_wrcdc_groups[] = { "gpio67" };
+static const char * const euro_us_groups[] = { "gpio120" };
+static const char * const ext_lpass_groups[] = { "gpio45" };
+static const char * const flash_strobe_groups[] = { "gpio31", "gpio32" };
+static const char * const gcc_gp1_clk_a_groups[] = { "gpio49" };
+static const char * const gcc_gp1_clk_b_groups[] = { "gpio97" };
+static const char * const gcc_gp2_clk_a_groups[] = { "gpio50" };
+static const char * const gcc_gp2_clk_b_groups[] = { "gpio12" };
+static const char * const gcc_gp3_clk_a_groups[] = { "gpio51" };
+static const char * const gcc_gp3_clk_b_groups[] = { "gpio13" };
+static const char * const gsm0_tx0_groups[] = { "gpio99" };
+static const char * const gsm0_tx1_groups[] = { "gpio100" };
+static const char * const gsm1_tx0_groups[] = { "gpio101" };
+static const char * const gsm1_tx1_groups[] = { "gpio102" };
+static const char * const gyro_accl_groups[] = {"gpio115" };
+static const char * const kpsns0_groups[] = { "gpio107" };
+static const char * const kpsns1_groups[] = { "gpio108" };
+static const char * const kpsns2_groups[] = { "gpio109" };
+static const char * const ldo_en_groups[] = { "gpio121" };
+static const char * const ldo_update_groups[] = { "gpio120" };
+static const char * const mag_int_groups[] = { "gpio69" };
+static const char * const mdp_vsync_groups[] = { "gpio24", "gpio25" };
+static const char * const modem_tsync_groups[] = { "gpio95" };
+static const char * const m_voc_groups[] = { "gpio8", "gpio119" };
+static const char * const nav_pps_groups[] = { "gpio95" };
+static const char * const nav_tsync_groups[] = { "gpio95" };
+static const char * const pa_indicator_groups[] = { "gpio86" };
+static const char * const pbs0_groups[] = { "gpio107" };
+static const char * const pbs1_groups[] = { "gpio108" };
+static const char * const pbs2_groups[] = { "gpio109" };
+static const char * const pri_mi2s_groups[] = {
+ "gpio113", "gpio114", "gpio115", "gpio116"
+};
+static const char * const pri_mi2s_ws_groups[] = { "gpio110" };
+static const char * const prng_rosc_groups[] = { "gpio43" };
+static const char * const pwr_crypto_enabled_a_groups[] = { "gpio35" };
+static const char * const pwr_crypto_enabled_b_groups[] = { "gpio115" };
+static const char * const pwr_modem_enabled_a_groups[] = { "gpio28" };
+static const char * const pwr_modem_enabled_b_groups[] = { "gpio113" };
+static const char * const pwr_nav_enabled_a_groups[] = { "gpio34" };
+static const char * const pwr_nav_enabled_b_groups[] = { "gpio114" };
+static const char * const qdss_ctitrig_in_a0_groups[] = { "gpio20" };
+static const char * const qdss_ctitrig_in_a1_groups[] = { "gpio49" };
+static const char * const qdss_ctitrig_in_b0_groups[] = { "gpio21" };
+static const char * const qdss_ctitrig_in_b1_groups[] = { "gpio50" };
+static const char * const qdss_ctitrig_out_a0_groups[] = { "gpio23" };
+static const char * const qdss_ctitrig_out_a1_groups[] = { "gpio52" };
+static const char * const qdss_ctitrig_out_b0_groups[] = { "gpio22" };
+static const char * const qdss_ctitrig_out_b1_groups[] = { "gpio51" };
+static const char * const qdss_traceclk_a_groups[] = { "gpio46" };
+static const char * const qdss_traceclk_b_groups[] = { "gpio5" };
+static const char * const qdss_tracectl_a_groups[] = { "gpio45" };
+static const char * const qdss_tracectl_b_groups[] = { "gpio4" };
+static const char * const qdss_tracedata_a_groups[] = {
+ "gpio8", "gpio9", "gpio10", "gpio39", "gpio40", "gpio41", "gpio42",
+ "gpio43", "gpio47", "gpio48", "gpio62", "gpio69", "gpio112", "gpio113",
+ "gpio114", "gpio115"
+};
+static const char * const qdss_tracedata_b_groups[] = {
+ "gpio26", "gpio27", "gpio28", "gpio29", "gpio30", "gpio31", "gpio32",
+ "gpio33", "gpio34", "gpio35", "gpio36", "gpio37", "gpio110", "gpio111",
+ "gpio120", "gpio121"
+};
+static const char * const reset_n_groups[] = { "gpio36" };
+static const char * const sd_card_groups[] = { "gpio38" };
+static const char * const sd_write_groups[] = { "gpio121" };
+static const char * const sec_mi2s_groups[] = {
+ "gpio112", "gpio117", "gpio118", "gpio119"
+};
+static const char * const smb_int_groups[] = { "gpio62" };
+static const char * const ssbi_wtr0_groups[] = { "gpio103", "gpio104" };
+static const char * const ssbi_wtr1_groups[] = { "gpio105", "gpio106" };
+static const char * const uim1_groups[] = {
+ "gpio57", "gpio58", "gpio59", "gpio60"
+};
+
+static const char * const uim2_groups[] = {
+ "gpio53", "gpio54", "gpio55", "gpio56"
+};
+static const char * const uim3_groups[] = {
+ "gpio49", "gpio50", "gpio51", "gpio52"
+};
+static const char * const uim_batt_groups[] = { "gpio61" };
+static const char * const wcss_bt_groups[] = { "gpio39", "gpio47", "gpio48" };
+static const char * const wcss_fm_groups[] = { "gpio45", "gpio46" };
+static const char * const wcss_wlan_groups[] = {
+ "gpio40", "gpio41", "gpio42", "gpio43", "gpio44"
+};
+static const char * const webcam1_rst_groups[] = { "gpio28" };
+
+static const struct msm_function msm8916_functions[] = {
+ FUNCTION(adsp_ext),
+ FUNCTION(alsp_int),
+ FUNCTION(atest_bbrx0),
+ FUNCTION(atest_bbrx1),
+ FUNCTION(atest_char),
+ FUNCTION(atest_char0),
+ FUNCTION(atest_char1),
+ FUNCTION(atest_char2),
+ FUNCTION(atest_char3),
+ FUNCTION(atest_combodac),
+ FUNCTION(atest_gpsadc0),
+ FUNCTION(atest_gpsadc1),
+ FUNCTION(atest_tsens),
+ FUNCTION(atest_wlan0),
+ FUNCTION(atest_wlan1),
+ FUNCTION(backlight_en),
+ FUNCTION(bimc_dte0),
+ FUNCTION(bimc_dte1),
+ FUNCTION(blsp_i2c1),
+ FUNCTION(blsp_i2c2),
+ FUNCTION(blsp_i2c3),
+ FUNCTION(blsp_i2c4),
+ FUNCTION(blsp_i2c5),
+ FUNCTION(blsp_i2c6),
+ FUNCTION(blsp_spi1),
+ FUNCTION(blsp_spi1_cs1),
+ FUNCTION(blsp_spi1_cs2),
+ FUNCTION(blsp_spi1_cs3),
+ FUNCTION(blsp_spi2),
+ FUNCTION(blsp_spi2_cs1),
+ FUNCTION(blsp_spi2_cs2),
+ FUNCTION(blsp_spi2_cs3),
+ FUNCTION(blsp_spi3),
+ FUNCTION(blsp_spi3_cs1),
+ FUNCTION(blsp_spi3_cs2),
+ FUNCTION(blsp_spi3_cs3),
+ FUNCTION(blsp_spi4),
+ FUNCTION(blsp_spi5),
+ FUNCTION(blsp_spi6),
+ FUNCTION(blsp_uart1),
+ FUNCTION(blsp_uart2),
+ FUNCTION(blsp_uim1),
+ FUNCTION(blsp_uim2),
+ FUNCTION(cam1_rst),
+ FUNCTION(cam1_standby),
+ FUNCTION(cam_mclk0),
+ FUNCTION(cam_mclk1),
+ FUNCTION(cci_async),
+ FUNCTION(cci_i2c),
+ FUNCTION(cci_timer0),
+ FUNCTION(cci_timer1),
+ FUNCTION(cci_timer2),
+ FUNCTION(cdc_pdm0),
+ FUNCTION(codec_mad),
+ FUNCTION(dbg_out),
+ FUNCTION(display_5v),
+ FUNCTION(dmic0_clk),
+ FUNCTION(dmic0_data),
+ FUNCTION(dsi_rst),
+ FUNCTION(ebi0_wrcdc),
+ FUNCTION(euro_us),
+ FUNCTION(ext_lpass),
+ FUNCTION(flash_strobe),
+ FUNCTION(gcc_gp1_clk_a),
+ FUNCTION(gcc_gp1_clk_b),
+ FUNCTION(gcc_gp2_clk_a),
+ FUNCTION(gcc_gp2_clk_b),
+ FUNCTION(gcc_gp3_clk_a),
+ FUNCTION(gcc_gp3_clk_b),
+ FUNCTION(gpio),
+ FUNCTION(gsm0_tx0),
+ FUNCTION(gsm0_tx1),
+ FUNCTION(gsm1_tx0),
+ FUNCTION(gsm1_tx1),
+ FUNCTION(gyro_accl),
+ FUNCTION(kpsns0),
+ FUNCTION(kpsns1),
+ FUNCTION(kpsns2),
+ FUNCTION(ldo_en),
+ FUNCTION(ldo_update),
+ FUNCTION(mag_int),
+ FUNCTION(mdp_vsync),
+ FUNCTION(modem_tsync),
+ FUNCTION(m_voc),
+ FUNCTION(nav_pps),
+ FUNCTION(nav_tsync),
+ FUNCTION(pa_indicator),
+ FUNCTION(pbs0),
+ FUNCTION(pbs1),
+ FUNCTION(pbs2),
+ FUNCTION(pri_mi2s),
+ FUNCTION(pri_mi2s_ws),
+ FUNCTION(prng_rosc),
+ FUNCTION(pwr_crypto_enabled_a),
+ FUNCTION(pwr_crypto_enabled_b),
+ FUNCTION(pwr_modem_enabled_a),
+ FUNCTION(pwr_modem_enabled_b),
+ FUNCTION(pwr_nav_enabled_a),
+ FUNCTION(pwr_nav_enabled_b),
+ FUNCTION(qdss_ctitrig_in_a0),
+ FUNCTION(qdss_ctitrig_in_a1),
+ FUNCTION(qdss_ctitrig_in_b0),
+ FUNCTION(qdss_ctitrig_in_b1),
+ FUNCTION(qdss_ctitrig_out_a0),
+ FUNCTION(qdss_ctitrig_out_a1),
+ FUNCTION(qdss_ctitrig_out_b0),
+ FUNCTION(qdss_ctitrig_out_b1),
+ FUNCTION(qdss_traceclk_a),
+ FUNCTION(qdss_traceclk_b),
+ FUNCTION(qdss_tracectl_a),
+ FUNCTION(qdss_tracectl_b),
+ FUNCTION(qdss_tracedata_a),
+ FUNCTION(qdss_tracedata_b),
+ FUNCTION(reset_n),
+ FUNCTION(sd_card),
+ FUNCTION(sd_write),
+ FUNCTION(sec_mi2s),
+ FUNCTION(smb_int),
+ FUNCTION(ssbi_wtr0),
+ FUNCTION(ssbi_wtr1),
+ FUNCTION(uim1),
+ FUNCTION(uim2),
+ FUNCTION(uim3),
+ FUNCTION(uim_batt),
+ FUNCTION(wcss_bt),
+ FUNCTION(wcss_fm),
+ FUNCTION(wcss_wlan),
+ FUNCTION(webcam1_rst)
+};
+
+static const struct msm_pingroup msm8916_groups[] = {
+ PINGROUP(0, blsp_spi1, blsp_uart1, blsp_uim1, dmic0_clk, NA, NA, NA, NA, NA),
+ PINGROUP(1, blsp_spi1, blsp_uart1, blsp_uim1, dmic0_data, NA, NA, NA, NA, NA),
+ PINGROUP(2, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(3, blsp_spi1, blsp_uart1, blsp_i2c1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(4, blsp_spi2, blsp_uart2, blsp_uim2, blsp_spi1_cs3, qdss_tracectl_b, NA, atest_combodac, NA, NA),
+ PINGROUP(5, blsp_spi2, blsp_uart2, blsp_uim2, blsp_spi2_cs3, qdss_traceclk_b, NA, NA, NA, NA),
+ PINGROUP(6, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA),
+ PINGROUP(7, blsp_spi2, blsp_uart2, blsp_i2c2, NA, NA, NA, NA, NA, NA),
+ PINGROUP(8, blsp_spi3, m_voc, qdss_tracedata_a, NA, NA, NA, NA, NA, NA),
+ PINGROUP(9, blsp_spi3, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(10, blsp_spi3, blsp_i2c3, qdss_tracedata_a, NA, NA, NA, NA, NA, NA),
+ PINGROUP(11, blsp_spi3, blsp_i2c3, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(12, blsp_spi4, gcc_gp2_clk_b, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(13, blsp_spi4, gcc_gp3_clk_b, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(14, blsp_spi4, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(15, blsp_spi4, blsp_i2c4, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(16, blsp_spi5, blsp_spi1_cs2, NA, atest_bbrx1, NA, NA, NA, NA, NA),
+ PINGROUP(17, blsp_spi5, blsp_spi2_cs2, NA, atest_bbrx0, NA, NA, NA, NA, NA),
+ PINGROUP(18, blsp_spi5, blsp_i2c5, NA, atest_gpsadc1, NA, NA, NA, NA, NA),
+ PINGROUP(19, blsp_spi5, blsp_i2c5, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(20, blsp_spi6, NA, NA, NA, NA, NA, NA, qdss_ctitrig_in_a0, NA),
+ PINGROUP(21, blsp_spi6, NA, NA, NA, NA, NA, NA, qdss_ctitrig_in_b0, NA),
+ PINGROUP(22, blsp_spi6, blsp_i2c6, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(23, blsp_spi6, blsp_i2c6, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(24, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(25, mdp_vsync, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(26, cam_mclk0, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+ PINGROUP(27, cam_mclk1, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
+ PINGROUP(28, pwr_modem_enabled_a, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac),
+ PINGROUP(29, cci_i2c, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, atest_combodac),
+ PINGROUP(30, cci_i2c, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
+ PINGROUP(31, cci_timer0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(32, cci_timer1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(33, cci_async, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
+ PINGROUP(34, pwr_nav_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
+ PINGROUP(35, pwr_crypto_enabled_a, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b),
+ PINGROUP(36, NA, NA, NA, NA, NA, NA, NA, qdss_tracedata_b, NA),
+ PINGROUP(37, blsp_spi3_cs2, NA, NA, NA, NA, NA, qdss_tracedata_b, NA, NA),
+ PINGROUP(38, cci_timer2, adsp_ext, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(39, wcss_bt, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(40, wcss_wlan, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(41, wcss_wlan, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(42, wcss_wlan, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(43, wcss_wlan, prng_rosc, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA),
+ PINGROUP(44, wcss_wlan, NA, atest_combodac, NA, NA, NA, NA, NA, NA),
+ PINGROUP(45, wcss_fm, ext_lpass, qdss_tracectl_a, NA, atest_combodac, NA, NA, NA, NA),
+ PINGROUP(46, wcss_fm, qdss_traceclk_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(47, wcss_bt, dbg_out, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA),
+ PINGROUP(48, wcss_bt, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(49, uim3, gcc_gp1_clk_a, qdss_ctitrig_in_a1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(50, uim3, gcc_gp2_clk_a, qdss_ctitrig_in_b1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(51, uim3, gcc_gp3_clk_a, qdss_ctitrig_out_b1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(52, uim3, NA, qdss_ctitrig_out_a1, NA, NA, NA, NA, NA, NA),
+ PINGROUP(53, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(54, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(55, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(56, uim2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(57, uim1, atest_char3, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(58, uim1, atest_char2, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(59, uim1, atest_char1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(60, uim1, atest_char0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(61, uim_batt, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(62, atest_char, qdss_tracedata_a, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(63, cdc_pdm0, bimc_dte0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(64, cdc_pdm0, bimc_dte1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(65, cdc_pdm0, bimc_dte0, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(66, cdc_pdm0, bimc_dte1, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(67, cdc_pdm0, ebi0_wrcdc, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(68, cdc_pdm0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(69, blsp_spi3_cs3, qdss_tracedata_a, NA, atest_combodac, NA, NA, NA, NA, NA),
+ PINGROUP(70, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(71, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(72, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(73, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(74, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(75, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(76, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(77, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(78, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(79, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(80, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(81, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(82, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(83, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(84, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(85, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(86, NA, pa_indicator, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(87, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(88, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(89, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(90, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(91, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(92, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(93, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(94, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(95, NA, modem_tsync, nav_tsync, nav_pps, NA, NA, NA, NA, NA),
+ PINGROUP(96, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(97, gcc_gp1_clk_b, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(98, NA, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(99, gsm0_tx0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(100, gsm0_tx1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(101, gsm1_tx0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(102, gsm1_tx1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(103, ssbi_wtr0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(104, ssbi_wtr0, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(105, ssbi_wtr1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(106, ssbi_wtr1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(107, pbs0, NA, atest_combodac, NA, NA, NA, NA, NA, NA),
+ PINGROUP(108, pbs1, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(109, pbs2, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(110, blsp_spi1_cs1, pri_mi2s_ws, NA, qdss_tracedata_b, NA, NA, NA, NA, NA),
+ PINGROUP(111, qdss_tracedata_b, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(112, sec_mi2s, NA, NA, NA, qdss_tracedata_a, NA, atest_tsens, NA, NA),
+ PINGROUP(113, pri_mi2s, NA, pwr_modem_enabled_b, NA, NA, NA, NA, NA, qdss_tracedata_a),
+ PINGROUP(114, pri_mi2s, pwr_nav_enabled_b, NA, NA, NA, NA, NA, qdss_tracedata_a, NA),
+ PINGROUP(115, pri_mi2s, pwr_crypto_enabled_b, NA, NA, NA, NA, NA, qdss_tracedata_a, NA),
+ PINGROUP(116, pri_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(117, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(118, sec_mi2s, NA, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(119, sec_mi2s, m_voc, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(120, blsp_spi3_cs1, ldo_update, NA, NA, NA, NA, NA, NA, NA),
+ PINGROUP(121, sd_write, blsp_spi2_cs1, ldo_en, NA, NA, NA, NA, NA, NA),
+ SDC_PINGROUP(sdc1_clk, 0x10a000, 13, 6),
+ SDC_PINGROUP(sdc1_cmd, 0x10a000, 11, 3),
+ SDC_PINGROUP(sdc1_data, 0x10a000, 9, 0),
+ SDC_PINGROUP(sdc2_clk, 0x109000, 14, 6),
+ SDC_PINGROUP(sdc2_cmd, 0x109000, 11, 3),
+ SDC_PINGROUP(sdc2_data, 0x109000, 9, 0),
+ SDC_PINGROUP(qdsd_clk, 0x19c000, 3, 0),
+ SDC_PINGROUP(qdsd_cmd, 0x19c000, 8, 5),
+ SDC_PINGROUP(qdsd_data0, 0x19c000, 13, 10),
+ SDC_PINGROUP(qdsd_data1, 0x19c000, 18, 15),
+ SDC_PINGROUP(qdsd_data2, 0x19c000, 23, 20),
+ SDC_PINGROUP(qdsd_data3, 0x19c000, 28, 25),
+};
+
+#define NUM_GPIO_PINGROUPS 122
+
+static const struct msm_pinctrl_soc_data msm8916_pinctrl = {
+ .pins = msm8916_pins,
+ .npins = ARRAY_SIZE(msm8916_pins),
+ .functions = msm8916_functions,
+ .nfunctions = ARRAY_SIZE(msm8916_functions),
+ .groups = msm8916_groups,
+ .ngroups = ARRAY_SIZE(msm8916_groups),
+ .ngpios = NUM_GPIO_PINGROUPS,
+};
+
+static int msm8916_pinctrl_probe(struct platform_device *pdev)
+{
+ return msm_pinctrl_probe(pdev, &msm8916_pinctrl);
+}
+
+static const struct of_device_id msm8916_pinctrl_of_match[] = {
+ { .compatible = "qcom,msm8916-pinctrl", },
+ { },
+};
+
+static struct platform_driver msm8916_pinctrl_driver = {
+ .driver = {
+ .name = "msm8916-pinctrl",
+ .of_match_table = msm8916_pinctrl_of_match,
+ },
+ .probe = msm8916_pinctrl_probe,
+ .remove = msm_pinctrl_remove,
+};
+
+static int __init msm8916_pinctrl_init(void)
+{
+ return platform_driver_register(&msm8916_pinctrl_driver);
+}
+arch_initcall(msm8916_pinctrl_init);
+
+static void __exit msm8916_pinctrl_exit(void)
+{
+ platform_driver_unregister(&msm8916_pinctrl_driver);
+}
+module_exit(msm8916_pinctrl_exit);
+
+MODULE_DESCRIPTION("Qualcomm msm8916 pinctrl driver");
+MODULE_LICENSE("GPL v2");
+MODULE_DEVICE_TABLE(of, msm8916_pinctrl_of_match);
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
index b863b5080890..0f11a26d932b 100644
--- a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -131,15 +131,17 @@ struct pmic_gpio_state {
struct gpio_chip chip;
};
-struct pmic_gpio_bindings {
- const char *property;
- unsigned param;
+static const struct pinconf_generic_params pmic_gpio_bindings[] = {
+ {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP, 0},
+ {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH, 0},
};
-static struct pmic_gpio_bindings pmic_gpio_bindings[] = {
- {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP},
- {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH},
+#ifdef CONFIG_DEBUG_FS
+static const struct pin_config_item pmic_conf_items[ARRAY_SIZE(pmic_gpio_bindings)] = {
+ PCONFDUMP(PMIC_GPIO_CONF_PULL_UP, "pull up strength", NULL, true),
+ PCONFDUMP(PMIC_GPIO_CONF_STRENGTH, "drive-strength", NULL, true),
};
+#endif
static const char *const pmic_gpio_groups[] = {
"gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8",
@@ -209,118 +211,11 @@ static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin,
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_node_to_map = pinconf_generic_dt_node_to_map_group,
.dt_free_map = pinctrl_utils_dt_free_map,
};
@@ -590,6 +485,7 @@ static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
}
static const struct pinconf_ops pmic_gpio_pinconf_ops = {
+ .is_generic = true,
.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,
@@ -848,6 +744,11 @@ static int pmic_gpio_probe(struct platform_device *pdev)
pctrldesc->name = dev_name(dev);
pctrldesc->pins = pindesc;
pctrldesc->npins = npins;
+ pctrldesc->num_custom_params = ARRAY_SIZE(pmic_gpio_bindings);
+ pctrldesc->custom_params = pmic_gpio_bindings;
+#ifdef CONFIG_DEBUG_FS
+ pctrldesc->custom_conf_items = pmic_conf_items;
+#endif
for (i = 0; i < npins; i++, pindesc++) {
pad = &pads[i];
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index becb3792977b..c8f83f96546c 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -1300,6 +1300,25 @@ static const struct samsung_pin_bank_data exynos7_pin_banks7[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr3", 0x0c),
};
+/* pin banks of exynos7 pin-controller - BUS1 */
+static const struct samsung_pin_bank_data exynos7_pin_banks8[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpf0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpf1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(4, 0x060, "gpf2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpf3", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0a0, "gpf4", 0x10),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0c0, "gpf5", 0x14),
+ EXYNOS_PIN_BANK_EINTG(5, 0x0e0, "gpg1", 0x18),
+ EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpg2", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(6, 0x120, "gph1", 0x20),
+ EXYNOS_PIN_BANK_EINTG(3, 0x140, "gpv6", 0x24),
+};
+
+static const struct samsung_pin_bank_data exynos7_pin_banks9[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
+};
+
const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 Alive data */
@@ -1342,5 +1361,15 @@ const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
.pin_banks = exynos7_pin_banks7,
.nr_banks = ARRAY_SIZE(exynos7_pin_banks7),
.eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 8 BUS1 data */
+ .pin_banks = exynos7_pin_banks8,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks8),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 9 AUD data */
+ .pin_banks = exynos7_pin_banks9,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks9),
+ .eint_gpio_init = exynos_eint_gpio_init,
},
};
diff --git a/drivers/pinctrl/sh-pfc/Kconfig b/drivers/pinctrl/sh-pfc/Kconfig
index 26187aa5cf5b..8c4b3d391823 100644
--- a/drivers/pinctrl/sh-pfc/Kconfig
+++ b/drivers/pinctrl/sh-pfc/Kconfig
@@ -20,6 +20,11 @@ config GPIO_SH_PFC
This enables support for GPIOs within the SoC's pin function
controller.
+config PINCTRL_PFC_EMEV2
+ def_bool y
+ depends on ARCH_EMEV2
+ select PINCTRL_SH_PFC
+
config PINCTRL_PFC_R8A73A4
def_bool y
depends on ARCH_R8A73A4
@@ -68,11 +73,6 @@ config PINCTRL_PFC_SH7269
depends on GPIOLIB
select PINCTRL_SH_PFC
-config PINCTRL_PFC_SH7372
- def_bool y
- depends on ARCH_SH7372
- select PINCTRL_SH_PFC
-
config PINCTRL_PFC_SH73A0
def_bool y
depends on ARCH_SH73A0
diff --git a/drivers/pinctrl/sh-pfc/Makefile b/drivers/pinctrl/sh-pfc/Makefile
index ad8f4cf9faaa..f4074e166bcf 100644
--- a/drivers/pinctrl/sh-pfc/Makefile
+++ b/drivers/pinctrl/sh-pfc/Makefile
@@ -3,6 +3,7 @@ ifeq ($(CONFIG_GPIO_SH_PFC),y)
sh-pfc-objs += gpio.o
endif
obj-$(CONFIG_PINCTRL_SH_PFC) += sh-pfc.o
+obj-$(CONFIG_PINCTRL_PFC_EMEV2) += pfc-emev2.o
obj-$(CONFIG_PINCTRL_PFC_R8A73A4) += pfc-r8a73a4.o
obj-$(CONFIG_PINCTRL_PFC_R8A7740) += pfc-r8a7740.o
obj-$(CONFIG_PINCTRL_PFC_R8A7778) += pfc-r8a7778.o
@@ -12,7 +13,6 @@ obj-$(CONFIG_PINCTRL_PFC_R8A7791) += pfc-r8a7791.o
obj-$(CONFIG_PINCTRL_PFC_SH7203) += pfc-sh7203.o
obj-$(CONFIG_PINCTRL_PFC_SH7264) += pfc-sh7264.o
obj-$(CONFIG_PINCTRL_PFC_SH7269) += pfc-sh7269.o
-obj-$(CONFIG_PINCTRL_PFC_SH7372) += pfc-sh7372.o
obj-$(CONFIG_PINCTRL_PFC_SH73A0) += pfc-sh73a0.o
obj-$(CONFIG_PINCTRL_PFC_SH7720) += pfc-sh7720.o
obj-$(CONFIG_PINCTRL_PFC_SH7722) += pfc-sh7722.o
diff --git a/drivers/pinctrl/sh-pfc/core.c b/drivers/pinctrl/sh-pfc/core.c
index 66dc62d2156c..a56280814a3f 100644
--- a/drivers/pinctrl/sh-pfc/core.c
+++ b/drivers/pinctrl/sh-pfc/core.c
@@ -439,6 +439,12 @@ static int sh_pfc_init_ranges(struct sh_pfc *pfc)
#ifdef CONFIG_OF
static const struct of_device_id sh_pfc_of_table[] = {
+#ifdef CONFIG_PINCTRL_PFC_EMEV2
+ {
+ .compatible = "renesas,pfc-emev2",
+ .data = &emev2_pinmux_info,
+ },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A73A4
{
.compatible = "renesas,pfc-r8a73a4",
@@ -475,12 +481,6 @@ static const struct of_device_id sh_pfc_of_table[] = {
.data = &r8a7791_pinmux_info,
},
#endif
-#ifdef CONFIG_PINCTRL_PFC_SH7372
- {
- .compatible = "renesas,pfc-sh7372",
- .data = &sh7372_pinmux_info,
- },
-#endif
#ifdef CONFIG_PINCTRL_PFC_SH73A0
{
.compatible = "renesas,pfc-sh73a0",
@@ -579,6 +579,9 @@ static int sh_pfc_remove(struct platform_device *pdev)
}
static const struct platform_device_id sh_pfc_id_table[] = {
+#ifdef CONFIG_PINCTRL_PFC_EMEV2
+ { "pfc-emev2", (kernel_ulong_t)&emev2_pinmux_info },
+#endif
#ifdef CONFIG_PINCTRL_PFC_R8A73A4
{ "pfc-r8a73a4", (kernel_ulong_t)&r8a73a4_pinmux_info },
#endif
@@ -606,9 +609,6 @@ static const struct platform_device_id sh_pfc_id_table[] = {
#ifdef CONFIG_PINCTRL_PFC_SH7269
{ "pfc-sh7269", (kernel_ulong_t)&sh7269_pinmux_info },
#endif
-#ifdef CONFIG_PINCTRL_PFC_SH7372
- { "pfc-sh7372", (kernel_ulong_t)&sh7372_pinmux_info },
-#endif
#ifdef CONFIG_PINCTRL_PFC_SH73A0
{ "pfc-sh73a0", (kernel_ulong_t)&sh73a0_pinmux_info },
#endif
diff --git a/drivers/pinctrl/sh-pfc/core.h b/drivers/pinctrl/sh-pfc/core.h
index 3daaa5241c47..6b59d63b9c01 100644
--- a/drivers/pinctrl/sh-pfc/core.h
+++ b/drivers/pinctrl/sh-pfc/core.h
@@ -65,6 +65,7 @@ void sh_pfc_write_raw_reg(void __iomem *mapped_reg, unsigned long reg_width,
int sh_pfc_get_pin_index(struct sh_pfc *pfc, unsigned int pin);
int sh_pfc_config_mux(struct sh_pfc *pfc, unsigned mark, int pinmux_type);
+extern const struct sh_pfc_soc_info emev2_pinmux_info;
extern const struct sh_pfc_soc_info r8a73a4_pinmux_info;
extern const struct sh_pfc_soc_info r8a7740_pinmux_info;
extern const struct sh_pfc_soc_info r8a7778_pinmux_info;
@@ -74,7 +75,6 @@ extern const struct sh_pfc_soc_info r8a7791_pinmux_info;
extern const struct sh_pfc_soc_info sh7203_pinmux_info;
extern const struct sh_pfc_soc_info sh7264_pinmux_info;
extern const struct sh_pfc_soc_info sh7269_pinmux_info;
-extern const struct sh_pfc_soc_info sh7372_pinmux_info;
extern const struct sh_pfc_soc_info sh73a0_pinmux_info;
extern const struct sh_pfc_soc_info sh7720_pinmux_info;
extern const struct sh_pfc_soc_info sh7722_pinmux_info;
diff --git a/drivers/pinctrl/sh-pfc/pfc-emev2.c b/drivers/pinctrl/sh-pfc/pfc-emev2.c
new file mode 100644
index 000000000000..849c6943ed30
--- /dev/null
+++ b/drivers/pinctrl/sh-pfc/pfc-emev2.c
@@ -0,0 +1,1711 @@
+/*
+ * Pin Function Controller Support
+ *
+ * Copyright (C) 2015 Niklas Söderlund
+ *
+ * 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/kernel.h>
+
+#include "sh_pfc.h"
+
+#define CPU_ALL_PORT(fn, pfx, sfx) \
+ PORT_10(0, fn, pfx, sfx), PORT_90(0, fn, pfx, sfx), \
+ PORT_10(100, fn, pfx##10, sfx), PORT_10(110, fn, pfx##11, sfx), \
+ PORT_10(120, fn, pfx##12, sfx), PORT_10(130, fn, pfx##13, sfx), \
+ PORT_10(140, fn, pfx##14, sfx), PORT_1(150, fn, pfx##150, sfx), \
+ PORT_1(151, fn, pfx##151, sfx), PORT_1(152, fn, pfx##152, sfx), \
+ PORT_1(153, fn, pfx##153, sfx), PORT_1(154, fn, pfx##154, sfx), \
+ PORT_1(155, fn, pfx##155, sfx), PORT_1(156, fn, pfx##156, sfx), \
+ PORT_1(157, fn, pfx##157, sfx), PORT_1(158, fn, pfx##158, sfx)
+
+enum {
+ PINMUX_RESERVED = 0,
+
+ PINMUX_DATA_BEGIN,
+ PORT_ALL(DATA),
+ PINMUX_DATA_END,
+
+ PINMUX_FUNCTION_BEGIN,
+ PORT_ALL(FN),
+
+ /* GPSR0 */
+ FN_LCD3_1_0_PORT18, FN_LCD3_1_0_PORT20, FN_LCD3_1_0_PORT21,
+ FN_LCD3_1_0_PORT22, FN_LCD3_1_0_PORT23,
+ FN_JT_SEL, FN_ERR_RST_REQB, FN_REF_CLKO, FN_EXT_CLKI, FN_LCD3_PXCLKB,
+
+ /* GPSR1 */
+ FN_LCD3_9_8_PORT38, FN_LCD3_9_8_PORT39, FN_LCD3_11_10_PORT40,
+ FN_LCD3_11_10_PORT41, FN_LCD3_11_10_PORT42, FN_LCD3_11_10_PORT43,
+ FN_IIC_1_0_PORT46, FN_IIC_1_0_PORT47,
+ FN_LCD3_R0, FN_LCD3_R1, FN_LCD3_R2, FN_LCD3_R3, FN_LCD3_R4, FN_LCD3_R5,
+ FN_IIC0_SCL, FN_IIC0_SDA, FN_SD_CKI, FN_SDI0_CKO, FN_SDI0_CKI,
+ FN_SDI0_CMD, FN_SDI0_DATA0, FN_SDI0_DATA1, FN_SDI0_DATA2,
+ FN_SDI0_DATA3, FN_SDI0_DATA4, FN_SDI0_DATA5, FN_SDI0_DATA6,
+ FN_SDI0_DATA7, FN_SDI1_CKO, FN_SDI1_CKI, FN_SDI1_CMD,
+
+ /* GPSR2 */
+ FN_AB_1_0_PORT71, FN_AB_1_0_PORT72, FN_AB_1_0_PORT73,
+ FN_AB_1_0_PORT74, FN_AB_1_0_PORT75, FN_AB_1_0_PORT76,
+ FN_AB_1_0_PORT77, FN_AB_1_0_PORT78, FN_AB_1_0_PORT79,
+ FN_AB_1_0_PORT80, FN_AB_1_0_PORT81, FN_AB_1_0_PORT82,
+ FN_AB_1_0_PORT83, FN_AB_1_0_PORT84, FN_AB_3_2_PORT85,
+ FN_AB_3_2_PORT86, FN_AB_3_2_PORT87, FN_AB_3_2_PORT88,
+ FN_AB_5_4_PORT89, FN_AB_5_4_PORT90, FN_AB_7_6_PORT91,
+ FN_AB_7_6_PORT92, FN_AB_1_0_PORT93, FN_AB_1_0_PORT94,
+ FN_AB_1_0_PORT95,
+ FN_SDI1_DATA0, FN_SDI1_DATA1, FN_SDI1_DATA2, FN_SDI1_DATA3,
+ FN_AB_CLK, FN_AB_CSB0, FN_AB_CSB1,
+
+ /* GPSR3 */
+ FN_AB_13_12_PORT104, FN_AB_13_12_PORT103, FN_AB_11_10_PORT102,
+ FN_AB_11_10_PORT101, FN_AB_11_10_PORT100, FN_AB_9_8_PORT99,
+ FN_AB_9_8_PORT98, FN_AB_9_8_PORT97,
+ FN_USI_1_0_PORT109, FN_USI_1_0_PORT110, FN_USI_1_0_PORT111,
+ FN_USI_1_0_PORT112, FN_USI_3_2_PORT113, FN_USI_3_2_PORT114,
+ FN_USI_5_4_PORT115, FN_USI_5_4_PORT116, FN_USI_5_4_PORT117,
+ FN_USI_5_4_PORT118, FN_USI_7_6_PORT119, FN_USI_9_8_PORT120,
+ FN_USI_9_8_PORT121,
+ FN_AB_A20, FN_USI0_CS1, FN_USI0_CS2, FN_USI1_DI,
+ FN_USI1_DO,
+ FN_NTSC_CLK, FN_NTSC_DATA0, FN_NTSC_DATA1, FN_NTSC_DATA2,
+ FN_NTSC_DATA3, FN_NTSC_DATA4,
+
+ /* GPRS4 */
+ FN_HSI_1_0_PORT143, FN_HSI_1_0_PORT144, FN_HSI_1_0_PORT145,
+ FN_HSI_1_0_PORT146, FN_HSI_1_0_PORT147, FN_HSI_1_0_PORT148,
+ FN_HSI_1_0_PORT149, FN_HSI_1_0_PORT150,
+ FN_UART_1_0_PORT157, FN_UART_1_0_PORT158,
+ FN_NTSC_DATA5, FN_NTSC_DATA6, FN_NTSC_DATA7, FN_CAM_CLKO,
+ FN_CAM_CLKI, FN_CAM_VS, FN_CAM_HS, FN_CAM_YUV0,
+ FN_CAM_YUV1, FN_CAM_YUV2, FN_CAM_YUV3, FN_CAM_YUV4,
+ FN_CAM_YUV5, FN_CAM_YUV6, FN_CAM_YUV7,
+ FN_JT_TDO, FN_JT_TDOEN, FN_LOWPWR, FN_USB_VBUS, FN_UART1_RX,
+ FN_UART1_TX,
+
+ /* CHG_PINSEL_LCD3 */
+ FN_SEL_LCD3_1_0_00, FN_SEL_LCD3_1_0_01,
+ FN_SEL_LCD3_9_8_00, FN_SEL_LCD3_9_8_10,
+ FN_SEL_LCD3_11_10_00, FN_SEL_LCD3_11_10_01, FN_SEL_LCD3_11_10_10,
+
+ /* CHG_PINSEL_IIC */
+ FN_SEL_IIC_1_0_00, FN_SEL_IIC_1_0_01,
+
+ /* CHG_PINSEL_AB */
+ FN_SEL_AB_1_0_00, FN_SEL_AB_1_0_10, FN_SEL_AB_3_2_00,
+ FN_SEL_AB_3_2_01, FN_SEL_AB_3_2_10, FN_SEL_AB_3_2_11,
+ FN_SEL_AB_5_4_00, FN_SEL_AB_5_4_01, FN_SEL_AB_5_4_10,
+ FN_SEL_AB_5_4_11, FN_SEL_AB_7_6_00, FN_SEL_AB_7_6_01,
+ FN_SEL_AB_7_6_10,
+ FN_SEL_AB_9_8_00, FN_SEL_AB_9_8_01, FN_SEL_AB_9_8_10,
+ FN_SEL_AB_11_10_00, FN_SEL_AB_11_10_10,
+ FN_SEL_AB_13_12_00, FN_SEL_AB_13_12_10,
+
+ /* CHG_PINSEL_USI */
+ FN_SEL_USI_1_0_00, FN_SEL_USI_1_0_01,
+ FN_SEL_USI_3_2_00, FN_SEL_USI_3_2_01,
+ FN_SEL_USI_5_4_00, FN_SEL_USI_5_4_01,
+ FN_SEL_USI_7_6_00, FN_SEL_USI_7_6_01,
+ FN_SEL_USI_9_8_00, FN_SEL_USI_9_8_01,
+
+ /* CHG_PINSEL_HSI */
+ FN_SEL_HSI_1_0_00, FN_SEL_HSI_1_0_01,
+
+ /* CHG_PINSEL_UART */
+ FN_SEL_UART_1_0_00, FN_SEL_UART_1_0_01,
+
+ PINMUX_FUNCTION_END,
+
+ PINMUX_MARK_BEGIN,
+
+ /* GPSR0 */
+ JT_SEL_MARK, ERR_RST_REQB_MARK, REF_CLKO_MARK, EXT_CLKI_MARK,
+ LCD3_PXCLKB_MARK, SD_CKI_MARK,
+
+ /* GPSR1 */
+ LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK, LCD3_R4_MARK,
+ LCD3_R5_MARK, IIC0_SCL_MARK, IIC0_SDA_MARK, SDI0_CKO_MARK,
+ SDI0_CKI_MARK, SDI0_CMD_MARK, SDI0_DATA0_MARK, SDI0_DATA1_MARK,
+ SDI0_DATA2_MARK, SDI0_DATA3_MARK, SDI0_DATA4_MARK, SDI0_DATA5_MARK,
+ SDI0_DATA6_MARK, SDI0_DATA7_MARK, SDI1_CKO_MARK, SDI1_CKI_MARK,
+ SDI1_CMD_MARK,
+
+ /* GPSR2 */
+ SDI1_DATA0_MARK, SDI1_DATA1_MARK, SDI1_DATA2_MARK, SDI1_DATA3_MARK,
+ AB_CLK_MARK, AB_CSB0_MARK, AB_CSB1_MARK,
+
+ /* GPSR3 */
+ AB_A20_MARK, USI0_CS1_MARK, USI0_CS2_MARK, USI1_DI_MARK,
+ USI1_DO_MARK,
+ NTSC_CLK_MARK, NTSC_DATA0_MARK, NTSC_DATA1_MARK, NTSC_DATA2_MARK,
+ NTSC_DATA3_MARK, NTSC_DATA4_MARK,
+
+ /* GPSR3 */
+ NTSC_DATA5_MARK, NTSC_DATA6_MARK, NTSC_DATA7_MARK, CAM_CLKO_MARK,
+ CAM_CLKI_MARK, CAM_VS_MARK, CAM_HS_MARK, CAM_YUV0_MARK,
+ CAM_YUV1_MARK, CAM_YUV2_MARK, CAM_YUV3_MARK, CAM_YUV4_MARK,
+ CAM_YUV5_MARK, CAM_YUV6_MARK, CAM_YUV7_MARK,
+ JT_TDO_MARK, JT_TDOEN_MARK, USB_VBUS_MARK, LOWPWR_MARK,
+ UART1_RX_MARK, UART1_TX_MARK,
+
+ /* CHG_PINSEL_LCD3 */
+ LCD3_PXCLK_MARK, LCD3_CLK_I_MARK, LCD3_HS_MARK, LCD3_VS_MARK,
+ LCD3_DE_MARK, LCD3_R6_MARK, LCD3_R7_MARK, LCD3_G0_MARK, LCD3_G1_MARK,
+ LCD3_G2_MARK, LCD3_G3_MARK, LCD3_G4_MARK, LCD3_G5_MARK, LCD3_G6_MARK,
+ LCD3_G7_MARK, LCD3_B0_MARK, LCD3_B1_MARK, LCD3_B2_MARK, LCD3_B3_MARK,
+ LCD3_B4_MARK, LCD3_B5_MARK, LCD3_B6_MARK, LCD3_B7_MARK,
+ YUV3_CLK_O_MARK, YUV3_CLK_I_MARK, YUV3_HS_MARK, YUV3_VS_MARK,
+ YUV3_DE_MARK, YUV3_D0_MARK, YUV3_D1_MARK, YUV3_D2_MARK, YUV3_D3_MARK,
+ YUV3_D4_MARK, YUV3_D5_MARK, YUV3_D6_MARK, YUV3_D7_MARK, YUV3_D8_MARK,
+ YUV3_D9_MARK, YUV3_D10_MARK, YUV3_D11_MARK, YUV3_D12_MARK,
+ YUV3_D13_MARK, YUV3_D14_MARK, YUV3_D15_MARK,
+ TP33_CLK_MARK, TP33_CTRL_MARK, TP33_DATA0_MARK, TP33_DATA1_MARK,
+ TP33_DATA2_MARK, TP33_DATA3_MARK, TP33_DATA4_MARK, TP33_DATA5_MARK,
+ TP33_DATA6_MARK, TP33_DATA7_MARK, TP33_DATA8_MARK, TP33_DATA9_MARK,
+ TP33_DATA10_MARK, TP33_DATA11_MARK, TP33_DATA12_MARK, TP33_DATA13_MARK,
+ TP33_DATA14_MARK, TP33_DATA15_MARK,
+
+ /* CHG_PINSEL_IIC */
+ IIC1_SCL_MARK, IIC1_SDA_MARK, UART3_RX_MARK, UART3_TX_MARK,
+
+ /* CHG_PINSEL_AB */
+ AB_CSB2_MARK, AB_CSB3_MARK, AB_RDB_MARK, AB_WRB_MARK,
+ AB_WAIT_MARK, AB_ADV_MARK, AB_AD0_MARK, AB_AD1_MARK,
+ AB_AD2_MARK, AB_AD3_MARK, AB_AD4_MARK, AB_AD5_MARK,
+ AB_AD6_MARK, AB_AD7_MARK, AB_AD8_MARK, AB_AD9_MARK,
+ AB_AD10_MARK, AB_AD11_MARK, AB_AD12_MARK, AB_AD13_MARK,
+ AB_AD14_MARK, AB_AD15_MARK, AB_A17_MARK, AB_A18_MARK,
+ AB_A19_MARK, AB_A21_MARK, AB_A22_MARK, AB_A23_MARK,
+ AB_A24_MARK, AB_A25_MARK, AB_A26_MARK, AB_A27_MARK,
+ AB_A28_MARK, AB_BEN0_MARK, AB_BEN1_MARK,
+ DTV_BCLK_A_MARK, DTV_PSYNC_A_MARK, DTV_VALID_A_MARK,
+ DTV_DATA_A_MARK,
+ SDI2_CKO_MARK, SDI2_CKI_MARK, SDI2_CMD_MARK,
+ SDI2_DATA0_MARK, SDI2_DATA1_MARK, SDI2_DATA2_MARK,
+ SDI2_DATA3_MARK,
+ CF_CSB0_MARK, CF_CSB1_MARK, CF_IORDB_MARK,
+ CF_IOWRB_MARK, CF_IORDY_MARK, CF_RESET_MARK,
+ CF_D00_MARK, CF_D01_MARK, CF_D02_MARK, CF_D03_MARK,
+ CF_D04_MARK, CF_D05_MARK, CF_D06_MARK, CF_D07_MARK,
+ CF_D08_MARK, CF_D09_MARK, CF_D10_MARK, CF_D11_MARK,
+ CF_D12_MARK, CF_D13_MARK, CF_D14_MARK, CF_D15_MARK,
+ CF_A00_MARK, CF_A01_MARK, CF_A02_MARK,
+ CF_INTRQ_MARK, CF_INPACKB_MARK, CF_CDB1_MARK, CF_CDB2_MARK,
+ USI5_CLK_A_MARK, USI5_DI_A_MARK, USI5_DO_A_MARK,
+ USI5_CS0_A_MARK, USI5_CS1_A_MARK, USI5_CS2_A_MARK,
+
+ /* CHG_PINSEL_USI */
+ USI0_CS3_MARK, USI0_CS4_MARK, USI0_CS5_MARK,
+ USI0_CS6_MARK,
+ USI2_CLK_MARK, USI2_DI_MARK, USI2_DO_MARK,
+ USI2_CS0_MARK, USI2_CS1_MARK, USI2_CS2_MARK,
+ USI3_CLK_MARK, USI3_DI_MARK, USI3_DO_MARK,
+ USI3_CS0_MARK,
+ USI4_CLK_MARK, USI4_DI_MARK, USI4_DO_MARK,
+ USI4_CS0_MARK, USI4_CS1_MARK,
+ PWM0_MARK, PWM1_MARK,
+ DTV_BCLK_B_MARK, DTV_PSYNC_B_MARK, DTV_VALID_B_MARK,
+ DTV_DATA_B_MARK,
+
+ /* CHG_PINSEL_HSI */
+ USI5_CLK_B_MARK, USI5_DO_B_MARK, USI5_CS0_B_MARK, USI5_CS1_B_MARK,
+ USI5_CS2_B_MARK, USI5_CS3_B_MARK, USI5_CS4_B_MARK, USI5_DI_B_MARK,
+
+ /* CHG_PINSEL_UART */
+ UART1_CTSB_MARK, UART1_RTSB_MARK,
+ UART2_RX_MARK, UART2_TX_MARK,
+
+ PINMUX_MARK_END,
+};
+
+/* Pin numbers for pins without a corresponding GPIO port number are computed
+ * from the row and column numbers with a 1000 offset to avoid collisions with
+ * GPIO port numbers. */
+#define PIN_NUMBER(row, col) (1000+((row)-1)*23+(col)-1)
+
+/* Expand to a list of sh_pfc_pin entries (named PORT#).
+ * NOTE: No config are recorded since the driver do not handle pinconf. */
+#define __PIN_CFG(pn, pfx, sfx) SH_PFC_PIN_CFG(pfx, 0)
+#define PINMUX_EMEV_GPIO_ALL() CPU_ALL_PORT(__PIN_CFG, , unused)
+
+static const struct sh_pfc_pin pinmux_pins[] = {
+ PINMUX_EMEV_GPIO_ALL(),
+
+ /* Pins not associated with a GPIO port */
+ SH_PFC_PIN_NAMED(2, 14, B14),
+ SH_PFC_PIN_NAMED(2, 15, B15),
+ SH_PFC_PIN_NAMED(2, 16, B16),
+ SH_PFC_PIN_NAMED(2, 17, B17),
+ SH_PFC_PIN_NAMED(3, 14, C14),
+ SH_PFC_PIN_NAMED(3, 15, C15),
+ SH_PFC_PIN_NAMED(3, 16, C16),
+ SH_PFC_PIN_NAMED(3, 17, C17),
+ SH_PFC_PIN_NAMED(4, 14, D14),
+ SH_PFC_PIN_NAMED(4, 15, D15),
+ SH_PFC_PIN_NAMED(4, 16, D16),
+ SH_PFC_PIN_NAMED(4, 17, D17),
+};
+
+/* Expand to a list of name_DATA, name_FN marks */
+#define __PORT_DATA(pn, pfx, sfx) PINMUX_DATA(PORT##pfx##_DATA, PORT##pfx##_FN)
+#define PINMUX_EMEV_DATA_ALL() CPU_ALL_PORT(__PORT_DATA, , unused)
+
+static const u16 pinmux_data[] = {
+ PINMUX_EMEV_DATA_ALL(), /* PINMUX_DATA(PORTN_DATA, PORTN_FN), */
+
+ /* GPSR0 */
+ /* V9 */
+ PINMUX_DATA(JT_SEL_MARK, FN_JT_SEL),
+ /* U9 */
+ PINMUX_DATA(ERR_RST_REQB_MARK, FN_ERR_RST_REQB),
+ /* V8 */
+ PINMUX_DATA(REF_CLKO_MARK, FN_REF_CLKO),
+ /* U8 */
+ PINMUX_DATA(EXT_CLKI_MARK, FN_EXT_CLKI),
+ /* B22*/
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, LCD3_PXCLK, SEL_LCD3_1_0_00),
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT18, YUV3_CLK_O, SEL_LCD3_1_0_01),
+ /* C21 */
+ PINMUX_DATA(LCD3_PXCLKB_MARK, FN_LCD3_PXCLKB),
+ /* A21 */
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, LCD3_CLK_I, SEL_LCD3_1_0_00),
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT20, YUV3_CLK_I, SEL_LCD3_1_0_01),
+ /* B21 */
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT21, LCD3_HS, SEL_LCD3_1_0_00),
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT21, YUV3_HS, SEL_LCD3_1_0_01),
+ /* C20 */
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT22, LCD3_VS, SEL_LCD3_1_0_00),
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT22, YUV3_VS, SEL_LCD3_1_0_01),
+ /* D19 */
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT23, LCD3_DE, SEL_LCD3_1_0_00),
+ PINMUX_IPSR_NOFN(LCD3_1_0_PORT23, YUV3_DE, SEL_LCD3_1_0_01),
+
+ /* GPSR1 */
+ /* A20 */
+ PINMUX_DATA(LCD3_R0_MARK, FN_LCD3_R0),
+ /* B20 */
+ PINMUX_DATA(LCD3_R1_MARK, FN_LCD3_R1),
+ /* A19 */
+ PINMUX_DATA(LCD3_R2_MARK, FN_LCD3_R2),
+ /* B19 */
+ PINMUX_DATA(LCD3_R3_MARK, FN_LCD3_R3),
+ /* C19 */
+ PINMUX_DATA(LCD3_R4_MARK, FN_LCD3_R4),
+ /* B18 */
+ PINMUX_DATA(LCD3_R5_MARK, FN_LCD3_R5),
+ /* C18 */
+ PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, LCD3_R6, SEL_LCD3_9_8_00),
+ PINMUX_IPSR_NOFN(LCD3_9_8_PORT38, TP33_CLK, SEL_LCD3_9_8_10),
+ /* D18 */
+ PINMUX_IPSR_NOFN(LCD3_9_8_PORT39, LCD3_R7, SEL_LCD3_9_8_00),
+ PINMUX_IPSR_NOFN(LCD3_9_8_PORT39, TP33_CTRL, SEL_LCD3_9_8_10),
+ /* A18 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT40, LCD3_G0, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT40, YUV3_D0, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT40, TP33_DATA0, SEL_LCD3_11_10_10),
+ /* A17 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT41, LCD3_G1, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT41, YUV3_D1, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT41, TP33_DATA1, SEL_LCD3_11_10_10),
+ /* B17 */
+ PINMUX_DATA(LCD3_G2_MARK, FN_SEL_LCD3_11_10_00),
+ PINMUX_DATA(YUV3_D2_MARK, FN_SEL_LCD3_11_10_01),
+ PINMUX_DATA(TP33_DATA2_MARK, FN_SEL_LCD3_11_10_10),
+ /* C17 */
+ PINMUX_DATA(LCD3_G3_MARK, FN_SEL_LCD3_11_10_00),
+ PINMUX_DATA(YUV3_D3_MARK, FN_SEL_LCD3_11_10_01),
+ PINMUX_DATA(TP33_DATA3_MARK, FN_SEL_LCD3_11_10_10),
+ /* D17 */
+ PINMUX_DATA(LCD3_G4_MARK, FN_SEL_LCD3_11_10_00),
+ PINMUX_DATA(YUV3_D4_MARK, FN_SEL_LCD3_11_10_01),
+ PINMUX_DATA(TP33_DATA4_MARK, FN_SEL_LCD3_11_10_10),
+ /* B16 */
+ PINMUX_DATA(LCD3_G5_MARK, FN_SEL_LCD3_11_10_00),
+ PINMUX_DATA(YUV3_D5_MARK, FN_SEL_LCD3_11_10_01),
+ PINMUX_DATA(TP33_DATA5_MARK, FN_SEL_LCD3_11_10_10),
+ /* C16 */
+ PINMUX_DATA(LCD3_G6_MARK, FN_SEL_LCD3_11_10_00),
+ PINMUX_DATA(YUV3_D6_MARK, FN_SEL_LCD3_11_10_01),
+ PINMUX_DATA(TP33_DATA6_MARK, FN_SEL_LCD3_11_10_10),
+ /* D16 */
+ PINMUX_DATA(LCD3_G7_MARK, FN_SEL_LCD3_11_10_00),
+ PINMUX_DATA(YUV3_D7_MARK, FN_SEL_LCD3_11_10_01),
+ PINMUX_DATA(TP33_DATA7_MARK, FN_SEL_LCD3_11_10_10),
+ /* A16 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT42, LCD3_B0, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT42, YUV3_D8, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT42, TP33_DATA8, SEL_LCD3_11_10_10),
+ /* A15 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B1, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D9, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA9, SEL_LCD3_11_10_10),
+ /* B15 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B2, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D10, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA10, SEL_LCD3_11_10_10),
+ /* C15 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B3, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D11, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA11, SEL_LCD3_11_10_10),
+ /* D15 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B4, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D12, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA12, SEL_LCD3_11_10_10),
+ /* B14 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B5, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D13, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA13, SEL_LCD3_11_10_10),
+ /* C14 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B6, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D14, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA14, SEL_LCD3_11_10_10),
+ /* D14 */
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, LCD3_B7, SEL_LCD3_11_10_00),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, YUV3_D15, SEL_LCD3_11_10_01),
+ PINMUX_IPSR_NOFN(LCD3_11_10_PORT43, TP33_DATA15, SEL_LCD3_11_10_10),
+ /* AA9 */
+ PINMUX_DATA(IIC0_SCL_MARK, FN_IIC0_SCL),
+ /* AA8 */
+ PINMUX_DATA(IIC0_SDA_MARK, FN_IIC0_SDA),
+ /* Y9 */
+ PINMUX_IPSR_NOFN(IIC_1_0_PORT46, IIC1_SCL, SEL_IIC_1_0_00),
+ PINMUX_IPSR_NOFN(IIC_1_0_PORT46, UART3_RX, SEL_IIC_1_0_01),
+ /* Y8 */
+ PINMUX_IPSR_NOFN(IIC_1_0_PORT47, IIC1_SDA, SEL_IIC_1_0_00),
+ PINMUX_IPSR_NOFN(IIC_1_0_PORT47, UART3_TX, SEL_IIC_1_0_01),
+ /* AC19 */
+ PINMUX_DATA(SD_CKI_MARK, FN_SD_CKI),
+ /* AB18 */
+ PINMUX_DATA(SDI0_CKO_MARK, FN_SDI0_CKO),
+ /* AC18 */
+ PINMUX_DATA(SDI0_CKI_MARK, FN_SDI0_CKI),
+ /* Y12 */
+ PINMUX_DATA(SDI0_CMD_MARK, FN_SDI0_CMD),
+ /* AA13 */
+ PINMUX_DATA(SDI0_DATA0_MARK, FN_SDI0_DATA0),
+ /* Y13 */
+ PINMUX_DATA(SDI0_DATA1_MARK, FN_SDI0_DATA1),
+ /* AA14 */
+ PINMUX_DATA(SDI0_DATA2_MARK, FN_SDI0_DATA2),
+ /* Y14 */
+ PINMUX_DATA(SDI0_DATA3_MARK, FN_SDI0_DATA3),
+ /* AA15 */
+ PINMUX_DATA(SDI0_DATA4_MARK, FN_SDI0_DATA4),
+ /* Y15 */
+ PINMUX_DATA(SDI0_DATA5_MARK, FN_SDI0_DATA5),
+ /* AA16 */
+ PINMUX_DATA(SDI0_DATA6_MARK, FN_SDI0_DATA6),
+ /* Y16 */
+ PINMUX_DATA(SDI0_DATA7_MARK, FN_SDI0_DATA7),
+ /* AB22 */
+ PINMUX_DATA(SDI1_CKO_MARK, FN_SDI1_CKO),
+ /* AA23 */
+ PINMUX_DATA(SDI1_CKI_MARK, FN_SDI1_CKI),
+ /* AC21 */
+ PINMUX_DATA(SDI1_CMD_MARK, FN_SDI1_CMD),
+
+ /* GPSR2 */
+ /* AB21 */
+ PINMUX_DATA(SDI1_DATA0_MARK, FN_SDI1_DATA0),
+ /* AB20 */
+ PINMUX_DATA(SDI1_DATA1_MARK, FN_SDI1_DATA1),
+ /* AB19 */
+ PINMUX_DATA(SDI1_DATA2_MARK, FN_SDI1_DATA2),
+ /* AA19 */
+ PINMUX_DATA(SDI1_DATA3_MARK, FN_SDI1_DATA3),
+ /* J23 */
+ PINMUX_DATA(AB_CLK_MARK, FN_AB_CLK),
+ /* D21 */
+ PINMUX_DATA(AB_CSB0_MARK, FN_AB_CSB0),
+ /* E21 */
+ PINMUX_DATA(AB_CSB1_MARK, FN_AB_CSB1),
+ /* F20 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT71, AB_CSB2, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT71, CF_CSB0, SEL_AB_1_0_10),
+ /* G20 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT72, AB_CSB3, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT72, CF_CSB1, SEL_AB_1_0_10),
+ /* J20 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT73, AB_RDB, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT73, CF_IORDB, SEL_AB_1_0_10),
+ /* H20 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT74, AB_WRB, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT74, CF_IOWRB, SEL_AB_1_0_10),
+ /* L20 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT75, AB_WAIT, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT75, CF_IORDY, SEL_AB_1_0_10),
+ /* K20 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT76, AB_ADV, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT76, CF_RESET, SEL_AB_1_0_10),
+ /* C23 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT77, AB_AD0, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT77, CF_D00, SEL_AB_1_0_10),
+ /* C22 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT78, AB_AD1, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT78, CF_D01, SEL_AB_1_0_10),
+ /* D23 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT79, AB_AD2, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT79, CF_D02, SEL_AB_1_0_10),
+ /* D22 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT80, AB_AD3, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT80, CF_D03, SEL_AB_1_0_10),
+ /* E23 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT81, AB_AD4, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT81, CF_D04, SEL_AB_1_0_10),
+ /* E22 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT82, AB_AD5, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT82, CF_D05, SEL_AB_1_0_10),
+ /* F23 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT83, AB_AD6, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT83, CF_D06, SEL_AB_1_0_10),
+ /* F22 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT84, AB_AD7, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT84, CF_D07, SEL_AB_1_0_10),
+ /* F21 */
+ PINMUX_IPSR_NOFN(AB_3_2_PORT85, AB_AD8, SEL_AB_3_2_00),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT85, DTV_BCLK_A, SEL_AB_3_2_01),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT85, CF_D08, SEL_AB_3_2_10),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT85, USI5_CLK_A, SEL_AB_3_2_11),
+ /* G23 */
+ PINMUX_IPSR_NOFN(AB_3_2_PORT86, AB_AD9, SEL_AB_3_2_00),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT86, DTV_PSYNC_A, SEL_AB_3_2_01),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT86, CF_D09, SEL_AB_3_2_10),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT86, USI5_DI_A, SEL_AB_3_2_11),
+ /* G22 */
+ PINMUX_IPSR_NOFN(AB_3_2_PORT87, AB_AD10, SEL_AB_3_2_00),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT87, DTV_VALID_A, SEL_AB_3_2_01),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT87, CF_D10, SEL_AB_3_2_10),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT87, USI5_DO_A, SEL_AB_3_2_11),
+ /* G21 */
+ PINMUX_IPSR_NOFN(AB_3_2_PORT88, AB_AD11, SEL_AB_3_2_00),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT88, DTV_DATA_A, SEL_AB_3_2_01),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT88, CF_D11, SEL_AB_3_2_10),
+ PINMUX_IPSR_NOFN(AB_3_2_PORT88, USI5_CS0_A, SEL_AB_3_2_11),
+ /* H23 */
+ PINMUX_IPSR_NOFN(AB_5_4_PORT89, AB_AD12, SEL_AB_5_4_00),
+ PINMUX_IPSR_NOFN(AB_5_4_PORT89, SDI2_DATA0, SEL_AB_5_4_01),
+ PINMUX_IPSR_NOFN(AB_5_4_PORT89, CF_D12, SEL_AB_5_4_10),
+ PINMUX_IPSR_NOFN(AB_5_4_PORT89, USI5_CS1_A, SEL_AB_5_4_11),
+ /* H22 */
+ PINMUX_IPSR_NOFN(AB_5_4_PORT90, AB_AD13, SEL_AB_5_4_00),
+ PINMUX_IPSR_NOFN(AB_5_4_PORT90, SDI2_DATA1, SEL_AB_5_4_01),
+ PINMUX_IPSR_NOFN(AB_5_4_PORT90, CF_D13, SEL_AB_5_4_10),
+ PINMUX_IPSR_NOFN(AB_5_4_PORT90, USI5_CS2_A, SEL_AB_5_4_11),
+ /* H21 */
+ PINMUX_IPSR_NOFN(AB_7_6_PORT91, AB_AD14, SEL_AB_7_6_00),
+ PINMUX_IPSR_NOFN(AB_7_6_PORT91, SDI2_DATA2, SEL_AB_7_6_01),
+ PINMUX_IPSR_NOFN(AB_7_6_PORT91, CF_D14, SEL_AB_7_6_10),
+ /* J22 */
+ PINMUX_IPSR_NOFN(AB_7_6_PORT92, AB_AD15, SEL_AB_7_6_00),
+ PINMUX_IPSR_NOFN(AB_7_6_PORT92, SDI2_DATA3, SEL_AB_7_6_01),
+ PINMUX_IPSR_NOFN(AB_7_6_PORT92, CF_D15, SEL_AB_7_6_10),
+ /* J21 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT93, AB_A17, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT93, CF_A00, SEL_AB_1_0_10),
+ /* K21 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT94, AB_A18, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT94, CF_A01, SEL_AB_1_0_10),
+ /* L21 */
+ PINMUX_IPSR_NOFN(AB_1_0_PORT95, AB_A19, SEL_AB_1_0_00),
+ PINMUX_IPSR_NOFN(AB_1_0_PORT95, CF_A02, SEL_AB_1_0_10),
+
+ /* GPSR3 */
+ /* M21 */
+ PINMUX_DATA(AB_A20_MARK, FN_AB_A20),
+ /* N21 */
+ PINMUX_IPSR_NOFN(AB_9_8_PORT97, AB_A21, SEL_AB_9_8_00),
+ PINMUX_IPSR_NOFN(AB_9_8_PORT97, SDI2_CKO, SEL_AB_9_8_01),
+ PINMUX_IPSR_NOFN(AB_9_8_PORT97, CF_INTRQ, SEL_AB_9_8_10),
+ /* M20 */
+ PINMUX_IPSR_NOFN(AB_9_8_PORT98, AB_A22, SEL_AB_9_8_00),
+ PINMUX_IPSR_NOFN(AB_9_8_PORT98, SDI2_CKI, SEL_AB_9_8_01),
+ /* N20 */
+ PINMUX_IPSR_NOFN(AB_9_8_PORT99, AB_A23, SEL_AB_9_8_00),
+ PINMUX_IPSR_NOFN(AB_9_8_PORT99, SDI2_CMD, SEL_AB_9_8_01),
+ /* L18 */
+ PINMUX_IPSR_NOFN(AB_11_10_PORT100, AB_A24, SEL_AB_11_10_00),
+ PINMUX_IPSR_NOFN(AB_11_10_PORT100, CF_INPACKB, SEL_AB_11_10_10),
+ /* M18 */
+ PINMUX_IPSR_NOFN(AB_11_10_PORT101, AB_A25, SEL_AB_11_10_00),
+ PINMUX_IPSR_NOFN(AB_11_10_PORT101, CF_CDB1, SEL_AB_11_10_10),
+ /* N18 */
+ PINMUX_IPSR_NOFN(AB_11_10_PORT102, AB_A26, SEL_AB_11_10_00),
+ PINMUX_IPSR_NOFN(AB_11_10_PORT102, CF_CDB2, SEL_AB_11_10_10),
+ /* L17 */
+ PINMUX_IPSR_NOFN(AB_13_12_PORT103, AB_A27, SEL_AB_13_12_00),
+ PINMUX_IPSR_NOFN(AB_13_12_PORT103, AB_BEN0, SEL_AB_13_12_10),
+ /* M17 */
+ PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_A28, SEL_AB_13_12_00),
+ PINMUX_IPSR_NOFN(AB_13_12_PORT104, AB_BEN1, SEL_AB_13_12_10),
+ /* B8 */
+ PINMUX_DATA(USI0_CS1_MARK, FN_USI0_CS1),
+ /* B9 */
+ PINMUX_DATA(USI0_CS2_MARK, FN_USI0_CS2),
+ /* C10 */
+ PINMUX_DATA(USI1_DI_MARK, FN_USI1_DI),
+ /* D10 */
+ PINMUX_DATA(USI1_DO_MARK, FN_USI1_DO),
+ /* AB5 */
+ PINMUX_IPSR_NOFN(USI_1_0_PORT109, USI2_CLK, SEL_USI_1_0_00),
+ PINMUX_IPSR_NOFN(USI_1_0_PORT109, DTV_BCLK_B, SEL_USI_1_0_01),
+ /* AA6 */
+ PINMUX_IPSR_NOFN(USI_1_0_PORT110, USI2_DI, SEL_USI_1_0_00),
+ PINMUX_IPSR_NOFN(USI_1_0_PORT110, DTV_PSYNC_B, SEL_USI_1_0_01),
+ /* AA5 */
+ PINMUX_IPSR_NOFN(USI_1_0_PORT111, USI2_DO, SEL_USI_1_0_00),
+ PINMUX_IPSR_NOFN(USI_1_0_PORT111, DTV_VALID_B, SEL_USI_1_0_01),
+ /* Y7 */
+ PINMUX_IPSR_NOFN(USI_1_0_PORT112, USI2_CS0, SEL_USI_1_0_00),
+ PINMUX_IPSR_NOFN(USI_1_0_PORT112, DTV_DATA_B, SEL_USI_1_0_01),
+ /* AA7 */
+ PINMUX_IPSR_NOFN(USI_3_2_PORT113, USI2_CS1, SEL_USI_3_2_00),
+ PINMUX_IPSR_NOFN(USI_3_2_PORT113, USI4_CS0, SEL_USI_3_2_01),
+ /* Y6 */
+ PINMUX_IPSR_NOFN(USI_3_2_PORT114, USI2_CS2, SEL_USI_3_2_00),
+ PINMUX_IPSR_NOFN(USI_3_2_PORT114, USI4_CS1, SEL_USI_3_2_01),
+ /* AC5 */
+ PINMUX_IPSR_NOFN(USI_5_4_PORT115, USI3_CLK, SEL_USI_5_4_00),
+ PINMUX_IPSR_NOFN(USI_5_4_PORT115, USI0_CS3, SEL_USI_5_4_01),
+ /* AC4 */
+ PINMUX_IPSR_NOFN(USI_5_4_PORT116, USI3_DI, SEL_USI_5_4_00),
+ PINMUX_IPSR_NOFN(USI_5_4_PORT116, USI0_CS4, SEL_USI_5_4_01),
+ /* AC3 */
+ PINMUX_IPSR_NOFN(USI_5_4_PORT117, USI3_DO, SEL_USI_5_4_00),
+ PINMUX_IPSR_NOFN(USI_5_4_PORT117, USI0_CS5, SEL_USI_5_4_01),
+ /* AB4 */
+ PINMUX_IPSR_NOFN(USI_5_4_PORT118, USI3_CS0, SEL_USI_5_4_00),
+ PINMUX_IPSR_NOFN(USI_5_4_PORT118, USI0_CS6, SEL_USI_5_4_01),
+ /* AB3 */
+ PINMUX_IPSR_NOFN(USI_7_6_PORT119, USI4_CLK, SEL_USI_7_6_01),
+ /* AA4 */
+ PINMUX_IPSR_NOFN(USI_9_8_PORT120, PWM0, SEL_USI_9_8_00),
+ PINMUX_IPSR_NOFN(USI_9_8_PORT120, USI4_DI, SEL_USI_9_8_01),
+ /* Y5 */
+ PINMUX_IPSR_NOFN(USI_9_8_PORT121, PWM1, SEL_USI_9_8_00),
+ PINMUX_IPSR_NOFN(USI_9_8_PORT121, USI4_DO, SEL_USI_9_8_01),
+ /* V20 */
+ PINMUX_DATA(NTSC_CLK_MARK, FN_NTSC_CLK),
+ /* P20 */
+ PINMUX_DATA(NTSC_DATA0_MARK, FN_NTSC_DATA0),
+ /* P18 */
+ PINMUX_DATA(NTSC_DATA1_MARK, FN_NTSC_DATA1),
+ /* R20 */
+ PINMUX_DATA(NTSC_DATA2_MARK, FN_NTSC_DATA2),
+ /* R18 */
+ PINMUX_DATA(NTSC_DATA3_MARK, FN_NTSC_DATA3),
+ /* T20 */
+ PINMUX_DATA(NTSC_DATA4_MARK, FN_NTSC_DATA4),
+
+ /* GPRS3 */
+ /* T18 */
+ PINMUX_DATA(NTSC_DATA5_MARK, FN_NTSC_DATA5),
+ /* U20 */
+ PINMUX_DATA(NTSC_DATA6_MARK, FN_NTSC_DATA6),
+ /* U18 */
+ PINMUX_DATA(NTSC_DATA7_MARK, FN_NTSC_DATA7),
+ /* W23 */
+ PINMUX_DATA(CAM_CLKO_MARK, FN_CAM_CLKO),
+ /* Y23 */
+ PINMUX_DATA(CAM_CLKI_MARK, FN_CAM_CLKI),
+ /* W22 */
+ PINMUX_DATA(CAM_VS_MARK, FN_CAM_VS),
+ /* V21 */
+ PINMUX_DATA(CAM_HS_MARK, FN_CAM_HS),
+ /* T21 */
+ PINMUX_DATA(CAM_YUV0_MARK, FN_CAM_YUV0),
+ /* T22 */
+ PINMUX_DATA(CAM_YUV1_MARK, FN_CAM_YUV1),
+ /* T23 */
+ PINMUX_DATA(CAM_YUV2_MARK, FN_CAM_YUV2),
+ /* U21 */
+ PINMUX_DATA(CAM_YUV3_MARK, FN_CAM_YUV3),
+ /* U22 */
+ PINMUX_DATA(CAM_YUV4_MARK, FN_CAM_YUV4),
+ /* U23 */
+ PINMUX_DATA(CAM_YUV5_MARK, FN_CAM_YUV5),
+ /* V22 */
+ PINMUX_DATA(CAM_YUV6_MARK, FN_CAM_YUV6),
+ /* V23 */
+ PINMUX_DATA(CAM_YUV7_MARK, FN_CAM_YUV7),
+ /* K22 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT143, USI5_CLK_B, SEL_HSI_1_0_01),
+ /* K23 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT144, USI5_DO_B, SEL_HSI_1_0_01),
+ /* L23 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT145, USI5_CS0_B, SEL_HSI_1_0_01),
+ /* L22 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT146, USI5_CS1_B, SEL_HSI_1_0_01),
+ /* N22 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT147, USI5_CS2_B, SEL_HSI_1_0_01),
+ /* N23 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT148, USI5_CS3_B, SEL_HSI_1_0_01),
+ /* M23 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT149, USI5_CS4_B, SEL_HSI_1_0_01),
+ /* M22 */
+ PINMUX_IPSR_NOFN(HSI_1_0_PORT150, USI5_DI_B, SEL_HSI_1_0_01),
+ /* D13 */
+ PINMUX_DATA(JT_TDO_MARK, FN_JT_TDO),
+ /* F13 */
+ PINMUX_DATA(JT_TDOEN_MARK, FN_JT_TDOEN),
+ /* AA12 */
+ PINMUX_DATA(USB_VBUS_MARK, FN_USB_VBUS),
+ /* A12 */
+ PINMUX_DATA(LOWPWR_MARK, FN_LOWPWR),
+ /* Y11 */
+ PINMUX_DATA(UART1_RX_MARK, FN_UART1_RX),
+ /* Y10 */
+ PINMUX_DATA(UART1_TX_MARK, FN_UART1_TX),
+ /* AA10 */
+ PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART1_CTSB, SEL_UART_1_0_00),
+ PINMUX_IPSR_NOFN(UART_1_0_PORT157, UART2_RX, SEL_UART_1_0_01),
+ /* AB10 */
+ PINMUX_IPSR_NOFN(UART_1_0_PORT158, UART1_RTSB, SEL_UART_1_0_00),
+ PINMUX_IPSR_NOFN(UART_1_0_PORT158, UART2_TX, SEL_UART_1_0_01),
+};
+
+
+#define EMEV_MUX_PIN(name, pin, mark) \
+ static const unsigned int name##_pins[] = { pin }; \
+ static const unsigned int name##_mux[] = { mark##_MARK }
+
+/* = [ System ] =========== */
+EMEV_MUX_PIN(err_rst_reqb, 3, ERR_RST_REQB);
+EMEV_MUX_PIN(ref_clko, 4, REF_CLKO);
+EMEV_MUX_PIN(ext_clki, 5, EXT_CLKI);
+EMEV_MUX_PIN(lowpwr, 154, LOWPWR);
+
+/* = [ External Memory] === */
+static const unsigned int ab_main_pins[] = {
+ /* AB_RDB, AB_WRB */
+ 73, 74,
+ /* AB_AD[0:15] */
+ 77, 78, 79, 80,
+ 81, 82, 83, 84,
+ 85, 86, 87, 88,
+ 89, 90, 91, 92,
+};
+static const unsigned int ab_main_mux[] = {
+ AB_RDB_MARK, AB_WRB_MARK,
+ AB_AD0_MARK, AB_AD1_MARK, AB_AD2_MARK, AB_AD3_MARK,
+ AB_AD4_MARK, AB_AD5_MARK, AB_AD6_MARK, AB_AD7_MARK,
+ AB_AD8_MARK, AB_AD9_MARK, AB_AD10_MARK, AB_AD11_MARK,
+ AB_AD12_MARK, AB_AD13_MARK, AB_AD14_MARK, AB_AD15_MARK,
+};
+
+EMEV_MUX_PIN(ab_clk, 68, AB_CLK);
+EMEV_MUX_PIN(ab_csb0, 69, AB_CSB0);
+EMEV_MUX_PIN(ab_csb1, 70, AB_CSB1);
+EMEV_MUX_PIN(ab_csb2, 71, AB_CSB2);
+EMEV_MUX_PIN(ab_csb3, 72, AB_CSB3);
+EMEV_MUX_PIN(ab_wait, 75, AB_WAIT);
+EMEV_MUX_PIN(ab_adv, 76, AB_ADV);
+EMEV_MUX_PIN(ab_a17, 93, AB_A17);
+EMEV_MUX_PIN(ab_a18, 94, AB_A18);
+EMEV_MUX_PIN(ab_a19, 95, AB_A19);
+EMEV_MUX_PIN(ab_a20, 96, AB_A20);
+EMEV_MUX_PIN(ab_a21, 97, AB_A21);
+EMEV_MUX_PIN(ab_a22, 98, AB_A22);
+EMEV_MUX_PIN(ab_a23, 99, AB_A23);
+EMEV_MUX_PIN(ab_a24, 100, AB_A24);
+EMEV_MUX_PIN(ab_a25, 101, AB_A25);
+EMEV_MUX_PIN(ab_a26, 102, AB_A26);
+EMEV_MUX_PIN(ab_a27, 103, AB_A27);
+EMEV_MUX_PIN(ab_a28, 104, AB_A28);
+EMEV_MUX_PIN(ab_ben0, 103, AB_BEN0);
+EMEV_MUX_PIN(ab_ben1, 104, AB_BEN1);
+
+/* = [ CAM ] ============== */
+EMEV_MUX_PIN(cam_clko, 131, CAM_CLKO);
+static const unsigned int cam_pins[] = {
+ /* CLKI, VS, HS */
+ 132, 133, 134,
+ /* CAM_YUV[0:7] */
+ 135, 136, 137, 138,
+ 139, 140, 141, 142,
+};
+static const unsigned int cam_mux[] = {
+ CAM_CLKI_MARK, CAM_VS_MARK, CAM_HS_MARK,
+ CAM_YUV0_MARK, CAM_YUV1_MARK, CAM_YUV2_MARK, CAM_YUV3_MARK,
+ CAM_YUV4_MARK, CAM_YUV5_MARK, CAM_YUV6_MARK, CAM_YUV7_MARK,
+};
+
+/* = [ CF ] -============== */
+static const unsigned int cf_ctrl_pins[] = {
+ /* CSB0, CSB1, IORDB, IOWRB, IORDY, RESET,
+ * A00, A01, A02, INTRQ, INPACKB, CDB1, CDB2 */
+ 71, 72, 73, 74,
+ 75, 76, 93, 94,
+ 95, 97, 100, 101,
+ 102,
+};
+static const unsigned int cf_ctrl_mux[] = {
+ CF_CSB0_MARK, CF_CSB1_MARK, CF_IORDB_MARK, CF_IOWRB_MARK,
+ CF_IORDY_MARK, CF_RESET_MARK, CF_A00_MARK, CF_A01_MARK,
+ CF_A02_MARK, CF_INTRQ_MARK, CF_INPACKB_MARK, CF_CDB1_MARK,
+ CF_CDB2_MARK,
+};
+
+static const unsigned int cf_data8_pins[] = {
+ /* CF_D[0:8] */
+ 77, 78, 79, 80,
+ 81, 82, 83, 84,
+};
+static const unsigned int cf_data8_mux[] = {
+ CF_D00_MARK, CF_D01_MARK, CF_D02_MARK, CF_D03_MARK,
+ CF_D04_MARK, CF_D05_MARK, CF_D06_MARK, CF_D07_MARK,
+};
+static const unsigned int cf_data16_pins[] = {
+ /* CF_D[0:15] */
+ 77, 78, 79, 80,
+ 81, 82, 83, 84,
+ 85, 86, 87, 88,
+ 89, 90, 91, 92,
+};
+static const unsigned int cf_data16_mux[] = {
+ CF_D00_MARK, CF_D01_MARK, CF_D02_MARK, CF_D03_MARK,
+ CF_D04_MARK, CF_D05_MARK, CF_D06_MARK, CF_D07_MARK,
+ CF_D08_MARK, CF_D09_MARK, CF_D10_MARK, CF_D11_MARK,
+ CF_D12_MARK, CF_D13_MARK, CF_D14_MARK, CF_D15_MARK,
+};
+
+/* = [ DTV ] ============== */
+static const unsigned int dtv_a_pins[] = {
+ /* BCLK, PSYNC, VALID, DATA */
+ 85, 86, 87, 88,
+};
+static const unsigned int dtv_a_mux[] = {
+ DTV_BCLK_A_MARK, DTV_PSYNC_A_MARK, DTV_VALID_A_MARK, DTV_DATA_A_MARK,
+};
+
+static const unsigned int dtv_b_pins[] = {
+ /* BCLK, PSYNC, VALID, DATA */
+ 109, 110, 111, 112,
+};
+static const unsigned int dtv_b_mux[] = {
+ DTV_BCLK_B_MARK, DTV_PSYNC_B_MARK, DTV_VALID_B_MARK, DTV_DATA_B_MARK,
+};
+
+/* = [ IIC0 ] ============= */
+static const unsigned int iic0_pins[] = {
+ /* SCL, SDA */
+ 44, 45,
+};
+static const unsigned int iic0_mux[] = {
+ IIC0_SCL_MARK, IIC0_SDA_MARK,
+};
+
+/* = [ IIC1 ] ============= */
+static const unsigned int iic1_pins[] = {
+ /* SCL, SDA */
+ 46, 47,
+};
+static const unsigned int iic1_mux[] = {
+ IIC1_SCL_MARK, IIC1_SDA_MARK,
+};
+
+/* = [ JTAG ] ============= */
+static const unsigned int jtag_pins[] = {
+ /* SEL, TDO, TDOEN */
+ 2, 151, 152,
+};
+static const unsigned int jtag_mux[] = {
+ JT_SEL_MARK, JT_TDO_MARK, JT_TDOEN_MARK,
+};
+
+/* = [ LCD/YUV ] ========== */
+EMEV_MUX_PIN(lcd3_pxclk, 18, LCD3_PXCLK);
+EMEV_MUX_PIN(lcd3_pxclkb, 19, LCD3_PXCLKB);
+EMEV_MUX_PIN(lcd3_clk_i, 20, LCD3_CLK_I);
+
+static const unsigned int lcd3_sync_pins[] = {
+ /* HS, VS, DE */
+ 21, 22, 23,
+};
+static const unsigned int lcd3_sync_mux[] = {
+ LCD3_HS_MARK, LCD3_VS_MARK, LCD3_DE_MARK,
+};
+
+static const unsigned int lcd3_rgb888_pins[] = {
+ /* R[0:7], G[0:7], B[0:7] */
+ 32, 33, 34, 35,
+ 36, 37, 38, 39,
+ 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
+ PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
+ PIN_NUMBER(4, 16),
+ 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
+ PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
+ PIN_NUMBER(4, 14)
+};
+static const unsigned int lcd3_rgb888_mux[] = {
+ LCD3_R0_MARK, LCD3_R1_MARK, LCD3_R2_MARK, LCD3_R3_MARK,
+ LCD3_R4_MARK, LCD3_R5_MARK, LCD3_R6_MARK, LCD3_R7_MARK,
+ LCD3_G0_MARK, LCD3_G1_MARK, LCD3_G2_MARK, LCD3_G3_MARK,
+ LCD3_G4_MARK, LCD3_G5_MARK, LCD3_G6_MARK, LCD3_G7_MARK,
+ LCD3_B0_MARK, LCD3_B1_MARK, LCD3_B2_MARK, LCD3_B3_MARK,
+ LCD3_B4_MARK, LCD3_B5_MARK, LCD3_B6_MARK, LCD3_B7_MARK,
+};
+
+EMEV_MUX_PIN(yuv3_clk_i, 20, YUV3_CLK_I);
+static const unsigned int yuv3_pins[] = {
+ /* CLK_O, HS, VS, DE */
+ 18, 21, 22, 23,
+ /* YUV3_D[0:15] */
+ 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
+ PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
+ PIN_NUMBER(4, 16),
+ 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
+ PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
+ PIN_NUMBER(4, 14),
+};
+static const unsigned int yuv3_mux[] = {
+ YUV3_CLK_O_MARK, YUV3_HS_MARK, YUV3_VS_MARK, YUV3_DE_MARK,
+ YUV3_D0_MARK, YUV3_D1_MARK, YUV3_D2_MARK, YUV3_D3_MARK,
+ YUV3_D4_MARK, YUV3_D5_MARK, YUV3_D6_MARK, YUV3_D7_MARK,
+ YUV3_D8_MARK, YUV3_D9_MARK, YUV3_D10_MARK, YUV3_D11_MARK,
+ YUV3_D12_MARK, YUV3_D13_MARK, YUV3_D14_MARK, YUV3_D15_MARK,
+};
+
+/* = [ NTSC ] ============= */
+EMEV_MUX_PIN(ntsc_clk, 122, NTSC_CLK);
+static const unsigned int ntsc_data_pins[] = {
+ /* NTSC_DATA[0:7] */
+ 123, 124, 125, 126,
+ 127, 128, 129, 130,
+};
+static const unsigned int ntsc_data_mux[] = {
+ NTSC_DATA0_MARK, NTSC_DATA1_MARK, NTSC_DATA2_MARK, NTSC_DATA3_MARK,
+ NTSC_DATA4_MARK, NTSC_DATA5_MARK, NTSC_DATA6_MARK, NTSC_DATA7_MARK,
+};
+
+/* = [ PWM0 ] ============= */
+EMEV_MUX_PIN(pwm0, 120, PWM0);
+
+/* = [ PWM1 ] ============= */
+EMEV_MUX_PIN(pwm1, 121, PWM1);
+
+/* = [ SD ] =============== */
+EMEV_MUX_PIN(sd_cki, 48, SD_CKI);
+
+/* = [ SDIO0 ] ============ */
+static const unsigned int sdi0_ctrl_pins[] = {
+ /* CKO, CKI, CMD */
+ 50, 51, 52,
+};
+static const unsigned int sdi0_ctrl_mux[] = {
+ SDI0_CKO_MARK, SDI0_CKI_MARK, SDI0_CMD_MARK,
+};
+
+static const unsigned int sdi0_data1_pins[] = {
+ /* SDI0_DATA[0] */
+ 53,
+};
+static const unsigned int sdi0_data1_mux[] = {
+ SDI0_DATA0_MARK,
+};
+static const unsigned int sdi0_data4_pins[] = {
+ /* SDI0_DATA[0:3] */
+ 53, 54, 55, 56,
+};
+static const unsigned int sdi0_data4_mux[] = {
+ SDI0_DATA0_MARK, SDI0_DATA1_MARK, SDI0_DATA2_MARK, SDI0_DATA3_MARK,
+};
+static const unsigned int sdi0_data8_pins[] = {
+ /* SDI0_DATA[0:7] */
+ 53, 54, 55, 56,
+ 57, 58, 59, 60
+};
+static const unsigned int sdi0_data8_mux[] = {
+ SDI0_DATA0_MARK, SDI0_DATA1_MARK, SDI0_DATA2_MARK, SDI0_DATA3_MARK,
+ SDI0_DATA4_MARK, SDI0_DATA5_MARK, SDI0_DATA6_MARK, SDI0_DATA7_MARK,
+};
+
+/* = [ SDIO1 ] ============ */
+static const unsigned int sdi1_ctrl_pins[] = {
+ /* CKO, CKI, CMD */
+ 61, 62, 63,
+};
+static const unsigned int sdi1_ctrl_mux[] = {
+ SDI1_CKO_MARK, SDI1_CKI_MARK, SDI1_CMD_MARK,
+};
+
+static const unsigned int sdi1_data1_pins[] = {
+ /* SDI1_DATA[0] */
+ 64,
+};
+static const unsigned int sdi1_data1_mux[] = {
+ SDI1_DATA0_MARK,
+};
+static const unsigned int sdi1_data4_pins[] = {
+ /* SDI1_DATA[0:3] */
+ 64, 65, 66, 67,
+};
+static const unsigned int sdi1_data4_mux[] = {
+ SDI1_DATA0_MARK, SDI1_DATA1_MARK, SDI1_DATA2_MARK, SDI1_DATA3_MARK,
+};
+
+/* = [ SDIO2 ] ============ */
+static const unsigned int sdi2_ctrl_pins[] = {
+ /* CKO, CKI, CMD */
+ 97, 98, 99,
+};
+static const unsigned int sdi2_ctrl_mux[] = {
+ SDI2_CKO_MARK, SDI2_CKI_MARK, SDI2_CMD_MARK,
+};
+
+static const unsigned int sdi2_data1_pins[] = {
+ /* SDI2_DATA[0] */
+ 89,
+};
+static const unsigned int sdi2_data1_mux[] = {
+ SDI2_DATA0_MARK,
+};
+static const unsigned int sdi2_data4_pins[] = {
+ /* SDI2_DATA[0:3] */
+ 89, 90, 91, 92,
+};
+static const unsigned int sdi2_data4_mux[] = {
+ SDI2_DATA0_MARK, SDI2_DATA1_MARK, SDI2_DATA2_MARK, SDI2_DATA3_MARK,
+};
+
+/* = [ TP33 ] ============= */
+static const unsigned int tp33_pins[] = {
+ /* CLK, CTRL */
+ 38, 39,
+ /* TP33_DATA[0:15] */
+ 40, 41, PIN_NUMBER(2, 17), PIN_NUMBER(3, 17),
+ PIN_NUMBER(4, 17), PIN_NUMBER(2, 16), PIN_NUMBER(3, 16),
+ PIN_NUMBER(4, 16),
+ 42, 43, PIN_NUMBER(2, 15), PIN_NUMBER(3, 15),
+ PIN_NUMBER(4, 15), PIN_NUMBER(2, 14), PIN_NUMBER(3, 14),
+ PIN_NUMBER(4, 14),
+};
+static const unsigned int tp33_mux[] = {
+ TP33_CLK_MARK, TP33_CTRL_MARK,
+ TP33_DATA0_MARK, TP33_DATA1_MARK, TP33_DATA2_MARK, TP33_DATA3_MARK,
+ TP33_DATA4_MARK, TP33_DATA5_MARK, TP33_DATA6_MARK, TP33_DATA7_MARK,
+ TP33_DATA8_MARK, TP33_DATA9_MARK, TP33_DATA10_MARK, TP33_DATA11_MARK,
+ TP33_DATA12_MARK, TP33_DATA13_MARK, TP33_DATA14_MARK, TP33_DATA15_MARK,
+};
+
+/* = [ UART1 ] ============ */
+static const unsigned int uart1_data_pins[] = {
+ /* RX, TX */
+ 155, 156,
+};
+static const unsigned int uart1_data_mux[] = {
+ UART1_RX_MARK, UART1_TX_MARK,
+};
+
+static const unsigned int uart1_ctrl_pins[] = {
+ /* CTSB, RTSB */
+ 157, 158,
+};
+static const unsigned int uart1_ctrl_mux[] = {
+ UART1_CTSB_MARK, UART1_RTSB_MARK,
+};
+
+/* = [ UART2 ] ============ */
+static const unsigned int uart2_data_pins[] = {
+ /* RX, TX */
+ 157, 158,
+};
+static const unsigned int uart2_data_mux[] = {
+ UART2_RX_MARK, UART2_TX_MARK,
+};
+
+/* = [ UART3 ] ============ */
+static const unsigned int uart3_data_pins[] = {
+ /* RX, TX */
+ 46, 47,
+};
+static const unsigned int uart3_data_mux[] = {
+ UART3_RX_MARK, UART3_TX_MARK,
+};
+
+/* = [ USB ] ============== */
+EMEV_MUX_PIN(usb_vbus, 153, USB_VBUS);
+
+/* = [ USI0 ] ============== */
+EMEV_MUX_PIN(usi0_cs1, 105, USI0_CS1);
+EMEV_MUX_PIN(usi0_cs2, 106, USI0_CS2);
+EMEV_MUX_PIN(usi0_cs3, 115, USI0_CS3);
+EMEV_MUX_PIN(usi0_cs4, 116, USI0_CS4);
+EMEV_MUX_PIN(usi0_cs5, 117, USI0_CS5);
+EMEV_MUX_PIN(usi0_cs6, 118, USI0_CS6);
+
+/* = [ USI1 ] ============== */
+static const unsigned int usi1_pins[] = {
+ /* DI, DO*/
+ 107, 108,
+};
+static const unsigned int usi1_mux[] = {
+ USI1_DI_MARK, USI1_DO_MARK,
+};
+
+/* = [ USI2 ] ============== */
+static const unsigned int usi2_pins[] = {
+ /* CLK, DI, DO*/
+ 109, 110, 111,
+};
+static const unsigned int usi2_mux[] = {
+ USI2_CLK_MARK, USI2_DI_MARK, USI2_DO_MARK,
+};
+EMEV_MUX_PIN(usi2_cs0, 112, USI2_CS0);
+EMEV_MUX_PIN(usi2_cs1, 113, USI2_CS1);
+EMEV_MUX_PIN(usi2_cs2, 114, USI2_CS2);
+
+/* = [ USI3 ] ============== */
+static const unsigned int usi3_pins[] = {
+ /* CLK, DI, DO*/
+ 115, 116, 117,
+};
+static const unsigned int usi3_mux[] = {
+ USI3_CLK_MARK, USI3_DI_MARK, USI3_DO_MARK,
+};
+EMEV_MUX_PIN(usi3_cs0, 118, USI3_CS0);
+
+/* = [ USI4 ] ============== */
+static const unsigned int usi4_pins[] = {
+ /* CLK, DI, DO*/
+ 119, 120, 121,
+};
+static const unsigned int usi4_mux[] = {
+ USI4_CLK_MARK, USI4_DI_MARK, USI4_DO_MARK,
+};
+EMEV_MUX_PIN(usi4_cs0, 113, USI4_CS0);
+EMEV_MUX_PIN(usi4_cs1, 114, USI4_CS1);
+
+/* = [ USI5 ] ============== */
+static const unsigned int usi5_a_pins[] = {
+ /* CLK, DI, DO*/
+ 85, 86, 87,
+};
+static const unsigned int usi5_a_mux[] = {
+ USI5_CLK_A_MARK, USI5_DI_A_MARK, USI5_DO_A_MARK,
+};
+EMEV_MUX_PIN(usi5_cs0_a, 88, USI5_CS0_A);
+EMEV_MUX_PIN(usi5_cs1_a, 89, USI5_CS1_A);
+EMEV_MUX_PIN(usi5_cs2_a, 90, USI5_CS2_A);
+
+static const unsigned int usi5_b_pins[] = {
+ /* CLK, DI, DO*/
+ 143, 144, 150,
+};
+static const unsigned int usi5_b_mux[] = {
+ USI5_CLK_B_MARK, USI5_DI_B_MARK, USI5_DO_B_MARK,
+};
+EMEV_MUX_PIN(usi5_cs0_b, 145, USI5_CS0_B);
+EMEV_MUX_PIN(usi5_cs1_b, 146, USI5_CS1_B);
+EMEV_MUX_PIN(usi5_cs2_b, 147, USI5_CS2_B);
+EMEV_MUX_PIN(usi5_cs3_b, 148, USI5_CS3_B);
+EMEV_MUX_PIN(usi5_cs4_b, 149, USI5_CS4_B);
+
+static const struct sh_pfc_pin_group pinmux_groups[] = {
+ SH_PFC_PIN_GROUP(err_rst_reqb),
+ SH_PFC_PIN_GROUP(ref_clko),
+ SH_PFC_PIN_GROUP(ext_clki),
+ SH_PFC_PIN_GROUP(lowpwr),
+
+ SH_PFC_PIN_GROUP(ab_main),
+ SH_PFC_PIN_GROUP(ab_clk),
+ SH_PFC_PIN_GROUP(ab_csb0),
+ SH_PFC_PIN_GROUP(ab_csb1),
+ SH_PFC_PIN_GROUP(ab_csb2),
+ SH_PFC_PIN_GROUP(ab_csb3),
+ SH_PFC_PIN_GROUP(ab_wait),
+ SH_PFC_PIN_GROUP(ab_adv),
+ SH_PFC_PIN_GROUP(ab_a17),
+ SH_PFC_PIN_GROUP(ab_a18),
+ SH_PFC_PIN_GROUP(ab_a19),
+ SH_PFC_PIN_GROUP(ab_a20),
+ SH_PFC_PIN_GROUP(ab_a21),
+ SH_PFC_PIN_GROUP(ab_a22),
+ SH_PFC_PIN_GROUP(ab_a23),
+ SH_PFC_PIN_GROUP(ab_a24),
+ SH_PFC_PIN_GROUP(ab_a25),
+ SH_PFC_PIN_GROUP(ab_a26),
+ SH_PFC_PIN_GROUP(ab_a27),
+ SH_PFC_PIN_GROUP(ab_a28),
+ SH_PFC_PIN_GROUP(ab_ben0),
+ SH_PFC_PIN_GROUP(ab_ben1),
+
+ SH_PFC_PIN_GROUP(cam_clko),
+ SH_PFC_PIN_GROUP(cam),
+
+ SH_PFC_PIN_GROUP(cf_ctrl),
+ SH_PFC_PIN_GROUP(cf_data8),
+ SH_PFC_PIN_GROUP(cf_data16),
+
+ SH_PFC_PIN_GROUP(dtv_a),
+ SH_PFC_PIN_GROUP(dtv_b),
+
+ SH_PFC_PIN_GROUP(iic0),
+
+ SH_PFC_PIN_GROUP(iic1),
+
+ SH_PFC_PIN_GROUP(jtag),
+
+ SH_PFC_PIN_GROUP(lcd3_pxclk),
+ SH_PFC_PIN_GROUP(lcd3_pxclkb),
+ SH_PFC_PIN_GROUP(lcd3_clk_i),
+ SH_PFC_PIN_GROUP(lcd3_sync),
+ SH_PFC_PIN_GROUP(lcd3_rgb888),
+ SH_PFC_PIN_GROUP(yuv3_clk_i),
+ SH_PFC_PIN_GROUP(yuv3),
+
+ SH_PFC_PIN_GROUP(ntsc_clk),
+ SH_PFC_PIN_GROUP(ntsc_data),
+
+ SH_PFC_PIN_GROUP(pwm0),
+
+ SH_PFC_PIN_GROUP(pwm1),
+
+ SH_PFC_PIN_GROUP(sd_cki),
+
+ SH_PFC_PIN_GROUP(sdi0_ctrl),
+ SH_PFC_PIN_GROUP(sdi0_data1),
+ SH_PFC_PIN_GROUP(sdi0_data4),
+ SH_PFC_PIN_GROUP(sdi0_data8),
+
+ SH_PFC_PIN_GROUP(sdi1_ctrl),
+ SH_PFC_PIN_GROUP(sdi1_data1),
+ SH_PFC_PIN_GROUP(sdi1_data4),
+
+ SH_PFC_PIN_GROUP(sdi2_ctrl),
+ SH_PFC_PIN_GROUP(sdi2_data1),
+ SH_PFC_PIN_GROUP(sdi2_data4),
+
+ SH_PFC_PIN_GROUP(tp33),
+
+ SH_PFC_PIN_GROUP(uart1_data),
+ SH_PFC_PIN_GROUP(uart1_ctrl),
+
+ SH_PFC_PIN_GROUP(uart2_data),
+
+ SH_PFC_PIN_GROUP(uart3_data),
+
+ SH_PFC_PIN_GROUP(usb_vbus),
+
+ SH_PFC_PIN_GROUP(usi0_cs1),
+ SH_PFC_PIN_GROUP(usi0_cs2),
+ SH_PFC_PIN_GROUP(usi0_cs3),
+ SH_PFC_PIN_GROUP(usi0_cs4),
+ SH_PFC_PIN_GROUP(usi0_cs5),
+ SH_PFC_PIN_GROUP(usi0_cs6),
+
+ SH_PFC_PIN_GROUP(usi1),
+
+ SH_PFC_PIN_GROUP(usi2),
+ SH_PFC_PIN_GROUP(usi2_cs0),
+ SH_PFC_PIN_GROUP(usi2_cs1),
+ SH_PFC_PIN_GROUP(usi2_cs2),
+
+ SH_PFC_PIN_GROUP(usi3),
+ SH_PFC_PIN_GROUP(usi3_cs0),
+
+ SH_PFC_PIN_GROUP(usi4),
+ SH_PFC_PIN_GROUP(usi4_cs0),
+ SH_PFC_PIN_GROUP(usi4_cs1),
+
+ SH_PFC_PIN_GROUP(usi5_a),
+ SH_PFC_PIN_GROUP(usi5_cs0_a),
+ SH_PFC_PIN_GROUP(usi5_cs1_a),
+ SH_PFC_PIN_GROUP(usi5_cs2_a),
+ SH_PFC_PIN_GROUP(usi5_b),
+ SH_PFC_PIN_GROUP(usi5_cs0_b),
+ SH_PFC_PIN_GROUP(usi5_cs1_b),
+ SH_PFC_PIN_GROUP(usi5_cs2_b),
+ SH_PFC_PIN_GROUP(usi5_cs3_b),
+ SH_PFC_PIN_GROUP(usi5_cs4_b),
+};
+
+static const char * const ab_groups[] = {
+ "ab_main",
+ "ab_clk",
+ "ab_csb0",
+ "ab_csb1",
+ "ab_csb2",
+ "ab_csb3",
+ "ab_wait",
+ "ab_adv",
+ "ab_a17",
+ "ab_a18",
+ "ab_a19",
+ "ab_a20",
+ "ab_a21",
+ "ab_a22",
+ "ab_a23",
+ "ab_a24",
+ "ab_a25",
+ "ab_a26",
+ "ab_a27",
+ "ab_a28",
+ "ab_ben0",
+ "ab_ben1",
+};
+
+static const char * const cam_groups[] = {
+ "cam_clko",
+ "cam",
+};
+
+static const char * const cf_groups[] = {
+ "cf_ctrl",
+ "cf_data8",
+ "cf_data16",
+};
+
+static const char * const dtv_groups[] = {
+ "dtv_a",
+ "dtv_b",
+};
+
+static const char * const iic0_groups[] = {
+ "iic0",
+};
+
+static const char * const iic1_groups[] = {
+ "iic1",
+};
+
+static const char * const jtag_groups[] = {
+ "jtag",
+};
+
+static const char * const lcd_groups[] = {
+ "lcd3_pxclk",
+ "lcd3_pxclkb",
+ "lcd3_clk_i",
+ "lcd3_sync",
+ "lcd3_rgb888",
+ "yuv3_clk_i",
+ "yuv3",
+};
+
+static const char * const ntsc_groups[] = {
+ "ntsc_clk",
+ "ntsc_data",
+};
+
+static const char * const pwm0_groups[] = {
+ "pwm0",
+};
+
+static const char * const pwm1_groups[] = {
+ "pwm1",
+};
+
+static const char * const sd_groups[] = {
+ "sd_cki",
+};
+
+static const char * const sdi0_groups[] = {
+ "sdi0_ctrl",
+ "sdi0_data1",
+ "sdi0_data4",
+ "sdi0_data8",
+};
+
+static const char * const sdi1_groups[] = {
+ "sdi1_ctrl",
+ "sdi1_data1",
+ "sdi1_data4",
+};
+
+static const char * const sdi2_groups[] = {
+ "sdi2_ctrl",
+ "sdi2_data1",
+ "sdi2_data4",
+};
+
+static const char * const tp33_groups[] = {
+ "tp33",
+};
+
+static const char * const uart1_groups[] = {
+ "uart1_data",
+ "uart1_ctrl",
+};
+
+static const char * const uart2_groups[] = {
+ "uart2_data",
+};
+
+static const char * const uart3_groups[] = {
+ "uart3_data",
+};
+
+static const char * const usb_groups[] = {
+ "usb_vbus",
+};
+
+static const char * const usi0_groups[] = {
+ "usi0_cs1",
+ "usi0_cs2",
+ "usi0_cs3",
+ "usi0_cs4",
+ "usi0_cs5",
+ "usi0_cs6",
+};
+
+static const char * const usi1_groups[] = {
+ "usi1",
+};
+
+static const char * const usi2_groups[] = {
+ "usi2",
+ "usi2_cs0",
+ "usi2_cs1",
+ "usi2_cs2",
+};
+
+static const char * const usi3_groups[] = {
+ "usi3",
+ "usi3_cs0",
+};
+
+static const char * const usi4_groups[] = {
+ "usi4",
+ "usi4_cs0",
+ "usi4_cs1",
+};
+
+static const char * const usi5_groups[] = {
+ "usi5_a",
+ "usi5_cs0_a",
+ "usi5_cs1_a",
+ "usi5_cs2_a",
+ "usi5_b",
+ "usi5_cs0_b",
+ "usi5_cs1_b",
+ "usi5_cs2_b",
+ "usi5_cs3_b",
+ "usi5_cs4_b",
+};
+
+static const struct sh_pfc_function pinmux_functions[] = {
+ SH_PFC_FUNCTION(ab),
+ SH_PFC_FUNCTION(cam),
+ SH_PFC_FUNCTION(cf),
+ SH_PFC_FUNCTION(dtv),
+ SH_PFC_FUNCTION(iic0),
+ SH_PFC_FUNCTION(iic1),
+ SH_PFC_FUNCTION(jtag),
+ SH_PFC_FUNCTION(lcd),
+ SH_PFC_FUNCTION(ntsc),
+ SH_PFC_FUNCTION(pwm0),
+ SH_PFC_FUNCTION(pwm1),
+ SH_PFC_FUNCTION(sd),
+ SH_PFC_FUNCTION(sdi0),
+ SH_PFC_FUNCTION(sdi1),
+ SH_PFC_FUNCTION(sdi2),
+ SH_PFC_FUNCTION(tp33),
+ SH_PFC_FUNCTION(uart1),
+ SH_PFC_FUNCTION(uart2),
+ SH_PFC_FUNCTION(uart3),
+ SH_PFC_FUNCTION(usb),
+ SH_PFC_FUNCTION(usi0),
+ SH_PFC_FUNCTION(usi1),
+ SH_PFC_FUNCTION(usi2),
+ SH_PFC_FUNCTION(usi3),
+ SH_PFC_FUNCTION(usi4),
+ SH_PFC_FUNCTION(usi5),
+};
+
+static const struct pinmux_cfg_reg pinmux_config_regs[] = {
+ { PINMUX_CFG_REG("GPSR0", 0xe0140200, 32, 1) {
+ 0, PORT31_FN, /* PIN: J18 */
+ 0, PORT30_FN, /* PIN: H18 */
+ 0, PORT29_FN, /* PIN: G18 */
+ 0, PORT28_FN, /* PIN: F18 */
+ 0, PORT27_FN, /* PIN: F17 */
+ 0, PORT26_FN, /* PIN: F16 */
+ 0, PORT25_FN, /* PIN: E20 */
+ 0, PORT24_FN, /* PIN: D20 */
+ FN_LCD3_1_0_PORT23, PORT23_FN, /* PIN: D19 */
+ FN_LCD3_1_0_PORT22, PORT22_FN, /* PIN: C20 */
+ FN_LCD3_1_0_PORT21, PORT21_FN, /* PIN: B21 */
+ FN_LCD3_1_0_PORT20, PORT20_FN, /* PIN: A21 */
+ FN_LCD3_PXCLKB, PORT19_FN, /* PIN: C21 */
+ FN_LCD3_1_0_PORT18, PORT18_FN, /* PIN: B22 */
+ 0, PORT17_FN, /* PIN: W20 */
+ 0, PORT16_FN, /* PIN: W21 */
+ 0, PORT15_FN, /* PIN: Y19 */
+ 0, PORT14_FN, /* PIN: Y20 */
+ 0, PORT13_FN, /* PIN: Y21 */
+ 0, PORT12_FN, /* PIN: AA20 */
+ 0, PORT11_FN, /* PIN: AA21 */
+ 0, PORT10_FN, /* PIN: AA22 */
+ 0, PORT9_FN, /* PIN: V15 */
+ 0, PORT8_FN, /* PIN: V16 */
+ 0, PORT7_FN, /* PIN: V17 */
+ 0, PORT6_FN, /* PIN: V18 */
+ FN_EXT_CLKI, PORT5_FN, /* PIN: U8 */
+ FN_REF_CLKO, PORT4_FN, /* PIN: V8 */
+ FN_ERR_RST_REQB, PORT3_FN, /* PIN: U9 */
+ FN_JT_SEL, PORT2_FN, /* PIN: V9 */
+ 0, PORT1_FN, /* PIN: U10 */
+ 0, PORT0_FN, /* PIN: V10 */
+ }
+ },
+ { PINMUX_CFG_REG("GPSR1", 0xe0140204, 32, 1) {
+ FN_SDI1_CMD, PORT63_FN, /* PIN: AC21 */
+ FN_SDI1_CKI, PORT62_FN, /* PIN: AA23 */
+ FN_SDI1_CKO, PORT61_FN, /* PIN: AB22 */
+ FN_SDI0_DATA7, PORT60_FN, /* PIN: Y16 */
+ FN_SDI0_DATA6, PORT59_FN, /* PIN: AA16 */
+ FN_SDI0_DATA5, PORT58_FN, /* PIN: Y15 */
+ FN_SDI0_DATA4, PORT57_FN, /* PIN: AA15 */
+ FN_SDI0_DATA3, PORT56_FN, /* PIN: Y14 */
+ FN_SDI0_DATA2, PORT55_FN, /* PIN: AA14 */
+ FN_SDI0_DATA1, PORT54_FN, /* PIN: Y13 */
+ FN_SDI0_DATA0, PORT53_FN, /* PIN: AA13 */
+ FN_SDI0_CMD, PORT52_FN, /* PIN: Y12 */
+ FN_SDI0_CKI, PORT51_FN, /* PIN: AC18 */
+ FN_SDI0_CKO, PORT50_FN, /* PIN: AB18 */
+ 0, PORT49_FN, /* PIN: AB16 */
+ FN_SD_CKI, PORT48_FN, /* PIN: AC19 */
+ FN_IIC_1_0_PORT47, PORT47_FN, /* PIN: Y8 */
+ FN_IIC_1_0_PORT46, PORT46_FN, /* PIN: Y9 */
+ FN_IIC0_SDA, PORT45_FN, /* PIN: AA8 */
+ FN_IIC0_SCL, PORT44_FN, /* PIN: AA9 */
+ FN_LCD3_11_10_PORT43, PORT43_FN, /* PIN: A15 */
+ FN_LCD3_11_10_PORT42, PORT42_FN, /* PIN: A16 */
+ FN_LCD3_11_10_PORT41, PORT41_FN, /* PIN: A17 */
+ FN_LCD3_11_10_PORT40, PORT40_FN, /* PIN: A18 */
+ FN_LCD3_9_8_PORT39, PORT39_FN, /* PIN: D18 */
+ FN_LCD3_9_8_PORT38, PORT38_FN, /* PIN: C18 */
+ FN_LCD3_R5, PORT37_FN, /* PIN: B18 */
+ FN_LCD3_R4, PORT36_FN, /* PIN: C19 */
+ FN_LCD3_R3, PORT35_FN, /* PIN: B19 */
+ FN_LCD3_R2, PORT34_FN, /* PIN: A19 */
+ FN_LCD3_R1, PORT33_FN, /* PIN: B20 */
+ FN_LCD3_R0, PORT32_FN, /* PIN: A20 */
+ }
+ },
+ { PINMUX_CFG_REG("GPSR2", 0xe0140208, 32, 1) {
+ FN_AB_1_0_PORT95, PORT95_FN, /* PIN: L21 */
+ FN_AB_1_0_PORT94, PORT94_FN, /* PIN: K21 */
+ FN_AB_1_0_PORT93, PORT93_FN, /* PIN: J21 */
+ FN_AB_7_6_PORT92, PORT92_FN, /* PIN: J22 */
+ FN_AB_7_6_PORT91, PORT91_FN, /* PIN: H21 */
+ FN_AB_5_4_PORT90, PORT90_FN, /* PIN: H22 */
+ FN_AB_5_4_PORT89, PORT89_FN, /* PIN: H23 */
+ FN_AB_3_2_PORT88, PORT88_FN, /* PIN: G21 */
+ FN_AB_3_2_PORT87, PORT87_FN, /* PIN: G22 */
+ FN_AB_3_2_PORT86, PORT86_FN, /* PIN: G23 */
+ FN_AB_3_2_PORT85, PORT85_FN, /* PIN: F21 */
+ FN_AB_1_0_PORT84, PORT84_FN, /* PIN: F22 */
+ FN_AB_1_0_PORT83, PORT83_FN, /* PIN: F23 */
+ FN_AB_1_0_PORT82, PORT82_FN, /* PIN: E22 */
+ FN_AB_1_0_PORT81, PORT81_FN, /* PIN: E23 */
+ FN_AB_1_0_PORT80, PORT80_FN, /* PIN: D22 */
+ FN_AB_1_0_PORT79, PORT79_FN, /* PIN: D23 */
+ FN_AB_1_0_PORT78, PORT78_FN, /* PIN: C22 */
+ FN_AB_1_0_PORT77, PORT77_FN, /* PIN: C23 */
+ FN_AB_1_0_PORT76, PORT76_FN, /* PIN: K20 */
+ FN_AB_1_0_PORT75, PORT75_FN, /* PIN: L20 */
+ FN_AB_1_0_PORT74, PORT74_FN, /* PIN: H20 */
+ FN_AB_1_0_PORT73, PORT73_FN, /* PIN: J20 */
+ FN_AB_1_0_PORT72, PORT72_FN, /* PIN: G20 */
+ FN_AB_1_0_PORT71, PORT71_FN, /* PIN: F20 */
+ FN_AB_CSB1, PORT70_FN, /* PIN: E21 */
+ FN_AB_CSB0, PORT69_FN, /* PIN: D21 */
+ FN_AB_CLK, PORT68_FN, /* PIN: J23 */
+ FN_SDI1_DATA3, PORT67_FN, /* PIN: AA19 */
+ FN_SDI1_DATA2, PORT66_FN, /* PIN: AB19 */
+ FN_SDI1_DATA1, PORT65_FN, /* PIN: AB20 */
+ FN_SDI1_DATA0, PORT64_FN, /* PIN: AB21 */
+ }
+ },
+ { PINMUX_CFG_REG("GPSR3", 0xe014020c, 32, 1) {
+ FN_NTSC_DATA4, PORT127_FN, /* PIN: T20 */
+ FN_NTSC_DATA3, PORT126_FN, /* PIN: R18 */
+ FN_NTSC_DATA2, PORT125_FN, /* PIN: R20 */
+ FN_NTSC_DATA1, PORT124_FN, /* PIN: P18 */
+ FN_NTSC_DATA0, PORT123_FN, /* PIN: P20 */
+ FN_NTSC_CLK, PORT122_FN, /* PIN: V20 */
+ FN_USI_9_8_PORT121, PORT121_FN, /* PIN: Y5 */
+ FN_USI_9_8_PORT120, PORT120_FN, /* PIN: AA4 */
+ FN_USI_7_6_PORT119, PORT119_FN, /* PIN: AB3 */
+ FN_USI_5_4_PORT118, PORT118_FN, /* PIN: AB4 */
+ FN_USI_5_4_PORT117, PORT117_FN, /* PIN: AC3 */
+ FN_USI_5_4_PORT116, PORT116_FN, /* PIN: AC4 */
+ FN_USI_5_4_PORT115, PORT115_FN, /* PIN: AC5 */
+ FN_USI_3_2_PORT114, PORT114_FN, /* PIN: Y6 */
+ FN_USI_3_2_PORT113, PORT113_FN, /* PIN: AA7 */
+ FN_USI_1_0_PORT112, PORT112_FN, /* PIN: Y7 */
+ FN_USI_1_0_PORT111, PORT111_FN, /* PIN: AA5 */
+ FN_USI_1_0_PORT110, PORT110_FN, /* PIN: AA6 */
+ FN_USI_1_0_PORT109, PORT109_FN, /* PIN: AB5 */
+ FN_USI1_DO, PORT108_FN, /* PIN: D10 */
+ FN_USI1_DI, PORT107_FN, /* PIN: C10 */
+ FN_USI0_CS2, PORT106_FN, /* PIN: B9 */
+ FN_USI0_CS1, PORT105_FN, /* PIN: B8 */
+ FN_AB_13_12_PORT104, PORT104_FN, /* PIN: M17 */
+ FN_AB_13_12_PORT103, PORT103_FN, /* PIN: L17 */
+ FN_AB_11_10_PORT102, PORT102_FN, /* PIN: N18 */
+ FN_AB_11_10_PORT101, PORT101_FN, /* PIN: M18 */
+ FN_AB_11_10_PORT100, PORT100_FN, /* PIN: L18 */
+ FN_AB_9_8_PORT99, PORT99_FN, /* PIN: N20 */
+ FN_AB_9_8_PORT98, PORT98_FN, /* PIN: M20 */
+ FN_AB_9_8_PORT97, PORT97_FN, /* PIN: N21 */
+ FN_AB_A20, PORT96_FN, /* PIN: M21 */
+ }
+ },
+ { PINMUX_CFG_REG("GPSR4", 0xe0140210, 32, 1) {
+ 0, 0,
+ FN_UART_1_0_PORT158, PORT158_FN, /* PIN: AB10 */
+ FN_UART_1_0_PORT157, PORT157_FN, /* PIN: AA10 */
+ FN_UART1_TX, PORT156_FN, /* PIN: Y10 */
+ FN_UART1_RX, PORT155_FN, /* PIN: Y11 */
+ FN_LOWPWR, PORT154_FN, /* PIN: A12 */
+ FN_USB_VBUS, PORT153_FN, /* PIN: AA12 */
+ FN_JT_TDOEN, PORT152_FN, /* PIN: F13 */
+ FN_JT_TDO, PORT151_FN, /* PIN: D13 */
+ FN_HSI_1_0_PORT150, PORT150_FN, /* PIN: M22 */
+ FN_HSI_1_0_PORT149, PORT149_FN, /* PIN: M23 */
+ FN_HSI_1_0_PORT148, PORT148_FN, /* PIN: N23 */
+ FN_HSI_1_0_PORT147, PORT147_FN, /* PIN: N22 */
+ FN_HSI_1_0_PORT146, PORT146_FN, /* PIN: L22 */
+ FN_HSI_1_0_PORT145, PORT145_FN, /* PIN: L23 */
+ FN_HSI_1_0_PORT144, PORT144_FN, /* PIN: K23 */
+ FN_HSI_1_0_PORT143, PORT143_FN, /* PIN: K22 */
+ FN_CAM_YUV7, PORT142_FN, /* PIN: V23 */
+ FN_CAM_YUV6, PORT141_FN, /* PIN: V22 */
+ FN_CAM_YUV5, PORT140_FN, /* PIN: U23 */
+ FN_CAM_YUV4, PORT139_FN, /* PIN: U22 */
+ FN_CAM_YUV3, PORT138_FN, /* PIN: U21 */
+ FN_CAM_YUV2, PORT137_FN, /* PIN: T23 */
+ FN_CAM_YUV1, PORT136_FN, /* PIN: T22 */
+ FN_CAM_YUV0, PORT135_FN, /* PIN: T21 */
+ FN_CAM_HS, PORT134_FN, /* PIN: V21 */
+ FN_CAM_VS, PORT133_FN, /* PIN: W22 */
+ FN_CAM_CLKI, PORT132_FN, /* PIN: Y23 */
+ FN_CAM_CLKO, PORT131_FN, /* PIN: W23 */
+ FN_NTSC_DATA7, PORT130_FN, /* PIN: U18 */
+ FN_NTSC_DATA6, PORT129_FN, /* PIN: U20 */
+ FN_NTSC_DATA5, PORT128_FN, /* PIN: T18 */
+ }
+ },
+ { PINMUX_CFG_REG_VAR("CHG_PINSEL_LCD3", 0xe0140284, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2) {
+ /* 31 - 12 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 11 - 10 */
+ FN_SEL_LCD3_11_10_00, FN_SEL_LCD3_11_10_01,
+ FN_SEL_LCD3_11_10_10, 0,
+ /* 9 - 8 */
+ FN_SEL_LCD3_9_8_00, 0, FN_SEL_LCD3_9_8_10, 0,
+ /* 7 - 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 1 - 0 */
+ FN_SEL_LCD3_1_0_00, FN_SEL_LCD3_1_0_01, 0, 0,
+ }
+ },
+ { PINMUX_CFG_REG_VAR("CHG_PINSEL_UART", 0xe0140288, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) {
+ /* 31 - 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 1 - 0 */
+ FN_SEL_UART_1_0_00, FN_SEL_UART_1_0_01, 0, 0,
+ }
+ },
+ { PINMUX_CFG_REG_VAR("CHG_PINSEL_IIC", 0xe014028c, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) {
+ /* 31 - 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 1 - 0 */
+ FN_SEL_IIC_1_0_00, FN_SEL_IIC_1_0_01, 0, 0,
+ }
+ },
+ { PINMUX_CFG_REG_VAR("CHG_PINSEL_AB", 0xe0140294, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2) {
+ /* 31 - 14 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0,
+ /* 13 - 12 */
+ FN_SEL_AB_13_12_00, 0, FN_SEL_AB_13_12_10, 0,
+ /* 11 - 10 */
+ FN_SEL_AB_11_10_00, 0, FN_SEL_AB_11_10_10, 0,
+ /* 9 - 8 */
+ FN_SEL_AB_9_8_00, FN_SEL_AB_9_8_01, FN_SEL_AB_9_8_10, 0,
+ /* 7 - 6 */
+ FN_SEL_AB_7_6_00, FN_SEL_AB_7_6_01, FN_SEL_AB_7_6_10, 0,
+ /* 5 - 4 */
+ FN_SEL_AB_5_4_00, FN_SEL_AB_5_4_01,
+ FN_SEL_AB_5_4_10, FN_SEL_AB_5_4_11,
+ /* 3 - 2 */
+ FN_SEL_AB_3_2_00, FN_SEL_AB_3_2_01,
+ FN_SEL_AB_3_2_10, FN_SEL_AB_3_2_11,
+ /* 1 - 0 */
+ FN_SEL_AB_1_0_00, 0, FN_SEL_AB_1_0_10, 0,
+ }
+ },
+ { PINMUX_CFG_REG_VAR("CHG_PINSEL_USI", 0xe0140298, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2) {
+ /* 31 - 10 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 9 - 8 */
+ FN_SEL_USI_9_8_00, FN_SEL_USI_9_8_01, 0, 0,
+ /* 7 - 6 */
+ FN_SEL_USI_7_6_00, FN_SEL_USI_7_6_01, 0, 0,
+ /* 5 - 4 */
+ FN_SEL_USI_5_4_00, FN_SEL_USI_5_4_01, 0, 0,
+ /* 3 - 2 */
+ FN_SEL_USI_3_2_00, FN_SEL_USI_3_2_01, 0, 0,
+ /* 1 - 0 */
+ FN_SEL_USI_1_0_00, FN_SEL_USI_1_0_01, 0, 0,
+ }
+ },
+ { PINMUX_CFG_REG_VAR("CHG_PINSEL_HSI", 0xe01402a8, 32,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2) {
+ /* 31 - 2 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ /* 1 - 0 */
+ FN_SEL_HSI_1_0_00, FN_SEL_HSI_1_0_01, 0, 0,
+ }
+ },
+ { },
+};
+
+const struct sh_pfc_soc_info emev2_pinmux_info = {
+ .name = "emev2_pfc",
+
+ .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
+
+ .pins = pinmux_pins,
+ .nr_pins = ARRAY_SIZE(pinmux_pins),
+ .groups = pinmux_groups,
+ .nr_groups = ARRAY_SIZE(pinmux_groups),
+ .functions = pinmux_functions,
+ .nr_functions = ARRAY_SIZE(pinmux_functions),
+
+ .cfg_regs = pinmux_config_regs,
+
+ .gpio_data = pinmux_data,
+ .gpio_data_size = ARRAY_SIZE(pinmux_data),
+};
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
index 9a179c94b4dc..80c1843bb6ad 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7790.c
@@ -2241,6 +2241,13 @@ static const unsigned int intc_irq3_pins[] = {
static const unsigned int intc_irq3_mux[] = {
IRQ3_MARK,
};
+/* - MLB+ ------------------------------------------------------------------- */
+static const unsigned int mlb_3pin_pins[] = {
+ RCAR_GP_PIN(4, 0), RCAR_GP_PIN(4, 1), RCAR_GP_PIN(4, 2),
+};
+static const unsigned int mlb_3pin_mux[] = {
+ MLB_CLK_MARK, MLB_SIG_MARK, MLB_DAT_MARK,
+};
/* - MMCIF0 ----------------------------------------------------------------- */
static const unsigned int mmc0_data1_pins[] = {
/* D[0] */
@@ -3873,6 +3880,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(intc_irq1),
SH_PFC_PIN_GROUP(intc_irq2),
SH_PFC_PIN_GROUP(intc_irq3),
+ SH_PFC_PIN_GROUP(mlb_3pin),
SH_PFC_PIN_GROUP(mmc0_data1),
SH_PFC_PIN_GROUP(mmc0_data4),
SH_PFC_PIN_GROUP(mmc0_data8),
@@ -4198,6 +4206,10 @@ static const char * const intc_groups[] = {
"intc_irq3",
};
+static const char * const mlb_groups[] = {
+ "mlb_3pin",
+};
+
static const char * const mmc0_groups[] = {
"mmc0_data1",
"mmc0_data4",
@@ -4511,6 +4523,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(iic2),
SH_PFC_FUNCTION(iic3),
SH_PFC_FUNCTION(intc),
+ SH_PFC_FUNCTION(mlb),
SH_PFC_FUNCTION(mmc0),
SH_PFC_FUNCTION(mmc1),
SH_PFC_FUNCTION(msiof0),
diff --git a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
index c6e5deba238e..fdd2c8729791 100644
--- a/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
+++ b/drivers/pinctrl/sh-pfc/pfc-r8a7791.c
@@ -378,7 +378,7 @@ enum {
/* IPSR16 */
FN_HRX1, FN_SCIFB1_RXD, FN_VI1_R0_B, FN_GLO_SDATA_C, FN_VI1_DATA6_C,
FN_HTX1, FN_SCIFB1_TXD, FN_VI1_R1_B, FN_GLO_SS_C, FN_VI1_DATA7_C,
- FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CK, FN_GLO_RFON_C,
+ FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CLK, FN_GLO_RFON_C,
FN_HCTS1_N, FN_SCIFB1_CTS_N, FN_MLB_SIG, FN_CAN1_TX_B,
FN_HRTS1_N, FN_SCIFB1_RTS_N, FN_MLB_DAT, FN_CAN1_RX_B,
@@ -764,7 +764,7 @@ enum {
GLO_SDATA_C_MARK, VI1_DATA6_C_MARK,
HTX1_MARK, SCIFB1_TXD_MARK, VI1_R1_B_MARK,
GLO_SS_C_MARK, VI1_DATA7_C_MARK,
- HSCK1_MARK, SCIFB1_SCK_MARK, MLB_CK_MARK, GLO_RFON_C_MARK,
+ HSCK1_MARK, SCIFB1_SCK_MARK, MLB_CLK_MARK, GLO_RFON_C_MARK,
HCTS1_N_MARK, SCIFB1_CTS_N_MARK, MLB_SIG_MARK, CAN1_TX_B_MARK,
HRTS1_N_MARK, SCIFB1_RTS_N_MARK, MLB_DAT_MARK, CAN1_RX_B_MARK,
PINMUX_MARK_END,
@@ -1664,7 +1664,7 @@ static const u16 pinmux_data[] = {
PINMUX_IPSR_MODSEL_DATA(IP16_5_3, VI1_DATA7_C, SEL_VI1_2),
PINMUX_IPSR_MODSEL_DATA(IP16_7_6, HSCK1, SEL_HSCIF1_0),
PINMUX_IPSR_MODSEL_DATA(IP16_7_6, SCIFB1_SCK, SEL_SCIFB1_0),
- PINMUX_IPSR_DATA(IP16_7_6, MLB_CK),
+ PINMUX_IPSR_DATA(IP16_7_6, MLB_CLK),
PINMUX_IPSR_MODSEL_DATA(IP16_7_6, GLO_RFON_C, SEL_GPS_2),
PINMUX_IPSR_MODSEL_DATA(IP16_9_8, HCTS1_N, SEL_HSCIF1_0),
PINMUX_IPSR_DATA(IP16_9_8, SCIFB1_CTS_N),
@@ -2391,6 +2391,13 @@ static const unsigned int intc_irq3_pins[] = {
static const unsigned int intc_irq3_mux[] = {
IRQ3_MARK,
};
+/* - MLB+ ------------------------------------------------------------------- */
+static const unsigned int mlb_3pin_pins[] = {
+ RCAR_GP_PIN(7, 7), RCAR_GP_PIN(7, 8), RCAR_GP_PIN(7, 9),
+};
+static const unsigned int mlb_3pin_mux[] = {
+ MLB_CLK_MARK, MLB_SIG_MARK, MLB_DAT_MARK,
+};
/* - MMCIF ------------------------------------------------------------------ */
static const unsigned int mmc_data1_pins[] = {
/* D[0] */
@@ -4267,6 +4274,7 @@ static const struct sh_pfc_pin_group pinmux_groups[] = {
SH_PFC_PIN_GROUP(intc_irq1),
SH_PFC_PIN_GROUP(intc_irq2),
SH_PFC_PIN_GROUP(intc_irq3),
+ SH_PFC_PIN_GROUP(mlb_3pin),
SH_PFC_PIN_GROUP(mmc_data1),
SH_PFC_PIN_GROUP(mmc_data4),
SH_PFC_PIN_GROUP(mmc_data8),
@@ -4648,6 +4656,10 @@ static const char * const intc_groups[] = {
"intc_irq3",
};
+static const char * const mlb_groups[] = {
+ "mlb_3pin",
+};
+
static const char * const mmc_groups[] = {
"mmc_data1",
"mmc_data4",
@@ -4972,6 +4984,7 @@ static const struct sh_pfc_function pinmux_functions[] = {
SH_PFC_FUNCTION(i2c7),
SH_PFC_FUNCTION(i2c8),
SH_PFC_FUNCTION(intc),
+ SH_PFC_FUNCTION(mlb),
SH_PFC_FUNCTION(mmc),
SH_PFC_FUNCTION(msiof0),
SH_PFC_FUNCTION(msiof1),
@@ -5974,7 +5987,7 @@ static const struct pinmux_cfg_reg pinmux_config_regs[] = {
/* IP16_9_8 [2] */
FN_HCTS1_N, FN_SCIFB1_CTS_N, FN_MLB_SIG, FN_CAN1_TX_B,
/* IP16_7_6 [2] */
- FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CK, FN_GLO_RFON_C,
+ FN_HSCK1, FN_SCIFB1_SCK, FN_MLB_CLK, FN_GLO_RFON_C,
/* IP16_5_3 [3] */
FN_HTX1, FN_SCIFB1_TXD, FN_VI1_R1_B,
FN_GLO_SS_C, FN_VI1_DATA7_C,
diff --git a/drivers/pinctrl/sh-pfc/pfc-sh7372.c b/drivers/pinctrl/sh-pfc/pfc-sh7372.c
deleted file mode 100644
index 8211f66a2f68..000000000000
--- a/drivers/pinctrl/sh-pfc/pfc-sh7372.c
+++ /dev/null
@@ -1,2645 +0,0 @@
-/*
- * sh7372 processor support - PFC hardware block
- *
- * Copyright (C) 2010 Kuninori Morimoto <morimoto.kuninori@renesas.com>
- *
- * Based on
- * sh7367 processor support - PFC hardware block
- * Copyright (C) 2010 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/io.h>
-#include <linux/kernel.h>
-#include <linux/pinctrl/pinconf-generic.h>
-#include <linux/sh_intc.h>
-
-#include "core.h"
-#include "sh_pfc.h"
-
-#define CPU_ALL_PORT(fn, pfx, sfx) \
- PORT_10(0, fn, pfx, sfx), PORT_90(0, fn, pfx, sfx), \
- PORT_10(100, fn, pfx##10, sfx), PORT_10(110, fn, pfx##11, sfx), \
- PORT_10(120, fn, pfx##12, sfx), PORT_10(130, fn, pfx##13, sfx), \
- PORT_10(140, fn, pfx##14, sfx), PORT_10(150, fn, pfx##15, sfx), \
- PORT_10(160, fn, pfx##16, sfx), PORT_10(170, fn, pfx##17, sfx), \
- PORT_10(180, fn, pfx##18, sfx), PORT_1(190, fn, pfx##190, sfx)
-
-#define IRQC_PIN_MUX(irq, pin) \
-static const unsigned int intc_irq##irq##_pins[] = { \
- pin, \
-}; \
-static const unsigned int intc_irq##irq##_mux[] = { \
- IRQ##irq##_MARK, \
-}
-
-#define IRQC_PINS_MUX(irq, pin0, pin1) \
-static const unsigned int intc_irq##irq##_0_pins[] = { \
- pin0, \
-}; \
-static const unsigned int intc_irq##irq##_0_mux[] = { \
- IRQ##irq##_##pin0##_MARK, \
-}; \
-static const unsigned int intc_irq##irq##_1_pins[] = { \
- pin1, \
-}; \
-static const unsigned int intc_irq##irq##_1_mux[] = { \
- IRQ##irq##_##pin1##_MARK, \
-}
-
-enum {
- PINMUX_RESERVED = 0,
-
- /* PORT0_DATA -> PORT190_DATA */
- PINMUX_DATA_BEGIN,
- PORT_ALL(DATA),
- PINMUX_DATA_END,
-
- /* PORT0_IN -> PORT190_IN */
- PINMUX_INPUT_BEGIN,
- PORT_ALL(IN),
- PINMUX_INPUT_END,
-
- /* PORT0_OUT -> PORT190_OUT */
- PINMUX_OUTPUT_BEGIN,
- PORT_ALL(OUT),
- PINMUX_OUTPUT_END,
-
- PINMUX_FUNCTION_BEGIN,
- PORT_ALL(FN_IN), /* PORT0_FN_IN -> PORT190_FN_IN */
- PORT_ALL(FN_OUT), /* PORT0_FN_OUT -> PORT190_FN_OUT */
- PORT_ALL(FN0), /* PORT0_FN0 -> PORT190_FN0 */
- PORT_ALL(FN1), /* PORT0_FN1 -> PORT190_FN1 */
- PORT_ALL(FN2), /* PORT0_FN2 -> PORT190_FN2 */
- PORT_ALL(FN3), /* PORT0_FN3 -> PORT190_FN3 */
- PORT_ALL(FN4), /* PORT0_FN4 -> PORT190_FN4 */
- PORT_ALL(FN5), /* PORT0_FN5 -> PORT190_FN5 */
- PORT_ALL(FN6), /* PORT0_FN6 -> PORT190_FN6 */
- PORT_ALL(FN7), /* PORT0_FN7 -> PORT190_FN7 */
-
- MSEL1CR_31_0, MSEL1CR_31_1,
- MSEL1CR_30_0, MSEL1CR_30_1,
- MSEL1CR_29_0, MSEL1CR_29_1,
- MSEL1CR_28_0, MSEL1CR_28_1,
- MSEL1CR_27_0, MSEL1CR_27_1,
- MSEL1CR_26_0, MSEL1CR_26_1,
- MSEL1CR_16_0, MSEL1CR_16_1,
- MSEL1CR_15_0, MSEL1CR_15_1,
- MSEL1CR_14_0, MSEL1CR_14_1,
- MSEL1CR_13_0, MSEL1CR_13_1,
- MSEL1CR_12_0, MSEL1CR_12_1,
- MSEL1CR_9_0, MSEL1CR_9_1,
- MSEL1CR_8_0, MSEL1CR_8_1,
- MSEL1CR_7_0, MSEL1CR_7_1,
- MSEL1CR_6_0, MSEL1CR_6_1,
- MSEL1CR_4_0, MSEL1CR_4_1,
- MSEL1CR_3_0, MSEL1CR_3_1,
- MSEL1CR_2_0, MSEL1CR_2_1,
- MSEL1CR_0_0, MSEL1CR_0_1,
-
- MSEL3CR_27_0, MSEL3CR_27_1,
- MSEL3CR_26_0, MSEL3CR_26_1,
- MSEL3CR_21_0, MSEL3CR_21_1,
- MSEL3CR_20_0, MSEL3CR_20_1,
- MSEL3CR_15_0, MSEL3CR_15_1,
- MSEL3CR_9_0, MSEL3CR_9_1,
- MSEL3CR_6_0, MSEL3CR_6_1,
-
- MSEL4CR_19_0, MSEL4CR_19_1,
- MSEL4CR_18_0, MSEL4CR_18_1,
- MSEL4CR_17_0, MSEL4CR_17_1,
- MSEL4CR_16_0, MSEL4CR_16_1,
- MSEL4CR_15_0, MSEL4CR_15_1,
- MSEL4CR_14_0, MSEL4CR_14_1,
- MSEL4CR_10_0, MSEL4CR_10_1,
- MSEL4CR_6_0, MSEL4CR_6_1,
- MSEL4CR_4_0, MSEL4CR_4_1,
- MSEL4CR_1_0, MSEL4CR_1_1,
- PINMUX_FUNCTION_END,
-
- PINMUX_MARK_BEGIN,
-
- /* IRQ */
- IRQ0_6_MARK, IRQ0_162_MARK, IRQ1_MARK, IRQ2_4_MARK,
- IRQ2_5_MARK, IRQ3_8_MARK, IRQ3_16_MARK, IRQ4_17_MARK,
- IRQ4_163_MARK, IRQ5_MARK, IRQ6_39_MARK, IRQ6_164_MARK,
- IRQ7_40_MARK, IRQ7_167_MARK, IRQ8_41_MARK, IRQ8_168_MARK,
- IRQ9_42_MARK, IRQ9_169_MARK, IRQ10_MARK, IRQ11_MARK,
- IRQ12_80_MARK, IRQ12_137_MARK, IRQ13_81_MARK, IRQ13_145_MARK,
- IRQ14_82_MARK, IRQ14_146_MARK, IRQ15_83_MARK, IRQ15_147_MARK,
- IRQ16_84_MARK, IRQ16_170_MARK, IRQ17_MARK, IRQ18_MARK,
- IRQ19_MARK, IRQ20_MARK, IRQ21_MARK, IRQ22_MARK,
- IRQ23_MARK, IRQ24_MARK, IRQ25_MARK, IRQ26_121_MARK,
- IRQ26_172_MARK, IRQ27_122_MARK, IRQ27_180_MARK, IRQ28_123_MARK,
- IRQ28_181_MARK, IRQ29_129_MARK, IRQ29_182_MARK, IRQ30_130_MARK,
- IRQ30_183_MARK, IRQ31_138_MARK, IRQ31_184_MARK,
-
- /* MSIOF0 */
- MSIOF0_TSYNC_MARK, MSIOF0_TSCK_MARK, MSIOF0_RXD_MARK,
- MSIOF0_RSCK_MARK, MSIOF0_RSYNC_MARK, MSIOF0_MCK0_MARK,
- MSIOF0_MCK1_MARK, MSIOF0_SS1_MARK, MSIOF0_SS2_MARK,
- MSIOF0_TXD_MARK,
-
- /* MSIOF1 */
- MSIOF1_TSCK_39_MARK, MSIOF1_TSYNC_40_MARK,
- MSIOF1_TSCK_88_MARK, MSIOF1_TSYNC_89_MARK,
- MSIOF1_TXD_41_MARK, MSIOF1_RXD_42_MARK,
- MSIOF1_TXD_90_MARK, MSIOF1_RXD_91_MARK,
- MSIOF1_SS1_43_MARK, MSIOF1_SS2_44_MARK,
- MSIOF1_SS1_92_MARK, MSIOF1_SS2_93_MARK,
- MSIOF1_RSCK_MARK, MSIOF1_RSYNC_MARK,
- MSIOF1_MCK0_MARK, MSIOF1_MCK1_MARK,
-
- /* MSIOF2 */
- MSIOF2_RSCK_MARK, MSIOF2_RSYNC_MARK, MSIOF2_MCK0_MARK,
- MSIOF2_MCK1_MARK, MSIOF2_SS1_MARK, MSIOF2_SS2_MARK,
- MSIOF2_TSYNC_MARK, MSIOF2_TSCK_MARK, MSIOF2_RXD_MARK,
- MSIOF2_TXD_MARK,
-
- /* BBIF1 */
- BBIF1_RXD_MARK, BBIF1_TSYNC_MARK, BBIF1_TSCK_MARK,
- BBIF1_TXD_MARK, BBIF1_RSCK_MARK, BBIF1_RSYNC_MARK,
- BBIF1_FLOW_MARK, BB_RX_FLOW_N_MARK,
-
- /* BBIF2 */
- BBIF2_TSCK1_MARK, BBIF2_TSYNC1_MARK,
- BBIF2_TXD1_MARK, BBIF2_RXD_MARK,
-
- /* FSI */
- FSIACK_MARK, FSIBCK_MARK, FSIAILR_MARK, FSIAIBT_MARK,
- FSIAISLD_MARK, FSIAOMC_MARK, FSIAOLR_MARK, FSIAOBT_MARK,
- FSIAOSLD_MARK, FSIASPDIF_11_MARK, FSIASPDIF_15_MARK,
-
- /* FMSI */
- FMSOCK_MARK, FMSOOLR_MARK, FMSIOLR_MARK, FMSOOBT_MARK,
- FMSIOBT_MARK, FMSOSLD_MARK, FMSOILR_MARK, FMSIILR_MARK,
- FMSOIBT_MARK, FMSIIBT_MARK, FMSISLD_MARK, FMSICK_MARK,
-
- /* SCIFA0 */
- SCIFA0_TXD_MARK, SCIFA0_RXD_MARK, SCIFA0_SCK_MARK,
- SCIFA0_RTS_MARK, SCIFA0_CTS_MARK,
-
- /* SCIFA1 */
- SCIFA1_TXD_MARK, SCIFA1_RXD_MARK, SCIFA1_SCK_MARK,
- SCIFA1_RTS_MARK, SCIFA1_CTS_MARK,
-
- /* SCIFA2 */
- SCIFA2_CTS1_MARK, SCIFA2_RTS1_MARK, SCIFA2_TXD1_MARK,
- SCIFA2_RXD1_MARK, SCIFA2_SCK1_MARK,
-
- /* SCIFA3 */
- SCIFA3_CTS_43_MARK, SCIFA3_CTS_140_MARK, SCIFA3_RTS_44_MARK,
- SCIFA3_RTS_141_MARK, SCIFA3_SCK_MARK, SCIFA3_TXD_MARK,
- SCIFA3_RXD_MARK,
-
- /* SCIFA4 */
- SCIFA4_RXD_MARK, SCIFA4_TXD_MARK,
-
- /* SCIFA5 */
- SCIFA5_RXD_MARK, SCIFA5_TXD_MARK,
-
- /* SCIFB */
- SCIFB_SCK_MARK, SCIFB_RTS_MARK, SCIFB_CTS_MARK,
- SCIFB_TXD_MARK, SCIFB_RXD_MARK,
-
- /* CEU */
- VIO_HD_MARK, VIO_CKO1_MARK, VIO_CKO2_MARK, VIO_VD_MARK,
- VIO_CLK_MARK, VIO_FIELD_MARK, VIO_CKO_MARK,
- VIO_D0_MARK, VIO_D1_MARK, VIO_D2_MARK, VIO_D3_MARK,
- VIO_D4_MARK, VIO_D5_MARK, VIO_D6_MARK, VIO_D7_MARK,
- VIO_D8_MARK, VIO_D9_MARK, VIO_D10_MARK, VIO_D11_MARK,
- VIO_D12_MARK, VIO_D13_MARK, VIO_D14_MARK, VIO_D15_MARK,
-
- /* USB0 */
- IDIN_0_MARK, EXTLP_0_MARK, OVCN2_0_MARK, PWEN_0_MARK,
- OVCN_0_MARK, VBUS0_0_MARK,
-
- /* USB1 */
- IDIN_1_18_MARK, IDIN_1_113_MARK,
- PWEN_1_115_MARK, PWEN_1_138_MARK,
- OVCN_1_114_MARK, OVCN_1_162_MARK,
- EXTLP_1_MARK, OVCN2_1_MARK,
- VBUS0_1_MARK,
-
- /* GPIO */
- GPI0_MARK, GPI1_MARK, GPO0_MARK, GPO1_MARK,
-
- /* BSC */
- BS_MARK, WE1_MARK,
- CKO_MARK, WAIT_MARK, RDWR_MARK,
-
- A0_MARK, A1_MARK, A2_MARK, A3_MARK,
- A6_MARK, A7_MARK, A8_MARK, A9_MARK,
- A10_MARK, A11_MARK, A12_MARK, A13_MARK,
- A14_MARK, A15_MARK, A16_MARK, A17_MARK,
- A18_MARK, A19_MARK, A20_MARK, A21_MARK,
- A22_MARK, A23_MARK, A24_MARK, A25_MARK,
- A26_MARK,
-
- CS0_MARK, CS2_MARK, CS4_MARK,
- CS5A_MARK, CS5B_MARK, CS6A_MARK,
-
- /* BSC/FLCTL */
- RD_FSC_MARK, WE0_FWE_MARK, A4_FOE_MARK, A5_FCDE_MARK,
- D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK,
- D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK,
- D8_NAF8_MARK, D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK,
- D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, D15_NAF15_MARK,
-
- /* MMCIF(1) */
- MMCD0_0_MARK, MMCD0_1_MARK, MMCD0_2_MARK, MMCD0_3_MARK,
- MMCD0_4_MARK, MMCD0_5_MARK, MMCD0_6_MARK, MMCD0_7_MARK,
- MMCCMD0_MARK, MMCCLK0_MARK,
-
- /* MMCIF(2) */
- MMCD1_0_MARK, MMCD1_1_MARK, MMCD1_2_MARK, MMCD1_3_MARK,
- MMCD1_4_MARK, MMCD1_5_MARK, MMCD1_6_MARK, MMCD1_7_MARK,
- MMCCLK1_MARK, MMCCMD1_MARK,
-
- /* SPU2 */
- VINT_I_MARK,
-
- /* FLCTL */
- FCE1_MARK, FCE0_MARK, FRB_MARK,
-
- /* HSI */
- GP_RX_FLAG_MARK, GP_RX_DATA_MARK, GP_TX_READY_MARK,
- GP_RX_WAKE_MARK, MP_TX_FLAG_MARK, MP_TX_DATA_MARK,
- MP_RX_READY_MARK, MP_TX_WAKE_MARK,
-
- /* MFI */
- MFIv6_MARK,
- MFIv4_MARK,
-
- MEMC_CS0_MARK, MEMC_BUSCLK_MEMC_A0_MARK,
- MEMC_CS1_MEMC_A1_MARK, MEMC_ADV_MEMC_DREQ0_MARK,
- MEMC_WAIT_MEMC_DREQ1_MARK, MEMC_NOE_MARK,
- MEMC_NWE_MARK, MEMC_INT_MARK,
-
- MEMC_AD0_MARK, MEMC_AD1_MARK, MEMC_AD2_MARK,
- MEMC_AD3_MARK, MEMC_AD4_MARK, MEMC_AD5_MARK,
- MEMC_AD6_MARK, MEMC_AD7_MARK, MEMC_AD8_MARK,
- MEMC_AD9_MARK, MEMC_AD10_MARK, MEMC_AD11_MARK,
- MEMC_AD12_MARK, MEMC_AD13_MARK, MEMC_AD14_MARK,
- MEMC_AD15_MARK,
-
- /* SIM */
- SIM_RST_MARK, SIM_CLK_MARK, SIM_D_MARK,
-
- /* TPU */
- TPU0TO0_MARK, TPU0TO1_MARK,
- TPU0TO2_93_MARK, TPU0TO2_99_MARK,
- TPU0TO3_MARK,
-
- /* I2C2 */
- I2C_SCL2_MARK, I2C_SDA2_MARK,
-
- /* I2C3(1) */
- I2C_SCL3_MARK, I2C_SDA3_MARK,
-
- /* I2C3(2) */
- I2C_SCL3S_MARK, I2C_SDA3S_MARK,
-
- /* I2C4(2) */
- I2C_SCL4_MARK, I2C_SDA4_MARK,
-
- /* I2C4(2) */
- I2C_SCL4S_MARK, I2C_SDA4S_MARK,
-
- /* KEYSC */
- KEYOUT0_MARK, KEYIN0_121_MARK, KEYIN0_136_MARK,
- KEYOUT1_MARK, KEYIN1_122_MARK, KEYIN1_135_MARK,
- KEYOUT2_MARK, KEYIN2_123_MARK, KEYIN2_134_MARK,
- KEYOUT3_MARK, KEYIN3_124_MARK, KEYIN3_133_MARK,
- KEYOUT4_MARK, KEYIN4_MARK,
- KEYOUT5_MARK, KEYIN5_MARK,
- KEYOUT6_MARK, KEYIN6_MARK,
- KEYOUT7_MARK, KEYIN7_MARK,
-
- /* LCDC */
- LCDC0_SELECT_MARK,
- LCDC1_SELECT_MARK,
- LCDHSYN_MARK, LCDCS_MARK, LCDVSYN_MARK, LCDDCK_MARK,
- LCDWR_MARK, LCDRD_MARK, LCDDISP_MARK, LCDRS_MARK,
- LCDLCLK_MARK, LCDDON_MARK,
-
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
- LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK,
- LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK,
- LCDD16_MARK, LCDD17_MARK, LCDD18_MARK, LCDD19_MARK,
- LCDD20_MARK, LCDD21_MARK, LCDD22_MARK, LCDD23_MARK,
-
- /* IRDA */
- IRDA_OUT_MARK, IRDA_IN_MARK, IRDA_FIRSEL_MARK,
- IROUT_139_MARK, IROUT_140_MARK,
-
- /* TSIF1 */
- TS0_1SELECT_MARK,
- TS0_2SELECT_MARK,
- TS1_1SELECT_MARK,
- TS1_2SELECT_MARK,
-
- TS_SPSYNC1_MARK, TS_SDAT1_MARK,
- TS_SDEN1_MARK, TS_SCK1_MARK,
-
- /* TSIF2 */
- TS_SPSYNC2_MARK, TS_SDAT2_MARK,
- TS_SDEN2_MARK, TS_SCK2_MARK,
-
- /* HDMI */
- HDMI_HPD_MARK, HDMI_CEC_MARK,
-
- /* SDHI0 */
- SDHICLK0_MARK, SDHICD0_MARK,
- SDHICMD0_MARK, SDHIWP0_MARK,
- SDHID0_0_MARK, SDHID0_1_MARK,
- SDHID0_2_MARK, SDHID0_3_MARK,
-
- /* SDHI1 */
- SDHICLK1_MARK, SDHICMD1_MARK, SDHID1_0_MARK,
- SDHID1_1_MARK, SDHID1_2_MARK, SDHID1_3_MARK,
-
- /* SDHI2 */
- SDHICLK2_MARK, SDHICMD2_MARK, SDHID2_0_MARK,
- SDHID2_1_MARK, SDHID2_2_MARK, SDHID2_3_MARK,
-
- /* SDENC */
- SDENC_CPG_MARK,
- SDENC_DV_CLKI_MARK,
-
- PINMUX_MARK_END,
-};
-
-static const u16 pinmux_data[] = {
- PINMUX_DATA_ALL(),
-
- /* IRQ */
- PINMUX_DATA(IRQ0_6_MARK, PORT6_FN0, MSEL1CR_0_0),
- PINMUX_DATA(IRQ0_162_MARK, PORT162_FN0, MSEL1CR_0_1),
- PINMUX_DATA(IRQ1_MARK, PORT12_FN0),
- PINMUX_DATA(IRQ2_4_MARK, PORT4_FN0, MSEL1CR_2_0),
- PINMUX_DATA(IRQ2_5_MARK, PORT5_FN0, MSEL1CR_2_1),
- PINMUX_DATA(IRQ3_8_MARK, PORT8_FN0, MSEL1CR_3_0),
- PINMUX_DATA(IRQ3_16_MARK, PORT16_FN0, MSEL1CR_3_1),
- PINMUX_DATA(IRQ4_17_MARK, PORT17_FN0, MSEL1CR_4_0),
- PINMUX_DATA(IRQ4_163_MARK, PORT163_FN0, MSEL1CR_4_1),
- PINMUX_DATA(IRQ5_MARK, PORT18_FN0),
- PINMUX_DATA(IRQ6_39_MARK, PORT39_FN0, MSEL1CR_6_0),
- PINMUX_DATA(IRQ6_164_MARK, PORT164_FN0, MSEL1CR_6_1),
- PINMUX_DATA(IRQ7_40_MARK, PORT40_FN0, MSEL1CR_7_1),
- PINMUX_DATA(IRQ7_167_MARK, PORT167_FN0, MSEL1CR_7_0),
- PINMUX_DATA(IRQ8_41_MARK, PORT41_FN0, MSEL1CR_8_1),
- PINMUX_DATA(IRQ8_168_MARK, PORT168_FN0, MSEL1CR_8_0),
- PINMUX_DATA(IRQ9_42_MARK, PORT42_FN0, MSEL1CR_9_0),
- PINMUX_DATA(IRQ9_169_MARK, PORT169_FN0, MSEL1CR_9_1),
- PINMUX_DATA(IRQ10_MARK, PORT65_FN0, MSEL1CR_9_1),
- PINMUX_DATA(IRQ11_MARK, PORT67_FN0),
- PINMUX_DATA(IRQ12_80_MARK, PORT80_FN0, MSEL1CR_12_0),
- PINMUX_DATA(IRQ12_137_MARK, PORT137_FN0, MSEL1CR_12_1),
- PINMUX_DATA(IRQ13_81_MARK, PORT81_FN0, MSEL1CR_13_0),
- PINMUX_DATA(IRQ13_145_MARK, PORT145_FN0, MSEL1CR_13_1),
- PINMUX_DATA(IRQ14_82_MARK, PORT82_FN0, MSEL1CR_14_0),
- PINMUX_DATA(IRQ14_146_MARK, PORT146_FN0, MSEL1CR_14_1),
- PINMUX_DATA(IRQ15_83_MARK, PORT83_FN0, MSEL1CR_15_0),
- PINMUX_DATA(IRQ15_147_MARK, PORT147_FN0, MSEL1CR_15_1),
- PINMUX_DATA(IRQ16_84_MARK, PORT84_FN0, MSEL1CR_16_0),
- PINMUX_DATA(IRQ16_170_MARK, PORT170_FN0, MSEL1CR_16_1),
- PINMUX_DATA(IRQ17_MARK, PORT85_FN0),
- PINMUX_DATA(IRQ18_MARK, PORT86_FN0),
- PINMUX_DATA(IRQ19_MARK, PORT87_FN0),
- PINMUX_DATA(IRQ20_MARK, PORT92_FN0),
- PINMUX_DATA(IRQ21_MARK, PORT93_FN0),
- PINMUX_DATA(IRQ22_MARK, PORT94_FN0),
- PINMUX_DATA(IRQ23_MARK, PORT95_FN0),
- PINMUX_DATA(IRQ24_MARK, PORT112_FN0),
- PINMUX_DATA(IRQ25_MARK, PORT119_FN0),
- PINMUX_DATA(IRQ26_121_MARK, PORT121_FN0, MSEL1CR_26_1),
- PINMUX_DATA(IRQ26_172_MARK, PORT172_FN0, MSEL1CR_26_0),
- PINMUX_DATA(IRQ27_122_MARK, PORT122_FN0, MSEL1CR_27_1),
- PINMUX_DATA(IRQ27_180_MARK, PORT180_FN0, MSEL1CR_27_0),
- PINMUX_DATA(IRQ28_123_MARK, PORT123_FN0, MSEL1CR_28_1),
- PINMUX_DATA(IRQ28_181_MARK, PORT181_FN0, MSEL1CR_28_0),
- PINMUX_DATA(IRQ29_129_MARK, PORT129_FN0, MSEL1CR_29_1),
- PINMUX_DATA(IRQ29_182_MARK, PORT182_FN0, MSEL1CR_29_0),
- PINMUX_DATA(IRQ30_130_MARK, PORT130_FN0, MSEL1CR_30_1),
- PINMUX_DATA(IRQ30_183_MARK, PORT183_FN0, MSEL1CR_30_0),
- PINMUX_DATA(IRQ31_138_MARK, PORT138_FN0, MSEL1CR_31_1),
- PINMUX_DATA(IRQ31_184_MARK, PORT184_FN0, MSEL1CR_31_0),
-
- /* Function 1 */
- PINMUX_DATA(BBIF2_TSCK1_MARK, PORT0_FN1),
- PINMUX_DATA(BBIF2_TSYNC1_MARK, PORT1_FN1),
- PINMUX_DATA(BBIF2_TXD1_MARK, PORT2_FN1),
- PINMUX_DATA(BBIF2_RXD_MARK, PORT3_FN1),
- PINMUX_DATA(FSIACK_MARK, PORT4_FN1),
- PINMUX_DATA(FSIAILR_MARK, PORT5_FN1),
- PINMUX_DATA(FSIAIBT_MARK, PORT6_FN1),
- PINMUX_DATA(FSIAISLD_MARK, PORT7_FN1),
- PINMUX_DATA(FSIAOMC_MARK, PORT8_FN1),
- PINMUX_DATA(FSIAOLR_MARK, PORT9_FN1),
- PINMUX_DATA(FSIAOBT_MARK, PORT10_FN1),
- PINMUX_DATA(FSIAOSLD_MARK, PORT11_FN1),
- PINMUX_DATA(FMSOCK_MARK, PORT12_FN1),
- PINMUX_DATA(FMSOOLR_MARK, PORT13_FN1),
- PINMUX_DATA(FMSOOBT_MARK, PORT14_FN1),
- PINMUX_DATA(FMSOSLD_MARK, PORT15_FN1),
- PINMUX_DATA(FMSOILR_MARK, PORT16_FN1),
- PINMUX_DATA(FMSOIBT_MARK, PORT17_FN1),
- PINMUX_DATA(FMSISLD_MARK, PORT18_FN1),
- PINMUX_DATA(A0_MARK, PORT19_FN1),
- PINMUX_DATA(A1_MARK, PORT20_FN1),
- PINMUX_DATA(A2_MARK, PORT21_FN1),
- PINMUX_DATA(A3_MARK, PORT22_FN1),
- PINMUX_DATA(A4_FOE_MARK, PORT23_FN1),
- PINMUX_DATA(A5_FCDE_MARK, PORT24_FN1),
- PINMUX_DATA(A6_MARK, PORT25_FN1),
- PINMUX_DATA(A7_MARK, PORT26_FN1),
- PINMUX_DATA(A8_MARK, PORT27_FN1),
- PINMUX_DATA(A9_MARK, PORT28_FN1),
- PINMUX_DATA(A10_MARK, PORT29_FN1),
- PINMUX_DATA(A11_MARK, PORT30_FN1),
- PINMUX_DATA(A12_MARK, PORT31_FN1),
- PINMUX_DATA(A13_MARK, PORT32_FN1),
- PINMUX_DATA(A14_MARK, PORT33_FN1),
- PINMUX_DATA(A15_MARK, PORT34_FN1),
- PINMUX_DATA(A16_MARK, PORT35_FN1),
- PINMUX_DATA(A17_MARK, PORT36_FN1),
- PINMUX_DATA(A18_MARK, PORT37_FN1),
- PINMUX_DATA(A19_MARK, PORT38_FN1),
- PINMUX_DATA(A20_MARK, PORT39_FN1),
- PINMUX_DATA(A21_MARK, PORT40_FN1),
- PINMUX_DATA(A22_MARK, PORT41_FN1),
- PINMUX_DATA(A23_MARK, PORT42_FN1),
- PINMUX_DATA(A24_MARK, PORT43_FN1),
- PINMUX_DATA(A25_MARK, PORT44_FN1),
- PINMUX_DATA(A26_MARK, PORT45_FN1),
- PINMUX_DATA(D0_NAF0_MARK, PORT46_FN1),
- PINMUX_DATA(D1_NAF1_MARK, PORT47_FN1),
- PINMUX_DATA(D2_NAF2_MARK, PORT48_FN1),
- PINMUX_DATA(D3_NAF3_MARK, PORT49_FN1),
- PINMUX_DATA(D4_NAF4_MARK, PORT50_FN1),
- PINMUX_DATA(D5_NAF5_MARK, PORT51_FN1),
- PINMUX_DATA(D6_NAF6_MARK, PORT52_FN1),
- PINMUX_DATA(D7_NAF7_MARK, PORT53_FN1),
- PINMUX_DATA(D8_NAF8_MARK, PORT54_FN1),
- PINMUX_DATA(D9_NAF9_MARK, PORT55_FN1),
- PINMUX_DATA(D10_NAF10_MARK, PORT56_FN1),
- PINMUX_DATA(D11_NAF11_MARK, PORT57_FN1),
- PINMUX_DATA(D12_NAF12_MARK, PORT58_FN1),
- PINMUX_DATA(D13_NAF13_MARK, PORT59_FN1),
- PINMUX_DATA(D14_NAF14_MARK, PORT60_FN1),
- PINMUX_DATA(D15_NAF15_MARK, PORT61_FN1),
- PINMUX_DATA(CS0_MARK, PORT62_FN1),
- PINMUX_DATA(CS2_MARK, PORT63_FN1),
- PINMUX_DATA(CS4_MARK, PORT64_FN1),
- PINMUX_DATA(CS5A_MARK, PORT65_FN1),
- PINMUX_DATA(CS5B_MARK, PORT66_FN1),
- PINMUX_DATA(CS6A_MARK, PORT67_FN1),
- PINMUX_DATA(FCE0_MARK, PORT68_FN1),
- PINMUX_DATA(RD_FSC_MARK, PORT69_FN1),
- PINMUX_DATA(WE0_FWE_MARK, PORT70_FN1),
- PINMUX_DATA(WE1_MARK, PORT71_FN1),
- PINMUX_DATA(CKO_MARK, PORT72_FN1),
- PINMUX_DATA(FRB_MARK, PORT73_FN1),
- PINMUX_DATA(WAIT_MARK, PORT74_FN1),
- PINMUX_DATA(RDWR_MARK, PORT75_FN1),
- PINMUX_DATA(MEMC_AD0_MARK, PORT76_FN1),
- PINMUX_DATA(MEMC_AD1_MARK, PORT77_FN1),
- PINMUX_DATA(MEMC_AD2_MARK, PORT78_FN1),
- PINMUX_DATA(MEMC_AD3_MARK, PORT79_FN1),
- PINMUX_DATA(MEMC_AD4_MARK, PORT80_FN1),
- PINMUX_DATA(MEMC_AD5_MARK, PORT81_FN1),
- PINMUX_DATA(MEMC_AD6_MARK, PORT82_FN1),
- PINMUX_DATA(MEMC_AD7_MARK, PORT83_FN1),
- PINMUX_DATA(MEMC_AD8_MARK, PORT84_FN1),
- PINMUX_DATA(MEMC_AD9_MARK, PORT85_FN1),
- PINMUX_DATA(MEMC_AD10_MARK, PORT86_FN1),
- PINMUX_DATA(MEMC_AD11_MARK, PORT87_FN1),
- PINMUX_DATA(MEMC_AD12_MARK, PORT88_FN1),
- PINMUX_DATA(MEMC_AD13_MARK, PORT89_FN1),
- PINMUX_DATA(MEMC_AD14_MARK, PORT90_FN1),
- PINMUX_DATA(MEMC_AD15_MARK, PORT91_FN1),
- PINMUX_DATA(MEMC_CS0_MARK, PORT92_FN1),
- PINMUX_DATA(MEMC_BUSCLK_MEMC_A0_MARK, PORT93_FN1),
- PINMUX_DATA(MEMC_CS1_MEMC_A1_MARK, PORT94_FN1),
- PINMUX_DATA(MEMC_ADV_MEMC_DREQ0_MARK, PORT95_FN1),
- PINMUX_DATA(MEMC_WAIT_MEMC_DREQ1_MARK, PORT96_FN1),
- PINMUX_DATA(MEMC_NOE_MARK, PORT97_FN1),
- PINMUX_DATA(MEMC_NWE_MARK, PORT98_FN1),
- PINMUX_DATA(MEMC_INT_MARK, PORT99_FN1),
- PINMUX_DATA(VIO_VD_MARK, PORT100_FN1),
- PINMUX_DATA(VIO_HD_MARK, PORT101_FN1),
- PINMUX_DATA(VIO_D0_MARK, PORT102_FN1),
- PINMUX_DATA(VIO_D1_MARK, PORT103_FN1),
- PINMUX_DATA(VIO_D2_MARK, PORT104_FN1),
- PINMUX_DATA(VIO_D3_MARK, PORT105_FN1),
- PINMUX_DATA(VIO_D4_MARK, PORT106_FN1),
- PINMUX_DATA(VIO_D5_MARK, PORT107_FN1),
- PINMUX_DATA(VIO_D6_MARK, PORT108_FN1),
- PINMUX_DATA(VIO_D7_MARK, PORT109_FN1),
- PINMUX_DATA(VIO_D8_MARK, PORT110_FN1),
- PINMUX_DATA(VIO_D9_MARK, PORT111_FN1),
- PINMUX_DATA(VIO_D10_MARK, PORT112_FN1),
- PINMUX_DATA(VIO_D11_MARK, PORT113_FN1),
- PINMUX_DATA(VIO_D12_MARK, PORT114_FN1),
- PINMUX_DATA(VIO_D13_MARK, PORT115_FN1),
- PINMUX_DATA(VIO_D14_MARK, PORT116_FN1),
- PINMUX_DATA(VIO_D15_MARK, PORT117_FN1),
- PINMUX_DATA(VIO_CLK_MARK, PORT118_FN1),
- PINMUX_DATA(VIO_FIELD_MARK, PORT119_FN1),
- PINMUX_DATA(VIO_CKO_MARK, PORT120_FN1),
- PINMUX_DATA(LCDD0_MARK, PORT121_FN1),
- PINMUX_DATA(LCDD1_MARK, PORT122_FN1),
- PINMUX_DATA(LCDD2_MARK, PORT123_FN1),
- PINMUX_DATA(LCDD3_MARK, PORT124_FN1),
- PINMUX_DATA(LCDD4_MARK, PORT125_FN1),
- PINMUX_DATA(LCDD5_MARK, PORT126_FN1),
- PINMUX_DATA(LCDD6_MARK, PORT127_FN1),
- PINMUX_DATA(LCDD7_MARK, PORT128_FN1),
- PINMUX_DATA(LCDD8_MARK, PORT129_FN1),
- PINMUX_DATA(LCDD9_MARK, PORT130_FN1),
- PINMUX_DATA(LCDD10_MARK, PORT131_FN1),
- PINMUX_DATA(LCDD11_MARK, PORT132_FN1),
- PINMUX_DATA(LCDD12_MARK, PORT133_FN1),
- PINMUX_DATA(LCDD13_MARK, PORT134_FN1),
- PINMUX_DATA(LCDD14_MARK, PORT135_FN1),
- PINMUX_DATA(LCDD15_MARK, PORT136_FN1),
- PINMUX_DATA(LCDD16_MARK, PORT137_FN1),
- PINMUX_DATA(LCDD17_MARK, PORT138_FN1),
- PINMUX_DATA(LCDD18_MARK, PORT139_FN1),
- PINMUX_DATA(LCDD19_MARK, PORT140_FN1),
- PINMUX_DATA(LCDD20_MARK, PORT141_FN1),
- PINMUX_DATA(LCDD21_MARK, PORT142_FN1),
- PINMUX_DATA(LCDD22_MARK, PORT143_FN1),
- PINMUX_DATA(LCDD23_MARK, PORT144_FN1),
- PINMUX_DATA(LCDHSYN_MARK, PORT145_FN1),
- PINMUX_DATA(LCDVSYN_MARK, PORT146_FN1),
- PINMUX_DATA(LCDDCK_MARK, PORT147_FN1),
- PINMUX_DATA(LCDRD_MARK, PORT148_FN1),
- PINMUX_DATA(LCDDISP_MARK, PORT149_FN1),
- PINMUX_DATA(LCDLCLK_MARK, PORT150_FN1),
- PINMUX_DATA(LCDDON_MARK, PORT151_FN1),
- PINMUX_DATA(SCIFA0_TXD_MARK, PORT152_FN1),
- PINMUX_DATA(SCIFA0_RXD_MARK, PORT153_FN1),
- PINMUX_DATA(SCIFA1_TXD_MARK, PORT154_FN1),
- PINMUX_DATA(SCIFA1_RXD_MARK, PORT155_FN1),
- PINMUX_DATA(TS_SPSYNC1_MARK, PORT156_FN1),
- PINMUX_DATA(TS_SDAT1_MARK, PORT157_FN1),
- PINMUX_DATA(TS_SDEN1_MARK, PORT158_FN1),
- PINMUX_DATA(TS_SCK1_MARK, PORT159_FN1),
- PINMUX_DATA(TPU0TO0_MARK, PORT160_FN1),
- PINMUX_DATA(TPU0TO1_MARK, PORT161_FN1),
- PINMUX_DATA(SCIFB_SCK_MARK, PORT162_FN1),
- PINMUX_DATA(SCIFB_RTS_MARK, PORT163_FN1),
- PINMUX_DATA(SCIFB_CTS_MARK, PORT164_FN1),
- PINMUX_DATA(SCIFB_TXD_MARK, PORT165_FN1),
- PINMUX_DATA(SCIFB_RXD_MARK, PORT166_FN1),
- PINMUX_DATA(VBUS0_0_MARK, PORT167_FN1),
- PINMUX_DATA(VBUS0_1_MARK, PORT168_FN1),
- PINMUX_DATA(HDMI_HPD_MARK, PORT169_FN1),
- PINMUX_DATA(HDMI_CEC_MARK, PORT170_FN1),
- PINMUX_DATA(SDHICLK0_MARK, PORT171_FN1),
- PINMUX_DATA(SDHICD0_MARK, PORT172_FN1),
- PINMUX_DATA(SDHID0_0_MARK, PORT173_FN1),
- PINMUX_DATA(SDHID0_1_MARK, PORT174_FN1),
- PINMUX_DATA(SDHID0_2_MARK, PORT175_FN1),
- PINMUX_DATA(SDHID0_3_MARK, PORT176_FN1),
- PINMUX_DATA(SDHICMD0_MARK, PORT177_FN1),
- PINMUX_DATA(SDHIWP0_MARK, PORT178_FN1),
- PINMUX_DATA(SDHICLK1_MARK, PORT179_FN1),
- PINMUX_DATA(SDHID1_0_MARK, PORT180_FN1),
- PINMUX_DATA(SDHID1_1_MARK, PORT181_FN1),
- PINMUX_DATA(SDHID1_2_MARK, PORT182_FN1),
- PINMUX_DATA(SDHID1_3_MARK, PORT183_FN1),
- PINMUX_DATA(SDHICMD1_MARK, PORT184_FN1),
- PINMUX_DATA(SDHICLK2_MARK, PORT185_FN1),
- PINMUX_DATA(SDHID2_0_MARK, PORT186_FN1),
- PINMUX_DATA(SDHID2_1_MARK, PORT187_FN1),
- PINMUX_DATA(SDHID2_2_MARK, PORT188_FN1),
- PINMUX_DATA(SDHID2_3_MARK, PORT189_FN1),
- PINMUX_DATA(SDHICMD2_MARK, PORT190_FN1),
-
- /* Function 2 */
- PINMUX_DATA(FSIBCK_MARK, PORT4_FN2),
- PINMUX_DATA(SCIFA4_RXD_MARK, PORT5_FN2),
- PINMUX_DATA(SCIFA4_TXD_MARK, PORT6_FN2),
- PINMUX_DATA(SCIFA5_RXD_MARK, PORT8_FN2),
- PINMUX_DATA(FSIASPDIF_11_MARK, PORT11_FN2),
- PINMUX_DATA(SCIFA5_TXD_MARK, PORT12_FN2),
- PINMUX_DATA(FMSIOLR_MARK, PORT13_FN2),
- PINMUX_DATA(FMSIOBT_MARK, PORT14_FN2),
- PINMUX_DATA(FSIASPDIF_15_MARK, PORT15_FN2),
- PINMUX_DATA(FMSIILR_MARK, PORT16_FN2),
- PINMUX_DATA(FMSIIBT_MARK, PORT17_FN2),
- PINMUX_DATA(BS_MARK, PORT19_FN2),
- PINMUX_DATA(MSIOF0_TSYNC_MARK, PORT36_FN2),
- PINMUX_DATA(MSIOF0_TSCK_MARK, PORT37_FN2),
- PINMUX_DATA(MSIOF0_RXD_MARK, PORT38_FN2),
- PINMUX_DATA(MSIOF0_RSCK_MARK, PORT39_FN2),
- PINMUX_DATA(MSIOF0_RSYNC_MARK, PORT40_FN2),
- PINMUX_DATA(MSIOF0_MCK0_MARK, PORT41_FN2),
- PINMUX_DATA(MSIOF0_MCK1_MARK, PORT42_FN2),
- PINMUX_DATA(MSIOF0_SS1_MARK, PORT43_FN2),
- PINMUX_DATA(MSIOF0_SS2_MARK, PORT44_FN2),
- PINMUX_DATA(MSIOF0_TXD_MARK, PORT45_FN2),
- PINMUX_DATA(FMSICK_MARK, PORT65_FN2),
- PINMUX_DATA(FCE1_MARK, PORT66_FN2),
- PINMUX_DATA(BBIF1_RXD_MARK, PORT76_FN2),
- PINMUX_DATA(BBIF1_TSYNC_MARK, PORT77_FN2),
- PINMUX_DATA(BBIF1_TSCK_MARK, PORT78_FN2),
- PINMUX_DATA(BBIF1_TXD_MARK, PORT79_FN2),
- PINMUX_DATA(BBIF1_RSCK_MARK, PORT80_FN2),
- PINMUX_DATA(BBIF1_RSYNC_MARK, PORT81_FN2),
- PINMUX_DATA(BBIF1_FLOW_MARK, PORT82_FN2),
- PINMUX_DATA(BB_RX_FLOW_N_MARK, PORT83_FN2),
- PINMUX_DATA(MSIOF1_RSCK_MARK, PORT84_FN2),
- PINMUX_DATA(MSIOF1_RSYNC_MARK, PORT85_FN2),
- PINMUX_DATA(MSIOF1_MCK0_MARK, PORT86_FN2),
- PINMUX_DATA(MSIOF1_MCK1_MARK, PORT87_FN2),
- PINMUX_DATA(MSIOF1_TSCK_88_MARK, PORT88_FN2, MSEL4CR_10_1),
- PINMUX_DATA(MSIOF1_TSYNC_89_MARK, PORT89_FN2, MSEL4CR_10_1),
- PINMUX_DATA(MSIOF1_TXD_90_MARK, PORT90_FN2, MSEL4CR_10_1),
- PINMUX_DATA(MSIOF1_RXD_91_MARK, PORT91_FN2, MSEL4CR_10_1),
- PINMUX_DATA(MSIOF1_SS1_92_MARK, PORT92_FN2, MSEL4CR_10_1),
- PINMUX_DATA(MSIOF1_SS2_93_MARK, PORT93_FN2, MSEL4CR_10_1),
- PINMUX_DATA(SCIFA2_CTS1_MARK, PORT94_FN2),
- PINMUX_DATA(SCIFA2_RTS1_MARK, PORT95_FN2),
- PINMUX_DATA(SCIFA2_TXD1_MARK, PORT96_FN2),
- PINMUX_DATA(SCIFA2_RXD1_MARK, PORT97_FN2),
- PINMUX_DATA(SCIFA2_SCK1_MARK, PORT98_FN2),
- PINMUX_DATA(I2C_SCL2_MARK, PORT110_FN2),
- PINMUX_DATA(I2C_SDA2_MARK, PORT111_FN2),
- PINMUX_DATA(I2C_SCL3_MARK, PORT114_FN2, MSEL4CR_16_1),
- PINMUX_DATA(I2C_SDA3_MARK, PORT115_FN2, MSEL4CR_16_1),
- PINMUX_DATA(I2C_SCL4_MARK, PORT116_FN2, MSEL4CR_17_1),
- PINMUX_DATA(I2C_SDA4_MARK, PORT117_FN2, MSEL4CR_17_1),
- PINMUX_DATA(MSIOF2_RSCK_MARK, PORT134_FN2),
- PINMUX_DATA(MSIOF2_RSYNC_MARK, PORT135_FN2),
- PINMUX_DATA(MSIOF2_MCK0_MARK, PORT136_FN2),
- PINMUX_DATA(MSIOF2_MCK1_MARK, PORT137_FN2),
- PINMUX_DATA(MSIOF2_SS1_MARK, PORT138_FN2),
- PINMUX_DATA(MSIOF2_SS2_MARK, PORT139_FN2),
- PINMUX_DATA(SCIFA3_CTS_140_MARK, PORT140_FN2, MSEL3CR_9_1),
- PINMUX_DATA(SCIFA3_RTS_141_MARK, PORT141_FN2),
- PINMUX_DATA(SCIFA3_SCK_MARK, PORT142_FN2),
- PINMUX_DATA(SCIFA3_TXD_MARK, PORT143_FN2),
- PINMUX_DATA(SCIFA3_RXD_MARK, PORT144_FN2),
- PINMUX_DATA(MSIOF2_TSYNC_MARK, PORT148_FN2),
- PINMUX_DATA(MSIOF2_TSCK_MARK, PORT149_FN2),
- PINMUX_DATA(MSIOF2_RXD_MARK, PORT150_FN2),
- PINMUX_DATA(MSIOF2_TXD_MARK, PORT151_FN2),
- PINMUX_DATA(SCIFA0_SCK_MARK, PORT156_FN2),
- PINMUX_DATA(SCIFA0_RTS_MARK, PORT157_FN2),
- PINMUX_DATA(SCIFA0_CTS_MARK, PORT158_FN2),
- PINMUX_DATA(SCIFA1_SCK_MARK, PORT159_FN2),
- PINMUX_DATA(SCIFA1_RTS_MARK, PORT160_FN2),
- PINMUX_DATA(SCIFA1_CTS_MARK, PORT161_FN2),
-
- /* Function 3 */
- PINMUX_DATA(VIO_CKO1_MARK, PORT16_FN3),
- PINMUX_DATA(VIO_CKO2_MARK, PORT17_FN3),
- PINMUX_DATA(IDIN_1_18_MARK, PORT18_FN3, MSEL4CR_14_1),
- PINMUX_DATA(MSIOF1_TSCK_39_MARK, PORT39_FN3, MSEL4CR_10_0),
- PINMUX_DATA(MSIOF1_TSYNC_40_MARK, PORT40_FN3, MSEL4CR_10_0),
- PINMUX_DATA(MSIOF1_TXD_41_MARK, PORT41_FN3, MSEL4CR_10_0),
- PINMUX_DATA(MSIOF1_RXD_42_MARK, PORT42_FN3, MSEL4CR_10_0),
- PINMUX_DATA(MSIOF1_SS1_43_MARK, PORT43_FN3, MSEL4CR_10_0),
- PINMUX_DATA(MSIOF1_SS2_44_MARK, PORT44_FN3, MSEL4CR_10_0),
- PINMUX_DATA(MMCD1_0_MARK, PORT54_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_1_MARK, PORT55_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_2_MARK, PORT56_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_3_MARK, PORT57_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_4_MARK, PORT58_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_5_MARK, PORT59_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_6_MARK, PORT60_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCD1_7_MARK, PORT61_FN3, MSEL4CR_15_1),
- PINMUX_DATA(VINT_I_MARK, PORT65_FN3),
- PINMUX_DATA(MMCCLK1_MARK, PORT66_FN3, MSEL4CR_15_1),
- PINMUX_DATA(MMCCMD1_MARK, PORT67_FN3, MSEL4CR_15_1),
- PINMUX_DATA(TPU0TO2_93_MARK, PORT93_FN3),
- PINMUX_DATA(TPU0TO2_99_MARK, PORT99_FN3),
- PINMUX_DATA(TPU0TO3_MARK, PORT112_FN3),
- PINMUX_DATA(IDIN_0_MARK, PORT113_FN3),
- PINMUX_DATA(EXTLP_0_MARK, PORT114_FN3),
- PINMUX_DATA(OVCN2_0_MARK, PORT115_FN3),
- PINMUX_DATA(PWEN_0_MARK, PORT116_FN3),
- PINMUX_DATA(OVCN_0_MARK, PORT117_FN3),
- PINMUX_DATA(KEYOUT7_MARK, PORT121_FN3),
- PINMUX_DATA(KEYOUT6_MARK, PORT122_FN3),
- PINMUX_DATA(KEYOUT5_MARK, PORT123_FN3),
- PINMUX_DATA(KEYOUT4_MARK, PORT124_FN3),
- PINMUX_DATA(KEYOUT3_MARK, PORT125_FN3),
- PINMUX_DATA(KEYOUT2_MARK, PORT126_FN3),
- PINMUX_DATA(KEYOUT1_MARK, PORT127_FN3),
- PINMUX_DATA(KEYOUT0_MARK, PORT128_FN3),
- PINMUX_DATA(KEYIN7_MARK, PORT129_FN3),
- PINMUX_DATA(KEYIN6_MARK, PORT130_FN3),
- PINMUX_DATA(KEYIN5_MARK, PORT131_FN3),
- PINMUX_DATA(KEYIN4_MARK, PORT132_FN3),
- PINMUX_DATA(KEYIN3_133_MARK, PORT133_FN3, MSEL4CR_18_0),
- PINMUX_DATA(KEYIN2_134_MARK, PORT134_FN3, MSEL4CR_18_0),
- PINMUX_DATA(KEYIN1_135_MARK, PORT135_FN3, MSEL4CR_18_0),
- PINMUX_DATA(KEYIN0_136_MARK, PORT136_FN3, MSEL4CR_18_0),
- PINMUX_DATA(TS_SPSYNC2_MARK, PORT137_FN3),
- PINMUX_DATA(IROUT_139_MARK, PORT139_FN3),
- PINMUX_DATA(IRDA_OUT_MARK, PORT140_FN3),
- PINMUX_DATA(IRDA_IN_MARK, PORT141_FN3),
- PINMUX_DATA(IRDA_FIRSEL_MARK, PORT142_FN3),
- PINMUX_DATA(TS_SDAT2_MARK, PORT145_FN3),
- PINMUX_DATA(TS_SDEN2_MARK, PORT146_FN3),
- PINMUX_DATA(TS_SCK2_MARK, PORT147_FN3),
-
- /* Function 4 */
- PINMUX_DATA(SCIFA3_CTS_43_MARK, PORT43_FN4, MSEL3CR_9_0),
- PINMUX_DATA(SCIFA3_RTS_44_MARK, PORT44_FN4),
- PINMUX_DATA(GP_RX_FLAG_MARK, PORT76_FN4),
- PINMUX_DATA(GP_RX_DATA_MARK, PORT77_FN4),
- PINMUX_DATA(GP_TX_READY_MARK, PORT78_FN4),
- PINMUX_DATA(GP_RX_WAKE_MARK, PORT79_FN4),
- PINMUX_DATA(MP_TX_FLAG_MARK, PORT80_FN4),
- PINMUX_DATA(MP_TX_DATA_MARK, PORT81_FN4),
- PINMUX_DATA(MP_RX_READY_MARK, PORT82_FN4),
- PINMUX_DATA(MP_TX_WAKE_MARK, PORT83_FN4),
- PINMUX_DATA(MMCD0_0_MARK, PORT84_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_1_MARK, PORT85_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_2_MARK, PORT86_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_3_MARK, PORT87_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_4_MARK, PORT88_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_5_MARK, PORT89_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_6_MARK, PORT90_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCD0_7_MARK, PORT91_FN4, MSEL4CR_15_0),
- PINMUX_DATA(MMCCMD0_MARK, PORT92_FN4, MSEL4CR_15_0),
- PINMUX_DATA(SIM_RST_MARK, PORT94_FN4),
- PINMUX_DATA(SIM_CLK_MARK, PORT95_FN4),
- PINMUX_DATA(SIM_D_MARK, PORT98_FN4),
- PINMUX_DATA(MMCCLK0_MARK, PORT99_FN4, MSEL4CR_15_0),
- PINMUX_DATA(IDIN_1_113_MARK, PORT113_FN4, MSEL4CR_14_0),
- PINMUX_DATA(OVCN_1_114_MARK, PORT114_FN4, MSEL4CR_14_0),
- PINMUX_DATA(PWEN_1_115_MARK, PORT115_FN4),
- PINMUX_DATA(EXTLP_1_MARK, PORT116_FN4),
- PINMUX_DATA(OVCN2_1_MARK, PORT117_FN4),
- PINMUX_DATA(KEYIN0_121_MARK, PORT121_FN4, MSEL4CR_18_1),
- PINMUX_DATA(KEYIN1_122_MARK, PORT122_FN4, MSEL4CR_18_1),
- PINMUX_DATA(KEYIN2_123_MARK, PORT123_FN4, MSEL4CR_18_1),
- PINMUX_DATA(KEYIN3_124_MARK, PORT124_FN4, MSEL4CR_18_1),
- PINMUX_DATA(PWEN_1_138_MARK, PORT138_FN4),
- PINMUX_DATA(IROUT_140_MARK, PORT140_FN4),
- PINMUX_DATA(LCDCS_MARK, PORT145_FN4),
- PINMUX_DATA(LCDWR_MARK, PORT147_FN4),
- PINMUX_DATA(LCDRS_MARK, PORT149_FN4),
- PINMUX_DATA(OVCN_1_162_MARK, PORT162_FN4, MSEL4CR_14_1),
-
- /* Function 5 */
- PINMUX_DATA(GPI0_MARK, PORT41_FN5),
- PINMUX_DATA(GPI1_MARK, PORT42_FN5),
- PINMUX_DATA(GPO0_MARK, PORT43_FN5),
- PINMUX_DATA(GPO1_MARK, PORT44_FN5),
- PINMUX_DATA(I2C_SCL3S_MARK, PORT137_FN5, MSEL4CR_16_0),
- PINMUX_DATA(I2C_SDA3S_MARK, PORT145_FN5, MSEL4CR_16_0),
- PINMUX_DATA(I2C_SCL4S_MARK, PORT146_FN5, MSEL4CR_17_0),
- PINMUX_DATA(I2C_SDA4S_MARK, PORT147_FN5, MSEL4CR_17_0),
-
- /* Function select */
- PINMUX_DATA(LCDC0_SELECT_MARK, MSEL3CR_6_0),
- PINMUX_DATA(LCDC1_SELECT_MARK, MSEL3CR_6_1),
-
- PINMUX_DATA(TS0_1SELECT_MARK, MSEL3CR_21_0, MSEL3CR_20_0),
- PINMUX_DATA(TS0_2SELECT_MARK, MSEL3CR_21_0, MSEL3CR_20_1),
- PINMUX_DATA(TS1_1SELECT_MARK, MSEL3CR_27_0, MSEL3CR_26_0),
- PINMUX_DATA(TS1_2SELECT_MARK, MSEL3CR_27_0, MSEL3CR_26_1),
-
- PINMUX_DATA(SDENC_CPG_MARK, MSEL4CR_19_0),
- PINMUX_DATA(SDENC_DV_CLKI_MARK, MSEL4CR_19_1),
-
- PINMUX_DATA(MFIv6_MARK, MSEL4CR_6_0),
- PINMUX_DATA(MFIv4_MARK, MSEL4CR_6_1),
-};
-
-#define __I (SH_PFC_PIN_CFG_INPUT)
-#define __O (SH_PFC_PIN_CFG_OUTPUT)
-#define __IO (SH_PFC_PIN_CFG_INPUT | SH_PFC_PIN_CFG_OUTPUT)
-#define __PD (SH_PFC_PIN_CFG_PULL_DOWN)
-#define __PU (SH_PFC_PIN_CFG_PULL_UP)
-#define __PUD (SH_PFC_PIN_CFG_PULL_DOWN | SH_PFC_PIN_CFG_PULL_UP)
-
-#define SH7372_PIN_I_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PD)
-#define SH7372_PIN_I_PU(pin) SH_PFC_PIN_CFG(pin, __I | __PU)
-#define SH7372_PIN_I_PU_PD(pin) SH_PFC_PIN_CFG(pin, __I | __PUD)
-#define SH7372_PIN_IO(pin) SH_PFC_PIN_CFG(pin, __IO)
-#define SH7372_PIN_IO_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PD)
-#define SH7372_PIN_IO_PU(pin) SH_PFC_PIN_CFG(pin, __IO | __PU)
-#define SH7372_PIN_IO_PU_PD(pin) SH_PFC_PIN_CFG(pin, __IO | __PUD)
-#define SH7372_PIN_O(pin) SH_PFC_PIN_CFG(pin, __O)
-#define SH7372_PIN_O_PU_PD(pin) SH_PFC_PIN_CFG(pin, __O | __PUD)
-
-static const struct sh_pfc_pin pinmux_pins[] = {
- /* Table 57-1 (I/O and Pull U/D) */
- SH7372_PIN_IO_PD(0), SH7372_PIN_IO_PD(1),
- SH7372_PIN_O(2), SH7372_PIN_I_PD(3),
- SH7372_PIN_I_PD(4), SH7372_PIN_I_PD(5),
- SH7372_PIN_IO_PU_PD(6), SH7372_PIN_I_PD(7),
- SH7372_PIN_IO_PD(8), SH7372_PIN_O(9),
- SH7372_PIN_O(10), SH7372_PIN_O(11),
- SH7372_PIN_IO_PU_PD(12), SH7372_PIN_IO_PD(13),
- SH7372_PIN_IO_PD(14), SH7372_PIN_O(15),
- SH7372_PIN_IO_PD(16), SH7372_PIN_IO_PD(17),
- SH7372_PIN_I_PD(18), SH7372_PIN_IO(19),
- SH7372_PIN_IO(20), SH7372_PIN_IO(21),
- SH7372_PIN_IO(22), SH7372_PIN_IO(23),
- SH7372_PIN_IO(24), SH7372_PIN_IO(25),
- SH7372_PIN_IO(26), SH7372_PIN_IO(27),
- SH7372_PIN_IO(28), SH7372_PIN_IO(29),
- SH7372_PIN_IO(30), SH7372_PIN_IO(31),
- SH7372_PIN_IO(32), SH7372_PIN_IO(33),
- SH7372_PIN_IO(34), SH7372_PIN_IO(35),
- SH7372_PIN_IO(36), SH7372_PIN_IO(37),
- SH7372_PIN_IO(38), SH7372_PIN_IO(39),
- SH7372_PIN_IO(40), SH7372_PIN_IO(41),
- SH7372_PIN_IO(42), SH7372_PIN_IO(43),
- SH7372_PIN_IO(44), SH7372_PIN_IO(45),
- SH7372_PIN_IO_PU(46), SH7372_PIN_IO_PU(47),
- SH7372_PIN_IO_PU(48), SH7372_PIN_IO_PU(49),
- SH7372_PIN_IO_PU(50), SH7372_PIN_IO_PU(51),
- SH7372_PIN_IO_PU(52), SH7372_PIN_IO_PU(53),
- SH7372_PIN_IO_PU(54), SH7372_PIN_IO_PU(55),
- SH7372_PIN_IO_PU(56), SH7372_PIN_IO_PU(57),
- SH7372_PIN_IO_PU(58), SH7372_PIN_IO_PU(59),
- SH7372_PIN_IO_PU(60), SH7372_PIN_IO_PU(61),
- SH7372_PIN_IO(62), SH7372_PIN_O(63),
- SH7372_PIN_O(64), SH7372_PIN_IO_PU(65),
- SH7372_PIN_O_PU_PD(66), SH7372_PIN_IO_PU(67),
- SH7372_PIN_O(68), SH7372_PIN_IO(69),
- SH7372_PIN_IO(70), SH7372_PIN_IO(71),
- SH7372_PIN_O(72), SH7372_PIN_I_PU(73),
- SH7372_PIN_I_PU_PD(74), SH7372_PIN_IO_PU_PD(75),
- SH7372_PIN_IO_PU_PD(76), SH7372_PIN_IO_PU_PD(77),
- SH7372_PIN_IO_PU_PD(78), SH7372_PIN_IO_PU_PD(79),
- SH7372_PIN_IO_PU_PD(80), SH7372_PIN_IO_PU_PD(81),
- SH7372_PIN_IO_PU_PD(82), SH7372_PIN_IO_PU_PD(83),
- SH7372_PIN_IO_PU_PD(84), SH7372_PIN_IO_PU_PD(85),
- SH7372_PIN_IO_PU_PD(86), SH7372_PIN_IO_PU_PD(87),
- SH7372_PIN_IO_PU_PD(88), SH7372_PIN_IO_PU_PD(89),
- SH7372_PIN_IO_PU_PD(90), SH7372_PIN_IO_PU_PD(91),
- SH7372_PIN_IO_PU_PD(92), SH7372_PIN_IO_PU_PD(93),
- SH7372_PIN_IO_PU_PD(94), SH7372_PIN_IO_PU_PD(95),
- SH7372_PIN_IO_PU(96), SH7372_PIN_IO_PU_PD(97),
- SH7372_PIN_IO_PU_PD(98), SH7372_PIN_O_PU_PD(99),
- SH7372_PIN_IO_PD(100), SH7372_PIN_IO_PD(101),
- SH7372_PIN_IO_PD(102), SH7372_PIN_IO_PD(103),
- SH7372_PIN_IO_PD(104), SH7372_PIN_IO_PD(105),
- SH7372_PIN_IO_PU(106), SH7372_PIN_IO_PU(107),
- SH7372_PIN_IO_PU(108), SH7372_PIN_IO_PU(109),
- SH7372_PIN_IO_PU(110), SH7372_PIN_IO_PU(111),
- SH7372_PIN_IO_PD(112), SH7372_PIN_IO_PD(113),
- SH7372_PIN_IO_PU(114), SH7372_PIN_IO_PU(115),
- SH7372_PIN_IO_PU(116), SH7372_PIN_IO_PU(117),
- SH7372_PIN_IO_PU(118), SH7372_PIN_IO_PU(119),
- SH7372_PIN_IO_PU(120), SH7372_PIN_IO_PD(121),
- SH7372_PIN_IO_PD(122), SH7372_PIN_IO_PD(123),
- SH7372_PIN_IO_PD(124), SH7372_PIN_IO_PD(125),
- SH7372_PIN_IO_PD(126), SH7372_PIN_IO_PD(127),
- SH7372_PIN_IO_PD(128), SH7372_PIN_IO_PU_PD(129),
- SH7372_PIN_IO_PU_PD(130), SH7372_PIN_IO_PU_PD(131),
- SH7372_PIN_IO_PU_PD(132), SH7372_PIN_IO_PU_PD(133),
- SH7372_PIN_IO_PU_PD(134), SH7372_PIN_IO_PU_PD(135),
- SH7372_PIN_IO_PD(136), SH7372_PIN_IO_PD(137),
- SH7372_PIN_IO_PD(138), SH7372_PIN_IO_PD(139),
- SH7372_PIN_IO_PD(140), SH7372_PIN_IO_PD(141),
- SH7372_PIN_IO_PD(142), SH7372_PIN_IO_PU_PD(143),
- SH7372_PIN_IO_PD(144), SH7372_PIN_IO_PD(145),
- SH7372_PIN_IO_PD(146), SH7372_PIN_IO_PD(147),
- SH7372_PIN_IO_PD(148), SH7372_PIN_IO_PD(149),
- SH7372_PIN_IO_PD(150), SH7372_PIN_IO_PD(151),
- SH7372_PIN_IO_PU_PD(152), SH7372_PIN_I_PD(153),
- SH7372_PIN_IO_PU_PD(154), SH7372_PIN_I_PD(155),
- SH7372_PIN_IO_PD(156), SH7372_PIN_IO_PD(157),
- SH7372_PIN_I_PD(158), SH7372_PIN_IO_PD(159),
- SH7372_PIN_O(160), SH7372_PIN_IO_PD(161),
- SH7372_PIN_IO_PD(162), SH7372_PIN_IO_PD(163),
- SH7372_PIN_I_PD(164), SH7372_PIN_IO_PD(165),
- SH7372_PIN_I_PD(166), SH7372_PIN_I_PD(167),
- SH7372_PIN_I_PD(168), SH7372_PIN_I_PD(169),
- SH7372_PIN_I_PD(170), SH7372_PIN_O(171),
- SH7372_PIN_IO_PU_PD(172), SH7372_PIN_IO_PU_PD(173),
- SH7372_PIN_IO_PU_PD(174), SH7372_PIN_IO_PU_PD(175),
- SH7372_PIN_IO_PU_PD(176), SH7372_PIN_IO_PU_PD(177),
- SH7372_PIN_IO_PU_PD(178), SH7372_PIN_O(179),
- SH7372_PIN_IO_PU_PD(180), SH7372_PIN_IO_PU_PD(181),
- SH7372_PIN_IO_PU_PD(182), SH7372_PIN_IO_PU_PD(183),
- SH7372_PIN_IO_PU_PD(184), SH7372_PIN_O(185),
- SH7372_PIN_IO_PU_PD(186), SH7372_PIN_IO_PU_PD(187),
- SH7372_PIN_IO_PU_PD(188), SH7372_PIN_IO_PU_PD(189),
- SH7372_PIN_IO_PU_PD(190),
-};
-
-/* - BSC -------------------------------------------------------------------- */
-static const unsigned int bsc_data8_pins[] = {
- /* D[0:7] */
- 46, 47, 48, 49, 50, 51, 52, 53,
-};
-static const unsigned int bsc_data8_mux[] = {
- D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK,
- D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK,
-};
-static const unsigned int bsc_data16_pins[] = {
- /* D[0:15] */
- 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
-};
-static const unsigned int bsc_data16_mux[] = {
- D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK,
- D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK,
- D8_NAF8_MARK, D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK,
- D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, D15_NAF15_MARK,
-};
-static const unsigned int bsc_cs0_pins[] = {
- /* CS */
- 62,
-};
-static const unsigned int bsc_cs0_mux[] = {
- CS0_MARK,
-};
-static const unsigned int bsc_cs2_pins[] = {
- /* CS */
- 63,
-};
-static const unsigned int bsc_cs2_mux[] = {
- CS2_MARK,
-};
-static const unsigned int bsc_cs4_pins[] = {
- /* CS */
- 64,
-};
-static const unsigned int bsc_cs4_mux[] = {
- CS4_MARK,
-};
-static const unsigned int bsc_cs5a_pins[] = {
- /* CS */
- 65,
-};
-static const unsigned int bsc_cs5a_mux[] = {
- CS5A_MARK,
-};
-static const unsigned int bsc_cs5b_pins[] = {
- /* CS */
- 66,
-};
-static const unsigned int bsc_cs5b_mux[] = {
- CS5B_MARK,
-};
-static const unsigned int bsc_cs6a_pins[] = {
- /* CS */
- 67,
-};
-static const unsigned int bsc_cs6a_mux[] = {
- CS6A_MARK,
-};
-static const unsigned int bsc_rd_we8_pins[] = {
- /* RD, WE[0] */
- 69, 70,
-};
-static const unsigned int bsc_rd_we8_mux[] = {
- RD_FSC_MARK, WE0_FWE_MARK,
-};
-static const unsigned int bsc_rd_we16_pins[] = {
- /* RD, WE[0:1] */
- 69, 70, 71,
-};
-static const unsigned int bsc_rd_we16_mux[] = {
- RD_FSC_MARK, WE0_FWE_MARK, WE1_MARK,
-};
-static const unsigned int bsc_bs_pins[] = {
- /* BS */
- 19,
-};
-static const unsigned int bsc_bs_mux[] = {
- BS_MARK,
-};
-static const unsigned int bsc_rdwr_pins[] = {
- /* RDWR */
- 75,
-};
-static const unsigned int bsc_rdwr_mux[] = {
- RDWR_MARK,
-};
-static const unsigned int bsc_wait_pins[] = {
- /* WAIT */
- 74,
-};
-static const unsigned int bsc_wait_mux[] = {
- WAIT_MARK,
-};
-/* - CEU -------------------------------------------------------------------- */
-static const unsigned int ceu_data_0_7_pins[] = {
- /* D[0:7] */
- 102, 103, 104, 105, 106, 107, 108, 109,
-};
-static const unsigned int ceu_data_0_7_mux[] = {
- VIO_D0_MARK, VIO_D1_MARK, VIO_D2_MARK, VIO_D3_MARK,
- VIO_D4_MARK, VIO_D5_MARK, VIO_D6_MARK, VIO_D7_MARK,
-};
-static const unsigned int ceu_data_8_15_pins[] = {
- /* D[8:15] */
- 110, 111, 112, 113, 114, 115, 116, 117,
-};
-static const unsigned int ceu_data_8_15_mux[] = {
- VIO_D8_MARK, VIO_D9_MARK, VIO_D10_MARK, VIO_D11_MARK,
- VIO_D12_MARK, VIO_D13_MARK, VIO_D14_MARK, VIO_D15_MARK,
-};
-static const unsigned int ceu_clk_0_pins[] = {
- /* CKO */
- 120,
-};
-static const unsigned int ceu_clk_0_mux[] = {
- VIO_CKO_MARK,
-};
-static const unsigned int ceu_clk_1_pins[] = {
- /* CKO */
- 16,
-};
-static const unsigned int ceu_clk_1_mux[] = {
- VIO_CKO1_MARK,
-};
-static const unsigned int ceu_clk_2_pins[] = {
- /* CKO */
- 17,
-};
-static const unsigned int ceu_clk_2_mux[] = {
- VIO_CKO2_MARK,
-};
-static const unsigned int ceu_sync_pins[] = {
- /* CLK, VD, HD */
- 118, 100, 101,
-};
-static const unsigned int ceu_sync_mux[] = {
- VIO_CLK_MARK, VIO_VD_MARK, VIO_HD_MARK,
-};
-static const unsigned int ceu_field_pins[] = {
- /* FIELD */
- 119,
-};
-static const unsigned int ceu_field_mux[] = {
- VIO_FIELD_MARK,
-};
-/* - FLCTL ------------------------------------------------------------------ */
-static const unsigned int flctl_data_pins[] = {
- /* NAF[0:15] */
- 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
-};
-static const unsigned int flctl_data_mux[] = {
- D0_NAF0_MARK, D1_NAF1_MARK, D2_NAF2_MARK, D3_NAF3_MARK,
- D4_NAF4_MARK, D5_NAF5_MARK, D6_NAF6_MARK, D7_NAF7_MARK,
- D8_NAF8_MARK, D9_NAF9_MARK, D10_NAF10_MARK, D11_NAF11_MARK,
- D12_NAF12_MARK, D13_NAF13_MARK, D14_NAF14_MARK, D15_NAF15_MARK,
-};
-static const unsigned int flctl_ce0_pins[] = {
- /* CE */
- 68,
-};
-static const unsigned int flctl_ce0_mux[] = {
- FCE0_MARK,
-};
-static const unsigned int flctl_ce1_pins[] = {
- /* CE */
- 66,
-};
-static const unsigned int flctl_ce1_mux[] = {
- FCE1_MARK,
-};
-static const unsigned int flctl_ctrl_pins[] = {
- /* FCDE, FOE, FSC, FWE, FRB */
- 24, 23, 69, 70, 73,
-};
-static const unsigned int flctl_ctrl_mux[] = {
- A5_FCDE_MARK, A4_FOE_MARK, RD_FSC_MARK, WE0_FWE_MARK, FRB_MARK,
-};
-/* - FSIA ------------------------------------------------------------------- */
-static const unsigned int fsia_mclk_in_pins[] = {
- /* CK */
- 4,
-};
-static const unsigned int fsia_mclk_in_mux[] = {
- FSIACK_MARK,
-};
-static const unsigned int fsia_mclk_out_pins[] = {
- /* OMC */
- 8,
-};
-static const unsigned int fsia_mclk_out_mux[] = {
- FSIAOMC_MARK,
-};
-static const unsigned int fsia_sclk_in_pins[] = {
- /* ILR, IBT */
- 5, 6,
-};
-static const unsigned int fsia_sclk_in_mux[] = {
- FSIAILR_MARK, FSIAIBT_MARK,
-};
-static const unsigned int fsia_sclk_out_pins[] = {
- /* OLR, OBT */
- 9, 10,
-};
-static const unsigned int fsia_sclk_out_mux[] = {
- FSIAOLR_MARK, FSIAOBT_MARK,
-};
-static const unsigned int fsia_data_in_pins[] = {
- /* ISLD */
- 7,
-};
-static const unsigned int fsia_data_in_mux[] = {
- FSIAISLD_MARK,
-};
-static const unsigned int fsia_data_out_pins[] = {
- /* OSLD */
- 11,
-};
-static const unsigned int fsia_data_out_mux[] = {
- FSIAOSLD_MARK,
-};
-static const unsigned int fsia_spdif_0_pins[] = {
- /* SPDIF */
- 11,
-};
-static const unsigned int fsia_spdif_0_mux[] = {
- FSIASPDIF_11_MARK,
-};
-static const unsigned int fsia_spdif_1_pins[] = {
- /* SPDIF */
- 15,
-};
-static const unsigned int fsia_spdif_1_mux[] = {
- FSIASPDIF_15_MARK,
-};
-/* - FSIB ------------------------------------------------------------------- */
-static const unsigned int fsib_mclk_in_pins[] = {
- /* CK */
- 4,
-};
-static const unsigned int fsib_mclk_in_mux[] = {
- FSIBCK_MARK,
-};
-/* - HDMI ------------------------------------------------------------------- */
-static const unsigned int hdmi_pins[] = {
- /* HPD, CEC */
- 169, 170,
-};
-static const unsigned int hdmi_mux[] = {
- HDMI_HPD_MARK, HDMI_CEC_MARK,
-};
-/* - INTC ------------------------------------------------------------------- */
-IRQC_PINS_MUX(0, 6, 162);
-IRQC_PIN_MUX(1, 12);
-IRQC_PINS_MUX(2, 4, 5);
-IRQC_PINS_MUX(3, 8, 16);
-IRQC_PINS_MUX(4, 17, 163);
-IRQC_PIN_MUX(5, 18);
-IRQC_PINS_MUX(6, 39, 164);
-IRQC_PINS_MUX(7, 40, 167);
-IRQC_PINS_MUX(8, 41, 168);
-IRQC_PINS_MUX(9, 42, 169);
-IRQC_PIN_MUX(10, 65);
-IRQC_PIN_MUX(11, 67);
-IRQC_PINS_MUX(12, 80, 137);
-IRQC_PINS_MUX(13, 81, 145);
-IRQC_PINS_MUX(14, 82, 146);
-IRQC_PINS_MUX(15, 83, 147);
-IRQC_PINS_MUX(16, 84, 170);
-IRQC_PIN_MUX(17, 85);
-IRQC_PIN_MUX(18, 86);
-IRQC_PIN_MUX(19, 87);
-IRQC_PIN_MUX(20, 92);
-IRQC_PIN_MUX(21, 93);
-IRQC_PIN_MUX(22, 94);
-IRQC_PIN_MUX(23, 95);
-IRQC_PIN_MUX(24, 112);
-IRQC_PIN_MUX(25, 119);
-IRQC_PINS_MUX(26, 121, 172);
-IRQC_PINS_MUX(27, 122, 180);
-IRQC_PINS_MUX(28, 123, 181);
-IRQC_PINS_MUX(29, 129, 182);
-IRQC_PINS_MUX(30, 130, 183);
-IRQC_PINS_MUX(31, 138, 184);
-/* - KEYSC ------------------------------------------------------------------ */
-static const unsigned int keysc_in04_0_pins[] = {
- /* KEYIN[0:4] */
- 136, 135, 134, 133, 132,
-};
-static const unsigned int keysc_in04_0_mux[] = {
- KEYIN0_136_MARK, KEYIN1_135_MARK, KEYIN2_134_MARK, KEYIN3_133_MARK,
- KEYIN4_MARK,
-};
-static const unsigned int keysc_in04_1_pins[] = {
- /* KEYIN[0:4] */
- 121, 122, 123, 124, 132,
-};
-static const unsigned int keysc_in04_1_mux[] = {
- KEYIN0_121_MARK, KEYIN1_122_MARK, KEYIN2_123_MARK, KEYIN3_124_MARK,
- KEYIN4_MARK,
-};
-static const unsigned int keysc_in5_pins[] = {
- /* KEYIN5 */
- 131,
-};
-static const unsigned int keysc_in5_mux[] = {
- KEYIN5_MARK,
-};
-static const unsigned int keysc_in6_pins[] = {
- /* KEYIN6 */
- 130,
-};
-static const unsigned int keysc_in6_mux[] = {
- KEYIN6_MARK,
-};
-static const unsigned int keysc_in7_pins[] = {
- /* KEYIN7 */
- 129,
-};
-static const unsigned int keysc_in7_mux[] = {
- KEYIN7_MARK,
-};
-static const unsigned int keysc_out4_pins[] = {
- /* KEYOUT[0:3] */
- 128, 127, 126, 125,
-};
-static const unsigned int keysc_out4_mux[] = {
- KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
-};
-static const unsigned int keysc_out5_pins[] = {
- /* KEYOUT[0:4] */
- 128, 127, 126, 125, 124,
-};
-static const unsigned int keysc_out5_mux[] = {
- KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
- KEYOUT4_MARK,
-};
-static const unsigned int keysc_out6_pins[] = {
- /* KEYOUT[0:5] */
- 128, 127, 126, 125, 124, 123,
-};
-static const unsigned int keysc_out6_mux[] = {
- KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
- KEYOUT4_MARK, KEYOUT5_MARK,
-};
-static const unsigned int keysc_out8_pins[] = {
- /* KEYOUT[0:7] */
- 128, 127, 126, 125, 124, 123, 122, 121,
-};
-static const unsigned int keysc_out8_mux[] = {
- KEYOUT0_MARK, KEYOUT1_MARK, KEYOUT2_MARK, KEYOUT3_MARK,
- KEYOUT4_MARK, KEYOUT5_MARK, KEYOUT6_MARK, KEYOUT7_MARK,
-};
-/* - LCD -------------------------------------------------------------------- */
-static const unsigned int lcd_data8_pins[] = {
- /* D[0:7] */
- 121, 122, 123, 124, 125, 126, 127, 128,
-};
-static const unsigned int lcd_data8_mux[] = {
- /* LCDC */
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
-};
-static const unsigned int lcd_data9_pins[] = {
- /* D[0:8] */
- 121, 122, 123, 124, 125, 126, 127, 128,
- 129,
- 137, 138, 139, 140, 141, 142, 143, 144,
-};
-static const unsigned int lcd_data9_mux[] = {
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
- LCDD8_MARK,
-};
-static const unsigned int lcd_data12_pins[] = {
- /* D[0:11] */
- 121, 122, 123, 124, 125, 126, 127, 128,
- 129, 130, 131, 132,
-};
-static const unsigned int lcd_data12_mux[] = {
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
- LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK,
-};
-static const unsigned int lcd_data16_pins[] = {
- /* D[0:15] */
- 121, 122, 123, 124, 125, 126, 127, 128,
- 129, 130, 131, 132, 133, 134, 135, 136,
-};
-static const unsigned int lcd_data16_mux[] = {
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
- LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK,
- LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK,
-};
-static const unsigned int lcd_data18_pins[] = {
- /* D[0:17] */
- 121, 122, 123, 124, 125, 126, 127, 128,
- 129, 130, 131, 132, 133, 134, 135, 136,
- 137, 138,
-};
-static const unsigned int lcd_data18_mux[] = {
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
- LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK,
- LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK,
- LCDD16_MARK, LCDD17_MARK,
-};
-static const unsigned int lcd_data24_pins[] = {
- /* D[0:23] */
- 121, 122, 123, 124, 125, 126, 127, 128,
- 129, 130, 131, 132, 133, 134, 135, 136,
- 137, 138, 139, 140, 141, 142, 143, 144,
-};
-static const unsigned int lcd_data24_mux[] = {
- LCDD0_MARK, LCDD1_MARK, LCDD2_MARK, LCDD3_MARK,
- LCDD4_MARK, LCDD5_MARK, LCDD6_MARK, LCDD7_MARK,
- LCDD8_MARK, LCDD9_MARK, LCDD10_MARK, LCDD11_MARK,
- LCDD12_MARK, LCDD13_MARK, LCDD14_MARK, LCDD15_MARK,
- LCDD16_MARK, LCDD17_MARK, LCDD18_MARK, LCDD19_MARK,
- LCDD20_MARK, LCDD21_MARK, LCDD22_MARK, LCDD23_MARK,
-};
-static const unsigned int lcd_display_pins[] = {
- /* DON */
- 151,
-};
-static const unsigned int lcd_display_mux[] = {
- LCDDON_MARK,
-};
-static const unsigned int lcd_lclk_pins[] = {
- /* LCLK */
- 150,
-};
-static const unsigned int lcd_lclk_mux[] = {
- LCDLCLK_MARK,
-};
-static const unsigned int lcd_sync_pins[] = {
- /* VSYN, HSYN, DCK, DISP */
- 146, 145, 147, 149,
-};
-static const unsigned int lcd_sync_mux[] = {
- LCDVSYN_MARK, LCDHSYN_MARK, LCDDCK_MARK, LCDDISP_MARK,
-};
-static const unsigned int lcd_sys_pins[] = {
- /* CS, WR, RD, RS */
- 145, 147, 148, 149,
-};
-static const unsigned int lcd_sys_mux[] = {
- LCDCS_MARK, LCDWR_MARK, LCDRD_MARK, LCDRS_MARK,
-};
-/* - MMCIF ------------------------------------------------------------------ */
-static const unsigned int mmc0_data1_0_pins[] = {
- /* D[0] */
- 84,
-};
-static const unsigned int mmc0_data1_0_mux[] = {
- MMCD0_0_MARK,
-};
-static const unsigned int mmc0_data4_0_pins[] = {
- /* D[0:3] */
- 84, 85, 86, 87,
-};
-static const unsigned int mmc0_data4_0_mux[] = {
- MMCD0_0_MARK, MMCD0_1_MARK, MMCD0_2_MARK, MMCD0_3_MARK,
-};
-static const unsigned int mmc0_data8_0_pins[] = {
- /* D[0:7] */
- 84, 85, 86, 87, 88, 89, 90, 91,
-};
-static const unsigned int mmc0_data8_0_mux[] = {
- MMCD0_0_MARK, MMCD0_1_MARK, MMCD0_2_MARK, MMCD0_3_MARK,
- MMCD0_4_MARK, MMCD0_5_MARK, MMCD0_6_MARK, MMCD0_7_MARK,
-};
-static const unsigned int mmc0_ctrl_0_pins[] = {
- /* CMD, CLK */
- 92, 99,
-};
-static const unsigned int mmc0_ctrl_0_mux[] = {
- MMCCMD0_MARK, MMCCLK0_MARK,
-};
-
-static const unsigned int mmc0_data1_1_pins[] = {
- /* D[0] */
- 54,
-};
-static const unsigned int mmc0_data1_1_mux[] = {
- MMCD1_0_MARK,
-};
-static const unsigned int mmc0_data4_1_pins[] = {
- /* D[0:3] */
- 54, 55, 56, 57,
-};
-static const unsigned int mmc0_data4_1_mux[] = {
- MMCD1_0_MARK, MMCD1_1_MARK, MMCD1_2_MARK, MMCD1_3_MARK,
-};
-static const unsigned int mmc0_data8_1_pins[] = {
- /* D[0:7] */
- 54, 55, 56, 57, 58, 59, 60, 61,
-};
-static const unsigned int mmc0_data8_1_mux[] = {
- MMCD1_0_MARK, MMCD1_1_MARK, MMCD1_2_MARK, MMCD1_3_MARK,
- MMCD1_4_MARK, MMCD1_5_MARK, MMCD1_6_MARK, MMCD1_7_MARK,
-};
-static const unsigned int mmc0_ctrl_1_pins[] = {
- /* CMD, CLK */
- 67, 66,
-};
-static const unsigned int mmc0_ctrl_1_mux[] = {
- MMCCMD1_MARK, MMCCLK1_MARK,
-};
-/* - SCIFA0 ----------------------------------------------------------------- */
-static const unsigned int scifa0_data_pins[] = {
- /* RXD, TXD */
- 153, 152,
-};
-static const unsigned int scifa0_data_mux[] = {
- SCIFA0_RXD_MARK, SCIFA0_TXD_MARK,
-};
-static const unsigned int scifa0_clk_pins[] = {
- /* SCK */
- 156,
-};
-static const unsigned int scifa0_clk_mux[] = {
- SCIFA0_SCK_MARK,
-};
-static const unsigned int scifa0_ctrl_pins[] = {
- /* RTS, CTS */
- 157, 158,
-};
-static const unsigned int scifa0_ctrl_mux[] = {
- SCIFA0_RTS_MARK, SCIFA0_CTS_MARK,
-};
-/* - SCIFA1 ----------------------------------------------------------------- */
-static const unsigned int scifa1_data_pins[] = {
- /* RXD, TXD */
- 155, 154,
-};
-static const unsigned int scifa1_data_mux[] = {
- SCIFA1_RXD_MARK, SCIFA1_TXD_MARK,
-};
-static const unsigned int scifa1_clk_pins[] = {
- /* SCK */
- 159,
-};
-static const unsigned int scifa1_clk_mux[] = {
- SCIFA1_SCK_MARK,
-};
-static const unsigned int scifa1_ctrl_pins[] = {
- /* RTS, CTS */
- 160, 161,
-};
-static const unsigned int scifa1_ctrl_mux[] = {
- SCIFA1_RTS_MARK, SCIFA1_CTS_MARK,
-};
-/* - SCIFA2 ----------------------------------------------------------------- */
-static const unsigned int scifa2_data_pins[] = {
- /* RXD, TXD */
- 97, 96,
-};
-static const unsigned int scifa2_data_mux[] = {
- SCIFA2_RXD1_MARK, SCIFA2_TXD1_MARK,
-};
-static const unsigned int scifa2_clk_pins[] = {
- /* SCK */
- 98,
-};
-static const unsigned int scifa2_clk_mux[] = {
- SCIFA2_SCK1_MARK,
-};
-static const unsigned int scifa2_ctrl_pins[] = {
- /* RTS, CTS */
- 95, 94,
-};
-static const unsigned int scifa2_ctrl_mux[] = {
- SCIFA2_RTS1_MARK, SCIFA2_CTS1_MARK,
-};
-/* - SCIFA3 ----------------------------------------------------------------- */
-static const unsigned int scifa3_data_pins[] = {
- /* RXD, TXD */
- 144, 143,
-};
-static const unsigned int scifa3_data_mux[] = {
- SCIFA3_RXD_MARK, SCIFA3_TXD_MARK,
-};
-static const unsigned int scifa3_clk_pins[] = {
- /* SCK */
- 142,
-};
-static const unsigned int scifa3_clk_mux[] = {
- SCIFA3_SCK_MARK,
-};
-static const unsigned int scifa3_ctrl_0_pins[] = {
- /* RTS, CTS */
- 44, 43,
-};
-static const unsigned int scifa3_ctrl_0_mux[] = {
- SCIFA3_RTS_44_MARK, SCIFA3_CTS_43_MARK,
-};
-static const unsigned int scifa3_ctrl_1_pins[] = {
- /* RTS, CTS */
- 141, 140,
-};
-static const unsigned int scifa3_ctrl_1_mux[] = {
- SCIFA3_RTS_141_MARK, SCIFA3_CTS_140_MARK,
-};
-/* - SCIFA4 ----------------------------------------------------------------- */
-static const unsigned int scifa4_data_pins[] = {
- /* RXD, TXD */
- 5, 6,
-};
-static const unsigned int scifa4_data_mux[] = {
- SCIFA4_RXD_MARK, SCIFA4_TXD_MARK,
-};
-/* - SCIFA5 ----------------------------------------------------------------- */
-static const unsigned int scifa5_data_pins[] = {
- /* RXD, TXD */
- 8, 12,
-};
-static const unsigned int scifa5_data_mux[] = {
- SCIFA5_RXD_MARK, SCIFA5_TXD_MARK,
-};
-/* - SCIFB ------------------------------------------------------------------ */
-static const unsigned int scifb_data_pins[] = {
- /* RXD, TXD */
- 166, 165,
-};
-static const unsigned int scifb_data_mux[] = {
- SCIFB_RXD_MARK, SCIFB_TXD_MARK,
-};
-static const unsigned int scifb_clk_pins[] = {
- /* SCK */
- 162,
-};
-static const unsigned int scifb_clk_mux[] = {
- SCIFB_SCK_MARK,
-};
-static const unsigned int scifb_ctrl_pins[] = {
- /* RTS, CTS */
- 163, 164,
-};
-static const unsigned int scifb_ctrl_mux[] = {
- SCIFB_RTS_MARK, SCIFB_CTS_MARK,
-};
-/* - SDHI0 ------------------------------------------------------------------ */
-static const unsigned int sdhi0_data1_pins[] = {
- /* D0 */
- 173,
-};
-static const unsigned int sdhi0_data1_mux[] = {
- SDHID0_0_MARK,
-};
-static const unsigned int sdhi0_data4_pins[] = {
- /* D[0:3] */
- 173, 174, 175, 176,
-};
-static const unsigned int sdhi0_data4_mux[] = {
- SDHID0_0_MARK, SDHID0_1_MARK, SDHID0_2_MARK, SDHID0_3_MARK,
-};
-static const unsigned int sdhi0_ctrl_pins[] = {
- /* CMD, CLK */
- 177, 171,
-};
-static const unsigned int sdhi0_ctrl_mux[] = {
- SDHICMD0_MARK, SDHICLK0_MARK,
-};
-static const unsigned int sdhi0_cd_pins[] = {
- /* CD */
- 172,
-};
-static const unsigned int sdhi0_cd_mux[] = {
- SDHICD0_MARK,
-};
-static const unsigned int sdhi0_wp_pins[] = {
- /* WP */
- 178,
-};
-static const unsigned int sdhi0_wp_mux[] = {
- SDHIWP0_MARK,
-};
-/* - SDHI1 ------------------------------------------------------------------ */
-static const unsigned int sdhi1_data1_pins[] = {
- /* D0 */
- 180,
-};
-static const unsigned int sdhi1_data1_mux[] = {
- SDHID1_0_MARK,
-};
-static const unsigned int sdhi1_data4_pins[] = {
- /* D[0:3] */
- 180, 181, 182, 183,
-};
-static const unsigned int sdhi1_data4_mux[] = {
- SDHID1_0_MARK, SDHID1_1_MARK, SDHID1_2_MARK, SDHID1_3_MARK,
-};
-static const unsigned int sdhi1_ctrl_pins[] = {
- /* CMD, CLK */
- 184, 179,
-};
-static const unsigned int sdhi1_ctrl_mux[] = {
- SDHICMD1_MARK, SDHICLK1_MARK,
-};
-
-static const unsigned int sdhi2_data1_pins[] = {
- /* D0 */
- 186,
-};
-static const unsigned int sdhi2_data1_mux[] = {
- SDHID2_0_MARK,
-};
-static const unsigned int sdhi2_data4_pins[] = {
- /* D[0:3] */
- 186, 187, 188, 189,
-};
-static const unsigned int sdhi2_data4_mux[] = {
- SDHID2_0_MARK, SDHID2_1_MARK, SDHID2_2_MARK, SDHID2_3_MARK,
-};
-static const unsigned int sdhi2_ctrl_pins[] = {
- /* CMD, CLK */
- 190, 185,
-};
-static const unsigned int sdhi2_ctrl_mux[] = {
- SDHICMD2_MARK, SDHICLK2_MARK,
-};
-/* - USB0 ------------------------------------------------------------------- */
-static const unsigned int usb0_vbus_pins[] = {
- /* VBUS */
- 167,
-};
-static const unsigned int usb0_vbus_mux[] = {
- VBUS0_0_MARK,
-};
-static const unsigned int usb0_otg_id_pins[] = {
- /* IDIN */
- 113,
-};
-static const unsigned int usb0_otg_id_mux[] = {
- IDIN_0_MARK,
-};
-static const unsigned int usb0_otg_ctrl_pins[] = {
- /* PWEN, EXTLP, OVCN, OVCN2 */
- 116, 114, 117, 115,
-};
-static const unsigned int usb0_otg_ctrl_mux[] = {
- PWEN_0_MARK, EXTLP_0_MARK, OVCN_0_MARK, OVCN2_0_MARK,
-};
-/* - USB1 ------------------------------------------------------------------- */
-static const unsigned int usb1_vbus_pins[] = {
- /* VBUS */
- 168,
-};
-static const unsigned int usb1_vbus_mux[] = {
- VBUS0_1_MARK,
-};
-static const unsigned int usb1_otg_id_0_pins[] = {
- /* IDIN */
- 113,
-};
-static const unsigned int usb1_otg_id_0_mux[] = {
- IDIN_1_113_MARK,
-};
-static const unsigned int usb1_otg_id_1_pins[] = {
- /* IDIN */
- 18,
-};
-static const unsigned int usb1_otg_id_1_mux[] = {
- IDIN_1_18_MARK,
-};
-static const unsigned int usb1_otg_ctrl_0_pins[] = {
- /* PWEN, EXTLP, OVCN, OVCN2 */
- 115, 116, 114, 117, 113,
-};
-static const unsigned int usb1_otg_ctrl_0_mux[] = {
- PWEN_1_115_MARK, EXTLP_1_MARK, OVCN_1_114_MARK, OVCN2_1_MARK,
-};
-static const unsigned int usb1_otg_ctrl_1_pins[] = {
- /* PWEN, EXTLP, OVCN, OVCN2 */
- 138, 116, 162, 117, 18,
-};
-static const unsigned int usb1_otg_ctrl_1_mux[] = {
- PWEN_1_138_MARK, EXTLP_1_MARK, OVCN_1_162_MARK, OVCN2_1_MARK,
-};
-
-static const struct sh_pfc_pin_group pinmux_groups[] = {
- SH_PFC_PIN_GROUP(bsc_data8),
- SH_PFC_PIN_GROUP(bsc_data16),
- SH_PFC_PIN_GROUP(bsc_cs0),
- SH_PFC_PIN_GROUP(bsc_cs2),
- SH_PFC_PIN_GROUP(bsc_cs4),
- SH_PFC_PIN_GROUP(bsc_cs5a),
- SH_PFC_PIN_GROUP(bsc_cs5b),
- SH_PFC_PIN_GROUP(bsc_cs6a),
- SH_PFC_PIN_GROUP(bsc_rd_we8),
- SH_PFC_PIN_GROUP(bsc_rd_we16),
- SH_PFC_PIN_GROUP(bsc_bs),
- SH_PFC_PIN_GROUP(bsc_rdwr),
- SH_PFC_PIN_GROUP(ceu_data_0_7),
- SH_PFC_PIN_GROUP(ceu_data_8_15),
- SH_PFC_PIN_GROUP(ceu_clk_0),
- SH_PFC_PIN_GROUP(ceu_clk_1),
- SH_PFC_PIN_GROUP(ceu_clk_2),
- SH_PFC_PIN_GROUP(ceu_sync),
- SH_PFC_PIN_GROUP(ceu_field),
- SH_PFC_PIN_GROUP(flctl_data),
- SH_PFC_PIN_GROUP(flctl_ce0),
- SH_PFC_PIN_GROUP(flctl_ce1),
- SH_PFC_PIN_GROUP(flctl_ctrl),
- SH_PFC_PIN_GROUP(fsia_mclk_in),
- SH_PFC_PIN_GROUP(fsia_mclk_out),
- SH_PFC_PIN_GROUP(fsia_sclk_in),
- SH_PFC_PIN_GROUP(fsia_sclk_out),
- SH_PFC_PIN_GROUP(fsia_data_in),
- SH_PFC_PIN_GROUP(fsia_data_out),
- SH_PFC_PIN_GROUP(fsia_spdif_0),
- SH_PFC_PIN_GROUP(fsia_spdif_1),
- SH_PFC_PIN_GROUP(fsib_mclk_in),
- SH_PFC_PIN_GROUP(hdmi),
- SH_PFC_PIN_GROUP(intc_irq0_0),
- SH_PFC_PIN_GROUP(intc_irq0_1),
- SH_PFC_PIN_GROUP(intc_irq1),
- SH_PFC_PIN_GROUP(intc_irq2_0),
- SH_PFC_PIN_GROUP(intc_irq2_1),
- SH_PFC_PIN_GROUP(intc_irq3_0),
- SH_PFC_PIN_GROUP(intc_irq3_1),
- SH_PFC_PIN_GROUP(intc_irq4_0),
- SH_PFC_PIN_GROUP(intc_irq4_1),
- SH_PFC_PIN_GROUP(intc_irq5),
- SH_PFC_PIN_GROUP(intc_irq6_0),
- SH_PFC_PIN_GROUP(intc_irq6_1),
- SH_PFC_PIN_GROUP(intc_irq7_0),
- SH_PFC_PIN_GROUP(intc_irq7_1),
- SH_PFC_PIN_GROUP(intc_irq8_0),
- SH_PFC_PIN_GROUP(intc_irq8_1),
- SH_PFC_PIN_GROUP(intc_irq9_0),
- SH_PFC_PIN_GROUP(intc_irq9_1),
- SH_PFC_PIN_GROUP(intc_irq10),
- SH_PFC_PIN_GROUP(intc_irq11),
- SH_PFC_PIN_GROUP(intc_irq12_0),
- SH_PFC_PIN_GROUP(intc_irq12_1),
- SH_PFC_PIN_GROUP(intc_irq13_0),
- SH_PFC_PIN_GROUP(intc_irq13_1),
- SH_PFC_PIN_GROUP(intc_irq14_0),
- SH_PFC_PIN_GROUP(intc_irq14_1),
- SH_PFC_PIN_GROUP(intc_irq15_0),
- SH_PFC_PIN_GROUP(intc_irq15_1),
- SH_PFC_PIN_GROUP(intc_irq16_0),
- SH_PFC_PIN_GROUP(intc_irq16_1),
- SH_PFC_PIN_GROUP(intc_irq17),
- SH_PFC_PIN_GROUP(intc_irq18),
- SH_PFC_PIN_GROUP(intc_irq19),
- SH_PFC_PIN_GROUP(intc_irq20),
- SH_PFC_PIN_GROUP(intc_irq21),
- SH_PFC_PIN_GROUP(intc_irq22),
- SH_PFC_PIN_GROUP(intc_irq23),
- SH_PFC_PIN_GROUP(intc_irq24),
- SH_PFC_PIN_GROUP(intc_irq25),
- SH_PFC_PIN_GROUP(intc_irq26_0),
- SH_PFC_PIN_GROUP(intc_irq26_1),
- SH_PFC_PIN_GROUP(intc_irq27_0),
- SH_PFC_PIN_GROUP(intc_irq27_1),
- SH_PFC_PIN_GROUP(intc_irq28_0),
- SH_PFC_PIN_GROUP(intc_irq28_1),
- SH_PFC_PIN_GROUP(intc_irq29_0),
- SH_PFC_PIN_GROUP(intc_irq29_1),
- SH_PFC_PIN_GROUP(intc_irq30_0),
- SH_PFC_PIN_GROUP(intc_irq30_1),
- SH_PFC_PIN_GROUP(intc_irq31_0),
- SH_PFC_PIN_GROUP(intc_irq31_1),
- SH_PFC_PIN_GROUP(keysc_in04_0),
- SH_PFC_PIN_GROUP(keysc_in04_1),
- SH_PFC_PIN_GROUP(keysc_in5),
- SH_PFC_PIN_GROUP(keysc_in6),
- SH_PFC_PIN_GROUP(keysc_in7),
- SH_PFC_PIN_GROUP(keysc_out4),
- SH_PFC_PIN_GROUP(keysc_out5),
- SH_PFC_PIN_GROUP(keysc_out6),
- SH_PFC_PIN_GROUP(keysc_out8),
- SH_PFC_PIN_GROUP(lcd_data8),
- SH_PFC_PIN_GROUP(lcd_data9),
- SH_PFC_PIN_GROUP(lcd_data12),
- SH_PFC_PIN_GROUP(lcd_data16),
- SH_PFC_PIN_GROUP(lcd_data18),
- SH_PFC_PIN_GROUP(lcd_data24),
- SH_PFC_PIN_GROUP(lcd_display),
- SH_PFC_PIN_GROUP(lcd_lclk),
- SH_PFC_PIN_GROUP(lcd_sync),
- SH_PFC_PIN_GROUP(lcd_sys),
- SH_PFC_PIN_GROUP(mmc0_data1_0),
- SH_PFC_PIN_GROUP(mmc0_data4_0),
- SH_PFC_PIN_GROUP(mmc0_data8_0),
- SH_PFC_PIN_GROUP(mmc0_ctrl_0),
- SH_PFC_PIN_GROUP(mmc0_data1_1),
- SH_PFC_PIN_GROUP(mmc0_data4_1),
- SH_PFC_PIN_GROUP(mmc0_data8_1),
- SH_PFC_PIN_GROUP(mmc0_ctrl_1),
- SH_PFC_PIN_GROUP(scifa0_data),
- SH_PFC_PIN_GROUP(scifa0_clk),
- SH_PFC_PIN_GROUP(scifa0_ctrl),
- SH_PFC_PIN_GROUP(scifa1_data),
- SH_PFC_PIN_GROUP(scifa1_clk),
- SH_PFC_PIN_GROUP(scifa1_ctrl),
- SH_PFC_PIN_GROUP(scifa2_data),
- SH_PFC_PIN_GROUP(scifa2_clk),
- SH_PFC_PIN_GROUP(scifa2_ctrl),
- SH_PFC_PIN_GROUP(scifa3_data),
- SH_PFC_PIN_GROUP(scifa3_clk),
- SH_PFC_PIN_GROUP(scifa3_ctrl_0),
- SH_PFC_PIN_GROUP(scifa3_ctrl_1),
- SH_PFC_PIN_GROUP(scifa4_data),
- SH_PFC_PIN_GROUP(scifa5_data),
- SH_PFC_PIN_GROUP(scifb_data),
- SH_PFC_PIN_GROUP(scifb_clk),
- SH_PFC_PIN_GROUP(scifb_ctrl),
- SH_PFC_PIN_GROUP(sdhi0_data1),
- SH_PFC_PIN_GROUP(sdhi0_data4),
- SH_PFC_PIN_GROUP(sdhi0_ctrl),
- SH_PFC_PIN_GROUP(sdhi0_cd),
- SH_PFC_PIN_GROUP(sdhi0_wp),
- SH_PFC_PIN_GROUP(sdhi1_data1),
- SH_PFC_PIN_GROUP(sdhi1_data4),
- SH_PFC_PIN_GROUP(sdhi1_ctrl),
- SH_PFC_PIN_GROUP(sdhi2_data1),
- SH_PFC_PIN_GROUP(sdhi2_data4),
- SH_PFC_PIN_GROUP(sdhi2_ctrl),
- SH_PFC_PIN_GROUP(usb0_vbus),
- SH_PFC_PIN_GROUP(usb0_otg_id),
- SH_PFC_PIN_GROUP(usb0_otg_ctrl),
- SH_PFC_PIN_GROUP(usb1_vbus),
- SH_PFC_PIN_GROUP(usb1_otg_id_0),
- SH_PFC_PIN_GROUP(usb1_otg_id_1),
- SH_PFC_PIN_GROUP(usb1_otg_ctrl_0),
- SH_PFC_PIN_GROUP(usb1_otg_ctrl_1),
-};
-
-static const char * const bsc_groups[] = {
- "bsc_data8",
- "bsc_data16",
- "bsc_cs0",
- "bsc_cs2",
- "bsc_cs4",
- "bsc_cs5a",
- "bsc_cs5b",
- "bsc_cs6a",
- "bsc_rd_we8",
- "bsc_rd_we16",
- "bsc_bs",
- "bsc_rdwr",
-};
-
-static const char * const ceu_groups[] = {
- "ceu_data_0_7",
- "ceu_data_8_15",
- "ceu_clk_0",
- "ceu_clk_1",
- "ceu_clk_2",
- "ceu_sync",
- "ceu_field",
-};
-
-static const char * const flctl_groups[] = {
- "flctl_data",
- "flctl_ce0",
- "flctl_ce1",
- "flctl_ctrl",
-};
-
-static const char * const fsia_groups[] = {
- "fsia_mclk_in",
- "fsia_mclk_out",
- "fsia_sclk_in",
- "fsia_sclk_out",
- "fsia_data_in",
- "fsia_data_out",
- "fsia_spdif_0",
- "fsia_spdif_1",
-};
-
-static const char * const fsib_groups[] = {
- "fsib_mclk_in",
-};
-
-static const char * const hdmi_groups[] = {
- "hdmi",
-};
-
-static const char * const intc_groups[] = {
- "intc_irq0_0",
- "intc_irq0_1",
- "intc_irq1",
- "intc_irq2_0",
- "intc_irq2_1",
- "intc_irq3_0",
- "intc_irq3_1",
- "intc_irq4_0",
- "intc_irq4_1",
- "intc_irq5",
- "intc_irq6_0",
- "intc_irq6_1",
- "intc_irq7_0",
- "intc_irq7_1",
- "intc_irq8_0",
- "intc_irq8_1",
- "intc_irq9_0",
- "intc_irq9_1",
- "intc_irq10",
- "intc_irq11",
- "intc_irq12_0",
- "intc_irq12_1",
- "intc_irq13_0",
- "intc_irq13_1",
- "intc_irq14_0",
- "intc_irq14_1",
- "intc_irq15_0",
- "intc_irq15_1",
- "intc_irq16_0",
- "intc_irq16_1",
- "intc_irq17",
- "intc_irq18",
- "intc_irq19",
- "intc_irq20",
- "intc_irq21",
- "intc_irq22",
- "intc_irq23",
- "intc_irq24",
- "intc_irq25",
- "intc_irq26_0",
- "intc_irq26_1",
- "intc_irq27_0",
- "intc_irq27_1",
- "intc_irq28_0",
- "intc_irq28_1",
- "intc_irq29_0",
- "intc_irq29_1",
- "intc_irq30_0",
- "intc_irq30_1",
- "intc_irq31_0",
- "intc_irq31_1",
-};
-
-static const char * const keysc_groups[] = {
- "keysc_in04_0",
- "keysc_in04_1",
- "keysc_in5",
- "keysc_in6",
- "keysc_in7",
- "keysc_out4",
- "keysc_out5",
- "keysc_out6",
- "keysc_out8",
-};
-
-static const char * const lcd_groups[] = {
- "lcd_data8",
- "lcd_data9",
- "lcd_data12",
- "lcd_data16",
- "lcd_data18",
- "lcd_data24",
- "lcd_display",
- "lcd_lclk",
- "lcd_sync",
- "lcd_sys",
-};
-
-static const char * const mmc0_groups[] = {
- "mmc0_data1_0",
- "mmc0_data4_0",
- "mmc0_data8_0",
- "mmc0_ctrl_0",
- "mmc0_data1_1",
- "mmc0_data4_1",
- "mmc0_data8_1",
- "mmc0_ctrl_1",
-};
-
-static const char * const scifa0_groups[] = {
- "scifa0_data",
- "scifa0_clk",
- "scifa0_ctrl",
-};
-
-static const char * const scifa1_groups[] = {
- "scifa1_data",
- "scifa1_clk",
- "scifa1_ctrl",
-};
-
-static const char * const scifa2_groups[] = {
- "scifa2_data",
- "scifa2_clk",
- "scifa2_ctrl",
-};
-
-static const char * const scifa3_groups[] = {
- "scifa3_data",
- "scifa3_clk",
- "scifa3_ctrl_0",
- "scifa3_ctrl_1",
-};
-
-static const char * const scifa4_groups[] = {
- "scifa4_data",
-};
-
-static const char * const scifa5_groups[] = {
- "scifa5_data",
-};
-
-static const char * const scifb_groups[] = {
- "scifb_data",
- "scifb_clk",
- "scifb_ctrl",
-};
-
-static const char * const sdhi0_groups[] = {
- "sdhi0_data1",
- "sdhi0_data4",
- "sdhi0_ctrl",
- "sdhi0_cd",
- "sdhi0_wp",
-};
-
-static const char * const sdhi1_groups[] = {
- "sdhi1_data1",
- "sdhi1_data4",
- "sdhi1_ctrl",
-};
-
-static const char * const sdhi2_groups[] = {
- "sdhi2_data1",
- "sdhi2_data4",
- "sdhi2_ctrl",
-};
-
-static const char * const usb0_groups[] = {
- "usb0_vbus",
- "usb0_otg_id",
- "usb0_otg_ctrl",
-};
-
-static const char * const usb1_groups[] = {
- "usb1_vbus",
- "usb1_otg_id_0",
- "usb1_otg_id_1",
- "usb1_otg_ctrl_0",
- "usb1_otg_ctrl_1",
-};
-
-static const struct sh_pfc_function pinmux_functions[] = {
- SH_PFC_FUNCTION(bsc),
- SH_PFC_FUNCTION(ceu),
- SH_PFC_FUNCTION(flctl),
- SH_PFC_FUNCTION(fsia),
- SH_PFC_FUNCTION(fsib),
- SH_PFC_FUNCTION(hdmi),
- SH_PFC_FUNCTION(intc),
- SH_PFC_FUNCTION(keysc),
- SH_PFC_FUNCTION(lcd),
- SH_PFC_FUNCTION(mmc0),
- SH_PFC_FUNCTION(scifa0),
- SH_PFC_FUNCTION(scifa1),
- SH_PFC_FUNCTION(scifa2),
- SH_PFC_FUNCTION(scifa3),
- SH_PFC_FUNCTION(scifa4),
- SH_PFC_FUNCTION(scifa5),
- SH_PFC_FUNCTION(scifb),
- SH_PFC_FUNCTION(sdhi0),
- SH_PFC_FUNCTION(sdhi1),
- SH_PFC_FUNCTION(sdhi2),
- SH_PFC_FUNCTION(usb0),
- SH_PFC_FUNCTION(usb1),
-};
-
-static const struct pinmux_cfg_reg pinmux_config_regs[] = {
- PORTCR(0, 0xE6051000), /* PORT0CR */
- PORTCR(1, 0xE6051001), /* PORT1CR */
- PORTCR(2, 0xE6051002), /* PORT2CR */
- PORTCR(3, 0xE6051003), /* PORT3CR */
- PORTCR(4, 0xE6051004), /* PORT4CR */
- PORTCR(5, 0xE6051005), /* PORT5CR */
- PORTCR(6, 0xE6051006), /* PORT6CR */
- PORTCR(7, 0xE6051007), /* PORT7CR */
- PORTCR(8, 0xE6051008), /* PORT8CR */
- PORTCR(9, 0xE6051009), /* PORT9CR */
- PORTCR(10, 0xE605100A), /* PORT10CR */
- PORTCR(11, 0xE605100B), /* PORT11CR */
- PORTCR(12, 0xE605100C), /* PORT12CR */
- PORTCR(13, 0xE605100D), /* PORT13CR */
- PORTCR(14, 0xE605100E), /* PORT14CR */
- PORTCR(15, 0xE605100F), /* PORT15CR */
- PORTCR(16, 0xE6051010), /* PORT16CR */
- PORTCR(17, 0xE6051011), /* PORT17CR */
- PORTCR(18, 0xE6051012), /* PORT18CR */
- PORTCR(19, 0xE6051013), /* PORT19CR */
- PORTCR(20, 0xE6051014), /* PORT20CR */
- PORTCR(21, 0xE6051015), /* PORT21CR */
- PORTCR(22, 0xE6051016), /* PORT22CR */
- PORTCR(23, 0xE6051017), /* PORT23CR */
- PORTCR(24, 0xE6051018), /* PORT24CR */
- PORTCR(25, 0xE6051019), /* PORT25CR */
- PORTCR(26, 0xE605101A), /* PORT26CR */
- PORTCR(27, 0xE605101B), /* PORT27CR */
- PORTCR(28, 0xE605101C), /* PORT28CR */
- PORTCR(29, 0xE605101D), /* PORT29CR */
- PORTCR(30, 0xE605101E), /* PORT30CR */
- PORTCR(31, 0xE605101F), /* PORT31CR */
- PORTCR(32, 0xE6051020), /* PORT32CR */
- PORTCR(33, 0xE6051021), /* PORT33CR */
- PORTCR(34, 0xE6051022), /* PORT34CR */
- PORTCR(35, 0xE6051023), /* PORT35CR */
- PORTCR(36, 0xE6051024), /* PORT36CR */
- PORTCR(37, 0xE6051025), /* PORT37CR */
- PORTCR(38, 0xE6051026), /* PORT38CR */
- PORTCR(39, 0xE6051027), /* PORT39CR */
- PORTCR(40, 0xE6051028), /* PORT40CR */
- PORTCR(41, 0xE6051029), /* PORT41CR */
- PORTCR(42, 0xE605102A), /* PORT42CR */
- PORTCR(43, 0xE605102B), /* PORT43CR */
- PORTCR(44, 0xE605102C), /* PORT44CR */
- PORTCR(45, 0xE605102D), /* PORT45CR */
- PORTCR(46, 0xE605202E), /* PORT46CR */
- PORTCR(47, 0xE605202F), /* PORT47CR */
- PORTCR(48, 0xE6052030), /* PORT48CR */
- PORTCR(49, 0xE6052031), /* PORT49CR */
- PORTCR(50, 0xE6052032), /* PORT50CR */
- PORTCR(51, 0xE6052033), /* PORT51CR */
- PORTCR(52, 0xE6052034), /* PORT52CR */
- PORTCR(53, 0xE6052035), /* PORT53CR */
- PORTCR(54, 0xE6052036), /* PORT54CR */
- PORTCR(55, 0xE6052037), /* PORT55CR */
- PORTCR(56, 0xE6052038), /* PORT56CR */
- PORTCR(57, 0xE6052039), /* PORT57CR */
- PORTCR(58, 0xE605203A), /* PORT58CR */
- PORTCR(59, 0xE605203B), /* PORT59CR */
- PORTCR(60, 0xE605203C), /* PORT60CR */
- PORTCR(61, 0xE605203D), /* PORT61CR */
- PORTCR(62, 0xE605203E), /* PORT62CR */
- PORTCR(63, 0xE605203F), /* PORT63CR */
- PORTCR(64, 0xE6052040), /* PORT64CR */
- PORTCR(65, 0xE6052041), /* PORT65CR */
- PORTCR(66, 0xE6052042), /* PORT66CR */
- PORTCR(67, 0xE6052043), /* PORT67CR */
- PORTCR(68, 0xE6052044), /* PORT68CR */
- PORTCR(69, 0xE6052045), /* PORT69CR */
- PORTCR(70, 0xE6052046), /* PORT70CR */
- PORTCR(71, 0xE6052047), /* PORT71CR */
- PORTCR(72, 0xE6052048), /* PORT72CR */
- PORTCR(73, 0xE6052049), /* PORT73CR */
- PORTCR(74, 0xE605204A), /* PORT74CR */
- PORTCR(75, 0xE605204B), /* PORT75CR */
- PORTCR(76, 0xE605004C), /* PORT76CR */
- PORTCR(77, 0xE605004D), /* PORT77CR */
- PORTCR(78, 0xE605004E), /* PORT78CR */
- PORTCR(79, 0xE605004F), /* PORT79CR */
- PORTCR(80, 0xE6050050), /* PORT80CR */
- PORTCR(81, 0xE6050051), /* PORT81CR */
- PORTCR(82, 0xE6050052), /* PORT82CR */
- PORTCR(83, 0xE6050053), /* PORT83CR */
- PORTCR(84, 0xE6050054), /* PORT84CR */
- PORTCR(85, 0xE6050055), /* PORT85CR */
- PORTCR(86, 0xE6050056), /* PORT86CR */
- PORTCR(87, 0xE6050057), /* PORT87CR */
- PORTCR(88, 0xE6050058), /* PORT88CR */
- PORTCR(89, 0xE6050059), /* PORT89CR */
- PORTCR(90, 0xE605005A), /* PORT90CR */
- PORTCR(91, 0xE605005B), /* PORT91CR */
- PORTCR(92, 0xE605005C), /* PORT92CR */
- PORTCR(93, 0xE605005D), /* PORT93CR */
- PORTCR(94, 0xE605005E), /* PORT94CR */
- PORTCR(95, 0xE605005F), /* PORT95CR */
- PORTCR(96, 0xE6050060), /* PORT96CR */
- PORTCR(97, 0xE6050061), /* PORT97CR */
- PORTCR(98, 0xE6050062), /* PORT98CR */
- PORTCR(99, 0xE6050063), /* PORT99CR */
- PORTCR(100, 0xE6053064), /* PORT100CR */
- PORTCR(101, 0xE6053065), /* PORT101CR */
- PORTCR(102, 0xE6053066), /* PORT102CR */
- PORTCR(103, 0xE6053067), /* PORT103CR */
- PORTCR(104, 0xE6053068), /* PORT104CR */
- PORTCR(105, 0xE6053069), /* PORT105CR */
- PORTCR(106, 0xE605306A), /* PORT106CR */
- PORTCR(107, 0xE605306B), /* PORT107CR */
- PORTCR(108, 0xE605306C), /* PORT108CR */
- PORTCR(109, 0xE605306D), /* PORT109CR */
- PORTCR(110, 0xE605306E), /* PORT110CR */
- PORTCR(111, 0xE605306F), /* PORT111CR */
- PORTCR(112, 0xE6053070), /* PORT112CR */
- PORTCR(113, 0xE6053071), /* PORT113CR */
- PORTCR(114, 0xE6053072), /* PORT114CR */
- PORTCR(115, 0xE6053073), /* PORT115CR */
- PORTCR(116, 0xE6053074), /* PORT116CR */
- PORTCR(117, 0xE6053075), /* PORT117CR */
- PORTCR(118, 0xE6053076), /* PORT118CR */
- PORTCR(119, 0xE6053077), /* PORT119CR */
- PORTCR(120, 0xE6053078), /* PORT120CR */
- PORTCR(121, 0xE6050079), /* PORT121CR */
- PORTCR(122, 0xE605007A), /* PORT122CR */
- PORTCR(123, 0xE605007B), /* PORT123CR */
- PORTCR(124, 0xE605007C), /* PORT124CR */
- PORTCR(125, 0xE605007D), /* PORT125CR */
- PORTCR(126, 0xE605007E), /* PORT126CR */
- PORTCR(127, 0xE605007F), /* PORT127CR */
- PORTCR(128, 0xE6050080), /* PORT128CR */
- PORTCR(129, 0xE6050081), /* PORT129CR */
- PORTCR(130, 0xE6050082), /* PORT130CR */
- PORTCR(131, 0xE6050083), /* PORT131CR */
- PORTCR(132, 0xE6050084), /* PORT132CR */
- PORTCR(133, 0xE6050085), /* PORT133CR */
- PORTCR(134, 0xE6050086), /* PORT134CR */
- PORTCR(135, 0xE6050087), /* PORT135CR */
- PORTCR(136, 0xE6050088), /* PORT136CR */
- PORTCR(137, 0xE6050089), /* PORT137CR */
- PORTCR(138, 0xE605008A), /* PORT138CR */
- PORTCR(139, 0xE605008B), /* PORT139CR */
- PORTCR(140, 0xE605008C), /* PORT140CR */
- PORTCR(141, 0xE605008D), /* PORT141CR */
- PORTCR(142, 0xE605008E), /* PORT142CR */
- PORTCR(143, 0xE605008F), /* PORT143CR */
- PORTCR(144, 0xE6050090), /* PORT144CR */
- PORTCR(145, 0xE6050091), /* PORT145CR */
- PORTCR(146, 0xE6050092), /* PORT146CR */
- PORTCR(147, 0xE6050093), /* PORT147CR */
- PORTCR(148, 0xE6050094), /* PORT148CR */
- PORTCR(149, 0xE6050095), /* PORT149CR */
- PORTCR(150, 0xE6050096), /* PORT150CR */
- PORTCR(151, 0xE6050097), /* PORT151CR */
- PORTCR(152, 0xE6053098), /* PORT152CR */
- PORTCR(153, 0xE6053099), /* PORT153CR */
- PORTCR(154, 0xE605309A), /* PORT154CR */
- PORTCR(155, 0xE605309B), /* PORT155CR */
- PORTCR(156, 0xE605009C), /* PORT156CR */
- PORTCR(157, 0xE605009D), /* PORT157CR */
- PORTCR(158, 0xE605009E), /* PORT158CR */
- PORTCR(159, 0xE605009F), /* PORT159CR */
- PORTCR(160, 0xE60500A0), /* PORT160CR */
- PORTCR(161, 0xE60500A1), /* PORT161CR */
- PORTCR(162, 0xE60500A2), /* PORT162CR */
- PORTCR(163, 0xE60500A3), /* PORT163CR */
- PORTCR(164, 0xE60500A4), /* PORT164CR */
- PORTCR(165, 0xE60500A5), /* PORT165CR */
- PORTCR(166, 0xE60500A6), /* PORT166CR */
- PORTCR(167, 0xE60520A7), /* PORT167CR */
- PORTCR(168, 0xE60520A8), /* PORT168CR */
- PORTCR(169, 0xE60520A9), /* PORT169CR */
- PORTCR(170, 0xE60520AA), /* PORT170CR */
- PORTCR(171, 0xE60520AB), /* PORT171CR */
- PORTCR(172, 0xE60520AC), /* PORT172CR */
- PORTCR(173, 0xE60520AD), /* PORT173CR */
- PORTCR(174, 0xE60520AE), /* PORT174CR */
- PORTCR(175, 0xE60520AF), /* PORT175CR */
- PORTCR(176, 0xE60520B0), /* PORT176CR */
- PORTCR(177, 0xE60520B1), /* PORT177CR */
- PORTCR(178, 0xE60520B2), /* PORT178CR */
- PORTCR(179, 0xE60520B3), /* PORT179CR */
- PORTCR(180, 0xE60520B4), /* PORT180CR */
- PORTCR(181, 0xE60520B5), /* PORT181CR */
- PORTCR(182, 0xE60520B6), /* PORT182CR */
- PORTCR(183, 0xE60520B7), /* PORT183CR */
- PORTCR(184, 0xE60520B8), /* PORT184CR */
- PORTCR(185, 0xE60520B9), /* PORT185CR */
- PORTCR(186, 0xE60520BA), /* PORT186CR */
- PORTCR(187, 0xE60520BB), /* PORT187CR */
- PORTCR(188, 0xE60520BC), /* PORT188CR */
- PORTCR(189, 0xE60520BD), /* PORT189CR */
- PORTCR(190, 0xE60520BE), /* PORT190CR */
-
- { PINMUX_CFG_REG("MSEL1CR", 0xE605800C, 32, 1) {
- MSEL1CR_31_0, MSEL1CR_31_1,
- MSEL1CR_30_0, MSEL1CR_30_1,
- MSEL1CR_29_0, MSEL1CR_29_1,
- MSEL1CR_28_0, MSEL1CR_28_1,
- MSEL1CR_27_0, MSEL1CR_27_1,
- MSEL1CR_26_0, MSEL1CR_26_1,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- MSEL1CR_16_0, MSEL1CR_16_1,
- MSEL1CR_15_0, MSEL1CR_15_1,
- MSEL1CR_14_0, MSEL1CR_14_1,
- MSEL1CR_13_0, MSEL1CR_13_1,
- MSEL1CR_12_0, MSEL1CR_12_1,
- 0, 0, 0, 0,
- MSEL1CR_9_0, MSEL1CR_9_1,
- MSEL1CR_8_0, MSEL1CR_8_1,
- MSEL1CR_7_0, MSEL1CR_7_1,
- MSEL1CR_6_0, MSEL1CR_6_1,
- 0, 0,
- MSEL1CR_4_0, MSEL1CR_4_1,
- MSEL1CR_3_0, MSEL1CR_3_1,
- MSEL1CR_2_0, MSEL1CR_2_1,
- 0, 0,
- MSEL1CR_0_0, MSEL1CR_0_1,
- }
- },
- { PINMUX_CFG_REG("MSEL3CR", 0xE6058020, 32, 1) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- MSEL3CR_27_0, MSEL3CR_27_1,
- MSEL3CR_26_0, MSEL3CR_26_1,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- MSEL3CR_21_0, MSEL3CR_21_1,
- MSEL3CR_20_0, MSEL3CR_20_1,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- MSEL3CR_15_0, MSEL3CR_15_1,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0,
- MSEL3CR_9_0, MSEL3CR_9_1,
- 0, 0, 0, 0,
- MSEL3CR_6_0, MSEL3CR_6_1,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- }
- },
- { PINMUX_CFG_REG("MSEL4CR", 0xE6058024, 32, 1) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- MSEL4CR_19_0, MSEL4CR_19_1,
- MSEL4CR_18_0, MSEL4CR_18_1,
- MSEL4CR_17_0, MSEL4CR_17_1,
- MSEL4CR_16_0, MSEL4CR_16_1,
- MSEL4CR_15_0, MSEL4CR_15_1,
- MSEL4CR_14_0, MSEL4CR_14_1,
- 0, 0, 0, 0,
- 0, 0,
- MSEL4CR_10_0, MSEL4CR_10_1,
- 0, 0, 0, 0,
- 0, 0,
- MSEL4CR_6_0, MSEL4CR_6_1,
- 0, 0,
- MSEL4CR_4_0, MSEL4CR_4_1,
- 0, 0, 0, 0,
- MSEL4CR_1_0, MSEL4CR_1_1,
- 0, 0,
- }
- },
- { },
-};
-
-static const struct pinmux_data_reg pinmux_data_regs[] = {
- { PINMUX_DATA_REG("PORTL095_064DR", 0xE6054008, 32) {
- PORT95_DATA, PORT94_DATA, PORT93_DATA, PORT92_DATA,
- PORT91_DATA, PORT90_DATA, PORT89_DATA, PORT88_DATA,
- PORT87_DATA, PORT86_DATA, PORT85_DATA, PORT84_DATA,
- PORT83_DATA, PORT82_DATA, PORT81_DATA, PORT80_DATA,
- PORT79_DATA, PORT78_DATA, PORT77_DATA, PORT76_DATA,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- }
- },
- { PINMUX_DATA_REG("PORTL127_096DR", 0xE605400C, 32) {
- PORT127_DATA, PORT126_DATA, PORT125_DATA, PORT124_DATA,
- PORT123_DATA, PORT122_DATA, PORT121_DATA, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PORT99_DATA, PORT98_DATA, PORT97_DATA, PORT96_DATA,
- }
- },
- { PINMUX_DATA_REG("PORTL159_128DR", 0xE6054010, 32) {
- PORT159_DATA, PORT158_DATA, PORT157_DATA, PORT156_DATA,
- 0, 0, 0, 0,
- PORT151_DATA, PORT150_DATA, PORT149_DATA, PORT148_DATA,
- PORT147_DATA, PORT146_DATA, PORT145_DATA, PORT144_DATA,
- PORT143_DATA, PORT142_DATA, PORT141_DATA, PORT140_DATA,
- PORT139_DATA, PORT138_DATA, PORT137_DATA, PORT136_DATA,
- PORT135_DATA, PORT134_DATA, PORT133_DATA, PORT132_DATA,
- PORT131_DATA, PORT130_DATA, PORT129_DATA, PORT128_DATA,
- }
- },
- { PINMUX_DATA_REG("PORTL191_160DR", 0xE6054014, 32) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, PORT166_DATA, PORT165_DATA, PORT164_DATA,
- PORT163_DATA, PORT162_DATA, PORT161_DATA, PORT160_DATA,
- }
- },
- { PINMUX_DATA_REG("PORTD031_000DR", 0xE6055000, 32) {
- PORT31_DATA, PORT30_DATA, PORT29_DATA, PORT28_DATA,
- PORT27_DATA, PORT26_DATA, PORT25_DATA, PORT24_DATA,
- PORT23_DATA, PORT22_DATA, PORT21_DATA, PORT20_DATA,
- PORT19_DATA, PORT18_DATA, PORT17_DATA, PORT16_DATA,
- PORT15_DATA, PORT14_DATA, PORT13_DATA, PORT12_DATA,
- PORT11_DATA, PORT10_DATA, PORT9_DATA, PORT8_DATA,
- PORT7_DATA, PORT6_DATA, PORT5_DATA, PORT4_DATA,
- PORT3_DATA, PORT2_DATA, PORT1_DATA, PORT0_DATA,
- }
- },
- { PINMUX_DATA_REG("PORTD063_032DR", 0xE6055004, 32) {
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, PORT45_DATA, PORT44_DATA,
- PORT43_DATA, PORT42_DATA, PORT41_DATA, PORT40_DATA,
- PORT39_DATA, PORT38_DATA, PORT37_DATA, PORT36_DATA,
- PORT35_DATA, PORT34_DATA, PORT33_DATA, PORT32_DATA,
- }
- },
- { PINMUX_DATA_REG("PORTR063_032DR", 0xE6056004, 32) {
- PORT63_DATA, PORT62_DATA, PORT61_DATA, PORT60_DATA,
- PORT59_DATA, PORT58_DATA, PORT57_DATA, PORT56_DATA,
- PORT55_DATA, PORT54_DATA, PORT53_DATA, PORT52_DATA,
- PORT51_DATA, PORT50_DATA, PORT49_DATA, PORT48_DATA,
- PORT47_DATA, PORT46_DATA, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- }
- },
- { PINMUX_DATA_REG("PORTR095_064DR", 0xE6056008, 32) {
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- 0, 0, 0, 0,
- PORT75_DATA, PORT74_DATA, PORT73_DATA, PORT72_DATA,
- PORT71_DATA, PORT70_DATA, PORT69_DATA, PORT68_DATA,
- PORT67_DATA, PORT66_DATA, PORT65_DATA, PORT64_DATA,
- }
- },
- { PINMUX_DATA_REG("PORTR191_160DR", 0xE6056014, 32) {
- 0, PORT190_DATA, PORT189_DATA, PORT188_DATA,
- PORT187_DATA, PORT186_DATA, PORT185_DATA, PORT184_DATA,
- PORT183_DATA, PORT182_DATA, PORT181_DATA, PORT180_DATA,
- PORT179_DATA, PORT178_DATA, PORT177_DATA, PORT176_DATA,
- PORT175_DATA, PORT174_DATA, PORT173_DATA, PORT172_DATA,
- PORT171_DATA, PORT170_DATA, PORT169_DATA, PORT168_DATA,
- PORT167_DATA, 0, 0, 0,
- 0, 0, 0, 0,
- }
- },
- { PINMUX_DATA_REG("PORTU127_096DR", 0xE605700C, 32) {
- 0, 0, 0, 0,
- 0, 0, 0, PORT120_DATA,
- PORT119_DATA, PORT118_DATA, PORT117_DATA, PORT116_DATA,
- PORT115_DATA, PORT114_DATA, PORT113_DATA, PORT112_DATA,
- PORT111_DATA, PORT110_DATA, PORT109_DATA, PORT108_DATA,
- PORT107_DATA, PORT106_DATA, PORT105_DATA, PORT104_DATA,
- PORT103_DATA, PORT102_DATA, PORT101_DATA, PORT100_DATA,
- 0, 0, 0, 0,
- }
- },
- { PINMUX_DATA_REG("PORTU159_128DR", 0xE6057010, 32) {
- 0, 0, 0, 0,
- PORT155_DATA, PORT154_DATA, PORT153_DATA, PORT152_DATA,
- 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 EXT_IRQ16L(n) evt2irq(0x200 + ((n) << 5))
-#define EXT_IRQ16H(n) evt2irq(0x3200 + (((n) - 16) << 5))
-static const struct pinmux_irq pinmux_irqs[] = {
- PINMUX_IRQ(EXT_IRQ16L(0), 6, 162),
- PINMUX_IRQ(EXT_IRQ16L(1), 12),
- PINMUX_IRQ(EXT_IRQ16L(2), 4, 5),
- PINMUX_IRQ(EXT_IRQ16L(3), 8, 16),
- PINMUX_IRQ(EXT_IRQ16L(4), 17, 163),
- PINMUX_IRQ(EXT_IRQ16L(5), 18),
- PINMUX_IRQ(EXT_IRQ16L(6), 39, 164),
- PINMUX_IRQ(EXT_IRQ16L(7), 40, 167),
- PINMUX_IRQ(EXT_IRQ16L(8), 41, 168),
- PINMUX_IRQ(EXT_IRQ16L(9), 42, 169),
- PINMUX_IRQ(EXT_IRQ16L(10), 65),
- PINMUX_IRQ(EXT_IRQ16L(11), 67),
- PINMUX_IRQ(EXT_IRQ16L(12), 80, 137),
- PINMUX_IRQ(EXT_IRQ16L(13), 81, 145),
- PINMUX_IRQ(EXT_IRQ16L(14), 82, 146),
- PINMUX_IRQ(EXT_IRQ16L(15), 83, 147),
- PINMUX_IRQ(EXT_IRQ16H(16), 84, 170),
- PINMUX_IRQ(EXT_IRQ16H(17), 85),
- PINMUX_IRQ(EXT_IRQ16H(18), 86),
- PINMUX_IRQ(EXT_IRQ16H(19), 87),
- PINMUX_IRQ(EXT_IRQ16H(20), 92),
- PINMUX_IRQ(EXT_IRQ16H(21), 93),
- PINMUX_IRQ(EXT_IRQ16H(22), 94),
- PINMUX_IRQ(EXT_IRQ16H(23), 95),
- PINMUX_IRQ(EXT_IRQ16H(24), 112),
- PINMUX_IRQ(EXT_IRQ16H(25), 119),
- PINMUX_IRQ(EXT_IRQ16H(26), 121, 172),
- PINMUX_IRQ(EXT_IRQ16H(27), 122, 180),
- PINMUX_IRQ(EXT_IRQ16H(28), 123, 181),
- PINMUX_IRQ(EXT_IRQ16H(29), 129, 182),
- PINMUX_IRQ(EXT_IRQ16H(30), 130, 183),
- PINMUX_IRQ(EXT_IRQ16H(31), 138, 184),
-};
-
-#define PORTnCR_PULMD_OFF (0 << 6)
-#define PORTnCR_PULMD_DOWN (2 << 6)
-#define PORTnCR_PULMD_UP (3 << 6)
-#define PORTnCR_PULMD_MASK (3 << 6)
-
-struct sh7372_portcr_group {
- unsigned int end_pin;
- unsigned int offset;
-};
-
-static const struct sh7372_portcr_group sh7372_portcr_offsets[] = {
- { 45, 0x1000 }, { 75, 0x2000 }, { 99, 0x0000 }, { 120, 0x3000 },
- { 151, 0x0000 }, { 155, 0x3000 }, { 166, 0x0000 }, { 190, 0x2000 },
-};
-
-static void __iomem *sh7372_pinmux_portcr(struct sh_pfc *pfc, unsigned int pin)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(sh7372_portcr_offsets); ++i) {
- const struct sh7372_portcr_group *group =
- &sh7372_portcr_offsets[i];
-
- if (pin <= group->end_pin)
- return pfc->windows->virt + group->offset + pin;
- }
-
- return NULL;
-}
-
-static unsigned int sh7372_pinmux_get_bias(struct sh_pfc *pfc, unsigned int pin)
-{
- void __iomem *addr = sh7372_pinmux_portcr(pfc, pin);
- u32 value = ioread8(addr) & PORTnCR_PULMD_MASK;
-
- switch (value) {
- case PORTnCR_PULMD_UP:
- return PIN_CONFIG_BIAS_PULL_UP;
- case PORTnCR_PULMD_DOWN:
- return PIN_CONFIG_BIAS_PULL_DOWN;
- case PORTnCR_PULMD_OFF:
- default:
- return PIN_CONFIG_BIAS_DISABLE;
- }
-}
-
-static void sh7372_pinmux_set_bias(struct sh_pfc *pfc, unsigned int pin,
- unsigned int bias)
-{
- void __iomem *addr = sh7372_pinmux_portcr(pfc, pin);
- u32 value = ioread8(addr) & ~PORTnCR_PULMD_MASK;
-
- switch (bias) {
- case PIN_CONFIG_BIAS_PULL_UP:
- value |= PORTnCR_PULMD_UP;
- break;
- case PIN_CONFIG_BIAS_PULL_DOWN:
- value |= PORTnCR_PULMD_DOWN;
- break;
- }
-
- iowrite8(value, addr);
-}
-
-static const struct sh_pfc_soc_operations sh7372_pfc_ops = {
- .get_bias = sh7372_pinmux_get_bias,
- .set_bias = sh7372_pinmux_set_bias,
-};
-
-const struct sh_pfc_soc_info sh7372_pinmux_info = {
- .name = "sh7372_pfc",
- .ops = &sh7372_pfc_ops,
-
- .input = { PINMUX_INPUT_BEGIN, PINMUX_INPUT_END },
- .output = { PINMUX_OUTPUT_BEGIN, PINMUX_OUTPUT_END },
- .function = { PINMUX_FUNCTION_BEGIN, PINMUX_FUNCTION_END },
-
- .pins = pinmux_pins,
- .nr_pins = ARRAY_SIZE(pinmux_pins),
- .groups = pinmux_groups,
- .nr_groups = ARRAY_SIZE(pinmux_groups),
- .functions = pinmux_functions,
- .nr_functions = ARRAY_SIZE(pinmux_functions),
-
- .cfg_regs = pinmux_config_regs,
- .data_regs = pinmux_data_regs,
-
- .gpio_data = pinmux_data,
- .gpio_data_size = ARRAY_SIZE(pinmux_data),
-
- .gpio_irq = pinmux_irqs,
- .gpio_irq_size = ARRAY_SIZE(pinmux_irqs),
-};
diff --git a/drivers/pinctrl/sh-pfc/pinctrl.c b/drivers/pinctrl/sh-pfc/pinctrl.c
index 910deaefa0ac..072e7c62cab7 100644
--- a/drivers/pinctrl/sh-pfc/pinctrl.c
+++ b/drivers/pinctrl/sh-pfc/pinctrl.c
@@ -122,7 +122,7 @@ static int sh_pfc_dt_subnode_to_map(struct device *dev, struct device_node *np,
return ret;
}
- ret = pinconf_generic_parse_dt_config(np, &configs, &num_configs);
+ ret = pinconf_generic_parse_dt_config(np, NULL, &configs, &num_configs);
if (ret < 0)
return ret;
diff --git a/drivers/pinctrl/sh-pfc/sh_pfc.h b/drivers/pinctrl/sh-pfc/sh_pfc.h
index 5b7283182c1e..c83728626906 100644
--- a/drivers/pinctrl/sh-pfc/sh_pfc.h
+++ b/drivers/pinctrl/sh-pfc/sh_pfc.h
@@ -167,6 +167,8 @@ struct sh_pfc_soc_info {
PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr)
#define PINMUX_IPSR_NOGM(ispr, fn, ms) \
PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ms)
+#define PINMUX_IPSR_NOFN(ipsr, fn, ms) \
+ PINMUX_DATA(fn##_MARK, FN_##ipsr, FN_##ms)
#define PINMUX_IPSR_MSEL(ipsr, fn, ms) \
PINMUX_DATA(fn##_MARK, FN_##fn, FN_##ipsr, FN_##ms)
#define PINMUX_IPSR_MODSEL_DATA(ipsr, fn, ms) \
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.c b/drivers/pinctrl/sirf/pinctrl-sirf.c
index 4871647c7f85..2a1f07249b2f 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.c
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.c
@@ -38,7 +38,6 @@ struct sirfsoc_gpio_bank {
struct sirfsoc_gpio_chip {
struct of_mm_gpio_chip chip;
- bool is_marco; /* for marco, some registers are different with prima2 */
struct sirfsoc_gpio_bank sgpio_bank[SIRFSOC_GPIO_NO_OF_BANKS];
};
@@ -149,23 +148,14 @@ static void sirfsoc_pinmux_endisable(struct sirfsoc_pmx *spmx,
for (i = 0; i < mux->muxmask_counts; i++) {
u32 muxval;
- if (!spmx->is_marco) {
- muxval = readl(spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN(mask[i].group));
- if (enable)
- muxval = muxval & ~mask[i].mask;
- else
- muxval = muxval | mask[i].mask;
- writel(muxval, spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN(mask[i].group));
- } else {
- if (enable)
- writel(mask[i].mask, spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN_CLR(mask[i].group));
- else
- writel(mask[i].mask, spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN(mask[i].group));
- }
+ muxval = readl(spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(mask[i].group));
+ if (enable)
+ muxval = muxval & ~mask[i].mask;
+ else
+ muxval = muxval | mask[i].mask;
+ writel(muxval, spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(mask[i].group));
}
if (mux->funcmask && enable) {
@@ -223,16 +213,11 @@ static int sirfsoc_pinmux_request_gpio(struct pinctrl_dev *pmxdev,
spmx = pinctrl_dev_get_drvdata(pmxdev);
- if (!spmx->is_marco) {
- muxval = readl(spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN(group));
- muxval = muxval | (1 << (offset - range->pin_base));
- writel(muxval, spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN(group));
- } else {
- writel(1 << (offset - range->pin_base), spmx->gpio_virtbase +
- SIRFSOC_GPIO_PAD_EN(group));
- }
+ muxval = readl(spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(group));
+ muxval = muxval | (1 << (offset - range->pin_base));
+ writel(muxval, spmx->gpio_virtbase +
+ SIRFSOC_GPIO_PAD_EN(group));
return 0;
}
@@ -256,7 +241,6 @@ static void __iomem *sirfsoc_rsc_of_iomap(void)
{
const struct of_device_id rsc_ids[] = {
{ .compatible = "sirf,prima2-rsc" },
- { .compatible = "sirf,marco-rsc" },
{}
};
struct device_node *np;
@@ -284,7 +268,6 @@ static int sirfsoc_gpio_of_xlate(struct gpio_chip *gc,
static const struct of_device_id pinmux_ids[] = {
{ .compatible = "sirf,prima2-pinctrl", .data = &prima2_pinctrl_data, },
{ .compatible = "sirf,atlas6-pinctrl", .data = &atlas6_pinctrl_data, },
- { .compatible = "sirf,marco-pinctrl", .data = &prima2_pinctrl_data, },
{}
};
@@ -317,9 +300,6 @@ static int sirfsoc_pinmux_probe(struct platform_device *pdev)
goto out_no_rsc_remap;
}
- if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
- spmx->is_marco = 1;
-
pdata = of_match_node(pinmux_ids, np)->data;
sirfsoc_pin_groups = pdata->grps;
sirfsoc_pingrp_cnt = pdata->grps_cnt;
@@ -803,7 +783,6 @@ static int sirfsoc_gpio_probe(struct device_node *np)
struct sirfsoc_gpio_bank *bank;
void __iomem *regs;
struct platform_device *pdev;
- bool is_marco = false;
u32 pullups[SIRFSOC_GPIO_NO_OF_BANKS], pulldowns[SIRFSOC_GPIO_NO_OF_BANKS];
@@ -819,9 +798,6 @@ static int sirfsoc_gpio_probe(struct device_node *np)
if (!regs)
return -ENOMEM;
- if (of_device_is_compatible(np, "sirf,marco-pinctrl"))
- is_marco = 1;
-
sgpio->chip.gc.request = sirfsoc_gpio_request;
sgpio->chip.gc.free = sirfsoc_gpio_free;
sgpio->chip.gc.direction_input = sirfsoc_gpio_direction_input;
@@ -836,7 +812,6 @@ static int sirfsoc_gpio_probe(struct device_node *np)
sgpio->chip.gc.of_gpio_n_cells = 2;
sgpio->chip.gc.dev = &pdev->dev;
sgpio->chip.regs = regs;
- sgpio->is_marco = is_marco;
err = gpiochip_add(&sgpio->chip.gc);
if (err) {
diff --git a/drivers/pinctrl/sirf/pinctrl-sirf.h b/drivers/pinctrl/sirf/pinctrl-sirf.h
index d7f16b499ad9..9550335fe57a 100644
--- a/drivers/pinctrl/sirf/pinctrl-sirf.h
+++ b/drivers/pinctrl/sirf/pinctrl-sirf.h
@@ -49,7 +49,6 @@ struct sirfsoc_pmx {
u32 paden_regs[SIRFSOC_GPIO_NO_OF_BANKS];
u32 dspen_regs;
u32 rsc_regs[3];
- bool is_marco;
};
/* SIRFSOC_GPIO_PAD_EN set */
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index 230a952608cb..2eb893e0ea1e 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -21,6 +21,10 @@ config PINCTRL_SUN6I_A31
def_bool MACH_SUN6I
select PINCTRL_SUNXI_COMMON
+config PINCTRL_SUN6I_A31S
+ def_bool MACH_SUN6I
+ select PINCTRL_SUNXI_COMMON
+
config PINCTRL_SUN6I_A31_R
def_bool MACH_SUN6I
depends on RESET_CONTROLLER
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index c7d92e4673b5..b796d579dce6 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_PINCTRL_SUN4I_A10) += pinctrl-sun4i-a10.o
obj-$(CONFIG_PINCTRL_SUN5I_A10S) += pinctrl-sun5i-a10s.o
obj-$(CONFIG_PINCTRL_SUN5I_A13) += pinctrl-sun5i-a13.o
obj-$(CONFIG_PINCTRL_SUN6I_A31) += pinctrl-sun6i-a31.o
+obj-$(CONFIG_PINCTRL_SUN6I_A31S) += pinctrl-sun6i-a31s.o
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
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
index f42858eaca28..18038f0d6b52 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31.c
@@ -134,24 +134,28 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "gmac"), /* RXD4 */
SUNXI_FUNCTION(0x3, "lcd1"), /* D15 */
+ SUNXI_FUNCTION(0x4, "clk_out_a"),
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"), /* RXD5 */
SUNXI_FUNCTION(0x3, "lcd1"), /* D16 */
+ SUNXI_FUNCTION(0x4, "dmic"), /* CLK */
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"), /* RXD6 */
SUNXI_FUNCTION(0x3, "lcd1"), /* D17 */
+ SUNXI_FUNCTION(0x4, "dmic"), /* DIN */
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
SUNXI_FUNCTION(0x0, "gpio_in"),
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "gmac"), /* RXD7 */
SUNXI_FUNCTION(0x3, "lcd1"), /* D18 */
+ SUNXI_FUNCTION(0x4, "clk_out_b"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
SUNXI_FUNCTION(0x0, "gpio_in"),
@@ -207,6 +211,7 @@ static const struct sunxi_desc_pin sun6i_a31_pins[] = {
SUNXI_FUNCTION(0x1, "gpio_out"),
SUNXI_FUNCTION(0x2, "gmac"), /* MDC */
SUNXI_FUNCTION(0x3, "lcd1"), /* HSYNC */
+ SUNXI_FUNCTION(0x4, "clk_out_c"),
SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)), /* PA_EINT26 */
SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27),
SUNXI_FUNCTION(0x0, "gpio_in"),
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
new file mode 100644
index 000000000000..9b5a91f610c7
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun6i-a31s.c
@@ -0,0 +1,815 @@
+/*
+ * Allwinner A31s SoCs pinctrl driver.
+ *
+ * Copyright (C) 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on pinctrl-sun6i-a31.c, which is:
+ * Copyright (C) 2014 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 sun6i_a31s_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXD0 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* DTR */
+ 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"), /* TXD1 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* DSR */
+ 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"), /* TXD2 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* DCD */
+ 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"), /* TXD3 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RING */
+ 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"), /* TXD4 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* TX */
+ 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"), /* TXD5 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RX */
+ 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"), /* TXD6 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RTS */
+ 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"), /* TXD7 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* CTS */
+ 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"), /* TXCLK */
+ 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, "mmc3"), /* CMD */
+ SUNXI_FUNCTION(0x5, "mmc2"), /* CMD */
+ 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"), /* GTXCLK */
+ SUNXI_FUNCTION(0x4, "mmc3"), /* CLK */
+ SUNXI_FUNCTION(0x5, "mmc2"), /* CLK */
+ 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"), /* RXD0 */
+ SUNXI_FUNCTION(0x4, "mmc3"), /* D0 */
+ SUNXI_FUNCTION(0x5, "mmc2"), /* D0 */
+ 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"), /* RXD1 */
+ SUNXI_FUNCTION(0x4, "mmc3"), /* D1 */
+ SUNXI_FUNCTION(0x5, "mmc2"), /* D1 */
+ 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"), /* RXD2 */
+ SUNXI_FUNCTION(0x4, "mmc3"), /* D2 */
+ SUNXI_FUNCTION(0x5, "mmc2"), /* D2 */
+ 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"), /* RXD3 */
+ SUNXI_FUNCTION(0x4, "mmc3"), /* D3 */
+ SUNXI_FUNCTION(0x5, "mmc2"), /* D3 */
+ 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"), /* RXD4 */
+ SUNXI_FUNCTION(0x4, "clk_out_a"),
+ 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"), /* RXD5 */
+ SUNXI_FUNCTION(0x4, "dmic"), /* CLK */
+ 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"), /* RXD6 */
+ SUNXI_FUNCTION(0x4, "dmic"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXD7 */
+ SUNXI_FUNCTION(0x4, "clk_out_b"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 18)), /* PA_EINT18 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXDV */
+ SUNXI_FUNCTION(0x4, "pwm3"), /* Positive */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 19)), /* PA_EINT19 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXCLK */
+ SUNXI_FUNCTION(0x4, "pwm3"), /* Negative */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 20)), /* PA_EINT20 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXERR */
+ SUNXI_FUNCTION(0x4, "spi3"), /* CS0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 21)), /* PA_EINT21 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXERR */
+ SUNXI_FUNCTION(0x4, "spi3"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 22)), /* PA_EINT22 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 23),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* COL */
+ SUNXI_FUNCTION(0x4, "spi3"), /* MOSI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 23)), /* PA_EINT23 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* CRS */
+ SUNXI_FUNCTION(0x4, "spi3"), /* MISO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 24)), /* PA_EINT24 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 25),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* CLKIN */
+ SUNXI_FUNCTION(0x4, "spi3"), /* CS1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 25)), /* PA_EINT25 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 26),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* MDC */
+ SUNXI_FUNCTION(0x4, "clk_out_c"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 26)), /* PA_EINT26 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 27),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* MDIO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 27)), /* PA_EINT27 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "uart3"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 0)), /* PB_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* BCLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 1)), /* PB_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* LRCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 2)), /* PB_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DO0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 3)), /* PB_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DO1 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 4)), /* PB_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2s0"), /* DO2 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* TX */
+ SUNXI_FUNCTION(0x4, "i2c3"), /* SCK */
+ 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(0x2, "i2s0"), /* DO3 */
+ SUNXI_FUNCTION(0x3, "uart3"), /* RX */
+ SUNXI_FUNCTION(0x4, "i2c3"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* PB_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "i2s0"), /* DI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 7)), /* PB_EINT7 */
+ /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* 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_FUNCTION(0x4, "mmc3")), /* D7 */
+ /* Hole in pin numbering ! */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQS */
+ SUNXI_FUNCTION(0x3, "mmc2"), /* RST */
+ SUNXI_FUNCTION(0x4, "mmc3")), /* RST */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 25),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 26),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 27),
+ 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_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D13 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D16 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D17 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D18 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D19 */
+ 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, "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, "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, "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, "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 */
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D1 */
+ SUNXI_FUNCTION(0x4, "jtag")), /* MS1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D0 */
+ SUNXI_FUNCTION(0x4, "jtag")), /* DI1 */
+ 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_FUNCTION(0x4, "jtag")), /* DO1 */
+ 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 */
+ SUNXI_FUNCTION(0x4, "jtag")), /* CK1 */
+ /* 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, "spi1"), /* CS1 */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* MCLK */
+ 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, "spi1"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* BCLK */
+ 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, "spi1"), /* CLK */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* LRCK */
+ 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, "spi1"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* DIN */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 15)), /* PG_EINT15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi1"), /* MISO */
+ SUNXI_FUNCTION(0x3, "i2s1"), /* DOUT */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 16)), /* PG_EINT16 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 17)), /* PG_EINT17 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 18)), /* PG_EINT18 */
+ /* Hole, note H starts at pin 9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* CS0 */
+ SUNXI_FUNCTION(0x3, "jtag"), /* MS0 */
+ SUNXI_FUNCTION(0x4, "pwm1")), /* Positive */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* CLK */
+ SUNXI_FUNCTION(0x3, "jtag"), /* CK0 */
+ SUNXI_FUNCTION(0x4, "pwm1")), /* Negative */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* MOSI */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DO0 */
+ SUNXI_FUNCTION(0x4, "pwm2")), /* Positive */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi2"), /* MISO */
+ SUNXI_FUNCTION(0x3, "jtag"), /* DI0 */
+ SUNXI_FUNCTION(0x4, "pwm2")), /* Negative */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm0")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 23),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 25),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 26),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 27),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 28),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out")),
+};
+
+static const struct sunxi_pinctrl_desc sun6i_a31s_pinctrl_data = {
+ .pins = sun6i_a31s_pins,
+ .npins = ARRAY_SIZE(sun6i_a31s_pins),
+ .irq_banks = 4,
+};
+
+static int sun6i_a31s_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun6i_a31s_pinctrl_data);
+}
+
+static struct of_device_id sun6i_a31s_pinctrl_match[] = {
+ { .compatible = "allwinner,sun6i-a31s-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun6i_a31s_pinctrl_match);
+
+static struct platform_driver sun6i_a31s_pinctrl_driver = {
+ .probe = sun6i_a31s_pinctrl_probe,
+ .driver = {
+ .name = "sun6i-a31s-pinctrl",
+ .owner = THIS_MODULE,
+ .of_match_table = sun6i_a31s_pinctrl_match,
+ },
+};
+module_platform_driver(sun6i_a31s_pinctrl_driver);
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Allwinner A31s pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
index 638e797037da..97527614141b 100644
--- a/drivers/platform/x86/Kconfig
+++ b/drivers/platform/x86/Kconfig
@@ -735,6 +735,31 @@ config INTEL_IPS
functionality. If in doubt, say Y here; it will only load on
supported platforms.
+config INTEL_IMR
+ bool "Intel Isolated Memory Region support"
+ default n
+ depends on X86_INTEL_QUARK && IOSF_MBI
+ ---help---
+ This option provides a means to manipulate Isolated Memory Regions.
+ IMRs are a set of registers that define read and write access masks
+ to prohibit certain system agents from accessing memory with 1 KiB
+ granularity.
+
+ IMRs make it possible to control read/write access to an address
+ by hardware agents inside the SoC. Read and write masks can be
+ defined for:
+ - eSRAM flush
+ - Dirty CPU snoop (write only)
+ - RMU access
+ - PCI Virtual Channel 0/Virtual Channel 1
+ - SMM mode
+ - Non SMM mode
+
+ Quark contains a set of eight IMR registers and makes use of those
+ registers during its bootup process.
+
+ If you are running on a Galileo/Quark say Y here.
+
config IBM_RTL
tristate "Device driver to enable PRTL support"
depends on X86 && PCI
diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index f71700e0d132..46b274693872 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -856,8 +856,8 @@ static void asus_backlight_exit(struct asus_laptop *asus)
* than count bytes. We set eof to 1 if we handle those 2 values. We return the
* number of bytes written in page
*/
-static ssize_t show_infos(struct device *dev,
- struct device_attribute *attr, char *page)
+static ssize_t infos_show(struct device *dev, struct device_attribute *attr,
+ char *page)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
int len = 0;
@@ -926,6 +926,7 @@ static ssize_t show_infos(struct device *dev,
return len;
}
+static DEVICE_ATTR_RO(infos);
static int parse_arg(const char *buf, unsigned long count, int *val)
{
@@ -957,15 +958,15 @@ static ssize_t sysfs_acpi_set(struct asus_laptop *asus,
/*
* LEDD display
*/
-static ssize_t show_ledd(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ledd_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "0x%08x\n", asus->ledd_status);
}
-static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
+static ssize_t ledd_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
@@ -981,6 +982,7 @@ static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
}
return rv;
}
+static DEVICE_ATTR_RW(ledd);
/*
* Wireless
@@ -1014,21 +1016,22 @@ static int asus_wlan_set(struct asus_laptop *asus, int status)
return 0;
}
-static ssize_t show_wlan(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t wlan_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS));
}
-static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
+static ssize_t wlan_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
}
+static DEVICE_ATTR_RW(wlan);
/*e
* Bluetooth
@@ -1042,15 +1045,15 @@ static int asus_bluetooth_set(struct asus_laptop *asus, int status)
return 0;
}
-static ssize_t show_bluetooth(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t bluetooth_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS));
}
-static ssize_t store_bluetooth(struct device *dev,
+static ssize_t bluetooth_store(struct device *dev,
struct device_attribute *attr, const char *buf,
size_t count)
{
@@ -1058,6 +1061,7 @@ static ssize_t store_bluetooth(struct device *dev,
return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
}
+static DEVICE_ATTR_RW(bluetooth);
/*
* Wimax
@@ -1071,22 +1075,22 @@ static int asus_wimax_set(struct asus_laptop *asus, int status)
return 0;
}
-static ssize_t show_wimax(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t wimax_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
}
-static ssize_t store_wimax(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t wimax_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
}
+static DEVICE_ATTR_RW(wimax);
/*
* Wwan
@@ -1100,22 +1104,22 @@ static int asus_wwan_set(struct asus_laptop *asus, int status)
return 0;
}
-static ssize_t show_wwan(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t wwan_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
}
-static ssize_t store_wwan(struct device *dev,
- struct device_attribute *attr, const char *buf,
- size_t count)
+static ssize_t wwan_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
}
+static DEVICE_ATTR_RW(wwan);
/*
* Display
@@ -1135,8 +1139,8 @@ static void asus_set_display(struct asus_laptop *asus, int value)
* displays hooked up simultaneously, so be warned. See the acpi4asus README
* for more info.
*/
-static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t display_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
@@ -1146,6 +1150,7 @@ static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
asus_set_display(asus, value);
return rv;
}
+static DEVICE_ATTR_WO(display);
/*
* Light Sens
@@ -1167,16 +1172,17 @@ static void asus_als_switch(struct asus_laptop *asus, int value)
asus->light_switch = value;
}
-static ssize_t show_lssw(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ls_switch_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus->light_switch);
}
-static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t ls_switch_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
@@ -1187,6 +1193,7 @@ static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
return rv;
}
+static DEVICE_ATTR_RW(ls_switch);
static void asus_als_level(struct asus_laptop *asus, int value)
{
@@ -1195,16 +1202,16 @@ static void asus_als_level(struct asus_laptop *asus, int value)
asus->light_level = value;
}
-static ssize_t show_lslvl(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ls_level_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus->light_level);
}
-static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
int rv, value;
@@ -1218,6 +1225,7 @@ static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
return rv;
}
+static DEVICE_ATTR_RW(ls_level);
static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
{
@@ -1234,8 +1242,8 @@ static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
return err;
}
-static ssize_t show_lsvalue(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t ls_value_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
int err, hi, lo;
@@ -1247,6 +1255,7 @@ static ssize_t show_lsvalue(struct device *dev,
return sprintf(buf, "%d\n", 10 * hi + lo);
return err;
}
+static DEVICE_ATTR_RO(ls_value);
/*
* GPS
@@ -1274,15 +1283,15 @@ static int asus_gps_switch(struct asus_laptop *asus, int status)
return 0;
}
-static ssize_t show_gps(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t gps_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", asus_gps_status(asus));
}
-static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
+static ssize_t gps_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct asus_laptop *asus = dev_get_drvdata(dev);
@@ -1298,6 +1307,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
rfkill_set_sw_state(asus->gps.rfkill, !value);
return rv;
}
+static DEVICE_ATTR_RW(gps);
/*
* rfkill
@@ -1569,19 +1579,6 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
asus_input_notify(asus, event);
}
-static DEVICE_ATTR(infos, S_IRUGO, show_infos, NULL);
-static DEVICE_ATTR(wlan, S_IRUGO | S_IWUSR, show_wlan, store_wlan);
-static DEVICE_ATTR(bluetooth, S_IRUGO | S_IWUSR,
- show_bluetooth, store_bluetooth);
-static DEVICE_ATTR(wimax, S_IRUGO | S_IWUSR, show_wimax, store_wimax);
-static DEVICE_ATTR(wwan, S_IRUGO | S_IWUSR, show_wwan, store_wwan);
-static DEVICE_ATTR(display, S_IWUSR, NULL, store_disp);
-static DEVICE_ATTR(ledd, S_IRUGO | S_IWUSR, show_ledd, store_ledd);
-static DEVICE_ATTR(ls_value, S_IRUGO, show_lsvalue, NULL);
-static DEVICE_ATTR(ls_level, S_IRUGO | S_IWUSR, show_lslvl, store_lslvl);
-static DEVICE_ATTR(ls_switch, S_IRUGO | S_IWUSR, show_lssw, store_lssw);
-static DEVICE_ATTR(gps, S_IRUGO | S_IWUSR, show_gps, store_gps);
-
static struct attribute *asus_attributes[] = {
&dev_attr_infos.attr,
&dev_attr_wlan.attr,
@@ -1616,7 +1613,7 @@ static umode_t asus_sysfs_is_visible(struct kobject *kobj,
else
goto normal;
- return supported;
+ return supported ? attr->mode : 0;
}
normal:
diff --git a/drivers/platform/x86/classmate-laptop.c b/drivers/platform/x86/classmate-laptop.c
index 70d355a9ae2c..55cf10bc7817 100644
--- a/drivers/platform/x86/classmate-laptop.c
+++ b/drivers/platform/x86/classmate-laptop.c
@@ -520,7 +520,7 @@ static acpi_status cmpc_get_accel(acpi_handle handle,
{
union acpi_object param[2];
struct acpi_object_list input;
- struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, 0 };
+ struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
unsigned char *locs;
acpi_status status;
diff --git a/drivers/platform/x86/fujitsu-laptop.c b/drivers/platform/x86/fujitsu-laptop.c
index 7c21c1c44dfa..2a9afa261c61 100644
--- a/drivers/platform/x86/fujitsu-laptop.c
+++ b/drivers/platform/x86/fujitsu-laptop.c
@@ -64,6 +64,7 @@
#include <linux/acpi.h>
#include <linux/dmi.h>
#include <linux/backlight.h>
+#include <linux/fb.h>
#include <linux/input.h>
#include <linux/kfifo.h>
#include <linux/platform_device.h>
@@ -398,7 +399,7 @@ static int bl_get_brightness(struct backlight_device *b)
static int bl_update_status(struct backlight_device *b)
{
int ret;
- if (b->props.power == 4)
+ if (b->props.power == FB_BLANK_POWERDOWN)
ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
else
ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
@@ -1139,9 +1140,9 @@ static int __init fujitsu_init(void)
if (!acpi_video_backlight_support()) {
if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
- fujitsu->bl_device->props.power = 4;
+ fujitsu->bl_device->props.power = FB_BLANK_POWERDOWN;
else
- fujitsu->bl_device->props.power = 0;
+ fujitsu->bl_device->props.power = FB_BLANK_UNBLANK;
}
pr_info("driver " FUJITSU_DRIVER_VERSION " successfully loaded\n");
diff --git a/drivers/platform/x86/intel_scu_ipc.c b/drivers/platform/x86/intel_scu_ipc.c
index 66a4d3284aab..001b199a8c33 100644
--- a/drivers/platform/x86/intel_scu_ipc.c
+++ b/drivers/platform/x86/intel_scu_ipc.c
@@ -1,7 +1,7 @@
/*
* intel_scu_ipc.c: Driver for the Intel SCU IPC mechanism
*
- * (C) Copyright 2008-2010 Intel Corporation
+ * (C) Copyright 2008-2010,2015 Intel Corporation
* Author: Sreedhara DS (sreedhara.ds@intel.com)
*
* This program is free software; you can redistribute it and/or
@@ -43,10 +43,9 @@
/*
* IPC register summary
*
- * IPC register blocks are memory mapped at fixed address of 0xFF11C000
+ * IPC register blocks are memory mapped at fixed address of PCI BAR 0.
* To read or write information to the SCU, driver writes to IPC-1 memory
- * mapped registers (base address 0xFF11C000). The following is the IPC
- * mechanism
+ * mapped registers. The following is the IPC mechanism
*
* 1. IA core cDMI interface claims this transaction and converts it to a
* Transaction Layer Packet (TLP) message which is sent across the cDMI.
@@ -67,36 +66,28 @@
#define PCI_DEVICE_ID_CLOVERVIEW 0x08ea
#define PCI_DEVICE_ID_TANGIER 0x11a0
-/* intel scu ipc driver data*/
+/* intel scu ipc driver data */
struct intel_scu_ipc_pdata_t {
- u32 ipc_base;
u32 i2c_base;
- u32 ipc_len;
u32 i2c_len;
u8 irq_mode;
};
static struct intel_scu_ipc_pdata_t intel_scu_ipc_lincroft_pdata = {
- .ipc_base = 0xff11c000,
.i2c_base = 0xff12b000,
- .ipc_len = 0x100,
.i2c_len = 0x10,
.irq_mode = 0,
};
/* Penwell and Cloverview */
static struct intel_scu_ipc_pdata_t intel_scu_ipc_penwell_pdata = {
- .ipc_base = 0xff11c000,
.i2c_base = 0xff12b000,
- .ipc_len = 0x100,
.i2c_len = 0x10,
.irq_mode = 1,
};
static struct intel_scu_ipc_pdata_t intel_scu_ipc_tangier_pdata = {
- .ipc_base = 0xff009000,
.i2c_base = 0xff00d000,
- .ipc_len = 0x100,
.i2c_len = 0x10,
.irq_mode = 0,
};
@@ -114,8 +105,6 @@ struct intel_scu_ipc_dev {
static struct intel_scu_ipc_dev ipcdev; /* Only one for now */
-static int platform; /* Platform type */
-
/*
* IPC Read Buffer (Read Only):
* 16 byte buffer for receiving data from SCU, if IPC command
@@ -160,7 +149,6 @@ static inline void ipc_data_writel(u32 data, u32 offset) /* Write ipc data */
* Format:
* |rfu3(8)|error code(8)|initiator id(8)|cmd id(4)|rfu1(2)|error(1)|busy(1)|
*/
-
static inline u8 ipc_read_status(void)
{
return __raw_readl(ipcdev.ipc_base + 0x04);
@@ -176,23 +164,24 @@ static inline u32 ipc_data_readl(u32 offset) /* Read ipc u32 data */
return readl(ipcdev.ipc_base + IPC_READ_BUFFER + offset);
}
-static inline int busy_loop(void) /* Wait till scu status is busy */
+/* Wait till scu status is busy */
+static inline int busy_loop(void)
{
- u32 status = 0;
- u32 loop_count = 0;
+ u32 status = ipc_read_status();
+ u32 loop_count = 100000;
- status = ipc_read_status();
- while (status & 1) {
+ /* break if scu doesn't reset busy bit after huge retry */
+ while ((status & BIT(0)) && --loop_count) {
udelay(1); /* scu processing time is in few u secods */
status = ipc_read_status();
- loop_count++;
- /* break if scu doesn't reset busy bit after huge retry */
- if (loop_count > 100000) {
- dev_err(&ipcdev.pdev->dev, "IPC timed out");
- return -ETIMEDOUT;
- }
}
- if ((status >> 1) & 1)
+
+ if (status & BIT(0)) {
+ dev_err(&ipcdev.pdev->dev, "IPC timed out");
+ return -ETIMEDOUT;
+ }
+
+ if (status & BIT(1))
return -EIO;
return 0;
@@ -210,14 +199,13 @@ static inline int ipc_wait_for_interrupt(void)
}
status = ipc_read_status();
-
- if ((status >> 1) & 1)
+ if (status & BIT(1))
return -EIO;
return 0;
}
-int intel_scu_ipc_check_status(void)
+static int intel_scu_ipc_check_status(void)
{
return ipcdev.irq_mode ? ipc_wait_for_interrupt() : busy_loop();
}
@@ -248,18 +236,18 @@ static int pwr_reg_rdwr(u16 *addr, u8 *data, u32 count, u32 op, u32 id)
if (id == IPC_CMD_PCNTRL_R) {
for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
ipc_data_writel(wbuf[nc], offset);
- ipc_command((count*2) << 16 | id << 12 | 0 << 8 | op);
+ ipc_command((count * 2) << 16 | id << 12 | 0 << 8 | op);
} else if (id == IPC_CMD_PCNTRL_W) {
for (nc = 0; nc < count; nc++, offset += 1)
cbuf[offset] = data[nc];
for (nc = 0, offset = 0; nc < count; nc++, offset += 4)
ipc_data_writel(wbuf[nc], offset);
- ipc_command((count*3) << 16 | id << 12 | 0 << 8 | op);
+ ipc_command((count * 3) << 16 | id << 12 | 0 << 8 | op);
} else if (id == IPC_CMD_PCNTRL_M) {
cbuf[offset] = data[0];
cbuf[offset + 1] = data[1];
ipc_data_writel(wbuf[0], 0); /* Write wbuff */
- ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
+ ipc_command(4 << 16 | id << 12 | 0 << 8 | op);
}
err = intel_scu_ipc_check_status();
@@ -301,7 +289,7 @@ EXPORT_SYMBOL(intel_scu_ipc_ioread8);
*/
int intel_scu_ipc_ioread16(u16 addr, u16 *data)
{
- u16 x[2] = {addr, addr + 1 };
+ u16 x[2] = {addr, addr + 1};
return pwr_reg_rdwr(x, (u8 *)data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_R);
}
EXPORT_SYMBOL(intel_scu_ipc_ioread16);
@@ -351,7 +339,7 @@ EXPORT_SYMBOL(intel_scu_ipc_iowrite8);
*/
int intel_scu_ipc_iowrite16(u16 addr, u16 data)
{
- u16 x[2] = {addr, addr + 1 };
+ u16 x[2] = {addr, addr + 1};
return pwr_reg_rdwr(x, (u8 *)&data, 2, IPCMSG_PCNTRL, IPC_CMD_PCNTRL_W);
}
EXPORT_SYMBOL(intel_scu_ipc_iowrite16);
@@ -412,7 +400,6 @@ int intel_scu_ipc_writev(u16 *addr, u8 *data, int len)
}
EXPORT_SYMBOL(intel_scu_ipc_writev);
-
/**
* intel_scu_ipc_update_register - r/m/w a register
* @addr: register address
@@ -475,9 +462,8 @@ EXPORT_SYMBOL(intel_scu_ipc_simple_command);
* Issue a command to the SCU which involves data transfers. Do the
* data copies under the lock but leave it for the caller to interpret
*/
-
int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
- u32 *out, int outlen)
+ u32 *out, int outlen)
{
int i, err;
@@ -503,7 +489,7 @@ int intel_scu_ipc_command(int cmd, int sub, u32 *in, int inlen,
}
EXPORT_SYMBOL(intel_scu_ipc_command);
-/*I2C commands */
+/* I2C commands */
#define IPC_I2C_WRITE 1 /* I2C Write command */
#define IPC_I2C_READ 2 /* I2C Read command */
@@ -577,7 +563,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
{
int err;
struct intel_scu_ipc_pdata_t *pdata;
- resource_size_t pci_resource;
+ resource_size_t base;
if (ipcdev.pdev) /* We support only one SCU */
return -EBUSY;
@@ -595,8 +581,8 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (err)
return err;
- pci_resource = pci_resource_start(dev, 0);
- if (!pci_resource)
+ base = pci_resource_start(dev, 0);
+ if (!base)
return -ENOMEM;
init_completion(&ipcdev.cmd_complete);
@@ -604,7 +590,7 @@ static int ipc_probe(struct pci_dev *dev, const struct pci_device_id *id)
if (request_irq(dev->irq, ioc, 0, "intel_scu_ipc", &ipcdev))
return -EBUSY;
- ipcdev.ipc_base = ioremap_nocache(pdata->ipc_base, pdata->ipc_len);
+ ipcdev.ipc_base = ioremap_nocache(base, pci_resource_len(dev, 0));
if (!ipcdev.ipc_base)
return -ENOMEM;
@@ -666,9 +652,10 @@ static struct pci_driver ipc_driver = {
.remove = ipc_remove,
};
-
static int __init intel_scu_ipc_init(void)
{
+ int platform; /* Platform type */
+
platform = intel_mid_identify_cpu();
if (platform == 0)
return -ENODEV;
diff --git a/drivers/platform/x86/samsung-laptop.c b/drivers/platform/x86/samsung-laptop.c
index ff765d8e1a09..9e701b2256f9 100644
--- a/drivers/platform/x86/samsung-laptop.c
+++ b/drivers/platform/x86/samsung-laptop.c
@@ -124,6 +124,10 @@ struct sabi_commands {
u16 get_wireless_status;
u16 set_wireless_status;
+ /* 0x80 is off, 0x81 is on */
+ u16 get_lid_handling;
+ u16 set_lid_handling;
+
/* 0x81 to read, (0x82 | level << 8) to set, 0xaabb to enable */
u16 kbd_backlight;
@@ -194,6 +198,9 @@ static const struct sabi_config sabi_configs[] = {
.get_wireless_status = 0xFFFF,
.set_wireless_status = 0xFFFF,
+ .get_lid_handling = 0xFFFF,
+ .set_lid_handling = 0xFFFF,
+
.kbd_backlight = 0xFFFF,
.set_linux = 0x0a,
@@ -254,6 +261,9 @@ static const struct sabi_config sabi_configs[] = {
.get_wireless_status = 0x69,
.set_wireless_status = 0x6a,
+ .get_lid_handling = 0x6d,
+ .set_lid_handling = 0x6e,
+
.kbd_backlight = 0x78,
.set_linux = 0xff,
@@ -353,6 +363,8 @@ struct samsung_quirks {
bool broken_acpi_video;
bool four_kbd_backlight_levels;
bool enable_kbd_backlight;
+ bool use_native_backlight;
+ bool lid_handling;
};
static struct samsung_quirks samsung_unknown = {};
@@ -361,11 +373,19 @@ static struct samsung_quirks samsung_broken_acpi_video = {
.broken_acpi_video = true,
};
+static struct samsung_quirks samsung_use_native_backlight = {
+ .use_native_backlight = true,
+};
+
static struct samsung_quirks samsung_np740u3e = {
.four_kbd_backlight_levels = true,
.enable_kbd_backlight = true,
};
+static struct samsung_quirks samsung_lid_handling = {
+ .lid_handling = true,
+};
+
static bool force;
module_param(force, bool, 0);
MODULE_PARM_DESC(force,
@@ -748,7 +768,7 @@ static ssize_t set_battery_life_extender(struct device *dev,
struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret, value;
- if (!count || sscanf(buf, "%i", &value) != 1)
+ if (!count || kstrtoint(buf, 0, &value) != 0)
return -EINVAL;
ret = write_battery_life_extender(samsung, !!value);
@@ -817,7 +837,7 @@ static ssize_t set_usb_charge(struct device *dev,
struct samsung_laptop *samsung = dev_get_drvdata(dev);
int ret, value;
- if (!count || sscanf(buf, "%i", &value) != 1)
+ if (!count || kstrtoint(buf, 0, &value) != 0)
return -EINVAL;
ret = write_usb_charge(samsung, !!value);
@@ -830,10 +850,76 @@ static ssize_t set_usb_charge(struct device *dev,
static DEVICE_ATTR(usb_charge, S_IWUSR | S_IRUGO,
get_usb_charge, set_usb_charge);
+static int read_lid_handling(struct samsung_laptop *samsung)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+ int retval;
+
+ if (commands->get_lid_handling == 0xFFFF)
+ return -ENODEV;
+
+ memset(&data, 0, sizeof(data));
+ retval = sabi_command(samsung, commands->get_lid_handling,
+ &data, &data);
+
+ if (retval)
+ return retval;
+
+ return data.data[0] & 0x1;
+}
+
+static int write_lid_handling(struct samsung_laptop *samsung,
+ int enabled)
+{
+ const struct sabi_commands *commands = &samsung->config->commands;
+ struct sabi_data data;
+
+ memset(&data, 0, sizeof(data));
+ data.data[0] = 0x80 | enabled;
+ return sabi_command(samsung, commands->set_lid_handling,
+ &data, NULL);
+}
+
+static ssize_t get_lid_handling(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ int ret;
+
+ ret = read_lid_handling(samsung);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", ret);
+}
+
+static ssize_t set_lid_handling(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct samsung_laptop *samsung = dev_get_drvdata(dev);
+ int ret, value;
+
+ if (!count || kstrtoint(buf, 0, &value) != 0)
+ return -EINVAL;
+
+ ret = write_lid_handling(samsung, !!value);
+ if (ret < 0)
+ return ret;
+
+ return count;
+}
+
+static DEVICE_ATTR(lid_handling, S_IWUSR | S_IRUGO,
+ get_lid_handling, set_lid_handling);
+
static struct attribute *platform_attributes[] = {
&dev_attr_performance_level.attr,
&dev_attr_battery_life_extender.attr,
&dev_attr_usb_charge.attr,
+ &dev_attr_lid_handling.attr,
NULL
};
@@ -956,6 +1042,22 @@ static int __init samsung_rfkill_init(struct samsung_laptop *samsung)
return 0;
}
+static void samsung_lid_handling_exit(struct samsung_laptop *samsung)
+{
+ if (samsung->quirks->lid_handling)
+ write_lid_handling(samsung, 0);
+}
+
+static int __init samsung_lid_handling_init(struct samsung_laptop *samsung)
+{
+ int retval = 0;
+
+ if (samsung->quirks->lid_handling)
+ retval = write_lid_handling(samsung, 1);
+
+ return retval;
+}
+
static int kbd_backlight_enable(struct samsung_laptop *samsung)
{
const struct sabi_commands *commands = &samsung->config->commands;
@@ -1111,7 +1213,7 @@ static int __init samsung_backlight_init(struct samsung_laptop *samsung)
}
static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
- struct attribute *attr, int idx)
+ struct attribute *attr, int idx)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct platform_device *pdev = to_platform_device(dev);
@@ -1124,6 +1226,8 @@ static umode_t samsung_sysfs_is_visible(struct kobject *kobj,
ok = !!(read_battery_life_extender(samsung) >= 0);
if (attr == &dev_attr_usb_charge.attr)
ok = !!(read_usb_charge(samsung) >= 0);
+ if (attr == &dev_attr_lid_handling.attr)
+ ok = !!(read_lid_handling(samsung) >= 0);
return ok ? attr->mode : 0;
}
@@ -1357,7 +1461,7 @@ static int __init samsung_sabi_init(struct samsung_laptop *samsung)
samsung_sabi_diag(samsung);
/* Try to find one of the signatures in memory to find the header */
- for (i = 0; sabi_configs[i].test_string != 0; ++i) {
+ for (i = 0; sabi_configs[i].test_string != NULL; ++i) {
samsung->config = &sabi_configs[i];
loca = find_signature(samsung->f0000_segment,
samsung->config->test_string);
@@ -1436,6 +1540,9 @@ static int samsung_pm_notification(struct notifier_block *nb,
samsung->quirks->enable_kbd_backlight)
kbd_backlight_enable(samsung);
+ if (val == PM_POST_HIBERNATION && samsung->quirks->lid_handling)
+ write_lid_handling(samsung, 1);
+
return 0;
}
@@ -1507,7 +1614,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N150P"),
DMI_MATCH(DMI_BOARD_NAME, "N150P"),
},
- .driver_data = &samsung_broken_acpi_video,
+ .driver_data = &samsung_use_native_backlight,
},
{
.callback = samsung_dmi_matched,
@@ -1517,7 +1624,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N145P/N250P/N260P"),
DMI_MATCH(DMI_BOARD_NAME, "N145P/N250P/N260P"),
},
- .driver_data = &samsung_broken_acpi_video,
+ .driver_data = &samsung_use_native_backlight,
},
{
.callback = samsung_dmi_matched,
@@ -1557,7 +1664,7 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N250P"),
DMI_MATCH(DMI_BOARD_NAME, "N250P"),
},
- .driver_data = &samsung_broken_acpi_video,
+ .driver_data = &samsung_use_native_backlight,
},
{
.callback = samsung_dmi_matched,
@@ -1578,6 +1685,15 @@ static struct dmi_system_id __initdata samsung_dmi_table[] = {
},
.driver_data = &samsung_np740u3e,
},
+ {
+ .callback = samsung_dmi_matched,
+ .ident = "300V3Z/300V4Z/300V5Z",
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
+ DMI_MATCH(DMI_PRODUCT_NAME, "300V3Z/300V4Z/300V5Z"),
+ },
+ .driver_data = &samsung_lid_handling,
+ },
{ },
};
MODULE_DEVICE_TABLE(dmi, samsung_dmi_table);
@@ -1616,6 +1732,15 @@ static int __init samsung_init(void)
pr_info("Disabling ACPI video driver\n");
acpi_video_unregister();
}
+
+ if (samsung->quirks->use_native_backlight) {
+ pr_info("Using native backlight driver\n");
+ /* Tell acpi-video to not handle the backlight */
+ acpi_video_dmi_promote_vendor();
+ acpi_video_unregister();
+ /* And also do not handle it ourselves */
+ samsung->handle_backlight = false;
+ }
#endif
ret = samsung_platform_init(samsung);
@@ -1648,6 +1773,10 @@ static int __init samsung_init(void)
if (ret)
goto error_leds;
+ ret = samsung_lid_handling_init(samsung);
+ if (ret)
+ goto error_lid_handling;
+
ret = samsung_debugfs_init(samsung);
if (ret)
goto error_debugfs;
@@ -1659,6 +1788,8 @@ static int __init samsung_init(void)
return ret;
error_debugfs:
+ samsung_lid_handling_exit(samsung);
+error_lid_handling:
samsung_leds_exit(samsung);
error_leds:
samsung_rfkill_exit(samsung);
@@ -1683,6 +1814,7 @@ static void __exit samsung_exit(void)
unregister_pm_notifier(&samsung->pm_nb);
samsung_debugfs_exit(samsung);
+ samsung_lid_handling_exit(samsung);
samsung_leds_exit(samsung);
samsung_rfkill_exit(samsung);
samsung_backlight_exit(samsung);
diff --git a/drivers/platform/x86/sony-laptop.c b/drivers/platform/x86/sony-laptop.c
index 6dd1c0e7dcd9..e51c1e753607 100644
--- a/drivers/platform/x86/sony-laptop.c
+++ b/drivers/platform/x86/sony-laptop.c
@@ -1032,7 +1032,7 @@ struct sony_backlight_props {
u8 offset;
u8 maxlvl;
};
-struct sony_backlight_props sony_bl_props;
+static struct sony_backlight_props sony_bl_props;
static int sony_backlight_update_status(struct backlight_device *bd)
{
diff --git a/drivers/platform/x86/thinkpad_acpi.c b/drivers/platform/x86/thinkpad_acpi.c
index c3d11fabc46f..3b8ceee7c5cb 100644
--- a/drivers/platform/x86/thinkpad_acpi.c
+++ b/drivers/platform/x86/thinkpad_acpi.c
@@ -196,6 +196,7 @@ enum tpacpi_hkey_event_t {
/* Key-related user-interface events */
TP_HKEY_EV_KEY_NUMLOCK = 0x6000, /* NumLock key pressed */
TP_HKEY_EV_KEY_FN = 0x6005, /* Fn key pressed? E420 */
+ TP_HKEY_EV_KEY_FN_ESC = 0x6060, /* Fn+Esc key pressed X240 */
/* Thermal events */
TP_HKEY_EV_ALARM_BAT_HOT = 0x6011, /* battery too hot */
@@ -3456,7 +3457,7 @@ enum ADAPTIVE_KEY_MODE {
LAYFLAT_MODE
};
-const int adaptive_keyboard_modes[] = {
+static const int adaptive_keyboard_modes[] = {
HOME_MODE,
/* WEB_BROWSER_MODE = 2,
WEB_CONFERENCE_MODE = 3, */
@@ -3712,6 +3713,7 @@ static bool hotkey_notify_6xxx(const u32 hkey,
case TP_HKEY_EV_KEY_NUMLOCK:
case TP_HKEY_EV_KEY_FN:
+ case TP_HKEY_EV_KEY_FN_ESC:
/* key press events, we just ignore them as long as the EC
* is still reporting them in the normal keyboard stream */
*send_acpi_ev = false;
@@ -8883,17 +8885,31 @@ static bool __pure __init tpacpi_is_fw_digit(const char c)
return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z');
}
-/* Most models: xxyTkkWW (#.##c); Ancient 570/600 and -SL lacks (#.##c) */
static bool __pure __init tpacpi_is_valid_fw_id(const char * const s,
const char t)
{
- return s && strlen(s) >= 8 &&
+ /*
+ * Most models: xxyTkkWW (#.##c)
+ * Ancient 570/600 and -SL lacks (#.##c)
+ */
+ if (s && strlen(s) >= 8 &&
tpacpi_is_fw_digit(s[0]) &&
tpacpi_is_fw_digit(s[1]) &&
s[2] == t &&
(s[3] == 'T' || s[3] == 'N') &&
tpacpi_is_fw_digit(s[4]) &&
- tpacpi_is_fw_digit(s[5]);
+ tpacpi_is_fw_digit(s[5]))
+ return true;
+
+ /* New models: xxxyTkkW (#.##c); T550 and some others */
+ return s && strlen(s) >= 8 &&
+ tpacpi_is_fw_digit(s[0]) &&
+ tpacpi_is_fw_digit(s[1]) &&
+ tpacpi_is_fw_digit(s[2]) &&
+ s[3] == t &&
+ (s[4] == 'T' || s[4] == 'N') &&
+ tpacpi_is_fw_digit(s[5]) &&
+ tpacpi_is_fw_digit(s[6]);
}
/* returns 0 - probe ok, or < 0 - probe error.
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
index fc34a71866ed..dbcb7a8915b8 100644
--- a/drivers/platform/x86/toshiba_acpi.c
+++ b/drivers/platform/x86/toshiba_acpi.c
@@ -1,11 +1,10 @@
/*
* toshiba_acpi.c - Toshiba Laptop ACPI Extras
*
- *
* Copyright (C) 2002-2004 John Belmonte
* Copyright (C) 2008 Philip Langdale
* Copyright (C) 2010 Pierre Ducroquet
- * Copyright (C) 2014 Azael Avalos
+ * Copyright (C) 2014-2015 Azael Avalos
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -17,10 +16,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU 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
- *
+ * The full GNU General Public License is included in this distribution in
+ * the file called "COPYING".
*
* The devolpment page for this driver is located at
* http://memebeam.org/toys/ToshibaAcpiDriver.
@@ -30,15 +27,11 @@
* engineering the Windows drivers
* Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
* Rob Miller - TV out and hotkeys help
- *
- *
- * TODO
- *
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-#define TOSHIBA_ACPI_VERSION "0.20"
+#define TOSHIBA_ACPI_VERSION "0.21"
#define PROC_INTERFACE_VERSION 1
#include <linux/kernel.h>
@@ -57,7 +50,7 @@
#include <linux/i8042.h>
#include <linux/acpi.h>
#include <linux/dmi.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
MODULE_AUTHOR("John Belmonte");
MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
@@ -71,7 +64,8 @@ MODULE_LICENSE("GPL");
/* Toshiba ACPI method paths */
#define METHOD_VIDEO_OUT "\\_SB_.VALX.DSSX"
-/* The Toshiba configuration interface is composed of the HCI and the SCI,
+/*
+ * The Toshiba configuration interface is composed of the HCI and the SCI,
* which are defined as follows:
*
* HCI is Toshiba's "Hardware Control Interface" which is supposed to
@@ -108,6 +102,7 @@ MODULE_LICENSE("GPL");
#define TOS_FIFO_EMPTY 0x8c00
#define TOS_DATA_NOT_AVAILABLE 0x8d20
#define TOS_NOT_INITIALIZED 0x8d50
+#define TOS_NOT_INSTALLED 0x8e00
/* registers */
#define HCI_FAN 0x0004
@@ -121,9 +116,14 @@ MODULE_LICENSE("GPL");
#define HCI_KBD_ILLUMINATION 0x0095
#define HCI_ECO_MODE 0x0097
#define HCI_ACCELEROMETER2 0x00a6
+#define SCI_PANEL_POWER_ON 0x010d
#define SCI_ILLUMINATION 0x014e
+#define SCI_USB_SLEEP_CHARGE 0x0150
#define SCI_KBD_ILLUM_STATUS 0x015c
+#define SCI_USB_SLEEP_MUSIC 0x015e
+#define SCI_USB_THREE 0x0169
#define SCI_TOUCHPAD 0x050e
+#define SCI_KBD_FUNCTION_KEYS 0x0522
/* field definitions */
#define HCI_ACCEL_MASK 0x7fff
@@ -146,6 +146,15 @@ MODULE_LICENSE("GPL");
#define SCI_KBD_MODE_ON 0x8
#define SCI_KBD_MODE_OFF 0x10
#define SCI_KBD_TIME_MAX 0x3c001a
+#define SCI_USB_CHARGE_MODE_MASK 0xff
+#define SCI_USB_CHARGE_DISABLED 0x30000
+#define SCI_USB_CHARGE_ALTERNATE 0x30009
+#define SCI_USB_CHARGE_AUTO 0x30021
+#define SCI_USB_CHARGE_BAT_MASK 0x7
+#define SCI_USB_CHARGE_BAT_LVL_OFF 0x1
+#define SCI_USB_CHARGE_BAT_LVL_ON 0x4
+#define SCI_USB_CHARGE_BAT_LVL 0x0200
+#define SCI_USB_CHARGE_RAPID_DSP 0x0300
struct toshiba_acpi_dev {
struct acpi_device *acpi_dev;
@@ -164,6 +173,7 @@ struct toshiba_acpi_dev {
int kbd_type;
int kbd_mode;
int kbd_time;
+ int usbsc_bat_level;
unsigned int illumination_supported:1;
unsigned int video_supported:1;
@@ -177,6 +187,12 @@ struct toshiba_acpi_dev {
unsigned int touchpad_supported:1;
unsigned int eco_supported:1;
unsigned int accelerometer_supported:1;
+ unsigned int usb_sleep_charge_supported:1;
+ unsigned int usb_rapid_charge_supported:1;
+ unsigned int usb_sleep_music_supported:1;
+ unsigned int kbd_function_keys_supported:1;
+ unsigned int panel_power_on_supported:1;
+ unsigned int usb_three_supported:1;
unsigned int sysfs_created:1;
struct mutex mutex;
@@ -264,15 +280,17 @@ static const struct key_entry toshiba_acpi_alt_keymap[] = {
{ KE_END, 0 },
};
-/* utility
+/*
+ * Utility
*/
-static __inline__ void _set_bit(u32 * word, u32 mask, int value)
+static inline void _set_bit(u32 *word, u32 mask, int value)
{
*word = (*word & ~mask) | (mask * value);
}
-/* acpi interface wrappers
+/*
+ * ACPI interface wrappers
*/
static int write_acpi_int(const char *methodName, int val)
@@ -283,7 +301,8 @@ static int write_acpi_int(const char *methodName, int val)
return (status == AE_OK) ? 0 : -EIO;
}
-/* Perform a raw configuration call. Here we don't care about input or output
+/*
+ * Perform a raw configuration call. Here we don't care about input or output
* buffer format.
*/
static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
@@ -310,15 +329,15 @@ static acpi_status tci_raw(struct toshiba_acpi_dev *dev,
(char *)dev->method_hci, &params,
&results);
if ((status == AE_OK) && (out_objs->package.count <= TCI_WORDS)) {
- for (i = 0; i < out_objs->package.count; ++i) {
+ for (i = 0; i < out_objs->package.count; ++i)
out[i] = out_objs->package.elements[i].integer.value;
- }
}
return status;
}
-/* common hci tasks (get or set one or two value)
+/*
+ * Common hci tasks (get or set one or two value)
*
* In addition to the ACPI status, the HCI system returns a result which
* may be useful (such as "not supported").
@@ -338,6 +357,7 @@ static u32 hci_read1(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
u32 in[TCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
u32 out[TCI_WORDS];
acpi_status status = tci_raw(dev, in, out);
+
if (ACPI_FAILURE(status))
return TOS_FAILURE;
@@ -355,11 +375,13 @@ static u32 hci_write2(struct toshiba_acpi_dev *dev, u32 reg, u32 in1, u32 in2)
return ACPI_SUCCESS(status) ? out[0] : TOS_FAILURE;
}
-static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2)
+static u32 hci_read2(struct toshiba_acpi_dev *dev,
+ u32 reg, u32 *out1, u32 *out2)
{
u32 in[TCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
u32 out[TCI_WORDS];
acpi_status status = tci_raw(dev, in, out);
+
if (ACPI_FAILURE(status))
return TOS_FAILURE;
@@ -369,7 +391,8 @@ static u32 hci_read2(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1, u32 *out2
return out[0];
}
-/* common sci tasks
+/*
+ * Common sci tasks
*/
static int sci_open(struct toshiba_acpi_dev *dev)
@@ -389,6 +412,20 @@ static int sci_open(struct toshiba_acpi_dev *dev)
} else if (out[0] == TOS_ALREADY_OPEN) {
pr_info("Toshiba SCI already opened\n");
return 1;
+ } else if (out[0] == TOS_NOT_SUPPORTED) {
+ /*
+ * Some BIOSes do not have the SCI open/close functions
+ * implemented and return 0x8000 (Not Supported), failing to
+ * register some supported features.
+ *
+ * Simply return 1 if we hit those affected laptops to make the
+ * supported features work.
+ *
+ * In the case that some laptops really do not support the SCI,
+ * all the SCI dependent functions check for TOS_NOT_SUPPORTED,
+ * and thus, not registering support for the queried feature.
+ */
+ return 1;
} else if (out[0] == TOS_NOT_PRESENT) {
pr_info("Toshiba SCI is not present\n");
}
@@ -421,6 +458,7 @@ static u32 sci_read(struct toshiba_acpi_dev *dev, u32 reg, u32 *out1)
u32 in[TCI_WORDS] = { SCI_GET, reg, 0, 0, 0, 0 };
u32 out[TCI_WORDS];
acpi_status status = tci_raw(dev, in, out);
+
if (ACPI_FAILURE(status))
return TOS_FAILURE;
@@ -529,10 +567,11 @@ static int toshiba_kbd_illum_available(struct toshiba_acpi_dev *dev)
return 0;
}
- /* Check for keyboard backlight timeout max value,
+ /*
+ * Check for keyboard backlight timeout max value,
* previous kbd backlight implementation set this to
* 0x3c0003, and now the new implementation set this
- * to 0x3c001a, use this to distinguish between them
+ * to 0x3c001a, use this to distinguish between them.
*/
if (out[3] == SCI_KBD_TIME_MAX)
dev->kbd_type = 2;
@@ -667,19 +706,37 @@ static int toshiba_touchpad_get(struct toshiba_acpi_dev *dev, u32 *state)
static int toshiba_eco_mode_available(struct toshiba_acpi_dev *dev)
{
acpi_status status;
- u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 1, 0, 0 };
+ u32 in[TCI_WORDS] = { HCI_GET, HCI_ECO_MODE, 0, 0, 0, 0 };
u32 out[TCI_WORDS];
status = tci_raw(dev, in, out);
- if (ACPI_FAILURE(status) || out[0] == TOS_INPUT_DATA_ERROR) {
- pr_info("ACPI call to get ECO led failed\n");
- return 0;
+ if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
+ pr_err("ACPI call to get ECO led failed\n");
+ } else if (out[0] == TOS_NOT_INSTALLED) {
+ pr_info("ECO led not installed");
+ } else if (out[0] == TOS_INPUT_DATA_ERROR) {
+ /*
+ * If we receive 0x8300 (Input Data Error), it means that the
+ * LED device is present, but that we just screwed the input
+ * parameters.
+ *
+ * Let's query the status of the LED to see if we really have a
+ * success response, indicating the actual presense of the LED,
+ * bail out otherwise.
+ */
+ in[3] = 1;
+ status = tci_raw(dev, in, out);
+ if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE)
+ pr_err("ACPI call to get ECO led failed\n");
+ else if (out[0] == TOS_SUCCESS)
+ return 1;
}
- return 1;
+ return 0;
}
-static enum led_brightness toshiba_eco_mode_get_status(struct led_classdev *cdev)
+static enum led_brightness
+toshiba_eco_mode_get_status(struct led_classdev *cdev)
{
struct toshiba_acpi_dev *dev = container_of(cdev,
struct toshiba_acpi_dev, eco_led);
@@ -721,7 +778,8 @@ static int toshiba_accelerometer_supported(struct toshiba_acpi_dev *dev)
u32 out[TCI_WORDS];
acpi_status status;
- /* Check if the accelerometer call exists,
+ /*
+ * Check if the accelerometer call exists,
* this call also serves as initialization
*/
status = tci_raw(dev, in, out);
@@ -760,6 +818,337 @@ static int toshiba_accelerometer_get(struct toshiba_acpi_dev *dev,
return 0;
}
+/* Sleep (Charge and Music) utilities support */
+static int toshiba_usb_sleep_charge_get(struct toshiba_acpi_dev *dev,
+ u32 *mode)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_read(dev, SCI_USB_SLEEP_CHARGE, mode);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to set USB S&C mode failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_usb_sleep_charge_set(struct toshiba_acpi_dev *dev,
+ u32 mode)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_write(dev, SCI_USB_SLEEP_CHARGE, mode);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to set USB S&C mode failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_sleep_functions_status_get(struct toshiba_acpi_dev *dev,
+ u32 *mode)
+{
+ u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ in[5] = SCI_USB_CHARGE_BAT_LVL;
+ status = tci_raw(dev, in, out);
+ sci_close(dev);
+ if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
+ pr_err("ACPI call to get USB S&C battery level failed\n");
+ return -EIO;
+ } else if (out[0] == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (out[0] == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ *mode = out[2];
+
+ return 0;
+}
+
+static int toshiba_sleep_functions_status_set(struct toshiba_acpi_dev *dev,
+ u32 mode)
+{
+ u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ in[2] = mode;
+ in[5] = SCI_USB_CHARGE_BAT_LVL;
+ status = tci_raw(dev, in, out);
+ sci_close(dev);
+ if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
+ pr_err("ACPI call to set USB S&C battery level failed\n");
+ return -EIO;
+ } else if (out[0] == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (out[0] == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_usb_rapid_charge_get(struct toshiba_acpi_dev *dev,
+ u32 *state)
+{
+ u32 in[TCI_WORDS] = { SCI_GET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ in[5] = SCI_USB_CHARGE_RAPID_DSP;
+ status = tci_raw(dev, in, out);
+ sci_close(dev);
+ if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
+ pr_err("ACPI call to get USB S&C battery level failed\n");
+ return -EIO;
+ } else if (out[0] == TOS_NOT_SUPPORTED ||
+ out[0] == TOS_INPUT_DATA_ERROR) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ }
+
+ *state = out[2];
+
+ return 0;
+}
+
+static int toshiba_usb_rapid_charge_set(struct toshiba_acpi_dev *dev,
+ u32 state)
+{
+ u32 in[TCI_WORDS] = { SCI_SET, SCI_USB_SLEEP_CHARGE, 0, 0, 0, 0 };
+ u32 out[TCI_WORDS];
+ acpi_status status;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ in[2] = state;
+ in[5] = SCI_USB_CHARGE_RAPID_DSP;
+ status = tci_raw(dev, in, out);
+ sci_close(dev);
+ if (ACPI_FAILURE(status) || out[0] == TOS_FAILURE) {
+ pr_err("ACPI call to set USB S&C battery level failed\n");
+ return -EIO;
+ } else if (out[0] == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (out[0] == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_usb_sleep_music_get(struct toshiba_acpi_dev *dev, u32 *state)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_read(dev, SCI_USB_SLEEP_MUSIC, state);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to set USB S&C mode failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_usb_sleep_music_set(struct toshiba_acpi_dev *dev, u32 state)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_write(dev, SCI_USB_SLEEP_MUSIC, state);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to set USB S&C mode failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("USB Sleep and Charge not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* Keyboard function keys */
+static int toshiba_function_keys_get(struct toshiba_acpi_dev *dev, u32 *mode)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_read(dev, SCI_KBD_FUNCTION_KEYS, mode);
+ sci_close(dev);
+ if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
+ pr_err("ACPI call to get KBD function keys failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("KBD function keys not supported\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int toshiba_function_keys_set(struct toshiba_acpi_dev *dev, u32 mode)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_write(dev, SCI_KBD_FUNCTION_KEYS, mode);
+ sci_close(dev);
+ if (result == TOS_FAILURE || result == TOS_INPUT_DATA_ERROR) {
+ pr_err("ACPI call to set KBD function keys failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("KBD function keys not supported\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* Panel Power ON */
+static int toshiba_panel_power_on_get(struct toshiba_acpi_dev *dev, u32 *state)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_read(dev, SCI_PANEL_POWER_ON, state);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to get Panel Power ON failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("Panel Power on not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_panel_power_on_set(struct toshiba_acpi_dev *dev, u32 state)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_write(dev, SCI_PANEL_POWER_ON, state);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to set Panel Power ON failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("Panel Power ON not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/* USB Three */
+static int toshiba_usb_three_get(struct toshiba_acpi_dev *dev, u32 *state)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_read(dev, SCI_USB_THREE, state);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to get USB 3 failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("USB 3 not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int toshiba_usb_three_set(struct toshiba_acpi_dev *dev, u32 state)
+{
+ u32 result;
+
+ if (!sci_open(dev))
+ return -EIO;
+
+ result = sci_write(dev, SCI_USB_THREE, state);
+ sci_close(dev);
+ if (result == TOS_FAILURE) {
+ pr_err("ACPI call to set USB 3 failed\n");
+ return -EIO;
+ } else if (result == TOS_NOT_SUPPORTED) {
+ pr_info("USB 3 not supported\n");
+ return -ENODEV;
+ } else if (result == TOS_INPUT_DATA_ERROR) {
+ return -EIO;
+ }
+
+ return 0;
+}
+
/* Bluetooth rfkill handlers */
static u32 hci_get_bt_present(struct toshiba_acpi_dev *dev, bool *present)
@@ -870,7 +1259,7 @@ static int set_tr_backlight_status(struct toshiba_acpi_dev *dev, bool enable)
return hci_result == TOS_SUCCESS ? 0 : -EIO;
}
-static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
+static struct proc_dir_entry *toshiba_proc_dir /*= 0*/;
static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
{
@@ -881,6 +1270,7 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
if (dev->tr_backlight_supported) {
bool enabled;
int ret = get_tr_backlight_status(dev, &enabled);
+
if (ret)
return ret;
if (enabled)
@@ -898,6 +1288,7 @@ static int __get_lcd_brightness(struct toshiba_acpi_dev *dev)
static int get_lcd_brightness(struct backlight_device *bd)
{
struct toshiba_acpi_dev *dev = bl_get_data(bd);
+
return __get_lcd_brightness(dev);
}
@@ -934,6 +1325,7 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
if (dev->tr_backlight_supported) {
bool enable = !value;
int ret = set_tr_backlight_status(dev, enable);
+
if (ret)
return ret;
if (value)
@@ -948,6 +1340,7 @@ static int set_lcd_brightness(struct toshiba_acpi_dev *dev, int value)
static int set_lcd_status(struct backlight_device *bd)
{
struct toshiba_acpi_dev *dev = bl_get_data(bd);
+
return set_lcd_brightness(dev, bd->props.brightness);
}
@@ -1005,6 +1398,7 @@ static int video_proc_show(struct seq_file *m, void *v)
int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
+
seq_printf(m, "lcd_out: %d\n", is_lcd);
seq_printf(m, "crt_out: %d\n", is_crt);
seq_printf(m, "tv_out: %d\n", is_tv);
@@ -1042,9 +1436,9 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
buffer = cmd;
- /* scan expression. Multiple expressions may be delimited with ;
- *
- * NOTE: to keep scanning simple, invalid fields are ignored
+ /*
+ * Scan expression. Multiple expressions may be delimited with ;
+ * NOTE: To keep scanning simple, invalid fields are ignored.
*/
while (remain) {
if (sscanf(buffer, " lcd_out : %i", &value) == 1)
@@ -1053,12 +1447,11 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
crt_out = value & 1;
else if (sscanf(buffer, " tv_out : %i", &value) == 1)
tv_out = value & 1;
- /* advance to one character past the next ; */
+ /* Advance to one character past the next ; */
do {
++buffer;
--remain;
- }
- while (remain && *(buffer - 1) != ';');
+ } while (remain && *(buffer - 1) != ';');
}
kfree(cmd);
@@ -1066,13 +1459,15 @@ static ssize_t video_proc_write(struct file *file, const char __user *buf,
ret = get_video_status(dev, &video_out);
if (!ret) {
unsigned int new_video_out = video_out;
+
if (lcd_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
if (crt_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
if (tv_out != -1)
_set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
- /* To avoid unnecessary video disruption, only write the new
+ /*
+ * To avoid unnecessary video disruption, only write the new
* video setting if something changed. */
if (new_video_out != video_out)
ret = write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
@@ -1135,10 +1530,10 @@ static ssize_t fan_proc_write(struct file *file, const char __user *buf,
if (sscanf(cmd, " force_on : %i", &value) == 1 &&
value >= 0 && value <= 1) {
hci_result = hci_write1(dev, HCI_FAN, value);
- if (hci_result != TOS_SUCCESS)
- return -EIO;
- else
+ if (hci_result == TOS_SUCCESS)
dev->force_fan = value;
+ else
+ return -EIO;
} else {
return -EINVAL;
}
@@ -1167,11 +1562,13 @@ static int keys_proc_show(struct seq_file *m, void *v)
dev->key_event_valid = 1;
dev->last_key_event = value;
} else if (hci_result == TOS_FIFO_EMPTY) {
- /* better luck next time */
+ /* Better luck next time */
} else if (hci_result == TOS_NOT_SUPPORTED) {
- /* This is a workaround for an unresolved issue on
+ /*
+ * This is a workaround for an unresolved issue on
* some machines where system events sporadically
- * become disabled. */
+ * become disabled.
+ */
hci_result = hci_write1(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n");
} else {
@@ -1203,11 +1600,10 @@ static ssize_t keys_proc_write(struct file *file, const char __user *buf,
return -EFAULT;
cmd[len] = '\0';
- if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0) {
+ if (sscanf(cmd, " hotkey_ready : %i", &value) == 1 && value == 0)
dev->key_event_valid = 0;
- } else {
+ else
return -EINVAL;
- }
return count;
}
@@ -1241,7 +1637,8 @@ static const struct file_operations version_proc_fops = {
.release = single_release,
};
-/* proc and module init
+/*
+ * Proc and module init
*/
#define PROC_TOSHIBA "toshiba"
@@ -1286,66 +1683,56 @@ static const struct backlight_ops toshiba_backlight_data = {
/*
* Sysfs files
*/
-static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-static ssize_t toshiba_kbd_type_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-static ssize_t toshiba_touchpad_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
-static ssize_t toshiba_touchpad_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-static ssize_t toshiba_position_show(struct device *dev,
- struct device_attribute *attr,
- char *buf);
-
-static DEVICE_ATTR(kbd_backlight_mode, S_IRUGO | S_IWUSR,
- toshiba_kbd_bl_mode_show, toshiba_kbd_bl_mode_store);
-static DEVICE_ATTR(kbd_type, S_IRUGO, toshiba_kbd_type_show, NULL);
-static DEVICE_ATTR(available_kbd_modes, S_IRUGO,
- toshiba_available_kbd_modes_show, NULL);
-static DEVICE_ATTR(kbd_backlight_timeout, S_IRUGO | S_IWUSR,
- toshiba_kbd_bl_timeout_show, toshiba_kbd_bl_timeout_store);
-static DEVICE_ATTR(touchpad, S_IRUGO | S_IWUSR,
- toshiba_touchpad_show, toshiba_touchpad_store);
-static DEVICE_ATTR(position, S_IRUGO, toshiba_position_show, NULL);
+static ssize_t version_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ return sprintf(buf, "%s\n", TOSHIBA_ACPI_VERSION);
+}
+static DEVICE_ATTR_RO(version);
-static struct attribute *toshiba_attributes[] = {
- &dev_attr_kbd_backlight_mode.attr,
- &dev_attr_kbd_type.attr,
- &dev_attr_available_kbd_modes.attr,
- &dev_attr_kbd_backlight_timeout.attr,
- &dev_attr_touchpad.attr,
- &dev_attr_position.attr,
- NULL,
-};
+static ssize_t fan_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 result;
+ int state;
+ int ret;
-static umode_t toshiba_sysfs_is_visible(struct kobject *,
- struct attribute *, int);
+ ret = kstrtoint(buf, 0, &state);
+ if (ret)
+ return ret;
-static struct attribute_group toshiba_attr_group = {
- .is_visible = toshiba_sysfs_is_visible,
- .attrs = toshiba_attributes,
-};
+ if (state != 0 && state != 1)
+ return -EINVAL;
-static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+ result = hci_write1(toshiba, HCI_FAN, state);
+ if (result == TOS_FAILURE)
+ return -EIO;
+ else if (result == TOS_NOT_SUPPORTED)
+ return -ENODEV;
+
+ return count;
+}
+
+static ssize_t fan_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 value;
+ int ret;
+
+ ret = get_fan_status(toshiba, &value);
+ if (ret)
+ return ret;
+
+ return sprintf(buf, "%d\n", value);
+}
+static DEVICE_ATTR_RW(fan);
+
+static ssize_t kbd_backlight_mode_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int mode;
@@ -1369,7 +1756,8 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
return -EINVAL;
}
- /* Set the Keyboard Backlight Mode where:
+ /*
+ * Set the Keyboard Backlight Mode where:
* Auto - KBD backlight turns off automatically in given time
* FN-Z - KBD backlight "toggles" when hotkey pressed
* ON - KBD backlight is always on
@@ -1400,9 +1788,9 @@ static ssize_t toshiba_kbd_bl_mode_store(struct device *dev,
return count;
}
-static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t kbd_backlight_mode_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 time;
@@ -1412,19 +1800,20 @@ static ssize_t toshiba_kbd_bl_mode_show(struct device *dev,
return sprintf(buf, "%i\n", time & SCI_KBD_MODE_MASK);
}
+static DEVICE_ATTR_RW(kbd_backlight_mode);
-static ssize_t toshiba_kbd_type_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t kbd_type_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", toshiba->kbd_type);
}
+static DEVICE_ATTR_RO(kbd_type);
-static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t available_kbd_modes_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
@@ -1435,10 +1824,11 @@ static ssize_t toshiba_available_kbd_modes_show(struct device *dev,
return sprintf(buf, "%x %x %x\n",
SCI_KBD_MODE_AUTO, SCI_KBD_MODE_ON, SCI_KBD_MODE_OFF);
}
+static DEVICE_ATTR_RO(available_kbd_modes);
-static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t kbd_backlight_timeout_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int time;
@@ -1479,9 +1869,9 @@ static ssize_t toshiba_kbd_bl_timeout_store(struct device *dev,
return count;
}
-static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static ssize_t kbd_backlight_timeout_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 time;
@@ -1491,10 +1881,11 @@ static ssize_t toshiba_kbd_bl_timeout_show(struct device *dev,
return sprintf(buf, "%i\n", time >> HCI_MISC_SHIFT);
}
+static DEVICE_ATTR_RW(kbd_backlight_timeout);
-static ssize_t toshiba_touchpad_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static ssize_t touchpad_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
int state;
@@ -1514,8 +1905,8 @@ static ssize_t toshiba_touchpad_store(struct device *dev,
return count;
}
-static ssize_t toshiba_touchpad_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t touchpad_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 state;
@@ -1527,9 +1918,10 @@ static ssize_t toshiba_touchpad_show(struct device *dev,
return sprintf(buf, "%i\n", state);
}
+static DEVICE_ATTR_RW(touchpad);
-static ssize_t toshiba_position_show(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t position_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
u32 xyval, zval, tmp;
@@ -1548,6 +1940,336 @@ static ssize_t toshiba_position_show(struct device *dev,
return sprintf(buf, "%d %d %d\n", x, y, z);
}
+static DEVICE_ATTR_RO(position);
+
+static ssize_t usb_sleep_charge_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 mode;
+ int ret;
+
+ ret = toshiba_usb_sleep_charge_get(toshiba, &mode);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%x\n", mode & SCI_USB_CHARGE_MODE_MASK);
+}
+
+static ssize_t usb_sleep_charge_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 mode;
+ int state;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &state);
+ if (ret)
+ return ret;
+ /*
+ * Check for supported values, where:
+ * 0 - Disabled
+ * 1 - Alternate (Non USB conformant devices that require more power)
+ * 2 - Auto (USB conformant devices)
+ */
+ if (state != 0 && state != 1 && state != 2)
+ return -EINVAL;
+
+ /* Set the USB charging mode to internal value */
+ if (state == 0)
+ mode = SCI_USB_CHARGE_DISABLED;
+ else if (state == 1)
+ mode = SCI_USB_CHARGE_ALTERNATE;
+ else if (state == 2)
+ mode = SCI_USB_CHARGE_AUTO;
+
+ ret = toshiba_usb_sleep_charge_set(toshiba, mode);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_sleep_charge);
+
+static ssize_t sleep_functions_on_battery_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 state;
+ int bat_lvl;
+ int status;
+ int ret;
+ int tmp;
+
+ ret = toshiba_sleep_functions_status_get(toshiba, &state);
+ if (ret < 0)
+ return ret;
+
+ /* Determine the status: 0x4 - Enabled | 0x1 - Disabled */
+ tmp = state & SCI_USB_CHARGE_BAT_MASK;
+ status = (tmp == 0x4) ? 1 : 0;
+ /* Determine the battery level set */
+ bat_lvl = state >> HCI_MISC_SHIFT;
+
+ return sprintf(buf, "%d %d\n", status, bat_lvl);
+}
+
+static ssize_t sleep_functions_on_battery_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 status;
+ int value;
+ int ret;
+ int tmp;
+
+ ret = kstrtoint(buf, 0, &value);
+ if (ret)
+ return ret;
+
+ /*
+ * Set the status of the function:
+ * 0 - Disabled
+ * 1-100 - Enabled
+ */
+ if (value < 0 || value > 100)
+ return -EINVAL;
+
+ if (value == 0) {
+ tmp = toshiba->usbsc_bat_level << HCI_MISC_SHIFT;
+ status = tmp | SCI_USB_CHARGE_BAT_LVL_OFF;
+ } else {
+ tmp = value << HCI_MISC_SHIFT;
+ status = tmp | SCI_USB_CHARGE_BAT_LVL_ON;
+ }
+ ret = toshiba_sleep_functions_status_set(toshiba, status);
+ if (ret < 0)
+ return ret;
+
+ toshiba->usbsc_bat_level = status >> HCI_MISC_SHIFT;
+
+ return count;
+}
+static DEVICE_ATTR_RW(sleep_functions_on_battery);
+
+static ssize_t usb_rapid_charge_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 state;
+ int ret;
+
+ ret = toshiba_usb_rapid_charge_get(toshiba, &state);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", state);
+}
+
+static ssize_t usb_rapid_charge_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ int state;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &state);
+ if (ret)
+ return ret;
+ if (state != 0 && state != 1)
+ return -EINVAL;
+
+ ret = toshiba_usb_rapid_charge_set(toshiba, state);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_rapid_charge);
+
+static ssize_t usb_sleep_music_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 state;
+ int ret;
+
+ ret = toshiba_usb_sleep_music_get(toshiba, &state);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", state);
+}
+
+static ssize_t usb_sleep_music_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ int state;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &state);
+ if (ret)
+ return ret;
+ if (state != 0 && state != 1)
+ return -EINVAL;
+
+ ret = toshiba_usb_sleep_music_set(toshiba, state);
+ if (ret)
+ return ret;
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_sleep_music);
+
+static ssize_t kbd_function_keys_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ int mode;
+ int ret;
+
+ ret = toshiba_function_keys_get(toshiba, &mode);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", mode);
+}
+
+static ssize_t kbd_function_keys_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ int mode;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &mode);
+ if (ret)
+ return ret;
+ /*
+ * Check for the function keys mode where:
+ * 0 - Normal operation (F{1-12} as usual and hotkeys via FN-F{1-12})
+ * 1 - Special functions (Opposite of the above setting)
+ */
+ if (mode != 0 && mode != 1)
+ return -EINVAL;
+
+ ret = toshiba_function_keys_set(toshiba, mode);
+ if (ret)
+ return ret;
+
+ pr_info("Reboot for changes to KBD Function Keys to take effect");
+
+ return count;
+}
+static DEVICE_ATTR_RW(kbd_function_keys);
+
+static ssize_t panel_power_on_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 state;
+ int ret;
+
+ ret = toshiba_panel_power_on_get(toshiba, &state);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", state);
+}
+
+static ssize_t panel_power_on_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ int state;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &state);
+ if (ret)
+ return ret;
+ if (state != 0 && state != 1)
+ return -EINVAL;
+
+ ret = toshiba_panel_power_on_set(toshiba, state);
+ if (ret)
+ return ret;
+
+ pr_info("Reboot for changes to Panel Power ON to take effect");
+
+ return count;
+}
+static DEVICE_ATTR_RW(panel_power_on);
+
+static ssize_t usb_three_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ u32 state;
+ int ret;
+
+ ret = toshiba_usb_three_get(toshiba, &state);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%d\n", state);
+}
+
+static ssize_t usb_three_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct toshiba_acpi_dev *toshiba = dev_get_drvdata(dev);
+ int state;
+ int ret;
+
+ ret = kstrtoint(buf, 0, &state);
+ if (ret)
+ return ret;
+ /*
+ * Check for USB 3 mode where:
+ * 0 - Disabled (Acts like a USB 2 port, saving power)
+ * 1 - Enabled
+ */
+ if (state != 0 && state != 1)
+ return -EINVAL;
+
+ ret = toshiba_usb_three_set(toshiba, state);
+ if (ret)
+ return ret;
+
+ pr_info("Reboot for changes to USB 3 to take effect");
+
+ return count;
+}
+static DEVICE_ATTR_RW(usb_three);
+
+static struct attribute *toshiba_attributes[] = {
+ &dev_attr_version.attr,
+ &dev_attr_fan.attr,
+ &dev_attr_kbd_backlight_mode.attr,
+ &dev_attr_kbd_type.attr,
+ &dev_attr_available_kbd_modes.attr,
+ &dev_attr_kbd_backlight_timeout.attr,
+ &dev_attr_touchpad.attr,
+ &dev_attr_position.attr,
+ &dev_attr_usb_sleep_charge.attr,
+ &dev_attr_sleep_functions_on_battery.attr,
+ &dev_attr_usb_rapid_charge.attr,
+ &dev_attr_usb_sleep_music.attr,
+ &dev_attr_kbd_function_keys.attr,
+ &dev_attr_panel_power_on.attr,
+ &dev_attr_usb_three.attr,
+ NULL,
+};
static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
struct attribute *attr, int idx)
@@ -1556,7 +2278,9 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
struct toshiba_acpi_dev *drv = dev_get_drvdata(dev);
bool exists = true;
- if (attr == &dev_attr_kbd_backlight_mode.attr)
+ if (attr == &dev_attr_fan.attr)
+ exists = (drv->fan_supported) ? true : false;
+ else if (attr == &dev_attr_kbd_backlight_mode.attr)
exists = (drv->kbd_illum_supported) ? true : false;
else if (attr == &dev_attr_kbd_backlight_timeout.attr)
exists = (drv->kbd_mode == SCI_KBD_MODE_AUTO) ? true : false;
@@ -1564,10 +2288,29 @@ static umode_t toshiba_sysfs_is_visible(struct kobject *kobj,
exists = (drv->touchpad_supported) ? true : false;
else if (attr == &dev_attr_position.attr)
exists = (drv->accelerometer_supported) ? true : false;
+ else if (attr == &dev_attr_usb_sleep_charge.attr)
+ exists = (drv->usb_sleep_charge_supported) ? true : false;
+ else if (attr == &dev_attr_sleep_functions_on_battery.attr)
+ exists = (drv->usb_sleep_charge_supported) ? true : false;
+ else if (attr == &dev_attr_usb_rapid_charge.attr)
+ exists = (drv->usb_rapid_charge_supported) ? true : false;
+ else if (attr == &dev_attr_usb_sleep_music.attr)
+ exists = (drv->usb_sleep_music_supported) ? true : false;
+ else if (attr == &dev_attr_kbd_function_keys.attr)
+ exists = (drv->kbd_function_keys_supported) ? true : false;
+ else if (attr == &dev_attr_panel_power_on.attr)
+ exists = (drv->panel_power_on_supported) ? true : false;
+ else if (attr == &dev_attr_usb_three.attr)
+ exists = (drv->usb_three_supported) ? true : false;
return exists ? attr->mode : 0;
}
+static struct attribute_group toshiba_attr_group = {
+ .is_visible = toshiba_sysfs_is_visible,
+ .attrs = toshiba_attributes,
+};
+
/*
* Hotkeys
*/
@@ -1644,7 +2387,7 @@ static void toshiba_acpi_report_hotkey(struct toshiba_acpi_dev *dev,
if (scancode == 0x100)
return;
- /* act on key press; ignore key release */
+ /* Act on key press; ignore key release */
if (scancode & 0x80)
return;
@@ -1680,7 +2423,7 @@ static void toshiba_acpi_process_hotkeys(struct toshiba_acpi_dev *dev)
hci_result =
hci_write1(dev, HCI_SYSTEM_EVENT, 1);
pr_notice("Re-enabled hotkeys\n");
- /* fall through */
+ /* Fall through */
default:
retries--;
break;
@@ -1802,7 +2545,7 @@ static int toshiba_acpi_setup_backlight(struct toshiba_acpi_dev *dev)
props.type = BACKLIGHT_PLATFORM;
props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
- /* adding an extra level and having 0 change to transflective mode */
+ /* Adding an extra level and having 0 change to transflective mode */
if (dev->tr_backlight_supported)
props.max_brightness++;
@@ -1973,6 +2716,24 @@ static int toshiba_acpi_add(struct acpi_device *acpi_dev)
ret = toshiba_accelerometer_supported(dev);
dev->accelerometer_supported = !ret;
+ ret = toshiba_usb_sleep_charge_get(dev, &dummy);
+ dev->usb_sleep_charge_supported = !ret;
+
+ ret = toshiba_usb_rapid_charge_get(dev, &dummy);
+ dev->usb_rapid_charge_supported = !ret;
+
+ ret = toshiba_usb_sleep_music_get(dev, &dummy);
+ dev->usb_sleep_music_supported = !ret;
+
+ ret = toshiba_function_keys_get(dev, &dummy);
+ dev->kbd_function_keys_supported = !ret;
+
+ ret = toshiba_panel_power_on_get(dev, &dummy);
+ dev->panel_power_on_supported = !ret;
+
+ ret = toshiba_usb_three_get(dev, &dummy);
+ dev->usb_three_supported = !ret;
+
/* Determine whether or not BIOS supports fan and video interfaces */
ret = get_video_status(dev, &dummy);
diff --git a/drivers/pnp/driver.c b/drivers/pnp/driver.c
index f748cc8cbb03..4e57d3370368 100644
--- a/drivers/pnp/driver.c
+++ b/drivers/pnp/driver.c
@@ -182,7 +182,7 @@ static int __pnp_bus_suspend(struct device *dev, pm_message_t state)
return error;
}
- if (pnp_dev->protocol->suspend)
+ if (pnp_can_suspend(pnp_dev))
pnp_dev->protocol->suspend(pnp_dev, state);
return 0;
}
diff --git a/drivers/pnp/pnpacpi/rsparser.c b/drivers/pnp/pnpacpi/rsparser.c
index 66977ebf13b3..ff0356fb378f 100644
--- a/drivers/pnp/pnpacpi/rsparser.c
+++ b/drivers/pnp/pnpacpi/rsparser.c
@@ -180,20 +180,21 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
struct pnp_dev *dev = data;
struct acpi_resource_dma *dma;
struct acpi_resource_vendor_typed *vendor_typed;
- struct resource r = {0};
+ struct resource_win win = {{0}, 0};
+ struct resource *r = &win.res;
int i, flags;
- if (acpi_dev_resource_address_space(res, &r)
- || acpi_dev_resource_ext_address_space(res, &r)) {
- pnp_add_resource(dev, &r);
+ if (acpi_dev_resource_address_space(res, &win)
+ || acpi_dev_resource_ext_address_space(res, &win)) {
+ pnp_add_resource(dev, &win.res);
return AE_OK;
}
- r.flags = 0;
- if (acpi_dev_resource_interrupt(res, 0, &r)) {
- pnpacpi_add_irqresource(dev, &r);
- for (i = 1; acpi_dev_resource_interrupt(res, i, &r); i++)
- pnpacpi_add_irqresource(dev, &r);
+ r->flags = 0;
+ if (acpi_dev_resource_interrupt(res, 0, r)) {
+ pnpacpi_add_irqresource(dev, r);
+ for (i = 1; acpi_dev_resource_interrupt(res, i, r); i++)
+ pnpacpi_add_irqresource(dev, r);
if (i > 1) {
/*
@@ -209,7 +210,7 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
}
}
return AE_OK;
- } else if (r.flags & IORESOURCE_DISABLED) {
+ } else if (r->flags & IORESOURCE_DISABLED) {
pnp_add_irq_resource(dev, 0, IORESOURCE_DISABLED);
return AE_OK;
}
@@ -218,13 +219,13 @@ static acpi_status pnpacpi_allocated_resource(struct acpi_resource *res,
case ACPI_RESOURCE_TYPE_MEMORY24:
case ACPI_RESOURCE_TYPE_MEMORY32:
case ACPI_RESOURCE_TYPE_FIXED_MEMORY32:
- if (acpi_dev_resource_memory(res, &r))
- pnp_add_resource(dev, &r);
+ if (acpi_dev_resource_memory(res, r))
+ pnp_add_resource(dev, r);
break;
case ACPI_RESOURCE_TYPE_IO:
case ACPI_RESOURCE_TYPE_FIXED_IO:
- if (acpi_dev_resource_io(res, &r))
- pnp_add_resource(dev, &r);
+ if (acpi_dev_resource_io(res, r))
+ pnp_add_resource(dev, r);
break;
case ACPI_RESOURCE_TYPE_DMA:
dma = &res->data.dma;
@@ -410,12 +411,12 @@ static __init void pnpacpi_parse_address_option(struct pnp_dev *dev,
if (p->resource_type == ACPI_MEMORY_RANGE) {
if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
flags = IORESOURCE_MEM_WRITEABLE;
- pnp_register_mem_resource(dev, option_flags, p->minimum,
- p->minimum, 0, p->address_length,
+ pnp_register_mem_resource(dev, option_flags, p->address.minimum,
+ p->address.minimum, 0, p->address.address_length,
flags);
} else if (p->resource_type == ACPI_IO_RANGE)
- pnp_register_port_resource(dev, option_flags, p->minimum,
- p->minimum, 0, p->address_length,
+ pnp_register_port_resource(dev, option_flags, p->address.minimum,
+ p->address.minimum, 0, p->address.address_length,
IORESOURCE_IO_FIXED);
}
@@ -429,12 +430,12 @@ static __init void pnpacpi_parse_ext_address_option(struct pnp_dev *dev,
if (p->resource_type == ACPI_MEMORY_RANGE) {
if (p->info.mem.write_protect == ACPI_READ_WRITE_MEMORY)
flags = IORESOURCE_MEM_WRITEABLE;
- pnp_register_mem_resource(dev, option_flags, p->minimum,
- p->minimum, 0, p->address_length,
+ pnp_register_mem_resource(dev, option_flags, p->address.minimum,
+ p->address.minimum, 0, p->address.address_length,
flags);
} else if (p->resource_type == ACPI_IO_RANGE)
- pnp_register_port_resource(dev, option_flags, p->minimum,
- p->minimum, 0, p->address_length,
+ pnp_register_port_resource(dev, option_flags, p->address.minimum,
+ p->address.minimum, 0, p->address.address_length,
IORESOURCE_IO_FIXED);
}
diff --git a/drivers/pnp/pnpbios/core.c b/drivers/pnp/pnpbios/core.c
index 074569e77d22..facd43b8516c 100644
--- a/drivers/pnp/pnpbios/core.c
+++ b/drivers/pnp/pnpbios/core.c
@@ -181,7 +181,8 @@ static int pnp_dock_thread(void *unused)
break;
default:
pnpbios_print_status("pnp_dock_thread", status);
- continue;
+ printk(KERN_WARNING "PnPBIOS: disabling dock monitoring.\n");
+ complete_and_exit(&unload_sem, 0);
}
if (d != docked) {
if (pnp_dock_event(d, &now) == 0) {
diff --git a/drivers/pnp/resource.c b/drivers/pnp/resource.c
index 782e82289571..f980ff7166e9 100644
--- a/drivers/pnp/resource.c
+++ b/drivers/pnp/resource.c
@@ -179,8 +179,9 @@ int pnp_check_port(struct pnp_dev *dev, struct resource *res)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if (!dev->active) {
- if (__check_region(&ioport_resource, *port, length(port, end)))
+ if (!request_region(*port, length(port, end), "pnp"))
return 0;
+ release_region(*port, length(port, end));
}
/* check if the resource is reserved */
@@ -241,8 +242,9 @@ int pnp_check_mem(struct pnp_dev *dev, struct resource *res)
/* check if the resource is already in use, skip if the
* device is active because it itself may be in use */
if (!dev->active) {
- if (check_mem_region(*addr, length(addr, end)))
+ if (!request_mem_region(*addr, length(addr, end), "pnp"))
return 0;
+ release_mem_region(*addr, length(addr, end));
}
/* check if the resource is reserved */
diff --git a/drivers/power/88pm860x_charger.c b/drivers/power/88pm860x_charger.c
index 650930e4fa79..734ec4afa14d 100644
--- a/drivers/power/88pm860x_charger.c
+++ b/drivers/power/88pm860x_charger.c
@@ -711,6 +711,7 @@ static int pm860x_charger_probe(struct platform_device *pdev)
return 0;
out_irq:
+ power_supply_unregister(&info->usb);
while (--i >= 0)
free_irq(info->irq[i], info);
out:
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
index 0108c2af005b..27b751b995fb 100644
--- a/drivers/power/Kconfig
+++ b/drivers/power/Kconfig
@@ -315,7 +315,7 @@ config CHARGER_GPIO
config CHARGER_MANAGER
bool "Battery charger manager for multiple chargers"
- depends on REGULATOR && RTC_CLASS
+ depends on REGULATOR
select EXTCON
help
Say Y to enable charger-manager support, which allows multiple
@@ -327,11 +327,16 @@ config CHARGER_MANAGER
config CHARGER_MAX14577
tristate "Maxim MAX14577/77836 battery charger driver"
depends on MFD_MAX14577
- depends on SYSFS
help
Say Y to enable support for the battery charger control sysfs and
platform data of MAX14577/77836 MUICs.
+config CHARGER_MAX77693
+ tristate "Maxim MAX77693 battery charger driver"
+ depends on MFD_MAX77693
+ help
+ Say Y to enable support for the Maxim MAX77693 battery charger.
+
config CHARGER_MAX8997
tristate "Maxim MAX8997/MAX8966 PMIC battery charger driver"
depends on MFD_MAX8997 && REGULATOR_MAX8997
@@ -383,6 +388,14 @@ config CHARGER_TPS65090
Say Y here to enable support for battery charging with TPS65090
PMIC chips.
+config BATTERY_GAUGE_LTC2941
+ tristate "LTC2941/LTC2943 Battery Gauge Driver"
+ depends on I2C
+ help
+ Say Y here to include support for LTC2941 and LTC2943 Battery
+ Gauge IC. The driver reports the charge count continuously, and
+ measures the voltage and temperature every 10 seconds.
+
config AB8500_BM
bool "AB8500 Battery Management Driver"
depends on AB8500_CORE && AB8500_GPADC
@@ -397,6 +410,14 @@ config BATTERY_GOLDFISH
Say Y to enable support for the battery and AC power in the
Goldfish emulator.
+config BATTERY_RT5033
+ tristate "RT5033 fuel gauge support"
+ depends on MFD_RT5033
+ help
+ This adds support for battery fuel gauge in Richtek RT5033 PMIC.
+ The fuelgauge calculates and determines the battery state of charge
+ according to battery open circuit voltage.
+
source "drivers/power/reset/Kconfig"
endif # POWER_SUPPLY
diff --git a/drivers/power/Makefile b/drivers/power/Makefile
index dfa894273926..36f9e0d10111 100644
--- a/drivers/power/Makefile
+++ b/drivers/power/Makefile
@@ -20,6 +20,7 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o
obj-$(CONFIG_BATTERY_DS2780) += ds2780_battery.o
obj-$(CONFIG_BATTERY_DS2781) += ds2781_battery.o
obj-$(CONFIG_BATTERY_DS2782) += ds2782_battery.o
+obj-$(CONFIG_BATTERY_GAUGE_LTC2941) += ltc2941-battery-gauge.o
obj-$(CONFIG_BATTERY_GOLDFISH) += goldfish_battery.o
obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o
obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o
@@ -34,6 +35,7 @@ obj-$(CONFIG_BATTERY_DA9052) += da9052-battery.o
obj-$(CONFIG_BATTERY_MAX17040) += max17040_battery.o
obj-$(CONFIG_BATTERY_MAX17042) += max17042_battery.o
obj-$(CONFIG_BATTERY_Z2) += z2_battery.o
+obj-$(CONFIG_BATTERY_RT5033) += rt5033_battery.o
obj-$(CONFIG_BATTERY_S3C_ADC) += s3c_adc_battery.o
obj-$(CONFIG_BATTERY_TWL4030_MADC) += twl4030_madc_battery.o
obj-$(CONFIG_CHARGER_88PM860X) += 88pm860x_charger.o
@@ -50,6 +52,7 @@ obj-$(CONFIG_CHARGER_LP8788) += lp8788-charger.o
obj-$(CONFIG_CHARGER_GPIO) += gpio-charger.o
obj-$(CONFIG_CHARGER_MANAGER) += charger-manager.o
obj-$(CONFIG_CHARGER_MAX14577) += max14577_charger.o
+obj-$(CONFIG_CHARGER_MAX77693) += max77693_charger.o
obj-$(CONFIG_CHARGER_MAX8997) += max8997_charger.o
obj-$(CONFIG_CHARGER_MAX8998) += max8998_charger.o
obj-$(CONFIG_CHARGER_BQ2415X) += bq2415x_charger.o
diff --git a/drivers/power/ab8500_fg.c b/drivers/power/ab8500_fg.c
index 69b80bcaa9e7..c908658aa31a 100644
--- a/drivers/power/ab8500_fg.c
+++ b/drivers/power/ab8500_fg.c
@@ -2435,20 +2435,6 @@ static void ab8500_fg_reinit_work(struct work_struct *work)
}
}
-/**
- * ab8500_fg_reinit() - forces FG algorithm to reinitialize with current values
- *
- * This function can be used to force the FG algorithm to recalculate a new
- * voltage based battery capacity.
- */
-void ab8500_fg_reinit(void)
-{
- struct ab8500_fg *di = ab8500_fg_get();
- /* User won't be notified if a null pointer returned. */
- if (di != NULL)
- queue_delayed_work(di->fg_wq, &di->fg_reinit_work, 0);
-}
-
/* Exposure to the sysfs interface */
struct ab8500_fg_sysfs_entry {
diff --git a/drivers/power/bq24190_charger.c b/drivers/power/bq24190_charger.c
index ad3ff8fbfbbb..d0e8236a6404 100644
--- a/drivers/power/bq24190_charger.c
+++ b/drivers/power/bq24190_charger.c
@@ -929,7 +929,7 @@ static void bq24190_charger_init(struct power_supply *charger)
charger->properties = bq24190_charger_properties;
charger->num_properties = ARRAY_SIZE(bq24190_charger_properties);
charger->supplied_to = bq24190_charger_supplied_to;
- charger->num_supplies = ARRAY_SIZE(bq24190_charger_supplied_to);
+ charger->num_supplicants = ARRAY_SIZE(bq24190_charger_supplied_to);
charger->get_property = bq24190_charger_get_property;
charger->set_property = bq24190_charger_set_property;
charger->property_is_writeable = bq24190_charger_property_is_writeable;
@@ -1208,7 +1208,7 @@ static irqreturn_t bq24190_irq_handler_thread(int irq, void *data)
{
struct bq24190_dev_info *bdi = data;
bool alert_userspace = false;
- u8 ss_reg, f_reg;
+ u8 ss_reg = 0, f_reg = 0;
int ret;
pm_runtime_get_sync(bdi->dev);
diff --git a/drivers/power/bq27x00_battery.c b/drivers/power/bq27x00_battery.c
index a78ac201828e..b72ba7c1bd69 100644
--- a/drivers/power/bq27x00_battery.c
+++ b/drivers/power/bq27x00_battery.c
@@ -76,7 +76,8 @@
/* bq27425 register addresses are same as bq27x00 addresses minus 4 */
#define BQ27425_REG_OFFSET 0x04
-#define BQ27425_REG_SOC 0x18 /* Register address plus offset */
+#define BQ27425_REG_SOC (0x1C + BQ27425_REG_OFFSET)
+#define BQ27425_REG_DCAP (0x3C + BQ27425_REG_OFFSET)
#define BQ27000_RS 20 /* Resistor sense */
#define BQ27x00_POWER_CONSTANT (256 * 29200 / 1000)
@@ -282,9 +283,12 @@ static int bq27x00_battery_read_ilmd(struct bq27x00_device_info *di)
{
int ilmd;
- if (bq27xxx_is_chip_version_higher(di))
- ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
- else
+ if (bq27xxx_is_chip_version_higher(di)) {
+ if (di->chip == BQ27425)
+ ilmd = bq27x00_read(di, BQ27425_REG_DCAP, false);
+ else
+ ilmd = bq27x00_read(di, BQ27500_REG_DCAP, false);
+ } else
ilmd = bq27x00_read(di, BQ27000_REG_ILMD, true);
if (ilmd < 0) {
@@ -493,10 +497,11 @@ static void bq27x00_update(struct bq27x00_device_info *di)
di->charge_design_full = bq27x00_battery_read_ilmd(di);
}
- if (memcmp(&di->cache, &cache, sizeof(cache)) != 0) {
- di->cache = cache;
+ if (di->cache.capacity != cache.capacity)
power_supply_changed(&di->bat);
- }
+
+ if (memcmp(&di->cache, &cache, sizeof(cache)) != 0)
+ di->cache = cache;
di->last_update = jiffies;
}
diff --git a/drivers/power/charger-manager.c b/drivers/power/charger-manager.c
index 649052e1f2d9..14b0d85318eb 100644
--- a/drivers/power/charger-manager.c
+++ b/drivers/power/charger-manager.c
@@ -69,16 +69,10 @@ static LIST_HEAD(cm_list);
static DEFINE_MUTEX(cm_list_mtx);
/* About in-suspend (suspend-again) monitoring */
-static struct rtc_device *rtc_dev;
-/*
- * Backup RTC alarm
- * Save the wakeup alarm before entering suspend-to-RAM
- */
-static struct rtc_wkalrm rtc_wkalarm_save;
-/* Backup RTC alarm time in terms of seconds since 01-01-1970 00:00:00 */
-static unsigned long rtc_wkalarm_save_time;
+static struct alarm *cm_timer;
+
static bool cm_suspended;
-static bool cm_rtc_set;
+static bool cm_timer_set;
static unsigned long cm_suspend_duration_ms;
/* About normal (not suspended) monitoring */
@@ -87,9 +81,6 @@ static unsigned long next_polling; /* Next appointed polling time */
static struct workqueue_struct *cm_wq; /* init at driver add */
static struct delayed_work cm_monitor_work; /* init at driver add */
-/* Global charger-manager description */
-static struct charger_global_desc *g_desc; /* init with setup_charger_manager */
-
/**
* is_batt_present - See if the battery presents in place.
* @cm: the Charger Manager representing the battery.
@@ -1047,10 +1038,13 @@ static bool cm_setup_timer(void)
{
struct charger_manager *cm;
unsigned int wakeup_ms = UINT_MAX;
- bool ret = false;
+ int timer_req = 0;
- mutex_lock(&cm_list_mtx);
+ if (time_after(next_polling, jiffies))
+ CM_MIN_VALID(wakeup_ms,
+ jiffies_to_msecs(next_polling - jiffies));
+ mutex_lock(&cm_list_mtx);
list_for_each_entry(cm, &cm_list, entry) {
unsigned int fbchk_ms = 0;
@@ -1070,162 +1064,38 @@ static bool cm_setup_timer(void)
/* Skip if polling is not required for this CM */
if (!is_polling_required(cm) && !cm->emergency_stop)
continue;
+ timer_req++;
if (cm->desc->polling_interval_ms == 0)
continue;
CM_MIN_VALID(wakeup_ms, cm->desc->polling_interval_ms);
}
-
mutex_unlock(&cm_list_mtx);
- if (wakeup_ms < UINT_MAX && wakeup_ms > 0) {
- pr_info("Charger Manager wakeup timer: %u ms\n", wakeup_ms);
- if (rtc_dev) {
- struct rtc_wkalrm tmp;
- unsigned long time, now;
- unsigned long add = DIV_ROUND_UP(wakeup_ms, 1000);
-
- /*
- * Set alarm with the polling interval (wakeup_ms)
- * except when rtc_wkalarm_save comes first.
- * However, the alarm time should be NOW +
- * CM_RTC_SMALL or later.
- */
- tmp.enabled = 1;
- rtc_read_time(rtc_dev, &tmp.time);
- rtc_tm_to_time(&tmp.time, &now);
- if (add < CM_RTC_SMALL)
- add = CM_RTC_SMALL;
- time = now + add;
+ if (timer_req && cm_timer) {
+ ktime_t now, add;
- ret = true;
+ /*
+ * Set alarm with the polling interval (wakeup_ms)
+ * The alarm time should be NOW + CM_RTC_SMALL or later.
+ */
+ if (wakeup_ms == UINT_MAX ||
+ wakeup_ms < CM_RTC_SMALL * MSEC_PER_SEC)
+ wakeup_ms = 2 * CM_RTC_SMALL * MSEC_PER_SEC;
- if (rtc_wkalarm_save.enabled &&
- rtc_wkalarm_save_time &&
- rtc_wkalarm_save_time < time) {
- if (rtc_wkalarm_save_time < now + CM_RTC_SMALL)
- time = now + CM_RTC_SMALL;
- else
- time = rtc_wkalarm_save_time;
+ pr_info("Charger Manager wakeup timer: %u ms\n", wakeup_ms);
- /* The timer is not appointed by CM */
- ret = false;
- }
+ now = ktime_get_boottime();
+ add = ktime_set(wakeup_ms / MSEC_PER_SEC,
+ (wakeup_ms % MSEC_PER_SEC) * NSEC_PER_MSEC);
+ alarm_start(cm_timer, ktime_add(now, add));
- pr_info("Waking up after %lu secs\n", time - now);
+ cm_suspend_duration_ms = wakeup_ms;
- rtc_time_to_tm(time, &tmp.time);
- rtc_set_alarm(rtc_dev, &tmp);
- cm_suspend_duration_ms += wakeup_ms;
- return ret;
- }
+ return true;
}
-
- if (rtc_dev)
- rtc_set_alarm(rtc_dev, &rtc_wkalarm_save);
return false;
}
-static void _cm_fbchk_in_suspend(struct charger_manager *cm)
-{
- unsigned long jiffy_now = jiffies;
-
- if (!cm->fullbatt_vchk_jiffies_at)
- return;
-
- if (g_desc && g_desc->assume_timer_stops_in_suspend)
- jiffy_now += msecs_to_jiffies(cm_suspend_duration_ms);
-
- /* Execute now if it's going to be executed not too long after */
- jiffy_now += CM_JIFFIES_SMALL;
-
- if (time_after_eq(jiffy_now, cm->fullbatt_vchk_jiffies_at))
- fullbatt_vchk(&cm->fullbatt_vchk_work.work);
-}
-
-/**
- * cm_suspend_again - Determine whether suspend again or not
- *
- * Returns true if the system should be suspended again
- * Returns false if the system should be woken up
- */
-bool cm_suspend_again(void)
-{
- struct charger_manager *cm;
- bool ret = false;
-
- if (!g_desc || !g_desc->rtc_only_wakeup || !g_desc->rtc_only_wakeup() ||
- !cm_rtc_set)
- return false;
-
- if (cm_monitor())
- goto out;
-
- ret = true;
- mutex_lock(&cm_list_mtx);
- list_for_each_entry(cm, &cm_list, entry) {
- _cm_fbchk_in_suspend(cm);
-
- if (cm->status_save_ext_pwr_inserted != is_ext_pwr_online(cm) ||
- cm->status_save_batt != is_batt_present(cm)) {
- ret = false;
- break;
- }
- }
- mutex_unlock(&cm_list_mtx);
-
- cm_rtc_set = cm_setup_timer();
-out:
- /* It's about the time when the non-CM appointed timer goes off */
- if (rtc_wkalarm_save.enabled) {
- unsigned long now;
- struct rtc_time tmp;
-
- rtc_read_time(rtc_dev, &tmp);
- rtc_tm_to_time(&tmp, &now);
-
- if (rtc_wkalarm_save_time &&
- now + CM_RTC_SMALL >= rtc_wkalarm_save_time)
- return false;
- }
- return ret;
-}
-EXPORT_SYMBOL_GPL(cm_suspend_again);
-
-/**
- * setup_charger_manager - initialize charger_global_desc data
- * @gd: pointer to instance of charger_global_desc
- */
-int setup_charger_manager(struct charger_global_desc *gd)
-{
- if (!gd)
- return -EINVAL;
-
- if (rtc_dev)
- rtc_class_close(rtc_dev);
- rtc_dev = NULL;
- g_desc = NULL;
-
- if (!gd->rtc_only_wakeup) {
- pr_err("The callback rtc_only_wakeup is not given\n");
- return -EINVAL;
- }
-
- if (gd->rtc_name) {
- rtc_dev = rtc_class_open(gd->rtc_name);
- if (IS_ERR_OR_NULL(rtc_dev)) {
- rtc_dev = NULL;
- /* Retry at probe. RTC may be not registered yet */
- }
- } else {
- pr_warn("No wakeup timer is given for charger manager. "
- "In-suspend monitoring won't work.\n");
- }
-
- g_desc = gd;
- return 0;
-}
-EXPORT_SYMBOL_GPL(setup_charger_manager);
-
/**
* charger_extcon_work - enable/diable charger according to the state
* of charger cable
@@ -1719,6 +1589,12 @@ static inline struct charger_desc *cm_get_drv_data(struct platform_device *pdev)
return dev_get_platdata(&pdev->dev);
}
+static enum alarmtimer_restart cm_timer_func(struct alarm *alarm, ktime_t now)
+{
+ cm_timer_set = false;
+ return ALARMTIMER_NORESTART;
+}
+
static int charger_manager_probe(struct platform_device *pdev)
{
struct charger_desc *desc = cm_get_drv_data(pdev);
@@ -1728,16 +1604,6 @@ static int charger_manager_probe(struct platform_device *pdev)
union power_supply_propval val;
struct power_supply *fuel_gauge;
- if (g_desc && !rtc_dev && g_desc->rtc_name) {
- rtc_dev = rtc_class_open(g_desc->rtc_name);
- if (IS_ERR_OR_NULL(rtc_dev)) {
- rtc_dev = NULL;
- dev_err(&pdev->dev, "Cannot get RTC %s\n",
- g_desc->rtc_name);
- return -ENODEV;
- }
- }
-
if (IS_ERR(desc)) {
dev_err(&pdev->dev, "No platform data (desc) found\n");
return -ENODEV;
@@ -1752,6 +1618,12 @@ static int charger_manager_probe(struct platform_device *pdev)
cm->dev = &pdev->dev;
cm->desc = desc;
+ /* Initialize alarm timer */
+ if (alarmtimer_get_rtcdev()) {
+ cm_timer = devm_kzalloc(cm->dev, sizeof(*cm_timer), GFP_KERNEL);
+ alarm_init(cm_timer, ALARM_BOOTTIME, cm_timer_func);
+ }
+
/*
* The following two do not need to be errors.
* Users may intentionally ignore those two features.
@@ -1993,38 +1865,41 @@ static int cm_suspend_noirq(struct device *dev)
return ret;
}
+static bool cm_need_to_awake(void)
+{
+ struct charger_manager *cm;
+
+ if (cm_timer)
+ return false;
+
+ mutex_lock(&cm_list_mtx);
+ list_for_each_entry(cm, &cm_list, entry) {
+ if (is_charging(cm)) {
+ mutex_unlock(&cm_list_mtx);
+ return true;
+ }
+ }
+ mutex_unlock(&cm_list_mtx);
+
+ return false;
+}
+
static int cm_suspend_prepare(struct device *dev)
{
struct charger_manager *cm = dev_get_drvdata(dev);
- if (!cm_suspended) {
- if (rtc_dev) {
- struct rtc_time tmp;
- unsigned long now;
-
- rtc_read_alarm(rtc_dev, &rtc_wkalarm_save);
- rtc_read_time(rtc_dev, &tmp);
+ if (cm_need_to_awake())
+ return -EBUSY;
- if (rtc_wkalarm_save.enabled) {
- rtc_tm_to_time(&rtc_wkalarm_save.time,
- &rtc_wkalarm_save_time);
- rtc_tm_to_time(&tmp, &now);
- if (now > rtc_wkalarm_save_time)
- rtc_wkalarm_save_time = 0;
- } else {
- rtc_wkalarm_save_time = 0;
- }
- }
+ if (!cm_suspended)
cm_suspended = true;
- }
- cancel_delayed_work(&cm->fullbatt_vchk_work);
- cm->status_save_ext_pwr_inserted = is_ext_pwr_online(cm);
- cm->status_save_batt = is_batt_present(cm);
+ cm_timer_set = cm_setup_timer();
- if (!cm_rtc_set) {
- cm_suspend_duration_ms = 0;
- cm_rtc_set = cm_setup_timer();
+ if (cm_timer_set) {
+ cancel_work_sync(&setup_polling);
+ cancel_delayed_work_sync(&cm_monitor_work);
+ cancel_delayed_work(&cm->fullbatt_vchk_work);
}
return 0;
@@ -2034,18 +1909,21 @@ static void cm_suspend_complete(struct device *dev)
{
struct charger_manager *cm = dev_get_drvdata(dev);
- if (cm_suspended) {
- if (rtc_dev) {
- struct rtc_wkalrm tmp;
-
- rtc_read_alarm(rtc_dev, &tmp);
- rtc_wkalarm_save.pending = tmp.pending;
- rtc_set_alarm(rtc_dev, &rtc_wkalarm_save);
- }
+ if (cm_suspended)
cm_suspended = false;
- cm_rtc_set = false;
+
+ if (cm_timer_set) {
+ ktime_t remain;
+
+ alarm_cancel(cm_timer);
+ cm_timer_set = false;
+ remain = alarm_expires_remaining(cm_timer);
+ cm_suspend_duration_ms -= ktime_to_ms(remain);
+ schedule_work(&setup_polling);
}
+ _cm_monitor(cm);
+
/* Re-enqueue delayed work (fullbatt_vchk_work) */
if (cm->fullbatt_vchk_jiffies_at) {
unsigned long delay = 0;
@@ -2060,21 +1938,18 @@ static void cm_suspend_complete(struct device *dev)
}
/*
- * Account for cm_suspend_duration_ms if
- * assume_timer_stops_in_suspend is active
+ * Account for cm_suspend_duration_ms with assuming that
+ * timer stops in suspend.
*/
- if (g_desc && g_desc->assume_timer_stops_in_suspend) {
- if (delay > cm_suspend_duration_ms)
- delay -= cm_suspend_duration_ms;
- else
- delay = 0;
- }
+ if (delay > cm_suspend_duration_ms)
+ delay -= cm_suspend_duration_ms;
+ else
+ delay = 0;
queue_delayed_work(cm_wq, &cm->fullbatt_vchk_work,
msecs_to_jiffies(delay));
}
device_set_wakeup_capable(cm->dev, false);
- uevent_notify(cm, NULL);
}
static const struct dev_pm_ops charger_manager_pm = {
diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
index d02ae02a7590..594e4dbc2d51 100644
--- a/drivers/power/collie_battery.c
+++ b/drivers/power/collie_battery.c
@@ -26,6 +26,7 @@
static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
static struct work_struct bat_work;
static struct ucb1x00 *ucb;
+static int wakeup_enabled;
struct collie_bat {
int status;
@@ -291,11 +292,21 @@ static int collie_bat_suspend(struct ucb1x00_dev *dev)
{
/* flush all pending status updates */
flush_work(&bat_work);
+
+ if (device_may_wakeup(&dev->ucb->dev) &&
+ collie_bat_main.status == POWER_SUPPLY_STATUS_CHARGING)
+ wakeup_enabled = !enable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO));
+ else
+ wakeup_enabled = 0;
+
return 0;
}
static int collie_bat_resume(struct ucb1x00_dev *dev)
{
+ if (wakeup_enabled)
+ disable_irq_wake(gpio_to_irq(COLLIE_GPIO_CO));
+
/* things may have changed while we were away */
schedule_work(&bat_work);
return 0;
@@ -334,10 +345,15 @@ static int collie_bat_probe(struct ucb1x00_dev *dev)
collie_bat_gpio_isr,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"main full", &collie_bat_main);
- if (!ret) {
- schedule_work(&bat_work);
- return 0;
- }
+ if (ret)
+ goto err_irq;
+
+ device_init_wakeup(&ucb->dev, 1);
+ schedule_work(&bat_work);
+
+ return 0;
+
+err_irq:
power_supply_unregister(&collie_bat_bu.psy);
err_psy_reg_bu:
power_supply_unregister(&collie_bat_main.psy);
diff --git a/drivers/power/gpio-charger.c b/drivers/power/gpio-charger.c
index aef74bdf7ab3..b7424c8501f1 100644
--- a/drivers/power/gpio-charger.c
+++ b/drivers/power/gpio-charger.c
@@ -229,7 +229,7 @@ static int gpio_charger_suspend(struct device *dev)
if (device_may_wakeup(dev))
gpio_charger->wakeup_enabled =
- enable_irq_wake(gpio_charger->irq);
+ !enable_irq_wake(gpio_charger->irq);
return 0;
}
@@ -239,7 +239,7 @@ static int gpio_charger_resume(struct device *dev)
struct platform_device *pdev = to_platform_device(dev);
struct gpio_charger *gpio_charger = platform_get_drvdata(pdev);
- if (gpio_charger->wakeup_enabled)
+ if (device_may_wakeup(dev) && gpio_charger->wakeup_enabled)
disable_irq_wake(gpio_charger->irq);
power_supply_changed(&gpio_charger->charger);
diff --git a/drivers/power/ltc2941-battery-gauge.c b/drivers/power/ltc2941-battery-gauge.c
new file mode 100644
index 000000000000..e31c927a6d16
--- /dev/null
+++ b/drivers/power/ltc2941-battery-gauge.c
@@ -0,0 +1,547 @@
+/*
+ * I2C client/driver for the Linear Technology LTC2941 and LTC2943
+ * Battery Gas Gauge IC
+ *
+ * Copyright (C) 2014 Topic Embedded Systems
+ *
+ * Author: Auryn Verwegen
+ * Author: Mike Looijmans
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/swab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/idr.h>
+#include <linux/power_supply.h>
+#include <linux/slab.h>
+
+#define I16_MSB(x) ((x >> 8) & 0xFF)
+#define I16_LSB(x) (x & 0xFF)
+
+#define LTC294X_WORK_DELAY 10 /* Update delay in seconds */
+
+#define LTC294X_MAX_VALUE 0xFFFF
+#define LTC294X_MID_SUPPLY 0x7FFF
+
+#define LTC2941_MAX_PRESCALER_EXP 7
+#define LTC2943_MAX_PRESCALER_EXP 6
+
+enum ltc294x_reg {
+ LTC294X_REG_STATUS = 0x00,
+ LTC294X_REG_CONTROL = 0x01,
+ LTC294X_REG_ACC_CHARGE_MSB = 0x02,
+ LTC294X_REG_ACC_CHARGE_LSB = 0x03,
+ LTC294X_REG_THRESH_HIGH_MSB = 0x04,
+ LTC294X_REG_THRESH_HIGH_LSB = 0x05,
+ LTC294X_REG_THRESH_LOW_MSB = 0x06,
+ LTC294X_REG_THRESH_LOW_LSB = 0x07,
+ LTC294X_REG_VOLTAGE_MSB = 0x08,
+ LTC294X_REG_VOLTAGE_LSB = 0x09,
+ LTC294X_REG_CURRENT_MSB = 0x0E,
+ LTC294X_REG_CURRENT_LSB = 0x0F,
+ LTC294X_REG_TEMPERATURE_MSB = 0x14,
+ LTC294X_REG_TEMPERATURE_LSB = 0x15,
+};
+
+#define LTC2943_REG_CONTROL_MODE_MASK (BIT(7) | BIT(6))
+#define LTC2943_REG_CONTROL_MODE_SCAN BIT(7)
+#define LTC294X_REG_CONTROL_PRESCALER_MASK (BIT(5) | BIT(4) | BIT(3))
+#define LTC294X_REG_CONTROL_SHUTDOWN_MASK (BIT(0))
+#define LTC294X_REG_CONTROL_PRESCALER_SET(x) \
+ ((x << 3) & LTC294X_REG_CONTROL_PRESCALER_MASK)
+#define LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED 0
+
+#define LTC2941_NUM_REGS 0x08
+#define LTC2943_NUM_REGS 0x18
+
+struct ltc294x_info {
+ struct i2c_client *client; /* I2C Client pointer */
+ struct power_supply supply; /* Supply pointer */
+ struct delayed_work work; /* Work scheduler */
+ int num_regs; /* Number of registers (chip type) */
+ int id; /* Identifier of ltc294x chip */
+ int charge; /* Last charge register content */
+ int r_sense; /* mOhm */
+ int Qlsb; /* nAh */
+};
+
+static DEFINE_IDR(ltc294x_id);
+static DEFINE_MUTEX(ltc294x_lock);
+
+static inline int convert_bin_to_uAh(
+ const struct ltc294x_info *info, int Q)
+{
+ return ((Q * (info->Qlsb / 10))) / 100;
+}
+
+static inline int convert_uAh_to_bin(
+ const struct ltc294x_info *info, int uAh)
+{
+ int Q;
+
+ Q = (uAh * 100) / (info->Qlsb/10);
+ return (Q < LTC294X_MAX_VALUE) ? Q : LTC294X_MAX_VALUE;
+}
+
+static int ltc294x_read_regs(struct i2c_client *client,
+ enum ltc294x_reg reg, u8 *buf, int num_regs)
+{
+ int ret;
+ struct i2c_msg msgs[2] = { };
+ u8 reg_start = reg;
+
+ msgs[0].addr = client->addr;
+ msgs[0].len = 1;
+ msgs[0].buf = &reg_start;
+
+ msgs[1].addr = client->addr;
+ msgs[1].len = num_regs;
+ msgs[1].buf = buf;
+ msgs[1].flags = I2C_M_RD;
+
+ ret = i2c_transfer(client->adapter, &msgs[0], 2);
+ if (ret < 0) {
+ dev_err(&client->dev, "ltc2941 read_reg failed!\n");
+ return ret;
+ }
+
+ dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
+ __func__, reg, num_regs, *buf);
+
+ return 0;
+}
+
+static int ltc294x_write_regs(struct i2c_client *client,
+ enum ltc294x_reg reg, const u8 *buf, int num_regs)
+{
+ int ret;
+ u8 reg_start = reg;
+
+ ret = i2c_smbus_write_i2c_block_data(client, reg_start, num_regs, buf);
+ if (ret < 0) {
+ dev_err(&client->dev, "ltc2941 write_reg failed!\n");
+ return ret;
+ }
+
+ dev_dbg(&client->dev, "%s (%#x, %d) -> %#x\n",
+ __func__, reg, num_regs, *buf);
+
+ return 0;
+}
+
+static int ltc294x_reset(const struct ltc294x_info *info, int prescaler_exp)
+{
+ int ret;
+ u8 value;
+ u8 control;
+
+ /* Read status and control registers */
+ ret = ltc294x_read_regs(info->client, LTC294X_REG_CONTROL, &value, 1);
+ if (ret < 0) {
+ dev_err(&info->client->dev,
+ "Could not read registers from device\n");
+ goto error_exit;
+ }
+
+ control = LTC294X_REG_CONTROL_PRESCALER_SET(prescaler_exp) |
+ LTC294X_REG_CONTROL_ALCC_CONFIG_DISABLED;
+ /* Put the 2943 into "monitor" mode, so it measures every 10 sec */
+ if (info->num_regs == LTC2943_NUM_REGS)
+ control |= LTC2943_REG_CONTROL_MODE_SCAN;
+
+ if (value != control) {
+ ret = ltc294x_write_regs(info->client,
+ LTC294X_REG_CONTROL, &control, 1);
+ if (ret < 0) {
+ dev_err(&info->client->dev,
+ "Could not write register\n");
+ goto error_exit;
+ }
+ }
+
+ return 0;
+
+error_exit:
+ return ret;
+}
+
+static int ltc294x_read_charge_register(const struct ltc294x_info *info)
+{
+ int ret;
+ u8 datar[2];
+
+ ret = ltc294x_read_regs(info->client,
+ LTC294X_REG_ACC_CHARGE_MSB, &datar[0], 2);
+ if (ret < 0)
+ return ret;
+ return (datar[0] << 8) + datar[1];
+}
+
+static int ltc294x_get_charge_now(const struct ltc294x_info *info, int *val)
+{
+ int value = ltc294x_read_charge_register(info);
+
+ if (value < 0)
+ return value;
+ /* When r_sense < 0, this counts up when the battery discharges */
+ if (info->Qlsb < 0)
+ value -= 0xFFFF;
+ *val = convert_bin_to_uAh(info, value);
+ return 0;
+}
+
+static int ltc294x_set_charge_now(const struct ltc294x_info *info, int val)
+{
+ int ret;
+ u8 dataw[2];
+ u8 ctrl_reg;
+ s32 value;
+
+ value = convert_uAh_to_bin(info, val);
+ /* Direction depends on how sense+/- were connected */
+ if (info->Qlsb < 0)
+ value += 0xFFFF;
+ if ((value < 0) || (value > 0xFFFF)) /* input validation */
+ return -EINVAL;
+
+ /* Read control register */
+ ret = ltc294x_read_regs(info->client,
+ LTC294X_REG_CONTROL, &ctrl_reg, 1);
+ if (ret < 0)
+ return ret;
+ /* Disable analog section */
+ ctrl_reg |= LTC294X_REG_CONTROL_SHUTDOWN_MASK;
+ ret = ltc294x_write_regs(info->client,
+ LTC294X_REG_CONTROL, &ctrl_reg, 1);
+ if (ret < 0)
+ return ret;
+ /* Set new charge value */
+ dataw[0] = I16_MSB(value);
+ dataw[1] = I16_LSB(value);
+ ret = ltc294x_write_regs(info->client,
+ LTC294X_REG_ACC_CHARGE_MSB, &dataw[0], 2);
+ if (ret < 0)
+ goto error_exit;
+ /* Enable analog section */
+error_exit:
+ ctrl_reg &= ~LTC294X_REG_CONTROL_SHUTDOWN_MASK;
+ ret = ltc294x_write_regs(info->client,
+ LTC294X_REG_CONTROL, &ctrl_reg, 1);
+
+ return ret < 0 ? ret : 0;
+}
+
+static int ltc294x_get_charge_counter(
+ const struct ltc294x_info *info, int *val)
+{
+ int value = ltc294x_read_charge_register(info);
+
+ if (value < 0)
+ return value;
+ value -= LTC294X_MID_SUPPLY;
+ *val = convert_bin_to_uAh(info, value);
+ return 0;
+}
+
+static int ltc294x_get_voltage(const struct ltc294x_info *info, int *val)
+{
+ int ret;
+ u8 datar[2];
+ u32 value;
+
+ ret = ltc294x_read_regs(info->client,
+ LTC294X_REG_VOLTAGE_MSB, &datar[0], 2);
+ value = (datar[0] << 8) | datar[1];
+ *val = ((value * 23600) / 0xFFFF) * 1000; /* in uV */
+ return ret;
+}
+
+static int ltc294x_get_current(const struct ltc294x_info *info, int *val)
+{
+ int ret;
+ u8 datar[2];
+ s32 value;
+
+ ret = ltc294x_read_regs(info->client,
+ LTC294X_REG_CURRENT_MSB, &datar[0], 2);
+ value = (datar[0] << 8) | datar[1];
+ value -= 0x7FFF;
+ /* Value is in range -32k..+32k, r_sense is usually 10..50 mOhm,
+ * the formula below keeps everything in s32 range while preserving
+ * enough digits */
+ *val = 1000 * ((60000 * value) / (info->r_sense * 0x7FFF)); /* in uA */
+ return ret;
+}
+
+static int ltc294x_get_temperature(const struct ltc294x_info *info, int *val)
+{
+ int ret;
+ u8 datar[2];
+ u32 value;
+
+ ret = ltc294x_read_regs(info->client,
+ LTC294X_REG_TEMPERATURE_MSB, &datar[0], 2);
+ value = (datar[0] << 8) | datar[1];
+ /* Full-scale is 510 Kelvin, convert to centidegrees */
+ *val = (((51000 * value) / 0xFFFF) - 27215);
+ return ret;
+}
+
+static int ltc294x_get_property(struct power_supply *psy,
+ enum power_supply_property prop,
+ union power_supply_propval *val)
+{
+ struct ltc294x_info *info =
+ container_of(psy, struct ltc294x_info, supply);
+
+ switch (prop) {
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ return ltc294x_get_charge_now(info, &val->intval);
+ case POWER_SUPPLY_PROP_CHARGE_COUNTER:
+ return ltc294x_get_charge_counter(info, &val->intval);
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ return ltc294x_get_voltage(info, &val->intval);
+ case POWER_SUPPLY_PROP_CURRENT_NOW:
+ return ltc294x_get_current(info, &val->intval);
+ case POWER_SUPPLY_PROP_TEMP:
+ return ltc294x_get_temperature(info, &val->intval);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int ltc294x_set_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ const union power_supply_propval *val)
+{
+ struct ltc294x_info *info =
+ container_of(psy, struct ltc294x_info, supply);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ return ltc294x_set_charge_now(info, val->intval);
+ default:
+ return -EPERM;
+ }
+}
+
+static int ltc294x_property_is_writeable(
+ struct power_supply *psy, enum power_supply_property psp)
+{
+ switch (psp) {
+ case POWER_SUPPLY_PROP_CHARGE_NOW:
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+static void ltc294x_update(struct ltc294x_info *info)
+{
+ int charge = ltc294x_read_charge_register(info);
+
+ if (charge != info->charge) {
+ info->charge = charge;
+ power_supply_changed(&info->supply);
+ }
+}
+
+static void ltc294x_work(struct work_struct *work)
+{
+ struct ltc294x_info *info;
+
+ info = container_of(work, struct ltc294x_info, work.work);
+ ltc294x_update(info);
+ schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
+}
+
+static enum power_supply_property ltc294x_properties[] = {
+ POWER_SUPPLY_PROP_CHARGE_COUNTER,
+ POWER_SUPPLY_PROP_CHARGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_CURRENT_NOW,
+ POWER_SUPPLY_PROP_TEMP,
+};
+
+static int ltc294x_i2c_remove(struct i2c_client *client)
+{
+ struct ltc294x_info *info = i2c_get_clientdata(client);
+
+ cancel_delayed_work(&info->work);
+ power_supply_unregister(&info->supply);
+ kfree(info->supply.name);
+ mutex_lock(&ltc294x_lock);
+ idr_remove(&ltc294x_id, info->id);
+ mutex_unlock(&ltc294x_lock);
+ return 0;
+}
+
+static int ltc294x_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct ltc294x_info *info;
+ int ret;
+ int num;
+ u32 prescaler_exp;
+ s32 r_sense;
+ struct device_node *np;
+
+ mutex_lock(&ltc294x_lock);
+ ret = idr_alloc(&ltc294x_id, client, 0, 0, GFP_KERNEL);
+ mutex_unlock(&ltc294x_lock);
+ if (ret < 0)
+ goto fail_id;
+
+ num = ret;
+
+ info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
+ if (info == NULL) {
+ ret = -ENOMEM;
+ goto fail_info;
+ }
+
+ i2c_set_clientdata(client, info);
+
+ info->num_regs = id->driver_data;
+ info->supply.name = kasprintf(GFP_KERNEL, "%s-%d", client->name, num);
+ if (!info->supply.name) {
+ ret = -ENOMEM;
+ goto fail_name;
+ }
+
+ np = of_node_get(client->dev.of_node);
+
+ /* r_sense can be negative, when sense+ is connected to the battery
+ * instead of the sense-. This results in reversed measurements. */
+ ret = of_property_read_u32(np, "lltc,resistor-sense", &r_sense);
+ if (ret < 0) {
+ dev_err(&client->dev,
+ "Could not find lltc,resistor-sense in devicetree\n");
+ goto fail_name;
+ }
+ info->r_sense = r_sense;
+
+ ret = of_property_read_u32(np, "lltc,prescaler-exponent",
+ &prescaler_exp);
+ if (ret < 0) {
+ dev_warn(&client->dev,
+ "lltc,prescaler-exponent not in devicetree\n");
+ prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
+ }
+
+ if (info->num_regs == LTC2943_NUM_REGS) {
+ if (prescaler_exp > LTC2943_MAX_PRESCALER_EXP)
+ prescaler_exp = LTC2943_MAX_PRESCALER_EXP;
+ info->Qlsb = ((340 * 50000) / r_sense) /
+ (4096 / (1 << (2*prescaler_exp)));
+ } else {
+ if (prescaler_exp > LTC2941_MAX_PRESCALER_EXP)
+ prescaler_exp = LTC2941_MAX_PRESCALER_EXP;
+ info->Qlsb = ((58 * 50000) / r_sense) /
+ (128 / (1 << prescaler_exp));
+ }
+
+ info->client = client;
+ info->id = num;
+ info->supply.type = POWER_SUPPLY_TYPE_BATTERY;
+ info->supply.properties = ltc294x_properties;
+ if (info->num_regs >= LTC294X_REG_TEMPERATURE_LSB)
+ info->supply.num_properties =
+ ARRAY_SIZE(ltc294x_properties);
+ else if (info->num_regs >= LTC294X_REG_CURRENT_LSB)
+ info->supply.num_properties =
+ ARRAY_SIZE(ltc294x_properties) - 1;
+ else if (info->num_regs >= LTC294X_REG_VOLTAGE_LSB)
+ info->supply.num_properties =
+ ARRAY_SIZE(ltc294x_properties) - 2;
+ else
+ info->supply.num_properties =
+ ARRAY_SIZE(ltc294x_properties) - 3;
+ info->supply.get_property = ltc294x_get_property;
+ info->supply.set_property = ltc294x_set_property;
+ info->supply.property_is_writeable = ltc294x_property_is_writeable;
+ info->supply.external_power_changed = NULL;
+
+ INIT_DELAYED_WORK(&info->work, ltc294x_work);
+
+ ret = ltc294x_reset(info, prescaler_exp);
+ if (ret < 0) {
+ dev_err(&client->dev, "Communication with chip failed\n");
+ goto fail_comm;
+ }
+
+ ret = power_supply_register(&client->dev, &info->supply);
+ if (ret) {
+ dev_err(&client->dev, "failed to register ltc2941\n");
+ goto fail_register;
+ } else {
+ schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
+ }
+
+ return 0;
+
+fail_register:
+ kfree(info->supply.name);
+fail_comm:
+fail_name:
+fail_info:
+ mutex_lock(&ltc294x_lock);
+ idr_remove(&ltc294x_id, num);
+ mutex_unlock(&ltc294x_lock);
+fail_id:
+ return ret;
+}
+
+#ifdef CONFIG_PM_SLEEP
+
+static int ltc294x_suspend(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc294x_info *info = i2c_get_clientdata(client);
+
+ cancel_delayed_work(&info->work);
+ return 0;
+}
+
+static int ltc294x_resume(struct device *dev)
+{
+ struct i2c_client *client = to_i2c_client(dev);
+ struct ltc294x_info *info = i2c_get_clientdata(client);
+
+ schedule_delayed_work(&info->work, LTC294X_WORK_DELAY * HZ);
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ltc294x_pm_ops, ltc294x_suspend, ltc294x_resume);
+#define LTC294X_PM_OPS (&ltc294x_pm_ops)
+
+#else
+#define LTC294X_PM_OPS NULL
+#endif /* CONFIG_PM_SLEEP */
+
+
+static const struct i2c_device_id ltc294x_i2c_id[] = {
+ {"ltc2941", LTC2941_NUM_REGS},
+ {"ltc2943", LTC2943_NUM_REGS},
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, ltc294x_i2c_id);
+
+static struct i2c_driver ltc294x_driver = {
+ .driver = {
+ .name = "LTC2941",
+ .pm = LTC294X_PM_OPS,
+ },
+ .probe = ltc294x_i2c_probe,
+ .remove = ltc294x_i2c_remove,
+ .id_table = ltc294x_i2c_id,
+};
+module_i2c_driver(ltc294x_driver);
+
+MODULE_AUTHOR("Auryn Verwegen, Topic Embedded Systems");
+MODULE_AUTHOR("Mike Looijmans, Topic Embedded Products");
+MODULE_DESCRIPTION("LTC2941/LTC2943 Battery Gas Gauge IC driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/max17042_battery.c b/drivers/power/max17042_battery.c
index 66da691c41cf..1da6c5fbdff5 100644
--- a/drivers/power/max17042_battery.c
+++ b/drivers/power/max17042_battery.c
@@ -658,7 +658,7 @@ max17042_get_pdata(struct device *dev)
}
#endif
-static struct regmap_config max17042_regmap_config = {
+static const struct regmap_config max17042_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
.val_format_endian = REGMAP_ENDIAN_NATIVE,
diff --git a/drivers/power/max77693_charger.c b/drivers/power/max77693_charger.c
new file mode 100644
index 000000000000..b042970fdeaf
--- /dev/null
+++ b/drivers/power/max77693_charger.c
@@ -0,0 +1,753 @@
+/*
+ * max77693_charger.c - Battery charger driver for the Maxim 77693
+ *
+ * Copyright (C) 2014 Samsung Electronics
+ * Krzysztof Kozlowski <k.kozlowski@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.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/power_supply.h>
+#include <linux/regmap.h>
+#include <linux/mfd/max77693.h>
+#include <linux/mfd/max77693-private.h>
+
+static const char *max77693_charger_name = "max77693-charger";
+static const char *max77693_charger_model = "MAX77693";
+static const char *max77693_charger_manufacturer = "Maxim Integrated";
+
+struct max77693_charger {
+ struct device *dev;
+ struct max77693_dev *max77693;
+ struct power_supply charger;
+
+ u32 constant_volt;
+ u32 min_system_volt;
+ u32 thermal_regulation_temp;
+ u32 batttery_overcurrent;
+ u32 charge_input_threshold_volt;
+};
+
+static int max77693_get_charger_state(struct regmap *regmap)
+{
+ int state;
+ unsigned int data;
+
+ if (regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data) < 0)
+ return POWER_SUPPLY_STATUS_UNKNOWN;
+
+ data &= CHG_DETAILS_01_CHG_MASK;
+ data >>= CHG_DETAILS_01_CHG_SHIFT;
+
+ switch (data) {
+ case MAX77693_CHARGING_PREQUALIFICATION:
+ case MAX77693_CHARGING_FAST_CONST_CURRENT:
+ case MAX77693_CHARGING_FAST_CONST_VOLTAGE:
+ case MAX77693_CHARGING_TOP_OFF:
+ /* In high temp the charging current is reduced, but still charging */
+ case MAX77693_CHARGING_HIGH_TEMP:
+ state = POWER_SUPPLY_STATUS_CHARGING;
+ break;
+ case MAX77693_CHARGING_DONE:
+ state = POWER_SUPPLY_STATUS_FULL;
+ break;
+ case MAX77693_CHARGING_TIMER_EXPIRED:
+ case MAX77693_CHARGING_THERMISTOR_SUSPEND:
+ state = POWER_SUPPLY_STATUS_NOT_CHARGING;
+ break;
+ case MAX77693_CHARGING_OFF:
+ case MAX77693_CHARGING_OVER_TEMP:
+ case MAX77693_CHARGING_WATCHDOG_EXPIRED:
+ state = POWER_SUPPLY_STATUS_DISCHARGING;
+ break;
+ case MAX77693_CHARGING_RESERVED:
+ default:
+ state = POWER_SUPPLY_STATUS_UNKNOWN;
+ }
+
+ return state;
+}
+
+static int max77693_get_charge_type(struct regmap *regmap)
+{
+ int state;
+ unsigned int data;
+
+ if (regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data) < 0)
+ return POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+
+ data &= CHG_DETAILS_01_CHG_MASK;
+ data >>= CHG_DETAILS_01_CHG_SHIFT;
+
+ switch (data) {
+ case MAX77693_CHARGING_PREQUALIFICATION:
+ /*
+ * Top-off: trickle or fast? In top-off the current varies between
+ * 100 and 250 mA. It is higher than prequalification current.
+ */
+ case MAX77693_CHARGING_TOP_OFF:
+ state = POWER_SUPPLY_CHARGE_TYPE_TRICKLE;
+ break;
+ case MAX77693_CHARGING_FAST_CONST_CURRENT:
+ case MAX77693_CHARGING_FAST_CONST_VOLTAGE:
+ /* In high temp the charging current is reduced, but still charging */
+ case MAX77693_CHARGING_HIGH_TEMP:
+ state = POWER_SUPPLY_CHARGE_TYPE_FAST;
+ break;
+ case MAX77693_CHARGING_DONE:
+ case MAX77693_CHARGING_TIMER_EXPIRED:
+ case MAX77693_CHARGING_THERMISTOR_SUSPEND:
+ case MAX77693_CHARGING_OFF:
+ case MAX77693_CHARGING_OVER_TEMP:
+ case MAX77693_CHARGING_WATCHDOG_EXPIRED:
+ state = POWER_SUPPLY_CHARGE_TYPE_NONE;
+ break;
+ case MAX77693_CHARGING_RESERVED:
+ default:
+ state = POWER_SUPPLY_CHARGE_TYPE_UNKNOWN;
+ }
+
+ return state;
+}
+
+/*
+ * Supported health statuses:
+ * - POWER_SUPPLY_HEALTH_DEAD
+ * - POWER_SUPPLY_HEALTH_GOOD
+ * - POWER_SUPPLY_HEALTH_OVERVOLTAGE
+ * - POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE
+ * - POWER_SUPPLY_HEALTH_UNKNOWN
+ * - POWER_SUPPLY_HEALTH_UNSPEC_FAILURE
+ */
+static int max77693_get_battery_health(struct regmap *regmap)
+{
+ int state;
+ unsigned int data;
+
+ if (regmap_read(regmap, MAX77693_CHG_REG_CHG_DETAILS_01, &data) < 0)
+ return POWER_SUPPLY_HEALTH_UNKNOWN;
+
+ data &= CHG_DETAILS_01_BAT_MASK;
+ data >>= CHG_DETAILS_01_BAT_SHIFT;
+
+ switch (data) {
+ case MAX77693_BATTERY_NOBAT:
+ state = POWER_SUPPLY_HEALTH_DEAD;
+ break;
+ case MAX77693_BATTERY_PREQUALIFICATION:
+ case MAX77693_BATTERY_GOOD:
+ case MAX77693_BATTERY_LOWVOLTAGE:
+ state = POWER_SUPPLY_HEALTH_GOOD;
+ break;
+ case MAX77693_BATTERY_TIMER_EXPIRED:
+ /*
+ * Took longer to charge than expected, charging suspended.
+ * Damaged battery?
+ */
+ state = POWER_SUPPLY_HEALTH_SAFETY_TIMER_EXPIRE;
+ break;
+ case MAX77693_BATTERY_OVERVOLTAGE:
+ state = POWER_SUPPLY_HEALTH_OVERVOLTAGE;
+ break;
+ case MAX77693_BATTERY_OVERCURRENT:
+ state = POWER_SUPPLY_HEALTH_UNSPEC_FAILURE;
+ break;
+ case MAX77693_BATTERY_RESERVED:
+ default:
+ state = POWER_SUPPLY_HEALTH_UNKNOWN;
+ break;
+ }
+
+ return state;
+}
+
+static int max77693_get_present(struct regmap *regmap)
+{
+ unsigned int data;
+
+ /*
+ * Read CHG_INT_OK register. High DETBAT bit here should be
+ * equal to value 0x0 in CHG_DETAILS_01/BAT field.
+ */
+ regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data);
+ if (data & CHG_INT_OK_DETBAT_MASK)
+ return 0;
+ return 1;
+}
+
+static int max77693_get_online(struct regmap *regmap)
+{
+ unsigned int data;
+
+ regmap_read(regmap, MAX77693_CHG_REG_CHG_INT_OK, &data);
+ if (data & CHG_INT_OK_CHGIN_MASK)
+ return 1;
+ return 0;
+}
+
+static enum power_supply_property max77693_charger_props[] = {
+ POWER_SUPPLY_PROP_STATUS,
+ POWER_SUPPLY_PROP_CHARGE_TYPE,
+ POWER_SUPPLY_PROP_HEALTH,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_ONLINE,
+ POWER_SUPPLY_PROP_MODEL_NAME,
+ POWER_SUPPLY_PROP_MANUFACTURER,
+};
+
+static int max77693_charger_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct max77693_charger *chg = container_of(psy,
+ struct max77693_charger,
+ charger);
+ struct regmap *regmap = chg->max77693->regmap;
+ int ret = 0;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_STATUS:
+ val->intval = max77693_get_charger_state(regmap);
+ break;
+ case POWER_SUPPLY_PROP_CHARGE_TYPE:
+ val->intval = max77693_get_charge_type(regmap);
+ break;
+ case POWER_SUPPLY_PROP_HEALTH:
+ val->intval = max77693_get_battery_health(regmap);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = max77693_get_present(regmap);
+ break;
+ case POWER_SUPPLY_PROP_ONLINE:
+ val->intval = max77693_get_online(regmap);
+ break;
+ case POWER_SUPPLY_PROP_MODEL_NAME:
+ val->strval = max77693_charger_model;
+ break;
+ case POWER_SUPPLY_PROP_MANUFACTURER:
+ val->strval = max77693_charger_manufacturer;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static ssize_t device_attr_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count,
+ int (*fn)(struct max77693_charger *, unsigned long))
+{
+ struct max77693_charger *chg = dev_get_drvdata(dev);
+ unsigned long val;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &val);
+ if (ret)
+ return ret;
+
+ ret = fn(chg, val);
+ if (ret)
+ return ret;
+
+ return count;
+}
+
+static ssize_t fast_charge_timer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct max77693_charger *chg = dev_get_drvdata(dev);
+ unsigned int data, val;
+ int ret;
+
+ ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_01,
+ &data);
+ if (ret < 0)
+ return ret;
+
+ data &= CHG_CNFG_01_FCHGTIME_MASK;
+ data >>= CHG_CNFG_01_FCHGTIME_SHIFT;
+ switch (data) {
+ case 0x1 ... 0x7:
+ /* Starting from 4 hours, step by 2 hours */
+ val = 4 + (data - 1) * 2;
+ break;
+ case 0x0:
+ default:
+ val = 0;
+ break;
+ }
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static int max77693_set_fast_charge_timer(struct max77693_charger *chg,
+ unsigned long hours)
+{
+ unsigned int data;
+
+ /*
+ * 0x00 - disable
+ * 0x01 - 4h
+ * 0x02 - 6h
+ * ...
+ * 0x07 - 16h
+ * Round down odd values.
+ */
+ switch (hours) {
+ case 4 ... 16:
+ data = (hours - 4) / 2 + 1;
+ break;
+ case 0:
+ /* Disable */
+ data = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ data <<= CHG_CNFG_01_FCHGTIME_SHIFT;
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_01,
+ CHG_CNFG_01_FCHGTIME_MASK, data);
+}
+
+static ssize_t fast_charge_timer_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return device_attr_store(dev, attr, buf, count,
+ max77693_set_fast_charge_timer);
+}
+
+static ssize_t top_off_threshold_current_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct max77693_charger *chg = dev_get_drvdata(dev);
+ unsigned int data, val;
+ int ret;
+
+ ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03,
+ &data);
+ if (ret < 0)
+ return ret;
+
+ data &= CHG_CNFG_03_TOITH_MASK;
+ data >>= CHG_CNFG_03_TOITH_SHIFT;
+
+ if (data <= 0x04)
+ val = 100000 + data * 25000;
+ else
+ val = data * 50000;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static int max77693_set_top_off_threshold_current(struct max77693_charger *chg,
+ unsigned long uamp)
+{
+ unsigned int data;
+
+ if (uamp < 100000 || uamp > 350000)
+ return -EINVAL;
+
+ if (uamp <= 200000)
+ data = (uamp - 100000) / 25000;
+ else
+ /* (200000, 350000> */
+ data = uamp / 50000;
+
+ data <<= CHG_CNFG_03_TOITH_SHIFT;
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_03,
+ CHG_CNFG_03_TOITH_MASK, data);
+}
+
+static ssize_t top_off_threshold_current_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return device_attr_store(dev, attr, buf, count,
+ max77693_set_top_off_threshold_current);
+}
+
+static ssize_t top_off_timer_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct max77693_charger *chg = dev_get_drvdata(dev);
+ unsigned int data, val;
+ int ret;
+
+ ret = regmap_read(chg->max77693->regmap, MAX77693_CHG_REG_CHG_CNFG_03,
+ &data);
+ if (ret < 0)
+ return ret;
+
+ data &= CHG_CNFG_03_TOTIME_MASK;
+ data >>= CHG_CNFG_03_TOTIME_SHIFT;
+
+ val = data * 10;
+
+ return scnprintf(buf, PAGE_SIZE, "%u\n", val);
+}
+
+static int max77693_set_top_off_timer(struct max77693_charger *chg,
+ unsigned long minutes)
+{
+ unsigned int data;
+
+ if (minutes > 70)
+ return -EINVAL;
+
+ data = minutes / 10;
+ data <<= CHG_CNFG_03_TOTIME_SHIFT;
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_03,
+ CHG_CNFG_03_TOTIME_MASK, data);
+}
+
+static ssize_t top_off_timer_store(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t count)
+{
+ return device_attr_store(dev, attr, buf, count,
+ max77693_set_top_off_timer);
+}
+
+static DEVICE_ATTR_RW(fast_charge_timer);
+static DEVICE_ATTR_RW(top_off_threshold_current);
+static DEVICE_ATTR_RW(top_off_timer);
+
+static int max77693_set_constant_volt(struct max77693_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ /*
+ * 0x00 - 3.650 V
+ * 0x01 - 3.675 V
+ * ...
+ * 0x1b - 4.325 V
+ * 0x1c - 4.340 V
+ * 0x1d - 4.350 V
+ * 0x1e - 4.375 V
+ * 0x1f - 4.400 V
+ */
+ if (uvolt >= 3650000 && uvolt < 4340000)
+ data = (uvolt - 3650000) / 25000;
+ else if (uvolt >= 4340000 && uvolt < 4350000)
+ data = 0x1c;
+ else if (uvolt >= 4350000 && uvolt <= 4400000)
+ data = 0x1d + (uvolt - 4350000) / 25000;
+ else {
+ dev_err(chg->dev, "Wrong value for charging constant voltage\n");
+ return -EINVAL;
+ }
+
+ data <<= CHG_CNFG_04_CHGCVPRM_SHIFT;
+
+ dev_dbg(chg->dev, "Charging constant voltage: %u (0x%x)\n", uvolt,
+ data);
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_04,
+ CHG_CNFG_04_CHGCVPRM_MASK, data);
+}
+
+static int max77693_set_min_system_volt(struct max77693_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ if (uvolt < 3000000 || uvolt > 3700000) {
+ dev_err(chg->dev, "Wrong value for minimum system regulation voltage\n");
+ return -EINVAL;
+ }
+
+ data = (uvolt - 3000000) / 100000;
+
+ data <<= CHG_CNFG_04_MINVSYS_SHIFT;
+
+ dev_dbg(chg->dev, "Minimum system regulation voltage: %u (0x%x)\n",
+ uvolt, data);
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_04,
+ CHG_CNFG_04_MINVSYS_MASK, data);
+}
+
+static int max77693_set_thermal_regulation_temp(struct max77693_charger *chg,
+ unsigned int cels)
+{
+ unsigned int data;
+
+ switch (cels) {
+ case 70:
+ case 85:
+ case 100:
+ case 115:
+ data = (cels - 70) / 15;
+ break;
+ default:
+ dev_err(chg->dev, "Wrong value for thermal regulation loop temperature\n");
+ return -EINVAL;
+ }
+
+ data <<= CHG_CNFG_07_REGTEMP_SHIFT;
+
+ dev_dbg(chg->dev, "Thermal regulation loop temperature: %u (0x%x)\n",
+ cels, data);
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_07,
+ CHG_CNFG_07_REGTEMP_MASK, data);
+}
+
+static int max77693_set_batttery_overcurrent(struct max77693_charger *chg,
+ unsigned int uamp)
+{
+ unsigned int data;
+
+ if (uamp && (uamp < 2000000 || uamp > 3500000)) {
+ dev_err(chg->dev, "Wrong value for battery overcurrent\n");
+ return -EINVAL;
+ }
+
+ if (uamp)
+ data = ((uamp - 2000000) / 250000) + 1;
+ else
+ data = 0; /* disable */
+
+ data <<= CHG_CNFG_12_B2SOVRC_SHIFT;
+
+ dev_dbg(chg->dev, "Battery overcurrent: %u (0x%x)\n", uamp, data);
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_12,
+ CHG_CNFG_12_B2SOVRC_MASK, data);
+}
+
+static int max77693_set_charge_input_threshold_volt(struct max77693_charger *chg,
+ unsigned int uvolt)
+{
+ unsigned int data;
+
+ switch (uvolt) {
+ case 4300000:
+ data = 0x0;
+ break;
+ case 4700000:
+ case 4800000:
+ case 4900000:
+ data = (uvolt - 4700000) / 100000;
+ default:
+ dev_err(chg->dev, "Wrong value for charge input voltage regulation threshold\n");
+ return -EINVAL;
+ }
+
+ data <<= CHG_CNFG_12_VCHGINREG_SHIFT;
+
+ dev_dbg(chg->dev, "Charge input voltage regulation threshold: %u (0x%x)\n",
+ uvolt, data);
+
+ return regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_12,
+ CHG_CNFG_12_VCHGINREG_MASK, data);
+}
+
+/*
+ * Sets charger registers to proper and safe default values.
+ */
+static int max77693_reg_init(struct max77693_charger *chg)
+{
+ int ret;
+ unsigned int data;
+
+ /* Unlock charger register protection */
+ data = (0x3 << CHG_CNFG_06_CHGPROT_SHIFT);
+ ret = regmap_update_bits(chg->max77693->regmap,
+ MAX77693_CHG_REG_CHG_CNFG_06,
+ CHG_CNFG_06_CHGPROT_MASK, data);
+ if (ret) {
+ dev_err(chg->dev, "Error unlocking registers: %d\n", ret);
+ return ret;
+ }
+
+ ret = max77693_set_fast_charge_timer(chg, DEFAULT_FAST_CHARGE_TIMER);
+ if (ret)
+ return ret;
+
+ ret = max77693_set_top_off_threshold_current(chg,
+ DEFAULT_TOP_OFF_THRESHOLD_CURRENT);
+ if (ret)
+ return ret;
+
+ ret = max77693_set_top_off_timer(chg, DEFAULT_TOP_OFF_TIMER);
+ if (ret)
+ return ret;
+
+ ret = max77693_set_constant_volt(chg, chg->constant_volt);
+ if (ret)
+ return ret;
+
+ ret = max77693_set_min_system_volt(chg, chg->min_system_volt);
+ if (ret)
+ return ret;
+
+ ret = max77693_set_thermal_regulation_temp(chg,
+ chg->thermal_regulation_temp);
+ if (ret)
+ return ret;
+
+ ret = max77693_set_batttery_overcurrent(chg, chg->batttery_overcurrent);
+ if (ret)
+ return ret;
+
+ return max77693_set_charge_input_threshold_volt(chg,
+ chg->charge_input_threshold_volt);
+}
+
+#ifdef CONFIG_OF
+static int max77693_dt_init(struct device *dev, struct max77693_charger *chg)
+{
+ struct device_node *np = dev->of_node;
+
+ if (!np) {
+ dev_err(dev, "no charger OF node\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "maxim,constant-microvolt",
+ &chg->constant_volt))
+ chg->constant_volt = DEFAULT_CONSTANT_VOLT;
+
+ if (of_property_read_u32(np, "maxim,min-system-microvolt",
+ &chg->min_system_volt))
+ chg->min_system_volt = DEFAULT_MIN_SYSTEM_VOLT;
+
+ if (of_property_read_u32(np, "maxim,thermal-regulation-celsius",
+ &chg->thermal_regulation_temp))
+ chg->thermal_regulation_temp = DEFAULT_THERMAL_REGULATION_TEMP;
+
+ if (of_property_read_u32(np, "maxim,battery-overcurrent-microamp",
+ &chg->batttery_overcurrent))
+ chg->batttery_overcurrent = DEFAULT_BATTERY_OVERCURRENT;
+
+ if (of_property_read_u32(np, "maxim,charge-input-threshold-microvolt",
+ &chg->charge_input_threshold_volt))
+ chg->charge_input_threshold_volt =
+ DEFAULT_CHARGER_INPUT_THRESHOLD_VOLT;
+
+ return 0;
+}
+#else /* CONFIG_OF */
+static int max77693_dt_init(struct device *dev, struct max77693_charger *chg)
+{
+ return 0;
+}
+#endif /* CONFIG_OF */
+
+static int max77693_charger_probe(struct platform_device *pdev)
+{
+ struct max77693_charger *chg;
+ struct max77693_dev *max77693 = dev_get_drvdata(pdev->dev.parent);
+ int ret;
+
+ chg = devm_kzalloc(&pdev->dev, sizeof(*chg), GFP_KERNEL);
+ if (!chg)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, chg);
+ chg->dev = &pdev->dev;
+ chg->max77693 = max77693;
+
+ ret = max77693_dt_init(&pdev->dev, chg);
+ if (ret)
+ return ret;
+
+ ret = max77693_reg_init(chg);
+ if (ret)
+ return ret;
+
+ chg->charger.name = max77693_charger_name;
+ chg->charger.type = POWER_SUPPLY_TYPE_BATTERY;
+ chg->charger.properties = max77693_charger_props;
+ chg->charger.num_properties = ARRAY_SIZE(max77693_charger_props);
+ chg->charger.get_property = max77693_charger_get_property;
+
+ ret = device_create_file(&pdev->dev, &dev_attr_fast_charge_timer);
+ if (ret) {
+ dev_err(&pdev->dev, "failed: create fast charge timer sysfs entry\n");
+ goto err;
+ }
+
+ ret = device_create_file(&pdev->dev,
+ &dev_attr_top_off_threshold_current);
+ if (ret) {
+ dev_err(&pdev->dev, "failed: create top off current sysfs entry\n");
+ goto err;
+ }
+
+ ret = device_create_file(&pdev->dev, &dev_attr_top_off_timer);
+ if (ret) {
+ dev_err(&pdev->dev, "failed: create top off timer sysfs entry\n");
+ goto err;
+ }
+
+ ret = power_supply_register(&pdev->dev, &chg->charger);
+ if (ret) {
+ dev_err(&pdev->dev, "failed: power supply register\n");
+ goto err;
+ }
+
+ return 0;
+
+err:
+ device_remove_file(&pdev->dev, &dev_attr_top_off_timer);
+ device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current);
+ device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
+
+ return ret;
+}
+
+static int max77693_charger_remove(struct platform_device *pdev)
+{
+ struct max77693_charger *chg = platform_get_drvdata(pdev);
+
+ device_remove_file(&pdev->dev, &dev_attr_top_off_timer);
+ device_remove_file(&pdev->dev, &dev_attr_top_off_threshold_current);
+ device_remove_file(&pdev->dev, &dev_attr_fast_charge_timer);
+
+ power_supply_unregister(&chg->charger);
+
+ return 0;
+}
+
+static const struct platform_device_id max77693_charger_id[] = {
+ { "max77693-charger", 0, },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, max77693_charger_id);
+
+static struct platform_driver max77693_charger_driver = {
+ .driver = {
+ .name = "max77693-charger",
+ },
+ .probe = max77693_charger_probe,
+ .remove = max77693_charger_remove,
+ .id_table = max77693_charger_id,
+};
+module_platform_driver(max77693_charger_driver);
+
+MODULE_AUTHOR("Krzysztof Kozlowski <k.kozlowski@samsung.com>");
+MODULE_DESCRIPTION("Maxim 77693 charger driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index 028e76504519..27f6646731b0 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -39,14 +39,13 @@ config POWER_RESET_AXXIA
Say Y if you have an Axxia family SoC.
config POWER_RESET_BRCMSTB
- bool "Broadcom STB reset driver" if COMPILE_TEST
- depends on ARM
+ bool "Broadcom STB reset driver"
+ depends on ARM || MIPS || COMPILE_TEST
default ARCH_BRCMSTB
help
- This driver provides restart support for ARM-based Broadcom STB
- boards.
+ This driver provides restart support for Broadcom STB boards.
- Say Y here if you have an ARM-based Broadcom STB board and you wish
+ Say Y here if you have a Broadcom STB board and you wish
to have restart support.
config POWER_RESET_GPIO
@@ -104,23 +103,16 @@ config POWER_RESET_QNAP
config POWER_RESET_RESTART
bool "Restart power-off driver"
- depends on ARM
help
Some boards don't actually have the ability to power off.
Instead they restart, and u-boot holds the SoC until the
user presses a key. u-boot then boots into Linux.
-config POWER_RESET_SUN6I
- bool "Allwinner A31 SoC reset driver"
- depends on ARCH_SUNXI
- help
- Reboot support for the Allwinner A31 SoCs.
-
config POWER_RESET_ST
- bool "ST restart power-off driver"
+ bool "ST restart driver"
depends on ARCH_STI
help
- Power off and reset support for STMicroelectronics boards.
+ Reset support for STMicroelectronics boards.
config POWER_RESET_VERSATILE
bool "ARM Versatile family reboot driver"
@@ -159,5 +151,11 @@ config POWER_RESET_SYSCON
help
Reboot support for generic SYSCON mapped register reset.
+config POWER_RESET_RMOBILE
+ tristate "Renesas R-Mobile reset driver"
+ depends on ARCH_RMOBILE || COMPILE_TEST
+ help
+ Reboot support for Renesas R-Mobile and SH-Mobile SoCs.
+
endif
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 1d4804d6b323..11de15bae52e 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -11,10 +11,10 @@ obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
obj-$(CONFIG_POWER_RESET_RESTART) += restart-poweroff.o
-obj-$(CONFIG_POWER_RESET_SUN6I) += sun6i-reboot.o
obj-$(CONFIG_POWER_RESET_ST) += st-poweroff.o
obj-$(CONFIG_POWER_RESET_VERSATILE) += arm-versatile-reboot.o
obj-$(CONFIG_POWER_RESET_VEXPRESS) += vexpress-poweroff.o
obj-$(CONFIG_POWER_RESET_XGENE) += xgene-reboot.o
obj-$(CONFIG_POWER_RESET_KEYSTONE) += keystone-reset.o
obj-$(CONFIG_POWER_RESET_SYSCON) += syscon-reboot.o
+obj-$(CONFIG_POWER_RESET_RMOBILE) += rmobile-reset.o
diff --git a/drivers/power/reset/arm-versatile-reboot.c b/drivers/power/reset/arm-versatile-reboot.c
index 5b08bffcf1a8..b208073c887d 100644
--- a/drivers/power/reset/arm-versatile-reboot.c
+++ b/drivers/power/reset/arm-versatile-reboot.c
@@ -13,16 +13,22 @@
#include <linux/reboot.h>
#include <linux/regmap.h>
#include <linux/of.h>
-#include <asm/system_misc.h>
+
+#define INTEGRATOR_HDR_CTRL_OFFSET 0x0C
+#define INTEGRATOR_HDR_LOCK_OFFSET 0x14
+#define INTEGRATOR_CM_CTRL_RESET (1 << 3)
#define REALVIEW_SYS_LOCK_OFFSET 0x20
-#define REALVIEW_SYS_LOCK_VAL 0xA05F
#define REALVIEW_SYS_RESETCTL_OFFSET 0x40
+/* Magic unlocking token used on all Versatile boards */
+#define VERSATILE_LOCK_VAL 0xA05F
+
/*
* We detect the different syscon types from the compatible strings.
*/
enum versatile_reboot {
+ INTEGRATOR_REBOOT_CM,
REALVIEW_REBOOT_EB,
REALVIEW_REBOOT_PB1176,
REALVIEW_REBOOT_PB11MP,
@@ -36,6 +42,10 @@ static enum versatile_reboot versatile_reboot_type;
static const struct of_device_id versatile_reboot_of_match[] = {
{
+ .compatible = "arm,core-module-integrator",
+ .data = (void *)INTEGRATOR_REBOOT_CM
+ },
+ {
.compatible = "arm,realview-eb-syscon",
.data = (void *)REALVIEW_REBOOT_EB,
},
@@ -55,31 +65,47 @@ static const struct of_device_id versatile_reboot_of_match[] = {
.compatible = "arm,realview-pbx-syscon",
.data = (void *)REALVIEW_REBOOT_PBX,
},
+ {},
};
-static void versatile_reboot(enum reboot_mode mode, const char *cmd)
+static int versatile_reboot(struct notifier_block *this, unsigned long mode,
+ void *cmd)
{
/* Unlock the reset register */
- regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
- REALVIEW_SYS_LOCK_VAL);
/* Then hit reset on the different machines */
switch (versatile_reboot_type) {
+ case INTEGRATOR_REBOOT_CM:
+ regmap_write(syscon_regmap, INTEGRATOR_HDR_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
+ regmap_update_bits(syscon_regmap,
+ INTEGRATOR_HDR_CTRL_OFFSET,
+ INTEGRATOR_CM_CTRL_RESET,
+ INTEGRATOR_CM_CTRL_RESET);
+ break;
case REALVIEW_REBOOT_EB:
+ regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap,
REALVIEW_SYS_RESETCTL_OFFSET, 0x0008);
break;
case REALVIEW_REBOOT_PB1176:
+ regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap,
REALVIEW_SYS_RESETCTL_OFFSET, 0x0100);
break;
case REALVIEW_REBOOT_PB11MP:
case REALVIEW_REBOOT_PBA8:
+ regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
0x0000);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
0x0004);
break;
case REALVIEW_REBOOT_PBX:
+ regmap_write(syscon_regmap, REALVIEW_SYS_LOCK_OFFSET,
+ VERSATILE_LOCK_VAL);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
0x00f0);
regmap_write(syscon_regmap, REALVIEW_SYS_RESETCTL_OFFSET,
@@ -87,12 +113,20 @@ static void versatile_reboot(enum reboot_mode mode, const char *cmd)
break;
}
dsb();
+
+ return NOTIFY_DONE;
}
+static struct notifier_block versatile_reboot_nb = {
+ .notifier_call = versatile_reboot,
+ .priority = 192,
+};
+
static int __init versatile_reboot_probe(void)
{
const struct of_device_id *reboot_id;
struct device_node *np;
+ int err;
np = of_find_matching_node_and_match(NULL, versatile_reboot_of_match,
&reboot_id);
@@ -104,7 +138,10 @@ static int __init versatile_reboot_probe(void)
if (IS_ERR(syscon_regmap))
return PTR_ERR(syscon_regmap);
- arm_pm_restart = versatile_reboot;
+ err = register_restart_handler(&versatile_reboot_nb);
+ if (err)
+ return err;
+
pr_info("versatile reboot driver registered\n");
return 0;
}
diff --git a/drivers/power/reset/at91-poweroff.c b/drivers/power/reset/at91-poweroff.c
index c61000333bb9..4b72ea51c364 100644
--- a/drivers/power/reset/at91-poweroff.c
+++ b/drivers/power/reset/at91-poweroff.c
@@ -71,10 +71,11 @@ static void at91_poweroff(void)
writel(AT91_SHDW_KEY | AT91_SHDW_SHDW, at91_shdwc_base + AT91_SHDW_CR);
}
-const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np)
+static int at91_poweroff_get_wakeup_mode(struct device_node *np)
{
const char *pm;
- int err, i;
+ unsigned int i;
+ int err;
err = of_property_read_string(np, "atmel,wakeup-mode", &pm);
if (err < 0)
@@ -90,7 +91,7 @@ const enum wakeup_type at91_poweroff_get_wakeup_mode(struct device_node *np)
static void at91_poweroff_dt_set_wakeup_mode(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
- enum wakeup_type wakeup_mode;
+ int wakeup_mode;
u32 mode = 0, tmp;
wakeup_mode = at91_poweroff_get_wakeup_mode(np);
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 69a75d99ae92..13584e24736a 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -17,8 +17,6 @@
#include <linux/platform_device.h>
#include <linux/reboot.h>
-#include <asm/system_misc.h>
-
#include <soc/at91/at91sam9_ddrsdr.h>
#include <soc/at91/at91sam9_sdramc.h>
@@ -54,7 +52,8 @@ static void __iomem *at91_ramc_base[2], *at91_rstc_base;
* reset register it can be left driving the data bus and
* killing the chance of a subsequent boot from NAND
*/
-static void at91sam9260_restart(enum reboot_mode mode, const char *cmd)
+static int at91sam9260_restart(struct notifier_block *this, unsigned long mode,
+ void *cmd)
{
asm volatile(
/* Align to cache lines */
@@ -76,9 +75,12 @@ static void at91sam9260_restart(enum reboot_mode mode, const char *cmd)
"r" (1),
"r" (AT91_SDRAMC_LPCB_POWER_DOWN),
"r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST));
+
+ return NOTIFY_DONE;
}
-static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd)
+static int at91sam9g45_restart(struct notifier_block *this, unsigned long mode,
+ void *cmd)
{
asm volatile(
/*
@@ -117,6 +119,8 @@ static void at91sam9g45_restart(enum reboot_mode mode, const char *cmd)
"r" (AT91_DDRSDRC_LPCB_POWER_DOWN),
"r" (AT91_RSTC_KEY | AT91_RSTC_PERRST | AT91_RSTC_PROCRST)
: "r0");
+
+ return NOTIFY_DONE;
}
static void __init at91_reset_status(struct platform_device *pdev)
@@ -161,6 +165,10 @@ static struct of_device_id at91_reset_of_match[] = {
{ /* sentinel */ }
};
+static struct notifier_block at91_restart_nb = {
+ .priority = 192,
+};
+
static int at91_reset_of_probe(struct platform_device *pdev)
{
const struct of_device_id *match;
@@ -183,9 +191,8 @@ static int at91_reset_of_probe(struct platform_device *pdev)
}
match = of_match_node(at91_reset_of_match, pdev->dev.of_node);
- arm_pm_restart = match->data;
-
- return 0;
+ at91_restart_nb.notifier_call = match->data;
+ return register_restart_handler(&at91_restart_nb);
}
static int at91_reset_platform_probe(struct platform_device *pdev)
@@ -212,10 +219,11 @@ static int at91_reset_platform_probe(struct platform_device *pdev)
}
match = platform_get_device_id(pdev);
- arm_pm_restart = (void (*)(enum reboot_mode, const char*))
- match->driver_data;
+ at91_restart_nb.notifier_call =
+ (int (*)(struct notifier_block *,
+ unsigned long, void *)) match->driver_data;
- return 0;
+ return register_restart_handler(&at91_restart_nb);
}
static int at91_reset_probe(struct platform_device *pdev)
diff --git a/drivers/power/reset/brcmstb-reboot.c b/drivers/power/reset/brcmstb-reboot.c
index 100606f9b3dc..884b53c483c0 100644
--- a/drivers/power/reset/brcmstb-reboot.c
+++ b/drivers/power/reset/brcmstb-reboot.c
@@ -11,6 +11,7 @@
* GNU General Public License for more details.
*/
+#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/errno.h>
#include <linux/init.h>
@@ -34,13 +35,20 @@ static struct regmap *regmap;
static u32 rst_src_en;
static u32 sw_mstr_rst;
+struct reset_reg_mask {
+ u32 rst_src_en_mask;
+ u32 sw_mstr_rst_mask;
+};
+
+static const struct reset_reg_mask *reset_masks;
+
static int brcmstb_restart_handler(struct notifier_block *this,
unsigned long mode, void *cmd)
{
int rc;
u32 tmp;
- rc = regmap_write(regmap, rst_src_en, 1);
+ rc = regmap_write(regmap, rst_src_en, reset_masks->rst_src_en_mask);
if (rc) {
pr_err("failed to write rst_src_en (%d)\n", rc);
return NOTIFY_DONE;
@@ -52,7 +60,7 @@ static int brcmstb_restart_handler(struct notifier_block *this,
return NOTIFY_DONE;
}
- rc = regmap_write(regmap, sw_mstr_rst, 1);
+ rc = regmap_write(regmap, sw_mstr_rst, reset_masks->sw_mstr_rst_mask);
if (rc) {
pr_err("failed to write sw_mstr_rst (%d)\n", rc);
return NOTIFY_DONE;
@@ -75,10 +83,34 @@ static struct notifier_block brcmstb_restart_nb = {
.priority = 128,
};
+static const struct reset_reg_mask reset_bits_40nm = {
+ .rst_src_en_mask = BIT(0),
+ .sw_mstr_rst_mask = BIT(0),
+};
+
+static const struct reset_reg_mask reset_bits_65nm = {
+ .rst_src_en_mask = BIT(3),
+ .sw_mstr_rst_mask = BIT(31),
+};
+
+static const struct of_device_id of_match[] = {
+ { .compatible = "brcm,brcmstb-reboot", .data = &reset_bits_40nm },
+ { .compatible = "brcm,bcm7038-reboot", .data = &reset_bits_65nm },
+ {},
+};
+
static int brcmstb_reboot_probe(struct platform_device *pdev)
{
int rc;
struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *of_id;
+
+ of_id = of_match_node(of_match, np);
+ if (!of_id) {
+ pr_err("failed to look up compatible string\n");
+ return -EINVAL;
+ }
+ reset_masks = of_id->data;
regmap = syscon_regmap_lookup_by_phandle(np, "syscon");
if (IS_ERR(regmap)) {
@@ -108,11 +140,6 @@ static int brcmstb_reboot_probe(struct platform_device *pdev)
return rc;
}
-static const struct of_device_id of_match[] = {
- { .compatible = "brcm,brcmstb-reboot", },
- {},
-};
-
static struct platform_driver brcmstb_reboot_driver = {
.probe = brcmstb_reboot_probe,
.driver = {
diff --git a/drivers/power/reset/ltc2952-poweroff.c b/drivers/power/reset/ltc2952-poweroff.c
index 34f38a3dc3ff..7ef193b6f7fe 100644
--- a/drivers/power/reset/ltc2952-poweroff.c
+++ b/drivers/power/reset/ltc2952-poweroff.c
@@ -32,7 +32,9 @@
* - trigger (input)
* A level change indicates the shut-down trigger. If it's state reverts
* within the time-out defined by trigger_delay, the shut down is not
- * executed.
+ * executed. If no pin is assigned to this input, the driver will start the
+ * watchdog toggle immediately. The chip will only power off the system if
+ * it is requested to do so through the kill line.
*
* - watchdog (output)
* Once a shut down is triggered, the driver will toggle this signal,
@@ -63,7 +65,7 @@
#include <linux/gpio/consumer.h>
#include <linux/reboot.h>
-struct ltc2952_poweroff_data {
+struct ltc2952_poweroff {
struct hrtimer timer_trigger;
struct hrtimer timer_wde;
@@ -72,22 +74,21 @@ struct ltc2952_poweroff_data {
struct device *dev;
- unsigned int virq;
+ struct gpio_desc *gpio_trigger;
+ struct gpio_desc *gpio_watchdog;
+ struct gpio_desc *gpio_kill;
- /**
- * 0: trigger
- * 1: watchdog
- * 2: kill
- */
- struct gpio_desc *gpio[3];
+ bool kernel_panic;
+ struct notifier_block panic_notifier;
};
-static int ltc2952_poweroff_panic;
-static struct ltc2952_poweroff_data *ltc2952_data;
+#define to_ltc2952(p, m) container_of(p, struct ltc2952_poweroff, m)
-#define POWERPATH_IO_TRIGGER 0
-#define POWERPATH_IO_WATCHDOG 1
-#define POWERPATH_IO_KILL 2
+/*
+ * This global variable is only needed for pm_power_off. We should
+ * remove it entirely once we don't need the global state anymore.
+ */
+static struct ltc2952_poweroff *ltc2952_data;
/**
* ltc2952_poweroff_timer_wde - Timer callback
@@ -103,29 +104,24 @@ static enum hrtimer_restart ltc2952_poweroff_timer_wde(struct hrtimer *timer)
ktime_t now;
int state;
unsigned long overruns;
+ struct ltc2952_poweroff *data = to_ltc2952(timer, timer_wde);
- if (ltc2952_poweroff_panic)
+ if (data->kernel_panic)
return HRTIMER_NORESTART;
- state = gpiod_get_value(ltc2952_data->gpio[POWERPATH_IO_WATCHDOG]);
- gpiod_set_value(ltc2952_data->gpio[POWERPATH_IO_WATCHDOG], !state);
+ state = gpiod_get_value(data->gpio_watchdog);
+ gpiod_set_value(data->gpio_watchdog, !state);
now = hrtimer_cb_get_time(timer);
- overruns = hrtimer_forward(timer, now, ltc2952_data->wde_interval);
+ overruns = hrtimer_forward(timer, now, data->wde_interval);
return HRTIMER_RESTART;
}
-static enum hrtimer_restart ltc2952_poweroff_timer_trigger(
- struct hrtimer *timer)
+static void ltc2952_poweroff_start_wde(struct ltc2952_poweroff *data)
{
- int ret;
-
- ret = hrtimer_start(&ltc2952_data->timer_wde,
- ltc2952_data->wde_interval, HRTIMER_MODE_REL);
-
- if (ret) {
- dev_err(ltc2952_data->dev, "unable to start the timer\n");
+ if (hrtimer_start(&data->timer_wde, data->wde_interval,
+ HRTIMER_MODE_REL)) {
/*
* The device will not toggle the watchdog reset,
* thus shut down is only safe if the PowerPath controller
@@ -134,10 +130,17 @@ static enum hrtimer_restart ltc2952_poweroff_timer_trigger(
*
* Only sending a warning as the system will power-off anyway
*/
+ dev_err(data->dev, "unable to start the timer\n");
}
+}
- dev_info(ltc2952_data->dev, "executing shutdown\n");
+static enum hrtimer_restart
+ltc2952_poweroff_timer_trigger(struct hrtimer *timer)
+{
+ struct ltc2952_poweroff *data = to_ltc2952(timer, timer_trigger);
+ ltc2952_poweroff_start_wde(data);
+ dev_info(data->dev, "executing shutdown\n");
orderly_poweroff(true);
return HRTIMER_NORESTART;
@@ -154,180 +157,161 @@ static enum hrtimer_restart ltc2952_poweroff_timer_trigger(
*/
static irqreturn_t ltc2952_poweroff_handler(int irq, void *dev_id)
{
- int ret;
- struct ltc2952_poweroff_data *data = dev_id;
+ struct ltc2952_poweroff *data = dev_id;
- if (ltc2952_poweroff_panic)
- goto irq_ok;
-
- if (hrtimer_active(&data->timer_wde)) {
+ if (data->kernel_panic || hrtimer_active(&data->timer_wde)) {
/* shutdown is already triggered, nothing to do any more */
- goto irq_ok;
+ return IRQ_HANDLED;
}
- if (!hrtimer_active(&data->timer_trigger)) {
- ret = hrtimer_start(&data->timer_trigger, data->trigger_delay,
- HRTIMER_MODE_REL);
-
- if (ret)
+ if (gpiod_get_value(data->gpio_trigger)) {
+ if (hrtimer_start(&data->timer_trigger, data->trigger_delay,
+ HRTIMER_MODE_REL))
dev_err(data->dev, "unable to start the wait timer\n");
} else {
- ret = hrtimer_cancel(&data->timer_trigger);
+ hrtimer_cancel(&data->timer_trigger);
/* omitting return value check, timer should have been valid */
}
-
-irq_ok:
return IRQ_HANDLED;
}
static void ltc2952_poweroff_kill(void)
{
- gpiod_set_value(ltc2952_data->gpio[POWERPATH_IO_KILL], 1);
-}
-
-static int ltc2952_poweroff_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- return -ENOSYS;
-}
-
-static int ltc2952_poweroff_resume(struct platform_device *pdev)
-{
- return -ENOSYS;
+ gpiod_set_value(ltc2952_data->gpio_kill, 1);
}
-static void ltc2952_poweroff_default(struct ltc2952_poweroff_data *data)
+static void ltc2952_poweroff_default(struct ltc2952_poweroff *data)
{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(data->gpio); i++)
- data->gpio[i] = NULL;
-
data->wde_interval = ktime_set(0, 300L*1E6L);
data->trigger_delay = ktime_set(2, 500L*1E6L);
hrtimer_init(&data->timer_trigger, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- data->timer_trigger.function = &ltc2952_poweroff_timer_trigger;
+ data->timer_trigger.function = ltc2952_poweroff_timer_trigger;
hrtimer_init(&data->timer_wde, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
- data->timer_wde.function = &ltc2952_poweroff_timer_wde;
+ data->timer_wde.function = ltc2952_poweroff_timer_wde;
}
static int ltc2952_poweroff_init(struct platform_device *pdev)
{
- int ret, virq;
- unsigned int i;
- struct ltc2952_poweroff_data *data;
-
- static char *name[] = {
- "trigger",
- "watchdog",
- "kill",
- NULL
- };
-
- data = ltc2952_data;
- ltc2952_poweroff_default(ltc2952_data);
-
- for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++) {
- ltc2952_data->gpio[i] = gpiod_get(&pdev->dev, name[i]);
+ int ret;
+ struct ltc2952_poweroff *data = platform_get_drvdata(pdev);
- if (IS_ERR(ltc2952_data->gpio[i])) {
- ret = PTR_ERR(ltc2952_data->gpio[i]);
- dev_err(&pdev->dev,
- "unable to claim the following gpio: %s\n",
- name[i]);
- goto err_io;
- }
- }
+ ltc2952_poweroff_default(data);
- ret = gpiod_direction_output(
- ltc2952_data->gpio[POWERPATH_IO_WATCHDOG], 0);
- if (ret) {
- dev_err(&pdev->dev, "unable to use watchdog-gpio as output\n");
- goto err_io;
+ data->gpio_watchdog = devm_gpiod_get(&pdev->dev, "watchdog",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpio_watchdog)) {
+ ret = PTR_ERR(data->gpio_watchdog);
+ dev_err(&pdev->dev, "unable to claim gpio \"watchdog\"\n");
+ return ret;
}
- ret = gpiod_direction_output(ltc2952_data->gpio[POWERPATH_IO_KILL], 0);
- if (ret) {
- dev_err(&pdev->dev, "unable to use kill-gpio as output\n");
- goto err_io;
+ data->gpio_kill = devm_gpiod_get(&pdev->dev, "kill", GPIOD_OUT_LOW);
+ if (IS_ERR(data->gpio_kill)) {
+ ret = PTR_ERR(data->gpio_kill);
+ dev_err(&pdev->dev, "unable to claim gpio \"kill\"\n");
+ return ret;
}
- virq = gpiod_to_irq(ltc2952_data->gpio[POWERPATH_IO_TRIGGER]);
- if (virq < 0) {
- dev_err(&pdev->dev, "cannot map GPIO as interrupt");
- goto err_io;
+ data->gpio_trigger = devm_gpiod_get(&pdev->dev, "trigger", GPIOD_IN);
+ if (IS_ERR(data->gpio_trigger)) {
+ /*
+ * It's not a problem if the trigger gpio isn't available, but
+ * it is worth a warning if its use was defined in the device
+ * tree.
+ */
+ if (PTR_ERR(data->gpio_trigger) != -ENOENT)
+ dev_err(&pdev->dev,
+ "unable to claim gpio \"trigger\"\n");
+ data->gpio_trigger = NULL;
}
- ltc2952_data->virq = virq;
- ret = request_irq(virq,
- ltc2952_poweroff_handler,
- (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
- "ltc2952-poweroff",
- ltc2952_data
- );
-
- if (ret) {
- dev_err(&pdev->dev, "cannot configure an interrupt handler\n");
- goto err_io;
+ if (devm_request_irq(&pdev->dev, gpiod_to_irq(data->gpio_trigger),
+ ltc2952_poweroff_handler,
+ (IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING),
+ "ltc2952-poweroff",
+ data)) {
+ /*
+ * Some things may have happened:
+ * - No trigger input was defined
+ * - Claiming the GPIO failed
+ * - We could not map to an IRQ
+ * - We couldn't register an interrupt handler
+ *
+ * None of these really are problems, but all of them
+ * disqualify the push button from controlling the power.
+ *
+ * It is therefore important to note that if the ltc2952
+ * detects a button press for long enough, it will still start
+ * its own powerdown window and cut the power on us if we don't
+ * start the watchdog trigger.
+ */
+ if (data->gpio_trigger) {
+ dev_warn(&pdev->dev,
+ "unable to configure the trigger interrupt\n");
+ devm_gpiod_put(&pdev->dev, data->gpio_trigger);
+ data->gpio_trigger = NULL;
+ }
+ dev_info(&pdev->dev,
+ "power down trigger input will not be used\n");
+ ltc2952_poweroff_start_wde(data);
}
return 0;
+}
-err_io:
- for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++)
- if (ltc2952_data->gpio[i])
- gpiod_put(ltc2952_data->gpio[i]);
+static int ltc2952_poweroff_notify_panic(struct notifier_block *nb,
+ unsigned long code, void *unused)
+{
+ struct ltc2952_poweroff *data = to_ltc2952(nb, panic_notifier);
- return ret;
+ data->kernel_panic = true;
+ return NOTIFY_DONE;
}
static int ltc2952_poweroff_probe(struct platform_device *pdev)
{
int ret;
+ struct ltc2952_poweroff *data;
if (pm_power_off) {
dev_err(&pdev->dev, "pm_power_off already registered");
return -EBUSY;
}
- ltc2952_data = kzalloc(sizeof(*ltc2952_data), GFP_KERNEL);
- if (!ltc2952_data)
+ data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
+ if (!data)
return -ENOMEM;
- ltc2952_data->dev = &pdev->dev;
+ data->dev = &pdev->dev;
+ platform_set_drvdata(pdev, data);
ret = ltc2952_poweroff_init(pdev);
if (ret)
- goto err;
+ return ret;
- pm_power_off = &ltc2952_poweroff_kill;
+ /* TODO: remove ltc2952_data */
+ ltc2952_data = data;
+ pm_power_off = ltc2952_poweroff_kill;
+ data->panic_notifier.notifier_call = ltc2952_poweroff_notify_panic;
+ atomic_notifier_chain_register(&panic_notifier_list,
+ &data->panic_notifier);
dev_info(&pdev->dev, "probe successful\n");
return 0;
-
-err:
- kfree(ltc2952_data);
- return ret;
}
static int ltc2952_poweroff_remove(struct platform_device *pdev)
{
- unsigned int i;
+ struct ltc2952_poweroff *data = platform_get_drvdata(pdev);
pm_power_off = NULL;
-
- if (ltc2952_data) {
- free_irq(ltc2952_data->virq, ltc2952_data);
-
- for (i = 0; i < ARRAY_SIZE(ltc2952_data->gpio); i++)
- gpiod_put(ltc2952_data->gpio[i]);
-
- kfree(ltc2952_data);
- }
-
+ hrtimer_cancel(&data->timer_trigger);
+ hrtimer_cancel(&data->timer_wde);
+ atomic_notifier_chain_unregister(&panic_notifier_list,
+ &data->panic_notifier);
return 0;
}
@@ -344,41 +328,9 @@ static struct platform_driver ltc2952_poweroff_driver = {
.name = "ltc2952-poweroff",
.of_match_table = of_ltc2952_poweroff_match,
},
- .suspend = ltc2952_poweroff_suspend,
- .resume = ltc2952_poweroff_resume,
-};
-
-static int ltc2952_poweroff_notify_panic(struct notifier_block *nb,
- unsigned long code, void *unused)
-{
- ltc2952_poweroff_panic = 1;
- return NOTIFY_DONE;
-}
-
-static struct notifier_block ltc2952_poweroff_panic_nb = {
- .notifier_call = ltc2952_poweroff_notify_panic,
};
-static int __init ltc2952_poweroff_platform_init(void)
-{
- ltc2952_poweroff_panic = 0;
-
- atomic_notifier_chain_register(&panic_notifier_list,
- &ltc2952_poweroff_panic_nb);
-
- return platform_driver_register(&ltc2952_poweroff_driver);
-}
-
-static void __exit ltc2952_poweroff_platform_exit(void)
-{
- atomic_notifier_chain_unregister(&panic_notifier_list,
- &ltc2952_poweroff_panic_nb);
-
- platform_driver_unregister(&ltc2952_poweroff_driver);
-}
-
-module_init(ltc2952_poweroff_platform_init);
-module_exit(ltc2952_poweroff_platform_exit);
+module_platform_driver(ltc2952_poweroff_driver);
MODULE_AUTHOR("René Moll <rene.moll@xsens.com>");
MODULE_DESCRIPTION("LTC PowerPath power-off driver");
diff --git a/drivers/power/reset/restart-poweroff.c b/drivers/power/reset/restart-poweroff.c
index f46f2c2e4648..41b22c4d5236 100644
--- a/drivers/power/reset/restart-poweroff.c
+++ b/drivers/power/reset/restart-poweroff.c
@@ -16,7 +16,6 @@
#include <linux/of_platform.h>
#include <linux/module.h>
#include <linux/reboot.h>
-#include <asm/system_misc.h>
static void restart_poweroff_do_poweroff(void)
{
diff --git a/drivers/power/reset/rmobile-reset.c b/drivers/power/reset/rmobile-reset.c
new file mode 100644
index 000000000000..e6569df76941
--- /dev/null
+++ b/drivers/power/reset/rmobile-reset.c
@@ -0,0 +1,91 @@
+/*
+ * Renesas R-Mobile Reset Driver
+ *
+ * Copyright (C) 2014 Glider bvba
+ *
+ * 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/io.h>
+#include <linux/module.h>
+#include <linux/notifier.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/printk.h>
+#include <linux/reboot.h>
+
+/* SYSC Register Bank 2 */
+#define RESCNT2 0x20 /* Reset Control Register 2 */
+
+/* Reset Control Register 2 */
+#define RESCNT2_PRES 0x80000000 /* Soft power-on reset */
+
+static void __iomem *sysc_base2;
+
+static int rmobile_reset_handler(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ pr_debug("%s %lu\n", __func__, mode);
+
+ /* Let's assume we have acquired the HPB semaphore */
+ writel(RESCNT2_PRES, sysc_base2 + RESCNT2);
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block rmobile_reset_nb = {
+ .notifier_call = rmobile_reset_handler,
+ .priority = 192,
+};
+
+static int rmobile_reset_probe(struct platform_device *pdev)
+{
+ int error;
+
+ sysc_base2 = of_iomap(pdev->dev.of_node, 1);
+ if (!sysc_base2)
+ return -ENODEV;
+
+ error = register_restart_handler(&rmobile_reset_nb);
+ if (error) {
+ dev_err(&pdev->dev,
+ "cannot register restart handler (err=%d)\n", error);
+ goto fail_unmap;
+ }
+
+ return 0;
+
+fail_unmap:
+ iounmap(sysc_base2);
+ return error;
+}
+
+static int rmobile_reset_remove(struct platform_device *pdev)
+{
+ unregister_restart_handler(&rmobile_reset_nb);
+ iounmap(sysc_base2);
+ return 0;
+}
+
+static const struct of_device_id rmobile_reset_of_match[] = {
+ { .compatible = "renesas,sysc-rmobile", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, rmobile_reset_of_match);
+
+static struct platform_driver rmobile_reset_driver = {
+ .probe = rmobile_reset_probe,
+ .remove = rmobile_reset_remove,
+ .driver = {
+ .name = "rmobile_reset",
+ .of_match_table = rmobile_reset_of_match,
+ },
+};
+
+module_platform_driver(rmobile_reset_driver);
+
+MODULE_DESCRIPTION("Renesas R-Mobile Reset Driver");
+MODULE_AUTHOR("Geert Uytterhoeven <geert+renesas@glider.be>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/power/reset/st-poweroff.c b/drivers/power/reset/st-poweroff.c
index a0acf25ee2a2..27383de9caa8 100644
--- a/drivers/power/reset/st-poweroff.c
+++ b/drivers/power/reset/st-poweroff.c
@@ -15,10 +15,9 @@
#include <linux/of_platform.h>
#include <linux/platform_device.h>
#include <linux/mfd/syscon.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
-#include <asm/system_misc.h>
-
struct reset_syscfg {
struct regmap *regmap;
/* syscfg used for reset */
@@ -75,7 +74,8 @@ static struct reset_syscfg stid127_reset = {
static struct reset_syscfg *st_restart_syscfg;
-static void st_restart(enum reboot_mode reboot_mode, const char *cmd)
+static int st_restart(struct notifier_block *this, unsigned long mode,
+ void *cmd)
{
/* reset syscfg updated */
regmap_update_bits(st_restart_syscfg->regmap,
@@ -88,8 +88,15 @@ static void st_restart(enum reboot_mode reboot_mode, const char *cmd)
st_restart_syscfg->offset_rst_msk,
st_restart_syscfg->mask_rst_msk,
0);
+
+ return NOTIFY_DONE;
}
+static struct notifier_block st_restart_nb = {
+ .notifier_call = st_restart,
+ .priority = 192,
+};
+
static struct of_device_id st_reset_of_match[] = {
{
.compatible = "st,stih415-restart",
@@ -126,9 +133,7 @@ static int st_reset_probe(struct platform_device *pdev)
return PTR_ERR(st_restart_syscfg->regmap);
}
- arm_pm_restart = st_restart;
-
- return 0;
+ return register_restart_handler(&st_restart_nb);
}
static struct platform_driver st_reset_driver = {
diff --git a/drivers/power/reset/sun6i-reboot.c b/drivers/power/reset/sun6i-reboot.c
deleted file mode 100644
index af2cd7ff2fe8..000000000000
--- a/drivers/power/reset/sun6i-reboot.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * Allwinner A31 SoCs reset code
- *
- * Copyright (C) 2012-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/delay.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/of_address.h>
-#include <linux/platform_device.h>
-#include <linux/reboot.h>
-
-#include <asm/system_misc.h>
-
-#define SUN6I_WATCHDOG1_IRQ_REG 0x00
-#define SUN6I_WATCHDOG1_CTRL_REG 0x10
-#define SUN6I_WATCHDOG1_CTRL_RESTART BIT(0)
-#define SUN6I_WATCHDOG1_CONFIG_REG 0x14
-#define SUN6I_WATCHDOG1_CONFIG_RESTART BIT(0)
-#define SUN6I_WATCHDOG1_CONFIG_IRQ BIT(1)
-#define SUN6I_WATCHDOG1_MODE_REG 0x18
-#define SUN6I_WATCHDOG1_MODE_ENABLE BIT(0)
-
-static void __iomem *wdt_base;
-
-static void sun6i_wdt_restart(enum reboot_mode mode, const char *cmd)
-{
- if (!wdt_base)
- return;
-
- /* Disable interrupts */
- writel(0, wdt_base + SUN6I_WATCHDOG1_IRQ_REG);
-
- /* We want to disable the IRQ and just reset the whole system */
- writel(SUN6I_WATCHDOG1_CONFIG_RESTART,
- wdt_base + SUN6I_WATCHDOG1_CONFIG_REG);
-
- /* Enable timer. The default and lowest interval value is 0.5s */
- writel(SUN6I_WATCHDOG1_MODE_ENABLE,
- wdt_base + SUN6I_WATCHDOG1_MODE_REG);
-
- /* Restart the watchdog. */
- writel(SUN6I_WATCHDOG1_CTRL_RESTART,
- wdt_base + SUN6I_WATCHDOG1_CTRL_REG);
-
- while (1) {
- mdelay(5);
- writel(SUN6I_WATCHDOG1_MODE_ENABLE,
- wdt_base + SUN6I_WATCHDOG1_MODE_REG);
- }
-}
-
-static int sun6i_reboot_probe(struct platform_device *pdev)
-{
- wdt_base = of_iomap(pdev->dev.of_node, 0);
- if (!wdt_base) {
- WARN(1, "failed to map watchdog base address");
- return -ENODEV;
- }
-
- arm_pm_restart = sun6i_wdt_restart;
-
- return 0;
-}
-
-static struct of_device_id sun6i_reboot_of_match[] = {
- { .compatible = "allwinner,sun6i-a31-wdt" },
- {}
-};
-
-static struct platform_driver sun6i_reboot_driver = {
- .probe = sun6i_reboot_probe,
- .driver = {
- .name = "sun6i-reboot",
- .of_match_table = sun6i_reboot_of_match,
- },
-};
-module_platform_driver(sun6i_reboot_driver);
diff --git a/drivers/power/reset/vexpress-poweroff.c b/drivers/power/reset/vexpress-poweroff.c
index 9dfc9cee3232..be12d9b92957 100644
--- a/drivers/power/reset/vexpress-poweroff.c
+++ b/drivers/power/reset/vexpress-poweroff.c
@@ -111,23 +111,20 @@ static int _vexpress_register_restart_handler(struct device *dev)
static int vexpress_reset_probe(struct platform_device *pdev)
{
- enum vexpress_reset_func func;
const struct of_device_id *match =
of_match_device(vexpress_reset_of_match, &pdev->dev);
struct regmap *regmap;
int ret = 0;
- if (match)
- func = (enum vexpress_reset_func)match->data;
- else
- func = pdev->id_entry->driver_data;
+ if (!match)
+ return -EINVAL;
regmap = devm_regmap_init_vexpress_config(&pdev->dev);
if (IS_ERR(regmap))
return PTR_ERR(regmap);
dev_set_drvdata(&pdev->dev, regmap);
- switch (func) {
+ switch ((enum vexpress_reset_func)match->data) {
case FUNC_SHUTDOWN:
vexpress_power_off_device = &pdev->dev;
pm_power_off = vexpress_power_off;
@@ -144,20 +141,12 @@ static int vexpress_reset_probe(struct platform_device *pdev)
return ret;
}
-static const struct platform_device_id vexpress_reset_id_table[] = {
- { .name = "vexpress-reset", .driver_data = FUNC_RESET, },
- { .name = "vexpress-shutdown", .driver_data = FUNC_SHUTDOWN, },
- { .name = "vexpress-reboot", .driver_data = FUNC_REBOOT, },
- {}
-};
-
static struct platform_driver vexpress_reset_driver = {
.probe = vexpress_reset_probe,
.driver = {
.name = "vexpress-reset",
.of_match_table = vexpress_reset_of_match,
},
- .id_table = vexpress_reset_id_table,
};
static int __init vexpress_reset_init(void)
diff --git a/drivers/power/rt5033_battery.c b/drivers/power/rt5033_battery.c
new file mode 100644
index 000000000000..7b898f41c595
--- /dev/null
+++ b/drivers/power/rt5033_battery.c
@@ -0,0 +1,177 @@
+/*
+ * Fuel gauge driver for 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/power_supply.h>
+#include <linux/mfd/rt5033-private.h>
+#include <linux/mfd/rt5033.h>
+
+static int rt5033_battery_get_capacity(struct i2c_client *client)
+{
+ struct rt5033_battery *battery = i2c_get_clientdata(client);
+ u32 msb;
+
+ regmap_read(battery->regmap, RT5033_FUEL_REG_SOC_H, &msb);
+
+ return msb;
+}
+
+static int rt5033_battery_get_present(struct i2c_client *client)
+{
+ struct rt5033_battery *battery = i2c_get_clientdata(client);
+ u32 val;
+
+ regmap_read(battery->regmap, RT5033_FUEL_REG_CONFIG_L, &val);
+
+ return (val & RT5033_FUEL_BAT_PRESENT) ? true : false;
+}
+
+static int rt5033_battery_get_watt_prop(struct i2c_client *client,
+ enum power_supply_property psp)
+{
+ struct rt5033_battery *battery = i2c_get_clientdata(client);
+ unsigned int regh, regl;
+ int ret;
+ u32 msb, lsb;
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ regh = RT5033_FUEL_REG_VBAT_H;
+ regl = RT5033_FUEL_REG_VBAT_L;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ regh = RT5033_FUEL_REG_AVG_VOLT_H;
+ regl = RT5033_FUEL_REG_AVG_VOLT_L;
+ break;
+ case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+ regh = RT5033_FUEL_REG_OCV_H;
+ regl = RT5033_FUEL_REG_OCV_L;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ regmap_read(battery->regmap, regh, &msb);
+ regmap_read(battery->regmap, regl, &lsb);
+
+ ret = ((msb << 4) + (lsb >> 4)) * 1250 / 1000;
+
+ return ret;
+}
+
+static int rt5033_battery_get_property(struct power_supply *psy,
+ enum power_supply_property psp,
+ union power_supply_propval *val)
+{
+ struct rt5033_battery *battery = container_of(psy,
+ struct rt5033_battery, psy);
+
+ switch (psp) {
+ case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+ case POWER_SUPPLY_PROP_VOLTAGE_AVG:
+ case POWER_SUPPLY_PROP_VOLTAGE_OCV:
+ val->intval = rt5033_battery_get_watt_prop(battery->client,
+ psp);
+ break;
+ case POWER_SUPPLY_PROP_PRESENT:
+ val->intval = rt5033_battery_get_present(battery->client);
+ break;
+ case POWER_SUPPLY_PROP_CAPACITY:
+ val->intval = rt5033_battery_get_capacity(battery->client);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static enum power_supply_property rt5033_battery_props[] = {
+ POWER_SUPPLY_PROP_VOLTAGE_NOW,
+ POWER_SUPPLY_PROP_VOLTAGE_AVG,
+ POWER_SUPPLY_PROP_VOLTAGE_OCV,
+ POWER_SUPPLY_PROP_PRESENT,
+ POWER_SUPPLY_PROP_CAPACITY,
+};
+
+static struct regmap_config rt5033_battery_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = RT5033_FUEL_REG_END,
+};
+
+static int rt5033_battery_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct rt5033_battery *battery;
+ u32 ret;
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE))
+ return -EIO;
+
+ battery = devm_kzalloc(&client->dev, sizeof(*battery), GFP_KERNEL);
+ if (!battery)
+ return -EINVAL;
+
+ battery->client = client;
+ battery->regmap = devm_regmap_init_i2c(client,
+ &rt5033_battery_regmap_config);
+ if (IS_ERR(battery->regmap)) {
+ dev_err(&client->dev, "Failed to initialize regmap\n");
+ return -EINVAL;
+ }
+
+ i2c_set_clientdata(client, battery);
+
+ battery->psy.name = "rt5033-battery";
+ battery->psy.type = POWER_SUPPLY_TYPE_BATTERY;
+ battery->psy.get_property = rt5033_battery_get_property;
+ battery->psy.properties = rt5033_battery_props;
+ battery->psy.num_properties = ARRAY_SIZE(rt5033_battery_props);
+
+ ret = power_supply_register(&client->dev, &battery->psy);
+ if (ret) {
+ dev_err(&client->dev, "Failed to register power supply\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int rt5033_battery_remove(struct i2c_client *client)
+{
+ struct rt5033_battery *battery = i2c_get_clientdata(client);
+
+ power_supply_unregister(&battery->psy);
+
+ return 0;
+}
+
+static const struct i2c_device_id rt5033_battery_id[] = {
+ { "rt5033-battery", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, rt5033_battery_id);
+
+static struct i2c_driver rt5033_battery_driver = {
+ .driver = {
+ .name = "rt5033-battery",
+ },
+ .probe = rt5033_battery_probe,
+ .remove = rt5033_battery_remove,
+ .id_table = rt5033_battery_id,
+};
+module_i2c_driver(rt5033_battery_driver);
+
+MODULE_DESCRIPTION("Richtek RT5033 fuel gauge driver");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/power/test_power.c b/drivers/power/test_power.c
index 0152f35dca5c..f26b1fa00fe1 100644
--- a/drivers/power/test_power.c
+++ b/drivers/power/test_power.c
@@ -21,6 +21,13 @@
#include <linux/delay.h>
#include <linux/vermagic.h>
+enum test_power_id {
+ TEST_AC,
+ TEST_BATTERY,
+ TEST_USB,
+ TEST_POWER_NUM,
+};
+
static int ac_online = 1;
static int usb_online = 1;
static int battery_status = POWER_SUPPLY_STATUS_DISCHARGING;
@@ -147,7 +154,7 @@ static char *test_power_ac_supplied_to[] = {
};
static struct power_supply test_power_supplies[] = {
- {
+ [TEST_AC] = {
.name = "test_ac",
.type = POWER_SUPPLY_TYPE_MAINS,
.supplied_to = test_power_ac_supplied_to,
@@ -155,13 +162,15 @@ static struct power_supply test_power_supplies[] = {
.properties = test_power_ac_props,
.num_properties = ARRAY_SIZE(test_power_ac_props),
.get_property = test_power_get_ac_property,
- }, {
+ },
+ [TEST_BATTERY] = {
.name = "test_battery",
.type = POWER_SUPPLY_TYPE_BATTERY,
.properties = test_power_battery_props,
.num_properties = ARRAY_SIZE(test_power_battery_props),
.get_property = test_power_get_battery_property,
- }, {
+ },
+ [TEST_USB] = {
.name = "test_usb",
.type = POWER_SUPPLY_TYPE_USB,
.supplied_to = test_power_ac_supplied_to,
@@ -178,6 +187,8 @@ static int __init test_power_init(void)
int i;
int ret;
+ BUILD_BUG_ON(TEST_POWER_NUM != ARRAY_SIZE(test_power_supplies));
+
for (i = 0; i < ARRAY_SIZE(test_power_supplies); i++) {
ret = power_supply_register(NULL, &test_power_supplies[i]);
if (ret) {
@@ -309,7 +320,7 @@ static inline void signal_power_supply_changed(struct power_supply *psy)
static int param_set_ac_online(const char *key, const struct kernel_param *kp)
{
ac_online = map_get_value(map_ac_online, key, ac_online);
- signal_power_supply_changed(&test_power_supplies[0]);
+ signal_power_supply_changed(&test_power_supplies[TEST_AC]);
return 0;
}
@@ -322,7 +333,7 @@ static int param_get_ac_online(char *buffer, const struct kernel_param *kp)
static int param_set_usb_online(const char *key, const struct kernel_param *kp)
{
usb_online = map_get_value(map_ac_online, key, usb_online);
- signal_power_supply_changed(&test_power_supplies[2]);
+ signal_power_supply_changed(&test_power_supplies[TEST_USB]);
return 0;
}
@@ -336,7 +347,7 @@ static int param_set_battery_status(const char *key,
const struct kernel_param *kp)
{
battery_status = map_get_value(map_status, key, battery_status);
- signal_power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]);
return 0;
}
@@ -350,7 +361,7 @@ static int param_set_battery_health(const char *key,
const struct kernel_param *kp)
{
battery_health = map_get_value(map_health, key, battery_health);
- signal_power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]);
return 0;
}
@@ -364,7 +375,7 @@ static int param_set_battery_present(const char *key,
const struct kernel_param *kp)
{
battery_present = map_get_value(map_present, key, battery_present);
- signal_power_supply_changed(&test_power_supplies[0]);
+ signal_power_supply_changed(&test_power_supplies[TEST_AC]);
return 0;
}
@@ -380,7 +391,7 @@ static int param_set_battery_technology(const char *key,
{
battery_technology = map_get_value(map_technology, key,
battery_technology);
- signal_power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]);
return 0;
}
@@ -401,7 +412,7 @@ static int param_set_battery_capacity(const char *key,
return -EINVAL;
battery_capacity = tmp;
- signal_power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]);
return 0;
}
@@ -416,7 +427,7 @@ static int param_set_battery_voltage(const char *key,
return -EINVAL;
battery_voltage = tmp;
- signal_power_supply_changed(&test_power_supplies[1]);
+ signal_power_supply_changed(&test_power_supplies[TEST_BATTERY]);
return 0;
}
diff --git a/drivers/ps3/ps3-vuart.c b/drivers/ps3/ps3-vuart.c
index bc1e5139ba29..d6db822bef84 100644
--- a/drivers/ps3/ps3-vuart.c
+++ b/drivers/ps3/ps3-vuart.c
@@ -151,11 +151,6 @@ static void __maybe_unused _dump_port_params(unsigned int port_number,
#endif
}
-struct vuart_triggers {
- unsigned long rx;
- unsigned long tx;
-};
-
int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev,
struct vuart_triggers *trig)
{
diff --git a/drivers/ps3/sys-manager-core.c b/drivers/ps3/sys-manager-core.c
index 0e41737ea835..c429ffca1ab7 100644
--- a/drivers/ps3/sys-manager-core.c
+++ b/drivers/ps3/sys-manager-core.c
@@ -47,7 +47,7 @@ void ps3_sys_manager_register_ops(const struct ps3_sys_manager_ops *ops)
}
EXPORT_SYMBOL_GPL(ps3_sys_manager_register_ops);
-void ps3_sys_manager_power_off(void)
+void __noreturn ps3_sys_manager_power_off(void)
{
if (ps3_sys_manager_ops.power_off)
ps3_sys_manager_ops.power_off(ps3_sys_manager_ops.dev);
@@ -55,7 +55,7 @@ void ps3_sys_manager_power_off(void)
ps3_sys_manager_halt();
}
-void ps3_sys_manager_restart(void)
+void __noreturn ps3_sys_manager_restart(void)
{
if (ps3_sys_manager_ops.restart)
ps3_sys_manager_ops.restart(ps3_sys_manager_ops.dev);
@@ -63,7 +63,7 @@ void ps3_sys_manager_restart(void)
ps3_sys_manager_halt();
}
-void ps3_sys_manager_halt(void)
+void __noreturn ps3_sys_manager_halt(void)
{
pr_emerg("System Halted, OK to turn off power\n");
local_irq_disable();
diff --git a/drivers/ps3/vuart.h b/drivers/ps3/vuart.h
index eb7f6d94a890..23358b719319 100644
--- a/drivers/ps3/vuart.h
+++ b/drivers/ps3/vuart.h
@@ -82,4 +82,20 @@ void ps3_vuart_cancel_async(struct ps3_system_bus_device *dev);
void ps3_vuart_clear_rx_bytes(struct ps3_system_bus_device *dev,
unsigned int bytes);
+struct vuart_triggers {
+ unsigned long rx;
+ unsigned long tx;
+};
+
+int ps3_vuart_get_triggers(struct ps3_system_bus_device *dev,
+ struct vuart_triggers *trig);
+int ps3_vuart_set_triggers(struct ps3_system_bus_device *dev, unsigned int tx,
+ unsigned int rx);
+int ps3_vuart_enable_interrupt_tx(struct ps3_system_bus_device *dev);
+int ps3_vuart_disable_interrupt_tx(struct ps3_system_bus_device *dev);
+int ps3_vuart_enable_interrupt_rx(struct ps3_system_bus_device *dev);
+int ps3_vuart_disable_interrupt_rx(struct ps3_system_bus_device *dev);
+int ps3_vuart_enable_interrupt_disconnect(struct ps3_system_bus_device *dev);
+int ps3_vuart_disable_interrupt_disconnect(struct ps3_system_bus_device *dev);
+
#endif
diff --git a/drivers/pwm/Kconfig b/drivers/pwm/Kconfig
index a3ecf5809634..b1541f40fd8d 100644
--- a/drivers/pwm/Kconfig
+++ b/drivers/pwm/Kconfig
@@ -53,6 +53,7 @@ config PWM_ATMEL
config PWM_ATMEL_HLCDC_PWM
tristate "Atmel HLCDC PWM support"
depends on MFD_ATMEL_HLCDC
+ depends on HAVE_CLK
help
Generic PWM framework driver for the PWM output of the HLCDC
(Atmel High-end LCD Controller). This PWM output is mainly used
@@ -130,6 +131,19 @@ config PWM_FSL_FTM
To compile this driver as a module, choose M here: the module
will be called pwm-fsl-ftm.
+config PWM_IMG
+ tristate "Imagination Technologies PWM driver"
+ depends on HAS_IOMEM
+ depends on MFD_SYSCON
+ depends on COMMON_CLK
+ depends on MIPS || COMPILE_TEST
+ help
+ Generic PWM framework driver for Imagination Technologies
+ PWM block which supports 4 channels.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-img
+
config PWM_IMX
tristate "i.MX PWM support"
depends on ARCH_MXC
@@ -283,6 +297,16 @@ config PWM_STI
To compile this driver as a module, choose M here: the module
will be called pwm-sti.
+config PWM_SUN4I
+ tristate "Allwinner PWM support"
+ depends on ARCH_SUNXI || COMPILE_TEST
+ depends on HAS_IOMEM && COMMON_CLK
+ help
+ Generic PWM framework driver for Allwinner SoCs.
+
+ To compile this driver as a module, choose M here: the module
+ will be called pwm-sun4i.
+
config PWM_TEGRA
tristate "NVIDIA Tegra PWM support"
depends on ARCH_TEGRA
diff --git a/drivers/pwm/Makefile b/drivers/pwm/Makefile
index 65259ac1e8de..ec50eb5b5a8f 100644
--- a/drivers/pwm/Makefile
+++ b/drivers/pwm/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_PWM_BFIN) += pwm-bfin.o
obj-$(CONFIG_PWM_CLPS711X) += pwm-clps711x.o
obj-$(CONFIG_PWM_EP93XX) += pwm-ep93xx.o
obj-$(CONFIG_PWM_FSL_FTM) += pwm-fsl-ftm.o
+obj-$(CONFIG_PWM_IMG) += pwm-img.o
obj-$(CONFIG_PWM_IMX) += pwm-imx.o
obj-$(CONFIG_PWM_JZ4740) += pwm-jz4740.o
obj-$(CONFIG_PWM_LP3943) += pwm-lp3943.o
@@ -26,6 +27,7 @@ obj-$(CONFIG_PWM_ROCKCHIP) += pwm-rockchip.o
obj-$(CONFIG_PWM_SAMSUNG) += pwm-samsung.o
obj-$(CONFIG_PWM_SPEAR) += pwm-spear.o
obj-$(CONFIG_PWM_STI) += pwm-sti.o
+obj-$(CONFIG_PWM_SUN4I) += pwm-sun4i.o
obj-$(CONFIG_PWM_TEGRA) += pwm-tegra.o
obj-$(CONFIG_PWM_TIECAP) += pwm-tiecap.o
obj-$(CONFIG_PWM_TIEHRPWM) += pwm-tiehrpwm.o
diff --git a/drivers/pwm/core.c b/drivers/pwm/core.c
index 966497d10c6e..810aef3f4c3e 100644
--- a/drivers/pwm/core.c
+++ b/drivers/pwm/core.c
@@ -192,7 +192,7 @@ static void of_pwmchip_add(struct pwm_chip *chip)
static void of_pwmchip_remove(struct pwm_chip *chip)
{
- if (chip->dev && chip->dev->of_node)
+ if (chip->dev)
of_node_put(chip->dev->of_node);
}
diff --git a/drivers/pwm/pwm-atmel-hlcdc.c b/drivers/pwm/pwm-atmel-hlcdc.c
index e7a785fadcdf..522f7075bb1a 100644
--- a/drivers/pwm/pwm-atmel-hlcdc.c
+++ b/drivers/pwm/pwm-atmel-hlcdc.c
@@ -64,6 +64,9 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
if (!chip->errata || !chip->errata->slow_clk_erratum) {
clk_freq = clk_get_rate(new_clk);
+ if (!clk_freq)
+ return -EINVAL;
+
clk_period_ns = (u64)NSEC_PER_SEC * 256;
do_div(clk_period_ns, clk_freq);
}
@@ -73,6 +76,9 @@ static int atmel_hlcdc_pwm_config(struct pwm_chip *c,
clk_period_ns > period_ns) {
new_clk = hlcdc->sys_clk;
clk_freq = clk_get_rate(new_clk);
+ if (!clk_freq)
+ return -EINVAL;
+
clk_period_ns = (u64)NSEC_PER_SEC * 256;
do_div(clk_period_ns, clk_freq);
}
diff --git a/drivers/pwm/pwm-img.c b/drivers/pwm/pwm-img.c
new file mode 100644
index 000000000000..476171a768d6
--- /dev/null
+++ b/drivers/pwm/pwm-img.c
@@ -0,0 +1,249 @@
+/*
+ * Imagination Technologies Pulse Width Modulator driver
+ *
+ * Copyright (c) 2014-2015, Imagination Technologies
+ *
+ * Based on drivers/pwm/pwm-tegra.c, Copyright (c) 2010, NVIDIA 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+/* PWM registers */
+#define PWM_CTRL_CFG 0x0000
+#define PWM_CTRL_CFG_NO_SUB_DIV 0
+#define PWM_CTRL_CFG_SUB_DIV0 1
+#define PWM_CTRL_CFG_SUB_DIV1 2
+#define PWM_CTRL_CFG_SUB_DIV0_DIV1 3
+#define PWM_CTRL_CFG_DIV_SHIFT(ch) ((ch) * 2 + 4)
+#define PWM_CTRL_CFG_DIV_MASK 0x3
+
+#define PWM_CH_CFG(ch) (0x4 + (ch) * 4)
+#define PWM_CH_CFG_TMBASE_SHIFT 0
+#define PWM_CH_CFG_DUTY_SHIFT 16
+
+#define PERIP_PWM_PDM_CONTROL 0x0140
+#define PERIP_PWM_PDM_CONTROL_CH_MASK 0x1
+#define PERIP_PWM_PDM_CONTROL_CH_SHIFT(ch) ((ch) * 4)
+
+#define MAX_TMBASE_STEPS 65536
+
+struct img_pwm_chip {
+ struct device *dev;
+ struct pwm_chip chip;
+ struct clk *pwm_clk;
+ struct clk *sys_clk;
+ void __iomem *base;
+ struct regmap *periph_regs;
+};
+
+static inline struct img_pwm_chip *to_img_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct img_pwm_chip, chip);
+}
+
+static inline void img_pwm_writel(struct img_pwm_chip *chip,
+ u32 reg, u32 val)
+{
+ writel(val, chip->base + reg);
+}
+
+static inline u32 img_pwm_readl(struct img_pwm_chip *chip,
+ u32 reg)
+{
+ return readl(chip->base + reg);
+}
+
+static int img_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ u32 val, div, duty, timebase;
+ unsigned long mul, output_clk_hz, input_clk_hz;
+ struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
+
+ input_clk_hz = clk_get_rate(pwm_chip->pwm_clk);
+ output_clk_hz = DIV_ROUND_UP(NSEC_PER_SEC, period_ns);
+
+ mul = DIV_ROUND_UP(input_clk_hz, output_clk_hz);
+ if (mul <= MAX_TMBASE_STEPS) {
+ div = PWM_CTRL_CFG_NO_SUB_DIV;
+ timebase = DIV_ROUND_UP(mul, 1);
+ } else if (mul <= MAX_TMBASE_STEPS * 8) {
+ div = PWM_CTRL_CFG_SUB_DIV0;
+ timebase = DIV_ROUND_UP(mul, 8);
+ } else if (mul <= MAX_TMBASE_STEPS * 64) {
+ div = PWM_CTRL_CFG_SUB_DIV1;
+ timebase = DIV_ROUND_UP(mul, 64);
+ } else if (mul <= MAX_TMBASE_STEPS * 512) {
+ div = PWM_CTRL_CFG_SUB_DIV0_DIV1;
+ timebase = DIV_ROUND_UP(mul, 512);
+ } else if (mul > MAX_TMBASE_STEPS * 512) {
+ dev_err(chip->dev,
+ "failed to configure timebase steps/divider value\n");
+ return -EINVAL;
+ }
+
+ duty = DIV_ROUND_UP(timebase * duty_ns, period_ns);
+
+ val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
+ val &= ~(PWM_CTRL_CFG_DIV_MASK << PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm));
+ val |= (div & PWM_CTRL_CFG_DIV_MASK) <<
+ PWM_CTRL_CFG_DIV_SHIFT(pwm->hwpwm);
+ img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val);
+
+ val = (duty << PWM_CH_CFG_DUTY_SHIFT) |
+ (timebase << PWM_CH_CFG_TMBASE_SHIFT);
+ img_pwm_writel(pwm_chip, PWM_CH_CFG(pwm->hwpwm), val);
+
+ return 0;
+}
+
+static int img_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ u32 val;
+ struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
+
+ val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
+ val |= BIT(pwm->hwpwm);
+ img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val);
+
+ regmap_update_bits(pwm_chip->periph_regs, PERIP_PWM_PDM_CONTROL,
+ PERIP_PWM_PDM_CONTROL_CH_MASK <<
+ PERIP_PWM_PDM_CONTROL_CH_SHIFT(pwm->hwpwm), 0);
+
+ return 0;
+}
+
+static void img_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ u32 val;
+ struct img_pwm_chip *pwm_chip = to_img_pwm_chip(chip);
+
+ val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
+ val &= ~BIT(pwm->hwpwm);
+ img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val);
+}
+
+static const struct pwm_ops img_pwm_ops = {
+ .config = img_pwm_config,
+ .enable = img_pwm_enable,
+ .disable = img_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static int img_pwm_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct resource *res;
+ struct img_pwm_chip *pwm;
+
+ pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+ if (!pwm)
+ return -ENOMEM;
+
+ pwm->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pwm->base))
+ return PTR_ERR(pwm->base);
+
+ pwm->periph_regs = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "img,cr-periph");
+ if (IS_ERR(pwm->periph_regs))
+ return PTR_ERR(pwm->periph_regs);
+
+ pwm->sys_clk = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(pwm->sys_clk)) {
+ dev_err(&pdev->dev, "failed to get system clock\n");
+ return PTR_ERR(pwm->sys_clk);
+ }
+
+ pwm->pwm_clk = devm_clk_get(&pdev->dev, "pwm");
+ if (IS_ERR(pwm->pwm_clk)) {
+ dev_err(&pdev->dev, "failed to get pwm clock\n");
+ return PTR_ERR(pwm->pwm_clk);
+ }
+
+ ret = clk_prepare_enable(pwm->sys_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not prepare or enable sys clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(pwm->pwm_clk);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "could not prepare or enable pwm clock\n");
+ goto disable_sysclk;
+ }
+
+ pwm->chip.dev = &pdev->dev;
+ pwm->chip.ops = &img_pwm_ops;
+ pwm->chip.base = -1;
+ pwm->chip.npwm = 4;
+
+ ret = pwmchip_add(&pwm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "pwmchip_add failed: %d\n", ret);
+ goto disable_pwmclk;
+ }
+
+ platform_set_drvdata(pdev, pwm);
+ return 0;
+
+disable_pwmclk:
+ clk_disable_unprepare(pwm->pwm_clk);
+disable_sysclk:
+ clk_disable_unprepare(pwm->sys_clk);
+ return ret;
+}
+
+static int img_pwm_remove(struct platform_device *pdev)
+{
+ struct img_pwm_chip *pwm_chip = platform_get_drvdata(pdev);
+ u32 val;
+ unsigned int i;
+
+ for (i = 0; i < pwm_chip->chip.npwm; i++) {
+ val = img_pwm_readl(pwm_chip, PWM_CTRL_CFG);
+ val &= ~BIT(i);
+ img_pwm_writel(pwm_chip, PWM_CTRL_CFG, val);
+ }
+
+ clk_disable_unprepare(pwm_chip->pwm_clk);
+ clk_disable_unprepare(pwm_chip->sys_clk);
+
+ return pwmchip_remove(&pwm_chip->chip);
+}
+
+static const struct of_device_id img_pwm_of_match[] = {
+ { .compatible = "img,pistachio-pwm", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, img_pwm_of_match);
+
+static struct platform_driver img_pwm_driver = {
+ .driver = {
+ .name = "img-pwm",
+ .of_match_table = img_pwm_of_match,
+ },
+ .probe = img_pwm_probe,
+ .remove = img_pwm_remove,
+};
+module_platform_driver(img_pwm_driver);
+
+MODULE_AUTHOR("Sai Masarapu <Sai.Masarapu@imgtec.com>");
+MODULE_DESCRIPTION("Imagination Technologies PWM DAC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-sti.c b/drivers/pwm/pwm-sti.c
index b95115cdaea7..92abbd56b9f7 100644
--- a/drivers/pwm/pwm-sti.c
+++ b/drivers/pwm/pwm-sti.c
@@ -57,6 +57,7 @@ struct sti_pwm_chip {
struct regmap_field *pwm_int_en;
struct pwm_chip chip;
struct pwm_device *cur;
+ unsigned long configured;
unsigned int en_count;
struct mutex sti_pwm_lock; /* To sync between enable/disable calls */
void __iomem *mmio;
@@ -102,24 +103,6 @@ static int sti_pwm_get_prescale(struct sti_pwm_chip *pc, unsigned long period,
return 0;
}
-/* Calculate the number of PWM devices configured with a period. */
-static unsigned int sti_pwm_count_configured(struct pwm_chip *chip)
-{
- struct pwm_device *pwm;
- unsigned int ncfg = 0;
- unsigned int i;
-
- for (i = 0; i < chip->npwm; i++) {
- pwm = &chip->pwms[i];
- if (test_bit(PWMF_REQUESTED, &pwm->flags)) {
- if (pwm_get_period(pwm))
- ncfg++;
- }
- }
-
- return ncfg;
-}
-
/*
* For STiH4xx PWM IP, the PWM period is fixed to 256 local clock cycles.
* The only way to change the period (apart from changing the PWM input clock)
@@ -141,7 +124,7 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
unsigned int ncfg;
bool period_same = false;
- ncfg = sti_pwm_count_configured(chip);
+ ncfg = hweight_long(pc->configured);
if (ncfg)
period_same = (period_ns == pwm_get_period(cur));
@@ -197,6 +180,7 @@ static int sti_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
ret = regmap_field_write(pc->pwm_int_en, 0);
+ set_bit(pwm->hwpwm, &pc->configured);
pc->cur = pwm;
dev_dbg(dev, "prescale:%u, period:%i, duty:%i, pwmvalx:%u\n",
@@ -254,10 +238,18 @@ static void sti_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
mutex_unlock(&pc->sti_pwm_lock);
}
+static void sti_pwm_free(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct sti_pwm_chip *pc = to_sti_pwmchip(chip);
+
+ clear_bit(pwm->hwpwm, &pc->configured);
+}
+
static const struct pwm_ops sti_pwm_ops = {
.config = sti_pwm_config,
.enable = sti_pwm_enable,
.disable = sti_pwm_disable,
+ .free = sti_pwm_free,
.owner = THIS_MODULE,
};
diff --git a/drivers/pwm/pwm-sun4i.c b/drivers/pwm/pwm-sun4i.c
new file mode 100644
index 000000000000..cd9dde563018
--- /dev/null
+++ b/drivers/pwm/pwm-sun4i.c
@@ -0,0 +1,366 @@
+/*
+ * Driver for Allwinner sun4i Pulse Width Modulation Controller
+ *
+ * Copyright (C) 2014 Alexandre Belloni <alexandre.belloni@free-electrons.com>
+ *
+ * Licensed under GPLv2.
+ */
+
+#include <linux/bitops.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/pwm.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#define PWM_CTRL_REG 0x0
+
+#define PWM_CH_PRD_BASE 0x4
+#define PWM_CH_PRD_OFFSET 0x4
+#define PWM_CH_PRD(ch) (PWM_CH_PRD_BASE + PWM_CH_PRD_OFFSET * (ch))
+
+#define PWMCH_OFFSET 15
+#define PWM_PRESCAL_MASK GENMASK(3, 0)
+#define PWM_PRESCAL_OFF 0
+#define PWM_EN BIT(4)
+#define PWM_ACT_STATE BIT(5)
+#define PWM_CLK_GATING BIT(6)
+#define PWM_MODE BIT(7)
+#define PWM_PULSE BIT(8)
+#define PWM_BYPASS BIT(9)
+
+#define PWM_RDY_BASE 28
+#define PWM_RDY_OFFSET 1
+#define PWM_RDY(ch) BIT(PWM_RDY_BASE + PWM_RDY_OFFSET * (ch))
+
+#define PWM_PRD(prd) (((prd) - 1) << 16)
+#define PWM_PRD_MASK GENMASK(15, 0)
+
+#define PWM_DTY_MASK GENMASK(15, 0)
+
+#define BIT_CH(bit, chan) ((bit) << ((chan) * PWMCH_OFFSET))
+
+static const u32 prescaler_table[] = {
+ 120,
+ 180,
+ 240,
+ 360,
+ 480,
+ 0,
+ 0,
+ 0,
+ 12000,
+ 24000,
+ 36000,
+ 48000,
+ 72000,
+ 0,
+ 0,
+ 0, /* Actually 1 but tested separately */
+};
+
+struct sun4i_pwm_data {
+ bool has_prescaler_bypass;
+ bool has_rdy;
+};
+
+struct sun4i_pwm_chip {
+ struct pwm_chip chip;
+ struct clk *clk;
+ void __iomem *base;
+ spinlock_t ctrl_lock;
+ const struct sun4i_pwm_data *data;
+};
+
+static inline struct sun4i_pwm_chip *to_sun4i_pwm_chip(struct pwm_chip *chip)
+{
+ return container_of(chip, struct sun4i_pwm_chip, chip);
+}
+
+static inline u32 sun4i_pwm_readl(struct sun4i_pwm_chip *chip,
+ unsigned long offset)
+{
+ return readl(chip->base + offset);
+}
+
+static inline void sun4i_pwm_writel(struct sun4i_pwm_chip *chip,
+ u32 val, unsigned long offset)
+{
+ writel(val, chip->base + offset);
+}
+
+static int sun4i_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
+ int duty_ns, int period_ns)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 prd, dty, val, clk_gate;
+ u64 clk_rate, div = 0;
+ unsigned int prescaler = 0;
+ int err;
+
+ clk_rate = clk_get_rate(sun4i_pwm->clk);
+
+ if (sun4i_pwm->data->has_prescaler_bypass) {
+ /* First, test without any prescaler when available */
+ prescaler = PWM_PRESCAL_MASK;
+ /*
+ * When not using any prescaler, the clock period in nanoseconds
+ * is not an integer so round it half up instead of
+ * truncating to get less surprising values.
+ */
+ div = clk_rate * period_ns + NSEC_PER_SEC/2;
+ do_div(div, NSEC_PER_SEC);
+ if (div - 1 > PWM_PRD_MASK)
+ prescaler = 0;
+ }
+
+ if (prescaler == 0) {
+ /* Go up from the first divider */
+ for (prescaler = 0; prescaler < PWM_PRESCAL_MASK; prescaler++) {
+ if (!prescaler_table[prescaler])
+ continue;
+ div = clk_rate;
+ do_div(div, prescaler_table[prescaler]);
+ div = div * period_ns;
+ do_div(div, NSEC_PER_SEC);
+ if (div - 1 <= PWM_PRD_MASK)
+ break;
+ }
+
+ if (div - 1 > PWM_PRD_MASK) {
+ dev_err(chip->dev, "period exceeds the maximum value\n");
+ return -EINVAL;
+ }
+ }
+
+ prd = div;
+ div *= duty_ns;
+ do_div(div, period_ns);
+ dty = div;
+
+ err = clk_prepare_enable(sun4i_pwm->clk);
+ if (err) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return err;
+ }
+
+ spin_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+
+ if (sun4i_pwm->data->has_rdy && (val & PWM_RDY(pwm->hwpwm))) {
+ spin_unlock(&sun4i_pwm->ctrl_lock);
+ clk_disable_unprepare(sun4i_pwm->clk);
+ return -EBUSY;
+ }
+
+ clk_gate = val & BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+ if (clk_gate) {
+ val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ }
+
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val &= ~BIT_CH(PWM_PRESCAL_MASK, pwm->hwpwm);
+ val |= BIT_CH(prescaler, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+
+ val = (dty & PWM_DTY_MASK) | PWM_PRD(prd);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CH_PRD(pwm->hwpwm));
+
+ if (clk_gate) {
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val |= clk_gate;
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ }
+
+ spin_unlock(&sun4i_pwm->ctrl_lock);
+ clk_disable_unprepare(sun4i_pwm->clk);
+
+ return 0;
+}
+
+static int sun4i_pwm_set_polarity(struct pwm_chip *chip, struct pwm_device *pwm,
+ enum pwm_polarity polarity)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 val;
+ int ret;
+
+ ret = clk_prepare_enable(sun4i_pwm->clk);
+ if (ret) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return ret;
+ }
+
+ spin_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+
+ if (polarity != PWM_POLARITY_NORMAL)
+ val &= ~BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
+ else
+ val |= BIT_CH(PWM_ACT_STATE, pwm->hwpwm);
+
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+
+ spin_unlock(&sun4i_pwm->ctrl_lock);
+ clk_disable_unprepare(sun4i_pwm->clk);
+
+ return 0;
+}
+
+static int sun4i_pwm_enable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 val;
+ int ret;
+
+ ret = clk_prepare_enable(sun4i_pwm->clk);
+ if (ret) {
+ dev_err(chip->dev, "failed to enable PWM clock\n");
+ return ret;
+ }
+
+ spin_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val |= BIT_CH(PWM_EN, pwm->hwpwm);
+ val |= BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ spin_unlock(&sun4i_pwm->ctrl_lock);
+
+ return 0;
+}
+
+static void sun4i_pwm_disable(struct pwm_chip *chip, struct pwm_device *pwm)
+{
+ struct sun4i_pwm_chip *sun4i_pwm = to_sun4i_pwm_chip(chip);
+ u32 val;
+
+ spin_lock(&sun4i_pwm->ctrl_lock);
+ val = sun4i_pwm_readl(sun4i_pwm, PWM_CTRL_REG);
+ val &= ~BIT_CH(PWM_EN, pwm->hwpwm);
+ val &= ~BIT_CH(PWM_CLK_GATING, pwm->hwpwm);
+ sun4i_pwm_writel(sun4i_pwm, val, PWM_CTRL_REG);
+ spin_unlock(&sun4i_pwm->ctrl_lock);
+
+ clk_disable_unprepare(sun4i_pwm->clk);
+}
+
+static const struct pwm_ops sun4i_pwm_ops = {
+ .config = sun4i_pwm_config,
+ .set_polarity = sun4i_pwm_set_polarity,
+ .enable = sun4i_pwm_enable,
+ .disable = sun4i_pwm_disable,
+ .owner = THIS_MODULE,
+};
+
+static const struct sun4i_pwm_data sun4i_pwm_data_a10 = {
+ .has_prescaler_bypass = false,
+ .has_rdy = false,
+};
+
+static const struct sun4i_pwm_data sun4i_pwm_data_a20 = {
+ .has_prescaler_bypass = true,
+ .has_rdy = true,
+};
+
+static const struct of_device_id sun4i_pwm_dt_ids[] = {
+ {
+ .compatible = "allwinner,sun4i-a10-pwm",
+ .data = &sun4i_pwm_data_a10,
+ }, {
+ .compatible = "allwinner,sun7i-a20-pwm",
+ .data = &sun4i_pwm_data_a20,
+ }, {
+ /* sentinel */
+ },
+};
+MODULE_DEVICE_TABLE(of, sun4i_pwm_dt_ids);
+
+static int sun4i_pwm_probe(struct platform_device *pdev)
+{
+ struct sun4i_pwm_chip *pwm;
+ struct resource *res;
+ u32 val;
+ int i, ret;
+ const struct of_device_id *match;
+
+ match = of_match_device(sun4i_pwm_dt_ids, &pdev->dev);
+
+ pwm = devm_kzalloc(&pdev->dev, sizeof(*pwm), GFP_KERNEL);
+ if (!pwm)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pwm->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pwm->base))
+ return PTR_ERR(pwm->base);
+
+ pwm->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pwm->clk))
+ return PTR_ERR(pwm->clk);
+
+ pwm->chip.dev = &pdev->dev;
+ pwm->chip.ops = &sun4i_pwm_ops;
+ pwm->chip.base = -1;
+ pwm->chip.npwm = 2;
+ pwm->chip.can_sleep = true;
+ pwm->chip.of_xlate = of_pwm_xlate_with_flags;
+ pwm->chip.of_pwm_n_cells = 3;
+ pwm->data = match->data;
+
+ spin_lock_init(&pwm->ctrl_lock);
+
+ ret = pwmchip_add(&pwm->chip);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "failed to add PWM chip: %d\n", ret);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, pwm);
+
+ ret = clk_prepare_enable(pwm->clk);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to enable PWM clock\n");
+ goto clk_error;
+ }
+
+ val = sun4i_pwm_readl(pwm, PWM_CTRL_REG);
+ for (i = 0; i < pwm->chip.npwm; i++)
+ if (!(val & BIT_CH(PWM_ACT_STATE, i)))
+ pwm->chip.pwms[i].polarity = PWM_POLARITY_INVERSED;
+ clk_disable_unprepare(pwm->clk);
+
+ return 0;
+
+clk_error:
+ pwmchip_remove(&pwm->chip);
+ return ret;
+}
+
+static int sun4i_pwm_remove(struct platform_device *pdev)
+{
+ struct sun4i_pwm_chip *pwm = platform_get_drvdata(pdev);
+
+ return pwmchip_remove(&pwm->chip);
+}
+
+static struct platform_driver sun4i_pwm_driver = {
+ .driver = {
+ .name = "sun4i-pwm",
+ .of_match_table = sun4i_pwm_dt_ids,
+ },
+ .probe = sun4i_pwm_probe,
+ .remove = sun4i_pwm_remove,
+};
+module_platform_driver(sun4i_pwm_driver);
+
+MODULE_ALIAS("platform:sun4i-pwm");
+MODULE_AUTHOR("Alexandre Belloni <alexandre.belloni@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner sun4i PWM driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pwm/pwm-tegra.c b/drivers/pwm/pwm-tegra.c
index 5b97cae5423a..cabd7d8e05cc 100644
--- a/drivers/pwm/pwm-tegra.c
+++ b/drivers/pwm/pwm-tegra.c
@@ -87,7 +87,7 @@ static int tegra_pwm_config(struct pwm_chip *chip, struct pwm_device *pwm,
* cycles at the PWM clock rate will take period_ns nanoseconds.
*/
rate = clk_get_rate(pc->clk) >> PWM_DUTY_WIDTH;
- hz = 1000000000ul / period_ns;
+ hz = NSEC_PER_SEC / period_ns;
rate = (rate + (hz / 2)) / hz;
diff --git a/drivers/rapidio/devices/tsi721.c b/drivers/rapidio/devices/tsi721.c
index 8bcfecd66281..eeca70ddbf61 100644
--- a/drivers/rapidio/devices/tsi721.c
+++ b/drivers/rapidio/devices/tsi721.c
@@ -2430,7 +2430,7 @@ static int tsi721_probe(struct pci_dev *pdev,
pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL,
PCI_EXP_DEVCTL_READRQ | PCI_EXP_DEVCTL_RELAX_EN |
PCI_EXP_DEVCTL_NOSNOOP_EN,
- 0x2 << MAX_READ_REQUEST_SZ_SHIFT);
+ PCI_EXP_DEVCTL_READRQ_512B);
/* Adjust PCIe completion timeout. */
pcie_capability_clear_and_set_word(pdev, PCI_EXP_DEVCTL2, 0xf, 0x2);
diff --git a/drivers/rapidio/devices/tsi721.h b/drivers/rapidio/devices/tsi721.h
index a7b42680a06a..9d2502543ef6 100644
--- a/drivers/rapidio/devices/tsi721.h
+++ b/drivers/rapidio/devices/tsi721.h
@@ -72,8 +72,6 @@
#define TSI721_MSIXPBA_OFFSET 0x2a000
#define TSI721_PCIECFG_EPCTL 0x400
-#define MAX_READ_REQUEST_SZ_SHIFT 12
-
/*
* Event Management Registers
*/
diff --git a/drivers/rapidio/devices/tsi721_dma.c b/drivers/rapidio/devices/tsi721_dma.c
index f64c5decb747..47295940a868 100644
--- a/drivers/rapidio/devices/tsi721_dma.c
+++ b/drivers/rapidio/devices/tsi721_dma.c
@@ -815,8 +815,7 @@ struct dma_async_tx_descriptor *tsi721_prep_rio_sg(struct dma_chan *dchan,
return txd;
}
-static int tsi721_device_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
- unsigned long arg)
+static int tsi721_terminate_all(struct dma_chan *dchan)
{
struct tsi721_bdma_chan *bdma_chan = to_tsi721_chan(dchan);
struct tsi721_tx_desc *desc, *_d;
@@ -825,9 +824,6 @@ static int tsi721_device_control(struct dma_chan *dchan, enum dma_ctrl_cmd cmd,
dev_dbg(dchan->device->dev, "%s: Entry\n", __func__);
- if (cmd != DMA_TERMINATE_ALL)
- return -ENOSYS;
-
spin_lock_bh(&bdma_chan->lock);
bdma_chan->active = false;
@@ -901,7 +897,7 @@ int tsi721_register_dma(struct tsi721_device *priv)
mport->dma.device_tx_status = tsi721_tx_status;
mport->dma.device_issue_pending = tsi721_issue_pending;
mport->dma.device_prep_slave_sg = tsi721_prep_rio_sg;
- mport->dma.device_control = tsi721_device_control;
+ mport->dma.device_terminate_all = tsi721_terminate_all;
err = dma_async_device_register(&mport->dma);
if (err)
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index c3a60b57a865..a6f116aa5235 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -414,6 +414,14 @@ config REGULATOR_MAX77802
Exynos5420/Exynos5800 SoCs to control various voltages.
It includes support for control of voltage and ramp speed.
+config REGULATOR_MAX77843
+ tristate "Maxim 77843 regulator"
+ depends on MFD_MAX77843
+ help
+ This driver controls a Maxim 77843 regulator.
+ The regulator include two 'SAFEOUT' for USB(Universal Serial Bus)
+ This is suitable for Exynos5433 SoC chips.
+
config REGULATOR_MC13XXX_CORE
tristate
@@ -433,6 +441,15 @@ config REGULATOR_MC13892
Say y here to support the regulators found on the Freescale MC13892
PMIC.
+config REGULATOR_MT6397
+ tristate "MediaTek MT6397 PMIC"
+ depends on MFD_MT6397
+ help
+ Say y here to select this option to enable the power regulator of
+ MediaTek MT6397 PMIC.
+ This driver supports the control of different power rails of device
+ through regulator interface.
+
config REGULATOR_PALMAS
tristate "TI Palmas PMIC Regulators"
depends on MFD_PALMAS
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 1f28ebfc6f3a..2c4da15e1545 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -55,9 +55,11 @@ obj-$(CONFIG_REGULATOR_MAX8998) += max8998.o
obj-$(CONFIG_REGULATOR_MAX77686) += max77686.o
obj-$(CONFIG_REGULATOR_MAX77693) += max77693.o
obj-$(CONFIG_REGULATOR_MAX77802) += max77802.o
+obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o
obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o
obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o
obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o
+obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o
obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o
obj-$(CONFIG_REGULATOR_PALMAS) += palmas-regulator.o
obj-$(CONFIG_REGULATOR_PFUZE100) += pfuze100-regulator.o
diff --git a/drivers/regulator/axp20x-regulator.c b/drivers/regulator/axp20x-regulator.c
index f23d7e1f2ee7..e4331f5e5d7d 100644
--- a/drivers/regulator/axp20x-regulator.c
+++ b/drivers/regulator/axp20x-regulator.c
@@ -32,11 +32,13 @@
#define AXP20X_FREQ_DCDC_MASK 0x0f
-#define AXP20X_DESC_IO(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \
- _emask, _enable_val, _disable_val) \
+#define AXP20X_DESC_IO(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \
+ _ereg, _emask, _enable_val, _disable_val) \
[AXP20X_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
+ .of_match = of_match_ptr(_match), \
+ .regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = AXP20X_##_id, \
.n_voltages = (((_max) - (_min)) / (_step) + 1), \
@@ -52,11 +54,13 @@
.ops = &axp20x_ops, \
}
-#define AXP20X_DESC(_id, _supply, _min, _max, _step, _vreg, _vmask, _ereg, \
- _emask) \
+#define AXP20X_DESC(_id, _match, _supply, _min, _max, _step, _vreg, _vmask, \
+ _ereg, _emask) \
[AXP20X_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
+ .of_match = of_match_ptr(_match), \
+ .regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = AXP20X_##_id, \
.n_voltages = (((_max) - (_min)) / (_step) + 1), \
@@ -70,10 +74,12 @@
.ops = &axp20x_ops, \
}
-#define AXP20X_DESC_FIXED(_id, _supply, _volt) \
+#define AXP20X_DESC_FIXED(_id, _match, _supply, _volt) \
[AXP20X_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
+ .of_match = of_match_ptr(_match), \
+ .regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = AXP20X_##_id, \
.n_voltages = 1, \
@@ -82,10 +88,13 @@
.ops = &axp20x_ops_fixed \
}
-#define AXP20X_DESC_TABLE(_id, _supply, _table, _vreg, _vmask, _ereg, _emask) \
+#define AXP20X_DESC_TABLE(_id, _match, _supply, _table, _vreg, _vmask, _ereg, \
+ _emask) \
[AXP20X_##_id] = { \
.name = #_id, \
.supply_name = (_supply), \
+ .of_match = of_match_ptr(_match), \
+ .regulators_node = of_match_ptr("regulators"), \
.type = REGULATOR_VOLTAGE, \
.id = AXP20X_##_id, \
.n_voltages = ARRAY_SIZE(_table), \
@@ -127,36 +136,20 @@ static struct regulator_ops axp20x_ops = {
};
static const struct regulator_desc axp20x_regulators[] = {
- AXP20X_DESC(DCDC2, "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT, 0x3f,
- AXP20X_PWR_OUT_CTRL, 0x10),
- AXP20X_DESC(DCDC3, "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT, 0x7f,
- AXP20X_PWR_OUT_CTRL, 0x02),
- AXP20X_DESC_FIXED(LDO1, "acin", 1300),
- AXP20X_DESC(LDO2, "ldo24in", 1800, 3300, 100, AXP20X_LDO24_V_OUT, 0xf0,
- AXP20X_PWR_OUT_CTRL, 0x04),
- AXP20X_DESC(LDO3, "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT, 0x7f,
- AXP20X_PWR_OUT_CTRL, 0x40),
- AXP20X_DESC_TABLE(LDO4, "ldo24in", axp20x_ldo4_data, AXP20X_LDO24_V_OUT, 0x0f,
- AXP20X_PWR_OUT_CTRL, 0x08),
- AXP20X_DESC_IO(LDO5, "ldo5in", 1800, 3300, 100, AXP20X_LDO5_V_OUT, 0xf0,
- AXP20X_GPIO0_CTRL, 0x07, AXP20X_IO_ENABLED,
- AXP20X_IO_DISABLED),
-};
-
-#define AXP_MATCH(_name, _id) \
- [AXP20X_##_id] = { \
- .name = #_name, \
- .driver_data = (void *) &axp20x_regulators[AXP20X_##_id], \
- }
-
-static struct of_regulator_match axp20x_matches[] = {
- AXP_MATCH(dcdc2, DCDC2),
- AXP_MATCH(dcdc3, DCDC3),
- AXP_MATCH(ldo1, LDO1),
- AXP_MATCH(ldo2, LDO2),
- AXP_MATCH(ldo3, LDO3),
- AXP_MATCH(ldo4, LDO4),
- AXP_MATCH(ldo5, LDO5),
+ AXP20X_DESC(DCDC2, "dcdc2", "vin2", 700, 2275, 25, AXP20X_DCDC2_V_OUT,
+ 0x3f, AXP20X_PWR_OUT_CTRL, 0x10),
+ AXP20X_DESC(DCDC3, "dcdc3", "vin3", 700, 3500, 25, AXP20X_DCDC3_V_OUT,
+ 0x7f, AXP20X_PWR_OUT_CTRL, 0x02),
+ AXP20X_DESC_FIXED(LDO1, "ldo1", "acin", 1300),
+ AXP20X_DESC(LDO2, "ldo2", "ldo24in", 1800, 3300, 100,
+ AXP20X_LDO24_V_OUT, 0xf0, AXP20X_PWR_OUT_CTRL, 0x04),
+ AXP20X_DESC(LDO3, "ldo3", "ldo3in", 700, 3500, 25, AXP20X_LDO3_V_OUT,
+ 0x7f, AXP20X_PWR_OUT_CTRL, 0x40),
+ AXP20X_DESC_TABLE(LDO4, "ldo4", "ldo24in", axp20x_ldo4_data,
+ AXP20X_LDO24_V_OUT, 0x0f, AXP20X_PWR_OUT_CTRL, 0x08),
+ AXP20X_DESC_IO(LDO5, "ldo5", "ldo5in", 1800, 3300, 100,
+ AXP20X_LDO5_V_OUT, 0xf0, AXP20X_GPIO0_CTRL, 0x07,
+ AXP20X_IO_ENABLED, AXP20X_IO_DISABLED),
};
static int axp20x_set_dcdc_freq(struct platform_device *pdev, u32 dcdcfreq)
@@ -193,13 +186,6 @@ static int axp20x_regulator_parse_dt(struct platform_device *pdev)
if (!regulators) {
dev_warn(&pdev->dev, "regulators node not found\n");
} else {
- ret = of_regulator_match(&pdev->dev, regulators, axp20x_matches,
- ARRAY_SIZE(axp20x_matches));
- if (ret < 0) {
- dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
- return ret;
- }
-
dcdcfreq = 1500;
of_property_read_u32(regulators, "x-powers,dcdc-freq", &dcdcfreq);
ret = axp20x_set_dcdc_freq(pdev, dcdcfreq);
@@ -233,23 +219,17 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
{
struct regulator_dev *rdev;
struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
- struct regulator_config config = { };
- struct regulator_init_data *init_data;
+ struct regulator_config config = {
+ .dev = pdev->dev.parent,
+ .regmap = axp20x->regmap,
+ };
int ret, i;
u32 workmode;
- ret = axp20x_regulator_parse_dt(pdev);
- if (ret)
- return ret;
+ /* This only sets the dcdc freq. Ignore any errors */
+ axp20x_regulator_parse_dt(pdev);
for (i = 0; i < AXP20X_REG_ID_MAX; i++) {
- init_data = axp20x_matches[i].init_data;
-
- config.dev = pdev->dev.parent;
- config.init_data = init_data;
- config.regmap = axp20x->regmap;
- config.of_node = axp20x_matches[i].of_node;
-
rdev = devm_regulator_register(&pdev->dev, &axp20x_regulators[i],
&config);
if (IS_ERR(rdev)) {
@@ -259,7 +239,8 @@ static int axp20x_regulator_probe(struct platform_device *pdev)
return PTR_ERR(rdev);
}
- ret = of_property_read_u32(axp20x_matches[i].of_node, "x-powers,dcdc-workmode",
+ ret = of_property_read_u32(rdev->dev.of_node,
+ "x-powers,dcdc-workmode",
&workmode);
if (!ret) {
if (axp20x_set_dcdc_workmode(rdev, i, workmode))
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 9c48fb32f660..b899947d839d 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -632,49 +632,34 @@ static ssize_t regulator_bypass_show(struct device *dev,
static DEVICE_ATTR(bypass, 0444,
regulator_bypass_show, NULL);
-/*
- * These are the only attributes are present for all regulators.
- * Other attributes are a function of regulator functionality.
- */
-static struct attribute *regulator_dev_attrs[] = {
- &dev_attr_name.attr,
- &dev_attr_num_users.attr,
- &dev_attr_type.attr,
- NULL,
-};
-ATTRIBUTE_GROUPS(regulator_dev);
-
-static void regulator_dev_release(struct device *dev)
-{
- struct regulator_dev *rdev = dev_get_drvdata(dev);
- kfree(rdev);
-}
-
-static struct class regulator_class = {
- .name = "regulator",
- .dev_release = regulator_dev_release,
- .dev_groups = regulator_dev_groups,
-};
-
/* Calculate the new optimum regulator operating mode based on the new total
* consumer load. All locks held by caller */
-static void drms_uA_update(struct regulator_dev *rdev)
+static int drms_uA_update(struct regulator_dev *rdev)
{
struct regulator *sibling;
int current_uA = 0, output_uV, input_uV, err;
unsigned int mode;
+ /*
+ * first check to see if we can set modes at all, otherwise just
+ * tell the consumer everything is OK.
+ */
err = regulator_check_drms(rdev);
- if (err < 0 || !rdev->desc->ops->get_optimum_mode ||
- (!rdev->desc->ops->get_voltage &&
- !rdev->desc->ops->get_voltage_sel) ||
- !rdev->desc->ops->set_mode)
- return;
+ if (err < 0)
+ return 0;
+
+ if (!rdev->desc->ops->get_optimum_mode)
+ return 0;
+
+ if (!rdev->desc->ops->set_mode)
+ return -EINVAL;
/* get output voltage */
output_uV = _regulator_get_voltage(rdev);
- if (output_uV <= 0)
- return;
+ if (output_uV <= 0) {
+ rdev_err(rdev, "invalid output voltage found\n");
+ return -EINVAL;
+ }
/* get input voltage */
input_uV = 0;
@@ -682,8 +667,10 @@ static void drms_uA_update(struct regulator_dev *rdev)
input_uV = regulator_get_voltage(rdev->supply);
if (input_uV <= 0)
input_uV = rdev->constraints->input_uV;
- if (input_uV <= 0)
- return;
+ if (input_uV <= 0) {
+ rdev_err(rdev, "invalid input voltage found\n");
+ return -EINVAL;
+ }
/* calc total requested load */
list_for_each_entry(sibling, &rdev->consumer_list, list)
@@ -695,8 +682,17 @@ static void drms_uA_update(struct regulator_dev *rdev)
/* check the new mode is allowed */
err = regulator_mode_constrain(rdev, &mode);
- if (err == 0)
- rdev->desc->ops->set_mode(rdev, mode);
+ if (err < 0) {
+ rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
+ current_uA, input_uV, output_uV);
+ return err;
+ }
+
+ err = rdev->desc->ops->set_mode(rdev, mode);
+ if (err < 0)
+ rdev_err(rdev, "failed to set optimum mode %x\n", mode);
+
+ return err;
}
static int suspend_set_state(struct regulator_dev *rdev,
@@ -3026,75 +3022,13 @@ EXPORT_SYMBOL_GPL(regulator_get_mode);
int regulator_set_optimum_mode(struct regulator *regulator, int uA_load)
{
struct regulator_dev *rdev = regulator->rdev;
- struct regulator *consumer;
- int ret, output_uV, input_uV = 0, total_uA_load = 0;
- unsigned int mode;
-
- if (rdev->supply)
- input_uV = regulator_get_voltage(rdev->supply);
+ int ret;
mutex_lock(&rdev->mutex);
-
- /*
- * first check to see if we can set modes at all, otherwise just
- * tell the consumer everything is OK.
- */
regulator->uA_load = uA_load;
- ret = regulator_check_drms(rdev);
- if (ret < 0) {
- ret = 0;
- goto out;
- }
-
- if (!rdev->desc->ops->get_optimum_mode)
- goto out;
-
- /*
- * we can actually do this so any errors are indicators of
- * potential real failure.
- */
- ret = -EINVAL;
-
- if (!rdev->desc->ops->set_mode)
- goto out;
-
- /* get output voltage */
- output_uV = _regulator_get_voltage(rdev);
- if (output_uV <= 0) {
- rdev_err(rdev, "invalid output voltage found\n");
- goto out;
- }
-
- /* No supply? Use constraint voltage */
- if (input_uV <= 0)
- input_uV = rdev->constraints->input_uV;
- if (input_uV <= 0) {
- rdev_err(rdev, "invalid input voltage found\n");
- goto out;
- }
-
- /* calc total requested load for this regulator */
- list_for_each_entry(consumer, &rdev->consumer_list, list)
- total_uA_load += consumer->uA_load;
-
- mode = rdev->desc->ops->get_optimum_mode(rdev,
- input_uV, output_uV,
- total_uA_load);
- ret = regulator_mode_constrain(rdev, &mode);
- if (ret < 0) {
- rdev_err(rdev, "failed to get optimum mode @ %d uA %d -> %d uV\n",
- total_uA_load, input_uV, output_uV);
- goto out;
- }
-
- ret = rdev->desc->ops->set_mode(rdev, mode);
- if (ret < 0) {
- rdev_err(rdev, "failed to set optimum mode %x\n", mode);
- goto out;
- }
- ret = mode;
-out:
+ ret = drms_uA_update(rdev);
mutex_unlock(&rdev->mutex);
+
return ret;
}
EXPORT_SYMBOL_GPL(regulator_set_optimum_mode);
@@ -3436,126 +3370,136 @@ int regulator_mode_to_status(unsigned int mode)
}
EXPORT_SYMBOL_GPL(regulator_mode_to_status);
+static struct attribute *regulator_dev_attrs[] = {
+ &dev_attr_name.attr,
+ &dev_attr_num_users.attr,
+ &dev_attr_type.attr,
+ &dev_attr_microvolts.attr,
+ &dev_attr_microamps.attr,
+ &dev_attr_opmode.attr,
+ &dev_attr_state.attr,
+ &dev_attr_status.attr,
+ &dev_attr_bypass.attr,
+ &dev_attr_requested_microamps.attr,
+ &dev_attr_min_microvolts.attr,
+ &dev_attr_max_microvolts.attr,
+ &dev_attr_min_microamps.attr,
+ &dev_attr_max_microamps.attr,
+ &dev_attr_suspend_standby_state.attr,
+ &dev_attr_suspend_mem_state.attr,
+ &dev_attr_suspend_disk_state.attr,
+ &dev_attr_suspend_standby_microvolts.attr,
+ &dev_attr_suspend_mem_microvolts.attr,
+ &dev_attr_suspend_disk_microvolts.attr,
+ &dev_attr_suspend_standby_mode.attr,
+ &dev_attr_suspend_mem_mode.attr,
+ &dev_attr_suspend_disk_mode.attr,
+ NULL
+};
+
/*
* To avoid cluttering sysfs (and memory) with useless state, only
* create attributes that can be meaningfully displayed.
*/
-static int add_regulator_attributes(struct regulator_dev *rdev)
+static umode_t regulator_attr_is_visible(struct kobject *kobj,
+ struct attribute *attr, int idx)
{
- struct device *dev = &rdev->dev;
+ struct device *dev = kobj_to_dev(kobj);
+ struct regulator_dev *rdev = container_of(dev, struct regulator_dev, dev);
const struct regulator_ops *ops = rdev->desc->ops;
- int status = 0;
+ umode_t mode = attr->mode;
+
+ /* these three are always present */
+ if (attr == &dev_attr_name.attr ||
+ attr == &dev_attr_num_users.attr ||
+ attr == &dev_attr_type.attr)
+ return mode;
/* some attributes need specific methods to be displayed */
- if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
- (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) ||
- (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) ||
- (rdev->desc->fixed_uV && (rdev->desc->n_voltages == 1))) {
- status = device_create_file(dev, &dev_attr_microvolts);
- if (status < 0)
- return status;
- }
- if (ops->get_current_limit) {
- status = device_create_file(dev, &dev_attr_microamps);
- if (status < 0)
- return status;
- }
- if (ops->get_mode) {
- status = device_create_file(dev, &dev_attr_opmode);
- if (status < 0)
- return status;
- }
- if (rdev->ena_pin || ops->is_enabled) {
- status = device_create_file(dev, &dev_attr_state);
- if (status < 0)
- return status;
- }
- if (ops->get_status) {
- status = device_create_file(dev, &dev_attr_status);
- if (status < 0)
- return status;
- }
- if (ops->get_bypass) {
- status = device_create_file(dev, &dev_attr_bypass);
- if (status < 0)
- return status;
+ if (attr == &dev_attr_microvolts.attr) {
+ if ((ops->get_voltage && ops->get_voltage(rdev) >= 0) ||
+ (ops->get_voltage_sel && ops->get_voltage_sel(rdev) >= 0) ||
+ (ops->list_voltage && ops->list_voltage(rdev, 0) >= 0) ||
+ (rdev->desc->fixed_uV && rdev->desc->n_voltages == 1))
+ return mode;
+ return 0;
}
+ if (attr == &dev_attr_microamps.attr)
+ return ops->get_current_limit ? mode : 0;
+
+ if (attr == &dev_attr_opmode.attr)
+ return ops->get_mode ? mode : 0;
+
+ if (attr == &dev_attr_state.attr)
+ return (rdev->ena_pin || ops->is_enabled) ? mode : 0;
+
+ if (attr == &dev_attr_status.attr)
+ return ops->get_status ? mode : 0;
+
+ if (attr == &dev_attr_bypass.attr)
+ return ops->get_bypass ? mode : 0;
+
/* some attributes are type-specific */
- if (rdev->desc->type == REGULATOR_CURRENT) {
- status = device_create_file(dev, &dev_attr_requested_microamps);
- if (status < 0)
- return status;
- }
+ if (attr == &dev_attr_requested_microamps.attr)
+ return rdev->desc->type == REGULATOR_CURRENT ? mode : 0;
/* all the other attributes exist to support constraints;
* don't show them if there are no constraints, or if the
* relevant supporting methods are missing.
*/
if (!rdev->constraints)
- return status;
+ return 0;
/* constraints need specific supporting methods */
- if (ops->set_voltage || ops->set_voltage_sel) {
- status = device_create_file(dev, &dev_attr_min_microvolts);
- if (status < 0)
- return status;
- status = device_create_file(dev, &dev_attr_max_microvolts);
- if (status < 0)
- return status;
- }
- if (ops->set_current_limit) {
- status = device_create_file(dev, &dev_attr_min_microamps);
- if (status < 0)
- return status;
- status = device_create_file(dev, &dev_attr_max_microamps);
- if (status < 0)
- return status;
- }
-
- status = device_create_file(dev, &dev_attr_suspend_standby_state);
- if (status < 0)
- return status;
- status = device_create_file(dev, &dev_attr_suspend_mem_state);
- if (status < 0)
- return status;
- status = device_create_file(dev, &dev_attr_suspend_disk_state);
- if (status < 0)
- return status;
+ if (attr == &dev_attr_min_microvolts.attr ||
+ attr == &dev_attr_max_microvolts.attr)
+ return (ops->set_voltage || ops->set_voltage_sel) ? mode : 0;
+
+ if (attr == &dev_attr_min_microamps.attr ||
+ attr == &dev_attr_max_microamps.attr)
+ return ops->set_current_limit ? mode : 0;
- if (ops->set_suspend_voltage) {
- status = device_create_file(dev,
- &dev_attr_suspend_standby_microvolts);
- if (status < 0)
- return status;
- status = device_create_file(dev,
- &dev_attr_suspend_mem_microvolts);
- if (status < 0)
- return status;
- status = device_create_file(dev,
- &dev_attr_suspend_disk_microvolts);
- if (status < 0)
- return status;
- }
-
- if (ops->set_suspend_mode) {
- status = device_create_file(dev,
- &dev_attr_suspend_standby_mode);
- if (status < 0)
- return status;
- status = device_create_file(dev,
- &dev_attr_suspend_mem_mode);
- if (status < 0)
- return status;
- status = device_create_file(dev,
- &dev_attr_suspend_disk_mode);
- if (status < 0)
- return status;
- }
-
- return status;
+ if (attr == &dev_attr_suspend_standby_state.attr ||
+ attr == &dev_attr_suspend_mem_state.attr ||
+ attr == &dev_attr_suspend_disk_state.attr)
+ return mode;
+
+ if (attr == &dev_attr_suspend_standby_microvolts.attr ||
+ attr == &dev_attr_suspend_mem_microvolts.attr ||
+ attr == &dev_attr_suspend_disk_microvolts.attr)
+ return ops->set_suspend_voltage ? mode : 0;
+
+ if (attr == &dev_attr_suspend_standby_mode.attr ||
+ attr == &dev_attr_suspend_mem_mode.attr ||
+ attr == &dev_attr_suspend_disk_mode.attr)
+ return ops->set_suspend_mode ? mode : 0;
+
+ return mode;
}
+static const struct attribute_group regulator_dev_group = {
+ .attrs = regulator_dev_attrs,
+ .is_visible = regulator_attr_is_visible,
+};
+
+static const struct attribute_group *regulator_dev_groups[] = {
+ &regulator_dev_group,
+ NULL
+};
+
+static void regulator_dev_release(struct device *dev)
+{
+ struct regulator_dev *rdev = dev_get_drvdata(dev);
+ kfree(rdev);
+}
+
+static struct class regulator_class = {
+ .name = "regulator",
+ .dev_release = regulator_dev_release,
+ .dev_groups = regulator_dev_groups,
+};
+
static void rdev_init_debugfs(struct regulator_dev *rdev)
{
rdev->debugfs = debugfs_create_dir(rdev_get_name(rdev), debugfs_root);
@@ -3575,7 +3519,7 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
/**
* regulator_register - register regulator
* @regulator_desc: regulator to register
- * @config: runtime configuration for regulator
+ * @cfg: runtime configuration for regulator
*
* Called by regulator drivers to register a regulator.
* Returns a valid pointer to struct regulator_dev on success
@@ -3583,20 +3527,21 @@ static void rdev_init_debugfs(struct regulator_dev *rdev)
*/
struct regulator_dev *
regulator_register(const struct regulator_desc *regulator_desc,
- const struct regulator_config *config)
+ const struct regulator_config *cfg)
{
const struct regulation_constraints *constraints = NULL;
const struct regulator_init_data *init_data;
- static atomic_t regulator_no = ATOMIC_INIT(0);
+ struct regulator_config *config = NULL;
+ static atomic_t regulator_no = ATOMIC_INIT(-1);
struct regulator_dev *rdev;
struct device *dev;
int ret, i;
const char *supply = NULL;
- if (regulator_desc == NULL || config == NULL)
+ if (regulator_desc == NULL || cfg == NULL)
return ERR_PTR(-EINVAL);
- dev = config->dev;
+ dev = cfg->dev;
WARN_ON(!dev);
if (regulator_desc->name == NULL || regulator_desc->ops == NULL)
@@ -3626,7 +3571,17 @@ regulator_register(const struct regulator_desc *regulator_desc,
if (rdev == NULL)
return ERR_PTR(-ENOMEM);
- init_data = regulator_of_get_init_data(dev, regulator_desc,
+ /*
+ * Duplicate the config so the driver could override it after
+ * parsing init data.
+ */
+ config = kmemdup(cfg, sizeof(*cfg), GFP_KERNEL);
+ if (config == NULL) {
+ kfree(rdev);
+ return ERR_PTR(-ENOMEM);
+ }
+
+ init_data = regulator_of_get_init_data(dev, regulator_desc, config,
&rdev->dev.of_node);
if (!init_data) {
init_data = config->init_data;
@@ -3660,8 +3615,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
/* register with sysfs */
rdev->dev.class = &regulator_class;
rdev->dev.parent = dev;
- dev_set_name(&rdev->dev, "regulator.%d",
- atomic_inc_return(&regulator_no) - 1);
+ dev_set_name(&rdev->dev, "regulator.%lu",
+ (unsigned long) atomic_inc_return(&regulator_no));
ret = device_register(&rdev->dev);
if (ret != 0) {
put_device(&rdev->dev);
@@ -3694,11 +3649,6 @@ regulator_register(const struct regulator_desc *regulator_desc,
if (ret < 0)
goto scrub;
- /* add attributes supported by this regulator */
- ret = add_regulator_attributes(rdev);
- if (ret < 0)
- goto scrub;
-
if (init_data && init_data->supply_regulator)
supply = init_data->supply_regulator;
else if (regulator_desc->supply_name)
@@ -3754,6 +3704,7 @@ add_dev:
rdev_init_debugfs(rdev);
out:
mutex_unlock(&regulator_list_mutex);
+ kfree(config);
return rdev;
unset_supplies:
diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c
index c78d2106d6cb..01343419555e 100644
--- a/drivers/regulator/da9211-regulator.c
+++ b/drivers/regulator/da9211-regulator.c
@@ -24,6 +24,7 @@
#include <linux/regmap.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
+#include <linux/of_gpio.h>
#include <linux/regulator/of_regulator.h>
#include <linux/regulator/da9211.h>
#include "da9211-regulator.h"
@@ -276,7 +277,10 @@ static struct da9211_pdata *da9211_parse_regulators_dt(
continue;
pdata->init_data[n] = da9211_matches[i].init_data;
-
+ pdata->reg_node[n] = da9211_matches[i].of_node;
+ pdata->gpio_ren[n] =
+ of_get_named_gpio(da9211_matches[i].of_node,
+ "enable-gpios", 0);
n++;
}
@@ -364,7 +368,15 @@ static int da9211_regulator_init(struct da9211 *chip)
config.dev = chip->dev;
config.driver_data = chip;
config.regmap = chip->regmap;
- config.of_node = chip->dev->of_node;
+ config.of_node = chip->pdata->reg_node[i];
+
+ if (gpio_is_valid(chip->pdata->gpio_ren[i])) {
+ config.ena_gpio = chip->pdata->gpio_ren[i];
+ config.ena_gpio_initialized = true;
+ } else {
+ config.ena_gpio = -EINVAL;
+ config.ena_gpio_initialized = false;
+ }
chip->rdev[i] = devm_regulator_register(chip->dev,
&da9211_regulators[i], &config);
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index 6c43ab2d5121..3c25db89a021 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -147,7 +147,7 @@ static unsigned int fan53555_get_mode(struct regulator_dev *rdev)
return REGULATOR_MODE_NORMAL;
}
-static int slew_rates[] = {
+static const int slew_rates[] = {
64000,
32000,
16000,
@@ -296,7 +296,7 @@ static int fan53555_regulator_register(struct fan53555_device_info *di,
return PTR_ERR_OR_ZERO(di->rdev);
}
-static struct regmap_config fan53555_regmap_config = {
+static const struct regmap_config fan53555_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
diff --git a/drivers/regulator/internal.h b/drivers/regulator/internal.h
index 80ba2a35a04b..c74ac8734023 100644
--- a/drivers/regulator/internal.h
+++ b/drivers/regulator/internal.h
@@ -38,11 +38,13 @@ struct regulator {
#ifdef CONFIG_OF
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
+ struct regulator_config *config,
struct device_node **node);
#else
static inline struct regulator_init_data *
regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
+ struct regulator_config *config,
struct device_node **node)
{
return NULL;
diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c
index 92fefd98da58..6e3a15fe00f1 100644
--- a/drivers/regulator/isl9305.c
+++ b/drivers/regulator/isl9305.c
@@ -177,8 +177,10 @@ static int isl9305_i2c_probe(struct i2c_client *i2c,
#ifdef CONFIG_OF
static const struct of_device_id isl9305_dt_ids[] = {
- { .compatible = "isl,isl9305" },
- { .compatible = "isl,isl9305h" },
+ { .compatible = "isl,isl9305" }, /* for backward compat., don't use */
+ { .compatible = "isil,isl9305" },
+ { .compatible = "isl,isl9305h" }, /* for backward compat., don't use */
+ { .compatible = "isil,isl9305h" },
{},
};
#endif
diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c
index 021d64d856bb..3de328ab41f3 100644
--- a/drivers/regulator/lp872x.c
+++ b/drivers/regulator/lp872x.c
@@ -106,7 +106,6 @@ struct lp872x {
struct device *dev;
enum lp872x_id chipid;
struct lp872x_platform_data *pdata;
- struct regulator_dev **regulators;
int num_regulators;
enum lp872x_dvs_state dvs_pin;
int dvs_gpio;
@@ -801,8 +800,6 @@ static int lp872x_regulator_register(struct lp872x *lp)
dev_err(lp->dev, "regulator register err");
return PTR_ERR(rdev);
}
-
- *(lp->regulators + i) = rdev;
}
return 0;
@@ -906,7 +903,7 @@ static struct lp872x_platform_data
static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
struct lp872x *lp;
- int ret, size, num_regulators;
+ int ret;
const int lp872x_num_regulators[] = {
[LP8720] = LP8720_NUM_REGULATORS,
[LP8725] = LP8725_NUM_REGULATORS,
@@ -918,38 +915,27 @@ static int lp872x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
lp = devm_kzalloc(&cl->dev, sizeof(struct lp872x), GFP_KERNEL);
if (!lp)
- goto err_mem;
-
- num_regulators = lp872x_num_regulators[id->driver_data];
- size = sizeof(struct regulator_dev *) * num_regulators;
+ return -ENOMEM;
- lp->regulators = devm_kzalloc(&cl->dev, size, GFP_KERNEL);
- if (!lp->regulators)
- goto err_mem;
+ lp->num_regulators = lp872x_num_regulators[id->driver_data];
lp->regmap = devm_regmap_init_i2c(cl, &lp872x_regmap_config);
if (IS_ERR(lp->regmap)) {
ret = PTR_ERR(lp->regmap);
dev_err(&cl->dev, "regmap init i2c err: %d\n", ret);
- goto err_dev;
+ return ret;
}
lp->dev = &cl->dev;
lp->pdata = dev_get_platdata(&cl->dev);
lp->chipid = id->driver_data;
- lp->num_regulators = num_regulators;
i2c_set_clientdata(cl, lp);
ret = lp872x_config(lp);
if (ret)
- goto err_dev;
+ return ret;
return lp872x_regulator_register(lp);
-
-err_mem:
- return -ENOMEM;
-err_dev:
- return ret;
}
static const struct of_device_id lp872x_dt_ids[] = {
diff --git a/drivers/regulator/max14577.c b/drivers/regulator/max14577.c
index bf9a44c5fdd2..b3678d289619 100644
--- a/drivers/regulator/max14577.c
+++ b/drivers/regulator/max14577.c
@@ -103,6 +103,8 @@ static struct regulator_ops max14577_charger_ops = {
static const struct regulator_desc max14577_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
+ .of_match = of_match_ptr("SAFEOUT"),
+ .regulators_node = of_match_ptr("regulators"),
.id = MAX14577_SAFEOUT,
.ops = &max14577_safeout_ops,
.type = REGULATOR_VOLTAGE,
@@ -114,6 +116,8 @@ static const struct regulator_desc max14577_supported_regulators[] = {
},
[MAX14577_CHARGER] = {
.name = "CHARGER",
+ .of_match = of_match_ptr("CHARGER"),
+ .regulators_node = of_match_ptr("regulators"),
.id = MAX14577_CHARGER,
.ops = &max14577_charger_ops,
.type = REGULATOR_CURRENT,
@@ -137,6 +141,8 @@ static struct regulator_ops max77836_ldo_ops = {
static const struct regulator_desc max77836_supported_regulators[] = {
[MAX14577_SAFEOUT] = {
.name = "SAFEOUT",
+ .of_match = of_match_ptr("SAFEOUT"),
+ .regulators_node = of_match_ptr("regulators"),
.id = MAX14577_SAFEOUT,
.ops = &max14577_safeout_ops,
.type = REGULATOR_VOLTAGE,
@@ -148,6 +154,8 @@ static const struct regulator_desc max77836_supported_regulators[] = {
},
[MAX14577_CHARGER] = {
.name = "CHARGER",
+ .of_match = of_match_ptr("CHARGER"),
+ .regulators_node = of_match_ptr("regulators"),
.id = MAX14577_CHARGER,
.ops = &max14577_charger_ops,
.type = REGULATOR_CURRENT,
@@ -157,6 +165,8 @@ static const struct regulator_desc max77836_supported_regulators[] = {
},
[MAX77836_LDO1] = {
.name = "LDO1",
+ .of_match = of_match_ptr("LDO1"),
+ .regulators_node = of_match_ptr("regulators"),
.id = MAX77836_LDO1,
.ops = &max77836_ldo_ops,
.type = REGULATOR_VOLTAGE,
@@ -171,6 +181,8 @@ static const struct regulator_desc max77836_supported_regulators[] = {
},
[MAX77836_LDO2] = {
.name = "LDO2",
+ .of_match = of_match_ptr("LDO2"),
+ .regulators_node = of_match_ptr("regulators"),
.id = MAX77836_LDO2,
.ops = &max77836_ldo_ops,
.type = REGULATOR_VOLTAGE,
@@ -198,43 +210,6 @@ static struct of_regulator_match max77836_regulator_matches[] = {
{ .name = "LDO2", },
};
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
- enum maxim_device_type dev_type)
-{
- int ret;
- struct device_node *np;
- struct of_regulator_match *regulator_matches;
- unsigned int regulator_matches_size;
-
- np = of_get_child_by_name(pdev->dev.parent->of_node, "regulators");
- if (!np) {
- dev_err(&pdev->dev, "Failed to get child OF node for regulators\n");
- return -EINVAL;
- }
-
- switch (dev_type) {
- case MAXIM_DEVICE_TYPE_MAX77836:
- regulator_matches = max77836_regulator_matches;
- regulator_matches_size = ARRAY_SIZE(max77836_regulator_matches);
- break;
- case MAXIM_DEVICE_TYPE_MAX14577:
- default:
- regulator_matches = max14577_regulator_matches;
- regulator_matches_size = ARRAY_SIZE(max14577_regulator_matches);
- }
-
- ret = of_regulator_match(&pdev->dev, np, regulator_matches,
- regulator_matches_size);
- if (ret < 0)
- dev_err(&pdev->dev, "Error parsing regulator init data: %d\n", ret);
- else
- ret = 0;
-
- of_node_put(np);
-
- return ret;
-}
-
static inline struct regulator_init_data *match_init_data(int index,
enum maxim_device_type dev_type)
{
@@ -261,11 +236,6 @@ static inline struct device_node *match_of_node(int index,
}
}
#else /* CONFIG_OF */
-static int max14577_regulator_dt_parse_pdata(struct platform_device *pdev,
- enum maxim_device_type dev_type)
-{
- return 0;
-}
static inline struct regulator_init_data *match_init_data(int index,
enum maxim_device_type dev_type)
{
@@ -308,16 +278,12 @@ static int max14577_regulator_probe(struct platform_device *pdev)
{
struct max14577 *max14577 = dev_get_drvdata(pdev->dev.parent);
struct max14577_platform_data *pdata = dev_get_platdata(max14577->dev);
- int i, ret;
+ int i, ret = 0;
struct regulator_config config = {};
const struct regulator_desc *supported_regulators;
unsigned int supported_regulators_size;
enum maxim_device_type dev_type = max14577->dev_type;
- ret = max14577_regulator_dt_parse_pdata(pdev, dev_type);
- if (ret)
- return ret;
-
switch (dev_type) {
case MAXIM_DEVICE_TYPE_MAX77836:
supported_regulators = max77836_supported_regulators;
@@ -329,7 +295,7 @@ static int max14577_regulator_probe(struct platform_device *pdev)
supported_regulators_size = ARRAY_SIZE(max14577_supported_regulators);
}
- config.dev = &pdev->dev;
+ config.dev = max14577->dev;
config.driver_data = max14577;
for (i = 0; i < supported_regulators_size; i++) {
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index 10d206266ac2..15fb1416bfbd 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -26,6 +26,7 @@
#include <linux/bug.h>
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/of_gpio.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/regulator/driver.h>
@@ -46,6 +47,11 @@
#define MAX77686_DVS_UVSTEP 12500
/*
+ * Value for configuring buck[89] and LDO{20,21,22} as GPIO control.
+ * It is the same as 'off' for other regulators.
+ */
+#define MAX77686_GPIO_CONTROL 0x0
+/*
* Values used for configuring LDOs and bucks.
* Forcing low power mode: LDO1, 3-5, 9, 13, 17-26
*/
@@ -82,6 +88,8 @@ enum max77686_ramp_rate {
};
struct max77686_data {
+ u64 gpio_enabled:MAX77686_REGULATORS;
+
/* Array indexed by regulator id */
unsigned int opmode[MAX77686_REGULATORS];
};
@@ -100,6 +108,26 @@ static unsigned int max77686_get_opmode_shift(int id)
}
}
+/*
+ * When regulator is configured for GPIO control then it
+ * replaces "normal" mode. Any change from low power mode to normal
+ * should actually change to GPIO control.
+ * Map normal mode to proper value for such regulators.
+ */
+static unsigned int max77686_map_normal_mode(struct max77686_data *max77686,
+ int id)
+{
+ switch (id) {
+ case MAX77686_BUCK8:
+ case MAX77686_BUCK9:
+ case MAX77686_LDO20 ... MAX77686_LDO22:
+ if (max77686->gpio_enabled & (1 << id))
+ return MAX77686_GPIO_CONTROL;
+ }
+
+ return MAX77686_NORMAL;
+}
+
/* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */
static int max77686_set_suspend_disable(struct regulator_dev *rdev)
{
@@ -136,7 +164,7 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
val = MAX77686_LDO_LOWPOWER_PWRREQ;
break;
case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
- val = MAX77686_NORMAL;
+ val = max77686_map_normal_mode(max77686, id);
break;
default:
pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n",
@@ -160,7 +188,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
{
unsigned int val;
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
- int ret;
+ int ret, id = rdev_get_id(rdev);
switch (mode) {
case REGULATOR_MODE_STANDBY: /* switch off */
@@ -170,7 +198,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
val = MAX77686_LDO_LOWPOWER_PWRREQ;
break;
case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
- val = MAX77686_NORMAL;
+ val = max77686_map_normal_mode(max77686, id);
break;
default:
pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n",
@@ -184,7 +212,7 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
if (ret)
return ret;
- max77686->opmode[rdev_get_id(rdev)] = val;
+ max77686->opmode[id] = val;
return 0;
}
@@ -197,7 +225,7 @@ static int max77686_enable(struct regulator_dev *rdev)
shift = max77686_get_opmode_shift(id);
if (max77686->opmode[id] == MAX77686_OFF_PWRREQ)
- max77686->opmode[id] = MAX77686_NORMAL;
+ max77686->opmode[id] = max77686_map_normal_mode(max77686, id);
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
@@ -229,6 +257,36 @@ static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
MAX77686_RAMP_RATE_MASK, ramp_value << 6);
}
+static int max77686_of_parse_cb(struct device_node *np,
+ const struct regulator_desc *desc,
+ struct regulator_config *config)
+{
+ struct max77686_data *max77686 = config->driver_data;
+
+ switch (desc->id) {
+ case MAX77686_BUCK8:
+ case MAX77686_BUCK9:
+ case MAX77686_LDO20 ... MAX77686_LDO22:
+ config->ena_gpio = of_get_named_gpio(np,
+ "maxim,ena-gpios", 0);
+ config->ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+ config->ena_gpio_initialized = true;
+ break;
+ default:
+ return 0;
+ }
+
+ if (gpio_is_valid(config->ena_gpio)) {
+ max77686->gpio_enabled |= (1 << desc->id);
+
+ return regmap_update_bits(config->regmap, desc->enable_reg,
+ desc->enable_mask,
+ MAX77686_GPIO_CONTROL);
+ }
+
+ return 0;
+}
+
static struct regulator_ops max77686_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
@@ -283,6 +341,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
.name = "LDO"#num, \
.of_match = of_match_ptr("LDO"#num), \
.regulators_node = of_match_ptr("voltage-regulators"), \
+ .of_parse_cb = max77686_of_parse_cb, \
.id = MAX77686_LDO##num, \
.ops = &max77686_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -355,6 +414,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
.name = "BUCK"#num, \
.of_match = of_match_ptr("BUCK"#num), \
.regulators_node = of_match_ptr("voltage-regulators"), \
+ .of_parse_cb = max77686_of_parse_cb, \
.id = MAX77686_BUCK##num, \
.ops = &max77686_ops, \
.type = REGULATOR_VOLTAGE, \
diff --git a/drivers/regulator/max77843.c b/drivers/regulator/max77843.c
new file mode 100644
index 000000000000..c132ef527cdd
--- /dev/null
+++ b/drivers/regulator/max77843.c
@@ -0,0 +1,227 @@
+/*
+ * max77843.c - Regulator driver for the Maxim MAX77843
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ * Author: Jaewon Kim <jaewon02.kim@samsung.com>
+ * 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 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/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/mfd/max77843-private.h>
+#include <linux/regulator/of_regulator.h>
+
+enum max77843_regulator_type {
+ MAX77843_SAFEOUT1 = 0,
+ MAX77843_SAFEOUT2,
+ MAX77843_CHARGER,
+
+ MAX77843_NUM,
+};
+
+static const unsigned int max77843_safeout_voltage_table[] = {
+ 4850000,
+ 4900000,
+ 4950000,
+ 3300000,
+};
+
+static int max77843_reg_is_enabled(struct regulator_dev *rdev)
+{
+ struct regmap *regmap = rdev->regmap;
+ int ret;
+ unsigned int reg;
+
+ ret = regmap_read(regmap, rdev->desc->enable_reg, &reg);
+ if (ret) {
+ dev_err(&rdev->dev, "Fialed to read charger register\n");
+ return ret;
+ }
+
+ return (reg & rdev->desc->enable_mask) == rdev->desc->enable_mask;
+}
+
+static int max77843_reg_get_current_limit(struct regulator_dev *rdev)
+{
+ struct regmap *regmap = rdev->regmap;
+ unsigned int chg_min_uA = rdev->constraints->min_uA;
+ unsigned int chg_max_uA = rdev->constraints->max_uA;
+ unsigned int val;
+ int ret;
+ unsigned int reg, sel;
+
+ ret = regmap_read(regmap, MAX77843_CHG_REG_CHG_CNFG_02, &reg);
+ if (ret) {
+ dev_err(&rdev->dev, "Failed to read charger register\n");
+ return ret;
+ }
+
+ sel = reg & MAX77843_CHG_FAST_CHG_CURRENT_MASK;
+
+ if (sel < 0x03)
+ sel = 0;
+ else
+ sel -= 2;
+
+ val = chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel;
+ if (val > chg_max_uA)
+ return -EINVAL;
+
+ return val;
+}
+
+static int max77843_reg_set_current_limit(struct regulator_dev *rdev,
+ int min_uA, int max_uA)
+{
+ struct regmap *regmap = rdev->regmap;
+ unsigned int chg_min_uA = rdev->constraints->min_uA;
+ int sel = 0;
+
+ while (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel < min_uA)
+ sel++;
+
+ if (chg_min_uA + MAX77843_CHG_FAST_CHG_CURRENT_STEP * sel > max_uA)
+ return -EINVAL;
+
+ sel += 2;
+
+ return regmap_write(regmap, MAX77843_CHG_REG_CHG_CNFG_02, sel);
+}
+
+static struct regulator_ops max77843_charger_ops = {
+ .is_enabled = max77843_reg_is_enabled,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .get_current_limit = max77843_reg_get_current_limit,
+ .set_current_limit = max77843_reg_set_current_limit,
+};
+
+static struct regulator_ops max77843_regulator_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .list_voltage = regulator_list_voltage_table,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc max77843_supported_regulators[] = {
+ [MAX77843_SAFEOUT1] = {
+ .name = "SAFEOUT1",
+ .id = MAX77843_SAFEOUT1,
+ .ops = &max77843_regulator_ops,
+ .of_match = of_match_ptr("SAFEOUT1"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(max77843_safeout_voltage_table),
+ .volt_table = max77843_safeout_voltage_table,
+ .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL,
+ .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT1,
+ .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL,
+ .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT1_MASK,
+ },
+ [MAX77843_SAFEOUT2] = {
+ .name = "SAFEOUT2",
+ .id = MAX77843_SAFEOUT2,
+ .ops = &max77843_regulator_ops,
+ .of_match = of_match_ptr("SAFEOUT2"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = ARRAY_SIZE(max77843_safeout_voltage_table),
+ .volt_table = max77843_safeout_voltage_table,
+ .enable_reg = MAX77843_SYS_REG_SAFEOUTCTRL,
+ .enable_mask = MAX77843_REG_SAFEOUTCTRL_ENSAFEOUT2,
+ .vsel_reg = MAX77843_SYS_REG_SAFEOUTCTRL,
+ .vsel_mask = MAX77843_REG_SAFEOUTCTRL_SAFEOUT2_MASK,
+ },
+ [MAX77843_CHARGER] = {
+ .name = "CHARGER",
+ .id = MAX77843_CHARGER,
+ .ops = &max77843_charger_ops,
+ .of_match = of_match_ptr("CHARGER"),
+ .regulators_node = of_match_ptr("regulators"),
+ .type = REGULATOR_CURRENT,
+ .owner = THIS_MODULE,
+ .enable_reg = MAX77843_CHG_REG_CHG_CNFG_00,
+ .enable_mask = MAX77843_CHG_MASK,
+ },
+};
+
+static struct regmap *max77843_get_regmap(struct max77843 *max77843, int reg_id)
+{
+ switch (reg_id) {
+ case MAX77843_SAFEOUT1:
+ case MAX77843_SAFEOUT2:
+ return max77843->regmap;
+ case MAX77843_CHARGER:
+ return max77843->regmap_chg;
+ default:
+ return max77843->regmap;
+ }
+}
+
+static int max77843_regulator_probe(struct platform_device *pdev)
+{
+ struct max77843 *max77843 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = {};
+ int i;
+
+ config.dev = max77843->dev;
+ config.driver_data = max77843;
+
+ for (i = 0; i < ARRAY_SIZE(max77843_supported_regulators); i++) {
+ struct regulator_dev *regulator;
+
+ config.regmap = max77843_get_regmap(max77843,
+ max77843_supported_regulators[i].id);
+
+ regulator = devm_regulator_register(&pdev->dev,
+ &max77843_supported_regulators[i], &config);
+ if (IS_ERR(regulator)) {
+ dev_err(&pdev->dev,
+ "Failed to regiser regulator-%d\n", i);
+ return PTR_ERR(regulator);
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id max77843_regulator_id[] = {
+ { "max77843-regulator", },
+ { /* sentinel */ },
+};
+
+static struct platform_driver max77843_regulator_driver = {
+ .driver = {
+ .name = "max77843-regulator",
+ },
+ .probe = max77843_regulator_probe,
+ .id_table = max77843_regulator_id,
+};
+
+static int __init max77843_regulator_init(void)
+{
+ return platform_driver_register(&max77843_regulator_driver);
+}
+subsys_initcall(max77843_regulator_init);
+
+static void __exit max77843_regulator_exit(void)
+{
+ platform_driver_unregister(&max77843_regulator_driver);
+}
+module_exit(max77843_regulator_exit);
+
+MODULE_AUTHOR("Jaewon Kim <jaewon02.kim@samsung.com>");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_DESCRIPTION("Maxim MAX77843 regulator driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/max8649.c b/drivers/regulator/max8649.c
index c8bddcc8f911..81229579ece9 100644
--- a/drivers/regulator/max8649.c
+++ b/drivers/regulator/max8649.c
@@ -115,7 +115,7 @@ static unsigned int max8649_get_mode(struct regulator_dev *rdev)
return REGULATOR_MODE_NORMAL;
}
-static struct regulator_ops max8649_dcdc_ops = {
+static const struct regulator_ops max8649_dcdc_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.list_voltage = regulator_list_voltage_linear,
@@ -143,7 +143,7 @@ static struct regulator_desc dcdc_desc = {
.enable_is_inverted = true,
};
-static struct regmap_config max8649_regmap_config = {
+static const struct regmap_config max8649_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
diff --git a/drivers/regulator/mt6397-regulator.c b/drivers/regulator/mt6397-regulator.c
new file mode 100644
index 000000000000..a5b2f4762677
--- /dev/null
+++ b/drivers/regulator/mt6397-regulator.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Flora Fu <flora.fu@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/mt6397/core.h>
+#include <linux/mfd/mt6397/registers.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
+#include <linux/regulator/mt6397-regulator.h>
+#include <linux/regulator/of_regulator.h>
+
+/*
+ * MT6397 regulators' information
+ *
+ * @desc: standard fields of regulator description.
+ * @qi: Mask for query enable signal status of regulators
+ * @vselon_reg: Register sections for hardware control mode of bucks
+ * @vselctrl_reg: Register for controlling the buck control mode.
+ * @vselctrl_mask: Mask for query buck's voltage control mode.
+ */
+struct mt6397_regulator_info {
+ struct regulator_desc desc;
+ u32 qi;
+ u32 vselon_reg;
+ u32 vselctrl_reg;
+ u32 vselctrl_mask;
+};
+
+#define MT6397_BUCK(match, vreg, min, max, step, volt_ranges, enreg, \
+ vosel, vosel_mask, voselon, vosel_ctrl) \
+[MT6397_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6397_volt_range_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6397_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = (max - min)/step + 1, \
+ .linear_ranges = volt_ranges, \
+ .n_linear_ranges = ARRAY_SIZE(volt_ranges), \
+ .vsel_reg = vosel, \
+ .vsel_mask = vosel_mask, \
+ .enable_reg = enreg, \
+ .enable_mask = BIT(0), \
+ }, \
+ .qi = BIT(13), \
+ .vselon_reg = voselon, \
+ .vselctrl_reg = vosel_ctrl, \
+ .vselctrl_mask = BIT(1), \
+}
+
+#define MT6397_LDO(match, vreg, ldo_volt_table, enreg, enbit, vosel, \
+ vosel_mask) \
+[MT6397_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6397_volt_table_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6397_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = ARRAY_SIZE(ldo_volt_table), \
+ .volt_table = ldo_volt_table, \
+ .vsel_reg = vosel, \
+ .vsel_mask = vosel_mask, \
+ .enable_reg = enreg, \
+ .enable_mask = BIT(enbit), \
+ }, \
+ .qi = BIT(15), \
+}
+
+#define MT6397_REG_FIXED(match, vreg, enreg, enbit, volt) \
+[MT6397_ID_##vreg] = { \
+ .desc = { \
+ .name = #vreg, \
+ .of_match = of_match_ptr(match), \
+ .ops = &mt6397_volt_fixed_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = MT6397_ID_##vreg, \
+ .owner = THIS_MODULE, \
+ .n_voltages = 1, \
+ .enable_reg = enreg, \
+ .enable_mask = BIT(enbit), \
+ .min_uV = volt, \
+ }, \
+ .qi = BIT(15), \
+}
+
+static const struct regulator_linear_range buck_volt_range1[] = {
+ REGULATOR_LINEAR_RANGE(700000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range2[] = {
+ REGULATOR_LINEAR_RANGE(800000, 0, 0x7f, 6250),
+};
+
+static const struct regulator_linear_range buck_volt_range3[] = {
+ REGULATOR_LINEAR_RANGE(1500000, 0, 0x1f, 20000),
+};
+
+static const u32 ldo_volt_table1[] = {
+ 1500000, 1800000, 2500000, 2800000,
+};
+
+static const u32 ldo_volt_table2[] = {
+ 1800000, 3300000,
+};
+
+static const u32 ldo_volt_table3[] = {
+ 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table4[] = {
+ 1220000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5[] = {
+ 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table5_v2[] = {
+ 1200000, 1000000, 1500000, 1800000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static const u32 ldo_volt_table6[] = {
+ 1200000, 1300000, 1500000, 1800000, 2500000, 2800000, 3000000, 2000000,
+};
+
+static const u32 ldo_volt_table7[] = {
+ 1300000, 1500000, 1800000, 2000000, 2500000, 2800000, 3000000, 3300000,
+};
+
+static int mt6397_get_status(struct regulator_dev *rdev)
+{
+ int ret;
+ u32 regval;
+ struct mt6397_regulator_info *info = rdev_get_drvdata(rdev);
+
+ ret = regmap_read(rdev->regmap, info->desc.enable_reg, &regval);
+ if (ret != 0) {
+ dev_err(&rdev->dev, "Failed to get enable reg: %d\n", ret);
+ return ret;
+ }
+
+ return (regval & info->qi) ? REGULATOR_STATUS_ON : REGULATOR_STATUS_OFF;
+}
+
+static struct regulator_ops mt6397_volt_range_ops = {
+ .list_voltage = regulator_list_voltage_linear_range,
+ .map_voltage = regulator_map_voltage_linear_range,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6397_get_status,
+};
+
+static struct regulator_ops mt6397_volt_table_ops = {
+ .list_voltage = regulator_list_voltage_table,
+ .map_voltage = regulator_map_voltage_iterate,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6397_get_status,
+};
+
+static struct regulator_ops mt6397_volt_fixed_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .get_status = mt6397_get_status,
+};
+
+/* The array is indexed by id(MT6397_ID_XXX) */
+static struct mt6397_regulator_info mt6397_regulators[] = {
+ MT6397_BUCK("buck_vpca15", VPCA15, 700000, 1493750, 6250,
+ buck_volt_range1, MT6397_VCA15_CON7, MT6397_VCA15_CON9, 0x7f,
+ MT6397_VCA15_CON10, MT6397_VCA15_CON5),
+ MT6397_BUCK("buck_vpca7", VPCA7, 700000, 1493750, 6250,
+ buck_volt_range1, MT6397_VPCA7_CON7, MT6397_VPCA7_CON9, 0x7f,
+ MT6397_VPCA7_CON10, MT6397_VPCA7_CON5),
+ MT6397_BUCK("buck_vsramca15", VSRAMCA15, 700000, 1493750, 6250,
+ buck_volt_range1, MT6397_VSRMCA15_CON7, MT6397_VSRMCA15_CON9,
+ 0x7f, MT6397_VSRMCA15_CON10, MT6397_VSRMCA15_CON5),
+ MT6397_BUCK("buck_vsramca7", VSRAMCA7, 700000, 1493750, 6250,
+ buck_volt_range1, MT6397_VSRMCA7_CON7, MT6397_VSRMCA7_CON9,
+ 0x7f, MT6397_VSRMCA7_CON10, MT6397_VSRMCA7_CON5),
+ MT6397_BUCK("buck_vcore", VCORE, 700000, 1493750, 6250,
+ buck_volt_range1, MT6397_VCORE_CON7, MT6397_VCORE_CON9, 0x7f,
+ MT6397_VCORE_CON10, MT6397_VCORE_CON5),
+ MT6397_BUCK("buck_vgpu", VGPU, 700000, 1493750, 6250, buck_volt_range1,
+ MT6397_VGPU_CON7, MT6397_VGPU_CON9, 0x7f,
+ MT6397_VGPU_CON10, MT6397_VGPU_CON5),
+ MT6397_BUCK("buck_vdrm", VDRM, 800000, 1593750, 6250, buck_volt_range2,
+ MT6397_VDRM_CON7, MT6397_VDRM_CON9, 0x7f,
+ MT6397_VDRM_CON10, MT6397_VDRM_CON5),
+ MT6397_BUCK("buck_vio18", VIO18, 1500000, 2120000, 20000,
+ buck_volt_range3, MT6397_VIO18_CON7, MT6397_VIO18_CON9, 0x1f,
+ MT6397_VIO18_CON10, MT6397_VIO18_CON5),
+ MT6397_REG_FIXED("ldo_vtcxo", VTCXO, MT6397_ANALDO_CON0, 10, 2800000),
+ MT6397_REG_FIXED("ldo_va28", VA28, MT6397_ANALDO_CON1, 14, 2800000),
+ MT6397_LDO("ldo_vcama", VCAMA, ldo_volt_table1,
+ MT6397_ANALDO_CON2, 15, MT6397_ANALDO_CON6, 0xC0),
+ MT6397_REG_FIXED("ldo_vio28", VIO28, MT6397_DIGLDO_CON0, 14, 2800000),
+ MT6397_REG_FIXED("ldo_vusb", VUSB, MT6397_DIGLDO_CON1, 14, 3300000),
+ MT6397_LDO("ldo_vmc", VMC, ldo_volt_table2,
+ MT6397_DIGLDO_CON2, 12, MT6397_DIGLDO_CON29, 0x10),
+ MT6397_LDO("ldo_vmch", VMCH, ldo_volt_table3,
+ MT6397_DIGLDO_CON3, 14, MT6397_DIGLDO_CON17, 0x80),
+ MT6397_LDO("ldo_vemc3v3", VEMC3V3, ldo_volt_table3,
+ MT6397_DIGLDO_CON4, 14, MT6397_DIGLDO_CON18, 0x10),
+ MT6397_LDO("ldo_vgp1", VGP1, ldo_volt_table4,
+ MT6397_DIGLDO_CON5, 15, MT6397_DIGLDO_CON19, 0xE0),
+ MT6397_LDO("ldo_vgp2", VGP2, ldo_volt_table5,
+ MT6397_DIGLDO_CON6, 15, MT6397_DIGLDO_CON20, 0xE0),
+ MT6397_LDO("ldo_vgp3", VGP3, ldo_volt_table5,
+ MT6397_DIGLDO_CON7, 15, MT6397_DIGLDO_CON21, 0xE0),
+ MT6397_LDO("ldo_vgp4", VGP4, ldo_volt_table5,
+ MT6397_DIGLDO_CON8, 15, MT6397_DIGLDO_CON22, 0xE0),
+ MT6397_LDO("ldo_vgp5", VGP5, ldo_volt_table6,
+ MT6397_DIGLDO_CON9, 15, MT6397_DIGLDO_CON23, 0xE0),
+ MT6397_LDO("ldo_vgp6", VGP6, ldo_volt_table5,
+ MT6397_DIGLDO_CON10, 15, MT6397_DIGLDO_CON33, 0xE0),
+ MT6397_LDO("ldo_vibr", VIBR, ldo_volt_table7,
+ MT6397_DIGLDO_CON24, 15, MT6397_DIGLDO_CON25, 0xE00),
+};
+
+static int mt6397_set_buck_vosel_reg(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+ int i;
+ u32 regval;
+
+ for (i = 0; i < MT6397_MAX_REGULATOR; i++) {
+ if (mt6397_regulators[i].vselctrl_reg) {
+ if (regmap_read(mt6397->regmap,
+ mt6397_regulators[i].vselctrl_reg,
+ &regval) < 0) {
+ dev_err(&pdev->dev,
+ "Failed to read buck ctrl\n");
+ return -EIO;
+ }
+
+ if (regval & mt6397_regulators[i].vselctrl_mask) {
+ mt6397_regulators[i].desc.vsel_reg =
+ mt6397_regulators[i].vselon_reg;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int mt6397_regulator_probe(struct platform_device *pdev)
+{
+ struct mt6397_chip *mt6397 = dev_get_drvdata(pdev->dev.parent);
+ struct regulator_config config = {};
+ struct regulator_dev *rdev;
+ int i;
+ u32 reg_value, version;
+
+ /* Query buck controller to select activated voltage register part */
+ if (mt6397_set_buck_vosel_reg(pdev))
+ return -EIO;
+
+ /* Read PMIC chip revision to update constraints and voltage table */
+ if (regmap_read(mt6397->regmap, MT6397_CID, &reg_value) < 0) {
+ dev_err(&pdev->dev, "Failed to read Chip ID\n");
+ return -EIO;
+ }
+ dev_info(&pdev->dev, "Chip ID = 0x%x\n", reg_value);
+
+ version = (reg_value & 0xFF);
+ switch (version) {
+ case MT6397_REGULATOR_ID91:
+ mt6397_regulators[MT6397_ID_VGP2].desc.volt_table =
+ ldo_volt_table5_v2;
+ break;
+ default:
+ break;
+ }
+
+ for (i = 0; i < MT6397_MAX_REGULATOR; i++) {
+ config.dev = &pdev->dev;
+ config.driver_data = &mt6397_regulators[i];
+ config.regmap = mt6397->regmap;
+ rdev = devm_regulator_register(&pdev->dev,
+ &mt6397_regulators[i].desc, &config);
+ if (IS_ERR(rdev)) {
+ dev_err(&pdev->dev, "failed to register %s\n",
+ mt6397_regulators[i].desc.name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+
+static struct platform_driver mt6397_regulator_driver = {
+ .driver = {
+ .name = "mt6397-regulator",
+ },
+ .probe = mt6397_regulator_probe,
+};
+
+module_platform_driver(mt6397_regulator_driver);
+
+MODULE_AUTHOR("Flora Fu <flora.fu@mediatek.com>");
+MODULE_DESCRIPTION("Regulator Driver for MediaTek MT6397 PMIC");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:mt6397-regulator");
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 91eaaf010524..24e812c48d93 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -270,6 +270,7 @@ EXPORT_SYMBOL_GPL(of_regulator_match);
struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
const struct regulator_desc *desc,
+ struct regulator_config *config,
struct device_node **node)
{
struct device_node *search, *child;
@@ -307,6 +308,16 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
break;
}
+ if (desc->of_parse_cb) {
+ if (desc->of_parse_cb(child, desc, config)) {
+ dev_err(dev,
+ "driver callback failed to parse DT for regulator %s\n",
+ child->name);
+ init_data = NULL;
+ break;
+ }
+ }
+
of_node_get(child);
*node = child;
break;
diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c
index c879dff597ee..8cc8d1877c44 100644
--- a/drivers/regulator/pfuze100-regulator.c
+++ b/drivers/regulator/pfuze100-regulator.c
@@ -56,7 +56,7 @@
#define PFUZE100_VGEN5VOL 0x70
#define PFUZE100_VGEN6VOL 0x71
-enum chips { PFUZE100, PFUZE200 };
+enum chips { PFUZE100, PFUZE200, PFUZE3000 = 3 };
struct pfuze_regulator {
struct regulator_desc desc;
@@ -80,9 +80,18 @@ static const int pfuze100_vsnvs[] = {
1000000, 1100000, 1200000, 1300000, 1500000, 1800000, 3000000,
};
+static const int pfuze3000_sw2lo[] = {
+ 1500000, 1550000, 1600000, 1650000, 1700000, 1750000, 1800000, 1850000,
+};
+
+static const int pfuze3000_sw2hi[] = {
+ 2500000, 2800000, 2850000, 3000000, 3100000, 3150000, 3200000, 3300000,
+};
+
static const struct i2c_device_id pfuze_device_id[] = {
{.name = "pfuze100", .driver_data = PFUZE100},
{.name = "pfuze200", .driver_data = PFUZE200},
+ {.name = "pfuze3000", .driver_data = PFUZE3000},
{ }
};
MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
@@ -90,6 +99,7 @@ MODULE_DEVICE_TABLE(i2c, pfuze_device_id);
static const struct of_device_id pfuze_dt_ids[] = {
{ .compatible = "fsl,pfuze100", .data = (void *)PFUZE100},
{ .compatible = "fsl,pfuze200", .data = (void *)PFUZE200},
+ { .compatible = "fsl,pfuze3000", .data = (void *)PFUZE3000},
{ }
};
MODULE_DEVICE_TABLE(of, pfuze_dt_ids);
@@ -219,6 +229,60 @@ static struct regulator_ops pfuze100_swb_regulator_ops = {
.stby_mask = 0x20, \
}
+#define PFUZE3000_VCC_REG(_chip, _name, base, min, max, step) { \
+ .desc = { \
+ .name = #_name, \
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pfuze100_ldo_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (base), \
+ .vsel_mask = 0x3, \
+ .enable_reg = (base), \
+ .enable_mask = 0x10, \
+ }, \
+ .stby_reg = (base), \
+ .stby_mask = 0x20, \
+}
+
+
+#define PFUZE3000_SW2_REG(_chip, _name, base, min, max, step) { \
+ .desc = { \
+ .name = #_name,\
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pfuze100_sw_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0x7, \
+ }, \
+ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \
+ .stby_mask = 0x7, \
+}
+
+#define PFUZE3000_SW3_REG(_chip, _name, base, min, max, step) { \
+ .desc = { \
+ .name = #_name,\
+ .n_voltages = ((max) - (min)) / (step) + 1, \
+ .ops = &pfuze100_sw_regulator_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .id = _chip ## _ ## _name, \
+ .owner = THIS_MODULE, \
+ .min_uV = (min), \
+ .uV_step = (step), \
+ .vsel_reg = (base) + PFUZE100_VOL_OFFSET, \
+ .vsel_mask = 0xf, \
+ }, \
+ .stby_reg = (base) + PFUZE100_STANDBY_OFFSET, \
+ .stby_mask = 0xf, \
+}
+
/* PFUZE100 */
static struct pfuze_regulator pfuze100_regulators[] = {
PFUZE100_SW_REG(PFUZE100, SW1AB, PFUZE100_SW1ABVOL, 300000, 1875000, 25000),
@@ -254,6 +318,22 @@ static struct pfuze_regulator pfuze200_regulators[] = {
PFUZE100_VGEN_REG(PFUZE200, VGEN6, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
};
+static struct pfuze_regulator pfuze3000_regulators[] = {
+ PFUZE100_SW_REG(PFUZE3000, SW1A, PFUZE100_SW1ABVOL, 700000, 1475000, 25000),
+ PFUZE100_SW_REG(PFUZE3000, SW1B, PFUZE100_SW1CVOL, 700000, 1475000, 25000),
+ PFUZE100_SWB_REG(PFUZE3000, SW2, PFUZE100_SW2VOL, 0x7, pfuze3000_sw2lo),
+ PFUZE3000_SW3_REG(PFUZE3000, SW3, PFUZE100_SW3AVOL, 900000, 1650000, 50000),
+ PFUZE100_SWB_REG(PFUZE3000, SWBST, PFUZE100_SWBSTCON1, 0x3, pfuze100_swbst),
+ PFUZE100_SWB_REG(PFUZE3000, VSNVS, PFUZE100_VSNVSVOL, 0x7, pfuze100_vsnvs),
+ PFUZE100_FIXED_REG(PFUZE3000, VREFDDR, PFUZE100_VREFDDRCON, 750000),
+ PFUZE100_VGEN_REG(PFUZE3000, VLDO1, PFUZE100_VGEN1VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE3000, VLDO2, PFUZE100_VGEN2VOL, 800000, 1550000, 50000),
+ PFUZE3000_VCC_REG(PFUZE3000, VCCSD, PFUZE100_VGEN3VOL, 2850000, 3300000, 150000),
+ PFUZE3000_VCC_REG(PFUZE3000, V33, PFUZE100_VGEN4VOL, 2850000, 3300000, 150000),
+ PFUZE100_VGEN_REG(PFUZE3000, VLDO3, PFUZE100_VGEN5VOL, 1800000, 3300000, 100000),
+ PFUZE100_VGEN_REG(PFUZE3000, VLDO4, PFUZE100_VGEN6VOL, 1800000, 3300000, 100000),
+};
+
static struct pfuze_regulator *pfuze_regulators;
#ifdef CONFIG_OF
@@ -294,6 +374,24 @@ static struct of_regulator_match pfuze200_matches[] = {
{ .name = "vgen6", },
};
+/* PFUZE3000 */
+static struct of_regulator_match pfuze3000_matches[] = {
+
+ { .name = "sw1a", },
+ { .name = "sw1b", },
+ { .name = "sw2", },
+ { .name = "sw3", },
+ { .name = "swbst", },
+ { .name = "vsnvs", },
+ { .name = "vrefddr", },
+ { .name = "vldo1", },
+ { .name = "vldo2", },
+ { .name = "vccsd", },
+ { .name = "v33", },
+ { .name = "vldo3", },
+ { .name = "vldo4", },
+};
+
static struct of_regulator_match *pfuze_matches;
static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
@@ -313,6 +411,11 @@ static int pfuze_parse_regulators_dt(struct pfuze_chip *chip)
}
switch (chip->chip_id) {
+ case PFUZE3000:
+ pfuze_matches = pfuze3000_matches;
+ ret = of_regulator_match(dev, parent, pfuze3000_matches,
+ ARRAY_SIZE(pfuze3000_matches));
+ break;
case PFUZE200:
pfuze_matches = pfuze200_matches;
ret = of_regulator_match(dev, parent, pfuze200_matches,
@@ -378,7 +481,8 @@ static int pfuze_identify(struct pfuze_chip *pfuze_chip)
* as ID=8 in PFUZE100
*/
dev_info(pfuze_chip->dev, "Assuming misprogrammed ID=0x8");
- } else if ((value & 0x0f) != pfuze_chip->chip_id) {
+ } else if ((value & 0x0f) != pfuze_chip->chip_id &&
+ (value & 0xf0) >> 4 != pfuze_chip->chip_id) {
/* device id NOT match with your setting */
dev_warn(pfuze_chip->dev, "Illegal ID: %x\n", value);
return -ENODEV;
@@ -417,7 +521,7 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
int i, ret;
const struct of_device_id *match;
u32 regulator_num;
- u32 sw_check_start, sw_check_end;
+ u32 sw_check_start, sw_check_end, sw_hi = 0x40;
pfuze_chip = devm_kzalloc(&client->dev, sizeof(*pfuze_chip),
GFP_KERNEL);
@@ -458,13 +562,19 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
/* use the right regulators after identify the right device */
switch (pfuze_chip->chip_id) {
+ case PFUZE3000:
+ pfuze_regulators = pfuze3000_regulators;
+ regulator_num = ARRAY_SIZE(pfuze3000_regulators);
+ sw_check_start = PFUZE3000_SW2;
+ sw_check_end = PFUZE3000_SW2;
+ sw_hi = 1 << 3;
+ break;
case PFUZE200:
pfuze_regulators = pfuze200_regulators;
regulator_num = ARRAY_SIZE(pfuze200_regulators);
sw_check_start = PFUZE200_SW2;
sw_check_end = PFUZE200_SW3B;
break;
-
case PFUZE100:
default:
pfuze_regulators = pfuze100_regulators;
@@ -474,7 +584,8 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
break;
}
dev_info(&client->dev, "pfuze%s found.\n",
- (pfuze_chip->chip_id == PFUZE100) ? "100" : "200");
+ (pfuze_chip->chip_id == PFUZE100) ? "100" :
+ ((pfuze_chip->chip_id == PFUZE200) ? "200" : "3000"));
memcpy(pfuze_chip->regulator_descs, pfuze_regulators,
sizeof(pfuze_chip->regulator_descs));
@@ -498,10 +609,15 @@ static int pfuze100_regulator_probe(struct i2c_client *client,
/* SW2~SW4 high bit check and modify the voltage value table */
if (i >= sw_check_start && i <= sw_check_end) {
regmap_read(pfuze_chip->regmap, desc->vsel_reg, &val);
- if (val & 0x40) {
- desc->min_uV = 800000;
- desc->uV_step = 50000;
- desc->n_voltages = 51;
+ if (val & sw_hi) {
+ if (pfuze_chip->chip_id == PFUZE3000) {
+ desc->volt_table = pfuze3000_sw2hi;
+ desc->n_voltages = ARRAY_SIZE(pfuze3000_sw2hi);
+ } else {
+ desc->min_uV = 800000;
+ desc->uV_step = 50000;
+ desc->n_voltages = 51;
+ }
}
}
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
index 8364ff331a81..00c5cc3d9546 100644
--- a/drivers/regulator/qcom_rpm-regulator.c
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -205,6 +205,7 @@ static int rpm_reg_write(struct qcom_rpm_reg *vreg,
vreg->val[req->word] |= value << req->shift;
return qcom_rpm_write(vreg->rpm,
+ QCOM_RPM_ACTIVE_STATE,
vreg->resource,
vreg->val,
vreg->parts->request_len);
@@ -227,9 +228,11 @@ static int rpm_reg_set_mV_sel(struct regulator_dev *rdev,
return uV;
mutex_lock(&vreg->lock);
- vreg->uV = uV;
if (vreg->is_enabled)
- ret = rpm_reg_write(vreg, req, vreg->uV / 1000);
+ ret = rpm_reg_write(vreg, req, uV / 1000);
+
+ if (!ret)
+ vreg->uV = uV;
mutex_unlock(&vreg->lock);
return ret;
@@ -252,9 +255,11 @@ static int rpm_reg_set_uV_sel(struct regulator_dev *rdev,
return uV;
mutex_lock(&vreg->lock);
- vreg->uV = uV;
if (vreg->is_enabled)
- ret = rpm_reg_write(vreg, req, vreg->uV);
+ ret = rpm_reg_write(vreg, req, uV);
+
+ if (!ret)
+ vreg->uV = uV;
mutex_unlock(&vreg->lock);
return ret;
@@ -674,6 +679,7 @@ static int rpm_reg_probe(struct platform_device *pdev)
vreg->desc.owner = THIS_MODULE;
vreg->desc.type = REGULATOR_VOLTAGE;
vreg->desc.name = pdev->dev.of_node->name;
+ vreg->desc.supply_name = "vin";
vreg->rpm = dev_get_drvdata(pdev->dev.parent);
if (!vreg->rpm) {
@@ -768,7 +774,7 @@ static int rpm_reg_probe(struct platform_device *pdev)
break;
}
- if (force_mode < 0) {
+ if (force_mode == -1) {
dev_err(&pdev->dev, "invalid force mode\n");
return -EINVAL;
}
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index c94a3e0f3b91..1f93b752a81c 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -97,7 +97,7 @@ 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)
+static int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
{
unsigned int reg;
int sel = regulator_map_voltage_linear_range(rdev, uv, uv);
@@ -112,7 +112,7 @@ int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
sel);
}
-int rk808_set_suspend_enable(struct regulator_dev *rdev)
+static int rk808_set_suspend_enable(struct regulator_dev *rdev)
{
unsigned int reg;
@@ -123,7 +123,7 @@ int rk808_set_suspend_enable(struct regulator_dev *rdev)
0);
}
-int rk808_set_suspend_disable(struct regulator_dev *rdev)
+static int rk808_set_suspend_disable(struct regulator_dev *rdev)
{
unsigned int reg;
diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c
index 870cc49438db..96d2c18e051a 100644
--- a/drivers/regulator/rt5033-regulator.c
+++ b/drivers/regulator/rt5033-regulator.c
@@ -36,6 +36,8 @@ static struct regulator_ops rt5033_buck_ops = {
static const struct regulator_desc rt5033_supported_regulators[] = {
[RT5033_BUCK] = {
.name = "BUCK",
+ .of_match = of_match_ptr("BUCK"),
+ .regulators_node = of_match_ptr("regulators"),
.id = RT5033_BUCK,
.ops = &rt5033_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -50,6 +52,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = {
},
[RT5033_LDO] = {
.name = "LDO",
+ .of_match = of_match_ptr("LDO"),
+ .regulators_node = of_match_ptr("regulators"),
.id = RT5033_LDO,
.ops = &rt5033_buck_ops,
.type = REGULATOR_VOLTAGE,
@@ -64,6 +68,8 @@ static const struct regulator_desc rt5033_supported_regulators[] = {
},
[RT5033_SAFE_LDO] = {
.name = "SAFE_LDO",
+ .of_match = of_match_ptr("SAFE_LDO"),
+ .regulators_node = of_match_ptr("regulators"),
.id = RT5033_SAFE_LDO,
.ops = &rt5033_safe_ldo_ops,
.type = REGULATOR_VOLTAGE,
@@ -81,7 +87,7 @@ static int rt5033_regulator_probe(struct platform_device *pdev)
int ret, i;
struct regulator_config config = {};
- config.dev = &pdev->dev;
+ config.dev = rt5033->dev;
config.driver_data = rt5033;
for (i = 0; i < ARRAY_SIZE(rt5033_supported_regulators); i++) {
diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c
index 7380af8bd50d..b941e564b3f3 100644
--- a/drivers/regulator/tps65023-regulator.c
+++ b/drivers/regulator/tps65023-regulator.c
@@ -173,7 +173,7 @@ static int tps65023_dcdc_set_voltage_sel(struct regulator_dev *dev,
}
/* Operations permitted on VDCDCx */
-static struct regulator_ops tps65023_dcdc_ops = {
+static const struct regulator_ops tps65023_dcdc_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -184,7 +184,7 @@ static struct regulator_ops tps65023_dcdc_ops = {
};
/* Operations permitted on LDOx */
-static struct regulator_ops tps65023_ldo_ops = {
+static const struct regulator_ops tps65023_ldo_ops = {
.is_enabled = regulator_is_enabled_regmap,
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
@@ -194,7 +194,7 @@ static struct regulator_ops tps65023_ldo_ops = {
.map_voltage = regulator_map_voltage_ascend,
};
-static struct regmap_config tps65023_regmap_config = {
+static const struct regmap_config tps65023_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index f15cddfeb897..b5b5c3d485d6 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -65,7 +65,7 @@ config RTC_DEBUG
comment "RTC interfaces"
config RTC_INTF_SYSFS
- boolean "/sys/class/rtc/rtcN (sysfs)"
+ bool "/sys/class/rtc/rtcN (sysfs)"
depends on SYSFS
default RTC_CLASS
help
@@ -75,7 +75,7 @@ config RTC_INTF_SYSFS
If unsure, say Y.
config RTC_INTF_PROC
- boolean "/proc/driver/rtc (procfs for rtcN)"
+ bool "/proc/driver/rtc (procfs for rtcN)"
depends on PROC_FS
default RTC_CLASS
help
@@ -88,7 +88,7 @@ config RTC_INTF_PROC
If unsure, say Y.
config RTC_INTF_DEV
- boolean "/dev/rtcN (character devices)"
+ bool "/dev/rtcN (character devices)"
default RTC_CLASS
help
Say yes here if you want to use your RTCs using the /dev
@@ -153,6 +153,17 @@ config RTC_DRV_88PM80X
This driver can also be built as a module. If so, the module
will be called rtc-88pm80x.
+config RTC_DRV_ABB5ZES3
+ depends on I2C
+ select REGMAP_I2C
+ tristate "Abracon AB-RTCMC-32.768kHz-B5ZE-S3"
+ help
+ If you say yes here you get support for the Abracon
+ AB-RTCMC-32.768kHz-B5ZE-S3 I2C RTC chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ab-b5ze-s3.
+
config RTC_DRV_AS3722
tristate "ams AS3722 RTC driver"
depends on MFD_AS3722
@@ -455,7 +466,7 @@ config RTC_DRV_DM355EVM
Supports the RTC firmware in the MSP430 on the DM355 EVM.
config RTC_DRV_TWL92330
- boolean "TI TWL92330/Menelaus"
+ bool "TI TWL92330/Menelaus"
depends on MENELAUS
help
If you say yes here you get support for the RTC on the
@@ -790,6 +801,96 @@ config RTC_DRV_DS1553
This driver can also be built as a module. If so, the module
will be called rtc-ds1553.
+config RTC_DRV_DS1685_FAMILY
+ tristate "Dallas/Maxim DS1685 Family"
+ help
+ If you say yes here you get support for the Dallas/Maxim DS1685
+ family of real time chips. This family includes the DS1685/DS1687,
+ DS1689/DS1693, DS17285/DS17287, DS17485/DS17487, and
+ DS17885/DS17887 chips.
+
+ This driver can also be built as a module. If so, the module
+ will be called rtc-ds1685.
+
+choice
+ prompt "Subtype"
+ depends on RTC_DRV_DS1685_FAMILY
+ default RTC_DRV_DS1685
+
+config RTC_DRV_DS1685
+ bool "DS1685/DS1687"
+ help
+ This enables support for the Dallas/Maxim DS1685/DS1687 real time
+ clock chip.
+
+ This chip is commonly found in SGI O2 (IP32) and SGI Octane (IP30)
+ systems, as well as EPPC-405-UC modules by electronic system design
+ GmbH.
+
+config RTC_DRV_DS1689
+ bool "DS1689/DS1693"
+ help
+ This enables support for the Dallas/Maxim DS1689/DS1693 real time
+ clock chip.
+
+ This is an older RTC chip, supplanted by the DS1685/DS1687 above,
+ which supports a few minor features such as Vcc, Vbat, and Power
+ Cycle counters, plus a customer-specific, 8-byte ROM/Serial number.
+
+ It also works for the even older DS1688/DS1691 RTC chips, which are
+ virtually the same and carry the same model number. Both chips
+ have 114 bytes of user NVRAM.
+
+config RTC_DRV_DS17285
+ bool "DS17285/DS17287"
+ help
+ This enables support for the Dallas/Maxim DS17285/DS17287 real time
+ clock chip.
+
+ This chip features 2kb of extended NV-SRAM. It may possibly be
+ found in some SGI O2 systems (rare).
+
+config RTC_DRV_DS17485
+ bool "DS17485/DS17487"
+ help
+ This enables support for the Dallas/Maxim DS17485/DS17487 real time
+ clock chip.
+
+ This chip features 4kb of extended NV-SRAM.
+
+config RTC_DRV_DS17885
+ bool "DS17885/DS17887"
+ help
+ This enables support for the Dallas/Maxim DS17885/DS17887 real time
+ clock chip.
+
+ This chip features 8kb of extended NV-SRAM.
+
+endchoice
+
+config RTC_DS1685_PROC_REGS
+ bool "Display register values in /proc"
+ depends on RTC_DRV_DS1685_FAMILY && PROC_FS
+ help
+ Enable this to display a readout of all of the RTC registers in
+ /proc/drivers/rtc. Keep in mind that this can potentially lead
+ to lost interrupts, as reading Control Register C will clear
+ all pending IRQ flags.
+
+ Unless you are debugging this driver, choose N.
+
+config RTC_DS1685_SYSFS_REGS
+ bool "SysFS access to RTC register bits"
+ depends on RTC_DRV_DS1685_FAMILY && SYSFS
+ help
+ Enable this to provide access to the RTC control register bits
+ in /sys. Some of the bits are read-write, others are read-only.
+
+ Keep in mind that reading Control C's bits automatically clears
+ all pending IRQ flags - this can cause lost interrupts.
+
+ If you know that you need access to these bits, choose Y, Else N.
+
config RTC_DRV_DS1742
tristate "Maxim/Dallas DS1742/1743"
depends on HAS_IOMEM
@@ -1141,34 +1242,6 @@ config RTC_DRV_AT91SAM9
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
- 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
- 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
- on some systems other software needs to use that register.
-
config RTC_DRV_AU1XXX
tristate "Au1xxx Counter0 RTC support"
depends on MIPS_ALCHEMY
@@ -1269,6 +1342,16 @@ config RTC_DRV_MV
This driver can also be built as a module. If so, the module
will be called rtc-mv.
+config RTC_DRV_ARMADA38X
+ tristate "Armada 38x Marvell SoC RTC"
+ depends on ARCH_MVEBU
+ help
+ If you say yes here you will get support for the in-chip RTC
+ that can be found in the Armada 38x Marvell's SoC device
+
+ This driver can also be built as a module. If so, the module
+ will be called armada38x-rtc.
+
config RTC_DRV_PS3
tristate "PS3 RTC"
depends on PPC_PS3
diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile
index c8ef3e1e6ccd..69c87062b098 100644
--- a/drivers/rtc/Makefile
+++ b/drivers/rtc/Makefile
@@ -24,6 +24,8 @@ obj-$(CONFIG_RTC_DRV_88PM860X) += rtc-88pm860x.o
obj-$(CONFIG_RTC_DRV_88PM80X) += rtc-88pm80x.o
obj-$(CONFIG_RTC_DRV_AB3100) += rtc-ab3100.o
obj-$(CONFIG_RTC_DRV_AB8500) += rtc-ab8500.o
+obj-$(CONFIG_RTC_DRV_ABB5ZES3) += rtc-ab-b5ze-s3.o
+obj-$(CONFIG_RTC_DRV_ARMADA38X) += rtc-armada38x.o
obj-$(CONFIG_RTC_DRV_AS3722) += rtc-as3722.o
obj-$(CONFIG_RTC_DRV_AT32AP700X)+= rtc-at32ap700x.o
obj-$(CONFIG_RTC_DRV_AT91RM9200)+= rtc-at91rm9200.o
@@ -52,6 +54,7 @@ obj-$(CONFIG_RTC_DRV_DS1390) += rtc-ds1390.o
obj-$(CONFIG_RTC_DRV_DS1511) += rtc-ds1511.o
obj-$(CONFIG_RTC_DRV_DS1553) += rtc-ds1553.o
obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_DS1685_FAMILY) += rtc-ds1685.o
obj-$(CONFIG_RTC_DRV_DS1742) += rtc-ds1742.o
obj-$(CONFIG_RTC_DRV_DS2404) += rtc-ds2404.o
obj-$(CONFIG_RTC_DRV_DS3232) += rtc-ds3232.o
diff --git a/drivers/rtc/hctosys.c b/drivers/rtc/hctosys.c
index 4aa60d74004e..6c719f23520a 100644
--- a/drivers/rtc/hctosys.c
+++ b/drivers/rtc/hctosys.c
@@ -26,7 +26,7 @@ static int __init rtc_hctosys(void)
{
int err = -ENODEV;
struct rtc_time tm;
- struct timespec tv = {
+ struct timespec64 tv64 = {
.tv_nsec = NSEC_PER_SEC >> 1,
};
struct rtc_device *rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
@@ -45,25 +45,17 @@ static int __init rtc_hctosys(void)
}
- err = rtc_valid_tm(&tm);
- if (err) {
- dev_err(rtc->dev.parent,
- "hctosys: invalid date/time\n");
- goto err_invalid;
- }
-
- rtc_tm_to_time(&tm, &tv.tv_sec);
+ tv64.tv_sec = rtc_tm_to_time64(&tm);
- err = do_settimeofday(&tv);
+ err = do_settimeofday64(&tv64);
dev_info(rtc->dev.parent,
"setting system clock to "
- "%d-%02d-%02d %02d:%02d:%02d UTC (%u)\n",
+ "%d-%02d-%02d %02d:%02d:%02d UTC (%lld)\n",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec,
- (unsigned int) tv.tv_sec);
+ (long long) tv64.tv_sec);
-err_invalid:
err_read:
rtc_class_close(rtc);
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 45bfc28ee3aa..37215cf983e9 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -73,10 +73,8 @@ int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm)
else if (rtc->ops->set_time)
err = rtc->ops->set_time(rtc->dev.parent, tm);
else if (rtc->ops->set_mmss) {
- unsigned long secs;
- err = rtc_tm_to_time(tm, &secs);
- if (err == 0)
- err = rtc->ops->set_mmss(rtc->dev.parent, secs);
+ time64_t secs64 = rtc_tm_to_time64(tm);
+ err = rtc->ops->set_mmss(rtc->dev.parent, secs64);
} else
err = -EINVAL;
@@ -105,7 +103,7 @@ int rtc_set_mmss(struct rtc_device *rtc, unsigned long secs)
err = rtc->ops->read_time(rtc->dev.parent, &old);
if (err == 0) {
- rtc_time_to_tm(secs, &new);
+ rtc_time64_to_tm(secs, &new);
/*
* avoid writing when we're going to change the day of
@@ -157,7 +155,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
int err;
struct rtc_time before, now;
int first_time = 1;
- unsigned long t_now, t_alm;
+ time64_t t_now, t_alm;
enum { none, day, month, year } missing = none;
unsigned days;
@@ -258,8 +256,8 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
}
/* with luck, no rollover is needed */
- rtc_tm_to_time(&now, &t_now);
- rtc_tm_to_time(&alarm->time, &t_alm);
+ t_now = rtc_tm_to_time64(&now);
+ t_alm = rtc_tm_to_time64(&alarm->time);
if (t_now < t_alm)
goto done;
@@ -273,7 +271,7 @@ int __rtc_read_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
case day:
dev_dbg(&rtc->dev, "alarm rollover: %s\n", "day");
t_alm += 24 * 60 * 60;
- rtc_time_to_tm(t_alm, &alarm->time);
+ rtc_time64_to_tm(t_alm, &alarm->time);
break;
/* Month rollover ... if it's the 31th, an alarm on the 3rd will
@@ -346,19 +344,19 @@ EXPORT_SYMBOL_GPL(rtc_read_alarm);
static int __rtc_set_alarm(struct rtc_device *rtc, struct rtc_wkalrm *alarm)
{
struct rtc_time tm;
- long now, scheduled;
+ time64_t now, scheduled;
int err;
err = rtc_valid_tm(&alarm->time);
if (err)
return err;
- rtc_tm_to_time(&alarm->time, &scheduled);
+ scheduled = rtc_tm_to_time64(&alarm->time);
/* Make sure we're not setting alarms in the past */
err = __rtc_read_time(rtc, &tm);
if (err)
return err;
- rtc_tm_to_time(&tm, &now);
+ now = rtc_tm_to_time64(&tm);
if (scheduled <= now)
return -ETIME;
/*
diff --git a/drivers/rtc/rtc-ab-b5ze-s3.c b/drivers/rtc/rtc-ab-b5ze-s3.c
new file mode 100644
index 000000000000..cfc2ef98d393
--- /dev/null
+++ b/drivers/rtc/rtc-ab-b5ze-s3.c
@@ -0,0 +1,1035 @@
+/*
+ * rtc-ab-b5ze-s3 - Driver for Abracon AB-RTCMC-32.768Khz-B5ZE-S3
+ * I2C RTC / Alarm chip
+ *
+ * Copyright (C) 2014, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * Detailed datasheet of the chip is available here:
+ *
+ * http://www.abracon.com/realtimeclock/AB-RTCMC-32.768kHz-B5ZE-S3-Application-Manual.pdf
+ *
+ * This work is based on ISL12057 driver (drivers/rtc/rtc-isl12057.c).
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/rtc.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/of.h>
+#include <linux/regmap.h>
+#include <linux/interrupt.h>
+
+#define DRV_NAME "rtc-ab-b5ze-s3"
+
+/* Control section */
+#define ABB5ZES3_REG_CTRL1 0x00 /* Control 1 register */
+#define ABB5ZES3_REG_CTRL1_CIE BIT(0) /* Pulse interrupt enable */
+#define ABB5ZES3_REG_CTRL1_AIE BIT(1) /* Alarm interrupt enable */
+#define ABB5ZES3_REG_CTRL1_SIE BIT(2) /* Second interrupt enable */
+#define ABB5ZES3_REG_CTRL1_PM BIT(3) /* 24h/12h mode */
+#define ABB5ZES3_REG_CTRL1_SR BIT(4) /* Software reset */
+#define ABB5ZES3_REG_CTRL1_STOP BIT(5) /* RTC circuit enable */
+#define ABB5ZES3_REG_CTRL1_CAP BIT(7)
+
+#define ABB5ZES3_REG_CTRL2 0x01 /* Control 2 register */
+#define ABB5ZES3_REG_CTRL2_CTBIE BIT(0) /* Countdown timer B int. enable */
+#define ABB5ZES3_REG_CTRL2_CTAIE BIT(1) /* Countdown timer A int. enable */
+#define ABB5ZES3_REG_CTRL2_WTAIE BIT(2) /* Watchdog timer A int. enable */
+#define ABB5ZES3_REG_CTRL2_AF BIT(3) /* Alarm interrupt status */
+#define ABB5ZES3_REG_CTRL2_SF BIT(4) /* Second interrupt status */
+#define ABB5ZES3_REG_CTRL2_CTBF BIT(5) /* Countdown timer B int. status */
+#define ABB5ZES3_REG_CTRL2_CTAF BIT(6) /* Countdown timer A int. status */
+#define ABB5ZES3_REG_CTRL2_WTAF BIT(7) /* Watchdog timer A int. status */
+
+#define ABB5ZES3_REG_CTRL3 0x02 /* Control 3 register */
+#define ABB5ZES3_REG_CTRL3_PM2 BIT(7) /* Power Management bit 2 */
+#define ABB5ZES3_REG_CTRL3_PM1 BIT(6) /* Power Management bit 1 */
+#define ABB5ZES3_REG_CTRL3_PM0 BIT(5) /* Power Management bit 0 */
+#define ABB5ZES3_REG_CTRL3_BSF BIT(3) /* Battery switchover int. status */
+#define ABB5ZES3_REG_CTRL3_BLF BIT(2) /* Battery low int. status */
+#define ABB5ZES3_REG_CTRL3_BSIE BIT(1) /* Battery switchover int. enable */
+#define ABB5ZES3_REG_CTRL3_BLIE BIT(0) /* Battery low int. enable */
+
+#define ABB5ZES3_CTRL_SEC_LEN 3
+
+/* RTC section */
+#define ABB5ZES3_REG_RTC_SC 0x03 /* RTC Seconds register */
+#define ABB5ZES3_REG_RTC_SC_OSC BIT(7) /* Clock integrity status */
+#define ABB5ZES3_REG_RTC_MN 0x04 /* RTC Minutes register */
+#define ABB5ZES3_REG_RTC_HR 0x05 /* RTC Hours register */
+#define ABB5ZES3_REG_RTC_HR_PM BIT(5) /* RTC Hours PM bit */
+#define ABB5ZES3_REG_RTC_DT 0x06 /* RTC Date register */
+#define ABB5ZES3_REG_RTC_DW 0x07 /* RTC Day of the week register */
+#define ABB5ZES3_REG_RTC_MO 0x08 /* RTC Month register */
+#define ABB5ZES3_REG_RTC_YR 0x09 /* RTC Year register */
+
+#define ABB5ZES3_RTC_SEC_LEN 7
+
+/* Alarm section (enable bits are all active low) */
+#define ABB5ZES3_REG_ALRM_MN 0x0A /* Alarm - minute register */
+#define ABB5ZES3_REG_ALRM_MN_AE BIT(7) /* Minute enable */
+#define ABB5ZES3_REG_ALRM_HR 0x0B /* Alarm - hours register */
+#define ABB5ZES3_REG_ALRM_HR_AE BIT(7) /* Hour enable */
+#define ABB5ZES3_REG_ALRM_DT 0x0C /* Alarm - date register */
+#define ABB5ZES3_REG_ALRM_DT_AE BIT(7) /* Date (day of the month) enable */
+#define ABB5ZES3_REG_ALRM_DW 0x0D /* Alarm - day of the week reg. */
+#define ABB5ZES3_REG_ALRM_DW_AE BIT(7) /* Day of the week enable */
+
+#define ABB5ZES3_ALRM_SEC_LEN 4
+
+/* Frequency offset section */
+#define ABB5ZES3_REG_FREQ_OF 0x0E /* Frequency offset register */
+#define ABB5ZES3_REG_FREQ_OF_MODE 0x0E /* Offset mode: 2 hours / minute */
+
+/* CLOCKOUT section */
+#define ABB5ZES3_REG_TIM_CLK 0x0F /* Timer & Clockout register */
+#define ABB5ZES3_REG_TIM_CLK_TAM BIT(7) /* Permanent/pulsed timer A/int. 2 */
+#define ABB5ZES3_REG_TIM_CLK_TBM BIT(6) /* Permanent/pulsed timer B */
+#define ABB5ZES3_REG_TIM_CLK_COF2 BIT(5) /* Clkout Freq bit 2 */
+#define ABB5ZES3_REG_TIM_CLK_COF1 BIT(4) /* Clkout Freq bit 1 */
+#define ABB5ZES3_REG_TIM_CLK_COF0 BIT(3) /* Clkout Freq bit 0 */
+#define ABB5ZES3_REG_TIM_CLK_TAC1 BIT(2) /* Timer A: - 01 : countdown */
+#define ABB5ZES3_REG_TIM_CLK_TAC0 BIT(1) /* - 10 : timer */
+#define ABB5ZES3_REG_TIM_CLK_TBC BIT(0) /* Timer B enable */
+
+/* Timer A Section */
+#define ABB5ZES3_REG_TIMA_CLK 0x10 /* Timer A clock register */
+#define ABB5ZES3_REG_TIMA_CLK_TAQ2 BIT(2) /* Freq bit 2 */
+#define ABB5ZES3_REG_TIMA_CLK_TAQ1 BIT(1) /* Freq bit 1 */
+#define ABB5ZES3_REG_TIMA_CLK_TAQ0 BIT(0) /* Freq bit 0 */
+#define ABB5ZES3_REG_TIMA 0x11 /* Timer A register */
+
+#define ABB5ZES3_TIMA_SEC_LEN 2
+
+/* Timer B Section */
+#define ABB5ZES3_REG_TIMB_CLK 0x12 /* Timer B clock register */
+#define ABB5ZES3_REG_TIMB_CLK_TBW2 BIT(6)
+#define ABB5ZES3_REG_TIMB_CLK_TBW1 BIT(5)
+#define ABB5ZES3_REG_TIMB_CLK_TBW0 BIT(4)
+#define ABB5ZES3_REG_TIMB_CLK_TAQ2 BIT(2)
+#define ABB5ZES3_REG_TIMB_CLK_TAQ1 BIT(1)
+#define ABB5ZES3_REG_TIMB_CLK_TAQ0 BIT(0)
+#define ABB5ZES3_REG_TIMB 0x13 /* Timer B register */
+#define ABB5ZES3_TIMB_SEC_LEN 2
+
+#define ABB5ZES3_MEM_MAP_LEN 0x14
+
+struct abb5zes3_rtc_data {
+ struct rtc_device *rtc;
+ struct regmap *regmap;
+ struct mutex lock;
+
+ int irq;
+
+ bool battery_low;
+ bool timer_alarm; /* current alarm is via timer A */
+};
+
+/*
+ * Try and match register bits w/ fixed null values to see whether we
+ * are dealing with an ABB5ZES3. Note: this function is called early
+ * during init and hence does need mutex protection.
+ */
+static int abb5zes3_i2c_validate_chip(struct regmap *regmap)
+{
+ u8 regs[ABB5ZES3_MEM_MAP_LEN];
+ static const u8 mask[ABB5ZES3_MEM_MAP_LEN] = { 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0xc0, 0xc0, 0xf8,
+ 0xe0, 0x00, 0x00, 0x40,
+ 0x40, 0x78, 0x00, 0x00,
+ 0xf8, 0x00, 0x88, 0x00 };
+ int ret, i;
+
+ ret = regmap_bulk_read(regmap, 0, regs, ABB5ZES3_MEM_MAP_LEN);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ABB5ZES3_MEM_MAP_LEN; ++i) {
+ if (regs[i] & mask[i]) /* check if bits are cleared */
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+/* Clear alarm status bit. */
+static int _abb5zes3_rtc_clear_alarm(struct device *dev)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL2,
+ ABB5ZES3_REG_CTRL2_AF, 0);
+ if (ret)
+ dev_err(dev, "%s: clearing alarm failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+/* Enable or disable alarm (i.e. alarm interrupt generation) */
+static int _abb5zes3_rtc_update_alarm(struct device *dev, bool enable)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL1,
+ ABB5ZES3_REG_CTRL1_AIE,
+ enable ? ABB5ZES3_REG_CTRL1_AIE : 0);
+ if (ret)
+ dev_err(dev, "%s: writing alarm INT failed (%d)\n",
+ __func__, ret);
+
+ return ret;
+}
+
+/* Enable or disable timer (watchdog timer A interrupt generation) */
+static int _abb5zes3_rtc_update_timer(struct device *dev, bool enable)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_CTRL2,
+ ABB5ZES3_REG_CTRL2_WTAIE,
+ enable ? ABB5ZES3_REG_CTRL2_WTAIE : 0);
+ if (ret)
+ dev_err(dev, "%s: writing timer INT failed (%d)\n",
+ __func__, ret);
+
+ return ret;
+}
+
+/*
+ * Note: we only read, so regmap inner lock protection is sufficient, i.e.
+ * we do not need driver's main lock protection.
+ */
+static int _abb5zes3_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ u8 regs[ABB5ZES3_REG_RTC_SC + ABB5ZES3_RTC_SEC_LEN];
+ int ret;
+
+ /*
+ * As we need to read CTRL1 register anyway to access 24/12h
+ * mode bit, we do a single bulk read of both control and RTC
+ * sections (they are consecutive). This also ease indexing
+ * of register values after bulk read.
+ */
+ ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_CTRL1, regs,
+ sizeof(regs));
+ if (ret) {
+ dev_err(dev, "%s: reading RTC time failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* If clock integrity is not guaranteed, do not return a time value */
+ if (regs[ABB5ZES3_REG_RTC_SC] & ABB5ZES3_REG_RTC_SC_OSC) {
+ ret = -ENODATA;
+ goto err;
+ }
+
+ tm->tm_sec = bcd2bin(regs[ABB5ZES3_REG_RTC_SC] & 0x7F);
+ tm->tm_min = bcd2bin(regs[ABB5ZES3_REG_RTC_MN]);
+
+ if (regs[ABB5ZES3_REG_CTRL1] & ABB5ZES3_REG_CTRL1_PM) { /* 12hr mode */
+ tm->tm_hour = bcd2bin(regs[ABB5ZES3_REG_RTC_HR] & 0x1f);
+ if (regs[ABB5ZES3_REG_RTC_HR] & ABB5ZES3_REG_RTC_HR_PM) /* PM */
+ tm->tm_hour += 12;
+ } else { /* 24hr mode */
+ tm->tm_hour = bcd2bin(regs[ABB5ZES3_REG_RTC_HR]);
+ }
+
+ tm->tm_mday = bcd2bin(regs[ABB5ZES3_REG_RTC_DT]);
+ tm->tm_wday = bcd2bin(regs[ABB5ZES3_REG_RTC_DW]);
+ tm->tm_mon = bcd2bin(regs[ABB5ZES3_REG_RTC_MO]) - 1; /* starts at 1 */
+ tm->tm_year = bcd2bin(regs[ABB5ZES3_REG_RTC_YR]) + 100;
+
+ ret = rtc_valid_tm(tm);
+
+err:
+ return ret;
+}
+
+static int abb5zes3_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ u8 regs[ABB5ZES3_REG_RTC_SC + ABB5ZES3_RTC_SEC_LEN];
+ int ret;
+
+ /*
+ * Year register is 8-bit wide and bcd-coded, i.e records values
+ * between 0 and 99. tm_year is an offset from 1900 and we are
+ * interested in the 2000-2099 range, so any value less than 100
+ * is invalid.
+ */
+ if (tm->tm_year < 100)
+ return -EINVAL;
+
+ regs[ABB5ZES3_REG_RTC_SC] = bin2bcd(tm->tm_sec); /* MSB=0 clears OSC */
+ regs[ABB5ZES3_REG_RTC_MN] = bin2bcd(tm->tm_min);
+ regs[ABB5ZES3_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */
+ regs[ABB5ZES3_REG_RTC_DT] = bin2bcd(tm->tm_mday);
+ regs[ABB5ZES3_REG_RTC_DW] = bin2bcd(tm->tm_wday);
+ regs[ABB5ZES3_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1);
+ regs[ABB5ZES3_REG_RTC_YR] = bin2bcd(tm->tm_year - 100);
+
+ mutex_lock(&data->lock);
+ ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_RTC_SC,
+ regs + ABB5ZES3_REG_RTC_SC,
+ ABB5ZES3_RTC_SEC_LEN);
+ mutex_unlock(&data->lock);
+
+
+ return ret;
+}
+
+/*
+ * Set provided TAQ and Timer A registers (TIMA_CLK and TIMA) based on
+ * given number of seconds.
+ */
+static inline void sec_to_timer_a(u8 secs, u8 *taq, u8 *timer_a)
+{
+ *taq = ABB5ZES3_REG_TIMA_CLK_TAQ1; /* 1Hz */
+ *timer_a = secs;
+}
+
+/*
+ * Return current number of seconds in Timer A. As we only use
+ * timer A with a 1Hz freq, this is what we expect to have.
+ */
+static inline int sec_from_timer_a(u8 *secs, u8 taq, u8 timer_a)
+{
+ if (taq != ABB5ZES3_REG_TIMA_CLK_TAQ1) /* 1Hz */
+ return -EINVAL;
+
+ *secs = timer_a;
+
+ return 0;
+}
+
+/*
+ * Read alarm currently configured via a watchdog timer using timer A. This
+ * is done by reading current RTC time and adding remaining timer time.
+ */
+static int _abb5zes3_rtc_read_timer(struct device *dev,
+ struct rtc_wkalrm *alarm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
+ u8 regs[ABB5ZES3_TIMA_SEC_LEN + 1];
+ unsigned long rtc_secs;
+ unsigned int reg;
+ u8 timer_secs;
+ int ret;
+
+ /*
+ * Instead of doing two separate calls, because they are consecutive,
+ * we grab both clockout register and Timer A section. The latter is
+ * used to decide if timer A is enabled (as a watchdog timer).
+ */
+ ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_TIM_CLK, regs,
+ ABB5ZES3_TIMA_SEC_LEN + 1);
+ if (ret) {
+ dev_err(dev, "%s: reading Timer A section failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* get current time ... */
+ ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ goto err;
+
+ /* ... convert to seconds ... */
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err;
+
+ /* ... add remaining timer A time ... */
+ ret = sec_from_timer_a(&timer_secs, regs[1], regs[2]);
+ if (ret)
+ goto err;
+
+ /* ... and convert back. */
+ rtc_time_to_tm(rtc_secs + timer_secs, alarm_tm);
+
+ ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL2, &reg);
+ if (ret) {
+ dev_err(dev, "%s: reading ctrl reg failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL2_WTAIE);
+
+err:
+ return ret;
+}
+
+/* Read alarm currently configured via a RTC alarm registers. */
+static int _abb5zes3_rtc_read_alarm(struct device *dev,
+ struct rtc_wkalrm *alarm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
+ unsigned long rtc_secs, alarm_secs;
+ u8 regs[ABB5ZES3_ALRM_SEC_LEN];
+ unsigned int reg;
+ int ret;
+
+ ret = regmap_bulk_read(data->regmap, ABB5ZES3_REG_ALRM_MN, regs,
+ ABB5ZES3_ALRM_SEC_LEN);
+ if (ret) {
+ dev_err(dev, "%s: reading alarm section failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ alarm_tm->tm_sec = 0;
+ alarm_tm->tm_min = bcd2bin(regs[0] & 0x7f);
+ alarm_tm->tm_hour = bcd2bin(regs[1] & 0x3f);
+ alarm_tm->tm_mday = bcd2bin(regs[2] & 0x3f);
+ alarm_tm->tm_wday = -1;
+
+ /*
+ * The alarm section does not store year/month. We use the ones in rtc
+ * section as a basis and increment month and then year if needed to get
+ * alarm after current time.
+ */
+ ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ goto err;
+
+ alarm_tm->tm_year = rtc_tm.tm_year;
+ alarm_tm->tm_mon = rtc_tm.tm_mon;
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err;
+
+ ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+ if (ret)
+ goto err;
+
+ if (alarm_secs < rtc_secs) {
+ if (alarm_tm->tm_mon == 11) {
+ alarm_tm->tm_mon = 0;
+ alarm_tm->tm_year += 1;
+ } else {
+ alarm_tm->tm_mon += 1;
+ }
+ }
+
+ ret = regmap_read(data->regmap, ABB5ZES3_REG_CTRL1, &reg);
+ if (ret) {
+ dev_err(dev, "%s: reading ctrl reg failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ alarm->enabled = !!(reg & ABB5ZES3_REG_CTRL1_AIE);
+
+err:
+ return ret;
+}
+
+/*
+ * As the Alarm mechanism supported by the chip is only accurate to the
+ * minute, we use the watchdog timer mechanism provided by timer A
+ * (up to 256 seconds w/ a second accuracy) for low alarm values (below
+ * 4 minutes). Otherwise, we use the common alarm mechanism provided
+ * by the chip. In order for that to work, we keep track of currently
+ * configured timer type via 'timer_alarm' flag in our private data
+ * structure.
+ */
+static int abb5zes3_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+ if (data->timer_alarm)
+ ret = _abb5zes3_rtc_read_timer(dev, alarm);
+ else
+ ret = _abb5zes3_rtc_read_alarm(dev, alarm);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+/*
+ * Set alarm using chip alarm mechanism. It is only accurate to the
+ * minute (not the second). The function expects alarm interrupt to
+ * be disabled.
+ */
+static int _abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ struct rtc_time *alarm_tm = &alarm->time;
+ unsigned long rtc_secs, alarm_secs;
+ u8 regs[ABB5ZES3_ALRM_SEC_LEN];
+ struct rtc_time rtc_tm;
+ int ret, enable = 1;
+
+ ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ goto err;
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err;
+
+ ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+ if (ret)
+ goto err;
+
+ /* If alarm time is before current time, disable the alarm */
+ if (!alarm->enabled || alarm_secs <= rtc_secs) {
+ enable = 0;
+ } else {
+ /*
+ * Chip only support alarms up to one month in the future. Let's
+ * return an error if we get something after that limit.
+ * Comparison is done by incrementing rtc_tm month field by one
+ * and checking alarm value is still below.
+ */
+ if (rtc_tm.tm_mon == 11) { /* handle year wrapping */
+ rtc_tm.tm_mon = 0;
+ rtc_tm.tm_year += 1;
+ } else {
+ rtc_tm.tm_mon += 1;
+ }
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err;
+
+ if (alarm_secs > rtc_secs) {
+ dev_err(dev, "%s: alarm maximum is one month in the "
+ "future (%d)\n", __func__, ret);
+ ret = -EINVAL;
+ goto err;
+ }
+ }
+
+ /*
+ * Program all alarm registers but DW one. For each register, setting
+ * MSB to 0 enables associated alarm.
+ */
+ regs[0] = bin2bcd(alarm_tm->tm_min) & 0x7f;
+ regs[1] = bin2bcd(alarm_tm->tm_hour) & 0x3f;
+ regs[2] = bin2bcd(alarm_tm->tm_mday) & 0x3f;
+ regs[3] = ABB5ZES3_REG_ALRM_DW_AE; /* do not match day of the week */
+
+ ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_ALRM_MN, regs,
+ ABB5ZES3_ALRM_SEC_LEN);
+ if (ret < 0) {
+ dev_err(dev, "%s: writing ALARM section failed (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* Record currently configured alarm is not a timer */
+ data->timer_alarm = 0;
+
+ /* Enable or disable alarm interrupt generation */
+ ret = _abb5zes3_rtc_update_alarm(dev, enable);
+
+err:
+ return ret;
+}
+
+/*
+ * Set alarm using timer watchdog (via timer A) mechanism. The function expects
+ * timer A interrupt to be disabled.
+ */
+static int _abb5zes3_rtc_set_timer(struct device *dev, struct rtc_wkalrm *alarm,
+ u8 secs)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ u8 regs[ABB5ZES3_TIMA_SEC_LEN];
+ u8 mask = ABB5ZES3_REG_TIM_CLK_TAC0 | ABB5ZES3_REG_TIM_CLK_TAC1;
+ int ret = 0;
+
+ /* Program given number of seconds to Timer A registers */
+ sec_to_timer_a(secs, &regs[0], &regs[1]);
+ ret = regmap_bulk_write(data->regmap, ABB5ZES3_REG_TIMA_CLK, regs,
+ ABB5ZES3_TIMA_SEC_LEN);
+ if (ret < 0) {
+ dev_err(dev, "%s: writing timer section failed\n", __func__);
+ goto err;
+ }
+
+ /* Configure Timer A as a watchdog timer */
+ ret = regmap_update_bits(data->regmap, ABB5ZES3_REG_TIM_CLK,
+ mask, ABB5ZES3_REG_TIM_CLK_TAC1);
+ if (ret)
+ dev_err(dev, "%s: failed to update timer\n", __func__);
+
+ /* Record currently configured alarm is a timer */
+ data->timer_alarm = 1;
+
+ /* Enable or disable timer interrupt generation */
+ ret = _abb5zes3_rtc_update_timer(dev, alarm->enabled);
+
+err:
+ return ret;
+}
+
+/*
+ * The chip has an alarm which is only accurate to the minute. In order to
+ * handle alarms below that limit, we use the watchdog timer function of
+ * timer A. More precisely, the timer method is used for alarms below 240
+ * seconds.
+ */
+static int abb5zes3_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ struct rtc_time *alarm_tm = &alarm->time;
+ unsigned long rtc_secs, alarm_secs;
+ struct rtc_time rtc_tm;
+ int ret;
+
+ mutex_lock(&data->lock);
+ ret = _abb5zes3_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ goto err;
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err;
+
+ ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+ if (ret)
+ goto err;
+
+ /* Let's first disable both the alarm and the timer interrupts */
+ ret = _abb5zes3_rtc_update_alarm(dev, false);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to disable alarm (%d)\n", __func__,
+ ret);
+ goto err;
+ }
+ ret = _abb5zes3_rtc_update_timer(dev, false);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to disable timer (%d)\n", __func__,
+ ret);
+ goto err;
+ }
+
+ data->timer_alarm = 0;
+
+ /*
+ * Let's now configure the alarm; if we are expected to ring in
+ * more than 240s, then we setup an alarm. Otherwise, a timer.
+ */
+ if ((alarm_secs > rtc_secs) && ((alarm_secs - rtc_secs) <= 240))
+ ret = _abb5zes3_rtc_set_timer(dev, alarm,
+ alarm_secs - rtc_secs);
+ else
+ ret = _abb5zes3_rtc_set_alarm(dev, alarm);
+
+ err:
+ mutex_unlock(&data->lock);
+
+ if (ret)
+ dev_err(dev, "%s: unable to configure alarm (%d)\n", __func__,
+ ret);
+
+ return ret;
+ }
+
+/* Enable or disable battery low irq generation */
+static inline int _abb5zes3_rtc_battery_low_irq_enable(struct regmap *regmap,
+ bool enable)
+{
+ return regmap_update_bits(regmap, ABB5ZES3_REG_CTRL3,
+ ABB5ZES3_REG_CTRL3_BLIE,
+ enable ? ABB5ZES3_REG_CTRL3_BLIE : 0);
+}
+
+/*
+ * Check current RTC status and enable/disable what needs to be. Return 0 if
+ * everything went ok and a negative value upon error. Note: this function
+ * is called early during init and hence does need mutex protection.
+ */
+static int abb5zes3_rtc_check_setup(struct device *dev)
+{
+ struct abb5zes3_rtc_data *data = dev_get_drvdata(dev);
+ struct regmap *regmap = data->regmap;
+ unsigned int reg;
+ int ret;
+ u8 mask;
+
+ /*
+ * By default, the devices generates a 32.768KHz signal on IRQ#1 pin. It
+ * is disabled here to prevent polluting the interrupt line and
+ * uselessly triggering the IRQ handler we install for alarm and battery
+ * low events. Note: this is done before clearing int. status below
+ * in this function.
+ * We also disable all timers and set timer interrupt to permanent (not
+ * pulsed).
+ */
+ mask = (ABB5ZES3_REG_TIM_CLK_TBC | ABB5ZES3_REG_TIM_CLK_TAC0 |
+ ABB5ZES3_REG_TIM_CLK_TAC1 | ABB5ZES3_REG_TIM_CLK_COF0 |
+ ABB5ZES3_REG_TIM_CLK_COF1 | ABB5ZES3_REG_TIM_CLK_COF2 |
+ ABB5ZES3_REG_TIM_CLK_TBM | ABB5ZES3_REG_TIM_CLK_TAM);
+ ret = regmap_update_bits(regmap, ABB5ZES3_REG_TIM_CLK, mask,
+ ABB5ZES3_REG_TIM_CLK_COF0 | ABB5ZES3_REG_TIM_CLK_COF1 |
+ ABB5ZES3_REG_TIM_CLK_COF2);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to initialize clkout register (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
+ * Each component of the alarm (MN, HR, DT, DW) can be enabled/disabled
+ * individually by clearing/setting MSB of each associated register. So,
+ * we set all alarm enable bits to disable current alarm setting.
+ */
+ mask = (ABB5ZES3_REG_ALRM_MN_AE | ABB5ZES3_REG_ALRM_HR_AE |
+ ABB5ZES3_REG_ALRM_DT_AE | ABB5ZES3_REG_ALRM_DW_AE);
+ ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL2, mask, mask);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to disable alarm setting (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Set Control 1 register (RTC enabled, 24hr mode, all int. disabled) */
+ mask = (ABB5ZES3_REG_CTRL1_CIE | ABB5ZES3_REG_CTRL1_AIE |
+ ABB5ZES3_REG_CTRL1_SIE | ABB5ZES3_REG_CTRL1_PM |
+ ABB5ZES3_REG_CTRL1_CAP | ABB5ZES3_REG_CTRL1_STOP);
+ ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL1, mask, 0);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to initialize CTRL1 register (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
+ * Set Control 2 register (timer int. disabled, alarm status cleared).
+ * WTAF is read-only and cleared automatically by reading the register.
+ */
+ mask = (ABB5ZES3_REG_CTRL2_CTBIE | ABB5ZES3_REG_CTRL2_CTAIE |
+ ABB5ZES3_REG_CTRL2_WTAIE | ABB5ZES3_REG_CTRL2_AF |
+ ABB5ZES3_REG_CTRL2_SF | ABB5ZES3_REG_CTRL2_CTBF |
+ ABB5ZES3_REG_CTRL2_CTAF);
+ ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL2, mask, 0);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to initialize CTRL2 register (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /*
+ * Enable battery low detection function and battery switchover function
+ * (standard mode). Disable associated interrupts. Clear battery
+ * switchover flag but not battery low flag. The latter is checked
+ * later below.
+ */
+ mask = (ABB5ZES3_REG_CTRL3_PM0 | ABB5ZES3_REG_CTRL3_PM1 |
+ ABB5ZES3_REG_CTRL3_PM2 | ABB5ZES3_REG_CTRL3_BLIE |
+ ABB5ZES3_REG_CTRL3_BSIE| ABB5ZES3_REG_CTRL3_BSF);
+ ret = regmap_update_bits(regmap, ABB5ZES3_REG_CTRL3, mask, 0);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to initialize CTRL3 register (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ /* Check oscillator integrity flag */
+ ret = regmap_read(regmap, ABB5ZES3_REG_RTC_SC, &reg);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to read osc. integrity flag (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ if (reg & ABB5ZES3_REG_RTC_SC_OSC) {
+ dev_err(dev, "clock integrity not guaranteed. Osc. has stopped "
+ "or has been interrupted.\n");
+ dev_err(dev, "change battery (if not already done) and "
+ "then set time to reset osc. failure flag.\n");
+ }
+
+ /*
+ * Check battery low flag at startup: this allows reporting battery
+ * is low at startup when IRQ line is not connected. Note: we record
+ * current status to avoid reenabling this interrupt later in probe
+ * function if battery is low.
+ */
+ ret = regmap_read(regmap, ABB5ZES3_REG_CTRL3, &reg);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to read battery low flag (%d)\n",
+ __func__, ret);
+ return ret;
+ }
+
+ data->battery_low = reg & ABB5ZES3_REG_CTRL3_BLF;
+ if (data->battery_low) {
+ dev_err(dev, "RTC battery is low; please, consider "
+ "changing it!\n");
+
+ ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, false);
+ if (ret)
+ dev_err(dev, "%s: disabling battery low interrupt "
+ "generation failed (%d)\n", __func__, ret);
+ }
+
+ return ret;
+}
+
+static int abb5zes3_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enable)
+{
+ struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+ int ret = 0;
+
+ if (rtc_data->irq) {
+ mutex_lock(&rtc_data->lock);
+ if (rtc_data->timer_alarm)
+ ret = _abb5zes3_rtc_update_timer(dev, enable);
+ else
+ ret = _abb5zes3_rtc_update_alarm(dev, enable);
+ mutex_unlock(&rtc_data->lock);
+ }
+
+ return ret;
+}
+
+static irqreturn_t _abb5zes3_rtc_interrupt(int irq, void *data)
+{
+ struct i2c_client *client = data;
+ struct device *dev = &client->dev;
+ struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+ struct rtc_device *rtc = rtc_data->rtc;
+ u8 regs[ABB5ZES3_CTRL_SEC_LEN];
+ int ret, handled = IRQ_NONE;
+
+ ret = regmap_bulk_read(rtc_data->regmap, 0, regs,
+ ABB5ZES3_CTRL_SEC_LEN);
+ if (ret) {
+ dev_err(dev, "%s: unable to read control section (%d)!\n",
+ __func__, ret);
+ return handled;
+ }
+
+ /*
+ * Check battery low detection flag and disable battery low interrupt
+ * generation if flag is set (interrupt can only be cleared when
+ * battery is replaced).
+ */
+ if (regs[ABB5ZES3_REG_CTRL3] & ABB5ZES3_REG_CTRL3_BLF) {
+ dev_err(dev, "RTC battery is low; please change it!\n");
+
+ _abb5zes3_rtc_battery_low_irq_enable(rtc_data->regmap, false);
+
+ handled = IRQ_HANDLED;
+ }
+
+ /* Check alarm flag */
+ if (regs[ABB5ZES3_REG_CTRL2] & ABB5ZES3_REG_CTRL2_AF) {
+ dev_dbg(dev, "RTC alarm!\n");
+
+ rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+ /* Acknowledge and disable the alarm */
+ _abb5zes3_rtc_clear_alarm(dev);
+ _abb5zes3_rtc_update_alarm(dev, 0);
+
+ handled = IRQ_HANDLED;
+ }
+
+ /* Check watchdog Timer A flag */
+ if (regs[ABB5ZES3_REG_CTRL2] & ABB5ZES3_REG_CTRL2_WTAF) {
+ dev_dbg(dev, "RTC timer!\n");
+
+ rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+ /*
+ * Acknowledge and disable the alarm. Note: WTAF
+ * flag had been cleared when reading CTRL2
+ */
+ _abb5zes3_rtc_update_timer(dev, 0);
+
+ rtc_data->timer_alarm = 0;
+
+ handled = IRQ_HANDLED;
+ }
+
+ return handled;
+}
+
+static const struct rtc_class_ops rtc_ops = {
+ .read_time = _abb5zes3_rtc_read_time,
+ .set_time = abb5zes3_rtc_set_time,
+ .read_alarm = abb5zes3_rtc_read_alarm,
+ .set_alarm = abb5zes3_rtc_set_alarm,
+ .alarm_irq_enable = abb5zes3_rtc_alarm_irq_enable,
+};
+
+static struct regmap_config abb5zes3_rtc_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+};
+
+static int abb5zes3_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct abb5zes3_rtc_data *data = NULL;
+ struct device *dev = &client->dev;
+ struct regmap *regmap;
+ int ret;
+
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C |
+ I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_I2C_BLOCK)) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ regmap = devm_regmap_init_i2c(client, &abb5zes3_rtc_regmap_config);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ dev_err(dev, "%s: regmap allocation failed: %d\n",
+ __func__, ret);
+ goto err;
+ }
+
+ ret = abb5zes3_i2c_validate_chip(regmap);
+ if (ret)
+ goto err;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ mutex_init(&data->lock);
+ data->regmap = regmap;
+ dev_set_drvdata(dev, data);
+
+ ret = abb5zes3_rtc_check_setup(dev);
+ if (ret)
+ goto err;
+
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ _abb5zes3_rtc_interrupt,
+ IRQF_SHARED|IRQF_ONESHOT,
+ DRV_NAME, client);
+ if (!ret) {
+ device_init_wakeup(dev, true);
+ data->irq = client->irq;
+ dev_dbg(dev, "%s: irq %d used by RTC\n", __func__,
+ client->irq);
+ } else {
+ dev_err(dev, "%s: irq %d unavailable (%d)\n",
+ __func__, client->irq, ret);
+ goto err;
+ }
+ }
+
+ data->rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops,
+ THIS_MODULE);
+ ret = PTR_ERR_OR_ZERO(data->rtc);
+ if (ret) {
+ dev_err(dev, "%s: unable to register RTC device (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* Enable battery low detection interrupt if battery not already low */
+ if (!data->battery_low && data->irq) {
+ ret = _abb5zes3_rtc_battery_low_irq_enable(regmap, true);
+ if (ret) {
+ dev_err(dev, "%s: enabling battery low interrupt "
+ "generation failed (%d)\n", __func__, ret);
+ goto err;
+ }
+ }
+
+err:
+ if (ret && data && data->irq)
+ device_init_wakeup(dev, false);
+ return ret;
+}
+
+static int abb5zes3_remove(struct i2c_client *client)
+{
+ struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(&client->dev);
+
+ if (rtc_data->irq > 0)
+ device_init_wakeup(&client->dev, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int abb5zes3_rtc_suspend(struct device *dev)
+{
+ struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ return enable_irq_wake(rtc_data->irq);
+
+ return 0;
+}
+
+static int abb5zes3_rtc_resume(struct device *dev)
+{
+ struct abb5zes3_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+ if (device_may_wakeup(dev))
+ return disable_irq_wake(rtc_data->irq);
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(abb5zes3_rtc_pm_ops, abb5zes3_rtc_suspend,
+ abb5zes3_rtc_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id abb5zes3_dt_match[] = {
+ { .compatible = "abracon,abb5zes3" },
+ { },
+};
+#endif
+
+static const struct i2c_device_id abb5zes3_id[] = {
+ { "abb5zes3", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, abb5zes3_id);
+
+static struct i2c_driver abb5zes3_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .pm = &abb5zes3_rtc_pm_ops,
+ .of_match_table = of_match_ptr(abb5zes3_dt_match),
+ },
+ .probe = abb5zes3_probe,
+ .remove = abb5zes3_remove,
+ .id_table = abb5zes3_id,
+};
+module_i2c_driver(abb5zes3_driver);
+
+MODULE_AUTHOR("Arnaud EBALARD <arno@natisbad.org>");
+MODULE_DESCRIPTION("Abracon AB-RTCMC-32.768kHz-B5ZE-S3 RTC/Alarm driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-armada38x.c b/drivers/rtc/rtc-armada38x.c
new file mode 100644
index 000000000000..43e04af39e09
--- /dev/null
+++ b/drivers/rtc/rtc-armada38x.c
@@ -0,0 +1,320 @@
+/*
+ * RTC driver for the Armada 38x Marvell SoCs
+ *
+ * Copyright (C) 2015 Marvell
+ *
+ * Gregory Clement <gregory.clement@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+
+#define RTC_STATUS 0x0
+#define RTC_STATUS_ALARM1 BIT(0)
+#define RTC_STATUS_ALARM2 BIT(1)
+#define RTC_IRQ1_CONF 0x4
+#define RTC_IRQ1_AL_EN BIT(0)
+#define RTC_IRQ1_FREQ_EN BIT(1)
+#define RTC_IRQ1_FREQ_1HZ BIT(2)
+#define RTC_TIME 0xC
+#define RTC_ALARM1 0x10
+
+#define SOC_RTC_INTERRUPT 0x8
+#define SOC_RTC_ALARM1 BIT(0)
+#define SOC_RTC_ALARM2 BIT(1)
+#define SOC_RTC_ALARM1_MASK BIT(2)
+#define SOC_RTC_ALARM2_MASK BIT(3)
+
+struct armada38x_rtc {
+ struct rtc_device *rtc_dev;
+ void __iomem *regs;
+ void __iomem *regs_soc;
+ spinlock_t lock;
+ int irq;
+};
+
+/*
+ * According to the datasheet, the OS should wait 5us after every
+ * register write to the RTC hard macro so that the required update
+ * can occur without holding off the system bus
+ */
+static void rtc_delayed_write(u32 val, struct armada38x_rtc *rtc, int offset)
+{
+ writel(val, rtc->regs + offset);
+ udelay(5);
+}
+
+static int armada38x_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long time, time_check, flags;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ time = readl(rtc->regs + RTC_TIME);
+ /*
+ * WA for failing time set attempts. As stated in HW ERRATA if
+ * more than one second between two time reads is detected
+ * then read once again.
+ */
+ time_check = readl(rtc->regs + RTC_TIME);
+ if ((time_check - time) > 1)
+ time_check = readl(rtc->regs + RTC_TIME);
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ rtc_time_to_tm(time_check, tm);
+
+ return 0;
+}
+
+static int armada38x_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+ int ret = 0;
+ unsigned long time, flags;
+
+ ret = rtc_tm_to_time(tm, &time);
+
+ if (ret)
+ goto out;
+ /*
+ * Setting the RTC time not always succeeds. According to the
+ * errata we need to first write on the status register and
+ * then wait for 100ms before writing to the time register to be
+ * sure that the data will be taken into account.
+ */
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ rtc_delayed_write(0, rtc, RTC_STATUS);
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ msleep(100);
+
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ rtc_delayed_write(time, rtc, RTC_TIME);
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+out:
+ return ret;
+}
+
+static int armada38x_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long time, flags;
+ u32 val;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ time = readl(rtc->regs + RTC_ALARM1);
+ val = readl(rtc->regs + RTC_IRQ1_CONF) & RTC_IRQ1_AL_EN;
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ alrm->enabled = val ? 1 : 0;
+ rtc_time_to_tm(time, &alrm->time);
+
+ return 0;
+}
+
+static int armada38x_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long time, flags;
+ int ret = 0;
+ u32 val;
+
+ ret = rtc_tm_to_time(&alrm->time, &time);
+
+ if (ret)
+ goto out;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ rtc_delayed_write(time, rtc, RTC_ALARM1);
+
+ if (alrm->enabled) {
+ rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
+ val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
+ writel(val | SOC_RTC_ALARM1_MASK,
+ rtc->regs_soc + SOC_RTC_INTERRUPT);
+ }
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+out:
+ return ret;
+}
+
+static int armada38x_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ if (enabled)
+ rtc_delayed_write(RTC_IRQ1_AL_EN, rtc, RTC_IRQ1_CONF);
+ else
+ rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
+
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ return 0;
+}
+
+static irqreturn_t armada38x_rtc_alarm_irq(int irq, void *data)
+{
+ struct armada38x_rtc *rtc = data;
+ u32 val;
+ int event = RTC_IRQF | RTC_AF;
+
+ dev_dbg(&rtc->rtc_dev->dev, "%s:irq(%d)\n", __func__, irq);
+
+ spin_lock(&rtc->lock);
+
+ val = readl(rtc->regs_soc + SOC_RTC_INTERRUPT);
+
+ writel(val & ~SOC_RTC_ALARM1, rtc->regs_soc + SOC_RTC_INTERRUPT);
+ val = readl(rtc->regs + RTC_IRQ1_CONF);
+ /* disable all the interrupts for alarm 1 */
+ rtc_delayed_write(0, rtc, RTC_IRQ1_CONF);
+ /* Ack the event */
+ rtc_delayed_write(RTC_STATUS_ALARM1, rtc, RTC_STATUS);
+
+ spin_unlock(&rtc->lock);
+
+ if (val & RTC_IRQ1_FREQ_EN) {
+ if (val & RTC_IRQ1_FREQ_1HZ)
+ event |= RTC_UF;
+ else
+ event |= RTC_PF;
+ }
+
+ rtc_update_irq(rtc->rtc_dev, 1, event);
+
+ return IRQ_HANDLED;
+}
+
+static struct rtc_class_ops armada38x_rtc_ops = {
+ .read_time = armada38x_rtc_read_time,
+ .set_time = armada38x_rtc_set_time,
+ .read_alarm = armada38x_rtc_read_alarm,
+ .set_alarm = armada38x_rtc_set_alarm,
+ .alarm_irq_enable = armada38x_rtc_alarm_irq_enable,
+};
+
+static __init int armada38x_rtc_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct armada38x_rtc *rtc;
+ int ret;
+
+ rtc = devm_kzalloc(&pdev->dev, sizeof(struct armada38x_rtc),
+ GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ spin_lock_init(&rtc->lock);
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc");
+ rtc->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtc->regs))
+ return PTR_ERR(rtc->regs);
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rtc-soc");
+ rtc->regs_soc = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtc->regs_soc))
+ return PTR_ERR(rtc->regs_soc);
+
+ rtc->irq = platform_get_irq(pdev, 0);
+
+ if (rtc->irq < 0) {
+ dev_err(&pdev->dev, "no irq\n");
+ return rtc->irq;
+ }
+ if (devm_request_irq(&pdev->dev, rtc->irq, armada38x_rtc_alarm_irq,
+ 0, pdev->name, rtc) < 0) {
+ dev_warn(&pdev->dev, "Interrupt not available.\n");
+ rtc->irq = -1;
+ /*
+ * If there is no interrupt available then we can't
+ * use the alarm
+ */
+ armada38x_rtc_ops.set_alarm = NULL;
+ armada38x_rtc_ops.alarm_irq_enable = NULL;
+ }
+ platform_set_drvdata(pdev, rtc);
+ if (rtc->irq != -1)
+ device_init_wakeup(&pdev->dev, 1);
+
+ rtc->rtc_dev = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &armada38x_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc_dev)) {
+ ret = PTR_ERR(rtc->rtc_dev);
+ dev_err(&pdev->dev, "Failed to register RTC device: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int armada38x_rtc_suspend(struct device *dev)
+{
+ if (device_may_wakeup(dev)) {
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+
+ return enable_irq_wake(rtc->irq);
+ }
+
+ return 0;
+}
+
+static int armada38x_rtc_resume(struct device *dev)
+{
+ if (device_may_wakeup(dev)) {
+ struct armada38x_rtc *rtc = dev_get_drvdata(dev);
+
+ return disable_irq_wake(rtc->irq);
+ }
+
+ return 0;
+}
+#endif
+
+static SIMPLE_DEV_PM_OPS(armada38x_rtc_pm_ops,
+ armada38x_rtc_suspend, armada38x_rtc_resume);
+
+#ifdef CONFIG_OF
+static const struct of_device_id armada38x_rtc_of_match_table[] = {
+ { .compatible = "marvell,armada-380-rtc", },
+ {}
+};
+#endif
+
+static struct platform_driver armada38x_rtc_driver = {
+ .driver = {
+ .name = "armada38x-rtc",
+ .pm = &armada38x_rtc_pm_ops,
+ .of_match_table = of_match_ptr(armada38x_rtc_of_match_table),
+ },
+};
+
+module_platform_driver_probe(armada38x_rtc_driver, armada38x_rtc_probe);
+
+MODULE_DESCRIPTION("Marvell Armada 38x RTC driver");
+MODULE_AUTHOR("Gregory CLEMENT <gregory.clement@free-electrons.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 6b9aaf1afc72..2183fd2750ab 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -313,7 +313,7 @@ static const struct rtc_class_ops at91_rtc_ops = {
.alarm_irq_enable = at91_rtc_alarm_irq_enable,
};
-static struct regmap_config gpbr_regmap_config = {
+static const struct regmap_config gpbr_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/rtc/rtc-dev.c b/drivers/rtc/rtc-dev.c
index d04939369251..799c34bcb26f 100644
--- a/drivers/rtc/rtc-dev.c
+++ b/drivers/rtc/rtc-dev.c
@@ -304,12 +304,12 @@ static long rtc_dev_ioctl(struct file *file,
* Not supported here.
*/
{
- unsigned long now, then;
+ time64_t now, then;
err = rtc_read_time(rtc, &tm);
if (err < 0)
return err;
- rtc_tm_to_time(&tm, &now);
+ now = rtc_tm_to_time64(&tm);
alarm.time.tm_mday = tm.tm_mday;
alarm.time.tm_mon = tm.tm_mon;
@@ -317,11 +317,11 @@ static long rtc_dev_ioctl(struct file *file,
err = rtc_valid_tm(&alarm.time);
if (err < 0)
return err;
- rtc_tm_to_time(&alarm.time, &then);
+ then = rtc_tm_to_time64(&alarm.time);
/* alarm may need to wrap into tomorrow */
if (then < now) {
- rtc_time_to_tm(now + 24 * 60 * 60, &tm);
+ rtc_time64_to_tm(now + 24 * 60 * 60, &tm);
alarm.time.tm_mday = tm.tm_mday;
alarm.time.tm_mon = tm.tm_mon;
alarm.time.tm_year = tm.tm_year;
diff --git a/drivers/rtc/rtc-ds1685.c b/drivers/rtc/rtc-ds1685.c
new file mode 100644
index 000000000000..803869c7d7c2
--- /dev/null
+++ b/drivers/rtc/rtc-ds1685.c
@@ -0,0 +1,2250 @@
+/*
+ * An rtc driver for the Dallas/Maxim DS1685/DS1687 and related real-time
+ * chips.
+ *
+ * Copyright (C) 2011-2014 Joshua Kinard <kumba@gentoo.org>.
+ * Copyright (C) 2009 Matthias Fuchs <matthias.fuchs@esd-electronics.com>.
+ *
+ * References:
+ * DS1685/DS1687 3V/5V Real-Time Clocks, 19-5215, Rev 4/10.
+ * DS17x85/DS17x87 3V/5V Real-Time Clocks, 19-5222, Rev 4/10.
+ * DS1689/DS1693 3V/5V Serialized Real-Time Clocks, Rev 112105.
+ * Application Note 90, Using the Multiplex Bus RTC Extended Features.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/bcd.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/rtc.h>
+#include <linux/workqueue.h>
+
+#include <linux/rtc/ds1685.h>
+
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
+
+#define DRV_VERSION "0.42.0"
+
+
+/* ----------------------------------------------------------------------- */
+/* Standard read/write functions if platform does not provide overrides */
+
+/**
+ * ds1685_read - read a value from an rtc register.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @reg: the register address to read.
+ */
+static u8
+ds1685_read(struct ds1685_priv *rtc, int reg)
+{
+ return readb((u8 __iomem *)rtc->regs +
+ (reg * rtc->regstep));
+}
+
+/**
+ * ds1685_write - write a value to an rtc register.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @reg: the register address to write.
+ * @value: value to write to the register.
+ */
+static void
+ds1685_write(struct ds1685_priv *rtc, int reg, u8 value)
+{
+ writeb(value, ((u8 __iomem *)rtc->regs +
+ (reg * rtc->regstep)));
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* Inlined functions */
+
+/**
+ * ds1685_rtc_bcd2bin - bcd2bin wrapper in case platform doesn't support BCD.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @val: u8 time value to consider converting.
+ * @bcd_mask: u8 mask value if BCD mode is used.
+ * @bin_mask: u8 mask value if BIN mode is used.
+ *
+ * Returns the value, converted to BIN if originally in BCD and bcd_mode TRUE.
+ */
+static inline u8
+ds1685_rtc_bcd2bin(struct ds1685_priv *rtc, u8 val, u8 bcd_mask, u8 bin_mask)
+{
+ if (rtc->bcd_mode)
+ return (bcd2bin(val) & bcd_mask);
+
+ return (val & bin_mask);
+}
+
+/**
+ * ds1685_rtc_bin2bcd - bin2bcd wrapper in case platform doesn't support BCD.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @val: u8 time value to consider converting.
+ * @bin_mask: u8 mask value if BIN mode is used.
+ * @bcd_mask: u8 mask value if BCD mode is used.
+ *
+ * Returns the value, converted to BCD if originally in BIN and bcd_mode TRUE.
+ */
+static inline u8
+ds1685_rtc_bin2bcd(struct ds1685_priv *rtc, u8 val, u8 bin_mask, u8 bcd_mask)
+{
+ if (rtc->bcd_mode)
+ return (bin2bcd(val) & bcd_mask);
+
+ return (val & bin_mask);
+}
+
+/**
+ * ds1685_rtc_switch_to_bank0 - switch the rtc to bank 0.
+ * @rtc: pointer to the ds1685 rtc structure.
+ */
+static inline void
+ds1685_rtc_switch_to_bank0(struct ds1685_priv *rtc)
+{
+ rtc->write(rtc, RTC_CTRL_A,
+ (rtc->read(rtc, RTC_CTRL_A) & ~(RTC_CTRL_A_DV0)));
+}
+
+/**
+ * ds1685_rtc_switch_to_bank1 - switch the rtc to bank 1.
+ * @rtc: pointer to the ds1685 rtc structure.
+ */
+static inline void
+ds1685_rtc_switch_to_bank1(struct ds1685_priv *rtc)
+{
+ rtc->write(rtc, RTC_CTRL_A,
+ (rtc->read(rtc, RTC_CTRL_A) | RTC_CTRL_A_DV0));
+}
+
+/**
+ * ds1685_rtc_begin_data_access - prepare the rtc for data access.
+ * @rtc: pointer to the ds1685 rtc structure.
+ *
+ * This takes several steps to prepare the rtc for access to get/set time
+ * and alarm values from the rtc registers:
+ * - Sets the SET bit in Control Register B.
+ * - Reads Ext Control Register 4A and checks the INCR bit.
+ * - If INCR is active, a short delay is added before Ext Control Register 4A
+ * is read again in a loop until INCR is inactive.
+ * - Switches the rtc to bank 1. This allows access to all relevant
+ * data for normal rtc operation, as bank 0 contains only the nvram.
+ */
+static inline void
+ds1685_rtc_begin_data_access(struct ds1685_priv *rtc)
+{
+ /* Set the SET bit in Ctrl B */
+ rtc->write(rtc, RTC_CTRL_B,
+ (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET));
+
+ /* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */
+ while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR)
+ cpu_relax();
+
+ /* Switch to Bank 1 */
+ ds1685_rtc_switch_to_bank1(rtc);
+}
+
+/**
+ * ds1685_rtc_end_data_access - end data access on the rtc.
+ * @rtc: pointer to the ds1685 rtc structure.
+ *
+ * This ends what was started by ds1685_rtc_begin_data_access:
+ * - Switches the rtc back to bank 0.
+ * - Clears the SET bit in Control Register B.
+ */
+static inline void
+ds1685_rtc_end_data_access(struct ds1685_priv *rtc)
+{
+ /* Switch back to Bank 0 */
+ ds1685_rtc_switch_to_bank1(rtc);
+
+ /* Clear the SET bit in Ctrl B */
+ rtc->write(rtc, RTC_CTRL_B,
+ (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_SET)));
+}
+
+/**
+ * ds1685_rtc_begin_ctrl_access - prepare the rtc for ctrl access.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @flags: irq flags variable for spin_lock_irqsave.
+ *
+ * This takes several steps to prepare the rtc for access to read just the
+ * control registers:
+ * - Sets a spinlock on the rtc IRQ.
+ * - Switches the rtc to bank 1. This allows access to the two extended
+ * control registers.
+ *
+ * Only use this where you are certain another lock will not be held.
+ */
+static inline void
+ds1685_rtc_begin_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+{
+ spin_lock_irqsave(&rtc->lock, flags);
+ ds1685_rtc_switch_to_bank1(rtc);
+}
+
+/**
+ * ds1685_rtc_end_ctrl_access - end ctrl access on the rtc.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @flags: irq flags variable for spin_unlock_irqrestore.
+ *
+ * This ends what was started by ds1685_rtc_begin_ctrl_access:
+ * - Switches the rtc back to bank 0.
+ * - Unsets the spinlock on the rtc IRQ.
+ */
+static inline void
+ds1685_rtc_end_ctrl_access(struct ds1685_priv *rtc, unsigned long flags)
+{
+ ds1685_rtc_switch_to_bank0(rtc);
+ spin_unlock_irqrestore(&rtc->lock, flags);
+}
+
+/**
+ * ds1685_rtc_get_ssn - retrieve the silicon serial number.
+ * @rtc: pointer to the ds1685 rtc structure.
+ * @ssn: u8 array to hold the bits of the silicon serial number.
+ *
+ * This number starts at 0x40, and is 8-bytes long, ending at 0x47. The
+ * first byte is the model number, the next six bytes are the serial number
+ * digits, and the final byte is a CRC check byte. Together, they form the
+ * silicon serial number.
+ *
+ * These values are stored in bank1, so ds1685_rtc_switch_to_bank1 must be
+ * called first before calling this function, else data will be read out of
+ * the bank0 NVRAM. Be sure to call ds1685_rtc_switch_to_bank0 when done.
+ */
+static inline void
+ds1685_rtc_get_ssn(struct ds1685_priv *rtc, u8 *ssn)
+{
+ ssn[0] = rtc->read(rtc, RTC_BANK1_SSN_MODEL);
+ ssn[1] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_1);
+ ssn[2] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_2);
+ ssn[3] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_3);
+ ssn[4] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_4);
+ ssn[5] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_5);
+ ssn[6] = rtc->read(rtc, RTC_BANK1_SSN_BYTE_6);
+ ssn[7] = rtc->read(rtc, RTC_BANK1_SSN_CRC);
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* Read/Set Time & Alarm functions */
+
+/**
+ * ds1685_rtc_read_time - reads the time registers.
+ * @dev: pointer to device structure.
+ * @tm: pointer to rtc_time structure.
+ */
+static int
+ds1685_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrlb, century;
+ u8 seconds, minutes, hours, wday, mday, month, years;
+
+ /* Fetch the time info from the RTC registers. */
+ ds1685_rtc_begin_data_access(rtc);
+ seconds = rtc->read(rtc, RTC_SECS);
+ minutes = rtc->read(rtc, RTC_MINS);
+ hours = rtc->read(rtc, RTC_HRS);
+ wday = rtc->read(rtc, RTC_WDAY);
+ mday = rtc->read(rtc, RTC_MDAY);
+ month = rtc->read(rtc, RTC_MONTH);
+ years = rtc->read(rtc, RTC_YEAR);
+ century = rtc->read(rtc, RTC_CENTURY);
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ ds1685_rtc_end_data_access(rtc);
+
+ /* bcd2bin if needed, perform fixups, and store to rtc_time. */
+ years = ds1685_rtc_bcd2bin(rtc, years, RTC_YEAR_BCD_MASK,
+ RTC_YEAR_BIN_MASK);
+ century = ds1685_rtc_bcd2bin(rtc, century, RTC_CENTURY_MASK,
+ RTC_CENTURY_MASK);
+ tm->tm_sec = ds1685_rtc_bcd2bin(rtc, seconds, RTC_SECS_BCD_MASK,
+ RTC_SECS_BIN_MASK);
+ tm->tm_min = ds1685_rtc_bcd2bin(rtc, minutes, RTC_MINS_BCD_MASK,
+ RTC_MINS_BIN_MASK);
+ tm->tm_hour = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_24_BCD_MASK,
+ RTC_HRS_24_BIN_MASK);
+ tm->tm_wday = (ds1685_rtc_bcd2bin(rtc, wday, RTC_WDAY_MASK,
+ RTC_WDAY_MASK) - 1);
+ tm->tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
+ RTC_MDAY_BIN_MASK);
+ tm->tm_mon = (ds1685_rtc_bcd2bin(rtc, month, RTC_MONTH_BCD_MASK,
+ RTC_MONTH_BIN_MASK) - 1);
+ tm->tm_year = ((years + (century * 100)) - 1900);
+ tm->tm_yday = rtc_year_days(tm->tm_mday, tm->tm_mon, tm->tm_year);
+ tm->tm_isdst = 0; /* RTC has hardcoded timezone, so don't use. */
+
+ return rtc_valid_tm(tm);
+}
+
+/**
+ * ds1685_rtc_set_time - sets the time registers.
+ * @dev: pointer to device structure.
+ * @tm: pointer to rtc_time structure.
+ */
+static int
+ds1685_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrlb, seconds, minutes, hours, wday, mday, month, years, century;
+
+ /* Fetch the time info from rtc_time. */
+ seconds = ds1685_rtc_bin2bcd(rtc, tm->tm_sec, RTC_SECS_BIN_MASK,
+ RTC_SECS_BCD_MASK);
+ minutes = ds1685_rtc_bin2bcd(rtc, tm->tm_min, RTC_MINS_BIN_MASK,
+ RTC_MINS_BCD_MASK);
+ hours = ds1685_rtc_bin2bcd(rtc, tm->tm_hour, RTC_HRS_24_BIN_MASK,
+ RTC_HRS_24_BCD_MASK);
+ wday = ds1685_rtc_bin2bcd(rtc, (tm->tm_wday + 1), RTC_WDAY_MASK,
+ RTC_WDAY_MASK);
+ mday = ds1685_rtc_bin2bcd(rtc, tm->tm_mday, RTC_MDAY_BIN_MASK,
+ RTC_MDAY_BCD_MASK);
+ month = ds1685_rtc_bin2bcd(rtc, (tm->tm_mon + 1), RTC_MONTH_BIN_MASK,
+ RTC_MONTH_BCD_MASK);
+ years = ds1685_rtc_bin2bcd(rtc, (tm->tm_year % 100),
+ RTC_YEAR_BIN_MASK, RTC_YEAR_BCD_MASK);
+ century = ds1685_rtc_bin2bcd(rtc, ((tm->tm_year + 1900) / 100),
+ RTC_CENTURY_MASK, RTC_CENTURY_MASK);
+
+ /*
+ * Perform Sanity Checks:
+ * - Months: !> 12, Month Day != 0.
+ * - Month Day !> Max days in current month.
+ * - Hours !>= 24, Mins !>= 60, Secs !>= 60, & Weekday !> 7.
+ */
+ if ((tm->tm_mon > 11) || (mday == 0))
+ return -EDOM;
+
+ if (tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year))
+ return -EDOM;
+
+ if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) ||
+ (tm->tm_sec >= 60) || (wday > 7))
+ return -EDOM;
+
+ /*
+ * Set the data mode to use and store the time values in the
+ * RTC registers.
+ */
+ ds1685_rtc_begin_data_access(rtc);
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ if (rtc->bcd_mode)
+ ctrlb &= ~(RTC_CTRL_B_DM);
+ else
+ ctrlb |= RTC_CTRL_B_DM;
+ rtc->write(rtc, RTC_CTRL_B, ctrlb);
+ rtc->write(rtc, RTC_SECS, seconds);
+ rtc->write(rtc, RTC_MINS, minutes);
+ rtc->write(rtc, RTC_HRS, hours);
+ rtc->write(rtc, RTC_WDAY, wday);
+ rtc->write(rtc, RTC_MDAY, mday);
+ rtc->write(rtc, RTC_MONTH, month);
+ rtc->write(rtc, RTC_YEAR, years);
+ rtc->write(rtc, RTC_CENTURY, century);
+ ds1685_rtc_end_data_access(rtc);
+
+ return 0;
+}
+
+/**
+ * ds1685_rtc_read_alarm - reads the alarm registers.
+ * @dev: pointer to device structure.
+ * @alrm: pointer to rtc_wkalrm structure.
+ *
+ * There are three primary alarm registers: seconds, minutes, and hours.
+ * A fourth alarm register for the month date is also available in bank1 for
+ * kickstart/wakeup features. The DS1685/DS1687 manual states that a
+ * "don't care" value ranging from 0xc0 to 0xff may be written into one or
+ * more of the three alarm bytes to act as a wildcard value. The fourth
+ * byte doesn't support a "don't care" value.
+ */
+static int
+ds1685_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 seconds, minutes, hours, mday, ctrlb, ctrlc;
+
+ /* Fetch the alarm info from the RTC alarm registers. */
+ ds1685_rtc_begin_data_access(rtc);
+ seconds = rtc->read(rtc, RTC_SECS_ALARM);
+ minutes = rtc->read(rtc, RTC_MINS_ALARM);
+ hours = rtc->read(rtc, RTC_HRS_ALARM);
+ mday = rtc->read(rtc, RTC_MDAY_ALARM);
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ ctrlc = rtc->read(rtc, RTC_CTRL_C);
+ ds1685_rtc_end_data_access(rtc);
+
+ /* Check month date. */
+ if (!(mday >= 1) && (mday <= 31))
+ return -EDOM;
+
+ /*
+ * Check the three alarm bytes.
+ *
+ * The Linux RTC system doesn't support the "don't care" capability
+ * of this RTC chip. We check for it anyways in case support is
+ * added in the future.
+ */
+ if (unlikely(seconds >= 0xc0))
+ alrm->time.tm_sec = -1;
+ else
+ alrm->time.tm_sec = ds1685_rtc_bcd2bin(rtc, seconds,
+ RTC_SECS_BCD_MASK,
+ RTC_SECS_BIN_MASK);
+
+ if (unlikely(minutes >= 0xc0))
+ alrm->time.tm_min = -1;
+ else
+ alrm->time.tm_min = ds1685_rtc_bcd2bin(rtc, minutes,
+ RTC_MINS_BCD_MASK,
+ RTC_MINS_BIN_MASK);
+
+ if (unlikely(hours >= 0xc0))
+ alrm->time.tm_hour = -1;
+ else
+ alrm->time.tm_hour = ds1685_rtc_bcd2bin(rtc, hours,
+ RTC_HRS_24_BCD_MASK,
+ RTC_HRS_24_BIN_MASK);
+
+ /* Write the data to rtc_wkalrm. */
+ alrm->time.tm_mday = ds1685_rtc_bcd2bin(rtc, mday, RTC_MDAY_BCD_MASK,
+ RTC_MDAY_BIN_MASK);
+ alrm->time.tm_mon = -1;
+ alrm->time.tm_year = -1;
+ alrm->time.tm_wday = -1;
+ alrm->time.tm_yday = -1;
+ alrm->time.tm_isdst = -1;
+ alrm->enabled = !!(ctrlb & RTC_CTRL_B_AIE);
+ alrm->pending = !!(ctrlc & RTC_CTRL_C_AF);
+
+ return 0;
+}
+
+/**
+ * ds1685_rtc_set_alarm - sets the alarm in registers.
+ * @dev: pointer to device structure.
+ * @alrm: pointer to rtc_wkalrm structure.
+ */
+static int
+ds1685_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrlb, seconds, minutes, hours, mday;
+
+ /* Fetch the alarm info and convert to BCD. */
+ seconds = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_sec,
+ RTC_SECS_BIN_MASK,
+ RTC_SECS_BCD_MASK);
+ minutes = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_min,
+ RTC_MINS_BIN_MASK,
+ RTC_MINS_BCD_MASK);
+ hours = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_hour,
+ RTC_HRS_24_BIN_MASK,
+ RTC_HRS_24_BCD_MASK);
+ mday = ds1685_rtc_bin2bcd(rtc, alrm->time.tm_mday,
+ RTC_MDAY_BIN_MASK,
+ RTC_MDAY_BCD_MASK);
+
+ /* Check the month date for validity. */
+ if (!(mday >= 1) && (mday <= 31))
+ return -EDOM;
+
+ /*
+ * Check the three alarm bytes.
+ *
+ * The Linux RTC system doesn't support the "don't care" capability
+ * of this RTC chip because rtc_valid_tm tries to validate every
+ * field, and we only support four fields. We put the support
+ * here anyways for the future.
+ */
+ if (unlikely(seconds >= 0xc0))
+ seconds = 0xff;
+
+ if (unlikely(minutes >= 0xc0))
+ minutes = 0xff;
+
+ if (unlikely(hours >= 0xc0))
+ hours = 0xff;
+
+ alrm->time.tm_mon = -1;
+ alrm->time.tm_year = -1;
+ alrm->time.tm_wday = -1;
+ alrm->time.tm_yday = -1;
+ alrm->time.tm_isdst = -1;
+
+ /* Disable the alarm interrupt first. */
+ ds1685_rtc_begin_data_access(rtc);
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ rtc->write(rtc, RTC_CTRL_B, (ctrlb & ~(RTC_CTRL_B_AIE)));
+
+ /* Read ctrlc to clear RTC_CTRL_C_AF. */
+ rtc->read(rtc, RTC_CTRL_C);
+
+ /*
+ * Set the data mode to use and store the time values in the
+ * RTC registers.
+ */
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ if (rtc->bcd_mode)
+ ctrlb &= ~(RTC_CTRL_B_DM);
+ else
+ ctrlb |= RTC_CTRL_B_DM;
+ rtc->write(rtc, RTC_CTRL_B, ctrlb);
+ rtc->write(rtc, RTC_SECS_ALARM, seconds);
+ rtc->write(rtc, RTC_MINS_ALARM, minutes);
+ rtc->write(rtc, RTC_HRS_ALARM, hours);
+ rtc->write(rtc, RTC_MDAY_ALARM, mday);
+
+ /* Re-enable the alarm if needed. */
+ if (alrm->enabled) {
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ ctrlb |= RTC_CTRL_B_AIE;
+ rtc->write(rtc, RTC_CTRL_B, ctrlb);
+ }
+
+ /* Done! */
+ ds1685_rtc_end_data_access(rtc);
+
+ return 0;
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* /dev/rtcX Interface functions */
+
+/**
+ * ds1685_rtc_alarm_irq_enable - replaces ioctl() RTC_AIE on/off.
+ * @dev: pointer to device structure.
+ * @enabled: flag indicating whether to enable or disable.
+ */
+static int
+ds1685_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
+{
+ struct ds1685_priv *rtc = dev_get_drvdata(dev);
+ unsigned long flags = 0;
+
+ /* Enable/disable the Alarm IRQ-Enable flag. */
+ spin_lock_irqsave(&rtc->lock, flags);
+
+ /* Flip the requisite interrupt-enable bit. */
+ if (enabled)
+ rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) |
+ RTC_CTRL_B_AIE));
+ else
+ rtc->write(rtc, RTC_CTRL_B, (rtc->read(rtc, RTC_CTRL_B) &
+ ~(RTC_CTRL_B_AIE)));
+
+ /* Read Control C to clear all the flag bits. */
+ rtc->read(rtc, RTC_CTRL_C);
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ return 0;
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* IRQ handler & workqueue. */
+
+/**
+ * ds1685_rtc_irq_handler - IRQ handler.
+ * @irq: IRQ number.
+ * @dev_id: platform device pointer.
+ */
+static irqreturn_t
+ds1685_rtc_irq_handler(int irq, void *dev_id)
+{
+ struct platform_device *pdev = dev_id;
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrlb, ctrlc;
+ unsigned long events = 0;
+ u8 num_irqs = 0;
+
+ /* Abort early if the device isn't ready yet (i.e., DEBUG_SHIRQ). */
+ if (unlikely(!rtc))
+ return IRQ_HANDLED;
+
+ /* Ctrlb holds the interrupt-enable bits and ctrlc the flag bits. */
+ spin_lock(&rtc->lock);
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ ctrlc = rtc->read(rtc, RTC_CTRL_C);
+
+ /* Is the IRQF bit set? */
+ if (likely(ctrlc & RTC_CTRL_C_IRQF)) {
+ /*
+ * We need to determine if it was one of the standard
+ * events: PF, AF, or UF. If so, we handle them and
+ * update the RTC core.
+ */
+ if (likely(ctrlc & RTC_CTRL_B_PAU_MASK)) {
+ events = RTC_IRQF;
+
+ /* Check for a periodic interrupt. */
+ if ((ctrlb & RTC_CTRL_B_PIE) &&
+ (ctrlc & RTC_CTRL_C_PF)) {
+ events |= RTC_PF;
+ num_irqs++;
+ }
+
+ /* Check for an alarm interrupt. */
+ if ((ctrlb & RTC_CTRL_B_AIE) &&
+ (ctrlc & RTC_CTRL_C_AF)) {
+ events |= RTC_AF;
+ num_irqs++;
+ }
+
+ /* Check for an update interrupt. */
+ if ((ctrlb & RTC_CTRL_B_UIE) &&
+ (ctrlc & RTC_CTRL_C_UF)) {
+ events |= RTC_UF;
+ num_irqs++;
+ }
+
+ rtc_update_irq(rtc->dev, num_irqs, events);
+ } else {
+ /*
+ * One of the "extended" interrupts was received that
+ * is not recognized by the RTC core. These need to
+ * be handled in task context as they can call other
+ * functions and the time spent in irq context needs
+ * to be minimized. Schedule them into a workqueue
+ * and inform the RTC core that the IRQs were handled.
+ */
+ spin_unlock(&rtc->lock);
+ schedule_work(&rtc->work);
+ rtc_update_irq(rtc->dev, 0, 0);
+ return IRQ_HANDLED;
+ }
+ }
+ spin_unlock(&rtc->lock);
+
+ return events ? IRQ_HANDLED : IRQ_NONE;
+}
+
+/**
+ * ds1685_rtc_work_queue - work queue handler.
+ * @work: work_struct containing data to work on in task context.
+ */
+static void
+ds1685_rtc_work_queue(struct work_struct *work)
+{
+ struct ds1685_priv *rtc = container_of(work,
+ struct ds1685_priv, work);
+ struct platform_device *pdev = to_platform_device(&rtc->dev->dev);
+ struct mutex *rtc_mutex = &rtc->dev->ops_lock;
+ u8 ctrl4a, ctrl4b;
+
+ mutex_lock(rtc_mutex);
+
+ ds1685_rtc_switch_to_bank1(rtc);
+ ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+ ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
+
+ /*
+ * Check for a kickstart interrupt. With Vcc applied, this
+ * typically means that the power button was pressed, so we
+ * begin the shutdown sequence.
+ */
+ if ((ctrl4b & RTC_CTRL_4B_KSE) && (ctrl4a & RTC_CTRL_4A_KF)) {
+ /* Briefly disable kickstarts to debounce button presses. */
+ rtc->write(rtc, RTC_EXT_CTRL_4B,
+ (rtc->read(rtc, RTC_EXT_CTRL_4B) &
+ ~(RTC_CTRL_4B_KSE)));
+
+ /* Clear the kickstart flag. */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (ctrl4a & ~(RTC_CTRL_4A_KF)));
+
+
+ /*
+ * Sleep 500ms before re-enabling kickstarts. This allows
+ * adequate time to avoid reading signal jitter as additional
+ * button presses.
+ */
+ msleep(500);
+ rtc->write(rtc, RTC_EXT_CTRL_4B,
+ (rtc->read(rtc, RTC_EXT_CTRL_4B) |
+ RTC_CTRL_4B_KSE));
+
+ /* Call the platform pre-poweroff function. Else, shutdown. */
+ if (rtc->prepare_poweroff != NULL)
+ rtc->prepare_poweroff();
+ else
+ ds1685_rtc_poweroff(pdev);
+ }
+
+ /*
+ * Check for a wake-up interrupt. With Vcc applied, this is
+ * essentially a second alarm interrupt, except it takes into
+ * account the 'date' register in bank1 in addition to the
+ * standard three alarm registers.
+ */
+ if ((ctrl4b & RTC_CTRL_4B_WIE) && (ctrl4a & RTC_CTRL_4A_WF)) {
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (ctrl4a & ~(RTC_CTRL_4A_WF)));
+
+ /* Call the platform wake_alarm function if defined. */
+ if (rtc->wake_alarm != NULL)
+ rtc->wake_alarm();
+ else
+ dev_warn(&pdev->dev,
+ "Wake Alarm IRQ just occurred!\n");
+ }
+
+ /*
+ * Check for a ram-clear interrupt. This happens if RIE=1 and RF=0
+ * when RCE=1 in 4B. This clears all NVRAM bytes in bank0 by setting
+ * each byte to a logic 1. This has no effect on any extended
+ * NV-SRAM that might be present, nor on the time/calendar/alarm
+ * registers. After a ram-clear is completed, there is a minimum
+ * recovery time of ~150ms in which all reads/writes are locked out.
+ * NOTE: A ram-clear can still occur if RCE=1 and RIE=0. We cannot
+ * catch this scenario.
+ */
+ if ((ctrl4b & RTC_CTRL_4B_RIE) && (ctrl4a & RTC_CTRL_4A_RF)) {
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (ctrl4a & ~(RTC_CTRL_4A_RF)));
+ msleep(150);
+
+ /* Call the platform post_ram_clear function if defined. */
+ if (rtc->post_ram_clear != NULL)
+ rtc->post_ram_clear();
+ else
+ dev_warn(&pdev->dev,
+ "RAM-Clear IRQ just occurred!\n");
+ }
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ mutex_unlock(rtc_mutex);
+}
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* ProcFS interface */
+
+#ifdef CONFIG_PROC_FS
+#define NUM_REGS 6 /* Num of control registers. */
+#define NUM_BITS 8 /* Num bits per register. */
+#define NUM_SPACES 4 /* Num spaces between each bit. */
+
+/*
+ * Periodic Interrupt Rates.
+ */
+static const char *ds1685_rtc_pirq_rate[16] = {
+ "none", "3.90625ms", "7.8125ms", "0.122070ms", "0.244141ms",
+ "0.488281ms", "0.9765625ms", "1.953125ms", "3.90625ms", "7.8125ms",
+ "15.625ms", "31.25ms", "62.5ms", "125ms", "250ms", "500ms"
+};
+
+/*
+ * Square-Wave Output Frequencies.
+ */
+static const char *ds1685_rtc_sqw_freq[16] = {
+ "none", "256Hz", "128Hz", "8192Hz", "4096Hz", "2048Hz", "1024Hz",
+ "512Hz", "256Hz", "128Hz", "64Hz", "32Hz", "16Hz", "8Hz", "4Hz", "2Hz"
+};
+
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+/**
+ * ds1685_rtc_print_regs - helper function to print register values.
+ * @hex: hex byte to convert into binary bits.
+ * @dest: destination char array.
+ *
+ * This is basically a hex->binary function, just with extra spacing between
+ * the digits. It only works on 1-byte values (8 bits).
+ */
+static char*
+ds1685_rtc_print_regs(u8 hex, char *dest)
+{
+ u32 i, j;
+ char *tmp = dest;
+
+ for (i = 0; i < NUM_BITS; i++) {
+ *tmp++ = ((hex & 0x80) != 0 ? '1' : '0');
+ for (j = 0; j < NUM_SPACES; j++)
+ *tmp++ = ' ';
+ hex <<= 1;
+ }
+ *tmp++ = '\0';
+
+ return dest;
+}
+#endif
+
+/**
+ * ds1685_rtc_proc - procfs access function.
+ * @dev: pointer to device structure.
+ * @seq: pointer to seq_file structure.
+ */
+static int
+ds1685_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrla, ctrlb, ctrlc, ctrld, ctrl4a, ctrl4b, ssn[8];
+ char *model = '\0';
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+ char bits[NUM_REGS][(NUM_BITS * NUM_SPACES) + NUM_BITS + 1];
+#endif
+
+ /* Read all the relevant data from the control registers. */
+ ds1685_rtc_switch_to_bank1(rtc);
+ ds1685_rtc_get_ssn(rtc, ssn);
+ ctrla = rtc->read(rtc, RTC_CTRL_A);
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ ctrlc = rtc->read(rtc, RTC_CTRL_C);
+ ctrld = rtc->read(rtc, RTC_CTRL_D);
+ ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+ ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ /* Determine the RTC model. */
+ switch (ssn[0]) {
+ case RTC_MODEL_DS1685:
+ model = "DS1685/DS1687\0";
+ break;
+ case RTC_MODEL_DS1689:
+ model = "DS1689/DS1693\0";
+ break;
+ case RTC_MODEL_DS17285:
+ model = "DS17285/DS17287\0";
+ break;
+ case RTC_MODEL_DS17485:
+ model = "DS17485/DS17487\0";
+ break;
+ case RTC_MODEL_DS17885:
+ model = "DS17885/DS17887\0";
+ break;
+ default:
+ model = "Unknown\0";
+ break;
+ }
+
+ /* Print out the information. */
+ seq_printf(seq,
+ "Model\t\t: %s\n"
+ "Oscillator\t: %s\n"
+ "12/24hr\t\t: %s\n"
+ "DST\t\t: %s\n"
+ "Data mode\t: %s\n"
+ "Battery\t\t: %s\n"
+ "Aux batt\t: %s\n"
+ "Update IRQ\t: %s\n"
+ "Periodic IRQ\t: %s\n"
+ "Periodic Rate\t: %s\n"
+ "SQW Freq\t: %s\n"
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+ "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n"
+ "Register Status\t:\n"
+ " Ctrl A\t: UIP DV2 DV1 DV0 RS3 RS2 RS1 RS0\n"
+ "\t\t: %s\n"
+ " Ctrl B\t: SET PIE AIE UIE SQWE DM 2412 DSE\n"
+ "\t\t: %s\n"
+ " Ctrl C\t: IRQF PF AF UF --- --- --- ---\n"
+ "\t\t: %s\n"
+ " Ctrl D\t: VRT --- --- --- --- --- --- ---\n"
+ "\t\t: %s\n"
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+ " Ctrl 4A\t: VRT2 INCR BME --- PAB RF WF KF\n"
+#else
+ " Ctrl 4A\t: VRT2 INCR --- --- PAB RF WF KF\n"
+#endif
+ "\t\t: %s\n"
+ " Ctrl 4B\t: ABE E32k CS RCE PRS RIE WIE KSE\n"
+ "\t\t: %s\n",
+#else
+ "Serial #\t: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+#endif
+ model,
+ ((ctrla & RTC_CTRL_A_DV1) ? "enabled" : "disabled"),
+ ((ctrlb & RTC_CTRL_B_2412) ? "24-hour" : "12-hour"),
+ ((ctrlb & RTC_CTRL_B_DSE) ? "enabled" : "disabled"),
+ ((ctrlb & RTC_CTRL_B_DM) ? "binary" : "BCD"),
+ ((ctrld & RTC_CTRL_D_VRT) ? "ok" : "exhausted or n/a"),
+ ((ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "exhausted or n/a"),
+ ((ctrlb & RTC_CTRL_B_UIE) ? "yes" : "no"),
+ ((ctrlb & RTC_CTRL_B_PIE) ? "yes" : "no"),
+ (!(ctrl4b & RTC_CTRL_4B_E32K) ?
+ ds1685_rtc_pirq_rate[(ctrla & RTC_CTRL_A_RS_MASK)] : "none"),
+ (!((ctrl4b & RTC_CTRL_4B_E32K)) ?
+ ds1685_rtc_sqw_freq[(ctrla & RTC_CTRL_A_RS_MASK)] : "32768Hz"),
+#ifdef CONFIG_RTC_DS1685_PROC_REGS
+ ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7],
+ ds1685_rtc_print_regs(ctrla, bits[0]),
+ ds1685_rtc_print_regs(ctrlb, bits[1]),
+ ds1685_rtc_print_regs(ctrlc, bits[2]),
+ ds1685_rtc_print_regs(ctrld, bits[3]),
+ ds1685_rtc_print_regs(ctrl4a, bits[4]),
+ ds1685_rtc_print_regs(ctrl4b, bits[5]));
+#else
+ ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5], ssn[6], ssn[7]);
+#endif
+ return 0;
+}
+#else
+#define ds1685_rtc_proc NULL
+#endif /* CONFIG_PROC_FS */
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* RTC Class operations */
+
+static const struct rtc_class_ops
+ds1685_rtc_ops = {
+ .proc = ds1685_rtc_proc,
+ .read_time = ds1685_rtc_read_time,
+ .set_time = ds1685_rtc_set_time,
+ .read_alarm = ds1685_rtc_read_alarm,
+ .set_alarm = ds1685_rtc_set_alarm,
+ .alarm_irq_enable = ds1685_rtc_alarm_irq_enable,
+};
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* SysFS interface */
+
+#ifdef CONFIG_SYSFS
+/**
+ * ds1685_rtc_sysfs_nvram_read - reads rtc nvram via sysfs.
+ * @file: pointer to file structure.
+ * @kobj: pointer to kobject structure.
+ * @bin_attr: pointer to bin_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ * @pos: current file position pointer.
+ * @size: size of the data to read.
+ */
+static ssize_t
+ds1685_rtc_sysfs_nvram_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ ssize_t count;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ /* Read NVRAM in time and bank0 registers. */
+ for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ_BANK0;
+ count++, size--) {
+ if (count < NVRAM_SZ_TIME)
+ *buf++ = rtc->read(rtc, (NVRAM_TIME_BASE + pos++));
+ else
+ *buf++ = rtc->read(rtc, (NVRAM_BANK0_BASE + pos++));
+ }
+
+#ifndef CONFIG_RTC_DRV_DS1689
+ if (size > 0) {
+ ds1685_rtc_switch_to_bank1(rtc);
+
+#ifndef CONFIG_RTC_DRV_DS1685
+ /* Enable burst-mode on DS17x85/DS17x87 */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (rtc->read(rtc, RTC_EXT_CTRL_4A) |
+ RTC_CTRL_4A_BME));
+
+ /* We need one write to RTC_BANK1_RAM_ADDR_LSB to start
+ * reading with burst-mode */
+ rtc->write(rtc, RTC_BANK1_RAM_ADDR_LSB,
+ (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+
+ /* Read NVRAM in bank1 registers. */
+ for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ;
+ count++, size--) {
+#ifdef CONFIG_RTC_DRV_DS1685
+ /* DS1685/DS1687 has to write to RTC_BANK1_RAM_ADDR
+ * before each read. */
+ rtc->write(rtc, RTC_BANK1_RAM_ADDR,
+ (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+ *buf++ = rtc->read(rtc, RTC_BANK1_RAM_DATA_PORT);
+ pos++;
+ }
+
+#ifndef CONFIG_RTC_DRV_DS1685
+ /* Disable burst-mode on DS17x85/DS17x87 */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (rtc->read(rtc, RTC_EXT_CTRL_4A) &
+ ~(RTC_CTRL_4A_BME)));
+#endif
+ ds1685_rtc_switch_to_bank0(rtc);
+ }
+#endif /* !CONFIG_RTC_DRV_DS1689 */
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ /*
+ * XXX: Bug? this appears to cause the function to get executed
+ * several times in succession. But it's the only way to actually get
+ * data written out to a file.
+ */
+ return count;
+}
+
+/**
+ * ds1685_rtc_sysfs_nvram_write - writes rtc nvram via sysfs.
+ * @file: pointer to file structure.
+ * @kobj: pointer to kobject structure.
+ * @bin_attr: pointer to bin_attribute structure.
+ * @buf: pointer to char array to hold the input.
+ * @pos: current file position pointer.
+ * @size: size of the data to write.
+ */
+static ssize_t
+ds1685_rtc_sysfs_nvram_write(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr, char *buf,
+ loff_t pos, size_t size)
+{
+ struct platform_device *pdev =
+ to_platform_device(container_of(kobj, struct device, kobj));
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ ssize_t count;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&rtc->lock, flags);
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ /* Write NVRAM in time and bank0 registers. */
+ for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ_BANK0;
+ count++, size--)
+ if (count < NVRAM_SZ_TIME)
+ rtc->write(rtc, (NVRAM_TIME_BASE + pos++),
+ *buf++);
+ else
+ rtc->write(rtc, (NVRAM_BANK0_BASE), *buf++);
+
+#ifndef CONFIG_RTC_DRV_DS1689
+ if (size > 0) {
+ ds1685_rtc_switch_to_bank1(rtc);
+
+#ifndef CONFIG_RTC_DRV_DS1685
+ /* Enable burst-mode on DS17x85/DS17x87 */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (rtc->read(rtc, RTC_EXT_CTRL_4A) |
+ RTC_CTRL_4A_BME));
+
+ /* We need one write to RTC_BANK1_RAM_ADDR_LSB to start
+ * writing with burst-mode */
+ rtc->write(rtc, RTC_BANK1_RAM_ADDR_LSB,
+ (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+
+ /* Write NVRAM in bank1 registers. */
+ for (count = 0; size > 0 && pos < NVRAM_TOTAL_SZ;
+ count++, size--) {
+#ifdef CONFIG_RTC_DRV_DS1685
+ /* DS1685/DS1687 has to write to RTC_BANK1_RAM_ADDR
+ * before each read. */
+ rtc->write(rtc, RTC_BANK1_RAM_ADDR,
+ (pos - NVRAM_TOTAL_SZ_BANK0));
+#endif
+ rtc->write(rtc, RTC_BANK1_RAM_DATA_PORT, *buf++);
+ pos++;
+ }
+
+#ifndef CONFIG_RTC_DRV_DS1685
+ /* Disable burst-mode on DS17x85/DS17x87 */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (rtc->read(rtc, RTC_EXT_CTRL_4A) &
+ ~(RTC_CTRL_4A_BME)));
+#endif
+ ds1685_rtc_switch_to_bank0(rtc);
+ }
+#endif /* !CONFIG_RTC_DRV_DS1689 */
+ spin_unlock_irqrestore(&rtc->lock, flags);
+
+ return count;
+}
+
+/**
+ * struct ds1685_rtc_sysfs_nvram_attr - sysfs attributes for rtc nvram.
+ * @attr: nvram attributes.
+ * @read: nvram read function.
+ * @write: nvram write function.
+ * @size: nvram total size (bank0 + extended).
+ */
+static struct bin_attribute
+ds1685_rtc_sysfs_nvram_attr = {
+ .attr = {
+ .name = "nvram",
+ .mode = S_IRUGO | S_IWUSR,
+ },
+ .read = ds1685_rtc_sysfs_nvram_read,
+ .write = ds1685_rtc_sysfs_nvram_write,
+ .size = NVRAM_TOTAL_SZ
+};
+
+/**
+ * ds1685_rtc_sysfs_battery_show - sysfs file for main battery status.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_battery_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrld;
+
+ ctrld = rtc->read(rtc, RTC_CTRL_D);
+
+ return snprintf(buf, 13, "%s\n",
+ (ctrld & RTC_CTRL_D_VRT) ? "ok" : "not ok or N/A");
+}
+static DEVICE_ATTR(battery, S_IRUGO, ds1685_rtc_sysfs_battery_show, NULL);
+
+/**
+ * ds1685_rtc_sysfs_auxbatt_show - sysfs file for aux battery status.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_auxbatt_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ctrl4a;
+
+ ds1685_rtc_switch_to_bank1(rtc);
+ ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ return snprintf(buf, 13, "%s\n",
+ (ctrl4a & RTC_CTRL_4A_VRT2) ? "ok" : "not ok or N/A");
+}
+static DEVICE_ATTR(auxbatt, S_IRUGO, ds1685_rtc_sysfs_auxbatt_show, NULL);
+
+/**
+ * ds1685_rtc_sysfs_serial_show - sysfs file for silicon serial number.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_serial_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+ u8 ssn[8];
+
+ ds1685_rtc_switch_to_bank1(rtc);
+ ds1685_rtc_get_ssn(rtc, ssn);
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ return snprintf(buf, 24, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
+ ssn[0], ssn[1], ssn[2], ssn[3], ssn[4], ssn[5],
+ ssn[6], ssn[7]);
+
+ return 0;
+}
+static DEVICE_ATTR(serial, S_IRUGO, ds1685_rtc_sysfs_serial_show, NULL);
+
+/**
+ * struct ds1685_rtc_sysfs_misc_attrs - list for misc RTC features.
+ */
+static struct attribute*
+ds1685_rtc_sysfs_misc_attrs[] = {
+ &dev_attr_battery.attr,
+ &dev_attr_auxbatt.attr,
+ &dev_attr_serial.attr,
+ NULL,
+};
+
+/**
+ * struct ds1685_rtc_sysfs_misc_grp - attr group for misc RTC features.
+ */
+static const struct attribute_group
+ds1685_rtc_sysfs_misc_grp = {
+ .name = "misc",
+ .attrs = ds1685_rtc_sysfs_misc_attrs,
+};
+
+#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
+/**
+ * struct ds1685_rtc_ctrl_regs.
+ * @name: char pointer for the bit name.
+ * @reg: control register the bit is in.
+ * @bit: the bit's offset in the register.
+ */
+struct ds1685_rtc_ctrl_regs {
+ const char *name;
+ const u8 reg;
+ const u8 bit;
+};
+
+/*
+ * Ctrl register bit lookup table.
+ */
+static const struct ds1685_rtc_ctrl_regs
+ds1685_ctrl_regs_table[] = {
+ { "uip", RTC_CTRL_A, RTC_CTRL_A_UIP },
+ { "dv2", RTC_CTRL_A, RTC_CTRL_A_DV2 },
+ { "dv1", RTC_CTRL_A, RTC_CTRL_A_DV1 },
+ { "dv0", RTC_CTRL_A, RTC_CTRL_A_DV0 },
+ { "rs3", RTC_CTRL_A, RTC_CTRL_A_RS3 },
+ { "rs2", RTC_CTRL_A, RTC_CTRL_A_RS2 },
+ { "rs1", RTC_CTRL_A, RTC_CTRL_A_RS1 },
+ { "rs0", RTC_CTRL_A, RTC_CTRL_A_RS0 },
+ { "set", RTC_CTRL_B, RTC_CTRL_B_SET },
+ { "pie", RTC_CTRL_B, RTC_CTRL_B_PIE },
+ { "aie", RTC_CTRL_B, RTC_CTRL_B_AIE },
+ { "uie", RTC_CTRL_B, RTC_CTRL_B_UIE },
+ { "sqwe", RTC_CTRL_B, RTC_CTRL_B_SQWE },
+ { "dm", RTC_CTRL_B, RTC_CTRL_B_DM },
+ { "2412", RTC_CTRL_B, RTC_CTRL_B_2412 },
+ { "dse", RTC_CTRL_B, RTC_CTRL_B_DSE },
+ { "irqf", RTC_CTRL_C, RTC_CTRL_C_IRQF },
+ { "pf", RTC_CTRL_C, RTC_CTRL_C_PF },
+ { "af", RTC_CTRL_C, RTC_CTRL_C_AF },
+ { "uf", RTC_CTRL_C, RTC_CTRL_C_UF },
+ { "vrt", RTC_CTRL_D, RTC_CTRL_D_VRT },
+ { "vrt2", RTC_EXT_CTRL_4A, RTC_CTRL_4A_VRT2 },
+ { "incr", RTC_EXT_CTRL_4A, RTC_CTRL_4A_INCR },
+ { "pab", RTC_EXT_CTRL_4A, RTC_CTRL_4A_PAB },
+ { "rf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_RF },
+ { "wf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_WF },
+ { "kf", RTC_EXT_CTRL_4A, RTC_CTRL_4A_KF },
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+ { "bme", RTC_EXT_CTRL_4A, RTC_CTRL_4A_BME },
+#endif
+ { "abe", RTC_EXT_CTRL_4B, RTC_CTRL_4B_ABE },
+ { "e32k", RTC_EXT_CTRL_4B, RTC_CTRL_4B_E32K },
+ { "cs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_CS },
+ { "rce", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RCE },
+ { "prs", RTC_EXT_CTRL_4B, RTC_CTRL_4B_PRS },
+ { "rie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_RIE },
+ { "wie", RTC_EXT_CTRL_4B, RTC_CTRL_4B_WIE },
+ { "kse", RTC_EXT_CTRL_4B, RTC_CTRL_4B_KSE },
+ { NULL, 0, 0 },
+};
+
+/**
+ * ds1685_rtc_sysfs_ctrl_regs_lookup - ctrl register bit lookup function.
+ * @name: ctrl register bit to look up in ds1685_ctrl_regs_table.
+ */
+static const struct ds1685_rtc_ctrl_regs*
+ds1685_rtc_sysfs_ctrl_regs_lookup(const char *name)
+{
+ const struct ds1685_rtc_ctrl_regs *p = ds1685_ctrl_regs_table;
+
+ for (; p->name != NULL; ++p)
+ if (strcmp(p->name, name) == 0)
+ return p;
+
+ return NULL;
+}
+
+/**
+ * ds1685_rtc_sysfs_ctrl_regs_show - reads a ctrl register bit via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_ctrl_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 tmp;
+ struct ds1685_priv *rtc = dev_get_drvdata(dev);
+ const struct ds1685_rtc_ctrl_regs *reg_info =
+ ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
+
+ /* Make sure we actually matched something. */
+ if (!reg_info)
+ return -EINVAL;
+
+ /* No spinlock during a read -- mutex is already held. */
+ ds1685_rtc_switch_to_bank1(rtc);
+ tmp = rtc->read(rtc, reg_info->reg) & reg_info->bit;
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ return snprintf(buf, 2, "%d\n", (tmp ? 1 : 0));
+}
+
+/**
+ * ds1685_rtc_sysfs_ctrl_regs_store - writes a ctrl register bit via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ * @count: number of bytes written.
+ */
+static ssize_t
+ds1685_rtc_sysfs_ctrl_regs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ds1685_priv *rtc = dev_get_drvdata(dev);
+ u8 reg = 0, bit = 0, tmp;
+ unsigned long flags = 0;
+ long int val = 0;
+ const struct ds1685_rtc_ctrl_regs *reg_info =
+ ds1685_rtc_sysfs_ctrl_regs_lookup(attr->attr.name);
+
+ /* We only accept numbers. */
+ if (kstrtol(buf, 10, &val) < 0)
+ return -EINVAL;
+
+ /* bits are binary, 0 or 1 only. */
+ if ((val != 0) && (val != 1))
+ return -ERANGE;
+
+ /* Make sure we actually matched something. */
+ if (!reg_info)
+ return -EINVAL;
+
+ reg = reg_info->reg;
+ bit = reg_info->bit;
+
+ /* Safe to spinlock during a write. */
+ ds1685_rtc_begin_ctrl_access(rtc, flags);
+ tmp = rtc->read(rtc, reg);
+ rtc->write(rtc, reg, (val ? (tmp | bit) : (tmp & ~(bit))));
+ ds1685_rtc_end_ctrl_access(rtc, flags);
+
+ return count;
+}
+
+/**
+ * DS1685_RTC_SYSFS_CTRL_REG_RO - device_attribute for read-only register bit.
+ * @bit: bit to read.
+ */
+#define DS1685_RTC_SYSFS_CTRL_REG_RO(bit) \
+ static DEVICE_ATTR(bit, S_IRUGO, \
+ ds1685_rtc_sysfs_ctrl_regs_show, NULL)
+
+/**
+ * DS1685_RTC_SYSFS_CTRL_REG_RW - device_attribute for read-write register bit.
+ * @bit: bit to read or write.
+ */
+#define DS1685_RTC_SYSFS_CTRL_REG_RW(bit) \
+ static DEVICE_ATTR(bit, S_IRUGO | S_IWUSR, \
+ ds1685_rtc_sysfs_ctrl_regs_show, \
+ ds1685_rtc_sysfs_ctrl_regs_store)
+
+/*
+ * Control Register A bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(uip);
+DS1685_RTC_SYSFS_CTRL_REG_RW(dv2);
+DS1685_RTC_SYSFS_CTRL_REG_RW(dv1);
+DS1685_RTC_SYSFS_CTRL_REG_RO(dv0);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs3);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs2);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs1);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rs0);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrla_attrs[] = {
+ &dev_attr_uip.attr,
+ &dev_attr_dv2.attr,
+ &dev_attr_dv1.attr,
+ &dev_attr_dv0.attr,
+ &dev_attr_rs3.attr,
+ &dev_attr_rs2.attr,
+ &dev_attr_rs1.attr,
+ &dev_attr_rs0.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrla_grp = {
+ .name = "ctrla",
+ .attrs = ds1685_rtc_sysfs_ctrla_attrs,
+};
+
+
+/*
+ * Control Register B bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(set);
+DS1685_RTC_SYSFS_CTRL_REG_RW(pie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(aie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(uie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(sqwe);
+DS1685_RTC_SYSFS_CTRL_REG_RO(dm);
+DS1685_RTC_SYSFS_CTRL_REG_RO(2412);
+DS1685_RTC_SYSFS_CTRL_REG_RO(dse);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrlb_attrs[] = {
+ &dev_attr_set.attr,
+ &dev_attr_pie.attr,
+ &dev_attr_aie.attr,
+ &dev_attr_uie.attr,
+ &dev_attr_sqwe.attr,
+ &dev_attr_dm.attr,
+ &dev_attr_2412.attr,
+ &dev_attr_dse.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrlb_grp = {
+ .name = "ctrlb",
+ .attrs = ds1685_rtc_sysfs_ctrlb_attrs,
+};
+
+/*
+ * Control Register C bits.
+ *
+ * Reading Control C clears these bits! Reading them individually can
+ * possibly cause an interrupt to be missed. Use the /proc interface
+ * to see all the bits in this register simultaneously.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(irqf);
+DS1685_RTC_SYSFS_CTRL_REG_RO(pf);
+DS1685_RTC_SYSFS_CTRL_REG_RO(af);
+DS1685_RTC_SYSFS_CTRL_REG_RO(uf);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrlc_attrs[] = {
+ &dev_attr_irqf.attr,
+ &dev_attr_pf.attr,
+ &dev_attr_af.attr,
+ &dev_attr_uf.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrlc_grp = {
+ .name = "ctrlc",
+ .attrs = ds1685_rtc_sysfs_ctrlc_attrs,
+};
+
+/*
+ * Control Register D bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(vrt);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrld_attrs[] = {
+ &dev_attr_vrt.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrld_grp = {
+ .name = "ctrld",
+ .attrs = ds1685_rtc_sysfs_ctrld_attrs,
+};
+
+/*
+ * Control Register 4A bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RO(vrt2);
+DS1685_RTC_SYSFS_CTRL_REG_RO(incr);
+DS1685_RTC_SYSFS_CTRL_REG_RW(pab);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rf);
+DS1685_RTC_SYSFS_CTRL_REG_RW(wf);
+DS1685_RTC_SYSFS_CTRL_REG_RW(kf);
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+DS1685_RTC_SYSFS_CTRL_REG_RO(bme);
+#endif
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrl4a_attrs[] = {
+ &dev_attr_vrt2.attr,
+ &dev_attr_incr.attr,
+ &dev_attr_pab.attr,
+ &dev_attr_rf.attr,
+ &dev_attr_wf.attr,
+ &dev_attr_kf.attr,
+#if !defined(CONFIG_RTC_DRV_DS1685) && !defined(CONFIG_RTC_DRV_DS1689)
+ &dev_attr_bme.attr,
+#endif
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrl4a_grp = {
+ .name = "ctrl4a",
+ .attrs = ds1685_rtc_sysfs_ctrl4a_attrs,
+};
+
+/*
+ * Control Register 4B bits.
+ */
+DS1685_RTC_SYSFS_CTRL_REG_RW(abe);
+DS1685_RTC_SYSFS_CTRL_REG_RW(e32k);
+DS1685_RTC_SYSFS_CTRL_REG_RO(cs);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rce);
+DS1685_RTC_SYSFS_CTRL_REG_RW(prs);
+DS1685_RTC_SYSFS_CTRL_REG_RW(rie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(wie);
+DS1685_RTC_SYSFS_CTRL_REG_RW(kse);
+
+static struct attribute*
+ds1685_rtc_sysfs_ctrl4b_attrs[] = {
+ &dev_attr_abe.attr,
+ &dev_attr_e32k.attr,
+ &dev_attr_cs.attr,
+ &dev_attr_rce.attr,
+ &dev_attr_prs.attr,
+ &dev_attr_rie.attr,
+ &dev_attr_wie.attr,
+ &dev_attr_kse.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_ctrl4b_grp = {
+ .name = "ctrl4b",
+ .attrs = ds1685_rtc_sysfs_ctrl4b_attrs,
+};
+
+
+/**
+ * struct ds1685_rtc_ctrl_regs.
+ * @name: char pointer for the bit name.
+ * @reg: control register the bit is in.
+ * @bit: the bit's offset in the register.
+ */
+struct ds1685_rtc_time_regs {
+ const char *name;
+ const u8 reg;
+ const u8 mask;
+ const u8 min;
+ const u8 max;
+};
+
+/*
+ * Time/Date register lookup tables.
+ */
+static const struct ds1685_rtc_time_regs
+ds1685_time_regs_bcd_table[] = {
+ { "seconds", RTC_SECS, RTC_SECS_BCD_MASK, 0, 59 },
+ { "minutes", RTC_MINS, RTC_MINS_BCD_MASK, 0, 59 },
+ { "hours", RTC_HRS, RTC_HRS_24_BCD_MASK, 0, 23 },
+ { "wday", RTC_WDAY, RTC_WDAY_MASK, 1, 7 },
+ { "mday", RTC_MDAY, RTC_MDAY_BCD_MASK, 1, 31 },
+ { "month", RTC_MONTH, RTC_MONTH_BCD_MASK, 1, 12 },
+ { "year", RTC_YEAR, RTC_YEAR_BCD_MASK, 0, 99 },
+ { "century", RTC_CENTURY, RTC_CENTURY_MASK, 0, 99 },
+ { "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BCD_MASK, 0, 59 },
+ { "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BCD_MASK, 0, 59 },
+ { "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BCD_MASK, 0, 23 },
+ { "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 1, 31 },
+ { NULL, 0, 0, 0, 0 },
+};
+
+static const struct ds1685_rtc_time_regs
+ds1685_time_regs_bin_table[] = {
+ { "seconds", RTC_SECS, RTC_SECS_BIN_MASK, 0x00, 0x3b },
+ { "minutes", RTC_MINS, RTC_MINS_BIN_MASK, 0x00, 0x3b },
+ { "hours", RTC_HRS, RTC_HRS_24_BIN_MASK, 0x00, 0x17 },
+ { "wday", RTC_WDAY, RTC_WDAY_MASK, 0x01, 0x07 },
+ { "mday", RTC_MDAY, RTC_MDAY_BIN_MASK, 0x01, 0x1f },
+ { "month", RTC_MONTH, RTC_MONTH_BIN_MASK, 0x01, 0x0c },
+ { "year", RTC_YEAR, RTC_YEAR_BIN_MASK, 0x00, 0x63 },
+ { "century", RTC_CENTURY, RTC_CENTURY_MASK, 0x00, 0x63 },
+ { "alarm_seconds", RTC_SECS_ALARM, RTC_SECS_BIN_MASK, 0x00, 0x3b },
+ { "alarm_minutes", RTC_MINS_ALARM, RTC_MINS_BIN_MASK, 0x00, 0x3b },
+ { "alarm_hours", RTC_HRS_ALARM, RTC_HRS_24_BIN_MASK, 0x00, 0x17 },
+ { "alarm_mday", RTC_MDAY_ALARM, RTC_MDAY_ALARM_MASK, 0x01, 0x1f },
+ { NULL, 0, 0, 0x00, 0x00 },
+};
+
+/**
+ * ds1685_rtc_sysfs_time_regs_bcd_lookup - time/date reg bit lookup function.
+ * @name: register bit to look up in ds1685_time_regs_bcd_table.
+ */
+static const struct ds1685_rtc_time_regs*
+ds1685_rtc_sysfs_time_regs_lookup(const char *name, bool bcd_mode)
+{
+ const struct ds1685_rtc_time_regs *p;
+
+ if (bcd_mode)
+ p = ds1685_time_regs_bcd_table;
+ else
+ p = ds1685_time_regs_bin_table;
+
+ for (; p->name != NULL; ++p)
+ if (strcmp(p->name, name) == 0)
+ return p;
+
+ return NULL;
+}
+
+/**
+ * ds1685_rtc_sysfs_time_regs_show - reads a time/date register via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ */
+static ssize_t
+ds1685_rtc_sysfs_time_regs_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ u8 tmp;
+ struct ds1685_priv *rtc = dev_get_drvdata(dev);
+ const struct ds1685_rtc_time_regs *bcd_reg_info =
+ ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true);
+ const struct ds1685_rtc_time_regs *bin_reg_info =
+ ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
+
+ /* Make sure we actually matched something. */
+ if (!bcd_reg_info || !bin_reg_info)
+ return -EINVAL;
+
+ /* bcd_reg_info->reg == bin_reg_info->reg. */
+ ds1685_rtc_begin_data_access(rtc);
+ tmp = rtc->read(rtc, bcd_reg_info->reg);
+ ds1685_rtc_end_data_access(rtc);
+
+ tmp = ds1685_rtc_bcd2bin(rtc, tmp, bcd_reg_info->mask,
+ bin_reg_info->mask);
+
+ return snprintf(buf, 4, "%d\n", tmp);
+}
+
+/**
+ * ds1685_rtc_sysfs_time_regs_store - writes a time/date register via sysfs.
+ * @dev: pointer to device structure.
+ * @attr: pointer to device_attribute structure.
+ * @buf: pointer to char array to hold the output.
+ * @count: number of bytes written.
+ */
+static ssize_t
+ds1685_rtc_sysfs_time_regs_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ long int val = 0;
+ struct ds1685_priv *rtc = dev_get_drvdata(dev);
+ const struct ds1685_rtc_time_regs *bcd_reg_info =
+ ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, true);
+ const struct ds1685_rtc_time_regs *bin_reg_info =
+ ds1685_rtc_sysfs_time_regs_lookup(attr->attr.name, false);
+
+ /* We only accept numbers. */
+ if (kstrtol(buf, 10, &val) < 0)
+ return -EINVAL;
+
+ /* Make sure we actually matched something. */
+ if (!bcd_reg_info || !bin_reg_info)
+ return -EINVAL;
+
+ /* Check for a valid range. */
+ if (rtc->bcd_mode) {
+ if ((val < bcd_reg_info->min) || (val > bcd_reg_info->max))
+ return -ERANGE;
+ } else {
+ if ((val < bin_reg_info->min) || (val > bin_reg_info->max))
+ return -ERANGE;
+ }
+
+ val = ds1685_rtc_bin2bcd(rtc, val, bin_reg_info->mask,
+ bcd_reg_info->mask);
+
+ /* bcd_reg_info->reg == bin_reg_info->reg. */
+ ds1685_rtc_begin_data_access(rtc);
+ rtc->write(rtc, bcd_reg_info->reg, val);
+ ds1685_rtc_end_data_access(rtc);
+
+ return count;
+}
+
+/**
+ * DS1685_RTC_SYSFS_REG_RW - device_attribute for a read-write time register.
+ * @reg: time/date register to read or write.
+ */
+#define DS1685_RTC_SYSFS_TIME_REG_RW(reg) \
+ static DEVICE_ATTR(reg, S_IRUGO | S_IWUSR, \
+ ds1685_rtc_sysfs_time_regs_show, \
+ ds1685_rtc_sysfs_time_regs_store)
+
+/*
+ * Time/Date Register bits.
+ */
+DS1685_RTC_SYSFS_TIME_REG_RW(seconds);
+DS1685_RTC_SYSFS_TIME_REG_RW(minutes);
+DS1685_RTC_SYSFS_TIME_REG_RW(hours);
+DS1685_RTC_SYSFS_TIME_REG_RW(wday);
+DS1685_RTC_SYSFS_TIME_REG_RW(mday);
+DS1685_RTC_SYSFS_TIME_REG_RW(month);
+DS1685_RTC_SYSFS_TIME_REG_RW(year);
+DS1685_RTC_SYSFS_TIME_REG_RW(century);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_seconds);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_minutes);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_hours);
+DS1685_RTC_SYSFS_TIME_REG_RW(alarm_mday);
+
+static struct attribute*
+ds1685_rtc_sysfs_time_attrs[] = {
+ &dev_attr_seconds.attr,
+ &dev_attr_minutes.attr,
+ &dev_attr_hours.attr,
+ &dev_attr_wday.attr,
+ &dev_attr_mday.attr,
+ &dev_attr_month.attr,
+ &dev_attr_year.attr,
+ &dev_attr_century.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_time_grp = {
+ .name = "datetime",
+ .attrs = ds1685_rtc_sysfs_time_attrs,
+};
+
+static struct attribute*
+ds1685_rtc_sysfs_alarm_attrs[] = {
+ &dev_attr_alarm_seconds.attr,
+ &dev_attr_alarm_minutes.attr,
+ &dev_attr_alarm_hours.attr,
+ &dev_attr_alarm_mday.attr,
+ NULL,
+};
+
+static const struct attribute_group
+ds1685_rtc_sysfs_alarm_grp = {
+ .name = "alarm",
+ .attrs = ds1685_rtc_sysfs_alarm_attrs,
+};
+#endif /* CONFIG_RTC_DS1685_SYSFS_REGS */
+
+
+/**
+ * ds1685_rtc_sysfs_register - register sysfs files.
+ * @dev: pointer to device structure.
+ */
+static int
+ds1685_rtc_sysfs_register(struct device *dev)
+{
+ int ret = 0;
+
+ sysfs_bin_attr_init(&ds1685_rtc_sysfs_nvram_attr);
+ ret = sysfs_create_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
+ if (ret)
+ return ret;
+
+#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp);
+ if (ret)
+ return ret;
+
+ ret = sysfs_create_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp);
+ if (ret)
+ return ret;
+#endif
+ return 0;
+}
+
+/**
+ * ds1685_rtc_sysfs_unregister - unregister sysfs files.
+ * @dev: pointer to device structure.
+ */
+static int
+ds1685_rtc_sysfs_unregister(struct device *dev)
+{
+ sysfs_remove_bin_file(&dev->kobj, &ds1685_rtc_sysfs_nvram_attr);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_misc_grp);
+
+#ifdef CONFIG_RTC_DS1685_SYSFS_REGS
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrla_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlb_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrlc_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrld_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4a_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_ctrl4b_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_time_grp);
+ sysfs_remove_group(&dev->kobj, &ds1685_rtc_sysfs_alarm_grp);
+#endif
+
+ return 0;
+}
+#endif /* CONFIG_SYSFS */
+
+
+
+/* ----------------------------------------------------------------------- */
+/* Driver Probe/Removal */
+
+/**
+ * ds1685_rtc_probe - initializes rtc driver.
+ * @pdev: pointer to platform_device structure.
+ */
+static int
+ds1685_rtc_probe(struct platform_device *pdev)
+{
+ struct rtc_device *rtc_dev;
+ struct resource *res;
+ struct ds1685_priv *rtc;
+ struct ds1685_rtc_platform_data *pdata;
+ u8 ctrla, ctrlb, hours;
+ unsigned char am_pm;
+ int ret = 0;
+
+ /* Get the platform data. */
+ pdata = (struct ds1685_rtc_platform_data *) pdev->dev.platform_data;
+ if (!pdata)
+ return -ENODEV;
+
+ /* Allocate memory for the rtc device. */
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
+
+ /*
+ * Allocate/setup any IORESOURCE_MEM resources, if required. Not all
+ * platforms put the RTC in an easy-access place. Like the SGI Octane,
+ * which attaches the RTC to a "ByteBus", hooked to a SuperIO chip
+ * that sits behind the IOC3 PCI metadevice.
+ */
+ if (pdata->alloc_io_resources) {
+ /* Get the platform resources. */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res)
+ return -ENXIO;
+ rtc->size = resource_size(res);
+
+ /* Request a memory region. */
+ /* XXX: mmio-only for now. */
+ if (!devm_request_mem_region(&pdev->dev, res->start, rtc->size,
+ pdev->name))
+ return -EBUSY;
+
+ /*
+ * Set the base address for the rtc, and ioremap its
+ * registers.
+ */
+ rtc->baseaddr = res->start;
+ rtc->regs = devm_ioremap(&pdev->dev, res->start, rtc->size);
+ if (!rtc->regs)
+ return -ENOMEM;
+ }
+ rtc->alloc_io_resources = pdata->alloc_io_resources;
+
+ /* Get the register step size. */
+ if (pdata->regstep > 0)
+ rtc->regstep = pdata->regstep;
+ else
+ rtc->regstep = 1;
+
+ /* Platform read function, else default if mmio setup */
+ if (pdata->plat_read)
+ rtc->read = pdata->plat_read;
+ else
+ if (pdata->alloc_io_resources)
+ rtc->read = ds1685_read;
+ else
+ return -ENXIO;
+
+ /* Platform write function, else default if mmio setup */
+ if (pdata->plat_write)
+ rtc->write = pdata->plat_write;
+ else
+ if (pdata->alloc_io_resources)
+ rtc->write = ds1685_write;
+ else
+ return -ENXIO;
+
+ /* Platform pre-shutdown function, if defined. */
+ if (pdata->plat_prepare_poweroff)
+ rtc->prepare_poweroff = pdata->plat_prepare_poweroff;
+
+ /* Platform wake_alarm function, if defined. */
+ if (pdata->plat_wake_alarm)
+ rtc->wake_alarm = pdata->plat_wake_alarm;
+
+ /* Platform post_ram_clear function, if defined. */
+ if (pdata->plat_post_ram_clear)
+ rtc->post_ram_clear = pdata->plat_post_ram_clear;
+
+ /* Init the spinlock, workqueue, & set the driver data. */
+ spin_lock_init(&rtc->lock);
+ INIT_WORK(&rtc->work, ds1685_rtc_work_queue);
+ platform_set_drvdata(pdev, rtc);
+
+ /* Turn the oscillator on if is not already on (DV1 = 1). */
+ ctrla = rtc->read(rtc, RTC_CTRL_A);
+ if (!(ctrla & RTC_CTRL_A_DV1))
+ ctrla |= RTC_CTRL_A_DV1;
+
+ /* Enable the countdown chain (DV2 = 0) */
+ ctrla &= ~(RTC_CTRL_A_DV2);
+
+ /* Clear RS3-RS0 in Control A. */
+ ctrla &= ~(RTC_CTRL_A_RS_MASK);
+
+ /*
+ * All done with Control A. Switch to Bank 1 for the remainder of
+ * the RTC setup so we have access to the extended functions.
+ */
+ ctrla |= RTC_CTRL_A_DV0;
+ rtc->write(rtc, RTC_CTRL_A, ctrla);
+
+ /* Default to 32768kHz output. */
+ rtc->write(rtc, RTC_EXT_CTRL_4B,
+ (rtc->read(rtc, RTC_EXT_CTRL_4B) | RTC_CTRL_4B_E32K));
+
+ /* Set the SET bit in Control B so we can do some housekeeping. */
+ rtc->write(rtc, RTC_CTRL_B,
+ (rtc->read(rtc, RTC_CTRL_B) | RTC_CTRL_B_SET));
+
+ /* Read Ext Ctrl 4A and check the INCR bit to avoid a lockout. */
+ while (rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_INCR)
+ cpu_relax();
+
+ /*
+ * If the platform supports BCD mode, then set DM=0 in Control B.
+ * Otherwise, set DM=1 for BIN mode.
+ */
+ ctrlb = rtc->read(rtc, RTC_CTRL_B);
+ if (pdata->bcd_mode)
+ ctrlb &= ~(RTC_CTRL_B_DM);
+ else
+ ctrlb |= RTC_CTRL_B_DM;
+ rtc->bcd_mode = pdata->bcd_mode;
+
+ /*
+ * Disable Daylight Savings Time (DSE = 0).
+ * The RTC has hardcoded timezone information that is rendered
+ * obselete. We'll let the OS deal with DST settings instead.
+ */
+ if (ctrlb & RTC_CTRL_B_DSE)
+ ctrlb &= ~(RTC_CTRL_B_DSE);
+
+ /* Force 24-hour mode (2412 = 1). */
+ if (!(ctrlb & RTC_CTRL_B_2412)) {
+ /* Reinitialize the time hours. */
+ hours = rtc->read(rtc, RTC_HRS);
+ am_pm = hours & RTC_HRS_AMPM_MASK;
+ hours = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_12_BCD_MASK,
+ RTC_HRS_12_BIN_MASK);
+ hours = ((hours == 12) ? 0 : ((am_pm) ? hours + 12 : hours));
+
+ /* Enable 24-hour mode. */
+ ctrlb |= RTC_CTRL_B_2412;
+
+ /* Write back to Control B, including DM & DSE bits. */
+ rtc->write(rtc, RTC_CTRL_B, ctrlb);
+
+ /* Write the time hours back. */
+ rtc->write(rtc, RTC_HRS,
+ ds1685_rtc_bin2bcd(rtc, hours,
+ RTC_HRS_24_BIN_MASK,
+ RTC_HRS_24_BCD_MASK));
+
+ /* Reinitialize the alarm hours. */
+ hours = rtc->read(rtc, RTC_HRS_ALARM);
+ am_pm = hours & RTC_HRS_AMPM_MASK;
+ hours = ds1685_rtc_bcd2bin(rtc, hours, RTC_HRS_12_BCD_MASK,
+ RTC_HRS_12_BIN_MASK);
+ hours = ((hours == 12) ? 0 : ((am_pm) ? hours + 12 : hours));
+
+ /* Write the alarm hours back. */
+ rtc->write(rtc, RTC_HRS_ALARM,
+ ds1685_rtc_bin2bcd(rtc, hours,
+ RTC_HRS_24_BIN_MASK,
+ RTC_HRS_24_BCD_MASK));
+ } else {
+ /* 24-hour mode is already set, so write Control B back. */
+ rtc->write(rtc, RTC_CTRL_B, ctrlb);
+ }
+
+ /* Unset the SET bit in Control B so the RTC can update. */
+ rtc->write(rtc, RTC_CTRL_B,
+ (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_SET)));
+
+ /* Check the main battery. */
+ if (!(rtc->read(rtc, RTC_CTRL_D) & RTC_CTRL_D_VRT))
+ dev_warn(&pdev->dev,
+ "Main battery is exhausted! RTC may be invalid!\n");
+
+ /* Check the auxillary battery. It is optional. */
+ if (!(rtc->read(rtc, RTC_EXT_CTRL_4A) & RTC_CTRL_4A_VRT2))
+ dev_warn(&pdev->dev,
+ "Aux battery is exhausted or not available.\n");
+
+ /* Read Ctrl B and clear PIE/AIE/UIE. */
+ rtc->write(rtc, RTC_CTRL_B,
+ (rtc->read(rtc, RTC_CTRL_B) & ~(RTC_CTRL_B_PAU_MASK)));
+
+ /* Reading Ctrl C auto-clears PF/AF/UF. */
+ rtc->read(rtc, RTC_CTRL_C);
+
+ /* Read Ctrl 4B and clear RIE/WIE/KSE. */
+ rtc->write(rtc, RTC_EXT_CTRL_4B,
+ (rtc->read(rtc, RTC_EXT_CTRL_4B) & ~(RTC_CTRL_4B_RWK_MASK)));
+
+ /* Clear RF/WF/KF in Ctrl 4A. */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (rtc->read(rtc, RTC_EXT_CTRL_4A) & ~(RTC_CTRL_4A_RWK_MASK)));
+
+ /*
+ * Re-enable KSE to handle power button events. We do not enable
+ * WIE or RIE by default.
+ */
+ rtc->write(rtc, RTC_EXT_CTRL_4B,
+ (rtc->read(rtc, RTC_EXT_CTRL_4B) | RTC_CTRL_4B_KSE));
+
+ /*
+ * Fetch the IRQ and setup the interrupt handler.
+ *
+ * Not all platforms have the IRQF pin tied to something. If not, the
+ * RTC will still set the *IE / *F flags and raise IRQF in ctrlc, but
+ * there won't be an automatic way of notifying the kernel about it,
+ * unless ctrlc is explicitly polled.
+ */
+ if (!pdata->no_irq) {
+ ret = platform_get_irq(pdev, 0);
+ if (ret > 0) {
+ rtc->irq_num = ret;
+
+ /* Request an IRQ. */
+ ret = devm_request_irq(&pdev->dev, rtc->irq_num,
+ ds1685_rtc_irq_handler,
+ IRQF_SHARED, pdev->name, pdev);
+
+ /* Check to see if something came back. */
+ if (unlikely(ret)) {
+ dev_warn(&pdev->dev,
+ "RTC interrupt not available\n");
+ rtc->irq_num = 0;
+ }
+ } else
+ return ret;
+ }
+ rtc->no_irq = pdata->no_irq;
+
+ /* Setup complete. */
+ ds1685_rtc_switch_to_bank0(rtc);
+
+ /* Register the device as an RTC. */
+ rtc_dev = rtc_device_register(pdev->name, &pdev->dev,
+ &ds1685_rtc_ops, THIS_MODULE);
+
+ /* Success? */
+ if (IS_ERR(rtc_dev))
+ return PTR_ERR(rtc_dev);
+
+ /* Maximum periodic rate is 8192Hz (0.122070ms). */
+ rtc_dev->max_user_freq = RTC_MAX_USER_FREQ;
+
+ /* See if the platform doesn't support UIE. */
+ if (pdata->uie_unsupported)
+ rtc_dev->uie_unsupported = 1;
+ rtc->uie_unsupported = pdata->uie_unsupported;
+
+ rtc->dev = rtc_dev;
+
+#ifdef CONFIG_SYSFS
+ ret = ds1685_rtc_sysfs_register(&pdev->dev);
+ if (ret)
+ rtc_device_unregister(rtc->dev);
+#endif
+
+ /* Done! */
+ return ret;
+}
+
+/**
+ * ds1685_rtc_remove - removes rtc driver.
+ * @pdev: pointer to platform_device structure.
+ */
+static int
+ds1685_rtc_remove(struct platform_device *pdev)
+{
+ struct ds1685_priv *rtc = platform_get_drvdata(pdev);
+
+#ifdef CONFIG_SYSFS
+ ds1685_rtc_sysfs_unregister(&pdev->dev);
+#endif
+
+ rtc_device_unregister(rtc->dev);
+
+ /* Read Ctrl B and clear PIE/AIE/UIE. */
+ rtc->write(rtc, RTC_CTRL_B,
+ (rtc->read(rtc, RTC_CTRL_B) &
+ ~(RTC_CTRL_B_PAU_MASK)));
+
+ /* Reading Ctrl C auto-clears PF/AF/UF. */
+ rtc->read(rtc, RTC_CTRL_C);
+
+ /* Read Ctrl 4B and clear RIE/WIE/KSE. */
+ rtc->write(rtc, RTC_EXT_CTRL_4B,
+ (rtc->read(rtc, RTC_EXT_CTRL_4B) &
+ ~(RTC_CTRL_4B_RWK_MASK)));
+
+ /* Manually clear RF/WF/KF in Ctrl 4A. */
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (rtc->read(rtc, RTC_EXT_CTRL_4A) &
+ ~(RTC_CTRL_4A_RWK_MASK)));
+
+ cancel_work_sync(&rtc->work);
+
+ return 0;
+}
+
+/**
+ * ds1685_rtc_driver - rtc driver properties.
+ */
+static struct platform_driver ds1685_rtc_driver = {
+ .driver = {
+ .name = "rtc-ds1685",
+ .owner = THIS_MODULE,
+ },
+ .probe = ds1685_rtc_probe,
+ .remove = ds1685_rtc_remove,
+};
+
+/**
+ * ds1685_rtc_init - rtc module init.
+ */
+static int __init
+ds1685_rtc_init(void)
+{
+ return platform_driver_register(&ds1685_rtc_driver);
+}
+
+/**
+ * ds1685_rtc_exit - rtc module exit.
+ */
+static void __exit
+ds1685_rtc_exit(void)
+{
+ platform_driver_unregister(&ds1685_rtc_driver);
+}
+
+module_init(ds1685_rtc_init);
+module_exit(ds1685_rtc_exit);
+/* ----------------------------------------------------------------------- */
+
+
+/* ----------------------------------------------------------------------- */
+/* Poweroff function */
+
+/**
+ * ds1685_rtc_poweroff - uses the RTC chip to power the system off.
+ * @pdev: pointer to platform_device structure.
+ */
+extern void __noreturn
+ds1685_rtc_poweroff(struct platform_device *pdev)
+{
+ u8 ctrla, ctrl4a, ctrl4b;
+ struct ds1685_priv *rtc;
+
+ /* Check for valid RTC data, else, spin forever. */
+ if (unlikely(!pdev)) {
+ pr_emerg("rtc-ds1685: platform device data not available, spinning forever ...\n");
+ unreachable();
+ } else {
+ /* Get the rtc data. */
+ rtc = platform_get_drvdata(pdev);
+
+ /*
+ * Disable our IRQ. We're powering down, so we're not
+ * going to worry about cleaning up. Most of that should
+ * have been taken care of by the shutdown scripts and this
+ * is the final function call.
+ */
+ if (!rtc->no_irq)
+ disable_irq_nosync(rtc->irq_num);
+
+ /* Oscillator must be on and the countdown chain enabled. */
+ ctrla = rtc->read(rtc, RTC_CTRL_A);
+ ctrla |= RTC_CTRL_A_DV1;
+ ctrla &= ~(RTC_CTRL_A_DV2);
+ rtc->write(rtc, RTC_CTRL_A, ctrla);
+
+ /*
+ * Read Control 4A and check the status of the auxillary
+ * battery. This must be present and working (VRT2 = 1)
+ * for wakeup and kickstart functionality to be useful.
+ */
+ ds1685_rtc_switch_to_bank1(rtc);
+ ctrl4a = rtc->read(rtc, RTC_EXT_CTRL_4A);
+ if (ctrl4a & RTC_CTRL_4A_VRT2) {
+ /* Clear all of the interrupt flags on Control 4A. */
+ ctrl4a &= ~(RTC_CTRL_4A_RWK_MASK);
+ rtc->write(rtc, RTC_EXT_CTRL_4A, ctrl4a);
+
+ /*
+ * The auxillary battery is present and working.
+ * Enable extended functions (ABE=1), enable
+ * wake-up (WIE=1), and enable kickstart (KSE=1)
+ * in Control 4B.
+ */
+ ctrl4b = rtc->read(rtc, RTC_EXT_CTRL_4B);
+ ctrl4b |= (RTC_CTRL_4B_ABE | RTC_CTRL_4B_WIE |
+ RTC_CTRL_4B_KSE);
+ rtc->write(rtc, RTC_EXT_CTRL_4B, ctrl4b);
+ }
+
+ /* Set PAB to 1 in Control 4A to power the system down. */
+ dev_warn(&pdev->dev, "Powerdown.\n");
+ msleep(20);
+ rtc->write(rtc, RTC_EXT_CTRL_4A,
+ (ctrl4a | RTC_CTRL_4A_PAB));
+
+ /* Spin ... we do not switch back to bank0. */
+ unreachable();
+ }
+}
+EXPORT_SYMBOL(ds1685_rtc_poweroff);
+/* ----------------------------------------------------------------------- */
+
+
+MODULE_AUTHOR("Joshua Kinard <kumba@gentoo.org>");
+MODULE_AUTHOR("Matthias Fuchs <matthias.fuchs@esd-electronics.com>");
+MODULE_DESCRIPTION("Dallas/Maxim DS1685/DS1687-series RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+MODULE_ALIAS("platform:rtc-ds1685");
diff --git a/drivers/rtc/rtc-imxdi.c b/drivers/rtc/rtc-imxdi.c
index 42f5570f42f8..c666eab98273 100644
--- a/drivers/rtc/rtc-imxdi.c
+++ b/drivers/rtc/rtc-imxdi.c
@@ -50,22 +50,58 @@
#define DCAMR_UNSET 0xFFFFFFFF /* doomsday - 1 sec */
#define DCR 0x10 /* Control Reg */
+#define DCR_TDCHL (1 << 30) /* Tamper-detect configuration hard lock */
+#define DCR_TDCSL (1 << 29) /* Tamper-detect configuration soft lock */
+#define DCR_KSSL (1 << 27) /* Key-select soft lock */
+#define DCR_MCHL (1 << 20) /* Monotonic-counter hard lock */
+#define DCR_MCSL (1 << 19) /* Monotonic-counter soft lock */
+#define DCR_TCHL (1 << 18) /* Timer-counter hard lock */
+#define DCR_TCSL (1 << 17) /* Timer-counter soft lock */
+#define DCR_FSHL (1 << 16) /* Failure state hard lock */
#define DCR_TCE (1 << 3) /* Time Counter Enable */
+#define DCR_MCE (1 << 2) /* Monotonic Counter Enable */
#define DSR 0x14 /* Status Reg */
-#define DSR_WBF (1 << 10) /* Write Busy Flag */
-#define DSR_WNF (1 << 9) /* Write Next Flag */
-#define DSR_WCF (1 << 8) /* Write Complete Flag */
+#define DSR_WTD (1 << 23) /* Wire-mesh tamper detected */
+#define DSR_ETBD (1 << 22) /* External tamper B detected */
+#define DSR_ETAD (1 << 21) /* External tamper A detected */
+#define DSR_EBD (1 << 20) /* External boot detected */
+#define DSR_SAD (1 << 19) /* SCC alarm detected */
+#define DSR_TTD (1 << 18) /* Temperatur tamper detected */
+#define DSR_CTD (1 << 17) /* Clock tamper detected */
+#define DSR_VTD (1 << 16) /* Voltage tamper detected */
+#define DSR_WBF (1 << 10) /* Write Busy Flag (synchronous) */
+#define DSR_WNF (1 << 9) /* Write Next Flag (synchronous) */
+#define DSR_WCF (1 << 8) /* Write Complete Flag (synchronous)*/
#define DSR_WEF (1 << 7) /* Write Error Flag */
#define DSR_CAF (1 << 4) /* Clock Alarm Flag */
+#define DSR_MCO (1 << 3) /* monotonic counter overflow */
+#define DSR_TCO (1 << 2) /* time counter overflow */
#define DSR_NVF (1 << 1) /* Non-Valid Flag */
#define DSR_SVF (1 << 0) /* Security Violation Flag */
-#define DIER 0x18 /* Interrupt Enable Reg */
+#define DIER 0x18 /* Interrupt Enable Reg (synchronous) */
#define DIER_WNIE (1 << 9) /* Write Next Interrupt Enable */
#define DIER_WCIE (1 << 8) /* Write Complete Interrupt Enable */
#define DIER_WEIE (1 << 7) /* Write Error Interrupt Enable */
#define DIER_CAIE (1 << 4) /* Clock Alarm Interrupt Enable */
+#define DIER_SVIE (1 << 0) /* Security-violation Interrupt Enable */
+
+#define DMCR 0x1c /* DryIce Monotonic Counter Reg */
+
+#define DTCR 0x28 /* DryIce Tamper Configuration Reg */
+#define DTCR_MOE (1 << 9) /* monotonic overflow enabled */
+#define DTCR_TOE (1 << 8) /* time overflow enabled */
+#define DTCR_WTE (1 << 7) /* wire-mesh tamper enabled */
+#define DTCR_ETBE (1 << 6) /* external B tamper enabled */
+#define DTCR_ETAE (1 << 5) /* external A tamper enabled */
+#define DTCR_EBE (1 << 4) /* external boot tamper enabled */
+#define DTCR_SAIE (1 << 3) /* SCC enabled */
+#define DTCR_TTE (1 << 2) /* temperature tamper enabled */
+#define DTCR_CTE (1 << 1) /* clock tamper enabled */
+#define DTCR_VTE (1 << 0) /* voltage tamper enabled */
+
+#define DGPR 0x3c /* DryIce General Purpose Reg */
/**
* struct imxdi_dev - private imxdi rtc data
@@ -313,7 +349,7 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
dier = __raw_readl(imxdi->ioaddr + DIER);
/* handle write complete and write error cases */
- if ((dier & DIER_WCIE)) {
+ if (dier & DIER_WCIE) {
/*If the write wait queue is empty then there is no pending
operations. It means the interrupt is for DryIce -Security.
IRQ must be returned as none.*/
@@ -322,7 +358,7 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
/* DSR_WCF clears itself on DSR read */
dsr = __raw_readl(imxdi->ioaddr + DSR);
- if ((dsr & (DSR_WCF | DSR_WEF))) {
+ if (dsr & (DSR_WCF | DSR_WEF)) {
/* mask the interrupt */
di_int_disable(imxdi, DIER_WCIE);
@@ -335,7 +371,7 @@ static irqreturn_t dryice_norm_irq(int irq, void *dev_id)
}
/* handle the alarm case */
- if ((dier & DIER_CAIE)) {
+ if (dier & DIER_CAIE) {
/* DSR_WCF clears itself on DSR read */
dsr = __raw_readl(imxdi->ioaddr + DSR);
if (dsr & DSR_CAF) {
diff --git a/drivers/rtc/rtc-isl12022.c b/drivers/rtc/rtc-isl12022.c
index ee3ba7e6b45e..f9b082784b90 100644
--- a/drivers/rtc/rtc-isl12022.c
+++ b/drivers/rtc/rtc-isl12022.c
@@ -275,7 +275,8 @@ static int isl12022_probe(struct i2c_client *client,
#ifdef CONFIG_OF
static const struct of_device_id isl12022_dt_match[] = {
- { .compatible = "isl,isl12022" },
+ { .compatible = "isl,isl12022" }, /* for backward compat., don't use */
+ { .compatible = "isil,isl12022" },
{ },
};
#endif
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c
index 6e1fcfb5d7e6..da818d3337ce 100644
--- a/drivers/rtc/rtc-isl12057.c
+++ b/drivers/rtc/rtc-isl12057.c
@@ -79,8 +79,10 @@
#define ISL12057_MEM_MAP_LEN 0x10
struct isl12057_rtc_data {
+ struct rtc_device *rtc;
struct regmap *regmap;
struct mutex lock;
+ int irq;
};
static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
@@ -160,14 +162,47 @@ static int isl12057_i2c_validate_chip(struct regmap *regmap)
return 0;
}
-static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
+static int _isl12057_rtc_clear_alarm(struct device *dev)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, ISL12057_REG_SR,
+ ISL12057_REG_SR_A1F, 0);
+ if (ret)
+ dev_err(dev, "%s: clearing alarm failed (%d)\n", __func__, ret);
+
+ return ret;
+}
+
+static int _isl12057_rtc_update_alarm(struct device *dev, int enable)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ ret = regmap_update_bits(data->regmap, ISL12057_REG_INT,
+ ISL12057_REG_INT_A1IE,
+ enable ? ISL12057_REG_INT_A1IE : 0);
+ if (ret)
+ dev_err(dev, "%s: changing alarm interrupt flag failed (%d)\n",
+ __func__, ret);
+
+ return ret;
+}
+
+/*
+ * Note: as we only read from device and do not perform any update, there is
+ * no need for an equivalent function which would try and get driver's main
+ * lock. Here, it is safe for everyone if we just use regmap internal lock
+ * on the device when reading.
+ */
+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",
@@ -187,8 +222,6 @@ static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
__func__, ret);
out:
- mutex_unlock(&data->lock);
-
if (ret)
return ret;
@@ -197,6 +230,168 @@ out:
return rtc_valid_tm(tm);
}
+static int isl12057_rtc_update_alarm(struct device *dev, int enable)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&data->lock);
+ ret = _isl12057_rtc_update_alarm(dev, enable);
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int isl12057_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+ struct rtc_time rtc_tm, *alarm_tm = &alarm->time;
+ unsigned long rtc_secs, alarm_secs;
+ u8 regs[ISL12057_A1_SEC_LEN];
+ unsigned int ir;
+ int ret;
+
+ mutex_lock(&data->lock);
+ ret = regmap_bulk_read(data->regmap, ISL12057_REG_A1_SC, regs,
+ ISL12057_A1_SEC_LEN);
+ if (ret) {
+ dev_err(dev, "%s: reading alarm section failed (%d)\n",
+ __func__, ret);
+ goto err_unlock;
+ }
+
+ alarm_tm->tm_sec = bcd2bin(regs[0] & 0x7f);
+ alarm_tm->tm_min = bcd2bin(regs[1] & 0x7f);
+ alarm_tm->tm_hour = bcd2bin(regs[2] & 0x3f);
+ alarm_tm->tm_mday = bcd2bin(regs[3] & 0x3f);
+ alarm_tm->tm_wday = -1;
+
+ /*
+ * The alarm section does not store year/month. We use the ones in rtc
+ * section as a basis and increment month and then year if needed to get
+ * alarm after current time.
+ */
+ ret = _isl12057_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ goto err_unlock;
+
+ alarm_tm->tm_year = rtc_tm.tm_year;
+ alarm_tm->tm_mon = rtc_tm.tm_mon;
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err_unlock;
+
+ ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+ if (ret)
+ goto err_unlock;
+
+ if (alarm_secs < rtc_secs) {
+ if (alarm_tm->tm_mon == 11) {
+ alarm_tm->tm_mon = 0;
+ alarm_tm->tm_year += 1;
+ } else {
+ alarm_tm->tm_mon += 1;
+ }
+ }
+
+ ret = regmap_read(data->regmap, ISL12057_REG_INT, &ir);
+ if (ret) {
+ dev_err(dev, "%s: reading alarm interrupt flag failed (%d)\n",
+ __func__, ret);
+ goto err_unlock;
+ }
+
+ alarm->enabled = !!(ir & ISL12057_REG_INT_A1IE);
+
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
+static int isl12057_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alarm)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+ struct rtc_time *alarm_tm = &alarm->time;
+ unsigned long rtc_secs, alarm_secs;
+ u8 regs[ISL12057_A1_SEC_LEN];
+ struct rtc_time rtc_tm;
+ int ret, enable = 1;
+
+ mutex_lock(&data->lock);
+ ret = _isl12057_rtc_read_time(dev, &rtc_tm);
+ if (ret)
+ goto err_unlock;
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err_unlock;
+
+ ret = rtc_tm_to_time(alarm_tm, &alarm_secs);
+ if (ret)
+ goto err_unlock;
+
+ /* If alarm time is before current time, disable the alarm */
+ if (!alarm->enabled || alarm_secs <= rtc_secs) {
+ enable = 0;
+ } else {
+ /*
+ * Chip only support alarms up to one month in the future. Let's
+ * return an error if we get something after that limit.
+ * Comparison is done by incrementing rtc_tm month field by one
+ * and checking alarm value is still below.
+ */
+ if (rtc_tm.tm_mon == 11) { /* handle year wrapping */
+ rtc_tm.tm_mon = 0;
+ rtc_tm.tm_year += 1;
+ } else {
+ rtc_tm.tm_mon += 1;
+ }
+
+ ret = rtc_tm_to_time(&rtc_tm, &rtc_secs);
+ if (ret)
+ goto err_unlock;
+
+ if (alarm_secs > rtc_secs) {
+ dev_err(dev, "%s: max for alarm is one month (%d)\n",
+ __func__, ret);
+ ret = -EINVAL;
+ goto err_unlock;
+ }
+ }
+
+ /* Disable the alarm before modifying it */
+ ret = _isl12057_rtc_update_alarm(dev, 0);
+ if (ret < 0) {
+ dev_err(dev, "%s: unable to disable the alarm (%d)\n",
+ __func__, ret);
+ goto err_unlock;
+ }
+
+ /* Program alarm registers */
+ regs[0] = bin2bcd(alarm_tm->tm_sec) & 0x7f;
+ regs[1] = bin2bcd(alarm_tm->tm_min) & 0x7f;
+ regs[2] = bin2bcd(alarm_tm->tm_hour) & 0x3f;
+ regs[3] = bin2bcd(alarm_tm->tm_mday) & 0x3f;
+
+ ret = regmap_bulk_write(data->regmap, ISL12057_REG_A1_SC, regs,
+ ISL12057_A1_SEC_LEN);
+ if (ret < 0) {
+ dev_err(dev, "%s: writing alarm section failed (%d)\n",
+ __func__, ret);
+ goto err_unlock;
+ }
+
+ /* Enable or disable alarm */
+ ret = _isl12057_rtc_update_alarm(dev, enable);
+
+err_unlock:
+ mutex_unlock(&data->lock);
+
+ return ret;
+}
+
static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
struct isl12057_rtc_data *data = dev_get_drvdata(dev);
@@ -262,12 +457,85 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap)
return 0;
}
+#ifdef CONFIG_OF
+/*
+ * One would expect the device to be marked as a wakeup source only
+ * when an IRQ pin of the RTC is routed to an interrupt line of the
+ * CPU. In practice, such an IRQ pin can be connected to a PMIC and
+ * this allows the device to be powered up when RTC alarm rings. This
+ * is for instance the case on ReadyNAS 102, 104 and 2120. On those
+ * devices with no IRQ driectly connected to the SoC, the RTC chip
+ * can be forced as a wakeup source by stating that explicitly in
+ * the device's .dts file using the "isil,irq2-can-wakeup-machine"
+ * boolean property. This will guarantee 'wakealarm' sysfs entry is
+ * available on the device.
+ *
+ * The function below returns 1, i.e. the capability of the chip to
+ * wakeup the device, based on IRQ availability or if the boolean
+ * property has been set in the .dts file. Otherwise, it returns 0.
+ */
+
+static bool isl12057_can_wakeup_machine(struct device *dev)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+
+ return (data->irq || of_property_read_bool(dev->of_node,
+ "isil,irq2-can-wakeup-machine"));
+}
+#else
+static bool isl12057_can_wakeup_machine(struct device *dev)
+{
+ struct isl12057_rtc_data *data = dev_get_drvdata(dev);
+
+ return !!data->irq;
+}
+#endif
+
+static int isl12057_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enable)
+{
+ struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev);
+ int ret = -ENOTTY;
+
+ if (rtc_data->irq)
+ ret = isl12057_rtc_update_alarm(dev, enable);
+
+ return ret;
+}
+
+static irqreturn_t isl12057_rtc_interrupt(int irq, void *data)
+{
+ struct i2c_client *client = data;
+ struct isl12057_rtc_data *rtc_data = dev_get_drvdata(&client->dev);
+ struct rtc_device *rtc = rtc_data->rtc;
+ int ret, handled = IRQ_NONE;
+ unsigned int sr;
+
+ ret = regmap_read(rtc_data->regmap, ISL12057_REG_SR, &sr);
+ if (!ret && (sr & ISL12057_REG_SR_A1F)) {
+ dev_dbg(&client->dev, "RTC alarm!\n");
+
+ rtc_update_irq(rtc, 1, RTC_IRQF | RTC_AF);
+
+ /* Acknowledge and disable the alarm */
+ _isl12057_rtc_clear_alarm(&client->dev);
+ _isl12057_rtc_update_alarm(&client->dev, 0);
+
+ handled = IRQ_HANDLED;
+ }
+
+ return handled;
+}
+
static const struct rtc_class_ops rtc_ops = {
- .read_time = isl12057_rtc_read_time,
+ .read_time = _isl12057_rtc_read_time,
.set_time = isl12057_rtc_set_time,
+ .read_alarm = isl12057_rtc_read_alarm,
+ .set_alarm = isl12057_rtc_set_alarm,
+ .alarm_irq_enable = isl12057_rtc_alarm_irq_enable,
};
-static struct regmap_config isl12057_rtc_regmap_config = {
+static const struct regmap_config isl12057_rtc_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
};
@@ -277,7 +545,6 @@ static int isl12057_probe(struct i2c_client *client,
{
struct device *dev = &client->dev;
struct isl12057_rtc_data *data;
- struct rtc_device *rtc;
struct regmap *regmap;
int ret;
@@ -310,13 +577,75 @@ static int isl12057_probe(struct i2c_client *client,
data->regmap = regmap;
dev_set_drvdata(dev, data);
- rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops, THIS_MODULE);
- return PTR_ERR_OR_ZERO(rtc);
+ if (client->irq > 0) {
+ ret = devm_request_threaded_irq(dev, client->irq, NULL,
+ isl12057_rtc_interrupt,
+ IRQF_SHARED|IRQF_ONESHOT,
+ DRV_NAME, client);
+ if (!ret)
+ data->irq = client->irq;
+ else
+ dev_err(dev, "%s: irq %d unavailable (%d)\n", __func__,
+ client->irq, ret);
+ }
+
+ if (isl12057_can_wakeup_machine(dev))
+ device_init_wakeup(dev, true);
+
+ data->rtc = devm_rtc_device_register(dev, DRV_NAME, &rtc_ops,
+ THIS_MODULE);
+ ret = PTR_ERR_OR_ZERO(data->rtc);
+ if (ret) {
+ dev_err(dev, "%s: unable to register RTC device (%d)\n",
+ __func__, ret);
+ goto err;
+ }
+
+ /* We cannot support UIE mode if we do not have an IRQ line */
+ if (!data->irq)
+ data->rtc->uie_unsupported = 1;
+
+err:
+ return ret;
+}
+
+static int isl12057_remove(struct i2c_client *client)
+{
+ if (isl12057_can_wakeup_machine(&client->dev))
+ device_init_wakeup(&client->dev, false);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int isl12057_rtc_suspend(struct device *dev)
+{
+ struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+ if (rtc_data->irq && device_may_wakeup(dev))
+ return enable_irq_wake(rtc_data->irq);
+
+ return 0;
+}
+
+static int isl12057_rtc_resume(struct device *dev)
+{
+ struct isl12057_rtc_data *rtc_data = dev_get_drvdata(dev);
+
+ if (rtc_data->irq && device_may_wakeup(dev))
+ return disable_irq_wake(rtc_data->irq);
+
+ return 0;
}
+#endif
+
+static SIMPLE_DEV_PM_OPS(isl12057_rtc_pm_ops, isl12057_rtc_suspend,
+ isl12057_rtc_resume);
#ifdef CONFIG_OF
static const struct of_device_id isl12057_dt_match[] = {
- { .compatible = "isl,isl12057" },
+ { .compatible = "isl,isl12057" }, /* for backward compat., don't use */
+ { .compatible = "isil,isl12057" },
{ },
};
#endif
@@ -331,9 +660,11 @@ static struct i2c_driver isl12057_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
+ .pm = &isl12057_rtc_pm_ops,
.of_match_table = of_match_ptr(isl12057_dt_match),
},
.probe = isl12057_probe,
+ .remove = isl12057_remove,
.id_table = isl12057_id,
};
module_i2c_driver(isl12057_driver);
diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c
index d1953bb244c5..8a7556cbcb7f 100644
--- a/drivers/rtc/rtc-pcf2123.c
+++ b/drivers/rtc/rtc-pcf2123.c
@@ -38,6 +38,7 @@
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/rtc.h>
@@ -340,10 +341,19 @@ static int pcf2123_remove(struct spi_device *spi)
return 0;
}
+#ifdef CONFIG_OF
+static const struct of_device_id pcf2123_dt_ids[] = {
+ { .compatible = "nxp,rtc-pcf2123", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, pcf2123_dt_ids);
+#endif
+
static struct spi_driver pcf2123_driver = {
.driver = {
.name = "rtc-pcf2123",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(pcf2123_dt_ids),
},
.probe = pcf2123_probe,
.remove = pcf2123_remove,
diff --git a/drivers/rtc/rtc-rk808.c b/drivers/rtc/rtc-rk808.c
index df42257668ac..91ca0bc1b484 100644
--- a/drivers/rtc/rtc-rk808.c
+++ b/drivers/rtc/rtc-rk808.c
@@ -67,15 +67,21 @@ static int rk808_rtc_readtime(struct device *dev, struct rtc_time *tm)
/* Force an update of the shadowed registers right now */
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
BIT_RTC_CTRL_REG_RTC_GET_TIME,
- 0);
+ BIT_RTC_CTRL_REG_RTC_GET_TIME);
if (ret) {
dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
return ret;
}
+ /*
+ * After we set the GET_TIME bit, the rtc time can't be read
+ * immediately. So we should wait up to 31.25 us, about one cycle of
+ * 32khz. If we clear the GET_TIME bit here, the time of i2c transfer
+ * certainly more than 31.25us: 16 * 2.5us at 400kHz bus frequency.
+ */
ret = regmap_update_bits(rk808->regmap, RK808_RTC_CTRL_REG,
BIT_RTC_CTRL_REG_RTC_GET_TIME,
- BIT_RTC_CTRL_REG_RTC_GET_TIME);
+ 0);
if (ret) {
dev_err(dev, "Failed to update bits rtc_ctrl: %d\n", ret);
return ret;
diff --git a/drivers/rtc/systohc.c b/drivers/rtc/systohc.c
index bf3e242ccc5c..eb71872d0361 100644
--- a/drivers/rtc/systohc.c
+++ b/drivers/rtc/systohc.c
@@ -20,16 +20,16 @@
*
* If temporary failure is indicated the caller should try again 'soon'
*/
-int rtc_set_ntp_time(struct timespec now)
+int rtc_set_ntp_time(struct timespec64 now)
{
struct rtc_device *rtc;
struct rtc_time tm;
int err = -ENODEV;
if (now.tv_nsec < (NSEC_PER_SEC >> 1))
- rtc_time_to_tm(now.tv_sec, &tm);
+ rtc_time64_to_tm(now.tv_sec, &tm);
else
- rtc_time_to_tm(now.tv_sec + 1, &tm);
+ rtc_time64_to_tm(now.tv_sec + 1, &tm);
rtc = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
if (rtc) {
diff --git a/drivers/s390/block/dasd.c b/drivers/s390/block/dasd.c
index 4abf11965484..be34ef41b7c7 100644
--- a/drivers/s390/block/dasd.c
+++ b/drivers/s390/block/dasd.c
@@ -674,8 +674,9 @@ EXPORT_SYMBOL(dasd_enable_device);
unsigned int dasd_global_profile_level = DASD_PROFILE_OFF;
#ifdef CONFIG_DASD_PROFILE
-struct dasd_profile_info dasd_global_profile_data;
-static struct dentry *dasd_global_profile_dentry;
+struct dasd_profile dasd_global_profile = {
+ .lock = __SPIN_LOCK_UNLOCKED(dasd_global_profile.lock),
+};
static struct dentry *dasd_debugfs_global_entry;
/*
@@ -696,11 +697,13 @@ static void dasd_profile_start(struct dasd_block *block,
if (++counter >= 31)
break;
- if (dasd_global_profile_level) {
- dasd_global_profile_data.dasd_io_nr_req[counter]++;
+ spin_lock(&dasd_global_profile.lock);
+ if (dasd_global_profile.data) {
+ dasd_global_profile.data->dasd_io_nr_req[counter]++;
if (rq_data_dir(req) == READ)
- dasd_global_profile_data.dasd_read_nr_req[counter]++;
+ dasd_global_profile.data->dasd_read_nr_req[counter]++;
}
+ spin_unlock(&dasd_global_profile.lock);
spin_lock(&block->profile.lock);
if (block->profile.data) {
@@ -825,8 +828,9 @@ static void dasd_profile_end(struct dasd_block *block,
dasd_profile_counter(irqtime / sectors, irqtimeps_ind);
dasd_profile_counter(endtime, endtime_ind);
- if (dasd_global_profile_level) {
- dasd_profile_end_add_data(&dasd_global_profile_data,
+ spin_lock(&dasd_global_profile.lock);
+ if (dasd_global_profile.data) {
+ dasd_profile_end_add_data(dasd_global_profile.data,
cqr->startdev != block->base,
cqr->cpmode == 1,
rq_data_dir(req) == READ,
@@ -835,6 +839,7 @@ static void dasd_profile_end(struct dasd_block *block,
irqtime_ind, irqtimeps_ind,
endtime_ind);
}
+ spin_unlock(&dasd_global_profile.lock);
spin_lock(&block->profile.lock);
if (block->profile.data)
@@ -876,12 +881,6 @@ void dasd_profile_reset(struct dasd_profile *profile)
spin_unlock_bh(&profile->lock);
}
-void dasd_global_profile_reset(void)
-{
- memset(&dasd_global_profile_data, 0, sizeof(dasd_global_profile_data));
- getnstimeofday(&dasd_global_profile_data.starttod);
-}
-
int dasd_profile_on(struct dasd_profile *profile)
{
struct dasd_profile_info *data;
@@ -949,12 +948,20 @@ static ssize_t dasd_stats_write(struct file *file,
dasd_profile_reset(prof);
} else if (strncmp(str, "on", 2) == 0) {
rc = dasd_profile_on(prof);
- if (!rc)
- rc = user_len;
+ if (rc)
+ goto out;
+ rc = user_len;
+ if (prof == &dasd_global_profile) {
+ dasd_profile_reset(prof);
+ dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
+ }
} else if (strncmp(str, "off", 3) == 0) {
+ if (prof == &dasd_global_profile)
+ dasd_global_profile_level = DASD_PROFILE_OFF;
dasd_profile_off(prof);
} else
rc = -EINVAL;
+out:
vfree(buffer);
return rc;
}
@@ -1044,57 +1051,6 @@ static const struct file_operations dasd_stats_raw_fops = {
.write = dasd_stats_write,
};
-static ssize_t dasd_stats_global_write(struct file *file,
- const char __user *user_buf,
- size_t user_len, loff_t *pos)
-{
- char *buffer, *str;
- ssize_t rc;
-
- if (user_len > 65536)
- user_len = 65536;
- buffer = dasd_get_user_string(user_buf, user_len);
- if (IS_ERR(buffer))
- return PTR_ERR(buffer);
- str = skip_spaces(buffer);
- rc = user_len;
- if (strncmp(str, "reset", 5) == 0) {
- dasd_global_profile_reset();
- } else if (strncmp(str, "on", 2) == 0) {
- dasd_global_profile_reset();
- dasd_global_profile_level = DASD_PROFILE_GLOBAL_ONLY;
- } else if (strncmp(str, "off", 3) == 0) {
- dasd_global_profile_level = DASD_PROFILE_OFF;
- } else
- rc = -EINVAL;
- vfree(buffer);
- return rc;
-}
-
-static int dasd_stats_global_show(struct seq_file *m, void *v)
-{
- if (!dasd_global_profile_level) {
- seq_puts(m, "disabled\n");
- return 0;
- }
- dasd_stats_seq_print(m, &dasd_global_profile_data);
- return 0;
-}
-
-static int dasd_stats_global_open(struct inode *inode, struct file *file)
-{
- return single_open(file, dasd_stats_global_show, NULL);
-}
-
-static const struct file_operations dasd_stats_global_fops = {
- .owner = THIS_MODULE,
- .open = dasd_stats_global_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = dasd_stats_global_write,
-};
-
static void dasd_profile_init(struct dasd_profile *profile,
struct dentry *base_dentry)
{
@@ -1123,20 +1079,16 @@ static void dasd_profile_exit(struct dasd_profile *profile)
static void dasd_statistics_removeroot(void)
{
dasd_global_profile_level = DASD_PROFILE_OFF;
- debugfs_remove(dasd_global_profile_dentry);
- dasd_global_profile_dentry = NULL;
+ dasd_profile_exit(&dasd_global_profile);
debugfs_remove(dasd_debugfs_global_entry);
debugfs_remove(dasd_debugfs_root_entry);
}
static void dasd_statistics_createroot(void)
{
- umode_t mode;
struct dentry *pde;
dasd_debugfs_root_entry = NULL;
- dasd_debugfs_global_entry = NULL;
- dasd_global_profile_dentry = NULL;
pde = debugfs_create_dir("dasd", NULL);
if (!pde || IS_ERR(pde))
goto error;
@@ -1145,13 +1097,7 @@ static void dasd_statistics_createroot(void)
if (!pde || IS_ERR(pde))
goto error;
dasd_debugfs_global_entry = pde;
-
- mode = (S_IRUSR | S_IWUSR | S_IFREG);
- pde = debugfs_create_file("statistics", mode, dasd_debugfs_global_entry,
- NULL, &dasd_stats_global_fops);
- if (!pde || IS_ERR(pde))
- goto error;
- dasd_global_profile_dentry = pde;
+ dasd_profile_init(&dasd_global_profile, dasd_debugfs_global_entry);
return;
error:
diff --git a/drivers/s390/block/dasd_int.h b/drivers/s390/block/dasd_int.h
index 8b5d4100abf7..227e3dea3155 100644
--- a/drivers/s390/block/dasd_int.h
+++ b/drivers/s390/block/dasd_int.h
@@ -651,7 +651,7 @@ dasd_check_blocksize(int bsize)
#define DASD_PROFILE_GLOBAL_ONLY 2
extern debug_info_t *dasd_debug_area;
-extern struct dasd_profile_info dasd_global_profile_data;
+extern struct dasd_profile dasd_global_profile;
extern unsigned int dasd_global_profile_level;
extern const struct block_device_operations dasd_device_operations;
@@ -728,7 +728,6 @@ int dasd_device_is_ro(struct dasd_device *);
void dasd_profile_reset(struct dasd_profile *);
int dasd_profile_on(struct dasd_profile *);
void dasd_profile_off(struct dasd_profile *);
-void dasd_global_profile_reset(void);
char *dasd_get_user_string(const char __user *, size_t);
/* externals in dasd_devmap.c */
diff --git a/drivers/s390/block/dasd_proc.c b/drivers/s390/block/dasd_proc.c
index 78ac905a5b7f..aa7bb2d1da81 100644
--- a/drivers/s390/block/dasd_proc.c
+++ b/drivers/s390/block/dasd_proc.c
@@ -212,14 +212,15 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v)
struct dasd_profile_info *prof;
int factor;
- /* check for active profiling */
- if (!dasd_global_profile_level) {
+ spin_lock_bh(&dasd_global_profile.lock);
+ prof = dasd_global_profile.data;
+ if (!prof) {
+ spin_unlock_bh(&dasd_global_profile.lock);
seq_printf(m, "Statistics are off - they might be "
"switched on using 'echo set on > "
"/proc/dasd/statistics'\n");
return 0;
}
- prof = &dasd_global_profile_data;
/* prevent counter 'overflow' on output */
for (factor = 1; (prof->dasd_io_reqs / factor) > 9999999;
@@ -255,6 +256,7 @@ static int dasd_stats_proc_show(struct seq_file *m, void *v)
dasd_statistics_array(m, prof->dasd_io_time3, factor);
seq_printf(m, "# of req in chanq at enqueuing (1..32) \n");
dasd_statistics_array(m, prof->dasd_io_nr_req, factor);
+ spin_unlock_bh(&dasd_global_profile.lock);
#else
seq_printf(m, "Statistics are not activated in this kernel\n");
#endif
@@ -291,14 +293,19 @@ static ssize_t dasd_stats_proc_write(struct file *file,
dasd_stats_all_block_off();
goto out_error;
}
- dasd_global_profile_reset();
+ rc = dasd_profile_on(&dasd_global_profile);
+ if (rc) {
+ dasd_stats_all_block_off();
+ goto out_error;
+ }
+ dasd_profile_reset(&dasd_global_profile);
dasd_global_profile_level = DASD_PROFILE_ON;
pr_info("The statistics feature has been switched "
"on\n");
} else if (strcmp(str, "off") == 0) {
- /* switch off and reset statistics profiling */
+ /* switch off statistics profiling */
dasd_global_profile_level = DASD_PROFILE_OFF;
- dasd_global_profile_reset();
+ dasd_profile_off(&dasd_global_profile);
dasd_stats_all_block_off();
pr_info("The statistics feature has been switched "
"off\n");
@@ -306,7 +313,7 @@ static ssize_t dasd_stats_proc_write(struct file *file,
goto out_parse_error;
} else if (strncmp(str, "reset", 5) == 0) {
/* reset the statistics */
- dasd_global_profile_reset();
+ dasd_profile_reset(&dasd_global_profile);
dasd_stats_all_block_reset();
pr_info("The statistics have been reset\n");
} else
diff --git a/drivers/s390/block/dcssblk.c b/drivers/s390/block/dcssblk.c
index b550c8c8d010..96128cb009f3 100644
--- a/drivers/s390/block/dcssblk.c
+++ b/drivers/s390/block/dcssblk.c
@@ -28,8 +28,8 @@
static int dcssblk_open(struct block_device *bdev, fmode_t mode);
static void dcssblk_release(struct gendisk *disk, fmode_t mode);
static void dcssblk_make_request(struct request_queue *q, struct bio *bio);
-static int dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
- void **kaddr, unsigned long *pfn);
+static long dcssblk_direct_access(struct block_device *bdev, sector_t secnum,
+ void **kaddr, unsigned long *pfn, long size);
static char dcssblk_segments[DCSSBLK_PARM_LEN] = "\0";
@@ -438,7 +438,13 @@ dcssblk_save_store(struct device *dev, struct device_attribute *attr, const char
pr_info("All DCSSs that map to device %s are "
"saved\n", dev_info->segment_name);
list_for_each_entry(entry, &dev_info->seg_list, lh) {
- segment_save(entry->segment_name);
+ if (entry->segment_type == SEG_TYPE_EN ||
+ entry->segment_type == SEG_TYPE_SN)
+ pr_warn("DCSS %s is of type SN or EN"
+ " and cannot be saved\n",
+ entry->segment_name);
+ else
+ segment_save(entry->segment_name);
}
} else {
// device is busy => we save it when it becomes
@@ -797,7 +803,12 @@ dcssblk_release(struct gendisk *disk, fmode_t mode)
pr_info("Device %s has become idle and is being saved "
"now\n", dev_info->segment_name);
list_for_each_entry(entry, &dev_info->seg_list, lh) {
- segment_save(entry->segment_name);
+ if (entry->segment_type == SEG_TYPE_EN ||
+ entry->segment_type == SEG_TYPE_SN)
+ pr_warn("DCSS %s is of type SN or EN and cannot"
+ " be saved\n", entry->segment_name);
+ else
+ segment_save(entry->segment_name);
}
dev_info->save_pending = 0;
}
@@ -866,25 +877,22 @@ fail:
bio_io_error(bio);
}
-static int
+static long
dcssblk_direct_access (struct block_device *bdev, sector_t secnum,
- void **kaddr, unsigned long *pfn)
+ void **kaddr, unsigned long *pfn, long size)
{
struct dcssblk_dev_info *dev_info;
- unsigned long pgoff;
+ unsigned long offset, dev_sz;
dev_info = bdev->bd_disk->private_data;
if (!dev_info)
return -ENODEV;
- if (secnum % (PAGE_SIZE/512))
- return -EINVAL;
- pgoff = secnum / (PAGE_SIZE / 512);
- if ((pgoff+1)*PAGE_SIZE-1 > dev_info->end - dev_info->start)
- return -ERANGE;
- *kaddr = (void *) (dev_info->start+pgoff*PAGE_SIZE);
+ dev_sz = dev_info->end - dev_info->start;
+ offset = secnum * 512;
+ *kaddr = (void *) (dev_info->start + offset);
*pfn = virt_to_phys(*kaddr) >> PAGE_SHIFT;
- return 0;
+ return dev_sz - offset;
}
static void
diff --git a/drivers/s390/char/hmcdrv_ftp.c b/drivers/s390/char/hmcdrv_ftp.c
index 4bd63322fc29..d4b61d9088fb 100644
--- a/drivers/s390/char/hmcdrv_ftp.c
+++ b/drivers/s390/char/hmcdrv_ftp.c
@@ -200,10 +200,9 @@ int hmcdrv_ftp_probe(void)
rc = hmcdrv_ftp_startup();
if (rc)
- return rc;
+ goto out;
rc = hmcdrv_ftp_do(&ftp);
- free_page((unsigned long) ftp.buf);
hmcdrv_ftp_shutdown();
switch (rc) {
@@ -216,7 +215,8 @@ int hmcdrv_ftp_probe(void)
rc = 0; /* clear length (success) */
break;
} /* switch */
-
+out:
+ free_page((unsigned long) ftp.buf);
return rc;
}
EXPORT_SYMBOL(hmcdrv_ftp_probe);
diff --git a/drivers/s390/char/hmcdrv_mod.c b/drivers/s390/char/hmcdrv_mod.c
index 505c6a78ee1a..251a318a9b75 100644
--- a/drivers/s390/char/hmcdrv_mod.c
+++ b/drivers/s390/char/hmcdrv_mod.c
@@ -11,7 +11,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
-#include <linux/version.h>
#include <linux/stat.h>
#include "hmcdrv_ftp.h"
diff --git a/drivers/s390/char/sclp_early.c b/drivers/s390/char/sclp_early.c
index 5bd6cb145a87..1efa4fdb7fe2 100644
--- a/drivers/s390/char/sclp_early.c
+++ b/drivers/s390/char/sclp_early.c
@@ -20,26 +20,31 @@ struct read_info_sccb {
struct sccb_header header; /* 0-7 */
u16 rnmax; /* 8-9 */
u8 rnsize; /* 10 */
- u8 _reserved0[16 - 11]; /* 11-15 */
+ u8 _pad_11[16 - 11]; /* 11-15 */
u16 ncpurl; /* 16-17 */
u16 cpuoff; /* 18-19 */
- u8 _reserved7[24 - 20]; /* 20-23 */
+ u8 _pad_20[24 - 20]; /* 20-23 */
u8 loadparm[8]; /* 24-31 */
- u8 _reserved1[48 - 32]; /* 32-47 */
+ u8 _pad_32[42 - 32]; /* 32-41 */
+ u8 fac42; /* 42 */
+ u8 fac43; /* 43 */
+ u8 _pad_44[48 - 44]; /* 44-47 */
u64 facilities; /* 48-55 */
- u8 _reserved2a[76 - 56]; /* 56-75 */
+ u8 _pad_56[66 - 56]; /* 56-65 */
+ u8 fac66; /* 66 */
+ u8 _pad_67[76 - 67]; /* 67-83 */
u32 ibc; /* 76-79 */
- u8 _reserved2b[84 - 80]; /* 80-83 */
+ u8 _pad80[84 - 80]; /* 80-83 */
u8 fac84; /* 84 */
u8 fac85; /* 85 */
- u8 _reserved3[91 - 86]; /* 86-90 */
+ u8 _pad_86[91 - 86]; /* 86-90 */
u8 flags; /* 91 */
- u8 _reserved4[100 - 92]; /* 92-99 */
+ u8 _pad_92[100 - 92]; /* 92-99 */
u32 rnsize2; /* 100-103 */
u64 rnmax2; /* 104-111 */
- u8 _reserved5[120 - 112]; /* 112-119 */
+ u8 _pad_112[120 - 112]; /* 112-119 */
u16 hcpua; /* 120-121 */
- u8 _reserved6[4096 - 122]; /* 122-4095 */
+ u8 _pad_122[4096 - 122]; /* 122-4095 */
} __packed __aligned(PAGE_SIZE);
static char sccb_early[PAGE_SIZE] __aligned(PAGE_SIZE) __initdata;
@@ -49,7 +54,12 @@ static unsigned long sclp_hsa_size;
static unsigned int sclp_max_cpu;
static struct sclp_ipl_info sclp_ipl_info;
static unsigned char sclp_siif;
+static unsigned char sclp_sigpif;
static u32 sclp_ibc;
+static unsigned int sclp_mtid;
+static unsigned int sclp_mtid_cp;
+static unsigned int sclp_mtid_max;
+static unsigned int sclp_mtid_prev;
u64 sclp_facilities;
u8 sclp_fac84;
@@ -128,9 +138,10 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
boot_cpu_address = stap();
cpue = (void *)sccb + sccb->cpuoff;
for (cpu = 0; cpu < sccb->ncpurl; cpue++, cpu++) {
- if (boot_cpu_address != cpue->address)
+ if (boot_cpu_address != cpue->core_id)
continue;
sclp_siif = cpue->siif;
+ sclp_sigpif = cpue->sigpif;
break;
}
@@ -139,6 +150,11 @@ static void __init sclp_facilities_detect(struct read_info_sccb *sccb)
if (sccb->flags & 0x2)
sclp_ipl_info.has_dump = 1;
memcpy(&sclp_ipl_info.loadparm, &sccb->loadparm, LOADPARM_LEN);
+
+ sclp_mtid = (sccb->fac42 & 0x80) ? (sccb->fac42 & 31) : 0;
+ sclp_mtid_cp = (sccb->fac42 & 0x80) ? (sccb->fac43 & 31) : 0;
+ sclp_mtid_max = max(sclp_mtid, sclp_mtid_cp);
+ sclp_mtid_prev = (sccb->fac42 & 0x80) ? (sccb->fac66 & 31) : 0;
}
bool __init sclp_has_linemode(void)
@@ -172,12 +188,33 @@ int sclp_has_siif(void)
}
EXPORT_SYMBOL(sclp_has_siif);
+int sclp_has_sigpif(void)
+{
+ return sclp_sigpif;
+}
+EXPORT_SYMBOL(sclp_has_sigpif);
+
unsigned int sclp_get_ibc(void)
{
return sclp_ibc;
}
EXPORT_SYMBOL(sclp_get_ibc);
+unsigned int sclp_get_mtid(u8 cpu_type)
+{
+ return cpu_type ? sclp_mtid : sclp_mtid_cp;
+}
+
+unsigned int sclp_get_mtid_max(void)
+{
+ return sclp_mtid_max;
+}
+
+unsigned int sclp_get_mtid_prev(void)
+{
+ return sclp_mtid_prev;
+}
+
/*
* This function will be called after sclp_facilities_detect(), which gets
* called from early.c code. The sclp_facilities_detect() function retrieves
diff --git a/drivers/s390/char/tape_34xx.c b/drivers/s390/char/tape_34xx.c
index 9aa79702b370..de69f0ddc321 100644
--- a/drivers/s390/char/tape_34xx.c
+++ b/drivers/s390/char/tape_34xx.c
@@ -773,13 +773,11 @@ tape_34xx_unit_check(struct tape_device *device, struct tape_request *request,
"occurred\n");
return tape_34xx_erp_failed(request, -EIO);
case 0x57:
- if (device->cdev->id.driver_info == tape_3480) {
- /* Attention intercept. */
- return tape_34xx_erp_retry(request);
- } else {
- /* Global status intercept. */
- return tape_34xx_erp_retry(request);
- }
+ /*
+ * 3480: Attention intercept.
+ * 3490: Global status intercept.
+ */
+ return tape_34xx_erp_retry(request);
case 0x5a:
/*
* Tape length incompatible. The tape inserted is too long,
diff --git a/drivers/s390/cio/cio.c b/drivers/s390/cio/cio.c
index 10eb738fc81a..3578105989a0 100644
--- a/drivers/s390/cio/cio.c
+++ b/drivers/s390/cio/cio.c
@@ -938,7 +938,7 @@ void reipl_ccw_dev(struct ccw_dev_id *devid)
{
struct subchannel_id uninitialized_var(schid);
- s390_reset_system(NULL, NULL);
+ s390_reset_system(NULL, NULL, NULL);
if (reipl_find_schid(devid, &schid) != 0)
panic("IPL Device not found\n");
do_reipl_asm(*((__u32*)&schid));
diff --git a/drivers/s390/cio/idset.c b/drivers/s390/cio/idset.c
index 5a999084a229..b3e06a7b9480 100644
--- a/drivers/s390/cio/idset.c
+++ b/drivers/s390/cio/idset.c
@@ -38,11 +38,6 @@ void idset_free(struct idset *set)
vfree(set);
}
-void idset_clear(struct idset *set)
-{
- memset(set->bitmap, 0, bitmap_size(set->num_ssid, set->num_id));
-}
-
void idset_fill(struct idset *set)
{
memset(set->bitmap, 0xff, bitmap_size(set->num_ssid, set->num_id));
@@ -103,21 +98,6 @@ int idset_sch_contains(struct idset *set, struct subchannel_id schid)
return idset_contains(set, schid.ssid, schid.sch_no);
}
-int idset_sch_get_first(struct idset *set, struct subchannel_id *schid)
-{
- int ssid = 0;
- int id = 0;
- int rc;
-
- rc = idset_get_first(set, &ssid, &id);
- if (rc) {
- init_subchannel_id(schid);
- schid->ssid = ssid;
- schid->sch_no = id;
- }
- return rc;
-}
-
int idset_is_empty(struct idset *set)
{
return bitmap_empty(set->bitmap, set->num_ssid * set->num_id);
diff --git a/drivers/s390/cio/idset.h b/drivers/s390/cio/idset.h
index 06d3bc01bb09..22b58104683b 100644
--- a/drivers/s390/cio/idset.h
+++ b/drivers/s390/cio/idset.h
@@ -11,7 +11,6 @@
struct idset;
void idset_free(struct idset *set);
-void idset_clear(struct idset *set);
void idset_fill(struct idset *set);
struct idset *idset_sch_new(void);
@@ -19,7 +18,6 @@ void idset_sch_add(struct idset *set, struct subchannel_id id);
void idset_sch_del(struct idset *set, struct subchannel_id id);
void idset_sch_del_subseq(struct idset *set, struct subchannel_id schid);
int idset_sch_contains(struct idset *set, struct subchannel_id id);
-int idset_sch_get_first(struct idset *set, struct subchannel_id *id);
int idset_is_empty(struct idset *set);
void idset_add_set(struct idset *to, struct idset *from);
diff --git a/drivers/s390/crypto/ap_bus.c b/drivers/s390/crypto/ap_bus.c
index 4d41bf75c233..3d7f19fb9a4e 100644
--- a/drivers/s390/crypto/ap_bus.c
+++ b/drivers/s390/crypto/ap_bus.c
@@ -204,6 +204,24 @@ ap_test_queue(ap_qid_t qid, int *queue_depth, int *device_type)
}
/**
+ * ap_query_facilities(): PQAP(TAPQ) query facilities.
+ * @qid: The AP queue number
+ *
+ * Returns content of general register 2 after the PQAP(TAPQ)
+ * instruction was called.
+ */
+static inline unsigned long ap_query_facilities(ap_qid_t qid)
+{
+ register unsigned long reg0 asm ("0") = qid | 0x00800000UL;
+ register unsigned long reg1 asm ("1");
+ register unsigned long reg2 asm ("2") = 0UL;
+
+ asm volatile(".long 0xb2af0000" /* PQAP(TAPQ) */
+ : "+d" (reg0), "=d" (reg1), "+d" (reg2) : : "cc");
+ return reg2;
+}
+
+/**
* ap_reset_queue(): Reset adjunct processor queue.
* @qid: The AP queue number
*
@@ -1007,6 +1025,51 @@ void ap_bus_force_rescan(void)
EXPORT_SYMBOL(ap_bus_force_rescan);
/*
+ * ap_test_config(): helper function to extract the nrth bit
+ * within the unsigned int array field.
+ */
+static inline int ap_test_config(unsigned int *field, unsigned int nr)
+{
+ if (nr > 0xFFu)
+ return 0;
+ return ap_test_bit((field + (nr >> 5)), (nr & 0x1f));
+}
+
+/*
+ * ap_test_config_card_id(): Test, whether an AP card ID is configured.
+ * @id AP card ID
+ *
+ * Returns 0 if the card is not configured
+ * 1 if the card is configured or
+ * if the configuration information is not available
+ */
+static inline int ap_test_config_card_id(unsigned int id)
+{
+ if (!ap_configuration)
+ return 1;
+ return ap_test_config(ap_configuration->apm, id);
+}
+
+/*
+ * ap_test_config_domain(): Test, whether an AP usage domain is configured.
+ * @domain AP usage domain ID
+ *
+ * Returns 0 if the usage domain is not configured
+ * 1 if the usage domain is configured or
+ * if the configuration information is not available
+ */
+static inline int ap_test_config_domain(unsigned int domain)
+{
+ if (!ap_configuration) /* QCI not supported */
+ if (domain < 16)
+ return 1; /* then domains 0...15 are configured */
+ else
+ return 0;
+ else
+ return ap_test_config(ap_configuration->aqm, domain);
+}
+
+/*
* AP bus attributes.
*/
static ssize_t ap_domain_show(struct bus_type *bus, char *buf)
@@ -1121,6 +1184,42 @@ static ssize_t poll_timeout_store(struct bus_type *bus, const char *buf,
static BUS_ATTR(poll_timeout, 0644, poll_timeout_show, poll_timeout_store);
+static ssize_t ap_max_domain_id_show(struct bus_type *bus, char *buf)
+{
+ ap_qid_t qid;
+ int i, nd, max_domain_id = -1;
+ unsigned long fbits;
+
+ if (ap_configuration) {
+ if (ap_domain_index >= 0 && ap_domain_index < AP_DOMAINS) {
+ for (i = 0; i < AP_DEVICES; i++) {
+ if (!ap_test_config_card_id(i))
+ continue;
+ qid = AP_MKQID(i, ap_domain_index);
+ fbits = ap_query_facilities(qid);
+ if (fbits & (1UL << 57)) {
+ /* the N bit is 0, Nd field is filled */
+ nd = (int)((fbits & 0x00FF0000UL)>>16);
+ if (nd > 0)
+ max_domain_id = nd;
+ else
+ max_domain_id = 15;
+ } else {
+ /* N bit is 1, max 16 domains */
+ max_domain_id = 15;
+ }
+ break;
+ }
+ }
+ } else {
+ /* no APXA support, older machines with max 16 domains */
+ max_domain_id = 15;
+ }
+ return snprintf(buf, PAGE_SIZE, "%d\n", max_domain_id);
+}
+
+static BUS_ATTR(ap_max_domain_id, 0444, ap_max_domain_id_show, NULL);
+
static struct bus_attribute *const ap_bus_attrs[] = {
&bus_attr_ap_domain,
&bus_attr_ap_control_domain_mask,
@@ -1128,50 +1227,10 @@ static struct bus_attribute *const ap_bus_attrs[] = {
&bus_attr_poll_thread,
&bus_attr_ap_interrupts,
&bus_attr_poll_timeout,
+ &bus_attr_ap_max_domain_id,
NULL,
};
-static inline int ap_test_config(unsigned int *field, unsigned int nr)
-{
- if (nr > 0xFFu)
- return 0;
- return ap_test_bit((field + (nr >> 5)), (nr & 0x1f));
-}
-
-/*
- * ap_test_config_card_id(): Test, whether an AP card ID is configured.
- * @id AP card ID
- *
- * Returns 0 if the card is not configured
- * 1 if the card is configured or
- * if the configuration information is not available
- */
-static inline int ap_test_config_card_id(unsigned int id)
-{
- if (!ap_configuration)
- return 1;
- return ap_test_config(ap_configuration->apm, id);
-}
-
-/*
- * ap_test_config_domain(): Test, whether an AP usage domain is configured.
- * @domain AP usage domain ID
- *
- * Returns 0 if the usage domain is not configured
- * 1 if the usage domain is configured or
- * if the configuration information is not available
- */
-static inline int ap_test_config_domain(unsigned int domain)
-{
- if (!ap_configuration) /* QCI not supported */
- if (domain < 16)
- return 1; /* then domains 0...15 are configured */
- else
- return 0;
- else
- return ap_test_config(ap_configuration->aqm, domain);
-}
-
/**
* ap_query_configuration(): Query AP configuration information.
*
@@ -1434,9 +1493,6 @@ static void ap_scan_bus(struct work_struct *unused)
continue;
}
break;
- case 11:
- ap_dev->device_type = 10;
- break;
default:
ap_dev->device_type = device_type;
}
diff --git a/drivers/s390/crypto/ap_bus.h b/drivers/s390/crypto/ap_bus.h
index 055a0f956d17..2737d261a324 100644
--- a/drivers/s390/crypto/ap_bus.h
+++ b/drivers/s390/crypto/ap_bus.h
@@ -117,6 +117,7 @@ static inline int ap_test_bit(unsigned int *ptr, unsigned int nr)
#define AP_DEVICE_TYPE_CEX3A 8
#define AP_DEVICE_TYPE_CEX3C 9
#define AP_DEVICE_TYPE_CEX4 10
+#define AP_DEVICE_TYPE_CEX5 11
/*
* Known function facilities
diff --git a/drivers/s390/crypto/zcrypt_api.h b/drivers/s390/crypto/zcrypt_api.h
index b3d496bfaa7e..750876891931 100644
--- a/drivers/s390/crypto/zcrypt_api.h
+++ b/drivers/s390/crypto/zcrypt_api.h
@@ -75,6 +75,7 @@ struct ica_z90_status {
#define ZCRYPT_CEX3C 7
#define ZCRYPT_CEX3A 8
#define ZCRYPT_CEX4 10
+#define ZCRYPT_CEX5 11
/**
* Large random numbers are pulled in 4096 byte chunks from the crypto cards
diff --git a/drivers/s390/crypto/zcrypt_cex4.c b/drivers/s390/crypto/zcrypt_cex4.c
index 569f8b1d86c0..71e698b85772 100644
--- a/drivers/s390/crypto/zcrypt_cex4.c
+++ b/drivers/s390/crypto/zcrypt_cex4.c
@@ -26,6 +26,10 @@
#define CEX4A_SPEED_RATING 900 /* TODO new card, new speed rating */
#define CEX4C_SPEED_RATING 6500 /* TODO new card, new speed rating */
+#define CEX4P_SPEED_RATING 7000 /* TODO new card, new speed rating */
+#define CEX5A_SPEED_RATING 450 /* TODO new card, new speed rating */
+#define CEX5C_SPEED_RATING 3250 /* TODO new card, new speed rating */
+#define CEX5P_SPEED_RATING 3500 /* TODO new card, new speed rating */
#define CEX4A_MAX_MESSAGE_SIZE MSGTYPE50_CRB3_MAX_MSG_SIZE
#define CEX4C_MAX_MESSAGE_SIZE MSGTYPE06_MAX_MSG_SIZE
@@ -39,6 +43,7 @@
static struct ap_device_id zcrypt_cex4_ids[] = {
{ AP_DEVICE(AP_DEVICE_TYPE_CEX4) },
+ { AP_DEVICE(AP_DEVICE_TYPE_CEX5) },
{ /* end of list */ },
};
@@ -70,11 +75,18 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
switch (ap_dev->device_type) {
case AP_DEVICE_TYPE_CEX4:
+ case AP_DEVICE_TYPE_CEX5:
if (ap_test_bit(&ap_dev->functions, AP_FUNC_ACCEL)) {
zdev = zcrypt_device_alloc(CEX4A_MAX_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
- zdev->type_string = "CEX4A";
+ if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
+ zdev->type_string = "CEX4A";
+ zdev->speed_rating = CEX4A_SPEED_RATING;
+ } else {
+ zdev->type_string = "CEX5A";
+ zdev->speed_rating = CEX5A_SPEED_RATING;
+ }
zdev->user_space_type = ZCRYPT_CEX3A;
zdev->min_mod_size = CEX4A_MIN_MOD_SIZE;
if (ap_test_bit(&ap_dev->functions, AP_FUNC_MEX4K) &&
@@ -90,33 +102,42 @@ static int zcrypt_cex4_probe(struct ap_device *ap_dev)
CEX4A_MAX_MOD_SIZE_2K;
}
zdev->short_crt = 1;
- zdev->speed_rating = CEX4A_SPEED_RATING;
zdev->ops = zcrypt_msgtype_request(MSGTYPE50_NAME,
MSGTYPE50_VARIANT_DEFAULT);
} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_COPRO)) {
zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
- zdev->type_string = "CEX4C";
+ if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
+ zdev->type_string = "CEX4C";
+ zdev->speed_rating = CEX4C_SPEED_RATING;
+ } else {
+ zdev->type_string = "CEX5C";
+ zdev->speed_rating = CEX5C_SPEED_RATING;
+ }
zdev->user_space_type = ZCRYPT_CEX3C;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
zdev->short_crt = 0;
- zdev->speed_rating = CEX4C_SPEED_RATING;
zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_DEFAULT);
} else if (ap_test_bit(&ap_dev->functions, AP_FUNC_EP11)) {
zdev = zcrypt_device_alloc(CEX4C_MAX_MESSAGE_SIZE);
if (!zdev)
return -ENOMEM;
- zdev->type_string = "CEX4P";
+ if (ap_dev->device_type == AP_DEVICE_TYPE_CEX4) {
+ zdev->type_string = "CEX4P";
+ zdev->speed_rating = CEX4P_SPEED_RATING;
+ } else {
+ zdev->type_string = "CEX5P";
+ zdev->speed_rating = CEX5P_SPEED_RATING;
+ }
zdev->user_space_type = ZCRYPT_CEX4;
zdev->min_mod_size = CEX4C_MIN_MOD_SIZE;
zdev->max_mod_size = CEX4C_MAX_MOD_SIZE;
zdev->max_exp_bit_length = CEX4C_MAX_MOD_SIZE;
zdev->short_crt = 0;
- zdev->speed_rating = CEX4C_SPEED_RATING;
zdev->ops = zcrypt_msgtype_request(MSGTYPE06_NAME,
MSGTYPE06_VARIANT_EP11);
}
diff --git a/drivers/s390/net/claw.c b/drivers/s390/net/claw.c
index 213e54ee8a66..d609ca09aa94 100644
--- a/drivers/s390/net/claw.c
+++ b/drivers/s390/net/claw.c
@@ -109,10 +109,8 @@ static debug_info_t *claw_dbf_trace;
static void
claw_unregister_debug_facility(void)
{
- if (claw_dbf_setup)
- debug_unregister(claw_dbf_setup);
- if (claw_dbf_trace)
- debug_unregister(claw_dbf_trace);
+ debug_unregister(claw_dbf_setup);
+ debug_unregister(claw_dbf_trace);
}
static int
diff --git a/drivers/s390/net/ctcm_fsms.c b/drivers/s390/net/ctcm_fsms.c
index fb92524d24ef..fd5944bbe224 100644
--- a/drivers/s390/net/ctcm_fsms.c
+++ b/drivers/s390/net/ctcm_fsms.c
@@ -251,13 +251,11 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg)
int first = 1;
int i;
unsigned long duration;
- struct timespec done_stamp = current_kernel_time(); /* xtime */
+ unsigned long done_stamp = jiffies;
CTCM_PR_DEBUG("%s(%s): %s\n", __func__, ch->id, dev->name);
- duration =
- (done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 +
- (done_stamp.tv_nsec - ch->prof.send_stamp.tv_nsec) / 1000;
+ duration = done_stamp - ch->prof.send_stamp;
if (duration > ch->prof.tx_time)
ch->prof.tx_time = duration;
@@ -307,7 +305,7 @@ static void chx_txdone(fsm_instance *fi, int event, void *arg)
spin_unlock(&ch->collect_lock);
ch->ccw[1].count = ch->trans_skb->len;
fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
- ch->prof.send_stamp = current_kernel_time(); /* xtime */
+ ch->prof.send_stamp = jiffies;
rc = ccw_device_start(ch->cdev, &ch->ccw[0],
(unsigned long)ch, 0xff, 0);
ch->prof.doios_multi++;
@@ -1229,14 +1227,12 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
int rc;
struct th_header *header;
struct pdu *p_header;
- struct timespec done_stamp = current_kernel_time(); /* xtime */
+ unsigned long done_stamp = jiffies;
CTCM_PR_DEBUG("Enter %s: %s cp:%i\n",
__func__, dev->name, smp_processor_id());
- duration =
- (done_stamp.tv_sec - ch->prof.send_stamp.tv_sec) * 1000000 +
- (done_stamp.tv_nsec - ch->prof.send_stamp.tv_nsec) / 1000;
+ duration = done_stamp - ch->prof.send_stamp;
if (duration > ch->prof.tx_time)
ch->prof.tx_time = duration;
@@ -1361,7 +1357,7 @@ static void ctcmpc_chx_txdone(fsm_instance *fi, int event, void *arg)
ch->ccw[1].count = ch->trans_skb->len;
fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
- ch->prof.send_stamp = current_kernel_time(); /* xtime */
+ ch->prof.send_stamp = jiffies;
if (do_debug_ccw)
ctcmpc_dumpit((char *)&ch->ccw[0], sizeof(struct ccw1) * 3);
rc = ccw_device_start(ch->cdev, &ch->ccw[0],
@@ -1827,7 +1823,7 @@ static void ctcmpc_chx_send_sweep(fsm_instance *fsm, int event, void *arg)
fsm_newstate(wch->fsm, CTC_STATE_TX);
spin_lock_irqsave(get_ccwdev_lock(wch->cdev), saveflags);
- wch->prof.send_stamp = current_kernel_time(); /* xtime */
+ wch->prof.send_stamp = jiffies;
rc = ccw_device_start(wch->cdev, &wch->ccw[3],
(unsigned long) wch, 0xff, 0);
spin_unlock_irqrestore(get_ccwdev_lock(wch->cdev), saveflags);
diff --git a/drivers/s390/net/ctcm_main.c b/drivers/s390/net/ctcm_main.c
index e056dd4fe44d..05c37d6d4afe 100644
--- a/drivers/s390/net/ctcm_main.c
+++ b/drivers/s390/net/ctcm_main.c
@@ -567,7 +567,7 @@ static int ctcm_transmit_skb(struct channel *ch, struct sk_buff *skb)
fsm_newstate(ch->fsm, CTC_STATE_TX);
fsm_addtimer(&ch->timer, CTCM_TIME_5_SEC, CTC_EVENT_TIMER, ch);
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
- ch->prof.send_stamp = current_kernel_time(); /* xtime */
+ ch->prof.send_stamp = jiffies;
rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx],
(unsigned long)ch, 0xff, 0);
spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
@@ -831,7 +831,7 @@ static int ctcmpc_transmit_skb(struct channel *ch, struct sk_buff *skb)
sizeof(struct ccw1) * 3);
spin_lock_irqsave(get_ccwdev_lock(ch->cdev), saveflags);
- ch->prof.send_stamp = current_kernel_time(); /* xtime */
+ ch->prof.send_stamp = jiffies;
rc = ccw_device_start(ch->cdev, &ch->ccw[ccw_idx],
(unsigned long)ch, 0xff, 0);
spin_unlock_irqrestore(get_ccwdev_lock(ch->cdev), saveflags);
diff --git a/drivers/s390/net/ctcm_main.h b/drivers/s390/net/ctcm_main.h
index 477c933685f3..6f4417c80247 100644
--- a/drivers/s390/net/ctcm_main.h
+++ b/drivers/s390/net/ctcm_main.h
@@ -121,7 +121,7 @@ struct ctcm_profile {
unsigned long doios_multi;
unsigned long txlen;
unsigned long tx_time;
- struct timespec send_stamp;
+ unsigned long send_stamp;
};
/*
diff --git a/drivers/s390/net/ctcm_sysfs.c b/drivers/s390/net/ctcm_sysfs.c
index 47773c4d235a..ddb0aa321339 100644
--- a/drivers/s390/net/ctcm_sysfs.c
+++ b/drivers/s390/net/ctcm_sysfs.c
@@ -100,8 +100,8 @@ static void ctcm_print_statistics(struct ctcm_priv *priv)
priv->channel[WRITE]->prof.doios_multi);
p += sprintf(p, " Netto bytes written: %ld\n",
priv->channel[WRITE]->prof.txlen);
- p += sprintf(p, " Max. TX IO-time: %ld\n",
- priv->channel[WRITE]->prof.tx_time);
+ p += sprintf(p, " Max. TX IO-time: %u\n",
+ jiffies_to_usecs(priv->channel[WRITE]->prof.tx_time));
printk(KERN_INFO "Statistics for %s:\n%s",
priv->channel[CTCM_WRITE]->netdev->name, sbuf);
diff --git a/drivers/s390/net/lcs.c b/drivers/s390/net/lcs.c
index 92190aa20b9f..00b7d9c9fe48 100644
--- a/drivers/s390/net/lcs.c
+++ b/drivers/s390/net/lcs.c
@@ -88,10 +88,8 @@ static debug_info_t *lcs_dbf_trace;
static void
lcs_unregister_debug_facility(void)
{
- if (lcs_dbf_setup)
- debug_unregister(lcs_dbf_setup);
- if (lcs_dbf_trace)
- debug_unregister(lcs_dbf_trace);
+ debug_unregister(lcs_dbf_setup);
+ debug_unregister(lcs_dbf_trace);
}
static int
diff --git a/drivers/s390/net/netiucv.c b/drivers/s390/net/netiucv.c
index 0a87809c8af7..33f7040d711d 100644
--- a/drivers/s390/net/netiucv.c
+++ b/drivers/s390/net/netiucv.c
@@ -178,7 +178,7 @@ struct connection_profile {
unsigned long doios_multi;
unsigned long txlen;
unsigned long tx_time;
- struct timespec send_stamp;
+ unsigned long send_stamp;
unsigned long tx_pending;
unsigned long tx_max_pending;
};
@@ -487,12 +487,9 @@ DEFINE_PER_CPU(char[256], iucv_dbf_txt_buf);
static void iucv_unregister_dbf_views(void)
{
- if (iucv_dbf_setup)
- debug_unregister(iucv_dbf_setup);
- if (iucv_dbf_data)
- debug_unregister(iucv_dbf_data);
- if (iucv_dbf_trace)
- debug_unregister(iucv_dbf_trace);
+ debug_unregister(iucv_dbf_setup);
+ debug_unregister(iucv_dbf_data);
+ debug_unregister(iucv_dbf_trace);
}
static int iucv_register_dbf_views(void)
{
@@ -786,7 +783,7 @@ static void conn_action_txdone(fsm_instance *fi, int event, void *arg)
header.next = 0;
memcpy(skb_put(conn->tx_buff, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
- conn->prof.send_stamp = current_kernel_time();
+ conn->prof.send_stamp = jiffies;
txmsg.class = 0;
txmsg.tag = 0;
rc = iucv_message_send(conn->path, &txmsg, 0, 0,
@@ -1220,7 +1217,7 @@ static int netiucv_transmit_skb(struct iucv_connection *conn,
memcpy(skb_put(nskb, NETIUCV_HDRLEN), &header, NETIUCV_HDRLEN);
fsm_newstate(conn->fsm, CONN_STATE_TX);
- conn->prof.send_stamp = current_kernel_time();
+ conn->prof.send_stamp = jiffies;
msg.tag = 1;
msg.class = 0;
diff --git a/drivers/s390/net/qeth_core.h b/drivers/s390/net/qeth_core.h
index 7a8bb9f78e76..3abac028899f 100644
--- a/drivers/s390/net/qeth_core.h
+++ b/drivers/s390/net/qeth_core.h
@@ -596,7 +596,6 @@ struct qeth_channel {
struct ccw1 ccw;
spinlock_t iob_lock;
wait_queue_head_t wait_q;
- struct tasklet_struct irq_tasklet;
struct ccw_device *ccwdev;
/*command buffer for control data*/
struct qeth_cmd_buffer iob[QETH_CMD_BUFFER_NO];
diff --git a/drivers/s390/net/qeth_core_sys.c b/drivers/s390/net/qeth_core_sys.c
index 15523f0e4c03..423bec56cffa 100644
--- a/drivers/s390/net/qeth_core_sys.c
+++ b/drivers/s390/net/qeth_core_sys.c
@@ -231,7 +231,6 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
- char *tmp;
int rc = 0;
if (!card)
@@ -253,36 +252,35 @@ static ssize_t qeth_dev_prioqing_store(struct device *dev,
goto out;
}
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "prio_queueing_prec")) {
+ if (sysfs_streq(buf, "prio_queueing_prec")) {
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_PREC;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
- } else if (!strcmp(tmp, "prio_queueing_skb")) {
+ } else if (sysfs_streq(buf, "prio_queueing_skb")) {
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_SKB;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
- } else if (!strcmp(tmp, "prio_queueing_tos")) {
+ } else if (sysfs_streq(buf, "prio_queueing_tos")) {
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_TOS;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
- } else if (!strcmp(tmp, "prio_queueing_vlan")) {
+ } else if (sysfs_streq(buf, "prio_queueing_vlan")) {
if (!card->options.layer2) {
rc = -ENOTSUPP;
goto out;
}
card->qdio.do_prio_queueing = QETH_PRIO_Q_ING_VLAN;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
- } else if (!strcmp(tmp, "no_prio_queueing:0")) {
+ } else if (sysfs_streq(buf, "no_prio_queueing:0")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 0;
- } else if (!strcmp(tmp, "no_prio_queueing:1")) {
+ } else if (sysfs_streq(buf, "no_prio_queueing:1")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 1;
- } else if (!strcmp(tmp, "no_prio_queueing:2")) {
+ } else if (sysfs_streq(buf, "no_prio_queueing:2")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 2;
- } else if (!strcmp(tmp, "no_prio_queueing:3")) {
+ } else if (sysfs_streq(buf, "no_prio_queueing:3")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = 3;
- } else if (!strcmp(tmp, "no_prio_queueing")) {
+ } else if (sysfs_streq(buf, "no_prio_queueing")) {
card->qdio.do_prio_queueing = QETH_NO_PRIO_QUEUEING;
card->qdio.default_out_queue = QETH_DEFAULT_QUEUE;
} else
@@ -497,8 +495,6 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
struct qeth_card *card = dev_get_drvdata(dev);
enum qeth_ipa_isolation_modes isolation;
int rc = 0;
- char *tmp, *curtoken;
- curtoken = (char *) buf;
if (!card)
return -EINVAL;
@@ -515,12 +511,11 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
}
/* parse input into isolation mode */
- tmp = strsep(&curtoken, "\n");
- if (!strcmp(tmp, ATTR_QETH_ISOLATION_NONE)) {
+ if (sysfs_streq(buf, ATTR_QETH_ISOLATION_NONE)) {
isolation = ISOLATION_MODE_NONE;
- } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_FWD)) {
+ } else if (sysfs_streq(buf, ATTR_QETH_ISOLATION_FWD)) {
isolation = ISOLATION_MODE_FWD;
- } else if (!strcmp(tmp, ATTR_QETH_ISOLATION_DROP)) {
+ } else if (sysfs_streq(buf, ATTR_QETH_ISOLATION_DROP)) {
isolation = ISOLATION_MODE_DROP;
} else {
rc = -EINVAL;
@@ -531,8 +526,7 @@ static ssize_t qeth_dev_isolation_store(struct device *dev,
/* defer IP assist if device is offline (until discipline->set_online)*/
card->options.prev_isolation = card->options.isolation;
card->options.isolation = isolation;
- if (card->state == CARD_STATE_SOFTSETUP ||
- card->state == CARD_STATE_UP) {
+ if (qeth_card_hw_is_reachable(card)) {
int ipa_rc = qeth_set_access_ctrl_online(card, 1);
if (ipa_rc != 0)
rc = ipa_rc;
@@ -555,7 +549,7 @@ static ssize_t qeth_dev_switch_attrs_show(struct device *dev,
if (!card)
return -EINVAL;
- if (card->state != CARD_STATE_SOFTSETUP && card->state != CARD_STATE_UP)
+ if (!qeth_card_hw_is_reachable(card))
return sprintf(buf, "n/a\n");
rc = qeth_query_switch_attributes(card, &sw_info);
@@ -598,19 +592,16 @@ static ssize_t qeth_hw_trap_store(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
int rc = 0;
- char *tmp, *curtoken;
int state = 0;
- curtoken = (char *)buf;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
- if (card->state == CARD_STATE_SOFTSETUP || card->state == CARD_STATE_UP)
+ if (qeth_card_hw_is_reachable(card))
state = 1;
- tmp = strsep(&curtoken, "\n");
- if (!strcmp(tmp, "arm") && !card->info.hwtrap) {
+ if (sysfs_streq(buf, "arm") && !card->info.hwtrap) {
if (state) {
if (qeth_is_diagass_supported(card,
QETH_DIAGS_CMD_TRAP)) {
@@ -621,14 +612,14 @@ static ssize_t qeth_hw_trap_store(struct device *dev,
rc = -EINVAL;
} else
card->info.hwtrap = 1;
- } else if (!strcmp(tmp, "disarm") && card->info.hwtrap) {
+ } else if (sysfs_streq(buf, "disarm") && card->info.hwtrap) {
if (state) {
rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_DISARM);
if (!rc)
card->info.hwtrap = 0;
} else
card->info.hwtrap = 0;
- } else if (!strcmp(tmp, "trap") && state && card->info.hwtrap)
+ } else if (sysfs_streq(buf, "trap") && state && card->info.hwtrap)
rc = qeth_hw_trap(card, QETH_DIAGS_TRAP_CAPTURE);
else
rc = -EINVAL;
diff --git a/drivers/s390/net/qeth_l2_main.c b/drivers/s390/net/qeth_l2_main.c
index ce87ae72edbd..0ea0869120cf 100644
--- a/drivers/s390/net/qeth_l2_main.c
+++ b/drivers/s390/net/qeth_l2_main.c
@@ -45,8 +45,7 @@ static int qeth_l2_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!card)
return -ENODEV;
- if ((card->state != CARD_STATE_UP) &&
- (card->state != CARD_STATE_SOFTSETUP))
+ if (!qeth_card_hw_is_reachable(card))
return -ENODEV;
if (card->info.type == QETH_CARD_TYPE_OSN)
@@ -1336,8 +1335,7 @@ int qeth_osn_assist(struct net_device *dev, void *data, int data_len)
if (!card)
return -ENODEV;
QETH_CARD_TEXT(card, 2, "osnsdmc");
- if ((card->state != CARD_STATE_UP) &&
- (card->state != CARD_STATE_SOFTSETUP))
+ if (!qeth_card_hw_is_reachable(card))
return -ENODEV;
iob = qeth_wait_for_buffer(&card->write);
memcpy(iob->data+IPA_PDU_HEADER_SIZE, data, data_len);
diff --git a/drivers/s390/net/qeth_l3_main.c b/drivers/s390/net/qeth_l3_main.c
index e2a0ee845399..04e42c649134 100644
--- a/drivers/s390/net/qeth_l3_main.c
+++ b/drivers/s390/net/qeth_l3_main.c
@@ -432,10 +432,8 @@ void qeth_l3_set_ip_addr_list(struct qeth_card *card)
QETH_CARD_TEXT(card, 2, "sdiplist");
QETH_CARD_HEX(card, 2, &card, sizeof(void *));
- if ((card->state != CARD_STATE_UP &&
- card->state != CARD_STATE_SOFTSETUP) || card->options.sniffer) {
+ if (!qeth_card_hw_is_reachable(card) || card->options.sniffer)
return;
- }
spin_lock_irqsave(&card->ip_lock, flags);
tbd_list = card->ip_tbd_list;
@@ -2650,8 +2648,7 @@ static int qeth_l3_do_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
if (!card)
return -ENODEV;
- if ((card->state != CARD_STATE_UP) &&
- (card->state != CARD_STATE_SOFTSETUP))
+ if (!qeth_card_hw_is_reachable(card))
return -ENODEV;
switch (cmd) {
@@ -2824,12 +2821,12 @@ static void qeth_l3_fill_header(struct qeth_card *card, struct qeth_hdr *hdr,
* before we're going to overwrite this location with next hop ip.
* v6 uses passthrough, v4 sets the tag in the QDIO header.
*/
- if (vlan_tx_tag_present(skb)) {
+ if (skb_vlan_tag_present(skb)) {
if ((ipv == 4) || (card->info.type == QETH_CARD_TYPE_IQD))
hdr->hdr.l3.ext_flags = QETH_HDR_EXT_VLAN_FRAME;
else
hdr->hdr.l3.ext_flags = QETH_HDR_EXT_INCLUDE_VLAN_TAG;
- hdr->hdr.l3.vlan_id = vlan_tx_tag_get(skb);
+ hdr->hdr.l3.vlan_id = skb_vlan_tag_get(skb);
}
hdr->hdr.l3.length = skb->len - sizeof(struct qeth_hdr);
@@ -3010,7 +3007,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_pull(new_skb, ETH_HLEN);
}
- if (ipv != 4 && vlan_tx_tag_present(new_skb)) {
+ if (ipv != 4 && skb_vlan_tag_present(new_skb)) {
skb_push(new_skb, VLAN_HLEN);
skb_copy_to_linear_data(new_skb, new_skb->data + 4, 4);
skb_copy_to_linear_data_offset(new_skb, 4,
@@ -3019,7 +3016,7 @@ static int qeth_l3_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
new_skb->data + 12, 4);
tag = (u16 *)(new_skb->data + 12);
*tag = __constant_htons(ETH_P_8021Q);
- *(tag + 1) = htons(vlan_tx_tag_get(new_skb));
+ *(tag + 1) = htons(skb_vlan_tag_get(new_skb));
}
}
diff --git a/drivers/s390/net/qeth_l3_sys.c b/drivers/s390/net/qeth_l3_sys.c
index adef5f5de118..386eb7b89b1e 100644
--- a/drivers/s390/net/qeth_l3_sys.c
+++ b/drivers/s390/net/qeth_l3_sys.c
@@ -57,29 +57,26 @@ static ssize_t qeth_l3_dev_route_store(struct qeth_card *card,
const char *buf, size_t count)
{
enum qeth_routing_types old_route_type = route->type;
- char *tmp;
int rc = 0;
- tmp = strsep((char **) &buf, "\n");
mutex_lock(&card->conf_mutex);
- if (!strcmp(tmp, "no_router")) {
+ if (sysfs_streq(buf, "no_router")) {
route->type = NO_ROUTER;
- } else if (!strcmp(tmp, "primary_connector")) {
+ } else if (sysfs_streq(buf, "primary_connector")) {
route->type = PRIMARY_CONNECTOR;
- } else if (!strcmp(tmp, "secondary_connector")) {
+ } else if (sysfs_streq(buf, "secondary_connector")) {
route->type = SECONDARY_CONNECTOR;
- } else if (!strcmp(tmp, "primary_router")) {
+ } else if (sysfs_streq(buf, "primary_router")) {
route->type = PRIMARY_ROUTER;
- } else if (!strcmp(tmp, "secondary_router")) {
+ } else if (sysfs_streq(buf, "secondary_router")) {
route->type = SECONDARY_ROUTER;
- } else if (!strcmp(tmp, "multicast_router")) {
+ } else if (sysfs_streq(buf, "multicast_router")) {
route->type = MULTICAST_ROUTER;
} else {
rc = -EINVAL;
goto out;
}
- if (((card->state == CARD_STATE_SOFTSETUP) ||
- (card->state == CARD_STATE_UP)) &&
+ if (qeth_card_hw_is_reachable(card) &&
(old_route_type != route->type)) {
if (prot == QETH_PROT_IPV4)
rc = qeth_l3_setrouting_v4(card);
@@ -371,7 +368,6 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
{
struct qeth_card *card = dev_get_drvdata(dev);
struct qeth_ipaddr *tmpipa, *t;
- char *tmp;
int rc = 0;
if (!card)
@@ -384,10 +380,9 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
goto out;
}
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "toggle")) {
+ if (sysfs_streq(buf, "toggle")) {
card->ipato.enabled = (card->ipato.enabled)? 0 : 1;
- } else if (!strcmp(tmp, "1")) {
+ } else if (sysfs_streq(buf, "1")) {
card->ipato.enabled = 1;
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
if ((tmpipa->type == QETH_IP_TYPE_NORMAL) &&
@@ -396,7 +391,7 @@ static ssize_t qeth_l3_dev_ipato_enable_store(struct device *dev,
QETH_IPA_SETIP_TAKEOVER_FLAG;
}
- } else if (!strcmp(tmp, "0")) {
+ } else if (sysfs_streq(buf, "0")) {
card->ipato.enabled = 0;
list_for_each_entry_safe(tmpipa, t, card->ip_tbd_list, entry) {
if (tmpipa->set_flags &
@@ -431,21 +426,19 @@ static ssize_t qeth_l3_dev_ipato_invert4_store(struct device *dev,
const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
- char *tmp;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "toggle")) {
+ if (sysfs_streq(buf, "toggle"))
card->ipato.invert4 = (card->ipato.invert4)? 0 : 1;
- } else if (!strcmp(tmp, "1")) {
+ else if (sysfs_streq(buf, "1"))
card->ipato.invert4 = 1;
- } else if (!strcmp(tmp, "0")) {
+ else if (sysfs_streq(buf, "0"))
card->ipato.invert4 = 0;
- } else
+ else
rc = -EINVAL;
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
@@ -613,21 +606,19 @@ static ssize_t qeth_l3_dev_ipato_invert6_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct qeth_card *card = dev_get_drvdata(dev);
- char *tmp;
int rc = 0;
if (!card)
return -EINVAL;
mutex_lock(&card->conf_mutex);
- tmp = strsep((char **) &buf, "\n");
- if (!strcmp(tmp, "toggle")) {
+ if (sysfs_streq(buf, "toggle"))
card->ipato.invert6 = (card->ipato.invert6)? 0 : 1;
- } else if (!strcmp(tmp, "1")) {
+ else if (sysfs_streq(buf, "1"))
card->ipato.invert6 = 1;
- } else if (!strcmp(tmp, "0")) {
+ else if (sysfs_streq(buf, "0"))
card->ipato.invert6 = 0;
- } else
+ else
rc = -EINVAL;
mutex_unlock(&card->conf_mutex);
return rc ? rc : count;
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index cd4129ff7ae4..7600639db4c4 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -608,7 +608,8 @@ static int twa_check_srl(TW_Device_Extension *tw_dev, int *flashed)
}
/* Load rest of compatibility struct */
- strncpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION, strlen(TW_DRIVER_VERSION));
+ strlcpy(tw_dev->tw_compat_info.driver_version, TW_DRIVER_VERSION,
+ sizeof(tw_dev->tw_compat_info.driver_version));
tw_dev->tw_compat_info.driver_srl_high = TW_CURRENT_DRIVER_SRL;
tw_dev->tw_compat_info.driver_branch_high = TW_CURRENT_DRIVER_BRANCH;
tw_dev->tw_compat_info.driver_build_high = TW_CURRENT_DRIVER_BUILD;
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 8d66a6469e29..c7be7bb37209 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -3485,7 +3485,7 @@ static int blogic_show_info(struct seq_file *m, struct Scsi_Host *shost)
seq_printf(m, "\n\
Current Driver Queue Depth: %d\n\
Currently Allocated CCBs: %d\n", adapter->drvr_qdepth, adapter->alloc_ccbs);
- seq_printf(m, "\n\n\
+ seq_puts(m, "\n\n\
DATA TRANSFER STATISTICS\n\
\n\
Target Tagged Queuing Queue Depth Active Attempted Completed\n\
@@ -3500,7 +3500,7 @@ Target Tagged Queuing Queue Depth Active Attempted Completed\n\
seq_printf(m,
" %3d %3u %9u %9u\n", adapter->qdepth[tgt], adapter->active_cmds[tgt], tgt_stats[tgt].cmds_tried, tgt_stats[tgt].cmds_complete);
}
- seq_printf(m, "\n\
+ seq_puts(m, "\n\
Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\
====== ============= ============== =================== ===================\n");
for (tgt = 0; tgt < adapter->maxdev; tgt++) {
@@ -3517,7 +3517,7 @@ Target Read Commands Write Commands Total Bytes Read Total Bytes Written\
else
seq_printf(m, " %9u\n", tgt_stats[tgt].byteswritten.units);
}
- seq_printf(m, "\n\
+ seq_puts(m, "\n\
Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\
====== ======= ========= ========= ========= ========= =========\n");
for (tgt = 0; tgt < adapter->maxdev; tgt++) {
@@ -3533,7 +3533,7 @@ Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\
tgt_stats[tgt].write_sz_buckets[0],
tgt_stats[tgt].write_sz_buckets[1], tgt_stats[tgt].write_sz_buckets[2], tgt_stats[tgt].write_sz_buckets[3], tgt_stats[tgt].write_sz_buckets[4]);
}
- seq_printf(m, "\n\
+ seq_puts(m, "\n\
Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\
====== ======= ========= ========= ========= ========= =========\n");
for (tgt = 0; tgt < adapter->maxdev; tgt++) {
@@ -3549,7 +3549,7 @@ Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\
tgt_stats[tgt].write_sz_buckets[5],
tgt_stats[tgt].write_sz_buckets[6], tgt_stats[tgt].write_sz_buckets[7], tgt_stats[tgt].write_sz_buckets[8], tgt_stats[tgt].write_sz_buckets[9]);
}
- seq_printf(m, "\n\n\
+ seq_puts(m, "\n\n\
ERROR RECOVERY STATISTICS\n\
\n\
Command Aborts Bus Device Resets Host Adapter Resets\n\
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 9c92f415229f..b021bcb88537 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -201,12 +201,12 @@ config SCSI_ENCLOSURE
certain enclosure conditions to be reported and is not required.
config SCSI_CONSTANTS
- bool "Verbose SCSI error reporting (kernel size +=12K)"
+ bool "Verbose SCSI error reporting (kernel size +=75K)"
depends on SCSI
help
The error messages regarding your SCSI hardware will be easier to
understand if you say Y here; it will enlarge your kernel by about
- 12 KB. If in doubt, say Y.
+ 75 KB. If in doubt, say Y.
config SCSI_LOGGING
bool "SCSI logging facility"
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 58158f11ed7b..dee160a4f163 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -159,15 +159,15 @@ obj-$(CONFIG_SCSI_OSD_INITIATOR) += osd/
# This goes last, so that "real" scsi devices probe earlier
obj-$(CONFIG_SCSI_DEBUG) += scsi_debug.o
-
-scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \
+scsi_mod-y += scsi.o hosts.o scsi_ioctl.o \
scsicam.o scsi_error.o scsi_lib.o
+scsi_mod-$(CONFIG_SCSI_CONSTANTS) += constants.o
scsi_mod-$(CONFIG_SCSI_DMA) += scsi_lib_dma.o
scsi_mod-y += scsi_scan.o scsi_sysfs.o scsi_devinfo.o
scsi_mod-$(CONFIG_SCSI_NETLINK) += scsi_netlink.o
scsi_mod-$(CONFIG_SYSCTL) += scsi_sysctl.o
scsi_mod-$(CONFIG_SCSI_PROC_FS) += scsi_proc.o
-scsi_mod-y += scsi_trace.o
+scsi_mod-y += scsi_trace.o scsi_logging.o
scsi_mod-$(CONFIG_PM) += scsi_pm.o
hv_storvsc-y := storvsc_drv.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 36244d63def2..8981701802ca 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -716,8 +716,6 @@ static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
}
#endif
-#undef SPRINTF
-#define SPRINTF(args...) seq_printf(m, ## args)
static
void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m);
static
@@ -734,19 +732,19 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
hostdata = (struct NCR5380_hostdata *) instance->hostdata;
#ifdef PSEUDO_DMA
- SPRINTF("Highwater I/O busy spin counts: write %d, read %d\n",
+ seq_printf(m, "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);
+ seq_printf(m, "scsi%d: no currently connected command\n", instance->host_no);
else
lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
- SPRINTF("scsi%d: issue_queue\n", instance->host_no);
+ seq_printf(m, "scsi%d: issue_queue\n", instance->host_no);
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);
+ seq_printf(m, "scsi%d: disconnected_queue\n", instance->host_no);
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);
@@ -755,8 +753,8 @@ static int __maybe_unused NCR5380_show_info(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 = ");
+ seq_printf(m, "scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
+ seq_puts(m, " command = ");
lprint_command(cmd->cmnd, m);
}
@@ -765,13 +763,13 @@ static void lprint_command(unsigned char *command, struct seq_file *m)
int i, s;
lprint_opcode(command[0], m);
for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- SPRINTF("%02x ", command[i]);
- SPRINTF("\n");
+ seq_printf(m, "%02x ", command[i]);
+ seq_putc(m, '\n');
}
static void lprint_opcode(int opcode, struct seq_file *m)
{
- SPRINTF("%2d (0x%02x)", opcode, opcode);
+ seq_printf(m, "%2d (0x%02x)", opcode, opcode);
}
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 2c5ce48c8f95..ae95e347f37d 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -2880,7 +2880,7 @@ static void asc_prt_board_devices(struct seq_file *m, struct Scsi_Host *shost)
chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
}
- seq_printf(m, "Target IDs Detected:");
+ seq_puts(m, "Target IDs Detected:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i))
seq_printf(m, " %X,", i);
@@ -2896,18 +2896,16 @@ static void asc_prt_adv_bios(struct seq_file *m, struct Scsi_Host *shost)
struct asc_board *boardp = shost_priv(shost);
ushort major, minor, letter;
- seq_printf(m, "\nROM BIOS Version: ");
+ seq_puts(m, "\nROM BIOS Version: ");
/*
* If the BIOS saved a valid signature, then fill in
* the BIOS code segment base address.
*/
if (boardp->bios_signature != 0x55AA) {
- seq_printf(m, "Disabled or Pre-3.1\n");
- seq_printf(m,
- "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n");
- seq_printf(m,
- "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
+ seq_puts(m, "Disabled or Pre-3.1\n"
+ "BIOS either disabled or Pre-3.1. If it is pre-3.1, then a newer version\n"
+ "can be found at the ConnectCom FTP site: ftp://ftp.connectcom.net/pub\n");
} else {
major = (boardp->bios_version >> 12) & 0xF;
minor = (boardp->bios_version >> 8) & 0xF;
@@ -2923,10 +2921,8 @@ static void asc_prt_adv_bios(struct seq_file *m, struct Scsi_Host *shost)
*/
if (major < 3 || (major <= 3 && minor < 1) ||
(major <= 3 && minor <= 1 && letter < ('I' - 'A'))) {
- seq_printf(m,
- "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n");
- seq_printf(m,
- "ftp://ftp.connectcom.net/pub\n");
+ seq_puts(m, "Newer version of ROM BIOS is available at the ConnectCom FTP site:\n"
+ "ftp://ftp.connectcom.net/pub\n");
}
}
}
@@ -3056,11 +3052,10 @@ static void asc_prt_asc_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
== ASC_TRUE)
seq_printf(m, " Serial Number: %s\n", serialstr);
else if (ep->adapter_info[5] == 0xBB)
- seq_printf(m,
- " Default Settings Used for EEPROM-less Adapter.\n");
+ seq_puts(m,
+ " Default Settings Used for EEPROM-less Adapter.\n");
else
- seq_printf(m,
- " Serial Number Signature Not Present.\n");
+ seq_puts(m, " Serial Number Signature Not Present.\n");
seq_printf(m,
" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
@@ -3070,34 +3065,30 @@ static void asc_prt_asc_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
seq_printf(m,
" cntl 0x%x, no_scam 0x%x\n", ep->cntl, ep->no_scam);
- seq_printf(m, " Target ID: ");
+ seq_puts(m, " Target ID: ");
for (i = 0; i <= ASC_MAX_TID; i++)
seq_printf(m, " %d", i);
- seq_printf(m, "\n");
- seq_printf(m, " Disconnects: ");
+ seq_puts(m, "\n Disconnects: ");
for (i = 0; i <= ASC_MAX_TID; i++)
seq_printf(m, " %c",
(ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
- seq_printf(m, " Command Queuing: ");
+ seq_puts(m, "\n Command Queuing: ");
for (i = 0; i <= ASC_MAX_TID; i++)
seq_printf(m, " %c",
(ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
- seq_printf(m, " Start Motor: ");
+ seq_puts(m, "\n Start Motor: ");
for (i = 0; i <= ASC_MAX_TID; i++)
seq_printf(m, " %c",
(ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
- seq_printf(m, " Synchronous Transfer:");
+ seq_puts(m, "\n Synchronous Transfer:");
for (i = 0; i <= ASC_MAX_TID; i++)
seq_printf(m, " %c",
(ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
#ifdef CONFIG_ISA
if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
@@ -3151,7 +3142,7 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
if (asc_get_eeprom_string(wordp, serialstr) == ASC_TRUE)
seq_printf(m, " Serial Number: %s\n", serialstr);
else
- seq_printf(m, " Serial Number Signature Not Present.\n");
+ seq_puts(m, " Serial Number Signature Not Present.\n");
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550)
seq_printf(m,
@@ -3209,10 +3200,10 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
ep_38C1600->termination_lvd, termstr,
ep_38C1600->bios_ctrl);
- seq_printf(m, " Target ID: ");
+ seq_puts(m, " Target ID: ");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %X", i);
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->disc_enable;
@@ -3221,11 +3212,11 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
} else {
word = ep_38C1600->disc_enable;
}
- seq_printf(m, " Disconnects: ");
+ seq_puts(m, " Disconnects: ");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %c",
(word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->tagqng_able;
@@ -3234,11 +3225,11 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
} else {
word = ep_38C1600->tagqng_able;
}
- seq_printf(m, " Command Queuing: ");
+ seq_puts(m, " Command Queuing: ");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %c",
(word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
word = ep_3550->start_motor;
@@ -3247,28 +3238,28 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
} else {
word = ep_38C1600->start_motor;
}
- seq_printf(m, " Start Motor: ");
+ seq_puts(m, " Start Motor: ");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %c",
(word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- seq_printf(m, " Synchronous Transfer:");
+ seq_puts(m, " Synchronous Transfer:");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %c",
(ep_3550->sdtr_able & ADV_TID_TO_TIDMASK(i)) ?
'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
- seq_printf(m, " Ultra Transfer: ");
+ seq_puts(m, " Ultra Transfer: ");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %c",
(ep_3550->ultra_able & ADV_TID_TO_TIDMASK(i))
? 'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC3550) {
@@ -3278,16 +3269,15 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
} else {
word = ep_38C1600->wdtr_able;
}
- seq_printf(m, " Wide Transfer: ");
+ seq_puts(m, " Wide Transfer: ");
for (i = 0; i <= ADV_MAX_TID; i++)
seq_printf(m, " %c",
(word & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
if (adv_dvc_varp->chip_type == ADV_CHIP_ASC38C0800 ||
adv_dvc_varp->chip_type == ADV_CHIP_ASC38C1600) {
- seq_printf(m,
- " Synchronous Transfer Speed (Mhz):\n ");
+ seq_puts(m, " Synchronous Transfer Speed (Mhz):\n ");
for (i = 0; i <= ADV_MAX_TID; i++) {
char *speed_str;
@@ -3325,10 +3315,10 @@ static void asc_prt_adv_board_eeprom(struct seq_file *m, struct Scsi_Host *shost
}
seq_printf(m, "%X:%s ", i, speed_str);
if (i == 7)
- seq_printf(m, "\n ");
+ seq_puts(m, "\n ");
sdtr_speed >>= 4;
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
}
@@ -3403,7 +3393,7 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
seq_printf(m,
" Total Command Pending: %d\n", v->cur_total_qng);
- seq_printf(m, " Command Queuing:");
+ seq_puts(m, " Command Queuing:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3413,10 +3403,9 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
i,
(v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- seq_printf(m, "\n");
/* Current number of commands waiting for a device. */
- seq_printf(m, " Command Queue Pending:");
+ seq_puts(m, "\n Command Queue Pending:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3424,10 +3413,9 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
}
seq_printf(m, " %X:%u", i, v->cur_dvc_qng[i]);
}
- seq_printf(m, "\n");
/* Current limit on number of commands that can be sent to a device. */
- seq_printf(m, " Command Queue Limit:");
+ seq_puts(m, "\n Command Queue Limit:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3435,10 +3423,9 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
}
seq_printf(m, " %X:%u", i, v->max_dvc_qng[i]);
}
- seq_printf(m, "\n");
/* Indicate whether the device has returned queue full status. */
- seq_printf(m, " Command Queue Full:");
+ seq_puts(m, "\n Command Queue Full:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3450,9 +3437,8 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
else
seq_printf(m, " %X:N", i);
}
- seq_printf(m, "\n");
- seq_printf(m, " Synchronous Transfer:");
+ seq_puts(m, "\n Synchronous Transfer:");
for (i = 0; i <= ASC_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3462,7 +3448,7 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
i,
(v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
for (i = 0; i <= ASC_MAX_TID; i++) {
uchar syn_period_ix;
@@ -3476,7 +3462,7 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
seq_printf(m, " %X:", i);
if ((boardp->sdtr_data[i] & ASC_SYN_MAX_OFFSET) == 0) {
- seq_printf(m, " Asynchronous");
+ seq_puts(m, " Asynchronous");
} else {
syn_period_ix =
(boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index -
@@ -3494,16 +3480,15 @@ static void asc_prt_asc_board_info(struct seq_file *m, struct Scsi_Host *shost)
}
if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- seq_printf(m, "*\n");
+ seq_puts(m, "*\n");
renegotiate = 1;
} else {
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
}
if (renegotiate) {
- seq_printf(m,
- " * = Re-negotiation pending before next command.\n");
+ seq_puts(m, " * = Re-negotiation pending before next command.\n");
}
}
@@ -3548,7 +3533,7 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
c->mcode_date, c->mcode_version);
AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, tagqng_able);
- seq_printf(m, " Queuing Enabled:");
+ seq_puts(m, " Queuing Enabled:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3559,9 +3544,8 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
i,
(tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- seq_printf(m, "\n");
- seq_printf(m, " Queue Limit:");
+ seq_puts(m, "\n Queue Limit:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3573,9 +3557,8 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
seq_printf(m, " %X:%d", i, lrambyte);
}
- seq_printf(m, "\n");
- seq_printf(m, " Command Pending:");
+ seq_puts(m, "\n Command Pending:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3587,10 +3570,10 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
seq_printf(m, " %X:%d", i, lrambyte);
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, wdtr_able);
- seq_printf(m, " Wide Enabled:");
+ seq_puts(m, " Wide Enabled:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3601,10 +3584,10 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
i,
(wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, wdtr_done);
- seq_printf(m, " Transfer Bit Width:");
+ seq_puts(m, " Transfer Bit Width:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3620,14 +3603,14 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
if ((wdtr_able & ADV_TID_TO_TIDMASK(i)) &&
(wdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- seq_printf(m, "*");
+ seq_putc(m, '*');
renegotiate = 1;
}
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
- seq_printf(m, " Synchronous Enabled:");
+ seq_puts(m, " Synchronous Enabled:");
for (i = 0; i <= ADV_MAX_TID; i++) {
if ((chip_scsi_id == i) ||
((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
@@ -3638,7 +3621,7 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
i,
(sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, sdtr_done);
for (i = 0; i <= ADV_MAX_TID; i++) {
@@ -3657,14 +3640,14 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
seq_printf(m, " %X:", i);
if ((lramword & 0x1F) == 0) { /* Check for REQ/ACK Offset 0. */
- seq_printf(m, " Asynchronous");
+ seq_puts(m, " Asynchronous");
} else {
- seq_printf(m, " Transfer Period Factor: ");
+ seq_puts(m, " Transfer Period Factor: ");
if ((lramword & 0x1F00) == 0x1100) { /* 80 Mhz */
- seq_printf(m, "9 (80.0 Mhz),");
+ seq_puts(m, "9 (80.0 Mhz),");
} else if ((lramword & 0x1F00) == 0x1000) { /* 40 Mhz */
- seq_printf(m, "10 (40.0 Mhz),");
+ seq_puts(m, "10 (40.0 Mhz),");
} else { /* 20 Mhz or below. */
period = (((lramword >> 8) * 25) + 50) / 4;
@@ -3684,16 +3667,15 @@ static void asc_prt_adv_board_info(struct seq_file *m, struct Scsi_Host *shost)
}
if ((sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
- seq_printf(m, "*\n");
+ seq_puts(m, "*\n");
renegotiate = 1;
} else {
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
}
if (renegotiate) {
- seq_printf(m,
- " * = Re-negotiation pending before next command.\n");
+ seq_puts(m, " * = Re-negotiation pending before next command.\n");
}
}
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index 2b960b326daf..e31c460a1335 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -2490,299 +2490,296 @@ static void show_queues(struct Scsi_Host *shpnt)
disp_enintr(shpnt);
}
-#undef SPRINTF
-#define SPRINTF(args...) seq_printf(m, ##args)
-
static void get_command(struct seq_file *m, Scsi_Cmnd * ptr)
{
int i;
- SPRINTF("%p: target=%d; lun=%d; cmnd=( ",
+ seq_printf(m, "%p: target=%d; lun=%d; cmnd=( ",
ptr, ptr->device->id, (u8)ptr->device->lun);
for (i = 0; i < COMMAND_SIZE(ptr->cmnd[0]); i++)
- SPRINTF("0x%02x ", ptr->cmnd[i]);
+ seq_printf(m, "0x%02x ", ptr->cmnd[i]);
- SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
+ seq_printf(m, "); resid=%d; residual=%d; buffers=%d; phase |",
scsi_get_resid(ptr), ptr->SCp.this_residual,
ptr->SCp.buffers_residual);
if (ptr->SCp.phase & not_issued)
- SPRINTF("not issued|");
+ seq_puts(m, "not issued|");
if (ptr->SCp.phase & selecting)
- SPRINTF("selecting|");
+ seq_puts(m, "selecting|");
if (ptr->SCp.phase & disconnected)
- SPRINTF("disconnected|");
+ seq_puts(m, "disconnected|");
if (ptr->SCp.phase & aborted)
- SPRINTF("aborted|");
+ seq_puts(m, "aborted|");
if (ptr->SCp.phase & identified)
- SPRINTF("identified|");
+ seq_puts(m, "identified|");
if (ptr->SCp.phase & completed)
- SPRINTF("completed|");
+ seq_puts(m, "completed|");
if (ptr->SCp.phase & spiordy)
- SPRINTF("spiordy|");
+ seq_puts(m, "spiordy|");
if (ptr->SCp.phase & syncneg)
- SPRINTF("syncneg|");
- SPRINTF("; next=0x%p\n", SCNEXT(ptr));
+ seq_puts(m, "syncneg|");
+ seq_printf(m, "; next=0x%p\n", SCNEXT(ptr));
}
static void get_ports(struct seq_file *m, struct Scsi_Host *shpnt)
{
int s;
- SPRINTF("\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
+ seq_printf(m, "\n%s: %s(%s) ", CURRENT_SC ? "on bus" : "waiting", states[STATE].name, states[PREVSTATE].name);
s = GETPORT(SCSISEQ);
- SPRINTF("SCSISEQ( ");
+ seq_puts(m, "SCSISEQ( ");
if (s & TEMODEO)
- SPRINTF("TARGET MODE ");
+ seq_puts(m, "TARGET MODE ");
if (s & ENSELO)
- SPRINTF("SELO ");
+ seq_puts(m, "SELO ");
if (s & ENSELI)
- SPRINTF("SELI ");
+ seq_puts(m, "SELI ");
if (s & ENRESELI)
- SPRINTF("RESELI ");
+ seq_puts(m, "RESELI ");
if (s & ENAUTOATNO)
- SPRINTF("AUTOATNO ");
+ seq_puts(m, "AUTOATNO ");
if (s & ENAUTOATNI)
- SPRINTF("AUTOATNI ");
+ seq_puts(m, "AUTOATNI ");
if (s & ENAUTOATNP)
- SPRINTF("AUTOATNP ");
+ seq_puts(m, "AUTOATNP ");
if (s & SCSIRSTO)
- SPRINTF("SCSIRSTO ");
- SPRINTF(");");
+ seq_puts(m, "SCSIRSTO ");
+ seq_puts(m, ");");
- SPRINTF(" SCSISIG(");
+ seq_puts(m, " SCSISIG(");
s = GETPORT(SCSISIG);
switch (s & P_MASK) {
case P_DATAO:
- SPRINTF("DATA OUT");
+ seq_puts(m, "DATA OUT");
break;
case P_DATAI:
- SPRINTF("DATA IN");
+ seq_puts(m, "DATA IN");
break;
case P_CMD:
- SPRINTF("COMMAND");
+ seq_puts(m, "COMMAND");
break;
case P_STATUS:
- SPRINTF("STATUS");
+ seq_puts(m, "STATUS");
break;
case P_MSGO:
- SPRINTF("MESSAGE OUT");
+ seq_puts(m, "MESSAGE OUT");
break;
case P_MSGI:
- SPRINTF("MESSAGE IN");
+ seq_puts(m, "MESSAGE IN");
break;
default:
- SPRINTF("*invalid*");
+ seq_puts(m, "*invalid*");
break;
}
- SPRINTF("); ");
+ seq_puts(m, "); ");
- SPRINTF("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+ seq_printf(m, "INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
- SPRINTF("SSTAT( ");
+ seq_puts(m, "SSTAT( ");
s = GETPORT(SSTAT0);
if (s & TARGET)
- SPRINTF("TARGET ");
+ seq_puts(m, "TARGET ");
if (s & SELDO)
- SPRINTF("SELDO ");
+ seq_puts(m, "SELDO ");
if (s & SELDI)
- SPRINTF("SELDI ");
+ seq_puts(m, "SELDI ");
if (s & SELINGO)
- SPRINTF("SELINGO ");
+ seq_puts(m, "SELINGO ");
if (s & SWRAP)
- SPRINTF("SWRAP ");
+ seq_puts(m, "SWRAP ");
if (s & SDONE)
- SPRINTF("SDONE ");
+ seq_puts(m, "SDONE ");
if (s & SPIORDY)
- SPRINTF("SPIORDY ");
+ seq_puts(m, "SPIORDY ");
if (s & DMADONE)
- SPRINTF("DMADONE ");
+ seq_puts(m, "DMADONE ");
s = GETPORT(SSTAT1);
if (s & SELTO)
- SPRINTF("SELTO ");
+ seq_puts(m, "SELTO ");
if (s & ATNTARG)
- SPRINTF("ATNTARG ");
+ seq_puts(m, "ATNTARG ");
if (s & SCSIRSTI)
- SPRINTF("SCSIRSTI ");
+ seq_puts(m, "SCSIRSTI ");
if (s & PHASEMIS)
- SPRINTF("PHASEMIS ");
+ seq_puts(m, "PHASEMIS ");
if (s & BUSFREE)
- SPRINTF("BUSFREE ");
+ seq_puts(m, "BUSFREE ");
if (s & SCSIPERR)
- SPRINTF("SCSIPERR ");
+ seq_puts(m, "SCSIPERR ");
if (s & PHASECHG)
- SPRINTF("PHASECHG ");
+ seq_puts(m, "PHASECHG ");
if (s & REQINIT)
- SPRINTF("REQINIT ");
- SPRINTF("); ");
+ seq_puts(m, "REQINIT ");
+ seq_puts(m, "); ");
- SPRINTF("SSTAT( ");
+ seq_puts(m, "SSTAT( ");
s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
if (s & TARGET)
- SPRINTF("TARGET ");
+ seq_puts(m, "TARGET ");
if (s & SELDO)
- SPRINTF("SELDO ");
+ seq_puts(m, "SELDO ");
if (s & SELDI)
- SPRINTF("SELDI ");
+ seq_puts(m, "SELDI ");
if (s & SELINGO)
- SPRINTF("SELINGO ");
+ seq_puts(m, "SELINGO ");
if (s & SWRAP)
- SPRINTF("SWRAP ");
+ seq_puts(m, "SWRAP ");
if (s & SDONE)
- SPRINTF("SDONE ");
+ seq_puts(m, "SDONE ");
if (s & SPIORDY)
- SPRINTF("SPIORDY ");
+ seq_puts(m, "SPIORDY ");
if (s & DMADONE)
- SPRINTF("DMADONE ");
+ seq_puts(m, "DMADONE ");
s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
if (s & SELTO)
- SPRINTF("SELTO ");
+ seq_puts(m, "SELTO ");
if (s & ATNTARG)
- SPRINTF("ATNTARG ");
+ seq_puts(m, "ATNTARG ");
if (s & SCSIRSTI)
- SPRINTF("SCSIRSTI ");
+ seq_puts(m, "SCSIRSTI ");
if (s & PHASEMIS)
- SPRINTF("PHASEMIS ");
+ seq_puts(m, "PHASEMIS ");
if (s & BUSFREE)
- SPRINTF("BUSFREE ");
+ seq_puts(m, "BUSFREE ");
if (s & SCSIPERR)
- SPRINTF("SCSIPERR ");
+ seq_puts(m, "SCSIPERR ");
if (s & PHASECHG)
- SPRINTF("PHASECHG ");
+ seq_puts(m, "PHASECHG ");
if (s & REQINIT)
- SPRINTF("REQINIT ");
- SPRINTF("); ");
+ seq_puts(m, "REQINIT ");
+ seq_puts(m, "); ");
- SPRINTF("SXFRCTL0( ");
+ seq_puts(m, "SXFRCTL0( ");
s = GETPORT(SXFRCTL0);
if (s & SCSIEN)
- SPRINTF("SCSIEN ");
+ seq_puts(m, "SCSIEN ");
if (s & DMAEN)
- SPRINTF("DMAEN ");
+ seq_puts(m, "DMAEN ");
if (s & CH1)
- SPRINTF("CH1 ");
+ seq_puts(m, "CH1 ");
if (s & CLRSTCNT)
- SPRINTF("CLRSTCNT ");
+ seq_puts(m, "CLRSTCNT ");
if (s & SPIOEN)
- SPRINTF("SPIOEN ");
+ seq_puts(m, "SPIOEN ");
if (s & CLRCH1)
- SPRINTF("CLRCH1 ");
- SPRINTF("); ");
+ seq_puts(m, "CLRCH1 ");
+ seq_puts(m, "); ");
- SPRINTF("SIGNAL( ");
+ seq_puts(m, "SIGNAL( ");
s = GETPORT(SCSISIG);
if (s & SIG_ATNI)
- SPRINTF("ATNI ");
+ seq_puts(m, "ATNI ");
if (s & SIG_SELI)
- SPRINTF("SELI ");
+ seq_puts(m, "SELI ");
if (s & SIG_BSYI)
- SPRINTF("BSYI ");
+ seq_puts(m, "BSYI ");
if (s & SIG_REQI)
- SPRINTF("REQI ");
+ seq_puts(m, "REQI ");
if (s & SIG_ACKI)
- SPRINTF("ACKI ");
- SPRINTF("); ");
+ seq_puts(m, "ACKI ");
+ seq_puts(m, "); ");
- SPRINTF("SELID(%02x), ", GETPORT(SELID));
+ seq_printf(m, "SELID(%02x), ", GETPORT(SELID));
- SPRINTF("STCNT(%d), ", GETSTCNT());
+ seq_printf(m, "STCNT(%d), ", GETSTCNT());
- SPRINTF("SSTAT2( ");
+ seq_puts(m, "SSTAT2( ");
s = GETPORT(SSTAT2);
if (s & SOFFSET)
- SPRINTF("SOFFSET ");
+ seq_puts(m, "SOFFSET ");
if (s & SEMPTY)
- SPRINTF("SEMPTY ");
+ seq_puts(m, "SEMPTY ");
if (s & SFULL)
- SPRINTF("SFULL ");
- SPRINTF("); SFCNT (%d); ", s & (SFULL | SFCNT));
+ seq_puts(m, "SFULL ");
+ seq_printf(m, "); SFCNT (%d); ", s & (SFULL | SFCNT));
s = GETPORT(SSTAT3);
- SPRINTF("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
+ seq_printf(m, "SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
- SPRINTF("SSTAT4( ");
+ seq_puts(m, "SSTAT4( ");
s = GETPORT(SSTAT4);
if (s & SYNCERR)
- SPRINTF("SYNCERR ");
+ seq_puts(m, "SYNCERR ");
if (s & FWERR)
- SPRINTF("FWERR ");
+ seq_puts(m, "FWERR ");
if (s & FRERR)
- SPRINTF("FRERR ");
- SPRINTF("); ");
+ seq_puts(m, "FRERR ");
+ seq_puts(m, "); ");
- SPRINTF("DMACNTRL0( ");
+ seq_puts(m, "DMACNTRL0( ");
s = GETPORT(DMACNTRL0);
- SPRINTF("%s ", s & _8BIT ? "8BIT" : "16BIT");
- SPRINTF("%s ", s & DMA ? "DMA" : "PIO");
- SPRINTF("%s ", s & WRITE_READ ? "WRITE" : "READ");
+ seq_printf(m, "%s ", s & _8BIT ? "8BIT" : "16BIT");
+ seq_printf(m, "%s ", s & DMA ? "DMA" : "PIO");
+ seq_printf(m, "%s ", s & WRITE_READ ? "WRITE" : "READ");
if (s & ENDMA)
- SPRINTF("ENDMA ");
+ seq_puts(m, "ENDMA ");
if (s & INTEN)
- SPRINTF("INTEN ");
+ seq_puts(m, "INTEN ");
if (s & RSTFIFO)
- SPRINTF("RSTFIFO ");
+ seq_puts(m, "RSTFIFO ");
if (s & SWINT)
- SPRINTF("SWINT ");
- SPRINTF("); ");
+ seq_puts(m, "SWINT ");
+ seq_puts(m, "); ");
- SPRINTF("DMASTAT( ");
+ seq_puts(m, "DMASTAT( ");
s = GETPORT(DMASTAT);
if (s & ATDONE)
- SPRINTF("ATDONE ");
+ seq_puts(m, "ATDONE ");
if (s & WORDRDY)
- SPRINTF("WORDRDY ");
+ seq_puts(m, "WORDRDY ");
if (s & DFIFOFULL)
- SPRINTF("DFIFOFULL ");
+ seq_puts(m, "DFIFOFULL ");
if (s & DFIFOEMP)
- SPRINTF("DFIFOEMP ");
- SPRINTF(")\n");
+ seq_puts(m, "DFIFOEMP ");
+ seq_puts(m, ")\n");
- SPRINTF("enabled interrupts( ");
+ seq_puts(m, "enabled interrupts( ");
s = GETPORT(SIMODE0);
if (s & ENSELDO)
- SPRINTF("ENSELDO ");
+ seq_puts(m, "ENSELDO ");
if (s & ENSELDI)
- SPRINTF("ENSELDI ");
+ seq_puts(m, "ENSELDI ");
if (s & ENSELINGO)
- SPRINTF("ENSELINGO ");
+ seq_puts(m, "ENSELINGO ");
if (s & ENSWRAP)
- SPRINTF("ENSWRAP ");
+ seq_puts(m, "ENSWRAP ");
if (s & ENSDONE)
- SPRINTF("ENSDONE ");
+ seq_puts(m, "ENSDONE ");
if (s & ENSPIORDY)
- SPRINTF("ENSPIORDY ");
+ seq_puts(m, "ENSPIORDY ");
if (s & ENDMADONE)
- SPRINTF("ENDMADONE ");
+ seq_puts(m, "ENDMADONE ");
s = GETPORT(SIMODE1);
if (s & ENSELTIMO)
- SPRINTF("ENSELTIMO ");
+ seq_puts(m, "ENSELTIMO ");
if (s & ENATNTARG)
- SPRINTF("ENATNTARG ");
+ seq_puts(m, "ENATNTARG ");
if (s & ENPHASEMIS)
- SPRINTF("ENPHASEMIS ");
+ seq_puts(m, "ENPHASEMIS ");
if (s & ENBUSFREE)
- SPRINTF("ENBUSFREE ");
+ seq_puts(m, "ENBUSFREE ");
if (s & ENSCSIPERR)
- SPRINTF("ENSCSIPERR ");
+ seq_puts(m, "ENSCSIPERR ");
if (s & ENPHASECHG)
- SPRINTF("ENPHASECHG ");
+ seq_puts(m, "ENPHASECHG ");
if (s & ENREQINIT)
- SPRINTF("ENREQINIT ");
- SPRINTF(")\n");
+ seq_puts(m, "ENREQINIT ");
+ seq_puts(m, ")\n");
}
static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
@@ -2825,56 +2822,56 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
Scsi_Cmnd *ptr;
unsigned long flags;
- SPRINTF(AHA152X_REVID "\n");
+ seq_puts(m, AHA152X_REVID "\n");
- SPRINTF("ioports 0x%04lx to 0x%04lx\n",
+ seq_printf(m, "ioports 0x%04lx to 0x%04lx\n",
shpnt->io_port, shpnt->io_port + shpnt->n_io_port - 1);
- SPRINTF("interrupt 0x%02x\n", shpnt->irq);
- SPRINTF("disconnection/reconnection %s\n",
+ seq_printf(m, "interrupt 0x%02x\n", shpnt->irq);
+ seq_printf(m, "disconnection/reconnection %s\n",
RECONNECT ? "enabled" : "disabled");
- SPRINTF("parity checking %s\n",
+ seq_printf(m, "parity checking %s\n",
PARITY ? "enabled" : "disabled");
- SPRINTF("synchronous transfers %s\n",
+ seq_printf(m, "synchronous transfers %s\n",
SYNCHRONOUS ? "enabled" : "disabled");
- SPRINTF("%d commands currently queued\n", HOSTDATA(shpnt)->commands);
+ seq_printf(m, "%d commands currently queued\n", HOSTDATA(shpnt)->commands);
if(SYNCHRONOUS) {
- SPRINTF("synchronously operating targets (tick=50 ns):\n");
+ seq_puts(m, "synchronously operating targets (tick=50 ns):\n");
for (i = 0; i < 8; i++)
if (HOSTDATA(shpnt)->syncrate[i] & 0x7f)
- SPRINTF("target %d: period %dT/%dns; req/ack offset %d\n",
+ seq_printf(m, "target %d: period %dT/%dns; req/ack offset %d\n",
i,
(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2),
(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
HOSTDATA(shpnt)->syncrate[i] & 0x0f);
}
- SPRINTF("\nqueue status:\n");
+ seq_puts(m, "\nqueue status:\n");
DO_LOCK(flags);
if (ISSUE_SC) {
- SPRINTF("not yet issued commands:\n");
+ seq_puts(m, "not yet issued commands:\n");
for (ptr = ISSUE_SC; ptr; ptr = SCNEXT(ptr))
get_command(m, ptr);
} else
- SPRINTF("no not yet issued commands\n");
+ seq_puts(m, "no not yet issued commands\n");
DO_UNLOCK(flags);
if (CURRENT_SC) {
- SPRINTF("current command:\n");
+ seq_puts(m, "current command:\n");
get_command(m, CURRENT_SC);
} else
- SPRINTF("no current command\n");
+ seq_puts(m, "no current command\n");
if (DISCONNECTED_SC) {
- SPRINTF("disconnected commands:\n");
+ seq_puts(m, "disconnected commands:\n");
for (ptr = DISCONNECTED_SC; ptr; ptr = SCNEXT(ptr))
get_command(m, ptr);
} else
- SPRINTF("no disconnected commands\n");
+ seq_puts(m, "no disconnected commands\n");
get_ports(m, shpnt);
#if defined(AHA152X_STAT)
- SPRINTF("statistics:\n"
+ seq_printf(m, "statistics:\n"
"total commands: %d\n"
"disconnections: %d\n"
"busfree with check condition: %d\n"
@@ -2894,7 +2891,7 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
HOSTDATA(shpnt)->busfree_without_done_command,
HOSTDATA(shpnt)->busfree_without_any_action);
for(i=0; i<maxstate; i++) {
- SPRINTF("%-10s %-12d %-12d %-12ld\n",
+ seq_printf(m, "%-10s %-12d %-12d %-12ld\n",
states[i].name,
HOSTDATA(shpnt)->count_trans[i],
HOSTDATA(shpnt)->count[i],
diff --git a/drivers/scsi/aic7xxx/aic79xx_core.c b/drivers/scsi/aic7xxx/aic79xx_core.c
index 0bcacf71aef8..97f2accd3dbb 100644
--- a/drivers/scsi/aic7xxx/aic79xx_core.c
+++ b/drivers/scsi/aic7xxx/aic79xx_core.c
@@ -1298,7 +1298,7 @@ rescan_fifos:
/*
* Wait for any inprogress DMA to complete and clear DMA state
- * if this if for an SCB in the qinfifo.
+ * if this is for an SCB in the qinfifo.
*/
while (((ccscbctl = ahd_inb(ahd, CCSCBCTL)) & (CCARREN|CCSCBEN)) != 0) {
diff --git a/drivers/scsi/aic7xxx/aic79xx_proc.c b/drivers/scsi/aic7xxx/aic79xx_proc.c
index 27dbfccea774..add2da581d66 100644
--- a/drivers/scsi/aic7xxx/aic79xx_proc.c
+++ b/drivers/scsi/aic7xxx/aic79xx_proc.c
@@ -97,7 +97,7 @@ ahd_format_transinfo(struct seq_file *m, struct ahd_transinfo *tinfo)
u_int mb;
if (tinfo->period == AHD_PERIOD_UNKNOWN) {
- seq_printf(m, "Renegotiation Pending\n");
+ seq_puts(m, "Renegotiation Pending\n");
return;
}
speed = 3300;
@@ -119,40 +119,38 @@ ahd_format_transinfo(struct seq_file *m, struct ahd_transinfo *tinfo)
printed_options = 0;
seq_printf(m, " (%d.%03dMHz", freq / 1000, freq % 1000);
if ((tinfo->ppr_options & MSG_EXT_PPR_RD_STRM) != 0) {
- seq_printf(m, " RDSTRM");
+ seq_puts(m, " RDSTRM");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_DT_REQ) != 0) {
- seq_printf(m, "%s", printed_options ? "|DT" : " DT");
+ seq_puts(m, printed_options ? "|DT" : " DT");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_IU_REQ) != 0) {
- seq_printf(m, "%s", printed_options ? "|IU" : " IU");
+ seq_puts(m, printed_options ? "|IU" : " IU");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_RTI) != 0) {
- seq_printf(m, "%s",
- printed_options ? "|RTI" : " RTI");
+ seq_puts(m, printed_options ? "|RTI" : " RTI");
printed_options++;
}
if ((tinfo->ppr_options & MSG_EXT_PPR_QAS_REQ) != 0) {
- seq_printf(m, "%s",
- printed_options ? "|QAS" : " QAS");
+ seq_puts(m, printed_options ? "|QAS" : " QAS");
printed_options++;
}
}
if (tinfo->width > 0) {
if (freq != 0) {
- seq_printf(m, ", ");
+ seq_puts(m, ", ");
} else {
- seq_printf(m, " (");
+ seq_puts(m, " (");
}
seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width));
} else if (freq != 0) {
- seq_printf(m, ")");
+ seq_putc(m, ')');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
static void
@@ -167,15 +165,15 @@ ahd_dump_target_state(struct ahd_softc *ahd, struct seq_file *m,
tinfo = ahd_fetch_transinfo(ahd, channel, our_id,
target_id, &tstate);
seq_printf(m, "Target %d Negotiation Settings\n", target_id);
- seq_printf(m, "\tUser: ");
+ seq_puts(m, "\tUser: ");
ahd_format_transinfo(m, &tinfo->user);
starget = ahd->platform_data->starget[target_id];
if (starget == NULL)
return;
- seq_printf(m, "\tGoal: ");
+ seq_puts(m, "\tGoal: ");
ahd_format_transinfo(m, &tinfo->goal);
- seq_printf(m, "\tCurr: ");
+ seq_puts(m, "\tCurr: ");
ahd_format_transinfo(m, &tinfo->curr);
for (lun = 0; lun < AHD_NUM_LUNS; lun++) {
@@ -291,19 +289,19 @@ ahd_linux_show_info(struct seq_file *m, struct Scsi_Host *shost)
max_targ = 16;
if (ahd->seep_config == NULL)
- seq_printf(m, "No Serial EEPROM\n");
+ seq_puts(m, "No Serial EEPROM\n");
else {
- seq_printf(m, "Serial EEPROM:\n");
+ seq_puts(m, "Serial EEPROM:\n");
for (i = 0; i < sizeof(*ahd->seep_config)/2; i++) {
if (((i % 8) == 0) && (i != 0)) {
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
seq_printf(m, "0x%.4x ",
((uint16_t*)ahd->seep_config)[i]);
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
if ((ahd->features & AHD_WIDE) == 0)
max_targ = 8;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_proc.c b/drivers/scsi/aic7xxx/aic7xxx_proc.c
index 64eec6c07a83..18459605d991 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_proc.c
@@ -119,15 +119,15 @@ ahc_format_transinfo(struct seq_file *m, struct ahc_transinfo *tinfo)
if (tinfo->width > 0) {
if (freq != 0) {
- seq_printf(m, ", ");
+ seq_puts(m, ", ");
} else {
- seq_printf(m, " (");
+ seq_puts(m, " (");
}
seq_printf(m, "%dbit)", 8 * (0x01 << tinfo->width));
} else if (freq != 0) {
- seq_printf(m, ")");
+ seq_putc(m, ')');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
static void
@@ -145,15 +145,15 @@ ahc_dump_target_state(struct ahc_softc *ahc, struct seq_file *m,
if ((ahc->features & AHC_TWIN) != 0)
seq_printf(m, "Channel %c ", channel);
seq_printf(m, "Target %d Negotiation Settings\n", target_id);
- seq_printf(m, "\tUser: ");
+ seq_puts(m, "\tUser: ");
ahc_format_transinfo(m, &tinfo->user);
starget = ahc->platform_data->starget[target_offset];
if (!starget)
return;
- seq_printf(m, "\tGoal: ");
+ seq_puts(m, "\tGoal: ");
ahc_format_transinfo(m, &tinfo->goal);
- seq_printf(m, "\tCurr: ");
+ seq_puts(m, "\tCurr: ");
ahc_format_transinfo(m, &tinfo->curr);
for (lun = 0; lun < AHC_NUM_LUNS; lun++) {
@@ -303,19 +303,19 @@ ahc_linux_show_info(struct seq_file *m, struct Scsi_Host *shost)
if (ahc->seep_config == NULL)
- seq_printf(m, "No Serial EEPROM\n");
+ seq_puts(m, "No Serial EEPROM\n");
else {
- seq_printf(m, "Serial EEPROM:\n");
+ seq_puts(m, "Serial EEPROM:\n");
for (i = 0; i < sizeof(*ahc->seep_config)/2; i++) {
if (((i % 8) == 0) && (i != 0)) {
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
seq_printf(m, "0x%.4x ",
((uint16_t*)ahc->seep_config)[i]);
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
max_targ = 16;
if ((ahc->features & (AHC_WIDE|AHC_TWIN)) == 0)
diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c
index aa3e2c7cd83c..a6f5ee80fadc 100644
--- a/drivers/scsi/am53c974.c
+++ b/drivers/scsi/am53c974.c
@@ -178,12 +178,6 @@ static void pci_esp_dma_drain(struct esp *esp)
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
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index e64c3af7c1a0..decdc71b6b86 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -2990,7 +2990,7 @@ void fas216_print_devices(FAS216_Info *info, struct seq_file *m)
struct fas216_device *dev;
struct scsi_device *scd;
- seq_printf(m, "Device/Lun TaggedQ Parity Sync\n");
+ seq_puts(m, "Device/Lun TaggedQ Parity Sync\n");
shost_for_each_device(scd, info->host) {
dev = &info->device[scd->id];
@@ -3000,7 +3000,7 @@ void fas216_print_devices(FAS216_Info *info, struct seq_file *m)
scd->simple_tags ? "en" : "dis",
scd->current_tag);
else
- seq_printf(m, "unsupported ");
+ seq_puts(m, "unsupported ");
seq_printf(m, "%3sabled ", dev->parity_enabled ? "en" : "dis");
@@ -3008,7 +3008,7 @@ void fas216_print_devices(FAS216_Info *info, struct seq_file *m)
seq_printf(m, "offset %d, %d ns\n",
dev->sof, dev->period * 4);
else
- seq_printf(m, "async\n");
+ seq_puts(m, "async\n");
}
}
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 6daed6b386d4..a70255413e7f 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -711,12 +711,12 @@ static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
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 = ");
+ seq_puts(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");
+ seq_putc(m, '\n');
}
static int __maybe_unused NCR5380_show_info(struct seq_file *m,
diff --git a/drivers/scsi/atp870u.c b/drivers/scsi/atp870u.c
index a795d81ef875..0836433e3a2d 100644
--- a/drivers/scsi/atp870u.c
+++ b/drivers/scsi/atp870u.c
@@ -3101,9 +3101,8 @@ static const char *atp870u_info(struct Scsi_Host *notused)
static int atp870u_show_info(struct seq_file *m, struct Scsi_Host *HBAptr)
{
- seq_printf(m, "ACARD AEC-671X Driver Version: 2.6+ac\n");
- seq_printf(m, "\n");
- seq_printf(m, "Adapter Configuration:\n");
+ seq_puts(m, "ACARD AEC-671X Driver Version: 2.6+ac\n\n"
+ "Adapter Configuration:\n");
seq_printf(m, " Base IO: %#.4lx\n", HBAptr->io_port);
seq_printf(m, " IRQ: %d\n", HBAptr->irq);
return 0;
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index f3193406776c..a7cc61837818 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -48,7 +48,6 @@ static unsigned int be_iopoll_budget = 10;
static unsigned int be_max_phys_size = 64;
static unsigned int enable_msix = 1;
-MODULE_DEVICE_TABLE(pci, beiscsi_pci_id_table);
MODULE_DESCRIPTION(DRV_DESC " " BUILD_STR);
MODULE_VERSION(BUILD_STR);
MODULE_AUTHOR("Emulex Corporation");
@@ -586,7 +585,6 @@ static struct beiscsi_hba *beiscsi_hba_alloc(struct pci_dev *pcidev)
"beiscsi_hba_alloc - iscsi_host_alloc failed\n");
return NULL;
}
- shost->dma_boundary = pcidev->dma_mask;
shost->max_id = BE2_MAX_SESSIONS;
shost->max_channel = 0;
shost->max_cmd_len = BEISCSI_MAX_CMD_LEN;
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index 6bac8a746ee2..0045742fab7d 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -194,16 +194,10 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len,
retry:
errno = 0;
- if (debug) {
- DPRINTK("command: ");
- __scsi_print_command(cmd, cmd_len);
- }
-
result = scsi_execute_req(ch->device, cmd, direction, buffer,
buflength, &sshdr, timeout * HZ,
MAX_RETRIES, NULL);
- DPRINTK("result: 0x%x\n",result);
if (driver_byte(result) & DRIVER_SENSE) {
if (debug)
scsi_print_sense_hdr(ch->device, ch->name, &sshdr);
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index e2068a2621c4..fa09d4be2b53 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -18,14 +18,10 @@
#include <scsi/scsi_eh.h>
#include <scsi/scsi_dbg.h>
-
-
/* Commands with service actions that change the command name */
#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;
@@ -37,7 +33,6 @@ struct value_name_pair {
const char * name;
};
-#ifdef CONFIG_SCSI_CONSTANTS
static const char * cdb_byte0_names[] = {
/* 00-03 */ "Test Unit Ready", "Rezero Unit/Rewind", NULL, "Request Sense",
/* 04-07 */ "Format Unit/Medium", "Read Block Limits", NULL,
@@ -261,28 +256,8 @@ static struct sa_name_list sa_names_arr[] = {
{0, NULL, 0},
};
-#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 */
-
-static bool scsi_opcode_sa_name(int opcode, int service_action,
- const char **cdb_name, const char **sa_name)
+bool scsi_opcode_sa_name(int opcode, int service_action,
+ const char **cdb_name, const char **sa_name)
{
struct sa_name_list *sa_name_ptr;
const struct value_name_pair *arr = NULL;
@@ -315,76 +290,6 @@ static bool scsi_opcode_sa_name(int opcode, int service_action,
return true;
}
-static void print_opcode_name(const unsigned char *cdbp, size_t cdb_len)
-{
- int sa, cdb0;
- const char *cdb_name = NULL, *sa_name = NULL;
-
- cdb0 = cdbp[0];
- 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];
- } else
- sa = cdbp[1] & 0x1f;
-
- 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, sa=0x%x", cdb0, sa);
- }
-}
-
-void __scsi_print_command(const unsigned char *cdb, size_t cdb_len)
-{
- int k, len;
-
- 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]);
- printk("\n");
-}
-EXPORT_SYMBOL(__scsi_print_command);
-
-void scsi_print_command(struct scsi_cmnd *cmd)
-{
- int k;
-
- if (cmd->cmnd == NULL)
- return;
-
- scmd_printk(KERN_INFO, cmd, "CDB: ");
- print_opcode_name(cmd->cmnd, cmd->cmd_len);
-
- /* print out all bytes in cdb */
- printk(":");
- for (k = 0; k < cmd->cmd_len; ++k)
- printk(" %02x", cmd->cmnd[k]);
- printk("\n");
-}
-EXPORT_SYMBOL(scsi_print_command);
-
-#ifdef CONFIG_SCSI_CONSTANTS
-
struct error_info {
unsigned short code12; /* 0x0302 looks better than 0x03,0x02 */
const char * text;
@@ -392,7 +297,7 @@ struct error_info {
/*
* The canonical list of T10 Additional Sense Codes is available at:
- * http://www.t10.org/lists/asc-num.txt [most recent: 20130605]
+ * http://www.t10.org/lists/asc-num.txt [most recent: 20141221]
*/
static const struct error_info additional[] =
@@ -421,6 +326,7 @@ static const struct error_info additional[] =
{0x001E, "Conflicting SA creation request"},
{0x001F, "Logical unit transitioning to another power condition"},
{0x0020, "Extended copy information available"},
+ {0x0021, "Atomic command aborted due to ACA"},
{0x0100, "No index/sector signal"},
@@ -446,6 +352,7 @@ static const struct error_info additional[] =
{0x040C, "Logical unit not accessible, target port in unavailable "
"state"},
{0x040D, "Logical unit not ready, structure check required"},
+ {0x040E, "Logical unit not ready, security session in progress"},
{0x0410, "Logical unit not ready, auxiliary memory not accessible"},
{0x0411, "Logical unit not ready, notify (enable spinup) required"},
{0x0412, "Logical unit not ready, offline"},
@@ -462,6 +369,11 @@ static const struct error_info additional[] =
{0x041C, "Logical unit not ready, additional power use not yet "
"granted"},
{0x041D, "Logical unit not ready, configuration in progress"},
+ {0x041E, "Logical unit not ready, microcode activation required"},
+ {0x041F, "Logical unit not ready, microcode download required"},
+ {0x0420, "Logical unit not ready, logical unit reset required"},
+ {0x0421, "Logical unit not ready, hard reset required"},
+ {0x0422, "Logical unit not ready, power cycle required"},
{0x0500, "Logical unit does not respond to selection"},
@@ -480,6 +392,7 @@ static const struct error_info additional[] =
{0x0902, "Focus servo failure"},
{0x0903, "Spindle servo failure"},
{0x0904, "Head select fault"},
+ {0x0905, "Vibration induced tracking error"},
{0x0A00, "Error log overflow"},
@@ -510,6 +423,7 @@ static const struct error_info additional[] =
{0x0C0D, "Write error - not enough unsolicited data"},
{0x0C0E, "Multiple write errors"},
{0x0C0F, "Defects in error window"},
+ {0x0C10, "Incomplete multiple atomic write operations"},
{0x0D00, "Error detected by third party temporary initiator"},
{0x0D01, "Third party device failure"},
@@ -635,6 +549,10 @@ static const struct error_info additional[] =
{0x2101, "Invalid element address"},
{0x2102, "Invalid address for write"},
{0x2103, "Invalid write crossing layer jump"},
+ {0x2104, "Unaligned write command"},
+ {0x2105, "Write boundary violation"},
+ {0x2106, "Attempt to read invalid data"},
+ {0x2107, "Read boundary violation"},
{0x2200, "Illegal function (use 20 00, 24 00, or 26 00)"},
@@ -691,6 +609,7 @@ static const struct error_info additional[] =
{0x2705, "Permanent write protect"},
{0x2706, "Conditional write protect"},
{0x2707, "Space allocation failed write protect"},
+ {0x2708, "Zone is read only"},
{0x2800, "Not ready to ready change, medium may have changed"},
{0x2801, "Import or export element accessed"},
@@ -743,10 +662,15 @@ static const struct error_info additional[] =
{0x2C0A, "Partition or collection contains user objects"},
{0x2C0B, "Not reserved"},
{0x2C0C, "Orwrite generation does not match"},
+ {0x2C0D, "Reset write pointer not allowed"},
+ {0x2C0E, "Zone is offline"},
{0x2D00, "Overwrite error on update in place"},
{0x2E00, "Insufficient time for operation"},
+ {0x2E01, "Command timeout before processing"},
+ {0x2E02, "Command timeout during processing"},
+ {0x2E03, "Command timeout during processing due to error recovery"},
{0x2F00, "Commands cleared by another initiator"},
{0x2F01, "Commands cleared by power loss notification"},
@@ -868,6 +792,7 @@ static const struct error_info additional[] =
{0x3F13, "iSCSI IP address removed"},
{0x3F14, "iSCSI IP address changed"},
{0x3F15, "Inspect referrals sense descriptors"},
+ {0x3F16, "Microcode has been changed without reset"},
/*
* {0x40NN, "Ram failure"},
* {0x40NN, "Diagnostic failure on component nn"},
@@ -946,6 +871,11 @@ static const struct error_info additional[] =
{0x5306, "Volume identifier missing"},
{0x5307, "Duplicate volume identifier"},
{0x5308, "Element status unknown"},
+ {0x5309, "Data transfer device error - load failed"},
+ {0x530a, "Data transfer device error - unload failed"},
+ {0x530b, "Data transfer device error - unload missing"},
+ {0x530c, "Data transfer device error - eject failed"},
+ {0x530d, "Data transfer device error - library communication failed"},
{0x5400, "Scsi to host system interface failure"},
@@ -963,6 +893,7 @@ static const struct error_info additional[] =
{0x550B, "Insufficient power for operation"},
{0x550C, "Insufficient resources to create rod"},
{0x550D, "Insufficient resources to create rod token"},
+ {0x550E, "Insufficient zone resources"},
{0x5700, "Unable to recover table-of-contents"},
@@ -1247,15 +1178,12 @@ static const char * const snstext[] = {
"Completed", /* F: command completed sense data reported,
may occur for successful command */
};
-#endif
/* Get sense key string or NULL if not available */
const char *
scsi_sense_key_string(unsigned char key) {
-#ifdef CONFIG_SCSI_CONSTANTS
if (key <= 0xE)
return snstext[key];
-#endif
return NULL;
}
EXPORT_SYMBOL(scsi_sense_key_string);
@@ -1267,7 +1195,6 @@ EXPORT_SYMBOL(scsi_sense_key_string);
const char *
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);
@@ -1283,122 +1210,10 @@ scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt)
return additional2[i].str;
}
}
-#else
- *fmt = NULL;
-#endif
return NULL;
}
EXPORT_SYMBOL(scsi_extd_sense_format);
-void
-scsi_show_extd_sense(const struct scsi_device *sdev, const char *name,
- unsigned char asc, unsigned char 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
- sdev_prefix_printk(KERN_INFO, sdev, name,
- "Add. Sense: %s", extd_sense_str);
-
- } 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(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)
- 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
- 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);
-
-/*
- * Print normalized SCSI sense header with a prefix.
- */
-void
-scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
- const struct scsi_sense_hdr *sshdr)
-{
- scsi_show_sense_hdr(sdev, name, sshdr);
- scsi_show_extd_sense(sdev, name, sshdr->asc, sshdr->ascq);
-}
-EXPORT_SYMBOL(scsi_print_sense_hdr);
-
-static void
-scsi_dump_sense_buffer(const unsigned char *sense_buffer, int sense_len)
-{
- 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("%02x ", sense_buffer[k]);
- }
- printk("\n");
- return;
-}
-
-/* Normalize and print sense buffer with name prefix */
-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;
-
- 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(const struct scsi_cmnd *cmd)
-{
- struct gendisk *disk = cmd->request->rq_disk;
- const char *disk_name = disk ? disk->disk_name : NULL;
-
- __scsi_print_sense(cmd->device, disk_name, cmd->sense_buffer,
- SCSI_SENSE_BUFFERSIZE);
-}
-EXPORT_SYMBOL(scsi_print_sense);
-
-#ifdef CONFIG_SCSI_CONSTANTS
-
static const char * const hostbyte_table[]={
"DID_OK", "DID_NO_CONNECT", "DID_BUS_BUSY", "DID_TIME_OUT", "DID_BAD_TARGET",
"DID_ABORT", "DID_PARITY", "DID_ERROR", "DID_RESET", "DID_BAD_INTR",
@@ -1410,17 +1225,13 @@ static const char * const driverbyte_table[]={
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
-#endif
-
const char *scsi_hostbyte_string(int result)
{
const char *hb_string = NULL;
-#ifdef CONFIG_SCSI_CONSTANTS
int hb = host_byte(result);
if (hb < ARRAY_SIZE(hostbyte_table))
hb_string = hostbyte_table[hb];
-#endif
return hb_string;
}
EXPORT_SYMBOL(scsi_hostbyte_string);
@@ -1428,17 +1239,14 @@ EXPORT_SYMBOL(scsi_hostbyte_string);
const char *scsi_driverbyte_string(int 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),
@@ -1451,11 +1259,9 @@ static const struct value_name_pair scsi_mlreturn_arr[] = {
scsi_mlreturn_name(SCSI_RETURN_NOT_HANDLED),
scsi_mlreturn_name(FAST_IO_FAIL)
};
-#endif
const char *scsi_mlreturn_string(int result)
{
-#ifdef CONFIG_SCSI_CONSTANTS
const struct value_name_pair *arr = scsi_mlreturn_arr;
int k;
@@ -1463,29 +1269,6 @@ const char *scsi_mlreturn_string(int result)
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)
-{
- 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/Makefile b/drivers/scsi/csiostor/Makefile
index 913b9a92fb06..3681a3fbd499 100644
--- a/drivers/scsi/csiostor/Makefile
+++ b/drivers/scsi/csiostor/Makefile
@@ -8,5 +8,5 @@ ccflags-y += -I$(srctree)/drivers/net/ethernet/chelsio/cxgb4
obj-$(CONFIG_SCSI_CHELSIO_FCOE) += csiostor.o
csiostor-objs := csio_attr.o csio_init.o csio_lnode.o csio_scsi.o \
- csio_hw.o csio_hw_t4.o csio_hw_t5.o csio_isr.o \
+ csio_hw.o csio_hw_t5.o csio_isr.o \
csio_mb.o csio_rnode.o csio_wr.o
diff --git a/drivers/scsi/csiostor/csio_hw.c b/drivers/scsi/csiostor/csio_hw.c
index 9ab997e18b20..2e66f34ebb79 100644
--- a/drivers/scsi/csiostor/csio_hw.c
+++ b/drivers/scsi/csiostor/csio_hw.c
@@ -60,37 +60,10 @@ int csio_msi = 2;
static int dev_num;
/* FCoE Adapter types & its description */
-static const struct csio_adap_desc csio_t4_fcoe_adapters[] = {
- {"T440-Dbg 10G", "Chelsio T440-Dbg 10G [FCoE]"},
- {"T420-CR 10G", "Chelsio T420-CR 10G [FCoE]"},
- {"T422-CR 10G/1G", "Chelsio T422-CR 10G/1G [FCoE]"},
- {"T440-CR 10G", "Chelsio T440-CR 10G [FCoE]"},
- {"T420-BCH 10G", "Chelsio T420-BCH 10G [FCoE]"},
- {"T440-BCH 10G", "Chelsio T440-BCH 10G [FCoE]"},
- {"T440-CH 10G", "Chelsio T440-CH 10G [FCoE]"},
- {"T420-SO 10G", "Chelsio T420-SO 10G [FCoE]"},
- {"T420-CX4 10G", "Chelsio T420-CX4 10G [FCoE]"},
- {"T420-BT 10G", "Chelsio T420-BT 10G [FCoE]"},
- {"T404-BT 1G", "Chelsio T404-BT 1G [FCoE]"},
- {"B420-SR 10G", "Chelsio B420-SR 10G [FCoE]"},
- {"B404-BT 1G", "Chelsio B404-BT 1G [FCoE]"},
- {"T480-CR 10G", "Chelsio T480-CR 10G [FCoE]"},
- {"T440-LP-CR 10G", "Chelsio T440-LP-CR 10G [FCoE]"},
- {"AMSTERDAM 10G", "Chelsio AMSTERDAM 10G [FCoE]"},
- {"HUAWEI T480 10G", "Chelsio HUAWEI T480 10G [FCoE]"},
- {"HUAWEI T440 10G", "Chelsio HUAWEI T440 10G [FCoE]"},
- {"HUAWEI STG 10G", "Chelsio HUAWEI STG 10G [FCoE]"},
- {"ACROMAG XAUI 10G", "Chelsio ACROMAG XAUI 10G [FCoE]"},
- {"ACROMAG SFP+ 10G", "Chelsio ACROMAG SFP+ 10G [FCoE]"},
- {"QUANTA SFP+ 10G", "Chelsio QUANTA SFP+ 10G [FCoE]"},
- {"HUAWEI 10Gbase-T", "Chelsio HUAWEI 10Gbase-T [FCoE]"},
- {"HUAWEI T4TOE 10G", "Chelsio HUAWEI T4TOE 10G [FCoE]"}
-};
-
static const struct csio_adap_desc csio_t5_fcoe_adapters[] = {
{"T580-Dbg 10G", "Chelsio T580-Dbg 10G [FCoE]"},
{"T520-CR 10G", "Chelsio T520-CR 10G [FCoE]"},
- {"T522-CR 10G/1G", "Chelsio T452-CR 10G/1G [FCoE]"},
+ {"T522-CR 10G/1G", "Chelsio T522-CR 10G/1G [FCoE]"},
{"T540-CR 10G", "Chelsio T540-CR 10G [FCoE]"},
{"T520-BCH 10G", "Chelsio T520-BCH 10G [FCoE]"},
{"T540-BCH 10G", "Chelsio T540-BCH 10G [FCoE]"},
@@ -107,7 +80,9 @@ static const struct csio_adap_desc csio_t5_fcoe_adapters[] = {
{"T580-LP-CR 40G", "Chelsio T580-LP-CR 40G [FCoE]"},
{"T520-LL-CR 10G", "Chelsio T520-LL-CR 10G [FCoE]"},
{"T560-CR 40G", "Chelsio T560-CR 40G [FCoE]"},
- {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"}
+ {"T580-CR 40G", "Chelsio T580-CR 40G [FCoE]"},
+ {"T580-SO 40G", "Chelsio T580-SO 40G [FCoE]"},
+ {"T502-BT 1G", "Chelsio T502-BT 1G [FCoE]"}
};
static void csio_mgmtm_cleanup(struct csio_mgmtm *);
@@ -188,9 +163,9 @@ void
csio_hw_tp_wr_bits_indirect(struct csio_hw *hw, unsigned int addr,
unsigned int mask, unsigned int val)
{
- csio_wr_reg32(hw, addr, TP_PIO_ADDR);
- val |= csio_rd_reg32(hw, TP_PIO_DATA) & ~mask;
- csio_wr_reg32(hw, val, TP_PIO_DATA);
+ csio_wr_reg32(hw, addr, TP_PIO_ADDR_A);
+ val |= csio_rd_reg32(hw, TP_PIO_DATA_A) & ~mask;
+ csio_wr_reg32(hw, val, TP_PIO_DATA_A);
}
void
@@ -256,7 +231,7 @@ csio_hw_seeprom_read(struct csio_hw *hw, uint32_t addr, uint32_t *data)
}
pci_read_config_dword(hw->pdev, base + PCI_VPD_DATA, data);
- *data = le32_to_cpu(*data);
+ *data = le32_to_cpu(*(__le32 *)data);
return 0;
}
@@ -421,17 +396,15 @@ csio_hw_sf1_read(struct csio_hw *hw, uint32_t byte_cnt, int32_t cont,
if (!byte_cnt || byte_cnt > 4)
return -EINVAL;
- if (csio_rd_reg32(hw, SF_OP) & SF_BUSY)
+ if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F)
return -EBUSY;
- cont = cont ? SF_CONT : 0;
- lock = lock ? SF_LOCK : 0;
-
- csio_wr_reg32(hw, lock | cont | BYTECNT(byte_cnt - 1), SF_OP);
- ret = csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS,
- 10, NULL);
+ csio_wr_reg32(hw, SF_LOCK_V(lock) | SF_CONT_V(cont) |
+ BYTECNT_V(byte_cnt - 1), SF_OP_A);
+ ret = csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS,
+ 10, NULL);
if (!ret)
- *valp = csio_rd_reg32(hw, SF_DATA);
+ *valp = csio_rd_reg32(hw, SF_DATA_A);
return ret;
}
@@ -453,16 +426,14 @@ csio_hw_sf1_write(struct csio_hw *hw, uint32_t byte_cnt, uint32_t cont,
{
if (!byte_cnt || byte_cnt > 4)
return -EINVAL;
- if (csio_rd_reg32(hw, SF_OP) & SF_BUSY)
+ if (csio_rd_reg32(hw, SF_OP_A) & SF_BUSY_F)
return -EBUSY;
- cont = cont ? SF_CONT : 0;
- lock = lock ? SF_LOCK : 0;
-
- csio_wr_reg32(hw, val, SF_DATA);
- csio_wr_reg32(hw, cont | BYTECNT(byte_cnt - 1) | OP_WR | lock, SF_OP);
+ csio_wr_reg32(hw, val, SF_DATA_A);
+ csio_wr_reg32(hw, SF_CONT_V(cont) | BYTECNT_V(byte_cnt - 1) |
+ OP_V(1) | SF_LOCK_V(lock), SF_OP_A);
- return csio_hw_wait_op_done_val(hw, SF_OP, SF_BUSY, 0, SF_ATTEMPTS,
+ return csio_hw_wait_op_done_val(hw, SF_OP_A, SF_BUSY_F, 0, SF_ATTEMPTS,
10, NULL);
}
@@ -533,11 +504,11 @@ csio_hw_read_flash(struct csio_hw *hw, uint32_t addr, uint32_t nwords,
for ( ; nwords; nwords--, data++) {
ret = csio_hw_sf1_read(hw, 4, nwords > 1, nwords == 1, data);
if (nwords == 1)
- csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */
+ csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */
if (ret)
return ret;
if (byte_oriented)
- *data = htonl(*data);
+ *data = (__force __u32) htonl(*data);
}
return 0;
}
@@ -586,7 +557,7 @@ csio_hw_write_flash(struct csio_hw *hw, uint32_t addr,
if (ret)
goto unlock;
- csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */
+ csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */
/* Read the page to verify the write succeeded */
ret = csio_hw_read_flash(hw, addr & ~0xff, ARRAY_SIZE(buf), buf, 1);
@@ -603,7 +574,7 @@ csio_hw_write_flash(struct csio_hw *hw, uint32_t addr,
return 0;
unlock:
- csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */
+ csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */
return ret;
}
@@ -641,7 +612,7 @@ out:
if (ret)
csio_err(hw, "erase of flash sector %d failed, error %d\n",
start, ret);
- csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */
+ csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */
return 0;
}
@@ -665,7 +636,7 @@ csio_hw_print_fw_version(struct csio_hw *hw, char *str)
static int
csio_hw_get_fw_version(struct csio_hw *hw, uint32_t *vers)
{
- return csio_hw_read_flash(hw, FW_IMG_START +
+ return csio_hw_read_flash(hw, FLASH_FW_START +
offsetof(struct fw_hdr, fw_ver), 1,
vers, 0);
}
@@ -686,43 +657,6 @@ csio_hw_get_tp_version(struct csio_hw *hw, u32 *vers)
}
/*
- * csio_hw_check_fw_version - check if the FW is compatible with
- * this driver
- * @hw: HW module
- *
- * Checks if an adapter's FW is compatible with the driver. Returns 0
- * if there's exact match, a negative error if the version could not be
- * read or there's a major/minor version mismatch/minor.
- */
-static int
-csio_hw_check_fw_version(struct csio_hw *hw)
-{
- int ret, major, minor, micro;
-
- ret = csio_hw_get_fw_version(hw, &hw->fwrev);
- if (!ret)
- ret = csio_hw_get_tp_version(hw, &hw->tp_vers);
- if (ret)
- return ret;
-
- major = FW_HDR_FW_VER_MAJOR_G(hw->fwrev);
- minor = FW_HDR_FW_VER_MINOR_G(hw->fwrev);
- micro = FW_HDR_FW_VER_MICRO_G(hw->fwrev);
-
- if (major != FW_VERSION_MAJOR(hw)) { /* major mismatch - fail */
- csio_err(hw, "card FW has major version %u, driver wants %u\n",
- major, FW_VERSION_MAJOR(hw));
- return -EINVAL;
- }
-
- if (minor == FW_VERSION_MINOR(hw) && micro == FW_VERSION_MICRO(hw))
- return 0; /* perfect match */
-
- /* Minor/micro version mismatch */
- return -EINVAL;
-}
-
-/*
* csio_hw_fw_dload - download firmware.
* @hw: HW module
* @fw_data: firmware image to write.
@@ -762,9 +696,9 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size)
return -EINVAL;
}
- if (size > FW_MAX_SIZE) {
+ if (size > FLASH_FW_MAX_SIZE) {
csio_err(hw, "FW image too large, max is %u bytes\n",
- FW_MAX_SIZE);
+ FLASH_FW_MAX_SIZE);
return -EINVAL;
}
@@ -780,10 +714,10 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size)
i = DIV_ROUND_UP(size, sf_sec_size); /* # of sectors spanned */
csio_dbg(hw, "Erasing sectors... start:%d end:%d\n",
- FW_START_SEC, FW_START_SEC + i - 1);
+ FLASH_FW_START_SEC, FLASH_FW_START_SEC + i - 1);
- ret = csio_hw_flash_erase_sectors(hw, FW_START_SEC,
- FW_START_SEC + i - 1);
+ ret = csio_hw_flash_erase_sectors(hw, FLASH_FW_START_SEC,
+ FLASH_FW_START_SEC + i - 1);
if (ret) {
csio_err(hw, "Flash Erase failed\n");
goto out;
@@ -796,14 +730,14 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size)
*/
memcpy(first_page, fw_data, SF_PAGE_SIZE);
((struct fw_hdr *)first_page)->fw_ver = htonl(0xffffffff);
- ret = csio_hw_write_flash(hw, FW_IMG_START, SF_PAGE_SIZE, first_page);
+ ret = csio_hw_write_flash(hw, FLASH_FW_START, SF_PAGE_SIZE, first_page);
if (ret)
goto out;
csio_dbg(hw, "Writing Flash .. start:%d end:%d\n",
FW_IMG_START, FW_IMG_START + size);
- addr = FW_IMG_START;
+ addr = FLASH_FW_START;
for (size -= SF_PAGE_SIZE; size; size -= SF_PAGE_SIZE) {
addr += SF_PAGE_SIZE;
fw_data += SF_PAGE_SIZE;
@@ -813,7 +747,7 @@ csio_hw_fw_dload(struct csio_hw *hw, uint8_t *fw_data, uint32_t size)
}
ret = csio_hw_write_flash(hw,
- FW_IMG_START +
+ FLASH_FW_START +
offsetof(struct fw_hdr, fw_ver),
sizeof(hdr->fw_ver),
(const uint8_t *)&hdr->fw_ver);
@@ -833,7 +767,7 @@ csio_hw_get_flash_params(struct csio_hw *hw)
ret = csio_hw_sf1_write(hw, 1, 1, 0, SF_RD_ID);
if (!ret)
ret = csio_hw_sf1_read(hw, 3, 0, 1, &info);
- csio_wr_reg32(hw, 0, SF_OP); /* unlock SF */
+ csio_wr_reg32(hw, 0, SF_OP_A); /* unlock SF */
if (ret != 0)
return ret;
@@ -861,17 +795,17 @@ csio_hw_dev_ready(struct csio_hw *hw)
uint32_t reg;
int cnt = 6;
- while (((reg = csio_rd_reg32(hw, PL_WHOAMI)) == 0xFFFFFFFF) &&
- (--cnt != 0))
+ while (((reg = csio_rd_reg32(hw, PL_WHOAMI_A)) == 0xFFFFFFFF) &&
+ (--cnt != 0))
mdelay(100);
- if ((cnt == 0) && (((int32_t)(SOURCEPF_GET(reg)) < 0) ||
- (SOURCEPF_GET(reg) >= CSIO_MAX_PFN))) {
+ if ((cnt == 0) && (((int32_t)(SOURCEPF_G(reg)) < 0) ||
+ (SOURCEPF_G(reg) >= CSIO_MAX_PFN))) {
csio_err(hw, "PL_WHOAMI returned 0x%x, cnt:%d\n", reg, cnt);
return -EIO;
}
- hw->pfn = SOURCEPF_GET(reg);
+ hw->pfn = SOURCEPF_G(reg);
return 0;
}
@@ -959,8 +893,8 @@ retry:
* timeout ... and then retry if we haven't exhausted
* our retries ...
*/
- pcie_fw = csio_rd_reg32(hw, PCIE_FW);
- if (!(pcie_fw & (PCIE_FW_ERR|PCIE_FW_INIT))) {
+ pcie_fw = csio_rd_reg32(hw, PCIE_FW_A);
+ if (!(pcie_fw & (PCIE_FW_ERR_F|PCIE_FW_INIT_F))) {
if (waiting <= 0) {
if (retries-- > 0)
goto retry;
@@ -976,10 +910,10 @@ retry:
* report errors preferentially.
*/
if (state) {
- if (pcie_fw & PCIE_FW_ERR) {
+ if (pcie_fw & PCIE_FW_ERR_F) {
*state = CSIO_DEV_STATE_ERR;
rv = -ETIMEDOUT;
- } else if (pcie_fw & PCIE_FW_INIT)
+ } else if (pcie_fw & PCIE_FW_INIT_F)
*state = CSIO_DEV_STATE_INIT;
}
@@ -988,9 +922,9 @@ retry:
* there's not a valid Master PF, grab its identity
* for our caller.
*/
- if (mpfn == PCIE_FW_MASTER_MASK &&
- (pcie_fw & PCIE_FW_MASTER_VLD))
- mpfn = PCIE_FW_MASTER_GET(pcie_fw);
+ if (mpfn == PCIE_FW_MASTER_M &&
+ (pcie_fw & PCIE_FW_MASTER_VLD_F))
+ mpfn = PCIE_FW_MASTER_G(pcie_fw);
break;
}
hw->flags &= ~CSIO_HWF_MASTER;
@@ -1078,7 +1012,7 @@ csio_do_reset(struct csio_hw *hw, bool fw_rst)
if (!fw_rst) {
/* PIO reset */
- csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST);
+ csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A);
mdelay(2000);
return 0;
}
@@ -1090,7 +1024,7 @@ csio_do_reset(struct csio_hw *hw, bool fw_rst)
}
csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO,
- PIORSTMODE | PIORST, 0, NULL);
+ PIORSTMODE_F | PIORST_F, 0, NULL);
if (csio_mb_issue(hw, mbp)) {
csio_err(hw, "Issue of RESET command failed.n");
@@ -1156,7 +1090,7 @@ csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force)
* If a legitimate mailbox is provided, issue a RESET command
* with a HALT indication.
*/
- if (mbox <= PCIE_FW_MASTER_MASK) {
+ if (mbox <= PCIE_FW_MASTER_M) {
struct csio_mb *mbp;
mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
@@ -1166,7 +1100,7 @@ csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force)
}
csio_mb_reset(hw, mbp, CSIO_MB_DEFAULT_TMO,
- PIORSTMODE | PIORST, FW_RESET_CMD_HALT_F,
+ PIORSTMODE_F | PIORST_F, FW_RESET_CMD_HALT_F,
NULL);
if (csio_mb_issue(hw, mbp)) {
@@ -1193,8 +1127,9 @@ csio_hw_fw_halt(struct csio_hw *hw, uint32_t mbox, int32_t force)
* rather than a RESET ... if it's new enough to understand that ...
*/
if (retval == 0 || force) {
- csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, UPCRST);
- csio_set_reg_field(hw, PCIE_FW, PCIE_FW_HALT, PCIE_FW_HALT);
+ csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, UPCRST_F);
+ csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F,
+ PCIE_FW_HALT_F);
}
/*
@@ -1234,7 +1169,7 @@ csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset)
* doing it automatically, we need to clear the PCIE_FW.HALT
* bit.
*/
- csio_set_reg_field(hw, PCIE_FW, PCIE_FW_HALT, 0);
+ csio_set_reg_field(hw, PCIE_FW_A, PCIE_FW_HALT_F, 0);
/*
* If we've been given a valid mailbox, first try to get the
@@ -1243,21 +1178,21 @@ csio_hw_fw_restart(struct csio_hw *hw, uint32_t mbox, int32_t reset)
* valid mailbox or the RESET command failed, fall back to
* hitting the chip with a hammer.
*/
- if (mbox <= PCIE_FW_MASTER_MASK) {
- csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, 0);
+ if (mbox <= PCIE_FW_MASTER_M) {
+ csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0);
msleep(100);
if (csio_do_reset(hw, true) == 0)
return 0;
}
- csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST);
+ csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A);
msleep(2000);
} else {
int ms;
- csio_set_reg_field(hw, CIM_BOOT_CFG, UPCRST, 0);
+ csio_set_reg_field(hw, CIM_BOOT_CFG_A, UPCRST_F, 0);
for (ms = 0; ms < FW_CMD_MAX_TIMEOUT; ) {
- if (!(csio_rd_reg32(hw, PCIE_FW) & PCIE_FW_HALT))
+ if (!(csio_rd_reg32(hw, PCIE_FW_A) & PCIE_FW_HALT_F))
return 0;
msleep(100);
ms += 100;
@@ -1315,116 +1250,6 @@ csio_hw_fw_upgrade(struct csio_hw *hw, uint32_t mbox,
return csio_hw_fw_restart(hw, mbox, reset);
}
-
-/*
- * csio_hw_fw_config_file - setup an adapter via a Configuration File
- * @hw: the HW module
- * @mbox: mailbox to use for the FW command
- * @mtype: the memory type where the Configuration File is located
- * @maddr: the memory address where the Configuration File is located
- * @finiver: return value for CF [fini] version
- * @finicsum: return value for CF [fini] checksum
- * @cfcsum: return value for CF computed checksum
- *
- * Issue a command to get the firmware to process the Configuration
- * File located at the specified mtype/maddress. If the Configuration
- * File is processed successfully and return value pointers are
- * provided, the Configuration File "[fini] section version and
- * checksum values will be returned along with the computed checksum.
- * It's up to the caller to decide how it wants to respond to the
- * checksums not matching but it recommended that a prominant warning
- * be emitted in order to help people rapidly identify changed or
- * corrupted Configuration Files.
- *
- * Also note that it's possible to modify things like "niccaps",
- * "toecaps",etc. between processing the Configuration File and telling
- * the firmware to use the new configuration. Callers which want to
- * do this will need to "hand-roll" their own CAPS_CONFIGS commands for
- * Configuration Files if they want to do this.
- */
-static int
-csio_hw_fw_config_file(struct csio_hw *hw,
- unsigned int mtype, unsigned int maddr,
- uint32_t *finiver, uint32_t *finicsum, uint32_t *cfcsum)
-{
- struct csio_mb *mbp;
- struct fw_caps_config_cmd *caps_cmd;
- int rv = -EINVAL;
- enum fw_retval ret;
-
- mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
- if (!mbp) {
- CSIO_INC_STATS(hw, n_err_nomem);
- return -ENOMEM;
- }
- /*
- * Tell the firmware to process the indicated Configuration File.
- * If there are no errors and the caller has provided return value
- * pointers for the [fini] section version, checksum and computed
- * checksum, pass those back to the caller.
- */
- caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb);
- CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1);
- caps_cmd->op_to_write =
- htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST_F |
- FW_CMD_READ_F);
- caps_cmd->cfvalid_to_len16 =
- htonl(FW_CAPS_CONFIG_CMD_CFVALID_F |
- FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) |
- FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) |
- FW_LEN16(*caps_cmd));
-
- if (csio_mb_issue(hw, mbp)) {
- csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n");
- goto out;
- }
-
- ret = csio_mb_fw_retval(mbp);
- if (ret != FW_SUCCESS) {
- csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv);
- goto out;
- }
-
- if (finiver)
- *finiver = ntohl(caps_cmd->finiver);
- if (finicsum)
- *finicsum = ntohl(caps_cmd->finicsum);
- if (cfcsum)
- *cfcsum = ntohl(caps_cmd->cfcsum);
-
- /* Validate device capabilities */
- if (csio_hw_validate_caps(hw, mbp)) {
- rv = -ENOENT;
- goto out;
- }
-
- /*
- * And now tell the firmware to use the configuration we just loaded.
- */
- caps_cmd->op_to_write =
- htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
- FW_CMD_REQUEST_F |
- FW_CMD_WRITE_F);
- caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd));
-
- if (csio_mb_issue(hw, mbp)) {
- csio_err(hw, "Issue of FW_CAPS_CONFIG_CMD failed!\n");
- goto out;
- }
-
- ret = csio_mb_fw_retval(mbp);
- if (ret != FW_SUCCESS) {
- csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv);
- goto out;
- }
-
- rv = 0;
-out:
- mempool_free(mbp, hw->mb_mempool);
- return rv;
-}
-
/*
* csio_get_device_params - Get device parameters.
* @hw: HW module
@@ -1547,7 +1372,8 @@ csio_config_device_caps(struct csio_hw *hw)
}
/* Validate device capabilities */
- if (csio_hw_validate_caps(hw, mbp))
+ rv = csio_hw_validate_caps(hw, mbp);
+ if (rv != 0)
goto out;
/* Don't config device capabilities if already configured */
@@ -1756,9 +1582,9 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
uint32_t *cfg_data;
int value_to_add = 0;
- if (request_firmware(&cf, CSIO_CF_FNAME(hw), dev) < 0) {
+ if (request_firmware(&cf, FW_CFG_NAME_T5, dev) < 0) {
csio_err(hw, "could not find config file %s, err: %d\n",
- CSIO_CF_FNAME(hw), ret);
+ FW_CFG_NAME_T5, ret);
return -ENOENT;
}
@@ -1798,8 +1624,8 @@ csio_hw_flash_config(struct csio_hw *hw, u32 *fw_cfg_param, char *path)
}
if (ret == 0) {
csio_info(hw, "config file upgraded to %s\n",
- CSIO_CF_FNAME(hw));
- snprintf(path, 64, "%s%s", "/lib/firmware/", CSIO_CF_FNAME(hw));
+ FW_CFG_NAME_T5);
+ snprintf(path, 64, "%s%s", "/lib/firmware/", FW_CFG_NAME_T5);
}
leave:
@@ -1827,11 +1653,13 @@ leave:
static int
csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
{
+ struct csio_mb *mbp = NULL;
+ struct fw_caps_config_cmd *caps_cmd;
unsigned int mtype, maddr;
- int rv;
+ int rv = -EINVAL;
uint32_t finiver = 0, finicsum = 0, cfcsum = 0;
- int using_flash;
char path[64];
+ char *config_name = NULL;
/*
* Reset device if necessary
@@ -1851,51 +1679,107 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
rv = csio_hw_flash_config(hw, fw_cfg_param, path);
spin_lock_irq(&hw->lock);
if (rv != 0) {
- if (rv == -ENOENT) {
- /*
- * config file was not found. Use default
- * config file from flash.
- */
- mtype = FW_MEMTYPE_CF_FLASH;
- maddr = hw->chip_ops->chip_flash_cfg_addr(hw);
- using_flash = 1;
- } else {
- /*
- * we revert back to the hardwired config if
- * flashing failed.
- */
- goto bye;
- }
+ /*
+ * config file was not found. Use default
+ * config file from flash.
+ */
+ config_name = "On FLASH";
+ mtype = FW_MEMTYPE_CF_FLASH;
+ maddr = hw->chip_ops->chip_flash_cfg_addr(hw);
} else {
+ config_name = path;
mtype = FW_PARAMS_PARAM_Y_G(*fw_cfg_param);
maddr = FW_PARAMS_PARAM_Z_G(*fw_cfg_param) << 16;
- using_flash = 0;
}
- hw->cfg_store = (uint8_t)mtype;
+ mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
+ if (!mbp) {
+ CSIO_INC_STATS(hw, n_err_nomem);
+ return -ENOMEM;
+ }
+ /*
+ * Tell the firmware to process the indicated Configuration File.
+ * If there are no errors and the caller has provided return value
+ * pointers for the [fini] section version, checksum and computed
+ * checksum, pass those back to the caller.
+ */
+ caps_cmd = (struct fw_caps_config_cmd *)(mbp->mb);
+ CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1);
+ caps_cmd->op_to_write =
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
+ caps_cmd->cfvalid_to_len16 =
+ htonl(FW_CAPS_CONFIG_CMD_CFVALID_F |
+ FW_CAPS_CONFIG_CMD_MEMTYPE_CF_V(mtype) |
+ FW_CAPS_CONFIG_CMD_MEMADDR64K_CF_V(maddr >> 16) |
+ FW_LEN16(*caps_cmd));
+
+ if (csio_mb_issue(hw, mbp)) {
+ rv = -EINVAL;
+ goto bye;
+ }
+
+ rv = csio_mb_fw_retval(mbp);
+ /* If the CAPS_CONFIG failed with an ENOENT (for a Firmware
+ * Configuration File in FLASH), our last gasp effort is to use the
+ * Firmware Configuration File which is embedded in the
+ * firmware. A very few early versions of the firmware didn't
+ * have one embedded but we can ignore those.
+ */
+ if (rv == ENOENT) {
+ CSIO_INIT_MBP(mbp, caps_cmd, CSIO_MB_DEFAULT_TMO, hw, NULL, 1);
+ caps_cmd->op_to_write = htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_READ_F);
+ caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd));
+
+ if (csio_mb_issue(hw, mbp)) {
+ rv = -EINVAL;
+ goto bye;
+ }
+
+ rv = csio_mb_fw_retval(mbp);
+ config_name = "Firmware Default";
+ }
+ if (rv != FW_SUCCESS)
+ goto bye;
+
+ finiver = ntohl(caps_cmd->finiver);
+ finicsum = ntohl(caps_cmd->finicsum);
+ cfcsum = ntohl(caps_cmd->cfcsum);
/*
- * Issue a Capability Configuration command to the firmware to get it
- * to parse the Configuration File.
+ * And now tell the firmware to use the configuration we just loaded.
*/
- rv = csio_hw_fw_config_file(hw, mtype, maddr, &finiver,
- &finicsum, &cfcsum);
- if (rv != 0)
+ caps_cmd->op_to_write =
+ htonl(FW_CMD_OP_V(FW_CAPS_CONFIG_CMD) |
+ FW_CMD_REQUEST_F |
+ FW_CMD_WRITE_F);
+ caps_cmd->cfvalid_to_len16 = htonl(FW_LEN16(*caps_cmd));
+
+ if (csio_mb_issue(hw, mbp)) {
+ rv = -EINVAL;
goto bye;
+ }
- hw->cfg_finiver = finiver;
- hw->cfg_finicsum = finicsum;
- hw->cfg_cfcsum = cfcsum;
- hw->cfg_csum_status = true;
+ rv = csio_mb_fw_retval(mbp);
+ if (rv != FW_SUCCESS) {
+ csio_dbg(hw, "FW_CAPS_CONFIG_CMD returned %d!\n", rv);
+ goto bye;
+ }
+ mempool_free(mbp, hw->mb_mempool);
if (finicsum != cfcsum) {
csio_warn(hw,
"Config File checksum mismatch: csum=%#x, computed=%#x\n",
finicsum, cfcsum);
-
- hw->cfg_csum_status = false;
}
+ /* Validate device capabilities */
+ rv = csio_hw_validate_caps(hw, mbp);
+ if (rv != 0)
+ goto bye;
/*
* Note that we're operating with parameters
* not supplied by the driver, rather than from hard-wired
@@ -1918,56 +1802,184 @@ csio_hw_use_fwconfig(struct csio_hw *hw, int reset, u32 *fw_cfg_param)
/* Post event to notify completion of configuration */
csio_post_event(&hw->sm, CSIO_HWE_INIT);
- csio_info(hw,
- "Firmware Configuration File %s, version %#x, computed checksum %#x\n",
- (using_flash ? "in device FLASH" : path), finiver, cfcsum);
-
+ csio_info(hw, "Successfully configure using Firmware "
+ "Configuration File %s, version %#x, computed checksum %#x\n",
+ config_name, finiver, cfcsum);
return 0;
/*
* Something bad happened. Return the error ...
*/
bye:
+ if (mbp)
+ mempool_free(mbp, hw->mb_mempool);
hw->flags &= ~CSIO_HWF_USING_SOFT_PARAMS;
- csio_dbg(hw, "Configuration file error %d\n", rv);
+ csio_warn(hw, "Configuration file error %d\n", rv);
return rv;
}
-/*
- * Attempt to initialize the adapter via hard-coded, driver supplied
- * parameters ...
+/* Is the given firmware API compatible with the one the driver was compiled
+ * with?
*/
-static int
-csio_hw_no_fwconfig(struct csio_hw *hw, int reset)
+static int fw_compatible(const struct fw_hdr *hdr1, const struct fw_hdr *hdr2)
{
- int rv;
- /*
- * Reset device if necessary
- */
- if (reset) {
- rv = csio_do_reset(hw, true);
- if (rv != 0)
- goto out;
+
+ /* short circuit if it's the exact same firmware version */
+ if (hdr1->chip == hdr2->chip && hdr1->fw_ver == hdr2->fw_ver)
+ return 1;
+
+#define SAME_INTF(x) (hdr1->intfver_##x == hdr2->intfver_##x)
+ if (hdr1->chip == hdr2->chip && SAME_INTF(nic) && SAME_INTF(vnic) &&
+ SAME_INTF(ri) && SAME_INTF(iscsi) && SAME_INTF(fcoe))
+ return 1;
+#undef SAME_INTF
+
+ return 0;
+}
+
+/* The firmware in the filesystem is usable, but should it be installed?
+ * This routine explains itself in detail if it indicates the filesystem
+ * firmware should be installed.
+ */
+static int csio_should_install_fs_fw(struct csio_hw *hw, int card_fw_usable,
+ int k, int c)
+{
+ const char *reason;
+
+ if (!card_fw_usable) {
+ reason = "incompatible or unusable";
+ goto install;
}
- /* Get and set device capabilities */
- rv = csio_config_device_caps(hw);
- if (rv != 0)
- goto out;
+ if (k > c) {
+ reason = "older than the version supported with this driver";
+ goto install;
+ }
- /* device parameters */
- rv = csio_get_device_params(hw);
- if (rv != 0)
- goto out;
+ return 0;
- /* Configure SGE */
- csio_wr_sge_init(hw);
+install:
+ csio_err(hw, "firmware on card (%u.%u.%u.%u) is %s, "
+ "installing firmware %u.%u.%u.%u on card.\n",
+ FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c),
+ FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c), reason,
+ FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
+ FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
- /* Post event to notify completion of configuration */
- csio_post_event(&hw->sm, CSIO_HWE_INIT);
+ return 1;
+}
-out:
- return rv;
+static struct fw_info fw_info_array[] = {
+ {
+ .chip = CHELSIO_T5,
+ .fs_name = FW_CFG_NAME_T5,
+ .fw_mod_name = FW_FNAME_T5,
+ .fw_hdr = {
+ .chip = FW_HDR_CHIP_T5,
+ .fw_ver = __cpu_to_be32(FW_VERSION(T5)),
+ .intfver_nic = FW_INTFVER(T5, NIC),
+ .intfver_vnic = FW_INTFVER(T5, VNIC),
+ .intfver_ri = FW_INTFVER(T5, RI),
+ .intfver_iscsi = FW_INTFVER(T5, ISCSI),
+ .intfver_fcoe = FW_INTFVER(T5, FCOE),
+ },
+ }
+};
+
+static struct fw_info *find_fw_info(int chip)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fw_info_array); i++) {
+ if (fw_info_array[i].chip == chip)
+ return &fw_info_array[i];
+ }
+ return NULL;
+}
+
+static int csio_hw_prep_fw(struct csio_hw *hw, struct fw_info *fw_info,
+ const u8 *fw_data, unsigned int fw_size,
+ struct fw_hdr *card_fw, enum csio_dev_state state,
+ int *reset)
+{
+ int ret, card_fw_usable, fs_fw_usable;
+ const struct fw_hdr *fs_fw;
+ const struct fw_hdr *drv_fw;
+
+ drv_fw = &fw_info->fw_hdr;
+
+ /* Read the header of the firmware on the card */
+ ret = csio_hw_read_flash(hw, FLASH_FW_START,
+ sizeof(*card_fw) / sizeof(uint32_t),
+ (uint32_t *)card_fw, 1);
+ if (ret == 0) {
+ card_fw_usable = fw_compatible(drv_fw, (const void *)card_fw);
+ } else {
+ csio_err(hw,
+ "Unable to read card's firmware header: %d\n", ret);
+ card_fw_usable = 0;
+ }
+
+ if (fw_data != NULL) {
+ fs_fw = (const void *)fw_data;
+ fs_fw_usable = fw_compatible(drv_fw, fs_fw);
+ } else {
+ fs_fw = NULL;
+ fs_fw_usable = 0;
+ }
+
+ if (card_fw_usable && card_fw->fw_ver == drv_fw->fw_ver &&
+ (!fs_fw_usable || fs_fw->fw_ver == drv_fw->fw_ver)) {
+ /* Common case: the firmware on the card is an exact match and
+ * the filesystem one is an exact match too, or the filesystem
+ * one is absent/incompatible.
+ */
+ } else if (fs_fw_usable && state == CSIO_DEV_STATE_UNINIT &&
+ csio_should_install_fs_fw(hw, card_fw_usable,
+ be32_to_cpu(fs_fw->fw_ver),
+ be32_to_cpu(card_fw->fw_ver))) {
+ ret = csio_hw_fw_upgrade(hw, hw->pfn, fw_data,
+ fw_size, 0);
+ if (ret != 0) {
+ csio_err(hw,
+ "failed to install firmware: %d\n", ret);
+ goto bye;
+ }
+
+ /* Installed successfully, update the cached header too. */
+ memcpy(card_fw, fs_fw, sizeof(*card_fw));
+ card_fw_usable = 1;
+ *reset = 0; /* already reset as part of load_fw */
+ }
+
+ if (!card_fw_usable) {
+ uint32_t d, c, k;
+
+ d = be32_to_cpu(drv_fw->fw_ver);
+ c = be32_to_cpu(card_fw->fw_ver);
+ k = fs_fw ? be32_to_cpu(fs_fw->fw_ver) : 0;
+
+ csio_err(hw, "Cannot find a usable firmware: "
+ "chip state %d, "
+ "driver compiled with %d.%d.%d.%d, "
+ "card has %d.%d.%d.%d, filesystem has %d.%d.%d.%d\n",
+ state,
+ FW_HDR_FW_VER_MAJOR_G(d), FW_HDR_FW_VER_MINOR_G(d),
+ FW_HDR_FW_VER_MICRO_G(d), FW_HDR_FW_VER_BUILD_G(d),
+ FW_HDR_FW_VER_MAJOR_G(c), FW_HDR_FW_VER_MINOR_G(c),
+ FW_HDR_FW_VER_MICRO_G(c), FW_HDR_FW_VER_BUILD_G(c),
+ FW_HDR_FW_VER_MAJOR_G(k), FW_HDR_FW_VER_MINOR_G(k),
+ FW_HDR_FW_VER_MICRO_G(k), FW_HDR_FW_VER_BUILD_G(k));
+ ret = EINVAL;
+ goto bye;
+ }
+
+ /* We're using whatever's on the card and it's known to be good. */
+ hw->fwrev = be32_to_cpu(card_fw->fw_ver);
+ hw->tp_vers = be32_to_cpu(card_fw->tp_microcode_ver);
+
+bye:
+ return ret;
}
/*
@@ -1977,48 +1989,52 @@ out:
* latest firmware ECANCELED is returned
*/
static int
-csio_hw_flash_fw(struct csio_hw *hw)
+csio_hw_flash_fw(struct csio_hw *hw, int *reset)
{
int ret = -ECANCELED;
const struct firmware *fw;
- const struct fw_hdr *hdr;
- u32 fw_ver;
+ struct fw_info *fw_info;
+ struct fw_hdr *card_fw;
struct pci_dev *pci_dev = hw->pdev;
struct device *dev = &pci_dev->dev ;
+ const u8 *fw_data = NULL;
+ unsigned int fw_size = 0;
- if (request_firmware(&fw, CSIO_FW_FNAME(hw), dev) < 0) {
- csio_err(hw, "could not find firmware image %s, err: %d\n",
- CSIO_FW_FNAME(hw), ret);
+ /* This is the firmware whose headers the driver was compiled
+ * against
+ */
+ fw_info = find_fw_info(CHELSIO_CHIP_VERSION(hw->chip_id));
+ if (fw_info == NULL) {
+ csio_err(hw,
+ "unable to get firmware info for chip %d.\n",
+ CHELSIO_CHIP_VERSION(hw->chip_id));
return -EINVAL;
}
- hdr = (const struct fw_hdr *)fw->data;
- fw_ver = ntohl(hdr->fw_ver);
- if (FW_HDR_FW_VER_MAJOR_G(fw_ver) != FW_VERSION_MAJOR(hw))
- return -EINVAL; /* wrong major version, won't do */
+ if (request_firmware(&fw, FW_FNAME_T5, dev) < 0) {
+ csio_err(hw, "could not find firmware image %s, err: %d\n",
+ FW_FNAME_T5, ret);
+ } else {
+ fw_data = fw->data;
+ fw_size = fw->size;
+ }
- /*
- * If the flash FW is unusable or we found something newer, load it.
+ /* allocate memory to read the header of the firmware on the
+ * card
*/
- if (FW_HDR_FW_VER_MAJOR_G(hw->fwrev) != FW_VERSION_MAJOR(hw) ||
- fw_ver > hw->fwrev) {
- ret = csio_hw_fw_upgrade(hw, hw->pfn, fw->data, fw->size,
- /*force=*/false);
- if (!ret)
- csio_info(hw,
- "firmware upgraded to version %pI4 from %s\n",
- &hdr->fw_ver, CSIO_FW_FNAME(hw));
- else
- csio_err(hw, "firmware upgrade failed! err=%d\n", ret);
- } else
- ret = -EINVAL;
+ card_fw = kmalloc(sizeof(*card_fw), GFP_KERNEL);
- release_firmware(fw);
+ /* upgrade FW logic */
+ ret = csio_hw_prep_fw(hw, fw_info, fw_data, fw_size, card_fw,
+ hw->fw_state, reset);
+ /* Cleaning up */
+ if (fw != NULL)
+ release_firmware(fw);
+ kfree(card_fw);
return ret;
}
-
/*
* csio_hw_configure - Configure HW
* @hw - HW module
@@ -2039,7 +2055,7 @@ csio_hw_configure(struct csio_hw *hw)
}
/* HW version */
- hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV);
+ hw->chip_ver = (char)csio_rd_reg32(hw, PL_REV_A);
/* Needed for FW download */
rv = csio_hw_get_flash_params(hw);
@@ -2074,50 +2090,43 @@ csio_hw_configure(struct csio_hw *hw)
if (rv != 0)
goto out;
+ csio_hw_get_fw_version(hw, &hw->fwrev);
+ csio_hw_get_tp_version(hw, &hw->tp_vers);
if (csio_is_hw_master(hw) && hw->fw_state != CSIO_DEV_STATE_INIT) {
- rv = csio_hw_check_fw_version(hw);
- if (rv == -EINVAL) {
/* Do firmware update */
- spin_unlock_irq(&hw->lock);
- rv = csio_hw_flash_fw(hw);
- spin_lock_irq(&hw->lock);
+ spin_unlock_irq(&hw->lock);
+ rv = csio_hw_flash_fw(hw, &reset);
+ spin_lock_irq(&hw->lock);
- if (rv == 0) {
- reset = 0;
- /*
- * Note that the chip was reset as part of the
- * firmware upgrade so we don't reset it again
- * below and grab the new firmware version.
- */
- rv = csio_hw_check_fw_version(hw);
- }
- }
- /*
- * If the firmware doesn't support Configuration
- * Files, use the old Driver-based, hard-wired
- * initialization. Otherwise, try using the
- * Configuration File support and fall back to the
- * Driver-based initialization if there's no
- * Configuration File found.
+ if (rv != 0)
+ goto out;
+
+ /* If the firmware doesn't support Configuration Files,
+ * return an error.
*/
- if (csio_hw_check_fwconfig(hw, param) == 0) {
- rv = csio_hw_use_fwconfig(hw, reset, param);
- if (rv == -ENOENT)
- goto out;
- if (rv != 0) {
- csio_info(hw,
- "No Configuration File present "
- "on adapter. Using hard-wired "
- "configuration parameters.\n");
- rv = csio_hw_no_fwconfig(hw, reset);
- }
- } else {
- rv = csio_hw_no_fwconfig(hw, reset);
+ rv = csio_hw_check_fwconfig(hw, param);
+ if (rv != 0) {
+ csio_info(hw, "Firmware doesn't support "
+ "Firmware Configuration files\n");
+ goto out;
}
- if (rv != 0)
+ /* The firmware provides us with a memory buffer where we can
+ * load a Configuration File from the host if we want to
+ * override the Configuration File in flash.
+ */
+ rv = csio_hw_use_fwconfig(hw, reset, param);
+ if (rv == -ENOENT) {
+ csio_info(hw, "Could not initialize "
+ "adapter, error%d\n", rv);
+ goto out;
+ }
+ if (rv != 0) {
+ csio_info(hw, "Could not initialize "
+ "adapter, error%d\n", rv);
goto out;
+ }
} else {
if (hw->fw_state == CSIO_DEV_STATE_INIT) {
@@ -2217,7 +2226,7 @@ out:
return;
}
-#define PF_INTR_MASK (PFSW | PFCIM)
+#define PF_INTR_MASK (PFSW_F | PFCIM_F)
/*
* csio_hw_intr_enable - Enable HW interrupts
@@ -2229,21 +2238,21 @@ static void
csio_hw_intr_enable(struct csio_hw *hw)
{
uint16_t vec = (uint16_t)csio_get_mb_intr_idx(csio_hw_to_mbm(hw));
- uint32_t pf = SOURCEPF_GET(csio_rd_reg32(hw, PL_WHOAMI));
- uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE);
+ uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
+ uint32_t pl = csio_rd_reg32(hw, PL_INT_ENABLE_A);
/*
* Set aivec for MSI/MSIX. PCIE_PF_CFG.INTXType is set up
* by FW, so do nothing for INTX.
*/
if (hw->intr_mode == CSIO_IM_MSIX)
- csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG),
- AIVEC(AIVEC_MASK), vec);
+ csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A),
+ AIVEC_V(AIVEC_M), vec);
else if (hw->intr_mode == CSIO_IM_MSI)
- csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG),
- AIVEC(AIVEC_MASK), 0);
+ csio_set_reg_field(hw, MYPF_REG(PCIE_PF_CFG_A),
+ AIVEC_V(AIVEC_M), 0);
- csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE));
+ csio_wr_reg32(hw, PF_INTR_MASK, MYPF_REG(PL_PF_INT_ENABLE_A));
/* Turn on MB interrupts - this will internally flush PIO as well */
csio_mb_intr_enable(hw);
@@ -2253,19 +2262,19 @@ csio_hw_intr_enable(struct csio_hw *hw)
/*
* Disable the Serial FLASH interrupt, if enabled!
*/
- pl &= (~SF);
- csio_wr_reg32(hw, pl, PL_INT_ENABLE);
+ pl &= (~SF_F);
+ csio_wr_reg32(hw, pl, PL_INT_ENABLE_A);
- csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE |
- EGRESS_SIZE_ERR | ERR_INVALID_CIDX_INC |
- ERR_CPL_OPCODE_0 | ERR_DROPPED_DB |
- ERR_DATA_CPL_ON_HIGH_QID1 |
- ERR_DATA_CPL_ON_HIGH_QID0 | ERR_BAD_DB_PIDX3 |
- ERR_BAD_DB_PIDX2 | ERR_BAD_DB_PIDX1 |
- ERR_BAD_DB_PIDX0 | ERR_ING_CTXT_PRIO |
- ERR_EGR_CTXT_PRIO | INGRESS_SIZE_ERR,
- SGE_INT_ENABLE3);
- csio_set_reg_field(hw, PL_INT_MAP0, 0, 1 << pf);
+ csio_wr_reg32(hw, ERR_CPL_EXCEED_IQE_SIZE_F |
+ EGRESS_SIZE_ERR_F | ERR_INVALID_CIDX_INC_F |
+ ERR_CPL_OPCODE_0_F | ERR_DROPPED_DB_F |
+ ERR_DATA_CPL_ON_HIGH_QID1_F |
+ ERR_DATA_CPL_ON_HIGH_QID0_F | ERR_BAD_DB_PIDX3_F |
+ ERR_BAD_DB_PIDX2_F | ERR_BAD_DB_PIDX1_F |
+ ERR_BAD_DB_PIDX0_F | ERR_ING_CTXT_PRIO_F |
+ ERR_EGR_CTXT_PRIO_F | INGRESS_SIZE_ERR_F,
+ SGE_INT_ENABLE3_A);
+ csio_set_reg_field(hw, PL_INT_MAP0_A, 0, 1 << pf);
}
hw->flags |= CSIO_HWF_HW_INTR_ENABLED;
@@ -2281,16 +2290,16 @@ csio_hw_intr_enable(struct csio_hw *hw)
void
csio_hw_intr_disable(struct csio_hw *hw)
{
- uint32_t pf = SOURCEPF_GET(csio_rd_reg32(hw, PL_WHOAMI));
+ uint32_t pf = SOURCEPF_G(csio_rd_reg32(hw, PL_WHOAMI_A));
if (!(hw->flags & CSIO_HWF_HW_INTR_ENABLED))
return;
hw->flags &= ~CSIO_HWF_HW_INTR_ENABLED;
- csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE));
+ csio_wr_reg32(hw, 0, MYPF_REG(PL_PF_INT_ENABLE_A));
if (csio_is_hw_master(hw))
- csio_set_reg_field(hw, PL_INT_MAP0, 1 << pf, 0);
+ csio_set_reg_field(hw, PL_INT_MAP0_A, 1 << pf, 0);
/* Turn off MB interrupts */
csio_mb_intr_disable(hw);
@@ -2300,7 +2309,7 @@ csio_hw_intr_disable(struct csio_hw *hw)
void
csio_hw_fatal_err(struct csio_hw *hw)
{
- csio_set_reg_field(hw, SGE_CONTROL, GLOBALENABLE, 0);
+ csio_set_reg_field(hw, SGE_CONTROL_A, GLOBALENABLE_F, 0);
csio_hw_intr_disable(hw);
/* Do not reset HW, we may need FW state for debugging */
@@ -2594,7 +2603,7 @@ csio_hws_removing(struct csio_hw *hw, enum csio_hw_ev evt)
* register directly.
*/
csio_err(hw, "Resetting HW and waiting 2 seconds...\n");
- csio_wr_reg32(hw, PIORSTMODE | PIORST, PL_RST);
+ csio_wr_reg32(hw, PIORSTMODE_F | PIORST_F, PL_RST_A);
mdelay(2000);
break;
@@ -2682,11 +2691,11 @@ static void csio_tp_intr_handler(struct csio_hw *hw)
{
static struct intr_info tp_intr_info[] = {
{ 0x3fffffff, "TP parity error", -1, 1 },
- { FLMTXFLSTEMPTY, "TP out of Tx pages", -1, 1 },
+ { FLMTXFLSTEMPTY_F, "TP out of Tx pages", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, TP_INT_CAUSE, tp_intr_info))
+ if (csio_handle_intr_status(hw, TP_INT_CAUSE_A, tp_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2698,52 +2707,52 @@ static void csio_sge_intr_handler(struct csio_hw *hw)
uint64_t v;
static struct intr_info sge_intr_info[] = {
- { ERR_CPL_EXCEED_IQE_SIZE,
+ { ERR_CPL_EXCEED_IQE_SIZE_F,
"SGE received CPL exceeding IQE size", -1, 1 },
- { ERR_INVALID_CIDX_INC,
+ { ERR_INVALID_CIDX_INC_F,
"SGE GTS CIDX increment too large", -1, 0 },
- { ERR_CPL_OPCODE_0, "SGE received 0-length CPL", -1, 0 },
- { ERR_DROPPED_DB, "SGE doorbell dropped", -1, 0 },
- { ERR_DATA_CPL_ON_HIGH_QID1 | ERR_DATA_CPL_ON_HIGH_QID0,
+ { ERR_CPL_OPCODE_0_F, "SGE received 0-length CPL", -1, 0 },
+ { ERR_DROPPED_DB_F, "SGE doorbell dropped", -1, 0 },
+ { ERR_DATA_CPL_ON_HIGH_QID1_F | ERR_DATA_CPL_ON_HIGH_QID0_F,
"SGE IQID > 1023 received CPL for FL", -1, 0 },
- { ERR_BAD_DB_PIDX3, "SGE DBP 3 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX3_F, "SGE DBP 3 pidx increment too large", -1,
0 },
- { ERR_BAD_DB_PIDX2, "SGE DBP 2 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX2_F, "SGE DBP 2 pidx increment too large", -1,
0 },
- { ERR_BAD_DB_PIDX1, "SGE DBP 1 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX1_F, "SGE DBP 1 pidx increment too large", -1,
0 },
- { ERR_BAD_DB_PIDX0, "SGE DBP 0 pidx increment too large", -1,
+ { ERR_BAD_DB_PIDX0_F, "SGE DBP 0 pidx increment too large", -1,
0 },
- { ERR_ING_CTXT_PRIO,
+ { ERR_ING_CTXT_PRIO_F,
"SGE too many priority ingress contexts", -1, 0 },
- { ERR_EGR_CTXT_PRIO,
+ { ERR_EGR_CTXT_PRIO_F,
"SGE too many priority egress contexts", -1, 0 },
- { INGRESS_SIZE_ERR, "SGE illegal ingress QID", -1, 0 },
- { EGRESS_SIZE_ERR, "SGE illegal egress QID", -1, 0 },
+ { INGRESS_SIZE_ERR_F, "SGE illegal ingress QID", -1, 0 },
+ { EGRESS_SIZE_ERR_F, "SGE illegal egress QID", -1, 0 },
{ 0, NULL, 0, 0 }
};
- v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1) |
- ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2) << 32);
+ v = (uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE1_A) |
+ ((uint64_t)csio_rd_reg32(hw, SGE_INT_CAUSE2_A) << 32);
if (v) {
csio_fatal(hw, "SGE parity error (%#llx)\n",
(unsigned long long)v);
csio_wr_reg32(hw, (uint32_t)(v & 0xFFFFFFFF),
- SGE_INT_CAUSE1);
- csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2);
+ SGE_INT_CAUSE1_A);
+ csio_wr_reg32(hw, (uint32_t)(v >> 32), SGE_INT_CAUSE2_A);
}
- v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3, sge_intr_info);
+ v |= csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info);
- if (csio_handle_intr_status(hw, SGE_INT_CAUSE3, sge_intr_info) ||
+ if (csio_handle_intr_status(hw, SGE_INT_CAUSE3_A, sge_intr_info) ||
v != 0)
csio_hw_fatal_err(hw);
}
-#define CIM_OBQ_INTR (OBQULP0PARERR | OBQULP1PARERR | OBQULP2PARERR |\
- OBQULP3PARERR | OBQSGEPARERR | OBQNCSIPARERR)
-#define CIM_IBQ_INTR (IBQTP0PARERR | IBQTP1PARERR | IBQULPPARERR |\
- IBQSGEHIPARERR | IBQSGELOPARERR | IBQNCSIPARERR)
+#define CIM_OBQ_INTR (OBQULP0PARERR_F | OBQULP1PARERR_F | OBQULP2PARERR_F |\
+ OBQULP3PARERR_F | OBQSGEPARERR_F | OBQNCSIPARERR_F)
+#define CIM_IBQ_INTR (IBQTP0PARERR_F | IBQTP1PARERR_F | IBQULPPARERR_F |\
+ IBQSGEHIPARERR_F | IBQSGELOPARERR_F | IBQNCSIPARERR_F)
/*
* CIM interrupt handler.
@@ -2751,53 +2760,53 @@ static void csio_sge_intr_handler(struct csio_hw *hw)
static void csio_cim_intr_handler(struct csio_hw *hw)
{
static struct intr_info cim_intr_info[] = {
- { PREFDROPINT, "CIM control register prefetch drop", -1, 1 },
+ { PREFDROPINT_F, "CIM control register prefetch drop", -1, 1 },
{ CIM_OBQ_INTR, "CIM OBQ parity error", -1, 1 },
{ CIM_IBQ_INTR, "CIM IBQ parity error", -1, 1 },
- { MBUPPARERR, "CIM mailbox uP parity error", -1, 1 },
- { MBHOSTPARERR, "CIM mailbox host parity error", -1, 1 },
- { TIEQINPARERRINT, "CIM TIEQ outgoing parity error", -1, 1 },
- { TIEQOUTPARERRINT, "CIM TIEQ incoming parity error", -1, 1 },
+ { MBUPPARERR_F, "CIM mailbox uP parity error", -1, 1 },
+ { MBHOSTPARERR_F, "CIM mailbox host parity error", -1, 1 },
+ { TIEQINPARERRINT_F, "CIM TIEQ outgoing parity error", -1, 1 },
+ { TIEQOUTPARERRINT_F, "CIM TIEQ incoming parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
static struct intr_info cim_upintr_info[] = {
- { RSVDSPACEINT, "CIM reserved space access", -1, 1 },
- { ILLTRANSINT, "CIM illegal transaction", -1, 1 },
- { ILLWRINT, "CIM illegal write", -1, 1 },
- { ILLRDINT, "CIM illegal read", -1, 1 },
- { ILLRDBEINT, "CIM illegal read BE", -1, 1 },
- { ILLWRBEINT, "CIM illegal write BE", -1, 1 },
- { SGLRDBOOTINT, "CIM single read from boot space", -1, 1 },
- { SGLWRBOOTINT, "CIM single write to boot space", -1, 1 },
- { BLKWRBOOTINT, "CIM block write to boot space", -1, 1 },
- { SGLRDFLASHINT, "CIM single read from flash space", -1, 1 },
- { SGLWRFLASHINT, "CIM single write to flash space", -1, 1 },
- { BLKWRFLASHINT, "CIM block write to flash space", -1, 1 },
- { SGLRDEEPROMINT, "CIM single EEPROM read", -1, 1 },
- { SGLWREEPROMINT, "CIM single EEPROM write", -1, 1 },
- { BLKRDEEPROMINT, "CIM block EEPROM read", -1, 1 },
- { BLKWREEPROMINT, "CIM block EEPROM write", -1, 1 },
- { SGLRDCTLINT , "CIM single read from CTL space", -1, 1 },
- { SGLWRCTLINT , "CIM single write to CTL space", -1, 1 },
- { BLKRDCTLINT , "CIM block read from CTL space", -1, 1 },
- { BLKWRCTLINT , "CIM block write to CTL space", -1, 1 },
- { SGLRDPLINT , "CIM single read from PL space", -1, 1 },
- { SGLWRPLINT , "CIM single write to PL space", -1, 1 },
- { BLKRDPLINT , "CIM block read from PL space", -1, 1 },
- { BLKWRPLINT , "CIM block write to PL space", -1, 1 },
- { REQOVRLOOKUPINT , "CIM request FIFO overwrite", -1, 1 },
- { RSPOVRLOOKUPINT , "CIM response FIFO overwrite", -1, 1 },
- { TIMEOUTINT , "CIM PIF timeout", -1, 1 },
- { TIMEOUTMAINT , "CIM PIF MA timeout", -1, 1 },
+ { RSVDSPACEINT_F, "CIM reserved space access", -1, 1 },
+ { ILLTRANSINT_F, "CIM illegal transaction", -1, 1 },
+ { ILLWRINT_F, "CIM illegal write", -1, 1 },
+ { ILLRDINT_F, "CIM illegal read", -1, 1 },
+ { ILLRDBEINT_F, "CIM illegal read BE", -1, 1 },
+ { ILLWRBEINT_F, "CIM illegal write BE", -1, 1 },
+ { SGLRDBOOTINT_F, "CIM single read from boot space", -1, 1 },
+ { SGLWRBOOTINT_F, "CIM single write to boot space", -1, 1 },
+ { BLKWRBOOTINT_F, "CIM block write to boot space", -1, 1 },
+ { SGLRDFLASHINT_F, "CIM single read from flash space", -1, 1 },
+ { SGLWRFLASHINT_F, "CIM single write to flash space", -1, 1 },
+ { BLKWRFLASHINT_F, "CIM block write to flash space", -1, 1 },
+ { SGLRDEEPROMINT_F, "CIM single EEPROM read", -1, 1 },
+ { SGLWREEPROMINT_F, "CIM single EEPROM write", -1, 1 },
+ { BLKRDEEPROMINT_F, "CIM block EEPROM read", -1, 1 },
+ { BLKWREEPROMINT_F, "CIM block EEPROM write", -1, 1 },
+ { SGLRDCTLINT_F, "CIM single read from CTL space", -1, 1 },
+ { SGLWRCTLINT_F, "CIM single write to CTL space", -1, 1 },
+ { BLKRDCTLINT_F, "CIM block read from CTL space", -1, 1 },
+ { BLKWRCTLINT_F, "CIM block write to CTL space", -1, 1 },
+ { SGLRDPLINT_F, "CIM single read from PL space", -1, 1 },
+ { SGLWRPLINT_F, "CIM single write to PL space", -1, 1 },
+ { BLKRDPLINT_F, "CIM block read from PL space", -1, 1 },
+ { BLKWRPLINT_F, "CIM block write to PL space", -1, 1 },
+ { REQOVRLOOKUPINT_F, "CIM request FIFO overwrite", -1, 1 },
+ { RSPOVRLOOKUPINT_F, "CIM response FIFO overwrite", -1, 1 },
+ { TIMEOUTINT_F, "CIM PIF timeout", -1, 1 },
+ { TIMEOUTMAINT_F, "CIM PIF MA timeout", -1, 1 },
{ 0, NULL, 0, 0 }
};
int fat;
- fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE,
- cim_intr_info) +
- csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE,
- cim_upintr_info);
+ fat = csio_handle_intr_status(hw, CIM_HOST_INT_CAUSE_A,
+ cim_intr_info) +
+ csio_handle_intr_status(hw, CIM_HOST_UPACC_INT_CAUSE_A,
+ cim_upintr_info);
if (fat)
csio_hw_fatal_err(hw);
}
@@ -2813,7 +2822,7 @@ static void csio_ulprx_intr_handler(struct csio_hw *hw)
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE, ulprx_intr_info))
+ if (csio_handle_intr_status(hw, ULP_RX_INT_CAUSE_A, ulprx_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2823,19 +2832,19 @@ static void csio_ulprx_intr_handler(struct csio_hw *hw)
static void csio_ulptx_intr_handler(struct csio_hw *hw)
{
static struct intr_info ulptx_intr_info[] = {
- { PBL_BOUND_ERR_CH3, "ULPTX channel 3 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH3_F, "ULPTX channel 3 PBL out of bounds", -1,
0 },
- { PBL_BOUND_ERR_CH2, "ULPTX channel 2 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH2_F, "ULPTX channel 2 PBL out of bounds", -1,
0 },
- { PBL_BOUND_ERR_CH1, "ULPTX channel 1 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH1_F, "ULPTX channel 1 PBL out of bounds", -1,
0 },
- { PBL_BOUND_ERR_CH0, "ULPTX channel 0 PBL out of bounds", -1,
+ { PBL_BOUND_ERR_CH0_F, "ULPTX channel 0 PBL out of bounds", -1,
0 },
{ 0xfffffff, "ULPTX parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE, ulptx_intr_info))
+ if (csio_handle_intr_status(hw, ULP_TX_INT_CAUSE_A, ulptx_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2845,20 +2854,20 @@ static void csio_ulptx_intr_handler(struct csio_hw *hw)
static void csio_pmtx_intr_handler(struct csio_hw *hw)
{
static struct intr_info pmtx_intr_info[] = {
- { PCMD_LEN_OVFL0, "PMTX channel 0 pcmd too large", -1, 1 },
- { PCMD_LEN_OVFL1, "PMTX channel 1 pcmd too large", -1, 1 },
- { PCMD_LEN_OVFL2, "PMTX channel 2 pcmd too large", -1, 1 },
- { ZERO_C_CMD_ERROR, "PMTX 0-length pcmd", -1, 1 },
+ { PCMD_LEN_OVFL0_F, "PMTX channel 0 pcmd too large", -1, 1 },
+ { PCMD_LEN_OVFL1_F, "PMTX channel 1 pcmd too large", -1, 1 },
+ { PCMD_LEN_OVFL2_F, "PMTX channel 2 pcmd too large", -1, 1 },
+ { ZERO_C_CMD_ERROR_F, "PMTX 0-length pcmd", -1, 1 },
{ 0xffffff0, "PMTX framing error", -1, 1 },
- { OESPI_PAR_ERROR, "PMTX oespi parity error", -1, 1 },
- { DB_OPTIONS_PAR_ERROR, "PMTX db_options parity error", -1,
+ { OESPI_PAR_ERROR_F, "PMTX oespi parity error", -1, 1 },
+ { DB_OPTIONS_PAR_ERROR_F, "PMTX db_options parity error", -1,
1 },
- { ICSPI_PAR_ERROR, "PMTX icspi parity error", -1, 1 },
- { C_PCMD_PAR_ERROR, "PMTX c_pcmd parity error", -1, 1},
+ { ICSPI_PAR_ERROR_F, "PMTX icspi parity error", -1, 1 },
+ { PMTX_C_PCMD_PAR_ERROR_F, "PMTX c_pcmd parity error", -1, 1},
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE, pmtx_intr_info))
+ if (csio_handle_intr_status(hw, PM_TX_INT_CAUSE_A, pmtx_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2868,17 +2877,17 @@ static void csio_pmtx_intr_handler(struct csio_hw *hw)
static void csio_pmrx_intr_handler(struct csio_hw *hw)
{
static struct intr_info pmrx_intr_info[] = {
- { ZERO_E_CMD_ERROR, "PMRX 0-length pcmd", -1, 1 },
+ { ZERO_E_CMD_ERROR_F, "PMRX 0-length pcmd", -1, 1 },
{ 0x3ffff0, "PMRX framing error", -1, 1 },
- { OCSPI_PAR_ERROR, "PMRX ocspi parity error", -1, 1 },
- { DB_OPTIONS_PAR_ERROR, "PMRX db_options parity error", -1,
+ { OCSPI_PAR_ERROR_F, "PMRX ocspi parity error", -1, 1 },
+ { DB_OPTIONS_PAR_ERROR_F, "PMRX db_options parity error", -1,
1 },
- { IESPI_PAR_ERROR, "PMRX iespi parity error", -1, 1 },
- { E_PCMD_PAR_ERROR, "PMRX e_pcmd parity error", -1, 1},
+ { IESPI_PAR_ERROR_F, "PMRX iespi parity error", -1, 1 },
+ { PMRX_E_PCMD_PAR_ERROR_F, "PMRX e_pcmd parity error", -1, 1},
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE, pmrx_intr_info))
+ if (csio_handle_intr_status(hw, PM_RX_INT_CAUSE_A, pmrx_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2888,16 +2897,16 @@ static void csio_pmrx_intr_handler(struct csio_hw *hw)
static void csio_cplsw_intr_handler(struct csio_hw *hw)
{
static struct intr_info cplsw_intr_info[] = {
- { CIM_OP_MAP_PERR, "CPLSW CIM op_map parity error", -1, 1 },
- { CIM_OVFL_ERROR, "CPLSW CIM overflow", -1, 1 },
- { TP_FRAMING_ERROR, "CPLSW TP framing error", -1, 1 },
- { SGE_FRAMING_ERROR, "CPLSW SGE framing error", -1, 1 },
- { CIM_FRAMING_ERROR, "CPLSW CIM framing error", -1, 1 },
- { ZERO_SWITCH_ERROR, "CPLSW no-switch error", -1, 1 },
+ { CIM_OP_MAP_PERR_F, "CPLSW CIM op_map parity error", -1, 1 },
+ { CIM_OVFL_ERROR_F, "CPLSW CIM overflow", -1, 1 },
+ { TP_FRAMING_ERROR_F, "CPLSW TP framing error", -1, 1 },
+ { SGE_FRAMING_ERROR_F, "CPLSW SGE framing error", -1, 1 },
+ { CIM_FRAMING_ERROR_F, "CPLSW CIM framing error", -1, 1 },
+ { ZERO_SWITCH_ERROR_F, "CPLSW no-switch error", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, CPL_INTR_CAUSE, cplsw_intr_info))
+ if (csio_handle_intr_status(hw, CPL_INTR_CAUSE_A, cplsw_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2907,15 +2916,15 @@ static void csio_cplsw_intr_handler(struct csio_hw *hw)
static void csio_le_intr_handler(struct csio_hw *hw)
{
static struct intr_info le_intr_info[] = {
- { LIPMISS, "LE LIP miss", -1, 0 },
- { LIP0, "LE 0 LIP error", -1, 0 },
- { PARITYERR, "LE parity error", -1, 1 },
- { UNKNOWNCMD, "LE unknown command", -1, 1 },
- { REQQPARERR, "LE request queue parity error", -1, 1 },
+ { LIPMISS_F, "LE LIP miss", -1, 0 },
+ { LIP0_F, "LE 0 LIP error", -1, 0 },
+ { PARITYERR_F, "LE parity error", -1, 1 },
+ { UNKNOWNCMD_F, "LE unknown command", -1, 1 },
+ { REQQPARERR_F, "LE request queue parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE, le_intr_info))
+ if (csio_handle_intr_status(hw, LE_DB_INT_CAUSE_A, le_intr_info))
csio_hw_fatal_err(hw);
}
@@ -2929,19 +2938,22 @@ static void csio_mps_intr_handler(struct csio_hw *hw)
{ 0, NULL, 0, 0 }
};
static struct intr_info mps_tx_intr_info[] = {
- { TPFIFO, "MPS Tx TP FIFO parity error", -1, 1 },
- { NCSIFIFO, "MPS Tx NC-SI FIFO parity error", -1, 1 },
- { TXDATAFIFO, "MPS Tx data FIFO parity error", -1, 1 },
- { TXDESCFIFO, "MPS Tx desc FIFO parity error", -1, 1 },
- { BUBBLE, "MPS Tx underflow", -1, 1 },
- { SECNTERR, "MPS Tx SOP/EOP error", -1, 1 },
- { FRMERR, "MPS Tx framing error", -1, 1 },
+ { TPFIFO_V(TPFIFO_M), "MPS Tx TP FIFO parity error", -1, 1 },
+ { NCSIFIFO_F, "MPS Tx NC-SI FIFO parity error", -1, 1 },
+ { TXDATAFIFO_V(TXDATAFIFO_M), "MPS Tx data FIFO parity error",
+ -1, 1 },
+ { TXDESCFIFO_V(TXDESCFIFO_M), "MPS Tx desc FIFO parity error",
+ -1, 1 },
+ { BUBBLE_F, "MPS Tx underflow", -1, 1 },
+ { SECNTERR_F, "MPS Tx SOP/EOP error", -1, 1 },
+ { FRMERR_F, "MPS Tx framing error", -1, 1 },
{ 0, NULL, 0, 0 }
};
static struct intr_info mps_trc_intr_info[] = {
- { FILTMEM, "MPS TRC filter parity error", -1, 1 },
- { PKTFIFO, "MPS TRC packet FIFO parity error", -1, 1 },
- { MISCPERR, "MPS TRC misc parity error", -1, 1 },
+ { FILTMEM_V(FILTMEM_M), "MPS TRC filter parity error", -1, 1 },
+ { PKTFIFO_V(PKTFIFO_M), "MPS TRC packet FIFO parity error",
+ -1, 1 },
+ { MISCPERR_F, "MPS TRC misc parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
static struct intr_info mps_stat_sram_intr_info[] = {
@@ -2957,36 +2969,37 @@ static void csio_mps_intr_handler(struct csio_hw *hw)
{ 0, NULL, 0, 0 }
};
static struct intr_info mps_cls_intr_info[] = {
- { MATCHSRAM, "MPS match SRAM parity error", -1, 1 },
- { MATCHTCAM, "MPS match TCAM parity error", -1, 1 },
- { HASHSRAM, "MPS hash SRAM parity error", -1, 1 },
+ { MATCHSRAM_F, "MPS match SRAM parity error", -1, 1 },
+ { MATCHTCAM_F, "MPS match TCAM parity error", -1, 1 },
+ { HASHSRAM_F, "MPS hash SRAM parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
int fat;
- fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE,
- mps_rx_intr_info) +
- csio_handle_intr_status(hw, MPS_TX_INT_CAUSE,
- mps_tx_intr_info) +
- csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE,
- mps_trc_intr_info) +
- csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM,
- mps_stat_sram_intr_info) +
- csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO,
- mps_stat_tx_intr_info) +
- csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO,
- mps_stat_rx_intr_info) +
- csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE,
- mps_cls_intr_info);
-
- csio_wr_reg32(hw, 0, MPS_INT_CAUSE);
- csio_rd_reg32(hw, MPS_INT_CAUSE); /* flush */
+ fat = csio_handle_intr_status(hw, MPS_RX_PERR_INT_CAUSE_A,
+ mps_rx_intr_info) +
+ csio_handle_intr_status(hw, MPS_TX_INT_CAUSE_A,
+ mps_tx_intr_info) +
+ csio_handle_intr_status(hw, MPS_TRC_INT_CAUSE_A,
+ mps_trc_intr_info) +
+ csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_SRAM_A,
+ mps_stat_sram_intr_info) +
+ csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_TX_FIFO_A,
+ mps_stat_tx_intr_info) +
+ csio_handle_intr_status(hw, MPS_STAT_PERR_INT_CAUSE_RX_FIFO_A,
+ mps_stat_rx_intr_info) +
+ csio_handle_intr_status(hw, MPS_CLS_INT_CAUSE_A,
+ mps_cls_intr_info);
+
+ csio_wr_reg32(hw, 0, MPS_INT_CAUSE_A);
+ csio_rd_reg32(hw, MPS_INT_CAUSE_A); /* flush */
if (fat)
csio_hw_fatal_err(hw);
}
-#define MEM_INT_MASK (PERR_INT_CAUSE | ECC_CE_INT_CAUSE | ECC_UE_INT_CAUSE)
+#define MEM_INT_MASK (PERR_INT_CAUSE_F | ECC_CE_INT_CAUSE_F | \
+ ECC_UE_INT_CAUSE_F)
/*
* EDC/MC interrupt handler.
@@ -2998,28 +3011,28 @@ static void csio_mem_intr_handler(struct csio_hw *hw, int idx)
unsigned int addr, cnt_addr, v;
if (idx <= MEM_EDC1) {
- addr = EDC_REG(EDC_INT_CAUSE, idx);
- cnt_addr = EDC_REG(EDC_ECC_STATUS, idx);
+ addr = EDC_REG(EDC_INT_CAUSE_A, idx);
+ cnt_addr = EDC_REG(EDC_ECC_STATUS_A, idx);
} else {
- addr = MC_INT_CAUSE;
- cnt_addr = MC_ECC_STATUS;
+ addr = MC_INT_CAUSE_A;
+ cnt_addr = MC_ECC_STATUS_A;
}
v = csio_rd_reg32(hw, addr) & MEM_INT_MASK;
- if (v & PERR_INT_CAUSE)
+ if (v & PERR_INT_CAUSE_F)
csio_fatal(hw, "%s FIFO parity error\n", name[idx]);
- if (v & ECC_CE_INT_CAUSE) {
- uint32_t cnt = ECC_CECNT_GET(csio_rd_reg32(hw, cnt_addr));
+ if (v & ECC_CE_INT_CAUSE_F) {
+ uint32_t cnt = ECC_CECNT_G(csio_rd_reg32(hw, cnt_addr));
- csio_wr_reg32(hw, ECC_CECNT_MASK, cnt_addr);
+ csio_wr_reg32(hw, ECC_CECNT_V(ECC_CECNT_M), cnt_addr);
csio_warn(hw, "%u %s correctable ECC data error%s\n",
cnt, name[idx], cnt > 1 ? "s" : "");
}
- if (v & ECC_UE_INT_CAUSE)
+ if (v & ECC_UE_INT_CAUSE_F)
csio_fatal(hw, "%s uncorrectable ECC data error\n", name[idx]);
csio_wr_reg32(hw, v, addr);
- if (v & (PERR_INT_CAUSE | ECC_UE_INT_CAUSE))
+ if (v & (PERR_INT_CAUSE_F | ECC_UE_INT_CAUSE_F))
csio_hw_fatal_err(hw);
}
@@ -3028,18 +3041,18 @@ static void csio_mem_intr_handler(struct csio_hw *hw, int idx)
*/
static void csio_ma_intr_handler(struct csio_hw *hw)
{
- uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE);
+ uint32_t v, status = csio_rd_reg32(hw, MA_INT_CAUSE_A);
- if (status & MEM_PERR_INT_CAUSE)
+ if (status & MEM_PERR_INT_CAUSE_F)
csio_fatal(hw, "MA parity error, parity status %#x\n",
- csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS));
- if (status & MEM_WRAP_INT_CAUSE) {
- v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS);
+ csio_rd_reg32(hw, MA_PARITY_ERROR_STATUS_A));
+ if (status & MEM_WRAP_INT_CAUSE_F) {
+ v = csio_rd_reg32(hw, MA_INT_WRAP_STATUS_A);
csio_fatal(hw,
"MA address wrap-around error by client %u to address %#x\n",
- MEM_WRAP_CLIENT_NUM_GET(v), MEM_WRAP_ADDRESS_GET(v) << 4);
+ MEM_WRAP_CLIENT_NUM_G(v), MEM_WRAP_ADDRESS_G(v) << 4);
}
- csio_wr_reg32(hw, status, MA_INT_CAUSE);
+ csio_wr_reg32(hw, status, MA_INT_CAUSE_A);
csio_hw_fatal_err(hw);
}
@@ -3049,13 +3062,13 @@ static void csio_ma_intr_handler(struct csio_hw *hw)
static void csio_smb_intr_handler(struct csio_hw *hw)
{
static struct intr_info smb_intr_info[] = {
- { MSTTXFIFOPARINT, "SMB master Tx FIFO parity error", -1, 1 },
- { MSTRXFIFOPARINT, "SMB master Rx FIFO parity error", -1, 1 },
- { SLVFIFOPARINT, "SMB slave FIFO parity error", -1, 1 },
+ { MSTTXFIFOPARINT_F, "SMB master Tx FIFO parity error", -1, 1 },
+ { MSTRXFIFOPARINT_F, "SMB master Rx FIFO parity error", -1, 1 },
+ { SLVFIFOPARINT_F, "SMB slave FIFO parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, SMB_INT_CAUSE, smb_intr_info))
+ if (csio_handle_intr_status(hw, SMB_INT_CAUSE_A, smb_intr_info))
csio_hw_fatal_err(hw);
}
@@ -3065,14 +3078,14 @@ static void csio_smb_intr_handler(struct csio_hw *hw)
static void csio_ncsi_intr_handler(struct csio_hw *hw)
{
static struct intr_info ncsi_intr_info[] = {
- { CIM_DM_PRTY_ERR, "NC-SI CIM parity error", -1, 1 },
- { MPS_DM_PRTY_ERR, "NC-SI MPS parity error", -1, 1 },
- { TXFIFO_PRTY_ERR, "NC-SI Tx FIFO parity error", -1, 1 },
- { RXFIFO_PRTY_ERR, "NC-SI Rx FIFO parity error", -1, 1 },
+ { CIM_DM_PRTY_ERR_F, "NC-SI CIM parity error", -1, 1 },
+ { MPS_DM_PRTY_ERR_F, "NC-SI MPS parity error", -1, 1 },
+ { TXFIFO_PRTY_ERR_F, "NC-SI Tx FIFO parity error", -1, 1 },
+ { RXFIFO_PRTY_ERR_F, "NC-SI Rx FIFO parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, NCSI_INT_CAUSE, ncsi_intr_info))
+ if (csio_handle_intr_status(hw, NCSI_INT_CAUSE_A, ncsi_intr_info))
csio_hw_fatal_err(hw);
}
@@ -3081,17 +3094,17 @@ static void csio_ncsi_intr_handler(struct csio_hw *hw)
*/
static void csio_xgmac_intr_handler(struct csio_hw *hw, int port)
{
- uint32_t v = csio_rd_reg32(hw, CSIO_MAC_INT_CAUSE_REG(hw, port));
+ uint32_t v = csio_rd_reg32(hw, T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A));
- v &= TXFIFO_PRTY_ERR | RXFIFO_PRTY_ERR;
+ v &= TXFIFO_PRTY_ERR_F | RXFIFO_PRTY_ERR_F;
if (!v)
return;
- if (v & TXFIFO_PRTY_ERR)
+ if (v & TXFIFO_PRTY_ERR_F)
csio_fatal(hw, "XGMAC %d Tx FIFO parity error\n", port);
- if (v & RXFIFO_PRTY_ERR)
+ if (v & RXFIFO_PRTY_ERR_F)
csio_fatal(hw, "XGMAC %d Rx FIFO parity error\n", port);
- csio_wr_reg32(hw, v, CSIO_MAC_INT_CAUSE_REG(hw, port));
+ csio_wr_reg32(hw, v, T5_PORT_REG(port, MAC_PORT_INT_CAUSE_A));
csio_hw_fatal_err(hw);
}
@@ -3101,12 +3114,12 @@ static void csio_xgmac_intr_handler(struct csio_hw *hw, int port)
static void csio_pl_intr_handler(struct csio_hw *hw)
{
static struct intr_info pl_intr_info[] = {
- { FATALPERR, "T4 fatal parity error", -1, 1 },
- { PERRVFID, "PL VFID_MAP parity error", -1, 1 },
+ { FATALPERR_F, "T4 fatal parity error", -1, 1 },
+ { PERRVFID_F, "PL VFID_MAP parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
- if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE, pl_intr_info))
+ if (csio_handle_intr_status(hw, PL_PL_INT_CAUSE_A, pl_intr_info))
csio_hw_fatal_err(hw);
}
@@ -3121,7 +3134,7 @@ static void csio_pl_intr_handler(struct csio_hw *hw)
int
csio_hw_slow_intr_handler(struct csio_hw *hw)
{
- uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE);
+ uint32_t cause = csio_rd_reg32(hw, PL_INT_CAUSE_A);
if (!(cause & CSIO_GLBL_INTR_MASK)) {
CSIO_INC_STATS(hw, n_plint_unexp);
@@ -3132,75 +3145,75 @@ csio_hw_slow_intr_handler(struct csio_hw *hw)
CSIO_INC_STATS(hw, n_plint_cnt);
- if (cause & CIM)
+ if (cause & CIM_F)
csio_cim_intr_handler(hw);
- if (cause & MPS)
+ if (cause & MPS_F)
csio_mps_intr_handler(hw);
- if (cause & NCSI)
+ if (cause & NCSI_F)
csio_ncsi_intr_handler(hw);
- if (cause & PL)
+ if (cause & PL_F)
csio_pl_intr_handler(hw);
- if (cause & SMB)
+ if (cause & SMB_F)
csio_smb_intr_handler(hw);
- if (cause & XGMAC0)
+ if (cause & XGMAC0_F)
csio_xgmac_intr_handler(hw, 0);
- if (cause & XGMAC1)
+ if (cause & XGMAC1_F)
csio_xgmac_intr_handler(hw, 1);
- if (cause & XGMAC_KR0)
+ if (cause & XGMAC_KR0_F)
csio_xgmac_intr_handler(hw, 2);
- if (cause & XGMAC_KR1)
+ if (cause & XGMAC_KR1_F)
csio_xgmac_intr_handler(hw, 3);
- if (cause & PCIE)
+ if (cause & PCIE_F)
hw->chip_ops->chip_pcie_intr_handler(hw);
- if (cause & MC)
+ if (cause & MC_F)
csio_mem_intr_handler(hw, MEM_MC);
- if (cause & EDC0)
+ if (cause & EDC0_F)
csio_mem_intr_handler(hw, MEM_EDC0);
- if (cause & EDC1)
+ if (cause & EDC1_F)
csio_mem_intr_handler(hw, MEM_EDC1);
- if (cause & LE)
+ if (cause & LE_F)
csio_le_intr_handler(hw);
- if (cause & TP)
+ if (cause & TP_F)
csio_tp_intr_handler(hw);
- if (cause & MA)
+ if (cause & MA_F)
csio_ma_intr_handler(hw);
- if (cause & PM_TX)
+ if (cause & PM_TX_F)
csio_pmtx_intr_handler(hw);
- if (cause & PM_RX)
+ if (cause & PM_RX_F)
csio_pmrx_intr_handler(hw);
- if (cause & ULP_RX)
+ if (cause & ULP_RX_F)
csio_ulprx_intr_handler(hw);
- if (cause & CPL_SWITCH)
+ if (cause & CPL_SWITCH_F)
csio_cplsw_intr_handler(hw);
- if (cause & SGE)
+ if (cause & SGE_F)
csio_sge_intr_handler(hw);
- if (cause & ULP_TX)
+ if (cause & ULP_TX_F)
csio_ulptx_intr_handler(hw);
/* Clear the interrupts just processed for which we are the master. */
- csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE);
- csio_rd_reg32(hw, PL_INT_CAUSE); /* flush */
+ csio_wr_reg32(hw, cause & CSIO_GLBL_INTR_MASK, PL_INT_CAUSE_A);
+ csio_rd_reg32(hw, PL_INT_CAUSE_A); /* flush */
return 1;
}
@@ -3840,13 +3853,7 @@ csio_hw_set_description(struct csio_hw *hw, uint16_t ven_id, uint16_t dev_id)
prot_type = (dev_id & CSIO_ASIC_DEVID_PROTO_MASK);
adap_type = (dev_id & CSIO_ASIC_DEVID_TYPE_MASK);
- if (prot_type == CSIO_T4_FCOE_ASIC) {
- memcpy(hw->hw_ver,
- csio_t4_fcoe_adapters[adap_type].model_no, 16);
- memcpy(hw->model_desc,
- csio_t4_fcoe_adapters[adap_type].description,
- 32);
- } else if (prot_type == CSIO_T5_FCOE_ASIC) {
+ if (prot_type == CSIO_T5_FCOE_ASIC) {
memcpy(hw->hw_ver,
csio_t5_fcoe_adapters[adap_type].model_no, 16);
memcpy(hw->model_desc,
@@ -3883,8 +3890,8 @@ csio_hw_init(struct csio_hw *hw)
strcpy(hw->name, CSIO_HW_NAME);
- /* Initialize the HW chip ops with T4/T5 specific ops */
- hw->chip_ops = csio_is_t4(hw->chip_id) ? &t4_ops : &t5_ops;
+ /* Initialize the HW chip ops T5 specific ops */
+ hw->chip_ops = &t5_ops;
/* Set the model & its description */
diff --git a/drivers/scsi/csiostor/csio_hw.h b/drivers/scsi/csiostor/csio_hw.h
index 68248da1b9af..029bef82c057 100644
--- a/drivers/scsi/csiostor/csio_hw.h
+++ b/drivers/scsi/csiostor/csio_hw.h
@@ -48,6 +48,7 @@
#include <scsi/scsi_device.h>
#include <scsi/scsi_transport_fc.h>
+#include "t4_hw.h"
#include "csio_hw_chip.h"
#include "csio_wr.h"
#include "csio_mb.h"
@@ -117,10 +118,10 @@ extern int csio_msi;
#define CSIO_ASIC_DEVID_PROTO_MASK 0xFF00
#define CSIO_ASIC_DEVID_TYPE_MASK 0x00FF
-#define CSIO_GLBL_INTR_MASK (CIM | MPS | PL | PCIE | MC | EDC0 | \
- EDC1 | LE | TP | MA | PM_TX | PM_RX | \
- ULP_RX | CPL_SWITCH | SGE | \
- ULP_TX | SF)
+#define CSIO_GLBL_INTR_MASK (CIM_F | MPS_F | PL_F | PCIE_F | MC_F | \
+ EDC0_F | EDC1_F | LE_F | TP_F | MA_F | \
+ PM_TX_F | PM_RX_F | ULP_RX_F | \
+ CPL_SWITCH_F | SGE_F | ULP_TX_F | SF_F)
/*
* Hard parameters used to initialize the card in the absence of a
@@ -174,16 +175,12 @@ struct csio_evt_msg {
};
enum {
- EEPROMVSIZE = 32768, /* Serial EEPROM virtual address space size */
SERNUM_LEN = 16, /* Serial # length */
EC_LEN = 16, /* E/C length */
ID_LEN = 16, /* ID length */
- TRACE_LEN = 112, /* length of trace data and mask */
};
enum {
- SF_PAGE_SIZE = 256, /* serial flash page size */
- SF_SEC_SIZE = 64 * 1024, /* serial flash sector size */
SF_SIZE = SF_SEC_SIZE * 16, /* serial flash size */
};
@@ -199,39 +196,8 @@ enum {
SF_RD_DATA_FAST = 0xb, /* read flash */
SF_RD_ID = 0x9f, /* read ID */
SF_ERASE_SECTOR = 0xd8, /* erase sector */
-
- FW_START_SEC = 8, /* first flash sector for FW */
- FW_END_SEC = 15, /* last flash sector for FW */
- FW_IMG_START = FW_START_SEC * SF_SEC_SIZE,
- FW_MAX_SIZE = (FW_END_SEC - FW_START_SEC + 1) * SF_SEC_SIZE,
-
- FLASH_CFG_MAX_SIZE = 0x10000 , /* max size of the flash config file*/
- FLASH_CFG_OFFSET = 0x1f0000,
- FLASH_CFG_START_SEC = FLASH_CFG_OFFSET / SF_SEC_SIZE,
};
-/*
- * Flash layout.
- */
-#define FLASH_START(start) ((start) * SF_SEC_SIZE)
-#define FLASH_MAX_SIZE(nsecs) ((nsecs) * SF_SEC_SIZE)
-
-enum {
- /*
- * Location of firmware image in FLASH.
- */
- FLASH_FW_START_SEC = 8,
- FLASH_FW_NSECS = 8,
- FLASH_FW_START = FLASH_START(FLASH_FW_START_SEC),
- FLASH_FW_MAX_SIZE = FLASH_MAX_SIZE(FLASH_FW_NSECS),
-
- /* Location of Firmware Configuration File in FLASH. */
- FLASH_CFG_START = FLASH_START(FLASH_CFG_START_SEC),
-};
-
-#undef FLASH_START
-#undef FLASH_MAX_SIZE
-
/* Management module */
enum {
CSIO_MGMT_EQ_WRSIZE = 512,
@@ -482,11 +448,6 @@ struct csio_hw {
uint32_t tp_vers;
char chip_ver;
uint16_t chip_id; /* Tells T4/T5 chip */
- uint32_t cfg_finiver;
- uint32_t cfg_finicsum;
- uint32_t cfg_cfcsum;
- uint8_t cfg_csum_status;
- uint8_t cfg_store;
enum csio_dev_state fw_state;
struct csio_vpd vpd;
diff --git a/drivers/scsi/csiostor/csio_hw_chip.h b/drivers/scsi/csiostor/csio_hw_chip.h
index 4752fed476df..b56a11d817be 100644
--- a/drivers/scsi/csiostor/csio_hw_chip.h
+++ b/drivers/scsi/csiostor/csio_hw_chip.h
@@ -37,24 +37,27 @@
#include "csio_defs.h"
/* Define MACRO values */
-#define CSIO_HW_T4 0x4000
-#define CSIO_T4_FCOE_ASIC 0x4600
#define CSIO_HW_T5 0x5000
#define CSIO_T5_FCOE_ASIC 0x5600
#define CSIO_HW_CHIP_MASK 0xF000
-#define T4_REGMAP_SIZE (160 * 1024)
#define T5_REGMAP_SIZE (332 * 1024)
-#define FW_FNAME_T4 "cxgb4/t4fw.bin"
#define FW_FNAME_T5 "cxgb4/t5fw.bin"
-#define FW_CFG_NAME_T4 "cxgb4/t4-config.txt"
#define FW_CFG_NAME_T5 "cxgb4/t5-config.txt"
-/* Define static functions */
-static inline int csio_is_t4(uint16_t chip)
-{
- return (chip == CSIO_HW_T4);
-}
+#define CHELSIO_CHIP_CODE(version, revision) (((version) << 4) | (revision))
+#define CHELSIO_CHIP_FPGA 0x100
+#define CHELSIO_CHIP_VERSION(code) (((code) >> 12) & 0xf)
+#define CHELSIO_CHIP_RELEASE(code) ((code) & 0xf)
+
+#define CHELSIO_T5 0x5
+
+enum chip_type {
+ T5_A0 = CHELSIO_CHIP_CODE(CHELSIO_T5, 0),
+ T5_A1 = CHELSIO_CHIP_CODE(CHELSIO_T5, 1),
+ T5_FIRST_REV = T5_A0,
+ T5_LAST_REV = T5_A1,
+};
static inline int csio_is_t5(uint16_t chip)
{
@@ -65,30 +68,22 @@ static inline int csio_is_t5(uint16_t chip)
#define CSIO_DEVICE(devid, idx) \
{ PCI_VENDOR_ID_CHELSIO, (devid), PCI_ANY_ID, PCI_ANY_ID, 0, 0, (idx) }
-#define CSIO_HW_PIDX(hw, index) \
- (csio_is_t4(hw->chip_id) ? (PIDX(index)) : \
- (PIDX_T5(index) | DBTYPE(1U)))
-
-#define CSIO_HW_LP_INT_THRESH(hw, val) \
- (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH(val)) : \
- (V_LP_INT_THRESH_T5(val)))
-
-#define CSIO_HW_M_LP_INT_THRESH(hw) \
- (csio_is_t4(hw->chip_id) ? (LP_INT_THRESH_MASK) : (M_LP_INT_THRESH_T5))
-
-#define CSIO_MAC_INT_CAUSE_REG(hw, port) \
- (csio_is_t4(hw->chip_id) ? (PORT_REG(port, XGMAC_PORT_INT_CAUSE)) : \
- (T5_PORT_REG(port, MAC_PORT_INT_CAUSE)))
-
-#define FW_VERSION_MAJOR(hw) (csio_is_t4(hw->chip_id) ? 1 : 0)
-#define FW_VERSION_MINOR(hw) (csio_is_t4(hw->chip_id) ? 2 : 0)
-#define FW_VERSION_MICRO(hw) (csio_is_t4(hw->chip_id) ? 8 : 0)
-
-#define CSIO_FW_FNAME(hw) \
- (csio_is_t4(hw->chip_id) ? FW_FNAME_T4 : FW_FNAME_T5)
-
-#define CSIO_CF_FNAME(hw) \
- (csio_is_t4(hw->chip_id) ? FW_CFG_NAME_T4 : FW_CFG_NAME_T5)
+#include "t4fw_api.h"
+#include "t4fw_version.h"
+
+#define FW_VERSION(chip) ( \
+ FW_HDR_FW_VER_MAJOR_G(chip##FW_VERSION_MAJOR) | \
+ FW_HDR_FW_VER_MINOR_G(chip##FW_VERSION_MINOR) | \
+ FW_HDR_FW_VER_MICRO_G(chip##FW_VERSION_MICRO) | \
+ FW_HDR_FW_VER_BUILD_G(chip##FW_VERSION_BUILD))
+#define FW_INTFVER(chip, intf) (FW_HDR_INTFVER_##intf)
+
+struct fw_info {
+ u8 chip;
+ char *fs_name;
+ char *fw_mod_name;
+ struct fw_hdr fw_hdr;
+};
/* Declare ENUMS */
enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 };
@@ -96,7 +91,6 @@ enum { MEM_EDC0, MEM_EDC1, MEM_MC, MEM_MC0 = MEM_MC, MEM_MC1 };
enum {
MEMWIN_APERTURE = 2048,
MEMWIN_BASE = 0x1b800,
- MEMWIN_CSIOSTOR = 6, /* PCI-e Memory Window access */
};
/* Slow path handlers */
@@ -122,7 +116,6 @@ struct csio_hw_chip_ops {
void (*chip_dfs_create_ext_mem)(struct csio_hw *);
};
-extern struct csio_hw_chip_ops t4_ops;
extern struct csio_hw_chip_ops t5_ops;
#endif /* #ifndef __CSIO_HW_CHIP_H__ */
diff --git a/drivers/scsi/csiostor/csio_hw_t4.c b/drivers/scsi/csiostor/csio_hw_t4.c
deleted file mode 100644
index 95d831857640..000000000000
--- a/drivers/scsi/csiostor/csio_hw_t4.c
+++ /dev/null
@@ -1,404 +0,0 @@
-/*
- * This file is part of the Chelsio FCoE driver for Linux.
- *
- * Copyright (c) 2008-2013 Chelsio Communications, Inc. All rights reserved.
- *
- * This software is available to you under a choice of one of two
- * licenses. You may choose to be licensed under the terms of the GNU
- * General Public License (GPL) Version 2, available from the file
- * OpenIB.org BSD license below:
- *
- * Redistribution and use in source and binary forms, with or
- * without modification, are permitted provided that the following
- * conditions are met:
- *
- * - Redistributions of source code must retain the above
- * copyright notice, this list of conditions and the following
- * - 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.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * 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 "csio_hw.h"
-#include "csio_init.h"
-
-/*
- * Return the specified PCI-E Configuration Space register from our Physical
- * Function. We try first via a Firmware LDST Command since we prefer to let
- * the firmware own all of these registers, but if that fails we go for it
- * directly ourselves.
- */
-static uint32_t
-csio_t4_read_pcie_cfg4(struct csio_hw *hw, int reg)
-{
- u32 val = 0;
- struct csio_mb *mbp;
- int rv;
- struct fw_ldst_cmd *ldst_cmd;
-
- mbp = mempool_alloc(hw->mb_mempool, GFP_ATOMIC);
- if (!mbp) {
- CSIO_INC_STATS(hw, n_err_nomem);
- pci_read_config_dword(hw->pdev, reg, &val);
- return val;
- }
-
- csio_mb_ldst(hw, mbp, CSIO_MB_DEFAULT_TMO, reg);
- rv = csio_mb_issue(hw, mbp);
-
- /*
- * If the LDST Command suucceeded, exctract the returned register
- * value. Otherwise read it directly ourself.
- */
- if (rv == 0) {
- ldst_cmd = (struct fw_ldst_cmd *)(mbp->mb);
- val = ntohl(ldst_cmd->u.pcie.data[0]);
- } else
- pci_read_config_dword(hw->pdev, reg, &val);
-
- mempool_free(mbp, hw->mb_mempool);
-
- return val;
-}
-
-static int
-csio_t4_set_mem_win(struct csio_hw *hw, uint32_t win)
-{
- u32 bar0;
- u32 mem_win_base;
-
- /*
- * Truncation intentional: we only read the bottom 32-bits of the
- * 64-bit BAR0/BAR1 ... We use the hardware backdoor mechanism to
- * read BAR0 instead of using pci_resource_start() because we could be
- * operating from within a Virtual Machine which is trapping our
- * accesses to our Configuration Space and we need to set up the PCI-E
- * Memory Window decoders with the actual addresses which will be
- * coming across the PCI-E link.
- */
- bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
- bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
-
- mem_win_base = bar0 + MEMWIN_BASE;
-
- /*
- * Set up memory window for accessing adapter memory ranges. (Read
- * back MA register to ensure that changes propagate before we attempt
- * to use the new values.)
- */
- csio_wr_reg32(hw, mem_win_base | BIR(0) |
- WINDOW(ilog2(MEMWIN_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
- csio_rd_reg32(hw,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
- return 0;
-}
-
-/*
- * Interrupt handler for the PCIE module.
- */
-static void
-csio_t4_pcie_intr_handler(struct csio_hw *hw)
-{
- static struct intr_info sysbus_intr_info[] = {
- { RNPP, "RXNP array parity error", -1, 1 },
- { RPCP, "RXPC array parity error", -1, 1 },
- { RCIP, "RXCIF array parity error", -1, 1 },
- { RCCP, "Rx completions control array parity error", -1, 1 },
- { RFTP, "RXFT array parity error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
- static struct intr_info pcie_port_intr_info[] = {
- { TPCP, "TXPC array parity error", -1, 1 },
- { TNPP, "TXNP array parity error", -1, 1 },
- { TFTP, "TXFT array parity error", -1, 1 },
- { TCAP, "TXCA array parity error", -1, 1 },
- { TCIP, "TXCIF array parity error", -1, 1 },
- { RCAP, "RXCA array parity error", -1, 1 },
- { OTDD, "outbound request TLP discarded", -1, 1 },
- { RDPE, "Rx data parity error", -1, 1 },
- { TDUE, "Tx uncorrectable data error", -1, 1 },
- { 0, NULL, 0, 0 }
- };
-
- static struct intr_info pcie_intr_info[] = {
- { MSIADDRLPERR, "MSI AddrL parity error", -1, 1 },
- { MSIADDRHPERR, "MSI AddrH parity error", -1, 1 },
- { MSIDATAPERR, "MSI data parity error", -1, 1 },
- { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
- { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
- { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
- { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
- { PIOCPLPERR, "PCI PIO completion FIFO parity error", -1, 1 },
- { PIOREQPERR, "PCI PIO request FIFO parity error", -1, 1 },
- { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
- { CCNTPERR, "PCI CMD channel count parity error", -1, 1 },
- { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
- { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
- { DCNTPERR, "PCI DMA channel count parity error", -1, 1 },
- { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
- { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
- { HCNTPERR, "PCI HMA channel count parity error", -1, 1 },
- { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
- { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
- { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
- { FIDPERR, "PCI FID parity error", -1, 1 },
- { INTXCLRPERR, "PCI INTx clear parity error", -1, 1 },
- { MATAGPERR, "PCI MA tag parity error", -1, 1 },
- { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
- { RXCPLPERR, "PCI Rx completion parity error", -1, 1 },
- { RXWRPERR, "PCI Rx write parity error", -1, 1 },
- { RPLPERR, "PCI replay buffer parity error", -1, 1 },
- { PCIESINT, "PCI core secondary fault", -1, 1 },
- { PCIEPINT, "PCI core primary fault", -1, 1 },
- { UNXSPLCPLERR, "PCI unexpected split completion error", -1,
- 0 },
- { 0, NULL, 0, 0 }
- };
-
- int fat;
- fat = csio_handle_intr_status(hw,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
- sysbus_intr_info) +
- csio_handle_intr_status(hw,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
- pcie_port_intr_info) +
- csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
- if (fat)
- csio_hw_fatal_err(hw);
-}
-
-/*
- * csio_t4_flash_cfg_addr - return the address of the flash configuration file
- * @hw: the HW module
- *
- * Return the address within the flash where the Firmware Configuration
- * File is stored.
- */
-static unsigned int
-csio_t4_flash_cfg_addr(struct csio_hw *hw)
-{
- return FLASH_CFG_OFFSET;
-}
-
-/*
- * csio_t4_mc_read - read from MC through backdoor accesses
- * @hw: the hw module
- * @idx: not used for T4 adapter
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from MC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-static int
-csio_t4_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
- uint64_t *ecc)
-{
- int i;
-
- if (csio_rd_reg32(hw, MC_BIST_CMD) & START_BIST)
- return -EBUSY;
- csio_wr_reg32(hw, addr & ~0x3fU, MC_BIST_CMD_ADDR);
- csio_wr_reg32(hw, 64, MC_BIST_CMD_LEN);
- csio_wr_reg32(hw, 0xc, MC_BIST_DATA_PATTERN);
- csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
- MC_BIST_CMD);
- i = csio_hw_wait_op_done_val(hw, MC_BIST_CMD, START_BIST,
- 0, 10, 1, NULL);
- if (i)
- return i;
-
-#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
- if (ecc)
- *ecc = csio_rd_reg64(hw, MC_DATA(16));
-#undef MC_DATA
- return 0;
-}
-
-/*
- * csio_t4_edc_read - read from EDC through backdoor accesses
- * @hw: the hw module
- * @idx: which EDC to access
- * @addr: address of first byte requested
- * @data: 64 bytes of data containing the requested address
- * @ecc: where to store the corresponding 64-bit ECC word
- *
- * Read 64 bytes of data from EDC starting at a 64-byte-aligned address
- * that covers the requested address @addr. If @parity is not %NULL it
- * is assigned the 64-bit ECC word for the read data.
- */
-static int
-csio_t4_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
- uint64_t *ecc)
-{
- int i;
-
- idx *= EDC_STRIDE;
- if (csio_rd_reg32(hw, EDC_BIST_CMD + idx) & START_BIST)
- return -EBUSY;
- csio_wr_reg32(hw, addr & ~0x3fU, EDC_BIST_CMD_ADDR + idx);
- csio_wr_reg32(hw, 64, EDC_BIST_CMD_LEN + idx);
- csio_wr_reg32(hw, 0xc, EDC_BIST_DATA_PATTERN + idx);
- csio_wr_reg32(hw, BIST_OPCODE(1) | BIST_CMD_GAP(1) | START_BIST,
- EDC_BIST_CMD + idx);
- i = csio_hw_wait_op_done_val(hw, EDC_BIST_CMD + idx, START_BIST,
- 0, 10, 1, NULL);
- if (i)
- return i;
-
-#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
-
- for (i = 15; i >= 0; i--)
- *data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
- if (ecc)
- *ecc = csio_rd_reg64(hw, EDC_DATA(16));
-#undef EDC_DATA
- return 0;
-}
-
-/*
- * csio_t4_memory_rw - read/write EDC 0, EDC 1 or MC via PCIE memory window
- * @hw: the csio_hw
- * @win: PCI-E memory Window to use
- * @mtype: memory type: MEM_EDC0, MEM_EDC1, MEM_MC0 (or MEM_MC) or MEM_MC1
- * @addr: address within indicated memory type
- * @len: amount of memory to transfer
- * @buf: host memory buffer
- * @dir: direction of transfer 1 => read, 0 => write
- *
- * Reads/writes an [almost] arbitrary memory region in the firmware: the
- * firmware memory address, length and host buffer must be aligned on
- * 32-bit boudaries. The memory is transferred as a raw byte sequence
- * from/to the firmware's memory. If this memory contains data
- * structures which contain multi-byte integers, it's the callers
- * responsibility to perform appropriate byte order conversions.
- */
-static int
-csio_t4_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
- u32 len, uint32_t *buf, int dir)
-{
- u32 pos, start, offset, memoffset, bar0;
- u32 edc_size, mc_size, mem_reg, mem_aperture, mem_base;
-
- /*
- * Argument sanity checks ...
- */
- if ((addr & 0x3) || (len & 0x3))
- return -EINVAL;
-
- /* Offset into the region of memory which is being accessed
- * MEM_EDC0 = 0
- * MEM_EDC1 = 1
- * MEM_MC = 2 -- T4
- */
- edc_size = EDRAM0_SIZE_G(csio_rd_reg32(hw, MA_EDRAM0_BAR_A));
- if (mtype != MEM_MC1)
- memoffset = (mtype * (edc_size * 1024 * 1024));
- else {
- mc_size = EXT_MEM_SIZE_G(csio_rd_reg32(hw,
- MA_EXT_MEMORY_BAR_A));
- memoffset = (MEM_MC0 * edc_size + mc_size) * 1024 * 1024;
- }
-
- /* Determine the PCIE_MEM_ACCESS_OFFSET */
- addr = addr + memoffset;
-
- /*
- * Each PCI-E Memory Window is programmed with a window size -- or
- * "aperture" -- which controls the granularity of its mapping onto
- * adapter memory. We need to grab that aperture in order to know
- * how to use the specified window. The window is also programmed
- * with the base address of the Memory Window in BAR0's address
- * space. For T4 this is an absolute PCI-E Bus Address. For T5
- * the address is relative to BAR0.
- */
- mem_reg = csio_rd_reg32(hw,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
- mem_aperture = 1 << (WINDOW(mem_reg) + 10);
- mem_base = GET_PCIEOFST(mem_reg) << 10;
-
- bar0 = csio_t4_read_pcie_cfg4(hw, PCI_BASE_ADDRESS_0);
- bar0 &= PCI_BASE_ADDRESS_MEM_MASK;
- mem_base -= bar0;
-
- start = addr & ~(mem_aperture-1);
- offset = addr - start;
-
- csio_dbg(hw, "csio_t4_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
- mem_reg, mem_aperture);
- csio_dbg(hw, "csio_t4_memory_rw: mem_base: 0x%x, mem_offset: 0x%x\n",
- mem_base, memoffset);
- csio_dbg(hw, "csio_t4_memory_rw: bar0: 0x%x, start:0x%x, offset:0x%x\n",
- bar0, start, offset);
- csio_dbg(hw, "csio_t4_memory_rw: mtype: %d, addr: 0x%x, len: %d\n",
- mtype, addr, len);
-
- for (pos = start; len > 0; pos += mem_aperture, offset = 0) {
- /*
- * Move PCI-E Memory Window to our current transfer
- * position. Read it back to ensure that changes propagate
- * before we attempt to use the new value.
- */
- csio_wr_reg32(hw, pos,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
- csio_rd_reg32(hw,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
-
- while (offset < mem_aperture && len > 0) {
- if (dir)
- *buf++ = csio_rd_reg32(hw, mem_base + offset);
- else
- csio_wr_reg32(hw, *buf++, mem_base + offset);
-
- offset += sizeof(__be32);
- len -= sizeof(__be32);
- }
- }
- return 0;
-}
-
-/*
- * csio_t4_dfs_create_ext_mem - setup debugfs for MC to read the values
- * @hw: the csio_hw
- *
- * This function creates files in the debugfs with external memory region MC.
- */
-static void
-csio_t4_dfs_create_ext_mem(struct csio_hw *hw)
-{
- u32 size;
- int i = csio_rd_reg32(hw, MA_TARGET_MEM_ENABLE_A);
-
- if (i & EXT_MEM_ENABLE_F) {
- size = csio_rd_reg32(hw, MA_EXT_MEMORY_BAR_A);
- csio_add_debugfs_mem(hw, "mc", MEM_MC,
- EXT_MEM_SIZE_G(size));
- }
-}
-
-/* T4 adapter specific function */
-struct csio_hw_chip_ops t4_ops = {
- .chip_set_mem_win = csio_t4_set_mem_win,
- .chip_pcie_intr_handler = csio_t4_pcie_intr_handler,
- .chip_flash_cfg_addr = csio_t4_flash_cfg_addr,
- .chip_mc_read = csio_t4_mc_read,
- .chip_edc_read = csio_t4_edc_read,
- .chip_memory_rw = csio_t4_memory_rw,
- .chip_dfs_create_ext_mem = csio_t4_dfs_create_ext_mem,
-};
diff --git a/drivers/scsi/csiostor/csio_hw_t5.c b/drivers/scsi/csiostor/csio_hw_t5.c
index 66e180a58718..3267f4f627c9 100644
--- a/drivers/scsi/csiostor/csio_hw_t5.c
+++ b/drivers/scsi/csiostor/csio_hw_t5.c
@@ -56,11 +56,11 @@ csio_t5_set_mem_win(struct csio_hw *hw, uint32_t win)
* back MA register to ensure that changes propagate before we attempt
* to use the new values.)
*/
- csio_wr_reg32(hw, mem_win_base | BIR(0) |
- WINDOW(ilog2(MEMWIN_APERTURE) - 10),
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ csio_wr_reg32(hw, mem_win_base | BIR_V(0) |
+ WINDOW_V(ilog2(MEMWIN_APERTURE) - 10),
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win));
csio_rd_reg32(hw,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win));
return 0;
}
@@ -72,74 +72,74 @@ static void
csio_t5_pcie_intr_handler(struct csio_hw *hw)
{
static struct intr_info sysbus_intr_info[] = {
- { RNPP, "RXNP array parity error", -1, 1 },
- { RPCP, "RXPC array parity error", -1, 1 },
- { RCIP, "RXCIF array parity error", -1, 1 },
- { RCCP, "Rx completions control array parity error", -1, 1 },
- { RFTP, "RXFT array parity error", -1, 1 },
+ { RNPP_F, "RXNP array parity error", -1, 1 },
+ { RPCP_F, "RXPC array parity error", -1, 1 },
+ { RCIP_F, "RXCIF array parity error", -1, 1 },
+ { RCCP_F, "Rx completions control array parity error", -1, 1 },
+ { RFTP_F, "RXFT array parity error", -1, 1 },
{ 0, NULL, 0, 0 }
};
static struct intr_info pcie_port_intr_info[] = {
- { TPCP, "TXPC array parity error", -1, 1 },
- { TNPP, "TXNP array parity error", -1, 1 },
- { TFTP, "TXFT array parity error", -1, 1 },
- { TCAP, "TXCA array parity error", -1, 1 },
- { TCIP, "TXCIF array parity error", -1, 1 },
- { RCAP, "RXCA array parity error", -1, 1 },
- { OTDD, "outbound request TLP discarded", -1, 1 },
- { RDPE, "Rx data parity error", -1, 1 },
- { TDUE, "Tx uncorrectable data error", -1, 1 },
+ { TPCP_F, "TXPC array parity error", -1, 1 },
+ { TNPP_F, "TXNP array parity error", -1, 1 },
+ { TFTP_F, "TXFT array parity error", -1, 1 },
+ { TCAP_F, "TXCA array parity error", -1, 1 },
+ { TCIP_F, "TXCIF array parity error", -1, 1 },
+ { RCAP_F, "RXCA array parity error", -1, 1 },
+ { OTDD_F, "outbound request TLP discarded", -1, 1 },
+ { RDPE_F, "Rx data parity error", -1, 1 },
+ { TDUE_F, "Tx uncorrectable data error", -1, 1 },
{ 0, NULL, 0, 0 }
};
static struct intr_info pcie_intr_info[] = {
- { MSTGRPPERR, "Master Response Read Queue parity error",
+ { MSTGRPPERR_F, "Master Response Read Queue parity error",
-1, 1 },
- { MSTTIMEOUTPERR, "Master Timeout FIFO parity error", -1, 1 },
- { MSIXSTIPERR, "MSI-X STI SRAM parity error", -1, 1 },
- { MSIXADDRLPERR, "MSI-X AddrL parity error", -1, 1 },
- { MSIXADDRHPERR, "MSI-X AddrH parity error", -1, 1 },
- { MSIXDATAPERR, "MSI-X data parity error", -1, 1 },
- { MSIXDIPERR, "MSI-X DI parity error", -1, 1 },
- { PIOCPLGRPPERR, "PCI PIO completion Group FIFO parity error",
+ { MSTTIMEOUTPERR_F, "Master Timeout FIFO parity error", -1, 1 },
+ { MSIXSTIPERR_F, "MSI-X STI SRAM parity error", -1, 1 },
+ { MSIXADDRLPERR_F, "MSI-X AddrL parity error", -1, 1 },
+ { MSIXADDRHPERR_F, "MSI-X AddrH parity error", -1, 1 },
+ { MSIXDATAPERR_F, "MSI-X data parity error", -1, 1 },
+ { MSIXDIPERR_F, "MSI-X DI parity error", -1, 1 },
+ { PIOCPLGRPPERR_F, "PCI PIO completion Group FIFO parity error",
-1, 1 },
- { PIOREQGRPPERR, "PCI PIO request Group FIFO parity error",
+ { PIOREQGRPPERR_F, "PCI PIO request Group FIFO parity error",
-1, 1 },
- { TARTAGPERR, "PCI PCI target tag FIFO parity error", -1, 1 },
- { MSTTAGQPERR, "PCI master tag queue parity error", -1, 1 },
- { CREQPERR, "PCI CMD channel request parity error", -1, 1 },
- { CRSPPERR, "PCI CMD channel response parity error", -1, 1 },
- { DREQWRPERR, "PCI DMA channel write request parity error",
+ { TARTAGPERR_F, "PCI PCI target tag FIFO parity error", -1, 1 },
+ { MSTTAGQPERR_F, "PCI master tag queue parity error", -1, 1 },
+ { CREQPERR_F, "PCI CMD channel request parity error", -1, 1 },
+ { CRSPPERR_F, "PCI CMD channel response parity error", -1, 1 },
+ { DREQWRPERR_F, "PCI DMA channel write request parity error",
-1, 1 },
- { DREQPERR, "PCI DMA channel request parity error", -1, 1 },
- { DRSPPERR, "PCI DMA channel response parity error", -1, 1 },
- { HREQWRPERR, "PCI HMA channel count parity error", -1, 1 },
- { HREQPERR, "PCI HMA channel request parity error", -1, 1 },
- { HRSPPERR, "PCI HMA channel response parity error", -1, 1 },
- { CFGSNPPERR, "PCI config snoop FIFO parity error", -1, 1 },
- { FIDPERR, "PCI FID parity error", -1, 1 },
- { VFIDPERR, "PCI INTx clear parity error", -1, 1 },
- { MAGRPPERR, "PCI MA group FIFO parity error", -1, 1 },
- { PIOTAGPERR, "PCI PIO tag parity error", -1, 1 },
- { IPRXHDRGRPPERR, "PCI IP Rx header group parity error",
+ { DREQPERR_F, "PCI DMA channel request parity error", -1, 1 },
+ { DRSPPERR_F, "PCI DMA channel response parity error", -1, 1 },
+ { HREQWRPERR_F, "PCI HMA channel count parity error", -1, 1 },
+ { HREQPERR_F, "PCI HMA channel request parity error", -1, 1 },
+ { HRSPPERR_F, "PCI HMA channel response parity error", -1, 1 },
+ { CFGSNPPERR_F, "PCI config snoop FIFO parity error", -1, 1 },
+ { FIDPERR_F, "PCI FID parity error", -1, 1 },
+ { VFIDPERR_F, "PCI INTx clear parity error", -1, 1 },
+ { MAGRPPERR_F, "PCI MA group FIFO parity error", -1, 1 },
+ { PIOTAGPERR_F, "PCI PIO tag parity error", -1, 1 },
+ { IPRXHDRGRPPERR_F, "PCI IP Rx header group parity error",
-1, 1 },
- { IPRXDATAGRPPERR, "PCI IP Rx data group parity error",
+ { IPRXDATAGRPPERR_F, "PCI IP Rx data group parity error",
-1, 1 },
- { RPLPERR, "PCI IP replay buffer parity error", -1, 1 },
- { IPSOTPERR, "PCI IP SOT buffer parity error", -1, 1 },
- { TRGT1GRPPERR, "PCI TRGT1 group FIFOs parity error", -1, 1 },
- { READRSPERR, "Outbound read error", -1, 0 },
+ { RPLPERR_F, "PCI IP replay buffer parity error", -1, 1 },
+ { IPSOTPERR_F, "PCI IP SOT buffer parity error", -1, 1 },
+ { TRGT1GRPPERR_F, "PCI TRGT1 group FIFOs parity error", -1, 1 },
+ { READRSPERR_F, "Outbound read error", -1, 0 },
{ 0, NULL, 0, 0 }
};
int fat;
fat = csio_handle_intr_status(hw,
- PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS,
+ PCIE_CORE_UTL_SYSTEM_BUS_AGENT_STATUS_A,
sysbus_intr_info) +
csio_handle_intr_status(hw,
- PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS,
+ PCIE_CORE_UTL_PCI_EXPRESS_PORT_STATUS_A,
pcie_port_intr_info) +
- csio_handle_intr_status(hw, PCIE_INT_CAUSE, pcie_intr_info);
+ csio_handle_intr_status(hw, PCIE_INT_CAUSE_A, pcie_intr_info);
if (fat)
csio_hw_fatal_err(hw);
}
@@ -177,25 +177,25 @@ csio_t5_mc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
uint32_t mc_bist_cmd_reg, mc_bist_cmd_addr_reg, mc_bist_cmd_len_reg;
uint32_t mc_bist_status_rdata_reg, mc_bist_data_pattern_reg;
- mc_bist_cmd_reg = MC_REG(MC_P_BIST_CMD, idx);
- mc_bist_cmd_addr_reg = MC_REG(MC_P_BIST_CMD_ADDR, idx);
- mc_bist_cmd_len_reg = MC_REG(MC_P_BIST_CMD_LEN, idx);
- mc_bist_status_rdata_reg = MC_REG(MC_P_BIST_STATUS_RDATA, idx);
- mc_bist_data_pattern_reg = MC_REG(MC_P_BIST_DATA_PATTERN, idx);
+ mc_bist_cmd_reg = MC_REG(MC_P_BIST_CMD_A, idx);
+ mc_bist_cmd_addr_reg = MC_REG(MC_P_BIST_CMD_ADDR_A, idx);
+ mc_bist_cmd_len_reg = MC_REG(MC_P_BIST_CMD_LEN_A, idx);
+ mc_bist_status_rdata_reg = MC_REG(MC_P_BIST_STATUS_RDATA_A, idx);
+ mc_bist_data_pattern_reg = MC_REG(MC_P_BIST_DATA_PATTERN_A, idx);
- if (csio_rd_reg32(hw, mc_bist_cmd_reg) & START_BIST)
+ if (csio_rd_reg32(hw, mc_bist_cmd_reg) & START_BIST_F)
return -EBUSY;
csio_wr_reg32(hw, addr & ~0x3fU, mc_bist_cmd_addr_reg);
csio_wr_reg32(hw, 64, mc_bist_cmd_len_reg);
csio_wr_reg32(hw, 0xc, mc_bist_data_pattern_reg);
- csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ csio_wr_reg32(hw, BIST_OPCODE_V(1) | START_BIST_F | BIST_CMD_GAP_V(1),
mc_bist_cmd_reg);
- i = csio_hw_wait_op_done_val(hw, mc_bist_cmd_reg, START_BIST,
+ i = csio_hw_wait_op_done_val(hw, mc_bist_cmd_reg, START_BIST_F,
0, 10, 1, NULL);
if (i)
return i;
-#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA, i)
+#define MC_DATA(i) MC_BIST_STATUS_REG(MC_BIST_STATUS_RDATA_A, i)
for (i = 15; i >= 0; i--)
*data++ = htonl(csio_rd_reg32(hw, MC_DATA(i)));
@@ -231,27 +231,27 @@ csio_t5_edc_read(struct csio_hw *hw, int idx, uint32_t addr, __be32 *data,
#define EDC_STRIDE_T5 (EDC_T51_BASE_ADDR - EDC_T50_BASE_ADDR)
#define EDC_REG_T5(reg, idx) (reg + EDC_STRIDE_T5 * idx)
- edc_bist_cmd_reg = EDC_REG_T5(EDC_H_BIST_CMD, idx);
- edc_bist_cmd_addr_reg = EDC_REG_T5(EDC_H_BIST_CMD_ADDR, idx);
- edc_bist_cmd_len_reg = EDC_REG_T5(EDC_H_BIST_CMD_LEN, idx);
- edc_bist_cmd_data_pattern = EDC_REG_T5(EDC_H_BIST_DATA_PATTERN, idx);
- edc_bist_status_rdata_reg = EDC_REG_T5(EDC_H_BIST_STATUS_RDATA, idx);
+ edc_bist_cmd_reg = EDC_REG_T5(EDC_H_BIST_CMD_A, idx);
+ edc_bist_cmd_addr_reg = EDC_REG_T5(EDC_H_BIST_CMD_ADDR_A, idx);
+ edc_bist_cmd_len_reg = EDC_REG_T5(EDC_H_BIST_CMD_LEN_A, idx);
+ edc_bist_cmd_data_pattern = EDC_REG_T5(EDC_H_BIST_DATA_PATTERN_A, idx);
+ edc_bist_status_rdata_reg = EDC_REG_T5(EDC_H_BIST_STATUS_RDATA_A, idx);
#undef EDC_REG_T5
#undef EDC_STRIDE_T5
- if (csio_rd_reg32(hw, edc_bist_cmd_reg) & START_BIST)
+ if (csio_rd_reg32(hw, edc_bist_cmd_reg) & START_BIST_F)
return -EBUSY;
csio_wr_reg32(hw, addr & ~0x3fU, edc_bist_cmd_addr_reg);
csio_wr_reg32(hw, 64, edc_bist_cmd_len_reg);
csio_wr_reg32(hw, 0xc, edc_bist_cmd_data_pattern);
- csio_wr_reg32(hw, BIST_OPCODE(1) | START_BIST | BIST_CMD_GAP(1),
+ csio_wr_reg32(hw, BIST_OPCODE_V(1) | START_BIST_F | BIST_CMD_GAP_V(1),
edc_bist_cmd_reg);
- i = csio_hw_wait_op_done_val(hw, edc_bist_cmd_reg, START_BIST,
+ i = csio_hw_wait_op_done_val(hw, edc_bist_cmd_reg, START_BIST_F,
0, 10, 1, NULL);
if (i)
return i;
-#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA, i) + idx)
+#define EDC_DATA(i) (EDC_BIST_STATUS_REG(EDC_BIST_STATUS_RDATA_A, i) + idx)
for (i = 15; i >= 0; i--)
*data++ = htonl(csio_rd_reg32(hw, EDC_DATA(i)));
@@ -320,13 +320,13 @@ csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
* the address is relative to BAR0.
*/
mem_reg = csio_rd_reg32(hw,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN, win));
- mem_aperture = 1 << (WINDOW(mem_reg) + 10);
- mem_base = GET_PCIEOFST(mem_reg) << 10;
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_BASE_WIN_A, win));
+ mem_aperture = 1 << (WINDOW_V(mem_reg) + 10);
+ mem_base = PCIEOFST_G(mem_reg) << 10;
start = addr & ~(mem_aperture-1);
offset = addr - start;
- win_pf = V_PFNUM(hw->pfn);
+ win_pf = PFNUM_V(hw->pfn);
csio_dbg(hw, "csio_t5_memory_rw: mem_reg: 0x%x, mem_aperture: 0x%x\n",
mem_reg, mem_aperture);
@@ -344,9 +344,9 @@ csio_t5_memory_rw(struct csio_hw *hw, u32 win, int mtype, u32 addr,
* before we attempt to use the new value.
*/
csio_wr_reg32(hw, pos | win_pf,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win));
csio_rd_reg32(hw,
- PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET, win));
+ PCIE_MEM_ACCESS_REG(PCIE_MEM_ACCESS_OFFSET_A, win));
while (offset < mem_aperture && len > 0) {
if (dir)
diff --git a/drivers/scsi/csiostor/csio_init.c b/drivers/scsi/csiostor/csio_init.c
index 34d20cc3e110..d9631e15f7b5 100644
--- a/drivers/scsi/csiostor/csio_init.c
+++ b/drivers/scsi/csiostor/csio_init.c
@@ -113,12 +113,9 @@ static const struct file_operations csio_mem_debugfs_fops = {
void csio_add_debugfs_mem(struct csio_hw *hw, const char *name,
unsigned int idx, unsigned int size_mb)
{
- struct dentry *de;
-
- de = debugfs_create_file(name, S_IRUSR, hw->debugfs_root,
- (void *)hw + idx, &csio_mem_debugfs_fops);
- if (de && de->d_inode)
- de->d_inode->i_size = size_mb << 20;
+ debugfs_create_file_size(name, S_IRUSR, hw->debugfs_root,
+ (void *)hw + idx, &csio_mem_debugfs_fops,
+ size_mb << 20);
}
static int csio_setup_debugfs(struct csio_hw *hw)
@@ -1176,9 +1173,8 @@ static struct pci_error_handlers csio_err_handler = {
*/
#define CH_PCI_DEVICE_ID_TABLE_DEFINE_BEGIN \
static struct pci_device_id csio_pci_tbl[] = {
-/* Define for iSCSI uses PF5, FCoE uses PF6 */
-#define CH_PCI_DEVICE_ID_FUNCTION 0x5
-#define CH_PCI_DEVICE_ID_FUNCTION2 0x6
+/* Define for FCoE uses PF6 */
+#define CH_PCI_DEVICE_ID_FUNCTION 0x6
#define CH_PCI_ID_TABLE_ENTRY(devid) \
{ PCI_VDEVICE(CHELSIO, (devid)), 0 }
@@ -1256,5 +1252,4 @@ MODULE_DESCRIPTION(CSIO_DRV_DESC);
MODULE_LICENSE(CSIO_DRV_LICENSE);
MODULE_DEVICE_TABLE(pci, csio_pci_tbl);
MODULE_VERSION(CSIO_DRV_VERSION);
-MODULE_FIRMWARE(FW_FNAME_T4);
MODULE_FIRMWARE(FW_FNAME_T5);
diff --git a/drivers/scsi/csiostor/csio_isr.c b/drivers/scsi/csiostor/csio_isr.c
index a8c748a35f9c..2fb71c6c3b37 100644
--- a/drivers/scsi/csiostor/csio_isr.c
+++ b/drivers/scsi/csiostor/csio_isr.c
@@ -317,7 +317,7 @@ csio_fcoe_isr(int irq, void *dev_id)
/* Disable the interrupt for this PCI function. */
if (hw->intr_mode == CSIO_IM_INTX)
- csio_wr_reg32(hw, 0, MYPF_REG(PCIE_PF_CLI));
+ csio_wr_reg32(hw, 0, MYPF_REG(PCIE_PF_CLI_A));
/*
* The read in the following function will flush the
diff --git a/drivers/scsi/csiostor/csio_lnode.c b/drivers/scsi/csiostor/csio_lnode.c
index 87f9280d9b43..c00b2ff72b55 100644
--- a/drivers/scsi/csiostor/csio_lnode.c
+++ b/drivers/scsi/csiostor/csio_lnode.c
@@ -1758,7 +1758,7 @@ csio_ln_mgmt_submit_wr(struct csio_mgmtm *mgmtm, struct csio_ioreq *io_req,
else {
/* Program DSGL to dma payload */
dsgl.cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) |
- ULPTX_MORE | ULPTX_NSGE(1));
+ ULPTX_MORE_F | ULPTX_NSGE_V(1));
dsgl.len0 = cpu_to_be32(pld_len);
dsgl.addr0 = cpu_to_be64(pld->paddr);
csio_wr_copy_to_wrp(&dsgl, &wrp, ALIGN(wr_off, 8),
diff --git a/drivers/scsi/csiostor/csio_mb.c b/drivers/scsi/csiostor/csio_mb.c
index 08c265c0f353..9451787ca7f2 100644
--- a/drivers/scsi/csiostor/csio_mb.c
+++ b/drivers/scsi/csiostor/csio_mb.c
@@ -327,7 +327,8 @@ csio_mb_caps_config(struct csio_hw *hw, struct csio_mb *mbp, uint32_t tmo,
}
#define CSIO_ADVERT_MASK (FW_PORT_CAP_SPEED_100M | FW_PORT_CAP_SPEED_1G |\
- FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_ANEG)
+ FW_PORT_CAP_SPEED_10G | FW_PORT_CAP_SPEED_40G |\
+ FW_PORT_CAP_ANEG)
/*
* csio_mb_port- FW PORT command helper
@@ -1104,8 +1105,8 @@ csio_mb_process_portparams_rsp(struct csio_hw *hw,
void
csio_mb_intr_enable(struct csio_hw *hw)
{
- csio_wr_reg32(hw, MBMSGRDYINTEN(1), MYPF_REG(CIM_PF_HOST_INT_ENABLE));
- csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE));
+ csio_wr_reg32(hw, MBMSGRDYINTEN_F, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
+ csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
}
/*
@@ -1117,8 +1118,9 @@ csio_mb_intr_enable(struct csio_hw *hw)
void
csio_mb_intr_disable(struct csio_hw *hw)
{
- csio_wr_reg32(hw, MBMSGRDYINTEN(0), MYPF_REG(CIM_PF_HOST_INT_ENABLE));
- csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE));
+ csio_wr_reg32(hw, MBMSGRDYINTEN_V(0),
+ MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
+ csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_ENABLE_A));
}
static void
@@ -1153,8 +1155,8 @@ csio_mb_debug_cmd_handler(struct csio_hw *hw)
{
int i;
__be64 cmd[CSIO_MB_MAX_REGS];
- uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL);
- uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA);
+ uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
+ uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
int size = sizeof(struct fw_debug_cmd);
/* Copy mailbox data */
@@ -1164,8 +1166,8 @@ csio_mb_debug_cmd_handler(struct csio_hw *hw)
csio_mb_dump_fw_dbg(hw, cmd);
/* Notify FW of mailbox by setting owner as UP */
- csio_wr_reg32(hw, MBMSGVALID | MBINTREQ | MBOWNER(CSIO_MBOWNER_FW),
- ctl_reg);
+ csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F |
+ MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg);
csio_rd_reg32(hw, ctl_reg);
wmb();
@@ -1187,8 +1189,8 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
__be64 *cmd = mbp->mb;
__be64 hdr;
struct csio_mbm *mbm = &hw->mbm;
- uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL);
- uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA);
+ uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
+ uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
int size = mbp->mb_size;
int rv = -EINVAL;
struct fw_cmd_hdr *fw_hdr;
@@ -1224,12 +1226,12 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
}
/* Now get ownership of mailbox */
- owner = MBOWNER_GET(csio_rd_reg32(hw, ctl_reg));
+ owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg));
if (!csio_mb_is_host_owner(owner)) {
for (i = 0; (owner == CSIO_MBOWNER_NONE) && (i < 3); i++)
- owner = MBOWNER_GET(csio_rd_reg32(hw, ctl_reg));
+ owner = MBOWNER_G(csio_rd_reg32(hw, ctl_reg));
/*
* Mailbox unavailable. In immediate mode, fail the command.
* In other modes, enqueue the request.
@@ -1271,10 +1273,10 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
if (mbp->mb_cbfn != NULL) {
mbm->mcurrent = mbp;
mod_timer(&mbm->timer, jiffies + msecs_to_jiffies(mbp->tmo));
- csio_wr_reg32(hw, MBMSGVALID | MBINTREQ |
- MBOWNER(CSIO_MBOWNER_FW), ctl_reg);
+ csio_wr_reg32(hw, MBMSGVALID_F | MBINTREQ_F |
+ MBOWNER_V(CSIO_MBOWNER_FW), ctl_reg);
} else
- csio_wr_reg32(hw, MBMSGVALID | MBOWNER(CSIO_MBOWNER_FW),
+ csio_wr_reg32(hw, MBMSGVALID_F | MBOWNER_V(CSIO_MBOWNER_FW),
ctl_reg);
/* Flush posted writes */
@@ -1294,9 +1296,9 @@ csio_mb_issue(struct csio_hw *hw, struct csio_mb *mbp)
/* Check for response */
ctl = csio_rd_reg32(hw, ctl_reg);
- if (csio_mb_is_host_owner(MBOWNER_GET(ctl))) {
+ if (csio_mb_is_host_owner(MBOWNER_G(ctl))) {
- if (!(ctl & MBMSGVALID)) {
+ if (!(ctl & MBMSGVALID_F)) {
csio_wr_reg32(hw, 0, ctl_reg);
continue;
}
@@ -1457,16 +1459,16 @@ csio_mb_isr_handler(struct csio_hw *hw)
__be64 *cmd;
uint32_t ctl, cim_cause, pl_cause;
int i;
- uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL);
- uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA);
+ uint32_t ctl_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_CTRL_A);
+ uint32_t data_reg = PF_REG(hw->pfn, CIM_PF_MAILBOX_DATA_A);
int size;
__be64 hdr;
struct fw_cmd_hdr *fw_hdr;
- pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE));
- cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE));
+ pl_cause = csio_rd_reg32(hw, MYPF_REG(PL_PF_INT_CAUSE_A));
+ cim_cause = csio_rd_reg32(hw, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A));
- if (!(pl_cause & PFCIM) || !(cim_cause & MBMSGRDYINT)) {
+ if (!(pl_cause & PFCIM_F) || !(cim_cause & MBMSGRDYINT_F)) {
CSIO_INC_STATS(hw, n_mbint_unexp);
return -EINVAL;
}
@@ -1477,16 +1479,16 @@ csio_mb_isr_handler(struct csio_hw *hw)
* the upper level cause register. In other words, CIM-cause
* first followed by PL-Cause next.
*/
- csio_wr_reg32(hw, MBMSGRDYINT, MYPF_REG(CIM_PF_HOST_INT_CAUSE));
- csio_wr_reg32(hw, PFCIM, MYPF_REG(PL_PF_INT_CAUSE));
+ csio_wr_reg32(hw, MBMSGRDYINT_F, MYPF_REG(CIM_PF_HOST_INT_CAUSE_A));
+ csio_wr_reg32(hw, PFCIM_F, MYPF_REG(PL_PF_INT_CAUSE_A));
ctl = csio_rd_reg32(hw, ctl_reg);
- if (csio_mb_is_host_owner(MBOWNER_GET(ctl))) {
+ if (csio_mb_is_host_owner(MBOWNER_G(ctl))) {
CSIO_DUMP_MB(hw, hw->pfn, data_reg);
- if (!(ctl & MBMSGVALID)) {
+ if (!(ctl & MBMSGVALID_F)) {
csio_warn(hw,
"Stray mailbox interrupt recvd,"
" mailbox data not valid\n");
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
index 3987284e0d2a..2c4562d82dc0 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -298,8 +298,8 @@ csio_scsi_init_ultptx_dsgl(struct csio_hw *hw, struct csio_ioreq *req,
struct csio_dma_buf *dma_buf;
struct scsi_cmnd *scmnd = csio_scsi_cmnd(req);
- sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_MORE |
- ULPTX_NSGE(req->nsge));
+ sgl->cmd_nsge = htonl(ULPTX_CMD_V(ULP_TX_SC_DSGL) | ULPTX_MORE_F |
+ ULPTX_NSGE_V(req->nsge));
/* Now add the data SGLs */
if (likely(!req->dcopy)) {
scsi_for_each_sg(scmnd, sgel, req->nsge, i) {
diff --git a/drivers/scsi/csiostor/csio_wr.c b/drivers/scsi/csiostor/csio_wr.c
index 773da14cfa14..e8f18174f2e9 100644
--- a/drivers/scsi/csiostor/csio_wr.c
+++ b/drivers/scsi/csiostor/csio_wr.c
@@ -51,12 +51,12 @@ int csio_intr_coalesce_time = 10; /* value:SGE_TIMER_VALUE_1 */
static int csio_sge_timer_reg = 1;
#define CSIO_SET_FLBUF_SIZE(_hw, _reg, _val) \
- csio_wr_reg32((_hw), (_val), SGE_FL_BUFFER_SIZE##_reg)
+ csio_wr_reg32((_hw), (_val), SGE_FL_BUFFER_SIZE##_reg##_A)
static void
csio_get_flbuf_size(struct csio_hw *hw, struct csio_sge *sge, uint32_t reg)
{
- sge->sge_fl_buf_size[reg] = csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE0 +
+ sge->sge_fl_buf_size[reg] = csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE0_A +
reg * sizeof(uint32_t));
}
@@ -71,7 +71,7 @@ csio_wr_fl_bufsz(struct csio_sge *sge, struct csio_dma_buf *buf)
static inline uint32_t
csio_wr_qstat_pgsz(struct csio_hw *hw)
{
- return (hw->wrm.sge.sge_control & EGRSTATUSPAGESIZE(1)) ? 128 : 64;
+ return (hw->wrm.sge.sge_control & EGRSTATUSPAGESIZE_F) ? 128 : 64;
}
/* Ring freelist doorbell */
@@ -84,9 +84,9 @@ csio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq)
* 8 freelist buffer pointers (since each pointer is 8 bytes).
*/
if (flq->inc_idx >= 8) {
- csio_wr_reg32(hw, DBPRIO(1) | QID(flq->un.fl.flid) |
- CSIO_HW_PIDX(hw, flq->inc_idx / 8),
- MYPF_REG(SGE_PF_KDOORBELL));
+ csio_wr_reg32(hw, DBPRIO_F | QID_V(flq->un.fl.flid) |
+ PIDX_T5_V(flq->inc_idx / 8) | DBTYPE_F,
+ MYPF_REG(SGE_PF_KDOORBELL_A));
flq->inc_idx &= 7;
}
}
@@ -95,10 +95,10 @@ csio_wr_ring_fldb(struct csio_hw *hw, struct csio_q *flq)
static void
csio_wr_sge_intr_enable(struct csio_hw *hw, uint16_t iqid)
{
- csio_wr_reg32(hw, CIDXINC(0) |
- INGRESSQID(iqid) |
- TIMERREG(X_TIMERREG_RESTART_COUNTER),
- MYPF_REG(SGE_PF_GTS));
+ csio_wr_reg32(hw, CIDXINC_V(0) |
+ INGRESSQID_V(iqid) |
+ TIMERREG_V(X_TIMERREG_RESTART_COUNTER),
+ MYPF_REG(SGE_PF_GTS_A));
}
/*
@@ -982,9 +982,9 @@ csio_wr_issue(struct csio_hw *hw, int qidx, bool prio)
wmb();
/* Ring SGE Doorbell writing q->pidx into it */
- csio_wr_reg32(hw, DBPRIO(prio) | QID(q->un.eq.physeqid) |
- CSIO_HW_PIDX(hw, q->inc_idx),
- MYPF_REG(SGE_PF_KDOORBELL));
+ csio_wr_reg32(hw, DBPRIO_V(prio) | QID_V(q->un.eq.physeqid) |
+ PIDX_T5_V(q->inc_idx) | DBTYPE_F,
+ MYPF_REG(SGE_PF_KDOORBELL_A));
q->inc_idx = 0;
return 0;
@@ -1242,10 +1242,10 @@ csio_wr_process_iq(struct csio_hw *hw, struct csio_q *q,
restart:
/* Now inform SGE about our incremental index value */
- csio_wr_reg32(hw, CIDXINC(q->inc_idx) |
- INGRESSQID(q->un.iq.physiqid) |
- TIMERREG(csio_sge_timer_reg),
- MYPF_REG(SGE_PF_GTS));
+ csio_wr_reg32(hw, CIDXINC_V(q->inc_idx) |
+ INGRESSQID_V(q->un.iq.physiqid) |
+ TIMERREG_V(csio_sge_timer_reg),
+ MYPF_REG(SGE_PF_GTS_A));
q->stats.n_tot_rsps += q->inc_idx;
q->inc_idx = 0;
@@ -1310,22 +1310,23 @@ csio_wr_fixup_host_params(struct csio_hw *hw)
uint32_t ingpad = 0;
uint32_t stat_len = clsz > 64 ? 128 : 64;
- csio_wr_reg32(hw, HOSTPAGESIZEPF0(s_hps) | HOSTPAGESIZEPF1(s_hps) |
- HOSTPAGESIZEPF2(s_hps) | HOSTPAGESIZEPF3(s_hps) |
- HOSTPAGESIZEPF4(s_hps) | HOSTPAGESIZEPF5(s_hps) |
- HOSTPAGESIZEPF6(s_hps) | HOSTPAGESIZEPF7(s_hps),
- SGE_HOST_PAGE_SIZE);
+ csio_wr_reg32(hw, HOSTPAGESIZEPF0_V(s_hps) | HOSTPAGESIZEPF1_V(s_hps) |
+ HOSTPAGESIZEPF2_V(s_hps) | HOSTPAGESIZEPF3_V(s_hps) |
+ HOSTPAGESIZEPF4_V(s_hps) | HOSTPAGESIZEPF5_V(s_hps) |
+ HOSTPAGESIZEPF6_V(s_hps) | HOSTPAGESIZEPF7_V(s_hps),
+ SGE_HOST_PAGE_SIZE_A);
sge->csio_fl_align = clsz < 32 ? 32 : clsz;
ingpad = ilog2(sge->csio_fl_align) - 5;
- csio_set_reg_field(hw, SGE_CONTROL, INGPADBOUNDARY_MASK |
- EGRSTATUSPAGESIZE(1),
- INGPADBOUNDARY(ingpad) |
- EGRSTATUSPAGESIZE(stat_len != 64));
+ csio_set_reg_field(hw, SGE_CONTROL_A,
+ INGPADBOUNDARY_V(INGPADBOUNDARY_M) |
+ EGRSTATUSPAGESIZE_F,
+ INGPADBOUNDARY_V(ingpad) |
+ EGRSTATUSPAGESIZE_V(stat_len != 64));
/* FL BUFFER SIZE#0 is Page size i,e already aligned to cache line */
- csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0);
+ csio_wr_reg32(hw, PAGE_SIZE, SGE_FL_BUFFER_SIZE0_A);
/*
* If using hard params, the following will get set correctly
@@ -1333,23 +1334,24 @@ csio_wr_fixup_host_params(struct csio_hw *hw)
*/
if (hw->flags & CSIO_HWF_USING_SOFT_PARAMS) {
csio_wr_reg32(hw,
- (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2) +
+ (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE2_A) +
sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
- SGE_FL_BUFFER_SIZE2);
+ SGE_FL_BUFFER_SIZE2_A);
csio_wr_reg32(hw,
- (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3) +
+ (csio_rd_reg32(hw, SGE_FL_BUFFER_SIZE3_A) +
sge->csio_fl_align - 1) & ~(sge->csio_fl_align - 1),
- SGE_FL_BUFFER_SIZE3);
+ SGE_FL_BUFFER_SIZE3_A);
}
- csio_wr_reg32(hw, HPZ0(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ);
+ csio_wr_reg32(hw, HPZ0_V(PAGE_SHIFT - 12), ULP_RX_TDDP_PSZ_A);
/* default value of rx_dma_offset of the NIC driver */
- csio_set_reg_field(hw, SGE_CONTROL, PKTSHIFT_MASK,
- PKTSHIFT(CSIO_SGE_RX_DMA_OFFSET));
+ csio_set_reg_field(hw, SGE_CONTROL_A,
+ PKTSHIFT_V(PKTSHIFT_M),
+ PKTSHIFT_V(CSIO_SGE_RX_DMA_OFFSET));
- csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG,
- CSUM_HAS_PSEUDO_HDR, 0);
+ csio_hw_tp_wr_bits_indirect(hw, TP_INGRESS_CONFIG_A,
+ CSUM_HAS_PSEUDO_HDR_F, 0);
}
static void
@@ -1384,9 +1386,9 @@ csio_wr_get_sge(struct csio_hw *hw)
u32 timer_value_0_and_1, timer_value_2_and_3, timer_value_4_and_5;
u32 ingress_rx_threshold;
- sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL);
+ sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL_A);
- ingpad = INGPADBOUNDARY_GET(sge->sge_control);
+ ingpad = INGPADBOUNDARY_G(sge->sge_control);
switch (ingpad) {
case X_INGPCIEBOUNDARY_32B:
@@ -1410,28 +1412,28 @@ csio_wr_get_sge(struct csio_hw *hw)
for (i = 0; i < CSIO_SGE_FL_SIZE_REGS; i++)
csio_get_flbuf_size(hw, sge, i);
- timer_value_0_and_1 = csio_rd_reg32(hw, SGE_TIMER_VALUE_0_AND_1);
- timer_value_2_and_3 = csio_rd_reg32(hw, SGE_TIMER_VALUE_2_AND_3);
- timer_value_4_and_5 = csio_rd_reg32(hw, SGE_TIMER_VALUE_4_AND_5);
+ timer_value_0_and_1 = csio_rd_reg32(hw, SGE_TIMER_VALUE_0_AND_1_A);
+ timer_value_2_and_3 = csio_rd_reg32(hw, SGE_TIMER_VALUE_2_AND_3_A);
+ timer_value_4_and_5 = csio_rd_reg32(hw, SGE_TIMER_VALUE_4_AND_5_A);
sge->timer_val[0] = (uint16_t)csio_core_ticks_to_us(hw,
- TIMERVALUE0_GET(timer_value_0_and_1));
+ TIMERVALUE0_G(timer_value_0_and_1));
sge->timer_val[1] = (uint16_t)csio_core_ticks_to_us(hw,
- TIMERVALUE1_GET(timer_value_0_and_1));
+ TIMERVALUE1_G(timer_value_0_and_1));
sge->timer_val[2] = (uint16_t)csio_core_ticks_to_us(hw,
- TIMERVALUE2_GET(timer_value_2_and_3));
+ TIMERVALUE2_G(timer_value_2_and_3));
sge->timer_val[3] = (uint16_t)csio_core_ticks_to_us(hw,
- TIMERVALUE3_GET(timer_value_2_and_3));
+ TIMERVALUE3_G(timer_value_2_and_3));
sge->timer_val[4] = (uint16_t)csio_core_ticks_to_us(hw,
- TIMERVALUE4_GET(timer_value_4_and_5));
+ TIMERVALUE4_G(timer_value_4_and_5));
sge->timer_val[5] = (uint16_t)csio_core_ticks_to_us(hw,
- TIMERVALUE5_GET(timer_value_4_and_5));
+ TIMERVALUE5_G(timer_value_4_and_5));
- ingress_rx_threshold = csio_rd_reg32(hw, SGE_INGRESS_RX_THRESHOLD);
- sge->counter_val[0] = THRESHOLD_0_GET(ingress_rx_threshold);
- sge->counter_val[1] = THRESHOLD_1_GET(ingress_rx_threshold);
- sge->counter_val[2] = THRESHOLD_2_GET(ingress_rx_threshold);
- sge->counter_val[3] = THRESHOLD_3_GET(ingress_rx_threshold);
+ ingress_rx_threshold = csio_rd_reg32(hw, SGE_INGRESS_RX_THRESHOLD_A);
+ sge->counter_val[0] = THRESHOLD_0_G(ingress_rx_threshold);
+ sge->counter_val[1] = THRESHOLD_1_G(ingress_rx_threshold);
+ sge->counter_val[2] = THRESHOLD_2_G(ingress_rx_threshold);
+ sge->counter_val[3] = THRESHOLD_3_G(ingress_rx_threshold);
csio_init_intr_coalesce_parms(hw);
}
@@ -1454,9 +1456,9 @@ csio_wr_set_sge(struct csio_hw *hw)
* Set up our basic SGE mode to deliver CPL messages to our Ingress
* Queue and Packet Date to the Free List.
*/
- csio_set_reg_field(hw, SGE_CONTROL, RXPKTCPLMODE(1), RXPKTCPLMODE(1));
+ csio_set_reg_field(hw, SGE_CONTROL_A, RXPKTCPLMODE_F, RXPKTCPLMODE_F);
- sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL);
+ sge->sge_control = csio_rd_reg32(hw, SGE_CONTROL_A);
/* sge->csio_fl_align is set up by csio_wr_fixup_host_params(). */
@@ -1464,22 +1466,23 @@ csio_wr_set_sge(struct csio_hw *hw)
* Set up to drop DOORBELL writes when the DOORBELL FIFO overflows
* and generate an interrupt when this occurs so we can recover.
*/
- csio_set_reg_field(hw, SGE_DBFIFO_STATUS,
- HP_INT_THRESH(HP_INT_THRESH_MASK) |
- CSIO_HW_LP_INT_THRESH(hw, CSIO_HW_M_LP_INT_THRESH(hw)),
- HP_INT_THRESH(CSIO_SGE_DBFIFO_INT_THRESH) |
- CSIO_HW_LP_INT_THRESH(hw, CSIO_SGE_DBFIFO_INT_THRESH));
+ csio_set_reg_field(hw, SGE_DBFIFO_STATUS_A,
+ LP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M),
+ LP_INT_THRESH_T5_V(CSIO_SGE_DBFIFO_INT_THRESH));
+ csio_set_reg_field(hw, SGE_DBFIFO_STATUS2_A,
+ HP_INT_THRESH_T5_V(LP_INT_THRESH_T5_M),
+ HP_INT_THRESH_T5_V(CSIO_SGE_DBFIFO_INT_THRESH));
- csio_set_reg_field(hw, SGE_DOORBELL_CONTROL, ENABLE_DROP,
- ENABLE_DROP);
+ csio_set_reg_field(hw, SGE_DOORBELL_CONTROL_A, ENABLE_DROP_F,
+ ENABLE_DROP_F);
/* SGE_FL_BUFFER_SIZE0 is set up by csio_wr_fixup_host_params(). */
CSIO_SET_FLBUF_SIZE(hw, 1, CSIO_SGE_FLBUF_SIZE1);
csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE2 + sge->csio_fl_align - 1)
- & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2);
+ & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE2_A);
csio_wr_reg32(hw, (CSIO_SGE_FLBUF_SIZE3 + sge->csio_fl_align - 1)
- & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3);
+ & ~(sge->csio_fl_align - 1), SGE_FL_BUFFER_SIZE3_A);
CSIO_SET_FLBUF_SIZE(hw, 4, CSIO_SGE_FLBUF_SIZE4);
CSIO_SET_FLBUF_SIZE(hw, 5, CSIO_SGE_FLBUF_SIZE5);
CSIO_SET_FLBUF_SIZE(hw, 6, CSIO_SGE_FLBUF_SIZE6);
@@ -1502,26 +1505,26 @@ csio_wr_set_sge(struct csio_hw *hw)
sge->counter_val[2] = CSIO_SGE_INT_CNT_VAL_2;
sge->counter_val[3] = CSIO_SGE_INT_CNT_VAL_3;
- csio_wr_reg32(hw, THRESHOLD_0(sge->counter_val[0]) |
- THRESHOLD_1(sge->counter_val[1]) |
- THRESHOLD_2(sge->counter_val[2]) |
- THRESHOLD_3(sge->counter_val[3]),
- SGE_INGRESS_RX_THRESHOLD);
+ csio_wr_reg32(hw, THRESHOLD_0_V(sge->counter_val[0]) |
+ THRESHOLD_1_V(sge->counter_val[1]) |
+ THRESHOLD_2_V(sge->counter_val[2]) |
+ THRESHOLD_3_V(sge->counter_val[3]),
+ SGE_INGRESS_RX_THRESHOLD_A);
csio_wr_reg32(hw,
- TIMERVALUE0(csio_us_to_core_ticks(hw, sge->timer_val[0])) |
- TIMERVALUE1(csio_us_to_core_ticks(hw, sge->timer_val[1])),
- SGE_TIMER_VALUE_0_AND_1);
+ TIMERVALUE0_V(csio_us_to_core_ticks(hw, sge->timer_val[0])) |
+ TIMERVALUE1_V(csio_us_to_core_ticks(hw, sge->timer_val[1])),
+ SGE_TIMER_VALUE_0_AND_1_A);
csio_wr_reg32(hw,
- TIMERVALUE2(csio_us_to_core_ticks(hw, sge->timer_val[2])) |
- TIMERVALUE3(csio_us_to_core_ticks(hw, sge->timer_val[3])),
- SGE_TIMER_VALUE_2_AND_3);
+ TIMERVALUE2_V(csio_us_to_core_ticks(hw, sge->timer_val[2])) |
+ TIMERVALUE3_V(csio_us_to_core_ticks(hw, sge->timer_val[3])),
+ SGE_TIMER_VALUE_2_AND_3_A);
csio_wr_reg32(hw,
- TIMERVALUE4(csio_us_to_core_ticks(hw, sge->timer_val[4])) |
- TIMERVALUE5(csio_us_to_core_ticks(hw, sge->timer_val[5])),
- SGE_TIMER_VALUE_4_AND_5);
+ TIMERVALUE4_V(csio_us_to_core_ticks(hw, sge->timer_val[4])) |
+ TIMERVALUE5_V(csio_us_to_core_ticks(hw, sge->timer_val[5])),
+ SGE_TIMER_VALUE_4_AND_5_A);
csio_init_intr_coalesce_parms(hw);
}
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index a83d2ceded83..dd00e5fe4a5e 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -28,6 +28,7 @@
#include "t4fw_api.h"
#include "l2t.h"
#include "cxgb4i.h"
+#include "clip_tbl.h"
static unsigned int dbg_level;
@@ -704,7 +705,7 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb)
struct cpl_act_establish *req = (struct cpl_act_establish *)skb->data;
unsigned short tcp_opt = ntohs(req->tcp_opt);
unsigned int tid = GET_TID(req);
- unsigned int atid = GET_TID_TID(ntohl(req->tos_atid));
+ unsigned int atid = TID_TID_G(ntohl(req->tos_atid));
struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
struct tid_info *t = lldi->tids;
u32 rcv_isn = be32_to_cpu(req->rcv_isn);
@@ -752,15 +753,15 @@ static void do_act_establish(struct cxgbi_device *cdev, struct sk_buff *skb)
if (cxgb4i_rcv_win > (RCV_BUFSIZ_MASK << 10))
csk->rcv_wup -= cxgb4i_rcv_win - (RCV_BUFSIZ_MASK << 10);
- csk->advmss = lldi->mtus[GET_TCPOPT_MSS(tcp_opt)] - 40;
- if (GET_TCPOPT_TSTAMP(tcp_opt))
+ csk->advmss = lldi->mtus[TCPOPT_MSS_G(tcp_opt)] - 40;
+ if (TCPOPT_TSTAMP_G(tcp_opt))
csk->advmss -= 12;
if (csk->advmss < 128)
csk->advmss = 128;
log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK,
"csk 0x%p, mss_idx %u, advmss %u.\n",
- csk, GET_TCPOPT_MSS(tcp_opt), csk->advmss);
+ csk, TCPOPT_MSS_G(tcp_opt), csk->advmss);
cxgbi_sock_established(csk, ntohl(req->snd_isn), ntohs(req->tcp_opt));
@@ -856,8 +857,8 @@ static void do_act_open_rpl(struct cxgbi_device *cdev, struct sk_buff *skb)
struct cpl_act_open_rpl *rpl = (struct cpl_act_open_rpl *)skb->data;
unsigned int tid = GET_TID(rpl);
unsigned int atid =
- GET_TID_TID(GET_AOPEN_ATID(be32_to_cpu(rpl->atid_status)));
- unsigned int status = GET_AOPEN_STATUS(be32_to_cpu(rpl->atid_status));
+ TID_TID_G(AOPEN_ATID_G(be32_to_cpu(rpl->atid_status)));
+ unsigned int status = AOPEN_STATUS_G(be32_to_cpu(rpl->atid_status));
struct cxgb4_lld_info *lldi = cxgbi_cdev_priv(cdev);
struct tid_info *t = lldi->tids;
@@ -1112,7 +1113,7 @@ static void do_rx_iscsi_hdr(struct cxgbi_device *cdev, struct sk_buff *skb)
hlen = ntohs(cpl->len);
dlen = ntohl(*(unsigned int *)(bhs + 4)) & 0xFFFFFF;
- plen = ISCSI_PDU_LEN(pdu_len_ddp);
+ plen = ISCSI_PDU_LEN_G(pdu_len_ddp);
if (is_t4(lldi->adapter_type))
plen -= 40;
@@ -1322,6 +1323,9 @@ static inline void l2t_put(struct cxgbi_sock *csk)
static void release_offload_resources(struct cxgbi_sock *csk)
{
struct cxgb4_lld_info *lldi;
+#if IS_ENABLED(CONFIG_IPV6)
+ struct net_device *ndev = csk->cdev->ports[csk->port_id];
+#endif
log_debug(1 << CXGBI_DBG_TOE | 1 << CXGBI_DBG_SOCK,
"csk 0x%p,%u,0x%lx,%u.\n",
@@ -1334,6 +1338,12 @@ static void release_offload_resources(struct cxgbi_sock *csk)
}
l2t_put(csk);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (csk->csk_family == AF_INET6)
+ cxgb4_clip_release(ndev,
+ (const u32 *)&csk->saddr6.sin6_addr, 1);
+#endif
+
if (cxgbi_sock_flag(csk, CTPF_HAS_ATID))
free_atid(csk);
else if (cxgbi_sock_flag(csk, CTPF_HAS_TID)) {
@@ -1391,10 +1401,15 @@ static int init_act_open(struct cxgbi_sock *csk)
csk->l2t = cxgb4_l2t_get(lldi->l2t, n, ndev, 0);
if (!csk->l2t) {
pr_err("%s, cannot alloc l2t.\n", ndev->name);
- goto rel_resource;
+ goto rel_resource_without_clip;
}
cxgbi_sock_get(csk);
+#if IS_ENABLED(CONFIG_IPV6)
+ if (csk->csk_family == AF_INET6)
+ cxgb4_clip_get(ndev, (const u32 *)&csk->saddr6.sin6_addr, 1);
+#endif
+
if (t4) {
size = sizeof(struct cpl_act_open_req);
size6 = sizeof(struct cpl_act_open_req6);
@@ -1451,6 +1466,12 @@ static int init_act_open(struct cxgbi_sock *csk)
return 0;
rel_resource:
+#if IS_ENABLED(CONFIG_IPV6)
+ if (csk->csk_family == AF_INET6)
+ cxgb4_clip_release(ndev,
+ (const u32 *)&csk->saddr6.sin6_addr, 1);
+#endif
+rel_resource_without_clip:
if (n)
neigh_release(n);
if (skb)
@@ -1619,7 +1640,7 @@ static int ddp_setup_conn_pgidx(struct cxgbi_sock *csk, unsigned int tid,
req = (struct cpl_set_tcb_field *)skb->head;
INIT_TP_WR(req, csk->tid);
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, csk->tid));
- req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid));
+ req->reply_ctrl = htons(NO_REPLY_V(reply) | QUEUENO_V(csk->rss_qid));
req->word_cookie = htons(0);
req->mask = cpu_to_be64(0x3 << 8);
req->val = cpu_to_be64(pg_idx << 8);
@@ -1651,7 +1672,7 @@ static int ddp_setup_conn_digest(struct cxgbi_sock *csk, unsigned int tid,
req = (struct cpl_set_tcb_field *)skb->head;
INIT_TP_WR(req, tid);
OPCODE_TID(req) = htonl(MK_OPCODE_TID(CPL_SET_TCB_FIELD, tid));
- req->reply_ctrl = htons(NO_REPLY(reply) | QUEUENO(csk->rss_qid));
+ req->reply_ctrl = htons(NO_REPLY_V(reply) | QUEUENO_V(csk->rss_qid));
req->word_cookie = htons(0);
req->mask = cpu_to_be64(0x3 << 4);
req->val = cpu_to_be64(((hcrc ? ULP_CRC_HEADER : 0) |
diff --git a/drivers/scsi/dc395x.c b/drivers/scsi/dc395x.c
index 0c6be0a17f53..5ee7f44cf869 100644
--- a/drivers/scsi/dc395x.c
+++ b/drivers/scsi/dc395x.c
@@ -4610,13 +4610,10 @@ static void adapter_uninit(struct AdapterCtlBlk *acb)
}
-#undef SPRINTF
-#define SPRINTF(args...) seq_printf(m,##args)
-
#undef YESNO
#define YESNO(YN) \
- if (YN) SPRINTF(" Yes ");\
- else SPRINTF(" No ")
+ if (YN) seq_printf(m, " Yes ");\
+ else seq_printf(m, " No ")
static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host)
{
@@ -4626,47 +4623,45 @@ static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host)
unsigned long flags;
int dev;
- SPRINTF(DC395X_BANNER " PCI SCSI Host Adapter\n");
- SPRINTF(" Driver Version " DC395X_VERSION "\n");
+ seq_puts(m, DC395X_BANNER " PCI SCSI Host Adapter\n"
+ " Driver Version " DC395X_VERSION "\n");
DC395x_LOCK_IO(acb->scsi_host, flags);
- SPRINTF("SCSI Host Nr %i, ", host->host_no);
- SPRINTF("DC395U/UW/F DC315/U %s\n",
+ seq_printf(m, "SCSI Host Nr %i, ", host->host_no);
+ seq_printf(m, "DC395U/UW/F DC315/U %s\n",
(acb->config & HCC_WIDE_CARD) ? "Wide" : "");
- SPRINTF("io_port_base 0x%04lx, ", acb->io_port_base);
- SPRINTF("irq_level 0x%04x, ", acb->irq_level);
- SPRINTF(" SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000);
+ seq_printf(m, "io_port_base 0x%04lx, ", acb->io_port_base);
+ seq_printf(m, "irq_level 0x%04x, ", acb->irq_level);
+ seq_printf(m, " SelTimeout %ims\n", (1638 * acb->sel_timeout) / 1000);
- SPRINTF("MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun);
- SPRINTF("AdapterID %i\n", host->this_id);
+ seq_printf(m, "MaxID %i, MaxLUN %llu, ", host->max_id, host->max_lun);
+ seq_printf(m, "AdapterID %i\n", host->this_id);
- SPRINTF("tag_max_num %i", acb->tag_max_num);
- /*SPRINTF(", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */
- SPRINTF(", FilterCfg 0x%02x",
+ seq_printf(m, "tag_max_num %i", acb->tag_max_num);
+ /*seq_printf(m, ", DMA_Status %i\n", DC395x_read8(acb, TRM_S1040_DMA_STATUS)); */
+ seq_printf(m, ", FilterCfg 0x%02x",
DC395x_read8(acb, TRM_S1040_SCSI_CONFIG1));
- SPRINTF(", DelayReset %is\n", acb->eeprom.delay_time);
- /*SPRINTF("\n"); */
+ seq_printf(m, ", DelayReset %is\n", acb->eeprom.delay_time);
+ /*seq_printf(m, "\n"); */
- SPRINTF("Nr of DCBs: %i\n", list_size(&acb->dcb_list));
- SPRINTF
- ("Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ seq_printf(m, "Nr of DCBs: %i\n", list_size(&acb->dcb_list));
+ seq_printf(m, "Map of attached LUNs: %02x %02x %02x %02x %02x %02x %02x %02x\n",
acb->dcb_map[0], acb->dcb_map[1], acb->dcb_map[2],
acb->dcb_map[3], acb->dcb_map[4], acb->dcb_map[5],
acb->dcb_map[6], acb->dcb_map[7]);
- SPRINTF
- (" %02x %02x %02x %02x %02x %02x %02x %02x\n",
+ seq_printf(m, " %02x %02x %02x %02x %02x %02x %02x %02x\n",
acb->dcb_map[8], acb->dcb_map[9], acb->dcb_map[10],
acb->dcb_map[11], acb->dcb_map[12], acb->dcb_map[13],
acb->dcb_map[14], acb->dcb_map[15]);
- SPRINTF
- ("Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n");
+ seq_puts(m,
+ "Un ID LUN Prty Sync Wide DsCn SndS TagQ nego_period SyncFreq SyncOffs MaxCmd\n");
dev = 0;
list_for_each_entry(dcb, &acb->dcb_list, list) {
int nego_period;
- SPRINTF("%02i %02i %02i ", dev, dcb->target_id,
+ seq_printf(m, "%02i %02i %02i ", dev, dcb->target_id,
dcb->target_lun);
YESNO(dcb->dev_mode & NTC_DO_PARITY_CHK);
YESNO(dcb->sync_offset);
@@ -4676,53 +4671,53 @@ static int dc395x_show_info(struct seq_file *m, struct Scsi_Host *host)
YESNO(dcb->sync_mode & EN_TAG_QUEUEING);
nego_period = clock_period[dcb->sync_period & 0x07] << 2;
if (dcb->sync_offset)
- SPRINTF(" %03i ns ", nego_period);
+ seq_printf(m, " %03i ns ", nego_period);
else
- SPRINTF(" (%03i ns)", (dcb->min_nego_period << 2));
+ seq_printf(m, " (%03i ns)", (dcb->min_nego_period << 2));
if (dcb->sync_offset & 0x0f) {
spd = 1000 / (nego_period);
spd1 = 1000 % (nego_period);
spd1 = (spd1 * 10 + nego_period / 2) / (nego_period);
- SPRINTF(" %2i.%1i M %02i ", spd, spd1,
+ seq_printf(m, " %2i.%1i M %02i ", spd, spd1,
(dcb->sync_offset & 0x0f));
} else
- SPRINTF(" ");
+ seq_puts(m, " ");
/* Add more info ... */
- SPRINTF(" %02i\n", dcb->max_command);
+ seq_printf(m, " %02i\n", dcb->max_command);
dev++;
}
if (timer_pending(&acb->waiting_timer))
- SPRINTF("Waiting queue timer running\n");
+ seq_puts(m, "Waiting queue timer running\n");
else
- SPRINTF("\n");
+ seq_putc(m, '\n');
list_for_each_entry(dcb, &acb->dcb_list, list) {
struct ScsiReqBlk *srb;
if (!list_empty(&dcb->srb_waiting_list))
- SPRINTF("DCB (%02i-%i): Waiting: %i:",
+ seq_printf(m, "DCB (%02i-%i): Waiting: %i:",
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_waiting_list));
list_for_each_entry(srb, &dcb->srb_waiting_list, list)
- SPRINTF(" %p", srb->cmd);
+ seq_printf(m, " %p", srb->cmd);
if (!list_empty(&dcb->srb_going_list))
- SPRINTF("\nDCB (%02i-%i): Going : %i:",
+ seq_printf(m, "\nDCB (%02i-%i): Going : %i:",
dcb->target_id, dcb->target_lun,
list_size(&dcb->srb_going_list));
list_for_each_entry(srb, &dcb->srb_going_list, list)
- SPRINTF(" %p", srb->cmd);
+ seq_printf(m, " %p", srb->cmd);
if (!list_empty(&dcb->srb_waiting_list) || !list_empty(&dcb->srb_going_list))
- SPRINTF("\n");
+ seq_putc(m, '\n');
}
if (debug_enabled(DBG_1)) {
- SPRINTF("DCB list for ACB %p:\n", acb);
+ seq_printf(m, "DCB list for ACB %p:\n", acb);
list_for_each_entry(dcb, &acb->dcb_list, list) {
- SPRINTF("%p -> ", dcb);
+ seq_printf(m, "%p -> ", dcb);
}
- SPRINTF("END\n");
+ seq_puts(m, "END\n");
}
DC395x_UNLOCK_IO(acb->scsi_host, flags);
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 1dba62c5cf6a..1efebc9eedfb 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -136,11 +136,12 @@ static void __detach_handler (struct kref *kref)
struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
struct scsi_device *sdev = scsi_dh_data->sdev;
+ scsi_dh->detach(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);
}
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 0bf976936a10..2806cfbec2b9 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -568,7 +568,7 @@ static int adpt_show_info(struct seq_file *m, struct Scsi_Host *host)
seq_printf(m, "\tpost fifo size = %d\n\treply fifo size = %d\n\tsg table size = %d\n\n",
host->can_queue, (int) pHba->reply_fifo_size , host->sg_tablesize);
- seq_printf(m, "Devices:\n");
+ seq_puts(m, "Devices:\n");
for(chan = 0; chan < MAX_CHANNEL; chan++) {
for(id = 0; id < MAX_ID; id++) {
d = pHba->channel[chan].device[id];
diff --git a/drivers/scsi/eata_pio.c b/drivers/scsi/eata_pio.c
index 8319d2b417b8..ca8003f0d8a3 100644
--- a/drivers/scsi/eata_pio.c
+++ b/drivers/scsi/eata_pio.c
@@ -102,7 +102,7 @@ static int eata_pio_show_info(struct seq_file *m, struct Scsi_Host *shost)
shost->host_no, SD(shost)->name);
seq_printf(m, "Firmware revision: v%s\n",
SD(shost)->revision);
- seq_printf(m, "IO: PIO\n");
+ seq_puts(m, "IO: PIO\n");
seq_printf(m, "Base IO : %#.4x\n", (u32) shost->base);
seq_printf(m, "Host Bus: %s\n",
(SD(shost)->bustype == 'P')?"PCI ":
diff --git a/drivers/scsi/esas2r/esas2r_init.c b/drivers/scsi/esas2r/esas2r_init.c
index 6776931e25d4..78ce4d61a69b 100644
--- a/drivers/scsi/esas2r/esas2r_init.c
+++ b/drivers/scsi/esas2r/esas2r_init.c
@@ -813,12 +813,13 @@ static void esas2r_init_pci_cfg_space(struct esas2r_adapter *a)
pci_read_config_word(a->pcid, pcie_cap_reg + PCI_EXP_DEVCTL,
&devcontrol);
- if ((devcontrol & PCI_EXP_DEVCTL_READRQ) > 0x2000) {
+ if ((devcontrol & PCI_EXP_DEVCTL_READRQ) >
+ PCI_EXP_DEVCTL_READRQ_512B) {
esas2r_log(ESAS2R_LOG_INFO,
"max read request size > 512B");
devcontrol &= ~PCI_EXP_DEVCTL_READRQ;
- devcontrol |= 0x2000;
+ devcontrol |= PCI_EXP_DEVCTL_READRQ_512B;
pci_write_config_word(a->pcid,
pcie_cap_reg + PCI_EXP_DEVCTL,
devcontrol);
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
index 7e1c21e6736b..31f8966b2e03 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -749,7 +749,7 @@ int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh)
if (dev_count == 0)
seq_puts(m, "none\n");
- seq_puts(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index ce5bd52fe692..065b25df741b 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -2396,8 +2396,6 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
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;
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 9fb632684863..e66e997992e3 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -173,7 +173,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
/* request is i.e. "cat /proc/scsi/gdth/0" */
/* format: %-15s\t%-10s\t%-15s\t%s */
/* driver parameters */
- seq_printf(m, "Driver Parameters:\n");
+ seq_puts(m, "Driver Parameters:\n");
if (reserve_list[0] == 0xff)
strcpy(hrec, "--");
else {
@@ -192,7 +192,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
max_ids, hdr_channel);
/* controller information */
- seq_printf(m,"\nDisk Array Controller Information:\n");
+ seq_puts(m, "\nDisk Array Controller Information:\n");
seq_printf(m,
" Number: \t%d \tName: \t%s\n",
ha->hanum, ha->binfo.type_string);
@@ -219,7 +219,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
#ifdef GDTH_DMA_STATISTICS
/* controller statistics */
- seq_printf(m,"\nController Statistics:\n");
+ seq_puts(m, "\nController Statistics:\n");
seq_printf(m,
" 32-bit DMA buffer:\t%lu\t64-bit DMA buffer:\t%lu\n",
ha->dma32_cnt, ha->dma64_cnt);
@@ -227,7 +227,7 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
if (ha->more_proc) {
/* more information: 2. about physical devices */
- seq_printf(m, "\nPhysical Devices:");
+ seq_puts(m, "\nPhysical Devices:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
@@ -326,10 +326,10 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag)
- seq_printf(m, "\n --\n");
+ seq_puts(m, "\n --\n");
/* 3. about logical drives */
- seq_printf(m,"\nLogical Drives:");
+ seq_puts(m, "\nLogical Drives:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
@@ -411,10 +411,10 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag)
- seq_printf(m, "\n --\n");
+ seq_puts(m, "\n --\n");
/* 4. about array drives */
- seq_printf(m,"\nArray Drives:");
+ seq_puts(m, "\nArray Drives:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, GDTH_SCRATCH, FALSE, &paddr);
@@ -471,10 +471,10 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
gdth_ioctl_free(ha, GDTH_SCRATCH, buf, paddr);
if (!flag)
- seq_printf(m, "\n --\n");
+ seq_puts(m, "\n --\n");
/* 5. about host drives */
- seq_printf(m,"\nHost Drives:");
+ seq_puts(m, "\nHost Drives:");
flag = FALSE;
buf = gdth_ioctl_alloc(ha, sizeof(gdth_hget_str), FALSE, &paddr);
@@ -527,11 +527,11 @@ int gdth_show_info(struct seq_file *m, struct Scsi_Host *host)
}
if (!flag)
- seq_printf(m, "\n --\n");
+ seq_puts(m, "\n --\n");
}
/* controller events */
- seq_printf(m,"\nController Events:\n");
+ seq_puts(m, "\nController Events:\n");
for (id = -1;;) {
id = gdth_read_event(ha, id, estr);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index 6bb4611b238a..a1cfbd3dda47 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -50,6 +50,7 @@
#include <linux/jiffies.h>
#include <linux/percpu-defs.h>
#include <linux/percpu.h>
+#include <asm/unaligned.h>
#include <asm/div64.h>
#include "hpsa_cmd.h"
#include "hpsa.h"
@@ -59,8 +60,11 @@
#define DRIVER_NAME "HP HPSA Driver (v " HPSA_DRIVER_VERSION ")"
#define HPSA "hpsa"
-/* How long to wait (in milliseconds) for board to go into simple mode */
-#define MAX_CONFIG_WAIT 30000
+/* How long to wait for CISS doorbell communication */
+#define CLEAR_EVENT_WAIT_INTERVAL 20 /* ms for each msleep() call */
+#define MODE_CHANGE_WAIT_INTERVAL 10 /* ms for each msleep() call */
+#define MAX_CLEAR_EVENT_WAIT 30000 /* times 20 ms = 600 s */
+#define MAX_MODE_CHANGE_WAIT 2000 /* times 10 ms = 20 s */
#define MAX_IOCTL_CONFIG_WAIT 1000
/*define how many times we will try a command because of bus resets */
@@ -164,24 +168,24 @@ static struct board_type products[] = {
{0x1926103C, "Smart Array P731m", &SA5_access},
{0x1928103C, "Smart Array P230i", &SA5_access},
{0x1929103C, "Smart Array P530", &SA5_access},
- {0x21BD103C, "Smart Array", &SA5_access},
- {0x21BE103C, "Smart Array", &SA5_access},
- {0x21BF103C, "Smart Array", &SA5_access},
- {0x21C0103C, "Smart Array", &SA5_access},
- {0x21C1103C, "Smart Array", &SA5_access},
- {0x21C2103C, "Smart Array", &SA5_access},
- {0x21C3103C, "Smart Array", &SA5_access},
+ {0x21BD103C, "Smart Array P244br", &SA5_access},
+ {0x21BE103C, "Smart Array P741m", &SA5_access},
+ {0x21BF103C, "Smart HBA H240ar", &SA5_access},
+ {0x21C0103C, "Smart Array P440ar", &SA5_access},
+ {0x21C1103C, "Smart Array P840ar", &SA5_access},
+ {0x21C2103C, "Smart Array P440", &SA5_access},
+ {0x21C3103C, "Smart Array P441", &SA5_access},
{0x21C4103C, "Smart Array", &SA5_access},
- {0x21C5103C, "Smart Array", &SA5_access},
- {0x21C6103C, "Smart Array", &SA5_access},
- {0x21C7103C, "Smart Array", &SA5_access},
- {0x21C8103C, "Smart Array", &SA5_access},
+ {0x21C5103C, "Smart Array P841", &SA5_access},
+ {0x21C6103C, "Smart HBA H244br", &SA5_access},
+ {0x21C7103C, "Smart HBA H240", &SA5_access},
+ {0x21C8103C, "Smart HBA H241", &SA5_access},
{0x21C9103C, "Smart Array", &SA5_access},
- {0x21CA103C, "Smart Array", &SA5_access},
- {0x21CB103C, "Smart Array", &SA5_access},
+ {0x21CA103C, "Smart Array P246br", &SA5_access},
+ {0x21CB103C, "Smart Array P840", &SA5_access},
{0x21CC103C, "Smart Array", &SA5_access},
{0x21CD103C, "Smart Array", &SA5_access},
- {0x21CE103C, "Smart Array", &SA5_access},
+ {0x21CE103C, "Smart HBA", &SA5_access},
{0x00761590, "HP Storage P1224 Array Controller", &SA5_access},
{0x00871590, "HP Storage P1224e Array Controller", &SA5_access},
{0x007D1590, "HP Storage P1228 Array Controller", &SA5_access},
@@ -195,8 +199,6 @@ 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 __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,
@@ -204,18 +206,18 @@ static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd,
#endif
static void cmd_free(struct ctlr_info *h, struct CommandList *c);
-static void cmd_special_free(struct ctlr_info *h, struct CommandList *c);
static struct CommandList *cmd_alloc(struct ctlr_info *h);
-static struct CommandList *cmd_special_alloc(struct ctlr_info *h);
static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
void *buff, size_t size, u16 page_code, unsigned char *scsi3addr,
int cmd_type);
+static void hpsa_free_cmd_pool(struct ctlr_info *h);
#define VPD_PAGE (1 << 8)
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);
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
@@ -229,7 +231,7 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
struct CommandList *c);
/* performant mode helper functions */
static void calc_bucket_map(int *bucket, int num_buckets,
- int nsgs, int min_blocks, int *bucket_map);
+ int nsgs, int min_blocks, u32 *bucket_map);
static void hpsa_put_ctlr_into_performant_mode(struct ctlr_info *h);
static inline u32 next_command(struct ctlr_info *h, u8 q);
static int hpsa_find_cfg_addrs(struct pci_dev *pdev, void __iomem *vaddr,
@@ -241,14 +243,15 @@ static int hpsa_lookup_board_id(struct pci_dev *pdev, u32 *board_id);
static int hpsa_wait_for_board_state(struct pci_dev *pdev, void __iomem *vaddr,
int wait_for_ready);
static inline void finish_cmd(struct CommandList *c);
-static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
+static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h);
#define BOARD_NOT_READY 0
#define BOARD_READY 1
static void hpsa_drain_accel_commands(struct ctlr_info *h);
static void hpsa_flush_cache(struct ctlr_info *h);
static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
- u8 *scsi3addr);
+ u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk);
+static void hpsa_command_resubmit_worker(struct work_struct *work);
static inline struct ctlr_info *sdev_to_hba(struct scsi_device *sdev)
{
@@ -505,8 +508,8 @@ static inline int is_logical_dev_addr_mode(unsigned char scsi3addr[])
return (scsi3addr[3] & 0xC0) == 0x40;
}
-static const char *raid_label[] = { "0", "4", "1(1+0)", "5", "5+1", "ADG",
- "1(ADM)", "UNKNOWN"
+static const char * const raid_label[] = { "0", "4", "1(+0)", "5", "5+1", "6",
+ "1(+0)ADM", "UNKNOWN"
};
#define HPSA_RAID_0 0
#define HPSA_RAID_4 1
@@ -671,7 +674,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 = scsi_change_queue_depth,
+ .change_queue_depth = hpsa_change_queue_depth,
.this_id = -1,
.use_clustering = ENABLE_CLUSTERING,
.eh_abort_handler = hpsa_eh_abort_handler,
@@ -688,13 +691,6 @@ static struct scsi_host_template hpsa_driver_template = {
.no_write_same = 1,
};
-
-/* Enqueuing and dequeuing functions for cmdlists. */
-static inline void addQ(struct list_head *list, struct CommandList *c)
-{
- list_add_tail(&c->list, list);
-}
-
static inline u32 next_command(struct ctlr_info *h, u8 q)
{
u32 a;
@@ -828,31 +824,21 @@ static void dial_up_lockup_detection_on_fw_flash_complete(struct ctlr_info *h,
static void enqueue_cmd_and_start_io(struct ctlr_info *h,
struct CommandList *c)
{
- unsigned long flags;
-
+ dial_down_lockup_detection_during_fw_flash(h, c);
+ atomic_inc(&h->commands_outstanding);
switch (c->cmd_type) {
case CMD_IOACCEL1:
set_ioaccel1_performant_mode(h, c);
+ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
break;
case CMD_IOACCEL2:
set_ioaccel2_performant_mode(h, c);
+ writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
break;
default:
set_performant_mode(h, c);
+ h->access.submit_command(h, c);
}
- dial_down_lockup_detection_during_fw_flash(h, c);
- spin_lock_irqsave(&h->lock, flags);
- addQ(&h->reqQ, c);
- h->Qdepth++;
- start_io(h, &flags);
- spin_unlock_irqrestore(&h->lock, flags);
-}
-
-static inline void removeQ(struct CommandList *c)
-{
- if (WARN_ON(list_empty(&c->list)))
- return;
- list_del_init(&c->list);
}
static inline int is_hba_lunid(unsigned char scsi3addr[])
@@ -919,7 +905,7 @@ static int hpsa_scsi_add_entry(struct ctlr_info *h, int hostno,
/* If this device a non-zero lun of a multi-lun device
* byte 4 of the 8-byte LUN addr will contain the logical
- * unit no, zero otherise.
+ * unit no, zero otherwise.
*/
if (device->scsi3addr[4] == 0) {
/* This is not a non-zero lun of a multi-lun device */
@@ -984,12 +970,24 @@ static void hpsa_scsi_update_entry(struct ctlr_info *h, int hostno,
/* Raid level changed. */
h->dev[entry]->raid_level = new_entry->raid_level;
- /* Raid offload parameters changed. */
+ /* Raid offload parameters changed. Careful about the ordering. */
+ if (new_entry->offload_config && new_entry->offload_enabled) {
+ /*
+ * if drive is newly offload_enabled, we want to copy the
+ * raid map data first. If previously offload_enabled and
+ * offload_config were set, raid map data had better be
+ * the same as it was before. if raid map data is changed
+ * then it had better be the case that
+ * h->dev[entry]->offload_enabled is currently 0.
+ */
+ h->dev[entry]->raid_map = new_entry->raid_map;
+ h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
+ wmb(); /* ensure raid map updated prior to ->offload_enabled */
+ }
h->dev[entry]->offload_config = new_entry->offload_config;
- h->dev[entry]->offload_enabled = new_entry->offload_enabled;
- h->dev[entry]->ioaccel_handle = new_entry->ioaccel_handle;
h->dev[entry]->offload_to_mirror = new_entry->offload_to_mirror;
- h->dev[entry]->raid_map = new_entry->raid_map;
+ h->dev[entry]->offload_enabled = new_entry->offload_enabled;
+ h->dev[entry]->queue_depth = new_entry->queue_depth;
dev_info(&h->pdev->dev, "%s device c%db%dt%dl%d updated.\n",
scsi_device_type(new_entry->devtype), hostno, new_entry->bus,
@@ -1115,6 +1113,8 @@ static inline int device_updated(struct hpsa_scsi_dev_t *dev1,
return 1;
if (dev1->offload_enabled != dev2->offload_enabled)
return 1;
+ if (dev1->queue_depth != dev2->queue_depth)
+ return 1;
return 0;
}
@@ -1260,6 +1260,85 @@ static void hpsa_show_volume_status(struct ctlr_info *h,
}
}
+/*
+ * Figure the list of physical drive pointers for a logical drive with
+ * raid offload configured.
+ */
+static void hpsa_figure_phys_disk_ptrs(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *dev[], int ndevices,
+ struct hpsa_scsi_dev_t *logical_drive)
+{
+ struct raid_map_data *map = &logical_drive->raid_map;
+ struct raid_map_disk_data *dd = &map->data[0];
+ int i, j;
+ int total_disks_per_row = le16_to_cpu(map->data_disks_per_row) +
+ le16_to_cpu(map->metadata_disks_per_row);
+ int nraid_map_entries = le16_to_cpu(map->row_cnt) *
+ le16_to_cpu(map->layout_map_count) *
+ total_disks_per_row;
+ int nphys_disk = le16_to_cpu(map->layout_map_count) *
+ total_disks_per_row;
+ int qdepth;
+
+ if (nraid_map_entries > RAID_MAP_MAX_ENTRIES)
+ nraid_map_entries = RAID_MAP_MAX_ENTRIES;
+
+ qdepth = 0;
+ for (i = 0; i < nraid_map_entries; i++) {
+ logical_drive->phys_disk[i] = NULL;
+ if (!logical_drive->offload_config)
+ continue;
+ for (j = 0; j < ndevices; j++) {
+ if (dev[j]->devtype != TYPE_DISK)
+ continue;
+ if (is_logical_dev_addr_mode(dev[j]->scsi3addr))
+ continue;
+ if (dev[j]->ioaccel_handle != dd[i].ioaccel_handle)
+ continue;
+
+ logical_drive->phys_disk[i] = dev[j];
+ if (i < nphys_disk)
+ qdepth = min(h->nr_cmds, qdepth +
+ logical_drive->phys_disk[i]->queue_depth);
+ break;
+ }
+
+ /*
+ * This can happen if a physical drive is removed and
+ * the logical drive is degraded. In that case, the RAID
+ * map data will refer to a physical disk which isn't actually
+ * present. And in that case offload_enabled should already
+ * be 0, but we'll turn it off here just in case
+ */
+ if (!logical_drive->phys_disk[i]) {
+ logical_drive->offload_enabled = 0;
+ logical_drive->queue_depth = h->nr_cmds;
+ }
+ }
+ if (nraid_map_entries)
+ /*
+ * This is correct for reads, too high for full stripe writes,
+ * way too high for partial stripe writes
+ */
+ logical_drive->queue_depth = qdepth;
+ else
+ logical_drive->queue_depth = h->nr_cmds;
+}
+
+static void hpsa_update_log_drive_phys_drive_ptrs(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *dev[], int ndevices)
+{
+ int i;
+
+ for (i = 0; i < ndevices; i++) {
+ if (dev[i]->devtype != TYPE_DISK)
+ continue;
+ if (!is_logical_dev_addr_mode(dev[i]->scsi3addr))
+ continue;
+ hpsa_figure_phys_disk_ptrs(h, dev, ndevices, dev[i]);
+ }
+}
+
static void adjust_hpsa_scsi_table(struct ctlr_info *h, int hostno,
struct hpsa_scsi_dev_t *sd[], int nsds)
{
@@ -1444,8 +1523,12 @@ static int hpsa_slave_alloc(struct scsi_device *sdev)
spin_lock_irqsave(&h->devlock, flags);
sd = lookup_hpsa_scsi_dev(h, sdev_channel(sdev),
sdev_id(sdev), sdev->lun);
- if (sd != NULL)
+ if (sd != NULL) {
sdev->hostdata = sd;
+ if (sd->queue_depth)
+ scsi_change_queue_depth(sdev, sd->queue_depth);
+ atomic_set(&sd->ioaccel_cmds_out, 0);
+ }
spin_unlock_irqrestore(&h->devlock, flags);
return 0;
}
@@ -1478,13 +1561,17 @@ static int hpsa_allocate_sg_chain_blocks(struct ctlr_info *h)
h->cmd_sg_list = kzalloc(sizeof(*h->cmd_sg_list) * h->nr_cmds,
GFP_KERNEL);
- if (!h->cmd_sg_list)
+ if (!h->cmd_sg_list) {
+ dev_err(&h->pdev->dev, "Failed to allocate SG list\n");
return -ENOMEM;
+ }
for (i = 0; i < h->nr_cmds; i++) {
h->cmd_sg_list[i] = kmalloc(sizeof(*h->cmd_sg_list[i]) *
h->chainsize, GFP_KERNEL);
- if (!h->cmd_sg_list[i])
+ if (!h->cmd_sg_list[i]) {
+ dev_err(&h->pdev->dev, "Failed to allocate cmd SG\n");
goto clean;
+ }
}
return 0;
@@ -1504,7 +1591,7 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h,
chain_block = h->cmd_sg_list[c->cmdindex];
chain_sg->Ext = cpu_to_le32(HPSA_SG_CHAIN);
chain_len = sizeof(*chain_sg) *
- (c->Header.SGTotal - h->max_cmd_sg_entries);
+ (le16_to_cpu(c->Header.SGTotal) - h->max_cmd_sg_entries);
chain_sg->Len = cpu_to_le32(chain_len);
temp64 = pci_map_single(h->pdev, chain_block, chain_len,
PCI_DMA_TODEVICE);
@@ -1635,7 +1722,6 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
struct hpsa_scsi_dev_t *dev)
{
struct io_accel2_cmd *c2 = &h->ioaccel2_cmd_pool[c->cmdindex];
- int raid_retry = 0;
/* check for good status */
if (likely(c2->error_data.serv_response == 0 &&
@@ -1652,26 +1738,22 @@ static void process_ioaccel2_completion(struct ctlr_info *h,
if (is_logical_dev_addr_mode(dev->scsi3addr) &&
c2->error_data.serv_response ==
IOACCEL2_SERV_RESPONSE_FAILURE) {
- dev->offload_enabled = 0;
- h->drv_req_rescan = 1; /* schedule controller for a rescan */
- cmd->result = DID_SOFT_ERROR << 16;
- cmd_free(h, c);
- cmd->scsi_done(cmd);
- return;
- }
- raid_retry = handle_ioaccel_mode2_error(h, c, cmd, c2);
- /* If error found, disable Smart Path, schedule a rescan,
- * and force a retry on the standard path.
- */
- if (raid_retry) {
- dev_warn(&h->pdev->dev, "%s: Retrying on standard path.\n",
- "HP SSD Smart Path");
- dev->offload_enabled = 0; /* Disable Smart Path */
- h->drv_req_rescan = 1; /* schedule controller rescan */
- cmd->result = DID_SOFT_ERROR << 16;
+ if (c2->error_data.status ==
+ IOACCEL2_STATUS_SR_IOACCEL_DISABLED)
+ dev->offload_enabled = 0;
+ goto retry_cmd;
}
+
+ if (handle_ioaccel_mode2_error(h, c, cmd, c2))
+ goto retry_cmd;
+
cmd_free(h, c);
cmd->scsi_done(cmd);
+ return;
+
+retry_cmd:
+ INIT_WORK(&c->work, hpsa_command_resubmit_worker);
+ queue_work_on(raw_smp_processor_id(), h->resubmit_wq, &c->work);
}
static void complete_scsi_command(struct CommandList *cp)
@@ -1687,18 +1769,21 @@ static void complete_scsi_command(struct CommandList *cp)
unsigned long sense_data_size;
ei = cp->err_info;
- cmd = (struct scsi_cmnd *) cp->scsi_cmd;
+ cmd = cp->scsi_cmd;
h = cp->h;
dev = cmd->device->hostdata;
scsi_dma_unmap(cmd); /* undo the DMA mappings */
if ((cp->cmd_type == CMD_SCSI) &&
- (cp->Header.SGTotal > h->max_cmd_sg_entries))
+ (le16_to_cpu(cp->Header.SGTotal) > h->max_cmd_sg_entries))
hpsa_unmap_sg_chain_block(h, cp);
cmd->result = (DID_OK << 16); /* host byte */
cmd->result |= (COMMAND_COMPLETE << 8); /* msg byte */
+ if (cp->cmd_type == CMD_IOACCEL2 || cp->cmd_type == CMD_IOACCEL1)
+ atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
+
if (cp->cmd_type == CMD_IOACCEL2)
return process_ioaccel2_completion(h, cp, cmd, dev);
@@ -1706,6 +1791,8 @@ static void complete_scsi_command(struct CommandList *cp)
scsi_set_resid(cmd, ei->ResidualCnt);
if (ei->CommandStatus == 0) {
+ if (cp->cmd_type == CMD_IOACCEL1)
+ atomic_dec(&cp->phys_disk->ioaccel_cmds_out);
cmd_free(h, cp);
cmd->scsi_done(cmd);
return;
@@ -1726,8 +1813,10 @@ static void complete_scsi_command(struct CommandList *cp)
*/
if (cp->cmd_type == CMD_IOACCEL1) {
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.SGList = scsi_sg_count(cmd);
+ cp->Header.SGTotal = cpu_to_le16(cp->Header.SGList);
+ cp->Request.CDBLen = le16_to_cpu(c->io_flags) &
+ IOACCEL1_IOFLAGS_CDBLEN_MASK;
cp->Header.tag = c->tag;
memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
@@ -1739,9 +1828,9 @@ static void complete_scsi_command(struct CommandList *cp)
if (is_logical_dev_addr_mode(dev->scsi3addr)) {
if (ei->CommandStatus == CMD_IOACCEL_DISABLED)
dev->offload_enabled = 0;
- cmd->result = DID_SOFT_ERROR << 16;
- cmd_free(h, cp);
- cmd->scsi_done(cmd);
+ INIT_WORK(&cp->work, hpsa_command_resubmit_worker);
+ queue_work_on(raw_smp_processor_id(),
+ h->resubmit_wq, &cp->work);
return;
}
}
@@ -1798,9 +1887,8 @@ static void complete_scsi_command(struct CommandList *cp)
case CMD_DATA_UNDERRUN: /* let mid layer handle it. */
break;
case CMD_DATA_OVERRUN:
- dev_warn(&h->pdev->dev, "cp %p has"
- " completed with data overrun "
- "reported\n", cp);
+ dev_warn(&h->pdev->dev,
+ "CDB %16phN data overrun\n", cp->Request.CDB);
break;
case CMD_INVALID: {
/* print_bytes(cp, sizeof(*cp), 1, 0);
@@ -1816,34 +1904,38 @@ static void complete_scsi_command(struct CommandList *cp)
break;
case CMD_PROTOCOL_ERR:
cmd->result = DID_ERROR << 16;
- dev_warn(&h->pdev->dev, "cp %p has "
- "protocol error\n", cp);
+ dev_warn(&h->pdev->dev, "CDB %16phN : protocol error\n",
+ cp->Request.CDB);
break;
case CMD_HARDWARE_ERR:
cmd->result = DID_ERROR << 16;
- dev_warn(&h->pdev->dev, "cp %p had hardware error\n", cp);
+ dev_warn(&h->pdev->dev, "CDB %16phN : hardware error\n",
+ cp->Request.CDB);
break;
case CMD_CONNECTION_LOST:
cmd->result = DID_ERROR << 16;
- dev_warn(&h->pdev->dev, "cp %p had connection lost\n", cp);
+ dev_warn(&h->pdev->dev, "CDB %16phN : connection lost\n",
+ cp->Request.CDB);
break;
case CMD_ABORTED:
cmd->result = DID_ABORT << 16;
- dev_warn(&h->pdev->dev, "cp %p was aborted with status 0x%x\n",
- cp, ei->ScsiStatus);
+ dev_warn(&h->pdev->dev, "CDB %16phN was aborted with status 0x%x\n",
+ cp->Request.CDB, ei->ScsiStatus);
break;
case CMD_ABORT_FAILED:
cmd->result = DID_ERROR << 16;
- dev_warn(&h->pdev->dev, "cp %p reports abort failed\n", cp);
+ dev_warn(&h->pdev->dev, "CDB %16phN : abort failed\n",
+ cp->Request.CDB);
break;
case CMD_UNSOLICITED_ABORT:
cmd->result = DID_SOFT_ERROR << 16; /* retry the command */
- dev_warn(&h->pdev->dev, "cp %p aborted due to an unsolicited "
- "abort\n", cp);
+ dev_warn(&h->pdev->dev, "CDB %16phN : unsolicited abort\n",
+ cp->Request.CDB);
break;
case CMD_TIMEOUT:
cmd->result = DID_TIME_OUT << 16;
- dev_warn(&h->pdev->dev, "cp %p timedout\n", cp);
+ dev_warn(&h->pdev->dev, "CDB %16phN timed out\n",
+ cp->Request.CDB);
break;
case CMD_UNABORTABLE:
cmd->result = DID_ERROR << 16;
@@ -2048,10 +2140,10 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
- if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ if (c == NULL) {
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
@@ -2067,7 +2159,7 @@ static int hpsa_scsi_do_inquiry(struct ctlr_info *h, unsigned char *scsi3addr,
rc = -1;
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
@@ -2079,10 +2171,9 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h,
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
-
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
@@ -2098,7 +2189,7 @@ static int hpsa_bmic_ctrl_mode_sense(struct ctlr_info *h,
rc = -1;
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
@@ -2109,10 +2200,10 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
@@ -2128,7 +2219,7 @@ static int hpsa_send_reset(struct ctlr_info *h, unsigned char *scsi3addr,
hpsa_scsi_interpret_error(h, c);
rc = -1;
}
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
@@ -2191,15 +2282,13 @@ static void hpsa_debug_map_buff(struct ctlr_info *h, int rc,
le16_to_cpu(map_buff->row_cnt));
dev_info(&h->pdev->dev, "layout_map_count = %u\n",
le16_to_cpu(map_buff->layout_map_count));
- dev_info(&h->pdev->dev, "flags = %u\n",
+ dev_info(&h->pdev->dev, "flags = 0x%x\n",
le16_to_cpu(map_buff->flags));
- if (map_buff->flags & RAID_MAP_FLAG_ENCRYPT_ON)
- dev_info(&h->pdev->dev, "encrypytion = ON\n");
- else
- dev_info(&h->pdev->dev, "encrypytion = OFF\n");
+ dev_info(&h->pdev->dev, "encrypytion = %s\n",
+ le16_to_cpu(map_buff->flags) &
+ RAID_MAP_FLAG_ENCRYPT_ON ? "ON" : "OFF");
dev_info(&h->pdev->dev, "dekindex = %u\n",
le16_to_cpu(map_buff->dekindex));
-
map_cnt = le16_to_cpu(map_buff->layout_map_count);
for (map = 0; map < map_cnt; map++) {
dev_info(&h->pdev->dev, "Map%u:\n", map);
@@ -2238,26 +2327,26 @@ static int hpsa_get_raid_map(struct ctlr_info *h,
struct CommandList *c;
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) {
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
if (fill_cmd(c, HPSA_GET_RAID_MAP, h, &this_device->raid_map,
sizeof(this_device->raid_map), 0,
scsi3addr, TYPE_CMD)) {
dev_warn(&h->pdev->dev, "Out of memory in hpsa_get_raid_map()\n");
- cmd_special_free(h, c);
+ cmd_free(h, c);
return -ENOMEM;
}
hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
ei = c->err_info;
if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
hpsa_scsi_interpret_error(h, c);
- cmd_special_free(h, c);
+ cmd_free(h, c);
return -1;
}
- cmd_special_free(h, c);
+ cmd_free(h, c);
/* @todo in the future, dynamically allocate RAID map memory */
if (le32_to_cpu(this_device->raid_map.structure_size) >
@@ -2269,6 +2358,34 @@ static int hpsa_get_raid_map(struct ctlr_info *h,
return rc;
}
+static int hpsa_bmic_id_physical_device(struct ctlr_info *h,
+ unsigned char scsi3addr[], u16 bmic_device_index,
+ struct bmic_identify_physical_device *buf, size_t bufsize)
+{
+ int rc = IO_OK;
+ struct CommandList *c;
+ struct ErrorInfo *ei;
+
+ c = cmd_alloc(h);
+ rc = fill_cmd(c, BMIC_IDENTIFY_PHYSICAL_DEVICE, h, buf, bufsize,
+ 0, RAID_CTLR_LUNID, TYPE_CMD);
+ if (rc)
+ goto out;
+
+ c->Request.CDB[2] = bmic_device_index & 0xff;
+ c->Request.CDB[9] = (bmic_device_index >> 8) & 0xff;
+
+ hpsa_scsi_do_simple_cmd_with_retry(h, c, PCI_DMA_FROMDEVICE);
+ ei = c->err_info;
+ if (ei->CommandStatus != 0 && ei->CommandStatus != CMD_DATA_UNDERRUN) {
+ hpsa_scsi_interpret_error(h, c);
+ rc = -1;
+ }
+out:
+ cmd_free(h, c);
+ return rc;
+}
+
static int hpsa_vpd_page_supported(struct ctlr_info *h,
unsigned char scsi3addr[], u8 page)
{
@@ -2369,7 +2486,7 @@ static int hpsa_get_device_id(struct ctlr_info *h, unsigned char *scsi3addr,
}
static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
- struct ReportLUNdata *buf, int bufsize,
+ void *buf, int bufsize,
int extended_response)
{
int rc = IO_OK;
@@ -2377,9 +2494,9 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
unsigned char scsi3addr[8];
struct ErrorInfo *ei;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_err(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -1;
}
/* address the controller */
@@ -2398,24 +2515,26 @@ static int hpsa_scsi_do_report_luns(struct ctlr_info *h, int logical,
hpsa_scsi_interpret_error(h, c);
rc = -1;
} else {
- if (buf->extended_response_flag != extended_response) {
+ struct ReportLUNdata *rld = buf;
+
+ if (rld->extended_response_flag != extended_response) {
dev_err(&h->pdev->dev,
"report luns requested format %u, got %u\n",
extended_response,
- buf->extended_response_flag);
+ rld->extended_response_flag);
rc = -1;
}
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
static inline int hpsa_scsi_do_report_phys_luns(struct ctlr_info *h,
- struct ReportLUNdata *buf,
- int bufsize, int extended_response)
+ struct ReportExtendedLUNdata *buf, int bufsize)
{
- return hpsa_scsi_do_report_luns(h, 0, buf, bufsize, extended_response);
+ return hpsa_scsi_do_report_luns(h, 0, buf, bufsize,
+ HPSA_REPORT_PHYS_EXTENDED);
}
static inline int hpsa_scsi_do_report_log_luns(struct ctlr_info *h,
@@ -2590,6 +2709,7 @@ static int hpsa_update_device_info(struct ctlr_info *h,
this_device->offload_config = 0;
this_device->offload_enabled = 0;
this_device->volume_offline = 0;
+ this_device->queue_depth = h->nr_cmds;
}
if (is_OBDR_device) {
@@ -2732,7 +2852,6 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
{
struct ReportExtendedLUNdata *physicals = NULL;
int responsesize = 24; /* size of physical extended response */
- int extended = 2; /* flag forces reporting 'other dev info'. */
int reportsize = sizeof(*physicals) + HPSA_MAX_PHYS_LUN * responsesize;
u32 nphysicals = 0; /* number of reported physical devs */
int found = 0; /* found match (1) or not (0) */
@@ -2741,8 +2860,8 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
struct scsi_cmnd *scmd; /* scsi command within request being aborted */
struct hpsa_scsi_dev_t *d; /* device of request being aborted */
struct io_accel2_cmd *c2a; /* ioaccel2 command to abort */
- u32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */
- u32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */
+ __le32 it_nexus; /* 4 byte device handle for the ioaccel2 cmd */
+ __le32 scsi_nexus; /* 4 byte device handle for the ioaccel2 cmd */
if (ioaccel2_cmd_to_abort->cmd_type != CMD_IOACCEL2)
return 0; /* no match */
@@ -2761,8 +2880,8 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
return 0; /* no match */
it_nexus = cpu_to_le32(d->ioaccel_handle);
- scsi_nexus = cpu_to_le32(c2a->scsi_nexus);
- find = c2a->scsi_nexus;
+ scsi_nexus = c2a->scsi_nexus;
+ find = le32_to_cpu(c2a->scsi_nexus);
if (h->raid_offload_debug > 0)
dev_info(&h->pdev->dev,
@@ -2779,8 +2898,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
physicals = kzalloc(reportsize, GFP_KERNEL);
if (physicals == NULL)
return 0;
- if (hpsa_scsi_do_report_phys_luns(h, (struct ReportLUNdata *) physicals,
- reportsize, extended)) {
+ if (hpsa_scsi_do_report_phys_luns(h, physicals, reportsize)) {
dev_err(&h->pdev->dev,
"Can't lookup %s device handle: report physical LUNs failed.\n",
"HP SSD Smart Path");
@@ -2821,34 +2939,20 @@ 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 reportphyslunsize, int reportloglunsize,
- struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode,
+ struct ReportExtendedLUNdata *physdev, u32 *nphysicals,
struct ReportLUNdata *logdev, u32 *nlogicals)
{
- int physical_entry_size = 8;
-
- *physical_mode = 0;
-
- /* For I/O accelerator mode we need to read physical device handles */
- if (h->transMethod & CFGTBL_Trans_io_accel1 ||
- h->transMethod & CFGTBL_Trans_io_accel2) {
- *physical_mode = HPSA_REPORT_PHYS_EXTENDED;
- physical_entry_size = 24;
- }
- if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize,
- *physical_mode)) {
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, sizeof(*physdev))) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
}
- *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) /
- physical_entry_size;
+ *nphysicals = be32_to_cpu(*((__be32 *)physdev->LUNListLength)) / 24;
if (*nphysicals > HPSA_MAX_PHYS_LUN) {
- dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded."
- " %d LUNs ignored.\n", HPSA_MAX_PHYS_LUN,
- *nphysicals - HPSA_MAX_PHYS_LUN);
+ dev_warn(&h->pdev->dev, "maximum physical LUNs (%d) exceeded. %d LUNs ignored.\n",
+ HPSA_MAX_PHYS_LUN, *nphysicals - HPSA_MAX_PHYS_LUN);
*nphysicals = HPSA_MAX_PHYS_LUN;
}
- if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) {
+ if (hpsa_scsi_do_report_log_luns(h, logdev, sizeof(*logdev))) {
dev_err(&h->pdev->dev, "report logical LUNs failed.\n");
return -1;
}
@@ -2921,6 +3025,33 @@ static int hpsa_hba_mode_enabled(struct ctlr_info *h)
return hba_mode_enabled;
}
+/* get physical drive ioaccel handle and queue depth */
+static void hpsa_get_ioaccel_drive_info(struct ctlr_info *h,
+ struct hpsa_scsi_dev_t *dev,
+ u8 *lunaddrbytes,
+ struct bmic_identify_physical_device *id_phys)
+{
+ int rc;
+ struct ext_report_lun_entry *rle =
+ (struct ext_report_lun_entry *) lunaddrbytes;
+
+ dev->ioaccel_handle = rle->ioaccel_handle;
+ memset(id_phys, 0, sizeof(*id_phys));
+ rc = hpsa_bmic_id_physical_device(h, lunaddrbytes,
+ GET_BMIC_DRIVE_NUMBER(lunaddrbytes), id_phys,
+ sizeof(*id_phys));
+ if (!rc)
+ /* Reserve space for FW operations */
+#define DRIVE_CMDS_RESERVED_FOR_FW 2
+#define DRIVE_QUEUE_DEPTH 7
+ dev->queue_depth =
+ le16_to_cpu(id_phys->current_queue_depth_limit) -
+ DRIVE_CMDS_RESERVED_FOR_FW;
+ else
+ dev->queue_depth = DRIVE_QUEUE_DEPTH; /* conservative */
+ atomic_set(&dev->ioaccel_cmds_out, 0);
+}
+
static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
{
/* the idea here is we could get notified
@@ -2935,9 +3066,9 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
*/
struct ReportExtendedLUNdata *physdev_list = NULL;
struct ReportLUNdata *logdev_list = NULL;
+ struct bmic_identify_physical_device *id_phys = NULL;
u32 nphysicals = 0;
u32 nlogicals = 0;
- int physical_mode = 0;
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
@@ -2950,8 +3081,10 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL);
logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
+ id_phys = kzalloc(sizeof(*id_phys), GFP_KERNEL);
- if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) {
+ if (!currentsd || !physdev_list || !logdev_list ||
+ !tmpdevice || !id_phys) {
dev_err(&h->pdev->dev, "out of memory\n");
goto out;
}
@@ -2968,10 +3101,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,
- sizeof(*physdev_list), sizeof(*logdev_list),
- (struct ReportLUNdata *) physdev_list, &nphysicals,
- &physical_mode, logdev_list, &nlogicals))
+ if (hpsa_gather_lun_info(h, physdev_list, &nphysicals,
+ logdev_list, &nlogicals))
goto out;
/* We might see up to the maximum number of logical and physical disks
@@ -3068,10 +3199,11 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
ncurrent++;
break;
}
- if (physical_mode == HPSA_REPORT_PHYS_EXTENDED) {
- memcpy(&this_device->ioaccel_handle,
- &lunaddrbytes[20],
- sizeof(this_device->ioaccel_handle));
+ if (h->transMethod & CFGTBL_Trans_io_accel1 ||
+ h->transMethod & CFGTBL_Trans_io_accel2) {
+ hpsa_get_ioaccel_drive_info(h, this_device,
+ lunaddrbytes, id_phys);
+ atomic_set(&this_device->ioaccel_cmds_out, 0);
ncurrent++;
}
break;
@@ -3095,6 +3227,7 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
if (ncurrent >= HPSA_MAX_DEVICES)
break;
}
+ hpsa_update_log_drive_phys_drive_ptrs(h, currentsd, ncurrent);
adjust_hpsa_scsi_table(h, hostno, currentsd, ncurrent);
out:
kfree(tmpdevice);
@@ -3103,9 +3236,22 @@ out:
kfree(currentsd);
kfree(physdev_list);
kfree(logdev_list);
+ kfree(id_phys);
}
-/* hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
+static void hpsa_set_sg_descriptor(struct SGDescriptor *desc,
+ struct scatterlist *sg)
+{
+ u64 addr64 = (u64) sg_dma_address(sg);
+ unsigned int len = sg_dma_len(sg);
+
+ desc->Addr = cpu_to_le64(addr64);
+ desc->Len = cpu_to_le32(len);
+ desc->Ext = 0;
+}
+
+/*
+ * hpsa_scatter_gather takes a struct scsi_cmnd, (cmd), and does the pci
* dma mapping and fills in the scatter gather entries of the
* hpsa command, cp.
*/
@@ -3113,9 +3259,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
struct CommandList *cp,
struct scsi_cmnd *cmd)
{
- unsigned int len;
struct scatterlist *sg;
- u64 addr64;
int use_sg, i, sg_index, chained;
struct SGDescriptor *curr_sg;
@@ -3138,13 +3282,11 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
curr_sg = h->cmd_sg_list[cp->cmdindex];
sg_index = 0;
}
- addr64 = (u64) sg_dma_address(sg);
- len = sg_dma_len(sg);
- curr_sg->Addr = cpu_to_le64(addr64);
- curr_sg->Len = cpu_to_le32(len);
- curr_sg->Ext = cpu_to_le32(0);
+ hpsa_set_sg_descriptor(curr_sg, sg);
curr_sg++;
}
+
+ /* Back the pointer up to the last entry and mark it as "last". */
(--curr_sg)->Ext = cpu_to_le32(HPSA_SG_LAST);
if (use_sg + chained > h->maxSG)
@@ -3163,7 +3305,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 = cpu_to_le16(use_sg); /* total sgs in this cmd list */
+ cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in cmd list */
return 0;
}
@@ -3217,7 +3359,7 @@ static int fixup_ioaccel_cdb(u8 *cdb, int *cdb_len)
static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
- u8 *scsi3addr)
+ u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
{
struct scsi_cmnd *cmd = c->scsi_cmd;
struct io_accel1_cmd *cp = &h->ioaccel_cmd_pool[c->cmdindex];
@@ -3230,13 +3372,17 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
u32 control = IOACCEL1_CONTROL_SIMPLEQUEUE;
/* TODO: implement chaining support */
- if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE;
+ }
BUG_ON(cmd->cmd_len > IOACCEL1_IOFLAGS_CDBLEN_MAX);
- if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE;
+ }
c->cmd_type = CMD_IOACCEL1;
@@ -3246,8 +3392,10 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
BUG_ON(c->busaddr & 0x0000007F);
use_sg = scsi_dma_map(cmd);
- if (use_sg < 0)
+ if (use_sg < 0) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
return use_sg;
+ }
if (use_sg) {
curr_sg = cp->SG;
@@ -3284,11 +3432,11 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
c->Header.SGList = use_sg;
/* Fill out the command structure to submit */
- cp->dev_handle = ioaccel_handle & 0xFFFF;
- cp->transfer_len = total_len;
- cp->io_flags = IOACCEL1_IOFLAGS_IO_REQ |
- (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK);
- cp->control = control;
+ cp->dev_handle = cpu_to_le16(ioaccel_handle & 0xFFFF);
+ cp->transfer_len = cpu_to_le32(total_len);
+ cp->io_flags = cpu_to_le16(IOACCEL1_IOFLAGS_IO_REQ |
+ (cdb_len & IOACCEL1_IOFLAGS_CDBLEN_MASK));
+ cp->control = cpu_to_le32(control);
memcpy(cp->CDB, cdb, cdb_len);
memcpy(cp->CISS_LUN, scsi3addr, 8);
/* Tag was already set at init time. */
@@ -3306,8 +3454,10 @@ static int hpsa_scsi_ioaccel_direct_map(struct ctlr_info *h,
struct scsi_cmnd *cmd = c->scsi_cmd;
struct hpsa_scsi_dev_t *dev = cmd->device->hostdata;
+ c->phys_disk = dev;
+
return hpsa_scsi_ioaccel_queue_command(h, c, dev->ioaccel_handle,
- cmd->cmnd, cmd->cmd_len, dev->scsi3addr);
+ cmd->cmnd, cmd->cmd_len, dev->scsi3addr, dev);
}
/*
@@ -3321,10 +3471,8 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h,
struct raid_map_data *map = &dev->raid_map;
u64 first_block;
- BUG_ON(!(dev->offload_config && dev->offload_enabled));
-
/* Are we doing encryption on this device */
- if (!(map->flags & RAID_MAP_FLAG_ENCRYPT_ON))
+ if (!(le16_to_cpu(map->flags) & RAID_MAP_FLAG_ENCRYPT_ON))
return;
/* Set the data encryption key index. */
cp->dekindex = map->dekindex;
@@ -3340,101 +3488,38 @@ static void set_encrypt_ioaccel2(struct ctlr_info *h,
/* Required? 6-byte cdbs eliminated by fixup_ioaccel_cdb */
case WRITE_6:
case READ_6:
- if (map->volume_blk_size == 512) {
- cp->tweak_lower =
- (((u32) cmd->cmnd[2]) << 8) |
- cmd->cmnd[3];
- cp->tweak_upper = 0;
- } else {
- first_block =
- (((u64) cmd->cmnd[2]) << 8) |
- cmd->cmnd[3];
- first_block = (first_block * map->volume_blk_size)/512;
- cp->tweak_lower = (u32)first_block;
- cp->tweak_upper = (u32)(first_block >> 32);
- }
+ first_block = get_unaligned_be16(&cmd->cmnd[2]);
break;
case WRITE_10:
case READ_10:
- if (map->volume_blk_size == 512) {
- cp->tweak_lower =
- (((u32) cmd->cmnd[2]) << 24) |
- (((u32) cmd->cmnd[3]) << 16) |
- (((u32) cmd->cmnd[4]) << 8) |
- cmd->cmnd[5];
- cp->tweak_upper = 0;
- } else {
- first_block =
- (((u64) cmd->cmnd[2]) << 24) |
- (((u64) cmd->cmnd[3]) << 16) |
- (((u64) cmd->cmnd[4]) << 8) |
- cmd->cmnd[5];
- first_block = (first_block * map->volume_blk_size)/512;
- cp->tweak_lower = (u32)first_block;
- cp->tweak_upper = (u32)(first_block >> 32);
- }
- break;
/* Required? 12-byte cdbs eliminated by fixup_ioaccel_cdb */
case WRITE_12:
case READ_12:
- if (map->volume_blk_size == 512) {
- cp->tweak_lower =
- (((u32) cmd->cmnd[2]) << 24) |
- (((u32) cmd->cmnd[3]) << 16) |
- (((u32) cmd->cmnd[4]) << 8) |
- cmd->cmnd[5];
- cp->tweak_upper = 0;
- } else {
- first_block =
- (((u64) cmd->cmnd[2]) << 24) |
- (((u64) cmd->cmnd[3]) << 16) |
- (((u64) cmd->cmnd[4]) << 8) |
- cmd->cmnd[5];
- first_block = (first_block * map->volume_blk_size)/512;
- cp->tweak_lower = (u32)first_block;
- cp->tweak_upper = (u32)(first_block >> 32);
- }
+ first_block = get_unaligned_be32(&cmd->cmnd[2]);
break;
case WRITE_16:
case READ_16:
- if (map->volume_blk_size == 512) {
- cp->tweak_lower =
- (((u32) cmd->cmnd[6]) << 24) |
- (((u32) cmd->cmnd[7]) << 16) |
- (((u32) cmd->cmnd[8]) << 8) |
- cmd->cmnd[9];
- cp->tweak_upper =
- (((u32) cmd->cmnd[2]) << 24) |
- (((u32) cmd->cmnd[3]) << 16) |
- (((u32) cmd->cmnd[4]) << 8) |
- cmd->cmnd[5];
- } else {
- first_block =
- (((u64) cmd->cmnd[2]) << 56) |
- (((u64) cmd->cmnd[3]) << 48) |
- (((u64) cmd->cmnd[4]) << 40) |
- (((u64) cmd->cmnd[5]) << 32) |
- (((u64) cmd->cmnd[6]) << 24) |
- (((u64) cmd->cmnd[7]) << 16) |
- (((u64) cmd->cmnd[8]) << 8) |
- cmd->cmnd[9];
- first_block = (first_block * map->volume_blk_size)/512;
- cp->tweak_lower = (u32)first_block;
- cp->tweak_upper = (u32)(first_block >> 32);
- }
+ first_block = get_unaligned_be64(&cmd->cmnd[2]);
break;
default:
dev_err(&h->pdev->dev,
- "ERROR: %s: IOACCEL request CDB size not supported for encryption\n",
- __func__);
+ "ERROR: %s: size (0x%x) not supported for encryption\n",
+ __func__, cmd->cmnd[0]);
BUG();
break;
}
+
+ if (le32_to_cpu(map->volume_blk_size) != 512)
+ first_block = first_block *
+ le32_to_cpu(map->volume_blk_size)/512;
+
+ cp->tweak_lower = cpu_to_le32(first_block);
+ cp->tweak_upper = cpu_to_le32(first_block >> 32);
}
static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
- u8 *scsi3addr)
+ u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
{
struct scsi_cmnd *cmd = c->scsi_cmd;
struct io_accel2_cmd *cp = &h->ioaccel2_cmd_pool[c->cmdindex];
@@ -3445,11 +3530,16 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
u32 len;
u32 total_len = 0;
- if (scsi_sg_count(cmd) > h->ioaccel_maxsg)
+ if (scsi_sg_count(cmd) > h->ioaccel_maxsg) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE;
+ }
- if (fixup_ioaccel_cdb(cdb, &cdb_len))
+ if (fixup_ioaccel_cdb(cdb, &cdb_len)) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
return IO_ACCEL_INELIGIBLE;
+ }
+
c->cmd_type = CMD_IOACCEL2;
/* Adjust the DMA address to point to the accelerated command buffer */
c->busaddr = (u32) h->ioaccel2_cmd_pool_dhandle +
@@ -3460,8 +3550,10 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
cp->IU_type = IOACCEL2_IU_TYPE;
use_sg = scsi_dma_map(cmd);
- if (use_sg < 0)
+ if (use_sg < 0) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
return use_sg;
+ }
if (use_sg) {
BUG_ON(use_sg > IOACCEL2_MAXSGENTRIES);
@@ -3506,9 +3598,8 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
/* Set encryption parameters, if necessary */
set_encrypt_ioaccel2(h, c, cp);
- cp->scsi_nexus = ioaccel_handle;
- cp->Tag = (c->cmdindex << DIRECT_LOOKUP_SHIFT) |
- DIRECT_LOOKUP_BIT;
+ cp->scsi_nexus = cpu_to_le32(ioaccel_handle);
+ cp->Tag = cpu_to_le32(c->cmdindex << DIRECT_LOOKUP_SHIFT);
memcpy(cp->cdb, cdb, sizeof(cp->cdb));
/* fill in sg elements */
@@ -3528,14 +3619,22 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
*/
static int hpsa_scsi_ioaccel_queue_command(struct ctlr_info *h,
struct CommandList *c, u32 ioaccel_handle, u8 *cdb, int cdb_len,
- u8 *scsi3addr)
+ u8 *scsi3addr, struct hpsa_scsi_dev_t *phys_disk)
{
+ /* Try to honor the device's queue depth */
+ if (atomic_inc_return(&phys_disk->ioaccel_cmds_out) >
+ phys_disk->queue_depth) {
+ atomic_dec(&phys_disk->ioaccel_cmds_out);
+ return IO_ACCEL_INELIGIBLE;
+ }
if (h->transMethod & CFGTBL_Trans_io_accel1)
return hpsa_scsi_ioaccel1_queue_command(h, c, ioaccel_handle,
- cdb, cdb_len, scsi3addr);
+ cdb, cdb_len, scsi3addr,
+ phys_disk);
else
return hpsa_scsi_ioaccel2_queue_command(h, c, ioaccel_handle,
- cdb, cdb_len, scsi3addr);
+ cdb, cdb_len, scsi3addr,
+ phys_disk);
}
static void raid_map_helper(struct raid_map_data *map,
@@ -3543,21 +3642,22 @@ static void raid_map_helper(struct raid_map_data *map,
{
if (offload_to_mirror == 0) {
/* use physical disk in the first mirrored group. */
- *map_index %= map->data_disks_per_row;
+ *map_index %= le16_to_cpu(map->data_disks_per_row);
return;
}
do {
/* determine mirror group that *map_index indicates */
- *current_group = *map_index / map->data_disks_per_row;
+ *current_group = *map_index /
+ le16_to_cpu(map->data_disks_per_row);
if (offload_to_mirror == *current_group)
continue;
- if (*current_group < (map->layout_map_count - 1)) {
+ if (*current_group < le16_to_cpu(map->layout_map_count) - 1) {
/* select map index from next group */
- *map_index += map->data_disks_per_row;
+ *map_index += le16_to_cpu(map->data_disks_per_row);
(*current_group)++;
} else {
/* select map index from first group */
- *map_index %= map->data_disks_per_row;
+ *map_index %= le16_to_cpu(map->data_disks_per_row);
*current_group = 0;
}
} while (offload_to_mirror != *current_group);
@@ -3595,13 +3695,12 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
u32 disk_block_cnt;
u8 cdb[16];
u8 cdb_len;
+ u16 strip_size;
#if BITS_PER_LONG == 32
u64 tmpdiv;
#endif
int offload_to_mirror;
- BUG_ON(!(dev->offload_config && dev->offload_enabled));
-
/* check for valid opcode, get LBA and block count */
switch (cmd->cmnd[0]) {
case WRITE_6:
@@ -3668,11 +3767,14 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
return IO_ACCEL_INELIGIBLE;
/* check for invalid block or wraparound */
- if (last_block >= map->volume_blk_cnt || last_block < first_block)
+ if (last_block >= le64_to_cpu(map->volume_blk_cnt) ||
+ last_block < first_block)
return IO_ACCEL_INELIGIBLE;
/* calculate stripe information for the request */
- blocks_per_row = map->data_disks_per_row * map->strip_size;
+ blocks_per_row = le16_to_cpu(map->data_disks_per_row) *
+ le16_to_cpu(map->strip_size);
+ strip_size = le16_to_cpu(map->strip_size);
#if BITS_PER_LONG == 32
tmpdiv = first_block;
(void) do_div(tmpdiv, blocks_per_row);
@@ -3683,18 +3785,18 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
tmpdiv = first_row_offset;
- (void) do_div(tmpdiv, map->strip_size);
+ (void) do_div(tmpdiv, strip_size);
first_column = tmpdiv;
tmpdiv = last_row_offset;
- (void) do_div(tmpdiv, map->strip_size);
+ (void) do_div(tmpdiv, strip_size);
last_column = tmpdiv;
#else
first_row = first_block / blocks_per_row;
last_row = last_block / blocks_per_row;
first_row_offset = (u32) (first_block - (first_row * blocks_per_row));
last_row_offset = (u32) (last_block - (last_row * blocks_per_row));
- first_column = first_row_offset / map->strip_size;
- last_column = last_row_offset / map->strip_size;
+ first_column = first_row_offset / strip_size;
+ last_column = last_row_offset / strip_size;
#endif
/* if this isn't a single row/column then give to the controller */
@@ -3702,10 +3804,10 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
return IO_ACCEL_INELIGIBLE;
/* proceeding with driver mapping */
- total_disks_per_row = map->data_disks_per_row +
- map->metadata_disks_per_row;
+ total_disks_per_row = le16_to_cpu(map->data_disks_per_row) +
+ le16_to_cpu(map->metadata_disks_per_row);
map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
- map->row_cnt;
+ le16_to_cpu(map->row_cnt);
map_index = (map_row * total_disks_per_row) + first_column;
switch (dev->raid_level) {
@@ -3716,23 +3818,24 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
* (2-drive R1 and R10 with even # of drives.)
* Appropriate for SSDs, not optimal for HDDs
*/
- BUG_ON(map->layout_map_count != 2);
+ BUG_ON(le16_to_cpu(map->layout_map_count) != 2);
if (dev->offload_to_mirror)
- map_index += map->data_disks_per_row;
+ map_index += le16_to_cpu(map->data_disks_per_row);
dev->offload_to_mirror = !dev->offload_to_mirror;
break;
case HPSA_RAID_ADM:
/* Handles N-way mirrors (R1-ADM)
* and R10 with # of drives divisible by 3.)
*/
- BUG_ON(map->layout_map_count != 3);
+ BUG_ON(le16_to_cpu(map->layout_map_count) != 3);
offload_to_mirror = dev->offload_to_mirror;
raid_map_helper(map, offload_to_mirror,
&map_index, &current_group);
/* set mirror group to use next time */
offload_to_mirror =
- (offload_to_mirror >= map->layout_map_count - 1)
+ (offload_to_mirror >=
+ le16_to_cpu(map->layout_map_count) - 1)
? 0 : offload_to_mirror + 1;
dev->offload_to_mirror = offload_to_mirror;
/* Avoid direct use of dev->offload_to_mirror within this
@@ -3742,14 +3845,16 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
break;
case HPSA_RAID_5:
case HPSA_RAID_6:
- if (map->layout_map_count <= 1)
+ if (le16_to_cpu(map->layout_map_count) <= 1)
break;
/* Verify first and last block are in same RAID group */
r5or6_blocks_per_row =
- map->strip_size * map->data_disks_per_row;
+ le16_to_cpu(map->strip_size) *
+ le16_to_cpu(map->data_disks_per_row);
BUG_ON(r5or6_blocks_per_row == 0);
- stripesize = r5or6_blocks_per_row * map->layout_map_count;
+ stripesize = r5or6_blocks_per_row *
+ le16_to_cpu(map->layout_map_count);
#if BITS_PER_LONG == 32
tmpdiv = first_block;
first_group = do_div(tmpdiv, stripesize);
@@ -3812,28 +3917,35 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
r5or6_blocks_per_row);
first_column = r5or6_first_column =
- r5or6_first_row_offset / map->strip_size;
+ r5or6_first_row_offset / le16_to_cpu(map->strip_size);
r5or6_last_column =
- r5or6_last_row_offset / map->strip_size;
+ r5or6_last_row_offset / le16_to_cpu(map->strip_size);
#endif
if (r5or6_first_column != r5or6_last_column)
return IO_ACCEL_INELIGIBLE;
/* Request is eligible */
map_row = ((u32)(first_row >> map->parity_rotation_shift)) %
- map->row_cnt;
+ le16_to_cpu(map->row_cnt);
map_index = (first_group *
- (map->row_cnt * total_disks_per_row)) +
+ (le16_to_cpu(map->row_cnt) * total_disks_per_row)) +
(map_row * total_disks_per_row) + first_column;
break;
default:
return IO_ACCEL_INELIGIBLE;
}
+ if (unlikely(map_index >= RAID_MAP_MAX_ENTRIES))
+ return IO_ACCEL_INELIGIBLE;
+
+ c->phys_disk = dev->phys_disk[map_index];
+
disk_handle = dd[map_index].ioaccel_handle;
- disk_block = map->disk_starting_blk + (first_row * map->strip_size) +
- (first_row_offset - (first_column * map->strip_size));
+ disk_block = le64_to_cpu(map->disk_starting_blk) +
+ first_row * le16_to_cpu(map->strip_size) +
+ (first_row_offset - first_column *
+ le16_to_cpu(map->strip_size));
disk_block_cnt = block_cnt;
/* handle differing logical/physical block sizes */
@@ -3876,78 +3988,21 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
cdb_len = 10;
}
return hpsa_scsi_ioaccel_queue_command(h, c, disk_handle, cdb, cdb_len,
- dev->scsi3addr);
+ dev->scsi3addr,
+ dev->phys_disk[map_index]);
}
-/*
- * 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)
+/* Submit commands down the "normal" RAID stack path */
+static int hpsa_ciss_submit(struct ctlr_info *h,
+ struct CommandList *c, struct scsi_cmnd *cmd,
+ unsigned char scsi3addr[])
{
- struct ctlr_info *h;
- struct hpsa_scsi_dev_t *dev;
- unsigned char scsi3addr[8];
- struct CommandList *c;
- int rc = 0;
-
- /* Get the ptr to our adapter structure out of cmd->host. */
- h = sdev_to_hba(cmd->device);
- dev = cmd->device->hostdata;
- if (!dev) {
- cmd->result = DID_NO_CONNECT << 16;
- cmd->scsi_done(cmd);
- return 0;
- }
- memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
-
- if (unlikely(lockup_detected(h))) {
- cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
- return 0;
- }
- c = cmd_alloc(h);
- if (c == NULL) { /* trouble... */
- dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
- return SCSI_MLQUEUE_HOST_BUSY;
- }
-
- /* Fill in the command list header */
- /* save c in case we have to abort it */
cmd->host_scribble = (unsigned char *) c;
-
c->cmd_type = CMD_SCSI;
c->scsi_cmd = cmd;
-
- /* Call alternate submit routine for I/O accelerated commands.
- * Retries always go down the normal I/O path.
- */
- if (likely(cmd->retries == 0 &&
- cmd->request->cmd_type == REQ_TYPE_FS &&
- h->acciopath_status)) {
- if (dev->offload_enabled) {
- rc = hpsa_scsi_ioaccel_raid_map(h, c);
- if (rc == 0)
- return 0; /* Sent on ioaccel path */
- if (rc < 0) { /* scsi_dma_map failed. */
- cmd_free(h, c);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
- } else if (dev->ioaccel_handle) {
- rc = hpsa_scsi_ioaccel_direct_map(h, c);
- if (rc == 0)
- return 0; /* Sent on direct map path */
- if (rc < 0) { /* scsi_dma_map failed. */
- cmd_free(h, c);
- return SCSI_MLQUEUE_HOST_BUSY;
- }
- }
- }
-
c->Header.ReplyQueue = 0; /* unused in simple mode */
memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
- c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT) |
- DIRECT_LOOKUP_BIT);
+ c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT));
/* Fill in the request block... */
@@ -4003,25 +4058,108 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
return 0;
}
-static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)
+static void hpsa_command_resubmit_worker(struct work_struct *work)
{
- unsigned long flags;
+ struct scsi_cmnd *cmd;
+ struct hpsa_scsi_dev_t *dev;
+ struct CommandList *c =
+ container_of(work, struct CommandList, work);
+
+ cmd = c->scsi_cmd;
+ dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ cmd->scsi_done(cmd);
+ return;
+ }
+ if (hpsa_ciss_submit(c->h, c, cmd, dev->scsi3addr)) {
+ /*
+ * If we get here, it means dma mapping failed. Try
+ * again via scsi mid layer, which will then get
+ * SCSI_MLQUEUE_HOST_BUSY.
+ */
+ cmd->result = DID_IMM_RETRY << 16;
+ cmd->scsi_done(cmd);
+ }
+}
+
+/* Running in struct Scsi_Host->host_lock less mode */
+static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+{
+ struct ctlr_info *h;
+ struct hpsa_scsi_dev_t *dev;
+ unsigned char scsi3addr[8];
+ struct CommandList *c;
+ int rc = 0;
+
+ /* Get the ptr to our adapter structure out of cmd->host. */
+ h = sdev_to_hba(cmd->device);
+ dev = cmd->device->hostdata;
+ if (!dev) {
+ cmd->result = DID_NO_CONNECT << 16;
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
+
+ if (unlikely(lockup_detected(h))) {
+ cmd->result = DID_ERROR << 16;
+ cmd->scsi_done(cmd);
+ return 0;
+ }
+ c = cmd_alloc(h);
+ if (c == NULL) { /* trouble... */
+ dev_err(&h->pdev->dev, "cmd_alloc returned NULL!\n");
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ if (unlikely(lockup_detected(h))) {
+ cmd->result = DID_ERROR << 16;
+ cmd_free(h, c);
+ cmd->scsi_done(cmd);
+ return 0;
+ }
/*
- * Don't let rescans be initiated on a controller known
- * to be locked up. If the controller locks up *during*
- * a rescan, that thread is probably hosed, but at least
- * we can prevent new rescan threads from piling up on a
- * locked up controller.
+ * Call alternate submit routine for I/O accelerated commands.
+ * Retries always go down the normal I/O path.
*/
- if (unlikely(lockup_detected(h))) {
- spin_lock_irqsave(&h->scan_lock, flags);
- h->scan_finished = 1;
- wake_up_all(&h->scan_wait_queue);
- spin_unlock_irqrestore(&h->scan_lock, flags);
- return 1;
+ if (likely(cmd->retries == 0 &&
+ cmd->request->cmd_type == REQ_TYPE_FS &&
+ h->acciopath_status)) {
+
+ cmd->host_scribble = (unsigned char *) c;
+ c->cmd_type = CMD_SCSI;
+ c->scsi_cmd = cmd;
+
+ if (dev->offload_enabled) {
+ rc = hpsa_scsi_ioaccel_raid_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on ioaccel path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ } else if (dev->ioaccel_handle) {
+ rc = hpsa_scsi_ioaccel_direct_map(h, c);
+ if (rc == 0)
+ return 0; /* Sent on direct map path */
+ if (rc < 0) { /* scsi_dma_map failed. */
+ cmd_free(h, c);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+ }
}
- return 0;
+ return hpsa_ciss_submit(h, c, cmd, scsi3addr);
+}
+
+static void hpsa_scan_complete(struct ctlr_info *h)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&h->scan_lock, flags);
+ h->scan_finished = 1;
+ wake_up_all(&h->scan_wait_queue);
+ spin_unlock_irqrestore(&h->scan_lock, flags);
}
static void hpsa_scan_start(struct Scsi_Host *sh)
@@ -4029,8 +4167,14 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
struct ctlr_info *h = shost_to_hba(sh);
unsigned long flags;
- if (do_not_scan_if_controller_locked_up(h))
- return;
+ /*
+ * Don't let rescans be initiated on a controller known to be locked
+ * up. If the controller locks up *during* a rescan, that thread is
+ * probably hosed, but at least we can prevent new rescan threads from
+ * piling up on a locked up controller.
+ */
+ if (unlikely(lockup_detected(h)))
+ return hpsa_scan_complete(h);
/* wait until any scan already in progress is finished. */
while (1) {
@@ -4048,15 +4192,27 @@ static void hpsa_scan_start(struct Scsi_Host *sh)
h->scan_finished = 0; /* mark scan as in progress */
spin_unlock_irqrestore(&h->scan_lock, flags);
- if (do_not_scan_if_controller_locked_up(h))
- return;
+ if (unlikely(lockup_detected(h)))
+ return hpsa_scan_complete(h);
hpsa_update_scsi_devices(h, h->scsi_host->host_no);
- spin_lock_irqsave(&h->scan_lock, flags);
- h->scan_finished = 1; /* mark scan as finished. */
- wake_up_all(&h->scan_wait_queue);
- spin_unlock_irqrestore(&h->scan_lock, flags);
+ hpsa_scan_complete(h);
+}
+
+static int hpsa_change_queue_depth(struct scsi_device *sdev, int qdepth)
+{
+ struct hpsa_scsi_dev_t *logical_drive = sdev->hostdata;
+
+ if (!logical_drive)
+ return -ENODEV;
+
+ if (qdepth < 1)
+ qdepth = 1;
+ else if (qdepth > logical_drive->queue_depth)
+ qdepth = logical_drive->queue_depth;
+
+ return scsi_change_queue_depth(sdev, qdepth);
}
static int hpsa_scan_finished(struct Scsi_Host *sh,
@@ -4096,11 +4252,11 @@ static int hpsa_register_scsi(struct ctlr_info *h)
sh->max_cmd_len = MAX_COMMAND_SIZE;
sh->max_lun = HPSA_MAX_LUN;
sh->max_id = HPSA_MAX_LUN;
- sh->can_queue = h->nr_cmds;
- if (h->hba_mode_enabled)
- sh->cmd_per_lun = 7;
- else
- sh->cmd_per_lun = h->nr_cmds;
+ sh->can_queue = h->nr_cmds -
+ HPSA_CMDS_RESERVED_FOR_ABORTS -
+ HPSA_CMDS_RESERVED_FOR_DRIVER -
+ HPSA_MAX_CONCURRENT_PASSTHRUS;
+ sh->cmd_per_lun = sh->can_queue;
sh->sg_tablesize = h->maxsgentries;
h->scsi_host = sh;
sh->hostdata[0] = (unsigned long) h;
@@ -4131,7 +4287,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
int waittime = 1; /* seconds */
struct CommandList *c;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (!c) {
dev_warn(&h->pdev->dev, "out of memory in "
"wait_for_device_to_become_ready.\n");
@@ -4177,7 +4333,7 @@ static int wait_for_device_to_become_ready(struct ctlr_info *h,
else
dev_warn(&h->pdev->dev, "device is ready.\n");
- cmd_special_free(h, c);
+ cmd_free(h, c);
return rc;
}
@@ -4194,6 +4350,10 @@ static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd)
h = sdev_to_hba(scsicmd->device);
if (h == NULL) /* paranoia */
return FAILED;
+
+ if (lockup_detected(h))
+ return FAILED;
+
dev = scsicmd->device->hostdata;
if (!dev) {
dev_err(&h->pdev->dev, "hpsa_eh_device_reset_handler: "
@@ -4227,13 +4387,15 @@ static void swizzle_abort_tag(u8 *tag)
}
static void hpsa_get_tag(struct ctlr_info *h,
- struct CommandList *c, u32 *taglower, u32 *tagupper)
+ struct CommandList *c, __le32 *taglower, __le32 *tagupper)
{
+ u64 tag;
if (c->cmd_type == CMD_IOACCEL1) {
struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *)
&h->ioaccel_cmd_pool[c->cmdindex];
- *tagupper = (u32) (cm1->tag >> 32);
- *taglower = (u32) (cm1->tag & 0x0ffffffffULL);
+ tag = le64_to_cpu(cm1->tag);
+ *tagupper = cpu_to_le32(tag >> 32);
+ *taglower = cpu_to_le32(tag);
return;
}
if (c->cmd_type == CMD_IOACCEL2) {
@@ -4244,8 +4406,9 @@ static void hpsa_get_tag(struct ctlr_info *h,
*taglower = cm2->Tag;
return;
}
- *tagupper = (u32) (c->Header.tag >> 32);
- *taglower = (u32) (c->Header.tag & 0x0ffffffffULL);
+ tag = le64_to_cpu(c->Header.tag);
+ *tagupper = cpu_to_le32(tag >> 32);
+ *taglower = cpu_to_le32(tag);
}
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
@@ -4254,11 +4417,11 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
int rc = IO_OK;
struct CommandList *c;
struct ErrorInfo *ei;
- u32 tagupper, taglower;
+ __le32 tagupper, taglower;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) { /* trouble... */
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
return -ENOMEM;
}
@@ -4287,62 +4450,12 @@ static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
rc = -1;
break;
}
- cmd_special_free(h, c);
+ cmd_free(h, c);
dev_dbg(&h->pdev->dev, "%s: Tag:0x%08x:%08x: Finished.\n",
__func__, tagupper, taglower);
return rc;
}
-/*
- * hpsa_find_cmd_in_queue
- *
- * Used to determine whether a command (find) is still present
- * in queue_head. Optionally excludes the last element of queue_head.
- *
- * This is used to avoid unnecessary aborts. Commands in h->reqQ have
- * not yet been submitted, and so can be aborted by the driver without
- * sending an abort to the hardware.
- *
- * Returns pointer to command if found in queue, NULL otherwise.
- */
-static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h,
- struct scsi_cmnd *find, struct list_head *queue_head)
-{
- unsigned long flags;
- struct CommandList *c = NULL; /* ptr into cmpQ */
-
- if (!find)
- 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 */
- continue;
- if (c->scsi_cmd == find) {
- spin_unlock_irqrestore(&h->lock, flags);
- return c;
- }
- }
- spin_unlock_irqrestore(&h->lock, flags);
- return NULL;
-}
-
-static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
- u8 *tag, struct list_head *queue_head)
-{
- unsigned long flags;
- struct CommandList *c;
-
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, queue_head, list) {
- if (memcmp(&c->Header.tag, tag, 8) != 0)
- continue;
- spin_unlock_irqrestore(&h->lock, flags);
- return c;
- }
- spin_unlock_irqrestore(&h->lock, flags);
- return NULL;
-}
-
/* ioaccel2 path firmware cannot handle abort task requests.
* Change abort requests to physical target reset, and send to the
* address of the physical disk used for the ioaccel 2 command.
@@ -4360,7 +4473,7 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
unsigned char *psa = &phys_scsi3addr[0];
/* Get a pointer to the hpsa logical device. */
- scmd = (struct scsi_cmnd *) abort->scsi_cmd;
+ scmd = abort->scsi_cmd;
dev = (struct hpsa_scsi_dev_t *)(scmd->device->hostdata);
if (dev == NULL) {
dev_warn(&h->pdev->dev,
@@ -4429,10 +4542,6 @@ static int hpsa_send_reset_as_abort_ioaccel2(struct ctlr_info *h,
static int hpsa_send_abort_both_ways(struct ctlr_info *h,
unsigned char *scsi3addr, struct CommandList *abort)
{
- u8 swizzled_tag[8];
- struct CommandList *c;
- int rc = 0, rc2 = 0;
-
/* ioccelerator mode 2 commands should be aborted via the
* accelerated path, since RAID path is unaware of these commands,
* but underlying firmware can't handle abort TMF.
@@ -4441,27 +4550,8 @@ static int hpsa_send_abort_both_ways(struct ctlr_info *h,
if (abort->cmd_type == CMD_IOACCEL2)
return hpsa_send_reset_as_abort_ioaccel2(h, scsi3addr, abort);
- /* we do not expect to find the swizzled tag in our queue, but
- * check anyway just to be sure the assumptions which make this
- * the case haven't become wrong.
- */
- memcpy(swizzled_tag, &abort->Request.CDB[4], 8);
- swizzle_abort_tag(swizzled_tag);
- c = hpsa_find_cmd_in_queue_by_tag(h, swizzled_tag, &h->cmpQ);
- if (c != NULL) {
- dev_warn(&h->pdev->dev, "Unexpectedly found byte-swapped tag in completion queue.\n");
- return hpsa_send_abort(h, scsi3addr, abort, 0);
- }
- rc = hpsa_send_abort(h, scsi3addr, abort, 0);
-
- /* if the command is still in our queue, we can't conclude that it was
- * aborted (it might have just completed normally) but in any case
- * we don't need to try to abort it another way.
- */
- c = hpsa_find_cmd_in_queue(h, abort->scsi_cmd, &h->cmpQ);
- if (c)
- rc2 = hpsa_send_abort(h, scsi3addr, abort, 1);
- return rc && rc2;
+ return hpsa_send_abort(h, scsi3addr, abort, 0) &&
+ hpsa_send_abort(h, scsi3addr, abort, 1);
}
/* Send an abort for the specified command.
@@ -4475,11 +4565,11 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
struct CommandList *abort; /* pointer to command to be aborted */
- struct CommandList *found;
struct scsi_cmnd *as; /* ptr to scsi cmd inside aborted command. */
char msg[256]; /* For debug messaging. */
int ml = 0;
- u32 tagupper, taglower;
+ __le32 tagupper, taglower;
+ int refcount;
/* Find the controller of the command to be aborted */
h = sdev_to_hba(sc->device);
@@ -4487,6 +4577,9 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
"ABORT REQUEST FAILED, Controller lookup failed.\n"))
return FAILED;
+ if (lockup_detected(h))
+ return FAILED;
+
/* Check that controller supports some kind of task abort */
if (!(HPSATMF_PHYS_TASK_ABORT & h->TMFSupportFlags) &&
!(HPSATMF_LOG_TASK_ABORT & h->TMFSupportFlags))
@@ -4508,41 +4601,23 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
/* Get SCSI command to be aborted */
abort = (struct CommandList *) sc->host_scribble;
if (abort == NULL) {
- dev_err(&h->pdev->dev, "%s FAILED, Command to abort is NULL.\n",
- msg);
- return FAILED;
+ /* This can happen if the command already completed. */
+ return SUCCESS;
+ }
+ refcount = atomic_inc_return(&abort->refcount);
+ if (refcount == 1) { /* Command is done already. */
+ cmd_free(h, abort);
+ return SUCCESS;
}
hpsa_get_tag(h, abort, &taglower, &tagupper);
ml += sprintf(msg+ml, "Tag:0x%08x:%08x ", tagupper, taglower);
- as = (struct scsi_cmnd *) abort->scsi_cmd;
+ as = abort->scsi_cmd;
if (as != NULL)
ml += sprintf(msg+ml, "Command:0x%x SN:0x%lx ",
as->cmnd[0], as->serial_number);
dev_dbg(&h->pdev->dev, "%s\n", msg);
dev_warn(&h->pdev->dev, "Abort request on C%d:B%d:T%d:L%d\n",
h->scsi_host->host_no, dev->bus, dev->target, dev->lun);
-
- /* Search reqQ to See if command is queued but not submitted,
- * if so, complete the command with aborted status and remove
- * it from the reqQ.
- */
- found = hpsa_find_cmd_in_queue(h, sc, &h->reqQ);
- if (found) {
- found->err_info->CommandStatus = CMD_ABORTED;
- finish_cmd(found);
- dev_info(&h->pdev->dev, "%s Request SUCCEEDED (driver queue).\n",
- msg);
- return SUCCESS;
- }
-
- /* not in reqQ, if also not in cmpQ, must have already completed */
- found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
- if (!found) {
- dev_dbg(&h->pdev->dev, "%s Request SUCCEEDED (not known to driver).\n",
- msg);
- return SUCCESS;
- }
-
/*
* Command is in flight, or possibly already completed
* by the firmware (but not to the scsi mid layer) but we can't
@@ -4554,6 +4629,7 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
dev_warn(&h->pdev->dev, "FAILED abort on device C%d:B%d:T%d:L%d\n",
h->scsi_host->host_no,
dev->bus, dev->target, dev->lun);
+ cmd_free(h, abort);
return FAILED;
}
dev_info(&h->pdev->dev, "%s REQUEST SUCCEEDED.\n", msg);
@@ -4565,32 +4641,38 @@ static int hpsa_eh_abort_handler(struct scsi_cmnd *sc)
*/
#define ABORT_COMPLETE_WAIT_SECS 30
for (i = 0; i < ABORT_COMPLETE_WAIT_SECS * 10; i++) {
- found = hpsa_find_cmd_in_queue(h, sc, &h->cmpQ);
- if (!found)
+ refcount = atomic_read(&abort->refcount);
+ if (refcount < 2) {
+ cmd_free(h, abort);
return SUCCESS;
- msleep(100);
+ } else {
+ msleep(100);
+ }
}
dev_warn(&h->pdev->dev, "%s FAILED. Aborted command has not completed after %d seconds.\n",
msg, ABORT_COMPLETE_WAIT_SECS);
+ cmd_free(h, abort);
return FAILED;
}
-
/*
* For operations that cannot sleep, a command block is allocated at init,
* and managed by cmd_alloc() and cmd_free() using a simple bitmap to track
* which ones are free or in use. Lock must be held when calling this.
* cmd_free() is the complement.
*/
+
static struct CommandList *cmd_alloc(struct ctlr_info *h)
{
struct CommandList *c;
int i;
union u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
- int loopcount;
+ int refcount;
+ unsigned long offset;
- /* There is some *extremely* small but non-zero chance that that
+ /*
+ * 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
@@ -4601,24 +4683,30 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
* infrequently as to be indistinguishable from never.
*/
- loopcount = 0;
- do {
- i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
- 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));
- cmd_dma_handle = h->cmd_pool_dhandle
- + i * sizeof(*c);
+ offset = h->last_allocation; /* benignly racy */
+ for (;;) {
+ i = find_next_zero_bit(h->cmd_pool_bits, h->nr_cmds, offset);
+ if (unlikely(i == h->nr_cmds)) {
+ offset = 0;
+ continue;
+ }
+ c = h->cmd_pool + i;
+ refcount = atomic_inc_return(&c->refcount);
+ if (unlikely(refcount > 1)) {
+ cmd_free(h, c); /* already in use */
+ offset = (i + 1) % h->nr_cmds;
+ continue;
+ }
+ set_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG));
+ break; /* it's ours now. */
+ }
+ h->last_allocation = i; /* benignly racy */
+
+ /* Zero out all of commandlist except the last field, refcount */
+ memset(c, 0, offsetof(struct CommandList, refcount));
+ c->Header.tag = cpu_to_le64((u64) (i << DIRECT_LOOKUP_SHIFT));
+ cmd_dma_handle = h->cmd_pool_dhandle + i * sizeof(*c);
c->err_info = h->errinfo_pool + i;
memset(c->err_info, 0, sizeof(*c->err_info));
err_dma_handle = h->errinfo_pool_dhandle
@@ -4626,45 +4714,10 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
c->cmdindex = i;
- INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
- c->ErrDesc.Addr = cpu_to_le64(err_dma_handle);
- c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info));
-
- c->h = h;
- return c;
-}
-
-/* For operations that can wait for kmalloc to possibly sleep,
- * this routine can be called. Lock need not be held to call
- * cmd_special_alloc. cmd_special_free() is the complement.
- */
-static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
-{
- struct CommandList *c;
- dma_addr_t cmd_dma_handle, err_dma_handle;
-
- c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle);
- if (c == NULL)
- return NULL;
-
- c->cmd_type = CMD_SCSI;
- c->cmdindex = -1;
-
- c->err_info = pci_zalloc_consistent(h->pdev, sizeof(*c->err_info),
- &err_dma_handle);
-
- if (c->err_info == NULL) {
- pci_free_consistent(h->pdev,
- sizeof(*c), c, cmd_dma_handle);
- return NULL;
- }
-
- INIT_LIST_HEAD(&c->list);
- c->busaddr = (u32) cmd_dma_handle;
- c->ErrDesc.Addr = cpu_to_le64(err_dma_handle);
- c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info));
+ c->ErrDesc.Addr = cpu_to_le64((u64) err_dma_handle);
+ c->ErrDesc.Len = cpu_to_le32((u32) sizeof(*c->err_info));
c->h = h;
return c;
@@ -4672,20 +4725,13 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
static void cmd_free(struct ctlr_info *h, struct CommandList *c)
{
- int i;
-
- i = c - h->cmd_pool;
- clear_bit(i & (BITS_PER_LONG - 1),
- h->cmd_pool_bits + (i / BITS_PER_LONG));
-}
+ if (atomic_dec_and_test(&c->refcount)) {
+ int i;
-static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
-{
- pci_free_consistent(h->pdev, sizeof(*c->err_info),
- 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));
+ i = c - h->cmd_pool;
+ clear_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG));
+ }
}
#ifdef CONFIG_COMPAT
@@ -4866,7 +4912,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
memset(buff, 0, iocommand.buf_size);
}
}
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) {
rc = -ENOMEM;
goto out_kfree;
@@ -4883,8 +4929,6 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
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 = c->busaddr;
/* Fill in Request block */
memcpy(&c->Request, &iocommand.Request,
@@ -4925,7 +4969,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
}
}
out:
- cmd_special_free(h, c);
+ cmd_free(h, c);
out_kfree:
kfree(buff);
return rc;
@@ -4940,7 +4984,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
u64 temp64;
BYTE sg_used = 0;
int status = 0;
- int i;
u32 left;
u32 sz;
BYTE __user *data_ptr;
@@ -5004,7 +5047,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
data_ptr += sz;
sg_used++;
}
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (c == NULL) {
status = -ENOMEM;
goto cleanup1;
@@ -5014,7 +5057,6 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
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 = c->busaddr;
memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
if (ioc->buf_size > 0) {
int i;
@@ -5047,6 +5089,8 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
goto cleanup0;
}
if ((ioc->Request.Type.Direction & XFER_READ) && ioc->buf_size > 0) {
+ int i;
+
/* Copy the data out of the buffer we created */
BYTE __user *ptr = ioc->buf;
for (i = 0; i < sg_used; i++) {
@@ -5059,9 +5103,11 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
}
status = 0;
cleanup0:
- cmd_special_free(h, c);
+ cmd_free(h, c);
cleanup1:
if (buff) {
+ int i;
+
for (i = 0; i < sg_used; i++)
kfree(buff[i]);
kfree(buff);
@@ -5079,35 +5125,6 @@ static void check_ioctl_unit_attention(struct ctlr_info *h,
(void) check_for_unit_attention(h, c);
}
-static int increment_passthru_count(struct ctlr_info *h)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&h->passthru_count_lock, flags);
- if (h->passthru_count >= HPSA_MAX_CONCURRENT_PASSTHRUS) {
- spin_unlock_irqrestore(&h->passthru_count_lock, flags);
- return -1;
- }
- h->passthru_count++;
- spin_unlock_irqrestore(&h->passthru_count_lock, flags);
- return 0;
-}
-
-static void decrement_passthru_count(struct ctlr_info *h)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&h->passthru_count_lock, flags);
- if (h->passthru_count <= 0) {
- spin_unlock_irqrestore(&h->passthru_count_lock, flags);
- /* not expecting to get here. */
- dev_warn(&h->pdev->dev, "Bug detected, passthru_count seems to be incorrect.\n");
- return;
- }
- h->passthru_count--;
- spin_unlock_irqrestore(&h->passthru_count_lock, flags);
-}
-
/*
* ioctl
*/
@@ -5130,16 +5147,16 @@ static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
case CCISS_GETDRIVVER:
return hpsa_getdrivver_ioctl(h, argp);
case CCISS_PASSTHRU:
- if (increment_passthru_count(h))
+ if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
return -EAGAIN;
rc = hpsa_passthru_ioctl(h, argp);
- decrement_passthru_count(h);
+ atomic_inc(&h->passthru_cmds_avail);
return rc;
case CCISS_BIG_PASSTHRU:
- if (increment_passthru_count(h))
+ if (atomic_dec_if_positive(&h->passthru_cmds_avail) < 0)
return -EAGAIN;
rc = hpsa_big_passthru_ioctl(h, argp);
- decrement_passthru_count(h);
+ atomic_inc(&h->passthru_cmds_avail);
return rc;
default:
return -ENOTTY;
@@ -5173,7 +5190,6 @@ 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;
@@ -5184,7 +5200,6 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Header.SGList = 0;
c->Header.SGTotal = cpu_to_le16(0);
}
- c->Header.tag = c->busaddr;
memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
if (cmd_type == TYPE_CMD) {
@@ -5256,6 +5271,16 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[7] = (size >> 16) & 0xFF;
c->Request.CDB[8] = (size >> 8) & 0xFF;
break;
+ case BMIC_IDENTIFY_PHYSICAL_DEVICE:
+ c->Request.CDBLen = 10;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
+ c->Request.Timeout = 0;
+ c->Request.CDB[0] = BMIC_READ;
+ c->Request.CDB[6] = BMIC_IDENTIFY_PHYSICAL_DEVICE;
+ c->Request.CDB[7] = (size >> 16) & 0xFF;
+ c->Request.CDB[8] = (size >> 8) & 0XFF;
+ break;
default:
dev_warn(&h->pdev->dev, "unknown command 0x%c\n", cmd);
BUG();
@@ -5281,10 +5306,9 @@ 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%016llx using request Tag:0x%016llx",
+ dev_dbg(&h->pdev->dev,
+ "Abort Tag:0x%016llx 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_attr_dir =
TYPE_ATTR_DIR(cmd_type,
@@ -5295,14 +5319,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
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] = 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;
+ memcpy(&c->Request.CDB[4], &a->Header.tag,
+ sizeof(a->Header.tag));
c->Request.CDB[12] = 0x00; /* reserved */
c->Request.CDB[13] = 0x00; /* reserved */
c->Request.CDB[14] = 0x00; /* reserved */
@@ -5349,47 +5367,6 @@ static void __iomem *remap_pci_mem(ulong base, ulong size)
return page_remapped ? (page_remapped + page_offs) : NULL;
}
-/* Takes cmds off the submission queue and sends them to the hardware,
- * then puts them on the queue of cmds waiting for completion.
- * Assumes h->lock is held
- */
-static void start_io(struct ctlr_info *h, unsigned long *flags)
-{
- struct CommandList *c;
-
- while (!list_empty(&h->reqQ)) {
- c = list_entry(h->reqQ.next, struct CommandList, list);
- /* can't do anything if fifo is full */
- if ((h->access.fifo_full(h))) {
- h->fifo_recently_full = 1;
- dev_warn(&h->pdev->dev, "fifo full\n");
- break;
- }
- h->fifo_recently_full = 0;
-
- /* Get the first entry from the Request Q */
- removeQ(c);
- h->Qdepth--;
-
- /* Put job onto the completed Q */
- addQ(&h->cmpQ, c);
- 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);
- }
-}
-
-static void lock_and_start_io(struct ctlr_info *h)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&h->lock, flags);
- start_io(h, &flags);
- spin_unlock_irqrestore(&h->lock, flags);
-}
-
static inline unsigned long get_next_completion(struct ctlr_info *h, u8 q)
{
return h->access.command_completed(h, q);
@@ -5418,53 +5395,12 @@ static inline int bad_tag(struct ctlr_info *h, u32 tag_index,
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);
-
- /*
- * Check for possibly stalled i/o.
- *
- * If a fifo_full condition is encountered, requests will back up
- * in h->reqQ. This queue is only emptied out by start_io which is
- * only called when a new i/o request comes in. If no i/o's are
- * forthcoming, the i/o's in h->reqQ can get stuck. So we call
- * start_io from here if we detect such a danger.
- *
- * Normally, we shouldn't hit this case, but pounding on the
- * CCISS_PASSTHRU ioctl can provoke it. Only call start_io if
- * commands_outstanding is low. We want to avoid calling
- * start_io from in here as much as possible, and esp. don't
- * want to get in a cycle where we call start_io every time
- * through here.
- */
- 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
|| c->cmd_type == CMD_IOACCEL2))
complete_scsi_command(c);
else if (c->cmd_type == CMD_IOCTL_PEND)
complete(c->waiting);
- if (unlikely(io_may_be_stalled))
- lock_and_start_io(h);
-}
-
-static inline u32 hpsa_tag_contains_index(u32 tag)
-{
- return tag & DIRECT_LOOKUP_BIT;
-}
-
-static inline u32 hpsa_tag_to_index(u32 tag)
-{
- return tag >> DIRECT_LOOKUP_SHIFT;
}
@@ -5484,34 +5420,13 @@ static inline void process_indexed_cmd(struct ctlr_info *h,
u32 tag_index;
struct CommandList *c;
- tag_index = hpsa_tag_to_index(raw_tag);
+ tag_index = raw_tag >> DIRECT_LOOKUP_SHIFT;
if (!bad_tag(h, tag_index, raw_tag)) {
c = h->cmd_pool + tag_index;
finish_cmd(c);
}
}
-/* process completion of a non-indexed command */
-static inline void process_nonindexed_cmd(struct ctlr_info *h,
- u32 raw_tag)
-{
- u32 tag;
- struct CommandList *c = NULL;
- unsigned long flags;
-
- tag = hpsa_tag_discard_error_bits(h, raw_tag);
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, &h->cmpQ, list) {
- if ((c->busaddr & 0xFFFFFFE0) == (tag & 0xFFFFFFE0)) {
- spin_unlock_irqrestore(&h->lock, flags);
- finish_cmd(c);
- return;
- }
- }
- spin_unlock_irqrestore(&h->lock, flags);
- bad_tag(h, h->nr_cmds + 1, raw_tag);
-}
-
/* Some controllers, like p400, will give us one interrupt
* after a soft reset, even if we turned interrupts off.
* Only need to check for this in the hpsa_xxx_discard_completions
@@ -5589,10 +5504,7 @@ static irqreturn_t do_hpsa_intr_intx(int irq, void *queue)
while (interrupt_pending(h)) {
raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (likely(hpsa_tag_contains_index(raw_tag)))
- process_indexed_cmd(h, raw_tag);
- else
- process_nonindexed_cmd(h, raw_tag);
+ process_indexed_cmd(h, raw_tag);
raw_tag = next_command(h, q);
}
}
@@ -5608,10 +5520,7 @@ static irqreturn_t do_hpsa_intr_msi(int irq, void *queue)
h->last_intr_timestamp = get_jiffies_64();
raw_tag = get_next_completion(h, q);
while (raw_tag != FIFO_EMPTY) {
- if (likely(hpsa_tag_contains_index(raw_tag)))
- process_indexed_cmd(h, raw_tag);
- else
- process_nonindexed_cmd(h, raw_tag);
+ process_indexed_cmd(h, raw_tag);
raw_tag = next_command(h, q);
}
return IRQ_HANDLED;
@@ -5633,7 +5542,8 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
static const size_t cmd_sz = sizeof(*cmd) +
sizeof(cmd->ErrorDescriptor);
dma_addr_t paddr64;
- uint32_t paddr32, tag;
+ __le32 paddr32;
+ u32 tag;
void __iomem *vaddr;
int i, err;
@@ -5648,7 +5558,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32));
if (err) {
iounmap(vaddr);
- return -ENOMEM;
+ return err;
}
cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
@@ -5661,12 +5571,12 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
* although there's no guarantee, we assume that the address is at
* least 4-byte aligned (most likely, it's page-aligned).
*/
- paddr32 = paddr64;
+ paddr32 = cpu_to_le32(paddr64);
cmd->CommandHeader.ReplyQueue = 0;
cmd->CommandHeader.SGList = 0;
cmd->CommandHeader.SGTotal = cpu_to_le16(0);
- cmd->CommandHeader.tag = paddr32;
+ cmd->CommandHeader.tag = cpu_to_le64(paddr64);
memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
cmd->Request.CDBLen = 16;
@@ -5677,14 +5587,14 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
cmd->Request.CDB[1] = type;
memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */
cmd->ErrorDescriptor.Addr =
- cpu_to_le64((paddr32 + sizeof(*cmd)));
+ cpu_to_le64((le32_to_cpu(paddr32) + sizeof(*cmd)));
cmd->ErrorDescriptor.Len = cpu_to_le32(sizeof(struct ErrorInfo));
- writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET);
+ writel(le32_to_cpu(paddr32), vaddr + SA5_REQUEST_PORT_OFFSET);
for (i = 0; i < HPSA_MSG_SEND_RETRY_LIMIT; i++) {
tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
- if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr32)
+ if ((tag & ~HPSA_SIMPLE_ERROR_BITS) == paddr64)
break;
msleep(HPSA_MSG_SEND_RETRY_INTERVAL_MSECS);
}
@@ -5718,8 +5628,6 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
static int hpsa_controller_hard_reset(struct pci_dev *pdev,
void __iomem *vaddr, u32 use_doorbell)
{
- u16 pmcsr;
- int pos;
if (use_doorbell) {
/* For everything after the P600, the PCI power state method
@@ -5745,26 +5653,21 @@ static int hpsa_controller_hard_reset(struct pci_dev *pdev,
* this causes a secondary PCI reset which will reset the
* controller." */
- pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
- if (pos == 0) {
- dev_err(&pdev->dev,
- "hpsa_reset_controller: "
- "PCI PM not supported\n");
- return -ENODEV;
- }
+ int rc = 0;
+
dev_info(&pdev->dev, "using PCI PM to reset controller\n");
+
/* enter the D3hot power management state */
- pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D3hot;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ rc = pci_set_power_state(pdev, PCI_D3hot);
+ if (rc)
+ return rc;
msleep(500);
/* enter the D0 power management state */
- pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
- pmcsr |= PCI_D0;
- pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+ rc = pci_set_power_state(pdev, PCI_D0);
+ if (rc)
+ return rc;
/*
* The P600 requires a small delay when changing states.
@@ -5858,8 +5761,12 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
*/
rc = hpsa_lookup_board_id(pdev, &board_id);
- if (rc < 0 || !ctlr_is_resettable(board_id)) {
- dev_warn(&pdev->dev, "Not resetting device.\n");
+ if (rc < 0) {
+ dev_warn(&pdev->dev, "Board ID not found\n");
+ return rc;
+ }
+ if (!ctlr_is_resettable(board_id)) {
+ dev_warn(&pdev->dev, "Controller not resettable\n");
return -ENODEV;
}
@@ -5892,7 +5799,7 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
}
rc = write_driver_ver_to_cfgtable(cfgtable);
if (rc)
- goto unmap_vaddr;
+ goto unmap_cfgtable;
/* If reset via doorbell register is supported, use that.
* There are two such methods. Favor the newest method.
@@ -5904,8 +5811,8 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
} else {
use_doorbell = misc_fw_support & MISC_FW_DOORBELL_RESET;
if (use_doorbell) {
- dev_warn(&pdev->dev, "Soft reset not supported. "
- "Firmware update is required.\n");
+ dev_warn(&pdev->dev,
+ "Soft reset not supported. Firmware update is required.\n");
rc = -ENOTSUPP; /* try soft reset */
goto unmap_cfgtable;
}
@@ -5925,8 +5832,7 @@ static int hpsa_kdump_hard_reset_controller(struct pci_dev *pdev)
rc = hpsa_wait_for_board_state(pdev, vaddr, BOARD_READY);
if (rc) {
dev_warn(&pdev->dev,
- "failed waiting for board to become ready "
- "after hard reset\n");
+ "Failed waiting for board to become ready after hard reset\n");
goto unmap_cfgtable;
}
@@ -5977,7 +5883,7 @@ static void print_cfg_table(struct device *dev, struct CfgTable __iomem *tb)
readl(&(tb->HostWrite.CoalIntDelay)));
dev_info(dev, " Coalesce Interrupt Count = 0x%x\n",
readl(&(tb->HostWrite.CoalIntCount)));
- dev_info(dev, " Max outstanding commands = 0x%d\n",
+ dev_info(dev, " Max outstanding commands = %d\n",
readl(&(tb->CmdsOutMax)));
dev_info(dev, " Bus Types = 0x%x\n", readl(&(tb->BusTypes)));
for (i = 0; i < 16; i++)
@@ -6025,7 +5931,7 @@ static int find_PCI_BAR_index(struct pci_dev *pdev, unsigned long pci_bar_addr)
}
/* If MSI/MSI-X is supported by the kernel we will try to enable it on
- * controllers that are capable. If not, we use IO-APIC mode.
+ * controllers that are capable. If not, we use legacy INTx mode.
*/
static void hpsa_interrupt_mode(struct ctlr_info *h)
@@ -6044,7 +5950,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h)
(h->board_id == 0x40820E11) || (h->board_id == 0x40830E11))
goto default_int_mode;
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSIX)) {
- dev_info(&h->pdev->dev, "MSIX\n");
+ dev_info(&h->pdev->dev, "MSI-X capable controller\n");
h->msix_vector = MAX_REPLY_QUEUES;
if (h->msix_vector > num_online_cpus())
h->msix_vector = num_online_cpus();
@@ -6065,7 +5971,7 @@ static void hpsa_interrupt_mode(struct ctlr_info *h)
}
single_msi_mode:
if (pci_find_capability(h->pdev, PCI_CAP_ID_MSI)) {
- dev_info(&h->pdev->dev, "MSI\n");
+ dev_info(&h->pdev->dev, "MSI capable controller\n");
if (!pci_enable_msi(h->pdev))
h->msi_vector = 1;
else
@@ -6172,8 +6078,10 @@ static int hpsa_find_cfgtables(struct ctlr_info *h)
return rc;
h->cfgtable = remap_pci_mem(pci_resource_start(h->pdev,
cfg_base_addr_index) + cfg_offset, sizeof(*h->cfgtable));
- if (!h->cfgtable)
+ if (!h->cfgtable) {
+ dev_err(&h->pdev->dev, "Failed mapping cfgtable\n");
return -ENOMEM;
+ }
rc = write_driver_ver_to_cfgtable(h->cfgtable);
if (rc)
return rc;
@@ -6204,6 +6112,15 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
}
}
+/* If the controller reports that the total max sg entries is greater than 512,
+ * then we know that chained SG blocks work. (Original smart arrays did not
+ * support chained SG blocks and would return zero for max sg entries.)
+ */
+static int hpsa_supports_chained_sg_blocks(struct ctlr_info *h)
+{
+ return h->maxsgentries > 512;
+}
+
/* Interrogate the hardware for some limits:
* max commands, max SG elements without chaining, and with chaining,
* SG chain block size, etc.
@@ -6211,21 +6128,23 @@ static void hpsa_get_max_perf_mode_cmds(struct ctlr_info *h)
static void hpsa_find_board_params(struct ctlr_info *h)
{
hpsa_get_max_perf_mode_cmds(h);
- h->nr_cmds = h->max_commands - 4; /* Allow room for some ioctls */
+ h->nr_cmds = h->max_commands;
h->maxsgentries = readl(&(h->cfgtable->MaxScatterGatherElements));
h->fw_support = readl(&(h->cfgtable->misc_fw_support));
- /*
- * Limit in-command s/g elements to 32 save dma'able memory.
- * Howvever spec says if 0, use 31
- */
- h->max_cmd_sg_entries = 31;
- if (h->maxsgentries > 512) {
+ if (hpsa_supports_chained_sg_blocks(h)) {
+ /* Limit in-command s/g elements to 32 save dma'able memory. */
h->max_cmd_sg_entries = 32;
h->chainsize = h->maxsgentries - h->max_cmd_sg_entries;
h->maxsgentries--; /* save one for chain pointer */
} else {
- h->chainsize = 0;
+ /*
+ * Original smart arrays supported at most 31 s/g entries
+ * embedded inline in the command (trying to use more
+ * would lock up the controller)
+ */
+ h->max_cmd_sg_entries = 31;
h->maxsgentries = 31; /* default to traditional values */
+ h->chainsize = 0;
}
/* Find out what task management functions are supported and cache */
@@ -6239,7 +6158,7 @@ static void hpsa_find_board_params(struct ctlr_info *h)
static inline bool hpsa_CISS_signature_present(struct ctlr_info *h)
{
if (!check_signature(h->cfgtable->Signature, "CISS", 4)) {
- dev_warn(&h->pdev->dev, "not a valid CISS config table\n");
+ dev_err(&h->pdev->dev, "not a valid CISS config table\n");
return false;
}
return true;
@@ -6272,24 +6191,27 @@ static inline void hpsa_p600_dma_prefetch_quirk(struct ctlr_info *h)
writel(dma_prefetch, h->vaddr + I2O_DMA1_CFG);
}
-static void hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
+static int hpsa_wait_for_clear_event_notify_ack(struct ctlr_info *h)
{
int i;
u32 doorbell_value;
unsigned long flags;
/* wait until the clear_event_notify bit 6 is cleared by controller. */
- for (i = 0; i < MAX_CONFIG_WAIT; i++) {
+ for (i = 0; i < MAX_CLEAR_EVENT_WAIT; i++) {
spin_lock_irqsave(&h->lock, flags);
doorbell_value = readl(h->vaddr + SA5_DOORBELL);
spin_unlock_irqrestore(&h->lock, flags);
if (!(doorbell_value & DOORBELL_CLEAR_EVENTS))
- break;
+ goto done;
/* delay and try again */
- msleep(20);
+ msleep(CLEAR_EVENT_WAIT_INTERVAL);
}
+ return -ENODEV;
+done:
+ return 0;
}
-static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
+static int hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
{
int i;
u32 doorbell_value;
@@ -6299,17 +6221,21 @@ static void hpsa_wait_for_mode_change_ack(struct ctlr_info *h)
* (e.g.: hot replace a failed 144GB drive in a RAID 5 set right
* as we enter this code.)
*/
- for (i = 0; i < MAX_CONFIG_WAIT; i++) {
+ for (i = 0; i < MAX_MODE_CHANGE_WAIT; i++) {
spin_lock_irqsave(&h->lock, flags);
doorbell_value = readl(h->vaddr + SA5_DOORBELL);
spin_unlock_irqrestore(&h->lock, flags);
if (!(doorbell_value & CFGTBL_ChangeReq))
- break;
+ goto done;
/* delay and try again */
- usleep_range(10000, 20000);
+ msleep(MODE_CHANGE_WAIT_INTERVAL);
}
+ return -ENODEV;
+done:
+ return 0;
}
+/* return -ENODEV or other reason on error, 0 on success */
static int hpsa_enter_simple_mode(struct ctlr_info *h)
{
u32 trans_support;
@@ -6324,14 +6250,15 @@ static int hpsa_enter_simple_mode(struct ctlr_info *h)
writel(CFGTBL_Trans_Simple, &(h->cfgtable->HostWrite.TransportRequest));
writel(0, &h->cfgtable->HostWrite.command_pool_addr_hi);
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
- hpsa_wait_for_mode_change_ack(h);
+ if (hpsa_wait_for_mode_change_ack(h))
+ goto error;
print_cfg_table(&h->pdev->dev, h->cfgtable);
if (!(readl(&(h->cfgtable->TransportActive)) & CFGTBL_Trans_Simple))
goto error;
h->transMethod = CFGTBL_Trans_Simple;
return 0;
error:
- dev_warn(&h->pdev->dev, "unable to get board into simple mode\n");
+ dev_err(&h->pdev->dev, "failed to enter simple mode\n");
return -ENODEV;
}
@@ -6341,7 +6268,7 @@ static int hpsa_pci_init(struct ctlr_info *h)
prod_index = hpsa_lookup_board_id(h->pdev, &h->board_id);
if (prod_index < 0)
- return -ENODEV;
+ return prod_index;
h->product_name = products[prod_index].product_name;
h->access = *(products[prod_index].access);
@@ -6422,6 +6349,7 @@ static void hpsa_hba_inquiry(struct ctlr_info *h)
static int hpsa_init_reset_devices(struct pci_dev *pdev)
{
int rc, i;
+ void __iomem *vaddr;
if (!reset_devices)
return 0;
@@ -6445,6 +6373,14 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev)
pci_set_master(pdev);
+ vaddr = pci_ioremap_bar(pdev, 0);
+ if (vaddr == NULL) {
+ rc = -ENOMEM;
+ goto out_disable;
+ }
+ writel(SA5_INTR_OFF, vaddr + SA5_REPLY_INTR_MASK_OFFSET);
+ iounmap(vaddr);
+
/* Reset the controller with a PCI power-cycle or via doorbell */
rc = hpsa_kdump_hard_reset_controller(pdev);
@@ -6453,14 +6389,11 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev)
* "performant mode". Or, it might be 640x, which can't reset
* due to concerns about shared bbwc between 6402/6404 pair.
*/
- if (rc) {
- if (rc != -ENOTSUPP) /* just try to do the kdump anyhow. */
- rc = -ENODEV;
+ if (rc)
goto out_disable;
- }
/* Now try to get the controller to respond to a no-op */
- dev_warn(&pdev->dev, "Waiting for controller to respond to no-op\n");
+ dev_info(&pdev->dev, "Waiting for controller to respond to no-op\n");
for (i = 0; i < HPSA_POST_RESET_NOOP_RETRIES; i++) {
if (hpsa_noop(pdev) == 0)
break;
@@ -6490,9 +6423,12 @@ static int hpsa_allocate_cmd_pool(struct ctlr_info *h)
|| (h->cmd_pool == NULL)
|| (h->errinfo_pool == NULL)) {
dev_err(&h->pdev->dev, "out of memory in %s", __func__);
- return -ENOMEM;
+ goto clean_up;
}
return 0;
+clean_up:
+ hpsa_free_cmd_pool(h);
+ return -ENOMEM;
}
static void hpsa_free_cmd_pool(struct ctlr_info *h)
@@ -6519,16 +6455,38 @@ static void hpsa_free_cmd_pool(struct ctlr_info *h)
static void hpsa_irq_affinity_hints(struct ctlr_info *h)
{
- int i, cpu, rc;
+ int i, cpu;
cpu = cpumask_first(cpu_online_mask);
for (i = 0; i < h->msix_vector; i++) {
- rc = irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu));
+ irq_set_affinity_hint(h->intr[i], get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
}
-static int hpsa_request_irq(struct ctlr_info *h,
+/* clear affinity hints and free MSI-X, MSI, or legacy INTx vectors */
+static void hpsa_free_irqs(struct ctlr_info *h)
+{
+ int i;
+
+ if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) {
+ /* Single reply queue, only one irq to free */
+ i = h->intr_mode;
+ irq_set_affinity_hint(h->intr[i], NULL);
+ free_irq(h->intr[i], &h->q[i]);
+ return;
+ }
+
+ for (i = 0; i < h->msix_vector; i++) {
+ irq_set_affinity_hint(h->intr[i], NULL);
+ free_irq(h->intr[i], &h->q[i]);
+ }
+ for (; i < MAX_REPLY_QUEUES; i++)
+ h->q[i] = 0;
+}
+
+/* returns 0 on success; cleans up and returns -Enn on error */
+static int hpsa_request_irqs(struct ctlr_info *h,
irqreturn_t (*msixhandler)(int, void *),
irqreturn_t (*intxhandler)(int, void *))
{
@@ -6543,10 +6501,25 @@ static int hpsa_request_irq(struct ctlr_info *h,
if (h->intr_mode == PERF_MODE_INT && h->msix_vector > 0) {
/* If performant mode and MSI-X, use multiple reply queues */
- for (i = 0; i < h->msix_vector; i++)
+ for (i = 0; i < h->msix_vector; i++) {
rc = request_irq(h->intr[i], msixhandler,
0, h->devname,
&h->q[i]);
+ if (rc) {
+ int j;
+
+ dev_err(&h->pdev->dev,
+ "failed to get irq %d for %s\n",
+ h->intr[i], h->devname);
+ for (j = 0; j < i; j++) {
+ free_irq(h->intr[j], &h->q[j]);
+ h->q[j] = 0;
+ }
+ for (; j < MAX_REPLY_QUEUES; j++)
+ h->q[j] = 0;
+ return rc;
+ }
+ }
hpsa_irq_affinity_hints(h);
} else {
/* Use single reply pool */
@@ -6592,27 +6565,9 @@ static int hpsa_kdump_soft_reset(struct ctlr_info *h)
return 0;
}
-static void free_irqs(struct ctlr_info *h)
-{
- int i;
-
- if (!h->msix_vector || h->intr_mode != PERF_MODE_INT) {
- /* Single reply queue, only one irq to free */
- i = h->intr_mode;
- irq_set_affinity_hint(h->intr[i], NULL);
- free_irq(h->intr[i], &h->q[i]);
- return;
- }
-
- for (i = 0; i < h->msix_vector; i++) {
- irq_set_affinity_hint(h->intr[i], NULL);
- free_irq(h->intr[i], &h->q[i]);
- }
-}
-
static void hpsa_free_irqs_and_disable_msix(struct ctlr_info *h)
{
- free_irqs(h);
+ hpsa_free_irqs(h);
#ifdef CONFIG_PCI_MSI
if (h->msix_vector) {
if (h->pdev->msix_enabled)
@@ -6658,16 +6613,20 @@ static void hpsa_undo_allocations_after_kdump_soft_reset(struct ctlr_info *h)
}
/* Called when controller lockup detected. */
-static void fail_all_cmds_on_list(struct ctlr_info *h, struct list_head *list)
+static void fail_all_outstanding_cmds(struct ctlr_info *h)
{
- struct CommandList *c = NULL;
+ int i, refcount;
+ struct CommandList *c;
- assert_spin_locked(&h->lock);
- /* Mark all outstanding commands as failed and complete them. */
- while (!list_empty(list)) {
- c = list_entry(list->next, struct CommandList, list);
- c->err_info->CommandStatus = CMD_HARDWARE_ERR;
- finish_cmd(c);
+ flush_workqueue(h->resubmit_wq); /* ensure all cmds are fully built */
+ for (i = 0; i < h->nr_cmds; i++) {
+ c = h->cmd_pool + i;
+ refcount = atomic_inc_return(&c->refcount);
+ if (refcount > 1) {
+ c->err_info->CommandStatus = CMD_HARDWARE_ERR;
+ finish_cmd(c);
+ }
+ cmd_free(h, c);
}
}
@@ -6704,10 +6663,7 @@ static void controller_lockup_detected(struct ctlr_info *h)
dev_warn(&h->pdev->dev, "Controller lockup detected: 0x%08x\n",
lockup_detected);
pci_disable_device(h->pdev);
- spin_lock_irqsave(&h->lock, flags);
- fail_all_cmds_on_list(h, &h->cmpQ);
- fail_all_cmds_on_list(h, &h->reqQ);
- spin_unlock_irqrestore(&h->lock, flags);
+ fail_all_outstanding_cmds(h);
}
static void detect_controller_lockup(struct ctlr_info *h)
@@ -6750,8 +6706,8 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h)
int i;
char *event_type;
- /* Clear the driver-requested rescan flag */
- h->drv_req_rescan = 0;
+ if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
+ return;
/* Ask the controller to clear the events we're handling. */
if ((h->transMethod & (CFGTBL_Trans_io_accel1
@@ -6798,9 +6754,6 @@ static void hpsa_ack_ctlr_events(struct ctlr_info *h)
*/
static int hpsa_ctlr_needs_rescan(struct ctlr_info *h)
{
- if (h->drv_req_rescan)
- return 1;
-
if (!(h->fw_support & MISC_FW_EVENT_NOTIFY))
return 0;
@@ -6834,34 +6787,58 @@ static int hpsa_offline_devices_ready(struct ctlr_info *h)
return 0;
}
-
-static void hpsa_monitor_ctlr_worker(struct work_struct *work)
+static void hpsa_rescan_ctlr_worker(struct work_struct *work)
{
unsigned long flags;
struct ctlr_info *h = container_of(to_delayed_work(work),
- struct ctlr_info, monitor_ctlr_work);
- detect_controller_lockup(h);
- if (lockup_detected(h))
+ struct ctlr_info, rescan_ctlr_work);
+
+
+ if (h->remove_in_progress)
return;
if (hpsa_ctlr_needs_rescan(h) || hpsa_offline_devices_ready(h)) {
scsi_host_get(h->scsi_host);
- h->drv_req_rescan = 0;
hpsa_ack_ctlr_events(h);
hpsa_scan_start(h->scsi_host);
scsi_host_put(h->scsi_host);
}
-
spin_lock_irqsave(&h->lock, flags);
- if (h->remove_in_progress) {
- spin_unlock_irqrestore(&h->lock, flags);
+ if (!h->remove_in_progress)
+ queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work,
+ h->heartbeat_sample_interval);
+ spin_unlock_irqrestore(&h->lock, flags);
+}
+
+static void hpsa_monitor_ctlr_worker(struct work_struct *work)
+{
+ unsigned long flags;
+ struct ctlr_info *h = container_of(to_delayed_work(work),
+ struct ctlr_info, monitor_ctlr_work);
+
+ detect_controller_lockup(h);
+ if (lockup_detected(h))
return;
- }
- schedule_delayed_work(&h->monitor_ctlr_work,
+
+ spin_lock_irqsave(&h->lock, flags);
+ if (!h->remove_in_progress)
+ schedule_delayed_work(&h->monitor_ctlr_work,
h->heartbeat_sample_interval);
spin_unlock_irqrestore(&h->lock, flags);
}
+static struct workqueue_struct *hpsa_create_controller_wq(struct ctlr_info *h,
+ char *name)
+{
+ struct workqueue_struct *wq = NULL;
+
+ wq = alloc_ordered_workqueue("%s_%d_hpsa", 0, name, h->ctlr);
+ if (!wq)
+ dev_err(&h->pdev->dev, "failed to create %s workqueue\n", name);
+
+ return wq;
+}
+
static int hpsa_init_one(struct pci_dev *pdev, const struct pci_device_id *ent)
{
int dac, rc;
@@ -6898,13 +6875,23 @@ reinit_after_soft_reset:
h->pdev = pdev;
h->intr_mode = hpsa_simple_mode ? SIMPLE_MODE_INT : PERF_MODE_INT;
- INIT_LIST_HEAD(&h->cmpQ);
- INIT_LIST_HEAD(&h->reqQ);
INIT_LIST_HEAD(&h->offline_device_list);
spin_lock_init(&h->lock);
spin_lock_init(&h->offline_device_lock);
spin_lock_init(&h->scan_lock);
- spin_lock_init(&h->passthru_count_lock);
+ atomic_set(&h->passthru_cmds_avail, HPSA_MAX_CONCURRENT_PASSTHRUS);
+
+ h->rescan_ctlr_wq = hpsa_create_controller_wq(h, "rescan");
+ if (!h->rescan_ctlr_wq) {
+ rc = -ENOMEM;
+ goto clean1;
+ }
+
+ h->resubmit_wq = hpsa_create_controller_wq(h, "resubmit");
+ if (!h->resubmit_wq) {
+ rc = -ENOMEM;
+ goto clean1;
+ }
/* Allocate and clear per-cpu variable lockup_detected */
h->lockup_detected = alloc_percpu(u32);
@@ -6939,13 +6926,14 @@ reinit_after_soft_reset:
/* make sure the board interrupts are off */
h->access.set_intr_mask(h, HPSA_INTR_OFF);
- if (hpsa_request_irq(h, do_hpsa_intr_msi, do_hpsa_intr_intx))
+ if (hpsa_request_irqs(h, do_hpsa_intr_msi, do_hpsa_intr_intx))
goto clean2;
dev_info(&pdev->dev, "%s: <0x%x> at IRQ %d%s using DAC\n",
h->devname, pdev->device,
h->intr[h->intr_mode], dac ? "" : " not");
- if (hpsa_allocate_cmd_pool(h))
- goto clean4;
+ rc = hpsa_allocate_cmd_pool(h);
+ if (rc)
+ goto clean2_and_free_irqs;
if (hpsa_allocate_sg_chain_blocks(h))
goto clean4;
init_waitqueue_head(&h->scan_wait_queue);
@@ -6974,12 +6962,12 @@ reinit_after_soft_reset:
spin_lock_irqsave(&h->lock, flags);
h->access.set_intr_mask(h, HPSA_INTR_OFF);
spin_unlock_irqrestore(&h->lock, flags);
- free_irqs(h);
- rc = hpsa_request_irq(h, hpsa_msix_discard_completions,
+ hpsa_free_irqs(h);
+ rc = hpsa_request_irqs(h, hpsa_msix_discard_completions,
hpsa_intx_discard_completions);
if (rc) {
- dev_warn(&h->pdev->dev, "Failed to request_irq after "
- "soft reset.\n");
+ dev_warn(&h->pdev->dev,
+ "Failed to request_irq after soft reset.\n");
goto clean4;
}
@@ -7016,7 +7004,6 @@ reinit_after_soft_reset:
/* Enable Accelerated IO path at driver layer */
h->acciopath_status = 1;
- h->drv_req_rescan = 0;
/* Turn the interrupts on so we can service requests */
h->access.set_intr_mask(h, HPSA_INTR_ON);
@@ -7029,14 +7016,22 @@ reinit_after_soft_reset:
INIT_DELAYED_WORK(&h->monitor_ctlr_work, hpsa_monitor_ctlr_worker);
schedule_delayed_work(&h->monitor_ctlr_work,
h->heartbeat_sample_interval);
+ INIT_DELAYED_WORK(&h->rescan_ctlr_work, hpsa_rescan_ctlr_worker);
+ queue_delayed_work(h->rescan_ctlr_wq, &h->rescan_ctlr_work,
+ h->heartbeat_sample_interval);
return 0;
clean4:
hpsa_free_sg_chain_blocks(h);
hpsa_free_cmd_pool(h);
- free_irqs(h);
+clean2_and_free_irqs:
+ hpsa_free_irqs(h);
clean2:
clean1:
+ if (h->resubmit_wq)
+ destroy_workqueue(h->resubmit_wq);
+ if (h->rescan_ctlr_wq)
+ destroy_workqueue(h->rescan_ctlr_wq);
if (h->lockup_detected)
free_percpu(h->lockup_detected);
kfree(h);
@@ -7055,9 +7050,9 @@ static void hpsa_flush_cache(struct ctlr_info *h)
if (!flush_buf)
return;
- c = cmd_special_alloc(h);
+ c = cmd_alloc(h);
if (!c) {
- dev_warn(&h->pdev->dev, "cmd_special_alloc returned NULL!\n");
+ dev_warn(&h->pdev->dev, "cmd_alloc returned NULL!\n");
goto out_of_memory;
}
if (fill_cmd(c, HPSA_CACHE_FLUSH, h, flush_buf, 4, 0,
@@ -7069,7 +7064,7 @@ static void hpsa_flush_cache(struct ctlr_info *h)
out:
dev_warn(&h->pdev->dev,
"error flushing cache on controller\n");
- cmd_special_free(h, c);
+ cmd_free(h, c);
out_of_memory:
kfree(flush_buf);
}
@@ -7110,9 +7105,11 @@ static void hpsa_remove_one(struct pci_dev *pdev)
/* Get rid of any controller monitoring work items */
spin_lock_irqsave(&h->lock, flags);
h->remove_in_progress = 1;
- cancel_delayed_work(&h->monitor_ctlr_work);
spin_unlock_irqrestore(&h->lock, flags);
-
+ cancel_delayed_work_sync(&h->monitor_ctlr_work);
+ cancel_delayed_work_sync(&h->rescan_ctlr_work);
+ destroy_workqueue(h->rescan_ctlr_wq);
+ destroy_workqueue(h->resubmit_wq);
hpsa_unregister_scsi(h); /* unhook from SCSI subsystem */
hpsa_shutdown(pdev);
iounmap(h->vaddr);
@@ -7172,7 +7169,7 @@ static struct pci_driver hpsa_pci_driver = {
* bits of the command address.
*/
static void calc_bucket_map(int bucket[], int num_buckets,
- int nsgs, int min_blocks, int *bucket_map)
+ int nsgs, int min_blocks, u32 *bucket_map)
{
int i, j, b, size;
@@ -7193,7 +7190,8 @@ static void calc_bucket_map(int bucket[], int num_buckets,
}
}
-static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
+/* return -ENODEV or other reason on error, 0 on success */
+static int hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
{
int i;
unsigned long register_value;
@@ -7285,12 +7283,16 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
}
}
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
- hpsa_wait_for_mode_change_ack(h);
+ if (hpsa_wait_for_mode_change_ack(h)) {
+ dev_err(&h->pdev->dev,
+ "performant mode problem - doorbell timeout\n");
+ return -ENODEV;
+ }
register_value = readl(&(h->cfgtable->TransportActive));
if (!(register_value & CFGTBL_Trans_Performant)) {
- dev_warn(&h->pdev->dev, "unable to get board into"
- " performant mode\n");
- return;
+ dev_err(&h->pdev->dev,
+ "performant mode problem - transport not active\n");
+ return -ENODEV;
}
/* Change the access methods to the performant access methods */
h->access = access;
@@ -7298,7 +7300,7 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
if (!((trans_support & CFGTBL_Trans_io_accel1) ||
(trans_support & CFGTBL_Trans_io_accel2)))
- return;
+ return 0;
if (trans_support & CFGTBL_Trans_io_accel1) {
/* Set up I/O accelerator mode */
@@ -7328,12 +7330,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
(i * sizeof(struct ErrorInfo)));
cp->err_info_len = sizeof(struct ErrorInfo);
cp->sgl_offset = IOACCEL1_SGLOFFSET;
- cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT;
+ cp->host_context_flags =
+ cpu_to_le16(IOACCEL1_HCFLAGS_CISS_FORMAT);
cp->timeout_sec = 0;
cp->ReplyQueue = 0;
cp->tag =
- cpu_to_le64((i << DIRECT_LOOKUP_SHIFT) |
- DIRECT_LOOKUP_BIT);
+ cpu_to_le64((i << DIRECT_LOOKUP_SHIFT));
cp->host_addr =
cpu_to_le64(h->ioaccel_cmd_pool_dhandle +
(i * sizeof(struct io_accel1_cmd)));
@@ -7362,7 +7364,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
writel(bft2[i], &h->ioaccel2_bft2_regs[i]);
}
writel(CFGTBL_ChangeReq, h->vaddr + SA5_DOORBELL);
- hpsa_wait_for_mode_change_ack(h);
+ if (hpsa_wait_for_mode_change_ack(h)) {
+ dev_err(&h->pdev->dev,
+ "performant mode problem - enabling ioaccel mode\n");
+ return -ENODEV;
+ }
+ return 0;
}
static int hpsa_alloc_ioaccel_cmd_and_bft(struct ctlr_info *h)
@@ -7508,17 +7515,18 @@ static int is_accelerated_cmd(struct CommandList *c)
static void hpsa_drain_accel_commands(struct ctlr_info *h)
{
struct CommandList *c = NULL;
- unsigned long flags;
- int accel_cmds_out;
+ int i, accel_cmds_out;
+ int refcount;
- do { /* wait for all outstanding commands to drain out */
+ do { /* wait for all outstanding ioaccel commands to drain out */
accel_cmds_out = 0;
- spin_lock_irqsave(&h->lock, flags);
- list_for_each_entry(c, &h->cmpQ, list)
- accel_cmds_out += is_accelerated_cmd(c);
- list_for_each_entry(c, &h->reqQ, list)
- accel_cmds_out += is_accelerated_cmd(c);
- spin_unlock_irqrestore(&h->lock, flags);
+ for (i = 0; i < h->nr_cmds; i++) {
+ c = h->cmd_pool + i;
+ refcount = atomic_inc_return(&c->refcount);
+ if (refcount > 1) /* Command is allocated */
+ accel_cmds_out += is_accelerated_cmd(c);
+ cmd_free(h, c);
+ }
if (accel_cmds_out <= 0)
break;
msleep(100);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 8e06d9e280ec..657713050349 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -32,7 +32,6 @@ struct access_method {
void (*submit_command)(struct ctlr_info *h,
struct CommandList *c);
void (*set_intr_mask)(struct ctlr_info *h, unsigned long val);
- unsigned long (*fifo_full)(struct ctlr_info *h);
bool (*intr_pending)(struct ctlr_info *h);
unsigned long (*command_completed)(struct ctlr_info *h, u8 q);
};
@@ -47,6 +46,11 @@ struct hpsa_scsi_dev_t {
unsigned char model[16]; /* bytes 16-31 of inquiry data */
unsigned char raid_level; /* from inquiry page 0xC1 */
unsigned char volume_offline; /* discovered via TUR or VPD */
+ u16 queue_depth; /* max queue_depth for this device */
+ atomic_t ioaccel_cmds_out; /* Only used for physical devices
+ * counts commands sent to physical
+ * device via "ioaccel" path.
+ */
u32 ioaccel_handle;
int offload_config; /* I/O accel RAID offload configured */
int offload_enabled; /* I/O accel RAID offload enabled */
@@ -55,6 +59,15 @@ struct hpsa_scsi_dev_t {
*/
struct raid_map_data raid_map; /* I/O accelerator RAID map */
+ /*
+ * Pointers from logical drive map indices to the phys drives that
+ * make those logical drives. Note, multiple logical drives may
+ * share physical drives. You can have for instance 5 physical
+ * drives with 3 logical drives each using those same 5 physical
+ * disks. We need these pointers for counting i/o's out to physical
+ * devices in order to honor physical device queue depth limits.
+ */
+ struct hpsa_scsi_dev_t *phys_disk[RAID_MAP_MAX_ENTRIES];
};
struct reply_queue_buffer {
@@ -115,9 +128,12 @@ struct ctlr_info {
void __iomem *vaddr;
unsigned long paddr;
int nr_cmds; /* Number of commands allowed on this controller */
+#define HPSA_CMDS_RESERVED_FOR_ABORTS 2
+#define HPSA_CMDS_RESERVED_FOR_DRIVER 1
struct CfgTable __iomem *cfgtable;
int interrupts_enabled;
int max_commands;
+ int last_allocation;
atomic_t commands_outstanding;
# define PERF_MODE_INT 0
# define DOORBELL_INT 1
@@ -131,8 +147,6 @@ struct ctlr_info {
char hba_mode_enabled;
/* queue and queue Info */
- struct list_head reqQ;
- struct list_head cmpQ;
unsigned int Qdepth;
unsigned int maxSG;
spinlock_t lock;
@@ -168,9 +182,8 @@ struct ctlr_info {
unsigned long transMethod;
/* cap concurrent passthrus at some reasonable maximum */
-#define HPSA_MAX_CONCURRENT_PASSTHRUS (20)
- spinlock_t passthru_count_lock; /* protects passthru_count */
- int passthru_count;
+#define HPSA_MAX_CONCURRENT_PASSTHRUS (10)
+ atomic_t passthru_cmds_avail;
/*
* Performant mode completion buffers
@@ -194,8 +207,8 @@ struct ctlr_info {
atomic_t firmware_flash_in_progress;
u32 __percpu *lockup_detected;
struct delayed_work monitor_ctlr_work;
+ struct delayed_work rescan_ctlr_work;
int remove_in_progress;
- u32 fifo_recently_full;
/* Address of h->q[x] is passed to intr handler to know which queue */
u8 q[MAX_REPLY_QUEUES];
u32 TMFSupportFlags; /* cache what task mgmt funcs are supported. */
@@ -237,8 +250,9 @@ struct ctlr_info {
spinlock_t offline_device_lock;
struct list_head offline_device_list;
int acciopath_status;
- int drv_req_rescan; /* flag for driver to request rescan event */
int raid_offload_debug;
+ struct workqueue_struct *resubmit_wq;
+ struct workqueue_struct *rescan_ctlr_wq;
};
struct offline_device_entry {
@@ -297,6 +311,8 @@ struct offline_device_entry {
*/
#define SA5_DOORBELL 0x20
#define SA5_REQUEST_PORT_OFFSET 0x40
+#define SA5_REQUEST_PORT64_LO_OFFSET 0xC0
+#define SA5_REQUEST_PORT64_HI_OFFSET 0xC4
#define SA5_REPLY_INTR_MASK_OFFSET 0x34
#define SA5_REPLY_PORT_OFFSET 0x44
#define SA5_INTR_STATUS 0x30
@@ -353,10 +369,7 @@ static void SA5_submit_command_no_read(struct ctlr_info *h,
static void SA5_submit_command_ioaccel2(struct ctlr_info *h,
struct CommandList *c)
{
- if (c->cmd_type == CMD_IOACCEL2)
- writel(c->busaddr, h->vaddr + IOACCEL2_INBOUND_POSTQ_32);
- else
- writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
+ writel(c->busaddr, h->vaddr + SA5_REQUEST_PORT_OFFSET);
}
/*
@@ -398,19 +411,19 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
unsigned long register_value = FIFO_EMPTY;
/* msi auto clears the interrupt pending bit. */
- if (!(h->msi_vector || h->msix_vector)) {
+ if (unlikely(!(h->msi_vector || h->msix_vector))) {
/* flush the controller write of the reply queue by reading
* outbound doorbell status register.
*/
- register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ (void) readl(h->vaddr + SA5_OUTDB_STATUS);
writel(SA5_OUTDB_CLEAR_PERF_BIT, h->vaddr + SA5_OUTDB_CLEAR);
/* Do a read in order to flush the write to the controller
* (as per spec.)
*/
- register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
+ (void) readl(h->vaddr + SA5_OUTDB_STATUS);
}
- if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
+ if ((((u32) rq->head[rq->current_entry]) & 1) == rq->wraparound) {
register_value = rq->head[rq->current_entry];
rq->current_entry++;
atomic_dec(&h->commands_outstanding);
@@ -426,14 +439,6 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
}
/*
- * Returns true if fifo is full.
- *
- */
-static unsigned long SA5_fifo_full(struct ctlr_info *h)
-{
- return atomic_read(&h->commands_outstanding) >= h->max_commands;
-}
-/*
* returns value read from hardware.
* returns FIFO_EMPTY if there is nothing to read
*/
@@ -473,9 +478,6 @@ static bool SA5_performant_intr_pending(struct ctlr_info *h)
if (!register_value)
return false;
- if (h->msi_vector || h->msix_vector)
- return true;
-
/* Read outbound doorbell to flush */
register_value = readl(h->vaddr + SA5_OUTDB_STATUS);
return register_value & SA5_OUTDB_STATUS_PERF_BIT;
@@ -525,7 +527,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
static struct access_method SA5_access = {
SA5_submit_command,
SA5_intr_mask,
- SA5_fifo_full,
SA5_intr_pending,
SA5_completed,
};
@@ -533,7 +534,6 @@ static struct access_method SA5_access = {
static struct access_method SA5_ioaccel_mode1_access = {
SA5_submit_command,
SA5_performant_intr_mask,
- SA5_fifo_full,
SA5_ioaccel_mode1_intr_pending,
SA5_ioaccel_mode1_completed,
};
@@ -541,7 +541,6 @@ static struct access_method SA5_ioaccel_mode1_access = {
static struct access_method SA5_ioaccel_mode2_access = {
SA5_submit_command_ioaccel2,
SA5_performant_intr_mask,
- SA5_fifo_full,
SA5_performant_intr_pending,
SA5_performant_completed,
};
@@ -549,7 +548,6 @@ static struct access_method SA5_ioaccel_mode2_access = {
static struct access_method SA5_performant_access = {
SA5_submit_command,
SA5_performant_intr_mask,
- SA5_fifo_full,
SA5_performant_intr_pending,
SA5_performant_completed,
};
@@ -557,7 +555,6 @@ static struct access_method SA5_performant_access = {
static struct access_method SA5_performant_access_no_read = {
SA5_submit_command_no_read,
SA5_performant_intr_mask,
- SA5_fifo_full,
SA5_performant_intr_pending,
SA5_performant_completed,
};
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index cb988c41cad9..3a621c74b76f 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -206,27 +206,27 @@ struct raid_map_disk_data {
};
struct raid_map_data {
- u32 structure_size; /* Size of entire structure in bytes */
- u32 volume_blk_size; /* bytes / block in the volume */
- u64 volume_blk_cnt; /* logical blocks on the volume */
+ __le32 structure_size; /* Size of entire structure in bytes */
+ __le32 volume_blk_size; /* bytes / block in the volume */
+ __le64 volume_blk_cnt; /* logical blocks on the volume */
u8 phys_blk_shift; /* Shift factor to convert between
* units of logical blocks and physical
* disk blocks */
u8 parity_rotation_shift; /* Shift factor to convert between units
* of logical stripes and physical
* stripes */
- u16 strip_size; /* blocks used on each disk / stripe */
- u64 disk_starting_blk; /* First disk block used in volume */
- u64 disk_blk_cnt; /* disk blocks used by volume / disk */
- u16 data_disks_per_row; /* data disk entries / row in the map */
- u16 metadata_disks_per_row; /* mirror/parity disk entries / row
+ __le16 strip_size; /* blocks used on each disk / stripe */
+ __le64 disk_starting_blk; /* First disk block used in volume */
+ __le64 disk_blk_cnt; /* disk blocks used by volume / disk */
+ __le16 data_disks_per_row; /* data disk entries / row in the map */
+ __le16 metadata_disks_per_row;/* mirror/parity disk entries / row
* in the map */
- u16 row_cnt; /* rows in each layout map */
- u16 layout_map_count; /* layout maps (1 map per mirror/parity
+ __le16 row_cnt; /* rows in each layout map */
+ __le16 layout_map_count; /* layout maps (1 map per mirror/parity
* group) */
- u16 flags; /* Bit 0 set if encryption enabled */
+ __le16 flags; /* Bit 0 set if encryption enabled */
#define RAID_MAP_FLAG_ENCRYPT_ON 0x01
- u16 dekindex; /* Data encryption key index. */
+ __le16 dekindex; /* Data encryption key index. */
u8 reserved[16];
struct raid_map_disk_data data[RAID_MAP_MAX_ENTRIES];
};
@@ -240,6 +240,10 @@ struct ReportLUNdata {
struct ext_report_lun_entry {
u8 lunid[8];
+#define GET_BMIC_BUS(lunid) ((lunid)[7] & 0x3F)
+#define GET_BMIC_LEVEL_TWO_TARGET(lunid) ((lunid)[6])
+#define GET_BMIC_DRIVE_NUMBER(lunid) (((GET_BMIC_BUS((lunid)) - 1) << 8) + \
+ GET_BMIC_LEVEL_TWO_TARGET((lunid)))
u8 wwid[8];
u8 device_type;
u8 device_flags;
@@ -268,6 +272,7 @@ struct SenseSubsystem_info {
#define HPSA_CACHE_FLUSH 0x01 /* C2 was already being used by HPSA */
#define BMIC_FLASH_FIRMWARE 0xF7
#define BMIC_SENSE_CONTROLLER_PARAMETERS 0x64
+#define BMIC_IDENTIFY_PHYSICAL_DEVICE 0x15
/* Command List Structure */
union SCSI3Addr {
@@ -313,8 +318,8 @@ union LUNAddr {
struct CommandListHeader {
u8 ReplyQueue;
u8 SGList;
- u16 SGTotal;
- u64 tag;
+ __le16 SGTotal;
+ __le64 tag;
union LUNAddr LUN;
};
@@ -338,14 +343,14 @@ struct RequestBlock {
};
struct ErrDescriptor {
- u64 Addr;
- u32 Len;
+ __le64 Addr;
+ __le32 Len;
};
struct SGDescriptor {
- u64 Addr;
- u32 Len;
- u32 Ext;
+ __le64 Addr;
+ __le32 Len;
+ __le32 Ext;
};
union MoreErrInfo {
@@ -375,22 +380,19 @@ struct ErrorInfo {
#define CMD_IOACCEL1 0x04
#define CMD_IOACCEL2 0x05
-#define DIRECT_LOOKUP_SHIFT 5
-#define DIRECT_LOOKUP_BIT 0x10
+#define DIRECT_LOOKUP_SHIFT 4
#define DIRECT_LOOKUP_MASK (~((1 << DIRECT_LOOKUP_SHIFT) - 1))
#define HPSA_ERROR_BIT 0x02
struct ctlr_info; /* defined in hpsa.h */
-/* The size of this structure needs to be divisible by 32
- * on all architectures because low 5 bits of the addresses
+/* The size of this structure needs to be divisible by 128
+ * on all architectures. The low 4 bits of the addresses
* are used as follows:
*
* bit 0: to device, used to indicate "performant mode" command
* from device, indidcates error status.
* bit 1-3: to device, indicates block fetch table entry for
* reducing DMA in fetching commands from host memory.
- * bit 4: used to indicate whether tag is "direct lookup" (index),
- * or a bus address.
*/
#define COMMANDLIST_ALIGNMENT 128
@@ -405,9 +407,21 @@ struct CommandList {
struct ctlr_info *h;
int cmd_type;
long cmdindex;
- struct list_head list;
struct completion *waiting;
- void *scsi_cmd;
+ struct scsi_cmnd *scsi_cmd;
+ struct work_struct work;
+
+ /*
+ * For commands using either of the two "ioaccel" paths to
+ * bypass the RAID stack and go directly to the physical disk
+ * phys_disk is a pointer to the hpsa_scsi_dev_t to which the
+ * i/o is destined. We need to store that here because the command
+ * may potentially encounter TASK SET FULL and need to be resubmitted
+ * For "normal" i/o's not using the "ioaccel" paths, phys_disk is
+ * not used.
+ */
+ struct hpsa_scsi_dev_t *phys_disk;
+ atomic_t refcount; /* Must be last to avoid memset in cmd_alloc */
} __aligned(COMMANDLIST_ALIGNMENT);
/* Max S/G elements in I/O accelerator command */
@@ -420,7 +434,7 @@ struct CommandList {
*/
#define IOACCEL1_COMMANDLIST_ALIGNMENT 128
struct io_accel1_cmd {
- u16 dev_handle; /* 0x00 - 0x01 */
+ __le16 dev_handle; /* 0x00 - 0x01 */
u8 reserved1; /* 0x02 */
u8 function; /* 0x03 */
u8 reserved2[8]; /* 0x04 - 0x0B */
@@ -430,20 +444,20 @@ struct io_accel1_cmd {
u8 reserved4; /* 0x13 */
u8 sgl_offset; /* 0x14 */
u8 reserved5[7]; /* 0x15 - 0x1B */
- u32 transfer_len; /* 0x1C - 0x1F */
+ __le32 transfer_len; /* 0x1C - 0x1F */
u8 reserved6[4]; /* 0x20 - 0x23 */
- u16 io_flags; /* 0x24 - 0x25 */
+ __le16 io_flags; /* 0x24 - 0x25 */
u8 reserved7[14]; /* 0x26 - 0x33 */
u8 LUN[8]; /* 0x34 - 0x3B */
- u32 control; /* 0x3C - 0x3F */
+ __le32 control; /* 0x3C - 0x3F */
u8 CDB[16]; /* 0x40 - 0x4F */
u8 reserved8[16]; /* 0x50 - 0x5F */
- u16 host_context_flags; /* 0x60 - 0x61 */
- u16 timeout_sec; /* 0x62 - 0x63 */
+ __le16 host_context_flags; /* 0x60 - 0x61 */
+ __le16 timeout_sec; /* 0x62 - 0x63 */
u8 ReplyQueue; /* 0x64 */
u8 reserved9[3]; /* 0x65 - 0x67 */
- u64 tag; /* 0x68 - 0x6F */
- u64 host_addr; /* 0x70 - 0x77 */
+ __le64 tag; /* 0x68 - 0x6F */
+ __le64 host_addr; /* 0x70 - 0x77 */
u8 CISS_LUN[8]; /* 0x78 - 0x7F */
struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES];
} __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT);
@@ -470,8 +484,8 @@ struct io_accel1_cmd {
#define IOACCEL1_BUSADDR_CMDTYPE 0x00000060
struct ioaccel2_sg_element {
- u64 address;
- u32 length;
+ __le64 address;
+ __le32 length;
u8 reserved[3];
u8 chain_indicator;
#define IOACCEL2_CHAIN 0x80
@@ -526,20 +540,20 @@ struct io_accel2_cmd {
/* 0=off, 1=on */
u8 reply_queue; /* Reply Queue ID */
u8 reserved1; /* Reserved */
- u32 scsi_nexus; /* Device Handle */
- u32 Tag; /* cciss tag, lower 4 bytes only */
- u32 tweak_lower; /* Encryption tweak, lower 4 bytes */
+ __le32 scsi_nexus; /* Device Handle */
+ __le32 Tag; /* cciss tag, lower 4 bytes only */
+ __le32 tweak_lower; /* Encryption tweak, lower 4 bytes */
u8 cdb[16]; /* SCSI Command Descriptor Block */
u8 cciss_lun[8]; /* 8 byte SCSI address */
- u32 data_len; /* Total bytes to transfer */
+ __le32 data_len; /* Total bytes to transfer */
u8 cmd_priority_task_attr; /* priority and task attrs */
#define IOACCEL2_PRIORITY_MASK 0x78
#define IOACCEL2_ATTR_MASK 0x07
u8 sg_count; /* Number of sg elements */
- u16 dekindex; /* Data encryption key index */
- u64 err_ptr; /* Error Pointer */
- u32 err_len; /* Error Length*/
- u32 tweak_upper; /* Encryption tweak, upper 4 bytes */
+ __le16 dekindex; /* Data encryption key index */
+ __le64 err_ptr; /* Error Pointer */
+ __le32 err_len; /* Error Length*/
+ __le32 tweak_upper; /* Encryption tweak, upper 4 bytes */
struct ioaccel2_sg_element sg[IOACCEL2_MAXSGENTRIES];
struct io_accel2_scsi_response error_data;
} __aligned(IOACCEL2_COMMANDLIST_ALIGNMENT);
@@ -563,18 +577,18 @@ 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 */
- 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 */
+ __le64 tag; /* cciss tag associated w/ request */
+ __le64 abort_tag; /* cciss tag of SCSI cmd or TMF to abort */
+ __le64 error_ptr; /* Error Pointer */
+ __le32 error_len; /* Error Length */
};
/* Configuration Table Structure */
struct HostWrite {
- u32 TransportRequest;
- u32 command_pool_addr_hi;
- u32 CoalIntDelay;
- u32 CoalIntCount;
+ __le32 TransportRequest;
+ __le32 command_pool_addr_hi;
+ __le32 CoalIntDelay;
+ __le32 CoalIntCount;
};
#define SIMPLE_MODE 0x02
@@ -585,54 +599,54 @@ struct HostWrite {
#define DRIVER_SUPPORT_UA_ENABLE 0x00000001
struct CfgTable {
- u8 Signature[4];
- u32 SpecValence;
- u32 TransportSupport;
- u32 TransportActive;
- struct HostWrite HostWrite;
- u32 CmdsOutMax;
- u32 BusTypes;
- u32 TransMethodOffset;
- u8 ServerName[16];
- u32 HeartBeat;
- u32 driver_support;
-#define ENABLE_SCSI_PREFETCH 0x100
-#define ENABLE_UNIT_ATTN 0x01
- u32 MaxScatterGatherElements;
- u32 MaxLogicalUnits;
- u32 MaxPhysicalDevices;
- u32 MaxPhysicalDrivesPerLogicalUnit;
- u32 MaxPerformantModeCommands;
- u32 MaxBlockFetch;
- u32 PowerConservationSupport;
- u32 PowerConservationEnable;
- u32 TMFSupportFlags;
+ u8 Signature[4];
+ __le32 SpecValence;
+ __le32 TransportSupport;
+ __le32 TransportActive;
+ struct HostWrite HostWrite;
+ __le32 CmdsOutMax;
+ __le32 BusTypes;
+ __le32 TransMethodOffset;
+ u8 ServerName[16];
+ __le32 HeartBeat;
+ __le32 driver_support;
+#define ENABLE_SCSI_PREFETCH 0x100
+#define ENABLE_UNIT_ATTN 0x01
+ __le32 MaxScatterGatherElements;
+ __le32 MaxLogicalUnits;
+ __le32 MaxPhysicalDevices;
+ __le32 MaxPhysicalDrivesPerLogicalUnit;
+ __le32 MaxPerformantModeCommands;
+ __le32 MaxBlockFetch;
+ __le32 PowerConservationSupport;
+ __le32 PowerConservationEnable;
+ __le32 TMFSupportFlags;
u8 TMFTagMask[8];
u8 reserved[0x78 - 0x70];
- u32 misc_fw_support; /* offset 0x78 */
-#define MISC_FW_DOORBELL_RESET (0x02)
-#define MISC_FW_DOORBELL_RESET2 (0x010)
-#define MISC_FW_RAID_OFFLOAD_BASIC (0x020)
-#define MISC_FW_EVENT_NOTIFY (0x080)
+ __le32 misc_fw_support; /* offset 0x78 */
+#define MISC_FW_DOORBELL_RESET 0x02
+#define MISC_FW_DOORBELL_RESET2 0x010
+#define MISC_FW_RAID_OFFLOAD_BASIC 0x020
+#define MISC_FW_EVENT_NOTIFY 0x080
u8 driver_version[32];
- u32 max_cached_write_size;
- u8 driver_scratchpad[16];
- u32 max_error_info_length;
- u32 io_accel_max_embedded_sg_count;
- u32 io_accel_request_size_offset;
- u32 event_notify;
-#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30)
-#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31)
- u32 clear_event_notify;
+ __le32 max_cached_write_size;
+ u8 driver_scratchpad[16];
+ __le32 max_error_info_length;
+ __le32 io_accel_max_embedded_sg_count;
+ __le32 io_accel_request_size_offset;
+ __le32 event_notify;
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_STATE_CHANGE (1 << 30)
+#define HPSA_EVENT_NOTIFY_ACCEL_IO_PATH_CONFIG_CHANGE (1 << 31)
+ __le32 clear_event_notify;
};
#define NUM_BLOCKFETCH_ENTRIES 8
struct TransTable_struct {
- u32 BlockFetch[NUM_BLOCKFETCH_ENTRIES];
- u32 RepQSize;
- u32 RepQCount;
- u32 RepQCtrAddrLow32;
- u32 RepQCtrAddrHigh32;
+ __le32 BlockFetch[NUM_BLOCKFETCH_ENTRIES];
+ __le32 RepQSize;
+ __le32 RepQCount;
+ __le32 RepQCtrAddrLow32;
+ __le32 RepQCtrAddrHigh32;
#define MAX_REPLY_QUEUES 64
struct vals32 RepQAddr[MAX_REPLY_QUEUES];
};
@@ -644,5 +658,137 @@ struct hpsa_pci_info {
u32 board_id;
};
+struct bmic_identify_physical_device {
+ u8 scsi_bus; /* SCSI Bus number on controller */
+ u8 scsi_id; /* SCSI ID on this bus */
+ __le16 block_size; /* sector size in bytes */
+ __le32 total_blocks; /* number for sectors on drive */
+ __le32 reserved_blocks; /* controller reserved (RIS) */
+ u8 model[40]; /* Physical Drive Model */
+ u8 serial_number[40]; /* Drive Serial Number */
+ u8 firmware_revision[8]; /* drive firmware revision */
+ u8 scsi_inquiry_bits; /* inquiry byte 7 bits */
+ u8 compaq_drive_stamp; /* 0 means drive not stamped */
+ u8 last_failure_reason;
+#define BMIC_LAST_FAILURE_TOO_SMALL_IN_LOAD_CONFIG 0x01
+#define BMIC_LAST_FAILURE_ERROR_ERASING_RIS 0x02
+#define BMIC_LAST_FAILURE_ERROR_SAVING_RIS 0x03
+#define BMIC_LAST_FAILURE_FAIL_DRIVE_COMMAND 0x04
+#define BMIC_LAST_FAILURE_MARK_BAD_FAILED 0x05
+#define BMIC_LAST_FAILURE_MARK_BAD_FAILED_IN_FINISH_REMAP 0x06
+#define BMIC_LAST_FAILURE_TIMEOUT 0x07
+#define BMIC_LAST_FAILURE_AUTOSENSE_FAILED 0x08
+#define BMIC_LAST_FAILURE_MEDIUM_ERROR_1 0x09
+#define BMIC_LAST_FAILURE_MEDIUM_ERROR_2 0x0a
+#define BMIC_LAST_FAILURE_NOT_READY_BAD_SENSE 0x0b
+#define BMIC_LAST_FAILURE_NOT_READY 0x0c
+#define BMIC_LAST_FAILURE_HARDWARE_ERROR 0x0d
+#define BMIC_LAST_FAILURE_ABORTED_COMMAND 0x0e
+#define BMIC_LAST_FAILURE_WRITE_PROTECTED 0x0f
+#define BMIC_LAST_FAILURE_SPIN_UP_FAILURE_IN_RECOVER 0x10
+#define BMIC_LAST_FAILURE_REBUILD_WRITE_ERROR 0x11
+#define BMIC_LAST_FAILURE_TOO_SMALL_IN_HOT_PLUG 0x12
+#define BMIC_LAST_FAILURE_BUS_RESET_RECOVERY_ABORTED 0x13
+#define BMIC_LAST_FAILURE_REMOVED_IN_HOT_PLUG 0x14
+#define BMIC_LAST_FAILURE_INIT_REQUEST_SENSE_FAILED 0x15
+#define BMIC_LAST_FAILURE_INIT_START_UNIT_FAILED 0x16
+#define BMIC_LAST_FAILURE_INQUIRY_FAILED 0x17
+#define BMIC_LAST_FAILURE_NON_DISK_DEVICE 0x18
+#define BMIC_LAST_FAILURE_READ_CAPACITY_FAILED 0x19
+#define BMIC_LAST_FAILURE_INVALID_BLOCK_SIZE 0x1a
+#define BMIC_LAST_FAILURE_HOT_PLUG_REQUEST_SENSE_FAILED 0x1b
+#define BMIC_LAST_FAILURE_HOT_PLUG_START_UNIT_FAILED 0x1c
+#define BMIC_LAST_FAILURE_WRITE_ERROR_AFTER_REMAP 0x1d
+#define BMIC_LAST_FAILURE_INIT_RESET_RECOVERY_ABORTED 0x1e
+#define BMIC_LAST_FAILURE_DEFERRED_WRITE_ERROR 0x1f
+#define BMIC_LAST_FAILURE_MISSING_IN_SAVE_RIS 0x20
+#define BMIC_LAST_FAILURE_WRONG_REPLACE 0x21
+#define BMIC_LAST_FAILURE_GDP_VPD_INQUIRY_FAILED 0x22
+#define BMIC_LAST_FAILURE_GDP_MODE_SENSE_FAILED 0x23
+#define BMIC_LAST_FAILURE_DRIVE_NOT_IN_48BIT_MODE 0x24
+#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_HOT_PLUG 0x25
+#define BMIC_LAST_FAILURE_DRIVE_TYPE_MIX_IN_LOAD_CFG 0x26
+#define BMIC_LAST_FAILURE_PROTOCOL_ADAPTER_FAILED 0x27
+#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_EMPTY 0x28
+#define BMIC_LAST_FAILURE_FAULTY_ID_BAY_OCCUPIED 0x29
+#define BMIC_LAST_FAILURE_FAULTY_ID_INVALID_BAY 0x2a
+#define BMIC_LAST_FAILURE_WRITE_RETRIES_FAILED 0x2b
+
+#define BMIC_LAST_FAILURE_SMART_ERROR_REPORTED 0x37
+#define BMIC_LAST_FAILURE_PHY_RESET_FAILED 0x38
+#define BMIC_LAST_FAILURE_ONLY_ONE_CTLR_CAN_SEE_DRIVE 0x40
+#define BMIC_LAST_FAILURE_KC_VOLUME_FAILED 0x41
+#define BMIC_LAST_FAILURE_UNEXPECTED_REPLACEMENT 0x42
+#define BMIC_LAST_FAILURE_OFFLINE_ERASE 0x80
+#define BMIC_LAST_FAILURE_OFFLINE_TOO_SMALL 0x81
+#define BMIC_LAST_FAILURE_OFFLINE_DRIVE_TYPE_MIX 0x82
+#define BMIC_LAST_FAILURE_OFFLINE_ERASE_COMPLETE 0x83
+
+ u8 flags;
+ u8 more_flags;
+ u8 scsi_lun; /* SCSI LUN for phys drive */
+ u8 yet_more_flags;
+ u8 even_more_flags;
+ __le32 spi_speed_rules;/* SPI Speed data:Ultra disable diagnose */
+ u8 phys_connector[2]; /* connector number on controller */
+ u8 phys_box_on_bus; /* phys enclosure this drive resides */
+ u8 phys_bay_in_box; /* phys drv bay this drive resides */
+ __le32 rpm; /* Drive rotational speed in rpm */
+ u8 device_type; /* type of drive */
+ u8 sata_version; /* only valid when drive_type is SATA */
+ __le64 big_total_block_count;
+ __le64 ris_starting_lba;
+ __le32 ris_size;
+ u8 wwid[20];
+ u8 controller_phy_map[32];
+ __le16 phy_count;
+ u8 phy_connected_dev_type[256];
+ u8 phy_to_drive_bay_num[256];
+ __le16 phy_to_attached_dev_index[256];
+ u8 box_index;
+ u8 reserved;
+ __le16 extra_physical_drive_flags;
+#define BMIC_PHYS_DRIVE_SUPPORTS_GAS_GAUGE(idphydrv) \
+ (idphydrv->extra_physical_drive_flags & (1 << 10))
+ u8 negotiated_link_rate[256];
+ u8 phy_to_phy_map[256];
+ u8 redundant_path_present_map;
+ u8 redundant_path_failure_map;
+ u8 active_path_number;
+ __le16 alternate_paths_phys_connector[8];
+ u8 alternate_paths_phys_box_on_port[8];
+ u8 multi_lun_device_lun_count;
+ u8 minimum_good_fw_revision[8];
+ u8 unique_inquiry_bytes[20];
+ u8 current_temperature_degreesC;
+ u8 temperature_threshold_degreesC;
+ u8 max_temperature_degreesC;
+ u8 logical_blocks_per_phys_block_exp; /* phyblocksize = 512*2^exp */
+ __le16 current_queue_depth_limit;
+ u8 switch_name[10];
+ __le16 switch_port;
+ u8 alternate_paths_switch_name[40];
+ u8 alternate_paths_switch_port[8];
+ __le16 power_on_hours; /* valid only if gas gauge supported */
+ __le16 percent_endurance_used; /* valid only if gas gauge supported. */
+#define BMIC_PHYS_DRIVE_SSD_WEAROUT(idphydrv) \
+ ((idphydrv->percent_endurance_used & 0x80) || \
+ (idphydrv->percent_endurance_used > 10000))
+ u8 drive_authentication;
+#define BMIC_PHYS_DRIVE_AUTHENTICATED(idphydrv) \
+ (idphydrv->drive_authentication == 0x80)
+ u8 smart_carrier_authentication;
+#define BMIC_SMART_CARRIER_AUTHENTICATION_SUPPORTED(idphydrv) \
+ (idphydrv->smart_carrier_authentication != 0x0)
+#define BMIC_SMART_CARRIER_AUTHENTICATED(idphydrv) \
+ (idphydrv->smart_carrier_authentication == 0x01)
+ u8 smart_carrier_app_fw_version;
+ u8 smart_carrier_bootloader_fw_version;
+ u8 encryption_key_name[64];
+ __le32 misc_drive_flags;
+ __le16 dek_index;
+ u8 padding[112];
+};
+
#pragma pack()
#endif /* HPSA_CMD_H */
diff --git a/drivers/scsi/in2000.c b/drivers/scsi/in2000.c
index ddf0694d87f0..3882d9f519c8 100644
--- a/drivers/scsi/in2000.c
+++ b/drivers/scsi/in2000.c
@@ -2226,36 +2226,36 @@ static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance)
if (hd->proc & PR_INFO) {
seq_printf(m, "\ndip_switch=%02x: irq=%d io=%02x floppy=%s sync/DOS5=%s", (hd->dip_switch & 0x7f), instance->irq, hd->io_base, (hd->dip_switch & 0x40) ? "Yes" : "No", (hd->dip_switch & 0x20) ? "Yes" : "No");
- seq_printf(m, "\nsync_xfer[] = ");
+ seq_puts(m, "\nsync_xfer[] = ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%02x", hd->sync_xfer[x]);
- seq_printf(m, "\nsync_stat[] = ");
+ seq_puts(m, "\nsync_stat[] = ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%02x", hd->sync_stat[x]);
}
#ifdef PROC_STATISTICS
if (hd->proc & PR_STATISTICS) {
- seq_printf(m, "\ncommands issued: ");
+ seq_puts(m, "\ncommands issued: ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%ld", hd->cmd_cnt[x]);
- seq_printf(m, "\ndisconnects allowed:");
+ seq_puts(m, "\ndisconnects allowed:");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]);
- seq_printf(m, "\ndisconnects done: ");
+ seq_puts(m, "\ndisconnects done: ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%ld", hd->disc_done_cnt[x]);
seq_printf(m, "\ninterrupts: \t%ld", hd->int_cnt);
}
#endif
if (hd->proc & PR_CONNECTED) {
- seq_printf(m, "\nconnected: ");
+ seq_puts(m, "\nconnected: ");
if (hd->connected) {
cmd = (Scsi_Cmnd *) hd->connected;
seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
}
}
if (hd->proc & PR_INPUTQ) {
- seq_printf(m, "\ninput_Q: ");
+ seq_puts(m, "\ninput_Q: ");
cmd = (Scsi_Cmnd *) hd->input_Q;
while (cmd) {
seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
@@ -2263,7 +2263,7 @@ static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance)
}
}
if (hd->proc & PR_DISCQ) {
- seq_printf(m, "\ndisconnected_Q:");
+ seq_puts(m, "\ndisconnected_Q:");
cmd = (Scsi_Cmnd *) hd->disconnected_Q;
while (cmd) {
seq_printf(m, " %d:%llu(%02x)", cmd->device->id, cmd->device->lun, cmd->cmnd[0]);
@@ -2273,7 +2273,7 @@ static int in2000_show_info(struct seq_file *m, struct Scsi_Host *instance)
if (hd->proc & PR_TEST) {
; /* insert your own custom function here */
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
spin_unlock_irqrestore(instance->host_lock, flags);
#endif /* PROC_INTERFACE */
return 0;
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index e5c28435d768..7542f11d3fcd 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -2038,15 +2038,14 @@ ips_host_info(ips_ha_t *ha, struct seq_file *m)
{
METHOD_TRACE("ips_host_info", 1);
- seq_printf(m, "\nIBM ServeRAID General Information:\n\n");
+ seq_puts(m, "\nIBM ServeRAID General Information:\n\n");
if ((le32_to_cpu(ha->nvram->signature) == IPS_NVRAM_P5_SIG) &&
(le16_to_cpu(ha->nvram->adapter_type) != 0))
seq_printf(m, "\tController Type : %s\n",
ips_adapter_name[ha->ad_type - 1]);
else
- seq_printf(m,
- "\tController Type : Unknown\n");
+ seq_puts(m, "\tController Type : Unknown\n");
if (ha->io_addr)
seq_printf(m,
@@ -2138,7 +2137,7 @@ ips_host_info(ips_ha_t *ha, struct seq_file *m)
seq_printf(m, "\tCurrent Active PT Commands : %d\n",
ha->num_ioctl);
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
diff --git a/drivers/scsi/lpfc/lpfc_els.c b/drivers/scsi/lpfc/lpfc_els.c
index 4c25485aa934..c66088d0fd2a 100644
--- a/drivers/scsi/lpfc/lpfc_els.c
+++ b/drivers/scsi/lpfc/lpfc_els.c
@@ -2225,6 +2225,15 @@ lpfc_adisc_done(struct lpfc_vport *vport)
if ((phba->sli3_options & LPFC_SLI3_NPIV_ENABLED) &&
!(vport->fc_flag & FC_RSCN_MODE) &&
(phba->sli_rev < LPFC_SLI_REV4)) {
+ /* The ADISCs are complete. Doesn't matter if they
+ * succeeded or failed because the ADISC completion
+ * routine guarantees to call the state machine and
+ * the RPI is either unregistered (failed ADISC response)
+ * or the RPI is still valid and the node is marked
+ * mapped for a target. The exchanges should be in the
+ * correct state. This code is specific to SLI3.
+ */
+ lpfc_issue_clear_la(phba, vport);
lpfc_issue_reg_vpi(phba, vport);
return;
}
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index 2485255f3414..bc7b34c02723 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -2240,7 +2240,7 @@ proc_show_battery(struct seq_file *m, void *v)
goto free_pdev;
if( mega_adapinq(adapter, dma_handle) != 0 ) {
- seq_printf(m, "Adapter inquiry failed.\n");
+ seq_puts(m, "Adapter inquiry failed.\n");
printk(KERN_WARNING "megaraid: inquiry failed.\n");
goto free_inquiry;
}
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index 0d44d91c2fce..14e5c7cea929 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -35,7 +35,7 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.805.06.01-rc1"
+#define MEGASAS_VERSION "06.806.08.00-rc1"
/*
* Device IDs
@@ -969,7 +969,20 @@ struct megasas_ctrl_info {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:25;
+ u32 reserved:12;
+ u32 discardCacheDuringLDDelete:1;
+ u32 supportSecurityonJBOD:1;
+ u32 supportCacheBypassModes:1;
+ u32 supportDisableSESMonitoring:1;
+ u32 supportForceFlash:1;
+ u32 supportNVDRAM:1;
+ u32 supportDrvActivityLEDSetting:1;
+ u32 supportAllowedOpsforDrvRemoval:1;
+ u32 supportHOQRebuild:1;
+ u32 supportForceTo512e:1;
+ u32 supportNVCacheErase:1;
+ u32 supportDebugQueue:1;
+ u32 supportSwZone:1;
u32 supportCrashDump:1;
u32 supportMaxExtLDs:1;
u32 supportT10RebuildAssist:1;
@@ -981,9 +994,22 @@ struct megasas_ctrl_info {
u32 supportThermalPollInterval:1;
u32 supportDisableImmediateIO:1;
u32 supportT10RebuildAssist:1;
- u32 supportMaxExtLDs:1;
- u32 supportCrashDump:1;
- u32 reserved:25;
+ u32 supportMaxExtLDs:1;
+ u32 supportCrashDump:1;
+ u32 supportSwZone:1;
+ u32 supportDebugQueue:1;
+ u32 supportNVCacheErase:1;
+ u32 supportForceTo512e:1;
+ u32 supportHOQRebuild:1;
+ u32 supportAllowedOpsforDrvRemoval:1;
+ u32 supportDrvActivityLEDSetting:1;
+ u32 supportNVDRAM:1;
+ u32 supportForceFlash:1;
+ u32 supportDisableSESMonitoring:1;
+ u32 supportCacheBypassModes:1;
+ u32 supportSecurityonJBOD:1;
+ u32 discardCacheDuringLDDelete:1;
+ u32 reserved:12;
#endif
} adapterOperations3;
@@ -1022,6 +1048,13 @@ enum MR_MFI_MPT_PTHR_FLAGS {
MFI_MPT_ATTACHED = 2,
};
+enum MR_SCSI_CMD_TYPE {
+ READ_WRITE_LDIO = 0,
+ NON_READ_WRITE_LDIO = 1,
+ READ_WRITE_SYSPDIO = 2,
+ NON_READ_WRITE_SYSPDIO = 3,
+};
+
/* Frame Type */
#define IO_FRAME 0
#define PTHRU_FRAME 1
@@ -1049,6 +1082,8 @@ enum MR_MFI_MPT_PTHR_FLAGS {
*/
#define MEGASAS_INT_CMDS 32
#define MEGASAS_SKINNY_INT_CMDS 5
+#define MEGASAS_FUSION_INTERNAL_CMDS 5
+#define MEGASAS_FUSION_IOCTL_CMDS 3
#define MEGASAS_MAX_MSIX_QUEUES 128
/*
@@ -1194,19 +1229,23 @@ union megasas_sgl_frame {
typedef union _MFI_CAPABILITIES {
struct {
#if defined(__BIG_ENDIAN_BITFIELD)
- u32 reserved:27;
+ u32 reserved:25;
+ u32 security_protocol_cmds_fw:1;
+ u32 support_core_affinity:1;
u32 support_ndrive_r1_lb:1;
u32 support_max_255lds:1;
- u32 reserved1:1;
+ u32 support_fastpath_wb:1;
u32 support_additional_msix:1;
u32 support_fp_remote_lun:1;
#else
u32 support_fp_remote_lun:1;
u32 support_additional_msix:1;
- u32 reserved1:1;
+ u32 support_fastpath_wb:1;
u32 support_max_255lds:1;
u32 support_ndrive_r1_lb:1;
- u32 reserved:27;
+ u32 support_core_affinity:1;
+ u32 security_protocol_cmds_fw:1;
+ u32 reserved:25;
#endif
} mfi_capabilities;
u32 reg;
@@ -1638,20 +1677,20 @@ struct megasas_instance {
u32 crash_dump_fw_support;
u32 crash_dump_drv_support;
u32 crash_dump_app_support;
+ u32 secure_jbod_support;
spinlock_t crashdump_lock;
struct megasas_register_set __iomem *reg_set;
u32 *reply_post_host_index_addr[MR_MAX_MSIX_REG_ARRAY];
struct megasas_pd_list pd_list[MEGASAS_MAX_PD];
struct megasas_pd_list local_pd_list[MEGASAS_MAX_PD];
- u8 ld_ids[MEGASAS_MAX_LD_IDS];
+ u8 ld_ids[MEGASAS_MAX_LD_IDS];
s8 init_id;
u16 max_num_sge;
u16 max_fw_cmds;
- /* For Fusion its num IOCTL cmds, for others MFI based its
- max_fw_cmds */
u16 max_mfi_cmds;
+ u16 max_scsi_cmds;
u32 max_sectors_per_req;
struct megasas_aen_event *ev;
@@ -1727,7 +1766,7 @@ struct megasas_instance {
u8 requestorId;
char PlasmaFW111;
char mpio;
- int throttlequeuedepth;
+ u16 throttlequeuedepth;
u8 mask_interrupts;
u8 is_imr;
};
@@ -1946,5 +1985,6 @@ void __megasas_return_cmd(struct megasas_instance *instance,
void megasas_return_mfi_mpt_pthr(struct megasas_instance *instance,
struct megasas_cmd *cmd_mfi, struct megasas_cmd_fusion *cmd_fusion);
+int megasas_cmd_type(struct scsi_cmnd *cmd);
#endif /*LSI_MEGARAID_SAS_H */
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index ff283d23788a..890637fdd61e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -78,7 +78,7 @@ static int allow_vf_ioctls;
module_param(allow_vf_ioctls, int, S_IRUGO);
MODULE_PARM_DESC(allow_vf_ioctls, "Allow ioctls in SR-IOV VF mode. Default: 0");
-static int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
+static unsigned int throttlequeuedepth = MEGASAS_THROTTLE_QUEUE_DEPTH;
module_param(throttlequeuedepth, int, S_IRUGO);
MODULE_PARM_DESC(throttlequeuedepth,
"Adapter queue depth when throttled due to I/O timeout. Default: 16");
@@ -1417,16 +1417,15 @@ megasas_build_ldio(struct megasas_instance *instance, struct scsi_cmnd *scp,
}
/**
- * megasas_is_ldio - Checks if the cmd is for logical drive
+ * megasas_cmd_type - Checks if the cmd is for logical drive/sysPD
+ * and whether it's RW or non RW
* @scmd: SCSI command
*
- * Called by megasas_queue_command to find out if the command to be queued
- * is a logical drive command
*/
-inline int megasas_is_ldio(struct scsi_cmnd *cmd)
+inline int megasas_cmd_type(struct scsi_cmnd *cmd)
{
- if (!MEGASAS_IS_LOGICAL(cmd))
- return 0;
+ int ret;
+
switch (cmd->cmnd[0]) {
case READ_10:
case WRITE_10:
@@ -1436,10 +1435,14 @@ inline int megasas_is_ldio(struct scsi_cmnd *cmd)
case WRITE_6:
case READ_16:
case WRITE_16:
- return 1;
+ ret = (MEGASAS_IS_LOGICAL(cmd)) ?
+ READ_WRITE_LDIO : READ_WRITE_SYSPDIO;
+ break;
default:
- return 0;
+ ret = (MEGASAS_IS_LOGICAL(cmd)) ?
+ NON_READ_WRITE_LDIO : NON_READ_WRITE_SYSPDIO;
}
+ return ret;
}
/**
@@ -1471,7 +1474,7 @@ megasas_dump_pending_frames(struct megasas_instance *instance)
if(!cmd->scmd)
continue;
printk(KERN_ERR "megasas[%d]: Frame addr :0x%08lx : ",instance->host->host_no,(unsigned long)cmd->frame_phys_addr);
- if (megasas_is_ldio(cmd->scmd)){
+ if (megasas_cmd_type(cmd->scmd) == READ_WRITE_LDIO) {
ldio = (struct megasas_io_frame *)cmd->frame;
mfi_sgl = &ldio->sgl;
sgcount = ldio->sge_count;
@@ -1531,7 +1534,7 @@ megasas_build_and_issue_cmd(struct megasas_instance *instance,
/*
* Logical drive command
*/
- if (megasas_is_ldio(scmd))
+ if (megasas_cmd_type(scmd) == READ_WRITE_LDIO)
frame_count = megasas_build_ldio(instance, scmd, cmd);
else
frame_count = megasas_build_dcdb(instance, scmd, cmd);
@@ -1689,22 +1692,66 @@ static int megasas_slave_alloc(struct scsi_device *sdev)
return 0;
}
+/*
+* megasas_complete_outstanding_ioctls - Complete outstanding ioctls after a
+* kill adapter
+* @instance: Adapter soft state
+*
+*/
+void megasas_complete_outstanding_ioctls(struct megasas_instance *instance)
+{
+ int i;
+ struct megasas_cmd *cmd_mfi;
+ struct megasas_cmd_fusion *cmd_fusion;
+ struct fusion_context *fusion = instance->ctrl_context;
+
+ /* Find all outstanding ioctls */
+ if (fusion) {
+ for (i = 0; i < instance->max_fw_cmds; i++) {
+ cmd_fusion = fusion->cmd_list[i];
+ if (cmd_fusion->sync_cmd_idx != (u32)ULONG_MAX) {
+ cmd_mfi = instance->cmd_list[cmd_fusion->sync_cmd_idx];
+ if (cmd_mfi->sync_cmd &&
+ cmd_mfi->frame->hdr.cmd != MFI_CMD_ABORT)
+ megasas_complete_cmd(instance,
+ cmd_mfi, DID_OK);
+ }
+ }
+ } else {
+ for (i = 0; i < instance->max_fw_cmds; i++) {
+ cmd_mfi = instance->cmd_list[i];
+ if (cmd_mfi->sync_cmd && cmd_mfi->frame->hdr.cmd !=
+ MFI_CMD_ABORT)
+ megasas_complete_cmd(instance, cmd_mfi, DID_OK);
+ }
+ }
+}
+
+
void megaraid_sas_kill_hba(struct megasas_instance *instance)
{
+ /* Set critical error to block I/O & ioctls in case caller didn't */
+ instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
+ /* Wait 1 second to ensure IO or ioctls in build have posted */
+ msleep(1000);
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
- writel(MFI_STOP_ADP, &instance->reg_set->doorbell);
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_FUSION) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_PLASMA) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY)) {
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->doorbell);
/* Flush */
readl(&instance->reg_set->doorbell);
if (instance->mpio && instance->requestorId)
memset(instance->ld_ids, 0xff, MEGASAS_MAX_LD_IDS);
} else {
- writel(MFI_STOP_ADP, &instance->reg_set->inbound_doorbell);
+ writel(MFI_STOP_ADP,
+ &instance->reg_set->inbound_doorbell);
}
+ /* Complete outstanding ioctls when adapter is killed */
+ megasas_complete_outstanding_ioctls(instance);
}
/**
@@ -1717,6 +1764,7 @@ void
megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
{
unsigned long flags;
+
if (instance->flag & MEGASAS_FW_BUSY
&& time_after(jiffies, instance->last_time + 5 * HZ)
&& atomic_read(&instance->fw_outstanding) <
@@ -1724,13 +1772,8 @@ megasas_check_and_restore_queue_depth(struct megasas_instance *instance)
spin_lock_irqsave(instance->host->host_lock, flags);
instance->flag &= ~MEGASAS_FW_BUSY;
- if (instance->is_imr) {
- instance->host->can_queue =
- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
- } else
- instance->host->can_queue =
- instance->max_fw_cmds - MEGASAS_INT_CMDS;
+ instance->host->can_queue = instance->max_scsi_cmds;
spin_unlock_irqrestore(instance->host->host_lock, flags);
}
}
@@ -3028,10 +3071,9 @@ megasas_issue_pending_cmds_again(struct megasas_instance *instance)
"was tried multiple times during reset."
"Shutting down the HBA\n",
cmd, cmd->scmd, cmd->sync_cmd);
+ instance->instancet->disable_intr(instance);
+ atomic_set(&instance->fw_reset_no_pci_access, 1);
megaraid_sas_kill_hba(instance);
-
- instance->adprecovery =
- MEGASAS_HW_CRITICAL_ERROR;
return;
}
}
@@ -3165,8 +3207,8 @@ process_fw_state_change_wq(struct work_struct *work)
if (megasas_transition_to_ready(instance, 1)) {
printk(KERN_NOTICE "megaraid_sas:adapter not ready\n");
+ atomic_set(&instance->fw_reset_no_pci_access, 1);
megaraid_sas_kill_hba(instance);
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
return ;
}
@@ -3547,7 +3589,6 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
int i;
u32 max_cmd;
u32 sge_sz;
- u32 sgl_sz;
u32 total_sz;
u32 frame_count;
struct megasas_cmd *cmd;
@@ -3566,24 +3607,23 @@ static int megasas_create_frame_pool(struct megasas_instance *instance)
}
/*
- * Calculated the number of 64byte frames required for SGL
- */
- sgl_sz = sge_sz * instance->max_num_sge;
- frame_count = (sgl_sz + MEGAMFI_FRAME_SIZE - 1) / MEGAMFI_FRAME_SIZE;
- frame_count = 15;
-
- /*
- * We need one extra frame for the MFI command
+ * For MFI controllers.
+ * max_num_sge = 60
+ * max_sge_sz = 16 byte (sizeof megasas_sge_skinny)
+ * Total 960 byte (15 MFI frame of 64 byte)
+ *
+ * Fusion adapter require only 3 extra frame.
+ * max_num_sge = 16 (defined as MAX_IOCTL_SGE)
+ * max_sge_sz = 12 byte (sizeof megasas_sge64)
+ * Total 192 byte (3 MFI frame of 64 byte)
*/
- frame_count++;
-
+ frame_count = instance->ctrl_context ? (3 + 1) : (15 + 1);
total_sz = MEGAMFI_FRAME_SIZE * frame_count;
/*
* Use DMA pool facility provided by PCI layer
*/
instance->frame_dma_pool = pci_pool_create("megasas frame pool",
- instance->pdev, total_sz, 64,
- 0);
+ instance->pdev, total_sz, 256, 0);
if (!instance->frame_dma_pool) {
printk(KERN_DEBUG "megasas: failed to setup frame pool\n");
@@ -4631,28 +4671,48 @@ static int megasas_init_fw(struct megasas_instance *instance)
instance->crash_dump_h);
instance->crash_dump_buf = NULL;
}
+
+ instance->secure_jbod_support =
+ ctrl_info->adapterOperations3.supportSecurityonJBOD;
+ if (instance->secure_jbod_support)
+ dev_info(&instance->pdev->dev, "Firmware supports Secure JBOD\n");
instance->max_sectors_per_req = instance->max_num_sge *
PAGE_SIZE / 512;
if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
instance->max_sectors_per_req = tmp_sectors;
- /* Check for valid throttlequeuedepth module parameter */
- if (instance->is_imr) {
- if (throttlequeuedepth > (instance->max_fw_cmds -
- MEGASAS_SKINNY_INT_CMDS))
- instance->throttlequeuedepth =
- MEGASAS_THROTTLE_QUEUE_DEPTH;
- else
- instance->throttlequeuedepth = throttlequeuedepth;
+ /*
+ * 1. For fusion adapters, 3 commands for IOCTL and 5 commands
+ * for driver's internal DCMDs.
+ * 2. For MFI skinny adapters, 5 commands for IOCTL + driver's
+ * internal DCMDs.
+ * 3. For rest of MFI adapters, 27 commands reserved for IOCTLs
+ * and 5 commands for drivers's internal DCMD.
+ */
+ if (instance->ctrl_context) {
+ instance->max_scsi_cmds = instance->max_fw_cmds -
+ (MEGASAS_FUSION_INTERNAL_CMDS +
+ MEGASAS_FUSION_IOCTL_CMDS);
+ sema_init(&instance->ioctl_sem, MEGASAS_FUSION_IOCTL_CMDS);
+ } else if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ instance->max_scsi_cmds = instance->max_fw_cmds -
+ MEGASAS_SKINNY_INT_CMDS;
+ sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
} else {
- if (throttlequeuedepth > (instance->max_fw_cmds -
- MEGASAS_INT_CMDS))
- instance->throttlequeuedepth =
- MEGASAS_THROTTLE_QUEUE_DEPTH;
- else
- instance->throttlequeuedepth = throttlequeuedepth;
+ instance->max_scsi_cmds = instance->max_fw_cmds -
+ MEGASAS_INT_CMDS;
+ sema_init(&instance->ioctl_sem, (MEGASAS_INT_CMDS - 5));
}
+ /* Check for valid throttlequeuedepth module parameter */
+ if (throttlequeuedepth &&
+ throttlequeuedepth <= instance->max_scsi_cmds)
+ instance->throttlequeuedepth = throttlequeuedepth;
+ else
+ instance->throttlequeuedepth =
+ MEGASAS_THROTTLE_QUEUE_DEPTH;
+
/*
* Setup tasklet for cmd completion
*/
@@ -4947,12 +5007,7 @@ static int megasas_io_attach(struct megasas_instance *instance)
*/
host->irq = instance->pdev->irq;
host->unique_id = instance->unique_id;
- if (instance->is_imr) {
- host->can_queue =
- instance->max_fw_cmds - MEGASAS_SKINNY_INT_CMDS;
- } else
- host->can_queue =
- instance->max_fw_cmds - MEGASAS_INT_CMDS;
+ host->can_queue = instance->max_scsi_cmds;
host->this_id = instance->init_id;
host->sg_tablesize = instance->max_num_sge;
@@ -5130,8 +5185,6 @@ static int megasas_probe_one(struct pci_dev *pdev,
((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,
- sizeof(struct LD_LOAD_BALANCE_INFO) * MAX_LOGICAL_DRIVES_EXT);
}
break;
default: /* For all other supported controllers */
@@ -5215,12 +5268,10 @@ static int megasas_probe_one(struct pci_dev *pdev,
instance->init_id = MEGASAS_DEFAULT_INIT_ID;
instance->ctrl_info = NULL;
+
if ((instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0073SKINNY) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY)) {
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_SAS0071SKINNY))
instance->flag_ieee = 1;
- sema_init(&instance->ioctl_sem, MEGASAS_SKINNY_INT_CMDS);
- } else
- sema_init(&instance->ioctl_sem, (MEGASAS_INT_CMDS - 5));
megasas_dbg_lvl = 0;
instance->flag = 0;
@@ -6215,9 +6266,6 @@ static int megasas_mgmt_ioctl_fw(struct file *file, unsigned long arg)
goto out_kfree_ioc;
}
- /*
- * We will allow only MEGASAS_INT_CMDS number of parallel ioctl cmds
- */
if (down_interruptible(&instance->ioctl_sem)) {
error = -ERESTARTSYS;
goto out_kfree_ioc;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 460c6a3d4ade..4f72287860ee 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -172,6 +172,7 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
struct MR_FW_RAID_MAP_ALL *fw_map_old = NULL;
struct MR_FW_RAID_MAP *pFwRaidMap = NULL;
int i;
+ u16 ld_count;
struct MR_DRV_RAID_MAP_ALL *drv_map =
@@ -191,9 +192,10 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
fw_map_old = (struct MR_FW_RAID_MAP_ALL *)
fusion->ld_map[(instance->map_id & 1)];
pFwRaidMap = &fw_map_old->raidMap;
+ ld_count = (u16)le32_to_cpu(pFwRaidMap->ldCount);
#if VD_EXT_DEBUG
- for (i = 0; i < le16_to_cpu(pFwRaidMap->ldCount); i++) {
+ for (i = 0; i < ld_count; 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,
@@ -205,12 +207,15 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
memset(drv_map, 0, fusion->drv_map_sz);
pDrvRaidMap->totalSize = pFwRaidMap->totalSize;
- pDrvRaidMap->ldCount = (__le16)pFwRaidMap->ldCount;
+ pDrvRaidMap->ldCount = (__le16)cpu_to_le16(ld_count);
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 < le16_to_cpu(pDrvRaidMap->ldCount); i++) {
+ for (i = (MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS);
+ i < MAX_LOGICAL_DRIVES_EXT; i++)
+ pDrvRaidMap->ldTgtIdToLd[i] = 0xff;
+ for (i = 0; i < ld_count; i++) {
pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i];
#if VD_EXT_DEBUG
dev_dbg(&instance->pdev->dev,
@@ -252,7 +257,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
struct LD_LOAD_BALANCE_INFO *lbInfo;
PLD_SPAN_INFO ldSpanInfo;
struct MR_LD_RAID *raid;
- int ldCount, num_lds;
+ u16 ldCount, num_lds;
u16 ld;
u32 expected_size;
@@ -356,7 +361,7 @@ static int getSpanInfo(struct MR_DRV_RAID_MAP_ALL *map,
for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) {
ld = MR_TargetIdToLdGet(ldCount, map);
- if (ld >= MAX_LOGICAL_DRIVES_EXT)
+ if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1))
continue;
raid = MR_LdRaidGet(ld, map);
dev_dbg(&instance->pdev->dev, "LD %x: span_depth=%x\n",
@@ -1157,7 +1162,7 @@ void mr_update_span_set(struct MR_DRV_RAID_MAP_ALL *map,
for (ldCount = 0; ldCount < MAX_LOGICAL_DRIVES_EXT; ldCount++) {
ld = MR_TargetIdToLdGet(ldCount, map);
- if (ld >= MAX_LOGICAL_DRIVES_EXT)
+ if (ld >= (MAX_LOGICAL_DRIVES_EXT - 1))
continue;
raid = MR_LdRaidGet(ld, map);
for (element = 0; element < MAX_QUAD_DEPTH; element++) {
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index 71557f64bb5e..675b5e7aba94 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -63,7 +63,6 @@ extern struct megasas_cmd *megasas_get_cmd(struct megasas_instance
extern void
megasas_complete_cmd(struct megasas_instance *instance,
struct megasas_cmd *cmd, u8 alt_status);
-int megasas_is_ldio(struct scsi_cmnd *cmd);
int
wait_and_poll(struct megasas_instance *instance, struct megasas_cmd *cmd,
int seconds);
@@ -103,6 +102,8 @@ megasas_enable_intr_fusion(struct megasas_instance *instance)
{
struct megasas_register_set __iomem *regs;
regs = instance->reg_set;
+
+ instance->mask_interrupts = 0;
/* For Thunderbolt/Invader also clear intr on enable */
writel(~0, &regs->outbound_intr_status);
readl(&regs->outbound_intr_status);
@@ -111,7 +112,6 @@ megasas_enable_intr_fusion(struct megasas_instance *instance)
/* Dummy readl to force pci flush */
readl(&regs->outbound_intr_mask);
- instance->mask_interrupts = 0;
}
/**
@@ -196,6 +196,7 @@ inline void megasas_return_cmd_fusion(struct megasas_instance *instance,
cmd->scmd = NULL;
cmd->sync_cmd_idx = (u32)ULONG_MAX;
+ memset(cmd->io_request, 0, sizeof(struct MPI2_RAID_SCSI_IO_REQUEST));
list_add(&cmd->list, (&fusion->cmd_pool)->next);
spin_unlock_irqrestore(&fusion->mpt_pool_lock, flags);
@@ -689,6 +690,8 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
= 1;
init_frame->driver_operations.mfi_capabilities.support_ndrive_r1_lb
= 1;
+ init_frame->driver_operations.mfi_capabilities.security_protocol_cmds_fw
+ = 1;
/* Convert capability to LE32 */
cpu_to_le32s((u32 *)&init_frame->driver_operations.mfi_capabilities);
@@ -698,12 +701,11 @@ megasas_ioc_init_fusion(struct megasas_instance *instance)
cpu_to_le32(lower_32_bits(ioc_init_handle));
init_frame->data_xfer_len = cpu_to_le32(sizeof(struct MPI2_IOC_INIT_REQUEST));
- req_desc.Words = 0;
+ req_desc.u.low = cpu_to_le32(lower_32_bits(cmd->frame_phys_addr));
+ req_desc.u.high = cpu_to_le32(upper_32_bits(cmd->frame_phys_addr));
req_desc.MFAIo.RequestFlags =
(MEGASAS_REQ_DESCRIPT_FLAGS_MFA <<
- MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- cpu_to_le32s((u32 *)&req_desc.MFAIo);
- req_desc.Words |= cpu_to_le64(cmd->frame_phys_addr);
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
/*
* disable the intr before firing the init frame
@@ -1017,8 +1019,12 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
* does not exceed max cmds that the FW can support
*/
instance->max_fw_cmds = instance->max_fw_cmds-1;
- /* Only internal cmds (DCMD) need to have MFI frames */
- instance->max_mfi_cmds = MEGASAS_INT_CMDS;
+
+ /*
+ * Only Driver's internal DCMDs and IOCTL DCMDs needs to have MFI frames
+ */
+ instance->max_mfi_cmds =
+ MEGASAS_FUSION_INTERNAL_CMDS + MEGASAS_FUSION_IOCTL_CMDS;
max_cmd = instance->max_fw_cmds;
@@ -1285,6 +1291,7 @@ megasas_make_sgl_fusion(struct megasas_instance *instance,
sgl_ptr =
(struct MPI25_IEEE_SGE_CHAIN64 *)cmd->sg_frame;
+ memset(sgl_ptr, 0, MEGASAS_MAX_SZ_CHAIN_FRAME);
}
}
@@ -1658,6 +1665,8 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
u32 device_id;
struct MPI2_RAID_SCSI_IO_REQUEST *io_request;
u16 pd_index = 0;
+ u16 os_timeout_value;
+ u16 timeout_limit;
struct MR_DRV_RAID_MAP_ALL *local_map_ptr;
struct fusion_context *fusion = instance->ctrl_context;
u8 span, physArm;
@@ -1674,52 +1683,66 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
io_request->DataLength = cpu_to_le32(scsi_bufflen(scmd));
-
- /* Check if this is a system PD I/O */
if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS &&
instance->pd_list[pd_index].driveState == MR_PD_STATE_SYSTEM) {
- io_request->Function = 0;
if (fusion->fast_path_io)
io_request->DevHandle =
local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
- io_request->RaidContext.timeoutValue =
- local_map_ptr->raidMap.fpPdIoTimeoutSec;
- io_request->RaidContext.regLockFlags = 0;
- io_request->RaidContext.regLockRowLBA = 0;
- io_request->RaidContext.regLockLength = 0;
io_request->RaidContext.RAIDFlags =
- MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD <<
- MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
- if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
- (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
- io_request->IoFlags |= cpu_to_le16(
- MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
- cmd->request_desc->SCSIIO.RequestFlags =
- (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
- MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
- cmd->request_desc->SCSIIO.DevHandle =
- local_map_ptr->raidMap.devHndlInfo[device_id].curDevHdl;
+ MR_RAID_FLAGS_IO_SUB_TYPE_SYSTEM_PD
+ << MR_RAID_CTX_RAID_FLAGS_IO_SUB_TYPE_SHIFT;
+ cmd->request_desc->SCSIIO.DevHandle = io_request->DevHandle;
cmd->request_desc->SCSIIO.MSIxIndex =
instance->msix_vectors ? smp_processor_id() % instance->msix_vectors : 0;
- /*
- * If the command is for the tape device, set the
- * FP timeout to the os layer timeout value.
- */
- if (scmd->device->type == TYPE_TAPE) {
- if ((scmd->request->timeout / HZ) > 0xFFFF)
- io_request->RaidContext.timeoutValue =
- 0xFFFF;
- else
- io_request->RaidContext.timeoutValue =
- scmd->request->timeout / HZ;
+ os_timeout_value = scmd->request->timeout / HZ;
+
+ if (instance->secure_jbod_support &&
+ (megasas_cmd_type(scmd) == NON_READ_WRITE_SYSPDIO)) {
+ /* system pd firmware path */
+ io_request->Function =
+ MEGASAS_MPI2_FUNCTION_LD_IO_REQUEST;
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_SCSI_IO <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
+ io_request->RaidContext.timeoutValue =
+ cpu_to_le16(os_timeout_value);
+ } else {
+ /* system pd Fast Path */
+ io_request->Function = MPI2_FUNCTION_SCSI_IO_REQUEST;
+ io_request->RaidContext.regLockFlags = 0;
+ io_request->RaidContext.regLockRowLBA = 0;
+ io_request->RaidContext.regLockLength = 0;
+ timeout_limit = (scmd->device->type == TYPE_DISK) ?
+ 255 : 0xFFFF;
+ io_request->RaidContext.timeoutValue =
+ cpu_to_le16((os_timeout_value > timeout_limit) ?
+ timeout_limit : os_timeout_value);
+ if ((instance->pdev->device == PCI_DEVICE_ID_LSI_INVADER) ||
+ (instance->pdev->device == PCI_DEVICE_ID_LSI_FURY))
+ io_request->IoFlags |=
+ cpu_to_le16(MPI25_SAS_DEVICE0_FLAGS_ENABLED_FAST_PATH);
+
+ cmd->request_desc->SCSIIO.RequestFlags =
+ (MPI2_REQ_DESCRIPT_FLAGS_HIGH_PRIORITY <<
+ MEGASAS_REQ_DESCRIPT_FLAGS_TYPE_SHIFT);
}
} else {
if (scmd->device->channel < MEGASAS_MAX_PD_CHANNELS)
goto NonFastPath;
+ /*
+ * For older firmware, Driver should not access ldTgtIdToLd
+ * beyond index 127 and for Extended VD firmware, ldTgtIdToLd
+ * should not go beyond 255.
+ */
+
+ if ((!fusion->fast_path_io) ||
+ (device_id >= instance->fw_supported_vd_count))
+ goto NonFastPath;
+
ld = MR_TargetIdToLdGet(device_id, local_map_ptr);
- if ((ld >= instance->fw_supported_vd_count) ||
- (!fusion->fast_path_io))
+
+ if (ld >= instance->fw_supported_vd_count)
goto NonFastPath;
raid = MR_LdRaidGet(ld, local_map_ptr);
@@ -1811,7 +1834,7 @@ megasas_build_io_fusion(struct megasas_instance *instance,
*/
io_request->IoFlags = cpu_to_le16(scp->cmd_len);
- if (megasas_is_ldio(scp))
+ if (megasas_cmd_type(scp) == READ_WRITE_LDIO)
megasas_build_ldio_fusion(instance, scp, cmd);
else
megasas_build_dcdb_fusion(instance, scp, cmd);
@@ -2612,7 +2635,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
instance->host->host_no);
megaraid_sas_kill_hba(instance);
instance->skip_heartbeat_timer_del = 1;
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
goto out;
}
@@ -2808,8 +2830,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
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;
}
@@ -2858,7 +2878,6 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
"adapter scsi%d.\n", instance->host->host_no);
megaraid_sas_kill_hba(instance);
instance->skip_heartbeat_timer_del = 1;
- instance->adprecovery = MEGASAS_HW_CRITICAL_ERROR;
retval = FAILED;
} else {
/* For VF: Restart HB timer if we didn't OCR */
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 5ab7daee11be..56e6db2d5874 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -306,14 +306,9 @@ struct MPI2_RAID_SCSI_IO_REQUEST {
* MPT RAID MFA IO Descriptor.
*/
struct MEGASAS_RAID_MFA_IO_REQUEST_DESCRIPTOR {
-#if defined(__BIG_ENDIAN_BITFIELD)
- u32 MessageAddress1:24; /* bits 31:8*/
- u32 RequestFlags:8;
-#else
u32 RequestFlags:8;
- u32 MessageAddress1:24; /* bits 31:8*/
-#endif
- u32 MessageAddress2; /* bits 61:32 */
+ u32 MessageAddress1:24;
+ u32 MessageAddress2;
};
/* Default Request Descriptor */
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2.h b/drivers/scsi/mpt2sas/mpi/mpi2.h
index 088eefa67da8..7fc6f23bd9dc 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2.h
@@ -8,7 +8,7 @@
* scatter/gather formats.
* Creation Date: June 21, 2006
*
- * mpi2.h Version: 02.00.32
+ * mpi2.h Version: 02.00.35
*
* Version History
* ---------------
@@ -83,6 +83,9 @@
* 04-09-13 02.00.30 Bumped MPI2_HEADER_VERSION_UNIT.
* 04-17-13 02.00.31 Bumped MPI2_HEADER_VERSION_UNIT.
* 08-19-13 02.00.32 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 12-05-13 02.00.33 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 01-08-14 02.00.34 Bumped MPI2_HEADER_VERSION_UNIT.
+ * 06-13-14 02.00.35 Bumped MPI2_HEADER_VERSION_UNIT.
* --------------------------------------------------------------------------
*/
@@ -108,7 +111,7 @@
#define MPI2_VERSION_02_00 (0x0200)
/* versioning for this MPI header set */
-#define MPI2_HEADER_VERSION_UNIT (0x20)
+#define MPI2_HEADER_VERSION_UNIT (0x23)
#define MPI2_HEADER_VERSION_DEV (0x00)
#define MPI2_HEADER_VERSION_UNIT_MASK (0xFF00)
#define MPI2_HEADER_VERSION_UNIT_SHIFT (8)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
index 510ef0dc8d7b..ee8d2d695d55 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_cnfg.h
@@ -6,7 +6,7 @@
* Title: MPI Configuration messages and pages
* Creation Date: November 10, 2006
*
- * mpi2_cnfg.h Version: 02.00.26
+ * mpi2_cnfg.h Version: 02.00.29
*
* Version History
* ---------------
@@ -157,6 +157,20 @@
* 04-09-13 02.00.25 Added MPI2_IOUNITPAGE1_ATA_SECURITY_FREEZE_LOCK.
* Fixed MPI2_IOUNITPAGE5_DMA_CAP_MASK_MAX_REQUESTS to
* match the specification.
+ * 12-05-13 02.00.27 Added MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL for
+ * MPI2_CONFIG_PAGE_MAN_7.
+ * Added EnclosureLevel and ConnectorName fields to
+ * MPI2_CONFIG_PAGE_SAS_DEV_0.
+ * Added MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID for
+ * MPI2_CONFIG_PAGE_SAS_DEV_0.
+ * Added EnclosureLevel field to
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * Added MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID for
+ * MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0.
+ * 01-08-14 02.00.28 Added more defines for the BiosOptions field of
+ * MPI2_CONFIG_PAGE_BIOS_1.
+ * 06-13-14 02.00.29 Added SSUTimeout field to MPI2_CONFIG_PAGE_BIOS_1, and
+ * more defines for the BiosOptions field.
* --------------------------------------------------------------------------
*/
@@ -706,6 +720,7 @@ typedef struct _MPI2_CONFIG_PAGE_MAN_7
#define MPI2_MANUFACTURING7_PAGEVERSION (0x01)
/* defines for the Flags field */
+#define MPI2_MANPAGE7_FLAG_BASE_ENCLOSURE_LEVEL (0x00000008)
#define MPI2_MANPAGE7_FLAG_EVENTREPLAY_SLOT_ORDER (0x00000002)
#define MPI2_MANPAGE7_FLAG_USE_SLOT_INFO (0x00000001)
@@ -1224,7 +1239,9 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1
MPI2_CONFIG_PAGE_HEADER Header; /* 0x00 */
U32 BiosOptions; /* 0x04 */
U32 IOCSettings; /* 0x08 */
- U32 Reserved1; /* 0x0C */
+ U8 SSUTimeout; /* 0x0C */
+ U8 Reserved1; /* 0x0D */
+ U16 Reserved2; /* 0x0E */
U32 DeviceSettings; /* 0x10 */
U16 NumberOfDevices; /* 0x14 */
U16 UEFIVersion; /* 0x16 */
@@ -1235,9 +1252,24 @@ typedef struct _MPI2_CONFIG_PAGE_BIOS_1
} MPI2_CONFIG_PAGE_BIOS_1, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_BIOS_1,
Mpi2BiosPage1_t, MPI2_POINTER pMpi2BiosPage1_t;
-#define MPI2_BIOSPAGE1_PAGEVERSION (0x05)
+#define MPI2_BIOSPAGE1_PAGEVERSION (0x07)
/* values for BIOS Page 1 BiosOptions field */
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_MASK (0x00003800)
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_PBDHL (0x00000000)
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_ENCSLOSURE (0x00000800)
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_LWWID (0x00001000)
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_PSENS (0x00001800)
+#define MPI2_BIOSPAGE1_OPTIONS_PNS_ESPHY (0x00002000)
+
+#define MPI2_BIOSPAGE1_OPTIONS_X86_DISABLE_BIOS (0x00000400)
+
+#define MPI2_BIOSPAGE1_OPTIONS_MASK_REGISTRATION_UEFI_BSD (0x00000300)
+#define MPI2_BIOSPAGE1_OPTIONS_USE_BIT0_REGISTRATION_UEFI_BSD (0x00000000)
+#define MPI2_BIOSPAGE1_OPTIONS_FULL_REGISTRATION_UEFI_BSD (0x00000100)
+#define MPI2_BIOSPAGE1_OPTIONS_ADAPTER_REGISTRATION_UEFI_BSD (0x00000200)
+#define MPI2_BIOSPAGE1_OPTIONS_DISABLE_REGISTRATION_UEFI_BSD (0x00000300)
+
#define MPI2_BIOSPAGE1_OPTIONS_MASK_OEM_ID (0x000000F0)
#define MPI2_BIOSPAGE1_OPTIONS_LSI_OEM_ID (0x00000000)
@@ -2420,13 +2452,13 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
U8 PortGroups; /* 0x2C */
U8 DmaGroup; /* 0x2D */
U8 ControlGroup; /* 0x2E */
- U8 Reserved1; /* 0x2F */
- U32 Reserved2; /* 0x30 */
+ U8 EnclosureLevel; /* 0x2F */
+ U8 ConnectorName[4]; /* 0x30 */
U32 Reserved3; /* 0x34 */
} MPI2_CONFIG_PAGE_SAS_DEV_0, MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_DEV_0,
Mpi2SasDevicePage0_t, MPI2_POINTER pMpi2SasDevicePage0_t;
-#define MPI2_SASDEVICE0_PAGEVERSION (0x08)
+#define MPI2_SASDEVICE0_PAGEVERSION (0x09)
/* values for SAS Device Page 0 AccessStatus field */
#define MPI2_SAS_DEVICE0_ASTATUS_NO_ERRORS (0x00)
@@ -2464,6 +2496,7 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_DEV_0
#define MPI2_SAS_DEVICE0_FLAGS_SATA_NCQ_SUPPORTED (0x0020)
#define MPI2_SAS_DEVICE0_FLAGS_SATA_FUA_SUPPORTED (0x0010)
#define MPI2_SAS_DEVICE0_FLAGS_PORT_SELECTOR_ATTACH (0x0008)
+#define MPI2_SAS_DEVICE0_FLAGS_ENCL_LEVEL_VALID (0x0002)
#define MPI2_SAS_DEVICE0_FLAGS_DEVICE_PRESENT (0x0001)
@@ -2732,7 +2765,8 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
U16 EnclosureHandle; /* 0x16 */
U16 NumSlots; /* 0x18 */
U16 StartSlot; /* 0x1A */
- U16 Reserved2; /* 0x1C */
+ U8 Reserved2; /* 0x1C */
+ U8 EnclosureLevel; /* 0x1D */
U16 SEPDevHandle; /* 0x1E */
U32 Reserved3; /* 0x20 */
U32 Reserved4; /* 0x24 */
@@ -2740,9 +2774,10 @@ typedef struct _MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0
MPI2_POINTER PTR_MPI2_CONFIG_PAGE_SAS_ENCLOSURE_0,
Mpi2SasEnclosurePage0_t, MPI2_POINTER pMpi2SasEnclosurePage0_t;
-#define MPI2_SASENCLOSURE0_PAGEVERSION (0x03)
+#define MPI2_SASENCLOSURE0_PAGEVERSION (0x04)
/* values for SAS Enclosure Page 0 Flags field */
+#define MPI2_SAS_ENCLS0_FLAGS_ENCL_LEVEL_VALID (0x0010)
#define MPI2_SAS_ENCLS0_FLAGS_MNG_MASK (0x000F)
#define MPI2_SAS_ENCLS0_FLAGS_MNG_UNKNOWN (0x0000)
#define MPI2_SAS_ENCLS0_FLAGS_MNG_IOC_SES (0x0001)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
index 2c3b0f28576b..b02de48be204 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_ioc.h
@@ -6,7 +6,7 @@
* Title: MPI IOC, Port, Event, FW Download, and FW Upload messages
* Creation Date: October 11, 2006
*
- * mpi2_ioc.h Version: 02.00.23
+ * mpi2_ioc.h Version: 02.00.24
*
* Version History
* ---------------
@@ -126,6 +126,7 @@
* Added MPI2_IOCFACTS_CAPABILITY_RDPQ_ARRAY_CAPABLE.
* Added MPI2_FW_DOWNLOAD_ITYPE_PUBLIC_KEY.
* Added Encrypted Hash Extended Image.
+ * 12-05-13 02.00.24 Added MPI25_HASH_IMAGE_TYPE_BIOS.
* --------------------------------------------------------------------------
*/
@@ -1589,6 +1590,7 @@ Mpi25EncryptedHashEntry_t, MPI2_POINTER pMpi25EncryptedHashEntry_t;
/* values for HashImageType */
#define MPI25_HASH_IMAGE_TYPE_UNUSED (0x00)
#define MPI25_HASH_IMAGE_TYPE_FIRMWARE (0x01)
+#define MPI25_HASH_IMAGE_TYPE_BIOS (0x02)
/* values for HashAlgorithm */
#define MPI25_HASH_ALGORITHM_UNUSED (0x00)
diff --git a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
index 9be03ed46180..659b8ac83ceb 100644
--- a/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
+++ b/drivers/scsi/mpt2sas/mpi/mpi2_tool.h
@@ -6,7 +6,7 @@
* Title: MPI diagnostic tool structures and definitions
* Creation Date: March 26, 2007
*
- * mpi2_tool.h Version: 02.00.11
+ * mpi2_tool.h Version: 02.00.12
*
* Version History
* ---------------
@@ -29,7 +29,8 @@
* MPI2_TOOLBOX_ISTWI_READ_WRITE_REQUEST.
* 07-26-12 02.00.10 Modified MPI2_TOOLBOX_DIAGNOSTIC_CLI_REQUEST so that
* it uses MPI Chain SGE as well as MPI Simple SGE.
- * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
+ * 08-19-13 02.00.11 Added MPI2_TOOLBOX_TEXT_DISPLAY_TOOL and related info.
+ * 01-08-14 02.00.12 Added MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC.
* --------------------------------------------------------------------------
*/
@@ -101,6 +102,7 @@ typedef struct _MPI2_TOOLBOX_CLEAN_REQUEST
#define MPI2_TOOLBOX_CLEAN_OTHER_PERSIST_PAGES (0x20000000)
#define MPI2_TOOLBOX_CLEAN_FW_CURRENT (0x10000000)
#define MPI2_TOOLBOX_CLEAN_FW_BACKUP (0x08000000)
+#define MPI2_TOOLBOX_CLEAN_BIT26_PRODUCT_SPECIFIC (0x04000000)
#define MPI2_TOOLBOX_CLEAN_MEGARAID (0x02000000)
#define MPI2_TOOLBOX_CLEAN_INITIALIZATION (0x01000000)
#define MPI2_TOOLBOX_CLEAN_FLASH (0x00000004)
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.c b/drivers/scsi/mpt2sas/mpt2sas_base.c
index 58e45216d1ec..11248de92b3b 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.c
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -639,6 +640,9 @@ _base_display_event_data(struct MPT2SAS_ADAPTER *ioc,
if (!ioc->hide_ir_msg)
desc = "Log Entry Added";
break;
+ case MPI2_EVENT_TEMP_THRESHOLD:
+ desc = "Temperature Threshold";
+ break;
}
if (!desc)
@@ -1296,6 +1300,8 @@ _base_free_irq(struct MPT2SAS_ADAPTER *ioc)
list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
list_del(&reply_q->list);
+ irq_set_affinity_hint(reply_q->vector, NULL);
+ free_cpumask_var(reply_q->affinity_hint);
synchronize_irq(reply_q->vector);
free_irq(reply_q->vector, reply_q);
kfree(reply_q);
@@ -1325,6 +1331,11 @@ _base_request_irq(struct MPT2SAS_ADAPTER *ioc, u8 index, u32 vector)
reply_q->ioc = ioc;
reply_q->msix_index = index;
reply_q->vector = vector;
+
+ if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
+ return -ENOMEM;
+ cpumask_clear(reply_q->affinity_hint);
+
atomic_set(&reply_q->busy, 0);
if (ioc->msix_enable)
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
@@ -1359,6 +1370,7 @@ static void
_base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc)
{
unsigned int cpu, nr_cpus, nr_msix, index = 0;
+ struct adapter_reply_queue *reply_q;
if (!_base_is_controller_msix_enabled(ioc))
return;
@@ -1373,20 +1385,30 @@ _base_assign_reply_queues(struct MPT2SAS_ADAPTER *ioc)
cpu = cpumask_first(cpu_online_mask);
- do {
+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+
unsigned int i, group = nr_cpus / nr_msix;
+ if (cpu >= nr_cpus)
+ break;
+
if (index < nr_cpus % nr_msix)
group++;
for (i = 0 ; i < group ; i++) {
ioc->cpu_msix_table[cpu] = index;
+ cpumask_or(reply_q->affinity_hint,
+ reply_q->affinity_hint, get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
+ if (irq_set_affinity_hint(reply_q->vector,
+ reply_q->affinity_hint))
+ dinitprintk(ioc, pr_info(MPT2SAS_FMT
+ "error setting affinity hint for irq vector %d\n",
+ ioc->name, reply_q->vector));
index++;
-
- } while (cpu < nr_cpus);
+ }
}
/**
@@ -2338,6 +2360,7 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
mpt2sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
mpt2sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
mpt2sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+ mpt2sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
_base_display_ioc_capabilities(ioc);
/*
@@ -2355,6 +2378,8 @@ _base_static_config_pages(struct MPT2SAS_ADAPTER *ioc)
ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
mpt2sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+ if (ioc->iounit_pg8.NumSensors)
+ ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
}
/**
@@ -2486,9 +2511,13 @@ _base_allocate_memory_pools(struct MPT2SAS_ADAPTER *ioc, int sleep_flag)
/* command line tunables for max sgl entries */
if (max_sgl_entries != -1) {
- ioc->shost->sg_tablesize = (max_sgl_entries <
- MPT2SAS_SG_DEPTH) ? max_sgl_entries :
- MPT2SAS_SG_DEPTH;
+ ioc->shost->sg_tablesize = min_t(unsigned short,
+ max_sgl_entries, SCSI_MAX_SG_CHAIN_SEGMENTS);
+ if (ioc->shost->sg_tablesize > MPT2SAS_SG_DEPTH)
+ printk(MPT2SAS_WARN_FMT
+ "sg_tablesize(%u) is bigger than kernel defined"
+ " SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
+ ioc->shost->sg_tablesize, MPT2SAS_SG_DEPTH);
} else {
ioc->shost->sg_tablesize = MPT2SAS_SG_DEPTH;
}
@@ -3236,7 +3265,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
u16 smid;
u32 ioc_state;
unsigned long timeleft;
- u8 issue_reset;
+ bool issue_reset = false;
int rc;
void *request;
u16 wait_state_count;
@@ -3300,7 +3329,7 @@ mpt2sas_base_sas_iounit_control(struct MPT2SAS_ADAPTER *ioc,
_debug_dump_mf(mpi_request,
sizeof(Mpi2SasIoUnitControlRequest_t)/4);
if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
+ issue_reset = true;
goto issue_host_reset;
}
if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
@@ -3341,7 +3370,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
u16 smid;
u32 ioc_state;
unsigned long timeleft;
- u8 issue_reset;
+ bool issue_reset = false;
int rc;
void *request;
u16 wait_state_count;
@@ -3398,7 +3427,7 @@ mpt2sas_base_scsi_enclosure_processor(struct MPT2SAS_ADAPTER *ioc,
_debug_dump_mf(mpi_request,
sizeof(Mpi2SepRequest_t)/4);
if (!(ioc->base_cmds.status & MPT2_CMD_RESET))
- issue_reset = 1;
+ issue_reset = true;
goto issue_host_reset;
}
if (ioc->base_cmds.status & MPT2_CMD_REPLY_VALID)
@@ -4594,6 +4623,7 @@ mpt2sas_base_attach(struct MPT2SAS_ADAPTER *ioc)
_base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
+ _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD);
r = _base_make_ioc_operational(ioc, CAN_SLEEP);
if (r)
goto out_free_resources;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h
index 239f169b0673..caff8d10cca4 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_base.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_base.h
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.h
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -67,10 +68,10 @@
/* driver versioning info */
#define MPT2SAS_DRIVER_NAME "mpt2sas"
-#define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
+#define MPT2SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver"
-#define MPT2SAS_DRIVER_VERSION "18.100.00.00"
-#define MPT2SAS_MAJOR_VERSION 18
+#define MPT2SAS_DRIVER_VERSION "20.100.00.00"
+#define MPT2SAS_MAJOR_VERSION 20
#define MPT2SAS_MINOR_VERSION 100
#define MPT2SAS_BUILD_VERSION 00
#define MPT2SAS_RELEASE_VERSION 00
@@ -586,6 +587,7 @@ struct adapter_reply_queue {
Mpi2ReplyDescriptorsUnion_t *reply_post_free;
char name[MPT_NAME_LENGTH];
atomic_t busy;
+ cpumask_var_t affinity_hint;
struct list_head list;
};
@@ -725,6 +727,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
* @ioc_pg8: static ioc page 8
* @iounit_pg0: static iounit page 0
* @iounit_pg1: static iounit page 1
+ * @iounit_pg8: static iounit page 8
* @sas_hba: sas host object
* @sas_expander_list: expander object list
* @sas_node_lock:
@@ -795,6 +798,7 @@ typedef void (*MPT2SAS_FLUSH_RUNNING_CMDS)(struct MPT2SAS_ADAPTER *ioc);
* @reply_post_host_index: head index in the pool where FW completes IO
* @delayed_tr_list: target reset link list
* @delayed_tr_volume_list: volume target reset link list
+ * @@temp_sensors_count: flag to carry the number of temperature sensors
*/
struct MPT2SAS_ADAPTER {
struct list_head list;
@@ -892,6 +896,7 @@ struct MPT2SAS_ADAPTER {
Mpi2IOCPage8_t ioc_pg8;
Mpi2IOUnitPage0_t iounit_pg0;
Mpi2IOUnitPage1_t iounit_pg1;
+ Mpi2IOUnitPage8_t iounit_pg8;
struct _boot_device req_boot_device;
struct _boot_device req_alt_boot_device;
@@ -992,6 +997,7 @@ struct MPT2SAS_ADAPTER {
struct list_head delayed_tr_list;
struct list_head delayed_tr_volume_list;
+ u8 temp_sensors_count;
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -1120,6 +1126,8 @@ int mpt2sas_config_get_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt2sas_config_set_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
+int mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page);
int mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage3_t *config_page, u16 sz);
int mpt2sas_config_get_sas_iounit_pg1(struct MPT2SAS_ADAPTER *ioc, Mpi2ConfigReply_t
diff --git a/drivers/scsi/mpt2sas/mpt2sas_config.c b/drivers/scsi/mpt2sas/mpt2sas_config.c
index c72a2fff5dbb..c43815b1a485 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_config.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_config.c
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_base.c
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -719,6 +720,42 @@ mpt2sas_config_get_iounit_pg3(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * mpt2sas_config_get_iounit_pg8 - obtain iounit page 8
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt2sas_config_get_iounit_pg8(struct MPT2SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+ mpi_request.Header.PageNumber = 8;
+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
+ mpt2sas_base_build_zero_len_sge(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT2_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+ sizeof(*config_page));
+ out:
+ return r;
+}
+
+/**
* mpt2sas_config_get_ioc_pg8 - obtain ioc page 8
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.c b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
index ca4e563c01dd..4e509604b571 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.c
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.c
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt2sas/mpt2sas_ctl.h b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
index 7f842c88abd2..46b2fc5b74af 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_ctl.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_ctl.h
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_ctl.h
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt2sas/mpt2sas_debug.h b/drivers/scsi/mpt2sas/mpt2sas_debug.h
index cc57ef31d0fe..277120d45648 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_debug.h
+++ b/drivers/scsi/mpt2sas/mpt2sas_debug.h
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_debug.c
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index 6a1c036a6f3f..3f26147bbc64 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_scsih.c
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -2729,9 +2730,18 @@ _scsih_host_reset(struct scsi_cmnd *scmd)
ioc->name, scmd);
scsi_print_command(scmd);
+ if (ioc->is_driver_loading) {
+ printk(MPT2SAS_INFO_FMT "Blocking the host reset\n",
+ ioc->name);
+ r = FAILED;
+ goto out;
+ }
+
retval = mpt2sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
r = (retval < 0) ? FAILED : SUCCESS;
+
+ out:
printk(MPT2SAS_INFO_FMT "host reset: %s scmd(%p)\n",
ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
@@ -3647,6 +3657,31 @@ _scsih_check_volume_delete_events(struct MPT2SAS_ADAPTER *ioc,
}
/**
+ * _scsih_temp_threshold_events - display temperature threshold exceeded events
+ * @ioc: per adapter object
+ * @event_data: the temp threshold event data
+ * Context: interrupt time.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_temp_threshold_events(struct MPT2SAS_ADAPTER *ioc,
+ Mpi2EventDataTemperature_t *event_data)
+{
+ if (ioc->temp_sensors_count >= event_data->SensorNum) {
+ printk(MPT2SAS_ERR_FMT "Temperature Threshold flags %s%s%s%s"
+ " exceeded for Sensor: %d !!!\n", ioc->name,
+ ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ",
+ ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ",
+ ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ",
+ ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ",
+ event_data->SensorNum);
+ printk(MPT2SAS_ERR_FMT "Current Temp In Celsius: %d\n",
+ ioc->name, event_data->CurrentTemperature);
+ }
+}
+
+/**
* _scsih_flush_running_cmds - completing outstanding commands.
* @ioc: per adapter object
*
@@ -4509,6 +4544,10 @@ _scsih_io_done(struct MPT2SAS_ADAPTER *ioc, u16 smid, u8 msix_index, u32 reply)
scmd->result = DID_TRANSPORT_DISRUPTED << 16;
goto out;
}
+ if (log_info == 0x32010081) {
+ scmd->result = DID_RESET << 16;
+ break;
+ }
scmd->result = DID_SOFT_ERROR << 16;
break;
case MPI2_IOCSTATUS_SCSI_TASK_TERMINATED:
@@ -7557,6 +7596,12 @@ mpt2sas_scsih_event_callback(struct MPT2SAS_ADAPTER *ioc, u8 msix_index,
case MPI2_EVENT_IR_PHYSICAL_DISK:
break;
+ case MPI2_EVENT_TEMP_THRESHOLD:
+ _scsih_temp_threshold_events(ioc,
+ (Mpi2EventDataTemperature_t *)
+ mpi_reply->EventData);
+ break;
+
default: /* ignore the rest */
return;
}
diff --git a/drivers/scsi/mpt2sas/mpt2sas_transport.c b/drivers/scsi/mpt2sas/mpt2sas_transport.c
index e689bf20a3ea..ff2500ab9ba4 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_transport.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_transport.c
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt2sas/mpt2_transport.c
* Copyright (C) 2007-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 20013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.c b/drivers/scsi/mpt3sas/mpt3sas_base.c
index 1560115079c7..14a781b6b88d 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.c
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -619,6 +620,9 @@ _base_display_event_data(struct MPT3SAS_ADAPTER *ioc,
case MPI2_EVENT_LOG_ENTRY_ADDED:
desc = "Log Entry Added";
break;
+ case MPI2_EVENT_TEMP_THRESHOLD:
+ desc = "Temperature Threshold";
+ break;
}
if (!desc)
@@ -1580,6 +1584,8 @@ _base_free_irq(struct MPT3SAS_ADAPTER *ioc)
list_for_each_entry_safe(reply_q, next, &ioc->reply_queue_list, list) {
list_del(&reply_q->list);
+ irq_set_affinity_hint(reply_q->vector, NULL);
+ free_cpumask_var(reply_q->affinity_hint);
synchronize_irq(reply_q->vector);
free_irq(reply_q->vector, reply_q);
kfree(reply_q);
@@ -1609,6 +1615,11 @@ _base_request_irq(struct MPT3SAS_ADAPTER *ioc, u8 index, u32 vector)
reply_q->ioc = ioc;
reply_q->msix_index = index;
reply_q->vector = vector;
+
+ if (!alloc_cpumask_var(&reply_q->affinity_hint, GFP_KERNEL))
+ return -ENOMEM;
+ cpumask_clear(reply_q->affinity_hint);
+
atomic_set(&reply_q->busy, 0);
if (ioc->msix_enable)
snprintf(reply_q->name, MPT_NAME_LENGTH, "%s%d-msix%d",
@@ -1643,6 +1654,7 @@ static void
_base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
{
unsigned int cpu, nr_cpus, nr_msix, index = 0;
+ struct adapter_reply_queue *reply_q;
if (!_base_is_controller_msix_enabled(ioc))
return;
@@ -1657,20 +1669,30 @@ _base_assign_reply_queues(struct MPT3SAS_ADAPTER *ioc)
cpu = cpumask_first(cpu_online_mask);
- do {
+ list_for_each_entry(reply_q, &ioc->reply_queue_list, list) {
+
unsigned int i, group = nr_cpus / nr_msix;
+ if (cpu >= nr_cpus)
+ break;
+
if (index < nr_cpus % nr_msix)
group++;
for (i = 0 ; i < group ; i++) {
ioc->cpu_msix_table[cpu] = index;
+ cpumask_or(reply_q->affinity_hint,
+ reply_q->affinity_hint, get_cpu_mask(cpu));
cpu = cpumask_next(cpu, cpu_online_mask);
}
+ if (irq_set_affinity_hint(reply_q->vector,
+ reply_q->affinity_hint))
+ dinitprintk(ioc, pr_info(MPT3SAS_FMT
+ "error setting affinity hint for irq vector %d\n",
+ ioc->name, reply_q->vector));
index++;
-
- } while (cpu < nr_cpus);
+ }
}
/**
@@ -2500,6 +2522,7 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
mpt3sas_config_get_ioc_pg8(ioc, &mpi_reply, &ioc->ioc_pg8);
mpt3sas_config_get_iounit_pg0(ioc, &mpi_reply, &ioc->iounit_pg0);
mpt3sas_config_get_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+ mpt3sas_config_get_iounit_pg8(ioc, &mpi_reply, &ioc->iounit_pg8);
_base_display_ioc_capabilities(ioc);
/*
@@ -2516,6 +2539,9 @@ _base_static_config_pages(struct MPT3SAS_ADAPTER *ioc)
MPI2_IOUNITPAGE1_DISABLE_TASK_SET_FULL_HANDLING;
ioc->iounit_pg1.Flags = cpu_to_le32(iounit_pg1_flags);
mpt3sas_config_set_iounit_pg1(ioc, &mpi_reply, &ioc->iounit_pg1);
+
+ if (ioc->iounit_pg8.NumSensors)
+ ioc->temp_sensors_count = ioc->iounit_pg8.NumSensors;
}
/**
@@ -2659,8 +2685,14 @@ _base_allocate_memory_pools(struct MPT3SAS_ADAPTER *ioc, int sleep_flag)
if (sg_tablesize < MPT3SAS_MIN_PHYS_SEGMENTS)
sg_tablesize = MPT3SAS_MIN_PHYS_SEGMENTS;
- else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS)
- sg_tablesize = MPT3SAS_MAX_PHYS_SEGMENTS;
+ else if (sg_tablesize > MPT3SAS_MAX_PHYS_SEGMENTS) {
+ sg_tablesize = min_t(unsigned short, sg_tablesize,
+ SCSI_MAX_SG_CHAIN_SEGMENTS);
+ pr_warn(MPT3SAS_FMT
+ "sg_tablesize(%u) is bigger than kernel"
+ " defined SCSI_MAX_SG_SEGMENTS(%u)\n", ioc->name,
+ sg_tablesize, MPT3SAS_MAX_PHYS_SEGMENTS);
+ }
ioc->shost->sg_tablesize = sg_tablesize;
ioc->hi_priority_depth = facts->HighPriorityCredit;
@@ -3419,7 +3451,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
u16 smid;
u32 ioc_state;
unsigned long timeleft;
- u8 issue_reset;
+ bool issue_reset = false;
int rc;
void *request;
u16 wait_state_count;
@@ -3483,7 +3515,7 @@ mpt3sas_base_sas_iounit_control(struct MPT3SAS_ADAPTER *ioc,
_debug_dump_mf(mpi_request,
sizeof(Mpi2SasIoUnitControlRequest_t)/4);
if (!(ioc->base_cmds.status & MPT3_CMD_RESET))
- issue_reset = 1;
+ issue_reset = true;
goto issue_host_reset;
}
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
@@ -3523,7 +3555,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
u16 smid;
u32 ioc_state;
unsigned long timeleft;
- u8 issue_reset;
+ bool issue_reset = false;
int rc;
void *request;
u16 wait_state_count;
@@ -3581,7 +3613,7 @@ mpt3sas_base_scsi_enclosure_processor(struct MPT3SAS_ADAPTER *ioc,
_debug_dump_mf(mpi_request,
sizeof(Mpi2SepRequest_t)/4);
if (!(ioc->base_cmds.status & MPT3_CMD_RESET))
- issue_reset = 1;
+ issue_reset = false;
goto issue_host_reset;
}
if (ioc->base_cmds.status & MPT3_CMD_REPLY_VALID)
@@ -4720,6 +4752,7 @@ mpt3sas_base_attach(struct MPT3SAS_ADAPTER *ioc)
_base_unmask_events(ioc, MPI2_EVENT_IR_PHYSICAL_DISK);
_base_unmask_events(ioc, MPI2_EVENT_IR_OPERATION_STATUS);
_base_unmask_events(ioc, MPI2_EVENT_LOG_ENTRY_ADDED);
+ _base_unmask_events(ioc, MPI2_EVENT_TEMP_THRESHOLD);
r = _base_make_ioc_operational(ioc, CAN_SLEEP);
if (r)
diff --git a/drivers/scsi/mpt3sas/mpt3sas_base.h b/drivers/scsi/mpt3sas/mpt3sas_base.h
index 40926aa9b24d..afa881682bef 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_base.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_base.h
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -68,7 +69,7 @@
/* driver versioning info */
#define MPT3SAS_DRIVER_NAME "mpt3sas"
-#define MPT3SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>"
+#define MPT3SAS_AUTHOR "Avago Technologies <MPT-FusionLinux.pdl@avagotech.com>"
#define MPT3SAS_DESCRIPTION "LSI MPT Fusion SAS 3.0 Device Driver"
#define MPT3SAS_DRIVER_VERSION "04.100.00.00"
#define MPT3SAS_MAJOR_VERSION 4
@@ -506,6 +507,7 @@ struct adapter_reply_queue {
Mpi2ReplyDescriptorsUnion_t *reply_post_free;
char name[MPT_NAME_LENGTH];
atomic_t busy;
+ cpumask_var_t affinity_hint;
struct list_head list;
};
@@ -659,6 +661,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @ioc_pg8: static ioc page 8
* @iounit_pg0: static iounit page 0
* @iounit_pg1: static iounit page 1
+ * @iounit_pg8: static iounit page 8
* @sas_hba: sas host object
* @sas_expander_list: expander object list
* @sas_node_lock:
@@ -728,6 +731,7 @@ typedef void (*MPT3SAS_FLUSH_RUNNING_CMDS)(struct MPT3SAS_ADAPTER *ioc);
* @reply_post_host_index: head index in the pool where FW completes IO
* @delayed_tr_list: target reset link list
* @delayed_tr_volume_list: volume target reset link list
+ * @@temp_sensors_count: flag to carry the number of temperature sensors
*/
struct MPT3SAS_ADAPTER {
struct list_head list;
@@ -834,6 +838,7 @@ struct MPT3SAS_ADAPTER {
Mpi2IOCPage8_t ioc_pg8;
Mpi2IOUnitPage0_t iounit_pg0;
Mpi2IOUnitPage1_t iounit_pg1;
+ Mpi2IOUnitPage8_t iounit_pg8;
struct _boot_device req_boot_device;
struct _boot_device req_alt_boot_device;
@@ -934,6 +939,7 @@ struct MPT3SAS_ADAPTER {
struct list_head delayed_tr_list;
struct list_head delayed_tr_volume_list;
+ u8 temp_sensors_count;
/* diag buffer support */
u8 *diag_buffer[MPI2_DIAG_BUF_TYPE_COUNT];
@@ -1082,6 +1088,8 @@ int mpt3sas_config_get_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
int mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
*mpi_reply, Mpi2IOUnitPage1_t *config_page);
+int mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc, Mpi2ConfigReply_t
+ *mpi_reply, Mpi2IOUnitPage8_t *config_page);
int mpt3sas_config_get_sas_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
Mpi2ConfigReply_t *mpi_reply, Mpi2SasIOUnitPage1_t *config_page,
u16 sz);
diff --git a/drivers/scsi/mpt3sas/mpt3sas_config.c b/drivers/scsi/mpt3sas/mpt3sas_config.c
index 4472c2af9255..e45c4613ef0c 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_config.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_config.c
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -871,6 +872,42 @@ mpt3sas_config_set_iounit_pg1(struct MPT3SAS_ADAPTER *ioc,
}
/**
+ * mpt3sas_config_get_iounit_pg8 - obtain iounit page 8
+ * @ioc: per adapter object
+ * @mpi_reply: reply mf payload returned from firmware
+ * @config_page: contents of the config page
+ * Context: sleep.
+ *
+ * Returns 0 for success, non-zero for failure.
+ */
+int
+mpt3sas_config_get_iounit_pg8(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2ConfigReply_t *mpi_reply, Mpi2IOUnitPage8_t *config_page)
+{
+ Mpi2ConfigRequest_t mpi_request;
+ int r;
+
+ memset(&mpi_request, 0, sizeof(Mpi2ConfigRequest_t));
+ mpi_request.Function = MPI2_FUNCTION_CONFIG;
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_HEADER;
+ mpi_request.Header.PageType = MPI2_CONFIG_PAGETYPE_IO_UNIT;
+ mpi_request.Header.PageNumber = 8;
+ mpi_request.Header.PageVersion = MPI2_IOUNITPAGE8_PAGEVERSION;
+ ioc->build_zero_len_sge_mpi(ioc, &mpi_request.PageBufferSGE);
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, NULL, 0);
+ if (r)
+ goto out;
+
+ mpi_request.Action = MPI2_CONFIG_ACTION_PAGE_READ_CURRENT;
+ r = _config_request(ioc, &mpi_request, mpi_reply,
+ MPT3_CONFIG_PAGE_DEFAULT_TIMEOUT, config_page,
+ sizeof(*config_page));
+ out:
+ return r;
+}
+
+/**
* mpt3sas_config_get_ioc_pg8 - obtain ioc page 8
* @ioc: per adapter object
* @mpi_reply: reply mf payload returned from firmware
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.c b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
index dca14877d5ab..080c8a76d23d 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.c
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt3sas/mpt3sas_ctl.h b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
index 5f3d7fd7c2f8..aee99ce67e54 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_ctl.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_ctl.h
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_ctl.h
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt3sas/mpt3sas_debug.h b/drivers/scsi/mpt3sas/mpt3sas_debug.h
index 4778e7dd98bd..4e8a63fdb304 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_debug.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_debug.h
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_debug.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 94261ee9e72d..5a97e3286719 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_scsih.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -2392,9 +2393,17 @@ _scsih_host_reset(struct scsi_cmnd *scmd)
ioc->name, scmd);
scsi_print_command(scmd);
+ if (ioc->is_driver_loading) {
+ pr_info(MPT3SAS_FMT "Blocking the host reset\n",
+ ioc->name);
+ r = FAILED;
+ goto out;
+ }
+
retval = mpt3sas_base_hard_reset_handler(ioc, CAN_SLEEP,
FORCE_BIG_HAMMER);
r = (retval < 0) ? FAILED : SUCCESS;
+out:
pr_info(MPT3SAS_FMT "host reset: %s scmd(%p)\n",
ioc->name, ((r == SUCCESS) ? "SUCCESS" : "FAILED"), scmd);
@@ -3342,6 +3351,31 @@ _scsih_check_volume_delete_events(struct MPT3SAS_ADAPTER *ioc,
}
/**
+ * _scsih_temp_threshold_events - display temperature threshold exceeded events
+ * @ioc: per adapter object
+ * @event_data: the temp threshold event data
+ * Context: interrupt time.
+ *
+ * Return nothing.
+ */
+static void
+_scsih_temp_threshold_events(struct MPT3SAS_ADAPTER *ioc,
+ Mpi2EventDataTemperature_t *event_data)
+{
+ if (ioc->temp_sensors_count >= event_data->SensorNum) {
+ pr_err(MPT3SAS_FMT "Temperature Threshold flags %s%s%s%s"
+ " exceeded for Sensor: %d !!!\n", ioc->name,
+ ((le16_to_cpu(event_data->Status) & 0x1) == 1) ? "0 " : " ",
+ ((le16_to_cpu(event_data->Status) & 0x2) == 2) ? "1 " : " ",
+ ((le16_to_cpu(event_data->Status) & 0x4) == 4) ? "2 " : " ",
+ ((le16_to_cpu(event_data->Status) & 0x8) == 8) ? "3 " : " ",
+ event_data->SensorNum);
+ pr_err(MPT3SAS_FMT "Current Temp In Celsius: %d\n",
+ ioc->name, event_data->CurrentTemperature);
+ }
+}
+
+/**
* _scsih_flush_running_cmds - completing outstanding commands.
* @ioc: per adapter object
*
@@ -7194,6 +7228,12 @@ mpt3sas_scsih_event_callback(struct MPT3SAS_ADAPTER *ioc, u8 msix_index,
case MPI2_EVENT_IR_PHYSICAL_DISK:
break;
+ case MPI2_EVENT_TEMP_THRESHOLD:
+ _scsih_temp_threshold_events(ioc,
+ (Mpi2EventDataTemperature_t *)
+ mpi_reply->EventData);
+ break;
+
default: /* ignore the rest */
return 1;
}
diff --git a/drivers/scsi/mpt3sas/mpt3sas_transport.c b/drivers/scsi/mpt3sas/mpt3sas_transport.c
index 3637ae6c0171..efb98afc46e0 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_transport.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_transport.c
@@ -3,7 +3,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_transport.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
index 8a2dd113f401..b60fd7a3b571 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
@@ -4,7 +4,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_trigger_diag.c
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
index f681db56c53b..6586a463bea9 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
+++ b/drivers/scsi/mpt3sas/mpt3sas_trigger_diag.h
@@ -5,7 +5,8 @@
*
* This code is based on drivers/scsi/mpt3sas/mpt3sas_base.h
* Copyright (C) 2012-2014 LSI Corporation
- * (mailto:DL-MPTFusionLinux@lsi.com)
+ * Copyright (C) 2013-2014 Avago Technologies
+ * (mailto: MPT-FusionLinux.pdl@avagotech.com)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/scsi/nsp32.c b/drivers/scsi/nsp32.c
index 90abb03c9074..c6077cefbeca 100644
--- a/drivers/scsi/nsp32.c
+++ b/drivers/scsi/nsp32.c
@@ -1441,8 +1441,6 @@ static irqreturn_t do_nsp32_isr(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-#undef SPRINTF
-#define SPRINTF(args...) seq_printf(m, ##args)
static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
{
@@ -1458,64 +1456,63 @@ static int nsp32_show_info(struct seq_file *m, struct Scsi_Host *host)
data = (nsp32_hw_data *)host->hostdata;
base = host->io_port;
- SPRINTF("NinjaSCSI-32 status\n\n");
- SPRINTF("Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version);
- SPRINTF("SCSI host No.: %d\n", hostno);
- SPRINTF("IRQ: %d\n", host->irq);
- SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
- SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
- SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
- SPRINTF("Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
+ seq_puts(m, "NinjaSCSI-32 status\n\n");
+ seq_printf(m, "Driver version: %s, $Revision: 1.33 $\n", nsp32_release_version);
+ seq_printf(m, "SCSI host No.: %d\n", hostno);
+ seq_printf(m, "IRQ: %d\n", host->irq);
+ seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+ seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
+ seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize);
+ seq_printf(m, "Chip revision: 0x%x\n", (nsp32_read2(base, INDEX_REG) >> 8) & 0xff);
mode_reg = nsp32_index_read1(base, CHIP_MODE);
model = data->pci_devid->driver_data;
#ifdef CONFIG_PM
- SPRINTF("Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no");
+ seq_printf(m, "Power Management: %s\n", (mode_reg & OPTF) ? "yes" : "no");
#endif
- SPRINTF("OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
+ seq_printf(m, "OEM: %ld, %s\n", (mode_reg & (OEM0|OEM1)), nsp32_model[model]);
spin_lock_irqsave(&(data->Lock), flags);
- SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
+ seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC);
spin_unlock_irqrestore(&(data->Lock), flags);
- SPRINTF("SDTR status\n");
+ seq_puts(m, "SDTR status\n");
for (id = 0; id < ARRAY_SIZE(data->target); id++) {
- SPRINTF("id %d: ", id);
+ seq_printf(m, "id %d: ", id);
if (id == host->this_id) {
- SPRINTF("----- NinjaSCSI-32 host adapter\n");
+ seq_puts(m, "----- NinjaSCSI-32 host adapter\n");
continue;
}
if (data->target[id].sync_flag == SDTR_DONE) {
if (data->target[id].period == 0 &&
data->target[id].offset == ASYNC_OFFSET ) {
- SPRINTF("async");
+ seq_puts(m, "async");
} else {
- SPRINTF(" sync");
+ seq_puts(m, " sync");
}
} else {
- SPRINTF(" none");
+ seq_puts(m, " none");
}
if (data->target[id].period != 0) {
speed = 1000000 / (data->target[id].period * 4);
- SPRINTF(" transfer %d.%dMB/s, offset %d",
+ seq_printf(m, " transfer %d.%dMB/s, offset %d",
speed / 1000,
speed % 1000,
data->target[id].offset
);
}
- SPRINTF("\n");
+ seq_putc(m, '\n');
}
return 0;
}
-#undef SPRINTF
diff --git a/drivers/scsi/pcmcia/nsp_cs.c b/drivers/scsi/pcmcia/nsp_cs.c
index 34aad32829f5..1b6c8833a304 100644
--- a/drivers/scsi/pcmcia/nsp_cs.c
+++ b/drivers/scsi/pcmcia/nsp_cs.c
@@ -1364,9 +1364,6 @@ static const char *nsp_info(struct Scsi_Host *shpnt)
return data->nspinfo;
}
-#undef SPRINTF
-#define SPRINTF(args...) seq_printf(m, ##args)
-
static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
{
int id;
@@ -1378,75 +1375,74 @@ static int nsp_show_info(struct seq_file *m, struct Scsi_Host *host)
hostno = host->host_no;
data = (nsp_hw_data *)host->hostdata;
- SPRINTF("NinjaSCSI status\n\n");
- SPRINTF("Driver version: $Revision: 1.23 $\n");
- SPRINTF("SCSI host No.: %d\n", hostno);
- SPRINTF("IRQ: %d\n", host->irq);
- SPRINTF("IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
- SPRINTF("MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
- SPRINTF("sg_tablesize: %d\n", host->sg_tablesize);
+ seq_puts(m, "NinjaSCSI status\n\n"
+ "Driver version: $Revision: 1.23 $\n");
+ seq_printf(m, "SCSI host No.: %d\n", hostno);
+ seq_printf(m, "IRQ: %d\n", host->irq);
+ seq_printf(m, "IO: 0x%lx-0x%lx\n", host->io_port, host->io_port + host->n_io_port - 1);
+ seq_printf(m, "MMIO(virtual address): 0x%lx-0x%lx\n", host->base, host->base + data->MmioLength - 1);
+ seq_printf(m, "sg_tablesize: %d\n", host->sg_tablesize);
- SPRINTF("burst transfer mode: ");
+ seq_puts(m, "burst transfer mode: ");
switch (nsp_burst_mode) {
case BURST_IO8:
- SPRINTF("io8");
+ seq_puts(m, "io8");
break;
case BURST_IO32:
- SPRINTF("io32");
+ seq_puts(m, "io32");
break;
case BURST_MEM32:
- SPRINTF("mem32");
+ seq_puts(m, "mem32");
break;
default:
- SPRINTF("???");
+ seq_puts(m, "???");
break;
}
- SPRINTF("\n");
+ seq_putc(m, '\n');
spin_lock_irqsave(&(data->Lock), flags);
- SPRINTF("CurrentSC: 0x%p\n\n", data->CurrentSC);
+ seq_printf(m, "CurrentSC: 0x%p\n\n", data->CurrentSC);
spin_unlock_irqrestore(&(data->Lock), flags);
- SPRINTF("SDTR status\n");
+ seq_puts(m, "SDTR status\n");
for(id = 0; id < ARRAY_SIZE(data->Sync); id++) {
- SPRINTF("id %d: ", id);
+ seq_printf(m, "id %d: ", id);
if (id == host->this_id) {
- SPRINTF("----- NinjaSCSI-3 host adapter\n");
+ seq_puts(m, "----- NinjaSCSI-3 host adapter\n");
continue;
}
switch(data->Sync[id].SyncNegotiation) {
case SYNC_OK:
- SPRINTF(" sync");
+ seq_puts(m, " sync");
break;
case SYNC_NG:
- SPRINTF("async");
+ seq_puts(m, "async");
break;
case SYNC_NOT_YET:
- SPRINTF(" none");
+ seq_puts(m, " none");
break;
default:
- SPRINTF("?????");
+ seq_puts(m, "?????");
break;
}
if (data->Sync[id].SyncPeriod != 0) {
speed = 1000000 / (data->Sync[id].SyncPeriod * 4);
- SPRINTF(" transfer %d.%dMB/s, offset %d",
+ seq_printf(m, " transfer %d.%dMB/s, offset %d",
speed / 1000,
speed % 1000,
data->Sync[id].SyncOffset
);
}
- SPRINTF("\n");
+ seq_putc(m, '\n');
}
return 0;
}
-#undef SPRINTF
/*---------------------------------------------------------------*/
/* error handler */
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index 8c27b6a77ec4..ed31d8cc6266 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -1473,13 +1473,7 @@ static int pmcraid_notify_aen(
}
/* send genetlink multicast message to notify appplications */
- result = genlmsg_end(skb, msg_header);
-
- if (result < 0) {
- pmcraid_err("genlmsg_end failed\n");
- nlmsg_free(skb);
- return result;
- }
+ genlmsg_end(skb, msg_header);
result = genlmsg_multicast(&pmcraid_event_family, skb,
0, 0, GFP_ATOMIC);
@@ -4223,7 +4217,7 @@ static ssize_t pmcraid_show_adapter_id(
static struct device_attribute pmcraid_adapter_id_attr = {
.attr = {
.name = "adapter_id",
- .mode = S_IRUGO | S_IWUSR,
+ .mode = S_IRUGO,
},
.show = pmcraid_show_adapter_id,
};
diff --git a/drivers/scsi/qla2xxx/qla_dfs.c b/drivers/scsi/qla2xxx/qla_dfs.c
index 2ca39b8e7166..15cf074ffa3c 100644
--- a/drivers/scsi/qla2xxx/qla_dfs.c
+++ b/drivers/scsi/qla2xxx/qla_dfs.c
@@ -23,10 +23,10 @@ qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
mutex_lock(&ha->fce_mutex);
- seq_printf(s, "FCE Trace Buffer\n");
+ seq_puts(s, "FCE Trace Buffer\n");
seq_printf(s, "In Pointer = %llx\n\n", (unsigned long long)ha->fce_wr);
seq_printf(s, "Base = %llx\n\n", (unsigned long long) ha->fce_dma);
- seq_printf(s, "FCE Enable Registers\n");
+ seq_puts(s, "FCE Enable Registers\n");
seq_printf(s, "%08x %08x %08x %08x %08x %08x\n",
ha->fce_mb[0], ha->fce_mb[2], ha->fce_mb[3], ha->fce_mb[4],
ha->fce_mb[5], ha->fce_mb[6]);
@@ -38,11 +38,11 @@ qla2x00_dfs_fce_show(struct seq_file *s, void *unused)
seq_printf(s, "\n%llx: ",
(unsigned long long)((cnt * 4) + fce_start));
else
- seq_printf(s, " ");
+ seq_putc(s, ' ');
seq_printf(s, "%08x", *fce++);
}
- seq_printf(s, "\nEnd\n");
+ seq_puts(s, "\nEnd\n");
mutex_unlock(&ha->fce_mutex);
diff --git a/drivers/scsi/qla2xxx/tcm_qla2xxx.c b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
index 73f9feecda72..99f43b7fc9ab 100644
--- a/drivers/scsi/qla2xxx/tcm_qla2xxx.c
+++ b/drivers/scsi/qla2xxx/tcm_qla2xxx.c
@@ -1570,9 +1570,7 @@ static int tcm_qla2xxx_check_initiator_node_acl(
* match the format by tcm_qla2xxx explict ConfigFS NodeACLs.
*/
memset(&port_name, 0, 36);
- snprintf(port_name, 36, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
- fc_wwpn[0], fc_wwpn[1], fc_wwpn[2], fc_wwpn[3], fc_wwpn[4],
- fc_wwpn[5], fc_wwpn[6], fc_wwpn[7]);
+ snprintf(port_name, sizeof(port_name), "%8phC", fc_wwpn);
/*
* Locate our struct se_node_acl either from an explict NodeACL created
* via ConfigFS, or via running in TPG demo mode.
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 9b3829931f40..c9c3b579eece 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -531,7 +531,7 @@ void scsi_log_send(struct scsi_cmnd *cmd)
*
* 3: same as 2
*
- * 4: same as 3 plus dump extra junk
+ * 4: same as 3
*/
if (unlikely(scsi_logging_level)) {
level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT,
@@ -540,13 +540,6 @@ void scsi_log_send(struct scsi_cmnd *cmd)
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,"
- " queuecommand 0x%p\n",
- scsi_sglist(cmd), scsi_bufflen(cmd),
- cmd->device->host->hostt->queuecommand);
-
- }
}
}
}
@@ -572,7 +565,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
SCSI_LOG_MLCOMPLETE_BITS);
if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||
(level > 1)) {
- scsi_print_result(cmd, "Done: ", disposition);
+ scsi_print_result(cmd, "Done", disposition);
scsi_print_command(cmd);
if (status_byte(cmd->result) & CHECK_CONDITION)
scsi_print_sense(cmd);
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 4aca1b0378c2..1f8e2dc9c616 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -80,6 +80,8 @@ static const char *scsi_debug_version_date = "20141022";
#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define UA_RESET_ASC 0x29
#define UA_CHANGED_ASC 0x2a
+#define TARGET_CHANGED_ASC 0x3f
+#define LUNS_CHANGED_ASCQ 0x0e
#define INSUFF_RES_ASC 0x55
#define INSUFF_RES_ASCQ 0x3
#define POWER_ON_RESET_ASCQ 0x0
@@ -91,6 +93,8 @@ static const char *scsi_debug_version_date = "20141022";
#define THRESHOLD_EXCEEDED 0x5d
#define LOW_POWER_COND_ON 0x5e
#define MISCOMPARE_VERIFY_ASC 0x1d
+#define MICROCODE_CHANGED_ASCQ 0x1 /* with TARGET_CHANGED_ASC */
+#define MICROCODE_CHANGED_WO_RESET_ASCQ 0x16
/* Additional Sense Code Qualifier (ASCQ) */
#define ACK_NAK_TO 0x3
@@ -180,7 +184,10 @@ static const char *scsi_debug_version_date = "20141022";
#define SDEBUG_UA_BUS_RESET 1
#define SDEBUG_UA_MODE_CHANGED 2
#define SDEBUG_UA_CAPACITY_CHANGED 3
-#define SDEBUG_NUM_UAS 4
+#define SDEBUG_UA_LUNS_CHANGED 4
+#define SDEBUG_UA_MICROCODE_CHANGED 5 /* simulate firmware change */
+#define SDEBUG_UA_MICROCODE_CHANGED_WO_RESET 6
+#define SDEBUG_NUM_UAS 7
/* for check_readiness() */
#define UAS_ONLY 1 /* check for UAs only */
@@ -326,6 +333,7 @@ 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 *);
+static int resp_write_buffer(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
@@ -480,8 +488,9 @@ static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
{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} },
+ {0, 0x3b, 0, F_D_OUT_MAYBE, resp_write_buffer, NULL,
+ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0,
+ 0, 0, 0, 0} }, /* WRITE_BUFFER */
{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} },
@@ -782,6 +791,22 @@ static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
/* return -ENOTTY; // correct return but upsets fdisk */
}
+static void clear_luns_changed_on_target(struct sdebug_dev_info *devip)
+{
+ struct sdebug_host_info *sdhp;
+ struct sdebug_dev_info *dp;
+
+ spin_lock(&sdebug_host_list_lock);
+ list_for_each_entry(sdhp, &sdebug_host_list, host_list) {
+ list_for_each_entry(dp, &sdhp->dev_info_list, dev_list) {
+ if ((devip->sdbg_host == dp->sdbg_host) &&
+ (devip->target == dp->target))
+ clear_bit(SDEBUG_UA_LUNS_CHANGED, dp->uas_bm);
+ }
+ }
+ spin_unlock(&sdebug_host_list_lock);
+}
+
static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
struct sdebug_dev_info * devip)
{
@@ -817,6 +842,36 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
if (debug)
cp = "capacity data changed";
break;
+ case SDEBUG_UA_MICROCODE_CHANGED:
+ mk_sense_buffer(SCpnt, UNIT_ATTENTION,
+ TARGET_CHANGED_ASC, MICROCODE_CHANGED_ASCQ);
+ if (debug)
+ cp = "microcode has been changed";
+ break;
+ case SDEBUG_UA_MICROCODE_CHANGED_WO_RESET:
+ mk_sense_buffer(SCpnt, UNIT_ATTENTION,
+ TARGET_CHANGED_ASC,
+ MICROCODE_CHANGED_WO_RESET_ASCQ);
+ if (debug)
+ cp = "microcode has been changed without reset";
+ break;
+ case SDEBUG_UA_LUNS_CHANGED:
+ /*
+ * SPC-3 behavior is to report a UNIT ATTENTION with
+ * ASC/ASCQ REPORTED LUNS DATA HAS CHANGED on every LUN
+ * on the target, until a REPORT LUNS command is
+ * received. SPC-4 behavior is to report it only once.
+ * NOTE: scsi_debug_scsi_level does not use the same
+ * values as struct scsi_device->scsi_level.
+ */
+ if (scsi_debug_scsi_level >= 6) /* SPC-4 and above */
+ clear_luns_changed_on_target(devip);
+ mk_sense_buffer(SCpnt, UNIT_ATTENTION,
+ TARGET_CHANGED_ASC,
+ LUNS_CHANGED_ASCQ);
+ if (debug)
+ cp = "reported luns data has changed";
+ break;
default:
pr_warn("%s: unexpected unit attention code=%d\n",
__func__, k);
@@ -3033,6 +3088,55 @@ resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
}
+/* Note the mode field is in the same position as the (lower) service action
+ * field. For the Report supported operation codes command, SPC-4 suggests
+ * each mode of this command should be reported separately; for future. */
+static int
+resp_write_buffer(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ u8 *cmd = scp->cmnd;
+ struct scsi_device *sdp = scp->device;
+ struct sdebug_dev_info *dp;
+ u8 mode;
+
+ mode = cmd[1] & 0x1f;
+ switch (mode) {
+ case 0x4: /* download microcode (MC) and activate (ACT) */
+ /* set UAs on this device only */
+ set_bit(SDEBUG_UA_BUS_RESET, devip->uas_bm);
+ set_bit(SDEBUG_UA_MICROCODE_CHANGED, devip->uas_bm);
+ break;
+ case 0x5: /* download MC, save and ACT */
+ set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET, devip->uas_bm);
+ break;
+ case 0x6: /* download MC with offsets and ACT */
+ /* set UAs on most devices (LUs) in this target */
+ list_for_each_entry(dp,
+ &devip->sdbg_host->dev_info_list,
+ dev_list)
+ if (dp->target == sdp->id) {
+ set_bit(SDEBUG_UA_BUS_RESET, dp->uas_bm);
+ if (devip != dp)
+ set_bit(SDEBUG_UA_MICROCODE_CHANGED,
+ dp->uas_bm);
+ }
+ break;
+ case 0x7: /* download MC with offsets, save, and ACT */
+ /* set UA on all devices (LUs) in this target */
+ list_for_each_entry(dp,
+ &devip->sdbg_host->dev_info_list,
+ dev_list)
+ if (dp->target == sdp->id)
+ set_bit(SDEBUG_UA_MICROCODE_CHANGED_WO_RESET,
+ dp->uas_bm);
+ break;
+ default:
+ /* do nothing for this command for other mode values */
+ break;
+ }
+ return 0;
+}
+
static int
resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
@@ -3229,6 +3333,7 @@ static int resp_report_luns(struct scsi_cmnd * scp,
unsigned char arr[SDEBUG_RLUN_ARR_SZ];
unsigned char * max_addr;
+ clear_luns_changed_on_target(devip);
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
shortish = (alloc_len < 4);
if (shortish || (select_report > 2)) {
@@ -4369,10 +4474,27 @@ static ssize_t max_luns_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_max_luns != n);
scsi_debug_max_luns = n;
sdebug_max_tgts_luns();
+ if (changed && (scsi_debug_scsi_level >= 5)) { /* >= SPC-3 */
+ struct sdebug_host_info *sdhp;
+ struct sdebug_dev_info *dp;
+
+ spin_lock(&sdebug_host_list_lock);
+ 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_LUNS_CHANGED,
+ dp->uas_bm);
+ }
+ }
+ spin_unlock(&sdebug_host_list_lock);
+ }
return count;
}
return -EINVAL;
@@ -4536,10 +4658,10 @@ static ssize_t map_show(struct device_driver *ddp, char *buf)
return scnprintf(buf, PAGE_SIZE, "0-%u\n",
sdebug_store_sectors);
- count = bitmap_scnlistprintf(buf, PAGE_SIZE, map_storep, map_size);
-
+ count = scnprintf(buf, PAGE_SIZE - 1, "%*pbl",
+ (int)map_size, map_storep);
buf[count++] = '\n';
- buf[count++] = 0;
+ buf[count] = '\0';
return count;
}
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index 8afb01604d51..4cdaffca17fc 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -124,41 +124,37 @@ scmd_eh_abort_handler(struct work_struct *work)
if (scsi_host_eh_past_deadline(sdev->host)) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "scmd %p eh timeout, not aborting\n",
- scmd));
+ "eh timeout, not aborting\n"));
} else {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "aborting command %p\n", scmd));
+ "aborting command\n"));
rtn = scsi_try_to_abort_cmd(sdev->host->hostt, scmd);
if (rtn == SUCCESS) {
set_host_byte(scmd, DID_TIME_OUT);
if (scsi_host_eh_past_deadline(sdev->host)) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "scmd %p eh timeout, "
- "not retrying aborted "
- "command\n", scmd));
+ "eh timeout, not retrying "
+ "aborted command\n"));
} else if (!scsi_noretry_cmd(scmd) &&
(++scmd->retries <= scmd->allowed)) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd,
- "scmd %p retry "
- "aborted command\n", scmd));
+ "retry aborted command\n"));
scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
return;
} else {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd,
- "scmd %p finish "
- "aborted command\n", scmd));
+ "finish aborted command\n"));
scsi_finish_command(scmd);
return;
}
} else {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "scmd %p abort %s\n", scmd,
+ "cmd abort %s\n",
(rtn == FAST_IO_FAIL) ?
"not send" : "failed"));
}
@@ -167,8 +163,7 @@ scmd_eh_abort_handler(struct work_struct *work)
if (!scsi_eh_scmd_add(scmd, 0)) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_WARNING, scmd,
- "scmd %p terminate "
- "aborted command\n", scmd));
+ "terminate aborted command\n"));
set_host_byte(scmd, DID_TIME_OUT);
scsi_finish_command(scmd);
}
@@ -194,7 +189,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)
scmd->eh_eflags &= ~SCSI_EH_ABORT_SCHEDULED;
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "scmd %p previous abort failed\n", scmd));
+ "previous abort failed\n"));
BUG_ON(delayed_work_pending(&scmd->abort_work));
return FAILED;
}
@@ -208,8 +203,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)
spin_unlock_irqrestore(shost->host_lock, flags);
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "scmd %p not aborting, host in recovery\n",
- scmd));
+ "not aborting, host in recovery\n"));
return FAILED;
}
@@ -219,8 +213,7 @@ scsi_abort_command(struct scsi_cmnd *scmd)
scmd->eh_eflags |= SCSI_EH_ABORT_SCHEDULED;
SCSI_LOG_ERROR_RECOVERY(3,
- scmd_printk(KERN_INFO, scmd,
- "scmd %p abort scheduled\n", scmd));
+ scmd_printk(KERN_INFO, scmd, "abort scheduled\n"));
queue_delayed_work(shost->tmf_work_q, &scmd->abort_work, HZ / 100);
return SUCCESS;
}
@@ -737,8 +730,7 @@ static void scsi_eh_done(struct scsi_cmnd *scmd)
struct completion *eh_action;
SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
- "%s scmd: %p result: %x\n",
- __func__, scmd, scmd->result));
+ "%s result: %x\n", __func__, scmd->result));
eh_action = scmd->device->host->eh_action;
if (eh_action)
@@ -868,6 +860,7 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
/**
* scsi_try_to_abort_cmd - Ask host to abort a SCSI command
+ * @hostt: SCSI driver host template
* @scmd: SCSI cmd used to send a target reset
*
* Return value:
@@ -1052,8 +1045,8 @@ retry:
scsi_log_completion(scmd, rtn);
SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
- "%s: scmd: %p, timeleft: %ld\n",
- __func__, scmd, timeleft));
+ "%s timeleft: %ld\n",
+ __func__, timeleft));
/*
* If there is time left scsi_eh_done got called, and we will examine
@@ -1192,8 +1185,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
continue;
SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
- "sense requested for %p result %x\n",
- scmd, scmd->result));
+ "sense requested, result %x\n", scmd->result));
SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense(scmd));
rtn = scsi_decide_disposition(scmd);
@@ -1235,7 +1227,7 @@ retry_tur:
scmd->device->eh_timeout, 0);
SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
- "%s: scmd %p rtn %x\n", __func__, scmd, rtn));
+ "%s return: %x\n", __func__, rtn));
switch (rtn) {
case NEEDS_RETRY:
@@ -2092,8 +2084,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
(++scmd->retries <= scmd->allowed)) {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "%s: flush retry cmd: %p\n",
- current->comm, scmd));
+ "%s: flush retry cmd\n",
+ current->comm));
scsi_queue_insert(scmd, SCSI_MLQUEUE_EH_RETRY);
} else {
/*
@@ -2105,8 +2097,8 @@ void scsi_eh_flush_done_q(struct list_head *done_q)
scmd->result |= (DRIVER_TIMEOUT << 24);
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "%s: flush finish cmd: %p\n",
- current->comm, scmd));
+ "%s: flush finish cmd\n",
+ current->comm));
scsi_finish_command(scmd);
}
}
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 17bb541f7cc2..54d7a6cbb98a 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -2197,6 +2197,8 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
shost->tag_set.cmd_size = cmd_size;
shost->tag_set.numa_node = NUMA_NO_NODE;
shost->tag_set.flags = BLK_MQ_F_SHOULD_MERGE | BLK_MQ_F_SG_MERGE;
+ shost->tag_set.flags |=
+ BLK_ALLOC_POLICY_TO_MQ_FLAG(shost->hostt->tag_alloc_policy);
shost->tag_set.driver_data = shost;
return blk_mq_alloc_tag_set(&shost->tag_set);
diff --git a/drivers/scsi/scsi_logging.c b/drivers/scsi/scsi_logging.c
new file mode 100644
index 000000000000..bd70339c1242
--- /dev/null
+++ b/drivers/scsi/scsi_logging.c
@@ -0,0 +1,485 @@
+/*
+ * scsi_logging.c
+ *
+ * Copyright (C) 2014 SUSE Linux Products GmbH
+ * Copyright (C) 2014 Hannes Reinecke <hare@suse.de>
+ *
+ * This file is released under the GPLv2
+ */
+
+#include <linux/kernel.h>
+#include <linux/atomic.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_eh.h>
+#include <scsi/scsi_dbg.h>
+
+#define SCSI_LOG_SPOOLSIZE 4096
+
+#if (SCSI_LOG_SPOOLSIZE / SCSI_LOG_BUFSIZE) > BITS_PER_LONG
+#warning SCSI logging bitmask too large
+#endif
+
+struct scsi_log_buf {
+ char buffer[SCSI_LOG_SPOOLSIZE];
+ unsigned long map;
+};
+
+static DEFINE_PER_CPU(struct scsi_log_buf, scsi_format_log);
+
+static char *scsi_log_reserve_buffer(size_t *len)
+{
+ struct scsi_log_buf *buf;
+ unsigned long map_bits = sizeof(buf->buffer) / SCSI_LOG_BUFSIZE;
+ unsigned long idx = 0;
+
+ preempt_disable();
+ buf = this_cpu_ptr(&scsi_format_log);
+ idx = find_first_zero_bit(&buf->map, map_bits);
+ if (likely(idx < map_bits)) {
+ while (test_and_set_bit(idx, &buf->map)) {
+ idx = find_next_zero_bit(&buf->map, map_bits, idx);
+ if (idx >= map_bits)
+ break;
+ }
+ }
+ if (WARN_ON(idx >= map_bits)) {
+ preempt_enable();
+ return NULL;
+ }
+ *len = SCSI_LOG_BUFSIZE;
+ return buf->buffer + idx * SCSI_LOG_BUFSIZE;
+}
+
+static void scsi_log_release_buffer(char *bufptr)
+{
+ struct scsi_log_buf *buf;
+ unsigned long idx;
+ int ret;
+
+ buf = this_cpu_ptr(&scsi_format_log);
+ if (bufptr >= buf->buffer &&
+ bufptr < buf->buffer + SCSI_LOG_SPOOLSIZE) {
+ idx = (bufptr - buf->buffer) / SCSI_LOG_BUFSIZE;
+ ret = test_and_clear_bit(idx, &buf->map);
+ WARN_ON(!ret);
+ }
+ preempt_enable();
+}
+
+static inline const char *scmd_name(const struct scsi_cmnd *scmd)
+{
+ return scmd->request->rq_disk ?
+ scmd->request->rq_disk->disk_name : NULL;
+}
+
+static size_t sdev_format_header(char *logbuf, size_t logbuf_len,
+ const char *name, int tag)
+{
+ size_t off = 0;
+
+ if (name)
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "[%s] ", name);
+
+ if (WARN_ON(off >= logbuf_len))
+ return off;
+
+ if (tag >= 0)
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "tag#%d ", tag);
+ return off;
+}
+
+void sdev_prefix_printk(const char *level, const struct scsi_device *sdev,
+ const char *name, const char *fmt, ...)
+{
+ va_list args;
+ char *logbuf;
+ size_t off = 0, logbuf_len;
+
+ if (!sdev)
+ return;
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+
+ if (name)
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "[%s] ", name);
+ if (!WARN_ON(off >= logbuf_len)) {
+ va_start(args, fmt);
+ off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
+ va_end(args);
+ }
+ dev_printk(level, &sdev->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+}
+EXPORT_SYMBOL(sdev_prefix_printk);
+
+void scmd_printk(const char *level, const struct scsi_cmnd *scmd,
+ const char *fmt, ...)
+{
+ va_list args;
+ char *logbuf;
+ size_t off = 0, logbuf_len;
+
+ if (!scmd || !scmd->cmnd)
+ return;
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+ off = sdev_format_header(logbuf, logbuf_len, scmd_name(scmd),
+ scmd->request->tag);
+ if (off < logbuf_len) {
+ va_start(args, fmt);
+ off += vscnprintf(logbuf + off, logbuf_len - off, fmt, args);
+ va_end(args);
+ }
+ dev_printk(level, &scmd->device->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+}
+EXPORT_SYMBOL(scmd_printk);
+
+static size_t scsi_format_opcode_name(char *buffer, size_t buf_len,
+ const unsigned char *cdbp)
+{
+ int sa, cdb0;
+ const char *cdb_name = NULL, *sa_name = NULL;
+ size_t off;
+
+ cdb0 = cdbp[0];
+ if (cdb0 == VARIABLE_LENGTH_CMD) {
+ int len = scsi_varlen_cdb_length(cdbp);
+
+ if (len < 10) {
+ off = scnprintf(buffer, buf_len,
+ "short variable length command, len=%d",
+ len);
+ return off;
+ }
+ sa = (cdbp[8] << 8) + cdbp[9];
+ } else
+ sa = cdbp[1] & 0x1f;
+
+ if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
+ if (cdb_name)
+ off = scnprintf(buffer, buf_len, "%s", cdb_name);
+ else {
+ off = scnprintf(buffer, buf_len, "opcode=0x%x", cdb0);
+ if (WARN_ON(off >= buf_len))
+ return off;
+ if (cdb0 >= VENDOR_SPECIFIC_CDB)
+ off += scnprintf(buffer + off, buf_len - off,
+ " (vendor)");
+ else if (cdb0 >= 0x60 && cdb0 < 0x7e)
+ off += scnprintf(buffer + off, buf_len - off,
+ " (reserved)");
+ }
+ } else {
+ if (sa_name)
+ off = scnprintf(buffer, buf_len, "%s", sa_name);
+ else if (cdb_name)
+ off = scnprintf(buffer, buf_len, "%s, sa=0x%x",
+ cdb_name, sa);
+ else
+ off = scnprintf(buffer, buf_len,
+ "opcode=0x%x, sa=0x%x", cdb0, sa);
+ }
+ WARN_ON(off >= buf_len);
+ return off;
+}
+
+size_t __scsi_format_command(char *logbuf, size_t logbuf_len,
+ const unsigned char *cdb, size_t cdb_len)
+{
+ int len, k;
+ size_t off;
+
+ off = scsi_format_opcode_name(logbuf, logbuf_len, cdb);
+ if (off >= logbuf_len)
+ return off;
+ len = scsi_command_size(cdb);
+ if (cdb_len < len)
+ len = cdb_len;
+ /* print out all bytes in cdb */
+ for (k = 0; k < len; ++k) {
+ if (off > logbuf_len - 3)
+ break;
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ " %02x", cdb[k]);
+ }
+ return off;
+}
+EXPORT_SYMBOL(__scsi_format_command);
+
+void scsi_print_command(struct scsi_cmnd *cmd)
+{
+ int k;
+ char *logbuf;
+ size_t off, logbuf_len;
+
+ if (!cmd->cmnd)
+ return;
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+
+ off = sdev_format_header(logbuf, logbuf_len,
+ scmd_name(cmd), cmd->request->tag);
+ if (off >= logbuf_len)
+ goto out_printk;
+ off += scnprintf(logbuf + off, logbuf_len - off, "CDB: ");
+ if (WARN_ON(off >= logbuf_len))
+ goto out_printk;
+
+ off += scsi_format_opcode_name(logbuf + off, logbuf_len - off,
+ cmd->cmnd);
+ if (off >= logbuf_len)
+ goto out_printk;
+
+ /* print out all bytes in cdb */
+ if (cmd->cmd_len > 16) {
+ /* Print opcode in one line and use separate lines for CDB */
+ off += scnprintf(logbuf + off, logbuf_len - off, "\n");
+ dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+ for (k = 0; k < cmd->cmd_len; k += 16) {
+ size_t linelen = min(cmd->cmd_len - k, 16);
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ break;
+ off = sdev_format_header(logbuf, logbuf_len,
+ scmd_name(cmd),
+ cmd->request->tag);
+ if (!WARN_ON(off > logbuf_len - 58)) {
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "CDB[%02x]: ", k);
+ hex_dump_to_buffer(&cmd->cmnd[k], linelen,
+ 16, 1, logbuf + off,
+ logbuf_len - off, false);
+ }
+ dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s",
+ logbuf);
+ scsi_log_release_buffer(logbuf);
+ }
+ return;
+ }
+ if (!WARN_ON(off > logbuf_len - 49)) {
+ off += scnprintf(logbuf + off, logbuf_len - off, " ");
+ hex_dump_to_buffer(cmd->cmnd, cmd->cmd_len, 16, 1,
+ logbuf + off, logbuf_len - off,
+ false);
+ }
+out_printk:
+ dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+}
+EXPORT_SYMBOL(scsi_print_command);
+
+static size_t
+scsi_format_extd_sense(char *buffer, size_t buf_len,
+ unsigned char asc, unsigned char ascq)
+{
+ size_t off = 0;
+ const char *extd_sense_fmt = NULL;
+ const char *extd_sense_str = scsi_extd_sense_format(asc, ascq,
+ &extd_sense_fmt);
+
+ if (extd_sense_str) {
+ off = scnprintf(buffer, buf_len, "Add. Sense: %s",
+ extd_sense_str);
+ if (extd_sense_fmt)
+ off += scnprintf(buffer + off, buf_len - off,
+ "(%s%x)", extd_sense_fmt, ascq);
+ } else {
+ if (asc >= 0x80)
+ off = scnprintf(buffer, buf_len, "<<vendor>>");
+ off += scnprintf(buffer + off, buf_len - off,
+ "ASC=0x%x ", asc);
+ if (ascq >= 0x80)
+ off += scnprintf(buffer + off, buf_len - off,
+ "<<vendor>>");
+ off += scnprintf(buffer + off, buf_len - off,
+ "ASCQ=0x%x ", ascq);
+ }
+ return off;
+}
+
+static size_t
+scsi_format_sense_hdr(char *buffer, size_t buf_len,
+ const struct scsi_sense_hdr *sshdr)
+{
+ const char *sense_txt;
+ size_t off;
+
+ off = scnprintf(buffer, buf_len, "Sense Key : ");
+ sense_txt = scsi_sense_key_string(sshdr->sense_key);
+ if (sense_txt)
+ off += scnprintf(buffer + off, buf_len - off,
+ "%s ", sense_txt);
+ else
+ off += scnprintf(buffer + off, buf_len - off,
+ "0x%x ", sshdr->sense_key);
+ off += scnprintf(buffer + off, buf_len - off,
+ scsi_sense_is_deferred(sshdr) ? "[deferred] " : "[current] ");
+
+ if (sshdr->response_code >= 0x72)
+ off += scnprintf(buffer + off, buf_len - off, "[descriptor] ");
+ return off;
+}
+
+static void
+scsi_log_dump_sense(const struct scsi_device *sdev, const char *name, int tag,
+ const unsigned char *sense_buffer, int sense_len)
+{
+ char *logbuf;
+ size_t logbuf_len;
+ int i;
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+
+ for (i = 0; i < sense_len; i += 16) {
+ int len = min(sense_len - i, 16);
+ size_t off;
+
+ off = sdev_format_header(logbuf, logbuf_len,
+ name, tag);
+ hex_dump_to_buffer(&sense_buffer[i], len, 16, 1,
+ logbuf + off, logbuf_len - off,
+ false);
+ dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
+ }
+ scsi_log_release_buffer(logbuf);
+}
+
+static void
+scsi_log_print_sense_hdr(const struct scsi_device *sdev, const char *name,
+ int tag, const struct scsi_sense_hdr *sshdr)
+{
+ char *logbuf;
+ size_t off, logbuf_len;
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+ off = sdev_format_header(logbuf, logbuf_len, name, tag);
+ off += scsi_format_sense_hdr(logbuf + off, logbuf_len - off, sshdr);
+ dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+ off = sdev_format_header(logbuf, logbuf_len, name, tag);
+ off += scsi_format_extd_sense(logbuf + off, logbuf_len - off,
+ sshdr->asc, sshdr->ascq);
+ dev_printk(KERN_INFO, &sdev->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+}
+
+static void
+scsi_log_print_sense(const struct scsi_device *sdev, const char *name, int tag,
+ const unsigned char *sense_buffer, int sense_len)
+{
+ struct scsi_sense_hdr sshdr;
+
+ if (scsi_normalize_sense(sense_buffer, sense_len, &sshdr))
+ scsi_log_print_sense_hdr(sdev, name, tag, &sshdr);
+ else
+ scsi_log_dump_sense(sdev, name, tag, sense_buffer, sense_len);
+}
+
+/*
+ * Print normalized SCSI sense header with a prefix.
+ */
+void
+scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
+ const struct scsi_sense_hdr *sshdr)
+{
+ scsi_log_print_sense_hdr(sdev, name, -1, sshdr);
+}
+EXPORT_SYMBOL(scsi_print_sense_hdr);
+
+/* Normalize and print sense buffer with name prefix */
+void __scsi_print_sense(const struct scsi_device *sdev, const char *name,
+ const unsigned char *sense_buffer, int sense_len)
+{
+ scsi_log_print_sense(sdev, name, -1, sense_buffer, sense_len);
+}
+EXPORT_SYMBOL(__scsi_print_sense);
+
+/* Normalize and print sense buffer in SCSI command */
+void scsi_print_sense(const struct scsi_cmnd *cmd)
+{
+ scsi_log_print_sense(cmd->device, scmd_name(cmd), cmd->request->tag,
+ cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
+}
+EXPORT_SYMBOL(scsi_print_sense);
+
+void scsi_print_result(const struct scsi_cmnd *cmd, const char *msg,
+ int disposition)
+{
+ char *logbuf;
+ size_t off, logbuf_len;
+ 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);
+
+ logbuf = scsi_log_reserve_buffer(&logbuf_len);
+ if (!logbuf)
+ return;
+
+ off = sdev_format_header(logbuf, logbuf_len,
+ scmd_name(cmd), cmd->request->tag);
+
+ if (off >= logbuf_len)
+ goto out_printk;
+
+ if (msg) {
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "%s: ", msg);
+ if (WARN_ON(off >= logbuf_len))
+ goto out_printk;
+ }
+ if (mlret_string)
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "%s ", mlret_string);
+ else
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "UNKNOWN(0x%02x) ", disposition);
+ if (WARN_ON(off >= logbuf_len))
+ goto out_printk;
+
+ off += scnprintf(logbuf + off, logbuf_len - off, "Result: ");
+ if (WARN_ON(off >= logbuf_len))
+ goto out_printk;
+
+ if (hb_string)
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "hostbyte=%s ", hb_string);
+ else
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "hostbyte=0x%02x ", host_byte(cmd->result));
+ if (WARN_ON(off >= logbuf_len))
+ goto out_printk;
+
+ if (db_string)
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "driverbyte=%s", db_string);
+ else
+ off += scnprintf(logbuf + off, logbuf_len - off,
+ "driverbyte=0x%02x", driver_byte(cmd->result));
+out_printk:
+ dev_printk(KERN_INFO, &cmd->device->sdev_gendev, "%s", logbuf);
+ scsi_log_release_buffer(logbuf);
+}
+EXPORT_SYMBOL(scsi_print_result);
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 6fcefa2da503..251598eb3547 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -189,36 +189,36 @@ static int proc_print_scsidevice(struct device *dev, void *data)
sdev->host->host_no, sdev->channel, sdev->id, sdev->lun);
for (i = 0; i < 8; i++) {
if (sdev->vendor[i] >= 0x20)
- seq_printf(s, "%c", sdev->vendor[i]);
+ seq_putc(s, sdev->vendor[i]);
else
- seq_printf(s, " ");
+ seq_putc(s, ' ');
}
- seq_printf(s, " Model: ");
+ seq_puts(s, " Model: ");
for (i = 0; i < 16; i++) {
if (sdev->model[i] >= 0x20)
- seq_printf(s, "%c", sdev->model[i]);
+ seq_putc(s, sdev->model[i]);
else
- seq_printf(s, " ");
+ seq_putc(s, ' ');
}
- seq_printf(s, " Rev: ");
+ seq_puts(s, " Rev: ");
for (i = 0; i < 4; i++) {
if (sdev->rev[i] >= 0x20)
- seq_printf(s, "%c", sdev->rev[i]);
+ seq_putc(s, sdev->rev[i]);
else
- seq_printf(s, " ");
+ seq_putc(s, ' ');
}
- seq_printf(s, "\n");
+ seq_putc(s, '\n');
seq_printf(s, " Type: %s ", scsi_device_type(sdev->type));
seq_printf(s, " ANSI SCSI revision: %02x",
sdev->scsi_level - (sdev->scsi_level > 1));
if (sdev->scsi_level == 2)
- seq_printf(s, " CCS\n");
+ seq_puts(s, " CCS\n");
else
- seq_printf(s, "\n");
+ seq_putc(s, '\n');
out:
return 0;
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index 983aed10ff2f..9c0a520d933c 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -34,6 +34,7 @@
#include <linux/spinlock.h>
#include <linux/async.h>
#include <linux/slab.h>
+#include <asm/unaligned.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -98,20 +99,6 @@ char scsi_scan_type[6] = SCSI_SCAN_TYPE_DEFAULT;
module_param_string(scan, scsi_scan_type, sizeof(scsi_scan_type), S_IRUGO);
MODULE_PARM_DESC(scan, "sync, async or none");
-/*
- * max_scsi_report_luns: the maximum number of LUNS that will be
- * returned from the REPORT LUNS command. 8 times this value must
- * be allocated. In theory this could be up to an 8 byte value, but
- * in practice, the maximum number of LUNs suppored by any device
- * is about 16k.
- */
-static unsigned int max_scsi_report_luns = 511;
-
-module_param_named(max_report_luns, max_scsi_report_luns, uint, S_IRUGO|S_IWUSR);
-MODULE_PARM_DESC(max_report_luns,
- "REPORT LUNS maximum number of LUNS received (should be"
- " between 1 and 16384)");
-
static unsigned int scsi_inq_timeout = SCSI_TIMEOUT/HZ + 18;
module_param_named(inq_timeout, scsi_inq_timeout, uint, S_IRUGO|S_IWUSR);
@@ -290,7 +277,8 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
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);
+ sdev->host->cmd_per_lun, shost->bqt,
+ shost->hostt->tag_alloc_policy);
}
scsi_change_queue_depth(sdev, sdev->host->cmd_per_lun);
@@ -1367,7 +1355,6 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
unsigned int retries;
int result;
struct scsi_lun *lunp, *lun_data;
- u8 *data;
struct scsi_sense_hdr sshdr;
struct scsi_device *sdev;
struct Scsi_Host *shost = dev_to_shost(&starget->dev);
@@ -1407,16 +1394,12 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
/*
* Allocate enough to hold the header (the same size as one scsi_lun)
- * plus the max number of luns we are requesting.
- *
- * Reallocating and trying again (with the exact amount we need)
- * would be nice, but then we need to somehow limit the size
- * allocated based on the available memory and the limits of
- * kmalloc - we don't want a kmalloc() failure of a huge value to
- * prevent us from finding any LUNs on this target.
+ * plus the number of luns we are requesting. 511 was the default
+ * value of the now removed max_report_luns parameter.
*/
- length = (max_scsi_report_luns + 1) * sizeof(struct scsi_lun);
- lun_data = kmalloc(length, GFP_ATOMIC |
+ length = (511 + 1) * sizeof(struct scsi_lun);
+retry:
+ lun_data = kmalloc(length, GFP_KERNEL |
(sdev->host->unchecked_isa_dma ? __GFP_DMA : 0));
if (!lun_data) {
printk(ALLOC_FAILURE_MSG, __func__);
@@ -1433,10 +1416,7 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
/*
* bytes 6 - 9: length of the command.
*/
- scsi_cmd[6] = (unsigned char) (length >> 24) & 0xff;
- scsi_cmd[7] = (unsigned char) (length >> 16) & 0xff;
- scsi_cmd[8] = (unsigned char) (length >> 8) & 0xff;
- scsi_cmd[9] = (unsigned char) length & 0xff;
+ put_unaligned_be32(length, &scsi_cmd[6]);
scsi_cmd[10] = 0; /* reserved */
scsi_cmd[11] = 0; /* control */
@@ -1484,19 +1464,16 @@ static int scsi_report_lun_scan(struct scsi_target *starget, int bflags,
/*
* Get the length from the first four bytes of lun_data.
*/
- data = (u8 *) lun_data->scsi_lun;
- length = ((data[0] << 24) | (data[1] << 16) |
- (data[2] << 8) | (data[3] << 0));
+ if (get_unaligned_be32(lun_data->scsi_lun) +
+ sizeof(struct scsi_lun) > length) {
+ length = get_unaligned_be32(lun_data->scsi_lun) +
+ sizeof(struct scsi_lun);
+ kfree(lun_data);
+ goto retry;
+ }
+ length = get_unaligned_be32(lun_data->scsi_lun);
num_luns = (length / sizeof(struct scsi_lun));
- if (num_luns > max_scsi_report_luns) {
- sdev_printk(KERN_WARNING, sdev,
- "Only %d (max_scsi_report_luns)"
- " of %d luns reported, try increasing"
- " max_scsi_report_luns.\n",
- max_scsi_report_luns, num_luns);
- num_luns = max_scsi_report_luns;
- }
SCSI_LOG_SCAN_BUS(3, sdev_printk (KERN_INFO, sdev,
"scsi scan: REPORT LUN scan\n"));
diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c
index 82af28b90294..08bb47b53bc3 100644
--- a/drivers/scsi/scsi_trace.c
+++ b/drivers/scsi/scsi_trace.c
@@ -143,7 +143,7 @@ scsi_trace_rw32(struct trace_seq *p, unsigned char *cdb, int len)
cmd = "WRITE_SAME";
break;
default:
- trace_seq_printf(p, "UNKNOWN");
+ trace_seq_puts(p, "UNKNOWN");
goto out;
}
@@ -204,7 +204,7 @@ scsi_trace_service_action_in(struct trace_seq *p, unsigned char *cdb, int len)
cmd = "GET_LBA_STATUS";
break;
default:
- trace_seq_printf(p, "UNKNOWN");
+ trace_seq_puts(p, "UNKNOWN");
goto out;
}
@@ -249,7 +249,7 @@ scsi_trace_misc(struct trace_seq *p, unsigned char *cdb, int len)
{
const char *ret = trace_seq_buffer_ptr(p);
- trace_seq_printf(p, "-");
+ trace_seq_putc(p, '-');
trace_seq_putc(p, 0);
return ret;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 399516925d80..6b78476d04bb 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -2800,9 +2800,11 @@ static int sd_revalidate_disk(struct gendisk *disk)
*/
sd_set_flush_flag(sdkp);
- max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue),
- sdkp->max_xfer_blocks);
+ max_xfer = sdkp->max_xfer_blocks;
max_xfer <<= ilog2(sdp->sector_size) - 9;
+
+ max_xfer = min_not_zero(queue_max_hw_sectors(sdkp->disk->queue),
+ max_xfer);
blk_queue_max_hw_sectors(sdkp->disk->queue, max_xfer);
set_capacity(disk, sdkp->capacity);
sd_config_write_same(sdkp);
@@ -3318,11 +3320,8 @@ module_exit(exit_sd);
static void sd_print_sense_hdr(struct scsi_disk *sdkp,
struct scsi_sense_hdr *sshdr)
{
- 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);
+ scsi_print_sense_hdr(sdkp->device,
+ sdkp->disk ? sdkp->disk->disk_name : NULL, sshdr);
}
static void sd_print_result(const struct scsi_disk *sdkp, const char *msg,
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index b7e79e7646ad..dcb0d76d7312 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -47,7 +47,6 @@ struct ses_device {
struct ses_component {
u64 addr;
- unsigned char *desc;
};
static int ses_probe(struct device *dev)
@@ -68,6 +67,20 @@ static int ses_probe(struct device *dev)
#define SES_TIMEOUT (30 * HZ)
#define SES_RETRIES 3
+static void init_device_slot_control(unsigned char *dest_desc,
+ struct enclosure_component *ecomp,
+ unsigned char *status)
+{
+ memcpy(dest_desc, status, 4);
+ dest_desc[0] = 0;
+ /* only clear byte 1 for ENCLOSURE_COMPONENT_DEVICE */
+ if (ecomp->type == ENCLOSURE_COMPONENT_DEVICE)
+ dest_desc[1] = 0;
+ dest_desc[2] &= 0xde;
+ dest_desc[3] &= 0x3c;
+}
+
+
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
void *buf, int bufflen)
{
@@ -179,14 +192,22 @@ static int ses_set_fault(struct enclosure_device *edev,
struct enclosure_component *ecomp,
enum enclosure_component_setting val)
{
- unsigned char desc[4] = {0 };
+ unsigned char desc[4];
+ unsigned char *desc_ptr;
+
+ desc_ptr = ses_get_page2_descriptor(edev, ecomp);
+
+ if (!desc_ptr)
+ return -EIO;
+
+ init_device_slot_control(desc, ecomp, desc_ptr);
switch (val) {
case ENCLOSURE_SETTING_DISABLED:
- /* zero is disabled */
+ desc[3] &= 0xdf;
break;
case ENCLOSURE_SETTING_ENABLED:
- desc[3] = 0x20;
+ desc[3] |= 0x20;
break;
default:
/* SES doesn't do the SGPIO blink settings */
@@ -220,14 +241,22 @@ static int ses_set_locate(struct enclosure_device *edev,
struct enclosure_component *ecomp,
enum enclosure_component_setting val)
{
- unsigned char desc[4] = {0 };
+ unsigned char desc[4];
+ unsigned char *desc_ptr;
+
+ desc_ptr = ses_get_page2_descriptor(edev, ecomp);
+
+ if (!desc_ptr)
+ return -EIO;
+
+ init_device_slot_control(desc, ecomp, desc_ptr);
switch (val) {
case ENCLOSURE_SETTING_DISABLED:
- /* zero is disabled */
+ desc[2] &= 0xfd;
break;
case ENCLOSURE_SETTING_ENABLED:
- desc[2] = 0x02;
+ desc[2] |= 0x02;
break;
default:
/* SES doesn't do the SGPIO blink settings */
@@ -240,15 +269,23 @@ static int ses_set_active(struct enclosure_device *edev,
struct enclosure_component *ecomp,
enum enclosure_component_setting val)
{
- unsigned char desc[4] = {0 };
+ unsigned char desc[4];
+ unsigned char *desc_ptr;
+
+ desc_ptr = ses_get_page2_descriptor(edev, ecomp);
+
+ if (!desc_ptr)
+ return -EIO;
+
+ init_device_slot_control(desc, ecomp, desc_ptr);
switch (val) {
case ENCLOSURE_SETTING_DISABLED:
- /* zero is disabled */
+ desc[2] &= 0x7f;
ecomp->active = 0;
break;
case ENCLOSURE_SETTING_ENABLED:
- desc[2] = 0x80;
+ desc[2] |= 0x80;
ecomp->active = 1;
break;
default:
@@ -258,13 +295,63 @@ static int ses_set_active(struct enclosure_device *edev,
return ses_set_page2_descriptor(edev, ecomp, desc);
}
+static int ses_show_id(struct enclosure_device *edev, char *buf)
+{
+ struct ses_device *ses_dev = edev->scratch;
+ unsigned long long id = get_unaligned_be64(ses_dev->page1+8+4);
+
+ return sprintf(buf, "%#llx\n", id);
+}
+
+static void ses_get_power_status(struct enclosure_device *edev,
+ struct enclosure_component *ecomp)
+{
+ unsigned char *desc;
+
+ desc = ses_get_page2_descriptor(edev, ecomp);
+ if (desc)
+ ecomp->power_status = (desc[3] & 0x10) ? 0 : 1;
+}
+
+static int ses_set_power_status(struct enclosure_device *edev,
+ struct enclosure_component *ecomp,
+ int val)
+{
+ unsigned char desc[4];
+ unsigned char *desc_ptr;
+
+ desc_ptr = ses_get_page2_descriptor(edev, ecomp);
+
+ if (!desc_ptr)
+ return -EIO;
+
+ init_device_slot_control(desc, ecomp, desc_ptr);
+
+ switch (val) {
+ /* power = 1 is device_off = 0 and vice versa */
+ case 0:
+ desc[3] |= 0x10;
+ break;
+ case 1:
+ desc[3] &= 0xef;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ecomp->power_status = val;
+ return ses_set_page2_descriptor(edev, ecomp, desc);
+}
+
static struct enclosure_component_callbacks ses_enclosure_callbacks = {
.get_fault = ses_get_fault,
.set_fault = ses_set_fault,
.get_status = ses_get_status,
.get_locate = ses_get_locate,
.set_locate = ses_set_locate,
+ .get_power_status = ses_get_power_status,
+ .set_power_status = ses_set_power_status,
.set_active = ses_set_active,
+ .show_id = ses_show_id,
};
struct ses_host_edev {
@@ -298,19 +385,26 @@ static void ses_process_descriptor(struct enclosure_component *ecomp,
int invalid = desc[0] & 0x80;
enum scsi_protocol proto = desc[0] & 0x0f;
u64 addr = 0;
+ int slot = -1;
struct ses_component *scomp = ecomp->scratch;
unsigned char *d;
- scomp->desc = desc;
-
if (invalid)
return;
switch (proto) {
+ case SCSI_PROTOCOL_FCP:
+ if (eip) {
+ d = desc + 4;
+ slot = d[3];
+ }
+ break;
case SCSI_PROTOCOL_SAS:
- if (eip)
+ if (eip) {
+ d = desc + 4;
+ slot = d[3];
d = desc + 8;
- else
+ } else
d = desc + 4;
/* only take the phy0 addr */
addr = (u64)d[12] << 56 |
@@ -326,6 +420,7 @@ static void ses_process_descriptor(struct enclosure_component *ecomp,
/* FIXME: Need to add more protocols than just SAS */
break;
}
+ ecomp->slot = slot;
scomp->addr = addr;
}
@@ -349,7 +444,8 @@ static int ses_enclosure_find_by_addr(struct enclosure_device *edev,
if (scomp->addr != efd->addr)
continue;
- enclosure_add_device(edev, i, efd->dev);
+ if (enclosure_add_device(edev, i, efd->dev) == 0)
+ kobject_uevent(&efd->dev->kobj, KOBJ_CHANGE);
return 1;
}
return 0;
@@ -423,16 +519,24 @@ static void ses_enclosure_data_process(struct enclosure_device *edev,
type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
if (create)
- ecomp = enclosure_component_register(edev,
- components++,
- type_ptr[0],
- name);
+ ecomp = enclosure_component_alloc(
+ edev,
+ components++,
+ type_ptr[0],
+ name);
else
ecomp = &edev->component[components++];
- if (!IS_ERR(ecomp) && addl_desc_ptr)
- ses_process_descriptor(ecomp,
- addl_desc_ptr);
+ if (!IS_ERR(ecomp)) {
+ ses_get_power_status(edev, ecomp);
+ if (addl_desc_ptr)
+ ses_process_descriptor(
+ ecomp,
+ addl_desc_ptr);
+ if (create)
+ enclosure_component_register(
+ ecomp);
+ }
}
if (desc_ptr)
desc_ptr += len;
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index b14f64cb9724..2270bd51f9c2 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -546,7 +546,7 @@ static ssize_t
sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
{
sg_io_hdr_t *hp = &srp->header;
- int err = 0;
+ int err = 0, err2;
int len;
if (count < SZ_SG_IO_HDR) {
@@ -575,8 +575,8 @@ sg_new_read(Sg_fd * sfp, char __user *buf, size_t count, Sg_request * srp)
goto err_out;
}
err_out:
- err = sg_finish_rem_req(srp);
- return (0 == err) ? count : err;
+ err2 = sg_finish_rem_req(srp);
+ return err ? : err2 ? : count;
}
static ssize_t
@@ -763,7 +763,7 @@ static int
sg_common_write(Sg_fd * sfp, Sg_request * srp,
unsigned char *cmnd, int timeout, int blocking)
{
- int k, data_dir, at_head;
+ int k, at_head;
Sg_device *sdp = sfp->parentdp;
sg_io_hdr_t *hp = &srp->header;
@@ -793,21 +793,6 @@ sg_common_write(Sg_fd * sfp, Sg_request * srp,
return -ENODEV;
}
- switch (hp->dxfer_direction) {
- case SG_DXFER_TO_FROM_DEV:
- case SG_DXFER_FROM_DEV:
- data_dir = DMA_FROM_DEVICE;
- break;
- case SG_DXFER_TO_DEV:
- data_dir = DMA_TO_DEVICE;
- break;
- case SG_DXFER_UNKNOWN:
- data_dir = DMA_BIDIRECTIONAL;
- break;
- default:
- data_dir = DMA_NONE;
- break;
- }
hp->duration = jiffies_to_msecs(jiffies);
if (hp->interface_id != '\0' && /* v3 (or later) interface */
(SG_FLAG_Q_AT_TAIL & hp->flags))
@@ -1350,6 +1335,17 @@ sg_rq_end_io(struct request *rq, int uptodate)
}
/* Rely on write phase to clean out srp status values, so no "else" */
+ /*
+ * Free the request as soon as it is complete so that its resources
+ * can be reused without waiting for userspace to read() the
+ * result. But keep the associated bio (if any) around until
+ * blk_rq_unmap_user() can be called from user context.
+ */
+ srp->rq = NULL;
+ if (rq->cmd != rq->__cmd)
+ kfree(rq->cmd);
+ __blk_put_request(rq->q, rq);
+
write_lock_irqsave(&sfp->rq_list_lock, iflags);
if (unlikely(srp->orphan)) {
if (sfp->keep_orphan)
@@ -1684,7 +1680,22 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
return -ENOMEM;
}
- rq = blk_get_request(q, rw, GFP_ATOMIC);
+ /*
+ * NOTE
+ *
+ * With scsi-mq enabled, there are a fixed number of preallocated
+ * requests equal in number to shost->can_queue. If all of the
+ * preallocated requests are already in use, then using GFP_ATOMIC with
+ * blk_get_request() will return -EWOULDBLOCK, whereas using GFP_KERNEL
+ * will cause blk_get_request() to sleep until an active command
+ * completes, freeing up a request. Neither option is ideal, but
+ * GFP_KERNEL is the better choice to prevent userspace from getting an
+ * unexpected EWOULDBLOCK.
+ *
+ * With scsi-mq disabled, blk_get_request() with GFP_KERNEL usually
+ * does not sleep except under memory pressure.
+ */
+ rq = blk_get_request(q, rw, GFP_KERNEL);
if (IS_ERR(rq)) {
kfree(long_cmdp);
return PTR_ERR(rq);
@@ -1734,22 +1745,19 @@ sg_start_req(Sg_request *srp, unsigned char *cmd)
}
if (iov_count) {
- int len, size = sizeof(struct sg_iovec) * iov_count;
+ int size = sizeof(struct iovec) * iov_count;
struct iovec *iov;
+ struct iov_iter i;
iov = memdup_user(hp->dxferp, size);
if (IS_ERR(iov))
return PTR_ERR(iov);
- len = iov_length(iov, iov_count);
- if (hp->dxfer_len < len) {
- iov_count = iov_shorten(iov, iov_count, hp->dxfer_len);
- len = hp->dxfer_len;
- }
+ iov_iter_init(&i, rw, iov, iov_count,
+ min_t(size_t, hp->dxfer_len,
+ iov_length(iov, iov_count)));
- res = blk_rq_map_user_iov(q, rq, md, (struct sg_iovec *)iov,
- iov_count,
- len, GFP_ATOMIC);
+ res = blk_rq_map_user_iov(q, rq, md, &i, GFP_ATOMIC);
kfree(iov);
} else
res = blk_rq_map_user(q, rq, md, hp->dxferp,
@@ -1777,10 +1785,10 @@ sg_finish_rem_req(Sg_request *srp)
SCSI_LOG_TIMEOUT(4, sg_printk(KERN_INFO, sfp->parentdp,
"sg_finish_rem_req: res_used=%d\n",
(int) srp->res_used));
- if (srp->rq) {
- if (srp->bio)
- ret = blk_rq_unmap_user(srp->bio);
+ if (srp->bio)
+ ret = blk_rq_unmap_user(srp->bio);
+ if (srp->rq) {
if (srp->rq->cmd != srp->rq->__cmd)
kfree(srp->rq->cmd);
blk_put_request(srp->rq);
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index fb929fac22ba..03054c0e7689 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -245,9 +245,6 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
sr_printk(KERN_INFO, cd,
"CDROM not ready. Make sure there "
"is a disc in the drive.\n");
-#ifdef DEBUG
- scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr);
-#endif
err = -ENOMEDIUM;
break;
case ILLEGAL_REQUEST:
@@ -256,16 +253,8 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
sshdr.ascq == 0x00)
/* sense: Invalid command operation code */
err = -EDRIVE_CANT_DO_THIS;
-#ifdef DEBUG
- __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, 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 128d3b55bdd9..9a1c34205254 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -4551,18 +4551,15 @@ static int sgl_map_user_pages(struct st_buffer *STbp,
return -ENOMEM;
/* Try to fault in all of the necessary pages */
- down_read(&current->mm->mmap_sem);
/* rw==READ means read from drive, write into memory area */
- res = get_user_pages(
+ res = get_user_pages_unlocked(
current,
current->mm,
uaddr,
nr_pages,
rw == READ,
0, /* don't force */
- pages,
- NULL);
- up_read(&current->mm->mmap_sem);
+ pages);
/* Errors and no page mapped should return here */
if (res < nr_pages)
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 4cff0ddc2c25..efc6e446b6c8 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -32,7 +32,6 @@
#include <linux/module.h>
#include <linux/device.h>
#include <linux/hyperv.h>
-#include <linux/mempool.h>
#include <linux/blkdev.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -309,14 +308,6 @@ enum storvsc_request_type {
* This is the end of Protocol specific defines.
*/
-
-/*
- * We setup a mempool to allocate request structures for this driver
- * on a per-lun basis. The following define specifies the number of
- * elements in the pool.
- */
-
-#define STORVSC_MIN_BUF_NR 64
static int storvsc_ringbuffer_size = (20 * PAGE_SIZE);
module_param(storvsc_ringbuffer_size, int, S_IRUGO);
@@ -346,7 +337,6 @@ static void storvsc_on_channel_callback(void *context);
#define STORVSC_IDE_MAX_CHANNELS 1
struct storvsc_cmd_request {
- struct list_head entry;
struct scsi_cmnd *cmd;
unsigned int bounce_sgl_count;
@@ -357,7 +347,6 @@ struct storvsc_cmd_request {
/* Synchronize the request/response if needed */
struct completion wait_event;
- unsigned char *sense_buffer;
struct hv_multipage_buffer data_buffer;
struct vstor_packet vstor_packet;
};
@@ -389,11 +378,6 @@ struct storvsc_device {
struct storvsc_cmd_request reset_request;
};
-struct stor_mem_pools {
- struct kmem_cache *request_pool;
- mempool_t *request_mempool;
-};
-
struct hv_host_device {
struct hv_device *dev;
unsigned int port;
@@ -426,21 +410,42 @@ done:
kfree(wrk);
}
-static void storvsc_bus_scan(struct work_struct *work)
+static void storvsc_host_scan(struct work_struct *work)
{
struct storvsc_scan_work *wrk;
- int id, order_id;
+ struct Scsi_Host *host;
+ struct scsi_device *sdev;
+ unsigned long flags;
wrk = container_of(work, struct storvsc_scan_work, work);
- for (id = 0; id < wrk->host->max_id; ++id) {
- if (wrk->host->reverse_ordering)
- order_id = wrk->host->max_id - id - 1;
- else
- order_id = id;
-
- scsi_scan_target(&wrk->host->shost_gendev, 0,
- order_id, SCAN_WILD_CARD, 1);
+ host = wrk->host;
+
+ /*
+ * Before scanning the host, first check to see if any of the
+ * currrently known devices have been hot removed. We issue a
+ * "unit ready" command against all currently known devices.
+ * This I/O will result in an error for devices that have been
+ * removed. As part of handling the I/O error, we remove the device.
+ *
+ * When a LUN is added or removed, the host sends us a signal to
+ * scan the host. Thus we are forced to discover the LUNs that
+ * may have been removed this way.
+ */
+ mutex_lock(&host->scan_mutex);
+ spin_lock_irqsave(host->host_lock, flags);
+ list_for_each_entry(sdev, &host->__devices, siblings) {
+ spin_unlock_irqrestore(host->host_lock, flags);
+ scsi_test_unit_ready(sdev, 1, 1, NULL);
+ spin_lock_irqsave(host->host_lock, flags);
+ continue;
}
+ spin_unlock_irqrestore(host->host_lock, flags);
+ mutex_unlock(&host->scan_mutex);
+ /*
+ * Now scan the host to discover LUNs that may have been added.
+ */
+ scsi_scan_host(host);
+
kfree(wrk);
}
@@ -1070,10 +1075,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
{
struct scsi_cmnd *scmnd = cmd_request->cmd;
struct hv_host_device *host_dev = shost_priv(scmnd->device->host);
- void (*scsi_done_fn)(struct scsi_cmnd *);
struct scsi_sense_hdr sense_hdr;
struct vmscsi_request *vm_srb;
- struct stor_mem_pools *memp = scmnd->device->hostdata;
struct Scsi_Host *host;
struct storvsc_device *stor_dev;
struct hv_device *dev = host_dev->dev;
@@ -1109,14 +1112,7 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
cmd_request->data_buffer.len -
vm_srb->data_transfer_length);
- scsi_done_fn = scmnd->scsi_done;
-
- scmnd->host_scribble = NULL;
- scmnd->scsi_done = NULL;
-
- scsi_done_fn(scmnd);
-
- mempool_free(cmd_request, memp->request_mempool);
+ scmnd->scsi_done(scmnd);
}
static void storvsc_on_io_completion(struct hv_device *device,
@@ -1160,7 +1156,7 @@ static void storvsc_on_io_completion(struct hv_device *device,
SRB_STATUS_AUTOSENSE_VALID) {
/* autosense data available */
- memcpy(request->sense_buffer,
+ memcpy(request->cmd->sense_buffer,
vstor_packet->vm_srb.sense_data,
vstor_packet->vm_srb.sense_info_length);
@@ -1198,7 +1194,7 @@ static void storvsc_on_receive(struct hv_device *device,
if (!work)
return;
- INIT_WORK(&work->work, storvsc_bus_scan);
+ INIT_WORK(&work->work, storvsc_host_scan);
work->host = stor_device->host;
schedule_work(&work->work);
break;
@@ -1378,55 +1374,6 @@ static int storvsc_do_io(struct hv_device *device,
return ret;
}
-static int storvsc_device_alloc(struct scsi_device *sdevice)
-{
- struct stor_mem_pools *memp;
- int number = STORVSC_MIN_BUF_NR;
-
- memp = kzalloc(sizeof(struct stor_mem_pools), GFP_KERNEL);
- if (!memp)
- return -ENOMEM;
-
- memp->request_pool =
- kmem_cache_create(dev_name(&sdevice->sdev_dev),
- sizeof(struct storvsc_cmd_request), 0,
- SLAB_HWCACHE_ALIGN, NULL);
-
- if (!memp->request_pool)
- goto err0;
-
- memp->request_mempool = mempool_create(number, mempool_alloc_slab,
- mempool_free_slab,
- memp->request_pool);
-
- if (!memp->request_mempool)
- goto err1;
-
- sdevice->hostdata = memp;
-
- return 0;
-
-err1:
- kmem_cache_destroy(memp->request_pool);
-
-err0:
- kfree(memp);
- return -ENOMEM;
-}
-
-static void storvsc_device_destroy(struct scsi_device *sdevice)
-{
- struct stor_mem_pools *memp = sdevice->hostdata;
-
- if (!memp)
- return;
-
- mempool_destroy(memp->request_mempool);
- kmem_cache_destroy(memp->request_pool);
- kfree(memp);
- sdevice->hostdata = NULL;
-}
-
static int storvsc_device_configure(struct scsi_device *sdevice)
{
scsi_change_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS);
@@ -1447,6 +1394,19 @@ static int storvsc_device_configure(struct scsi_device *sdevice)
*/
sdevice->sdev_bflags |= msft_blist_flags;
+ /*
+ * If the host is WIN8 or WIN8 R2, claim conformance to SPC-3
+ * if the device is a MSFT virtual device.
+ */
+ if (!strncmp(sdevice->vendor, "Msft", 4)) {
+ switch (vmbus_proto_version) {
+ case VERSION_WIN8:
+ case VERSION_WIN8_1:
+ sdevice->scsi_level = SCSI_SPC_3;
+ break;
+ }
+ }
+
return 0;
}
@@ -1561,13 +1521,11 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
int ret;
struct hv_host_device *host_dev = shost_priv(host);
struct hv_device *dev = host_dev->dev;
- struct storvsc_cmd_request *cmd_request;
- unsigned int request_size = 0;
+ struct storvsc_cmd_request *cmd_request = scsi_cmd_priv(scmnd);
int i;
struct scatterlist *sgl;
unsigned int sg_count = 0;
struct vmscsi_request *vm_srb;
- struct stor_mem_pools *memp = scmnd->device->hostdata;
if (vmstor_current_major <= VMSTOR_WIN8_MAJOR) {
/*
@@ -1584,25 +1542,9 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
}
}
- request_size = sizeof(struct storvsc_cmd_request);
-
- cmd_request = mempool_alloc(memp->request_mempool,
- GFP_ATOMIC);
-
- /*
- * We might be invoked in an interrupt context; hence
- * mempool_alloc() can fail.
- */
- if (!cmd_request)
- return SCSI_MLQUEUE_DEVICE_BUSY;
-
- memset(cmd_request, 0, sizeof(struct storvsc_cmd_request));
-
/* Setup the cmd request */
cmd_request->cmd = scmnd;
- scmnd->host_scribble = (unsigned char *)cmd_request;
-
vm_srb = &cmd_request->vstor_packet.vm_srb;
vm_srb->win8_extension.time_out_value = 60;
@@ -1637,9 +1579,6 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
memcpy(vm_srb->cdb, scmnd->cmnd, vm_srb->cdb_length);
- cmd_request->sense_buffer = scmnd->sense_buffer;
-
-
cmd_request->data_buffer.len = scsi_bufflen(scmnd);
if (scsi_sg_count(scmnd)) {
sgl = (struct scatterlist *)scsi_sglist(scmnd);
@@ -1651,10 +1590,8 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
create_bounce_buffer(sgl, scsi_sg_count(scmnd),
scsi_bufflen(scmnd),
vm_srb->data_in);
- if (!cmd_request->bounce_sgl) {
- ret = SCSI_MLQUEUE_HOST_BUSY;
- goto queue_error;
- }
+ if (!cmd_request->bounce_sgl)
+ return SCSI_MLQUEUE_HOST_BUSY;
cmd_request->bounce_sgl_count =
ALIGN(scsi_bufflen(scmnd), PAGE_SIZE) >>
@@ -1692,27 +1629,21 @@ static int storvsc_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *scmnd)
destroy_bounce_buffer(cmd_request->bounce_sgl,
cmd_request->bounce_sgl_count);
- ret = SCSI_MLQUEUE_DEVICE_BUSY;
- goto queue_error;
+ return SCSI_MLQUEUE_DEVICE_BUSY;
}
return 0;
-
-queue_error:
- mempool_free(cmd_request, memp->request_mempool);
- scmnd->host_scribble = NULL;
- return ret;
}
static struct scsi_host_template scsi_driver = {
.module = THIS_MODULE,
.name = "storvsc_host_t",
+ .cmd_size = sizeof(struct storvsc_cmd_request),
.bios_param = storvsc_get_chs,
.queuecommand = storvsc_queuecommand,
.eh_host_reset_handler = storvsc_host_reset_handler,
+ .proc_name = "storvsc_host",
.eh_timed_out = storvsc_eh_timed_out,
- .slave_alloc = storvsc_device_alloc,
- .slave_destroy = storvsc_device_destroy,
.slave_configure = storvsc_device_configure,
.cmd_per_lun = 255,
.can_queue = STORVSC_MAX_IO_REQUESTS*STORVSC_MAX_TARGETS,
@@ -1760,6 +1691,9 @@ static int storvsc_probe(struct hv_device *device,
bool dev_is_ide = ((dev_id->driver_data == IDE_GUID) ? true : false);
int target = 0;
struct storvsc_device *stor_device;
+ int max_luns_per_target;
+ int max_targets;
+ int max_channels;
/*
* Based on the windows host we are running on,
@@ -1773,12 +1707,18 @@ static int storvsc_probe(struct hv_device *device,
vmscsi_size_delta = sizeof(struct vmscsi_win8_extension);
vmstor_current_major = VMSTOR_WIN7_MAJOR;
vmstor_current_minor = VMSTOR_WIN7_MINOR;
+ max_luns_per_target = STORVSC_IDE_MAX_LUNS_PER_TARGET;
+ max_targets = STORVSC_IDE_MAX_TARGETS;
+ max_channels = STORVSC_IDE_MAX_CHANNELS;
break;
default:
sense_buffer_size = POST_WIN7_STORVSC_SENSE_BUFFER_SIZE;
vmscsi_size_delta = 0;
vmstor_current_major = VMSTOR_WIN8_MAJOR;
vmstor_current_minor = VMSTOR_WIN8_MINOR;
+ max_luns_per_target = STORVSC_MAX_LUNS_PER_TARGET;
+ max_targets = STORVSC_MAX_TARGETS;
+ max_channels = STORVSC_MAX_CHANNELS;
break;
}
@@ -1826,9 +1766,9 @@ static int storvsc_probe(struct hv_device *device,
break;
case SCSI_GUID:
- host->max_lun = STORVSC_MAX_LUNS_PER_TARGET;
- host->max_id = STORVSC_MAX_TARGETS;
- host->max_channel = STORVSC_MAX_CHANNELS - 1;
+ host->max_lun = max_luns_per_target;
+ host->max_id = max_targets;
+ host->max_channel = max_channels - 1;
break;
default:
diff --git a/drivers/scsi/ufs/Kconfig b/drivers/scsi/ufs/Kconfig
index 6e07b2afddeb..8a1f4b355416 100644
--- a/drivers/scsi/ufs/Kconfig
+++ b/drivers/scsi/ufs/Kconfig
@@ -70,3 +70,16 @@ config SCSI_UFSHCD_PLATFORM
If you have a controller with this interface, say Y or M here.
If unsure, say N.
+
+config SCSI_UFS_QCOM
+ bool "QCOM specific hooks to UFS controller platform driver"
+ depends on SCSI_UFSHCD_PLATFORM && ARCH_MSM
+ select PHY_QCOM_UFS
+ help
+ This selects the QCOM specific additions to UFSHCD platform driver.
+ UFS host on QCOM needs some vendor specific configuration before
+ accessing the hardware which includes PHY configuration and vendor
+ specific registers.
+
+ Select this if you have UFS controller on QCOM chipset.
+ If unsure, say N.
diff --git a/drivers/scsi/ufs/Makefile b/drivers/scsi/ufs/Makefile
index 1e5bd48457d6..8303bcce7a23 100644
--- a/drivers/scsi/ufs/Makefile
+++ b/drivers/scsi/ufs/Makefile
@@ -1,4 +1,5 @@
# UFSHCD makefile
+obj-$(CONFIG_SCSI_UFS_QCOM) += ufs-qcom.o
obj-$(CONFIG_SCSI_UFSHCD) += ufshcd.o
obj-$(CONFIG_SCSI_UFSHCD_PCI) += ufshcd-pci.o
obj-$(CONFIG_SCSI_UFSHCD_PLATFORM) += ufshcd-pltfrm.o
diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c
new file mode 100644
index 000000000000..9217af9bf734
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-qcom.c
@@ -0,0 +1,1004 @@
+/*
+ * Copyright (c) 2013-2015, 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/time.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/phy/phy.h>
+
+#include <linux/phy/phy-qcom-ufs.h>
+#include "ufshcd.h"
+#include "unipro.h"
+#include "ufs-qcom.h"
+#include "ufshci.h"
+
+static struct ufs_qcom_host *ufs_qcom_hosts[MAX_UFS_QCOM_HOSTS];
+
+static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result);
+static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
+ const char *speed_mode);
+static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote);
+
+static int ufs_qcom_get_connected_tx_lanes(struct ufs_hba *hba, u32 *tx_lanes)
+{
+ int err = 0;
+
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(PA_CONNECTEDTXDATALANES), tx_lanes);
+ if (err)
+ dev_err(hba->dev, "%s: couldn't read PA_CONNECTEDTXDATALANES %d\n",
+ __func__, err);
+
+ return err;
+}
+
+static int ufs_qcom_host_clk_get(struct device *dev,
+ const char *name, struct clk **clk_out)
+{
+ struct clk *clk;
+ int err = 0;
+
+ clk = devm_clk_get(dev, name);
+ if (IS_ERR(clk)) {
+ err = PTR_ERR(clk);
+ dev_err(dev, "%s: failed to get %s err %d",
+ __func__, name, err);
+ } else {
+ *clk_out = clk;
+ }
+
+ return err;
+}
+
+static int ufs_qcom_host_clk_enable(struct device *dev,
+ const char *name, struct clk *clk)
+{
+ int err = 0;
+
+ err = clk_prepare_enable(clk);
+ if (err)
+ dev_err(dev, "%s: %s enable failed %d\n", __func__, name, err);
+
+ return err;
+}
+
+static void ufs_qcom_disable_lane_clks(struct ufs_qcom_host *host)
+{
+ if (!host->is_lane_clks_enabled)
+ return;
+
+ clk_disable_unprepare(host->tx_l1_sync_clk);
+ clk_disable_unprepare(host->tx_l0_sync_clk);
+ clk_disable_unprepare(host->rx_l1_sync_clk);
+ clk_disable_unprepare(host->rx_l0_sync_clk);
+
+ host->is_lane_clks_enabled = false;
+}
+
+static int ufs_qcom_enable_lane_clks(struct ufs_qcom_host *host)
+{
+ int err = 0;
+ struct device *dev = host->hba->dev;
+
+ if (host->is_lane_clks_enabled)
+ return 0;
+
+ err = ufs_qcom_host_clk_enable(dev, "rx_lane0_sync_clk",
+ host->rx_l0_sync_clk);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_host_clk_enable(dev, "tx_lane0_sync_clk",
+ host->tx_l0_sync_clk);
+ if (err)
+ goto disable_rx_l0;
+
+ err = ufs_qcom_host_clk_enable(dev, "rx_lane1_sync_clk",
+ host->rx_l1_sync_clk);
+ if (err)
+ goto disable_tx_l0;
+
+ err = ufs_qcom_host_clk_enable(dev, "tx_lane1_sync_clk",
+ host->tx_l1_sync_clk);
+ if (err)
+ goto disable_rx_l1;
+
+ host->is_lane_clks_enabled = true;
+ goto out;
+
+disable_rx_l1:
+ clk_disable_unprepare(host->rx_l1_sync_clk);
+disable_tx_l0:
+ clk_disable_unprepare(host->tx_l0_sync_clk);
+disable_rx_l0:
+ clk_disable_unprepare(host->rx_l0_sync_clk);
+out:
+ return err;
+}
+
+static int ufs_qcom_init_lane_clks(struct ufs_qcom_host *host)
+{
+ int err = 0;
+ struct device *dev = host->hba->dev;
+
+ err = ufs_qcom_host_clk_get(dev,
+ "rx_lane0_sync_clk", &host->rx_l0_sync_clk);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_host_clk_get(dev,
+ "tx_lane0_sync_clk", &host->tx_l0_sync_clk);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_host_clk_get(dev, "rx_lane1_sync_clk",
+ &host->rx_l1_sync_clk);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_host_clk_get(dev, "tx_lane1_sync_clk",
+ &host->tx_l1_sync_clk);
+out:
+ return err;
+}
+
+static int ufs_qcom_link_startup_post_change(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ struct phy *phy = host->generic_phy;
+ u32 tx_lanes;
+ int err = 0;
+
+ err = ufs_qcom_get_connected_tx_lanes(hba, &tx_lanes);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_phy_set_tx_lane_enable(phy, tx_lanes);
+ if (err)
+ dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable failed\n",
+ __func__);
+
+out:
+ return err;
+}
+
+static int ufs_qcom_check_hibern8(struct ufs_hba *hba)
+{
+ int err;
+ u32 tx_fsm_val = 0;
+ unsigned long timeout = jiffies + msecs_to_jiffies(HBRN8_POLL_TOUT_MS);
+
+ do {
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val);
+ if (err || tx_fsm_val == TX_FSM_HIBERN8)
+ break;
+
+ /* sleep for max. 200us */
+ usleep_range(100, 200);
+ } while (time_before(jiffies, timeout));
+
+ /*
+ * we might have scheduled out for long during polling so
+ * check the state again.
+ */
+ if (time_after(jiffies, timeout))
+ err = ufshcd_dme_get(hba,
+ UIC_ARG_MIB(MPHY_TX_FSM_STATE), &tx_fsm_val);
+
+ if (err) {
+ dev_err(hba->dev, "%s: unable to get TX_FSM_STATE, err %d\n",
+ __func__, err);
+ } else if (tx_fsm_val != TX_FSM_HIBERN8) {
+ err = tx_fsm_val;
+ dev_err(hba->dev, "%s: invalid TX_FSM_STATE = %d\n",
+ __func__, err);
+ }
+
+ return err;
+}
+
+static int ufs_qcom_power_up_sequence(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ struct phy *phy = host->generic_phy;
+ int ret = 0;
+ u8 major;
+ u16 minor, step;
+ bool is_rate_B = (UFS_QCOM_LIMIT_HS_RATE == PA_HS_MODE_B)
+ ? true : false;
+
+ /* Assert PHY reset and apply PHY calibration values */
+ ufs_qcom_assert_reset(hba);
+ /* provide 1ms delay to let the reset pulse propagate */
+ usleep_range(1000, 1100);
+
+ ufs_qcom_get_controller_revision(hba, &major, &minor, &step);
+ ufs_qcom_phy_save_controller_version(phy, major, minor, step);
+ ret = ufs_qcom_phy_calibrate_phy(phy, is_rate_B);
+ if (ret) {
+ dev_err(hba->dev, "%s: ufs_qcom_phy_calibrate_phy() failed, ret = %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ /* De-assert PHY reset and start serdes */
+ ufs_qcom_deassert_reset(hba);
+
+ /*
+ * after reset deassertion, phy will need all ref clocks,
+ * voltage, current to settle down before starting serdes.
+ */
+ usleep_range(1000, 1100);
+ ret = ufs_qcom_phy_start_serdes(phy);
+ if (ret) {
+ dev_err(hba->dev, "%s: ufs_qcom_phy_start_serdes() failed, ret = %d\n",
+ __func__, ret);
+ goto out;
+ }
+
+ ret = ufs_qcom_phy_is_pcs_ready(phy);
+ if (ret)
+ dev_err(hba->dev, "%s: is_physical_coding_sublayer_ready() failed, ret = %d\n",
+ __func__, ret);
+
+out:
+ return ret;
+}
+
+/*
+ * The UTP controller has a number of internal clock gating cells (CGCs).
+ * Internal hardware sub-modules within the UTP controller control the CGCs.
+ * Hardware CGCs disable the clock to inactivate UTP sub-modules not involved
+ * in a specific operation, UTP controller CGCs are by default disabled and
+ * this function enables them (after every UFS link startup) to save some power
+ * leakage.
+ */
+static void ufs_qcom_enable_hw_clk_gating(struct ufs_hba *hba)
+{
+ ufshcd_writel(hba,
+ ufshcd_readl(hba, REG_UFS_CFG2) | REG_UFS_CFG2_CGC_EN_ALL,
+ REG_UFS_CFG2);
+
+ /* Ensure that HW clock gating is enabled before next operations */
+ mb();
+}
+
+static int ufs_qcom_hce_enable_notify(struct ufs_hba *hba, bool status)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ int err = 0;
+
+ switch (status) {
+ case PRE_CHANGE:
+ ufs_qcom_power_up_sequence(hba);
+ /*
+ * The PHY PLL output is the source of tx/rx lane symbol
+ * clocks, hence, enable the lane clocks only after PHY
+ * is initialized.
+ */
+ err = ufs_qcom_enable_lane_clks(host);
+ break;
+ case POST_CHANGE:
+ /* check if UFS PHY moved from DISABLED to HIBERN8 */
+ err = ufs_qcom_check_hibern8(hba);
+ ufs_qcom_enable_hw_clk_gating(hba);
+
+ break;
+ default:
+ dev_err(hba->dev, "%s: invalid status %d\n", __func__, status);
+ err = -EINVAL;
+ break;
+ }
+ return err;
+}
+
+/**
+ * Returns non-zero for success (which rate of core_clk) and 0
+ * in case of a failure
+ */
+static unsigned long
+ufs_qcom_cfg_timers(struct ufs_hba *hba, u32 gear, u32 hs, u32 rate)
+{
+ struct ufs_clk_info *clki;
+ u32 core_clk_period_in_ns;
+ u32 tx_clk_cycles_per_us = 0;
+ unsigned long core_clk_rate = 0;
+ u32 core_clk_cycles_per_us = 0;
+
+ static u32 pwm_fr_table[][2] = {
+ {UFS_PWM_G1, 0x1},
+ {UFS_PWM_G2, 0x1},
+ {UFS_PWM_G3, 0x1},
+ {UFS_PWM_G4, 0x1},
+ };
+
+ static u32 hs_fr_table_rA[][2] = {
+ {UFS_HS_G1, 0x1F},
+ {UFS_HS_G2, 0x3e},
+ };
+
+ static u32 hs_fr_table_rB[][2] = {
+ {UFS_HS_G1, 0x24},
+ {UFS_HS_G2, 0x49},
+ };
+
+ if (gear == 0) {
+ dev_err(hba->dev, "%s: invalid gear = %d\n", __func__, gear);
+ goto out_error;
+ }
+
+ list_for_each_entry(clki, &hba->clk_list_head, list) {
+ if (!strcmp(clki->name, "core_clk"))
+ core_clk_rate = clk_get_rate(clki->clk);
+ }
+
+ /* If frequency is smaller than 1MHz, set to 1MHz */
+ if (core_clk_rate < DEFAULT_CLK_RATE_HZ)
+ core_clk_rate = DEFAULT_CLK_RATE_HZ;
+
+ core_clk_cycles_per_us = core_clk_rate / USEC_PER_SEC;
+ ufshcd_writel(hba, core_clk_cycles_per_us, REG_UFS_SYS1CLK_1US);
+
+ core_clk_period_in_ns = NSEC_PER_SEC / core_clk_rate;
+ core_clk_period_in_ns <<= OFFSET_CLK_NS_REG;
+ core_clk_period_in_ns &= MASK_CLK_NS_REG;
+
+ switch (hs) {
+ case FASTAUTO_MODE:
+ case FAST_MODE:
+ if (rate == PA_HS_MODE_A) {
+ if (gear > ARRAY_SIZE(hs_fr_table_rA)) {
+ dev_err(hba->dev,
+ "%s: index %d exceeds table size %zu\n",
+ __func__, gear,
+ ARRAY_SIZE(hs_fr_table_rA));
+ goto out_error;
+ }
+ tx_clk_cycles_per_us = hs_fr_table_rA[gear-1][1];
+ } else if (rate == PA_HS_MODE_B) {
+ if (gear > ARRAY_SIZE(hs_fr_table_rB)) {
+ dev_err(hba->dev,
+ "%s: index %d exceeds table size %zu\n",
+ __func__, gear,
+ ARRAY_SIZE(hs_fr_table_rB));
+ goto out_error;
+ }
+ tx_clk_cycles_per_us = hs_fr_table_rB[gear-1][1];
+ } else {
+ dev_err(hba->dev, "%s: invalid rate = %d\n",
+ __func__, rate);
+ goto out_error;
+ }
+ break;
+ case SLOWAUTO_MODE:
+ case SLOW_MODE:
+ if (gear > ARRAY_SIZE(pwm_fr_table)) {
+ dev_err(hba->dev,
+ "%s: index %d exceeds table size %zu\n",
+ __func__, gear,
+ ARRAY_SIZE(pwm_fr_table));
+ goto out_error;
+ }
+ tx_clk_cycles_per_us = pwm_fr_table[gear-1][1];
+ break;
+ case UNCHANGED:
+ default:
+ dev_err(hba->dev, "%s: invalid mode = %d\n", __func__, hs);
+ goto out_error;
+ }
+
+ /* this register 2 fields shall be written at once */
+ ufshcd_writel(hba, core_clk_period_in_ns | tx_clk_cycles_per_us,
+ REG_UFS_TX_SYMBOL_CLK_NS_US);
+ goto out;
+
+out_error:
+ core_clk_rate = 0;
+out:
+ return core_clk_rate;
+}
+
+static int ufs_qcom_link_startup_notify(struct ufs_hba *hba, bool status)
+{
+ unsigned long core_clk_rate = 0;
+ u32 core_clk_cycles_per_100ms;
+
+ switch (status) {
+ case PRE_CHANGE:
+ core_clk_rate = ufs_qcom_cfg_timers(hba, UFS_PWM_G1,
+ SLOWAUTO_MODE, 0);
+ if (!core_clk_rate) {
+ dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
+ __func__);
+ return -EINVAL;
+ }
+ core_clk_cycles_per_100ms =
+ (core_clk_rate / MSEC_PER_SEC) * 100;
+ ufshcd_writel(hba, core_clk_cycles_per_100ms,
+ REG_UFS_PA_LINK_STARTUP_TIMER);
+ break;
+ case POST_CHANGE:
+ ufs_qcom_link_startup_post_change(hba);
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int ufs_qcom_suspend(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ struct phy *phy = host->generic_phy;
+ int ret = 0;
+
+ if (ufs_qcom_is_link_off(hba)) {
+ /*
+ * Disable the tx/rx lane symbol clocks before PHY is
+ * powered down as the PLL source should be disabled
+ * after downstream clocks are disabled.
+ */
+ ufs_qcom_disable_lane_clks(host);
+ phy_power_off(phy);
+
+ /* Assert PHY soft reset */
+ ufs_qcom_assert_reset(hba);
+ goto out;
+ }
+
+ /*
+ * If UniPro link is not active, PHY ref_clk, main PHY analog power
+ * rail and low noise analog power rail for PLL can be switched off.
+ */
+ if (!ufs_qcom_is_link_active(hba))
+ phy_power_off(phy);
+
+out:
+ return ret;
+}
+
+static int ufs_qcom_resume(struct ufs_hba *hba, enum ufs_pm_op pm_op)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ struct phy *phy = host->generic_phy;
+ int err;
+
+ err = phy_power_on(phy);
+ if (err) {
+ dev_err(hba->dev, "%s: failed enabling regs, err = %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ hba->is_sys_suspended = false;
+
+out:
+ return err;
+}
+
+struct ufs_qcom_dev_params {
+ u32 pwm_rx_gear; /* pwm rx gear to work in */
+ u32 pwm_tx_gear; /* pwm tx gear to work in */
+ u32 hs_rx_gear; /* hs rx gear to work in */
+ u32 hs_tx_gear; /* hs tx gear to work in */
+ u32 rx_lanes; /* number of rx lanes */
+ u32 tx_lanes; /* number of tx lanes */
+ u32 rx_pwr_pwm; /* rx pwm working pwr */
+ u32 tx_pwr_pwm; /* tx pwm working pwr */
+ u32 rx_pwr_hs; /* rx hs working pwr */
+ u32 tx_pwr_hs; /* tx hs working pwr */
+ u32 hs_rate; /* rate A/B to work in HS */
+ u32 desired_working_mode;
+};
+
+static int ufs_qcom_get_pwr_dev_param(struct ufs_qcom_dev_params *qcom_param,
+ struct ufs_pa_layer_attr *dev_max,
+ struct ufs_pa_layer_attr *agreed_pwr)
+{
+ int min_qcom_gear;
+ int min_dev_gear;
+ bool is_dev_sup_hs = false;
+ bool is_qcom_max_hs = false;
+
+ if (dev_max->pwr_rx == FAST_MODE)
+ is_dev_sup_hs = true;
+
+ if (qcom_param->desired_working_mode == FAST) {
+ is_qcom_max_hs = true;
+ min_qcom_gear = min_t(u32, qcom_param->hs_rx_gear,
+ qcom_param->hs_tx_gear);
+ } else {
+ min_qcom_gear = min_t(u32, qcom_param->pwm_rx_gear,
+ qcom_param->pwm_tx_gear);
+ }
+
+ /*
+ * device doesn't support HS but qcom_param->desired_working_mode is
+ * HS, thus device and qcom_param don't agree
+ */
+ if (!is_dev_sup_hs && is_qcom_max_hs) {
+ pr_err("%s: failed to agree on power mode (device doesn't support HS but requested power is HS)\n",
+ __func__);
+ return -ENOTSUPP;
+ } else if (is_dev_sup_hs && is_qcom_max_hs) {
+ /*
+ * since device supports HS, it supports FAST_MODE.
+ * since qcom_param->desired_working_mode is also HS
+ * then final decision (FAST/FASTAUTO) is done according
+ * to qcom_params as it is the restricting factor
+ */
+ agreed_pwr->pwr_rx = agreed_pwr->pwr_tx =
+ qcom_param->rx_pwr_hs;
+ } else {
+ /*
+ * here qcom_param->desired_working_mode is PWM.
+ * it doesn't matter whether device supports HS or PWM,
+ * in both cases qcom_param->desired_working_mode will
+ * determine the mode
+ */
+ agreed_pwr->pwr_rx = agreed_pwr->pwr_tx =
+ qcom_param->rx_pwr_pwm;
+ }
+
+ /*
+ * we would like tx to work in the minimum number of lanes
+ * between device capability and vendor preferences.
+ * the same decision will be made for rx
+ */
+ agreed_pwr->lane_tx = min_t(u32, dev_max->lane_tx,
+ qcom_param->tx_lanes);
+ agreed_pwr->lane_rx = min_t(u32, dev_max->lane_rx,
+ qcom_param->rx_lanes);
+
+ /* device maximum gear is the minimum between device rx and tx gears */
+ min_dev_gear = min_t(u32, dev_max->gear_rx, dev_max->gear_tx);
+
+ /*
+ * if both device capabilities and vendor pre-defined preferences are
+ * both HS or both PWM then set the minimum gear to be the chosen
+ * working gear.
+ * if one is PWM and one is HS then the one that is PWM get to decide
+ * what is the gear, as it is the one that also decided previously what
+ * pwr the device will be configured to.
+ */
+ if ((is_dev_sup_hs && is_qcom_max_hs) ||
+ (!is_dev_sup_hs && !is_qcom_max_hs))
+ agreed_pwr->gear_rx = agreed_pwr->gear_tx =
+ min_t(u32, min_dev_gear, min_qcom_gear);
+ else if (!is_dev_sup_hs)
+ agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_dev_gear;
+ else
+ agreed_pwr->gear_rx = agreed_pwr->gear_tx = min_qcom_gear;
+
+ agreed_pwr->hs_rate = qcom_param->hs_rate;
+ return 0;
+}
+
+static int ufs_qcom_update_bus_bw_vote(struct ufs_qcom_host *host)
+{
+ int vote;
+ int err = 0;
+ char mode[BUS_VECTOR_NAME_LEN];
+
+ ufs_qcom_get_speed_mode(&host->dev_req_params, mode);
+
+ vote = ufs_qcom_get_bus_vote(host, mode);
+ if (vote >= 0)
+ err = ufs_qcom_set_bus_vote(host, vote);
+ else
+ err = vote;
+
+ if (err)
+ dev_err(host->hba->dev, "%s: failed %d\n", __func__, err);
+ else
+ host->bus_vote.saved_vote = vote;
+ return err;
+}
+
+static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba,
+ bool status,
+ struct ufs_pa_layer_attr *dev_max_params,
+ struct ufs_pa_layer_attr *dev_req_params)
+{
+ u32 val;
+ struct ufs_qcom_host *host = hba->priv;
+ struct phy *phy = host->generic_phy;
+ struct ufs_qcom_dev_params ufs_qcom_cap;
+ int ret = 0;
+ int res = 0;
+
+ if (!dev_req_params) {
+ pr_err("%s: incoming dev_req_params is NULL\n", __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ switch (status) {
+ case PRE_CHANGE:
+ ufs_qcom_cap.tx_lanes = UFS_QCOM_LIMIT_NUM_LANES_TX;
+ ufs_qcom_cap.rx_lanes = UFS_QCOM_LIMIT_NUM_LANES_RX;
+ ufs_qcom_cap.hs_rx_gear = UFS_QCOM_LIMIT_HSGEAR_RX;
+ ufs_qcom_cap.hs_tx_gear = UFS_QCOM_LIMIT_HSGEAR_TX;
+ ufs_qcom_cap.pwm_rx_gear = UFS_QCOM_LIMIT_PWMGEAR_RX;
+ ufs_qcom_cap.pwm_tx_gear = UFS_QCOM_LIMIT_PWMGEAR_TX;
+ ufs_qcom_cap.rx_pwr_pwm = UFS_QCOM_LIMIT_RX_PWR_PWM;
+ ufs_qcom_cap.tx_pwr_pwm = UFS_QCOM_LIMIT_TX_PWR_PWM;
+ ufs_qcom_cap.rx_pwr_hs = UFS_QCOM_LIMIT_RX_PWR_HS;
+ ufs_qcom_cap.tx_pwr_hs = UFS_QCOM_LIMIT_TX_PWR_HS;
+ ufs_qcom_cap.hs_rate = UFS_QCOM_LIMIT_HS_RATE;
+ ufs_qcom_cap.desired_working_mode =
+ UFS_QCOM_LIMIT_DESIRED_MODE;
+
+ ret = ufs_qcom_get_pwr_dev_param(&ufs_qcom_cap,
+ dev_max_params,
+ dev_req_params);
+ if (ret) {
+ pr_err("%s: failed to determine capabilities\n",
+ __func__);
+ goto out;
+ }
+
+ break;
+ case POST_CHANGE:
+ if (!ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
+ dev_req_params->pwr_rx,
+ dev_req_params->hs_rate)) {
+ dev_err(hba->dev, "%s: ufs_qcom_cfg_timers() failed\n",
+ __func__);
+ /*
+ * we return error code at the end of the routine,
+ * but continue to configure UFS_PHY_TX_LANE_ENABLE
+ * and bus voting as usual
+ */
+ ret = -EINVAL;
+ }
+
+ val = ~(MAX_U32 << dev_req_params->lane_tx);
+ res = ufs_qcom_phy_set_tx_lane_enable(phy, val);
+ if (res) {
+ dev_err(hba->dev, "%s: ufs_qcom_phy_set_tx_lane_enable() failed res = %d\n",
+ __func__, res);
+ ret = res;
+ }
+
+ /* cache the power mode parameters to use internally */
+ memcpy(&host->dev_req_params,
+ dev_req_params, sizeof(*dev_req_params));
+ ufs_qcom_update_bus_bw_vote(host);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+out:
+ return ret;
+}
+
+/**
+ * ufs_qcom_advertise_quirks - advertise the known QCOM UFS controller quirks
+ * @hba: host controller instance
+ *
+ * QCOM UFS host controller might have some non standard behaviours (quirks)
+ * than what is specified by UFSHCI specification. Advertise all such
+ * quirks to standard UFS host controller driver so standard takes them into
+ * account.
+ */
+static void ufs_qcom_advertise_quirks(struct ufs_hba *hba)
+{
+ u8 major;
+ u16 minor, step;
+
+ ufs_qcom_get_controller_revision(hba, &major, &minor, &step);
+
+ /*
+ * TBD
+ * here we should be advertising controller quirks according to
+ * controller version.
+ */
+}
+
+static int ufs_qcom_get_bus_vote(struct ufs_qcom_host *host,
+ const char *speed_mode)
+{
+ struct device *dev = host->hba->dev;
+ struct device_node *np = dev->of_node;
+ int err;
+ const char *key = "qcom,bus-vector-names";
+
+ if (!speed_mode) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (host->bus_vote.is_max_bw_needed && !!strcmp(speed_mode, "MIN"))
+ err = of_property_match_string(np, key, "MAX");
+ else
+ err = of_property_match_string(np, key, speed_mode);
+
+out:
+ if (err < 0)
+ dev_err(dev, "%s: Invalid %s mode %d\n",
+ __func__, speed_mode, err);
+ return err;
+}
+
+static int ufs_qcom_set_bus_vote(struct ufs_qcom_host *host, int vote)
+{
+ int err = 0;
+
+ if (vote != host->bus_vote.curr_vote)
+ host->bus_vote.curr_vote = vote;
+
+ return err;
+}
+
+static void ufs_qcom_get_speed_mode(struct ufs_pa_layer_attr *p, char *result)
+{
+ int gear = max_t(u32, p->gear_rx, p->gear_tx);
+ int lanes = max_t(u32, p->lane_rx, p->lane_tx);
+ int pwr;
+
+ /* default to PWM Gear 1, Lane 1 if power mode is not initialized */
+ if (!gear)
+ gear = 1;
+
+ if (!lanes)
+ lanes = 1;
+
+ if (!p->pwr_rx && !p->pwr_tx) {
+ pwr = SLOWAUTO_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "MIN");
+ } else if (p->pwr_rx == FAST_MODE || p->pwr_rx == FASTAUTO_MODE ||
+ p->pwr_tx == FAST_MODE || p->pwr_tx == FASTAUTO_MODE) {
+ pwr = FAST_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "%s_R%s_G%d_L%d", "HS",
+ p->hs_rate == PA_HS_MODE_B ? "B" : "A", gear, lanes);
+ } else {
+ pwr = SLOW_MODE;
+ snprintf(result, BUS_VECTOR_NAME_LEN, "%s_G%d_L%d",
+ "PWM", gear, lanes);
+ }
+}
+
+static int ufs_qcom_setup_clocks(struct ufs_hba *hba, bool on)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ int err = 0;
+ int vote = 0;
+
+ /*
+ * In case ufs_qcom_init() is not yet done, simply ignore.
+ * This ufs_qcom_setup_clocks() shall be called from
+ * ufs_qcom_init() after init is done.
+ */
+ if (!host)
+ return 0;
+
+ if (on) {
+ err = ufs_qcom_phy_enable_iface_clk(host->generic_phy);
+ if (err)
+ goto out;
+
+ err = ufs_qcom_phy_enable_ref_clk(host->generic_phy);
+ if (err) {
+ dev_err(hba->dev, "%s enable phy ref clock failed, err=%d\n",
+ __func__, err);
+ ufs_qcom_phy_disable_iface_clk(host->generic_phy);
+ goto out;
+ }
+ /* enable the device ref clock */
+ ufs_qcom_phy_enable_dev_ref_clk(host->generic_phy);
+ vote = host->bus_vote.saved_vote;
+ if (vote == host->bus_vote.min_bw_vote)
+ ufs_qcom_update_bus_bw_vote(host);
+ } else {
+ /* M-PHY RMMI interface clocks can be turned off */
+ ufs_qcom_phy_disable_iface_clk(host->generic_phy);
+ if (!ufs_qcom_is_link_active(hba)) {
+ /* turn off UFS local PHY ref_clk */
+ ufs_qcom_phy_disable_ref_clk(host->generic_phy);
+ /* disable device ref_clk */
+ ufs_qcom_phy_disable_dev_ref_clk(host->generic_phy);
+ }
+ vote = host->bus_vote.min_bw_vote;
+ }
+
+ err = ufs_qcom_set_bus_vote(host, vote);
+ if (err)
+ dev_err(hba->dev, "%s: set bus vote failed %d\n",
+ __func__, err);
+
+out:
+ return err;
+}
+
+static ssize_t
+show_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_qcom_host *host = hba->priv;
+
+ return snprintf(buf, PAGE_SIZE, "%u\n",
+ host->bus_vote.is_max_bw_needed);
+}
+
+static ssize_t
+store_ufs_to_mem_max_bus_bw(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct ufs_hba *hba = dev_get_drvdata(dev);
+ struct ufs_qcom_host *host = hba->priv;
+ uint32_t value;
+
+ if (!kstrtou32(buf, 0, &value)) {
+ host->bus_vote.is_max_bw_needed = !!value;
+ ufs_qcom_update_bus_bw_vote(host);
+ }
+
+ return count;
+}
+
+static int ufs_qcom_bus_register(struct ufs_qcom_host *host)
+{
+ int err;
+ struct device *dev = host->hba->dev;
+ struct device_node *np = dev->of_node;
+
+ err = of_property_count_strings(np, "qcom,bus-vector-names");
+ if (err < 0 ) {
+ dev_err(dev, "%s: qcom,bus-vector-names not specified correctly %d\n",
+ __func__, err);
+ goto out;
+ }
+
+ /* cache the vote index for minimum and maximum bandwidth */
+ host->bus_vote.min_bw_vote = ufs_qcom_get_bus_vote(host, "MIN");
+ host->bus_vote.max_bw_vote = ufs_qcom_get_bus_vote(host, "MAX");
+
+ host->bus_vote.max_bus_bw.show = show_ufs_to_mem_max_bus_bw;
+ host->bus_vote.max_bus_bw.store = store_ufs_to_mem_max_bus_bw;
+ sysfs_attr_init(&host->bus_vote.max_bus_bw.attr);
+ host->bus_vote.max_bus_bw.attr.name = "max_bus_bw";
+ host->bus_vote.max_bus_bw.attr.mode = S_IRUGO | S_IWUSR;
+ err = device_create_file(dev, &host->bus_vote.max_bus_bw);
+out:
+ return err;
+}
+
+#define ANDROID_BOOT_DEV_MAX 30
+static char android_boot_dev[ANDROID_BOOT_DEV_MAX];
+static int get_android_boot_dev(char *str)
+{
+ strlcpy(android_boot_dev, str, ANDROID_BOOT_DEV_MAX);
+ return 1;
+}
+__setup("androidboot.bootdevice=", get_android_boot_dev);
+
+/**
+ * ufs_qcom_init - bind phy with controller
+ * @hba: host controller instance
+ *
+ * Binds PHY with controller and powers up PHY enabling clocks
+ * and regulators.
+ *
+ * Returns -EPROBE_DEFER if binding fails, returns negative error
+ * on phy power up failure and returns zero on success.
+ */
+static int ufs_qcom_init(struct ufs_hba *hba)
+{
+ int err;
+ struct device *dev = hba->dev;
+ struct ufs_qcom_host *host;
+
+ if (strlen(android_boot_dev) && strcmp(android_boot_dev, dev_name(dev)))
+ return -ENODEV;
+
+ host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
+ if (!host) {
+ err = -ENOMEM;
+ dev_err(dev, "%s: no memory for qcom ufs host\n", __func__);
+ goto out;
+ }
+
+ host->hba = hba;
+ hba->priv = (void *)host;
+
+ host->generic_phy = devm_phy_get(dev, "ufsphy");
+
+ if (IS_ERR(host->generic_phy)) {
+ err = PTR_ERR(host->generic_phy);
+ dev_err(dev, "%s: PHY get failed %d\n", __func__, err);
+ goto out;
+ }
+
+ err = ufs_qcom_bus_register(host);
+ if (err)
+ goto out_host_free;
+
+ phy_init(host->generic_phy);
+ err = phy_power_on(host->generic_phy);
+ if (err)
+ goto out_unregister_bus;
+
+ err = ufs_qcom_init_lane_clks(host);
+ if (err)
+ goto out_disable_phy;
+
+ ufs_qcom_advertise_quirks(hba);
+
+ hba->caps |= UFSHCD_CAP_CLK_GATING | UFSHCD_CAP_CLK_SCALING;
+ hba->caps |= UFSHCD_CAP_AUTO_BKOPS_SUSPEND;
+
+ ufs_qcom_setup_clocks(hba, true);
+
+ if (hba->dev->id < MAX_UFS_QCOM_HOSTS)
+ ufs_qcom_hosts[hba->dev->id] = host;
+
+ goto out;
+
+out_disable_phy:
+ phy_power_off(host->generic_phy);
+out_unregister_bus:
+ phy_exit(host->generic_phy);
+out_host_free:
+ devm_kfree(dev, host);
+ hba->priv = NULL;
+out:
+ return err;
+}
+
+static void ufs_qcom_exit(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = hba->priv;
+
+ ufs_qcom_disable_lane_clks(host);
+ phy_power_off(host->generic_phy);
+}
+
+static
+void ufs_qcom_clk_scale_notify(struct ufs_hba *hba)
+{
+ struct ufs_qcom_host *host = hba->priv;
+ struct ufs_pa_layer_attr *dev_req_params = &host->dev_req_params;
+
+ if (!dev_req_params)
+ return;
+
+ ufs_qcom_cfg_timers(hba, dev_req_params->gear_rx,
+ dev_req_params->pwr_rx,
+ dev_req_params->hs_rate);
+}
+
+/**
+ * struct ufs_hba_qcom_vops - UFS QCOM specific variant operations
+ *
+ * The variant operations configure the necessary controller and PHY
+ * handshake during initialization.
+ */
+static const struct ufs_hba_variant_ops ufs_hba_qcom_vops = {
+ .name = "qcom",
+ .init = ufs_qcom_init,
+ .exit = ufs_qcom_exit,
+ .clk_scale_notify = ufs_qcom_clk_scale_notify,
+ .setup_clocks = ufs_qcom_setup_clocks,
+ .hce_enable_notify = ufs_qcom_hce_enable_notify,
+ .link_startup_notify = ufs_qcom_link_startup_notify,
+ .pwr_change_notify = ufs_qcom_pwr_change_notify,
+ .suspend = ufs_qcom_suspend,
+ .resume = ufs_qcom_resume,
+};
+EXPORT_SYMBOL(ufs_hba_qcom_vops);
diff --git a/drivers/scsi/ufs/ufs-qcom.h b/drivers/scsi/ufs/ufs-qcom.h
new file mode 100644
index 000000000000..9a6febd007df
--- /dev/null
+++ b/drivers/scsi/ufs/ufs-qcom.h
@@ -0,0 +1,170 @@
+/* Copyright (c) 2013-2015, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef UFS_QCOM_H_
+#define UFS_QCOM_H_
+
+#define MAX_UFS_QCOM_HOSTS 1
+#define MAX_U32 (~(u32)0)
+#define MPHY_TX_FSM_STATE 0x41
+#define TX_FSM_HIBERN8 0x1
+#define HBRN8_POLL_TOUT_MS 100
+#define DEFAULT_CLK_RATE_HZ 1000000
+#define BUS_VECTOR_NAME_LEN 32
+
+#define UFS_HW_VER_MAJOR_SHFT (28)
+#define UFS_HW_VER_MAJOR_MASK (0x000F << UFS_HW_VER_MAJOR_SHFT)
+#define UFS_HW_VER_MINOR_SHFT (16)
+#define UFS_HW_VER_MINOR_MASK (0x0FFF << UFS_HW_VER_MINOR_SHFT)
+#define UFS_HW_VER_STEP_SHFT (0)
+#define UFS_HW_VER_STEP_MASK (0xFFFF << UFS_HW_VER_STEP_SHFT)
+
+/* vendor specific pre-defined parameters */
+#define SLOW 1
+#define FAST 2
+
+#define UFS_QCOM_LIMIT_NUM_LANES_RX 2
+#define UFS_QCOM_LIMIT_NUM_LANES_TX 2
+#define UFS_QCOM_LIMIT_HSGEAR_RX UFS_HS_G2
+#define UFS_QCOM_LIMIT_HSGEAR_TX UFS_HS_G2
+#define UFS_QCOM_LIMIT_PWMGEAR_RX UFS_PWM_G4
+#define UFS_QCOM_LIMIT_PWMGEAR_TX UFS_PWM_G4
+#define UFS_QCOM_LIMIT_RX_PWR_PWM SLOW_MODE
+#define UFS_QCOM_LIMIT_TX_PWR_PWM SLOW_MODE
+#define UFS_QCOM_LIMIT_RX_PWR_HS FAST_MODE
+#define UFS_QCOM_LIMIT_TX_PWR_HS FAST_MODE
+#define UFS_QCOM_LIMIT_HS_RATE PA_HS_MODE_B
+#define UFS_QCOM_LIMIT_DESIRED_MODE FAST
+
+/* QCOM UFS host controller vendor specific registers */
+enum {
+ REG_UFS_SYS1CLK_1US = 0xC0,
+ REG_UFS_TX_SYMBOL_CLK_NS_US = 0xC4,
+ REG_UFS_LOCAL_PORT_ID_REG = 0xC8,
+ REG_UFS_PA_ERR_CODE = 0xCC,
+ REG_UFS_RETRY_TIMER_REG = 0xD0,
+ REG_UFS_PA_LINK_STARTUP_TIMER = 0xD8,
+ REG_UFS_CFG1 = 0xDC,
+ REG_UFS_CFG2 = 0xE0,
+ REG_UFS_HW_VERSION = 0xE4,
+
+ UFS_DBG_RD_REG_UAWM = 0x100,
+ UFS_DBG_RD_REG_UARM = 0x200,
+ UFS_DBG_RD_REG_TXUC = 0x300,
+ UFS_DBG_RD_REG_RXUC = 0x400,
+ UFS_DBG_RD_REG_DFC = 0x500,
+ UFS_DBG_RD_REG_TRLUT = 0x600,
+ UFS_DBG_RD_REG_TMRLUT = 0x700,
+ UFS_UFS_DBG_RD_REG_OCSC = 0x800,
+
+ UFS_UFS_DBG_RD_DESC_RAM = 0x1500,
+ UFS_UFS_DBG_RD_PRDT_RAM = 0x1700,
+ UFS_UFS_DBG_RD_RESP_RAM = 0x1800,
+ UFS_UFS_DBG_RD_EDTL_RAM = 0x1900,
+};
+
+/* bit definitions for REG_UFS_CFG2 register */
+#define UAWM_HW_CGC_EN (1 << 0)
+#define UARM_HW_CGC_EN (1 << 1)
+#define TXUC_HW_CGC_EN (1 << 2)
+#define RXUC_HW_CGC_EN (1 << 3)
+#define DFC_HW_CGC_EN (1 << 4)
+#define TRLUT_HW_CGC_EN (1 << 5)
+#define TMRLUT_HW_CGC_EN (1 << 6)
+#define OCSC_HW_CGC_EN (1 << 7)
+
+#define REG_UFS_CFG2_CGC_EN_ALL (UAWM_HW_CGC_EN | UARM_HW_CGC_EN |\
+ TXUC_HW_CGC_EN | RXUC_HW_CGC_EN |\
+ DFC_HW_CGC_EN | TRLUT_HW_CGC_EN |\
+ TMRLUT_HW_CGC_EN | OCSC_HW_CGC_EN)
+
+/* bit offset */
+enum {
+ OFFSET_UFS_PHY_SOFT_RESET = 1,
+ OFFSET_CLK_NS_REG = 10,
+};
+
+/* bit masks */
+enum {
+ MASK_UFS_PHY_SOFT_RESET = 0x2,
+ MASK_TX_SYMBOL_CLK_1US_REG = 0x3FF,
+ MASK_CLK_NS_REG = 0xFFFC00,
+};
+
+enum ufs_qcom_phy_init_type {
+ UFS_PHY_INIT_FULL,
+ UFS_PHY_INIT_CFG_RESTORE,
+};
+
+static inline void
+ufs_qcom_get_controller_revision(struct ufs_hba *hba,
+ u8 *major, u16 *minor, u16 *step)
+{
+ u32 ver = ufshcd_readl(hba, REG_UFS_HW_VERSION);
+
+ *major = (ver & UFS_HW_VER_MAJOR_MASK) >> UFS_HW_VER_MAJOR_SHFT;
+ *minor = (ver & UFS_HW_VER_MINOR_MASK) >> UFS_HW_VER_MINOR_SHFT;
+ *step = (ver & UFS_HW_VER_STEP_MASK) >> UFS_HW_VER_STEP_SHFT;
+};
+
+static inline void ufs_qcom_assert_reset(struct ufs_hba *hba)
+{
+ ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
+ 1 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
+
+ /*
+ * Make sure assertion of ufs phy reset is written to
+ * register before returning
+ */
+ mb();
+}
+
+static inline void ufs_qcom_deassert_reset(struct ufs_hba *hba)
+{
+ ufshcd_rmwl(hba, MASK_UFS_PHY_SOFT_RESET,
+ 0 << OFFSET_UFS_PHY_SOFT_RESET, REG_UFS_CFG1);
+
+ /*
+ * Make sure de-assertion of ufs phy reset is written to
+ * register before returning
+ */
+ mb();
+}
+
+struct ufs_qcom_bus_vote {
+ uint32_t client_handle;
+ uint32_t curr_vote;
+ int min_bw_vote;
+ int max_bw_vote;
+ int saved_vote;
+ bool is_max_bw_needed;
+ struct device_attribute max_bus_bw;
+};
+
+struct ufs_qcom_host {
+ struct phy *generic_phy;
+ struct ufs_hba *hba;
+ struct ufs_qcom_bus_vote bus_vote;
+ struct ufs_pa_layer_attr dev_req_params;
+ struct clk *rx_l0_sync_clk;
+ struct clk *tx_l0_sync_clk;
+ struct clk *rx_l1_sync_clk;
+ struct clk *tx_l1_sync_clk;
+ bool is_lane_clks_enabled;
+};
+
+#define ufs_qcom_is_link_off(hba) ufshcd_is_link_off(hba)
+#define ufs_qcom_is_link_active(hba) ufshcd_is_link_active(hba)
+#define ufs_qcom_is_link_hibern8(hba) ufshcd_is_link_hibern8(hba)
+
+#endif /* UFS_QCOM_H_ */
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 2e4614b9dddf..5d60a868830d 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -4714,10 +4714,8 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
sdev_printk(KERN_WARNING, sdp,
"START_STOP failed for power mode: %d, result %x\n",
pwr_mode, ret);
- if (driver_byte(ret) & DRIVER_SENSE) {
- scsi_show_sense_hdr(sdp, NULL, &sshdr);
- scsi_show_extd_sense(sdp, NULL, sshdr.asc, sshdr.ascq);
- }
+ if (driver_byte(ret) & DRIVER_SENSE)
+ scsi_print_sense_hdr(sdp, NULL, &sshdr);
}
if (!ret)
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index c52bb5dfaedb..f164f24a4a55 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -950,6 +950,12 @@ static int virtscsi_probe(struct virtio_device *vdev)
u32 num_queues;
struct scsi_host_template *hostt;
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
/* We need to know how many queues before we allocate. */
num_queues = virtscsi_config_get(vdev, num_queues) ? : 1;
diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c
index c0506de4f3b6..9e09da412b92 100644
--- a/drivers/scsi/wd33c93.c
+++ b/drivers/scsi/wd33c93.c
@@ -2143,22 +2143,22 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
seq_printf(m, "\nclock_freq=%02x no_sync=%02x no_dma=%d"
" dma_mode=%02x fast=%d",
hd->clock_freq, hd->no_sync, hd->no_dma, hd->dma_mode, hd->fast);
- seq_printf(m, "\nsync_xfer[] = ");
+ seq_puts(m, "\nsync_xfer[] = ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%02x", hd->sync_xfer[x]);
- seq_printf(m, "\nsync_stat[] = ");
+ seq_puts(m, "\nsync_stat[] = ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%02x", hd->sync_stat[x]);
}
#ifdef PROC_STATISTICS
if (hd->proc & PR_STATISTICS) {
- seq_printf(m, "\ncommands issued: ");
+ seq_puts(m, "\ncommands issued: ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%ld", hd->cmd_cnt[x]);
- seq_printf(m, "\ndisconnects allowed:");
+ seq_puts(m, "\ndisconnects allowed:");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%ld", hd->disc_allowed_cnt[x]);
- seq_printf(m, "\ndisconnects done: ");
+ seq_puts(m, "\ndisconnects done: ");
for (x = 0; x < 7; x++)
seq_printf(m, "\t%ld", hd->disc_done_cnt[x]);
seq_printf(m,
@@ -2167,7 +2167,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
}
#endif
if (hd->proc & PR_CONNECTED) {
- seq_printf(m, "\nconnected: ");
+ seq_puts(m, "\nconnected: ");
if (hd->connected) {
cmd = (struct scsi_cmnd *) hd->connected;
seq_printf(m, " %d:%llu(%02x)",
@@ -2175,7 +2175,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
}
}
if (hd->proc & PR_INPUTQ) {
- seq_printf(m, "\ninput_Q: ");
+ seq_puts(m, "\ninput_Q: ");
cmd = (struct scsi_cmnd *) hd->input_Q;
while (cmd) {
seq_printf(m, " %d:%llu(%02x)",
@@ -2184,7 +2184,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
}
}
if (hd->proc & PR_DISCQ) {
- seq_printf(m, "\ndisconnected_Q:");
+ seq_puts(m, "\ndisconnected_Q:");
cmd = (struct scsi_cmnd *) hd->disconnected_Q;
while (cmd) {
seq_printf(m, " %d:%llu(%02x)",
@@ -2192,7 +2192,7 @@ wd33c93_show_info(struct seq_file *m, struct Scsi_Host *instance)
cmd = (struct scsi_cmnd *) cmd->host_scribble;
}
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
spin_unlock_irq(&hd->lock);
#endif /* PROC_INTERFACE */
return 0;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index f94d73611ab4..0c0f17b9a3eb 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1295,9 +1295,6 @@ static void wd7000_revision(Adapter * host)
}
-#undef SPRINTF
-#define SPRINTF(args...) { seq_printf(m, ## args); }
-
static int wd7000_set_info(struct Scsi_Host *host, char *buffer, int length)
{
dprintk("Buffer = <%.*s>, length = %d\n", length, buffer, length);
@@ -1320,43 +1317,43 @@ static int wd7000_show_info(struct seq_file *m, struct Scsi_Host *host)
#endif
spin_lock_irqsave(host->host_lock, flags);
- SPRINTF("Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
- SPRINTF(" IO base: 0x%x\n", adapter->iobase);
- SPRINTF(" IRQ: %d\n", adapter->irq);
- SPRINTF(" DMA channel: %d\n", adapter->dma);
- SPRINTF(" Interrupts: %d\n", adapter->int_counter);
- SPRINTF(" BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125);
- SPRINTF(" BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
+ seq_printf(m, "Host scsi%d: Western Digital WD-7000 (rev %d.%d)\n", host->host_no, adapter->rev1, adapter->rev2);
+ seq_printf(m, " IO base: 0x%x\n", adapter->iobase);
+ seq_printf(m, " IRQ: %d\n", adapter->irq);
+ seq_printf(m, " DMA channel: %d\n", adapter->dma);
+ seq_printf(m, " Interrupts: %d\n", adapter->int_counter);
+ seq_printf(m, " BUS_ON time: %d nanoseconds\n", adapter->bus_on * 125);
+ seq_printf(m, " BUS_OFF time: %d nanoseconds\n", adapter->bus_off * 125);
#ifdef WD7000_DEBUG
ogmbs = adapter->mb.ogmb;
icmbs = adapter->mb.icmb;
- SPRINTF("\nControl port value: 0x%x\n", adapter->control);
- SPRINTF("Incoming mailbox:\n");
- SPRINTF(" size: %d\n", ICMB_CNT);
- SPRINTF(" queued messages: ");
+ seq_printf(m, "\nControl port value: 0x%x\n", adapter->control);
+ seq_puts(m, "Incoming mailbox:\n");
+ seq_printf(m, " size: %d\n", ICMB_CNT);
+ seq_puts(m, " queued messages: ");
for (i = count = 0; i < ICMB_CNT; i++)
if (icmbs[i].status) {
count++;
- SPRINTF("0x%x ", i);
+ seq_printf(m, "0x%x ", i);
}
- SPRINTF(count ? "\n" : "none\n");
+ seq_puts(m, count ? "\n" : "none\n");
- SPRINTF("Outgoing mailbox:\n");
- SPRINTF(" size: %d\n", OGMB_CNT);
- SPRINTF(" next message: 0x%x\n", adapter->next_ogmb);
- SPRINTF(" queued messages: ");
+ seq_puts(m, "Outgoing mailbox:\n");
+ seq_printf(m, " size: %d\n", OGMB_CNT);
+ seq_printf(m, " next message: 0x%x\n", adapter->next_ogmb);
+ seq_puts(m, " queued messages: ");
for (i = count = 0; i < OGMB_CNT; i++)
if (ogmbs[i].status) {
count++;
- SPRINTF("0x%x ", i);
+ seq_printf(m, "0x%x ", i);
}
- SPRINTF(count ? "\n" : "none\n");
+ seq_puts(m, count ? "\n" : "none\n");
#endif
spin_unlock_irqrestore(host->host_lock, flags);
diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c
index 7702664d7ed3..289ad016d925 100644
--- a/drivers/scsi/wd719x.c
+++ b/drivers/scsi/wd719x.c
@@ -870,6 +870,7 @@ fail_free_params:
}
static struct scsi_host_template wd719x_template = {
+ .module = THIS_MODULE,
.name = "Western Digital 719x",
.queuecommand = wd719x_queuecommand,
.eh_abort_handler = wd719x_abort,
diff --git a/drivers/sfi/sfi_core.c b/drivers/sfi/sfi_core.c
index 1e824fb1649b..296db7a69c27 100644
--- a/drivers/sfi/sfi_core.c
+++ b/drivers/sfi/sfi_core.c
@@ -161,7 +161,7 @@ static int sfi_verify_table(struct sfi_table_header *table)
* Check for common case that we can re-use mapping to SYST,
* which requires syst_pa, syst_va to be initialized.
*/
-struct sfi_table_header *sfi_map_table(u64 pa)
+static struct sfi_table_header *sfi_map_table(u64 pa)
{
struct sfi_table_header *th;
u32 length;
@@ -189,7 +189,7 @@ struct sfi_table_header *sfi_map_table(u64 pa)
* Undoes effect of sfi_map_table() by unmapping table
* if it did not completely fit on same page as SYST.
*/
-void sfi_unmap_table(struct sfi_table_header *th)
+static void sfi_unmap_table(struct sfi_table_header *th)
{
if (!TABLE_ON_PAGE(syst_va, th, th->len))
sfi_unmap_memory(th, TABLE_ON_PAGE(th, th, th->len) ?
diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c
index f3ee439d6f0e..cd4c293f0dd0 100644
--- a/drivers/sh/pm_runtime.c
+++ b/drivers/sh/pm_runtime.c
@@ -81,7 +81,9 @@ static int __init sh_pm_runtime_init(void)
if (!of_machine_is_compatible("renesas,emev2") &&
!of_machine_is_compatible("renesas,r7s72100") &&
!of_machine_is_compatible("renesas,r8a73a4") &&
+#ifndef CONFIG_PM_GENERIC_DOMAINS_OF
!of_machine_is_compatible("renesas,r8a7740") &&
+#endif
!of_machine_is_compatible("renesas,r8a7778") &&
!of_machine_is_compatible("renesas,r8a7779") &&
!of_machine_is_compatible("renesas,r8a7790") &&
diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index 011a3363c265..c0d660f1aaac 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -81,6 +81,7 @@ static const struct of_device_id car_match[] __initconst = {
{ .compatible = "nvidia,tegra30-car", },
{ .compatible = "nvidia,tegra114-car", },
{ .compatible = "nvidia,tegra124-car", },
+ { .compatible = "nvidia,tegra132-car", },
{},
};
diff --git a/drivers/soc/tegra/fuse/fuse-tegra30.c b/drivers/soc/tegra/fuse/fuse-tegra30.c
index 8646fa920d8d..4d2f71bf65c5 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra30.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra30.c
@@ -56,7 +56,7 @@ struct tegra_fuse_info {
static void __iomem *fuse_base;
static struct clk *fuse_clk;
-static struct tegra_fuse_info *fuse_info;
+static const struct tegra_fuse_info *fuse_info;
u32 tegra30_fuse_readl(const unsigned int offset)
{
@@ -78,18 +78,18 @@ u32 tegra30_fuse_readl(const unsigned int offset)
return val;
}
-static struct tegra_fuse_info tegra30_info = {
+static const struct tegra_fuse_info tegra30_info = {
.size = 0x2a4,
.spare_bit = 0x144,
.speedo_idx = SPEEDO_TEGRA30,
};
-static struct tegra_fuse_info tegra114_info = {
+static const struct tegra_fuse_info tegra114_info = {
.size = 0x2a0,
.speedo_idx = SPEEDO_TEGRA114,
};
-static struct tegra_fuse_info tegra124_info = {
+static const struct tegra_fuse_info tegra124_info = {
.size = 0x300,
.speedo_idx = SPEEDO_TEGRA124,
};
@@ -182,6 +182,7 @@ static void __init legacy_fuse_init(void)
fuse_info = &tegra114_info;
break;
case TEGRA124:
+ case TEGRA132:
fuse_info = &tegra124_info;
break;
default:
diff --git a/drivers/soc/tegra/pmc.c b/drivers/soc/tegra/pmc.c
index a2c0ceb95f8f..c956395cf46f 100644
--- a/drivers/soc/tegra/pmc.c
+++ b/drivers/soc/tegra/pmc.c
@@ -70,6 +70,10 @@
#define PMC_SCRATCH41 0x140
+#define PMC_SENSOR_CTRL 0x1b0
+#define PMC_SENSOR_CTRL_SCRATCH_WRITE (1 << 2)
+#define PMC_SENSOR_CTRL_ENABLE_RST (1 << 1)
+
#define IO_DPD_REQ 0x1b8
#define IO_DPD_REQ_CODE_IDLE (0 << 30)
#define IO_DPD_REQ_CODE_OFF (1 << 30)
@@ -81,6 +85,18 @@
#define IO_DPD2_STATUS 0x1c4
#define SEL_DPD_TIM 0x1c8
+#define PMC_SCRATCH54 0x258
+#define PMC_SCRATCH54_DATA_SHIFT 8
+#define PMC_SCRATCH54_ADDR_SHIFT 0
+
+#define PMC_SCRATCH55 0x25c
+#define PMC_SCRATCH55_RESET_TEGRA (1 << 31)
+#define PMC_SCRATCH55_CNTRL_ID_SHIFT 27
+#define PMC_SCRATCH55_PINMUX_SHIFT 24
+#define PMC_SCRATCH55_16BITOP (1 << 15)
+#define PMC_SCRATCH55_CHECKSUM_SHIFT 16
+#define PMC_SCRATCH55_I2CSLV1_SHIFT 0
+
#define GPU_RG_CNTRL 0x2d4
struct tegra_pmc_soc {
@@ -88,6 +104,9 @@ struct tegra_pmc_soc {
const char *const *powergates;
unsigned int num_cpu_powergates;
const u8 *cpu_powergates;
+
+ bool has_tsense_reset;
+ bool has_gpu_clamps;
};
/**
@@ -110,6 +129,7 @@ struct tegra_pmc_soc {
* @powergates_lock: mutex for power gate register access
*/
struct tegra_pmc {
+ struct device *dev;
void __iomem *base;
struct clk *clk;
@@ -225,11 +245,11 @@ int tegra_powergate_remove_clamping(int id)
return -EINVAL;
/*
- * The Tegra124 GPU has a separate register (with different semantics)
- * to remove clamps.
+ * On Tegra124 and later, the clamps for the GPU are controlled by a
+ * separate register (with different semantics).
*/
- if (tegra_get_chip_id() == TEGRA124) {
- if (id == TEGRA_POWERGATE_3D) {
+ if (id == TEGRA_POWERGATE_3D) {
+ if (pmc->soc->has_gpu_clamps) {
tegra_pmc_writel(0, GPU_RG_CNTRL);
return 0;
}
@@ -703,6 +723,83 @@ static void tegra_pmc_init(struct tegra_pmc *pmc)
tegra_pmc_writel(value, PMC_CNTRL);
}
+void tegra_pmc_init_tsense_reset(struct tegra_pmc *pmc)
+{
+ static const char disabled[] = "emergency thermal reset disabled";
+ u32 pmu_addr, ctrl_id, reg_addr, reg_data, pinmux;
+ struct device *dev = pmc->dev;
+ struct device_node *np;
+ u32 value, checksum;
+
+ if (!pmc->soc->has_tsense_reset)
+ goto out;
+
+ np = of_find_node_by_name(pmc->dev->of_node, "i2c-thermtrip");
+ if (!np) {
+ dev_warn(dev, "i2c-thermtrip node not found, %s.\n", disabled);
+ goto out;
+ }
+
+ if (of_property_read_u32(np, "nvidia,i2c-controller-id", &ctrl_id)) {
+ dev_err(dev, "I2C controller ID missing, %s.\n", disabled);
+ goto out;
+ }
+
+ if (of_property_read_u32(np, "nvidia,bus-addr", &pmu_addr)) {
+ dev_err(dev, "nvidia,bus-addr missing, %s.\n", disabled);
+ goto out;
+ }
+
+ if (of_property_read_u32(np, "nvidia,reg-addr", &reg_addr)) {
+ dev_err(dev, "nvidia,reg-addr missing, %s.\n", disabled);
+ goto out;
+ }
+
+ if (of_property_read_u32(np, "nvidia,reg-data", &reg_data)) {
+ dev_err(dev, "nvidia,reg-data missing, %s.\n", disabled);
+ goto out;
+ }
+
+ if (of_property_read_u32(np, "nvidia,pinmux-id", &pinmux))
+ pinmux = 0;
+
+ value = tegra_pmc_readl(PMC_SENSOR_CTRL);
+ value |= PMC_SENSOR_CTRL_SCRATCH_WRITE;
+ tegra_pmc_writel(value, PMC_SENSOR_CTRL);
+
+ value = (reg_data << PMC_SCRATCH54_DATA_SHIFT) |
+ (reg_addr << PMC_SCRATCH54_ADDR_SHIFT);
+ tegra_pmc_writel(value, PMC_SCRATCH54);
+
+ value = PMC_SCRATCH55_RESET_TEGRA;
+ value |= ctrl_id << PMC_SCRATCH55_CNTRL_ID_SHIFT;
+ value |= pinmux << PMC_SCRATCH55_PINMUX_SHIFT;
+ value |= pmu_addr << PMC_SCRATCH55_I2CSLV1_SHIFT;
+
+ /*
+ * Calculate checksum of SCRATCH54, SCRATCH55 fields. Bits 23:16 will
+ * contain the checksum and are currently zero, so they are not added.
+ */
+ checksum = reg_addr + reg_data + (value & 0xff) + ((value >> 8) & 0xff)
+ + ((value >> 24) & 0xff);
+ checksum &= 0xff;
+ checksum = 0x100 - checksum;
+
+ value |= checksum << PMC_SCRATCH55_CHECKSUM_SHIFT;
+
+ tegra_pmc_writel(value, PMC_SCRATCH55);
+
+ value = tegra_pmc_readl(PMC_SENSOR_CTRL);
+ value |= PMC_SENSOR_CTRL_ENABLE_RST;
+ tegra_pmc_writel(value, PMC_SENSOR_CTRL);
+
+ dev_info(pmc->dev, "emergency thermal reset enabled\n");
+
+out:
+ of_node_put(np);
+ return;
+}
+
static int tegra_pmc_probe(struct platform_device *pdev)
{
void __iomem *base = pmc->base;
@@ -728,8 +825,12 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return err;
}
+ pmc->dev = &pdev->dev;
+
tegra_pmc_init(pmc);
+ tegra_pmc_init_tsense_reset(pmc);
+
if (IS_ENABLED(CONFIG_DEBUG_FS)) {
err = tegra_powergate_debugfs_init();
if (err < 0)
@@ -739,7 +840,7 @@ static int tegra_pmc_probe(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
static int tegra_pmc_suspend(struct device *dev)
{
tegra_pmc_writel(virt_to_phys(tegra_resume), PMC_SCRATCH41);
@@ -753,10 +854,11 @@ static int tegra_pmc_resume(struct device *dev)
return 0;
}
-#endif
static SIMPLE_DEV_PM_OPS(tegra_pmc_pm_ops, tegra_pmc_suspend, tegra_pmc_resume);
+#endif
+
static const char * const tegra20_powergates[] = {
[TEGRA_POWERGATE_CPU] = "cpu",
[TEGRA_POWERGATE_3D] = "3d",
@@ -772,6 +874,8 @@ static const struct tegra_pmc_soc tegra20_pmc_soc = {
.powergates = tegra20_powergates,
.num_cpu_powergates = 0,
.cpu_powergates = NULL,
+ .has_tsense_reset = false,
+ .has_gpu_clamps = false,
};
static const char * const tegra30_powergates[] = {
@@ -803,6 +907,8 @@ static const struct tegra_pmc_soc tegra30_pmc_soc = {
.powergates = tegra30_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra30_cpu_powergates),
.cpu_powergates = tegra30_cpu_powergates,
+ .has_tsense_reset = true,
+ .has_gpu_clamps = false,
};
static const char * const tegra114_powergates[] = {
@@ -838,6 +944,8 @@ static const struct tegra_pmc_soc tegra114_pmc_soc = {
.powergates = tegra114_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra114_cpu_powergates),
.cpu_powergates = tegra114_cpu_powergates,
+ .has_tsense_reset = true,
+ .has_gpu_clamps = false,
};
static const char * const tegra124_powergates[] = {
@@ -879,6 +987,8 @@ static const struct tegra_pmc_soc tegra124_pmc_soc = {
.powergates = tegra124_powergates,
.num_cpu_powergates = ARRAY_SIZE(tegra124_cpu_powergates),
.cpu_powergates = tegra124_cpu_powergates,
+ .has_tsense_reset = true,
+ .has_gpu_clamps = true,
};
static const struct of_device_id tegra_pmc_match[] = {
@@ -894,7 +1004,9 @@ static struct platform_driver tegra_pmc_driver = {
.name = "tegra-pmc",
.suppress_bind_attrs = true,
.of_match_table = tegra_pmc_match,
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_ARM)
.pm = &tegra_pmc_pm_ops,
+#endif
},
.probe = tegra_pmc_probe,
};
diff --git a/drivers/soc/ti/Makefile b/drivers/soc/ti/Makefile
index 6bed611e1934..135bdad7a6de 100644
--- a/drivers/soc/ti/Makefile
+++ b/drivers/soc/ti/Makefile
@@ -1,5 +1,6 @@
#
# TI Keystone SOC drivers
#
-obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss_queue.o knav_qmss_acc.o
+obj-$(CONFIG_KEYSTONE_NAVIGATOR_QMSS) += knav_qmss.o
+knav_qmss-y := knav_qmss_queue.o knav_qmss_acc.o
obj-$(CONFIG_KEYSTONE_NAVIGATOR_DMA) += knav_dma.o
diff --git a/drivers/soc/ti/knav_qmss_acc.c b/drivers/soc/ti/knav_qmss_acc.c
index 6fbfde6e748f..ef6f69db0bd0 100644
--- a/drivers/soc/ti/knav_qmss_acc.c
+++ b/drivers/soc/ti/knav_qmss_acc.c
@@ -209,7 +209,7 @@ static irqreturn_t knav_acc_int_handler(int irq, void *_instdata)
return IRQ_HANDLED;
}
-int knav_range_setup_acc_irq(struct knav_range_info *range,
+static int knav_range_setup_acc_irq(struct knav_range_info *range,
int queue, bool enabled)
{
struct knav_device *kdev = range->kdev;
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 8e6a95d91d33..6d8646db52cc 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -626,6 +626,7 @@ int knav_queue_push(void *qhandle, dma_addr_t dma,
atomic_inc(&qh->stats.pushes);
return 0;
}
+EXPORT_SYMBOL_GPL(knav_queue_push);
/**
* knav_queue_pop() - pop data (or descriptor) from the head of a queue
@@ -663,6 +664,7 @@ dma_addr_t knav_queue_pop(void *qhandle, unsigned *size)
atomic_inc(&qh->stats.pops);
return dma;
}
+EXPORT_SYMBOL_GPL(knav_queue_pop);
/* carve out descriptors and push into queue */
static void kdesc_fill_pool(struct knav_pool *pool)
@@ -717,12 +719,14 @@ dma_addr_t knav_pool_desc_virt_to_dma(void *ph, void *virt)
struct knav_pool *pool = ph;
return pool->region->dma_start + (virt - pool->region->virt_start);
}
+EXPORT_SYMBOL_GPL(knav_pool_desc_virt_to_dma);
void *knav_pool_desc_dma_to_virt(void *ph, dma_addr_t dma)
{
struct knav_pool *pool = ph;
return pool->region->virt_start + (dma - pool->region->dma_start);
}
+EXPORT_SYMBOL_GPL(knav_pool_desc_dma_to_virt);
/**
* knav_pool_create() - Create a pool of descriptors
@@ -878,6 +882,7 @@ void *knav_pool_desc_get(void *ph)
data = knav_pool_desc_dma_to_virt(pool, dma);
return data;
}
+EXPORT_SYMBOL_GPL(knav_pool_desc_get);
/**
* knav_pool_desc_put() - return a descriptor to the pool
@@ -890,6 +895,7 @@ void knav_pool_desc_put(void *ph, void *desc)
dma = knav_pool_desc_virt_to_dma(pool, desc);
knav_queue_push(pool->queue, dma, pool->region->desc_size, 0);
}
+EXPORT_SYMBOL_GPL(knav_pool_desc_put);
/**
* knav_pool_desc_map() - Map descriptor for DMA transfer
@@ -916,6 +922,7 @@ int knav_pool_desc_map(void *ph, void *desc, unsigned size,
return 0;
}
+EXPORT_SYMBOL_GPL(knav_pool_desc_map);
/**
* knav_pool_desc_unmap() - Unmap descriptor after DMA transfer
@@ -938,6 +945,7 @@ void *knav_pool_desc_unmap(void *ph, dma_addr_t dma, unsigned dma_sz)
prefetch(desc);
return desc;
}
+EXPORT_SYMBOL_GPL(knav_pool_desc_unmap);
/**
* knav_pool_count() - Get the number of descriptors in pool.
@@ -949,6 +957,7 @@ int knav_pool_count(void *ph)
struct knav_pool *pool = ph;
return knav_queue_get_count(pool->queue);
}
+EXPORT_SYMBOL_GPL(knav_pool_count);
static void knav_queue_setup_region(struct knav_device *kdev,
struct knav_region *region)
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 99829985c1a1..ab8dfbef6f1b 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -29,7 +29,7 @@ menuconfig SPI
if SPI
config SPI_DEBUG
- boolean "Debug support for SPI drivers"
+ bool "Debug support for SPI drivers"
depends on DEBUG_KERNEL
help
Say "yes" to enable debug messaging (like dev_dbg and pr_debug),
@@ -40,8 +40,8 @@ config SPI_DEBUG
#
config SPI_MASTER
-# boolean "SPI Master Support"
- boolean
+# bool "SPI Master Support"
+ bool
default SPI
help
If your system has an master-capable SPI controller (which
@@ -185,6 +185,16 @@ config SPI_DAVINCI
help
SPI master controller for DaVinci/DA8x/OMAP-L/AM1x SPI modules.
+config SPI_DLN2
+ tristate "Diolan DLN-2 USB SPI adapter"
+ depends on MFD_DLN2
+ help
+ If you say yes to this option, support will be included for Diolan
+ DLN2, a USB to SPI interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called spi-dln2.
+
config SPI_EFM32
tristate "EFM32 SPI controller"
depends on OF && ARM && (ARCH_EFM32 || COMPILE_TEST)
@@ -279,7 +289,7 @@ config SPI_FSL_CPM
depends on FSL_SOC
config SPI_FSL_SPI
- bool "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
+ tristate "Freescale SPI controller and Aeroflex Gaisler GRLIB SPI controller"
depends on OF
select SPI_FSL_LIB
select SPI_FSL_CPM if FSL_SOC
@@ -292,7 +302,6 @@ config SPI_FSL_SPI
config SPI_FSL_DSPI
tristate "Freescale DSPI controller"
- select SPI_BITBANG
select REGMAP_MMIO
depends on SOC_VF610 || COMPILE_TEST
help
@@ -300,7 +309,7 @@ config SPI_FSL_DSPI
mode. VF610 platform uses the controller.
config SPI_FSL_ESPI
- bool "Freescale eSPI controller"
+ tristate "Freescale eSPI controller"
depends on FSL_SOC
select SPI_FSL_LIB
help
@@ -460,7 +469,6 @@ config SPI_S3C24XX_FIQ
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
- select S3C64XX_PL080 if ARCH_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
@@ -503,6 +511,13 @@ config SPI_SIRF
help
SPI driver for CSR SiRFprimaII SoCs
+config SPI_ST_SSC4
+ tristate "STMicroelectronics SPI SSC-based driver"
+ depends on ARCH_STI
+ help
+ STMicroelectronics SoCs support for SPI. If you say yes to
+ this option, support will be included for the SSC driven SPI.
+
config SPI_SUN4I
tristate "Allwinner A10 SoCs SPI controller"
depends on ARCH_SUNXI || COMPILE_TEST
@@ -595,7 +610,6 @@ config SPI_XTENSA_XTFPGA
16 bit words in SPI mode 0, automatically asserting CS on transfer
start and deasserting on end.
-
config SPI_NUC900
tristate "Nuvoton NUC900 series SPI"
depends on ARCH_W90X900
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 6b9d2ac629cc..d8cbf654976b 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_SPI_CADENCE) += spi-cadence.o
obj-$(CONFIG_SPI_CLPS711X) += spi-clps711x.o
obj-$(CONFIG_SPI_COLDFIRE_QSPI) += spi-coldfire-qspi.o
obj-$(CONFIG_SPI_DAVINCI) += spi-davinci.o
+obj-$(CONFIG_SPI_DLN2) += spi-dln2.o
obj-$(CONFIG_SPI_DESIGNWARE) += spi-dw.o
obj-$(CONFIG_SPI_DW_MMIO) += spi-dw-mmio.o
obj-$(CONFIG_SPI_DW_PCI) += spi-dw-midpci.o
@@ -76,6 +77,7 @@ obj-$(CONFIG_SPI_SH_HSPI) += spi-sh-hspi.o
obj-$(CONFIG_SPI_SH_MSIOF) += spi-sh-msiof.o
obj-$(CONFIG_SPI_SH_SCI) += spi-sh-sci.o
obj-$(CONFIG_SPI_SIRF) += spi-sirf.o
+obj-$(CONFIG_SPI_ST_SSC4) += spi-st-ssc4.o
obj-$(CONFIG_SPI_SUN4I) += spi-sun4i.o
obj-$(CONFIG_SPI_SUN6I) += spi-sun6i.o
obj-$(CONFIG_SPI_TEGRA114) += spi-tegra114.o
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 23d8f5f56579..9af7841f2e8c 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -1046,6 +1046,7 @@ static int atmel_spi_one_transfer(struct spi_master *master,
struct atmel_spi_device *asd;
int timeout;
int ret;
+ unsigned long dma_timeout;
as = spi_master_get_devdata(master);
@@ -1103,15 +1104,12 @@ static int atmel_spi_one_transfer(struct spi_master *master,
/* interrupts are disabled, so free the lock for schedule */
atmel_spi_unlock(as);
- ret = wait_for_completion_timeout(&as->xfer_completion,
- SPI_DMA_TIMEOUT);
+ dma_timeout = wait_for_completion_timeout(&as->xfer_completion,
+ SPI_DMA_TIMEOUT);
atmel_spi_lock(as);
- if (WARN_ON(ret == 0)) {
- dev_err(&spi->dev,
- "spi trasfer timeout, err %d\n", ret);
+ if (WARN_ON(dma_timeout == 0)) {
+ dev_err(&spi->dev, "spi transfer timeout\n");
as->done_status = -EIO;
- } else {
- ret = 0;
}
if (as->done_status)
diff --git a/drivers/spi/spi-au1550.c b/drivers/spi/spi-au1550.c
index 326f47973684..f45e085c01a6 100644
--- a/drivers/spi/spi-au1550.c
+++ b/drivers/spi/spi-au1550.c
@@ -15,10 +15,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>
diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 98aab457b24d..419a782ab6d5 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.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.
*/
#include <linux/clk.h>
diff --git a/drivers/spi/spi-bcm53xx.c b/drivers/spi/spi-bcm53xx.c
index 17b34cbadc03..3fb91c81015a 100644
--- a/drivers/spi/spi-bcm53xx.c
+++ b/drivers/spi/spi-bcm53xx.c
@@ -216,7 +216,7 @@ static struct spi_board_info bcm53xx_info = {
static const struct bcma_device_id bcm53xxspi_bcma_tbl[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_NS_QSPI, BCMA_ANY_REV, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
+ {},
};
MODULE_DEVICE_TABLE(bcma, bcm53xxspi_bcma_tbl);
diff --git a/drivers/spi/spi-bcm63xx.c b/drivers/spi/spi-bcm63xx.c
index c20530982e26..e73e2b052c9c 100644
--- a/drivers/spi/spi-bcm63xx.c
+++ b/drivers/spi/spi-bcm63xx.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 Street, Fifth Floor,
*/
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-bitbang.c b/drivers/spi/spi-bitbang.c
index dc7d2c2d643e..5ef6638d5e8a 100644
--- a/drivers/spi/spi-bitbang.c
+++ b/drivers/spi/spi-bitbang.c
@@ -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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/spinlock.h>
diff --git a/drivers/spi/spi-butterfly.c b/drivers/spi/spi-butterfly.c
index ee4f91ccd8fd..9a95862986c8 100644
--- a/drivers/spi/spi-butterfly.c
+++ b/drivers/spi/spi-butterfly.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/spi/spi-coldfire-qspi.c b/drivers/spi/spi-coldfire-qspi.c
index 41b5dc4445f6..688956ff5095 100644
--- a/drivers/spi/spi-coldfire-qspi.c
+++ b/drivers/spi/spi-coldfire-qspi.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/kernel.h>
diff --git a/drivers/spi/spi-davinci.c b/drivers/spi/spi-davinci.c
index b3707badb1e5..5e991065f5b0 100644
--- a/drivers/spi/spi-davinci.c
+++ b/drivers/spi/spi-davinci.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/interrupt.h>
diff --git a/drivers/spi/spi-dln2.c b/drivers/spi/spi-dln2.c
new file mode 100644
index 000000000000..3b7d91d94fea
--- /dev/null
+++ b/drivers/spi/spi-dln2.c
@@ -0,0 +1,881 @@
+/*
+ * Driver for the Diolan DLN-2 USB-SPI 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/platform_device.h>
+#include <linux/mfd/dln2.h>
+#include <linux/spi/spi.h>
+#include <linux/pm_runtime.h>
+#include <asm/unaligned.h>
+
+#define DLN2_SPI_MODULE_ID 0x02
+#define DLN2_SPI_CMD(cmd) DLN2_CMD(cmd, DLN2_SPI_MODULE_ID)
+
+/* SPI commands */
+#define DLN2_SPI_GET_PORT_COUNT DLN2_SPI_CMD(0x00)
+#define DLN2_SPI_ENABLE DLN2_SPI_CMD(0x11)
+#define DLN2_SPI_DISABLE DLN2_SPI_CMD(0x12)
+#define DLN2_SPI_IS_ENABLED DLN2_SPI_CMD(0x13)
+#define DLN2_SPI_SET_MODE DLN2_SPI_CMD(0x14)
+#define DLN2_SPI_GET_MODE DLN2_SPI_CMD(0x15)
+#define DLN2_SPI_SET_FRAME_SIZE DLN2_SPI_CMD(0x16)
+#define DLN2_SPI_GET_FRAME_SIZE DLN2_SPI_CMD(0x17)
+#define DLN2_SPI_SET_FREQUENCY DLN2_SPI_CMD(0x18)
+#define DLN2_SPI_GET_FREQUENCY DLN2_SPI_CMD(0x19)
+#define DLN2_SPI_READ_WRITE DLN2_SPI_CMD(0x1A)
+#define DLN2_SPI_READ DLN2_SPI_CMD(0x1B)
+#define DLN2_SPI_WRITE DLN2_SPI_CMD(0x1C)
+#define DLN2_SPI_SET_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x20)
+#define DLN2_SPI_GET_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x21)
+#define DLN2_SPI_SET_DELAY_AFTER_SS DLN2_SPI_CMD(0x22)
+#define DLN2_SPI_GET_DELAY_AFTER_SS DLN2_SPI_CMD(0x23)
+#define DLN2_SPI_SET_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x24)
+#define DLN2_SPI_GET_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x25)
+#define DLN2_SPI_SET_SS DLN2_SPI_CMD(0x26)
+#define DLN2_SPI_GET_SS DLN2_SPI_CMD(0x27)
+#define DLN2_SPI_RELEASE_SS DLN2_SPI_CMD(0x28)
+#define DLN2_SPI_SS_VARIABLE_ENABLE DLN2_SPI_CMD(0x2B)
+#define DLN2_SPI_SS_VARIABLE_DISABLE DLN2_SPI_CMD(0x2C)
+#define DLN2_SPI_SS_VARIABLE_IS_ENABLED DLN2_SPI_CMD(0x2D)
+#define DLN2_SPI_SS_AAT_ENABLE DLN2_SPI_CMD(0x2E)
+#define DLN2_SPI_SS_AAT_DISABLE DLN2_SPI_CMD(0x2F)
+#define DLN2_SPI_SS_AAT_IS_ENABLED DLN2_SPI_CMD(0x30)
+#define DLN2_SPI_SS_BETWEEN_FRAMES_ENABLE DLN2_SPI_CMD(0x31)
+#define DLN2_SPI_SS_BETWEEN_FRAMES_DISABLE DLN2_SPI_CMD(0x32)
+#define DLN2_SPI_SS_BETWEEN_FRAMES_IS_ENABLED DLN2_SPI_CMD(0x33)
+#define DLN2_SPI_SET_CPHA DLN2_SPI_CMD(0x34)
+#define DLN2_SPI_GET_CPHA DLN2_SPI_CMD(0x35)
+#define DLN2_SPI_SET_CPOL DLN2_SPI_CMD(0x36)
+#define DLN2_SPI_GET_CPOL DLN2_SPI_CMD(0x37)
+#define DLN2_SPI_SS_MULTI_ENABLE DLN2_SPI_CMD(0x38)
+#define DLN2_SPI_SS_MULTI_DISABLE DLN2_SPI_CMD(0x39)
+#define DLN2_SPI_SS_MULTI_IS_ENABLED DLN2_SPI_CMD(0x3A)
+#define DLN2_SPI_GET_SUPPORTED_MODES DLN2_SPI_CMD(0x40)
+#define DLN2_SPI_GET_SUPPORTED_CPHA_VALUES DLN2_SPI_CMD(0x41)
+#define DLN2_SPI_GET_SUPPORTED_CPOL_VALUES DLN2_SPI_CMD(0x42)
+#define DLN2_SPI_GET_SUPPORTED_FRAME_SIZES DLN2_SPI_CMD(0x43)
+#define DLN2_SPI_GET_SS_COUNT DLN2_SPI_CMD(0x44)
+#define DLN2_SPI_GET_MIN_FREQUENCY DLN2_SPI_CMD(0x45)
+#define DLN2_SPI_GET_MAX_FREQUENCY DLN2_SPI_CMD(0x46)
+#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x47)
+#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_SS DLN2_SPI_CMD(0x48)
+#define DLN2_SPI_GET_MIN_DELAY_AFTER_SS DLN2_SPI_CMD(0x49)
+#define DLN2_SPI_GET_MAX_DELAY_AFTER_SS DLN2_SPI_CMD(0x4A)
+#define DLN2_SPI_GET_MIN_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4B)
+#define DLN2_SPI_GET_MAX_DELAY_BETWEEN_FRAMES DLN2_SPI_CMD(0x4C)
+
+#define DLN2_SPI_MAX_XFER_SIZE 256
+#define DLN2_SPI_BUF_SIZE (DLN2_SPI_MAX_XFER_SIZE + 16)
+#define DLN2_SPI_ATTR_LEAVE_SS_LOW BIT(0)
+#define DLN2_TRANSFERS_WAIT_COMPLETE 1
+#define DLN2_TRANSFERS_CANCEL 0
+#define DLN2_RPM_AUTOSUSPEND_TIMEOUT 2000
+
+struct dln2_spi {
+ struct platform_device *pdev;
+ struct spi_master *master;
+ u8 port;
+
+ /*
+ * This buffer will be used mainly for read/write operations. Since
+ * they're quite large, we cannot use the stack. Protection is not
+ * needed because all SPI communication is serialized by the SPI core.
+ */
+ void *buf;
+
+ u8 bpw;
+ u32 speed;
+ u16 mode;
+ u8 cs;
+};
+
+/*
+ * Enable/Disable SPI module. The disable command will wait for transfers to
+ * complete first.
+ */
+static int dln2_spi_enable(struct dln2_spi *dln2, bool enable)
+{
+ u16 cmd;
+ struct {
+ u8 port;
+ u8 wait_for_completion;
+ } tx;
+ unsigned len = sizeof(tx);
+
+ tx.port = dln2->port;
+
+ if (enable) {
+ cmd = DLN2_SPI_ENABLE;
+ len -= sizeof(tx.wait_for_completion);
+ } else {
+ tx.wait_for_completion = DLN2_TRANSFERS_WAIT_COMPLETE;
+ cmd = DLN2_SPI_DISABLE;
+ }
+
+ return dln2_transfer_tx(dln2->pdev, cmd, &tx, len);
+}
+
+/*
+ * Select/unselect multiple CS lines. The selected lines will be automatically
+ * toggled LOW/HIGH by the board firmware during transfers, provided they're
+ * enabled first.
+ *
+ * Ex: cs_mask = 0x03 -> CS0 & CS1 will be selected and the next WR/RD operation
+ * will toggle the lines LOW/HIGH automatically.
+ */
+static int dln2_spi_cs_set(struct dln2_spi *dln2, u8 cs_mask)
+{
+ struct {
+ u8 port;
+ u8 cs;
+ } tx;
+
+ tx.port = dln2->port;
+
+ /*
+ * According to Diolan docs, "a slave device can be selected by changing
+ * the corresponding bit value to 0". The rest must be set to 1. Hence
+ * the bitwise NOT in front.
+ */
+ tx.cs = ~cs_mask;
+
+ return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_SS, &tx, sizeof(tx));
+}
+
+/*
+ * Select one CS line. The other lines will be un-selected.
+ */
+static int dln2_spi_cs_set_one(struct dln2_spi *dln2, u8 cs)
+{
+ return dln2_spi_cs_set(dln2, BIT(cs));
+}
+
+/*
+ * Enable/disable CS lines for usage. The module has to be disabled first.
+ */
+static int dln2_spi_cs_enable(struct dln2_spi *dln2, u8 cs_mask, bool enable)
+{
+ struct {
+ u8 port;
+ u8 cs;
+ } tx;
+ u16 cmd;
+
+ tx.port = dln2->port;
+ tx.cs = cs_mask;
+ cmd = enable ? DLN2_SPI_SS_MULTI_ENABLE : DLN2_SPI_SS_MULTI_DISABLE;
+
+ return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx));
+}
+
+static int dln2_spi_cs_enable_all(struct dln2_spi *dln2, bool enable)
+{
+ u8 cs_mask = GENMASK(dln2->master->num_chipselect - 1, 0);
+
+ return dln2_spi_cs_enable(dln2, cs_mask, enable);
+}
+
+static int dln2_spi_get_cs_num(struct dln2_spi *dln2, u16 *cs_num)
+{
+ int ret;
+ struct {
+ u8 port;
+ } tx;
+ struct {
+ __le16 cs_count;
+ } rx;
+ unsigned rx_len = sizeof(rx);
+
+ tx.port = dln2->port;
+ ret = dln2_transfer(dln2->pdev, DLN2_SPI_GET_SS_COUNT, &tx, sizeof(tx),
+ &rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx))
+ return -EPROTO;
+
+ *cs_num = le16_to_cpu(rx.cs_count);
+
+ dev_dbg(&dln2->pdev->dev, "cs_num = %d\n", *cs_num);
+
+ return 0;
+}
+
+static int dln2_spi_get_speed(struct dln2_spi *dln2, u16 cmd, u32 *freq)
+{
+ int ret;
+ struct {
+ u8 port;
+ } tx;
+ struct {
+ __le32 speed;
+ } rx;
+ unsigned rx_len = sizeof(rx);
+
+ tx.port = dln2->port;
+
+ ret = dln2_transfer(dln2->pdev, cmd, &tx, sizeof(tx), &rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx))
+ return -EPROTO;
+
+ *freq = le32_to_cpu(rx.speed);
+
+ return 0;
+}
+
+/*
+ * Get bus min/max frequencies.
+ */
+static int dln2_spi_get_speed_range(struct dln2_spi *dln2, u32 *fmin, u32 *fmax)
+{
+ int ret;
+
+ ret = dln2_spi_get_speed(dln2, DLN2_SPI_GET_MIN_FREQUENCY, fmin);
+ if (ret < 0)
+ return ret;
+
+ ret = dln2_spi_get_speed(dln2, DLN2_SPI_GET_MAX_FREQUENCY, fmax);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&dln2->pdev->dev, "freq_min = %d, freq_max = %d\n",
+ *fmin, *fmax);
+
+ return 0;
+}
+
+/*
+ * Set the bus speed. The module will automatically round down to the closest
+ * available frequency and returns it. The module has to be disabled first.
+ */
+static int dln2_spi_set_speed(struct dln2_spi *dln2, u32 speed)
+{
+ int ret;
+ struct {
+ u8 port;
+ __le32 speed;
+ } __packed tx;
+ struct {
+ __le32 speed;
+ } rx;
+ int rx_len = sizeof(rx);
+
+ tx.port = dln2->port;
+ tx.speed = cpu_to_le32(speed);
+
+ ret = dln2_transfer(dln2->pdev, DLN2_SPI_SET_FREQUENCY, &tx, sizeof(tx),
+ &rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx))
+ return -EPROTO;
+
+ return 0;
+}
+
+/*
+ * Change CPOL & CPHA. The module has to be disabled first.
+ */
+static int dln2_spi_set_mode(struct dln2_spi *dln2, u8 mode)
+{
+ struct {
+ u8 port;
+ u8 mode;
+ } tx;
+
+ tx.port = dln2->port;
+ tx.mode = mode;
+
+ return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_MODE, &tx, sizeof(tx));
+}
+
+/*
+ * Change frame size. The module has to be disabled first.
+ */
+static int dln2_spi_set_bpw(struct dln2_spi *dln2, u8 bpw)
+{
+ struct {
+ u8 port;
+ u8 bpw;
+ } tx;
+
+ tx.port = dln2->port;
+ tx.bpw = bpw;
+
+ return dln2_transfer_tx(dln2->pdev, DLN2_SPI_SET_FRAME_SIZE,
+ &tx, sizeof(tx));
+}
+
+static int dln2_spi_get_supported_frame_sizes(struct dln2_spi *dln2,
+ u32 *bpw_mask)
+{
+ int ret;
+ struct {
+ u8 port;
+ } tx;
+ struct {
+ u8 count;
+ u8 frame_sizes[36];
+ } *rx = dln2->buf;
+ unsigned rx_len = sizeof(*rx);
+ int i;
+
+ tx.port = dln2->port;
+
+ ret = dln2_transfer(dln2->pdev, DLN2_SPI_GET_SUPPORTED_FRAME_SIZES,
+ &tx, sizeof(tx), rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(*rx))
+ return -EPROTO;
+ if (rx->count > ARRAY_SIZE(rx->frame_sizes))
+ return -EPROTO;
+
+ *bpw_mask = 0;
+ for (i = 0; i < rx->count; i++)
+ *bpw_mask |= BIT(rx->frame_sizes[i] - 1);
+
+ dev_dbg(&dln2->pdev->dev, "bpw_mask = 0x%X\n", *bpw_mask);
+
+ return 0;
+}
+
+/*
+ * Copy the data to DLN2 buffer and change the byte order to LE, requested by
+ * DLN2 module. SPI core makes sure that the data length is a multiple of word
+ * size.
+ */
+static int dln2_spi_copy_to_buf(u8 *dln2_buf, const u8 *src, u16 len, u8 bpw)
+{
+#ifdef __LITTLE_ENDIAN
+ memcpy(dln2_buf, src, len);
+#else
+ if (bpw <= 8) {
+ memcpy(dln2_buf, src, len);
+ } else if (bpw <= 16) {
+ __le16 *d = (__le16 *)dln2_buf;
+ u16 *s = (u16 *)src;
+
+ len = len / 2;
+ while (len--)
+ *d++ = cpu_to_le16p(s++);
+ } else {
+ __le32 *d = (__le32 *)dln2_buf;
+ u32 *s = (u32 *)src;
+
+ len = len / 4;
+ while (len--)
+ *d++ = cpu_to_le32p(s++);
+ }
+#endif
+
+ return 0;
+}
+
+/*
+ * Copy the data from DLN2 buffer and convert to CPU byte order since the DLN2
+ * buffer is LE ordered. SPI core makes sure that the data length is a multiple
+ * of word size. The RX dln2_buf is 2 byte aligned so, for BE, we have to make
+ * sure we avoid unaligned accesses for 32 bit case.
+ */
+static int dln2_spi_copy_from_buf(u8 *dest, const u8 *dln2_buf, u16 len, u8 bpw)
+{
+#ifdef __LITTLE_ENDIAN
+ memcpy(dest, dln2_buf, len);
+#else
+ if (bpw <= 8) {
+ memcpy(dest, dln2_buf, len);
+ } else if (bpw <= 16) {
+ u16 *d = (u16 *)dest;
+ __le16 *s = (__le16 *)dln2_buf;
+
+ len = len / 2;
+ while (len--)
+ *d++ = le16_to_cpup(s++);
+ } else {
+ u32 *d = (u32 *)dest;
+ __le32 *s = (__le32 *)dln2_buf;
+
+ len = len / 4;
+ while (len--)
+ *d++ = get_unaligned_le32(s++);
+ }
+#endif
+
+ return 0;
+}
+
+/*
+ * Perform one write operation.
+ */
+static int dln2_spi_write_one(struct dln2_spi *dln2, const u8 *data,
+ u16 data_len, u8 attr)
+{
+ struct {
+ u8 port;
+ __le16 size;
+ u8 attr;
+ u8 buf[DLN2_SPI_MAX_XFER_SIZE];
+ } __packed *tx = dln2->buf;
+ unsigned tx_len;
+
+ BUILD_BUG_ON(sizeof(*tx) > DLN2_SPI_BUF_SIZE);
+
+ if (data_len > DLN2_SPI_MAX_XFER_SIZE)
+ return -EINVAL;
+
+ tx->port = dln2->port;
+ tx->size = cpu_to_le16(data_len);
+ tx->attr = attr;
+
+ dln2_spi_copy_to_buf(tx->buf, data, data_len, dln2->bpw);
+
+ tx_len = sizeof(*tx) + data_len - DLN2_SPI_MAX_XFER_SIZE;
+ return dln2_transfer_tx(dln2->pdev, DLN2_SPI_WRITE, tx, tx_len);
+}
+
+/*
+ * Perform one read operation.
+ */
+static int dln2_spi_read_one(struct dln2_spi *dln2, u8 *data,
+ u16 data_len, u8 attr)
+{
+ int ret;
+ struct {
+ u8 port;
+ __le16 size;
+ u8 attr;
+ } __packed tx;
+ struct {
+ __le16 size;
+ u8 buf[DLN2_SPI_MAX_XFER_SIZE];
+ } __packed *rx = dln2->buf;
+ unsigned rx_len = sizeof(*rx);
+
+ BUILD_BUG_ON(sizeof(*rx) > DLN2_SPI_BUF_SIZE);
+
+ if (data_len > DLN2_SPI_MAX_XFER_SIZE)
+ return -EINVAL;
+
+ tx.port = dln2->port;
+ tx.size = cpu_to_le16(data_len);
+ tx.attr = attr;
+
+ ret = dln2_transfer(dln2->pdev, DLN2_SPI_READ, &tx, sizeof(tx),
+ rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx->size) + data_len)
+ return -EPROTO;
+ if (le16_to_cpu(rx->size) != data_len)
+ return -EPROTO;
+
+ dln2_spi_copy_from_buf(data, rx->buf, data_len, dln2->bpw);
+
+ return 0;
+}
+
+/*
+ * Perform one write & read operation.
+ */
+static int dln2_spi_read_write_one(struct dln2_spi *dln2, const u8 *tx_data,
+ u8 *rx_data, u16 data_len, u8 attr)
+{
+ int ret;
+ struct {
+ u8 port;
+ __le16 size;
+ u8 attr;
+ u8 buf[DLN2_SPI_MAX_XFER_SIZE];
+ } __packed *tx;
+ struct {
+ __le16 size;
+ u8 buf[DLN2_SPI_MAX_XFER_SIZE];
+ } __packed *rx;
+ unsigned tx_len, rx_len;
+
+ BUILD_BUG_ON(sizeof(*tx) > DLN2_SPI_BUF_SIZE ||
+ sizeof(*rx) > DLN2_SPI_BUF_SIZE);
+
+ if (data_len > DLN2_SPI_MAX_XFER_SIZE)
+ return -EINVAL;
+
+ /*
+ * Since this is a pseudo full-duplex communication, we're perfectly
+ * safe to use the same buffer for both tx and rx. When DLN2 sends the
+ * response back, with the rx data, we don't need the tx buffer anymore.
+ */
+ tx = dln2->buf;
+ rx = dln2->buf;
+
+ tx->port = dln2->port;
+ tx->size = cpu_to_le16(data_len);
+ tx->attr = attr;
+
+ dln2_spi_copy_to_buf(tx->buf, tx_data, data_len, dln2->bpw);
+
+ tx_len = sizeof(*tx) + data_len - DLN2_SPI_MAX_XFER_SIZE;
+ rx_len = sizeof(*rx);
+
+ ret = dln2_transfer(dln2->pdev, DLN2_SPI_READ_WRITE, tx, tx_len,
+ rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx->size) + data_len)
+ return -EPROTO;
+ if (le16_to_cpu(rx->size) != data_len)
+ return -EPROTO;
+
+ dln2_spi_copy_from_buf(rx_data, rx->buf, data_len, dln2->bpw);
+
+ return 0;
+}
+
+/*
+ * Read/Write wrapper. It will automatically split an operation into multiple
+ * single ones due to device buffer constraints.
+ */
+static int dln2_spi_rdwr(struct dln2_spi *dln2, const u8 *tx_data,
+ u8 *rx_data, u16 data_len, u8 attr) {
+ int ret;
+ u16 len;
+ u8 temp_attr;
+ u16 remaining = data_len;
+ u16 offset;
+
+ do {
+ if (remaining > DLN2_SPI_MAX_XFER_SIZE) {
+ len = DLN2_SPI_MAX_XFER_SIZE;
+ temp_attr = DLN2_SPI_ATTR_LEAVE_SS_LOW;
+ } else {
+ len = remaining;
+ temp_attr = attr;
+ }
+
+ offset = data_len - remaining;
+
+ if (tx_data && rx_data) {
+ ret = dln2_spi_read_write_one(dln2,
+ tx_data + offset,
+ rx_data + offset,
+ len, temp_attr);
+ } else if (tx_data) {
+ ret = dln2_spi_write_one(dln2,
+ tx_data + offset,
+ len, temp_attr);
+ } else if (rx_data) {
+ ret = dln2_spi_read_one(dln2,
+ rx_data + offset,
+ len, temp_attr);
+ } else {
+ return -EINVAL;
+ }
+
+ if (ret < 0)
+ return ret;
+
+ remaining -= len;
+ } while (remaining);
+
+ return 0;
+}
+
+static int dln2_spi_prepare_message(struct spi_master *master,
+ struct spi_message *message)
+{
+ int ret;
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ struct spi_device *spi = message->spi;
+
+ if (dln2->cs != spi->chip_select) {
+ ret = dln2_spi_cs_set_one(dln2, spi->chip_select);
+ if (ret < 0)
+ return ret;
+
+ dln2->cs = spi->chip_select;
+ }
+
+ return 0;
+}
+
+static int dln2_spi_transfer_setup(struct dln2_spi *dln2, u32 speed,
+ u8 bpw, u8 mode)
+{
+ int ret;
+ bool bus_setup_change;
+
+ bus_setup_change = dln2->speed != speed || dln2->mode != mode ||
+ dln2->bpw != bpw;
+
+ if (!bus_setup_change)
+ return 0;
+
+ ret = dln2_spi_enable(dln2, false);
+ if (ret < 0)
+ return ret;
+
+ if (dln2->speed != speed) {
+ ret = dln2_spi_set_speed(dln2, speed);
+ if (ret < 0)
+ return ret;
+
+ dln2->speed = speed;
+ }
+
+ if (dln2->mode != mode) {
+ ret = dln2_spi_set_mode(dln2, mode & 0x3);
+ if (ret < 0)
+ return ret;
+
+ dln2->mode = mode;
+ }
+
+ if (dln2->bpw != bpw) {
+ ret = dln2_spi_set_bpw(dln2, bpw);
+ if (ret < 0)
+ return ret;
+
+ dln2->bpw = bpw;
+ }
+
+ return dln2_spi_enable(dln2, true);
+}
+
+static int dln2_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+ int status;
+ u8 attr = 0;
+
+ status = dln2_spi_transfer_setup(dln2, xfer->speed_hz,
+ xfer->bits_per_word,
+ spi->mode);
+ if (status < 0) {
+ dev_err(&dln2->pdev->dev, "Cannot setup transfer\n");
+ return status;
+ }
+
+ if (!xfer->cs_change && !spi_transfer_is_last(master, xfer))
+ attr = DLN2_SPI_ATTR_LEAVE_SS_LOW;
+
+ status = dln2_spi_rdwr(dln2, xfer->tx_buf, xfer->rx_buf,
+ xfer->len, attr);
+ if (status < 0)
+ dev_err(&dln2->pdev->dev, "write/read failed!\n");
+
+ return status;
+}
+
+static int dln2_spi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct dln2_spi *dln2;
+ struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
+ int ret;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*dln2));
+ if (!master)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, master);
+
+ dln2 = spi_master_get_devdata(master);
+
+ dln2->buf = devm_kmalloc(&pdev->dev, DLN2_SPI_BUF_SIZE, GFP_KERNEL);
+ if (!dln2->buf) {
+ ret = -ENOMEM;
+ goto exit_free_master;
+ }
+
+ dln2->master = master;
+ dln2->pdev = pdev;
+ dln2->port = pdata->port;
+ /* cs/mode can never be 0xff, so the first transfer will set them */
+ dln2->cs = 0xff;
+ dln2->mode = 0xff;
+
+ /* disable SPI module before continuing with the setup */
+ ret = dln2_spi_enable(dln2, false);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to disable SPI module\n");
+ goto exit_free_master;
+ }
+
+ ret = dln2_spi_get_cs_num(dln2, &master->num_chipselect);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to get number of CS pins\n");
+ goto exit_free_master;
+ }
+
+ ret = dln2_spi_get_speed_range(dln2,
+ &master->min_speed_hz,
+ &master->max_speed_hz);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to read bus min/max freqs\n");
+ goto exit_free_master;
+ }
+
+ ret = dln2_spi_get_supported_frame_sizes(dln2,
+ &master->bits_per_word_mask);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to read supported frame sizes\n");
+ goto exit_free_master;
+ }
+
+ ret = dln2_spi_cs_enable_all(dln2, true);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to enable CS pins\n");
+ goto exit_free_master;
+ }
+
+ master->bus_num = -1;
+ master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->prepare_message = dln2_spi_prepare_message;
+ master->transfer_one = dln2_spi_transfer_one;
+ master->auto_runtime_pm = true;
+
+ /* enable SPI module, we're good to go */
+ ret = dln2_spi_enable(dln2, true);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to enable SPI module\n");
+ goto exit_free_master;
+ }
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ DLN2_RPM_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 < 0) {
+ dev_err(&pdev->dev, "Failed to register master\n");
+ goto exit_register;
+ }
+
+ return ret;
+
+exit_register:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+
+ if (dln2_spi_enable(dln2, false) < 0)
+ dev_err(&pdev->dev, "Failed to disable SPI module\n");
+exit_free_master:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int dln2_spi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = spi_master_get(platform_get_drvdata(pdev));
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+
+ pm_runtime_disable(&pdev->dev);
+
+ if (dln2_spi_enable(dln2, false) < 0)
+ dev_err(&pdev->dev, "Failed to disable SPI module\n");
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int dln2_spi_suspend(struct device *dev)
+{
+ int ret;
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+
+ ret = spi_master_suspend(master);
+ if (ret < 0)
+ return ret;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = dln2_spi_enable(dln2, false);
+ if (ret < 0)
+ return ret;
+ }
+
+ /*
+ * USB power may be cut off during sleep. Resetting the following
+ * parameters will force the board to be set up before first transfer.
+ */
+ dln2->cs = 0xff;
+ dln2->speed = 0;
+ dln2->bpw = 0;
+ dln2->mode = 0xff;
+
+ return 0;
+}
+
+static int dln2_spi_resume(struct device *dev)
+{
+ int ret;
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = dln2_spi_cs_enable_all(dln2, true);
+ if (ret < 0)
+ return ret;
+
+ ret = dln2_spi_enable(dln2, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ return spi_master_resume(master);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM
+static int dln2_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+
+ return dln2_spi_enable(dln2, false);
+}
+
+static int dln2_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct dln2_spi *dln2 = spi_master_get_devdata(master);
+
+ return dln2_spi_enable(dln2, true);
+}
+#endif /* CONFIG_PM */
+
+static const struct dev_pm_ops dln2_spi_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(dln2_spi_suspend, dln2_spi_resume)
+ SET_RUNTIME_PM_OPS(dln2_spi_runtime_suspend,
+ dln2_spi_runtime_resume, NULL)
+};
+
+static struct platform_driver spi_dln2_driver = {
+ .driver = {
+ .name = "dln2-spi",
+ .pm = &dln2_spi_pm,
+ },
+ .probe = dln2_spi_probe,
+ .remove = dln2_spi_remove,
+};
+module_platform_driver(spi_dln2_driver);
+
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 SPI master interface");
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dln2-spi");
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index a67d37c7e3c0..a0197fd4e95c 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -247,9 +247,9 @@ static struct dw_spi_dma_ops mid_dma_ops = {
/* Some specific info for SPI0 controller on Intel MID */
-/* HW info for MRST CLk Control Unit, one 32b reg */
+/* HW info for MRST Clk Control Unit, 32b reg per controller */
#define MRST_SPI_CLK_BASE 100000000 /* 100m */
-#define MRST_CLK_SPI0_REG 0xff11d86c
+#define MRST_CLK_SPI_REG 0xff11d86c
#define CLK_SPI_BDIV_OFFSET 0
#define CLK_SPI_BDIV_MASK 0x00000007
#define CLK_SPI_CDIV_OFFSET 9
@@ -261,16 +261,17 @@ int dw_spi_mid_init(struct dw_spi *dws)
void __iomem *clk_reg;
u32 clk_cdiv;
- clk_reg = ioremap_nocache(MRST_CLK_SPI0_REG, 16);
+ clk_reg = ioremap_nocache(MRST_CLK_SPI_REG, 16);
if (!clk_reg)
return -ENOMEM;
- /* get SPI controller operating freq info */
- clk_cdiv = (readl(clk_reg) & CLK_SPI_CDIV_MASK) >> CLK_SPI_CDIV_OFFSET;
+ /* Get SPI controller operating freq info */
+ clk_cdiv = readl(clk_reg + dws->bus_num * sizeof(u32));
+ clk_cdiv &= CLK_SPI_CDIV_MASK;
+ clk_cdiv >>= CLK_SPI_CDIV_OFFSET;
dws->max_freq = MRST_SPI_CLK_BASE / (clk_cdiv + 1);
- iounmap(clk_reg);
- dws->num_cs = 16;
+ iounmap(clk_reg);
#ifdef CONFIG_SPI_DW_MID_DMA
dws->dma_priv = kzalloc(sizeof(struct mid_dma), GFP_KERNEL);
diff --git a/drivers/spi/spi-dw-pci.c b/drivers/spi/spi-dw-pci.c
index ba68da12cdf0..5ba331047cbe 100644
--- a/drivers/spi/spi-dw-pci.c
+++ b/drivers/spi/spi-dw-pci.c
@@ -30,10 +30,20 @@ struct dw_spi_pci {
struct spi_pci_desc {
int (*setup)(struct dw_spi *);
+ u16 num_cs;
+ u16 bus_num;
};
-static struct spi_pci_desc spi_pci_mid_desc = {
+static struct spi_pci_desc spi_pci_mid_desc_1 = {
.setup = dw_spi_mid_init,
+ .num_cs = 32,
+ .bus_num = 0,
+};
+
+static struct spi_pci_desc spi_pci_mid_desc_2 = {
+ .setup = dw_spi_mid_init,
+ .num_cs = 4,
+ .bus_num = 1,
};
static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -65,18 +75,23 @@ static int spi_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
dws->regs = pcim_iomap_table(pdev)[pci_bar];
- dws->bus_num = 0;
- dws->num_cs = 4;
dws->irq = pdev->irq;
/*
* Specific handling for paltforms, like dma setup,
* clock rate, FIFO depth.
*/
- if (desc && desc->setup) {
- ret = desc->setup(dws);
- if (ret)
- return ret;
+ if (desc) {
+ dws->num_cs = desc->num_cs;
+ dws->bus_num = desc->bus_num;
+
+ if (desc->setup) {
+ ret = desc->setup(dws);
+ if (ret)
+ return ret;
+ }
+ } else {
+ return -ENODEV;
}
ret = dw_spi_add_host(&pdev->dev, dws);
@@ -121,7 +136,14 @@ static SIMPLE_DEV_PM_OPS(dw_spi_pm_ops, spi_suspend, spi_resume);
static const struct pci_device_id pci_ids[] = {
/* Intel MID platform SPI controller 0 */
- { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc},
+ /*
+ * The access to the device 8086:0801 is disabled by HW, since it's
+ * exclusively used by SCU to communicate with MSIC.
+ */
+ /* Intel MID platform SPI controller 1 */
+ { PCI_VDEVICE(INTEL, 0x0800), (kernel_ulong_t)&spi_pci_mid_desc_1},
+ /* Intel MID platform SPI controller 2 */
+ { PCI_VDEVICE(INTEL, 0x0812), (kernel_ulong_t)&spi_pci_mid_desc_2},
{},
};
diff --git a/drivers/spi/spi-dw.c b/drivers/spi/spi-dw.c
index 8edcd1b84562..5a97a62b298a 100644
--- a/drivers/spi/spi-dw.c
+++ b/drivers/spi/spi-dw.c
@@ -608,7 +608,7 @@ static void dw_spi_cleanup(struct spi_device *spi)
}
/* Restart the controller, disable all interrupts, clean rx fifo */
-static void spi_hw_init(struct dw_spi *dws)
+static void spi_hw_init(struct device *dev, struct dw_spi *dws)
{
spi_enable_chip(dws, 0);
spi_mask_intr(dws, 0xff);
@@ -626,9 +626,10 @@ static void spi_hw_init(struct dw_spi *dws)
if (fifo != dw_readw(dws, DW_SPI_TXFLTR))
break;
}
+ dw_writew(dws, DW_SPI_TXFLTR, 0);
dws->fifo_len = (fifo == 2) ? 0 : fifo - 1;
- dw_writew(dws, DW_SPI_TXFLTR, 0);
+ dev_dbg(dev, "Detected FIFO size: %u bytes\n", dws->fifo_len);
}
}
@@ -668,7 +669,7 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
master->dev.of_node = dev->of_node;
/* Basic HW init */
- spi_hw_init(dws);
+ spi_hw_init(dev, dws);
if (dws->dma_ops && dws->dma_ops->dma_init) {
ret = dws->dma_ops->dma_init(dws);
@@ -731,7 +732,7 @@ int dw_spi_resume_host(struct dw_spi *dws)
{
int ret;
- spi_hw_init(dws);
+ spi_hw_init(&dws->master->dev, dws);
ret = spi_master_resume(dws->master);
if (ret)
dev_err(&dws->master->dev, "fail to start queue (%d)\n", ret);
diff --git a/drivers/spi/spi-falcon.c b/drivers/spi/spi-falcon.c
index 912b9037e9cf..286b2c81fc6b 100644
--- a/drivers/spi/spi-falcon.c
+++ b/drivers/spi/spi-falcon.c
@@ -353,16 +353,6 @@ static int falcon_sflash_setup(struct spi_device *spi)
return 0;
}
-static int falcon_sflash_prepare_xfer(struct spi_master *master)
-{
- return 0;
-}
-
-static int falcon_sflash_unprepare_xfer(struct spi_master *master)
-{
- return 0;
-}
-
static int falcon_sflash_xfer_one(struct spi_master *master,
struct spi_message *m)
{
@@ -420,9 +410,7 @@ static int falcon_sflash_probe(struct platform_device *pdev)
master->mode_bits = SPI_MODE_3;
master->flags = SPI_MASTER_HALF_DUPLEX;
master->setup = falcon_sflash_setup;
- master->prepare_transfer_hardware = falcon_sflash_prepare_xfer;
master->transfer_one_message = falcon_sflash_xfer_one;
- master->unprepare_transfer_hardware = falcon_sflash_unprepare_xfer;
master->dev.of_node = pdev->dev.of_node;
ret = devm_spi_register_master(&pdev->dev, master);
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index e85ab1cb17a2..9c46a3058743 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -20,6 +20,7 @@
#include <linux/dma-mapping.h>
#include <linux/fsl_devices.h>
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/spi/spi.h>
#include <linux/types.h>
@@ -68,6 +69,7 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi)
}
}
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_reinit_txrx);
static void fsl_spi_cpm_bufs_start(struct mpc8xxx_spi *mspi)
{
@@ -162,6 +164,7 @@ err_rx_dma:
dma_unmap_single(dev, mspi->tx_dma, t->len, DMA_TO_DEVICE);
return -ENOMEM;
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs);
void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
{
@@ -174,6 +177,7 @@ void fsl_spi_cpm_bufs_complete(struct mpc8xxx_spi *mspi)
dma_unmap_single(dev, mspi->rx_dma, t->len, DMA_FROM_DEVICE);
mspi->xfer_in_progress = NULL;
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_bufs_complete);
void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
{
@@ -198,6 +202,7 @@ void fsl_spi_cpm_irq(struct mpc8xxx_spi *mspi, u32 events)
else
complete(&mspi->done);
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_irq);
static void *fsl_spi_alloc_dummy_rx(void)
{
@@ -375,6 +380,7 @@ err_pram:
fsl_spi_free_dummy_rx();
return -ENOMEM;
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_init);
void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
{
@@ -389,3 +395,6 @@ void fsl_spi_cpm_free(struct mpc8xxx_spi *mspi)
cpm_muram_free(cpm_muram_offset(mspi->pram));
fsl_spi_free_dummy_rx();
}
+EXPORT_SYMBOL_GPL(fsl_spi_cpm_free);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 4cda994d3f40..d1a39249704a 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -106,7 +106,7 @@ struct chip_data {
};
struct fsl_dspi {
- struct spi_bitbang bitbang;
+ struct spi_master *master;
struct platform_device *pdev;
struct regmap *regmap;
@@ -114,6 +114,7 @@ struct fsl_dspi {
struct clk *clk;
struct spi_transfer *cur_transfer;
+ struct spi_message *cur_msg;
struct chip_data *cur_chip;
size_t len;
void *tx;
@@ -123,6 +124,7 @@ struct fsl_dspi {
char dataflags;
u8 cs;
u16 void_write_data;
+ u32 cs_change;
wait_queue_head_t waitq;
u32 waitflags;
@@ -225,6 +227,8 @@ static int dspi_transfer_write(struct fsl_dspi *dspi)
if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
/* last transfer in the transfer */
dspi_pushr |= SPI_PUSHR_EOQ;
+ if ((dspi->cs_change) && (!dspi->len))
+ dspi_pushr &= ~SPI_PUSHR_CONT;
} else if (tx_word && (dspi->len == 1))
dspi_pushr |= SPI_PUSHR_EOQ;
@@ -246,6 +250,7 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
int rx_count = 0;
int rx_word = is_double_byte_mode(dspi);
u16 d;
+
while ((dspi->rx < dspi->rx_end)
&& (rx_count < DSPI_FIFO_SIZE)) {
if (rx_word) {
@@ -276,86 +281,89 @@ static int dspi_transfer_read(struct fsl_dspi *dspi)
return rx_count;
}
-static int dspi_txrx_transfer(struct spi_device *spi, struct spi_transfer *t)
+static int dspi_transfer_one_message(struct spi_master *master,
+ struct spi_message *message)
{
- struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
- dspi->cur_transfer = t;
- dspi->cur_chip = spi_get_ctldata(spi);
- dspi->cs = spi->chip_select;
- dspi->void_write_data = dspi->cur_chip->void_write_data;
-
- dspi->dataflags = 0;
- dspi->tx = (void *)t->tx_buf;
- dspi->tx_end = dspi->tx + t->len;
- dspi->rx = t->rx_buf;
- dspi->rx_end = dspi->rx + t->len;
- dspi->len = t->len;
-
- if (!dspi->rx)
- dspi->dataflags |= TRAN_STATE_RX_VOID;
-
- if (!dspi->tx)
- dspi->dataflags |= TRAN_STATE_TX_VOID;
-
- regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
- regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val);
- regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
-
- if (t->speed_hz)
+ struct fsl_dspi *dspi = spi_master_get_devdata(master);
+ struct spi_device *spi = message->spi;
+ struct spi_transfer *transfer;
+ int status = 0;
+ message->actual_length = 0;
+
+ list_for_each_entry(transfer, &message->transfers, transfer_list) {
+ dspi->cur_transfer = transfer;
+ dspi->cur_msg = message;
+ dspi->cur_chip = spi_get_ctldata(spi);
+ dspi->cs = spi->chip_select;
+ if (dspi->cur_transfer->transfer_list.next
+ == &dspi->cur_msg->transfers)
+ transfer->cs_change = 1;
+ dspi->cs_change = transfer->cs_change;
+ dspi->void_write_data = dspi->cur_chip->void_write_data;
+
+ dspi->dataflags = 0;
+ dspi->tx = (void *)transfer->tx_buf;
+ dspi->tx_end = dspi->tx + transfer->len;
+ dspi->rx = transfer->rx_buf;
+ dspi->rx_end = dspi->rx + transfer->len;
+ dspi->len = transfer->len;
+
+ if (!dspi->rx)
+ dspi->dataflags |= TRAN_STATE_RX_VOID;
+
+ if (!dspi->tx)
+ dspi->dataflags |= TRAN_STATE_TX_VOID;
+
+ regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
+ regmap_update_bits(dspi->regmap, SPI_MCR,
+ SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
+ SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
dspi->cur_chip->ctar_val);
+ if (transfer->speed_hz)
+ regmap_write(dspi->regmap, SPI_CTAR(dspi->cs),
+ dspi->cur_chip->ctar_val);
- dspi_transfer_write(dspi);
+ regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE);
+ message->actual_length += dspi_transfer_write(dspi);
- if (wait_event_interruptible(dspi->waitq, dspi->waitflags))
- dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n");
- dspi->waitflags = 0;
-
- return t->len - dspi->len;
-}
+ if (wait_event_interruptible(dspi->waitq, dspi->waitflags))
+ dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n");
+ dspi->waitflags = 0;
-static void dspi_chipselect(struct spi_device *spi, int value)
-{
- struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
- unsigned int pushr;
-
- regmap_read(dspi->regmap, SPI_PUSHR, &pushr);
-
- switch (value) {
- case BITBANG_CS_ACTIVE:
- pushr |= SPI_PUSHR_CONT;
- break;
- case BITBANG_CS_INACTIVE:
- pushr &= ~SPI_PUSHR_CONT;
- break;
+ if (transfer->delay_usecs)
+ udelay(transfer->delay_usecs);
}
- regmap_write(dspi->regmap, SPI_PUSHR, pushr);
+ message->status = status;
+ spi_finalize_current_message(master);
+
+ return status;
}
-static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
+static int dspi_setup(struct spi_device *spi)
{
struct chip_data *chip;
struct fsl_dspi *dspi = spi_master_get_devdata(spi->master);
unsigned char br = 0, pbr = 0, fmsz = 0;
+ if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
+ fmsz = spi->bits_per_word - 1;
+ } else {
+ pr_err("Invalid wordsize\n");
+ return -ENODEV;
+ }
+
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
- chip = devm_kzalloc(&spi->dev, sizeof(struct chip_data),
- GFP_KERNEL);
+ chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
if (!chip)
return -ENOMEM;
}
chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
- if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
- fmsz = spi->bits_per_word - 1;
- } else {
- pr_err("Invalid wordsize\n");
- return -ENODEV;
- }
chip->void_write_data = 0;
@@ -374,34 +382,34 @@ static int dspi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
-static int dspi_setup(struct spi_device *spi)
+static void dspi_cleanup(struct spi_device *spi)
{
- if (!spi->max_speed_hz)
- return -EINVAL;
+ struct chip_data *chip = spi_get_ctldata((struct spi_device *)spi);
+
+ dev_dbg(&spi->dev, "spi_device %u.%u cleanup\n",
+ spi->master->bus_num, spi->chip_select);
- return dspi_setup_transfer(spi, NULL);
+ kfree(chip);
}
static irqreturn_t dspi_interrupt(int irq, void *dev_id)
{
struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id;
- regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
+ struct spi_message *msg = dspi->cur_msg;
+ regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF);
dspi_transfer_read(dspi);
if (!dspi->len) {
if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
regmap_update_bits(dspi->regmap, SPI_CTAR(dspi->cs),
- SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
+ SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(16));
dspi->waitflags = 1;
wake_up_interruptible(&dspi->waitq);
- } else {
- dspi_transfer_write(dspi);
-
- return IRQ_HANDLED;
- }
+ } else
+ msg->actual_length += dspi_transfer_write(dspi);
return IRQ_HANDLED;
}
@@ -460,13 +468,14 @@ static int dspi_probe(struct platform_device *pdev)
dspi = spi_master_get_devdata(master);
dspi->pdev = pdev;
- dspi->bitbang.master = master;
- dspi->bitbang.chipselect = dspi_chipselect;
- dspi->bitbang.setup_transfer = dspi_setup_transfer;
- dspi->bitbang.txrx_bufs = dspi_txrx_transfer;
- dspi->bitbang.master->setup = dspi_setup;
- dspi->bitbang.master->dev.of_node = pdev->dev.of_node;
+ dspi->master = master;
+
+ master->transfer = NULL;
+ master->setup = dspi_setup;
+ master->transfer_one_message = dspi_transfer_one_message;
+ master->dev.of_node = pdev->dev.of_node;
+ master->cleanup = dspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA;
master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
SPI_BPW_MASK(16);
@@ -525,7 +534,7 @@ static int dspi_probe(struct platform_device *pdev)
init_waitqueue_head(&dspi->waitq);
platform_set_drvdata(pdev, master);
- ret = spi_bitbang_start(&dspi->bitbang);
+ ret = spi_register_master(master);
if (ret != 0) {
dev_err(&pdev->dev, "Problem registering DSPI master\n");
goto out_clk_put;
@@ -547,9 +556,9 @@ static int dspi_remove(struct platform_device *pdev)
struct fsl_dspi *dspi = spi_master_get_devdata(master);
/* Disconnect from the SPI framework */
- spi_bitbang_stop(&dspi->bitbang);
clk_disable_unprepare(dspi->clk);
- spi_master_put(dspi->bitbang.master);
+ spi_unregister_master(dspi->master);
+ spi_master_put(dspi->master);
return 0;
}
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 446b737e1532..cb35d2f0d0e6 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -21,6 +21,7 @@
#include <linux/interrupt.h>
#include <linux/kernel.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/of_platform.h>
#include <linux/spi/spi.h>
#ifdef CONFIG_FSL_SOC
@@ -35,7 +36,8 @@ void mpc8xxx_spi_rx_buf_##type(u32 data, struct mpc8xxx_spi *mpc8xxx_spi) \
type *rx = mpc8xxx_spi->rx; \
*rx++ = (type)(data >> mpc8xxx_spi->rx_shift); \
mpc8xxx_spi->rx = rx; \
-}
+} \
+EXPORT_SYMBOL_GPL(mpc8xxx_spi_rx_buf_##type);
#define MPC8XXX_SPI_TX_BUF(type) \
u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \
@@ -47,7 +49,8 @@ u32 mpc8xxx_spi_tx_buf_##type(struct mpc8xxx_spi *mpc8xxx_spi) \
data = *tx++ << mpc8xxx_spi->tx_shift; \
mpc8xxx_spi->tx = tx; \
return data; \
-}
+} \
+EXPORT_SYMBOL_GPL(mpc8xxx_spi_tx_buf_##type);
MPC8XXX_SPI_RX_BUF(u8)
MPC8XXX_SPI_RX_BUF(u16)
@@ -60,6 +63,7 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
{
return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
}
+EXPORT_SYMBOL_GPL(to_of_pinfo);
const char *mpc8xxx_spi_strmode(unsigned int flags)
{
@@ -75,6 +79,7 @@ const char *mpc8xxx_spi_strmode(unsigned int flags)
}
return "CPU";
}
+EXPORT_SYMBOL_GPL(mpc8xxx_spi_strmode);
void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq)
@@ -102,13 +107,12 @@ void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
mpc8xxx_spi->rx_shift = 0;
mpc8xxx_spi->tx_shift = 0;
- init_completion(&mpc8xxx_spi->done);
-
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
init_completion(&mpc8xxx_spi->done);
}
+EXPORT_SYMBOL_GPL(mpc8xxx_spi_probe);
int mpc8xxx_spi_remove(struct device *dev)
{
@@ -127,6 +131,7 @@ int mpc8xxx_spi_remove(struct device *dev)
return 0;
}
+EXPORT_SYMBOL_GPL(mpc8xxx_spi_remove);
int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
{
@@ -173,3 +178,6 @@ int of_mpc8xxx_spi_probe(struct platform_device *ofdev)
return 0;
}
+EXPORT_SYMBOL_GPL(of_mpc8xxx_spi_probe);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index b4ed04e8862f..1326a392adca 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -28,7 +28,7 @@ struct mpc8xxx_spi {
/* rx & tx bufs from the spi_transfer */
const void *tx;
void *rx;
-#ifdef CONFIG_SPI_FSL_ESPI
+#if IS_ENABLED(CONFIG_SPI_FSL_ESPI)
int len;
#endif
@@ -68,7 +68,7 @@ struct mpc8xxx_spi {
unsigned int flags;
-#ifdef CONFIG_SPI_FSL_SPI
+#if IS_ENABLED(CONFIG_SPI_FSL_SPI)
int type;
int native_chipselects;
u8 max_bits_per_word;
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index aee4e7589568..1c34c9314c8a 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/module.h>
@@ -92,7 +88,7 @@ struct spi_gpio {
/*----------------------------------------------------------------------*/
-static inline struct spi_gpio * __pure
+static inline struct spi_gpio *__pure
spi_to_spi_gpio(const struct spi_device *spi)
{
const struct spi_bitbang *bang;
@@ -103,7 +99,7 @@ spi_to_spi_gpio(const struct spi_device *spi)
return spi_gpio;
}
-static inline struct spi_gpio_platform_data * __pure
+static inline struct spi_gpio_platform_data *__pure
spi_to_pdata(const struct spi_device *spi)
{
return &spi_to_spi_gpio(spi)->pdata;
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
index aad6683db81b..c01567d53581 100644
--- a/drivers/spi/spi-img-spfi.c
+++ b/drivers/spi/spi-img-spfi.c
@@ -160,16 +160,16 @@ static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
unsigned int count = 0;
u32 status;
- while (count < max) {
+ while (count < max / 4) {
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;
+ spfi_writel(spfi, buf[count], SPFI_TX_32BIT_VALID_DATA);
+ count++;
}
- return count;
+ return count * 4;
}
static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf,
@@ -196,17 +196,17 @@ static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf,
unsigned int count = 0;
u32 status;
- while (count < max) {
+ while (count < max / 4) {
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;
+ buf[count] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA);
+ count++;
}
- return count;
+ return count * 4;
}
static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf,
@@ -251,17 +251,15 @@ static int img_spfi_start_pio(struct spi_master *master,
time_before(jiffies, timeout)) {
unsigned int tx_count, rx_count;
- switch (xfer->bits_per_word) {
- case 32:
+ if (tx_bytes >= 4)
tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes);
- rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes);
- break;
- case 8:
- default:
+ else
tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes);
+
+ if (rx_bytes >= 4)
+ rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes);
+ else
rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes);
- break;
- }
tx_buf += tx_count;
rx_buf += rx_count;
@@ -331,14 +329,11 @@ static int img_spfi_start_dma(struct spi_master *master,
if (xfer->rx_buf) {
rxconf.direction = DMA_DEV_TO_MEM;
- switch (xfer->bits_per_word) {
- case 32:
+ if (xfer->len % 4 == 0) {
rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA;
rxconf.src_addr_width = 4;
rxconf.src_maxburst = 4;
- break;
- case 8:
- default:
+ } else {
rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA;
rxconf.src_addr_width = 1;
rxconf.src_maxburst = 4;
@@ -358,18 +353,14 @@ static int img_spfi_start_dma(struct spi_master *master,
if (xfer->tx_buf) {
txconf.direction = DMA_MEM_TO_DEV;
- switch (xfer->bits_per_word) {
- case 32:
+ if (xfer->len % 4 == 0) {
txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA;
txconf.dst_addr_width = 4;
txconf.dst_maxburst = 4;
- break;
- case 8:
- default:
+ } else {
txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA;
txconf.dst_addr_width = 1;
txconf.dst_maxburst = 4;
- break;
}
dmaengine_slave_config(spfi->tx_ch, &txconf);
@@ -508,9 +499,7 @@ static void img_spfi_set_cs(struct spi_device *spi, bool enable)
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)
+ if (xfer->len > SPFI_32BIT_FIFO_SIZE)
return true;
return false;
}
diff --git a/drivers/spi/spi-imx.c b/drivers/spi/spi-imx.c
index 961b97d43b43..6fea4af51c41 100644
--- a/drivers/spi/spi-imx.c
+++ b/drivers/spi/spi-imx.c
@@ -89,7 +89,6 @@ struct spi_imx_data {
struct completion xfer_done;
void __iomem *base;
- int irq;
struct clk *clk_per;
struct clk *clk_ipg;
unsigned long spi_clk;
@@ -823,6 +822,10 @@ static int spi_imx_sdma_init(struct device *dev, struct spi_imx_data *spi_imx,
struct dma_slave_config slave_config = {};
int ret;
+ /* use pio mode for i.mx6dl chip TKT238285 */
+ if (of_machine_is_compatible("fsl,imx6dl"))
+ return 0;
+
/* Prepare for TX DMA: */
master->dma_tx = dma_request_slave_channel(dev, "tx");
if (!master->dma_tx) {
@@ -892,6 +895,7 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
{
struct dma_async_tx_descriptor *desc_tx = NULL, *desc_rx = NULL;
int ret;
+ unsigned long timeout;
u32 dma;
int left;
struct spi_master *master = spi_imx->bitbang.master;
@@ -939,17 +943,17 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
dma_async_issue_pending(master->dma_tx);
dma_async_issue_pending(master->dma_rx);
/* Wait SDMA to finish the data transfer.*/
- ret = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
+ timeout = wait_for_completion_timeout(&spi_imx->dma_tx_completion,
IMX_DMA_TIMEOUT);
- if (!ret) {
+ if (!timeout) {
pr_warn("%s %s: I/O Error in DMA TX\n",
dev_driver_string(&master->dev),
dev_name(&master->dev));
dmaengine_terminate_all(master->dma_tx);
} else {
- ret = wait_for_completion_timeout(&spi_imx->dma_rx_completion,
- IMX_DMA_TIMEOUT);
- if (!ret) {
+ timeout = wait_for_completion_timeout(
+ &spi_imx->dma_rx_completion, IMX_DMA_TIMEOUT);
+ if (!timeout) {
pr_warn("%s %s: I/O Error in DMA RX\n",
dev_driver_string(&master->dev),
dev_name(&master->dev));
@@ -964,9 +968,9 @@ static int spi_imx_dma_transfer(struct spi_imx_data *spi_imx,
spi_imx->dma_finished = 1;
spi_imx->devtype_data->trigger(spi_imx);
- if (!ret)
+ if (!timeout)
ret = -ETIMEDOUT;
- else if (ret > 0)
+ else
ret = transfer->len;
return ret;
@@ -1076,7 +1080,7 @@ static int spi_imx_probe(struct platform_device *pdev)
struct spi_master *master;
struct spi_imx_data *spi_imx;
struct resource *res;
- int i, ret, num_cs;
+ int i, ret, num_cs, irq;
if (!np && !mxc_platform_info) {
dev_err(&pdev->dev, "can't get the platform data\n");
@@ -1143,16 +1147,16 @@ static int spi_imx_probe(struct platform_device *pdev)
goto out_master_put;
}
- spi_imx->irq = platform_get_irq(pdev, 0);
- if (spi_imx->irq < 0) {
- ret = spi_imx->irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ ret = irq;
goto out_master_put;
}
- ret = devm_request_irq(&pdev->dev, spi_imx->irq, spi_imx_isr, 0,
+ ret = devm_request_irq(&pdev->dev, irq, spi_imx_isr, 0,
dev_name(&pdev->dev), spi_imx);
if (ret) {
- dev_err(&pdev->dev, "can't get irq%d: %d\n", spi_imx->irq, ret);
+ dev_err(&pdev->dev, "can't get irq%d: %d\n", irq, ret);
goto out_master_put;
}
diff --git a/drivers/spi/spi-lm70llp.c b/drivers/spi/spi-lm70llp.c
index 41c5765be746..ba72347cb99d 100644
--- a/drivers/spi/spi-lm70llp.c
+++ b/drivers/spi/spi-lm70llp.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c
index 1bbac0378bf7..5468fc70dbf8 100644
--- a/drivers/spi/spi-meson-spifc.c
+++ b/drivers/spi/spi-meson-spifc.c
@@ -85,7 +85,7 @@ struct meson_spifc {
struct device *dev;
};
-static struct regmap_config spifc_regmap_config = {
+static const struct regmap_config spifc_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 4045a1e580e1..5b0e9a3e83f6 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -282,9 +282,8 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
dmaengine_submit(desc);
dma_async_issue_pending(ssp->dmach);
- ret = wait_for_completion_timeout(&spi->c,
- msecs_to_jiffies(SSP_TIMEOUT));
- if (!ret) {
+ if (!wait_for_completion_timeout(&spi->c,
+ msecs_to_jiffies(SSP_TIMEOUT))) {
dev_err(ssp->dev, "DMA transfer timeout\n");
ret = -ETIMEDOUT;
dmaengine_terminate_all(ssp->dmach);
diff --git a/drivers/spi/spi-omap-100k.c b/drivers/spi/spi-omap-100k.c
index 79399ae9c84c..d890d309dff9 100644
--- a/drivers/spi/spi-omap-100k.c
+++ b/drivers/spi/spi-omap-100k.c
@@ -16,11 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/spi/spi-omap-uwire.c b/drivers/spi/spi-omap-uwire.c
index daf1ada5cd11..3c0844457c07 100644
--- a/drivers/spi/spi-omap-uwire.c
+++ b/drivers/spi/spi-omap-uwire.c
@@ -28,10 +28,6 @@
* 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.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
#include <linux/init.h>
diff --git a/drivers/spi/spi-omap2-mcspi.c b/drivers/spi/spi-omap2-mcspi.c
index 3bc3cbabbbc0..4df8942058de 100644
--- a/drivers/spi/spi-omap2-mcspi.c
+++ b/drivers/spi/spi-omap2-mcspi.c
@@ -14,11 +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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
*/
#include <linux/kernel.h>
diff --git a/drivers/spi/spi-orion.c b/drivers/spi/spi-orion.c
index 3dec9e0b99b8..861664776672 100644
--- a/drivers/spi/spi-orion.c
+++ b/drivers/spi/spi-orion.c
@@ -28,7 +28,12 @@
/* Runtime PM autosuspend timeout: PM is fairly light on this driver */
#define SPI_AUTOSUSPEND_TIMEOUT 200
-#define ORION_NUM_CHIPSELECTS 1 /* only one slave is supported*/
+/* Some SoCs using this driver support up to 8 chip selects.
+ * It is up to the implementer to only use the chip selects
+ * that are available.
+ */
+#define ORION_NUM_CHIPSELECTS 8
+
#define ORION_SPI_WAIT_RDY_MAX_LOOP 2000 /* in usec */
#define ORION_SPI_IF_CTRL_REG 0x00
@@ -44,6 +49,10 @@
#define ARMADA_SPI_CLK_PRESCALE_MASK 0xDF
#define ORION_SPI_MODE_MASK (ORION_SPI_MODE_CPOL | \
ORION_SPI_MODE_CPHA)
+#define ORION_SPI_CS_MASK 0x1C
+#define ORION_SPI_CS_SHIFT 2
+#define ORION_SPI_CS(cs) ((cs << ORION_SPI_CS_SHIFT) & \
+ ORION_SPI_CS_MASK)
enum orion_spi_type {
ORION_SPI,
@@ -215,9 +224,18 @@ orion_spi_setup_transfer(struct spi_device *spi, struct spi_transfer *t)
return 0;
}
-static void orion_spi_set_cs(struct orion_spi *orion_spi, int enable)
+static void orion_spi_set_cs(struct spi_device *spi, bool enable)
{
- if (enable)
+ struct orion_spi *orion_spi;
+
+ orion_spi = spi_master_get_devdata(spi->master);
+
+ orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, ORION_SPI_CS_MASK);
+ orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG,
+ ORION_SPI_CS(spi->chip_select));
+
+ /* Chip select logic is inverted from spi_set_cs */
+ if (!enable)
orion_spi_setbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
else
orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
@@ -332,64 +350,31 @@ out:
return xfer->len - count;
}
-static int orion_spi_transfer_one_message(struct spi_master *master,
- struct spi_message *m)
+static int orion_spi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *t)
{
- struct orion_spi *orion_spi = spi_master_get_devdata(master);
- struct spi_device *spi = m->spi;
- struct spi_transfer *t = NULL;
- int par_override = 0;
int status = 0;
- int cs_active = 0;
-
- /* Load defaults */
- status = orion_spi_setup_transfer(spi, NULL);
+ status = orion_spi_setup_transfer(spi, t);
if (status < 0)
- goto msg_done;
-
- list_for_each_entry(t, &m->transfers, transfer_list) {
- if (par_override || t->speed_hz || t->bits_per_word) {
- par_override = 1;
- status = orion_spi_setup_transfer(spi, t);
- if (status < 0)
- break;
- if (!t->speed_hz && !t->bits_per_word)
- par_override = 0;
- }
-
- if (!cs_active) {
- orion_spi_set_cs(orion_spi, 1);
- cs_active = 1;
- }
+ return status;
- if (t->len)
- m->actual_length += orion_spi_write_read(spi, t);
+ if (t->len)
+ orion_spi_write_read(spi, t);
- if (t->delay_usecs)
- udelay(t->delay_usecs);
-
- if (t->cs_change) {
- orion_spi_set_cs(orion_spi, 0);
- cs_active = 0;
- }
- }
-
-msg_done:
- if (cs_active)
- orion_spi_set_cs(orion_spi, 0);
-
- m->status = status;
- spi_finalize_current_message(master);
+ return status;
+}
- return 0;
+static int orion_spi_setup(struct spi_device *spi)
+{
+ return orion_spi_setup_transfer(spi, NULL);
}
static int orion_spi_reset(struct orion_spi *orion_spi)
{
/* Verify that the CS is deasserted */
- orion_spi_set_cs(orion_spi, 0);
-
+ orion_spi_clrbits(orion_spi, ORION_SPI_IF_CTRL_REG, 0x1);
return 0;
}
@@ -442,9 +427,10 @@ static int orion_spi_probe(struct platform_device *pdev)
/* we support only mode 0, and no options */
master->mode_bits = SPI_CPHA | SPI_CPOL;
-
- master->transfer_one_message = orion_spi_transfer_one_message;
+ master->set_cs = orion_spi_set_cs;
+ master->transfer_one = orion_spi_transfer_one;
master->num_chipselect = ORION_NUM_CHIPSELECTS;
+ master->setup = orion_spi_setup;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
master->auto_runtime_pm = true;
diff --git a/drivers/spi/spi-pxa2xx-dma.c b/drivers/spi/spi-pxa2xx-dma.c
index 62a9297e96ac..66a173939be8 100644
--- a/drivers/spi/spi-pxa2xx-dma.c
+++ b/drivers/spi/spi-pxa2xx-dma.c
@@ -111,23 +111,24 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
* by using ->dma_running.
*/
if (atomic_dec_and_test(&drv_data->dma_running)) {
- void __iomem *reg = drv_data->ioaddr;
-
/*
* If the other CPU is still handling the ROR interrupt we
* might not know about the error yet. So we re-check the
* ROR bit here before we clear the status register.
*/
if (!error) {
- u32 status = read_SSSR(reg) & drv_data->mask_sr;
+ u32 status = pxa2xx_spi_read(drv_data, SSSR)
+ & drv_data->mask_sr;
error = status & SSSR_ROR;
}
/* Clear status & disable interrupts */
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ pxa2xx_spi_write(drv_data, SSCR1,
+ pxa2xx_spi_read(drv_data, SSCR1)
+ & ~drv_data->dma_cr1);
write_SSSR_CS(drv_data, drv_data->clear_sr);
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
if (!error) {
pxa2xx_spi_unmap_dma_buffers(drv_data);
@@ -139,7 +140,9 @@ static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data,
msg->state = pxa2xx_spi_next_transfer(drv_data);
} else {
/* In case we got an error we disable the SSP now */
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ pxa2xx_spi_write(drv_data, SSCR0,
+ pxa2xx_spi_read(drv_data, SSCR0)
+ & ~SSCR0_SSE);
msg->state = ERROR_STATE;
}
@@ -247,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
u32 status;
- status = read_SSSR(drv_data->ioaddr) & drv_data->mask_sr;
+ status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
if (status & SSSR_ROR) {
dev_err(&drv_data->pdev->dev, "FIFO overrun\n");
diff --git a/drivers/spi/spi-pxa2xx-pxadma.c b/drivers/spi/spi-pxa2xx-pxadma.c
index e8a26f25d5c0..2e0796a0003f 100644
--- a/drivers/spi/spi-pxa2xx-pxadma.c
+++ b/drivers/spi/spi-pxa2xx-pxadma.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/delay.h>
@@ -25,6 +21,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
+#include <mach/dma.h>
#include "spi-pxa2xx.h"
#define DMA_INT_MASK (DCSR_ENDINTR | DCSR_STARTINTR | DCSR_BUSERR)
@@ -118,11 +115,11 @@ static void pxa2xx_spi_unmap_dma_buffers(struct driver_data *drv_data)
drv_data->dma_mapped = 0;
}
-static int wait_ssp_rx_stall(void const __iomem *ioaddr)
+static int wait_ssp_rx_stall(struct driver_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
- while ((read_SSSR(ioaddr) & SSSR_BSY) && --limit)
+ while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit)
cpu_relax();
return limit;
@@ -141,17 +138,18 @@ static int wait_dma_channel_stop(int channel)
static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
const char *msg)
{
- void __iomem *reg = drv_data->ioaddr;
-
/* Stop and reset */
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
write_SSSR_CS(drv_data, drv_data->clear_sr);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ pxa2xx_spi_write(drv_data, SSCR1,
+ pxa2xx_spi_read(drv_data, SSCR1)
+ & ~drv_data->dma_cr1);
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
pxa2xx_spi_flush(drv_data);
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ pxa2xx_spi_write(drv_data, SSCR0,
+ pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
pxa2xx_spi_unmap_dma_buffers(drv_data);
@@ -163,11 +161,12 @@ static void pxa2xx_spi_dma_error_stop(struct driver_data *drv_data,
static void pxa2xx_spi_dma_transfer_complete(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
struct spi_message *msg = drv_data->cur_msg;
/* Clear and disable interrupts on SSP and DMA channels*/
- write_SSCR1(read_SSCR1(reg) & ~drv_data->dma_cr1, reg);
+ pxa2xx_spi_write(drv_data, SSCR1,
+ pxa2xx_spi_read(drv_data, SSCR1)
+ & ~drv_data->dma_cr1);
write_SSSR_CS(drv_data, drv_data->clear_sr);
DCSR(drv_data->tx_channel) = RESET_DMA_CHANNEL;
DCSR(drv_data->rx_channel) = RESET_DMA_CHANNEL;
@@ -228,7 +227,7 @@ void pxa2xx_spi_dma_handler(int channel, void *data)
&& (drv_data->ssp_type == PXA25x_SSP)) {
/* Wait for rx to stall */
- if (wait_ssp_rx_stall(drv_data->ioaddr) == 0)
+ if (wait_ssp_rx_stall(drv_data) == 0)
dev_err(&drv_data->pdev->dev,
"dma_handler: ssp rx stall failed\n");
@@ -240,9 +239,8 @@ void pxa2xx_spi_dma_handler(int channel, void *data)
irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
{
u32 irq_status;
- void __iomem *reg = drv_data->ioaddr;
- irq_status = read_SSSR(reg) & drv_data->mask_sr;
+ irq_status = pxa2xx_spi_read(drv_data, SSSR) & drv_data->mask_sr;
if (irq_status & SSSR_ROR) {
pxa2xx_spi_dma_error_stop(drv_data,
"dma_transfer: fifo overrun");
@@ -252,7 +250,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
/* Check for false positive timeout */
if ((irq_status & SSSR_TINT)
&& (DCSR(drv_data->tx_channel) & DCSR_RUN)) {
- write_SSSR(SSSR_TINT, reg);
+ pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT);
return IRQ_HANDLED;
}
@@ -261,7 +259,7 @@ irqreturn_t pxa2xx_spi_dma_transfer(struct driver_data *drv_data)
/* Clear and disable timeout interrupt, do the rest in
* dma_transfer_complete */
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
/* finish this transfer, start the next */
pxa2xx_spi_dma_transfer_complete(drv_data);
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 23822e7df6c1..6f72ad01e041 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
@@ -45,8 +41,6 @@ MODULE_DESCRIPTION("PXA2xx SSP SPI Controller");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:pxa2xx-spi");
-#define MAX_BUSES 3
-
#define TIMOUT_DFLT 1000
/*
@@ -162,7 +156,6 @@ pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data)
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) {
@@ -174,7 +167,7 @@ static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
break;
}
- return (read_SSSR(reg) & mask) == mask;
+ return (pxa2xx_spi_read(drv_data, SSSR) & mask) == mask;
}
static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
@@ -253,9 +246,6 @@ static void lpss_ssp_setup(struct driver_data *drv_data)
unsigned offset = 0x400;
u32 value, orig;
- if (!is_lpss_ssp(drv_data))
- return;
-
/*
* Perform auto-detection of the LPSS SSP private registers. They
* can be either at 1k or 2k offset from the base address.
@@ -304,9 +294,6 @@ static void lpss_ssp_cs_control(struct driver_data *drv_data, bool enable)
{
u32 value;
- if (!is_lpss_ssp(drv_data))
- return;
-
value = __lpss_ssp_read_priv(drv_data, SPI_CS_CONTROL);
if (enable)
value &= ~SPI_CS_CONTROL_CS_HIGH;
@@ -320,7 +307,7 @@ static void cs_assert(struct driver_data *drv_data)
struct chip_data *chip = drv_data->cur_chip;
if (drv_data->ssp_type == CE4100_SSP) {
- write_SSSR(drv_data->cur_chip->frm, drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSSR, drv_data->cur_chip->frm);
return;
}
@@ -334,7 +321,8 @@ static void cs_assert(struct driver_data *drv_data)
return;
}
- lpss_ssp_cs_control(drv_data, true);
+ if (is_lpss_ssp(drv_data))
+ lpss_ssp_cs_control(drv_data, true);
}
static void cs_deassert(struct driver_data *drv_data)
@@ -354,20 +342,18 @@ static void cs_deassert(struct driver_data *drv_data)
return;
}
- lpss_ssp_cs_control(drv_data, false);
+ if (is_lpss_ssp(drv_data))
+ lpss_ssp_cs_control(drv_data, false);
}
int pxa2xx_spi_flush(struct driver_data *drv_data)
{
unsigned long limit = loops_per_jiffy << 1;
- void __iomem *reg = drv_data->ioaddr;
-
do {
- while (read_SSSR(reg) & SSSR_RNE) {
- read_SSDR(reg);
- }
- } while ((read_SSSR(reg) & SSSR_BSY) && --limit);
+ while (pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+ pxa2xx_spi_read(drv_data, SSDR);
+ } while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_BSY) && --limit);
write_SSSR_CS(drv_data, SSSR_ROR);
return limit;
@@ -375,14 +361,13 @@ int pxa2xx_spi_flush(struct driver_data *drv_data)
static int null_writer(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
- write_SSDR(0, reg);
+ pxa2xx_spi_write(drv_data, SSDR, 0);
drv_data->tx += n_bytes;
return 1;
@@ -390,12 +375,11 @@ static int null_writer(struct driver_data *drv_data)
static int null_reader(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
- while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
- read_SSDR(reg);
+ while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ pxa2xx_spi_read(drv_data, SSDR);
drv_data->rx += n_bytes;
}
@@ -404,13 +388,11 @@ static int null_reader(struct driver_data *drv_data)
static int u8_writer(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
- write_SSDR(*(u8 *)(drv_data->tx), reg);
+ pxa2xx_spi_write(drv_data, SSDR, *(u8 *)(drv_data->tx));
++drv_data->tx;
return 1;
@@ -418,11 +400,9 @@ static int u8_writer(struct driver_data *drv_data)
static int u8_reader(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
- while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
- *(u8 *)(drv_data->rx) = read_SSDR(reg);
+ while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ *(u8 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
++drv_data->rx;
}
@@ -431,13 +411,11 @@ static int u8_reader(struct driver_data *drv_data)
static int u16_writer(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
- write_SSDR(*(u16 *)(drv_data->tx), reg);
+ pxa2xx_spi_write(drv_data, SSDR, *(u16 *)(drv_data->tx));
drv_data->tx += 2;
return 1;
@@ -445,11 +423,9 @@ static int u16_writer(struct driver_data *drv_data)
static int u16_reader(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
- while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
- *(u16 *)(drv_data->rx) = read_SSDR(reg);
+ while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ *(u16 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
drv_data->rx += 2;
}
@@ -458,13 +434,11 @@ static int u16_reader(struct driver_data *drv_data)
static int u32_writer(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
- write_SSDR(*(u32 *)(drv_data->tx), reg);
+ pxa2xx_spi_write(drv_data, SSDR, *(u32 *)(drv_data->tx));
drv_data->tx += 4;
return 1;
@@ -472,11 +446,9 @@ static int u32_writer(struct driver_data *drv_data)
static int u32_reader(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
- while ((read_SSSR(reg) & SSSR_RNE)
- && (drv_data->rx < drv_data->rx_end)) {
- *(u32 *)(drv_data->rx) = read_SSDR(reg);
+ while ((pxa2xx_spi_read(drv_data, SSSR) & SSSR_RNE)
+ && (drv_data->rx < drv_data->rx_end)) {
+ *(u32 *)(drv_data->rx) = pxa2xx_spi_read(drv_data, SSDR);
drv_data->rx += 4;
}
@@ -552,27 +524,25 @@ static void giveback(struct driver_data *drv_data)
static void reset_sccr1(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
struct chip_data *chip = drv_data->cur_chip;
u32 sccr1_reg;
- sccr1_reg = read_SSCR1(reg) & ~drv_data->int_cr1;
+ sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1) & ~drv_data->int_cr1;
sccr1_reg &= ~SSCR1_RFT;
sccr1_reg |= chip->threshold;
- write_SSCR1(sccr1_reg, reg);
+ pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
}
static void int_error_stop(struct driver_data *drv_data, const char* msg)
{
- void __iomem *reg = drv_data->ioaddr;
-
/* Stop and reset SSP */
write_SSSR_CS(drv_data, drv_data->clear_sr);
reset_sccr1(drv_data);
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
pxa2xx_spi_flush(drv_data);
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
+ pxa2xx_spi_write(drv_data, SSCR0,
+ pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
dev_err(&drv_data->pdev->dev, "%s\n", msg);
@@ -582,13 +552,11 @@ static void int_error_stop(struct driver_data *drv_data, const char* msg)
static void int_transfer_complete(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
-
/* Stop SSP */
write_SSSR_CS(drv_data, drv_data->clear_sr);
reset_sccr1(drv_data);
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
/* Update total byte transferred return count actual bytes read */
drv_data->cur_msg->actual_length += drv_data->len -
@@ -607,12 +575,10 @@ static void int_transfer_complete(struct driver_data *drv_data)
static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
{
- void __iomem *reg = drv_data->ioaddr;
+ u32 irq_mask = (pxa2xx_spi_read(drv_data, SSCR1) & SSCR1_TIE) ?
+ drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
- u32 irq_mask = (read_SSCR1(reg) & SSCR1_TIE) ?
- drv_data->mask_sr : drv_data->mask_sr & ~SSSR_TFS;
-
- u32 irq_status = read_SSSR(reg) & irq_mask;
+ u32 irq_status = pxa2xx_spi_read(drv_data, SSSR) & irq_mask;
if (irq_status & SSSR_ROR) {
int_error_stop(drv_data, "interrupt_transfer: fifo overrun");
@@ -620,7 +586,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
}
if (irq_status & SSSR_TINT) {
- write_SSSR(SSSR_TINT, reg);
+ pxa2xx_spi_write(drv_data, SSSR, SSSR_TINT);
if (drv_data->read(drv_data)) {
int_transfer_complete(drv_data);
return IRQ_HANDLED;
@@ -644,7 +610,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
u32 bytes_left;
u32 sccr1_reg;
- sccr1_reg = read_SSCR1(reg);
+ sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
sccr1_reg &= ~SSCR1_TIE;
/*
@@ -670,7 +636,7 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre);
}
- write_SSCR1(sccr1_reg, reg);
+ pxa2xx_spi_write(drv_data, SSCR1, sccr1_reg);
}
/* We did something */
@@ -680,7 +646,6 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
static irqreturn_t ssp_int(int irq, void *dev_id)
{
struct driver_data *drv_data = dev_id;
- void __iomem *reg = drv_data->ioaddr;
u32 sccr1_reg;
u32 mask = drv_data->mask_sr;
u32 status;
@@ -700,11 +665,11 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
* are all set to one. That means that the device is already
* powered off.
*/
- status = read_SSSR(reg);
+ status = pxa2xx_spi_read(drv_data, SSSR);
if (status == ~0)
return IRQ_NONE;
- sccr1_reg = read_SSCR1(reg);
+ sccr1_reg = pxa2xx_spi_read(drv_data, SSCR1);
/* Ignore possible writes if we don't need to write */
if (!(sccr1_reg & SSCR1_TIE))
@@ -715,10 +680,14 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
if (!drv_data->cur_msg) {
- write_SSCR0(read_SSCR0(reg) & ~SSCR0_SSE, reg);
- write_SSCR1(read_SSCR1(reg) & ~drv_data->int_cr1, reg);
+ pxa2xx_spi_write(drv_data, SSCR0,
+ pxa2xx_spi_read(drv_data, SSCR0)
+ & ~SSCR0_SSE);
+ pxa2xx_spi_write(drv_data, SSCR1,
+ pxa2xx_spi_read(drv_data, SSCR1)
+ & ~drv_data->int_cr1);
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, reg);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
write_SSSR_CS(drv_data, drv_data->clear_sr);
dev_err(&drv_data->pdev->dev,
@@ -787,7 +756,6 @@ static void pump_transfers(unsigned long data)
struct spi_transfer *transfer = NULL;
struct spi_transfer *previous = NULL;
struct chip_data *chip = NULL;
- void __iomem *reg = drv_data->ioaddr;
u32 clk_div = 0;
u8 bits = 0;
u32 speed = 0;
@@ -931,7 +899,7 @@ static void pump_transfers(unsigned long data)
/* Clear status and start DMA engine */
cr1 = chip->cr1 | dma_thresh | drv_data->dma_cr1;
- write_SSSR(drv_data->clear_sr, reg);
+ pxa2xx_spi_write(drv_data, SSSR, drv_data->clear_sr);
pxa2xx_spi_dma_start(drv_data);
} else {
@@ -944,39 +912,43 @@ static void pump_transfers(unsigned long data)
}
if (is_lpss_ssp(drv_data)) {
- if ((read_SSIRF(reg) & 0xff) != chip->lpss_rx_threshold)
- write_SSIRF(chip->lpss_rx_threshold, reg);
- if ((read_SSITF(reg) & 0xffff) != chip->lpss_tx_threshold)
- write_SSITF(chip->lpss_tx_threshold, reg);
+ if ((pxa2xx_spi_read(drv_data, SSIRF) & 0xff)
+ != chip->lpss_rx_threshold)
+ pxa2xx_spi_write(drv_data, SSIRF,
+ chip->lpss_rx_threshold);
+ if ((pxa2xx_spi_read(drv_data, SSITF) & 0xffff)
+ != chip->lpss_tx_threshold)
+ pxa2xx_spi_write(drv_data, SSITF,
+ chip->lpss_tx_threshold);
}
if (is_quark_x1000_ssp(drv_data) &&
- (read_DDS_RATE(reg) != chip->dds_rate))
- write_DDS_RATE(chip->dds_rate, reg);
+ (pxa2xx_spi_read(drv_data, DDS_RATE) != chip->dds_rate))
+ pxa2xx_spi_write(drv_data, DDS_RATE, chip->dds_rate);
/* see if we need to reload the config registers */
- if ((read_SSCR0(reg) != cr0) ||
- (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) {
-
+ if ((pxa2xx_spi_read(drv_data, SSCR0) != cr0)
+ || (pxa2xx_spi_read(drv_data, SSCR1) & change_mask)
+ != (cr1 & change_mask)) {
/* stop the SSP, and update the other bits */
- write_SSCR0(cr0 & ~SSCR0_SSE, reg);
+ pxa2xx_spi_write(drv_data, SSCR0, cr0 & ~SSCR0_SSE);
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(chip->timeout, reg);
+ pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
/* first set CR1 without interrupt and service enables */
- write_SSCR1(cr1 & change_mask, reg);
+ pxa2xx_spi_write(drv_data, SSCR1, cr1 & change_mask);
/* restart the SSP */
- write_SSCR0(cr0, reg);
+ pxa2xx_spi_write(drv_data, SSCR0, cr0);
} else {
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(chip->timeout, reg);
+ pxa2xx_spi_write(drv_data, SSTO, chip->timeout);
}
cs_assert(drv_data);
/* after chip select, release the data by enabling service
* requests and interrupts, without changing any mode bits */
- write_SSCR1(cr1, reg);
+ pxa2xx_spi_write(drv_data, SSCR1, cr1);
}
static int pxa2xx_spi_transfer_one_message(struct spi_master *master,
@@ -1005,8 +977,8 @@ static int pxa2xx_spi_unprepare_transfer(struct spi_master *master)
struct driver_data *drv_data = spi_master_get_devdata(master);
/* Disable the SSP now */
- write_SSCR0(read_SSCR0(drv_data->ioaddr) & ~SSCR0_SSE,
- drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSCR0,
+ pxa2xx_spi_read(drv_data, SSCR0) & ~SSCR0_SSE);
return 0;
}
@@ -1289,6 +1261,7 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
struct driver_data *drv_data;
struct ssp_device *ssp;
int status;
+ u32 tmp;
platform_info = dev_get_platdata(dev);
if (!platform_info) {
@@ -1386,38 +1359,35 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->max_clk_rate = clk_get_rate(ssp->clk);
/* Load default SSP configuration */
- write_SSCR0(0, drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSCR0, 0);
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);
+ tmp = QUARK_X1000_SSCR1_RxTresh(RX_THRESH_QUARK_X1000_DFLT)
+ | QUARK_X1000_SSCR1_TxTresh(TX_THRESH_QUARK_X1000_DFLT);
+ pxa2xx_spi_write(drv_data, SSCR1, tmp);
/* using the Motorola SPI protocol and use 8 bit frame */
- write_SSCR0(QUARK_X1000_SSCR0_Motorola
- | QUARK_X1000_SSCR0_DataSize(8),
- drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSCR0,
+ QUARK_X1000_SSCR0_Motorola
+ | QUARK_X1000_SSCR0_DataSize(8));
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);
+ tmp = SSCR1_RxTresh(RX_THRESH_DFLT) |
+ SSCR1_TxTresh(TX_THRESH_DFLT);
+ pxa2xx_spi_write(drv_data, SSCR1, tmp);
+ tmp = SSCR0_SCR(2) | SSCR0_Motorola | SSCR0_DataSize(8);
+ pxa2xx_spi_write(drv_data, SSCR0, tmp);
break;
}
if (!pxa25x_ssp_comp(drv_data))
- write_SSTO(0, drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSTO, 0);
if (!is_quark_x1000_ssp(drv_data))
- write_SSPSP(0, drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSPSP, 0);
- lpss_ssp_setup(drv_data);
+ if (is_lpss_ssp(drv_data))
+ lpss_ssp_setup(drv_data);
tasklet_init(&drv_data->pump_transfers, pump_transfers,
(unsigned long)drv_data);
@@ -1460,7 +1430,7 @@ static int pxa2xx_spi_remove(struct platform_device *pdev)
pm_runtime_get_sync(&pdev->dev);
/* Disable the SSP at the peripheral and SOC level */
- write_SSCR0(0, drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSCR0, 0);
clk_disable_unprepare(ssp->clk);
/* Release DMA */
@@ -1497,7 +1467,7 @@ static int pxa2xx_spi_suspend(struct device *dev)
status = spi_master_suspend(drv_data->master);
if (status != 0)
return status;
- write_SSCR0(0, drv_data->ioaddr);
+ pxa2xx_spi_write(drv_data, SSCR0, 0);
if (!pm_runtime_suspended(dev))
clk_disable_unprepare(ssp->clk);
@@ -1518,7 +1488,8 @@ static int pxa2xx_spi_resume(struct device *dev)
clk_prepare_enable(ssp->clk);
/* Restore LPSS private register bits */
- lpss_ssp_setup(drv_data);
+ if (is_lpss_ssp(drv_data))
+ lpss_ssp_setup(drv_data);
/* Start the queue running */
status = spi_master_resume(drv_data->master);
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 6bec59c90cd4..85a58c906869 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -115,23 +115,17 @@ struct chip_data {
void (*cs_control)(u32 command);
};
-#define DEFINE_SSP_REG(reg, off) \
-static inline u32 read_##reg(void const __iomem *p) \
-{ return __raw_readl(p + (off)); } \
-\
-static inline void write_##reg(u32 v, void __iomem *p) \
-{ __raw_writel(v, p + (off)); }
-
-DEFINE_SSP_REG(SSCR0, 0x00)
-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)
-DEFINE_SSP_REG(SSIRF, SSIRF)
+static inline u32 pxa2xx_spi_read(const struct driver_data *drv_data,
+ unsigned reg)
+{
+ return __raw_readl(drv_data->ioaddr + reg);
+}
+
+static inline void pxa2xx_spi_write(const struct driver_data *drv_data,
+ unsigned reg, u32 val)
+{
+ __raw_writel(val, drv_data->ioaddr + reg);
+}
#define START_STATE ((void *)0)
#define RUNNING_STATE ((void *)1)
@@ -155,13 +149,11 @@ static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
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 ||
drv_data->ssp_type == QUARK_X1000_SSP)
- val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
+ val |= pxa2xx_spi_read(drv_data, SSSR) & SSSR_ALT_FRM_MASK;
- write_SSSR(val, reg);
+ pxa2xx_spi_write(drv_data, SSSR, val);
}
extern int pxa2xx_spi_flush(struct driver_data *drv_data);
diff --git a/drivers/spi/spi-qup.c b/drivers/spi/spi-qup.c
index e7fb5a0d2e8d..ff9cdbdb6672 100644
--- a/drivers/spi/spi-qup.c
+++ b/drivers/spi/spi-qup.c
@@ -337,7 +337,7 @@ static irqreturn_t spi_qup_qup_irq(int irq, void *dev_id)
static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
{
struct spi_qup *controller = spi_master_get_devdata(spi->master);
- u32 config, iomode, mode;
+ u32 config, iomode, mode, control;
int ret, n_words, w_size;
if (spi->mode & SPI_LOOP && xfer->len > controller->in_fifo_sz) {
@@ -392,6 +392,15 @@ static int spi_qup_io_config(struct spi_device *spi, struct spi_transfer *xfer)
writel_relaxed(iomode, controller->base + QUP_IO_M_MODES);
+ control = readl_relaxed(controller->base + SPI_IO_CONTROL);
+
+ if (spi->mode & SPI_CPOL)
+ control |= SPI_IO_C_CLK_IDLE_HIGH;
+ else
+ control &= ~SPI_IO_C_CLK_IDLE_HIGH;
+
+ writel_relaxed(control, controller->base + SPI_IO_CONTROL);
+
config = readl_relaxed(controller->base + SPI_CONFIG);
if (spi->mode & SPI_LOOP)
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index daabbabd26b0..1a777dc261d6 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -437,6 +437,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
rs->state &= ~TXBUSY;
spin_unlock_irqrestore(&rs->lock, flags);
+ rxdesc = NULL;
if (rs->rx) {
rxconf.direction = rs->dma_rx.direction;
rxconf.src_addr = rs->dma_rx.addr;
@@ -453,6 +454,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
rxdesc->callback_param = rs;
}
+ txdesc = NULL;
if (rs->tx) {
txconf.direction = rs->dma_tx.direction;
txconf.dst_addr = rs->dma_tx.addr;
@@ -470,7 +472,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
}
/* rx must be started before tx due to spi instinct */
- if (rs->rx) {
+ if (rxdesc) {
spin_lock_irqsave(&rs->lock, flags);
rs->state |= RXBUSY;
spin_unlock_irqrestore(&rs->lock, flags);
@@ -478,7 +480,7 @@ static void rockchip_spi_prepare_dma(struct rockchip_spi *rs)
dma_async_issue_pending(rs->dma_rx.ch);
}
- if (rs->tx) {
+ if (txdesc) {
spin_lock_irqsave(&rs->lock, flags);
rs->state |= TXBUSY;
spin_unlock_irqrestore(&rs->lock, flags);
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c
index 2071f788c6fb..46ce47076e63 100644
--- a/drivers/spi/spi-rspi.c
+++ b/drivers/spi/spi-rspi.c
@@ -15,11 +15,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/module.h>
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 37b19836f5cb..9231c34b5a5c 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
diff --git a/drivers/spi/spi-sc18is602.c b/drivers/spi/spi-sc18is602.c
index 237f2e7a7179..5a56acf8a43e 100644
--- a/drivers/spi/spi-sc18is602.c
+++ b/drivers/spi/spi-sc18is602.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/kernel.h>
diff --git a/drivers/spi/spi-sh-hspi.c b/drivers/spi/spi-sh-hspi.c
index fc29233d0650..20e800e70442 100644
--- a/drivers/spi/spi-sh-hspi.c
+++ b/drivers/spi/spi-sh-hspi.c
@@ -16,11 +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/clk.h>
diff --git a/drivers/spi/spi-sh-msiof.c b/drivers/spi/spi-sh-msiof.c
index 3ab7a21445fc..e57eec0b2f46 100644
--- a/drivers/spi/spi-sh-msiof.c
+++ b/drivers/spi/spi-sh-msiof.c
@@ -82,6 +82,8 @@ struct sh_msiof_spi_priv {
#define MDR1_SYNCMD_LR 0x30000000 /* L/R mode */
#define MDR1_SYNCAC_SHIFT 25 /* Sync Polarity (1 = Active-low) */
#define MDR1_BITLSB_SHIFT 24 /* MSB/LSB First (1 = LSB first) */
+#define MDR1_DTDL_SHIFT 20 /* Data Pin Bit Delay for MSIOF_SYNC */
+#define MDR1_SYNCDL_SHIFT 16 /* Frame Sync Signal Timing Delay */
#define MDR1_FLD_MASK 0x0000000c /* Frame Sync Signal Interval (0-3) */
#define MDR1_FLD_SHIFT 2
#define MDR1_XXSTP 0x00000001 /* Transmission/Reception Stop on FIFO */
@@ -241,42 +243,80 @@ static irqreturn_t sh_msiof_spi_irq(int irq, void *data)
static struct {
unsigned short div;
- unsigned short scr;
-} const sh_msiof_spi_clk_table[] = {
- { 1, SCR_BRPS( 1) | SCR_BRDV_DIV_1 },
- { 2, SCR_BRPS( 1) | SCR_BRDV_DIV_2 },
- { 4, SCR_BRPS( 1) | SCR_BRDV_DIV_4 },
- { 8, SCR_BRPS( 1) | SCR_BRDV_DIV_8 },
- { 16, SCR_BRPS( 1) | SCR_BRDV_DIV_16 },
- { 32, SCR_BRPS( 1) | SCR_BRDV_DIV_32 },
- { 64, SCR_BRPS(32) | SCR_BRDV_DIV_2 },
- { 128, SCR_BRPS(32) | SCR_BRDV_DIV_4 },
- { 256, SCR_BRPS(32) | SCR_BRDV_DIV_8 },
- { 512, SCR_BRPS(32) | SCR_BRDV_DIV_16 },
- { 1024, SCR_BRPS(32) | SCR_BRDV_DIV_32 },
+ unsigned short brdv;
+} const sh_msiof_spi_div_table[] = {
+ { 1, SCR_BRDV_DIV_1 },
+ { 2, SCR_BRDV_DIV_2 },
+ { 4, SCR_BRDV_DIV_4 },
+ { 8, SCR_BRDV_DIV_8 },
+ { 16, SCR_BRDV_DIV_16 },
+ { 32, SCR_BRDV_DIV_32 },
};
static void sh_msiof_spi_set_clk_regs(struct sh_msiof_spi_priv *p,
unsigned long parent_rate, u32 spi_hz)
{
unsigned long div = 1024;
+ u32 brps, scr;
size_t k;
if (!WARN_ON(!spi_hz || !parent_rate))
div = DIV_ROUND_UP(parent_rate, spi_hz);
- /* TODO: make more fine grained */
-
- for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_clk_table); k++) {
- if (sh_msiof_spi_clk_table[k].div >= div)
+ for (k = 0; k < ARRAY_SIZE(sh_msiof_spi_div_table); k++) {
+ brps = DIV_ROUND_UP(div, sh_msiof_spi_div_table[k].div);
+ if (brps <= 32) /* max of brdv is 32 */
break;
}
- k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_clk_table) - 1);
+ k = min_t(int, k, ARRAY_SIZE(sh_msiof_spi_div_table) - 1);
- sh_msiof_write(p, TSCR, sh_msiof_spi_clk_table[k].scr);
+ scr = sh_msiof_spi_div_table[k].brdv | SCR_BRPS(brps);
+ sh_msiof_write(p, TSCR, scr);
if (!(p->chipdata->master_flags & SPI_MASTER_MUST_TX))
- sh_msiof_write(p, RSCR, sh_msiof_spi_clk_table[k].scr);
+ sh_msiof_write(p, RSCR, scr);
+}
+
+static u32 sh_msiof_get_delay_bit(u32 dtdl_or_syncdl)
+{
+ /*
+ * DTDL/SYNCDL bit : p->info->dtdl or p->info->syncdl
+ * b'000 : 0
+ * b'001 : 100
+ * b'010 : 200
+ * b'011 (SYNCDL only) : 300
+ * b'101 : 50
+ * b'110 : 150
+ */
+ if (dtdl_or_syncdl % 100)
+ return dtdl_or_syncdl / 100 + 5;
+ else
+ return dtdl_or_syncdl / 100;
+}
+
+static u32 sh_msiof_spi_get_dtdl_and_syncdl(struct sh_msiof_spi_priv *p)
+{
+ u32 val;
+
+ if (!p->info)
+ return 0;
+
+ /* check if DTDL and SYNCDL is allowed value */
+ if (p->info->dtdl > 200 || p->info->syncdl > 300) {
+ dev_warn(&p->pdev->dev, "DTDL or SYNCDL is too large\n");
+ return 0;
+ }
+
+ /* check if the sum of DTDL and SYNCDL becomes an integer value */
+ if ((p->info->dtdl + p->info->syncdl) % 100) {
+ dev_warn(&p->pdev->dev, "the sum of DTDL/SYNCDL is not good\n");
+ return 0;
+ }
+
+ val = sh_msiof_get_delay_bit(p->info->dtdl) << MDR1_DTDL_SHIFT;
+ val |= sh_msiof_get_delay_bit(p->info->syncdl) << MDR1_SYNCDL_SHIFT;
+
+ return val;
}
static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
@@ -296,6 +336,7 @@ static void sh_msiof_spi_set_pin_regs(struct sh_msiof_spi_priv *p,
tmp = MDR1_SYNCMD_SPI | 1 << MDR1_FLD_SHIFT | MDR1_XXSTP;
tmp |= !cs_high << MDR1_SYNCAC_SHIFT;
tmp |= lsb_first << MDR1_BITLSB_SHIFT;
+ tmp |= sh_msiof_spi_get_dtdl_and_syncdl(p);
sh_msiof_write(p, TMDR1, tmp | MDR1_TRMD | TMDR1_PCON);
if (p->chipdata->master_flags & SPI_MASTER_MUST_TX) {
/* These bits are reserved if RX needs TX */
@@ -501,7 +542,7 @@ static int sh_msiof_spi_setup(struct spi_device *spi)
gpio_set_value(spi->cs_gpio, !(spi->mode & SPI_CS_HIGH));
- pm_runtime_put_sync(&p->pdev->dev);
+ pm_runtime_put(&p->pdev->dev);
return 0;
}
@@ -595,8 +636,7 @@ static int sh_msiof_spi_txrx_once(struct sh_msiof_spi_priv *p,
}
/* wait for tx fifo to be emptied / rx fifo to be filled */
- ret = wait_for_completion_timeout(&p->done, HZ);
- if (!ret) {
+ if (!wait_for_completion_timeout(&p->done, HZ)) {
dev_err(&p->pdev->dev, "PIO timeout\n");
ret = -ETIMEDOUT;
goto stop_reset;
@@ -706,8 +746,7 @@ static int sh_msiof_dma_once(struct sh_msiof_spi_priv *p, const void *tx,
}
/* wait for tx fifo to be emptied / rx fifo to be filled */
- ret = wait_for_completion_timeout(&p->done, HZ);
- if (!ret) {
+ if (!wait_for_completion_timeout(&p->done, HZ)) {
dev_err(&p->pdev->dev, "DMA timeout\n");
ret = -ETIMEDOUT;
goto stop_reset;
@@ -957,6 +996,8 @@ static struct sh_msiof_spi_info *sh_msiof_spi_parse_dt(struct device *dev)
&info->tx_fifo_override);
of_property_read_u32(np, "renesas,rx-fifo-size",
&info->rx_fifo_override);
+ of_property_read_u32(np, "renesas,dtdl", &info->dtdl);
+ of_property_read_u32(np, "renesas,syncdl", &info->syncdl);
info->num_chipselect = num_cs;
diff --git a/drivers/spi/spi-sh.c b/drivers/spi/spi-sh.c
index 1cfc906dd174..502501187c9e 100644
--- a/drivers/spi/spi-sh.c
+++ b/drivers/spi/spi-sh.c
@@ -14,11 +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/module.h>
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index d075191476f0..f5715c9f68b0 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -818,7 +818,6 @@ static SIMPLE_DEV_PM_OPS(spi_sirfsoc_pm_ops, spi_sirfsoc_suspend,
static const struct of_device_id spi_sirfsoc_of_match[] = {
{ .compatible = "sirf,prima2-spi", },
- { .compatible = "sirf,marco-spi", },
{}
};
MODULE_DEVICE_TABLE(of, spi_sirfsoc_of_match);
diff --git a/drivers/spi/spi-st-ssc4.c b/drivers/spi/spi-st-ssc4.c
new file mode 100644
index 000000000000..2faeaa7b57a8
--- /dev/null
+++ b/drivers/spi/spi-st-ssc4.c
@@ -0,0 +1,504 @@
+/*
+ * Copyright (c) 2008-2014 STMicroelectronics Limited
+ *
+ * Author: Angus Clark <Angus.Clark@st.com>
+ * Patrice Chotard <patrice.chotard@st.com>
+ * Lee Jones <lee.jones@linaro.org>
+ *
+ * SPI master mode controller driver, used in STMicroelectronics devices.
+ *
+ * May be copied or modified under the terms of the GNU General Public
+ * License Version 2.0 only. See linux/COPYING for more information.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+#include <linux/of_irq.h>
+#include <linux/pm_runtime.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+
+/* SSC registers */
+#define SSC_BRG 0x000
+#define SSC_TBUF 0x004
+#define SSC_RBUF 0x008
+#define SSC_CTL 0x00C
+#define SSC_IEN 0x010
+#define SSC_I2C 0x018
+
+/* SSC Control */
+#define SSC_CTL_DATA_WIDTH_9 0x8
+#define SSC_CTL_DATA_WIDTH_MSK 0xf
+#define SSC_CTL_BM 0xf
+#define SSC_CTL_HB BIT(4)
+#define SSC_CTL_PH BIT(5)
+#define SSC_CTL_PO BIT(6)
+#define SSC_CTL_SR BIT(7)
+#define SSC_CTL_MS BIT(8)
+#define SSC_CTL_EN BIT(9)
+#define SSC_CTL_LPB BIT(10)
+#define SSC_CTL_EN_TX_FIFO BIT(11)
+#define SSC_CTL_EN_RX_FIFO BIT(12)
+#define SSC_CTL_EN_CLST_RX BIT(13)
+
+/* SSC Interrupt Enable */
+#define SSC_IEN_TEEN BIT(2)
+
+#define FIFO_SIZE 8
+
+struct spi_st {
+ /* SSC SPI Controller */
+ void __iomem *base;
+ struct clk *clk;
+ struct device *dev;
+
+ /* SSC SPI current transaction */
+ const u8 *tx_ptr;
+ u8 *rx_ptr;
+ u16 bytes_per_word;
+ unsigned int words_remaining;
+ unsigned int baud;
+ struct completion done;
+};
+
+static int spi_st_clk_enable(struct spi_st *spi_st)
+{
+ /*
+ * Current platforms use one of the core clocks for SPI and I2C.
+ * If we attempt to disable the clock, the system will hang.
+ *
+ * TODO: Remove this when platform supports power domains.
+ */
+ return 0;
+
+ return clk_prepare_enable(spi_st->clk);
+}
+
+static void spi_st_clk_disable(struct spi_st *spi_st)
+{
+ /*
+ * Current platforms use one of the core clocks for SPI and I2C.
+ * If we attempt to disable the clock, the system will hang.
+ *
+ * TODO: Remove this when platform supports power domains.
+ */
+ return;
+
+ clk_disable_unprepare(spi_st->clk);
+}
+
+/* Load the TX FIFO */
+static void ssc_write_tx_fifo(struct spi_st *spi_st)
+{
+ unsigned int count, i;
+ uint32_t word = 0;
+
+ if (spi_st->words_remaining > FIFO_SIZE)
+ count = FIFO_SIZE;
+ else
+ count = spi_st->words_remaining;
+
+ for (i = 0; i < count; i++) {
+ if (spi_st->tx_ptr) {
+ if (spi_st->bytes_per_word == 1) {
+ word = *spi_st->tx_ptr++;
+ } else {
+ word = *spi_st->tx_ptr++;
+ word = *spi_st->tx_ptr++ | (word << 8);
+ }
+ }
+ writel_relaxed(word, spi_st->base + SSC_TBUF);
+ }
+}
+
+/* Read the RX FIFO */
+static void ssc_read_rx_fifo(struct spi_st *spi_st)
+{
+ unsigned int count, i;
+ uint32_t word = 0;
+
+ if (spi_st->words_remaining > FIFO_SIZE)
+ count = FIFO_SIZE;
+ else
+ count = spi_st->words_remaining;
+
+ for (i = 0; i < count; i++) {
+ word = readl_relaxed(spi_st->base + SSC_RBUF);
+
+ if (spi_st->rx_ptr) {
+ if (spi_st->bytes_per_word == 1) {
+ *spi_st->rx_ptr++ = (uint8_t)word;
+ } else {
+ *spi_st->rx_ptr++ = (word >> 8);
+ *spi_st->rx_ptr++ = word & 0xff;
+ }
+ }
+ }
+ spi_st->words_remaining -= count;
+}
+
+static int spi_st_transfer_one(struct spi_master *master,
+ struct spi_device *spi, struct spi_transfer *t)
+{
+ struct spi_st *spi_st = spi_master_get_devdata(master);
+ uint32_t ctl = 0;
+
+ /* Setup transfer */
+ spi_st->tx_ptr = t->tx_buf;
+ spi_st->rx_ptr = t->rx_buf;
+
+ if (spi->bits_per_word > 8) {
+ /*
+ * Anything greater than 8 bits-per-word requires 2
+ * bytes-per-word in the RX/TX buffers
+ */
+ spi_st->bytes_per_word = 2;
+ spi_st->words_remaining = t->len / 2;
+
+ } else if (spi->bits_per_word == 8 && !(t->len & 0x1)) {
+ /*
+ * If transfer is even-length, and 8 bits-per-word, then
+ * implement as half-length 16 bits-per-word transfer
+ */
+ spi_st->bytes_per_word = 2;
+ spi_st->words_remaining = t->len / 2;
+
+ /* Set SSC_CTL to 16 bits-per-word */
+ ctl = readl_relaxed(spi_st->base + SSC_CTL);
+ writel_relaxed((ctl | 0xf), spi_st->base + SSC_CTL);
+
+ readl_relaxed(spi_st->base + SSC_RBUF);
+
+ } else {
+ spi_st->bytes_per_word = 1;
+ spi_st->words_remaining = t->len;
+ }
+
+ reinit_completion(&spi_st->done);
+
+ /* Start transfer by writing to the TX FIFO */
+ ssc_write_tx_fifo(spi_st);
+ writel_relaxed(SSC_IEN_TEEN, spi_st->base + SSC_IEN);
+
+ /* Wait for transfer to complete */
+ wait_for_completion(&spi_st->done);
+
+ /* Restore SSC_CTL if necessary */
+ if (ctl)
+ writel_relaxed(ctl, spi_st->base + SSC_CTL);
+
+ spi_finalize_current_transfer(spi->master);
+
+ return t->len;
+}
+
+static void spi_st_cleanup(struct spi_device *spi)
+{
+ int cs = spi->cs_gpio;
+
+ if (gpio_is_valid(cs))
+ devm_gpio_free(&spi->dev, cs);
+}
+
+/* the spi->mode bits understood by this driver: */
+#define MODEBITS (SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP | SPI_CS_HIGH)
+static int spi_st_setup(struct spi_device *spi)
+{
+ struct spi_st *spi_st = spi_master_get_devdata(spi->master);
+ u32 spi_st_clk, sscbrg, var;
+ u32 hz = spi->max_speed_hz;
+ int cs = spi->cs_gpio;
+ int ret;
+
+ if (!hz) {
+ dev_err(&spi->dev, "max_speed_hz unspecified\n");
+ return -EINVAL;
+ }
+
+ if (!gpio_is_valid(cs)) {
+ dev_err(&spi->dev, "%d is not a valid gpio\n", cs);
+ return -EINVAL;
+ }
+
+ if (devm_gpio_request(&spi->dev, cs, dev_name(&spi->dev))) {
+ dev_err(&spi->dev, "could not request gpio:%d\n", cs);
+ return -EINVAL;
+ }
+
+ ret = gpio_direction_output(cs, spi->mode & SPI_CS_HIGH);
+ if (ret)
+ return ret;
+
+ spi_st_clk = clk_get_rate(spi_st->clk);
+
+ /* Set SSC_BRF */
+ sscbrg = spi_st_clk / (2 * hz);
+ if (sscbrg < 0x07 || sscbrg > BIT(16)) {
+ dev_err(&spi->dev,
+ "baudrate %d outside valid range %d\n", sscbrg, hz);
+ return -EINVAL;
+ }
+
+ spi_st->baud = spi_st_clk / (2 * sscbrg);
+ if (sscbrg == BIT(16)) /* 16-bit counter wraps */
+ sscbrg = 0x0;
+
+ writel_relaxed(sscbrg, spi_st->base + SSC_BRG);
+
+ dev_dbg(&spi->dev,
+ "setting baudrate:target= %u hz, actual= %u hz, sscbrg= %u\n",
+ hz, spi_st->baud, sscbrg);
+
+ /* Set SSC_CTL and enable SSC */
+ var = readl_relaxed(spi_st->base + SSC_CTL);
+ var |= SSC_CTL_MS;
+
+ if (spi->mode & SPI_CPOL)
+ var |= SSC_CTL_PO;
+ else
+ var &= ~SSC_CTL_PO;
+
+ if (spi->mode & SPI_CPHA)
+ var |= SSC_CTL_PH;
+ else
+ var &= ~SSC_CTL_PH;
+
+ if ((spi->mode & SPI_LSB_FIRST) == 0)
+ var |= SSC_CTL_HB;
+ else
+ var &= ~SSC_CTL_HB;
+
+ if (spi->mode & SPI_LOOP)
+ var |= SSC_CTL_LPB;
+ else
+ var &= ~SSC_CTL_LPB;
+
+ var &= ~SSC_CTL_DATA_WIDTH_MSK;
+ var |= (spi->bits_per_word - 1);
+
+ var |= SSC_CTL_EN_TX_FIFO | SSC_CTL_EN_RX_FIFO;
+ var |= SSC_CTL_EN;
+
+ writel_relaxed(var, spi_st->base + SSC_CTL);
+
+ /* Clear the status register */
+ readl_relaxed(spi_st->base + SSC_RBUF);
+
+ return 0;
+}
+
+/* Interrupt fired when TX shift register becomes empty */
+static irqreturn_t spi_st_irq(int irq, void *dev_id)
+{
+ struct spi_st *spi_st = (struct spi_st *)dev_id;
+
+ /* Read RX FIFO */
+ ssc_read_rx_fifo(spi_st);
+
+ /* Fill TX FIFO */
+ if (spi_st->words_remaining) {
+ ssc_write_tx_fifo(spi_st);
+ } else {
+ /* TX/RX complete */
+ writel_relaxed(0x0, spi_st->base + SSC_IEN);
+ /*
+ * read SSC_IEN to ensure that this bit is set
+ * before re-enabling interrupt
+ */
+ readl(spi_st->base + SSC_IEN);
+ complete(&spi_st->done);
+ }
+
+ return IRQ_HANDLED;
+}
+
+static int spi_st_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct spi_master *master;
+ struct resource *res;
+ struct spi_st *spi_st;
+ int irq, ret = 0;
+ u32 var;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*spi_st));
+ if (!master)
+ return -ENOMEM;
+
+ master->dev.of_node = np;
+ master->mode_bits = MODEBITS;
+ master->setup = spi_st_setup;
+ master->cleanup = spi_st_cleanup;
+ master->transfer_one = spi_st_transfer_one;
+ master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(16);
+ master->auto_runtime_pm = true;
+ master->bus_num = pdev->id;
+ spi_st = spi_master_get_devdata(master);
+
+ spi_st->clk = devm_clk_get(&pdev->dev, "ssc");
+ if (IS_ERR(spi_st->clk)) {
+ dev_err(&pdev->dev, "Unable to request clock\n");
+ return PTR_ERR(spi_st->clk);
+ }
+
+ ret = spi_st_clk_enable(spi_st);
+ if (ret)
+ return ret;
+
+ init_completion(&spi_st->done);
+
+ /* Get resources */
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ spi_st->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(spi_st->base)) {
+ ret = PTR_ERR(spi_st->base);
+ goto clk_disable;
+ }
+
+ /* Disable I2C and Reset SSC */
+ writel_relaxed(0x0, spi_st->base + SSC_I2C);
+ var = readw_relaxed(spi_st->base + SSC_CTL);
+ var |= SSC_CTL_SR;
+ writel_relaxed(var, spi_st->base + SSC_CTL);
+
+ udelay(1);
+ var = readl_relaxed(spi_st->base + SSC_CTL);
+ var &= ~SSC_CTL_SR;
+ writel_relaxed(var, spi_st->base + SSC_CTL);
+
+ /* Set SSC into slave mode before reconfiguring PIO pins */
+ var = readl_relaxed(spi_st->base + SSC_CTL);
+ var &= ~SSC_CTL_MS;
+ writel_relaxed(var, spi_st->base + SSC_CTL);
+
+ irq = irq_of_parse_and_map(np, 0);
+ if (!irq) {
+ dev_err(&pdev->dev, "IRQ missing or invalid\n");
+ ret = -EINVAL;
+ goto clk_disable;
+ }
+
+ ret = devm_request_irq(&pdev->dev, irq, spi_st_irq, 0,
+ pdev->name, spi_st);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request irq %d\n", irq);
+ goto clk_disable;
+ }
+
+ /* by default the device is on */
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
+ platform_set_drvdata(pdev, master);
+
+ ret = devm_spi_register_master(&pdev->dev, master);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register master\n");
+ goto clk_disable;
+ }
+
+ return 0;
+
+clk_disable:
+ spi_st_clk_disable(spi_st);
+
+ return ret;
+}
+
+static int spi_st_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct spi_st *spi_st = spi_master_get_devdata(master);
+
+ spi_st_clk_disable(spi_st);
+
+ pinctrl_pm_select_sleep_state(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int spi_st_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_st *spi_st = spi_master_get_devdata(master);
+
+ writel_relaxed(0, spi_st->base + SSC_IEN);
+ pinctrl_pm_select_sleep_state(dev);
+
+ spi_st_clk_disable(spi_st);
+
+ return 0;
+}
+
+static int spi_st_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct spi_st *spi_st = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_st_clk_enable(spi_st);
+ pinctrl_pm_select_default_state(dev);
+
+ return ret;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int spi_st_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int spi_st_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ int ret;
+
+ ret = spi_master_resume(master);
+ if (ret)
+ return ret;
+
+ return pm_runtime_force_resume(dev);
+}
+#endif
+
+static const struct dev_pm_ops spi_st_pm = {
+ SET_SYSTEM_SLEEP_PM_OPS(spi_st_suspend, spi_st_resume)
+ SET_RUNTIME_PM_OPS(spi_st_runtime_suspend, spi_st_runtime_resume, NULL)
+};
+
+static struct of_device_id stm_spi_match[] = {
+ { .compatible = "st,comms-ssc4-spi", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, stm_spi_match);
+
+static struct platform_driver spi_st_driver = {
+ .driver = {
+ .name = "spi-st",
+ .pm = &spi_st_pm,
+ .of_match_table = of_match_ptr(stm_spi_match),
+ },
+ .probe = spi_st_probe,
+ .remove = spi_st_remove,
+};
+module_platform_driver(spi_st_driver);
+
+MODULE_AUTHOR("Patrice Chotard <patrice.chotard@st.com>");
+MODULE_DESCRIPTION("STM SSC SPI driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-ti-qspi.c b/drivers/spi/spi-ti-qspi.c
index 6146c4cd6583..884a716e50cb 100644
--- a/drivers/spi/spi-ti-qspi.c
+++ b/drivers/spi/spi-ti-qspi.c
@@ -201,7 +201,7 @@ static void ti_qspi_restore_ctx(struct ti_qspi *qspi)
static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
{
- int wlen, count, ret;
+ int wlen, count;
unsigned int cmd;
const u8 *txbuf;
@@ -230,9 +230,8 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
}
ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
- ret = wait_for_completion_timeout(&qspi->transfer_complete,
- QSPI_COMPLETION_TIMEOUT);
- if (ret == 0) {
+ if (!wait_for_completion_timeout(&qspi->transfer_complete,
+ QSPI_COMPLETION_TIMEOUT)) {
dev_err(qspi->dev, "write timed out\n");
return -ETIMEDOUT;
}
@@ -245,7 +244,7 @@ static int qspi_write_msg(struct ti_qspi *qspi, struct spi_transfer *t)
static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
{
- int wlen, count, ret;
+ int wlen, count;
unsigned int cmd;
u8 *rxbuf;
@@ -268,9 +267,8 @@ static int qspi_read_msg(struct ti_qspi *qspi, struct spi_transfer *t)
while (count) {
dev_dbg(qspi->dev, "rx cmd %08x dc %08x\n", cmd, qspi->dc);
ti_qspi_write(qspi, cmd, QSPI_SPI_CMD_REG);
- ret = wait_for_completion_timeout(&qspi->transfer_complete,
- QSPI_COMPLETION_TIMEOUT);
- if (ret == 0) {
+ if (!wait_for_completion_timeout(&qspi->transfer_complete,
+ QSPI_COMPLETION_TIMEOUT)) {
dev_err(qspi->dev, "read timed out\n");
return -ETIMEDOUT;
}
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c
index be692ad50442..93dfcee0f987 100644
--- a/drivers/spi/spi-topcliff-pch.c
+++ b/drivers/spi/spi-topcliff-pch.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/delay.h>
diff --git a/drivers/spi/spi-xilinx.c b/drivers/spi/spi-xilinx.c
index 79bd84f43430..133f53a9c1d4 100644
--- a/drivers/spi/spi-xilinx.c
+++ b/drivers/spi/spi-xilinx.c
@@ -22,6 +22,8 @@
#include <linux/spi/xilinx_spi.h>
#include <linux/io.h>
+#define XILINX_SPI_MAX_CS 32
+
#define XILINX_SPI_NAME "xilinx_spi"
/* Register definitions as per "OPB Serial Peripheral Interface (SPI) (v1.00e)
@@ -34,7 +36,8 @@
#define XSPI_CR_MASTER_MODE 0x04
#define XSPI_CR_CPOL 0x08
#define XSPI_CR_CPHA 0x10
-#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL)
+#define XSPI_CR_MODE_MASK (XSPI_CR_CPHA | XSPI_CR_CPOL | \
+ XSPI_CR_LSB_FIRST | XSPI_CR_LOOP)
#define XSPI_CR_TXFIFO_RESET 0x20
#define XSPI_CR_RXFIFO_RESET 0x40
#define XSPI_CR_MANUAL_SSELECT 0x80
@@ -85,12 +88,11 @@ struct xilinx_spi {
u8 *rx_ptr; /* pointer in the Tx buffer */
const u8 *tx_ptr; /* pointer in the Rx buffer */
- int remaining_bytes; /* the number of bytes left to transfer */
- u8 bits_per_word;
+ u8 bytes_per_word;
+ int buffer_size; /* buffer size in words */
+ u32 cs_inactive; /* Level of the CS pins when inactive*/
unsigned int (*read_fn)(void __iomem *);
void (*write_fn)(u32, void __iomem *);
- void (*tx_fn)(struct xilinx_spi *);
- void (*rx_fn)(struct xilinx_spi *);
};
static void xspi_write32(u32 val, void __iomem *addr)
@@ -113,49 +115,51 @@ static unsigned int xspi_read32_be(void __iomem *addr)
return ioread32be(addr);
}
-static void xspi_tx8(struct xilinx_spi *xspi)
+static void xilinx_spi_tx(struct xilinx_spi *xspi)
{
- xspi->write_fn(*xspi->tx_ptr, xspi->regs + XSPI_TXD_OFFSET);
- xspi->tx_ptr++;
-}
-
-static void xspi_tx16(struct xilinx_spi *xspi)
-{
- xspi->write_fn(*(u16 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
- xspi->tx_ptr += 2;
-}
+ u32 data = 0;
-static void xspi_tx32(struct xilinx_spi *xspi)
-{
- xspi->write_fn(*(u32 *)(xspi->tx_ptr), xspi->regs + XSPI_TXD_OFFSET);
- xspi->tx_ptr += 4;
-}
-
-static void xspi_rx8(struct xilinx_spi *xspi)
-{
- u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
- if (xspi->rx_ptr) {
- *xspi->rx_ptr = data & 0xff;
- xspi->rx_ptr++;
+ if (!xspi->tx_ptr) {
+ xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
+ return;
}
-}
-static void xspi_rx16(struct xilinx_spi *xspi)
-{
- u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
- if (xspi->rx_ptr) {
- *(u16 *)(xspi->rx_ptr) = data & 0xffff;
- xspi->rx_ptr += 2;
+ switch (xspi->bytes_per_word) {
+ case 1:
+ data = *(u8 *)(xspi->tx_ptr);
+ break;
+ case 2:
+ data = *(u16 *)(xspi->tx_ptr);
+ break;
+ case 4:
+ data = *(u32 *)(xspi->tx_ptr);
+ break;
}
+
+ xspi->write_fn(data, xspi->regs + XSPI_TXD_OFFSET);
+ xspi->tx_ptr += xspi->bytes_per_word;
}
-static void xspi_rx32(struct xilinx_spi *xspi)
+static void xilinx_spi_rx(struct xilinx_spi *xspi)
{
u32 data = xspi->read_fn(xspi->regs + XSPI_RXD_OFFSET);
- if (xspi->rx_ptr) {
+
+ if (!xspi->rx_ptr)
+ return;
+
+ switch (xspi->bytes_per_word) {
+ case 1:
+ *(u8 *)(xspi->rx_ptr) = data;
+ break;
+ case 2:
+ *(u16 *)(xspi->rx_ptr) = data;
+ break;
+ case 4:
*(u32 *)(xspi->rx_ptr) = data;
- xspi->rx_ptr += 4;
+ break;
}
+
+ xspi->rx_ptr += xspi->bytes_per_word;
}
static void xspi_init_hw(struct xilinx_spi *xspi)
@@ -165,46 +169,56 @@ static void xspi_init_hw(struct xilinx_spi *xspi)
/* Reset the SPI device */
xspi->write_fn(XIPIF_V123B_RESET_MASK,
regs_base + XIPIF_V123B_RESETR_OFFSET);
- /* Disable all the interrupts just in case */
- xspi->write_fn(0, regs_base + XIPIF_V123B_IIER_OFFSET);
- /* Enable the global IPIF interrupt */
- xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
- regs_base + XIPIF_V123B_DGIER_OFFSET);
+ /* Enable the transmit empty interrupt, which we use to determine
+ * progress on the transmission.
+ */
+ xspi->write_fn(XSPI_INTR_TX_EMPTY,
+ regs_base + XIPIF_V123B_IIER_OFFSET);
+ /* Disable the global IPIF interrupt */
+ xspi->write_fn(0, regs_base + XIPIF_V123B_DGIER_OFFSET);
/* Deselect the slave on the SPI bus */
xspi->write_fn(0xffff, regs_base + XSPI_SSR_OFFSET);
/* Disable the transmitter, enable Manual Slave Select Assertion,
* put SPI controller into master mode, and enable it */
- xspi->write_fn(XSPI_CR_TRANS_INHIBIT | XSPI_CR_MANUAL_SSELECT |
- XSPI_CR_MASTER_MODE | XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET |
- XSPI_CR_RXFIFO_RESET, regs_base + XSPI_CR_OFFSET);
+ xspi->write_fn(XSPI_CR_MANUAL_SSELECT | XSPI_CR_MASTER_MODE |
+ XSPI_CR_ENABLE | XSPI_CR_TXFIFO_RESET | XSPI_CR_RXFIFO_RESET,
+ regs_base + XSPI_CR_OFFSET);
}
static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
{
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
+ u16 cr;
+ u32 cs;
if (is_on == BITBANG_CS_INACTIVE) {
/* Deselect the slave on the SPI bus */
- xspi->write_fn(0xffff, xspi->regs + XSPI_SSR_OFFSET);
- } else if (is_on == BITBANG_CS_ACTIVE) {
- /* Set the SPI clock phase and polarity */
- u16 cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET)
- & ~XSPI_CR_MODE_MASK;
- if (spi->mode & SPI_CPHA)
- cr |= XSPI_CR_CPHA;
- if (spi->mode & SPI_CPOL)
- cr |= XSPI_CR_CPOL;
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
-
- /* We do not check spi->max_speed_hz here as the SPI clock
- * frequency is not software programmable (the IP block design
- * parameter)
- */
-
- /* Activate the chip select */
- xspi->write_fn(~(0x0001 << spi->chip_select),
- xspi->regs + XSPI_SSR_OFFSET);
+ xspi->write_fn(xspi->cs_inactive, xspi->regs + XSPI_SSR_OFFSET);
+ return;
}
+
+ /* Set the SPI clock phase and polarity */
+ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) & ~XSPI_CR_MODE_MASK;
+ if (spi->mode & SPI_CPHA)
+ cr |= XSPI_CR_CPHA;
+ if (spi->mode & SPI_CPOL)
+ cr |= XSPI_CR_CPOL;
+ if (spi->mode & SPI_LSB_FIRST)
+ cr |= XSPI_CR_LSB_FIRST;
+ if (spi->mode & SPI_LOOP)
+ cr |= XSPI_CR_LOOP;
+ xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+
+ /* We do not check spi->max_speed_hz here as the SPI clock
+ * frequency is not software programmable (the IP block design
+ * parameter)
+ */
+
+ cs = xspi->cs_inactive;
+ cs ^= BIT(spi->chip_select);
+
+ /* Activate the chip select */
+ xspi->write_fn(cs, xspi->regs + XSPI_SSR_OFFSET);
}
/* spi_bitbang requires custom setup_transfer() to be defined if there is a
@@ -213,85 +227,85 @@ static void xilinx_spi_chipselect(struct spi_device *spi, int is_on)
static int xilinx_spi_setup_transfer(struct spi_device *spi,
struct spi_transfer *t)
{
- return 0;
-}
+ struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
-static void xilinx_spi_fill_tx_fifo(struct xilinx_spi *xspi)
-{
- u8 sr;
+ if (spi->mode & SPI_CS_HIGH)
+ xspi->cs_inactive &= ~BIT(spi->chip_select);
+ else
+ xspi->cs_inactive |= BIT(spi->chip_select);
- /* Fill the Tx FIFO with as many bytes as possible */
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- while ((sr & XSPI_SR_TX_FULL_MASK) == 0 && xspi->remaining_bytes > 0) {
- if (xspi->tx_ptr)
- xspi->tx_fn(xspi);
- else
- xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
- xspi->remaining_bytes -= xspi->bits_per_word / 8;
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- }
+ return 0;
}
static int xilinx_spi_txrx_bufs(struct spi_device *spi, struct spi_transfer *t)
{
struct xilinx_spi *xspi = spi_master_get_devdata(spi->master);
- u32 ipif_ier;
+ int remaining_words; /* the number of words left to transfer */
+ bool use_irq = false;
+ u16 cr = 0;
/* We get here with transmitter inhibited */
xspi->tx_ptr = t->tx_buf;
xspi->rx_ptr = t->rx_buf;
- xspi->remaining_bytes = t->len;
+ remaining_words = t->len / xspi->bytes_per_word;
reinit_completion(&xspi->done);
+ if (xspi->irq >= 0 && remaining_words > xspi->buffer_size) {
+ use_irq = true;
+ xspi->write_fn(XSPI_INTR_TX_EMPTY,
+ xspi->regs + XIPIF_V123B_IISR_OFFSET);
+ /* Enable the global IPIF interrupt */
+ xspi->write_fn(XIPIF_V123B_GINTR_ENABLE,
+ xspi->regs + XIPIF_V123B_DGIER_OFFSET);
+ /* Inhibit irq to avoid spurious irqs on tx_empty*/
+ cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
+ xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
+ xspi->regs + XSPI_CR_OFFSET);
+ }
- /* Enable the transmit empty interrupt, which we use to determine
- * progress on the transmission.
- */
- ipif_ier = xspi->read_fn(xspi->regs + XIPIF_V123B_IIER_OFFSET);
- xspi->write_fn(ipif_ier | XSPI_INTR_TX_EMPTY,
- xspi->regs + XIPIF_V123B_IIER_OFFSET);
+ while (remaining_words) {
+ int n_words, tx_words, rx_words;
- for (;;) {
- u16 cr;
- u8 sr;
+ n_words = min(remaining_words, xspi->buffer_size);
- xilinx_spi_fill_tx_fifo(xspi);
+ tx_words = n_words;
+ while (tx_words--)
+ xilinx_spi_tx(xspi);
/* Start the transfer by not inhibiting the transmitter any
* longer
*/
- cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET) &
- ~XSPI_CR_TRANS_INHIBIT;
- xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
- wait_for_completion(&xspi->done);
+ if (use_irq) {
+ xspi->write_fn(cr, xspi->regs + XSPI_CR_OFFSET);
+ wait_for_completion(&xspi->done);
+ } else
+ while (!(xspi->read_fn(xspi->regs + XSPI_SR_OFFSET) &
+ XSPI_SR_TX_EMPTY_MASK))
+ ;
/* A transmit has just completed. Process received data and
* check for more data to transmit. Always inhibit the
* transmitter while the Isr refills the transmit register/FIFO,
* or make sure it is stopped if we're done.
*/
- cr = xspi->read_fn(xspi->regs + XSPI_CR_OFFSET);
- xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
+ if (use_irq)
+ xspi->write_fn(cr | XSPI_CR_TRANS_INHIBIT,
xspi->regs + XSPI_CR_OFFSET);
/* Read out all the data from the Rx FIFO */
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- while ((sr & XSPI_SR_RX_EMPTY_MASK) == 0) {
- xspi->rx_fn(xspi);
- sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
- }
-
- /* See if there is more data to send */
- if (xspi->remaining_bytes <= 0)
- break;
+ rx_words = n_words;
+ while (rx_words--)
+ xilinx_spi_rx(xspi);
+
+ remaining_words -= n_words;
}
- /* Disable the transmit empty interrupt */
- xspi->write_fn(ipif_ier, xspi->regs + XIPIF_V123B_IIER_OFFSET);
+ if (use_irq)
+ xspi->write_fn(0, xspi->regs + XIPIF_V123B_DGIER_OFFSET);
- return t->len - xspi->remaining_bytes;
+ return t->len;
}
@@ -316,6 +330,28 @@ static irqreturn_t xilinx_spi_irq(int irq, void *dev_id)
return IRQ_HANDLED;
}
+static int xilinx_spi_find_buffer_size(struct xilinx_spi *xspi)
+{
+ u8 sr;
+ int n_words = 0;
+
+ /*
+ * Before the buffer_size detection we reset the core
+ * to make sure we start with a clean state.
+ */
+ xspi->write_fn(XIPIF_V123B_RESET_MASK,
+ xspi->regs + XIPIF_V123B_RESETR_OFFSET);
+
+ /* Fill the Tx FIFO with as many words as possible */
+ do {
+ xspi->write_fn(0, xspi->regs + XSPI_TXD_OFFSET);
+ sr = xspi->read_fn(xspi->regs + XSPI_SR_OFFSET);
+ n_words++;
+ } while (!(sr & XSPI_SR_TX_FULL_MASK));
+
+ return n_words;
+}
+
static const struct of_device_id xilinx_spi_of_match[] = {
{ .compatible = "xlnx,xps-spi-2.00.a", },
{ .compatible = "xlnx,xps-spi-2.00.b", },
@@ -348,14 +384,21 @@ static int xilinx_spi_probe(struct platform_device *pdev)
return -EINVAL;
}
+ if (num_cs > XILINX_SPI_MAX_CS) {
+ dev_err(&pdev->dev, "Invalid number of spi slaves\n");
+ return -EINVAL;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(struct xilinx_spi));
if (!master)
return -ENODEV;
/* the spi->mode bits understood by this driver: */
- master->mode_bits = SPI_CPOL | SPI_CPHA;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_LOOP |
+ SPI_CS_HIGH;
xspi = spi_master_get_devdata(master);
+ xspi->cs_inactive = 0xffffffff;
xspi->bitbang.master = master;
xspi->bitbang.chipselect = xilinx_spi_chipselect;
xspi->bitbang.setup_transfer = xilinx_spi_setup_transfer;
@@ -392,35 +435,20 @@ static int xilinx_spi_probe(struct platform_device *pdev)
}
master->bits_per_word_mask = SPI_BPW_MASK(bits_per_word);
- xspi->bits_per_word = bits_per_word;
- if (xspi->bits_per_word == 8) {
- xspi->tx_fn = xspi_tx8;
- xspi->rx_fn = xspi_rx8;
- } else if (xspi->bits_per_word == 16) {
- xspi->tx_fn = xspi_tx16;
- xspi->rx_fn = xspi_rx16;
- } else if (xspi->bits_per_word == 32) {
- xspi->tx_fn = xspi_tx32;
- xspi->rx_fn = xspi_rx32;
- } else {
- ret = -EINVAL;
- goto put_master;
- }
-
- /* SPI controller initializations */
- xspi_init_hw(xspi);
+ xspi->bytes_per_word = bits_per_word / 8;
+ xspi->buffer_size = xilinx_spi_find_buffer_size(xspi);
xspi->irq = platform_get_irq(pdev, 0);
- if (xspi->irq < 0) {
- ret = xspi->irq;
- goto put_master;
+ if (xspi->irq >= 0) {
+ /* Register for SPI Interrupt */
+ ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
+ dev_name(&pdev->dev), xspi);
+ if (ret)
+ goto put_master;
}
- /* Register for SPI Interrupt */
- ret = devm_request_irq(&pdev->dev, xspi->irq, xilinx_spi_irq, 0,
- dev_name(&pdev->dev), xspi);
- if (ret)
- goto put_master;
+ /* SPI controller initializations */
+ xspi_init_hw(xspi);
ret = spi_bitbang_start(&xspi->bitbang);
if (ret) {
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 66a70e9bc743..c64a3e59fce3 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/kernel.h>
@@ -788,7 +784,7 @@ static int spi_transfer_one_message(struct spi_master *master,
struct spi_transfer *xfer;
bool keep_cs = false;
int ret = 0;
- int ms = 1;
+ unsigned long ms = 1;
spi_set_cs(msg->spi, true);
@@ -875,31 +871,59 @@ void spi_finalize_current_transfer(struct spi_master *master)
EXPORT_SYMBOL_GPL(spi_finalize_current_transfer);
/**
- * spi_pump_messages - kthread work function which processes spi message queue
- * @work: pointer to kthread work struct contained in the master struct
+ * __spi_pump_messages - function which processes spi message queue
+ * @master: master to process queue for
+ * @in_kthread: true if we are in the context of the message pump thread
*
* This function checks if there is any spi message in the queue that
* needs processing and if so call out to the driver to initialize hardware
* and transfer each message.
*
+ * Note that it is called both from the kthread itself and also from
+ * inside spi_sync(); the queue extraction handling at the top of the
+ * function should deal with this safely.
*/
-static void spi_pump_messages(struct kthread_work *work)
+static void __spi_pump_messages(struct spi_master *master, bool in_kthread)
{
- struct spi_master *master =
- container_of(work, struct spi_master, pump_messages);
unsigned long flags;
bool was_busy = false;
int ret;
- /* Lock queue and check for queue work */
+ /* Lock queue */
spin_lock_irqsave(&master->queue_lock, flags);
+
+ /* Make sure we are not already running a message */
+ if (master->cur_msg) {
+ spin_unlock_irqrestore(&master->queue_lock, flags);
+ return;
+ }
+
+ /* If another context is idling the device then defer */
+ if (master->idling) {
+ queue_kthread_work(&master->kworker, &master->pump_messages);
+ spin_unlock_irqrestore(&master->queue_lock, flags);
+ return;
+ }
+
+ /* Check if the queue is idle */
if (list_empty(&master->queue) || !master->running) {
if (!master->busy) {
spin_unlock_irqrestore(&master->queue_lock, flags);
return;
}
+
+ /* Only do teardown in the thread */
+ if (!in_kthread) {
+ queue_kthread_work(&master->kworker,
+ &master->pump_messages);
+ spin_unlock_irqrestore(&master->queue_lock, flags);
+ return;
+ }
+
master->busy = false;
+ master->idling = true;
spin_unlock_irqrestore(&master->queue_lock, flags);
+
kfree(master->dummy_rx);
master->dummy_rx = NULL;
kfree(master->dummy_tx);
@@ -913,14 +937,13 @@ static void spi_pump_messages(struct kthread_work *work)
pm_runtime_put_autosuspend(master->dev.parent);
}
trace_spi_master_idle(master);
- return;
- }
- /* Make sure we are not already running a message */
- if (master->cur_msg) {
+ spin_lock_irqsave(&master->queue_lock, flags);
+ master->idling = false;
spin_unlock_irqrestore(&master->queue_lock, flags);
return;
}
+
/* Extract head of queue */
master->cur_msg =
list_first_entry(&master->queue, struct spi_message, queue);
@@ -985,13 +1008,22 @@ static void spi_pump_messages(struct kthread_work *work)
}
}
+/**
+ * spi_pump_messages - kthread work function which processes spi message queue
+ * @work: pointer to kthread work struct contained in the master struct
+ */
+static void spi_pump_messages(struct kthread_work *work)
+{
+ struct spi_master *master =
+ container_of(work, struct spi_master, pump_messages);
+
+ __spi_pump_messages(master, true);
+}
+
static int spi_init_queue(struct spi_master *master)
{
struct sched_param param = { .sched_priority = MAX_RT_PRIO - 1 };
- INIT_LIST_HEAD(&master->queue);
- spin_lock_init(&master->queue_lock);
-
master->running = false;
master->busy = false;
@@ -1161,12 +1193,9 @@ static int spi_destroy_queue(struct spi_master *master)
return 0;
}
-/**
- * spi_queued_transfer - transfer function for queued transfers
- * @spi: spi device which is requesting transfer
- * @msg: spi message which is to handled is queued to driver queue
- */
-static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
+static int __spi_queued_transfer(struct spi_device *spi,
+ struct spi_message *msg,
+ bool need_pump)
{
struct spi_master *master = spi->master;
unsigned long flags;
@@ -1181,13 +1210,23 @@ static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
msg->status = -EINPROGRESS;
list_add_tail(&msg->queue, &master->queue);
- if (!master->busy)
+ if (!master->busy && need_pump)
queue_kthread_work(&master->kworker, &master->pump_messages);
spin_unlock_irqrestore(&master->queue_lock, flags);
return 0;
}
+/**
+ * spi_queued_transfer - transfer function for queued transfers
+ * @spi: spi device which is requesting transfer
+ * @msg: spi message which is to handled is queued to driver queue
+ */
+static int spi_queued_transfer(struct spi_device *spi, struct spi_message *msg)
+{
+ return __spi_queued_transfer(spi, msg, true);
+}
+
static int spi_master_initialize_queue(struct spi_master *master)
{
int ret;
@@ -1609,6 +1648,8 @@ int spi_register_master(struct spi_master *master)
dynamic = 1;
}
+ INIT_LIST_HEAD(&master->queue);
+ spin_lock_init(&master->queue_lock);
spin_lock_init(&master->bus_lock_spinlock);
mutex_init(&master->bus_lock_mutex);
master->bus_lock_flag = 0;
@@ -2114,19 +2155,46 @@ static int __spi_sync(struct spi_device *spi, struct spi_message *message,
DECLARE_COMPLETION_ONSTACK(done);
int status;
struct spi_master *master = spi->master;
+ unsigned long flags;
+
+ status = __spi_validate(spi, message);
+ if (status != 0)
+ return status;
message->complete = spi_complete;
message->context = &done;
+ message->spi = spi;
if (!bus_locked)
mutex_lock(&master->bus_lock_mutex);
- status = spi_async_locked(spi, message);
+ /* If we're not using the legacy transfer method then we will
+ * try to transfer in the calling context so special case.
+ * This code would be less tricky if we could remove the
+ * support for driver implemented message queues.
+ */
+ if (master->transfer == spi_queued_transfer) {
+ spin_lock_irqsave(&master->bus_lock_spinlock, flags);
+
+ trace_spi_message_submit(message);
+
+ status = __spi_queued_transfer(spi, message, false);
+
+ spin_unlock_irqrestore(&master->bus_lock_spinlock, flags);
+ } else {
+ status = spi_async_locked(spi, message);
+ }
if (!bus_locked)
mutex_unlock(&master->bus_lock_mutex);
if (status == 0) {
+ /* Push out the messages in the calling context if we
+ * can.
+ */
+ if (master->transfer == spi_queued_transfer)
+ __spi_pump_messages(master, false);
+
wait_for_completion(&done);
status = message->status;
}
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index 6941e04afb8c..4eb7a980e670 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/init.h>
@@ -317,6 +313,37 @@ done:
return status;
}
+static struct spi_ioc_transfer *
+spidev_get_ioc_message(unsigned int cmd, struct spi_ioc_transfer __user *u_ioc,
+ unsigned *n_ioc)
+{
+ struct spi_ioc_transfer *ioc;
+ u32 tmp;
+
+ /* Check type, command number and direction */
+ if (_IOC_TYPE(cmd) != SPI_IOC_MAGIC
+ || _IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
+ || _IOC_DIR(cmd) != _IOC_WRITE)
+ return ERR_PTR(-ENOTTY);
+
+ tmp = _IOC_SIZE(cmd);
+ if ((tmp % sizeof(struct spi_ioc_transfer)) != 0)
+ return ERR_PTR(-EINVAL);
+ *n_ioc = tmp / sizeof(struct spi_ioc_transfer);
+ if (*n_ioc == 0)
+ return NULL;
+
+ /* copy into scratch area */
+ ioc = kmalloc(tmp, GFP_KERNEL);
+ if (!ioc)
+ return ERR_PTR(-ENOMEM);
+ if (__copy_from_user(ioc, u_ioc, tmp)) {
+ kfree(ioc);
+ return ERR_PTR(-EFAULT);
+ }
+ return ioc;
+}
+
static long
spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
@@ -456,32 +483,15 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
default:
/* segmented and/or full-duplex I/O request */
- if (_IOC_NR(cmd) != _IOC_NR(SPI_IOC_MESSAGE(0))
- || _IOC_DIR(cmd) != _IOC_WRITE) {
- retval = -ENOTTY;
- break;
- }
-
- tmp = _IOC_SIZE(cmd);
- if ((tmp % sizeof(struct spi_ioc_transfer)) != 0) {
- retval = -EINVAL;
- break;
- }
- n_ioc = tmp / sizeof(struct spi_ioc_transfer);
- if (n_ioc == 0)
- break;
-
- /* copy into scratch area */
- ioc = kmalloc(tmp, GFP_KERNEL);
- if (!ioc) {
- retval = -ENOMEM;
- break;
- }
- if (__copy_from_user(ioc, (void __user *)arg, tmp)) {
- kfree(ioc);
- retval = -EFAULT;
+ /* Check message and copy into scratch area */
+ ioc = spidev_get_ioc_message(cmd,
+ (struct spi_ioc_transfer __user *)arg, &n_ioc);
+ if (IS_ERR(ioc)) {
+ retval = PTR_ERR(ioc);
break;
}
+ if (!ioc)
+ break; /* n_ioc is also 0 */
/* translate to spi_message, execute */
retval = spidev_message(spidev, ioc, n_ioc);
@@ -496,8 +506,67 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
#ifdef CONFIG_COMPAT
static long
+spidev_compat_ioc_message(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ struct spi_ioc_transfer __user *u_ioc;
+ int retval = 0;
+ struct spidev_data *spidev;
+ struct spi_device *spi;
+ unsigned n_ioc, n;
+ struct spi_ioc_transfer *ioc;
+
+ u_ioc = (struct spi_ioc_transfer __user *) compat_ptr(arg);
+ if (!access_ok(VERIFY_READ, u_ioc, _IOC_SIZE(cmd)))
+ return -EFAULT;
+
+ /* guard against device removal before, or while,
+ * we issue this ioctl.
+ */
+ spidev = filp->private_data;
+ spin_lock_irq(&spidev->spi_lock);
+ spi = spi_dev_get(spidev->spi);
+ spin_unlock_irq(&spidev->spi_lock);
+
+ if (spi == NULL)
+ return -ESHUTDOWN;
+
+ /* SPI_IOC_MESSAGE needs the buffer locked "normally" */
+ mutex_lock(&spidev->buf_lock);
+
+ /* Check message and copy into scratch area */
+ ioc = spidev_get_ioc_message(cmd, u_ioc, &n_ioc);
+ if (IS_ERR(ioc)) {
+ retval = PTR_ERR(ioc);
+ goto done;
+ }
+ if (!ioc)
+ goto done; /* n_ioc is also 0 */
+
+ /* Convert buffer pointers */
+ for (n = 0; n < n_ioc; n++) {
+ ioc[n].rx_buf = (uintptr_t) compat_ptr(ioc[n].rx_buf);
+ ioc[n].tx_buf = (uintptr_t) compat_ptr(ioc[n].tx_buf);
+ }
+
+ /* translate to spi_message, execute */
+ retval = spidev_message(spidev, ioc, n_ioc);
+ kfree(ioc);
+
+done:
+ mutex_unlock(&spidev->buf_lock);
+ spi_dev_put(spi);
+ return retval;
+}
+
+static long
spidev_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
+ if (_IOC_TYPE(cmd) == SPI_IOC_MAGIC
+ && _IOC_NR(cmd) == _IOC_NR(SPI_IOC_MESSAGE(0))
+ && _IOC_DIR(cmd) == _IOC_WRITE)
+ return spidev_compat_ioc_message(filp, cmd, arg);
+
return spidev_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
}
#else
diff --git a/drivers/ssb/driver_gige.c b/drivers/ssb/driver_gige.c
index 21f71a1581fa..e9734051e3c4 100644
--- a/drivers/ssb/driver_gige.c
+++ b/drivers/ssb/driver_gige.c
@@ -24,7 +24,7 @@ MODULE_LICENSE("GPL");
static const struct ssb_device_id ssb_gige_tbl[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_ETHERNET_GBIT, SSB_ANY_REV),
- SSB_DEVTABLE_END
+ {},
};
/* MODULE_DEVICE_TABLE(ssb, ssb_gige_tbl); */
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c
index 2fead3820849..1e180c400f17 100644
--- a/drivers/ssb/main.c
+++ b/drivers/ssb/main.c
@@ -90,25 +90,6 @@ found:
}
#endif /* CONFIG_SSB_PCMCIAHOST */
-#ifdef CONFIG_SSB_SDIOHOST
-struct ssb_bus *ssb_sdio_func_to_bus(struct sdio_func *func)
-{
- struct ssb_bus *bus;
-
- ssb_buses_lock();
- list_for_each_entry(bus, &buses, list) {
- if (bus->bustype == SSB_BUSTYPE_SDIO &&
- bus->host_sdio == func)
- goto found;
- }
- bus = NULL;
-found:
- ssb_buses_unlock();
-
- return bus;
-}
-#endif /* CONFIG_SSB_SDIOHOST */
-
int ssb_for_each_bus_call(unsigned long data,
int (*func)(struct ssb_bus *bus, unsigned long data))
{
diff --git a/drivers/staging/Kconfig b/drivers/staging/Kconfig
index 815de379a130..45baa83be7ce 100644
--- a/drivers/staging/Kconfig
+++ b/drivers/staging/Kconfig
@@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig"
source "drivers/staging/rts5208/Kconfig"
-source "drivers/staging/line6/Kconfig"
-
source "drivers/staging/octeon/Kconfig"
source "drivers/staging/octeon-usb/Kconfig"
@@ -58,6 +56,8 @@ source "drivers/staging/vt6656/Kconfig"
source "drivers/staging/iio/Kconfig"
+source "drivers/staging/sm7xxfb/Kconfig"
+
source "drivers/staging/xgifb/Kconfig"
source "drivers/staging/emxx_udc/Kconfig"
@@ -66,8 +66,6 @@ source "drivers/staging/ft1000/Kconfig"
source "drivers/staging/speakup/Kconfig"
-source "drivers/staging/cptm1217/Kconfig"
-
source "drivers/staging/ste_rmi4/Kconfig"
source "drivers/staging/nvec/Kconfig"
@@ -106,4 +104,8 @@ source "drivers/staging/unisys/Kconfig"
source "drivers/staging/clocking-wizard/Kconfig"
+source "drivers/staging/fbtft/Kconfig"
+
+source "drivers/staging/i2o/Kconfig"
+
endif # STAGING
diff --git a/drivers/staging/Makefile b/drivers/staging/Makefile
index 33c640b49566..29160790841f 100644
--- a/drivers/staging/Makefile
+++ b/drivers/staging/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U) += rtl8712/
obj-$(CONFIG_R8188EU) += rtl8188eu/
obj-$(CONFIG_R8723AU) += rtl8723au/
obj-$(CONFIG_RTS5208) += rts5208/
-obj-$(CONFIG_LINE6_USB) += line6/
obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
obj-$(CONFIG_OCTEON_ETHERNET) += octeon/
obj-$(CONFIG_OCTEON_USB) += octeon-usb/
@@ -23,11 +22,11 @@ obj-$(CONFIG_VT6655) += vt6655/
obj-$(CONFIG_VT6656) += vt6656/
obj-$(CONFIG_VME_BUS) += vme/
obj-$(CONFIG_IIO) += iio/
+obj-$(CONFIG_FB_SM7XX) += sm7xxfb/
obj-$(CONFIG_FB_XGI) += xgifb/
obj-$(CONFIG_USB_EMXX) += emxx_udc/
obj-$(CONFIG_FT1000) += ft1000/
obj-$(CONFIG_SPEAKUP) += speakup/
-obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += cptm1217/
obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_I2C_RMI4) += ste_rmi4/
obj-$(CONFIG_MFD_NVEC) += nvec/
obj-$(CONFIG_ANDROID) += android/
@@ -45,3 +44,5 @@ obj-$(CONFIG_GS_FPGABOOT) += gs_fpgaboot/
obj-$(CONFIG_CRYPTO_SKEIN) += skein/
obj-$(CONFIG_UNISYSSPAR) += unisys/
obj-$(CONFIG_COMMON_CLK_XLNX_CLKWZRD) += clocking-wizard/
+obj-$(CONFIG_FB_TFT) += fbtft/
+obj-$(CONFIG_I2O) += i2o/
diff --git a/drivers/staging/android/Kconfig b/drivers/staging/android/Kconfig
index 7e012f37792b..8feb9048e62f 100644
--- a/drivers/staging/android/Kconfig
+++ b/drivers/staging/android/Kconfig
@@ -14,23 +14,6 @@ config ASHMEM
It is, in theory, a good memory allocator for low-memory devices,
because it can discard shared memory units when under memory pressure.
-config ANDROID_LOGGER
- tristate "Android log driver"
- default n
- ---help---
- This adds support for system-wide logging using four log buffers.
-
- These are:
-
- 1: main
- 2: events
- 3: radio
- 4: system
-
- Log reading and writing is performed via normal Linux reads and
- optimized writes. This optimization avoids logging having too
- much overhead in the system.
-
config ANDROID_TIMED_OUTPUT
bool "Timed output class driver"
default y
@@ -45,15 +28,6 @@ config ANDROID_LOW_MEMORY_KILLER
---help---
Registers processes to be killed when memory is low
-config ANDROID_INTF_ALARM_DEV
- tristate "Android alarm driver"
- depends on RTC_CLASS
- default n
- ---help---
- Provides non-wakeup and rtc backed wakeup alarms based on rtc or
- elapsed realtime, and a non-wakeup alarm on the monotonic clock.
- Also exports the alarm interface to user-space.
-
config SYNC
bool "Synchronization framework"
default n
diff --git a/drivers/staging/android/Makefile b/drivers/staging/android/Makefile
index 479b2b86f8c8..c7b6c99cc5ce 100644
--- a/drivers/staging/android/Makefile
+++ b/drivers/staging/android/Makefile
@@ -3,10 +3,8 @@ ccflags-y += -I$(src) # needed for trace events
obj-y += ion/
obj-$(CONFIG_ASHMEM) += ashmem.o
-obj-$(CONFIG_ANDROID_LOGGER) += logger.o
obj-$(CONFIG_ANDROID_TIMED_OUTPUT) += timed_output.o
obj-$(CONFIG_ANDROID_TIMED_GPIO) += timed_gpio.o
obj-$(CONFIG_ANDROID_LOW_MEMORY_KILLER) += lowmemorykiller.o
-obj-$(CONFIG_ANDROID_INTF_ALARM_DEV) += alarm-dev.o
obj-$(CONFIG_SYNC) += sync.o sync_debug.o
obj-$(CONFIG_SW_SYNC) += sw_sync.o
diff --git a/drivers/staging/android/alarm-dev.c b/drivers/staging/android/alarm-dev.c
deleted file mode 100644
index ff4b3e8758a7..000000000000
--- a/drivers/staging/android/alarm-dev.c
+++ /dev/null
@@ -1,446 +0,0 @@
-/* drivers/rtc/alarm-dev.c
- *
- * Copyright (C) 2007-2009 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#include <linux/time.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <linux/miscdevice.h>
-#include <linux/fs.h>
-#include <linux/platform_device.h>
-#include <linux/sched.h>
-#include <linux/spinlock.h>
-#include <linux/uaccess.h>
-#include <linux/alarmtimer.h>
-#include "android_alarm.h"
-
-#define ANDROID_ALARM_PRINT_INFO (1U << 0)
-#define ANDROID_ALARM_PRINT_IO (1U << 1)
-#define ANDROID_ALARM_PRINT_INT (1U << 2)
-
-static int debug_mask = ANDROID_ALARM_PRINT_INFO;
-module_param_named(debug_mask, debug_mask, int, S_IRUGO | S_IWUSR | S_IWGRP);
-
-#define alarm_dbg(debug_level_mask, fmt, ...) \
-do { \
- if (debug_mask & ANDROID_ALARM_PRINT_##debug_level_mask) \
- pr_info(fmt, ##__VA_ARGS__); \
-} while (0)
-
-#define ANDROID_ALARM_WAKEUP_MASK ( \
- ANDROID_ALARM_RTC_WAKEUP_MASK | \
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK)
-
-static int alarm_opened;
-static DEFINE_SPINLOCK(alarm_slock);
-static struct wakeup_source alarm_wake_lock;
-static DECLARE_WAIT_QUEUE_HEAD(alarm_wait_queue);
-static uint32_t alarm_pending;
-static uint32_t alarm_enabled;
-static uint32_t wait_pending;
-
-struct devalarm {
- union {
- struct hrtimer hrt;
- struct alarm alrm;
- } u;
- enum android_alarm_type type;
-};
-
-static struct devalarm alarms[ANDROID_ALARM_TYPE_COUNT];
-
-/**
- * is_wakeup() - Checks to see if this alarm can wake the device
- * @type: The type of alarm being checked
- *
- * Return: 1 if this is a wakeup alarm, otherwise 0
- */
-static int is_wakeup(enum android_alarm_type type)
-{
- return type == ANDROID_ALARM_RTC_WAKEUP ||
- type == ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP;
-}
-
-static void devalarm_start(struct devalarm *alrm, ktime_t exp)
-{
- if (is_wakeup(alrm->type))
- alarm_start(&alrm->u.alrm, exp);
- else
- hrtimer_start(&alrm->u.hrt, exp, HRTIMER_MODE_ABS);
-}
-
-static int devalarm_try_to_cancel(struct devalarm *alrm)
-{
- if (is_wakeup(alrm->type))
- return alarm_try_to_cancel(&alrm->u.alrm);
- return hrtimer_try_to_cancel(&alrm->u.hrt);
-}
-
-static void devalarm_cancel(struct devalarm *alrm)
-{
- if (is_wakeup(alrm->type))
- alarm_cancel(&alrm->u.alrm);
- else
- hrtimer_cancel(&alrm->u.hrt);
-}
-
-static void alarm_clear(enum android_alarm_type alarm_type)
-{
- uint32_t alarm_type_mask = 1U << alarm_type;
- unsigned long flags;
-
- spin_lock_irqsave(&alarm_slock, flags);
- alarm_dbg(IO, "alarm %d clear\n", alarm_type);
- devalarm_try_to_cancel(&alarms[alarm_type]);
- if (alarm_pending) {
- alarm_pending &= ~alarm_type_mask;
- if (!alarm_pending && !wait_pending)
- __pm_relax(&alarm_wake_lock);
- }
- alarm_enabled &= ~alarm_type_mask;
- spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-static void alarm_set(enum android_alarm_type alarm_type,
- struct timespec *ts)
-{
- uint32_t alarm_type_mask = 1U << alarm_type;
- unsigned long flags;
-
- spin_lock_irqsave(&alarm_slock, flags);
- alarm_dbg(IO, "alarm %d set %ld.%09ld\n",
- alarm_type, ts->tv_sec, ts->tv_nsec);
- alarm_enabled |= alarm_type_mask;
- devalarm_start(&alarms[alarm_type], timespec_to_ktime(*ts));
- spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-static int alarm_wait(void)
-{
- unsigned long flags;
- int rv = 0;
-
- spin_lock_irqsave(&alarm_slock, flags);
- alarm_dbg(IO, "alarm wait\n");
- if (!alarm_pending && wait_pending) {
- __pm_relax(&alarm_wake_lock);
- wait_pending = 0;
- }
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- rv = wait_event_interruptible(alarm_wait_queue, alarm_pending);
- if (rv)
- return rv;
-
- spin_lock_irqsave(&alarm_slock, flags);
- rv = alarm_pending;
- wait_pending = 1;
- alarm_pending = 0;
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- return rv;
-}
-
-static int alarm_set_rtc(struct timespec *ts)
-{
- struct rtc_time new_rtc_tm;
- struct rtc_device *rtc_dev;
- unsigned long flags;
- int rv = 0;
-
- rtc_time_to_tm(ts->tv_sec, &new_rtc_tm);
- rtc_dev = alarmtimer_get_rtcdev();
- rv = do_settimeofday(ts);
- if (rv < 0)
- return rv;
- if (rtc_dev)
- rv = rtc_set_time(rtc_dev, &new_rtc_tm);
-
- spin_lock_irqsave(&alarm_slock, flags);
- alarm_pending |= ANDROID_ALARM_TIME_CHANGE_MASK;
- wake_up(&alarm_wait_queue);
- spin_unlock_irqrestore(&alarm_slock, flags);
-
- return rv;
-}
-
-static int alarm_get_time(enum android_alarm_type alarm_type,
- struct timespec *ts)
-{
- int rv = 0;
-
- switch (alarm_type) {
- case ANDROID_ALARM_RTC_WAKEUP:
- case ANDROID_ALARM_RTC:
- getnstimeofday(ts);
- break;
- case ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP:
- case ANDROID_ALARM_ELAPSED_REALTIME:
- get_monotonic_boottime(ts);
- break;
- case ANDROID_ALARM_SYSTEMTIME:
- ktime_get_ts(ts);
- break;
- default:
- rv = -EINVAL;
- }
- return rv;
-}
-
-static long alarm_do_ioctl(struct file *file, unsigned int cmd,
- struct timespec *ts)
-{
- int rv = 0;
- unsigned long flags;
- enum android_alarm_type alarm_type = ANDROID_ALARM_IOCTL_TO_TYPE(cmd);
-
- if (alarm_type >= ANDROID_ALARM_TYPE_COUNT)
- return -EINVAL;
-
- if (ANDROID_ALARM_BASE_CMD(cmd) != ANDROID_ALARM_GET_TIME(0)) {
- if ((file->f_flags & O_ACCMODE) == O_RDONLY)
- return -EPERM;
- if (file->private_data == NULL &&
- cmd != ANDROID_ALARM_SET_RTC) {
- spin_lock_irqsave(&alarm_slock, flags);
- if (alarm_opened) {
- spin_unlock_irqrestore(&alarm_slock, flags);
- return -EBUSY;
- }
- alarm_opened = 1;
- file->private_data = (void *)1;
- spin_unlock_irqrestore(&alarm_slock, flags);
- }
- }
-
- switch (ANDROID_ALARM_BASE_CMD(cmd)) {
- case ANDROID_ALARM_CLEAR(0):
- alarm_clear(alarm_type);
- break;
- case ANDROID_ALARM_SET(0):
- alarm_set(alarm_type, ts);
- break;
- case ANDROID_ALARM_SET_AND_WAIT(0):
- alarm_set(alarm_type, ts);
- /* fall though */
- case ANDROID_ALARM_WAIT:
- rv = alarm_wait();
- break;
- case ANDROID_ALARM_SET_RTC:
- rv = alarm_set_rtc(ts);
- break;
- case ANDROID_ALARM_GET_TIME(0):
- rv = alarm_get_time(alarm_type, ts);
- break;
-
- default:
- rv = -EINVAL;
- }
- return rv;
-}
-
-static long alarm_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
-
- struct timespec ts;
- int rv;
-
- switch (ANDROID_ALARM_BASE_CMD(cmd)) {
- case ANDROID_ALARM_SET_AND_WAIT(0):
- case ANDROID_ALARM_SET(0):
- case ANDROID_ALARM_SET_RTC:
- if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
- return -EFAULT;
- break;
- }
-
- rv = alarm_do_ioctl(file, cmd, &ts);
- if (rv)
- return rv;
-
- switch (ANDROID_ALARM_BASE_CMD(cmd)) {
- case ANDROID_ALARM_GET_TIME(0):
- if (copy_to_user((void __user *)arg, &ts, sizeof(ts)))
- return -EFAULT;
- break;
- }
-
- return 0;
-}
-
-#ifdef CONFIG_COMPAT
-static long alarm_compat_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
-
- struct timespec ts;
- int rv;
-
- switch (ANDROID_ALARM_BASE_CMD(cmd)) {
- case ANDROID_ALARM_SET_AND_WAIT_COMPAT(0):
- case ANDROID_ALARM_SET_COMPAT(0):
- case ANDROID_ALARM_SET_RTC_COMPAT:
- if (compat_get_timespec(&ts, (void __user *)arg))
- return -EFAULT;
- /* fall through */
- case ANDROID_ALARM_GET_TIME_COMPAT(0):
- cmd = ANDROID_ALARM_COMPAT_TO_NORM(cmd);
- break;
- }
-
- rv = alarm_do_ioctl(file, cmd, &ts);
- if (rv)
- return rv;
-
- switch (ANDROID_ALARM_BASE_CMD(cmd)) {
- case ANDROID_ALARM_GET_TIME(0): /* NOTE: we modified cmd above */
- if (compat_put_timespec(&ts, (void __user *)arg))
- return -EFAULT;
- break;
- }
-
- return 0;
-}
-#endif
-
-static int alarm_open(struct inode *inode, struct file *file)
-{
- file->private_data = NULL;
- return 0;
-}
-
-static int alarm_release(struct inode *inode, struct file *file)
-{
- int i;
- unsigned long flags;
-
- spin_lock_irqsave(&alarm_slock, flags);
- if (file->private_data) {
- for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
- uint32_t alarm_type_mask = 1U << i;
-
- if (alarm_enabled & alarm_type_mask) {
- alarm_dbg(INFO,
- "%s: clear alarm, pending %d\n",
- __func__,
- !!(alarm_pending & alarm_type_mask));
- alarm_enabled &= ~alarm_type_mask;
- }
- spin_unlock_irqrestore(&alarm_slock, flags);
- devalarm_cancel(&alarms[i]);
- spin_lock_irqsave(&alarm_slock, flags);
- }
- if (alarm_pending | wait_pending) {
- if (alarm_pending)
- alarm_dbg(INFO, "%s: clear pending alarms %x\n",
- __func__, alarm_pending);
- __pm_relax(&alarm_wake_lock);
- wait_pending = 0;
- alarm_pending = 0;
- }
- alarm_opened = 0;
- }
- spin_unlock_irqrestore(&alarm_slock, flags);
- return 0;
-}
-
-static void devalarm_triggered(struct devalarm *alarm)
-{
- unsigned long flags;
- uint32_t alarm_type_mask = 1U << alarm->type;
-
- alarm_dbg(INT, "%s: type %d\n", __func__, alarm->type);
- spin_lock_irqsave(&alarm_slock, flags);
- if (alarm_enabled & alarm_type_mask) {
- __pm_wakeup_event(&alarm_wake_lock, 5000); /* 5secs */
- alarm_enabled &= ~alarm_type_mask;
- alarm_pending |= alarm_type_mask;
- wake_up(&alarm_wait_queue);
- }
- spin_unlock_irqrestore(&alarm_slock, flags);
-}
-
-static enum hrtimer_restart devalarm_hrthandler(struct hrtimer *hrt)
-{
- struct devalarm *devalrm = container_of(hrt, struct devalarm, u.hrt);
-
- devalarm_triggered(devalrm);
- return HRTIMER_NORESTART;
-}
-
-static enum alarmtimer_restart devalarm_alarmhandler(struct alarm *alrm,
- ktime_t now)
-{
- struct devalarm *devalrm = container_of(alrm, struct devalarm, u.alrm);
-
- devalarm_triggered(devalrm);
- return ALARMTIMER_NORESTART;
-}
-
-
-static const struct file_operations alarm_fops = {
- .owner = THIS_MODULE,
- .unlocked_ioctl = alarm_ioctl,
- .open = alarm_open,
- .release = alarm_release,
-#ifdef CONFIG_COMPAT
- .compat_ioctl = alarm_compat_ioctl,
-#endif
-};
-
-static struct miscdevice alarm_device = {
- .minor = MISC_DYNAMIC_MINOR,
- .name = "alarm",
- .fops = &alarm_fops,
-};
-
-static int __init alarm_dev_init(void)
-{
- int err;
- int i;
-
- err = misc_register(&alarm_device);
- if (err)
- return err;
-
- alarm_init(&alarms[ANDROID_ALARM_RTC_WAKEUP].u.alrm,
- ALARM_REALTIME, devalarm_alarmhandler);
- hrtimer_init(&alarms[ANDROID_ALARM_RTC].u.hrt,
- CLOCK_REALTIME, HRTIMER_MODE_ABS);
- alarm_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP].u.alrm,
- ALARM_BOOTTIME, devalarm_alarmhandler);
- hrtimer_init(&alarms[ANDROID_ALARM_ELAPSED_REALTIME].u.hrt,
- CLOCK_BOOTTIME, HRTIMER_MODE_ABS);
- hrtimer_init(&alarms[ANDROID_ALARM_SYSTEMTIME].u.hrt,
- CLOCK_MONOTONIC, HRTIMER_MODE_ABS);
-
- for (i = 0; i < ANDROID_ALARM_TYPE_COUNT; i++) {
- alarms[i].type = i;
- if (!is_wakeup(i))
- alarms[i].u.hrt.function = devalarm_hrthandler;
- }
-
- wakeup_source_init(&alarm_wake_lock, "alarm");
- return 0;
-}
-
-static void __exit alarm_dev_exit(void)
-{
- misc_deregister(&alarm_device);
- wakeup_source_trash(&alarm_wake_lock);
-}
-
-module_init(alarm_dev_init);
-module_exit(alarm_dev_exit);
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/android/android_alarm.h b/drivers/staging/android/android_alarm.h
deleted file mode 100644
index 495b20cf3bf6..000000000000
--- a/drivers/staging/android/android_alarm.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/* include/linux/android_alarm.h
- *
- * Copyright (C) 2006-2007 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _LINUX_ANDROID_ALARM_H
-#define _LINUX_ANDROID_ALARM_H
-
-#include <linux/compat.h>
-#include <linux/ioctl.h>
-
-#include "uapi/android_alarm.h"
-
-#ifdef CONFIG_COMPAT
-#define ANDROID_ALARM_SET_COMPAT(type) ALARM_IOW(2, type, \
- struct compat_timespec)
-#define ANDROID_ALARM_SET_AND_WAIT_COMPAT(type) ALARM_IOW(3, type, \
- struct compat_timespec)
-#define ANDROID_ALARM_GET_TIME_COMPAT(type) ALARM_IOW(4, type, \
- struct compat_timespec)
-#define ANDROID_ALARM_SET_RTC_COMPAT _IOW('a', 5, \
- struct compat_timespec)
-#define ANDROID_ALARM_IOCTL_NR(cmd) (_IOC_NR(cmd) & ((1<<4)-1))
-#define ANDROID_ALARM_COMPAT_TO_NORM(cmd) \
- ALARM_IOW(ANDROID_ALARM_IOCTL_NR(cmd), \
- ANDROID_ALARM_IOCTL_TO_TYPE(cmd), \
- struct timespec)
-
-#endif
-
-#endif
diff --git a/drivers/staging/android/ashmem.c b/drivers/staging/android/ashmem.c
index 8c7852742f4b..d140b733940c 100644
--- a/drivers/staging/android/ashmem.c
+++ b/drivers/staging/android/ashmem.c
@@ -447,8 +447,8 @@ ashmem_shrink_scan(struct shrinker *shrink, struct shrink_control *sc)
loff_t end = (range->pgend + 1) * PAGE_SIZE;
vfs_fallocate(range->asma->file,
- FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
- start, end - start);
+ FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE,
+ start, end - start);
range->purged = ASHMEM_WAS_PURGED;
lru_del(range);
@@ -549,7 +549,6 @@ static int get_name(struct ashmem_area *asma, void __user *name)
mutex_lock(&ashmem_mutex);
if (asma->name[ASHMEM_NAME_PREFIX_LEN] != '\0') {
-
/*
* Copying only `len', instead of ASHMEM_NAME_LEN, bytes
* prevents us from revealing one user's stack to another.
@@ -751,10 +750,10 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
switch (cmd) {
case ASHMEM_SET_NAME:
- ret = set_name(asma, (void __user *) arg);
+ ret = set_name(asma, (void __user *)arg);
break;
case ASHMEM_GET_NAME:
- ret = get_name(asma, (void __user *) arg);
+ ret = get_name(asma, (void __user *)arg);
break;
case ASHMEM_SET_SIZE:
ret = -EINVAL;
@@ -775,7 +774,7 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case ASHMEM_PIN:
case ASHMEM_UNPIN:
case ASHMEM_GET_PIN_STATUS:
- ret = ashmem_pin_unpin(asma, cmd, (void __user *) arg);
+ ret = ashmem_pin_unpin(asma, cmd, (void __user *)arg);
break;
case ASHMEM_PURGE_ALL_CACHES:
ret = -EPERM;
@@ -798,7 +797,6 @@ static long ashmem_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static long compat_ashmem_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
-
switch (cmd) {
case COMPAT_ASHMEM_SET_SIZE:
cmd = ASHMEM_SET_SIZE;
diff --git a/drivers/staging/android/ion/ion.c b/drivers/staging/android/ion/ion.c
index 296d347660fc..b8f1c491553e 100644
--- a/drivers/staging/android/ion/ion.c
+++ b/drivers/staging/android/ion/ion.c
@@ -1508,6 +1508,9 @@ void ion_device_add_heap(struct ion_device *dev, struct ion_heap *heap)
pr_err("%s: can not add heap with invalid ops struct.\n",
__func__);
+ spin_lock_init(&heap->free_lock);
+ heap->free_list_size = 0;
+
if (heap->flags & ION_HEAP_FLAG_DEFER_FREE)
ion_heap_init_deferred_free(heap);
diff --git a/drivers/staging/android/ion/ion_cma_heap.c b/drivers/staging/android/ion/ion_cma_heap.c
index f8cabcbc39e5..f4211f1be488 100644
--- a/drivers/staging/android/ion/ion_cma_heap.c
+++ b/drivers/staging/android/ion/ion_cma_heap.c
@@ -39,24 +39,6 @@ struct ion_cma_buffer_info {
struct sg_table *table;
};
-/*
- * Create scatter-list for the already allocated DMA buffer.
- * This function could be replaced by dma_common_get_sgtable
- * as soon as it will avalaible.
- */
-static int ion_cma_get_sgtable(struct device *dev, struct sg_table *sgt,
- void *cpu_addr, dma_addr_t handle, size_t size)
-{
- struct page *page = virt_to_page(cpu_addr);
- int ret;
-
- ret = sg_alloc_table(sgt, 1, GFP_KERNEL);
- if (unlikely(ret))
- return ret;
-
- sg_set_page(sgt->sgl, page, PAGE_ALIGN(size), 0);
- return 0;
-}
/* ION CMA heap operations functions */
static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
@@ -91,7 +73,7 @@ static int ion_cma_allocate(struct ion_heap *heap, struct ion_buffer *buffer,
if (!info->table)
goto free_mem;
- if (ion_cma_get_sgtable
+ if (dma_common_get_sgtable
(dev, info->table, info->cpu_addr, info->handle, len))
goto free_table;
/* keep this for memory release */
diff --git a/drivers/staging/android/ion/ion_heap.c b/drivers/staging/android/ion/ion_heap.c
index 4605e04712aa..fd13d05b538a 100644
--- a/drivers/staging/android/ion/ion_heap.c
+++ b/drivers/staging/android/ion/ion_heap.c
@@ -253,8 +253,6 @@ int ion_heap_init_deferred_free(struct ion_heap *heap)
struct sched_param param = { .sched_priority = 0 };
INIT_LIST_HEAD(&heap->free_list);
- heap->free_list_size = 0;
- spin_lock_init(&heap->free_lock);
init_waitqueue_head(&heap->waitqueue);
heap->task = kthread_run(ion_heap_deferred_free, heap,
"%s", heap->name);
diff --git a/drivers/staging/android/logger.c b/drivers/staging/android/logger.c
deleted file mode 100644
index a673ffa34aa3..000000000000
--- a/drivers/staging/android/logger.c
+++ /dev/null
@@ -1,808 +0,0 @@
-/*
- * drivers/misc/logger.c
- *
- * A Logging Subsystem
- *
- * Copyright (C) 2007-2008 Google, Inc.
- *
- * Robert Love <rlove@google.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#define pr_fmt(fmt) "logger: " fmt
-
-#include <linux/sched.h>
-#include <linux/module.h>
-#include <linux/fs.h>
-#include <linux/miscdevice.h>
-#include <linux/uaccess.h>
-#include <linux/poll.h>
-#include <linux/slab.h>
-#include <linux/time.h>
-#include <linux/vmalloc.h>
-#include <linux/aio.h>
-#include "logger.h"
-
-#include <asm/ioctls.h>
-
-/**
- * struct logger_log - represents a specific log, such as 'main' or 'radio'
- * @buffer: The actual ring buffer
- * @misc: The "misc" device representing the log
- * @wq: The wait queue for @readers
- * @readers: This log's readers
- * @mutex: The mutex that protects the @buffer
- * @w_off: The current write head offset
- * @head: The head, or location that readers start reading at.
- * @size: The size of the log
- * @logs: The list of log channels
- *
- * This structure lives from module insertion until module removal, so it does
- * not need additional reference counting. The structure is protected by the
- * mutex 'mutex'.
- */
-struct logger_log {
- unsigned char *buffer;
- struct miscdevice misc;
- wait_queue_head_t wq;
- struct list_head readers;
- struct mutex mutex;
- size_t w_off;
- size_t head;
- size_t size;
- struct list_head logs;
-};
-
-static LIST_HEAD(log_list);
-
-
-/**
- * struct logger_reader - a logging device open for reading
- * @log: The associated log
- * @list: The associated entry in @logger_log's list
- * @r_off: The current read head offset.
- * @r_all: Reader can read all entries
- * @r_ver: Reader ABI version
- *
- * This object lives from open to release, so we don't need additional
- * reference counting. The structure is protected by log->mutex.
- */
-struct logger_reader {
- struct logger_log *log;
- struct list_head list;
- size_t r_off;
- bool r_all;
- int r_ver;
-};
-
-/* logger_offset - returns index 'n' into the log via (optimized) modulus */
-static size_t logger_offset(struct logger_log *log, size_t n)
-{
- return n & (log->size - 1);
-}
-
-
-/*
- * file_get_log - Given a file structure, return the associated log
- *
- * This isn't aesthetic. We have several goals:
- *
- * 1) Need to quickly obtain the associated log during an I/O operation
- * 2) Readers need to maintain state (logger_reader)
- * 3) Writers need to be very fast (open() should be a near no-op)
- *
- * In the reader case, we can trivially go file->logger_reader->logger_log.
- * For a writer, we don't want to maintain a logger_reader, so we just go
- * file->logger_log. Thus what file->private_data points at depends on whether
- * or not the file was opened for reading. This function hides that dirtiness.
- */
-static inline struct logger_log *file_get_log(struct file *file)
-{
- if (file->f_mode & FMODE_READ) {
- struct logger_reader *reader = file->private_data;
-
- return reader->log;
- }
- return file->private_data;
-}
-
-/*
- * get_entry_header - returns a pointer to the logger_entry header within
- * 'log' starting at offset 'off'. A temporary logger_entry 'scratch' must
- * be provided. Typically the return value will be a pointer within
- * 'logger->buf'. However, a pointer to 'scratch' may be returned if
- * the log entry spans the end and beginning of the circular buffer.
- */
-static struct logger_entry *get_entry_header(struct logger_log *log,
- size_t off, struct logger_entry *scratch)
-{
- size_t len = min(sizeof(struct logger_entry), log->size - off);
-
- if (len != sizeof(struct logger_entry)) {
- memcpy(((void *) scratch), log->buffer + off, len);
- memcpy(((void *) scratch) + len, log->buffer,
- sizeof(struct logger_entry) - len);
- return scratch;
- }
-
- return (struct logger_entry *) (log->buffer + off);
-}
-
-/*
- * get_entry_msg_len - Grabs the length of the message of the entry
- * starting from from 'off'.
- *
- * An entry length is 2 bytes (16 bits) in host endian order.
- * In the log, the length does not include the size of the log entry structure.
- * This function returns the size including the log entry structure.
- *
- * Caller needs to hold log->mutex.
- */
-static __u32 get_entry_msg_len(struct logger_log *log, size_t off)
-{
- struct logger_entry scratch;
- struct logger_entry *entry;
-
- entry = get_entry_header(log, off, &scratch);
- return entry->len;
-}
-
-static size_t get_user_hdr_len(int ver)
-{
- if (ver < 2)
- return sizeof(struct user_logger_entry_compat);
- return sizeof(struct logger_entry);
-}
-
-static ssize_t copy_header_to_user(int ver, struct logger_entry *entry,
- char __user *buf)
-{
- void *hdr;
- size_t hdr_len;
- struct user_logger_entry_compat v1;
-
- if (ver < 2) {
- v1.len = entry->len;
- v1.__pad = 0;
- v1.pid = entry->pid;
- v1.tid = entry->tid;
- v1.sec = entry->sec;
- v1.nsec = entry->nsec;
- hdr = &v1;
- hdr_len = sizeof(struct user_logger_entry_compat);
- } else {
- hdr = entry;
- hdr_len = sizeof(struct logger_entry);
- }
-
- return copy_to_user(buf, hdr, hdr_len);
-}
-
-/*
- * do_read_log_to_user - reads exactly 'count' bytes from 'log' into the
- * user-space buffer 'buf'. Returns 'count' on success.
- *
- * Caller must hold log->mutex.
- */
-static ssize_t do_read_log_to_user(struct logger_log *log,
- struct logger_reader *reader,
- char __user *buf,
- size_t count)
-{
- struct logger_entry scratch;
- struct logger_entry *entry;
- size_t len;
- size_t msg_start;
-
- /*
- * First, copy the header to userspace, using the version of
- * the header requested
- */
- entry = get_entry_header(log, reader->r_off, &scratch);
- if (copy_header_to_user(reader->r_ver, entry, buf))
- return -EFAULT;
-
- count -= get_user_hdr_len(reader->r_ver);
- buf += get_user_hdr_len(reader->r_ver);
- msg_start = logger_offset(log,
- reader->r_off + sizeof(struct logger_entry));
-
- /*
- * We read from the msg in two disjoint operations. First, we read from
- * the current msg head offset up to 'count' bytes or to the end of
- * the log, whichever comes first.
- */
- len = min(count, log->size - msg_start);
- if (copy_to_user(buf, log->buffer + msg_start, len))
- return -EFAULT;
-
- /*
- * Second, we read any remaining bytes, starting back at the head of
- * the log.
- */
- if (count != len)
- if (copy_to_user(buf + len, log->buffer, count - len))
- return -EFAULT;
-
- reader->r_off = logger_offset(log, reader->r_off +
- sizeof(struct logger_entry) + count);
-
- return count + get_user_hdr_len(reader->r_ver);
-}
-
-/*
- * get_next_entry_by_uid - Starting at 'off', returns an offset into
- * 'log->buffer' which contains the first entry readable by 'euid'
- */
-static size_t get_next_entry_by_uid(struct logger_log *log,
- size_t off, kuid_t euid)
-{
- while (off != log->w_off) {
- struct logger_entry *entry;
- struct logger_entry scratch;
- size_t next_len;
-
- entry = get_entry_header(log, off, &scratch);
-
- if (uid_eq(entry->euid, euid))
- return off;
-
- next_len = sizeof(struct logger_entry) + entry->len;
- off = logger_offset(log, off + next_len);
- }
-
- return off;
-}
-
-/*
- * logger_read - our log's read() method
- *
- * Behavior:
- *
- * - O_NONBLOCK works
- * - If there are no log entries to read, blocks until log is written to
- * - Atomically reads exactly one log entry
- *
- * Will set errno to EINVAL if read
- * buffer is insufficient to hold next entry.
- */
-static ssize_t logger_read(struct file *file, char __user *buf,
- size_t count, loff_t *pos)
-{
- struct logger_reader *reader = file->private_data;
- struct logger_log *log = reader->log;
- ssize_t ret;
- DEFINE_WAIT(wait);
-
-start:
- while (1) {
- mutex_lock(&log->mutex);
-
- prepare_to_wait(&log->wq, &wait, TASK_INTERRUPTIBLE);
-
- ret = (log->w_off == reader->r_off);
- mutex_unlock(&log->mutex);
- if (!ret)
- break;
-
- if (file->f_flags & O_NONBLOCK) {
- ret = -EAGAIN;
- break;
- }
-
- if (signal_pending(current)) {
- ret = -EINTR;
- break;
- }
-
- schedule();
- }
-
- finish_wait(&log->wq, &wait);
- if (ret)
- return ret;
-
- mutex_lock(&log->mutex);
-
- if (!reader->r_all)
- reader->r_off = get_next_entry_by_uid(log,
- reader->r_off, current_euid());
-
- /* is there still something to read or did we race? */
- if (unlikely(log->w_off == reader->r_off)) {
- mutex_unlock(&log->mutex);
- goto start;
- }
-
- /* get the size of the next entry */
- ret = get_user_hdr_len(reader->r_ver) +
- get_entry_msg_len(log, reader->r_off);
- if (count < ret) {
- ret = -EINVAL;
- goto out;
- }
-
- /* get exactly one entry from the log */
- ret = do_read_log_to_user(log, reader, buf, ret);
-
-out:
- mutex_unlock(&log->mutex);
-
- return ret;
-}
-
-/*
- * get_next_entry - return the offset of the first valid entry at least 'len'
- * bytes after 'off'.
- *
- * Caller must hold log->mutex.
- */
-static size_t get_next_entry(struct logger_log *log, size_t off, size_t len)
-{
- size_t count = 0;
-
- do {
- size_t nr = sizeof(struct logger_entry) +
- get_entry_msg_len(log, off);
- off = logger_offset(log, off + nr);
- count += nr;
- } while (count < len);
-
- return off;
-}
-
-/*
- * is_between - is a < c < b, accounting for wrapping of a, b, and c
- * positions in the buffer
- *
- * That is, if a<b, check for c between a and b
- * and if a>b, check for c outside (not between) a and b
- *
- * |------- a xxxxxxxx b --------|
- * c^
- *
- * |xxxxx b --------- a xxxxxxxxx|
- * c^
- * or c^
- */
-static inline int is_between(size_t a, size_t b, size_t c)
-{
- if (a < b) {
- /* is c between a and b? */
- if (a < c && c <= b)
- return 1;
- } else {
- /* is c outside of b through a? */
- if (c <= b || a < c)
- return 1;
- }
-
- return 0;
-}
-
-/*
- * fix_up_readers - walk the list of all readers and "fix up" any who were
- * lapped by the writer; also do the same for the default "start head".
- * We do this by "pulling forward" the readers and start head to the first
- * entry after the new write head.
- *
- * The caller needs to hold log->mutex.
- */
-static void fix_up_readers(struct logger_log *log, size_t len)
-{
- size_t old = log->w_off;
- size_t new = logger_offset(log, old + len);
- struct logger_reader *reader;
-
- if (is_between(old, new, log->head))
- log->head = get_next_entry(log, log->head, len);
-
- list_for_each_entry(reader, &log->readers, list)
- if (is_between(old, new, reader->r_off))
- reader->r_off = get_next_entry(log, reader->r_off, len);
-}
-
-/*
- * logger_write_iter - our write method, implementing support for write(),
- * writev(), and aio_write(). Writes are our fast path, and we try to optimize
- * them above all else.
- */
-static ssize_t logger_write_iter(struct kiocb *iocb, struct iov_iter *from)
-{
- struct logger_log *log = file_get_log(iocb->ki_filp);
- struct logger_entry header;
- struct timespec now;
- size_t len, count, w_off;
-
- count = min_t(size_t, iocb->ki_nbytes, LOGGER_ENTRY_MAX_PAYLOAD);
-
- now = current_kernel_time();
-
- header.pid = current->tgid;
- header.tid = current->pid;
- header.sec = now.tv_sec;
- header.nsec = now.tv_nsec;
- header.euid = current_euid();
- header.len = count;
- header.hdr_size = sizeof(struct logger_entry);
-
- /* null writes succeed, return zero */
- if (unlikely(!header.len))
- return 0;
-
- mutex_lock(&log->mutex);
-
- /*
- * Fix up any readers, pulling them forward to the first readable
- * entry after (what will be) the new write offset. We do this now
- * because if we partially fail, we can end up with clobbered log
- * entries that encroach on readable buffer.
- */
- fix_up_readers(log, sizeof(struct logger_entry) + header.len);
-
- len = min(sizeof(header), log->size - log->w_off);
- memcpy(log->buffer + log->w_off, &header, len);
- memcpy(log->buffer, (char *)&header + len, sizeof(header) - len);
-
- /* Work with a copy until we are ready to commit the whole entry */
- w_off = logger_offset(log, log->w_off + sizeof(struct logger_entry));
-
- len = min(count, log->size - w_off);
-
- if (copy_from_iter(log->buffer + w_off, len, from) != len) {
- /*
- * Note that by not updating log->w_off, this abandons the
- * portion of the new entry that *was* successfully
- * copied, just above. This is intentional to avoid
- * message corruption from missing fragments.
- */
- mutex_unlock(&log->mutex);
- return -EFAULT;
- }
-
- if (copy_from_iter(log->buffer, count - len, from) != count - len) {
- mutex_unlock(&log->mutex);
- return -EFAULT;
- }
-
- log->w_off = logger_offset(log, w_off + count);
- mutex_unlock(&log->mutex);
-
- /* wake up any blocked readers */
- wake_up_interruptible(&log->wq);
-
- return len;
-}
-
-static struct logger_log *get_log_from_minor(int minor)
-{
- struct logger_log *log;
-
- list_for_each_entry(log, &log_list, logs)
- if (log->misc.minor == minor)
- return log;
- return NULL;
-}
-
-/*
- * logger_open - the log's open() file operation
- *
- * Note how near a no-op this is in the write-only case. Keep it that way!
- */
-static int logger_open(struct inode *inode, struct file *file)
-{
- struct logger_log *log;
- int ret;
-
- ret = nonseekable_open(inode, file);
- if (ret)
- return ret;
-
- log = get_log_from_minor(MINOR(inode->i_rdev));
- if (!log)
- return -ENODEV;
-
- if (file->f_mode & FMODE_READ) {
- struct logger_reader *reader;
-
- reader = kmalloc(sizeof(struct logger_reader), GFP_KERNEL);
- if (!reader)
- return -ENOMEM;
-
- reader->log = log;
- reader->r_ver = 1;
- reader->r_all = in_egroup_p(inode->i_gid) ||
- capable(CAP_SYSLOG);
-
- INIT_LIST_HEAD(&reader->list);
-
- mutex_lock(&log->mutex);
- reader->r_off = log->head;
- list_add_tail(&reader->list, &log->readers);
- mutex_unlock(&log->mutex);
-
- file->private_data = reader;
- } else
- file->private_data = log;
-
- return 0;
-}
-
-/*
- * logger_release - the log's release file operation
- *
- * Note this is a total no-op in the write-only case. Keep it that way!
- */
-static int logger_release(struct inode *ignored, struct file *file)
-{
- if (file->f_mode & FMODE_READ) {
- struct logger_reader *reader = file->private_data;
- struct logger_log *log = reader->log;
-
- mutex_lock(&log->mutex);
- list_del(&reader->list);
- mutex_unlock(&log->mutex);
-
- kfree(reader);
- }
-
- return 0;
-}
-
-/*
- * logger_poll - the log's poll file operation, for poll/select/epoll
- *
- * Note we always return POLLOUT, because you can always write() to the log.
- * Note also that, strictly speaking, a return value of POLLIN does not
- * guarantee that the log is readable without blocking, as there is a small
- * chance that the writer can lap the reader in the interim between poll()
- * returning and the read() request.
- */
-static unsigned int logger_poll(struct file *file, poll_table *wait)
-{
- struct logger_reader *reader;
- struct logger_log *log;
- unsigned int ret = POLLOUT | POLLWRNORM;
-
- if (!(file->f_mode & FMODE_READ))
- return ret;
-
- reader = file->private_data;
- log = reader->log;
-
- poll_wait(file, &log->wq, wait);
-
- mutex_lock(&log->mutex);
- if (!reader->r_all)
- reader->r_off = get_next_entry_by_uid(log,
- reader->r_off, current_euid());
-
- if (log->w_off != reader->r_off)
- ret |= POLLIN | POLLRDNORM;
- mutex_unlock(&log->mutex);
-
- return ret;
-}
-
-static long logger_set_version(struct logger_reader *reader, void __user *arg)
-{
- int version;
-
- if (copy_from_user(&version, arg, sizeof(int)))
- return -EFAULT;
-
- if ((version < 1) || (version > 2))
- return -EINVAL;
-
- reader->r_ver = version;
- return 0;
-}
-
-static long logger_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct logger_log *log = file_get_log(file);
- struct logger_reader *reader;
- long ret = -EINVAL;
- void __user *argp = (void __user *) arg;
-
- mutex_lock(&log->mutex);
-
- switch (cmd) {
- case LOGGER_GET_LOG_BUF_SIZE:
- ret = log->size;
- break;
- case LOGGER_GET_LOG_LEN:
- if (!(file->f_mode & FMODE_READ)) {
- ret = -EBADF;
- break;
- }
- reader = file->private_data;
- if (log->w_off >= reader->r_off)
- ret = log->w_off - reader->r_off;
- else
- ret = (log->size - reader->r_off) + log->w_off;
- break;
- case LOGGER_GET_NEXT_ENTRY_LEN:
- if (!(file->f_mode & FMODE_READ)) {
- ret = -EBADF;
- break;
- }
- reader = file->private_data;
-
- if (!reader->r_all)
- reader->r_off = get_next_entry_by_uid(log,
- reader->r_off, current_euid());
-
- if (log->w_off != reader->r_off)
- ret = get_user_hdr_len(reader->r_ver) +
- get_entry_msg_len(log, reader->r_off);
- else
- ret = 0;
- break;
- case LOGGER_FLUSH_LOG:
- if (!(file->f_mode & FMODE_WRITE)) {
- ret = -EBADF;
- break;
- }
- if (!(in_egroup_p(file_inode(file)->i_gid) ||
- capable(CAP_SYSLOG))) {
- ret = -EPERM;
- break;
- }
- list_for_each_entry(reader, &log->readers, list)
- reader->r_off = log->w_off;
- log->head = log->w_off;
- ret = 0;
- break;
- case LOGGER_GET_VERSION:
- if (!(file->f_mode & FMODE_READ)) {
- ret = -EBADF;
- break;
- }
- reader = file->private_data;
- ret = reader->r_ver;
- break;
- case LOGGER_SET_VERSION:
- if (!(file->f_mode & FMODE_READ)) {
- ret = -EBADF;
- break;
- }
- reader = file->private_data;
- ret = logger_set_version(reader, argp);
- break;
- }
-
- mutex_unlock(&log->mutex);
-
- return ret;
-}
-
-static const struct file_operations logger_fops = {
- .owner = THIS_MODULE,
- .read = logger_read,
- .write_iter = logger_write_iter,
- .poll = logger_poll,
- .unlocked_ioctl = logger_ioctl,
- .compat_ioctl = logger_ioctl,
- .open = logger_open,
- .release = logger_release,
-};
-
-/*
- * Log size must must be a power of two, and greater than
- * (LOGGER_ENTRY_MAX_PAYLOAD + sizeof(struct logger_entry)).
- */
-static int __init create_log(char *log_name, int size)
-{
- int ret = 0;
- struct logger_log *log;
- unsigned char *buffer;
-
- buffer = vmalloc(size);
- if (buffer == NULL)
- return -ENOMEM;
-
- log = kzalloc(sizeof(struct logger_log), GFP_KERNEL);
- if (log == NULL) {
- ret = -ENOMEM;
- goto out_free_buffer;
- }
- log->buffer = buffer;
-
- log->misc.minor = MISC_DYNAMIC_MINOR;
- log->misc.name = kstrdup(log_name, GFP_KERNEL);
- if (log->misc.name == NULL) {
- ret = -ENOMEM;
- goto out_free_log;
- }
-
- log->misc.fops = &logger_fops;
- log->misc.parent = NULL;
-
- init_waitqueue_head(&log->wq);
- INIT_LIST_HEAD(&log->readers);
- mutex_init(&log->mutex);
- log->w_off = 0;
- log->head = 0;
- log->size = size;
-
- INIT_LIST_HEAD(&log->logs);
- list_add_tail(&log->logs, &log_list);
-
- /* finally, initialize the misc device for this log */
- ret = misc_register(&log->misc);
- if (unlikely(ret)) {
- pr_err("failed to register misc device for log '%s'!\n",
- log->misc.name);
- goto out_free_misc_name;
- }
-
- pr_info("created %luK log '%s'\n",
- (unsigned long) log->size >> 10, log->misc.name);
-
- return 0;
-
-out_free_misc_name:
- kfree(log->misc.name);
-
-out_free_log:
- kfree(log);
-
-out_free_buffer:
- vfree(buffer);
- return ret;
-}
-
-static int __init logger_init(void)
-{
- int ret;
-
- ret = create_log(LOGGER_LOG_MAIN, 256*1024);
- if (unlikely(ret))
- goto out;
-
- ret = create_log(LOGGER_LOG_EVENTS, 256*1024);
- if (unlikely(ret))
- goto out;
-
- ret = create_log(LOGGER_LOG_RADIO, 256*1024);
- if (unlikely(ret))
- goto out;
-
- ret = create_log(LOGGER_LOG_SYSTEM, 256*1024);
- if (unlikely(ret))
- goto out;
-
-out:
- return ret;
-}
-
-static void __exit logger_exit(void)
-{
- struct logger_log *current_log, *next_log;
-
- list_for_each_entry_safe(current_log, next_log, &log_list, logs) {
- /* we have to delete all the entry inside log_list */
- misc_deregister(&current_log->misc);
- vfree(current_log->buffer);
- kfree(current_log->misc.name);
- list_del(&current_log->logs);
- kfree(current_log);
- }
-}
-
-
-device_initcall(logger_init);
-module_exit(logger_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Robert Love, <rlove@google.com>");
-MODULE_DESCRIPTION("Android Logger");
diff --git a/drivers/staging/android/logger.h b/drivers/staging/android/logger.h
deleted file mode 100644
index 70af7d805dff..000000000000
--- a/drivers/staging/android/logger.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/* include/linux/logger.h
- *
- * Copyright (C) 2007-2008 Google, Inc.
- * Author: Robert Love <rlove@android.com>
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _LINUX_LOGGER_H
-#define _LINUX_LOGGER_H
-
-#include <linux/types.h>
-#include <linux/ioctl.h>
-
-/**
- * struct user_logger_entry_compat - defines a single entry that is given to a logger
- * @len: The length of the payload
- * @__pad: Two bytes of padding that appear to be required
- * @pid: The generating process' process ID
- * @tid: The generating process' thread ID
- * @sec: The number of seconds that have elapsed since the Epoch
- * @nsec: The number of nanoseconds that have elapsed since @sec
- * @msg: The message that is to be logged
- *
- * The userspace structure for version 1 of the logger_entry ABI.
- * This structure is returned to userspace unless the caller requests
- * an upgrade to a newer ABI version.
- */
-struct user_logger_entry_compat {
- __u16 len;
- __u16 __pad;
- __s32 pid;
- __s32 tid;
- __s32 sec;
- __s32 nsec;
- char msg[0];
-};
-
-/**
- * struct logger_entry - defines a single entry that is given to a logger
- * @len: The length of the payload
- * @hdr_size: sizeof(struct logger_entry_v2)
- * @pid: The generating process' process ID
- * @tid: The generating process' thread ID
- * @sec: The number of seconds that have elapsed since the Epoch
- * @nsec: The number of nanoseconds that have elapsed since @sec
- * @euid: Effective UID of logger
- * @msg: The message that is to be logged
- *
- * The structure for version 2 of the logger_entry ABI.
- * This structure is returned to userspace if ioctl(LOGGER_SET_VERSION)
- * is called with version >= 2
- */
-struct logger_entry {
- __u16 len;
- __u16 hdr_size;
- __s32 pid;
- __s32 tid;
- __s32 sec;
- __s32 nsec;
- kuid_t euid;
- char msg[0];
-};
-
-#define LOGGER_LOG_RADIO "log_radio" /* radio-related messages */
-#define LOGGER_LOG_EVENTS "log_events" /* system/hardware events */
-#define LOGGER_LOG_SYSTEM "log_system" /* system/framework messages */
-#define LOGGER_LOG_MAIN "log_main" /* everything else */
-
-#define LOGGER_ENTRY_MAX_PAYLOAD 4076
-
-#define __LOGGERIO 0xAE
-
-#define LOGGER_GET_LOG_BUF_SIZE _IO(__LOGGERIO, 1) /* size of log */
-#define LOGGER_GET_LOG_LEN _IO(__LOGGERIO, 2) /* used log len */
-#define LOGGER_GET_NEXT_ENTRY_LEN _IO(__LOGGERIO, 3) /* next entry len */
-#define LOGGER_FLUSH_LOG _IO(__LOGGERIO, 4) /* flush log */
-#define LOGGER_GET_VERSION _IO(__LOGGERIO, 5) /* abi version */
-#define LOGGER_SET_VERSION _IO(__LOGGERIO, 6) /* abi version */
-
-#endif /* _LINUX_LOGGER_H */
diff --git a/drivers/staging/android/lowmemorykiller.c b/drivers/staging/android/lowmemorykiller.c
index b545d3d1da3e..feafa172b155 100644
--- a/drivers/staging/android/lowmemorykiller.c
+++ b/drivers/staging/android/lowmemorykiller.c
@@ -160,7 +160,12 @@ static unsigned long lowmem_scan(struct shrinker *s, struct shrink_control *sc)
selected->pid, selected->comm,
selected_oom_score_adj, selected_tasksize);
lowmem_deathpending_timeout = jiffies + HZ;
- set_tsk_thread_flag(selected, TIF_MEMDIE);
+ /*
+ * FIXME: lowmemorykiller shouldn't abuse global OOM killer
+ * infrastructure. There is no real reason why the selected
+ * task should have access to the memory reserves.
+ */
+ mark_tsk_oom_victim(selected);
send_sig(SIGKILL, selected, 0);
rem += selected_tasksize;
}
diff --git a/drivers/staging/android/sync_debug.c b/drivers/staging/android/sync_debug.c
index 1532a86404be..91ed2c4cff45 100644
--- a/drivers/staging/android/sync_debug.c
+++ b/drivers/staging/android/sync_debug.c
@@ -96,7 +96,8 @@ static void sync_print_pt(struct seq_file *s, struct sync_pt *pt, bool fence)
sync_status_str(status));
if (status <= 0) {
- struct timespec64 ts64 = ktime_to_timespec64(pt->base.timestamp);
+ struct timespec64 ts64 =
+ ktime_to_timespec64(pt->base.timestamp);
seq_printf(s, "@%lld.%09ld", (s64)ts64.tv_sec, ts64.tv_nsec);
}
diff --git a/drivers/staging/android/uapi/android_alarm.h b/drivers/staging/android/uapi/android_alarm.h
deleted file mode 100644
index aa013f6f5f3a..000000000000
--- a/drivers/staging/android/uapi/android_alarm.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/* drivers/staging/android/uapi/android_alarm.h
- *
- * Copyright (C) 2006-2007 Google, Inc.
- *
- * This software is licensed under the terms of the GNU General Public
- * License version 2, as published by the Free Software Foundation, and
- * may be copied, distributed, and modified under those terms.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
-
-#ifndef _UAPI_LINUX_ANDROID_ALARM_H
-#define _UAPI_LINUX_ANDROID_ALARM_H
-
-#include <linux/ioctl.h>
-#include <linux/time.h>
-
-enum android_alarm_type {
- /* return code bit numbers or set alarm arg */
- ANDROID_ALARM_RTC_WAKEUP,
- ANDROID_ALARM_RTC,
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
- ANDROID_ALARM_ELAPSED_REALTIME,
- ANDROID_ALARM_SYSTEMTIME,
-
- ANDROID_ALARM_TYPE_COUNT,
-
- /* return code bit numbers */
- /* ANDROID_ALARM_TIME_CHANGE = 16 */
-};
-
-enum android_alarm_return_flags {
- ANDROID_ALARM_RTC_WAKEUP_MASK = 1U << ANDROID_ALARM_RTC_WAKEUP,
- ANDROID_ALARM_RTC_MASK = 1U << ANDROID_ALARM_RTC,
- ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP_MASK =
- 1U << ANDROID_ALARM_ELAPSED_REALTIME_WAKEUP,
- ANDROID_ALARM_ELAPSED_REALTIME_MASK =
- 1U << ANDROID_ALARM_ELAPSED_REALTIME,
- ANDROID_ALARM_SYSTEMTIME_MASK = 1U << ANDROID_ALARM_SYSTEMTIME,
- ANDROID_ALARM_TIME_CHANGE_MASK = 1U << 16
-};
-
-/* Disable alarm */
-#define ANDROID_ALARM_CLEAR(type) _IO('a', 0 | ((type) << 4))
-
-/* Ack last alarm and wait for next */
-#define ANDROID_ALARM_WAIT _IO('a', 1)
-
-#define ALARM_IOW(c, type, size) _IOW('a', (c) | ((type) << 4), size)
-/* Set alarm */
-#define ANDROID_ALARM_SET(type) ALARM_IOW(2, type, struct timespec)
-#define ANDROID_ALARM_SET_AND_WAIT(type) ALARM_IOW(3, type, struct timespec)
-#define ANDROID_ALARM_GET_TIME(type) ALARM_IOW(4, type, struct timespec)
-#define ANDROID_ALARM_SET_RTC _IOW('a', 5, struct timespec)
-#define ANDROID_ALARM_BASE_CMD(cmd) (cmd & ~(_IOC(0, 0, 0xf0, 0)))
-#define ANDROID_ALARM_IOCTL_TO_TYPE(cmd) (_IOC_NR(cmd) >> 4)
-
-#endif
diff --git a/drivers/staging/board/Kconfig b/drivers/staging/board/Kconfig
index 7eda0b8b7aab..0a89ad16371f 100644
--- a/drivers/staging/board/Kconfig
+++ b/drivers/staging/board/Kconfig
@@ -1,5 +1,5 @@
config STAGING_BOARD
- boolean "Staging Board Support"
+ bool "Staging Board Support"
depends on OF_ADDRESS
depends on BROKEN
help
diff --git a/drivers/staging/board/board.c b/drivers/staging/board/board.c
index 6050fbdfd31f..d5a6abc84519 100644
--- a/drivers/staging/board/board.c
+++ b/drivers/staging/board/board.c
@@ -11,8 +11,7 @@ static bool find_by_address(u64 base_address)
struct resource res;
while (dn) {
- if (of_can_translate_address(dn)
- && !of_address_to_resource(dn, 0, &res)) {
+ if (!of_address_to_resource(dn, 0, &res)) {
if (res.start == base_address) {
of_node_put(dn);
return true;
diff --git a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
index 471d0877f382..5455bf3d5a91 100644
--- a/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
+++ b/drivers/staging/clocking-wizard/clk-xlnx-clock-wizard.c
@@ -91,8 +91,10 @@ static int clk_wzrd_clk_notifier(struct notifier_block *nb, unsigned long event,
if (ndata->clk == clk_wzrd->clk_in1)
max = clk_wzrd_max_freq[clk_wzrd->speed_grade - 1];
- if (ndata->clk == clk_wzrd->axi_clk)
+ else if (ndata->clk == clk_wzrd->axi_clk)
max = WZRD_ACLK_MAX_FREQ;
+ else
+ return NOTIFY_DONE; /* should never happen */
switch (event) {
case PRE_RATE_CHANGE:
@@ -239,6 +241,7 @@ static int clk_wzrd_probe(struct platform_device *pdev)
/* register div per output */
for (i = WZRD_NUM_OUTPUTS - 1; i >= 0 ; i--) {
const char *clkout_name;
+
if (of_property_read_string_index(np, "clock-output-names", i,
&clkout_name)) {
dev_err(&pdev->dev,
diff --git a/drivers/staging/comedi/Kconfig b/drivers/staging/comedi/Kconfig
index a8201fe87512..593fcb1783b4 100644
--- a/drivers/staging/comedi/Kconfig
+++ b/drivers/staging/comedi/Kconfig
@@ -168,7 +168,7 @@ config COMEDI_PCL730
config COMEDI_PCL812
tristate "Advantech PCL-812/813 and ADlink ACL-8112/8113/8113/8216"
- depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
---help---
Enable support for Advantech PCL-812/PG, PCL-813/B, ADLink
ACL-8112DG/HG/PG, ACL-8113, ACL-8216, ICP DAS A-821PGH/PGL/PGL-NDA,
@@ -179,7 +179,7 @@ config COMEDI_PCL812
config COMEDI_PCL816
tristate "Advantech PCL-814 and PCL-816 ISA card support"
- depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
---help---
Enable support for Advantech PCL-814 and PCL-816 ISA cards
@@ -188,7 +188,7 @@ config COMEDI_PCL816
config COMEDI_PCL818
tristate "Advantech PCL-718 and PCL-818 ISA card support"
- depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
---help---
Enable support for Advantech PCL-818 ISA cards
PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818 and PCL-718
@@ -281,7 +281,7 @@ config COMEDI_DAS08_ISA
config COMEDI_DAS16
tristate "DAS-16 compatible ISA and PC/104 card support"
- depends on ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
select COMEDI_8255
---help---
Enable support for Keithley Metrabyte/ComputerBoards DAS16
@@ -309,7 +309,7 @@ config COMEDI_DAS800
config COMEDI_DAS1800
tristate "DAS1800 and compatible ISA card support"
- depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
---help---
Enable support for DAS1800 and compatible ISA cards
Keithley Metrabyte DAS-1701ST, DAS-1701ST-DA, DAS-1701/AO,
@@ -372,7 +372,7 @@ config COMEDI_DT2817
config COMEDI_DT282X
tristate "Data Translation DT2821 series and DT-EZ ISA card support"
- depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
---help---
Enable support for Data Translation DT2821 series including DT-EZ
DT2821, DT2821-F-16SE, DT2821-F-8DI, DT2821-G-16SE, DT2821-G-8DI,
@@ -462,7 +462,7 @@ config COMEDI_ADQ12B
config COMEDI_NI_AT_A2150
tristate "NI AT-A2150 ISA card support"
- depends on VIRT_TO_BUS && ISA_DMA_API
+ select COMEDI_ISADMA if ISA_DMA_API
---help---
Enable support for National Instruments AT-A2150 cards
@@ -502,7 +502,7 @@ config COMEDI_NI_ATMIO16D
config COMEDI_NI_LABPC_ISA
tristate "NI Lab-PC and compatibles ISA support"
select COMEDI_NI_LABPC
- select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API && VIRT_TO_BUS
+ select COMEDI_NI_LABPC_ISADMA if ISA_DMA_API
---help---
Enable support for National Instruments Lab-PC and compatibles
Lab-PC-1200, Lab-PC-1200AI, Lab-PC+.
@@ -724,7 +724,6 @@ config COMEDI_ADL_PCI9111
config COMEDI_ADL_PCI9118
tristate "ADLink PCI-9118DG, PCI-9118HG, PCI-9118HR support"
depends on HAS_DMA
- depends on VIRT_TO_BUS
---help---
Enable support for ADlink PCI-9118DG, PCI-9118HG, PCI-9118HR cards
@@ -1263,12 +1262,16 @@ config COMEDI_DAS08
tristate
select COMEDI_8255
+config COMEDI_ISADMA
+ tristate
+
config COMEDI_NI_LABPC
tristate
select COMEDI_8255
config COMEDI_NI_LABPC_ISADMA
tristate
+ select COMEDI_ISADMA
config COMEDI_NI_TIO
tristate
diff --git a/drivers/staging/comedi/comedi_compat32.c b/drivers/staging/comedi/comedi_compat32.c
index 5a4c74f703b3..25848244c4b1 100644
--- a/drivers/staging/comedi/comedi_compat32.c
+++ b/drivers/staging/comedi/comedi_compat32.c
@@ -1,23 +1,23 @@
/*
- comedi/comedi_compat32.c
- 32-bit ioctl compatibility for 64-bit comedi kernel module.
-
- Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
- Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * comedi/comedi_compat32.c
+ * 32-bit ioctl compatibility for 64-bit comedi kernel module.
+ *
+ * Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
+ * Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#include <linux/uaccess.h>
#include <linux/compat.h>
@@ -27,11 +27,15 @@
#define COMEDI32_CHANINFO _IOR(CIO, 3, struct comedi32_chaninfo_struct)
#define COMEDI32_RANGEINFO _IOR(CIO, 8, struct comedi32_rangeinfo_struct)
-/* N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
- * It's too late to change it now, but it only affects the command number. */
+/*
+ * N.B. COMEDI32_CMD and COMEDI_CMD ought to use _IOWR, not _IOR.
+ * It's too late to change it now, but it only affects the command number.
+ */
#define COMEDI32_CMD _IOR(CIO, 9, struct comedi32_cmd_struct)
-/* N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
- * It's too late to change it now, but it only affects the command number. */
+/*
+ * N.B. COMEDI32_CMDTEST and COMEDI_CMDTEST ought to use _IOWR, not _IOR.
+ * It's too late to change it now, but it only affects the command number.
+ */
#define COMEDI32_CMDTEST _IOR(CIO, 10, struct comedi32_cmd_struct)
#define COMEDI32_INSNLIST _IOR(CIO, 11, struct comedi32_insnlist_struct)
#define COMEDI32_INSN _IOR(CIO, 12, struct comedi32_insn_struct)
@@ -39,7 +43,7 @@
struct comedi32_chaninfo_struct {
unsigned int subdev;
compat_uptr_t maxdata_list; /* 32-bit 'unsigned int *' */
- compat_uptr_t flaglist; /* 32-bit 'unsigned int *' */
+ compat_uptr_t flaglist; /* 32-bit 'unsigned int *' */
compat_uptr_t rangelist; /* 32-bit 'unsigned int *' */
unsigned int unused[4];
};
@@ -62,16 +66,16 @@ struct comedi32_cmd_struct {
unsigned int scan_end_arg;
unsigned int stop_src;
unsigned int stop_arg;
- compat_uptr_t chanlist; /* 32-bit 'unsigned int *' */
+ compat_uptr_t chanlist; /* 32-bit 'unsigned int *' */
unsigned int chanlist_len;
- compat_uptr_t data; /* 32-bit 'short *' */
+ compat_uptr_t data; /* 32-bit 'short *' */
unsigned int data_len;
};
struct comedi32_insn_struct {
unsigned int insn;
unsigned int n;
- compat_uptr_t data; /* 32-bit 'unsigned int *' */
+ compat_uptr_t data; /* 32-bit 'unsigned int *' */
unsigned int subdev;
unsigned int chanspec;
unsigned int unused[3];
@@ -79,7 +83,7 @@ struct comedi32_insn_struct {
struct comedi32_insnlist_struct {
unsigned int n_insns;
- compat_uptr_t insns; /* 32-bit 'struct comedi_insn *' */
+ compat_uptr_t insns; /* 32-bit 'struct comedi_insn *' */
};
/* Handle translated ioctl. */
@@ -215,10 +219,12 @@ static int put_compat_cmd(struct comedi32_cmd_struct __user *cmd32,
int err;
unsigned int temp;
- /* Copy back most of cmd structure. */
- /* Assume the pointer values are already valid. */
- /* (Could use ptr_to_compat() to set them, but that wasn't implemented
- * until kernel version 2.6.11.) */
+ /*
+ * Copy back most of cmd structure.
+ *
+ * Assume the pointer values are already valid.
+ * (Could use ptr_to_compat() to set them.)
+ */
if (!access_ok(VERIFY_READ, cmd, sizeof(*cmd)) ||
!access_ok(VERIFY_WRITE, cmd32, sizeof(*cmd32)))
return -EFAULT;
@@ -262,7 +268,7 @@ static int compat_cmd(struct file *file, unsigned long arg)
{
struct comedi_cmd __user *cmd;
struct comedi32_cmd_struct __user *cmd32;
- int rc;
+ int rc, err;
cmd32 = compat_ptr(arg);
cmd = compat_alloc_user_space(sizeof(*cmd));
@@ -271,7 +277,15 @@ static int compat_cmd(struct file *file, unsigned long arg)
if (rc)
return rc;
- return translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
+ rc = translated_ioctl(file, COMEDI_CMD, (unsigned long)cmd);
+ if (rc == -EAGAIN) {
+ /* Special case: copy cmd back to user. */
+ err = put_compat_cmd(cmd32, cmd);
+ if (err)
+ rc = err;
+ }
+
+ return rc;
}
/* Handle 32-bit COMEDI_CMDTEST ioctl. */
@@ -395,10 +409,12 @@ static int compat_insn(struct file *file, unsigned long arg)
return translated_ioctl(file, COMEDI_INSN, (unsigned long)insn);
}
-/* Process untranslated ioctl. */
-/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
-static inline int raw_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+/*
+ * compat_ioctl file operation.
+ *
+ * Returns -ENOIOCTLCMD for unrecognised ioctl codes.
+ */
+long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
int rc;
@@ -445,10 +461,3 @@ static inline int raw_ioctl(struct file *file, unsigned int cmd,
}
return rc;
}
-
-/* compat_ioctl file operation. */
-/* Returns -ENOIOCTLCMD for unrecognised ioctl codes. */
-long comedi_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-{
- return raw_ioctl(file, cmd, arg);
-}
diff --git a/drivers/staging/comedi/comedi_compat32.h b/drivers/staging/comedi/comedi_compat32.h
index 2d0a6fcf60f3..5ce77f3e8c22 100644
--- a/drivers/staging/comedi/comedi_compat32.h
+++ b/drivers/staging/comedi/comedi_compat32.h
@@ -1,23 +1,23 @@
/*
- comedi/comedi_compat32.h
- 32-bit ioctl compatibility for 64-bit comedi kernel module.
-
- Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
- Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * comedi/comedi_compat32.h
+ * 32-bit ioctl compatibility for 64-bit comedi kernel module.
+ *
+ * Author: Ian Abbott, MEV Ltd. <abbotti@mev.co.uk>
+ * Copyright (C) 2007 MEV Ltd. <http://www.mev.co.uk/>
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2007 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#ifndef _COMEDI_COMPAT32_H
#define _COMEDI_COMPAT32_H
diff --git a/drivers/staging/comedi/comedi_fops.c b/drivers/staging/comedi/comedi_fops.c
index f143cb64d69e..727640e89c73 100644
--- a/drivers/staging/comedi/comedi_fops.c
+++ b/drivers/staging/comedi/comedi_fops.c
@@ -1,20 +1,20 @@
/*
- comedi/comedi_fops.c
- comedi kernel module
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * comedi/comedi_fops.c
+ * comedi kernel module
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -113,6 +113,18 @@ static void comedi_dev_kref_release(struct kref *kref)
kfree(dev);
}
+/**
+ * comedi_dev_put - release a use of a comedi device structure
+ * @dev: comedi_device struct
+ *
+ * Must be called when a user of a comedi device is finished with it.
+ * When the last user of the comedi device calls this function, the
+ * comedi device is destroyed.
+ *
+ * Return 1 if the comedi device is destroyed by this call or dev is
+ * NULL, otherwise return 0. Callers must not assume the comedi
+ * device is still valid if this function returns 0.
+ */
int comedi_dev_put(struct comedi_device *dev)
{
if (dev)
@@ -220,6 +232,18 @@ static struct comedi_device *comedi_dev_get_from_subdevice_minor(unsigned minor)
return dev;
}
+/**
+ * comedi_dev_get_from_minor - get comedi device by minor device number
+ * @minor: minor device number
+ *
+ * Finds the comedi device associated by the minor device number, if any,
+ * and increments its reference count. The comedi device is prevented from
+ * being freed until a matching call is made to comedi_dev_put().
+ *
+ * Return a pointer to the comedi device if it exists, with its usage
+ * reference incremented. Return NULL if no comedi device exists with the
+ * specified minor device number.
+ */
struct comedi_device *comedi_dev_get_from_minor(unsigned minor)
{
if (minor < COMEDI_NUM_BOARD_MINORS)
@@ -323,8 +347,7 @@ static int resize_async_buffer(struct comedi_device *dev,
return -EBUSY;
}
- /* make sure buffer is an integral number of pages
- * (we round up) */
+ /* make sure buffer is an integral number of pages (we round up) */
new_size = (new_size + PAGE_SIZE - 1) & PAGE_MASK;
retval = comedi_buf_alloc(dev, s, new_size);
@@ -600,11 +623,18 @@ static unsigned comedi_get_subdevice_runflags(struct comedi_subdevice *s)
return runflags;
}
+/**
+ * comedi_is_subdevice_running - check if async command running on subdevice
+ * @s: comedi_subdevice struct
+ *
+ * Return true if an asynchronous comedi command is active on the comedi
+ * subdevice, else return false.
+ */
bool comedi_is_subdevice_running(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
- return (runflags & SRF_RUNNING) ? true : false;
+ return (runflags & COMEDI_SRF_RUNNING) ? true : false;
}
EXPORT_SYMBOL_GPL(comedi_is_subdevice_running);
@@ -612,14 +642,14 @@ static bool comedi_is_subdevice_in_error(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
- return (runflags & SRF_ERROR) ? true : false;
+ return (runflags & COMEDI_SRF_ERROR) ? true : false;
}
static bool comedi_is_subdevice_idle(struct comedi_subdevice *s)
{
unsigned runflags = comedi_get_subdevice_runflags(s);
- return (runflags & (SRF_ERROR | SRF_RUNNING)) ? false : true;
+ return (runflags & COMEDI_SRF_BUSY_MASK) ? false : true;
}
/**
@@ -634,20 +664,20 @@ void *comedi_alloc_spriv(struct comedi_subdevice *s, size_t size)
{
s->private = kzalloc(size, GFP_KERNEL);
if (s->private)
- s->runflags |= SRF_FREE_SPRIV;
+ s->runflags |= COMEDI_SRF_FREE_SPRIV;
return s->private;
}
EXPORT_SYMBOL_GPL(comedi_alloc_spriv);
/*
- This function restores a subdevice to an idle state.
+ * This function restores a subdevice to an idle state.
*/
static void do_become_nonbusy(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
- comedi_set_subdevice_runflags(s, SRF_RUNNING, 0);
+ comedi_set_subdevice_runflags(s, COMEDI_SRF_RUNNING, 0);
if (async) {
comedi_buf_reset(s);
async->inttrig = NULL;
@@ -709,18 +739,18 @@ static int is_device_busy(struct comedi_device *dev)
}
/*
- COMEDI_DEVCONFIG
- device config ioctl
-
- arg:
- pointer to devconfig structure
-
- reads:
- devconfig structure at arg
-
- writes:
- none
-*/
+ * COMEDI_DEVCONFIG ioctl
+ * attaches (and configures) or detaches a legacy device
+ *
+ * arg:
+ * pointer to comedi_devconfig structure (NULL if detaching)
+ *
+ * reads:
+ * comedi_devconfig structure (if attaching)
+ *
+ * writes:
+ * nothing
+ */
static int do_devconfig_ioctl(struct comedi_device *dev,
struct comedi_devconfig __user *arg)
{
@@ -761,19 +791,18 @@ static int do_devconfig_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_BUFCONFIG
- buffer configuration ioctl
-
- arg:
- pointer to bufconfig structure
-
- reads:
- bufconfig at arg
-
- writes:
- modified bufconfig at arg
-
-*/
+ * COMEDI_BUFCONFIG ioctl
+ * buffer configuration
+ *
+ * arg:
+ * pointer to comedi_bufconfig structure
+ *
+ * reads:
+ * comedi_bufconfig structure
+ *
+ * writes:
+ * modified comedi_bufconfig structure
+ */
static int do_bufconfig_ioctl(struct comedi_device *dev,
struct comedi_bufconfig __user *arg)
{
@@ -823,19 +852,18 @@ copyback:
}
/*
- COMEDI_DEVINFO
- device info ioctl
-
- arg:
- pointer to devinfo structure
-
- reads:
- none
-
- writes:
- devinfo structure
-
-*/
+ * COMEDI_DEVINFO ioctl
+ * device info
+ *
+ * arg:
+ * pointer to comedi_devinfo structure
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * comedi_devinfo structure
+ */
static int do_devinfo_ioctl(struct comedi_device *dev,
struct comedi_devinfo __user *arg,
struct file *file)
@@ -870,19 +898,18 @@ static int do_devinfo_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_SUBDINFO
- subdevice info ioctl
-
- arg:
- pointer to array of subdevice info structures
-
- reads:
- none
-
- writes:
- array of subdevice info structures at arg
-
-*/
+ * COMEDI_SUBDINFO ioctl
+ * subdevices info
+ *
+ * arg:
+ * pointer to array of comedi_subdinfo structures
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * array of comedi_subdinfo structures
+ */
static int do_subdinfo_ioctl(struct comedi_device *dev,
struct comedi_subdinfo __user *arg, void *file)
{
@@ -944,19 +971,19 @@ static int do_subdinfo_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_CHANINFO
- subdevice info ioctl
-
- arg:
- pointer to chaninfo structure
-
- reads:
- chaninfo structure at arg
-
- writes:
- arrays at elements of chaninfo structure
-
-*/
+ * COMEDI_CHANINFO ioctl
+ * subdevice channel info
+ *
+ * arg:
+ * pointer to comedi_chaninfo structure
+ *
+ * reads:
+ * comedi_chaninfo structure
+ *
+ * writes:
+ * array of maxdata values to chaninfo->maxdata_list if requested
+ * array of range table lengths to chaninfo->range_table_list if requested
+ */
static int do_chaninfo_ioctl(struct comedi_device *dev,
struct comedi_chaninfo __user *arg)
{
@@ -1004,20 +1031,19 @@ static int do_chaninfo_ioctl(struct comedi_device *dev,
return 0;
}
- /*
- COMEDI_BUFINFO
- buffer information ioctl
-
- arg:
- pointer to bufinfo structure
-
- reads:
- bufinfo at arg
-
- writes:
- modified bufinfo at arg
-
- */
+/*
+ * COMEDI_BUFINFO ioctl
+ * buffer information
+ *
+ * arg:
+ * pointer to comedi_bufinfo structure
+ *
+ * reads:
+ * comedi_bufinfo structure
+ *
+ * writes:
+ * modified comedi_bufinfo structure
+ */
static int do_bufinfo_ioctl(struct comedi_device *dev,
struct comedi_bufinfo __user *arg, void *file)
{
@@ -1135,8 +1161,10 @@ static int check_insn_config_length(struct comedi_insn *insn,
if (insn->n == 6)
return 0;
break;
- /* by default we allow the insn since we don't have checks for
- * all possible cases yet */
+ /*
+ * by default we allow the insn since we don't have checks for
+ * all possible cases yet
+ */
default:
pr_warn("No check for data length of config insn id %i is implemented\n",
data[0]);
@@ -1287,9 +1315,11 @@ static int parse_insn(struct comedi_device *dev, struct comedi_insn *insn,
if (insn->n != 2) {
ret = -EINVAL;
} else {
- /* Most drivers ignore the base channel in
+ /*
+ * Most drivers ignore the base channel in
* insn->chanspec. Fix this here if
- * the subdevice has <= 32 channels. */
+ * the subdevice has <= 32 channels.
+ */
unsigned int orig_mask = data[0];
unsigned int shift = 0;
@@ -1326,19 +1356,19 @@ out:
}
/*
- * COMEDI_INSNLIST
- * synchronous instructions
+ * COMEDI_INSNLIST ioctl
+ * synchronous instruction list
*
- * arg:
- * pointer to sync cmd structure
+ * arg:
+ * pointer to comedi_insnlist structure
*
- * reads:
- * sync cmd struct at arg
- * instruction list
- * data (for writes)
+ * reads:
+ * comedi_insnlist structure
+ * array of comedi_insn structures from insnlist->insns pointer
+ * data (for writes) from insns[].data pointers
*
- * writes:
- * data (for reads)
+ * writes:
+ * data (for reads) to insns[].data pointers
*/
/* arbitrary limits */
#define MAX_SAMPLES 256
@@ -1415,18 +1445,18 @@ error:
}
/*
- * COMEDI_INSN
- * synchronous instructions
+ * COMEDI_INSN ioctl
+ * synchronous instruction
*
- * arg:
- * pointer to insn
+ * arg:
+ * pointer to comedi_insn structure
*
- * reads:
- * struct comedi_insn struct at arg
- * data (for writes)
+ * reads:
+ * comedi_insn structure
+ * data (for writes) from insn->data pointer
*
- * writes:
- * data (for reads)
+ * writes:
+ * data (for reads) to insn->data pointer
*/
static int do_insn_ioctl(struct comedi_device *dev,
struct comedi_insn __user *arg, void *file)
@@ -1558,6 +1588,20 @@ static int __comedi_get_user_chanlist(struct comedi_device *dev,
return 0;
}
+/*
+ * COMEDI_CMD ioctl
+ * asynchronous acquisition command set-up
+ *
+ * arg:
+ * pointer to comedi_cmd structure
+ *
+ * reads:
+ * comedi_cmd structure
+ * channel/range list from cmd->chanlist pointer
+ *
+ * writes:
+ * possibly modified comedi_cmd structure (when -EAGAIN returned)
+ */
static int do_cmd_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
@@ -1634,10 +1678,13 @@ static int do_cmd_ioctl(struct comedi_device *dev,
if (async->cmd.flags & CMDF_WAKE_EOS)
async->cb_mask |= COMEDI_CB_EOS;
- comedi_set_subdevice_runflags(s, SRF_ERROR | SRF_RUNNING, SRF_RUNNING);
+ comedi_set_subdevice_runflags(s, COMEDI_SRF_BUSY_MASK,
+ COMEDI_SRF_RUNNING);
- /* set s->busy _after_ setting SRF_RUNNING flag to avoid race with
- * comedi_read() or comedi_write() */
+ /*
+ * Set s->busy _after_ setting COMEDI_SRF_RUNNING flag to avoid
+ * race with comedi_read() or comedi_write().
+ */
s->busy = file;
ret = s->do_cmd(dev, s);
if (ret == 0)
@@ -1650,20 +1697,19 @@ cleanup:
}
/*
- COMEDI_CMDTEST
- command testing ioctl
-
- arg:
- pointer to cmd structure
-
- reads:
- cmd structure at arg
- channel/range list
-
- writes:
- modified cmd structure at arg
-
-*/
+ * COMEDI_CMDTEST ioctl
+ * asynchronous aquisition command testing
+ *
+ * arg:
+ * pointer to comedi_cmd structure
+ *
+ * reads:
+ * comedi_cmd structure
+ * channel/range list from cmd->chanlist pointer
+ *
+ * writes:
+ * possibly modified comedi_cmd structure
+ */
static int do_cmdtest_ioctl(struct comedi_device *dev,
struct comedi_cmd __user *arg, void *file)
{
@@ -1706,20 +1752,18 @@ static int do_cmdtest_ioctl(struct comedi_device *dev,
}
/*
- COMEDI_LOCK
- lock subdevice
-
- arg:
- subdevice number
-
- reads:
- none
-
- writes:
- none
-
-*/
-
+ * COMEDI_LOCK ioctl
+ * lock subdevice
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1742,21 +1786,18 @@ static int do_lock_ioctl(struct comedi_device *dev, unsigned long arg,
}
/*
- COMEDI_UNLOCK
- unlock subdevice
-
- arg:
- subdevice number
-
- reads:
- none
-
- writes:
- none
-
- This function isn't protected by the semaphore, since
- we already own the lock.
-*/
+ * COMEDI_UNLOCK ioctl
+ * unlock subdevice
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1779,19 +1820,18 @@ static int do_unlock_ioctl(struct comedi_device *dev, unsigned long arg,
}
/*
- COMEDI_CANCEL
- cancel acquisition ioctl
-
- arg:
- subdevice number
-
- reads:
- nothing
-
- writes:
- nothing
-
-*/
+ * COMEDI_CANCEL ioctl
+ * cancel asynchronous acquisition
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1813,19 +1853,18 @@ static int do_cancel_ioctl(struct comedi_device *dev, unsigned long arg,
}
/*
- COMEDI_POLL ioctl
- instructs driver to synchronize buffers
-
- arg:
- subdevice number
-
- reads:
- nothing
-
- writes:
- nothing
-
-*/
+ * COMEDI_POLL ioctl
+ * instructs driver to synchronize buffers
+ *
+ * arg:
+ * subdevice number
+ *
+ * reads:
+ * nothing
+ *
+ * writes:
+ * nothing
+ */
static int do_poll_ioctl(struct comedi_device *dev, unsigned long arg,
void *file)
{
@@ -1941,8 +1980,10 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&dev->mutex);
- /* Device config is special, because it must work on
- * an unconfigured device. */
+ /*
+ * Device config is special, because it must work on
+ * an unconfigured device.
+ */
if (cmd == COMEDI_DEVCONFIG) {
if (minor >= COMEDI_NUM_BOARD_MINORS) {
/* Device config not appropriate on non-board minors. */
@@ -1954,8 +1995,10 @@ static long comedi_unlocked_ioctl(struct file *file, unsigned int cmd,
if (rc == 0) {
if (arg == 0 &&
dev->minor >= comedi_num_legacy_minors) {
- /* Successfully unconfigured a dynamically
- * allocated device. Try and remove it. */
+ /*
+ * Successfully unconfigured a dynamically
+ * allocated device. Try and remove it.
+ */
if (comedi_clear_board_dev(dev)) {
mutex_unlock(&dev->mutex);
comedi_free_board_dev(dev);
@@ -2581,6 +2624,17 @@ static const struct file_operations comedi_fops = {
.llseek = noop_llseek,
};
+/**
+ * comedi_event - handle events for asynchronous comedi command
+ * @dev: comedi_device struct
+ * @s: comedi_subdevice struct associated with dev
+ * Context: interrupt (usually), s->spin_lock spin-lock not held
+ *
+ * If an asynchronous comedi command is active on the subdevice, process
+ * any COMEDI_CB_... event flags that have been set, usually by an
+ * interrupt handler. These may change the run state of the asynchronous
+ * command, wake a task, and/or send a SIGIO signal.
+ */
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct comedi_async *async = s->async;
@@ -2591,18 +2645,21 @@ void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s)
return;
if (s->async->events & COMEDI_CB_CANCEL_MASK)
- runflags_mask |= SRF_RUNNING;
+ runflags_mask |= COMEDI_SRF_RUNNING;
/*
* Remember if an error event has occurred, so an error
* can be returned the next time the user does a read().
*/
if (s->async->events & COMEDI_CB_ERROR_MASK) {
- runflags_mask |= SRF_ERROR;
- runflags |= SRF_ERROR;
+ runflags_mask |= COMEDI_SRF_ERROR;
+ runflags |= COMEDI_SRF_ERROR;
}
if (runflags_mask) {
- /*sets SRF_ERROR and SRF_RUNNING together atomically */
+ /*
+ * Sets COMEDI_SRF_ERROR and COMEDI_SRF_RUNNING together
+ * atomically.
+ */
comedi_set_subdevice_runflags(s, runflags_mask, runflags);
}
diff --git a/drivers/staging/comedi/comedi_pcmcia.c b/drivers/staging/comedi/comedi_pcmcia.c
index 0529bae8e5ac..7e784399a16f 100644
--- a/drivers/staging/comedi/comedi_pcmcia.c
+++ b/drivers/staging/comedi/comedi_pcmcia.c
@@ -19,10 +19,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
-#include "comedidev.h"
+#include "comedi_pcmcia.h"
/**
* comedi_to_pcmcia_dev() - comedi_device pointer to pcmcia_device pointer.
diff --git a/drivers/staging/comedi/comedi_pcmcia.h b/drivers/staging/comedi/comedi_pcmcia.h
new file mode 100644
index 000000000000..5d3db2b9b4a1
--- /dev/null
+++ b/drivers/staging/comedi/comedi_pcmcia.h
@@ -0,0 +1,55 @@
+/*
+ * comedi_pcmcia.h
+ * header file for Comedi PCMCIA drivers
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _COMEDI_PCMCIA_H
+#define _COMEDI_PCMCIA_H
+
+#include <pcmcia/cistpl.h>
+#include <pcmcia/ds.h>
+
+#include "comedidev.h"
+
+struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *);
+
+int comedi_pcmcia_enable(struct comedi_device *,
+ int (*conf_check)(struct pcmcia_device *, void *));
+void comedi_pcmcia_disable(struct comedi_device *);
+
+int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *);
+void comedi_pcmcia_auto_unconfig(struct pcmcia_device *);
+
+int comedi_pcmcia_driver_register(struct comedi_driver *,
+ struct pcmcia_driver *);
+void comedi_pcmcia_driver_unregister(struct comedi_driver *,
+ struct pcmcia_driver *);
+
+/**
+ * module_comedi_pcmcia_driver() - Helper macro for registering a comedi PCMCIA driver
+ * @__comedi_driver: comedi_driver struct
+ * @__pcmcia_driver: pcmcia_driver struct
+ *
+ * Helper macro for comedi PCMCIA drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_pcmcia_driver(__comedi_driver, __pcmcia_driver) \
+ module_driver(__comedi_driver, comedi_pcmcia_driver_register, \
+ comedi_pcmcia_driver_unregister, &(__pcmcia_driver))
+
+#endif /* _COMEDI_PCMCIA_H */
diff --git a/drivers/staging/comedi/comedi_usb.c b/drivers/staging/comedi/comedi_usb.c
index 0b862a64c049..68b75e8feec0 100644
--- a/drivers/staging/comedi/comedi_usb.c
+++ b/drivers/staging/comedi/comedi_usb.c
@@ -17,9 +17,8 @@
*/
#include <linux/module.h>
-#include <linux/usb.h>
-#include "comedidev.h"
+#include "comedi_usb.h"
/**
* comedi_to_usb_interface() - comedi_device pointer to usb_interface pointer.
diff --git a/drivers/staging/comedi/comedi_usb.h b/drivers/staging/comedi/comedi_usb.h
new file mode 100644
index 000000000000..721128bece3c
--- /dev/null
+++ b/drivers/staging/comedi/comedi_usb.h
@@ -0,0 +1,50 @@
+/*
+ * comedi_usb.h
+ * header file for USB Comedi drivers
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _COMEDI_USB_H
+#define _COMEDI_USB_H
+
+#include <linux/usb.h>
+
+#include "comedidev.h"
+
+struct usb_interface *comedi_to_usb_interface(struct comedi_device *);
+struct usb_device *comedi_to_usb_dev(struct comedi_device *);
+
+int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *,
+ unsigned long context);
+void comedi_usb_auto_unconfig(struct usb_interface *);
+
+int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
+void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
+
+/**
+ * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
+ * @__comedi_driver: comedi_driver struct
+ * @__usb_driver: usb_driver struct
+ *
+ * Helper macro for comedi USB drivers which do not do anything special
+ * in module init/exit. This eliminates a lot of boilerplate. Each
+ * module may only use this macro once, and calling it replaces
+ * module_init() and module_exit()
+ */
+#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
+ module_driver(__comedi_driver, comedi_usb_driver_register, \
+ comedi_usb_driver_unregister, &(__usb_driver))
+
+#endif /* _COMEDI_USB_H */
diff --git a/drivers/staging/comedi/comedidev.h b/drivers/staging/comedi/comedidev.h
index 77be191988ca..e138eb0dc374 100644
--- a/drivers/staging/comedi/comedidev.h
+++ b/drivers/staging/comedi/comedidev.h
@@ -299,34 +299,25 @@ struct comedi_device {
void comedi_event(struct comedi_device *dev, struct comedi_subdevice *s);
-/* we can expand the number of bits used to encode devices/subdevices into
- the minor number soon, after more distros support > 8 bit minor numbers
- (like after Debian Etch gets released) */
-enum comedi_minor_bits {
- COMEDI_DEVICE_MINOR_MASK = 0xf,
- COMEDI_SUBDEVICE_MINOR_MASK = 0xf0
-};
-
-static const unsigned COMEDI_SUBDEVICE_MINOR_SHIFT = 4;
-static const unsigned COMEDI_SUBDEVICE_MINOR_OFFSET = 1;
-
struct comedi_device *comedi_dev_get_from_minor(unsigned minor);
int comedi_dev_put(struct comedi_device *dev);
-void init_polling(void);
-void cleanup_polling(void);
-void start_polling(struct comedi_device *);
-void stop_polling(struct comedi_device *);
-
-/* subdevice runflags */
-enum subdevice_runflags {
- SRF_RT = 0x00000002,
- /* indicates an COMEDI_CB_ERROR event has occurred since the last
- * command was started */
- SRF_ERROR = 0x00000004,
- SRF_RUNNING = 0x08000000,
- SRF_FREE_SPRIV = 0x80000000, /* free s->private on detach */
-};
+/**
+ * comedi_subdevice "runflags"
+ * @COMEDI_SRF_RT: DEPRECATED: command is running real-time
+ * @COMEDI_SRF_ERROR: indicates an COMEDI_CB_ERROR event has occurred
+ * since the last command was started
+ * @COMEDI_SRF_RUNNING: command is running
+ * @COMEDI_SRF_FREE_SPRIV: free s->private on detach
+ *
+ * @COMEDI_SRF_BUSY_MASK: runflags that indicate the subdevice is "busy"
+ */
+#define COMEDI_SRF_RT BIT(1)
+#define COMEDI_SRF_ERROR BIT(2)
+#define COMEDI_SRF_RUNNING BIT(27)
+#define COMEDI_SRF_FREE_SPRIV BIT(31)
+
+#define COMEDI_SRF_BUSY_MASK (COMEDI_SRF_ERROR | COMEDI_SRF_RUNNING)
bool comedi_is_subdevice_running(struct comedi_subdevice *s);
@@ -605,66 +596,4 @@ void comedi_pci_driver_unregister(struct comedi_driver *, struct pci_driver *);
module_driver(__comedi_driver, comedi_pci_driver_register, \
comedi_pci_driver_unregister, &(__pci_driver))
-/* comedi_pcmcia.c - comedi PCMCIA driver specific functions */
-
-struct pcmcia_driver;
-struct pcmcia_device;
-
-struct pcmcia_device *comedi_to_pcmcia_dev(struct comedi_device *);
-
-int comedi_pcmcia_enable(struct comedi_device *,
- int (*conf_check)(struct pcmcia_device *, void *));
-void comedi_pcmcia_disable(struct comedi_device *);
-
-int comedi_pcmcia_auto_config(struct pcmcia_device *, struct comedi_driver *);
-void comedi_pcmcia_auto_unconfig(struct pcmcia_device *);
-
-int comedi_pcmcia_driver_register(struct comedi_driver *,
- struct pcmcia_driver *);
-void comedi_pcmcia_driver_unregister(struct comedi_driver *,
- struct pcmcia_driver *);
-
-/**
- * module_comedi_pcmcia_driver() - Helper macro for registering a comedi PCMCIA driver
- * @__comedi_driver: comedi_driver struct
- * @__pcmcia_driver: pcmcia_driver struct
- *
- * Helper macro for comedi PCMCIA drivers which do not do anything special
- * in module init/exit. This eliminates a lot of boilerplate. Each
- * module may only use this macro once, and calling it replaces
- * module_init() and module_exit()
- */
-#define module_comedi_pcmcia_driver(__comedi_driver, __pcmcia_driver) \
- module_driver(__comedi_driver, comedi_pcmcia_driver_register, \
- comedi_pcmcia_driver_unregister, &(__pcmcia_driver))
-
-/* comedi_usb.c - comedi USB driver specific functions */
-
-struct usb_driver;
-struct usb_interface;
-
-struct usb_interface *comedi_to_usb_interface(struct comedi_device *);
-struct usb_device *comedi_to_usb_dev(struct comedi_device *);
-
-int comedi_usb_auto_config(struct usb_interface *, struct comedi_driver *,
- unsigned long context);
-void comedi_usb_auto_unconfig(struct usb_interface *);
-
-int comedi_usb_driver_register(struct comedi_driver *, struct usb_driver *);
-void comedi_usb_driver_unregister(struct comedi_driver *, struct usb_driver *);
-
-/**
- * module_comedi_usb_driver() - Helper macro for registering a comedi USB driver
- * @__comedi_driver: comedi_driver struct
- * @__usb_driver: usb_driver struct
- *
- * Helper macro for comedi USB drivers which do not do anything special
- * in module init/exit. This eliminates a lot of boilerplate. Each
- * module may only use this macro once, and calling it replaces
- * module_init() and module_exit()
- */
-#define module_comedi_usb_driver(__comedi_driver, __usb_driver) \
- module_driver(__comedi_driver, comedi_usb_driver_register, \
- comedi_usb_driver_unregister, &(__usb_driver))
-
#endif /* _COMEDIDEV_H */
diff --git a/drivers/staging/comedi/drivers.c b/drivers/staging/comedi/drivers.c
index 61802d7947ae..f32e71438948 100644
--- a/drivers/staging/comedi/drivers.c
+++ b/drivers/staging/comedi/drivers.c
@@ -125,7 +125,7 @@ static void comedi_device_detach_cleanup(struct comedi_device *dev)
if (dev->subdevices) {
for (i = 0; i < dev->n_subdevices; i++) {
s = &dev->subdevices[i];
- if (s->runflags & SRF_FREE_SPRIV)
+ if (s->runflags & COMEDI_SRF_FREE_SPRIV)
kfree(s->private);
comedi_free_subdevice_minor(s);
if (s->async) {
diff --git a/drivers/staging/comedi/drivers/8253.h b/drivers/staging/comedi/drivers/8253.h
index 9f4c1411719d..51b9c8d279c0 100644
--- a/drivers/staging/comedi/drivers/8253.h
+++ b/drivers/staging/comedi/drivers/8253.h
@@ -1,20 +1,20 @@
/*
- comedi/drivers/8253.h
- Header file for 8253
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 2000 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * comedi/drivers/8253.h
+ * Header file for 8253
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 2000 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#ifndef _8253_H
#define _8253_H
@@ -44,9 +44,11 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
unsigned int start;
unsigned int ns_low, ns_high;
static const unsigned int max_count = 0x10000;
- /* exit early if everything is already correct (this can save time
+ /*
+ * exit early if everything is already correct (this can save time
* since this function may be called repeatedly during command tests
- * and execution) */
+ * and execution)
+ */
div1 = *d1 ? *d1 : max_count;
div2 = *d2 ? *d2 : max_count;
divider = div1 * div2;
@@ -114,13 +116,14 @@ static inline void i8253_cascade_ns_to_timer(int i8253_osc_base,
}
*nanosec = div1 * div2 * i8253_osc_base;
- /* masking is done since counter maps zero to 0x10000 */
+ /* masking is done since counter maps zero to 0x10000 */
*d1 = div1 & 0xffff;
*d2 = div2 & 0xffff;
}
#ifndef CMDTEST
-/* i8254_load programs 8254 counter chip. It should also work for the 8253.
+/*
+ * i8254_load programs 8254 counter chip. It should also work for the 8253.
* base_address is the lowest io address
* for the chip (the address of counter 0).
* counter_number is the counter you want to load (0,1 or 2)
@@ -158,12 +161,12 @@ static inline int i8254_load(unsigned long base_address, unsigned int regshift,
return -1;
byte = counter_number << 6;
- byte |= 0x30; /* load low then high byte */
- byte |= (mode << 1); /* set counter mode */
+ byte |= 0x30; /* load low then high byte */
+ byte |= (mode << 1); /* set counter mode */
outb(byte, base_address + (i8254_control_reg << regshift));
- byte = count & 0xff; /* lsb of counter value */
+ byte = count & 0xff; /* lsb of counter value */
outb(byte, base_address + (counter_number << regshift));
- byte = (count >> 8) & 0xff; /* msb of counter value */
+ byte = (count >> 8) & 0xff; /* msb of counter value */
outb(byte, base_address + (counter_number << regshift));
return 0;
@@ -187,18 +190,18 @@ static inline int i8254_mm_load(void __iomem *base_address,
return -1;
byte = counter_number << 6;
- byte |= 0x30; /* load low then high byte */
- byte |= (mode << 1); /* set counter mode */
+ byte |= 0x30; /* load low then high byte */
+ byte |= (mode << 1); /* set counter mode */
writeb(byte, base_address + (i8254_control_reg << regshift));
- byte = count & 0xff; /* lsb of counter value */
+ byte = count & 0xff; /* lsb of counter value */
writeb(byte, base_address + (counter_number << regshift));
- byte = (count >> 8) & 0xff; /* msb of counter value */
+ byte = (count >> 8) & 0xff; /* msb of counter value */
writeb(byte, base_address + (counter_number << regshift));
return 0;
}
-/* Returns 16 bit counter value, should work for 8253 also.*/
+/* Returns 16 bit counter value, should work for 8253 also. */
static inline int i8254_read(unsigned long base_address, unsigned int regshift,
unsigned int counter_number)
{
@@ -208,13 +211,13 @@ static inline int i8254_read(unsigned long base_address, unsigned int regshift,
if (counter_number > 2)
return -1;
- /* latch counter */
+ /* latch counter */
byte = counter_number << 6;
outb(byte, base_address + (i8254_control_reg << regshift));
- /* read lsb */
+ /* read lsb */
ret = inb(base_address + (counter_number << regshift));
- /* read msb */
+ /* read msb */
ret += inb(base_address + (counter_number << regshift)) << 8;
return ret;
@@ -230,13 +233,13 @@ static inline int i8254_mm_read(void __iomem *base_address,
if (counter_number > 2)
return -1;
- /* latch counter */
+ /* latch counter */
byte = counter_number << 6;
writeb(byte, base_address + (i8254_control_reg << regshift));
- /* read lsb */
+ /* read lsb */
ret = readb(base_address + (counter_number << regshift));
- /* read msb */
+ /* read msb */
ret += readb(base_address + (counter_number << regshift)) << 8;
return ret;
@@ -252,9 +255,9 @@ static inline void i8254_write(unsigned long base_address,
if (counter_number > 2)
return;
- byte = count & 0xff; /* lsb of counter value */
+ byte = count & 0xff; /* lsb of counter value */
outb(byte, base_address + (counter_number << regshift));
- byte = (count >> 8) & 0xff; /* msb of counter value */
+ byte = (count >> 8) & 0xff; /* msb of counter value */
outb(byte, base_address + (counter_number << regshift));
}
@@ -268,13 +271,14 @@ static inline void i8254_mm_write(void __iomem *base_address,
if (counter_number > 2)
return;
- byte = count & 0xff; /* lsb of counter value */
+ byte = count & 0xff; /* lsb of counter value */
writeb(byte, base_address + (counter_number << regshift));
- byte = (count >> 8) & 0xff; /* msb of counter value */
+ byte = (count >> 8) & 0xff; /* msb of counter value */
writeb(byte, base_address + (counter_number << regshift));
}
-/* Set counter mode, should work for 8253 also.
+/*
+ * Set counter mode, should work for 8253 also.
* Note: the 'mode' value is different to that for i8254_load() and comes
* from the INSN_CONFIG_8254_SET_MODE command:
* I8254_MODE0, I8254_MODE1, ..., I8254_MODE5
@@ -293,8 +297,8 @@ static inline int i8254_set_mode(unsigned long base_address,
return -1;
byte = counter_number << 6;
- byte |= 0x30; /* load low then high byte */
- byte |= mode; /* set counter mode and BCD|binary */
+ byte |= 0x30; /* load low then high byte */
+ byte |= mode; /* set counter mode and BCD|binary */
outb(byte, base_address + (i8254_control_reg << regshift));
return 0;
@@ -313,8 +317,8 @@ static inline int i8254_mm_set_mode(void __iomem *base_address,
return -1;
byte = counter_number << 6;
- byte |= 0x30; /* load low then high byte */
- byte |= mode; /* set counter mode and BCD|binary */
+ byte |= 0x30; /* load low then high byte */
+ byte |= mode; /* set counter mode and BCD|binary */
writeb(byte, base_address + (i8254_control_reg << regshift));
return 0;
diff --git a/drivers/staging/comedi/drivers/8255.c b/drivers/staging/comedi/drivers/8255.c
index 34d4d8b5f31e..c2f15de6a547 100644
--- a/drivers/staging/comedi/drivers/8255.c
+++ b/drivers/staging/comedi/drivers/8255.c
@@ -1,76 +1,51 @@
/*
- comedi/drivers/8255.c
- Driver for 8255
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
-/*
-Driver: 8255
-Description: generic 8255 support
-Devices: [standard] 8255 (8255)
-Author: ds
-Status: works
-Updated: Fri, 7 Jun 2002 12:56:45 -0700
-
-The classic in digital I/O. The 8255 appears in Comedi as a single
-digital I/O subdevice with 24 channels. The channel 0 corresponds
-to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
-7. Direction configuration is done in blocks, with channels 0-7,
-8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode
-supported is mode 0.
-
-You should enable compilation this driver if you plan to use a board
-that has an 8255 chip. For multifunction boards, the main driver will
-configure the 8255 subdevice automatically.
-
-This driver also works independently with ISA and PCI cards that
-directly map the 8255 registers to I/O ports, including cards with
-multiple 8255 chips. To configure the driver for such a card, the
-option list should be a list of the I/O port bases for each of the
-8255 chips. For example,
-
- comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
-
-Note that most PCI 8255 boards do NOT work with this driver, and
-need a separate driver as a wrapper. For those that do work, the
-I/O port base address can be found in the output of 'lspci -v'.
-
-*/
+ * comedi/drivers/8255.c
+ * Driver for 8255
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
/*
- This file contains an exported subdevice for driving an 8255.
-
- To use this subdevice as part of another driver, you need to
- set up the subdevice in the attach function of the driver by
- calling:
-
- subdev_8255_init(device, subdevice, io_function, iobase)
-
- device and subdevice are pointers to the device and subdevice
- structures. io_function will be called to provide the
- low-level input/output to the device, i.e., actual register
- access. io_function will be called with the value of iobase
- as the last parameter. If the 8255 device is mapped as 4
- consecutive I/O ports, you can use NULL for io_function
- and the I/O port base for iobase, and an internal function will
- handle the register access.
-
- In addition, if the main driver handles interrupts, you can
- enable commands on the subdevice by calling subdev_8255_init_irq()
- instead. Then, when you get an interrupt that is likely to be
- from the 8255, you should call subdev_8255_interrupt(), which
- will copy the latched value to a Comedi buffer.
+ * Driver: 8255
+ * Description: generic 8255 support
+ * Devices: [standard] 8255 (8255)
+ * Author: ds
+ * Status: works
+ * Updated: Fri, 7 Jun 2002 12:56:45 -0700
+ *
+ * The classic in digital I/O. The 8255 appears in Comedi as a single
+ * digital I/O subdevice with 24 channels. The channel 0 corresponds
+ * to the 8255's port A, bit 0; channel 23 corresponds to port C, bit
+ * 7. Direction configuration is done in blocks, with channels 0-7,
+ * 8-15, 16-19, and 20-23 making up the 4 blocks. The only 8255 mode
+ * supported is mode 0.
+ *
+ * You should enable compilation this driver if you plan to use a board
+ * that has an 8255 chip. For multifunction boards, the main driver will
+ * configure the 8255 subdevice automatically.
+ *
+ * This driver also works independently with ISA and PCI cards that
+ * directly map the 8255 registers to I/O ports, including cards with
+ * multiple 8255 chips. To configure the driver for such a card, the
+ * option list should be a list of the I/O port bases for each of the
+ * 8255 chips. For example,
+ *
+ * comedi_config /dev/comedi0 8255 0x200,0x204,0x208,0x20c
+ *
+ * Note that most PCI 8255 boards do NOT work with this driver, and
+ * need a separate driver as a wrapper. For those that do work, the
+ * I/O port base address can be found in the output of 'lspci -v'.
*/
#include <linux/module.h>
@@ -218,6 +193,33 @@ static int __subdev_8255_init(struct comedi_device *dev,
return 0;
}
+/**
+ * subdev_8255_init - initialize DIO subdevice for driving I/O mapped 8255
+ * @dev: comedi device owning subdevice
+ * @s: comedi subdevice to initialize
+ * @io: (optional) register I/O call-back function
+ * @regbase: offset of 8255 registers from dev->iobase, or call-back context
+ *
+ * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
+ *
+ * If the optional I/O call-back function is provided, its prototype is of
+ * the following form:
+ *
+ * int my_8255_callback(struct comedi_device *dev,
+ * struct comedi_subdevice *s, int dir, int port,
+ * int data, unsigned long regbase);
+ *
+ * where 'dev', 's', and 'regbase' match the values passed to this function,
+ * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir'
+ * is the direction (0 for read, 1 for write) and 'data' is the value to be
+ * written. It should return 0 if writing or the value read if reading.
+ *
+ * If the optional I/O call-back function is not provided, an internal
+ * call-back function is used which uses consecutive I/O port addresses
+ * starting at dev->iobase + regbase.
+ *
+ * Return: -ENOMEM if failed to allocate memory, zero on success.
+ */
int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
int (*io)(struct comedi_device *,
int, int, int, unsigned long),
@@ -227,6 +229,33 @@ int subdev_8255_init(struct comedi_device *dev, struct comedi_subdevice *s,
}
EXPORT_SYMBOL_GPL(subdev_8255_init);
+/**
+ * subdev_8255_mm_init - initialize DIO subdevice for driving mmio-mapped 8255
+ * @dev: comedi device owning subdevice
+ * @s: comedi subdevice to initialize
+ * @io: (optional) register I/O call-back function
+ * @regbase: offset of 8255 registers from dev->mmio, or call-back context
+ *
+ * Initializes a comedi subdevice as a DIO subdevice driving an 8255 chip.
+ *
+ * If the optional I/O call-back function is provided, its prototype is of
+ * the following form:
+ *
+ * int my_8255_callback(struct comedi_device *dev,
+ * struct comedi_subdevice *s, int dir, int port,
+ * int data, unsigned long regbase);
+ *
+ * where 'dev', 's', and 'regbase' match the values passed to this function,
+ * 'port' is the 8255 port number 0 to 3 (including the control port), 'dir'
+ * is the direction (0 for read, 1 for write) and 'data' is the value to be
+ * written. It should return 0 if writing or the value read if reading.
+ *
+ * If the optional I/O call-back function is not provided, an internal
+ * call-back function is used which uses consecutive MMIO virtual addresses
+ * starting at dev->mmio + regbase.
+ *
+ * Return: -ENOMEM if failed to allocate memory, zero on success.
+ */
int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
int (*io)(struct comedi_device *,
int, int, int, unsigned long),
@@ -235,10 +264,9 @@ int subdev_8255_mm_init(struct comedi_device *dev, struct comedi_subdevice *s,
return __subdev_8255_init(dev, s, io, regbase, true);
}
EXPORT_SYMBOL_GPL(subdev_8255_mm_init);
-/*
-
- Start of the 8255 standalone device
+/*
+ * Start of the 8255 standalone device
*/
static int dev_8255_attach(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/8255.h b/drivers/staging/comedi/drivers/8255.h
index 5985c8e0330f..934b940ebd3c 100644
--- a/drivers/staging/comedi/drivers/8255.h
+++ b/drivers/staging/comedi/drivers/8255.h
@@ -1,20 +1,20 @@
/*
- module/8255.h
- Header file for 8255
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1998 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * module/8255.h
+ * Header file for 8255
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1998 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#ifndef _8255_H
#define _8255_H
diff --git a/drivers/staging/comedi/drivers/8255_pci.c b/drivers/staging/comedi/drivers/8255_pci.c
index 8b9589828855..984764211a2d 100644
--- a/drivers/staging/comedi/drivers/8255_pci.c
+++ b/drivers/staging/comedi/drivers/8255_pci.c
@@ -22,33 +22,44 @@
*/
/*
-Driver: 8255_pci
-Description: Generic PCI based 8255 Digital I/O boards
-Devices: (ADLink) PCI-7224 [adl_pci-7224] - 24 channels
- (ADLink) PCI-7248 [adl_pci-7248] - 48 channels
- (ADLink) PCI-7296 [adl_pci-7296] - 96 channels
- (Measurement Computing) PCI-DIO24 [cb_pci-dio24] - 24 channels
- (Measurement Computing) PCI-DIO24H [cb_pci-dio24h] - 24 channels
- (Measurement Computing) PCI-DIO48H [cb_pci-dio48h] - 48 channels
- (Measurement Computing) PCI-DIO96H [cb_pci-dio96h] - 96 channels
- (National Instruments) PCI-DIO-96 [ni_pci-dio-96] - 96 channels
- (National Instruments) PCI-DIO-96B [ni_pci-dio-96b] - 96 channels
- (National Instruments) PXI-6508 [ni_pxi-6508] - 96 channels
- (National Instruments) PCI-6503 [ni_pci-6503] - 24 channels
- (National Instruments) PCI-6503B [ni_pci-6503b] - 24 channels
- (National Instruments) PCI-6503X [ni_pci-6503x] - 24 channels
- (National Instruments) PXI-6503 [ni_pxi-6503] - 24 channels
-Author: H Hartley Sweeten <hsweeten@visionengravers.com>
-Updated: Wed, 12 Sep 2012 11:52:01 -0700
-Status: untested
-
-Some of these boards also have an 8254 programmable timer/counter
-chip. This chip is not currently supported by this driver.
-
-Interrupt support for these boards is also not currently supported.
-
-Configuration Options: not applicable, uses PCI auto config
-*/
+ * Driver: 8255_pci
+ * Description: Generic PCI based 8255 Digital I/O boards
+ * Devices: [ADLink] PCI-7224 (adl_pci-7224), PCI-7248 (adl_pci-7248),
+ * PCI-7296 (adl_pci-7296),
+ * [Measurement Computing] PCI-DIO24 (cb_pci-dio24),
+ * PCI-DIO24H (cb_pci-dio24h), PCI-DIO48H (cb_pci-dio48h),
+ * PCI-DIO96H (cb_pci-dio96h),
+ * [National Instruments] PCI-DIO-96 (ni_pci-dio-96),
+ * PCI-DIO-96B (ni_pci-dio-96b), PXI-6508 (ni_pxi-6508),
+ * PCI-6503 (ni_pci-6503), PCI-6503B (ni_pci-6503b),
+ * PCI-6503X (ni_pci-6503x), PXI-6503 (ni_pxi-6503)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Wed, 12 Sep 2012 11:52:01 -0700
+ * Status: untested
+ *
+ * These boards have one or more 8255 digital I/O chips, each of which
+ * is supported as a separate 24-channel DIO subdevice.
+ *
+ * Boards with 24 DIO channels (1 DIO subdevice):
+ *
+ * PCI-7224, PCI-DIO24, PCI-DIO24H, PCI-6503, PCI-6503B, PCI-6503X,
+ * PXI-6503
+ *
+ * Boards with 48 DIO channels (2 DIO subdevices):
+ *
+ * PCI-7248, PCI-DIO48H
+ *
+ * Boards with 96 DIO channels (4 DIO subdevices):
+ *
+ * PCI-7296, PCI-DIO96H, PCI-DIO-96, PCI-DIO-96B, PXI-6508
+ *
+ * Some of these boards also have an 8254 programmable timer/counter
+ * chip. This chip is not currently supported by this driver.
+ *
+ * Interrupt support for these boards is also not currently supported.
+ *
+ * Configuration Options: not applicable, uses PCI auto config.
+ */
#include <linux/module.h>
#include <linux/pci.h>
diff --git a/drivers/staging/comedi/drivers/Makefile b/drivers/staging/comedi/drivers/Makefile
index 84fdf20ca986..7d1fbd53a8ab 100644
--- a/drivers/staging/comedi/drivers/Makefile
+++ b/drivers/staging/comedi/drivers/Makefile
@@ -3,6 +3,7 @@
ccflags-$(CONFIG_COMEDI_DEBUG) := -DDEBUG
# Comedi "helper" modules
+obj-$(CONFIG_COMEDI_ISADMA) += comedi_isadma.o
# Comedi misc drivers
obj-$(CONFIG_COMEDI_BOND) += comedi_bond.o
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
deleted file mode 100644
index bfa9228c833f..000000000000
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci1500.c
+++ /dev/null
@@ -1,2365 +0,0 @@
-/*
- * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
- *
- * ADDI-DATA GmbH
- * Dieselstrasse 3
- * D-77833 Ottersweier
- * Tel: +19(0)7223/9493-0
- * Fax: +49(0)7223/9493-92
- * http://www.addi-data.com
- * info@addi-data.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.
- *
- */
-
-/* Card Specific information */
-#define APCI1500_ADDRESS_RANGE 4
-
-/* DIGITAL INPUT-OUTPUT DEFINE */
-
-#define APCI1500_DIGITAL_OP 2
-#define APCI1500_DIGITAL_IP 0
-#define APCI1500_AND 2
-#define APCI1500_OR 4
-#define APCI1500_OR_PRIORITY 6
-#define APCI1500_CLK_SELECT 0
-#define COUNTER1 0
-#define COUNTER2 1
-#define COUNTER3 2
-#define APCI1500_COUNTER 0x20
-#define APCI1500_TIMER 0
-#define APCI1500_WATCHDOG 0
-#define APCI1500_SINGLE 0
-#define APCI1500_CONTINUOUS 0x80
-#define APCI1500_DISABLE 0
-#define APCI1500_ENABLE 1
-#define APCI1500_SOFTWARE_TRIGGER 0x4
-#define APCI1500_HARDWARE_TRIGGER 0x10
-#define APCI1500_SOFTWARE_GATE 0
-#define APCI1500_HARDWARE_GATE 0x8
-#define START 0
-#define STOP 1
-#define TRIGGER 2
-
-/*
- * Zillog I/O enumeration
- */
-enum {
- APCI1500_Z8536_PORT_C,
- APCI1500_Z8536_PORT_B,
- APCI1500_Z8536_PORT_A,
- APCI1500_Z8536_CONTROL_REGISTER
-};
-
-/*
- * Z8536 CIO Internal Address
- */
-enum {
- APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
- APCI1500_RW_PORT_B_INTERRUPT_CONTROL,
- APCI1500_RW_TIMER_COUNTER_INTERRUPT_VECTOR,
- APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
- APCI1500_RW_PORT_C_DATA_DIRECTION,
- APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
-
- APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- APCI1500_RW_CPT_TMR1_CMD_STATUS,
- APCI1500_RW_CPT_TMR2_CMD_STATUS,
- APCI1500_RW_CPT_TMR3_CMD_STATUS,
- APCI1500_RW_PORT_A_DATA,
- APCI1500_RW_PORT_B_DATA,
- APCI1500_RW_PORT_C_DATA,
-
- APCI1500_R_CPT_TMR1_VALUE_HIGH,
- APCI1500_R_CPT_TMR1_VALUE_LOW,
- APCI1500_R_CPT_TMR2_VALUE_HIGH,
- APCI1500_R_CPT_TMR2_VALUE_LOW,
- APCI1500_R_CPT_TMR3_VALUE_HIGH,
- APCI1500_R_CPT_TMR3_VALUE_LOW,
- APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
- APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
- APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
- APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
- APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
- APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
- APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
- APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
- APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
- APCI1500_R_CURRENT_VECTOR,
-
- APCI1500_RW_PORT_A_SPECIFICATION,
- APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
- APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
- APCI1500_RW_PORT_A_DATA_DIRECTION,
- APCI1500_RW_PORT_A_SPECIAL_IO_CONTROL,
- APCI1500_RW_PORT_A_PATTERN_POLARITY,
- APCI1500_RW_PORT_A_PATTERN_TRANSITION,
- APCI1500_RW_PORT_A_PATTERN_MASK,
-
- APCI1500_RW_PORT_B_SPECIFICATION,
- APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
- APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
- APCI1500_RW_PORT_B_DATA_DIRECTION,
- APCI1500_RW_PORT_B_SPECIAL_IO_CONTROL,
- APCI1500_RW_PORT_B_PATTERN_POLARITY,
- APCI1500_RW_PORT_B_PATTERN_TRANSITION,
- APCI1500_RW_PORT_B_PATTERN_MASK
-};
-
-static int i_TimerCounter1Init;
-static int i_TimerCounter2Init;
-static int i_WatchdogCounter3Init;
-static int i_Event1Status, i_Event2Status;
-static int i_TimerCounterWatchdogInterrupt;
-static int i_Logic, i_CounterLogic;
-static int i_InterruptMask;
-static int i_InputChannel;
-static int i_TimerCounter1Enabled, i_TimerCounter2Enabled,
- i_WatchdogCounter3Enabled;
-
-/*
- * An event can be generated for each port. The first event is related to the
- * first 8 channels (port 1) and the second to the following 6 channels (port 2)
- * An interrupt is generated when one or both events have occurred.
- *
- * data[0] Number of the input port on which the event will take place (1 or 2)
- * data[1] The event logic for port 1 has three possibilities:
- * APCI1500_AND This logic links the inputs with an AND logic.
- * APCI1500_OR This logic links the inputs with a OR logic.
- * APCI1500_OR_PRIORITY This logic links the inputs with a priority OR
- * logic. Input 1 has the highest priority level
- * and input 8 the smallest.
- * For the second port the user has 1 possibility:
- * APCI1500_OR This logic links the inputs with a polarity OR logic
- * data[2] These 8-character word for port1 and 6-character word for port 2
- * give the mask of the event. Each place gives the state of the input
- * channels and can have one of these six characters
- * 0 This input must be on 0
- * 1 This input must be on 1
- * 2 This input reacts to a falling edge
- * 3 This input reacts to a rising edge
- * 4 This input reacts to both edges
- * 5 This input is not used for event
- */
-static int apci1500_di_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_PatternPolarity = 0, i_PatternTransition = 0, i_PatternMask = 0;
- int i_MaxChannel = 0, i_Count = 0, i_EventMask = 0;
- int i_PatternTransitionCount = 0, i_RegValue;
- int i;
-
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Disables the main interrupt on the board */
- outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- if (data[0] == 1) {
- i_MaxChannel = 8;
- } else {
- if (data[0] == 2) {
- i_MaxChannel = 6;
- } else {
- dev_warn(dev->class_dev,
- "The specified port event does not exist\n");
- return -EINVAL;
- }
- }
- switch (data[1]) {
- case 0:
- data[1] = APCI1500_AND;
- break;
- case 1:
- data[1] = APCI1500_OR;
- break;
- case 2:
- data[1] = APCI1500_OR_PRIORITY;
- break;
- default:
- dev_warn(dev->class_dev,
- "The specified interrupt logic does not exist\n");
- return -EINVAL;
- }
-
- i_Logic = data[1];
- for (i_Count = i_MaxChannel, i = 0; i_Count > 0; i_Count--, i++) {
- i_EventMask = data[2 + i];
- switch (i_EventMask) {
- case 0:
- i_PatternMask =
- i_PatternMask | (1 << (i_MaxChannel - i_Count));
- break;
- case 1:
- i_PatternMask =
- i_PatternMask | (1 << (i_MaxChannel - i_Count));
- i_PatternPolarity =
- i_PatternPolarity | (1 << (i_MaxChannel -
- i_Count));
- break;
- case 2:
- i_PatternMask =
- i_PatternMask | (1 << (i_MaxChannel - i_Count));
- i_PatternTransition =
- i_PatternTransition | (1 << (i_MaxChannel -
- i_Count));
- break;
- case 3:
- i_PatternMask =
- i_PatternMask | (1 << (i_MaxChannel - i_Count));
- i_PatternPolarity =
- i_PatternPolarity | (1 << (i_MaxChannel -
- i_Count));
- i_PatternTransition =
- i_PatternTransition | (1 << (i_MaxChannel -
- i_Count));
- break;
- case 4:
- i_PatternTransition =
- i_PatternTransition | (1 << (i_MaxChannel -
- i_Count));
- break;
- case 5:
- break;
- default:
- dev_warn(dev->class_dev,
- "The option indicated in the event mask does not exist\n");
- return -EINVAL;
- }
- }
-
- if (data[0] == 1) {
- /* Test the interrupt logic */
-
- if (data[1] == APCI1500_AND ||
- data[1] == APCI1500_OR ||
- data[1] == APCI1500_OR_PRIORITY) {
- /* Tests if a transition was declared */
- /* for a OR PRIORITY logic */
-
- if (data[1] == APCI1500_OR_PRIORITY
- && i_PatternTransition != 0) {
- dev_warn(dev->class_dev,
- "Transition error on an OR PRIORITY logic\n");
- return -EINVAL;
- }
-
- /* Tests if more than one transition */
- /* was declared for an AND logic */
-
- if (data[1] == APCI1500_AND) {
- for (i_Count = 0; i_Count < 8; i_Count++) {
- i_PatternTransitionCount =
- i_PatternTransitionCount +
- ((i_PatternTransition >>
- i_Count) & 0x1);
-
- }
-
- if (i_PatternTransitionCount > 1) {
- dev_warn(dev->class_dev,
- "Transition error on an AND logic\n");
- return -EINVAL;
- }
- }
-
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable Port A */
- outb(0xF0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the polarity register of port 1 */
- outb(APCI1500_RW_PORT_A_PATTERN_POLARITY,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_PatternPolarity,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the pattern mask register of */
- /* port 1 */
- outb(APCI1500_RW_PORT_A_PATTERN_MASK,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_PatternMask,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the pattern transition register */
- /* of port 1 */
- outb(APCI1500_RW_PORT_A_PATTERN_TRANSITION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_PatternTransition,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification mask */
- /* register of port 1 */
- outb(APCI1500_RW_PORT_A_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification mask */
- /* register of port 1 */
- outb(APCI1500_RW_PORT_A_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Port A new mode */
-
- i_RegValue = (i_RegValue & 0xF9) | data[1] | 0x9;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- i_Event1Status = 1;
-
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Enable Port A */
- outb(0xF4,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- } else {
- dev_warn(dev->class_dev,
- "The choice for interrupt logic does not exist\n");
- return -EINVAL;
- }
- }
-
- /* Test if event setting for port 2 */
-
- if (data[0] == 2) {
- /* Test the event logic */
-
- if (data[1] == APCI1500_OR) {
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable Port B */
- outb(0x74,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the mode specification mask */
- /* register of port B */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification mask */
- /* register of port B */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = i_RegValue & 0xF9;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects error channels 1 and 2 */
-
- i_PatternMask = (i_PatternMask | 0xC0);
- i_PatternPolarity = (i_PatternPolarity | 0xC0);
- i_PatternTransition = (i_PatternTransition | 0xC0);
-
- /* Selects the polarity register of port 2 */
- outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_PatternPolarity,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the pattern transition register */
- /* of port 2 */
- outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_PatternTransition,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the pattern Mask register */
- /* of port 2 */
-
- outb(APCI1500_RW_PORT_B_PATTERN_MASK,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_PatternMask,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification mask */
- /* register of port 2 */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the mode specification mask */
- /* register of port 2 */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = (i_RegValue & 0xF9) | 4;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- i_Event2Status = 1;
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
-
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Enable Port B */
-
- outb(0xF4,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "The choice for interrupt logic does not exist\n");
- return -EINVAL;
- }
- }
-
- return insn->n;
-}
-
-/*
- * Allows or disallows a port event
- *
- * data[0] 0 = Start input event, 1 = Stop input event
- * data[1] Number of port (1 or 2)
- */
-static int apci1500_di_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_Event1InterruptStatus = 0, i_Event2InterruptStatus =
- 0, i_RegValue;
-
- switch (data[0]) {
- case START:
- /* Tests the port number */
-
- if (data[1] == 1 || data[1] == 2) {
- /* Test if port 1 selected */
-
- if (data[1] == 1) {
- /* Test if event initialised */
- if (i_Event1Status == 1) {
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable Port A */
- outb(0xF0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of */
- /* port 1 */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Allows the pattern interrupt */
- outb(0xC0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Enable Port A */
- outb(0xF4,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_Event1InterruptStatus = 1;
- outb(APCI1500_RW_PORT_A_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Authorizes the main interrupt on the board */
- outb(0xD0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- } else {
- dev_warn(dev->class_dev,
- "Event 1 not initialised\n");
- return -EINVAL;
- }
- }
- if (data[1] == 2) {
-
- if (i_Event2Status == 1) {
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable Port B */
- outb(0x74,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of */
- /* port 2 */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Allows the pattern interrupt */
- outb(0xC0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Enable Port B */
- outb(0xF4,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Authorizes the main interrupt on the board */
- outb(0xD0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_Event2InterruptStatus = 1;
- } else {
- dev_warn(dev->class_dev,
- "Event 2 not initialised\n");
- return -EINVAL;
- }
- }
- } else {
- dev_warn(dev->class_dev,
- "The port parameter is in error\n");
- return -EINVAL;
- }
-
- break;
-
- case STOP:
- /* Tests the port number */
-
- if (data[1] == 1 || data[1] == 2) {
- /* Test if port 1 selected */
-
- if (data[1] == 1) {
- /* Test if event initialised */
- if (i_Event1Status == 1) {
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable Port A */
- outb(0xF0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of */
- /* port 1 */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Inhibits the pattern interrupt */
- outb(0xE0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Enable Port A */
- outb(0xF4,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_Event1InterruptStatus = 0;
- } else {
- dev_warn(dev->class_dev,
- "Event 1 not initialised\n");
- return -EINVAL;
- }
- }
- if (data[1] == 2) {
- /* Test if event initialised */
- if (i_Event2Status == 1) {
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable Port B */
- outb(0x74,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of */
- /* port 2 */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Inhibits the pattern interrupt */
- outb(0xE0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the APCI1500_RW_MASTER_CONFIGURATION_CONTROL register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Enable Port B */
- outb(0xF4,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_Event2InterruptStatus = 0;
- } else {
-
- dev_warn(dev->class_dev,
- "Event 2 not initialised\n");
- return -EINVAL;
- }
- }
-
- } else {
- dev_warn(dev->class_dev,
- "The port parameter is in error\n");
- return -EINVAL;
- }
- break;
- default:
- dev_warn(dev->class_dev,
- "The option of START/STOP logic does not exist\n");
- return -EINVAL;
- }
-
- return insn->n;
-}
-
-/*
- * Return the status of the digital input
- */
-static int apci1500_di_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_DummyRead = 0;
-
- /* Software reset */
- i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master configuration control register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification register of port A */
- outb(APCI1500_RW_PORT_A_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the data path polarity register of port A */
- outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* High level of port A means 1 */
- outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the data direction register of port A */
- outb(APCI1500_RW_PORT_A_DATA_DIRECTION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* All bits used as inputs */
- outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates the interrupt management of port A: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the handshake specification register of port A */
- outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the register */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification register of port B */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the data path polarity register of port B */
- outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* A high level of port B means 1 */
- outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the data direction register of port B */
- outb(APCI1500_RW_PORT_B_DATA_DIRECTION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* All bits used as inputs */
- outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates the interrupt management of port B: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the handshake specification register of port B */
- outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the register */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the data path polarity register of port C */
- outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* High level of port C means 1 */
- outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the data direction register of port C */
- outb(APCI1500_RW_PORT_C_DATA_DIRECTION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* All bits used as inputs except channel 1 */
- outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the special IO register of port C */
- outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes it */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates the interrupt management of timer 1 */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates Timer 2 interrupt management: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of Timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates interrupt management of timer 3: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes all interrupts */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- return insn->n;
-}
-
-static int apci1500_di_insn_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
-
- data[1] = inw(devpriv->i_IobaseAddon + APCI1500_DIGITAL_IP);
-
- return insn->n;
-}
-
-/*
- * Configures the digital output memory and the digital output error interrupt
- *
- * data[1] 1 = Enable the voltage error interrupt
- * 2 = Disable the voltage error interrupt
- */
-static int apci1500_do_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
-
- devpriv->b_OutputMemoryStatus = data[0];
- return insn->n;
-}
-
-/*
- * Writes port value to the selected port
- */
-static int apci1500_do_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- static unsigned int ui_Temp;
- unsigned int ui_Temp1;
- unsigned int ui_NoOfChannel = CR_CHAN(insn->chanspec); /* get the channel */
-
- if (!devpriv->b_OutputMemoryStatus)
- ui_Temp = 0;
-
- if (data[3] == 0) {
- if (data[1] == 0) {
- data[0] = (data[0] << ui_NoOfChannel) | ui_Temp;
- outw(data[0],
- devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
- } else {
- if (data[1] == 1) {
- switch (ui_NoOfChannel) {
-
- case 2:
- data[0] =
- (data[0] << (2 *
- data[2])) | ui_Temp;
- break;
-
- case 4:
- data[0] =
- (data[0] << (4 *
- data[2])) | ui_Temp;
- break;
-
- case 8:
- data[0] =
- (data[0] << (8 *
- data[2])) | ui_Temp;
- break;
-
- case 15:
- data[0] = data[0] | ui_Temp;
- break;
-
- default:
- dev_err(dev->class_dev,
- "chan spec wrong\n");
- return -EINVAL; /* "sorry channel spec wrong " */
-
- }
-
- outw(data[0],
- devpriv->i_IobaseAddon +
- APCI1500_DIGITAL_OP);
- } else {
- dev_warn(dev->class_dev,
- "Specified channel not supported\n");
- return -EINVAL;
- }
- }
- } else {
- if (data[3] == 1) {
- if (data[1] == 0) {
- data[0] = ~data[0] & 0x1;
- ui_Temp1 = 1;
- ui_Temp1 = ui_Temp1 << ui_NoOfChannel;
- ui_Temp = ui_Temp | ui_Temp1;
- data[0] =
- (data[0] << ui_NoOfChannel) ^
- 0xffffffff;
- data[0] = data[0] & ui_Temp;
- outw(data[0],
- devpriv->i_IobaseAddon +
- APCI1500_DIGITAL_OP);
- } else {
- if (data[1] == 1) {
- switch (ui_NoOfChannel) {
-
- case 2:
- data[0] = ~data[0] & 0x3;
- ui_Temp1 = 3;
- ui_Temp1 =
- ui_Temp1 << 2 * data[2];
- ui_Temp = ui_Temp | ui_Temp1;
- data[0] =
- ((data[0] << (2 *
- data
- [2])) ^
- 0xffffffff) & ui_Temp;
- break;
-
- case 4:
- data[0] = ~data[0] & 0xf;
- ui_Temp1 = 15;
- ui_Temp1 =
- ui_Temp1 << 4 * data[2];
- ui_Temp = ui_Temp | ui_Temp1;
- data[0] =
- ((data[0] << (4 *
- data
- [2])) ^
- 0xffffffff) & ui_Temp;
- break;
-
- case 8:
- data[0] = ~data[0] & 0xff;
- ui_Temp1 = 255;
- ui_Temp1 =
- ui_Temp1 << 8 * data[2];
- ui_Temp = ui_Temp | ui_Temp1;
- data[0] =
- ((data[0] << (8 *
- data
- [2])) ^
- 0xffffffff) & ui_Temp;
- break;
-
- case 15:
- break;
-
- default:
- dev_err(dev->class_dev,
- "chan spec wrong\n");
- return -EINVAL; /* "sorry channel spec wrong " */
-
- }
-
- outw(data[0],
- devpriv->i_IobaseAddon +
- APCI1500_DIGITAL_OP);
- } else {
- dev_warn(dev->class_dev,
- "Specified channel not supported\n");
- return -EINVAL;
- }
- }
- } else {
- dev_warn(dev->class_dev,
- "Specified functionality does not exist\n");
- return -EINVAL;
- }
- }
- ui_Temp = data[0];
- return insn->n;
-}
-
-/*
- * Configures The Watchdog
- *
- * data[0] 0 = APCI1500_115_KHZ, 1 = APCI1500_3_6_KHZ, 2 = APCI1500_1_8_KHZ
- * data[1] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
- * data[2] 0 = Counter, 1 = Timer/Watchdog
- * data[3] This parameter has two meanings. If the counter/timer is used as
- * a counter the limit value of the counter is given. If the counter/timer
- * is used as a timer, the divider factor for the output is given.
- * data[4] 0 = APCI1500_CONTINUOUS, 1 = APCI1500_SINGLE
- * data[5] 0 = Software Trigger, 1 = Hardware Trigger
- * data[6] 0 = Software gate, 1 = Hardware gate
- * data[7] 0 = Interrupt Disable, 1 = Interrupt Enable
- */
-static int apci1500_timer_config(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_TimerCounterMode, i_MasterConfiguration;
-
- devpriv->tsk_Current = current;
-
- /* Selection of the input clock */
- if (data[0] == 0 || data[0] == 1 || data[0] == 2) {
- outw(data[0], devpriv->i_IobaseAddon + APCI1500_CLK_SELECT);
- } else {
- if (data[0] != 3) {
- dev_warn(dev->class_dev,
- "The option for input clock selection does not exist\n");
- return -EINVAL;
- }
- }
- /* Select the counter/timer */
- switch (data[1]) {
- case COUNTER1:
- /* selecting counter or timer */
- switch (data[2]) {
- case 0:
- data[2] = APCI1500_COUNTER;
- break;
- case 1:
- data[2] = APCI1500_TIMER;
- break;
- default:
- dev_warn(dev->class_dev,
- "This choice is not a timer nor a counter\n");
- return -EINVAL;
- }
-
- /* Selecting single or continuous mode */
- switch (data[4]) {
- case 0:
- data[4] = APCI1500_CONTINUOUS;
- break;
- case 1:
- data[4] = APCI1500_SINGLE;
- break;
- default:
- dev_warn(dev->class_dev,
- "This option for single/continuous mode does not exist\n");
- return -EINVAL;
- }
-
- i_TimerCounterMode = data[2] | data[4] | 7;
- /* Test the reload value */
-
- if ((data[3] >= 0) && (data[3] <= 65535)) {
- if (data[7] == APCI1500_ENABLE
- || data[7] == APCI1500_DISABLE) {
-
- /* Selects the mode register of timer/counter 1 */
- outb(APCI1500_RW_CPT_TMR1_MODE_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Writes the new mode */
- outb(i_TimerCounterMode,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the constant register of timer/counter 1 */
-
- outb(APCI1500_RW_CPT_TMR1_TIME_CST_LOW,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the low value */
-
- outb(data[3],
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the constant register of timer/counter 1 */
-
- outb(APCI1500_RW_CPT_TMR1_TIME_CST_HIGH,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the high value */
-
- data[3] = data[3] >> 8;
- outb(data[3],
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master configuration register */
-
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Reads the register */
-
- i_MasterConfiguration =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Enables timer/counter 1 and triggers timer/counter 1 */
-
- i_MasterConfiguration =
- i_MasterConfiguration | 0x40;
-
- /* Selects the master configuration register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the new configuration */
- outb(i_MasterConfiguration,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the commands register of */
- /* timer/counter 1 */
-
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Disable timer/counter 1 */
-
- outb(0x0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the commands register of */
- /* timer/counter 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Trigger timer/counter 1 */
- outb(0x2,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Error in selection of interrupt enable or disable\n");
- return -EINVAL;
- }
- } else {
- dev_warn(dev->class_dev,
- "Error in selection of reload value\n");
- return -EINVAL;
- }
- i_TimerCounterWatchdogInterrupt = data[7];
- i_TimerCounter1Init = 1;
- break;
-
- case COUNTER2: /* selecting counter or timer */
- switch (data[2]) {
- case 0:
- data[2] = APCI1500_COUNTER;
- break;
- case 1:
- data[2] = APCI1500_TIMER;
- break;
- default:
- dev_warn(dev->class_dev,
- "This choice is not a timer nor a counter\n");
- return -EINVAL;
- }
-
- /* Selecting single or continuous mode */
- switch (data[4]) {
- case 0:
- data[4] = APCI1500_CONTINUOUS;
- break;
- case 1:
- data[4] = APCI1500_SINGLE;
- break;
- default:
- dev_warn(dev->class_dev,
- "This option for single/continuous mode does not exist\n");
- return -EINVAL;
- }
-
- /* Selecting software or hardware trigger */
- switch (data[5]) {
- case 0:
- data[5] = APCI1500_SOFTWARE_TRIGGER;
- break;
- case 1:
- data[5] = APCI1500_HARDWARE_TRIGGER;
- break;
- default:
- dev_warn(dev->class_dev,
- "This choice for software or hardware trigger does not exist\n");
- return -EINVAL;
- }
-
- /* Selecting software or hardware gate */
- switch (data[6]) {
- case 0:
- data[6] = APCI1500_SOFTWARE_GATE;
- break;
- case 1:
- data[6] = APCI1500_HARDWARE_GATE;
- break;
- default:
- dev_warn(dev->class_dev,
- "This choice for software or hardware gate does not exist\n");
- return -EINVAL;
- }
-
- i_TimerCounterMode = data[2] | data[4] | data[5] | data[6] | 7;
-
- /* Test the reload value */
-
- if ((data[3] >= 0) && (data[3] <= 65535)) {
- if (data[7] == APCI1500_ENABLE
- || data[7] == APCI1500_DISABLE) {
-
- /* Selects the mode register of timer/counter 2 */
- outb(APCI1500_RW_CPT_TMR2_MODE_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Writes the new mode */
- outb(i_TimerCounterMode,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the constant register of timer/counter 2 */
-
- outb(APCI1500_RW_CPT_TMR2_TIME_CST_LOW,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the low value */
-
- outb(data[3],
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the constant register of timer/counter 2 */
-
- outb(APCI1500_RW_CPT_TMR2_TIME_CST_HIGH,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the high value */
-
- data[3] = data[3] >> 8;
- outb(data[3],
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master configuration register */
-
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Reads the register */
-
- i_MasterConfiguration =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Enables timer/counter 2 and triggers timer/counter 2 */
-
- i_MasterConfiguration =
- i_MasterConfiguration | 0x20;
-
- /* Selects the master configuration register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the new configuration */
- outb(i_MasterConfiguration,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the commands register of */
- /* timer/counter 2 */
-
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Disable timer/counter 2 */
-
- outb(0x0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the commands register of */
- /* timer/counter 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Trigger timer/counter 1 */
- outb(0x2,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Error in selection of interrupt enable or disable\n");
- return -EINVAL;
- }
- } else {
- dev_warn(dev->class_dev,
- "Error in selection of reload value\n");
- return -EINVAL;
- }
- i_TimerCounterWatchdogInterrupt = data[7];
- i_TimerCounter2Init = 1;
- break;
-
- case COUNTER3: /* selecting counter or watchdog */
- switch (data[2]) {
- case 0:
- data[2] = APCI1500_COUNTER;
- break;
- case 1:
- data[2] = APCI1500_WATCHDOG;
- break;
- default:
- dev_warn(dev->class_dev,
- "This choice is not a watchdog nor a counter\n");
- return -EINVAL;
- }
-
- /* Selecting single or continuous mode */
- switch (data[4]) {
- case 0:
- data[4] = APCI1500_CONTINUOUS;
- break;
- case 1:
- data[4] = APCI1500_SINGLE;
- break;
- default:
- dev_warn(dev->class_dev,
- "This option for single/continuous mode does not exist\n");
- return -EINVAL;
- }
-
- /* Selecting software or hardware gate */
- switch (data[6]) {
- case 0:
- data[6] = APCI1500_SOFTWARE_GATE;
- break;
- case 1:
- data[6] = APCI1500_HARDWARE_GATE;
- break;
- default:
- dev_warn(dev->class_dev,
- "This choice for software or hardware gate does not exist\n");
- return -EINVAL;
- }
-
- /* Test if used for watchdog */
-
- if (data[2] == APCI1500_WATCHDOG) {
- /* - Enables the output line */
- /* - Enables retrigger */
- /* - Pulses output */
- i_TimerCounterMode = data[2] | data[4] | 0x54;
- } else {
- i_TimerCounterMode = data[2] | data[4] | data[6] | 7;
- }
- /* Test the reload value */
-
- if ((data[3] >= 0) && (data[3] <= 65535)) {
- if (data[7] == APCI1500_ENABLE
- || data[7] == APCI1500_DISABLE) {
-
- /* Selects the mode register of watchdog/counter 3 */
- outb(APCI1500_RW_CPT_TMR3_MODE_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Writes the new mode */
- outb(i_TimerCounterMode,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the constant register of watchdog/counter 3 */
-
- outb(APCI1500_RW_CPT_TMR3_TIME_CST_LOW,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the low value */
-
- outb(data[3],
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the constant register of watchdog/counter 3 */
-
- outb(APCI1500_RW_CPT_TMR3_TIME_CST_HIGH,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the high value */
-
- data[3] = data[3] >> 8;
- outb(data[3],
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master configuration register */
-
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Reads the register */
-
- i_MasterConfiguration =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Enables watchdog/counter 3 and triggers watchdog/counter 3 */
-
- i_MasterConfiguration =
- i_MasterConfiguration | 0x10;
-
- /* Selects the master configuration register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Writes the new configuration */
- outb(i_MasterConfiguration,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Test if COUNTER */
- if (data[2] == APCI1500_COUNTER) {
-
- /* Selects the command register of */
- /* watchdog/counter 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Disable the watchdog/counter 3 and starts it */
- outb(0x0,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the command register of */
- /* watchdog/counter 3 */
-
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Trigger the watchdog/counter 3 and starts it */
- outb(0x2,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- }
-
- } else {
-
- dev_warn(dev->class_dev,
- "Error in selection of interrupt enable or disable\n");
- return -EINVAL;
- }
- } else {
- dev_warn(dev->class_dev,
- "Error in selection of reload value\n");
- return -EINVAL;
- }
- i_TimerCounterWatchdogInterrupt = data[7];
- i_WatchdogCounter3Init = 1;
- break;
-
- default:
- dev_warn(dev->class_dev,
- "The specified counter/timer option does not exist\n");
- return -EINVAL;
- }
- i_CounterLogic = data[2];
- return insn->n;
-}
-
-/*
- * Start / Stop or trigger the timer counter or Watchdog
- *
- * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
- * data[1] 0 = Start, 1 = Stop, 2 = Trigger
- * data[2] 0 = Counter, 1 = Timer/Watchdog
- */
-static int apci1500_timer_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_CommandAndStatusValue;
-
- switch (data[0]) {
- case COUNTER1:
- switch (data[1]) {
- case START:
- if (i_TimerCounter1Init == 1) {
- if (i_TimerCounterWatchdogInterrupt == 1)
- i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */
- else
- i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
-
- /* Starts timer/counter 1 */
- i_TimerCounter1Enabled = 1;
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Counter/Timer1 not configured\n");
- return -EINVAL;
- }
- break;
-
- case STOP:
-
- /* Stop timer/counter 1 */
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x00,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_TimerCounter1Enabled = 0;
- break;
-
- case TRIGGER:
- if (i_TimerCounter1Init == 1) {
- if (i_TimerCounter1Enabled == 1) {
- /* Set Trigger and gate */
-
- i_CommandAndStatusValue = 0x6;
- } else {
- /* Set Trigger */
-
- i_CommandAndStatusValue = 0x2;
- }
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Counter/Timer1 not configured\n");
- return -EINVAL;
- }
- break;
-
- default:
- dev_warn(dev->class_dev,
- "The specified option for start/stop/trigger does not exist\n");
- return -EINVAL;
- }
- break;
-
- case COUNTER2:
- switch (data[1]) {
- case START:
- if (i_TimerCounter2Init == 1) {
- if (i_TimerCounterWatchdogInterrupt == 1)
- i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */
- else
- i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
-
- /* Starts timer/counter 2 */
- i_TimerCounter2Enabled = 1;
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Counter/Timer2 not configured\n");
- return -EINVAL;
- }
- break;
-
- case STOP:
-
- /* Stop timer/counter 2 */
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x00,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_TimerCounter2Enabled = 0;
- break;
- case TRIGGER:
- if (i_TimerCounter2Init == 1) {
- if (i_TimerCounter2Enabled == 1) {
- /* Set Trigger and gate */
-
- i_CommandAndStatusValue = 0x6;
- } else {
- /* Set Trigger */
-
- i_CommandAndStatusValue = 0x2;
- }
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Counter/Timer2 not configured\n");
- return -EINVAL;
- }
- break;
- default:
- dev_warn(dev->class_dev,
- "The specified option for start/stop/trigger does not exist\n");
- return -EINVAL;
- }
- break;
- case COUNTER3:
- switch (data[1]) {
- case START:
- if (i_WatchdogCounter3Init == 1) {
-
- if (i_TimerCounterWatchdogInterrupt == 1)
- i_CommandAndStatusValue = 0xC4; /* Enable the interrupt */
- else
- i_CommandAndStatusValue = 0xE4; /* disable the interrupt */
-
- /* Starts Watchdog/counter 3 */
- i_WatchdogCounter3Enabled = 1;
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- } else {
- dev_warn(dev->class_dev,
- "Watchdog/Counter3 not configured\n");
- return -EINVAL;
- }
- break;
-
- case STOP:
-
- /* Stop Watchdog/counter 3 */
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x00,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_WatchdogCounter3Enabled = 0;
- break;
-
- case TRIGGER:
- switch (data[2]) {
- case 0: /* triggering counter 3 */
- if (i_WatchdogCounter3Init == 1) {
- if (i_WatchdogCounter3Enabled == 1) {
- /* Set Trigger and gate */
-
- i_CommandAndStatusValue = 0x6;
- } else {
- /* Set Trigger */
-
- i_CommandAndStatusValue = 0x2;
- }
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Counter3 not configured\n");
- return -EINVAL;
- }
- break;
- case 1:
- /* triggering Watchdog 3 */
- if (i_WatchdogCounter3Init == 1) {
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x6,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Watchdog 3 not configured\n");
- return -EINVAL;
- }
- break;
- default:
- dev_warn(dev->class_dev,
- "Wrong choice of watchdog/counter3\n");
- return -EINVAL;
- }
- break;
- default:
- dev_warn(dev->class_dev,
- "The specified option for start/stop/trigger does not exist\n");
- return -EINVAL;
- }
- break;
- default:
- dev_warn(dev->class_dev,
- "The specified choice for counter/watchdog/timer does not exist\n");
- return -EINVAL;
- }
- return insn->n;
-}
-
-/*
- * Read The Watchdog
- *
- * data[0] 0 = Counter1/Timer1, 1 = Counter2/Timer2, 2 = Counter3/Watchdog
- */
-static int apci1500_timer_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_CommandAndStatusValue;
-
- switch (data[0]) {
- case COUNTER1:
- /* Read counter/timer1 */
- if (i_TimerCounter1Init == 1) {
- if (i_TimerCounter1Enabled == 1) {
- /* Set RCC and gate */
-
- i_CommandAndStatusValue = 0xC;
- } else {
- /* Set RCC */
-
- i_CommandAndStatusValue = 0x8;
- }
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the counter register (high) */
- outb(APCI1500_R_CPT_TMR1_VALUE_HIGH,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] = data[0] << 8;
- data[0] = data[0] & 0xff00;
- outb(APCI1500_R_CPT_TMR1_VALUE_LOW,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] =
- data[0] | inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Timer/Counter1 not configured\n");
- return -EINVAL;
- }
- break;
- case COUNTER2:
- /* Read counter/timer2 */
- if (i_TimerCounter2Init == 1) {
- if (i_TimerCounter2Enabled == 1) {
- /* Set RCC and gate */
-
- i_CommandAndStatusValue = 0xC;
- } else {
- /* Set RCC */
-
- i_CommandAndStatusValue = 0x8;
- }
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the counter register (high) */
- outb(APCI1500_R_CPT_TMR2_VALUE_HIGH,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] = data[0] << 8;
- data[0] = data[0] & 0xff00;
- outb(APCI1500_R_CPT_TMR2_VALUE_LOW,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] =
- data[0] | inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Timer/Counter2 not configured\n");
- return -EINVAL;
- }
- break;
- case COUNTER3:
- /* Read counter/watchdog2 */
- if (i_WatchdogCounter3Init == 1) {
- if (i_WatchdogCounter3Enabled == 1) {
- /* Set RCC and gate */
-
- i_CommandAndStatusValue = 0xC;
- } else {
- /* Set RCC */
-
- i_CommandAndStatusValue = 0x8;
- }
-
- /* Selects the commands and status register */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_CommandAndStatusValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the counter register (high) */
- outb(APCI1500_R_CPT_TMR3_VALUE_HIGH,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] = data[0] << 8;
- data[0] = data[0] & 0xff00;
- outb(APCI1500_R_CPT_TMR3_VALUE_LOW,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- data[0] =
- data[0] | inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "WatchdogCounter3 not configured\n");
- return -EINVAL;
- }
- break;
- default:
- dev_warn(dev->class_dev,
- "The choice of timer/counter/watchdog does not exist\n");
- return -EINVAL;
- }
-
- return insn->n;
-}
-
-/*
- * Read the interrupt mask
- *
- * data[0] The interrupt mask value
- * data[1] Channel Number
- */
-static int apci1500_timer_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- data[0] = i_InterruptMask;
- data[1] = i_InputChannel;
- i_InterruptMask = 0;
- return insn->n;
-}
-
-/*
- * Configures the interrupt registers
- */
-static int apci1500_do_bits(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
-{
- struct apci1500_private *devpriv = dev->private;
- unsigned int ui_Status;
- int i_RegValue;
- int i_Constant;
-
- devpriv->tsk_Current = current;
- outl(0x0, devpriv->i_IobaseAmcc + 0x38);
- if (data[0] == 1) {
- i_Constant = 0xC0;
- } else {
- if (data[0] == 0) {
- i_Constant = 0x00;
- } else {
- dev_warn(dev->class_dev,
- "The parameter passed to driver is in error for enabling the voltage interrupt\n");
- return -EINVAL;
- }
- }
-
- /* Selects the mode specification register of port B */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Writes the new configuration (APCI1500_OR) */
- i_RegValue = (i_RegValue & 0xF9) | APCI1500_OR;
-
- outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Authorises the interrupt on the board */
- outb(0xC0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the pattern polarity register of port B */
- outb(APCI1500_RW_PORT_B_PATTERN_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the pattern transition register of port B */
- outb(APCI1500_RW_PORT_B_PATTERN_TRANSITION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the pattern mask register of port B */
- outb(APCI1500_RW_PORT_B_PATTERN_MASK,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(i_Constant, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of port A */
-
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of port B */
-
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of timer 1 */
-
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of timer 2 */
-
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the command and status register of timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of timer 3 */
-
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Authorizes the main interrupt on the board */
- outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Enables the PCI interrupt */
- outl(0x3000, devpriv->i_IobaseAmcc + 0x38);
- ui_Status = inl(devpriv->i_IobaseAmcc + 0x10);
- ui_Status = inl(devpriv->i_IobaseAmcc + 0x38);
- outl(0x23000, devpriv->i_IobaseAmcc + 0x38);
-
- return insn->n;
-}
-
-static irqreturn_t apci1500_interrupt(int irq, void *d)
-{
-
- struct comedi_device *dev = d;
- struct apci1500_private *devpriv = dev->private;
- unsigned int ui_InterruptStatus = 0;
- int i_RegValue = 0;
-
- /* Clear the interrupt mask */
- i_InterruptMask = 0;
-
- /* Read the board interrupt status */
- ui_InterruptStatus = inl(devpriv->i_IobaseAmcc + 0x38);
-
- /* Test if board generated a interrupt */
- if ((ui_InterruptStatus & 0x800000) == 0x800000) {
- /* Disable all Interrupt */
- /* Selects the master interrupt control register */
- /* Disables the main interrupt on the board */
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- if ((i_RegValue & 0x60) == 0x60) {
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of port A */
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_InterruptMask = i_InterruptMask | 1;
- if (i_Logic == APCI1500_OR_PRIORITY) {
- outb(APCI1500_RW_PORT_A_SPECIFICATION,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the interrupt vector register of port A */
- outb(APCI1500_RW_PORT_A_INTERRUPT_CONTROL,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
-
- i_InputChannel = 1 + (i_RegValue >> 1);
-
- } else {
- i_InputChannel = 0;
- }
- }
-
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- if ((i_RegValue & 0x60) == 0x60) {
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of port B */
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Reads port B */
- i_RegValue =
- inb((unsigned int) devpriv->iobase +
- APCI1500_Z8536_PORT_B);
-
- i_RegValue = i_RegValue & 0xC0;
- /* Tests if this is an external error */
-
- if (i_RegValue) {
- /* Disable the interrupt */
- /* Selects the command and status register of port B */
- outl(0x0, devpriv->i_IobaseAmcc + 0x38);
-
- if (i_RegValue & 0x80) {
- i_InterruptMask =
- i_InterruptMask | 0x40;
- }
-
- if (i_RegValue & 0x40) {
- i_InterruptMask =
- i_InterruptMask | 0x80;
- }
- } else {
- i_InterruptMask = i_InterruptMask | 2;
- }
- }
-
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- if ((i_RegValue & 0x60) == 0x60) {
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of timer 1 */
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_InterruptMask = i_InterruptMask | 4;
- }
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- if ((i_RegValue & 0x60) == 0x60) {
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of timer 2 */
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- i_InterruptMask = i_InterruptMask | 8;
- }
-
- /* Selects the command and status register of timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_RegValue =
- inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- if ((i_RegValue & 0x60) == 0x60) {
- /* Selects the command and status register of timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the interrupt of timer 3 */
- i_RegValue = (i_RegValue & 0x0F) | 0x20;
- outb(i_RegValue,
- devpriv->iobase +
- APCI1500_Z8536_CONTROL_REGISTER);
- if (i_CounterLogic == APCI1500_COUNTER)
- i_InterruptMask = i_InterruptMask | 0x10;
- else
- i_InterruptMask = i_InterruptMask | 0x20;
- }
-
- send_sig(SIGIO, devpriv->tsk_Current, 0); /* send signal to the sample */
- /* Enable all Interrupts */
-
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Authorizes the main interrupt on the board */
- outb(0xD0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- } else {
- dev_warn(dev->class_dev,
- "Interrupt from unknown source\n");
-
- }
-
- return IRQ_HANDLED;
-}
-
-static int apci1500_reset(struct comedi_device *dev)
-{
- struct apci1500_private *devpriv = dev->private;
- int i_DummyRead = 0;
-
- i_TimerCounter1Init = 0;
- i_TimerCounter2Init = 0;
- i_WatchdogCounter3Init = 0;
- i_Event1Status = 0;
- i_Event2Status = 0;
- i_TimerCounterWatchdogInterrupt = 0;
- i_Logic = 0;
- i_CounterLogic = 0;
- i_InterruptMask = 0;
- i_InputChannel = 0;
- i_TimerCounter1Enabled = 0;
- i_TimerCounter2Enabled = 0;
- i_WatchdogCounter3Enabled = 0;
-
- /* Software reset */
- i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- i_DummyRead = inb(devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(1, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the master configuration control register */
- outb(APCI1500_RW_MASTER_CONFIGURATION_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0xF4, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification register of port A */
- outb(APCI1500_RW_PORT_A_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the data path polarity register of port A */
- outb(APCI1500_RW_PORT_A_DATA_PCITCH_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* High level of port A means 1 */
- outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the data direction register of port A */
- outb(APCI1500_RW_PORT_A_DATA_DIRECTION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* All bits used as inputs */
- outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates the interrupt management of port A: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the handshake specification register of port A */
- outb(APCI1500_RW_PORT_A_HANDSHAKE_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the register */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the mode specification register of port B */
- outb(APCI1500_RW_PORT_B_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- outb(0x10, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the data path polarity register of port B */
- outb(APCI1500_RW_PORT_B_DATA_PCITCH_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* A high level of port B means 1 */
- outb(0x7F, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the data direction register of port B */
- outb(APCI1500_RW_PORT_B_DATA_DIRECTION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* All bits used as inputs */
- outb(0xFF, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates the interrupt management of port B: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the handshake specification register of port B */
- outb(APCI1500_RW_PORT_B_HANDSHAKE_SPECIFICATION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes the register */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
-
- /* Selects the data path polarity register of port C */
- outb(APCI1500_RW_PORT_C_DATA_PCITCH_POLARITY,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* High level of port C means 1 */
- outb(0x9, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the data direction register of port C */
- outb(APCI1500_RW_PORT_C_DATA_DIRECTION,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* All bits used as inputs except channel 1 */
- outb(0x0E, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the special IO register of port C */
- outb(APCI1500_RW_PORT_C_SPECIAL_IO_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes it */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates the interrupt management of timer 1 */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates Timer 2 interrupt management: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes IP and IUS */
- outb(0x20, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of Timer 3 */
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates interrupt management of timer 3: */
- outb(0xE0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deletes all interrupts */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* reset all the digital outputs */
- outw(0x0, devpriv->i_IobaseAddon + APCI1500_DIGITAL_OP);
- /* Disable the board interrupt */
- /* Selects the master interrupt control register */
- outb(APCI1500_RW_MASTER_INTERRUPT_CONTROL,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates all interrupts */
- outb(0, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port A */
- outb(APCI1500_RW_PORT_A_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates all interrupts */
- outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of port B */
- outb(APCI1500_RW_PORT_B_COMMAND_AND_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates all interrupts */
- outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 1 */
- outb(APCI1500_RW_CPT_TMR1_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates all interrupts */
- outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 2 */
- outb(APCI1500_RW_CPT_TMR2_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates all interrupts */
- outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Selects the command and status register of timer 3*/
- outb(APCI1500_RW_CPT_TMR3_CMD_STATUS,
- devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- /* Deactivates all interrupts */
- outb(0x00, devpriv->iobase + APCI1500_Z8536_CONTROL_REGISTER);
- return 0;
-}
diff --git a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
index 339519a3d6b5..1f2f78186d58 100644
--- a/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
+++ b/drivers/staging/comedi/drivers/addi-data/hwdrv_apci3501.c
@@ -93,7 +93,6 @@ static int apci3501_write_insn_timer(struct comedi_device *dev,
{
struct apci3501_private *devpriv = dev->private;
unsigned int ul_Command1 = 0;
- int i_Temp;
if (devpriv->b_TimerSelectMode == ADDIDATA_WATCHDOG) {
@@ -135,7 +134,7 @@ static int apci3501_write_insn_timer(struct comedi_device *dev,
}
}
- i_Temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1;
+ inl(dev->iobase + APCI3501_TIMER_STATUS_REG);
return insn->n;
}
diff --git a/drivers/staging/comedi/drivers/addi_apci_1032.c b/drivers/staging/comedi/drivers/addi_apci_1032.c
index bf14165297b7..4911b627203b 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1032.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1032.c
@@ -22,6 +22,54 @@
* more details.
*/
+/*
+ * Driver: addi_apci_1032
+ * Description: ADDI-DATA APCI-1032 Digital Input Board
+ * Author: ADDI-DATA GmbH <info@addi-data.com>,
+ * H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Status: untested
+ * Devices: [ADDI-DATA] APCI-1032 (addi_apci_1032)
+ *
+ * Configuration options:
+ * None; devices are configured automatically.
+ *
+ * This driver models the APCI-1032 as a 32-channel, digital input subdevice
+ * plus an additional digital input subdevice to handle change-of-state (COS)
+ * interrupts (if an interrupt handler can be set up successfully).
+ *
+ * The COS subdevice supports comedi asynchronous read commands.
+ *
+ * Change-Of-State (COS) interrupt configuration:
+ *
+ * Channels 0 to 15 are interruptible. These channels can be configured
+ * to generate interrupts based on AND/OR logic for the desired channels.
+ *
+ * OR logic:
+ * - reacts to rising or falling edges
+ * - interrupt is generated when any enabled channel meets the desired
+ * interrupt condition
+ *
+ * AND logic:
+ * - reacts to changes in level of the selected inputs
+ * - interrupt is generated when all enabled channels meet the desired
+ * interrupt condition
+ * - after an interrupt, a change in level must occur on the selected
+ * inputs to release the IRQ logic
+ *
+ * The COS subdevice must be configured before setting up a comedi
+ * asynchronous command:
+ *
+ * data[0] : INSN_CONFIG_DIGITAL_TRIG
+ * data[1] : trigger number (= 0)
+ * data[2] : configuration operation:
+ * - COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
+ * - COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts
+ * - COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts
+ * data[3] : left-shift for data[4] and data[5]
+ * data[4] : rising-edge/high level channels
+ * data[5] : falling-edge/low level channels
+ */
+
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
@@ -62,36 +110,6 @@ static int apci1032_reset(struct comedi_device *dev)
return 0;
}
-/*
- * Change-Of-State (COS) interrupt configuration
- *
- * Channels 0 to 15 are interruptible. These channels can be configured
- * to generate interrupts based on AND/OR logic for the desired channels.
- *
- * OR logic
- * - reacts to rising or falling edges
- * - interrupt is generated when any enabled channel
- * meet the desired interrupt condition
- *
- * AND logic
- * - reacts to changes in level of the selected inputs
- * - interrupt is generated when all enabled channels
- * meet the desired interrupt condition
- * - after an interrupt, a change in level must occur on
- * the selected inputs to release the IRQ logic
- *
- * The COS interrupt must be configured before it can be enabled.
- *
- * data[0] : INSN_CONFIG_DIGITAL_TRIG
- * data[1] : trigger number (= 0)
- * data[2] : configuration operation:
- * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
- * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = OR (edge) interrupts
- * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = AND (level) interrupts
- * data[3] : left-shift for data[4] and data[5]
- * data[4] : rising-edge/high level channels
- * data[5] : falling-edge/low level channels
- */
static int apci1032_cos_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
diff --git a/drivers/staging/comedi/drivers/addi_apci_1500.c b/drivers/staging/comedi/drivers/addi_apci_1500.c
index 30b132c3d092..f15aa1f6b476 100644
--- a/drivers/staging/comedi/drivers/addi_apci_1500.c
+++ b/drivers/staging/comedi/drivers/addi_apci_1500.c
@@ -1,22 +1,755 @@
+/*
+ * addi_apci_1500.c
+ * Copyright (C) 2004,2005 ADDI-DATA GmbH for the source code of this module.
+ *
+ * ADDI-DATA GmbH
+ * Dieselstrasse 3
+ * D-77833 Ottersweier
+ * Tel: +19(0)7223/9493-0
+ * Fax: +49(0)7223/9493-92
+ * http://www.addi-data.com
+ * info@addi-data.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
#include <linux/module.h>
#include <linux/pci.h>
-#include <linux/sched.h>
#include <linux/interrupt.h>
#include "../comedidev.h"
#include "comedi_fc.h"
#include "amcc_s5933.h"
+#include "z8536.h"
+
+/*
+ * PCI Bar 0 Register map (devpriv->amcc)
+ * see amcc_s5933.h for register and bit defines
+ */
+
+/*
+ * PCI Bar 1 Register map (dev->iobase)
+ * see z8536.h for Z8536 internal registers and bit defines
+ */
+#define APCI1500_Z8536_PORTC_REG 0x00
+#define APCI1500_Z8536_PORTB_REG 0x01
+#define APCI1500_Z8536_PORTA_REG 0x02
+#define APCI1500_Z8536_CTRL_REG 0x03
+
+/*
+ * PCI Bar 2 Register map (devpriv->addon)
+ */
+#define APCI1500_CLK_SEL_REG 0x00
+#define APCI1500_DI_REG 0x00
+#define APCI1500_DO_REG 0x02
struct apci1500_private {
- int iobase;
- int i_IobaseAmcc;
- int i_IobaseAddon;
- int i_IobaseReserved;
- unsigned char b_OutputMemoryStatus;
- struct task_struct *tsk_Current;
+ unsigned long amcc;
+ unsigned long addon;
+
+ unsigned int clk_src;
+
+ /* Digital trigger configuration [0]=AND [1]=OR */
+ unsigned int pm[2]; /* Pattern Mask */
+ unsigned int pt[2]; /* Pattern Transition */
+ unsigned int pp[2]; /* Pattern Polarity */
};
-#include "addi-data/hwdrv_apci1500.c"
+static unsigned int z8536_read(struct comedi_device *dev, unsigned int reg)
+{
+ unsigned long flags;
+ unsigned int val;
+
+ spin_lock_irqsave(&dev->spinlock, flags);
+ outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ val = inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ return val;
+}
+
+static void z8536_write(struct comedi_device *dev,
+ unsigned int val, unsigned int reg)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->spinlock, flags);
+ outb(reg, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ outb(val, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+}
+
+static void z8536_reset(struct comedi_device *dev)
+{
+ unsigned long flags;
+
+ /*
+ * Even if the state of the Z8536 is not known, the following
+ * sequence will reset it and put it in State 0.
+ */
+ spin_lock_irqsave(&dev->spinlock, flags);
+ inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+ outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ inb(dev->iobase + APCI1500_Z8536_CTRL_REG);
+ outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ outb(1, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ outb(0, dev->iobase + APCI1500_Z8536_CTRL_REG);
+ spin_unlock_irqrestore(&dev->spinlock, flags);
+
+ /* Disable all Ports and Counter/Timers */
+ z8536_write(dev, 0x00, Z8536_CFG_CTRL_REG);
+
+ /*
+ * Port A is connected to Ditial Input channels 0-7.
+ * Configure the port to allow interrupt detection.
+ */
+ z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
+ Z8536_PAB_MODE_SB |
+ Z8536_PAB_MODE_PMS_DISABLE,
+ Z8536_PA_MODE_REG);
+ z8536_write(dev, 0xff, Z8536_PB_DPP_REG);
+ z8536_write(dev, 0xff, Z8536_PA_DD_REG);
+
+ /*
+ * Port B is connected to Ditial Input channels 8-13.
+ * Configure the port to allow interrupt detection.
+ *
+ * NOTE: Bits 7 and 6 of Port B are connected to internal
+ * diagnostic signals and bit 7 is inverted.
+ */
+ z8536_write(dev, Z8536_PAB_MODE_PTS_BIT |
+ Z8536_PAB_MODE_SB |
+ Z8536_PAB_MODE_PMS_DISABLE,
+ Z8536_PB_MODE_REG);
+ z8536_write(dev, 0x7f, Z8536_PB_DPP_REG);
+ z8536_write(dev, 0xff, Z8536_PB_DD_REG);
+
+ /*
+ * Not sure what Port C is connected to...
+ */
+ z8536_write(dev, 0x09, Z8536_PC_DPP_REG);
+ z8536_write(dev, 0x0e, Z8536_PC_DD_REG);
+
+ /*
+ * Clear and disable all interrupt sources.
+ *
+ * Just in case, the reset of the Z8536 should have already
+ * done this.
+ */
+ z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PA_CMDSTAT_REG);
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
+
+ z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_PB_CMDSTAT_REG);
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
+
+ z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(0));
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(0));
+
+ z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(1));
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(1));
+
+ z8536_write(dev, Z8536_CMD_CLR_IP_IUS, Z8536_CT_CMDSTAT_REG(2));
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_CT_CMDSTAT_REG(2));
+
+ /* Disable all interrupts */
+ z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
+}
+
+static void apci1500_port_enable(struct comedi_device *dev, bool enable)
+{
+ unsigned int cfg;
+
+ cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
+ if (enable)
+ cfg |= (Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
+ else
+ cfg &= ~(Z8536_CFG_CTRL_PAE | Z8536_CFG_CTRL_PBE);
+ z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
+}
+
+static void apci1500_timer_enable(struct comedi_device *dev,
+ unsigned int chan, bool enable)
+{
+ unsigned int bit;
+ unsigned int cfg;
+
+ if (chan == 0)
+ bit = Z8536_CFG_CTRL_CT1E;
+ else if (chan == 1)
+ bit = Z8536_CFG_CTRL_CT2E;
+ else
+ bit = Z8536_CFG_CTRL_PCE_CT3E;
+
+ cfg = z8536_read(dev, Z8536_CFG_CTRL_REG);
+ if (enable) {
+ cfg |= bit;
+ } else {
+ cfg &= ~bit;
+ z8536_write(dev, 0x00, Z8536_CT_CMDSTAT_REG(chan));
+ }
+ z8536_write(dev, cfg, Z8536_CFG_CTRL_REG);
+}
+
+static bool apci1500_ack_irq(struct comedi_device *dev,
+ unsigned int reg)
+{
+ unsigned int val;
+
+ val = z8536_read(dev, reg);
+ if ((val & Z8536_STAT_IE_IP) == Z8536_STAT_IE_IP) {
+ val &= 0x0f; /* preserve any write bits */
+ val |= Z8536_CMD_CLR_IP_IUS;
+ z8536_write(dev, val, reg);
+
+ return true;
+ }
+ return false;
+}
+
+static irqreturn_t apci1500_interrupt(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ struct apci1500_private *devpriv = dev->private;
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int status = 0;
+ unsigned int val;
+
+ val = inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
+ if (!(val & INTCSR_INTR_ASSERTED))
+ return IRQ_NONE;
+
+ if (apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG))
+ status |= 0x01; /* port a event (inputs 0-7) */
+
+ if (apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG)) {
+ /* Tests if this is an external error */
+ val = inb(dev->iobase + APCI1500_Z8536_PORTB_REG);
+ val &= 0xc0;
+ if (val) {
+ if (val & 0x80) /* voltage error */
+ status |= 0x40;
+ if (val & 0x40) /* short circuit error */
+ status |= 0x80;
+ } else {
+ status |= 0x02; /* port b event (inputs 8-13) */
+ }
+ }
+
+ /*
+ * NOTE: The 'status' returned by the sample matches the
+ * interrupt mask information from the APCI-1500 Users Manual.
+ *
+ * Mask Meaning
+ * ---------- ------------------------------------------
+ * 0x00000001 Event 1 has occured
+ * 0x00000010 Event 2 has occured
+ * 0x00000100 Counter/timer 1 has run down (not implemented)
+ * 0x00001000 Counter/timer 2 has run down (not implemented)
+ * 0x00010000 Counter 3 has run down (not implemented)
+ * 0x00100000 Watchdog has run down (not implemented)
+ * 0x01000000 Voltage error
+ * 0x10000000 Short-circuit error
+ */
+ comedi_buf_write_samples(s, &status, 1);
+ comedi_handle_events(dev, s);
+
+ return IRQ_HANDLED;
+}
+
+static int apci1500_di_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ /* Disables the main interrupt on the board */
+ z8536_write(dev, 0x00, Z8536_INT_CTRL_REG);
+
+ /* Disable Ports A & B */
+ apci1500_port_enable(dev, false);
+
+ /* Ack any pending interrupts */
+ apci1500_ack_irq(dev, Z8536_PA_CMDSTAT_REG);
+ apci1500_ack_irq(dev, Z8536_PB_CMDSTAT_REG);
+
+ /* Disable pattern interrupts */
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PA_CMDSTAT_REG);
+ z8536_write(dev, Z8536_CMD_CLR_IE, Z8536_PB_CMDSTAT_REG);
+
+ /* Enable Ports A & B */
+ apci1500_port_enable(dev, true);
+
+ return 0;
+}
+
+static int apci1500_di_inttrig_start(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int trig_num)
+{
+ struct apci1500_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int pa_mode = Z8536_PAB_MODE_PMS_DISABLE;
+ unsigned int pb_mode = Z8536_PAB_MODE_PMS_DISABLE;
+ unsigned int pa_trig = trig_num & 0x01;
+ unsigned int pb_trig = (trig_num >> 1) & 0x01;
+ bool valid_trig = false;
+ unsigned int val;
+
+ if (trig_num != cmd->start_arg)
+ return -EINVAL;
+
+ /* Disable Ports A & B */
+ apci1500_port_enable(dev, false);
+
+ /* Set Port A for selected trigger pattern */
+ z8536_write(dev, devpriv->pm[pa_trig] & 0xff, Z8536_PA_PM_REG);
+ z8536_write(dev, devpriv->pt[pa_trig] & 0xff, Z8536_PA_PT_REG);
+ z8536_write(dev, devpriv->pp[pa_trig] & 0xff, Z8536_PA_PP_REG);
+
+ /* Set Port B for selected trigger pattern */
+ z8536_write(dev, (devpriv->pm[pb_trig] >> 8) & 0xff, Z8536_PB_PM_REG);
+ z8536_write(dev, (devpriv->pt[pb_trig] >> 8) & 0xff, Z8536_PB_PT_REG);
+ z8536_write(dev, (devpriv->pp[pb_trig] >> 8) & 0xff, Z8536_PB_PP_REG);
+
+ /* Set Port A trigger mode (if enabled) and enable interrupt */
+ if (devpriv->pm[pa_trig] & 0xff) {
+ pa_mode = pa_trig ? Z8536_PAB_MODE_PMS_AND
+ : Z8536_PAB_MODE_PMS_OR;
+
+ val = z8536_read(dev, Z8536_PA_MODE_REG);
+ val &= ~Z8536_PAB_MODE_PMS_MASK;
+ val |= (pa_mode | Z8536_PAB_MODE_IMO);
+ z8536_write(dev, val, Z8536_PA_MODE_REG);
+
+ z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PA_CMDSTAT_REG);
+
+ valid_trig = true;
+
+ dev_dbg(dev->class_dev,
+ "Port A configured for %s mode pattern detection\n",
+ pa_trig ? "AND" : "OR");
+ }
+
+ /* Set Port B trigger mode (if enabled) and enable interrupt */
+ if (devpriv->pm[pb_trig] & 0xff00) {
+ pb_mode = pb_trig ? Z8536_PAB_MODE_PMS_AND
+ : Z8536_PAB_MODE_PMS_OR;
+
+ val = z8536_read(dev, Z8536_PB_MODE_REG);
+ val &= ~Z8536_PAB_MODE_PMS_MASK;
+ val |= (pb_mode | Z8536_PAB_MODE_IMO);
+ z8536_write(dev, val, Z8536_PB_MODE_REG);
+
+ z8536_write(dev, Z8536_CMD_SET_IE, Z8536_PB_CMDSTAT_REG);
+
+ valid_trig = true;
+
+ dev_dbg(dev->class_dev,
+ "Port B configured for %s mode pattern detection\n",
+ pb_trig ? "AND" : "OR");
+ }
+
+ /* Enable Ports A & B */
+ apci1500_port_enable(dev, true);
+
+ if (!valid_trig) {
+ dev_dbg(dev->class_dev,
+ "digital trigger %d is not configured\n", trig_num);
+ return -EINVAL;
+ }
+
+ /* Authorizes the main interrupt on the board */
+ z8536_write(dev, Z8536_INT_CTRL_MIE | Z8536_INT_CTRL_DLC,
+ Z8536_INT_CTRL_REG);
+
+ return 0;
+}
+
+static int apci1500_di_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ s->async->inttrig = apci1500_di_inttrig_start;
+
+ return 0;
+}
+
+static int apci1500_di_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int err = 0;
+
+ /* Step 1 : check if triggers are trivially valid */
+
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_INT);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+ err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+ /* Step 2b : and mutually compatible */
+
+ /* Step 3: check if arguments are trivially valid */
+
+ /*
+ * Internal start source triggers:
+ *
+ * 0 AND mode for Port A (digital inputs 0-7)
+ * AND mode for Port B (digital inputs 8-13 and internal signals)
+ *
+ * 1 OR mode for Port A (digital inputs 0-7)
+ * AND mode for Port B (digital inputs 8-13 and internal signals)
+ *
+ * 2 AND mode for Port A (digital inputs 0-7)
+ * OR mode for Port B (digital inputs 8-13 and internal signals)
+ *
+ * 3 OR mode for Port A (digital inputs 0-7)
+ * OR mode for Port B (digital inputs 8-13 and internal signals)
+ */
+ err |= cfc_check_trigger_arg_max(&cmd->start_arg, 3);
+
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+ if (err)
+ return 3;
+
+ /* Step 4: fix up any arguments */
+
+ /* Step 5: check channel list if it exists */
+
+ return 0;
+}
+
+/*
+ * The pattern-recognition logic must be configured before the digital
+ * input async command is started.
+ *
+ * Digital input channels 0 to 13 can generate interrupts. Channels 14
+ * and 15 are connected to internal board status/diagnostic signals.
+ *
+ * Channel 14 - Voltage error (the external supply is < 5V)
+ * Channel 15 - Short-circuit/overtemperature error
+ *
+ * data[0] : INSN_CONFIG_DIGITAL_TRIG
+ * data[1] : trigger number
+ * 0 = AND mode
+ * 1 = OR mode
+ * data[2] : configuration operation:
+ * COMEDI_DIGITAL_TRIG_DISABLE = no interrupts
+ * COMEDI_DIGITAL_TRIG_ENABLE_EDGES = edge interrupts
+ * COMEDI_DIGITAL_TRIG_ENABLE_LEVELS = level interrupts
+ * data[3] : left-shift for data[4] and data[5]
+ * data[4] : rising-edge/high level channels
+ * data[5] : falling-edge/low level channels
+ */
+static int apci1500_di_cfg_trig(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct apci1500_private *devpriv = dev->private;
+ unsigned int trig = data[1];
+ unsigned int shift = data[3];
+ unsigned int hi_mask = data[4] << shift;
+ unsigned int lo_mask = data[5] << shift;
+ unsigned int chan_mask = hi_mask | lo_mask;
+ unsigned int old_mask = (1 << shift) - 1;
+ unsigned int pm = devpriv->pm[trig] & old_mask;
+ unsigned int pt = devpriv->pt[trig] & old_mask;
+ unsigned int pp = devpriv->pp[trig] & old_mask;
+
+ if (trig > 1) {
+ dev_dbg(dev->class_dev,
+ "invalid digital trigger number (0=AND, 1=OR)\n");
+ return -EINVAL;
+ }
+
+ if (chan_mask > 0xffff) {
+ dev_dbg(dev->class_dev, "invalid digital trigger channel\n");
+ return -EINVAL;
+ }
+
+ switch (data[2]) {
+ case COMEDI_DIGITAL_TRIG_DISABLE:
+ /* clear trigger configuration */
+ pm = 0;
+ pt = 0;
+ pp = 0;
+ break;
+ case COMEDI_DIGITAL_TRIG_ENABLE_EDGES:
+ pm |= chan_mask; /* enable channels */
+ pt |= chan_mask; /* enable edge detection */
+ pp |= hi_mask; /* rising-edge channels */
+ pp &= ~lo_mask; /* falling-edge channels */
+ break;
+ case COMEDI_DIGITAL_TRIG_ENABLE_LEVELS:
+ pm |= chan_mask; /* enable channels */
+ pt &= ~chan_mask; /* enable level detection */
+ pp |= hi_mask; /* high level channels */
+ pp &= ~lo_mask; /* low level channels */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /*
+ * The AND mode trigger can only have one channel (max) enabled
+ * for edge detection.
+ */
+ if (trig == 0) {
+ int ret = 0;
+ unsigned int src;
+
+ src = pt & 0xff;
+ if (src)
+ ret |= cfc_check_trigger_is_unique(src);
+
+ src = (pt >> 8) & 0xff;
+ if (src)
+ ret |= cfc_check_trigger_is_unique(src);
+
+ if (ret) {
+ dev_dbg(dev->class_dev,
+ "invalid AND trigger configuration\n");
+ return ret;
+ }
+ }
+
+ /* save the trigger configuration */
+ devpriv->pm[trig] = pm;
+ devpriv->pt[trig] = pt;
+ devpriv->pp[trig] = pp;
+
+ return insn->n;
+}
+
+static int apci1500_di_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ switch (data[0]) {
+ case INSN_CONFIG_DIGITAL_TRIG:
+ return apci1500_di_cfg_trig(dev, s, insn, data);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int apci1500_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct apci1500_private *devpriv = dev->private;
+
+ data[1] = inw(devpriv->addon + APCI1500_DI_REG);
+
+ return insn->n;
+}
+
+static int apci1500_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct apci1500_private *devpriv = dev->private;
+
+ if (comedi_dio_update_state(s, data))
+ outw(s->state, devpriv->addon + APCI1500_DO_REG);
+
+ data[1] = s->state;
+
+ return insn->n;
+}
+
+static int apci1500_timer_insn_config(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ struct apci1500_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int val;
+
+ switch (data[0]) {
+ case INSN_CONFIG_ARM:
+ val = data[1] & s->maxdata;
+ z8536_write(dev, val & 0xff, Z8536_CT_RELOAD_LSB_REG(chan));
+ z8536_write(dev, (val >> 8) & 0xff,
+ Z8536_CT_RELOAD_MSB_REG(chan));
+
+ apci1500_timer_enable(dev, chan, true);
+ z8536_write(dev, Z8536_CT_CMDSTAT_GCB,
+ Z8536_CT_CMDSTAT_REG(chan));
+ break;
+ case INSN_CONFIG_DISARM:
+ apci1500_timer_enable(dev, chan, false);
+ break;
+
+ case INSN_CONFIG_GET_COUNTER_STATUS:
+ data[1] = 0;
+ val = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+ if (val & Z8536_CT_STAT_CIP)
+ data[1] |= COMEDI_COUNTER_COUNTING;
+ if (val & Z8536_CT_CMDSTAT_GCB)
+ data[1] |= COMEDI_COUNTER_ARMED;
+ if (val & Z8536_STAT_IP) {
+ data[1] |= COMEDI_COUNTER_TERMINAL_COUNT;
+ apci1500_ack_irq(dev, Z8536_CT_CMDSTAT_REG(chan));
+ }
+ data[2] = COMEDI_COUNTER_ARMED | COMEDI_COUNTER_COUNTING |
+ COMEDI_COUNTER_TERMINAL_COUNT;
+ break;
+
+ case INSN_CONFIG_SET_COUNTER_MODE:
+ /* Simulate the 8254 timer modes */
+ switch (data[1]) {
+ case I8254_MODE0:
+ /* Interrupt on Terminal Count */
+ val = Z8536_CT_MODE_ECE |
+ Z8536_CT_MODE_DCS_ONESHOT;
+ break;
+ case I8254_MODE1:
+ /* Hardware Retriggerable One-Shot */
+ val = Z8536_CT_MODE_ETE |
+ Z8536_CT_MODE_DCS_ONESHOT;
+ break;
+ case I8254_MODE2:
+ /* Rate Generator */
+ val = Z8536_CT_MODE_CSC |
+ Z8536_CT_MODE_DCS_PULSE;
+ break;
+ case I8254_MODE3:
+ /* Square Wave Mode */
+ val = Z8536_CT_MODE_CSC |
+ Z8536_CT_MODE_DCS_SQRWAVE;
+ break;
+ case I8254_MODE4:
+ /* Software Triggered Strobe */
+ val = Z8536_CT_MODE_REB |
+ Z8536_CT_MODE_DCS_PULSE;
+ break;
+ case I8254_MODE5:
+ /* Hardware Triggered Strobe (watchdog) */
+ val = Z8536_CT_MODE_EOE |
+ Z8536_CT_MODE_ETE |
+ Z8536_CT_MODE_REB |
+ Z8536_CT_MODE_DCS_PULSE;
+ break;
+ default:
+ return -EINVAL;
+ }
+ apci1500_timer_enable(dev, chan, false);
+ z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
+ break;
+
+ case INSN_CONFIG_SET_CLOCK_SRC:
+ if (data[1] > 2)
+ return -EINVAL;
+ devpriv->clk_src = data[1];
+ if (devpriv->clk_src == 2)
+ devpriv->clk_src = 3;
+ outw(devpriv->clk_src, devpriv->addon + APCI1500_CLK_SEL_REG);
+ break;
+ case INSN_CONFIG_GET_CLOCK_SRC:
+ switch (devpriv->clk_src) {
+ case 0:
+ data[1] = 0; /* 111.86 kHz / 2 */
+ data[2] = 17879; /* 17879 ns (approx) */
+ break;
+ case 1:
+ data[1] = 1; /* 3.49 kHz / 2 */
+ data[2] = 573066; /* 573066 ns (approx) */
+ break;
+ case 3:
+ data[1] = 2; /* 1.747 kHz / 2 */
+ data[2] = 1164822; /* 1164822 ns (approx) */
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+
+ case INSN_CONFIG_SET_GATE_SRC:
+ if (chan == 0)
+ return -EINVAL;
+
+ val = z8536_read(dev, Z8536_CT_MODE_REG(chan));
+ val &= Z8536_CT_MODE_EGE;
+ if (data[1] == 1)
+ val |= Z8536_CT_MODE_EGE;
+ else if (data[1] > 1)
+ return -EINVAL;
+ z8536_write(dev, val, Z8536_CT_MODE_REG(chan));
+ break;
+ case INSN_CONFIG_GET_GATE_SRC:
+ if (chan == 0)
+ return -EINVAL;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+ return insn->n;
+}
+
+static int apci1500_timer_insn_write(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int cmd;
+
+ cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+ cmd &= Z8536_CT_CMDSTAT_GCB; /* preserve gate */
+ cmd |= Z8536_CT_CMD_TCB; /* set trigger */
+
+ /* software trigger a timer, it only makes sense to do one write */
+ if (insn->n)
+ z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
+
+ return insn->n;
+}
+
+static int apci1500_timer_insn_read(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
+{
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int cmd;
+ unsigned int val;
+ int i;
+
+ cmd = z8536_read(dev, Z8536_CT_CMDSTAT_REG(chan));
+ cmd &= Z8536_CT_CMDSTAT_GCB; /* preserve gate */
+ cmd |= Z8536_CT_CMD_RCC; /* set RCC */
+
+ for (i = 0; i < insn->n; i++) {
+ z8536_write(dev, cmd, Z8536_CT_CMDSTAT_REG(chan));
+
+ val = z8536_read(dev, Z8536_CT_VAL_MSB_REG(chan)) << 8;
+ val |= z8536_read(dev, Z8536_CT_VAL_LSB_REG(chan));
+
+ data[i] = val;
+ }
+
+ return insn->n;
+}
static int apci1500_auto_attach(struct comedi_device *dev,
unsigned long context)
@@ -35,10 +768,10 @@ static int apci1500_auto_attach(struct comedi_device *dev,
return ret;
dev->iobase = pci_resource_start(pcidev, 1);
- devpriv->iobase = dev->iobase;
- devpriv->i_IobaseAmcc = pci_resource_start(pcidev, 0);
- devpriv->i_IobaseAddon = pci_resource_start(pcidev, 2);
- devpriv->i_IobaseReserved = pci_resource_start(pcidev, 3);
+ devpriv->amcc = pci_resource_start(pcidev, 0);
+ devpriv->addon = pci_resource_start(pcidev, 2);
+
+ z8536_reset(dev);
if (pcidev->irq > 0) {
ret = request_irq(pcidev->irq, apci1500_interrupt, IRQF_SHARED,
@@ -51,51 +784,66 @@ static int apci1500_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- /* Allocate and Initialise DI Subdevice Structures */
+ /* Digital Input subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = apci1500_di_config;
- s->insn_read = apci1500_di_read;
- s->insn_write = apci1500_di_write;
- s->insn_bits = apci1500_di_insn_bits;
-
- /* Allocate and Initialise DO Subdevice Structures */
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = apci1500_di_insn_bits;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = 1;
+ s->insn_config = apci1500_di_insn_config;
+ s->do_cmdtest = apci1500_di_cmdtest;
+ s->do_cmd = apci1500_di_cmd;
+ s->cancel = apci1500_di_cancel;
+ }
+
+ /* Digital Output subdevice */
s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_config = apci1500_do_config;
- s->insn_write = apci1500_do_write;
- s->insn_bits = apci1500_do_bits;
-
- /* Allocate and Initialise Timer Subdevice Structures */
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = apci1500_do_insn_bits;
+
+ /* reset all the digital outputs */
+ outw(0x0, devpriv->addon + APCI1500_DO_REG);
+
+ /* Counter/Timer(Watchdog) subdevice */
s = &dev->subdevices[2];
- s->type = COMEDI_SUBD_TIMER;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 1;
- s->maxdata = 0;
- s->len_chanlist = 1;
- s->range_table = &range_digital;
- s->insn_write = apci1500_timer_write;
- s->insn_read = apci1500_timer_read;
- s->insn_config = apci1500_timer_config;
- s->insn_bits = apci1500_timer_bits;
-
- apci1500_reset(dev);
+ s->type = COMEDI_SUBD_TIMER;
+ s->subdev_flags = SDF_WRITABLE | SDF_READABLE;
+ s->n_chan = 3;
+ s->maxdata = 0xffff;
+ s->range_table = &range_unknown;
+ s->insn_config = apci1500_timer_insn_config;
+ s->insn_write = apci1500_timer_insn_write;
+ s->insn_read = apci1500_timer_insn_read;
+
+ /* Enable the PCI interrupt */
+ if (dev->irq) {
+ outl(0x2000 | INTCSR_INBOX_FULL_INT,
+ devpriv->amcc + AMCC_OP_REG_INTCSR);
+ inl(devpriv->amcc + AMCC_OP_REG_IMB1);
+ inl(devpriv->amcc + AMCC_OP_REG_INTCSR);
+ outl(INTCSR_INBOX_INTR_STATUS | 0x2000 | INTCSR_INBOX_FULL_INT,
+ devpriv->amcc + AMCC_OP_REG_INTCSR);
+ }
return 0;
}
static void apci1500_detach(struct comedi_device *dev)
{
- if (dev->iobase)
- apci1500_reset(dev);
+ struct apci1500_private *devpriv = dev->private;
+
+ if (devpriv->amcc)
+ outl(0x0, devpriv->amcc + AMCC_OP_REG_INTCSR);
comedi_pci_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/addi_apci_3501.c b/drivers/staging/comedi/drivers/addi_apci_3501.c
index a726efcea6a5..5961f195ba0b 100644
--- a/drivers/staging/comedi/drivers/addi_apci_3501.c
+++ b/drivers/staging/comedi/drivers/addi_apci_3501.c
@@ -267,7 +267,6 @@ static irqreturn_t apci3501_interrupt(int irq, void *d)
struct apci3501_private *devpriv = dev->private;
unsigned int ui_Timer_AOWatchdog;
unsigned long ul_Command1;
- int i_temp;
/* Disable Interrupt */
ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
@@ -285,7 +284,7 @@ static irqreturn_t apci3501_interrupt(int irq, void *d)
ul_Command1 = inl(dev->iobase + APCI3501_TIMER_CTRL_REG);
ul_Command1 = ((ul_Command1 & 0xFFFFF9FDul) | 1 << 1);
outl(ul_Command1, dev->iobase + APCI3501_TIMER_CTRL_REG);
- i_temp = inl(dev->iobase + APCI3501_TIMER_STATUS_REG) & 0x1;
+ inl(dev->iobase + APCI3501_TIMER_STATUS_REG);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/comedi/drivers/adl_pci6208.c b/drivers/staging/comedi/drivers/adl_pci6208.c
index 528f15c25dae..a3ea4b7c18dd 100644
--- a/drivers/staging/comedi/drivers/adl_pci6208.c
+++ b/drivers/staging/comedi/drivers/adl_pci6208.c
@@ -19,8 +19,7 @@
/*
* Driver: adl_pci6208
* Description: ADLink PCI-6208/6216 Series Multi-channel Analog Output Cards
- * Devices: (ADLink) PCI-6208 [adl_pci6208]
- * (ADLink) PCI-6216 [adl_pci6216]
+ * Devices: [ADLink] PCI-6208 (adl_pci6208), PCI-6216 (adl_pci6216)
* Author: nsyeow <nsyeow@pd.jaring.my>
* Updated: Fri, 30 Jan 2004 14:44:27 +0800
* Status: untested
diff --git a/drivers/staging/comedi/drivers/adl_pci7x3x.c b/drivers/staging/comedi/drivers/adl_pci7x3x.c
index fb8e5f582496..618e641ffaac 100644
--- a/drivers/staging/comedi/drivers/adl_pci7x3x.c
+++ b/drivers/staging/comedi/drivers/adl_pci7x3x.c
@@ -22,27 +22,35 @@
*/
/*
-Driver: adl_pci7x3x
-Description: 32/64-Channel Isolated Digital I/O Boards
-Devices: (ADLink) PCI-7230 [adl_pci7230] - 16 input / 16 output
- (ADLink) PCI-7233 [adl_pci7233] - 32 input
- (ADLink) PCI-7234 [adl_pci7234] - 32 output
- (ADLink) PCI-7432 [adl_pci7432] - 32 input / 32 output
- (ADLink) PCI-7433 [adl_pci7433] - 64 input
- (ADLink) PCI-7434 [adl_pci7434] - 64 output
-Author: H Hartley Sweeten <hsweeten@visionengravers.com>
-Updated: Thu, 02 Aug 2012 14:27:46 -0700
-Status: untested
-
-The PCI-7230, PCI-7432 and PCI-7433 boards also support external
-interrupt signals on digital input channels 0 and 1. The PCI-7233
-has dual-interrupt sources for change-of-state (COS) on any 16
-digital input channels of LSB and for COS on any 16 digital input
-lines of MSB. Interrupts are not currently supported by this
-driver.
-
-Configuration Options: not applicable, uses comedi PCI auto config
-*/
+ * Driver: adl_pci7x3x
+ * Description: 32/64-Channel Isolated Digital I/O Boards
+ * Devices: [ADLink] PCI-7230 (adl_pci7230), PCI-7233 (adl_pci7233),
+ * PCI-7234 (adl_pci7234), PCI-7432 (adl_pci7432), PCI-7433 (adl_pci7433),
+ * PCI-7434 (adl_pci7434)
+ * Author: H Hartley Sweeten <hsweeten@visionengravers.com>
+ * Updated: Thu, 02 Aug 2012 14:27:46 -0700
+ * Status: untested
+ *
+ * One or two subdevices are setup by this driver depending on
+ * the number of digital inputs and/or outputs provided by the
+ * board. Each subdevice has a maximum of 32 channels.
+ *
+ * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
+ * PCI-7233 - 1 subdevice: 0 - 32 input
+ * PCI-7234 - 1 subdevice: 0 - 32 output
+ * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
+ * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
+ * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
+ *
+ * The PCI-7230, PCI-7432 and PCI-7433 boards also support external
+ * interrupt signals on digital input channels 0 and 1. The PCI-7233
+ * has dual-interrupt sources for change-of-state (COS) on any 16
+ * digital input channels of LSB and for COS on any 16 digital input
+ * lines of MSB. Interrupts are not currently supported by this
+ * driver.
+ *
+ * Configuration Options: not applicable, uses comedi PCI auto config
+ */
#include <linux/module.h>
#include <linux/pci.h>
@@ -155,18 +163,6 @@ static int adl_pci7x3x_auto_attach(struct comedi_device *dev,
return ret;
dev->iobase = pci_resource_start(pcidev, 2);
- /*
- * One or two subdevices are setup by this driver depending on
- * the number of digital inputs and/or outputs provided by the
- * board. Each subdevice has a maximum of 32 channels.
- *
- * PCI-7230 - 2 subdevices: 0 - 16 input, 1 - 16 output
- * PCI-7233 - 1 subdevice: 0 - 32 input
- * PCI-7234 - 1 subdevice: 0 - 32 output
- * PCI-7432 - 2 subdevices: 0 - 32 input, 1 - 32 output
- * PCI-7433 - 2 subdevices: 0 - 32 input, 1 - 32 input
- * PCI-7434 - 2 subdevices: 0 - 32 output, 1 - 32 output
- */
ret = comedi_alloc_subdevices(dev, board->nsubdevs);
if (ret)
return ret;
diff --git a/drivers/staging/comedi/drivers/adl_pci8164.c b/drivers/staging/comedi/drivers/adl_pci8164.c
index 72bccb447a74..cc6c53b800a7 100644
--- a/drivers/staging/comedi/drivers/adl_pci8164.c
+++ b/drivers/staging/comedi/drivers/adl_pci8164.c
@@ -18,7 +18,7 @@
/*
* Driver: adl_pci8164
* Description: Driver for the Adlink PCI-8164 4 Axes Motion Control board
- * Devices: (ADLink) PCI-8164 [adl_pci8164]
+ * Devices: [ADLink] PCI-8164 (adl_pci8164)
* Author: Michel Lachaine <mike@mikelachaine.ca>
* Status: experimental
* Updated: Mon, 14 Apr 2008 15:10:32 +0100
diff --git a/drivers/staging/comedi/drivers/adl_pci9111.c b/drivers/staging/comedi/drivers/adl_pci9111.c
index 47f6c0e9f014..f68dc99f8e27 100644
--- a/drivers/staging/comedi/drivers/adl_pci9111.c
+++ b/drivers/staging/comedi/drivers/adl_pci9111.c
@@ -539,7 +539,7 @@ static irqreturn_t pci9111_interrupt(int irq, void *p_device)
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
dev_dbg(dev->class_dev, "fifo overflow\n");
outb(0, dev->iobase + PCI9111_INT_CLR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
return IRQ_HANDLED;
diff --git a/drivers/staging/comedi/drivers/adl_pci9118.c b/drivers/staging/comedi/drivers/adl_pci9118.c
index 26603582e71a..f61e392c2d3e 100644
--- a/drivers/staging/comedi/drivers/adl_pci9118.c
+++ b/drivers/staging/comedi/drivers/adl_pci9118.c
@@ -749,13 +749,13 @@ static irqreturn_t pci9118_interrupt(int irq, void *d)
if (intcsr & MASTER_ABORT_INT) {
dev_err(dev->class_dev, "AMCC IRQ - MASTER DMA ABORT!\n");
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
goto interrupt_exit;
}
if (intcsr & TARGET_ABORT_INT) {
dev_err(dev->class_dev, "AMCC IRQ - TARGET DMA ABORT!\n");
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
goto interrupt_exit;
}
diff --git a/drivers/staging/comedi/drivers/adv_pci1710.c b/drivers/staging/comedi/drivers/adv_pci1710.c
index d02df7d0c629..9800c01e6fb9 100644
--- a/drivers/staging/comedi/drivers/adv_pci1710.c
+++ b/drivers/staging/comedi/drivers/adv_pci1710.c
@@ -51,11 +51,6 @@ Configuration options:
#include "8253.h"
#include "amcc_s5933.h"
-/* hardware types of the cards */
-#define TYPE_PCI171X 0
-#define TYPE_PCI1713 2
-#define TYPE_PCI1720 3
-
#define PCI171x_AD_DATA 0 /* R: A/D data */
#define PCI171x_SOFTTRG 0 /* W: soft trigger for A/D */
#define PCI171x_RANGE 2 /* W: A/D gain/range register */
@@ -164,7 +159,7 @@ static const struct comedi_lrange range_pci17x1 = {
static const char range_codes_pci17x1[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
-static const struct comedi_lrange range_pci1720 = {
+static const struct comedi_lrange pci1720_ao_range = {
4, {
UNI_RANGE(5),
UNI_RANGE(10),
@@ -173,7 +168,7 @@ static const struct comedi_lrange range_pci1720 = {
}
};
-static const struct comedi_lrange range_pci171x_da = {
+static const struct comedi_lrange pci171x_ao_range = {
2, {
UNI_RANGE(5),
UNI_RANGE(10)
@@ -191,112 +186,81 @@ enum pci1710_boardid {
struct boardtype {
const char *name; /* board name */
- char have_irq; /* 1=card support IRQ */
- char cardtype; /* 0=1710& co. 2=1713, ... */
int n_aichan; /* num of A/D chans */
- int n_aichand; /* num of A/D chans in diff mode */
- int n_aochan; /* num of D/A chans */
- int n_dichan; /* num of DI chans */
- int n_dochan; /* num of DO chans */
- int n_counter; /* num of counters */
- int ai_maxdata; /* resolution of A/D */
- int ao_maxdata; /* resolution of D/A */
const struct comedi_lrange *rangelist_ai; /* rangelist for A/D */
const char *rangecode_ai; /* range codes for programming */
- const struct comedi_lrange *rangelist_ao; /* rangelist for D/A */
- unsigned int ai_ns_min; /* max sample speed of card v ns */
- unsigned int fifo_half_size; /* size of FIFO/2 */
+ unsigned int is_pci1713:1;
+ unsigned int is_pci1720:1;
+ unsigned int has_irq:1;
+ unsigned int has_large_fifo:1; /* 4K or 1K FIFO */
+ unsigned int has_diff_ai:1;
+ unsigned int has_ao:1;
+ unsigned int has_di_do:1;
+ unsigned int has_counter:1;
};
static const struct boardtype boardtypes[] = {
[BOARD_PCI1710] = {
.name = "pci1710",
- .have_irq = 1,
- .cardtype = TYPE_PCI171X,
.n_aichan = 16,
- .n_aichand = 8,
- .n_aochan = 2,
- .n_dichan = 16,
- .n_dochan = 16,
- .n_counter = 1,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
.rangelist_ai = &range_pci1710_3,
.rangecode_ai = range_codes_pci1710_3,
- .rangelist_ao = &range_pci171x_da,
- .ai_ns_min = 10000,
- .fifo_half_size = 2048,
+ .has_irq = 1,
+ .has_large_fifo = 1,
+ .has_diff_ai = 1,
+ .has_ao = 1,
+ .has_di_do = 1,
+ .has_counter = 1,
},
[BOARD_PCI1710HG] = {
.name = "pci1710hg",
- .have_irq = 1,
- .cardtype = TYPE_PCI171X,
.n_aichan = 16,
- .n_aichand = 8,
- .n_aochan = 2,
- .n_dichan = 16,
- .n_dochan = 16,
- .n_counter = 1,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
.rangelist_ai = &range_pci1710hg,
.rangecode_ai = range_codes_pci1710hg,
- .rangelist_ao = &range_pci171x_da,
- .ai_ns_min = 10000,
- .fifo_half_size = 2048,
+ .has_irq = 1,
+ .has_large_fifo = 1,
+ .has_diff_ai = 1,
+ .has_ao = 1,
+ .has_di_do = 1,
+ .has_counter = 1,
},
[BOARD_PCI1711] = {
.name = "pci1711",
- .have_irq = 1,
- .cardtype = TYPE_PCI171X,
.n_aichan = 16,
- .n_aochan = 2,
- .n_dichan = 16,
- .n_dochan = 16,
- .n_counter = 1,
- .ai_maxdata = 0x0fff,
- .ao_maxdata = 0x0fff,
.rangelist_ai = &range_pci17x1,
.rangecode_ai = range_codes_pci17x1,
- .rangelist_ao = &range_pci171x_da,
- .ai_ns_min = 10000,
- .fifo_half_size = 512,
+ .has_irq = 1,
+ .has_ao = 1,
+ .has_di_do = 1,
+ .has_counter = 1,
},
[BOARD_PCI1713] = {
.name = "pci1713",
- .have_irq = 1,
- .cardtype = TYPE_PCI1713,
.n_aichan = 32,
- .n_aichand = 16,
- .ai_maxdata = 0x0fff,
.rangelist_ai = &range_pci1710_3,
.rangecode_ai = range_codes_pci1710_3,
- .ai_ns_min = 10000,
- .fifo_half_size = 2048,
+ .is_pci1713 = 1,
+ .has_irq = 1,
+ .has_large_fifo = 1,
+ .has_diff_ai = 1,
},
[BOARD_PCI1720] = {
.name = "pci1720",
- .cardtype = TYPE_PCI1720,
- .n_aochan = 4,
- .ao_maxdata = 0x0fff,
- .rangelist_ao = &range_pci1720,
+ .is_pci1720 = 1,
+ .has_ao = 1,
},
[BOARD_PCI1731] = {
.name = "pci1731",
- .have_irq = 1,
- .cardtype = TYPE_PCI171X,
.n_aichan = 16,
- .n_dichan = 16,
- .n_dochan = 16,
- .ai_maxdata = 0x0fff,
.rangelist_ai = &range_pci17x1,
.rangecode_ai = range_codes_pci17x1,
- .ai_ns_min = 10000,
- .fifo_half_size = 512,
+ .has_irq = 1,
+ .has_di_do = 1,
},
};
struct pci1710_private {
+ unsigned int max_samples;
unsigned int CntrlReg; /* Control register */
unsigned char ai_et;
unsigned int ai_et_CntrlReg;
@@ -308,39 +272,10 @@ struct pci1710_private {
unsigned int act_chanlist[32]; /* list of scanned channel */
unsigned char saved_seglen; /* len of the non-repeating chanlist */
unsigned char da_ranges; /* copy of D/A outpit range register */
- unsigned short ao_data[4]; /* data output buffer */
unsigned int cnt0_write_wait; /* after a write, wait for update of the
* internal state */
};
-/* used for gain list programming */
-static const unsigned int muxonechan[] = {
- 0x0000, 0x0101, 0x0202, 0x0303, 0x0404, 0x0505, 0x0606, 0x0707,
- 0x0808, 0x0909, 0x0a0a, 0x0b0b, 0x0c0c, 0x0d0d, 0x0e0e, 0x0f0f,
- 0x1010, 0x1111, 0x1212, 0x1313, 0x1414, 0x1515, 0x1616, 0x1717,
- 0x1818, 0x1919, 0x1a1a, 0x1b1b, 0x1c1c, 0x1d1d, 0x1e1e, 0x1f1f
-};
-
-static int pci171x_ai_dropout(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int chan,
- unsigned int val)
-{
- const struct boardtype *board = dev->board_ptr;
- struct pci1710_private *devpriv = dev->private;
-
- if (board->cardtype != TYPE_PCI1713) {
- if ((val & 0xf000) != devpriv->act_chanlist[chan]) {
- dev_err(dev->class_dev,
- "A/D data droput: received from channel %d, expected %d\n",
- (val >> 12) & 0xf,
- (devpriv->act_chanlist[chan] >> 12) & 0xf);
- return -ENODATA;
- }
- }
- return 0;
-}
-
static int pci171x_ai_check_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -407,33 +342,39 @@ static int pci171x_ai_check_chanlist(struct comedi_device *dev,
return 0;
}
-static void setup_channel_list(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int *chanlist, unsigned int n_chan,
- unsigned int seglen)
+static void pci171x_ai_setup_chanlist(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int *chanlist,
+ unsigned int n_chan,
+ unsigned int seglen)
{
- const struct boardtype *this_board = dev->board_ptr;
+ const struct boardtype *board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
- unsigned int i, range, chanprog;
+ unsigned int first_chan = CR_CHAN(chanlist[0]);
+ unsigned int last_chan = CR_CHAN(chanlist[seglen - 1]);
+ unsigned int i;
for (i = 0; i < seglen; i++) { /* store range list to card */
- chanprog = muxonechan[CR_CHAN(chanlist[i])];
- outw(chanprog, dev->iobase + PCI171x_MUX); /* select channel */
- range = this_board->rangecode_ai[CR_RANGE(chanlist[i])];
- if (CR_AREF(chanlist[i]) == AREF_DIFF)
- range |= 0x0020;
- outw(range, dev->iobase + PCI171x_RANGE); /* select gain */
- devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
- }
- for ( ; i < n_chan; i++) { /* store remainder of channel list */
- devpriv->act_chanlist[i] =
- (CR_CHAN(chanlist[i]) << 12) & 0xf000;
+ unsigned int chan = CR_CHAN(chanlist[i]);
+ unsigned int range = CR_RANGE(chanlist[i]);
+ unsigned int aref = CR_AREF(chanlist[i]);
+ unsigned int rangeval;
+
+ rangeval = board->rangecode_ai[range];
+ if (aref == AREF_DIFF)
+ rangeval |= 0x0020;
+
+ /* select channel and set range */
+ outw(chan | (chan << 8), dev->iobase + PCI171x_MUX);
+ outw(rangeval, dev->iobase + PCI171x_RANGE);
+
+ devpriv->act_chanlist[i] = chan;
}
+ for ( ; i < n_chan; i++) /* store remainder of channel list */
+ devpriv->act_chanlist[i] = CR_CHAN(chanlist[i]);
- devpriv->ai_et_MuxVal =
- CR_CHAN(chanlist[0]) | (CR_CHAN(chanlist[seglen - 1]) << 8);
/* select channel interval to scan */
+ devpriv->ai_et_MuxVal = first_chan | (last_chan << 8);
outw(devpriv->ai_et_MuxVal, dev->iobase + PCI171x_MUX);
}
@@ -450,9 +391,39 @@ static int pci171x_ai_eoc(struct comedi_device *dev,
return -EBUSY;
}
-static int pci171x_insn_read_ai(struct comedi_device *dev,
+static int pci171x_ai_read_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int cur_chan,
+ unsigned int *val)
+{
+ const struct boardtype *board = dev->board_ptr;
+ struct pci1710_private *devpriv = dev->private;
+ unsigned int sample;
+ unsigned int chan;
+
+ sample = inw(dev->iobase + PCI171x_AD_DATA);
+ if (!board->is_pci1713) {
+ /*
+ * The upper 4 bits of the 16-bit sample are the channel number
+ * that the sample was acquired from. Verify that this channel
+ * number matches the expected channel number.
+ */
+ chan = sample >> 12;
+ if (chan != devpriv->act_chanlist[cur_chan]) {
+ dev_err(dev->class_dev,
+ "A/D data droput: received from channel %d, expected %d\n",
+ chan, devpriv->act_chanlist[cur_chan]);
+ return -ENODATA;
+ }
+ }
+ *val = sample & s->maxdata;
+ return 0;
+}
+
+static int pci171x_ai_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
unsigned int chan = CR_CHAN(insn->chanspec);
@@ -465,7 +436,7 @@ static int pci171x_insn_read_ai(struct comedi_device *dev,
outb(0, dev->iobase + PCI171x_CLRFIFO);
outb(0, dev->iobase + PCI171x_CLRINT);
- setup_channel_list(dev, s, &insn->chanspec, 1, 1);
+ pci171x_ai_setup_chanlist(dev, s, &insn->chanspec, 1, 1);
for (i = 0; i < insn->n; i++) {
unsigned int val;
@@ -476,12 +447,11 @@ static int pci171x_insn_read_ai(struct comedi_device *dev,
if (ret)
break;
- val = inw(dev->iobase + PCI171x_AD_DATA);
- ret = pci171x_ai_dropout(dev, s, chan, val);
+ ret = pci171x_ai_read_sample(dev, s, chan, &val);
if (ret)
break;
- data[i] = val & s->maxdata;
+ data[i] = val;
}
outb(0, dev->iobase + PCI171x_CLRFIFO);
@@ -490,73 +460,43 @@ static int pci171x_insn_read_ai(struct comedi_device *dev,
return ret ? ret : insn->n;
}
-/*
-==============================================================================
-*/
-static int pci171x_insn_write_ao(struct comedi_device *dev,
+static int pci171x_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
- unsigned int val;
- int n, chan, range, ofs;
-
- chan = CR_CHAN(insn->chanspec);
- range = CR_RANGE(insn->chanspec);
- if (chan) {
- devpriv->da_ranges &= 0xfb;
- devpriv->da_ranges |= (range << 2);
- outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
- ofs = PCI171x_DA2;
- } else {
- devpriv->da_ranges &= 0xfe;
- devpriv->da_ranges |= range;
- outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
- ofs = PCI171x_DA1;
- }
- val = devpriv->ao_data[chan];
-
- for (n = 0; n < insn->n; n++) {
- val = data[n];
- outw(val, dev->iobase + ofs);
- }
-
- devpriv->ao_data[chan] = val;
-
- return n;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
+ unsigned int reg = chan ? PCI171x_DA2 : PCI171x_DA1;
+ unsigned int val = s->readback[chan];
+ int i;
-}
+ devpriv->da_ranges &= ~(1 << (chan << 1));
+ devpriv->da_ranges |= (range << (chan << 1));
+ outw(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
-/*
-==============================================================================
-*/
-static int pci171x_insn_read_ao(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
-{
- struct pci1710_private *devpriv = dev->private;
- int n, chan;
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
+ outw(val, dev->iobase + reg);
+ }
- chan = CR_CHAN(insn->chanspec);
- for (n = 0; n < insn->n; n++)
- data[n] = devpriv->ao_data[chan];
+ s->readback[chan] = val;
- return n;
+ return insn->n;
}
-/*
-==============================================================================
-*/
-static int pci171x_insn_bits_di(struct comedi_device *dev,
+static int pci171x_di_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
data[1] = inw(dev->iobase + PCI171x_DI);
return insn->n;
}
-static int pci171x_insn_bits_do(struct comedi_device *dev,
+static int pci171x_do_insn_bits(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -584,10 +524,7 @@ static void pci171x_start_pacer(struct comedi_device *dev,
}
}
-/*
-==============================================================================
-*/
-static int pci171x_insn_counter_read(struct comedi_device *dev,
+static int pci171x_counter_insn_read(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -608,10 +545,7 @@ static int pci171x_insn_counter_read(struct comedi_device *dev,
return insn->n;
}
-/*
-==============================================================================
-*/
-static int pci171x_insn_counter_write(struct comedi_device *dev,
+static int pci171x_counter_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -638,10 +572,7 @@ static int pci171x_insn_counter_write(struct comedi_device *dev,
return insn->n;
}
-/*
-==============================================================================
-*/
-static int pci171x_insn_counter_config(struct comedi_device *dev,
+static int pci171x_counter_insn_config(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_insn *insn,
unsigned int *data)
@@ -677,57 +608,48 @@ static int pci171x_insn_counter_config(struct comedi_device *dev,
return 1;
}
-/*
-==============================================================================
-*/
-static int pci1720_insn_write_ao(struct comedi_device *dev,
+static int pci1720_ao_insn_write(struct comedi_device *dev,
struct comedi_subdevice *s,
- struct comedi_insn *insn, unsigned int *data)
+ struct comedi_insn *insn,
+ unsigned int *data)
{
struct pci1710_private *devpriv = dev->private;
+ unsigned int chan = CR_CHAN(insn->chanspec);
+ unsigned int range = CR_RANGE(insn->chanspec);
unsigned int val;
- int n, rangereg, chan;
-
- chan = CR_CHAN(insn->chanspec);
- rangereg = devpriv->da_ranges & (~(0x03 << (chan << 1)));
- rangereg |= (CR_RANGE(insn->chanspec) << (chan << 1));
- if (rangereg != devpriv->da_ranges) {
- outb(rangereg, dev->iobase + PCI1720_RANGE);
- devpriv->da_ranges = rangereg;
+ int i;
+
+ val = devpriv->da_ranges & (~(0x03 << (chan << 1)));
+ val |= (range << (chan << 1));
+ if (val != devpriv->da_ranges) {
+ outb(val, dev->iobase + PCI1720_RANGE);
+ devpriv->da_ranges = val;
}
- val = devpriv->ao_data[chan];
- for (n = 0; n < insn->n; n++) {
- val = data[n];
+ val = s->readback[chan];
+ for (i = 0; i < insn->n; i++) {
+ val = data[i];
outw(val, dev->iobase + PCI1720_DA0 + (chan << 1));
- outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
+ outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
}
- devpriv->ao_data[chan] = val;
+ s->readback[chan] = val;
- return n;
+ return insn->n;
}
-/*
-==============================================================================
-*/
static int pci171x_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
- switch (this_board->cardtype) {
- default:
- devpriv->CntrlReg &= Control_CNT0;
- devpriv->CntrlReg |= Control_SW;
- /* reset any operations */
- outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
- pci171x_start_pacer(dev, false);
- outb(0, dev->iobase + PCI171x_CLRFIFO);
- outb(0, dev->iobase + PCI171x_CLRINT);
- break;
- }
+ devpriv->CntrlReg &= Control_CNT0;
+ devpriv->CntrlReg |= Control_SW;
+ /* reset any operations */
+ outw(devpriv->CntrlReg, dev->iobase + PCI171x_CONTROL);
+ pci171x_start_pacer(dev, false);
+ outb(0, dev->iobase + PCI171x_CLRFIFO);
+ outb(0, dev->iobase + PCI171x_CLRINT);
return 0;
}
@@ -743,29 +665,25 @@ static void pci1710_handle_every_sample(struct comedi_device *dev,
status = inw(dev->iobase + PCI171x_STATUS);
if (status & Status_FE) {
dev_dbg(dev->class_dev, "A/D FIFO empty (%4x)\n", status);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_handle_events(dev, s);
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
if (status & Status_FF) {
dev_dbg(dev->class_dev,
"A/D FIFO Full status (Fatal Error!) (%4x)\n", status);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_handle_events(dev, s);
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
for (; !(inw(dev->iobase + PCI171x_STATUS) & Status_FE);) {
- val = inw(dev->iobase + PCI171x_AD_DATA);
- ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
+ ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
if (ret) {
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
break;
}
- val &= s->maxdata;
comedi_buf_write_samples(s, &val, 1);
if (cmd->stop_src == TRIG_COUNT &&
@@ -776,85 +694,53 @@ static void pci1710_handle_every_sample(struct comedi_device *dev,
}
outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
-
- comedi_handle_events(dev, s);
-}
-
-/*
-==============================================================================
-*/
-static int move_block_from_fifo(struct comedi_device *dev,
- struct comedi_subdevice *s, int n, int turn)
-{
- unsigned int val;
- int ret;
- int i;
-
- for (i = 0; i < n; i++) {
- val = inw(dev->iobase + PCI171x_AD_DATA);
-
- ret = pci171x_ai_dropout(dev, s, s->async->cur_chan, val);
- if (ret) {
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- return ret;
- }
-
- val &= s->maxdata;
- comedi_buf_write_samples(s, &val, 1);
- }
- return 0;
}
static void pci1710_handle_fifo(struct comedi_device *dev,
struct comedi_subdevice *s)
{
- const struct boardtype *this_board = dev->board_ptr;
- struct comedi_cmd *cmd = &s->async->cmd;
- unsigned int nsamples;
- unsigned int m;
-
- m = inw(dev->iobase + PCI171x_STATUS);
- if (!(m & Status_FH)) {
- dev_dbg(dev->class_dev, "A/D FIFO not half full! (%4x)\n", m);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_handle_events(dev, s);
+ struct pci1710_private *devpriv = dev->private;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned int status;
+ int i;
+
+ status = inw(dev->iobase + PCI171x_STATUS);
+ if (!(status & Status_FH)) {
+ dev_dbg(dev->class_dev, "A/D FIFO not half full!\n");
+ async->events |= COMEDI_CB_ERROR;
return;
}
- if (m & Status_FF) {
+ if (status & Status_FF) {
dev_dbg(dev->class_dev,
- "A/D FIFO Full status (Fatal Error!) (%4x)\n", m);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- comedi_handle_events(dev, s);
+ "A/D FIFO Full status (Fatal Error!)\n");
+ async->events |= COMEDI_CB_ERROR;
return;
}
- nsamples = this_board->fifo_half_size;
- if (comedi_samples_to_bytes(s, nsamples) >= s->async->prealloc_bufsz) {
- m = comedi_bytes_to_samples(s, s->async->prealloc_bufsz);
- if (move_block_from_fifo(dev, s, m, 0))
- return;
- nsamples -= m;
- }
+ for (i = 0; i < devpriv->max_samples; i++) {
+ unsigned int val;
+ int ret;
- if (nsamples) {
- if (move_block_from_fifo(dev, s, nsamples, 1))
- return;
- }
+ ret = pci171x_ai_read_sample(dev, s, s->async->cur_chan, &val);
+ if (ret) {
+ s->async->events |= COMEDI_CB_ERROR;
+ break;
+ }
- if (cmd->stop_src == TRIG_COUNT &&
- s->async->scans_done >= cmd->stop_arg) {
- s->async->events |= COMEDI_CB_EOA;
- comedi_handle_events(dev, s);
- return;
+ if (!comedi_buf_write_samples(s, &val, 1))
+ break;
+
+ if (cmd->stop_src == TRIG_COUNT &&
+ async->scans_done >= cmd->stop_arg) {
+ async->events |= COMEDI_CB_EOA;
+ break;
+ }
}
- outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
- comedi_handle_events(dev, s);
+ outb(0, dev->iobase + PCI171x_CLRINT); /* clear our INT request */
}
-/*
-==============================================================================
-*/
static irqreturn_t interrupt_service_pci1710(int irq, void *d)
{
struct comedi_device *dev = d;
@@ -891,6 +777,8 @@ static irqreturn_t interrupt_service_pci1710(int irq, void *d)
else
pci1710_handle_fifo(dev, s);
+ comedi_handle_events(dev, s);
+
return IRQ_HANDLED;
}
@@ -901,8 +789,8 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
pci171x_start_pacer(dev, false);
- setup_channel_list(dev, s, cmd->chanlist, cmd->chanlist_len,
- devpriv->saved_seglen);
+ pci171x_ai_setup_chanlist(dev, s, cmd->chanlist, cmd->chanlist_len,
+ devpriv->saved_seglen);
outb(0, dev->iobase + PCI171x_CLRFIFO);
outb(0, dev->iobase + PCI171x_CLRINT);
@@ -937,14 +825,10 @@ static int pci171x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
return 0;
}
-/*
-==============================================================================
-*/
static int pci171x_ai_cmdtest(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
{
- const struct boardtype *this_board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
int err = 0;
unsigned int arg;
@@ -977,8 +861,7 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
if (cmd->convert_src == TRIG_TIMER)
- err |= cfc_check_trigger_arg_min(&cmd->convert_arg,
- this_board->ai_ns_min);
+ err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 10000);
else /* TRIG_FOLLOW */
err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
@@ -1016,12 +899,9 @@ static int pci171x_ai_cmdtest(struct comedi_device *dev,
return 0;
}
-/*
-==============================================================================
-*/
static int pci171x_reset(struct comedi_device *dev)
{
- const struct boardtype *this_board = dev->board_ptr;
+ const struct boardtype *board = dev->board_ptr;
struct pci1710_private *devpriv = dev->private;
outw(0x30, dev->iobase + PCI171x_CNTCTRL);
@@ -1033,15 +913,11 @@ static int pci171x_reset(struct comedi_device *dev)
outb(0, dev->iobase + PCI171x_CLRINT); /* clear INT request */
pci171x_start_pacer(dev, false);
devpriv->da_ranges = 0;
- if (this_board->n_aochan) {
+ if (board->has_ao) {
/* set DACs to 0..5V */
outb(devpriv->da_ranges, dev->iobase + PCI171x_DAREF);
outw(0, dev->iobase + PCI171x_DA1); /* set DA outputs to 0V */
- devpriv->ao_data[0] = 0x0000;
- if (this_board->n_aochan > 1) {
- outw(0, dev->iobase + PCI171x_DA2);
- devpriv->ao_data[1] = 0x0000;
- }
+ outw(0, dev->iobase + PCI171x_DA2);
}
outw(0, dev->iobase + PCI171x_DO); /* digital outputs to 0 */
outb(0, dev->iobase + PCI171x_CLRFIFO); /* clear FIFO */
@@ -1050,9 +926,6 @@ static int pci171x_reset(struct comedi_device *dev)
return 0;
}
-/*
-==============================================================================
-*/
static int pci1720_reset(struct comedi_device *dev)
{
struct pci1710_private *devpriv = dev->private;
@@ -1066,43 +939,35 @@ static int pci1720_reset(struct comedi_device *dev)
outw(0x0800, dev->iobase + PCI1720_DA2);
outw(0x0800, dev->iobase + PCI1720_DA3);
outb(0, dev->iobase + PCI1720_SYNCOUT); /* update outputs */
- devpriv->ao_data[0] = 0x0800;
- devpriv->ao_data[1] = 0x0800;
- devpriv->ao_data[2] = 0x0800;
- devpriv->ao_data[3] = 0x0800;
+
return 0;
}
-/*
-==============================================================================
-*/
static int pci1710_reset(struct comedi_device *dev)
{
- const struct boardtype *this_board = dev->board_ptr;
+ const struct boardtype *board = dev->board_ptr;
- switch (this_board->cardtype) {
- case TYPE_PCI1720:
+ if (board->is_pci1720)
return pci1720_reset(dev);
- default:
- return pci171x_reset(dev);
- }
+
+ return pci171x_reset(dev);
}
static int pci1710_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
- const struct boardtype *this_board = NULL;
+ const struct boardtype *board = NULL;
struct pci1710_private *devpriv;
struct comedi_subdevice *s;
int ret, subdev, n_subdevices;
if (context < ARRAY_SIZE(boardtypes))
- this_board = &boardtypes[context];
- if (!this_board)
+ board = &boardtypes[context];
+ if (!board)
return -ENODEV;
- dev->board_ptr = this_board;
- dev->board_name = this_board->name;
+ dev->board_ptr = board;
+ dev->board_name = board->name;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -1114,15 +979,13 @@ static int pci1710_auto_attach(struct comedi_device *dev,
dev->iobase = pci_resource_start(pcidev, 2);
n_subdevices = 0;
- if (this_board->n_aichan)
- n_subdevices++;
- if (this_board->n_aochan)
- n_subdevices++;
- if (this_board->n_dichan)
+ if (board->n_aichan)
n_subdevices++;
- if (this_board->n_dochan)
+ if (board->has_ao)
n_subdevices++;
- if (this_board->n_counter)
+ if (board->has_di_do)
+ n_subdevices += 2;
+ if (board->has_counter)
n_subdevices++;
ret = comedi_alloc_subdevices(dev, n_subdevices);
@@ -1131,7 +994,7 @@ static int pci1710_auto_attach(struct comedi_device *dev,
pci1710_reset(dev);
- if (this_board->have_irq && pcidev->irq) {
+ if (board->has_irq && pcidev->irq) {
ret = request_irq(pcidev->irq, interrupt_service_pci1710,
IRQF_SHARED, dev->board_name, dev);
if (ret == 0)
@@ -1140,85 +1003,93 @@ static int pci1710_auto_attach(struct comedi_device *dev,
subdev = 0;
- if (this_board->n_aichan) {
+ if (board->n_aichan) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AI;
- s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
- if (this_board->n_aichand)
- s->subdev_flags |= SDF_DIFF;
- s->n_chan = this_board->n_aichan;
- s->maxdata = this_board->ai_maxdata;
- s->range_table = this_board->rangelist_ai;
- s->insn_read = pci171x_insn_read_ai;
+ s->type = COMEDI_SUBD_AI;
+ s->subdev_flags = SDF_READABLE | SDF_COMMON | SDF_GROUND;
+ if (board->has_diff_ai)
+ s->subdev_flags |= SDF_DIFF;
+ s->n_chan = board->n_aichan;
+ s->maxdata = 0x0fff;
+ s->range_table = board->rangelist_ai;
+ s->insn_read = pci171x_ai_insn_read;
if (dev->irq) {
dev->read_subdev = s;
- s->subdev_flags |= SDF_CMD_READ;
- s->len_chanlist = s->n_chan;
- s->do_cmdtest = pci171x_ai_cmdtest;
- s->do_cmd = pci171x_ai_cmd;
- s->cancel = pci171x_ai_cancel;
+ s->subdev_flags |= SDF_CMD_READ;
+ s->len_chanlist = s->n_chan;
+ s->do_cmdtest = pci171x_ai_cmdtest;
+ s->do_cmd = pci171x_ai_cmd;
+ s->cancel = pci171x_ai_cancel;
}
subdev++;
}
- if (this_board->n_aochan) {
+ if (board->has_ao) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_AO;
- s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
- s->n_chan = this_board->n_aochan;
- s->maxdata = this_board->ao_maxdata;
- s->len_chanlist = this_board->n_aochan;
- s->range_table = this_board->rangelist_ao;
- switch (this_board->cardtype) {
- case TYPE_PCI1720:
- s->insn_write = pci1720_insn_write_ao;
- break;
- default:
- s->insn_write = pci171x_insn_write_ao;
- break;
+ s->type = COMEDI_SUBD_AO;
+ s->subdev_flags = SDF_WRITABLE | SDF_GROUND | SDF_COMMON;
+ s->maxdata = 0x0fff;
+ if (board->is_pci1720) {
+ s->n_chan = 4;
+ s->range_table = &pci1720_ao_range;
+ s->insn_write = pci1720_ao_insn_write;
+ } else {
+ s->n_chan = 2;
+ s->range_table = &pci171x_ao_range;
+ s->insn_write = pci171x_ao_insn_write;
}
- s->insn_read = pci171x_insn_read_ao;
+
+ ret = comedi_alloc_subdev_readback(s);
+ if (ret)
+ return ret;
+
+ /* initialize the readback values to match the board reset */
+ if (board->is_pci1720) {
+ int i;
+
+ for (i = 0; i < s->n_chan; i++)
+ s->readback[i] = 0x0800;
+ }
+
subdev++;
}
- if (this_board->n_dichan) {
+ if (board->has_di_do) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DI;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = this_board->n_dichan;
- s->maxdata = 1;
- s->len_chanlist = this_board->n_dichan;
- s->range_table = &range_digital;
- s->insn_bits = pci171x_insn_bits_di;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci171x_di_insn_bits;
subdev++;
- }
- if (this_board->n_dochan) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_DO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = this_board->n_dochan;
- s->maxdata = 1;
- s->len_chanlist = this_board->n_dochan;
- s->range_table = &range_digital;
- s->insn_bits = pci171x_insn_bits_do;
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = pci171x_do_insn_bits;
subdev++;
}
- if (this_board->n_counter) {
+ if (board->has_counter) {
s = &dev->subdevices[subdev];
- s->type = COMEDI_SUBD_COUNTER;
- s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
- s->n_chan = this_board->n_counter;
- s->len_chanlist = this_board->n_counter;
- s->maxdata = 0xffff;
- s->range_table = &range_unknown;
- s->insn_read = pci171x_insn_counter_read;
- s->insn_write = pci171x_insn_counter_write;
- s->insn_config = pci171x_insn_counter_config;
+ s->type = COMEDI_SUBD_COUNTER;
+ s->subdev_flags = SDF_READABLE | SDF_WRITABLE;
+ s->n_chan = 1;
+ s->maxdata = 0xffff;
+ s->range_table = &range_unknown;
+ s->insn_read = pci171x_counter_insn_read;
+ s->insn_write = pci171x_counter_insn_write;
+ s->insn_config = pci171x_counter_insn_config;
subdev++;
}
+ /* max_samples is half the FIFO size (2 bytes/sample) */
+ devpriv->max_samples = (board->has_large_fifo) ? 2048 : 512;
+
return 0;
}
@@ -1312,5 +1183,5 @@ static struct pci_driver adv_pci1710_pci_driver = {
module_comedi_pci_driver(adv_pci1710_driver, adv_pci1710_pci_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi: Advantech PCI-1710 Series Multifunction DAS Cards");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/adv_pci1723.c b/drivers/staging/comedi/drivers/adv_pci1723.c
index 65f854e1eb66..f1945be89eff 100644
--- a/drivers/staging/comedi/drivers/adv_pci1723.c
+++ b/drivers/staging/comedi/drivers/adv_pci1723.c
@@ -20,7 +20,7 @@
* Driver: adv_pci1723
* Description: Advantech PCI-1723
* Author: yonggang <rsmgnu@gmail.com>, Ian Abbott <abbotti@mev.co.uk>
- * Devices: (Advantech) PCI-1723 [adv_pci1723]
+ * Devices: [Advantech] PCI-1723 (adv_pci1723)
* Updated: Mon, 14 Apr 2008 15:12:56 +0100
* Status: works
*
diff --git a/drivers/staging/comedi/drivers/adv_pci1724.c b/drivers/staging/comedi/drivers/adv_pci1724.c
index a8d28403262e..a3573ea6f9c0 100644
--- a/drivers/staging/comedi/drivers/adv_pci1724.c
+++ b/drivers/staging/comedi/drivers/adv_pci1724.c
@@ -22,7 +22,7 @@
/*
* Driver: adv_pci1724
* Description: Advantech PCI-1724U
- * Devices: (Advantech) PCI-1724U [adv_pci1724]
+ * Devices: [Advantech] PCI-1724U (adv_pci1724)
* Author: Frank Mori Hess <fmh6jj@gmail.com>
* Updated: 2013-02-09
* Status: works
diff --git a/drivers/staging/comedi/drivers/aio_iiro_16.c b/drivers/staging/comedi/drivers/aio_iiro_16.c
index 7b5ed439c164..1c7b325a373c 100644
--- a/drivers/staging/comedi/drivers/aio_iiro_16.c
+++ b/drivers/staging/comedi/drivers/aio_iiro_16.c
@@ -1,48 +1,155 @@
/*
+ * aio_iiro_16.c
+ * Comedi driver for Access I/O Products 104-IIRO-16 board
+ * Copyright (C) 2006 C&C Technologies, 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.
+ */
- comedi/drivers/aio_iiro_16.c
+/*
+ * Driver: aio_iiro_16
+ * Description: Access I/O Products PC/104 Isolated Input/Relay Output Board
+ * Author: Zachary Ware <zach.ware@cctechnol.com>
+ * Devices: [Access I/O] 104-IIRO-16 (aio_iiro_16)
+ * Status: experimental
+ *
+ * Configuration Options:
+ * [0] - I/O port base address
+ * [1] - IRQ (optional)
+ *
+ * The board supports interrupts on change of state of the digital inputs.
+ * The sample data returned by the async command indicates which inputs
+ * changed state and the current state of the inputs:
+ *
+ * Bit 23 - IRQ Enable (1) / Disable (0)
+ * Bit 17 - Input 8-15 Changed State (1 = Changed, 0 = No Change)
+ * Bit 16 - Input 0-7 Changed State (1 = Changed, 0 = No Change)
+ * Bit 15 - Digital input 15
+ * ...
+ * Bit 0 - Digital input 0
+ */
- Driver for Access I/O Products PC-104 AIO-IIRO-16 Digital I/O board
- Copyright (C) 2006 C&C Technologies, Inc.
+#include <linux/module.h>
+#include <linux/interrupt.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.
+#include "../comedidev.h"
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+#include "comedi_fc.h"
-/*
+#define AIO_IIRO_16_RELAY_0_7 0x00
+#define AIO_IIRO_16_INPUT_0_7 0x01
+#define AIO_IIRO_16_IRQ 0x02
+#define AIO_IIRO_16_RELAY_8_15 0x04
+#define AIO_IIRO_16_INPUT_8_15 0x05
+#define AIO_IIRO_16_STATUS 0x07
+#define AIO_IIRO_16_STATUS_IRQE BIT(7)
+#define AIO_IIRO_16_STATUS_INPUT_8_15 BIT(1)
+#define AIO_IIRO_16_STATUS_INPUT_0_7 BIT(0)
-Driver: aio_iiro_16
-Description: Access I/O Products PC-104 IIRO16 Relay And Isolated Input Board
-Author: Zachary Ware <zach.ware@cctechnol.com>
-Devices:
- [Access I/O] PC-104 AIO12-8
-Status: experimental
+static unsigned int aio_iiro_16_read_inputs(struct comedi_device *dev)
+{
+ unsigned int val;
-Configuration Options:
- [0] - I/O port base address
+ val = inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
+ val |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
-*/
+ return val;
+}
-#include <linux/module.h>
-#include "../comedidev.h"
+static irqreturn_t aio_iiro_16_cos(int irq, void *d)
+{
+ struct comedi_device *dev = d;
+ struct comedi_subdevice *s = dev->read_subdev;
+ unsigned int status;
+ unsigned int val;
+
+ status = inb(dev->iobase + AIO_IIRO_16_STATUS);
+ if (!(status & AIO_IIRO_16_STATUS_IRQE))
+ return IRQ_NONE;
+
+ val = aio_iiro_16_read_inputs(dev);
+ val |= (status << 16);
+
+ comedi_buf_write_samples(s, &val, 1);
+ comedi_handle_events(dev, s);
+
+ return IRQ_HANDLED;
+}
+
+static void aio_iiro_enable_irq(struct comedi_device *dev, bool enable)
+{
+ if (enable)
+ inb(dev->iobase + AIO_IIRO_16_IRQ);
+ else
+ outb(0, dev->iobase + AIO_IIRO_16_IRQ);
+}
+
+static int aio_iiro_16_cos_cancel(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ aio_iiro_enable_irq(dev, false);
+
+ return 0;
+}
-#define AIO_IIRO_16_RELAY_0_7 0x00
-#define AIO_IIRO_16_INPUT_0_7 0x01
-#define AIO_IIRO_16_IRQ 0x02
-#define AIO_IIRO_16_RELAY_8_15 0x04
-#define AIO_IIRO_16_INPUT_8_15 0x05
+static int aio_iiro_16_cos_cmd(struct comedi_device *dev,
+ struct comedi_subdevice *s)
+{
+ aio_iiro_enable_irq(dev, true);
+
+ return 0;
+}
+
+static int aio_iiro_16_cos_cmdtest(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_cmd *cmd)
+{
+ int err = 0;
+
+ /* Step 1 : check if triggers are trivially valid */
+
+ err |= cfc_check_trigger_src(&cmd->start_src, TRIG_NOW);
+ err |= cfc_check_trigger_src(&cmd->scan_begin_src, TRIG_EXT);
+ err |= cfc_check_trigger_src(&cmd->convert_src, TRIG_FOLLOW);
+ err |= cfc_check_trigger_src(&cmd->scan_end_src, TRIG_COUNT);
+ err |= cfc_check_trigger_src(&cmd->stop_src, TRIG_NONE);
+
+ if (err)
+ return 1;
+
+ /* Step 2a : make sure trigger sources are unique */
+ /* Step 2b : and mutually compatible */
+
+ /* Step 3: check if arguments are trivially valid */
-static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+ err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->convert_arg, 0);
+ err |= cfc_check_trigger_arg_is(&cmd->scan_end_arg, cmd->chanlist_len);
+ err |= cfc_check_trigger_arg_is(&cmd->stop_arg, 0);
+
+ if (err)
+ return 3;
+
+ /* Step 4: fix up any arguments */
+
+ /* Step 5: check channel list if it exists */
+
+ return 0;
+}
+
+static int aio_iiro_16_do_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
if (comedi_dio_update_state(s, data)) {
outb(s->state & 0xff, dev->iobase + AIO_IIRO_16_RELAY_0_7);
@@ -55,14 +162,12 @@ static int aio_iiro_16_dio_insn_bits_write(struct comedi_device *dev,
return insn->n;
}
-static int aio_iiro_16_dio_insn_bits_read(struct comedi_device *dev,
- struct comedi_subdevice *s,
- struct comedi_insn *insn,
- unsigned int *data)
+static int aio_iiro_16_di_insn_bits(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_insn *insn,
+ unsigned int *data)
{
- data[1] = 0;
- data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_0_7);
- data[1] |= inb(dev->iobase + AIO_IIRO_16_INPUT_8_15) << 8;
+ data[1] = aio_iiro_16_read_inputs(dev);
return insn->n;
}
@@ -77,25 +182,52 @@ static int aio_iiro_16_attach(struct comedi_device *dev,
if (ret)
return ret;
+ aio_iiro_enable_irq(dev, false);
+
+ /*
+ * Digital input change of state interrupts are optionally supported
+ * using IRQ 2-7, 10-12, 14, or 15.
+ */
+ if ((1 << it->options[1]) & 0xdcfc) {
+ ret = request_irq(it->options[1], aio_iiro_16_cos, 0,
+ dev->board_name, dev);
+ if (ret == 0)
+ dev->irq = it->options[1];
+ }
+
ret = comedi_alloc_subdevices(dev, 2);
if (ret)
return ret;
+ /* Digital Output subdevice */
s = &dev->subdevices[0];
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_WRITABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = aio_iiro_16_dio_insn_bits_write;
-
+ s->type = COMEDI_SUBD_DO;
+ s->subdev_flags = SDF_WRITABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = aio_iiro_16_do_insn_bits;
+
+ /* get the initial state of the relays */
+ s->state = inb(dev->iobase + AIO_IIRO_16_RELAY_0_7) |
+ (inb(dev->iobase + AIO_IIRO_16_RELAY_8_15) << 8);
+
+ /* Digital Input subdevice */
s = &dev->subdevices[1];
- s->type = COMEDI_SUBD_DIO;
- s->subdev_flags = SDF_READABLE;
- s->n_chan = 16;
- s->maxdata = 1;
- s->range_table = &range_digital;
- s->insn_bits = aio_iiro_16_dio_insn_bits_read;
+ s->type = COMEDI_SUBD_DI;
+ s->subdev_flags = SDF_READABLE;
+ s->n_chan = 16;
+ s->maxdata = 1;
+ s->range_table = &range_digital;
+ s->insn_bits = aio_iiro_16_di_insn_bits;
+ if (dev->irq) {
+ dev->read_subdev = s;
+ s->subdev_flags |= SDF_CMD_READ | SDF_LSAMPL;
+ s->len_chanlist = 1;
+ s->do_cmdtest = aio_iiro_16_cos_cmdtest;
+ s->do_cmd = aio_iiro_16_cos_cmd;
+ s->cancel = aio_iiro_16_cos_cancel;
+ }
return 0;
}
@@ -109,5 +241,5 @@ static struct comedi_driver aio_iiro_16_driver = {
module_comedi_driver(aio_iiro_16_driver);
MODULE_AUTHOR("Comedi http://www.comedi.org");
-MODULE_DESCRIPTION("Comedi low-level driver");
+MODULE_DESCRIPTION("Comedi driver for Access I/O Products 104-IIRO-16 board");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/c6xdigio.c b/drivers/staging/comedi/drivers/c6xdigio.c
index e7cb7032a910..1a109e30d8ff 100644
--- a/drivers/staging/comedi/drivers/c6xdigio.c
+++ b/drivers/staging/comedi/drivers/c6xdigio.c
@@ -22,7 +22,7 @@
* Description: Mechatronic Systems Inc. C6x_DIGIO DSP daughter card
* Author: Dan Block
* Status: unknown
- * Devices: (Mechatronic Systems Inc.) C6x_DIGIO DSP daughter card [c6xdigio]
+ * Devices: [Mechatronic Systems Inc.] C6x_DIGIO DSP daughter card (c6xdigio)
* Updated: Sun Nov 20 20:18:34 EST 2005
*
* Configuration Options:
diff --git a/drivers/staging/comedi/drivers/cb_das16_cs.c b/drivers/staging/comedi/drivers/cb_das16_cs.c
index 0a48d2a961d5..1079b6c72b15 100644
--- a/drivers/staging/comedi/drivers/cb_das16_cs.c
+++ b/drivers/staging/comedi/drivers/cb_das16_cs.c
@@ -38,10 +38,7 @@ Status: experimental
#include <linux/interrupt.h>
#include <linux/delay.h>
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
#include "comedi_fc.h"
#include "8253.h"
diff --git a/drivers/staging/comedi/drivers/cb_pcidas.c b/drivers/staging/comedi/drivers/cb_pcidas.c
index 669b1703eb99..dd0c65a5b5a0 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas.c
@@ -1355,7 +1355,7 @@ static irqreturn_t cb_pcidas_interrupt(int irq, void *d)
outw(devpriv->adc_fifo_bits | LADFUL,
devpriv->control_status + INT_ADCFIFO);
spin_unlock_irqrestore(&dev->spinlock, flags);
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
}
comedi_handle_events(dev, s);
diff --git a/drivers/staging/comedi/drivers/cb_pcidas64.c b/drivers/staging/comedi/drivers/cb_pcidas64.c
index eddb7ace43df..5b43e4e6d037 100644
--- a/drivers/staging/comedi/drivers/cb_pcidas64.c
+++ b/drivers/staging/comedi/drivers/cb_pcidas64.c
@@ -439,6 +439,29 @@ static const struct comedi_lrange ai_ranges_64xx = {
}
};
+static const uint8_t ai_range_code_64xx[8] = {
+ 0x0, 0x1, 0x2, 0x3, /* bipolar 10, 5, 2,5, 1.25 */
+ 0x8, 0x9, 0xa, 0xb /* unipolar 10, 5, 2.5, 1.25 */
+};
+
+/* analog input ranges for 64-Mx boards */
+static const struct comedi_lrange ai_ranges_64_mx = {
+ 7, {
+ BIP_RANGE(5),
+ BIP_RANGE(2.5),
+ BIP_RANGE(1.25),
+ BIP_RANGE(0.625),
+ UNI_RANGE(5),
+ UNI_RANGE(2.5),
+ UNI_RANGE(1.25)
+ }
+};
+
+static const uint8_t ai_range_code_64_mx[7] = {
+ 0x0, 0x1, 0x2, 0x3, /* bipolar 5, 2.5, 1.25, 0.625 */
+ 0x9, 0xa, 0xb /* unipolar 5, 2.5, 1.25 */
+};
+
/* analog input ranges for 60xx boards */
static const struct comedi_lrange ai_ranges_60xx = {
4, {
@@ -449,6 +472,10 @@ static const struct comedi_lrange ai_ranges_60xx = {
}
};
+static const uint8_t ai_range_code_60xx[4] = {
+ 0x0, 0x1, 0x4, 0x7 /* bipolar 10, 5, 0.5, 0.05 */
+};
+
/* analog input ranges for 6030, etc boards */
static const struct comedi_lrange ai_ranges_6030 = {
14, {
@@ -469,6 +496,11 @@ static const struct comedi_lrange ai_ranges_6030 = {
}
};
+static const uint8_t ai_range_code_6030[14] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, /* bip 10, 5, 2, 1, 0.5, 0.2, 0.1 */
+ 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* uni 10, 5, 2, 1, 0.5, 0.2, 0.1 */
+};
+
/* analog input ranges for 6052, etc boards */
static const struct comedi_lrange ai_ranges_6052 = {
15, {
@@ -490,6 +522,11 @@ static const struct comedi_lrange ai_ranges_6052 = {
}
};
+static const uint8_t ai_range_code_6052[15] = {
+ 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, /* bipolar 10 ... 0.05 */
+ 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf /* unipolar 10 ... 0.1 */
+};
+
/* analog input ranges for 4020 board */
static const struct comedi_lrange ai_ranges_4020 = {
2, {
@@ -593,6 +630,7 @@ struct pcidas64_board {
int ai_bits; /* analog input resolution */
int ai_speed; /* fastest conversion period in ns */
const struct comedi_lrange *ai_range_table;
+ const uint8_t *ai_range_code;
int ao_nchan; /* number of analog out channels */
int ao_bits; /* analog output resolution */
int ao_scan_speed; /* analog output scan speed */
@@ -651,6 +689,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
.ai_range_table = &ai_ranges_64xx,
+ .ai_range_code = ai_range_code_64xx,
.ao_range_table = &ao_ranges_64xx,
.ao_range_code = ao_range_code_64xx,
.ai_fifo = &ai_fifo_64xx,
@@ -666,6 +705,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
.ai_range_table = &ai_ranges_64xx,
+ .ai_range_code = ai_range_code_64xx,
.ao_range_table = &ao_ranges_64xx,
.ao_range_code = ao_range_code_64xx,
.ai_fifo = &ai_fifo_64xx,
@@ -680,7 +720,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_bits = 16,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ao_range_table = &ao_ranges_64xx,
.ao_range_code = ao_range_code_64xx,
.ai_fifo = &ai_fifo_64xx,
@@ -695,7 +736,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_bits = 16,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ao_range_table = &ao_ranges_64xx,
.ao_range_code = ao_range_code_64xx,
.ai_fifo = &ai_fifo_64xx,
@@ -710,7 +752,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_bits = 16,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ao_range_table = &ao_ranges_64xx,
.ao_range_code = ao_range_code_64xx,
.ai_fifo = &ai_fifo_64xx,
@@ -725,6 +768,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_bits = 16,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ao_range_table = &range_bipolar10,
.ao_range_code = ao_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
@@ -740,6 +784,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 100000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ao_range_table = &range_bipolar10,
.ao_range_code = ao_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
@@ -754,6 +799,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 100000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ao_range_table = &range_bipolar10,
.ao_range_code = ao_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
@@ -769,6 +815,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 100000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ao_range_table = &range_bipolar10,
.ao_range_code = ao_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
@@ -784,6 +831,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 10000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6030,
+ .ai_range_code = ai_range_code_6030,
.ao_range_table = &ao_ranges_6030,
.ao_range_code = ao_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
@@ -799,6 +847,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 10000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6030,
+ .ai_range_code = ai_range_code_6030,
.ao_range_table = &ao_ranges_6030,
.ao_range_code = ao_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
@@ -812,6 +861,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 0,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6030,
+ .ai_range_code = ai_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
.has_8255 = 0,
},
@@ -823,6 +873,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 0,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6030,
+ .ai_range_code = ai_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
.has_8255 = 0,
},
@@ -835,6 +886,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 0,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
.has_8255 = 0,
},
@@ -848,6 +900,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 100000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ao_range_table = &range_bipolar10,
.ao_range_code = ao_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
@@ -863,6 +916,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 100000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_60xx,
+ .ai_range_code = ai_range_code_60xx,
.ao_range_table = &range_bipolar10,
.ao_range_code = ao_range_code_60xx,
.ai_fifo = &ai_fifo_60xx,
@@ -878,6 +932,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 1000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6052,
+ .ai_range_code = ai_range_code_6052,
.ao_range_table = &ao_ranges_6030,
.ao_range_code = ao_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
@@ -893,6 +948,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 3333,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6052,
+ .ai_range_code = ai_range_code_6052,
.ao_range_table = &ao_ranges_6030,
.ao_range_code = ao_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
@@ -908,6 +964,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 1000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6052,
+ .ai_range_code = ai_range_code_6052,
.ao_range_table = &ao_ranges_6030,
.ao_range_code = ao_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
@@ -923,6 +980,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 1000,
.layout = LAYOUT_60XX,
.ai_range_table = &ai_ranges_6052,
+ .ai_range_code = ai_range_code_6052,
.ao_range_table = &ao_ranges_6030,
.ao_range_code = ao_range_code_6030,
.ai_fifo = &ai_fifo_60xx,
@@ -957,6 +1015,7 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
.ai_range_table = &ai_ranges_64xx,
+ .ai_range_code = ai_range_code_64xx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -968,7 +1027,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 0,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -980,7 +1040,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 0,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -992,7 +1053,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 0,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -1004,7 +1066,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 2,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -1016,7 +1079,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 2,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -1028,7 +1092,8 @@ static const struct pcidas64_board pcidas64_boards[] = {
.ao_nchan = 2,
.ao_scan_speed = 10000,
.layout = LAYOUT_64XX,
- .ai_range_table = &ai_ranges_64xx,
+ .ai_range_table = &ai_ranges_64_mx,
+ .ai_range_code = ai_range_code_64_mx,
.ai_fifo = ai_fifo_64xx,
.has_8255 = 1,
},
@@ -1115,45 +1180,8 @@ static unsigned int ai_range_bits_6xxx(const struct comedi_device *dev,
unsigned int range_index)
{
const struct pcidas64_board *thisboard = dev->board_ptr;
- const struct comedi_krange *range =
- &thisboard->ai_range_table->range[range_index];
- unsigned int bits = 0;
- switch (range->max) {
- case 10000000:
- bits = 0x000;
- break;
- case 5000000:
- bits = 0x100;
- break;
- case 2000000:
- case 2500000:
- bits = 0x200;
- break;
- case 1000000:
- case 1250000:
- bits = 0x300;
- break;
- case 500000:
- bits = 0x400;
- break;
- case 200000:
- case 250000:
- bits = 0x500;
- break;
- case 100000:
- bits = 0x600;
- break;
- case 50000:
- bits = 0x700;
- break;
- default:
- dev_err(dev->class_dev, "bug! in %s\n", __func__);
- break;
- }
- if (range->min == 0)
- bits += 0x900;
- return bits;
+ return thisboard->ai_range_code[range_index] << 8;
}
static unsigned int hw_revision(const struct comedi_device *dev,
@@ -2776,7 +2804,7 @@ static void handle_ai_interrupt(struct comedi_device *dev,
/* check for fifo overrun */
if (status & ADC_OVERRUN_BIT) {
dev_err(dev->class_dev, "fifo overrun\n");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
}
/* spin lock makes sure no one else changes plx dma control reg */
spin_lock_irqsave(&dev->spinlock, flags);
diff --git a/drivers/staging/comedi/drivers/cb_pcidda.c b/drivers/staging/comedi/drivers/cb_pcidda.c
index 01875d7c376f..2b2cfcdda5bd 100644
--- a/drivers/staging/comedi/drivers/cb_pcidda.c
+++ b/drivers/staging/comedi/drivers/cb_pcidda.c
@@ -22,12 +22,10 @@
/*
* Driver: cb_pcidda
* Description: MeasurementComputing PCI-DDA series
- * Devices: (Measurement Computing) PCI-DDA08/12 [pci-dda08/12]
- * (Measurement Computing) PCI-DDA04/12 [pci-dda04/12]
- * (Measurement Computing) PCI-DDA02/12 [pci-dda02/12]
- * (Measurement Computing) PCI-DDA08/16 [pci-dda08/16]
- * (Measurement Computing) PCI-DDA04/16 [pci-dda04/16]
- * (Measurement Computing) PCI-DDA02/16 [pci-dda02/16]
+ * Devices: [Measurement Computing] PCI-DDA08/12 (pci-dda08/12),
+ * PCI-DDA04/12 (pci-dda04/12), PCI-DDA02/12 (pci-dda02/12),
+ * PCI-DDA08/16 (pci-dda08/16), PCI-DDA04/16 (pci-dda04/16),
+ * PCI-DDA02/16 (pci-dda02/16)
* Author: Ivan Martinez <ivanmr@altavista.com>
* Frank Mori Hess <fmhess@users.sourceforge.net>
* Status: works
diff --git a/drivers/staging/comedi/drivers/comedi_bond.c b/drivers/staging/comedi/drivers/comedi_bond.c
index 85b2f4ab1ba4..221d3819c967 100644
--- a/drivers/staging/comedi/drivers/comedi_bond.c
+++ b/drivers/staging/comedi/drivers/comedi_bond.c
@@ -261,6 +261,7 @@ static int do_dev_config(struct comedi_device *dev, struct comedi_devconfig *it)
{
/* Append dev:subdev to devpriv->name */
char buf[20];
+
snprintf(buf, sizeof(buf), "%u:%u ",
bdev->minor, bdev->subdev);
strlcat(devpriv->name, buf,
diff --git a/drivers/staging/comedi/drivers/comedi_isadma.c b/drivers/staging/comedi/drivers/comedi_isadma.c
new file mode 100644
index 000000000000..dbdea71d6b95
--- /dev/null
+++ b/drivers/staging/comedi/drivers/comedi_isadma.c
@@ -0,0 +1,262 @@
+/*
+ * COMEDI ISA DMA support functions
+ * Copyright (c) 2014 H Hartley Sweeten <hsweeten@visionengravers.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <asm/dma.h>
+
+#include "../comedidev.h"
+
+#include "comedi_isadma.h"
+
+/**
+ * comedi_isadma_program - program and enable an ISA DMA transfer
+ * @desc: the ISA DMA cookie to program and enable
+ */
+void comedi_isadma_program(struct comedi_isadma_desc *desc)
+{
+ unsigned long flags;
+
+ flags = claim_dma_lock();
+ clear_dma_ff(desc->chan);
+ set_dma_mode(desc->chan, desc->mode);
+ set_dma_addr(desc->chan, desc->hw_addr);
+ set_dma_count(desc->chan, desc->size);
+ enable_dma(desc->chan);
+ release_dma_lock(flags);
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_program);
+
+/**
+ * comedi_isadma_disable - disable the ISA DMA channel
+ * @dma_chan: the DMA channel to disable
+ *
+ * Returns the residue (remaining bytes) left in the DMA transfer.
+ */
+unsigned int comedi_isadma_disable(unsigned int dma_chan)
+{
+ unsigned long flags;
+ unsigned int residue;
+
+ flags = claim_dma_lock();
+ disable_dma(dma_chan);
+ residue = get_dma_residue(dma_chan);
+ release_dma_lock(flags);
+
+ return residue;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_disable);
+
+/**
+ * comedi_isadma_disable_on_sample - disable the ISA DMA channel
+ * @dma_chan: the DMA channel to disable
+ * @size: the sample size (in bytes)
+ *
+ * Returns the residue (remaining bytes) left in the DMA transfer.
+ */
+unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
+ unsigned int size)
+{
+ int stalled = 0;
+ unsigned long flags;
+ unsigned int residue;
+ unsigned int new_residue;
+
+ residue = comedi_isadma_disable(dma_chan);
+ while (residue % size) {
+ /* residue is a partial sample, enable DMA to allow more data */
+ flags = claim_dma_lock();
+ enable_dma(dma_chan);
+ release_dma_lock(flags);
+
+ udelay(2);
+ new_residue = comedi_isadma_disable(dma_chan);
+
+ /* is DMA stalled? */
+ if (new_residue == residue) {
+ stalled++;
+ if (stalled > 10)
+ break;
+ }
+ residue = new_residue;
+ stalled = 0;
+ }
+ return residue;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_disable_on_sample);
+
+/**
+ * comedi_isadma_poll - poll the current DMA transfer
+ * @dma: the ISA DMA to poll
+ *
+ * Returns the position (in bytes) of the current DMA transfer.
+ */
+unsigned int comedi_isadma_poll(struct comedi_isadma *dma)
+{
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned long flags;
+ unsigned int result;
+ unsigned int result1;
+
+ flags = claim_dma_lock();
+ clear_dma_ff(desc->chan);
+ if (!isa_dma_bridge_buggy)
+ disable_dma(desc->chan);
+ result = get_dma_residue(desc->chan);
+ /*
+ * Read the counter again and choose higher value in order to
+ * avoid reading during counter lower byte roll over if the
+ * isa_dma_bridge_buggy is set.
+ */
+ result1 = get_dma_residue(desc->chan);
+ if (!isa_dma_bridge_buggy)
+ enable_dma(desc->chan);
+ release_dma_lock(flags);
+
+ if (result < result1)
+ result = result1;
+ if (result >= desc->size || result == 0)
+ return 0;
+ else
+ return desc->size - result;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_poll);
+
+/**
+ * comedi_isadma_set_mode - set the ISA DMA transfer direction
+ * @desc: the ISA DMA cookie to set
+ * @dma_dir: the DMA direction
+ */
+void comedi_isadma_set_mode(struct comedi_isadma_desc *desc, char dma_dir)
+{
+ desc->mode = (dma_dir == COMEDI_ISADMA_READ) ? DMA_MODE_READ
+ : DMA_MODE_WRITE;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_set_mode);
+
+/**
+ * comedi_isadma_alloc - allocate and initialize the ISA DMA
+ * @dev: comedi_device struct
+ * @n_desc: the number of cookies to allocate
+ * @dma_chan: DMA channel for the first cookie
+ * @dma_chan2: DMA channel for the second cookie
+ * @maxsize: the size of the buffer to allocate for each cookie
+ * @dma_dir: the DMA direction
+ *
+ * Returns the allocated and initialized ISA DMA or NULL if anything fails.
+ */
+struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *dev,
+ int n_desc, unsigned int dma_chan1,
+ unsigned int dma_chan2,
+ unsigned int maxsize, char dma_dir)
+{
+ struct comedi_isadma *dma = NULL;
+ struct comedi_isadma_desc *desc;
+ unsigned int dma_chans[2];
+ int i;
+
+ if (n_desc < 1 || n_desc > 2)
+ goto no_dma;
+
+ dma = kzalloc(sizeof(*dma), GFP_KERNEL);
+ if (!dma)
+ goto no_dma;
+
+ desc = kcalloc(n_desc, sizeof(*desc), GFP_KERNEL);
+ if (!desc)
+ goto no_dma;
+ dma->desc = desc;
+ dma->n_desc = n_desc;
+
+ dma_chans[0] = dma_chan1;
+ if (dma_chan2 == 0 || dma_chan2 == dma_chan1)
+ dma_chans[1] = dma_chan1;
+ else
+ dma_chans[1] = dma_chan2;
+
+ if (request_dma(dma_chans[0], dev->board_name))
+ goto no_dma;
+ dma->chan = dma_chans[0];
+ if (dma_chans[1] != dma_chans[0]) {
+ if (request_dma(dma_chans[1], dev->board_name))
+ goto no_dma;
+ }
+ dma->chan2 = dma_chans[1];
+
+ for (i = 0; i < n_desc; i++) {
+ desc = &dma->desc[i];
+ desc->chan = dma_chans[i];
+ desc->maxsize = maxsize;
+ desc->virt_addr = dma_alloc_coherent(NULL, desc->maxsize,
+ &desc->hw_addr,
+ GFP_KERNEL);
+ if (!desc->virt_addr)
+ goto no_dma;
+ comedi_isadma_set_mode(desc, dma_dir);
+ }
+
+ return dma;
+
+no_dma:
+ comedi_isadma_free(dma);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_alloc);
+
+/**
+ * comedi_isadma_free - free the ISA DMA
+ * @dma: the ISA DMA to free
+ */
+void comedi_isadma_free(struct comedi_isadma *dma)
+{
+ struct comedi_isadma_desc *desc;
+ int i;
+
+ if (!dma)
+ return;
+
+ if (dma->desc) {
+ for (i = 0; i < dma->n_desc; i++) {
+ desc = &dma->desc[i];
+ if (desc->virt_addr)
+ dma_free_coherent(NULL, desc->maxsize,
+ desc->virt_addr, desc->hw_addr);
+ }
+ kfree(dma->desc);
+ }
+ if (dma->chan2 && dma->chan2 != dma->chan)
+ free_dma(dma->chan2);
+ if (dma->chan)
+ free_dma(dma->chan);
+ kfree(dma);
+}
+EXPORT_SYMBOL_GPL(comedi_isadma_free);
+
+static int __init comedi_isadma_init(void)
+{
+ return 0;
+}
+module_init(comedi_isadma_init);
+
+static void __exit comedi_isadma_exit(void)
+{
+}
+module_exit(comedi_isadma_exit);
+
+MODULE_AUTHOR("H Hartley Sweeten <hsweeten@visionengravers.com>");
+MODULE_DESCRIPTION("Comedi ISA DMA support");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/comedi/drivers/comedi_isadma.h b/drivers/staging/comedi/drivers/comedi_isadma.h
new file mode 100644
index 000000000000..c7c524faf595
--- /dev/null
+++ b/drivers/staging/comedi/drivers/comedi_isadma.h
@@ -0,0 +1,116 @@
+/*
+ * COMEDI ISA DMA support functions
+ * Copyright (c) 2014 H Hartley Sweeten <hsweeten@visionengravers.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 _COMEDI_ISADMA_H
+#define _COMEDI_ISADMA_H
+
+/*
+ * These are used to avoid issues when <asm/dma.h> and the DMA_MODE_
+ * defines are not available.
+ */
+#define COMEDI_ISADMA_READ 0
+#define COMEDI_ISADMA_WRITE 1
+
+/**
+ * struct comedi_isadma_desc - cookie for ISA DMA
+ * @virt_addr: virtual address of buffer
+ * @hw_addr: hardware (bus) address of buffer
+ * @chan: DMA channel
+ * @maxsize: allocated size of buffer (in bytes)
+ * @size: transfer size (in bytes)
+ * @mode: DMA_MODE_READ or DMA_MODE_WRITE
+ */
+struct comedi_isadma_desc {
+ void *virt_addr;
+ dma_addr_t hw_addr;
+ unsigned int chan;
+ unsigned int maxsize;
+ unsigned int size;
+ char mode;
+};
+
+/**
+ * struct comedi_isadma - ISA DMA data
+ * @desc: cookie for each DMA buffer
+ * @n_desc: the number of cookies
+ * @cur_dma: the current cookie in use
+ * @chan: the first DMA channel requested
+ * @chan2: the second DMA channel requested
+ */
+struct comedi_isadma {
+ struct comedi_isadma_desc *desc;
+ int n_desc;
+ int cur_dma;
+ unsigned int chan;
+ unsigned int chan2;
+};
+
+#if IS_ENABLED(CONFIG_ISA_DMA_API)
+
+void comedi_isadma_program(struct comedi_isadma_desc *);
+unsigned int comedi_isadma_disable(unsigned int dma_chan);
+unsigned int comedi_isadma_disable_on_sample(unsigned int dma_chan,
+ unsigned int size);
+unsigned int comedi_isadma_poll(struct comedi_isadma *);
+void comedi_isadma_set_mode(struct comedi_isadma_desc *, char dma_dir);
+
+struct comedi_isadma *comedi_isadma_alloc(struct comedi_device *,
+ int n_desc, unsigned int dma_chan1,
+ unsigned int dma_chan2,
+ unsigned int maxsize, char dma_dir);
+void comedi_isadma_free(struct comedi_isadma *);
+
+#else /* !IS_ENABLED(CONFIG_ISA_DMA_API) */
+
+static inline void comedi_isadma_program(struct comedi_isadma_desc *desc)
+{
+}
+
+static inline unsigned int comedi_isadma_disable(unsigned int dma_chan)
+{
+ return 0;
+}
+
+static inline unsigned int
+comedi_isadma_disable_on_sample(unsigned int dma_chan, unsigned int size)
+{
+ return 0;
+}
+
+static inline unsigned int comedi_isadma_poll(struct comedi_isadma *dma)
+{
+ return 0;
+}
+
+static inline void comedi_isadma_set_mode(struct comedi_isadma_desc *desc,
+ char dma_dir)
+{
+}
+
+static inline struct comedi_isadma *
+comedi_isadma_alloc(struct comedi_device *dev, int n_desc,
+ unsigned int dma_chan1, unsigned int dma_chan2,
+ unsigned int maxsize, char dma_dir)
+{
+ return NULL;
+}
+
+static inline void comedi_isadma_free(struct comedi_isadma *dma)
+{
+}
+
+#endif /* !IS_ENABLED(CONFIG_ISA_DMA_API) */
+
+#endif /* #ifndef _COMEDI_ISADMA_H */
diff --git a/drivers/staging/comedi/drivers/comedi_parport.c b/drivers/staging/comedi/drivers/comedi_parport.c
index 3bac903c8627..ceef6931edbe 100644
--- a/drivers/staging/comedi/drivers/comedi_parport.c
+++ b/drivers/staging/comedi/drivers/comedi_parport.c
@@ -24,7 +24,7 @@
* Description: Standard PC parallel port
* Author: ds
* Status: works in immediate mode
- * Devices: (standard) parallel port [comedi_parport]
+ * Devices: [standard] parallel port (comedi_parport)
* Updated: Tue, 30 Apr 2002 21:11:45 -0700
*
* A cheap and easy way to get a few more digital I/O lines. Steal
diff --git a/drivers/staging/comedi/drivers/dac02.c b/drivers/staging/comedi/drivers/dac02.c
index beb36c8dd00a..a6798ad8fa7f 100644
--- a/drivers/staging/comedi/drivers/dac02.c
+++ b/drivers/staging/comedi/drivers/dac02.c
@@ -24,7 +24,7 @@
/*
* Driver: dac02
* Description: Comedi driver for DAC02 compatible boards
- * Devices: (Keithley Metrabyte) DAC-02 [dac02]
+ * Devices: [Keithley Metrabyte] DAC-02 (dac02)
* Author: H Hartley Sweeten <hsweeten@visionengravers.com>
* Updated: Tue, 11 Mar 2014 11:27:19 -0700
* Status: unknown
diff --git a/drivers/staging/comedi/drivers/das08.c b/drivers/staging/comedi/drivers/das08.c
index 20a9f0eb72b5..c78c0df9bbe3 100644
--- a/drivers/staging/comedi/drivers/das08.c
+++ b/drivers/staging/comedi/drivers/das08.c
@@ -1,6 +1,6 @@
/*
* comedi/drivers/das08.c
- * comedi driver for common DAS08 support (used by ISA/PCI/PCMCIA drivers)
+ * comedi module for common DAS08 support (used by ISA/PCI/PCMCIA drivers)
*
* COMEDI - Linux Control and Measurement Device Interface
* Copyright (C) 2000 David A. Schleef <ds@schleef.org>
@@ -18,21 +18,6 @@
* GNU General Public License for more details.
*/
-/*
- * Driver: das08
- * Description: DAS-08 compatible boards
- * Devices: various, see das08_isa, das08_cs, and das08_pci drivers
- * Author: Warren Jasper, ds, Frank Hess
- * Updated: Fri, 31 Aug 2012 19:19:06 +0100
- * Status: works
- *
- * This driver is used by the das08_isa, das08_cs, and das08_pci
- * drivers to provide the common support for the DAS-08 hardware.
- *
- * The driver doesn't support asynchronous commands, since the
- * cheap das08 hardware doesn't really support them.
- */
-
#include <linux/module.h>
#include "../comedidev.h"
diff --git a/drivers/staging/comedi/drivers/das08_cs.c b/drivers/staging/comedi/drivers/das08_cs.c
index f3ccc2ce6d49..93fab6890161 100644
--- a/drivers/staging/comedi/drivers/das08_cs.c
+++ b/drivers/staging/comedi/drivers/das08_cs.c
@@ -41,10 +41,7 @@ Command support does not exist, but could be added for this board.
#include <linux/module.h>
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
#include "das08.h"
diff --git a/drivers/staging/comedi/drivers/das08_isa.c b/drivers/staging/comedi/drivers/das08_isa.c
index e4ba268e78ab..2d9a31dab552 100644
--- a/drivers/staging/comedi/drivers/das08_isa.c
+++ b/drivers/staging/comedi/drivers/das08_isa.c
@@ -21,18 +21,12 @@
/*
* Driver: das08_isa
* Description: DAS-08 ISA/PC-104 compatible boards
- * Devices: (Keithley Metrabyte) DAS08 [isa-das08],
- * (ComputerBoards) DAS08 [isa-das08]
- * (ComputerBoards) DAS08-PGM [das08-pgm]
- * (ComputerBoards) DAS08-PGH [das08-pgh]
- * (ComputerBoards) DAS08-PGL [das08-pgl]
- * (ComputerBoards) DAS08-AOH [das08-aoh]
- * (ComputerBoards) DAS08-AOL [das08-aol]
- * (ComputerBoards) DAS08-AOM [das08-aom]
- * (ComputerBoards) DAS08/JR-AO [das08/jr-ao]
- * (ComputerBoards) DAS08/JR-16-AO [das08jr-16-ao]
- * (ComputerBoards) PC104-DAS08 [pc104-das08]
- * (ComputerBoards) DAS08/JR/16 [das08jr/16]
+ * Devices: [Keithley Metrabyte] DAS08 (isa-das08),
+ * [ComputerBoards] DAS08 (isa-das08), DAS08-PGM (das08-pgm),
+ * DAS08-PGH (das08-pgh), DAS08-PGL (das08-pgl), DAS08-AOH (das08-aoh),
+ * DAS08-AOL (das08-aol), DAS08-AOM (das08-aom), DAS08/JR-AO (das08/jr-ao),
+ * DAS08/JR-16-AO (das08jr-16-ao), PC104-DAS08 (pc104-das08),
+ * DAS08/JR/16 (das08jr/16)
* Author: Warren Jasper, ds, Frank Hess
* Updated: Fri, 31 Aug 2012 19:19:06 +0100
* Status: works
diff --git a/drivers/staging/comedi/drivers/das08_pci.c b/drivers/staging/comedi/drivers/das08_pci.c
index 0987ce554945..b2ea10b848c3 100644
--- a/drivers/staging/comedi/drivers/das08_pci.c
+++ b/drivers/staging/comedi/drivers/das08_pci.c
@@ -21,7 +21,7 @@
/*
* Driver: das08_pci
* Description: DAS-08 PCI compatible boards
- * Devices: (ComputerBoards) PCI-DAS08 [pci-das08]
+ * Devices: [ComputerBoards] PCI-DAS08 (pci-das08)
* Author: Warren Jasper, ds, Frank Hess
* Updated: Fri, 31 Aug 2012 19:19:06 +0100
* Status: works
diff --git a/drivers/staging/comedi/drivers/das16.c b/drivers/staging/comedi/drivers/das16.c
index 2436057304a3..2c20311120f1 100644
--- a/drivers/staging/comedi/drivers/das16.c
+++ b/drivers/staging/comedi/drivers/das16.c
@@ -22,28 +22,17 @@
* Driver: das16
* Description: DAS16 compatible boards
* Author: Sam Moore, Warren Jasper, ds, Chris Baugher, Frank Hess, Roman Fietze
- * Devices: (Keithley Metrabyte) DAS-16 [das-16]
- * (Keithley Metrabyte) DAS-16G [das-16g]
- * (Keithley Metrabyte) DAS-16F [das-16f]
- * (Keithley Metrabyte) DAS-1201 [das-1201]
- * (Keithley Metrabyte) DAS-1202 [das-1202]
- * (Keithley Metrabyte) DAS-1401 [das-1401]
- * (Keithley Metrabyte) DAS-1402 [das-1402]
- * (Keithley Metrabyte) DAS-1601 [das-1601]
- * (Keithley Metrabyte) DAS-1602 [das-1602]
- * (ComputerBoards) PC104-DAS16/JR [pc104-das16jr]
- * (ComputerBoards) PC104-DAS16JR/16 [pc104-das16jr/16]
- * (ComputerBoards) CIO-DAS16 [cio-das16]
- * (ComputerBoards) CIO-DAS16F [cio-das16/f]
- * (ComputerBoards) CIO-DAS16/JR [cio-das16/jr]
- * (ComputerBoards) CIO-DAS16JR/16 [cio-das16jr/16]
- * (ComputerBoards) CIO-DAS1401/12 [cio-das1401/12]
- * (ComputerBoards) CIO-DAS1402/12 [cio-das1402/12]
- * (ComputerBoards) CIO-DAS1402/16 [cio-das1402/16]
- * (ComputerBoards) CIO-DAS1601/12 [cio-das1601/12]
- * (ComputerBoards) CIO-DAS1602/12 [cio-das1602/12]
- * (ComputerBoards) CIO-DAS1602/16 [cio-das1602/16]
- * (ComputerBoards) CIO-DAS16/330 [cio-das16/330]
+ * Devices: [Keithley Metrabyte] DAS-16 (das-16), DAS-16G (das-16g),
+ * DAS-16F (das-16f), DAS-1201 (das-1201), DAS-1202 (das-1202),
+ * DAS-1401 (das-1401), DAS-1402 (das-1402), DAS-1601 (das-1601),
+ * DAS-1602 (das-1602),
+ * [ComputerBoards] PC104-DAS16/JR (pc104-das16jr),
+ * PC104-DAS16JR/16 (pc104-das16jr/16), CIO-DAS16 (cio-das16),
+ * CIO-DAS16F (cio-das16/f), CIO-DAS16/JR (cio-das16/jr),
+ * CIO-DAS16JR/16 (cio-das16jr/16), CIO-DAS1401/12 (cio-das1401/12),
+ * CIO-DAS1402/12 (cio-das1402/12), CIO-DAS1402/16 (cio-das1402/16),
+ * CIO-DAS1601/12 (cio-das1601/12), CIO-DAS1602/12 (cio-das1602/12),
+ * CIO-DAS1602/16 (cio-das1602/16), CIO-DAS16/330 (cio-das16/330)
* Status: works
* Updated: 2003-10-12
*
@@ -82,17 +71,14 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/pci.h>
#include <linux/interrupt.h>
-#include <asm/dma.h>
-
#include "../comedidev.h"
+#include "comedi_isadma.h"
+#include "comedi_fc.h"
#include "8253.h"
#include "8255.h"
-#include "comedi_fc.h"
#define DAS16_DMA_SIZE 0xff00 /* size in bytes of allocated dma buffer */
@@ -451,86 +437,37 @@ static inline int timer_period(void)
}
struct das16_private_struct {
+ struct comedi_isadma *dma;
unsigned int clockbase;
unsigned int ctrl_reg;
- unsigned long adc_byte_count;
unsigned int divisor1;
unsigned int divisor2;
- unsigned int dma_chan;
- uint16_t *dma_buffer[2];
- dma_addr_t dma_buffer_addr[2];
- unsigned int current_buffer;
- unsigned int dma_transfer_size;
- struct comedi_lrange *user_ai_range_table;
- struct comedi_lrange *user_ao_range_table;
struct timer_list timer;
- short timer_running;
unsigned long extra_iobase;
unsigned int can_burst:1;
+ unsigned int timer_running:1;
};
-static void das16_ai_enable(struct comedi_device *dev,
- unsigned int mode, unsigned int src)
-{
- struct das16_private_struct *devpriv = dev->private;
-
- devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
- DAS16_CTRL_DMAE |
- DAS16_CTRL_PACING_MASK);
- devpriv->ctrl_reg |= mode;
-
- if (src == TRIG_EXT)
- devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
- else
- devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
- outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
-}
-
-static void das16_ai_disable(struct comedi_device *dev)
+static void das16_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int unread_samples)
{
struct das16_private_struct *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
+ unsigned int nsamples;
- /* disable interrupts, dma and pacer clocked conversions */
- devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE |
- DAS16_CTRL_DMAE |
- DAS16_CTRL_PACING_MASK);
- outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
-}
-
-/* the pc104-das16jr (at least) has problems if the dma
- transfer is interrupted in the middle of transferring
- a 16 bit sample, so this function takes care to get
- an even transfer count after disabling dma
- channel.
-*/
-static int disable_dma_on_even(struct comedi_device *dev)
-{
- struct das16_private_struct *devpriv = dev->private;
- static const int disable_limit = 100;
- static const int enable_timeout = 100;
- int residue;
- int new_residue;
- int i;
- int j;
-
- disable_dma(devpriv->dma_chan);
- residue = get_dma_residue(devpriv->dma_chan);
- for (i = 0; i < disable_limit && (residue % 2); ++i) {
- enable_dma(devpriv->dma_chan);
- for (j = 0; j < enable_timeout; ++j) {
- udelay(2);
- new_residue = get_dma_residue(devpriv->dma_chan);
- if (new_residue != residue)
- break;
- }
- disable_dma(devpriv->dma_chan);
- residue = get_dma_residue(devpriv->dma_chan);
- }
- if (i == disable_limit) {
- dev_err(dev->class_dev,
- "failed to get an even dma transfer, could be trouble\n");
+ /*
+ * Determine dma size based on the buffer size plus the number of
+ * unread samples and the number of samples remaining in the command.
+ */
+ nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+ if (nsamples > unread_samples) {
+ nsamples -= unread_samples;
+ desc->size = comedi_samples_to_bytes(s, nsamples);
+ comedi_isadma_program(desc);
}
- return residue;
}
static void das16_interrupt(struct comedi_device *dev)
@@ -539,11 +476,12 @@ static void das16_interrupt(struct comedi_device *dev)
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
unsigned long spin_flags;
- unsigned long dma_flags;
+ unsigned int residue;
+ unsigned int nbytes;
unsigned int nsamples;
- int num_bytes, residue;
- int buffer_index;
spin_lock_irqsave(&dev->spinlock, spin_flags);
if (!(devpriv->ctrl_reg & DAS16_CTRL_DMAE)) {
@@ -551,42 +489,36 @@ static void das16_interrupt(struct comedi_device *dev)
return;
}
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma_chan);
- residue = disable_dma_on_even(dev);
+ /*
+ * The pc104-das16jr (at least) has problems if the dma
+ * transfer is interrupted in the middle of transferring
+ * a 16 bit sample.
+ */
+ residue = comedi_isadma_disable_on_sample(desc->chan,
+ comedi_bytes_per_sample(s));
- /* figure out how many points to read */
- if (residue > devpriv->dma_transfer_size) {
+ /* figure out how many samples to read */
+ if (residue > desc->size) {
dev_err(dev->class_dev, "residue > transfer size!\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
- num_bytes = 0;
- } else
- num_bytes = devpriv->dma_transfer_size - residue;
-
- if (cmd->stop_src == TRIG_COUNT &&
- num_bytes >= devpriv->adc_byte_count) {
- num_bytes = devpriv->adc_byte_count;
- async->events |= COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
+ nbytes = 0;
+ } else {
+ nbytes = desc->size - residue;
}
+ nsamples = comedi_bytes_to_samples(s, nbytes);
- buffer_index = devpriv->current_buffer;
- devpriv->current_buffer = (devpriv->current_buffer + 1) % 2;
- devpriv->adc_byte_count -= num_bytes;
-
- /* re-enable dma */
- if ((async->events & COMEDI_CB_EOA) == 0) {
- set_dma_addr(devpriv->dma_chan,
- devpriv->dma_buffer_addr[devpriv->current_buffer]);
- set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma_chan);
+ /* restart DMA if more samples are needed */
+ if (nsamples) {
+ dma->cur_dma = 1 - dma->cur_dma;
+ das16_ai_setup_dma(dev, s, nsamples);
}
- release_dma_lock(dma_flags);
spin_unlock_irqrestore(&dev->spinlock, spin_flags);
- nsamples = comedi_bytes_to_samples(s, num_bytes);
- comedi_buf_write_samples(s, devpriv->dma_buffer[buffer_index],
- nsamples);
+ comedi_buf_write_samples(s, desc->virt_addr, nsamples);
+
+ if (cmd->stop_src == TRIG_COUNT && async->scans_done >= cmd->stop_arg)
+ async->events |= COMEDI_CB_EOA;
comedi_handle_events(dev, s);
}
@@ -605,6 +537,29 @@ static void das16_timer_interrupt(unsigned long arg)
spin_unlock_irqrestore(&dev->spinlock, flags);
}
+static void das16_ai_set_mux_range(struct comedi_device *dev,
+ unsigned int first_chan,
+ unsigned int last_chan,
+ unsigned int range)
+{
+ const struct das16_board *board = dev->board_ptr;
+
+ /* set multiplexer */
+ outb(first_chan | (last_chan << 4), dev->iobase + DAS16_MUX_REG);
+
+ /* some boards do not have programmable gain */
+ if (board->ai_pg == das16_pg_none)
+ return;
+
+ /*
+ * Set gain (this is also burst rate register but according to
+ * computer boards manual, burst rate does nothing, even on
+ * keithley cards).
+ */
+ outb((das16_gainlists[board->ai_pg])[range],
+ dev->iobase + DAS16_GAIN_REG);
+}
+
static int das16_ai_check_chanlist(struct comedi_device *dev,
struct comedi_subdevice *s,
struct comedi_cmd *cmd)
@@ -755,13 +710,15 @@ static unsigned int das16_set_pacer(struct comedi_device *dev, unsigned int ns,
static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
{
- const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
+ unsigned int first_chan = CR_CHAN(cmd->chanlist[0]);
+ unsigned int last_chan = CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]);
+ unsigned int range = CR_RANGE(cmd->chanlist[0]);
unsigned int byte;
unsigned long flags;
- int range;
if (cmd->flags & CMDF_PRIORITY) {
dev_err(dev->class_dev,
@@ -769,24 +726,11 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
return -1;
}
- devpriv->adc_byte_count = cmd->stop_arg * comedi_bytes_per_scan(s);
-
if (devpriv->can_burst)
outb(DAS1600_CONV_DISABLE, dev->iobase + DAS1600_CONV_REG);
- /* set scan limits */
- byte = CR_CHAN(cmd->chanlist[0]);
- byte |= CR_CHAN(cmd->chanlist[cmd->chanlist_len - 1]) << 4;
- outb(byte, dev->iobase + DAS16_MUX_REG);
-
- /* set gain (this is also burst rate register but according to
- * computer boards manual, burst rate does nothing, even on
- * keithley cards) */
- if (board->ai_pg != das16_pg_none) {
- range = CR_RANGE(cmd->chanlist[0]);
- outb((das16_gainlists[board->ai_pg])[range],
- dev->iobase + DAS16_GAIN_REG);
- }
+ /* set mux and range for chanlist scan */
+ das16_ai_set_mux_range(dev, first_chan, last_chan, range);
/* set counter mode and counts */
cmd->convert_arg = das16_set_pacer(dev, cmd->convert_arg, cmd->flags);
@@ -805,19 +749,9 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
}
outb(byte, dev->iobase + DAS16_PACER_REG);
- /* set up dma transfer */
- flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma_chan);
- devpriv->current_buffer = 0;
- set_dma_addr(devpriv->dma_chan,
- devpriv->dma_buffer_addr[devpriv->current_buffer]);
- devpriv->dma_transfer_size = DAS16_DMA_SIZE;
- set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma_chan);
- release_dma_lock(flags);
+ /* set up dma transfer */
+ dma->cur_dma = 0;
+ das16_ai_setup_dma(dev, s, 0);
/* set up timer */
spin_lock_irqsave(&dev->spinlock, flags);
@@ -825,7 +759,14 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->timer.expires = jiffies + timer_period();
add_timer(&devpriv->timer);
- das16_ai_enable(dev, DAS16_CTRL_DMAE, cmd->convert_src);
+ /* enable DMA interrupt with external or internal pacing */
+ devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_PACING_MASK);
+ devpriv->ctrl_reg |= DAS16_CTRL_DMAE;
+ if (cmd->convert_src == TRIG_EXT)
+ devpriv->ctrl_reg |= DAS16_CTRL_EXT_PACER;
+ else
+ devpriv->ctrl_reg |= DAS16_CTRL_INT_PACER;
+ outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
if (devpriv->can_burst)
outb(0, dev->iobase + DAS1600_CONV_REG);
@@ -837,12 +778,17 @@ static int das16_cmd_exec(struct comedi_device *dev, struct comedi_subdevice *s)
static int das16_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct das16_private_struct *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
unsigned long flags;
spin_lock_irqsave(&dev->spinlock, flags);
- das16_ai_disable(dev);
- disable_dma(devpriv->dma_chan);
+ /* disable interrupts, dma and pacer clocked conversions */
+ devpriv->ctrl_reg &= ~(DAS16_CTRL_INTE | DAS16_CTRL_DMAE |
+ DAS16_CTRL_PACING_MASK);
+ outb(devpriv->ctrl_reg, dev->iobase + DAS16_CTRL_REG);
+
+ comedi_isadma_disable(dma->chan);
/* disable SW timer */
if (devpriv->timer_running) {
@@ -893,23 +839,14 @@ static int das16_ai_insn_read(struct comedi_device *dev,
struct comedi_insn *insn,
unsigned int *data)
{
- const struct das16_board *board = dev->board_ptr;
unsigned int chan = CR_CHAN(insn->chanspec);
unsigned int range = CR_RANGE(insn->chanspec);
unsigned int val;
int ret;
int i;
- das16_ai_disable(dev);
-
- /* set multiplexer */
- outb(chan | (chan << 4), dev->iobase + DAS16_MUX_REG);
-
- /* set gain */
- if (board->ai_pg != das16_pg_none) {
- outb((das16_gainlists[board->ai_pg])[range],
- dev->iobase + DAS16_GAIN_REG);
- }
+ /* set mux and range for single channel */
+ das16_ai_set_mux_range(dev, chan, chan, range);
for (i = 0; i < insn->n; i++) {
/* trigger conversion */
@@ -1001,14 +938,107 @@ static void das16_reset(struct comedi_device *dev)
outb(0, dev->iobase + DAS16_TIMER_BASE_REG + i8254_control_reg);
}
+static void das16_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+ struct das16_private_struct *devpriv = dev->private;
+
+ /* only DMA channels 3 and 1 are valid */
+ if (!(dma_chan == 1 || dma_chan == 3))
+ return;
+
+ /* DMA uses two buffers */
+ devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+ DAS16_DMA_SIZE, COMEDI_ISADMA_READ);
+ if (devpriv->dma) {
+ init_timer(&devpriv->timer);
+ devpriv->timer.function = das16_timer_interrupt;
+ devpriv->timer.data = (unsigned long)dev;
+ }
+}
+
+static void das16_free_dma(struct comedi_device *dev)
+{
+ struct das16_private_struct *devpriv = dev->private;
+
+ if (devpriv) {
+ if (devpriv->timer.data)
+ del_timer_sync(&devpriv->timer);
+ comedi_isadma_free(devpriv->dma);
+ }
+}
+
+static const struct comedi_lrange *das16_ai_range(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_devconfig *it,
+ unsigned int pg_type,
+ unsigned int status)
+{
+ unsigned int min = it->options[4];
+ unsigned int max = it->options[5];
+
+ /* get any user-defined input range */
+ if (pg_type == das16_pg_none && (min || max)) {
+ struct comedi_lrange *lrange;
+ struct comedi_krange *krange;
+
+ /* allocate single-range range table */
+ lrange = comedi_alloc_spriv(s,
+ sizeof(*lrange) + sizeof(*krange));
+ if (!lrange)
+ return &range_unknown;
+
+ /* initialize ai range */
+ lrange->length = 1;
+ krange = lrange->range;
+ krange->min = min;
+ krange->max = max;
+ krange->flags = UNIT_volt;
+
+ return lrange;
+ }
+
+ /* use software programmable range */
+ if (status & DAS16_STATUS_UNIPOLAR)
+ return das16_ai_uni_lranges[pg_type];
+ return das16_ai_bip_lranges[pg_type];
+}
+
+static const struct comedi_lrange *das16_ao_range(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ struct comedi_devconfig *it)
+{
+ unsigned int min = it->options[6];
+ unsigned int max = it->options[7];
+
+ /* get any user-defined output range */
+ if (min || max) {
+ struct comedi_lrange *lrange;
+ struct comedi_krange *krange;
+
+ /* allocate single-range range table */
+ lrange = comedi_alloc_spriv(s,
+ sizeof(*lrange) + sizeof(*krange));
+ if (!lrange)
+ return &range_unknown;
+
+ /* initialize ao range */
+ lrange->length = 1;
+ krange = lrange->range;
+ krange->min = min;
+ krange->max = max;
+ krange->flags = UNIT_volt;
+
+ return lrange;
+ }
+
+ return &range_unknown;
+}
+
static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv;
struct comedi_subdevice *s;
- struct comedi_lrange *lrange;
- struct comedi_krange *krange;
- unsigned int dma_chan = it->options[2];
unsigned int status;
int ret;
@@ -1063,72 +1093,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->clockbase = I8254_OSC_BASE_1MHZ;
}
- /* initialize dma */
- if (dma_chan == 1 || dma_chan == 3) {
- unsigned long flags;
- int i;
-
- if (request_dma(dma_chan, dev->board_name)) {
- dev_err(dev->class_dev,
- "failed to request dma channel %i\n",
- dma_chan);
- return -EINVAL;
- }
- devpriv->dma_chan = dma_chan;
-
- /* allocate dma buffers */
- for (i = 0; i < 2; i++) {
- void *p;
-
- p = pci_alloc_consistent(NULL, DAS16_DMA_SIZE,
- &devpriv->dma_buffer_addr[i]);
- if (!p)
- return -ENOMEM;
- devpriv->dma_buffer[i] = p;
- }
-
- flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
- release_dma_lock(flags);
-
- init_timer(&devpriv->timer);
- devpriv->timer.function = das16_timer_interrupt;
- devpriv->timer.data = (unsigned long)dev;
- }
-
- /* get any user-defined input range */
- if (board->ai_pg == das16_pg_none &&
- (it->options[4] || it->options[5])) {
- /* allocate single-range range table */
- lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
- if (!lrange)
- return -ENOMEM;
-
- /* initialize ai range */
- devpriv->user_ai_range_table = lrange;
- lrange->length = 1;
- krange = devpriv->user_ai_range_table->range;
- krange->min = it->options[4];
- krange->max = it->options[5];
- krange->flags = UNIT_volt;
- }
-
- /* get any user-defined output range */
- if (it->options[6] || it->options[7]) {
- /* allocate single-range range table */
- lrange = kzalloc(sizeof(*lrange) + sizeof(*krange), GFP_KERNEL);
- if (!lrange)
- return -ENOMEM;
-
- /* initialize ao range */
- devpriv->user_ao_range_table = lrange;
- lrange->length = 1;
- krange = devpriv->user_ao_range_table->range;
- krange->min = it->options[6];
- krange->max = it->options[7];
- krange->flags = UNIT_volt;
- }
+ das16_alloc_dma(dev, it->options[2]);
ret = comedi_alloc_subdevices(dev, 4 + board->has_8255);
if (ret)
@@ -1149,15 +1114,9 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
s->len_chanlist = s->n_chan;
s->maxdata = board->ai_maxdata;
- if (devpriv->user_ai_range_table) { /* user defined ai range */
- s->range_table = devpriv->user_ai_range_table;
- } else if (status & DAS16_STATUS_UNIPOLAR) {
- s->range_table = das16_ai_uni_lranges[board->ai_pg];
- } else {
- s->range_table = das16_ai_bip_lranges[board->ai_pg];
- }
+ s->range_table = das16_ai_range(dev, s, it, board->ai_pg, status);
s->insn_read = das16_ai_insn_read;
- if (devpriv->dma_chan) {
+ if (devpriv->dma) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->do_cmdtest = das16_cmd_test;
@@ -1173,7 +1132,7 @@ static int das16_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->subdev_flags = SDF_WRITABLE;
s->n_chan = 2;
s->maxdata = 0x0fff;
- s->range_table = devpriv->user_ao_range_table;
+ s->range_table = das16_ao_range(dev, s, it);
s->insn_write = das16_ao_insn_write;
ret = comedi_alloc_subdev_readback(s);
@@ -1230,25 +1189,11 @@ static void das16_detach(struct comedi_device *dev)
{
const struct das16_board *board = dev->board_ptr;
struct das16_private_struct *devpriv = dev->private;
- int i;
if (devpriv) {
- if (devpriv->timer.data)
- del_timer_sync(&devpriv->timer);
if (dev->iobase)
das16_reset(dev);
-
- for (i = 0; i < 2; i++) {
- if (devpriv->dma_buffer[i])
- pci_free_consistent(NULL, DAS16_DMA_SIZE,
- devpriv->dma_buffer[i],
- devpriv->
- dma_buffer_addr[i]);
- }
- if (devpriv->dma_chan)
- free_dma(devpriv->dma_chan);
- kfree(devpriv->user_ai_range_table);
- kfree(devpriv->user_ao_range_table);
+ das16_free_dma(dev);
if (devpriv->extra_iobase)
release_region(devpriv->extra_iobase,
diff --git a/drivers/staging/comedi/drivers/das16m1.c b/drivers/staging/comedi/drivers/das16m1.c
index 80f41b7e8273..3666a68979fb 100644
--- a/drivers/staging/comedi/drivers/das16m1.c
+++ b/drivers/staging/comedi/drivers/das16m1.c
@@ -455,7 +455,7 @@ static void das16m1_handler(struct comedi_device *dev, unsigned int status)
/* this probably won't catch overruns since the card doesn't generate
* overrun interrupts, but we might as well try */
if (status & OVRUN) {
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
dev_err(dev->class_dev, "fifo overflow\n");
}
diff --git a/drivers/staging/comedi/drivers/das1800.c b/drivers/staging/comedi/drivers/das1800.c
index be825d21a185..0790a28828de 100644
--- a/drivers/staging/comedi/drivers/das1800.c
+++ b/drivers/staging/comedi/drivers/das1800.c
@@ -98,12 +98,12 @@ TODO:
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/io.h>
-#include "../comedidev.h"
-#include <asm/dma.h>
+#include "../comedidev.h"
-#include "8253.h"
+#include "comedi_isadma.h"
#include "comedi_fc.h"
+#include "8253.h"
/* misc. defines */
#define DAS1800_SIZE 16 /* uses 16 io addresses */
@@ -421,19 +421,14 @@ static const struct das1800_board das1800_boards[] = {
};
struct das1800_private {
+ struct comedi_isadma *dma;
unsigned int divisor1; /* value to load into board's counter 1 for timed conversions */
unsigned int divisor2; /* value to load into board's counter 2 for timed conversions */
int irq_dma_bits; /* bits for control register b */
/* dma bits for control register b, stored so that dma can be
* turned on and off */
int dma_bits;
- unsigned int dma0; /* dma channels used */
- unsigned int dma1;
- unsigned int dma_current; /* dma channel currently in use */
- uint16_t *ai_buf0; /* pointers to dma buffers */
- uint16_t *ai_buf1;
- uint16_t *dma_current_buf; /* pointer to dma buffer currently being used */
- unsigned int dma_transfer_size; /* size of transfer currently used, in bytes */
+ uint16_t *fifo_buf; /* bounce buffer for analog input FIFO */
unsigned long iobase2; /* secondary io address used for analog out on 'ao' boards */
unsigned short ao_update_bits; /* remembers the last write to the
* 'update' dac */
@@ -480,9 +475,9 @@ static void das1800_handle_fifo_half_full(struct comedi_device *dev,
struct das1800_private *devpriv = dev->private;
unsigned int nsamples = comedi_nsamples_left(s, FIFO_SIZE / 2);
- insw(dev->iobase + DAS1800_FIFO, devpriv->ai_buf0, nsamples);
- munge_data(dev, devpriv->ai_buf0, nsamples);
- comedi_buf_write_samples(s, devpriv->ai_buf0, nsamples);
+ insw(dev->iobase + DAS1800_FIFO, devpriv->fifo_buf, nsamples);
+ munge_data(dev, devpriv->fifo_buf, nsamples);
+ comedi_buf_write_samples(s, devpriv->fifo_buf, nsamples);
}
static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
@@ -508,29 +503,21 @@ static void das1800_handle_fifo_not_empty(struct comedi_device *dev,
}
}
-/* Utility function used by das1800_flush_dma() and das1800_handle_dma().
- * Assumes dma lock is held */
+/* Utility function used by das1800_flush_dma() and das1800_handle_dma() */
static void das1800_flush_dma_channel(struct comedi_device *dev,
struct comedi_subdevice *s,
- unsigned int channel, uint16_t *buffer)
+ struct comedi_isadma_desc *desc)
{
- struct das1800_private *devpriv = dev->private;
- unsigned int nbytes;
+ unsigned int residue = comedi_isadma_disable(desc->chan);
+ unsigned int nbytes = desc->size - residue;
unsigned int nsamples;
- disable_dma(channel);
-
- /* clear flip-flop to make sure 2-byte registers
- * get set correctly */
- clear_dma_ff(channel);
-
/* figure out how many points to read */
- nbytes = devpriv->dma_transfer_size - get_dma_residue(channel);
nsamples = comedi_bytes_to_samples(s, nbytes);
nsamples = comedi_nsamples_left(s, nsamples);
- munge_data(dev, buffer, nsamples);
- comedi_buf_write_samples(s, buffer, nsamples);
+ munge_data(dev, desc->virt_addr, nsamples);
+ comedi_buf_write_samples(s, desc->virt_addr, nsamples);
}
/* flushes remaining data from board when external trigger has stopped acquisition
@@ -539,28 +526,19 @@ static void das1800_flush_dma(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct das1800_private *devpriv = dev->private;
- unsigned long flags;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
- flags = claim_dma_lock();
- das1800_flush_dma_channel(dev, s, devpriv->dma_current,
- devpriv->dma_current_buf);
+ das1800_flush_dma_channel(dev, s, desc);
if (dual_dma) {
/* switch to other channel and flush it */
- if (devpriv->dma_current == devpriv->dma0) {
- devpriv->dma_current = devpriv->dma1;
- devpriv->dma_current_buf = devpriv->ai_buf1;
- } else {
- devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->ai_buf0;
- }
- das1800_flush_dma_channel(dev, s, devpriv->dma_current,
- devpriv->dma_current_buf);
+ dma->cur_dma = 1 - dma->cur_dma;
+ desc = &dma->desc[dma->cur_dma];
+ das1800_flush_dma_channel(dev, s, desc);
}
- release_dma_lock(flags);
-
/* get any remaining samples in fifo */
das1800_handle_fifo_not_empty(dev, s);
}
@@ -569,47 +547,41 @@ static void das1800_handle_dma(struct comedi_device *dev,
struct comedi_subdevice *s, unsigned int status)
{
struct das1800_private *devpriv = dev->private;
- unsigned long flags;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
- flags = claim_dma_lock();
- das1800_flush_dma_channel(dev, s, devpriv->dma_current,
- devpriv->dma_current_buf);
- /* re-enable dma channel */
- set_dma_addr(devpriv->dma_current,
- virt_to_bus(devpriv->dma_current_buf));
- set_dma_count(devpriv->dma_current, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma_current);
- release_dma_lock(flags);
+ das1800_flush_dma_channel(dev, s, desc);
+
+ /* re-enable dma channel */
+ comedi_isadma_program(desc);
if (status & DMATC) {
/* clear DMATC interrupt bit */
outb(CLEAR_INTR_MASK & ~DMATC, dev->iobase + DAS1800_STATUS);
/* switch dma channels for next time, if appropriate */
- if (dual_dma) {
- /* read data from the other channel next time */
- if (devpriv->dma_current == devpriv->dma0) {
- devpriv->dma_current = devpriv->dma1;
- devpriv->dma_current_buf = devpriv->ai_buf1;
- } else {
- devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->ai_buf0;
- }
- }
+ if (dual_dma)
+ dma->cur_dma = 1 - dma->cur_dma;
}
}
static int das1800_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct das1800_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc;
+ int i;
outb(0x0, dev->iobase + DAS1800_STATUS); /* disable conversions */
outb(0x0, dev->iobase + DAS1800_CONTROL_B); /* disable interrupts and dma */
outb(0x0, dev->iobase + DAS1800_CONTROL_A); /* disable and clear fifo and stop triggering */
- if (devpriv->dma0)
- disable_dma(devpriv->dma0);
- if (devpriv->dma1)
- disable_dma(devpriv->dma1);
+
+ for (i = 0; i < 2; i++) {
+ desc = &dma->desc[i];
+ if (desc->chan)
+ comedi_isadma_disable(desc->chan);
+ }
+
return 0;
}
@@ -639,7 +611,7 @@ static void das1800_ai_handler(struct comedi_device *dev)
/* clear OVF interrupt bit */
outb(CLEAR_INTR_MASK & ~OVF, dev->iobase + DAS1800_STATUS);
dev_err(dev->class_dev, "FIFO overflow\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
return;
}
@@ -963,79 +935,64 @@ static void das1800_setup_counters(struct comedi_device *dev,
}
}
-/* utility function that suggests a dma transfer size based on the conversion period 'ns' */
-static unsigned int suggest_transfer_size(const struct comedi_cmd *cmd)
+static unsigned int das1800_ai_transfer_size(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int maxbytes,
+ unsigned int ns)
{
- unsigned int size = DMA_BUF_SIZE;
- static const int sample_size = 2; /* size in bytes of one sample from board */
- unsigned int fill_time = 300000000; /* target time in nanoseconds for filling dma buffer */
- unsigned int max_size; /* maximum size we will allow for a transfer */
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int max_samples = comedi_bytes_to_samples(s, maxbytes);
+ unsigned int samples;
+
+ samples = max_samples;
- /* make dma buffer fill in 0.3 seconds for timed modes */
+ /* for timed modes, make dma buffer fill in 'ns' time */
switch (cmd->scan_begin_src) {
- case TRIG_FOLLOW: /* not in burst mode */
+ case TRIG_FOLLOW: /* not in burst mode */
if (cmd->convert_src == TRIG_TIMER)
- size = (fill_time / cmd->convert_arg) * sample_size;
+ samples = ns / cmd->convert_arg;
break;
case TRIG_TIMER:
- size = (fill_time / (cmd->scan_begin_arg * cmd->chanlist_len)) *
- sample_size;
- break;
- default:
- size = DMA_BUF_SIZE;
+ samples = ns / (cmd->scan_begin_arg * cmd->chanlist_len);
break;
}
- /* set a minimum and maximum size allowed */
- max_size = DMA_BUF_SIZE;
- /* if we are taking limited number of conversions, limit transfer size to that */
- if (cmd->stop_src == TRIG_COUNT &&
- cmd->stop_arg * cmd->chanlist_len * sample_size < max_size)
- max_size = cmd->stop_arg * cmd->chanlist_len * sample_size;
+ /* limit samples to what is remaining in the command */
+ samples = comedi_nsamples_left(s, samples);
- if (size > max_size)
- size = max_size;
- if (size < sample_size)
- size = sample_size;
+ if (samples > max_samples)
+ samples = max_samples;
+ if (samples < 1)
+ samples = 1;
- return size;
+ return comedi_samples_to_bytes(s, samples);
}
-/* sets up dma */
-static void setup_dma(struct comedi_device *dev, const struct comedi_cmd *cmd)
+static void das1800_ai_setup_dma(struct comedi_device *dev,
+ struct comedi_subdevice *s)
{
struct das1800_private *devpriv = dev->private;
- unsigned long lock_flags;
- const int dual_dma = devpriv->irq_dma_bits & DMA_DUAL;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[0];
+ unsigned int bytes;
if ((devpriv->irq_dma_bits & DMA_ENABLED) == 0)
return;
- /* determine a reasonable dma transfer size */
- devpriv->dma_transfer_size = suggest_transfer_size(cmd);
- lock_flags = claim_dma_lock();
- disable_dma(devpriv->dma0);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma0);
- set_dma_addr(devpriv->dma0, virt_to_bus(devpriv->ai_buf0));
- /* set appropriate size of transfer */
- set_dma_count(devpriv->dma0, devpriv->dma_transfer_size);
- devpriv->dma_current = devpriv->dma0;
- devpriv->dma_current_buf = devpriv->ai_buf0;
- enable_dma(devpriv->dma0);
- /* set up dual dma if appropriate */
- if (dual_dma) {
- disable_dma(devpriv->dma1);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma1);
- set_dma_addr(devpriv->dma1, virt_to_bus(devpriv->ai_buf1));
- /* set appropriate size of transfer */
- set_dma_count(devpriv->dma1, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma1);
+ dma->cur_dma = 0;
+
+ /* determine a dma transfer size to fill buffer in 0.3 sec */
+ bytes = das1800_ai_transfer_size(dev, s, desc->maxsize, 300000000);
+
+ desc->size = bytes;
+ comedi_isadma_program(desc);
+
+ /* set up dual dma if appropriate */
+ if (devpriv->irq_dma_bits & DMA_DUAL) {
+ desc = &dma->desc[1];
+ desc->size = bytes;
+ comedi_isadma_program(desc);
}
- release_dma_lock(lock_flags);
}
/* programs channel/gain list into card */
@@ -1097,7 +1054,7 @@ static int das1800_ai_do_cmd(struct comedi_device *dev,
/* setup card and start */
program_chanlist(dev, cmd);
das1800_setup_counters(dev, cmd);
- setup_dma(dev, cmd);
+ das1800_ai_setup_dma(dev, s);
outb(control_c, dev->iobase + DAS1800_CONTROL_C);
/* set conversion rate and length for burst mode */
if (control_c & BMDE) {
@@ -1234,79 +1191,57 @@ static int das1800_do_wbits(struct comedi_device *dev,
return insn->n;
}
-static int das1800_init_dma(struct comedi_device *dev, unsigned int dma0,
- unsigned int dma1)
+static void das1800_init_dma(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
struct das1800_private *devpriv = dev->private;
- unsigned long flags;
+ unsigned int *dma_chan;
- /* need an irq to do dma */
- if (dev->irq && dma0) {
- /* encode dma0 and dma1 into 2 digit hexadecimal for switch */
- switch ((dma0 & 0x7) | (dma1 << 4)) {
- case 0x5: /* dma0 == 5 */
- devpriv->dma_bits |= DMA_CH5;
- break;
- case 0x6: /* dma0 == 6 */
- devpriv->dma_bits |= DMA_CH6;
- break;
- case 0x7: /* dma0 == 7 */
- devpriv->dma_bits |= DMA_CH7;
- break;
- case 0x65: /* dma0 == 5, dma1 == 6 */
- devpriv->dma_bits |= DMA_CH5_CH6;
- break;
- case 0x76: /* dma0 == 6, dma1 == 7 */
- devpriv->dma_bits |= DMA_CH6_CH7;
- break;
- case 0x57: /* dma0 == 7, dma1 == 5 */
- devpriv->dma_bits |= DMA_CH7_CH5;
- break;
- default:
- dev_err(dev->class_dev,
- "only supports dma channels 5 through 7\n");
- dev_err(dev->class_dev,
- "Dual dma only allows the following combinations:\n");
- dev_err(dev->class_dev,
- "dma 5,6 / 6,7 / or 7,5\n");
- return -EINVAL;
- }
- if (request_dma(dma0, dev->driver->driver_name)) {
- dev_err(dev->class_dev,
- "failed to allocate dma channel %i\n", dma0);
- return -EINVAL;
- }
- devpriv->dma0 = dma0;
- devpriv->dma_current = dma0;
- if (dma1) {
- if (request_dma(dma1, dev->driver->driver_name)) {
- dev_err(dev->class_dev,
- "failed to allocate dma channel %i\n",
- dma1);
- return -EINVAL;
- }
- devpriv->dma1 = dma1;
- }
- devpriv->ai_buf0 = kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
- if (devpriv->ai_buf0 == NULL)
- return -ENOMEM;
- devpriv->dma_current_buf = devpriv->ai_buf0;
- if (dma1) {
- devpriv->ai_buf1 =
- kmalloc(DMA_BUF_SIZE, GFP_KERNEL | GFP_DMA);
- if (devpriv->ai_buf1 == NULL)
- return -ENOMEM;
- }
- flags = claim_dma_lock();
- disable_dma(devpriv->dma0);
- set_dma_mode(devpriv->dma0, DMA_MODE_READ);
- if (dma1) {
- disable_dma(devpriv->dma1);
- set_dma_mode(devpriv->dma1, DMA_MODE_READ);
- }
- release_dma_lock(flags);
+ /*
+ * it->options[2] is DMA channel 0
+ * it->options[3] is DMA channel 1
+ *
+ * Encode the DMA channels into 2 digit hexadecimal for switch.
+ */
+ dma_chan = &it->options[2];
+
+ switch ((dma_chan[0] & 0x7) | (dma_chan[1] << 4)) {
+ case 0x5: /* dma0 == 5 */
+ devpriv->dma_bits = DMA_CH5;
+ break;
+ case 0x6: /* dma0 == 6 */
+ devpriv->dma_bits = DMA_CH6;
+ break;
+ case 0x7: /* dma0 == 7 */
+ devpriv->dma_bits = DMA_CH7;
+ break;
+ case 0x65: /* dma0 == 5, dma1 == 6 */
+ devpriv->dma_bits = DMA_CH5_CH6;
+ break;
+ case 0x76: /* dma0 == 6, dma1 == 7 */
+ devpriv->dma_bits = DMA_CH6_CH7;
+ break;
+ case 0x57: /* dma0 == 7, dma1 == 5 */
+ devpriv->dma_bits = DMA_CH7_CH5;
+ break;
+ default:
+ return;
}
- return 0;
+
+ /* DMA can use 1 or 2 buffers, each with a separate channel */
+ devpriv->dma = comedi_isadma_alloc(dev, dma_chan[1] ? 2 : 1,
+ dma_chan[0], dma_chan[1],
+ DMA_BUF_SIZE, COMEDI_ISADMA_READ);
+ if (!devpriv->dma)
+ devpriv->dma_bits = 0;
+}
+
+static void das1800_free_dma(struct comedi_device *dev)
+{
+ struct das1800_private *devpriv = dev->private;
+
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
}
static int das1800_probe(struct comedi_device *dev)
@@ -1374,8 +1309,6 @@ static int das1800_attach(struct comedi_device *dev,
struct das1800_private *devpriv;
struct comedi_subdevice *s;
unsigned int irq = it->options[1];
- unsigned int dma0 = it->options[2];
- unsigned int dma1 = it->options[3];
int board;
int ret;
@@ -1437,16 +1370,13 @@ static int das1800_attach(struct comedi_device *dev,
}
}
- ret = das1800_init_dma(dev, dma0, dma1);
- if (ret < 0)
- return ret;
+ /* an irq and one dma channel is required to use dma */
+ if (dev->irq & it->options[2])
+ das1800_init_dma(dev, it);
- if (devpriv->ai_buf0 == NULL) {
- devpriv->ai_buf0 =
- kmalloc(FIFO_SIZE * sizeof(uint16_t), GFP_KERNEL);
- if (devpriv->ai_buf0 == NULL)
- return -ENOMEM;
- }
+ devpriv->fifo_buf = kmalloc_array(FIFO_SIZE, sizeof(uint16_t), GFP_KERNEL);
+ if (!devpriv->fifo_buf)
+ return -ENOMEM;
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -1523,13 +1453,9 @@ static void das1800_detach(struct comedi_device *dev)
{
struct das1800_private *devpriv = dev->private;
+ das1800_free_dma(dev);
if (devpriv) {
- if (devpriv->dma0)
- free_dma(devpriv->dma0);
- if (devpriv->dma1)
- free_dma(devpriv->dma1);
- kfree(devpriv->ai_buf0);
- kfree(devpriv->ai_buf1);
+ kfree(devpriv->fifo_buf);
if (devpriv->iobase2)
release_region(devpriv->iobase2, DAS1800_SIZE);
}
diff --git a/drivers/staging/comedi/drivers/das6402.c b/drivers/staging/comedi/drivers/das6402.c
index 780f4f646ea0..b8755b50a11e 100644
--- a/drivers/staging/comedi/drivers/das6402.c
+++ b/drivers/staging/comedi/drivers/das6402.c
@@ -20,8 +20,8 @@
/*
* Driver: das6402
* Description: Keithley Metrabyte DAS6402 (& compatibles)
- * Devices: (Keithley Metrabyte) DAS6402-12 (das6402-12)
- * (Keithley Metrabyte) DAS6402-16 (das6402-16)
+ * Devices: [Keithley Metrabyte] DAS6402-12 (das6402-12),
+ * DAS6402-16 (das6402-16)
* Author: H Hartley Sweeten <hsweeten@visionengravers.com>
* Updated: Fri, 14 Mar 2014 10:18:43 -0700
* Status: unknown
diff --git a/drivers/staging/comedi/drivers/das800.c b/drivers/staging/comedi/drivers/das800.c
index e5bdc2423445..ff7f4be3f314 100644
--- a/drivers/staging/comedi/drivers/das800.c
+++ b/drivers/staging/comedi/drivers/das800.c
@@ -511,7 +511,7 @@ static irqreturn_t das800_interrupt(int irq, void *d)
if (fifo_overflow) {
spin_unlock_irqrestore(&dev->spinlock, irq_flags);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
return IRQ_HANDLED;
}
diff --git a/drivers/staging/comedi/drivers/dmm32at.c b/drivers/staging/comedi/drivers/dmm32at.c
index 6df298a99cc6..1af006609fc1 100644
--- a/drivers/staging/comedi/drivers/dmm32at.c
+++ b/drivers/staging/comedi/drivers/dmm32at.c
@@ -19,7 +19,7 @@
/*
* Driver: dmm32at
* Description: Diamond Systems Diamond-MM-32-AT
- * Devices: (Diamond Systems) Diamond-MM-32-AT [dmm32at]
+ * Devices: [Diamond Systems] Diamond-MM-32-AT (dmm32at)
* Author: Perry J. Piplani <perry.j.piplani@nasa.gov>
* Updated: Fri Jun 4 09:13:24 CDT 2004
* Status: experimental
@@ -365,7 +365,7 @@ static void dmm32at_setaitimer(struct comedi_device *dev, unsigned int nansec)
/* enable the ai conversion interrupt and the clock to start scans */
outb(DMM32AT_INTCLK_ADINT |
DMM32AT_INTCLK_CLKEN | DMM32AT_INTCLK_CLKSEL,
- dev->iobase + DMM32AT_INTCLK_REG);
+ dev->iobase + DMM32AT_INTCLK_REG);
}
static int dmm32at_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
diff --git a/drivers/staging/comedi/drivers/dt282x.c b/drivers/staging/comedi/drivers/dt282x.c
index 2be98bb9a809..db21d2135856 100644
--- a/drivers/staging/comedi/drivers/dt282x.c
+++ b/drivers/staging/comedi/drivers/dt282x.c
@@ -20,22 +20,12 @@
* Driver: dt282x
* Description: Data Translation DT2821 series (including DT-EZ)
* Author: ds
- * Devices: (Data Translation) DT2821 [dt2821]
- * (Data Translation) DT2821-F-16SE [dt2821-f]
- * (Data Translation) DT2821-F-8DI [dt2821-f]
- * (Data Translation) DT2821-G-16SE [dt2821-g]
- * (Data Translation) DT2821-G-8DI [dt2821-g]
- * (Data Translation) DT2823 [dt2823]
- * (Data Translation) DT2824-PGH [dt2824-pgh]
- * (Data Translation) DT2824-PGL [dt2824-pgl]
- * (Data Translation) DT2825 [dt2825]
- * (Data Translation) DT2827 [dt2827]
- * (Data Translation) DT2828 [dt2828]
- * (Data Translation) DT2928 [dt2829]
- * (Data Translation) DT21-EZ [dt21-ez]
- * (Data Translation) DT23-EZ [dt23-ez]
- * (Data Translation) DT24-EZ [dt24-ez]
- * (Data Translation) DT24-EZ-PGL [dt24-ez-pgl]
+ * Devices: [Data Translation] DT2821 (dt2821), DT2821-F-16SE (dt2821-f),
+ * DT2821-F-8DI (dt2821-f), DT2821-G-16SE (dt2821-g),
+ * DT2821-G-8DI (dt2821-g), DT2823 (dt2823), DT2824-PGH (dt2824-pgh),
+ * DT2824-PGL (dt2824-pgl), DT2825 (dt2825), DT2827 (dt2827),
+ * DT2828 (dt2828), DT2928 (dt2829), DT21-EZ (dt21-ez), DT23-EZ (dt23-ez),
+ * DT24-EZ (dt24-ez), DT24-EZ-PGL (dt24-ez-pgl)
* Status: complete
* Updated: Wed, 22 Aug 2001 17:11:34 -0700
*
@@ -66,15 +56,14 @@
*/
#include <linux/module.h>
-#include "../comedidev.h"
-
#include <linux/delay.h>
#include <linux/gfp.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include <asm/dma.h>
+#include "../comedidev.h"
+#include "comedi_isadma.h"
#include "comedi_fc.h"
/*
@@ -311,55 +300,36 @@ static const struct dt282x_board boardtypes[] = {
};
struct dt282x_private {
+ struct comedi_isadma *dma;
unsigned int ad_2scomp:1;
-
unsigned int divisor;
-
int dacsr; /* software copies of registers */
int adcsr;
int supcsr;
-
int ntrig;
int nread;
-
- struct {
- int chan;
- unsigned short *buf; /* DMA buffer */
- int size; /* size of current transfer */
- } dma[2];
- int dma_maxsize; /* max size of DMA transfer (in bytes) */
- int current_dma_index;
int dma_dir;
};
static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
{
struct dt282x_private *devpriv = dev->private;
- int dma_chan;
- unsigned long dma_ptr;
- unsigned long flags;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma_index];
if (!devpriv->ntrig)
return 0;
if (n == 0)
- n = devpriv->dma_maxsize;
+ n = desc->maxsize;
if (n > devpriv->ntrig * 2)
n = devpriv->ntrig * 2;
devpriv->ntrig -= n / 2;
- devpriv->dma[dma_index].size = n;
- dma_chan = devpriv->dma[dma_index].chan;
- dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
-
- set_dma_mode(dma_chan, DMA_MODE_READ);
- flags = claim_dma_lock();
- clear_dma_ff(dma_chan);
- set_dma_addr(dma_chan, dma_ptr);
- set_dma_count(dma_chan, n);
- release_dma_lock(flags);
+ desc->size = n;
+ comedi_isadma_set_mode(desc, devpriv->dma_dir);
- enable_dma(dma_chan);
+ comedi_isadma_program(desc);
return n;
}
@@ -367,22 +337,13 @@ static int dt282x_prep_ai_dma(struct comedi_device *dev, int dma_index, int n)
static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
{
struct dt282x_private *devpriv = dev->private;
- int dma_chan;
- unsigned long dma_ptr;
- unsigned long flags;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma_index];
- devpriv->dma[dma_index].size = n;
- dma_chan = devpriv->dma[dma_index].chan;
- dma_ptr = virt_to_bus(devpriv->dma[dma_index].buf);
+ desc->size = n;
+ comedi_isadma_set_mode(desc, devpriv->dma_dir);
- set_dma_mode(dma_chan, DMA_MODE_WRITE);
- flags = claim_dma_lock();
- clear_dma_ff(dma_chan);
- set_dma_addr(dma_chan, dma_ptr);
- set_dma_count(dma_chan, n);
- release_dma_lock(flags);
-
- enable_dma(dma_chan);
+ comedi_isadma_program(desc);
return n;
}
@@ -390,9 +351,14 @@ static int dt282x_prep_ao_dma(struct comedi_device *dev, int dma_index, int n)
static void dt282x_disable_dma(struct comedi_device *dev)
{
struct dt282x_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc;
+ int i;
- disable_dma(devpriv->dma[0].chan);
- disable_dma(devpriv->dma[1].chan);
+ for (i = 0; i < 2; i++) {
+ desc = &dma->desc[i];
+ comedi_isadma_disable(desc->chan);
+ }
}
static unsigned int dt282x_ns_to_timer(unsigned int *ns, unsigned int flags)
@@ -454,11 +420,12 @@ static unsigned int dt282x_ao_setup_dma(struct comedi_device *dev,
int cur_dma)
{
struct dt282x_private *devpriv = dev->private;
- void *ptr = devpriv->dma[cur_dma].buf;
- unsigned int nsamples = comedi_bytes_to_samples(s, devpriv->dma_maxsize);
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[cur_dma];
+ unsigned int nsamples = comedi_bytes_to_samples(s, desc->maxsize);
unsigned int nbytes;
- nbytes = comedi_buf_read_samples(s, ptr, nsamples);
+ nbytes = comedi_buf_read_samples(s, desc->virt_addr, nsamples);
if (nbytes)
dt282x_prep_ao_dma(dev, cur_dma, nbytes);
else
@@ -471,39 +438,37 @@ static void dt282x_ao_dma_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct dt282x_private *devpriv = dev->private;
- int cur_dma = devpriv->current_dma_index;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
dev->iobase + DT2821_SUPCSR_REG);
- disable_dma(devpriv->dma[cur_dma].chan);
-
- devpriv->current_dma_index = 1 - cur_dma;
+ comedi_isadma_disable(desc->chan);
- if (!dt282x_ao_setup_dma(dev, s, cur_dma))
+ if (!dt282x_ao_setup_dma(dev, s, dma->cur_dma))
s->async->events |= COMEDI_CB_OVERFLOW;
+
+ dma->cur_dma = 1 - dma->cur_dma;
}
static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct dt282x_private *devpriv = dev->private;
- int cur_dma = devpriv->current_dma_index;
- void *ptr = devpriv->dma[cur_dma].buf;
- int size = devpriv->dma[cur_dma].size;
- unsigned int nsamples = comedi_bytes_to_samples(s, size);
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
int ret;
outw(devpriv->supcsr | DT2821_SUPCSR_CLRDMADNE,
dev->iobase + DT2821_SUPCSR_REG);
- disable_dma(devpriv->dma[cur_dma].chan);
-
- devpriv->current_dma_index = 1 - cur_dma;
+ comedi_isadma_disable(desc->chan);
- dt282x_munge(dev, s, ptr, size);
- ret = comedi_buf_write_samples(s, ptr, nsamples);
- if (ret != size)
+ dt282x_munge(dev, s, desc->virt_addr, desc->size);
+ ret = comedi_buf_write_samples(s, desc->virt_addr, nsamples);
+ if (ret != desc->size)
return;
devpriv->nread -= nsamples;
@@ -524,7 +489,9 @@ static void dt282x_ai_dma_interrupt(struct comedi_device *dev,
}
#endif
/* restart the channel */
- dt282x_prep_ai_dma(dev, cur_dma, 0);
+ dt282x_prep_ai_dma(dev, dma->cur_dma, 0);
+
+ dma->cur_dma = 1 - dma->cur_dma;
}
static irqreturn_t dt282x_interrupt(int irq, void *d)
@@ -545,7 +512,7 @@ static irqreturn_t dt282x_interrupt(int irq, void *d)
dacsr = inw(dev->iobase + DT2821_DACSR_REG);
supcsr = inw(dev->iobase + DT2821_SUPCSR_REG);
if (supcsr & DT2821_SUPCSR_DMAD) {
- if (devpriv->dma_dir == DMA_MODE_READ)
+ if (devpriv->dma_dir == COMEDI_ISADMA_READ)
dt282x_ai_dma_interrupt(dev, s);
else
dt282x_ao_dma_interrupt(dev, s_ao);
@@ -718,14 +685,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
err |= cfc_check_trigger_arg_is(&cmd->start_arg, 0);
- if (cmd->scan_begin_src == TRIG_FOLLOW) {
- /* internal trigger */
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
- } else {
- /* external trigger */
- /* should be level/edge, hi/lo specification here */
- err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
- }
+ err |= cfc_check_trigger_arg_is(&cmd->scan_begin_arg, 0);
err |= cfc_check_trigger_arg_min(&cmd->convert_arg, 4000);
@@ -757,6 +717,7 @@ static int dt282x_ai_cmdtest(struct comedi_device *dev,
static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct dt282x_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_cmd *cmd = &s->async->cmd;
int ret;
@@ -778,8 +739,8 @@ static int dt282x_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ntrig = cmd->stop_arg * cmd->scan_end_arg;
devpriv->nread = devpriv->ntrig;
- devpriv->dma_dir = DMA_MODE_READ;
- devpriv->current_dma_index = 0;
+ devpriv->dma_dir = COMEDI_ISADMA_READ;
+ dma->cur_dma = 0;
dt282x_prep_ai_dma(dev, 0, 0);
if (devpriv->ntrig) {
dt282x_prep_ai_dma(dev, 1, 0);
@@ -942,6 +903,7 @@ static int dt282x_ao_inttrig(struct comedi_device *dev,
static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct dt282x_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_cmd *cmd = &s->async->cmd;
dt282x_disable_dma(dev);
@@ -958,8 +920,8 @@ static int dt282x_ao_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ntrig = cmd->stop_arg * cmd->chanlist_len;
devpriv->nread = devpriv->ntrig;
- devpriv->dma_dir = DMA_MODE_WRITE;
- devpriv->current_dma_index = 0;
+ devpriv->dma_dir = COMEDI_ISADMA_WRITE;
+ dma->cur_dma = 0;
outw(devpriv->divisor, dev->iobase + DT2821_TMRCTR_REG);
@@ -1063,46 +1025,42 @@ static const struct comedi_lrange *opt_ai_range_lkup(int ispgl, int x)
return ai_range_table[x];
}
-static int dt282x_grab_dma(struct comedi_device *dev, int dma1, int dma2)
+static void dt282x_alloc_dma(struct comedi_device *dev,
+ struct comedi_devconfig *it)
{
struct dt282x_private *devpriv = dev->private;
- int ret;
+ unsigned int irq_num = it->options[1];
+ unsigned int dma_chan[2];
- ret = request_dma(dma1, "dt282x A");
- if (ret)
- return -EBUSY;
- devpriv->dma[0].chan = dma1;
+ if (it->options[2] < it->options[3]) {
+ dma_chan[0] = it->options[2];
+ dma_chan[1] = it->options[3];
+ } else {
+ dma_chan[0] = it->options[3];
+ dma_chan[1] = it->options[2];
+ }
- ret = request_dma(dma2, "dt282x B");
- if (ret)
- return -EBUSY;
- devpriv->dma[1].chan = dma2;
+ if (!irq_num || dma_chan[0] == dma_chan[1] ||
+ dma_chan[0] < 5 || dma_chan[0] > 7 ||
+ dma_chan[1] < 5 || dma_chan[1] > 7)
+ return;
- devpriv->dma_maxsize = PAGE_SIZE;
- devpriv->dma[0].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- devpriv->dma[1].buf = (void *)__get_free_page(GFP_KERNEL | GFP_DMA);
- if (!devpriv->dma[0].buf || !devpriv->dma[1].buf)
- return -ENOMEM;
+ if (request_irq(irq_num, dt282x_interrupt, 0, dev->board_name, dev))
+ return;
- return 0;
+ /* DMA uses two 4K buffers with separate DMA channels */
+ devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan[0], dma_chan[1],
+ PAGE_SIZE, 0);
+ if (!devpriv->dma)
+ free_irq(irq_num, dev);
}
static void dt282x_free_dma(struct comedi_device *dev)
{
struct dt282x_private *devpriv = dev->private;
- int i;
-
- if (!devpriv)
- return;
- for (i = 0; i < 2; i++) {
- if (devpriv->dma[i].chan)
- free_dma(devpriv->dma[i].chan);
- if (devpriv->dma[i].buf)
- free_page((unsigned long)devpriv->dma[i].buf);
- devpriv->dma[i].chan = 0;
- devpriv->dma[i].buf = NULL;
- }
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
}
static int dt282x_initialize(struct comedi_device *dev)
@@ -1160,36 +1118,7 @@ static int dt282x_attach(struct comedi_device *dev, struct comedi_devconfig *it)
return -ENOMEM;
/* an IRQ and 2 DMA channels are required for async command support */
- if (it->options[1] && it->options[2] && it->options[3]) {
- unsigned int irq = it->options[1];
- unsigned int dma1 = it->options[2];
- unsigned int dma2 = it->options[3];
-
- if (dma2 < dma1) {
- unsigned int swap;
-
- swap = dma1;
- dma1 = dma2;
- dma2 = swap;
- }
-
- if (dma1 != dma2 &&
- dma1 >= 5 && dma1 <= 7 &&
- dma2 >= 5 && dma2 <= 7) {
- ret = request_irq(irq, dt282x_interrupt, 0,
- dev->board_name, dev);
- if (ret == 0) {
- dev->irq = irq;
-
- ret = dt282x_grab_dma(dev, dma1, dma2);
- if (ret < 0) {
- dt282x_free_dma(dev);
- free_irq(dev->irq, dev);
- dev->irq = 0;
- }
- }
- }
- }
+ dt282x_alloc_dma(dev, it);
ret = comedi_alloc_subdevices(dev, 3);
if (ret)
diff --git a/drivers/staging/comedi/drivers/dt3000.c b/drivers/staging/comedi/drivers/dt3000.c
index 1d9a7a63e06f..0aa51980e327 100644
--- a/drivers/staging/comedi/drivers/dt3000.c
+++ b/drivers/staging/comedi/drivers/dt3000.c
@@ -355,7 +355,7 @@ static irqreturn_t dt3k_interrupt(int irq, void *d)
dt3k_ai_empty_fifo(dev, s);
if (status & (DT3000_ADSWERR | DT3000_ADHWERR))
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
debug_n_ints++;
if (debug_n_ints >= 10)
diff --git a/drivers/staging/comedi/drivers/dt9812.c b/drivers/staging/comedi/drivers/dt9812.c
index 06c601d8fdff..e11c216a4c85 100644
--- a/drivers/staging/comedi/drivers/dt9812.c
+++ b/drivers/staging/comedi/drivers/dt9812.c
@@ -42,9 +42,8 @@ for my needs.
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/uaccess.h>
-#include <linux/usb.h>
-#include "../comedidev.h"
+#include "../comedi_usb.h"
#define DT9812_DIAGS_BOARD_INFO_ADDR 0xFBFF
#define DT9812_MAX_WRITE_CMD_PIPE_SIZE 32
diff --git a/drivers/staging/comedi/drivers/dyna_pci10xx.c b/drivers/staging/comedi/drivers/dyna_pci10xx.c
index 1b6324c6eb29..6c1e442f6c81 100644
--- a/drivers/staging/comedi/drivers/dyna_pci10xx.c
+++ b/drivers/staging/comedi/drivers/dyna_pci10xx.c
@@ -14,24 +14,23 @@
*/
/*
- Driver: dyna_pci10xx
- Devices: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/
- Author: Prashant Shah <pshah.mumbai@gmail.com>
- Developed at Automation Labs, Chemical Dept., IIT Bombay, India.
- Prof. Kannan Moudgalya <kannan@iitb.ac.in>
- http://www.iitb.ac.in
- Status: Stable
- Version: 1.0
- Device Supported :
- - Dynalog PCI 1050
-
- Notes :
- - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and
- they are using the PLX Technlogies Vendor ID since that is the PCI Chip used
- in the card.
- - Dynalog India Pvt. Ltd. has provided the internal register specification for
- their cards in their manuals.
-*/
+ * Driver: dyna_pci10xx
+ * Description: Dynalog India PCI DAQ Cards, http://www.dynalogindia.com/
+ * Devices: [Dynalog] PCI-1050 (dyna_pci1050)
+ * Author: Prashant Shah <pshah.mumbai@gmail.com>
+ * Status: Stable
+ *
+ * Developed at Automation Labs, Chemical Dept., IIT Bombay, India.
+ * Prof. Kannan Moudgalya <kannan@iitb.ac.in>
+ * http://www.iitb.ac.in
+ *
+ * Notes :
+ * - Dynalog India Pvt. Ltd. does not have a registered PCI Vendor ID and
+ * they are using the PLX Technlogies Vendor ID since that is the PCI Chip
+ * used in the card.
+ * - Dynalog India Pvt. Ltd. has provided the internal register specification
+ * for their cards in their manuals.
+ */
#include <linux/module.h>
#include <linux/delay.h>
diff --git a/drivers/staging/comedi/drivers/gsc_hpdi.c b/drivers/staging/comedi/drivers/gsc_hpdi.c
index 0979f536ed39..deada9784b69 100644
--- a/drivers/staging/comedi/drivers/gsc_hpdi.c
+++ b/drivers/staging/comedi/drivers/gsc_hpdi.c
@@ -261,12 +261,12 @@ static irqreturn_t gsc_hpdi_interrupt(int irq, void *d)
if (hpdi_board_status & RX_OVERRUN_BIT) {
dev_err(dev->class_dev, "rx fifo overrun\n");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
}
if (hpdi_board_status & RX_UNDERRUN_BIT) {
dev_err(dev->class_dev, "rx fifo underrun\n");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
}
if (devpriv->dio_count == 0)
diff --git a/drivers/staging/comedi/drivers/ii_pci20kc.c b/drivers/staging/comedi/drivers/ii_pci20kc.c
index 1085d66935fe..0768bc42a5db 100644
--- a/drivers/staging/comedi/drivers/ii_pci20kc.c
+++ b/drivers/staging/comedi/drivers/ii_pci20kc.c
@@ -9,7 +9,7 @@
/*
* Driver: ii_pci20kc
* Description: Intelligent Instruments PCI-20001C carrier board
- * Devices: (Intelligent Instrumentation) PCI-20001C [ii_pci20kc]
+ * Devices: [Intelligent Instrumentation] PCI-20001C (ii_pci20kc)
* Author: Markus Kempf <kempf@matsci.uni-sb.de>
* Status: works
*
diff --git a/drivers/staging/comedi/drivers/jr3_pci.h b/drivers/staging/comedi/drivers/jr3_pci.h
index 20478ae8fad6..356811defaf4 100644
--- a/drivers/staging/comedi/drivers/jr3_pci.h
+++ b/drivers/staging/comedi/drivers/jr3_pci.h
@@ -261,8 +261,9 @@ struct intern_transform {
} link[8];
};
-/* JR3 force/torque sensor data definition. For more information see sensor and */
-/* hardware manuals. */
+/* JR3 force/torque sensor data definition. For more information see sensor
+ * and hardware manuals.
+ */
struct jr3_channel {
/* Raw_channels is the area used to store the raw data coming from */
diff --git a/drivers/staging/comedi/drivers/ke_counter.c b/drivers/staging/comedi/drivers/ke_counter.c
index 77e94a34b51e..3c19e0f178ca 100644
--- a/drivers/staging/comedi/drivers/ke_counter.c
+++ b/drivers/staging/comedi/drivers/ke_counter.c
@@ -19,7 +19,7 @@
/*
* Driver: ke_counter
* Description: Driver for Kolter Electronic Counter Card
- * Devices: (Kolter Electronic) PCI Counter Card [ke_counter]
+ * Devices: [Kolter Electronic] PCI Counter Card (ke_counter)
* Author: Michael Hillmann
* Updated: Mon, 14 Apr 2008 15:42:42 +0100
* Status: tested
diff --git a/drivers/staging/comedi/drivers/me4000.c b/drivers/staging/comedi/drivers/me4000.c
index 915685c1c85c..d120aa244cf9 100644
--- a/drivers/staging/comedi/drivers/me4000.c
+++ b/drivers/staging/comedi/drivers/me4000.c
@@ -1068,7 +1068,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
ME4000_AI_CTRL_BIT_SC_IRQ);
outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
dev_err(dev->class_dev, "FIFO overflow\n");
} else if ((tmp & ME4000_AI_STATUS_BIT_FF_DATA)
@@ -1089,7 +1089,7 @@ static irqreturn_t me4000_ai_isr(int irq, void *dev_id)
ME4000_AI_CTRL_BIT_SC_IRQ);
outl(tmp, dev->iobase + ME4000_AI_CTRL_REG);
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
dev_err(dev->class_dev, "Undefined FIFO state\n");
}
diff --git a/drivers/staging/comedi/drivers/me_daq.c b/drivers/staging/comedi/drivers/me_daq.c
index b5278c11e622..92e23527f2cb 100644
--- a/drivers/staging/comedi/drivers/me_daq.c
+++ b/drivers/staging/comedi/drivers/me_daq.c
@@ -19,8 +19,7 @@
/*
* Driver: me_daq
* Description: Meilhaus PCI data acquisition cards
- * Devices: (Meilhaus) ME-2600i [me-2600i]
- * (Meilhaus) ME-2000i [me-2000i]
+ * Devices: [Meilhaus] ME-2600i (me-2600i), ME-2000i (me-2000i)
* Author: Michael Hillmann <hillmann@syscongroup.de>
* Status: experimental
*
@@ -175,7 +174,7 @@ struct me_private_data {
static inline void sleep(unsigned sec)
{
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(sec * HZ);
}
diff --git a/drivers/staging/comedi/drivers/mf6x4.c b/drivers/staging/comedi/drivers/mf6x4.c
index af21bc180c46..db972bce2b5b 100644
--- a/drivers/staging/comedi/drivers/mf6x4.c
+++ b/drivers/staging/comedi/drivers/mf6x4.c
@@ -18,7 +18,7 @@
/*
* Driver: mf6x4
* Description: Humusoft MF634 and MF624 Data acquisition card driver
- * Devices: Humusoft MF634, Humusoft MF624
+ * Devices: [Humusoft] MF634 (mf634), MF624 (mf624)
* Author: Rostislav Lisovy <lisovy@gmail.com>
* Status: works
* Updated:
diff --git a/drivers/staging/comedi/drivers/mite.c b/drivers/staging/comedi/drivers/mite.c
index ffc9e61d6cdd..1e537a5cf862 100644
--- a/drivers/staging/comedi/drivers/mite.c
+++ b/drivers/staging/comedi/drivers/mite.c
@@ -494,9 +494,7 @@ EXPORT_SYMBOL_GPL(mite_bytes_read_from_memory_ub);
unsigned mite_dma_tcr(struct mite_channel *mite_chan)
{
struct mite_struct *mite = mite_chan->mite;
- int lkar;
- lkar = readl(mite->mite_io_addr + MITE_LKAR(mite_chan->channel));
return readl(mite->mite_io_addr + MITE_TCR(mite_chan->channel));
}
EXPORT_SYMBOL_GPL(mite_dma_tcr);
diff --git a/drivers/staging/comedi/drivers/ni_6527.c b/drivers/staging/comedi/drivers/ni_6527.c
index f99847f3999f..530f716f6586 100644
--- a/drivers/staging/comedi/drivers/ni_6527.c
+++ b/drivers/staging/comedi/drivers/ni_6527.c
@@ -19,8 +19,7 @@
/*
* Driver: ni_6527
* Description: National Instruments 6527
- * Devices: (National Instruments) PCI-6527 [pci-6527]
- * (National Instruments) PXI-6527 [pxi-6527]
+ * Devices: [National Instruments] PCI-6527 (pci-6527), PXI-6527 (pxi-6527)
* Author: David A. Schleef <ds@schleef.org>
* Updated: Sat, 25 Jan 2003 13:24:40 -0800
* Status: works
diff --git a/drivers/staging/comedi/drivers/ni_65xx.c b/drivers/staging/comedi/drivers/ni_65xx.c
index bcb326e31562..67cb758eb0cd 100644
--- a/drivers/staging/comedi/drivers/ni_65xx.c
+++ b/drivers/staging/comedi/drivers/ni_65xx.c
@@ -25,28 +25,14 @@
* Author: Jon Grierson <jd@renko.co.uk>,
* Frank Mori Hess <fmhess@users.sourceforge.net>
* Status: testing
- * Devices: (National Instruments) PCI-6509 [ni_65xx]
- * (National Instruments) PXI-6509 [ni_65xx]
- * (National Instruments) PCI-6510 [ni_65xx]
- * (National Instruments) PCI-6511 [ni_65xx]
- * (National Instruments) PXI-6511 [ni_65xx]
- * (National Instruments) PCI-6512 [ni_65xx]
- * (National Instruments) PXI-6512 [ni_65xx]
- * (National Instruments) PCI-6513 [ni_65xx]
- * (National Instruments) PXI-6513 [ni_65xx]
- * (National Instruments) PCI-6514 [ni_65xx]
- * (National Instruments) PXI-6514 [ni_65xx]
- * (National Instruments) PCI-6515 [ni_65xx]
- * (National Instruments) PXI-6515 [ni_65xx]
- * (National Instruments) PCI-6516 [ni_65xx]
- * (National Instruments) PCI-6517 [ni_65xx]
- * (National Instruments) PCI-6518 [ni_65xx]
- * (National Instruments) PCI-6519 [ni_65xx]
- * (National Instruments) PCI-6520 [ni_65xx]
- * (National Instruments) PCI-6521 [ni_65xx]
- * (National Instruments) PXI-6521 [ni_65xx]
- * (National Instruments) PCI-6528 [ni_65xx]
- * (National Instruments) PXI-6528 [ni_65xx]
+ * Devices: [National Instruments] PCI-6509 (pci-6509), PXI-6509 (pxi-6509),
+ * PCI-6510 (pci-6510), PCI-6511 (pci-6511), PXI-6511 (pxi-6511),
+ * PCI-6512 (pci-6512), PXI-6512 (pxi-6512), PCI-6513 (pci-6513),
+ * PXI-6513 (pxi-6513), PCI-6514 (pci-6514), PXI-6514 (pxi-6514),
+ * PCI-6515 (pxi-6515), PXI-6515 (pxi-6515), PCI-6516 (pci-6516),
+ * PCI-6517 (pci-6517), PCI-6518 (pci-6518), PCI-6519 (pci-6519),
+ * PCI-6520 (pci-6520), PCI-6521 (pci-6521), PXI-6521 (pxi-6521),
+ * PCI-6528 (pci-6528), PXI-6528 (pxi-6528)
* Updated: Mon, 21 Jul 2014 12:49:58 +0000
*
* Configuration Options: not applicable, uses PCI auto config
diff --git a/drivers/staging/comedi/drivers/ni_at_a2150.c b/drivers/staging/comedi/drivers/ni_at_a2150.c
index 69e543a0bf22..a1ce0b0b8c41 100644
--- a/drivers/staging/comedi/drivers/ni_at_a2150.c
+++ b/drivers/staging/comedi/drivers/ni_at_a2150.c
@@ -62,14 +62,13 @@ TRIG_WAKE_EOS
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
-#include "../comedidev.h"
-
#include <linux/io.h>
-#include <asm/dma.h>
+#include "../comedidev.h"
-#include "8253.h"
+#include "comedi_isadma.h"
#include "comedi_fc.h"
+#include "8253.h"
#define A2150_DMA_BUFFER_SIZE 0xff00 /* size in bytes of dma buffer */
@@ -146,11 +145,8 @@ static const struct a2150_board a2150_boards[] = {
};
struct a2150_private {
-
- volatile unsigned int count; /* number of data points left to be taken */
- unsigned int dma; /* dma channel */
- uint16_t *dma_buffer; /* dma buffer */
- unsigned int dma_transfer_size; /* size in bytes of dma transfers */
+ struct comedi_isadma *dma;
+ unsigned int count; /* number of data points left to be taken */
int irq_dma_bits; /* irq/dma register bits */
int config_bits; /* config register bits */
};
@@ -158,68 +154,54 @@ struct a2150_private {
/* interrupt service routine */
static irqreturn_t a2150_interrupt(int irq, void *d)
{
- int i;
- int status;
- unsigned long flags;
struct comedi_device *dev = d;
struct a2150_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[0];
struct comedi_subdevice *s = dev->read_subdev;
- struct comedi_async *async;
- struct comedi_cmd *cmd;
+ struct comedi_async *async = s->async;
+ struct comedi_cmd *cmd = &async->cmd;
+ unsigned short *buf = desc->virt_addr;
unsigned int max_points, num_points, residue, leftover;
unsigned short dpnt;
+ int status;
+ int i;
- if (!dev->attached) {
- dev_err(dev->class_dev, "premature interrupt\n");
+ if (!dev->attached)
return IRQ_HANDLED;
- }
- /* initialize async here to make sure s is not NULL */
- async = s->async;
- cmd = &async->cmd;
status = inw(dev->iobase + STATUS_REG);
-
- if ((status & INTR_BIT) == 0) {
- dev_err(dev->class_dev, "spurious interrupt\n");
+ if ((status & INTR_BIT) == 0)
return IRQ_NONE;
- }
if (status & OVFL_BIT) {
- dev_err(dev->class_dev, "fifo overflow\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
}
if ((status & DMA_TC_BIT) == 0) {
- dev_err(dev->class_dev,
- "caught non-dma interrupt? Aborting.\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
return IRQ_HANDLED;
}
- flags = claim_dma_lock();
- disable_dma(devpriv->dma);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma);
-
- /* figure out how many points to read */
- max_points = comedi_bytes_to_samples(s, devpriv->dma_transfer_size);
- /* residue is the number of points left to be done on the dma
+ /*
+ * residue is the number of bytes left to be done on the dma
* transfer. It should always be zero at this point unless
* the stop_src is set to external triggering.
*/
- residue = comedi_bytes_to_samples(s, get_dma_residue(devpriv->dma));
- num_points = max_points - residue;
+ residue = comedi_isadma_disable(desc->chan);
+
+ /* figure out how many points to read */
+ max_points = comedi_bytes_to_samples(s, desc->size);
+ num_points = max_points - comedi_bytes_to_samples(s, residue);
if (devpriv->count < num_points && cmd->stop_src == TRIG_COUNT)
num_points = devpriv->count;
/* figure out how many points will be stored next time */
leftover = 0;
if (cmd->stop_src == TRIG_NONE) {
- leftover = comedi_bytes_to_samples(s,
- devpriv->dma_transfer_size);
+ leftover = comedi_bytes_to_samples(s, desc->size);
} else if (devpriv->count > max_points) {
leftover = devpriv->count - max_points;
if (leftover > max_points)
@@ -234,7 +216,7 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
for (i = 0; i < num_points; i++) {
/* write data point to comedi buffer */
- dpnt = devpriv->dma_buffer[i];
+ dpnt = buf[i];
/* convert from 2's complement to unsigned coding */
dpnt ^= 0x8000;
comedi_buf_write_samples(s, &dpnt, 1);
@@ -245,14 +227,11 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
}
}
}
- /* re-enable dma */
+ /* re-enable dma */
if (leftover) {
- set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer));
- set_dma_count(devpriv->dma,
- comedi_samples_to_bytes(s, leftover));
- enable_dma(devpriv->dma);
+ desc->size = comedi_samples_to_bytes(s, leftover);
+ comedi_isadma_program(desc);
}
- release_dma_lock(flags);
comedi_handle_events(dev, s);
@@ -265,13 +244,15 @@ static irqreturn_t a2150_interrupt(int irq, void *d)
static int a2150_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct a2150_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[0];
/* disable dma on card */
devpriv->irq_dma_bits &= ~DMA_INTR_EN_BIT & ~DMA_EN_BIT;
outw(devpriv->irq_dma_bits, dev->iobase + IRQ_DMA_CNTRL_REG);
/* disable computer's dma */
- disable_dma(devpriv->dma);
+ comedi_isadma_disable(desc->chan);
/* clear fifo and reset triggering circuitry */
outw(0, dev->iobase + FIFO_RESET_REG);
@@ -503,10 +484,11 @@ static int a2150_ai_cmdtest(struct comedi_device *dev,
static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct a2150_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[0];
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
unsigned long timer_base = dev->iobase + I8253_BASE_REG;
- unsigned long lock_flags;
unsigned int old_config_bits = devpriv->config_bits;
unsigned int trigger_bits;
@@ -542,27 +524,19 @@ static int a2150_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
/* initialize number of samples remaining */
devpriv->count = cmd->stop_arg * cmd->chanlist_len;
- /* enable computer's dma */
- lock_flags = claim_dma_lock();
- disable_dma(devpriv->dma);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, virt_to_bus(devpriv->dma_buffer));
+ comedi_isadma_disable(desc->chan);
+
/* set size of transfer to fill in 1/3 second */
#define ONE_THIRD_SECOND 333333333
- devpriv->dma_transfer_size =
- sizeof(devpriv->dma_buffer[0]) * cmd->chanlist_len *
- ONE_THIRD_SECOND / cmd->scan_begin_arg;
- if (devpriv->dma_transfer_size > A2150_DMA_BUFFER_SIZE)
- devpriv->dma_transfer_size = A2150_DMA_BUFFER_SIZE;
- if (devpriv->dma_transfer_size < sizeof(devpriv->dma_buffer[0]))
- devpriv->dma_transfer_size = sizeof(devpriv->dma_buffer[0]);
- devpriv->dma_transfer_size -=
- devpriv->dma_transfer_size % sizeof(devpriv->dma_buffer[0]);
- set_dma_count(devpriv->dma, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma);
- release_dma_lock(lock_flags);
+ desc->size = comedi_bytes_per_sample(s) * cmd->chanlist_len *
+ ONE_THIRD_SECOND / cmd->scan_begin_arg;
+ if (desc->size > desc->maxsize)
+ desc->size = desc->maxsize;
+ if (desc->size < comedi_bytes_per_sample(s))
+ desc->size = comedi_bytes_per_sample(s);
+ desc->size -= desc->size % comedi_bytes_per_sample(s);
+
+ comedi_isadma_program(desc);
/* clear dma interrupt before enabling it, to try and get rid of that
* one spurious interrupt that has been happening */
@@ -677,6 +651,45 @@ static int a2150_ai_rinsn(struct comedi_device *dev, struct comedi_subdevice *s,
return n;
}
+static void a2150_alloc_irq_and_dma(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct a2150_private *devpriv = dev->private;
+ unsigned int irq_num = it->options[1];
+ unsigned int dma_chan = it->options[2];
+
+ /*
+ * Only IRQs 15, 14, 12-9, and 7-3 are valid.
+ * Only DMA channels 7-5 and 3-0 are valid.
+ */
+ if (irq_num > 15 || dma_chan > 7 ||
+ !((1 << irq_num) & 0xdef8) || !((1 << dma_chan) & 0xef))
+ return;
+
+ if (request_irq(irq_num, a2150_interrupt, 0, dev->board_name, dev))
+ return;
+
+ /* DMA uses 1 buffer */
+ devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan,
+ A2150_DMA_BUFFER_SIZE,
+ COMEDI_ISADMA_READ);
+ if (!devpriv->dma) {
+ free_irq(irq_num, dev);
+ } else {
+ dev->irq = irq_num;
+ devpriv->irq_dma_bits = IRQ_LVL_BITS(irq_num) |
+ DMA_CHAN_BITS(dma_chan);
+ }
+}
+
+static void a2150_free_dma(struct comedi_device *dev)
+{
+ struct a2150_private *devpriv = dev->private;
+
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
+}
+
/* probes board type, returns offset */
static int a2150_probe(struct comedi_device *dev)
{
@@ -690,8 +703,6 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
const struct a2150_board *thisboard;
struct a2150_private *devpriv;
struct comedi_subdevice *s;
- unsigned int irq = it->options[1];
- unsigned int dma = it->options[2];
static const int timeout = 2000;
int i;
int ret;
@@ -712,31 +723,8 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
thisboard = dev->board_ptr;
dev->board_name = thisboard->name;
- if ((irq >= 3 && irq <= 7) || (irq >= 9 && irq <= 12) ||
- irq == 14 || irq == 15) {
- ret = request_irq(irq, a2150_interrupt, 0,
- dev->board_name, dev);
- if (ret == 0) {
- devpriv->irq_dma_bits |= IRQ_LVL_BITS(irq);
- dev->irq = irq;
- }
- }
-
- if (dev->irq && dma <= 7 && dma != 4) {
- ret = request_dma(dma, dev->board_name);
- if (ret == 0) {
- devpriv->dma = dma;
- devpriv->dma_buffer = kmalloc(A2150_DMA_BUFFER_SIZE,
- GFP_KERNEL | GFP_DMA);
- if (!devpriv->dma_buffer)
- return -ENOMEM;
-
- disable_dma(dma);
- set_dma_mode(dma, DMA_MODE_READ);
-
- devpriv->irq_dma_bits |= DMA_CHAN_BITS(dma);
- }
- }
+ /* an IRQ and DMA are required to support async commands */
+ a2150_alloc_irq_and_dma(dev, it);
ret = comedi_alloc_subdevices(dev, 1);
if (ret)
@@ -750,7 +738,7 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = 0xffff;
s->range_table = &range_a2150;
s->insn_read = a2150_ai_rinsn;
- if (dev->irq && devpriv->dma) {
+ if (dev->irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->len_chanlist = s->n_chan;
@@ -791,15 +779,9 @@ static int a2150_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void a2150_detach(struct comedi_device *dev)
{
- struct a2150_private *devpriv = dev->private;
-
if (dev->iobase)
outw(APD_BIT | DPD_BIT, dev->iobase + CONFIG_REG);
- if (devpriv) {
- if (devpriv->dma)
- free_dma(devpriv->dma);
- kfree(devpriv->dma_buffer);
- }
+ a2150_free_dma(dev);
comedi_legacy_detach(dev);
};
diff --git a/drivers/staging/comedi/drivers/ni_at_ao.c b/drivers/staging/comedi/drivers/ni_at_ao.c
index 05370a4a74a5..9eeaf3c5a858 100644
--- a/drivers/staging/comedi/drivers/ni_at_ao.c
+++ b/drivers/staging/comedi/drivers/ni_at_ao.c
@@ -19,8 +19,7 @@
/*
* Driver: ni_at_ao
* Description: National Instruments AT-AO-6/10
- * Devices: (National Instruments) AT-AO-6 [at-ao-6]
- * (National Instruments) AT-AO-10 [at-ao-10]
+ * Devices: [National Instruments] AT-AO-6 (at-ao-6), AT-AO-10 (at-ao-10)
* Status: should work
* Author: David A. Schleef <ds@schleef.org>
* Updated: Sun Dec 26 12:26:28 EST 2004
diff --git a/drivers/staging/comedi/drivers/ni_atmio.c b/drivers/staging/comedi/drivers/ni_atmio.c
index 0c5ff287dcef..301f154be813 100644
--- a/drivers/staging/comedi/drivers/ni_atmio.c
+++ b/drivers/staging/comedi/drivers/ni_atmio.c
@@ -300,7 +300,6 @@ static int ni_atmio_attach(struct comedi_device *dev,
struct comedi_devconfig *it)
{
const struct ni_board_struct *boardtype;
- struct ni_private *devpriv;
struct pnp_dev *isapnp_dev;
int ret;
unsigned long iobase;
@@ -310,7 +309,6 @@ static int ni_atmio_attach(struct comedi_device *dev,
ret = ni_alloc_private(dev);
if (ret)
return ret;
- devpriv = dev->private;
iobase = it->options[0];
irq = it->options[1];
diff --git a/drivers/staging/comedi/drivers/ni_daq_700.c b/drivers/staging/comedi/drivers/ni_daq_700.c
index 5e472cb7fbd7..8f6396edd21c 100644
--- a/drivers/staging/comedi/drivers/ni_daq_700.c
+++ b/drivers/staging/comedi/drivers/ni_daq_700.c
@@ -51,10 +51,7 @@
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
/* daqcard700 registers */
#define DIO_W 0x04 /* WO 8bit */
diff --git a/drivers/staging/comedi/drivers/ni_daq_dio24.c b/drivers/staging/comedi/drivers/ni_daq_dio24.c
index 8cfabdbaa30c..a208cb348437 100644
--- a/drivers/staging/comedi/drivers/ni_daq_dio24.c
+++ b/drivers/staging/comedi/drivers/ni_daq_dio24.c
@@ -32,11 +32,7 @@ the PCMCIA interface.
*/
#include <linux/module.h>
-#include "../comedidev.h"
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
+#include "../comedi_pcmcia.h"
#include "8255.h"
diff --git a/drivers/staging/comedi/drivers/ni_labpc.c b/drivers/staging/comedi/drivers/ni_labpc.c
index 1fbfdb4c80c0..a916047791b8 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.c
+++ b/drivers/staging/comedi/drivers/ni_labpc.c
@@ -17,9 +17,8 @@
/*
* Driver: ni_labpc
* Description: National Instruments Lab-PC (& compatibles)
- * Devices: (National Instruments) Lab-PC-1200 [lab-pc-1200]
- * (National Instruments) Lab-PC-1200AI [lab-pc-1200ai]
- * (National Instruments) Lab-PC+ [lab-pc+]
+ * Devices: [National Instruments] Lab-PC-1200 (lab-pc-1200),
+ * Lab-PC-1200AI (lab-pc-1200ai), Lab-PC+ (lab-pc+)
* Author: Frank Mori Hess <fmhess@users.sourceforge.net>
* Status: works
*
@@ -85,15 +84,10 @@ static const struct labpc_boardinfo labpc_boards[] = {
static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
- struct labpc_private *devpriv;
unsigned int irq = it->options[1];
unsigned int dma_chan = it->options[2];
int ret;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
ret = comedi_request_region(dev, it->options[0], 0x20);
if (ret)
return ret;
@@ -110,11 +104,7 @@ static int labpc_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void labpc_detach(struct comedi_device *dev)
{
- struct labpc_private *devpriv = dev->private;
-
- if (devpriv)
- labpc_free_dma_chan(dev);
-
+ labpc_free_dma_chan(dev);
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc.h b/drivers/staging/comedi/drivers/ni_labpc.h
index ac2c01f9dfdc..be89ae479afc 100644
--- a/drivers/staging/comedi/drivers/ni_labpc.h
+++ b/drivers/staging/comedi/drivers/ni_labpc.h
@@ -35,6 +35,8 @@ struct labpc_boardinfo {
};
struct labpc_private {
+ struct comedi_isadma *dma;
+
/* number of data points left to be taken */
unsigned long long count;
/* software copys of bits written to command registers */
@@ -61,11 +63,7 @@ struct labpc_private {
* conversions
*/
unsigned int divisor_b1;
- unsigned int dma_chan; /* dma channel to use */
- u16 *dma_buffer; /* buffer ai will dma into */
- phys_addr_t dma_addr;
- /* transfer size in bytes for current transfer */
- unsigned int dma_transfer_size;
+
/* we are using dma/fifo-half-full/etc. */
enum transfer_type current_transfer;
/*
diff --git a/drivers/staging/comedi/drivers/ni_labpc_common.c b/drivers/staging/comedi/drivers/ni_labpc_common.c
index d89d5852aeea..b88ee2614bfe 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_common.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_common.c
@@ -368,10 +368,6 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
enum scan_mode mode)
{
struct labpc_private *devpriv = dev->private;
- /* max value for 16 bit counter in mode 2 */
- const int max_counter_value = 0x10000;
- /* min value for 16 bit counter in mode 2 */
- const int min_counter_value = 2;
unsigned int base_period;
unsigned int scan_period;
unsigned int convert_period;
@@ -388,11 +384,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
* clock speed on convert and scan counters)
*/
devpriv->divisor_b0 = (scan_period - 1) /
- (I8254_OSC_BASE_2MHZ * max_counter_value) + 1;
- if (devpriv->divisor_b0 < min_counter_value)
- devpriv->divisor_b0 = min_counter_value;
- if (devpriv->divisor_b0 > max_counter_value)
- devpriv->divisor_b0 = max_counter_value;
+ (I8254_OSC_BASE_2MHZ * 0x10000) + 1;
+
+ cfc_check_trigger_arg_min(&devpriv->divisor_b0, 2);
+ cfc_check_trigger_arg_max(&devpriv->divisor_b0, 0x10000);
base_period = I8254_OSC_BASE_2MHZ * devpriv->divisor_b0;
@@ -400,16 +395,16 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
switch (cmd->flags & CMDF_ROUND_MASK) {
default:
case CMDF_ROUND_NEAREST:
- devpriv->divisor_a0 =
- (convert_period + (base_period / 2)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period / 2)) / base_period;
+ devpriv->divisor_a0 = DIV_ROUND_CLOSEST(convert_period,
+ base_period);
+ devpriv->divisor_b1 = DIV_ROUND_CLOSEST(scan_period,
+ base_period);
break;
case CMDF_ROUND_UP:
- devpriv->divisor_a0 =
- (convert_period + (base_period - 1)) / base_period;
- devpriv->divisor_b1 =
- (scan_period + (base_period - 1)) / base_period;
+ devpriv->divisor_a0 = DIV_ROUND_UP(convert_period,
+ base_period);
+ devpriv->divisor_b1 = DIV_ROUND_UP(scan_period,
+ base_period);
break;
case CMDF_ROUND_DOWN:
devpriv->divisor_a0 = convert_period / base_period;
@@ -417,14 +412,10 @@ static void labpc_adc_timing(struct comedi_device *dev, struct comedi_cmd *cmd,
break;
}
/* make sure a0 and b1 values are acceptable */
- if (devpriv->divisor_a0 < min_counter_value)
- devpriv->divisor_a0 = min_counter_value;
- if (devpriv->divisor_a0 > max_counter_value)
- devpriv->divisor_a0 = max_counter_value;
- if (devpriv->divisor_b1 < min_counter_value)
- devpriv->divisor_b1 = min_counter_value;
- if (devpriv->divisor_b1 > max_counter_value)
- devpriv->divisor_b1 = max_counter_value;
+ cfc_check_trigger_arg_min(&devpriv->divisor_a0, 2);
+ cfc_check_trigger_arg_max(&devpriv->divisor_a0, 0x10000);
+ cfc_check_trigger_arg_min(&devpriv->divisor_b1, 2);
+ cfc_check_trigger_arg_max(&devpriv->divisor_b1, 0x10000);
/* write corrected timings to command */
labpc_set_ai_convert_period(cmd, mode,
base_period * devpriv->divisor_a0);
@@ -687,7 +678,7 @@ static int labpc_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
}
/* figure out what method we will use to transfer data */
- if (labpc_have_dma_chan(dev) &&
+ if (devpriv->dma &&
/* dma unsafe at RT priority,
* and too much setup time for CMDF_WAKE_EOS */
(cmd->flags & (CMDF_WAKE_EOS | CMDF_PRIORITY)) == 0)
@@ -823,7 +814,7 @@ static int labpc_drain_fifo(struct comedi_device *dev)
}
if (i == timeout) {
dev_err(dev->class_dev, "ai timeout, fifo never empties\n");
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
return -1;
}
@@ -875,7 +866,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
if (devpriv->stat1 & STAT1_OVERRUN) {
/* clear error interrupt */
devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
dev_err(dev->class_dev, "overrun\n");
return IRQ_HANDLED;
@@ -895,7 +886,7 @@ static irqreturn_t labpc_interrupt(int irq, void *d)
if (devpriv->stat1 & STAT1_OVERFLOW) {
/* clear error interrupt */
devpriv->write_byte(dev, 0x1, ADC_FIFO_CLEAR_REG);
- async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
dev_err(dev->class_dev, "overflow\n");
return IRQ_HANDLED;
@@ -1215,11 +1206,15 @@ int labpc_common_attach(struct comedi_device *dev,
unsigned int irq, unsigned long isr_flags)
{
const struct labpc_boardinfo *board = dev->board_ptr;
- struct labpc_private *devpriv = dev->private;
+ struct labpc_private *devpriv;
struct comedi_subdevice *s;
int ret;
int i;
+ devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
+ if (!devpriv)
+ return -ENOMEM;
+
if (dev->mmio) {
devpriv->read_byte = labpc_readb;
devpriv->write_byte = labpc_writeb;
diff --git a/drivers/staging/comedi/drivers/ni_labpc_cs.c b/drivers/staging/comedi/drivers/ni_labpc_cs.c
index 0a8b3223f74e..746c4cd9978d 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_cs.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_cs.c
@@ -54,19 +54,11 @@ NI manuals:
*/
#include <linux/module.h>
-#include "../comedidev.h"
-#include <linux/delay.h>
+#include "../comedi_pcmcia.h"
-#include "8253.h"
-#include "8255.h"
-#include "comedi_fc.h"
#include "ni_labpc.h"
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
static const struct labpc_boardinfo labpc_cs_boards[] = {
{
.name = "daqcard-1200",
@@ -80,7 +72,6 @@ static int labpc_auto_attach(struct comedi_device *dev,
unsigned long context)
{
struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
- struct labpc_private *devpriv;
int ret;
/* The ni_labpc driver needs the board_ptr */
@@ -96,10 +87,6 @@ static int labpc_auto_attach(struct comedi_device *dev,
if (!link->irq)
return -EINVAL;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
return labpc_common_attach(dev, link->irq, IRQF_SHARED);
}
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.c b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
index 6d386050e59d..6b4ccd86b3d0 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_isadma.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.c
@@ -19,23 +19,25 @@
#include <linux/module.h>
#include <linux/slab.h>
-#include "../comedidev.h"
-#include <asm/dma.h>
+#include "../comedidev.h"
+#include "comedi_isadma.h"
#include "comedi_fc.h"
#include "ni_labpc.h"
#include "ni_labpc_regs.h"
#include "ni_labpc_isadma.h"
/* size in bytes of dma buffer */
-static const int dma_buffer_size = 0xff00;
-/* 2 bytes per sample */
-static const int sample_size = 2;
+#define LABPC_ISADMA_BUFFER_SIZE 0xff00
/* utility function that suggests a dma transfer size in bytes */
-static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
+static unsigned int labpc_suggest_transfer_size(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int maxbytes)
{
+ struct comedi_cmd *cmd = &s->async->cmd;
+ unsigned int sample_size = comedi_bytes_per_sample(s);
unsigned int size;
unsigned int freq;
@@ -49,8 +51,8 @@ static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
size = (freq / 3) * sample_size;
/* set a minimum and maximum size allowed */
- if (size > dma_buffer_size)
- size = dma_buffer_size - dma_buffer_size % sample_size;
+ if (size > maxbytes)
+ size = maxbytes;
else if (size < sample_size)
size = sample_size;
@@ -60,23 +62,18 @@ static unsigned int labpc_suggest_transfer_size(const struct comedi_cmd *cmd)
void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct labpc_private *devpriv = dev->private;
+ struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
struct comedi_cmd *cmd = &s->async->cmd;
- unsigned long irq_flags;
-
- irq_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma_chan);
- set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
+ unsigned int sample_size = comedi_bytes_per_sample(s);
+
/* set appropriate size of transfer */
- devpriv->dma_transfer_size = labpc_suggest_transfer_size(cmd);
+ desc->size = labpc_suggest_transfer_size(dev, s, desc->maxsize);
if (cmd->stop_src == TRIG_COUNT &&
- devpriv->count * sample_size < devpriv->dma_transfer_size)
- devpriv->dma_transfer_size = devpriv->count * sample_size;
- set_dma_count(devpriv->dma_chan, devpriv->dma_transfer_size);
- enable_dma(devpriv->dma_chan);
- release_dma_lock(irq_flags);
+ devpriv->count * sample_size < desc->size)
+ desc->size = devpriv->count * sample_size;
+
+ comedi_isadma_program(desc);
+
/* set CMD3 bits for caller to enable DMA and interrupt */
devpriv->cmd3 |= (CMD3_DMAEN | CMD3_DMATCINTEN);
}
@@ -85,61 +82,55 @@ EXPORT_SYMBOL_GPL(labpc_setup_dma);
void labpc_drain_dma(struct comedi_device *dev)
{
struct labpc_private *devpriv = dev->private;
+ struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
struct comedi_subdevice *s = dev->read_subdev;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
- int status;
- unsigned long flags;
- unsigned int max_points, num_points, residue, leftover;
+ unsigned int max_samples = comedi_bytes_to_samples(s, desc->size);
+ unsigned int residue;
+ unsigned int nsamples;
+ unsigned int leftover;
- status = devpriv->stat1;
-
- flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- /* clear flip-flop to make sure 2-byte registers for
- * count and address get set correctly */
- clear_dma_ff(devpriv->dma_chan);
-
- /* figure out how many points to read */
- max_points = devpriv->dma_transfer_size / sample_size;
- /* residue is the number of points left to be done on the dma
+ /*
+ * residue is the number of bytes left to be done on the dma
* transfer. It should always be zero at this point unless
* the stop_src is set to external triggering.
*/
- residue = get_dma_residue(devpriv->dma_chan) / sample_size;
- num_points = max_points - residue;
- if (cmd->stop_src == TRIG_COUNT && devpriv->count < num_points)
- num_points = devpriv->count;
-
- /* figure out how many points will be stored next time */
- leftover = 0;
- if (cmd->stop_src != TRIG_COUNT) {
- leftover = devpriv->dma_transfer_size / sample_size;
- } else if (devpriv->count > num_points) {
- leftover = devpriv->count - num_points;
- if (leftover > max_points)
- leftover = max_points;
- }
-
- comedi_buf_write_samples(s, devpriv->dma_buffer, num_points);
+ residue = comedi_isadma_disable(desc->chan);
- if (cmd->stop_src == TRIG_COUNT)
- devpriv->count -= num_points;
+ /*
+ * Figure out how many samples to read for this transfer and
+ * how many will be stored for next time.
+ */
+ nsamples = max_samples - comedi_bytes_to_samples(s, residue);
+ if (cmd->stop_src == TRIG_COUNT) {
+ if (devpriv->count <= nsamples) {
+ nsamples = devpriv->count;
+ leftover = 0;
+ } else {
+ leftover = devpriv->count - nsamples;
+ if (leftover > max_samples)
+ leftover = max_samples;
+ }
+ devpriv->count -= nsamples;
+ } else {
+ leftover = max_samples;
+ }
+ desc->size = comedi_samples_to_bytes(s, leftover);
- /* set address and count for next transfer */
- set_dma_addr(devpriv->dma_chan, devpriv->dma_addr);
- set_dma_count(devpriv->dma_chan, leftover * sample_size);
- release_dma_lock(flags);
+ comedi_buf_write_samples(s, desc->virt_addr, nsamples);
}
EXPORT_SYMBOL_GPL(labpc_drain_dma);
static void handle_isa_dma(struct comedi_device *dev)
{
struct labpc_private *devpriv = dev->private;
+ struct comedi_isadma_desc *desc = &devpriv->dma->desc[0];
labpc_drain_dma(dev);
- enable_dma(devpriv->dma_chan);
+ if (desc->size)
+ comedi_isadma_program(desc);
/* clear dma tc interrupt */
devpriv->write_byte(dev, 0x1, DMATC_CLEAR_REG);
@@ -160,36 +151,18 @@ void labpc_handle_dma_status(struct comedi_device *dev)
}
EXPORT_SYMBOL_GPL(labpc_handle_dma_status);
-int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
+void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan)
{
struct labpc_private *devpriv = dev->private;
- void *dma_buffer;
- unsigned long dma_flags;
- int ret;
+ /* only DMA channels 3 and 1 are valid */
if (dma_chan != 1 && dma_chan != 3)
- return -EINVAL;
-
- dma_buffer = kmalloc(dma_buffer_size, GFP_KERNEL | GFP_DMA);
- if (!dma_buffer)
- return -ENOMEM;
-
- ret = request_dma(dma_chan, dev->board_name);
- if (ret) {
- kfree(dma_buffer);
- return ret;
- }
-
- devpriv->dma_buffer = dma_buffer;
- devpriv->dma_chan = dma_chan;
- devpriv->dma_addr = virt_to_bus(devpriv->dma_buffer);
-
- dma_flags = claim_dma_lock();
- disable_dma(devpriv->dma_chan);
- set_dma_mode(devpriv->dma_chan, DMA_MODE_READ);
- release_dma_lock(dma_flags);
+ return;
- return 0;
+ /* DMA uses 1 buffer */
+ devpriv->dma = comedi_isadma_alloc(dev, 1, dma_chan, dma_chan,
+ LABPC_ISADMA_BUFFER_SIZE,
+ COMEDI_ISADMA_READ);
}
EXPORT_SYMBOL_GPL(labpc_init_dma_chan);
@@ -197,12 +170,8 @@ void labpc_free_dma_chan(struct comedi_device *dev)
{
struct labpc_private *devpriv = dev->private;
- kfree(devpriv->dma_buffer);
- devpriv->dma_buffer = NULL;
- if (devpriv->dma_chan) {
- free_dma(devpriv->dma_chan);
- devpriv->dma_chan = 0;
- }
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
}
EXPORT_SYMBOL_GPL(labpc_free_dma_chan);
diff --git a/drivers/staging/comedi/drivers/ni_labpc_isadma.h b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
index 771af4bd5a76..b8a1b0ee6290 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_isadma.h
+++ b/drivers/staging/comedi/drivers/ni_labpc_isadma.h
@@ -5,18 +5,9 @@
#ifndef _NI_LABPC_ISADMA_H
#define _NI_LABPC_ISADMA_H
-#define NI_LABPC_HAVE_ISA_DMA IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA)
+#if IS_ENABLED(CONFIG_COMEDI_NI_LABPC_ISADMA)
-#if NI_LABPC_HAVE_ISA_DMA
-
-static inline bool labpc_have_dma_chan(struct comedi_device *dev)
-{
- struct labpc_private *devpriv = dev->private;
-
- return (bool)devpriv->dma_chan;
-}
-
-int labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan);
+void labpc_init_dma_chan(struct comedi_device *dev, unsigned int dma_chan);
void labpc_free_dma_chan(struct comedi_device *dev);
void labpc_setup_dma(struct comedi_device *dev, struct comedi_subdevice *s);
void labpc_drain_dma(struct comedi_device *dev);
@@ -24,15 +15,9 @@ void labpc_handle_dma_status(struct comedi_device *dev);
#else
-static inline bool labpc_have_dma_chan(struct comedi_device *dev)
-{
- return false;
-}
-
-static inline int labpc_init_dma_chan(struct comedi_device *dev,
- unsigned int dma_chan)
+static inline void labpc_init_dma_chan(struct comedi_device *dev,
+ unsigned int dma_chan)
{
- return -ENOTSUPP;
}
static inline void labpc_free_dma_chan(struct comedi_device *dev)
diff --git a/drivers/staging/comedi/drivers/ni_labpc_pci.c b/drivers/staging/comedi/drivers/ni_labpc_pci.c
index 3fc420406564..0407ff681dfd 100644
--- a/drivers/staging/comedi/drivers/ni_labpc_pci.c
+++ b/drivers/staging/comedi/drivers/ni_labpc_pci.c
@@ -17,7 +17,7 @@
/*
* Driver: ni_labpc_pci
* Description: National Instruments Lab-PC PCI-1200
- * Devices: (National Instruments) PCI-1200 [ni_pci-1200]
+ * Devices: [National Instruments] PCI-1200 (ni_pci-1200)
* Author: Frank Mori Hess <fmhess@users.sourceforge.net>
* Status: works
*
@@ -79,7 +79,6 @@ static int labpc_pci_auto_attach(struct comedi_device *dev,
{
struct pci_dev *pcidev = comedi_to_pci_dev(dev);
const struct labpc_boardinfo *board = NULL;
- struct labpc_private *devpriv;
int ret;
if (context < ARRAY_SIZE(labpc_pci_boards))
@@ -101,10 +100,6 @@ static int labpc_pci_auto_attach(struct comedi_device *dev,
if (!dev->mmio)
return -ENOMEM;
- devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
- if (!devpriv)
- return -ENOMEM;
-
return labpc_common_attach(dev, pcidev->irq, IRQF_SHARED);
}
diff --git a/drivers/staging/comedi/drivers/ni_mio_common.c b/drivers/staging/comedi/drivers/ni_mio_common.c
index 11e70173712d..b6ddc015dedf 100644
--- a/drivers/staging/comedi/drivers/ni_mio_common.c
+++ b/drivers/staging/comedi/drivers/ni_mio_common.c
@@ -1478,7 +1478,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
dev_err(dev->class_dev,
"unknown mite interrupt (ai_mite_status=%08x)\n",
ai_mite_status);
- s->async->events |= COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
/* disable_irq(dev->irq); */
}
#endif
@@ -1491,8 +1491,7 @@ static void handle_a_interrupt(struct comedi_device *dev, unsigned short status,
/* we probably aren't even running a command now,
* so it's a good idea to be careful. */
if (comedi_is_subdevice_running(s)) {
- s->async->events |=
- COMEDI_CB_ERROR | COMEDI_CB_EOA;
+ s->async->events |= COMEDI_CB_ERROR;
comedi_handle_events(dev, s);
}
return;
@@ -1579,7 +1578,7 @@ static void handle_b_interrupt(struct comedi_device *dev,
dev_err(dev->class_dev,
"unknown mite interrupt (ao_mite_status=%08x)\n",
ao_mite_status);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
}
#endif
diff --git a/drivers/staging/comedi/drivers/ni_mio_cs.c b/drivers/staging/comedi/drivers/ni_mio_cs.c
index 9b201e48233e..e3d821bf2d6a 100644
--- a/drivers/staging/comedi/drivers/ni_mio_cs.c
+++ b/drivers/staging/comedi/drivers/ni_mio_cs.c
@@ -37,16 +37,12 @@ See the notes in the ni_atmio.o driver.
*/
#include <linux/module.h>
-#include "../comedidev.h"
-
#include <linux/delay.h>
+#include "../comedi_pcmcia.h"
#include "ni_stc.h"
#include "8255.h"
-#include <pcmcia/cistpl.h>
-#include <pcmcia/ds.h>
-
/*
* AT specific setup
*/
@@ -163,7 +159,6 @@ static int mio_cs_auto_attach(struct comedi_device *dev,
{
struct pcmcia_device *link = comedi_to_pcmcia_dev(dev);
static const struct ni_board_struct *board;
- struct ni_private *devpriv;
int ret;
board = ni_getboardtype(dev, link);
@@ -188,8 +183,6 @@ static int mio_cs_auto_attach(struct comedi_device *dev,
if (ret)
return ret;
- devpriv = dev->private;
-
return ni_E_init(dev, 0, 1);
}
diff --git a/drivers/staging/comedi/drivers/ni_pcidio.c b/drivers/staging/comedi/drivers/ni_pcidio.c
index db7e8aac67b5..db399fe8c301 100644
--- a/drivers/staging/comedi/drivers/ni_pcidio.c
+++ b/drivers/staging/comedi/drivers/ni_pcidio.c
@@ -418,7 +418,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
CHSR_DRQ1 | CHSR_MRDY)) {
dev_dbg(dev->class_dev,
"unknown mite interrupt, disabling IRQ\n");
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
disable_irq(dev->irq);
}
}
@@ -460,7 +460,7 @@ static irqreturn_t nidio_interrupt(int irq, void *d)
break;
} else if (flags & Waited) {
writeb(ClearWaited, dev->mmio + Group_1_First_Clear);
- async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ async->events |= COMEDI_CB_ERROR;
break;
} else if (flags & PrimaryTC) {
writeb(ClearPrimaryTC,
diff --git a/drivers/staging/comedi/drivers/ni_tio.c b/drivers/staging/comedi/drivers/ni_tio.c
index 0525292c1d8b..c20c51bef3e7 100644
--- a/drivers/staging/comedi/drivers/ni_tio.c
+++ b/drivers/staging/comedi/drivers/ni_tio.c
@@ -16,29 +16,28 @@
*/
/*
-Driver: ni_tio
-Description: National Instruments general purpose counters
-Devices:
-Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
- Herman.Bruyninckx@mech.kuleuven.ac.be,
- Wim.Meeussen@mech.kuleuven.ac.be,
- Klaas.Gadeyne@mech.kuleuven.ac.be,
- Frank Mori Hess <fmhess@users.sourceforge.net>
-Updated: Thu Nov 16 09:50:32 EST 2006
-Status: works
-
-This module is not used directly by end-users. Rather, it
-is used by other drivers (for example ni_660x and ni_pcimio)
-to provide support for NI's general purpose counters. It was
-originally based on the counter code from ni_660x.c and
-ni_mio_common.c.
-
-References:
-DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
-DAQ 6601/6602 User Manual (NI 322137B-01)
-340934b.pdf DAQ-STC reference manual
+ * Module: ni_tio
+ * Description: National Instruments general purpose counters
+ * Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
+ * Herman.Bruyninckx@mech.kuleuven.ac.be,
+ * Wim.Meeussen@mech.kuleuven.ac.be,
+ * Klaas.Gadeyne@mech.kuleuven.ac.be,
+ * Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Updated: Thu Nov 16 09:50:32 EST 2006
+ * Status: works
+ *
+ * This module is not used directly by end-users. Rather, it
+ * is used by other drivers (for example ni_660x and ni_pcimio)
+ * to provide support for NI's general purpose counters. It was
+ * originally based on the counter code from ni_660x.c and
+ * ni_mio_common.c.
+ *
+ * References:
+ * DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
+ * DAQ 6601/6602 User Manual (NI 322137B-01)
+ * 340934b.pdf DAQ-STC reference manual
+ */
-*/
/*
TODO:
Support use of both banks X and Y
diff --git a/drivers/staging/comedi/drivers/ni_tiocmd.c b/drivers/staging/comedi/drivers/ni_tiocmd.c
index 6037bec77ef1..d36c3abd3120 100644
--- a/drivers/staging/comedi/drivers/ni_tiocmd.c
+++ b/drivers/staging/comedi/drivers/ni_tiocmd.c
@@ -16,29 +16,28 @@
*/
/*
-Driver: ni_tiocmd
-Description: National Instruments general purpose counters command support
-Devices:
-Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
- Herman.Bruyninckx@mech.kuleuven.ac.be,
- Wim.Meeussen@mech.kuleuven.ac.be,
- Klaas.Gadeyne@mech.kuleuven.ac.be,
- Frank Mori Hess <fmhess@users.sourceforge.net>
-Updated: Fri, 11 Apr 2008 12:32:35 +0100
-Status: works
-
-This module is not used directly by end-users. Rather, it
-is used by other drivers (for example ni_660x and ni_pcimio)
-to provide command support for NI's general purpose counters.
-It was originally split out of ni_tio.c to stop the 'ni_tio'
-module depending on the 'mite' module.
-
-References:
-DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
-DAQ 6601/6602 User Manual (NI 322137B-01)
-340934b.pdf DAQ-STC reference manual
+ * Module: ni_tiocmd
+ * Description: National Instruments general purpose counters command support
+ * Author: J.P. Mellor <jpmellor@rose-hulman.edu>,
+ * Herman.Bruyninckx@mech.kuleuven.ac.be,
+ * Wim.Meeussen@mech.kuleuven.ac.be,
+ * Klaas.Gadeyne@mech.kuleuven.ac.be,
+ * Frank Mori Hess <fmhess@users.sourceforge.net>
+ * Updated: Fri, 11 Apr 2008 12:32:35 +0100
+ * Status: works
+ *
+ * This module is not used directly by end-users. Rather, it
+ * is used by other drivers (for example ni_660x and ni_pcimio)
+ * to provide command support for NI's general purpose counters.
+ * It was originally split out of ni_tio.c to stop the 'ni_tio'
+ * module depending on the 'mite' module.
+ *
+ * References:
+ * DAQ 660x Register-Level Programmer Manual (NI 370505A-01)
+ * DAQ 6601/6602 User Manual (NI 322137B-01)
+ * 340934b.pdf DAQ-STC reference manual
+ */
-*/
/*
TODO:
Support use of both banks X and Y
diff --git a/drivers/staging/comedi/drivers/ni_usb6501.c b/drivers/staging/comedi/drivers/ni_usb6501.c
index 3b5a1b90366d..5f649f88d55c 100644
--- a/drivers/staging/comedi/drivers/ni_usb6501.c
+++ b/drivers/staging/comedi/drivers/ni_usb6501.c
@@ -96,9 +96,8 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
-#include "../comedidev.h"
+#include "../comedi_usb.h"
#define NI6501_TIMEOUT 1000
diff --git a/drivers/staging/comedi/drivers/pcl711.c b/drivers/staging/comedi/drivers/pcl711.c
index 938aebc8e0ea..cb7e4c37b8b9 100644
--- a/drivers/staging/comedi/drivers/pcl711.c
+++ b/drivers/staging/comedi/drivers/pcl711.c
@@ -22,10 +22,8 @@
/*
* Driver: pcl711
* Description: Advantech PCL-711 and 711b, ADLink ACL-8112
- * Devices: (Advantech) PCL-711 [pcl711]
- * (Advantech) PCL-711B [pcl711b]
- * (AdLink) ACL-8112HG [acl8112hg]
- * (AdLink) ACL-8112DG [acl8112dg]
+ * Devices: [Advantech] PCL-711 (pcl711), PCL-711B (pcl711b),
+ * [ADLink] ACL-8112HG (acl8112hg), ACL-8112DG (acl8112dg)
* Author: David A. Schleef <ds@schleef.org>
* Janne Jalkanen <jalkanen@cs.hut.fi>
* Eric Bunn <ebu@cs.hut.fi>
diff --git a/drivers/staging/comedi/drivers/pcl724.c b/drivers/staging/comedi/drivers/pcl724.c
index fcc440855e66..74b07e1744c7 100644
--- a/drivers/staging/comedi/drivers/pcl724.c
+++ b/drivers/staging/comedi/drivers/pcl724.c
@@ -8,14 +8,10 @@
/*
* Driver: pcl724
* Description: Comedi driver for 8255 based ISA DIO boards
- * Devices: (Advantech) PCL-724 [pcl724]
- * (Advantech) PCL-722 [pcl722]
- * (Advantech) PCL-731 [pcl731]
- * (ADLink) ACL-7122 [acl7122]
- * (ADLink) ACL-7124 [acl7124]
- * (ADLink) PET-48DIO [pet48dio]
- * (WinSystems) PCM-IO48 [pcmio48]
- * (Diamond Systems) ONYX-MM-DIO [onyx-mm-dio]
+ * Devices: [Advantech] PCL-724 (pcl724), PCL-722 (pcl722), PCL-731 (pcl731),
+ * [ADLink] ACL-7122 (acl7122), ACL-7124 (acl7124), PET-48DIO (pet48dio),
+ * [WinSystems] PCM-IO48 (pcmio48),
+ * [Diamond Systems] ONYX-MM-DIO (onyx-mm-dio)
* Author: Michal Dobes <dobes@tesnet.cz>
* Status: untested
*
diff --git a/drivers/staging/comedi/drivers/pcl726.c b/drivers/staging/comedi/drivers/pcl726.c
index 86f713fdf1d0..40798150cfd8 100644
--- a/drivers/staging/comedi/drivers/pcl726.c
+++ b/drivers/staging/comedi/drivers/pcl726.c
@@ -21,11 +21,8 @@
* Description: Advantech PCL-726 & compatibles
* Author: David A. Schleef <ds@schleef.org>
* Status: untested
- * Devices: (Advantech) PCL-726 [pcl726]
- * (Advantech) PCL-727 [pcl727]
- * (Advantech) PCL-728 [pcl728]
- * (ADLink) ACL-6126 [acl6126]
- * (ADLink) ACL-6128 [acl6128]
+ * Devices: [Advantech] PCL-726 (pcl726), PCL-727 (pcl727), PCL-728 (pcl728),
+ * [ADLink] ACL-6126 (acl6126), ACL-6128 (acl6128)
*
* Configuration Options:
* [0] - IO Base
diff --git a/drivers/staging/comedi/drivers/pcl730.c b/drivers/staging/comedi/drivers/pcl730.c
index a6c5770b2808..ce958eef2a61 100644
--- a/drivers/staging/comedi/drivers/pcl730.c
+++ b/drivers/staging/comedi/drivers/pcl730.c
@@ -7,19 +7,12 @@
/*
* Driver: pcl730
* Description: Advantech PCL-730 (& compatibles)
- * Devices: (Advantech) PCL-730 [pcl730]
- * (ICP) ISO-730 [iso730]
- * (Adlink) ACL-7130 [acl7130]
- * (Advantech) PCM-3730 [pcm3730]
- * (Advantech) PCL-725 [pcl725]
- * (ICP) P8R8-DIO [p16r16dio]
- * (Adlink) ACL-7225b [acl7225b]
- * (ICP) P16R16-DIO [p16r16dio]
- * (Advantech) PCL-733 [pcl733]
- * (Advantech) PCL-734 [pcl734]
- * (Diamond Systems) OPMM-1616-XT [opmm-1616-xt]
- * (Diamond Systems) PEARL-MM-P [prearl-mm-p]
- * (Diamond Systems) IR104-PBF [ir104-pbf]
+ * Devices: [Advantech] PCL-730 (pcl730), PCM-3730 (pcm3730), PCL-725 (pcl725),
+ * PCL-733 (pcl733), PCL-734 (pcl734),
+ * [ADLink] ACL-7130 (acl7130), ACL-7225b (acl7225b),
+ * [ICP] ISO-730 (iso730), P8R8-DIO (p8r8dio), P16R16-DIO (p16r16dio),
+ * [Diamond Systems] OPMM-1616-XT (opmm-1616-xt), PEARL-MM-P (pearl-mm-p),
+ * IR104-PBF (ir104-pbf),
* Author: José Luis Sánchez (jsanchezv@teleline.es)
* Status: untested
*
diff --git a/drivers/staging/comedi/drivers/pcl812.c b/drivers/staging/comedi/drivers/pcl812.c
index ac243ca5e0f8..3ffb1ea2ecc8 100644
--- a/drivers/staging/comedi/drivers/pcl812.c
+++ b/drivers/staging/comedi/drivers/pcl812.c
@@ -111,12 +111,12 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/gfp.h>
-#include "../comedidev.h"
-
#include <linux/delay.h>
#include <linux/io.h>
-#include <asm/dma.h>
+#include "../comedidev.h"
+
+#include "comedi_isadma.h"
#include "comedi_fc.h"
#include "8253.h"
@@ -507,19 +507,11 @@ static const struct pcl812_board boardtypes[] = {
};
struct pcl812_private {
- unsigned char dma; /* >0 use dma ( usedDMA channel) */
+ struct comedi_isadma *dma;
unsigned char range_correction; /* =1 we must add 1 to range number */
unsigned int last_ai_chanspec;
unsigned char mode_reg_int; /* there is stored INT number for some card */
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
- unsigned int dmapages;
- unsigned int hwdmasize;
- unsigned long dmabuf[2]; /* PTR to DMA buf */
- unsigned int hwdmaptr[2]; /* HW PTR to DMA buf */
- unsigned int dmabytestomove[2]; /* how many bytes DMA transfer */
- int next_dma_buf; /* which buffer is next to use */
- unsigned int dma_runs_to_end; /* how many times we must switch DMA buffers */
- unsigned int last_dma_run; /* how many bytes to transfer on last DMA buffer */
unsigned int max_812_ai_mode0_rangewait; /* setling time for gain */
unsigned int divisor1;
unsigned int divisor2;
@@ -546,90 +538,32 @@ static void pcl812_start_pacer(struct comedi_device *dev, bool load_timers)
}
static void pcl812_ai_setup_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
+ struct comedi_subdevice *s,
+ unsigned int unread_samples)
{
struct pcl812_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- unsigned int dma_flags;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
unsigned int bytes;
+ unsigned int max_samples;
+ unsigned int nsamples;
- /* we use EOS, so adapt DMA buffer to one scan */
- if (devpriv->ai_eos) {
- devpriv->dmabytestomove[0] = comedi_bytes_per_scan(s);
- devpriv->dmabytestomove[1] = comedi_bytes_per_scan(s);
- devpriv->dma_runs_to_end = 1;
- } else {
- devpriv->dmabytestomove[0] = devpriv->hwdmasize;
- devpriv->dmabytestomove[1] = devpriv->hwdmasize;
- if (s->async->prealloc_bufsz < devpriv->hwdmasize) {
- devpriv->dmabytestomove[0] =
- s->async->prealloc_bufsz;
- devpriv->dmabytestomove[1] =
- s->async->prealloc_bufsz;
- }
- if (cmd->stop_src == TRIG_NONE) {
- devpriv->dma_runs_to_end = 1;
- } else {
- /* how many samples we must transfer? */
- bytes = cmd->stop_arg * comedi_bytes_per_scan(s);
-
- /* how many DMA pages we must fill */
- devpriv->dma_runs_to_end =
- bytes / devpriv->dmabytestomove[0];
-
- /* on last dma transfer must be moved */
- devpriv->last_dma_run =
- bytes % devpriv->dmabytestomove[0];
- if (devpriv->dma_runs_to_end == 0)
- devpriv->dmabytestomove[0] =
- devpriv->last_dma_run;
- devpriv->dma_runs_to_end--;
- }
- }
- if (devpriv->dmabytestomove[0] > devpriv->hwdmasize) {
- devpriv->dmabytestomove[0] = devpriv->hwdmasize;
- devpriv->ai_eos = 0;
- }
- if (devpriv->dmabytestomove[1] > devpriv->hwdmasize) {
- devpriv->dmabytestomove[1] = devpriv->hwdmasize;
- devpriv->ai_eos = 0;
- }
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, devpriv->dmabytestomove[0]);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
-}
+ comedi_isadma_disable(dma->chan);
-static void pcl812_ai_setup_next_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl812_private *devpriv = dev->private;
- unsigned long dma_flags;
-
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- disable_dma(devpriv->dma);
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->ai_eos) {
- set_dma_count(devpriv->dma,
- devpriv->dmabytestomove[devpriv->next_dma_buf]);
- } else {
- if (devpriv->dma_runs_to_end) {
- set_dma_count(devpriv->dma,
- devpriv->dmabytestomove[devpriv->
- next_dma_buf]);
- } else {
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- }
- devpriv->dma_runs_to_end--;
+ /* if using EOS, adapt DMA buffer to one scan */
+ bytes = devpriv->ai_eos ? comedi_bytes_per_scan(s) : desc->maxsize;
+ max_samples = comedi_bytes_to_samples(s, bytes);
+
+ /*
+ * Determine dma size based on the buffer size plus the number of
+ * unread samples and the number of samples remaining in the command.
+ */
+ nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+ if (nsamples > unread_samples) {
+ nsamples -= unread_samples;
+ desc->size = comedi_samples_to_bytes(s, nsamples);
+ comedi_isadma_program(desc);
}
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
}
static void pcl812_ai_set_chan_range(struct comedi_device *dev,
@@ -786,6 +720,7 @@ static int pcl812_ai_cmdtest(struct comedi_device *dev,
static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int ctrl = 0;
unsigned int i;
@@ -794,7 +729,7 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
pcl812_ai_set_chan_range(dev, cmd->chanlist[0], 1);
- if (devpriv->dma) { /* check if we can use DMA transfer */
+ if (dma) { /* check if we can use DMA transfer */
devpriv->ai_dma = 1;
for (i = 1; i < cmd->chanlist_len; i++)
if (cmd->chanlist[0] != cmd->chanlist[i]) {
@@ -817,8 +752,11 @@ static int pcl812_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_dma = 0;
}
- if (devpriv->ai_dma)
- pcl812_ai_setup_dma(dev, s);
+ if (devpriv->ai_dma) {
+ /* setup and enable dma for the first buffer */
+ dma->cur_dma = 0;
+ pcl812_ai_setup_dma(dev, s, 0);
+ }
switch (cmd->convert_src) {
case TRIG_TIMER:
@@ -859,7 +797,7 @@ static void pcl812_handle_eoc(struct comedi_device *dev,
if (pcl812_ai_eoc(dev, s, NULL, 0)) {
dev_dbg(dev->class_dev, "A/D cmd IRQ without DRDY!\n");
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
@@ -895,19 +833,21 @@ static void pcl812_handle_dma(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
- int len, bufptr;
- unsigned short *ptr;
-
- ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
- len = (devpriv->dmabytestomove[devpriv->next_dma_buf] >> 1) -
- devpriv->ai_poll_ptr;
-
- pcl812_ai_setup_next_dma(dev, s);
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned int nsamples;
+ int bufptr;
+ nsamples = comedi_bytes_to_samples(s, desc->size) -
+ devpriv->ai_poll_ptr;
bufptr = devpriv->ai_poll_ptr;
devpriv->ai_poll_ptr = 0;
- transfer_from_dma_buf(dev, s, ptr, bufptr, len);
+ /* restart dma with the next buffer */
+ dma->cur_dma = 1 - dma->cur_dma;
+ pcl812_ai_setup_dma(dev, s, nsamples);
+
+ transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples);
}
static irqreturn_t pcl812_interrupt(int irq, void *d)
@@ -935,45 +875,37 @@ static irqreturn_t pcl812_interrupt(int irq, void *d)
static int pcl812_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl812_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc;
unsigned long flags;
- unsigned int top1, top2, i;
+ unsigned int poll;
+ int ret;
+ /* poll is valid only for DMA transfer */
if (!devpriv->ai_dma)
- return 0; /* poll is valid only for DMA transfer */
+ return 0;
spin_lock_irqsave(&dev->spinlock, flags);
- for (i = 0; i < 10; i++) {
- /* where is now DMA */
- top1 = get_dma_residue(devpriv->ai_dma);
- top2 = get_dma_residue(devpriv->ai_dma);
- if (top1 == top2)
- break;
- }
-
- if (top1 != top2) {
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
- }
- /* where is now DMA in buffer */
- top1 = devpriv->dmabytestomove[1 - devpriv->next_dma_buf] - top1;
- top1 >>= 1; /* sample position */
- top2 = top1 - devpriv->ai_poll_ptr;
- if (top2 < 1) { /* no new samples */
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
+ poll = comedi_isadma_poll(dma);
+ poll = comedi_bytes_to_samples(s, poll);
+ if (poll > devpriv->ai_poll_ptr) {
+ desc = &dma->desc[dma->cur_dma];
+ transfer_from_dma_buf(dev, s, desc->virt_addr,
+ devpriv->ai_poll_ptr,
+ poll - devpriv->ai_poll_ptr);
+ /* new buffer position */
+ devpriv->ai_poll_ptr = poll;
+
+ ret = comedi_buf_n_bytes_ready(s);
+ } else {
+ /* no new samples */
+ ret = 0;
}
- transfer_from_dma_buf(dev, s,
- (void *)devpriv->dmabuf[1 -
- devpriv->next_dma_buf],
- devpriv->ai_poll_ptr, top2);
-
- devpriv->ai_poll_ptr = top1; /* new buffer position */
-
spin_unlock_irqrestore(&dev->spinlock, flags);
- return comedi_buf_n_bytes_ready(s);
+ return ret;
}
static int pcl812_ai_cancel(struct comedi_device *dev,
@@ -982,7 +914,7 @@ static int pcl812_ai_cancel(struct comedi_device *dev,
struct pcl812_private *devpriv = dev->private;
if (devpriv->ai_dma)
- disable_dma(devpriv->dma);
+ comedi_isadma_disable(devpriv->dma->chan);
outb(devpriv->mode_reg_int | PCL812_CTRL_DISABLE_TRIG,
dev->iobase + PCL812_CTRL_REG);
@@ -1192,6 +1124,27 @@ static void pcl812_set_ai_range_table(struct comedi_device *dev,
}
}
+static void pcl812_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+ struct pcl812_private *devpriv = dev->private;
+
+ /* only DMA channels 3 and 1 are valid */
+ if (!(dma_chan == 3 || dma_chan == 1))
+ return;
+
+ /* DMA uses two 8K buffers */
+ devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+ PAGE_SIZE * 2, COMEDI_ISADMA_READ);
+}
+
+static void pcl812_free_dma(struct comedi_device *dev)
+{
+ struct pcl812_private *devpriv = dev->private;
+
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
+}
+
static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl812_board *board = dev->board_ptr;
@@ -1200,7 +1153,6 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
int n_subdevices;
int subdev;
int ret;
- int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -1218,31 +1170,8 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
}
/* we need an IRQ to do DMA on channel 3 or 1 */
- if (dev->irq && board->has_dma &&
- (it->options[2] == 3 || it->options[2] == 1)) {
- ret = request_dma(it->options[2], dev->board_name);
- if (ret) {
- dev_err(dev->class_dev,
- "unable to request DMA channel %d\n",
- it->options[2]);
- return -EBUSY;
- }
- devpriv->dma = it->options[2];
-
- devpriv->dmapages = 1; /* we want 8KB */
- devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
- for (i = 0; i < 2; i++) {
- unsigned long dmabuf;
-
- dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
- if (!dmabuf)
- return -ENOMEM;
-
- devpriv->dmabuf[i] = dmabuf;
- devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
- }
- }
+ if (dev->irq && board->has_dma)
+ pcl812_alloc_dma(dev, it->options[2]);
/* differential analog inputs? */
switch (board->board_type) {
@@ -1384,16 +1313,7 @@ static int pcl812_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void pcl812_detach(struct comedi_device *dev)
{
- struct pcl812_private *devpriv = dev->private;
-
- if (devpriv) {
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- }
+ pcl812_free_dma(dev);
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/pcl816.c b/drivers/staging/comedi/drivers/pcl816.c
index 73deb4bd5c93..da35edfccbc3 100644
--- a/drivers/staging/comedi/drivers/pcl816.c
+++ b/drivers/staging/comedi/drivers/pcl816.c
@@ -33,14 +33,14 @@ Configuration Options:
*/
#include <linux/module.h>
-#include "../comedidev.h"
-
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/interrupt.h>
-#include <asm/dma.h>
+#include "../comedidev.h"
+
+#include "comedi_isadma.h"
#include "comedi_fc.h"
#include "8253.h"
@@ -114,14 +114,7 @@ static const struct pcl816_board boardtypes[] = {
};
struct pcl816_private {
- unsigned int dma; /* used DMA, 0=don't use DMA */
- unsigned int dmapages;
- unsigned int hwdmasize;
- unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- int next_dma_buf; /* which DMA buffer will be used next round */
- long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
- unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
+ struct comedi_isadma *dma;
unsigned int ai_poll_ptr; /* how many sampes transfer poll */
unsigned int divisor1;
unsigned int divisor2;
@@ -149,63 +142,27 @@ static void pcl816_start_pacer(struct comedi_device *dev, bool load_counters)
}
static void pcl816_ai_setup_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl816_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- unsigned int dma_flags;
- unsigned int bytes;
-
- bytes = devpriv->hwdmasize;
- if (cmd->stop_src == TRIG_COUNT) {
- /* how many */
- bytes = cmd->stop_arg * comedi_bytes_per_scan(s);
-
- /* how many DMA pages we must fill */
- devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
-
- /* on last dma transfer must be moved */
- devpriv->last_dma_run = bytes % devpriv->hwdmasize;
- devpriv->dma_runs_to_end--;
- if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize;
- } else
- devpriv->dma_runs_to_end = -1;
-
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
-}
-
-static void pcl816_ai_setup_next_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
+ struct comedi_subdevice *s,
+ unsigned int unread_samples)
{
struct pcl816_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- unsigned long dma_flags;
-
- disable_dma(devpriv->dma);
- if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
- /* switch dma bufs */
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- dma_flags = claim_dma_lock();
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->dma_runs_to_end)
- set_dma_count(devpriv->dma, devpriv->hwdmasize);
- else
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- release_dma_lock(dma_flags);
- enable_dma(devpriv->dma);
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
+ unsigned int nsamples;
+
+ comedi_isadma_disable(dma->chan);
+
+ /*
+ * Determine dma size based on the buffer maxsize plus the number of
+ * unread samples and the number of samples remaining in the command.
+ */
+ nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+ if (nsamples > unread_samples) {
+ nsamples -= unread_samples;
+ desc->size = comedi_samples_to_bytes(s, nsamples);
+ comedi_isadma_program(desc);
}
-
- devpriv->dma_runs_to_end--;
}
static void pcl816_ai_set_chan_range(struct comedi_device *dev,
@@ -318,9 +275,10 @@ static irqreturn_t pcl816_interrupt(int irq, void *d)
struct comedi_device *dev = d;
struct comedi_subdevice *s = dev->read_subdev;
struct pcl816_private *devpriv = dev->private;
- unsigned short *ptr;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned int nsamples;
unsigned int bufptr;
- unsigned int len;
if (!dev->attached || !devpriv->ai_cmd_running) {
pcl816_ai_clear_eoc(dev);
@@ -333,15 +291,16 @@ static irqreturn_t pcl816_interrupt(int irq, void *d)
return IRQ_HANDLED;
}
- ptr = (unsigned short *)devpriv->dmabuf[devpriv->next_dma_buf];
-
- pcl816_ai_setup_next_dma(dev, s);
-
- len = (devpriv->hwdmasize >> 1) - devpriv->ai_poll_ptr;
+ nsamples = comedi_bytes_to_samples(s, desc->size) -
+ devpriv->ai_poll_ptr;
bufptr = devpriv->ai_poll_ptr;
devpriv->ai_poll_ptr = 0;
- transfer_from_dma_buf(dev, s, ptr, bufptr, len);
+ /* restart dma with the next buffer */
+ dma->cur_dma = 1 - dma->cur_dma;
+ pcl816_ai_setup_dma(dev, s, nsamples);
+
+ transfer_from_dma_buf(dev, s, desc->virt_addr, bufptr, nsamples);
pcl816_ai_clear_eoc(dev);
@@ -483,6 +442,7 @@ static int pcl816_ai_cmdtest(struct comedi_device *dev,
static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl816_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int ctrl;
unsigned int seglen;
@@ -502,7 +462,9 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
devpriv->ai_poll_ptr = 0;
devpriv->ai_cmd_canceled = 0;
- pcl816_ai_setup_dma(dev, s);
+ /* setup and enable dma for the first buffer */
+ dma->cur_dma = 0;
+ pcl816_ai_setup_dma(dev, s, 0);
pcl816_start_pacer(dev, true);
@@ -513,7 +475,8 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
ctrl |= PCL816_CTRL_EXT_TRIG;
outb(ctrl, dev->iobase + PCL816_CTRL_REG);
- outb((devpriv->dma << 4) | dev->irq, dev->iobase + PCL816_STATUS_REG);
+ outb((dma->chan << 4) | dev->irq,
+ dev->iobase + PCL816_STATUS_REG);
return 0;
}
@@ -521,42 +484,34 @@ static int pcl816_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int pcl816_ai_poll(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct pcl816_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc;
unsigned long flags;
- unsigned int top1, top2, i;
+ unsigned int poll;
+ int ret;
spin_lock_irqsave(&dev->spinlock, flags);
- for (i = 0; i < 20; i++) {
- top1 = get_dma_residue(devpriv->dma); /* where is now DMA */
- top2 = get_dma_residue(devpriv->dma);
- if (top1 == top2)
- break;
- }
- if (top1 != top2) {
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
- }
-
- /* where is now DMA in buffer */
- top1 = devpriv->hwdmasize - top1;
- top1 >>= 1; /* sample position */
- top2 = top1 - devpriv->ai_poll_ptr;
- if (top2 < 1) { /* no new samples */
- spin_unlock_irqrestore(&dev->spinlock, flags);
- return 0;
- }
+ poll = comedi_isadma_poll(dma);
+ poll = comedi_bytes_to_samples(s, poll);
+ if (poll > devpriv->ai_poll_ptr) {
+ desc = &dma->desc[dma->cur_dma];
+ transfer_from_dma_buf(dev, s, desc->virt_addr,
+ devpriv->ai_poll_ptr,
+ poll - devpriv->ai_poll_ptr);
+ /* new buffer position */
+ devpriv->ai_poll_ptr = poll;
- transfer_from_dma_buf(dev, s,
- (unsigned short *)devpriv->dmabuf[devpriv->
- next_dma_buf],
- devpriv->ai_poll_ptr, top2);
+ comedi_handle_events(dev, s);
- devpriv->ai_poll_ptr = top1; /* new buffer position */
+ ret = comedi_buf_n_bytes_ready(s);
+ } else {
+ /* no new samples */
+ ret = 0;
+ }
spin_unlock_irqrestore(&dev->spinlock, flags);
- comedi_handle_events(dev, s);
-
- return comedi_buf_n_bytes_ready(s);
+ return ret;
}
static int pcl816_ai_cancel(struct comedi_device *dev,
@@ -657,13 +612,44 @@ static void pcl816_reset(struct comedi_device *dev)
outb(0, dev->iobase + PCL816_DO_DI_MSB_REG);
}
+static void pcl816_alloc_irq_and_dma(struct comedi_device *dev,
+ struct comedi_devconfig *it)
+{
+ struct pcl816_private *devpriv = dev->private;
+ unsigned int irq_num = it->options[1];
+ unsigned int dma_chan = it->options[2];
+
+ /* only IRQs 2-7 and DMA channels 3 and 1 are valid */
+ if (!(irq_num >= 2 && irq_num <= 7) ||
+ !(dma_chan == 3 || dma_chan == 1))
+ return;
+
+ if (request_irq(irq_num, pcl816_interrupt, 0, dev->board_name, dev))
+ return;
+
+ /* DMA uses two 16K buffers */
+ devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+ PAGE_SIZE * 4, COMEDI_ISADMA_READ);
+ if (!devpriv->dma)
+ free_irq(irq_num, dev);
+ else
+ dev->irq = irq_num;
+}
+
+static void pcl816_free_dma(struct comedi_device *dev)
+{
+ struct pcl816_private *devpriv = dev->private;
+
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
+}
+
static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl816_board *board = dev->board_ptr;
struct pcl816_private *devpriv;
struct comedi_subdevice *s;
int ret;
- int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -673,39 +659,8 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
if (ret)
return ret;
- /* we can use IRQ 2-7 for async command support */
- if (it->options[1] >= 2 && it->options[1] <= 7) {
- ret = request_irq(it->options[1], pcl816_interrupt, 0,
- dev->board_name, dev);
- if (ret == 0)
- dev->irq = it->options[1];
- }
-
- /* we need an IRQ to do DMA on channel 3 or 1 */
- if (dev->irq && (it->options[2] == 3 || it->options[2] == 1)) {
- ret = request_dma(it->options[2], dev->board_name);
- if (ret) {
- dev_err(dev->class_dev,
- "unable to request DMA channel %d\n",
- it->options[2]);
- return -EBUSY;
- }
- devpriv->dma = it->options[2];
-
- devpriv->dmapages = 2; /* we need 16KB */
- devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
- for (i = 0; i < 2; i++) {
- unsigned long dmabuf;
-
- dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
- if (!dmabuf)
- return -ENOMEM;
-
- devpriv->dmabuf[i] = dmabuf;
- devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
- }
- }
+ /* an IRQ and DMA are required to support async commands */
+ pcl816_alloc_irq_and_dma(dev, it);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -718,7 +673,7 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
s->maxdata = board->ai_maxdata;
s->range_table = &range_pcl816;
s->insn_read = pcl816_ai_insn_read;
- if (devpriv->dma) {
+ if (dev->irq) {
dev->read_subdev = s;
s->subdev_flags |= SDF_CMD_READ;
s->len_chanlist = board->ai_chanlist;
@@ -764,18 +719,11 @@ static int pcl816_attach(struct comedi_device *dev, struct comedi_devconfig *it)
static void pcl816_detach(struct comedi_device *dev)
{
- struct pcl816_private *devpriv = dev->private;
-
if (dev->private) {
pcl816_ai_cancel(dev, dev->read_subdev);
pcl816_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
+ pcl816_free_dma(dev);
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/pcl818.c b/drivers/staging/comedi/drivers/pcl818.c
index 8edea35532a9..7e4cdea5fe59 100644
--- a/drivers/staging/comedi/drivers/pcl818.c
+++ b/drivers/staging/comedi/drivers/pcl818.c
@@ -1,112 +1,105 @@
/*
- comedi/drivers/pcl818.c
-
- Author: Michal Dobes <dobes@tesnet.cz>
-
- hardware driver for Advantech cards:
- card: PCL-818L, PCL-818H, PCL-818HD, PCL-818HG, PCL-818, PCL-718
- driver: pcl818l, pcl818h, pcl818hd, pcl818hg, pcl818, pcl718
-*/
-/*
-Driver: pcl818
-Description: Advantech PCL-818 cards, PCL-718
-Author: Michal Dobes <dobes@tesnet.cz>
-Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
- PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
- PCL-718 (pcl718)
-Status: works
-
-All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
-Differences are only at maximal sample speed, range list and FIFO
-support.
-The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
-only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
-PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
-but this code is untested.
-A word or two about DMA. Driver support DMA operations at two ways:
-1) DMA uses two buffers and after one is filled then is generated
- INT and DMA restart with second buffer. With this mode I'm unable run
- more that 80Ksamples/secs without data dropouts on K6/233.
-2) DMA uses one buffer and run in autoinit mode and the data are
- from DMA buffer moved on the fly with 2kHz interrupts from RTC.
- This mode is used if the interrupt 8 is available for allocation.
- If not, then first DMA mode is used. With this I can run at
- full speed one card (100ksamples/secs) or two cards with
- 60ksamples/secs each (more is problem on account of ISA limitations).
- To use this mode you must have compiled kernel with disabled
- "Enhanced Real Time Clock Support".
- Maybe you can have problems if you use xntpd or similar.
- If you've data dropouts with DMA mode 2 then:
- a) disable IDE DMA
- b) switch text mode console to fb.
-
- Options for PCL-818L:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
- [2] - DMA (0=disable, 1, 3)
- [3] - 0, 10=10MHz clock for 8254
- 1= 1MHz clock for 8254
- [4] - 0, 5=A/D input -5V.. +5V
- 1, 10=A/D input -10V..+10V
- [5] - 0, 5=D/A output 0-5V (internal reference -5V)
- 1, 10=D/A output 0-10V (internal reference -10V)
- 2 =D/A output unknown (external reference)
-
- Options for PCL-818, PCL-818H:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
- [2] - DMA (0=disable, 1, 3)
- [3] - 0, 10=10MHz clock for 8254
- 1= 1MHz clock for 8254
- [4] - 0, 5=D/A output 0-5V (internal reference -5V)
- 1, 10=D/A output 0-10V (internal reference -10V)
- 2 =D/A output unknown (external reference)
-
- Options for PCL-818HD, PCL-818HG:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
- [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
- 1=use DMA ch 1, 3=use DMA ch 3)
- [3] - 0, 10=10MHz clock for 8254
- 1= 1MHz clock for 8254
- [4] - 0, 5=D/A output 0-5V (internal reference -5V)
- 1, 10=D/A output 0-10V (internal reference -10V)
- 2 =D/A output unknown (external reference)
-
- Options for PCL-718:
- [0] - IO Base
- [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
- [2] - DMA (0=disable, 1, 3)
- [3] - 0, 10=10MHz clock for 8254
- 1= 1MHz clock for 8254
- [4] - 0=A/D Range is +/-10V
- 1= +/-5V
- 2= +/-2.5V
- 3= +/-1V
- 4= +/-0.5V
- 5= user defined bipolar
- 6= 0-10V
- 7= 0-5V
- 8= 0-2V
- 9= 0-1V
- 10= user defined unipolar
- [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
- 1, 10=D/A outputs 0-10V (internal reference -10V)
- 2=D/A outputs unknown (external reference)
- [6] - 0, 60=max 60kHz A/D sampling
- 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
-
-*/
+ * comedi/drivers/pcl818.c
+ *
+ * Driver: pcl818
+ * Description: Advantech PCL-818 cards, PCL-718
+ * Author: Michal Dobes <dobes@tesnet.cz>
+ * Devices: [Advantech] PCL-818L (pcl818l), PCL-818H (pcl818h),
+ * PCL-818HD (pcl818hd), PCL-818HG (pcl818hg), PCL-818 (pcl818),
+ * PCL-718 (pcl718)
+ * Status: works
+ *
+ * All cards have 16 SE/8 DIFF ADCs, one or two DACs, 16 DI and 16 DO.
+ * Differences are only at maximal sample speed, range list and FIFO
+ * support.
+ * The driver support AI mode 0, 1, 3 other subdevices (AO, DI, DO) support
+ * only mode 0. If DMA/FIFO/INT are disabled then AI support only mode 0.
+ * PCL-818HD and PCL-818HG support 1kword FIFO. Driver support this FIFO
+ * but this code is untested.
+ * A word or two about DMA. Driver support DMA operations at two ways:
+ * 1) DMA uses two buffers and after one is filled then is generated
+ * INT and DMA restart with second buffer. With this mode I'm unable run
+ * more that 80Ksamples/secs without data dropouts on K6/233.
+ * 2) DMA uses one buffer and run in autoinit mode and the data are
+ * from DMA buffer moved on the fly with 2kHz interrupts from RTC.
+ * This mode is used if the interrupt 8 is available for allocation.
+ * If not, then first DMA mode is used. With this I can run at
+ * full speed one card (100ksamples/secs) or two cards with
+ * 60ksamples/secs each (more is problem on account of ISA limitations).
+ * To use this mode you must have compiled kernel with disabled
+ * "Enhanced Real Time Clock Support".
+ * Maybe you can have problems if you use xntpd or similar.
+ * If you've data dropouts with DMA mode 2 then:
+ * a) disable IDE DMA
+ * b) switch text mode console to fb.
+ *
+ * Options for PCL-818L:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0, 10=10MHz clock for 8254
+ * 1= 1MHz clock for 8254
+ * [4] - 0, 5=A/D input -5V.. +5V
+ * 1, 10=A/D input -10V..+10V
+ * [5] - 0, 5=D/A output 0-5V (internal reference -5V)
+ * 1, 10=D/A output 0-10V (internal reference -10V)
+ * 2 =D/A output unknown (external reference)
+ *
+ * Options for PCL-818, PCL-818H:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0, 10=10MHz clock for 8254
+ * 1= 1MHz clock for 8254
+ * [4] - 0, 5=D/A output 0-5V (internal reference -5V)
+ * 1, 10=D/A output 0-10V (internal reference -10V)
+ * 2 =D/A output unknown (external reference)
+ *
+ * Options for PCL-818HD, PCL-818HG:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - DMA/FIFO (-1=use FIFO, 0=disable both FIFO and DMA,
+ * 1=use DMA ch 1, 3=use DMA ch 3)
+ * [3] - 0, 10=10MHz clock for 8254
+ * 1= 1MHz clock for 8254
+ * [4] - 0, 5=D/A output 0-5V (internal reference -5V)
+ * 1, 10=D/A output 0-10V (internal reference -10V)
+ * 2 =D/A output unknown (external reference)
+ *
+ * Options for PCL-718:
+ * [0] - IO Base
+ * [1] - IRQ (0=disable, 2, 3, 4, 5, 6, 7)
+ * [2] - DMA (0=disable, 1, 3)
+ * [3] - 0, 10=10MHz clock for 8254
+ * 1= 1MHz clock for 8254
+ * [4] - 0=A/D Range is +/-10V
+ * 1= +/-5V
+ * 2= +/-2.5V
+ * 3= +/-1V
+ * 4= +/-0.5V
+ * 5= user defined bipolar
+ * 6= 0-10V
+ * 7= 0-5V
+ * 8= 0-2V
+ * 9= 0-1V
+ * 10= user defined unipolar
+ * [5] - 0, 5=D/A outputs 0-5V (internal reference -5V)
+ * 1, 10=D/A outputs 0-10V (internal reference -10V)
+ * 2=D/A outputs unknown (external reference)
+ * [6] - 0, 60=max 60kHz A/D sampling
+ * 1,100=max 100kHz A/D sampling (PCL-718 with Option 001 installed)
+ *
+ */
#include <linux/module.h>
#include <linux/gfp.h>
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/interrupt.h>
-#include <asm/dma.h>
#include "../comedidev.h"
+#include "comedi_isadma.h"
#include "comedi_fc.h"
#include "8253.h"
@@ -303,20 +296,14 @@ static const struct pcl818_board boardtypes[] = {
};
struct pcl818_private {
- unsigned int dma; /* used DMA, 0=don't use DMA */
- unsigned int dmapages;
- unsigned int hwdmasize;
- unsigned long dmabuf[2]; /* pointers to begin of DMA buffers */
- unsigned int hwdmaptr[2]; /* hardware address of DMA buffers */
- int next_dma_buf; /* which DMA buffer will be used next round */
- long dma_runs_to_end; /* how many we must permorm DMA transfer to end of record */
- unsigned long last_dma_run; /* how many bytes we must transfer on last DMA page */
- unsigned int ns_min; /* manimal allowed delay between samples (in us) for actual card */
+ struct comedi_isadma *dma;
+ /* manimal allowed delay between samples (in us) for actual card */
+ unsigned int ns_min;
int i8253_osc_base; /* 1/frequency of on board oscilator in ns */
- unsigned int act_chanlist[16]; /* MUX setting for actual AI operations */
+ /* MUX setting for actual AI operations */
+ unsigned int act_chanlist[16];
unsigned int act_chanlist_len; /* how long is actual MUX list */
unsigned int act_chanlist_pos; /* actual position in MUX list */
- unsigned int ai_data_len; /* len of data buffer */
unsigned int divisor1;
unsigned int divisor2;
unsigned int usefifo:1;
@@ -340,58 +327,27 @@ static void pcl818_start_pacer(struct comedi_device *dev, bool load_counters)
}
static void pcl818_ai_setup_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- unsigned int flags;
- unsigned int bytes;
-
- disable_dma(devpriv->dma); /* disable dma */
- bytes = devpriv->hwdmasize;
- if (cmd->stop_src == TRIG_COUNT) {
- bytes = cmd->stop_arg * comedi_bytes_per_scan(s);
- devpriv->dma_runs_to_end = bytes / devpriv->hwdmasize;
- devpriv->last_dma_run = bytes % devpriv->hwdmasize;
- devpriv->dma_runs_to_end--;
- if (devpriv->dma_runs_to_end >= 0)
- bytes = devpriv->hwdmasize;
- }
-
- devpriv->next_dma_buf = 0;
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- clear_dma_ff(devpriv->dma);
- set_dma_addr(devpriv->dma, devpriv->hwdmaptr[0]);
- set_dma_count(devpriv->dma, bytes);
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
-}
-
-static void pcl818_ai_setup_next_dma(struct comedi_device *dev,
- struct comedi_subdevice *s)
+ struct comedi_subdevice *s,
+ unsigned int unread_samples)
{
struct pcl818_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
- unsigned long flags;
-
- disable_dma(devpriv->dma);
- devpriv->next_dma_buf = 1 - devpriv->next_dma_buf;
- if (devpriv->dma_runs_to_end > -1 || cmd->stop_src == TRIG_NONE) {
- /* switch dma bufs */
- set_dma_mode(devpriv->dma, DMA_MODE_READ);
- flags = claim_dma_lock();
- set_dma_addr(devpriv->dma,
- devpriv->hwdmaptr[devpriv->next_dma_buf]);
- if (devpriv->dma_runs_to_end || cmd->stop_src == TRIG_NONE)
- set_dma_count(devpriv->dma, devpriv->hwdmasize);
- else
- set_dma_count(devpriv->dma, devpriv->last_dma_run);
- release_dma_lock(flags);
- enable_dma(devpriv->dma);
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned int max_samples = comedi_bytes_to_samples(s, desc->maxsize);
+ unsigned int nsamples;
+
+ comedi_isadma_disable(dma->chan);
+
+ /*
+ * Determine dma size based on the buffer maxsize plus the number of
+ * unread samples and the number of samples remaining in the command.
+ */
+ nsamples = comedi_nsamples_left(s, max_samples + unread_samples);
+ if (nsamples > unread_samples) {
+ nsamples -= unread_samples;
+ desc->size = comedi_samples_to_bytes(s, nsamples);
+ comedi_isadma_program(desc);
}
-
- devpriv->dma_runs_to_end--;
}
static void pcl818_ai_set_chan_range(struct comedi_device *dev,
@@ -493,11 +449,12 @@ static int pcl818_ai_eoc(struct comedi_device *dev,
return -EBUSY;
}
-static bool pcl818_ai_dropout(struct comedi_device *dev,
- struct comedi_subdevice *s,
- unsigned int chan)
+static bool pcl818_ai_write_sample(struct comedi_device *dev,
+ struct comedi_subdevice *s,
+ unsigned int chan, unsigned int val)
{
struct pcl818_private *devpriv = dev->private;
+ struct comedi_cmd *cmd = &s->async->cmd;
unsigned int expected_chan;
expected_chan = devpriv->act_chanlist[devpriv->act_chanlist_pos];
@@ -507,17 +464,11 @@ static bool pcl818_ai_dropout(struct comedi_device *dev,
(devpriv->dma) ? "DMA" :
(devpriv->usefifo) ? "FIFO" : "IRQ",
chan, expected_chan);
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
- return true;
+ s->async->events |= COMEDI_CB_ERROR;
+ return false;
}
- return false;
-}
-static bool pcl818_ai_next_chan(struct comedi_device *dev,
- struct comedi_subdevice *s)
-{
- struct pcl818_private *devpriv = dev->private;
- struct comedi_cmd *cmd = &s->async->cmd;
+ comedi_buf_write_samples(s, &val, 1);
devpriv->act_chanlist_pos++;
if (devpriv->act_chanlist_pos >= devpriv->act_chanlist_len)
@@ -540,47 +491,35 @@ static void pcl818_handle_eoc(struct comedi_device *dev,
if (pcl818_ai_eoc(dev, s, NULL, 0)) {
dev_err(dev->class_dev, "A/D mode1/3 IRQ without DRDY!\n");
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
val = pcl818_ai_get_sample(dev, s, &chan);
-
- if (pcl818_ai_dropout(dev, s, chan))
- return;
-
- comedi_buf_write_samples(s, &val, 1);
-
- pcl818_ai_next_chan(dev, s);
+ pcl818_ai_write_sample(dev, s, chan, val);
}
static void pcl818_handle_dma(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
- unsigned short *ptr;
+ struct comedi_isadma *dma = devpriv->dma;
+ struct comedi_isadma_desc *desc = &dma->desc[dma->cur_dma];
+ unsigned short *ptr = desc->virt_addr;
+ unsigned int nsamples = comedi_bytes_to_samples(s, desc->size);
unsigned int chan;
unsigned int val;
- int i, len, bufptr;
-
- pcl818_ai_setup_next_dma(dev, s);
-
- ptr = (unsigned short *)devpriv->dmabuf[1 - devpriv->next_dma_buf];
+ int i;
- len = devpriv->hwdmasize >> 1;
- bufptr = 0;
+ /* restart dma with the next buffer */
+ dma->cur_dma = 1 - dma->cur_dma;
+ pcl818_ai_setup_dma(dev, s, nsamples);
- for (i = 0; i < len; i++) {
- val = ptr[bufptr++];
+ for (i = 0; i < nsamples; i++) {
+ val = ptr[i];
chan = val & 0xf;
val = (val >> 4) & s->maxdata;
-
- if (pcl818_ai_dropout(dev, s, chan))
- break;
-
- comedi_buf_write_samples(s, &val, 1);
-
- if (!pcl818_ai_next_chan(dev, s))
+ if (!pcl818_ai_write_sample(dev, s, chan, val))
break;
}
}
@@ -597,14 +536,14 @@ static void pcl818_handle_fifo(struct comedi_device *dev,
if (status & 4) {
dev_err(dev->class_dev, "A/D mode1/3 FIFO overflow!\n");
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
if (status & 1) {
dev_err(dev->class_dev,
"A/D mode1/3 FIFO interrupt without data!\n");
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
return;
}
@@ -615,13 +554,7 @@ static void pcl818_handle_fifo(struct comedi_device *dev,
for (i = 0; i < len; i++) {
val = pcl818_ai_get_fifo_sample(dev, s, &chan);
-
- if (pcl818_ai_dropout(dev, s, chan))
- break;
-
- comedi_buf_write_samples(s, &val, 1);
-
- if (!pcl818_ai_next_chan(dev, s))
+ if (!pcl818_ai_write_sample(dev, s, chan, val))
break;
}
}
@@ -687,7 +620,8 @@ static int check_channel_list(struct comedi_device *dev,
break;
nowmustbechan =
(CR_CHAN(chansegment[i - 1]) + 1) % s->n_chan;
- if (nowmustbechan != CR_CHAN(chanlist[i])) { /* channel list isn't continuous :-( */
+ if (nowmustbechan != CR_CHAN(chanlist[i])) {
+ /* channel list isn't continuous :-( */
dev_dbg(dev->class_dev,
"channel list must be continuous! chanlist[%i]=%d but must be %d or %d!\n",
i, CR_CHAN(chanlist[i]), nowmustbechan,
@@ -804,6 +738,7 @@ static int pcl818_ai_cmd(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_cmd *cmd = &s->async->cmd;
unsigned int ctrl = 0;
unsigned int seglen;
@@ -818,11 +753,9 @@ static int pcl818_ai_cmd(struct comedi_device *dev,
return -EINVAL;
pcl818_ai_setup_chanlist(dev, cmd->chanlist, seglen);
- devpriv->ai_data_len = s->async->prealloc_bufsz;
devpriv->ai_cmd_running = 1;
devpriv->ai_cmd_canceled = 0;
devpriv->act_chanlist_pos = 0;
- devpriv->dma_runs_to_end = 0;
if (cmd->convert_src == TRIG_TIMER)
ctrl |= PCL818_CTRL_PACER_TRIG;
@@ -831,8 +764,10 @@ static int pcl818_ai_cmd(struct comedi_device *dev,
outb(PCL818_CNTENABLE_PACER_ENA, dev->iobase + PCL818_CNTENABLE_REG);
- if (devpriv->dma) {
- pcl818_ai_setup_dma(dev, s);
+ if (dma) {
+ /* setup and enable dma for the first buffer */
+ dma->cur_dma = 0;
+ pcl818_ai_setup_dma(dev, s, 0);
ctrl |= PCL818_CTRL_INTE | PCL818_CTRL_IRQ(dev->irq) |
PCL818_CTRL_DMAE;
@@ -854,12 +789,13 @@ static int pcl818_ai_cancel(struct comedi_device *dev,
struct comedi_subdevice *s)
{
struct pcl818_private *devpriv = dev->private;
+ struct comedi_isadma *dma = devpriv->dma;
struct comedi_cmd *cmd = &s->async->cmd;
if (!devpriv->ai_cmd_running)
return 0;
- if (devpriv->dma) {
+ if (dma) {
if (cmd->stop_src == TRIG_NONE ||
(cmd->stop_src == TRIG_COUNT &&
s->async->scans_done < cmd->stop_arg)) {
@@ -872,7 +808,7 @@ static int pcl818_ai_cancel(struct comedi_device *dev,
return 0;
}
}
- disable_dma(devpriv->dma);
+ comedi_isadma_disable(dma->chan);
}
outb(PCL818_CTRL_DISABLE_TRIG, dev->iobase + PCL818_CTRL_REG);
@@ -1054,13 +990,33 @@ static void pcl818_set_ai_range_table(struct comedi_device *dev,
}
}
+static void pcl818_alloc_dma(struct comedi_device *dev, unsigned int dma_chan)
+{
+ struct pcl818_private *devpriv = dev->private;
+
+ /* only DMA channels 3 and 1 are valid */
+ if (!(dma_chan == 3 || dma_chan == 1))
+ return;
+
+ /* DMA uses two 16K buffers */
+ devpriv->dma = comedi_isadma_alloc(dev, 2, dma_chan, dma_chan,
+ PAGE_SIZE * 4, COMEDI_ISADMA_READ);
+}
+
+static void pcl818_free_dma(struct comedi_device *dev)
+{
+ struct pcl818_private *devpriv = dev->private;
+
+ if (devpriv)
+ comedi_isadma_free(devpriv->dma);
+}
+
static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
{
const struct pcl818_board *board = dev->board_ptr;
struct pcl818_private *devpriv;
struct comedi_subdevice *s;
int ret;
- int i;
devpriv = comedi_alloc_devpriv(dev, sizeof(*devpriv));
if (!devpriv)
@@ -1084,31 +1040,8 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->usefifo = 1;
/* we need an IRQ to do DMA on channel 3 or 1 */
- if (dev->irq && board->has_dma &&
- (it->options[2] == 3 || it->options[2] == 1)) {
- ret = request_dma(it->options[2], dev->board_name);
- if (ret) {
- dev_err(dev->class_dev,
- "unable to request DMA channel %d\n",
- it->options[2]);
- return -EBUSY;
- }
- devpriv->dma = it->options[2];
-
- devpriv->dmapages = 2; /* we need 16KB */
- devpriv->hwdmasize = (1 << devpriv->dmapages) * PAGE_SIZE;
-
- for (i = 0; i < 2; i++) {
- unsigned long dmabuf;
-
- dmabuf = __get_dma_pages(GFP_KERNEL, devpriv->dmapages);
- if (!dmabuf)
- return -ENOMEM;
-
- devpriv->dmabuf[i] = dmabuf;
- devpriv->hwdmaptr[i] = virt_to_bus((void *)dmabuf);
- }
- }
+ if (dev->irq && board->has_dma)
+ pcl818_alloc_dma(dev, it->options[2]);
ret = comedi_alloc_subdevices(dev, 4);
if (ret)
@@ -1194,8 +1127,10 @@ static int pcl818_attach(struct comedi_device *dev, struct comedi_devconfig *it)
devpriv->ns_min = board->ns_min;
if (!board->is_818) {
- if ((it->options[6] == 1) || (it->options[6] == 100))
- devpriv->ns_min = 10000; /* extended PCL718 to 100kHz DAC */
+ if ((it->options[6] == 1) || (it->options[6] == 100)) {
+ /* extended PCL718 to 100kHz DAC */
+ devpriv->ns_min = 10000;
+ }
}
pcl818_reset(dev);
@@ -1210,13 +1145,8 @@ static void pcl818_detach(struct comedi_device *dev)
if (devpriv) {
pcl818_ai_cancel(dev, dev->read_subdev);
pcl818_reset(dev);
- if (devpriv->dma)
- free_dma(devpriv->dma);
- if (devpriv->dmabuf[0])
- free_pages(devpriv->dmabuf[0], devpriv->dmapages);
- if (devpriv->dmabuf[1])
- free_pages(devpriv->dmabuf[1], devpriv->dmapages);
}
+ pcl818_free_dma(dev);
comedi_legacy_detach(dev);
}
diff --git a/drivers/staging/comedi/drivers/pcmad.c b/drivers/staging/comedi/drivers/pcmad.c
index e3ac8ac6190e..12f94fe82f5b 100644
--- a/drivers/staging/comedi/drivers/pcmad.c
+++ b/drivers/staging/comedi/drivers/pcmad.c
@@ -19,8 +19,7 @@
/*
* Driver: pcmad
* Description: Winsystems PCM-A/D12, PCM-A/D16
- * Devices: (Winsystems) PCM-A/D12 [pcmad12]
- * (Winsystems) PCM-A/D16 [pcmad16]
+ * Devices: [Winsystems] PCM-A/D12 (pcmad12), PCM-A/D16 (pcmad16)
* Author: ds
* Status: untested
*
diff --git a/drivers/staging/comedi/drivers/pcmda12.c b/drivers/staging/comedi/drivers/pcmda12.c
index 59108c06cedc..d86c5e2cd0c7 100644
--- a/drivers/staging/comedi/drivers/pcmda12.c
+++ b/drivers/staging/comedi/drivers/pcmda12.c
@@ -19,7 +19,7 @@
/*
* Driver: pcmda12
* Description: A driver for the Winsystems PCM-D/A-12
- * Devices: (Winsystems) PCM-D/A-12 [pcmda12]
+ * Devices: [Winsystems] PCM-D/A-12 (pcmda12)
* Author: Calin Culianu <calin@ajvar.org>
* Updated: Fri, 13 Jan 2006 12:01:01 -0500
* Status: works
diff --git a/drivers/staging/comedi/drivers/pcmmio.c b/drivers/staging/comedi/drivers/pcmmio.c
index f0059e935da0..2c0e7ecbf494 100644
--- a/drivers/staging/comedi/drivers/pcmmio.c
+++ b/drivers/staging/comedi/drivers/pcmmio.c
@@ -19,7 +19,7 @@
/*
* Driver: pcmmio
* Description: A driver for the PCM-MIO multifunction board
- * Devices: (Winsystems) PCM-MIO [pcmmio]
+ * Devices: [Winsystems] PCM-MIO (pcmmio)
* Author: Calin Culianu <calin@ajvar.org>
* Updated: Wed, May 16 2007 16:21:10 -0500
* Status: works
diff --git a/drivers/staging/comedi/drivers/pcmuio.c b/drivers/staging/comedi/drivers/pcmuio.c
index 0f5483b6147f..a1641d981812 100644
--- a/drivers/staging/comedi/drivers/pcmuio.c
+++ b/drivers/staging/comedi/drivers/pcmuio.c
@@ -19,8 +19,7 @@
/*
* Driver: pcmuio
* Description: Winsystems PC-104 based 48/96-channel DIO boards.
- * Devices: (Winsystems) PCM-UIO48A [pcmuio48]
- * (Winsystems) PCM-UIO96A [pcmuio96]
+ * Devices: [Winsystems] PCM-UIO48A (pcmuio48), PCM-UIO96A (pcmuio96)
* Author: Calin Culianu <calin@ajvar.org>
* Updated: Fri, 13 Jan 2006 12:01:01 -0500
* Status: works
diff --git a/drivers/staging/comedi/drivers/quatech_daqp_cs.c b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
index 96098110b0b3..8387fd0e4b7e 100644
--- a/drivers/staging/comedi/drivers/quatech_daqp_cs.c
+++ b/drivers/staging/comedi/drivers/quatech_daqp_cs.c
@@ -48,15 +48,10 @@ Devices: [Quatech] DAQP-208 (daqp), DAQP-308
*/
#include <linux/module.h>
-#include "../comedidev.h"
#include <linux/semaphore.h>
-
-#include <pcmcia/cistpl.h>
-#include <pcmcia/cisreg.h>
-#include <pcmcia/ds.h>
-
#include <linux/completion.h>
+#include "../comedi_pcmcia.h"
#include "comedi_fc.h"
struct daqp_private {
@@ -210,8 +205,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
unsigned short data;
if (status & DAQP_STATUS_DATA_LOST) {
- s->async->events |=
- COMEDI_CB_EOA | COMEDI_CB_OVERFLOW;
+ s->async->events |= COMEDI_CB_OVERFLOW;
dev_warn(dev->class_dev, "data lost\n");
break;
}
@@ -239,7 +233,7 @@ static enum irqreturn daqp_interrupt(int irq, void *dev_id)
if (loop_limit <= 0) {
dev_warn(dev->class_dev,
"loop_limit reached in daqp_interrupt()\n");
- s->async->events |= COMEDI_CB_EOA | COMEDI_CB_ERROR;
+ s->async->events |= COMEDI_CB_ERROR;
}
comedi_handle_events(dev, s);
diff --git a/drivers/staging/comedi/drivers/rtd520.c b/drivers/staging/comedi/drivers/rtd520.c
index 581aa58d9c0a..c94ad12ed446 100644
--- a/drivers/staging/comedi/drivers/rtd520.c
+++ b/drivers/staging/comedi/drivers/rtd520.c
@@ -19,10 +19,8 @@
/*
* Driver: rtd520
* Description: Real Time Devices PCI4520/DM7520
- * Devices: (Real Time Devices) DM7520HR-1 [DM7520]
- * (Real Time Devices) DM7520HR-8 [DM7520]
- * (Real Time Devices) PCI4520 [PCI4520]
- * (Real Time Devices) PCI4520-8 [PCI4520]
+ * Devices: [Real Time Devices] DM7520HR-1 (DM7520), DM7520HR-8,
+ * PCI4520 (PCI4520), PCI4520-8
* Author: Dan Christian
* Status: Works. Only tested on DM7520-8. Not SMP safe.
*
@@ -1014,10 +1012,8 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
readw(dev->mmio + LAS0_CLEAR);
/* TODO: allow multiple interrupt sources */
- if (devpriv->xfer_count > 0) /* transfer every N samples */
- writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
- else /* 1/2 FIFO transfers */
- writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
+ /* transfer every N samples */
+ writew(IRQM_ADC_ABOUT_CNT, dev->mmio + LAS0_IT);
/* BUG: start_src is ASSUMED to be TRIG_NOW */
/* BUG? it seems like things are running before the "start" */
@@ -1031,8 +1027,6 @@ static int rtd_ai_cmd(struct comedi_device *dev, struct comedi_subdevice *s)
static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
{
struct rtd_private *devpriv = dev->private;
- u32 overrun;
- u16 status;
/* pacer stop source: SOFTWARE */
writel(0, dev->mmio + LAS0_PACER_STOP);
@@ -1040,8 +1034,6 @@ static int rtd_ai_cancel(struct comedi_device *dev, struct comedi_subdevice *s)
writel(0, dev->mmio + LAS0_ADC_CONVERSION);
writew(0, dev->mmio + LAS0_IT);
devpriv->ai_count = 0; /* stop and don't transfer any more */
- status = readw(dev->mmio + LAS0_IT);
- overrun = readl(dev->mmio + LAS0_OVERRUN) & 0xffff;
writel(0, dev->mmio + LAS0_ADC_FIFO_CLEAR);
return 0;
}
diff --git a/drivers/staging/comedi/drivers/rti800.c b/drivers/staging/comedi/drivers/rti800.c
index 67b4b378bd01..340ac776e951 100644
--- a/drivers/staging/comedi/drivers/rti800.c
+++ b/drivers/staging/comedi/drivers/rti800.c
@@ -19,8 +19,7 @@
/*
* Driver: rti800
* Description: Analog Devices RTI-800/815
- * Devices: (Analog Devices) RTI-800 [rti800]
- * (Analog Devices) RTI-815 [rti815]
+ * Devices: [Analog Devices] RTI-800 (rti800), RTI-815 (rti815)
* Author: David A. Schleef <ds@schleef.org>
* Status: unknown
* Updated: Fri, 05 Sep 2008 14:50:44 +0100
diff --git a/drivers/staging/comedi/drivers/rti802.c b/drivers/staging/comedi/drivers/rti802.c
index 96c3974207ae..6db58fcfd496 100644
--- a/drivers/staging/comedi/drivers/rti802.c
+++ b/drivers/staging/comedi/drivers/rti802.c
@@ -20,7 +20,7 @@
* Driver: rti802
* Description: Analog Devices RTI-802
* Author: Anders Blomdell <anders.blomdell@control.lth.se>
- * Devices: (Analog Devices) RTI-802 [rti802]
+ * Devices: [Analog Devices] RTI-802 (rti802)
* Status: works
*
* Configuration Options:
diff --git a/drivers/staging/comedi/drivers/s626.c b/drivers/staging/comedi/drivers/s626.c
index 14932c5f3798..fc497dd92021 100644
--- a/drivers/staging/comedi/drivers/s626.c
+++ b/drivers/staging/comedi/drivers/s626.c
@@ -118,7 +118,7 @@ static void s626_mc_enable(struct comedi_device *dev,
static void s626_mc_disable(struct comedi_device *dev,
unsigned int cmd, unsigned int reg)
{
- writel(cmd << 16 , dev->mmio + reg);
+ writel(cmd << 16, dev->mmio + reg);
mmiowb();
}
diff --git a/drivers/staging/comedi/drivers/usbdux.c b/drivers/staging/comedi/drivers/usbdux.c
index 4737dbf8e01d..1cd7403a4e9c 100644
--- a/drivers/staging/comedi/drivers/usbdux.c
+++ b/drivers/staging/comedi/drivers/usbdux.c
@@ -16,10 +16,11 @@
/*
* Driver: usbdux
* Description: University of Stirling USB DAQ & INCITE Technology Limited
- * Devices: (ITL) USB-DUX [usbdux]
+ * Devices: [ITL] USB-DUX (usbdux)
* Author: Bernd Porr <mail@berndporr.me.uk>
* Updated: 10 Oct 2014
* Status: Stable
+ *
* Connection scheme for the counter at the digital port:
* 0=/CLK0, 1=UP/DOWN0, 2=RESET0, 4=/CLK1, 5=UP/DOWN1, 6=RESET1.
* The sampling rate of the counter is approximately 500Hz.
@@ -79,11 +80,10 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
-#include <linux/usb.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
-#include "../comedidev.h"
+#include "../comedi_usb.h"
#include "comedi_fc.h"
diff --git a/drivers/staging/comedi/drivers/usbduxfast.c b/drivers/staging/comedi/drivers/usbduxfast.c
index ddc4cb9d5ed4..7ce27c16c2f9 100644
--- a/drivers/staging/comedi/drivers/usbduxfast.c
+++ b/drivers/staging/comedi/drivers/usbduxfast.c
@@ -15,7 +15,7 @@
/*
* Driver: usbduxfast
* Description: University of Stirling USB DAQ & INCITE Technology Limited
- * Devices: (ITL) USB-DUX [usbduxfast]
+ * Devices: [ITL] USB-DUX-FAST (usbduxfast)
* Author: Bernd Porr <mail@berndporr.me.uk>
* Updated: 10 Oct 2014
* Status: stable
@@ -46,11 +46,10 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
-#include <linux/usb.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
#include "comedi_fc.h"
-#include "../comedidev.h"
+#include "../comedi_usb.h"
/*
* timeout for the USB-transfer
diff --git a/drivers/staging/comedi/drivers/usbduxsigma.c b/drivers/staging/comedi/drivers/usbduxsigma.c
index dc19435b6520..394969b7458c 100644
--- a/drivers/staging/comedi/drivers/usbduxsigma.c
+++ b/drivers/staging/comedi/drivers/usbduxsigma.c
@@ -16,7 +16,7 @@
/*
* Driver: usbduxsigma
* Description: University of Stirling USB DAQ & INCITE Technology Limited
- * Devices: (ITL) USB-DUX [usbduxsigma]
+ * Devices: [ITL] USB-DUX-SIGMA (usbduxsigma)
* Author: Bernd Porr <mail@berndporr.me.uk>
* Updated: 10 Oct 2014
* Status: stable
@@ -45,13 +45,12 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/input.h>
-#include <linux/usb.h>
#include <linux/fcntl.h>
#include <linux/compiler.h>
#include <asm/unaligned.h>
#include "comedi_fc.h"
-#include "../comedidev.h"
+#include "../comedi_usb.h"
/* timeout for the USB-transfer in ms*/
#define BULK_TIMEOUT 1000
@@ -215,7 +214,6 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev,
struct usbduxsigma_private *devpriv = dev->private;
struct comedi_async *async = s->async;
struct comedi_cmd *cmd = &async->cmd;
- unsigned int dio_state;
uint32_t val;
int ret;
int i;
@@ -224,9 +222,6 @@ static void usbduxsigma_ai_handle_urb(struct comedi_device *dev,
if (devpriv->ai_counter == 0) {
devpriv->ai_counter = devpriv->ai_timer;
- /* get the state of the dio pins to allow external trigger */
- dio_state = be32_to_cpu(devpriv->in_buf[0]);
-
/* get the data from the USB bus and hand it over to comedi */
for (i = 0; i < cmd->chanlist_len; i++) {
/* transfer data, note first byte is the DIO state */
diff --git a/drivers/staging/comedi/drivers/vmk80xx.c b/drivers/staging/comedi/drivers/vmk80xx.c
index a19a56ee0eef..e37118321a27 100644
--- a/drivers/staging/comedi/drivers/vmk80xx.c
+++ b/drivers/staging/comedi/drivers/vmk80xx.c
@@ -18,21 +18,22 @@
GNU General Public License for more details.
*/
/*
-Driver: vmk80xx
-Description: Velleman USB Board Low-Level Driver
-Devices: K8055/K8061 aka VM110/VM140
-Author: Manuel Gebele <forensixs@gmx.de>
-Updated: Sun, 10 May 2009 11:14:59 +0200
-Status: works
-
-Supports:
- - analog input
- - analog output
- - digital input
- - digital output
- - counter
- - pwm
-*/
+ * Driver: vmk80xx
+ * Description: Velleman USB Board Low-Level Driver
+ * Devices: [Velleman] K8055 (K8055/VM110), K8061 (K8061/VM140),
+ * VM110 (K8055/VM110), VM140 (K8061/VM140)
+ * Author: Manuel Gebele <forensixs@gmx.de>
+ * Updated: Sun, 10 May 2009 11:14:59 +0200
+ * Status: works
+ *
+ * Supports:
+ * - analog input
+ * - analog output
+ * - digital input
+ * - digital output
+ * - counter
+ * - pwm
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -41,10 +42,9 @@ Supports:
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/poll.h>
-#include <linux/usb.h>
#include <linux/uaccess.h>
-#include "../comedidev.h"
+#include "../comedi_usb.h"
enum {
DEVICE_VMK8055,
@@ -550,41 +550,35 @@ static int vmk80xx_cnt_insn_config(struct comedi_device *dev,
unsigned int *data)
{
struct vmk80xx_private *devpriv = dev->private;
- unsigned int insn_cmd;
- int chan;
+ unsigned int chan = CR_CHAN(insn->chanspec);
int cmd;
int reg;
- int n;
-
- insn_cmd = data[0];
- if (insn_cmd != INSN_CONFIG_RESET && insn_cmd != GPCT_RESET)
- return -EINVAL;
+ int ret;
down(&devpriv->limit_sem);
-
- chan = CR_CHAN(insn->chanspec);
-
- if (devpriv->model == VMK8055_MODEL) {
- if (!chan) {
- cmd = VMK8055_CMD_RST_CNT1;
- reg = VMK8055_CNT1_REG;
+ switch (data[0]) {
+ case INSN_CONFIG_RESET:
+ if (devpriv->model == VMK8055_MODEL) {
+ if (!chan) {
+ cmd = VMK8055_CMD_RST_CNT1;
+ reg = VMK8055_CNT1_REG;
+ } else {
+ cmd = VMK8055_CMD_RST_CNT2;
+ reg = VMK8055_CNT2_REG;
+ }
+ devpriv->usb_tx_buf[reg] = 0x00;
} else {
- cmd = VMK8055_CMD_RST_CNT2;
- reg = VMK8055_CNT2_REG;
+ cmd = VMK8061_CMD_RST_CNT;
}
-
- devpriv->usb_tx_buf[reg] = 0x00;
- } else {
- cmd = VMK8061_CMD_RST_CNT;
+ ret = vmk80xx_write_packet(dev, cmd);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
-
- for (n = 0; n < insn->n; n++)
- if (vmk80xx_write_packet(dev, cmd))
- break;
-
up(&devpriv->limit_sem);
- return n;
+ return ret ? ret : insn->n;
}
static int vmk80xx_cnt_insn_write(struct comedi_device *dev,
diff --git a/drivers/staging/comedi/drivers/z8536.h b/drivers/staging/comedi/drivers/z8536.h
new file mode 100644
index 000000000000..7be53109cc8d
--- /dev/null
+++ b/drivers/staging/comedi/drivers/z8536.h
@@ -0,0 +1,202 @@
+/*
+ * Z8536 CIO Internal registers
+ */
+
+#ifndef _Z8536_H
+#define _Z8536_H
+
+/* Master Interrupt Control register */
+#define Z8536_INT_CTRL_REG 0x00
+#define Z8536_INT_CTRL_MIE BIT(7) /* Master Interrupt Enable */
+#define Z8536_INT_CTRL_DLC BIT(6) /* Disable Lower Chain */
+#define Z8536_INT_CTRL_NV BIT(5) /* No Vector */
+#define Z8536_INT_CTRL_PA_VIS BIT(4) /* Port A Vect Inc Status */
+#define Z8536_INT_CTRL_PB_VIS BIT(3) /* Port B Vect Inc Status */
+#define Z8536_INT_CTRL_VT_VIS BIT(2) /* C/T Vect Inc Status */
+#define Z8536_INT_CTRL_RJA BIT(1) /* Right Justified Addresses */
+#define Z8536_INT_CTRL_RESET BIT(0) /* Reset */
+
+/* Master Configuration Control register */
+#define Z8536_CFG_CTRL_REG 0x01
+#define Z8536_CFG_CTRL_PBE BIT(7) /* Port B Enable */
+#define Z8536_CFG_CTRL_CT1E BIT(6) /* C/T 1 Enable */
+#define Z8536_CFG_CTRL_CT2E BIT(5) /* C/T 2 Enable */
+#define Z8536_CFG_CTRL_PCE_CT3E BIT(4) /* Port C & C/T 3 Enable */
+#define Z8536_CFG_CTRL_PLC BIT(3) /* Port A/B Link Control */
+#define Z8536_CFG_CTRL_PAE BIT(2) /* Port A Enable */
+#define Z8536_CFG_CTRL_LC_INDEP (0 << 0)/* C/Ts Independent */
+#define Z8536_CFG_CTRL_LC_GATE (1 << 0)/* C/T 1 Out Gates C/T 2 */
+#define Z8536_CFG_CTRL_LC_TRIG (2 << 0)/* C/T 1 Out Triggers C/T 2 */
+#define Z8536_CFG_CTRL_LC_CLK (3 << 0)/* C/T 1 Out Clocks C/T 2 */
+#define Z8536_CFG_CTRL_LC_MASK (3 << 0)/* C/T Link Control mask */
+
+/* Interrupt Vector registers */
+#define Z8536_PA_INT_VECT_REG 0x02
+#define Z8536_PB_INT_VECT_REG 0x03
+#define Z8536_CT_INT_VECT_REG 0x04
+#define Z8536_CURR_INT_VECT_REG 0x1f
+
+/* Port A/B & Counter/Timer 1/2/3 Command and Status registers */
+#define Z8536_PA_CMDSTAT_REG 0x08
+#define Z8536_PB_CMDSTAT_REG 0x09
+#define Z8536_CT1_CMDSTAT_REG 0x0a
+#define Z8536_CT2_CMDSTAT_REG 0x0b
+#define Z8536_CT3_CMDSTAT_REG 0x0c
+#define Z8536_CT_CMDSTAT_REG(x) (0x0a + (x))
+#define Z8536_CMD_NULL (0 << 5)/* Null Code */
+#define Z8536_CMD_CLR_IP_IUS (1 << 5)/* Clear IP & IUS */
+#define Z8536_CMD_SET_IUS (2 << 5)/* Set IUS */
+#define Z8536_CMD_CLR_IUS (3 << 5)/* Clear IUS */
+#define Z8536_CMD_SET_IP (4 << 5)/* Set IP */
+#define Z8536_CMD_CLR_IP (5 << 5)/* Clear IP */
+#define Z8536_CMD_SET_IE (6 << 5)/* Set IE */
+#define Z8536_CMD_CLR_IE (7 << 5)/* Clear IE */
+#define Z8536_CMD_MASK (7 << 5)
+
+#define Z8536_STAT_IUS BIT(7) /* Interrupt Under Service */
+#define Z8536_STAT_IE BIT(6) /* Interrupt Enable */
+#define Z8536_STAT_IP BIT(5) /* Interrupt Pending */
+#define Z8536_STAT_ERR BIT(4) /* Interrupt Error */
+#define Z8536_STAT_IE_IP (Z8536_STAT_IE | Z8536_STAT_IP)
+
+#define Z8536_PAB_STAT_ORE BIT(3) /* Output Register Empty */
+#define Z8536_PAB_STAT_IRF BIT(2) /* Input Register Full */
+#define Z8536_PAB_STAT_PMF BIT(1) /* Pattern Match Flag */
+#define Z8536_PAB_CMDSTAT_IOE BIT(0) /* Interrupt On Error */
+
+#define Z8536_CT_CMD_RCC BIT(3) /* Read Counter Control */
+#define Z8536_CT_CMDSTAT_GCB BIT(2) /* Gate Command Bit */
+#define Z8536_CT_CMD_TCB BIT(1) /* Trigger Command Bit */
+#define Z8536_CT_STAT_CIP BIT(0) /* Count In Progress */
+
+/* Port Data registers */
+#define Z8536_PA_DATA_REG 0x0d
+#define Z8536_PB_DATA_REG 0x0e
+#define Z8536_PC_DATA_REG 0x0f
+
+/* Counter/Timer 1/2/3 Current Count registers */
+#define Z8536_CT1_VAL_MSB_REG 0x10
+#define Z8536_CT1_VAL_LSB_REG 0x11
+#define Z8536_CT2_VAL_MSB_REG 0x12
+#define Z8536_CT2_VAL_LSB_REG 0x13
+#define Z8536_CT3_VAL_MSB_REG 0x14
+#define Z8536_CT3_VAL_LSB_REG 0x15
+#define Z8536_CT_VAL_MSB_REG(x) (0x10 + ((x) * 2))
+#define Z8536_CT_VAL_LSB_REG(x) (0x11 + ((x) * 2))
+
+/* Counter/Timer 1/2/3 Time Constant registers */
+#define Z8536_CT1_RELOAD_MSB_REG 0x16
+#define Z8536_CT1_RELOAD_LSB_REG 0x17
+#define Z8536_CT2_RELOAD_MSB_REG 0x18
+#define Z8536_CT2_RELOAD_LSB_REG 0x19
+#define Z8536_CT3_RELOAD_MSB_REG 0x1a
+#define Z8536_CT3_RELOAD_LSB_REG 0x1b
+#define Z8536_CT_RELOAD_MSB_REG(x) (0x16 + ((x) * 2))
+#define Z8536_CT_RELOAD_LSB_REG(x) (0x17 + ((x) * 2))
+
+/* Counter/Timer 1/2/3 Mode Specification registers */
+#define Z8536_CT1_MODE_REG 0x1c
+#define Z8536_CT2_MODE_REG 0x1d
+#define Z8536_CT3_MODE_REG 0x1e
+#define Z8536_CT_MODE_REG(x) (0x1c + (x))
+#define Z8536_CT_MODE_CSC BIT(7) /* Continuous/Single Cycle */
+#define Z8536_CT_MODE_EOE BIT(6) /* External Output Enable */
+#define Z8536_CT_MODE_ECE BIT(5) /* External Count Enable */
+#define Z8536_CT_MODE_ETE BIT(4) /* External Trigger Enable */
+#define Z8536_CT_MODE_EGE BIT(3) /* External Gate Enable */
+#define Z8536_CT_MODE_REB BIT(2) /* Retrigger Enable Bit */
+#define Z8536_CT_MODE_DCS_PULSE (0 << 0)/* Duty Cycle - Pulse */
+#define Z8536_CT_MODE_DCS_ONESHOT (1 << 0)/* Duty Cycle - One-Shot */
+#define Z8536_CT_MODE_DCS_SQRWAVE (2 << 0)/* Duty Cycle - Square Wave */
+#define Z8536_CT_MODE_DCS_DO_NOT_USE (3 << 0)/* Duty Cycle - Do Not Use */
+#define Z8536_CT_MODE_DCS_MASK (3 << 0)/* Duty Cycle mask */
+
+/* Port A/B Mode Specification registers */
+#define Z8536_PA_MODE_REG 0x20
+#define Z8536_PB_MODE_REG 0x28
+#define Z8536_PAB_MODE_PTS_BIT (0 << 6)/* Bit Port */
+#define Z8536_PAB_MODE_PTS_INPUT (1 << 6)/* Input Port */
+#define Z8536_PAB_MODE_PTS_OUTPUT (2 << 6)/* Output Port */
+#define Z8536_PAB_MODE_PTS_BIDIR (3 << 6)/* Bidirectional Port */
+#define Z8536_PAB_MODE_PTS_MASK (3 << 6)/* Port Type Select mask */
+#define Z8536_PAB_MODE_ITB BIT(5) /* Interrupt on Two Bytes */
+#define Z8536_PAB_MODE_SB BIT(4) /* Single Buffered mode */
+#define Z8536_PAB_MODE_IMO BIT(3) /* Interrupt on Match Only */
+#define Z8536_PAB_MODE_PMS_DISABLE (0 << 1)/* Disable Pattern Match */
+#define Z8536_PAB_MODE_PMS_AND (1 << 1)/* "AND" mode */
+#define Z8536_PAB_MODE_PMS_OR (2 << 1)/* "OR" mode */
+#define Z8536_PAB_MODE_PMS_OR_PEV (3 << 1)/* "OR-Priority" mode */
+#define Z8536_PAB_MODE_PMS_MASK (3 << 1)/* Pattern Mode mask */
+#define Z8536_PAB_MODE_LPM BIT(0) /* Latch on Pattern Match */
+#define Z8536_PAB_MODE_DTE BIT(0) /* Deskew Timer Enabled */
+
+/* Port A/B Handshake Specification registers */
+#define Z8536_PA_HANDSHAKE_REG 0x21
+#define Z8536_PB_HANDSHAKE_REG 0x29
+#define Z8536_PAB_HANDSHAKE_HST_INTER (0 << 6)/* Interlocked Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_STROBED (1 << 6)/* Strobed Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_PULSED (2 << 6)/* Pulsed Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_3WIRE (3 << 6)/* Three-Wire Handshake */
+#define Z8536_PAB_HANDSHAKE_HST_MASK (3 << 6)/* Handshake Type mask */
+#define Z8536_PAB_HANDSHAKE_RWS_DISABLE (0 << 3)/* Req/Wait Disabled */
+#define Z8536_PAB_HANDSHAKE_RWS_OUTWAIT (1 << 3)/* Output Wait */
+#define Z8536_PAB_HANDSHAKE_RWS_INWAIT (3 << 3)/* Input Wait */
+#define Z8536_PAB_HANDSHAKE_RWS_SPREQ (4 << 3)/* Special Request */
+#define Z8536_PAB_HANDSHAKE_RWS_OUTREQ (5 << 4)/* Output Request */
+#define Z8536_PAB_HANDSHAKE_RWS_INREQ (7 << 3)/* Input Request */
+#define Z8536_PAB_HANDSHAKE_RWS_MASK (7 << 3)/* Req/Wait mask */
+#define Z8536_PAB_HANDSHAKE_DESKEW(x) ((x) << 0)/* Deskew Time */
+#define Z8536_PAB_HANDSHAKE_DESKEW_MASK (3 << 0)/* Deskew Time mask */
+
+/*
+ * Port A/B/C Data Path Polarity registers
+ *
+ * 0 = Non-Inverting
+ * 1 = Inverting
+ */
+#define Z8536_PA_DPP_REG 0x22
+#define Z8536_PB_DPP_REG 0x2a
+#define Z8536_PC_DPP_REG 0x05
+
+/*
+ * Port A/B/C Data Direction registers
+ *
+ * 0 = Output bit
+ * 1 = Input bit
+ */
+#define Z8536_PA_DD_REG 0x23
+#define Z8536_PB_DD_REG 0x2b
+#define Z8536_PC_DD_REG 0x06
+
+/*
+ * Port A/B/C Special I/O Control registers
+ *
+ * 0 = Normal Input or Output
+ * 1 = Output with open drain or Input with 1's catcher
+ */
+#define Z8536_PA_SIO_REG 0x24
+#define Z8536_PB_SIO_REG 0x2c
+#define Z8536_PC_SIO_REG 0x07
+
+/*
+ * Port A/B Pattern Polarity/Transition/Mask registers
+ *
+ * PM PT PP Pattern Specification
+ * -- -- -- -------------------------------------
+ * 0 0 x Bit masked off
+ * 0 1 x Any transition
+ * 1 0 0 Zero (low-level)
+ * 1 0 1 One (high-level)
+ * 1 1 0 One-to-zero transition (falling-edge)
+ * 1 1 1 Zero-to-one transition (rising-edge)
+ */
+#define Z8536_PA_PP_REG 0x25
+#define Z8536_PB_PP_REG 0x2d
+
+#define Z8536_PA_PT_REG 0x26
+#define Z8536_PB_PT_REG 0x2e
+
+#define Z8536_PA_PM_REG 0x27
+#define Z8536_PB_PM_REG 0x2f
+
+#endif /* _Z8536_H */
diff --git a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
index 8777f958c041..973f544e85e1 100644
--- a/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
+++ b/drivers/staging/comedi/kcomedilib/kcomedilib_main.c
@@ -95,7 +95,7 @@ static int comedi_do_insn(struct comedi_device *dev,
if (s->type == COMEDI_SUBD_UNUSED) {
dev_err(dev->class_dev,
- "%d not useable subdevice\n", insn->subdev);
+ "%d not usable subdevice\n", insn->subdev);
ret = -EIO;
goto error;
}
diff --git a/drivers/staging/comedi/range.c b/drivers/staging/comedi/range.c
index 9a1dc56f21d1..6a393b24bdd9 100644
--- a/drivers/staging/comedi/range.c
+++ b/drivers/staging/comedi/range.c
@@ -1,20 +1,20 @@
/*
- module/range.c
- comedi routines for voltage ranges
-
- COMEDI - Linux Control and Measurement Device Interface
- Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-*/
+ * comedi/range.c
+ * comedi routines for voltage ranges
+ *
+ * COMEDI - Linux Control and Measurement Device Interface
+ * Copyright (C) 1997-8 David A. Schleef <ds@schleef.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
#include <linux/uaccess.h>
#include "comedidev.h"
@@ -42,18 +42,18 @@ const struct comedi_lrange range_unknown = { 1, {{0, 1000000, UNIT_none} } };
EXPORT_SYMBOL_GPL(range_unknown);
/*
- COMEDI_RANGEINFO
- range information ioctl
-
- arg:
- pointer to rangeinfo structure
-
- reads:
- range info structure
-
- writes:
- n struct comedi_krange structures to rangeinfo->range_ptr
-*/
+ * COMEDI_RANGEINFO ioctl
+ * range information
+ *
+ * arg:
+ * pointer to comedi_rangeinfo structure
+ *
+ * reads:
+ * comedi_rangeinfo structure
+ *
+ * writes:
+ * array of comedi_krange structures to rangeinfo->range_ptr pointer
+ */
int do_rangeinfo_ioctl(struct comedi_device *dev,
struct comedi_rangeinfo __user *arg)
{
diff --git a/drivers/staging/cptm1217/Kconfig b/drivers/staging/cptm1217/Kconfig
deleted file mode 100644
index 43b1cc0a50a5..000000000000
--- a/drivers/staging/cptm1217/Kconfig
+++ /dev/null
@@ -1,12 +0,0 @@
-config TOUCHSCREEN_CLEARPAD_TM1217
- tristate "Synaptics Clearpad TM1217"
- depends on I2C
- depends on GPIOLIB
- depends on INPUT
- help
- Say Y here if you have a Synaptics Clearpad TM1217 Controller
-
- If unsure, say N.
-
- To compile this driver as a module, choose M here: the
- module will be called clearpad_tm1217.
diff --git a/drivers/staging/cptm1217/Makefile b/drivers/staging/cptm1217/Makefile
deleted file mode 100644
index 8961fafa80e7..000000000000
--- a/drivers/staging/cptm1217/Makefile
+++ /dev/null
@@ -1,2 +0,0 @@
-obj-$(CONFIG_TOUCHSCREEN_CLEARPAD_TM1217) += clearpad_tm1217.o
-
diff --git a/drivers/staging/cptm1217/TODO b/drivers/staging/cptm1217/TODO
deleted file mode 100644
index 303922465e4d..000000000000
--- a/drivers/staging/cptm1217/TODO
+++ /dev/null
@@ -1,5 +0,0 @@
-- Wait for the official upstream general clearpad drivers as promised over
- the past few months
-- Merge any device support needed from this driver into it
-- Delete this driver
-
diff --git a/drivers/staging/cptm1217/clearpad_tm1217.c b/drivers/staging/cptm1217/clearpad_tm1217.c
deleted file mode 100644
index 7f265ce0dd13..000000000000
--- a/drivers/staging/cptm1217/clearpad_tm1217.c
+++ /dev/null
@@ -1,665 +0,0 @@
-/*
- * clearpad_tm1217.c - Touch Screen driver for Synaptics Clearpad
- * TM1217 controller
- *
- * Copyright (C) 2008 Intel Corp
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; ifnot, write to the Free Software Foundation, Inc.,
- * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *
- * Questions/Comments/Bug fixes to Ramesh Agarwal (ramesh.agarwal@intel.com)
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/input.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/i2c.h>
-#include <linux/timer.h>
-#include <linux/gpio.h>
-#include <linux/hrtimer.h>
-#include <linux/kthread.h>
-#include <linux/delay.h>
-#include <linux/slab.h>
-#include "cp_tm1217.h"
-
-#define CPTM1217_DEVICE_NAME "cptm1217"
-#define CPTM1217_DRIVER_NAME CPTM1217_DEVICE_NAME
-
-#define MAX_TOUCH_SUPPORTED 2
-#define TOUCH_SUPPORTED 1
-#define SAMPLING_FREQ 80 /* Frequency in HZ */
-#define DELAY_BTWIN_SAMPLE (1000 / SAMPLING_FREQ)
-#define WAIT_FOR_RESPONSE 5 /* 5msec just works */
-#define MAX_RETRIES 5 /* As above */
-#define INCREMENTAL_DELAY 5 /* As above */
-
-/* Regster Definitions */
-#define TMA1217_DEV_STATUS 0x13 /* Device Status */
-#define TMA1217_INT_STATUS 0x14 /* Interrupt Status */
-
-/* Controller can detect up to 2 possible finger touches.
- * Each finger touch provides 12 bit X Y co-ordinates, the values are split
- * across 2 registers, and an 8 bit Z value */
-#define TMA1217_FINGER_STATE 0x18 /* Finger State */
-#define TMA1217_FINGER1_X_HIGHER8 0x19 /* Higher 8 bit of X coordinate */
-#define TMA1217_FINGER1_Y_HIGHER8 0x1A /* Higher 8 bit of Y coordinate */
-#define TMA1217_FINGER1_XY_LOWER4 0x1B /* Lower 4 bits of X and Y */
-#define TMA1217_FINGER1_Z_VALUE 0x1D /* 8 bit Z value for finger 1 */
-#define TMA1217_FINGER2_X_HIGHER8 0x1E /* Higher 8 bit of X coordinate */
-#define TMA1217_FINGER2_Y_HIGHER8 0x1F /* Higher 8 bit of Y coordinate */
-#define TMA1217_FINGER2_XY_LOWER4 0x20 /* Lower 4 bits of X and Y */
-#define TMA1217_FINGER2_Z_VALUE 0x22 /* 8 bit Z value for finger 2 */
-#define TMA1217_DEVICE_CTRL 0x23 /* Device Control */
-#define TMA1217_INTERRUPT_ENABLE 0x24 /* Interrupt Enable */
-#define TMA1217_REPORT_MODE 0x2B /* Reporting Mode */
-#define TMA1217_MAX_X_LOWER8 0x31 /* Bit 0-7 for Max X */
-#define TMA1217_MAX_X_HIGHER4 0x32 /* Bit 8-11 for Max X */
-#define TMA1217_MAX_Y_LOWER8 0x33 /* Bit 0-7 for Max Y */
-#define TMA1217_MAX_Y_HIGHER4 0x34 /* Bit 8-11 for Max Y */
-#define TMA1217_DEVICE_CMD_RESET 0x67 /* Device CMD reg for reset */
-#define TMA1217_DEVICE_CMD_REZERO 0x69 /* Device CMD reg for rezero */
-
-#define TMA1217_MANUFACTURER_ID 0x73 /* Manufacturer Id */
-#define TMA1217_PRODUCT_FAMILY 0x75 /* Product Family */
-#define TMA1217_FIRMWARE_REVISION 0x76 /* Firmware Revision */
-#define TMA1217_SERIAL_NO_HIGH 0x7C /* Bit 8-15 of device serial no. */
-#define TMA1217_SERIAL_NO_LOW 0x7D /* Bit 0-7 of device serial no. */
-#define TMA1217_PRODUCT_ID_START 0x7E /* Start address for 10 byte ID */
-#define TMA1217_DEVICE_CAPABILITY 0x8B /* Reporting capability */
-
-
-/*
- * The touch position structure.
- */
-struct touch_state {
- int x;
- int y;
- bool button;
-};
-
-/* Device Specific info given by the controller */
-struct cp_dev_info {
- u16 maxX;
- u16 maxY;
-};
-
-/* Vendor related info given by the controller */
-struct cp_vendor_info {
- u8 vendor_id;
- u8 product_family;
- u8 firmware_rev;
- u16 serial_no;
-};
-
-/*
- * Private structure to store the device details
- */
-struct cp_tm1217_device {
- struct i2c_client *client;
- struct device *dev;
- struct cp_vendor_info vinfo;
- struct cp_dev_info dinfo;
- struct input_dev_info {
- char phys[32];
- char name[128];
- struct input_dev *input;
- struct touch_state touch;
- } cp_input_info[MAX_TOUCH_SUPPORTED];
-
- int thread_running;
- struct mutex thread_mutex;
-
- int gpio;
-};
-
-
-/* The following functions are used to read/write registers on the device
- * as per the RMI prorocol. Technically, a page select should be written
- * before doing read/write but since the register offsets are below 0xFF
- * we can use the default value of page which is 0x00
- */
-static int cp_tm1217_read(struct cp_tm1217_device *ts,
- u8 *req, int size)
-{
- int i, retval;
-
- /* Send the address */
- retval = i2c_master_send(ts->client, &req[0], 1);
- if (retval != 1) {
- dev_err(ts->dev, "cp_tm1217: I2C send failed\n");
- return retval;
- }
- msleep(WAIT_FOR_RESPONSE);
- for (i = 0; i < MAX_RETRIES; i++) {
- retval = i2c_master_recv(ts->client, &req[1], size);
- if (retval == size)
- break;
-
- msleep(INCREMENTAL_DELAY);
- dev_dbg(ts->dev, "cp_tm1217: Retry count is %d\n", i);
- }
- if (retval != size)
- dev_err(ts->dev, "cp_tm1217: Read from device failed\n");
-
- return retval;
-}
-
-static int cp_tm1217_write(struct cp_tm1217_device *ts,
- u8 *req, int size)
-{
- int retval;
-
- /* Send the address and the data to be written */
- retval = i2c_master_send(ts->client, &req[0], size + 1);
- if (retval != size + 1) {
- dev_err(ts->dev, "cp_tm1217: I2C write failed: %d\n", retval);
- return retval;
- }
- /* Wait for the write to complete. TBD why this is required */
- msleep(WAIT_FOR_RESPONSE);
-
- return size;
-}
-
-static int cp_tm1217_mask_interrupt(struct cp_tm1217_device *ts)
-{
- u8 req[2];
- int retval;
-
- req[0] = TMA1217_INTERRUPT_ENABLE;
- req[1] = 0x0;
- retval = cp_tm1217_write(ts, req, 1);
- if (retval != 1)
- return -EIO;
-
- return 0;
-}
-
-static int cp_tm1217_unmask_interrupt(struct cp_tm1217_device *ts)
-{
- u8 req[2];
- int retval;
-
- req[0] = TMA1217_INTERRUPT_ENABLE;
- req[1] = 0xa;
- retval = cp_tm1217_write(ts, req, 1);
- if (retval != 1)
- return -EIO;
-
- return 0;
-}
-
-static void process_touch(struct cp_tm1217_device *ts, int index)
-{
- int retval;
- struct input_dev_info *input_info =
- (struct input_dev_info *)&ts->cp_input_info[index];
- u8 xy_data[6];
-
- if (index == 0)
- xy_data[0] = TMA1217_FINGER1_X_HIGHER8;
- else
- xy_data[0] = TMA1217_FINGER2_X_HIGHER8;
-
- retval = cp_tm1217_read(ts, xy_data, 5);
- if (retval < 5) {
- dev_err(ts->dev, "cp_tm1217: XY read from device failed\n");
- return;
- }
-
- /* Note: Currently not using the Z values but may be requried in
- the future. */
- input_info->touch.x = (xy_data[1] << 4)
- | (xy_data[3] & 0x0F);
- input_info->touch.y = (xy_data[2] << 4)
- | ((xy_data[3] & 0xF0) >> 4);
- input_report_abs(input_info->input, ABS_X, input_info->touch.x);
- input_report_abs(input_info->input, ABS_Y, input_info->touch.y);
- input_sync(input_info->input);
-}
-
-static void cp_tm1217_get_data(struct cp_tm1217_device *ts)
-{
- u8 req[2];
- int retval, i, finger_touched = 0;
-
- do {
- req[0] = TMA1217_FINGER_STATE;
- retval = cp_tm1217_read(ts, req, 1);
- if (retval != 1) {
- dev_err(ts->dev,
- "cp_tm1217: Read from device failed\n");
- continue;
- }
- finger_touched = 0;
- /* Start sampling until the pressure is below
- threshold */
- for (i = 0; i < TOUCH_SUPPORTED; i++) {
- if (req[1] & 0x3) {
- finger_touched++;
- if (ts->cp_input_info[i].touch.button == 0) {
- /* send the button touch event */
- input_report_key(
- ts->cp_input_info[i].input,
- BTN_TOUCH, 1);
- ts->cp_input_info[i].touch.button = 1;
- }
- process_touch(ts, i);
- } else {
- if (ts->cp_input_info[i].touch.button == 1) {
- /* send the button release event */
- input_report_key(
- ts->cp_input_info[i].input,
- BTN_TOUCH, 0);
- input_sync(ts->cp_input_info[i].input);
- ts->cp_input_info[i].touch.button = 0;
- }
- }
- req[1] = req[1] >> 2;
- }
- msleep(DELAY_BTWIN_SAMPLE);
- } while (finger_touched > 0);
-}
-
-static irqreturn_t cp_tm1217_sample_thread(int irq, void *handle)
-{
- struct cp_tm1217_device *ts = handle;
- u8 req[2];
- int retval;
-
- /* Chedk if another thread is already running */
- mutex_lock(&ts->thread_mutex);
- if (ts->thread_running == 1) {
- mutex_unlock(&ts->thread_mutex);
- return IRQ_HANDLED;
- }
-
- ts->thread_running = 1;
- mutex_unlock(&ts->thread_mutex);
-
- /* Mask the interrupts */
- retval = cp_tm1217_mask_interrupt(ts);
-
- /* Read the Interrupt Status register to find the cause of the
- Interrupt */
- req[0] = TMA1217_INT_STATUS;
- retval = cp_tm1217_read(ts, req, 1);
- if (retval != 1)
- goto exit_thread;
-
- if (!(req[1] & 0x8))
- goto exit_thread;
-
- cp_tm1217_get_data(ts);
-
-exit_thread:
- /* Unmask the interrupts before going to sleep */
- retval = cp_tm1217_unmask_interrupt(ts);
-
- mutex_lock(&ts->thread_mutex);
- ts->thread_running = 0;
- mutex_unlock(&ts->thread_mutex);
-
- return IRQ_HANDLED;
-}
-
-static int cp_tm1217_init_data(struct cp_tm1217_device *ts)
-{
- int retval;
- u8 req[2];
-
- /* Read the vendor id/ fw revision etc. Ignoring return check as this
- is non critical info */
- req[0] = TMA1217_MANUFACTURER_ID;
- retval = cp_tm1217_read(ts, req, 1);
- ts->vinfo.vendor_id = req[1];
-
- req[0] = TMA1217_PRODUCT_FAMILY;
- retval = cp_tm1217_read(ts, req, 1);
- ts->vinfo.product_family = req[1];
-
- req[0] = TMA1217_FIRMWARE_REVISION;
- retval = cp_tm1217_read(ts, req, 1);
- ts->vinfo.firmware_rev = req[1];
-
- req[0] = TMA1217_SERIAL_NO_HIGH;
- retval = cp_tm1217_read(ts, req, 1);
- ts->vinfo.serial_no = (req[1] << 8);
-
- req[0] = TMA1217_SERIAL_NO_LOW;
- retval = cp_tm1217_read(ts, req, 1);
- ts->vinfo.serial_no = ts->vinfo.serial_no | req[1];
-
- req[0] = TMA1217_MAX_X_HIGHER4;
- retval = cp_tm1217_read(ts, req, 1);
- ts->dinfo.maxX = (req[1] & 0xF) << 8;
-
- req[0] = TMA1217_MAX_X_LOWER8;
- retval = cp_tm1217_read(ts, req, 1);
- ts->dinfo.maxX = ts->dinfo.maxX | req[1];
-
- req[0] = TMA1217_MAX_Y_HIGHER4;
- retval = cp_tm1217_read(ts, req, 1);
- ts->dinfo.maxY = (req[1] & 0xF) << 8;
-
- req[0] = TMA1217_MAX_Y_LOWER8;
- retval = cp_tm1217_read(ts, req, 1);
- ts->dinfo.maxY = ts->dinfo.maxY | req[1];
-
- return 0;
-
-}
-
-/*
- * Set up a GPIO for use as the interrupt. We can't simply do this at
- * boot time because the GPIO drivers themselves may not be around at
- * boot/firmware set up time to do the work. Instead defer it to driver
- * detection.
- */
-
-static int cp_tm1217_setup_gpio_irq(struct cp_tm1217_device *ts)
-{
- int retval;
-
- /* Hook up the irq handler */
- retval = gpio_request(ts->gpio, "cp_tm1217_touch");
- if (retval < 0) {
- dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
- retval);
- return retval;
- }
-
- retval = gpio_direction_input(ts->gpio);
- if (retval < 0) {
- dev_err(ts->dev,
- "cp_tm1217: GPIO direction configuration failed, error %d\n",
- retval);
- gpio_free(ts->gpio);
- return retval;
- }
-
- retval = gpio_to_irq(ts->gpio);
- if (retval < 0) {
- dev_err(ts->dev,
- "cp_tm1217: GPIO to IRQ failed, error %d\n", retval);
- gpio_free(ts->gpio);
- }
- dev_dbg(ts->dev,
- "cp_tm1217: Got IRQ number is %d for GPIO %d\n",
- retval, ts->gpio);
- return retval;
-}
-
-static int cp_tm1217_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct cp_tm1217_device *ts;
- struct input_dev *input_dev;
- struct input_dev_info *input_info;
- struct cp_tm1217_platform_data *pdata;
- u8 req[2];
- int i, retval;
-
- /* No pdata is fine - we then use "normal" IRQ mode */
-
- pdata = client->dev.platform_data;
-
- ts = kzalloc(sizeof(struct cp_tm1217_device), GFP_KERNEL);
- if (!ts)
- return -ENOMEM;
-
- ts->client = client;
- ts->dev = &client->dev;
- i2c_set_clientdata(client, ts);
-
- ts->thread_running = 0;
- mutex_init(&ts->thread_mutex);
-
- /* Reset the Controller */
- req[0] = TMA1217_DEVICE_CMD_RESET;
- req[1] = 0x1;
- retval = cp_tm1217_write(ts, req, 1);
- if (retval != 1) {
- dev_err(ts->dev, "cp_tm1217: Controller reset failed\n");
- kfree(ts);
- return -EIO;
- }
-
- /* Clear up the interrupt status from reset. */
- req[0] = TMA1217_INT_STATUS;
- retval = cp_tm1217_read(ts, req, 1);
-
- /* Mask all the interrupts */
- retval = cp_tm1217_mask_interrupt(ts);
-
- /* Read the controller information */
- cp_tm1217_init_data(ts);
-
- /* The following code will register multiple event devices when
- multi-pointer is enabled, the code has not been tested
- with MPX */
- for (i = 0; i < TOUCH_SUPPORTED; i++) {
- input_dev = input_allocate_device();
- if (input_dev == NULL) {
- retval = -ENOMEM;
- goto fail;
- }
- input_info = &ts->cp_input_info[i];
- snprintf(input_info->name, sizeof(input_info->name),
- "cp_tm1217_touchscreen_%d", i);
- input_dev->name = input_info->name;
- snprintf(input_info->phys, sizeof(input_info->phys),
- "%s/input%d", dev_name(&client->dev), i);
-
- input_dev->phys = input_info->phys;
- input_dev->id.bustype = BUS_I2C;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
- input_dev->keybit[BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH);
-
- input_set_abs_params(input_dev, ABS_X, 0, ts->dinfo.maxX, 0, 0);
- input_set_abs_params(input_dev, ABS_Y, 0, ts->dinfo.maxY, 0, 0);
-
- retval = input_register_device(input_dev);
- if (retval) {
- dev_err(ts->dev,
- "Input dev registration failed for %s\n",
- input_dev->name);
- input_free_device(input_dev);
- goto fail;
- }
- input_info->input = input_dev;
- }
-
- /* Setup the reporting mode to send an interrupt only when
- finger arrives or departs. */
- req[0] = TMA1217_REPORT_MODE;
- req[1] = 0x02;
- retval = cp_tm1217_write(ts, req, 1);
-
- /* Setup the device to no sleep mode for now and make it configured */
- req[0] = TMA1217_DEVICE_CTRL;
- req[1] = 0x84;
- retval = cp_tm1217_write(ts, req, 1);
-
- /* Check for the status of the device */
- req[0] = TMA1217_DEV_STATUS;
- retval = cp_tm1217_read(ts, req, 1);
- if (req[1] != 0) {
- dev_err(ts->dev,
- "cp_tm1217: Device Status 0x%x != 0: config failed\n",
- req[1]);
-
- retval = -EIO;
- goto fail;
- }
-
- if (pdata && pdata->gpio) {
- ts->gpio = pdata->gpio;
- retval = cp_tm1217_setup_gpio_irq(ts);
- } else
- retval = client->irq;
-
- if (retval < 0) {
- dev_err(ts->dev, "cp_tm1217: GPIO request failed error %d\n",
- retval);
- goto fail;
- }
-
- client->irq = retval;
-
-
- retval = request_threaded_irq(client->irq,
- NULL, cp_tm1217_sample_thread,
- IRQF_TRIGGER_FALLING, "cp_tm1217_touch", ts);
- if (retval < 0) {
- dev_err(ts->dev, "cp_tm1217: Request IRQ error %d\n", retval);
- goto fail_gpio;
- }
-
- /* Unmask the interrupts */
- retval = cp_tm1217_unmask_interrupt(ts);
- if (retval == 0)
- return 0;
-
- free_irq(client->irq, ts);
-fail_gpio:
- if (ts->gpio)
- gpio_free(ts->gpio);
-fail:
- /* Clean up before returning failure */
- for (i = 0; i < TOUCH_SUPPORTED; i++) {
- if (ts->cp_input_info[i].input)
- input_unregister_device(ts->cp_input_info[i].input);
- }
- kfree(ts);
- return retval;
-
-}
-
-#ifdef CONFIG_PM_SLEEP
-
-/*
- * cp_tm1217 suspend
- *
- */
-static int cp_tm1217_suspend(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct cp_tm1217_device *ts = i2c_get_clientdata(client);
- u8 req[2];
- int retval;
-
- /* Put the controller to sleep */
- req[0] = TMA1217_DEVICE_CTRL;
- retval = cp_tm1217_read(ts, req, 1);
- req[1] = (req[1] & 0xF8) | 0x1;
- retval = cp_tm1217_write(ts, req, 1);
-
- if (device_may_wakeup(&client->dev))
- enable_irq_wake(client->irq);
-
- return 0;
-}
-
-/*
- * cp_tm1217_resume
- *
- */
-static int cp_tm1217_resume(struct device *dev)
-{
- struct i2c_client *client = to_i2c_client(dev);
- struct cp_tm1217_device *ts = i2c_get_clientdata(client);
- u8 req[2];
- int retval;
-
- /* Take the controller out of sleep */
- req[0] = TMA1217_DEVICE_CTRL;
- retval = cp_tm1217_read(ts, req, 1);
- req[1] = (req[1] & 0xF8) | 0x4;
- retval = cp_tm1217_write(ts, req, 1);
-
- /* Restore the register settings sinc the power to the
- could have been cut off */
-
- /* Setup the reporting mode to send an interrupt only when
- finger arrives or departs. */
- req[0] = TMA1217_REPORT_MODE;
- req[1] = 0x02;
- retval = cp_tm1217_write(ts, req, 1);
-
- /* Setup the device to no sleep mode for now and make it configured */
- req[0] = TMA1217_DEVICE_CTRL;
- req[1] = 0x84;
- retval = cp_tm1217_write(ts, req, 1);
-
- /* Setup the interrupt mask */
- retval = cp_tm1217_unmask_interrupt(ts);
-
- if (device_may_wakeup(&client->dev))
- disable_irq_wake(client->irq);
-
- return 0;
-}
-
-#endif
-
-static SIMPLE_DEV_PM_OPS(cp_tm1217_pm_ops, cp_tm1217_suspend,
- cp_tm1217_resume);
-
-/*
- * cp_tm1217_remove
- *
- */
-static int cp_tm1217_remove(struct i2c_client *client)
-{
- struct cp_tm1217_device *ts = i2c_get_clientdata(client);
- int i;
-
- free_irq(client->irq, ts);
- if (ts->gpio)
- gpio_free(ts->gpio);
- for (i = 0; i < TOUCH_SUPPORTED; i++)
- input_unregister_device(ts->cp_input_info[i].input);
- kfree(ts);
- return 0;
-}
-
-static struct i2c_device_id cp_tm1217_idtable[] = {
- { CPTM1217_DEVICE_NAME, 0 },
- { }
-};
-
-MODULE_DEVICE_TABLE(i2c, cp_tm1217_idtable);
-
-static struct i2c_driver cp_tm1217_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = CPTM1217_DRIVER_NAME,
- .pm = &cp_tm1217_pm_ops,
- },
- .id_table = cp_tm1217_idtable,
- .probe = cp_tm1217_probe,
- .remove = cp_tm1217_remove,
-};
-
-module_i2c_driver(cp_tm1217_driver);
-
-MODULE_AUTHOR("Ramesh Agarwal <ramesh.agarwal@intel.com>");
-MODULE_DESCRIPTION("Synaptics TM1217 TouchScreen Driver");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/staging/cptm1217/cp_tm1217.h b/drivers/staging/cptm1217/cp_tm1217.h
deleted file mode 100644
index 30bad357a055..000000000000
--- a/drivers/staging/cptm1217/cp_tm1217.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef __LINUX_I2C_CP_TM1217_H
-#define __LINUX_I2C_CP_TM1217_H
-
-struct cp_tm1217_platform_data {
- int gpio; /* If not set uses the IRQ resource 0 */
-};
-
-#endif
diff --git a/drivers/staging/dgap/dgap.c b/drivers/staging/dgap/dgap.c
index bdb5317e3d9d..7184747e0652 100644
--- a/drivers/staging/dgap/dgap.c
+++ b/drivers/staging/dgap/dgap.c
@@ -978,8 +978,8 @@ static int dgap_parsefile(char **in)
brd->u.board.conc1++;
conc_type = dgap_gettok(in);
- if (conc_type == 0 || conc_type != CX ||
- conc_type != EPC) {
+ if (conc_type == 0 || (conc_type != CX &&
+ conc_type != EPC)) {
pr_err("failed to set a type of concentratros");
return -1;
}
@@ -1019,8 +1019,8 @@ static int dgap_parsefile(char **in)
brd->u.board.module1++;
module_type = dgap_gettok(in);
- if (module_type == 0 || module_type != PORTS ||
- module_type != MODEM) {
+ if (module_type == 0 || (module_type != PORTS &&
+ module_type != MODEM)) {
pr_err("failed to set a type of module");
return -1;
}
@@ -1400,27 +1400,27 @@ static int dgap_remap(struct board_t *brd)
return -ENOMEM;
if (!request_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000,
- "dgap")) {
- release_mem_region(brd->membase, 0x200000);
- return -ENOMEM;
- }
+ "dgap"))
+ goto err_req_mem;
brd->re_map_membase = ioremap(brd->membase, 0x200000);
- if (!brd->re_map_membase) {
- release_mem_region(brd->membase, 0x200000);
- release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
- return -ENOMEM;
- }
+ if (!brd->re_map_membase)
+ goto err_remap_mem;
brd->re_map_port = ioremap((brd->membase + PCI_IO_OFFSET), 0x200000);
- if (!brd->re_map_port) {
- release_mem_region(brd->membase, 0x200000);
- release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
- iounmap(brd->re_map_membase);
- return -ENOMEM;
- }
+ if (!brd->re_map_port)
+ goto err_remap_port;
return 0;
+
+err_remap_port:
+ iounmap(brd->re_map_membase);
+err_remap_mem:
+ release_mem_region(brd->membase + PCI_IO_OFFSET, 0x200000);
+err_req_mem:
+ release_mem_region(brd->membase, 0x200000);
+
+ return -ENOMEM;
}
static void dgap_unmap(struct board_t *brd)
diff --git a/drivers/staging/dgnc/dgnc_driver.c b/drivers/staging/dgnc/dgnc_driver.c
index ba98ff348112..f177d3a258c2 100644
--- a/drivers/staging/dgnc/dgnc_driver.c
+++ b/drivers/staging/dgnc/dgnc_driver.c
@@ -97,12 +97,12 @@ static uint dgnc_poll_stop; /* Used to tell poller to stop */
static struct timer_list dgnc_poll_timer;
-static struct pci_device_id dgnc_pci_tbl[] = {
- { DIGI_VID, PCI_DEVICE_CLASSIC_4_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1 },
- { DIGI_VID, PCI_DEVICE_CLASSIC_8_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2 },
- { DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 3 },
- {0,} /* 0 terminated list. */
+static const struct pci_device_id dgnc_pci_tbl[] = {
+ {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_DID), .driver_data = 0},
+ {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_4_422_DID), .driver_data = 1},
+ {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_DID), .driver_data = 2},
+ {PCI_DEVICE(DIGI_VID, PCI_DEVICE_CLASSIC_8_422_DID), .driver_data = 3},
+ {0,}
};
MODULE_DEVICE_TABLE(pci, dgnc_pci_tbl);
@@ -238,6 +238,7 @@ static int dgnc_start(void)
{
int rc = 0;
unsigned long flags;
+ struct device *dev;
/* make sure that the globals are init'd before we do anything else */
dgnc_init_globals();
@@ -257,9 +258,20 @@ static int dgnc_start(void)
dgnc_Major = rc;
dgnc_class = class_create(THIS_MODULE, "dgnc_mgmt");
- device_create(dgnc_class, NULL,
- MKDEV(dgnc_Major, 0),
- NULL, "dgnc_mgmt");
+ if (IS_ERR(dgnc_class)) {
+ rc = PTR_ERR(dgnc_class);
+ pr_err(DRVSTR ": Can't create dgnc_mgmt class (%d)\n", rc);
+ goto failed_class;
+ }
+
+ dev = device_create(dgnc_class, NULL,
+ MKDEV(dgnc_Major, 0),
+ NULL, "dgnc_mgmt");
+ if (IS_ERR(dev)) {
+ rc = PTR_ERR(dev);
+ pr_err(DRVSTR ": Can't create device (%d)\n", rc);
+ goto failed_device;
+ }
/*
* Init any global tty stuff.
@@ -268,7 +280,7 @@ static int dgnc_start(void)
if (rc < 0) {
pr_err(DRVSTR ": tty preinit - not enough memory (%d)\n", rc);
- return rc;
+ goto failed_tty;
}
/* Start the poller */
@@ -282,6 +294,14 @@ static int dgnc_start(void)
add_timer(&dgnc_poll_timer);
+ return 0;
+
+failed_tty:
+ device_destroy(dgnc_class, MKDEV(dgnc_Major, 0));
+failed_device:
+ class_destroy(dgnc_class);
+failed_class:
+ unregister_chrdev(dgnc_Major, "dgnc");
return rc;
}
diff --git a/drivers/staging/dgnc/dgnc_utils.c b/drivers/staging/dgnc/dgnc_utils.c
index 61efc13ec160..80b51332292c 100644
--- a/drivers/staging/dgnc/dgnc_utils.c
+++ b/drivers/staging/dgnc/dgnc_utils.c
@@ -12,7 +12,7 @@
*/
int dgnc_ms_sleep(ulong ms)
{
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((ms * HZ) / 1000);
return signal_pending(current);
}
diff --git a/drivers/staging/dgnc/digi.h b/drivers/staging/dgnc/digi.h
index 3181a3590465..d6e0b9f6b24a 100644
--- a/drivers/staging/dgnc/digi.h
+++ b/drivers/staging/dgnc/digi.h
@@ -38,8 +38,8 @@
#if !defined(TIOCMODG)
-#define TIOCMODG ('d'<<8) | 250 /* get modem ctrl state */
-#define TIOCMODS ('d'<<8) | 251 /* set modem ctrl state */
+#define TIOCMODG (('d'<<8) | 250) /* get modem ctrl state */
+#define TIOCMODS (('d'<<8) | 251) /* set modem ctrl state */
#ifndef TIOCM_LE
#define TIOCM_LE 0x01 /* line enable */
@@ -58,44 +58,44 @@
#endif
#if !defined(TIOCMSET)
-#define TIOCMSET ('d'<<8) | 252 /* set modem ctrl state */
-#define TIOCMGET ('d'<<8) | 253 /* set modem ctrl state */
+#define TIOCMSET (('d'<<8) | 252) /* set modem ctrl state */
+#define TIOCMGET (('d'<<8) | 253) /* set modem ctrl state */
#endif
#if !defined(TIOCMBIC)
-#define TIOCMBIC ('d'<<8) | 254 /* set modem ctrl state */
-#define TIOCMBIS ('d'<<8) | 255 /* set modem ctrl state */
+#define TIOCMBIC (('d'<<8) | 254) /* set modem ctrl state */
+#define TIOCMBIS (('d'<<8) | 255) /* set modem ctrl state */
#endif
#if !defined(TIOCSDTR)
-#define TIOCSDTR ('e'<<8) | 0 /* set DTR */
-#define TIOCCDTR ('e'<<8) | 1 /* clear DTR */
+#define TIOCSDTR (('e'<<8) | 0) /* set DTR */
+#define TIOCCDTR (('e'<<8) | 1) /* clear DTR */
#endif
/************************************************************************
* Ioctl command arguments for DIGI parameters.
************************************************************************/
-#define DIGI_GETA ('e'<<8) | 94 /* Read params */
+#define DIGI_GETA (('e'<<8) | 94) /* Read params */
-#define DIGI_SETA ('e'<<8) | 95 /* Set params */
-#define DIGI_SETAW ('e'<<8) | 96 /* Drain & set params */
-#define DIGI_SETAF ('e'<<8) | 97 /* Drain, flush & set params */
+#define DIGI_SETA (('e'<<8) | 95) /* Set params */
+#define DIGI_SETAW (('e'<<8) | 96) /* Drain & set params */
+#define DIGI_SETAF (('e'<<8) | 97) /* Drain, flush & set params */
-#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */
+#define DIGI_KME (('e'<<8) | 98) /* Read/Write Host */
/* Adapter Memory */
-#define DIGI_GETFLOW ('e'<<8) | 99 /* Get startc/stopc flow */
+#define DIGI_GETFLOW (('e'<<8) | 99) /* Get startc/stopc flow */
/* control characters */
-#define DIGI_SETFLOW ('e'<<8) | 100 /* Set startc/stopc flow */
+#define DIGI_SETFLOW (('e'<<8) | 100) /* Set startc/stopc flow */
/* control characters */
-#define DIGI_GETAFLOW ('e'<<8) | 101 /* Get Aux. startc/stopc */
+#define DIGI_GETAFLOW (('e'<<8) | 101) /* Get Aux. startc/stopc */
/* flow control chars */
-#define DIGI_SETAFLOW ('e'<<8) | 102 /* Set Aux. startc/stopc */
+#define DIGI_SETAFLOW (('e'<<8) | 102) /* Set Aux. startc/stopc */
/* flow control chars */
-#define DIGI_GEDELAY ('d'<<8) | 246 /* Get edelay */
-#define DIGI_SEDELAY ('d'<<8) | 247 /* Set edelay */
+#define DIGI_GEDELAY (('d'<<8) | 246) /* Get edelay */
+#define DIGI_SEDELAY (('d'<<8) | 247) /* Set edelay */
struct digiflow_t {
unsigned char startc; /* flow cntl start char */
@@ -104,8 +104,8 @@ struct digiflow_t {
#ifdef FLOW_2200
-#define F2200_GETA ('e'<<8) | 104 /* Get 2x36 flow cntl flags */
-#define F2200_SETAW ('e'<<8) | 105 /* Set 2x36 flow cntl flags */
+#define F2200_GETA (('e'<<8) | 104) /* Get 2x36 flow cntl flags */
+#define F2200_SETAW (('e'<<8) | 105) /* Set 2x36 flow cntl flags */
#define F2200_MASK 0x03 /* 2200 flow cntl bit mask */
#define FCNTL_2200 0x01 /* 2x36 terminal flow cntl */
#define PCNTL_2200 0x02 /* 2x36 printer flow cntl */
@@ -241,7 +241,7 @@ struct digi_dinfo {
char dinfo_version[16]; /* driver version */
};
-#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */
+#define DIGI_GETDD (('d'<<8) | 248) /* get driver info */
/************************************************************************
* Structure used with ioctl commands for per-board information
@@ -261,7 +261,7 @@ struct digi_info {
char info_reserved[7]; /* for future expansion */
};
-#define DIGI_GETBD ('d'<<8) | 249 /* get board info */
+#define DIGI_GETBD (('d'<<8) | 249) /* get board info */
struct digi_stat {
unsigned int info_chan; /* Channel number (0 based) */
@@ -276,7 +276,7 @@ struct digi_stat {
unsigned int info_reserved[8]; /* for future expansion */
};
-#define DIGI_GETSTAT ('d'<<8) | 244 /* get board info */
+#define DIGI_GETSTAT (('d'<<8) | 244) /* get board info */
/************************************************************************
*
* Structure used with ioctl commands for per-channel information
@@ -339,7 +339,7 @@ struct digi_getcounter {
#define INFO_CH_WLOW 0x0020
#define INFO_XXBUF_BUSY 0x0040
-#define DIGI_GETCH ('d'<<8) | 245 /* get board info */
+#define DIGI_GETCH (('d'<<8) | 245) /* get board info */
/* Board type definitions */
@@ -384,15 +384,15 @@ struct digi_getcounter {
#define BD_TRIBOOT 0x8
#define BD_BADKME 0x80
-#define DIGI_SPOLL ('d'<<8) | 254 /* change poller rate */
+#define DIGI_SPOLL (('d'<<8) | 254) /* change poller rate */
#define DIGI_SETCUSTOMBAUD _IOW('e', 106, int) /* Set integer baud rate */
#define DIGI_GETCUSTOMBAUD _IOR('e', 107, int) /* Get integer baud rate */
-#define DIGI_REALPORT_GETBUFFERS ('e'<<8) | 108
-#define DIGI_REALPORT_SENDIMMEDIATE ('e'<<8) | 109
-#define DIGI_REALPORT_GETCOUNTERS ('e'<<8) | 110
-#define DIGI_REALPORT_GETEVENTS ('e'<<8) | 111
+#define DIGI_REALPORT_GETBUFFERS (('e'<<8) | 108)
+#define DIGI_REALPORT_SENDIMMEDIATE (('e'<<8) | 109)
+#define DIGI_REALPORT_GETCOUNTERS (('e'<<8) | 110)
+#define DIGI_REALPORT_GETEVENTS (('e'<<8) | 111)
#define EV_OPU 0x0001 /* !<Output paused by client */
#define EV_OPS 0x0002 /* !<Output paused by reqular sw flowctrl */
diff --git a/drivers/staging/dgnc/dpacompat.h b/drivers/staging/dgnc/dpacompat.h
index b2d2dc08f869..33cb394524b8 100644
--- a/drivers/staging/dgnc/dpacompat.h
+++ b/drivers/staging/dgnc/dpacompat.h
@@ -51,7 +51,7 @@ struct ni_info {
#define RW_READ 1
#define RW_WRITE 2
-#define DIGI_KME ('e'<<8) | 98 /* Read/Write Host */
+#define DIGI_KME (('e'<<8) | 98) /* Read/Write Host */
#define SUBTYPE 0007
#define T_PCXI 0000
@@ -106,10 +106,10 @@ struct ni_info {
/* Ioctls needed for dpa operation */
-#define DIGI_GETDD ('d'<<8) | 248 /* get driver info */
-#define DIGI_GETBD ('d'<<8) | 249 /* get board info */
-#define DIGI_GET_NI_INFO ('d'<<8) | 250 /* nonintelligent state snfo */
+#define DIGI_GETDD (('d'<<8) | 248) /* get driver info */
+#define DIGI_GETBD (('d'<<8) | 249) /* get board info */
+#define DIGI_GET_NI_INFO (('d'<<8) | 250) /* nonintelligent state snfo */
/* Other special ioctls */
-#define DIGI_TIMERIRQ ('d'<<8) | 251 /* Enable/disable RS_TIMER use */
-#define DIGI_LOOPBACK ('d'<<8) | 252 /* Enable/disable UART internal loopback */
+#define DIGI_TIMERIRQ (('d'<<8) | 251) /* Enable/disable RS_TIMER use */
+#define DIGI_LOOPBACK (('d'<<8) | 252) /* Enable/disable UART internal loopback */
diff --git a/drivers/staging/emxx_udc/Kconfig b/drivers/staging/emxx_udc/Kconfig
index 9bc6d3db86d9..cc3402020487 100644
--- a/drivers/staging/emxx_udc/Kconfig
+++ b/drivers/staging/emxx_udc/Kconfig
@@ -1,5 +1,5 @@
config USB_EMXX
- boolean "EMXX USB Function Device Controller"
+ bool "EMXX USB Function Device Controller"
depends on USB_GADGET && (ARCH_SHMOBILE || (ARM && COMPILE_TEST))
help
The Emma Mobile series of SoCs from Renesas Electronics and
diff --git a/drivers/staging/emxx_udc/emxx_udc.c b/drivers/staging/emxx_udc/emxx_udc.c
index eb178fcb7954..4be646ce8a12 100644
--- a/drivers/staging/emxx_udc/emxx_udc.c
+++ b/drivers/staging/emxx_udc/emxx_udc.c
@@ -1608,7 +1608,7 @@ static int std_req_get_status(struct nbu2ss_udc *udc)
switch (recipient) {
case USB_RECIP_DEVICE:
if (udc->ctrl.wIndex == 0x0000) {
- if (udc->self_powered)
+ if (udc->gadget.is_selfpowered)
status_data |= (1 << USB_DEVICE_SELF_POWERED);
if (udc->remote_wakeup)
@@ -3117,7 +3117,7 @@ static int nbu2ss_gad_wakeup(struct usb_gadget *pgadget)
static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
int is_selfpowered)
{
- struct nbu2ss_udc *udc;
+ struct nbu2ss_udc *udc;
unsigned long flags;
/* INFO("=== %s()\n", __func__); */
@@ -3130,7 +3130,7 @@ static int nbu2ss_gad_set_selfpowered(struct usb_gadget *pgadget,
udc = container_of(pgadget, struct nbu2ss_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
- udc->self_powered = (is_selfpowered != 0);
+ pgadget->is_selfpowered = (is_selfpowered != 0);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
@@ -3249,42 +3249,6 @@ static const char *gp_ep_name[NUM_ENDPOINTS] = {
};
/*-------------------------------------------------------------------------*/
-static void __init nbu2ss_drv_set_ep_info(
- struct nbu2ss_udc *udc,
- struct nbu2ss_ep *ep,
- const char *name)
-{
- ep->udc = udc;
- ep->desc = NULL;
-
- ep->ep.driver_data = NULL;
- ep->ep.name = name;
- ep->ep.ops = &nbu2ss_ep_ops;
-
- if (isdigit(name[2])) {
-
- long num;
- int res;
- char tempbuf[2];
-
- tempbuf[0] = name[2];
- tempbuf[1] = '\0';
- res = kstrtol(tempbuf, 16, &num);
-
- if (num == 0)
- ep->ep.maxpacket = EP0_PACKETSIZE;
- else
- ep->ep.maxpacket = EP_PACKETSIZE;
-
- } else {
- ep->ep.maxpacket = EP_PACKETSIZE;
- }
-
- list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
- INIT_LIST_HEAD(&ep->queue);
-}
-
-/*-------------------------------------------------------------------------*/
static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
{
int i;
@@ -3292,9 +3256,21 @@ static void __init nbu2ss_drv_ep_init(struct nbu2ss_udc *udc)
INIT_LIST_HEAD(&udc->gadget.ep_list);
udc->gadget.ep0 = &udc->ep[0].ep;
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ struct nbu2ss_ep *ep = &udc->ep[i];
+
+ ep->udc = udc;
+ ep->desc = NULL;
+
+ ep->ep.driver_data = NULL;
+ ep->ep.name = gp_ep_name[i];
+ ep->ep.ops = &nbu2ss_ep_ops;
- for (i = 0; i < NUM_ENDPOINTS; i++)
- nbu2ss_drv_set_ep_info(udc, &udc->ep[i], gp_ep_name[i]);
+ ep->ep.maxpacket = (i == 0 ? EP0_PACKETSIZE : EP_PACKETSIZE);
+
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ INIT_LIST_HEAD(&ep->queue);
+ }
list_del_init(&udc->ep[0].ep.ep_list);
}
@@ -3308,7 +3284,7 @@ static int __init nbu2ss_drv_contest_init(
spin_lock_init(&udc->lock);
udc->dev = &pdev->dev;
- udc->self_powered = 1;
+ udc->gadget.is_selfpowered = 1;
udc->devstate = USB_STATE_NOTATTACHED;
udc->pdev = pdev;
udc->mA = 0;
diff --git a/drivers/staging/emxx_udc/emxx_udc.h b/drivers/staging/emxx_udc/emxx_udc.h
index ee1b80d705fa..202e2dc72bba 100644
--- a/drivers/staging/emxx_udc/emxx_udc.h
+++ b/drivers/staging/emxx_udc/emxx_udc.h
@@ -624,7 +624,6 @@ struct nbu2ss_udc {
unsigned linux_suspended:1;
unsigned linux_resume:1;
unsigned usb_suspended:1;
- unsigned self_powered:1;
unsigned remote_wakeup:1;
unsigned udc_enabled:1;
diff --git a/drivers/staging/fbtft/Kconfig b/drivers/staging/fbtft/Kconfig
new file mode 100644
index 000000000000..995a9101a080
--- /dev/null
+++ b/drivers/staging/fbtft/Kconfig
@@ -0,0 +1,169 @@
+menuconfig FB_TFT
+ tristate "Support for small TFT LCD display modules"
+ depends on FB && SPI && GPIOLIB
+ select FB_SYS_FILLRECT
+ select FB_SYS_COPYAREA
+ select FB_SYS_IMAGEBLIT
+ select FB_SYS_FOPS
+ select FB_DEFERRED_IO
+ select FB_BACKLIGHT
+
+config FB_TFT_AGM1264K_FL
+ tristate "FB driver for the AGM1264K-FL LCD display"
+ depends on FB_TFT
+ help
+ Framebuffer support for the AGM1264K-FL LCD display (two Samsung KS0108 compatable chips)
+
+config FB_TFT_BD663474
+ tristate "FB driver for the BD663474 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for BD663474
+
+config FB_TFT_HX8340BN
+ tristate "FB driver for the HX8340BN LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for HX8340BN
+
+config FB_TFT_HX8347D
+ tristate "FB driver for the HX8347D LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for HX8347D
+
+config FB_TFT_HX8353D
+ tristate "FB driver for the HX8353D LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for HX8353D
+
+config FB_TFT_ILI9320
+ tristate "FB driver for the ILI9320 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ILI9320
+
+config FB_TFT_ILI9325
+ tristate "FB driver for the ILI9325 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ILI9325
+
+config FB_TFT_ILI9340
+ tristate "FB driver for the ILI9340 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ILI9340
+
+config FB_TFT_ILI9341
+ tristate "FB driver for the ILI9341 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ILI9341
+
+config FB_TFT_ILI9481
+ tristate "FB driver for the ILI9481 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ILI9481
+
+config FB_TFT_ILI9486
+ tristate "FB driver for the ILI9486 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ILI9486
+
+config FB_TFT_PCD8544
+ tristate "FB driver for the PCD8544 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for PCD8544
+
+config FB_TFT_RA8875
+ tristate "FB driver for the RA8875 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for RA8875
+
+config FB_TFT_S6D02A1
+ tristate "FB driver for the S6D02A1 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for S6D02A1
+
+config FB_TFT_S6D1121
+ tristate "FB driver for the S6D1211 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for S6D1121
+
+config FB_TFT_SSD1289
+ tristate "FB driver for the SSD1289 LCD Controller"
+ depends on FB_TFT
+ help
+ Framebuffer support for SSD1289
+
+config FB_TFT_SSD1306
+ tristate "FB driver for the SSD1306 OLED Controller"
+ depends on FB_TFT
+ help
+ Framebuffer support for SSD1306
+
+config FB_TFT_SSD1331
+ tristate "FB driver for the SSD1331 LCD Controller"
+ depends on FB_TFT
+ help
+ Framebuffer support for SSD1331
+
+config FB_TFT_SSD1351
+ tristate "FB driver for the SSD1351 LCD Controller"
+ depends on FB_TFT
+ help
+ Framebuffer support for SSD1351
+
+config FB_TFT_ST7735R
+ tristate "FB driver for the ST7735R LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for ST7735R
+
+config FB_TFT_TINYLCD
+ tristate "FB driver for tinylcd.com display"
+ depends on FB_TFT
+ help
+ Custom Framebuffer support for tinylcd.com display
+
+config FB_TFT_TLS8204
+ tristate "FB driver for the TLS8204 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for TLS8204
+
+config FB_TFT_UC1701
+ tristate "FB driver for the UC1701 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for UC1701
+
+config FB_TFT_UPD161704
+ tristate "FB driver for the uPD161704 LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for uPD161704
+
+config FB_TFT_WATTEROTT
+ tristate "FB driver for the WATTEROTT LCD Controller"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for WATTEROTT
+
+config FB_FLEX
+ tristate "Generic FB driver for TFT LCD displays"
+ depends on FB_TFT
+ help
+ Generic Framebuffer support for TFT LCD displays.
+
+config FB_TFT_FBTFT_DEVICE
+ tristate "Module to for adding FBTFT devices"
+ depends on FB_TFT
diff --git a/drivers/staging/fbtft/Makefile b/drivers/staging/fbtft/Makefile
new file mode 100644
index 000000000000..e773f0fdcfe8
--- /dev/null
+++ b/drivers/staging/fbtft/Makefile
@@ -0,0 +1,34 @@
+# Core module
+obj-$(CONFIG_FB_TFT) += fbtft.o
+fbtft-y += fbtft-core.o fbtft-sysfs.o fbtft-bus.o fbtft-io.o
+
+# drivers
+obj-$(CONFIG_FB_TFT_AGM1264K_FL) += fb_agm1264k-fl.o
+obj-$(CONFIG_FB_TFT_BD663474) += fb_bd663474.o
+obj-$(CONFIG_FB_TFT_HX8340BN) += fb_hx8340bn.o
+obj-$(CONFIG_FB_TFT_HX8347D) += fb_hx8347d.o
+obj-$(CONFIG_FB_TFT_HX8353D) += fb_hx8353d.o
+obj-$(CONFIG_FB_TFT_ILI9320) += fb_ili9320.o
+obj-$(CONFIG_FB_TFT_ILI9325) += fb_ili9325.o
+obj-$(CONFIG_FB_TFT_ILI9340) += fb_ili9340.o
+obj-$(CONFIG_FB_TFT_ILI9341) += fb_ili9341.o
+obj-$(CONFIG_FB_TFT_ILI9481) += fb_ili9481.o
+obj-$(CONFIG_FB_TFT_ILI9486) += fb_ili9486.o
+obj-$(CONFIG_FB_TFT_PCD8544) += fb_pcd8544.o
+obj-$(CONFIG_FB_TFT_RA8875) += fb_ra8875.o
+obj-$(CONFIG_FB_TFT_S6D02A1) += fb_s6d02a1.o
+obj-$(CONFIG_FB_TFT_S6D1121) += fb_s6d1121.o
+obj-$(CONFIG_FB_TFT_SSD1289) += fb_ssd1289.o
+obj-$(CONFIG_FB_TFT_SSD1306) += fb_ssd1306.o
+obj-$(CONFIG_FB_TFT_SSD1331) += fb_ssd1331.o
+obj-$(CONFIG_FB_TFT_SSD1351) += fb_ssd1351.o
+obj-$(CONFIG_FB_TFT_ST7735R) += fb_st7735r.o
+obj-$(CONFIG_FB_TFT_TINYLCD) += fb_tinylcd.o
+obj-$(CONFIG_FB_TFT_TLS8204) += fb_tls8204.o
+obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o
+obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o
+obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o
+obj-$(CONFIG_FB_FLEX) += flexfb.o
+
+# Device modules
+obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o
diff --git a/drivers/staging/fbtft/README b/drivers/staging/fbtft/README
new file mode 100644
index 000000000000..bc89b5805f7b
--- /dev/null
+++ b/drivers/staging/fbtft/README
@@ -0,0 +1,32 @@
+ FBTFT
+=========
+
+Linux Framebuffer drivers for small TFT LCD display modules.
+The module 'fbtft' makes writing drivers for some of these displays very easy.
+
+Development is done on a Raspberry Pi running the Raspbian "wheezy" distribution.
+
+INSTALLATION
+ Download kernel sources
+
+ From Linux 3.15
+ cd drivers/video/fbdev/fbtft
+ git clone https://github.com/notro/fbtft.git
+
+ Add to drivers/video/fbdev/Kconfig: source "drivers/video/fbdev/fbtft/Kconfig"
+ Add to drivers/video/fbdev/Makefile: obj-y += fbtft/
+
+ Before Linux 3.15
+ cd drivers/video
+ git clone https://github.com/notro/fbtft.git
+
+ Add to drivers/video/Kconfig: source "drivers/video/fbtft/Kconfig"
+ Add to drivers/video/Makefile: obj-y += fbtft/
+
+ Enable driver(s) in menuconfig and build the kernel
+
+
+See wiki for more information: https://github.com/notro/fbtft/wiki
+
+
+Source: https://github.com/notro/fbtft/
diff --git a/drivers/staging/fbtft/fb_agm1264k-fl.c b/drivers/staging/fbtft/fb_agm1264k-fl.c
new file mode 100644
index 000000000000..9cc7d25cf0e5
--- /dev/null
+++ b/drivers/staging/fbtft/fb_agm1264k-fl.c
@@ -0,0 +1,462 @@
+/*
+ * FB driver for Two KS0108 LCD controllers in AGM1264K-FL display
+ *
+ * Copyright (C) 2014 ololoshka2871
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+
+#include "fbtft.h"
+
+/* Uncomment text line to use negative image on display */
+/*#define NEGATIVE*/
+
+#define WHITE 0xff
+#define BLACK 0
+
+#define DRVNAME "fb_agm1264k-fl"
+#define WIDTH 64
+#define HEIGHT 64
+#define TOTALWIDTH (WIDTH * 2) /* because 2 x ks0108 in one display */
+#define FPS 20
+
+#define EPIN gpio.wr
+#define RS gpio.dc
+#define RW gpio.aux[2]
+#define CS0 gpio.aux[0]
+#define CS1 gpio.aux[1]
+
+
+/* diffusing error (“Floyd-Steinberg”) */
+#define DIFFUSING_MATRIX_WIDTH 2
+#define DIFFUSING_MATRIX_HEIGHT 2
+
+static const signed char
+diffusing_matrix[DIFFUSING_MATRIX_WIDTH][DIFFUSING_MATRIX_HEIGHT] = {
+ {-1, 3},
+ {3, 2},
+};
+
+static const unsigned char gamma_correction_table[] = {
+0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
+1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 6,
+6, 6, 6, 7, 7, 7, 8, 8, 8, 9, 9, 9, 10, 10, 11, 11, 11, 12, 12, 13,
+13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21,
+22, 22, 23, 23, 24, 25, 25, 26, 26, 27, 28, 28, 29, 30, 30, 31, 32,
+33, 33, 34, 35, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 43, 44, 45,
+46, 47, 48, 49, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,
+62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 73, 74, 75, 76, 77, 78, 79, 81,
+82, 83, 84, 85, 87, 88, 89, 90, 91, 93, 94, 95, 97, 98, 99, 100, 102,
+103, 105, 106, 107, 109, 110, 111, 113, 114, 116, 117, 119, 120, 121,
+123, 124, 126, 127, 129, 130, 132, 133, 135, 137, 138, 140, 141, 143,
+145, 146, 148, 149, 151, 153, 154, 156, 158, 159, 161, 163, 165, 166,
+168, 170, 172, 173, 175, 177, 179, 181, 182, 184, 186, 188, 190, 192,
+194, 196, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219,
+221, 223, 225, 227, 229, 231, 234, 236, 238, 240, 242, 244, 246, 248,
+251, 253, 255
+};
+
+static int init_display(struct fbtft_par *par)
+{
+ u8 i;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ for (i = 0; i < 2; ++i) {
+ write_reg(par, i, 0x3f); /* display on */
+ write_reg(par, i, 0x40); /* set x to 0 */
+ write_reg(par, i, 0xb0); /* set page to 0 */
+ write_reg(par, i, 0xc0); /* set start line to 0 */
+ }
+
+ return 0;
+}
+
+static void reset(struct fbtft_par *par)
+{
+ if (par->gpio.reset == -1)
+ return;
+
+ fbtft_dev_dbg(DEBUG_RESET, par, par->info->device, "%s()\n", __func__);
+
+ gpio_set_value(par->gpio.reset, 0);
+ udelay(20);
+ gpio_set_value(par->gpio.reset, 1);
+ mdelay(120);
+}
+
+/* Check if all necessary GPIOS defined */
+static int verify_gpios(struct fbtft_par *par)
+{
+ int i;
+
+ fbtft_dev_dbg(DEBUG_VERIFY_GPIOS, par, par->info->device,
+ "%s()\n", __func__);
+
+ if (par->EPIN < 0) {
+ dev_err(par->info->device,
+ "Missing info about 'wr' (aka E) gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < 8; ++i) {
+ if (par->gpio.db[i] < 0) {
+ dev_err(par->info->device,
+ "Missing info about 'db[%i]' gpio. Aborting.\n",
+ i);
+ return -EINVAL;
+ }
+ }
+ if (par->CS0 < 0) {
+ dev_err(par->info->device,
+ "Missing info about 'cs0' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ if (par->CS1 < 0) {
+ dev_err(par->info->device,
+ "Missing info about 'cs1' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ if (par->RW < 0) {
+ dev_err(par->info->device,
+ "Missing info about 'rw' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static unsigned long
+request_gpios_match(struct fbtft_par *par, const struct fbtft_gpio *gpio)
+{
+ fbtft_dev_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, par->info->device,
+ "%s('%s')\n", __func__, gpio->name);
+
+ if (strcasecmp(gpio->name, "wr") == 0) {
+ /* left ks0108 E pin */
+ par->EPIN = gpio->gpio;
+ return GPIOF_OUT_INIT_LOW;
+ } else if (strcasecmp(gpio->name, "cs0") == 0) {
+ /* left ks0108 controller pin */
+ par->CS0 = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ } else if (strcasecmp(gpio->name, "cs1") == 0) {
+ /* right ks0108 controller pin */
+ par->CS1 = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ }
+
+ /* if write (rw = 0) e(1->0) perform write */
+ /* if read (rw = 1) e(0->1) set data on D0-7*/
+ else if (strcasecmp(gpio->name, "rw") == 0) {
+ par->RW = gpio->gpio;
+ return GPIOF_OUT_INIT_LOW;
+ }
+
+ return FBTFT_GPIO_NO_MATCH;
+}
+
+/* This function oses to enter commands
+ * first byte - destination controller 0 or 1
+ * folowing - commands
+ */
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+ va_list args;
+ int i, ret;
+ u8 *buf = (u8 *)par->buf;
+
+ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+ va_start(args, len);
+ for (i = 0; i < len; i++)
+ buf[i] = (u8)va_arg(args, unsigned int);
+
+ va_end(args);
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
+ par->info->device, u8, buf, len, "%s: ", __func__);
+ }
+
+ va_start(args, len);
+
+ *buf = (u8)va_arg(args, unsigned int);
+
+ if (*buf > 1) {
+ va_end(args);
+ dev_err(par->info->device, "%s: Incorrect chip sellect request (%d)\n",
+ __func__, *buf);
+ return;
+ }
+
+ /* select chip */
+ if (*buf) {
+ /* cs1 */
+ gpio_set_value(par->CS0, 1);
+ gpio_set_value(par->CS1, 0);
+ } else {
+ /* cs0 */
+ gpio_set_value(par->CS0, 0);
+ gpio_set_value(par->CS1, 1);
+ }
+
+ gpio_set_value(par->RS, 0); /* RS->0 (command mode) */
+ len--;
+
+ if (len) {
+ i = len;
+ while (i--)
+ *buf++ = (u8)va_arg(args, unsigned int);
+ ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8)));
+ if (ret < 0) {
+ va_end(args);
+ dev_err(par->info->device, "%s: write() failed and returned %d\n",
+ __func__, ret);
+ return;
+ }
+ }
+
+ va_end(args);
+}
+
+static struct
+{
+ int xs, ys_page, xe, ye_page;
+} addr_win;
+
+/* save display writing zone */
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ addr_win.xs = xs;
+ addr_win.ys_page = ys / 8;
+ addr_win.xe = xe;
+ addr_win.ye_page = ye / 8;
+
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys_page=%d, xe=%d, ye_page=%d)\n", __func__,
+ addr_win.xs, addr_win.ys_page, addr_win.xe, addr_win.ye_page);
+}
+
+static void
+construct_line_bitmap(struct fbtft_par *par, u8 *dest, signed short *src,
+ int xs, int xe, int y)
+{
+ int x, i;
+
+ for (x = xs; x < xe; ++x) {
+ u8 res = 0;
+
+ for (i = 0; i < 8; i++)
+ if (src[(y * 8 + i) * par->info->var.xres + x])
+ res |= 1 << i;
+#ifdef NEGATIVE
+ *dest++ = res;
+#else
+ *dest++ = ~res;
+#endif
+ }
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16 = (u16 *)par->info->screen_base;
+ u8 *buf = par->txbuf.buf;
+ int x, y;
+ int ret = 0;
+
+ /* buffer to convert RGB565 -> grayscale16 -> Ditherd image 1bpp */
+ signed short *convert_buf = kmalloc(par->info->var.xres *
+ par->info->var.yres * sizeof(signed short), GFP_NOIO);
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ /* converting to grayscale16 */
+ for (x = 0; x < par->info->var.xres; ++x)
+ for (y = 0; y < par->info->var.yres; ++y) {
+ u16 pixel = vmem16[y * par->info->var.xres + x];
+ u16 b = pixel & 0x1f;
+ u16 g = (pixel & (0x3f << 5)) >> 5;
+ u16 r = (pixel & (0x1f << (5 + 6))) >> (5 + 6);
+
+ pixel = (299 * r + 587 * g + 114 * b) / 200;
+ if (pixel > 255)
+ pixel = 255;
+
+ /* gamma-correction by table */
+ convert_buf[y * par->info->var.xres + x] =
+ (signed short)gamma_correction_table[pixel];
+ }
+
+ /* Image Dithering */
+ for (x = 0; x < par->info->var.xres; ++x)
+ for (y = 0; y < par->info->var.yres; ++y) {
+ signed short pixel =
+ convert_buf[y * par->info->var.xres + x];
+ signed short error_b = pixel - BLACK;
+ signed short error_w = pixel - WHITE;
+ signed short error;
+ u16 i, j;
+
+ /* what color close? */
+ if (abs(error_b) >= abs(error_w)) {
+ /* white */
+ error = error_w;
+ pixel = 0xff;
+ } else {
+ /* black */
+ error = error_b;
+ pixel = 0;
+ }
+
+ error /= 8;
+
+ /* diffusion matrix row */
+ for (i = 0; i < DIFFUSING_MATRIX_WIDTH; ++i)
+ /* diffusion matrix column */
+ for (j = 0; j < DIFFUSING_MATRIX_HEIGHT; ++j) {
+ signed short *write_pos;
+ signed char coeff;
+
+ /* skip pixels out of zone */
+ if (x + i < 0 ||
+ x + i >= par->info->var.xres
+ || y + j >= par->info->var.yres)
+ continue;
+ write_pos = &convert_buf[
+ (y + j) * par->info->var.xres +
+ x + i];
+ coeff = diffusing_matrix[i][j];
+ if (coeff == -1)
+ /* pixel itself */
+ *write_pos = pixel;
+ else {
+ signed short p = *write_pos +
+ error * coeff;
+
+ if (p > WHITE)
+ p = WHITE;
+ if (p < BLACK)
+ p = BLACK;
+ *write_pos = p;
+ }
+ }
+ }
+
+ /* 1 string = 2 pages */
+ for (y = addr_win.ys_page; y <= addr_win.ye_page; ++y) {
+ /* left half of display */
+ if (addr_win.xs < par->info->var.xres / 2) {
+ construct_line_bitmap(par, buf, convert_buf,
+ addr_win.xs, par->info->var.xres / 2, y);
+
+ len = par->info->var.xres / 2 - addr_win.xs;
+
+ /* select left side (sc0)
+ * set addr
+ */
+ write_reg(par, 0x00, (1 << 6) | (u8)addr_win.xs);
+ write_reg(par, 0x00, (0x17 << 3) | (u8)y);
+
+ /* write bitmap */
+ gpio_set_value(par->RS, 1); /* RS->1 (data mode) */
+ ret = par->fbtftops.write(par, buf, len);
+ if (ret < 0)
+ dev_err(par->info->device,
+ "%s: write failed and returned: %d\n",
+ __func__, ret);
+ }
+ /* right half of display */
+ if (addr_win.xe >= par->info->var.xres / 2) {
+ construct_line_bitmap(par, buf,
+ convert_buf, par->info->var.xres / 2,
+ addr_win.xe + 1, y);
+
+ len = addr_win.xe + 1 - par->info->var.xres / 2;
+
+ /* select right side (sc1)
+ * set addr
+ */
+ write_reg(par, 0x01, (1 << 6));
+ write_reg(par, 0x01, (0x17 << 3) | (u8)y);
+
+ /* write bitmap */
+ gpio_set_value(par->RS, 1); /* RS->1 (data mode) */
+ par->fbtftops.write(par, buf, len);
+ if (ret < 0)
+ dev_err(par->info->device,
+ "%s: write failed and returned: %d\n",
+ __func__, ret);
+ }
+ }
+ kfree(convert_buf);
+
+ gpio_set_value(par->CS0, 1);
+ gpio_set_value(par->CS1, 1);
+
+ return ret;
+}
+
+static int write(struct fbtft_par *par, void *buf, size_t len)
+{
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ gpio_set_value(par->RW, 0); /* set write mode */
+
+
+ while (len--) {
+ u8 i, data;
+
+ data = *(u8 *) buf++;
+
+ /* set data bus */
+ for (i = 0; i < 8; ++i)
+ gpio_set_value(par->gpio.db[i], data & (1 << i));
+ /* set E */
+ gpio_set_value(par->EPIN, 1);
+ udelay(5);
+ /* unset E - write */
+ gpio_set_value(par->EPIN, 0);
+ udelay(1);
+ }
+
+ return 0;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = TOTALWIDTH,
+ .height = HEIGHT,
+ .fps = FPS,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .verify_gpios = verify_gpios,
+ .request_gpios_match = request_gpios_match,
+ .reset = reset,
+ .write = write,
+ .write_register = write_reg8_bus8,
+ .write_vmem = write_vmem,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "displaytronic,fb_agm1264k-fl", &display);
+
+MODULE_ALIAS("platform:" DRVNAME);
+
+MODULE_DESCRIPTION("Two KS0108 LCD controllers in AGM1264K-FL display");
+MODULE_AUTHOR("ololoshka2871");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_bd663474.c b/drivers/staging/fbtft/fb_bd663474.c
new file mode 100644
index 000000000000..7e00c609c7fe
--- /dev/null
+++ b/drivers/staging/fbtft/fb_bd663474.c
@@ -0,0 +1,193 @@
+/*
+ * FB driver for the uPD161704 LCD Controller
+ *
+ * Copyright (C) 2014 Seong-Woo Kim
+ *
+ * Based on fb_ili9325.c by Noralf Tronnes
+ * Based on ili9325.c by Jeroen Domburg
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_bd663474"
+#define WIDTH 240
+#define HEIGHT 320
+#define BPP 16
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ if (par->gpio.cs != -1)
+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+
+ par->fbtftops.reset(par);
+
+ /* Initialization sequence from Lib_UTFT */
+
+ /* oscillator start */
+ write_reg(par, 0x000,0x0001); /*oscillator 0: stop, 1: operation */
+ mdelay(10);
+
+ /* Power settings */
+ write_reg(par, 0x100, 0x0000 ); /* power supply setup */
+ write_reg(par, 0x101, 0x0000 );
+ write_reg(par, 0x102, 0x3110 );
+ write_reg(par, 0x103, 0xe200 );
+ write_reg(par, 0x110, 0x009d );
+ write_reg(par, 0x111, 0x0022 );
+ write_reg(par, 0x100, 0x0120 );
+ mdelay( 20 );
+
+ write_reg(par, 0x100, 0x3120 );
+ mdelay( 80 );
+ /* Display control */
+ write_reg(par, 0x001, 0x0100 );
+ write_reg(par, 0x002, 0x0000 );
+ write_reg(par, 0x003, 0x1230 );
+ write_reg(par, 0x006, 0x0000 );
+ write_reg(par, 0x007, 0x0101 );
+ write_reg(par, 0x008, 0x0808 );
+ write_reg(par, 0x009, 0x0000 );
+ write_reg(par, 0x00b, 0x0000 );
+ write_reg(par, 0x00c, 0x0000 );
+ write_reg(par, 0x00d, 0x0018 );
+ /* LTPS control settings */
+ write_reg(par, 0x012, 0x0000 );
+ write_reg(par, 0x013, 0x0000 );
+ write_reg(par, 0x018, 0x0000 );
+ write_reg(par, 0x019, 0x0000 );
+
+ write_reg(par, 0x203, 0x0000 );
+ write_reg(par, 0x204, 0x0000 );
+
+ write_reg(par, 0x210, 0x0000 );
+ write_reg(par, 0x211, 0x00ef );
+ write_reg(par, 0x212, 0x0000 );
+ write_reg(par, 0x213, 0x013f );
+ write_reg(par, 0x214, 0x0000 );
+ write_reg(par, 0x215, 0x0000 );
+ write_reg(par, 0x216, 0x0000 );
+ write_reg(par, 0x217, 0x0000 );
+
+ /* Gray scale settings */
+ write_reg(par, 0x300, 0x5343);
+ write_reg(par, 0x301, 0x1021);
+ write_reg(par, 0x302, 0x0003);
+ write_reg(par, 0x303, 0x0011);
+ write_reg(par, 0x304, 0x050a);
+ write_reg(par, 0x305, 0x4342);
+ write_reg(par, 0x306, 0x1100);
+ write_reg(par, 0x307, 0x0003);
+ write_reg(par, 0x308, 0x1201);
+ write_reg(par, 0x309, 0x050a);
+
+ /* RAM access settings */
+ write_reg(par, 0x400, 0x4027 );
+ write_reg(par, 0x401, 0x0000 );
+ write_reg(par, 0x402, 0x0000 ); /* First screen drive position (1) */
+ write_reg(par, 0x403, 0x013f ); /* First screen drive position (2) */
+ write_reg(par, 0x404, 0x0000 );
+
+ write_reg(par, 0x200, 0x0000 );
+ write_reg(par, 0x201, 0x0000 );
+ write_reg(par, 0x100, 0x7120 );
+ write_reg(par, 0x007, 0x0103 );
+ mdelay( 10 );
+ write_reg(par, 0x007, 0x0113 );
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+ switch (par->info->var.rotate) {
+ /* R200h = Horizontal GRAM Start Address */
+ /* R201h = Vertical GRAM Start Address */
+ case 0:
+ write_reg(par, 0x0200, xs);
+ write_reg(par, 0x0201, ys);
+ break;
+ case 180:
+ write_reg(par, 0x0200, WIDTH - 1 - xs);
+ write_reg(par, 0x0201, HEIGHT - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x0200, WIDTH - 1 - ys);
+ write_reg(par, 0x0201, xs);
+ break;
+ case 90:
+ write_reg(par, 0x0200, ys);
+ write_reg(par, 0x0201, HEIGHT - 1 - xs);
+ break;
+ }
+ write_reg(par, 0x202); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ /* AM: GRAM update direction */
+ case 0:
+ write_reg(par, 0x003, 0x1230);
+ break;
+ case 180:
+ write_reg(par, 0x003, 0x1200);
+ break;
+ case 270:
+ write_reg(par, 0x003, 0x1228);
+ break;
+ case 90:
+ write_reg(par, 0x003, 0x1218);
+ break;
+ }
+
+ return 0;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 16,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .bpp = BPP,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "hitachi,bd663474", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:bd663474");
+MODULE_ALIAS("platform:bd663474");
+
+MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller");
+MODULE_AUTHOR("Seong-Woo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_hx8340bn.c b/drivers/staging/fbtft/fb_hx8340bn.c
new file mode 100644
index 000000000000..3939502f2c81
--- /dev/null
+++ b/drivers/staging/fbtft/fb_hx8340bn.c
@@ -0,0 +1,229 @@
+/*
+ * FB driver for the HX8340BN LCD Controller
+ *
+ * This display uses 9-bit SPI: Data/Command bit + 8 data bits
+ * For platforms that doesn't support 9-bit, the driver is capable
+ * of emulating this using 8-bit transfer.
+ * This is done by transfering eight 9-bit words in 9 bytes.
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_hx8340bn"
+#define WIDTH 176
+#define HEIGHT 220
+#define TXBUFLEN (4 * PAGE_SIZE)
+#define DEFAULT_GAMMA "1 3 0E 5 0 2 09 0 6 1 7 1 0 2 2\n" \
+ "3 3 17 8 4 7 05 7 6 0 3 1 6 0 0 "
+
+
+static bool emulate;
+module_param(emulate, bool, 0);
+MODULE_PARM_DESC(emulate, "Force emulation in 9-bit mode");
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ /* BTL221722-276L startup sequence, from datasheet */
+
+ /* SETEXTCOM: Set extended command set (C1h)
+ This command is used to set extended command set access enable.
+ Enable: After command (C1h), must write: ffh,83h,40h */
+ write_reg(par, 0xC1, 0xFF, 0x83, 0x40);
+
+ /* Sleep out
+ This command turns off sleep mode.
+ In this mode the DC/DC converter is enabled, Internal oscillator
+ is started, and panel scanning is started. */
+ write_reg(par, 0x11);
+ mdelay(150);
+
+ /* Undoc'd register? */
+ write_reg(par, 0xCA, 0x70, 0x00, 0xD9);
+
+ /* SETOSC: Set Internal Oscillator (B0h)
+ This command is used to set internal oscillator related settings */
+ /* OSC_EN: Enable internal oscillator */
+ /* Internal oscillator frequency: 125% x 2.52MHz */
+ write_reg(par, 0xB0, 0x01, 0x11);
+
+ /* Drive ability setting */
+ write_reg(par, 0xC9, 0x90, 0x49, 0x10, 0x28, 0x28, 0x10, 0x00, 0x06);
+ mdelay(20);
+
+ /* SETPWCTR5: Set Power Control 5(B5h)
+ This command is used to set VCOM Low and VCOM High Voltage */
+ /* VCOMH 0110101 : 3.925 */
+ /* VCOML 0100000 : -1.700 */
+ /* 45h=69 VCOMH: "VMH" + 5d VCOML: "VMH" + 5d */
+ write_reg(par, 0xB5, 0x35, 0x20, 0x45);
+
+ /* SETPWCTR4: Set Power Control 4(B4h)
+ VRH[4:0]: Specify the VREG1 voltage adjusting.
+ VREG1 voltage is for gamma voltage setting.
+ BT[2:0]: Switch the output factor of step-up circuit 2
+ for VGH and VGL voltage generation. */
+ write_reg(par, 0xB4, 0x33, 0x25, 0x4C);
+ mdelay(10);
+
+ /* Interface Pixel Format (3Ah)
+ This command is used to define the format of RGB picture data,
+ which is to be transfer via the system and RGB interface. */
+ /* RGB interface: 16 Bit/Pixel */
+ write_reg(par, 0x3A, 0x05);
+
+ /* Display on (29h)
+ This command is used to recover from DISPLAY OFF mode.
+ Output from the Frame Memory is enabled. */
+ write_reg(par, 0x29);
+ mdelay(10);
+
+ return 0;
+}
+
+void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ write_reg(par, FBTFT_CASET, 0x00, xs, 0x00, xe);
+ write_reg(par, FBTFT_RASET, 0x00, ys, 0x00, ye);
+ write_reg(par, FBTFT_RAMWR);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* MADCTL - Memory data access control */
+ /* RGB/BGR can be set with H/W pin SRGB and MADCTL BGR bit */
+#define MY (1 << 7)
+#define MX (1 << 6)
+#define MV (1 << 5)
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x36, (par->bgr << 3));
+ break;
+ case 270:
+ write_reg(par, 0x36, MX | MV | (par->bgr << 3));
+ break;
+ case 180:
+ write_reg(par, 0x36, MX | MY | (par->bgr << 3));
+ break;
+ case 90:
+ write_reg(par, 0x36, MY | MV | (par->bgr << 3));
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Gamma Curve selection, GC (only GC0 can be customized):
+ 0 = 2.2, 1 = 1.8, 2 = 2.5, 3 = 1.0
+ Gamma string format:
+ OP0 OP1 CP0 CP1 CP2 CP3 CP4 MP0 MP1 MP2 MP3 MP4 MP5 CGM0 CGM1
+ ON0 ON1 CN0 CN1 CN2 CN3 CN4 MN0 MN1 MN2 MN3 MN4 MN5 XXXX GC
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long mask[] = {
+ 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111,
+ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b11, 0b11,
+ 0b1111, 0b1111, 0b11111, 0b1111, 0b1111, 0b1111, 0b11111,
+ 0b111, 0b111, 0b111, 0b111, 0b111, 0b111, 0b0, 0b0 };
+ int i, j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < par->gamma.num_curves; i++)
+ for (j = 0; j < par->gamma.num_values; j++)
+ CURVE(i, j) &= mask[i * par->gamma.num_values + j];
+
+ write_reg(par, 0x26, 1 << CURVE(1, 14)); /* Gamma Set (26h) */
+
+ if (CURVE(1, 14))
+ return 0; /* only GC0 can be customized */
+
+ write_reg(par, 0xC2,
+ (CURVE(0, 8) << 4) | CURVE(0, 7),
+ (CURVE(0, 10) << 4) | CURVE(0, 9),
+ (CURVE(0, 12) << 4) | CURVE(0, 11),
+ CURVE(0, 2),
+ (CURVE(0, 4) << 4) | CURVE(0, 3),
+ CURVE(0, 5),
+ CURVE(0, 6),
+ (CURVE(0, 1) << 4) | CURVE(0, 0),
+ (CURVE(0, 14) << 2) | CURVE(0, 13));
+
+ write_reg(par, 0xC3,
+ (CURVE(1, 8) << 4) | CURVE(1, 7),
+ (CURVE(1, 10) << 4) | CURVE(1, 9),
+ (CURVE(1, 12) << 4) | CURVE(1, 11),
+ CURVE(1, 2),
+ (CURVE(1, 4) << 4) | CURVE(1, 3),
+ CURVE(1, 5),
+ CURVE(1, 6),
+ (CURVE(1, 1) << 4) | CURVE(1, 0));
+
+ mdelay(10);
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .txbuflen = TXBUFLEN,
+ .gamma_num = 2,
+ .gamma_len = 15,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8340bn", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:hx8340bn");
+MODULE_ALIAS("platform:hx8340bn");
+
+MODULE_DESCRIPTION("FB driver for the HX8340BN LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_hx8347d.c b/drivers/staging/fbtft/fb_hx8347d.c
new file mode 100644
index 000000000000..8139a8f587b7
--- /dev/null
+++ b/drivers/staging/fbtft/fb_hx8347d.c
@@ -0,0 +1,181 @@
+/*
+ * FB driver for the HX8347D LCD Controller
+ *
+ * Copyright (C) 2013 Christian Vogelgsang
+ *
+ * Based on driver code found here: https://github.com/watterott/r61505u-Adapter
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_hx8347d"
+#define WIDTH 320
+#define HEIGHT 240
+#define DEFAULT_GAMMA "0 0 0 0 0 0 0 0 0 0 0 0 0 0\n" \
+ "0 0 0 0 0 0 0 0 0 0 0 0 0 0"
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ /* driving ability */
+ write_reg(par, 0xEA, 0x00);
+ write_reg(par, 0xEB, 0x20);
+ write_reg(par, 0xEC, 0x0C);
+ write_reg(par, 0xED, 0xC4);
+ write_reg(par, 0xE8, 0x40);
+ write_reg(par, 0xE9, 0x38);
+ write_reg(par, 0xF1, 0x01);
+ write_reg(par, 0xF2, 0x10);
+ write_reg(par, 0x27, 0xA3);
+
+ /* power voltage */
+ write_reg(par, 0x1B, 0x1B);
+ write_reg(par, 0x1A, 0x01);
+ write_reg(par, 0x24, 0x2F);
+ write_reg(par, 0x25, 0x57);
+
+ /* VCOM offset */
+ write_reg(par, 0x23, 0x8D); /* for flicker adjust */
+
+ /* power on */
+ write_reg(par, 0x18, 0x36);
+ write_reg(par, 0x19, 0x01); /* start osc */
+ write_reg(par, 0x01, 0x00); /* wakeup */
+ write_reg(par, 0x1F, 0x88);
+ mdelay(5);
+ write_reg(par, 0x1F, 0x80);
+ mdelay(5);
+ write_reg(par, 0x1F, 0x90);
+ mdelay(5);
+ write_reg(par, 0x1F, 0xD0);
+ mdelay(5);
+
+ /* color selection */
+ write_reg(par, 0x17, 0x05); /* 65k */
+
+ /*panel characteristic */
+ write_reg(par, 0x36, 0x00);
+
+ /*display on */
+ write_reg(par, 0x28, 0x38);
+ mdelay(40);
+ write_reg(par, 0x28, 0x3C);
+
+ /* orientation */
+ write_reg(par, 0x16, 0x60 | (par->bgr << 3));
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ write_reg(par, 0x02, (xs >> 8) & 0xFF);
+ write_reg(par, 0x03, xs & 0xFF);
+ write_reg(par, 0x04, (xe >> 8) & 0xFF);
+ write_reg(par, 0x05, xe & 0xFF);
+ write_reg(par, 0x06, (ys >> 8) & 0xFF);
+ write_reg(par, 0x07, ys & 0xFF);
+ write_reg(par, 0x08, (ye >> 8) & 0xFF);
+ write_reg(par, 0x09, ye & 0xFF);
+ write_reg(par, 0x22);
+}
+
+/*
+ Gamma string format:
+ VRP0 VRP1 VRP2 VRP3 VRP4 VRP5 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 CGM
+ VRN0 VRN1 VRN2 VRN3 VRN4 VRN5 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 CGM
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long mask[] = {
+ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+ 0b1111111, 0b1111111,
+ 0b11111, 0b11111, 0b11111, 0b11111, 0b11111,
+ 0b1111};
+ int i, j;
+ int acc = 0;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < par->gamma.num_curves; i++)
+ for (j = 0; j < par->gamma.num_values; j++) {
+ acc += CURVE(i, j);
+ CURVE(i, j) &= mask[j];
+ }
+
+ if (acc == 0) /* skip if all values are zero */
+ return 0;
+
+ for (i = 0; i < par->gamma.num_curves; i++) {
+ write_reg(par, 0x40 + (i * 0x10), CURVE(i, 0));
+ write_reg(par, 0x41 + (i * 0x10), CURVE(i, 1));
+ write_reg(par, 0x42 + (i * 0x10), CURVE(i, 2));
+ write_reg(par, 0x43 + (i * 0x10), CURVE(i, 3));
+ write_reg(par, 0x44 + (i * 0x10), CURVE(i, 4));
+ write_reg(par, 0x45 + (i * 0x10), CURVE(i, 5));
+ write_reg(par, 0x46 + (i * 0x10), CURVE(i, 6));
+ write_reg(par, 0x47 + (i * 0x10), CURVE(i, 7));
+ write_reg(par, 0x48 + (i * 0x10), CURVE(i, 8));
+ write_reg(par, 0x49 + (i * 0x10), CURVE(i, 9));
+ write_reg(par, 0x4A + (i * 0x10), CURVE(i, 10));
+ write_reg(par, 0x4B + (i * 0x10), CURVE(i, 11));
+ write_reg(par, 0x4C + (i * 0x10), CURVE(i, 12));
+ }
+ write_reg(par, 0x5D, (CURVE(1, 0) << 4) | CURVE(0, 0));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .gamma_num = 2,
+ .gamma_len = 14,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8347d", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:hx8347d");
+MODULE_ALIAS("platform:hx8347d");
+
+MODULE_DESCRIPTION("FB driver for the HX8347D LCD Controller");
+MODULE_AUTHOR("Christian Vogelgsang");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_hx8353d.c b/drivers/staging/fbtft/fb_hx8353d.c
new file mode 100644
index 000000000000..c9512dc5f4d3
--- /dev/null
+++ b/drivers/staging/fbtft/fb_hx8353d.c
@@ -0,0 +1,166 @@
+/*
+ * FB driver for the HX8353D LCD Controller
+ *
+ * Copyright (c) 2014 Petr Olivka
+ * Copyright (c) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_hx8353d"
+#define DEFAULT_GAMMA "50 77 40 08 BF 00 03 0F 00 01 73 00 72 03 B0 0F 08 00 0F"
+
+static int init_display(struct fbtft_par *par)
+{
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+ mdelay(150);
+
+ /* SETEXTC */
+ write_reg(par, 0xB9, 0xFF, 0x83, 0x53);
+
+ /* RADJ */
+ write_reg(par, 0xB0, 0x3C, 0x01);
+
+ /* VCOM */
+ write_reg(par, 0xB6, 0x94, 0x6C, 0x50);
+
+ /* PWR */
+ write_reg(par, 0xB1, 0x00, 0x01, 0x1B, 0x03, 0x01, 0x08, 0x77, 0x89);
+
+ /* COLMOD */
+ write_reg(par, 0x3A, 0x05);
+
+ /* MEM ACCESS */
+ write_reg(par, 0x36, 0xC0);
+
+ /* SLPOUT - Sleep out & booster on */
+ write_reg(par, 0x11);
+ mdelay(150);
+
+ /* DISPON - Display On */
+ write_reg(par, 0x29);
+
+ /* RGBSET */
+ write_reg(par, 0x2D,
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62);
+
+ return 0;
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* column address */
+ write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff);
+
+ /* row adress */
+ write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff);
+
+ /* memory write */
+ write_reg(par, 0x2c);
+}
+
+#define my (1 << 7)
+#define mx (1 << 6)
+#define mv (1 << 5)
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* madctl - memory data access control
+ rgb/bgr:
+ 1. mode selection pin srgb
+ rgb h/w pin for color filter setting: 0=rgb, 1=bgr
+ 2. madctl rgb bit
+ rgb-bgr order color filter panel: 0=rgb, 1=bgr */
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x36, mx | my | (par->bgr << 3));
+ break;
+ case 270:
+ write_reg(par, 0x36, my | mv | (par->bgr << 3));
+ break;
+ case 180:
+ write_reg(par, 0x36, (par->bgr << 3));
+ break;
+ case 90:
+ write_reg(par, 0x36, mx | mv | (par->bgr << 3));
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ gamma string format:
+*/
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ write_reg(par, 0xE0,
+ curves[0], curves[1], curves[2], curves[3],
+ curves[4], curves[5], curves[6], curves[7],
+ curves[8], curves[9], curves[10], curves[11],
+ curves[12], curves[13], curves[14], curves[15],
+ curves[16], curves[17], curves[18]);
+
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = 128,
+ .height = 160,
+ .gamma_num = 1,
+ .gamma_len = 19,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "himax,hx8353d", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:hx8353d");
+MODULE_ALIAS("platform:hx8353d");
+
+MODULE_DESCRIPTION("FB driver for the HX8353D LCD Controller");
+MODULE_AUTHOR("Petr Olivka");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9320.c b/drivers/staging/fbtft/fb_ili9320.c
new file mode 100644
index 000000000000..b26d89368da7
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9320.c
@@ -0,0 +1,234 @@
+/*
+ * FB driver for the ILI9320 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ili9320"
+#define WIDTH 240
+#define HEIGHT 320
+#define DEFAULT_GAMMA "07 07 6 0 0 0 5 5 4 0\n" \
+ "07 08 4 7 5 1 2 0 7 7"
+
+
+static unsigned read_devicecode(struct fbtft_par *par)
+{
+ int ret;
+ u8 rxbuf[8] = {0, };
+
+ write_reg(par, 0x0000);
+ ret = par->fbtftops.read(par, rxbuf, 4);
+ return (rxbuf[2] << 8) | rxbuf[3];
+}
+
+static int init_display(struct fbtft_par *par)
+{
+ unsigned devcode;
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ devcode = read_devicecode(par);
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Device code: 0x%04X\n",
+ devcode);
+ if ((devcode != 0x0000) && (devcode != 0x9320))
+ dev_warn(par->info->device,
+ "Unrecognized Device code: 0x%04X (expected 0x9320)\n",
+ devcode);
+
+ /* Initialization sequence from ILI9320 Application Notes */
+
+ /* *********** Start Initial Sequence ********* */
+ write_reg(par, 0x00E5, 0x8000); /* Set the Vcore voltage and this setting is must. */
+ write_reg(par, 0x0000, 0x0001); /* Start internal OSC. */
+ write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */
+ write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */
+ write_reg(par, 0x0004, 0x0000); /* Resize register */
+ write_reg(par, 0x0008, 0x0202); /* set the back and front porch */
+ write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */
+ write_reg(par, 0x000A, 0x0000); /* FMARK function */
+ write_reg(par, 0x000C, 0x0000); /* RGB interface setting */
+ write_reg(par, 0x000D, 0x0000); /* Frame marker Position */
+ write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */
+
+ /* ***********Power On sequence *************** */
+ write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+ write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */
+ write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */
+ write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */
+ mdelay(200); /* Dis-charge capacitor power voltage */
+ write_reg(par, 0x0010, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+ write_reg(par, 0x0011, 0x0031); /* R11h=0x0031 at VCI=3.3V DC1[2:0], DC0[2:0], VC[2:0] */
+ mdelay(50);
+ write_reg(par, 0x0012, 0x0138); /* R12h=0x0138 at VCI=3.3V VREG1OUT voltage */
+ mdelay(50);
+ write_reg(par, 0x0013, 0x1800); /* R13h=0x1800 at VCI=3.3V VDV[4:0] for VCOM amplitude */
+ write_reg(par, 0x0029, 0x0008); /* R29h=0x0008 at VCI=3.3V VCM[4:0] for VCOMH */
+ mdelay(50);
+ write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */
+ write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */
+
+ /* ------------------ Set GRAM area --------------- */
+ write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */
+ write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */
+ write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */
+ write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */
+ write_reg(par, 0x0060, 0x2700); /* Gate Scan Line */
+ write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */
+ write_reg(par, 0x006A, 0x0000); /* set scrolling line */
+
+ /* -------------- Partial Display Control --------- */
+ write_reg(par, 0x0080, 0x0000);
+ write_reg(par, 0x0081, 0x0000);
+ write_reg(par, 0x0082, 0x0000);
+ write_reg(par, 0x0083, 0x0000);
+ write_reg(par, 0x0084, 0x0000);
+ write_reg(par, 0x0085, 0x0000);
+
+ /* -------------- Panel Control ------------------- */
+ write_reg(par, 0x0090, 0x0010);
+ write_reg(par, 0x0092, 0x0000);
+ write_reg(par, 0x0093, 0x0003);
+ write_reg(par, 0x0095, 0x0110);
+ write_reg(par, 0x0097, 0x0000);
+ write_reg(par, 0x0098, 0x0000);
+ write_reg(par, 0x0007, 0x0173); /* 262K color and display ON */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ switch (par->info->var.rotate) {
+ /* R20h = Horizontal GRAM Start Address */
+ /* R21h = Vertical GRAM Start Address */
+ case 0:
+ write_reg(par, 0x0020, xs);
+ write_reg(par, 0x0021, ys);
+ break;
+ case 180:
+ write_reg(par, 0x0020, WIDTH - 1 - xs);
+ write_reg(par, 0x0021, HEIGHT - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x0020, WIDTH - 1 - ys);
+ write_reg(par, 0x0021, xs);
+ break;
+ case 90:
+ write_reg(par, 0x0020, ys);
+ write_reg(par, 0x0021, HEIGHT - 1 - xs);
+ break;
+ }
+ write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x3, (par->bgr << 12) | 0x30);
+ break;
+ case 270:
+ write_reg(par, 0x3, (par->bgr << 12) | 0x28);
+ break;
+ case 180:
+ write_reg(par, 0x3, (par->bgr << 12) | 0x00);
+ break;
+ case 90:
+ write_reg(par, 0x3, (par->bgr << 12) | 0x18);
+ break;
+ }
+ return 0;
+}
+
+/*
+ Gamma string format:
+ VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5
+ VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long mask[] = {
+ 0b11111, 0b11111, 0b111, 0b111, 0b111,
+ 0b111, 0b111, 0b111, 0b111, 0b111,
+ 0b11111, 0b11111, 0b111, 0b111, 0b111,
+ 0b111, 0b111, 0b111, 0b111, 0b111 };
+ int i, j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 10; j++)
+ CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4));
+ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6));
+ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8));
+ write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2));
+ write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0));
+
+ write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4));
+ write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6));
+ write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8));
+ write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2));
+ write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 16,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .gamma_num = 2,
+ .gamma_len = 10,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9320", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9320");
+MODULE_ALIAS("platform:ili9320");
+
+MODULE_DESCRIPTION("FB driver for the ILI9320 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9325.c b/drivers/staging/fbtft/fb_ili9325.c
new file mode 100644
index 000000000000..5f88145fac9b
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9325.c
@@ -0,0 +1,291 @@
+/*
+ * FB driver for the ILI9325 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * Based on ili9325.c by Jeroen Domburg
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ili9325"
+#define WIDTH 240
+#define HEIGHT 320
+#define BPP 16
+#define FPS 20
+#define DEFAULT_GAMMA "0F 00 7 2 0 0 6 5 4 1\n" \
+ "04 16 2 7 6 3 2 1 7 7"
+
+
+static unsigned bt = 6; /* VGL=Vci*4 , VGH=Vci*4 */
+module_param(bt, uint, 0);
+MODULE_PARM_DESC(bt, "Sets the factor used in the step-up circuits");
+
+static unsigned vc = 0b011; /* Vci1=Vci*0.80 */
+module_param(vc, uint, 0);
+MODULE_PARM_DESC(vc,
+"Sets the ratio factor of Vci to generate the reference voltages Vci1");
+
+static unsigned vrh = 0b1101; /* VREG1OUT=Vci*1.85 */
+module_param(vrh, uint, 0);
+MODULE_PARM_DESC(vrh,
+"Set the amplifying rate (1.6 ~ 1.9) of Vci applied to output the VREG1OUT");
+
+static unsigned vdv = 0b10010; /* VCOMH amplitude=VREG1OUT*0.98 */
+module_param(vdv, uint, 0);
+MODULE_PARM_DESC(vdv,
+"Select the factor of VREG1OUT to set the amplitude of Vcom");
+
+static unsigned vcm = 0b001010; /* VCOMH=VREG1OUT*0.735 */
+module_param(vcm, uint, 0);
+MODULE_PARM_DESC(vcm, "Set the internal VcomH voltage");
+
+
+/*
+Verify that this configuration is within the Voltage limits
+
+Display module configuration: Vcc = IOVcc = Vci = 3.3V
+
+ Voltages
+----------
+Vci = 3.3
+Vci1 = Vci * 0.80 = 2.64
+DDVDH = Vci1 * 2 = 5.28
+VCL = -Vci1 = -2.64
+VREG1OUT = Vci * 1.85 = 4.88
+VCOMH = VREG1OUT * 0.735 = 3.59
+VCOM amplitude = VREG1OUT * 0.98 = 4.79
+VGH = Vci * 4 = 13.2
+VGL = -Vci * 4 = -13.2
+
+ Limits
+--------
+Power supplies
+1.65 < IOVcc < 3.30 => 1.65 < 3.3 < 3.30
+2.40 < Vcc < 3.30 => 2.40 < 3.3 < 3.30
+2.50 < Vci < 3.30 => 2.50 < 3.3 < 3.30
+
+Source/VCOM power supply voltage
+ 4.50 < DDVDH < 6.0 => 4.50 < 5.28 < 6.0
+-3.0 < VCL < -2.0 => -3.0 < -2.64 < -2.0
+VCI - VCL < 6.0 => 5.94 < 6.0
+
+Gate driver output voltage
+ 10 < VGH < 20 => 10 < 13.2 < 20
+-15 < VGL < -5 => -15 < -13.2 < -5
+VGH - VGL < 32 => 26.4 < 32
+
+VCOM driver output voltage
+VCOMH - VCOML < 6.0 => 4.79 < 6.0
+*/
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ if (par->gpio.cs != -1)
+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+
+ bt &= 0b111;
+ vc &= 0b111;
+ vrh &= 0b1111;
+ vdv &= 0b11111;
+ vcm &= 0b111111;
+
+ /* Initialization sequence from ILI9325 Application Notes */
+
+ /* ----------- Start Initial Sequence ----------- */
+ write_reg(par, 0x00E3, 0x3008); /* Set internal timing */
+ write_reg(par, 0x00E7, 0x0012); /* Set internal timing */
+ write_reg(par, 0x00EF, 0x1231); /* Set internal timing */
+ write_reg(par, 0x0001, 0x0100); /* set SS and SM bit */
+ write_reg(par, 0x0002, 0x0700); /* set 1 line inversion */
+ write_reg(par, 0x0004, 0x0000); /* Resize register */
+ write_reg(par, 0x0008, 0x0207); /* set the back porch and front porch */
+ write_reg(par, 0x0009, 0x0000); /* set non-display area refresh cycle */
+ write_reg(par, 0x000A, 0x0000); /* FMARK function */
+ write_reg(par, 0x000C, 0x0000); /* RGB interface setting */
+ write_reg(par, 0x000D, 0x0000); /* Frame marker Position */
+ write_reg(par, 0x000F, 0x0000); /* RGB interface polarity */
+
+ /* ----------- Power On sequence ----------- */
+ write_reg(par, 0x0010, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+ write_reg(par, 0x0011, 0x0007); /* DC1[2:0], DC0[2:0], VC[2:0] */
+ write_reg(par, 0x0012, 0x0000); /* VREG1OUT voltage */
+ write_reg(par, 0x0013, 0x0000); /* VDV[4:0] for VCOM amplitude */
+ mdelay(200); /* Dis-charge capacitor power voltage */
+ write_reg(par, 0x0010, /* SAP, BT[3:0], AP, DSTB, SLP, STB */
+ (1 << 12) | (bt << 8) | (1 << 7) | (0b001 << 4));
+ write_reg(par, 0x0011, 0x220 | vc); /* DC1[2:0], DC0[2:0], VC[2:0] */
+ mdelay(50); /* Delay 50ms */
+ write_reg(par, 0x0012, vrh); /* Internal reference voltage= Vci; */
+ mdelay(50); /* Delay 50ms */
+ write_reg(par, 0x0013, vdv << 8); /* Set VDV[4:0] for VCOM amplitude */
+ write_reg(par, 0x0029, vcm); /* Set VCM[5:0] for VCOMH */
+ write_reg(par, 0x002B, 0x000C); /* Set Frame Rate */
+ mdelay(50); /* Delay 50ms */
+ write_reg(par, 0x0020, 0x0000); /* GRAM horizontal Address */
+ write_reg(par, 0x0021, 0x0000); /* GRAM Vertical Address */
+
+ /*------------------ Set GRAM area --------------- */
+ write_reg(par, 0x0050, 0x0000); /* Horizontal GRAM Start Address */
+ write_reg(par, 0x0051, 0x00EF); /* Horizontal GRAM End Address */
+ write_reg(par, 0x0052, 0x0000); /* Vertical GRAM Start Address */
+ write_reg(par, 0x0053, 0x013F); /* Vertical GRAM Start Address */
+ write_reg(par, 0x0060, 0xA700); /* Gate Scan Line */
+ write_reg(par, 0x0061, 0x0001); /* NDL,VLE, REV */
+ write_reg(par, 0x006A, 0x0000); /* set scrolling line */
+
+ /*-------------- Partial Display Control --------- */
+ write_reg(par, 0x0080, 0x0000);
+ write_reg(par, 0x0081, 0x0000);
+ write_reg(par, 0x0082, 0x0000);
+ write_reg(par, 0x0083, 0x0000);
+ write_reg(par, 0x0084, 0x0000);
+ write_reg(par, 0x0085, 0x0000);
+
+ /*-------------- Panel Control ------------------- */
+ write_reg(par, 0x0090, 0x0010);
+ write_reg(par, 0x0092, 0x0600);
+ write_reg(par, 0x0007, 0x0133); /* 262K color and display ON */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+ switch (par->info->var.rotate) {
+ /* R20h = Horizontal GRAM Start Address */
+ /* R21h = Vertical GRAM Start Address */
+ case 0:
+ write_reg(par, 0x0020, xs);
+ write_reg(par, 0x0021, ys);
+ break;
+ case 180:
+ write_reg(par, 0x0020, WIDTH - 1 - xs);
+ write_reg(par, 0x0021, HEIGHT - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x0020, WIDTH - 1 - ys);
+ write_reg(par, 0x0021, xs);
+ break;
+ case 90:
+ write_reg(par, 0x0020, ys);
+ write_reg(par, 0x0021, HEIGHT - 1 - xs);
+ break;
+ }
+ write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ /* AM: GRAM update direction */
+ case 0:
+ write_reg(par, 0x03, 0x0030 | (par->bgr << 12));
+ break;
+ case 180:
+ write_reg(par, 0x03, 0x0000 | (par->bgr << 12));
+ break;
+ case 270:
+ write_reg(par, 0x03, 0x0028 | (par->bgr << 12));
+ break;
+ case 90:
+ write_reg(par, 0x03, 0x0018 | (par->bgr << 12));
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Gamma string format:
+ VRP0 VRP1 RP0 RP1 KP0 KP1 KP2 KP3 KP4 KP5
+ VRN0 VRN1 RN0 RN1 KN0 KN1 KN2 KN3 KN4 KN5
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long mask[] = {
+ 0b11111, 0b11111, 0b111, 0b111, 0b111,
+ 0b111, 0b111, 0b111, 0b111, 0b111,
+ 0b11111, 0b11111, 0b111, 0b111, 0b111,
+ 0b111, 0b111, 0b111, 0b111, 0b111 };
+ int i, j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 10; j++)
+ CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4));
+ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6));
+ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8));
+ write_reg(par, 0x0035, CURVE(0, 3) << 8 | CURVE(0, 2));
+ write_reg(par, 0x0036, CURVE(0, 1) << 8 | CURVE(0, 0));
+
+ write_reg(par, 0x0037, CURVE(1, 5) << 8 | CURVE(1, 4));
+ write_reg(par, 0x0038, CURVE(1, 7) << 8 | CURVE(1, 6));
+ write_reg(par, 0x0039, CURVE(1, 9) << 8 | CURVE(1, 8));
+ write_reg(par, 0x003C, CURVE(1, 3) << 8 | CURVE(1, 2));
+ write_reg(par, 0x003D, CURVE(1, 1) << 8 | CURVE(1, 0));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 16,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .bpp = BPP,
+ .fps = FPS,
+ .gamma_num = 2,
+ .gamma_len = 10,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9325", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9325");
+MODULE_ALIAS("platform:ili9325");
+
+MODULE_DESCRIPTION("FB driver for the ILI9325 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9340.c b/drivers/staging/fbtft/fb_ili9340.c
new file mode 100644
index 000000000000..985687d94ec2
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9340.c
@@ -0,0 +1,163 @@
+/*
+ * FB driver for the ILI9340 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ili9340"
+#define WIDTH 240
+#define HEIGHT 320
+
+
+/* Init sequence taken from: Arduino Library for the Adafruit 2.2" display */
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ write_reg(par, 0xEF, 0x03, 0x80, 0x02);
+ write_reg(par, 0xCF, 0x00 , 0XC1 , 0X30);
+ write_reg(par, 0xED, 0x64 , 0x03 , 0X12 , 0X81);
+ write_reg(par, 0xE8, 0x85 , 0x00 , 0x78);
+ write_reg(par, 0xCB, 0x39 , 0x2C , 0x00 , 0x34 , 0x02);
+ write_reg(par, 0xF7, 0x20);
+ write_reg(par, 0xEA, 0x00 , 0x00);
+
+ /* Power Control 1 */
+ write_reg(par, 0xC0, 0x23);
+
+ /* Power Control 2 */
+ write_reg(par, 0xC1, 0x10);
+
+ /* VCOM Control 1 */
+ write_reg(par, 0xC5, 0x3e, 0x28);
+
+ /* VCOM Control 2 */
+ write_reg(par, 0xC7, 0x86);
+
+ /* COLMOD: Pixel Format Set */
+ /* 16 bits/pixel */
+ write_reg(par, 0x3A, 0x55);
+
+ /* Frame Rate Control */
+ /* Division ratio = fosc, Frame Rate = 79Hz */
+ write_reg(par, 0xB1, 0x00, 0x18);
+
+ /* Display Function Control */
+ write_reg(par, 0xB6, 0x08, 0x82, 0x27);
+
+ /* Gamma Function Disable */
+ write_reg(par, 0xF2, 0x00);
+
+ /* Gamma curve selected */
+ write_reg(par, 0x26, 0x01);
+
+ /* Positive Gamma Correction */
+ write_reg(par, 0xE0,
+ 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E, 0xF1,
+ 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00);
+
+ /* Negative Gamma Correction */
+ write_reg(par, 0xE1,
+ 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31, 0xC1,
+ 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F);
+
+ /* Sleep OUT */
+ write_reg(par, 0x11);
+
+ mdelay(120);
+
+ /* Display ON */
+ write_reg(par, 0x29);
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address */
+ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+ /* Row adress */
+ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+#define ILI9340_MADCTL_MV 0x20
+#define ILI9340_MADCTL_MX 0x40
+#define ILI9340_MADCTL_MY 0x80
+static int set_var(struct fbtft_par *par)
+{
+ u8 val;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ case 270:
+ val = ILI9340_MADCTL_MV;
+ break;
+ case 180:
+ val = ILI9340_MADCTL_MY;
+ break;
+ case 90:
+ val = ILI9340_MADCTL_MV | ILI9340_MADCTL_MY | ILI9340_MADCTL_MX;
+ break;
+ default:
+ val = ILI9340_MADCTL_MX;
+ break;
+ }
+ /* Memory Access Control */
+ write_reg(par, 0x36, val | (par->bgr << 3));
+
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9340", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9340");
+MODULE_ALIAS("platform:ili9340");
+
+MODULE_DESCRIPTION("FB driver for the ILI9340 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9341.c b/drivers/staging/fbtft/fb_ili9341.c
new file mode 100644
index 000000000000..225b2d84371f
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9341.c
@@ -0,0 +1,179 @@
+/*
+ * FB driver for the ILI9341 LCD display controller
+ *
+ * This display uses 9-bit SPI: Data/Command bit + 8 data bits
+ * For platforms that doesn't support 9-bit, the driver is capable
+ * of emulating this using 8-bit transfer.
+ * This is done by transfering eight 9-bit words in 9 bytes.
+ *
+ * Copyright (C) 2013 Christian Vogelgsang
+ * Based on adafruit22fb.c by Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ili9341"
+#define WIDTH 240
+#define HEIGHT 320
+#define TXBUFLEN (4 * PAGE_SIZE)
+#define DEFAULT_GAMMA "1F 1A 18 0A 0F 06 45 87 32 0A 07 02 07 05 00\n" \
+ "00 25 27 05 10 09 3A 78 4D 05 18 0D 38 3A 1F"
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ /* startup sequence for MI0283QT-9A */
+ write_reg(par, 0x01); /* software reset */
+ mdelay(5);
+ write_reg(par, 0x28); /* display off */
+ /* --------------------------------------------------------- */
+ write_reg(par, 0xCF, 0x00, 0x83, 0x30);
+ write_reg(par, 0xED, 0x64, 0x03, 0x12, 0x81);
+ write_reg(par, 0xE8, 0x85, 0x01, 0x79);
+ write_reg(par, 0xCB, 0x39, 0X2C, 0x00, 0x34, 0x02);
+ write_reg(par, 0xF7, 0x20);
+ write_reg(par, 0xEA, 0x00, 0x00);
+ /* ------------power control-------------------------------- */
+ write_reg(par, 0xC0, 0x26);
+ write_reg(par, 0xC1, 0x11);
+ /* ------------VCOM --------- */
+ write_reg(par, 0xC5, 0x35, 0x3E);
+ write_reg(par, 0xC7, 0xBE);
+ /* ------------memory access control------------------------ */
+ write_reg(par, 0x3A, 0x55); /* 16bit pixel */
+ /* ------------frame rate----------------------------------- */
+ write_reg(par, 0xB1, 0x00, 0x1B);
+ /* ------------Gamma---------------------------------------- */
+ /* write_reg(par, 0xF2, 0x08); */ /* Gamma Function Disable */
+ write_reg(par, 0x26, 0x01);
+ /* ------------display-------------------------------------- */
+ write_reg(par, 0xB7, 0x07); /* entry mode set */
+ write_reg(par, 0xB6, 0x0A, 0x82, 0x27, 0x00);
+ write_reg(par, 0x11); /* sleep out */
+ mdelay(100);
+ write_reg(par, 0x29); /* display on */
+ mdelay(20);
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address set */
+ write_reg(par, 0x2A,
+ (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
+
+ /* Row adress set */
+ write_reg(par, 0x2B,
+ (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+#define MEM_Y (7) /* MY row address order */
+#define MEM_X (6) /* MX column address order */
+#define MEM_V (5) /* MV row / column exchange */
+#define MEM_L (4) /* ML vertical refresh order */
+#define MEM_H (2) /* MH horizontal refresh order */
+#define MEM_BGR (3) /* RGB-BGR Order */
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x36, (1 << MEM_X) | (par->bgr << MEM_BGR));
+ break;
+ case 270:
+ write_reg(par, 0x36,
+ (1<<MEM_V) | (1 << MEM_L) | (par->bgr << MEM_BGR));
+ break;
+ case 180:
+ write_reg(par, 0x36, (1 << MEM_Y) | (par->bgr << MEM_BGR));
+ break;
+ case 90:
+ write_reg(par, 0x36, (1 << MEM_Y) | (1 << MEM_X) |
+ (1 << MEM_V) | (par->bgr << MEM_BGR));
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Gamma string format:
+ Positive: Par1 Par2 [...] Par15
+ Negative: Par1 Par2 [...] Par15
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ int i;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ for (i = 0; i < par->gamma.num_curves; i++)
+ write_reg(par, 0xE0 + i,
+ CURVE(i, 0), CURVE(i, 1), CURVE(i, 2),
+ CURVE(i, 3), CURVE(i, 4), CURVE(i, 5),
+ CURVE(i, 6), CURVE(i, 7), CURVE(i, 8),
+ CURVE(i, 9), CURVE(i, 10), CURVE(i, 11),
+ CURVE(i, 12), CURVE(i, 13), CURVE(i, 14));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .txbuflen = TXBUFLEN,
+ .gamma_num = 2,
+ .gamma_len = 15,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9341", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9341");
+MODULE_ALIAS("platform:ili9341");
+
+MODULE_DESCRIPTION("FB driver for the ILI9341 LCD display controller");
+MODULE_AUTHOR("Christian Vogelgsang");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9481.c b/drivers/staging/fbtft/fb_ili9481.c
new file mode 100644
index 000000000000..725157a1ac41
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9481.c
@@ -0,0 +1,117 @@
+/*
+ * FB driver for the ILI9481 LCD Controller
+ *
+ * Copyright (c) 2014 Petr Olivka
+ * Copyright (c) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ili9481"
+#define WIDTH 320
+#define HEIGHT 480
+
+static int default_init_sequence[] = {
+
+ /* SLP_OUT - Sleep out */
+ -1, 0x11,
+ -2, 50,
+ /* Power setting */
+ -1, 0xD0, 0x07, 0x42, 0x18,
+ /* VCOM */
+ -1, 0xD1, 0x00, 0x07, 0x10,
+ /* Power setting for norm. mode */
+ -1, 0xD2, 0x01, 0x02,
+ /* Panel driving setting */
+ -1, 0xC0, 0x10, 0x3B, 0x00, 0x02, 0x11,
+ /* Frame rate & inv. */
+ -1, 0xC5, 0x03,
+ /* Pixel format */
+ -1, 0x3A, 0x55,
+ /* Gamma */
+ -1, 0xC8, 0x00, 0x32, 0x36, 0x45, 0x06, 0x16,
+ 0x37, 0x75, 0x77, 0x54, 0x0C, 0x00,
+ /* DISP_ON */
+ -1, 0x29,
+ -3
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* column address */
+ write_reg(par, 0x2a, xs >> 8, xs & 0xff, xe >> 8, xe & 0xff);
+
+ /* row adress */
+ write_reg(par, 0x2b, ys >> 8, ys & 0xff, ye >> 8, ye & 0xff);
+
+ /* memory write */
+ write_reg(par, 0x2c);
+}
+
+#define HFLIP 0x01
+#define VFLIP 0x02
+#define ROWxCOL 0x20
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ case 270:
+ write_reg(par, 0x36, ROWxCOL | HFLIP | VFLIP | (par->bgr << 3));
+ break;
+ case 180:
+ write_reg(par, 0x36, VFLIP | (par->bgr << 3));
+ break;
+ case 90:
+ write_reg(par, 0x36, ROWxCOL | (par->bgr << 3));
+ break;
+ default:
+ write_reg(par, 0x36, HFLIP | (par->bgr << 3));
+ break;
+ }
+
+ return 0;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .init_sequence = default_init_sequence,
+ .fbtftops = {
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9481", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9481");
+MODULE_ALIAS("platform:ili9481");
+
+MODULE_DESCRIPTION("FB driver for the ILI9481 LCD Controller");
+MODULE_AUTHOR("Petr Olivka");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ili9486.c b/drivers/staging/fbtft/fb_ili9486.c
new file mode 100644
index 000000000000..95b89999d32a
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ili9486.c
@@ -0,0 +1,121 @@
+/*
+ * FB driver for the ILI9486 LCD Controller
+ *
+ * Copyright (C) 2014 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ili9486"
+#define WIDTH 320
+#define HEIGHT 480
+
+
+/* this init sequence matches PiScreen */
+static int default_init_sequence[] = {
+ /* Interface Mode Control */
+ -1, 0xb0, 0x0,
+ /* Sleep OUT */
+ -1, 0x11,
+ -2, 250,
+ /* Interface Pixel Format */
+ -1, 0x3A, 0x55,
+ /* Power Control 3 */
+ -1, 0xC2, 0x44,
+ /* VCOM Control 1 */
+ -1, 0xC5, 0x00, 0x00, 0x00, 0x00,
+ /* PGAMCTRL(Positive Gamma Control) */
+ -1, 0xE0, 0x0F, 0x1F, 0x1C, 0x0C, 0x0F, 0x08, 0x48, 0x98,
+ 0x37, 0x0A, 0x13, 0x04, 0x11, 0x0D, 0x00,
+ /* NGAMCTRL(Negative Gamma Control) */
+ -1, 0xE1, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
+ 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00,
+ /* Digital Gamma Control 1 */
+ -1, 0xE2, 0x0F, 0x32, 0x2E, 0x0B, 0x0D, 0x05, 0x47, 0x75,
+ 0x37, 0x06, 0x10, 0x03, 0x24, 0x20, 0x00,
+ /* Sleep OUT */
+ -1, 0x11,
+ /* Display ON */
+ -1, 0x29,
+ /* end marker */
+ -3
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address */
+ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+ /* Row adress */
+ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x36, 0x80 | (par->bgr << 3));
+ break;
+ case 90:
+ write_reg(par, 0x36, 0x20 | (par->bgr << 3));
+ break;
+ case 180:
+ write_reg(par, 0x36, 0x40 | (par->bgr << 3));
+ break;
+ case 270:
+ write_reg(par, 0x36, 0xE0 | (par->bgr << 3));
+ break;
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .init_sequence = default_init_sequence,
+ .fbtftops = {
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "ilitek,ili9486", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ili9486");
+MODULE_ALIAS("platform:ili9486");
+
+MODULE_DESCRIPTION("FB driver for the ILI9486 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_pcd8544.c b/drivers/staging/fbtft/fb_pcd8544.c
new file mode 100644
index 000000000000..8b9ebfb49ef8
--- /dev/null
+++ b/drivers/staging/fbtft/fb_pcd8544.c
@@ -0,0 +1,177 @@
+/*
+ * FB driver for the PCD8544 LCD Controller
+ *
+ * The display is monochrome and the video memory is RGB565.
+ * Any pixel value except 0 turns the pixel on.
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_pcd8544"
+#define WIDTH 84
+#define HEIGHT 48
+#define TXBUFLEN (84*6)
+#define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */
+
+static unsigned tc;
+module_param(tc, uint, 0);
+MODULE_PARM_DESC(tc, "TC[1:0] Temperature coefficient: 0-3 (default: 0)");
+
+static unsigned bs = 4;
+module_param(bs, uint, 0);
+MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ /* Function set */
+ write_reg(par, 0x21); /* 5:1 1
+ 2:0 PD - Powerdown control: chip is active
+ 1:0 V - Entry mode: horizontal addressing
+ 0:1 H - Extended instruction set control: extended
+ */
+
+ /* H=1 Temperature control */
+ write_reg(par, 0x04 | (tc & 0x3)); /*
+ 2:1 1
+ 1:x TC1 - Temperature Coefficient: 0x10
+ 0:x TC0
+ */
+
+ /* H=1 Bias system */
+ write_reg(par, 0x10 | (bs & 0x7)); /*
+ 4:1 1
+ 3:0 0
+ 2:x BS2 - Bias System
+ 1:x BS1
+ 0:x BS0
+ */
+
+ /* Function set */
+ write_reg(par, 0x22); /* 5:1 1
+ 2:0 PD - Powerdown control: chip is active
+ 1:1 V - Entry mode: vertical addressing
+ 0:0 H - Extended instruction set control: basic
+ */
+
+ /* H=0 Display control */
+ write_reg(par, 0x08 | 4); /*
+ 3:1 1
+ 2:1 D - DE: 10=normal mode
+ 1:0 0
+ 0:0 E
+ */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* H=0 Set X address of RAM */
+ write_reg(par, 0x80); /* 7:1 1
+ 6-0: X[6:0] - 0x00
+ */
+
+ /* H=0 Set Y address of RAM */
+ write_reg(par, 0x40); /* 7:0 0
+ 6:1 1
+ 2-0: Y[2:0] - 0x0
+ */
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16 = (u16 *)par->info->screen_base;
+ u8 *buf = par->txbuf.buf;
+ int x, y, i;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ for (x = 0; x < 84; x++) {
+ for (y = 0; y < 6; y++) {
+ *buf = 0x00;
+ for (i = 0; i < 8; i++) {
+ *buf |= (vmem16[(y*8+i)*84+x] ? 1 : 0) << i;
+ }
+ buf++;
+ }
+ }
+
+ /* Write data */
+ gpio_set_value(par->gpio.dc, 1);
+ ret = par->fbtftops.write(par, par->txbuf.buf, 6*84);
+ if (ret < 0)
+ dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret);
+
+ return ret;
+}
+
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ curves[0] &= 0x7F;
+
+ write_reg(par, 0x23); /* turn on extended instruction set */
+ write_reg(par, 0x80 | curves[0]);
+ write_reg(par, 0x22); /* turn off extended instruction set */
+
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .txbuflen = TXBUFLEN,
+ .gamma_num = 1,
+ .gamma_len = 1,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .write_vmem = write_vmem,
+ .set_gamma = set_gamma,
+ },
+ .backlight = 1,
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "philips,pdc8544", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:pdc8544");
+
+MODULE_DESCRIPTION("FB driver for the PCD8544 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ra8875.c b/drivers/staging/fbtft/fb_ra8875.c
new file mode 100644
index 000000000000..c323c06344fd
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ra8875.c
@@ -0,0 +1,331 @@
+/******************************************************************************
+
+ ProjectName: FBTFT driver ***** *****
+ for the RA8875 LCD Controller * * ************
+ * ** ** * *
+ Copyright © by Pf@nne & NOTRO * * * * * **** *
+ * * * * * * *
+ Last modification by: * * * * **** *
+ - Pf@nne (pf@nne-mail.de) * * ***** *
+ * * * *******
+ ***** * *
+ Date : 10.06.2014 * *
+ Version : V1.13 *****
+ Revison : 5
+
+*******************************************************************************
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include <linux/gpio.h>
+#include "fbtft.h"
+
+#define DRVNAME "fb_ra8875"
+
+static int write_spi(struct fbtft_par *par, void *buf, size_t len)
+{
+ struct spi_transfer t = {
+ .tx_buf = buf,
+ .len = len,
+ .speed_hz = 1000000,
+ };
+ struct spi_message m;
+
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ if (!par->spi) {
+ dev_err(par->info->device,
+ "%s: par->spi is unexpectedly NULL\n", __func__);
+ return -1;
+ }
+
+ spi_message_init(&m);
+ if (par->txbuf.dma && buf == par->txbuf.buf) {
+ t.tx_dma = par->txbuf.dma;
+ m.is_dma_mapped = 1;
+ }
+ spi_message_add_tail(&t, &m);
+ return spi_sync(par->spi, &m);
+}
+
+static int init_display(struct fbtft_par *par)
+{
+ gpio_set_value(par->gpio.dc, 1);
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "%s()\n", __func__);
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "display size %dx%d\n", par->info->var.xres, par->info->var.yres);
+
+ par->fbtftops.reset(par);
+
+ if ((par->info->var.xres == 320) && (par->info->var.yres == 240)) {
+ /* PLL clock frequency */
+ write_reg(par, 0x88 , 0x0A);
+ write_reg(par, 0x89 , 0x02);
+ mdelay(10);
+ /* color deep / MCU Interface */
+ write_reg(par, 0x10 , 0x0C);
+ /* pixel clock period */
+ write_reg(par, 0x04 , 0x03);
+ mdelay(1);
+ /* horizontal settings */
+ write_reg(par, 0x14 , 0x27);
+ write_reg(par, 0x15 , 0x00);
+ write_reg(par, 0x16 , 0x05);
+ write_reg(par, 0x17 , 0x04);
+ write_reg(par, 0x18 , 0x03);
+ /* vertical settings */
+ write_reg(par, 0x19 , 0xEF);
+ write_reg(par, 0x1A , 0x00);
+ write_reg(par, 0x1B , 0x05);
+ write_reg(par, 0x1C , 0x00);
+ write_reg(par, 0x1D , 0x0E);
+ write_reg(par, 0x1E , 0x00);
+ write_reg(par, 0x1F , 0x02);
+ } else if ((par->info->var.xres == 480) && (par->info->var.yres == 272)) {
+ /* PLL clock frequency */
+ write_reg(par, 0x88 , 0x0A);
+ write_reg(par, 0x89 , 0x02);
+ mdelay(10);
+ /* color deep / MCU Interface */
+ write_reg(par, 0x10 , 0x0C);
+ /* pixel clock period */
+ write_reg(par, 0x04 , 0x82);
+ mdelay(1);
+ /* horizontal settings */
+ write_reg(par, 0x14 , 0x3B);
+ write_reg(par, 0x15 , 0x00);
+ write_reg(par, 0x16 , 0x01);
+ write_reg(par, 0x17 , 0x00);
+ write_reg(par, 0x18 , 0x05);
+ /* vertical settings */
+ write_reg(par, 0x19 , 0x0F);
+ write_reg(par, 0x1A , 0x01);
+ write_reg(par, 0x1B , 0x02);
+ write_reg(par, 0x1C , 0x00);
+ write_reg(par, 0x1D , 0x07);
+ write_reg(par, 0x1E , 0x00);
+ write_reg(par, 0x1F , 0x09);
+ } else if ((par->info->var.xres == 640) && (par->info->var.yres == 480)) {
+ /* PLL clock frequency */
+ write_reg(par, 0x88 , 0x0B);
+ write_reg(par, 0x89 , 0x02);
+ mdelay(10);
+ /* color deep / MCU Interface */
+ write_reg(par, 0x10 , 0x0C);
+ /* pixel clock period */
+ write_reg(par, 0x04 , 0x01);
+ mdelay(1);
+ /* horizontal settings */
+ write_reg(par, 0x14 , 0x4F);
+ write_reg(par, 0x15 , 0x05);
+ write_reg(par, 0x16 , 0x0F);
+ write_reg(par, 0x17 , 0x01);
+ write_reg(par, 0x18 , 0x00);
+ /* vertical settings */
+ write_reg(par, 0x19 , 0xDF);
+ write_reg(par, 0x1A , 0x01);
+ write_reg(par, 0x1B , 0x0A);
+ write_reg(par, 0x1C , 0x00);
+ write_reg(par, 0x1D , 0x0E);
+ write_reg(par, 0x1E , 0x00);
+ write_reg(par, 0x1F , 0x01);
+ } else if ((par->info->var.xres == 800) && (par->info->var.yres == 480)) {
+ /* PLL clock frequency */
+ write_reg(par, 0x88 , 0x0B);
+ write_reg(par, 0x89 , 0x02);
+ mdelay(10);
+ /* color deep / MCU Interface */
+ write_reg(par, 0x10 , 0x0C);
+ /* pixel clock period */
+ write_reg(par, 0x04 , 0x81);
+ mdelay(1);
+ /* horizontal settings */
+ write_reg(par, 0x14 , 0x63);
+ write_reg(par, 0x15 , 0x03);
+ write_reg(par, 0x16 , 0x03);
+ write_reg(par, 0x17 , 0x02);
+ write_reg(par, 0x18 , 0x00);
+ /* vertical settings */
+ write_reg(par, 0x19 , 0xDF);
+ write_reg(par, 0x1A , 0x01);
+ write_reg(par, 0x1B , 0x14);
+ write_reg(par, 0x1C , 0x00);
+ write_reg(par, 0x1D , 0x06);
+ write_reg(par, 0x1E , 0x00);
+ write_reg(par, 0x1F , 0x01);
+ } else {
+ dev_err(par->info->device, "display size is not supported!!");
+ return -1;
+ }
+
+ /* PWM clock */
+ write_reg(par, 0x8a , 0x81);
+ write_reg(par, 0x8b , 0xFF);
+ mdelay(10);
+
+ /* Display ON */
+ write_reg(par, 0x01 , 0x80);
+ mdelay(10);
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Set_Active_Window */
+ write_reg(par, 0x30 , xs & 0x00FF);
+ write_reg(par, 0x31 , (xs & 0xFF00) >> 8);
+ write_reg(par, 0x32 , ys & 0x00FF);
+ write_reg(par, 0x33 , (ys & 0xFF00) >> 8);
+ write_reg(par, 0x34 , (xs+xe) & 0x00FF);
+ write_reg(par, 0x35 , ((xs+xe) & 0xFF00) >> 8);
+ write_reg(par, 0x36 , (ys+ye) & 0x00FF);
+ write_reg(par, 0x37 , ((ys+ye) & 0xFF00) >> 8);
+
+ /* Set_Memory_Write_Cursor */
+ write_reg(par, 0x46, xs & 0xff);
+ write_reg(par, 0x47, (xs >> 8) & 0x03);
+ write_reg(par, 0x48, ys & 0xff);
+ write_reg(par, 0x49, (ys >> 8) & 0x01);
+
+ write_reg(par, 0x02);
+}
+
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+ va_list args;
+ int i, ret;
+ u8 *buf = (u8 *)par->buf;
+
+ /* slow down spi-speed for writing registers */
+ par->fbtftops.write = write_spi;
+
+ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+ va_start(args, len);
+ for (i = 0; i < len; i++)
+ buf[i] = (u8)va_arg(args, unsigned int);
+ va_end(args);
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device,
+ u8, buf, len, "%s: ", __func__);
+ }
+
+ va_start(args, len);
+ *buf++ = 0x80;
+ *buf = (u8)va_arg(args, unsigned int);
+ ret = par->fbtftops.write(par, par->buf, 2);
+ if (ret < 0) {
+ va_end(args);
+ dev_err(par->info->device, "%s: write() failed and returned %dn",
+ __func__, ret);
+ return;
+ }
+ len--;
+
+ udelay(100);
+
+ if (len) {
+ buf = (u8 *)par->buf;
+ *buf++ = 0x00;
+ i = len;
+ while (i--)
+ *buf++ = (u8)va_arg(args, unsigned int);
+
+ ret = par->fbtftops.write(par, par->buf, len + 1);
+ if (ret < 0) {
+ va_end(args);
+ dev_err(par->info->device, "%s: write() failed and returned %dn",
+ __func__, ret);
+ return;
+ }
+ }
+ va_end(args);
+
+ /* restore user spi-speed */
+ par->fbtftops.write = fbtft_write_spi;
+ udelay(100);
+}
+
+static int write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16;
+ u16 *txbuf16 = (u16 *)par->txbuf.buf;
+ size_t remain;
+ size_t to_copy;
+ size_t tx_array_size;
+ int i;
+ int ret = 0;
+ size_t startbyte_size = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+ __func__, offset, len);
+
+ remain = len / 2;
+ vmem16 = (u16 *)(par->info->screen_base + offset);
+ tx_array_size = par->txbuf.len / 2;
+ txbuf16 = (u16 *)(par->txbuf.buf + 1);
+ tx_array_size -= 2;
+ *(u8 *)(par->txbuf.buf) = 0x00;
+ startbyte_size = 1;
+
+ while (remain) {
+ to_copy = remain > tx_array_size ? tx_array_size : remain;
+ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n",
+ to_copy, remain - to_copy);
+
+ for (i = 0; i < to_copy; i++)
+ txbuf16[i] = cpu_to_be16(vmem16[i]);
+
+ vmem16 = vmem16 + to_copy;
+ ret = par->fbtftops.write(par, par->txbuf.buf,
+ startbyte_size + to_copy * 2);
+ if (ret < 0)
+ return ret;
+ remain -= to_copy;
+ }
+
+ return ret;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .write_register = write_reg8_bus8,
+ .write_vmem = write_vmem16_bus8,
+ .write = write_spi,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "raio,ra8875", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ra8875");
+MODULE_ALIAS("platform:ra8875");
+
+MODULE_DESCRIPTION("FB driver for the RA8875 LCD Controller");
+MODULE_AUTHOR("Pf@nne");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_s6d02a1.c b/drivers/staging/fbtft/fb_s6d02a1.c
new file mode 100644
index 000000000000..e412a42443e5
--- /dev/null
+++ b/drivers/staging/fbtft/fb_s6d02a1.c
@@ -0,0 +1,168 @@
+/*
+ * FB driver for the S6D02A1 LCD Controller
+ *
+ * Based on fb_st7735r.c by Noralf Tronnes
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_s6d02a1"
+
+static int default_init_sequence[] = {
+
+ -1, 0xf0, 0x5a, 0x5a,
+
+ -1, 0xfc, 0x5a, 0x5a,
+
+ -1, 0xfa, 0x02, 0x1f, 0x00, 0x10, 0x22, 0x30, 0x38, 0x3A, 0x3A, 0x3A, 0x3A, 0x3A, 0x3d, 0x02, 0x01,
+
+ -1, 0xfb, 0x21, 0x00, 0x02, 0x04, 0x07, 0x0a, 0x0b, 0x0c, 0x0c, 0x16, 0x1e, 0x30, 0x3f, 0x01, 0x02,
+
+ /* power setting sequence */
+ -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x01, 0x01, 0x00, 0x1f, 0x1f,
+
+ -1, 0xf4, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00,
+
+ -1, 0xf5, 0x00, 0x70, 0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6d, 0x66, 0x06,
+
+ -1, 0xf6, 0x02, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x02, 0x00, 0x06, 0x01, 0x00,
+
+ -1, 0xf2, 0x00, 0x01, 0x03, 0x08, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x04, 0x08, 0x08,
+
+ -1, 0xf8, 0x11,
+
+ -1, 0xf7, 0xc8, 0x20, 0x00, 0x00,
+
+ -1, 0xf3, 0x00, 0x00,
+
+ -1, 0x11,
+ -2, 50,
+
+ -1, 0xf3, 0x00, 0x01,
+ -2, 50,
+ -1, 0xf3, 0x00, 0x03,
+ -2, 50,
+ -1, 0xf3, 0x00, 0x07,
+ -2, 50,
+ -1, 0xf3, 0x00, 0x0f,
+ -2, 50,
+
+ -1, 0xf4, 0x00, 0x04, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00,
+ -2, 50,
+
+ -1, 0xf3, 0x00, 0x1f,
+ -2, 50,
+ -1, 0xf3, 0x00, 0x7f,
+ -2, 50,
+
+ -1, 0xf3, 0x00, 0xff,
+ -2, 50,
+
+ -1, 0xfd, 0x00, 0x00, 0x00, 0x17, 0x10, 0x00, 0x00, 0x01, 0x00, 0x16, 0x16,
+
+ -1, 0xf4, 0x00, 0x09, 0x00, 0x00, 0x00, 0x3f, 0x3f, 0x07, 0x00, 0x3C, 0x36, 0x00, 0x3C, 0x36, 0x00,
+
+ /* initializing sequence */
+
+ -1, 0x36, 0x08,
+
+ -1, 0x35, 0x00,
+
+ -1, 0x3a, 0x05,
+
+ /* gamma setting sequence */
+ -1, 0x26, 0x01, /* preset gamma curves, possible values 0x01, 0x02, 0x04, 0x08 */
+
+ -2, 150,
+ -1, 0x29,
+ -1, 0x2c,
+ /* end marker */
+ -3
+
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address */
+ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+ /* Row adress */
+ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+#define MY (1 << 7)
+#define MX (1 << 6)
+#define MV (1 << 5)
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* MADCTL - Memory data access control
+ RGB/BGR:
+ 1. Mode selection pin SRGB
+ RGB H/W pin for color filter setting: 0=RGB, 1=BGR
+ 2. MADCTL RGB bit
+ RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x36, MX | MY | (par->bgr << 3));
+ break;
+ case 270:
+ write_reg(par, 0x36, MY | MV | (par->bgr << 3));
+ break;
+ case 180:
+ write_reg(par, 0x36, (par->bgr << 3));
+ break;
+ case 90:
+ write_reg(par, 0x36, MX | MV | (par->bgr << 3));
+ break;
+ }
+
+ return 0;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = 128,
+ .height = 160,
+ .init_sequence = default_init_sequence,
+ .fbtftops = {
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d02a1", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:s6d02a1");
+MODULE_ALIAS("platform:s6d02a1");
+
+MODULE_DESCRIPTION("FB driver for the S6D02A1 LCD Controller");
+MODULE_AUTHOR("WOLFGANG BUENING");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_s6d1121.c b/drivers/staging/fbtft/fb_s6d1121.c
new file mode 100644
index 000000000000..1ef8c1ad827e
--- /dev/null
+++ b/drivers/staging/fbtft/fb_s6d1121.c
@@ -0,0 +1,208 @@
+/*
+ * FB driver for the S6D1121 LCD Controller
+ *
+ * Copyright (C) 2013 Roman Rolinsky
+ *
+ * Based on fb_ili9325.c by Noralf Tronnes
+ * Based on ili9325.c by Jeroen Domburg
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_s6d1121"
+#define WIDTH 240
+#define HEIGHT 320
+#define BPP 16
+#define FPS 20
+#define DEFAULT_GAMMA "26 09 24 2C 1F 23 24 25 22 26 25 23 0D 00\n" \
+ "1C 1A 13 1D 0B 11 12 10 13 15 36 19 00 0D"
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ if (par->gpio.cs != -1)
+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+
+ /* Initialization sequence from Lib_UTFT */
+
+ write_reg(par, 0x0011, 0x2004);
+ write_reg(par, 0x0013, 0xCC00);
+ write_reg(par, 0x0015, 0x2600);
+ write_reg(par, 0x0014, 0x252A);
+ write_reg(par, 0x0012, 0x0033);
+ write_reg(par, 0x0013, 0xCC04);
+ write_reg(par, 0x0013, 0xCC06);
+ write_reg(par, 0x0013, 0xCC4F);
+ write_reg(par, 0x0013, 0x674F);
+ write_reg(par, 0x0011, 0x2003);
+ write_reg(par, 0x0016, 0x0007);
+ write_reg(par, 0x0002, 0x0013);
+ write_reg(par, 0x0003, 0x0003);
+ write_reg(par, 0x0001, 0x0127);
+ write_reg(par, 0x0008, 0x0303);
+ write_reg(par, 0x000A, 0x000B);
+ write_reg(par, 0x000B, 0x0003);
+ write_reg(par, 0x000C, 0x0000);
+ write_reg(par, 0x0041, 0x0000);
+ write_reg(par, 0x0050, 0x0000);
+ write_reg(par, 0x0060, 0x0005);
+ write_reg(par, 0x0070, 0x000B);
+ write_reg(par, 0x0071, 0x0000);
+ write_reg(par, 0x0078, 0x0000);
+ write_reg(par, 0x007A, 0x0000);
+ write_reg(par, 0x0079, 0x0007);
+ write_reg(par, 0x0007, 0x0051);
+ write_reg(par, 0x0007, 0x0053);
+ write_reg(par, 0x0079, 0x0000);
+
+ write_reg(par, 0x0022); /* Write Data to GRAM */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+ switch (par->info->var.rotate) {
+ /* R20h = Horizontal GRAM Start Address */
+ /* R21h = Vertical GRAM Start Address */
+ case 0:
+ write_reg(par, 0x0020, xs);
+ write_reg(par, 0x0021, ys);
+ break;
+ case 180:
+ write_reg(par, 0x0020, WIDTH - 1 - xs);
+ write_reg(par, 0x0021, HEIGHT - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x0020, WIDTH - 1 - ys);
+ write_reg(par, 0x0021, xs);
+ break;
+ case 90:
+ write_reg(par, 0x0020, ys);
+ write_reg(par, 0x0021, HEIGHT - 1 - xs);
+ break;
+ }
+ write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ /* AM: GRAM update direction */
+ case 0:
+ write_reg(par, 0x03, 0x0003 | (par->bgr << 12));
+ break;
+ case 180:
+ write_reg(par, 0x03, 0x0000 | (par->bgr << 12));
+ break;
+ case 270:
+ write_reg(par, 0x03, 0x000A | (par->bgr << 12));
+ break;
+ case 90:
+ write_reg(par, 0x03, 0x0009 | (par->bgr << 12));
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Gamma string format:
+ PKP0 PKP1 PKP2 PKP3 PKP4 PKP5 PKP6 PKP7 PKP8 PKP9 PKP10 PKP11 VRP0 VRP1
+ PKN0 PKN1 PKN2 PKN3 PKN4 PKN5 PKN6 PKN7 PRN8 PRN9 PRN10 PRN11 VRN0 VRN1
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long mask[] = {
+ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+ 0b11111, 0b11111,
+ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+ 0b111111, 0b111111, 0b111111, 0b111111, 0b111111, 0b111111,
+ 0b11111, 0b11111 };
+ int i, j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 14; j++)
+ CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+ write_reg(par, 0x0030, CURVE(0, 1) << 8 | CURVE(0, 0));
+ write_reg(par, 0x0031, CURVE(0, 3) << 8 | CURVE(0, 2));
+ write_reg(par, 0x0032, CURVE(0, 5) << 8 | CURVE(0, 3));
+ write_reg(par, 0x0033, CURVE(0, 7) << 8 | CURVE(0, 6));
+ write_reg(par, 0x0034, CURVE(0, 9) << 8 | CURVE(0, 8));
+ write_reg(par, 0x0035, CURVE(0, 11) << 8 | CURVE(0, 10));
+
+ write_reg(par, 0x0036, CURVE(1, 1) << 8 | CURVE(1, 0));
+ write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2));
+ write_reg(par, 0x0038, CURVE(1, 5) << 8 | CURVE(1, 4));
+ write_reg(par, 0x0039, CURVE(1, 7) << 8 | CURVE(1, 6));
+ write_reg(par, 0x003A, CURVE(1, 9) << 8 | CURVE(1, 8));
+ write_reg(par, 0x003B, CURVE(1, 11) << 8 | CURVE(1, 10));
+
+ write_reg(par, 0x003C, CURVE(0, 13) << 8 | CURVE(0, 12));
+ write_reg(par, 0x003D, CURVE(1, 13) << 8 | CURVE(1, 12));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 16,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .bpp = BPP,
+ .fps = FPS,
+ .gamma_num = 2,
+ .gamma_len = 14,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "samsung,s6d1121", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:s6d1121");
+MODULE_ALIAS("platform:s6d1121");
+
+MODULE_DESCRIPTION("FB driver for the S6D1121 LCD Controller");
+MODULE_AUTHOR("Roman Rolinsky");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1289.c b/drivers/staging/fbtft/fb_ssd1289.c
new file mode 100644
index 000000000000..ef46fbca2700
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1289.c
@@ -0,0 +1,206 @@
+/*
+ * FB driver for the SSD1289 LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * Init sequence taken from ITDB02_Graph16.cpp - (C)2010-2011 Henning Karlsen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ssd1289"
+#define WIDTH 240
+#define HEIGHT 320
+#define DEFAULT_GAMMA "02 03 2 5 7 7 4 2 4 2\n" \
+ "02 03 2 5 7 5 4 2 4 2"
+
+static unsigned reg11 = 0x6040;
+module_param(reg11, uint, 0);
+MODULE_PARM_DESC(reg11, "Register 11h value");
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ if (par->gpio.cs != -1)
+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+
+ write_reg(par, 0x00, 0x0001);
+ write_reg(par, 0x03, 0xA8A4);
+ write_reg(par, 0x0C, 0x0000);
+ write_reg(par, 0x0D, 0x080C);
+ write_reg(par, 0x0E, 0x2B00);
+ write_reg(par, 0x1E, 0x00B7);
+ write_reg(par, 0x01,
+ (1 << 13) | (par->bgr << 11) | (1 << 9) | (HEIGHT - 1));
+ write_reg(par, 0x02, 0x0600);
+ write_reg(par, 0x10, 0x0000);
+ write_reg(par, 0x05, 0x0000);
+ write_reg(par, 0x06, 0x0000);
+ write_reg(par, 0x16, 0xEF1C);
+ write_reg(par, 0x17, 0x0003);
+ write_reg(par, 0x07, 0x0233);
+ write_reg(par, 0x0B, 0x0000);
+ write_reg(par, 0x0F, 0x0000);
+ write_reg(par, 0x41, 0x0000);
+ write_reg(par, 0x42, 0x0000);
+ write_reg(par, 0x48, 0x0000);
+ write_reg(par, 0x49, 0x013F);
+ write_reg(par, 0x4A, 0x0000);
+ write_reg(par, 0x4B, 0x0000);
+ write_reg(par, 0x44, 0xEF00);
+ write_reg(par, 0x45, 0x0000);
+ write_reg(par, 0x46, 0x013F);
+ write_reg(par, 0x23, 0x0000);
+ write_reg(par, 0x24, 0x0000);
+ write_reg(par, 0x25, 0x8000);
+ write_reg(par, 0x4f, 0x0000);
+ write_reg(par, 0x4e, 0x0000);
+ write_reg(par, 0x22);
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ switch (par->info->var.rotate) {
+ /* R4Eh - Set GDDRAM X address counter */
+ /* R4Fh - Set GDDRAM Y address counter */
+ case 0:
+ write_reg(par, 0x4e, xs);
+ write_reg(par, 0x4f, ys);
+ break;
+ case 180:
+ write_reg(par, 0x4e, par->info->var.xres - 1 - xs);
+ write_reg(par, 0x4f, par->info->var.yres - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x4e, par->info->var.yres - 1 - ys);
+ write_reg(par, 0x4f, xs);
+ break;
+ case 90:
+ write_reg(par, 0x4e, ys);
+ write_reg(par, 0x4f, par->info->var.xres - 1 - xs);
+ break;
+ }
+
+ /* R22h - RAM data write */
+ write_reg(par, 0x22);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ if (par->fbtftops.init_display != init_display) {
+ /* don't risk messing up register 11h */
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "%s: skipping since custom init_display() is used\n",
+ __func__);
+ return 0;
+ }
+
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x11, reg11 | 0b110000);
+ break;
+ case 270:
+ write_reg(par, 0x11, reg11 | 0b101000);
+ break;
+ case 180:
+ write_reg(par, 0x11, reg11 | 0b000000);
+ break;
+ case 90:
+ write_reg(par, 0x11, reg11 | 0b011000);
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Gamma string format:
+ VRP0 VRP1 PRP0 PRP1 PKP0 PKP1 PKP2 PKP3 PKP4 PKP5
+ VRN0 VRN1 PRN0 PRN1 PKN0 PKN1 PKN2 PKN3 PKN4 PKN5
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long mask[] = {
+ 0b11111, 0b11111, 0b111, 0b111, 0b111,
+ 0b111, 0b111, 0b111, 0b111, 0b111,
+ 0b11111, 0b11111, 0b111, 0b111, 0b111,
+ 0b111, 0b111, 0b111, 0b111, 0b111 };
+ int i, j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < 2; i++)
+ for (j = 0; j < 10; j++)
+ CURVE(i, j) &= mask[i*par->gamma.num_values + j];
+
+ write_reg(par, 0x0030, CURVE(0, 5) << 8 | CURVE(0, 4));
+ write_reg(par, 0x0031, CURVE(0, 7) << 8 | CURVE(0, 6));
+ write_reg(par, 0x0032, CURVE(0, 9) << 8 | CURVE(0, 8));
+ write_reg(par, 0x0033, CURVE(0, 3) << 8 | CURVE(0, 2));
+ write_reg(par, 0x0034, CURVE(1, 5) << 8 | CURVE(1, 4));
+ write_reg(par, 0x0035, CURVE(1, 7) << 8 | CURVE(1, 6));
+ write_reg(par, 0x0036, CURVE(1, 9) << 8 | CURVE(1, 8));
+ write_reg(par, 0x0037, CURVE(1, 3) << 8 | CURVE(1, 2));
+ write_reg(par, 0x003A, CURVE(0, 1) << 8 | CURVE(0, 0));
+ write_reg(par, 0x003B, CURVE(1, 1) << 8 | CURVE(1, 0));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 16,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .gamma_num = 2,
+ .gamma_len = 10,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1289", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1289");
+MODULE_ALIAS("platform:ssd1289");
+
+MODULE_DESCRIPTION("FB driver for the SSD1289 LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1306.c b/drivers/staging/fbtft/fb_ssd1306.c
new file mode 100644
index 000000000000..5ea195b0de1b
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1306.c
@@ -0,0 +1,229 @@
+/*
+ * FB driver for the SSD1306 OLED Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ssd1306"
+#define WIDTH 128
+#define HEIGHT 64
+
+
+/*
+ write_reg() caveat:
+
+ This doesn't work because D/C has to be LOW for both values:
+ write_reg(par, val1, val2);
+
+ Do it like this:
+ write_reg(par, val1);
+ write_reg(par, val2);
+*/
+
+/* Init sequence taken from the Adafruit SSD1306 Arduino library */
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ if (par->gamma.curves[0] == 0) {
+ mutex_lock(&par->gamma.lock);
+ if (par->info->var.yres == 64)
+ par->gamma.curves[0] = 0xCF;
+ else
+ par->gamma.curves[0] = 0x8F;
+ mutex_unlock(&par->gamma.lock);
+ }
+
+ /* Set Display OFF */
+ write_reg(par, 0xAE);
+
+ /* Set Display Clock Divide Ratio/ Oscillator Frequency */
+ write_reg(par, 0xD5);
+ write_reg(par, 0x80);
+
+ /* Set Multiplex Ratio */
+ write_reg(par, 0xA8);
+ if (par->info->var.yres == 64)
+ write_reg(par, 0x3F);
+ else
+ write_reg(par, 0x1F);
+
+ /* Set Display Offset */
+ write_reg(par, 0xD3);
+ write_reg(par, 0x0);
+
+ /* Set Display Start Line */
+ write_reg(par, 0x40 | 0x0);
+
+ /* Charge Pump Setting */
+ write_reg(par, 0x8D);
+ /* A[2] = 1b, Enable charge pump during display on */
+ write_reg(par, 0x14);
+
+ /* Set Memory Addressing Mode */
+ write_reg(par, 0x20);
+ /* Vertical addressing mode */
+ write_reg(par, 0x01);
+
+ /*Set Segment Re-map */
+ /* column address 127 is mapped to SEG0 */
+ write_reg(par, 0xA0 | 0x1);
+
+ /* Set COM Output Scan Direction */
+ /* remapped mode. Scan from COM[N-1] to COM0 */
+ write_reg(par, 0xC8);
+
+ /* Set COM Pins Hardware Configuration */
+ write_reg(par, 0xDA);
+ if (par->info->var.yres == 64)
+ /* A[4]=1b, Alternative COM pin configuration */
+ write_reg(par, 0x12);
+ else
+ /* A[4]=0b, Sequential COM pin configuration */
+ write_reg(par, 0x02);
+
+ /* Set Pre-charge Period */
+ write_reg(par, 0xD9);
+ write_reg(par, 0xF1);
+
+ /* Set VCOMH Deselect Level */
+ write_reg(par, 0xDB);
+ /* according to the datasheet, this value is out of bounds */
+ write_reg(par, 0x40);
+
+ /* Entire Display ON */
+ /* Resume to RAM content display. Output follows RAM content */
+ write_reg(par, 0xA4);
+
+ /* Set Normal Display
+ 0 in RAM: OFF in display panel
+ 1 in RAM: ON in display panel */
+ write_reg(par, 0xA6);
+
+ /* Set Display ON */
+ write_reg(par, 0xAF);
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Set Lower Column Start Address for Page Addressing Mode */
+ write_reg(par, 0x00 | 0x0);
+ /* Set Higher Column Start Address for Page Addressing Mode */
+ write_reg(par, 0x10 | 0x0);
+ /* Set Display Start Line */
+ write_reg(par, 0x40 | 0x0);
+}
+
+static int blank(struct fbtft_par *par, bool on)
+{
+ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
+ __func__, on ? "true" : "false");
+
+ if (on)
+ write_reg(par, 0xAE);
+ else
+ write_reg(par, 0xAF);
+ return 0;
+}
+
+/* Gamma is used to control Contrast */
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ curves[0] &= 0xFF;
+
+ /* Set Contrast Control for BANK0 */
+ write_reg(par, 0x81);
+ write_reg(par, curves[0]);
+
+ return 0;
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16 = (u16 *)par->info->screen_base;
+ u8 *buf = par->txbuf.buf;
+ int x, y, i;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ for (x = 0; x < par->info->var.xres; x++) {
+ for (y = 0; y < par->info->var.yres/8; y++) {
+ *buf = 0x00;
+ for (i = 0; i < 8; i++)
+ *buf |= (vmem16[(y*8+i)*par->info->var.xres+x] ? 1 : 0) << i;
+ buf++;
+ }
+ }
+
+ /* Write data */
+ gpio_set_value(par->gpio.dc, 1);
+ ret = par->fbtftops.write(par, par->txbuf.buf,
+ par->info->var.xres*par->info->var.yres/8);
+ if (ret < 0)
+ dev_err(par->info->device,
+ "%s: write failed and returned: %d\n", __func__, ret);
+
+ return ret;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .gamma_num = 1,
+ .gamma_len = 1,
+ .gamma = "00",
+ .fbtftops = {
+ .write_vmem = write_vmem,
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .blank = blank,
+ .set_gamma = set_gamma,
+ },
+};
+
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1306", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1306");
+MODULE_ALIAS("platform:ssd1306");
+
+MODULE_DESCRIPTION("SSD1306 OLED Driver");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1331.c b/drivers/staging/fbtft/fb_ssd1331.c
new file mode 100644
index 000000000000..da7464f90e37
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1331.c
@@ -0,0 +1,205 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ssd1331"
+#define WIDTH 96
+#define HEIGHT 64
+#define GAMMA_NUM 1
+#define GAMMA_LEN 63
+#define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2" \
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ write_reg(par, 0xae); /* Display Off */
+ write_reg(par, 0xa0, 0x70 | (par->bgr << 2)); /* Set Colour Depth */
+ write_reg(par, 0x72); // RGB colour
+ write_reg(par, 0xa1, 0x00); /* Set Display Start Line */
+ write_reg(par, 0xa2, 0x00); /* Set Display Offset */
+ write_reg(par, 0xa4); /* NORMALDISPLAY */
+ write_reg(par, 0xa8, 0x3f); // Set multiplex
+ write_reg(par, 0xad, 0x8e); // Set master
+ // write_reg(par, 0xb0, 0x0b); // Set power mode
+ write_reg(par, 0xb1, 0x31); // Precharge
+ write_reg(par, 0xb3, 0xf0); // Clock div
+ write_reg(par, 0x8a, 0x64); // Precharge A
+ write_reg(par, 0x8b, 0x78); // Precharge B
+ write_reg(par, 0x8c, 0x64); // Precharge C
+ write_reg(par, 0xbb, 0x3a); // Precharge level
+ write_reg(par, 0xbe, 0x3e); // vcomh
+ write_reg(par, 0x87, 0x06); // Master current
+ write_reg(par, 0x81, 0x91); // Contrast A
+ write_reg(par, 0x82, 0x50); // Contrast B
+ write_reg(par, 0x83, 0x7d); // Contrast C
+ write_reg(par, 0xaf); /* Set Sleep Mode Display On */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ write_reg(par, 0x15, xs, xe);
+ write_reg(par, 0x75, ys, ye);
+}
+
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+ va_list args;
+ int i, ret;
+ u8 *buf = (u8 *)par->buf;
+
+ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+ va_start(args, len);
+ for (i = 0; i < len; i++) {
+ buf[i] = (u8)va_arg(args, unsigned int);
+ }
+ va_end(args);
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, u8, buf, len, "%s: ", __func__);
+ }
+
+ va_start(args, len);
+
+ *buf = (u8)va_arg(args, unsigned int);
+ if (par->gpio.dc != -1)
+ gpio_set_value(par->gpio.dc, 0);
+ ret = par->fbtftops.write(par, par->buf, sizeof(u8));
+ if (ret < 0) {
+ va_end(args);
+ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret);
+ return;
+ }
+ len--;
+
+ if (len) {
+ i = len;
+ while (i--) {
+ *buf++ = (u8)va_arg(args, unsigned int);
+ }
+ ret = par->fbtftops.write(par, par->buf, len * (sizeof(u8)));
+ if (ret < 0) {
+ va_end(args);
+ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret);
+ return;
+ }
+ }
+ if (par->gpio.dc != -1)
+ gpio_set_value(par->gpio.dc, 1);
+ va_end(args);
+}
+
+/*
+ Grayscale Lookup Table
+ GS1 - GS63
+ The driver Gamma curve contains the relative values between the entries
+ in the Lookup table.
+
+ From datasheet:
+ 8.8 Gray Scale Decoder
+
+ there are total 180 Gamma Settings (Setting 0 to Setting 180)
+ available for the Gray Scale table.
+
+ The gray scale is defined in incremental way, with reference
+ to the length of previous table entry:
+ Setting of GS1 has to be >= 0
+ Setting of GS2 has to be > Setting of GS1 +1
+ Setting of GS3 has to be > Setting of GS2 +1
+ :
+ Setting of GS63 has to be > Setting of GS62 +1
+
+
+*/
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long tmp[GAMMA_NUM * GAMMA_LEN];
+ int i, acc = 0;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ for (i = 0; i < 63; i++) {
+ if (i > 0 && curves[i] < 2) {
+ dev_err(par->info->device,
+ "Illegal value in Grayscale Lookup Table at index %d. " \
+ "Must be greater than 1\n", i);
+ return -EINVAL;
+ }
+ acc += curves[i];
+ tmp[i] = acc;
+ if (acc > 180) {
+ dev_err(par->info->device,
+ "Illegal value(s) in Grayscale Lookup Table. " \
+ "At index=%d, the accumulated value has exceeded 180\n", i);
+ return -EINVAL;
+ }
+ }
+
+ write_reg(par, 0xB8,
+ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7],
+ tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15],
+ tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23],
+ tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31],
+ tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39],
+ tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47],
+ tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55],
+ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]);
+
+ return 0;
+}
+
+static int blank(struct fbtft_par *par, bool on)
+{
+ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
+ __func__, on ? "true" : "false");
+ if (on)
+ write_reg(par, 0xAE);
+ else
+ write_reg(par, 0xAF);
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .gamma_num = GAMMA_NUM,
+ .gamma_len = GAMMA_LEN,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .write_register = write_reg8_bus8,
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_gamma = set_gamma,
+ .blank = blank,
+ },
+};
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1331", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1331");
+MODULE_ALIAS("platform:ssd1331");
+
+MODULE_DESCRIPTION("SSD1331 OLED Driver");
+MODULE_AUTHOR("Alec Smecher (adapted from SSD1351 by James Davies)");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_ssd1351.c b/drivers/staging/fbtft/fb_ssd1351.c
new file mode 100644
index 000000000000..062d98660f63
--- /dev/null
+++ b/drivers/staging/fbtft/fb_ssd1351.c
@@ -0,0 +1,258 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_ssd1351"
+#define WIDTH 128
+#define HEIGHT 128
+#define GAMMA_NUM 1
+#define GAMMA_LEN 63
+#define DEFAULT_GAMMA "0 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2" \
+
+static void register_onboard_backlight(struct fbtft_par *par);
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ if (par->pdata
+ && par->pdata->display.backlight == FBTFT_ONBOARD_BACKLIGHT) {
+ /* module uses onboard GPIO for panel power */
+ par->fbtftops.register_backlight = register_onboard_backlight;
+ }
+
+ par->fbtftops.reset(par);
+
+ write_reg(par, 0xfd, 0x12); /* Command Lock */
+ write_reg(par, 0xfd, 0xb1); /* Command Lock */
+ write_reg(par, 0xae); /* Display Off */
+ write_reg(par, 0xb3, 0xf1); /* Front Clock Div */
+ write_reg(par, 0xca, 0x7f); /* Set Mux Ratio */
+ write_reg(par, 0x15, 0x00, 0x7f); /* Set Column Address */
+ write_reg(par, 0x75, 0x00, 0x7f); /* Set Row Address */
+ write_reg(par, 0xa1, 0x00); /* Set Display Start Line */
+ write_reg(par, 0xa2, 0x00); /* Set Display Offset */
+ write_reg(par, 0xb5, 0x00); /* Set GPIO */
+ write_reg(par, 0xab, 0x01); /* Set Function Selection */
+ write_reg(par, 0xb1, 0x32); /* Set Phase Length */
+ write_reg(par, 0xb4, 0xa0, 0xb5, 0x55); /* Set Segment Low Voltage */
+ write_reg(par, 0xbb, 0x17); /* Set Precharge Voltage */
+ write_reg(par, 0xbe, 0x05); /* Set VComH Voltage */
+ write_reg(par, 0xc1, 0xc8, 0x80, 0xc8); /* Set Contrast */
+ write_reg(par, 0xc7, 0x0f); /* Set Master Contrast */
+ write_reg(par, 0xb6, 0x01); /* Set Second Precharge Period */
+ write_reg(par, 0xa6); /* Set Display Mode Reset */
+ write_reg(par, 0xaf); /* Set Sleep Mode Display On */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ write_reg(par, 0x15, xs, xe);
+ write_reg(par, 0x75, ys, ye);
+ write_reg(par, 0x5c);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ unsigned remap;
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ if (par->fbtftops.init_display != init_display) {
+ /* don't risk messing up register A0h */
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "%s: skipping since custom init_display() is used\n",
+ __func__);
+ return 0;
+ }
+
+ remap = 0x60 | (par->bgr << 2); /* Set Colour Depth */
+
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0xA0, remap | 0b00 | 1<<4);
+ break;
+ case 270:
+ write_reg(par, 0xA0, remap | 0b11 | 1<<4);
+ break;
+ case 180:
+ write_reg(par, 0xA0, remap | 0b10);
+ break;
+ case 90:
+ write_reg(par, 0xA0, remap | 0b01);
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Grayscale Lookup Table
+ GS1 - GS63
+ The driver Gamma curve contains the relative values between the entries
+ in the Lookup table.
+
+ From datasheet:
+ 8.8 Gray Scale Decoder
+
+ there are total 180 Gamma Settings (Setting 0 to Setting 180)
+ available for the Gray Scale table.
+
+ The gray scale is defined in incremental way, with reference
+ to the length of previous table entry:
+ Setting of GS1 has to be >= 0
+ Setting of GS2 has to be > Setting of GS1 +1
+ Setting of GS3 has to be > Setting of GS2 +1
+ :
+ Setting of GS63 has to be > Setting of GS62 +1
+
+
+*/
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ unsigned long tmp[GAMMA_NUM * GAMMA_LEN];
+ int i, acc = 0;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ for (i = 0; i < 63; i++) {
+ if (i > 0 && curves[i] < 2) {
+ dev_err(par->info->device,
+ "Illegal value in Grayscale Lookup Table at index %d. " \
+ "Must be greater than 1\n", i);
+ return -EINVAL;
+ }
+ acc += curves[i];
+ tmp[i] = acc;
+ if (acc > 180) {
+ dev_err(par->info->device,
+ "Illegal value(s) in Grayscale Lookup Table. " \
+ "At index=%d, the accumulated value has exceeded 180\n", i);
+ return -EINVAL;
+ }
+ }
+
+ write_reg(par, 0xB8,
+ tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7],
+ tmp[8], tmp[9], tmp[10], tmp[11], tmp[12], tmp[13], tmp[14], tmp[15],
+ tmp[16], tmp[17], tmp[18], tmp[19], tmp[20], tmp[21], tmp[22], tmp[23],
+ tmp[24], tmp[25], tmp[26], tmp[27], tmp[28], tmp[29], tmp[30], tmp[31],
+ tmp[32], tmp[33], tmp[34], tmp[35], tmp[36], tmp[37], tmp[38], tmp[39],
+ tmp[40], tmp[41], tmp[42], tmp[43], tmp[44], tmp[45], tmp[46], tmp[47],
+ tmp[48], tmp[49], tmp[50], tmp[51], tmp[52], tmp[53], tmp[54], tmp[55],
+ tmp[56], tmp[57], tmp[58], tmp[59], tmp[60], tmp[61], tmp[62]);
+
+ return 0;
+}
+
+static int blank(struct fbtft_par *par, bool on)
+{
+ fbtft_par_dbg(DEBUG_BLANK, par, "%s(blank=%s)\n",
+ __func__, on ? "true" : "false");
+ if (on)
+ write_reg(par, 0xAE);
+ else
+ write_reg(par, 0xAF);
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .gamma_num = GAMMA_NUM,
+ .gamma_len = GAMMA_LEN,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ .blank = blank,
+ },
+};
+
+#ifdef CONFIG_FB_BACKLIGHT
+static int update_onboard_backlight(struct backlight_device *bd)
+{
+ struct fbtft_par *par = bl_get_data(bd);
+ bool on;
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+ "%s: power=%d, fb_blank=%d\n",
+ __func__, bd->props.power, bd->props.fb_blank);
+
+ on = (bd->props.power == FB_BLANK_UNBLANK)
+ && (bd->props.fb_blank == FB_BLANK_UNBLANK);
+ /* Onboard backlight connected to GPIO0 on SSD1351, GPIO1 unused */
+ write_reg(par, 0xB5, on ? 0x03 : 0x02);
+
+ return 0;
+}
+
+static void register_onboard_backlight(struct fbtft_par *par)
+{
+ struct backlight_device *bd;
+ struct backlight_properties bl_props = { 0, };
+ struct backlight_ops *bl_ops;
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops),
+ GFP_KERNEL);
+ if (!bl_ops) {
+ dev_err(par->info->device,
+ "%s: could not allocate memory for backlight operations.\n",
+ __func__);
+ return;
+ }
+
+ bl_ops->update_status = update_onboard_backlight;
+ bl_props.type = BACKLIGHT_RAW;
+ bl_props.power = FB_BLANK_POWERDOWN;
+
+ bd = backlight_device_register(dev_driver_string(par->info->device),
+ par->info->device, par, bl_ops, &bl_props);
+ if (IS_ERR(bd)) {
+ dev_err(par->info->device,
+ "cannot register backlight device (%ld)\n",
+ PTR_ERR(bd));
+ return;
+ }
+ par->info->bl_dev = bd;
+
+ if (!par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+}
+#else
+static void register_onboard_backlight(struct fbtft_par *par) { };
+#endif
+
+
+FBTFT_REGISTER_DRIVER(DRVNAME, "solomon,ssd1351", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:ssd1351");
+MODULE_ALIAS("platform:ssd1351");
+
+MODULE_DESCRIPTION("SSD1351 OLED Driver");
+MODULE_AUTHOR("James Davies");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_st7735r.c b/drivers/staging/fbtft/fb_st7735r.c
new file mode 100644
index 000000000000..b63aa38e51cf
--- /dev/null
+++ b/drivers/staging/fbtft/fb_st7735r.c
@@ -0,0 +1,195 @@
+/*
+ * FB driver for the ST7735R LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_st7735r"
+#define DEFAULT_GAMMA "0F 1A 0F 18 2F 28 20 22 1F 1B 23 37 00 07 02 10\n" \
+ "0F 1B 0F 17 33 2C 29 2E 30 30 39 3F 00 07 03 10"
+
+
+static int default_init_sequence[] = {
+ /* SWRESET - Software reset */
+ -1, 0x01,
+ -2, 150, /* delay */
+
+ /* SLPOUT - Sleep out & booster on */
+ -1, 0x11,
+ -2, 500, /* delay */
+
+ /* FRMCTR1 - frame rate control: normal mode
+ frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */
+ -1, 0xB1, 0x01, 0x2C, 0x2D,
+
+ /* FRMCTR2 - frame rate control: idle mode
+ frame rate = fosc / (1 x 2 + 40) * (LINE + 2C + 2D) */
+ -1, 0xB2, 0x01, 0x2C, 0x2D,
+
+ /* FRMCTR3 - frame rate control - partial mode
+ dot inversion mode, line inversion mode */
+ -1, 0xB3, 0x01, 0x2C, 0x2D, 0x01, 0x2C, 0x2D,
+
+ /* INVCTR - display inversion control
+ no inversion */
+ -1, 0xB4, 0x07,
+
+ /* PWCTR1 - Power Control
+ -4.6V, AUTO mode */
+ -1, 0xC0, 0xA2, 0x02, 0x84,
+
+ /* PWCTR2 - Power Control
+ VGH25 = 2.4C VGSEL = -10 VGH = 3 * AVDD */
+ -1, 0xC1, 0xC5,
+
+ /* PWCTR3 - Power Control
+ Opamp current small, Boost frequency */
+ -1, 0xC2, 0x0A, 0x00,
+
+ /* PWCTR4 - Power Control
+ BCLK/2, Opamp current small & Medium low */
+ -1, 0xC3,0x8A,0x2A,
+
+ /* PWCTR5 - Power Control */
+ -1, 0xC4, 0x8A, 0xEE,
+
+ /* VMCTR1 - Power Control */
+ -1, 0xC5, 0x0E,
+
+ /* INVOFF - Display inversion off */
+ -1, 0x20,
+
+ /* COLMOD - Interface pixel format */
+ -1, 0x3A, 0x05,
+
+ /* DISPON - Display On */
+ -1, 0x29,
+ -2, 100, /* delay */
+
+ /* NORON - Partial off (Normal) */
+ -1, 0x13,
+ -2, 10, /* delay */
+
+ /* end marker */
+ -3
+};
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address */
+ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+ /* Row adress */
+ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+#define MY (1 << 7)
+#define MX (1 << 6)
+#define MV (1 << 5)
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* MADCTL - Memory data access control
+ RGB/BGR:
+ 1. Mode selection pin SRGB
+ RGB H/W pin for color filter setting: 0=RGB, 1=BGR
+ 2. MADCTL RGB bit
+ RGB-BGR ORDER color filter panel: 0=RGB, 1=BGR */
+ switch (par->info->var.rotate) {
+ case 0:
+ write_reg(par, 0x36, MX | MY | (par->bgr << 3));
+ break;
+ case 270:
+ write_reg(par, 0x36, MY | MV | (par->bgr << 3));
+ break;
+ case 180:
+ write_reg(par, 0x36, (par->bgr << 3));
+ break;
+ case 90:
+ write_reg(par, 0x36, MX | MV | (par->bgr << 3));
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ Gamma string format:
+ VRF0P VOS0P PK0P PK1P PK2P PK3P PK4P PK5P PK6P PK7P PK8P PK9P SELV0P SELV1P SELV62P SELV63P
+ VRF0N VOS0N PK0N PK1N PK2N PK3N PK4N PK5N PK6N PK7N PK8N PK9N SELV0N SELV1N SELV62N SELV63N
+*/
+#define CURVE(num, idx) curves[num*par->gamma.num_values + idx]
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ int i,j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ for (i = 0; i < par->gamma.num_curves; i++)
+ for (j = 0; j < par->gamma.num_values; j++)
+ CURVE(i,j) &= 0b111111;
+
+ for (i = 0; i < par->gamma.num_curves; i++)
+ write_reg(par, 0xE0 + i,
+ CURVE(i, 0), CURVE(i, 1), CURVE(i, 2), CURVE(i, 3),
+ CURVE(i, 4), CURVE(i, 5), CURVE(i, 6), CURVE(i, 7),
+ CURVE(i, 8), CURVE(i, 9), CURVE(i, 10), CURVE(i, 11),
+ CURVE(i, 12), CURVE(i, 13), CURVE(i, 14), CURVE(i,15));
+
+ return 0;
+}
+#undef CURVE
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = 128,
+ .height = 160,
+ .init_sequence = default_init_sequence,
+ .gamma_num = 2,
+ .gamma_len = 16,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .set_gamma = set_gamma,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "sitronix,st7735r", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:st7735r");
+MODULE_ALIAS("platform:st7735r");
+
+MODULE_DESCRIPTION("FB driver for the ST7735R LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_tinylcd.c b/drivers/staging/fbtft/fb_tinylcd.c
new file mode 100644
index 000000000000..ca98bfb5c7df
--- /dev/null
+++ b/drivers/staging/fbtft/fb_tinylcd.c
@@ -0,0 +1,124 @@
+/*
+ * Custom FB driver for tinylcd.com display
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_tinylcd"
+#define WIDTH 320
+#define HEIGHT 480
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ write_reg(par, 0xB0, 0x80);
+ write_reg(par, 0xC0, 0x0A, 0x0A);
+ write_reg(par, 0xC1, 0x45, 0x07);
+ write_reg(par, 0xC2, 0x33);
+ write_reg(par, 0xC5, 0x00, 0x42, 0x80);
+ write_reg(par, 0xB1, 0xD0, 0x11);
+ write_reg(par, 0xB4, 0x02);
+ write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+ write_reg(par, 0xB7, 0x07);
+ write_reg(par, 0x36, 0x58);
+ write_reg(par, 0xF0, 0x36, 0xA5, 0xD3);
+ write_reg(par, 0xE5, 0x80);
+ write_reg(par, 0xE5, 0x01);
+ write_reg(par, 0xB3, 0x00);
+ write_reg(par, 0xE5, 0x00);
+ write_reg(par, 0xF0, 0x36, 0xA5, 0x53);
+ write_reg(par, 0xE0, 0x00, 0x35, 0x33, 0x00, 0x00, 0x00,
+ 0x00, 0x35, 0x33, 0x00, 0x00, 0x00);
+ write_reg(par, 0x3A, 0x55);
+ write_reg(par, 0x11);
+ udelay(250);
+ write_reg(par, 0x29);
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address */
+ write_reg(par, 0x2A, xs >> 8, xs & 0xFF, xe >> 8, xe & 0xFF);
+
+ /* Row adress */
+ write_reg(par, 0x2B, ys >> 8, ys & 0xFF, ye >> 8, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ case 270:
+ write_reg(par, 0xB6, 0x00, 0x02, 0x3B);
+ write_reg(par, 0x36, 0x28);
+ break;
+ case 180:
+ write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+ write_reg(par, 0x36, 0x58);
+ break;
+ case 90:
+ write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+ write_reg(par, 0x36, 0x38);
+ break;
+ default:
+ write_reg(par, 0xB6, 0x00, 0x22, 0x3B);
+ write_reg(par, 0x36, 0x08);
+ break;
+ }
+
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "neosec,tinylcd", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:tinylcd");
+
+MODULE_DESCRIPTION("Custom FB driver for tinylcd.com display");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_tls8204.c b/drivers/staging/fbtft/fb_tls8204.c
new file mode 100644
index 000000000000..8738c7a7bfda
--- /dev/null
+++ b/drivers/staging/fbtft/fb_tls8204.c
@@ -0,0 +1,176 @@
+/*
+ * FB driver for the TLS8204 LCD Controller
+ *
+ * The display is monochrome and the video memory is RGB565.
+ * Any pixel value except 0 turns the pixel on.
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ * Copyright (C) 2014 Michael Hope (adapted for the TLS8204)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_tls8204"
+#define WIDTH 84
+#define HEIGHT 48
+#define TXBUFLEN WIDTH
+#define DEFAULT_GAMMA "40" /* gamma is used to control contrast in this driver */
+
+static unsigned bs = 4;
+module_param(bs, uint, 0);
+MODULE_PARM_DESC(bs, "BS[2:0] Bias voltage level: 0-7 (default: 4)");
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ /* Enter extended command mode */
+ write_reg(par, 0x21); /* 5:1 1
+ 2:0 PD - Powerdown control: chip is active
+ 1:0 V - Entry mode: horizontal addressing
+ 0:1 H - Extended instruction set control: extended
+ */
+
+ /* H=1 Bias system */
+ write_reg(par, 0x10 | (bs & 0x7)); /*
+ 4:1 1
+ 3:0 0
+ 2:x BS2 - Bias System
+ 1:x BS1
+ 0:x BS0
+ */
+
+ /* Set the address of the first display line. */
+ write_reg(par, 0x04 | (64 >> 6));
+ write_reg(par, 0x40 | (64 & 0x3F));
+
+ /* Enter H=0 standard command mode */
+ write_reg(par, 0x20);
+
+ /* H=0 Display control */
+ write_reg(par, 0x08 | 4); /*
+ 3:1 1
+ 2:1 D - DE: 10=normal mode
+ 1:0 0
+ 0:0 E
+ */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* H=0 Set X address of RAM */
+ write_reg(par, 0x80); /* 7:1 1
+ 6-0: X[6:0] - 0x00
+ */
+
+ /* H=0 Set Y address of RAM */
+ write_reg(par, 0x40); /* 7:0 0
+ 6:1 1
+ 2-0: Y[2:0] - 0x0
+ */
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16 = (u16 *)par->info->screen_base;
+ int x, y, i;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ for (y = 0; y < HEIGHT/8; y++) {
+ u8 *buf = par->txbuf.buf;
+ /* The display is 102x68 but the LCD is 84x48. Set
+ the write pointer at the start of each row. */
+ gpio_set_value(par->gpio.dc, 0);
+ write_reg(par, 0x80 | 0);
+ write_reg(par, 0x40 | y);
+
+ for (x = 0; x < WIDTH; x++) {
+ u8 ch = 0;
+ for (i = 0; i < 8*WIDTH; i += WIDTH) {
+ ch >>= 1;
+ if (vmem16[(y*8*WIDTH)+i+x])
+ ch |= 0x80;
+ }
+ *buf++ = ch;
+ }
+ /* Write the row */
+ gpio_set_value(par->gpio.dc, 1);
+ ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
+ if (ret < 0) {
+ dev_err(par->info->device,
+ "%s: write failed and returned: %d\n", __func__, ret);
+ break;
+ }
+ }
+
+ return ret;
+}
+
+static int set_gamma(struct fbtft_par *par, unsigned long *curves)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* apply mask */
+ curves[0] &= 0x7F;
+
+ write_reg(par, 0x21); /* turn on extended instruction set */
+ write_reg(par, 0x80 | curves[0]);
+ write_reg(par, 0x20); /* turn off extended instruction set */
+
+ return 0;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .txbuflen = TXBUFLEN,
+ .gamma_num = 1,
+ .gamma_len = 1,
+ .gamma = DEFAULT_GAMMA,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .write_vmem = write_vmem,
+ .set_gamma = set_gamma,
+ },
+ .backlight = 1,
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "teralane,tls8204", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:tls8204");
+
+MODULE_DESCRIPTION("FB driver for the TLS8204 LCD Controller");
+MODULE_AUTHOR("Michael Hope");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_uc1701.c b/drivers/staging/fbtft/fb_uc1701.c
new file mode 100644
index 000000000000..d70ac524278c
--- /dev/null
+++ b/drivers/staging/fbtft/fb_uc1701.c
@@ -0,0 +1,210 @@
+/*
+ * FB driver for the UC1701 LCD Controller
+ *
+ * The display is monochrome and the video memory is RGB565.
+ * Any pixel value except 0 turns the pixel on.
+ *
+ * Copyright (C) 2014 Juergen Holzmann
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_uc1701"
+#define WIDTH 102
+#define HEIGHT 64
+#define PAGES (HEIGHT/8)
+
+/* 1: Display on/off */
+#define LCD_DISPLAY_ENABLE 0xAE
+/* 2: display start line set */
+#define LCD_START_LINE 0x40
+/* 3: Page address set (lower 4 bits select one of the pages) */
+#define LCD_PAGE_ADDRESS 0xB0
+/* 4: column address */
+#define LCD_COL_ADDRESS 0x10
+/* 8: select orientation */
+#define LCD_BOTTOMVIEW 0xA0
+/* 9: inverted display */
+#define LCD_DISPLAY_INVERT 0xA6
+/* 10: show memory content or switch all pixels on */
+#define LCD_ALL_PIXEL 0xA4
+/* 11: lcd bias set */
+#define LCD_BIAS 0xA2
+/* 14: Reset Controller */
+#define LCD_RESET_CMD 0xE2
+/* 15: output mode select (turns display upside-down) */
+#define LCD_SCAN_DIR 0xC0
+/* 16: power control set */
+#define LCD_POWER_CONTROL 0x28
+/* 17: voltage regulator resistor ratio set */
+#define LCD_VOLTAGE 0x20
+/* 18: Volume mode set */
+#define LCD_VOLUME_MODE 0x81
+/* 22: NOP command */
+#define LCD_NO_OP 0xE3
+/* 25: advanced program control */
+#define LCD_ADV_PROG_CTRL 0xFA
+/* 25: advanced program control2 */
+#define LCD_ADV_PROG_CTRL2 0x10
+#define LCD_TEMPCOMP_HIGH 0x80
+/* column offset for normal orientation */
+#define SHIFT_ADDR_NORMAL 0
+/* column offset for bottom view orientation */
+#define SHIFT_ADDR_TOPVIEW 30
+
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ /* softreset of LCD */
+ write_reg(par, LCD_RESET_CMD);
+ mdelay(10);
+
+ /* set startpoint */
+ /* LCD_START_LINE | (pos & 0x3F) */
+ write_reg(par, LCD_START_LINE);
+
+ /* select orientation BOTTOMVIEW */
+ write_reg(par, LCD_BOTTOMVIEW | 1);
+ /* output mode select (turns display upside-down) */
+ write_reg(par, LCD_SCAN_DIR | 0x00);
+
+ /* Normal Pixel mode */
+ write_reg(par, LCD_ALL_PIXEL | 0);
+
+ /* positive display */
+ write_reg(par, LCD_DISPLAY_INVERT | 0);
+
+ /* bias 1/9 */
+ write_reg(par, LCD_BIAS | 0);
+
+ /* power control mode: all features on */
+ /* LCD_POWER_CONTROL | (val&0x07) */
+ write_reg(par, LCD_POWER_CONTROL | 0x07);
+
+ /* set voltage regulator R/R */
+ /* LCD_VOLTAGE | (val&0x07) */
+ write_reg(par, LCD_VOLTAGE | 0x07);
+
+ /* volume mode set */
+ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
+ write_reg(par, LCD_VOLUME_MODE);
+ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
+ write_reg(par, 0x09);
+ /* ???? */
+ /* LCD_VOLUME_MODE,val&0x3f,LCD_NO_OP */
+ write_reg(par, LCD_NO_OP);
+
+ /* advanced program control */
+ write_reg(par, LCD_ADV_PROG_CTRL);
+ write_reg(par, LCD_ADV_PROG_CTRL2|LCD_TEMPCOMP_HIGH);
+
+ /* enable display */
+ write_reg(par, LCD_DISPLAY_ENABLE | 1);
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* goto address */
+ /* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+ (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+ write_reg(par, LCD_PAGE_ADDRESS);
+ /* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+ (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+ write_reg(par, 0x00);
+ /* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+ (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+ write_reg(par, LCD_COL_ADDRESS);
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16 = (u16 *)par->info->screen_base;
+ u8 *buf = par->txbuf.buf;
+ int x, y, i;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ for (y = 0; y < PAGES; y++) {
+ buf = par->txbuf.buf;
+ for (x = 0; x < WIDTH; x++) {
+ *buf = 0x00;
+ for (i = 0; i < 8; i++)
+ *buf |= (vmem16[((y*8*WIDTH)+(i*WIDTH))+x] ? 1 : 0) << i;
+ buf++;
+ }
+ /* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+ (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+ write_reg(par, LCD_PAGE_ADDRESS|(u8)y);
+ /* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+ (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+ write_reg(par, 0x00);
+ /* LCD_PAGE_ADDRESS | ((page) & 0x1F),
+ (((col)+SHIFT_ADDR_NORMAL) & 0x0F),
+ LCD_COL_ADDRESS | ((((col)+SHIFT_ADDR_NORMAL)>>4) & 0x0F) */
+ write_reg(par, LCD_COL_ADDRESS);
+ gpio_set_value(par->gpio.dc, 1);
+ ret = par->fbtftops.write(par, par->txbuf.buf, WIDTH);
+ gpio_set_value(par->gpio.dc, 0);
+ }
+
+ if (ret < 0)
+ dev_err(par->info->device, "%s: write failed and returned: %d\n", __func__, ret);
+
+ return ret;
+}
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .write_vmem = write_vmem,
+ },
+ .backlight = 1,
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "UltraChip,uc1701", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("spi:uc1701");
+
+MODULE_DESCRIPTION("FB driver for the UC1701 LCD Controller");
+MODULE_AUTHOR("Juergen Holzmann");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_upd161704.c b/drivers/staging/fbtft/fb_upd161704.c
new file mode 100644
index 000000000000..fff57b330ba2
--- /dev/null
+++ b/drivers/staging/fbtft/fb_upd161704.c
@@ -0,0 +1,206 @@
+/*
+ * FB driver for the uPD161704 LCD Controller
+ *
+ * Copyright (C) 2014 Seong-Woo Kim
+ *
+ * Based on fb_ili9325.c by Noralf Tronnes
+ * Based on ili9325.c by Jeroen Domburg
+ * Init code from UTFT library by Henning Karlsen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_upd161704"
+#define WIDTH 240
+#define HEIGHT 320
+#define BPP 16
+
+static int init_display(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ par->fbtftops.reset(par);
+
+ if (par->gpio.cs != -1)
+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+
+ /* Initialization sequence from Lib_UTFT */
+
+ /* register reset */
+ write_reg(par, 0x0003,0x0001); /* Soft reset */
+
+ /* oscillator start */
+ write_reg(par, 0x003A,0x0001); /*Oscillator 0: stop, 1: operation */
+ udelay(100);
+
+ /* y-setting */
+ write_reg(par, 0x0024,0x007B); /* amplitude setting */
+ udelay(10);
+ write_reg(par, 0x0025,0x003B); /* amplitude setting */
+ write_reg(par, 0x0026,0x0034); /* amplitude setting */
+ udelay(10);
+ write_reg(par, 0x0027,0x0004); /* amplitude setting */
+ write_reg(par, 0x0052,0x0025); /* circuit setting 1 */
+ udelay(10);
+ write_reg(par, 0x0053,0x0033); /* circuit setting 2 */
+ write_reg(par, 0x0061,0x001C); /* adjustment V10 positive polarity */
+ udelay(10);
+ write_reg(par, 0x0062,0x002C); /* adjustment V9 negative polarity */
+ write_reg(par, 0x0063,0x0022); /* adjustment V34 positive polarity */
+ udelay(10);
+ write_reg(par, 0x0064,0x0027); /* adjustment V31 negative polarity */
+ udelay(10);
+ write_reg(par, 0x0065,0x0014); /* adjustment V61 negative polarity */
+ udelay(10);
+ write_reg(par, 0x0066,0x0010); /* adjustment V61 negative polarity */
+
+ /* Basical clock for 1 line (BASECOUNT[7:0]) number specified */
+ write_reg(par, 0x002E,0x002D);
+
+ /* Power supply setting */
+ write_reg(par, 0x0019,0x0000); /* DC/DC output setting */
+ udelay(200);
+ write_reg(par, 0x001A,0x1000); /* DC/DC frequency setting */
+ write_reg(par, 0x001B,0x0023); /* DC/DC rising setting */
+ write_reg(par, 0x001C,0x0C01); /* Regulator voltage setting */
+ write_reg(par, 0x001D,0x0000); /* Regulator current setting */
+ write_reg(par, 0x001E,0x0009); /* VCOM output setting */
+ write_reg(par, 0x001F,0x0035); /* VCOM amplitude setting */
+ write_reg(par, 0x0020,0x0015); /* VCOMM cencter setting */
+ write_reg(par, 0x0018,0x1E7B); /* DC/DC operation setting */
+
+ /* windows setting */
+ write_reg(par, 0x0008,0x0000); /* Minimum X address */
+ write_reg(par, 0x0009,0x00EF); /* Maximum X address */
+ write_reg(par, 0x000a,0x0000); /* Minimum Y address */
+ write_reg(par, 0x000b,0x013F); /* Maximum Y address */
+
+ /* LCD display area setting */
+ write_reg(par, 0x0029,0x0000); /* [LCDSIZE] X MIN. size set */
+ write_reg(par, 0x002A,0x0000); /* [LCDSIZE] Y MIN. size set */
+ write_reg(par, 0x002B,0x00EF); /* [LCDSIZE] X MAX. size set */
+ write_reg(par, 0x002C,0x013F); /* [LCDSIZE] Y MAX. size set */
+
+ /* Gate scan setting */
+ write_reg(par, 0x0032,0x0002);
+
+ /* n line inversion line number */
+ write_reg(par, 0x0033,0x0000);
+
+ /* Line inversion/frame inversion/interlace setting */
+ write_reg(par, 0x0037,0x0000);
+
+ /* Gate scan operation setting register */
+ write_reg(par, 0x003B,0x0001);
+
+ /* Color mode */
+ /*GS = 0: 260-k color (64 gray scale), GS = 1: 8 color (2 gray scale) */
+ write_reg(par, 0x0004,0x0000);
+
+ /* RAM control register */
+ write_reg(par, 0x0005,0x0000); /*Window access 00:Normal, 10:Window */
+
+ /* Display setting register 2 */
+ write_reg(par, 0x0001,0x0000);
+
+ /* display setting */
+ write_reg(par, 0x0000,0x0000); /* display on */
+
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+ switch (par->info->var.rotate) {
+ /* R20h = Horizontal GRAM Start Address */
+ /* R21h = Vertical GRAM Start Address */
+ case 0:
+ write_reg(par, 0x0006, xs);
+ write_reg(par, 0x0007, ys);
+ break;
+ case 180:
+ write_reg(par, 0x0006, WIDTH - 1 - xs);
+ write_reg(par, 0x0007, HEIGHT - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x0006, WIDTH - 1 - ys);
+ write_reg(par, 0x0007, xs);
+ break;
+ case 90:
+ write_reg(par, 0x0006, ys);
+ write_reg(par, 0x0007, HEIGHT - 1 - xs);
+ break;
+ }
+
+ write_reg(par, 0x0e); /* Write Data to GRAM */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ switch (par->info->var.rotate) {
+ /* AM: GRAM update direction */
+ case 0:
+ write_reg(par, 0x01, 0x0000);
+ write_reg(par, 0x05, 0x0000);
+ break;
+ case 180:
+ write_reg(par, 0x01, 0x00C0);
+ write_reg(par, 0x05, 0x0000);
+ break;
+ case 270:
+ write_reg(par, 0x01, 0x0080);
+ write_reg(par, 0x05, 0x0001);
+ break;
+ case 90:
+ write_reg(par, 0x01, 0x0040);
+ write_reg(par, 0x05, 0x0001);
+ break;
+ }
+
+ return 0;
+}
+
+static struct fbtft_display display = {
+ .regwidth = 16,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .fbtftops = {
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "nec,upd161704", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+MODULE_ALIAS("platform:" DRVNAME);
+MODULE_ALIAS("spi:upd161704");
+MODULE_ALIAS("platform:upd161704");
+
+MODULE_DESCRIPTION("FB driver for the uPD161704 LCD Controller");
+MODULE_AUTHOR("Seong-Woo Kim");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fb_watterott.c b/drivers/staging/fbtft/fb_watterott.c
new file mode 100644
index 000000000000..975b579359f3
--- /dev/null
+++ b/drivers/staging/fbtft/fb_watterott.c
@@ -0,0 +1,324 @@
+/*
+ * FB driver for the Watterott LCD Controller
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fb_watterott"
+#define WIDTH 320
+#define HEIGHT 240
+#define FPS 5
+#define TXBUFLEN 1024
+#define DEFAULT_BRIGHTNESS 50
+
+#define CMD_VERSION 0x01
+#define CMD_LCD_LED 0x10
+#define CMD_LCD_RESET 0x11
+#define CMD_LCD_ORIENTATION 0x20
+#define CMD_LCD_DRAWIMAGE 0x27
+#define COLOR_RGB323 8
+#define COLOR_RGB332 9
+#define COLOR_RGB233 10
+#define COLOR_RGB565 16
+
+
+static short mode = 565;
+module_param(mode, short, 0);
+MODULE_PARM_DESC(mode, "RGB color transfer mode: 332, 565 (default)");
+
+static void write_reg8_bus8(struct fbtft_par *par, int len, ...)
+{
+ va_list args;
+ int i, ret;
+ u8 *buf = par->buf;
+
+ va_start(args, len);
+ for (i = 0; i < len; i++)
+ *buf++ = (u8)va_arg(args, unsigned int);
+ va_end(args);
+
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
+ par->info->device, u8, par->buf, len, "%s: ", __func__);
+
+ ret = par->fbtftops.write(par, par->buf, len);
+ if (ret < 0) {
+ dev_err(par->info->device,
+ "%s: write() failed and returned %d\n", __func__, ret);
+ return;
+ }
+}
+
+static int write_vmem(struct fbtft_par *par, size_t offset, size_t len)
+{
+ unsigned start_line, end_line;
+ u16 *vmem16 = (u16 *)(par->info->screen_base + offset);
+ u16 *pos = par->txbuf.buf + 1;
+ u16 *buf16 = par->txbuf.buf + 10;
+ int i, j;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ start_line = offset / par->info->fix.line_length;
+ end_line = start_line + (len / par->info->fix.line_length) - 1;
+
+ /* Set command header. pos: x, y, w, h */
+ ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE;
+ pos[0] = 0;
+ pos[2] = cpu_to_be16(par->info->var.xres);
+ pos[3] = cpu_to_be16(1);
+ ((u8 *)par->txbuf.buf)[9] = COLOR_RGB565;
+
+ for (i = start_line; i <= end_line; i++) {
+ pos[1] = cpu_to_be16(i);
+ for (j = 0; j < par->info->var.xres; j++)
+ buf16[j] = cpu_to_be16(*vmem16++);
+ ret = par->fbtftops.write(par,
+ par->txbuf.buf, 10 + par->info->fix.line_length);
+ if (ret < 0)
+ return ret;
+ udelay(300);
+ }
+
+ return 0;
+}
+
+#define RGB565toRGB323(c) (((c&0xE000)>>8) | ((c&0600)>>6) | ((c&0x001C)>>2))
+#define RGB565toRGB332(c) (((c&0xE000)>>8) | ((c&0700)>>6) | ((c&0x0018)>>3))
+#define RGB565toRGB233(c) (((c&0xC000)>>8) | ((c&0700)>>5) | ((c&0x001C)>>2))
+
+static int write_vmem_8bit(struct fbtft_par *par, size_t offset, size_t len)
+{
+ unsigned start_line, end_line;
+ u16 *vmem16 = (u16 *)(par->info->screen_base + offset);
+ u16 *pos = par->txbuf.buf + 1;
+ u8 *buf8 = par->txbuf.buf + 10;
+ int i, j;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s()\n", __func__);
+
+ start_line = offset / par->info->fix.line_length;
+ end_line = start_line + (len / par->info->fix.line_length) - 1;
+
+ /* Set command header. pos: x, y, w, h */
+ ((u8 *)par->txbuf.buf)[0] = CMD_LCD_DRAWIMAGE;
+ pos[0] = 0;
+ pos[2] = cpu_to_be16(par->info->var.xres);
+ pos[3] = cpu_to_be16(1);
+ ((u8 *)par->txbuf.buf)[9] = COLOR_RGB332;
+
+ for (i = start_line; i <= end_line; i++) {
+ pos[1] = cpu_to_be16(i);
+ for (j = 0; j < par->info->var.xres; j++) {
+ buf8[j] = RGB565toRGB332(*vmem16);
+ vmem16++;
+ }
+ ret = par->fbtftops.write(par,
+ par->txbuf.buf, 10 + par->info->var.xres);
+ if (ret < 0)
+ return ret;
+ udelay(700);
+ }
+
+ return 0;
+}
+
+static unsigned firmware_version(struct fbtft_par *par)
+{
+ u8 rxbuf[4] = {0, };
+
+ write_reg(par, CMD_VERSION);
+ par->fbtftops.read(par, rxbuf, 4);
+ if (rxbuf[1] != '.')
+ return 0;
+
+ return (rxbuf[0] - '0') << 8 | (rxbuf[2] - '0') << 4 | (rxbuf[3] - '0');
+}
+
+static int init_display(struct fbtft_par *par)
+{
+ int ret;
+ unsigned version;
+ u8 save_mode;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* enable SPI interface by having CS and MOSI low during reset */
+ save_mode = par->spi->mode;
+ par->spi->mode |= SPI_CS_HIGH;
+ ret = par->spi->master->setup(par->spi); /* set CS inactive low */
+ if (ret) {
+ dev_err(par->info->device, "Could not set SPI_CS_HIGH\n");
+ return ret;
+ }
+ write_reg(par, 0x00); /* make sure mode is set */
+
+ mdelay(50);
+ par->fbtftops.reset(par);
+ mdelay(1000);
+ par->spi->mode = save_mode;
+ ret = par->spi->master->setup(par->spi);
+ if (ret) {
+ dev_err(par->info->device, "Could not restore SPI mode\n");
+ return ret;
+ }
+ write_reg(par, 0x00);
+
+ version = firmware_version(par);
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "Firmware version: %x.%02x\n",
+ version >> 8, version & 0xFF);
+
+ if (mode == 332)
+ par->fbtftops.write_vmem = write_vmem_8bit;
+ return 0;
+}
+
+static void set_addr_win(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ /* not used on this controller */
+}
+
+static int set_var(struct fbtft_par *par)
+{
+ u8 rotate;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* this controller rotates clock wise */
+ switch (par->info->var.rotate) {
+ case 90:
+ rotate = 27;
+ break;
+ case 180:
+ rotate = 18;
+ break;
+ case 270:
+ rotate = 9;
+ break;
+ default:
+ rotate = 0;
+ }
+ write_reg(par, CMD_LCD_ORIENTATION, rotate);
+
+ return 0;
+}
+
+static int verify_gpios(struct fbtft_par *par)
+{
+ if (par->gpio.reset < 0) {
+ dev_err(par->info->device, "Missing 'reset' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ return 0;
+}
+
+#ifdef CONFIG_FB_BACKLIGHT
+static int backlight_chip_update_status(struct backlight_device *bd)
+{
+ struct fbtft_par *par = bl_get_data(bd);
+ int brightness = bd->props.brightness;
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+ "%s: brightness=%d, power=%d, fb_blank=%d\n",
+ __func__, bd->props.brightness, bd->props.power,
+ bd->props.fb_blank);
+
+ if (bd->props.power != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ if (bd->props.fb_blank != FB_BLANK_UNBLANK)
+ brightness = 0;
+
+ write_reg(par, CMD_LCD_LED, brightness);
+
+ return 0;
+}
+
+static void register_chip_backlight(struct fbtft_par *par)
+{
+ struct backlight_device *bd;
+ struct backlight_properties bl_props = { 0, };
+ struct backlight_ops *bl_ops;
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops),
+ GFP_KERNEL);
+ if (!bl_ops) {
+ dev_err(par->info->device,
+ "%s: could not allocate memory for backlight operations.\n",
+ __func__);
+ return;
+ }
+
+ bl_ops->update_status = backlight_chip_update_status;
+ bl_props.type = BACKLIGHT_RAW;
+ bl_props.power = FB_BLANK_POWERDOWN;
+ bl_props.max_brightness = 100;
+ bl_props.brightness = DEFAULT_BRIGHTNESS;
+
+ bd = backlight_device_register(dev_driver_string(par->info->device),
+ par->info->device, par, bl_ops, &bl_props);
+ if (IS_ERR(bd)) {
+ dev_err(par->info->device,
+ "cannot register backlight device (%ld)\n",
+ PTR_ERR(bd));
+ return;
+ }
+ par->info->bl_dev = bd;
+
+ if (!par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+}
+#else
+#define register_chip_backlight NULL
+#endif
+
+
+static struct fbtft_display display = {
+ .regwidth = 8,
+ .buswidth = 8,
+ .width = WIDTH,
+ .height = HEIGHT,
+ .fps = FPS,
+ .txbuflen = TXBUFLEN,
+ .fbtftops = {
+ .write_register = write_reg8_bus8,
+ .write_vmem = write_vmem,
+ .init_display = init_display,
+ .set_addr_win = set_addr_win,
+ .set_var = set_var,
+ .verify_gpios = verify_gpios,
+ .register_backlight = register_chip_backlight,
+ },
+};
+FBTFT_REGISTER_DRIVER(DRVNAME, "watterott,openlcd", &display);
+
+MODULE_ALIAS("spi:" DRVNAME);
+
+MODULE_DESCRIPTION("FB driver for the Watterott LCD Controller");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fbtft-bus.c b/drivers/staging/fbtft/fbtft-bus.c
new file mode 100644
index 000000000000..b3cddb0b3d69
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-bus.c
@@ -0,0 +1,256 @@
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include "fbtft.h"
+
+
+
+
+/*****************************************************************************
+ *
+ * void (*write_reg)(struct fbtft_par *par, int len, ...);
+ *
+ *****************************************************************************/
+
+#define define_fbtft_write_reg(func, type, modifier) \
+void func(struct fbtft_par *par, int len, ...) \
+{ \
+ va_list args; \
+ int i, ret; \
+ int offset = 0; \
+ type *buf = (type *)par->buf; \
+ \
+ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) { \
+ va_start(args, len); \
+ for (i = 0; i < len; i++) { \
+ buf[i] = (type)va_arg(args, unsigned int); \
+ } \
+ va_end(args); \
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par, par->info->device, type, buf, len, "%s: ", __func__); \
+ } \
+ \
+ va_start(args, len); \
+ \
+ if (par->startbyte) { \
+ *(u8 *)par->buf = par->startbyte; \
+ buf = (type *)(par->buf + 1); \
+ offset = 1; \
+ } \
+ \
+ *buf = modifier((type)va_arg(args, unsigned int)); \
+ if (par->gpio.dc != -1) \
+ gpio_set_value(par->gpio.dc, 0); \
+ ret = par->fbtftops.write(par, par->buf, sizeof(type)+offset); \
+ if (ret < 0) { \
+ va_end(args); \
+ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \
+ return; \
+ } \
+ len--; \
+ \
+ if (par->startbyte) \
+ *(u8 *)par->buf = par->startbyte | 0x2; \
+ \
+ if (len) { \
+ i = len; \
+ while (i--) { \
+ *buf++ = modifier((type)va_arg(args, unsigned int)); \
+ } \
+ if (par->gpio.dc != -1) \
+ gpio_set_value(par->gpio.dc, 1); \
+ ret = par->fbtftops.write(par, par->buf, len * (sizeof(type)+offset)); \
+ if (ret < 0) { \
+ va_end(args); \
+ dev_err(par->info->device, "%s: write() failed and returned %d\n", __func__, ret); \
+ return; \
+ } \
+ } \
+ va_end(args); \
+} \
+EXPORT_SYMBOL(func);
+
+define_fbtft_write_reg(fbtft_write_reg8_bus8, u8, )
+define_fbtft_write_reg(fbtft_write_reg16_bus8, u16, cpu_to_be16)
+define_fbtft_write_reg(fbtft_write_reg16_bus16, u16, )
+
+void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...)
+{
+ va_list args;
+ int i, ret;
+ int pad = 0;
+ u16 *buf = (u16 *)par->buf;
+
+ if (unlikely(par->debug & DEBUG_WRITE_REGISTER)) {
+ va_start(args, len);
+ for (i = 0; i < len; i++)
+ *(((u8 *)buf) + i) = (u8)va_arg(args, unsigned int);
+ va_end(args);
+ fbtft_par_dbg_hex(DEBUG_WRITE_REGISTER, par,
+ par->info->device, u8, buf, len, "%s: ", __func__);
+ }
+ if (len <= 0)
+ return;
+
+ if (par->spi && (par->spi->bits_per_word == 8)) {
+ /* we're emulating 9-bit, pad start of buffer with no-ops
+ (assuming here that zero is a no-op) */
+ pad = (len % 4) ? 4 - (len % 4) : 0;
+ for (i = 0; i < pad; i++)
+ *buf++ = 0x000;
+ }
+
+ va_start(args, len);
+ *buf++ = (u8)va_arg(args, unsigned int);
+ i = len - 1;
+ while (i--) {
+ *buf = (u8)va_arg(args, unsigned int);
+ *buf++ |= 0x100; /* dc=1 */
+ }
+ va_end(args);
+ ret = par->fbtftops.write(par, par->buf, (len + pad) * sizeof(u16));
+ if (ret < 0) {
+ dev_err(par->info->device,
+ "%s: write() failed and returned %d\n", __func__, ret);
+ return;
+ }
+}
+EXPORT_SYMBOL(fbtft_write_reg8_bus9);
+
+
+
+
+/*****************************************************************************
+ *
+ * int (*write_vmem)(struct fbtft_par *par);
+ *
+ *****************************************************************************/
+
+/* 16 bit pixel over 8-bit databus */
+int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16;
+ u16 *txbuf16 = (u16 *)par->txbuf.buf;
+ size_t remain;
+ size_t to_copy;
+ size_t tx_array_size;
+ int i;
+ int ret = 0;
+ size_t startbyte_size = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+ __func__, offset, len);
+
+ remain = len / 2;
+ vmem16 = (u16 *)(par->info->screen_base + offset);
+
+ if (par->gpio.dc != -1)
+ gpio_set_value(par->gpio.dc, 1);
+
+ /* non buffered write */
+ if (!par->txbuf.buf)
+ return par->fbtftops.write(par, vmem16, len);
+
+ /* buffered write */
+ tx_array_size = par->txbuf.len / 2;
+
+ if (par->startbyte) {
+ txbuf16 = (u16 *)(par->txbuf.buf + 1);
+ tx_array_size -= 2;
+ *(u8 *)(par->txbuf.buf) = par->startbyte | 0x2;
+ startbyte_size = 1;
+ }
+
+ while (remain) {
+ to_copy = remain > tx_array_size ? tx_array_size : remain;
+ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n",
+ to_copy, remain - to_copy);
+
+ for (i = 0; i < to_copy; i++)
+ txbuf16[i] = cpu_to_be16(vmem16[i]);
+
+ vmem16 = vmem16 + to_copy;
+ ret = par->fbtftops.write(par, par->txbuf.buf,
+ startbyte_size + to_copy * 2);
+ if (ret < 0)
+ return ret;
+ remain -= to_copy;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(fbtft_write_vmem16_bus8);
+
+/* 16 bit pixel over 9-bit SPI bus: dc + high byte, dc + low byte */
+int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u8 *vmem8;
+ u16 *txbuf16 = par->txbuf.buf;
+ size_t remain;
+ size_t to_copy;
+ size_t tx_array_size;
+ int i;
+ int ret = 0;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+ __func__, offset, len);
+
+ if (!par->txbuf.buf) {
+ dev_err(par->info->device, "%s: txbuf.buf is NULL\n", __func__);
+ return -1;
+ }
+
+ remain = len;
+ vmem8 = par->info->screen_base + offset;
+
+ tx_array_size = par->txbuf.len / 2;
+
+ while (remain) {
+ to_copy = remain > tx_array_size ? tx_array_size : remain;
+ dev_dbg(par->info->device, " to_copy=%zu, remain=%zu\n",
+ to_copy, remain - to_copy);
+
+#ifdef __LITTLE_ENDIAN
+ for (i = 0; i < to_copy; i += 2) {
+ txbuf16[i] = 0x0100 | vmem8[i+1];
+ txbuf16[i+1] = 0x0100 | vmem8[i];
+ }
+#else
+ for (i = 0; i < to_copy; i++)
+ txbuf16[i] = 0x0100 | vmem8[i];
+#endif
+ vmem8 = vmem8 + to_copy;
+ ret = par->fbtftops.write(par, par->txbuf.buf, to_copy*2);
+ if (ret < 0)
+ return ret;
+ remain -= to_copy;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(fbtft_write_vmem16_bus9);
+
+int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len)
+{
+ dev_err(par->info->device, "%s: function not implemented\n", __func__);
+ return -1;
+}
+EXPORT_SYMBOL(fbtft_write_vmem8_bus8);
+
+/* 16 bit pixel over 16-bit databus */
+int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len)
+{
+ u16 *vmem16;
+
+ fbtft_par_dbg(DEBUG_WRITE_VMEM, par, "%s(offset=%zu, len=%zu)\n",
+ __func__, offset, len);
+
+ vmem16 = (u16 *)(par->info->screen_base + offset);
+
+ if (par->gpio.dc != -1)
+ gpio_set_value(par->gpio.dc, 1);
+
+ /* no need for buffered write with 16-bit bus */
+ return par->fbtftops.write(par, vmem16, len);
+}
+EXPORT_SYMBOL(fbtft_write_vmem16_bus16);
diff --git a/drivers/staging/fbtft/fbtft-core.c b/drivers/staging/fbtft/fbtft-core.c
new file mode 100644
index 000000000000..37dcf7eb191a
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-core.c
@@ -0,0 +1,1521 @@
+/*
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This driver is inspired by:
+ * st7735fb.c, Copyright (C) 2011, Matt Porter
+ * broadsheetfb.c, Copyright (C) 2008, Jaya Kumar
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/fb.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+#include <linux/uaccess.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/dma-mapping.h>
+#include <linux/of.h>
+#include <linux/of_gpio.h>
+
+#include "fbtft.h"
+
+extern void fbtft_sysfs_init(struct fbtft_par *par);
+extern void fbtft_sysfs_exit(struct fbtft_par *par);
+extern void fbtft_expand_debug_value(unsigned long *debug);
+extern int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves,
+ const char *str, int size);
+
+static unsigned long debug;
+module_param(debug, ulong , 0);
+MODULE_PARM_DESC(debug, "override device debug level");
+
+static bool dma = true;
+module_param(dma, bool, 0);
+MODULE_PARM_DESC(dma, "Use DMA buffer");
+
+
+void fbtft_dbg_hex(const struct device *dev, int groupsize,
+ void *buf, size_t len, const char *fmt, ...)
+{
+ va_list args;
+ static char textbuf[512];
+ char *text = textbuf;
+ size_t text_len;
+
+ va_start(args, fmt);
+ text_len = vscnprintf(text, sizeof(textbuf), fmt, args);
+ va_end(args);
+
+ hex_dump_to_buffer(buf, len, 32, groupsize, text + text_len,
+ 512 - text_len, false);
+
+ if (len > 32)
+ dev_info(dev, "%s ...\n", text);
+ else
+ dev_info(dev, "%s\n", text);
+}
+EXPORT_SYMBOL(fbtft_dbg_hex);
+
+static unsigned long fbtft_request_gpios_match(struct fbtft_par *par,
+ const struct fbtft_gpio *gpio)
+{
+ int ret;
+ long val;
+
+ fbtft_par_dbg(DEBUG_REQUEST_GPIOS_MATCH, par, "%s('%s')\n",
+ __func__, gpio->name);
+
+ if (strcasecmp(gpio->name, "reset") == 0) {
+ par->gpio.reset = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ } else if (strcasecmp(gpio->name, "dc") == 0) {
+ par->gpio.dc = gpio->gpio;
+ return GPIOF_OUT_INIT_LOW;
+ } else if (strcasecmp(gpio->name, "cs") == 0) {
+ par->gpio.cs = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ } else if (strcasecmp(gpio->name, "wr") == 0) {
+ par->gpio.wr = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ } else if (strcasecmp(gpio->name, "rd") == 0) {
+ par->gpio.rd = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ } else if (strcasecmp(gpio->name, "latch") == 0) {
+ par->gpio.latch = gpio->gpio;
+ return GPIOF_OUT_INIT_LOW;
+ } else if (gpio->name[0] == 'd' && gpio->name[1] == 'b') {
+ ret = kstrtol(&gpio->name[2], 10, &val);
+ if (ret == 0 && val < 16) {
+ par->gpio.db[val] = gpio->gpio;
+ return GPIOF_OUT_INIT_LOW;
+ }
+ } else if (strcasecmp(gpio->name, "led") == 0) {
+ par->gpio.led[0] = gpio->gpio;
+ return GPIOF_OUT_INIT_LOW;
+ } else if (strcasecmp(gpio->name, "led_") == 0) {
+ par->gpio.led[0] = gpio->gpio;
+ return GPIOF_OUT_INIT_HIGH;
+ }
+
+ return FBTFT_GPIO_NO_MATCH;
+}
+
+static int fbtft_request_gpios(struct fbtft_par *par)
+{
+ struct fbtft_platform_data *pdata = par->pdata;
+ const struct fbtft_gpio *gpio;
+ unsigned long flags;
+ int ret;
+
+ if (pdata && pdata->gpios) {
+ gpio = pdata->gpios;
+ while (gpio->name[0]) {
+ flags = FBTFT_GPIO_NO_MATCH;
+ /* if driver provides match function, try it first,
+ if no match use our own */
+ if (par->fbtftops.request_gpios_match)
+ flags = par->fbtftops.request_gpios_match(par, gpio);
+ if (flags == FBTFT_GPIO_NO_MATCH)
+ flags = fbtft_request_gpios_match(par, gpio);
+ if (flags != FBTFT_GPIO_NO_MATCH) {
+ ret = devm_gpio_request_one(par->info->device,
+ gpio->gpio, flags,
+ par->info->device->driver->name);
+ if (ret < 0) {
+ dev_err(par->info->device,
+ "%s: gpio_request_one('%s'=%d) failed with %d\n",
+ __func__, gpio->name,
+ gpio->gpio, ret);
+ return ret;
+ }
+ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par,
+ "%s: '%s' = GPIO%d\n",
+ __func__, gpio->name, gpio->gpio);
+ }
+ gpio++;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static int fbtft_request_one_gpio(struct fbtft_par *par,
+ const char *name, int index, int *gpiop)
+{
+ struct device *dev = par->info->device;
+ struct device_node *node = dev->of_node;
+ int gpio, flags, ret = 0;
+ enum of_gpio_flags of_flags;
+
+ if (of_find_property(node, name, NULL)) {
+ gpio = of_get_named_gpio_flags(node, name, index, &of_flags);
+ if (gpio == -ENOENT)
+ return 0;
+ if (gpio == -EPROBE_DEFER)
+ return gpio;
+ if (gpio < 0) {
+ dev_err(dev,
+ "failed to get '%s' from DT\n", name);
+ return gpio;
+ }
+
+ /* active low translates to initially low */
+ flags = (of_flags & OF_GPIO_ACTIVE_LOW) ? GPIOF_OUT_INIT_LOW :
+ GPIOF_OUT_INIT_HIGH;
+ ret = devm_gpio_request_one(dev, gpio, flags,
+ dev->driver->name);
+ if (ret) {
+ dev_err(dev,
+ "gpio_request_one('%s'=%d) failed with %d\n",
+ name, gpio, ret);
+ return ret;
+ }
+ if (gpiop)
+ *gpiop = gpio;
+ fbtft_par_dbg(DEBUG_REQUEST_GPIOS, par, "%s: '%s' = GPIO%d\n",
+ __func__, name, gpio);
+ }
+
+ return ret;
+}
+
+static int fbtft_request_gpios_dt(struct fbtft_par *par)
+{
+ int i;
+ int ret;
+
+ if (!par->info->device->of_node)
+ return -EINVAL;
+
+ ret = fbtft_request_one_gpio(par, "reset-gpios", 0, &par->gpio.reset);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "dc-gpios", 0, &par->gpio.dc);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "rd-gpios", 0, &par->gpio.rd);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "wr-gpios", 0, &par->gpio.wr);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "cs-gpios", 0, &par->gpio.cs);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "latch-gpios", 0, &par->gpio.latch);
+ if (ret)
+ return ret;
+ for (i = 0; i < 16; i++) {
+ ret = fbtft_request_one_gpio(par, "db-gpios", i,
+ &par->gpio.db[i]);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "led-gpios", i,
+ &par->gpio.led[i]);
+ if (ret)
+ return ret;
+ ret = fbtft_request_one_gpio(par, "aux-gpios", i,
+ &par->gpio.aux[i]);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_FB_BACKLIGHT
+static int fbtft_backlight_update_status(struct backlight_device *bd)
+{
+ struct fbtft_par *par = bl_get_data(bd);
+ bool polarity = !!(bd->props.state & BL_CORE_DRIVER1);
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+ "%s: polarity=%d, power=%d, fb_blank=%d\n",
+ __func__, polarity, bd->props.power, bd->props.fb_blank);
+
+ if ((bd->props.power == FB_BLANK_UNBLANK) && (bd->props.fb_blank == FB_BLANK_UNBLANK))
+ gpio_set_value(par->gpio.led[0], polarity);
+ else
+ gpio_set_value(par->gpio.led[0], !polarity);
+
+ return 0;
+}
+
+static int fbtft_backlight_get_brightness(struct backlight_device *bd)
+{
+ return bd->props.brightness;
+}
+
+void fbtft_unregister_backlight(struct fbtft_par *par)
+{
+ const struct backlight_ops *bl_ops;
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+ if (par->info->bl_dev) {
+ par->info->bl_dev->props.power = FB_BLANK_POWERDOWN;
+ backlight_update_status(par->info->bl_dev);
+ bl_ops = par->info->bl_dev->ops;
+ backlight_device_unregister(par->info->bl_dev);
+ par->info->bl_dev = NULL;
+ }
+}
+
+void fbtft_register_backlight(struct fbtft_par *par)
+{
+ struct backlight_device *bd;
+ struct backlight_properties bl_props = { 0, };
+ struct backlight_ops *bl_ops;
+
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par, "%s()\n", __func__);
+
+ if (par->gpio.led[0] == -1) {
+ fbtft_par_dbg(DEBUG_BACKLIGHT, par,
+ "%s(): led pin not set, exiting.\n", __func__);
+ return;
+ }
+
+ bl_ops = devm_kzalloc(par->info->device, sizeof(struct backlight_ops),
+ GFP_KERNEL);
+ if (!bl_ops) {
+ dev_err(par->info->device,
+ "%s: could not allocate memeory for backlight operations.\n",
+ __func__);
+ return;
+ }
+
+ bl_ops->get_brightness = fbtft_backlight_get_brightness;
+ bl_ops->update_status = fbtft_backlight_update_status;
+ bl_props.type = BACKLIGHT_RAW;
+ /* Assume backlight is off, get polarity from current state of pin */
+ bl_props.power = FB_BLANK_POWERDOWN;
+ if (!gpio_get_value(par->gpio.led[0]))
+ bl_props.state |= BL_CORE_DRIVER1;
+
+ bd = backlight_device_register(dev_driver_string(par->info->device),
+ par->info->device, par, bl_ops, &bl_props);
+ if (IS_ERR(bd)) {
+ dev_err(par->info->device,
+ "cannot register backlight device (%ld)\n",
+ PTR_ERR(bd));
+ return;
+ }
+ par->info->bl_dev = bd;
+
+ if (!par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight = fbtft_unregister_backlight;
+}
+#else
+void fbtft_register_backlight(struct fbtft_par *par) { };
+void fbtft_unregister_backlight(struct fbtft_par *par) { };
+#endif
+EXPORT_SYMBOL(fbtft_register_backlight);
+EXPORT_SYMBOL(fbtft_unregister_backlight);
+
+static void fbtft_set_addr_win(struct fbtft_par *par, int xs, int ys, int xe,
+ int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ /* Column address set */
+ write_reg(par, 0x2A,
+ (xs >> 8) & 0xFF, xs & 0xFF, (xe >> 8) & 0xFF, xe & 0xFF);
+
+ /* Row adress set */
+ write_reg(par, 0x2B,
+ (ys >> 8) & 0xFF, ys & 0xFF, (ye >> 8) & 0xFF, ye & 0xFF);
+
+ /* Memory write */
+ write_reg(par, 0x2C);
+}
+
+
+static void fbtft_reset(struct fbtft_par *par)
+{
+ if (par->gpio.reset == -1)
+ return;
+ fbtft_par_dbg(DEBUG_RESET, par, "%s()\n", __func__);
+ gpio_set_value(par->gpio.reset, 0);
+ udelay(20);
+ gpio_set_value(par->gpio.reset, 1);
+ mdelay(120);
+}
+
+
+static void fbtft_update_display(struct fbtft_par *par, unsigned start_line,
+ unsigned end_line)
+{
+ size_t offset, len;
+ struct timespec ts_start, ts_end, ts_fps, ts_duration;
+ long fps_ms, fps_us, duration_ms, duration_us;
+ long fps, throughput;
+ bool timeit = false;
+ int ret = 0;
+
+ if (unlikely(par->debug & (DEBUG_TIME_FIRST_UPDATE | DEBUG_TIME_EACH_UPDATE))) {
+ if ((par->debug & DEBUG_TIME_EACH_UPDATE) || \
+ ((par->debug & DEBUG_TIME_FIRST_UPDATE) && !par->first_update_done)) {
+ getnstimeofday(&ts_start);
+ timeit = true;
+ }
+ }
+
+ /* Sanity checks */
+ if (start_line > end_line) {
+ dev_warn(par->info->device,
+ "%s: start_line=%u is larger than end_line=%u. Shouldn't happen, will do full display update\n",
+ __func__, start_line, end_line);
+ start_line = 0;
+ end_line = par->info->var.yres - 1;
+ }
+ if (start_line > par->info->var.yres - 1 || end_line > par->info->var.yres - 1) {
+ dev_warn(par->info->device,
+ "%s: start_line=%u or end_line=%u is larger than max=%d. Shouldn't happen, will do full display update\n",
+ __func__, start_line, end_line, par->info->var.yres - 1);
+ start_line = 0;
+ end_line = par->info->var.yres - 1;
+ }
+
+ fbtft_par_dbg(DEBUG_UPDATE_DISPLAY, par, "%s(start_line=%u, end_line=%u)\n",
+ __func__, start_line, end_line);
+
+ if (par->fbtftops.set_addr_win)
+ par->fbtftops.set_addr_win(par, 0, start_line,
+ par->info->var.xres-1, end_line);
+
+ offset = start_line * par->info->fix.line_length;
+ len = (end_line - start_line + 1) * par->info->fix.line_length;
+ ret = par->fbtftops.write_vmem(par, offset, len);
+ if (ret < 0)
+ dev_err(par->info->device,
+ "%s: write_vmem failed to update display buffer\n",
+ __func__);
+
+ if (unlikely(timeit)) {
+ getnstimeofday(&ts_end);
+ if (par->update_time.tv_nsec == 0 && par->update_time.tv_sec == 0) {
+ par->update_time.tv_sec = ts_start.tv_sec;
+ par->update_time.tv_nsec = ts_start.tv_nsec;
+ }
+ ts_fps = timespec_sub(ts_start, par->update_time);
+ par->update_time.tv_sec = ts_start.tv_sec;
+ par->update_time.tv_nsec = ts_start.tv_nsec;
+ fps_ms = (ts_fps.tv_sec * 1000) + ((ts_fps.tv_nsec / 1000000) % 1000);
+ fps_us = (ts_fps.tv_nsec / 1000) % 1000;
+ fps = fps_ms * 1000 + fps_us;
+ fps = fps ? 1000000 / fps : 0;
+
+ ts_duration = timespec_sub(ts_end, ts_start);
+ duration_ms = (ts_duration.tv_sec * 1000) + ((ts_duration.tv_nsec / 1000000) % 1000);
+ duration_us = (ts_duration.tv_nsec / 1000) % 1000;
+ throughput = duration_ms * 1000 + duration_us;
+ throughput = throughput ? (len * 1000) / throughput : 0;
+ throughput = throughput * 1000 / 1024;
+
+ dev_info(par->info->device,
+ "Display update: %ld kB/s (%ld.%.3ld ms), fps=%ld (%ld.%.3ld ms)\n",
+ throughput, duration_ms, duration_us,
+ fps, fps_ms, fps_us);
+ par->first_update_done = true;
+ }
+}
+
+
+static void fbtft_mkdirty(struct fb_info *info, int y, int height)
+{
+ struct fbtft_par *par = info->par;
+ struct fb_deferred_io *fbdefio = info->fbdefio;
+
+ /* special case, needed ? */
+ if (y == -1) {
+ y = 0;
+ height = info->var.yres - 1;
+ }
+
+ /* Mark display lines/area as dirty */
+ spin_lock(&par->dirty_lock);
+ if (y < par->dirty_lines_start)
+ par->dirty_lines_start = y;
+ if (y + height - 1 > par->dirty_lines_end)
+ par->dirty_lines_end = y + height - 1;
+ spin_unlock(&par->dirty_lock);
+
+ /* Schedule deferred_io to update display (no-op if already on queue)*/
+ schedule_delayed_work(&info->deferred_work, fbdefio->delay);
+}
+
+static void fbtft_deferred_io(struct fb_info *info, struct list_head *pagelist)
+{
+ struct fbtft_par *par = info->par;
+ unsigned dirty_lines_start, dirty_lines_end;
+ struct page *page;
+ unsigned long index;
+ unsigned y_low = 0, y_high = 0;
+ int count = 0;
+
+ spin_lock(&par->dirty_lock);
+ dirty_lines_start = par->dirty_lines_start;
+ dirty_lines_end = par->dirty_lines_end;
+ /* set display line markers as clean */
+ par->dirty_lines_start = par->info->var.yres - 1;
+ par->dirty_lines_end = 0;
+ spin_unlock(&par->dirty_lock);
+
+ /* Mark display lines as dirty */
+ list_for_each_entry(page, pagelist, lru) {
+ count++;
+ index = page->index << PAGE_SHIFT;
+ y_low = index / info->fix.line_length;
+ y_high = (index + PAGE_SIZE - 1) / info->fix.line_length;
+ fbtft_dev_dbg(DEBUG_DEFERRED_IO, par, info->device,
+ "page->index=%lu y_low=%d y_high=%d\n",
+ page->index, y_low, y_high);
+ if (y_high > info->var.yres - 1)
+ y_high = info->var.yres - 1;
+ if (y_low < dirty_lines_start)
+ dirty_lines_start = y_low;
+ if (y_high > dirty_lines_end)
+ dirty_lines_end = y_high;
+ }
+
+ par->fbtftops.update_display(info->par,
+ dirty_lines_start, dirty_lines_end);
+}
+
+
+static void fbtft_fb_fillrect(struct fb_info *info,
+ const struct fb_fillrect *rect)
+{
+ struct fbtft_par *par = info->par;
+
+ fbtft_dev_dbg(DEBUG_FB_FILLRECT, par, info->dev,
+ "%s: dx=%d, dy=%d, width=%d, height=%d\n",
+ __func__, rect->dx, rect->dy, rect->width, rect->height);
+ sys_fillrect(info, rect);
+
+ par->fbtftops.mkdirty(info, rect->dy, rect->height);
+}
+
+static void fbtft_fb_copyarea(struct fb_info *info,
+ const struct fb_copyarea *area)
+{
+ struct fbtft_par *par = info->par;
+
+ fbtft_dev_dbg(DEBUG_FB_COPYAREA, par, info->dev,
+ "%s: dx=%d, dy=%d, width=%d, height=%d\n",
+ __func__, area->dx, area->dy, area->width, area->height);
+ sys_copyarea(info, area);
+
+ par->fbtftops.mkdirty(info, area->dy, area->height);
+}
+
+static void fbtft_fb_imageblit(struct fb_info *info,
+ const struct fb_image *image)
+{
+ struct fbtft_par *par = info->par;
+
+ fbtft_dev_dbg(DEBUG_FB_IMAGEBLIT, par, info->dev,
+ "%s: dx=%d, dy=%d, width=%d, height=%d\n",
+ __func__, image->dx, image->dy, image->width, image->height);
+ sys_imageblit(info, image);
+
+ par->fbtftops.mkdirty(info, image->dy, image->height);
+}
+
+static ssize_t fbtft_fb_write(struct fb_info *info, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct fbtft_par *par = info->par;
+ ssize_t res;
+
+ fbtft_dev_dbg(DEBUG_FB_WRITE, par, info->dev,
+ "%s: count=%zd, ppos=%llu\n", __func__, count, *ppos);
+ res = fb_sys_write(info, buf, count, ppos);
+
+ /* TODO: only mark changed area
+ update all for now */
+ par->fbtftops.mkdirty(info, -1, 0);
+
+ return res;
+}
+
+/* from pxafb.c */
+static unsigned int chan_to_field(unsigned chan, struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int fbtft_fb_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned transp,
+ struct fb_info *info)
+{
+ struct fbtft_par *par = info->par;
+ unsigned val;
+ int ret = 1;
+
+ fbtft_dev_dbg(DEBUG_FB_SETCOLREG, par, info->dev,
+ "%s(regno=%u, red=0x%X, green=0x%X, blue=0x%X, trans=0x%X)\n",
+ __func__, regno, red, green, blue, transp);
+
+ switch (info->fix.visual) {
+ case FB_VISUAL_TRUECOLOR:
+ if (regno < 16) {
+ u32 *pal = info->pseudo_palette;
+
+ val = chan_to_field(red, &info->var.red);
+ val |= chan_to_field(green, &info->var.green);
+ val |= chan_to_field(blue, &info->var.blue);
+
+ pal[regno] = val;
+ ret = 0;
+ }
+ break;
+
+ }
+ return ret;
+}
+
+static int fbtft_fb_blank(int blank, struct fb_info *info)
+{
+ struct fbtft_par *par = info->par;
+ int ret = -EINVAL;
+
+ fbtft_dev_dbg(DEBUG_FB_BLANK, par, info->dev, "%s(blank=%d)\n",
+ __func__, blank);
+
+ if (!par->fbtftops.blank)
+ return ret;
+
+ switch (blank) {
+ case FB_BLANK_POWERDOWN:
+ case FB_BLANK_VSYNC_SUSPEND:
+ case FB_BLANK_HSYNC_SUSPEND:
+ case FB_BLANK_NORMAL:
+ ret = par->fbtftops.blank(par, true);
+ break;
+ case FB_BLANK_UNBLANK:
+ ret = par->fbtftops.blank(par, false);
+ break;
+ }
+ return ret;
+}
+
+static void fbtft_merge_fbtftops(struct fbtft_ops *dst, struct fbtft_ops *src)
+{
+ if (src->write)
+ dst->write = src->write;
+ if (src->read)
+ dst->read = src->read;
+ if (src->write_vmem)
+ dst->write_vmem = src->write_vmem;
+ if (src->write_register)
+ dst->write_register = src->write_register;
+ if (src->set_addr_win)
+ dst->set_addr_win = src->set_addr_win;
+ if (src->reset)
+ dst->reset = src->reset;
+ if (src->mkdirty)
+ dst->mkdirty = src->mkdirty;
+ if (src->update_display)
+ dst->update_display = src->update_display;
+ if (src->init_display)
+ dst->init_display = src->init_display;
+ if (src->blank)
+ dst->blank = src->blank;
+ if (src->request_gpios_match)
+ dst->request_gpios_match = src->request_gpios_match;
+ if (src->request_gpios)
+ dst->request_gpios = src->request_gpios;
+ if (src->verify_gpios)
+ dst->verify_gpios = src->verify_gpios;
+ if (src->register_backlight)
+ dst->register_backlight = src->register_backlight;
+ if (src->unregister_backlight)
+ dst->unregister_backlight = src->unregister_backlight;
+ if (src->set_var)
+ dst->set_var = src->set_var;
+ if (src->set_gamma)
+ dst->set_gamma = src->set_gamma;
+}
+
+/**
+ * fbtft_framebuffer_alloc - creates a new frame buffer info structure
+ *
+ * @display: pointer to structure describing the display
+ * @dev: pointer to the device for this fb, this can be NULL
+ *
+ * Creates a new frame buffer info structure.
+ *
+ * Also creates and populates the following structures:
+ * info->fbops
+ * info->fbdefio
+ * info->pseudo_palette
+ * par->fbtftops
+ * par->txbuf
+ *
+ * Returns the new structure, or NULL if an error occurred.
+ *
+ */
+struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
+ struct device *dev)
+{
+ struct fb_info *info;
+ struct fbtft_par *par;
+ struct fb_ops *fbops = NULL;
+ struct fb_deferred_io *fbdefio = NULL;
+ struct fbtft_platform_data *pdata = dev->platform_data;
+ u8 *vmem = NULL;
+ void *txbuf = NULL;
+ void *buf = NULL;
+ unsigned width;
+ unsigned height;
+ int txbuflen = display->txbuflen;
+ unsigned bpp = display->bpp;
+ unsigned fps = display->fps;
+ int vmem_size, i;
+ int *init_sequence = display->init_sequence;
+ char *gamma = display->gamma;
+ unsigned long *gamma_curves = NULL;
+
+ /* sanity check */
+ if (display->gamma_num * display->gamma_len > FBTFT_GAMMA_MAX_VALUES_TOTAL) {
+ dev_err(dev,
+ "%s: FBTFT_GAMMA_MAX_VALUES_TOTAL=%d is exceeded\n",
+ __func__, FBTFT_GAMMA_MAX_VALUES_TOTAL);
+ return NULL;
+ }
+
+ /* defaults */
+ if (!fps)
+ fps = 20;
+ if (!bpp)
+ bpp = 16;
+
+ if (!pdata) {
+ dev_err(dev, "platform data is missing\n");
+ return NULL;
+ }
+
+ /* override driver values? */
+ if (pdata->fps)
+ fps = pdata->fps;
+ if (pdata->txbuflen)
+ txbuflen = pdata->txbuflen;
+ if (pdata->display.init_sequence)
+ init_sequence = pdata->display.init_sequence;
+ if (pdata->gamma)
+ gamma = pdata->gamma;
+ if (pdata->display.debug)
+ display->debug = pdata->display.debug;
+ if (pdata->display.backlight)
+ display->backlight = pdata->display.backlight;
+ if (pdata->display.width)
+ display->width = pdata->display.width;
+ if (pdata->display.height)
+ display->height = pdata->display.height;
+ if (pdata->display.buswidth)
+ display->buswidth = pdata->display.buswidth;
+ if (pdata->display.regwidth)
+ display->regwidth = pdata->display.regwidth;
+
+ display->debug |= debug;
+ fbtft_expand_debug_value(&display->debug);
+
+ switch (pdata->rotate) {
+ case 90:
+ case 270:
+ width = display->height;
+ height = display->width;
+ break;
+ default:
+ width = display->width;
+ height = display->height;
+ }
+
+ vmem_size = display->width * display->height * bpp / 8;
+ vmem = vzalloc(vmem_size);
+ if (!vmem)
+ goto alloc_fail;
+
+ fbops = devm_kzalloc(dev, sizeof(struct fb_ops), GFP_KERNEL);
+ if (!fbops)
+ goto alloc_fail;
+
+ fbdefio = devm_kzalloc(dev, sizeof(struct fb_deferred_io), GFP_KERNEL);
+ if (!fbdefio)
+ goto alloc_fail;
+
+ buf = devm_kzalloc(dev, 128, GFP_KERNEL);
+ if (!buf)
+ goto alloc_fail;
+
+ if (display->gamma_num && display->gamma_len) {
+ gamma_curves = devm_kzalloc(dev, display->gamma_num * display->gamma_len * sizeof(gamma_curves[0]),
+ GFP_KERNEL);
+ if (!gamma_curves)
+ goto alloc_fail;
+ }
+
+ info = framebuffer_alloc(sizeof(struct fbtft_par), dev);
+ if (!info)
+ goto alloc_fail;
+
+ info->screen_base = (u8 __force __iomem *)vmem;
+ info->fbops = fbops;
+ info->fbdefio = fbdefio;
+
+ fbops->owner = dev->driver->owner;
+ fbops->fb_read = fb_sys_read;
+ fbops->fb_write = fbtft_fb_write;
+ fbops->fb_fillrect = fbtft_fb_fillrect;
+ fbops->fb_copyarea = fbtft_fb_copyarea;
+ fbops->fb_imageblit = fbtft_fb_imageblit;
+ fbops->fb_setcolreg = fbtft_fb_setcolreg;
+ fbops->fb_blank = fbtft_fb_blank;
+
+ fbdefio->delay = HZ/fps;
+ fbdefio->deferred_io = fbtft_deferred_io;
+ fb_deferred_io_init(info);
+
+ strncpy(info->fix.id, dev->driver->name, 16);
+ info->fix.type = FB_TYPE_PACKED_PIXELS;
+ info->fix.visual = FB_VISUAL_TRUECOLOR;
+ info->fix.xpanstep = 0;
+ info->fix.ypanstep = 0;
+ info->fix.ywrapstep = 0;
+ info->fix.line_length = width*bpp/8;
+ info->fix.accel = FB_ACCEL_NONE;
+ info->fix.smem_len = vmem_size;
+
+ info->var.rotate = pdata->rotate;
+ info->var.xres = width;
+ info->var.yres = height;
+ info->var.xres_virtual = info->var.xres;
+ info->var.yres_virtual = info->var.yres;
+ info->var.bits_per_pixel = bpp;
+ info->var.nonstd = 1;
+
+ /* RGB565 */
+ info->var.red.offset = 11;
+ info->var.red.length = 5;
+ info->var.green.offset = 5;
+ info->var.green.length = 6;
+ info->var.blue.offset = 0;
+ info->var.blue.length = 5;
+ info->var.transp.offset = 0;
+ info->var.transp.length = 0;
+
+ info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
+
+ par = info->par;
+ par->info = info;
+ par->pdata = dev->platform_data;
+ par->debug = display->debug;
+ par->buf = buf;
+ spin_lock_init(&par->dirty_lock);
+ par->bgr = pdata->bgr;
+ par->startbyte = pdata->startbyte;
+ par->init_sequence = init_sequence;
+ par->gamma.curves = gamma_curves;
+ par->gamma.num_curves = display->gamma_num;
+ par->gamma.num_values = display->gamma_len;
+ mutex_init(&par->gamma.lock);
+ info->pseudo_palette = par->pseudo_palette;
+
+ if (par->gamma.curves && gamma) {
+ if (fbtft_gamma_parse_str(par,
+ par->gamma.curves, gamma, strlen(gamma)))
+ goto alloc_fail;
+ }
+
+ /* Transmit buffer */
+ if (txbuflen == -1)
+ txbuflen = vmem_size + 2; /* add in case startbyte is used */
+
+#ifdef __LITTLE_ENDIAN
+ if ((!txbuflen) && (bpp > 8))
+ txbuflen = PAGE_SIZE; /* need buffer for byteswapping */
+#endif
+
+ if (txbuflen > 0) {
+ if (dma) {
+ dev->coherent_dma_mask = ~0;
+ txbuf = dmam_alloc_coherent(dev, txbuflen, &par->txbuf.dma, GFP_DMA);
+ } else {
+ txbuf = devm_kzalloc(par->info->device, txbuflen, GFP_KERNEL);
+ }
+ if (!txbuf)
+ goto alloc_fail;
+ par->txbuf.buf = txbuf;
+ par->txbuf.len = txbuflen;
+ }
+
+ /* Initialize gpios to disabled */
+ par->gpio.reset = -1;
+ par->gpio.dc = -1;
+ par->gpio.rd = -1;
+ par->gpio.wr = -1;
+ par->gpio.cs = -1;
+ par->gpio.latch = -1;
+ for (i = 0; i < 16; i++) {
+ par->gpio.db[i] = -1;
+ par->gpio.led[i] = -1;
+ par->gpio.aux[i] = -1;
+ }
+
+ /* default fbtft operations */
+ par->fbtftops.write = fbtft_write_spi;
+ par->fbtftops.read = fbtft_read_spi;
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+ par->fbtftops.write_register = fbtft_write_reg8_bus8;
+ par->fbtftops.set_addr_win = fbtft_set_addr_win;
+ par->fbtftops.reset = fbtft_reset;
+ par->fbtftops.mkdirty = fbtft_mkdirty;
+ par->fbtftops.update_display = fbtft_update_display;
+ par->fbtftops.request_gpios = fbtft_request_gpios;
+ if (display->backlight)
+ par->fbtftops.register_backlight = fbtft_register_backlight;
+
+ /* use driver provided functions */
+ fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops);
+
+ return info;
+
+alloc_fail:
+ vfree(vmem);
+
+ return NULL;
+}
+EXPORT_SYMBOL(fbtft_framebuffer_alloc);
+
+/**
+ * fbtft_framebuffer_release - frees up all memory used by the framebuffer
+ *
+ * @info: frame buffer info structure
+ *
+ */
+void fbtft_framebuffer_release(struct fb_info *info)
+{
+ fb_deferred_io_cleanup(info);
+ vfree(info->screen_base);
+ framebuffer_release(info);
+}
+EXPORT_SYMBOL(fbtft_framebuffer_release);
+
+/**
+ * fbtft_register_framebuffer - registers a tft frame buffer device
+ * @fb_info: frame buffer info structure
+ *
+ * Sets SPI driverdata if needed
+ * Requests needed gpios.
+ * Initializes display
+ * Updates display.
+ * Registers a frame buffer device @fb_info.
+ *
+ * Returns negative errno on error, or zero for success.
+ *
+ */
+int fbtft_register_framebuffer(struct fb_info *fb_info)
+{
+ int ret;
+ char text1[50] = "";
+ char text2[50] = "";
+ struct fbtft_par *par = fb_info->par;
+ struct spi_device *spi = par->spi;
+
+ /* sanity checks */
+ if (!par->fbtftops.init_display) {
+ dev_err(fb_info->device, "missing fbtftops.init_display()\n");
+ return -EINVAL;
+ }
+
+ if (spi)
+ spi_set_drvdata(spi, fb_info);
+ if (par->pdev)
+ platform_set_drvdata(par->pdev, fb_info);
+
+ ret = par->fbtftops.request_gpios(par);
+ if (ret < 0)
+ goto reg_fail;
+
+ if (par->fbtftops.verify_gpios) {
+ ret = par->fbtftops.verify_gpios(par);
+ if (ret < 0)
+ goto reg_fail;
+ }
+
+ ret = par->fbtftops.init_display(par);
+ if (ret < 0)
+ goto reg_fail;
+ if (par->fbtftops.set_var) {
+ ret = par->fbtftops.set_var(par);
+ if (ret < 0)
+ goto reg_fail;
+ }
+
+ /* update the entire display */
+ par->fbtftops.update_display(par, 0, par->info->var.yres - 1);
+
+ if (par->fbtftops.set_gamma && par->gamma.curves) {
+ ret = par->fbtftops.set_gamma(par, par->gamma.curves);
+ if (ret)
+ goto reg_fail;
+ }
+
+ if (par->fbtftops.register_backlight)
+ par->fbtftops.register_backlight(par);
+
+ ret = register_framebuffer(fb_info);
+ if (ret < 0)
+ goto reg_fail;
+
+ fbtft_sysfs_init(par);
+
+ if (par->txbuf.buf)
+ sprintf(text1, ", %d KiB %sbuffer memory",
+ par->txbuf.len >> 10, par->txbuf.dma ? "DMA " : "");
+ if (spi)
+ sprintf(text2, ", spi%d.%d at %d MHz", spi->master->bus_num,
+ spi->chip_select, spi->max_speed_hz/1000000);
+ dev_info(fb_info->dev,
+ "%s frame buffer, %dx%d, %d KiB video memory%s, fps=%lu%s\n",
+ fb_info->fix.id, fb_info->var.xres, fb_info->var.yres,
+ fb_info->fix.smem_len >> 10, text1,
+ HZ/fb_info->fbdefio->delay, text2);
+
+#ifdef CONFIG_FB_BACKLIGHT
+ /* Turn on backlight if available */
+ if (fb_info->bl_dev) {
+ fb_info->bl_dev->props.power = FB_BLANK_UNBLANK;
+ fb_info->bl_dev->ops->update_status(fb_info->bl_dev);
+ }
+#endif
+
+ return 0;
+
+reg_fail:
+ if (par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight(par);
+ if (spi)
+ spi_set_drvdata(spi, NULL);
+ if (par->pdev)
+ platform_set_drvdata(par->pdev, NULL);
+
+ return ret;
+}
+EXPORT_SYMBOL(fbtft_register_framebuffer);
+
+/**
+ * fbtft_unregister_framebuffer - releases a tft frame buffer device
+ * @fb_info: frame buffer info structure
+ *
+ * Frees SPI driverdata if needed
+ * Frees gpios.
+ * Unregisters frame buffer device.
+ *
+ */
+int fbtft_unregister_framebuffer(struct fb_info *fb_info)
+{
+ struct fbtft_par *par = fb_info->par;
+ struct spi_device *spi = par->spi;
+ int ret;
+
+ if (spi)
+ spi_set_drvdata(spi, NULL);
+ if (par->pdev)
+ platform_set_drvdata(par->pdev, NULL);
+ if (par->fbtftops.unregister_backlight)
+ par->fbtftops.unregister_backlight(par);
+ fbtft_sysfs_exit(par);
+ ret = unregister_framebuffer(fb_info);
+ return ret;
+}
+EXPORT_SYMBOL(fbtft_unregister_framebuffer);
+
+#ifdef CONFIG_OF
+/**
+ * fbtft_init_display_dt() - Device Tree init_display() function
+ * @par: Driver data
+ *
+ * Return: 0 if successful, negative if error
+ */
+static int fbtft_init_display_dt(struct fbtft_par *par)
+{
+ struct device_node *node = par->info->device->of_node;
+ struct property *prop;
+ const __be32 *p;
+ u32 val;
+ int buf[64], i, j;
+ char msg[128];
+ char str[16];
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ if (!node)
+ return -EINVAL;
+
+ prop = of_find_property(node, "init", NULL);
+ p = of_prop_next_u32(prop, NULL, &val);
+ if (!p)
+ return -EINVAL;
+ while (p) {
+ if (val & FBTFT_OF_INIT_CMD) {
+ val &= 0xFFFF;
+ i = 0;
+ while (p && !(val & 0xFFFF0000)) {
+ if (i > 63) {
+ dev_err(par->info->device,
+ "%s: Maximum register values exceeded\n",
+ __func__);
+ return -EINVAL;
+ }
+ buf[i++] = val;
+ p = of_prop_next_u32(prop, p, &val);
+ }
+ /* make debug message */
+ msg[0] = '\0';
+ for (j = 0; j < i; j++) {
+ snprintf(str, 128, " %02X", buf[j]);
+ strcat(msg, str);
+ }
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "init: write_register:%s\n", msg);
+
+ par->fbtftops.write_register(par, i,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7],
+ buf[8], buf[9], buf[10], buf[11],
+ buf[12], buf[13], buf[14], buf[15],
+ buf[16], buf[17], buf[18], buf[19],
+ buf[20], buf[21], buf[22], buf[23],
+ buf[24], buf[25], buf[26], buf[27],
+ buf[28], buf[29], buf[30], buf[31],
+ buf[32], buf[33], buf[34], buf[35],
+ buf[36], buf[37], buf[38], buf[39],
+ buf[40], buf[41], buf[42], buf[43],
+ buf[44], buf[45], buf[46], buf[47],
+ buf[48], buf[49], buf[50], buf[51],
+ buf[52], buf[53], buf[54], buf[55],
+ buf[56], buf[57], buf[58], buf[59],
+ buf[60], buf[61], buf[62], buf[63]);
+ } else if (val & FBTFT_OF_INIT_DELAY) {
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "init: msleep(%u)\n", val & 0xFFFF);
+ msleep(val & 0xFFFF);
+ p = of_prop_next_u32(prop, p, &val);
+ } else {
+ dev_err(par->info->device, "illegal init value 0x%X\n",
+ val);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+/**
+ * fbtft_init_display() - Generic init_display() function
+ * @par: Driver data
+ *
+ * Uses par->init_sequence to do the initialization
+ *
+ * Return: 0 if successful, negative if error
+ */
+int fbtft_init_display(struct fbtft_par *par)
+{
+ int buf[64];
+ char msg[128];
+ char str[16];
+ int i = 0;
+ int j;
+
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par, "%s()\n", __func__);
+
+ /* sanity check */
+ if (!par->init_sequence) {
+ dev_err(par->info->device,
+ "error: init_sequence is not set\n");
+ return -EINVAL;
+ }
+
+ /* make sure stop marker exists */
+ for (i = 0; i < FBTFT_MAX_INIT_SEQUENCE; i++)
+ if (par->init_sequence[i] == -3)
+ break;
+ if (i == FBTFT_MAX_INIT_SEQUENCE) {
+ dev_err(par->info->device,
+ "missing stop marker at end of init sequence\n");
+ return -EINVAL;
+ }
+
+ par->fbtftops.reset(par);
+ if (par->gpio.cs != -1)
+ gpio_set_value(par->gpio.cs, 0); /* Activate chip */
+
+ i = 0;
+ while (i < FBTFT_MAX_INIT_SEQUENCE) {
+ if (par->init_sequence[i] == -3) {
+ /* done */
+ return 0;
+ }
+ if (par->init_sequence[i] >= 0) {
+ dev_err(par->info->device,
+ "missing delimiter at position %d\n", i);
+ return -EINVAL;
+ }
+ if (par->init_sequence[i+1] < 0) {
+ dev_err(par->info->device,
+ "missing value after delimiter %d at position %d\n",
+ par->init_sequence[i], i);
+ return -EINVAL;
+ }
+ switch (par->init_sequence[i]) {
+ case -1:
+ i++;
+ /* make debug message */
+ strcpy(msg, "");
+ j = i + 1;
+ while (par->init_sequence[j] >= 0) {
+ sprintf(str, "0x%02X ", par->init_sequence[j]);
+ strcat(msg, str);
+ j++;
+ }
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "init: write(0x%02X) %s\n",
+ par->init_sequence[i], msg);
+
+ /* Write */
+ j = 0;
+ while (par->init_sequence[i] >= 0) {
+ if (j > 63) {
+ dev_err(par->info->device,
+ "%s: Maximum register values exceeded\n",
+ __func__);
+ return -EINVAL;
+ }
+ buf[j++] = par->init_sequence[i++];
+ }
+ par->fbtftops.write_register(par, j,
+ buf[0], buf[1], buf[2], buf[3],
+ buf[4], buf[5], buf[6], buf[7],
+ buf[8], buf[9], buf[10], buf[11],
+ buf[12], buf[13], buf[14], buf[15],
+ buf[16], buf[17], buf[18], buf[19],
+ buf[20], buf[21], buf[22], buf[23],
+ buf[24], buf[25], buf[26], buf[27],
+ buf[28], buf[29], buf[30], buf[31],
+ buf[32], buf[33], buf[34], buf[35],
+ buf[36], buf[37], buf[38], buf[39],
+ buf[40], buf[41], buf[42], buf[43],
+ buf[44], buf[45], buf[46], buf[47],
+ buf[48], buf[49], buf[50], buf[51],
+ buf[52], buf[53], buf[54], buf[55],
+ buf[56], buf[57], buf[58], buf[59],
+ buf[60], buf[61], buf[62], buf[63]);
+ break;
+ case -2:
+ i++;
+ fbtft_par_dbg(DEBUG_INIT_DISPLAY, par,
+ "init: mdelay(%d)\n", par->init_sequence[i]);
+ mdelay(par->init_sequence[i++]);
+ break;
+ default:
+ dev_err(par->info->device,
+ "unknown delimiter %d at position %d\n",
+ par->init_sequence[i], i);
+ return -EINVAL;
+ }
+ }
+
+ dev_err(par->info->device,
+ "%s: something is wrong. Shouldn't get here.\n", __func__);
+ return -EINVAL;
+}
+EXPORT_SYMBOL(fbtft_init_display);
+
+/**
+ * fbtft_verify_gpios() - Generic verify_gpios() function
+ * @par: Driver data
+ *
+ * Uses @spi, @pdev and @buswidth to determine which GPIOs is needed
+ *
+ * Return: 0 if successful, negative if error
+ */
+static int fbtft_verify_gpios(struct fbtft_par *par)
+{
+ struct fbtft_platform_data *pdata;
+ int i;
+
+ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
+
+ pdata = par->info->device->platform_data;
+ if (pdata->display.buswidth != 9 && par->startbyte == 0 && \
+ par->gpio.dc < 0) {
+ dev_err(par->info->device,
+ "Missing info about 'dc' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+
+ if (!par->pdev)
+ return 0;
+
+ if (par->gpio.wr < 0) {
+ dev_err(par->info->device, "Missing 'wr' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ for (i = 0; i < pdata->display.buswidth; i++) {
+ if (par->gpio.db[i] < 0) {
+ dev_err(par->info->device,
+ "Missing 'db%02d' gpio. Aborting.\n", i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+/* returns 0 if the property is not present */
+static u32 fbtft_of_value(struct device_node *node, const char *propname)
+{
+ int ret;
+ u32 val = 0;
+
+ ret = of_property_read_u32(node, propname, &val);
+ if (ret == 0)
+ pr_info("%s: %s = %u\n", __func__, propname, val);
+
+ return val;
+}
+
+static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
+{
+ struct device_node *node = dev->of_node;
+ struct fbtft_platform_data *pdata;
+
+ if (!node) {
+ dev_err(dev, "Missing platform data or DT\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL);
+ if (!pdata)
+ return ERR_PTR(-ENOMEM);
+
+ pdata->display.width = fbtft_of_value(node, "width");
+ pdata->display.height = fbtft_of_value(node, "height");
+ pdata->display.regwidth = fbtft_of_value(node, "regwidth");
+ pdata->display.buswidth = fbtft_of_value(node, "buswidth");
+ pdata->display.backlight = fbtft_of_value(node, "backlight");
+ pdata->display.bpp = fbtft_of_value(node, "bpp");
+ pdata->display.debug = fbtft_of_value(node, "debug");
+ pdata->rotate = fbtft_of_value(node, "rotate");
+ pdata->bgr = of_property_read_bool(node, "bgr");
+ pdata->fps = fbtft_of_value(node, "fps");
+ pdata->txbuflen = fbtft_of_value(node, "txbuflen");
+ pdata->startbyte = fbtft_of_value(node, "startbyte");
+ of_property_read_string(node, "gamma", (const char **)&pdata->gamma);
+
+ if (of_find_property(node, "led-gpios", NULL))
+ pdata->display.backlight = 1;
+ if (of_find_property(node, "init", NULL))
+ pdata->display.fbtftops.init_display = fbtft_init_display_dt;
+ pdata->display.fbtftops.request_gpios = fbtft_request_gpios_dt;
+
+ return pdata;
+}
+#else
+static struct fbtft_platform_data *fbtft_probe_dt(struct device *dev)
+{
+ dev_err(dev, "Missing platform data\n");
+ return ERR_PTR(-EINVAL);
+}
+#endif
+
+/**
+ * fbtft_probe_common() - Generic device probe() helper function
+ * @display: Display properties
+ * @sdev: SPI device
+ * @pdev: Platform device
+ *
+ * Allocates, initializes and registers a framebuffer
+ *
+ * Either @sdev or @pdev should be NULL
+ *
+ * Return: 0 if successful, negative if error
+ */
+int fbtft_probe_common(struct fbtft_display *display,
+ struct spi_device *sdev, struct platform_device *pdev)
+{
+ struct device *dev;
+ struct fb_info *info;
+ struct fbtft_par *par;
+ struct fbtft_platform_data *pdata;
+ int ret;
+
+ if (sdev)
+ dev = &sdev->dev;
+ else
+ dev = &pdev->dev;
+
+ if (unlikely(display->debug & DEBUG_DRIVER_INIT_FUNCTIONS))
+ dev_info(dev, "%s()\n", __func__);
+
+ pdata = dev->platform_data;
+ if (!pdata) {
+ pdata = fbtft_probe_dt(dev);
+ if (IS_ERR(pdata))
+ return PTR_ERR(pdata);
+ dev->platform_data = pdata;
+ }
+
+ info = fbtft_framebuffer_alloc(display, dev);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+ par->spi = sdev;
+ par->pdev = pdev;
+
+ if (display->buswidth == 0) {
+ dev_err(dev, "buswidth is not set\n");
+ return -EINVAL;
+ }
+
+ /* write register functions */
+ if (display->regwidth == 8 && display->buswidth == 8) {
+ par->fbtftops.write_register = fbtft_write_reg8_bus8;
+ } else
+ if (display->regwidth == 8 && display->buswidth == 9 && par->spi) {
+ par->fbtftops.write_register = fbtft_write_reg8_bus9;
+ } else if (display->regwidth == 16 && display->buswidth == 8) {
+ par->fbtftops.write_register = fbtft_write_reg16_bus8;
+ } else if (display->regwidth == 16 && display->buswidth == 16) {
+ par->fbtftops.write_register = fbtft_write_reg16_bus16;
+ } else {
+ dev_warn(dev,
+ "no default functions for regwidth=%d and buswidth=%d\n",
+ display->regwidth, display->buswidth);
+ }
+
+ /* write_vmem() functions */
+ if (display->buswidth == 8)
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+ else if (display->buswidth == 9)
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus9;
+ else if (display->buswidth == 16)
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus16;
+
+ /* GPIO write() functions */
+ if (par->pdev) {
+ if (display->buswidth == 8)
+ par->fbtftops.write = fbtft_write_gpio8_wr;
+ else if (display->buswidth == 16)
+ par->fbtftops.write = fbtft_write_gpio16_wr;
+ }
+
+ /* 9-bit SPI setup */
+ if (par->spi && display->buswidth == 9) {
+ par->spi->bits_per_word = 9;
+ ret = par->spi->master->setup(par->spi);
+ if (ret) {
+ dev_warn(&par->spi->dev,
+ "9-bit SPI not available, emulating using 8-bit.\n");
+ par->spi->bits_per_word = 8;
+ ret = par->spi->master->setup(par->spi);
+ if (ret)
+ goto out_release;
+ /* allocate buffer with room for dc bits */
+ par->extra = devm_kzalloc(par->info->device,
+ par->txbuf.len + (par->txbuf.len / 8) + 8,
+ GFP_KERNEL);
+ if (!par->extra) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
+ par->fbtftops.write = fbtft_write_spi_emulate_9;
+ }
+ }
+
+ if (!par->fbtftops.verify_gpios)
+ par->fbtftops.verify_gpios = fbtft_verify_gpios;
+
+ /* make sure we still use the driver provided functions */
+ fbtft_merge_fbtftops(&par->fbtftops, &display->fbtftops);
+
+ /* use init_sequence if provided */
+ if (par->init_sequence)
+ par->fbtftops.init_display = fbtft_init_display;
+
+ /* use platform_data provided functions above all */
+ fbtft_merge_fbtftops(&par->fbtftops, &pdata->display.fbtftops);
+
+ ret = fbtft_register_framebuffer(info);
+ if (ret < 0)
+ goto out_release;
+
+ return 0;
+
+out_release:
+ fbtft_framebuffer_release(info);
+
+ return ret;
+}
+EXPORT_SYMBOL(fbtft_probe_common);
+
+/**
+ * fbtft_remove_common() - Generic device remove() helper function
+ * @dev: Device
+ * @info: Framebuffer
+ *
+ * Unregisters and releases the framebuffer
+ *
+ * Return: 0 if successful, negative if error
+ */
+int fbtft_remove_common(struct device *dev, struct fb_info *info)
+{
+ struct fbtft_par *par;
+
+ if (!info)
+ return -EINVAL;
+ par = info->par;
+ if (par)
+ fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par,
+ "%s()\n", __func__);
+ fbtft_unregister_framebuffer(info);
+ fbtft_framebuffer_release(info);
+
+ return 0;
+}
+EXPORT_SYMBOL(fbtft_remove_common);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/fbtft-io.c b/drivers/staging/fbtft/fbtft-io.c
new file mode 100644
index 000000000000..32155a7b2a62
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-io.c
@@ -0,0 +1,239 @@
+#include <linux/export.h>
+#include <linux/errno.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include "fbtft.h"
+
+int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len)
+{
+ struct spi_transfer t = {
+ .tx_buf = buf,
+ .len = len,
+ };
+ struct spi_message m;
+
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ if (!par->spi) {
+ dev_err(par->info->device,
+ "%s: par->spi is unexpectedly NULL\n", __func__);
+ return -1;
+ }
+
+ spi_message_init(&m);
+ if (par->txbuf.dma && buf == par->txbuf.buf) {
+ t.tx_dma = par->txbuf.dma;
+ m.is_dma_mapped = 1;
+ }
+ spi_message_add_tail(&t, &m);
+ return spi_sync(par->spi, &m);
+}
+EXPORT_SYMBOL(fbtft_write_spi);
+
+/**
+ * fbtft_write_spi_emulate_9() - write SPI emulating 9-bit
+ * @par: Driver data
+ * @buf: Buffer to write
+ * @len: Length of buffer (must be divisible by 8)
+ *
+ * When 9-bit SPI is not available, this function can be used to emulate that.
+ * par->extra must hold a transformation buffer used for transfer.
+ */
+int fbtft_write_spi_emulate_9(struct fbtft_par *par, void *buf, size_t len)
+{
+ u16 *src = buf;
+ u8 *dst = par->extra;
+ size_t size = len / 2;
+ size_t added = 0;
+ int bits, i, j;
+ u64 val, dc, tmp;
+
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ if (!par->extra) {
+ dev_err(par->info->device, "%s: error: par->extra is NULL\n",
+ __func__);
+ return -EINVAL;
+ }
+ if ((len % 8) != 0) {
+ dev_err(par->info->device,
+ "%s: error: len=%d must be divisible by 8\n",
+ __func__, len);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < size; i += 8) {
+ tmp = 0;
+ bits = 63;
+ for (j = 0; j < 7; j++) {
+ dc = (*src & 0x0100) ? 1 : 0;
+ val = *src & 0x00FF;
+ tmp |= dc << bits;
+ bits -= 8;
+ tmp |= val << bits--;
+ src++;
+ }
+ tmp |= ((*src & 0x0100) ? 1 : 0);
+ *(u64 *)dst = cpu_to_be64(tmp);
+ dst += 8;
+ *dst++ = (u8)(*src++ & 0x00FF);
+ added++;
+ }
+
+ return spi_write(par->spi, par->extra, size + added);
+}
+EXPORT_SYMBOL(fbtft_write_spi_emulate_9);
+
+int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len)
+{
+ int ret;
+ u8 txbuf[32] = { 0, };
+ struct spi_transfer t = {
+ .speed_hz = 2000000,
+ .rx_buf = buf,
+ .len = len,
+ };
+ struct spi_message m;
+
+ if (!par->spi) {
+ dev_err(par->info->device,
+ "%s: par->spi is unexpectedly NULL\n", __func__);
+ return -ENODEV;
+ }
+
+ if (par->startbyte) {
+ if (len > 32) {
+ dev_err(par->info->device,
+ "%s: len=%d can't be larger than 32 when using 'startbyte'\n",
+ __func__, len);
+ return -EINVAL;
+ }
+ txbuf[0] = par->startbyte | 0x3;
+ t.tx_buf = txbuf;
+ fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8,
+ txbuf, len, "%s(len=%d) txbuf => ", __func__, len);
+ }
+
+ spi_message_init(&m);
+ spi_message_add_tail(&t, &m);
+ ret = spi_sync(par->spi, &m);
+ fbtft_par_dbg_hex(DEBUG_READ, par, par->info->device, u8, buf, len,
+ "%s(len=%d) buf <= ", __func__, len);
+
+ return ret;
+}
+EXPORT_SYMBOL(fbtft_read_spi);
+
+/*
+ * Optimized use of gpiolib is twice as fast as no optimization
+ * only one driver can use the optimized version at a time
+ */
+int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len)
+{
+ u8 data;
+ int i;
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ static u8 prev_data;
+#endif
+
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ while (len--) {
+ data = *(u8 *) buf;
+
+ /* Start writing by pulling down /WR */
+ gpio_set_value(par->gpio.wr, 0);
+
+ /* Set data */
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ if (data == prev_data) {
+ gpio_set_value(par->gpio.wr, 0); /* used as delay */
+ } else {
+ for (i = 0; i < 8; i++) {
+ if ((data & 1) != (prev_data & 1))
+ gpio_set_value(par->gpio.db[i],
+ (data & 1));
+ data >>= 1;
+ prev_data >>= 1;
+ }
+ }
+#else
+ for (i = 0; i < 8; i++) {
+ gpio_set_value(par->gpio.db[i], (data & 1));
+ data >>= 1;
+ }
+#endif
+
+ /* Pullup /WR */
+ gpio_set_value(par->gpio.wr, 1);
+
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ prev_data = *(u8 *) buf;
+#endif
+ buf++;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(fbtft_write_gpio8_wr);
+
+int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len)
+{
+ u16 data;
+ int i;
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ static u16 prev_data;
+#endif
+
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ while (len) {
+ data = *(u16 *) buf;
+
+ /* Start writing by pulling down /WR */
+ gpio_set_value(par->gpio.wr, 0);
+
+ /* Set data */
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ if (data == prev_data) {
+ gpio_set_value(par->gpio.wr, 0); /* used as delay */
+ } else {
+ for (i = 0; i < 16; i++) {
+ if ((data & 1) != (prev_data & 1))
+ gpio_set_value(par->gpio.db[i],
+ (data & 1));
+ data >>= 1;
+ prev_data >>= 1;
+ }
+ }
+#else
+ for (i = 0; i < 16; i++) {
+ gpio_set_value(par->gpio.db[i], (data & 1));
+ data >>= 1;
+ }
+#endif
+
+ /* Pullup /WR */
+ gpio_set_value(par->gpio.wr, 1);
+
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ prev_data = *(u16 *) buf;
+#endif
+ buf += 2;
+ len -= 2;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(fbtft_write_gpio16_wr);
+
+int fbtft_write_gpio16_wr_latched(struct fbtft_par *par, void *buf, size_t len)
+{
+ dev_err(par->info->device, "%s: function not implemented\n", __func__);
+ return -1;
+}
+EXPORT_SYMBOL(fbtft_write_gpio16_wr_latched);
diff --git a/drivers/staging/fbtft/fbtft-sysfs.c b/drivers/staging/fbtft/fbtft-sysfs.c
new file mode 100644
index 000000000000..45f8de3d11ad
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft-sysfs.c
@@ -0,0 +1,222 @@
+#include "fbtft.h"
+
+
+static int get_next_ulong(char **str_p, unsigned long *val, char *sep, int base)
+{
+ char *p_val;
+ int ret;
+
+ if (!str_p || !(*str_p))
+ return -EINVAL;
+
+ p_val = strsep(str_p, sep);
+
+ if (!p_val)
+ return -EINVAL;
+
+ ret = kstrtoul(p_val, base, val);
+ if (ret)
+ return -EINVAL;
+
+ return 0;
+}
+
+int fbtft_gamma_parse_str(struct fbtft_par *par, unsigned long *curves,
+ const char *str, int size)
+{
+ char *str_p, *curve_p = NULL;
+ char *tmp;
+ unsigned long val = 0;
+ int ret = 0;
+ int curve_counter, value_counter;
+
+ fbtft_par_dbg(DEBUG_SYSFS, par, "%s() str=\n", __func__);
+
+ if (!str || !curves)
+ return -EINVAL;
+
+ fbtft_par_dbg(DEBUG_SYSFS, par, "%s\n", str);
+
+ tmp = kmalloc(size+1, GFP_KERNEL);
+ if (!tmp)
+ return -ENOMEM;
+ memcpy(tmp, str, size+1);
+
+ /* replace optional separators */
+ str_p = tmp;
+ while (*str_p) {
+ if (*str_p == ',')
+ *str_p = ' ';
+ if (*str_p == ';')
+ *str_p = '\n';
+ str_p++;
+ }
+
+ str_p = strim(tmp);
+
+ curve_counter = 0;
+ while (str_p) {
+ if (curve_counter == par->gamma.num_curves) {
+ dev_err(par->info->device, "Gamma: Too many curves\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ curve_p = strsep(&str_p, "\n");
+ value_counter = 0;
+ while (curve_p) {
+ if (value_counter == par->gamma.num_values) {
+ dev_err(par->info->device,
+ "Gamma: Too many values\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ ret = get_next_ulong(&curve_p, &val, " ", 16);
+ if (ret)
+ goto out;
+ curves[curve_counter * par->gamma.num_values + value_counter] = val;
+ value_counter++;
+ }
+ if (value_counter != par->gamma.num_values) {
+ dev_err(par->info->device, "Gamma: Too few values\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ curve_counter++;
+ }
+ if (curve_counter != par->gamma.num_curves) {
+ dev_err(par->info->device, "Gamma: Too few curves\n");
+ ret = -EINVAL;
+ goto out;
+ }
+
+out:
+ kfree(tmp);
+ return ret;
+}
+
+static ssize_t
+sprintf_gamma(struct fbtft_par *par, unsigned long *curves, char *buf)
+{
+ ssize_t len = 0;
+ unsigned int i, j;
+
+ mutex_lock(&par->gamma.lock);
+ for (i = 0; i < par->gamma.num_curves; i++) {
+ for (j = 0; j < par->gamma.num_values; j++)
+ len += scnprintf(&buf[len], PAGE_SIZE,
+ "%04lx ", curves[i*par->gamma.num_values + j]);
+ buf[len-1] = '\n';
+ }
+ mutex_unlock(&par->gamma.lock);
+
+ return len;
+}
+
+static ssize_t store_gamma_curve(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = dev_get_drvdata(device);
+ struct fbtft_par *par = fb_info->par;
+ unsigned long tmp_curves[FBTFT_GAMMA_MAX_VALUES_TOTAL];
+ int ret;
+
+ ret = fbtft_gamma_parse_str(par, tmp_curves, buf, count);
+ if (ret)
+ return ret;
+
+ ret = par->fbtftops.set_gamma(par, tmp_curves);
+ if (ret)
+ return ret;
+
+ mutex_lock(&par->gamma.lock);
+ memcpy(par->gamma.curves, tmp_curves,
+ par->gamma.num_curves * par->gamma.num_values * sizeof(tmp_curves[0]));
+ mutex_unlock(&par->gamma.lock);
+
+ return count;
+}
+
+static ssize_t show_gamma_curve(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fb_info = dev_get_drvdata(device);
+ struct fbtft_par *par = fb_info->par;
+
+ return sprintf_gamma(par, par->gamma.curves, buf);
+}
+
+static struct device_attribute gamma_device_attrs[] = {
+ __ATTR(gamma, 0660, show_gamma_curve, store_gamma_curve),
+};
+
+
+void fbtft_expand_debug_value(unsigned long *debug)
+{
+ switch (*debug & 0b111) {
+ case 1:
+ *debug |= DEBUG_LEVEL_1;
+ break;
+ case 2:
+ *debug |= DEBUG_LEVEL_2;
+ break;
+ case 3:
+ *debug |= DEBUG_LEVEL_3;
+ break;
+ case 4:
+ *debug |= DEBUG_LEVEL_4;
+ break;
+ case 5:
+ *debug |= DEBUG_LEVEL_5;
+ break;
+ case 6:
+ *debug |= DEBUG_LEVEL_6;
+ break;
+ case 7:
+ *debug = 0xFFFFFFFF;
+ break;
+ }
+}
+
+static ssize_t store_debug(struct device *device,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct fb_info *fb_info = dev_get_drvdata(device);
+ struct fbtft_par *par = fb_info->par;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &par->debug);
+ if (ret)
+ return ret;
+ fbtft_expand_debug_value(&par->debug);
+
+ return count;
+}
+
+static ssize_t show_debug(struct device *device,
+ struct device_attribute *attr, char *buf)
+{
+ struct fb_info *fb_info = dev_get_drvdata(device);
+ struct fbtft_par *par = fb_info->par;
+
+ return snprintf(buf, PAGE_SIZE, "%lu\n", par->debug);
+}
+
+static struct device_attribute debug_device_attr = \
+ __ATTR(debug, 0660, show_debug, store_debug);
+
+
+void fbtft_sysfs_init(struct fbtft_par *par)
+{
+ device_create_file(par->info->dev, &debug_device_attr);
+ if (par->gamma.curves && par->fbtftops.set_gamma)
+ device_create_file(par->info->dev, &gamma_device_attrs[0]);
+}
+
+void fbtft_sysfs_exit(struct fbtft_par *par)
+{
+ device_remove_file(par->info->dev, &debug_device_attr);
+ if (par->gamma.curves && par->fbtftops.set_gamma)
+ device_remove_file(par->info->dev, &gamma_device_attrs[0]);
+}
diff --git a/drivers/staging/fbtft/fbtft.h b/drivers/staging/fbtft/fbtft.h
new file mode 100644
index 000000000000..0dbf3f95fe78
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft.h
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef __LINUX_FBTFT_H
+#define __LINUX_FBTFT_H
+
+#include <linux/fb.h>
+#include <linux/spinlock.h>
+#include <linux/spi/spi.h>
+#include <linux/platform_device.h>
+
+
+#define FBTFT_NOP 0x00
+#define FBTFT_SWRESET 0x01
+#define FBTFT_RDDID 0x04
+#define FBTFT_RDDST 0x09
+#define FBTFT_CASET 0x2A
+#define FBTFT_RASET 0x2B
+#define FBTFT_RAMWR 0x2C
+
+#define FBTFT_ONBOARD_BACKLIGHT 2
+
+#define FBTFT_GPIO_NO_MATCH 0xFFFF
+#define FBTFT_GPIO_NAME_SIZE 32
+#define FBTFT_MAX_INIT_SEQUENCE 512
+#define FBTFT_GAMMA_MAX_VALUES_TOTAL 128
+
+#define FBTFT_OF_INIT_CMD BIT(24)
+#define FBTFT_OF_INIT_DELAY BIT(25)
+
+/**
+ * struct fbtft_gpio - Structure that holds one pinname to gpio mapping
+ * @name: pinname (reset, dc, etc.)
+ * @gpio: GPIO number
+ *
+ */
+struct fbtft_gpio {
+ char name[FBTFT_GPIO_NAME_SIZE];
+ unsigned gpio;
+};
+
+struct fbtft_par;
+
+/**
+ * struct fbtft_ops - FBTFT operations structure
+ * @write: Writes to interface bus
+ * @read: Reads from interface bus
+ * @write_vmem: Writes video memory to display
+ * @write_reg: Writes to controller register
+ * @set_addr_win: Set the GRAM update window
+ * @reset: Reset the LCD controller
+ * @mkdirty: Marks display lines for update
+ * @update_display: Updates the display
+ * @init_display: Initializes the display
+ * @blank: Blank the display (optional)
+ * @request_gpios_match: Do pinname to gpio matching
+ * @request_gpios: Request gpios from the kernel
+ * @free_gpios: Free previously requested gpios
+ * @verify_gpios: Verify that necessary gpios is present (optional)
+ * @register_backlight: Used to register backlight device (optional)
+ * @unregister_backlight: Unregister backlight device (optional)
+ * @set_var: Configure LCD with values from variables like @rotate and @bgr
+ * (optional)
+ * @set_gamma: Set Gamma curve (optional)
+ *
+ * Most of these operations have default functions assigned to them in
+ * fbtft_framebuffer_alloc()
+ */
+struct fbtft_ops {
+ int (*write)(struct fbtft_par *par, void *buf, size_t len);
+ int (*read)(struct fbtft_par *par, void *buf, size_t len);
+ int (*write_vmem)(struct fbtft_par *par, size_t offset, size_t len);
+ void (*write_register)(struct fbtft_par *par, int len, ...);
+
+ void (*set_addr_win)(struct fbtft_par *par,
+ int xs, int ys, int xe, int ye);
+ void (*reset)(struct fbtft_par *par);
+ void (*mkdirty)(struct fb_info *info, int from, int to);
+ void (*update_display)(struct fbtft_par *par,
+ unsigned start_line, unsigned end_line);
+ int (*init_display)(struct fbtft_par *par);
+ int (*blank)(struct fbtft_par *par, bool on);
+
+ unsigned long (*request_gpios_match)(struct fbtft_par *par,
+ const struct fbtft_gpio *gpio);
+ int (*request_gpios)(struct fbtft_par *par);
+ int (*verify_gpios)(struct fbtft_par *par);
+
+ void (*register_backlight)(struct fbtft_par *par);
+ void (*unregister_backlight)(struct fbtft_par *par);
+
+ int (*set_var)(struct fbtft_par *par);
+ int (*set_gamma)(struct fbtft_par *par, unsigned long *curves);
+};
+
+/**
+ * struct fbtft_display - Describes the display properties
+ * @width: Width of display in pixels
+ * @height: Height of display in pixels
+ * @regwidth: LCD Controller Register width in bits
+ * @buswidth: Display interface bus width in bits
+ * @backlight: Backlight type.
+ * @fbtftops: FBTFT operations provided by driver or device (platform_data)
+ * @bpp: Bits per pixel
+ * @fps: Frames per second
+ * @txbuflen: Size of transmit buffer
+ * @init_sequence: Pointer to LCD initialization array
+ * @gamma: String representation of Gamma curve(s)
+ * @gamma_num: Number of Gamma curves
+ * @gamma_len: Number of values per Gamma curve
+ * @debug: Initial debug value
+ *
+ * This structure is not stored by FBTFT except for init_sequence.
+ */
+struct fbtft_display {
+ unsigned width;
+ unsigned height;
+ unsigned regwidth;
+ unsigned buswidth;
+ unsigned backlight;
+ struct fbtft_ops fbtftops;
+ unsigned bpp;
+ unsigned fps;
+ int txbuflen;
+ int *init_sequence;
+ char *gamma;
+ int gamma_num;
+ int gamma_len;
+ unsigned long debug;
+};
+
+/**
+ * struct fbtft_platform_data - Passes display specific data to the driver
+ * @display: Display properties
+ * @gpios: Pointer to an array of piname to gpio mappings
+ * @rotate: Display rotation angle
+ * @bgr: LCD Controller BGR bit
+ * @fps: Frames per second (this will go away, use @fps in @fbtft_display)
+ * @txbuflen: Size of transmit buffer
+ * @startbyte: When set, enables use of Startbyte in transfers
+ * @gamma: String representation of Gamma curve(s)
+ * @extra: A way to pass extra info
+ */
+struct fbtft_platform_data {
+ struct fbtft_display display;
+ const struct fbtft_gpio *gpios;
+ unsigned rotate;
+ bool bgr;
+ unsigned fps;
+ int txbuflen;
+ u8 startbyte;
+ char *gamma;
+ void *extra;
+};
+
+/**
+ * struct fbtft_par - Main FBTFT data structure
+ *
+ * This structure holds all relevant data to operate the display
+ *
+ * See sourcefile for documentation since nested structs is not
+ * supported by kernel-doc.
+ *
+ */
+/* @spi: Set if it is a SPI device
+ * @pdev: Set if it is a platform device
+ * @info: Pointer to framebuffer fb_info structure
+ * @pdata: Pointer to platform data
+ * @ssbuf: Not used
+ * @pseudo_palette: Used by fb_set_colreg()
+ * @txbuf.buf: Transmit buffer
+ * @txbuf.len: Transmit buffer length
+ * @buf: Small buffer used when writing init data over SPI
+ * @startbyte: Used by some controllers when in SPI mode.
+ * Format: 6 bit Device id + RS bit + RW bit
+ * @fbtftops: FBTFT operations provided by driver or device (platform_data)
+ * @dirty_lock: Protects dirty_lines_start and dirty_lines_end
+ * @dirty_lines_start: Where to begin updating display
+ * @dirty_lines_end: Where to end updating display
+ * @gpio.reset: GPIO used to reset display
+ * @gpio.dc: Data/Command signal, also known as RS
+ * @gpio.rd: Read latching signal
+ * @gpio.wr: Write latching signal
+ * @gpio.latch: Bus latch signal, eg. 16->8 bit bus latch
+ * @gpio.cs: LCD Chip Select with parallel interface bus
+ * @gpio.db[16]: Parallel databus
+ * @gpio.led[16]: Led control signals
+ * @gpio.aux[16]: Auxillary signals, not used by core
+ * @init_sequence: Pointer to LCD initialization array
+ * @gamma.lock: Mutex for Gamma curve locking
+ * @gamma.curves: Pointer to Gamma curve array
+ * @gamma.num_values: Number of values per Gamma curve
+ * @gamma.num_curves: Number of Gamma curves
+ * @debug: Pointer to debug value
+ * @current_debug:
+ * @first_update_done: Used to only time the first display update
+ * @update_time: Used to calculate 'fps' in debug output
+ * @bgr: BGR mode/\n
+ * @extra: Extra info needed by driver
+ */
+struct fbtft_par {
+ struct spi_device *spi;
+ struct platform_device *pdev;
+ struct fb_info *info;
+ struct fbtft_platform_data *pdata;
+ u16 *ssbuf;
+ u32 pseudo_palette[16];
+ struct {
+ void *buf;
+ dma_addr_t dma;
+ size_t len;
+ } txbuf;
+ u8 *buf;
+ u8 startbyte;
+ struct fbtft_ops fbtftops;
+ spinlock_t dirty_lock;
+ unsigned dirty_lines_start;
+ unsigned dirty_lines_end;
+ struct {
+ int reset;
+ int dc;
+ int rd;
+ int wr;
+ int latch;
+ int cs;
+ int db[16];
+ int led[16];
+ int aux[16];
+ } gpio;
+ int *init_sequence;
+ struct {
+ struct mutex lock;
+ unsigned long *curves;
+ int num_values;
+ int num_curves;
+ } gamma;
+ unsigned long debug;
+ bool first_update_done;
+ struct timespec update_time;
+ bool bgr;
+ void *extra;
+};
+
+#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
+
+#define write_reg(par, ...) \
+do { \
+ par->fbtftops.write_register(par, NUMARGS(__VA_ARGS__), __VA_ARGS__); \
+} while (0)
+
+/* fbtft-core.c */
+extern void fbtft_dbg_hex(const struct device *dev,
+ int groupsize, void *buf, size_t len, const char *fmt, ...);
+extern struct fb_info *fbtft_framebuffer_alloc(struct fbtft_display *display,
+ struct device *dev);
+extern void fbtft_framebuffer_release(struct fb_info *info);
+extern int fbtft_register_framebuffer(struct fb_info *fb_info);
+extern int fbtft_unregister_framebuffer(struct fb_info *fb_info);
+extern void fbtft_register_backlight(struct fbtft_par *par);
+extern void fbtft_unregister_backlight(struct fbtft_par *par);
+extern int fbtft_init_display(struct fbtft_par *par);
+extern int fbtft_probe_common(struct fbtft_display *display,
+ struct spi_device *sdev, struct platform_device *pdev);
+extern int fbtft_remove_common(struct device *dev, struct fb_info *info);
+
+/* fbtft-io.c */
+extern int fbtft_write_spi(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_spi_emulate_9(struct fbtft_par *par,
+ void *buf, size_t len);
+extern int fbtft_read_spi(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_gpio8_wr(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_gpio16_wr(struct fbtft_par *par, void *buf, size_t len);
+extern int fbtft_write_gpio16_wr_latched(struct fbtft_par *par,
+ void *buf, size_t len);
+
+/* fbtft-bus.c */
+extern int fbtft_write_vmem8_bus8(struct fbtft_par *par, size_t offset, size_t len);
+extern int fbtft_write_vmem16_bus16(struct fbtft_par *par, size_t offset, size_t len);
+extern int fbtft_write_vmem16_bus8(struct fbtft_par *par, size_t offset, size_t len);
+extern int fbtft_write_vmem16_bus9(struct fbtft_par *par, size_t offset, size_t len);
+extern void fbtft_write_reg8_bus8(struct fbtft_par *par, int len, ...);
+extern void fbtft_write_reg8_bus9(struct fbtft_par *par, int len, ...);
+extern void fbtft_write_reg16_bus8(struct fbtft_par *par, int len, ...);
+extern void fbtft_write_reg16_bus16(struct fbtft_par *par, int len, ...);
+
+
+#define FBTFT_REGISTER_DRIVER(_name, _compatible, _display) \
+ \
+static int fbtft_driver_probe_spi(struct spi_device *spi) \
+{ \
+ return fbtft_probe_common(_display, spi, NULL); \
+} \
+ \
+static int fbtft_driver_remove_spi(struct spi_device *spi) \
+{ \
+ struct fb_info *info = spi_get_drvdata(spi); \
+ \
+ return fbtft_remove_common(&spi->dev, info); \
+} \
+ \
+static int fbtft_driver_probe_pdev(struct platform_device *pdev) \
+{ \
+ return fbtft_probe_common(_display, NULL, pdev); \
+} \
+ \
+static int fbtft_driver_remove_pdev(struct platform_device *pdev) \
+{ \
+ struct fb_info *info = platform_get_drvdata(pdev); \
+ \
+ return fbtft_remove_common(&pdev->dev, info); \
+} \
+ \
+static const struct of_device_id dt_ids[] = { \
+ { .compatible = _compatible }, \
+ {}, \
+}; \
+ \
+MODULE_DEVICE_TABLE(of, dt_ids); \
+ \
+ \
+static struct spi_driver fbtft_driver_spi_driver = { \
+ .driver = { \
+ .name = _name, \
+ .owner = THIS_MODULE, \
+ .of_match_table = of_match_ptr(dt_ids), \
+ }, \
+ .probe = fbtft_driver_probe_spi, \
+ .remove = fbtft_driver_remove_spi, \
+}; \
+ \
+static struct platform_driver fbtft_driver_platform_driver = { \
+ .driver = { \
+ .name = _name, \
+ .owner = THIS_MODULE, \
+ .of_match_table = of_match_ptr(dt_ids), \
+ }, \
+ .probe = fbtft_driver_probe_pdev, \
+ .remove = fbtft_driver_remove_pdev, \
+}; \
+ \
+static int __init fbtft_driver_module_init(void) \
+{ \
+ int ret; \
+ \
+ ret = spi_register_driver(&fbtft_driver_spi_driver); \
+ if (ret < 0) \
+ return ret; \
+ return platform_driver_register(&fbtft_driver_platform_driver); \
+} \
+ \
+static void __exit fbtft_driver_module_exit(void) \
+{ \
+ spi_unregister_driver(&fbtft_driver_spi_driver); \
+ platform_driver_unregister(&fbtft_driver_platform_driver); \
+} \
+ \
+module_init(fbtft_driver_module_init); \
+module_exit(fbtft_driver_module_exit);
+
+
+/* Debug macros */
+
+/* shorthand debug levels */
+#define DEBUG_LEVEL_1 DEBUG_REQUEST_GPIOS
+#define DEBUG_LEVEL_2 (DEBUG_LEVEL_1 | DEBUG_DRIVER_INIT_FUNCTIONS | DEBUG_TIME_FIRST_UPDATE)
+#define DEBUG_LEVEL_3 (DEBUG_LEVEL_2 | DEBUG_RESET | DEBUG_INIT_DISPLAY | DEBUG_BLANK | DEBUG_REQUEST_GPIOS | DEBUG_FREE_GPIOS | DEBUG_VERIFY_GPIOS | DEBUG_BACKLIGHT | DEBUG_SYSFS)
+#define DEBUG_LEVEL_4 (DEBUG_LEVEL_2 | DEBUG_FB_READ | DEBUG_FB_WRITE | DEBUG_FB_FILLRECT | DEBUG_FB_COPYAREA | DEBUG_FB_IMAGEBLIT | DEBUG_FB_BLANK)
+#define DEBUG_LEVEL_5 (DEBUG_LEVEL_3 | DEBUG_UPDATE_DISPLAY)
+#define DEBUG_LEVEL_6 (DEBUG_LEVEL_4 | DEBUG_LEVEL_5)
+#define DEBUG_LEVEL_7 0xFFFFFFFF
+
+#define DEBUG_DRIVER_INIT_FUNCTIONS (1<<3)
+#define DEBUG_TIME_FIRST_UPDATE (1<<4)
+#define DEBUG_TIME_EACH_UPDATE (1<<5)
+#define DEBUG_DEFERRED_IO (1<<6)
+#define DEBUG_FBTFT_INIT_FUNCTIONS (1<<7)
+
+/* fbops */
+#define DEBUG_FB_READ (1<<8)
+#define DEBUG_FB_WRITE (1<<9)
+#define DEBUG_FB_FILLRECT (1<<10)
+#define DEBUG_FB_COPYAREA (1<<11)
+#define DEBUG_FB_IMAGEBLIT (1<<12)
+#define DEBUG_FB_SETCOLREG (1<<13)
+#define DEBUG_FB_BLANK (1<<14)
+
+#define DEBUG_SYSFS (1<<16)
+
+/* fbtftops */
+#define DEBUG_BACKLIGHT (1<<17)
+#define DEBUG_READ (1<<18)
+#define DEBUG_WRITE (1<<19)
+#define DEBUG_WRITE_VMEM (1<<20)
+#define DEBUG_WRITE_REGISTER (1<<21)
+#define DEBUG_SET_ADDR_WIN (1<<22)
+#define DEBUG_RESET (1<<23)
+#define DEBUG_MKDIRTY (1<<24)
+#define DEBUG_UPDATE_DISPLAY (1<<25)
+#define DEBUG_INIT_DISPLAY (1<<26)
+#define DEBUG_BLANK (1<<27)
+#define DEBUG_REQUEST_GPIOS (1<<28)
+#define DEBUG_FREE_GPIOS (1<<29)
+#define DEBUG_REQUEST_GPIOS_MATCH (1<<30)
+#define DEBUG_VERIFY_GPIOS (1<<31)
+
+
+#define fbtft_init_dbg(dev, format, arg...) \
+do { \
+ if (unlikely((dev)->platform_data && \
+ (((struct fbtft_platform_data *)(dev)->platform_data)->display.debug & DEBUG_DRIVER_INIT_FUNCTIONS))) \
+ dev_info(dev, format, ##arg); \
+} while (0)
+
+#define fbtft_par_dbg(level, par, format, arg...) \
+do { \
+ if (unlikely(par->debug & level)) \
+ dev_info(par->info->device, format, ##arg); \
+} while (0)
+
+#define fbtft_dev_dbg(level, par, dev, format, arg...) \
+do { \
+ if (unlikely(par->debug & level)) \
+ dev_info(dev, format, ##arg); \
+} while (0)
+
+#define fbtft_par_dbg_hex(level, par, dev, type, buf, num, format, arg...) \
+do { \
+ if (unlikely(par->debug & level)) \
+ fbtft_dbg_hex(dev, sizeof(type), buf, num * sizeof(type), format, ##arg); \
+} while (0)
+
+#endif /* __LINUX_FBTFT_H */
diff --git a/drivers/staging/fbtft/fbtft_device.c b/drivers/staging/fbtft/fbtft_device.c
new file mode 100644
index 000000000000..b9f4c30e39c6
--- /dev/null
+++ b/drivers/staging/fbtft/fbtft_device.c
@@ -0,0 +1,1444 @@
+/*
+ *
+ * Copyright (C) 2013, Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "fbtft_device"
+
+#define MAX_GPIOS 32
+
+struct spi_device *spi_device;
+struct platform_device *p_device;
+
+static char *name;
+module_param(name, charp, 0);
+MODULE_PARM_DESC(name, "Devicename (required). " \
+"name=list => list all supported devices.");
+
+static unsigned rotate;
+module_param(rotate, uint, 0);
+MODULE_PARM_DESC(rotate,
+"Angle to rotate display counter clockwise: 0, 90, 180, 270");
+
+static unsigned busnum;
+module_param(busnum, uint, 0);
+MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
+
+static unsigned cs;
+module_param(cs, uint, 0);
+MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
+
+static unsigned speed;
+module_param(speed, uint, 0);
+MODULE_PARM_DESC(speed, "SPI speed (override device default)");
+
+static int mode = -1;
+module_param(mode, int, 0);
+MODULE_PARM_DESC(mode, "SPI mode (override device default)");
+
+static char *gpios;
+module_param(gpios, charp, 0);
+MODULE_PARM_DESC(gpios,
+"List of gpios. Comma separated with the form: reset:23,dc:24 " \
+"(when overriding the default, all gpios must be specified)");
+
+static unsigned fps;
+module_param(fps, uint, 0);
+MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
+
+static char *gamma;
+module_param(gamma, charp, 0);
+MODULE_PARM_DESC(gamma,
+"String representation of Gamma Curve(s). Driver specific.");
+
+static int txbuflen;
+module_param(txbuflen, int, 0);
+MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
+
+static int bgr = -1;
+module_param(bgr, int, 0);
+MODULE_PARM_DESC(bgr,
+"BGR bit (supported by some drivers).");
+
+static unsigned startbyte;
+module_param(startbyte, uint, 0);
+MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
+
+static bool custom;
+module_param(custom, bool, 0);
+MODULE_PARM_DESC(custom, "Add a custom display device. " \
+"Use speed= argument to make it a SPI device, else platform_device");
+
+static unsigned width;
+module_param(width, uint, 0);
+MODULE_PARM_DESC(width, "Display width, used with the custom argument");
+
+static unsigned height;
+module_param(height, uint, 0);
+MODULE_PARM_DESC(height, "Display height, used with the custom argument");
+
+static unsigned buswidth = 8;
+module_param(buswidth, uint, 0);
+MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
+
+static int init[FBTFT_MAX_INIT_SEQUENCE];
+static int init_num;
+module_param_array(init, int, &init_num, 0);
+MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
+
+static unsigned long debug;
+module_param(debug, ulong , 0);
+MODULE_PARM_DESC(debug,
+"level: 0-7 (the remaining 29 bits is for advanced usage)");
+
+static unsigned verbose = 3;
+module_param(verbose, uint, 0);
+MODULE_PARM_DESC(verbose,
+"0 silent, >0 show gpios, >1 show devices, >2 show devices before (default=3)");
+
+
+struct fbtft_device_display {
+ char *name;
+ struct spi_board_info *spi;
+ struct platform_device *pdev;
+};
+
+static void fbtft_device_pdev_release(struct device *dev);
+
+static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len);
+static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
+ int xs, int ys, int xe, int ye);
+
+#define ADAFRUIT18_GAMMA \
+ "02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
+ "03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
+
+static int hy28b_init_sequence[] = {
+ -1,0x00e7,0x0010,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700,
+ -1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0207,-1,0x0009,0x0000,
+ -1,0x000a,0x0000,-1,0x000c,0x0001,-1,0x000d,0x0000,-1,0x000f,0x0000,
+ -1,0x0010,0x0000,-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,
+ -2,50,-1,0x0010,0x1590,-1,0x0011,0x0227,-2,50,-1,0x0012,0x009c,-2,50,
+ -1,0x0013,0x1900,-1,0x0029,0x0023,-1,0x002b,0x000e,-2,50,
+ -1,0x0020,0x0000,-1,0x0021,0x0000,-2,50,-1,0x0050,0x0000,
+ -1,0x0051,0x00ef,-1,0x0052,0x0000,-1,0x0053,0x013f,-1,0x0060,0xa700,
+ -1,0x0061,0x0001,-1,0x006a,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,
+ -1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,
+ -1,0x0090,0x0010,-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110,
+ -1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0133,-1,0x0020,0x0000,
+ -1,0x0021,0x0000,-2,100,-3 };
+
+#define HY28B_GAMMA \
+ "04 1F 4 7 7 0 7 7 6 0\n" \
+ "0F 00 1 7 4 0 0 0 6 7"
+
+static int pitft_init_sequence[] = {
+ -1,0x01,-2,5,-1,0x28,-1,0xEF,0x03,0x80,0x02,-1,0xCF,0x00,0xC1,0x30,
+ -1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x00,0x78,
+ -1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00,
+ -1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86,-1,0x3A,0x55,
+ -1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27,-1,0xF2,0x00,-1,0x26,0x01,
+ -1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,
+ 0x0E,0x09,0x00,-1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,
+ 0x08,0x0F,0x0C,0x31,0x36,0x0F,-1,0x11,-2,100,-1,0x29,-2,20,-3 };
+
+static int waveshare32b_init_sequence[] = {
+ -1,0xCB,0x39,0x2C,0x00,0x34,0x02,-1,0xCF,0x00,0xC1,0x30,
+ -1,0xE8,0x85,0x00,0x78,-1,0xEA,0x00,0x00,-1,0xED,0x64,0x03,0x12,0x81,
+ -1,0xF7,0x20,-1,0xC0,0x23,-1,0xC1,0x10,-1,0xC5,0x3e,0x28,-1,0xC7,0x86,
+ -1,0x36,0x28,-1,0x3A,0x55,-1,0xB1,0x00,0x18,-1,0xB6,0x08,0x82,0x27,
+ -1,0xF2,0x00,-1,0x26,0x01,
+ -1,0xE0,0x0F,0x31,0x2B,0x0C,0x0E,0x08,0x4E,0xF1,0x37,0x07,0x10,0x03,0x0E,0x09,0x00,
+ -1,0xE1,0x00,0x0E,0x14,0x03,0x11,0x07,0x31,0xC1,0x48,0x08,0x0F,0x0C,0x31,0x36,0x0F,
+ -1,0x11,-2,120,-1,0x29,-1,0x2c,-3 };
+
+/* Supported displays in alphabetical order */
+static struct fbtft_device_display displays[] = {
+ {
+ .name = "adafruit18",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_st7735r",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ .gamma = ADAFRUIT18_GAMMA,
+ }
+ }
+ }, {
+ .name = "adafruit18_green",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_st7735r",
+ .max_speed_hz = 4000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ .fbtftops.set_addr_win = \
+ adafruit18_green_tab_set_addr_win,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ .gamma = ADAFRUIT18_GAMMA,
+ }
+ }
+ }, {
+ .name = "adafruit22",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_hx8340bn",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 9,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "led", 23 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "adafruit22a",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9340",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "adafruit28",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9341",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "adafruit13m",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ssd1306",
+ .max_speed_hz = 16000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "agm1264k-fl",
+ .pdev = &(struct platform_device) {
+ .name = "fb_agm1264k-fl",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = FBTFT_ONBOARD_BACKLIGHT,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ },
+ }
+ }
+ }, {
+ .name = "dogs102",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_uc1701",
+ .max_speed_hz = 8000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 13 },
+ { "dc", 6 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "er_tftm050_2",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ra8875",
+ .max_speed_hz = 5000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ .width = 480,
+ .height = 272,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "er_tftm070_5",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ra8875",
+ .max_speed_hz = 5000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ .width = 800,
+ .height = 480,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "flexfb",
+ .spi = &(struct spi_board_info) {
+ .modalias = "flexfb",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "flexpfb",
+ .pdev = &(struct platform_device) {
+ .name = "flexpfb",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 17 },
+ { "dc", 1 },
+ { "wr", 0 },
+ { "cs", 21 },
+ { "db00", 9 },
+ { "db01", 11 },
+ { "db02", 18 },
+ { "db03", 23 },
+ { "db04", 24 },
+ { "db05", 25 },
+ { "db06", 8 },
+ { "db07", 7 },
+ { "led", 4 },
+ {},
+ },
+ },
+ }
+ }
+ }, {
+ .name = "freetronicsoled128",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ssd1351",
+ .max_speed_hz = 20000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = FBTFT_ONBOARD_BACKLIGHT,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 24 },
+ { "dc", 25 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "hx8353d",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_hx8353d",
+ .max_speed_hz = 16000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 23 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "hy28a",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9320",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .startbyte = 0b01110000,
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "hy28b",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9325",
+ .max_speed_hz = 48000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ .init_sequence = hy28b_init_sequence,
+ },
+ .startbyte = 0b01110000,
+ .bgr = true,
+ .fps= 50,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "led", 18 },
+ {},
+ },
+ .gamma = HY28B_GAMMA,
+ }
+ }
+ }, {
+ .name = "ili9481",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9481",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .regwidth = 16,
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 22 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "itdb24",
+ .pdev = &(struct platform_device) {
+ .name = "fb_s6d1121",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = false,
+ .gpios = (const struct fbtft_gpio []) {
+ /* Wiring for LCD adapter kit */
+ { "reset", 7 },
+ { "dc", 0 }, /* rev 2: 2 */
+ { "wr", 1 }, /* rev 2: 3 */
+ { "cs", 8 },
+ { "db00", 17 },
+ { "db01", 18 },
+ { "db02", 21 }, /* rev 2: 27 */
+ { "db03", 22 },
+ { "db04", 23 },
+ { "db05", 24 },
+ { "db06", 25 },
+ { "db07", 4 },
+ {}
+ },
+ },
+ }
+ }
+ }, {
+ .name = "itdb28",
+ .pdev = &(struct platform_device) {
+ .name = "fb_ili9325",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ },
+ }
+ }
+ }, {
+ .name = "itdb28_spi",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9325",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "mi0283qt-2",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_hx8347d",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .startbyte = 0b01110000,
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "mi0283qt-9a",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9341",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 9,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "mi0283qt-v2",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_watterott",
+ .max_speed_hz = 4000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "nokia3310",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_pcd8544",
+ .max_speed_hz = 400000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 23 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "nokia3310a",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_tls8204",
+ .max_speed_hz = 1000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 23 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "piscreen",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9486",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .regwidth = 16,
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 22 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "pitft",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9340",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .chip_select = 0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ .init_sequence = pitft_init_sequence,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "dc", 25 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "pioled",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ssd1351",
+ .max_speed_hz = 20000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 24 },
+ { "dc", 25 },
+ {},
+ },
+ .gamma = "0 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 2 " \
+ "2 2 2 2 2 2 2 3 " \
+ "3 3 3 3 3 3 3 3 " \
+ "3 3 3 3 3 3 3 3 " \
+ "3 3 3 4 4 4 4 4 " \
+ "4 4 4 4 4 4 4"
+ }
+ }
+ }, {
+ .name = "rpi-display",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9341",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 23 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "s6d02a1",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_s6d02a1",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 23 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "sainsmart18",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_st7735r",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "sainsmart32",
+ .pdev = &(struct platform_device) {
+ .name = "fb_ssd1289",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 16,
+ .txbuflen = -2, /* disable buffer */
+ .backlight = 1,
+ .fbtftops.write = write_gpio16_wr_slow,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ },
+ },
+ }
+ }, {
+ .name = "sainsmart32_fast",
+ .pdev = &(struct platform_device) {
+ .name = "fb_ssd1289",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 16,
+ .txbuflen = -2, /* disable buffer */
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ },
+ },
+ }
+ }, {
+ .name = "sainsmart32_latched",
+ .pdev = &(struct platform_device) {
+ .name = "fb_ssd1289",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 16,
+ .txbuflen = -2, /* disable buffer */
+ .backlight = 1,
+ .fbtftops.write = \
+ fbtft_write_gpio16_wr_latched,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ },
+ },
+ }
+ }, {
+ .name = "sainsmart32_spi",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ssd1289",
+ .max_speed_hz = 16000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "spidev",
+ .spi = &(struct spi_board_info) {
+ .modalias = "spidev",
+ .max_speed_hz = 500000,
+ .bus_num = 0,
+ .chip_select = 0,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "ssd1331",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ssd1331",
+ .max_speed_hz = 20000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 24 },
+ { "dc", 25 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "tinylcd35",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_tinylcd",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "tm022hdh26",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9341",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 25 },
+ { "dc", 24 },
+ { "led", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "tontec35_9481", /* boards before 02 July 2014 */
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9481",
+ .max_speed_hz = 128000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 15 },
+ { "dc", 25 },
+ { "led_", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "tontec35_9486", /* boards after 02 July 2014 */
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9486",
+ .max_speed_hz = 128000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 15 },
+ { "dc", 25 },
+ { "led_", 18 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "upd161704",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_upd161704",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 24 },
+ { "dc", 25 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "waveshare32b",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_ili9340",
+ .max_speed_hz = 48000000,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ .backlight = 1,
+ .init_sequence = waveshare32b_init_sequence,
+ },
+ .bgr = true,
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 27 },
+ { "dc", 22 },
+ {},
+ },
+ }
+ }
+ }, {
+ .name = "waveshare22",
+ .spi = &(struct spi_board_info) {
+ .modalias = "fb_bd663474",
+ .max_speed_hz = 32000000,
+ .mode = SPI_MODE_3,
+ .platform_data = &(struct fbtft_platform_data) {
+ .display = {
+ .buswidth = 8,
+ },
+ .gpios = (const struct fbtft_gpio []) {
+ { "reset", 24 },
+ { "dc", 25 },
+ {},
+ },
+ }
+ }
+ }, {
+ /* This should be the last item.
+ Used with the custom argument */
+ .name = "",
+ .spi = &(struct spi_board_info) {
+ .modalias = "",
+ .max_speed_hz = 0,
+ .mode = SPI_MODE_0,
+ .platform_data = &(struct fbtft_platform_data) {
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ }
+ },
+ .pdev = &(struct platform_device) {
+ .name = "",
+ .id = 0,
+ .dev = {
+ .release = fbtft_device_pdev_release,
+ .platform_data = &(struct fbtft_platform_data) {
+ .gpios = (const struct fbtft_gpio []) {
+ {},
+ },
+ },
+ },
+ },
+ }
+};
+
+static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
+{
+ u16 data;
+ int i;
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ static u16 prev_data;
+#endif
+
+ fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
+ "%s(len=%d): ", __func__, len);
+
+ while (len) {
+ data = *(u16 *) buf;
+
+ /* Start writing by pulling down /WR */
+ gpio_set_value(par->gpio.wr, 0);
+
+ /* Set data */
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ if (data == prev_data) {
+ gpio_set_value(par->gpio.wr, 0); /* used as delay */
+ } else {
+ for (i = 0; i < 16; i++) {
+ if ((data & 1) != (prev_data & 1))
+ gpio_set_value(par->gpio.db[i],
+ (data & 1));
+ data >>= 1;
+ prev_data >>= 1;
+ }
+ }
+#else
+ for (i = 0; i < 16; i++) {
+ gpio_set_value(par->gpio.db[i], (data & 1));
+ data >>= 1;
+ }
+#endif
+
+ /* Pullup /WR */
+ gpio_set_value(par->gpio.wr, 1);
+
+#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
+ prev_data = *(u16 *) buf;
+#endif
+ buf += 2;
+ len -= 2;
+ }
+
+ return 0;
+}
+
+static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
+ int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par,
+ "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+ write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
+ write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
+ write_reg(par, 0x2C);
+}
+
+/* used if gpios parameter is present */
+static struct fbtft_gpio fbtft_device_param_gpios[MAX_GPIOS+1] = { };
+
+static void fbtft_device_pdev_release(struct device *dev)
+{
+/* Needed to silence this message:
+Device 'xxx' does not have a release() function, it is broken and must be fixed
+*/
+}
+
+static int spi_device_found(struct device *dev, void *data)
+{
+ struct spi_device *spi = container_of(dev, struct spi_device, dev);
+
+ pr_info(DRVNAME": %s %s %dkHz %d bits mode=0x%02X\n",
+ spi->modalias, dev_name(dev), spi->max_speed_hz/1000,
+ spi->bits_per_word, spi->mode);
+
+ return 0;
+}
+
+static void pr_spi_devices(void)
+{
+ pr_info(DRVNAME": SPI devices registered:\n");
+ bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found);
+}
+
+static int p_device_found(struct device *dev, void *data)
+{
+ struct platform_device
+ *pdev = container_of(dev, struct platform_device, dev);
+
+ if (strstr(pdev->name, "fb"))
+ pr_info(DRVNAME": %s id=%d pdata? %s\n",
+ pdev->name, pdev->id,
+ pdev->dev.platform_data ? "yes" : "no");
+
+ return 0;
+}
+
+static void pr_p_devices(void)
+{
+ pr_info(DRVNAME": 'fb' Platform devices registered:\n");
+ bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found);
+}
+
+#ifdef MODULE
+static void fbtft_device_spi_delete(struct spi_master *master, unsigned cs)
+{
+ struct device *dev;
+ char str[32];
+
+ snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
+
+ dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
+ if (dev) {
+ if (verbose)
+ pr_info(DRVNAME": Deleting %s\n", str);
+ device_del(dev);
+ }
+}
+
+static int fbtft_device_spi_device_register(struct spi_board_info *spi)
+{
+ struct spi_master *master;
+
+ master = spi_busnum_to_master(spi->bus_num);
+ if (!master) {
+ pr_err(DRVNAME ": spi_busnum_to_master(%d) returned NULL\n",
+ spi->bus_num);
+ return -EINVAL;
+ }
+ /* make sure it's available */
+ fbtft_device_spi_delete(master, spi->chip_select);
+ spi_device = spi_new_device(master, spi);
+ put_device(&master->dev);
+ if (!spi_device) {
+ pr_err(DRVNAME ": spi_new_device() returned NULL\n");
+ return -EPERM;
+ }
+ return 0;
+}
+#else
+static int fbtft_device_spi_device_register(struct spi_board_info *spi)
+{
+ return spi_register_board_info(spi, 1);
+}
+#endif
+
+static int __init fbtft_device_init(void)
+{
+ struct spi_board_info *spi = NULL;
+ struct fbtft_platform_data *pdata;
+ const struct fbtft_gpio *gpio = NULL;
+ char *p_gpio, *p_name, *p_num;
+ bool found = false;
+ int i = 0;
+ long val;
+ int ret = 0;
+
+ pr_debug("\n\n"DRVNAME": init\n");
+
+ if (name == NULL) {
+#ifdef MODULE
+ pr_err(DRVNAME": missing module parameter: 'name'\n");
+ return -EINVAL;
+#else
+ return 0;
+#endif
+ }
+
+ if (init_num > FBTFT_MAX_INIT_SEQUENCE) {
+ pr_err(DRVNAME \
+ ": init parameter: exceeded max array size: %d\n",
+ FBTFT_MAX_INIT_SEQUENCE);
+ return -EINVAL;
+ }
+
+ /* parse module parameter: gpios */
+ while ((p_gpio = strsep(&gpios, ","))) {
+ if (strchr(p_gpio, ':') == NULL) {
+ pr_err(DRVNAME \
+ ": error: missing ':' in gpios parameter: %s\n",
+ p_gpio);
+ return -EINVAL;
+ }
+ p_num = p_gpio;
+ p_name = strsep(&p_num, ":");
+ if (p_name == NULL || p_num == NULL) {
+ pr_err(DRVNAME \
+ ": something bad happened parsing gpios parameter: %s\n",
+ p_gpio);
+ return -EINVAL;
+ }
+ ret = kstrtol(p_num, 10, &val);
+ if (ret) {
+ pr_err(DRVNAME \
+ ": could not parse number in gpios parameter: %s:%s\n",
+ p_name, p_num);
+ return -EINVAL;
+ }
+ strcpy(fbtft_device_param_gpios[i].name, p_name);
+ fbtft_device_param_gpios[i++].gpio = (int) val;
+ if (i == MAX_GPIOS) {
+ pr_err(DRVNAME \
+ ": gpios parameter: exceeded max array size: %d\n",
+ MAX_GPIOS);
+ return -EINVAL;
+ }
+ }
+ if (fbtft_device_param_gpios[0].name[0])
+ gpio = fbtft_device_param_gpios;
+
+ if (verbose > 2)
+ pr_spi_devices(); /* print list of registered SPI devices */
+
+ if (verbose > 2)
+ pr_p_devices(); /* print list of 'fb' platform devices */
+
+ pr_debug(DRVNAME": name='%s', busnum=%d, cs=%d\n", name, busnum, cs);
+
+ if (rotate > 0 && rotate < 4) {
+ rotate = (4 - rotate) * 90;
+ pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
+ rotate);
+ }
+ if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
+ pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
+ rotate);
+ rotate = 0;
+ }
+
+ /* name=list lists all supported displays */
+ if (strncmp(name, "list", 32) == 0) {
+ pr_info(DRVNAME": Supported displays:\n");
+
+ for (i = 0; i < ARRAY_SIZE(displays); i++)
+ pr_info(DRVNAME": %s\n", displays[i].name);
+ return -ECANCELED;
+ }
+
+ if (custom) {
+ i = ARRAY_SIZE(displays) - 1;
+ displays[i].name = name;
+ if (speed == 0) {
+ displays[i].pdev->name = name;
+ displays[i].spi = NULL;
+ } else {
+ strncpy(displays[i].spi->modalias, name, SPI_NAME_SIZE);
+ displays[i].pdev = NULL;
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(displays); i++) {
+ if (strncmp(name, displays[i].name, 32) == 0) {
+ if (displays[i].spi) {
+ spi = displays[i].spi;
+ spi->chip_select = cs;
+ spi->bus_num = busnum;
+ if (speed)
+ spi->max_speed_hz = speed;
+ if (mode != -1)
+ spi->mode = mode;
+ pdata = (void *)spi->platform_data;
+ } else if (displays[i].pdev) {
+ p_device = displays[i].pdev;
+ pdata = p_device->dev.platform_data;
+ } else {
+ pr_err(DRVNAME": broken displays array\n");
+ return -EINVAL;
+ }
+
+ pdata->rotate = rotate;
+ if (bgr == 0)
+ pdata->bgr = false;
+ else if (bgr == 1)
+ pdata->bgr = true;
+ if (startbyte)
+ pdata->startbyte = startbyte;
+ if (gamma)
+ pdata->gamma = gamma;
+ pdata->display.debug = debug;
+ if (fps)
+ pdata->fps = fps;
+ if (txbuflen)
+ pdata->txbuflen = txbuflen;
+ if (init_num)
+ pdata->display.init_sequence = init;
+ if (gpio)
+ pdata->gpios = gpio;
+ if (custom) {
+ pdata->display.width = width;
+ pdata->display.height = height;
+ pdata->display.buswidth = buswidth;
+ pdata->display.backlight = 1;
+ }
+
+ if (displays[i].spi) {
+ ret = fbtft_device_spi_device_register(spi);
+ if (ret) {
+ pr_err(DRVNAME \
+ ": failed to register SPI device\n");
+ return ret;
+ }
+ found = true;
+ break;
+ } else {
+ ret = platform_device_register(p_device);
+ if (ret < 0) {
+ pr_err(DRVNAME \
+ ": platform_device_register() returned %d\n",
+ ret);
+ return ret;
+ }
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ pr_err(DRVNAME": display not supported: '%s'\n", name);
+ return -EINVAL;
+ }
+
+ if (verbose && pdata && pdata->gpios) {
+ gpio = pdata->gpios;
+ pr_info(DRVNAME": GPIOS used by '%s':\n", name);
+ found = false;
+ while (verbose && gpio->name[0]) {
+ pr_info(DRVNAME": '%s' = GPIO%d\n",
+ gpio->name, gpio->gpio);
+ gpio++;
+ found = true;
+ }
+ if (!found)
+ pr_info(DRVNAME": (none)\n");
+ }
+
+ if (spi_device && (verbose > 1))
+ pr_spi_devices();
+ if (p_device && (verbose > 1))
+ pr_p_devices();
+
+ return 0;
+}
+
+static void __exit fbtft_device_exit(void)
+{
+ pr_debug(DRVNAME" - exit\n");
+
+ if (spi_device) {
+ device_del(&spi_device->dev);
+ kfree(spi_device);
+ }
+
+ if (p_device)
+ platform_device_unregister(p_device);
+
+}
+
+arch_initcall(fbtft_device_init);
+module_exit(fbtft_device_exit);
+
+MODULE_DESCRIPTION("Add a FBTFT device.");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/fbtft/flexfb.c b/drivers/staging/fbtft/flexfb.c
new file mode 100644
index 000000000000..90832c36e557
--- /dev/null
+++ b/drivers/staging/fbtft/flexfb.c
@@ -0,0 +1,592 @@
+/*
+ * Generic FB driver for TFT LCD displays
+ *
+ * Copyright (C) 2013 Noralf Tronnes
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/vmalloc.h>
+#include <linux/gpio.h>
+#include <linux/spi/spi.h>
+#include <linux/delay.h>
+
+#include "fbtft.h"
+
+#define DRVNAME "flexfb"
+
+
+static char *chip;
+module_param(chip, charp, 0);
+MODULE_PARM_DESC(chip, "LCD controller");
+
+static unsigned int width;
+module_param(width, uint, 0);
+MODULE_PARM_DESC(width, "Display width");
+
+static unsigned int height;
+module_param(height, uint, 0);
+MODULE_PARM_DESC(height, "Display height");
+
+static int init[512];
+static int init_num;
+module_param_array(init, int, &init_num, 0);
+MODULE_PARM_DESC(init, "Init sequence");
+
+static unsigned int setaddrwin;
+module_param(setaddrwin, uint, 0);
+MODULE_PARM_DESC(setaddrwin, "Which set_addr_win() implementation to use");
+
+static unsigned int buswidth = 8;
+module_param(buswidth, uint, 0);
+MODULE_PARM_DESC(buswidth, "Width of databus (default: 8)");
+
+static unsigned int regwidth = 8;
+module_param(regwidth, uint, 0);
+MODULE_PARM_DESC(regwidth, "Width of controller register (default: 8)");
+
+static bool nobacklight;
+module_param(nobacklight, bool, 0);
+MODULE_PARM_DESC(nobacklight, "Turn off backlight functionality.");
+
+static bool latched;
+module_param(latched, bool, 0);
+MODULE_PARM_DESC(latched, "Use with latched 16-bit databus");
+
+
+static int *initp;
+static int initp_num;
+
+/* default init sequences */
+static int st7735r_init[] = { \
+-1,0x01,-2,150,-1,0x11,-2,500,-1,0xB1,0x01,0x2C,0x2D,-1,0xB2,0x01,0x2C,0x2D,-1,0xB3,0x01,0x2C,0x2D,0x01,0x2C,0x2D, \
+-1,0xB4,0x07,-1,0xC0,0xA2,0x02,0x84,-1,0xC1,0xC5,-1,0xC2,0x0A,0x00,-1,0xC3,0x8A,0x2A,-1,0xC4,0x8A,0xEE,-1,0xC5,0x0E, \
+-1,0x20,-1,0x36,0xC0,-1,0x3A,0x05,-1,0xE0,0x0f,0x1a,0x0f,0x18,0x2f,0x28,0x20,0x22,0x1f,0x1b,0x23,0x37,0x00,0x07,0x02,0x10, \
+-1,0xE1,0x0f,0x1b,0x0f,0x17,0x33,0x2c,0x29,0x2e,0x30,0x30,0x39,0x3f,0x00,0x07,0x03,0x10,-1,0x29,-2,100,-1,0x13,-2,10,-3 };
+
+static int ssd1289_init[] = { \
+-1,0x00,0x0001,-1,0x03,0xA8A4,-1,0x0C,0x0000,-1,0x0D,0x080C,-1,0x0E,0x2B00,-1,0x1E,0x00B7,-1,0x01,0x2B3F,-1,0x02,0x0600, \
+-1,0x10,0x0000,-1,0x11,0x6070,-1,0x05,0x0000,-1,0x06,0x0000,-1,0x16,0xEF1C,-1,0x17,0x0003,-1,0x07,0x0233,-1,0x0B,0x0000, \
+-1,0x0F,0x0000,-1,0x41,0x0000,-1,0x42,0x0000,-1,0x48,0x0000,-1,0x49,0x013F,-1,0x4A,0x0000,-1,0x4B,0x0000,-1,0x44,0xEF00, \
+-1,0x45,0x0000,-1,0x46,0x013F,-1,0x30,0x0707,-1,0x31,0x0204,-1,0x32,0x0204,-1,0x33,0x0502,-1,0x34,0x0507,-1,0x35,0x0204, \
+-1,0x36,0x0204,-1,0x37,0x0502,-1,0x3A,0x0302,-1,0x3B,0x0302,-1,0x23,0x0000,-1,0x24,0x0000,-1,0x25,0x8000,-1,0x4f,0x0000, \
+-1,0x4e,0x0000,-1,0x22,-3 };
+
+static int hx8340bn_init[] = { \
+-1,0xC1,0xFF,0x83,0x40,-1,0x11,-2,150,-1,0xCA,0x70,0x00,0xD9,-1,0xB0,0x01,0x11, \
+-1,0xC9,0x90,0x49,0x10,0x28,0x28,0x10,0x00,0x06,-2,20,-1,0xC2,0x60,0x71,0x01,0x0E,0x05,0x02,0x09,0x31,0x0A, \
+-1,0xC3,0x67,0x30,0x61,0x17,0x48,0x07,0x05,0x33,-2,10,-1,0xB5,0x35,0x20,0x45,-1,0xB4,0x33,0x25,0x4C,-2,10, \
+-1,0x3A,0x05,-1,0x29,-2,10,-3 };
+
+static int ili9225_init[] = { \
+-1,0x0001,0x011C,-1,0x0002,0x0100,-1,0x0003,0x1030,-1,0x0008,0x0808,-1,0x000C,0x0000,-1,0x000F,0x0A01,-1,0x0020,0x0000, \
+-1,0x0021,0x0000,-2,50,-1,0x0010,0x0A00,-1,0x0011,0x1038,-2,50,-1,0x0012,0x1121,-1,0x0013,0x004E,-1,0x0014,0x676F, \
+-1,0x0030,0x0000,-1,0x0031,0x00DB,-1,0x0032,0x0000,-1,0x0033,0x0000,-1,0x0034,0x00DB,-1,0x0035,0x0000,-1,0x0036,0x00AF, \
+-1,0x0037,0x0000,-1,0x0038,0x00DB,-1,0x0039,0x0000,-1,0x0050,0x0000,-1,0x0051,0x060A,-1,0x0052,0x0D0A,-1,0x0053,0x0303, \
+-1,0x0054,0x0A0D,-1,0x0055,0x0A06,-1,0x0056,0x0000,-1,0x0057,0x0303,-1,0x0058,0x0000,-1,0x0059,0x0000,-2,50, \
+-1,0x0007,0x1017,-2,50,-3 };
+
+static int ili9320_init[] = { \
+-1,0x00E5,0x8000,-1,0x0000,0x0001,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000,-1,0x0008,0x0202, \
+-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000,-1,0x0011,0x0007, \
+-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x17B0,-1,0x0011,0x0031,-2,50,-1,0x0012,0x0138,-2,50,-1,0x0013,0x1800, \
+-1,0x0029,0x0008,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000,-1,0x0031,0x0505,-1,0x0032,0x0004, \
+-1,0x0035,0x0006,-1,0x0036,0x0707,-1,0x0037,0x0105,-1,0x0038,0x0002,-1,0x0039,0x0707,-1,0x003C,0x0704,-1,0x003D,0x0807, \
+-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0x2700,-1,0x0061,0x0001,-1,0x006A,0x0000, \
+-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000,-1,0x0085,0x0000,-1,0x0090,0x0010, \
+-1,0x0092,0x0000,-1,0x0093,0x0003,-1,0x0095,0x0110,-1,0x0097,0x0000,-1,0x0098,0x0000,-1,0x0007,0x0173,-3 };
+
+static int ili9325_init[] = { \
+-1,0x00E3,0x3008,-1,0x00E7,0x0012,-1,0x00EF,0x1231,-1,0x0001,0x0100,-1,0x0002,0x0700,-1,0x0003,0x1030,-1,0x0004,0x0000, \
+-1,0x0008,0x0207,-1,0x0009,0x0000,-1,0x000A,0x0000,-1,0x000C,0x0000,-1,0x000D,0x0000,-1,0x000F,0x0000,-1,0x0010,0x0000, \
+-1,0x0011,0x0007,-1,0x0012,0x0000,-1,0x0013,0x0000,-2,200,-1,0x0010,0x1690,-1,0x0011,0x0223,-2,50,-1,0x0012,0x000D,-2,50, \
+-1,0x0013,0x1200,-1,0x0029,0x000A,-1,0x002B,0x000C,-2,50,-1,0x0020,0x0000,-1,0x0021,0x0000,-1,0x0030,0x0000, \
+-1,0x0031,0x0506,-1,0x0032,0x0104,-1,0x0035,0x0207,-1,0x0036,0x000F,-1,0x0037,0x0306,-1,0x0038,0x0102,-1,0x0039,0x0707, \
+-1,0x003C,0x0702,-1,0x003D,0x1604,-1,0x0050,0x0000,-1,0x0051,0x00EF,-1,0x0052,0x0000,-1,0x0053,0x013F,-1,0x0060,0xA700, \
+-1,0x0061,0x0001,-1,0x006A,0x0000,-1,0x0080,0x0000,-1,0x0081,0x0000,-1,0x0082,0x0000,-1,0x0083,0x0000,-1,0x0084,0x0000, \
+-1,0x0085,0x0000,-1,0x0090,0x0010,-1,0x0092,0x0600,-1,0x0007,0x0133,-3 };
+
+static int ili9341_init[] = { \
+-1,0x28,-2,20,-1,0xCF,0x00,0x83,0x30,-1,0xED,0x64,0x03,0x12,0x81,-1,0xE8,0x85,0x01,0x79, \
+-1,0xCB,0x39,0x2c,0x00,0x34,0x02,-1,0xF7,0x20,-1,0xEA,0x00,0x00,-1,0xC0,0x26,-1,0xC1,0x11, \
+-1,0xC5,0x35,0x3E,-1,0xC7,0xBE,-1,0xB1,0x00,0x1B,-1,0xB6,0x0a,0x82,0x27,0x00,-1,0xB7,0x07, \
+-1,0x3A,0x55,-1,0x36,0x48,-1,0x11,-2,120,-1,0x29,-2,20,-3 };
+
+static int ssd1351_init[] = { -1,0xfd,0x12,-1,0xfd,0xb1,-1,0xae,-1,0xb3,0xf1,-1,0xca,0x7f,-1,0xa0,0x74, \
+ -1,0x15,0x00,0x7f,-1,0x75,0x00,0x7f,-1,0xa1,0x00,-1,0xa2,0x00,-1,0xb5,0x00, \
+ -1,0xab,0x01,-1,0xb1,0x32,-1,0xb4,0xa0,0xb5,0x55,-1,0xbb,0x17,-1,0xbe,0x05, \
+ -1,0xc1,0xc8,0x80,0xc8,-1,0xc7,0x0f,-1,0xb6,0x01,-1,0xa6,-1,0xaf,-3 };
+
+
+/* ili9320, ili9325 */
+static void flexfb_set_addr_win_1(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+ switch (par->info->var.rotate) {
+ /* R20h = Horizontal GRAM Start Address */
+ /* R21h = Vertical GRAM Start Address */
+ case 0:
+ write_reg(par, 0x0020, xs);
+ write_reg(par, 0x0021, ys);
+ break;
+ case 180:
+ write_reg(par, 0x0020, width - 1 - xs);
+ write_reg(par, 0x0021, height - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x0020, width - 1 - ys);
+ write_reg(par, 0x0021, xs);
+ break;
+ case 90:
+ write_reg(par, 0x0020, ys);
+ write_reg(par, 0x0021, height - 1 - xs);
+ break;
+ }
+ write_reg(par, 0x0022); /* Write Data to GRAM */
+}
+
+/* ssd1289 */
+static void flexfb_set_addr_win_2(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ switch (par->info->var.rotate) {
+ /* R4Eh - Set GDDRAM X address counter */
+ /* R4Fh - Set GDDRAM Y address counter */
+ case 0:
+ write_reg(par, 0x4e, xs);
+ write_reg(par, 0x4f, ys);
+ break;
+ case 180:
+ write_reg(par, 0x4e, par->info->var.xres - 1 - xs);
+ write_reg(par, 0x4f, par->info->var.yres - 1 - ys);
+ break;
+ case 270:
+ write_reg(par, 0x4e, par->info->var.yres - 1 - ys);
+ write_reg(par, 0x4f, xs);
+ break;
+ case 90:
+ write_reg(par, 0x4e, ys);
+ write_reg(par, 0x4f, par->info->var.xres - 1 - xs);
+ break;
+ }
+
+ /* R22h - RAM data write */
+ write_reg(par, 0x22, 0);
+}
+
+/* ssd1351 */
+static void set_addr_win_3(struct fbtft_par *par, int xs, int ys, int xe, int ye)
+{
+ fbtft_par_dbg(DEBUG_SET_ADDR_WIN, par, "%s(xs=%d, ys=%d, xe=%d, ye=%d)\n", __func__, xs, ys, xe, ye);
+
+ write_reg(par, 0x15, xs, xe);
+ write_reg(par, 0x75, ys, ye);
+ write_reg(par, 0x5C);
+}
+
+static int flexfb_verify_gpios_dc(struct fbtft_par *par)
+{
+ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
+
+ if (par->gpio.dc < 0) {
+ dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int flexfb_verify_gpios_db(struct fbtft_par *par)
+{
+ int i;
+ int num_db = buswidth;
+
+ fbtft_par_dbg(DEBUG_VERIFY_GPIOS, par, "%s()\n", __func__);
+
+ if (par->gpio.dc < 0) {
+ dev_err(par->info->device, "Missing info about 'dc' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ if (par->gpio.wr < 0) {
+ dev_err(par->info->device, "Missing info about 'wr' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ if (latched && (par->gpio.latch < 0)) {
+ dev_err(par->info->device, "Missing info about 'latch' gpio. Aborting.\n");
+ return -EINVAL;
+ }
+ if (latched)
+ num_db=buswidth/2;
+ for (i=0;i < num_db;i++) {
+ if (par->gpio.db[i] < 0) {
+ dev_err(par->info->device, "Missing info about 'db%02d' gpio. Aborting.\n", i);
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+static struct fbtft_display flex_display = { };
+
+static int flexfb_probe_common(struct spi_device *sdev, struct platform_device *pdev)
+{
+ struct device *dev;
+ struct fb_info *info;
+ struct fbtft_par *par;
+ int ret;
+
+ initp = init;
+ initp_num = init_num;
+
+ if (sdev)
+ dev = &sdev->dev;
+ else
+ dev = &pdev->dev;
+
+ fbtft_init_dbg(dev, "%s(%s)\n", __func__, sdev ? "'SPI device'" : "'Platform device'");
+
+ if (chip) {
+
+ if (!strcmp(chip, "st7735r")) {
+ if (!width)
+ width = 128;
+ if (!height)
+ height = 160;
+ if (init_num == 0) {
+ initp = st7735r_init;
+ initp_num = ARRAY_SIZE(st7735r_init);
+ }
+
+
+ } else if (!strcmp(chip, "hx8340bn")) {
+ if (!width)
+ width = 176;
+ if (!height)
+ height = 220;
+ setaddrwin = 0;
+ if (init_num == 0) {
+ initp = hx8340bn_init;
+ initp_num = ARRAY_SIZE(hx8340bn_init);
+ }
+
+
+ } else if (!strcmp(chip, "ili9225")) {
+ if (!width)
+ width = 176;
+ if (!height)
+ height = 220;
+ setaddrwin = 0;
+ regwidth = 16;
+ if (init_num == 0) {
+ initp = ili9225_init;
+ initp_num = ARRAY_SIZE(ili9225_init);
+ }
+
+
+
+ } else if (!strcmp(chip, "ili9320")) {
+ if (!width)
+ width = 240;
+ if (!height)
+ height = 320;
+ setaddrwin = 1;
+ regwidth = 16;
+ if (init_num == 0) {
+ initp = ili9320_init;
+ initp_num = ARRAY_SIZE(ili9320_init);
+ }
+
+
+ } else if (!strcmp(chip, "ili9325")) {
+ if (!width)
+ width = 240;
+ if (!height)
+ height = 320;
+ setaddrwin = 1;
+ regwidth = 16;
+ if (init_num == 0) {
+ initp = ili9325_init;
+ initp_num = ARRAY_SIZE(ili9325_init);
+ }
+
+ } else if (!strcmp(chip, "ili9341")) {
+ if (!width)
+ width = 240;
+ if (!height)
+ height = 320;
+ setaddrwin = 0;
+ regwidth = 8;
+ if (init_num == 0) {
+ initp = ili9341_init;
+ initp_num = ARRAY_SIZE(ili9341_init);
+ }
+
+
+ } else if (!strcmp(chip, "ssd1289")) {
+ if (!width)
+ width = 240;
+ if (!height)
+ height = 320;
+ setaddrwin = 2;
+ regwidth = 16;
+ if (init_num == 0) {
+ initp = ssd1289_init;
+ initp_num = ARRAY_SIZE(ssd1289_init);
+ }
+
+
+
+ } else if (!strcmp(chip, "ssd1351")) {
+ if (!width)
+ width = 128;
+ if (!height)
+ height = 128;
+ setaddrwin = 3;
+ if (init_num == 0) {
+ initp = ssd1351_init;
+ initp_num = ARRAY_SIZE(ssd1351_init);
+ }
+ } else {
+ dev_err(dev, "chip=%s is not supported\n", chip);
+ return -EINVAL;
+ }
+ }
+
+ if (width == 0 || height == 0) {
+ dev_err(dev, "argument(s) missing: width and height has to be set.\n");
+ return -EINVAL;
+ }
+ flex_display.width = width;
+ flex_display.height = height;
+ fbtft_init_dbg(dev, "Display resolution: %dx%d\n", width, height);
+ fbtft_init_dbg(dev, "chip = %s\n", chip ? chip : "not set");
+ fbtft_init_dbg(dev, "setaddrwin = %d\n", setaddrwin);
+ fbtft_init_dbg(dev, "regwidth = %d\n", regwidth);
+ fbtft_init_dbg(dev, "buswidth = %d\n", buswidth);
+
+ info = fbtft_framebuffer_alloc(&flex_display, dev);
+ if (!info)
+ return -ENOMEM;
+
+ par = info->par;
+ if (sdev)
+ par->spi = sdev;
+ else
+ par->pdev = pdev;
+ if (!par->init_sequence)
+ par->init_sequence = initp;
+ par->fbtftops.init_display = fbtft_init_display;
+
+ /* registerwrite functions */
+ switch (regwidth) {
+ case 8:
+ par->fbtftops.write_register = fbtft_write_reg8_bus8;
+ break;
+ case 16:
+ par->fbtftops.write_register = fbtft_write_reg16_bus8;
+ break;
+ default:
+ dev_err(dev, "argument 'regwidth': %d is not supported.\n", regwidth);
+ return -EINVAL;
+ }
+
+ /* bus functions */
+ if (sdev) {
+ par->fbtftops.write = fbtft_write_spi;
+ switch (buswidth) {
+ case 8:
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+ if (!par->startbyte)
+ par->fbtftops.verify_gpios = flexfb_verify_gpios_dc;
+ break;
+ case 9:
+ if (regwidth == 16) {
+ dev_err(dev, "argument 'regwidth': %d is not supported with buswidth=%d and SPI.\n", regwidth, buswidth);
+ return -EINVAL;
+ }
+ par->fbtftops.write_register = fbtft_write_reg8_bus9;
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus9;
+ sdev->bits_per_word=9;
+ ret = sdev->master->setup(sdev);
+ if (ret) {
+ dev_warn(dev,
+ "9-bit SPI not available, emulating using 8-bit.\n");
+ sdev->bits_per_word = 8;
+ ret = sdev->master->setup(sdev);
+ if (ret)
+ goto out_release;
+ /* allocate buffer with room for dc bits */
+ par->extra = devm_kzalloc(par->info->device,
+ par->txbuf.len + (par->txbuf.len / 8) + 8,
+ GFP_KERNEL);
+ if (!par->extra) {
+ ret = -ENOMEM;
+ goto out_release;
+ }
+ par->fbtftops.write = fbtft_write_spi_emulate_9;
+ }
+ break;
+ default:
+ dev_err(dev, "argument 'buswidth': %d is not supported with SPI.\n", buswidth);
+ return -EINVAL;
+ }
+ } else {
+ par->fbtftops.verify_gpios = flexfb_verify_gpios_db;
+ switch (buswidth) {
+ case 8:
+ par->fbtftops.write = fbtft_write_gpio8_wr;
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus8;
+ break;
+ case 16:
+ par->fbtftops.write_register = fbtft_write_reg16_bus16;
+ if (latched)
+ par->fbtftops.write = fbtft_write_gpio16_wr_latched;
+ else
+ par->fbtftops.write = fbtft_write_gpio16_wr;
+ par->fbtftops.write_vmem = fbtft_write_vmem16_bus16;
+ break;
+ default:
+ dev_err(dev, "argument 'buswidth': %d is not supported with parallel.\n", buswidth);
+ return -EINVAL;
+ }
+ }
+
+ /* set_addr_win function */
+ switch (setaddrwin) {
+ case 0:
+ /* use default */
+ break;
+ case 1:
+ par->fbtftops.set_addr_win = flexfb_set_addr_win_1;
+ break;
+ case 2:
+ par->fbtftops.set_addr_win = flexfb_set_addr_win_2;
+ break;
+ case 3:
+ par->fbtftops.set_addr_win = set_addr_win_3;
+ break;
+ default:
+ dev_err(dev, "argument 'setaddrwin': unknown value %d.\n", setaddrwin);
+ return -EINVAL;
+ }
+
+ if (!nobacklight)
+ par->fbtftops.register_backlight = fbtft_register_backlight;
+
+ ret = fbtft_register_framebuffer(info);
+ if (ret < 0)
+ goto out_release;
+
+ return 0;
+
+out_release:
+ fbtft_framebuffer_release(info);
+
+ return ret;
+}
+
+static int flexfb_remove_common(struct device *dev, struct fb_info *info)
+{
+ struct fbtft_par *par;
+
+ if (!info)
+ return -EINVAL;
+ par = info->par;
+ if (par)
+ fbtft_par_dbg(DEBUG_DRIVER_INIT_FUNCTIONS, par,
+ "%s()\n", __func__);
+ fbtft_unregister_framebuffer(info);
+ fbtft_framebuffer_release(info);
+
+ return 0;
+}
+
+static int flexfb_probe_spi(struct spi_device *spi)
+{
+ return flexfb_probe_common(spi, NULL);
+}
+
+static int flexfb_remove_spi(struct spi_device *spi)
+{
+ struct fb_info *info = spi_get_drvdata(spi);
+
+ return flexfb_remove_common(&spi->dev, info);
+}
+
+static int flexfb_probe_pdev(struct platform_device *pdev)
+{
+ return flexfb_probe_common(NULL, pdev);
+}
+
+static int flexfb_remove_pdev(struct platform_device *pdev)
+{
+ struct fb_info *info = platform_get_drvdata(pdev);
+
+ return flexfb_remove_common(&pdev->dev, info);
+}
+
+static struct spi_driver flexfb_spi_driver = {
+ .driver = {
+ .name = DRVNAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = flexfb_probe_spi,
+ .remove = flexfb_remove_spi,
+};
+
+static const struct platform_device_id flexfb_platform_ids[] = {
+ { "flexpfb", 0 },
+ { },
+};
+
+static struct platform_driver flexfb_platform_driver = {
+ .driver = {
+ .name = DRVNAME,
+ },
+ .id_table = flexfb_platform_ids,
+ .probe = flexfb_probe_pdev,
+ .remove = flexfb_remove_pdev,
+};
+
+static int __init flexfb_init(void)
+{
+ int ret, ret2;
+
+ ret = spi_register_driver(&flexfb_spi_driver);
+ ret2 = platform_driver_register(&flexfb_platform_driver);
+ if (ret < 0)
+ return ret;
+ return ret2;
+}
+
+static void __exit flexfb_exit(void)
+{
+ spi_unregister_driver(&flexfb_spi_driver);
+ platform_driver_unregister(&flexfb_platform_driver);
+}
+
+/* ------------------------------------------------------------------------- */
+
+module_init(flexfb_init);
+module_exit(flexfb_exit);
+
+MODULE_DESCRIPTION("Generic FB driver for TFT LCD displays");
+MODULE_AUTHOR("Noralf Tronnes");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
index d5475b7270a8..017c3b92f51b 100644
--- a/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-pcmcia/ft1000_hw.c
@@ -172,11 +172,11 @@ u16 ft1000_read_dpram_mag_16(struct net_device *dev, int offset, int Index)
spin_lock_irqsave(&info->dpram_lock, flags);
ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, offset);
/* check if we want to read upper or lower 32-bit word */
- if (Index) {
+ if (Index)
data = ft1000_read_reg(dev, FT1000_REG_MAG_DPDATAL);
- } else {
+ else
data = ft1000_read_reg(dev, FT1000_REG_MAG_DPDATAH);
- }
+
spin_unlock_irqrestore(&info->dpram_lock, flags);
return data;
@@ -204,11 +204,11 @@ static inline void ft1000_write_dpram_mag_16(struct net_device *dev,
/* Provide mutual exclusive access while reading ASIC registers. */
spin_lock_irqsave(&info->dpram_lock, flags);
ft1000_write_reg(dev, FT1000_REG_DPRAM_ADDR, offset);
- if (Index) {
+ if (Index)
ft1000_write_reg(dev, FT1000_REG_MAG_DPDATAL, value);
- } else {
+ else
ft1000_write_reg(dev, FT1000_REG_MAG_DPDATAH, value);
- }
+
spin_unlock_irqrestore(&info->dpram_lock, flags);
}
@@ -440,9 +440,8 @@ static int ft1000_reset_card(struct net_device *dev)
tempword =
ft1000_read_dpram_mag_16(dev, FT1000_MAG_DPRAM_FEFE,
FT1000_MAG_DPRAM_FEFE_INDX);
- if (tempword == 0xfefe) {
+ if (tempword == 0xfefe)
break;
- }
mdelay(20);
}
@@ -570,12 +569,12 @@ static void ft1000_hbchk(u_long data)
pr_debug("hi_ho value = 0x%x\n", tempword);
/* Let's perform another check if ho is not detected */
if (tempword != ho) {
- if (info->AsicID == ELECTRABUZZ_ID) {
+ if (info->AsicID == ELECTRABUZZ_ID)
tempword = ft1000_read_dpram(dev, FT1000_HI_HO);
- }
- else {
- tempword = ntohs(ft1000_read_dpram_mag_16(dev, FT1000_MAG_HI_HO, FT1000_MAG_HI_HO_INDX));
- }
+ else
+ tempword = ntohs(ft1000_read_dpram_mag_16(dev,
+ FT1000_MAG_HI_HO,
+ FT1000_MAG_HI_HO_INDX));
}
if (tempword != ho) {
pr_info("heartbeat failed - no ho detected\n");
@@ -621,9 +620,9 @@ static void ft1000_hbchk(u_long data)
tempword = ft1000_read_reg(dev, FT1000_REG_DOORBELL);
/* Let's check doorbell again if fail */
- if (tempword & FT1000_DB_HB) {
+ if (tempword & FT1000_DB_HB)
tempword = ft1000_read_reg(dev, FT1000_REG_DOORBELL);
- }
+
if (tempword & FT1000_DB_HB) {
pr_info("heartbeat doorbell not clear by firmware\n");
if (info->AsicID == ELECTRABUZZ_ID) {
@@ -686,19 +685,15 @@ static void ft1000_hbchk(u_long data)
}
/* Let's write hi again if fail */
if (tempword != hi) {
- if (info->AsicID == ELECTRABUZZ_ID) {
+ if (info->AsicID == ELECTRABUZZ_ID)
ft1000_write_dpram(dev, FT1000_HI_HO, hi);
- }
- else {
+ else
ft1000_write_dpram_mag_16(dev, FT1000_MAG_HI_HO, hi_mag, FT1000_MAG_HI_HO_INDX);
- }
- if (info->AsicID == ELECTRABUZZ_ID) {
+ if (info->AsicID == ELECTRABUZZ_ID)
tempword = ft1000_read_dpram(dev, FT1000_HI_HO);
- }
- else {
+ else
tempword = ntohs(ft1000_read_dpram_mag_16(dev, FT1000_MAG_HI_HO, FT1000_MAG_HI_HO_INDX));
- }
}
@@ -770,9 +765,8 @@ static void ft1000_send_cmd(struct net_device *dev, u16 *ptempbuffer, int size,
size += sizeof(struct pseudo_hdr);
/* check for odd byte and increment to 16-bit word align value */
- if ((size & 0x0001)) {
+ if ((size & 0x0001))
size++;
- }
pr_debug("total length = %d\n", size);
pr_debug("length = %d\n", ntohs(*ptempbuffer));
/*
@@ -915,9 +909,8 @@ static bool ft1000_receive_cmd(struct net_device *dev, u16 *pbuffer,
* Calculate pseudo header checksum
*/
tempword = *ppseudohdr++;
- for (i = 1; i < 7; i++) {
+ for (i = 1; i < 7; i++)
tempword ^= *ppseudohdr++;
- }
if ((tempword != *ppseudohdr)) {
pr_debug("Pseudo header checksum mismatch\n");
/* Drop this message */
@@ -957,12 +950,11 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
u16 wrd;
} convert;
- if (info->AsicID == ELECTRABUZZ_ID) {
+ if (info->AsicID == ELECTRABUZZ_ID)
tempword = FT1000_DPRAM_RX_BASE+2;
- }
- else {
+ else
tempword = FT1000_DPRAM_MAG_RX_BASE;
- }
+
if (ft1000_receive_cmd(dev, &cmdbuffer[0], MAX_CMD_SQSIZE, &tempword)) {
/* Get the message type which is total_len + PSEUDO header + msgtype + message body */
@@ -982,9 +974,8 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
while (tempword & FT1000_DB_DPRAM_TX) {
mdelay(5);
i++;
- if (i == 10) {
+ if (i == 10)
break;
- }
}
ptr =
list_entry(info->prov_list.next,
@@ -1039,8 +1030,7 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
info->ConTm = 0;
}
}
- }
- else {
+ } else {
pr_debug("Media is down\n");
if (info->mediastate == 1) {
info->mediastate = 0;
@@ -1105,9 +1095,8 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
mdelay(10);
tempword =
ft1000_read_reg(dev, FT1000_REG_DOORBELL);
- if (tempword & FT1000_DB_DPRAM_TX) {
+ if (tempword & FT1000_DB_DPRAM_TX)
mdelay(10);
- }
}
if ((tempword & FT1000_DB_DPRAM_TX) == 0) {
@@ -1134,9 +1123,9 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
ppseudo_hdr->portsrc = 0;
/* Calculate new checksum */
ppseudo_hdr->checksum = *pmsg++;
- for (i = 1; i < 7; i++) {
+ for (i = 1; i < 7; i++)
ppseudo_hdr->checksum ^= *pmsg++;
- }
+
info->DSPInfoBlk[8] = 0x7200;
info->DSPInfoBlk[9] =
htons(info->DSPInfoBlklen);
@@ -1156,9 +1145,8 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
mdelay(10);
tempword =
ft1000_read_reg(dev, FT1000_REG_DOORBELL);
- if (tempword & FT1000_DB_DPRAM_TX) {
+ if (tempword & FT1000_DB_DPRAM_TX)
mdelay(10);
- }
}
if ((tempword & FT1000_DB_DPRAM_TX) == 0) {
@@ -1184,9 +1172,9 @@ static void ft1000_proc_drvmsg(struct net_device *dev)
ppseudo_hdr->portsrc = 0;
/* Calculate new checksum */
ppseudo_hdr->checksum = *pmsg++;
- for (i = 1; i < 7; i++) {
+ for (i = 1; i < 7; i++)
ppseudo_hdr->checksum ^= *pmsg++;
- }
+
pmsg = (u16 *)&tempbuffer[16];
*pmsg++ = htons(RSP_DRV_ERR_RPT_MSG);
*pmsg++ = htons(0x000e);
@@ -1508,9 +1496,8 @@ static void ft1000_flush_fifo(struct net_device *dev, u16 DrvErrNum)
tempword = inw(dev->base_addr + FT1000_REG_MAG_DFSR);
pr_debug("FT1000_REG_MAG_DFSR = 0x%x\n", tempword);
}
- if (DrvErrNum) {
+ if (DrvErrNum)
pcmcia->PktIntfErr++;
- }
}
}
@@ -1567,9 +1554,9 @@ static int ft1000_copy_up_pkt(struct net_device *dev)
if (skb == NULL) {
pr_debug("No Network buffers available\n");
/* Read High word to complete 32 bit access */
- if (info->AsicID == MAGNEMITE_ID) {
+ if (info->AsicID == MAGNEMITE_ID)
tempword = ft1000_read_reg(dev, FT1000_REG_MAG_DFRH);
- }
+
ft1000_flush_fifo(dev, 0);
info->stats.rx_errors++;
return FAILURE;
@@ -1673,9 +1660,8 @@ static int ft1000_copy_up_pkt(struct net_device *dev)
}
pr_debug("Data passed to Protocol layer:\n");
- for (i = 0; i < len + 12; i++) {
+ for (i = 0; i < len + 12; i++)
pr_debug("Protocol Data: 0x%x\n", *ptemp++);
- }
skb->dev = dev;
skb->protocol = eth_type_trans(skb, dev);
@@ -1729,21 +1715,16 @@ static int ft1000_copy_down_pkt(struct net_device *dev, u16 *packet, u16 len)
/* Check if there is room on the FIFO */
if (len > ft1000_read_fifo_len(dev)) {
udelay(10);
- if (len > ft1000_read_fifo_len(dev)) {
+ if (len > ft1000_read_fifo_len(dev))
udelay(20);
- }
- if (len > ft1000_read_fifo_len(dev)) {
+ if (len > ft1000_read_fifo_len(dev))
udelay(20);
- }
- if (len > ft1000_read_fifo_len(dev)) {
+ if (len > ft1000_read_fifo_len(dev))
udelay(20);
- }
- if (len > ft1000_read_fifo_len(dev)) {
+ if (len > ft1000_read_fifo_len(dev))
udelay(20);
- }
- if (len > ft1000_read_fifo_len(dev)) {
+ if (len > ft1000_read_fifo_len(dev))
udelay(20);
- }
if (len > ft1000_read_fifo_len(dev)) {
pr_debug("Transmit FIFO is full - pkt drop\n");
info->stats.tx_errors++;
@@ -1751,11 +1732,11 @@ static int ft1000_copy_down_pkt(struct net_device *dev, u16 *packet, u16 len)
}
}
/* Create pseudo header and send pseudo/ip to hardware */
- if (info->AsicID == ELECTRABUZZ_ID) {
+ if (info->AsicID == ELECTRABUZZ_ID)
pseudo.blk.length = len;
- } else {
+ else
pseudo.blk.length = ntohs(len);
- }
+
pseudo.blk.source = DSPID; /* Need to swap to get in correct order */
pseudo.blk.destination = HOSTID;
pseudo.blk.portdest = NETWORKID; /* Need to swap to get in correct order */
@@ -1768,9 +1749,8 @@ static int ft1000_copy_down_pkt(struct net_device *dev, u16 *packet, u16 len)
pseudo.blk.qos_class = 0;
/* Calculate pseudo header checksum */
pseudo.blk.checksum = pseudo.buff[0];
- for (i = 1; i < 7; i++) {
+ for (i = 1; i < 7; i++)
pseudo.blk.checksum ^= pseudo.buff[i];
- }
/* Production Mode */
if (info->AsicID == ELECTRABUZZ_ID) {
@@ -1835,9 +1815,8 @@ static int ft1000_copy_down_pkt(struct net_device *dev, u16 *packet, u16 len)
plong = (u32 *)packet;
/* Write PPP type + IP Packet into Downlink FIFO */
- for (i = 0; i < (len >> 2); i++) {
+ for (i = 0; i < (len >> 2); i++)
outl(*plong++, dev->base_addr + FT1000_REG_MAG_UFDR);
- }
/* Check for odd alignment */
if (len & 0x0003) {
diff --git a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
index d12cfc9aa32a..f0ac43838461 100644
--- a/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
+++ b/drivers/staging/ft1000/ft1000-usb/ft1000_hw.c
@@ -332,15 +332,15 @@ int card_send_command(struct ft1000_usb *ft1000dev, void *ptempbuffer,
pr_debug("enter card_send_command... size=%d\n", size);
+ ret = ft1000_read_register(ft1000dev, &temp, FT1000_REG_DOORBELL);
+ if (ret)
+ return ret;
+
commandbuf = kmalloc(size + 2, GFP_KERNEL);
if (!commandbuf)
return -ENOMEM;
memcpy((void *)commandbuf + 2, (void *)ptempbuffer, size);
- ret = ft1000_read_register(ft1000dev, &temp, FT1000_REG_DOORBELL);
- if (ret)
- return ret;
-
if (temp & 0x0100)
usleep_range(900, 1100);
diff --git a/drivers/staging/gdm724x/gdm_lte.c b/drivers/staging/gdm724x/gdm_lte.c
index 73eede163820..7c4a77bb94aa 100644
--- a/drivers/staging/gdm724x/gdm_lte.c
+++ b/drivers/staging/gdm724x/gdm_lte.c
@@ -281,7 +281,8 @@ static int gdm_lte_emulate_ndp(struct sk_buff *skb_in, u32 nic_type)
icmp6_out.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT;
icmp6_out.icmp6_code = 0;
icmp6_out.icmp6_cksum = 0;
- icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000); /* R=0, S=1, O=1 */
+ /* R=0, S=1, O=1 */
+ icmp6_out.icmp6_dataun.un_data32[0] = htonl(0x60000000);
ns = (struct neighbour_solicitation *)
(skb_in->data + mac_header_len +
diff --git a/drivers/staging/gdm724x/gdm_mux.c b/drivers/staging/gdm724x/gdm_mux.c
index b5b063a738f8..d1ab996b3305 100644
--- a/drivers/staging/gdm724x/gdm_mux.c
+++ b/drivers/staging/gdm724x/gdm_mux.c
@@ -220,7 +220,7 @@ static int up_to_host(struct mux_rx *r)
static void do_rx(struct work_struct *work)
{
struct mux_dev *mux_dev =
- container_of(work, struct mux_dev , work_rx.work);
+ container_of(work, struct mux_dev, work_rx.work);
struct mux_rx *r;
struct rx_cxt *rx = (struct rx_cxt *)&mux_dev->rx;
unsigned long flags;
diff --git a/drivers/staging/gs_fpgaboot/io.c b/drivers/staging/gs_fpgaboot/io.c
index b260e45c6698..819db53da64d 100644
--- a/drivers/staging/gs_fpgaboot/io.c
+++ b/drivers/staging/gs_fpgaboot/io.c
@@ -79,15 +79,6 @@ void xl_shift_bytes_out(enum wbus bus_byte, unsigned char *pdata)
/*
* generic bit swap for xilinx SYSTEMMAP FPGA programming
*/
-static inline unsigned char bitswap(unsigned char s)
-{
- unsigned char d;
-
- d = (((s&0x80)>>7) | ((s&0x40)>>5) | ((s&0x20)>>3) | ((s&0x10)>>1) |
- ((s&0x08)<<1) | ((s&0x04)<<3) | ((s&0x02)<<5) | ((s&0x01)<<7));
- return d;
-}
-
void xl_program_b(int32_t i)
{
}
diff --git a/drivers/staging/i2o/Kconfig b/drivers/staging/i2o/Kconfig
new file mode 100644
index 000000000000..286c53f4b13d
--- /dev/null
+++ b/drivers/staging/i2o/Kconfig
@@ -0,0 +1,120 @@
+menuconfig I2O
+ tristate "I2O device support"
+ depends on PCI
+ ---help---
+ The Intelligent Input/Output (I2O) architecture allows hardware
+ drivers to be split into two parts: an operating system specific
+ module called the OSM and an hardware specific module called the
+ HDM. The OSM can talk to a whole range of HDM's, and ideally the
+ HDM's are not OS dependent. This allows for the same HDM driver to
+ be used under different operating systems if the relevant OSM is in
+ place. In order for this to work, you need to have an I2O interface
+ adapter card in your computer. This card contains a special I/O
+ processor (IOP), thus allowing high speeds since the CPU does not
+ have to deal with I/O.
+
+ If you say Y here, you will get a choice of interface adapter
+ drivers and OSM's with the following questions.
+
+ To compile this support as a module, choose M here: the
+ modules will be called i2o_core.
+
+ If unsure, say N.
+
+if I2O
+
+config I2O_LCT_NOTIFY_ON_CHANGES
+ bool "Enable LCT notification"
+ default y
+ ---help---
+ Only say N here if you have a I2O controller from SUN. The SUN
+ firmware doesn't support LCT notification on changes. If this option
+ is enabled on such a controller the driver will hang up in a endless
+ loop. On all other controllers say Y.
+
+ If unsure, say Y.
+
+config I2O_EXT_ADAPTEC
+ bool "Enable Adaptec extensions"
+ default y
+ ---help---
+ Say Y for support of raidutils for Adaptec I2O controllers. You also
+ have to say Y to "I2O Configuration support", "I2O SCSI OSM" below
+ and to "SCSI generic support" under "SCSI device configuration".
+
+config I2O_EXT_ADAPTEC_DMA64
+ bool "Enable 64-bit DMA"
+ depends on I2O_EXT_ADAPTEC && ( 64BIT || HIGHMEM64G )
+ default y
+ ---help---
+ Say Y for support of 64-bit DMA transfer mode on Adaptec I2O
+ controllers.
+ Note: You need at least firmware version 3709.
+
+config I2O_CONFIG
+ tristate "I2O Configuration support"
+ depends on VIRT_TO_BUS
+ ---help---
+ Say Y for support of the configuration interface for the I2O adapters.
+ If you have a RAID controller from Adaptec and you want to use the
+ raidutils to manage your RAID array, you have to say Y here.
+
+ To compile this support as a module, choose M here: the
+ module will be called i2o_config.
+
+ Note: If you want to use the new API you have to download the
+ i2o_config patch from http://i2o.shadowconnect.com/
+
+config I2O_CONFIG_OLD_IOCTL
+ bool "Enable ioctls (OBSOLETE)"
+ depends on I2O_CONFIG
+ default y
+ ---help---
+ Enables old ioctls.
+
+config I2O_BUS
+ tristate "I2O Bus Adapter OSM"
+ ---help---
+ Include support for the I2O Bus Adapter OSM. The Bus Adapter OSM
+ provides access to the busses on the I2O controller. The main purpose
+ is to rescan the bus to find new devices.
+
+ To compile this support as a module, choose M here: the
+ module will be called i2o_bus.
+
+config I2O_BLOCK
+ tristate "I2O Block OSM"
+ depends on BLOCK
+ ---help---
+ Include support for the I2O Block OSM. The Block OSM presents disk
+ and other structured block devices to the operating system. If you
+ are using an RAID controller, you could access the array only by
+ the Block OSM driver. But it is possible to access the single disks
+ by the SCSI OSM driver, for example to monitor the disks.
+
+ To compile this support as a module, choose M here: the
+ module will be called i2o_block.
+
+config I2O_SCSI
+ tristate "I2O SCSI OSM"
+ depends on SCSI
+ ---help---
+ Allows direct SCSI access to SCSI devices on a SCSI or FibreChannel
+ I2O controller. You can use both the SCSI and Block OSM together if
+ you wish. To access a RAID array, you must use the Block OSM driver.
+ But you could use the SCSI OSM driver to monitor the single disks.
+
+ To compile this support as a module, choose M here: the
+ module will be called i2o_scsi.
+
+config I2O_PROC
+ tristate "I2O /proc support"
+ ---help---
+ If you say Y here and to "/proc file system support", you will be
+ able to read I2O related information from the virtual directory
+ /proc/i2o.
+
+ To compile this support as a module, choose M here: the
+ module will be called i2o_proc.
+
+endif # I2O
diff --git a/drivers/message/i2o/Makefile b/drivers/staging/i2o/Makefile
index b0982dacfd0a..b0982dacfd0a 100644
--- a/drivers/message/i2o/Makefile
+++ b/drivers/staging/i2o/Makefile
diff --git a/drivers/message/i2o/README b/drivers/staging/i2o/README
index f072a8eb3041..f072a8eb3041 100644
--- a/drivers/message/i2o/README
+++ b/drivers/staging/i2o/README
diff --git a/drivers/message/i2o/README.ioctl b/drivers/staging/i2o/README.ioctl
index 4a7d2ebdfc97..4a7d2ebdfc97 100644
--- a/drivers/message/i2o/README.ioctl
+++ b/drivers/staging/i2o/README.ioctl
diff --git a/drivers/staging/i2o/bus-osm.c b/drivers/staging/i2o/bus-osm.c
new file mode 100644
index 000000000000..7aa0339aea05
--- /dev/null
+++ b/drivers/staging/i2o/bus-osm.c
@@ -0,0 +1,176 @@
+/*
+ * Bus Adapter OSM
+ *
+ * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+
+#define OSM_NAME "bus-osm"
+#define OSM_VERSION "1.317"
+#define OSM_DESCRIPTION "I2O Bus Adapter OSM"
+
+static struct i2o_driver i2o_bus_driver;
+
+/* Bus OSM class handling definition */
+static struct i2o_class_id i2o_bus_class_id[] = {
+ {I2O_CLASS_BUS_ADAPTER},
+ {I2O_CLASS_END}
+};
+
+/**
+ * i2o_bus_scan - Scan the bus for new devices
+ * @dev: I2O device of the bus, which should be scanned
+ *
+ * Scans the bus dev for new / removed devices. After the scan a new LCT
+ * will be fetched automatically.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_bus_scan(struct i2o_device *dev)
+{
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return -ETIMEDOUT;
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_BUS_SCAN << 24 | HOST_TID << 12 | dev->lct_data.
+ tid);
+
+ return i2o_msg_post_wait(dev->iop, msg, 60);
+};
+
+/**
+ * i2o_bus_store_scan - Scan the I2O Bus Adapter
+ * @d: device which should be scanned
+ * @attr: device_attribute
+ * @buf: output buffer
+ * @count: buffer size
+ *
+ * Returns count.
+ */
+static ssize_t i2o_bus_store_scan(struct device *d,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(d);
+ int rc;
+
+ if ((rc = i2o_bus_scan(i2o_dev)))
+ osm_warn("bus scan failed %d\n", rc);
+
+ return count;
+}
+
+/* Bus Adapter OSM device attributes */
+static DEVICE_ATTR(scan, S_IWUSR, NULL, i2o_bus_store_scan);
+
+/**
+ * i2o_bus_probe - verify if dev is a I2O Bus Adapter device and install it
+ * @dev: device to verify if it is a I2O Bus Adapter device
+ *
+ * Because we want all Bus Adapters always return 0.
+ * Except when we fail. Then we are sad.
+ *
+ * Returns 0, except when we fail to excel.
+ */
+static int i2o_bus_probe(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(get_device(dev));
+ int rc;
+
+ rc = device_create_file(dev, &dev_attr_scan);
+ if (rc)
+ goto err_out;
+
+ osm_info("device added (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+ return 0;
+
+err_out:
+ put_device(dev);
+ return rc;
+};
+
+/**
+ * i2o_bus_remove - remove the I2O Bus Adapter device from the system again
+ * @dev: I2O Bus Adapter device which should be removed
+ *
+ * Always returns 0.
+ */
+static int i2o_bus_remove(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+ device_remove_file(dev, &dev_attr_scan);
+
+ put_device(dev);
+
+ osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+ return 0;
+};
+
+/* Bus Adapter OSM driver struct */
+static struct i2o_driver i2o_bus_driver = {
+ .name = OSM_NAME,
+ .classes = i2o_bus_class_id,
+ .driver = {
+ .probe = i2o_bus_probe,
+ .remove = i2o_bus_remove,
+ },
+};
+
+/**
+ * i2o_bus_init - Bus Adapter OSM initialization function
+ *
+ * Only register the Bus Adapter OSM in the I2O core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_bus_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ /* Register Bus Adapter OSM into I2O core */
+ rc = i2o_driver_register(&i2o_bus_driver);
+ if (rc) {
+ osm_err("Could not register Bus Adapter OSM\n");
+ return rc;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_bus_exit - Bus Adapter OSM exit function
+ *
+ * Unregisters Bus Adapter OSM from I2O core.
+ */
+static void __exit i2o_bus_exit(void)
+{
+ i2o_driver_unregister(&i2o_bus_driver);
+};
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_bus_init);
+module_exit(i2o_bus_exit);
diff --git a/drivers/staging/i2o/config-osm.c b/drivers/staging/i2o/config-osm.c
new file mode 100644
index 000000000000..519f52f9f688
--- /dev/null
+++ b/drivers/staging/i2o/config-osm.c
@@ -0,0 +1,90 @@
+/*
+ * Configuration OSM
+ *
+ * Copyright (C) 2005 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/dcache.h>
+#include <linux/namei.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+
+#define OSM_NAME "config-osm"
+#define OSM_VERSION "1.323"
+#define OSM_DESCRIPTION "I2O Configuration OSM"
+
+/* access mode user rw */
+#define S_IWRSR (S_IRUSR | S_IWUSR)
+
+static struct i2o_driver i2o_config_driver;
+
+/* Config OSM driver struct */
+static struct i2o_driver i2o_config_driver = {
+ .name = OSM_NAME,
+};
+
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+#include "i2o_config.c"
+#endif
+
+/**
+ * i2o_config_init - Configuration OSM initialization function
+ *
+ * Registers Configuration OSM in the I2O core and if old ioctl's are
+ * compiled in initialize them.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_config_init(void)
+{
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ if (i2o_driver_register(&i2o_config_driver)) {
+ osm_err("handler register failed.\n");
+ return -EBUSY;
+ }
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+ if (i2o_config_old_init()) {
+ osm_err("old config handler initialization failed\n");
+ i2o_driver_unregister(&i2o_config_driver);
+ return -EBUSY;
+ }
+#endif
+
+ return 0;
+}
+
+/**
+ * i2o_config_exit - Configuration OSM exit function
+ *
+ * If old ioctl's are compiled in exit remove them and unregisters
+ * Configuration OSM from I2O core.
+ */
+static void i2o_config_exit(void)
+{
+#ifdef CONFIG_I2O_CONFIG_OLD_IOCTL
+ i2o_config_old_exit();
+#endif
+
+ i2o_driver_unregister(&i2o_config_driver);
+}
+
+MODULE_AUTHOR("Markus Lidel <Markus.Lidel@shadowconnect.com>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_config_init);
+module_exit(i2o_config_exit);
diff --git a/drivers/message/i2o/core.h b/drivers/staging/i2o/core.h
index 91614f11f89a..91614f11f89a 100644
--- a/drivers/message/i2o/core.h
+++ b/drivers/staging/i2o/core.h
diff --git a/drivers/staging/i2o/debug.c b/drivers/staging/i2o/debug.c
new file mode 100644
index 000000000000..7a16114ed8ea
--- /dev/null
+++ b/drivers/staging/i2o/debug.c
@@ -0,0 +1,472 @@
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "i2o.h"
+
+static void i2o_report_util_cmd(u8 cmd);
+static void i2o_report_exec_cmd(u8 cmd);
+static void i2o_report_fail_status(u8 req_status, u32 * msg);
+static void i2o_report_common_status(u8 req_status);
+static void i2o_report_common_dsc(u16 detailed_status);
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Report Cmd name, Request status, Detailed Status.
+ */
+void i2o_report_status(const char *severity, const char *str,
+ struct i2o_message *m)
+{
+ u32 *msg = (u32 *) m;
+ u8 cmd = (msg[1] >> 24) & 0xFF;
+ u8 req_status = (msg[4] >> 24) & 0xFF;
+ u16 detailed_status = msg[4] & 0xFFFF;
+
+ if (cmd == I2O_CMD_UTIL_EVT_REGISTER)
+ return; // No status in this reply
+
+ printk("%s%s: ", severity, str);
+
+ if (cmd < 0x1F) // Utility cmd
+ i2o_report_util_cmd(cmd);
+
+ else if (cmd >= 0xA0 && cmd <= 0xEF) // Executive cmd
+ i2o_report_exec_cmd(cmd);
+ else
+ printk("Cmd = %0#2x, ", cmd); // Other cmds
+
+ if (msg[0] & MSG_FAIL) {
+ i2o_report_fail_status(req_status, msg);
+ return;
+ }
+
+ i2o_report_common_status(req_status);
+
+ if (cmd < 0x1F || (cmd >= 0xA0 && cmd <= 0xEF))
+ i2o_report_common_dsc(detailed_status);
+ else
+ printk(" / DetailedStatus = %0#4x.\n",
+ detailed_status);
+}
+
+/* Used to dump a message to syslog during debugging */
+void i2o_dump_message(struct i2o_message *m)
+{
+#ifdef DEBUG
+ u32 *msg = (u32 *) m;
+ int i;
+ printk(KERN_INFO "Dumping I2O message size %d @ %p\n",
+ msg[0] >> 16 & 0xffff, msg);
+ for (i = 0; i < ((msg[0] >> 16) & 0xffff); i++)
+ printk(KERN_INFO " msg[%d] = %0#10x\n", i, msg[i]);
+#endif
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following fail status are common to all classes.
+ * The preserved message must be handled in the reply handler.
+ */
+static void i2o_report_fail_status(u8 req_status, u32 * msg)
+{
+ static char *FAIL_STATUS[] = {
+ "0x80", /* not used */
+ "SERVICE_SUSPENDED", /* 0x81 */
+ "SERVICE_TERMINATED", /* 0x82 */
+ "CONGESTION",
+ "FAILURE",
+ "STATE_ERROR",
+ "TIME_OUT",
+ "ROUTING_FAILURE",
+ "INVALID_VERSION",
+ "INVALID_OFFSET",
+ "INVALID_MSG_FLAGS",
+ "FRAME_TOO_SMALL",
+ "FRAME_TOO_LARGE",
+ "INVALID_TARGET_ID",
+ "INVALID_INITIATOR_ID",
+ "INVALID_INITIATOR_CONTEX", /* 0x8F */
+ "UNKNOWN_FAILURE" /* 0xFF */
+ };
+
+ if (req_status == I2O_FSC_TRANSPORT_UNKNOWN_FAILURE)
+ printk("TRANSPORT_UNKNOWN_FAILURE (%0#2x).\n",
+ req_status);
+ else
+ printk("TRANSPORT_%s.\n",
+ FAIL_STATUS[req_status & 0x0F]);
+
+ /* Dump some details */
+
+ printk(KERN_ERR " InitiatorId = %d, TargetId = %d\n",
+ (msg[1] >> 12) & 0xFFF, msg[1] & 0xFFF);
+ printk(KERN_ERR " LowestVersion = 0x%02X, HighestVersion = 0x%02X\n",
+ (msg[4] >> 8) & 0xFF, msg[4] & 0xFF);
+ printk(KERN_ERR " FailingHostUnit = 0x%04X, FailingIOP = 0x%03X\n",
+ msg[5] >> 16, msg[5] & 0xFFF);
+
+ printk(KERN_ERR " Severity: 0x%02X\n", (msg[4] >> 16) & 0xFF);
+ if (msg[4] & (1 << 16))
+ printk(KERN_DEBUG "(FormatError), "
+ "this msg can never be delivered/processed.\n");
+ if (msg[4] & (1 << 17))
+ printk(KERN_DEBUG "(PathError), "
+ "this msg can no longer be delivered/processed.\n");
+ if (msg[4] & (1 << 18))
+ printk(KERN_DEBUG "(PathState), "
+ "the system state does not allow delivery.\n");
+ if (msg[4] & (1 << 19))
+ printk(KERN_DEBUG
+ "(Congestion), resources temporarily not available;"
+ "do not retry immediately.\n");
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following reply status are common to all classes.
+ */
+static void i2o_report_common_status(u8 req_status)
+{
+ static char *REPLY_STATUS[] = {
+ "SUCCESS",
+ "ABORT_DIRTY",
+ "ABORT_NO_DATA_TRANSFER",
+ "ABORT_PARTIAL_TRANSFER",
+ "ERROR_DIRTY",
+ "ERROR_NO_DATA_TRANSFER",
+ "ERROR_PARTIAL_TRANSFER",
+ "PROCESS_ABORT_DIRTY",
+ "PROCESS_ABORT_NO_DATA_TRANSFER",
+ "PROCESS_ABORT_PARTIAL_TRANSFER",
+ "TRANSACTION_ERROR",
+ "PROGRESS_REPORT"
+ };
+
+ if (req_status >= ARRAY_SIZE(REPLY_STATUS))
+ printk("RequestStatus = %0#2x", req_status);
+ else
+ printk("%s", REPLY_STATUS[req_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes.
+ * Following detailed status are valid for executive class,
+ * utility class, DDM class and for transaction error replies.
+ */
+static void i2o_report_common_dsc(u16 detailed_status)
+{
+ static char *COMMON_DSC[] = {
+ "SUCCESS",
+ "0x01", // not used
+ "BAD_KEY",
+ "TCL_ERROR",
+ "REPLY_BUFFER_FULL",
+ "NO_SUCH_PAGE",
+ "INSUFFICIENT_RESOURCE_SOFT",
+ "INSUFFICIENT_RESOURCE_HARD",
+ "0x08", // not used
+ "CHAIN_BUFFER_TOO_LARGE",
+ "UNSUPPORTED_FUNCTION",
+ "DEVICE_LOCKED",
+ "DEVICE_RESET",
+ "INAPPROPRIATE_FUNCTION",
+ "INVALID_INITIATOR_ADDRESS",
+ "INVALID_MESSAGE_FLAGS",
+ "INVALID_OFFSET",
+ "INVALID_PARAMETER",
+ "INVALID_REQUEST",
+ "INVALID_TARGET_ADDRESS",
+ "MESSAGE_TOO_LARGE",
+ "MESSAGE_TOO_SMALL",
+ "MISSING_PARAMETER",
+ "TIMEOUT",
+ "UNKNOWN_ERROR",
+ "UNKNOWN_FUNCTION",
+ "UNSUPPORTED_VERSION",
+ "DEVICE_BUSY",
+ "DEVICE_NOT_AVAILABLE"
+ };
+
+ if (detailed_status > I2O_DSC_DEVICE_NOT_AVAILABLE)
+ printk(" / DetailedStatus = %0#4x.\n",
+ detailed_status);
+ else
+ printk(" / %s.\n", COMMON_DSC[detailed_status]);
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_util_cmd(u8 cmd)
+{
+ switch (cmd) {
+ case I2O_CMD_UTIL_NOP:
+ printk("UTIL_NOP, ");
+ break;
+ case I2O_CMD_UTIL_ABORT:
+ printk("UTIL_ABORT, ");
+ break;
+ case I2O_CMD_UTIL_CLAIM:
+ printk("UTIL_CLAIM, ");
+ break;
+ case I2O_CMD_UTIL_RELEASE:
+ printk("UTIL_CLAIM_RELEASE, ");
+ break;
+ case I2O_CMD_UTIL_CONFIG_DIALOG:
+ printk("UTIL_CONFIG_DIALOG, ");
+ break;
+ case I2O_CMD_UTIL_DEVICE_RESERVE:
+ printk("UTIL_DEVICE_RESERVE, ");
+ break;
+ case I2O_CMD_UTIL_DEVICE_RELEASE:
+ printk("UTIL_DEVICE_RELEASE, ");
+ break;
+ case I2O_CMD_UTIL_EVT_ACK:
+ printk("UTIL_EVENT_ACKNOWLEDGE, ");
+ break;
+ case I2O_CMD_UTIL_EVT_REGISTER:
+ printk("UTIL_EVENT_REGISTER, ");
+ break;
+ case I2O_CMD_UTIL_LOCK:
+ printk("UTIL_LOCK, ");
+ break;
+ case I2O_CMD_UTIL_LOCK_RELEASE:
+ printk("UTIL_LOCK_RELEASE, ");
+ break;
+ case I2O_CMD_UTIL_PARAMS_GET:
+ printk("UTIL_PARAMS_GET, ");
+ break;
+ case I2O_CMD_UTIL_PARAMS_SET:
+ printk("UTIL_PARAMS_SET, ");
+ break;
+ case I2O_CMD_UTIL_REPLY_FAULT_NOTIFY:
+ printk("UTIL_REPLY_FAULT_NOTIFY, ");
+ break;
+ default:
+ printk("Cmd = %0#2x, ", cmd);
+ }
+}
+
+/*
+ * Used for error reporting/debugging purposes
+ */
+static void i2o_report_exec_cmd(u8 cmd)
+{
+ switch (cmd) {
+ case I2O_CMD_ADAPTER_ASSIGN:
+ printk("EXEC_ADAPTER_ASSIGN, ");
+ break;
+ case I2O_CMD_ADAPTER_READ:
+ printk("EXEC_ADAPTER_READ, ");
+ break;
+ case I2O_CMD_ADAPTER_RELEASE:
+ printk("EXEC_ADAPTER_RELEASE, ");
+ break;
+ case I2O_CMD_BIOS_INFO_SET:
+ printk("EXEC_BIOS_INFO_SET, ");
+ break;
+ case I2O_CMD_BOOT_DEVICE_SET:
+ printk("EXEC_BOOT_DEVICE_SET, ");
+ break;
+ case I2O_CMD_CONFIG_VALIDATE:
+ printk("EXEC_CONFIG_VALIDATE, ");
+ break;
+ case I2O_CMD_CONN_SETUP:
+ printk("EXEC_CONN_SETUP, ");
+ break;
+ case I2O_CMD_DDM_DESTROY:
+ printk("EXEC_DDM_DESTROY, ");
+ break;
+ case I2O_CMD_DDM_ENABLE:
+ printk("EXEC_DDM_ENABLE, ");
+ break;
+ case I2O_CMD_DDM_QUIESCE:
+ printk("EXEC_DDM_QUIESCE, ");
+ break;
+ case I2O_CMD_DDM_RESET:
+ printk("EXEC_DDM_RESET, ");
+ break;
+ case I2O_CMD_DDM_SUSPEND:
+ printk("EXEC_DDM_SUSPEND, ");
+ break;
+ case I2O_CMD_DEVICE_ASSIGN:
+ printk("EXEC_DEVICE_ASSIGN, ");
+ break;
+ case I2O_CMD_DEVICE_RELEASE:
+ printk("EXEC_DEVICE_RELEASE, ");
+ break;
+ case I2O_CMD_HRT_GET:
+ printk("EXEC_HRT_GET, ");
+ break;
+ case I2O_CMD_ADAPTER_CLEAR:
+ printk("EXEC_IOP_CLEAR, ");
+ break;
+ case I2O_CMD_ADAPTER_CONNECT:
+ printk("EXEC_IOP_CONNECT, ");
+ break;
+ case I2O_CMD_ADAPTER_RESET:
+ printk("EXEC_IOP_RESET, ");
+ break;
+ case I2O_CMD_LCT_NOTIFY:
+ printk("EXEC_LCT_NOTIFY, ");
+ break;
+ case I2O_CMD_OUTBOUND_INIT:
+ printk("EXEC_OUTBOUND_INIT, ");
+ break;
+ case I2O_CMD_PATH_ENABLE:
+ printk("EXEC_PATH_ENABLE, ");
+ break;
+ case I2O_CMD_PATH_QUIESCE:
+ printk("EXEC_PATH_QUIESCE, ");
+ break;
+ case I2O_CMD_PATH_RESET:
+ printk("EXEC_PATH_RESET, ");
+ break;
+ case I2O_CMD_STATIC_MF_CREATE:
+ printk("EXEC_STATIC_MF_CREATE, ");
+ break;
+ case I2O_CMD_STATIC_MF_RELEASE:
+ printk("EXEC_STATIC_MF_RELEASE, ");
+ break;
+ case I2O_CMD_STATUS_GET:
+ printk("EXEC_STATUS_GET, ");
+ break;
+ case I2O_CMD_SW_DOWNLOAD:
+ printk("EXEC_SW_DOWNLOAD, ");
+ break;
+ case I2O_CMD_SW_UPLOAD:
+ printk("EXEC_SW_UPLOAD, ");
+ break;
+ case I2O_CMD_SW_REMOVE:
+ printk("EXEC_SW_REMOVE, ");
+ break;
+ case I2O_CMD_SYS_ENABLE:
+ printk("EXEC_SYS_ENABLE, ");
+ break;
+ case I2O_CMD_SYS_MODIFY:
+ printk("EXEC_SYS_MODIFY, ");
+ break;
+ case I2O_CMD_SYS_QUIESCE:
+ printk("EXEC_SYS_QUIESCE, ");
+ break;
+ case I2O_CMD_SYS_TAB_SET:
+ printk("EXEC_SYS_TAB_SET, ");
+ break;
+ default:
+ printk("Cmd = %#02x, ", cmd);
+ }
+}
+
+void i2o_debug_state(struct i2o_controller *c)
+{
+ printk(KERN_INFO "%s: State = ", c->name);
+ switch (((i2o_status_block *) c->status_block.virt)->iop_state) {
+ case 0x01:
+ printk("INIT\n");
+ break;
+ case 0x02:
+ printk("RESET\n");
+ break;
+ case 0x04:
+ printk("HOLD\n");
+ break;
+ case 0x05:
+ printk("READY\n");
+ break;
+ case 0x08:
+ printk("OPERATIONAL\n");
+ break;
+ case 0x10:
+ printk("FAILED\n");
+ break;
+ case 0x11:
+ printk("FAULTED\n");
+ break;
+ default:
+ printk("%x (unknown !!)\n",
+ ((i2o_status_block *) c->status_block.virt)->iop_state);
+ }
+};
+
+void i2o_dump_hrt(struct i2o_controller *c)
+{
+ u32 *rows = (u32 *) c->hrt.virt;
+ u8 *p = (u8 *) c->hrt.virt;
+ u8 *d;
+ int count;
+ int length;
+ int i;
+ int state;
+
+ if (p[3] != 0) {
+ printk(KERN_ERR
+ "%s: HRT table for controller is too new a version.\n",
+ c->name);
+ return;
+ }
+
+ count = p[0] | (p[1] << 8);
+ length = p[2];
+
+ printk(KERN_INFO "%s: HRT has %d entries of %d bytes each.\n",
+ c->name, count, length << 2);
+
+ rows += 2;
+
+ for (i = 0; i < count; i++) {
+ printk(KERN_INFO "Adapter %08X: ", rows[0]);
+ p = (u8 *) (rows + 1);
+ d = (u8 *) (rows + 2);
+ state = p[1] << 8 | p[0];
+
+ printk("TID %04X:[", state & 0xFFF);
+ state >>= 12;
+ if (state & (1 << 0))
+ printk("H"); /* Hidden */
+ if (state & (1 << 2)) {
+ printk("P"); /* Present */
+ if (state & (1 << 1))
+ printk("C"); /* Controlled */
+ }
+ if (state > 9)
+ printk("*"); /* Hard */
+
+ printk("]:");
+
+ switch (p[3] & 0xFFFF) {
+ case 0:
+ /* Adapter private bus - easy */
+ printk("Local bus %d: I/O at 0x%04X Mem 0x%08X", p[2],
+ d[1] << 8 | d[0], *(u32 *) (d + 4));
+ break;
+ case 1:
+ /* ISA bus */
+ printk("ISA %d: CSN %d I/O at 0x%04X Mem 0x%08X", p[2],
+ d[2], d[1] << 8 | d[0], *(u32 *) (d + 4));
+ break;
+
+ case 2: /* EISA bus */
+ printk("EISA %d: Slot %d I/O at 0x%04X Mem 0x%08X",
+ p[2], d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
+ break;
+
+ case 3: /* MCA bus */
+ printk("MCA %d: Slot %d I/O at 0x%04X Mem 0x%08X", p[2],
+ d[3], d[1] << 8 | d[0], *(u32 *) (d + 4));
+ break;
+
+ case 4: /* PCI bus */
+ printk("PCI %d: Bus %d Device %d Function %d", p[2],
+ d[2], d[1], d[0]);
+ break;
+
+ case 0x80: /* Other */
+ default:
+ printk("Unsupported bus type.");
+ break;
+ }
+ printk("\n");
+ rows += length;
+ }
+}
+
+EXPORT_SYMBOL(i2o_dump_message);
diff --git a/drivers/staging/i2o/device.c b/drivers/staging/i2o/device.c
new file mode 100644
index 000000000000..2af22553dd4e
--- /dev/null
+++ b/drivers/staging/i2o/device.c
@@ -0,0 +1,594 @@
+/*
+ * Functions to handle I2O devices
+ *
+ * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+/**
+ * i2o_device_issue_claim - claim or release a device
+ * @dev: I2O device to claim or release
+ * @cmd: claim or release command
+ * @type: type of claim
+ *
+ * Issue I2O UTIL_CLAIM or UTIL_RELEASE messages. The message to be sent
+ * is set by cmd. dev is the I2O device which should be claim or
+ * released and the type is the claim type (see the I2O spec).
+ *
+ * Returs 0 on success or negative error code on failure.
+ */
+static inline int i2o_device_issue_claim(struct i2o_device *dev, u32 cmd,
+ u32 type)
+{
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(cmd << 24 | HOST_TID << 12 | dev->lct_data.tid);
+ msg->body[0] = cpu_to_le32(type);
+
+ return i2o_msg_post_wait(dev->iop, msg, 60);
+}
+
+/**
+ * i2o_device_claim - claim a device for use by an OSM
+ * @dev: I2O device to claim
+ *
+ * Do the leg work to assign a device to a given OSM. If the claim succeeds,
+ * the owner is the primary. If the attempt fails a negative errno code
+ * is returned. On success zero is returned.
+ */
+int i2o_device_claim(struct i2o_device *dev)
+{
+ int rc = 0;
+
+ mutex_lock(&dev->lock);
+
+ rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_CLAIM, I2O_CLAIM_PRIMARY);
+ if (!rc)
+ pr_debug("i2o: claim of device %d succeeded\n",
+ dev->lct_data.tid);
+ else
+ pr_debug("i2o: claim of device %d failed %d\n",
+ dev->lct_data.tid, rc);
+
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+/**
+ * i2o_device_claim_release - release a device that the OSM is using
+ * @dev: device to release
+ *
+ * Drop a claim by an OSM on a given I2O device.
+ *
+ * AC - some devices seem to want to refuse an unclaim until they have
+ * finished internal processing. It makes sense since you don't want a
+ * new device to go reconfiguring the entire system until you are done.
+ * Thus we are prepared to wait briefly.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_claim_release(struct i2o_device *dev)
+{
+ int tries;
+ int rc = 0;
+
+ mutex_lock(&dev->lock);
+
+ /*
+ * If the controller takes a nonblocking approach to
+ * releases we have to sleep/poll for a few times.
+ */
+ for (tries = 0; tries < 10; tries++) {
+ rc = i2o_device_issue_claim(dev, I2O_CMD_UTIL_RELEASE,
+ I2O_CLAIM_PRIMARY);
+ if (!rc)
+ break;
+
+ ssleep(1);
+ }
+
+ if (!rc)
+ pr_debug("i2o: claim release of device %d succeeded\n",
+ dev->lct_data.tid);
+ else
+ pr_debug("i2o: claim release of device %d failed %d\n",
+ dev->lct_data.tid, rc);
+
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+/**
+ * i2o_device_release - release the memory for a I2O device
+ * @dev: I2O device which should be released
+ *
+ * Release the allocated memory. This function is called if refcount of
+ * device reaches 0 automatically.
+ */
+static void i2o_device_release(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+ pr_debug("i2o: device %s released\n", dev_name(dev));
+
+ kfree(i2o_dev);
+}
+
+/**
+ * class_id_show - Displays class id of I2O device
+ * @dev: device of which the class id should be displayed
+ * @attr: pointer to device attribute
+ * @buf: buffer into which the class id should be printed
+ *
+ * Returns the number of bytes which are printed into the buffer.
+ */
+static ssize_t class_id_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+ sprintf(buf, "0x%03x\n", i2o_dev->lct_data.class_id);
+ return strlen(buf) + 1;
+}
+static DEVICE_ATTR_RO(class_id);
+
+/**
+ * tid_show - Displays TID of I2O device
+ * @dev: device of which the TID should be displayed
+ * @attr: pointer to device attribute
+ * @buf: buffer into which the TID should be printed
+ *
+ * Returns the number of bytes which are printed into the buffer.
+ */
+static ssize_t tid_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+
+ sprintf(buf, "0x%03x\n", i2o_dev->lct_data.tid);
+ return strlen(buf) + 1;
+}
+static DEVICE_ATTR_RO(tid);
+
+/* I2O device attributes */
+static struct attribute *i2o_device_attrs[] = {
+ &dev_attr_class_id.attr,
+ &dev_attr_tid.attr,
+ NULL,
+};
+
+static const struct attribute_group i2o_device_group = {
+ .attrs = i2o_device_attrs,
+};
+
+const struct attribute_group *i2o_device_groups[] = {
+ &i2o_device_group,
+ NULL,
+};
+
+/**
+ * i2o_device_alloc - Allocate a I2O device and initialize it
+ *
+ * Allocate the memory for a I2O device and initialize locks and lists
+ *
+ * Returns the allocated I2O device or a negative error code if the device
+ * could not be allocated.
+ */
+static struct i2o_device *i2o_device_alloc(void)
+{
+ struct i2o_device *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&dev->list);
+ mutex_init(&dev->lock);
+
+ dev->device.bus = &i2o_bus_type;
+ dev->device.release = &i2o_device_release;
+
+ return dev;
+}
+
+/**
+ * i2o_device_add - allocate a new I2O device and add it to the IOP
+ * @c: I2O controller that the device is on
+ * @entry: LCT entry of the I2O device
+ *
+ * Allocate a new I2O device and initialize it with the LCT entry. The
+ * device is appended to the device list of the controller.
+ *
+ * Returns zero on success, or a -ve errno.
+ */
+static int i2o_device_add(struct i2o_controller *c, i2o_lct_entry *entry)
+{
+ struct i2o_device *i2o_dev, *tmp;
+ int rc;
+
+ i2o_dev = i2o_device_alloc();
+ if (IS_ERR(i2o_dev)) {
+ printk(KERN_ERR "i2o: unable to allocate i2o device\n");
+ return PTR_ERR(i2o_dev);
+ }
+
+ i2o_dev->lct_data = *entry;
+
+ dev_set_name(&i2o_dev->device, "%d:%03x", c->unit,
+ i2o_dev->lct_data.tid);
+
+ i2o_dev->iop = c;
+ i2o_dev->device.parent = &c->device;
+
+ rc = device_register(&i2o_dev->device);
+ if (rc)
+ goto err;
+
+ list_add_tail(&i2o_dev->list, &c->devices);
+
+ /* create user entries for this device */
+ tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.user_tid);
+ if (tmp && (tmp != i2o_dev)) {
+ rc = sysfs_create_link(&i2o_dev->device.kobj,
+ &tmp->device.kobj, "user");
+ if (rc)
+ goto unreg_dev;
+ }
+
+ /* create user entries referring to this device */
+ list_for_each_entry(tmp, &c->devices, list)
+ if ((tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+ && (tmp != i2o_dev)) {
+ rc = sysfs_create_link(&tmp->device.kobj,
+ &i2o_dev->device.kobj, "user");
+ if (rc)
+ goto rmlink1;
+ }
+
+ /* create parent entries for this device */
+ tmp = i2o_iop_find_device(i2o_dev->iop, i2o_dev->lct_data.parent_tid);
+ if (tmp && (tmp != i2o_dev)) {
+ rc = sysfs_create_link(&i2o_dev->device.kobj,
+ &tmp->device.kobj, "parent");
+ if (rc)
+ goto rmlink1;
+ }
+
+ /* create parent entries referring to this device */
+ list_for_each_entry(tmp, &c->devices, list)
+ if ((tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+ && (tmp != i2o_dev)) {
+ rc = sysfs_create_link(&tmp->device.kobj,
+ &i2o_dev->device.kobj, "parent");
+ if (rc)
+ goto rmlink2;
+ }
+
+ i2o_driver_notify_device_add_all(i2o_dev);
+
+ pr_debug("i2o: device %s added\n", dev_name(&i2o_dev->device));
+
+ return 0;
+
+rmlink2:
+ /* If link creating failed halfway, we loop whole list to cleanup.
+ * And we don't care wrong removing of link, because sysfs_remove_link
+ * will take care of it.
+ */
+ list_for_each_entry(tmp, &c->devices, list) {
+ if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+ sysfs_remove_link(&tmp->device.kobj, "parent");
+ }
+ sysfs_remove_link(&i2o_dev->device.kobj, "parent");
+rmlink1:
+ list_for_each_entry(tmp, &c->devices, list)
+ if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+ sysfs_remove_link(&tmp->device.kobj, "user");
+ sysfs_remove_link(&i2o_dev->device.kobj, "user");
+unreg_dev:
+ list_del(&i2o_dev->list);
+ device_unregister(&i2o_dev->device);
+err:
+ kfree(i2o_dev);
+ return rc;
+}
+
+/**
+ * i2o_device_remove - remove an I2O device from the I2O core
+ * @i2o_dev: I2O device which should be released
+ *
+ * Is used on I2O controller removal or LCT modification, when the device
+ * is removed from the system. Note that the device could still hang
+ * around until the refcount reaches 0.
+ */
+void i2o_device_remove(struct i2o_device *i2o_dev)
+{
+ struct i2o_device *tmp;
+ struct i2o_controller *c = i2o_dev->iop;
+
+ i2o_driver_notify_device_remove_all(i2o_dev);
+
+ sysfs_remove_link(&i2o_dev->device.kobj, "parent");
+ sysfs_remove_link(&i2o_dev->device.kobj, "user");
+
+ list_for_each_entry(tmp, &c->devices, list) {
+ if (tmp->lct_data.parent_tid == i2o_dev->lct_data.tid)
+ sysfs_remove_link(&tmp->device.kobj, "parent");
+ if (tmp->lct_data.user_tid == i2o_dev->lct_data.tid)
+ sysfs_remove_link(&tmp->device.kobj, "user");
+ }
+ list_del(&i2o_dev->list);
+
+ device_unregister(&i2o_dev->device);
+}
+
+/**
+ * i2o_device_parse_lct - Parse a previously fetched LCT and create devices
+ * @c: I2O controller from which the LCT should be parsed.
+ *
+ * The Logical Configuration Table tells us what we can talk to on the
+ * board. For every entry we create an I2O device, which is registered in
+ * the I2O core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_device_parse_lct(struct i2o_controller *c)
+{
+ struct i2o_device *dev, *tmp;
+ i2o_lct *lct;
+ u32 *dlct = c->dlct.virt;
+ int max = 0, i = 0;
+ u16 table_size;
+ u32 buf;
+
+ mutex_lock(&c->lct_lock);
+
+ kfree(c->lct);
+
+ buf = le32_to_cpu(*dlct++);
+ table_size = buf & 0xffff;
+
+ lct = c->lct = kmalloc(table_size * 4, GFP_KERNEL);
+ if (!lct) {
+ mutex_unlock(&c->lct_lock);
+ return -ENOMEM;
+ }
+
+ lct->lct_ver = buf >> 28;
+ lct->boot_tid = buf >> 16 & 0xfff;
+ lct->table_size = table_size;
+ lct->change_ind = le32_to_cpu(*dlct++);
+ lct->iop_flags = le32_to_cpu(*dlct++);
+
+ table_size -= 3;
+
+ pr_debug("%s: LCT has %d entries (LCT size: %d)\n", c->name, max,
+ lct->table_size);
+
+ while (table_size > 0) {
+ i2o_lct_entry *entry = &lct->lct_entry[max];
+ int found = 0;
+
+ buf = le32_to_cpu(*dlct++);
+ entry->entry_size = buf & 0xffff;
+ entry->tid = buf >> 16 & 0xfff;
+
+ entry->change_ind = le32_to_cpu(*dlct++);
+ entry->device_flags = le32_to_cpu(*dlct++);
+
+ buf = le32_to_cpu(*dlct++);
+ entry->class_id = buf & 0xfff;
+ entry->version = buf >> 12 & 0xf;
+ entry->vendor_id = buf >> 16;
+
+ entry->sub_class = le32_to_cpu(*dlct++);
+
+ buf = le32_to_cpu(*dlct++);
+ entry->user_tid = buf & 0xfff;
+ entry->parent_tid = buf >> 12 & 0xfff;
+ entry->bios_info = buf >> 24;
+
+ memcpy(&entry->identity_tag, dlct, 8);
+ dlct += 2;
+
+ entry->event_capabilities = le32_to_cpu(*dlct++);
+
+ /* add new devices, which are new in the LCT */
+ list_for_each_entry_safe(dev, tmp, &c->devices, list) {
+ if (entry->tid == dev->lct_data.tid) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ i2o_device_add(c, entry);
+
+ table_size -= 9;
+ max++;
+ }
+
+ /* remove devices, which are not in the LCT anymore */
+ list_for_each_entry_safe(dev, tmp, &c->devices, list) {
+ int found = 0;
+
+ for (i = 0; i < max; i++) {
+ if (lct->lct_entry[i].tid == dev->lct_data.tid) {
+ found = 1;
+ break;
+ }
+ }
+
+ if (!found)
+ i2o_device_remove(dev);
+ }
+
+ mutex_unlock(&c->lct_lock);
+
+ return 0;
+}
+
+/*
+ * Run time support routines
+ */
+
+/* Issue UTIL_PARAMS_GET or UTIL_PARAMS_SET
+ *
+ * This function can be used for all UtilParamsGet/Set operations.
+ * The OperationList is given in oplist-buffer,
+ * and results are returned in reslist-buffer.
+ * Note that the minimum sized reslist is 8 bytes and contains
+ * ResultCount, ErrorInfoSize, BlockStatus and BlockSize.
+ */
+int i2o_parm_issue(struct i2o_device *i2o_dev, int cmd, void *oplist,
+ int oplen, void *reslist, int reslen)
+{
+ struct i2o_message *msg;
+ int i = 0;
+ int rc;
+ struct i2o_dma res;
+ struct i2o_controller *c = i2o_dev->iop;
+ struct device *dev = &c->pdev->dev;
+
+ res.virt = NULL;
+
+ if (i2o_dma_alloc(dev, &res, reslen))
+ return -ENOMEM;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg)) {
+ i2o_dma_free(dev, &res);
+ return PTR_ERR(msg);
+ }
+
+ i = 0;
+ msg->u.head[1] =
+ cpu_to_le32(cmd << 24 | HOST_TID << 12 | i2o_dev->lct_data.tid);
+ msg->body[i++] = cpu_to_le32(0x00000000);
+ msg->body[i++] = cpu_to_le32(0x4C000000 | oplen); /* OperationList */
+ memcpy(&msg->body[i], oplist, oplen);
+ i += (oplen / 4 + (oplen % 4 ? 1 : 0));
+ msg->body[i++] = cpu_to_le32(0xD0000000 | res.len); /* ResultList */
+ msg->body[i++] = cpu_to_le32(res.phys);
+
+ msg->u.head[0] =
+ cpu_to_le32(I2O_MESSAGE_SIZE(i + sizeof(struct i2o_message) / 4) |
+ SGL_OFFSET_5);
+
+ rc = i2o_msg_post_wait_mem(c, msg, 10, &res);
+
+ /* This only looks like a memory leak - don't "fix" it. */
+ if (rc == -ETIMEDOUT)
+ return rc;
+
+ memcpy(reslist, res.virt, res.len);
+ i2o_dma_free(dev, &res);
+
+ return rc;
+}
+
+/*
+ * Query one field group value or a whole scalar group.
+ */
+int i2o_parm_field_get(struct i2o_device *i2o_dev, int group, int field,
+ void *buf, int buflen)
+{
+ u32 opblk[] = { cpu_to_le32(0x00000001),
+ cpu_to_le32((u16) group << 16 | I2O_PARAMS_FIELD_GET),
+ cpu_to_le32((s16) field << 16 | 0x00000001)
+ };
+ u8 *resblk; /* 8 bytes for header */
+ int rc;
+
+ resblk = kmalloc(buflen + 8, GFP_KERNEL);
+ if (!resblk)
+ return -ENOMEM;
+
+ rc = i2o_parm_issue(i2o_dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
+ sizeof(opblk), resblk, buflen + 8);
+
+ memcpy(buf, resblk + 8, buflen); /* cut off header */
+
+ kfree(resblk);
+
+ return rc;
+}
+
+/*
+ * if oper == I2O_PARAMS_TABLE_GET, get from all rows
+ * if fieldcount == -1 return all fields
+ * ibuf and ibuflen are unused (use NULL, 0)
+ * else return specific fields
+ * ibuf contains fieldindexes
+ *
+ * if oper == I2O_PARAMS_LIST_GET, get from specific rows
+ * if fieldcount == -1 return all fields
+ * ibuf contains rowcount, keyvalues
+ * else return specific fields
+ * fieldcount is # of fieldindexes
+ * ibuf contains fieldindexes, rowcount, keyvalues
+ *
+ * You could also use directly function i2o_issue_params().
+ */
+int i2o_parm_table_get(struct i2o_device *dev, int oper, int group,
+ int fieldcount, void *ibuf, int ibuflen, void *resblk,
+ int reslen)
+{
+ u16 *opblk;
+ int size;
+
+ size = 10 + ibuflen;
+ if (size % 4)
+ size += 4 - size % 4;
+
+ opblk = kmalloc(size, GFP_KERNEL);
+ if (opblk == NULL) {
+ printk(KERN_ERR "i2o: no memory for query buffer.\n");
+ return -ENOMEM;
+ }
+
+ opblk[0] = 1; /* operation count */
+ opblk[1] = 0; /* pad */
+ opblk[2] = oper;
+ opblk[3] = group;
+ opblk[4] = fieldcount;
+ memcpy(opblk + 5, ibuf, ibuflen); /* other params */
+
+ size = i2o_parm_issue(dev, I2O_CMD_UTIL_PARAMS_GET, opblk,
+ size, resblk, reslen);
+
+ kfree(opblk);
+ if (size > reslen)
+ return reslen;
+
+ return size;
+}
+
+EXPORT_SYMBOL(i2o_device_claim);
+EXPORT_SYMBOL(i2o_device_claim_release);
+EXPORT_SYMBOL(i2o_parm_field_get);
+EXPORT_SYMBOL(i2o_parm_table_get);
+EXPORT_SYMBOL(i2o_parm_issue);
diff --git a/drivers/staging/i2o/driver.c b/drivers/staging/i2o/driver.c
new file mode 100644
index 000000000000..111c3edde035
--- /dev/null
+++ b/drivers/staging/i2o/driver.c
@@ -0,0 +1,382 @@
+/*
+ * Functions to handle I2O drivers (OSMs) and I2O bus type for sysfs
+ *
+ * Copyright (C) 2004 Markus Lidel <Markus.Lidel@shadowconnect.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.
+ *
+ * Fixes/additions:
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * initial version.
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/rwsem.h>
+#include "i2o.h"
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+#define OSM_NAME "i2o"
+
+/* max_drivers - Maximum I2O drivers (OSMs) which could be registered */
+static unsigned int i2o_max_drivers = I2O_MAX_DRIVERS;
+module_param_named(max_drivers, i2o_max_drivers, uint, 0);
+MODULE_PARM_DESC(max_drivers, "maximum number of OSM's to support");
+
+/* I2O drivers lock and array */
+static spinlock_t i2o_drivers_lock;
+static struct i2o_driver **i2o_drivers;
+
+/**
+ * i2o_bus_match - Tell if I2O device class id matches the class ids of the I2O driver (OSM)
+ * @dev: device which should be verified
+ * @drv: the driver to match against
+ *
+ * Used by the bus to check if the driver wants to handle the device.
+ *
+ * Returns 1 if the class ids of the driver match the class id of the
+ * device, otherwise 0.
+ */
+static int i2o_bus_match(struct device *dev, struct device_driver *drv)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+ struct i2o_driver *i2o_drv = to_i2o_driver(drv);
+ struct i2o_class_id *ids = i2o_drv->classes;
+
+ if (ids)
+ while (ids->class_id != I2O_CLASS_END) {
+ if (ids->class_id == i2o_dev->lct_data.class_id)
+ return 1;
+ ids++;
+ }
+ return 0;
+};
+
+/* I2O bus type */
+struct bus_type i2o_bus_type = {
+ .name = "i2o",
+ .match = i2o_bus_match,
+ .dev_groups = i2o_device_groups,
+};
+
+/**
+ * i2o_driver_register - Register a I2O driver (OSM) in the I2O core
+ * @drv: I2O driver which should be registered
+ *
+ * Registers the OSM drv in the I2O core and creates an event queues if
+ * necessary.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_driver_register(struct i2o_driver *drv)
+{
+ struct i2o_controller *c;
+ int i;
+ int rc = 0;
+ unsigned long flags;
+
+ osm_debug("Register driver %s\n", drv->name);
+
+ if (drv->event) {
+ drv->event_queue = alloc_workqueue("%s", WQ_MEM_RECLAIM, 1,
+ drv->name);
+ if (!drv->event_queue) {
+ osm_err("Could not initialize event queue for driver "
+ "%s\n", drv->name);
+ return -EFAULT;
+ }
+ osm_debug("Event queue initialized for driver %s\n", drv->name);
+ } else
+ drv->event_queue = NULL;
+
+ drv->driver.name = drv->name;
+ drv->driver.bus = &i2o_bus_type;
+
+ spin_lock_irqsave(&i2o_drivers_lock, flags);
+
+ for (i = 0; i2o_drivers[i]; i++)
+ if (i >= i2o_max_drivers) {
+ osm_err("too many drivers registered, increase "
+ "max_drivers\n");
+ spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+ rc = -EFAULT;
+ goto out;
+ }
+
+ drv->context = i;
+ i2o_drivers[i] = drv;
+
+ spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+ osm_debug("driver %s gets context id %d\n", drv->name, drv->context);
+
+ list_for_each_entry(c, &i2o_controllers, list) {
+ struct i2o_device *i2o_dev;
+
+ i2o_driver_notify_controller_add(drv, c);
+ list_for_each_entry(i2o_dev, &c->devices, list)
+ i2o_driver_notify_device_add(drv, i2o_dev);
+ }
+
+ rc = driver_register(&drv->driver);
+ if (rc)
+ goto out;
+
+ return 0;
+out:
+ if (drv->event_queue) {
+ destroy_workqueue(drv->event_queue);
+ drv->event_queue = NULL;
+ }
+
+ return rc;
+};
+
+/**
+ * i2o_driver_unregister - Unregister a I2O driver (OSM) from the I2O core
+ * @drv: I2O driver which should be unregistered
+ *
+ * Unregisters the OSM drv from the I2O core and cleanup event queues if
+ * necessary.
+ */
+void i2o_driver_unregister(struct i2o_driver *drv)
+{
+ struct i2o_controller *c;
+ unsigned long flags;
+
+ osm_debug("unregister driver %s\n", drv->name);
+
+ driver_unregister(&drv->driver);
+
+ list_for_each_entry(c, &i2o_controllers, list) {
+ struct i2o_device *i2o_dev;
+
+ list_for_each_entry(i2o_dev, &c->devices, list)
+ i2o_driver_notify_device_remove(drv, i2o_dev);
+
+ i2o_driver_notify_controller_remove(drv, c);
+ }
+
+ spin_lock_irqsave(&i2o_drivers_lock, flags);
+ i2o_drivers[drv->context] = NULL;
+ spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+ if (drv->event_queue) {
+ destroy_workqueue(drv->event_queue);
+ drv->event_queue = NULL;
+ osm_debug("event queue removed for %s\n", drv->name);
+ }
+};
+
+/**
+ * i2o_driver_dispatch - dispatch an I2O reply message
+ * @c: I2O controller of the message
+ * @m: I2O message number
+ *
+ * The reply is delivered to the driver from which the original message
+ * was. This function is only called from interrupt context.
+ *
+ * Returns 0 on success and the message should not be flushed. Returns > 0
+ * on success and if the message should be flushed afterwords. Returns
+ * negative error code on failure (the message will be flushed too).
+ */
+int i2o_driver_dispatch(struct i2o_controller *c, u32 m)
+{
+ struct i2o_driver *drv;
+ struct i2o_message *msg = i2o_msg_out_to_virt(c, m);
+ u32 context = le32_to_cpu(msg->u.s.icntxt);
+ unsigned long flags;
+
+ if (unlikely(context >= i2o_max_drivers)) {
+ osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+ context);
+ return -EIO;
+ }
+
+ spin_lock_irqsave(&i2o_drivers_lock, flags);
+ drv = i2o_drivers[context];
+ spin_unlock_irqrestore(&i2o_drivers_lock, flags);
+
+ if (unlikely(!drv)) {
+ osm_warn("%s: Spurious reply to unknown driver %d\n", c->name,
+ context);
+ return -EIO;
+ }
+
+ if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_UTIL_EVT_REGISTER) {
+ struct i2o_device *dev, *tmp;
+ struct i2o_event *evt;
+ u16 size;
+ u16 tid = le32_to_cpu(msg->u.head[1]) & 0xfff;
+
+ osm_debug("event received from device %d\n", tid);
+
+ if (!drv->event)
+ return -EIO;
+
+ /* cut of header from message size (in 32-bit words) */
+ size = (le32_to_cpu(msg->u.head[0]) >> 16) - 5;
+
+ evt = kzalloc(size * 4 + sizeof(*evt), GFP_ATOMIC);
+ if (!evt)
+ return -ENOMEM;
+
+ evt->size = size;
+ evt->tcntxt = le32_to_cpu(msg->u.s.tcntxt);
+ evt->event_indicator = le32_to_cpu(msg->body[0]);
+ memcpy(&evt->data, &msg->body[1], size * 4);
+
+ list_for_each_entry_safe(dev, tmp, &c->devices, list)
+ if (dev->lct_data.tid == tid) {
+ evt->i2o_dev = dev;
+ break;
+ }
+
+ INIT_WORK(&evt->work, drv->event);
+ queue_work(drv->event_queue, &evt->work);
+ return 1;
+ }
+
+ if (unlikely(!drv->reply)) {
+ osm_debug("%s: Reply to driver %s, but no reply function"
+ " defined!\n", c->name, drv->name);
+ return -EIO;
+ }
+
+ return drv->reply(c, m, msg);
+}
+
+/**
+ * i2o_driver_notify_controller_add_all - Send notify of added controller
+ * @c: newly added controller
+ *
+ * Send notifications to all registered drivers that a new controller was
+ * added.
+ */
+void i2o_driver_notify_controller_add_all(struct i2o_controller *c)
+{
+ int i;
+ struct i2o_driver *drv;
+
+ for (i = 0; i < i2o_max_drivers; i++) {
+ drv = i2o_drivers[i];
+
+ if (drv)
+ i2o_driver_notify_controller_add(drv, c);
+ }
+}
+
+/**
+ * i2o_driver_notify_controller_remove_all - Send notify of removed controller
+ * @c: controller that is being removed
+ *
+ * Send notifications to all registered drivers that a controller was
+ * removed.
+ */
+void i2o_driver_notify_controller_remove_all(struct i2o_controller *c)
+{
+ int i;
+ struct i2o_driver *drv;
+
+ for (i = 0; i < i2o_max_drivers; i++) {
+ drv = i2o_drivers[i];
+
+ if (drv)
+ i2o_driver_notify_controller_remove(drv, c);
+ }
+}
+
+/**
+ * i2o_driver_notify_device_add_all - Send notify of added device
+ * @i2o_dev: newly added I2O device
+ *
+ * Send notifications to all registered drivers that a device was added.
+ */
+void i2o_driver_notify_device_add_all(struct i2o_device *i2o_dev)
+{
+ int i;
+ struct i2o_driver *drv;
+
+ for (i = 0; i < i2o_max_drivers; i++) {
+ drv = i2o_drivers[i];
+
+ if (drv)
+ i2o_driver_notify_device_add(drv, i2o_dev);
+ }
+}
+
+/**
+ * i2o_driver_notify_device_remove_all - Send notify of removed device
+ * @i2o_dev: device that is being removed
+ *
+ * Send notifications to all registered drivers that a device was removed.
+ */
+void i2o_driver_notify_device_remove_all(struct i2o_device *i2o_dev)
+{
+ int i;
+ struct i2o_driver *drv;
+
+ for (i = 0; i < i2o_max_drivers; i++) {
+ drv = i2o_drivers[i];
+
+ if (drv)
+ i2o_driver_notify_device_remove(drv, i2o_dev);
+ }
+}
+
+/**
+ * i2o_driver_init - initialize I2O drivers (OSMs)
+ *
+ * Registers the I2O bus and allocate memory for the array of OSMs.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int __init i2o_driver_init(void)
+{
+ int rc = 0;
+
+ spin_lock_init(&i2o_drivers_lock);
+
+ if ((i2o_max_drivers < 2) || (i2o_max_drivers > 64)) {
+ osm_warn("max_drivers set to %d, but must be >=2 and <= 64\n",
+ i2o_max_drivers);
+ i2o_max_drivers = I2O_MAX_DRIVERS;
+ }
+ osm_info("max drivers = %d\n", i2o_max_drivers);
+
+ i2o_drivers =
+ kcalloc(i2o_max_drivers, sizeof(*i2o_drivers), GFP_KERNEL);
+ if (!i2o_drivers)
+ return -ENOMEM;
+
+ rc = bus_register(&i2o_bus_type);
+
+ if (rc < 0)
+ kfree(i2o_drivers);
+
+ return rc;
+};
+
+/**
+ * i2o_driver_exit - clean up I2O drivers (OSMs)
+ *
+ * Unregisters the I2O bus and frees driver array.
+ */
+void i2o_driver_exit(void)
+{
+ bus_unregister(&i2o_bus_type);
+ kfree(i2o_drivers);
+};
+
+EXPORT_SYMBOL(i2o_driver_register);
+EXPORT_SYMBOL(i2o_driver_unregister);
+EXPORT_SYMBOL(i2o_driver_notify_controller_add_all);
+EXPORT_SYMBOL(i2o_driver_notify_controller_remove_all);
+EXPORT_SYMBOL(i2o_driver_notify_device_add_all);
+EXPORT_SYMBOL(i2o_driver_notify_device_remove_all);
diff --git a/drivers/staging/i2o/exec-osm.c b/drivers/staging/i2o/exec-osm.c
new file mode 100644
index 000000000000..16d857d5e655
--- /dev/null
+++ b/drivers/staging/i2o/exec-osm.c
@@ -0,0 +1,612 @@
+/*
+ * Executive OSM
+ *
+ * Copyright (C) 1999-2002 Red Hat Software
+ *
+ * Written by Alan Cox, Building Number Three 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.
+ *
+ * A lot of the I2O message side code from this is taken from the Red
+ * Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ * Fixes/additions:
+ * Philipp Rumpf
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Deepak Saxena <deepak@plexity.net>
+ * Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ * Ported to Linux 2.5.
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Minor fixes for 2.6.
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Support for sysfs included.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/delay.h>
+#include <linux/workqueue.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/sched.h> /* wait_event_interruptible_timeout() needs this */
+#include <asm/param.h> /* HZ */
+#include "core.h"
+
+#define OSM_NAME "exec-osm"
+
+struct i2o_driver i2o_exec_driver;
+
+/* global wait list for POST WAIT */
+static LIST_HEAD(i2o_exec_wait_list);
+
+/* Wait struct needed for POST WAIT */
+struct i2o_exec_wait {
+ wait_queue_head_t *wq; /* Pointer to Wait queue */
+ struct i2o_dma dma; /* DMA buffers to free on failure */
+ u32 tcntxt; /* transaction context from reply */
+ int complete; /* 1 if reply received otherwise 0 */
+ u32 m; /* message id */
+ struct i2o_message *msg; /* pointer to the reply message */
+ struct list_head list; /* node in global wait list */
+ spinlock_t lock; /* lock before modifying */
+};
+
+/* Work struct needed to handle LCT NOTIFY replies */
+struct i2o_exec_lct_notify_work {
+ struct work_struct work; /* work struct */
+ struct i2o_controller *c; /* controller on which the LCT NOTIFY
+ was received */
+};
+
+/* Exec OSM class handling definition */
+static struct i2o_class_id i2o_exec_class_id[] = {
+ {I2O_CLASS_EXECUTIVE},
+ {I2O_CLASS_END}
+};
+
+/**
+ * i2o_exec_wait_alloc - Allocate a i2o_exec_wait struct an initialize it
+ *
+ * Allocate the i2o_exec_wait struct and initialize the wait.
+ *
+ * Returns i2o_exec_wait pointer on success or negative error code on
+ * failure.
+ */
+static struct i2o_exec_wait *i2o_exec_wait_alloc(void)
+{
+ struct i2o_exec_wait *wait;
+
+ wait = kzalloc(sizeof(*wait), GFP_KERNEL);
+ if (!wait)
+ return NULL;
+
+ INIT_LIST_HEAD(&wait->list);
+ spin_lock_init(&wait->lock);
+
+ return wait;
+};
+
+/**
+ * i2o_exec_wait_free - Free an i2o_exec_wait struct
+ * @wait: I2O wait data which should be cleaned up
+ */
+static void i2o_exec_wait_free(struct i2o_exec_wait *wait)
+{
+ kfree(wait);
+};
+
+/**
+ * i2o_msg_post_wait_mem - Post and wait a message with DMA buffers
+ * @c: controller
+ * @msg: message to post
+ * @timeout: time in seconds to wait
+ * @dma: i2o_dma struct of the DMA buffer to free on failure
+ *
+ * This API allows an OSM to post a message and then be told whether or
+ * not the system received a successful reply. If the message times out
+ * then the value '-ETIMEDOUT' is returned. This is a special case. In
+ * this situation the message may (should) complete at an indefinite time
+ * in the future. When it completes it will use the memory buffer
+ * attached to the request. If -ETIMEDOUT is returned then the memory
+ * buffer must not be freed. Instead the event completion will free them
+ * for you. In all other cases the buffer are your problem.
+ *
+ * Returns 0 on success, negative error code on timeout or positive error
+ * code from reply.
+ */
+int i2o_msg_post_wait_mem(struct i2o_controller *c, struct i2o_message *msg,
+ unsigned long timeout, struct i2o_dma *dma)
+{
+ DECLARE_WAIT_QUEUE_HEAD_ONSTACK(wq);
+ struct i2o_exec_wait *wait;
+ static u32 tcntxt = 0x80000000;
+ unsigned long flags;
+ int rc = 0;
+
+ wait = i2o_exec_wait_alloc();
+ if (!wait) {
+ i2o_msg_nop(c, msg);
+ return -ENOMEM;
+ }
+
+ if (tcntxt == 0xffffffff)
+ tcntxt = 0x80000000;
+
+ if (dma)
+ wait->dma = *dma;
+
+ /*
+ * Fill in the message initiator context and transaction context.
+ * We will only use transaction contexts >= 0x80000000 for POST WAIT,
+ * so we could find a POST WAIT reply easier in the reply handler.
+ */
+ msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+ wait->tcntxt = tcntxt++;
+ msg->u.s.tcntxt = cpu_to_le32(wait->tcntxt);
+
+ wait->wq = &wq;
+ /*
+ * we add elements to the head, because if a entry in the list will
+ * never be removed, we have to iterate over it every time
+ */
+ list_add(&wait->list, &i2o_exec_wait_list);
+
+ /*
+ * Post the message to the controller. At some point later it will
+ * return. If we time out before it returns then complete will be zero.
+ */
+ i2o_msg_post(c, msg);
+
+ wait_event_interruptible_timeout(wq, wait->complete, timeout * HZ);
+
+ spin_lock_irqsave(&wait->lock, flags);
+
+ wait->wq = NULL;
+
+ if (wait->complete)
+ rc = le32_to_cpu(wait->msg->body[0]) >> 24;
+ else {
+ /*
+ * We cannot remove it now. This is important. When it does
+ * terminate (which it must do if the controller has not
+ * died...) then it will otherwise scribble on stuff.
+ *
+ * FIXME: try abort message
+ */
+ if (dma)
+ dma->virt = NULL;
+
+ rc = -ETIMEDOUT;
+ }
+
+ spin_unlock_irqrestore(&wait->lock, flags);
+
+ if (rc != -ETIMEDOUT) {
+ i2o_flush_reply(c, wait->m);
+ i2o_exec_wait_free(wait);
+ }
+
+ return rc;
+};
+
+/**
+ * i2o_msg_post_wait_complete - Reply to a i2o_msg_post request from IOP
+ * @c: I2O controller which answers
+ * @m: message id
+ * @msg: pointer to the I2O reply message
+ * @context: transaction context of request
+ *
+ * This function is called in interrupt context only. If the reply reached
+ * before the timeout, the i2o_exec_wait struct is filled with the message
+ * and the task will be waked up. The task is now responsible for returning
+ * the message m back to the controller! If the message reaches us after
+ * the timeout clean up the i2o_exec_wait struct (including allocated
+ * DMA buffer).
+ *
+ * Return 0 on success and if the message m should not be given back to the
+ * I2O controller, or >0 on success and if the message should be given back
+ * afterwords. Returns negative error code on failure. In this case the
+ * message must also be given back to the controller.
+ */
+static int i2o_msg_post_wait_complete(struct i2o_controller *c, u32 m,
+ struct i2o_message *msg, u32 context)
+{
+ struct i2o_exec_wait *wait, *tmp;
+ unsigned long flags;
+ int rc = 1;
+
+ /*
+ * We need to search through the i2o_exec_wait_list to see if the given
+ * message is still outstanding. If not, it means that the IOP took
+ * longer to respond to the message than we had allowed and timer has
+ * already expired. Not much we can do about that except log it for
+ * debug purposes, increase timeout, and recompile.
+ */
+ list_for_each_entry_safe(wait, tmp, &i2o_exec_wait_list, list) {
+ if (wait->tcntxt == context) {
+ spin_lock_irqsave(&wait->lock, flags);
+
+ list_del(&wait->list);
+
+ wait->m = m;
+ wait->msg = msg;
+ wait->complete = 1;
+
+ if (wait->wq)
+ rc = 0;
+ else
+ rc = -1;
+
+ spin_unlock_irqrestore(&wait->lock, flags);
+
+ if (rc) {
+ struct device *dev;
+
+ dev = &c->pdev->dev;
+
+ pr_debug("%s: timedout reply received!\n",
+ c->name);
+ i2o_dma_free(dev, &wait->dma);
+ i2o_exec_wait_free(wait);
+ } else
+ wake_up_interruptible(wait->wq);
+
+ return rc;
+ }
+ }
+
+ osm_warn("%s: Bogus reply in POST WAIT (tr-context: %08x)!\n", c->name,
+ context);
+
+ return -1;
+};
+
+/**
+ * i2o_exec_show_vendor_id - Displays Vendor ID of controller
+ * @d: device of which the Vendor ID should be displayed
+ * @attr: device_attribute to display
+ * @buf: buffer into which the Vendor ID should be printed
+ *
+ * Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_vendor_id(struct device *d,
+ struct device_attribute *attr, char *buf)
+{
+ struct i2o_device *dev = to_i2o_device(d);
+ u16 id;
+
+ if (!i2o_parm_field_get(dev, 0x0000, 0, &id, 2)) {
+ sprintf(buf, "0x%04x", le16_to_cpu(id));
+ return strlen(buf) + 1;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_exec_show_product_id - Displays Product ID of controller
+ * @d: device of which the Product ID should be displayed
+ * @attr: device_attribute to display
+ * @buf: buffer into which the Product ID should be printed
+ *
+ * Returns number of bytes printed into buffer.
+ */
+static ssize_t i2o_exec_show_product_id(struct device *d,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct i2o_device *dev = to_i2o_device(d);
+ u16 id;
+
+ if (!i2o_parm_field_get(dev, 0x0000, 1, &id, 2)) {
+ sprintf(buf, "0x%04x", le16_to_cpu(id));
+ return strlen(buf) + 1;
+ }
+
+ return 0;
+};
+
+/* Exec-OSM device attributes */
+static DEVICE_ATTR(vendor_id, S_IRUGO, i2o_exec_show_vendor_id, NULL);
+static DEVICE_ATTR(product_id, S_IRUGO, i2o_exec_show_product_id, NULL);
+
+/**
+ * i2o_exec_probe - Called if a new I2O device (executive class) appears
+ * @dev: I2O device which should be probed
+ *
+ * Registers event notification for every event from Executive device. The
+ * return is always 0, because we want all devices of class Executive.
+ *
+ * Returns 0 on success.
+ */
+static int i2o_exec_probe(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+ int rc;
+
+ rc = i2o_event_register(i2o_dev, &i2o_exec_driver, 0, 0xffffffff);
+ if (rc) goto err_out;
+
+ rc = device_create_file(dev, &dev_attr_vendor_id);
+ if (rc) goto err_evtreg;
+ rc = device_create_file(dev, &dev_attr_product_id);
+ if (rc) goto err_vid;
+
+ i2o_dev->iop->exec = i2o_dev;
+
+ return 0;
+
+err_vid:
+ device_remove_file(dev, &dev_attr_vendor_id);
+err_evtreg:
+ i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+err_out:
+ return rc;
+};
+
+/**
+ * i2o_exec_remove - Called on I2O device removal
+ * @dev: I2O device which was removed
+ *
+ * Unregisters event notification from Executive I2O device.
+ *
+ * Returns 0 on success.
+ */
+static int i2o_exec_remove(struct device *dev)
+{
+ device_remove_file(dev, &dev_attr_product_id);
+ device_remove_file(dev, &dev_attr_vendor_id);
+
+ i2o_event_register(to_i2o_device(dev), &i2o_exec_driver, 0, 0);
+
+ return 0;
+};
+
+#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
+/**
+ * i2o_exec_lct_notify - Send a asynchronus LCT NOTIFY request
+ * @c: I2O controller to which the request should be send
+ * @change_ind: change indicator
+ *
+ * This function sends a LCT NOTIFY request to the I2O controller with
+ * the change indicator change_ind. If the change_ind == 0 the controller
+ * replies immediately after the request. If change_ind > 0 the reply is
+ * send after change indicator of the LCT is > change_ind.
+ */
+static int i2o_exec_lct_notify(struct i2o_controller *c, u32 change_ind)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ struct device *dev;
+ struct i2o_message *msg;
+
+ mutex_lock(&c->lct_lock);
+
+ dev = &c->pdev->dev;
+
+ if (i2o_dma_realloc(dev, &c->dlct,
+ le32_to_cpu(sb->expected_lct_size))) {
+ mutex_unlock(&c->lct_lock);
+ return -ENOMEM;
+ }
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg)) {
+ mutex_unlock(&c->lct_lock);
+ return PTR_ERR(msg);
+ }
+
+ msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+ msg->u.head[1] = cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+ msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+ msg->body[0] = cpu_to_le32(0xffffffff);
+ msg->body[1] = cpu_to_le32(change_ind);
+ msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
+ msg->body[3] = cpu_to_le32(c->dlct.phys);
+
+ i2o_msg_post(c, msg);
+
+ mutex_unlock(&c->lct_lock);
+
+ return 0;
+}
+#endif
+
+/**
+ * i2o_exec_lct_modified - Called on LCT NOTIFY reply
+ * @_work: work struct for a specific controller
+ *
+ * This function handles asynchronus LCT NOTIFY replies. It parses the
+ * new LCT and if the buffer for the LCT was to small sends a LCT NOTIFY
+ * again, otherwise send LCT NOTIFY to get informed on next LCT change.
+ */
+static void i2o_exec_lct_modified(struct work_struct *_work)
+{
+ struct i2o_exec_lct_notify_work *work =
+ container_of(_work, struct i2o_exec_lct_notify_work, work);
+ u32 change_ind = 0;
+ struct i2o_controller *c = work->c;
+
+ kfree(work);
+
+ if (i2o_device_parse_lct(c) != -EAGAIN)
+ change_ind = c->lct->change_ind + 1;
+
+#ifdef CONFIG_I2O_LCT_NOTIFY_ON_CHANGES
+ i2o_exec_lct_notify(c, change_ind);
+#endif
+};
+
+/**
+ * i2o_exec_reply - I2O Executive reply handler
+ * @c: I2O controller from which the reply comes
+ * @m: message id
+ * @msg: pointer to the I2O reply message
+ *
+ * This function is always called from interrupt context. If a POST WAIT
+ * reply was received, pass it to the complete function. If a LCT NOTIFY
+ * reply was received, a new event is created to handle the update.
+ *
+ * Returns 0 on success and if the reply should not be flushed or > 0
+ * on success and if the reply should be flushed. Returns negative error
+ * code on failure and if the reply should be flushed.
+ */
+static int i2o_exec_reply(struct i2o_controller *c, u32 m,
+ struct i2o_message *msg)
+{
+ u32 context;
+
+ if (le32_to_cpu(msg->u.head[0]) & MSG_FAIL) {
+ struct i2o_message __iomem *pmsg;
+ u32 pm;
+
+ /*
+ * If Fail bit is set we must take the transaction context of
+ * the preserved message to find the right request again.
+ */
+
+ pm = le32_to_cpu(msg->body[3]);
+ pmsg = i2o_msg_in_to_virt(c, pm);
+ context = readl(&pmsg->u.s.tcntxt);
+
+ i2o_report_status(KERN_INFO, "i2o_core", msg);
+
+ /* Release the preserved msg */
+ i2o_msg_nop_mfa(c, pm);
+ } else
+ context = le32_to_cpu(msg->u.s.tcntxt);
+
+ if (context & 0x80000000)
+ return i2o_msg_post_wait_complete(c, m, msg, context);
+
+ if ((le32_to_cpu(msg->u.head[1]) >> 24) == I2O_CMD_LCT_NOTIFY) {
+ struct i2o_exec_lct_notify_work *work;
+
+ pr_debug("%s: LCT notify received\n", c->name);
+
+ work = kmalloc(sizeof(*work), GFP_ATOMIC);
+ if (!work)
+ return -ENOMEM;
+
+ work->c = c;
+
+ INIT_WORK(&work->work, i2o_exec_lct_modified);
+ queue_work(i2o_exec_driver.event_queue, &work->work);
+ return 1;
+ }
+
+ /*
+ * If this happens, we want to dump the message to the syslog so
+ * it can be sent back to the card manufacturer by the end user
+ * to aid in debugging.
+ *
+ */
+ printk(KERN_WARNING "%s: Unsolicited message reply sent to core!"
+ "Message dumped to syslog\n", c->name);
+ i2o_dump_message(msg);
+
+ return -EFAULT;
+}
+
+/**
+ * i2o_exec_event - Event handling function
+ * @work: Work item in occurring event
+ *
+ * Handles events send by the Executive device. At the moment does not do
+ * anything useful.
+ */
+static void i2o_exec_event(struct work_struct *work)
+{
+ struct i2o_event *evt = container_of(work, struct i2o_event, work);
+
+ if (likely(evt->i2o_dev))
+ osm_debug("Event received from device: %d\n",
+ evt->i2o_dev->lct_data.tid);
+ kfree(evt);
+};
+
+/**
+ * i2o_exec_lct_get - Get the IOP's Logical Configuration Table
+ * @c: I2O controller from which the LCT should be fetched
+ *
+ * Send a LCT NOTIFY request to the controller, and wait
+ * I2O_TIMEOUT_LCT_GET seconds until arrival of response. If the LCT is
+ * to large, retry it.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_exec_lct_get(struct i2o_controller *c)
+{
+ struct i2o_message *msg;
+ int i = 0;
+ int rc = -EAGAIN;
+
+ for (i = 1; i <= I2O_LCT_GET_TRIES; i++) {
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] =
+ cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_LCT_NOTIFY << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->body[0] = cpu_to_le32(0xffffffff);
+ msg->body[1] = cpu_to_le32(0x00000000);
+ msg->body[2] = cpu_to_le32(0xd0000000 | c->dlct.len);
+ msg->body[3] = cpu_to_le32(c->dlct.phys);
+
+ rc = i2o_msg_post_wait(c, msg, I2O_TIMEOUT_LCT_GET);
+ if (rc < 0)
+ break;
+
+ rc = i2o_device_parse_lct(c);
+ if (rc != -EAGAIN)
+ break;
+ }
+
+ return rc;
+}
+
+/* Exec OSM driver struct */
+struct i2o_driver i2o_exec_driver = {
+ .name = OSM_NAME,
+ .reply = i2o_exec_reply,
+ .event = i2o_exec_event,
+ .classes = i2o_exec_class_id,
+ .driver = {
+ .probe = i2o_exec_probe,
+ .remove = i2o_exec_remove,
+ },
+};
+
+/**
+ * i2o_exec_init - Registers the Exec OSM
+ *
+ * Registers the Exec OSM in the I2O core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int __init i2o_exec_init(void)
+{
+ return i2o_driver_register(&i2o_exec_driver);
+};
+
+/**
+ * i2o_exec_exit - Removes the Exec OSM
+ *
+ * Unregisters the Exec OSM from the I2O core.
+ */
+void i2o_exec_exit(void)
+{
+ i2o_driver_unregister(&i2o_exec_driver);
+};
+
+EXPORT_SYMBOL(i2o_msg_post_wait_mem);
+EXPORT_SYMBOL(i2o_exec_lct_get);
diff --git a/drivers/staging/i2o/i2o.h b/drivers/staging/i2o/i2o.h
new file mode 100644
index 000000000000..d23c3c20b201
--- /dev/null
+++ b/drivers/staging/i2o/i2o.h
@@ -0,0 +1,988 @@
+/*
+ * I2O kernel space accessible structures/APIs
+ *
+ * (c) Copyright 1999, 2000 Red Hat Software
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ *************************************************************************
+ *
+ * This header file defined the I2O APIs/structures for use by
+ * the I2O kernel modules.
+ *
+ */
+
+#ifndef _I2O_H
+#define _I2O_H
+
+#include <linux/i2o-dev.h>
+
+/* How many different OSM's are we allowing */
+#define I2O_MAX_DRIVERS 8
+
+#include <linux/pci.h>
+#include <linux/bug.h>
+#include <linux/dma-mapping.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/workqueue.h> /* work_struct */
+#include <linux/mempool.h>
+#include <linux/mutex.h>
+#include <linux/scatterlist.h>
+#include <linux/semaphore.h> /* Needed for MUTEX init macros */
+
+#include <asm/io.h>
+
+/* message queue empty */
+#define I2O_QUEUE_EMPTY 0xffffffff
+
+/*
+ * Cache strategies
+ */
+
+/* The NULL strategy leaves everything up to the controller. This tends to be a
+ * pessimal but functional choice.
+ */
+#define CACHE_NULL 0
+/* Prefetch data when reading. We continually attempt to load the next 32 sectors
+ * into the controller cache.
+ */
+#define CACHE_PREFETCH 1
+/* Prefetch data when reading. We sometimes attempt to load the next 32 sectors
+ * into the controller cache. When an I/O is less <= 8K we assume its probably
+ * not sequential and don't prefetch (default)
+ */
+#define CACHE_SMARTFETCH 2
+/* Data is written to the cache and then out on to the disk. The I/O must be
+ * physically on the medium before the write is acknowledged (default without
+ * NVRAM)
+ */
+#define CACHE_WRITETHROUGH 17
+/* Data is written to the cache and then out on to the disk. The controller
+ * is permitted to write back the cache any way it wants. (default if battery
+ * backed NVRAM is present). It can be useful to set this for swap regardless of
+ * battery state.
+ */
+#define CACHE_WRITEBACK 18
+/* Optimise for under powered controllers, especially on RAID1 and RAID0. We
+ * write large I/O's directly to disk bypassing the cache to avoid the extra
+ * memory copy hits. Small writes are writeback cached
+ */
+#define CACHE_SMARTBACK 19
+/* Optimise for under powered controllers, especially on RAID1 and RAID0. We
+ * write large I/O's directly to disk bypassing the cache to avoid the extra
+ * memory copy hits. Small writes are writethrough cached. Suitable for devices
+ * lacking battery backup
+ */
+#define CACHE_SMARTTHROUGH 20
+
+/*
+ * Ioctl structures
+ */
+
+#define BLKI2OGRSTRAT _IOR('2', 1, int)
+#define BLKI2OGWSTRAT _IOR('2', 2, int)
+#define BLKI2OSRSTRAT _IOW('2', 3, int)
+#define BLKI2OSWSTRAT _IOW('2', 4, int)
+
+/*
+ * I2O Function codes
+ */
+
+/*
+ * Executive Class
+ */
+#define I2O_CMD_ADAPTER_ASSIGN 0xB3
+#define I2O_CMD_ADAPTER_READ 0xB2
+#define I2O_CMD_ADAPTER_RELEASE 0xB5
+#define I2O_CMD_BIOS_INFO_SET 0xA5
+#define I2O_CMD_BOOT_DEVICE_SET 0xA7
+#define I2O_CMD_CONFIG_VALIDATE 0xBB
+#define I2O_CMD_CONN_SETUP 0xCA
+#define I2O_CMD_DDM_DESTROY 0xB1
+#define I2O_CMD_DDM_ENABLE 0xD5
+#define I2O_CMD_DDM_QUIESCE 0xC7
+#define I2O_CMD_DDM_RESET 0xD9
+#define I2O_CMD_DDM_SUSPEND 0xAF
+#define I2O_CMD_DEVICE_ASSIGN 0xB7
+#define I2O_CMD_DEVICE_RELEASE 0xB9
+#define I2O_CMD_HRT_GET 0xA8
+#define I2O_CMD_ADAPTER_CLEAR 0xBE
+#define I2O_CMD_ADAPTER_CONNECT 0xC9
+#define I2O_CMD_ADAPTER_RESET 0xBD
+#define I2O_CMD_LCT_NOTIFY 0xA2
+#define I2O_CMD_OUTBOUND_INIT 0xA1
+#define I2O_CMD_PATH_ENABLE 0xD3
+#define I2O_CMD_PATH_QUIESCE 0xC5
+#define I2O_CMD_PATH_RESET 0xD7
+#define I2O_CMD_STATIC_MF_CREATE 0xDD
+#define I2O_CMD_STATIC_MF_RELEASE 0xDF
+#define I2O_CMD_STATUS_GET 0xA0
+#define I2O_CMD_SW_DOWNLOAD 0xA9
+#define I2O_CMD_SW_UPLOAD 0xAB
+#define I2O_CMD_SW_REMOVE 0xAD
+#define I2O_CMD_SYS_ENABLE 0xD1
+#define I2O_CMD_SYS_MODIFY 0xC1
+#define I2O_CMD_SYS_QUIESCE 0xC3
+#define I2O_CMD_SYS_TAB_SET 0xA3
+
+/*
+ * Utility Class
+ */
+#define I2O_CMD_UTIL_NOP 0x00
+#define I2O_CMD_UTIL_ABORT 0x01
+#define I2O_CMD_UTIL_CLAIM 0x09
+#define I2O_CMD_UTIL_RELEASE 0x0B
+#define I2O_CMD_UTIL_PARAMS_GET 0x06
+#define I2O_CMD_UTIL_PARAMS_SET 0x05
+#define I2O_CMD_UTIL_EVT_REGISTER 0x13
+#define I2O_CMD_UTIL_EVT_ACK 0x14
+#define I2O_CMD_UTIL_CONFIG_DIALOG 0x10
+#define I2O_CMD_UTIL_DEVICE_RESERVE 0x0D
+#define I2O_CMD_UTIL_DEVICE_RELEASE 0x0F
+#define I2O_CMD_UTIL_LOCK 0x17
+#define I2O_CMD_UTIL_LOCK_RELEASE 0x19
+#define I2O_CMD_UTIL_REPLY_FAULT_NOTIFY 0x15
+
+/*
+ * SCSI Host Bus Adapter Class
+ */
+#define I2O_CMD_SCSI_EXEC 0x81
+#define I2O_CMD_SCSI_ABORT 0x83
+#define I2O_CMD_SCSI_BUSRESET 0x27
+
+/*
+ * Bus Adapter Class
+ */
+#define I2O_CMD_BUS_ADAPTER_RESET 0x85
+#define I2O_CMD_BUS_RESET 0x87
+#define I2O_CMD_BUS_SCAN 0x89
+#define I2O_CMD_BUS_QUIESCE 0x8b
+
+/*
+ * Random Block Storage Class
+ */
+#define I2O_CMD_BLOCK_READ 0x30
+#define I2O_CMD_BLOCK_WRITE 0x31
+#define I2O_CMD_BLOCK_CFLUSH 0x37
+#define I2O_CMD_BLOCK_MLOCK 0x49
+#define I2O_CMD_BLOCK_MUNLOCK 0x4B
+#define I2O_CMD_BLOCK_MMOUNT 0x41
+#define I2O_CMD_BLOCK_MEJECT 0x43
+#define I2O_CMD_BLOCK_POWER 0x70
+
+#define I2O_CMD_PRIVATE 0xFF
+
+/* Command status values */
+
+#define I2O_CMD_IN_PROGRESS 0x01
+#define I2O_CMD_REJECTED 0x02
+#define I2O_CMD_FAILED 0x03
+#define I2O_CMD_COMPLETED 0x04
+
+/* I2O API function return values */
+
+#define I2O_RTN_NO_ERROR 0
+#define I2O_RTN_NOT_INIT 1
+#define I2O_RTN_FREE_Q_EMPTY 2
+#define I2O_RTN_TCB_ERROR 3
+#define I2O_RTN_TRANSACTION_ERROR 4
+#define I2O_RTN_ADAPTER_ALREADY_INIT 5
+#define I2O_RTN_MALLOC_ERROR 6
+#define I2O_RTN_ADPTR_NOT_REGISTERED 7
+#define I2O_RTN_MSG_REPLY_TIMEOUT 8
+#define I2O_RTN_NO_STATUS 9
+#define I2O_RTN_NO_FIRM_VER 10
+#define I2O_RTN_NO_LINK_SPEED 11
+
+/* Reply message status defines for all messages */
+
+#define I2O_REPLY_STATUS_SUCCESS 0x00
+#define I2O_REPLY_STATUS_ABORT_DIRTY 0x01
+#define I2O_REPLY_STATUS_ABORT_NO_DATA_TRANSFER 0x02
+#define I2O_REPLY_STATUS_ABORT_PARTIAL_TRANSFER 0x03
+#define I2O_REPLY_STATUS_ERROR_DIRTY 0x04
+#define I2O_REPLY_STATUS_ERROR_NO_DATA_TRANSFER 0x05
+#define I2O_REPLY_STATUS_ERROR_PARTIAL_TRANSFER 0x06
+#define I2O_REPLY_STATUS_PROCESS_ABORT_DIRTY 0x08
+#define I2O_REPLY_STATUS_PROCESS_ABORT_NO_DATA_TRANSFER 0x09
+#define I2O_REPLY_STATUS_PROCESS_ABORT_PARTIAL_TRANSFER 0x0A
+#define I2O_REPLY_STATUS_TRANSACTION_ERROR 0x0B
+#define I2O_REPLY_STATUS_PROGRESS_REPORT 0x80
+
+/* Status codes and Error Information for Parameter functions */
+
+#define I2O_PARAMS_STATUS_SUCCESS 0x00
+#define I2O_PARAMS_STATUS_BAD_KEY_ABORT 0x01
+#define I2O_PARAMS_STATUS_BAD_KEY_CONTINUE 0x02
+#define I2O_PARAMS_STATUS_BUFFER_FULL 0x03
+#define I2O_PARAMS_STATUS_BUFFER_TOO_SMALL 0x04
+#define I2O_PARAMS_STATUS_FIELD_UNREADABLE 0x05
+#define I2O_PARAMS_STATUS_FIELD_UNWRITEABLE 0x06
+#define I2O_PARAMS_STATUS_INSUFFICIENT_FIELDS 0x07
+#define I2O_PARAMS_STATUS_INVALID_GROUP_ID 0x08
+#define I2O_PARAMS_STATUS_INVALID_OPERATION 0x09
+#define I2O_PARAMS_STATUS_NO_KEY_FIELD 0x0A
+#define I2O_PARAMS_STATUS_NO_SUCH_FIELD 0x0B
+#define I2O_PARAMS_STATUS_NON_DYNAMIC_GROUP 0x0C
+#define I2O_PARAMS_STATUS_OPERATION_ERROR 0x0D
+#define I2O_PARAMS_STATUS_SCALAR_ERROR 0x0E
+#define I2O_PARAMS_STATUS_TABLE_ERROR 0x0F
+#define I2O_PARAMS_STATUS_WRONG_GROUP_TYPE 0x10
+
+/* DetailedStatusCode defines for Executive, DDM, Util and Transaction error
+ * messages: Table 3-2 Detailed Status Codes.*/
+
+#define I2O_DSC_SUCCESS 0x0000
+#define I2O_DSC_BAD_KEY 0x0002
+#define I2O_DSC_TCL_ERROR 0x0003
+#define I2O_DSC_REPLY_BUFFER_FULL 0x0004
+#define I2O_DSC_NO_SUCH_PAGE 0x0005
+#define I2O_DSC_INSUFFICIENT_RESOURCE_SOFT 0x0006
+#define I2O_DSC_INSUFFICIENT_RESOURCE_HARD 0x0007
+#define I2O_DSC_CHAIN_BUFFER_TOO_LARGE 0x0009
+#define I2O_DSC_UNSUPPORTED_FUNCTION 0x000A
+#define I2O_DSC_DEVICE_LOCKED 0x000B
+#define I2O_DSC_DEVICE_RESET 0x000C
+#define I2O_DSC_INAPPROPRIATE_FUNCTION 0x000D
+#define I2O_DSC_INVALID_INITIATOR_ADDRESS 0x000E
+#define I2O_DSC_INVALID_MESSAGE_FLAGS 0x000F
+#define I2O_DSC_INVALID_OFFSET 0x0010
+#define I2O_DSC_INVALID_PARAMETER 0x0011
+#define I2O_DSC_INVALID_REQUEST 0x0012
+#define I2O_DSC_INVALID_TARGET_ADDRESS 0x0013
+#define I2O_DSC_MESSAGE_TOO_LARGE 0x0014
+#define I2O_DSC_MESSAGE_TOO_SMALL 0x0015
+#define I2O_DSC_MISSING_PARAMETER 0x0016
+#define I2O_DSC_TIMEOUT 0x0017
+#define I2O_DSC_UNKNOWN_ERROR 0x0018
+#define I2O_DSC_UNKNOWN_FUNCTION 0x0019
+#define I2O_DSC_UNSUPPORTED_VERSION 0x001A
+#define I2O_DSC_DEVICE_BUSY 0x001B
+#define I2O_DSC_DEVICE_NOT_AVAILABLE 0x001C
+
+/* DetailedStatusCode defines for Block Storage Operation: Table 6-7 Detailed
+ Status Codes.*/
+
+#define I2O_BSA_DSC_SUCCESS 0x0000
+#define I2O_BSA_DSC_MEDIA_ERROR 0x0001
+#define I2O_BSA_DSC_ACCESS_ERROR 0x0002
+#define I2O_BSA_DSC_DEVICE_FAILURE 0x0003
+#define I2O_BSA_DSC_DEVICE_NOT_READY 0x0004
+#define I2O_BSA_DSC_MEDIA_NOT_PRESENT 0x0005
+#define I2O_BSA_DSC_MEDIA_LOCKED 0x0006
+#define I2O_BSA_DSC_MEDIA_FAILURE 0x0007
+#define I2O_BSA_DSC_PROTOCOL_FAILURE 0x0008
+#define I2O_BSA_DSC_BUS_FAILURE 0x0009
+#define I2O_BSA_DSC_ACCESS_VIOLATION 0x000A
+#define I2O_BSA_DSC_WRITE_PROTECTED 0x000B
+#define I2O_BSA_DSC_DEVICE_RESET 0x000C
+#define I2O_BSA_DSC_VOLUME_CHANGED 0x000D
+#define I2O_BSA_DSC_TIMEOUT 0x000E
+
+/* FailureStatusCodes, Table 3-3 Message Failure Codes */
+
+#define I2O_FSC_TRANSPORT_SERVICE_SUSPENDED 0x81
+#define I2O_FSC_TRANSPORT_SERVICE_TERMINATED 0x82
+#define I2O_FSC_TRANSPORT_CONGESTION 0x83
+#define I2O_FSC_TRANSPORT_FAILURE 0x84
+#define I2O_FSC_TRANSPORT_STATE_ERROR 0x85
+#define I2O_FSC_TRANSPORT_TIME_OUT 0x86
+#define I2O_FSC_TRANSPORT_ROUTING_FAILURE 0x87
+#define I2O_FSC_TRANSPORT_INVALID_VERSION 0x88
+#define I2O_FSC_TRANSPORT_INVALID_OFFSET 0x89
+#define I2O_FSC_TRANSPORT_INVALID_MSG_FLAGS 0x8A
+#define I2O_FSC_TRANSPORT_FRAME_TOO_SMALL 0x8B
+#define I2O_FSC_TRANSPORT_FRAME_TOO_LARGE 0x8C
+#define I2O_FSC_TRANSPORT_INVALID_TARGET_ID 0x8D
+#define I2O_FSC_TRANSPORT_INVALID_INITIATOR_ID 0x8E
+#define I2O_FSC_TRANSPORT_INVALID_INITIATOR_CONTEXT 0x8F
+#define I2O_FSC_TRANSPORT_UNKNOWN_FAILURE 0xFF
+
+/* Device Claim Types */
+#define I2O_CLAIM_PRIMARY 0x01000000
+#define I2O_CLAIM_MANAGEMENT 0x02000000
+#define I2O_CLAIM_AUTHORIZED 0x03000000
+#define I2O_CLAIM_SECONDARY 0x04000000
+
+/* Message header defines for VersionOffset */
+#define I2OVER15 0x0001
+#define I2OVER20 0x0002
+
+/* Default is 1.5 */
+#define I2OVERSION I2OVER15
+
+#define SGL_OFFSET_0 I2OVERSION
+#define SGL_OFFSET_4 (0x0040 | I2OVERSION)
+#define SGL_OFFSET_5 (0x0050 | I2OVERSION)
+#define SGL_OFFSET_6 (0x0060 | I2OVERSION)
+#define SGL_OFFSET_7 (0x0070 | I2OVERSION)
+#define SGL_OFFSET_8 (0x0080 | I2OVERSION)
+#define SGL_OFFSET_9 (0x0090 | I2OVERSION)
+#define SGL_OFFSET_10 (0x00A0 | I2OVERSION)
+#define SGL_OFFSET_11 (0x00B0 | I2OVERSION)
+#define SGL_OFFSET_12 (0x00C0 | I2OVERSION)
+#define SGL_OFFSET(x) (((x)<<4) | I2OVERSION)
+
+/* Transaction Reply Lists (TRL) Control Word structure */
+#define TRL_SINGLE_FIXED_LENGTH 0x00
+#define TRL_SINGLE_VARIABLE_LENGTH 0x40
+#define TRL_MULTIPLE_FIXED_LENGTH 0x80
+
+ /* msg header defines for MsgFlags */
+#define MSG_STATIC 0x0100
+#define MSG_64BIT_CNTXT 0x0200
+#define MSG_MULTI_TRANS 0x1000
+#define MSG_FAIL 0x2000
+#define MSG_FINAL 0x4000
+#define MSG_REPLY 0x8000
+
+ /* minimum size msg */
+#define THREE_WORD_MSG_SIZE 0x00030000
+#define FOUR_WORD_MSG_SIZE 0x00040000
+#define FIVE_WORD_MSG_SIZE 0x00050000
+#define SIX_WORD_MSG_SIZE 0x00060000
+#define SEVEN_WORD_MSG_SIZE 0x00070000
+#define EIGHT_WORD_MSG_SIZE 0x00080000
+#define NINE_WORD_MSG_SIZE 0x00090000
+#define TEN_WORD_MSG_SIZE 0x000A0000
+#define ELEVEN_WORD_MSG_SIZE 0x000B0000
+#define I2O_MESSAGE_SIZE(x) ((x)<<16)
+
+/* special TID assignments */
+#define ADAPTER_TID 0
+#define HOST_TID 1
+
+/* outbound queue defines */
+#define I2O_MAX_OUTBOUND_MSG_FRAMES 128
+#define I2O_OUTBOUND_MSG_FRAME_SIZE 128 /* in 32-bit words */
+
+/* inbound queue definitions */
+#define I2O_MSG_INPOOL_MIN 32
+#define I2O_INBOUND_MSG_FRAME_SIZE 128 /* in 32-bit words */
+
+#define I2O_POST_WAIT_OK 0
+#define I2O_POST_WAIT_TIMEOUT -ETIMEDOUT
+
+#define I2O_CONTEXT_LIST_MIN_LENGTH 15
+#define I2O_CONTEXT_LIST_USED 0x01
+#define I2O_CONTEXT_LIST_DELETED 0x02
+
+/* timeouts */
+#define I2O_TIMEOUT_INIT_OUTBOUND_QUEUE 15
+#define I2O_TIMEOUT_MESSAGE_GET 5
+#define I2O_TIMEOUT_RESET 30
+#define I2O_TIMEOUT_STATUS_GET 5
+#define I2O_TIMEOUT_LCT_GET 360
+#define I2O_TIMEOUT_SCSI_SCB_ABORT 240
+
+/* retries */
+#define I2O_HRT_GET_TRIES 3
+#define I2O_LCT_GET_TRIES 3
+
+/* defines for max_sectors and max_phys_segments */
+#define I2O_MAX_SECTORS 1024
+#define I2O_MAX_SECTORS_LIMITED 128
+#define I2O_MAX_PHYS_SEGMENTS BLK_MAX_SEGMENTS
+
+/*
+ * Message structures
+ */
+struct i2o_message {
+ union {
+ struct {
+ u8 version_offset;
+ u8 flags;
+ u16 size;
+ u32 target_tid:12;
+ u32 init_tid:12;
+ u32 function:8;
+ u32 icntxt; /* initiator context */
+ u32 tcntxt; /* transaction context */
+ } s;
+ u32 head[4];
+ } u;
+ /* List follows */
+ u32 body[0];
+};
+
+/* MFA and I2O message used by mempool */
+struct i2o_msg_mfa {
+ u32 mfa; /* MFA returned by the controller */
+ struct i2o_message msg; /* I2O message */
+};
+
+/*
+ * Each I2O device entity has one of these. There is one per device.
+ */
+struct i2o_device {
+ i2o_lct_entry lct_data; /* Device LCT information */
+
+ struct i2o_controller *iop; /* Controlling IOP */
+ struct list_head list; /* node in IOP devices list */
+
+ struct device device;
+
+ struct mutex lock; /* device lock */
+};
+
+/*
+ * Event structure provided to the event handling function
+ */
+struct i2o_event {
+ struct work_struct work;
+ struct i2o_device *i2o_dev; /* I2O device pointer from which the
+ event reply was initiated */
+ u16 size; /* Size of data in 32-bit words */
+ u32 tcntxt; /* Transaction context used at
+ registration */
+ u32 event_indicator; /* Event indicator from reply */
+ u32 data[0]; /* Event data from reply */
+};
+
+/*
+ * I2O classes which could be handled by the OSM
+ */
+struct i2o_class_id {
+ u16 class_id:12;
+};
+
+/*
+ * I2O driver structure for OSMs
+ */
+struct i2o_driver {
+ char *name; /* OSM name */
+ int context; /* Low 8 bits of the transaction info */
+ struct i2o_class_id *classes; /* I2O classes that this OSM handles */
+
+ /* Message reply handler */
+ int (*reply) (struct i2o_controller *, u32, struct i2o_message *);
+
+ /* Event handler */
+ work_func_t event;
+
+ struct workqueue_struct *event_queue; /* Event queue */
+
+ struct device_driver driver;
+
+ /* notification of changes */
+ void (*notify_controller_add) (struct i2o_controller *);
+ void (*notify_controller_remove) (struct i2o_controller *);
+ void (*notify_device_add) (struct i2o_device *);
+ void (*notify_device_remove) (struct i2o_device *);
+
+ struct semaphore lock;
+};
+
+/*
+ * Contains DMA mapped address information
+ */
+struct i2o_dma {
+ void *virt;
+ dma_addr_t phys;
+ size_t len;
+};
+
+/*
+ * Contains slab cache and mempool information
+ */
+struct i2o_pool {
+ char *name;
+ struct kmem_cache *slab;
+ mempool_t *mempool;
+};
+
+/*
+ * Contains IO mapped address information
+ */
+struct i2o_io {
+ void __iomem *virt;
+ unsigned long phys;
+ unsigned long len;
+};
+
+/*
+ * Context queue entry, used for 32-bit context on 64-bit systems
+ */
+struct i2o_context_list_element {
+ struct list_head list;
+ u32 context;
+ void *ptr;
+ unsigned long timestamp;
+};
+
+/*
+ * Each I2O controller has one of these objects
+ */
+struct i2o_controller {
+ char name[16];
+ int unit;
+ int type;
+
+ struct pci_dev *pdev; /* PCI device */
+
+ unsigned int promise:1; /* Promise controller */
+ unsigned int adaptec:1; /* DPT / Adaptec controller */
+ unsigned int raptor:1; /* split bar */
+ unsigned int no_quiesce:1; /* dont quiesce before reset */
+ unsigned int short_req:1; /* use small block sizes */
+ unsigned int limit_sectors:1; /* limit number of sectors / request */
+ unsigned int pae_support:1; /* controller has 64-bit SGL support */
+
+ struct list_head devices; /* list of I2O devices */
+ struct list_head list; /* Controller list */
+
+ void __iomem *in_port; /* Inbout port address */
+ void __iomem *out_port; /* Outbound port address */
+ void __iomem *irq_status; /* Interrupt status register address */
+ void __iomem *irq_mask; /* Interrupt mask register address */
+
+ struct i2o_dma status; /* IOP status block */
+
+ struct i2o_dma hrt; /* HW Resource Table */
+ i2o_lct *lct; /* Logical Config Table */
+ struct i2o_dma dlct; /* Temp LCT */
+ struct mutex lct_lock; /* Lock for LCT updates */
+ struct i2o_dma status_block; /* IOP status block */
+
+ struct i2o_io base; /* controller messaging unit */
+ struct i2o_io in_queue; /* inbound message queue Host->IOP */
+ struct i2o_dma out_queue; /* outbound message queue IOP->Host */
+
+ struct i2o_pool in_msg; /* mempool for inbound messages */
+
+ unsigned int battery:1; /* Has a battery backup */
+ unsigned int io_alloc:1; /* An I/O resource was allocated */
+ unsigned int mem_alloc:1; /* A memory resource was allocated */
+
+ struct resource io_resource; /* I/O resource allocated to the IOP */
+ struct resource mem_resource; /* Mem resource allocated to the IOP */
+
+ struct device device;
+ struct i2o_device *exec; /* Executive */
+#if BITS_PER_LONG == 64
+ spinlock_t context_list_lock; /* lock for context_list */
+ atomic_t context_list_counter; /* needed for unique contexts */
+ struct list_head context_list; /* list of context id's
+ and pointers */
+#endif
+ spinlock_t lock; /* lock for controller
+ configuration */
+ void *driver_data[I2O_MAX_DRIVERS]; /* storage for drivers */
+};
+
+/*
+ * I2O System table entry
+ *
+ * The system table contains information about all the IOPs in the
+ * system. It is sent to all IOPs so that they can create peer2peer
+ * connections between them.
+ */
+struct i2o_sys_tbl_entry {
+ u16 org_id;
+ u16 reserved1;
+ u32 iop_id:12;
+ u32 reserved2:20;
+ u16 seg_num:12;
+ u16 i2o_version:4;
+ u8 iop_state;
+ u8 msg_type;
+ u16 frame_size;
+ u16 reserved3;
+ u32 last_changed;
+ u32 iop_capabilities;
+ u32 inbound_low;
+ u32 inbound_high;
+};
+
+struct i2o_sys_tbl {
+ u8 num_entries;
+ u8 version;
+ u16 reserved1;
+ u32 change_ind;
+ u32 reserved2;
+ u32 reserved3;
+ struct i2o_sys_tbl_entry iops[0];
+};
+
+extern struct list_head i2o_controllers;
+
+/* Message functions */
+extern struct i2o_message *i2o_msg_get_wait(struct i2o_controller *, int);
+extern int i2o_msg_post_wait_mem(struct i2o_controller *, struct i2o_message *,
+ unsigned long, struct i2o_dma *);
+
+/* IOP functions */
+extern int i2o_status_get(struct i2o_controller *);
+
+extern int i2o_event_register(struct i2o_device *, struct i2o_driver *, int,
+ u32);
+extern struct i2o_device *i2o_iop_find_device(struct i2o_controller *, u16);
+extern struct i2o_controller *i2o_find_iop(int);
+
+/* Functions needed for handling 64-bit pointers in 32-bit context */
+#if BITS_PER_LONG == 64
+extern u32 i2o_cntxt_list_add(struct i2o_controller *, void *);
+extern void *i2o_cntxt_list_get(struct i2o_controller *, u32);
+extern u32 i2o_cntxt_list_remove(struct i2o_controller *, void *);
+extern u32 i2o_cntxt_list_get_ptr(struct i2o_controller *, void *);
+
+static inline u32 i2o_ptr_low(void *ptr)
+{
+ return (u32) (u64) ptr;
+};
+
+static inline u32 i2o_ptr_high(void *ptr)
+{
+ return (u32) ((u64) ptr >> 32);
+};
+
+static inline u32 i2o_dma_low(dma_addr_t dma_addr)
+{
+ return (u32) (u64) dma_addr;
+};
+
+static inline u32 i2o_dma_high(dma_addr_t dma_addr)
+{
+ return (u32) ((u64) dma_addr >> 32);
+};
+#else
+static inline u32 i2o_cntxt_list_add(struct i2o_controller *c, void *ptr)
+{
+ return (u32) ptr;
+};
+
+static inline void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
+{
+ return (void *)context;
+};
+
+static inline u32 i2o_cntxt_list_remove(struct i2o_controller *c, void *ptr)
+{
+ return (u32) ptr;
+};
+
+static inline u32 i2o_cntxt_list_get_ptr(struct i2o_controller *c, void *ptr)
+{
+ return (u32) ptr;
+};
+
+static inline u32 i2o_ptr_low(void *ptr)
+{
+ return (u32) ptr;
+};
+
+static inline u32 i2o_ptr_high(void *ptr)
+{
+ return 0;
+};
+
+static inline u32 i2o_dma_low(dma_addr_t dma_addr)
+{
+ return (u32) dma_addr;
+};
+
+static inline u32 i2o_dma_high(dma_addr_t dma_addr)
+{
+ return 0;
+};
+#endif
+
+extern u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size);
+extern dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+ size_t size,
+ enum dma_data_direction direction,
+ u32 ** sg_ptr);
+extern int i2o_dma_map_sg(struct i2o_controller *c,
+ struct scatterlist *sg, int sg_count,
+ enum dma_data_direction direction,
+ u32 ** sg_ptr);
+extern int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len);
+extern void i2o_dma_free(struct device *dev, struct i2o_dma *addr);
+extern int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr,
+ size_t len);
+extern int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+ size_t size, int min_nr);
+extern void i2o_pool_free(struct i2o_pool *pool);
+/* I2O driver (OSM) functions */
+extern int i2o_driver_register(struct i2o_driver *);
+extern void i2o_driver_unregister(struct i2o_driver *);
+
+/**
+ * i2o_driver_notify_controller_add - Send notification of added controller
+ * @drv: I2O driver
+ * @c: I2O controller
+ *
+ * Send notification of added controller to a single registered driver.
+ */
+static inline void i2o_driver_notify_controller_add(struct i2o_driver *drv,
+ struct i2o_controller *c)
+{
+ if (drv->notify_controller_add)
+ drv->notify_controller_add(c);
+};
+
+/**
+ * i2o_driver_notify_controller_remove - Send notification of removed controller
+ * @drv: I2O driver
+ * @c: I2O controller
+ *
+ * Send notification of removed controller to a single registered driver.
+ */
+static inline void i2o_driver_notify_controller_remove(struct i2o_driver *drv,
+ struct i2o_controller *c)
+{
+ if (drv->notify_controller_remove)
+ drv->notify_controller_remove(c);
+};
+
+/**
+ * i2o_driver_notify_device_add - Send notification of added device
+ * @drv: I2O driver
+ * @i2o_dev: the added i2o_device
+ *
+ * Send notification of added device to a single registered driver.
+ */
+static inline void i2o_driver_notify_device_add(struct i2o_driver *drv,
+ struct i2o_device *i2o_dev)
+{
+ if (drv->notify_device_add)
+ drv->notify_device_add(i2o_dev);
+};
+
+/**
+ * i2o_driver_notify_device_remove - Send notification of removed device
+ * @drv: I2O driver
+ * @i2o_dev: the added i2o_device
+ *
+ * Send notification of removed device to a single registered driver.
+ */
+static inline void i2o_driver_notify_device_remove(struct i2o_driver *drv,
+ struct i2o_device *i2o_dev)
+{
+ if (drv->notify_device_remove)
+ drv->notify_device_remove(i2o_dev);
+};
+
+extern void i2o_driver_notify_controller_add_all(struct i2o_controller *);
+extern void i2o_driver_notify_controller_remove_all(struct i2o_controller *);
+extern void i2o_driver_notify_device_add_all(struct i2o_device *);
+extern void i2o_driver_notify_device_remove_all(struct i2o_device *);
+
+/* I2O device functions */
+extern int i2o_device_claim(struct i2o_device *);
+extern int i2o_device_claim_release(struct i2o_device *);
+
+/* Exec OSM functions */
+extern int i2o_exec_lct_get(struct i2o_controller *);
+
+/* device / driver / kobject conversion functions */
+#define to_i2o_driver(drv) container_of(drv,struct i2o_driver, driver)
+#define to_i2o_device(dev) container_of(dev, struct i2o_device, device)
+#define to_i2o_controller(dev) container_of(dev, struct i2o_controller, device)
+
+/**
+ * i2o_out_to_virt - Turn an I2O message to a virtual address
+ * @c: controller
+ * @m: message engine value
+ *
+ * Turn a receive message from an I2O controller bus address into
+ * a Linux virtual address. The shared page frame is a linear block
+ * so we simply have to shift the offset. This function does not
+ * work for sender side messages as they are ioremap objects
+ * provided by the I2O controller.
+ */
+static inline struct i2o_message *i2o_msg_out_to_virt(struct i2o_controller *c,
+ u32 m)
+{
+ BUG_ON(m < c->out_queue.phys
+ || m >= c->out_queue.phys + c->out_queue.len);
+
+ return c->out_queue.virt + (m - c->out_queue.phys);
+};
+
+/**
+ * i2o_msg_in_to_virt - Turn an I2O message to a virtual address
+ * @c: controller
+ * @m: message engine value
+ *
+ * Turn a send message from an I2O controller bus address into
+ * a Linux virtual address. The shared page frame is a linear block
+ * so we simply have to shift the offset. This function does not
+ * work for receive side messages as they are kmalloc objects
+ * in a different pool.
+ */
+static inline struct i2o_message __iomem *i2o_msg_in_to_virt(struct
+ i2o_controller *c,
+ u32 m)
+{
+ return c->in_queue.virt + m;
+};
+
+/**
+ * i2o_msg_get - obtain an I2O message from the IOP
+ * @c: I2O controller
+ *
+ * This function tries to get a message frame. If no message frame is
+ * available do not wait until one is available (see also i2o_msg_get_wait).
+ * The returned pointer to the message frame is not in I/O memory, it is
+ * allocated from a mempool. But because a MFA is allocated from the
+ * controller too it is guaranteed that i2o_msg_post() will never fail.
+ *
+ * On a success a pointer to the message frame is returned. If the message
+ * queue is empty -EBUSY is returned and if no memory is available -ENOMEM
+ * is returned.
+ */
+static inline struct i2o_message *i2o_msg_get(struct i2o_controller *c)
+{
+ struct i2o_msg_mfa *mmsg = mempool_alloc(c->in_msg.mempool, GFP_ATOMIC);
+ if (!mmsg)
+ return ERR_PTR(-ENOMEM);
+
+ mmsg->mfa = readl(c->in_port);
+ if (unlikely(mmsg->mfa >= c->in_queue.len)) {
+ u32 mfa = mmsg->mfa;
+
+ mempool_free(mmsg, c->in_msg.mempool);
+
+ if (mfa == I2O_QUEUE_EMPTY)
+ return ERR_PTR(-EBUSY);
+ return ERR_PTR(-EFAULT);
+ }
+
+ return &mmsg->msg;
+};
+
+/**
+ * i2o_msg_post - Post I2O message to I2O controller
+ * @c: I2O controller to which the message should be send
+ * @msg: message returned by i2o_msg_get()
+ *
+ * Post the message to the I2O controller and return immediately.
+ */
+static inline void i2o_msg_post(struct i2o_controller *c,
+ struct i2o_message *msg)
+{
+ struct i2o_msg_mfa *mmsg;
+
+ mmsg = container_of(msg, struct i2o_msg_mfa, msg);
+ memcpy_toio(i2o_msg_in_to_virt(c, mmsg->mfa), msg,
+ (le32_to_cpu(msg->u.head[0]) >> 16) << 2);
+ writel(mmsg->mfa, c->in_port);
+ mempool_free(mmsg, c->in_msg.mempool);
+};
+
+/**
+ * i2o_msg_post_wait - Post and wait a message and wait until return
+ * @c: controller
+ * @msg: message to post
+ * @timeout: time in seconds to wait
+ *
+ * This API allows an OSM to post a message and then be told whether or
+ * not the system received a successful reply. If the message times out
+ * then the value '-ETIMEDOUT' is returned.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static inline int i2o_msg_post_wait(struct i2o_controller *c,
+ struct i2o_message *msg,
+ unsigned long timeout)
+{
+ return i2o_msg_post_wait_mem(c, msg, timeout, NULL);
+};
+
+/**
+ * i2o_msg_nop_mfa - Returns a fetched MFA back to the controller
+ * @c: I2O controller from which the MFA was fetched
+ * @mfa: MFA which should be returned
+ *
+ * This function must be used for preserved messages, because i2o_msg_nop()
+ * also returns the allocated memory back to the msg_pool mempool.
+ */
+static inline void i2o_msg_nop_mfa(struct i2o_controller *c, u32 mfa)
+{
+ struct i2o_message __iomem *msg;
+ u32 nop[3] = {
+ THREE_WORD_MSG_SIZE | SGL_OFFSET_0,
+ I2O_CMD_UTIL_NOP << 24 | HOST_TID << 12 | ADAPTER_TID,
+ 0x00000000
+ };
+
+ msg = i2o_msg_in_to_virt(c, mfa);
+ memcpy_toio(msg, nop, sizeof(nop));
+ writel(mfa, c->in_port);
+};
+
+/**
+ * i2o_msg_nop - Returns a message which is not used
+ * @c: I2O controller from which the message was created
+ * @msg: message which should be returned
+ *
+ * If you fetch a message via i2o_msg_get, and can't use it, you must
+ * return the message with this function. Otherwise the MFA is lost as well
+ * as the allocated memory from the mempool.
+ */
+static inline void i2o_msg_nop(struct i2o_controller *c,
+ struct i2o_message *msg)
+{
+ struct i2o_msg_mfa *mmsg;
+ mmsg = container_of(msg, struct i2o_msg_mfa, msg);
+
+ i2o_msg_nop_mfa(c, mmsg->mfa);
+ mempool_free(mmsg, c->in_msg.mempool);
+};
+
+/**
+ * i2o_flush_reply - Flush reply from I2O controller
+ * @c: I2O controller
+ * @m: the message identifier
+ *
+ * The I2O controller must be informed that the reply message is not needed
+ * anymore. If you forget to flush the reply, the message frame can't be
+ * used by the controller anymore and is therefore lost.
+ */
+static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
+{
+ writel(m, c->out_port);
+};
+
+/*
+ * Endian handling wrapped into the macro - keeps the core code
+ * cleaner.
+ */
+
+#define i2o_raw_writel(val, mem) __raw_writel(cpu_to_le32(val), mem)
+
+extern int i2o_parm_field_get(struct i2o_device *, int, int, void *, int);
+extern int i2o_parm_table_get(struct i2o_device *, int, int, int, void *, int,
+ void *, int);
+
+/* debugging and troubleshooting/diagnostic helpers. */
+#define osm_printk(level, format, arg...) \
+ printk(level "%s: " format, OSM_NAME , ## arg)
+
+#ifdef DEBUG
+#define osm_debug(format, arg...) \
+ osm_printk(KERN_DEBUG, format , ## arg)
+#else
+#define osm_debug(format, arg...) \
+ do { } while (0)
+#endif
+
+#define osm_err(format, arg...) \
+ osm_printk(KERN_ERR, format , ## arg)
+#define osm_info(format, arg...) \
+ osm_printk(KERN_INFO, format , ## arg)
+#define osm_warn(format, arg...) \
+ osm_printk(KERN_WARNING, format , ## arg)
+
+/* debugging functions */
+extern void i2o_report_status(const char *, const char *, struct i2o_message *);
+extern void i2o_dump_message(struct i2o_message *);
+extern void i2o_dump_hrt(struct i2o_controller *c);
+extern void i2o_debug_state(struct i2o_controller *c);
+
+#endif /* _I2O_H */
diff --git a/drivers/staging/i2o/i2o_block.c b/drivers/staging/i2o/i2o_block.c
new file mode 100644
index 000000000000..0a13c64ce000
--- /dev/null
+++ b/drivers/staging/i2o/i2o_block.c
@@ -0,0 +1,1228 @@
+/*
+ * Block OSM
+ *
+ * Copyright (C) 1999-2002 Red Hat Software
+ *
+ * Written by Alan Cox, Building Number Three 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.
+ *
+ * For the purpose of avoiding doubt the preferred form of the work
+ * for making modifications shall be a standards compliant form such
+ * gzipped tar and not one requiring a proprietary or patent encumbered
+ * tool to unpack.
+ *
+ * Fixes/additions:
+ * Steve Ralston:
+ * Multiple device handling error fixes,
+ * Added a queue depth.
+ * Alan Cox:
+ * FC920 has an rmw bug. Dont or in the end marker.
+ * Removed queue walk, fixed for 64bitness.
+ * Rewrote much of the code over time
+ * Added indirect block lists
+ * Handle 64K limits on many controllers
+ * Don't use indirects on the Promise (breaks)
+ * Heavily chop down the queue depths
+ * Deepak Saxena:
+ * Independent queues per IOP
+ * Support for dynamic device creation/deletion
+ * Code cleanup
+ * Support for larger I/Os through merge* functions
+ * (taken from DAC960 driver)
+ * Boji T Kannanthanam:
+ * Set the I2O Block devices to be detected in increasing
+ * order of TIDs during boot.
+ * Search and set the I2O block device that we boot off
+ * from as the first device to be claimed (as /dev/i2o/hda)
+ * Properly attach/detach I2O gendisk structure from the
+ * system gendisk list. The I2O block devices now appear in
+ * /proc/partitions.
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Minor bugfixes for 2.6.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include "i2o.h"
+#include <linux/mutex.h>
+
+#include <linux/mempool.h>
+
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/hdreg.h>
+
+#include <scsi/scsi.h>
+
+#include "i2o_block.h"
+
+#define OSM_NAME "block-osm"
+#define OSM_VERSION "1.325"
+#define OSM_DESCRIPTION "I2O Block Device OSM"
+
+static DEFINE_MUTEX(i2o_block_mutex);
+static struct i2o_driver i2o_block_driver;
+
+/* global Block OSM request mempool */
+static struct i2o_block_mempool i2o_blk_req_pool;
+
+/* Block OSM class handling definition */
+static struct i2o_class_id i2o_block_class_id[] = {
+ {I2O_CLASS_RANDOM_BLOCK_STORAGE},
+ {I2O_CLASS_END}
+};
+
+/**
+ * i2o_block_device_free - free the memory of the I2O Block device
+ * @dev: I2O Block device, which should be cleaned up
+ *
+ * Frees the request queue, gendisk and the i2o_block_device structure.
+ */
+static void i2o_block_device_free(struct i2o_block_device *dev)
+{
+ blk_cleanup_queue(dev->gd->queue);
+
+ put_disk(dev->gd);
+
+ kfree(dev);
+};
+
+/**
+ * i2o_block_remove - remove the I2O Block device from the system again
+ * @dev: I2O Block device which should be removed
+ *
+ * Remove gendisk from system and free all allocated memory.
+ *
+ * Always returns 0.
+ */
+static int i2o_block_remove(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+ struct i2o_block_device *i2o_blk_dev = dev_get_drvdata(dev);
+
+ osm_info("device removed (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+ i2o_blk_dev->gd->disk_name);
+
+ i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0);
+
+ del_gendisk(i2o_blk_dev->gd);
+
+ dev_set_drvdata(dev, NULL);
+
+ i2o_device_claim_release(i2o_dev);
+
+ i2o_block_device_free(i2o_blk_dev);
+
+ return 0;
+};
+
+/**
+ * i2o_block_device flush - Flush all dirty data of I2O device dev
+ * @dev: I2O device which should be flushed
+ *
+ * Flushes all dirty data on device dev.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_flush(struct i2o_device *dev)
+{
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_BLOCK_CFLUSH << 24 | HOST_TID << 12 | dev->
+ lct_data.tid);
+ msg->body[0] = cpu_to_le32(60 << 16);
+ osm_debug("Flushing...\n");
+
+ return i2o_msg_post_wait(dev->iop, msg, 60);
+};
+
+/**
+ * i2o_block_device_mount - Mount (load) the media of device dev
+ * @dev: I2O device which should receive the mount request
+ * @media_id: Media Identifier
+ *
+ * Load a media into drive. Identifier should be set to -1, because the
+ * spec does not support any other value.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_mount(struct i2o_device *dev, u32 media_id)
+{
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_BLOCK_MMOUNT << 24 | HOST_TID << 12 | dev->
+ lct_data.tid);
+ msg->body[0] = cpu_to_le32(-1);
+ msg->body[1] = cpu_to_le32(0x00000000);
+ osm_debug("Mounting...\n");
+
+ return i2o_msg_post_wait(dev->iop, msg, 2);
+};
+
+/**
+ * i2o_block_device_lock - Locks the media of device dev
+ * @dev: I2O device which should receive the lock request
+ * @media_id: Media Identifier
+ *
+ * Lock media of device dev to prevent removal. The media identifier
+ * should be set to -1, because the spec does not support any other value.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_lock(struct i2o_device *dev, u32 media_id)
+{
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_BLOCK_MLOCK << 24 | HOST_TID << 12 | dev->
+ lct_data.tid);
+ msg->body[0] = cpu_to_le32(-1);
+ osm_debug("Locking...\n");
+
+ return i2o_msg_post_wait(dev->iop, msg, 2);
+};
+
+/**
+ * i2o_block_device_unlock - Unlocks the media of device dev
+ * @dev: I2O device which should receive the unlocked request
+ * @media_id: Media Identifier
+ *
+ * Unlocks the media in device dev. The media identifier should be set to
+ * -1, because the spec does not support any other value.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_unlock(struct i2o_device *dev, u32 media_id)
+{
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(dev->iop, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_BLOCK_MUNLOCK << 24 | HOST_TID << 12 | dev->
+ lct_data.tid);
+ msg->body[0] = cpu_to_le32(media_id);
+ osm_debug("Unlocking...\n");
+
+ return i2o_msg_post_wait(dev->iop, msg, 2);
+};
+
+/**
+ * i2o_block_device_power - Power management for device dev
+ * @dev: I2O device which should receive the power management request
+ * @op: Operation to send
+ *
+ * Send a power management request to the device dev.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_device_power(struct i2o_block_device *dev, u8 op)
+{
+ struct i2o_device *i2o_dev = dev->i2o_dev;
+ struct i2o_controller *c = i2o_dev->iop;
+ struct i2o_message *msg;
+ int rc;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_BLOCK_POWER << 24 | HOST_TID << 12 | i2o_dev->
+ lct_data.tid);
+ msg->body[0] = cpu_to_le32(op << 24);
+ osm_debug("Power...\n");
+
+ rc = i2o_msg_post_wait(c, msg, 60);
+ if (!rc)
+ dev->power = op;
+
+ return rc;
+};
+
+/**
+ * i2o_block_request_alloc - Allocate an I2O block request struct
+ *
+ * Allocates an I2O block request struct and initialize the list.
+ *
+ * Returns a i2o_block_request pointer on success or negative error code
+ * on failure.
+ */
+static inline struct i2o_block_request *i2o_block_request_alloc(void)
+{
+ struct i2o_block_request *ireq;
+
+ ireq = mempool_alloc(i2o_blk_req_pool.pool, GFP_ATOMIC);
+ if (!ireq)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&ireq->queue);
+ sg_init_table(ireq->sg_table, I2O_MAX_PHYS_SEGMENTS);
+
+ return ireq;
+};
+
+/**
+ * i2o_block_request_free - Frees a I2O block request
+ * @ireq: I2O block request which should be freed
+ *
+ * Frees the allocated memory (give it back to the request mempool).
+ */
+static inline void i2o_block_request_free(struct i2o_block_request *ireq)
+{
+ mempool_free(ireq, i2o_blk_req_pool.pool);
+};
+
+/**
+ * i2o_block_sglist_alloc - Allocate the SG list and map it
+ * @c: I2O controller to which the request belongs
+ * @ireq: I2O block request
+ * @mptr: message body pointer
+ *
+ * Builds the SG list and map it to be accessible by the controller.
+ *
+ * Returns 0 on failure or 1 on success.
+ */
+static inline int i2o_block_sglist_alloc(struct i2o_controller *c,
+ struct i2o_block_request *ireq,
+ u32 ** mptr)
+{
+ int nents;
+ enum dma_data_direction direction;
+
+ ireq->dev = &c->pdev->dev;
+ nents = blk_rq_map_sg(ireq->req->q, ireq->req, ireq->sg_table);
+
+ if (rq_data_dir(ireq->req) == READ)
+ direction = PCI_DMA_FROMDEVICE;
+ else
+ direction = PCI_DMA_TODEVICE;
+
+ ireq->sg_nents = nents;
+
+ return i2o_dma_map_sg(c, ireq->sg_table, nents, direction, mptr);
+};
+
+/**
+ * i2o_block_sglist_free - Frees the SG list
+ * @ireq: I2O block request from which the SG should be freed
+ *
+ * Frees the SG list from the I2O block request.
+ */
+static inline void i2o_block_sglist_free(struct i2o_block_request *ireq)
+{
+ enum dma_data_direction direction;
+
+ if (rq_data_dir(ireq->req) == READ)
+ direction = PCI_DMA_FROMDEVICE;
+ else
+ direction = PCI_DMA_TODEVICE;
+
+ dma_unmap_sg(ireq->dev, ireq->sg_table, ireq->sg_nents, direction);
+};
+
+/**
+ * i2o_block_prep_req_fn - Allocates I2O block device specific struct
+ * @q: request queue for the request
+ * @req: the request to prepare
+ *
+ * Allocate the necessary i2o_block_request struct and connect it to
+ * the request. This is needed that we not lose the SG list later on.
+ *
+ * Returns BLKPREP_OK on success or BLKPREP_DEFER on failure.
+ */
+static int i2o_block_prep_req_fn(struct request_queue *q, struct request *req)
+{
+ struct i2o_block_device *i2o_blk_dev = q->queuedata;
+ struct i2o_block_request *ireq;
+
+ if (unlikely(!i2o_blk_dev)) {
+ osm_err("block device already removed\n");
+ return BLKPREP_KILL;
+ }
+
+ /* connect the i2o_block_request to the request */
+ if (!req->special) {
+ ireq = i2o_block_request_alloc();
+ if (IS_ERR(ireq)) {
+ osm_debug("unable to allocate i2o_block_request!\n");
+ return BLKPREP_DEFER;
+ }
+
+ ireq->i2o_blk_dev = i2o_blk_dev;
+ req->special = ireq;
+ ireq->req = req;
+ }
+ /* do not come back here */
+ req->cmd_flags |= REQ_DONTPREP;
+
+ return BLKPREP_OK;
+};
+
+/**
+ * i2o_block_delayed_request_fn - delayed request queue function
+ * @work: the delayed request with the queue to start
+ *
+ * If the request queue is stopped for a disk, and there is no open
+ * request, a new event is created, which calls this function to start
+ * the queue after I2O_BLOCK_REQUEST_TIME. Otherwise the queue will never
+ * be started again.
+ */
+static void i2o_block_delayed_request_fn(struct work_struct *work)
+{
+ struct i2o_block_delayed_request *dreq =
+ container_of(work, struct i2o_block_delayed_request,
+ work.work);
+ struct request_queue *q = dreq->queue;
+ unsigned long flags;
+
+ spin_lock_irqsave(q->queue_lock, flags);
+ blk_start_queue(q);
+ spin_unlock_irqrestore(q->queue_lock, flags);
+ kfree(dreq);
+};
+
+/**
+ * i2o_block_end_request - Post-processing of completed commands
+ * @req: request which should be completed
+ * @error: 0 for success, < 0 for error
+ * @nr_bytes: number of bytes to complete
+ *
+ * Mark the request as complete. The lock must not be held when entering.
+ *
+ */
+static void i2o_block_end_request(struct request *req, int error,
+ int nr_bytes)
+{
+ struct i2o_block_request *ireq = req->special;
+ struct i2o_block_device *dev = ireq->i2o_blk_dev;
+ struct request_queue *q = req->q;
+ unsigned long flags;
+
+ if (blk_end_request(req, error, nr_bytes))
+ if (error)
+ blk_end_request_all(req, -EIO);
+
+ spin_lock_irqsave(q->queue_lock, flags);
+
+ if (likely(dev)) {
+ dev->open_queue_depth--;
+ list_del(&ireq->queue);
+ }
+
+ blk_start_queue(q);
+
+ spin_unlock_irqrestore(q->queue_lock, flags);
+
+ i2o_block_sglist_free(ireq);
+ i2o_block_request_free(ireq);
+};
+
+/**
+ * i2o_block_reply - Block OSM reply handler.
+ * @c: I2O controller from which the message arrives
+ * @m: message id of reply
+ * @msg: the actual I2O message reply
+ *
+ * This function gets all the message replies.
+ *
+ */
+static int i2o_block_reply(struct i2o_controller *c, u32 m,
+ struct i2o_message *msg)
+{
+ struct request *req;
+ int error = 0;
+
+ req = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
+ if (unlikely(!req)) {
+ osm_err("NULL reply received!\n");
+ return -1;
+ }
+
+ /*
+ * Lets see what is cooking. We stuffed the
+ * request in the context.
+ */
+
+ if ((le32_to_cpu(msg->body[0]) >> 24) != 0) {
+ u32 status = le32_to_cpu(msg->body[0]);
+ /*
+ * Device not ready means two things. One is that the
+ * the thing went offline (but not a removal media)
+ *
+ * The second is that you have a SuperTrak 100 and the
+ * firmware got constipated. Unlike standard i2o card
+ * setups the supertrak returns an error rather than
+ * blocking for the timeout in these cases.
+ *
+ * Don't stick a supertrak100 into cache aggressive modes
+ */
+
+ osm_err("TID %03x error status: 0x%02x, detailed status: "
+ "0x%04x\n", (le32_to_cpu(msg->u.head[1]) >> 12 & 0xfff),
+ status >> 24, status & 0xffff);
+
+ req->errors++;
+
+ error = -EIO;
+ }
+
+ i2o_block_end_request(req, error, le32_to_cpu(msg->body[1]));
+
+ return 1;
+};
+
+static void i2o_block_event(struct work_struct *work)
+{
+ struct i2o_event *evt = container_of(work, struct i2o_event, work);
+ osm_debug("event received\n");
+ kfree(evt);
+};
+
+/*
+ * SCSI-CAM for ioctl geometry mapping
+ * Duplicated with SCSI - this should be moved into somewhere common
+ * perhaps genhd ?
+ *
+ * LBA -> CHS mapping table taken from:
+ *
+ * "Incorporating the I2O Architecture into BIOS for Intel Architecture
+ * Platforms"
+ *
+ * This is an I2O document that is only available to I2O members,
+ * not developers.
+ *
+ * From my understanding, this is how all the I2O cards do this
+ *
+ * Disk Size | Sectors | Heads | Cylinders
+ * ---------------+---------+-------+-------------------
+ * 1 < X <= 528M | 63 | 16 | X/(63 * 16 * 512)
+ * 528M < X <= 1G | 63 | 32 | X/(63 * 32 * 512)
+ * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512)
+ * 1 < X <528M | 63 | 16 | X/(63 * 16 * 512)
+ *
+ */
+#define BLOCK_SIZE_528M 1081344
+#define BLOCK_SIZE_1G 2097152
+#define BLOCK_SIZE_21G 4403200
+#define BLOCK_SIZE_42G 8806400
+#define BLOCK_SIZE_84G 17612800
+
+static void i2o_block_biosparam(unsigned long capacity, unsigned short *cyls,
+ unsigned char *hds, unsigned char *secs)
+{
+ unsigned long heads, sectors, cylinders;
+
+ sectors = 63L; /* Maximize sectors per track */
+ if (capacity <= BLOCK_SIZE_528M)
+ heads = 16;
+ else if (capacity <= BLOCK_SIZE_1G)
+ heads = 32;
+ else if (capacity <= BLOCK_SIZE_21G)
+ heads = 64;
+ else if (capacity <= BLOCK_SIZE_42G)
+ heads = 128;
+ else
+ heads = 255;
+
+ cylinders = (unsigned long)capacity / (heads * sectors);
+
+ *cyls = (unsigned short)cylinders; /* Stuff return values */
+ *secs = (unsigned char)sectors;
+ *hds = (unsigned char)heads;
+}
+
+/**
+ * i2o_block_open - Open the block device
+ * @bdev: block device being opened
+ * @mode: file open mode
+ *
+ * Power up the device, mount and lock the media. This function is called,
+ * if the block device is opened for access.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_open(struct block_device *bdev, fmode_t mode)
+{
+ struct i2o_block_device *dev = bdev->bd_disk->private_data;
+
+ if (!dev->i2o_dev)
+ return -ENODEV;
+
+ mutex_lock(&i2o_block_mutex);
+ if (dev->power > 0x1f)
+ i2o_block_device_power(dev, 0x02);
+
+ i2o_block_device_mount(dev->i2o_dev, -1);
+
+ i2o_block_device_lock(dev->i2o_dev, -1);
+
+ osm_debug("Ready.\n");
+ mutex_unlock(&i2o_block_mutex);
+
+ return 0;
+};
+
+/**
+ * i2o_block_release - Release the I2O block device
+ * @disk: gendisk device being released
+ * @mode: file open mode
+ *
+ * Unlock and unmount the media, and power down the device. Gets called if
+ * the block device is closed.
+ */
+static void i2o_block_release(struct gendisk *disk, fmode_t mode)
+{
+ struct i2o_block_device *dev = disk->private_data;
+ u8 operation;
+
+ /*
+ * This is to deal with the case of an application
+ * opening a device and then the device disappears while
+ * it's in use, and then the application tries to release
+ * it. ex: Unmounting a deleted RAID volume at reboot.
+ * If we send messages, it will just cause FAILs since
+ * the TID no longer exists.
+ */
+ if (!dev->i2o_dev)
+ return;
+
+ mutex_lock(&i2o_block_mutex);
+ i2o_block_device_flush(dev->i2o_dev);
+
+ i2o_block_device_unlock(dev->i2o_dev, -1);
+
+ if (dev->flags & (1 << 3 | 1 << 4)) /* Removable */
+ operation = 0x21;
+ else
+ operation = 0x24;
+
+ i2o_block_device_power(dev, operation);
+ mutex_unlock(&i2o_block_mutex);
+}
+
+static int i2o_block_getgeo(struct block_device *bdev, struct hd_geometry *geo)
+{
+ i2o_block_biosparam(get_capacity(bdev->bd_disk),
+ &geo->cylinders, &geo->heads, &geo->sectors);
+ return 0;
+}
+
+/**
+ * i2o_block_ioctl - Issue device specific ioctl calls.
+ * @bdev: block device being opened
+ * @mode: file open mode
+ * @cmd: ioctl command
+ * @arg: arg
+ *
+ * Handles ioctl request for the block device.
+ *
+ * Return 0 on success or negative error on failure.
+ */
+static int i2o_block_ioctl(struct block_device *bdev, fmode_t mode,
+ unsigned int cmd, unsigned long arg)
+{
+ struct gendisk *disk = bdev->bd_disk;
+ struct i2o_block_device *dev = disk->private_data;
+ int ret = -ENOTTY;
+
+ /* Anyone capable of this syscall can do *real bad* things */
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ mutex_lock(&i2o_block_mutex);
+ switch (cmd) {
+ case BLKI2OGRSTRAT:
+ ret = put_user(dev->rcache, (int __user *)arg);
+ break;
+ case BLKI2OGWSTRAT:
+ ret = put_user(dev->wcache, (int __user *)arg);
+ break;
+ case BLKI2OSRSTRAT:
+ ret = -EINVAL;
+ if (arg < 0 || arg > CACHE_SMARTFETCH)
+ break;
+ dev->rcache = arg;
+ ret = 0;
+ break;
+ case BLKI2OSWSTRAT:
+ ret = -EINVAL;
+ if (arg != 0
+ && (arg < CACHE_WRITETHROUGH || arg > CACHE_SMARTBACK))
+ break;
+ dev->wcache = arg;
+ ret = 0;
+ break;
+ }
+ mutex_unlock(&i2o_block_mutex);
+
+ return ret;
+};
+
+/**
+ * i2o_block_check_events - Have we seen a media change?
+ * @disk: gendisk which should be verified
+ * @clearing: events being cleared
+ *
+ * Verifies if the media has changed.
+ *
+ * Returns 1 if the media was changed or 0 otherwise.
+ */
+static unsigned int i2o_block_check_events(struct gendisk *disk,
+ unsigned int clearing)
+{
+ struct i2o_block_device *p = disk->private_data;
+
+ if (p->media_change_flag) {
+ p->media_change_flag = 0;
+ return DISK_EVENT_MEDIA_CHANGE;
+ }
+ return 0;
+}
+
+/**
+ * i2o_block_transfer - Transfer a request to/from the I2O controller
+ * @req: the request which should be transferred
+ *
+ * This function converts the request into a I2O message. The necessary
+ * DMA buffers are allocated and after everything is setup post the message
+ * to the I2O controller. No cleanup is done by this function. It is done
+ * on the interrupt side when the reply arrives.
+ *
+ * Return 0 on success or negative error code on failure.
+ */
+static int i2o_block_transfer(struct request *req)
+{
+ struct i2o_block_device *dev = req->rq_disk->private_data;
+ struct i2o_controller *c;
+ u32 tid;
+ struct i2o_message *msg;
+ u32 *mptr;
+ struct i2o_block_request *ireq = req->special;
+ u32 tcntxt;
+ u32 sgl_offset = SGL_OFFSET_8;
+ u32 ctl_flags = 0x00000000;
+ int rc;
+ u32 cmd;
+
+ if (unlikely(!dev->i2o_dev)) {
+ osm_err("transfer to removed drive\n");
+ rc = -ENODEV;
+ goto exit;
+ }
+
+ tid = dev->i2o_dev->lct_data.tid;
+ c = dev->i2o_dev->iop;
+
+ msg = i2o_msg_get(c);
+ if (IS_ERR(msg)) {
+ rc = PTR_ERR(msg);
+ goto exit;
+ }
+
+ tcntxt = i2o_cntxt_list_add(c, req);
+ if (!tcntxt) {
+ rc = -ENOMEM;
+ goto nop_msg;
+ }
+
+ msg->u.s.icntxt = cpu_to_le32(i2o_block_driver.context);
+ msg->u.s.tcntxt = cpu_to_le32(tcntxt);
+
+ mptr = &msg->body[0];
+
+ if (rq_data_dir(req) == READ) {
+ cmd = I2O_CMD_BLOCK_READ << 24;
+
+ switch (dev->rcache) {
+ case CACHE_PREFETCH:
+ ctl_flags = 0x201F0008;
+ break;
+
+ case CACHE_SMARTFETCH:
+ if (blk_rq_sectors(req) > 16)
+ ctl_flags = 0x201F0008;
+ else
+ ctl_flags = 0x001F0000;
+ break;
+
+ default:
+ break;
+ }
+ } else {
+ cmd = I2O_CMD_BLOCK_WRITE << 24;
+
+ switch (dev->wcache) {
+ case CACHE_WRITETHROUGH:
+ ctl_flags = 0x001F0008;
+ break;
+ case CACHE_WRITEBACK:
+ ctl_flags = 0x001F0010;
+ break;
+ case CACHE_SMARTBACK:
+ if (blk_rq_sectors(req) > 16)
+ ctl_flags = 0x001F0004;
+ else
+ ctl_flags = 0x001F0010;
+ break;
+ case CACHE_SMARTTHROUGH:
+ if (blk_rq_sectors(req) > 16)
+ ctl_flags = 0x001F0004;
+ else
+ ctl_flags = 0x001F0010;
+ default:
+ break;
+ }
+ }
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u8 cmd[10];
+ u32 scsi_flags;
+ u16 hwsec;
+
+ hwsec = queue_logical_block_size(req->q) >> KERNEL_SECTOR_SHIFT;
+ memset(cmd, 0, 10);
+
+ sgl_offset = SGL_OFFSET_12;
+
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_PRIVATE << 24 | HOST_TID << 12 | tid);
+
+ *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
+ *mptr++ = cpu_to_le32(tid);
+
+ /*
+ * ENABLE_DISCONNECT
+ * SIMPLE_TAG
+ * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+ */
+ if (rq_data_dir(req) == READ) {
+ cmd[0] = READ_10;
+ scsi_flags = 0x60a0000a;
+ } else {
+ cmd[0] = WRITE_10;
+ scsi_flags = 0xa0a0000a;
+ }
+
+ *mptr++ = cpu_to_le32(scsi_flags);
+
+ *((u32 *) & cmd[2]) = cpu_to_be32(blk_rq_pos(req) * hwsec);
+ *((u16 *) & cmd[7]) = cpu_to_be16(blk_rq_sectors(req) * hwsec);
+
+ memcpy(mptr, cmd, 10);
+ mptr += 4;
+ *mptr++ = cpu_to_le32(blk_rq_bytes(req));
+ } else
+#endif
+ {
+ msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
+ *mptr++ = cpu_to_le32(ctl_flags);
+ *mptr++ = cpu_to_le32(blk_rq_bytes(req));
+ *mptr++ =
+ cpu_to_le32((u32) (blk_rq_pos(req) << KERNEL_SECTOR_SHIFT));
+ *mptr++ =
+ cpu_to_le32(blk_rq_pos(req) >> (32 - KERNEL_SECTOR_SHIFT));
+ }
+
+ if (!i2o_block_sglist_alloc(c, ireq, &mptr)) {
+ rc = -ENOMEM;
+ goto context_remove;
+ }
+
+ msg->u.head[0] =
+ cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
+
+ list_add_tail(&ireq->queue, &dev->open_queue);
+ dev->open_queue_depth++;
+
+ i2o_msg_post(c, msg);
+
+ return 0;
+
+ context_remove:
+ i2o_cntxt_list_remove(c, req);
+
+ nop_msg:
+ i2o_msg_nop(c, msg);
+
+ exit:
+ return rc;
+};
+
+/**
+ * i2o_block_request_fn - request queue handling function
+ * @q: request queue from which the request could be fetched
+ *
+ * Takes the next request from the queue, transfers it and if no error
+ * occurs dequeue it from the queue. On arrival of the reply the message
+ * will be processed further. If an error occurs requeue the request.
+ */
+static void i2o_block_request_fn(struct request_queue *q)
+{
+ struct request *req;
+
+ while ((req = blk_peek_request(q)) != NULL) {
+ if (req->cmd_type == REQ_TYPE_FS) {
+ struct i2o_block_delayed_request *dreq;
+ struct i2o_block_request *ireq = req->special;
+ unsigned int queue_depth;
+
+ queue_depth = ireq->i2o_blk_dev->open_queue_depth;
+
+ if (queue_depth < I2O_BLOCK_MAX_OPEN_REQUESTS) {
+ if (!i2o_block_transfer(req)) {
+ blk_start_request(req);
+ continue;
+ } else
+ osm_info("transfer error\n");
+ }
+
+ if (queue_depth)
+ break;
+
+ /* stop the queue and retry later */
+ dreq = kmalloc(sizeof(*dreq), GFP_ATOMIC);
+ if (!dreq)
+ continue;
+
+ dreq->queue = q;
+ INIT_DELAYED_WORK(&dreq->work,
+ i2o_block_delayed_request_fn);
+
+ if (!queue_delayed_work(i2o_block_driver.event_queue,
+ &dreq->work,
+ I2O_BLOCK_RETRY_TIME))
+ kfree(dreq);
+ else {
+ blk_stop_queue(q);
+ break;
+ }
+ } else {
+ blk_start_request(req);
+ __blk_end_request_all(req, -EIO);
+ }
+ }
+};
+
+/* I2O Block device operations definition */
+static const struct block_device_operations i2o_block_fops = {
+ .owner = THIS_MODULE,
+ .open = i2o_block_open,
+ .release = i2o_block_release,
+ .ioctl = i2o_block_ioctl,
+ .compat_ioctl = i2o_block_ioctl,
+ .getgeo = i2o_block_getgeo,
+ .check_events = i2o_block_check_events,
+};
+
+/**
+ * i2o_block_device_alloc - Allocate memory for a I2O Block device
+ *
+ * Allocate memory for the i2o_block_device struct, gendisk and request
+ * queue and initialize them as far as no additional information is needed.
+ *
+ * Returns a pointer to the allocated I2O Block device on success or a
+ * negative error code on failure.
+ */
+static struct i2o_block_device *i2o_block_device_alloc(void)
+{
+ struct i2o_block_device *dev;
+ struct gendisk *gd;
+ struct request_queue *queue;
+ int rc;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ osm_err("Insufficient memory to allocate I2O Block disk.\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ INIT_LIST_HEAD(&dev->open_queue);
+ spin_lock_init(&dev->lock);
+ dev->rcache = CACHE_PREFETCH;
+ dev->wcache = CACHE_WRITEBACK;
+
+ /* allocate a gendisk with 16 partitions */
+ gd = alloc_disk(16);
+ if (!gd) {
+ osm_err("Insufficient memory to allocate gendisk.\n");
+ rc = -ENOMEM;
+ goto cleanup_dev;
+ }
+
+ /* initialize the request queue */
+ queue = blk_init_queue(i2o_block_request_fn, &dev->lock);
+ if (!queue) {
+ osm_err("Insufficient memory to allocate request queue.\n");
+ rc = -ENOMEM;
+ goto cleanup_queue;
+ }
+
+ blk_queue_prep_rq(queue, i2o_block_prep_req_fn);
+
+ gd->major = I2O_MAJOR;
+ gd->queue = queue;
+ gd->fops = &i2o_block_fops;
+ gd->private_data = dev;
+
+ dev->gd = gd;
+
+ return dev;
+
+ cleanup_queue:
+ put_disk(gd);
+
+ cleanup_dev:
+ kfree(dev);
+
+ exit:
+ return ERR_PTR(rc);
+};
+
+/**
+ * i2o_block_probe - verify if dev is a I2O Block device and install it
+ * @dev: device to verify if it is a I2O Block device
+ *
+ * We only verify if the user_tid of the device is 0xfff and then install
+ * the device. Otherwise it is used by some other device (e. g. RAID).
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_block_probe(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+ struct i2o_controller *c = i2o_dev->iop;
+ struct i2o_block_device *i2o_blk_dev;
+ struct gendisk *gd;
+ struct request_queue *queue;
+ static int unit = 0;
+ int rc;
+ u64 size;
+ u32 blocksize;
+ u16 body_size = 4;
+ u16 power;
+ unsigned short max_sectors;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec)
+ body_size = 8;
+#endif
+
+ if (c->limit_sectors)
+ max_sectors = I2O_MAX_SECTORS_LIMITED;
+ else
+ max_sectors = I2O_MAX_SECTORS;
+
+ /* skip devices which are used by IOP */
+ if (i2o_dev->lct_data.user_tid != 0xfff) {
+ osm_debug("skipping used device %03x\n", i2o_dev->lct_data.tid);
+ return -ENODEV;
+ }
+
+ if (i2o_device_claim(i2o_dev)) {
+ osm_warn("Unable to claim device. Installation aborted\n");
+ rc = -EFAULT;
+ goto exit;
+ }
+
+ i2o_blk_dev = i2o_block_device_alloc();
+ if (IS_ERR(i2o_blk_dev)) {
+ osm_err("could not alloc a new I2O block device");
+ rc = PTR_ERR(i2o_blk_dev);
+ goto claim_release;
+ }
+
+ i2o_blk_dev->i2o_dev = i2o_dev;
+ dev_set_drvdata(dev, i2o_blk_dev);
+
+ /* setup gendisk */
+ gd = i2o_blk_dev->gd;
+ gd->first_minor = unit << 4;
+ sprintf(gd->disk_name, "i2o/hd%c", 'a' + unit);
+ gd->driverfs_dev = &i2o_dev->device;
+
+ /* setup request queue */
+ queue = gd->queue;
+ queue->queuedata = i2o_blk_dev;
+
+ blk_queue_max_hw_sectors(queue, max_sectors);
+ blk_queue_max_segments(queue, i2o_sg_tablesize(c, body_size));
+
+ osm_debug("max sectors = %d\n", queue->max_sectors);
+ osm_debug("phys segments = %d\n", queue->max_phys_segments);
+ osm_debug("max hw segments = %d\n", queue->max_hw_segments);
+
+ /*
+ * Ask for the current media data. If that isn't supported
+ * then we ask for the device capacity data
+ */
+ if (!i2o_parm_field_get(i2o_dev, 0x0004, 1, &blocksize, 4) ||
+ !i2o_parm_field_get(i2o_dev, 0x0000, 3, &blocksize, 4)) {
+ blk_queue_logical_block_size(queue, le32_to_cpu(blocksize));
+ } else
+ osm_warn("unable to get blocksize of %s\n", gd->disk_name);
+
+ if (!i2o_parm_field_get(i2o_dev, 0x0004, 0, &size, 8) ||
+ !i2o_parm_field_get(i2o_dev, 0x0000, 4, &size, 8)) {
+ set_capacity(gd, le64_to_cpu(size) >> KERNEL_SECTOR_SHIFT);
+ } else
+ osm_warn("could not get size of %s\n", gd->disk_name);
+
+ if (!i2o_parm_field_get(i2o_dev, 0x0000, 2, &power, 2))
+ i2o_blk_dev->power = power;
+
+ i2o_event_register(i2o_dev, &i2o_block_driver, 0, 0xffffffff);
+
+ add_disk(gd);
+
+ unit++;
+
+ osm_info("device added (TID: %03x): %s\n", i2o_dev->lct_data.tid,
+ i2o_blk_dev->gd->disk_name);
+
+ return 0;
+
+ claim_release:
+ i2o_device_claim_release(i2o_dev);
+
+ exit:
+ return rc;
+};
+
+/* Block OSM driver struct */
+static struct i2o_driver i2o_block_driver = {
+ .name = OSM_NAME,
+ .event = i2o_block_event,
+ .reply = i2o_block_reply,
+ .classes = i2o_block_class_id,
+ .driver = {
+ .probe = i2o_block_probe,
+ .remove = i2o_block_remove,
+ },
+};
+
+/**
+ * i2o_block_init - Block OSM initialization function
+ *
+ * Allocate the slab and mempool for request structs, registers i2o_block
+ * block device and finally register the Block OSM in the I2O core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_block_init(void)
+{
+ int rc;
+ int size;
+
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ /* Allocate request mempool and slab */
+ size = sizeof(struct i2o_block_request);
+ i2o_blk_req_pool.slab = kmem_cache_create("i2o_block_req", size, 0,
+ SLAB_HWCACHE_ALIGN, NULL);
+ if (!i2o_blk_req_pool.slab) {
+ osm_err("can't init request slab\n");
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ i2o_blk_req_pool.pool =
+ mempool_create_slab_pool(I2O_BLOCK_REQ_MEMPOOL_SIZE,
+ i2o_blk_req_pool.slab);
+ if (!i2o_blk_req_pool.pool) {
+ osm_err("can't init request mempool\n");
+ rc = -ENOMEM;
+ goto free_slab;
+ }
+
+ /* Register the block device interfaces */
+ rc = register_blkdev(I2O_MAJOR, "i2o_block");
+ if (rc) {
+ osm_err("unable to register block device\n");
+ goto free_mempool;
+ }
+#ifdef MODULE
+ osm_info("registered device at major %d\n", I2O_MAJOR);
+#endif
+
+ /* Register Block OSM into I2O core */
+ rc = i2o_driver_register(&i2o_block_driver);
+ if (rc) {
+ osm_err("Could not register Block driver\n");
+ goto unregister_blkdev;
+ }
+
+ return 0;
+
+ unregister_blkdev:
+ unregister_blkdev(I2O_MAJOR, "i2o_block");
+
+ free_mempool:
+ mempool_destroy(i2o_blk_req_pool.pool);
+
+ free_slab:
+ kmem_cache_destroy(i2o_blk_req_pool.slab);
+
+ exit:
+ return rc;
+};
+
+/**
+ * i2o_block_exit - Block OSM exit function
+ *
+ * Unregisters Block OSM from I2O core, unregisters i2o_block block device
+ * and frees the mempool and slab.
+ */
+static void __exit i2o_block_exit(void)
+{
+ /* Unregister I2O Block OSM from I2O core */
+ i2o_driver_unregister(&i2o_block_driver);
+
+ /* Unregister block device */
+ unregister_blkdev(I2O_MAJOR, "i2o_block");
+
+ /* Free request mempool and slab */
+ mempool_destroy(i2o_blk_req_pool.pool);
+ kmem_cache_destroy(i2o_blk_req_pool.slab);
+};
+
+MODULE_AUTHOR("Red Hat");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_block_init);
+module_exit(i2o_block_exit);
diff --git a/drivers/message/i2o/i2o_block.h b/drivers/staging/i2o/i2o_block.h
index cf8873cbca3f..cf8873cbca3f 100644
--- a/drivers/message/i2o/i2o_block.h
+++ b/drivers/staging/i2o/i2o_block.h
diff --git a/drivers/message/i2o/i2o_config.c b/drivers/staging/i2o/i2o_config.c
index 04bd3b6de401..04bd3b6de401 100644
--- a/drivers/message/i2o/i2o_config.c
+++ b/drivers/staging/i2o/i2o_config.c
diff --git a/drivers/staging/i2o/i2o_proc.c b/drivers/staging/i2o/i2o_proc.c
new file mode 100644
index 000000000000..ad84f3304f3c
--- /dev/null
+++ b/drivers/staging/i2o/i2o_proc.c
@@ -0,0 +1,2045 @@
+/*
+ * procfs handler for Linux I2O subsystem
+ *
+ * (c) Copyright 1999 Deepak Saxena
+ *
+ * Originally written by Deepak Saxena(deepak@plexity.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 is an initial test release. The code is based on the design of the
+ * ide procfs system (drivers/block/ide-proc.c). Some code taken from
+ * i2o-core module by Alan Cox.
+ *
+ * DISCLAIMER: This code is still under development/test and may cause
+ * your system to behave unpredictably. Use at your own discretion.
+ *
+ *
+ * Fixes/additions:
+ * Juha Sievänen (Juha.Sievanen@cs.Helsinki.FI),
+ * Auvo Häkkinen (Auvo.Hakkinen@cs.Helsinki.FI)
+ * University of Helsinki, Department of Computer Science
+ * LAN entries
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>
+ * Changes for new I2O API
+ */
+
+#define OSM_NAME "proc-osm"
+#define OSM_VERSION "1.316"
+#define OSM_DESCRIPTION "I2O ProcFS OSM"
+
+#define I2O_MAX_MODULES 4
+// FIXME!
+#define FMT_U64_HEX "0x%08x%08x"
+#define U64_VAL(pu64) *((u32*)(pu64)+1), *((u32*)(pu64))
+
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include "i2o.h"
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+
+#include <asm/io.h>
+#include <asm/uaccess.h>
+#include <asm/byteorder.h>
+
+/* Structure used to define /proc entries */
+typedef struct _i2o_proc_entry_t {
+ char *name; /* entry name */
+ umode_t mode; /* mode */
+ const struct file_operations *fops; /* open function */
+} i2o_proc_entry;
+
+/* global I2O /proc/i2o entry */
+static struct proc_dir_entry *i2o_proc_dir_root;
+
+/* proc OSM driver struct */
+static struct i2o_driver i2o_proc_driver = {
+ .name = OSM_NAME,
+};
+
+static int print_serial_number(struct seq_file *seq, u8 * serialno, int max_len)
+{
+ int i;
+
+ /* 19990419 -sralston
+ * The I2O v1.5 (and v2.0 so far) "official specification"
+ * got serial numbers WRONG!
+ * Apparently, and despite what Section 3.4.4 says and
+ * Figure 3-35 shows (pg 3-39 in the pdf doc),
+ * the convention / consensus seems to be:
+ * + First byte is SNFormat
+ * + Second byte is SNLen (but only if SNFormat==7 (?))
+ * + (v2.0) SCSI+BS may use IEEE Registered (64 or 128 bit) format
+ */
+ switch (serialno[0]) {
+ case I2O_SNFORMAT_BINARY: /* Binary */
+ seq_printf(seq, "0x");
+ for (i = 0; i < serialno[1]; i++) {
+ seq_printf(seq, "%02X", serialno[2 + i]);
+ }
+ break;
+
+ case I2O_SNFORMAT_ASCII: /* ASCII */
+ if (serialno[1] < ' ') { /* printable or SNLen? */
+ /* sanity */
+ max_len =
+ (max_len < serialno[1]) ? max_len : serialno[1];
+ serialno[1 + max_len] = '\0';
+
+ /* just print it */
+ seq_printf(seq, "%s", &serialno[2]);
+ } else {
+ /* print chars for specified length */
+ for (i = 0; i < serialno[1]; i++) {
+ seq_printf(seq, "%c", serialno[2 + i]);
+ }
+ }
+ break;
+
+ case I2O_SNFORMAT_UNICODE: /* UNICODE */
+ seq_printf(seq, "UNICODE Format. Can't Display\n");
+ break;
+
+ case I2O_SNFORMAT_LAN48_MAC: /* LAN-48 MAC Address */
+ seq_printf(seq, "LAN-48 MAC address @ %pM", &serialno[2]);
+ break;
+
+ case I2O_SNFORMAT_WAN: /* WAN MAC Address */
+ /* FIXME: Figure out what a WAN access address looks like?? */
+ seq_printf(seq, "WAN Access Address");
+ break;
+
+/* plus new in v2.0 */
+ case I2O_SNFORMAT_LAN64_MAC: /* LAN-64 MAC Address */
+ /* FIXME: Figure out what a LAN-64 address really looks like?? */
+ seq_printf(seq,
+ "LAN-64 MAC address @ [?:%02X:%02X:?] %pM",
+ serialno[8], serialno[9], &serialno[2]);
+ break;
+
+ case I2O_SNFORMAT_DDM: /* I2O DDM */
+ seq_printf(seq,
+ "DDM: Tid=%03Xh, Rsvd=%04Xh, OrgId=%04Xh",
+ *(u16 *) & serialno[2],
+ *(u16 *) & serialno[4], *(u16 *) & serialno[6]);
+ break;
+
+ case I2O_SNFORMAT_IEEE_REG64: /* IEEE Registered (64-bit) */
+ case I2O_SNFORMAT_IEEE_REG128: /* IEEE Registered (128-bit) */
+ /* FIXME: Figure if this is even close?? */
+ seq_printf(seq,
+ "IEEE NodeName(hi,lo)=(%08Xh:%08Xh), PortName(hi,lo)=(%08Xh:%08Xh)\n",
+ *(u32 *) & serialno[2],
+ *(u32 *) & serialno[6],
+ *(u32 *) & serialno[10], *(u32 *) & serialno[14]);
+ break;
+
+ case I2O_SNFORMAT_UNKNOWN: /* Unknown 0 */
+ case I2O_SNFORMAT_UNKNOWN2: /* Unknown 0xff */
+ default:
+ seq_printf(seq, "Unknown data format (0x%02x)", serialno[0]);
+ break;
+ }
+
+ return 0;
+}
+
+/**
+ * i2o_get_class_name - do i2o class name lookup
+ * @class: class number
+ *
+ * Return a descriptive string for an i2o class.
+ */
+static const char *i2o_get_class_name(int class)
+{
+ int idx = 16;
+ static char *i2o_class_name[] = {
+ "Executive",
+ "Device Driver Module",
+ "Block Device",
+ "Tape Device",
+ "LAN Interface",
+ "WAN Interface",
+ "Fibre Channel Port",
+ "Fibre Channel Device",
+ "SCSI Device",
+ "ATE Port",
+ "ATE Device",
+ "Floppy Controller",
+ "Floppy Device",
+ "Secondary Bus Port",
+ "Peer Transport Agent",
+ "Peer Transport",
+ "Unknown"
+ };
+
+ switch (class & 0xfff) {
+ case I2O_CLASS_EXECUTIVE:
+ idx = 0;
+ break;
+ case I2O_CLASS_DDM:
+ idx = 1;
+ break;
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ idx = 2;
+ break;
+ case I2O_CLASS_SEQUENTIAL_STORAGE:
+ idx = 3;
+ break;
+ case I2O_CLASS_LAN:
+ idx = 4;
+ break;
+ case I2O_CLASS_WAN:
+ idx = 5;
+ break;
+ case I2O_CLASS_FIBRE_CHANNEL_PORT:
+ idx = 6;
+ break;
+ case I2O_CLASS_FIBRE_CHANNEL_PERIPHERAL:
+ idx = 7;
+ break;
+ case I2O_CLASS_SCSI_PERIPHERAL:
+ idx = 8;
+ break;
+ case I2O_CLASS_ATE_PORT:
+ idx = 9;
+ break;
+ case I2O_CLASS_ATE_PERIPHERAL:
+ idx = 10;
+ break;
+ case I2O_CLASS_FLOPPY_CONTROLLER:
+ idx = 11;
+ break;
+ case I2O_CLASS_FLOPPY_DEVICE:
+ idx = 12;
+ break;
+ case I2O_CLASS_BUS_ADAPTER:
+ idx = 13;
+ break;
+ case I2O_CLASS_PEER_TRANSPORT_AGENT:
+ idx = 14;
+ break;
+ case I2O_CLASS_PEER_TRANSPORT:
+ idx = 15;
+ break;
+ }
+
+ return i2o_class_name[idx];
+}
+
+#define SCSI_TABLE_SIZE 13
+static char *scsi_devices[] = {
+ "Direct-Access Read/Write",
+ "Sequential-Access Storage",
+ "Printer",
+ "Processor",
+ "WORM Device",
+ "CD-ROM Device",
+ "Scanner Device",
+ "Optical Memory Device",
+ "Medium Changer Device",
+ "Communications Device",
+ "Graphics Art Pre-Press Device",
+ "Graphics Art Pre-Press Device",
+ "Array Controller Device"
+};
+
+static char *chtostr(char *tmp, u8 *chars, int n)
+{
+ tmp[0] = 0;
+ return strncat(tmp, (char *)chars, n);
+}
+
+static int i2o_report_query_status(struct seq_file *seq, int block_status,
+ char *group)
+{
+ switch (block_status) {
+ case -ETIMEDOUT:
+ return seq_printf(seq, "Timeout reading group %s.\n", group);
+ case -ENOMEM:
+ return seq_printf(seq, "No free memory to read the table.\n");
+ case -I2O_PARAMS_STATUS_INVALID_GROUP_ID:
+ return seq_printf(seq, "Group %s not supported.\n", group);
+ default:
+ return seq_printf(seq,
+ "Error reading group %s. BlockStatus 0x%02X\n",
+ group, -block_status);
+ }
+}
+
+static char *bus_strings[] = {
+ "Local Bus",
+ "ISA",
+ "EISA",
+ "PCI",
+ "PCMCIA",
+ "NUBUS",
+ "CARDBUS"
+};
+
+static int i2o_seq_show_hrt(struct seq_file *seq, void *v)
+{
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ i2o_hrt *hrt = (i2o_hrt *) c->hrt.virt;
+ u32 bus;
+ int i;
+
+ if (hrt->hrt_version) {
+ seq_printf(seq,
+ "HRT table for controller is too new a version.\n");
+ return 0;
+ }
+
+ seq_printf(seq, "HRT has %d entries of %d bytes each.\n",
+ hrt->num_entries, hrt->entry_len << 2);
+
+ for (i = 0; i < hrt->num_entries; i++) {
+ seq_printf(seq, "Entry %d:\n", i);
+ seq_printf(seq, " Adapter ID: %0#10x\n",
+ hrt->hrt_entry[i].adapter_id);
+ seq_printf(seq, " Controlling tid: %0#6x\n",
+ hrt->hrt_entry[i].parent_tid);
+
+ if (hrt->hrt_entry[i].bus_type != 0x80) {
+ bus = hrt->hrt_entry[i].bus_type;
+ seq_printf(seq, " %s Information\n",
+ bus_strings[bus]);
+
+ switch (bus) {
+ case I2O_BUS_LOCAL:
+ seq_printf(seq, " IOBase: %0#6x,",
+ hrt->hrt_entry[i].bus.local_bus.
+ LbBaseIOPort);
+ seq_printf(seq, " MemoryBase: %0#10x\n",
+ hrt->hrt_entry[i].bus.local_bus.
+ LbBaseMemoryAddress);
+ break;
+
+ case I2O_BUS_ISA:
+ seq_printf(seq, " IOBase: %0#6x,",
+ hrt->hrt_entry[i].bus.isa_bus.
+ IsaBaseIOPort);
+ seq_printf(seq, " MemoryBase: %0#10x,",
+ hrt->hrt_entry[i].bus.isa_bus.
+ IsaBaseMemoryAddress);
+ seq_printf(seq, " CSN: %0#4x,",
+ hrt->hrt_entry[i].bus.isa_bus.CSN);
+ break;
+
+ case I2O_BUS_EISA:
+ seq_printf(seq, " IOBase: %0#6x,",
+ hrt->hrt_entry[i].bus.eisa_bus.
+ EisaBaseIOPort);
+ seq_printf(seq, " MemoryBase: %0#10x,",
+ hrt->hrt_entry[i].bus.eisa_bus.
+ EisaBaseMemoryAddress);
+ seq_printf(seq, " Slot: %0#4x,",
+ hrt->hrt_entry[i].bus.eisa_bus.
+ EisaSlotNumber);
+ break;
+
+ case I2O_BUS_PCI:
+ seq_printf(seq, " Bus: %0#4x",
+ hrt->hrt_entry[i].bus.pci_bus.
+ PciBusNumber);
+ seq_printf(seq, " Dev: %0#4x",
+ hrt->hrt_entry[i].bus.pci_bus.
+ PciDeviceNumber);
+ seq_printf(seq, " Func: %0#4x",
+ hrt->hrt_entry[i].bus.pci_bus.
+ PciFunctionNumber);
+ seq_printf(seq, " Vendor: %0#6x",
+ hrt->hrt_entry[i].bus.pci_bus.
+ PciVendorID);
+ seq_printf(seq, " Device: %0#6x\n",
+ hrt->hrt_entry[i].bus.pci_bus.
+ PciDeviceID);
+ break;
+
+ default:
+ seq_printf(seq, " Unsupported Bus Type\n");
+ }
+ } else
+ seq_printf(seq, " Unknown Bus Type\n");
+ }
+
+ return 0;
+}
+
+static int i2o_seq_show_lct(struct seq_file *seq, void *v)
+{
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ i2o_lct *lct = (i2o_lct *) c->lct;
+ int entries;
+ int i;
+
+#define BUS_TABLE_SIZE 3
+ static char *bus_ports[] = {
+ "Generic Bus",
+ "SCSI Bus",
+ "Fibre Channel Bus"
+ };
+
+ entries = (lct->table_size - 3) / 9;
+
+ seq_printf(seq, "LCT contains %d %s\n", entries,
+ entries == 1 ? "entry" : "entries");
+ if (lct->boot_tid)
+ seq_printf(seq, "Boot Device @ ID %d\n", lct->boot_tid);
+
+ seq_printf(seq, "Current Change Indicator: %#10x\n", lct->change_ind);
+
+ for (i = 0; i < entries; i++) {
+ seq_printf(seq, "Entry %d\n", i);
+ seq_printf(seq, " Class, SubClass : %s",
+ i2o_get_class_name(lct->lct_entry[i].class_id));
+
+ /*
+ * Classes which we'll print subclass info for
+ */
+ switch (lct->lct_entry[i].class_id & 0xFFF) {
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ switch (lct->lct_entry[i].sub_class) {
+ case 0x00:
+ seq_printf(seq, ", Direct-Access Read/Write");
+ break;
+
+ case 0x04:
+ seq_printf(seq, ", WORM Drive");
+ break;
+
+ case 0x05:
+ seq_printf(seq, ", CD-ROM Drive");
+ break;
+
+ case 0x07:
+ seq_printf(seq, ", Optical Memory Device");
+ break;
+
+ default:
+ seq_printf(seq, ", Unknown (0x%02x)",
+ lct->lct_entry[i].sub_class);
+ break;
+ }
+ break;
+
+ case I2O_CLASS_LAN:
+ switch (lct->lct_entry[i].sub_class & 0xFF) {
+ case 0x30:
+ seq_printf(seq, ", Ethernet");
+ break;
+
+ case 0x40:
+ seq_printf(seq, ", 100base VG");
+ break;
+
+ case 0x50:
+ seq_printf(seq, ", IEEE 802.5/Token-Ring");
+ break;
+
+ case 0x60:
+ seq_printf(seq, ", ANSI X3T9.5 FDDI");
+ break;
+
+ case 0x70:
+ seq_printf(seq, ", Fibre Channel");
+ break;
+
+ default:
+ seq_printf(seq, ", Unknown Sub-Class (0x%02x)",
+ lct->lct_entry[i].sub_class & 0xFF);
+ break;
+ }
+ break;
+
+ case I2O_CLASS_SCSI_PERIPHERAL:
+ if (lct->lct_entry[i].sub_class < SCSI_TABLE_SIZE)
+ seq_printf(seq, ", %s",
+ scsi_devices[lct->lct_entry[i].
+ sub_class]);
+ else
+ seq_printf(seq, ", Unknown Device Type");
+ break;
+
+ case I2O_CLASS_BUS_ADAPTER:
+ if (lct->lct_entry[i].sub_class < BUS_TABLE_SIZE)
+ seq_printf(seq, ", %s",
+ bus_ports[lct->lct_entry[i].
+ sub_class]);
+ else
+ seq_printf(seq, ", Unknown Bus Type");
+ break;
+ }
+ seq_printf(seq, "\n");
+
+ seq_printf(seq, " Local TID : 0x%03x\n",
+ lct->lct_entry[i].tid);
+ seq_printf(seq, " User TID : 0x%03x\n",
+ lct->lct_entry[i].user_tid);
+ seq_printf(seq, " Parent TID : 0x%03x\n",
+ lct->lct_entry[i].parent_tid);
+ seq_printf(seq, " Identity Tag : 0x%x%x%x%x%x%x%x%x\n",
+ lct->lct_entry[i].identity_tag[0],
+ lct->lct_entry[i].identity_tag[1],
+ lct->lct_entry[i].identity_tag[2],
+ lct->lct_entry[i].identity_tag[3],
+ lct->lct_entry[i].identity_tag[4],
+ lct->lct_entry[i].identity_tag[5],
+ lct->lct_entry[i].identity_tag[6],
+ lct->lct_entry[i].identity_tag[7]);
+ seq_printf(seq, " Change Indicator : %0#10x\n",
+ lct->lct_entry[i].change_ind);
+ seq_printf(seq, " Event Capab Mask : %0#10x\n",
+ lct->lct_entry[i].device_flags);
+ }
+
+ return 0;
+}
+
+static int i2o_seq_show_status(struct seq_file *seq, void *v)
+{
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ char prodstr[25];
+ int version;
+ i2o_status_block *sb = c->status_block.virt;
+
+ i2o_status_get(c); // reread the status block
+
+ seq_printf(seq, "Organization ID : %0#6x\n", sb->org_id);
+
+ version = sb->i2o_version;
+
+/* FIXME for Spec 2.0
+ if (version == 0x02) {
+ seq_printf(seq, "Lowest I2O version supported: ");
+ switch(workspace[2]) {
+ case 0x00:
+ seq_printf(seq, "1.0\n");
+ break;
+ case 0x01:
+ seq_printf(seq, "1.5\n");
+ break;
+ case 0x02:
+ seq_printf(seq, "2.0\n");
+ break;
+ }
+
+ seq_printf(seq, "Highest I2O version supported: ");
+ switch(workspace[3]) {
+ case 0x00:
+ seq_printf(seq, "1.0\n");
+ break;
+ case 0x01:
+ seq_printf(seq, "1.5\n");
+ break;
+ case 0x02:
+ seq_printf(seq, "2.0\n");
+ break;
+ }
+ }
+*/
+ seq_printf(seq, "IOP ID : %0#5x\n", sb->iop_id);
+ seq_printf(seq, "Host Unit ID : %0#6x\n", sb->host_unit_id);
+ seq_printf(seq, "Segment Number : %0#5x\n", sb->segment_number);
+
+ seq_printf(seq, "I2O version : ");
+ switch (version) {
+ case 0x00:
+ seq_printf(seq, "1.0\n");
+ break;
+ case 0x01:
+ seq_printf(seq, "1.5\n");
+ break;
+ case 0x02:
+ seq_printf(seq, "2.0\n");
+ break;
+ default:
+ seq_printf(seq, "Unknown version\n");
+ }
+
+ seq_printf(seq, "IOP State : ");
+ switch (sb->iop_state) {
+ case 0x01:
+ seq_printf(seq, "INIT\n");
+ break;
+
+ case 0x02:
+ seq_printf(seq, "RESET\n");
+ break;
+
+ case 0x04:
+ seq_printf(seq, "HOLD\n");
+ break;
+
+ case 0x05:
+ seq_printf(seq, "READY\n");
+ break;
+
+ case 0x08:
+ seq_printf(seq, "OPERATIONAL\n");
+ break;
+
+ case 0x10:
+ seq_printf(seq, "FAILED\n");
+ break;
+
+ case 0x11:
+ seq_printf(seq, "FAULTED\n");
+ break;
+
+ default:
+ seq_printf(seq, "Unknown\n");
+ break;
+ }
+
+ seq_printf(seq, "Messenger Type : ");
+ switch (sb->msg_type) {
+ case 0x00:
+ seq_printf(seq, "Memory mapped\n");
+ break;
+ case 0x01:
+ seq_printf(seq, "Memory mapped only\n");
+ break;
+ case 0x02:
+ seq_printf(seq, "Remote only\n");
+ break;
+ case 0x03:
+ seq_printf(seq, "Memory mapped and remote\n");
+ break;
+ default:
+ seq_printf(seq, "Unknown\n");
+ }
+
+ seq_printf(seq, "Inbound Frame Size : %d bytes\n",
+ sb->inbound_frame_size << 2);
+ seq_printf(seq, "Max Inbound Frames : %d\n",
+ sb->max_inbound_frames);
+ seq_printf(seq, "Current Inbound Frames : %d\n",
+ sb->cur_inbound_frames);
+ seq_printf(seq, "Max Outbound Frames : %d\n",
+ sb->max_outbound_frames);
+
+ /* Spec doesn't say if NULL terminated or not... */
+ memcpy(prodstr, sb->product_id, 24);
+ prodstr[24] = '\0';
+ seq_printf(seq, "Product ID : %s\n", prodstr);
+ seq_printf(seq, "Expected LCT Size : %d bytes\n",
+ sb->expected_lct_size);
+
+ seq_printf(seq, "IOP Capabilities\n");
+ seq_printf(seq, " Context Field Size Support : ");
+ switch (sb->iop_capabilities & 0x0000003) {
+ case 0:
+ seq_printf(seq, "Supports only 32-bit context fields\n");
+ break;
+ case 1:
+ seq_printf(seq, "Supports only 64-bit context fields\n");
+ break;
+ case 2:
+ seq_printf(seq, "Supports 32-bit and 64-bit context fields, "
+ "but not concurrently\n");
+ break;
+ case 3:
+ seq_printf(seq, "Supports 32-bit and 64-bit context fields "
+ "concurrently\n");
+ break;
+ default:
+ seq_printf(seq, "0x%08x\n", sb->iop_capabilities);
+ }
+ seq_printf(seq, " Current Context Field Size : ");
+ switch (sb->iop_capabilities & 0x0000000C) {
+ case 0:
+ seq_printf(seq, "not configured\n");
+ break;
+ case 4:
+ seq_printf(seq, "Supports only 32-bit context fields\n");
+ break;
+ case 8:
+ seq_printf(seq, "Supports only 64-bit context fields\n");
+ break;
+ case 12:
+ seq_printf(seq, "Supports both 32-bit or 64-bit context fields "
+ "concurrently\n");
+ break;
+ default:
+ seq_printf(seq, "\n");
+ }
+ seq_printf(seq, " Inbound Peer Support : %s\n",
+ (sb->
+ iop_capabilities & 0x00000010) ? "Supported" :
+ "Not supported");
+ seq_printf(seq, " Outbound Peer Support : %s\n",
+ (sb->
+ iop_capabilities & 0x00000020) ? "Supported" :
+ "Not supported");
+ seq_printf(seq, " Peer to Peer Support : %s\n",
+ (sb->
+ iop_capabilities & 0x00000040) ? "Supported" :
+ "Not supported");
+
+ seq_printf(seq, "Desired private memory size : %d kB\n",
+ sb->desired_mem_size >> 10);
+ seq_printf(seq, "Allocated private memory size : %d kB\n",
+ sb->current_mem_size >> 10);
+ seq_printf(seq, "Private memory base address : %0#10x\n",
+ sb->current_mem_base);
+ seq_printf(seq, "Desired private I/O size : %d kB\n",
+ sb->desired_io_size >> 10);
+ seq_printf(seq, "Allocated private I/O size : %d kB\n",
+ sb->current_io_size >> 10);
+ seq_printf(seq, "Private I/O base address : %0#10x\n",
+ sb->current_io_base);
+
+ return 0;
+}
+
+static int i2o_seq_show_hw(struct seq_file *seq, void *v)
+{
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ static u32 work32[5];
+ static u8 *work8 = (u8 *) work32;
+ static u16 *work16 = (u16 *) work32;
+ int token;
+ u32 hwcap;
+
+ static char *cpu_table[] = {
+ "Intel 80960 series",
+ "AMD2900 series",
+ "Motorola 68000 series",
+ "ARM series",
+ "MIPS series",
+ "Sparc series",
+ "PowerPC series",
+ "Intel x86 series"
+ };
+
+ token =
+ i2o_parm_field_get(c->exec, 0x0000, -1, &work32, sizeof(work32));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0x0000 IOP Hardware");
+ return 0;
+ }
+
+ seq_printf(seq, "I2O Vendor ID : %0#6x\n", work16[0]);
+ seq_printf(seq, "Product ID : %0#6x\n", work16[1]);
+ seq_printf(seq, "CPU : ");
+ if (work8[16] > 8)
+ seq_printf(seq, "Unknown\n");
+ else
+ seq_printf(seq, "%s\n", cpu_table[work8[16]]);
+ /* Anyone using ProcessorVersion? */
+
+ seq_printf(seq, "RAM : %dkB\n", work32[1] >> 10);
+ seq_printf(seq, "Non-Volatile Mem : %dkB\n", work32[2] >> 10);
+
+ hwcap = work32[3];
+ seq_printf(seq, "Capabilities : 0x%08x\n", hwcap);
+ seq_printf(seq, " [%s] Self booting\n",
+ (hwcap & 0x00000001) ? "+" : "-");
+ seq_printf(seq, " [%s] Upgradable IRTOS\n",
+ (hwcap & 0x00000002) ? "+" : "-");
+ seq_printf(seq, " [%s] Supports downloading DDMs\n",
+ (hwcap & 0x00000004) ? "+" : "-");
+ seq_printf(seq, " [%s] Supports installing DDMs\n",
+ (hwcap & 0x00000008) ? "+" : "-");
+ seq_printf(seq, " [%s] Battery-backed RAM\n",
+ (hwcap & 0x00000010) ? "+" : "-");
+
+ return 0;
+}
+
+/* Executive group 0003h - Executing DDM List (table) */
+static int i2o_seq_show_ddm_table(struct seq_file *seq, void *v)
+{
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ int token;
+ int i;
+
+ typedef struct _i2o_exec_execute_ddm_table {
+ u16 ddm_tid;
+ u8 module_type;
+ u8 reserved;
+ u16 i2o_vendor_id;
+ u16 module_id;
+ u8 module_name_version[28];
+ u32 data_size;
+ u32 code_size;
+ } i2o_exec_execute_ddm_table;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ i2o_exec_execute_ddm_table ddm_table[I2O_MAX_MODULES];
+ } *result;
+
+ i2o_exec_execute_ddm_table ddm_table;
+ char tmp[28 + 1];
+
+ result = kmalloc(sizeof(*result), GFP_KERNEL);
+ if (!result)
+ return -ENOMEM;
+
+ token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0003, -1,
+ NULL, 0, result, sizeof(*result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0x0003 Executing DDM List");
+ goto out;
+ }
+
+ seq_printf(seq,
+ "Tid Module_type Vendor Mod_id Module_name Vrs Data_size Code_size\n");
+ ddm_table = result->ddm_table[0];
+
+ for (i = 0; i < result->row_count; ddm_table = result->ddm_table[++i]) {
+ seq_printf(seq, "0x%03x ", ddm_table.ddm_tid & 0xFFF);
+
+ switch (ddm_table.module_type) {
+ case 0x01:
+ seq_printf(seq, "Downloaded DDM ");
+ break;
+ case 0x22:
+ seq_printf(seq, "Embedded DDM ");
+ break;
+ default:
+ seq_printf(seq, " ");
+ }
+
+ seq_printf(seq, "%-#7x", ddm_table.i2o_vendor_id);
+ seq_printf(seq, "%-#8x", ddm_table.module_id);
+ seq_printf(seq, "%-29s",
+ chtostr(tmp, ddm_table.module_name_version, 28));
+ seq_printf(seq, "%9d ", ddm_table.data_size);
+ seq_printf(seq, "%8d", ddm_table.code_size);
+
+ seq_printf(seq, "\n");
+ }
+ out:
+ kfree(result);
+ return 0;
+}
+
+/* Executive group 0004h - Driver Store (scalar) */
+static int i2o_seq_show_driver_store(struct seq_file *seq, void *v)
+{
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ u32 work32[8];
+ int token;
+
+ token =
+ i2o_parm_field_get(c->exec, 0x0004, -1, &work32, sizeof(work32));
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0x0004 Driver Store");
+ return 0;
+ }
+
+ seq_printf(seq, "Module limit : %d\n"
+ "Module count : %d\n"
+ "Current space : %d kB\n"
+ "Free space : %d kB\n",
+ work32[0], work32[1], work32[2] >> 10, work32[3] >> 10);
+
+ return 0;
+}
+
+/* Executive group 0005h - Driver Store Table (table) */
+static int i2o_seq_show_drivers_stored(struct seq_file *seq, void *v)
+{
+ typedef struct _i2o_driver_store {
+ u16 stored_ddm_index;
+ u8 module_type;
+ u8 reserved;
+ u16 i2o_vendor_id;
+ u16 module_id;
+ u8 module_name_version[28];
+ u8 date[8];
+ u32 module_size;
+ u32 mpb_size;
+ u32 module_flags;
+ } i2o_driver_store_table;
+
+ struct i2o_controller *c = (struct i2o_controller *)seq->private;
+ int token;
+ int i;
+
+ typedef struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ i2o_driver_store_table dst[I2O_MAX_MODULES];
+ } i2o_driver_result_table;
+
+ i2o_driver_result_table *result;
+ i2o_driver_store_table *dst;
+ char tmp[28 + 1];
+
+ result = kmalloc(sizeof(i2o_driver_result_table), GFP_KERNEL);
+ if (result == NULL)
+ return -ENOMEM;
+
+ token = i2o_parm_table_get(c->exec, I2O_PARAMS_TABLE_GET, 0x0005, -1,
+ NULL, 0, result, sizeof(*result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0x0005 DRIVER STORE TABLE");
+ kfree(result);
+ return 0;
+ }
+
+ seq_printf(seq,
+ "# Module_type Vendor Mod_id Module_name Vrs"
+ "Date Mod_size Par_size Flags\n");
+ for (i = 0, dst = &result->dst[0]; i < result->row_count;
+ dst = &result->dst[++i]) {
+ seq_printf(seq, "%-3d", dst->stored_ddm_index);
+ switch (dst->module_type) {
+ case 0x01:
+ seq_printf(seq, "Downloaded DDM ");
+ break;
+ case 0x22:
+ seq_printf(seq, "Embedded DDM ");
+ break;
+ default:
+ seq_printf(seq, " ");
+ }
+
+ seq_printf(seq, "%-#7x", dst->i2o_vendor_id);
+ seq_printf(seq, "%-#8x", dst->module_id);
+ seq_printf(seq, "%-29s",
+ chtostr(tmp, dst->module_name_version, 28));
+ seq_printf(seq, "%-9s", chtostr(tmp, dst->date, 8));
+ seq_printf(seq, "%8d ", dst->module_size);
+ seq_printf(seq, "%8d ", dst->mpb_size);
+ seq_printf(seq, "0x%04x", dst->module_flags);
+ seq_printf(seq, "\n");
+ }
+
+ kfree(result);
+ return 0;
+}
+
+/* Generic group F000h - Params Descriptor (table) */
+static int i2o_seq_show_groups(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+ int i;
+ u8 properties;
+
+ typedef struct _i2o_group_info {
+ u16 group_number;
+ u16 field_count;
+ u16 row_count;
+ u8 properties;
+ u8 reserved;
+ } i2o_group_info;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ i2o_group_info group[256];
+ } *result;
+
+ result = kmalloc(sizeof(*result), GFP_KERNEL);
+ if (!result)
+ return -ENOMEM;
+
+ token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
+ result, sizeof(*result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0xF000 Params Descriptor");
+ goto out;
+ }
+
+ seq_printf(seq,
+ "# Group FieldCount RowCount Type Add Del Clear\n");
+
+ for (i = 0; i < result->row_count; i++) {
+ seq_printf(seq, "%-3d", i);
+ seq_printf(seq, "0x%04X ", result->group[i].group_number);
+ seq_printf(seq, "%10d ", result->group[i].field_count);
+ seq_printf(seq, "%8d ", result->group[i].row_count);
+
+ properties = result->group[i].properties;
+ if (properties & 0x1)
+ seq_printf(seq, "Table ");
+ else
+ seq_printf(seq, "Scalar ");
+ if (properties & 0x2)
+ seq_printf(seq, " + ");
+ else
+ seq_printf(seq, " - ");
+ if (properties & 0x4)
+ seq_printf(seq, " + ");
+ else
+ seq_printf(seq, " - ");
+ if (properties & 0x8)
+ seq_printf(seq, " + ");
+ else
+ seq_printf(seq, " - ");
+
+ seq_printf(seq, "\n");
+ }
+
+ if (result->more_flag)
+ seq_printf(seq, "There is more...\n");
+ out:
+ kfree(result);
+ return 0;
+}
+
+/* Generic group F001h - Physical Device Table (table) */
+static int i2o_seq_show_phys_device(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+ int i;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ u32 adapter_id[64];
+ } result;
+
+ token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF001, -1, NULL, 0,
+ &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0xF001 Physical Device Table");
+ return 0;
+ }
+
+ if (result.row_count)
+ seq_printf(seq, "# AdapterId\n");
+
+ for (i = 0; i < result.row_count; i++) {
+ seq_printf(seq, "%-2d", i);
+ seq_printf(seq, "%#7x\n", result.adapter_id[i]);
+ }
+
+ if (result.more_flag)
+ seq_printf(seq, "There is more...\n");
+
+ return 0;
+}
+
+/* Generic group F002h - Claimed Table (table) */
+static int i2o_seq_show_claimed(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+ int i;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ u16 claimed_tid[64];
+ } result;
+
+ token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF002, -1, NULL, 0,
+ &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0xF002 Claimed Table");
+ return 0;
+ }
+
+ if (result.row_count)
+ seq_printf(seq, "# ClaimedTid\n");
+
+ for (i = 0; i < result.row_count; i++) {
+ seq_printf(seq, "%-2d", i);
+ seq_printf(seq, "%#7x\n", result.claimed_tid[i]);
+ }
+
+ if (result.more_flag)
+ seq_printf(seq, "There is more...\n");
+
+ return 0;
+}
+
+/* Generic group F003h - User Table (table) */
+static int i2o_seq_show_users(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+ int i;
+
+ typedef struct _i2o_user_table {
+ u16 instance;
+ u16 user_tid;
+ u8 claim_type;
+ u8 reserved1;
+ u16 reserved2;
+ } i2o_user_table;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ i2o_user_table user[64];
+ } *result;
+
+ result = kmalloc(sizeof(*result), GFP_KERNEL);
+ if (!result)
+ return -ENOMEM;
+
+ token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF003, -1, NULL, 0,
+ result, sizeof(*result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0xF003 User Table");
+ goto out;
+ }
+
+ seq_printf(seq, "# Instance UserTid ClaimType\n");
+
+ for (i = 0; i < result->row_count; i++) {
+ seq_printf(seq, "%-3d", i);
+ seq_printf(seq, "%#8x ", result->user[i].instance);
+ seq_printf(seq, "%#7x ", result->user[i].user_tid);
+ seq_printf(seq, "%#9x\n", result->user[i].claim_type);
+ }
+
+ if (result->more_flag)
+ seq_printf(seq, "There is more...\n");
+ out:
+ kfree(result);
+ return 0;
+}
+
+/* Generic group F005h - Private message extensions (table) (optional) */
+static int i2o_seq_show_priv_msgs(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+ int i;
+
+ typedef struct _i2o_private {
+ u16 ext_instance;
+ u16 organization_id;
+ u16 x_function_code;
+ } i2o_private;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ i2o_private extension[64];
+ } result;
+
+ token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF000, -1, NULL, 0,
+ &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0xF005 Private Message Extensions (optional)");
+ return 0;
+ }
+
+ seq_printf(seq, "Instance# OrgId FunctionCode\n");
+
+ for (i = 0; i < result.row_count; i++) {
+ seq_printf(seq, "%0#9x ", result.extension[i].ext_instance);
+ seq_printf(seq, "%0#6x ", result.extension[i].organization_id);
+ seq_printf(seq, "%0#6x", result.extension[i].x_function_code);
+
+ seq_printf(seq, "\n");
+ }
+
+ if (result.more_flag)
+ seq_printf(seq, "There is more...\n");
+
+ return 0;
+}
+
+/* Generic group F006h - Authorized User Table (table) */
+static int i2o_seq_show_authorized_users(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+ int i;
+
+ struct {
+ u16 result_count;
+ u16 pad;
+ u16 block_size;
+ u8 block_status;
+ u8 error_info_size;
+ u16 row_count;
+ u16 more_flag;
+ u32 alternate_tid[64];
+ } result;
+
+ token = i2o_parm_table_get(d, I2O_PARAMS_TABLE_GET, 0xF006, -1, NULL, 0,
+ &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0xF006 Autohorized User Table");
+ return 0;
+ }
+
+ if (result.row_count)
+ seq_printf(seq, "# AlternateTid\n");
+
+ for (i = 0; i < result.row_count; i++) {
+ seq_printf(seq, "%-2d", i);
+ seq_printf(seq, "%#7x ", result.alternate_tid[i]);
+ }
+
+ if (result.more_flag)
+ seq_printf(seq, "There is more...\n");
+
+ return 0;
+}
+
+/* Generic group F100h - Device Identity (scalar) */
+static int i2o_seq_show_dev_identity(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ static u32 work32[128]; // allow for "stuff" + up to 256 byte (max) serial number
+ // == (allow) 512d bytes (max)
+ static u16 *work16 = (u16 *) work32;
+ int token;
+ char tmp[16 + 1];
+
+ token = i2o_parm_field_get(d, 0xF100, -1, &work32, sizeof(work32));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0xF100 Device Identity");
+ return 0;
+ }
+
+ seq_printf(seq, "Device Class : %s\n", i2o_get_class_name(work16[0]));
+ seq_printf(seq, "Owner TID : %0#5x\n", work16[2]);
+ seq_printf(seq, "Parent TID : %0#5x\n", work16[3]);
+ seq_printf(seq, "Vendor info : %s\n",
+ chtostr(tmp, (u8 *) (work32 + 2), 16));
+ seq_printf(seq, "Product info : %s\n",
+ chtostr(tmp, (u8 *) (work32 + 6), 16));
+ seq_printf(seq, "Description : %s\n",
+ chtostr(tmp, (u8 *) (work32 + 10), 16));
+ seq_printf(seq, "Product rev. : %s\n",
+ chtostr(tmp, (u8 *) (work32 + 14), 8));
+
+ seq_printf(seq, "Serial number : ");
+ print_serial_number(seq, (u8 *) (work32 + 16),
+ /* allow for SNLen plus
+ * possible trailing '\0'
+ */
+ sizeof(work32) - (16 * sizeof(u32)) - 2);
+ seq_printf(seq, "\n");
+
+ return 0;
+}
+
+static int i2o_seq_show_dev_name(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+
+ seq_printf(seq, "%s\n", dev_name(&d->device));
+
+ return 0;
+}
+
+/* Generic group F101h - DDM Identity (scalar) */
+static int i2o_seq_show_ddm_identity(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+
+ struct {
+ u16 ddm_tid;
+ u8 module_name[24];
+ u8 module_rev[8];
+ u8 sn_format;
+ u8 serial_number[12];
+ u8 pad[256]; // allow up to 256 byte (max) serial number
+ } result;
+
+ char tmp[24 + 1];
+
+ token = i2o_parm_field_get(d, 0xF101, -1, &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0xF101 DDM Identity");
+ return 0;
+ }
+
+ seq_printf(seq, "Registering DDM TID : 0x%03x\n", result.ddm_tid);
+ seq_printf(seq, "Module name : %s\n",
+ chtostr(tmp, result.module_name, 24));
+ seq_printf(seq, "Module revision : %s\n",
+ chtostr(tmp, result.module_rev, 8));
+
+ seq_printf(seq, "Serial number : ");
+ print_serial_number(seq, result.serial_number, sizeof(result) - 36);
+ /* allow for SNLen plus possible trailing '\0' */
+
+ seq_printf(seq, "\n");
+
+ return 0;
+}
+
+/* Generic group F102h - User Information (scalar) */
+static int i2o_seq_show_uinfo(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+
+ struct {
+ u8 device_name[64];
+ u8 service_name[64];
+ u8 physical_location[64];
+ u8 instance_number[4];
+ } result;
+
+ char tmp[64 + 1];
+
+ token = i2o_parm_field_get(d, 0xF102, -1, &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token, "0xF102 User Information");
+ return 0;
+ }
+
+ seq_printf(seq, "Device name : %s\n",
+ chtostr(tmp, result.device_name, 64));
+ seq_printf(seq, "Service name : %s\n",
+ chtostr(tmp, result.service_name, 64));
+ seq_printf(seq, "Physical name : %s\n",
+ chtostr(tmp, result.physical_location, 64));
+ seq_printf(seq, "Instance number : %s\n",
+ chtostr(tmp, result.instance_number, 4));
+
+ return 0;
+}
+
+/* Generic group F103h - SGL Operating Limits (scalar) */
+static int i2o_seq_show_sgl_limits(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ static u32 work32[12];
+ static u16 *work16 = (u16 *) work32;
+ static u8 *work8 = (u8 *) work32;
+ int token;
+
+ token = i2o_parm_field_get(d, 0xF103, -1, &work32, sizeof(work32));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0xF103 SGL Operating Limits");
+ return 0;
+ }
+
+ seq_printf(seq, "SGL chain size : %d\n", work32[0]);
+ seq_printf(seq, "Max SGL chain size : %d\n", work32[1]);
+ seq_printf(seq, "SGL chain size target : %d\n", work32[2]);
+ seq_printf(seq, "SGL frag count : %d\n", work16[6]);
+ seq_printf(seq, "Max SGL frag count : %d\n", work16[7]);
+ seq_printf(seq, "SGL frag count target : %d\n", work16[8]);
+
+/* FIXME
+ if (d->i2oversion == 0x02)
+ {
+*/
+ seq_printf(seq, "SGL data alignment : %d\n", work16[8]);
+ seq_printf(seq, "SGL addr limit : %d\n", work8[20]);
+ seq_printf(seq, "SGL addr sizes supported : ");
+ if (work8[21] & 0x01)
+ seq_printf(seq, "32 bit ");
+ if (work8[21] & 0x02)
+ seq_printf(seq, "64 bit ");
+ if (work8[21] & 0x04)
+ seq_printf(seq, "96 bit ");
+ if (work8[21] & 0x08)
+ seq_printf(seq, "128 bit ");
+ seq_printf(seq, "\n");
+/*
+ }
+*/
+
+ return 0;
+}
+
+/* Generic group F200h - Sensors (scalar) */
+static int i2o_seq_show_sensors(struct seq_file *seq, void *v)
+{
+ struct i2o_device *d = (struct i2o_device *)seq->private;
+ int token;
+
+ struct {
+ u16 sensor_instance;
+ u8 component;
+ u16 component_instance;
+ u8 sensor_class;
+ u8 sensor_type;
+ u8 scaling_exponent;
+ u32 actual_reading;
+ u32 minimum_reading;
+ u32 low2lowcat_treshold;
+ u32 lowcat2low_treshold;
+ u32 lowwarn2low_treshold;
+ u32 low2lowwarn_treshold;
+ u32 norm2lowwarn_treshold;
+ u32 lowwarn2norm_treshold;
+ u32 nominal_reading;
+ u32 hiwarn2norm_treshold;
+ u32 norm2hiwarn_treshold;
+ u32 high2hiwarn_treshold;
+ u32 hiwarn2high_treshold;
+ u32 hicat2high_treshold;
+ u32 hi2hicat_treshold;
+ u32 maximum_reading;
+ u8 sensor_state;
+ u16 event_enable;
+ } result;
+
+ token = i2o_parm_field_get(d, 0xF200, -1, &result, sizeof(result));
+
+ if (token < 0) {
+ i2o_report_query_status(seq, token,
+ "0xF200 Sensors (optional)");
+ return 0;
+ }
+
+ seq_printf(seq, "Sensor instance : %d\n", result.sensor_instance);
+
+ seq_printf(seq, "Component : %d = ", result.component);
+ switch (result.component) {
+ case 0:
+ seq_printf(seq, "Other");
+ break;
+ case 1:
+ seq_printf(seq, "Planar logic Board");
+ break;
+ case 2:
+ seq_printf(seq, "CPU");
+ break;
+ case 3:
+ seq_printf(seq, "Chassis");
+ break;
+ case 4:
+ seq_printf(seq, "Power Supply");
+ break;
+ case 5:
+ seq_printf(seq, "Storage");
+ break;
+ case 6:
+ seq_printf(seq, "External");
+ break;
+ }
+ seq_printf(seq, "\n");
+
+ seq_printf(seq, "Component instance : %d\n",
+ result.component_instance);
+ seq_printf(seq, "Sensor class : %s\n",
+ result.sensor_class ? "Analog" : "Digital");
+
+ seq_printf(seq, "Sensor type : %d = ", result.sensor_type);
+ switch (result.sensor_type) {
+ case 0:
+ seq_printf(seq, "Other\n");
+ break;
+ case 1:
+ seq_printf(seq, "Thermal\n");
+ break;
+ case 2:
+ seq_printf(seq, "DC voltage (DC volts)\n");
+ break;
+ case 3:
+ seq_printf(seq, "AC voltage (AC volts)\n");
+ break;
+ case 4:
+ seq_printf(seq, "DC current (DC amps)\n");
+ break;
+ case 5:
+ seq_printf(seq, "AC current (AC volts)\n");
+ break;
+ case 6:
+ seq_printf(seq, "Door open\n");
+ break;
+ case 7:
+ seq_printf(seq, "Fan operational\n");
+ break;
+ }
+
+ seq_printf(seq, "Scaling exponent : %d\n",
+ result.scaling_exponent);
+ seq_printf(seq, "Actual reading : %d\n", result.actual_reading);
+ seq_printf(seq, "Minimum reading : %d\n", result.minimum_reading);
+ seq_printf(seq, "Low2LowCat treshold : %d\n",
+ result.low2lowcat_treshold);
+ seq_printf(seq, "LowCat2Low treshold : %d\n",
+ result.lowcat2low_treshold);
+ seq_printf(seq, "LowWarn2Low treshold : %d\n",
+ result.lowwarn2low_treshold);
+ seq_printf(seq, "Low2LowWarn treshold : %d\n",
+ result.low2lowwarn_treshold);
+ seq_printf(seq, "Norm2LowWarn treshold : %d\n",
+ result.norm2lowwarn_treshold);
+ seq_printf(seq, "LowWarn2Norm treshold : %d\n",
+ result.lowwarn2norm_treshold);
+ seq_printf(seq, "Nominal reading : %d\n", result.nominal_reading);
+ seq_printf(seq, "HiWarn2Norm treshold : %d\n",
+ result.hiwarn2norm_treshold);
+ seq_printf(seq, "Norm2HiWarn treshold : %d\n",
+ result.norm2hiwarn_treshold);
+ seq_printf(seq, "High2HiWarn treshold : %d\n",
+ result.high2hiwarn_treshold);
+ seq_printf(seq, "HiWarn2High treshold : %d\n",
+ result.hiwarn2high_treshold);
+ seq_printf(seq, "HiCat2High treshold : %d\n",
+ result.hicat2high_treshold);
+ seq_printf(seq, "High2HiCat treshold : %d\n",
+ result.hi2hicat_treshold);
+ seq_printf(seq, "Maximum reading : %d\n", result.maximum_reading);
+
+ seq_printf(seq, "Sensor state : %d = ", result.sensor_state);
+ switch (result.sensor_state) {
+ case 0:
+ seq_printf(seq, "Normal\n");
+ break;
+ case 1:
+ seq_printf(seq, "Abnormal\n");
+ break;
+ case 2:
+ seq_printf(seq, "Unknown\n");
+ break;
+ case 3:
+ seq_printf(seq, "Low Catastrophic (LoCat)\n");
+ break;
+ case 4:
+ seq_printf(seq, "Low (Low)\n");
+ break;
+ case 5:
+ seq_printf(seq, "Low Warning (LoWarn)\n");
+ break;
+ case 6:
+ seq_printf(seq, "High Warning (HiWarn)\n");
+ break;
+ case 7:
+ seq_printf(seq, "High (High)\n");
+ break;
+ case 8:
+ seq_printf(seq, "High Catastrophic (HiCat)\n");
+ break;
+ }
+
+ seq_printf(seq, "Event_enable : 0x%02X\n", result.event_enable);
+ seq_printf(seq, " [%s] Operational state change. \n",
+ (result.event_enable & 0x01) ? "+" : "-");
+ seq_printf(seq, " [%s] Low catastrophic. \n",
+ (result.event_enable & 0x02) ? "+" : "-");
+ seq_printf(seq, " [%s] Low reading. \n",
+ (result.event_enable & 0x04) ? "+" : "-");
+ seq_printf(seq, " [%s] Low warning. \n",
+ (result.event_enable & 0x08) ? "+" : "-");
+ seq_printf(seq,
+ " [%s] Change back to normal from out of range state. \n",
+ (result.event_enable & 0x10) ? "+" : "-");
+ seq_printf(seq, " [%s] High warning. \n",
+ (result.event_enable & 0x20) ? "+" : "-");
+ seq_printf(seq, " [%s] High reading. \n",
+ (result.event_enable & 0x40) ? "+" : "-");
+ seq_printf(seq, " [%s] High catastrophic. \n",
+ (result.event_enable & 0x80) ? "+" : "-");
+
+ return 0;
+}
+
+static int i2o_seq_open_hrt(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_hrt, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_lct(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_lct, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_status(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_status, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_hw(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_hw, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_ddm_table(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_ddm_table, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_driver_store(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_driver_store, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_drivers_stored(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_drivers_stored, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_groups(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_groups, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_phys_device(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_phys_device, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_claimed(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_claimed, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_users(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_users, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_priv_msgs(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_priv_msgs, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_authorized_users(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_authorized_users,
+ PDE_DATA(inode));
+};
+
+static int i2o_seq_open_dev_identity(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_dev_identity, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_ddm_identity(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_ddm_identity, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_uinfo(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_uinfo, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_sgl_limits(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_sgl_limits, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_sensors(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_sensors, PDE_DATA(inode));
+};
+
+static int i2o_seq_open_dev_name(struct inode *inode, struct file *file)
+{
+ return single_open(file, i2o_seq_show_dev_name, PDE_DATA(inode));
+};
+
+static const struct file_operations i2o_seq_fops_lct = {
+ .open = i2o_seq_open_lct,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_hrt = {
+ .open = i2o_seq_open_hrt,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_status = {
+ .open = i2o_seq_open_status,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_hw = {
+ .open = i2o_seq_open_hw,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_ddm_table = {
+ .open = i2o_seq_open_ddm_table,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_driver_store = {
+ .open = i2o_seq_open_driver_store,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_drivers_stored = {
+ .open = i2o_seq_open_drivers_stored,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_groups = {
+ .open = i2o_seq_open_groups,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_phys_device = {
+ .open = i2o_seq_open_phys_device,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_claimed = {
+ .open = i2o_seq_open_claimed,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_users = {
+ .open = i2o_seq_open_users,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_priv_msgs = {
+ .open = i2o_seq_open_priv_msgs,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_authorized_users = {
+ .open = i2o_seq_open_authorized_users,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_dev_name = {
+ .open = i2o_seq_open_dev_name,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_dev_identity = {
+ .open = i2o_seq_open_dev_identity,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_ddm_identity = {
+ .open = i2o_seq_open_ddm_identity,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_uinfo = {
+ .open = i2o_seq_open_uinfo,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_sgl_limits = {
+ .open = i2o_seq_open_sgl_limits,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static const struct file_operations i2o_seq_fops_sensors = {
+ .open = i2o_seq_open_sensors,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/*
+ * IOP specific entries...write field just in case someone
+ * ever wants one.
+ */
+static i2o_proc_entry i2o_proc_generic_iop_entries[] = {
+ {"hrt", S_IFREG | S_IRUGO, &i2o_seq_fops_hrt},
+ {"lct", S_IFREG | S_IRUGO, &i2o_seq_fops_lct},
+ {"status", S_IFREG | S_IRUGO, &i2o_seq_fops_status},
+ {"hw", S_IFREG | S_IRUGO, &i2o_seq_fops_hw},
+ {"ddm_table", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_table},
+ {"driver_store", S_IFREG | S_IRUGO, &i2o_seq_fops_driver_store},
+ {"drivers_stored", S_IFREG | S_IRUGO, &i2o_seq_fops_drivers_stored},
+ {NULL, 0, NULL}
+};
+
+/*
+ * Device specific entries
+ */
+static i2o_proc_entry generic_dev_entries[] = {
+ {"groups", S_IFREG | S_IRUGO, &i2o_seq_fops_groups},
+ {"phys_dev", S_IFREG | S_IRUGO, &i2o_seq_fops_phys_device},
+ {"claimed", S_IFREG | S_IRUGO, &i2o_seq_fops_claimed},
+ {"users", S_IFREG | S_IRUGO, &i2o_seq_fops_users},
+ {"priv_msgs", S_IFREG | S_IRUGO, &i2o_seq_fops_priv_msgs},
+ {"authorized_users", S_IFREG | S_IRUGO, &i2o_seq_fops_authorized_users},
+ {"dev_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_identity},
+ {"ddm_identity", S_IFREG | S_IRUGO, &i2o_seq_fops_ddm_identity},
+ {"user_info", S_IFREG | S_IRUGO, &i2o_seq_fops_uinfo},
+ {"sgl_limits", S_IFREG | S_IRUGO, &i2o_seq_fops_sgl_limits},
+ {"sensors", S_IFREG | S_IRUGO, &i2o_seq_fops_sensors},
+ {NULL, 0, NULL}
+};
+
+/*
+ * Storage unit specific entries (SCSI Periph, BS) with device names
+ */
+static i2o_proc_entry rbs_dev_entries[] = {
+ {"dev_name", S_IFREG | S_IRUGO, &i2o_seq_fops_dev_name},
+ {NULL, 0, NULL}
+};
+
+/**
+ * i2o_proc_create_entries - Creates proc dir entries
+ * @dir: proc dir entry under which the entries should be placed
+ * @i2o_pe: pointer to the entries which should be added
+ * @data: pointer to I2O controller or device
+ *
+ * Create proc dir entries for a I2O controller or I2O device.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_proc_create_entries(struct proc_dir_entry *dir,
+ i2o_proc_entry * i2o_pe, void *data)
+{
+ struct proc_dir_entry *tmp;
+
+ while (i2o_pe->name) {
+ tmp = proc_create_data(i2o_pe->name, i2o_pe->mode, dir,
+ i2o_pe->fops, data);
+ if (!tmp)
+ return -1;
+
+ i2o_pe++;
+ }
+
+ return 0;
+}
+
+/**
+ * i2o_proc_device_add - Add an I2O device to the proc dir
+ * @dir: proc dir entry to which the device should be added
+ * @dev: I2O device which should be added
+ *
+ * Add an I2O device to the proc dir entry dir and create the entries for
+ * the device depending on the class of the I2O device.
+ */
+static void i2o_proc_device_add(struct proc_dir_entry *dir,
+ struct i2o_device *dev)
+{
+ char buff[10];
+ struct proc_dir_entry *devdir;
+ i2o_proc_entry *i2o_pe = NULL;
+
+ sprintf(buff, "%03x", dev->lct_data.tid);
+
+ osm_debug("adding device /proc/i2o/%s/%s\n", dev->iop->name, buff);
+
+ devdir = proc_mkdir_data(buff, 0, dir, dev);
+ if (!devdir) {
+ osm_warn("Could not allocate procdir!\n");
+ return;
+ }
+
+ i2o_proc_create_entries(devdir, generic_dev_entries, dev);
+
+ /* Inform core that we want updates about this device's status */
+ switch (dev->lct_data.class_id) {
+ case I2O_CLASS_SCSI_PERIPHERAL:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_pe = rbs_dev_entries;
+ break;
+ default:
+ break;
+ }
+ if (i2o_pe)
+ i2o_proc_create_entries(devdir, i2o_pe, dev);
+}
+
+/**
+ * i2o_proc_iop_add - Add an I2O controller to the i2o proc tree
+ * @dir: parent proc dir entry
+ * @c: I2O controller which should be added
+ *
+ * Add the entries to the parent proc dir entry. Also each device is added
+ * to the controllers proc dir entry.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_proc_iop_add(struct proc_dir_entry *dir,
+ struct i2o_controller *c)
+{
+ struct proc_dir_entry *iopdir;
+ struct i2o_device *dev;
+
+ osm_debug("adding IOP /proc/i2o/%s\n", c->name);
+
+ iopdir = proc_mkdir_data(c->name, 0, dir, c);
+ if (!iopdir)
+ return -1;
+
+ i2o_proc_create_entries(iopdir, i2o_proc_generic_iop_entries, c);
+
+ list_for_each_entry(dev, &c->devices, list)
+ i2o_proc_device_add(iopdir, dev);
+
+ return 0;
+}
+
+/**
+ * i2o_proc_fs_create - Create the i2o proc fs.
+ *
+ * Iterate over each I2O controller and create the entries for it.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_proc_fs_create(void)
+{
+ struct i2o_controller *c;
+
+ i2o_proc_dir_root = proc_mkdir("i2o", NULL);
+ if (!i2o_proc_dir_root)
+ return -1;
+
+ list_for_each_entry(c, &i2o_controllers, list)
+ i2o_proc_iop_add(i2o_proc_dir_root, c);
+
+ return 0;
+};
+
+/**
+ * i2o_proc_fs_destroy - Cleanup the all i2o proc entries
+ *
+ * Iterate over each I2O controller and remove the entries for it.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __exit i2o_proc_fs_destroy(void)
+{
+ remove_proc_subtree("i2o", NULL);
+
+ return 0;
+};
+
+/**
+ * i2o_proc_init - Init function for procfs
+ *
+ * Registers Proc OSM and creates procfs entries.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_proc_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ rc = i2o_driver_register(&i2o_proc_driver);
+ if (rc)
+ return rc;
+
+ rc = i2o_proc_fs_create();
+ if (rc) {
+ i2o_driver_unregister(&i2o_proc_driver);
+ return rc;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_proc_exit - Exit function for procfs
+ *
+ * Unregisters Proc OSM and removes procfs entries.
+ */
+static void __exit i2o_proc_exit(void)
+{
+ i2o_driver_unregister(&i2o_proc_driver);
+ i2o_proc_fs_destroy();
+};
+
+MODULE_AUTHOR("Deepak Saxena");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_proc_init);
+module_exit(i2o_proc_exit);
diff --git a/drivers/staging/i2o/i2o_scsi.c b/drivers/staging/i2o/i2o_scsi.c
new file mode 100644
index 000000000000..1b11dcb3faea
--- /dev/null
+++ b/drivers/staging/i2o/i2o_scsi.c
@@ -0,0 +1,814 @@
+/*
+ * This program is free software; you can redistribute 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.
+ *
+ * For the avoidance of doubt the "preferred form" of this code is one which
+ * is in an open non patent encumbered format. Where cryptographic key signing
+ * forms part of the process of creating an executable the information
+ * including keys needed to generate an equivalently functional executable
+ * are deemed to be part of the source code.
+ *
+ * Complications for I2O scsi
+ *
+ * o Each (bus,lun) is a logical device in I2O. We keep a map
+ * table. We spoof failed selection for unmapped units
+ * o Request sense buffers can come back for free.
+ * o Scatter gather is a bit dynamic. We have to investigate at
+ * setup time.
+ * o Some of our resources are dynamically shared. The i2o core
+ * needs a message reservation protocol to avoid swap v net
+ * deadlocking. We need to back off queue requests.
+ *
+ * In general the firmware wants to help. Where its help isn't performance
+ * useful we just ignore the aid. Its not worth the code in truth.
+ *
+ * Fixes/additions:
+ * Steve Ralston:
+ * Scatter gather now works
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Minor fixes for 2.6.
+ *
+ * To Do:
+ * 64bit cleanups
+ * Fix the resource management problems.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/jiffies.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/delay.h>
+#include <linux/proc_fs.h>
+#include <linux/prefetch.h>
+#include <linux/pci.h>
+#include <linux/blkdev.h>
+#include "i2o.h"
+#include <linux/scatterlist.h>
+
+#include <asm/dma.h>
+#include <asm/io.h>
+#include <linux/atomic.h>
+
+#include <scsi/scsi.h>
+#include <scsi/scsi_host.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/sg.h>
+
+#define OSM_NAME "scsi-osm"
+#define OSM_VERSION "1.316"
+#define OSM_DESCRIPTION "I2O SCSI Peripheral OSM"
+
+static struct i2o_driver i2o_scsi_driver;
+
+static unsigned int i2o_scsi_max_id = 16;
+static unsigned int i2o_scsi_max_lun = 255;
+
+struct i2o_scsi_host {
+ struct Scsi_Host *scsi_host; /* pointer to the SCSI host */
+ struct i2o_controller *iop; /* pointer to the I2O controller */
+ u64 lun; /* lun's used for block devices */
+ struct i2o_device *channel[0]; /* channel->i2o_dev mapping table */
+};
+
+static struct scsi_host_template i2o_scsi_host_template;
+
+#define I2O_SCSI_CAN_QUEUE 4
+
+/* SCSI OSM class handling definition */
+static struct i2o_class_id i2o_scsi_class_id[] = {
+ {I2O_CLASS_SCSI_PERIPHERAL},
+ {I2O_CLASS_END}
+};
+
+static struct i2o_scsi_host *i2o_scsi_host_alloc(struct i2o_controller *c)
+{
+ struct i2o_scsi_host *i2o_shost;
+ struct i2o_device *i2o_dev;
+ struct Scsi_Host *scsi_host;
+ int max_channel = 0;
+ u8 type;
+ int i;
+ size_t size;
+ u16 body_size = 6;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec)
+ body_size = 8;
+#endif
+
+ list_for_each_entry(i2o_dev, &c->devices, list)
+ if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+ if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* SCSI bus */
+ max_channel++;
+ }
+
+ if (!max_channel) {
+ osm_warn("no channels found on %s\n", c->name);
+ return ERR_PTR(-EFAULT);
+ }
+
+ size = max_channel * sizeof(struct i2o_device *)
+ + sizeof(struct i2o_scsi_host);
+
+ scsi_host = scsi_host_alloc(&i2o_scsi_host_template, size);
+ if (!scsi_host) {
+ osm_warn("Could not allocate SCSI host\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ scsi_host->max_channel = max_channel - 1;
+ scsi_host->max_id = i2o_scsi_max_id;
+ scsi_host->max_lun = i2o_scsi_max_lun;
+ scsi_host->this_id = c->unit;
+ scsi_host->sg_tablesize = i2o_sg_tablesize(c, body_size);
+
+ i2o_shost = (struct i2o_scsi_host *)scsi_host->hostdata;
+ i2o_shost->scsi_host = scsi_host;
+ i2o_shost->iop = c;
+ i2o_shost->lun = 1;
+
+ i = 0;
+ list_for_each_entry(i2o_dev, &c->devices, list)
+ if (i2o_dev->lct_data.class_id == I2O_CLASS_BUS_ADAPTER) {
+ if (!i2o_parm_field_get(i2o_dev, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* only SCSI bus */
+ i2o_shost->channel[i++] = i2o_dev;
+
+ if (i >= max_channel)
+ break;
+ }
+
+ return i2o_shost;
+};
+
+/**
+ * i2o_scsi_get_host - Get an I2O SCSI host
+ * @c: I2O controller to for which to get the SCSI host
+ *
+ * If the I2O controller already exists as SCSI host, the SCSI host
+ * is returned, otherwise the I2O controller is added to the SCSI
+ * core.
+ *
+ * Returns pointer to the I2O SCSI host on success or NULL on failure.
+ */
+static struct i2o_scsi_host *i2o_scsi_get_host(struct i2o_controller *c)
+{
+ return c->driver_data[i2o_scsi_driver.context];
+};
+
+/**
+ * i2o_scsi_remove - Remove I2O device from SCSI core
+ * @dev: device which should be removed
+ *
+ * Removes the I2O device from the SCSI core again.
+ *
+ * Returns 0 on success.
+ */
+static int i2o_scsi_remove(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+ struct i2o_controller *c = i2o_dev->iop;
+ struct i2o_scsi_host *i2o_shost;
+ struct scsi_device *scsi_dev;
+
+ osm_info("device removed (TID: %03x)\n", i2o_dev->lct_data.tid);
+
+ i2o_shost = i2o_scsi_get_host(c);
+
+ shost_for_each_device(scsi_dev, i2o_shost->scsi_host)
+ if (scsi_dev->hostdata == i2o_dev) {
+ sysfs_remove_link(&i2o_dev->device.kobj, "scsi");
+ scsi_remove_device(scsi_dev);
+ scsi_device_put(scsi_dev);
+ break;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_scsi_probe - verify if dev is a I2O SCSI device and install it
+ * @dev: device to verify if it is a I2O SCSI device
+ *
+ * Retrieve channel, id and lun for I2O device. If everything goes well
+ * register the I2O device as SCSI device on the I2O SCSI controller.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_scsi_probe(struct device *dev)
+{
+ struct i2o_device *i2o_dev = to_i2o_device(dev);
+ struct i2o_controller *c = i2o_dev->iop;
+ struct i2o_scsi_host *i2o_shost;
+ struct Scsi_Host *scsi_host;
+ struct i2o_device *parent;
+ struct scsi_device *scsi_dev;
+ u32 id = -1;
+ u64 lun = -1;
+ int channel = -1;
+ int i, rc;
+
+ i2o_shost = i2o_scsi_get_host(c);
+ if (!i2o_shost)
+ return -EFAULT;
+
+ scsi_host = i2o_shost->scsi_host;
+
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ case I2O_CLASS_EXECUTIVE:
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u8 type;
+ struct i2o_device *d = i2o_shost->channel[0];
+
+ if (!i2o_parm_field_get(d, 0x0000, 0, &type, 1)
+ && (type == 0x01)) /* SCSI bus */
+ if (!i2o_parm_field_get(d, 0x0200, 4, &id, 4)) {
+ channel = 0;
+ if (i2o_dev->lct_data.class_id ==
+ I2O_CLASS_RANDOM_BLOCK_STORAGE)
+ lun =
+ cpu_to_le64(i2o_shost->
+ lun++);
+ else
+ lun = 0;
+ }
+ }
+#endif
+ break;
+
+ case I2O_CLASS_SCSI_PERIPHERAL:
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 3, &id, 4))
+ return -EFAULT;
+
+ if (i2o_parm_field_get(i2o_dev, 0x0000, 4, &lun, 8))
+ return -EFAULT;
+
+ parent = i2o_iop_find_device(c, i2o_dev->lct_data.parent_tid);
+ if (!parent) {
+ osm_warn("can not find parent of device %03x\n",
+ i2o_dev->lct_data.tid);
+ return -EFAULT;
+ }
+
+ for (i = 0; i <= i2o_shost->scsi_host->max_channel; i++)
+ if (i2o_shost->channel[i] == parent)
+ channel = i;
+ break;
+
+ default:
+ return -EFAULT;
+ }
+
+ if (channel == -1) {
+ osm_warn("can not find channel of device %03x\n",
+ i2o_dev->lct_data.tid);
+ return -EFAULT;
+ }
+
+ if (le32_to_cpu(id) >= scsi_host->max_id) {
+ osm_warn("SCSI device id (%d) >= max_id of I2O host (%d)",
+ le32_to_cpu(id), scsi_host->max_id);
+ return -EFAULT;
+ }
+
+ if (le64_to_cpu(lun) >= scsi_host->max_lun) {
+ osm_warn("SCSI device lun (%llu) >= max_lun of I2O host (%llu)",
+ le64_to_cpu(lun), scsi_host->max_lun);
+ return -EFAULT;
+ }
+
+ scsi_dev =
+ __scsi_add_device(i2o_shost->scsi_host, channel, le32_to_cpu(id),
+ le64_to_cpu(lun), i2o_dev);
+
+ if (IS_ERR(scsi_dev)) {
+ osm_warn("can not add SCSI device %03x\n",
+ i2o_dev->lct_data.tid);
+ return PTR_ERR(scsi_dev);
+ }
+
+ rc = sysfs_create_link(&i2o_dev->device.kobj,
+ &scsi_dev->sdev_gendev.kobj, "scsi");
+ if (rc)
+ goto err;
+
+ osm_info("device added (TID: %03x) channel: %d, id: %d, lun: %llu\n",
+ i2o_dev->lct_data.tid, channel, le32_to_cpu(id),
+ le64_to_cpu(lun));
+
+ return 0;
+
+err:
+ scsi_remove_device(scsi_dev);
+ return rc;
+};
+
+static const char *i2o_scsi_info(struct Scsi_Host *SChost)
+{
+ struct i2o_scsi_host *hostdata;
+ hostdata = (struct i2o_scsi_host *)SChost->hostdata;
+ return hostdata->iop->name;
+}
+
+/**
+ * i2o_scsi_reply - SCSI OSM message reply handler
+ * @c: controller issuing the reply
+ * @m: message id for flushing
+ * @msg: the message from the controller
+ *
+ * Process reply messages (interrupts in normal scsi controller think).
+ * We can get a variety of messages to process. The normal path is
+ * scsi command completions. We must also deal with IOP failures,
+ * the reply to a bus reset and the reply to a LUN query.
+ *
+ * Returns 0 on success and if the reply should not be flushed or > 0
+ * on success and if the reply should be flushed. Returns negative error
+ * code on failure and if the reply should be flushed.
+ */
+static int i2o_scsi_reply(struct i2o_controller *c, u32 m,
+ struct i2o_message *msg)
+{
+ struct scsi_cmnd *cmd;
+ u32 error;
+ struct device *dev;
+
+ cmd = i2o_cntxt_list_get(c, le32_to_cpu(msg->u.s.tcntxt));
+ if (unlikely(!cmd)) {
+ osm_err("NULL reply received!\n");
+ return -1;
+ }
+
+ /*
+ * Low byte is device status, next is adapter status,
+ * (then one byte reserved), then request status.
+ */
+ error = le32_to_cpu(msg->body[0]);
+
+ osm_debug("Completed %0x%p\n", cmd);
+
+ cmd->result = error & 0xff;
+ /*
+ * if DeviceStatus is not SCSI_SUCCESS copy over the sense data and let
+ * the SCSI layer handle the error
+ */
+ if (cmd->result)
+ memcpy(cmd->sense_buffer, &msg->body[3],
+ min(SCSI_SENSE_BUFFERSIZE, 40));
+
+ /* only output error code if AdapterStatus is not HBA_SUCCESS */
+ if ((error >> 8) & 0xff)
+ osm_err("SCSI error %08x\n", error);
+
+ dev = &c->pdev->dev;
+
+ scsi_dma_unmap(cmd);
+
+ cmd->scsi_done(cmd);
+
+ return 1;
+};
+
+/**
+ * i2o_scsi_notify_device_add - Retrieve notifications of added devices
+ * @i2o_dev: the I2O device which was added
+ *
+ * If a I2O device is added we catch the notification, because I2O classes
+ * other than SCSI peripheral will not be received through
+ * i2o_scsi_probe().
+ */
+static void i2o_scsi_notify_device_add(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_probe(&i2o_dev->device);
+ break;
+
+ default:
+ break;
+ }
+};
+
+/**
+ * i2o_scsi_notify_device_remove - Retrieve notifications of removed devices
+ * @i2o_dev: the I2O device which was removed
+ *
+ * If a I2O device is removed, we catch the notification to remove the
+ * corresponding SCSI device.
+ */
+static void i2o_scsi_notify_device_remove(struct i2o_device *i2o_dev)
+{
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ i2o_scsi_remove(&i2o_dev->device);
+ break;
+
+ default:
+ break;
+ }
+};
+
+/**
+ * i2o_scsi_notify_controller_add - Retrieve notifications of added controllers
+ * @c: the controller which was added
+ *
+ * If a I2O controller is added, we catch the notification to add a
+ * corresponding Scsi_Host.
+ */
+static void i2o_scsi_notify_controller_add(struct i2o_controller *c)
+{
+ struct i2o_scsi_host *i2o_shost;
+ int rc;
+
+ i2o_shost = i2o_scsi_host_alloc(c);
+ if (IS_ERR(i2o_shost)) {
+ osm_err("Could not initialize SCSI host\n");
+ return;
+ }
+
+ rc = scsi_add_host(i2o_shost->scsi_host, &c->device);
+ if (rc) {
+ osm_err("Could not add SCSI host\n");
+ scsi_host_put(i2o_shost->scsi_host);
+ return;
+ }
+
+ c->driver_data[i2o_scsi_driver.context] = i2o_shost;
+
+ osm_debug("new I2O SCSI host added\n");
+};
+
+/**
+ * i2o_scsi_notify_controller_remove - Retrieve notifications of removed controllers
+ * @c: the controller which was removed
+ *
+ * If a I2O controller is removed, we catch the notification to remove the
+ * corresponding Scsi_Host.
+ */
+static void i2o_scsi_notify_controller_remove(struct i2o_controller *c)
+{
+ struct i2o_scsi_host *i2o_shost;
+ i2o_shost = i2o_scsi_get_host(c);
+ if (!i2o_shost)
+ return;
+
+ c->driver_data[i2o_scsi_driver.context] = NULL;
+
+ scsi_remove_host(i2o_shost->scsi_host);
+ scsi_host_put(i2o_shost->scsi_host);
+ osm_debug("I2O SCSI host removed\n");
+};
+
+/* SCSI OSM driver struct */
+static struct i2o_driver i2o_scsi_driver = {
+ .name = OSM_NAME,
+ .reply = i2o_scsi_reply,
+ .classes = i2o_scsi_class_id,
+ .notify_device_add = i2o_scsi_notify_device_add,
+ .notify_device_remove = i2o_scsi_notify_device_remove,
+ .notify_controller_add = i2o_scsi_notify_controller_add,
+ .notify_controller_remove = i2o_scsi_notify_controller_remove,
+ .driver = {
+ .probe = i2o_scsi_probe,
+ .remove = i2o_scsi_remove,
+ },
+};
+
+/**
+ * i2o_scsi_queuecommand - queue a SCSI command
+ * @SCpnt: scsi command pointer
+ * @done: callback for completion
+ *
+ * Issue a scsi command asynchronously. Return 0 on success or 1 if
+ * we hit an error (normally message queue congestion). The only
+ * minor complication here is that I2O deals with the device addressing
+ * so we have to map the bus/dev/lun back to an I2O handle as well
+ * as faking absent devices ourself.
+ *
+ * Locks: takes the controller lock on error path only
+ */
+
+static int i2o_scsi_queuecommand_lck(struct scsi_cmnd *SCpnt,
+ void (*done) (struct scsi_cmnd *))
+{
+ struct i2o_controller *c;
+ struct i2o_device *i2o_dev;
+ int tid;
+ struct i2o_message *msg;
+ /*
+ * ENABLE_DISCONNECT
+ * SIMPLE_TAG
+ * RETURN_SENSE_DATA_IN_REPLY_MESSAGE_FRAME
+ */
+ u32 scsi_flags = 0x20a00000;
+ u32 sgl_offset;
+ u32 *mptr;
+ u32 cmd = I2O_CMD_SCSI_EXEC << 24;
+ int rc = 0;
+
+ /*
+ * Do the incoming paperwork
+ */
+ i2o_dev = SCpnt->device->hostdata;
+
+ SCpnt->scsi_done = done;
+
+ if (unlikely(!i2o_dev)) {
+ osm_warn("no I2O device in request\n");
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ goto exit;
+ }
+ c = i2o_dev->iop;
+ tid = i2o_dev->lct_data.tid;
+
+ osm_debug("qcmd: Tid = %03x\n", tid);
+ osm_debug("Real scsi messages.\n");
+
+ /*
+ * Put together a scsi execscb message
+ */
+ switch (SCpnt->sc_data_direction) {
+ case PCI_DMA_NONE:
+ /* DATA NO XFER */
+ sgl_offset = SGL_OFFSET_0;
+ break;
+
+ case PCI_DMA_TODEVICE:
+ /* DATA OUT (iop-->dev) */
+ scsi_flags |= 0x80000000;
+ sgl_offset = SGL_OFFSET_10;
+ break;
+
+ case PCI_DMA_FROMDEVICE:
+ /* DATA IN (iop<--dev) */
+ scsi_flags |= 0x40000000;
+ sgl_offset = SGL_OFFSET_10;
+ break;
+
+ default:
+ /* Unknown - kill the command */
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ goto exit;
+ }
+
+ /*
+ * Obtain an I2O message. If there are none free then
+ * throw it back to the scsi layer
+ */
+
+ msg = i2o_msg_get(c);
+ if (IS_ERR(msg)) {
+ rc = SCSI_MLQUEUE_HOST_BUSY;
+ goto exit;
+ }
+
+ mptr = &msg->body[0];
+
+#if 0 /* this code can't work */
+#ifdef CONFIG_I2O_EXT_ADAPTEC
+ if (c->adaptec) {
+ u32 adpt_flags = 0;
+
+ if (SCpnt->sc_request && SCpnt->sc_request->upper_private_data) {
+ i2o_sg_io_hdr_t __user *usr_ptr =
+ ((Sg_request *) (SCpnt->sc_request->
+ upper_private_data))->header.
+ usr_ptr;
+
+ if (usr_ptr)
+ get_user(adpt_flags, &usr_ptr->flags);
+ }
+
+ switch (i2o_dev->lct_data.class_id) {
+ case I2O_CLASS_EXECUTIVE:
+ case I2O_CLASS_RANDOM_BLOCK_STORAGE:
+ /* interpret flag has to be set for executive */
+ adpt_flags ^= I2O_DPT_SG_FLAG_INTERPRET;
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * for Adaptec controllers we use the PRIVATE command, because
+ * the normal SCSI EXEC doesn't support all SCSI commands on
+ * all controllers (for example READ CAPACITY).
+ */
+ if (sgl_offset == SGL_OFFSET_10)
+ sgl_offset = SGL_OFFSET_12;
+ cmd = I2O_CMD_PRIVATE << 24;
+ *mptr++ = cpu_to_le32(I2O_VENDOR_DPT << 16 | I2O_CMD_SCSI_EXEC);
+ *mptr++ = cpu_to_le32(adpt_flags | tid);
+ }
+#endif
+#endif
+
+ msg->u.head[1] = cpu_to_le32(cmd | HOST_TID << 12 | tid);
+ msg->u.s.icntxt = cpu_to_le32(i2o_scsi_driver.context);
+
+ /* We want the SCSI control block back */
+ msg->u.s.tcntxt = cpu_to_le32(i2o_cntxt_list_add(c, SCpnt));
+
+ /* LSI_920_PCI_QUIRK
+ *
+ * Intermittant observations of msg frame word data corruption
+ * observed on msg[4] after:
+ * WRITE, READ-MODIFY-WRITE
+ * operations. 19990606 -sralston
+ *
+ * (Hence we build this word via tag. Its good practice anyway
+ * we don't want fetches over PCI needlessly)
+ */
+
+ /* Attach tags to the devices */
+ /* FIXME: implement
+ if(SCpnt->device->tagged_supported) {
+ if(SCpnt->tag == HEAD_OF_QUEUE_TAG)
+ scsi_flags |= 0x01000000;
+ else if(SCpnt->tag == ORDERED_QUEUE_TAG)
+ scsi_flags |= 0x01800000;
+ }
+ */
+
+ *mptr++ = cpu_to_le32(scsi_flags | SCpnt->cmd_len);
+
+ /* Write SCSI command into the message - always 16 byte block */
+ memcpy(mptr, SCpnt->cmnd, 16);
+ mptr += 4;
+
+ if (sgl_offset != SGL_OFFSET_0) {
+ /* write size of data addressed by SGL */
+ *mptr++ = cpu_to_le32(scsi_bufflen(SCpnt));
+
+ /* Now fill in the SGList and command */
+
+ if (scsi_sg_count(SCpnt)) {
+ if (!i2o_dma_map_sg(c, scsi_sglist(SCpnt),
+ scsi_sg_count(SCpnt),
+ SCpnt->sc_data_direction, &mptr))
+ goto nomem;
+ }
+ }
+
+ /* Stick the headers on */
+ msg->u.head[0] =
+ cpu_to_le32(I2O_MESSAGE_SIZE(mptr - &msg->u.head[0]) | sgl_offset);
+
+ /* Queue the message */
+ i2o_msg_post(c, msg);
+
+ osm_debug("Issued %0x%p\n", SCpnt);
+
+ return 0;
+
+ nomem:
+ rc = -ENOMEM;
+ i2o_msg_nop(c, msg);
+
+ exit:
+ return rc;
+}
+
+static DEF_SCSI_QCMD(i2o_scsi_queuecommand)
+
+/**
+ * i2o_scsi_abort - abort a running command
+ * @SCpnt: command to abort
+ *
+ * Ask the I2O controller to abort a command. This is an asynchrnous
+ * process and our callback handler will see the command complete with an
+ * aborted message if it succeeds.
+ *
+ * Returns 0 if the command is successfully aborted or negative error code
+ * on failure.
+ */
+static int i2o_scsi_abort(struct scsi_cmnd *SCpnt)
+{
+ struct i2o_device *i2o_dev;
+ struct i2o_controller *c;
+ struct i2o_message *msg;
+ int tid;
+ int status = FAILED;
+
+ osm_warn("Aborting command block.\n");
+
+ i2o_dev = SCpnt->device->hostdata;
+ c = i2o_dev->iop;
+ tid = i2o_dev->lct_data.tid;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_SCSI_ABORT << 24 | HOST_TID << 12 | tid);
+ msg->body[0] = cpu_to_le32(i2o_cntxt_list_get_ptr(c, SCpnt));
+
+ if (!i2o_msg_post_wait(c, msg, I2O_TIMEOUT_SCSI_SCB_ABORT))
+ status = SUCCESS;
+
+ return status;
+}
+
+/**
+ * i2o_scsi_bios_param - Invent disk geometry
+ * @sdev: scsi device
+ * @dev: block layer device
+ * @capacity: size in sectors
+ * @ip: geometry array
+ *
+ * This is anyone's guess quite frankly. We use the same rules everyone
+ * else appears to and hope. It seems to work.
+ */
+
+static int i2o_scsi_bios_param(struct scsi_device *sdev,
+ struct block_device *dev, sector_t capacity,
+ int *ip)
+{
+ int size;
+
+ size = capacity;
+ ip[0] = 64; /* heads */
+ ip[1] = 32; /* sectors */
+ if ((ip[2] = size >> 11) > 1024) { /* cylinders, test for big disk */
+ ip[0] = 255; /* heads */
+ ip[1] = 63; /* sectors */
+ ip[2] = size / (255 * 63); /* cylinders */
+ }
+ return 0;
+}
+
+static struct scsi_host_template i2o_scsi_host_template = {
+ .proc_name = OSM_NAME,
+ .name = OSM_DESCRIPTION,
+ .info = i2o_scsi_info,
+ .queuecommand = i2o_scsi_queuecommand,
+ .eh_abort_handler = i2o_scsi_abort,
+ .bios_param = i2o_scsi_bios_param,
+ .can_queue = I2O_SCSI_CAN_QUEUE,
+ .sg_tablesize = 8,
+ .cmd_per_lun = 6,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+/**
+ * i2o_scsi_init - SCSI OSM initialization function
+ *
+ * Register SCSI OSM into I2O core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_scsi_init(void)
+{
+ int rc;
+
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ /* Register SCSI OSM into I2O core */
+ rc = i2o_driver_register(&i2o_scsi_driver);
+ if (rc) {
+ osm_err("Could not register SCSI driver\n");
+ return rc;
+ }
+
+ return 0;
+};
+
+/**
+ * i2o_scsi_exit - SCSI OSM exit function
+ *
+ * Unregisters SCSI OSM from I2O core.
+ */
+static void __exit i2o_scsi_exit(void)
+{
+ /* Unregister I2O SCSI OSM from I2O core */
+ i2o_driver_unregister(&i2o_scsi_driver);
+};
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+module_init(i2o_scsi_init);
+module_exit(i2o_scsi_exit);
diff --git a/drivers/staging/i2o/iop.c b/drivers/staging/i2o/iop.c
new file mode 100644
index 000000000000..52334fc8b547
--- /dev/null
+++ b/drivers/staging/i2o/iop.c
@@ -0,0 +1,1247 @@
+/*
+ * Functions to handle I2O controllers and I2O message handling
+ *
+ * Copyright (C) 1999-2002 Red Hat Software
+ *
+ * Written by Alan Cox, Building Number Three 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.
+ *
+ * A lot of the I2O message side code from this is taken from the
+ * Red Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ * Fixes/additions:
+ * Philipp Rumpf
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Deepak Saxena <deepak@plexity.net>
+ * Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ * Ported to Linux 2.5.
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Minor fixes for 2.6.
+ */
+
+#include <linux/module.h>
+#include "i2o.h"
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include "core.h"
+
+#define OSM_NAME "i2o"
+#define OSM_VERSION "1.325"
+#define OSM_DESCRIPTION "I2O subsystem"
+
+/* global I2O controller list */
+LIST_HEAD(i2o_controllers);
+
+/*
+ * global I2O System Table. Contains information about all the IOPs in the
+ * system. Used to inform IOPs about each others existence.
+ */
+static struct i2o_dma i2o_systab;
+
+static int i2o_hrt_get(struct i2o_controller *c);
+
+/**
+ * i2o_msg_get_wait - obtain an I2O message from the IOP
+ * @c: I2O controller
+ * @wait: how long to wait until timeout
+ *
+ * This function waits up to wait seconds for a message slot to be
+ * available.
+ *
+ * On a success the message is returned and the pointer to the message is
+ * set in msg. The returned message is the physical page frame offset
+ * address from the read port (see the i2o spec). If no message is
+ * available returns I2O_QUEUE_EMPTY and msg is leaved untouched.
+ */
+struct i2o_message *i2o_msg_get_wait(struct i2o_controller *c, int wait)
+{
+ unsigned long timeout = jiffies + wait * HZ;
+ struct i2o_message *msg;
+
+ while (IS_ERR(msg = i2o_msg_get(c))) {
+ if (time_after(jiffies, timeout)) {
+ osm_debug("%s: Timeout waiting for message frame.\n",
+ c->name);
+ return ERR_PTR(-ETIMEDOUT);
+ }
+ schedule_timeout_uninterruptible(1);
+ }
+
+ return msg;
+};
+
+#if BITS_PER_LONG == 64
+/**
+ * i2o_cntxt_list_add - Append a pointer to context list and return a id
+ * @c: controller to which the context list belong
+ * @ptr: pointer to add to the context list
+ *
+ * Because the context field in I2O is only 32-bit large, on 64-bit the
+ * pointer is to large to fit in the context field. The i2o_cntxt_list
+ * functions therefore map pointers to context fields.
+ *
+ * Returns context id > 0 on success or 0 on failure.
+ */
+u32 i2o_cntxt_list_add(struct i2o_controller * c, void *ptr)
+{
+ struct i2o_context_list_element *entry;
+ unsigned long flags;
+
+ if (!ptr)
+ osm_err("%s: couldn't add NULL pointer to context list!\n",
+ c->name);
+
+ entry = kmalloc(sizeof(*entry), GFP_ATOMIC);
+ if (!entry) {
+ osm_err("%s: Could not allocate memory for context list element"
+ "\n", c->name);
+ return 0;
+ }
+
+ entry->ptr = ptr;
+ entry->timestamp = jiffies;
+ INIT_LIST_HEAD(&entry->list);
+
+ spin_lock_irqsave(&c->context_list_lock, flags);
+
+ if (unlikely(atomic_inc_and_test(&c->context_list_counter)))
+ atomic_inc(&c->context_list_counter);
+
+ entry->context = atomic_read(&c->context_list_counter);
+
+ list_add(&entry->list, &c->context_list);
+
+ spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+ osm_debug("%s: Add context to list %p -> %d\n", c->name, ptr, context);
+
+ return entry->context;
+};
+
+/**
+ * i2o_cntxt_list_remove - Remove a pointer from the context list
+ * @c: controller to which the context list belong
+ * @ptr: pointer which should be removed from the context list
+ *
+ * Removes a previously added pointer from the context list and returns
+ * the matching context id.
+ *
+ * Returns context id on success or 0 on failure.
+ */
+u32 i2o_cntxt_list_remove(struct i2o_controller * c, void *ptr)
+{
+ struct i2o_context_list_element *entry;
+ u32 context = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->context_list_lock, flags);
+ list_for_each_entry(entry, &c->context_list, list)
+ if (entry->ptr == ptr) {
+ list_del(&entry->list);
+ context = entry->context;
+ kfree(entry);
+ break;
+ }
+ spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+ if (!context)
+ osm_warn("%s: Could not remove nonexistent ptr %p\n", c->name,
+ ptr);
+
+ osm_debug("%s: remove ptr from context list %d -> %p\n", c->name,
+ context, ptr);
+
+ return context;
+};
+
+/**
+ * i2o_cntxt_list_get - Get a pointer from the context list and remove it
+ * @c: controller to which the context list belong
+ * @context: context id to which the pointer belong
+ *
+ * Returns pointer to the matching context id on success or NULL on
+ * failure.
+ */
+void *i2o_cntxt_list_get(struct i2o_controller *c, u32 context)
+{
+ struct i2o_context_list_element *entry;
+ unsigned long flags;
+ void *ptr = NULL;
+
+ spin_lock_irqsave(&c->context_list_lock, flags);
+ list_for_each_entry(entry, &c->context_list, list)
+ if (entry->context == context) {
+ list_del(&entry->list);
+ ptr = entry->ptr;
+ kfree(entry);
+ break;
+ }
+ spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+ if (!ptr)
+ osm_warn("%s: context id %d not found\n", c->name, context);
+
+ osm_debug("%s: get ptr from context list %d -> %p\n", c->name, context,
+ ptr);
+
+ return ptr;
+};
+
+/**
+ * i2o_cntxt_list_get_ptr - Get a context id from the context list
+ * @c: controller to which the context list belong
+ * @ptr: pointer to which the context id should be fetched
+ *
+ * Returns context id which matches to the pointer on success or 0 on
+ * failure.
+ */
+u32 i2o_cntxt_list_get_ptr(struct i2o_controller * c, void *ptr)
+{
+ struct i2o_context_list_element *entry;
+ u32 context = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&c->context_list_lock, flags);
+ list_for_each_entry(entry, &c->context_list, list)
+ if (entry->ptr == ptr) {
+ context = entry->context;
+ break;
+ }
+ spin_unlock_irqrestore(&c->context_list_lock, flags);
+
+ if (!context)
+ osm_warn("%s: Could not find nonexistent ptr %p\n", c->name,
+ ptr);
+
+ osm_debug("%s: get context id from context list %p -> %d\n", c->name,
+ ptr, context);
+
+ return context;
+};
+#endif
+
+/**
+ * i2o_iop_find - Find an I2O controller by id
+ * @unit: unit number of the I2O controller to search for
+ *
+ * Lookup the I2O controller on the controller list.
+ *
+ * Returns pointer to the I2O controller on success or NULL if not found.
+ */
+struct i2o_controller *i2o_find_iop(int unit)
+{
+ struct i2o_controller *c;
+
+ list_for_each_entry(c, &i2o_controllers, list) {
+ if (c->unit == unit)
+ return c;
+ }
+
+ return NULL;
+};
+
+/**
+ * i2o_iop_find_device - Find a I2O device on an I2O controller
+ * @c: I2O controller where the I2O device hangs on
+ * @tid: TID of the I2O device to search for
+ *
+ * Searches the devices of the I2O controller for a device with TID tid and
+ * returns it.
+ *
+ * Returns a pointer to the I2O device if found, otherwise NULL.
+ */
+struct i2o_device *i2o_iop_find_device(struct i2o_controller *c, u16 tid)
+{
+ struct i2o_device *dev;
+
+ list_for_each_entry(dev, &c->devices, list)
+ if (dev->lct_data.tid == tid)
+ return dev;
+
+ return NULL;
+};
+
+/**
+ * i2o_quiesce_controller - quiesce controller
+ * @c: controller
+ *
+ * Quiesce an IOP. Causes IOP to make external operation quiescent
+ * (i2o 'READY' state). Internal operation of the IOP continues normally.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_quiesce(struct i2o_controller *c)
+{
+ struct i2o_message *msg;
+ i2o_status_block *sb = c->status_block.virt;
+ int rc;
+
+ i2o_status_get(c);
+
+ /* SysQuiesce discarded if IOP not in READY or OPERATIONAL state */
+ if ((sb->iop_state != ADAPTER_STATE_READY) &&
+ (sb->iop_state != ADAPTER_STATE_OPERATIONAL))
+ return 0;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_SYS_QUIESCE << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+
+ /* Long timeout needed for quiesce if lots of devices */
+ if ((rc = i2o_msg_post_wait(c, msg, 240)))
+ osm_info("%s: Unable to quiesce (status=%#x).\n", c->name, -rc);
+ else
+ osm_debug("%s: Quiesced.\n", c->name);
+
+ i2o_status_get(c); // Entered READY state
+
+ return rc;
+};
+
+/**
+ * i2o_iop_enable - move controller from ready to OPERATIONAL
+ * @c: I2O controller
+ *
+ * Enable IOP. This allows the IOP to resume external operations and
+ * reverses the effect of a quiesce. Returns zero or an error code if
+ * an error occurs.
+ */
+static int i2o_iop_enable(struct i2o_controller *c)
+{
+ struct i2o_message *msg;
+ i2o_status_block *sb = c->status_block.virt;
+ int rc;
+
+ i2o_status_get(c);
+
+ /* Enable only allowed on READY state */
+ if (sb->iop_state != ADAPTER_STATE_READY)
+ return -EINVAL;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_SYS_ENABLE << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+
+ /* How long of a timeout do we need? */
+ if ((rc = i2o_msg_post_wait(c, msg, 240)))
+ osm_err("%s: Could not enable (status=%#x).\n", c->name, -rc);
+ else
+ osm_debug("%s: Enabled.\n", c->name);
+
+ i2o_status_get(c); // entered OPERATIONAL state
+
+ return rc;
+};
+
+/**
+ * i2o_iop_quiesce_all - Quiesce all I2O controllers on the system
+ *
+ * Quiesce all I2O controllers which are connected to the system.
+ */
+static inline void i2o_iop_quiesce_all(void)
+{
+ struct i2o_controller *c, *tmp;
+
+ list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
+ if (!c->no_quiesce)
+ i2o_iop_quiesce(c);
+ }
+};
+
+/**
+ * i2o_iop_enable_all - Enables all controllers on the system
+ *
+ * Enables all I2O controllers which are connected to the system.
+ */
+static inline void i2o_iop_enable_all(void)
+{
+ struct i2o_controller *c, *tmp;
+
+ list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
+ i2o_iop_enable(c);
+};
+
+/**
+ * i2o_clear_controller - Bring I2O controller into HOLD state
+ * @c: controller
+ *
+ * Clear an IOP to HOLD state, ie. terminate external operations, clear all
+ * input queues and prepare for a system restart. IOP's internal operation
+ * continues normally and the outbound queue is alive. The IOP is not
+ * expected to rebuild its LCT.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_clear(struct i2o_controller *c)
+{
+ struct i2o_message *msg;
+ int rc;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ /* Quiesce all IOPs first */
+ i2o_iop_quiesce_all();
+
+ msg->u.head[0] = cpu_to_le32(FOUR_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_ADAPTER_CLEAR << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+
+ if ((rc = i2o_msg_post_wait(c, msg, 30)))
+ osm_info("%s: Unable to clear (status=%#x).\n", c->name, -rc);
+ else
+ osm_debug("%s: Cleared.\n", c->name);
+
+ /* Enable all IOPs */
+ i2o_iop_enable_all();
+
+ return rc;
+}
+
+/**
+ * i2o_iop_init_outbound_queue - setup the outbound message queue
+ * @c: I2O controller
+ *
+ * Clear and (re)initialize IOP's outbound queue and post the message
+ * frames to the IOP.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_init_outbound_queue(struct i2o_controller *c)
+{
+ u32 m;
+ volatile u8 *status = c->status.virt;
+ struct i2o_message *msg;
+ ulong timeout;
+ int i;
+
+ osm_debug("%s: Initializing Outbound Queue...\n", c->name);
+
+ memset(c->status.virt, 0, 4);
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_6);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_OUTBOUND_INIT << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+ msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+ msg->body[0] = cpu_to_le32(PAGE_SIZE);
+ /* Outbound msg frame size in words and Initcode */
+ msg->body[1] = cpu_to_le32(I2O_OUTBOUND_MSG_FRAME_SIZE << 16 | 0x80);
+ msg->body[2] = cpu_to_le32(0xd0000004);
+ msg->body[3] = cpu_to_le32(i2o_dma_low(c->status.phys));
+ msg->body[4] = cpu_to_le32(i2o_dma_high(c->status.phys));
+
+ i2o_msg_post(c, msg);
+
+ timeout = jiffies + I2O_TIMEOUT_INIT_OUTBOUND_QUEUE * HZ;
+ while (*status <= I2O_CMD_IN_PROGRESS) {
+ if (time_after(jiffies, timeout)) {
+ osm_warn("%s: Timeout Initializing\n", c->name);
+ return -ETIMEDOUT;
+ }
+ schedule_timeout_uninterruptible(1);
+ }
+
+ m = c->out_queue.phys;
+
+ /* Post frames */
+ for (i = 0; i < I2O_MAX_OUTBOUND_MSG_FRAMES; i++) {
+ i2o_flush_reply(c, m);
+ udelay(1); /* Promise */
+ m += I2O_OUTBOUND_MSG_FRAME_SIZE * sizeof(u32);
+ }
+
+ return 0;
+}
+
+/**
+ * i2o_iop_reset - reset an I2O controller
+ * @c: controller to reset
+ *
+ * Reset the IOP into INIT state and wait until IOP gets into RESET state.
+ * Terminate all external operations, clear IOP's inbound and outbound
+ * queues, terminate all DDMs, and reload the IOP's operating environment
+ * and all local DDMs. The IOP rebuilds its LCT.
+ */
+static int i2o_iop_reset(struct i2o_controller *c)
+{
+ volatile u8 *status = c->status.virt;
+ struct i2o_message *msg;
+ unsigned long timeout;
+ i2o_status_block *sb = c->status_block.virt;
+ int rc = 0;
+
+ osm_debug("%s: Resetting controller\n", c->name);
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ memset(c->status_block.virt, 0, 8);
+
+ /* Quiesce all IOPs first */
+ i2o_iop_quiesce_all();
+
+ msg->u.head[0] = cpu_to_le32(EIGHT_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_ADAPTER_RESET << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+ msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+ msg->body[0] = cpu_to_le32(0x00000000);
+ msg->body[1] = cpu_to_le32(0x00000000);
+ msg->body[2] = cpu_to_le32(i2o_dma_low(c->status.phys));
+ msg->body[3] = cpu_to_le32(i2o_dma_high(c->status.phys));
+
+ i2o_msg_post(c, msg);
+
+ /* Wait for a reply */
+ timeout = jiffies + I2O_TIMEOUT_RESET * HZ;
+ while (!*status) {
+ if (time_after(jiffies, timeout))
+ break;
+
+ schedule_timeout_uninterruptible(1);
+ }
+
+ switch (*status) {
+ case I2O_CMD_REJECTED:
+ osm_warn("%s: IOP reset rejected\n", c->name);
+ rc = -EPERM;
+ break;
+
+ case I2O_CMD_IN_PROGRESS:
+ /*
+ * Once the reset is sent, the IOP goes into the INIT state
+ * which is indeterminate. We need to wait until the IOP has
+ * rebooted before we can let the system talk to it. We read
+ * the inbound Free_List until a message is available. If we
+ * can't read one in the given amount of time, we assume the
+ * IOP could not reboot properly.
+ */
+ osm_debug("%s: Reset in progress, waiting for reboot...\n",
+ c->name);
+
+ while (IS_ERR(msg = i2o_msg_get_wait(c, I2O_TIMEOUT_RESET))) {
+ if (time_after(jiffies, timeout)) {
+ osm_err("%s: IOP reset timeout.\n", c->name);
+ rc = PTR_ERR(msg);
+ goto exit;
+ }
+ schedule_timeout_uninterruptible(1);
+ }
+ i2o_msg_nop(c, msg);
+
+ /* from here all quiesce commands are safe */
+ c->no_quiesce = 0;
+
+ /* verify if controller is in state RESET */
+ i2o_status_get(c);
+
+ if (!c->promise && (sb->iop_state != ADAPTER_STATE_RESET))
+ osm_warn("%s: reset completed, but adapter not in RESET"
+ " state.\n", c->name);
+ else
+ osm_debug("%s: reset completed.\n", c->name);
+
+ break;
+
+ default:
+ osm_err("%s: IOP reset timeout.\n", c->name);
+ rc = -ETIMEDOUT;
+ break;
+ }
+
+ exit:
+ /* Enable all IOPs */
+ i2o_iop_enable_all();
+
+ return rc;
+};
+
+/**
+ * i2o_iop_activate - Bring controller up to HOLD
+ * @c: controller
+ *
+ * This function brings an I2O controller into HOLD state. The adapter
+ * is reset if necessary and then the queues and resource table are read.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_activate(struct i2o_controller *c)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ int rc;
+ int state;
+
+ /* In INIT state, Wait Inbound Q to initialize (in i2o_status_get) */
+ /* In READY state, Get status */
+
+ rc = i2o_status_get(c);
+ if (rc) {
+ osm_info("%s: Unable to obtain status, attempting a reset.\n",
+ c->name);
+ rc = i2o_iop_reset(c);
+ if (rc)
+ return rc;
+ }
+
+ if (sb->i2o_version > I2OVER15) {
+ osm_err("%s: Not running version 1.5 of the I2O Specification."
+ "\n", c->name);
+ return -ENODEV;
+ }
+
+ switch (sb->iop_state) {
+ case ADAPTER_STATE_FAULTED:
+ osm_err("%s: hardware fault\n", c->name);
+ return -EFAULT;
+
+ case ADAPTER_STATE_READY:
+ case ADAPTER_STATE_OPERATIONAL:
+ case ADAPTER_STATE_HOLD:
+ case ADAPTER_STATE_FAILED:
+ osm_debug("%s: already running, trying to reset...\n", c->name);
+ rc = i2o_iop_reset(c);
+ if (rc)
+ return rc;
+ }
+
+ /* preserve state */
+ state = sb->iop_state;
+
+ rc = i2o_iop_init_outbound_queue(c);
+ if (rc)
+ return rc;
+
+ /* if adapter was not in RESET state clear now */
+ if (state != ADAPTER_STATE_RESET)
+ i2o_iop_clear(c);
+
+ i2o_status_get(c);
+
+ if (sb->iop_state != ADAPTER_STATE_HOLD) {
+ osm_err("%s: failed to bring IOP into HOLD state\n", c->name);
+ return -EIO;
+ }
+
+ return i2o_hrt_get(c);
+};
+
+static void i2o_res_alloc(struct i2o_controller *c, unsigned long flags)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ struct resource *res = &c->mem_resource;
+ resource_size_t size, align;
+ int err;
+
+ res->name = c->pdev->bus->name;
+ res->flags = flags;
+ res->start = 0;
+ res->end = 0;
+ osm_info("%s: requires private memory resources.\n", c->name);
+
+ if (flags & IORESOURCE_MEM) {
+ size = sb->desired_mem_size;
+ align = 1 << 20; /* unspecified, use 1Mb and play safe */
+ } else {
+ size = sb->desired_io_size;
+ align = 1 << 12; /* unspecified, use 4Kb and play safe */
+ }
+
+ err = pci_bus_alloc_resource(c->pdev->bus, res, size, align, 0, 0,
+ NULL, NULL);
+ if (err < 0)
+ return;
+
+ if (flags & IORESOURCE_MEM) {
+ c->mem_alloc = 1;
+ sb->current_mem_size = resource_size(res);
+ sb->current_mem_base = res->start;
+ } else if (flags & IORESOURCE_IO) {
+ c->io_alloc = 1;
+ sb->current_io_size = resource_size(res);
+ sb->current_io_base = res->start;
+ }
+ osm_info("%s: allocated PCI space %pR\n", c->name, res);
+}
+
+/**
+ * i2o_iop_systab_set - Set the I2O System Table of the specified IOP
+ * @c: I2O controller to which the system table should be send
+ *
+ * Before the systab could be set i2o_systab_build() must be called.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_systab_set(struct i2o_controller *c)
+{
+ struct i2o_message *msg;
+ i2o_status_block *sb = c->status_block.virt;
+ struct device *dev = &c->pdev->dev;
+ int rc;
+
+ if (sb->current_mem_size < sb->desired_mem_size)
+ i2o_res_alloc(c, IORESOURCE_MEM);
+
+ if (sb->current_io_size < sb->desired_io_size)
+ i2o_res_alloc(c, IORESOURCE_IO);
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ i2o_systab.phys = dma_map_single(dev, i2o_systab.virt, i2o_systab.len,
+ PCI_DMA_TODEVICE);
+ if (!i2o_systab.phys) {
+ i2o_msg_nop(c, msg);
+ return -ENOMEM;
+ }
+
+ msg->u.head[0] = cpu_to_le32(I2O_MESSAGE_SIZE(12) | SGL_OFFSET_6);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_SYS_TAB_SET << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+
+ /*
+ * Provide three SGL-elements:
+ * System table (SysTab), Private memory space declaration and
+ * Private i/o space declaration
+ */
+
+ msg->body[0] = cpu_to_le32(c->unit + 2);
+ msg->body[1] = cpu_to_le32(0x00000000);
+ msg->body[2] = cpu_to_le32(0x54000000 | i2o_systab.len);
+ msg->body[3] = cpu_to_le32(i2o_systab.phys);
+ msg->body[4] = cpu_to_le32(0x54000000 | sb->current_mem_size);
+ msg->body[5] = cpu_to_le32(sb->current_mem_base);
+ msg->body[6] = cpu_to_le32(0xd4000000 | sb->current_io_size);
+ msg->body[6] = cpu_to_le32(sb->current_io_base);
+
+ rc = i2o_msg_post_wait(c, msg, 120);
+
+ dma_unmap_single(dev, i2o_systab.phys, i2o_systab.len,
+ PCI_DMA_TODEVICE);
+
+ if (rc < 0)
+ osm_err("%s: Unable to set SysTab (status=%#x).\n", c->name,
+ -rc);
+ else
+ osm_debug("%s: SysTab set.\n", c->name);
+
+ return rc;
+}
+
+/**
+ * i2o_iop_online - Bring a controller online into OPERATIONAL state.
+ * @c: I2O controller
+ *
+ * Send the system table and enable the I2O controller.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_iop_online(struct i2o_controller *c)
+{
+ int rc;
+
+ rc = i2o_iop_systab_set(c);
+ if (rc)
+ return rc;
+
+ /* In READY state */
+ osm_debug("%s: Attempting to enable...\n", c->name);
+ rc = i2o_iop_enable(c);
+ if (rc)
+ return rc;
+
+ return 0;
+};
+
+/**
+ * i2o_iop_remove - Remove the I2O controller from the I2O core
+ * @c: I2O controller
+ *
+ * Remove the I2O controller from the I2O core. If devices are attached to
+ * the controller remove these also and finally reset the controller.
+ */
+void i2o_iop_remove(struct i2o_controller *c)
+{
+ struct i2o_device *dev, *tmp;
+
+ osm_debug("%s: deleting controller\n", c->name);
+
+ i2o_driver_notify_controller_remove_all(c);
+
+ list_del(&c->list);
+
+ list_for_each_entry_safe(dev, tmp, &c->devices, list)
+ i2o_device_remove(dev);
+
+ device_del(&c->device);
+
+ /* Ask the IOP to switch to RESET state */
+ i2o_iop_reset(c);
+}
+
+/**
+ * i2o_systab_build - Build system table
+ *
+ * The system table contains information about all the IOPs in the system
+ * (duh) and is used by the Executives on the IOPs to establish peer2peer
+ * connections. We're not supporting peer2peer at the moment, but this
+ * will be needed down the road for things like lan2lan forwarding.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_systab_build(void)
+{
+ struct i2o_controller *c, *tmp;
+ int num_controllers = 0;
+ u32 change_ind = 0;
+ int count = 0;
+ struct i2o_sys_tbl *systab = i2o_systab.virt;
+
+ list_for_each_entry_safe(c, tmp, &i2o_controllers, list)
+ num_controllers++;
+
+ if (systab) {
+ change_ind = systab->change_ind;
+ kfree(i2o_systab.virt);
+ }
+
+ /* Header + IOPs */
+ i2o_systab.len = sizeof(struct i2o_sys_tbl) + num_controllers *
+ sizeof(struct i2o_sys_tbl_entry);
+
+ systab = i2o_systab.virt = kzalloc(i2o_systab.len, GFP_KERNEL);
+ if (!systab) {
+ osm_err("unable to allocate memory for System Table\n");
+ return -ENOMEM;
+ }
+
+ systab->version = I2OVERSION;
+ systab->change_ind = change_ind + 1;
+
+ list_for_each_entry_safe(c, tmp, &i2o_controllers, list) {
+ i2o_status_block *sb;
+
+ if (count >= num_controllers) {
+ osm_err("controller added while building system table"
+ "\n");
+ break;
+ }
+
+ sb = c->status_block.virt;
+
+ /*
+ * Get updated IOP state so we have the latest information
+ *
+ * We should delete the controller at this point if it
+ * doesn't respond since if it's not on the system table
+ * it is techninically not part of the I2O subsystem...
+ */
+ if (unlikely(i2o_status_get(c))) {
+ osm_err("%s: Deleting b/c could not get status while "
+ "attempting to build system table\n", c->name);
+ i2o_iop_remove(c);
+ continue; // try the next one
+ }
+
+ systab->iops[count].org_id = sb->org_id;
+ systab->iops[count].iop_id = c->unit + 2;
+ systab->iops[count].seg_num = 0;
+ systab->iops[count].i2o_version = sb->i2o_version;
+ systab->iops[count].iop_state = sb->iop_state;
+ systab->iops[count].msg_type = sb->msg_type;
+ systab->iops[count].frame_size = sb->inbound_frame_size;
+ systab->iops[count].last_changed = change_ind;
+ systab->iops[count].iop_capabilities = sb->iop_capabilities;
+ systab->iops[count].inbound_low =
+ i2o_dma_low(c->base.phys + I2O_IN_PORT);
+ systab->iops[count].inbound_high =
+ i2o_dma_high(c->base.phys + I2O_IN_PORT);
+
+ count++;
+ }
+
+ systab->num_entries = count;
+
+ return 0;
+};
+
+/**
+ * i2o_parse_hrt - Parse the hardware resource table.
+ * @c: I2O controller
+ *
+ * We don't do anything with it except dumping it (in debug mode).
+ *
+ * Returns 0.
+ */
+static int i2o_parse_hrt(struct i2o_controller *c)
+{
+ i2o_dump_hrt(c);
+ return 0;
+};
+
+/**
+ * i2o_status_get - Get the status block from the I2O controller
+ * @c: I2O controller
+ *
+ * Issue a status query on the controller. This updates the attached
+ * status block. The status block could then be accessed through
+ * c->status_block.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_status_get(struct i2o_controller *c)
+{
+ struct i2o_message *msg;
+ volatile u8 *status_block;
+ unsigned long timeout;
+
+ status_block = (u8 *) c->status_block.virt;
+ memset(c->status_block.virt, 0, sizeof(i2o_status_block));
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(NINE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_STATUS_GET << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->u.s.icntxt = cpu_to_le32(i2o_exec_driver.context);
+ msg->u.s.tcntxt = cpu_to_le32(0x00000000);
+ msg->body[0] = cpu_to_le32(0x00000000);
+ msg->body[1] = cpu_to_le32(0x00000000);
+ msg->body[2] = cpu_to_le32(i2o_dma_low(c->status_block.phys));
+ msg->body[3] = cpu_to_le32(i2o_dma_high(c->status_block.phys));
+ msg->body[4] = cpu_to_le32(sizeof(i2o_status_block)); /* always 88 bytes */
+
+ i2o_msg_post(c, msg);
+
+ /* Wait for a reply */
+ timeout = jiffies + I2O_TIMEOUT_STATUS_GET * HZ;
+ while (status_block[87] != 0xFF) {
+ if (time_after(jiffies, timeout)) {
+ osm_err("%s: Get status timeout.\n", c->name);
+ return -ETIMEDOUT;
+ }
+
+ schedule_timeout_uninterruptible(1);
+ }
+
+#ifdef DEBUG
+ i2o_debug_state(c);
+#endif
+
+ return 0;
+}
+
+/*
+ * i2o_hrt_get - Get the Hardware Resource Table from the I2O controller
+ * @c: I2O controller from which the HRT should be fetched
+ *
+ * The HRT contains information about possible hidden devices but is
+ * mostly useless to us.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_hrt_get(struct i2o_controller *c)
+{
+ int rc;
+ int i;
+ i2o_hrt *hrt = c->hrt.virt;
+ u32 size = sizeof(i2o_hrt);
+ struct device *dev = &c->pdev->dev;
+
+ for (i = 0; i < I2O_HRT_GET_TRIES; i++) {
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(SIX_WORD_MSG_SIZE | SGL_OFFSET_4);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_HRT_GET << 24 | HOST_TID << 12 |
+ ADAPTER_TID);
+ msg->body[0] = cpu_to_le32(0xd0000000 | c->hrt.len);
+ msg->body[1] = cpu_to_le32(c->hrt.phys);
+
+ rc = i2o_msg_post_wait_mem(c, msg, 20, &c->hrt);
+
+ if (rc < 0) {
+ osm_err("%s: Unable to get HRT (status=%#x)\n", c->name,
+ -rc);
+ return rc;
+ }
+
+ size = hrt->num_entries * hrt->entry_len << 2;
+ if (size > c->hrt.len) {
+ if (i2o_dma_realloc(dev, &c->hrt, size))
+ return -ENOMEM;
+ else
+ hrt = c->hrt.virt;
+ } else
+ return i2o_parse_hrt(c);
+ }
+
+ osm_err("%s: Unable to get HRT after %d tries, giving up\n", c->name,
+ I2O_HRT_GET_TRIES);
+
+ return -EBUSY;
+}
+
+/**
+ * i2o_iop_release - release the memory for a I2O controller
+ * @dev: I2O controller which should be released
+ *
+ * Release the allocated memory. This function is called if refcount of
+ * device reaches 0 automatically.
+ */
+static void i2o_iop_release(struct device *dev)
+{
+ struct i2o_controller *c = to_i2o_controller(dev);
+
+ i2o_iop_free(c);
+};
+
+/**
+ * i2o_iop_alloc - Allocate and initialize a i2o_controller struct
+ *
+ * Allocate the necessary memory for a i2o_controller struct and
+ * initialize the lists and message mempool.
+ *
+ * Returns a pointer to the I2O controller or a negative error code on
+ * failure.
+ */
+struct i2o_controller *i2o_iop_alloc(void)
+{
+ static int unit = 0; /* 0 and 1 are NULL IOP and Local Host */
+ struct i2o_controller *c;
+ char poolname[32];
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c) {
+ osm_err("i2o: Insufficient memory to allocate a I2O controller."
+ "\n");
+ return ERR_PTR(-ENOMEM);
+ }
+
+ c->unit = unit++;
+ sprintf(c->name, "iop%d", c->unit);
+
+ snprintf(poolname, sizeof(poolname), "i2o_%s_msg_inpool", c->name);
+ if (i2o_pool_alloc
+ (&c->in_msg, poolname, I2O_INBOUND_MSG_FRAME_SIZE * 4 + sizeof(u32),
+ I2O_MSG_INPOOL_MIN)) {
+ kfree(c);
+ return ERR_PTR(-ENOMEM);
+ };
+
+ INIT_LIST_HEAD(&c->devices);
+ spin_lock_init(&c->lock);
+ mutex_init(&c->lct_lock);
+
+ device_initialize(&c->device);
+
+ c->device.release = &i2o_iop_release;
+
+ dev_set_name(&c->device, "iop%d", c->unit);
+
+#if BITS_PER_LONG == 64
+ spin_lock_init(&c->context_list_lock);
+ atomic_set(&c->context_list_counter, 0);
+ INIT_LIST_HEAD(&c->context_list);
+#endif
+
+ return c;
+};
+
+/**
+ * i2o_iop_add - Initialize the I2O controller and add him to the I2O core
+ * @c: controller
+ *
+ * Initialize the I2O controller and if no error occurs add him to the I2O
+ * core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_iop_add(struct i2o_controller *c)
+{
+ int rc;
+
+ if ((rc = device_add(&c->device))) {
+ osm_err("%s: could not add controller\n", c->name);
+ goto iop_reset;
+ }
+
+ osm_info("%s: Activating I2O controller...\n", c->name);
+ osm_info("%s: This may take a few minutes if there are many devices\n",
+ c->name);
+
+ if ((rc = i2o_iop_activate(c))) {
+ osm_err("%s: could not activate controller\n", c->name);
+ goto device_del;
+ }
+
+ osm_debug("%s: building sys table...\n", c->name);
+
+ if ((rc = i2o_systab_build()))
+ goto device_del;
+
+ osm_debug("%s: online controller...\n", c->name);
+
+ if ((rc = i2o_iop_online(c)))
+ goto device_del;
+
+ osm_debug("%s: getting LCT...\n", c->name);
+
+ if ((rc = i2o_exec_lct_get(c)))
+ goto device_del;
+
+ list_add(&c->list, &i2o_controllers);
+
+ i2o_driver_notify_controller_add_all(c);
+
+ osm_info("%s: Controller added\n", c->name);
+
+ return 0;
+
+ device_del:
+ device_del(&c->device);
+
+ iop_reset:
+ i2o_iop_reset(c);
+
+ return rc;
+};
+
+/**
+ * i2o_event_register - Turn on/off event notification for a I2O device
+ * @dev: I2O device which should receive the event registration request
+ * @drv: driver which want to get notified
+ * @tcntxt: transaction context to use with this notifier
+ * @evt_mask: mask of events
+ *
+ * Create and posts an event registration message to the task. No reply
+ * is waited for, or expected. If you do not want further notifications,
+ * call the i2o_event_register again with a evt_mask of 0.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_event_register(struct i2o_device *dev, struct i2o_driver *drv,
+ int tcntxt, u32 evt_mask)
+{
+ struct i2o_controller *c = dev->iop;
+ struct i2o_message *msg;
+
+ msg = i2o_msg_get_wait(c, I2O_TIMEOUT_MESSAGE_GET);
+ if (IS_ERR(msg))
+ return PTR_ERR(msg);
+
+ msg->u.head[0] = cpu_to_le32(FIVE_WORD_MSG_SIZE | SGL_OFFSET_0);
+ msg->u.head[1] =
+ cpu_to_le32(I2O_CMD_UTIL_EVT_REGISTER << 24 | HOST_TID << 12 | dev->
+ lct_data.tid);
+ msg->u.s.icntxt = cpu_to_le32(drv->context);
+ msg->u.s.tcntxt = cpu_to_le32(tcntxt);
+ msg->body[0] = cpu_to_le32(evt_mask);
+
+ i2o_msg_post(c, msg);
+
+ return 0;
+};
+
+/**
+ * i2o_iop_init - I2O main initialization function
+ *
+ * Initialize the I2O drivers (OSM) functions, register the Executive OSM,
+ * initialize the I2O PCI part and finally initialize I2O device stuff.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int __init i2o_iop_init(void)
+{
+ int rc = 0;
+
+ printk(KERN_INFO OSM_DESCRIPTION " v" OSM_VERSION "\n");
+
+ if ((rc = i2o_driver_init()))
+ goto exit;
+
+ if ((rc = i2o_exec_init()))
+ goto driver_exit;
+
+ if ((rc = i2o_pci_init()))
+ goto exec_exit;
+
+ return 0;
+
+ exec_exit:
+ i2o_exec_exit();
+
+ driver_exit:
+ i2o_driver_exit();
+
+ exit:
+ return rc;
+}
+
+/**
+ * i2o_iop_exit - I2O main exit function
+ *
+ * Removes I2O controllers from PCI subsystem and shut down OSMs.
+ */
+static void __exit i2o_iop_exit(void)
+{
+ i2o_pci_exit();
+ i2o_exec_exit();
+ i2o_driver_exit();
+};
+
+module_init(i2o_iop_init);
+module_exit(i2o_iop_exit);
+
+MODULE_AUTHOR("Red Hat Software");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(OSM_DESCRIPTION);
+MODULE_VERSION(OSM_VERSION);
+
+#if BITS_PER_LONG == 64
+EXPORT_SYMBOL(i2o_cntxt_list_add);
+EXPORT_SYMBOL(i2o_cntxt_list_get);
+EXPORT_SYMBOL(i2o_cntxt_list_remove);
+EXPORT_SYMBOL(i2o_cntxt_list_get_ptr);
+#endif
+EXPORT_SYMBOL(i2o_msg_get_wait);
+EXPORT_SYMBOL(i2o_find_iop);
+EXPORT_SYMBOL(i2o_iop_find_device);
+EXPORT_SYMBOL(i2o_event_register);
+EXPORT_SYMBOL(i2o_status_get);
+EXPORT_SYMBOL(i2o_controllers);
diff --git a/drivers/staging/i2o/memory.c b/drivers/staging/i2o/memory.c
new file mode 100644
index 000000000000..8f9509d275a4
--- /dev/null
+++ b/drivers/staging/i2o/memory.c
@@ -0,0 +1,313 @@
+/*
+ * Functions to handle I2O memory
+ *
+ * Pulled from the inlines in i2o headers and uninlined
+ *
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the 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 "i2o.h"
+#include <linux/delay.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include "core.h"
+
+/* Protects our 32/64bit mask switching */
+static DEFINE_MUTEX(mem_lock);
+
+/**
+ * i2o_sg_tablesize - Calculate the maximum number of elements in a SGL
+ * @c: I2O controller for which the calculation should be done
+ * @body_size: maximum body size used for message in 32-bit words.
+ *
+ * Return the maximum number of SG elements in a SG list.
+ */
+u16 i2o_sg_tablesize(struct i2o_controller *c, u16 body_size)
+{
+ i2o_status_block *sb = c->status_block.virt;
+ u16 sg_count =
+ (sb->inbound_frame_size - sizeof(struct i2o_message) / 4) -
+ body_size;
+
+ if (c->pae_support) {
+ /*
+ * for 64-bit a SG attribute element must be added and each
+ * SG element needs 12 bytes instead of 8.
+ */
+ sg_count -= 2;
+ sg_count /= 3;
+ } else
+ sg_count /= 2;
+
+ if (c->short_req && (sg_count > 8))
+ sg_count = 8;
+
+ return sg_count;
+}
+EXPORT_SYMBOL_GPL(i2o_sg_tablesize);
+
+
+/**
+ * i2o_dma_map_single - Map pointer to controller and fill in I2O message.
+ * @c: I2O controller
+ * @ptr: pointer to the data which should be mapped
+ * @size: size of data in bytes
+ * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ * @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ * This function does all necessary DMA handling and also writes the I2O
+ * SGL elements into the I2O message. For details on DMA handling see also
+ * dma_map_single(). The pointer sg_ptr will only be set to the end of the
+ * SG list if the allocation was successful.
+ *
+ * Returns DMA address which must be checked for failures using
+ * dma_mapping_error().
+ */
+dma_addr_t i2o_dma_map_single(struct i2o_controller *c, void *ptr,
+ size_t size,
+ enum dma_data_direction direction,
+ u32 ** sg_ptr)
+{
+ u32 sg_flags;
+ u32 *mptr = *sg_ptr;
+ dma_addr_t dma_addr;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ sg_flags = 0xd4000000;
+ break;
+ case DMA_FROM_DEVICE:
+ sg_flags = 0xd0000000;
+ break;
+ default:
+ return 0;
+ }
+
+ dma_addr = dma_map_single(&c->pdev->dev, ptr, size, direction);
+ if (!dma_mapping_error(&c->pdev->dev, dma_addr)) {
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+ *mptr++ = cpu_to_le32(0x7C020002);
+ *mptr++ = cpu_to_le32(PAGE_SIZE);
+ }
+#endif
+
+ *mptr++ = cpu_to_le32(sg_flags | size);
+ *mptr++ = cpu_to_le32(i2o_dma_low(dma_addr));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+ *mptr++ = cpu_to_le32(i2o_dma_high(dma_addr));
+#endif
+ *sg_ptr = mptr;
+ }
+ return dma_addr;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_single);
+
+/**
+ * i2o_dma_map_sg - Map a SG List to controller and fill in I2O message.
+ * @c: I2O controller
+ * @sg: SG list to be mapped
+ * @sg_count: number of elements in the SG list
+ * @direction: DMA_TO_DEVICE / DMA_FROM_DEVICE
+ * @sg_ptr: pointer to the SG list inside the I2O message
+ *
+ * This function does all necessary DMA handling and also writes the I2O
+ * SGL elements into the I2O message. For details on DMA handling see also
+ * dma_map_sg(). The pointer sg_ptr will only be set to the end of the SG
+ * list if the allocation was successful.
+ *
+ * Returns 0 on failure or 1 on success.
+ */
+int i2o_dma_map_sg(struct i2o_controller *c, struct scatterlist *sg,
+ int sg_count, enum dma_data_direction direction, u32 ** sg_ptr)
+{
+ u32 sg_flags;
+ u32 *mptr = *sg_ptr;
+
+ switch (direction) {
+ case DMA_TO_DEVICE:
+ sg_flags = 0x14000000;
+ break;
+ case DMA_FROM_DEVICE:
+ sg_flags = 0x10000000;
+ break;
+ default:
+ return 0;
+ }
+
+ sg_count = dma_map_sg(&c->pdev->dev, sg, sg_count, direction);
+ if (!sg_count)
+ return 0;
+
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support) {
+ *mptr++ = cpu_to_le32(0x7C020002);
+ *mptr++ = cpu_to_le32(PAGE_SIZE);
+ }
+#endif
+
+ while (sg_count-- > 0) {
+ if (!sg_count)
+ sg_flags |= 0xC0000000;
+ *mptr++ = cpu_to_le32(sg_flags | sg_dma_len(sg));
+ *mptr++ = cpu_to_le32(i2o_dma_low(sg_dma_address(sg)));
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if ((sizeof(dma_addr_t) > 4) && c->pae_support)
+ *mptr++ = cpu_to_le32(i2o_dma_high(sg_dma_address(sg)));
+#endif
+ sg = sg_next(sg);
+ }
+ *sg_ptr = mptr;
+
+ return 1;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_map_sg);
+
+/**
+ * i2o_dma_alloc - Allocate DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: i2o_dma struct which should get the DMA buffer
+ * @len: length of the new DMA memory
+ *
+ * Allocate a coherent DMA memory and write the pointers into addr.
+ *
+ * Returns 0 on success or -ENOMEM on failure.
+ */
+int i2o_dma_alloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int dma_64 = 0;
+
+ mutex_lock(&mem_lock);
+ if ((sizeof(dma_addr_t) > 4) && (pdev->dma_mask == DMA_BIT_MASK(64))) {
+ dma_64 = 1;
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ mutex_unlock(&mem_lock);
+ return -ENOMEM;
+ }
+ }
+
+ addr->virt = dma_alloc_coherent(dev, len, &addr->phys, GFP_KERNEL);
+
+ if ((sizeof(dma_addr_t) > 4) && dma_64)
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+ printk(KERN_WARNING "i2o: unable to set 64-bit DMA");
+ mutex_unlock(&mem_lock);
+
+ if (!addr->virt)
+ return -ENOMEM;
+
+ memset(addr->virt, 0, len);
+ addr->len = len;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_alloc);
+
+
+/**
+ * i2o_dma_free - Free DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: i2o_dma struct which contains the DMA buffer
+ *
+ * Free a coherent DMA memory and set virtual address of addr to NULL.
+ */
+void i2o_dma_free(struct device *dev, struct i2o_dma *addr)
+{
+ if (addr->virt) {
+ if (addr->phys)
+ dma_free_coherent(dev, addr->len, addr->virt,
+ addr->phys);
+ else
+ kfree(addr->virt);
+ addr->virt = NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(i2o_dma_free);
+
+
+/**
+ * i2o_dma_realloc - Realloc DMA memory
+ * @dev: struct device pointer to the PCI device of the I2O controller
+ * @addr: pointer to a i2o_dma struct DMA buffer
+ * @len: new length of memory
+ *
+ * If there was something allocated in the addr, free it first. If len > 0
+ * than try to allocate it and write the addresses back to the addr
+ * structure. If len == 0 set the virtual address to NULL.
+ *
+ * Returns the 0 on success or negative error code on failure.
+ */
+int i2o_dma_realloc(struct device *dev, struct i2o_dma *addr, size_t len)
+{
+ i2o_dma_free(dev, addr);
+
+ if (len)
+ return i2o_dma_alloc(dev, addr, len);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(i2o_dma_realloc);
+
+/*
+ * i2o_pool_alloc - Allocate an slab cache and mempool
+ * @mempool: pointer to struct i2o_pool to write data into.
+ * @name: name which is used to identify cache
+ * @size: size of each object
+ * @min_nr: minimum number of objects
+ *
+ * First allocates a slab cache with name and size. Then allocates a
+ * mempool which uses the slab cache for allocation and freeing.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+int i2o_pool_alloc(struct i2o_pool *pool, const char *name,
+ size_t size, int min_nr)
+{
+ pool->name = kmalloc(strlen(name) + 1, GFP_KERNEL);
+ if (!pool->name)
+ goto exit;
+ strcpy(pool->name, name);
+
+ pool->slab =
+ kmem_cache_create(pool->name, size, 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (!pool->slab)
+ goto free_name;
+
+ pool->mempool = mempool_create_slab_pool(min_nr, pool->slab);
+ if (!pool->mempool)
+ goto free_slab;
+
+ return 0;
+
+free_slab:
+ kmem_cache_destroy(pool->slab);
+
+free_name:
+ kfree(pool->name);
+
+exit:
+ return -ENOMEM;
+}
+EXPORT_SYMBOL_GPL(i2o_pool_alloc);
+
+/*
+ * i2o_pool_free - Free slab cache and mempool again
+ * @mempool: pointer to struct i2o_pool which should be freed
+ *
+ * Note that you have to return all objects to the mempool again before
+ * calling i2o_pool_free().
+ */
+void i2o_pool_free(struct i2o_pool *pool)
+{
+ mempool_destroy(pool->mempool);
+ kmem_cache_destroy(pool->slab);
+ kfree(pool->name);
+};
+EXPORT_SYMBOL_GPL(i2o_pool_free);
diff --git a/drivers/staging/i2o/pci.c b/drivers/staging/i2o/pci.c
new file mode 100644
index 000000000000..b3b8a61dd4a6
--- /dev/null
+++ b/drivers/staging/i2o/pci.c
@@ -0,0 +1,497 @@
+/*
+ * PCI handling of I2O controller
+ *
+ * Copyright (C) 1999-2002 Red Hat Software
+ *
+ * Written by Alan Cox, Building Number Three 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.
+ *
+ * A lot of the I2O message side code from this is taken from the Red
+ * Creek RCPCI45 adapter driver by Red Creek Communications
+ *
+ * Fixes/additions:
+ * Philipp Rumpf
+ * Juha Sievänen <Juha.Sievanen@cs.Helsinki.FI>
+ * Auvo Häkkinen <Auvo.Hakkinen@cs.Helsinki.FI>
+ * Deepak Saxena <deepak@plexity.net>
+ * Boji T Kannanthanam <boji.t.kannanthanam@intel.com>
+ * Alan Cox <alan@lxorguk.ukuu.org.uk>:
+ * Ported to Linux 2.5.
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Minor fixes for 2.6.
+ * Markus Lidel <Markus.Lidel@shadowconnect.com>:
+ * Support for sysfs included.
+ */
+
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include "i2o.h"
+#include <linux/module.h>
+#include "core.h"
+
+#define OSM_DESCRIPTION "I2O-subsystem"
+
+/* PCI device id table for all I2O controllers */
+static struct pci_device_id i2o_pci_ids[] = {
+ {PCI_DEVICE_CLASS(PCI_CLASS_INTELLIGENT_I2O << 8, 0xffff00)},
+ {PCI_DEVICE(PCI_VENDOR_ID_DPT, 0xa511)},
+ {.vendor = PCI_VENDOR_ID_INTEL,.device = 0x1962,
+ .subvendor = PCI_VENDOR_ID_PROMISE,.subdevice = PCI_ANY_ID},
+ {0}
+};
+
+/**
+ * i2o_pci_free - Frees the DMA memory for the I2O controller
+ * @c: I2O controller to free
+ *
+ * Remove all allocated DMA memory and unmap memory IO regions. If MTRR
+ * is enabled, also remove it again.
+ */
+static void i2o_pci_free(struct i2o_controller *c)
+{
+ struct device *dev;
+
+ dev = &c->pdev->dev;
+
+ i2o_dma_free(dev, &c->out_queue);
+ i2o_dma_free(dev, &c->status_block);
+ kfree(c->lct);
+ i2o_dma_free(dev, &c->dlct);
+ i2o_dma_free(dev, &c->hrt);
+ i2o_dma_free(dev, &c->status);
+
+ if (c->raptor && c->in_queue.virt)
+ iounmap(c->in_queue.virt);
+
+ if (c->base.virt)
+ iounmap(c->base.virt);
+
+ pci_release_regions(c->pdev);
+}
+
+/**
+ * i2o_pci_alloc - Allocate DMA memory, map IO memory for I2O controller
+ * @c: I2O controller
+ *
+ * Allocate DMA memory for a PCI (or in theory AGP) I2O controller. All
+ * IO mappings are also done here. If MTRR is enabled, also do add memory
+ * regions here.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_alloc(struct i2o_controller *c)
+{
+ struct pci_dev *pdev = c->pdev;
+ struct device *dev = &pdev->dev;
+ int i;
+
+ if (pci_request_regions(pdev, OSM_DESCRIPTION)) {
+ printk(KERN_ERR "%s: device already claimed\n", c->name);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < 6; i++) {
+ /* Skip I/O spaces */
+ if (!(pci_resource_flags(pdev, i) & IORESOURCE_IO)) {
+ if (!c->base.phys) {
+ c->base.phys = pci_resource_start(pdev, i);
+ c->base.len = pci_resource_len(pdev, i);
+
+ /*
+ * If we know what card it is, set the size
+ * correctly. Code is taken from dpt_i2o.c
+ */
+ if (pdev->device == 0xa501) {
+ if (pdev->subsystem_device >= 0xc032 &&
+ pdev->subsystem_device <= 0xc03b) {
+ if (c->base.len > 0x400000)
+ c->base.len = 0x400000;
+ } else {
+ if (c->base.len > 0x100000)
+ c->base.len = 0x100000;
+ }
+ }
+ if (!c->raptor)
+ break;
+ } else {
+ c->in_queue.phys = pci_resource_start(pdev, i);
+ c->in_queue.len = pci_resource_len(pdev, i);
+ break;
+ }
+ }
+ }
+
+ if (i == 6) {
+ printk(KERN_ERR "%s: I2O controller has no memory regions"
+ " defined.\n", c->name);
+ i2o_pci_free(c);
+ return -EINVAL;
+ }
+
+ /* Map the I2O controller */
+ if (c->raptor) {
+ printk(KERN_INFO "%s: PCI I2O controller\n", c->name);
+ printk(KERN_INFO " BAR0 at 0x%08lX size=%ld\n",
+ (unsigned long)c->base.phys, (unsigned long)c->base.len);
+ printk(KERN_INFO " BAR1 at 0x%08lX size=%ld\n",
+ (unsigned long)c->in_queue.phys,
+ (unsigned long)c->in_queue.len);
+ } else
+ printk(KERN_INFO "%s: PCI I2O controller at %08lX size=%ld\n",
+ c->name, (unsigned long)c->base.phys,
+ (unsigned long)c->base.len);
+
+ c->base.virt = ioremap_nocache(c->base.phys, c->base.len);
+ if (!c->base.virt) {
+ printk(KERN_ERR "%s: Unable to map controller.\n", c->name);
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+
+ if (c->raptor) {
+ c->in_queue.virt =
+ ioremap_nocache(c->in_queue.phys, c->in_queue.len);
+ if (!c->in_queue.virt) {
+ printk(KERN_ERR "%s: Unable to map controller.\n",
+ c->name);
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+ } else
+ c->in_queue = c->base;
+
+ c->irq_status = c->base.virt + I2O_IRQ_STATUS;
+ c->irq_mask = c->base.virt + I2O_IRQ_MASK;
+ c->in_port = c->base.virt + I2O_IN_PORT;
+ c->out_port = c->base.virt + I2O_OUT_PORT;
+
+ /* Motorola/Freescale chip does not follow spec */
+ if (pdev->vendor == PCI_VENDOR_ID_MOTOROLA && pdev->device == 0x18c0) {
+ /* Check if CPU is enabled */
+ if (be32_to_cpu(readl(c->base.virt + 0x10000)) & 0x10000000) {
+ printk(KERN_INFO "%s: MPC82XX needs CPU running to "
+ "service I2O.\n", c->name);
+ i2o_pci_free(c);
+ return -ENODEV;
+ } else {
+ c->irq_status += I2O_MOTOROLA_PORT_OFFSET;
+ c->irq_mask += I2O_MOTOROLA_PORT_OFFSET;
+ c->in_port += I2O_MOTOROLA_PORT_OFFSET;
+ c->out_port += I2O_MOTOROLA_PORT_OFFSET;
+ printk(KERN_INFO "%s: MPC82XX workarounds activated.\n",
+ c->name);
+ }
+ }
+
+ if (i2o_dma_alloc(dev, &c->status, 8)) {
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+
+ if (i2o_dma_alloc(dev, &c->hrt, sizeof(i2o_hrt))) {
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+
+ if (i2o_dma_alloc(dev, &c->dlct, 8192)) {
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+
+ if (i2o_dma_alloc(dev, &c->status_block, sizeof(i2o_status_block))) {
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+
+ if (i2o_dma_alloc(dev, &c->out_queue,
+ I2O_MAX_OUTBOUND_MSG_FRAMES * I2O_OUTBOUND_MSG_FRAME_SIZE *
+ sizeof(u32))) {
+ i2o_pci_free(c);
+ return -ENOMEM;
+ }
+
+ pci_set_drvdata(pdev, c);
+
+ return 0;
+}
+
+/**
+ * i2o_pci_interrupt - Interrupt handler for I2O controller
+ * @irq: interrupt line
+ * @dev_id: pointer to the I2O controller
+ *
+ * Handle an interrupt from a PCI based I2O controller. This turns out
+ * to be rather simple. We keep the controller pointer in the cookie.
+ */
+static irqreturn_t i2o_pci_interrupt(int irq, void *dev_id)
+{
+ struct i2o_controller *c = dev_id;
+ u32 m;
+ irqreturn_t rc = IRQ_NONE;
+
+ while (readl(c->irq_status) & I2O_IRQ_OUTBOUND_POST) {
+ m = readl(c->out_port);
+ if (m == I2O_QUEUE_EMPTY) {
+ /*
+ * Old 960 steppings had a bug in the I2O unit that
+ * caused the queue to appear empty when it wasn't.
+ */
+ m = readl(c->out_port);
+ if (unlikely(m == I2O_QUEUE_EMPTY))
+ break;
+ }
+
+ /* dispatch it */
+ if (i2o_driver_dispatch(c, m))
+ /* flush it if result != 0 */
+ i2o_flush_reply(c, m);
+
+ rc = IRQ_HANDLED;
+ }
+
+ return rc;
+}
+
+/**
+ * i2o_pci_irq_enable - Allocate interrupt for I2O controller
+ * @c: i2o_controller that the request is for
+ *
+ * Allocate an interrupt for the I2O controller, and activate interrupts
+ * on the I2O controller.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_irq_enable(struct i2o_controller *c)
+{
+ struct pci_dev *pdev = c->pdev;
+ int rc;
+
+ writel(0xffffffff, c->irq_mask);
+
+ if (pdev->irq) {
+ rc = request_irq(pdev->irq, i2o_pci_interrupt, IRQF_SHARED,
+ c->name, c);
+ if (rc < 0) {
+ printk(KERN_ERR "%s: unable to allocate interrupt %d."
+ "\n", c->name, pdev->irq);
+ return rc;
+ }
+ }
+
+ writel(0x00000000, c->irq_mask);
+
+ printk(KERN_INFO "%s: Installed at IRQ %d\n", c->name, pdev->irq);
+
+ return 0;
+}
+
+/**
+ * i2o_pci_irq_disable - Free interrupt for I2O controller
+ * @c: I2O controller
+ *
+ * Disable interrupts in I2O controller and then free interrupt.
+ */
+static void i2o_pci_irq_disable(struct i2o_controller *c)
+{
+ writel(0xffffffff, c->irq_mask);
+
+ if (c->pdev->irq > 0)
+ free_irq(c->pdev->irq, c);
+}
+
+/**
+ * i2o_pci_probe - Probe the PCI device for an I2O controller
+ * @pdev: PCI device to test
+ * @id: id which matched with the PCI device id table
+ *
+ * Probe the PCI device for any device which is a memory of the
+ * Intelligent, I2O class or an Adaptec Zero Channel Controller. We
+ * attempt to set up each such device and register it with the core.
+ *
+ * Returns 0 on success or negative error code on failure.
+ */
+static int i2o_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct i2o_controller *c;
+ int rc;
+ struct pci_dev *i960 = NULL;
+
+ printk(KERN_INFO "i2o: Checking for PCI I2O controllers...\n");
+
+ if ((pdev->class & 0xff) > 1) {
+ printk(KERN_WARNING "i2o: %s does not support I2O 1.5 "
+ "(skipping).\n", pci_name(pdev));
+ return -ENODEV;
+ }
+
+ if ((rc = pci_enable_device(pdev))) {
+ printk(KERN_WARNING "i2o: couldn't enable device %s\n",
+ pci_name(pdev));
+ return rc;
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ printk(KERN_WARNING "i2o: no suitable DMA found for %s\n",
+ pci_name(pdev));
+ rc = -ENODEV;
+ goto disable;
+ }
+
+ pci_set_master(pdev);
+
+ c = i2o_iop_alloc();
+ if (IS_ERR(c)) {
+ printk(KERN_ERR "i2o: couldn't allocate memory for %s\n",
+ pci_name(pdev));
+ rc = PTR_ERR(c);
+ goto disable;
+ } else
+ printk(KERN_INFO "%s: controller found (%s)\n", c->name,
+ pci_name(pdev));
+
+ c->pdev = pdev;
+ c->device.parent = &pdev->dev;
+
+ /* Cards that fall apart if you hit them with large I/O loads... */
+ if (pdev->vendor == PCI_VENDOR_ID_NCR && pdev->device == 0x0630) {
+ c->short_req = 1;
+ printk(KERN_INFO "%s: Symbios FC920 workarounds activated.\n",
+ c->name);
+ }
+
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_PROMISE) {
+ /*
+ * Expose the ship behind i960 for initialization, or it will
+ * failed
+ */
+ i960 = pci_get_slot(c->pdev->bus,
+ PCI_DEVFN(PCI_SLOT(c->pdev->devfn), 0));
+
+ if (i960) {
+ pci_write_config_word(i960, 0x42, 0);
+ pci_dev_put(i960);
+ }
+
+ c->promise = 1;
+ c->limit_sectors = 1;
+ }
+
+ if (pdev->subsystem_vendor == PCI_VENDOR_ID_DPT)
+ c->adaptec = 1;
+
+ /* Cards that go bananas if you quiesce them before you reset them. */
+ if (pdev->vendor == PCI_VENDOR_ID_DPT) {
+ c->no_quiesce = 1;
+ if (pdev->device == 0xa511)
+ c->raptor = 1;
+
+ if (pdev->subsystem_device == 0xc05a) {
+ c->limit_sectors = 1;
+ printk(KERN_INFO
+ "%s: limit sectors per request to %d\n", c->name,
+ I2O_MAX_SECTORS_LIMITED);
+ }
+#ifdef CONFIG_I2O_EXT_ADAPTEC_DMA64
+ if (sizeof(dma_addr_t) > 4) {
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64)))
+ printk(KERN_INFO "%s: 64-bit DMA unavailable\n",
+ c->name);
+ else {
+ c->pae_support = 1;
+ printk(KERN_INFO "%s: using 64-bit DMA\n",
+ c->name);
+ }
+ }
+#endif
+ }
+
+ if ((rc = i2o_pci_alloc(c))) {
+ printk(KERN_ERR "%s: DMA / IO allocation for I2O controller "
+ "failed\n", c->name);
+ goto free_controller;
+ }
+
+ if (i2o_pci_irq_enable(c)) {
+ printk(KERN_ERR "%s: unable to enable interrupts for I2O "
+ "controller\n", c->name);
+ goto free_pci;
+ }
+
+ if ((rc = i2o_iop_add(c)))
+ goto uninstall;
+
+ if (i960)
+ pci_write_config_word(i960, 0x42, 0x03ff);
+
+ return 0;
+
+ uninstall:
+ i2o_pci_irq_disable(c);
+
+ free_pci:
+ i2o_pci_free(c);
+
+ free_controller:
+ i2o_iop_free(c);
+
+ disable:
+ pci_disable_device(pdev);
+
+ return rc;
+}
+
+/**
+ * i2o_pci_remove - Removes a I2O controller from the system
+ * @pdev: I2O controller which should be removed
+ *
+ * Reset the I2O controller, disable interrupts and remove all allocated
+ * resources.
+ */
+static void i2o_pci_remove(struct pci_dev *pdev)
+{
+ struct i2o_controller *c;
+ c = pci_get_drvdata(pdev);
+
+ i2o_iop_remove(c);
+ i2o_pci_irq_disable(c);
+ i2o_pci_free(c);
+
+ pci_disable_device(pdev);
+
+ printk(KERN_INFO "%s: Controller removed.\n", c->name);
+
+ put_device(&c->device);
+};
+
+/* PCI driver for I2O controller */
+static struct pci_driver i2o_pci_driver = {
+ .name = "PCI_I2O",
+ .id_table = i2o_pci_ids,
+ .probe = i2o_pci_probe,
+ .remove = i2o_pci_remove,
+};
+
+/**
+ * i2o_pci_init - registers I2O PCI driver in PCI subsystem
+ *
+ * Returns > 0 on success or negative error code on failure.
+ */
+int __init i2o_pci_init(void)
+{
+ return pci_register_driver(&i2o_pci_driver);
+};
+
+/**
+ * i2o_pci_exit - unregisters I2O PCI driver from PCI subsystem
+ */
+void __exit i2o_pci_exit(void)
+{
+ pci_unregister_driver(&i2o_pci_driver);
+};
+
+MODULE_DEVICE_TABLE(pci, i2o_pci_ids);
diff --git a/drivers/staging/iio/Documentation/iio_event_monitor.c b/drivers/staging/iio/Documentation/iio_event_monitor.c
index 940ed2399e73..72c96aa6e992 100644
--- a/drivers/staging/iio/Documentation/iio_event_monitor.c
+++ b/drivers/staging/iio/Documentation/iio_event_monitor.c
@@ -49,6 +49,8 @@ static const char * const iio_chan_type_name_spec[] = {
[IIO_CCT] = "cct",
[IIO_PRESSURE] = "pressure",
[IIO_HUMIDITYRELATIVE] = "humidityrelative",
+ [IIO_ACTIVITY] = "activity",
+ [IIO_STEPS] = "steps",
};
static const char * const iio_ev_type_text[] = {
@@ -57,6 +59,7 @@ static const char * const iio_ev_type_text[] = {
[IIO_EV_TYPE_ROC] = "roc",
[IIO_EV_TYPE_THRESH_ADAPTIVE] = "thresh_adaptive",
[IIO_EV_TYPE_MAG_ADAPTIVE] = "mag_adaptive",
+ [IIO_EV_TYPE_CHANGE] = "change",
};
static const char * const iio_ev_dir_text[] = {
@@ -92,6 +95,10 @@ static const char * const iio_modifier_names[] = {
[IIO_MOD_NORTH_TRUE] = "from_north_true",
[IIO_MOD_NORTH_MAGN_TILT_COMP] = "from_north_magnetic_tilt_comp",
[IIO_MOD_NORTH_TRUE_TILT_COMP] = "from_north_true_tilt_comp",
+ [IIO_MOD_RUNNING] = "running",
+ [IIO_MOD_JOGGING] = "jogging",
+ [IIO_MOD_WALKING] = "walking",
+ [IIO_MOD_STILL] = "still",
};
static bool event_is_known(struct iio_event_data *event)
@@ -121,6 +128,8 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_CCT:
case IIO_PRESSURE:
case IIO_HUMIDITYRELATIVE:
+ case IIO_ACTIVITY:
+ case IIO_STEPS:
break;
default:
return false;
@@ -154,6 +163,10 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_MOD_NORTH_TRUE:
case IIO_MOD_NORTH_MAGN_TILT_COMP:
case IIO_MOD_NORTH_TRUE_TILT_COMP:
+ case IIO_MOD_RUNNING:
+ case IIO_MOD_JOGGING:
+ case IIO_MOD_WALKING:
+ case IIO_MOD_STILL:
break;
default:
return false;
@@ -165,6 +178,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_EV_TYPE_ROC:
case IIO_EV_TYPE_THRESH_ADAPTIVE:
case IIO_EV_TYPE_MAG_ADAPTIVE:
+ case IIO_EV_TYPE_CHANGE:
break;
default:
return false;
@@ -174,6 +188,7 @@ static bool event_is_known(struct iio_event_data *event)
case IIO_EV_DIR_EITHER:
case IIO_EV_DIR_RISING:
case IIO_EV_DIR_FALLING:
+ case IIO_EV_DIR_NONE:
break;
default:
return false;
@@ -214,9 +229,11 @@ static void print_event(struct iio_event_data *event)
else if (chan >= 0)
printf("channel: %d, ", chan);
- printf("evtype: %s, direction: %s\n",
- iio_ev_type_text[ev_type],
- iio_ev_dir_text[dir]);
+ printf("evtype: %s", iio_ev_type_text[ev_type]);
+
+ if (dir != IIO_EV_DIR_NONE)
+ printf(", direction: %s", iio_ev_dir_text[dir]);
+ printf("\n");
}
int main(int argc, char **argv)
diff --git a/drivers/staging/iio/Documentation/ring.txt b/drivers/staging/iio/Documentation/ring.txt
index e1da43381d0e..18718fcaf259 100644
--- a/drivers/staging/iio/Documentation/ring.txt
+++ b/drivers/staging/iio/Documentation/ring.txt
@@ -39,9 +39,9 @@ request_update
If parameters have changed that require reinitialization or configuration of
the buffer this will trigger it.
-get_bytes_per_datum, set_bytes_per_datum
- Get/set the number of bytes for a complete scan. (All samples + timestamp)
+set_bytes_per_datum
+ Set the number of bytes for a complete scan. (All samples + timestamp)
-get_length / set_length
- Get/set the number of complete scans that may be held by the buffer.
+set_length
+ Set the number of complete scans that may be held by the buffer.
diff --git a/drivers/staging/iio/Kconfig b/drivers/staging/iio/Kconfig
index fa38be0982f9..24183028bd71 100644
--- a/drivers/staging/iio/Kconfig
+++ b/drivers/staging/iio/Kconfig
@@ -30,13 +30,13 @@ config IIO_SIMPLE_DUMMY
if IIO_SIMPLE_DUMMY
config IIO_SIMPLE_DUMMY_EVENTS
- boolean "Event generation support"
+ bool "Event generation support"
select IIO_DUMMY_EVGEN
help
Add some dummy events to the simple dummy driver.
config IIO_SIMPLE_DUMMY_BUFFER
- boolean "Buffered capture support"
+ bool "Buffered capture support"
select IIO_BUFFER
select IIO_KFIFO_BUF
help
diff --git a/drivers/staging/iio/accel/lis3l02dq_core.c b/drivers/staging/iio/accel/lis3l02dq_core.c
index f5e145caffa9..b78c9c5d5588 100644
--- a/drivers/staging/iio/accel/lis3l02dq_core.c
+++ b/drivers/staging/iio/accel/lis3l02dq_core.c
@@ -716,14 +716,6 @@ static int lis3l02dq_probe(struct spi_device *spi)
if (ret)
return ret;
- ret = iio_buffer_register(indio_dev,
- lis3l02dq_channels,
- ARRAY_SIZE(lis3l02dq_channels));
- if (ret) {
- dev_err(&spi->dev, "failed to initialize the buffer\n");
- goto error_unreg_buffer_funcs;
- }
-
if (spi->irq) {
ret = request_threaded_irq(st->us->irq,
&lis3l02dq_th,
@@ -732,7 +724,7 @@ static int lis3l02dq_probe(struct spi_device *spi)
"lis3l02dq",
indio_dev);
if (ret)
- goto error_uninitialize_buffer;
+ goto error_unreg_buffer_funcs;
ret = lis3l02dq_probe_trigger(indio_dev);
if (ret)
@@ -756,8 +748,6 @@ error_remove_trigger:
error_free_interrupt:
if (spi->irq)
free_irq(st->us->irq, indio_dev);
-error_uninitialize_buffer:
- iio_buffer_unregister(indio_dev);
error_unreg_buffer_funcs:
lis3l02dq_unconfigure_buffer(indio_dev);
return ret;
@@ -804,7 +794,6 @@ static int lis3l02dq_remove(struct spi_device *spi)
free_irq(st->us->irq, indio_dev);
lis3l02dq_remove_trigger(indio_dev);
- iio_buffer_unregister(indio_dev);
lis3l02dq_unconfigure_buffer(indio_dev);
return 0;
diff --git a/drivers/staging/iio/accel/lis3l02dq_ring.c b/drivers/staging/iio/accel/lis3l02dq_ring.c
index 9efc77b0ebdd..1fd90090a633 100644
--- a/drivers/staging/iio/accel/lis3l02dq_ring.c
+++ b/drivers/staging/iio/accel/lis3l02dq_ring.c
@@ -393,7 +393,7 @@ int lis3l02dq_configure_buffer(struct iio_dev *indio_dev)
int ret;
struct iio_buffer *buffer;
- buffer = iio_kfifo_allocate(indio_dev);
+ buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
diff --git a/drivers/staging/iio/accel/sca3000_core.c b/drivers/staging/iio/accel/sca3000_core.c
index e4e56391487a..31fb2182c198 100644
--- a/drivers/staging/iio/accel/sca3000_core.c
+++ b/drivers/staging/iio/accel/sca3000_core.c
@@ -223,33 +223,6 @@ error_ret:
return ret;
}
-#ifdef SCA3000_DEBUG
-/**
- * sca3000_check_status() check the status register
- *
- * Only used for debugging purposes
- **/
-static int sca3000_check_status(struct device *dev)
-{
- int ret;
- struct iio_dev *indio_dev = dev_to_iio_dev(dev);
- struct sca3000_state *st = iio_priv(indio_dev);
-
- mutex_lock(&st->lock);
- ret = sca3000_read_data_short(st, SCA3000_REG_ADDR_STATUS, 1);
- if (ret < 0)
- goto error_ret;
- if (st->rx[0] & SCA3000_EEPROM_CS_ERROR)
- dev_err(dev, "eeprom error\n");
- if (st->rx[0] & SCA3000_SPI_FRAME_ERROR)
- dev_err(dev, "Previous SPI Frame was corrupt\n");
-
-error_ret:
- mutex_unlock(&st->lock);
- return ret;
-}
-#endif /* SCA3000_DEBUG */
-
/**
* sca3000_show_rev() - sysfs interface to read the chip revision number
**/
@@ -459,6 +432,8 @@ static const struct iio_chan_spec sca3000_channels_with_temp[] = {
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
.info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) |
BIT(IIO_CHAN_INFO_OFFSET),
+ /* No buffer support */
+ .scan_index = -1,
},
};
@@ -1154,17 +1129,6 @@ static int sca3000_probe(struct spi_device *spi)
if (ret < 0)
return ret;
- ret = iio_buffer_register(indio_dev,
- sca3000_channels,
- ARRAY_SIZE(sca3000_channels));
- if (ret < 0)
- goto error_unregister_dev;
- if (indio_dev->buffer) {
- iio_scan_mask_set(indio_dev, indio_dev->buffer, 0);
- iio_scan_mask_set(indio_dev, indio_dev->buffer, 1);
- iio_scan_mask_set(indio_dev, indio_dev->buffer, 2);
- }
-
if (spi->irq) {
ret = request_threaded_irq(spi->irq,
NULL,
@@ -1173,7 +1137,7 @@ static int sca3000_probe(struct spi_device *spi)
"sca3000",
indio_dev);
if (ret)
- goto error_unregister_ring;
+ goto error_unregister_dev;
}
sca3000_register_ring_funcs(indio_dev);
ret = sca3000_clean_setup(st);
@@ -1184,8 +1148,6 @@ static int sca3000_probe(struct spi_device *spi)
error_free_irq:
if (spi->irq)
free_irq(spi->irq, indio_dev);
-error_unregister_ring:
- iio_buffer_unregister(indio_dev);
error_unregister_dev:
iio_device_unregister(indio_dev);
return ret;
@@ -1219,7 +1181,6 @@ static int sca3000_remove(struct spi_device *spi)
if (spi->irq)
free_irq(spi->irq, indio_dev);
iio_device_unregister(indio_dev);
- iio_buffer_unregister(indio_dev);
sca3000_unconfigure_ring(indio_dev);
return 0;
diff --git a/drivers/staging/iio/accel/sca3000_ring.c b/drivers/staging/iio/accel/sca3000_ring.c
index 157827651bfa..f76a26885808 100644
--- a/drivers/staging/iio/accel/sca3000_ring.c
+++ b/drivers/staging/iio/accel/sca3000_ring.c
@@ -129,26 +129,11 @@ error_ret:
return ret ? ret : num_read;
}
-/* This is only valid with all 3 elements enabled */
-static int sca3000_ring_get_length(struct iio_buffer *r)
-{
- return 64;
-}
-
-/* only valid if resolution is kept at 11bits */
-static int sca3000_ring_get_bytes_per_datum(struct iio_buffer *r)
-{
- return 6;
-}
-
static bool sca3000_ring_buf_data_available(struct iio_buffer *r)
{
return r->stufftoread;
}
-static IIO_BUFFER_ENABLE_ATTR;
-static IIO_BUFFER_LENGTH_ATTR;
-
/**
* sca3000_query_ring_int() is the hardware ring status interrupt enabled
**/
@@ -238,20 +223,13 @@ static IIO_DEVICE_ATTR(in_accel_scale,
* only apply to the ring buffer. At all times full rate and accuracy
* is available via direct reading from registers.
*/
-static struct attribute *sca3000_ring_attributes[] = {
- &dev_attr_length.attr,
- &dev_attr_enable.attr,
+static const struct attribute *sca3000_ring_attributes[] = {
&iio_dev_attr_50_percent.dev_attr.attr,
&iio_dev_attr_75_percent.dev_attr.attr,
&iio_dev_attr_in_accel_scale.dev_attr.attr,
NULL,
};
-static struct attribute_group sca3000_ring_attr = {
- .attrs = sca3000_ring_attributes,
- .name = "buffer",
-};
-
static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev)
{
struct iio_buffer *buf;
@@ -264,7 +242,8 @@ static struct iio_buffer *sca3000_rb_allocate(struct iio_dev *indio_dev)
ring->private = indio_dev;
buf = &ring->buf;
buf->stufftoread = 0;
- buf->attrs = &sca3000_ring_attr;
+ buf->length = 64;
+ buf->attrs = sca3000_ring_attributes;
iio_buffer_init(buf);
return buf;
@@ -277,8 +256,6 @@ static void sca3000_ring_release(struct iio_buffer *r)
static const struct iio_buffer_access_funcs sca3000_ring_access_funcs = {
.read_first_n = &sca3000_read_first_n_hw_rb,
- .get_length = &sca3000_ring_get_length,
- .get_bytes_per_datum = &sca3000_ring_get_bytes_per_datum,
.data_available = sca3000_ring_buf_data_available,
.release = sca3000_ring_release,
};
diff --git a/drivers/staging/iio/adc/ad7192.c b/drivers/staging/iio/adc/ad7192.c
index f6526aa22e8a..6f8ce6c6574b 100644
--- a/drivers/staging/iio/adc/ad7192.c
+++ b/drivers/staging/iio/adc/ad7192.c
@@ -612,7 +612,7 @@ static int ad7192_probe(struct spi_device *spi)
const struct ad7192_platform_data *pdata = spi->dev.platform_data;
struct ad7192_state *st;
struct iio_dev *indio_dev;
- int ret , voltage_uv = 0;
+ int ret, voltage_uv = 0;
if (!pdata) {
dev_err(&spi->dev, "no platform data?\n");
diff --git a/drivers/staging/iio/adc/mxs-lradc.c b/drivers/staging/iio/adc/mxs-lradc.c
index f053535385bf..d9d6fad7cb00 100644
--- a/drivers/staging/iio/adc/mxs-lradc.c
+++ b/drivers/staging/iio/adc/mxs-lradc.c
@@ -436,7 +436,14 @@ static void mxs_lradc_setup_ts_channel(struct mxs_lradc *lradc, unsigned ch)
*/
mxs_lradc_reg_clear(lradc, LRADC_CH_VALUE_MASK, LRADC_CH(ch));
- /* prepare the delay/loop unit according to the oversampling count */
+ /*
+ * prepare the delay/loop unit according to the oversampling count
+ *
+ * from the datasheet:
+ * "The DELAY fields in HW_LRADC_DELAY0, HW_LRADC_DELAY1,
+ * HW_LRADC_DELAY2, and HW_LRADC_DELAY3 must be non-zero; otherwise,
+ * the LRADC will not trigger the delay group."
+ */
mxs_lradc_reg_wrt(lradc, LRADC_DELAY_TRIGGER(1 << ch) |
LRADC_DELAY_TRIGGER_DELAYS(0) |
LRADC_DELAY_LOOP(lradc->over_sample_cnt - 1) |
@@ -1495,20 +1502,38 @@ static int mxs_lradc_probe_touchscreen(struct mxs_lradc *lradc,
return -EINVAL;
}
- lradc->over_sample_cnt = 4;
- ret = of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt);
- if (ret == 0)
+ if (of_property_read_u32(lradc_node, "fsl,ave-ctrl", &adapt)) {
+ lradc->over_sample_cnt = 4;
+ } else {
+ if (adapt < 1 || adapt > 32) {
+ dev_err(lradc->dev, "Invalid sample count (%u)\n",
+ adapt);
+ return -EINVAL;
+ }
lradc->over_sample_cnt = adapt;
+ }
- lradc->over_sample_delay = 2;
- ret = of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt);
- if (ret == 0)
+ if (of_property_read_u32(lradc_node, "fsl,ave-delay", &adapt)) {
+ lradc->over_sample_delay = 2;
+ } else {
+ if (adapt < 2 || adapt > LRADC_DELAY_DELAY_MASK + 1) {
+ dev_err(lradc->dev, "Invalid sample delay (%u)\n",
+ adapt);
+ return -EINVAL;
+ }
lradc->over_sample_delay = adapt;
+ }
- lradc->settling_delay = 10;
- ret = of_property_read_u32(lradc_node, "fsl,settling", &adapt);
- if (ret == 0)
+ if (of_property_read_u32(lradc_node, "fsl,settling", &adapt)) {
+ lradc->settling_delay = 10;
+ } else {
+ if (adapt < 1 || adapt > LRADC_DELAY_DELAY_MASK) {
+ dev_err(lradc->dev, "Invalid settling delay (%u)\n",
+ adapt);
+ return -EINVAL;
+ }
lradc->settling_delay = adapt;
+ }
return 0;
}
diff --git a/drivers/staging/iio/iio_dummy_evgen.c b/drivers/staging/iio/iio_dummy_evgen.c
index 5a804f16ec2f..59ad5a3efe9c 100644
--- a/drivers/staging/iio/iio_dummy_evgen.c
+++ b/drivers/staging/iio/iio_dummy_evgen.c
@@ -33,6 +33,7 @@
* @base: base of irq range
* @enabled: mask of which irqs are enabled
* @inuse: mask of which irqs are connected
+ * @regs: irq regs we are faking
* @lock: protect the evgen state
*/
struct iio_dummy_eventgen {
@@ -40,6 +41,7 @@ struct iio_dummy_eventgen {
int base;
bool enabled[IIO_EVENTGEN_NO];
bool inuse[IIO_EVENTGEN_NO];
+ struct iio_dummy_regs regs[IIO_EVENTGEN_NO];
struct mutex lock;
};
@@ -136,6 +138,12 @@ int iio_dummy_evgen_release_irq(int irq)
}
EXPORT_SYMBOL_GPL(iio_dummy_evgen_release_irq);
+struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq)
+{
+ return &iio_evgen->regs[irq - iio_evgen->base];
+}
+EXPORT_SYMBOL_GPL(iio_dummy_evgen_get_regs);
+
static void iio_dummy_evgen_free(void)
{
irq_free_descs(iio_evgen->base, IIO_EVENTGEN_NO);
@@ -153,6 +161,15 @@ static ssize_t iio_evgen_poke(struct device *dev,
size_t len)
{
struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
+ unsigned long event;
+ int ret;
+
+ ret = kstrtoul(buf, 10, &event);
+ if (ret)
+ return ret;
+
+ iio_evgen->regs[this_attr->address].reg_id = this_attr->address;
+ iio_evgen->regs[this_attr->address].reg_data = event;
if (iio_evgen->enabled[this_attr->address])
handle_nested_irq(iio_evgen->base + this_attr->address);
diff --git a/drivers/staging/iio/iio_dummy_evgen.h b/drivers/staging/iio/iio_dummy_evgen.h
index 3a180811b315..2ac293ab7c8f 100644
--- a/drivers/staging/iio/iio_dummy_evgen.h
+++ b/drivers/staging/iio/iio_dummy_evgen.h
@@ -1,6 +1,12 @@
#ifndef _IIO_DUMMY_EVGEN_H_
#define _IIO_DUMMY_EVGEN_H_
+struct iio_dummy_regs {
+ u32 reg_id;
+ u32 reg_data;
+};
+
+struct iio_dummy_regs *iio_dummy_evgen_get_regs(int irq);
int iio_dummy_evgen_get_irq(void);
int iio_dummy_evgen_release_irq(int irq);
diff --git a/drivers/staging/iio/iio_simple_dummy.c b/drivers/staging/iio/iio_simple_dummy.c
index bf78e6f0311f..e4520213f627 100644
--- a/drivers/staging/iio/iio_simple_dummy.c
+++ b/drivers/staging/iio/iio_simple_dummy.c
@@ -69,6 +69,34 @@ static const struct iio_event_spec iio_dummy_event = {
.mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
};
+/*
+ * simple step detect event - triggered when a step is detected
+ */
+static const struct iio_event_spec step_detect_event = {
+ .type = IIO_EV_TYPE_CHANGE,
+ .dir = IIO_EV_DIR_NONE,
+ .mask_separate = BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple transition event - triggered when the reported running confidence
+ * value rises above a threshold value
+ */
+static const struct iio_event_spec iio_running_event = {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_RISING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
+
+/*
+ * simple transition event - triggered when the reported walking confidence
+ * value falls under a threshold value
+ */
+static const struct iio_event_spec iio_walking_event = {
+ .type = IIO_EV_TYPE_THRESH,
+ .dir = IIO_EV_DIR_FALLING,
+ .mask_separate = BIT(IIO_EV_INFO_VALUE) | BIT(IIO_EV_INFO_ENABLE),
+};
#endif
/*
@@ -211,10 +239,44 @@ static const struct iio_chan_spec iio_dummy_channels[] = {
{
.type = IIO_VOLTAGE,
.info_mask_separate = BIT(IIO_CHAN_INFO_RAW),
+ .scan_index = -1, /* No buffer support */
.output = 1,
.indexed = 1,
.channel = 0,
},
+ {
+ .type = IIO_STEPS,
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_ENABLE) |
+ BIT(IIO_CHAN_INFO_CALIBHEIGHT),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+ .event_spec = &step_detect_event,
+ .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_RUNNING,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+ .event_spec = &iio_running_event,
+ .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+ },
+ {
+ .type = IIO_ACTIVITY,
+ .modified = 1,
+ .channel2 = IIO_MOD_WALKING,
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .scan_index = -1, /* No buffer support */
+#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
+ .event_spec = &iio_walking_event,
+ .num_event_specs = 1,
+#endif /* CONFIG_IIO_SIMPLE_DUMMY_EVENTS */
+ },
};
/**
@@ -263,24 +325,55 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
break;
}
break;
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = st->steps;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_ACTIVITY:
+ switch (chan->channel2) {
+ case IIO_MOD_RUNNING:
+ *val = st->activity_running;
+ ret = IIO_VAL_INT;
+ break;
+ case IIO_MOD_WALKING:
+ *val = st->activity_walking;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
case IIO_CHAN_INFO_OFFSET:
/* only single ended adc -> 7 */
*val = 7;
ret = IIO_VAL_INT;
break;
case IIO_CHAN_INFO_SCALE:
- switch (chan->differential) {
- case 0:
- /* only single ended adc -> 0.001333 */
- *val = 0;
- *val2 = 1333;
- ret = IIO_VAL_INT_PLUS_MICRO;
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ switch (chan->differential) {
+ case 0:
+ /* only single ended adc -> 0.001333 */
+ *val = 0;
+ *val2 = 1333;
+ ret = IIO_VAL_INT_PLUS_MICRO;
+ break;
+ case 1:
+ /* all differential adc channels ->
+ * 0.000001344 */
+ *val = 0;
+ *val2 = 1344;
+ ret = IIO_VAL_INT_PLUS_NANO;
+ }
+ break;
+ default:
break;
- case 1:
- /* all differential adc channels -> 0.000001344 */
- *val = 0;
- *val2 = 1344;
- ret = IIO_VAL_INT_PLUS_NANO;
}
break;
case IIO_CHAN_INFO_CALIBBIAS:
@@ -298,6 +391,27 @@ static int iio_dummy_read_raw(struct iio_dev *indio_dev,
*val2 = 33;
ret = IIO_VAL_INT_PLUS_NANO;
break;
+ case IIO_CHAN_INFO_ENABLE:
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = st->steps_enabled;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ break;
+ }
+ break;
+ case IIO_CHAN_INFO_CALIBHEIGHT:
+ switch (chan->type) {
+ case IIO_STEPS:
+ *val = st->height;
+ ret = IIO_VAL_INT;
+ break;
+ default:
+ break;
+ }
+ break;
+
default:
break;
}
@@ -330,14 +444,45 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
switch (mask) {
case IIO_CHAN_INFO_RAW:
- if (chan->output == 0)
+ switch (chan->type) {
+ case IIO_VOLTAGE:
+ if (chan->output == 0)
+ return -EINVAL;
+
+ /* Locking not required as writing single value */
+ mutex_lock(&st->lock);
+ st->dac_val = val;
+ mutex_unlock(&st->lock);
+ return 0;
+ default:
return -EINVAL;
-
- /* Locking not required as writing single value */
- mutex_lock(&st->lock);
- st->dac_val = val;
- mutex_unlock(&st->lock);
- return 0;
+ }
+ case IIO_CHAN_INFO_PROCESSED:
+ switch (chan->type) {
+ case IIO_STEPS:
+ mutex_lock(&st->lock);
+ st->steps = val;
+ mutex_unlock(&st->lock);
+ return 0;
+ case IIO_ACTIVITY:
+ if (val < 0)
+ val = 0;
+ if (val > 100)
+ val = 100;
+ switch (chan->channel2) {
+ case IIO_MOD_RUNNING:
+ st->activity_running = val;
+ return 0;
+ case IIO_MOD_WALKING:
+ st->activity_walking = val;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ break;
+ default:
+ return -EINVAL;
+ }
case IIO_CHAN_INFO_CALIBSCALE:
mutex_lock(&st->lock);
/* Compare against table - hard matching here */
@@ -356,6 +501,24 @@ static int iio_dummy_write_raw(struct iio_dev *indio_dev,
st->accel_calibbias = val;
mutex_unlock(&st->lock);
return 0;
+ case IIO_CHAN_INFO_ENABLE:
+ switch (chan->type) {
+ case IIO_STEPS:
+ mutex_lock(&st->lock);
+ st->steps_enabled = val;
+ mutex_unlock(&st->lock);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ case IIO_CHAN_INFO_CALIBHEIGHT:
+ switch (chan->type) {
+ case IIO_STEPS:
+ st->height = val;
+ return 0;
+ default:
+ return -EINVAL;
+ }
default:
return -EINVAL;
@@ -395,6 +558,9 @@ static int iio_dummy_init_device(struct iio_dev *indio_dev)
st->accel_val = 34;
st->accel_calibbias = -7;
st->accel_calibscale = &dummy_scales[0];
+ st->steps = 47;
+ st->activity_running = 98;
+ st->activity_walking = 4;
return 0;
}
@@ -475,13 +641,7 @@ static int iio_dummy_probe(int index)
if (ret < 0)
goto error_free_device;
- /*
- * Configure buffered capture support and register the channels with the
- * buffer, but avoid the output channel being registered by reducing the
- * number of channels by 1.
- */
- ret = iio_simple_dummy_configure_buffer(indio_dev,
- iio_dummy_channels, 5);
+ ret = iio_simple_dummy_configure_buffer(indio_dev);
if (ret < 0)
goto error_unregister_events;
diff --git a/drivers/staging/iio/iio_simple_dummy.h b/drivers/staging/iio/iio_simple_dummy.h
index 3027aed79093..34989bf248a7 100644
--- a/drivers/staging/iio/iio_simple_dummy.h
+++ b/drivers/staging/iio/iio_simple_dummy.h
@@ -13,6 +13,7 @@
#include <linux/kernel.h>
struct iio_dummy_accel_calibscale;
+struct iio_dummy_regs;
/**
* struct iio_dummy_state - device instance specific state.
@@ -33,8 +34,14 @@ struct iio_dummy_state {
int differential_adc_val[2];
int accel_val;
int accel_calibbias;
+ int activity_running;
+ int activity_walking;
const struct iio_dummy_accel_calibscale *accel_calibscale;
struct mutex lock;
+ struct iio_dummy_regs *regs;
+ int steps_enabled;
+ int steps;
+ int height;
#ifdef CONFIG_IIO_SIMPLE_DUMMY_EVENTS
int event_irq;
int event_val;
@@ -107,12 +114,10 @@ enum iio_simple_dummy_scan_elements {
};
#ifdef CONFIG_IIO_SIMPLE_DUMMY_BUFFER
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
- const struct iio_chan_spec *channels, unsigned int num_channels);
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev);
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev);
#else
-static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
- const struct iio_chan_spec *channels, unsigned int num_channels)
+static inline int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{
return 0;
};
diff --git a/drivers/staging/iio/iio_simple_dummy_buffer.c b/drivers/staging/iio/iio_simple_dummy_buffer.c
index fd74f9166a5f..360a4c980722 100644
--- a/drivers/staging/iio/iio_simple_dummy_buffer.c
+++ b/drivers/staging/iio/iio_simple_dummy_buffer.c
@@ -115,14 +115,13 @@ static const struct iio_buffer_setup_ops iio_simple_dummy_buffer_setup_ops = {
.predisable = &iio_triggered_buffer_predisable,
};
-int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
- const struct iio_chan_spec *channels, unsigned int num_channels)
+int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev)
{
int ret;
struct iio_buffer *buffer;
/* Allocate a buffer to use - here a kfifo */
- buffer = iio_kfifo_allocate(indio_dev);
+ buffer = iio_kfifo_allocate();
if (buffer == NULL) {
ret = -ENOMEM;
goto error_ret;
@@ -173,14 +172,8 @@ int iio_simple_dummy_configure_buffer(struct iio_dev *indio_dev,
*/
indio_dev->modes |= INDIO_BUFFER_TRIGGERED;
- ret = iio_buffer_register(indio_dev, channels, num_channels);
- if (ret)
- goto error_dealloc_pollfunc;
-
return 0;
-error_dealloc_pollfunc:
- iio_dealloc_pollfunc(indio_dev->pollfunc);
error_free_buffer:
iio_kfifo_free(indio_dev->buffer);
error_ret:
@@ -194,7 +187,6 @@ error_ret:
*/
void iio_simple_dummy_unconfigure_buffer(struct iio_dev *indio_dev)
{
- iio_buffer_unregister(indio_dev);
iio_dealloc_pollfunc(indio_dev->pollfunc);
iio_kfifo_free(indio_dev->buffer);
}
diff --git a/drivers/staging/iio/iio_simple_dummy_events.c b/drivers/staging/iio/iio_simple_dummy_events.c
index 64b45b077549..a5cd3bb219fe 100644
--- a/drivers/staging/iio/iio_simple_dummy_events.c
+++ b/drivers/staging/iio/iio_simple_dummy_events.c
@@ -72,6 +72,22 @@ int iio_simple_dummy_write_event_config(struct iio_dev *indio_dev,
st->event_en = state;
else
return -EINVAL;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case IIO_ACTIVITY:
+ switch (type) {
+ case IIO_EV_TYPE_THRESH:
+ st->event_en = state;
+ break;
+ default:
+ return -EINVAL;
+ }
+ case IIO_STEPS:
+ switch (type) {
+ case IIO_EV_TYPE_CHANGE:
+ st->event_en = state;
break;
default:
return -EINVAL;
@@ -148,12 +164,50 @@ int iio_simple_dummy_write_event_value(struct iio_dev *indio_dev,
static irqreturn_t iio_simple_dummy_event_handler(int irq, void *private)
{
struct iio_dev *indio_dev = private;
+ struct iio_dummy_state *st = iio_priv(indio_dev);
+
+ dev_dbg(&indio_dev->dev, "id %x event %x\n",
+ st->regs->reg_id, st->regs->reg_data);
+
+ switch (st->regs->reg_data) {
+ case 0:
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
+ IIO_EV_DIR_RISING,
+ IIO_EV_TYPE_THRESH, 0, 0, 0),
+ iio_get_time_ns());
+ break;
+ case 1:
+ if (st->activity_running > st->event_val)
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+ IIO_MOD_RUNNING,
+ IIO_EV_DIR_RISING,
+ IIO_EV_TYPE_THRESH,
+ 0, 0, 0),
+ iio_get_time_ns());
+ break;
+ case 2:
+ if (st->activity_walking < st->event_val)
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_ACTIVITY, 0,
+ IIO_MOD_WALKING,
+ IIO_EV_DIR_FALLING,
+ IIO_EV_TYPE_THRESH,
+ 0, 0, 0),
+ iio_get_time_ns());
+ break;
+ case 3:
+ iio_push_event(indio_dev,
+ IIO_EVENT_CODE(IIO_STEPS, 0, IIO_NO_MOD,
+ IIO_EV_DIR_NONE,
+ IIO_EV_TYPE_CHANGE, 0, 0, 0),
+ iio_get_time_ns());
+ break;
+ default:
+ break;
+ }
- iio_push_event(indio_dev,
- IIO_EVENT_CODE(IIO_VOLTAGE, 0, 0,
- IIO_EV_DIR_RISING,
- IIO_EV_TYPE_THRESH, 0, 0, 0),
- iio_get_time_ns());
return IRQ_HANDLED;
}
@@ -179,6 +233,8 @@ int iio_simple_dummy_events_register(struct iio_dev *indio_dev)
ret = st->event_irq;
goto error_ret;
}
+ st->regs = iio_dummy_evgen_get_regs(st->event_irq);
+
ret = request_threaded_irq(st->event_irq,
NULL,
&iio_simple_dummy_event_handler,
diff --git a/drivers/staging/iio/impedance-analyzer/ad5933.c b/drivers/staging/iio/impedance-analyzer/ad5933.c
index b6bd609c3655..79194399e040 100644
--- a/drivers/staging/iio/impedance-analyzer/ad5933.c
+++ b/drivers/staging/iio/impedance-analyzer/ad5933.c
@@ -89,7 +89,6 @@
struct ad5933_state {
struct i2c_client *client;
struct regulator *reg;
- struct ad5933_platform_data *pdata;
struct delayed_work work;
unsigned long mclk_hz;
unsigned char ctrl_hb;
@@ -113,7 +112,8 @@ static const struct iio_chan_spec ad5933_channels[] = {
.type = IIO_TEMP,
.indexed = 1,
.channel = 0,
- .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW) |
+ BIT(IIO_CHAN_INFO_SCALE),
.address = AD5933_REG_TEMP_DATA,
.scan_index = -1,
.scan_type = {
@@ -360,11 +360,11 @@ static ssize_t ad5933_show(struct device *dev,
mutex_lock(&indio_dev->mlock);
switch ((u32) this_attr->address) {
case AD5933_OUT_RANGE:
- len = sprintf(buf, "%d\n",
+ len = sprintf(buf, "%u\n",
st->range_avail[(st->ctrl_hb >> 1) & 0x3]);
break;
case AD5933_OUT_RANGE_AVAIL:
- len = sprintf(buf, "%d %d %d %d\n", st->range_avail[0],
+ len = sprintf(buf, "%u %u %u %u\n", st->range_avail[0],
st->range_avail[3], st->range_avail[2],
st->range_avail[1]);
break;
@@ -520,12 +520,11 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
{
struct ad5933_state *st = iio_priv(indio_dev);
__be16 dat;
- int ret = -EINVAL;
+ int ret;
- mutex_lock(&indio_dev->mlock);
switch (m) {
case IIO_CHAN_INFO_RAW:
- case IIO_CHAN_INFO_PROCESSED:
+ mutex_lock(&indio_dev->mlock);
if (iio_buffer_enabled(indio_dev)) {
ret = -EBUSY;
goto out;
@@ -543,16 +542,16 @@ static int ad5933_read_raw(struct iio_dev *indio_dev,
if (ret < 0)
goto out;
mutex_unlock(&indio_dev->mlock);
- ret = be16_to_cpu(dat);
- /* Temp in Milli degrees Celsius */
- if (ret < 8192)
- *val = ret * 1000 / 32;
- else
- *val = (ret - 16384) * 1000 / 32;
+ *val = sign_extend32(be16_to_cpu(dat), 13);
return IIO_VAL_INT;
+ case IIO_CHAN_INFO_SCALE:
+ *val = 1000;
+ *val2 = 5;
+ return IIO_VAL_FRACTIONAL_LOG2;
}
+ return -EINVAL;
out:
mutex_unlock(&indio_dev->mlock);
return ret;
@@ -626,7 +625,7 @@ static int ad5933_register_ring_funcs_and_init(struct iio_dev *indio_dev)
{
struct iio_buffer *buffer;
- buffer = iio_kfifo_allocate(indio_dev);
+ buffer = iio_kfifo_allocate();
if (!buffer)
return -ENOMEM;
@@ -712,9 +711,7 @@ static int ad5933_probe(struct i2c_client *client,
st->client = client;
if (!pdata)
- st->pdata = &ad5933_default_pdata;
- else
- st->pdata = pdata;
+ pdata = &ad5933_default_pdata;
st->reg = devm_regulator_get(&client->dev, "vcc");
if (!IS_ERR(st->reg)) {
@@ -727,10 +724,10 @@ static int ad5933_probe(struct i2c_client *client,
if (voltage_uv)
st->vref_mv = voltage_uv / 1000;
else
- st->vref_mv = st->pdata->vref_mv;
+ st->vref_mv = pdata->vref_mv;
- if (st->pdata->ext_clk_Hz) {
- st->mclk_hz = st->pdata->ext_clk_Hz;
+ if (pdata->ext_clk_Hz) {
+ st->mclk_hz = pdata->ext_clk_Hz;
st->ctrl_lb = AD5933_CTRL_EXT_SYSCLK;
} else {
st->mclk_hz = AD5933_INT_OSC_FREQ_Hz;
@@ -752,27 +749,16 @@ static int ad5933_probe(struct i2c_client *client,
if (ret)
goto error_disable_reg;
- ret = iio_buffer_register(indio_dev, ad5933_channels,
- ARRAY_SIZE(ad5933_channels));
- if (ret)
- goto error_unreg_ring;
-
- /* enable both REAL and IMAG channels by default */
- iio_scan_mask_set(indio_dev, indio_dev->buffer, 0);
- iio_scan_mask_set(indio_dev, indio_dev->buffer, 1);
-
ret = ad5933_setup(st);
if (ret)
- goto error_uninitialize_ring;
+ goto error_unreg_ring;
ret = iio_device_register(indio_dev);
if (ret)
- goto error_uninitialize_ring;
+ goto error_unreg_ring;
return 0;
-error_uninitialize_ring:
- iio_buffer_unregister(indio_dev);
error_unreg_ring:
iio_kfifo_free(indio_dev->buffer);
error_disable_reg:
@@ -788,7 +774,6 @@ static int ad5933_remove(struct i2c_client *client)
struct ad5933_state *st = iio_priv(indio_dev);
iio_device_unregister(indio_dev);
- iio_buffer_unregister(indio_dev);
iio_kfifo_free(indio_dev->buffer);
if (!IS_ERR(st->reg))
regulator_disable(st->reg);
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index e969107ddb47..6440e3b293ca 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -537,8 +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 = "isl,isl29028", },
- { .compatible = "isil,isl29028", },/* deprecated, don't use */
+ { .compatible = "isl,isl29028", }, /* for backward compat., don't use */
+ { .compatible = "isil,isl29028", },
{ },
};
MODULE_DEVICE_TABLE(of, isl29028_of_match);
diff --git a/drivers/staging/iio/light/tsl2583.c b/drivers/staging/iio/light/tsl2583.c
index cc4ddcce4ff9..8afae8e33d56 100644
--- a/drivers/staging/iio/light/tsl2583.c
+++ b/drivers/staging/iio/light/tsl2583.c
@@ -692,7 +692,7 @@ static ssize_t taos_luxtable_show(struct device *dev,
int offset = 0;
for (i = 0; i < ARRAY_SIZE(taos_device_lux); i++) {
- offset += sprintf(buf + offset, "%d,%d,%d,",
+ offset += sprintf(buf + offset, "%u,%u,%u,",
taos_device_lux[i].ratio,
taos_device_lux[i].ch0,
taos_device_lux[i].ch1);
diff --git a/drivers/staging/iio/light/tsl2x7x_core.c b/drivers/staging/iio/light/tsl2x7x_core.c
index 423f96bdf595..4a5dc26fed4c 100644
--- a/drivers/staging/iio/light/tsl2x7x_core.c
+++ b/drivers/staging/iio/light/tsl2x7x_core.c
@@ -1147,7 +1147,7 @@ static ssize_t tsl2x7x_luxtable_show(struct device *dev,
int offset = 0;
while (i < (TSL2X7X_MAX_LUX_TABLE_SIZE * 3)) {
- offset += snprintf(buf + offset, PAGE_SIZE, "%d,%d,%d,",
+ offset += snprintf(buf + offset, PAGE_SIZE, "%u,%u,%u,",
chip->tsl2x7x_device_lux[i].ratio,
chip->tsl2x7x_device_lux[i].ch0,
chip->tsl2x7x_device_lux[i].ch1);
diff --git a/drivers/staging/iio/meter/ade7758.h b/drivers/staging/iio/meter/ade7758.h
index e8c98cf57070..f6739e2c24b1 100644
--- a/drivers/staging/iio/meter/ade7758.h
+++ b/drivers/staging/iio/meter/ade7758.h
@@ -145,7 +145,6 @@ ssize_t ade7758_read_data_from_ring(struct device *dev,
int ade7758_configure_ring(struct iio_dev *indio_dev);
void ade7758_unconfigure_ring(struct iio_dev *indio_dev);
-void ade7758_uninitialize_ring(struct iio_dev *indio_dev);
int ade7758_set_irq(struct device *dev, bool enable);
int ade7758_spi_write_reg_8(struct device *dev,
diff --git a/drivers/staging/iio/meter/ade7758_core.c b/drivers/staging/iio/meter/ade7758_core.c
index fb373b89dcc2..70e96b20c2eb 100644
--- a/drivers/staging/iio/meter/ade7758_core.c
+++ b/drivers/staging/iio/meter/ade7758_core.c
@@ -850,23 +850,15 @@ static int ade7758_probe(struct spi_device *spi)
if (ret)
goto error_free_tx;
- ret = iio_buffer_register(indio_dev,
- &ade7758_channels[0],
- ARRAY_SIZE(ade7758_channels));
- if (ret) {
- dev_err(&spi->dev, "failed to initialize the ring\n");
- goto error_unreg_ring_funcs;
- }
-
/* Get the device into a sane initial state */
ret = ade7758_initial_setup(indio_dev);
if (ret)
- goto error_uninitialize_ring;
+ goto error_unreg_ring_funcs;
if (spi->irq) {
ret = ade7758_probe_trigger(indio_dev);
if (ret)
- goto error_uninitialize_ring;
+ goto error_unreg_ring_funcs;
}
ret = iio_device_register(indio_dev);
@@ -878,8 +870,6 @@ static int ade7758_probe(struct spi_device *spi)
error_remove_trigger:
if (spi->irq)
ade7758_remove_trigger(indio_dev);
-error_uninitialize_ring:
- ade7758_uninitialize_ring(indio_dev);
error_unreg_ring_funcs:
ade7758_unconfigure_ring(indio_dev);
error_free_tx:
@@ -897,7 +887,6 @@ static int ade7758_remove(struct spi_device *spi)
iio_device_unregister(indio_dev);
ade7758_stop_device(&indio_dev->dev);
ade7758_remove_trigger(indio_dev);
- ade7758_uninitialize_ring(indio_dev);
ade7758_unconfigure_ring(indio_dev);
kfree(st->tx);
kfree(st->rx);
diff --git a/drivers/staging/iio/meter/ade7758_ring.c b/drivers/staging/iio/meter/ade7758_ring.c
index 6e9006490742..3792b5761645 100644
--- a/drivers/staging/iio/meter/ade7758_ring.c
+++ b/drivers/staging/iio/meter/ade7758_ring.c
@@ -118,7 +118,7 @@ int ade7758_configure_ring(struct iio_dev *indio_dev)
struct iio_buffer *buffer;
int ret = 0;
- buffer = iio_kfifo_allocate(indio_dev);
+ buffer = iio_kfifo_allocate();
if (!buffer) {
ret = -ENOMEM;
return ret;
@@ -180,8 +180,3 @@ error_iio_kfifo_free:
iio_kfifo_free(indio_dev->buffer);
return ret;
}
-
-void ade7758_uninitialize_ring(struct iio_dev *indio_dev)
-{
- iio_buffer_unregister(indio_dev);
-}
diff --git a/drivers/staging/iio/meter/ade7759.c b/drivers/staging/iio/meter/ade7759.c
index 7d217430616a..b0c7dbc8a428 100644
--- a/drivers/staging/iio/meter/ade7759.c
+++ b/drivers/staging/iio/meter/ade7759.c
@@ -116,7 +116,7 @@ static int ade7759_spi_read_reg_40(struct device *dev,
mutex_lock(&st->buf_lock);
st->tx[0] = ADE7759_READ_REG(reg_address);
- memset(&st->tx[1], 0 , 5);
+ memset(&st->tx[1], 0, 5);
ret = spi_sync_transfer(st->us, xfers, ARRAY_SIZE(xfers));
if (ret) {
diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig
deleted file mode 100644
index 4f1219b4c692..000000000000
--- a/drivers/staging/line6/Kconfig
+++ /dev/null
@@ -1,38 +0,0 @@
-menuconfig LINE6_USB
- tristate "Line6 USB support"
- depends on USB && SND
- select SND_RAWMIDI
- select SND_PCM
- help
- This is a driver for the guitar amp, cab, and effects modeller
- PODxt Pro by Line6 (and similar devices), supporting the
- following features:
- * Reading/writing individual parameters
- * Reading/writing complete channel, effects setup, and amp
- setup data
- * Channel switching
- * Virtual MIDI interface
- * Tuner access
- * Playback/capture/mixer device for any ALSA-compatible PCM
- audio application
- * Signal routing (record clean/processed guitar signal,
- re-amping)
-
- Preliminary support for the Variax Workbench and TonePort
- devices is included.
-
-if LINE6_USB
-
-config LINE6_USB_IMPULSE_RESPONSE
- bool "measure impulse response"
- default n
- help
- Say Y here to add code to measure the impulse response of a Line6
- device. This is more accurate than user-space methods since it
- bypasses any PCM data buffering (e.g., by ALSA or jack). This is
- useful for assessing the performance of new devices, but is not
- required for normal operation.
-
- If unsure, say N.
-
-endif # LINE6_USB
diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile
deleted file mode 100644
index ae5c374b0f87..000000000000
--- a/drivers/staging/line6/Makefile
+++ /dev/null
@@ -1,14 +0,0 @@
-obj-$(CONFIG_LINE6_USB) += line6usb.o
-
-line6usb-y := \
- audio.o \
- capture.o \
- driver.o \
- midi.o \
- midibuf.o \
- pcm.o \
- playback.o \
- pod.o \
- toneport.o \
- variax.o \
- podhd.o
diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c
deleted file mode 100644
index 171d80c1b020..000000000000
--- a/drivers/staging/line6/audio.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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 <sound/core.h>
-#include <sound/initval.h>
-#include <linux/export.h>
-
-#include "driver.h"
-#include "audio.h"
-
-/*
- Initialize the Line6 USB audio system.
-*/
-int line6_init_audio(struct usb_line6 *line6)
-{
- struct snd_card *card;
- int err;
-
- err = snd_card_new(line6->ifcdev,
- SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
- THIS_MODULE, 0, &card);
- if (err < 0)
- return err;
-
- line6->card = card;
-
- strcpy(card->id, line6->properties->id);
- strcpy(card->driver, DRIVER_NAME);
- strcpy(card->shortname, line6->properties->name);
- /* longname is 80 chars - see asound.h */
- sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
- dev_name(line6->ifcdev));
- return 0;
-}
-
-/*
- Register the Line6 USB audio system.
-*/
-int line6_register_audio(struct usb_line6 *line6)
-{
- int err;
-
- err = snd_card_register(line6->card);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-/*
- Cleanup the Line6 USB audio system.
-*/
-void line6_cleanup_audio(struct usb_line6 *line6)
-{
- struct snd_card *card = line6->card;
-
- if (card == NULL)
- return;
-
- snd_card_disconnect(card);
- snd_card_free(card);
- line6->card = NULL;
-}
diff --git a/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h
deleted file mode 100644
index 5f8a09a0fa95..000000000000
--- a/drivers/staging/line6/audio.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef AUDIO_H
-#define AUDIO_H
-
-#include "driver.h"
-
-extern void line6_cleanup_audio(struct usb_line6 *);
-extern int line6_init_audio(struct usb_line6 *);
-extern int line6_register_audio(struct usb_line6 *);
-
-#endif
diff --git a/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
deleted file mode 100644
index e6ca631e3f79..000000000000
--- a/drivers/staging/line6/capture.c
+++ /dev/null
@@ -1,432 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "pcm.h"
-#include "pod.h"
-
-/*
- Find a free URB and submit it.
-*/
-static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
-{
- int index;
- unsigned long flags;
- int i, urb_size;
- int ret;
- struct urb *urb_in;
-
- spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
- index =
- find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
-
- if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
- dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
- return -EINVAL;
- }
-
- urb_in = line6pcm->urb_audio_in[index];
- urb_size = 0;
-
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- struct usb_iso_packet_descriptor *fin =
- &urb_in->iso_frame_desc[i];
- fin->offset = urb_size;
- fin->length = line6pcm->max_packet_size;
- urb_size += line6pcm->max_packet_size;
- }
-
- urb_in->transfer_buffer =
- line6pcm->buffer_in +
- index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
- urb_in->transfer_buffer_length = urb_size;
- urb_in->context = line6pcm;
-
- ret = usb_submit_urb(urb_in, GFP_ATOMIC);
-
- if (ret == 0)
- set_bit(index, &line6pcm->active_urb_in);
- else
- dev_err(line6pcm->line6->ifcdev,
- "URB in #%d submission failed (%d)\n", index, ret);
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
- return 0;
-}
-
-/*
- Submit all currently available capture URBs.
-*/
-int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
-{
- int ret, i;
-
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- ret = submit_audio_in_urb(line6pcm);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-/*
- Unlink all currently active capture URBs.
-*/
-void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- unsigned int i;
-
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_in)) {
- if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
- struct urb *u = line6pcm->urb_audio_in[i];
-
- usb_unlink_urb(u);
- }
- }
- }
-}
-
-/*
- Wait until unlinking of all currently active capture URBs has been
- finished.
-*/
-void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- int timeout = HZ;
- unsigned int i;
- int alive;
-
- do {
- alive = 0;
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_in))
- alive++;
- }
- if (!alive)
- break;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- } while (--timeout > 0);
- if (alive)
- snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
- Unlink all currently active capture URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- line6_unlink_audio_in_urbs(line6pcm);
- line6_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
- Copy data into ALSA capture buffer.
-*/
-void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
-{
- struct snd_pcm_substream *substream =
- get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
- struct snd_pcm_runtime *runtime = substream->runtime;
- const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
- int frames = fsize / bytes_per_frame;
-
- if (runtime == NULL)
- return;
-
- if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
- /*
- The transferred area goes over buffer boundary,
- copy two separate chunks.
- */
- int len;
-
- len = runtime->buffer_size - line6pcm->pos_in_done;
-
- if (len > 0) {
- memcpy(runtime->dma_area +
- line6pcm->pos_in_done * bytes_per_frame, fbuf,
- len * bytes_per_frame);
- memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
- (frames - len) * bytes_per_frame);
- } else {
- /* this is somewhat paranoid */
- dev_err(line6pcm->line6->ifcdev,
- "driver bug: len = %d\n", len);
- }
- } else {
- /* copy single chunk */
- memcpy(runtime->dma_area +
- line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
- }
-
- line6pcm->pos_in_done += frames;
- if (line6pcm->pos_in_done >= runtime->buffer_size)
- line6pcm->pos_in_done -= runtime->buffer_size;
-}
-
-void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
-{
- struct snd_pcm_substream *substream =
- get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
-
- line6pcm->bytes_in += length;
- if (line6pcm->bytes_in >= line6pcm->period_in) {
- line6pcm->bytes_in %= line6pcm->period_in;
- snd_pcm_period_elapsed(substream);
- }
-}
-
-void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
-{
- kfree(line6pcm->buffer_in);
- line6pcm->buffer_in = NULL;
-}
-
-/*
- * Callback for completed capture URB.
- */
-static void audio_in_callback(struct urb *urb)
-{
- int i, index, length = 0, shutdown = 0;
- unsigned long flags;
-
- struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
-
- line6pcm->last_frame_in = urb->start_frame;
-
- /* find index of URB */
- for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
- if (urb == line6pcm->urb_audio_in[index])
- break;
-
- spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
-
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- char *fbuf;
- int fsize;
- struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
-
- if (fin->status == -EXDEV) {
- shutdown = 1;
- break;
- }
-
- fbuf = urb->transfer_buffer + fin->offset;
- fsize = fin->actual_length;
-
- if (fsize > line6pcm->max_packet_size) {
- dev_err(line6pcm->line6->ifcdev,
- "driver and/or device bug: packet too large (%d > %d)\n",
- fsize, line6pcm->max_packet_size);
- }
-
- length += fsize;
-
- /* the following assumes LINE6_ISO_PACKETS == 1: */
- line6pcm->prev_fbuf = fbuf;
- line6pcm->prev_fsize = fsize;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
- if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
- &line6pcm->flags) && (fsize > 0))
- line6_capture_copy(line6pcm, fbuf, fsize);
- }
-
- clear_bit(index, &line6pcm->active_urb_in);
-
- if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
- shutdown = 1;
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-
- if (!shutdown) {
- submit_audio_in_urb(line6pcm);
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
- if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
- &line6pcm->flags))
- line6_capture_check_period(line6pcm, length);
- }
-}
-
-/* open capture callback */
-static int snd_line6_capture_open(struct snd_pcm_substream *substream)
-{
- int err;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- err = snd_pcm_hw_constraint_ratdens(runtime, 0,
- SNDRV_PCM_HW_PARAM_RATE,
- (&line6pcm->
- properties->snd_line6_rates));
- if (err < 0)
- return err;
-
- runtime->hw = line6pcm->properties->snd_line6_capture_hw;
- return 0;
-}
-
-/* close capture callback */
-static int snd_line6_capture_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-/* hw_params capture callback */
-static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- int ret;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- /* -- Florian Demski [FD] */
- /* don't ask me why, but this fixes the bug on my machine */
- if (line6pcm == NULL) {
- if (substream->pcm == NULL)
- return -ENOMEM;
- if (substream->pcm->private_data == NULL)
- return -ENOMEM;
- substream->private_data = substream->pcm->private_data;
- line6pcm = snd_pcm_substream_chip(substream);
- }
- /* -- [FD] end */
-
- ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-
- if (ret < 0)
- return ret;
-
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0) {
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
- return ret;
- }
-
- line6pcm->period_in = params_period_bytes(hw_params);
- return 0;
-}
-
-/* hw_free capture callback */
-static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger callback */
-int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
- int err;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_RESUME:
-#endif
- err = line6_pcm_acquire(line6pcm,
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
- err = line6_pcm_release(line6pcm,
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* capture pointer callback */
-static snd_pcm_uframes_t
-snd_line6_capture_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- return line6pcm->pos_in_done;
-}
-
-/* capture operators */
-struct snd_pcm_ops snd_line6_capture_ops = {
- .open = snd_line6_capture_open,
- .close = snd_line6_capture_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_line6_capture_hw_params,
- .hw_free = snd_line6_capture_hw_free,
- .prepare = snd_line6_prepare,
- .trigger = snd_line6_trigger,
- .pointer = snd_line6_capture_pointer,
-};
-
-int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
- int i;
-
- /* create audio URBs and fill in constant values: */
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- struct urb *urb;
-
- /* URB for audio in: */
- urb = line6pcm->urb_audio_in[i] =
- usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
-
- if (urb == NULL) {
- dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- urb->dev = line6pcm->line6->usbdev;
- urb->pipe =
- usb_rcvisocpipe(line6pcm->line6->usbdev,
- line6pcm->ep_audio_read &
- USB_ENDPOINT_NUMBER_MASK);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->start_frame = -1;
- urb->number_of_packets = LINE6_ISO_PACKETS;
- urb->interval = LINE6_ISO_INTERVAL;
- urb->error_count = 0;
- urb->complete = audio_in_callback;
- }
-
- return 0;
-}
diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h
deleted file mode 100644
index 4157bcb598a9..000000000000
--- a/drivers/staging/line6/capture.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef CAPTURE_H
-#define CAPTURE_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "pcm.h"
-
-extern struct snd_pcm_ops snd_line6_capture_ops;
-
-extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
- int fsize);
-extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
- int length);
-extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
- *line6pcm);
-extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
deleted file mode 100644
index 503b2d763595..000000000000
--- a/drivers/staging/line6/driver.c
+++ /dev/null
@@ -1,1162 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/usb.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "midi.h"
-#include "playback.h"
-#include "pod.h"
-#include "podhd.h"
-#include "revision.h"
-#include "toneport.h"
-#include "usbdefs.h"
-#include "variax.h"
-
-#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>"
-#define DRIVER_DESC "Line6 USB Driver"
-#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION
-
-/* table of devices that work with this driver */
-static const struct usb_device_id line6_id_table[] = {
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD400)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)},
- {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)},
- {},
-};
-
-MODULE_DEVICE_TABLE(usb, line6_id_table);
-
-#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\
- {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\
- .name = dev_name, .capabilities = LINE6_BIT_##dev_cap}
-
-/* *INDENT-OFF* */
-static const struct line6_properties line6_properties_table[] = {
- L6PROP(BASSPODXT, "BassPODxt", "BassPODxt", CTRL_PCM_HW),
- L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW),
- L6PROP(BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW),
- L6PROP(GUITARPORT, "GuitarPort", "GuitarPort", PCM),
- L6PROP(POCKETPOD, "PocketPOD", "Pocket POD", CONTROL),
- L6PROP(PODHD300, "PODHD300", "POD HD300", CTRL_PCM_HW),
- L6PROP(PODHD400, "PODHD400", "POD HD400", CTRL_PCM_HW),
- L6PROP(PODHD500, "PODHD500", "POD HD500", CTRL_PCM_HW),
- L6PROP(PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", PCM),
- L6PROP(PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", PCM),
- L6PROP(PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", PCM),
- L6PROP(PODX3, "PODX3", "POD X3", PCM),
- L6PROP(PODX3LIVE, "PODX3Live", "POD X3 Live", PCM),
- L6PROP(PODXT, "PODxt", "PODxt", CTRL_PCM_HW),
- L6PROP(PODXTLIVE, "PODxtLive", "PODxt Live", CTRL_PCM_HW),
- L6PROP(PODXTPRO, "PODxtPro", "PODxt Pro", CTRL_PCM_HW),
- L6PROP(TONEPORT_GX, "TonePortGX", "TonePort GX", PCM),
- L6PROP(TONEPORT_UX1, "TonePortUX1", "TonePort UX1", PCM),
- L6PROP(TONEPORT_UX2, "TonePortUX2", "TonePort UX2", PCM),
- L6PROP(VARIAX, "Variax", "Variax Workbench", CONTROL),
-};
-/* *INDENT-ON* */
-
-/*
- This is Line6's MIDI manufacturer ID.
-*/
-const unsigned char line6_midi_id[] = {
- 0x00, 0x01, 0x0c
-};
-
-/*
- Code to request version of POD, Variax interface
- (and maybe other devices).
-*/
-static const char line6_request_version[] = {
- 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
-};
-
-/**
- Class for asynchronous messages.
-*/
-struct message {
- struct usb_line6 *line6;
- const char *buffer;
- int size;
- int done;
-};
-
-/*
- Forward declarations.
-*/
-static void line6_data_received(struct urb *urb);
-static int line6_send_raw_message_async_part(struct message *msg,
- struct urb *urb);
-
-/*
- Start to listen on endpoint.
-*/
-static int line6_start_listen(struct usb_line6 *line6)
-{
- int err;
-
- usb_fill_int_urb(line6->urb_listen, line6->usbdev,
- usb_rcvintpipe(line6->usbdev, line6->ep_control_read),
- line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
- line6_data_received, line6, line6->interval);
- line6->urb_listen->actual_length = 0;
- err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
- return err;
-}
-
-/*
- Stop listening on endpoint.
-*/
-static void line6_stop_listen(struct usb_line6 *line6)
-{
- usb_kill_urb(line6->urb_listen);
-}
-
-/*
- Send raw message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
- int size)
-{
- int i, done = 0;
-
- for (i = 0; i < size; i += line6->max_packet_size) {
- int partial;
- const char *frag_buf = buffer + i;
- int frag_size = min(line6->max_packet_size, size - i);
- int retval;
-
- retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- (char *)frag_buf, frag_size,
- &partial, LINE6_TIMEOUT * HZ);
-
- if (retval) {
- dev_err(line6->ifcdev,
- "usb_interrupt_msg failed (%d)\n", retval);
- break;
- }
-
- done += frag_size;
- }
-
- return done;
-}
-
-/*
- Notification of completion of asynchronous request transmission.
-*/
-static void line6_async_request_sent(struct urb *urb)
-{
- struct message *msg = (struct message *)urb->context;
-
- if (msg->done >= msg->size) {
- usb_free_urb(urb);
- kfree(msg);
- } else
- line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
- Asynchronously send part of a raw message.
-*/
-static int line6_send_raw_message_async_part(struct message *msg,
- struct urb *urb)
-{
- int retval;
- struct usb_line6 *line6 = msg->line6;
- int done = msg->done;
- int bytes = min(msg->size - done, line6->max_packet_size);
-
- usb_fill_int_urb(urb, line6->usbdev,
- usb_sndintpipe(line6->usbdev, line6->ep_control_write),
- (char *)msg->buffer + done, bytes,
- line6_async_request_sent, msg, line6->interval);
-
- msg->done += bytes;
- retval = usb_submit_urb(urb, GFP_ATOMIC);
-
- if (retval < 0) {
- dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
- __func__, retval);
- usb_free_urb(urb);
- kfree(msg);
- return retval;
- }
-
- return 0;
-}
-
-/*
- Setup and start timer.
-*/
-void line6_start_timer(struct timer_list *timer, unsigned int msecs,
- void (*function)(unsigned long), unsigned long data)
-{
- setup_timer(timer, function, data);
- timer->expires = jiffies + msecs * HZ / 1000;
- add_timer(timer);
-}
-
-/*
- Asynchronously send raw message.
-*/
-int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
- int size)
-{
- struct message *msg;
- struct urb *urb;
-
- /* create message: */
- msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
- if (msg == NULL)
- return -ENOMEM;
-
- /* create URB: */
- urb = usb_alloc_urb(0, GFP_ATOMIC);
-
- if (urb == NULL) {
- kfree(msg);
- dev_err(line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- /* set message data: */
- msg->line6 = line6;
- msg->buffer = buffer;
- msg->size = size;
- msg->done = 0;
-
- /* start sending: */
- return line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
- Send asynchronous device version request.
-*/
-int line6_version_request_async(struct usb_line6 *line6)
-{
- char *buffer;
- int retval;
-
- buffer = kmemdup(line6_request_version,
- sizeof(line6_request_version), GFP_ATOMIC);
- if (buffer == NULL) {
- dev_err(line6->ifcdev, "Out of memory");
- return -ENOMEM;
- }
-
- retval = line6_send_raw_message_async(line6, buffer,
- sizeof(line6_request_version));
- kfree(buffer);
- return retval;
-}
-
-/*
- Send sysex message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
- int size)
-{
- return line6_send_raw_message(line6, buffer,
- size + SYSEX_EXTRA_SIZE) -
- SYSEX_EXTRA_SIZE;
-}
-
-/*
- Allocate buffer for sysex message and prepare header.
- @param code sysex message code
- @param size number of bytes between code and sysex end
-*/
-char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
- int size)
-{
- char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
-
- if (!buffer)
- return NULL;
-
- buffer[0] = LINE6_SYSEX_BEGIN;
- memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
- buffer[sizeof(line6_midi_id) + 1] = code1;
- buffer[sizeof(line6_midi_id) + 2] = code2;
- buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
- return buffer;
-}
-
-/*
- Notification of data received from the Line6 device.
-*/
-static void line6_data_received(struct urb *urb)
-{
- struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
- struct midi_buffer *mb = &line6->line6midi->midibuf_in;
- int done;
-
- if (urb->status == -ESHUTDOWN)
- return;
-
- done =
- line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
-
- if (done < urb->actual_length) {
- line6_midibuf_ignore(mb, done);
- dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
- done, urb->actual_length);
- }
-
- for (;;) {
- done =
- line6_midibuf_read(mb, line6->buffer_message,
- LINE6_MESSAGE_MAXLEN);
-
- if (done == 0)
- break;
-
- line6->message_length = done;
- line6_midi_receive(line6, line6->buffer_message, done);
-
- switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- line6_pod_process_message((struct usb_line6_pod *)
- line6);
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- case LINE6_DEVID_PODHD500:
- break; /* let userspace handle MIDI */
-
- case LINE6_DEVID_PODXTLIVE:
- switch (line6->interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- line6_pod_process_message((struct usb_line6_pod
- *)line6);
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- line6_variax_process_message((struct
- usb_line6_variax
- *)line6);
- break;
-
- default:
- dev_err(line6->ifcdev,
- "PODxt Live interface %d not supported\n",
- line6->interface_number);
- }
- break;
-
- case LINE6_DEVID_VARIAX:
- line6_variax_process_message((struct usb_line6_variax *)
- line6);
- break;
-
- default:
- MISSING_CASE;
- }
- }
-
- line6_start_listen(line6);
-}
-
-/*
- Send channel number (i.e., switch to a different sound).
-*/
-int line6_send_program(struct usb_line6 *line6, u8 value)
-{
- int retval;
- unsigned char *buffer;
- int partial;
-
- buffer = kmalloc(2, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST;
- buffer[1] = value;
-
- retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- buffer, 2, &partial, LINE6_TIMEOUT * HZ);
-
- if (retval)
- dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
- retval);
-
- kfree(buffer);
- return retval;
-}
-
-/*
- Transmit Line6 control parameter.
-*/
-int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value)
-{
- int retval;
- unsigned char *buffer;
- int partial;
-
- buffer = kmalloc(3, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST;
- buffer[1] = param;
- buffer[2] = value;
-
- retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- buffer, 3, &partial, LINE6_TIMEOUT * HZ);
-
- if (retval)
- dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
- retval);
-
- kfree(buffer);
- return retval;
-}
-
-/*
- Read data from device.
-*/
-int line6_read_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen)
-{
- struct usb_device *usbdev = line6->usbdev;
- int ret;
- unsigned char len;
-
- /* query the serial number: */
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- (datalen << 8) | 0x21, address,
- NULL, 0, LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
- return ret;
- }
-
- /* Wait for data length. We'll get 0xff until length arrives. */
- do {
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_IN,
- 0x0012, 0x0000, &len, 1,
- LINE6_TIMEOUT * HZ);
- if (ret < 0) {
- dev_err(line6->ifcdev,
- "receive length failed (error %d)\n", ret);
- return ret;
- }
- } while (len == 0xff);
-
- if (len != datalen) {
- /* should be equal or something went wrong */
- dev_err(line6->ifcdev,
- "length mismatch (expected %d, got %d)\n",
- (int)datalen, (int)len);
- return -EINVAL;
- }
-
- /* receive the result: */
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0x0013, 0x0000, data, datalen,
- LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-/*
- Write data to device.
-*/
-int line6_write_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen)
-{
- struct usb_device *usbdev = line6->usbdev;
- int ret;
- unsigned char status;
-
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- 0x0022, address, data, datalen,
- LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev,
- "write request failed (error %d)\n", ret);
- return ret;
- }
-
- do {
- ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
- 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE |
- USB_DIR_IN,
- 0x0012, 0x0000,
- &status, 1, LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(line6->ifcdev,
- "receiving status failed (error %d)\n", ret);
- return ret;
- }
- } while (status == 0xff);
-
- if (status != 0) {
- dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- Read Line6 device serial number.
- (POD, TonePort, GuitarPort)
-*/
-int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
-{
- return line6_read_data(line6, 0x80d0, serial_number,
- sizeof(*serial_number));
-}
-
-/*
- No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- return 0;
-}
-
-/*
- Generic destructor.
-*/
-static void line6_destruct(struct usb_interface *interface)
-{
- struct usb_line6 *line6;
-
- if (interface == NULL)
- return;
- line6 = usb_get_intfdata(interface);
- if (line6 == NULL)
- return;
-
- /* free buffer memory first: */
- kfree(line6->buffer_message);
- kfree(line6->buffer_listen);
-
- /* then free URBs: */
- usb_free_urb(line6->urb_listen);
-
- /* make sure the device isn't destructed twice: */
- usb_set_intfdata(interface, NULL);
-
- /* free interface data: */
- kfree(line6);
-}
-
-/*
- Probe USB device.
-*/
-static int line6_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- int devtype;
- struct usb_device *usbdev;
- struct usb_line6 *line6;
- const struct line6_properties *properties;
- int interface_number, alternate = 0;
- int product;
- int size = 0;
- int ep_read = 0, ep_write = 0;
- int ret;
-
- if (interface == NULL)
- return -ENODEV;
- usbdev = interface_to_usbdev(interface);
- if (usbdev == NULL)
- return -ENODEV;
-
- /* we don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1) {
- ret = -ENODEV;
- goto err_put;
- }
-
- /* check vendor and product id */
- for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) {
- u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor);
- u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
- if (idVendor == line6_id_table[devtype].idVendor &&
- idProduct == line6_id_table[devtype].idProduct)
- break;
- }
-
- if (devtype < 0) {
- ret = -ENODEV;
- goto err_put;
- }
-
- /* initialize device info: */
- properties = &line6_properties_table[devtype];
- dev_info(&interface->dev, "Line6 %s found\n", properties->name);
- product = le16_to_cpu(usbdev->descriptor.idProduct);
-
- /* query interface number */
- interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
-
- switch (product) {
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_PODXTLIVE:
- case LINE6_DEVID_VARIAX:
- alternate = 1;
- break;
-
- case LINE6_DEVID_POCKETPOD:
- switch (interface_number) {
- case 0:
- return -ENODEV; /* this interface has no endpoints */
- case 1:
- alternate = 0;
- break;
- default:
- MISSING_CASE;
- }
- break;
-
- case LINE6_DEVID_PODHD500:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- switch (interface_number) {
- case 0:
- alternate = 1;
- break;
- case 1:
- alternate = 0;
- break;
- default:
- MISSING_CASE;
- }
- break;
-
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- alternate = 5;
- break;
-
- case LINE6_DEVID_GUITARPORT:
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- alternate = 2; /* 1..4 seem to be ok */
- break;
-
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX2:
- switch (interface_number) {
- case 0:
- /* defaults to 44.1kHz, 16-bit */
- alternate = 2;
- break;
- case 1:
- /* don't know yet what this is ...
- alternate = 1;
- break;
- */
- return -ENODEV;
- default:
- MISSING_CASE;
- }
- break;
-
- default:
- MISSING_CASE;
- ret = -ENODEV;
- goto err_put;
- }
-
- ret = usb_set_interface(usbdev, interface_number, alternate);
- if (ret < 0) {
- dev_err(&interface->dev, "set_interface failed\n");
- goto err_put;
- }
-
- /* initialize device data based on product id: */
- switch (product) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x84;
- ep_write = 0x03;
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- size = sizeof(struct usb_line6_podhd);
- ep_read = 0x84;
- ep_write = 0x03;
- break;
-
- case LINE6_DEVID_PODHD500:
- size = sizeof(struct usb_line6_podhd);
- ep_read = 0x81;
- ep_write = 0x01;
- break;
-
- case LINE6_DEVID_POCKETPOD:
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x82;
- ep_write = 0x02;
- break;
-
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- /* currently unused! */
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x81;
- ep_write = 0x01;
- break;
-
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- size = sizeof(struct usb_line6_toneport);
- /* these don't have a control channel */
- break;
-
- case LINE6_DEVID_PODXTLIVE:
- switch (interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- size = sizeof(struct usb_line6_pod);
- ep_read = 0x84;
- ep_write = 0x03;
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- size = sizeof(struct usb_line6_variax);
- ep_read = 0x86;
- ep_write = 0x05;
- break;
-
- default:
- ret = -ENODEV;
- goto err_put;
- }
- break;
-
- case LINE6_DEVID_VARIAX:
- size = sizeof(struct usb_line6_variax);
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
- default:
- MISSING_CASE;
- ret = -ENODEV;
- goto err_put;
- }
-
- if (size == 0) {
- dev_err(&interface->dev,
- "driver bug: interface data size not set\n");
- ret = -ENODEV;
- goto err_put;
- }
-
- line6 = kzalloc(size, GFP_KERNEL);
- if (line6 == NULL) {
- ret = -ENODEV;
- goto err_put;
- }
-
- /* store basic data: */
- line6->interface_number = interface_number;
- line6->properties = properties;
- line6->usbdev = usbdev;
- line6->ifcdev = &interface->dev;
- line6->ep_control_read = ep_read;
- line6->ep_control_write = ep_write;
- line6->product = product;
-
- /* get data from endpoint descriptor (see usb_maxpacket): */
- {
- struct usb_host_endpoint *ep;
- unsigned epnum =
- usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read));
- ep = usbdev->ep_in[epnum];
-
- if (ep != NULL) {
- line6->interval = ep->desc.bInterval;
- line6->max_packet_size =
- le16_to_cpu(ep->desc.wMaxPacketSize);
- } else {
- line6->interval = LINE6_FALLBACK_INTERVAL;
- line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
- dev_err(line6->ifcdev,
- "endpoint not available, using fallback values");
- }
- }
-
- usb_set_intfdata(interface, line6);
-
- if (properties->capabilities & LINE6_BIT_CONTROL) {
- /* initialize USB buffers: */
- line6->buffer_listen =
- kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
- if (line6->buffer_listen == NULL) {
- ret = -ENOMEM;
- goto err_destruct;
- }
-
- line6->buffer_message =
- kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
- if (line6->buffer_message == NULL) {
- ret = -ENOMEM;
- goto err_destruct;
- }
-
- line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
-
- if (line6->urb_listen == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- line6_destruct(interface);
- ret = -ENOMEM;
- goto err_destruct;
- }
-
- ret = line6_start_listen(line6);
- if (ret < 0) {
- dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
- __func__);
- goto err_destruct;
- }
- }
-
- /* initialize device data based on product id: */
- switch (product) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- ret = line6_pod_init(interface, (struct usb_line6_pod *)line6);
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- case LINE6_DEVID_PODHD500:
- ret = line6_podhd_init(interface,
- (struct usb_line6_podhd *)line6);
- break;
-
- case LINE6_DEVID_PODXTLIVE:
- switch (interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- ret =
- line6_pod_init(interface,
- (struct usb_line6_pod *)line6);
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- ret =
- line6_variax_init(interface,
- (struct usb_line6_variax *)line6);
- break;
-
- default:
- dev_err(&interface->dev,
- "PODxt Live interface %d not supported\n",
- interface_number);
- ret = -ENODEV;
- }
-
- break;
-
- case LINE6_DEVID_VARIAX:
- ret =
- line6_variax_init(interface,
- (struct usb_line6_variax *)line6);
- break;
-
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- ret =
- line6_toneport_init(interface,
- (struct usb_line6_toneport *)line6);
- break;
-
- default:
- MISSING_CASE;
- ret = -ENODEV;
- }
-
- if (ret < 0)
- goto err_destruct;
-
- ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
- "usb_device");
- if (ret < 0)
- goto err_destruct;
-
- /* creation of additional special files should go here */
-
- dev_info(&interface->dev, "Line6 %s now attached\n",
- line6->properties->name);
-
- switch (product) {
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- dev_info(&interface->dev,
- "NOTE: the Line6 %s is detected, but not yet supported\n",
- line6->properties->name);
- }
-
- /* increment reference counters: */
- usb_get_intf(interface);
- usb_get_dev(usbdev);
-
- return 0;
-
-err_destruct:
- line6_destruct(interface);
-err_put:
- return ret;
-}
-
-/*
- Line6 device disconnected.
-*/
-static void line6_disconnect(struct usb_interface *interface)
-{
- struct usb_line6 *line6;
- struct usb_device *usbdev;
- int interface_number;
-
- if (interface == NULL)
- return;
- usbdev = interface_to_usbdev(interface);
- if (usbdev == NULL)
- return;
-
- /* removal of additional special files should go here */
-
- sysfs_remove_link(&interface->dev.kobj, "usb_device");
-
- interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
- line6 = usb_get_intfdata(interface);
-
- if (line6 != NULL) {
- if (line6->urb_listen != NULL)
- line6_stop_listen(line6);
-
- if (usbdev != line6->usbdev)
- dev_err(line6->ifcdev,
- "driver bug: inconsistent usb device\n");
-
- switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTPRO:
- line6_pod_disconnect(interface);
- break;
-
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- case LINE6_DEVID_PODHD500:
- line6_podhd_disconnect(interface);
- break;
-
- case LINE6_DEVID_PODXTLIVE:
- switch (interface_number) {
- case PODXTLIVE_INTERFACE_POD:
- line6_pod_disconnect(interface);
- break;
-
- case PODXTLIVE_INTERFACE_VARIAX:
- line6_variax_disconnect(interface);
- break;
- }
-
- break;
-
- case LINE6_DEVID_VARIAX:
- line6_variax_disconnect(interface);
- break;
-
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- line6_toneport_disconnect(interface);
- break;
-
- default:
- MISSING_CASE;
- }
-
- dev_info(&interface->dev, "Line6 %s now disconnected\n",
- line6->properties->name);
- }
-
- line6_destruct(interface);
-
- /* decrement reference counters: */
- usb_put_intf(interface);
- usb_put_dev(usbdev);
-}
-
-#ifdef CONFIG_PM
-
-/*
- Suspend Line6 device.
-*/
-static int line6_suspend(struct usb_interface *interface, pm_message_t message)
-{
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- struct snd_line6_pcm *line6pcm = line6->line6pcm;
-
- snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
-
- if (line6->properties->capabilities & LINE6_BIT_CONTROL)
- line6_stop_listen(line6);
-
- if (line6pcm != NULL) {
- snd_pcm_suspend_all(line6pcm->pcm);
- line6_pcm_disconnect(line6pcm);
- line6pcm->flags = 0;
- }
-
- return 0;
-}
-
-/*
- Resume Line6 device.
-*/
-static int line6_resume(struct usb_interface *interface)
-{
- struct usb_line6 *line6 = usb_get_intfdata(interface);
-
- if (line6->properties->capabilities & LINE6_BIT_CONTROL)
- line6_start_listen(line6);
-
- snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
- return 0;
-}
-
-/*
- Resume Line6 device after reset.
-*/
-static int line6_reset_resume(struct usb_interface *interface)
-{
- struct usb_line6 *line6 = usb_get_intfdata(interface);
-
- switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_GUITARPORT:
- line6_toneport_reset_resume((struct usb_line6_toneport *)line6);
- }
-
- return line6_resume(interface);
-}
-
-#endif /* CONFIG_PM */
-
-static struct usb_driver line6_driver = {
- .name = DRIVER_NAME,
- .probe = line6_probe,
- .disconnect = line6_disconnect,
-#ifdef CONFIG_PM
- .suspend = line6_suspend,
- .resume = line6_resume,
- .reset_resume = line6_reset_resume,
-#endif
- .id_table = line6_id_table,
-};
-
-module_usb_driver(line6_driver);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
deleted file mode 100644
index 16e3fc2f1f15..000000000000
--- a/drivers/staging/line6/driver.h
+++ /dev/null
@@ -1,215 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef DRIVER_H
-#define DRIVER_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "midi.h"
-
-#define DRIVER_NAME "line6usb"
-
-#define LINE6_TIMEOUT 1
-#define LINE6_BUFSIZE_LISTEN 32
-#define LINE6_MESSAGE_MAXLEN 256
-
-/*
- Line6 MIDI control commands
-*/
-#define LINE6_PARAM_CHANGE 0xb0
-#define LINE6_PROGRAM_CHANGE 0xc0
-#define LINE6_SYSEX_BEGIN 0xf0
-#define LINE6_SYSEX_END 0xf7
-#define LINE6_RESET 0xff
-
-/*
- MIDI channel for messages initiated by the host
- (and eventually echoed back by the device)
-*/
-#define LINE6_CHANNEL_HOST 0x00
-
-/*
- MIDI channel for messages initiated by the device
-*/
-#define LINE6_CHANNEL_DEVICE 0x02
-
-#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */
-
-#define LINE6_CHANNEL_MASK 0x0f
-
-#define MISSING_CASE \
- pr_err("line6usb driver bug: missing case in %s:%d\n", \
- __FILE__, __LINE__)
-
-#define CHECK_RETURN(x) \
-do { \
- err = x; \
- if (err < 0) \
- return err; \
-} while (0)
-
-#define CHECK_STARTUP_PROGRESS(x, n) \
-do { \
- if ((x) >= (n)) \
- return; \
- x = (n); \
-} while (0)
-
-extern const unsigned char line6_midi_id[3];
-
-static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
-static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
-
-/**
- Common properties of Line6 devices.
-*/
-struct line6_properties {
- /**
- Bit identifying this device in the line6usb driver.
- */
- int device_bit;
-
- /**
- Card id string (maximum 16 characters).
- This can be used to address the device in ALSA programs as
- "default:CARD=<id>"
- */
- const char *id;
-
- /**
- Card short name (maximum 32 characters).
- */
- const char *name;
-
- /**
- Bit vector defining this device's capabilities in the
- line6usb driver.
- */
- int capabilities;
-};
-
-/**
- Common data shared by all Line6 devices.
- Corresponds to a pair of USB endpoints.
-*/
-struct usb_line6 {
- /**
- USB device.
- */
- struct usb_device *usbdev;
-
- /**
- Product id.
- */
- int product;
-
- /**
- Properties.
- */
- const struct line6_properties *properties;
-
- /**
- Interface number.
- */
- int interface_number;
-
- /**
- Interval (ms).
- */
- int interval;
-
- /**
- Maximum size of USB packet.
- */
- int max_packet_size;
-
- /**
- Device representing the USB interface.
- */
- struct device *ifcdev;
-
- /**
- Line6 sound card data structure.
- Each device has at least MIDI or PCM.
- */
- struct snd_card *card;
-
- /**
- Line6 PCM device data structure.
- */
- struct snd_line6_pcm *line6pcm;
-
- /**
- Line6 MIDI device data structure.
- */
- struct snd_line6_midi *line6midi;
-
- /**
- USB endpoint for listening to control commands.
- */
- int ep_control_read;
-
- /**
- USB endpoint for writing control commands.
- */
- int ep_control_write;
-
- /**
- URB for listening to PODxt Pro control endpoint.
- */
- struct urb *urb_listen;
-
- /**
- Buffer for listening to PODxt Pro control endpoint.
- */
- unsigned char *buffer_listen;
-
- /**
- Buffer for message to be processed.
- */
- unsigned char *buffer_message;
-
- /**
- Length of message to be processed.
- */
- int message_length;
-};
-
-extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
- int code2, int size);
-extern ssize_t line6_nop_read(struct device *dev,
- struct device_attribute *attr, char *buf);
-extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen);
-extern int line6_read_serial_number(struct usb_line6 *line6,
- int *serial_number);
-extern int line6_send_program(struct usb_line6 *line6, u8 value);
-extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
- int size);
-extern int line6_send_raw_message_async(struct usb_line6 *line6,
- const char *buffer, int size);
-extern int line6_send_sysex_message(struct usb_line6 *line6,
- const char *buffer, int size);
-extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count);
-extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
- void (*function)(unsigned long),
- unsigned long data);
-extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
- u8 value);
-extern int line6_version_request_async(struct usb_line6 *line6);
-extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
- size_t datalen);
-
-#endif
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
deleted file mode 100644
index 1ac343b649c1..000000000000
--- a/drivers/staging/line6/midi.c
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-#include <linux/usb.h>
-#include <sound/core.h>
-#include <sound/rawmidi.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "midi.h"
-#include "pod.h"
-#include "usbdefs.h"
-
-#define line6_rawmidi_substream_midi(substream) \
- ((struct snd_line6_midi *)((substream)->rmidi->private_data))
-
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
- int length);
-
-/*
- Pass data received via USB to MIDI.
-*/
-void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
- int length)
-{
- if (line6->line6midi->substream_receive)
- snd_rawmidi_receive(line6->line6midi->substream_receive,
- data, length);
-}
-
-/*
- Read data from MIDI buffer and transmit them via USB.
-*/
-static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
-{
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
- struct snd_line6_midi *line6midi = line6->line6midi;
- struct midi_buffer *mb = &line6midi->midibuf_out;
- unsigned long flags;
- unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
- int req, done;
-
- spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
-
- for (;;) {
- req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
- done = snd_rawmidi_transmit_peek(substream, chunk, req);
-
- if (done == 0)
- break;
-
- line6_midibuf_write(mb, chunk, done);
- snd_rawmidi_transmit_ack(substream, done);
- }
-
- for (;;) {
- done = line6_midibuf_read(mb, chunk,
- LINE6_FALLBACK_MAXPACKETSIZE);
-
- if (done == 0)
- break;
-
- send_midi_async(line6, chunk, done);
- }
-
- spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
-}
-
-/*
- Notification of completion of MIDI transmission.
-*/
-static void midi_sent(struct urb *urb)
-{
- unsigned long flags;
- int status;
- int num;
- struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-
- status = urb->status;
- kfree(urb->transfer_buffer);
- usb_free_urb(urb);
-
- if (status == -ESHUTDOWN)
- return;
-
- spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
- num = --line6->line6midi->num_active_send_urbs;
-
- if (num == 0) {
- line6_midi_transmit(line6->line6midi->substream_transmit);
- num = line6->line6midi->num_active_send_urbs;
- }
-
- if (num == 0)
- wake_up(&line6->line6midi->send_wait);
-
- spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-/*
- Send an asynchronous MIDI message.
- Assumes that line6->line6midi->send_urb_lock is held
- (i.e., this function is serialized).
-*/
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
- int length)
-{
- struct urb *urb;
- int retval;
- unsigned char *transfer_buffer;
-
- urb = usb_alloc_urb(0, GFP_ATOMIC);
-
- if (urb == NULL) {
- dev_err(line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
-
- if (transfer_buffer == NULL) {
- usb_free_urb(urb);
- dev_err(line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- usb_fill_int_urb(urb, line6->usbdev,
- usb_sndbulkpipe(line6->usbdev,
- line6->ep_control_write),
- transfer_buffer, length, midi_sent, line6,
- line6->interval);
- urb->actual_length = 0;
- retval = usb_submit_urb(urb, GFP_ATOMIC);
-
- if (retval < 0) {
- dev_err(line6->ifcdev, "usb_submit_urb failed\n");
- usb_free_urb(urb);
- return retval;
- }
-
- ++line6->line6midi->num_active_send_urbs;
- return 0;
-}
-
-static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
- int up)
-{
- unsigned long flags;
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
-
- line6->line6midi->substream_transmit = substream;
- spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
-
- if (line6->line6midi->num_active_send_urbs == 0)
- line6_midi_transmit(substream);
-
- spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
-{
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
- struct snd_line6_midi *midi = line6->line6midi;
-
- wait_event_interruptible(midi->send_wait,
- midi->num_active_send_urbs == 0);
-}
-
-static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
-{
- return 0;
-}
-
-static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
- int up)
-{
- struct usb_line6 *line6 =
- line6_rawmidi_substream_midi(substream)->line6;
-
- if (up)
- line6->line6midi->substream_receive = substream;
- else
- line6->line6midi->substream_receive = NULL;
-}
-
-static struct snd_rawmidi_ops line6_midi_output_ops = {
- .open = line6_midi_output_open,
- .close = line6_midi_output_close,
- .trigger = line6_midi_output_trigger,
- .drain = line6_midi_output_drain,
-};
-
-static struct snd_rawmidi_ops line6_midi_input_ops = {
- .open = line6_midi_input_open,
- .close = line6_midi_input_close,
- .trigger = line6_midi_input_trigger,
-};
-
-/*
- Cleanup the Line6 MIDI device.
-*/
-static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
-{
-}
-
-/* Create a MIDI device */
-static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
-{
- struct snd_rawmidi *rmidi;
- int err;
-
- err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
- &rmidi);
- if (err < 0)
- return err;
-
- rmidi->private_data = line6midi;
- rmidi->private_free = line6_cleanup_midi;
- strcpy(rmidi->id, line6midi->line6->properties->id);
- strcpy(rmidi->name, line6midi->line6->properties->name);
-
- rmidi->info_flags =
- SNDRV_RAWMIDI_INFO_OUTPUT |
- SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
- &line6_midi_output_ops);
- snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
- &line6_midi_input_ops);
- return 0;
-}
-
-/* MIDI device destructor */
-static int snd_line6_midi_free(struct snd_device *device)
-{
- struct snd_line6_midi *line6midi = device->device_data;
-
- line6_midibuf_destroy(&line6midi->midibuf_in);
- line6_midibuf_destroy(&line6midi->midibuf_out);
- return 0;
-}
-
-/*
- Initialize the Line6 MIDI subsystem.
-*/
-int line6_init_midi(struct usb_line6 *line6)
-{
- static struct snd_device_ops midi_ops = {
- .dev_free = snd_line6_midi_free,
- };
-
- int err;
- struct snd_line6_midi *line6midi;
-
- if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) {
- /* skip MIDI initialization and report success */
- return 0;
- }
-
- line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
-
- if (line6midi == NULL)
- return -ENOMEM;
-
- err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
- if (err < 0) {
- kfree(line6midi);
- return err;
- }
-
- err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
- if (err < 0) {
- kfree(line6midi->midibuf_in.buf);
- kfree(line6midi);
- return err;
- }
-
- line6midi->line6 = line6;
- line6->line6midi = line6midi;
-
- err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
- &midi_ops);
- if (err < 0)
- return err;
-
- err = snd_line6_new_midi(line6midi);
- if (err < 0)
- return err;
-
- init_waitqueue_head(&line6midi->send_wait);
- spin_lock_init(&line6midi->send_urb_lock);
- spin_lock_init(&line6midi->midi_transmit_lock);
- return 0;
-}
diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h
deleted file mode 100644
index 78f903fb4d41..000000000000
--- a/drivers/staging/line6/midi.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef MIDI_H
-#define MIDI_H
-
-#include <sound/rawmidi.h>
-
-#include "midibuf.h"
-
-#define MIDI_BUFFER_SIZE 1024
-
-struct snd_line6_midi {
- /**
- Pointer back to the Line6 driver data structure.
- */
- struct usb_line6 *line6;
-
- /**
- MIDI substream for receiving (or NULL if not active).
- */
- struct snd_rawmidi_substream *substream_receive;
-
- /**
- MIDI substream for transmitting (or NULL if not active).
- */
- struct snd_rawmidi_substream *substream_transmit;
-
- /**
- Number of currently active MIDI send URBs.
- */
- int num_active_send_urbs;
-
- /**
- Spin lock to protect updates of send_urb.
- */
- spinlock_t send_urb_lock;
-
- /**
- Spin lock to protect MIDI buffer handling.
- */
- spinlock_t midi_transmit_lock;
-
- /**
- Wait queue for MIDI transmission.
- */
- wait_queue_head_t send_wait;
-
- /**
- Buffer for incoming MIDI stream.
- */
- struct midi_buffer midibuf_in;
-
- /**
- Buffer for outgoing MIDI stream.
- */
- struct midi_buffer midibuf_out;
-};
-
-extern int line6_init_midi(struct usb_line6 *line6);
-extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
- int length);
-
-#endif
diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c
deleted file mode 100644
index 1ff856989fd6..000000000000
--- a/drivers/staging/line6/midibuf.c
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-
-#include "midibuf.h"
-
-static int midibuf_message_length(unsigned char code)
-{
- int message_length;
-
- if (code < 0x80)
- message_length = -1;
- else if (code < 0xf0) {
- static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
-
- message_length = length[(code >> 4) - 8];
- } else {
- /*
- Note that according to the MIDI specification 0xf2 is
- the "Song Position Pointer", but this is used by Line6
- to send sysex messages to the host.
- */
- static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
- 1, 1, 1, -1, 1, 1
- };
- message_length = length[code & 0x0f];
- }
-
- return message_length;
-}
-
-static int midibuf_is_empty(struct midi_buffer *this)
-{
- return (this->pos_read == this->pos_write) && !this->full;
-}
-
-static int midibuf_is_full(struct midi_buffer *this)
-{
- return this->full;
-}
-
-void line6_midibuf_reset(struct midi_buffer *this)
-{
- this->pos_read = this->pos_write = this->full = 0;
- this->command_prev = -1;
-}
-
-int line6_midibuf_init(struct midi_buffer *this, int size, int split)
-{
- this->buf = kmalloc(size, GFP_KERNEL);
-
- if (this->buf == NULL)
- return -ENOMEM;
-
- this->size = size;
- this->split = split;
- line6_midibuf_reset(this);
- return 0;
-}
-
-void line6_midibuf_status(struct midi_buffer *this)
-{
- pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
- this->size, this->split, this->pos_read, this->pos_write,
- this->full, this->command_prev);
-}
-
-int line6_midibuf_bytes_free(struct midi_buffer *this)
-{
- return
- midibuf_is_full(this) ?
- 0 :
- (this->pos_read - this->pos_write + this->size - 1) % this->size +
- 1;
-}
-
-int line6_midibuf_bytes_used(struct midi_buffer *this)
-{
- return
- midibuf_is_empty(this) ?
- 0 :
- (this->pos_write - this->pos_read + this->size - 1) % this->size +
- 1;
-}
-
-int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
- int length)
-{
- int bytes_free;
- int length1, length2;
- int skip_active_sense = 0;
-
- if (midibuf_is_full(this) || (length <= 0))
- return 0;
-
- /* skip trailing active sense */
- if (data[length - 1] == 0xfe) {
- --length;
- skip_active_sense = 1;
- }
-
- bytes_free = line6_midibuf_bytes_free(this);
-
- if (length > bytes_free)
- length = bytes_free;
-
- if (length > 0) {
- length1 = this->size - this->pos_write;
-
- if (length < length1) {
- /* no buffer wraparound */
- memcpy(this->buf + this->pos_write, data, length);
- this->pos_write += length;
- } else {
- /* buffer wraparound */
- length2 = length - length1;
- memcpy(this->buf + this->pos_write, data, length1);
- memcpy(this->buf, data + length1, length2);
- this->pos_write = length2;
- }
-
- if (this->pos_write == this->pos_read)
- this->full = 1;
- }
-
- return length + skip_active_sense;
-}
-
-int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
- int length)
-{
- int bytes_used;
- int length1, length2;
- int command;
- int midi_length;
- int repeat = 0;
- int i;
-
- /* we need to be able to store at least a 3 byte MIDI message */
- if (length < 3)
- return -EINVAL;
-
- if (midibuf_is_empty(this))
- return 0;
-
- bytes_used = line6_midibuf_bytes_used(this);
-
- if (length > bytes_used)
- length = bytes_used;
-
- length1 = this->size - this->pos_read;
-
- /* check MIDI command length */
- command = this->buf[this->pos_read];
-
- if (command & 0x80) {
- midi_length = midibuf_message_length(command);
- this->command_prev = command;
- } else {
- if (this->command_prev > 0) {
- int midi_length_prev =
- midibuf_message_length(this->command_prev);
-
- if (midi_length_prev > 0) {
- midi_length = midi_length_prev - 1;
- repeat = 1;
- } else
- midi_length = -1;
- } else
- midi_length = -1;
- }
-
- if (midi_length < 0) {
- /* search for end of message */
- if (length < length1) {
- /* no buffer wraparound */
- for (i = 1; i < length; ++i)
- if (this->buf[this->pos_read + i] & 0x80)
- break;
-
- midi_length = i;
- } else {
- /* buffer wraparound */
- length2 = length - length1;
-
- for (i = 1; i < length1; ++i)
- if (this->buf[this->pos_read + i] & 0x80)
- break;
-
- if (i < length1)
- midi_length = i;
- else {
- for (i = 0; i < length2; ++i)
- if (this->buf[i] & 0x80)
- break;
-
- midi_length = length1 + i;
- }
- }
-
- if (midi_length == length)
- midi_length = -1; /* end of message not found */
- }
-
- if (midi_length < 0) {
- if (!this->split)
- return 0; /* command is not yet complete */
- } else {
- if (length < midi_length)
- return 0; /* command is not yet complete */
-
- length = midi_length;
- }
-
- if (length < length1) {
- /* no buffer wraparound */
- memcpy(data + repeat, this->buf + this->pos_read, length);
- this->pos_read += length;
- } else {
- /* buffer wraparound */
- length2 = length - length1;
- memcpy(data + repeat, this->buf + this->pos_read, length1);
- memcpy(data + repeat + length1, this->buf, length2);
- this->pos_read = length2;
- }
-
- if (repeat)
- data[0] = this->command_prev;
-
- this->full = 0;
- return length + repeat;
-}
-
-int line6_midibuf_ignore(struct midi_buffer *this, int length)
-{
- int bytes_used = line6_midibuf_bytes_used(this);
-
- if (length > bytes_used)
- length = bytes_used;
-
- this->pos_read = (this->pos_read + length) % this->size;
- this->full = 0;
- return length;
-}
-
-int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
-{
- int cmd = this->command_prev;
-
- if ((cmd >= 0x80) && (cmd < 0xf0))
- if ((mask & (1 << (cmd & 0x0f))) == 0)
- return 1;
-
- return 0;
-}
-
-void line6_midibuf_destroy(struct midi_buffer *this)
-{
- kfree(this->buf);
- this->buf = NULL;
-}
diff --git a/drivers/staging/line6/midibuf.h b/drivers/staging/line6/midibuf.h
deleted file mode 100644
index 707482b940e4..000000000000
--- a/drivers/staging/line6/midibuf.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef MIDIBUF_H
-#define MIDIBUF_H
-
-struct midi_buffer {
- unsigned char *buf;
- int size;
- int split;
- int pos_read, pos_write;
- int full;
- int command_prev;
-};
-
-extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
-extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
-extern void line6_midibuf_destroy(struct midi_buffer *mb);
-extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
-extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
-extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
- int length);
-extern void line6_midibuf_reset(struct midi_buffer *mb);
-extern int line6_midibuf_skip_message(struct midi_buffer *mb,
- unsigned short mask);
-extern void line6_midibuf_status(struct midi_buffer *mb);
-extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
- int length);
-
-#endif
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
deleted file mode 100644
index a3136b189ee5..000000000000
--- a/drivers/staging/line6/pcm.c
+++ /dev/null
@@ -1,576 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-#include <sound/core.h>
-#include <sound/control.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-static struct snd_line6_pcm *dev2pcm(struct device *dev)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- struct snd_line6_pcm *line6pcm = line6->line6pcm;
- return line6pcm;
-}
-
-/*
- "read" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
-}
-
-/*
- "write" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct snd_line6_pcm *line6pcm = dev2pcm(dev);
- int value;
- int ret;
-
- ret = kstrtoint(buf, 10, &value);
- if (ret < 0)
- return ret;
-
- line6pcm->impulse_volume = value;
-
- if (value > 0)
- line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
- else
- line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
-
- return count;
-}
-static DEVICE_ATTR_RW(impulse_volume);
-
-/*
- "read" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
-}
-
-/*
- "write" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_store(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int value;
- int ret;
-
- ret = kstrtoint(buf, 10, &value);
- if (ret < 0)
- return ret;
-
- dev2pcm(dev)->impulse_period = value;
- return count;
-}
-static DEVICE_ATTR_RW(impulse_period);
-
-#endif
-
-static bool test_flags(unsigned long flags0, unsigned long flags1,
- unsigned long mask)
-{
- return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
-}
-
-int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
-{
- unsigned long flags_old, flags_new, flags_final;
- int err;
-
- do {
- flags_old = ACCESS_ONCE(line6pcm->flags);
- flags_new = flags_old | channels;
- } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
- flags_final = flags_old;
-
- line6pcm->prev_fbuf = NULL;
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
- /* Invoked multiple times in a row so allocate once only */
- if (!line6pcm->buffer_in) {
- line6pcm->buffer_in =
- kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
- line6pcm->max_packet_size, GFP_KERNEL);
- if (!line6pcm->buffer_in) {
- err = -ENOMEM;
- goto pcm_acquire_error;
- }
-
- flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
- }
- }
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
- /*
- Waiting for completion of active URBs in the stop handler is
- a bug, we therefore report an error if capturing is restarted
- too soon.
- */
- if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
- dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
- return -EBUSY;
- }
-
- line6pcm->count_in = 0;
- line6pcm->prev_fsize = 0;
- err = line6_submit_audio_in_all_urbs(line6pcm);
-
- if (err < 0)
- goto pcm_acquire_error;
-
- flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
- }
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
- /* Invoked multiple times in a row so allocate once only */
- if (!line6pcm->buffer_out) {
- line6pcm->buffer_out =
- kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
- line6pcm->max_packet_size, GFP_KERNEL);
- if (!line6pcm->buffer_out) {
- err = -ENOMEM;
- goto pcm_acquire_error;
- }
-
- flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
- }
- }
-
- if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
- /*
- See comment above regarding PCM restart.
- */
- if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
- dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
- return -EBUSY;
- }
-
- line6pcm->count_out = 0;
- err = line6_submit_audio_out_all_urbs(line6pcm);
-
- if (err < 0)
- goto pcm_acquire_error;
-
- flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
- }
-
- return 0;
-
-pcm_acquire_error:
- /*
- If not all requested resources/streams could be obtained, release
- those which were successfully obtained (if any).
- */
- line6_pcm_release(line6pcm, flags_final & channels);
- return err;
-}
-
-int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
-{
- unsigned long flags_old, flags_new;
-
- do {
- flags_old = ACCESS_ONCE(line6pcm->flags);
- flags_new = flags_old & ~channels;
- } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
- line6_unlink_audio_in_urbs(line6pcm);
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
- line6_wait_clear_audio_in_urbs(line6pcm);
- line6_free_capture_buffer(line6pcm);
- }
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
- line6_unlink_audio_out_urbs(line6pcm);
-
- if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
- line6_wait_clear_audio_out_urbs(line6pcm);
- line6_free_playback_buffer(line6pcm);
- }
-
- return 0;
-}
-
-/* trigger callback */
-int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- struct snd_pcm_substream *s;
- int err;
- unsigned long flags;
-
- spin_lock_irqsave(&line6pcm->lock_trigger, flags);
- clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
-
- snd_pcm_group_for_each_entry(s, substream) {
- switch (s->stream) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- err = snd_line6_playback_trigger(line6pcm, cmd);
-
- if (err < 0) {
- spin_unlock_irqrestore(&line6pcm->lock_trigger,
- flags);
- return err;
- }
-
- break;
-
- case SNDRV_PCM_STREAM_CAPTURE:
- err = snd_line6_capture_trigger(line6pcm, cmd);
-
- if (err < 0) {
- spin_unlock_irqrestore(&line6pcm->lock_trigger,
- flags);
- return err;
- }
-
- break;
-
- default:
- dev_err(line6pcm->line6->ifcdev,
- "Unknown stream direction %d\n", s->stream);
- }
- }
-
- spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
- return 0;
-}
-
-/* control info callback */
-static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 256;
- return 0;
-}
-
-/* control get callback */
-static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int i;
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- for (i = 2; i--;)
- ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
-
- return 0;
-}
-
-/* control put callback */
-static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- int i, changed = 0;
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- for (i = 2; i--;)
- if (line6pcm->volume_playback[i] !=
- ucontrol->value.integer.value[i]) {
- line6pcm->volume_playback[i] =
- ucontrol->value.integer.value[i];
- changed = 1;
- }
-
- return changed;
-}
-
-/* control definition */
-static struct snd_kcontrol_new line6_control_playback = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Volume",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_line6_control_playback_info,
- .get = snd_line6_control_playback_get,
- .put = snd_line6_control_playback_put
-};
-
-/*
- Cleanup the PCM device.
-*/
-static void line6_cleanup_pcm(struct snd_pcm *pcm)
-{
- int i;
- struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
- device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
-#endif
-
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (line6pcm->urb_audio_out[i]) {
- usb_kill_urb(line6pcm->urb_audio_out[i]);
- usb_free_urb(line6pcm->urb_audio_out[i]);
- }
- if (line6pcm->urb_audio_in[i]) {
- usb_kill_urb(line6pcm->urb_audio_in[i]);
- usb_free_urb(line6pcm->urb_audio_in[i]);
- }
- }
-}
-
-/* create a PCM device */
-static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
-{
- struct snd_pcm *pcm;
- int err;
-
- err = snd_pcm_new(line6pcm->line6->card,
- (char *)line6pcm->line6->properties->name,
- 0, 1, 1, &pcm);
- if (err < 0)
- return err;
-
- pcm->private_data = line6pcm;
- pcm->private_free = line6_cleanup_pcm;
- line6pcm->pcm = pcm;
- strcpy(pcm->name, line6pcm->line6->properties->name);
-
- /* set operators */
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
- &snd_line6_playback_ops);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
-
- /* pre-allocation of buffers */
- snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
- snd_dma_continuous_data
- (GFP_KERNEL), 64 * 1024,
- 128 * 1024);
-
- return 0;
-}
-
-/* PCM device destructor */
-static int snd_line6_pcm_free(struct snd_device *device)
-{
- return 0;
-}
-
-/*
- Stop substream if still running.
-*/
-static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
-{
- if (substream->runtime && snd_pcm_running(substream)) {
- snd_pcm_stream_lock_irq(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
- snd_pcm_stream_unlock_irq(substream);
- }
-}
-
-/*
- Stop PCM stream.
-*/
-void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
-{
- pcm_disconnect_substream(get_substream
- (line6pcm, SNDRV_PCM_STREAM_CAPTURE));
- pcm_disconnect_substream(get_substream
- (line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
- line6_unlink_wait_clear_audio_out_urbs(line6pcm);
- line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
- Create and register the PCM device and mixer entries.
- Create URBs for playback and capture.
-*/
-int line6_init_pcm(struct usb_line6 *line6,
- struct line6_pcm_properties *properties)
-{
- static struct snd_device_ops pcm_ops = {
- .dev_free = snd_line6_pcm_free,
- };
-
- int err;
- int ep_read = 0, ep_write = 0;
- struct snd_line6_pcm *line6pcm;
-
- if (!(line6->properties->capabilities & LINE6_BIT_PCM))
- return 0; /* skip PCM initialization and report success */
-
- /* initialize PCM subsystem based on product id: */
- switch (line6->product) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTLIVE:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_PODHD300:
- case LINE6_DEVID_PODHD400:
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
- case LINE6_DEVID_PODHD500:
- case LINE6_DEVID_PODX3:
- case LINE6_DEVID_PODX3LIVE:
- ep_read = 0x86;
- ep_write = 0x02;
- break;
-
- case LINE6_DEVID_POCKETPOD:
- ep_read = 0x82;
- ep_write = 0x02;
- break;
-
- case LINE6_DEVID_GUITARPORT:
- case LINE6_DEVID_PODSTUDIO_GX:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- case LINE6_DEVID_TONEPORT_GX:
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
- /* this is for interface_number == 1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX2:
- ep_read = 0x87;
- ep_write = 0x00;
- break; */
-
- default:
- MISSING_CASE;
- }
-
- line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
-
- if (line6pcm == NULL)
- return -ENOMEM;
-
- line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
- line6pcm->volume_monitor = 255;
- line6pcm->line6 = line6;
- line6pcm->ep_audio_read = ep_read;
- line6pcm->ep_audio_write = ep_write;
-
- /* Read and write buffers are sized identically, so choose minimum */
- line6pcm->max_packet_size = min(
- usb_maxpacket(line6->usbdev,
- usb_rcvisocpipe(line6->usbdev, ep_read), 0),
- usb_maxpacket(line6->usbdev,
- usb_sndisocpipe(line6->usbdev, ep_write), 1));
-
- line6pcm->properties = properties;
- line6->line6pcm = line6pcm;
-
- /* PCM device: */
- err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
- if (err < 0)
- return err;
-
- err = snd_line6_new_pcm(line6pcm);
- if (err < 0)
- return err;
-
- spin_lock_init(&line6pcm->lock_audio_out);
- spin_lock_init(&line6pcm->lock_audio_in);
- spin_lock_init(&line6pcm->lock_trigger);
-
- err = line6_create_audio_out_urbs(line6pcm);
- if (err < 0)
- return err;
-
- err = line6_create_audio_in_urbs(line6pcm);
- if (err < 0)
- return err;
-
- /* mixer: */
- err =
- snd_ctl_add(line6->card,
- snd_ctl_new1(&line6_control_playback, line6pcm));
- if (err < 0)
- return err;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- /* impulse response test: */
- err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
- if (err < 0)
- return err;
-
- err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
- if (err < 0)
- return err;
-
- line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
-#endif
-
- return 0;
-}
-
-/* prepare pcm callback */
-int snd_line6_prepare(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- switch (substream->stream) {
- case SNDRV_PCM_STREAM_PLAYBACK:
- if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
- line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-
- break;
-
- case SNDRV_PCM_STREAM_CAPTURE:
- if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
- line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-
- break;
-
- default:
- MISSING_CASE;
- }
-
- if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
- line6pcm->count_out = 0;
- line6pcm->pos_out = 0;
- line6pcm->pos_out_done = 0;
- line6pcm->bytes_out = 0;
- line6pcm->count_in = 0;
- line6pcm->pos_in_done = 0;
- line6pcm->bytes_in = 0;
- }
-
- return 0;
-}
diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h
deleted file mode 100644
index 6aa0d46a2890..000000000000
--- a/drivers/staging/line6/pcm.h
+++ /dev/null
@@ -1,382 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-/*
- PCM interface to POD series devices.
-*/
-
-#ifndef PCM_H
-#define PCM_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "usbdefs.h"
-
-/* number of URBs */
-#define LINE6_ISO_BUFFERS 2
-
-/*
- number of USB frames per URB
- The Line6 Windows driver always transmits two frames per packet, but
- the Linux driver performs significantly better (i.e., lower latency)
- with only one frame per packet.
-*/
-#define LINE6_ISO_PACKETS 1
-
-/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
-#define LINE6_ISO_INTERVAL 1
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-#define LINE6_IMPULSE_DEFAULT_PERIOD 100
-#endif
-
-/*
- Get substream from Line6 PCM data structure
-*/
-#define get_substream(line6pcm, stream) \
- (line6pcm->pcm->streams[stream].substream)
-
-/*
- PCM mode bits.
-
- There are several features of the Line6 USB driver which require PCM
- data to be exchanged with the device:
- *) PCM playback and capture via ALSA
- *) software monitoring (for devices without hardware monitoring)
- *) optional impulse response measurement
- However, from the device's point of view, there is just a single
- capture and playback stream, which must be shared between these
- subsystems. It is therefore necessary to maintain the state of the
- subsystems with respect to PCM usage. We define several constants of
- the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
- following meanings:
- *) <subsystem> is one of
- -) ALSA: PCM playback and capture via ALSA
- -) MONITOR: software monitoring
- -) IMPULSE: optional impulse response measurement
- *) <direction> is one of
- -) PLAYBACK: audio output (from host to device)
- -) CAPTURE: audio input (from device to host)
- *) <resource> is one of
- -) BUFFER: buffer required by PCM data stream
- -) STREAM: actual PCM data stream
-
- The subsystems call line6_pcm_acquire() to acquire the (shared)
- resources needed for a particular operation (e.g., allocate the buffer
- for ALSA playback or start the capture stream for software monitoring).
- When a resource is no longer needed, it is released by calling
- line6_pcm_release(). Buffer allocation and stream startup are handled
- separately to allow the ALSA kernel driver to perform them at
- appropriate places (since the callback which starts a PCM stream is not
- allowed to sleep).
-*/
-enum {
- /* individual bit indices: */
- LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
- LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
- LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
- LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
- LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
- LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
- LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
- LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
- LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
- LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
- LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
- LINE6_INDEX_PAUSE_PLAYBACK,
- LINE6_INDEX_PREPARED,
-
- /* individual bit masks: */
- LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
- LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
- LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
- LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
- LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
- LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
- LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
- LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
- LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
- LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
- LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
-#endif
- LINE6_BIT(PAUSE_PLAYBACK),
- LINE6_BIT(PREPARED),
-
- /* combined bit masks (by operation): */
- LINE6_BITS_PCM_ALSA_BUFFER =
- LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
-
- LINE6_BITS_PCM_ALSA_STREAM =
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
-
- LINE6_BITS_PCM_MONITOR =
- LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM |
- LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
- LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BITS_PCM_IMPULSE =
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
- LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
- LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
-
- /* combined bit masks (by direction): */
- LINE6_BITS_PLAYBACK_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
-#endif
- LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
- LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER ,
-
- LINE6_BITS_PLAYBACK_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
-#endif
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
- LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM ,
-
- LINE6_BITS_CAPTURE_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
-#endif
- LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
- LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER ,
-
- LINE6_BITS_CAPTURE_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
-#endif
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
- LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
-
- LINE6_BITS_STREAM =
- LINE6_BITS_PLAYBACK_STREAM |
- LINE6_BITS_CAPTURE_STREAM
-};
-
-struct line6_pcm_properties {
- struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
- struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
- int bytes_per_frame;
-};
-
-struct snd_line6_pcm {
- /**
- Pointer back to the Line6 driver data structure.
- */
- struct usb_line6 *line6;
-
- /**
- Properties.
- */
- struct line6_pcm_properties *properties;
-
- /**
- ALSA pcm stream
- */
- struct snd_pcm *pcm;
-
- /**
- URBs for audio playback.
- */
- struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
-
- /**
- URBs for audio capture.
- */
- struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
-
- /**
- Temporary buffer for playback.
- Since the packet size is not known in advance, this buffer is
- large enough to store maximum size packets.
- */
- unsigned char *buffer_out;
-
- /**
- Temporary buffer for capture.
- Since the packet size is not known in advance, this buffer is
- large enough to store maximum size packets.
- */
- unsigned char *buffer_in;
-
- /**
- Previously captured frame (for software monitoring).
- */
- unsigned char *prev_fbuf;
-
- /**
- Size of previously captured frame (for software monitoring).
- */
- int prev_fsize;
-
- /**
- Free frame position in the playback buffer.
- */
- snd_pcm_uframes_t pos_out;
-
- /**
- Count processed bytes for playback.
- This is modulo period size (to determine when a period is
- finished).
- */
- unsigned bytes_out;
-
- /**
- Counter to create desired playback sample rate.
- */
- unsigned count_out;
-
- /**
- Playback period size in bytes
- */
- unsigned period_out;
-
- /**
- Processed frame position in the playback buffer.
- The contents of the output ring buffer have been consumed by
- the USB subsystem (i.e., sent to the USB device) up to this
- position.
- */
- snd_pcm_uframes_t pos_out_done;
-
- /**
- Count processed bytes for capture.
- This is modulo period size (to determine when a period is
- finished).
- */
- unsigned bytes_in;
-
- /**
- Counter to create desired capture sample rate.
- */
- unsigned count_in;
-
- /**
- Capture period size in bytes
- */
- unsigned period_in;
-
- /**
- Processed frame position in the capture buffer.
- The contents of the output ring buffer have been consumed by
- the USB subsystem (i.e., sent to the USB device) up to this
- position.
- */
- snd_pcm_uframes_t pos_in_done;
-
- /**
- Bit mask of active playback URBs.
- */
- unsigned long active_urb_out;
-
- /**
- Maximum size of USB packet.
- */
- int max_packet_size;
-
- /**
- USB endpoint for listening to audio data.
- */
- int ep_audio_read;
-
- /**
- USB endpoint for writing audio data.
- */
- int ep_audio_write;
-
- /**
- Bit mask of active capture URBs.
- */
- unsigned long active_urb_in;
-
- /**
- Bit mask of playback URBs currently being unlinked.
- */
- unsigned long unlink_urb_out;
-
- /**
- Bit mask of capture URBs currently being unlinked.
- */
- unsigned long unlink_urb_in;
-
- /**
- Spin lock to protect updates of the playback buffer positions (not
- contents!)
- */
- spinlock_t lock_audio_out;
-
- /**
- Spin lock to protect updates of the capture buffer positions (not
- contents!)
- */
- spinlock_t lock_audio_in;
-
- /**
- Spin lock to protect trigger.
- */
- spinlock_t lock_trigger;
-
- /**
- PCM playback volume (left and right).
- */
- int volume_playback[2];
-
- /**
- PCM monitor volume.
- */
- int volume_monitor;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- /**
- Volume of impulse response test signal (if zero, test is disabled).
- */
- int impulse_volume;
-
- /**
- Period of impulse response test signal.
- */
- int impulse_period;
-
- /**
- Counter for impulse response test signal.
- */
- int impulse_count;
-#endif
-
- /**
- Several status bits (see LINE6_BIT_*).
- */
- unsigned long flags;
-
- int last_frame_in, last_frame_out;
-};
-
-extern int line6_init_pcm(struct usb_line6 *line6,
- struct line6_pcm_properties *properties);
-extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
-extern int snd_line6_prepare(struct snd_pcm_substream *substream);
-extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
-extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
-extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
-
-#endif
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
deleted file mode 100644
index 2ca8900e68c3..000000000000
--- a/drivers/staging/line6/playback.c
+++ /dev/null
@@ -1,592 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "pcm.h"
-#include "pod.h"
-#include "playback.h"
-
-/*
- Software stereo volume control.
-*/
-static void change_volume(struct urb *urb_out, int volume[],
- int bytes_per_frame)
-{
- int chn = 0;
-
- if (volume[0] == 256 && volume[1] == 256)
- return; /* maximum volume - no change */
-
- if (bytes_per_frame == 4) {
- short *p, *buf_end;
-
- p = (short *)urb_out->transfer_buffer;
- buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
-
- for (; p < buf_end; ++p) {
- *p = (*p * volume[chn & 1]) >> 8;
- ++chn;
- }
- } else if (bytes_per_frame == 6) {
- unsigned char *p, *buf_end;
-
- p = (unsigned char *)urb_out->transfer_buffer;
- buf_end = p + urb_out->transfer_buffer_length;
-
- for (; p < buf_end; p += 3) {
- int val;
-
- val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
- val = (val * volume[chn & 1]) >> 8;
- p[0] = val;
- p[1] = val >> 8;
- p[2] = val >> 16;
- ++chn;
- }
- }
-}
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-/*
- Create signal for impulse response test.
-*/
-static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
- struct urb *urb_out, int bytes_per_frame)
-{
- int frames = urb_out->transfer_buffer_length / bytes_per_frame;
-
- if (bytes_per_frame == 4) {
- int i;
- short *pi = (short *)line6pcm->prev_fbuf;
- short *po = (short *)urb_out->transfer_buffer;
-
- for (i = 0; i < frames; ++i) {
- po[0] = pi[0];
- po[1] = 0;
- pi += 2;
- po += 2;
- }
- } else if (bytes_per_frame == 6) {
- int i, j;
- unsigned char *pi = line6pcm->prev_fbuf;
- unsigned char *po = urb_out->transfer_buffer;
-
- for (i = 0; i < frames; ++i) {
- for (j = 0; j < bytes_per_frame / 2; ++j)
- po[j] = pi[j];
-
- for (; j < bytes_per_frame; ++j)
- po[j] = 0;
-
- pi += bytes_per_frame;
- po += bytes_per_frame;
- }
- }
- if (--line6pcm->impulse_count <= 0) {
- ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
- 1] =
- line6pcm->impulse_volume;
- line6pcm->impulse_count = line6pcm->impulse_period;
- }
-}
-
-#endif
-
-/*
- Add signal to buffer for software monitoring.
-*/
-static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
- int volume, int bytes_per_frame)
-{
- if (volume == 0)
- return; /* zero volume - no change */
-
- if (bytes_per_frame == 4) {
- short *pi, *po, *buf_end;
-
- pi = (short *)signal;
- po = (short *)urb_out->transfer_buffer;
- buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
-
- for (; po < buf_end; ++pi, ++po)
- *po += (*pi * volume) >> 8;
- }
-
- /*
- We don't need to handle devices with 6 bytes per frame here
- since they all support hardware monitoring.
- */
-}
-
-/*
- Find a free URB, prepare audio data, and submit URB.
-*/
-static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
-{
- int index;
- unsigned long flags;
- int i, urb_size, urb_frames;
- int ret;
- const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
- const int frame_increment =
- line6pcm->properties->snd_line6_rates.rats[0].num_min;
- const int frame_factor =
- line6pcm->properties->snd_line6_rates.rats[0].den *
- (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
- struct urb *urb_out;
-
- spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
- index =
- find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
-
- if (index < 0 || index >= LINE6_ISO_BUFFERS) {
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
- dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
- return -EINVAL;
- }
-
- urb_out = line6pcm->urb_audio_out[index];
- urb_size = 0;
-
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- /* compute frame size for given sampling rate */
- int fsize = 0;
- struct usb_iso_packet_descriptor *fout =
- &urb_out->iso_frame_desc[i];
-
- if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
- fsize = line6pcm->prev_fsize;
-
- if (fsize == 0) {
- int n;
-
- line6pcm->count_out += frame_increment;
- n = line6pcm->count_out / frame_factor;
- line6pcm->count_out -= n * frame_factor;
- fsize = n * bytes_per_frame;
- }
-
- fout->offset = urb_size;
- fout->length = fsize;
- urb_size += fsize;
- }
-
- if (urb_size == 0) {
- /* can't determine URB size */
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
- dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
- return -EINVAL;
- }
-
- urb_frames = urb_size / bytes_per_frame;
- urb_out->transfer_buffer =
- line6pcm->buffer_out +
- index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
- urb_out->transfer_buffer_length = urb_size;
- urb_out->context = line6pcm;
-
- if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
- !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
- struct snd_pcm_runtime *runtime =
- get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
-
- if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
- /*
- The transferred area goes over buffer boundary,
- copy the data to the temp buffer.
- */
- int len;
-
- len = runtime->buffer_size - line6pcm->pos_out;
-
- if (len > 0) {
- memcpy(urb_out->transfer_buffer,
- runtime->dma_area +
- line6pcm->pos_out * bytes_per_frame,
- len * bytes_per_frame);
- memcpy(urb_out->transfer_buffer +
- len * bytes_per_frame, runtime->dma_area,
- (urb_frames - len) * bytes_per_frame);
- } else
- dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
- len);
- } else {
- memcpy(urb_out->transfer_buffer,
- runtime->dma_area +
- line6pcm->pos_out * bytes_per_frame,
- urb_out->transfer_buffer_length);
- }
-
- line6pcm->pos_out += urb_frames;
- if (line6pcm->pos_out >= runtime->buffer_size)
- line6pcm->pos_out -= runtime->buffer_size;
- } else {
- memset(urb_out->transfer_buffer, 0,
- urb_out->transfer_buffer_length);
- }
-
- change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
-
- if (line6pcm->prev_fbuf != NULL) {
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
- create_impulse_test_signal(line6pcm, urb_out,
- bytes_per_frame);
- if (line6pcm->flags &
- LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
- line6_capture_copy(line6pcm,
- urb_out->transfer_buffer,
- urb_out->
- transfer_buffer_length);
- line6_capture_check_period(line6pcm,
- urb_out->transfer_buffer_length);
- }
- } else {
-#endif
- if (!
- (line6pcm->line6->
- properties->capabilities & LINE6_BIT_HWMON)
- && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
- && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
- add_monitor_signal(urb_out, line6pcm->prev_fbuf,
- line6pcm->volume_monitor,
- bytes_per_frame);
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
- }
-#endif
- }
-
- ret = usb_submit_urb(urb_out, GFP_ATOMIC);
-
- if (ret == 0)
- set_bit(index, &line6pcm->active_urb_out);
- else
- dev_err(line6pcm->line6->ifcdev,
- "URB out #%d submission failed (%d)\n", index, ret);
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
- return 0;
-}
-
-/*
- Submit all currently available playback URBs.
-*/
-int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
-{
- int ret, i;
-
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- ret = submit_audio_out_urb(line6pcm);
- if (ret < 0)
- return ret;
- }
-
- return 0;
-}
-
-/*
- Unlink all currently active playback URBs.
-*/
-void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- unsigned int i;
-
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_out)) {
- if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
- struct urb *u = line6pcm->urb_audio_out[i];
-
- usb_unlink_urb(u);
- }
- }
- }
-}
-
-/*
- Wait until unlinking of all currently active playback URBs has been
- finished.
-*/
-void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- int timeout = HZ;
- unsigned int i;
- int alive;
-
- do {
- alive = 0;
- for (i = LINE6_ISO_BUFFERS; i--;) {
- if (test_bit(i, &line6pcm->active_urb_out))
- alive++;
- }
- if (!alive)
- break;
- set_current_state(TASK_UNINTERRUPTIBLE);
- schedule_timeout(1);
- } while (--timeout > 0);
- if (alive)
- snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
- Unlink all currently active playback URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- line6_unlink_audio_out_urbs(line6pcm);
- line6_wait_clear_audio_out_urbs(line6pcm);
-}
-
-void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
-{
- kfree(line6pcm->buffer_out);
- line6pcm->buffer_out = NULL;
-}
-
-/*
- Callback for completed playback URB.
-*/
-static void audio_out_callback(struct urb *urb)
-{
- int i, index, length = 0, shutdown = 0;
- unsigned long flags;
- struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
- struct snd_pcm_substream *substream =
- get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
-
-#if USE_CLEAR_BUFFER_WORKAROUND
- memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
-#endif
-
- line6pcm->last_frame_out = urb->start_frame;
-
- /* find index of URB */
- for (index = LINE6_ISO_BUFFERS; index--;)
- if (urb == line6pcm->urb_audio_out[index])
- break;
-
- if (index < 0)
- return; /* URB has been unlinked asynchronously */
-
- for (i = LINE6_ISO_PACKETS; i--;)
- length += urb->iso_frame_desc[i].length;
-
- spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
-
- if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- line6pcm->pos_out_done +=
- length / line6pcm->properties->bytes_per_frame;
-
- if (line6pcm->pos_out_done >= runtime->buffer_size)
- line6pcm->pos_out_done -= runtime->buffer_size;
- }
-
- clear_bit(index, &line6pcm->active_urb_out);
-
- for (i = LINE6_ISO_PACKETS; i--;)
- if (urb->iso_frame_desc[i].status == -EXDEV) {
- shutdown = 1;
- break;
- }
-
- if (test_and_clear_bit(index, &line6pcm->unlink_urb_out))
- shutdown = 1;
-
- spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-
- if (!shutdown) {
- submit_audio_out_urb(line6pcm);
-
- if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
- &line6pcm->flags)) {
- line6pcm->bytes_out += length;
- if (line6pcm->bytes_out >= line6pcm->period_out) {
- line6pcm->bytes_out %= line6pcm->period_out;
- snd_pcm_period_elapsed(substream);
- }
- }
- }
-}
-
-/* open playback callback */
-static int snd_line6_playback_open(struct snd_pcm_substream *substream)
-{
- int err;
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- (&line6pcm->
- properties->snd_line6_rates));
- if (err < 0)
- return err;
-
- runtime->hw = line6pcm->properties->snd_line6_playback_hw;
- return 0;
-}
-
-/* close playback callback */
-static int snd_line6_playback_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-/* hw_params playback callback */
-static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- int ret;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- /* -- Florian Demski [FD] */
- /* don't ask me why, but this fixes the bug on my machine */
- if (line6pcm == NULL) {
- if (substream->pcm == NULL)
- return -ENOMEM;
- if (substream->pcm->private_data == NULL)
- return -ENOMEM;
- substream->private_data = substream->pcm->private_data;
- line6pcm = snd_pcm_substream_chip(substream);
- }
- /* -- [FD] end */
-
- ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-
- if (ret < 0)
- return ret;
-
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
- if (ret < 0) {
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
- return ret;
- }
-
- line6pcm->period_out = params_period_bytes(hw_params);
- return 0;
-}
-
-/* hw_free playback callback */
-static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
- return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger playback callback */
-int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
- int err;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_RESUME:
-#endif
- err = line6_pcm_acquire(line6pcm,
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
- case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
- err = line6_pcm_release(line6pcm,
- LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
-
- if (err < 0)
- return err;
-
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
- break;
-
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* playback pointer callback */
-static snd_pcm_uframes_t
-snd_line6_playback_pointer(struct snd_pcm_substream *substream)
-{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
- return line6pcm->pos_out_done;
-}
-
-/* playback operators */
-struct snd_pcm_ops snd_line6_playback_ops = {
- .open = snd_line6_playback_open,
- .close = snd_line6_playback_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_line6_playback_hw_params,
- .hw_free = snd_line6_playback_hw_free,
- .prepare = snd_line6_prepare,
- .trigger = snd_line6_trigger,
- .pointer = snd_line6_playback_pointer,
-};
-
-int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
- int i;
-
- /* create audio URBs and fill in constant values: */
- for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
- struct urb *urb;
-
- /* URB for audio out: */
- urb = line6pcm->urb_audio_out[i] =
- usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
-
- if (urb == NULL) {
- dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
- return -ENOMEM;
- }
-
- urb->dev = line6pcm->line6->usbdev;
- urb->pipe =
- usb_sndisocpipe(line6pcm->line6->usbdev,
- line6pcm->ep_audio_write &
- USB_ENDPOINT_NUMBER_MASK);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->start_frame = -1;
- urb->number_of_packets = LINE6_ISO_PACKETS;
- urb->interval = LINE6_ISO_INTERVAL;
- urb->error_count = 0;
- urb->complete = audio_out_callback;
- }
-
- return 0;
-}
diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h
deleted file mode 100644
index 743bd6f74c57..000000000000
--- a/drivers/staging/line6/playback.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef PLAYBACK_H
-#define PLAYBACK_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-
-/*
- * When the TonePort is used with jack in full duplex mode and the outputs are
- * not connected, the software monitor produces an ugly noise since everything
- * written to the output buffer (i.e., the input signal) will be repeated in
- * the next period (sounds like a delay effect). As a workaround, the output
- * buffer is cleared after the data have been read, but there must be a better
- * solution. Until one is found, this workaround can be used to fix the
- * problem.
- */
-#define USE_CLEAR_BUFFER_WORKAROUND 1
-
-extern struct snd_pcm_ops snd_line6_playback_ops;
-
-extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
- *line6pcm);
-extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
deleted file mode 100644
index 44f4b2f98570..000000000000
--- a/drivers/staging/line6/pod.c
+++ /dev/null
@@ -1,458 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-#include <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#define POD_SYSEX_CODE 3
-#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
-
-/* *INDENT-OFF* */
-
-enum {
- POD_SYSEX_SAVE = 0x24,
- POD_SYSEX_SYSTEM = 0x56,
- POD_SYSEX_SYSTEMREQ = 0x57,
- /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
- POD_SYSEX_STORE = 0x71,
- POD_SYSEX_FINISH = 0x72,
- POD_SYSEX_DUMPMEM = 0x73,
- POD_SYSEX_DUMP = 0x74,
- POD_SYSEX_DUMPREQ = 0x75
-
- /* dumps entire internal memory of PODxt Pro */
- /* POD_SYSEX_DUMPMEM2 = 0x76 */
-};
-
-enum {
- POD_MONITOR_LEVEL = 0x04,
- POD_SYSTEM_INVALID = 0x10000
-};
-
-/* *INDENT-ON* */
-
-enum {
- POD_DUMP_MEMORY = 2
-};
-
-enum {
- POD_BUSY_READ,
- POD_BUSY_WRITE,
- POD_CHANNEL_DIRTY,
- POD_SAVE_PRESSED,
- POD_BUSY_MIDISEND
-};
-
-static struct snd_ratden pod_ratden = {
- .num_min = 78125,
- .num_max = 78125,
- .num_step = 1,
- .den = 2
-};
-
-static struct line6_pcm_properties pod_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 39062,
- .rate_max = 39063,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 39062,
- .rate_max = 39063,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_rates = {
- .nrats = 1,
- .rats = &pod_ratden},
- .bytes_per_frame = POD_BYTES_PER_FRAME
-};
-
-static const char pod_version_header[] = {
- 0xf2, 0x7e, 0x7f, 0x06, 0x02
-};
-
-/* forward declarations: */
-static void pod_startup2(unsigned long data);
-static void pod_startup3(struct usb_line6_pod *pod);
-
-static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
- int size)
-{
- return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
- size);
-}
-
-/*
- Process a completely received message.
-*/
-void line6_pod_process_message(struct usb_line6_pod *pod)
-{
- const unsigned char *buf = pod->line6.buffer_message;
-
- if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
- pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
- pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
- (int) buf[10];
- pod_startup3(pod);
- return;
- }
-
- /* Only look for sysex messages from this device */
- if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
- buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
- return;
- }
- if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
- return;
-
- if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
- short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
- ((int)buf[9] << 4) | (int)buf[10];
- pod->monitor_level = value;
- }
-}
-
-/*
- Transmit PODxt Pro control parameter.
-*/
-void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
- u8 value)
-{
- line6_transmit_parameter(&pod->line6, param, value);
-}
-
-/*
- Send system parameter (from integer).
-*/
-static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
- int code)
-{
- char *sysex;
- static const int size = 5;
-
- sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
- if (!sysex)
- return -ENOMEM;
- sysex[SYSEX_DATA_OFS] = code;
- sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
- sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
- sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
- sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
- line6_send_sysex_message(&pod->line6, sysex, size);
- kfree(sysex);
- return 0;
-}
-
-/*
- "read" request on "serial_number" special file.
-*/
-static ssize_t serial_number_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- return sprintf(buf, "%d\n", pod->serial_number);
-}
-
-/*
- "read" request on "firmware_version" special file.
-*/
-static ssize_t firmware_version_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
- pod->firmware_version % 100);
-}
-
-/*
- "read" request on "device_id" special file.
-*/
-static ssize_t device_id_show(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- return sprintf(buf, "%d\n", pod->device_id);
-}
-
-/*
- POD startup procedure.
- This is a sequence of functions with special requirements (e.g., must
- not run immediately after initialization, must not run in interrupt
- context). After the last one has finished, the device is ready to use.
-*/
-
-static void pod_startup1(struct usb_line6_pod *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
- (unsigned long)pod);
-}
-
-static void pod_startup2(unsigned long data)
-{
- struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
- struct usb_line6 *line6 = &pod->line6;
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
-
- /* request firmware version: */
- line6_version_request_async(line6);
-}
-
-static void pod_startup3(struct usb_line6_pod *pod)
-{
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&pod->startup_work);
-}
-
-static void pod_startup4(struct work_struct *work)
-{
- struct usb_line6_pod *pod =
- container_of(work, struct usb_line6_pod, startup_work);
- struct usb_line6 *line6 = &pod->line6;
-
- CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
-
- /* serial number: */
- line6_read_serial_number(&pod->line6, &pod->serial_number);
-
- /* ALSA audio interface: */
- line6_register_audio(line6);
-}
-
-/* POD special files: */
-static DEVICE_ATTR_RO(device_id);
-static DEVICE_ATTR_RO(firmware_version);
-static DEVICE_ATTR_RO(serial_number);
-
-/* control info callback */
-static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 65535;
- return 0;
-}
-
-/* control get callback */
-static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
-
- ucontrol->value.integer.value[0] = pod->monitor_level;
- return 0;
-}
-
-/* control put callback */
-static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
-
- if (ucontrol->value.integer.value[0] == pod->monitor_level)
- return 0;
-
- pod->monitor_level = ucontrol->value.integer.value[0];
- pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
- POD_MONITOR_LEVEL);
- return 1;
-}
-
-/* control definition */
-static struct snd_kcontrol_new pod_control_monitor = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Monitor Playback Volume",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_pod_control_monitor_info,
- .get = snd_pod_control_monitor_get,
- .put = snd_pod_control_monitor_put
-};
-
-/*
- POD destructor.
-*/
-static void pod_destruct(struct usb_interface *interface)
-{
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- if (pod == NULL)
- return;
- line6_cleanup_audio(&pod->line6);
-
- del_timer(&pod->startup_timer);
- cancel_work_sync(&pod->startup_work);
-}
-
-/*
- Create sysfs entries.
-*/
-static int pod_create_files2(struct device *dev)
-{
- int err;
-
- CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
- CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
- CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
- return 0;
-}
-
-/*
- Try to init POD device.
-*/
-static int pod_try_init(struct usb_interface *interface,
- struct usb_line6_pod *pod)
-{
- int err;
- struct usb_line6 *line6 = &pod->line6;
-
- init_timer(&pod->startup_timer);
- INIT_WORK(&pod->startup_work, pod_startup4);
-
- if ((interface == NULL) || (pod == NULL))
- return -ENODEV;
-
- /* create sysfs entries: */
- err = pod_create_files2(&interface->dev);
- if (err < 0)
- return err;
-
- /* initialize audio system: */
- err = line6_init_audio(line6);
- if (err < 0)
- return err;
-
- /* initialize MIDI subsystem: */
- err = line6_init_midi(line6);
- if (err < 0)
- return err;
-
- /* initialize PCM subsystem: */
- err = line6_init_pcm(line6, &pod_pcm_properties);
- if (err < 0)
- return err;
-
- /* register monitor control: */
- err = snd_ctl_add(line6->card,
- snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
- if (err < 0)
- return err;
-
- /*
- When the sound card is registered at this point, the PODxt Live
- displays "Invalid Code Error 07", so we do it later in the event
- handler.
- */
-
- if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
- pod->monitor_level = POD_SYSTEM_INVALID;
-
- /* initiate startup procedure: */
- pod_startup1(pod);
- }
-
- return 0;
-}
-
-/*
- Init POD device (and clean up in case of failure).
-*/
-int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
-{
- int err = pod_try_init(interface, pod);
-
- if (err < 0)
- pod_destruct(interface);
-
- return err;
-}
-
-/*
- POD device disconnected.
-*/
-void line6_pod_disconnect(struct usb_interface *interface)
-{
- struct usb_line6_pod *pod;
-
- if (interface == NULL)
- return;
- pod = usb_get_intfdata(interface);
-
- if (pod != NULL) {
- struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
- struct device *dev = &interface->dev;
-
- if (line6pcm != NULL)
- line6_pcm_disconnect(line6pcm);
-
- if (dev != NULL) {
- /* remove sysfs entries: */
- device_remove_file(dev, &dev_attr_device_id);
- device_remove_file(dev, &dev_attr_firmware_version);
- device_remove_file(dev, &dev_attr_serial_number);
- }
- }
-
- pod_destruct(interface);
-}
diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h
deleted file mode 100644
index 3e3f1671337a..000000000000
--- a/drivers/staging/line6/pod.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef POD_H
-#define POD_H
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <sound/core.h>
-
-#include "driver.h"
-
-/*
- PODxt Live interfaces
-*/
-#define PODXTLIVE_INTERFACE_POD 0
-#define PODXTLIVE_INTERFACE_VARIAX 1
-
-/*
- Locate name in binary program dump
-*/
-#define POD_NAME_OFFSET 0
-#define POD_NAME_LENGTH 16
-
-/*
- Other constants
-*/
-#define POD_CONTROL_SIZE 0x80
-#define POD_BUFSIZE_DUMPREQ 7
-#define POD_STARTUP_DELAY 1000
-
-/*
- Stages of POD startup procedure
-*/
-enum {
- POD_STARTUP_INIT = 1,
- POD_STARTUP_VERSIONREQ,
- POD_STARTUP_WORKQUEUE,
- POD_STARTUP_SETUP,
- POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
-};
-
-struct usb_line6_pod {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-
- /**
- Instrument monitor level.
- */
- int monitor_level;
-
- /**
- Timer for device initializaton.
- */
- struct timer_list startup_timer;
-
- /**
- Work handler for device initializaton.
- */
- struct work_struct startup_work;
-
- /**
- Current progress in startup procedure.
- */
- int startup_progress;
-
- /**
- Serial number of device.
- */
- int serial_number;
-
- /**
- Firmware version (x 100).
- */
- int firmware_version;
-
- /**
- Device ID.
- */
- int device_id;
-};
-
-extern void line6_pod_disconnect(struct usb_interface *interface);
-extern int line6_pod_init(struct usb_interface *interface,
- struct usb_line6_pod *pod);
-extern void line6_pod_process_message(struct usb_line6_pod *pod);
-extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
- u8 value);
-
-#endif
diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c
deleted file mode 100644
index 7ef45437b4f2..000000000000
--- a/drivers/staging/line6/podhd.c
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@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, version 2.
- *
- */
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "pcm.h"
-#include "podhd.h"
-
-#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
-
-static struct snd_ratden podhd_ratden = {
- .num_min = 48000,
- .num_max = 48000,
- .num_step = 1,
- .den = 1,
-};
-
-static struct line6_pcm_properties podhd_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_48000,
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_rates = {
- .nrats = 1,
- .rats = &podhd_ratden},
- .bytes_per_frame = PODHD_BYTES_PER_FRAME
-};
-
-/*
- POD HD destructor.
-*/
-static void podhd_destruct(struct usb_interface *interface)
-{
- struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
-
- if (podhd == NULL)
- return;
- line6_cleanup_audio(&podhd->line6);
-}
-
-/*
- Try to init POD HD device.
-*/
-static int podhd_try_init(struct usb_interface *interface,
- struct usb_line6_podhd *podhd)
-{
- int err;
- struct usb_line6 *line6 = &podhd->line6;
-
- if ((interface == NULL) || (podhd == NULL))
- return -ENODEV;
-
- /* initialize audio system: */
- err = line6_init_audio(line6);
- if (err < 0)
- return err;
-
- /* initialize MIDI subsystem: */
- err = line6_init_midi(line6);
- if (err < 0)
- return err;
-
- /* initialize PCM subsystem: */
- err = line6_init_pcm(line6, &podhd_pcm_properties);
- if (err < 0)
- return err;
-
- /* register USB audio system: */
- err = line6_register_audio(line6);
- return err;
-}
-
-/*
- Init POD HD device (and clean up in case of failure).
-*/
-int line6_podhd_init(struct usb_interface *interface,
- struct usb_line6_podhd *podhd)
-{
- int err = podhd_try_init(interface, podhd);
-
- if (err < 0)
- podhd_destruct(interface);
-
- return err;
-}
-
-/*
- POD HD device disconnected.
-*/
-void line6_podhd_disconnect(struct usb_interface *interface)
-{
- struct usb_line6_podhd *podhd;
-
- if (interface == NULL)
- return;
- podhd = usb_get_intfdata(interface);
-
- if (podhd != NULL) {
- struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
-
- if (line6pcm != NULL)
- line6_pcm_disconnect(line6pcm);
- }
-
- podhd_destruct(interface);
-}
diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h
deleted file mode 100644
index 652f74056bb9..000000000000
--- a/drivers/staging/line6/podhd.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@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, version 2.
- *
- */
-
-#ifndef PODHD_H
-#define PODHD_H
-
-#include <linux/usb.h>
-
-#include "driver.h"
-
-struct usb_line6_podhd {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-};
-
-extern void line6_podhd_disconnect(struct usb_interface *interface);
-extern int line6_podhd_init(struct usb_interface *interface,
- struct usb_line6_podhd *podhd);
-
-#endif /* PODHD_H */
diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h
deleted file mode 100644
index b4eee2b73831..000000000000
--- a/drivers/staging/line6/revision.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef DRIVER_REVISION
-/* current subversion revision */
-#define DRIVER_REVISION " (904)"
-#endif
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
deleted file mode 100644
index 69437158d383..000000000000
--- a/drivers/staging/line6/toneport.c
+++ /dev/null
@@ -1,460 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- * Emil Myhrman (emil.myhrman@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, version 2.
- *
- */
-
-#include <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "toneport.h"
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
-
-#define TONEPORT_PCM_DELAY 1
-
-static struct snd_ratden toneport_ratden = {
- .num_min = 44100,
- .num_max = 44100,
- .num_step = 1,
- .den = 1
-};
-
-static struct line6_pcm_properties toneport_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 44100,
- .rate_max = 44100,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
- SNDRV_PCM_INFO_RESUME |
-#endif
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 44100,
- .rate_max = 44100,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = 64,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024},
- .snd_line6_rates = {
- .nrats = 1,
- .rats = &toneport_ratden},
- .bytes_per_frame = 4
-};
-
-/*
- For the led on Guitarport.
- Brightness goes from 0x00 to 0x26. Set a value above this to have led
- blink.
- (void cmd_0x02(byte red, byte green)
-*/
-static int led_red = 0x00;
-static int led_green = 0x26;
-
-static const struct {
- const char *name;
- int code;
-} toneport_source_info[] = {
- {"Microphone", 0x0a01},
- {"Line", 0x0801},
- {"Instrument", 0x0b01},
- {"Inst & Mic", 0x0901}
-};
-
-static bool toneport_has_led(short product)
-{
- return
- (product == LINE6_DEVID_GUITARPORT) ||
- (product == LINE6_DEVID_TONEPORT_GX);
- /* add your device here if you are missing support for the LEDs */
-}
-
-static void toneport_update_led(struct device *dev)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_toneport *tp = usb_get_intfdata(interface);
- struct usb_line6 *line6;
-
- if (!tp)
- return;
-
- line6 = &tp->line6;
- if (line6)
- toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
- led_green);
-}
-
-static ssize_t toneport_set_led_red(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int retval;
-
- retval = kstrtoint(buf, 10, &led_red);
- if (retval)
- return retval;
-
- toneport_update_led(dev);
- return count;
-}
-
-static ssize_t toneport_set_led_green(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- int retval;
-
- retval = kstrtoint(buf, 10, &led_green);
- if (retval)
- return retval;
-
- toneport_update_led(dev);
- return count;
-}
-
-static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
- toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
- toneport_set_led_green);
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
-{
- int ret;
-
- ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
-
- if (ret < 0) {
- dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
- return ret;
- }
-
- return 0;
-}
-
-/* monitor info callback */
-static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = 256;
- return 0;
-}
-
-/* monitor get callback */
-static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
- return 0;
-}
-
-/* monitor put callback */
-static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
- if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
- return 0;
-
- line6pcm->volume_monitor = ucontrol->value.integer.value[0];
-
- if (line6pcm->volume_monitor > 0)
- line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
- else
- line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
-
- return 1;
-}
-
-/* source info callback */
-static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- const int size = ARRAY_SIZE(toneport_source_info);
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = size;
-
- if (uinfo->value.enumerated.item >= size)
- uinfo->value.enumerated.item = size - 1;
-
- strcpy(uinfo->value.enumerated.name,
- toneport_source_info[uinfo->value.enumerated.item].name);
-
- return 0;
-}
-
-/* source get callback */
-static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6pcm->line6;
- ucontrol->value.enumerated.item[0] = toneport->source;
- return 0;
-}
-
-/* source put callback */
-static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
- struct usb_line6_toneport *toneport =
- (struct usb_line6_toneport *)line6pcm->line6;
- unsigned int source;
-
- source = ucontrol->value.enumerated.item[0];
- if (source >= ARRAY_SIZE(toneport_source_info))
- return -EINVAL;
- if (source == toneport->source)
- return 0;
-
- toneport->source = source;
- toneport_send_cmd(toneport->line6.usbdev,
- toneport_source_info[source].code, 0x0000);
- return 1;
-}
-
-static void toneport_start_pcm(unsigned long arg)
-{
- struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
- struct usb_line6 *line6 = &toneport->line6;
-
- line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
-}
-
-/* control definition */
-static struct snd_kcontrol_new toneport_control_monitor = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Monitor Playback Volume",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_toneport_monitor_info,
- .get = snd_toneport_monitor_get,
- .put = snd_toneport_monitor_put
-};
-
-/* source selector definition */
-static struct snd_kcontrol_new toneport_control_source = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Capture Source",
- .index = 0,
- .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
- .info = snd_toneport_source_info,
- .get = snd_toneport_source_get,
- .put = snd_toneport_source_put
-};
-
-/*
- Toneport destructor.
-*/
-static void toneport_destruct(struct usb_interface *interface)
-{
- struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
-
- if (toneport == NULL)
- return;
- line6_cleanup_audio(&toneport->line6);
-}
-
-/*
- Setup Toneport device.
-*/
-static void toneport_setup(struct usb_line6_toneport *toneport)
-{
- int ticks;
- struct usb_line6 *line6 = &toneport->line6;
- struct usb_device *usbdev = line6->usbdev;
- u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
- /* sync time on device with host: */
- ticks = (int)get_seconds();
- line6_write_data(line6, 0x80c6, &ticks, 4);
-
- /* enable device: */
- toneport_send_cmd(usbdev, 0x0301, 0x0000);
-
- /* initialize source select: */
- switch (le16_to_cpu(usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- toneport_send_cmd(usbdev,
- toneport_source_info[toneport->source].code,
- 0x0000);
- }
-
- if (toneport_has_led(idProduct))
- toneport_update_led(&usbdev->dev);
-}
-
-/*
- Try to init Toneport device.
-*/
-static int toneport_try_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport)
-{
- int err;
- struct usb_line6 *line6 = &toneport->line6;
- struct usb_device *usbdev = line6->usbdev;
- u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
-
- if ((interface == NULL) || (toneport == NULL))
- return -ENODEV;
-
- /* initialize audio system: */
- err = line6_init_audio(line6);
- if (err < 0)
- return err;
-
- /* initialize PCM subsystem: */
- err = line6_init_pcm(line6, &toneport_pcm_properties);
- if (err < 0)
- return err;
-
- /* register monitor control: */
- err = snd_ctl_add(line6->card,
- snd_ctl_new1(&toneport_control_monitor,
- line6->line6pcm));
- if (err < 0)
- return err;
-
- /* register source select control: */
- switch (le16_to_cpu(usbdev->descriptor.idProduct)) {
- case LINE6_DEVID_TONEPORT_UX1:
- case LINE6_DEVID_TONEPORT_UX2:
- case LINE6_DEVID_PODSTUDIO_UX1:
- case LINE6_DEVID_PODSTUDIO_UX2:
- err =
- snd_ctl_add(line6->card,
- snd_ctl_new1(&toneport_control_source,
- line6->line6pcm));
- if (err < 0)
- return err;
- }
-
- /* register audio system: */
- err = line6_register_audio(line6);
- if (err < 0)
- return err;
-
- line6_read_serial_number(line6, &toneport->serial_number);
- line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
-
- if (toneport_has_led(idProduct)) {
- CHECK_RETURN(device_create_file
- (&interface->dev, &dev_attr_led_red));
- CHECK_RETURN(device_create_file
- (&interface->dev, &dev_attr_led_green));
- }
-
- toneport_setup(toneport);
-
- init_timer(&toneport->timer);
- toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
- toneport->timer.function = toneport_start_pcm;
- toneport->timer.data = (unsigned long)toneport;
- add_timer(&toneport->timer);
-
- return 0;
-}
-
-/*
- Init Toneport device (and clean up in case of failure).
-*/
-int line6_toneport_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport)
-{
- int err = toneport_try_init(interface, toneport);
-
- if (err < 0)
- toneport_destruct(interface);
-
- return err;
-}
-
-/*
- Resume Toneport device after reset.
-*/
-void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
-{
- toneport_setup(toneport);
-}
-
-/*
- Toneport device disconnected.
-*/
-void line6_toneport_disconnect(struct usb_interface *interface)
-{
- struct usb_line6_toneport *toneport;
- u16 idProduct;
-
- if (interface == NULL)
- return;
-
- toneport = usb_get_intfdata(interface);
- del_timer_sync(&toneport->timer);
- idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct);
-
- if (toneport_has_led(idProduct)) {
- device_remove_file(&interface->dev, &dev_attr_led_red);
- device_remove_file(&interface->dev, &dev_attr_led_green);
- }
-
- if (toneport != NULL) {
- struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
-
- if (line6pcm != NULL) {
- line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
- line6_pcm_disconnect(line6pcm);
- }
- }
-
- toneport_destruct(interface);
-}
diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h
deleted file mode 100644
index 8576b7263648..000000000000
--- a/drivers/staging/line6/toneport.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef TONEPORT_H
-#define TONEPORT_H
-
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-struct usb_line6_toneport {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-
- /**
- Source selector.
- */
- int source;
-
- /**
- Serial number of device.
- */
- int serial_number;
-
- /**
- Firmware version (x 100).
- */
- int firmware_version;
-
- /**
- Timer for delayed PCM startup.
- */
- struct timer_list timer;
-};
-
-extern void line6_toneport_disconnect(struct usb_interface *interface);
-extern int line6_toneport_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport);
-extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
-
-#endif
diff --git a/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h
deleted file mode 100644
index 2d1cc472bead..000000000000
--- a/drivers/staging/line6/usbdefs.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef USBDEFS_H
-#define USBDEFS_H
-
-#define LINE6_VENDOR_ID 0x0e41
-
-#define USB_INTERVALS_PER_SECOND 1000
-
-/*
- Device ids.
-*/
-#define LINE6_DEVID_BASSPODXT 0x4250
-#define LINE6_DEVID_BASSPODXTLIVE 0x4642
-#define LINE6_DEVID_BASSPODXTPRO 0x4252
-#define LINE6_DEVID_GUITARPORT 0x4750
-#define LINE6_DEVID_POCKETPOD 0x5051
-#define LINE6_DEVID_PODHD300 0x5057
-#define LINE6_DEVID_PODHD400 0x5058
-#define LINE6_DEVID_PODHD500 0x414D
-#define LINE6_DEVID_PODSTUDIO_GX 0x4153
-#define LINE6_DEVID_PODSTUDIO_UX1 0x4150
-#define LINE6_DEVID_PODSTUDIO_UX2 0x4151
-#define LINE6_DEVID_PODX3 0x414a
-#define LINE6_DEVID_PODX3LIVE 0x414b
-#define LINE6_DEVID_PODXT 0x5044
-#define LINE6_DEVID_PODXTLIVE 0x4650
-#define LINE6_DEVID_PODXTPRO 0x5050
-#define LINE6_DEVID_TONEPORT_GX 0x4147
-#define LINE6_DEVID_TONEPORT_UX1 0x4141
-#define LINE6_DEVID_TONEPORT_UX2 0x4142
-#define LINE6_DEVID_VARIAX 0x534d
-
-#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
-
-enum {
- LINE6_INDEX_BASSPODXT,
- LINE6_INDEX_BASSPODXTLIVE,
- LINE6_INDEX_BASSPODXTPRO,
- LINE6_INDEX_GUITARPORT,
- LINE6_INDEX_POCKETPOD,
- LINE6_INDEX_PODHD300,
- LINE6_INDEX_PODHD400,
- LINE6_INDEX_PODHD500,
- LINE6_INDEX_PODSTUDIO_GX,
- LINE6_INDEX_PODSTUDIO_UX1,
- LINE6_INDEX_PODSTUDIO_UX2,
- LINE6_INDEX_PODX3,
- LINE6_INDEX_PODX3LIVE,
- LINE6_INDEX_PODXT,
- LINE6_INDEX_PODXTLIVE,
- LINE6_INDEX_PODXTPRO,
- LINE6_INDEX_TONEPORT_GX,
- LINE6_INDEX_TONEPORT_UX1,
- LINE6_INDEX_TONEPORT_UX2,
- LINE6_INDEX_VARIAX,
-
- LINE6_BIT(BASSPODXT),
- LINE6_BIT(BASSPODXTLIVE),
- LINE6_BIT(BASSPODXTPRO),
- LINE6_BIT(GUITARPORT),
- LINE6_BIT(POCKETPOD),
- LINE6_BIT(PODHD300),
- LINE6_BIT(PODHD400),
- LINE6_BIT(PODHD500),
- LINE6_BIT(PODSTUDIO_GX),
- LINE6_BIT(PODSTUDIO_UX1),
- LINE6_BIT(PODSTUDIO_UX2),
- LINE6_BIT(PODX3),
- LINE6_BIT(PODX3LIVE),
- LINE6_BIT(PODXT),
- LINE6_BIT(PODXTLIVE),
- LINE6_BIT(PODXTPRO),
- LINE6_BIT(TONEPORT_GX),
- LINE6_BIT(TONEPORT_UX1),
- LINE6_BIT(TONEPORT_UX2),
- LINE6_BIT(VARIAX),
-
- LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO,
- LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE |
- LINE6_BIT_PODX3LIVE,
- LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE |
- LINE6_BIT_PODXTPRO,
- LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE,
- LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
- LINE6_BIT_PODHD400 |
- LINE6_BIT_PODHD500,
- LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT |
- LINE6_BIT_BASSPODXTLIVE |
- LINE6_BIT_BASSPODXTPRO
-};
-
-/* device supports settings parameter via USB */
-#define LINE6_BIT_CONTROL (1 << 0)
-/* device supports PCM input/output via USB */
-#define LINE6_BIT_PCM (1 << 1)
-/* device support hardware monitoring */
-#define LINE6_BIT_HWMON (1 << 2)
-
-#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \
- LINE6_BIT_PCM | \
- LINE6_BIT_HWMON)
-
-#define LINE6_FALLBACK_INTERVAL 10
-#define LINE6_FALLBACK_MAXPACKETSIZE 16
-
-#endif
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
deleted file mode 100644
index ae2be99f9a92..000000000000
--- a/drivers/staging/line6/variax.c
+++ /dev/null
@@ -1,235 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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/slab.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "variax.h"
-
-#define VARIAX_OFFSET_ACTIVATE 7
-
-/*
- This message is sent by the device during initialization and identifies
- the connected guitar version.
-*/
-static const char variax_init_version[] = {
- 0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
- 0x07, 0x00, 0x00, 0x00
-};
-
-/*
- This message is the last one sent by the device during initialization.
-*/
-static const char variax_init_done[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
-};
-
-static const char variax_activate[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
- 0xf7
-};
-
-/* forward declarations: */
-static void variax_startup2(unsigned long data);
-static void variax_startup4(unsigned long data);
-static void variax_startup5(unsigned long data);
-
-static void variax_activate_async(struct usb_line6_variax *variax, int a)
-{
- variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
- line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
- sizeof(variax_activate));
-}
-
-/*
- Variax startup procedure.
- This is a sequence of functions with special requirements (e.g., must
- not run immediately after initialization, must not run in interrupt
- context). After the last one has finished, the device is ready to use.
-*/
-
-static void variax_startup1(struct usb_line6_variax *variax)
-{
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-
- /* delay startup procedure: */
- line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
- variax_startup2, (unsigned long)variax);
-}
-
-static void variax_startup2(unsigned long data)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
- struct usb_line6 *line6 = &variax->line6;
-
- /* schedule another startup procedure until startup is complete: */
- if (variax->startup_progress >= VARIAX_STARTUP_LAST)
- return;
-
- variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
- line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
- variax_startup2, (unsigned long)variax);
-
- /* request firmware version: */
- line6_version_request_async(line6);
-}
-
-static void variax_startup3(struct usb_line6_variax *variax)
-{
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
-
- /* delay startup procedure: */
- line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
- variax_startup4, (unsigned long)variax);
-}
-
-static void variax_startup4(unsigned long data)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress,
- VARIAX_STARTUP_ACTIVATE);
-
- /* activate device: */
- variax_activate_async(variax, 1);
- line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
- variax_startup5, (unsigned long)variax);
-}
-
-static void variax_startup5(unsigned long data)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress,
- VARIAX_STARTUP_WORKQUEUE);
-
- /* schedule work for global work queue: */
- schedule_work(&variax->startup_work);
-}
-
-static void variax_startup6(struct work_struct *work)
-{
- struct usb_line6_variax *variax =
- container_of(work, struct usb_line6_variax, startup_work);
-
- CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-
- /* ALSA audio interface: */
- line6_register_audio(&variax->line6);
-}
-
-/*
- Process a completely received message.
-*/
-void line6_variax_process_message(struct usb_line6_variax *variax)
-{
- const unsigned char *buf = variax->line6.buffer_message;
-
- switch (buf[0]) {
- case LINE6_RESET:
- dev_info(variax->line6.ifcdev, "VARIAX reset\n");
- break;
-
- case LINE6_SYSEX_BEGIN:
- if (memcmp(buf + 1, variax_init_version + 1,
- sizeof(variax_init_version) - 1) == 0) {
- variax_startup3(variax);
- } else if (memcmp(buf + 1, variax_init_done + 1,
- sizeof(variax_init_done) - 1) == 0) {
- /* notify of complete initialization: */
- variax_startup4((unsigned long)variax);
- }
- break;
- }
-}
-
-/*
- Variax destructor.
-*/
-static void variax_destruct(struct usb_interface *interface)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(interface);
-
- if (variax == NULL)
- return;
- line6_cleanup_audio(&variax->line6);
-
- del_timer(&variax->startup_timer1);
- del_timer(&variax->startup_timer2);
- cancel_work_sync(&variax->startup_work);
-
- kfree(variax->buffer_activate);
-}
-
-/*
- Try to init workbench device.
-*/
-static int variax_try_init(struct usb_interface *interface,
- struct usb_line6_variax *variax)
-{
- int err;
-
- init_timer(&variax->startup_timer1);
- init_timer(&variax->startup_timer2);
- INIT_WORK(&variax->startup_work, variax_startup6);
-
- if ((interface == NULL) || (variax == NULL))
- return -ENODEV;
-
- /* initialize USB buffers: */
- variax->buffer_activate = kmemdup(variax_activate,
- sizeof(variax_activate), GFP_KERNEL);
-
- if (variax->buffer_activate == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- return -ENOMEM;
- }
-
- /* initialize audio system: */
- err = line6_init_audio(&variax->line6);
- if (err < 0)
- return err;
-
- /* initialize MIDI subsystem: */
- err = line6_init_midi(&variax->line6);
- if (err < 0)
- return err;
-
- /* initiate startup procedure: */
- variax_startup1(variax);
- return 0;
-}
-
-/*
- Init workbench device (and clean up in case of failure).
-*/
-int line6_variax_init(struct usb_interface *interface,
- struct usb_line6_variax *variax)
-{
- int err = variax_try_init(interface, variax);
-
- if (err < 0)
- variax_destruct(interface);
-
- return err;
-}
-
-/*
- Workbench device disconnected.
-*/
-void line6_variax_disconnect(struct usb_interface *interface)
-{
- if (interface == NULL)
- return;
-
- variax_destruct(interface);
-}
diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h
deleted file mode 100644
index 24de79620d89..000000000000
--- a/drivers/staging/line6/variax.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- * This program is free software; 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.
- *
- */
-
-#ifndef VARIAX_H
-#define VARIAX_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-#define VARIAX_STARTUP_DELAY1 1000
-#define VARIAX_STARTUP_DELAY3 100
-#define VARIAX_STARTUP_DELAY4 100
-
-/*
- Stages of Variax startup procedure
-*/
-enum {
- VARIAX_STARTUP_INIT = 1,
- VARIAX_STARTUP_VERSIONREQ,
- VARIAX_STARTUP_WAIT,
- VARIAX_STARTUP_ACTIVATE,
- VARIAX_STARTUP_WORKQUEUE,
- VARIAX_STARTUP_SETUP,
- VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
-};
-
-struct usb_line6_variax {
- /**
- Generic Line6 USB data.
- */
- struct usb_line6 line6;
-
- /**
- Buffer for activation code.
- */
- unsigned char *buffer_activate;
-
- /**
- Handler for device initializaton.
- */
- struct work_struct startup_work;
-
- /**
- Timers for device initializaton.
- */
- struct timer_list startup_timer1;
- struct timer_list startup_timer2;
-
- /**
- Current progress in startup procedure.
- */
- int startup_progress;
-};
-
-extern void line6_variax_disconnect(struct usb_interface *interface);
-extern int line6_variax_init(struct usb_interface *interface,
- struct usb_line6_variax *variax);
-extern void line6_variax_process_message(struct usb_line6_variax *variax);
-
-#endif
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs.h b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
index a6b2f906bb1a..4410d7fdc1b4 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs.h
@@ -85,6 +85,9 @@ static inline int __is_po2(unsigned long long val)
#include <linux/list.h>
+int libcfs_arch_init(void);
+void libcfs_arch_cleanup(void);
+
/* libcfs tcpip */
int libcfs_ipif_query(char *name, int *up, __u32 *ip, __u32 *mask);
int libcfs_ipif_enumerate(char ***names);
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
index 375586bf7312..808e49411a30 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_hash.h
@@ -454,25 +454,23 @@ cfs_hash_bkt_size(struct cfs_hash *hs)
hs->hs_extra_bytes;
}
-#define CFS_HOP(hs, op) (hs)->hs_ops->hs_ ## op
-
static inline unsigned
cfs_hash_id(struct cfs_hash *hs, const void *key, unsigned mask)
{
- return CFS_HOP(hs, hash)(hs, key, mask);
+ return hs->hs_ops->hs_hash(hs, key, mask);
}
static inline void *
cfs_hash_key(struct cfs_hash *hs, struct hlist_node *hnode)
{
- return CFS_HOP(hs, key)(hnode);
+ return hs->hs_ops->hs_key(hnode);
}
static inline void
cfs_hash_keycpy(struct cfs_hash *hs, struct hlist_node *hnode, void *key)
{
- if (CFS_HOP(hs, keycpy) != NULL)
- CFS_HOP(hs, keycpy)(hnode, key);
+ if (hs->hs_ops->hs_keycpy)
+ hs->hs_ops->hs_keycpy(hnode, key);
}
/**
@@ -481,42 +479,38 @@ cfs_hash_keycpy(struct cfs_hash *hs, struct hlist_node *hnode, void *key)
static inline int
cfs_hash_keycmp(struct cfs_hash *hs, const void *key, struct hlist_node *hnode)
{
- return CFS_HOP(hs, keycmp)(key, hnode);
+ return hs->hs_ops->hs_keycmp(key, hnode);
}
static inline void *
cfs_hash_object(struct cfs_hash *hs, struct hlist_node *hnode)
{
- return CFS_HOP(hs, object)(hnode);
+ return hs->hs_ops->hs_object(hnode);
}
static inline void
cfs_hash_get(struct cfs_hash *hs, struct hlist_node *hnode)
{
- return CFS_HOP(hs, get)(hs, hnode);
+ return hs->hs_ops->hs_get(hs, hnode);
}
static inline void
cfs_hash_put_locked(struct cfs_hash *hs, struct hlist_node *hnode)
{
- LASSERT(CFS_HOP(hs, put_locked) != NULL);
-
- return CFS_HOP(hs, put_locked)(hs, hnode);
+ return hs->hs_ops->hs_put_locked(hs, hnode);
}
static inline void
cfs_hash_put(struct cfs_hash *hs, struct hlist_node *hnode)
{
- LASSERT(CFS_HOP(hs, put) != NULL);
-
- return CFS_HOP(hs, put)(hs, hnode);
+ return hs->hs_ops->hs_put(hs, hnode);
}
static inline void
cfs_hash_exit(struct cfs_hash *hs, struct hlist_node *hnode)
{
- if (CFS_HOP(hs, exit))
- CFS_HOP(hs, exit)(hs, hnode);
+ if (hs->hs_ops->hs_exit)
+ hs->hs_ops->hs_exit(hs, hnode);
}
static inline void cfs_hash_lock(struct cfs_hash *hs, int excl)
diff --git a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
index 2817112c0633..3d86fb5b5481 100644
--- a/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
+++ b/drivers/staging/lustre/include/linux/libcfs/libcfs_private.h
@@ -458,14 +458,6 @@ struct libcfs_device_userstate {
struct page *ldu_memhog_root_page;
};
-/* what used to be in portals_lib.h */
-#ifndef MIN
-# define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-#ifndef MAX
-# define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
#define MKSTR(ptr) ((ptr)) ? (ptr) : ""
static inline int cfs_size_round4(int val)
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
index 7e89b3be1a74..0038d29a37fe 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-lnet.h
@@ -636,6 +636,7 @@ lnet_net2rnethash(__u32 net)
}
extern lnd_t the_lolnd;
+extern int avoid_asym_router_failure;
int lnet_cpt_of_nid_locked(lnet_nid_t nid);
int lnet_cpt_of_nid(lnet_nid_t nid);
@@ -752,9 +753,9 @@ int lnet_fail_nid(lnet_nid_t nid, unsigned int threshold);
void lnet_counters_get(lnet_counters_t *counters);
void lnet_counters_reset(void);
-unsigned int lnet_iov_nob(unsigned int niov, struct iovec *iov);
-int lnet_extract_iov(int dst_niov, struct iovec *dst,
- int src_niov, struct iovec *src,
+unsigned int lnet_iov_nob(unsigned int niov, struct kvec *iov);
+int lnet_extract_iov(int dst_niov, struct kvec *dst,
+ int src_niov, struct kvec *src,
unsigned int offset, unsigned int len);
unsigned int lnet_kiov_nob(unsigned int niov, lnet_kiov_t *iov);
@@ -762,17 +763,17 @@ int lnet_extract_kiov(int dst_niov, lnet_kiov_t *dst,
int src_niov, lnet_kiov_t *src,
unsigned int offset, unsigned int len);
-void lnet_copy_iov2iov(unsigned int ndiov, struct iovec *diov,
+void lnet_copy_iov2iov(unsigned int ndiov, struct kvec *diov,
unsigned int doffset,
- unsigned int nsiov, struct iovec *siov,
+ unsigned int nsiov, struct kvec *siov,
unsigned int soffset, unsigned int nob);
-void lnet_copy_kiov2iov(unsigned int niov, struct iovec *iov,
+void lnet_copy_kiov2iov(unsigned int niov, struct kvec *iov,
unsigned int iovoffset,
unsigned int nkiov, lnet_kiov_t *kiov,
unsigned int kiovoffset, unsigned int nob);
void lnet_copy_iov2kiov(unsigned int nkiov, lnet_kiov_t *kiov,
unsigned int kiovoffset,
- unsigned int niov, struct iovec *iov,
+ unsigned int niov, struct kvec *iov,
unsigned int iovoffset, unsigned int nob);
void lnet_copy_kiov2kiov(unsigned int ndkiov, lnet_kiov_t *dkiov,
unsigned int doffset,
@@ -781,10 +782,10 @@ void lnet_copy_kiov2kiov(unsigned int ndkiov, lnet_kiov_t *dkiov,
static inline void
lnet_copy_iov2flat(int dlen, void *dest, unsigned int doffset,
- unsigned int nsiov, struct iovec *siov, unsigned int soffset,
+ unsigned int nsiov, struct kvec *siov, unsigned int soffset,
unsigned int nob)
{
- struct iovec diov = {/*.iov_base = */ dest, /*.iov_len = */ dlen};
+ struct kvec diov = {/*.iov_base = */ dest, /*.iov_len = */ dlen};
lnet_copy_iov2iov(1, &diov, doffset,
nsiov, siov, soffset, nob);
@@ -795,17 +796,17 @@ lnet_copy_kiov2flat(int dlen, void *dest, unsigned int doffset,
unsigned int nsiov, lnet_kiov_t *skiov,
unsigned int soffset, unsigned int nob)
{
- struct iovec diov = {/* .iov_base = */ dest, /* .iov_len = */ dlen};
+ struct kvec diov = {/* .iov_base = */ dest, /* .iov_len = */ dlen};
lnet_copy_kiov2iov(1, &diov, doffset,
nsiov, skiov, soffset, nob);
}
static inline void
-lnet_copy_flat2iov(unsigned int ndiov, struct iovec *diov, unsigned int doffset,
+lnet_copy_flat2iov(unsigned int ndiov, struct kvec *diov, unsigned int doffset,
int slen, void *src, unsigned int soffset, unsigned int nob)
{
- struct iovec siov = {/*.iov_base = */ src, /*.iov_len = */slen};
+ struct kvec siov = {/*.iov_base = */ src, /*.iov_len = */slen};
lnet_copy_iov2iov(ndiov, diov, doffset,
1, &siov, soffset, nob);
@@ -816,7 +817,7 @@ lnet_copy_flat2kiov(unsigned int ndiov, lnet_kiov_t *dkiov,
unsigned int doffset, int slen, void *src,
unsigned int soffset, unsigned int nob)
{
- struct iovec siov = {/* .iov_base = */ src, /* .iov_len = */ slen};
+ struct kvec siov = {/* .iov_base = */ src, /* .iov_len = */ slen};
lnet_copy_iov2kiov(ndiov, dkiov, doffset,
1, &siov, soffset, nob);
@@ -851,6 +852,7 @@ int lnet_peer_buffer_credits(lnet_ni_t *ni);
int lnet_router_checker_start(void);
void lnet_router_checker_stop(void);
+void lnet_router_ni_update_locked(lnet_peer_t *gw, __u32 net);
void lnet_swap_pinginfo(lnet_ping_info_t *info);
int lnet_ping_target_init(void);
@@ -870,4 +872,12 @@ void lnet_peer_tables_destroy(void);
int lnet_peer_tables_create(void);
void lnet_debug_peer(lnet_nid_t nid);
+static inline void lnet_peer_set_alive(lnet_peer_t *lp)
+{
+ lp->lp_last_alive = lp->lp_last_query = get_seconds();
+ if (!lp->lp_alive)
+ lnet_notify_locked(lp, 0, 1, lp->lp_last_alive);
+}
+
+
#endif
diff --git a/drivers/staging/lustre/include/linux/lnet/lib-types.h b/drivers/staging/lustre/include/linux/lnet/lib-types.h
index f16213f1771a..50537668f59d 100644
--- a/drivers/staging/lustre/include/linux/lnet/lib-types.h
+++ b/drivers/staging/lustre/include/linux/lnet/lib-types.h
@@ -217,7 +217,7 @@ typedef struct lnet_msg {
unsigned int msg_wanted;
unsigned int msg_offset;
unsigned int msg_niov;
- struct iovec *msg_iov;
+ struct kvec *msg_iov;
lnet_kiov_t *msg_kiov;
lnet_event_t msg_ev;
@@ -271,7 +271,7 @@ typedef struct lnet_libmd {
lnet_eq_t *md_eq;
unsigned int md_niov; /* # frags */
union {
- struct iovec iov[LNET_MAX_IOV];
+ struct kvec iov[LNET_MAX_IOV];
lnet_kiov_t kiov[LNET_MAX_IOV];
} md_iov;
} lnet_libmd_t;
@@ -346,7 +346,7 @@ typedef struct lnet_lnd {
* credit if the LND does flow control. */
int (*lnd_recv)(struct lnet_ni *ni, void *private, lnet_msg_t *msg,
int delayed, unsigned int niov,
- struct iovec *iov, lnet_kiov_t *kiov,
+ struct kvec *iov, lnet_kiov_t *kiov,
unsigned int offset, unsigned int mlen, unsigned int rlen);
/* lnet_parse() has had to delay processing of this message
@@ -622,7 +622,7 @@ typedef struct lnet_portal {
/* Match table for each CPT */
struct lnet_match_table **ptl_mtables;
/* spread rotor of incoming "PUT" */
- int ptl_rotor;
+ unsigned int ptl_rotor;
/* # active entries for this portal */
int ptl_mt_nmaps;
/* array of active entries' cpu-partition-id */
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
index 62b575deac3a..651016919669 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.c
@@ -1538,7 +1538,7 @@ kiblnd_fmr_pool_unmap(kib_fmr_t *fmr, int status)
fmr->fmr_pfmr = NULL;
spin_lock(&fps->fps_lock);
- fpo->fpo_map_count --; /* decref the pool */
+ fpo->fpo_map_count--; /* decref the pool */
list_for_each_entry_safe(fpo, tmp, &fps->fps_pool_list, fpo_list) {
/* the first pool is persistent */
@@ -1547,7 +1547,7 @@ kiblnd_fmr_pool_unmap(kib_fmr_t *fmr, int status)
if (kiblnd_fmr_pool_is_idle(fpo, now)) {
list_move(&fpo->fpo_list, &zombies);
- fps->fps_version ++;
+ fps->fps_version++;
}
}
spin_unlock(&fps->fps_lock);
@@ -1752,7 +1752,7 @@ kiblnd_pool_free_node(kib_pool_t *pool, struct list_head *node)
LASSERT (pool->po_allocated > 0);
list_add(node, &pool->po_free_list);
- pool->po_allocated --;
+ pool->po_allocated--;
list_for_each_entry_safe(pool, tmp, &ps->ps_pool_list, po_list) {
/* the first pool is persistent */
@@ -1781,7 +1781,7 @@ kiblnd_pool_alloc_node(kib_poolset_t *ps)
if (list_empty(&pool->po_free_list))
continue;
- pool->po_allocated ++;
+ pool->po_allocated++;
pool->po_deadline = cfs_time_shift(IBLND_POOL_DEADLINE);
node = pool->po_free_list.next;
list_del(node);
@@ -1864,7 +1864,7 @@ kiblnd_pmr_pool_map(kib_pmr_poolset_t *pps, kib_hca_dev_t *hdev,
return -EAGAIN;
}
- for (i = 0; i < rd->rd_nfrags; i ++) {
+ for (i = 0; i < rd->rd_nfrags; i++) {
pmr->pmr_ipb[i].addr = rd->rd_frags[i].rf_addr;
pmr->pmr_ipb[i].size = rd->rd_frags[i].rf_nob;
}
@@ -2117,7 +2117,7 @@ kiblnd_tx_init(kib_pool_t *pool, struct list_head *node)
tps_poolset);
kib_tx_t *tx = list_entry(node, kib_tx_t, tx_list);
- tx->tx_cookie = tps->tps_next_tx_cookie ++;
+ tx->tx_cookie = tps->tps_next_tx_cookie++;
}
static void
@@ -2326,7 +2326,7 @@ kiblnd_hdev_get_attr(kib_hca_dev_t *hdev)
}
for (hdev->ibh_mr_shift = 0;
- hdev->ibh_mr_shift < 64; hdev->ibh_mr_shift ++) {
+ hdev->ibh_mr_shift < 64; hdev->ibh_mr_shift++) {
if (hdev->ibh_mr_size == (1ULL << hdev->ibh_mr_shift) ||
hdev->ibh_mr_size == (1ULL << hdev->ibh_mr_shift) - 1)
return 0;
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
index b02b4ec1e29d..ab128dee9483 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd.h
@@ -1026,5 +1026,5 @@ int kiblnd_post_rx (kib_rx_t *rx, int credit);
int kiblnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg);
int kiblnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed,
- unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov,
+ unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov,
unsigned int offset, unsigned int mlen, unsigned int rlen);
diff --git a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
index b48d7edf5669..48d885dc51d9 100644
--- a/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/o2iblnd/o2iblnd_cb.c
@@ -697,7 +697,7 @@ kiblnd_map_tx(lnet_ni_t *ni, kib_tx_t *tx,
static int
kiblnd_setup_rd_iov(lnet_ni_t *ni, kib_tx_t *tx, kib_rdma_desc_t *rd,
- unsigned int niov, struct iovec *iov, int offset, int nob)
+ unsigned int niov, struct kvec *iov, int offset, int nob)
{
kib_net_t *net = ni->ni_data;
struct page *page;
@@ -1125,8 +1125,9 @@ kiblnd_init_rdma (kib_conn_t *conn, kib_tx_t *tx, int type,
break;
}
- wrknob = MIN(MIN(kiblnd_rd_frag_size(srcrd, srcidx),
- kiblnd_rd_frag_size(dstrd, dstidx)), resid);
+ wrknob = min(min(kiblnd_rd_frag_size(srcrd, srcidx),
+ kiblnd_rd_frag_size(dstrd, dstidx)),
+ (__u32) resid);
sge = &tx->tx_sge[tx->tx_nwrq];
sge->addr = kiblnd_rd_frag_addr(srcrd, srcidx);
@@ -1461,7 +1462,7 @@ kiblnd_send (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
int target_is_router = lntmsg->msg_target_is_router;
int routing = lntmsg->msg_routing;
unsigned int payload_niov = lntmsg->msg_niov;
- struct iovec *payload_iov = lntmsg->msg_iov;
+ struct kvec *payload_iov = lntmsg->msg_iov;
lnet_kiov_t *payload_kiov = lntmsg->msg_kiov;
unsigned int payload_offset = lntmsg->msg_offset;
unsigned int payload_nob = lntmsg->msg_len;
@@ -1628,7 +1629,7 @@ kiblnd_reply (lnet_ni_t *ni, kib_rx_t *rx, lnet_msg_t *lntmsg)
{
lnet_process_id_t target = lntmsg->msg_target;
unsigned int niov = lntmsg->msg_niov;
- struct iovec *iov = lntmsg->msg_iov;
+ struct kvec *iov = lntmsg->msg_iov;
lnet_kiov_t *kiov = lntmsg->msg_kiov;
unsigned int offset = lntmsg->msg_offset;
unsigned int nob = lntmsg->msg_len;
@@ -1687,7 +1688,7 @@ kiblnd_reply (lnet_ni_t *ni, kib_rx_t *rx, lnet_msg_t *lntmsg)
int
kiblnd_recv (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg, int delayed,
- unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov,
+ unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov,
unsigned int offset, unsigned int mlen, unsigned int rlen)
{
kib_rx_t *rx = private;
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
index 9188b34e6948..5956dbac5d04 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.c
@@ -773,7 +773,7 @@ ksocknal_select_ips(ksock_peer_t *peer, __u32 *peerips, int n_peerips)
/* Only match interfaces for additional connections
* if I have > 1 interface */
n_ips = (net->ksnn_ninterfaces < 2) ? 0 :
- MIN(n_peerips, net->ksnn_ninterfaces);
+ min(n_peerips, net->ksnn_ninterfaces);
for (i = 0; peer->ksnp_n_passive_ips < n_ips; i++) {
/* ^ yes really... */
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
index a29d4da6e343..03488d289c74 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd.h
@@ -69,7 +69,7 @@ typedef struct /* per scheduler state */
int kss_nconns;
struct ksock_sched_info *kss_info; /* owner of it */
struct page *kss_rx_scratch_pgs[LNET_MAX_IOV];
- struct iovec kss_scratch_iov[LNET_MAX_IOV];
+ struct kvec kss_scratch_iov[LNET_MAX_IOV];
} ksock_sched_t;
struct ksock_sched_info {
@@ -213,7 +213,7 @@ typedef struct /* transmit packet */
int tx_nob; /* # packet bytes */
int tx_resid; /* residual bytes */
int tx_niov; /* # packet iovec frags */
- struct iovec *tx_iov; /* packet iovec frags */
+ struct kvec *tx_iov; /* packet iovec frags */
int tx_nkiov; /* # packet page frags */
unsigned short tx_zc_aborted; /* aborted ZC request */
unsigned short tx_zc_capable:1; /* payload is large enough for ZC */
@@ -227,11 +227,11 @@ typedef struct /* transmit packet */
int tx_desc_size; /* size of this descriptor */
union {
struct {
- struct iovec iov; /* virt hdr */
+ struct kvec iov; /* virt hdr */
lnet_kiov_t kiov[0]; /* paged payload */
} paged;
struct {
- struct iovec iov[1]; /* virt hdr + payload */
+ struct kvec iov[1]; /* virt hdr + payload */
} virt;
} tx_frags;
} ksock_tx_t;
@@ -243,7 +243,7 @@ typedef struct /* transmit packet */
/* space for the rx frag descriptors; we either read a single contiguous
* header, or up to LNET_MAX_IOV frags of payload of either type. */
typedef union {
- struct iovec iov[LNET_MAX_IOV];
+ struct kvec iov[LNET_MAX_IOV];
lnet_kiov_t kiov[LNET_MAX_IOV];
} ksock_rxiovspace_t;
@@ -284,7 +284,7 @@ typedef struct ksock_conn {
int ksnc_rx_nob_left; /* # bytes to next hdr/body */
int ksnc_rx_nob_wanted; /* bytes actually wanted */
int ksnc_rx_niov; /* # iovec frags */
- struct iovec *ksnc_rx_iov; /* the iovec frags */
+ struct kvec *ksnc_rx_iov; /* the iovec frags */
int ksnc_rx_nkiov; /* # page frags */
lnet_kiov_t *ksnc_rx_kiov; /* the page frags */
ksock_rxiovspace_t ksnc_rx_iov_space;/* space for frag descriptors */
@@ -517,7 +517,7 @@ int ksocknal_ctl(lnet_ni_t *ni, unsigned int cmd, void *arg);
int ksocknal_send (lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg);
int ksocknal_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg,
int delayed, unsigned int niov,
- struct iovec *iov, lnet_kiov_t *kiov,
+ struct kvec *iov, lnet_kiov_t *kiov,
unsigned int offset, unsigned int mlen, unsigned int rlen);
int ksocknal_accept(lnet_ni_t *ni, struct socket *sock);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
index e6c1d3647952..92760fe94184 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_cb.c
@@ -110,7 +110,7 @@ ksocknal_free_tx (ksock_tx_t *tx)
static int
ksocknal_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
{
- struct iovec *iov = tx->tx_iov;
+ struct kvec *iov = tx->tx_iov;
int nob;
int rc;
@@ -251,7 +251,7 @@ ksocknal_transmit (ksock_conn_t *conn, ksock_tx_t *tx)
static int
ksocknal_recv_iov (ksock_conn_t *conn)
{
- struct iovec *iov = conn->ksnc_rx_iov;
+ struct kvec *iov = conn->ksnc_rx_iov;
int nob;
int rc;
@@ -926,7 +926,7 @@ ksocknal_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
int type = lntmsg->msg_type;
lnet_process_id_t target = lntmsg->msg_target;
unsigned int payload_niov = lntmsg->msg_niov;
- struct iovec *payload_iov = lntmsg->msg_iov;
+ struct kvec *payload_iov = lntmsg->msg_iov;
lnet_kiov_t *payload_kiov = lntmsg->msg_kiov;
unsigned int payload_offset = lntmsg->msg_offset;
unsigned int payload_nob = lntmsg->msg_len;
@@ -1047,8 +1047,8 @@ ksocknal_new_packet (ksock_conn_t *conn, int nob_to_skip)
case KSOCK_PROTO_V2:
case KSOCK_PROTO_V3:
conn->ksnc_rx_state = SOCKNAL_RX_KSM_HEADER;
- conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
- conn->ksnc_rx_iov[0].iov_base = (char *)&conn->ksnc_msg;
+ conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
+ conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg;
conn->ksnc_rx_nob_wanted = offsetof(ksock_msg_t, ksm_u);
conn->ksnc_rx_nob_left = offsetof(ksock_msg_t, ksm_u);
@@ -1061,8 +1061,8 @@ ksocknal_new_packet (ksock_conn_t *conn, int nob_to_skip)
conn->ksnc_rx_nob_wanted = sizeof(lnet_hdr_t);
conn->ksnc_rx_nob_left = sizeof(lnet_hdr_t);
- conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
- conn->ksnc_rx_iov[0].iov_base = (char *)&conn->ksnc_msg.ksm_u.lnetmsg;
+ conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
+ conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg.ksm_u.lnetmsg;
conn->ksnc_rx_iov[0].iov_len = sizeof (lnet_hdr_t);
break;
@@ -1082,12 +1082,12 @@ ksocknal_new_packet (ksock_conn_t *conn, int nob_to_skip)
conn->ksnc_rx_state = SOCKNAL_RX_SLOP;
conn->ksnc_rx_nob_left = nob_to_skip;
- conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
+ conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
skipped = 0;
niov = 0;
do {
- nob = MIN (nob_to_skip, sizeof (ksocknal_slop_buffer));
+ nob = min_t(int, nob_to_skip, sizeof(ksocknal_slop_buffer));
conn->ksnc_rx_iov[niov].iov_base = ksocknal_slop_buffer;
conn->ksnc_rx_iov[niov].iov_len = nob;
@@ -1212,8 +1212,8 @@ ksocknal_process_receive (ksock_conn_t *conn)
conn->ksnc_rx_nob_wanted = sizeof(ksock_lnet_msg_t);
conn->ksnc_rx_nob_left = sizeof(ksock_lnet_msg_t);
- conn->ksnc_rx_iov = (struct iovec *)&conn->ksnc_rx_iov_space;
- conn->ksnc_rx_iov[0].iov_base = (char *)&conn->ksnc_msg.ksm_u.lnetmsg;
+ conn->ksnc_rx_iov = (struct kvec *)&conn->ksnc_rx_iov_space;
+ conn->ksnc_rx_iov[0].iov_base = &conn->ksnc_msg.ksm_u.lnetmsg;
conn->ksnc_rx_iov[0].iov_len = sizeof(ksock_lnet_msg_t);
conn->ksnc_rx_niov = 1;
@@ -1311,7 +1311,7 @@ ksocknal_process_receive (ksock_conn_t *conn)
int
ksocknal_recv (lnet_ni_t *ni, void *private, lnet_msg_t *msg, int delayed,
- unsigned int niov, struct iovec *iov, lnet_kiov_t *kiov,
+ unsigned int niov, struct kvec *iov, lnet_kiov_t *kiov,
unsigned int offset, unsigned int mlen, unsigned int rlen)
{
ksock_conn_t *conn = (ksock_conn_t *)private;
@@ -1950,10 +1950,10 @@ ksocknal_connect (ksock_route_t *route)
/* This is a retry rather than a new connection */
route->ksnr_retry_interval *= 2;
route->ksnr_retry_interval =
- MAX(route->ksnr_retry_interval,
+ max(route->ksnr_retry_interval,
cfs_time_seconds(*ksocknal_tunables.ksnd_min_reconnectms)/1000);
route->ksnr_retry_interval =
- MIN(route->ksnr_retry_interval,
+ min(route->ksnr_retry_interval,
cfs_time_seconds(*ksocknal_tunables.ksnd_max_reconnectms)/1000);
LASSERT (route->ksnr_retry_interval != 0);
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
index 245c9d7560af..66cc509295e5 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_lib-linux.c
@@ -92,11 +92,11 @@ ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
{
#if SOCKNAL_SINGLE_FRAG_TX
- struct iovec scratch;
- struct iovec *scratchiov = &scratch;
+ struct kvec scratch;
+ struct kvec *scratchiov = &scratch;
unsigned int niov = 1;
#else
- struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+ struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
unsigned int niov = tx->tx_niov;
#endif
struct msghdr msg = {.msg_flags = MSG_DONTWAIT};
@@ -111,7 +111,7 @@ ksocknal_lib_send_iov (ksock_conn_t *conn, ksock_tx_t *tx)
nob < tx->tx_resid)
msg.msg_flags |= MSG_MORE;
- rc = kernel_sendmsg(sock, &msg, (struct kvec *)scratchiov, niov, nob);
+ rc = kernel_sendmsg(sock, &msg, scratchiov, niov, nob);
}
return rc;
}
@@ -153,14 +153,14 @@ ksocknal_lib_send_kiov (ksock_conn_t *conn, ksock_tx_t *tx)
}
} else {
#if SOCKNAL_SINGLE_FRAG_TX || !SOCKNAL_RISK_KMAP_DEADLOCK
- struct iovec scratch;
- struct iovec *scratchiov = &scratch;
+ struct kvec scratch;
+ struct kvec *scratchiov = &scratch;
unsigned int niov = 1;
#else
#ifdef CONFIG_HIGHMEM
#warning "XXX risk of kmap deadlock on multiple frags..."
#endif
- struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+ struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
unsigned int niov = tx->tx_nkiov;
#endif
struct msghdr msg = {.msg_flags = MSG_DONTWAIT};
@@ -203,14 +203,14 @@ int
ksocknal_lib_recv_iov (ksock_conn_t *conn)
{
#if SOCKNAL_SINGLE_FRAG_RX
- struct iovec scratch;
- struct iovec *scratchiov = &scratch;
+ struct kvec scratch;
+ struct kvec *scratchiov = &scratch;
unsigned int niov = 1;
#else
- struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+ struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
unsigned int niov = conn->ksnc_rx_niov;
#endif
- struct iovec *iov = conn->ksnc_rx_iov;
+ struct kvec *iov = conn->ksnc_rx_iov;
struct msghdr msg = {
.msg_flags = 0
};
@@ -232,7 +232,7 @@ ksocknal_lib_recv_iov (ksock_conn_t *conn)
LASSERT (nob <= conn->ksnc_rx_nob_wanted);
rc = kernel_recvmsg(conn->ksnc_sock, &msg,
- (struct kvec *)scratchiov, niov, nob, MSG_DONTWAIT);
+ scratchiov, niov, nob, MSG_DONTWAIT);
saved_csum = 0;
if (conn->ksnc_proto == &ksocknal_protocol_v2x) {
@@ -269,7 +269,7 @@ ksocknal_lib_kiov_vunmap(void *addr)
static void *
ksocknal_lib_kiov_vmap(lnet_kiov_t *kiov, int niov,
- struct iovec *iov, struct page **pages)
+ struct kvec *iov, struct page **pages)
{
void *addr;
int nob;
@@ -307,15 +307,15 @@ int
ksocknal_lib_recv_kiov (ksock_conn_t *conn)
{
#if SOCKNAL_SINGLE_FRAG_RX || !SOCKNAL_RISK_KMAP_DEADLOCK
- struct iovec scratch;
- struct iovec *scratchiov = &scratch;
+ struct kvec scratch;
+ struct kvec *scratchiov = &scratch;
struct page **pages = NULL;
unsigned int niov = 1;
#else
#ifdef CONFIG_HIGHMEM
#warning "XXX risk of kmap deadlock on multiple frags..."
#endif
- struct iovec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
+ struct kvec *scratchiov = conn->ksnc_scheduler->kss_scratch_iov;
struct page **pages = conn->ksnc_scheduler->kss_rx_scratch_pgs;
unsigned int niov = conn->ksnc_rx_nkiov;
#endif
@@ -390,13 +390,13 @@ ksocknal_lib_csum_tx(ksock_tx_t *tx)
__u32 csum;
void *base;
- LASSERT(tx->tx_iov[0].iov_base == (void *)&tx->tx_msg);
+ LASSERT(tx->tx_iov[0].iov_base == &tx->tx_msg);
LASSERT(tx->tx_conn != NULL);
LASSERT(tx->tx_conn->ksnc_proto == &ksocknal_protocol_v2x);
tx->tx_msg.ksm_csum = 0;
- csum = ksocknal_csum(~0, (void *)tx->tx_iov[0].iov_base,
+ csum = ksocknal_csum(~0, tx->tx_iov[0].iov_base,
tx->tx_iov[0].iov_len);
if (tx->tx_kiov != NULL) {
diff --git a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
index ea9d80f40cab..b2f88eb47bba 100644
--- a/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
+++ b/drivers/staging/lustre/lnet/klnds/socklnd/socklnd_proto.c
@@ -717,7 +717,7 @@ ksocknal_pack_msg_v1(ksock_tx_t *tx)
LASSERT(tx->tx_msg.ksm_type != KSOCK_MSG_NOOP);
LASSERT(tx->tx_lnetmsg != NULL);
- tx->tx_iov[0].iov_base = (void *)&tx->tx_lnetmsg->msg_hdr;
+ tx->tx_iov[0].iov_base = &tx->tx_lnetmsg->msg_hdr;
tx->tx_iov[0].iov_len = sizeof(lnet_hdr_t);
tx->tx_resid = tx->tx_nob = tx->tx_lnetmsg->msg_len + sizeof(lnet_hdr_t);
@@ -726,7 +726,7 @@ ksocknal_pack_msg_v1(ksock_tx_t *tx)
static void
ksocknal_pack_msg_v2(ksock_tx_t *tx)
{
- tx->tx_iov[0].iov_base = (void *)&tx->tx_msg;
+ tx->tx_iov[0].iov_base = &tx->tx_msg;
if (tx->tx_lnetmsg != NULL) {
LASSERT(tx->tx_msg.ksm_type != KSOCK_MSG_NOOP);
diff --git a/drivers/staging/lustre/lnet/lnet/lib-move.c b/drivers/staging/lustre/lnet/lnet/lib-move.c
index c8c1ed84fe5c..0f53c761f1a9 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-move.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-move.c
@@ -158,7 +158,7 @@ fail_peer(lnet_nid_t nid, int outgoing)
}
unsigned int
-lnet_iov_nob(unsigned int niov, struct iovec *iov)
+lnet_iov_nob(unsigned int niov, struct kvec *iov)
{
unsigned int nob = 0;
@@ -170,8 +170,8 @@ lnet_iov_nob(unsigned int niov, struct iovec *iov)
EXPORT_SYMBOL(lnet_iov_nob);
void
-lnet_copy_iov2iov(unsigned int ndiov, struct iovec *diov, unsigned int doffset,
- unsigned int nsiov, struct iovec *siov, unsigned int soffset,
+lnet_copy_iov2iov(unsigned int ndiov, struct kvec *diov, unsigned int doffset,
+ unsigned int nsiov, struct kvec *siov, unsigned int soffset,
unsigned int nob)
{
/* NB diov, siov are READ-ONLY */
@@ -201,9 +201,9 @@ lnet_copy_iov2iov(unsigned int ndiov, struct iovec *diov, unsigned int doffset,
do {
LASSERT(ndiov > 0);
LASSERT(nsiov > 0);
- this_nob = MIN(diov->iov_len - doffset,
+ this_nob = min(diov->iov_len - doffset,
siov->iov_len - soffset);
- this_nob = MIN(this_nob, nob);
+ this_nob = min(this_nob, nob);
memcpy((char *)diov->iov_base + doffset,
(char *)siov->iov_base + soffset, this_nob);
@@ -229,8 +229,8 @@ lnet_copy_iov2iov(unsigned int ndiov, struct iovec *diov, unsigned int doffset,
EXPORT_SYMBOL(lnet_copy_iov2iov);
int
-lnet_extract_iov(int dst_niov, struct iovec *dst,
- int src_niov, struct iovec *src,
+lnet_extract_iov(int dst_niov, struct kvec *dst,
+ int src_niov, struct kvec *src,
unsigned int offset, unsigned int len)
{
/* Initialise 'dst' to the subset of 'src' starting at 'offset',
@@ -322,9 +322,9 @@ lnet_copy_kiov2kiov(unsigned int ndiov, lnet_kiov_t *diov, unsigned int doffset,
do {
LASSERT(ndiov > 0);
LASSERT(nsiov > 0);
- this_nob = MIN(diov->kiov_len - doffset,
+ this_nob = min(diov->kiov_len - doffset,
siov->kiov_len - soffset);
- this_nob = MIN(this_nob, nob);
+ this_nob = min(this_nob, nob);
if (daddr == NULL)
daddr = ((char *)kmap(diov->kiov_page)) +
@@ -371,7 +371,7 @@ lnet_copy_kiov2kiov(unsigned int ndiov, lnet_kiov_t *diov, unsigned int doffset,
EXPORT_SYMBOL(lnet_copy_kiov2kiov);
void
-lnet_copy_kiov2iov(unsigned int niov, struct iovec *iov, unsigned int iovoffset,
+lnet_copy_kiov2iov(unsigned int niov, struct kvec *iov, unsigned int iovoffset,
unsigned int nkiov, lnet_kiov_t *kiov,
unsigned int kiovoffset, unsigned int nob)
{
@@ -403,9 +403,9 @@ lnet_copy_kiov2iov(unsigned int niov, struct iovec *iov, unsigned int iovoffset,
do {
LASSERT(niov > 0);
LASSERT(nkiov > 0);
- this_nob = MIN(iov->iov_len - iovoffset,
- kiov->kiov_len - kiovoffset);
- this_nob = MIN(this_nob, nob);
+ this_nob = min(iov->iov_len - iovoffset,
+ (__kernel_size_t) kiov->kiov_len - kiovoffset);
+ this_nob = min(this_nob, nob);
if (addr == NULL)
addr = ((char *)kmap(kiov->kiov_page)) +
@@ -443,7 +443,7 @@ EXPORT_SYMBOL(lnet_copy_kiov2iov);
void
lnet_copy_iov2kiov(unsigned int nkiov, lnet_kiov_t *kiov,
unsigned int kiovoffset, unsigned int niov,
- struct iovec *iov, unsigned int iovoffset,
+ struct kvec *iov, unsigned int iovoffset,
unsigned int nob)
{
/* NB kiov, iov are READ-ONLY */
@@ -474,9 +474,9 @@ lnet_copy_iov2kiov(unsigned int nkiov, lnet_kiov_t *kiov,
do {
LASSERT(nkiov > 0);
LASSERT(niov > 0);
- this_nob = MIN(kiov->kiov_len - kiovoffset,
+ this_nob = min((__kernel_size_t) kiov->kiov_len - kiovoffset,
iov->iov_len - iovoffset);
- this_nob = MIN(this_nob, nob);
+ this_nob = min(this_nob, nob);
if (addr == NULL)
addr = ((char *)kmap(kiov->kiov_page)) +
@@ -566,7 +566,7 @@ lnet_ni_recv(lnet_ni_t *ni, void *private, lnet_msg_t *msg, int delayed,
unsigned int offset, unsigned int mlen, unsigned int rlen)
{
unsigned int niov = 0;
- struct iovec *iov = NULL;
+ struct kvec *iov = NULL;
lnet_kiov_t *kiov = NULL;
int rc;
@@ -1530,7 +1530,7 @@ lnet_parse_reply(lnet_ni_t *ni, lnet_msg_t *msg)
LASSERT(md->md_offset == 0);
rlength = hdr->payload_length;
- mlength = MIN(rlength, (int)md->md_length);
+ mlength = min_t(int, rlength, md->md_length);
if (mlength < rlength &&
(md->md_options & LNET_MD_TRUNCATE) == 0) {
@@ -1877,6 +1877,19 @@ lnet_parse(lnet_ni_t *ni, lnet_hdr_t *hdr, lnet_nid_t from_nid,
goto drop;
}
+ if (lnet_isrouter(msg->msg_rxpeer)) {
+ lnet_peer_set_alive(msg->msg_rxpeer);
+ if (avoid_asym_router_failure &&
+ LNET_NIDNET(src_nid) != LNET_NIDNET(from_nid)) {
+ /* received a remote message from router, update
+ * remote NI status on this router.
+ * NB: multi-hop routed message will be ignored.
+ */
+ lnet_router_ni_update_locked(msg->msg_rxpeer,
+ LNET_NIDNET(src_nid));
+ }
+ }
+
lnet_msg_commit(msg, cpt);
if (!for_me) {
diff --git a/drivers/staging/lustre/lnet/lnet/lib-ptl.c b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
index 19ed696344fe..3ba0da919b41 100644
--- a/drivers/staging/lustre/lnet/lnet/lib-ptl.c
+++ b/drivers/staging/lustre/lnet/lnet/lib-ptl.c
@@ -262,10 +262,10 @@ lnet_mt_of_match(struct lnet_match_info *info, struct lnet_msg *msg)
{
struct lnet_match_table *mtable;
struct lnet_portal *ptl;
- int nmaps;
- int rotor;
- int routed;
- int cpt;
+ unsigned int nmaps;
+ unsigned int rotor;
+ unsigned int cpt;
+ bool routed;
/* NB: called w/o lock */
LASSERT(info->mi_portal < the_lnet.ln_nportals);
diff --git a/drivers/staging/lustre/lnet/lnet/lo.c b/drivers/staging/lustre/lnet/lnet/lo.c
index 17e1643fd675..f708c2e649d7 100644
--- a/drivers/staging/lustre/lnet/lnet/lo.c
+++ b/drivers/staging/lustre/lnet/lnet/lo.c
@@ -47,7 +47,7 @@ lolnd_send(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg)
static int
lolnd_recv(lnet_ni_t *ni, void *private, lnet_msg_t *lntmsg,
int delayed, unsigned int niov,
- struct iovec *iov, lnet_kiov_t *kiov,
+ struct kvec *iov, lnet_kiov_t *kiov,
unsigned int offset, unsigned int mlen, unsigned int rlen)
{
lnet_msg_t *sendmsg = private;
diff --git a/drivers/staging/lustre/lnet/lnet/module.c b/drivers/staging/lustre/lnet/lnet/module.c
index 3c23677bc280..72b7fbc83718 100644
--- a/drivers/staging/lustre/lnet/lnet/module.c
+++ b/drivers/staging/lustre/lnet/lnet/module.c
@@ -108,7 +108,7 @@ lnet_ioctl(unsigned int cmd, struct libcfs_ioctl_data *data)
}
}
-DECLARE_IOCTL_HANDLER(lnet_ioctl_handler, lnet_ioctl);
+static DECLARE_IOCTL_HANDLER(lnet_ioctl_handler, lnet_ioctl);
static int __init
init_lnet(void)
diff --git a/drivers/staging/lustre/lnet/lnet/router.c b/drivers/staging/lustre/lnet/lnet/router.c
index c667b5b76761..52ec0ab7e3c3 100644
--- a/drivers/staging/lustre/lnet/lnet/router.c
+++ b/drivers/staging/lustre/lnet/lnet/router.c
@@ -46,7 +46,7 @@ MODULE_PARM_DESC(small_router_buffers, "# of small (1 page) messages to buffer i
static int large_router_buffers;
module_param(large_router_buffers, int, 0444);
MODULE_PARM_DESC(large_router_buffers, "# of large messages to buffer in the router");
-static int peer_buffer_credits = 0;
+static int peer_buffer_credits;
module_param(peer_buffer_credits, int, 0444);
MODULE_PARM_DESC(peer_buffer_credits, "# router buffer credits per peer");
@@ -80,11 +80,11 @@ lnet_peer_buffer_credits(lnet_ni_t *ni)
#endif
-static int check_routers_before_use = 0;
+static int check_routers_before_use;
module_param(check_routers_before_use, int, 0444);
MODULE_PARM_DESC(check_routers_before_use, "Assume routers are down and ping them before use");
-static int avoid_asym_router_failure = 1;
+int avoid_asym_router_failure = 1;
module_param(avoid_asym_router_failure, int, 0644);
MODULE_PARM_DESC(avoid_asym_router_failure, "Avoid asymmetrical router failures (0 to disable)");
@@ -245,7 +245,7 @@ lnet_find_net_locked (__u32 net)
static void lnet_shuffle_seed(void)
{
- static int seeded = 0;
+ static int seeded;
int lnd_type, seed[2];
struct timeval tv;
lnet_ni_t *ni;
@@ -783,6 +783,21 @@ lnet_wait_known_routerstate(void)
}
}
+void
+lnet_router_ni_update_locked(lnet_peer_t *gw, __u32 net)
+{
+ lnet_route_t *rte;
+
+ if ((gw->lp_ping_feats & LNET_PING_FEAT_NI_STATUS) != 0) {
+ list_for_each_entry(rte, &gw->lp_routes, lr_gwlist) {
+ if (rte->lr_net == net) {
+ rte->lr_downis = 0;
+ break;
+ }
+ }
+ }
+}
+
static void
lnet_update_ni_status_locked(void)
{
@@ -793,7 +808,7 @@ lnet_update_ni_status_locked(void)
LASSERT(the_lnet.ln_routing);
timeout = router_ping_timeout +
- MAX(live_router_check_interval, dead_router_check_interval);
+ max(live_router_check_interval, dead_router_check_interval);
now = get_seconds();
list_for_each_entry(ni, &the_lnet.ln_nis, ni_list) {
@@ -1578,8 +1593,8 @@ lnet_notify (lnet_ni_t *ni, lnet_nid_t nid, int alive, unsigned long when)
void
lnet_router_checker (void)
{
- static time_t last = 0;
- static int running = 0;
+ static time_t last;
+ static int running;
time_t now = get_seconds();
int interval = now - last;
@@ -1593,7 +1608,7 @@ lnet_router_checker (void)
return;
if (last != 0 &&
- interval > MAX(live_router_check_interval,
+ interval > max(live_router_check_interval,
dead_router_check_interval))
CNETERR("Checker(%d/%d) not called for %d seconds\n",
live_router_check_interval, dead_router_check_interval,
@@ -1664,13 +1679,16 @@ lnet_get_tunables (void)
char *s;
s = getenv("LNET_ROUTER_PING_TIMEOUT");
- if (s != NULL) router_ping_timeout = atoi(s);
+ if (s != NULL)
+ router_ping_timeout = atoi(s);
s = getenv("LNET_LIVE_ROUTER_CHECK_INTERVAL");
- if (s != NULL) live_router_check_interval = atoi(s);
+ if (s != NULL)
+ live_router_check_interval = atoi(s);
s = getenv("LNET_DEAD_ROUTER_CHECK_INTERVAL");
- if (s != NULL) dead_router_check_interval = atoi(s);
+ if (s != NULL)
+ dead_router_check_interval = atoi(s);
/* This replaces old lnd_notify mechanism */
check_routers_before_use = 1;
diff --git a/drivers/staging/lustre/lnet/lnet/router_proc.c b/drivers/staging/lustre/lnet/lnet/router_proc.c
index 46cde7036f1d..c055afc86eb4 100644
--- a/drivers/staging/lustre/lnet/lnet/router_proc.c
+++ b/drivers/staging/lustre/lnet/lnet/router_proc.c
@@ -49,7 +49,7 @@ enum {
*/
#define LNET_PROC_CPT_BITS (LNET_CPT_BITS + 1)
/* change version, 16 bits or 8 bits */
-#define LNET_PROC_VER_BITS MAX(((MIN(LNET_LOFFT_BITS, 64)) / 4), 8)
+#define LNET_PROC_VER_BITS max_t(size_t, min_t(size_t, LNET_LOFFT_BITS, 64) / 4, 8)
#define LNET_PROC_HASH_BITS LNET_PEER_HASH_BITS
/*
diff --git a/drivers/staging/lustre/lnet/selftest/conctl.c b/drivers/staging/lustre/lnet/selftest/conctl.c
index 5bc615309e72..fbff84cea52f 100644
--- a/drivers/staging/lustre/lnet/selftest/conctl.c
+++ b/drivers/staging/lustre/lnet/selftest/conctl.c
@@ -721,7 +721,7 @@ lst_stat_query_ioctl(lstio_stat_args_t *args)
return rc;
}
-int lst_test_add_ioctl(lstio_test_args_t *args)
+static int lst_test_add_ioctl(lstio_test_args_t *args)
{
char *batch_name;
char *src_name = NULL;
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.c b/drivers/staging/lustre/lnet/selftest/conrpc.c
index 9999b0dc03e4..77f02b76128e 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.c
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.c
@@ -703,7 +703,7 @@ lstcon_statrpc_prep(lstcon_node_t *nd, unsigned feats, lstcon_rpc_t **crpc)
return 0;
}
-lnet_process_id_packed_t *
+static lnet_process_id_packed_t *
lstcon_next_id(int idx, int nkiov, lnet_kiov_t *kiov)
{
lnet_process_id_packed_t *pid;
diff --git a/drivers/staging/lustre/lnet/selftest/conrpc.h b/drivers/staging/lustre/lnet/selftest/conrpc.h
index fc1cb56cbab2..2353889c6eac 100644
--- a/drivers/staging/lustre/lnet/selftest/conrpc.h
+++ b/drivers/staging/lustre/lnet/selftest/conrpc.h
@@ -54,7 +54,7 @@
#define LST_TRANS_TIMEOUT 30
#define LST_TRANS_MIN_TIMEOUT 3
-#define LST_VALIDATE_TIMEOUT(t) MIN(MAX(t, LST_TRANS_MIN_TIMEOUT), LST_TRANS_TIMEOUT)
+#define LST_VALIDATE_TIMEOUT(t) min(max(t, LST_TRANS_MIN_TIMEOUT), LST_TRANS_TIMEOUT)
#define LST_PING_INTERVAL 8
diff --git a/drivers/staging/lustre/lnet/selftest/console.c b/drivers/staging/lustre/lnet/selftest/console.c
index 49cb6543d538..1e0afc286847 100644
--- a/drivers/staging/lustre/lnet/selftest/console.c
+++ b/drivers/staging/lustre/lnet/selftest/console.c
@@ -46,17 +46,17 @@
#include "console.h"
#include "conrpc.h"
-#define LST_NODE_STATE_COUNTER(nd, p) \
-do { \
- if ((nd)->nd_state == LST_NODE_ACTIVE) \
- (p)->nle_nactive ++; \
+#define LST_NODE_STATE_COUNTER(nd, p) \
+do { \
+ if ((nd)->nd_state == LST_NODE_ACTIVE) \
+ (p)->nle_nactive++; \
else if ((nd)->nd_state == LST_NODE_BUSY) \
- (p)->nle_nbusy ++; \
+ (p)->nle_nbusy++; \
else if ((nd)->nd_state == LST_NODE_DOWN) \
- (p)->nle_ndown ++; \
- else \
- (p)->nle_nunknown ++; \
- (p)->nle_nnode ++; \
+ (p)->nle_ndown++; \
+ else \
+ (p)->nle_nunknown++; \
+ (p)->nle_nnode++; \
} while (0)
lstcon_session_t console_session;
@@ -223,7 +223,7 @@ lstcon_group_alloc(char *name, lstcon_group_t **grpp)
static void
lstcon_group_addref(lstcon_group_t *grp)
{
- grp->grp_ref ++;
+ grp->grp_ref++;
}
static void lstcon_group_ndlink_release(lstcon_group_t *, lstcon_ndlink_t *);
@@ -298,7 +298,7 @@ lstcon_group_ndlink_find(lstcon_group_t *grp, lnet_process_id_t id,
return 0;
list_add_tail(&(*ndlpp)->ndl_link, &grp->grp_ndl_list);
- grp->grp_nnode ++;
+ grp->grp_nnode++;
return 0;
}
@@ -324,7 +324,7 @@ lstcon_group_ndlink_move(lstcon_group_t *old,
list_add_tail(&ndl->ndl_hlink, &new->grp_ndl_hash[idx]);
list_add_tail(&ndl->ndl_link, &new->grp_ndl_list);
- new->grp_nnode ++;
+ new->grp_nnode++;
return;
}
@@ -767,7 +767,7 @@ lstcon_nodes_getent(struct list_head *head, int *index_p,
&nd->nd_state, sizeof(nd->nd_state)))
return -EFAULT;
- count ++;
+ count++;
}
if (index <= *index_p)
@@ -1343,7 +1343,7 @@ lstcon_test_add(char *batch_name, int type, int loop,
/* add to test list anyway, so user can check what's going on */
list_add_tail(&test->tes_link, &batch->bat_test_list);
- batch->bat_ntest ++;
+ batch->bat_ntest++;
test->tes_hdr.tsb_index = batch->bat_ntest;
/* hold groups so nobody can change them */
@@ -1986,7 +1986,7 @@ static void lstcon_init_acceptor_service(void)
extern int lstcon_ioctl_entry(unsigned int cmd, struct libcfs_ioctl_data *data);
-DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
+static DECLARE_IOCTL_HANDLER(lstcon_ioctl_handler, lstcon_ioctl_entry);
/* initialize console */
int
diff --git a/drivers/staging/lustre/lnet/selftest/framework.c b/drivers/staging/lustre/lnet/selftest/framework.c
index cc9d1826ae66..570914828b8c 100644
--- a/drivers/staging/lustre/lnet/selftest/framework.c
+++ b/drivers/staging/lustre/lnet/selftest/framework.c
@@ -103,7 +103,7 @@ do { \
#define sfw_test_active(t) (atomic_read(&(t)->tsi_nactive) != 0)
#define sfw_batch_active(b) (atomic_read(&(b)->bat_nactive) != 0)
-struct smoketest_framework {
+static struct smoketest_framework {
struct list_head fw_zombie_rpcs; /* RPCs to be recycled */
struct list_head fw_zombie_sessions; /* stopping sessions */
struct list_head fw_tests; /* registered test cases */
@@ -194,9 +194,9 @@ sfw_del_session_timer (void)
return EBUSY; /* racing with sfw_session_expired() */
}
-/* called with sfw_data.fw_lock held */
static void
sfw_deactivate_session (void)
+ __must_hold(&sfw_data.fw_lock)
{
sfw_session_t *sn = sfw_data.fw_session;
int nactive = 0;
diff --git a/drivers/staging/lustre/lnet/selftest/module.c b/drivers/staging/lustre/lnet/selftest/module.c
index c6ef5b0d8de1..faf409802372 100644
--- a/drivers/staging/lustre/lnet/selftest/module.c
+++ b/drivers/staging/lustre/lnet/selftest/module.c
@@ -61,31 +61,31 @@ lnet_selftest_fini(void)
int i;
switch (lst_init_step) {
- case LST_INIT_CONSOLE:
- lstcon_console_fini();
- case LST_INIT_FW:
- sfw_shutdown();
- case LST_INIT_RPC:
- srpc_shutdown();
- case LST_INIT_WI_TEST:
- for (i = 0;
- i < cfs_cpt_number(lnet_cpt_table()); i++) {
- if (lst_sched_test[i] == NULL)
- continue;
- cfs_wi_sched_destroy(lst_sched_test[i]);
- }
- LIBCFS_FREE(lst_sched_test,
- sizeof(lst_sched_test[0]) *
- cfs_cpt_number(lnet_cpt_table()));
- lst_sched_test = NULL;
-
- case LST_INIT_WI_SERIAL:
- cfs_wi_sched_destroy(lst_sched_serial);
- lst_sched_serial = NULL;
- case LST_INIT_NONE:
- break;
- default:
- LBUG();
+ case LST_INIT_CONSOLE:
+ lstcon_console_fini();
+ case LST_INIT_FW:
+ sfw_shutdown();
+ case LST_INIT_RPC:
+ srpc_shutdown();
+ case LST_INIT_WI_TEST:
+ for (i = 0;
+ i < cfs_cpt_number(lnet_cpt_table()); i++) {
+ if (lst_sched_test[i] == NULL)
+ continue;
+ cfs_wi_sched_destroy(lst_sched_test[i]);
+ }
+ LIBCFS_FREE(lst_sched_test,
+ sizeof(lst_sched_test[0]) *
+ cfs_cpt_number(lnet_cpt_table()));
+ lst_sched_test = NULL;
+
+ case LST_INIT_WI_SERIAL:
+ cfs_wi_sched_destroy(lst_sched_serial);
+ lst_sched_serial = NULL;
+ case LST_INIT_NONE:
+ break;
+ default:
+ LBUG();
}
return;
}
diff --git a/drivers/staging/lustre/lnet/selftest/rpc.c b/drivers/staging/lustre/lnet/selftest/rpc.c
index f753add7bfb3..1f7d9a6248db 100644
--- a/drivers/staging/lustre/lnet/selftest/rpc.c
+++ b/drivers/staging/lustre/lnet/selftest/rpc.c
@@ -54,7 +54,7 @@ typedef enum {
SRPC_STATE_STOPPING,
} srpc_state_t;
-struct smoketest_rpc {
+static struct smoketest_rpc {
spinlock_t rpc_glock; /* global lock */
srpc_service_t *rpc_services[SRPC_SERVICE_MAX_ID + 1];
lnet_handle_eq_t rpc_lnet_eq; /* _the_ LNet event queue */
@@ -468,6 +468,7 @@ srpc_post_passive_rqtbuf(int service, int local, void *buf, int len,
static int
srpc_service_post_buffer(struct srpc_service_cd *scd, struct srpc_buffer *buf)
+ __must_hold(&scd->scd_lock)
{
struct srpc_service *sv = scd->scd_svc;
struct srpc_msg *msg = &buf->buf_msg;
@@ -559,7 +560,7 @@ srpc_add_buffer(struct swi_workitem *wi)
LASSERT(scd->scd_buf_posting > 0);
scd->scd_buf_posting--;
scd->scd_buf_total++;
- scd->scd_buf_low = MAX(2, scd->scd_buf_total / 4);
+ scd->scd_buf_low = max(2, scd->scd_buf_total / 4);
}
if (rc != 0) {
@@ -697,6 +698,7 @@ srpc_finish_service(struct srpc_service *sv)
/* called with sv->sv_lock held */
static void
srpc_service_recycle_buffer(struct srpc_service_cd *scd, srpc_buffer_t *buf)
+ __must_hold(&scd->scd_lock)
{
if (!scd->scd_svc->sv_shuttingdown && scd->scd_buf_adjust >= 0) {
if (srpc_service_post_buffer(scd, buf) != 0) {
@@ -1486,7 +1488,7 @@ srpc_lnet_ev_handler(lnet_event_t *ev)
if (scd->scd_buf_err == 0 && /* adding buffer is enabled */
scd->scd_buf_adjust == 0 &&
scd->scd_buf_nposted < scd->scd_buf_low) {
- scd->scd_buf_adjust = MAX(scd->scd_buf_total / 2,
+ scd->scd_buf_adjust = max(scd->scd_buf_total / 2,
SFW_TEST_WI_MIN);
swi_schedule_workitem(&scd->scd_buf_wi);
}
diff --git a/drivers/staging/lustre/lnet/selftest/selftest.h b/drivers/staging/lustre/lnet/selftest/selftest.h
index 9b5c5df6eb2c..d48701834b18 100644
--- a/drivers/staging/lustre/lnet/selftest/selftest.h
+++ b/drivers/staging/lustre/lnet/selftest/selftest.h
@@ -609,4 +609,16 @@ srpc_wait_service_shutdown(srpc_service_t *sv)
}
}
+extern sfw_test_client_ops_t brw_test_client;
+void brw_init_test_client(void);
+
+extern srpc_service_t brw_test_service;
+void brw_init_test_service(void);
+
+extern sfw_test_client_ops_t ping_test_client;
+void ping_init_test_client(void);
+
+extern srpc_service_t ping_test_service;
+void ping_init_test_service(void);
+
#endif /* __SELFTEST_SELFTEST_H__ */
diff --git a/drivers/staging/lustre/lnet/selftest/timer.c b/drivers/staging/lustre/lnet/selftest/timer.c
index f8352c2a7d37..441f9472a834 100644
--- a/drivers/staging/lustre/lnet/selftest/timer.c
+++ b/drivers/staging/lustre/lnet/selftest/timer.c
@@ -57,7 +57,7 @@
#define STTIMER_SLOT(t) (&stt_data.stt_hash[(((t) >> STTIMER_MINPOLL) & \
(STTIMER_NSLOTS - 1))])
-struct st_timer_data {
+static struct st_timer_data {
spinlock_t stt_lock;
/* start time of the slot processed previously */
unsigned long stt_prev_slot;
diff --git a/drivers/staging/lustre/lustre/fid/fid_internal.h b/drivers/staging/lustre/lustre/fid/fid_internal.h
index eb607c52ef3b..b5e8da8956f2 100644
--- a/drivers/staging/lustre/lustre/fid/fid_internal.h
+++ b/drivers/staging/lustre/lustre/fid/fid_internal.h
@@ -47,7 +47,7 @@
int seq_client_alloc_super(struct lu_client_seq *seq,
const struct lu_env *env);
-#if defined (CONFIG_PROC_FS)
+#if defined(CONFIG_PROC_FS)
extern struct lprocfs_vars seq_client_proc_list[];
#endif
diff --git a/drivers/staging/lustre/lustre/fid/fid_request.c b/drivers/staging/lustre/lustre/fid/fid_request.c
index 64b1d80c64b0..063441abfcfc 100644
--- a/drivers/staging/lustre/lustre/fid/fid_request.c
+++ b/drivers/staging/lustre/lustre/fid/fid_request.c
@@ -402,7 +402,7 @@ EXPORT_SYMBOL(seq_client_flush);
static void seq_client_proc_fini(struct lu_client_seq *seq)
{
-#if defined (CONFIG_PROC_FS)
+#if defined(CONFIG_PROC_FS)
if (seq->lcs_proc_dir) {
if (!IS_ERR(seq->lcs_proc_dir))
lprocfs_remove(&seq->lcs_proc_dir);
@@ -413,7 +413,7 @@ static void seq_client_proc_fini(struct lu_client_seq *seq)
static int seq_client_proc_init(struct lu_client_seq *seq)
{
-#if defined (CONFIG_PROC_FS)
+#if defined(CONFIG_PROC_FS)
int rc;
seq->lcs_proc_dir = lprocfs_register(seq->lcs_name,
diff --git a/drivers/staging/lustre/lustre/fld/fld_cache.c b/drivers/staging/lustre/lustre/fld/fld_cache.c
index 5d95d0b358b8..0d0a73745065 100644
--- a/drivers/staging/lustre/lustre/fld/fld_cache.c
+++ b/drivers/staging/lustre/lustre/fld/fld_cache.c
@@ -257,9 +257,9 @@ void fld_cache_flush(struct fld_cache *cache)
* entry accordingly.
*/
-void fld_cache_punch_hole(struct fld_cache *cache,
- struct fld_cache_entry *f_curr,
- struct fld_cache_entry *f_new)
+static void fld_cache_punch_hole(struct fld_cache *cache,
+ struct fld_cache_entry *f_curr,
+ struct fld_cache_entry *f_new)
{
const struct lu_seq_range *range = &f_new->fce_range;
const u64 new_start = range->lsr_start;
diff --git a/drivers/staging/lustre/lustre/fld/fld_internal.h b/drivers/staging/lustre/lustre/fld/fld_internal.h
index 8806b6096953..6125bbe822b5 100644
--- a/drivers/staging/lustre/lustre/fld/fld_internal.h
+++ b/drivers/staging/lustre/lustre/fld/fld_internal.h
@@ -111,7 +111,7 @@ struct fld_cache {
/**
* Cache name used for debug and messages. */
- char fci_name[80];
+ char fci_name[LUSTRE_MDT_MAXNAMELEN];
unsigned int fci_no_shrink:1;
};
diff --git a/drivers/staging/lustre/lustre/fld/fld_request.c b/drivers/staging/lustre/lustre/fld/fld_request.c
index 0d361ff43212..b8d17e109a96 100644
--- a/drivers/staging/lustre/lustre/fld/fld_request.c
+++ b/drivers/staging/lustre/lustre/fld/fld_request.c
@@ -131,11 +131,20 @@ fld_rrb_scan(struct lu_client_fld *fld, u64 seq)
else
hash = 0;
+again:
list_for_each_entry(target, &fld->lcf_targets, ft_chain) {
if (target->ft_idx == hash)
return target;
}
+ if (hash != 0) {
+ /* It is possible the remote target(MDT) are not connected to
+ * with client yet, so we will refer this to MDT0, which should
+ * be connected during mount */
+ hash = 0;
+ goto again;
+ }
+
CERROR("%s: Can't find target by hash %d (seq %#llx). Targets (%d):\n",
fld->lcf_name, hash, seq, fld->lcf_count);
@@ -269,7 +278,7 @@ int fld_client_del_target(struct lu_client_fld *fld, __u64 idx)
}
EXPORT_SYMBOL(fld_client_del_target);
-struct proc_dir_entry *fld_type_proc_dir = NULL;
+static struct proc_dir_entry *fld_type_proc_dir;
#if defined (CONFIG_PROC_FS)
static int fld_client_proc_init(struct lu_client_fld *fld)
diff --git a/drivers/staging/lustre/lustre/fld/lproc_fld.c b/drivers/staging/lustre/lustre/fld/lproc_fld.c
index 95e7de18d2f1..8c5a65704a37 100644
--- a/drivers/staging/lustre/lustre/fld/lproc_fld.c
+++ b/drivers/staging/lustre/lustre/fld/lproc_fld.c
@@ -87,13 +87,21 @@ fld_proc_hash_seq_show(struct seq_file *m, void *unused)
}
static ssize_t
-fld_proc_hash_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+fld_proc_hash_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct lu_client_fld *fld;
struct lu_fld_hash *hash = NULL;
+ char fh_name[8];
int i;
+ if (count > sizeof(fh_name))
+ return -ENAMETOOLONG;
+
+ if (copy_from_user(fh_name, buffer, count) != 0)
+ return -EFAULT;
+
fld = ((struct seq_file *)file->private_data)->private;
LASSERT(fld != NULL);
@@ -101,7 +109,7 @@ fld_proc_hash_seq_write(struct file *file, const char *buffer,
if (count != strlen(fld_hash[i].fh_name))
continue;
- if (!strncmp(fld_hash[i].fh_name, buffer, count)) {
+ if (!strncmp(fld_hash[i].fh_name, fh_name, count)) {
hash = &fld_hash[i];
break;
}
@@ -146,7 +154,7 @@ static int fld_proc_cache_flush_release(struct inode *inode, struct file *file)
return 0;
}
-struct file_operations fld_proc_cache_flush_fops = {
+static struct file_operations fld_proc_cache_flush_fops = {
.owner = THIS_MODULE,
.open = fld_proc_cache_flush_open,
.write = fld_proc_cache_flush_write,
diff --git a/drivers/staging/lustre/lustre/include/lclient.h b/drivers/staging/lustre/lustre/include/lclient.h
index b3b841f4d6e6..c5c3a8d9eaa4 100644
--- a/drivers/staging/lustre/lustre/include/lclient.h
+++ b/drivers/staging/lustre/lustre/include/lclient.h
@@ -135,6 +135,7 @@ static inline struct ccc_thread_info *ccc_env_info(const struct lu_env *env)
static inline struct cl_attr *ccc_env_thread_attr(const struct lu_env *env)
{
struct cl_attr *attr = &ccc_env_info(env)->cti_attr;
+
memset(attr, 0, sizeof(*attr));
return attr;
}
@@ -142,6 +143,7 @@ static inline struct cl_attr *ccc_env_thread_attr(const struct lu_env *env)
static inline struct cl_io *ccc_env_thread_io(const struct lu_env *env)
{
struct cl_io *io = &ccc_env_info(env)->cti_io;
+
memset(io, 0, sizeof(*io));
return io;
}
@@ -323,6 +325,7 @@ void ccc_lock_fini(const struct lu_env *env, struct cl_lock_slice *slice);
int ccc_lock_enqueue(const struct lu_env *env,
const struct cl_lock_slice *slice,
struct cl_io *io, __u32 enqflags);
+int ccc_lock_use(const struct lu_env *env, const struct cl_lock_slice *slice);
int ccc_lock_unuse(const struct lu_env *env, const struct cl_lock_slice *slice);
int ccc_lock_wait(const struct lu_env *env, const struct cl_lock_slice *slice);
int ccc_lock_fits_into(const struct lu_env *env,
diff --git a/drivers/staging/lustre/lustre/include/lprocfs_status.h b/drivers/staging/lustre/lustre/include/lprocfs_status.h
index cfe503b7df62..8a25cf6f6825 100644
--- a/drivers/staging/lustre/lustre/include/lprocfs_status.h
+++ b/drivers/staging/lustre/lustre/include/lprocfs_status.h
@@ -627,16 +627,16 @@ struct adaptive_timeout;
extern int lprocfs_at_hist_helper(struct seq_file *m,
struct adaptive_timeout *at);
extern int lprocfs_rd_timeouts(struct seq_file *m, void *data);
-extern int lprocfs_wr_timeouts(struct file *file, const char *buffer,
+extern int lprocfs_wr_timeouts(struct file *file, const char __user *buffer,
unsigned long count, void *data);
-extern int lprocfs_wr_evict_client(struct file *file, const char *buffer,
+extern int lprocfs_wr_evict_client(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
-extern int lprocfs_wr_ping(struct file *file, const char *buffer,
+extern int lprocfs_wr_ping(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
-extern int lprocfs_wr_import(struct file *file, const char *buffer,
+extern int lprocfs_wr_import(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
extern int lprocfs_rd_pinger_recov(struct seq_file *m, void *n);
-extern int lprocfs_wr_pinger_recov(struct file *file, const char *buffer,
+extern int lprocfs_wr_pinger_recov(struct file *file, const char __user *buffer,
size_t count, loff_t *off);
/* Statfs helpers */
@@ -650,8 +650,8 @@ extern int lprocfs_rd_filesfree(struct seq_file *m, void *data);
extern int lprocfs_write_helper(const char __user *buffer, unsigned long count,
int *val);
extern int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult);
-extern int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
- __u64 *val);
+extern int lprocfs_write_u64_helper(const char __user *buffer,
+ unsigned long count, __u64 *val);
extern int lprocfs_write_frac_u64_helper(const char *buffer,
unsigned long count,
__u64 *val, int mult);
@@ -716,7 +716,8 @@ static struct file_operations name##_fops = { \
return lprocfs_rd_##type(m, m->private); \
} \
static ssize_t name##_##type##_seq_write(struct file *file, \
- const char *buffer, size_t count, loff_t *off) \
+ const char __user *buffer, size_t count, \
+ loff_t *off) \
{ \
struct seq_file *seq = file->private_data; \
return lprocfs_wr_##type(file, buffer, \
@@ -726,7 +727,8 @@ static struct file_operations name##_fops = { \
#define LPROC_SEQ_FOPS_WR_ONLY(name, type) \
static ssize_t name##_##type##_write(struct file *file, \
- const char *buffer, size_t count, loff_t *off) \
+ const char __user *buffer, size_t count, \
+ loff_t *off) \
{ \
return lprocfs_wr_##type(file, buffer, count, off); \
} \
@@ -939,20 +941,24 @@ static inline int lprocfs_at_hist_helper(struct seq_file *m,
static inline int lprocfs_rd_timeouts(struct seq_file *m, void *data)
{ return 0; }
static inline int lprocfs_wr_timeouts(struct file *file,
- const char *buffer,
- unsigned long count, void *data)
+ const char __user *buffer,
+ unsigned long count, void *data)
{ return 0; }
-static inline int lprocfs_wr_evict_client(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static inline int lprocfs_wr_evict_client(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{ return 0; }
-static inline int lprocfs_wr_ping(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static inline int lprocfs_wr_ping(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{ return 0; }
-static inline int lprocfs_wr_import(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static inline int lprocfs_wr_import(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{ return 0; }
-static inline int lprocfs_wr_pinger_recov(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static inline int lprocfs_wr_pinger_recov(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{ return 0; }
/* Statfs helpers */
diff --git a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
index 7b7457cf70e3..305ecbee9b78 100644
--- a/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
+++ b/drivers/staging/lustre/lustre/include/lustre/lustre_idl.h
@@ -105,6 +105,11 @@
* FOO_BULK_PORTAL is for incoming bulk on the FOO
*/
+/* Lustre service names are following the format
+ * service name + MDT + seq name
+ */
+#define LUSTRE_MDT_MAXNAMELEN 80
+
#define CONNMGR_REQUEST_PORTAL 1
#define CONNMGR_REPLY_PORTAL 2
//#define OSC_REQUEST_PORTAL 3
diff --git a/drivers/staging/lustre/lustre/include/lustre_fid.h b/drivers/staging/lustre/lustre/include/lustre_fid.h
index 2d6fbb4b1b39..0a0929fd9023 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fid.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fid.h
@@ -358,7 +358,7 @@ struct lu_client_seq {
* Service uuid, passed from MDT + seq name to form unique seq name to
* use it with procfs.
*/
- char lcs_name[80];
+ char lcs_name[LUSTRE_MDT_MAXNAMELEN];
/*
* Sequence width, that is how many objects may be allocated in one
@@ -408,7 +408,7 @@ struct lu_server_seq {
* Service uuid, passed from MDT + seq name to form unique seq name to
* use it with procfs.
*/
- char lss_name[80];
+ char lss_name[LUSTRE_MDT_MAXNAMELEN];
/*
* Allocation chunks for super and meta sequences. Default values are
diff --git a/drivers/staging/lustre/lustre/include/lustre_fld.h b/drivers/staging/lustre/lustre/include/lustre_fld.h
index 64c504849a22..5ee4b1ed0995 100644
--- a/drivers/staging/lustre/lustre/include/lustre_fld.h
+++ b/drivers/staging/lustre/lustre/include/lustre_fld.h
@@ -93,7 +93,7 @@ struct lu_server_fld {
/**
* Fld service name in form "fld-srv-lustre-MDTXXX" */
- char lsf_name[80];
+ char lsf_name[LUSTRE_MDT_MAXNAMELEN];
};
@@ -124,7 +124,7 @@ struct lu_client_fld {
/**
* Client fld proc entry name. */
- char lcf_name[80];
+ char lcf_name[LUSTRE_MDT_MAXNAMELEN];
int lcf_flags;
};
diff --git a/drivers/staging/lustre/lustre/include/lustre_update.h b/drivers/staging/lustre/lustre/include/lustre_update.h
deleted file mode 100644
index 84defce0f623..000000000000
--- a/drivers/staging/lustre/lustre/include/lustre_update.h
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * GPL HEADER START
- *
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 only,
- * as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License version 2 for more details (a copy is included
- * in the LICENSE file that accompanied this code).
- *
- * You should have received a copy of the GNU General Public License
- * version 2 along with this program; If not, see
- * http://www.gnu.org/licenses/gpl-2.0.htm
- *
- * GPL HEADER END
- */
-/*
- * Copyright (c) 2013, Intel Corporation.
- */
-/*
- * lustre/include/lustre_update.h
- *
- * Author: Di Wang <di.wang@intel.com>
- */
-
-#ifndef _LUSTRE_UPDATE_H
-#define _LUSTRE_UPDATE_H
-
-#define UPDATE_BUFFER_SIZE 8192
-struct update_request {
- struct dt_device *ur_dt;
- struct list_head ur_list; /* attached itself to thandle */
- int ur_flags;
- int ur_rc; /* request result */
- int ur_batchid; /* Current batch(trans) id */
- struct update_buf *ur_buf; /* Holding the update req */
-};
-
-static inline unsigned long update_size(struct update *update)
-{
- unsigned long size;
- int i;
-
- size = cfs_size_round(offsetof(struct update, u_bufs[0]));
- for (i = 0; i < UPDATE_BUF_COUNT; i++)
- size += cfs_size_round(update->u_lens[i]);
-
- return size;
-}
-
-static inline void *update_param_buf(struct update *update, int index,
- int *size)
-{
- int i;
- void *ptr;
-
- if (index >= UPDATE_BUF_COUNT)
- return NULL;
-
- ptr = (char *)update + cfs_size_round(offsetof(struct update,
- u_bufs[0]));
- for (i = 0; i < index; i++) {
- LASSERT(update->u_lens[i] > 0);
- ptr += cfs_size_round(update->u_lens[i]);
- }
-
- if (size != NULL)
- *size = update->u_lens[index];
-
- return ptr;
-}
-
-static inline unsigned long update_buf_size(struct update_buf *buf)
-{
- unsigned long size;
- int i = 0;
-
- size = cfs_size_round(offsetof(struct update_buf, ub_bufs[0]));
- for (i = 0; i < buf->ub_count; i++) {
- struct update *update;
-
- update = (struct update *)((char *)buf + size);
- size += update_size(update);
- }
- LASSERT(size <= UPDATE_BUFFER_SIZE);
- return size;
-}
-
-static inline void *update_buf_get(struct update_buf *buf, int index, int *size)
-{
- int count = buf->ub_count;
- void *ptr;
- int i = 0;
-
- if (index >= count)
- return NULL;
-
- ptr = (char *)buf + cfs_size_round(offsetof(struct update_buf,
- ub_bufs[0]));
- for (i = 0; i < index; i++)
- ptr += update_size((struct update *)ptr);
-
- if (size != NULL)
- *size = update_size((struct update *)ptr);
-
- return ptr;
-}
-
-static inline void update_init_reply_buf(struct update_reply *reply, int count)
-{
- reply->ur_version = UPDATE_REPLY_V1;
- reply->ur_count = count;
-}
-
-static inline void *update_get_buf_internal(struct update_reply *reply,
- int index, int *size)
-{
- char *ptr;
- int count = reply->ur_count;
- int i;
-
- if (index >= count)
- return NULL;
-
- ptr = (char *)reply + cfs_size_round(offsetof(struct update_reply,
- ur_lens[count]));
- for (i = 0; i < index; i++) {
- LASSERT(reply->ur_lens[i] > 0);
- ptr += cfs_size_round(reply->ur_lens[i]);
- }
-
- if (size != NULL)
- *size = reply->ur_lens[index];
-
- return ptr;
-}
-
-static inline void update_insert_reply(struct update_reply *reply, void *data,
- int data_len, int index, int rc)
-{
- char *ptr;
-
- ptr = update_get_buf_internal(reply, index, NULL);
- LASSERT(ptr != NULL);
-
- *(int *)ptr = cpu_to_le32(rc);
- ptr += sizeof(int);
- if (data_len > 0) {
- LASSERT(data != NULL);
- memcpy(ptr, data, data_len);
- }
- reply->ur_lens[index] = data_len + sizeof(int);
-}
-
-static inline int update_get_reply_buf(struct update_reply *reply, void **buf,
- int index)
-{
- char *ptr;
- int size = 0;
- int result;
-
- ptr = update_get_buf_internal(reply, index, &size);
- result = *(int *)ptr;
-
- if (result < 0)
- return result;
-
- LASSERT((ptr != NULL && size >= sizeof(int)));
- *buf = ptr + sizeof(int);
- return size - sizeof(int);
-}
-
-static inline int update_get_reply_result(struct update_reply *reply,
- void **buf, int index)
-{
- void *ptr;
- int size;
-
- ptr = update_get_buf_internal(reply, index, &size);
- LASSERT(ptr != NULL && size > sizeof(int));
- return *(int *)ptr;
-}
-
-#endif
diff --git a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
index 24d26ab35346..23095bb75226 100644
--- a/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
+++ b/drivers/staging/lustre/lustre/lclient/lcommon_cl.c
@@ -586,6 +586,12 @@ int ccc_lock_enqueue(const struct lu_env *env,
return 0;
}
+int ccc_lock_use(const struct lu_env *env, const struct cl_lock_slice *slice)
+{
+ CLOBINVRNT(env, slice->cls_obj, ccc_object_invariant(slice->cls_obj));
+ return 0;
+}
+
int ccc_lock_unuse(const struct lu_env *env, const struct cl_lock_slice *slice)
{
CLOBINVRNT(env, slice->cls_obj, ccc_object_invariant(slice->cls_obj));
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
index 6c6c57ca91de..20e64cddb1f4 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_internal.h
@@ -249,8 +249,9 @@ typedef enum ldlm_policy_res ldlm_policy_res_t;
struct __##var##__dummy_read {; } /* semicolon catcher */
#define LDLM_POOL_PROC_WRITER(var, type) \
- static int lprocfs_wr_##var(struct file *file, const char *buffer, \
- unsigned long count, void *data) \
+ static int lprocfs_wr_##var(struct file *file, \
+ const char __user *buffer, \
+ unsigned long count, void *data) \
{ \
struct ldlm_pool *pl = data; \
type tmp; \
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
index 4c838f615a64..d20d277dc2f7 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_pool.c
@@ -470,6 +470,7 @@ static void ldlm_cli_pool_pop_slv(struct ldlm_pool *pl)
static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
{
time_t recalc_interval_sec;
+ int ret;
recalc_interval_sec = get_seconds() - pl->pl_recalc_time;
if (recalc_interval_sec < pl->pl_recalc_period)
@@ -490,16 +491,15 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
*/
ldlm_cli_pool_pop_slv(pl);
- pl->pl_recalc_time = get_seconds();
- lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
- recalc_interval_sec);
spin_unlock(&pl->pl_lock);
/*
* Do not cancel locks in case lru resize is disabled for this ns.
*/
- if (!ns_connect_lru_resize(ldlm_pl2ns(pl)))
- return 0;
+ if (!ns_connect_lru_resize(ldlm_pl2ns(pl))) {
+ ret = 0;
+ goto out;
+ }
/*
* In the time of canceling locks on client we do not need to maintain
@@ -507,7 +507,19 @@ static int ldlm_cli_pool_recalc(struct ldlm_pool *pl)
* It may be called when SLV has changed much, this is why we do not
* take into account pl->pl_recalc_time here.
*/
- return ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
+ ret = ldlm_cancel_lru(ldlm_pl2ns(pl), 0, LCF_ASYNC, LDLM_CANCEL_LRUR);
+
+out:
+ spin_lock(&pl->pl_lock);
+ /*
+ * Time of LRU resizing might be longer than period,
+ * so update after LRU resizing rather than before it.
+ */
+ pl->pl_recalc_time = get_seconds();
+ lprocfs_counter_add(pl->pl_stats, LDLM_POOL_TIMING_STAT,
+ recalc_interval_sec);
+ spin_unlock(&pl->pl_lock);
+ return ret;
}
/**
@@ -591,6 +603,14 @@ int ldlm_pool_recalc(struct ldlm_pool *pl)
}
recalc_interval_sec = pl->pl_recalc_time - get_seconds() +
pl->pl_recalc_period;
+ if (recalc_interval_sec <= 0) {
+ /* Prevent too frequent recalculation. */
+ CDEBUG(D_DLMTRACE, "Negative interval(%ld), "
+ "too short period(%ld)",
+ recalc_interval_sec,
+ pl->pl_recalc_period);
+ recalc_interval_sec = 1;
+ }
return recalc_interval_sec;
}
@@ -697,8 +717,8 @@ LPROC_SEQ_FOPS_RO(lprocfs_grant_plan);
LDLM_POOL_PROC_READER_SEQ_SHOW(recalc_period, int);
LDLM_POOL_PROC_WRITER(recalc_period, int);
static ssize_t lprocfs_recalc_period_seq_write(struct file *file,
- const char *buf, size_t len,
- loff_t *off)
+ const char __user *buf,
+ size_t len, loff_t *off)
{
struct seq_file *seq = file->private_data;
diff --git a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
index 1f150e46f50e..c6f62a91b233 100644
--- a/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
+++ b/drivers/staging/lustre/lustre/ldlm/ldlm_resource.c
@@ -72,7 +72,7 @@ extern unsigned int ldlm_cancel_unused_locks_before_replay;
unsigned int ldlm_dump_granted_max = 256;
#if defined(CONFIG_PROC_FS)
-static ssize_t lprocfs_wr_dump_ns(struct file *file, const char *buffer,
+static ssize_t lprocfs_wr_dump_ns(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
ldlm_dump_all_namespaces(LDLM_NAMESPACE_SERVER, D_DLMTRACE);
@@ -287,8 +287,9 @@ static int lprocfs_elc_seq_show(struct seq_file *m, void *v)
return lprocfs_rd_uint(m, &supp);
}
-static ssize_t lprocfs_elc_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t lprocfs_elc_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct ldlm_namespace *ns = ((struct seq_file *)file->private_data)->private;
unsigned int supp = -1;
diff --git a/drivers/staging/lustre/lustre/libcfs/debug.c b/drivers/staging/lustre/lustre/libcfs/debug.c
index a7a7ac626aaf..76c62e87a415 100644
--- a/drivers/staging/lustre/lustre/libcfs/debug.c
+++ b/drivers/staging/lustre/lustre/libcfs/debug.c
@@ -57,7 +57,7 @@ module_param(libcfs_debug, int, 0644);
MODULE_PARM_DESC(libcfs_debug, "Lustre kernel debug mask");
EXPORT_SYMBOL(libcfs_debug);
-unsigned int libcfs_debug_mb = 0;
+static unsigned int libcfs_debug_mb;
module_param(libcfs_debug_mb, uint, 0644);
MODULE_PARM_DESC(libcfs_debug_mb, "Total debug buffer size.");
EXPORT_SYMBOL(libcfs_debug_mb);
@@ -93,7 +93,7 @@ EXPORT_SYMBOL(libcfs_debug_binary);
unsigned int libcfs_stack = 3 * THREAD_SIZE / 4;
EXPORT_SYMBOL(libcfs_stack);
-unsigned int portal_enter_debugger;
+static unsigned int portal_enter_debugger;
EXPORT_SYMBOL(portal_enter_debugger);
unsigned int libcfs_catastrophe;
@@ -115,7 +115,7 @@ static wait_queue_head_t debug_ctlwq;
char libcfs_debug_file_path_arr[PATH_MAX] = LIBCFS_DEBUG_FILE_PATH_DEFAULT;
/* We need to pass a pointer here, but elsewhere this must be a const */
-char *libcfs_debug_file_path;
+static char *libcfs_debug_file_path;
module_param(libcfs_debug_file_path, charp, 0644);
MODULE_PARM_DESC(libcfs_debug_file_path,
"Path for dumping debug logs, set 'NONE' to prevent log dumping");
@@ -124,7 +124,7 @@ int libcfs_panic_in_progress;
/* libcfs_debug_token2mask() expects the returned
* string in lower-case */
-const char *
+static const char *
libcfs_debug_subsys2str(int subsys)
{
switch (1 << subsys) {
@@ -185,7 +185,7 @@ libcfs_debug_subsys2str(int subsys)
/* libcfs_debug_token2mask() expects the returned
* string in lower-case */
-const char *
+static const char *
libcfs_debug_dbg2str(int debug)
{
switch (1 << debug) {
@@ -350,7 +350,7 @@ void libcfs_debug_dumplog_internal(void *arg)
current->journal_info = journal_info;
}
-int libcfs_debug_dumplog_thread(void *arg)
+static int libcfs_debug_dumplog_thread(void *arg)
{
libcfs_debug_dumplog_internal(arg);
wake_up(&debug_ctlwq);
diff --git a/drivers/staging/lustre/lustre/libcfs/hash.c b/drivers/staging/lustre/lustre/libcfs/hash.c
index 2d1e6729e996..ec3a2a8b8b2c 100644
--- a/drivers/staging/lustre/lustre/libcfs/hash.c
+++ b/drivers/staging/lustre/lustre/libcfs/hash.c
@@ -126,18 +126,21 @@ cfs_hash_nl_unlock(union cfs_hash_lock *lock, int exclusive) {}
static inline void
cfs_hash_spin_lock(union cfs_hash_lock *lock, int exclusive)
+ __acquires(&lock->spin)
{
spin_lock(&lock->spin);
}
static inline void
cfs_hash_spin_unlock(union cfs_hash_lock *lock, int exclusive)
+ __releases(&lock->spin)
{
spin_unlock(&lock->spin);
}
static inline void
cfs_hash_rw_lock(union cfs_hash_lock *lock, int exclusive)
+ __acquires(&lock->rw)
{
if (!exclusive)
read_lock(&lock->rw);
@@ -147,6 +150,7 @@ cfs_hash_rw_lock(union cfs_hash_lock *lock, int exclusive)
static inline void
cfs_hash_rw_unlock(union cfs_hash_lock *lock, int exclusive)
+ __releases(&lock->rw)
{
if (!exclusive)
read_unlock(&lock->rw);
@@ -1580,7 +1584,7 @@ cfs_hash_for_each_relax(struct cfs_hash *hs, cfs_hash_for_each_cb_t func,
stop_on_change = cfs_hash_with_rehash_key(hs) ||
!cfs_hash_with_no_itemref(hs) ||
- CFS_HOP(hs, put_locked) == NULL;
+ hs->hs_ops->hs_put_locked == NULL;
cfs_hash_lock(hs, 0);
LASSERT(!cfs_hash_is_rehashing(hs));
@@ -1635,9 +1639,9 @@ cfs_hash_for_each_nolock(struct cfs_hash *hs,
!cfs_hash_with_no_itemref(hs))
return -EOPNOTSUPP;
- if (CFS_HOP(hs, get) == NULL ||
- (CFS_HOP(hs, put) == NULL &&
- CFS_HOP(hs, put_locked) == NULL))
+ if (hs->hs_ops->hs_get == NULL ||
+ (hs->hs_ops->hs_put == NULL &&
+ hs->hs_ops->hs_put_locked == NULL))
return -EOPNOTSUPP;
cfs_hash_for_each_enter(hs);
@@ -1667,9 +1671,9 @@ cfs_hash_for_each_empty(struct cfs_hash *hs,
if (cfs_hash_with_no_lock(hs))
return -EOPNOTSUPP;
- if (CFS_HOP(hs, get) == NULL ||
- (CFS_HOP(hs, put) == NULL &&
- CFS_HOP(hs, put_locked) == NULL))
+ if (hs->hs_ops->hs_get == NULL ||
+ (hs->hs_ops->hs_put == NULL &&
+ hs->hs_ops->hs_put_locked == NULL))
return -EOPNOTSUPP;
cfs_hash_for_each_enter(hs);
diff --git a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
index e2aa637abcf9..d9b7c6b69db4 100644
--- a/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
+++ b/drivers/staging/lustre/lustre/libcfs/kernel_user_comm.c
@@ -228,12 +228,12 @@ int libcfs_kkuc_group_foreach(int group, libcfs_kkuc_cb_t cb_func,
if (kkuc_groups[group].next == NULL)
return 0;
- down_read(&kg_sem);
+ down_write(&kg_sem);
list_for_each_entry(reg, &kkuc_groups[group], kr_chain) {
if (reg->kr_fp != NULL)
rc = cb_func(reg->kr_data, cb_arg);
}
- up_read(&kg_sem);
+ up_write(&kg_sem);
return rc;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
index fb88733607a9..76d4392bd282 100644
--- a/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
+++ b/drivers/staging/lustre/lustre/libcfs/libcfs_string.c
@@ -47,7 +47,7 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
int *oldmask, int minmask, int allmask)
{
const char *debugstr;
- char op = 0;
+ char op = '\0';
int newmask = minmask, i, len, found = 0;
/* <str> must be a list of tokens separated by whitespace
@@ -55,10 +55,10 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
* appears first in <str>, '*oldmask' is used as the starting point
* (relative), otherwise minmask is used (absolute). An operator
* applies to all following tokens up to the next operator. */
- while (*str != 0) {
+ while (*str != '\0') {
while (isspace(*str))
str++;
- if (*str == 0)
+ if (*str == '\0')
break;
if (*str == '+' || *str == '-') {
op = *str++;
@@ -67,13 +67,15 @@ int cfs_str2mask(const char *str, const char *(*bit2str)(int bit),
newmask = *oldmask;
while (isspace(*str))
str++;
- if (*str == 0) /* trailing op */
+ if (*str == '\0') /* trailing op */
return -EINVAL;
}
/* find token length */
- for (len = 0; str[len] != 0 && !isspace(str[len]) &&
- str[len] != '+' && str[len] != '-'; len++);
+ len = 0;
+ while (str[len] != '\0' && !isspace(str[len]) &&
+ str[len] != '+' && str[len] != '-')
+ len++;
/* match token */
found = 0;
@@ -132,7 +134,7 @@ char *cfs_firststr(char *str, size_t size)
++end;
}
- *end= '\0';
+ *end = '\0';
out:
return str;
}
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
index d71ad5ed1f6d..277f6b890e09 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-curproc.c
@@ -82,17 +82,12 @@ int cfs_cap_raised(cfs_cap_t cap)
return cap_raised(current_cap(), cap);
}
-void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap)
+static void cfs_kernel_cap_pack(kernel_cap_t kcap, cfs_cap_t *cap)
{
/* XXX lost high byte */
*cap = kcap.cap[0];
}
-void cfs_kernel_cap_unpack(kernel_cap_t *kcap, cfs_cap_t cap)
-{
- kcap->cap[0] = cap;
-}
-
cfs_cap_t cfs_curproc_cap_pack(void)
{
cfs_cap_t cap;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
index 83d3f08a37b2..c539e3741583 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-proc.c
@@ -232,8 +232,9 @@ static int proc_debug_mb(struct ctl_table *table, int write,
__proc_debug_mb);
}
-int proc_console_max_delay_cs(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_console_max_delay_cs(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
{
int rc, max_delay_cs;
struct ctl_table dummy = *table;
@@ -264,8 +265,9 @@ int proc_console_max_delay_cs(struct ctl_table *table, int write,
return rc;
}
-int proc_console_min_delay_cs(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_console_min_delay_cs(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
{
int rc, min_delay_cs;
struct ctl_table dummy = *table;
@@ -296,8 +298,8 @@ int proc_console_min_delay_cs(struct ctl_table *table, int write,
return rc;
}
-int proc_console_backoff(struct ctl_table *table, int write,
- void __user *buffer, size_t *lenp, loff_t *ppos)
+static int proc_console_backoff(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp, loff_t *ppos)
{
int rc, backoff;
struct ctl_table dummy = *table;
@@ -324,16 +326,18 @@ int proc_console_backoff(struct ctl_table *table, int write,
return rc;
}
-int libcfs_force_lbug(struct ctl_table *table, int write, void __user *buffer,
- size_t *lenp, loff_t *ppos)
+static int libcfs_force_lbug(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
{
if (write)
LBUG();
return 0;
}
-int proc_fail_loc(struct ctl_table *table, int write, void __user *buffer,
- size_t *lenp, loff_t *ppos)
+static int proc_fail_loc(struct ctl_table *table, int write,
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
{
int rc;
long old_fail_loc = cfs_fail_loc;
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
index b91a1f95bbd0..cd2fc01dea4c 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tcpip.c
@@ -43,7 +43,7 @@
/* For sys_open & sys_close */
#include <linux/syscalls.h>
-int
+static int
libcfs_sock_ioctl(int cmd, unsigned long arg)
{
mm_segment_t oldmm = get_fs();
diff --git a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
index 976c61ed49f4..c8e293002e07 100644
--- a/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/linux/linux-tracefile.c
@@ -151,6 +151,7 @@ cfs_trace_buf_type_t cfs_trace_buf_idx_get(void)
* for details.
*/
int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
+ __acquires(&tcd->tc_lock)
{
__LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
@@ -165,6 +166,7 @@ int cfs_trace_lock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
}
void cfs_trace_unlock_tcd(struct cfs_trace_cpu_data *tcd, int walking)
+ __releases(&tcd->tcd_lock)
{
__LASSERT(tcd->tcd_type < CFS_TCD_TYPE_MAX);
if (tcd->tcd_type == CFS_TCD_TYPE_IRQ)
@@ -269,5 +271,5 @@ int cfs_trace_max_debug_mb(void)
{
int total_mb = (totalram_pages >> (20 - PAGE_SHIFT));
- return MAX(512, (total_mb * 80)/100);
+ return max(512, (total_mb * 80)/100);
}
diff --git a/drivers/staging/lustre/lustre/libcfs/module.c b/drivers/staging/lustre/lustre/libcfs/module.c
index 2c4fc74505bc..7dc77dd402b8 100644
--- a/drivers/staging/lustre/lustre/libcfs/module.c
+++ b/drivers/staging/lustre/lustre/libcfs/module.c
@@ -42,8 +42,7 @@
#include "../../include/linux/lnet/lnet.h"
#include "tracefile.h"
-void
-kportal_memhog_free (struct libcfs_device_userstate *ldu)
+static void kportal_memhog_free (struct libcfs_device_userstate *ldu)
{
struct page **level0p = &ldu->ldu_memhog_root_page;
struct page **level1p;
@@ -86,8 +85,7 @@ kportal_memhog_free (struct libcfs_device_userstate *ldu)
LASSERT (ldu->ldu_memhog_pages == 0);
}
-int
-kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
+static int kportal_memhog_alloc(struct libcfs_device_userstate *ldu, int npages,
gfp_t flags)
{
struct page **level0p;
@@ -334,8 +332,6 @@ extern struct mutex cfs_trace_thread_mutex;
extern struct cfs_wi_sched *cfs_sched_rehash;
extern void libcfs_init_nidstrings(void);
-extern int libcfs_arch_init(void);
-extern void libcfs_arch_cleanup(void);
static int init_libcfs_module(void)
{
diff --git a/drivers/staging/lustre/lustre/libcfs/nidstrings.c b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
index 47c239f22ba8..087449f4e6c1 100644
--- a/drivers/staging/lustre/lustre/libcfs/nidstrings.c
+++ b/drivers/staging/lustre/lustre/libcfs/nidstrings.c
@@ -81,14 +81,105 @@ libcfs_next_nidstring(void)
return str;
}
-static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr);
-static void libcfs_ip_addr2str(__u32 addr, char *str);
-static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr);
-static void libcfs_decnum_addr2str(__u32 addr, char *str);
-static void libcfs_hexnum_addr2str(__u32 addr, char *str);
-static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr);
-static int libcfs_num_parse(char *str, int len, struct list_head *list);
-static int libcfs_num_match(__u32 addr, struct list_head *list);
+static int libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
+{
+ *addr = 0;
+ return 1;
+}
+
+static void libcfs_ip_addr2str(__u32 addr, char *str)
+{
+ snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
+ (addr >> 24) & 0xff, (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff, addr & 0xff);
+}
+
+static int libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
+{
+ unsigned int a;
+ unsigned int b;
+ unsigned int c;
+ unsigned int d;
+ int n = nob; /* XscanfX */
+
+ /* numeric IP? */
+ if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
+ n == nob &&
+ (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
+ (c & ~0xff) == 0 && (d & ~0xff) == 0) {
+ *addr = ((a<<24)|(b<<16)|(c<<8)|d);
+ return 1;
+ }
+
+ return 0;
+}
+
+static void libcfs_decnum_addr2str(__u32 addr, char *str)
+{
+ snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
+}
+
+static void libcfs_hexnum_addr2str(__u32 addr, char *str)
+{
+ snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
+}
+
+static int libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
+{
+ int n;
+
+ n = nob;
+ if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
+ return 1;
+
+ n = nob;
+ if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
+ return 1;
+
+ n = nob;
+ if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Nf_parse_addrlist method for networks using numeric addresses.
+ *
+ * Examples of such networks are gm and elan.
+ *
+ * \retval 0 if \a str parsed to numeric address
+ * \retval errno otherwise
+ */
+static int
+libcfs_num_parse(char *str, int len, struct list_head *list)
+{
+ struct cfs_expr_list *el;
+ int rc;
+
+ rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
+ if (rc == 0)
+ list_add_tail(&el->el_link, list);
+
+ return rc;
+}
+
+/*
+ * Nf_match_addr method for networks using numeric addresses
+ *
+ * \retval 1 on match
+ * \retval 0 otherwise
+ */
+static int
+libcfs_num_match(__u32 addr, struct list_head *numaddr)
+{
+ struct cfs_expr_list *el;
+
+ LASSERT(!list_empty(numaddr));
+ el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
+
+ return cfs_expr_list_match(addr, el);
+}
struct netstrfns {
int nf_type;
@@ -197,24 +288,7 @@ static struct netstrfns libcfs_netstrfns[] = {
{/* .nf_type */ -1},
};
-const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
-
-int
-libcfs_lo_str2addr(const char *str, int nob, __u32 *addr)
-{
- *addr = 0;
- return 1;
-}
-
-void
-libcfs_ip_addr2str(__u32 addr, char *str)
-{
-#if 0 /* never lookup */
-#endif
- snprintf(str, LNET_NIDSTR_SIZE, "%u.%u.%u.%u",
- (addr >> 24) & 0xff, (addr >> 16) & 0xff,
- (addr >> 8) & 0xff, addr & 0xff);
-}
+static const int libcfs_nnetstrfns = ARRAY_SIZE(libcfs_netstrfns);
/* CAVEAT EMPTOR XscanfX
* I use "%n" at the end of a sscanf format to detect trailing junk. However
@@ -223,60 +297,7 @@ libcfs_ip_addr2str(__u32 addr, char *str)
* fine, if it doesn't, then the scan ended at the end of the string, which is
* fine too :) */
-int
-libcfs_ip_str2addr(const char *str, int nob, __u32 *addr)
-{
- unsigned int a;
- unsigned int b;
- unsigned int c;
- unsigned int d;
- int n = nob; /* XscanfX */
-
- /* numeric IP? */
- if (sscanf(str, "%u.%u.%u.%u%n", &a, &b, &c, &d, &n) >= 4 &&
- n == nob &&
- (a & ~0xff) == 0 && (b & ~0xff) == 0 &&
- (c & ~0xff) == 0 && (d & ~0xff) == 0) {
- *addr = ((a<<24)|(b<<16)|(c<<8)|d);
- return 1;
- }
-
- return 0;
-}
-
-void
-libcfs_decnum_addr2str(__u32 addr, char *str)
-{
- snprintf(str, LNET_NIDSTR_SIZE, "%u", addr);
-}
-
-void
-libcfs_hexnum_addr2str(__u32 addr, char *str)
-{
- snprintf(str, LNET_NIDSTR_SIZE, "0x%x", addr);
-}
-
-int
-libcfs_num_str2addr(const char *str, int nob, __u32 *addr)
-{
- int n;
-
- n = nob;
- if (sscanf(str, "0x%x%n", addr, &n) >= 1 && n == nob)
- return 1;
-
- n = nob;
- if (sscanf(str, "0X%x%n", addr, &n) >= 1 && n == nob)
- return 1;
-
- n = nob;
- if (sscanf(str, "%u%n", addr, &n) >= 1 && n == nob)
- return 1;
-
- return 0;
-}
-
-struct netstrfns *
+static struct netstrfns *
libcfs_lnd2netstrfns(int lnd)
{
int i;
@@ -289,7 +310,7 @@ libcfs_lnd2netstrfns(int lnd)
return NULL;
}
-struct netstrfns *
+static struct netstrfns *
libcfs_namenum2netstrfns(const char *name)
{
struct netstrfns *nf;
@@ -304,7 +325,7 @@ libcfs_namenum2netstrfns(const char *name)
return NULL;
}
-struct netstrfns *
+static struct netstrfns *
libcfs_name2netstrfns(const char *name)
{
int i;
@@ -343,7 +364,7 @@ libcfs_lnd2str(int lnd)
return nf->nf_name;
str = libcfs_next_nidstring();
- snprintf(str, LNET_NIDSTR_SIZE, "?%u?", lnd);
+ snprintf(str, LNET_NIDSTR_SIZE, "?%d?", lnd);
return str;
}
EXPORT_SYMBOL(libcfs_lnd2str);
@@ -369,11 +390,11 @@ libcfs_net2str(__u32 net)
char *str = libcfs_next_nidstring();
if (nf == NULL)
- snprintf(str, LNET_NIDSTR_SIZE, "<%u:%u>", lnd, num);
+ snprintf(str, LNET_NIDSTR_SIZE, "<%d:%d>", lnd, num);
else if (num == 0)
snprintf(str, LNET_NIDSTR_SIZE, "%s", nf->nf_name);
else
- snprintf(str, LNET_NIDSTR_SIZE, "%s%u", nf->nf_name, num);
+ snprintf(str, LNET_NIDSTR_SIZE, "%s%d", nf->nf_name, num);
return str;
}
@@ -397,7 +418,7 @@ libcfs_nid2str(lnet_nid_t nid)
str = libcfs_next_nidstring();
if (nf == NULL)
- snprintf(str, LNET_NIDSTR_SIZE, "%x@<%u:%u>", addr, lnd, nnum);
+ snprintf(str, LNET_NIDSTR_SIZE, "%x@<%d:%d>", addr, lnd, nnum);
else {
nf->nf_addr2str(addr, str);
nob = strlen(str);
@@ -405,7 +426,7 @@ libcfs_nid2str(lnet_nid_t nid)
snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s",
nf->nf_name);
else
- snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%u",
+ snprintf(str + nob, LNET_NIDSTR_SIZE - nob, "@%s%d",
nf->nf_name, nnum);
}
@@ -586,27 +607,6 @@ struct addrrange {
};
/**
- * Nf_parse_addrlist method for networks using numeric addresses.
- *
- * Examples of such networks are gm and elan.
- *
- * \retval 0 if \a str parsed to numeric address
- * \retval errno otherwise
- */
-static int
-libcfs_num_parse(char *str, int len, struct list_head *list)
-{
- struct cfs_expr_list *el;
- int rc;
-
- rc = cfs_expr_list_parse(str, len, 0, MAX_NUMERIC_VALUE, &el);
- if (rc == 0)
- list_add_tail(&el->el_link, list);
-
- return rc;
-}
-
-/**
* Parses \<addrrange\> token on the syntax.
*
* Allocates struct addrrange and links to \a nidrange via
@@ -812,23 +812,6 @@ cfs_parse_nidlist(char *str, int len, struct list_head *nidlist)
}
EXPORT_SYMBOL(cfs_parse_nidlist);
-/*
- * Nf_match_addr method for networks using numeric addresses
- *
- * \retval 1 on match
- * \retval 0 otherwise
- */
-static int
-libcfs_num_match(__u32 addr, struct list_head *numaddr)
-{
- struct cfs_expr_list *el;
-
- LASSERT(!list_empty(numaddr));
- el = list_entry(numaddr->next, struct cfs_expr_list, el_link);
-
- return cfs_expr_list_match(addr, el);
-}
-
/**
* Matches a nid (\a nid) against the compiled list of nidranges (\a nidlist).
*
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index 5917c31c7ed6..eb65b50f832d 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -55,7 +55,7 @@ static struct tracefiled_ctl trace_tctl;
struct mutex cfs_trace_thread_mutex;
static int thread_running = 0;
-atomic_t cfs_tage_allocated = ATOMIC_INIT(0);
+static atomic_t cfs_tage_allocated = ATOMIC_INIT(0);
static void put_pages_on_tcd_daemon_list(struct page_collection *pc,
struct cfs_trace_cpu_data *tcd);
@@ -1037,6 +1037,7 @@ static int tracefiled(void *arg)
tage->used, rc);
put_pages_back(&pc);
__LASSERT(list_empty(&pc.pc_pages));
+ break;
}
}
MMSPACE_CLOSE;
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 5bb9c85cec81..ddf1fa9f67f8 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -263,14 +263,6 @@ void ll_invalidate_aliases(struct inode *inode)
dentry, dentry, dentry->d_parent,
dentry->d_inode, dentry->d_flags);
- if (unlikely(dentry == dentry->d_sb->s_root)) {
- CERROR("%s: called on root dentry=%p, fid="DFID"\n",
- ll_get_fsname(dentry->d_sb, NULL, 0),
- dentry, PFID(ll_inode2fid(inode)));
- lustre_dump_dentry(dentry, 1);
- dump_stack();
- }
-
d_lustre_invalidate(dentry, 0);
}
ll_unlock_dcache(inode);
@@ -278,7 +270,7 @@ void ll_invalidate_aliases(struct inode *inode)
int ll_revalidate_it_finish(struct ptlrpc_request *request,
struct lookup_intent *it,
- struct dentry *de)
+ struct inode *inode)
{
int rc = 0;
@@ -288,19 +280,17 @@ int ll_revalidate_it_finish(struct ptlrpc_request *request,
if (it_disposition(it, DISP_LOOKUP_NEG))
return -ENOENT;
- rc = ll_prep_inode(&de->d_inode, request, NULL, it);
+ rc = ll_prep_inode(&inode, request, NULL, it);
return rc;
}
-void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry)
+void ll_lookup_finish_locks(struct lookup_intent *it, struct inode *inode)
{
LASSERT(it != NULL);
- LASSERT(dentry != NULL);
- if (it->d.lustre.it_lock_mode && dentry->d_inode != NULL) {
- struct inode *inode = dentry->d_inode;
- struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode);
+ if (it->d.lustre.it_lock_mode && inode != NULL) {
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
CDEBUG(D_DLMTRACE, "setting l_data to inode %p (%lu/%u)\n",
inode, inode->i_ino, inode->i_generation);
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index 1ac7a702ce26..a18201913273 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -183,7 +183,10 @@ static int ll_dir_filler(void *_hash, struct page *page0)
op_data->op_offset = hash;
rc = md_readpage(exp, op_data, page_pool, &request);
ll_finish_md_op_data(op_data);
- if (rc == 0) {
+ if (rc < 0) {
+ /* page0 is special, which was added into page cache early */
+ delete_from_page_cache(page0);
+ } else if (rc == 0) {
body = req_capsule_server_get(&request->rq_pill, &RMF_MDT_BODY);
/* Checked by mdc_readpage() */
LASSERT(body != NULL);
@@ -278,7 +281,7 @@ static struct page *ll_dir_page_locate(struct inode *dir, __u64 *hash,
spin_lock_irq(&mapping->tree_lock);
found = radix_tree_gang_lookup(&mapping->page_tree,
(void **)&page, offset, 1);
- if (found > 0) {
+ if (found > 0 && !radix_tree_exceptional_entry(page)) {
struct lu_dirpage *dp;
page_cache_get(page);
@@ -652,8 +655,8 @@ static int ll_send_mgc_param(struct obd_export *mgc, char *string)
return rc;
}
-int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
- char *filename)
+static int ll_dir_setdirstripe(struct inode *dir, struct lmv_user_md *lump,
+ char *filename)
{
struct ptlrpc_request *request = NULL;
struct md_op_data *op_data;
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index 35a2df01528c..5ebee6ca0a10 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -1553,6 +1553,11 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
struct ccc_grouplock grouplock;
int rc;
+ if (arg == 0) {
+ CWARN("group id for group lock must not be 0\n");
+ return -EINVAL;
+ }
+
if (ll_file_nolock(file))
return -EOPNOTSUPP;
@@ -1587,7 +1592,8 @@ ll_get_grouplock(struct inode *inode, struct file *file, unsigned long arg)
return 0;
}
-int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
+static int ll_put_grouplock(struct inode *inode, struct file *file,
+ unsigned long arg)
{
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
@@ -2906,8 +2912,8 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
oit.it_op = IT_LOOKUP;
/* Call getattr by fid, so do not provide name at all. */
- op_data = ll_prep_md_op_data(NULL, dentry->d_inode,
- dentry->d_inode, NULL, 0, 0,
+ op_data = ll_prep_md_op_data(NULL, inode,
+ inode, NULL, 0, 0,
LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
return PTR_ERR(op_data);
@@ -2925,7 +2931,7 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
goto out;
}
- rc = ll_revalidate_it_finish(req, &oit, dentry);
+ rc = ll_revalidate_it_finish(req, &oit, inode);
if (rc != 0) {
ll_intent_release(&oit);
goto out;
@@ -2938,7 +2944,7 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
if (!dentry->d_inode->i_nlink)
d_lustre_invalidate(dentry, 0);
- ll_lookup_finish_locks(&oit, dentry);
+ ll_lookup_finish_locks(&oit, inode);
} else if (!ll_have_md_lock(dentry->d_inode, &ibits, LCK_MINMODE)) {
struct ll_sb_info *sbi = ll_i2sbi(dentry->d_inode);
u64 valid = OBD_MD_FLGETATTR;
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 37306e0c7aad..2af1d7286250 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -786,9 +786,9 @@ extern const struct dentry_operations ll_d_ops;
void ll_intent_drop_lock(struct lookup_intent *);
void ll_intent_release(struct lookup_intent *);
void ll_invalidate_aliases(struct inode *);
-void ll_lookup_finish_locks(struct lookup_intent *it, struct dentry *dentry);
+void ll_lookup_finish_locks(struct lookup_intent *it, struct inode *inode);
int ll_revalidate_it_finish(struct ptlrpc_request *request,
- struct lookup_intent *it, struct dentry *de);
+ struct lookup_intent *it, struct inode *inode);
/* llite/llite_lib.c */
extern struct super_operations lustre_super_operations;
@@ -816,7 +816,6 @@ int ll_show_options(struct seq_file *seq, struct dentry *dentry);
void ll_dirty_page_discard_warn(struct page *page, int ioret);
int ll_prep_inode(struct inode **inode, struct ptlrpc_request *req,
struct super_block *, struct lookup_intent *);
-void lustre_dump_dentry(struct dentry *, int recur);
int ll_obd_statfs(struct inode *inode, void *arg);
int ll_get_max_mdsize(struct ll_sb_info *sbi, int *max_mdsize);
int ll_get_default_mdsize(struct ll_sb_info *sbi, int *default_mdsize);
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index a3367bfb1456..0c1b583a4ea1 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -665,48 +665,6 @@ int ll_get_default_cookiesize(struct ll_sb_info *sbi, int *lmmsize)
return rc;
}
-static void ll_dump_inode(struct inode *inode)
-{
- struct ll_d_hlist_node *tmp;
- int dentry_count = 0;
-
- LASSERT(inode != NULL);
-
- ll_d_hlist_for_each(tmp, &inode->i_dentry)
- dentry_count++;
-
- CERROR("inode %p dump: dev=%s ino=%lu mode=%o count=%u, %d dentries\n",
- inode, ll_i2mdexp(inode)->exp_obd->obd_name, inode->i_ino,
- inode->i_mode, atomic_read(&inode->i_count), dentry_count);
-}
-
-void lustre_dump_dentry(struct dentry *dentry, int recur)
-{
- struct list_head *tmp;
- int subdirs = 0;
-
- LASSERT(dentry != NULL);
-
- list_for_each(tmp, &dentry->d_subdirs)
- subdirs++;
-
- CERROR("dentry %p dump: name=%pd parent=%pd (%p), inode=%p, count=%u, flags=0x%x, fsdata=%p, %d subdirs\n",
- dentry, dentry, dentry->d_parent, dentry->d_parent,
- dentry->d_inode, d_count(dentry),
- dentry->d_flags, dentry->d_fsdata, subdirs);
- if (dentry->d_inode != NULL)
- ll_dump_inode(dentry->d_inode);
-
- if (recur == 0)
- return;
-
- list_for_each(tmp, &dentry->d_subdirs) {
- struct dentry *d = list_entry(tmp, struct dentry, d_child);
-
- lustre_dump_dentry(d, recur - 1);
- }
-}
-
static void client_common_put_super(struct super_block *sb)
{
struct ll_sb_info *sbi = ll_s2sbi(sb);
@@ -987,7 +945,7 @@ int ll_fill_super(struct super_block *sb, struct vfsmount *mnt)
if (err)
goto out_free;
lsi->lsi_flags |= LSI_BDI_INITIALIZED;
- lsi->lsi_bdi.capabilities = BDI_CAP_MAP_COPY;
+ lsi->lsi_bdi.capabilities = 0;
err = ll_bdi_register(&lsi->lsi_bdi);
if (err)
goto out_free;
@@ -1812,10 +1770,6 @@ void ll_read_inode2(struct inode *inode, void *opaque)
/* OIDEBUG(inode); */
- /* initializing backing dev info. */
- inode->i_mapping->backing_dev_info = &s2lsi(inode->i_sb)->lsi_bdi;
-
-
if (S_ISREG(inode->i_mode)) {
struct ll_sb_info *sbi = ll_i2sbi(inode);
diff --git a/drivers/staging/lustre/lustre/llite/lproc_llite.c b/drivers/staging/lustre/lustre/llite/lproc_llite.c
index e6a909e6faf0..aaa13bd3e8de 100644
--- a/drivers/staging/lustre/lustre/llite/lproc_llite.c
+++ b/drivers/staging/lustre/lustre/llite/lproc_llite.c
@@ -399,9 +399,6 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file,
return -ERANGE;
}
- if (sbi->ll_dt_exp == NULL)
- return -ENODEV;
-
spin_lock(&sbi->ll_lock);
diff = pages_number - cache->ccc_lru_max;
spin_unlock(&sbi->ll_lock);
@@ -437,6 +434,11 @@ static ssize_t ll_max_cached_mb_seq_write(struct file *file,
if (diff <= 0)
break;
+ if (sbi->ll_dt_exp == NULL) { /* being initialized */
+ rc = -ENODEV;
+ break;
+ }
+
/* difficult - have to ask OSCs to drop LRU slots. */
tmp = diff << 1;
rc = obd_set_info_async(NULL, sbi->ll_dt_exp,
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index 4f361b77c749..890ac190f5fa 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -481,6 +481,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
struct lookup_intent lookup_it = { .it_op = IT_LOOKUP };
struct dentry *save = dentry, *retval;
struct ptlrpc_request *req = NULL;
+ struct inode *inode;
struct md_op_data *op_data;
__u32 opc;
int rc;
@@ -539,12 +540,13 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
goto out;
}
- 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->d_inode, it);
+ inode = dentry->d_inode;
+ if ((it->it_op & IT_OPEN) && inode &&
+ !S_ISREG(inode->i_mode) &&
+ !S_ISDIR(inode->i_mode)) {
+ ll_release_openhandle(inode, it);
}
- ll_lookup_finish_locks(it, dentry);
+ ll_lookup_finish_locks(it, inode);
if (dentry == save)
retval = NULL;
diff --git a/drivers/staging/lustre/lustre/llite/super25.c b/drivers/staging/lustre/lustre/llite/super25.c
index 6aff155651cc..7c1e02a031ba 100644
--- a/drivers/staging/lustre/lustre/llite/super25.c
+++ b/drivers/staging/lustre/lustre/llite/super25.c
@@ -72,21 +72,6 @@ static void ll_destroy_inode(struct inode *inode)
call_rcu(&inode->i_rcu, ll_inode_destroy_callback);
}
-static int ll_init_inodecache(void)
-{
- ll_inode_cachep = kmem_cache_create("lustre_inode_cache",
- sizeof(struct ll_inode_info),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (ll_inode_cachep == NULL)
- return -ENOMEM;
- return 0;
-}
-
-static void ll_destroy_inodecache(void)
-{
- kmem_cache_destroy(ll_inode_cachep);
-}
-
/* exported operations */
struct super_operations lustre_super_operations = {
.alloc_inode = ll_alloc_inode,
@@ -104,9 +89,10 @@ void lustre_register_client_process_config(int (*cpc)(struct lustre_cfg *lcfg));
static int __init init_lustre_lite(void)
{
- int i, rc, seed[2];
- struct timeval tv;
+ struct proc_dir_entry *entry;
lnet_process_id_t lnet_id;
+ struct timeval tv;
+ int i, rc, seed[2];
CLASSERT(sizeof(LUSTRE_VOLATILE_HDR) == LUSTRE_VOLATILE_HDR_LEN + 1);
@@ -116,59 +102,52 @@ static int __init init_lustre_lite(void)
CDEBUG(D_INFO, "Lustre client module (%p).\n",
&lustre_super_operations);
- rc = ll_init_inodecache();
- if (rc)
- return -ENOMEM;
+ rc = -ENOMEM;
+ ll_inode_cachep = kmem_cache_create("lustre_inode_cache",
+ sizeof(struct ll_inode_info),
+ 0, SLAB_HWCACHE_ALIGN, NULL);
+ if (ll_inode_cachep == NULL)
+ goto out_cache;
+
ll_file_data_slab = kmem_cache_create("ll_file_data",
sizeof(struct ll_file_data), 0,
SLAB_HWCACHE_ALIGN, NULL);
- if (ll_file_data_slab == NULL) {
- ll_destroy_inodecache();
- return -ENOMEM;
- }
+ if (ll_file_data_slab == NULL)
+ goto out_cache;
ll_remote_perm_cachep = kmem_cache_create("ll_remote_perm_cache",
sizeof(struct ll_remote_perm),
0, 0, NULL);
- if (ll_remote_perm_cachep == NULL) {
- kmem_cache_destroy(ll_file_data_slab);
- ll_file_data_slab = NULL;
- ll_destroy_inodecache();
- return -ENOMEM;
- }
+ if (ll_remote_perm_cachep == NULL)
+ goto out_cache;
ll_rmtperm_hash_cachep = kmem_cache_create("ll_rmtperm_hash_cache",
REMOTE_PERM_HASHSIZE *
sizeof(struct list_head),
0, 0, NULL);
- if (ll_rmtperm_hash_cachep == NULL) {
- kmem_cache_destroy(ll_remote_perm_cachep);
- ll_remote_perm_cachep = NULL;
- kmem_cache_destroy(ll_file_data_slab);
- ll_file_data_slab = NULL;
- ll_destroy_inodecache();
- return -ENOMEM;
+ if (ll_rmtperm_hash_cachep == NULL)
+ goto out_cache;
+
+ entry = lprocfs_register("llite", proc_lustre_root, NULL, NULL);
+ if (IS_ERR(entry)) {
+ rc = PTR_ERR(entry);
+ CERROR("cannot register '/proc/fs/lustre/llite': rc = %d\n",
+ rc);
+ goto out_cache;
}
- proc_lustre_fs_root = proc_lustre_root ?
- lprocfs_register("llite", proc_lustre_root, NULL, NULL) : NULL;
-
- lustre_register_client_fill_super(ll_fill_super);
- lustre_register_kill_super_cb(ll_kill_super);
-
- lustre_register_client_process_config(ll_process_config);
+ proc_lustre_fs_root = entry;
cfs_get_random_bytes(seed, sizeof(seed));
- /* Nodes with small feet have little entropy
- * the NID for this node gives the most entropy in the low bits */
- for (i = 0; ; i++) {
- if (LNetGetId(i, &lnet_id) == -ENOENT) {
+ /* Nodes with small feet have little entropy. The NID for this
+ * node gives the most entropy in the low bits */
+ for (i = 0;; i++) {
+ if (LNetGetId(i, &lnet_id) == -ENOENT)
break;
- }
- if (LNET_NETTYP(LNET_NIDNET(lnet_id.nid)) != LOLND) {
+
+ if (LNET_NETTYP(LNET_NIDNET(lnet_id.nid)) != LOLND)
seed[0] ^= LNET_NIDADDR(lnet_id.nid);
- }
}
do_gettimeofday(&tv);
@@ -177,20 +156,54 @@ static int __init init_lustre_lite(void)
init_timer(&ll_capa_timer);
ll_capa_timer.function = ll_capa_timer_callback;
rc = ll_capa_thread_start();
- /*
- * XXX normal cleanup is needed here.
- */
- if (rc == 0)
- rc = vvp_global_init();
+ if (rc != 0)
+ goto out_proc;
- if (rc == 0)
- rc = ll_xattr_init();
+ rc = vvp_global_init();
+ if (rc != 0)
+ goto out_capa;
+
+ rc = ll_xattr_init();
+ if (rc != 0)
+ goto out_vvp;
+
+ lustre_register_client_fill_super(ll_fill_super);
+ lustre_register_kill_super_cb(ll_kill_super);
+ lustre_register_client_process_config(ll_process_config);
+
+ return 0;
+
+out_vvp:
+ vvp_global_fini();
+out_capa:
+ del_timer(&ll_capa_timer);
+ ll_capa_thread_stop();
+out_proc:
+ lprocfs_remove(&proc_lustre_fs_root);
+out_cache:
+ if (ll_inode_cachep != NULL)
+ kmem_cache_destroy(ll_inode_cachep);
+
+ if (ll_file_data_slab != NULL)
+ kmem_cache_destroy(ll_file_data_slab);
+
+ if (ll_remote_perm_cachep != NULL)
+ kmem_cache_destroy(ll_remote_perm_cachep);
+
+ if (ll_rmtperm_hash_cachep != NULL)
+ kmem_cache_destroy(ll_rmtperm_hash_cachep);
return rc;
}
static void __exit exit_lustre_lite(void)
{
+ lustre_register_client_fill_super(NULL);
+ lustre_register_kill_super_cb(NULL);
+ lustre_register_client_process_config(NULL);
+
+ lprocfs_remove(&proc_lustre_fs_root);
+
ll_xattr_fini();
vvp_global_fini();
del_timer(&ll_capa_timer);
@@ -199,22 +212,12 @@ static void __exit exit_lustre_lite(void)
"client remaining capa count %d\n",
capa_count[CAPA_SITE_CLIENT]);
- lustre_register_client_fill_super(NULL);
- lustre_register_kill_super_cb(NULL);
-
- lustre_register_client_process_config(NULL);
-
- ll_destroy_inodecache();
-
+ kmem_cache_destroy(ll_inode_cachep);
kmem_cache_destroy(ll_rmtperm_hash_cachep);
- ll_rmtperm_hash_cachep = NULL;
kmem_cache_destroy(ll_remote_perm_cachep);
- ll_remote_perm_cachep = NULL;
kmem_cache_destroy(ll_file_data_slab);
- if (proc_lustre_fs_root && !IS_ERR(proc_lustre_fs_root))
- lprocfs_remove(&proc_lustre_fs_root);
}
MODULE_AUTHOR("Sun Microsystems, Inc. <http://www.lustre.org/>");
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index 930f6010203e..91bba79678cf 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -307,18 +307,13 @@ static int vvp_io_rw_lock(const struct lu_env *env, struct cl_io *io,
static int vvp_io_read_lock(const struct lu_env *env,
const struct cl_io_slice *ios)
{
- struct cl_io *io = ios->cis_io;
- struct ll_inode_info *lli = ll_i2info(ccc_object_inode(io->ci_obj));
+ struct cl_io *io = ios->cis_io;
+ struct cl_io_rw_common *rd = &io->u.ci_rd.rd;
int result;
- /* XXX: Layer violation, we shouldn't see lsm at llite level. */
- if (lli->lli_has_smd) /* lsm-less file doesn't need to lock */
- result = vvp_io_rw_lock(env, io, CLM_READ,
- io->u.ci_rd.rd.crw_pos,
- io->u.ci_rd.rd.crw_pos +
- io->u.ci_rd.rd.crw_count - 1);
- else
- result = 0;
+ result = vvp_io_rw_lock(env, io, CLM_READ, rd->crw_pos,
+ rd->crw_pos + rd->crw_count - 1);
+
return result;
}
@@ -632,7 +627,7 @@ static int vvp_io_kernel_fault(struct vvp_fault_io *cfio)
return 0;
}
- if (cfio->fault.ft_flags & VM_FAULT_SIGBUS) {
+ if (cfio->fault.ft_flags & (VM_FAULT_SIGBUS | VM_FAULT_SIGSEGV)) {
CDEBUG(D_PAGE, "got addr %p - SIGBUS\n", vmf->virtual_address);
return -EFAULT;
}
diff --git a/drivers/staging/lustre/lustre/llite/vvp_lock.c b/drivers/staging/lustre/lustre/llite/vvp_lock.c
index 372633e164b9..f354e82d4ae7 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_lock.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_lock.c
@@ -71,6 +71,7 @@ static const struct cl_lock_operations vvp_lock_ops = {
.clo_fini = ccc_lock_fini,
.clo_enqueue = ccc_lock_enqueue,
.clo_wait = ccc_lock_wait,
+ .clo_use = ccc_lock_use,
.clo_unuse = ccc_lock_unuse,
.clo_fits_into = ccc_lock_fits_into,
.clo_state = ccc_lock_state,
diff --git a/drivers/staging/lustre/lustre/lmv/lmv_obd.c b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
index 9f3837412cdf..b779f47384c5 100644
--- a/drivers/staging/lustre/lustre/lmv/lmv_obd.c
+++ b/drivers/staging/lustre/lustre/lmv/lmv_obd.c
@@ -128,7 +128,7 @@ static int lmv_set_mdc_active(struct lmv_obd *lmv, struct obd_uuid *uuid,
return rc;
}
-struct obd_uuid *lmv_get_uuid(struct obd_export *exp)
+static struct obd_uuid *lmv_get_uuid(struct obd_export *exp)
{
struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
@@ -335,7 +335,7 @@ static int lmv_init_ea_size(struct obd_export *exp, int easize,
#define MAX_STRING_SIZE 128
-int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
+static int lmv_connect_mdc(struct obd_device *obd, struct lmv_tgt_desc *tgt)
{
struct proc_dir_entry *lmv_proc_dir;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -1663,10 +1663,10 @@ struct lmv_tgt_desc
return tgt;
}
-int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
- const void *data, int datalen, int mode, __u32 uid,
- __u32 gid, cfs_cap_t cap_effective, __u64 rdev,
- struct ptlrpc_request **request)
+static int lmv_create(struct obd_export *exp, struct md_op_data *op_data,
+ const void *data, int datalen, int mode, __u32 uid,
+ __u32 gid, cfs_cap_t cap_effective, __u64 rdev,
+ struct ptlrpc_request **request)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2387,9 +2387,9 @@ static int lmv_get_info(const struct lu_env *env, struct obd_export *exp,
return -EINVAL;
}
-int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
- u32 keylen, void *key, u32 vallen,
- void *val, struct ptlrpc_request_set *set)
+static int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
+ u32 keylen, void *key, u32 vallen,
+ void *val, struct ptlrpc_request_set *set)
{
struct lmv_tgt_desc *tgt;
struct obd_device *obd;
@@ -2425,8 +2425,8 @@ int lmv_set_info_async(const struct lu_env *env, struct obd_export *exp,
return -EINVAL;
}
-int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
- struct lov_stripe_md *lsm)
+static int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
+ struct lov_stripe_md *lsm)
{
struct obd_device *obd = class_exp2obd(exp);
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2473,8 +2473,8 @@ int lmv_packmd(struct obd_export *exp, struct lov_mds_md **lmmp,
return mea_size;
}
-int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
- struct lov_mds_md *lmm, int lmm_size)
+static int lmv_unpackmd(struct obd_export *exp, struct lov_stripe_md **lsmp,
+ struct lov_mds_md *lmm, int lmm_size)
{
struct obd_device *obd = class_exp2obd(exp);
struct lmv_stripe_md **tmea = (struct lmv_stripe_md **)lsmp;
@@ -2551,8 +2551,8 @@ static int lmv_cancel_unused(struct obd_export *exp, const struct lu_fid *fid,
return rc;
}
-int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
- __u64 *bits)
+static int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
+ __u64 *bits)
{
struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
int rc;
@@ -2561,10 +2561,10 @@ int lmv_set_lock_data(struct obd_export *exp, __u64 *lockh, void *data,
return rc;
}
-ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
- const struct lu_fid *fid, ldlm_type_t type,
- ldlm_policy_data_t *policy, ldlm_mode_t mode,
- struct lustre_handle *lockh)
+static ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
+ const struct lu_fid *fid, ldlm_type_t type,
+ ldlm_policy_data_t *policy, ldlm_mode_t mode,
+ struct lustre_handle *lockh)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2594,16 +2594,18 @@ ldlm_mode_t lmv_lock_match(struct obd_export *exp, __u64 flags,
return 0;
}
-int lmv_get_lustre_md(struct obd_export *exp, struct ptlrpc_request *req,
- struct obd_export *dt_exp, struct obd_export *md_exp,
- struct lustre_md *md)
+static int lmv_get_lustre_md(struct obd_export *exp,
+ struct ptlrpc_request *req,
+ struct obd_export *dt_exp,
+ struct obd_export *md_exp,
+ struct lustre_md *md)
{
struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
return md_get_lustre_md(lmv->tgts[0]->ltd_exp, req, dt_exp, md_exp, md);
}
-int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
+static int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2613,9 +2615,9 @@ int lmv_free_lustre_md(struct obd_export *exp, struct lustre_md *md)
return md_free_lustre_md(lmv->tgts[0]->ltd_exp, md);
}
-int lmv_set_open_replay_data(struct obd_export *exp,
- struct obd_client_handle *och,
- struct lookup_intent *it)
+static int lmv_set_open_replay_data(struct obd_export *exp,
+ struct obd_client_handle *och,
+ struct lookup_intent *it)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2628,8 +2630,8 @@ int lmv_set_open_replay_data(struct obd_export *exp,
return md_set_open_replay_data(tgt->ltd_exp, och, it);
}
-int lmv_clear_open_replay_data(struct obd_export *exp,
- struct obd_client_handle *och)
+static int lmv_clear_open_replay_data(struct obd_export *exp,
+ struct obd_client_handle *och)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2684,17 +2686,18 @@ static int lmv_renew_capa(struct obd_export *exp, struct obd_capa *oc,
return rc;
}
-int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
- const struct req_msg_field *field, struct obd_capa **oc)
+static int lmv_unpack_capa(struct obd_export *exp, struct ptlrpc_request *req,
+ const struct req_msg_field *field,
+ struct obd_capa **oc)
{
struct lmv_obd *lmv = &exp->exp_obd->u.lmv;
return md_unpack_capa(lmv->tgts[0]->ltd_exp, req, field, oc);
}
-int lmv_intent_getattr_async(struct obd_export *exp,
- struct md_enqueue_info *minfo,
- struct ldlm_enqueue_info *einfo)
+static int lmv_intent_getattr_async(struct obd_export *exp,
+ struct md_enqueue_info *minfo,
+ struct ldlm_enqueue_info *einfo)
{
struct md_op_data *op_data = &minfo->mi_data;
struct obd_device *obd = exp->exp_obd;
@@ -2714,8 +2717,8 @@ int lmv_intent_getattr_async(struct obd_export *exp,
return rc;
}
-int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
- struct lu_fid *fid, __u64 *bits)
+static int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
+ struct lu_fid *fid, __u64 *bits)
{
struct obd_device *obd = exp->exp_obd;
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2739,8 +2742,8 @@ int lmv_revalidate_lock(struct obd_export *exp, struct lookup_intent *it,
* process with other slave MDTs. The only exception is Q_GETOQUOTA for which
* we directly fetch data from the slave MDTs.
*/
-int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
- struct obd_quotactl *oqctl)
+static int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
+ struct obd_quotactl *oqctl)
{
struct obd_device *obd = class_exp2obd(exp);
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2786,8 +2789,8 @@ int lmv_quotactl(struct obd_device *unused, struct obd_export *exp,
return rc;
}
-int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
- struct obd_quotactl *oqctl)
+static int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
+ struct obd_quotactl *oqctl)
{
struct obd_device *obd = class_exp2obd(exp);
struct lmv_obd *lmv = &obd->u.lmv;
@@ -2810,7 +2813,7 @@ int lmv_quotacheck(struct obd_device *unused, struct obd_export *exp,
return rc;
}
-struct obd_ops lmv_obd_ops = {
+static struct obd_ops lmv_obd_ops = {
.o_owner = THIS_MODULE,
.o_setup = lmv_setup,
.o_cleanup = lmv_cleanup,
@@ -2830,7 +2833,7 @@ struct obd_ops lmv_obd_ops = {
.o_quotactl = lmv_quotactl
};
-struct md_ops lmv_md_ops = {
+static struct md_ops lmv_md_ops = {
.m_getstatus = lmv_getstatus,
.m_null_inode = lmv_null_inode,
.m_find_cbdata = lmv_find_cbdata,
@@ -2864,7 +2867,7 @@ struct md_ops lmv_md_ops = {
.m_revalidate_lock = lmv_revalidate_lock
};
-int __init lmv_init(void)
+static int __init lmv_init(void)
{
struct lprocfs_static_vars lvars;
int rc;
diff --git a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
index 117002097b28..5be4176829d3 100644
--- a/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
+++ b/drivers/staging/lustre/lustre/lmv/lproc_lmv.c
@@ -175,7 +175,7 @@ static int lmv_tgt_seq_show(struct seq_file *p, void *v)
tgt->ltd_uuid.uuid, tgt->ltd_active ? "" : "IN");
}
-struct seq_operations lmv_tgt_sops = {
+static struct seq_operations lmv_tgt_sops = {
.start = lmv_tgt_seq_start,
.stop = lmv_tgt_seq_stop,
.next = lmv_tgt_seq_next,
@@ -199,7 +199,7 @@ static int lmv_target_seq_open(struct inode *inode, struct file *file)
LPROC_SEQ_FOPS_RO_TYPE(lmv, uuid);
-struct lprocfs_vars lprocfs_lmv_obd_vars[] = {
+static struct lprocfs_vars lprocfs_lmv_obd_vars[] = {
{ "numobd", &lmv_numobd_fops, NULL, 0 },
{ "placement", &lmv_placement_fops, NULL, 0 },
{ "activeobd", &lmv_activeobd_fops, NULL, 0 },
diff --git a/drivers/staging/lustre/lustre/lov/lproc_lov.c b/drivers/staging/lustre/lustre/lov/lproc_lov.c
index c993f25fb303..c99f2f44ec62 100644
--- a/drivers/staging/lustre/lustre/lov/lproc_lov.c
+++ b/drivers/staging/lustre/lustre/lov/lproc_lov.c
@@ -51,8 +51,9 @@ static int lov_stripesize_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%llu\n", desc->ld_default_stripe_size);
}
-static ssize_t lov_stripesize_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t lov_stripesize_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct lov_desc *desc;
@@ -81,8 +82,9 @@ static int lov_stripeoffset_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%llu\n", desc->ld_default_stripe_offset);
}
-static ssize_t lov_stripeoffset_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t lov_stripeoffset_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct lov_desc *desc;
@@ -110,8 +112,9 @@ static int lov_stripetype_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%u\n", desc->ld_pattern);
}
-static ssize_t lov_stripetype_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t lov_stripetype_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct lov_desc *desc;
@@ -140,8 +143,9 @@ static int lov_stripecount_seq_show(struct seq_file *m, void *v)
(__s16)(desc->ld_default_stripe_count + 1) - 1);
}
-static ssize_t lov_stripecount_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t lov_stripecount_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct lov_desc *desc;
diff --git a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
index 16341c818358..c791941bd810 100644
--- a/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
+++ b/drivers/staging/lustre/lustre/mdc/lproc_mdc.c
@@ -52,7 +52,7 @@ static int mdc_max_rpcs_in_flight_seq_show(struct seq_file *m, void *v)
}
static ssize_t mdc_max_rpcs_in_flight_seq_write(struct file *file,
- const char *buffer,
+ const char __user *buffer,
size_t count,
loff_t *off)
{
@@ -82,8 +82,9 @@ static int mdc_kuc_open(struct inode *inode, struct file *file)
}
/* temporary for testing */
-static ssize_t mdc_kuc_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t mdc_kuc_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd =
((struct seq_file *)file->private_data)->private;
@@ -105,6 +106,8 @@ static ssize_t mdc_kuc_write(struct file *file, const char *buffer,
/* for mockup below */ 2 * cfs_size_round(sizeof(*hai));
OBD_ALLOC(lh, len);
+ if (!lh)
+ return -ENOMEM;
lh->kuc_magic = KUC_MAGIC;
lh->kuc_transport = KUC_TRANSPORT_HSM;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_lib.c b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
index 4e59995e0042..d3234cb1ea22 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_lib.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_lib.c
@@ -222,10 +222,9 @@ void mdc_open_pack(struct ptlrpc_request *req, struct md_op_data *op_data,
rec->cr_fsuid = from_kuid(&init_user_ns, current_fsuid());
rec->cr_fsgid = from_kgid(&init_user_ns, current_fsgid());
rec->cr_cap = cfs_curproc_cap_pack();
- if (op_data != NULL) {
- rec->cr_fid1 = op_data->op_fid1;
- rec->cr_fid2 = op_data->op_fid2;
- }
+ rec->cr_fid1 = op_data->op_fid1;
+ rec->cr_fid2 = op_data->op_fid2;
+
rec->cr_mode = mode;
cr_flags = mds_pack_open_flags(flags, mode);
rec->cr_rdev = rdev;
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_locks.c b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
index 8c9b4f5494e9..d1c224ecd2b7 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_locks.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_locks.c
@@ -828,6 +828,7 @@ resend:
einfo->ei_type);
policy = (ldlm_policy_data_t *)lmm;
res_id.name[3] = LDLM_FLOCK;
+ req = NULL;
} else if (it->it_op & IT_OPEN) {
req = mdc_intent_open_pack(exp, it, op_data, lmm, lmmsize,
einfo->ei_cbdata);
diff --git a/drivers/staging/lustre/lustre/mdc/mdc_request.c b/drivers/staging/lustre/lustre/mdc/mdc_request.c
index 3b0f245a8780..ef2744700d8b 100644
--- a/drivers/staging/lustre/lustre/mdc/mdc_request.c
+++ b/drivers/staging/lustre/lustre/mdc/mdc_request.c
@@ -855,8 +855,8 @@ static void mdc_close_handle_reply(struct ptlrpc_request *req,
}
}
-int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
- struct md_open_data *mod, struct ptlrpc_request **request)
+static int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
+ struct md_open_data *mod, struct ptlrpc_request **request)
{
struct obd_device *obd = class_exp2obd(exp);
struct ptlrpc_request *req;
@@ -974,8 +974,8 @@ int mdc_close(struct obd_export *exp, struct md_op_data *op_data,
return rc < 0 ? rc : saved_rc;
}
-int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
- struct md_open_data *mod)
+static int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
+ struct md_open_data *mod)
{
struct obd_device *obd = class_exp2obd(exp);
struct ptlrpc_request *req;
@@ -1044,8 +1044,8 @@ int mdc_done_writing(struct obd_export *exp, struct md_op_data *op_data,
}
-int mdc_readpage(struct obd_export *exp, struct md_op_data *op_data,
- struct page **pages, struct ptlrpc_request **request)
+static int mdc_readpage(struct obd_export *exp, struct md_op_data *op_data,
+ struct page **pages, struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
struct ptlrpc_bulk_desc *desc;
@@ -1908,8 +1908,8 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
/* copy UUID */
if (copy_to_user(data->ioc_pbuf2, obd2cli_tgt(obd),
- min((int) data->ioc_plen2,
- (int) sizeof(struct obd_uuid)))) {
+ min_t(size_t, data->ioc_plen2,
+ sizeof(struct obd_uuid)))) {
rc = -EFAULT;
goto out;
}
@@ -1921,8 +1921,8 @@ static int mdc_iocontrol(unsigned int cmd, struct obd_export *exp, int len,
goto out;
if (copy_to_user(data->ioc_pbuf1, &stat_buf,
- min((int) data->ioc_plen1,
- (int) sizeof(stat_buf)))) {
+ min_t(size_t, data->ioc_plen1,
+ sizeof(stat_buf)))) {
rc = -EFAULT;
goto out;
}
@@ -1974,9 +1974,9 @@ out:
return rc;
}
-int mdc_get_info_rpc(struct obd_export *exp,
- u32 keylen, void *key,
- int vallen, void *val)
+static int mdc_get_info_rpc(struct obd_export *exp,
+ u32 keylen, void *key,
+ int vallen, void *val)
{
struct obd_import *imp = class_exp2cliimp(exp);
struct ptlrpc_request *req;
@@ -2148,11 +2148,11 @@ static int mdc_kuc_reregister(struct obd_import *imp)
(void *)imp);
}
-int mdc_set_info_async(const struct lu_env *env,
- struct obd_export *exp,
- u32 keylen, void *key,
- u32 vallen, void *val,
- struct ptlrpc_request_set *set)
+static int mdc_set_info_async(const struct lu_env *env,
+ struct obd_export *exp,
+ u32 keylen, void *key,
+ u32 vallen, void *val,
+ struct ptlrpc_request_set *set)
{
struct obd_import *imp = class_exp2cliimp(exp);
int rc;
@@ -2199,9 +2199,9 @@ int mdc_set_info_async(const struct lu_env *env,
return -EINVAL;
}
-int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
- __u32 keylen, void *key, __u32 *vallen, void *val,
- struct lov_stripe_md *lsm)
+static int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
+ __u32 keylen, void *key, __u32 *vallen, void *val,
+ struct lov_stripe_md *lsm)
{
int rc = -EINVAL;
@@ -2263,8 +2263,8 @@ int mdc_get_info(const struct lu_env *env, struct obd_export *exp,
return rc;
}
-int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
- struct obd_capa *oc, struct ptlrpc_request **request)
+static int mdc_sync(struct obd_export *exp, const struct lu_fid *fid,
+ struct obd_capa *oc, struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
int rc;
@@ -2356,7 +2356,7 @@ int mdc_fid_alloc(struct obd_export *exp, struct lu_fid *fid,
return seq_client_alloc_fid(NULL, seq, fid);
}
-struct obd_uuid *mdc_get_uuid(struct obd_export *exp)
+static struct obd_uuid *mdc_get_uuid(struct obd_export *exp)
{
struct client_obd *cli = &exp->exp_obd->u.cli;
@@ -2390,7 +2390,7 @@ static int mdc_resource_inode_free(struct ldlm_resource *res)
return 0;
}
-struct ldlm_valblock_ops inode_lvbo = {
+static struct ldlm_valblock_ops inode_lvbo = {
.lvbo_free = mdc_resource_inode_free,
};
@@ -2550,9 +2550,9 @@ static int mdc_process_config(struct obd_device *obd, u32 len, void *buf)
/* get remote permission for current user on fid */
-int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
- struct obd_capa *oc, __u32 suppgid,
- struct ptlrpc_request **request)
+static int mdc_get_remote_perm(struct obd_export *exp, const struct lu_fid *fid,
+ struct obd_capa *oc, __u32 suppgid,
+ struct ptlrpc_request **request)
{
struct ptlrpc_request *req;
int rc;
@@ -2647,7 +2647,7 @@ static int mdc_renew_capa(struct obd_export *exp, struct obd_capa *oc,
return 0;
}
-struct obd_ops mdc_obd_ops = {
+static struct obd_ops mdc_obd_ops = {
.o_owner = THIS_MODULE,
.o_setup = mdc_setup,
.o_precleanup = mdc_precleanup,
@@ -2670,7 +2670,7 @@ struct obd_ops mdc_obd_ops = {
.o_quotacheck = mdc_quotacheck
};
-struct md_ops mdc_md_ops = {
+static struct md_ops mdc_md_ops = {
.m_getstatus = mdc_getstatus,
.m_null_inode = mdc_null_inode,
.m_find_cbdata = mdc_find_cbdata,
@@ -2705,7 +2705,7 @@ struct md_ops mdc_md_ops = {
.m_revalidate_lock = mdc_revalidate_lock
};
-int __init mdc_init(void)
+static int __init mdc_init(void)
{
int rc;
struct lprocfs_static_vars lvars = { NULL };
diff --git a/drivers/staging/lustre/lustre/obdclass/cl_object.c b/drivers/staging/lustre/lustre/obdclass/cl_object.c
index ce96bd279111..f13d1fbffd9d 100644
--- a/drivers/staging/lustre/lustre/obdclass/cl_object.c
+++ b/drivers/staging/lustre/lustre/obdclass/cl_object.c
@@ -193,6 +193,7 @@ static spinlock_t *cl_object_attr_guard(struct cl_object *o)
* cl_object_attr_get(), cl_object_attr_set().
*/
void cl_object_attr_lock(struct cl_object *o)
+ __acquires(cl_object_attr_guard(o))
{
spin_lock(cl_object_attr_guard(o));
}
@@ -202,6 +203,7 @@ EXPORT_SYMBOL(cl_object_attr_lock);
* Releases data-attributes lock, acquired by cl_object_attr_lock().
*/
void cl_object_attr_unlock(struct cl_object *o)
+ __releases(cl_object_attr_guard(o))
{
spin_unlock(cl_object_attr_guard(o));
}
@@ -662,7 +664,8 @@ static int cl_env_store_init(void) {
return cl_env_hash != NULL ? 0 :-ENOMEM;
}
-static void cl_env_store_fini(void) {
+static void cl_env_store_fini(void)
+{
cfs_hash_putref(cl_env_hash);
}
diff --git a/drivers/staging/lustre/lustre/obdclass/class_obd.c b/drivers/staging/lustre/lustre/obdclass/class_obd.c
index 89a3fb2e56b2..29456e1ad225 100644
--- a/drivers/staging/lustre/lustre/obdclass/class_obd.c
+++ b/drivers/staging/lustre/lustre/obdclass/class_obd.c
@@ -61,7 +61,7 @@ __u64 obd_alloc;
EXPORT_SYMBOL(obd_alloc);
__u64 obd_pages;
EXPORT_SYMBOL(obd_pages);
-DEFINE_SPINLOCK(obd_updatemax_lock);
+static DEFINE_SPINLOCK(obd_updatemax_lock);
/* The following are visible and mutable through /proc/sys/lustre/. */
unsigned int obd_alloc_fail_rate = 0;
diff --git a/drivers/staging/lustre/lustre/obdclass/genops.c b/drivers/staging/lustre/lustre/obdclass/genops.c
index 736ca410aca3..82508210465e 100644
--- a/drivers/staging/lustre/lustre/obdclass/genops.c
+++ b/drivers/staging/lustre/lustre/obdclass/genops.c
@@ -1151,22 +1151,24 @@ void class_export_recovery_cleanup(struct obd_export *exp)
exp->exp_obd->obd_stale_clients++;
}
spin_unlock(&obd->obd_recovery_task_lock);
+
+ spin_lock(&exp->exp_lock);
/** Cleanup req replay fields */
if (exp->exp_req_replay_needed) {
- spin_lock(&exp->exp_lock);
exp->exp_req_replay_needed = 0;
- spin_unlock(&exp->exp_lock);
+
LASSERT(atomic_read(&obd->obd_req_replay_clients));
atomic_dec(&obd->obd_req_replay_clients);
}
+
/** Cleanup lock replay data */
if (exp->exp_lock_replay_needed) {
- spin_lock(&exp->exp_lock);
exp->exp_lock_replay_needed = 0;
- spin_unlock(&exp->exp_lock);
+
LASSERT(atomic_read(&obd->obd_lock_replay_clients));
atomic_dec(&obd->obd_lock_replay_clients);
}
+ spin_unlock(&exp->exp_lock);
}
/* This function removes 1-3 references from the export:
diff --git a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
index 66ceab20c743..b94aeac18a37 100644
--- a/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
+++ b/drivers/staging/lustre/lustre/obdclass/linux/linux-module.c
@@ -83,9 +83,8 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
int err;
int offset = 0;
- err = copy_from_user(&hdr, (void *)arg, sizeof(hdr));
- if (err)
- return err;
+ if (copy_from_user(&hdr, (void *)arg, sizeof(hdr)))
+ return -EFAULT;
if (hdr.ioc_version != OBD_IOCTL_VERSION) {
CERROR("Version mismatch kernel (%x) vs application (%x)\n",
@@ -117,18 +116,19 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
*len = hdr.ioc_len;
data = (struct obd_ioctl_data *)*buf;
- err = copy_from_user(*buf, (void *)arg, hdr.ioc_len);
- if (err) {
- OBD_FREE_LARGE(*buf, hdr.ioc_len);
- return err;
+ if (copy_from_user(*buf, (void *)arg, hdr.ioc_len)) {
+ err = -EFAULT;
+ goto free_buf;
+ }
+ if (hdr.ioc_len != data->ioc_len) {
+ err = -EINVAL;
+ goto free_buf;
}
- if (hdr.ioc_len != data->ioc_len)
- return -EINVAL;
if (obd_ioctl_is_invalid(data)) {
CERROR("ioctl not correctly formatted\n");
- OBD_FREE_LARGE(*buf, hdr.ioc_len);
- return -EINVAL;
+ err = -EINVAL;
+ goto free_buf;
}
if (data->ioc_inllen1) {
@@ -151,6 +151,10 @@ int obd_ioctl_getdata(char **buf, int *len, void *arg)
}
return 0;
+
+free_buf:
+ OBD_FREE_LARGE(*buf, hdr.ioc_len);
+ return err;
}
EXPORT_SYMBOL(obd_ioctl_getdata);
@@ -272,8 +276,9 @@ static int obd_proc_jobid_var_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%s\n", obd_jobid_var);
}
-static ssize_t obd_proc_jobid_var_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t obd_proc_jobid_var_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
if (!count || count > JOBSTATS_JOBID_VAR_MAX_LEN)
return -EINVAL;
diff --git a/drivers/staging/lustre/lustre/obdclass/llog_swab.c b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
index d3ec90e85eb9..a2d5aa105d6b 100644
--- a/drivers/staging/lustre/lustre/obdclass/llog_swab.c
+++ b/drivers/staging/lustre/lustre/obdclass/llog_swab.c
@@ -168,7 +168,8 @@ void lustre_swab_llog_rec(struct llog_rec_hdr *rec)
}
case CHANGELOG_REC:
{
- struct llog_changelog_rec *cr = (struct llog_changelog_rec *)rec;
+ struct llog_changelog_rec *cr =
+ (struct llog_changelog_rec *)rec;
__swab16s(&cr->cr.cr_namelen);
__swab16s(&cr->cr.cr_flags);
@@ -188,6 +189,8 @@ void lustre_swab_llog_rec(struct llog_rec_hdr *rec)
} else {
tail = &cr->cr_tail;
}
+ tail = (struct llog_rec_tail *)((char *)tail +
+ cr->cr.cr_namelen);
break;
}
case CHANGELOG_USER_REC:
diff --git a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
index 3b7dfc367722..ddab94d7ee82 100644
--- a/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
+++ b/drivers/staging/lustre/lustre/obdclass/lprocfs_status.c
@@ -45,6 +45,7 @@
#include "../include/lprocfs_status.h"
#include "../include/lustre/lustre_idl.h"
#include <linux/seq_file.h>
+#include <linux/ctype.h>
static const char * const obd_connect_names[] = {
"read_only",
@@ -1849,7 +1850,7 @@ int lprocfs_seq_read_frac_helper(struct seq_file *m, long val, int mult)
}
EXPORT_SYMBOL(lprocfs_seq_read_frac_helper);
-int lprocfs_write_u64_helper(const char *buffer, unsigned long count,
+int lprocfs_write_u64_helper(const char __user *buffer, unsigned long count,
__u64 *val)
{
return lprocfs_write_frac_u64_helper(buffer, count, val, 1);
@@ -1862,6 +1863,7 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
char kernbuf[22], *end, *pbuf;
__u64 whole, frac = 0, units;
unsigned frac_d = 1;
+ int sign = 1;
if (count > (sizeof(kernbuf) - 1))
return -EINVAL;
@@ -1872,7 +1874,7 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
kernbuf[count] = '\0';
pbuf = kernbuf;
if (*pbuf == '-') {
- mult = -mult;
+ sign = -1;
pbuf++;
}
@@ -1880,7 +1882,7 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
if (pbuf == end)
return -EINVAL;
- if (end != NULL && *end == '.') {
+ if (*end == '.') {
int i;
pbuf = end + 1;
@@ -1895,25 +1897,25 @@ int lprocfs_write_frac_u64_helper(const char *buffer, unsigned long count,
}
units = 1;
- switch (*end) {
- case 'p': case 'P':
+ switch (tolower(*end)) {
+ case 'p':
units <<= 10;
- case 't': case 'T':
+ case 't':
units <<= 10;
- case 'g': case 'G':
+ case 'g':
units <<= 10;
- case 'm': case 'M':
+ case 'm':
units <<= 10;
- case 'k': case 'K':
+ case 'k':
units <<= 10;
}
/* Specified units override the multiplier */
- if (units)
- mult = mult < 0 ? -units : units;
+ if (units > 1)
+ mult = units;
frac *= mult;
do_div(frac, frac_d);
- *val = whole * mult + frac;
+ *val = sign * (whole * mult + frac);
return 0;
}
EXPORT_SYMBOL(lprocfs_write_frac_u64_helper);
diff --git a/drivers/staging/lustre/lustre/obdclass/obd_mount.c b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
index 4f39cdee1b5c..3c0c9109cefd 100644
--- a/drivers/staging/lustre/lustre/obdclass/obd_mount.c
+++ b/drivers/staging/lustre/lustre/obdclass/obd_mount.c
@@ -376,6 +376,11 @@ int lustre_start_mgc(struct super_block *sb)
/* Random uuid for MGC allows easier reconnects */
OBD_ALLOC_PTR(uuid);
+ if (!uuid) {
+ rc = -ENOMEM;
+ goto out_free;
+ }
+
ll_generate_random_uuid(uuidc);
class_uuid_unparse(uuidc, uuid);
diff --git a/drivers/staging/lustre/lustre/osc/lproc_osc.c b/drivers/staging/lustre/lustre/osc/lproc_osc.c
index 9f719bcecab3..1795d3a7a029 100644
--- a/drivers/staging/lustre/lustre/osc/lproc_osc.c
+++ b/drivers/staging/lustre/lustre/osc/lproc_osc.c
@@ -53,8 +53,9 @@ static int osc_active_seq_show(struct seq_file *m, void *v)
return rc;
}
-static ssize_t osc_active_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_active_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
int val, rc;
@@ -88,7 +89,8 @@ static int osc_max_rpcs_in_flight_seq_show(struct seq_file *m, void *v)
}
static ssize_t osc_max_rpcs_in_flight_seq_write(struct file *file,
- const char *buffer, size_t count, loff_t *off)
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct client_obd *cli = &dev->u.cli;
@@ -130,8 +132,9 @@ static int osc_max_dirty_mb_seq_show(struct seq_file *m, void *v)
return lprocfs_seq_read_frac_helper(m, val, mult);
}
-static ssize_t osc_max_dirty_mb_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_max_dirty_mb_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct client_obd *cli = &dev->u.cli;
@@ -233,8 +236,9 @@ static int osc_cur_grant_bytes_seq_show(struct seq_file *m, void *v)
return rc;
}
-static ssize_t osc_cur_grant_bytes_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_cur_grant_bytes_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
struct client_obd *cli = &obd->u.cli;
@@ -290,7 +294,8 @@ static int osc_grant_shrink_interval_seq_show(struct seq_file *m, void *v)
}
static ssize_t osc_grant_shrink_interval_seq_write(struct file *file,
- const char *buffer, size_t count, loff_t *off)
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
int val, rc;
@@ -322,8 +327,9 @@ static int osc_checksum_seq_show(struct seq_file *m, void *v)
obd->u.cli.cl_checksum ? 1 : 0);
}
-static ssize_t osc_checksum_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_checksum_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
int val, rc;
@@ -358,11 +364,12 @@ static int osc_checksum_type_seq_show(struct seq_file *m, void *v)
else
seq_printf(m, "%s ", cksum_name[i]);
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
-static ssize_t osc_checksum_type_seq_write(struct file *file, const char *buffer,
+static ssize_t osc_checksum_type_seq_write(struct file *file,
+ const char __user *buffer,
size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -401,8 +408,9 @@ static int osc_resend_count_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%u\n", atomic_read(&obd->u.cli.cl_resends));
}
-static ssize_t osc_resend_count_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_resend_count_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
int val, rc;
@@ -428,8 +436,9 @@ static int osc_contention_seconds_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%u\n", od->od_contention_time);
}
-static ssize_t osc_contention_seconds_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_contention_seconds_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
struct osc_device *od = obd2osc_dev(obd);
@@ -447,8 +456,9 @@ static int osc_lockless_truncate_seq_show(struct seq_file *m, void *v)
return seq_printf(m, "%u\n", od->od_lockless_truncate);
}
-static ssize_t osc_lockless_truncate_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+static ssize_t osc_lockless_truncate_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
struct osc_device *od = obd2osc_dev(obd);
@@ -472,7 +482,8 @@ static int osc_obd_max_pages_per_rpc_seq_show(struct seq_file *m, void *v)
}
static ssize_t osc_obd_max_pages_per_rpc_seq_write(struct file *file,
- const char *buffer, size_t count, loff_t *off)
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct obd_device *dev = ((struct seq_file *)file->private_data)->private;
struct client_obd *cli = &dev->u.cli;
@@ -590,9 +601,9 @@ static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
seq_printf(seq, "pending read pages: %d\n",
atomic_read(&cli->cl_pending_r_pages));
- seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
- seq_printf(seq, "pages per rpc rpcs %% cum %% |");
- seq_printf(seq, " rpcs %% cum %%\n");
+ seq_puts(seq, "\n\t\t\tread\t\t\twrite\n");
+ seq_puts(seq, "pages per rpc rpcs % cum % |");
+ seq_puts(seq, " rpcs % cum %\n");
read_tot = lprocfs_oh_sum(&cli->cl_read_page_hist);
write_tot = lprocfs_oh_sum(&cli->cl_write_page_hist);
@@ -613,9 +624,9 @@ static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
break;
}
- seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
- seq_printf(seq, "rpcs in flight rpcs %% cum %% |");
- seq_printf(seq, " rpcs %% cum %%\n");
+ seq_puts(seq, "\n\t\t\tread\t\t\twrite\n");
+ seq_puts(seq, "rpcs in flight rpcs % cum % |");
+ seq_puts(seq, " rpcs % cum %\n");
read_tot = lprocfs_oh_sum(&cli->cl_read_rpc_hist);
write_tot = lprocfs_oh_sum(&cli->cl_write_rpc_hist);
@@ -636,9 +647,9 @@ static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
break;
}
- seq_printf(seq, "\n\t\t\tread\t\t\twrite\n");
- seq_printf(seq, "offset rpcs %% cum %% |");
- seq_printf(seq, " rpcs %% cum %%\n");
+ seq_puts(seq, "\n\t\t\tread\t\t\twrite\n");
+ seq_puts(seq, "offset rpcs % cum % |");
+ seq_puts(seq, " rpcs % cum %\n");
read_tot = lprocfs_oh_sum(&cli->cl_read_offset_hist);
write_tot = lprocfs_oh_sum(&cli->cl_write_offset_hist);
@@ -664,8 +675,9 @@ static int osc_rpc_stats_seq_show(struct seq_file *seq, void *v)
}
#undef pct
-static ssize_t osc_rpc_stats_seq_write(struct file *file, const char *buf,
- size_t len, loff_t *off)
+static ssize_t osc_rpc_stats_seq_write(struct file *file,
+ const char __user *buf,
+ size_t len, loff_t *off)
{
struct seq_file *seq = file->private_data;
struct obd_device *dev = seq->private;
@@ -702,8 +714,9 @@ static int osc_stats_seq_show(struct seq_file *seq, void *v)
return 0;
}
-static ssize_t osc_stats_seq_write(struct file *file, const char *buf,
- size_t len, loff_t *off)
+static ssize_t osc_stats_seq_write(struct file *file,
+ const char __user *buf,
+ size_t len, loff_t *off)
{
struct seq_file *seq = file->private_data;
struct obd_device *dev = seq->private;
diff --git a/drivers/staging/lustre/lustre/osc/osc_cache.c b/drivers/staging/lustre/lustre/osc/osc_cache.c
index 370e6d4896c6..7022ed42d2d1 100644
--- a/drivers/staging/lustre/lustre/osc/osc_cache.c
+++ b/drivers/staging/lustre/lustre/osc/osc_cache.c
@@ -1820,6 +1820,9 @@ static int try_to_add_extent_for_io(struct client_obd *cli,
int *pc, unsigned int *max_pages)
{
struct osc_extent *tmp;
+ struct osc_async_page *oap = list_first_entry(&ext->oe_pages,
+ struct osc_async_page,
+ oap_pending_item);
EASSERT((ext->oe_state == OES_CACHE || ext->oe_state == OES_LOCK_DONE),
ext);
@@ -1829,6 +1832,10 @@ static int try_to_add_extent_for_io(struct client_obd *cli,
return 0;
list_for_each_entry(tmp, rpclist, oe_link) {
+ struct osc_async_page *oap2;
+
+ oap2 = list_first_entry(&tmp->oe_pages, struct osc_async_page,
+ oap_pending_item);
EASSERT(tmp->oe_owner == current, tmp);
#if 0
if (overlapped(tmp, ext)) {
@@ -1836,6 +1843,11 @@ static int try_to_add_extent_for_io(struct client_obd *cli,
EASSERT(0, ext);
}
#endif
+ if (oap2cl_page(oap)->cp_type != oap2cl_page(oap2)->cp_type) {
+ CDEBUG(D_CACHE, "Do not permit different type of IO"
+ " for a same RPC\n");
+ return 0;
+ }
if (tmp->oe_srvlock != ext->oe_srvlock ||
!tmp->oe_grants != !ext->oe_grants)
diff --git a/drivers/staging/lustre/lustre/osc/osc_internal.h b/drivers/staging/lustre/lustre/osc/osc_internal.h
index d788dac93cd0..af96c7bc7764 100644
--- a/drivers/staging/lustre/lustre/osc/osc_internal.h
+++ b/drivers/staging/lustre/lustre/osc/osc_internal.h
@@ -160,11 +160,6 @@ static inline unsigned long rpcs_in_flight(struct client_obd *cli)
return cli->cl_r_in_flight + cli->cl_w_in_flight;
}
-#ifndef min_t
-#define min_t(type, x, y) \
- ({ type __x = (x); type __y = (y); __x < __y ? __x: __y; })
-#endif
-
struct osc_device {
struct cl_device od_cl;
struct obd_export *od_exp;
diff --git a/drivers/staging/lustre/lustre/osc/osc_lock.c b/drivers/staging/lustre/lustre/osc/osc_lock.c
index a7f08bc48166..445655724904 100644
--- a/drivers/staging/lustre/lustre/osc/osc_lock.c
+++ b/drivers/staging/lustre/lustre/osc/osc_lock.c
@@ -100,14 +100,14 @@ static int osc_lock_invariant(struct osc_lock *ols)
/*
* If all the following "ergo"s are true, return 1, otherwise 0
*/
- if (! ergo(olock != NULL, handle_used))
+ if (!ergo(olock != NULL, handle_used))
return 0;
- if (! ergo(olock != NULL,
+ if (!ergo(olock != NULL,
olock->l_handle.h_cookie == ols->ols_handle.cookie))
return 0;
- if (! ergo(handle_used,
+ if (!ergo(handle_used,
ergo(lock != NULL && olock != NULL, lock == olock) &&
ergo(lock == NULL, olock == NULL)))
return 0;
@@ -115,18 +115,18 @@ static int osc_lock_invariant(struct osc_lock *ols)
* Check that ->ols_handle and ->ols_lock are consistent, but
* take into account that they are set at the different time.
*/
- if (! ergo(ols->ols_state == OLS_CANCELLED,
+ if (!ergo(ols->ols_state == OLS_CANCELLED,
olock == NULL && !handle_used))
return 0;
/*
* DLM lock is destroyed only after we have seen cancellation
* ast.
*/
- if (! ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
+ if (!ergo(olock != NULL && ols->ols_state < OLS_CANCELLED,
((olock->l_flags & LDLM_FL_DESTROYED) == 0)))
return 0;
- if (! ergo(ols->ols_state == OLS_GRANTED,
+ if (!ergo(ols->ols_state == OLS_GRANTED,
olock != NULL &&
olock->l_req_mode == olock->l_granted_mode &&
ols->ols_hold))
diff --git a/drivers/staging/lustre/lustre/osc/osc_request.c b/drivers/staging/lustre/lustre/osc/osc_request.c
index b9450b95f1c5..0adfa707a763 100644
--- a/drivers/staging/lustre/lustre/osc/osc_request.c
+++ b/drivers/staging/lustre/lustre/osc/osc_request.c
@@ -3332,7 +3332,7 @@ extern struct lu_kmem_descr osc_caches[];
extern spinlock_t osc_ast_guard;
extern struct lock_class_key osc_ast_guard_class;
-int __init osc_init(void)
+static int __init osc_init(void)
{
struct lprocfs_static_vars lvars = { NULL };
int rc;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/client.c b/drivers/staging/lustre/lustre/ptlrpc/client.c
index dc9e406f3212..4882dd0a4483 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/client.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/client.c
@@ -1247,7 +1247,9 @@ static int after_reply(struct ptlrpc_request *req)
time_t now = get_seconds();
DEBUG_REQ(D_RPCTRACE, req, "Resending request on EINPROGRESS");
+ spin_lock(&req->rq_lock);
req->rq_resend = 1;
+ spin_unlock(&req->rq_lock);
req->rq_nr_resend++;
/* allocate new xid to avoid reply reconstruction */
@@ -1497,11 +1499,13 @@ static inline int ptlrpc_set_producer(struct ptlrpc_request_set *set)
int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
{
struct list_head *tmp, *next;
+ struct list_head comp_reqs;
int force_timer_recalc = 0;
if (atomic_read(&set->set_remaining) == 0)
return 1;
+ INIT_LIST_HEAD(&comp_reqs);
list_for_each_safe(tmp, next, &set->set_requests) {
struct ptlrpc_request *req =
list_entry(tmp, struct ptlrpc_request,
@@ -1576,8 +1580,10 @@ int ptlrpc_check_set(const struct lu_env *env, struct ptlrpc_request_set *set)
ptlrpc_rqphase_move(req, req->rq_next_phase);
}
- if (req->rq_phase == RQ_PHASE_COMPLETE)
+ if (req->rq_phase == RQ_PHASE_COMPLETE) {
+ list_move_tail(&req->rq_set_chain, &comp_reqs);
continue;
+ }
if (req->rq_phase == RQ_PHASE_INTERPRET)
goto interpret;
@@ -1860,9 +1866,15 @@ interpret:
if (req->rq_status != 0)
set->set_rc = req->rq_status;
ptlrpc_req_finished(req);
+ } else {
+ list_move_tail(&req->rq_set_chain, &comp_reqs);
}
}
+ /* move completed request at the head of list so it's easier for
+ * caller to find them */
+ list_splice(&comp_reqs, &set->set_requests);
+
/* If we hit an error, we want to recover promptly. */
return atomic_read(&set->set_remaining) == 0 || force_timer_recalc;
}
diff --git a/drivers/staging/lustre/lustre/ptlrpc/layout.c b/drivers/staging/lustre/lustre/ptlrpc/layout.c
index dc5ceb55d001..bbef666b1d16 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/layout.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/layout.c
@@ -65,7 +65,6 @@
#endif
/* struct ptlrpc_request, lustre_msg* */
#include "../include/lustre_req_layout.h"
-#include "../include/lustre_update.h"
#include "../include/lustre_acl.h"
#include "../include/lustre_debug.h"
diff --git a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
index 4011e0050fcb..0e2071b8a36e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/lproc_ptlrpc.c
@@ -45,7 +45,7 @@
#include "ptlrpc_internal.h"
-struct ll_rpc_opcode {
+static struct ll_rpc_opcode {
__u32 opcode;
const char *opname;
} ll_rpc_opcode_table[LUSTRE_MAX_OPCODES] = {
@@ -136,7 +136,7 @@ struct ll_rpc_opcode {
{ UPDATE_OBJ, "update_obj" },
};
-struct ll_eopcode {
+static struct ll_eopcode {
__u32 opcode;
const char *opname;
} ll_eopcode_table[EXTRA_LAST_OPC] = {
@@ -175,15 +175,17 @@ const char *ll_opcode2str(__u32 opcode)
return ll_rpc_opcode_table[offset].opname;
}
-const char *ll_eopcode2str(__u32 opcode)
+static const char *ll_eopcode2str(__u32 opcode)
{
LASSERT(ll_eopcode_table[opcode].opcode == opcode);
return ll_eopcode_table[opcode].opname;
}
+
#if defined (CONFIG_PROC_FS)
-void ptlrpc_lprocfs_register(struct proc_dir_entry *root, char *dir,
- char *name, struct proc_dir_entry **procroot_ret,
- struct lprocfs_stats **stats_ret)
+static void ptlrpc_lprocfs_register(struct proc_dir_entry *root, char *dir,
+ char *name,
+ struct proc_dir_entry **procroot_ret,
+ struct lprocfs_stats **stats_ret)
{
struct proc_dir_entry *svc_procroot;
struct lprocfs_stats *svc_stats;
@@ -284,8 +286,9 @@ ptlrpc_lprocfs_req_history_max_seq_show(struct seq_file *m, void *n)
}
static ssize_t
-ptlrpc_lprocfs_req_history_max_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+ptlrpc_lprocfs_req_history_max_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private;
int bufpages;
@@ -329,8 +332,9 @@ ptlrpc_lprocfs_threads_min_seq_show(struct seq_file *m, void *n)
}
static ssize_t
-ptlrpc_lprocfs_threads_min_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+ptlrpc_lprocfs_threads_min_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private;
int val;
@@ -381,8 +385,9 @@ ptlrpc_lprocfs_threads_max_seq_show(struct seq_file *m, void *n)
}
static ssize_t
-ptlrpc_lprocfs_threads_max_seq_write(struct file *file, const char *buffer,
- size_t count, loff_t *off)
+ptlrpc_lprocfs_threads_max_seq_write(struct file *file,
+ const char __user *buffer,
+ size_t count, loff_t *off)
{
struct ptlrpc_service *svc = ((struct seq_file *)file->private_data)->private;
int val;
@@ -723,7 +728,7 @@ struct ptlrpc_srh_iterator {
struct ptlrpc_request *srhi_req;
};
-int
+static int
ptlrpc_lprocfs_svc_req_history_seek(struct ptlrpc_service_part *svcpt,
struct ptlrpc_srh_iterator *srhi,
__u64 seq)
@@ -1025,7 +1030,7 @@ static int ptlrpc_lprocfs_hp_ratio_seq_show(struct seq_file *m, void *v)
}
static ssize_t ptlrpc_lprocfs_hp_ratio_seq_write(struct file *file,
- const char *buffer,
+ const char __user *buffer,
size_t count,
loff_t *off)
{
@@ -1175,7 +1180,7 @@ EXPORT_SYMBOL(ptlrpc_lprocfs_unregister_obd);
#define BUFLEN (UUID_MAX + 5)
-int lprocfs_wr_evict_client(struct file *file, const char *buffer,
+int lprocfs_wr_evict_client(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -1223,7 +1228,7 @@ EXPORT_SYMBOL(lprocfs_wr_evict_client);
#undef BUFLEN
-int lprocfs_wr_ping(struct file *file, const char *buffer,
+int lprocfs_wr_ping(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -1251,7 +1256,7 @@ EXPORT_SYMBOL(lprocfs_wr_ping);
* The connection UUID is a node's primary NID. For example,
* "echo connection=192.168.0.1@tcp0::instance > .../import".
*/
-int lprocfs_wr_import(struct file *file, const char *buffer,
+int lprocfs_wr_import(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
@@ -1329,7 +1334,7 @@ int lprocfs_rd_pinger_recov(struct seq_file *m, void *n)
}
EXPORT_SYMBOL(lprocfs_rd_pinger_recov);
-int lprocfs_wr_pinger_recov(struct file *file, const char *buffer,
+int lprocfs_wr_pinger_recov(struct file *file, const char __user *buffer,
size_t count, loff_t *off)
{
struct obd_device *obd = ((struct seq_file *)file->private_data)->private;
diff --git a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
index cbcc541cac43..4621b71fe0b6 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/ptlrpcd.c
@@ -306,21 +306,16 @@ static int ptlrpcd_check(struct lu_env *env, struct ptlrpcd_ctl *pc)
if (atomic_read(&set->set_remaining))
rc |= ptlrpc_check_set(env, set);
- if (!list_empty(&set->set_requests)) {
- /*
- * XXX: our set never completes, so we prune the completed
- * reqs after each iteration. boy could this be smarter.
- */
- list_for_each_safe(pos, tmp, &set->set_requests) {
- req = list_entry(pos, struct ptlrpc_request,
- rq_set_chain);
- if (req->rq_phase != RQ_PHASE_COMPLETE)
- continue;
+ /* NB: ptlrpc_check_set has already moved completed request at the
+ * head of seq::set_requests */
+ list_for_each_safe(pos, tmp, &set->set_requests) {
+ req = list_entry(pos, struct ptlrpc_request, rq_set_chain);
+ if (req->rq_phase != RQ_PHASE_COMPLETE)
+ break;
- list_del_init(&req->rq_set_chain);
- req->rq_set = NULL;
- ptlrpc_req_finished(req);
- }
+ list_del_init(&req->rq_set_chain);
+ req->rq_set = NULL;
+ ptlrpc_req_finished(req);
}
if (rc == 0) {
diff --git a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
index c500aff66193..81de68edb04e 100644
--- a/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
+++ b/drivers/staging/lustre/lustre/ptlrpc/sec_gc.c
@@ -47,6 +47,8 @@
#include "../include/lustre_net.h"
#include "../include/lustre_sec.h"
+#include "ptlrpc_internal.h"
+
#define SEC_GC_INTERVAL (30 * 60)
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 2a054a99d433..96498b7fc20e 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -27,18 +27,12 @@ source "drivers/staging/media/davinci_vpfe/Kconfig"
source "drivers/staging/media/dt3155v4l/Kconfig"
-source "drivers/staging/media/tlg2300/Kconfig"
-
source "drivers/staging/media/mn88472/Kconfig"
source "drivers/staging/media/mn88473/Kconfig"
source "drivers/staging/media/omap4iss/Kconfig"
-source "drivers/staging/media/parport/Kconfig"
-
-source "drivers/staging/media/vino/Kconfig"
-
# Keep LIRC at the end, as it has sub-menus
source "drivers/staging/media/lirc/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 412b28408398..a9006bcb4472 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -6,7 +6,3 @@ obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
obj-$(CONFIG_DVB_MN88472) += mn88472/
obj-$(CONFIG_DVB_MN88473) += mn88473/
-obj-y += parport/
-obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
-obj-y += vino/
-
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index 60a57b2a8fb2..538250667918 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -2684,9 +2684,7 @@ static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client)
vd = bdev->videodev;
bcm2048_sysfs_unregister_properties(bdev, ARRAY_SIZE(attrs));
-
- if (vd)
- video_unregister_device(vd);
+ video_unregister_device(vd);
if (bdev->power_state)
bcm2048_set_power_state(bdev, BCM2048_POWER_OFF);
@@ -2699,8 +2697,6 @@ static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client)
kfree(bdev);
}
- i2c_set_clientdata(client, NULL);
-
return 0;
}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index 704fa202ee18..a425f71dfb97 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -901,7 +901,7 @@ static int ipipe_set_gbce_params(struct vpfe_ipipe_device *ipipe, void *param)
struct device *dev = ipipe->subdev.v4l2_dev->dev;
if (!gbce_param) {
- memset(gbce, 0 , sizeof(struct vpfe_ipipe_gbce));
+ memset(gbce, 0, sizeof(struct vpfe_ipipe_gbce));
} else {
memcpy(gbce, gbce_param, sizeof(struct vpfe_ipipe_gbce));
if (ipipe_validate_gbce_params(gbce) < 0) {
@@ -1086,7 +1086,7 @@ static int ipipe_set_car_params(struct vpfe_ipipe_device *ipipe, void *param)
struct vpfe_ipipe_car *car = &ipipe->config.car;
if (!car_param) {
- memset(car , 0, sizeof(struct vpfe_ipipe_car));
+ memset(car, 0, sizeof(struct vpfe_ipipe_car));
} else {
memcpy(car, car_param, sizeof(struct vpfe_ipipe_car));
if (ipipe_validate_car_params(car) < 0) {
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index 0ba0bf2c1cff..bcf762bc233d 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -1535,7 +1535,7 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
/*
- * isif_pad_set_crop() - set crop rectangle on pad
+ * isif_pad_set_selection() - set crop rectangle on pad
* @sd: VPFE isif V4L2 subdevice
* @fh: V4L2 subdev file handle
* @code: pointer to v4l2_subdev_mbus_code_enum structure
@@ -1543,35 +1543,36 @@ isif_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
* Return 0 on success, -EINVAL if pad is invalid
*/
static int
-isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+isif_pad_set_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *format;
- /* check wether its a valid pad */
- if (crop->pad != ISIF_PAD_SINK)
+ /* check whether it's a valid pad and target */
+ if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- format = __isif_get_format(vpfe_isif, fh, crop->pad, crop->which);
+ format = __isif_get_format(vpfe_isif, fh, sel->pad, sel->which);
if (format == NULL)
return -EINVAL;
/* check wether crop rect is within limits */
- if (crop->rect.top < 0 || crop->rect.left < 0 ||
- (crop->rect.left + crop->rect.width >
+ if (sel->r.top < 0 || sel->r.left < 0 ||
+ (sel->r.left + sel->r.width >
vpfe_isif->formats[ISIF_PAD_SINK].width) ||
- (crop->rect.top + crop->rect.height >
+ (sel->r.top + sel->r.height >
vpfe_isif->formats[ISIF_PAD_SINK].height)) {
- crop->rect.left = 0;
- crop->rect.top = 0;
- crop->rect.width = format->width;
- crop->rect.height = format->height;
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = format->width;
+ sel->r.height = format->height;
}
/* adjust the width to 16 pixel boundary */
- crop->rect.width = ((crop->rect.width + 15) & ~0xf);
- vpfe_isif->crop = crop->rect;
- if (crop->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
+ sel->r.width = ((sel->r.width + 15) & ~0xf);
+ vpfe_isif->crop = sel->r;
+ if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
isif_set_image_window(vpfe_isif);
} else {
struct v4l2_rect *rect;
@@ -1583,7 +1584,7 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
/*
- * isif_pad_get_crop() - get crop rectangle on pad
+ * isif_pad_get_selection() - get crop rectangle on pad
* @sd: VPFE isif V4L2 subdevice
* @fh: V4L2 subdev file handle
* @code: pointer to v4l2_subdev_mbus_code_enum structure
@@ -1591,22 +1592,23 @@ isif_pad_set_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
* Return 0 on success, -EINVAL if pad is invalid
*/
static int
-isif_pad_get_crop(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_crop *crop)
+isif_pad_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_selection *sel)
{
struct vpfe_isif_device *vpfe_isif = v4l2_get_subdevdata(sd);
- /* check wether its a valid pad */
- if (crop->pad != ISIF_PAD_SINK)
+ /* check whether it's a valid pad and target */
+ if (sel->pad != ISIF_PAD_SINK || sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- if (crop->which == V4L2_SUBDEV_FORMAT_TRY) {
+ if (sel->which == V4L2_SUBDEV_FORMAT_TRY) {
struct v4l2_rect *rect;
rect = v4l2_subdev_get_try_crop(fh, ISIF_PAD_SINK);
- memcpy(&crop->rect, rect, sizeof(*rect));
+ memcpy(&sel->r, rect, sizeof(*rect));
} else {
- crop->rect = vpfe_isif->crop;
+ sel->r = vpfe_isif->crop;
}
return 0;
@@ -1626,7 +1628,7 @@ isif_init_formats(struct v4l2_subdev *sd,
struct v4l2_subdev_fh *fh)
{
struct v4l2_subdev_format format;
- struct v4l2_subdev_crop crop;
+ struct v4l2_subdev_selection sel;
memset(&format, 0, sizeof(format));
format.pad = ISIF_PAD_SINK;
@@ -1644,12 +1646,13 @@ isif_init_formats(struct v4l2_subdev *sd,
format.format.height = MAX_HEIGHT;
isif_set_format(sd, fh, &format);
- memset(&crop, 0, sizeof(crop));
- crop.pad = ISIF_PAD_SINK;
- crop.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- crop.rect.width = MAX_WIDTH;
- crop.rect.height = MAX_HEIGHT;
- isif_pad_set_crop(sd, fh, &crop);
+ memset(&sel, 0, sizeof(sel));
+ sel.pad = ISIF_PAD_SINK;
+ sel.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+ sel.target = V4L2_SEL_TGT_CROP;
+ sel.r.width = MAX_WIDTH;
+ sel.r.height = MAX_HEIGHT;
+ isif_pad_set_selection(sd, fh, &sel);
return 0;
}
@@ -1675,8 +1678,8 @@ static const struct v4l2_subdev_pad_ops isif_v4l2_pad_ops = {
.enum_frame_size = isif_enum_frame_size,
.get_fmt = isif_get_format,
.set_fmt = isif_set_format,
- .set_crop = isif_pad_set_crop,
- .get_crop = isif_pad_get_crop,
+ .set_selection = isif_pad_set_selection,
+ .get_selection = isif_pad_get_selection,
};
/* subdev operations */
diff --git a/drivers/staging/media/lirc/lirc_serial.c b/drivers/staging/media/lirc/lirc_serial.c
index eb4ccb8d2a93..19628d0104ab 100644
--- a/drivers/staging/media/lirc/lirc_serial.c
+++ b/drivers/staging/media/lirc/lirc_serial.c
@@ -107,7 +107,7 @@ static int io;
static int irq;
static bool iommap;
static int ioshift;
-static bool softcarrier = 1;
+static bool softcarrier = true;
static bool share_irq;
static bool debug;
static int sense = -1; /* -1 = auto, 0 = active high, 1 = active low */
@@ -266,7 +266,7 @@ static unsigned long space_width;
/* fetch serial input packet (1 byte) from register offset */
static u8 sinp(int offset)
{
- if (iommap != 0)
+ if (iommap)
/* the register is memory-mapped */
offset <<= ioshift;
@@ -276,7 +276,7 @@ static u8 sinp(int offset)
/* write serial output packet (1 byte) of value to register offset */
static void soutp(int offset, u8 value)
{
- if (iommap != 0)
+ if (iommap)
/* the register is memory-mapped */
offset <<= ioshift;
@@ -799,10 +799,10 @@ static int lirc_serial_probe(struct platform_device *dev)
* For memory mapped I/O you *might* need to use ioremap() first,
* for the NSLU2 it's done in boot code.
*/
- if (((iommap != 0)
+ if (((iommap)
&& (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift,
LIRC_DRIVER_NAME) == NULL))
- || ((iommap == 0)
+ || ((!iommap)
&& (devm_request_region(&dev->dev, io, 8,
LIRC_DRIVER_NAME) == NULL))) {
dev_err(&dev->dev, "port %04x already in use\n", io);
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
index cc872fb4ca68..e16627ca488e 100644
--- a/drivers/staging/media/lirc/lirc_zilog.c
+++ b/drivers/staging/media/lirc/lirc_zilog.c
@@ -369,17 +369,17 @@ static int add_to_buf(struct IR *ir)
ret = i2c_master_send(rx->c, sendbuf, 1);
if (ret != 1) {
dev_err(ir->l.dev, "i2c_master_send failed with %d\n",
- ret);
+ ret);
if (failures >= 3) {
mutex_unlock(&ir->ir_lock);
- dev_err(ir->l.dev, "unable to read from the IR chip "
- "after 3 resets, giving up\n");
+ dev_err(ir->l.dev,
+ "unable to read from the IR chip after 3 resets, giving up\n");
break;
}
/* Looks like the chip crashed, reset it */
- dev_err(ir->l.dev, "polling the IR receiver chip failed, "
- "trying reset\n");
+ dev_err(ir->l.dev,
+ "polling the IR receiver chip failed, trying reset\n");
set_current_state(TASK_UNINTERRUPTIBLE);
if (kthread_should_stop()) {
@@ -405,14 +405,16 @@ static int add_to_buf(struct IR *ir)
ret = i2c_master_recv(rx->c, keybuf, sizeof(keybuf));
mutex_unlock(&ir->ir_lock);
if (ret != sizeof(keybuf)) {
- dev_err(ir->l.dev, "i2c_master_recv failed with %d -- "
- "keeping last read buffer\n", ret);
+ dev_err(ir->l.dev,
+ "i2c_master_recv failed with %d -- keeping last read buffer\n",
+ ret);
} else {
rx->b[0] = keybuf[3];
rx->b[1] = keybuf[4];
rx->b[2] = keybuf[5];
- dev_dbg(ir->l.dev, "key (0x%02x/0x%02x)\n",
- rx->b[0], rx->b[1]);
+ dev_dbg(ir->l.dev,
+ "key (0x%02x/0x%02x)\n",
+ rx->b[0], rx->b[1]);
}
/* key pressed ? */
@@ -656,8 +658,8 @@ static int send_data_block(struct IR_tx *tx, unsigned char *data_block)
dev_dbg(tx->ir->l.dev, "%*ph", 5, buf);
ret = i2c_master_send(tx->c, buf, tosend + 1);
if (ret != tosend + 1) {
- dev_err(tx->ir->l.dev, "i2c_master_send failed with %d\n",
- ret);
+ dev_err(tx->ir->l.dev,
+ "i2c_master_send failed with %d\n", ret);
return ret < 0 ? ret : -EFAULT;
}
i += tosend;
@@ -710,11 +712,12 @@ static int send_boot_data(struct IR_tx *tx)
}
if ((buf[0] != 0x80) && (buf[0] != 0xa0)) {
dev_err(tx->ir->l.dev, "unexpected IR TX init response: %02x\n",
- buf[0]);
+ buf[0]);
return 0;
}
- dev_notice(tx->ir->l.dev, "Zilog/Hauppauge IR blaster firmware version "
- "%d.%d.%d loaded\n", buf[1], buf[2], buf[3]);
+ dev_notice(tx->ir->l.dev,
+ "Zilog/Hauppauge IR blaster firmware version %d.%d.%d loaded\n",
+ buf[1], buf[2], buf[3]);
return 0;
}
@@ -759,8 +762,9 @@ static int fw_load(struct IR_tx *tx)
/* Request codeset data file */
ret = request_firmware(&fw_entry, "haup-ir-blaster.bin", tx->ir->l.dev);
if (ret != 0) {
- dev_err(tx->ir->l.dev, "firmware haup-ir-blaster.bin not available (%d)\n",
- ret);
+ dev_err(tx->ir->l.dev,
+ "firmware haup-ir-blaster.bin not available (%d)\n",
+ ret);
ret = ret < 0 ? ret : -EFAULT;
goto out;
}
@@ -792,9 +796,9 @@ static int fw_load(struct IR_tx *tx)
if (!read_uint8(&data, tx_data->endp, &version))
goto corrupt;
if (version != 1) {
- dev_err(tx->ir->l.dev, "unsupported code set file version (%u, expected"
- "1) -- please upgrade to a newer driver",
- version);
+ dev_err(tx->ir->l.dev,
+ "unsupported code set file version (%u, expected 1) -- please upgrade to a newer driver\n",
+ version);
fw_unload_locked();
ret = -EFAULT;
goto out;
@@ -810,7 +814,7 @@ static int fw_load(struct IR_tx *tx)
goto corrupt;
dev_dbg(tx->ir->l.dev, "%u IR blaster codesets loaded\n",
- tx_data->num_code_sets);
+ tx_data->num_code_sets);
tx_data->code_sets = vmalloc(
tx_data->num_code_sets * sizeof(char *));
@@ -940,8 +944,9 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n,
unsigned char buf[MAX_XFER_SIZE];
if (rbuf->chunk_size > sizeof(buf)) {
- dev_err(ir->l.dev, "chunk_size is too big (%d)!\n",
- rbuf->chunk_size);
+ dev_err(ir->l.dev,
+ "chunk_size is too big (%d)!\n",
+ rbuf->chunk_size);
ret = -EINVAL;
break;
}
@@ -964,8 +969,8 @@ static ssize_t read(struct file *filep, char __user *outbuf, size_t n,
put_ir_rx(rx, false);
set_current_state(TASK_RUNNING);
- dev_dbg(ir->l.dev, "read result = %d (%s)\n",
- ret, ret ? "Error" : "OK");
+ dev_dbg(ir->l.dev, "read result = %d (%s)\n", ret,
+ ret ? "Error" : "OK");
return ret ? ret : written;
}
@@ -981,8 +986,9 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
ret = get_key_data(data_block, code, key);
if (ret == -EPROTO) {
- dev_err(tx->ir->l.dev, "failed to get data for code %u, key %u -- check "
- "lircd.conf entries\n", code, key);
+ dev_err(tx->ir->l.dev,
+ "failed to get data for code %u, key %u -- check lircd.conf entries\n",
+ code, key);
return ret;
} else if (ret != 0)
return ret;
@@ -1057,12 +1063,14 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
ret = i2c_master_send(tx->c, buf, 1);
if (ret == 1)
break;
- dev_dbg(tx->ir->l.dev, "NAK expected: i2c_master_send "
- "failed with %d (try %d)\n", ret, i+1);
+ dev_dbg(tx->ir->l.dev,
+ "NAK expected: i2c_master_send failed with %d (try %d)\n",
+ ret, i+1);
}
if (ret != 1) {
- dev_err(tx->ir->l.dev, "IR TX chip never got ready: last i2c_master_send "
- "failed with %d\n", ret);
+ dev_err(tx->ir->l.dev,
+ "IR TX chip never got ready: last i2c_master_send failed with %d\n",
+ ret);
return ret < 0 ? ret : -EFAULT;
}
@@ -1074,7 +1082,7 @@ static int send_code(struct IR_tx *tx, unsigned int code, unsigned int key)
}
if (buf[0] != 0x80) {
dev_err(tx->ir->l.dev, "unexpected IR TX response #2: %02x\n",
- buf[0]);
+ buf[0]);
return -EFAULT;
}
@@ -1165,12 +1173,12 @@ static ssize_t write(struct file *filep, const char __user *buf, size_t n,
*/
if (ret != 0) {
/* Looks like the chip crashed, reset it */
- dev_err(tx->ir->l.dev, "sending to the IR transmitter chip "
- "failed, trying reset\n");
+ dev_err(tx->ir->l.dev,
+ "sending to the IR transmitter chip failed, trying reset\n");
if (failures >= 3) {
- dev_err(tx->ir->l.dev, "unable to send to the IR chip "
- "after 3 resets, giving up\n");
+ dev_err(tx->ir->l.dev,
+ "unable to send to the IR chip after 3 resets, giving up\n");
mutex_unlock(&ir->ir_lock);
mutex_unlock(&tx->client_lock);
put_ir_tx(tx, false);
@@ -1226,7 +1234,7 @@ static unsigned int poll(struct file *filep, poll_table *wait)
ret = lirc_buffer_empty(rbuf) ? 0 : (POLLIN|POLLRDNORM);
dev_dbg(ir->l.dev, "poll result = %s\n",
- ret ? "POLLIN|POLLRDNORM" : "none");
+ ret ? "POLLIN|POLLRDNORM" : "none");
return ret;
}
@@ -1333,7 +1341,8 @@ static int close(struct inode *node, struct file *filep)
struct IR *ir = filep->private_data;
if (ir == NULL) {
- dev_err(ir->l.dev, "close: no private_data attached to the file!\n");
+ dev_err(ir->l.dev,
+ "close: no private_data attached to the file!\n");
return -ENODEV;
}
@@ -1540,8 +1549,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Proceed only if the Rx client is also ready or not needed */
if (rx == NULL && !tx_only) {
- dev_info(tx->ir->l.dev, "probe of IR Tx on %s (i2c-%d) done. Waiting"
- " on IR Rx.\n", adap->name, adap->nr);
+ dev_info(tx->ir->l.dev,
+ "probe of IR Tx on %s (i2c-%d) done. Waiting on IR Rx.\n",
+ adap->name, adap->nr);
goto out_ok;
}
} else {
@@ -1579,8 +1589,9 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
"zilog-rx-i2c-%d", adap->nr);
if (IS_ERR(rx->task)) {
ret = PTR_ERR(rx->task);
- dev_err(tx->ir->l.dev, "%s: could not start IR Rx polling thread"
- "\n", __func__);
+ dev_err(tx->ir->l.dev,
+ "%s: could not start IR Rx polling thread\n",
+ __func__);
/* Failed kthread, so put back the ir ref */
put_ir_device(ir, true);
/* Failure exit, so put back rx ref from i2c_client */
@@ -1592,8 +1603,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
/* Proceed only if the Tx client is also ready */
if (tx == NULL) {
- pr_info("probe of IR Rx on %s (i2c-%d) done. Waiting"
- " on IR Tx.\n", adap->name, adap->nr);
+ pr_info("probe of IR Rx on %s (i2c-%d) done. Waiting on IR Tx.\n",
+ adap->name, adap->nr);
goto out_ok;
}
}
@@ -1602,13 +1613,15 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
ir->l.minor = minor; /* module option: user requested minor number */
ir->l.minor = lirc_register_driver(&ir->l);
if (ir->l.minor < 0 || ir->l.minor >= MAX_IRCTL_DEVICES) {
- dev_err(tx->ir->l.dev, "%s: \"minor\" must be between 0 and %d (%d)!\n",
- __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
+ dev_err(tx->ir->l.dev,
+ "%s: \"minor\" must be between 0 and %d (%d)!\n",
+ __func__, MAX_IRCTL_DEVICES-1, ir->l.minor);
ret = -EBADRQC;
goto out_put_xx;
}
- dev_info(ir->l.dev, "IR unit on %s (i2c-%d) registered as lirc%d and ready\n",
- adap->name, adap->nr, ir->l.minor);
+ dev_info(ir->l.dev,
+ "IR unit on %s (i2c-%d) registered as lirc%d and ready\n",
+ adap->name, adap->nr, ir->l.minor);
out_ok:
if (rx != NULL)
@@ -1616,8 +1629,9 @@ out_ok:
if (tx != NULL)
put_ir_tx(tx, true);
put_ir_device(ir, true);
- dev_info(ir->l.dev, "probe of IR %s on %s (i2c-%d) done\n",
- tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
+ dev_info(ir->l.dev,
+ "probe of IR %s on %s (i2c-%d) done\n",
+ tx_probe ? "Tx" : "Rx", adap->name, adap->nr);
mutex_unlock(&ir_devices_lock);
return 0;
@@ -1629,9 +1643,9 @@ out_put_xx:
out_put_ir:
put_ir_device(ir, true);
out_no_ir:
- dev_err(&client->dev, "%s: probing IR %s on %s (i2c-%d) failed with %d\n",
- __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr,
- ret);
+ dev_err(&client->dev,
+ "%s: probing IR %s on %s (i2c-%d) failed with %d\n",
+ __func__, tx_probe ? "Tx" : "Rx", adap->name, adap->nr, ret);
mutex_unlock(&ir_devices_lock);
return ret;
}
diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c
index 52de8f85d36c..6eebe564e557 100644
--- a/drivers/staging/media/mn88472/mn88472.c
+++ b/drivers/staging/media/mn88472/mn88472.c
@@ -30,6 +30,7 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, i;
u32 if_frequency = 0;
+ u64 tmp;
u8 delivery_system_val, if_val[3], bw_val[7], bw_val2;
dev_dbg(&client->dev,
@@ -57,36 +58,22 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
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);
+ if (c->bandwidth_hz <= 5000000) {
+ memcpy(bw_val, "\xe5\x99\x9a\x1b\xa9\x1b\xa9", 7);
+ bw_val2 = 0x03;
+ } else if (c->bandwidth_hz <= 6000000) {
+ /* IF 3570000 Hz, BW 6000000 Hz */
+ 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(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(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7);
bw_val2 = 0x00;
- break;
- default:
+ } else {
ret = -EINVAL;
goto err;
}
@@ -106,17 +93,12 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
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;
- }
+ /* Calculate IF registers ( (1<<24)*IF / Xtal ) */
+ tmp = div_u64(if_frequency * (u64)(1<<24) + (dev->xtal / 2),
+ dev->xtal);
+ if_val[0] = ((tmp >> 16) & 0xff);
+ if_val[1] = ((tmp >> 8) & 0xff);
+ if_val[2] = ((tmp >> 0) & 0xff);
ret = regmap_write(dev->regmap[2], 0xfb, 0x13);
ret = regmap_write(dev->regmap[2], 0xef, 0x13);
@@ -198,6 +180,8 @@ static int mn88472_set_frontend(struct dvb_frontend *fe)
ret = regmap_write(dev->regmap[0], 0xae, 0x00);
ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
ret = regmap_write(dev->regmap[0], 0xd9, 0xe3);
+
+ /* Reset demod */
ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
if (ret)
goto err;
@@ -411,6 +395,7 @@ static int mn88472_probe(struct i2c_client *client,
}
dev->i2c_wr_max = config->i2c_wr_max;
+ dev->xtal = config->xtal;
dev->client[0] = client;
dev->regmap[0] = regmap_init_i2c(dev->client[0], &regmap_config);
if (IS_ERR(dev->regmap[0])) {
diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h
index 1095949f040d..b12b731e2d4e 100644
--- a/drivers/staging/media/mn88472/mn88472_priv.h
+++ b/drivers/staging/media/mn88472/mn88472_priv.h
@@ -31,6 +31,7 @@ struct mn88472_dev {
u16 i2c_wr_max;
fe_delivery_system_t delivery_system;
bool warm; /* FW running */
+ u32 xtal;
};
#endif
diff --git a/drivers/staging/media/omap4iss/iss.c b/drivers/staging/media/omap4iss/iss.c
index cc1dfadd91eb..44b81a2c8b6f 100644
--- a/drivers/staging/media/omap4iss/iss.c
+++ b/drivers/staging/media/omap4iss/iss.c
@@ -560,41 +560,28 @@ static int iss_pipeline_link_notify(struct media_link *link, u32 flags,
*/
/*
- * iss_pipeline_enable - Enable streaming on a pipeline
+ * iss_pipeline_disable - Disable streaming on a pipeline
* @pipe: ISS pipeline
- * @mode: Stream mode (single shot or continuous)
+ * @until: entity at which to stop pipeline walk
*
- * Walk the entities chain starting at the pipeline output video node and start
- * all modules in the chain in the given mode.
+ * Walk the entities chain starting at the pipeline output video node and stop
+ * all modules in the chain. Wait synchronously for the modules to be stopped if
+ * necessary.
*
- * Return 0 if successful, or the return value of the failed video::s_stream
- * operation otherwise.
+ * If the until argument isn't NULL, stop the pipeline walk when reaching the
+ * until entity. This is used to disable a partially started pipeline due to a
+ * subdev start error.
*/
-static int iss_pipeline_enable(struct iss_pipeline *pipe,
- enum iss_pipeline_stream_state mode)
+static int iss_pipeline_disable(struct iss_pipeline *pipe,
+ struct media_entity *until)
{
struct iss_device *iss = pipe->output->iss;
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
- unsigned long flags;
+ int failure = 0;
int ret;
- /* If one of the entities in the pipeline has crashed it will not work
- * properly. Refuse to start streaming in that case. This check must be
- * performed before the loop below to avoid starting entities if the
- * pipeline won't start anyway (those entities would then likely fail to
- * stop, making the problem worse).
- */
- if (pipe->entities & iss->crashed)
- return -EIO;
-
- spin_lock_irqsave(&pipe->lock, flags);
- pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
- spin_unlock_irqrestore(&pipe->lock, flags);
-
- pipe->do_propagation = false;
-
entity = &pipe->output->video.entity;
while (1) {
pad = &entity->pads[0];
@@ -607,33 +594,62 @@ static int iss_pipeline_enable(struct iss_pipeline *pipe,
break;
entity = pad->entity;
- subdev = media_entity_to_v4l2_subdev(entity);
+ if (entity == until)
+ break;
- ret = v4l2_subdev_call(subdev, video, s_stream, mode);
- if (ret < 0 && ret != -ENOIOCTLCMD)
- return ret;
+ subdev = media_entity_to_v4l2_subdev(entity);
+ ret = v4l2_subdev_call(subdev, video, s_stream, 0);
+ if (ret < 0) {
+ dev_dbg(iss->dev, "%s: module stop timeout.\n",
+ subdev->name);
+ /* If the entity failed to stopped, assume it has
+ * crashed. Mark it as such, the ISS will be reset when
+ * applications will release it.
+ */
+ iss->crashed |= 1U << subdev->entity.id;
+ failure = -ETIMEDOUT;
+ }
}
- iss_print_status(pipe->output->iss);
- return 0;
+
+ return failure;
}
/*
- * iss_pipeline_disable - Disable streaming on a pipeline
+ * iss_pipeline_enable - Enable streaming on a pipeline
* @pipe: ISS pipeline
+ * @mode: Stream mode (single shot or continuous)
*
- * Walk the entities chain starting at the pipeline output video node and stop
- * all modules in the chain. Wait synchronously for the modules to be stopped if
- * necessary.
+ * Walk the entities chain starting at the pipeline output video node and start
+ * all modules in the chain in the given mode.
+ *
+ * Return 0 if successful, or the return value of the failed video::s_stream
+ * operation otherwise.
*/
-static int iss_pipeline_disable(struct iss_pipeline *pipe)
+static int iss_pipeline_enable(struct iss_pipeline *pipe,
+ enum iss_pipeline_stream_state mode)
{
struct iss_device *iss = pipe->output->iss;
struct media_entity *entity;
struct media_pad *pad;
struct v4l2_subdev *subdev;
- int failure = 0;
+ unsigned long flags;
int ret;
+ /* If one of the entities in the pipeline has crashed it will not work
+ * properly. Refuse to start streaming in that case. This check must be
+ * performed before the loop below to avoid starting entities if the
+ * pipeline won't start anyway (those entities would then likely fail to
+ * stop, making the problem worse).
+ */
+ if (pipe->entities & iss->crashed)
+ return -EIO;
+
+ spin_lock_irqsave(&pipe->lock, flags);
+ pipe->state &= ~(ISS_PIPELINE_IDLE_INPUT | ISS_PIPELINE_IDLE_OUTPUT);
+ spin_unlock_irqrestore(&pipe->lock, flags);
+
+ pipe->do_propagation = false;
+
entity = &pipe->output->video.entity;
while (1) {
pad = &entity->pads[0];
@@ -648,20 +664,19 @@ static int iss_pipeline_disable(struct iss_pipeline *pipe)
entity = pad->entity;
subdev = media_entity_to_v4l2_subdev(entity);
- ret = v4l2_subdev_call(subdev, video, s_stream, 0);
- if (ret < 0) {
- dev_dbg(iss->dev, "%s: module stop timeout.\n",
- subdev->name);
- /* If the entity failed to stopped, assume it has
- * crashed. Mark it as such, the ISS will be reset when
- * applications will release it.
- */
- iss->crashed |= 1U << subdev->entity.id;
- failure = -ETIMEDOUT;
+ ret = v4l2_subdev_call(subdev, video, s_stream, mode);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ iss_pipeline_disable(pipe, entity);
+ return ret;
}
+
+ if (subdev == &iss->csi2a.subdev ||
+ subdev == &iss->csi2b.subdev)
+ pipe->do_propagation = true;
}
- return failure;
+ iss_print_status(pipe->output->iss);
+ return 0;
}
/*
@@ -682,7 +697,7 @@ int omap4iss_pipeline_set_stream(struct iss_pipeline *pipe,
int ret;
if (state == ISS_PIPELINE_STREAM_STOPPED)
- ret = iss_pipeline_disable(pipe);
+ ret = iss_pipeline_disable(pipe, NULL);
else
ret = iss_pipeline_enable(pipe, state);
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index 21971c675b8c..2d96fb3eca53 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -319,6 +319,8 @@ static void csi2_ctx_config(struct iss_csi2_device *csi2,
{
u32 reg = 0;
+ ctx->frame = 0;
+
/* Set up CSI2_CTx_CTRL1 */
if (ctx->eof_enabled)
reg = CSI2_CTX_CTRL1_EOF_EN;
@@ -396,21 +398,18 @@ static void csi2_timing_config(struct iss_csi2_device *csi2,
*/
static void csi2_irq_ctx_set(struct iss_csi2_device *csi2, int enable)
{
- u32 reg = CSI2_CTX_IRQ_FE;
+ const u32 mask = CSI2_CTX_IRQ_FE | CSI2_CTX_IRQ_FS;
int i;
- if (csi2->use_fs_irq)
- reg |= CSI2_CTX_IRQ_FS;
-
for (i = 0; i < 8; i++) {
iss_reg_write(csi2->iss, csi2->regs1, CSI2_CTX_IRQSTATUS(i),
- reg);
+ mask);
if (enable)
iss_reg_set(csi2->iss, csi2->regs1,
- CSI2_CTX_IRQENABLE(i), reg);
+ CSI2_CTX_IRQENABLE(i), mask);
else
iss_reg_clr(csi2->iss, csi2->regs1,
- CSI2_CTX_IRQENABLE(i), reg);
+ CSI2_CTX_IRQENABLE(i), mask);
}
}
@@ -679,8 +678,34 @@ static void csi2_isr_ctx(struct iss_csi2_device *csi2,
if (status & CSI2_CTX_IRQ_FS) {
struct iss_pipeline *pipe =
to_iss_pipeline(&csi2->subdev.entity);
- if (pipe->do_propagation)
+ u16 frame;
+ u16 delta;
+
+ frame = iss_reg_read(csi2->iss, csi2->regs1,
+ CSI2_CTX_CTRL2(ctx->ctxnum))
+ >> CSI2_CTX_CTRL2_FRAME_SHIFT;
+
+ if (frame == 0) {
+ /* A zero value means that the counter isn't implemented
+ * by the source. Increment the frame number in software
+ * in that case.
+ */
atomic_inc(&pipe->frame_number);
+ } else {
+ /* Extend the 16 bit frame number to 32 bits by
+ * computing the delta between two consecutive CSI2
+ * frame numbers and adding it to the software frame
+ * number. The hardware counter starts at 1 and wraps
+ * from 0xffff to 1 without going through 0, so subtract
+ * 1 when the counter wraps.
+ */
+ delta = frame - ctx->frame;
+ if (frame < ctx->frame)
+ delta--;
+ ctx->frame = frame;
+
+ atomic_add(delta, &pipe->frame_number);
+ }
}
if (!(status & CSI2_CTX_IRQ_FE))
@@ -1039,7 +1064,6 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
{
struct iss_csi2_device *csi2 = v4l2_get_subdevdata(sd);
struct iss_device *iss = csi2->iss;
- struct iss_pipeline *pipe = to_iss_pipeline(&csi2->subdev.entity);
struct iss_video *video_out = &csi2->video_out;
int ret = 0;
@@ -1058,7 +1082,6 @@ static int csi2_set_stream(struct v4l2_subdev *sd, int enable)
if (omap4iss_csiphy_acquire(csi2->phy) < 0)
return -ENODEV;
- csi2->use_fs_irq = pipe->do_propagation;
csi2_configure(csi2);
csi2_print_status(csi2);
diff --git a/drivers/staging/media/omap4iss/iss_csi2.h b/drivers/staging/media/omap4iss/iss_csi2.h
index 971aa7b08013..3b37978a3bdf 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.h
+++ b/drivers/staging/media/omap4iss/iss_csi2.h
@@ -82,6 +82,7 @@ struct iss_csi2_ctx_cfg {
u8 virtual_id;
u16 format_id; /* as in CSI2_CTx_CTRL2[9:0] */
u8 dpcm_predictor; /* 1: simple, 0: advanced */
+ u16 frame;
/* Fields in CSI2_CTx_CTRL1/3 - Shadowed */
u16 alpha;
@@ -137,7 +138,6 @@ struct iss_csi2_device {
u32 output; /* output to IPIPEIF, memory or both? */
bool dpcm_decompress;
unsigned int frame_skip;
- bool use_fs_irq;
struct iss_csiphy *phy;
struct iss_csi2_ctx_cfg contexts[ISS_CSI2_MAX_CTX_NUM + 1];
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
index 32a748398ced..3943fae699ee 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.c
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.c
@@ -242,23 +242,6 @@ static void ipipeif_isr_buffer(struct iss_ipipeif_device *ipipeif)
}
/*
- * ipipeif_isif0_isr - Handle ISIF0 event
- * @ipipeif: Pointer to ISP IPIPEIF device.
- *
- * Executes LSC deferred enablement before next frame starts.
- */
-static void ipipeif_isif0_isr(struct iss_ipipeif_device *ipipeif)
-{
- struct iss_pipeline *pipe =
- to_iss_pipeline(&ipipeif->subdev.entity);
- if (pipe->do_propagation)
- atomic_inc(&pipe->frame_number);
-
- if (ipipeif->output & IPIPEIF_OUTPUT_MEMORY)
- ipipeif_isr_buffer(ipipeif);
-}
-
-/*
* omap4iss_ipipeif_isr - Configure ipipeif during interframe time.
* @ipipeif: Pointer to ISP IPIPEIF device.
* @events: IPIPEIF events
@@ -269,8 +252,9 @@ void omap4iss_ipipeif_isr(struct iss_ipipeif_device *ipipeif, u32 events)
&ipipeif->stopping))
return;
- if (events & ISP5_IRQ_ISIF_INT(0))
- ipipeif_isif0_isr(ipipeif);
+ if ((events & ISP5_IRQ_ISIF_INT(0)) &&
+ (ipipeif->output & IPIPEIF_OUTPUT_MEMORY))
+ ipipeif_isr_buffer(ipipeif);
}
/* -----------------------------------------------------------------------------
diff --git a/drivers/staging/media/omap4iss/iss_regs.h b/drivers/staging/media/omap4iss/iss_regs.h
index efd0291a86f7..d2b6b6ae9174 100644
--- a/drivers/staging/media/omap4iss/iss_regs.h
+++ b/drivers/staging/media/omap4iss/iss_regs.h
@@ -215,6 +215,8 @@
#define CSI2_CTX_CTRL1_CTX_EN (1 << 0)
#define CSI2_CTX_CTRL2(i) (0x74 + (0x20 * i))
+#define CSI2_CTX_CTRL2_FRAME_MASK (0xffff << 16)
+#define CSI2_CTX_CTRL2_FRAME_SHIFT 16
#define CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT 13
#define CSI2_CTX_CTRL2_USER_DEF_MAP_MASK \
(0x3 << CSI2_CTX_CTRL2_USER_DEF_MAP_SHIFT)
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index 88522a8cdf56..3ab972818f1b 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -283,22 +283,6 @@ static void resizer_isr_buffer(struct iss_resizer_device *resizer)
}
/*
- * resizer_isif0_isr - Handle ISIF0 event
- * @resizer: Pointer to ISP RESIZER device.
- *
- * Executes LSC deferred enablement before next frame starts.
- */
-static void resizer_int_dma_isr(struct iss_resizer_device *resizer)
-{
- struct iss_pipeline *pipe =
- to_iss_pipeline(&resizer->subdev.entity);
- if (pipe->do_propagation)
- atomic_inc(&pipe->frame_number);
-
- resizer_isr_buffer(resizer);
-}
-
-/*
* omap4iss_resizer_isr - Configure resizer during interframe time.
* @resizer: Pointer to ISP RESIZER device.
* @events: RESIZER events
@@ -322,7 +306,7 @@ void omap4iss_resizer_isr(struct iss_resizer_device *resizer, u32 events)
return;
if (events & ISP5_IRQ_RSZ_INT_DMA)
- resizer_int_dma_isr(resizer);
+ resizer_isr_buffer(resizer);
}
/* -----------------------------------------------------------------------------
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index cdee5966cbca..69550445a341 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -25,9 +25,6 @@
#include "iss_video.h"
#include "iss.h"
-static unsigned debug;
-module_param(debug, uint, 0644);
-MODULE_PARM_DESC(debug, "activates debug info");
/* -----------------------------------------------------------------------------
* Helper functions
@@ -773,6 +770,14 @@ iss_video_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
}
static int
+iss_video_expbuf(struct file *file, void *fh, struct v4l2_exportbuffer *e)
+{
+ struct iss_video_fh *vfh = to_iss_video_fh(fh);
+
+ return vb2_expbuf(&vfh->queue, e);
+}
+
+static int
iss_video_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
{
struct iss_video_fh *vfh = to_iss_video_fh(fh);
@@ -1021,6 +1026,7 @@ static const struct v4l2_ioctl_ops iss_video_ioctl_ops = {
.vidioc_reqbufs = iss_video_reqbufs,
.vidioc_querybuf = iss_video_querybuf,
.vidioc_qbuf = iss_video_qbuf,
+ .vidioc_expbuf = iss_video_expbuf,
.vidioc_dqbuf = iss_video_dqbuf,
.vidioc_streamon = iss_video_streamon,
.vidioc_streamoff = iss_video_streamoff,
@@ -1044,8 +1050,6 @@ static int iss_video_open(struct file *file)
if (handle == NULL)
return -ENOMEM;
- video->video.debug = debug;
-
v4l2_fh_init(&handle->vfh, &video->video);
v4l2_fh_add(&handle->vfh);
@@ -1071,7 +1075,7 @@ static int iss_video_open(struct file *file)
q = &handle->queue;
q->type = video->type;
- q->io_modes = VB2_MMAP;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
q->drv_priv = handle;
q->ops = &iss_video_vb2ops;
q->mem_ops = &vb2_dma_contig_memops;
diff --git a/drivers/staging/media/parport/Kconfig b/drivers/staging/media/parport/Kconfig
deleted file mode 100644
index 15974efdba1d..000000000000
--- a/drivers/staging/media/parport/Kconfig
+++ /dev/null
@@ -1,69 +0,0 @@
-menuconfig MEDIA_PARPORT_SUPPORT
- bool "ISA and parallel port devices"
- depends on (ISA || PARPORT) && MEDIA_CAMERA_SUPPORT
- help
- Enables drivers for ISA and parallel port bus. If you
- need media drivers using those legacy buses, say Y.
-
-if MEDIA_PARPORT_SUPPORT
-config VIDEO_BWQCAM
- tristate "Quickcam BW Video For Linux (Deprecated)"
- depends on PARPORT && VIDEO_V4L2
- select VIDEOBUF2_VMALLOC
- help
- Say Y have if you the black and white version of the QuickCam
- camera. See the next option for the color version.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-
- To compile this driver as a module, choose M here: the
- module will be called bw-qcam.
-
-config VIDEO_CQCAM
- tristate "QuickCam Colour Video For Linux (Deprecated)"
- depends on PARPORT && VIDEO_V4L2
- help
- This is the video4linux driver for the colour version of the
- Connectix QuickCam. If you have one of these cameras, say Y here,
- otherwise say N. This driver does not work with the original
- monochrome QuickCam, QuickCam VC or QuickClip. It is also available
- as a module (c-qcam).
- Read <file:Documentation/video4linux/CQcam.txt> for more information.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-
-config VIDEO_PMS
- tristate "Mediavision Pro Movie Studio Video For Linux (Deprecated)"
- depends on ISA && VIDEO_V4L2
- help
- Say Y if you have the ISA Mediavision Pro Movie Studio
- capture card.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-
- To compile this driver as a module, choose M here: the
- module will be called pms.
-
-config VIDEO_W9966
- tristate "W9966CF Webcam (FlyCam Supra and others) Video For Linux (Deprecated)"
- depends on PARPORT_1284 && PARPORT && VIDEO_V4L2
- help
- Video4linux driver for Winbond's w9966 based Webcams.
- Currently tested with the LifeView FlyCam Supra.
- If you have one of these cameras, say Y here
- otherwise say N.
- This driver is also available as a module (w9966).
-
- Check out <file:Documentation/video4linux/w9966.txt> for more
- information.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-endif
diff --git a/drivers/staging/media/parport/Makefile b/drivers/staging/media/parport/Makefile
deleted file mode 100644
index 4eea06d7af5b..000000000000
--- a/drivers/staging/media/parport/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-obj-$(CONFIG_VIDEO_CQCAM) += c-qcam.o
-obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
-obj-$(CONFIG_VIDEO_W9966) += w9966.o
-obj-$(CONFIG_VIDEO_PMS) += pms.o
diff --git a/drivers/staging/media/parport/bw-qcam.c b/drivers/staging/media/parport/bw-qcam.c
deleted file mode 100644
index 67b9da1dc43f..000000000000
--- a/drivers/staging/media/parport/bw-qcam.c
+++ /dev/null
@@ -1,1177 +0,0 @@
-/*
- * QuickCam Driver For Video4Linux.
- *
- * Video4Linux conversion work by Alan Cox.
- * Parport compatibility by Phil Blundell.
- * Busy loop avoidance by Mark Cooke.
- *
- * Module parameters:
- *
- * maxpoll=<1 - 5000>
- *
- * When polling the QuickCam for a response, busy-wait for a
- * maximum of this many loops. The default of 250 gives little
- * impact on interactive response.
- *
- * NOTE: If this parameter is set too high, the processor
- * will busy wait until this loop times out, and then
- * slowly poll for a further 5 seconds before failing
- * the transaction. You have been warned.
- *
- * yieldlines=<1 - 250>
- *
- * When acquiring a frame from the camera, the data gathering
- * loop will yield back to the scheduler after completing
- * this many lines. The default of 4 provides a trade-off
- * between increased frame acquisition time and impact on
- * interactive response.
- */
-
-/* qcam-lib.c -- Library for programming with the Connectix QuickCam.
- * See the included documentation for usage instructions and details
- * of the protocol involved. */
-
-
-/* Version 0.5, August 4, 1996 */
-/* Version 0.7, August 27, 1996 */
-/* Version 0.9, November 17, 1996 */
-
-
-/******************************************************************
-
-Copyright (C) 1996 by Scott Laird
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-******************************************************************/
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/parport.h>
-#include <linux/sched.h>
-#include <linux/videodev2.h>
-#include <linux/mutex.h>
-#include <asm/uaccess.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <media/videobuf2-vmalloc.h>
-
-/* One from column A... */
-#define QC_NOTSET 0
-#define QC_UNIDIR 1
-#define QC_BIDIR 2
-#define QC_SERIAL 3
-
-/* ... and one from column B */
-#define QC_ANY 0x00
-#define QC_FORCE_UNIDIR 0x10
-#define QC_FORCE_BIDIR 0x20
-#define QC_FORCE_SERIAL 0x30
-/* in the port_mode member */
-
-#define QC_MODE_MASK 0x07
-#define QC_FORCE_MASK 0x70
-
-#define MAX_HEIGHT 243
-#define MAX_WIDTH 336
-
-/* Bit fields for status flags */
-#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */
-
-struct qcam {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct v4l2_ctrl_handler hdl;
- struct vb2_queue vb_vidq;
- struct pardevice *pdev;
- struct parport *pport;
- struct mutex lock;
- struct mutex queue_lock;
- int width, height;
- int bpp;
- int mode;
- int contrast, brightness, whitebal;
- int port_mode;
- int transfer_scale;
- int top, left;
- int status;
- unsigned int saved_bits;
- unsigned long in_use;
-};
-
-static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */
-static unsigned int yieldlines = 4; /* Yield after this many during capture */
-static int video_nr = -1;
-static unsigned int force_init; /* Whether to probe aggressively */
-
-module_param(maxpoll, int, 0);
-module_param(yieldlines, int, 0);
-module_param(video_nr, int, 0);
-
-/* Set force_init=1 to avoid detection by polling status register and
- * immediately attempt to initialize qcam */
-module_param(force_init, int, 0);
-
-#define MAX_CAMS 4
-static struct qcam *qcams[MAX_CAMS];
-static unsigned int num_cams;
-
-static inline int read_lpstatus(struct qcam *q)
-{
- return parport_read_status(q->pport);
-}
-
-static inline int read_lpdata(struct qcam *q)
-{
- return parport_read_data(q->pport);
-}
-
-static inline void write_lpdata(struct qcam *q, int d)
-{
- parport_write_data(q->pport, d);
-}
-
-static void write_lpcontrol(struct qcam *q, int d)
-{
- if (d & 0x20) {
- /* Set bidirectional mode to reverse (data in) */
- parport_data_reverse(q->pport);
- } else {
- /* Set bidirectional mode to forward (data out) */
- parport_data_forward(q->pport);
- }
-
- /* Now issue the regular port command, but strip out the
- * direction flag */
- d &= ~0x20;
- parport_write_control(q->pport, d);
-}
-
-
-/* qc_waithand busy-waits for a handshake signal from the QuickCam.
- * Almost all communication with the camera requires handshaking. */
-
-static int qc_waithand(struct qcam *q, int val)
-{
- int status;
- int runs = 0;
-
- if (val) {
- while (!((status = read_lpstatus(q)) & 8)) {
- /* 1000 is enough spins on the I/O for all normal
- cases, at that point we start to poll slowly
- until the camera wakes up. However, we are
- busy blocked until the camera responds, so
- setting it lower is much better for interactive
- response. */
-
- if (runs++ > maxpoll)
- msleep_interruptible(5);
- if (runs > (maxpoll + 1000)) /* 5 seconds */
- return -1;
- }
- } else {
- while (((status = read_lpstatus(q)) & 8)) {
- /* 1000 is enough spins on the I/O for all normal
- cases, at that point we start to poll slowly
- until the camera wakes up. However, we are
- busy blocked until the camera responds, so
- setting it lower is much better for interactive
- response. */
-
- if (runs++ > maxpoll)
- msleep_interruptible(5);
- if (runs++ > (maxpoll + 1000)) /* 5 seconds */
- return -1;
- }
- }
-
- return status;
-}
-
-/* Waithand2 is used when the qcam is in bidirectional mode, and the
- * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1
- * (bit 3 of status register). It also returns the last value read,
- * since this data is useful. */
-
-static unsigned int qc_waithand2(struct qcam *q, int val)
-{
- unsigned int status;
- int runs = 0;
-
- do {
- status = read_lpdata(q);
- /* 1000 is enough spins on the I/O for all normal
- cases, at that point we start to poll slowly
- until the camera wakes up. However, we are
- busy blocked until the camera responds, so
- setting it lower is much better for interactive
- response. */
-
- if (runs++ > maxpoll)
- msleep_interruptible(5);
- if (runs++ > (maxpoll + 1000)) /* 5 seconds */
- return 0;
- } while ((status & 1) != val);
-
- return status;
-}
-
-/* qc_command is probably a bit of a misnomer -- it's used to send
- * bytes *to* the camera. Generally, these bytes are either commands
- * or arguments to commands, so the name fits, but it still bugs me a
- * bit. See the documentation for a list of commands. */
-
-static int qc_command(struct qcam *q, int command)
-{
- int n1, n2;
- int cmd;
-
- write_lpdata(q, command);
- write_lpcontrol(q, 6);
-
- n1 = qc_waithand(q, 1);
-
- write_lpcontrol(q, 0xe);
- n2 = qc_waithand(q, 0);
-
- cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
- return cmd;
-}
-
-static int qc_readparam(struct qcam *q)
-{
- int n1, n2;
- int cmd;
-
- write_lpcontrol(q, 6);
- n1 = qc_waithand(q, 1);
-
- write_lpcontrol(q, 0xe);
- n2 = qc_waithand(q, 0);
-
- cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
- return cmd;
-}
-
-
-/* Try to detect a QuickCam. It appears to flash the upper 4 bits of
- the status register at 5-10 Hz. This is only used in the autoprobe
- code. Be aware that this isn't the way Connectix detects the
- camera (they send a reset and try to handshake), but this should be
- almost completely safe, while their method screws up my printer if
- I plug it in before the camera. */
-
-static int qc_detect(struct qcam *q)
-{
- int reg, lastreg;
- int count = 0;
- int i;
-
- if (force_init)
- return 1;
-
- lastreg = reg = read_lpstatus(q) & 0xf0;
-
- for (i = 0; i < 500; i++) {
- reg = read_lpstatus(q) & 0xf0;
- if (reg != lastreg)
- count++;
- lastreg = reg;
- mdelay(2);
- }
-
-
-#if 0
- /* Force camera detection during testing. Sometimes the camera
- won't be flashing these bits. Possibly unloading the module
- in the middle of a grab? Or some timeout condition?
- I've seen this parameter as low as 19 on my 450Mhz box - mpc */
- printk(KERN_DEBUG "Debugging: QCam detection counter <30-200 counts as detected>: %d\n", count);
- return 1;
-#endif
-
- /* Be (even more) liberal in what you accept... */
-
- if (count > 20 && count < 400) {
- return 1; /* found */
- } else {
- printk(KERN_ERR "No Quickcam found on port %s\n",
- q->pport->name);
- printk(KERN_DEBUG "Quickcam detection counter: %u\n", count);
- return 0; /* not found */
- }
-}
-
-/* Decide which scan mode to use. There's no real requirement that
- * the scanmode match the resolution in q->height and q-> width -- the
- * camera takes the picture at the resolution specified in the
- * "scanmode" and then returns the image at the resolution specified
- * with the resolution commands. If the scan is bigger than the
- * requested resolution, the upper-left hand corner of the scan is
- * returned. If the scan is smaller, then the rest of the image
- * returned contains garbage. */
-
-static int qc_setscanmode(struct qcam *q)
-{
- int old_mode = q->mode;
-
- switch (q->transfer_scale) {
- case 1:
- q->mode = 0;
- break;
- case 2:
- q->mode = 4;
- break;
- case 4:
- q->mode = 8;
- break;
- }
-
- switch (q->bpp) {
- case 4:
- break;
- case 6:
- q->mode += 2;
- break;
- }
-
- switch (q->port_mode & QC_MODE_MASK) {
- case QC_BIDIR:
- q->mode += 1;
- break;
- case QC_NOTSET:
- case QC_UNIDIR:
- break;
- }
-
- if (q->mode != old_mode)
- q->status |= QC_PARAM_CHANGE;
-
- return 0;
-}
-
-
-/* Reset the QuickCam. This uses the same sequence the Windows
- * QuickPic program uses. Someone with a bi-directional port should
- * check that bi-directional mode is detected right, and then
- * implement bi-directional mode in qc_readbyte(). */
-
-static void qc_reset(struct qcam *q)
-{
- switch (q->port_mode & QC_FORCE_MASK) {
- case QC_FORCE_UNIDIR:
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
- break;
-
- case QC_FORCE_BIDIR:
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
- break;
-
- case QC_ANY:
- write_lpcontrol(q, 0x20);
- write_lpdata(q, 0x75);
-
- if (read_lpdata(q) != 0x75)
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
- else
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
- break;
- }
-
- write_lpcontrol(q, 0xb);
- udelay(250);
- write_lpcontrol(q, 0xe);
- qc_setscanmode(q); /* in case port_mode changed */
-}
-
-
-
-/* Reset the QuickCam and program for brightness, contrast,
- * white-balance, and resolution. */
-
-static void qc_set(struct qcam *q)
-{
- int val;
- int val2;
-
- /* Set the brightness. Yes, this is repetitive, but it works.
- * Shorter versions seem to fail subtly. Feel free to try :-). */
- /* I think the problem was in qc_command, not here -- bls */
-
- qc_command(q, 0xb);
- qc_command(q, q->brightness);
-
- val = q->height / q->transfer_scale;
- qc_command(q, 0x11);
- qc_command(q, val);
- if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) {
- /* The normal "transfers per line" calculation doesn't seem to work
- as expected here (and yet it works fine in qc_scan). No idea
- why this case is the odd man out. Fortunately, Laird's original
- working version gives me a good way to guess at working values.
- -- bls */
- val = q->width;
- val2 = q->transfer_scale * 4;
- } else {
- val = q->width * q->bpp;
- val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
- q->transfer_scale;
- }
- val = DIV_ROUND_UP(val, val2);
- qc_command(q, 0x13);
- qc_command(q, val);
-
- /* Setting top and left -- bls */
- qc_command(q, 0xd);
- qc_command(q, q->top);
- qc_command(q, 0xf);
- qc_command(q, q->left / 2);
-
- qc_command(q, 0x19);
- qc_command(q, q->contrast);
- qc_command(q, 0x1f);
- qc_command(q, q->whitebal);
-
- /* Clear flag that we must update the grabbing parameters on the camera
- before we grab the next frame */
- q->status &= (~QC_PARAM_CHANGE);
-}
-
-/* Qc_readbytes reads some bytes from the QC and puts them in
- the supplied buffer. It returns the number of bytes read,
- or -1 on error. */
-
-static inline int qc_readbytes(struct qcam *q, char buffer[])
-{
- int ret = 1;
- unsigned int hi, lo;
- unsigned int hi2, lo2;
- static int state;
-
- if (buffer == NULL) {
- state = 0;
- return 0;
- }
-
- switch (q->port_mode & QC_MODE_MASK) {
- case QC_BIDIR: /* Bi-directional Port */
- write_lpcontrol(q, 0x26);
- lo = (qc_waithand2(q, 1) >> 1);
- hi = (read_lpstatus(q) >> 3) & 0x1f;
- write_lpcontrol(q, 0x2e);
- lo2 = (qc_waithand2(q, 0) >> 1);
- hi2 = (read_lpstatus(q) >> 3) & 0x1f;
- switch (q->bpp) {
- case 4:
- buffer[0] = lo & 0xf;
- buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3);
- buffer[2] = (hi & 0x1e) >> 1;
- buffer[3] = lo2 & 0xf;
- buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3);
- buffer[5] = (hi2 & 0x1e) >> 1;
- ret = 6;
- break;
- case 6:
- buffer[0] = lo & 0x3f;
- buffer[1] = ((lo & 0x40) >> 6) | (hi << 1);
- buffer[2] = lo2 & 0x3f;
- buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1);
- ret = 4;
- break;
- }
- break;
-
- case QC_UNIDIR: /* Unidirectional Port */
- write_lpcontrol(q, 6);
- lo = (qc_waithand(q, 1) & 0xf0) >> 4;
- write_lpcontrol(q, 0xe);
- hi = (qc_waithand(q, 0) & 0xf0) >> 4;
-
- switch (q->bpp) {
- case 4:
- buffer[0] = lo;
- buffer[1] = hi;
- ret = 2;
- break;
- case 6:
- switch (state) {
- case 0:
- buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
- q->saved_bits = (hi & 3) << 4;
- state = 1;
- ret = 1;
- break;
- case 1:
- buffer[0] = lo | q->saved_bits;
- q->saved_bits = hi << 2;
- state = 2;
- ret = 1;
- break;
- case 2:
- buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits;
- buffer[1] = ((lo & 3) << 4) | hi;
- state = 0;
- ret = 2;
- break;
- }
- break;
- }
- break;
- }
- return ret;
-}
-
-/* requests a scan from the camera. It sends the correct instructions
- * to the camera and then reads back the correct number of bytes. In
- * previous versions of this routine the return structure contained
- * the raw output from the camera, and there was a 'qc_convertscan'
- * function that converted that to a useful format. In version 0.3 I
- * rolled qc_convertscan into qc_scan and now I only return the
- * converted scan. The format is just an one-dimensional array of
- * characters, one for each pixel, with 0=black up to n=white, where
- * n=2^(bit depth)-1. Ask me for more details if you don't understand
- * this. */
-
-static long qc_capture(struct qcam *q, u8 *buf, unsigned long len)
-{
- int i, j, k, yield;
- int bytes;
- int linestotrans, transperline;
- int divisor;
- int pixels_per_line;
- int pixels_read = 0;
- int got = 0;
- char buffer[6];
- int shift = 8 - q->bpp;
- char invert;
-
- if (q->mode == -1)
- return -ENXIO;
-
- qc_command(q, 0x7);
- qc_command(q, q->mode);
-
- if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
- write_lpcontrol(q, 0x2e); /* turn port around */
- write_lpcontrol(q, 0x26);
- qc_waithand(q, 1);
- write_lpcontrol(q, 0x2e);
- qc_waithand(q, 0);
- }
-
- /* strange -- should be 15:63 below, but 4bpp is odd */
- invert = (q->bpp == 4) ? 16 : 63;
-
- linestotrans = q->height / q->transfer_scale;
- pixels_per_line = q->width / q->transfer_scale;
- transperline = q->width * q->bpp;
- divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
- q->transfer_scale;
- transperline = DIV_ROUND_UP(transperline, divisor);
-
- for (i = 0, yield = yieldlines; i < linestotrans; i++) {
- for (pixels_read = j = 0; j < transperline; j++) {
- bytes = qc_readbytes(q, buffer);
- for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) {
- int o;
- if (buffer[k] == 0 && invert == 16) {
- /* 4bpp is odd (again) -- inverter is 16, not 15, but output
- must be 0-15 -- bls */
- buffer[k] = 16;
- }
- o = i * pixels_per_line + pixels_read + k;
- if (o < len) {
- u8 ch = invert - buffer[k];
- got++;
- buf[o] = ch << shift;
- }
- }
- pixels_read += bytes;
- }
- qc_readbytes(q, NULL); /* reset state machine */
-
- /* Grabbing an entire frame from the quickcam is a lengthy
- process. We don't (usually) want to busy-block the
- processor for the entire frame. yieldlines is a module
- parameter. If we yield every line, the minimum frame
- time will be 240 / 200 = 1.2 seconds. The compile-time
- default is to yield every 4 lines. */
- if (i >= yield) {
- msleep_interruptible(5);
- yield = i + yieldlines;
- }
- }
-
- if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) {
- write_lpcontrol(q, 2);
- write_lpcontrol(q, 6);
- udelay(3);
- write_lpcontrol(q, 0xe);
- }
- if (got < len)
- return got;
- return len;
-}
-
-/* ------------------------------------------------------------------
- Videobuf operations
- ------------------------------------------------------------------*/
-static int queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
- unsigned int *nbuffers, unsigned int *nplanes,
- unsigned int sizes[], void *alloc_ctxs[])
-{
- struct qcam *dev = vb2_get_drv_priv(vq);
-
- if (0 == *nbuffers)
- *nbuffers = 3;
- *nplanes = 1;
- mutex_lock(&dev->lock);
- if (fmt)
- sizes[0] = fmt->fmt.pix.width * fmt->fmt.pix.height;
- else
- sizes[0] = (dev->width / dev->transfer_scale) *
- (dev->height / dev->transfer_scale);
- mutex_unlock(&dev->lock);
- return 0;
-}
-
-static void buffer_queue(struct vb2_buffer *vb)
-{
- vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
-}
-
-static void buffer_finish(struct vb2_buffer *vb)
-{
- struct qcam *qcam = vb2_get_drv_priv(vb->vb2_queue);
- void *vbuf = vb2_plane_vaddr(vb, 0);
- int size = vb->vb2_queue->plane_sizes[0];
- int len;
-
- if (!vb2_is_streaming(vb->vb2_queue))
- return;
-
- mutex_lock(&qcam->lock);
- parport_claim_or_block(qcam->pdev);
-
- qc_reset(qcam);
-
- /* Update the camera parameters if we need to */
- if (qcam->status & QC_PARAM_CHANGE)
- qc_set(qcam);
-
- len = qc_capture(qcam, vbuf, size);
-
- parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
- if (len != size)
- vb->state = VB2_BUF_STATE_ERROR;
- vb2_set_plane_payload(vb, 0, len);
-}
-
-static struct vb2_ops qcam_video_qops = {
- .queue_setup = queue_setup,
- .buf_queue = buffer_queue,
- .buf_finish = buffer_finish,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
-};
-
-/*
- * Video4linux interfacing
- */
-
-static int qcam_querycap(struct file *file, void *priv,
- struct v4l2_capability *vcap)
-{
- struct qcam *qcam = video_drvdata(file);
-
- strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
- strlcpy(vcap->card, "Connectix B&W Quickcam", sizeof(vcap->card));
- strlcpy(vcap->bus_info, qcam->pport->name, sizeof(vcap->bus_info));
- vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING;
- vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
-{
- if (vin->index > 0)
- return -EINVAL;
- strlcpy(vin->name, "Camera", sizeof(vin->name));
- vin->type = V4L2_INPUT_TYPE_CAMERA;
- vin->audioset = 0;
- vin->tuner = 0;
- vin->std = 0;
- vin->status = 0;
- return 0;
-}
-
-static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
-{
- *inp = 0;
- return 0;
-}
-
-static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
-{
- return (inp > 0) ? -EINVAL : 0;
-}
-
-static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct qcam *qcam = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- pix->width = qcam->width / qcam->transfer_scale;
- pix->height = qcam->height / qcam->transfer_scale;
- pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = pix->width;
- pix->sizeimage = pix->width * pix->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- if (pix->height <= 60 || pix->width <= 80) {
- pix->height = 60;
- pix->width = 80;
- } else if (pix->height <= 120 || pix->width <= 160) {
- pix->height = 120;
- pix->width = 160;
- } else {
- pix->height = 240;
- pix->width = 320;
- }
- if (pix->pixelformat != V4L2_PIX_FMT_Y4 &&
- pix->pixelformat != V4L2_PIX_FMT_Y6)
- pix->pixelformat = V4L2_PIX_FMT_Y4;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = pix->width;
- pix->sizeimage = pix->width * pix->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct qcam *qcam = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
- int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
-
- if (ret)
- return ret;
- if (vb2_is_busy(&qcam->vb_vidq))
- return -EBUSY;
- qcam->width = 320;
- qcam->height = 240;
- if (pix->height == 60)
- qcam->transfer_scale = 4;
- else if (pix->height == 120)
- qcam->transfer_scale = 2;
- else
- qcam->transfer_scale = 1;
- if (pix->pixelformat == V4L2_PIX_FMT_Y6)
- qcam->bpp = 6;
- else
- qcam->bpp = 4;
-
- qc_setscanmode(qcam);
- /* We must update the camera before we grab. We could
- just have changed the grab size */
- qcam->status |= QC_PARAM_CHANGE;
- return 0;
-}
-
-static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
-{
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "4-Bit Monochrome", V4L2_PIX_FMT_Y4,
- { 0, 0, 0, 0 }
- },
- { 1, 0, 0,
- "6-Bit Monochrome", V4L2_PIX_FMT_Y6,
- { 0, 0, 0, 0 }
- },
- };
- enum v4l2_buf_type type = fmt->type;
-
- if (fmt->index > 1)
- return -EINVAL;
-
- *fmt = formats[fmt->index];
- fmt->type = type;
- return 0;
-}
-
-static int qcam_enum_framesizes(struct file *file, void *fh,
- struct v4l2_frmsizeenum *fsize)
-{
- static const struct v4l2_frmsize_discrete sizes[] = {
- { 80, 60 },
- { 160, 120 },
- { 320, 240 },
- };
-
- if (fsize->index > 2)
- return -EINVAL;
- if (fsize->pixel_format != V4L2_PIX_FMT_Y4 &&
- fsize->pixel_format != V4L2_PIX_FMT_Y6)
- return -EINVAL;
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete = sizes[fsize->index];
- return 0;
-}
-
-static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct qcam *qcam =
- container_of(ctrl->handler, struct qcam, hdl);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- qcam->brightness = ctrl->val;
- break;
- case V4L2_CID_CONTRAST:
- qcam->contrast = ctrl->val;
- break;
- case V4L2_CID_GAMMA:
- qcam->whitebal = ctrl->val;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret == 0)
- qcam->status |= QC_PARAM_CHANGE;
- return ret;
-}
-
-static const struct v4l2_file_operations qcam_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = vb2_fop_release,
- .poll = vb2_fop_poll,
- .unlocked_ioctl = video_ioctl2,
- .read = vb2_fop_read,
- .mmap = vb2_fop_mmap,
-};
-
-static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
- .vidioc_querycap = qcam_querycap,
- .vidioc_g_input = qcam_g_input,
- .vidioc_s_input = qcam_s_input,
- .vidioc_enum_input = qcam_enum_input,
- .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
- .vidioc_enum_framesizes = qcam_enum_framesizes,
- .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
- .vidioc_reqbufs = vb2_ioctl_reqbufs,
- .vidioc_create_bufs = vb2_ioctl_create_bufs,
- .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
- .vidioc_querybuf = vb2_ioctl_querybuf,
- .vidioc_qbuf = vb2_ioctl_qbuf,
- .vidioc_dqbuf = vb2_ioctl_dqbuf,
- .vidioc_streamon = vb2_ioctl_streamon,
- .vidioc_streamoff = vb2_ioctl_streamoff,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
- .s_ctrl = qcam_s_ctrl,
-};
-
-/* Initialize the QuickCam driver control structure. This is where
- * defaults are set for people who don't have a config file.*/
-
-static struct qcam *qcam_init(struct parport *port)
-{
- struct qcam *qcam;
- struct v4l2_device *v4l2_dev;
- struct vb2_queue *q;
- int err;
-
- qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
- if (qcam == NULL)
- return NULL;
-
- v4l2_dev = &qcam->v4l2_dev;
- snprintf(v4l2_dev->name, sizeof(v4l2_dev->name), "bw-qcam%u", num_cams);
-
- if (v4l2_device_register(port->dev, v4l2_dev) < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- kfree(qcam);
- return NULL;
- }
-
- v4l2_ctrl_handler_init(&qcam->hdl, 3);
- v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 180);
- v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 192);
- v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
- V4L2_CID_GAMMA, 0, 255, 1, 105);
- if (qcam->hdl.error) {
- v4l2_err(v4l2_dev, "couldn't register controls\n");
- goto exit;
- }
-
- mutex_init(&qcam->lock);
- mutex_init(&qcam->queue_lock);
-
- /* initialize queue */
- q = &qcam->vb_vidq;
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_READ;
- q->drv_priv = qcam;
- q->ops = &qcam_video_qops;
- q->mem_ops = &vb2_vmalloc_memops;
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- err = vb2_queue_init(q);
- if (err < 0) {
- v4l2_err(v4l2_dev, "couldn't init vb2_queue for %s.\n", port->name);
- goto exit;
- }
- qcam->vdev.queue = q;
- qcam->vdev.queue->lock = &qcam->queue_lock;
-
- qcam->pport = port;
- qcam->pdev = parport_register_device(port, v4l2_dev->name, NULL, NULL,
- NULL, 0, NULL);
- if (qcam->pdev == NULL) {
- v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
- goto exit;
- }
-
- strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
- qcam->vdev.v4l2_dev = v4l2_dev;
- qcam->vdev.ctrl_handler = &qcam->hdl;
- qcam->vdev.fops = &qcam_fops;
- qcam->vdev.lock = &qcam->lock;
- qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
- qcam->vdev.release = video_device_release_empty;
- video_set_drvdata(&qcam->vdev, qcam);
-
- qcam->port_mode = (QC_ANY | QC_NOTSET);
- qcam->width = 320;
- qcam->height = 240;
- qcam->bpp = 4;
- qcam->transfer_scale = 2;
- qcam->contrast = 192;
- qcam->brightness = 180;
- qcam->whitebal = 105;
- qcam->top = 1;
- qcam->left = 14;
- qcam->mode = -1;
- qcam->status = QC_PARAM_CHANGE;
- return qcam;
-
-exit:
- v4l2_ctrl_handler_free(&qcam->hdl);
- kfree(qcam);
- return NULL;
-}
-
-static int qc_calibrate(struct qcam *q)
-{
- /*
- * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
- * The white balance is an individual value for each
- * quickcam.
- */
-
- int value;
- int count = 0;
-
- qc_command(q, 27); /* AutoAdjustOffset */
- qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
-
- /* GetOffset (33) will read 255 until autocalibration */
- /* is finished. After that, a value of 1-254 will be */
- /* returned. */
-
- do {
- qc_command(q, 33);
- value = qc_readparam(q);
- mdelay(1);
- schedule();
- count++;
- } while (value == 0xff && count < 2048);
-
- q->whitebal = value;
- return value;
-}
-
-static int init_bwqcam(struct parport *port)
-{
- struct qcam *qcam;
-
- if (num_cams == MAX_CAMS) {
- printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
- return -ENOSPC;
- }
-
- qcam = qcam_init(port);
- if (qcam == NULL)
- return -ENODEV;
-
- parport_claim_or_block(qcam->pdev);
-
- qc_reset(qcam);
-
- if (qc_detect(qcam) == 0) {
- parport_release(qcam->pdev);
- parport_unregister_device(qcam->pdev);
- kfree(qcam);
- return -ENODEV;
- }
- qc_calibrate(qcam);
- v4l2_ctrl_handler_setup(&qcam->hdl);
-
- parport_release(qcam->pdev);
-
- v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name);
-
- if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- parport_unregister_device(qcam->pdev);
- kfree(qcam);
- return -ENODEV;
- }
-
- qcams[num_cams++] = qcam;
-
- return 0;
-}
-
-static void close_bwqcam(struct qcam *qcam)
-{
- video_unregister_device(&qcam->vdev);
- v4l2_ctrl_handler_free(&qcam->hdl);
- parport_unregister_device(qcam->pdev);
- kfree(qcam);
-}
-
-/* The parport parameter controls which parports will be scanned.
- * Scanning all parports causes some printers to print a garbage page.
- * -- March 14, 1999 Billy Donahue <billy@escape.com> */
-#ifdef MODULE
-static char *parport[MAX_CAMS] = { NULL, };
-module_param_array(parport, charp, NULL, 0);
-#endif
-
-static int accept_bwqcam(struct parport *port)
-{
-#ifdef MODULE
- int n;
-
- if (parport[0] && strncmp(parport[0], "auto", 4) != 0) {
- /* user gave parport parameters */
- for (n = 0; n < MAX_CAMS && parport[n]; n++) {
- char *ep;
- unsigned long r;
- r = simple_strtoul(parport[n], &ep, 0);
- if (ep == parport[n]) {
- printk(KERN_ERR
- "bw-qcam: bad port specifier \"%s\"\n",
- parport[n]);
- continue;
- }
- if (r == port->number)
- return 1;
- }
- return 0;
- }
-#endif
- return 1;
-}
-
-static void bwqcam_attach(struct parport *port)
-{
- if (accept_bwqcam(port))
- init_bwqcam(port);
-}
-
-static void bwqcam_detach(struct parport *port)
-{
- int i;
- for (i = 0; i < num_cams; i++) {
- struct qcam *qcam = qcams[i];
- if (qcam && qcam->pdev->port == port) {
- qcams[i] = NULL;
- close_bwqcam(qcam);
- }
- }
-}
-
-static struct parport_driver bwqcam_driver = {
- .name = "bw-qcam",
- .attach = bwqcam_attach,
- .detach = bwqcam_detach,
-};
-
-static void __exit exit_bw_qcams(void)
-{
- parport_unregister_driver(&bwqcam_driver);
-}
-
-static int __init init_bw_qcams(void)
-{
-#ifdef MODULE
- /* Do some sanity checks on the module parameters. */
- if (maxpoll > 5000) {
- printk(KERN_INFO "Connectix Quickcam max-poll was above 5000. Using 5000.\n");
- maxpoll = 5000;
- }
-
- if (yieldlines < 1) {
- printk(KERN_INFO "Connectix Quickcam yieldlines was less than 1. Using 1.\n");
- yieldlines = 1;
- }
-#endif
- return parport_register_driver(&bwqcam_driver);
-}
-
-module_init(init_bw_qcams);
-module_exit(exit_bw_qcams);
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.3");
diff --git a/drivers/staging/media/parport/c-qcam.c b/drivers/staging/media/parport/c-qcam.c
deleted file mode 100644
index b9010bd3ed3e..000000000000
--- a/drivers/staging/media/parport/c-qcam.c
+++ /dev/null
@@ -1,882 +0,0 @@
-/*
- * Video4Linux Colour QuickCam driver
- * Copyright 1997-2000 Philip Blundell <philb@gnu.org>
- *
- * Module parameters:
- *
- * parport=auto -- probe all parports (default)
- * parport=0 -- parport0 becomes qcam1
- * parport=2,0,1 -- parports 2,0,1 are tried in that order
- *
- * probe=0 -- do no probing, assume camera is present
- * probe=1 -- use IEEE-1284 autoprobe data only (default)
- * probe=2 -- probe aggressively for cameras
- *
- * force_rgb=1 -- force data format to RGB (default is BGR)
- *
- * The parport parameter controls which parports will be scanned.
- * Scanning all parports causes some printers to print a garbage page.
- * -- March 14, 1999 Billy Donahue <billy@escape.com>
- *
- * Fixed data format to BGR, added force_rgb parameter. Added missing
- * parport_unregister_driver() on module removal.
- * -- May 28, 2000 Claudio Matsuoka <claudio@conectiva.com>
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/parport.h>
-#include <linux/sched.h>
-#include <linux/mutex.h>
-#include <linux/jiffies.h>
-#include <linux/videodev2.h>
-#include <asm/uaccess.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-
-struct qcam {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct v4l2_ctrl_handler hdl;
- struct pardevice *pdev;
- struct parport *pport;
- int width, height;
- int ccd_width, ccd_height;
- int mode;
- int contrast, brightness, whitebal;
- int top, left;
- unsigned int bidirectional;
- struct mutex lock;
-};
-
-/* cameras maximum */
-#define MAX_CAMS 4
-
-/* The three possible QuickCam modes */
-#define QC_MILLIONS 0x18
-#define QC_BILLIONS 0x10
-#define QC_THOUSANDS 0x08 /* with VIDEC compression (not supported) */
-
-/* The three possible decimations */
-#define QC_DECIMATION_1 0
-#define QC_DECIMATION_2 2
-#define QC_DECIMATION_4 4
-
-#define BANNER "Colour QuickCam for Video4Linux v0.06"
-
-static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
-static int probe = 2;
-static bool force_rgb;
-static int video_nr = -1;
-
-/* FIXME: parport=auto would never have worked, surely? --RR */
-MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
- "probe=<0|1|2> for camera detection method\n"
- "force_rgb=<0|1> for RGB data format (default BGR)");
-module_param_array(parport, int, NULL, 0);
-module_param(probe, int, 0);
-module_param(force_rgb, bool, 0);
-module_param(video_nr, int, 0);
-
-static struct qcam *qcams[MAX_CAMS];
-static unsigned int num_cams;
-
-static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
-{
- /* note: the QC specs refer to the PCAck pin by voltage, not
- software level. PC ports have builtin inverters. */
- parport_frob_control(qcam->pport, 8, i ? 8 : 0);
-}
-
-static inline unsigned int qcam_ready1(struct qcam *qcam)
-{
- return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
-}
-
-static inline unsigned int qcam_ready2(struct qcam *qcam)
-{
- return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
-}
-
-static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
-{
- struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
- unsigned long oldjiffies = jiffies;
- unsigned int i;
-
- for (oldjiffies = jiffies;
- time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
- if (qcam_ready1(qcam) == value)
- return 0;
-
- /* If the camera didn't respond within 1/25 second, poll slowly
- for a while. */
- for (i = 0; i < 50; i++) {
- if (qcam_ready1(qcam) == value)
- return 0;
- msleep_interruptible(100);
- }
-
- /* Probably somebody pulled the plug out. Not much we can do. */
- v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
- parport_read_status(qcam->pport),
- parport_read_control(qcam->pport));
- return 1;
-}
-
-static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
-{
- struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
- unsigned long oldjiffies = jiffies;
- unsigned int i;
-
- for (oldjiffies = jiffies;
- time_before(jiffies, oldjiffies + msecs_to_jiffies(40));)
- if (qcam_ready2(qcam) == value)
- return 0;
-
- /* If the camera didn't respond within 1/25 second, poll slowly
- for a while. */
- for (i = 0; i < 50; i++) {
- if (qcam_ready2(qcam) == value)
- return 0;
- msleep_interruptible(100);
- }
-
- /* Probably somebody pulled the plug out. Not much we can do. */
- v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
- parport_read_status(qcam->pport),
- parport_read_control(qcam->pport),
- parport_read_data(qcam->pport));
- return 1;
-}
-
-static int qcam_read_data(struct qcam *qcam)
-{
- unsigned int idata;
-
- qcam_set_ack(qcam, 0);
- if (qcam_await_ready1(qcam, 1))
- return -1;
- idata = parport_read_status(qcam->pport) & 0xf0;
- qcam_set_ack(qcam, 1);
- if (qcam_await_ready1(qcam, 0))
- return -1;
- idata |= parport_read_status(qcam->pport) >> 4;
- return idata;
-}
-
-static int qcam_write_data(struct qcam *qcam, unsigned int data)
-{
- struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
- unsigned int idata;
-
- parport_write_data(qcam->pport, data);
- idata = qcam_read_data(qcam);
- if (data != idata) {
- v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
- idata);
- return 1;
- }
- return 0;
-}
-
-static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
-{
- if (qcam_write_data(qcam, cmd))
- return -1;
- if (qcam_write_data(qcam, data))
- return -1;
- return 0;
-}
-
-static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
-{
- if (qcam_write_data(qcam, cmd))
- return -1;
- return qcam_read_data(qcam);
-}
-
-static int qc_detect(struct qcam *qcam)
-{
- unsigned int stat, ostat, i, count = 0;
-
- /* The probe routine below is not very reliable. The IEEE-1284
- probe takes precedence. */
- /* XXX Currently parport provides no way to distinguish between
- "the IEEE probe was not done" and "the probe was done, but
- no device was found". Fix this one day. */
- if (qcam->pport->probe_info[0].class == PARPORT_CLASS_MEDIA
- && qcam->pport->probe_info[0].model
- && !strcmp(qcam->pdev->port->probe_info[0].model,
- "Color QuickCam 2.0")) {
- printk(KERN_DEBUG "QuickCam: Found by IEEE1284 probe.\n");
- return 1;
- }
-
- if (probe < 2)
- return 0;
-
- parport_write_control(qcam->pport, 0xc);
-
- /* look for a heartbeat */
- ostat = stat = parport_read_status(qcam->pport);
- for (i = 0; i < 250; i++) {
- mdelay(1);
- stat = parport_read_status(qcam->pport);
- if (ostat != stat) {
- if (++count >= 3)
- return 1;
- ostat = stat;
- }
- }
-
- /* Reset the camera and try again */
- parport_write_control(qcam->pport, 0xc);
- parport_write_control(qcam->pport, 0x8);
- mdelay(1);
- parport_write_control(qcam->pport, 0xc);
- mdelay(1);
- count = 0;
-
- ostat = stat = parport_read_status(qcam->pport);
- for (i = 0; i < 250; i++) {
- mdelay(1);
- stat = parport_read_status(qcam->pport);
- if (ostat != stat) {
- if (++count >= 3)
- return 1;
- ostat = stat;
- }
- }
-
- /* no (or flatline) camera, give up */
- return 0;
-}
-
-static void qc_reset(struct qcam *qcam)
-{
- parport_write_control(qcam->pport, 0xc);
- parport_write_control(qcam->pport, 0x8);
- mdelay(1);
- parport_write_control(qcam->pport, 0xc);
- mdelay(1);
-}
-
-/* Reset the QuickCam and program for brightness, contrast,
- * white-balance, and resolution. */
-
-static void qc_setup(struct qcam *qcam)
-{
- qc_reset(qcam);
-
- /* Set the brightness. */
- qcam_set(qcam, 11, qcam->brightness);
-
- /* Set the height and width. These refer to the actual
- CCD area *before* applying the selected decimation. */
- qcam_set(qcam, 17, qcam->ccd_height);
- qcam_set(qcam, 19, qcam->ccd_width / 2);
-
- /* Set top and left. */
- qcam_set(qcam, 0xd, qcam->top);
- qcam_set(qcam, 0xf, qcam->left);
-
- /* Set contrast and white balance. */
- qcam_set(qcam, 0x19, qcam->contrast);
- qcam_set(qcam, 0x1f, qcam->whitebal);
-
- /* Set the speed. */
- qcam_set(qcam, 45, 2);
-}
-
-/* Read some bytes from the camera and put them in the buffer.
- nbytes should be a multiple of 3, because bidirectional mode gives
- us three bytes at a time. */
-
-static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
-{
- unsigned int bytes = 0;
-
- qcam_set_ack(qcam, 0);
- if (qcam->bidirectional) {
- /* It's a bidirectional port */
- while (bytes < nbytes) {
- unsigned int lo1, hi1, lo2, hi2;
- unsigned char r, g, b;
-
- if (qcam_await_ready2(qcam, 1))
- return bytes;
- lo1 = parport_read_data(qcam->pport) >> 1;
- hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
- qcam_set_ack(qcam, 1);
- if (qcam_await_ready2(qcam, 0))
- return bytes;
- lo2 = parport_read_data(qcam->pport) >> 1;
- hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
- qcam_set_ack(qcam, 0);
- r = lo1 | ((hi1 & 1) << 7);
- g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
- b = lo2 | ((hi2 & 1) << 7);
- if (force_rgb) {
- buf[bytes++] = r;
- buf[bytes++] = g;
- buf[bytes++] = b;
- } else {
- buf[bytes++] = b;
- buf[bytes++] = g;
- buf[bytes++] = r;
- }
- }
- } else {
- /* It's a unidirectional port */
- int i = 0, n = bytes;
- unsigned char rgb[3];
-
- while (bytes < nbytes) {
- unsigned int hi, lo;
-
- if (qcam_await_ready1(qcam, 1))
- return bytes;
- hi = (parport_read_status(qcam->pport) & 0xf0);
- qcam_set_ack(qcam, 1);
- if (qcam_await_ready1(qcam, 0))
- return bytes;
- lo = (parport_read_status(qcam->pport) & 0xf0);
- qcam_set_ack(qcam, 0);
- /* flip some bits */
- rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
- if (i >= 2) {
-get_fragment:
- if (force_rgb) {
- buf[n++] = rgb[0];
- buf[n++] = rgb[1];
- buf[n++] = rgb[2];
- } else {
- buf[n++] = rgb[2];
- buf[n++] = rgb[1];
- buf[n++] = rgb[0];
- }
- }
- }
- if (i) {
- i = 0;
- goto get_fragment;
- }
- }
- return bytes;
-}
-
-#define BUFSZ 150
-
-static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
-{
- struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
- unsigned lines, pixelsperline;
- unsigned int is_bi_dir = qcam->bidirectional;
- size_t wantlen, outptr = 0;
- char tmpbuf[BUFSZ];
-
- if (!access_ok(VERIFY_WRITE, buf, len))
- return -EFAULT;
-
- /* Wait for camera to become ready */
- for (;;) {
- int i = qcam_get(qcam, 41);
-
- if (i == -1) {
- qc_setup(qcam);
- return -EIO;
- }
- if ((i & 0x80) == 0)
- break;
- schedule();
- }
-
- if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
- return -EIO;
-
- lines = qcam->height;
- pixelsperline = qcam->width;
-
- if (is_bi_dir) {
- /* Turn the port around */
- parport_data_reverse(qcam->pport);
- mdelay(3);
- qcam_set_ack(qcam, 0);
- if (qcam_await_ready1(qcam, 1)) {
- qc_setup(qcam);
- return -EIO;
- }
- qcam_set_ack(qcam, 1);
- if (qcam_await_ready1(qcam, 0)) {
- qc_setup(qcam);
- return -EIO;
- }
- }
-
- wantlen = lines * pixelsperline * 24 / 8;
-
- while (wantlen) {
- size_t t, s;
-
- s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
- t = qcam_read_bytes(qcam, tmpbuf, s);
- if (outptr < len) {
- size_t sz = len - outptr;
-
- if (sz > t)
- sz = t;
- if (__copy_to_user(buf + outptr, tmpbuf, sz))
- break;
- outptr += sz;
- }
- wantlen -= t;
- if (t < s)
- break;
- cond_resched();
- }
-
- len = outptr;
-
- if (wantlen) {
- v4l2_err(v4l2_dev, "short read.\n");
- if (is_bi_dir)
- parport_data_forward(qcam->pport);
- qc_setup(qcam);
- return len;
- }
-
- if (is_bi_dir) {
- int l;
-
- do {
- l = qcam_read_bytes(qcam, tmpbuf, 3);
- cond_resched();
- } while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
- if (force_rgb) {
- if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- v4l2_err(v4l2_dev, "bad EOF\n");
- } else {
- if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
- v4l2_err(v4l2_dev, "bad EOF\n");
- }
- qcam_set_ack(qcam, 0);
- if (qcam_await_ready1(qcam, 1)) {
- v4l2_err(v4l2_dev, "no ack after EOF\n");
- parport_data_forward(qcam->pport);
- qc_setup(qcam);
- return len;
- }
- parport_data_forward(qcam->pport);
- mdelay(3);
- qcam_set_ack(qcam, 1);
- if (qcam_await_ready1(qcam, 0)) {
- v4l2_err(v4l2_dev, "no ack to port turnaround\n");
- qc_setup(qcam);
- return len;
- }
- } else {
- int l;
-
- do {
- l = qcam_read_bytes(qcam, tmpbuf, 1);
- cond_resched();
- } while (l && tmpbuf[0] == 0x7e);
- l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
- if (force_rgb) {
- if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- v4l2_err(v4l2_dev, "bad EOF\n");
- } else {
- if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
- v4l2_err(v4l2_dev, "bad EOF\n");
- }
- }
-
- qcam_write_data(qcam, 0);
- return len;
-}
-
-/*
- * Video4linux interfacing
- */
-
-static int qcam_querycap(struct file *file, void *priv,
- struct v4l2_capability *vcap)
-{
- struct qcam *qcam = video_drvdata(file);
-
- strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
- strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
- strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
- vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
- vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
-{
- if (vin->index > 0)
- return -EINVAL;
- strlcpy(vin->name, "Camera", sizeof(vin->name));
- vin->type = V4L2_INPUT_TYPE_CAMERA;
- vin->audioset = 0;
- vin->tuner = 0;
- vin->std = 0;
- vin->status = 0;
- return 0;
-}
-
-static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
-{
- *inp = 0;
- return 0;
-}
-
-static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
-{
- return (inp > 0) ? -EINVAL : 0;
-}
-
-static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct qcam *qcam = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- pix->width = qcam->width;
- pix->height = qcam->height;
- pix->pixelformat = V4L2_PIX_FMT_RGB24;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = 3 * qcam->width;
- pix->sizeimage = 3 * qcam->width * qcam->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- if (pix->height < 60 || pix->width < 80) {
- pix->height = 60;
- pix->width = 80;
- } else if (pix->height < 120 || pix->width < 160) {
- pix->height = 120;
- pix->width = 160;
- } else {
- pix->height = 240;
- pix->width = 320;
- }
- pix->pixelformat = V4L2_PIX_FMT_RGB24;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = 3 * pix->width;
- pix->sizeimage = 3 * pix->width * pix->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct qcam *qcam = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
- int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
-
- if (ret)
- return ret;
- switch (pix->height) {
- case 60:
- qcam->mode = QC_DECIMATION_4;
- break;
- case 120:
- qcam->mode = QC_DECIMATION_2;
- break;
- default:
- qcam->mode = QC_DECIMATION_1;
- break;
- }
-
- mutex_lock(&qcam->lock);
- qcam->mode |= QC_MILLIONS;
- qcam->height = pix->height;
- qcam->width = pix->width;
- parport_claim_or_block(qcam->pdev);
- qc_setup(qcam);
- parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- return 0;
-}
-
-static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
-{
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
- { 0, 0, 0, 0 }
- },
- };
- enum v4l2_buf_type type = fmt->type;
-
- if (fmt->index > 0)
- return -EINVAL;
-
- *fmt = formats[fmt->index];
- fmt->type = type;
- return 0;
-}
-
-static ssize_t qcam_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct qcam *qcam = video_drvdata(file);
- int len;
-
- mutex_lock(&qcam->lock);
- parport_claim_or_block(qcam->pdev);
- /* Probably should have a semaphore against multiple users */
- len = qc_capture(qcam, buf, count);
- parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- return len;
-}
-
-static int qcam_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct qcam *qcam =
- container_of(ctrl->handler, struct qcam, hdl);
- int ret = 0;
-
- mutex_lock(&qcam->lock);
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- qcam->brightness = ctrl->val;
- break;
- case V4L2_CID_CONTRAST:
- qcam->contrast = ctrl->val;
- break;
- case V4L2_CID_GAMMA:
- qcam->whitebal = ctrl->val;
- break;
- default:
- ret = -EINVAL;
- break;
- }
- if (ret == 0) {
- parport_claim_or_block(qcam->pdev);
- qc_setup(qcam);
- parport_release(qcam->pdev);
- }
- mutex_unlock(&qcam->lock);
- return ret;
-}
-
-static const struct v4l2_file_operations qcam_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = v4l2_fh_release,
- .poll = v4l2_ctrl_poll,
- .unlocked_ioctl = video_ioctl2,
- .read = qcam_read,
-};
-
-static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
- .vidioc_querycap = qcam_querycap,
- .vidioc_g_input = qcam_g_input,
- .vidioc_s_input = qcam_s_input,
- .vidioc_enum_input = qcam_enum_input,
- .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct v4l2_ctrl_ops qcam_ctrl_ops = {
- .s_ctrl = qcam_s_ctrl,
-};
-
-/* Initialize the QuickCam driver control structure. */
-
-static struct qcam *qcam_init(struct parport *port)
-{
- struct qcam *qcam;
- struct v4l2_device *v4l2_dev;
-
- qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
- if (qcam == NULL)
- return NULL;
-
- v4l2_dev = &qcam->v4l2_dev;
- strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
-
- if (v4l2_device_register(NULL, v4l2_dev) < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- kfree(qcam);
- return NULL;
- }
-
- v4l2_ctrl_handler_init(&qcam->hdl, 3);
- v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 240);
- v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 192);
- v4l2_ctrl_new_std(&qcam->hdl, &qcam_ctrl_ops,
- V4L2_CID_GAMMA, 0, 255, 1, 128);
- if (qcam->hdl.error) {
- v4l2_err(v4l2_dev, "couldn't register controls\n");
- v4l2_ctrl_handler_free(&qcam->hdl);
- kfree(qcam);
- return NULL;
- }
-
- qcam->pport = port;
- qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
- NULL, 0, NULL);
-
- qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
-
- if (qcam->pdev == NULL) {
- v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
- v4l2_ctrl_handler_free(&qcam->hdl);
- kfree(qcam);
- return NULL;
- }
-
- strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
- qcam->vdev.v4l2_dev = v4l2_dev;
- qcam->vdev.fops = &qcam_fops;
- qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
- qcam->vdev.release = video_device_release_empty;
- qcam->vdev.ctrl_handler = &qcam->hdl;
- video_set_drvdata(&qcam->vdev, qcam);
-
- mutex_init(&qcam->lock);
- qcam->width = qcam->ccd_width = 320;
- qcam->height = qcam->ccd_height = 240;
- qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
- qcam->contrast = 192;
- qcam->brightness = 240;
- qcam->whitebal = 128;
- qcam->top = 1;
- qcam->left = 14;
- return qcam;
-}
-
-static int init_cqcam(struct parport *port)
-{
- struct qcam *qcam;
- struct v4l2_device *v4l2_dev;
-
- if (parport[0] != -1) {
- /* The user gave specific instructions */
- int i, found = 0;
-
- for (i = 0; i < MAX_CAMS && parport[i] != -1; i++) {
- if (parport[0] == port->number)
- found = 1;
- }
- if (!found)
- return -ENODEV;
- }
-
- if (num_cams == MAX_CAMS)
- return -ENOSPC;
-
- qcam = qcam_init(port);
- if (qcam == NULL)
- return -ENODEV;
-
- v4l2_dev = &qcam->v4l2_dev;
-
- parport_claim_or_block(qcam->pdev);
-
- qc_reset(qcam);
-
- if (probe && qc_detect(qcam) == 0) {
- parport_release(qcam->pdev);
- parport_unregister_device(qcam->pdev);
- kfree(qcam);
- return -ENODEV;
- }
-
- qc_setup(qcam);
-
- parport_release(qcam->pdev);
-
- if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
- qcam->pport->name);
- parport_unregister_device(qcam->pdev);
- kfree(qcam);
- return -ENODEV;
- }
-
- v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
- video_device_node_name(&qcam->vdev), qcam->pport->name);
-
- qcams[num_cams++] = qcam;
-
- return 0;
-}
-
-static void close_cqcam(struct qcam *qcam)
-{
- video_unregister_device(&qcam->vdev);
- v4l2_ctrl_handler_free(&qcam->hdl);
- parport_unregister_device(qcam->pdev);
- kfree(qcam);
-}
-
-static void cq_attach(struct parport *port)
-{
- init_cqcam(port);
-}
-
-static void cq_detach(struct parport *port)
-{
- /* Write this some day. */
-}
-
-static struct parport_driver cqcam_driver = {
- .name = "cqcam",
- .attach = cq_attach,
- .detach = cq_detach,
-};
-
-static int __init cqcam_init(void)
-{
- printk(KERN_INFO BANNER "\n");
-
- return parport_register_driver(&cqcam_driver);
-}
-
-static void __exit cqcam_cleanup(void)
-{
- unsigned int i;
-
- for (i = 0; i < num_cams; i++)
- close_cqcam(qcams[i]);
-
- parport_unregister_driver(&cqcam_driver);
-}
-
-MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
-MODULE_DESCRIPTION(BANNER);
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.4");
-
-module_init(cqcam_init);
-module_exit(cqcam_cleanup);
diff --git a/drivers/staging/media/parport/pms.c b/drivers/staging/media/parport/pms.c
deleted file mode 100644
index e6b497528cea..000000000000
--- a/drivers/staging/media/parport/pms.c
+++ /dev/null
@@ -1,1156 +0,0 @@
-/*
- * Media Vision Pro Movie Studio
- * or
- * "all you need is an I2C bus some RAM and a prayer"
- *
- * This draws heavily on code
- *
- * (c) Wolfgang Koehler, wolf@first.gmd.de, Dec. 1994
- * Kiefernring 15
- * 14478 Potsdam, Germany
- *
- * Most of this code is directly derived from his userspace driver.
- * His driver works so send any reports to alan@lxorguk.ukuu.org.uk
- * unless the userspace driver also doesn't work for you...
- *
- * Changes:
- * 25-11-2009 Hans Verkuil <hverkuil@xs4all.nl>
- * - converted to version 2 of the V4L API.
- * 08/07/2003 Daniele Bellucci <bellucda@tiscali.it>
- * - pms_capture: report back -EFAULT
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/mutex.h>
-#include <linux/uaccess.h>
-#include <linux/isa.h>
-#include <asm/io.h>
-
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-device.h>
-
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.5");
-
-#define MOTOROLA 1
-#define PHILIPS2 2 /* SAA7191 */
-#define PHILIPS1 3
-#define MVVMEMORYWIDTH 0x40 /* 512 bytes */
-
-struct i2c_info {
- u8 slave;
- u8 sub;
- u8 data;
- u8 hits;
-};
-
-struct pms {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct v4l2_ctrl_handler hdl;
- int height;
- int width;
- int depth;
- int input;
- struct mutex lock;
- int i2c_count;
- struct i2c_info i2cinfo[64];
-
- int decoder;
- int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
- v4l2_std_id std;
- int io;
- int data;
- void __iomem *mem;
-};
-
-/*
- * I/O ports and Shared Memory
- */
-
-static int io_port = 0x250;
-module_param(io_port, int, 0);
-
-static int mem_base = 0xc8000;
-module_param(mem_base, int, 0);
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-
-
-static inline void mvv_write(struct pms *dev, u8 index, u8 value)
-{
- outw(index | (value << 8), dev->io);
-}
-
-static inline u8 mvv_read(struct pms *dev, u8 index)
-{
- outb(index, dev->io);
- return inb(dev->data);
-}
-
-static int pms_i2c_stat(struct pms *dev, u8 slave)
-{
- int counter = 0;
- int i;
-
- outb(0x28, dev->io);
-
- while ((inb(dev->data) & 0x01) == 0)
- if (counter++ == 256)
- break;
-
- while ((inb(dev->data) & 0x01) != 0)
- if (counter++ == 256)
- break;
-
- outb(slave, dev->io);
-
- counter = 0;
- while ((inb(dev->data) & 0x01) == 0)
- if (counter++ == 256)
- break;
-
- while ((inb(dev->data) & 0x01) != 0)
- if (counter++ == 256)
- break;
-
- for (i = 0; i < 12; i++) {
- char st = inb(dev->data);
-
- if ((st & 2) != 0)
- return -1;
- if ((st & 1) == 0)
- break;
- }
- outb(0x29, dev->io);
- return inb(dev->data);
-}
-
-static int pms_i2c_write(struct pms *dev, u16 slave, u16 sub, u16 data)
-{
- int skip = 0;
- int count;
- int i;
-
- for (i = 0; i < dev->i2c_count; i++) {
- if ((dev->i2cinfo[i].slave == slave) &&
- (dev->i2cinfo[i].sub == sub)) {
- if (dev->i2cinfo[i].data == data)
- skip = 1;
- dev->i2cinfo[i].data = data;
- i = dev->i2c_count + 1;
- }
- }
-
- if (i == dev->i2c_count && dev->i2c_count < 64) {
- dev->i2cinfo[dev->i2c_count].slave = slave;
- dev->i2cinfo[dev->i2c_count].sub = sub;
- dev->i2cinfo[dev->i2c_count].data = data;
- dev->i2c_count++;
- }
-
- if (skip)
- return 0;
-
- mvv_write(dev, 0x29, sub);
- mvv_write(dev, 0x2A, data);
- mvv_write(dev, 0x28, slave);
-
- outb(0x28, dev->io);
-
- count = 0;
- while ((inb(dev->data) & 1) == 0)
- if (count > 255)
- break;
- while ((inb(dev->data) & 1) != 0)
- if (count > 255)
- break;
-
- count = inb(dev->data);
-
- if (count & 2)
- return -1;
- return count;
-}
-
-static int pms_i2c_read(struct pms *dev, int slave, int sub)
-{
- int i;
-
- for (i = 0; i < dev->i2c_count; i++) {
- if (dev->i2cinfo[i].slave == slave && dev->i2cinfo[i].sub == sub)
- return dev->i2cinfo[i].data;
- }
- return 0;
-}
-
-
-static void pms_i2c_andor(struct pms *dev, int slave, int sub, int and, int or)
-{
- u8 tmp;
-
- tmp = pms_i2c_read(dev, slave, sub);
- tmp = (tmp & and) | or;
- pms_i2c_write(dev, slave, sub, tmp);
-}
-
-/*
- * Control functions
- */
-
-
-static void pms_videosource(struct pms *dev, short source)
-{
- switch (dev->decoder) {
- case MOTOROLA:
- break;
- case PHILIPS2:
- pms_i2c_andor(dev, 0x8a, 0x06, 0x7f, source ? 0x80 : 0);
- break;
- case PHILIPS1:
- break;
- }
- mvv_write(dev, 0x2E, 0x31);
- /* Was: mvv_write(dev, 0x2E, source ? 0x31 : 0x30);
- But could not make this work correctly. Only Composite input
- worked for me. */
-}
-
-static void pms_hue(struct pms *dev, short hue)
-{
- switch (dev->decoder) {
- case MOTOROLA:
- pms_i2c_write(dev, 0x8a, 0x00, hue);
- break;
- case PHILIPS2:
- pms_i2c_write(dev, 0x8a, 0x07, hue);
- break;
- case PHILIPS1:
- pms_i2c_write(dev, 0x42, 0x07, hue);
- break;
- }
-}
-
-static void pms_saturation(struct pms *dev, short sat)
-{
- switch (dev->decoder) {
- case MOTOROLA:
- pms_i2c_write(dev, 0x8a, 0x00, sat);
- break;
- case PHILIPS1:
- pms_i2c_write(dev, 0x42, 0x12, sat);
- break;
- }
-}
-
-
-static void pms_contrast(struct pms *dev, short contrast)
-{
- switch (dev->decoder) {
- case MOTOROLA:
- pms_i2c_write(dev, 0x8a, 0x00, contrast);
- break;
- case PHILIPS1:
- pms_i2c_write(dev, 0x42, 0x13, contrast);
- break;
- }
-}
-
-static void pms_brightness(struct pms *dev, short brightness)
-{
- switch (dev->decoder) {
- case MOTOROLA:
- pms_i2c_write(dev, 0x8a, 0x00, brightness);
- pms_i2c_write(dev, 0x8a, 0x00, brightness);
- pms_i2c_write(dev, 0x8a, 0x00, brightness);
- break;
- case PHILIPS1:
- pms_i2c_write(dev, 0x42, 0x19, brightness);
- break;
- }
-}
-
-
-static void pms_format(struct pms *dev, short format)
-{
- int target;
-
- dev->standard = format;
-
- if (dev->decoder == PHILIPS1)
- target = 0x42;
- else if (dev->decoder == PHILIPS2)
- target = 0x8a;
- else
- return;
-
- switch (format) {
- case 0: /* Auto */
- pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
- pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x80);
- break;
- case 1: /* NTSC */
- pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
- pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x40);
- break;
- case 2: /* PAL */
- pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x00);
- pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
- break;
- case 3: /* SECAM */
- pms_i2c_andor(dev, target, 0x0d, 0xfe, 0x01);
- pms_i2c_andor(dev, target, 0x0f, 0x3f, 0x00);
- break;
- }
-}
-
-#ifdef FOR_FUTURE_EXPANSION
-
-/*
- * These features of the PMS card are not currently exposes. They
- * could become a private v4l ioctl for PMSCONFIG or somesuch if
- * people need it. We also don't yet use the PMS interrupt.
- */
-
-static void pms_hstart(struct pms *dev, short start)
-{
- switch (dev->decoder) {
- case PHILIPS1:
- pms_i2c_write(dev, 0x8a, 0x05, start);
- pms_i2c_write(dev, 0x8a, 0x18, start);
- break;
- case PHILIPS2:
- pms_i2c_write(dev, 0x42, 0x05, start);
- pms_i2c_write(dev, 0x42, 0x18, start);
- break;
- }
-}
-
-/*
- * Bandpass filters
- */
-
-static void pms_bandpass(struct pms *dev, short pass)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x06, 0xcf, (pass & 0x03) << 4);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x06, 0xcf, (pass & 0x03) << 4);
-}
-
-static void pms_antisnow(struct pms *dev, short snow)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x06, 0xf3, (snow & 0x03) << 2);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x06, 0xf3, (snow & 0x03) << 2);
-}
-
-static void pms_sharpness(struct pms *dev, short sharp)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x06, 0xfc, sharp & 0x03);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x06, 0xfc, sharp & 0x03);
-}
-
-static void pms_chromaagc(struct pms *dev, short agc)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x0c, 0x9f, (agc & 0x03) << 5);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x0c, 0x9f, (agc & 0x03) << 5);
-}
-
-static void pms_vertnoise(struct pms *dev, short noise)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x10, 0xfc, noise & 3);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x10, 0xfc, noise & 3);
-}
-
-static void pms_forcecolour(struct pms *dev, short colour)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x0c, 0x7f, (colour & 1) << 7);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x0c, 0x7, (colour & 1) << 7);
-}
-
-static void pms_antigamma(struct pms *dev, short gamma)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0xb8, 0x00, 0x7f, (gamma & 1) << 7);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x20, 0x7, (gamma & 1) << 7);
-}
-
-static void pms_prefilter(struct pms *dev, short filter)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x06, 0xbf, (filter & 1) << 6);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x06, 0xbf, (filter & 1) << 6);
-}
-
-static void pms_hfilter(struct pms *dev, short filter)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0xb8, 0x04, 0x1f, (filter & 7) << 5);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x24, 0x1f, (filter & 7) << 5);
-}
-
-static void pms_vfilter(struct pms *dev, short filter)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0xb8, 0x08, 0x9f, (filter & 3) << 5);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x28, 0x9f, (filter & 3) << 5);
-}
-
-static void pms_killcolour(struct pms *dev, short colour)
-{
- if (dev->decoder == PHILIPS2) {
- pms_i2c_andor(dev, 0x8a, 0x08, 0x07, (colour & 0x1f) << 3);
- pms_i2c_andor(dev, 0x8a, 0x09, 0x07, (colour & 0x1f) << 3);
- } else if (dev->decoder == PHILIPS1) {
- pms_i2c_andor(dev, 0x42, 0x08, 0x07, (colour & 0x1f) << 3);
- pms_i2c_andor(dev, 0x42, 0x09, 0x07, (colour & 0x1f) << 3);
- }
-}
-
-static void pms_chromagain(struct pms *dev, short chroma)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_write(dev, 0x8a, 0x11, chroma);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_write(dev, 0x42, 0x11, chroma);
-}
-
-
-static void pms_spacialcompl(struct pms *dev, short data)
-{
- mvv_write(dev, 0x3b, data);
-}
-
-static void pms_spacialcomph(struct pms *dev, short data)
-{
- mvv_write(dev, 0x3a, data);
-}
-
-static void pms_vstart(struct pms *dev, short start)
-{
- mvv_write(dev, 0x16, start);
- mvv_write(dev, 0x17, (start >> 8) & 0x01);
-}
-
-#endif
-
-static void pms_secamcross(struct pms *dev, short cross)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x0f, 0xdf, (cross & 1) << 5);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x0f, 0xdf, (cross & 1) << 5);
-}
-
-
-static void pms_swsense(struct pms *dev, short sense)
-{
- if (dev->decoder == PHILIPS2) {
- pms_i2c_write(dev, 0x8a, 0x0a, sense);
- pms_i2c_write(dev, 0x8a, 0x0b, sense);
- } else if (dev->decoder == PHILIPS1) {
- pms_i2c_write(dev, 0x42, 0x0a, sense);
- pms_i2c_write(dev, 0x42, 0x0b, sense);
- }
-}
-
-
-static void pms_framerate(struct pms *dev, short frr)
-{
- int fps = (dev->std & V4L2_STD_525_60) ? 30 : 25;
-
- if (frr == 0)
- return;
- fps = fps/frr;
- mvv_write(dev, 0x14, 0x80 | fps);
- mvv_write(dev, 0x15, 1);
-}
-
-static void pms_vert(struct pms *dev, u8 deciden, u8 decinum)
-{
- mvv_write(dev, 0x1c, deciden); /* Denominator */
- mvv_write(dev, 0x1d, decinum); /* Numerator */
-}
-
-/*
- * Turn 16bit ratios into best small ratio the chipset can grok
- */
-
-static void pms_vertdeci(struct pms *dev, unsigned short decinum, unsigned short deciden)
-{
- /* Knock it down by / 5 once */
- if (decinum % 5 == 0) {
- deciden /= 5;
- decinum /= 5;
- }
- /*
- * 3's
- */
- while (decinum % 3 == 0 && deciden % 3 == 0) {
- deciden /= 3;
- decinum /= 3;
- }
- /*
- * 2's
- */
- while (decinum % 2 == 0 && deciden % 2 == 0) {
- decinum /= 2;
- deciden /= 2;
- }
- /*
- * Fudgyify
- */
- while (deciden > 32) {
- deciden /= 2;
- decinum = (decinum + 1) / 2;
- }
- if (deciden == 32)
- deciden--;
- pms_vert(dev, deciden, decinum);
-}
-
-static void pms_horzdeci(struct pms *dev, short decinum, short deciden)
-{
- if (decinum <= 512) {
- if (decinum % 5 == 0) {
- decinum /= 5;
- deciden /= 5;
- }
- } else {
- decinum = 512;
- deciden = 640; /* 768 would be ideal */
- }
-
- while (((decinum | deciden) & 1) == 0) {
- decinum >>= 1;
- deciden >>= 1;
- }
- while (deciden > 32) {
- deciden >>= 1;
- decinum = (decinum + 1) >> 1;
- }
- if (deciden == 32)
- deciden--;
-
- mvv_write(dev, 0x24, 0x80 | deciden);
- mvv_write(dev, 0x25, decinum);
-}
-
-static void pms_resolution(struct pms *dev, short width, short height)
-{
- int fg_height;
-
- fg_height = height;
- if (fg_height > 280)
- fg_height = 280;
-
- mvv_write(dev, 0x18, fg_height);
- mvv_write(dev, 0x19, fg_height >> 8);
-
- if (dev->std & V4L2_STD_525_60) {
- mvv_write(dev, 0x1a, 0xfc);
- mvv_write(dev, 0x1b, 0x00);
- if (height > fg_height)
- pms_vertdeci(dev, 240, 240);
- else
- pms_vertdeci(dev, fg_height, 240);
- } else {
- mvv_write(dev, 0x1a, 0x1a);
- mvv_write(dev, 0x1b, 0x01);
- if (fg_height > 256)
- pms_vertdeci(dev, 270, 270);
- else
- pms_vertdeci(dev, fg_height, 270);
- }
- mvv_write(dev, 0x12, 0);
- mvv_write(dev, 0x13, MVVMEMORYWIDTH);
- mvv_write(dev, 0x42, 0x00);
- mvv_write(dev, 0x43, 0x00);
- mvv_write(dev, 0x44, MVVMEMORYWIDTH);
-
- mvv_write(dev, 0x22, width + 8);
- mvv_write(dev, 0x23, (width + 8) >> 8);
-
- if (dev->std & V4L2_STD_525_60)
- pms_horzdeci(dev, width, 640);
- else
- pms_horzdeci(dev, width + 8, 768);
-
- mvv_write(dev, 0x30, mvv_read(dev, 0x30) & 0xfe);
- mvv_write(dev, 0x08, mvv_read(dev, 0x08) | 0x01);
- mvv_write(dev, 0x01, mvv_read(dev, 0x01) & 0xfd);
- mvv_write(dev, 0x32, 0x00);
- mvv_write(dev, 0x33, MVVMEMORYWIDTH);
-}
-
-
-/*
- * Set Input
- */
-
-static void pms_vcrinput(struct pms *dev, short input)
-{
- if (dev->decoder == PHILIPS2)
- pms_i2c_andor(dev, 0x8a, 0x0d, 0x7f, (input & 1) << 7);
- else if (dev->decoder == PHILIPS1)
- pms_i2c_andor(dev, 0x42, 0x0d, 0x7f, (input & 1) << 7);
-}
-
-
-static int pms_capture(struct pms *dev, char __user *buf, int rgb555, int count)
-{
- int y;
- int dw = 2 * dev->width;
- char *tmp; /* using a temp buffer is faster than direct */
- int cnt = 0;
- int len = 0;
- unsigned char r8 = 0x5; /* value for reg8 */
-
- tmp = kmalloc(dw + 32, GFP_KERNEL);
- if (!tmp)
- return 0;
-
- if (rgb555)
- r8 |= 0x20; /* else use untranslated rgb = 565 */
- mvv_write(dev, 0x08, r8); /* capture rgb555/565, init DRAM, PC enable */
-
-/* printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
-
- for (y = 0; y < dev->height; y++) {
- writeb(0, dev->mem); /* synchronisiert neue Zeile */
-
- /*
- * This is in truth a fifo, be very careful as if you
- * forgot this odd things will occur 8)
- */
-
- memcpy_fromio(tmp, dev->mem, dw + 32); /* discard 16 word */
- cnt -= dev->height;
- while (cnt <= 0) {
- /*
- * Don't copy too far
- */
- int dt = dw;
- if (dt + len > count)
- dt = count - len;
- cnt += dev->height;
- if (copy_to_user(buf, tmp + 32, dt))
- return len ? len : -EFAULT;
- buf += dt;
- len += dt;
- }
- }
- kfree(tmp);
- return len;
-}
-
-
-/*
- * Video4linux interfacing
- */
-
-static int pms_querycap(struct file *file, void *priv,
- struct v4l2_capability *vcap)
-{
- struct pms *dev = video_drvdata(file);
-
- strlcpy(vcap->driver, dev->v4l2_dev.name, sizeof(vcap->driver));
- strlcpy(vcap->card, "Mediavision PMS", sizeof(vcap->card));
- snprintf(vcap->bus_info, sizeof(vcap->bus_info),
- "ISA:%s", dev->v4l2_dev.name);
- vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
- vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int pms_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
-{
- static const char *inputs[4] = {
- "Composite",
- "S-Video",
- "Composite (VCR)",
- "S-Video (VCR)"
- };
-
- if (vin->index > 3)
- return -EINVAL;
- strlcpy(vin->name, inputs[vin->index], sizeof(vin->name));
- vin->type = V4L2_INPUT_TYPE_CAMERA;
- vin->audioset = 0;
- vin->tuner = 0;
- vin->std = V4L2_STD_ALL;
- vin->status = 0;
- return 0;
-}
-
-static int pms_g_input(struct file *file, void *fh, unsigned int *inp)
-{
- struct pms *dev = video_drvdata(file);
-
- *inp = dev->input;
- return 0;
-}
-
-static int pms_s_input(struct file *file, void *fh, unsigned int inp)
-{
- struct pms *dev = video_drvdata(file);
-
- if (inp > 3)
- return -EINVAL;
-
- dev->input = inp;
- pms_videosource(dev, inp & 1);
- pms_vcrinput(dev, inp >> 1);
- return 0;
-}
-
-static int pms_g_std(struct file *file, void *fh, v4l2_std_id *std)
-{
- struct pms *dev = video_drvdata(file);
-
- *std = dev->std;
- return 0;
-}
-
-static int pms_s_std(struct file *file, void *fh, v4l2_std_id std)
-{
- struct pms *dev = video_drvdata(file);
- int ret = 0;
-
- dev->std = std;
- if (dev->std & V4L2_STD_NTSC) {
- pms_framerate(dev, 30);
- pms_secamcross(dev, 0);
- pms_format(dev, 1);
- } else if (dev->std & V4L2_STD_PAL) {
- pms_framerate(dev, 25);
- pms_secamcross(dev, 0);
- pms_format(dev, 2);
- } else if (dev->std & V4L2_STD_SECAM) {
- pms_framerate(dev, 25);
- pms_secamcross(dev, 1);
- pms_format(dev, 2);
- } else {
- ret = -EINVAL;
- }
- /*
- switch (v->mode) {
- case VIDEO_MODE_AUTO:
- pms_framerate(dev, 25);
- pms_secamcross(dev, 0);
- pms_format(dev, 0);
- break;
- }*/
- return ret;
-}
-
-static int pms_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct pms *dev = container_of(ctrl->handler, struct pms, hdl);
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- pms_brightness(dev, ctrl->val);
- break;
- case V4L2_CID_CONTRAST:
- pms_contrast(dev, ctrl->val);
- break;
- case V4L2_CID_SATURATION:
- pms_saturation(dev, ctrl->val);
- break;
- case V4L2_CID_HUE:
- pms_hue(dev, ctrl->val);
- break;
- default:
- ret = -EINVAL;
- break;
- }
- return ret;
-}
-
-static int pms_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct pms *dev = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- pix->width = dev->width;
- pix->height = dev->height;
- pix->pixelformat = dev->width == 15 ?
- V4L2_PIX_FMT_RGB555 : V4L2_PIX_FMT_RGB565;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = 2 * dev->width;
- pix->sizeimage = 2 * dev->width * dev->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int pms_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- if (pix->height < 16 || pix->height > 480)
- return -EINVAL;
- if (pix->width < 16 || pix->width > 640)
- return -EINVAL;
- if (pix->pixelformat != V4L2_PIX_FMT_RGB555 &&
- pix->pixelformat != V4L2_PIX_FMT_RGB565)
- return -EINVAL;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = 2 * pix->width;
- pix->sizeimage = 2 * pix->width * pix->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- return 0;
-}
-
-static int pms_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct pms *dev = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
- int ret = pms_try_fmt_vid_cap(file, fh, fmt);
-
- if (ret)
- return ret;
- dev->width = pix->width;
- dev->height = pix->height;
- dev->depth = (pix->pixelformat == V4L2_PIX_FMT_RGB555) ? 15 : 16;
- pms_resolution(dev, dev->width, dev->height);
- /* Ok we figured out what to use from our wide choice */
- return 0;
-}
-
-static int pms_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
-{
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "RGB 5:5:5", V4L2_PIX_FMT_RGB555,
- { 0, 0, 0, 0 }
- },
- { 1, 0, 0,
- "RGB 5:6:5", V4L2_PIX_FMT_RGB565,
- { 0, 0, 0, 0 }
- },
- };
- enum v4l2_buf_type type = fmt->type;
-
- if (fmt->index > 1)
- return -EINVAL;
-
- *fmt = formats[fmt->index];
- fmt->type = type;
- return 0;
-}
-
-static ssize_t pms_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct pms *dev = video_drvdata(file);
- int len;
-
- len = pms_capture(dev, buf, (dev->depth == 15), count);
- return len;
-}
-
-static unsigned int pms_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct v4l2_fh *fh = file->private_data;
- unsigned int res = POLLIN | POLLRDNORM;
-
- if (v4l2_event_pending(fh))
- res |= POLLPRI;
- poll_wait(file, &fh->wait, wait);
- return res;
-}
-
-static const struct v4l2_file_operations pms_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = v4l2_fh_release,
- .poll = pms_poll,
- .unlocked_ioctl = video_ioctl2,
- .read = pms_read,
-};
-
-static const struct v4l2_ioctl_ops pms_ioctl_ops = {
- .vidioc_querycap = pms_querycap,
- .vidioc_g_input = pms_g_input,
- .vidioc_s_input = pms_s_input,
- .vidioc_enum_input = pms_enum_input,
- .vidioc_g_std = pms_g_std,
- .vidioc_s_std = pms_s_std,
- .vidioc_enum_fmt_vid_cap = pms_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = pms_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = pms_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = pms_try_fmt_vid_cap,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-/*
- * Probe for and initialise the Mediavision PMS
- */
-
-static int init_mediavision(struct pms *dev)
-{
- int idec, decst;
- int i;
- static const unsigned char i2c_defs[] = {
- 0x4c, 0x30, 0x00, 0xe8,
- 0xb6, 0xe2, 0x00, 0x00,
- 0xff, 0xff, 0x00, 0x00,
- 0x00, 0x00, 0x78, 0x98,
- 0x00, 0x00, 0x00, 0x00,
- 0x34, 0x0a, 0xf4, 0xce,
- 0xe4
- };
-
- dev->mem = ioremap(mem_base, 0x800);
- if (!dev->mem)
- return -ENOMEM;
-
- if (!request_region(0x9a01, 1, "Mediavision PMS config")) {
- printk(KERN_WARNING "mediavision: unable to detect: 0x9a01 in use.\n");
- iounmap(dev->mem);
- return -EBUSY;
- }
- if (!request_region(dev->io, 3, "Mediavision PMS")) {
- printk(KERN_WARNING "mediavision: I/O port %d in use.\n", dev->io);
- release_region(0x9a01, 1);
- iounmap(dev->mem);
- return -EBUSY;
- }
- outb(0xb8, 0x9a01); /* Unlock */
- outb(dev->io >> 4, 0x9a01); /* Set IO port */
-
-
- decst = pms_i2c_stat(dev, 0x43);
-
- if (decst != -1)
- idec = 2;
- else if (pms_i2c_stat(dev, 0xb9) != -1)
- idec = 3;
- else if (pms_i2c_stat(dev, 0x8b) != -1)
- idec = 1;
- else
- idec = 0;
-
- printk(KERN_INFO "PMS type is %d\n", idec);
- if (idec == 0) {
- release_region(dev->io, 3);
- release_region(0x9a01, 1);
- iounmap(dev->mem);
- return -ENODEV;
- }
-
- /*
- * Ok we have a PMS of some sort
- */
-
- mvv_write(dev, 0x04, mem_base >> 12); /* Set the memory area */
-
- /* Ok now load the defaults */
-
- for (i = 0; i < 0x19; i++) {
- if (i2c_defs[i] == 0xff)
- pms_i2c_andor(dev, 0x8a, i, 0x07, 0x00);
- else
- pms_i2c_write(dev, 0x8a, i, i2c_defs[i]);
- }
-
- pms_i2c_write(dev, 0xb8, 0x00, 0x12);
- pms_i2c_write(dev, 0xb8, 0x04, 0x00);
- pms_i2c_write(dev, 0xb8, 0x07, 0x00);
- pms_i2c_write(dev, 0xb8, 0x08, 0x00);
- pms_i2c_write(dev, 0xb8, 0x09, 0xff);
- pms_i2c_write(dev, 0xb8, 0x0a, 0x00);
- pms_i2c_write(dev, 0xb8, 0x0b, 0x10);
- pms_i2c_write(dev, 0xb8, 0x10, 0x03);
-
- mvv_write(dev, 0x01, 0x00);
- mvv_write(dev, 0x05, 0xa0);
- mvv_write(dev, 0x08, 0x25);
- mvv_write(dev, 0x09, 0x00);
- mvv_write(dev, 0x0a, 0x20 | MVVMEMORYWIDTH);
-
- mvv_write(dev, 0x10, 0x02);
- mvv_write(dev, 0x1e, 0x0c);
- mvv_write(dev, 0x1f, 0x03);
- mvv_write(dev, 0x26, 0x06);
-
- mvv_write(dev, 0x2b, 0x00);
- mvv_write(dev, 0x2c, 0x20);
- mvv_write(dev, 0x2d, 0x00);
- mvv_write(dev, 0x2f, 0x70);
- mvv_write(dev, 0x32, 0x00);
- mvv_write(dev, 0x33, MVVMEMORYWIDTH);
- mvv_write(dev, 0x34, 0x00);
- mvv_write(dev, 0x35, 0x00);
- mvv_write(dev, 0x3a, 0x80);
- mvv_write(dev, 0x3b, 0x10);
- mvv_write(dev, 0x20, 0x00);
- mvv_write(dev, 0x21, 0x00);
- mvv_write(dev, 0x30, 0x22);
- return 0;
-}
-
-/*
- * Initialization and module stuff
- */
-
-#ifndef MODULE
-static int enable;
-module_param(enable, int, 0);
-#endif
-
-static const struct v4l2_ctrl_ops pms_ctrl_ops = {
- .s_ctrl = pms_s_ctrl,
-};
-
-static int pms_probe(struct device *pdev, unsigned int card)
-{
- struct pms *dev;
- struct v4l2_device *v4l2_dev;
- struct v4l2_ctrl_handler *hdl;
- int res;
-
-#ifndef MODULE
- if (!enable) {
- pr_err("PMS: not enabled, use pms.enable=1 to probe\n");
- return -ENODEV;
- }
-#endif
-
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (dev == NULL)
- return -ENOMEM;
-
- dev->decoder = PHILIPS2;
- dev->io = io_port;
- dev->data = io_port + 1;
- v4l2_dev = &dev->v4l2_dev;
- hdl = &dev->hdl;
-
- res = v4l2_device_register(pdev, v4l2_dev);
- if (res < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- goto free_dev;
- }
- v4l2_info(v4l2_dev, "Mediavision Pro Movie Studio driver 0.05\n");
-
- res = init_mediavision(dev);
- if (res) {
- v4l2_err(v4l2_dev, "Board not found.\n");
- goto free_io;
- }
-
- v4l2_ctrl_handler_init(hdl, 4);
- v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 139);
- v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
- V4L2_CID_CONTRAST, 0, 255, 1, 70);
- v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
- V4L2_CID_SATURATION, 0, 255, 1, 64);
- v4l2_ctrl_new_std(hdl, &pms_ctrl_ops,
- V4L2_CID_HUE, 0, 255, 1, 0);
- if (hdl->error) {
- res = hdl->error;
- goto free_hdl;
- }
-
- mutex_init(&dev->lock);
- strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
- dev->vdev.v4l2_dev = v4l2_dev;
- dev->vdev.ctrl_handler = hdl;
- dev->vdev.fops = &pms_fops;
- dev->vdev.ioctl_ops = &pms_ioctl_ops;
- dev->vdev.release = video_device_release_empty;
- dev->vdev.lock = &dev->lock;
- dev->vdev.tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
- video_set_drvdata(&dev->vdev, dev);
- dev->std = V4L2_STD_NTSC_M;
- dev->height = 240;
- dev->width = 320;
- dev->depth = 16;
- pms_swsense(dev, 75);
- pms_resolution(dev, 320, 240);
- pms_videosource(dev, 0);
- pms_vcrinput(dev, 0);
- v4l2_ctrl_handler_setup(hdl);
- res = video_register_device(&dev->vdev, VFL_TYPE_GRABBER, video_nr);
- if (res >= 0)
- return 0;
-
-free_hdl:
- v4l2_ctrl_handler_free(hdl);
- v4l2_device_unregister(&dev->v4l2_dev);
-free_io:
- release_region(dev->io, 3);
- release_region(0x9a01, 1);
- iounmap(dev->mem);
-free_dev:
- kfree(dev);
- return res;
-}
-
-static int pms_remove(struct device *pdev, unsigned int card)
-{
- struct pms *dev = dev_get_drvdata(pdev);
-
- video_unregister_device(&dev->vdev);
- v4l2_ctrl_handler_free(&dev->hdl);
- release_region(dev->io, 3);
- release_region(0x9a01, 1);
- iounmap(dev->mem);
- return 0;
-}
-
-static struct isa_driver pms_driver = {
- .probe = pms_probe,
- .remove = pms_remove,
- .driver = {
- .name = "pms",
- },
-};
-
-static int __init pms_init(void)
-{
- return isa_register_driver(&pms_driver, 1);
-}
-
-static void __exit pms_exit(void)
-{
- isa_unregister_driver(&pms_driver);
-}
-
-module_init(pms_init);
-module_exit(pms_exit);
diff --git a/drivers/staging/media/parport/w9966.c b/drivers/staging/media/parport/w9966.c
deleted file mode 100644
index f7502f3a6a3c..000000000000
--- a/drivers/staging/media/parport/w9966.c
+++ /dev/null
@@ -1,980 +0,0 @@
-/*
- Winbond w9966cf Webcam parport driver.
-
- Version 0.33
-
- Copyright (C) 2001 Jakob Kemi <jakob.kemi@post.utfors.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.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
-*/
-/*
- Supported devices:
- *Lifeview FlyCam Supra (using the Philips saa7111a chip)
-
- Does any other model using the w9966 interface chip exist ?
-
- Todo:
-
- *Add a working EPP mode, since DMA ECP read isn't implemented
- in the parport drivers. (That's why it's so sloow)
-
- *Add support for other ccd-control chips than the saa7111
- please send me feedback on what kind of chips you have.
-
- *Add proper probing. I don't know what's wrong with the IEEE1284
- parport drivers but (IEEE1284_MODE_NIBBLE|IEEE1284_DEVICE_ID)
- and nibble read seems to be broken for some peripherals.
-
- *Add probing for onboard SRAM, port directions etc. (if possible)
-
- *Add support for the hardware compressed modes (maybe using v4l2)
-
- *Fix better support for the capture window (no skewed images, v4l
- interface to capt. window)
-
- *Probably some bugs that I don't know of
-
- Please support me by sending feedback!
-
- Changes:
-
- Alan Cox: Removed RGB mode for kernel merge, added THIS_MODULE
- and owner support for newer module locks
-*/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-fh.h>
-#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
-#include <linux/parport.h>
-
-/*#define DEBUG*/ /* Undef me for production */
-
-#ifdef DEBUG
-#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
-#else
-#define DPRINTF(x...)
-#endif
-
-/*
- * Defines, simple typedefs etc.
- */
-
-#define W9966_DRIVERNAME "W9966CF Webcam"
-#define W9966_MAXCAMS 4 /* Maximum number of cameras */
-#define W9966_RBUFFER 2048 /* Read buffer (must be an even number) */
-#define W9966_SRAMSIZE 131072 /* 128kb */
-#define W9966_SRAMID 0x02 /* check w9966cf.pdf */
-
-/* Empirically determined window limits */
-#define W9966_WND_MIN_X 16
-#define W9966_WND_MIN_Y 14
-#define W9966_WND_MAX_X 705
-#define W9966_WND_MAX_Y 253
-#define W9966_WND_MAX_W (W9966_WND_MAX_X - W9966_WND_MIN_X)
-#define W9966_WND_MAX_H (W9966_WND_MAX_Y - W9966_WND_MIN_Y)
-
-/* Keep track of our current state */
-#define W9966_STATE_PDEV 0x01
-#define W9966_STATE_CLAIMED 0x02
-#define W9966_STATE_VDEV 0x04
-
-#define W9966_I2C_W_ID 0x48
-#define W9966_I2C_R_ID 0x49
-#define W9966_I2C_R_DATA 0x08
-#define W9966_I2C_R_CLOCK 0x04
-#define W9966_I2C_W_DATA 0x02
-#define W9966_I2C_W_CLOCK 0x01
-
-struct w9966 {
- struct v4l2_device v4l2_dev;
- struct v4l2_ctrl_handler hdl;
- unsigned char dev_state;
- unsigned char i2c_state;
- unsigned short ppmode;
- struct parport *pport;
- struct pardevice *pdev;
- struct video_device vdev;
- unsigned short width;
- unsigned short height;
- unsigned char brightness;
- signed char contrast;
- signed char color;
- signed char hue;
- struct mutex lock;
-};
-
-/*
- * Module specific properties
- */
-
-MODULE_AUTHOR("Jakob Kemi <jakob.kemi@post.utfors.se>");
-MODULE_DESCRIPTION("Winbond w9966cf WebCam driver (0.32)");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.33.1");
-
-#ifdef MODULE
-static char *pardev[] = {[0 ... W9966_MAXCAMS] = ""};
-#else
-static char *pardev[] = {[0 ... W9966_MAXCAMS] = "aggressive"};
-#endif
-module_param_array(pardev, charp, NULL, 0);
-MODULE_PARM_DESC(pardev, "pardev: where to search for\n"
- "\teach camera. 'aggressive' means brute-force search.\n"
- "\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n"
- "\tcam 1 to parport3 and search every parport for cam 2 etc...");
-
-static int parmode;
-module_param(parmode, int, 0);
-MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-
-static struct w9966 w9966_cams[W9966_MAXCAMS];
-
-/*
- * Private function defines
- */
-
-
-/* Set camera phase flags, so we know what to uninit when terminating */
-static inline void w9966_set_state(struct w9966 *cam, int mask, int val)
-{
- cam->dev_state = (cam->dev_state & ~mask) ^ val;
-}
-
-/* Get camera phase flags */
-static inline int w9966_get_state(struct w9966 *cam, int mask, int val)
-{
- return ((cam->dev_state & mask) == val);
-}
-
-/* Claim parport for ourself */
-static void w9966_pdev_claim(struct w9966 *cam)
-{
- if (w9966_get_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED))
- return;
- parport_claim_or_block(cam->pdev);
- w9966_set_state(cam, W9966_STATE_CLAIMED, W9966_STATE_CLAIMED);
-}
-
-/* Release parport for others to use */
-static void w9966_pdev_release(struct w9966 *cam)
-{
- if (w9966_get_state(cam, W9966_STATE_CLAIMED, 0))
- return;
- parport_release(cam->pdev);
- w9966_set_state(cam, W9966_STATE_CLAIMED, 0);
-}
-
-/* Read register from W9966 interface-chip
- Expects a claimed pdev
- -1 on error, else register data (byte) */
-static int w9966_read_reg(struct w9966 *cam, int reg)
-{
- /* ECP, read, regtransfer, REG, REG, REG, REG, REG */
- const unsigned char addr = 0x80 | (reg & 0x1f);
- unsigned char val;
-
- if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
- return -1;
- if (parport_write(cam->pport, &addr, 1) != 1)
- return -1;
- if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
- return -1;
- if (parport_read(cam->pport, &val, 1) != 1)
- return -1;
-
- return val;
-}
-
-/* Write register to W9966 interface-chip
- Expects a claimed pdev
- -1 on error */
-static int w9966_write_reg(struct w9966 *cam, int reg, int data)
-{
- /* ECP, write, regtransfer, REG, REG, REG, REG, REG */
- const unsigned char addr = 0xc0 | (reg & 0x1f);
- const unsigned char val = data;
-
- if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_ADDR) != 0)
- return -1;
- if (parport_write(cam->pport, &addr, 1) != 1)
- return -1;
- if (parport_negotiate(cam->pport, cam->ppmode | IEEE1284_DATA) != 0)
- return -1;
- if (parport_write(cam->pport, &val, 1) != 1)
- return -1;
-
- return 0;
-}
-
-/*
- * Ugly and primitive i2c protocol functions
- */
-
-/* Sets the data line on the i2c bus.
- Expects a claimed pdev. */
-static void w9966_i2c_setsda(struct w9966 *cam, int state)
-{
- if (state)
- cam->i2c_state |= W9966_I2C_W_DATA;
- else
- cam->i2c_state &= ~W9966_I2C_W_DATA;
-
- w9966_write_reg(cam, 0x18, cam->i2c_state);
- udelay(5);
-}
-
-/* Get peripheral clock line
- Expects a claimed pdev. */
-static int w9966_i2c_getscl(struct w9966 *cam)
-{
- const unsigned char state = w9966_read_reg(cam, 0x18);
- return ((state & W9966_I2C_R_CLOCK) > 0);
-}
-
-/* Sets the clock line on the i2c bus.
- Expects a claimed pdev. -1 on error */
-static int w9966_i2c_setscl(struct w9966 *cam, int state)
-{
- unsigned long timeout;
-
- if (state)
- cam->i2c_state |= W9966_I2C_W_CLOCK;
- else
- cam->i2c_state &= ~W9966_I2C_W_CLOCK;
-
- w9966_write_reg(cam, 0x18, cam->i2c_state);
- udelay(5);
-
- /* we go to high, we also expect the peripheral to ack. */
- if (state) {
- timeout = jiffies + 100;
- while (!w9966_i2c_getscl(cam)) {
- if (time_after(jiffies, timeout))
- return -1;
- }
- }
- return 0;
-}
-
-#if 0
-/* Get peripheral data line
- Expects a claimed pdev. */
-static int w9966_i2c_getsda(struct w9966 *cam)
-{
- const unsigned char state = w9966_read_reg(cam, 0x18);
- return ((state & W9966_I2C_R_DATA) > 0);
-}
-#endif
-
-/* Write a byte with ack to the i2c bus.
- Expects a claimed pdev. -1 on error */
-static int w9966_i2c_wbyte(struct w9966 *cam, int data)
-{
- int i;
-
- for (i = 7; i >= 0; i--) {
- w9966_i2c_setsda(cam, (data >> i) & 0x01);
-
- if (w9966_i2c_setscl(cam, 1) == -1)
- return -1;
- w9966_i2c_setscl(cam, 0);
- }
-
- w9966_i2c_setsda(cam, 1);
-
- if (w9966_i2c_setscl(cam, 1) == -1)
- return -1;
- w9966_i2c_setscl(cam, 0);
-
- return 0;
-}
-
-/* Read a data byte with ack from the i2c-bus
- Expects a claimed pdev. -1 on error */
-#if 0
-static int w9966_i2c_rbyte(struct w9966 *cam)
-{
- unsigned char data = 0x00;
- int i;
-
- w9966_i2c_setsda(cam, 1);
-
- for (i = 0; i < 8; i++) {
- if (w9966_i2c_setscl(cam, 1) == -1)
- return -1;
- data = data << 1;
- if (w9966_i2c_getsda(cam))
- data |= 0x01;
-
- w9966_i2c_setscl(cam, 0);
- }
- return data;
-}
-#endif
-
-/* Read a register from the i2c device.
- Expects claimed pdev. -1 on error */
-#if 0
-static int w9966_read_reg_i2c(struct w9966 *cam, int reg)
-{
- int data;
-
- w9966_i2c_setsda(cam, 0);
- w9966_i2c_setscl(cam, 0);
-
- if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
- w9966_i2c_wbyte(cam, reg) == -1)
- return -1;
-
- w9966_i2c_setsda(cam, 1);
- if (w9966_i2c_setscl(cam, 1) == -1)
- return -1;
- w9966_i2c_setsda(cam, 0);
- w9966_i2c_setscl(cam, 0);
-
- if (w9966_i2c_wbyte(cam, W9966_I2C_R_ID) == -1)
- return -1;
- data = w9966_i2c_rbyte(cam);
- if (data == -1)
- return -1;
-
- w9966_i2c_setsda(cam, 0);
-
- if (w9966_i2c_setscl(cam, 1) == -1)
- return -1;
- w9966_i2c_setsda(cam, 1);
-
- return data;
-}
-#endif
-
-/* Write a register to the i2c device.
- Expects claimed pdev. -1 on error */
-static int w9966_write_reg_i2c(struct w9966 *cam, int reg, int data)
-{
- w9966_i2c_setsda(cam, 0);
- w9966_i2c_setscl(cam, 0);
-
- if (w9966_i2c_wbyte(cam, W9966_I2C_W_ID) == -1 ||
- w9966_i2c_wbyte(cam, reg) == -1 ||
- w9966_i2c_wbyte(cam, data) == -1)
- return -1;
-
- w9966_i2c_setsda(cam, 0);
- if (w9966_i2c_setscl(cam, 1) == -1)
- return -1;
-
- w9966_i2c_setsda(cam, 1);
-
- return 0;
-}
-
-/* Find a good length for capture window (used both for W and H)
- A bit ugly but pretty functional. The capture length
- have to match the downscale */
-static int w9966_findlen(int near, int size, int maxlen)
-{
- int bestlen = size;
- int besterr = abs(near - bestlen);
- int len;
-
- for (len = size + 1; len < maxlen; len++) {
- int err;
- if (((64 * size) % len) != 0)
- continue;
-
- err = abs(near - len);
-
- /* Only continue as long as we keep getting better values */
- if (err > besterr)
- break;
-
- besterr = err;
- bestlen = len;
- }
-
- return bestlen;
-}
-
-/* Modify capture window (if necessary)
- and calculate downscaling
- Return -1 on error */
-static int w9966_calcscale(int size, int min, int max, int *beg, int *end, unsigned char *factor)
-{
- int maxlen = max - min;
- int len = *end - *beg + 1;
- int newlen = w9966_findlen(len, size, maxlen);
- int err = newlen - len;
-
- /* Check for bad format */
- if (newlen > maxlen || newlen < size)
- return -1;
-
- /* Set factor (6 bit fixed) */
- *factor = (64 * size) / newlen;
- if (*factor == 64)
- *factor = 0x00; /* downscale is disabled */
- else
- *factor |= 0x80; /* set downscale-enable bit */
-
- /* Modify old beginning and end */
- *beg -= err / 2;
- *end += err - (err / 2);
-
- /* Move window if outside borders */
- if (*beg < min) {
- *end += min - *beg;
- *beg += min - *beg;
- }
- if (*end > max) {
- *beg -= *end - max;
- *end -= *end - max;
- }
-
- return 0;
-}
-
-/* Setup the cameras capture window etc.
- Expects a claimed pdev
- return -1 on error */
-static int w9966_setup(struct w9966 *cam, int x1, int y1, int x2, int y2, int w, int h)
-{
- unsigned int i;
- unsigned int enh_s, enh_e;
- unsigned char scale_x, scale_y;
- unsigned char regs[0x1c];
- unsigned char saa7111_regs[] = {
- 0x21, 0x00, 0xd8, 0x23, 0x00, 0x80, 0x80, 0x00,
- 0x88, 0x10, 0x80, 0x40, 0x40, 0x00, 0x01, 0x00,
- 0x48, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x71, 0xe7, 0x00, 0x00, 0xc0
- };
-
-
- if (w * h * 2 > W9966_SRAMSIZE) {
- DPRINTF("capture window exceeds SRAM size!.\n");
- w = 200; h = 160; /* Pick default values */
- }
-
- w &= ~0x1;
- if (w < 2)
- w = 2;
- if (h < 1)
- h = 1;
- if (w > W9966_WND_MAX_W)
- w = W9966_WND_MAX_W;
- if (h > W9966_WND_MAX_H)
- h = W9966_WND_MAX_H;
-
- cam->width = w;
- cam->height = h;
-
- enh_s = 0;
- enh_e = w * h * 2;
-
- /* Modify capture window if necessary and calculate downscaling */
- if (w9966_calcscale(w, W9966_WND_MIN_X, W9966_WND_MAX_X, &x1, &x2, &scale_x) != 0 ||
- w9966_calcscale(h, W9966_WND_MIN_Y, W9966_WND_MAX_Y, &y1, &y2, &scale_y) != 0)
- return -1;
-
- DPRINTF("%dx%d, x: %d<->%d, y: %d<->%d, sx: %d/64, sy: %d/64.\n",
- w, h, x1, x2, y1, y2, scale_x & ~0x80, scale_y & ~0x80);
-
- /* Setup registers */
- regs[0x00] = 0x00; /* Set normal operation */
- regs[0x01] = 0x18; /* Capture mode */
- regs[0x02] = scale_y; /* V-scaling */
- regs[0x03] = scale_x; /* H-scaling */
-
- /* Capture window */
- regs[0x04] = (x1 & 0x0ff); /* X-start (8 low bits) */
- regs[0x05] = (x1 & 0x300)>>8; /* X-start (2 high bits) */
- regs[0x06] = (y1 & 0x0ff); /* Y-start (8 low bits) */
- regs[0x07] = (y1 & 0x300)>>8; /* Y-start (2 high bits) */
- regs[0x08] = (x2 & 0x0ff); /* X-end (8 low bits) */
- regs[0x09] = (x2 & 0x300)>>8; /* X-end (2 high bits) */
- regs[0x0a] = (y2 & 0x0ff); /* Y-end (8 low bits) */
-
- regs[0x0c] = W9966_SRAMID; /* SRAM-banks (1x 128kb) */
-
- /* Enhancement layer */
- regs[0x0d] = (enh_s & 0x000ff); /* Enh. start (0-7) */
- regs[0x0e] = (enh_s & 0x0ff00) >> 8; /* Enh. start (8-15) */
- regs[0x0f] = (enh_s & 0x70000) >> 16; /* Enh. start (16-17/18??) */
- regs[0x10] = (enh_e & 0x000ff); /* Enh. end (0-7) */
- regs[0x11] = (enh_e & 0x0ff00) >> 8; /* Enh. end (8-15) */
- regs[0x12] = (enh_e & 0x70000) >> 16; /* Enh. end (16-17/18??) */
-
- /* Misc */
- regs[0x13] = 0x40; /* VEE control (raw 4:2:2) */
- regs[0x17] = 0x00; /* ??? */
- regs[0x18] = cam->i2c_state = 0x00; /* Serial bus */
- regs[0x19] = 0xff; /* I/O port direction control */
- regs[0x1a] = 0xff; /* I/O port data register */
- regs[0x1b] = 0x10; /* ??? */
-
- /* SAA7111 chip settings */
- saa7111_regs[0x0a] = cam->brightness;
- saa7111_regs[0x0b] = cam->contrast;
- saa7111_regs[0x0c] = cam->color;
- saa7111_regs[0x0d] = cam->hue;
-
- /* Reset (ECP-fifo & serial-bus) */
- if (w9966_write_reg(cam, 0x00, 0x03) == -1)
- return -1;
-
- /* Write regs to w9966cf chip */
- for (i = 0; i < 0x1c; i++)
- if (w9966_write_reg(cam, i, regs[i]) == -1)
- return -1;
-
- /* Write regs to saa7111 chip */
- for (i = 0; i < 0x20; i++)
- if (w9966_write_reg_i2c(cam, i, saa7111_regs[i]) == -1)
- return -1;
-
- return 0;
-}
-
-/*
- * Video4linux interfacing
- */
-
-static int cam_querycap(struct file *file, void *priv,
- struct v4l2_capability *vcap)
-{
- struct w9966 *cam = video_drvdata(file);
-
- strlcpy(vcap->driver, cam->v4l2_dev.name, sizeof(vcap->driver));
- strlcpy(vcap->card, W9966_DRIVERNAME, sizeof(vcap->card));
- strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
- vcap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
- vcap->capabilities = vcap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int cam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
-{
- if (vin->index > 0)
- return -EINVAL;
- strlcpy(vin->name, "Camera", sizeof(vin->name));
- vin->type = V4L2_INPUT_TYPE_CAMERA;
- vin->audioset = 0;
- vin->tuner = 0;
- vin->std = 0;
- vin->status = 0;
- return 0;
-}
-
-static int cam_g_input(struct file *file, void *fh, unsigned int *inp)
-{
- *inp = 0;
- return 0;
-}
-
-static int cam_s_input(struct file *file, void *fh, unsigned int inp)
-{
- return (inp > 0) ? -EINVAL : 0;
-}
-
-static int cam_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct w9966 *cam =
- container_of(ctrl->handler, struct w9966, hdl);
- int ret = 0;
-
- mutex_lock(&cam->lock);
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- cam->brightness = ctrl->val;
- break;
- case V4L2_CID_CONTRAST:
- cam->contrast = ctrl->val;
- break;
- case V4L2_CID_SATURATION:
- cam->color = ctrl->val;
- break;
- case V4L2_CID_HUE:
- cam->hue = ctrl->val;
- break;
- default:
- ret = -EINVAL;
- break;
- }
-
- if (ret == 0) {
- w9966_pdev_claim(cam);
-
- if (w9966_write_reg_i2c(cam, 0x0a, cam->brightness) == -1 ||
- w9966_write_reg_i2c(cam, 0x0b, cam->contrast) == -1 ||
- w9966_write_reg_i2c(cam, 0x0c, cam->color) == -1 ||
- w9966_write_reg_i2c(cam, 0x0d, cam->hue) == -1) {
- ret = -EIO;
- }
-
- w9966_pdev_release(cam);
- }
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-static int cam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct w9966 *cam = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- pix->width = cam->width;
- pix->height = cam->height;
- pix->pixelformat = V4L2_PIX_FMT_YUYV;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = 2 * cam->width;
- pix->sizeimage = 2 * cam->width * cam->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
- return 0;
-}
-
-static int cam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- if (pix->width < 2)
- pix->width = 2;
- if (pix->height < 1)
- pix->height = 1;
- if (pix->width > W9966_WND_MAX_W)
- pix->width = W9966_WND_MAX_W;
- if (pix->height > W9966_WND_MAX_H)
- pix->height = W9966_WND_MAX_H;
- pix->pixelformat = V4L2_PIX_FMT_YUYV;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = 2 * pix->width;
- pix->sizeimage = 2 * pix->width * pix->height;
- /* Just a guess */
- pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
- return 0;
-}
-
-static int cam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
-{
- struct w9966 *cam = video_drvdata(file);
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
- int ret = cam_try_fmt_vid_cap(file, fh, fmt);
-
- if (ret)
- return ret;
-
- mutex_lock(&cam->lock);
- /* Update camera regs */
- w9966_pdev_claim(cam);
- ret = w9966_setup(cam, 0, 0, 1023, 1023, pix->width, pix->height);
- w9966_pdev_release(cam);
- mutex_unlock(&cam->lock);
- return ret;
-}
-
-static int cam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
-{
- static struct v4l2_fmtdesc formats[] = {
- { 0, 0, 0,
- "YUV 4:2:2", V4L2_PIX_FMT_YUYV,
- { 0, 0, 0, 0 }
- },
- };
- enum v4l2_buf_type type = fmt->type;
-
- if (fmt->index > 0)
- return -EINVAL;
-
- *fmt = formats[fmt->index];
- fmt->type = type;
- return 0;
-}
-
-/* Capture data */
-static ssize_t w9966_v4l_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct w9966 *cam = video_drvdata(file);
- unsigned char addr = 0xa0; /* ECP, read, CCD-transfer, 00000 */
- unsigned char __user *dest = (unsigned char __user *)buf;
- unsigned long dleft = count;
- unsigned char *tbuf;
-
- /* Why would anyone want more than this?? */
- if (count > cam->width * cam->height * 2)
- return -EINVAL;
-
- mutex_lock(&cam->lock);
- w9966_pdev_claim(cam);
- w9966_write_reg(cam, 0x00, 0x02); /* Reset ECP-FIFO buffer */
- w9966_write_reg(cam, 0x00, 0x00); /* Return to normal operation */
- w9966_write_reg(cam, 0x01, 0x98); /* Enable capture */
-
- /* write special capture-addr and negotiate into data transfer */
- if ((parport_negotiate(cam->pport, cam->ppmode|IEEE1284_ADDR) != 0) ||
- (parport_write(cam->pport, &addr, 1) != 1) ||
- (parport_negotiate(cam->pport, cam->ppmode|IEEE1284_DATA) != 0)) {
- w9966_pdev_release(cam);
- mutex_unlock(&cam->lock);
- return -EFAULT;
- }
-
- tbuf = kmalloc(W9966_RBUFFER, GFP_KERNEL);
- if (tbuf == NULL) {
- count = -ENOMEM;
- goto out;
- }
-
- while (dleft > 0) {
- unsigned long tsize = (dleft > W9966_RBUFFER) ? W9966_RBUFFER : dleft;
-
- if (parport_read(cam->pport, tbuf, tsize) < tsize) {
- count = -EFAULT;
- goto out;
- }
- if (copy_to_user(dest, tbuf, tsize) != 0) {
- count = -EFAULT;
- goto out;
- }
- dest += tsize;
- dleft -= tsize;
- }
-
- w9966_write_reg(cam, 0x01, 0x18); /* Disable capture */
-
-out:
- kfree(tbuf);
- w9966_pdev_release(cam);
- mutex_unlock(&cam->lock);
-
- return count;
-}
-
-static const struct v4l2_file_operations w9966_fops = {
- .owner = THIS_MODULE,
- .open = v4l2_fh_open,
- .release = v4l2_fh_release,
- .poll = v4l2_ctrl_poll,
- .unlocked_ioctl = video_ioctl2,
- .read = w9966_v4l_read,
-};
-
-static const struct v4l2_ioctl_ops w9966_ioctl_ops = {
- .vidioc_querycap = cam_querycap,
- .vidioc_g_input = cam_g_input,
- .vidioc_s_input = cam_s_input,
- .vidioc_enum_input = cam_enum_input,
- .vidioc_enum_fmt_vid_cap = cam_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = cam_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = cam_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = cam_try_fmt_vid_cap,
- .vidioc_log_status = v4l2_ctrl_log_status,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static const struct v4l2_ctrl_ops cam_ctrl_ops = {
- .s_ctrl = cam_s_ctrl,
-};
-
-
-/* Initialize camera device. Setup all internal flags, set a
- default video mode, setup ccd-chip, register v4l device etc..
- Also used for 'probing' of hardware.
- -1 on error */
-static int w9966_init(struct w9966 *cam, struct parport *port)
-{
- struct v4l2_device *v4l2_dev = &cam->v4l2_dev;
-
- if (cam->dev_state != 0)
- return -1;
-
- strlcpy(v4l2_dev->name, "w9966", sizeof(v4l2_dev->name));
-
- if (v4l2_device_register(NULL, v4l2_dev) < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- return -1;
- }
-
- v4l2_ctrl_handler_init(&cam->hdl, 4);
- v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
- V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
- v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
- V4L2_CID_CONTRAST, -64, 64, 1, 64);
- v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
- V4L2_CID_SATURATION, -64, 64, 1, 64);
- v4l2_ctrl_new_std(&cam->hdl, &cam_ctrl_ops,
- V4L2_CID_HUE, -128, 127, 1, 0);
- if (cam->hdl.error) {
- v4l2_err(v4l2_dev, "couldn't register controls\n");
- return -1;
- }
- cam->pport = port;
- cam->brightness = 128;
- cam->contrast = 64;
- cam->color = 64;
- cam->hue = 0;
-
- /* Select requested transfer mode */
- switch (parmode) {
- default: /* Auto-detect (priority: hw-ecp, hw-epp, sw-ecp) */
- case 0:
- if (port->modes & PARPORT_MODE_ECP)
- cam->ppmode = IEEE1284_MODE_ECP;
- else if (port->modes & PARPORT_MODE_EPP)
- cam->ppmode = IEEE1284_MODE_EPP;
- else
- cam->ppmode = IEEE1284_MODE_ECP;
- break;
- case 1: /* hw- or sw-ecp */
- cam->ppmode = IEEE1284_MODE_ECP;
- break;
- case 2: /* hw- or sw-epp */
- cam->ppmode = IEEE1284_MODE_EPP;
- break;
- }
-
- /* Tell the parport driver that we exists */
- cam->pdev = parport_register_device(port, "w9966", NULL, NULL, NULL, 0, NULL);
- if (cam->pdev == NULL) {
- DPRINTF("parport_register_device() failed\n");
- return -1;
- }
- w9966_set_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV);
-
- w9966_pdev_claim(cam);
-
- /* Setup a default capture mode */
- if (w9966_setup(cam, 0, 0, 1023, 1023, 200, 160) != 0) {
- DPRINTF("w9966_setup() failed.\n");
- return -1;
- }
-
- w9966_pdev_release(cam);
-
- /* Fill in the video_device struct and register us to v4l */
- strlcpy(cam->vdev.name, W9966_DRIVERNAME, sizeof(cam->vdev.name));
- cam->vdev.v4l2_dev = v4l2_dev;
- cam->vdev.fops = &w9966_fops;
- cam->vdev.ioctl_ops = &w9966_ioctl_ops;
- cam->vdev.release = video_device_release_empty;
- cam->vdev.ctrl_handler = &cam->hdl;
- video_set_drvdata(&cam->vdev, cam);
-
- mutex_init(&cam->lock);
-
- if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
- return -1;
-
- w9966_set_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV);
-
- /* All ok */
- v4l2_info(v4l2_dev, "Found and initialized a webcam on %s.\n",
- cam->pport->name);
- return 0;
-}
-
-
-/* Terminate everything gracefully */
-static void w9966_term(struct w9966 *cam)
-{
- /* Unregister from v4l */
- if (w9966_get_state(cam, W9966_STATE_VDEV, W9966_STATE_VDEV)) {
- video_unregister_device(&cam->vdev);
- w9966_set_state(cam, W9966_STATE_VDEV, 0);
- }
-
- v4l2_ctrl_handler_free(&cam->hdl);
-
- /* Terminate from IEEE1284 mode and release pdev block */
- if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
- w9966_pdev_claim(cam);
- parport_negotiate(cam->pport, IEEE1284_MODE_COMPAT);
- w9966_pdev_release(cam);
- }
-
- /* Unregister from parport */
- if (w9966_get_state(cam, W9966_STATE_PDEV, W9966_STATE_PDEV)) {
- parport_unregister_device(cam->pdev);
- w9966_set_state(cam, W9966_STATE_PDEV, 0);
- }
- memset(cam, 0, sizeof(*cam));
-}
-
-
-/* Called once for every parport on init */
-static void w9966_attach(struct parport *port)
-{
- int i;
-
- for (i = 0; i < W9966_MAXCAMS; i++) {
- if (w9966_cams[i].dev_state != 0) /* Cam is already assigned */
- continue;
- if (strcmp(pardev[i], "aggressive") == 0 || strcmp(pardev[i], port->name) == 0) {
- if (w9966_init(&w9966_cams[i], port) != 0)
- w9966_term(&w9966_cams[i]);
- break; /* return */
- }
- }
-}
-
-/* Called once for every parport on termination */
-static void w9966_detach(struct parport *port)
-{
- int i;
-
- for (i = 0; i < W9966_MAXCAMS; i++)
- if (w9966_cams[i].dev_state != 0 && w9966_cams[i].pport == port)
- w9966_term(&w9966_cams[i]);
-}
-
-
-static struct parport_driver w9966_ppd = {
- .name = W9966_DRIVERNAME,
- .attach = w9966_attach,
- .detach = w9966_detach,
-};
-
-/* Module entry point */
-static int __init w9966_mod_init(void)
-{
- int i;
-
- for (i = 0; i < W9966_MAXCAMS; i++)
- w9966_cams[i].dev_state = 0;
-
- return parport_register_driver(&w9966_ppd);
-}
-
-/* Module cleanup */
-static void __exit w9966_mod_term(void)
-{
- parport_unregister_driver(&w9966_ppd);
-}
-
-module_init(w9966_mod_init);
-module_exit(w9966_mod_term);
diff --git a/drivers/staging/media/tlg2300/Kconfig b/drivers/staging/media/tlg2300/Kconfig
deleted file mode 100644
index 77d8753f6ba4..000000000000
--- a/drivers/staging/media/tlg2300/Kconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-config VIDEO_TLG2300
- tristate "Telegent TLG2300 USB video capture support (Deprecated)"
- depends on VIDEO_DEV && I2C && SND && DVB_CORE
- depends on MEDIA_USB_SUPPORT
- select VIDEO_TUNER
- select VIDEO_TVEEPROM
- depends on RC_CORE
- select VIDEOBUF_VMALLOC
- select SND_PCM
- select VIDEOBUF_DVB
-
- ---help---
- This is a video4linux driver for Telegent tlg2300 based TV cards.
- The driver supports V4L2, DVB-T and radio.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-
- To compile this driver as a module, choose M here: the
- module will be called poseidon
diff --git a/drivers/staging/media/tlg2300/Makefile b/drivers/staging/media/tlg2300/Makefile
deleted file mode 100644
index 137f8e38cdec..000000000000
--- a/drivers/staging/media/tlg2300/Makefile
+++ /dev/null
@@ -1,9 +0,0 @@
-poseidon-objs := pd-video.o pd-alsa.o pd-dvb.o pd-radio.o pd-main.o
-
-obj-$(CONFIG_VIDEO_TLG2300) += poseidon.o
-
-ccflags-y += -Idrivers/media/i2c
-ccflags-y += -Idrivers/media/tuners
-ccflags-y += -Idrivers/media/dvb-core
-ccflags-y += -Idrivers/media/dvb-frontends
-
diff --git a/drivers/staging/media/tlg2300/pd-alsa.c b/drivers/staging/media/tlg2300/pd-alsa.c
deleted file mode 100644
index dd8fe100590f..000000000000
--- a/drivers/staging/media/tlg2300/pd-alsa.c
+++ /dev/null
@@ -1,337 +0,0 @@
-#include <linux/kernel.h>
-#include <linux/usb.h>
-#include <linux/init.h>
-#include <linux/sound.h>
-#include <linux/spinlock.h>
-#include <linux/soundcard.h>
-#include <linux/vmalloc.h>
-#include <linux/proc_fs.h>
-#include <linux/module.h>
-#include <linux/gfp.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/info.h>
-#include <sound/initval.h>
-#include <sound/control.h>
-#include <media/v4l2-common.h>
-#include "pd-common.h"
-#include "vendorcmds.h"
-
-static void complete_handler_audio(struct urb *urb);
-#define AUDIO_EP (0x83)
-#define AUDIO_BUF_SIZE (512)
-#define PERIOD_SIZE (1024 * 8)
-#define PERIOD_MIN (4)
-#define PERIOD_MAX PERIOD_MIN
-
-static struct snd_pcm_hardware snd_pd_hw_capture = {
- .info = SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_MMAP_VALID,
-
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- .rates = SNDRV_PCM_RATE_48000,
-
- .rate_min = 48000,
- .rate_max = 48000,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = PERIOD_SIZE * PERIOD_MIN,
- .period_bytes_min = PERIOD_SIZE,
- .period_bytes_max = PERIOD_SIZE,
- .periods_min = PERIOD_MIN,
- .periods_max = PERIOD_MAX,
- /*
- .buffer_bytes_max = 62720 * 8,
- .period_bytes_min = 64,
- .period_bytes_max = 12544,
- .periods_min = 2,
- .periods_max = 98
- */
-};
-
-static int snd_pd_capture_open(struct snd_pcm_substream *substream)
-{
- struct poseidon *p = snd_pcm_substream_chip(substream);
- struct poseidon_audio *pa = &p->audio;
- struct snd_pcm_runtime *runtime = substream->runtime;
-
- if (!p)
- return -ENODEV;
- pa->users++;
- pa->card_close = 0;
- pa->capture_pcm_substream = substream;
- runtime->private_data = p;
-
- runtime->hw = snd_pd_hw_capture;
- snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS);
- usb_autopm_get_interface(p->interface);
- kref_get(&p->kref);
- return 0;
-}
-
-static int snd_pd_pcm_close(struct snd_pcm_substream *substream)
-{
- struct poseidon *p = snd_pcm_substream_chip(substream);
- struct poseidon_audio *pa = &p->audio;
-
- pa->users--;
- pa->card_close = 1;
- usb_autopm_put_interface(p->interface);
- kref_put(&p->kref, poseidon_delete);
- return 0;
-}
-
-static int snd_pd_hw_capture_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int size;
-
- size = params_buffer_bytes(hw_params);
- if (runtime->dma_area) {
- if (runtime->dma_bytes > size)
- return 0;
- vfree(runtime->dma_area);
- }
- runtime->dma_area = vmalloc(size);
- if (!runtime->dma_area)
- return -ENOMEM;
- else
- runtime->dma_bytes = size;
- return 0;
-}
-
-static int audio_buf_free(struct poseidon *p)
-{
- struct poseidon_audio *pa = &p->audio;
- int i;
-
- for (i = 0; i < AUDIO_BUFS; i++)
- if (pa->urb_array[i])
- usb_kill_urb(pa->urb_array[i]);
- free_all_urb_generic(pa->urb_array, AUDIO_BUFS);
- logpm();
- return 0;
-}
-
-static int snd_pd_hw_capture_free(struct snd_pcm_substream *substream)
-{
- struct poseidon *p = snd_pcm_substream_chip(substream);
-
- logpm();
- audio_buf_free(p);
- return 0;
-}
-
-static int snd_pd_prepare(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-#define AUDIO_TRAILER_SIZE (16)
-static inline void handle_audio_data(struct urb *urb, int *period_elapsed)
-{
- struct poseidon_audio *pa = urb->context;
- struct snd_pcm_runtime *runtime = pa->capture_pcm_substream->runtime;
-
- int stride = runtime->frame_bits >> 3;
- int len = urb->actual_length / stride;
- unsigned char *cp = urb->transfer_buffer;
- unsigned int oldptr = pa->rcv_position;
-
- if (urb->actual_length == AUDIO_BUF_SIZE - 4)
- len -= (AUDIO_TRAILER_SIZE / stride);
-
- /* do the copy */
- if (oldptr + len >= runtime->buffer_size) {
- unsigned int cnt = runtime->buffer_size - oldptr;
-
- memcpy(runtime->dma_area + oldptr * stride, cp, cnt * stride);
- memcpy(runtime->dma_area, (cp + cnt * stride),
- (len * stride - cnt * stride));
- } else
- memcpy(runtime->dma_area + oldptr * stride, cp, len * stride);
-
- /* update the statas */
- snd_pcm_stream_lock(pa->capture_pcm_substream);
- pa->rcv_position += len;
- if (pa->rcv_position >= runtime->buffer_size)
- pa->rcv_position -= runtime->buffer_size;
-
- pa->copied_position += (len);
- if (pa->copied_position >= runtime->period_size) {
- pa->copied_position -= runtime->period_size;
- *period_elapsed = 1;
- }
- snd_pcm_stream_unlock(pa->capture_pcm_substream);
-}
-
-static void complete_handler_audio(struct urb *urb)
-{
- struct poseidon_audio *pa = urb->context;
- struct snd_pcm_substream *substream = pa->capture_pcm_substream;
- int period_elapsed = 0;
- int ret;
-
- if (1 == pa->card_close || pa->capture_stream != STREAM_ON)
- return;
-
- if (urb->status != 0) {
- /*if (urb->status == -ESHUTDOWN)*/
- return;
- }
-
- if (substream) {
- if (urb->actual_length) {
- handle_audio_data(urb, &period_elapsed);
- if (period_elapsed)
- snd_pcm_period_elapsed(substream);
- }
- }
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret < 0)
- log("audio urb failed (errcod = %i)", ret);
- return;
-}
-
-static int fire_audio_urb(struct poseidon *p)
-{
- int i, ret = 0;
- struct poseidon_audio *pa = &p->audio;
-
- alloc_bulk_urbs_generic(pa->urb_array, AUDIO_BUFS,
- p->udev, AUDIO_EP,
- AUDIO_BUF_SIZE, GFP_ATOMIC,
- complete_handler_audio, pa);
-
- for (i = 0; i < AUDIO_BUFS; i++) {
- ret = usb_submit_urb(pa->urb_array[i], GFP_KERNEL);
- if (ret)
- log("urb err : %d", ret);
- }
- log();
- return ret;
-}
-
-static int snd_pd_capture_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct poseidon *p = snd_pcm_substream_chip(substream);
- struct poseidon_audio *pa = &p->audio;
-
- if (debug_mode)
- log("cmd %d, audio stat : %d\n", cmd, pa->capture_stream);
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_START:
- if (pa->capture_stream == STREAM_ON)
- return 0;
-
- pa->rcv_position = pa->copied_position = 0;
- pa->capture_stream = STREAM_ON;
-
- if (in_hibernation(p))
- return 0;
- fire_audio_urb(p);
- return 0;
-
- case SNDRV_PCM_TRIGGER_SUSPEND:
- pa->capture_stream = STREAM_SUSPEND;
- return 0;
- case SNDRV_PCM_TRIGGER_STOP:
- pa->capture_stream = STREAM_OFF;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-static snd_pcm_uframes_t
-snd_pd_capture_pointer(struct snd_pcm_substream *substream)
-{
- struct poseidon *p = snd_pcm_substream_chip(substream);
- struct poseidon_audio *pa = &p->audio;
- return pa->rcv_position;
-}
-
-static struct page *snd_pcm_pd_get_page(struct snd_pcm_substream *subs,
- unsigned long offset)
-{
- void *pageptr = subs->runtime->dma_area + offset;
- return vmalloc_to_page(pageptr);
-}
-
-static struct snd_pcm_ops pcm_capture_ops = {
- .open = snd_pd_capture_open,
- .close = snd_pd_pcm_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = snd_pd_hw_capture_params,
- .hw_free = snd_pd_hw_capture_free,
- .prepare = snd_pd_prepare,
- .trigger = snd_pd_capture_trigger,
- .pointer = snd_pd_capture_pointer,
- .page = snd_pcm_pd_get_page,
-};
-
-#ifdef CONFIG_PM
-int pm_alsa_suspend(struct poseidon *p)
-{
- logpm(p);
- audio_buf_free(p);
- return 0;
-}
-
-int pm_alsa_resume(struct poseidon *p)
-{
- logpm(p);
- fire_audio_urb(p);
- return 0;
-}
-#endif
-
-int poseidon_audio_init(struct poseidon *p)
-{
- struct poseidon_audio *pa = &p->audio;
- struct snd_card *card;
- struct snd_pcm *pcm;
- int ret;
-
- ret = snd_card_new(&p->interface->dev, -1, "Telegent",
- THIS_MODULE, 0, &card);
- if (ret != 0)
- return ret;
-
- ret = snd_pcm_new(card, "poseidon audio", 0, 0, 1, &pcm);
- if (ret < 0) {
- snd_card_free(card);
- return ret;
- }
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &pcm_capture_ops);
- pcm->info_flags = 0;
- pcm->private_data = p;
- strcpy(pcm->name, "poseidon audio capture");
-
- strcpy(card->driver, "ALSA driver");
- strcpy(card->shortname, "poseidon Audio");
- strcpy(card->longname, "poseidon ALSA Audio");
-
- if (snd_card_register(card)) {
- snd_card_free(card);
- return -ENOMEM;
- }
- pa->card = card;
- return 0;
-}
-
-int poseidon_audio_free(struct poseidon *p)
-{
- struct poseidon_audio *pa = &p->audio;
-
- if (pa->card)
- snd_card_free(pa->card);
- return 0;
-}
diff --git a/drivers/staging/media/tlg2300/pd-common.h b/drivers/staging/media/tlg2300/pd-common.h
deleted file mode 100644
index 9e23ad32d2fe..000000000000
--- a/drivers/staging/media/tlg2300/pd-common.h
+++ /dev/null
@@ -1,271 +0,0 @@
-#ifndef PD_COMMON_H
-#define PD_COMMON_H
-
-#include <linux/fs.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/videodev2.h>
-#include <linux/semaphore.h>
-#include <linux/usb.h>
-#include <linux/poll.h>
-#include <media/videobuf-vmalloc.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ctrls.h>
-
-#include "dvb_frontend.h"
-#include "dvbdev.h"
-#include "dvb_demux.h"
-#include "dmxdev.h"
-
-#define SBUF_NUM 8
-#define MAX_BUFFER_NUM 6
-#define PK_PER_URB 32
-#define ISO_PKT_SIZE 3072
-
-#define POSEIDON_STATE_NONE (0x0000)
-#define POSEIDON_STATE_ANALOG (0x0001)
-#define POSEIDON_STATE_FM (0x0002)
-#define POSEIDON_STATE_DVBT (0x0004)
-#define POSEIDON_STATE_DISCONNECT (0x0080)
-
-#define PM_SUSPEND_DELAY 3
-
-#define V4L_PAL_VBI_LINES 18
-#define V4L_NTSC_VBI_LINES 12
-#define V4L_PAL_VBI_FRAMESIZE (V4L_PAL_VBI_LINES * 1440 * 2)
-#define V4L_NTSC_VBI_FRAMESIZE (V4L_NTSC_VBI_LINES * 1440 * 2)
-
-#define TUNER_FREQ_MIN (45000000U)
-#define TUNER_FREQ_MAX (862000000U)
-
-struct vbi_data {
- struct video_device v_dev;
- struct video_data *video;
- struct front_face *front;
-
- unsigned int copied;
- unsigned int vbi_size; /* the whole size of two fields */
- int users;
-};
-
-/*
- * This is the running context of the video, it is useful for
- * resume()
- */
-struct running_context {
- u32 freq; /* VIDIOC_S_FREQUENCY */
- int audio_idx; /* VIDIOC_S_TUNER */
- v4l2_std_id tvnormid; /* VIDIOC_S_STD */
- int sig_index; /* VIDIOC_S_INPUT */
- struct v4l2_pix_format pix; /* VIDIOC_S_FMT */
-};
-
-struct video_data {
- /* v4l2 video device */
- struct video_device v_dev;
- struct v4l2_ctrl_handler ctrl_handler;
-
- /* the working context */
- struct running_context context;
-
- /* for data copy */
- int field_count;
-
- char *dst;
- int lines_copied;
- int prev_left;
-
- int lines_per_field;
- int lines_size;
-
- /* for communication */
- u8 endpoint_addr;
- struct urb *urb_array[SBUF_NUM];
- struct vbi_data *vbi;
- struct poseidon *pd;
- struct front_face *front;
-
- int is_streaming;
- int users;
-
- /* for bubble handler */
- struct work_struct bubble_work;
-};
-
-enum pcm_stream_state {
- STREAM_OFF,
- STREAM_ON,
- STREAM_SUSPEND,
-};
-
-#define AUDIO_BUFS (3)
-#define CAPTURE_STREAM_EN 1
-struct poseidon_audio {
- struct urb *urb_array[AUDIO_BUFS];
- unsigned int copied_position;
- struct snd_pcm_substream *capture_pcm_substream;
-
- unsigned int rcv_position;
- struct snd_card *card;
- int card_close;
-
- int users;
- int pm_state;
- enum pcm_stream_state capture_stream;
-};
-
-struct radio_data {
- __u32 fm_freq;
- unsigned int is_radio_streaming;
- int pre_emphasis;
- struct video_device fm_dev;
- struct v4l2_ctrl_handler ctrl_handler;
-};
-
-#define DVB_SBUF_NUM 4
-#define DVB_URB_BUF_SIZE 0x2000
-struct pd_dvb_adapter {
- struct dvb_adapter dvb_adap;
- struct dvb_frontend dvb_fe;
- struct dmxdev dmxdev;
- struct dvb_demux demux;
-
- atomic_t users;
- atomic_t active_feed;
-
- /* data transfer */
- s32 is_streaming;
- struct urb *urb_array[DVB_SBUF_NUM];
- struct poseidon *pd_device;
- u8 ep_addr;
- u8 reserved[3];
-
- /* data for power resume*/
- struct dtv_frontend_properties fe_param;
-
- /* for channel scanning */
- int prev_freq;
- int bandwidth;
- unsigned long last_jiffies;
-};
-
-struct front_face {
- /* use this field to distinguish VIDEO and VBI */
- enum v4l2_buf_type type;
-
- /* for host */
- struct videobuf_queue q;
-
- /* the bridge for host and device */
- struct videobuf_buffer *curr_frame;
-
- /* for device */
- spinlock_t queue_lock;
- struct list_head active;
- struct poseidon *pd;
-};
-
-struct poseidon {
- struct list_head device_list;
-
- struct mutex lock;
- struct kref kref;
-
- /* for V4L2 */
- struct v4l2_device v4l2_dev;
-
- /* hardware info */
- struct usb_device *udev;
- struct usb_interface *interface;
- int cur_transfer_mode;
-
- struct video_data video_data; /* video */
- struct vbi_data vbi_data; /* vbi */
- struct poseidon_audio audio; /* audio (alsa) */
- struct radio_data radio_data; /* FM */
- struct pd_dvb_adapter dvb_data; /* DVB */
-
- u32 state;
- struct file *file_for_stream; /* the active stream*/
-
-#ifdef CONFIG_PM
- int (*pm_suspend)(struct poseidon *);
- int (*pm_resume)(struct poseidon *);
- pm_message_t msg;
-
- struct work_struct pm_work;
- u8 portnum;
-#endif
-};
-
-struct poseidon_format {
- char *name;
- int fourcc; /* video4linux 2 */
- int depth; /* bit/pixel */
- int flags;
-};
-
-struct poseidon_tvnorm {
- v4l2_std_id v4l2_id;
- char name[12];
- u32 tlg_tvnorm;
-};
-
-/* video */
-int pd_video_init(struct poseidon *);
-void pd_video_exit(struct poseidon *);
-int stop_all_video_stream(struct poseidon *);
-
-/* alsa audio */
-int poseidon_audio_init(struct poseidon *);
-int poseidon_audio_free(struct poseidon *);
-#ifdef CONFIG_PM
-int pm_alsa_suspend(struct poseidon *);
-int pm_alsa_resume(struct poseidon *);
-#endif
-
-/* dvb */
-int pd_dvb_usb_device_init(struct poseidon *);
-void pd_dvb_usb_device_exit(struct poseidon *);
-void pd_dvb_usb_device_cleanup(struct poseidon *);
-int pd_dvb_get_adapter_num(struct pd_dvb_adapter *);
-void dvb_stop_streaming(struct pd_dvb_adapter *);
-
-/* FM */
-int poseidon_fm_init(struct poseidon *);
-int poseidon_fm_exit(struct poseidon *);
-
-/* vendor command ops */
-int send_set_req(struct poseidon*, u8, s32, s32*);
-int send_get_req(struct poseidon*, u8, s32, void*, s32*, s32);
-s32 set_tuner_mode(struct poseidon*, unsigned char);
-
-/* bulk urb alloc/free */
-int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
- struct usb_device *udev, u8 ep_addr,
- int buf_size, gfp_t gfp_flags,
- usb_complete_t complete_fn, void *context);
-void free_all_urb_generic(struct urb **urb_array, int num);
-
-/* misc */
-void poseidon_delete(struct kref *kref);
-extern int debug_mode;
-void set_debug_mode(struct video_device *vfd, int debug_mode);
-
-#ifdef CONFIG_PM
-#define in_hibernation(pd) (pd->msg.event == PM_EVENT_FREEZE)
-#else
-#define in_hibernation(pd) (0)
-#endif
-#define get_pm_count(p) (atomic_read(&(p)->interface->pm_usage_cnt))
-
-#define log(a, ...) printk(KERN_DEBUG "\t[ %s : %.3d ] "a"\n", \
- __func__, __LINE__, ## __VA_ARGS__)
-
-/* for power management */
-#define logpm(pd) do {\
- if (debug_mode & 0x10)\
- log();\
- } while (0)
-
-#endif
diff --git a/drivers/staging/media/tlg2300/pd-dvb.c b/drivers/staging/media/tlg2300/pd-dvb.c
deleted file mode 100644
index ca4994a5190c..000000000000
--- a/drivers/staging/media/tlg2300/pd-dvb.c
+++ /dev/null
@@ -1,597 +0,0 @@
-#include "pd-common.h"
-#include <linux/kernel.h>
-#include <linux/usb.h>
-#include <linux/time.h>
-#include <linux/dvb/dmx.h>
-#include <linux/delay.h>
-#include <linux/gfp.h>
-
-#include "vendorcmds.h"
-#include <linux/sched.h>
-#include <linux/atomic.h>
-
-static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb);
-
-static int dvb_bandwidth[][2] = {
- { TLG_BW_8, 8000000 },
- { TLG_BW_7, 7000000 },
- { TLG_BW_6, 6000000 }
-};
-static int dvb_bandwidth_length = ARRAY_SIZE(dvb_bandwidth);
-
-static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb);
-static int poseidon_check_mode_dvbt(struct poseidon *pd)
-{
- s32 ret = 0, cmd_status = 0;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/4);
-
- ret = usb_set_interface(pd->udev, 0, BULK_ALTERNATE_IFACE);
- if (ret != 0)
- return ret;
-
- ret = set_tuner_mode(pd, TLG_MODE_CAPS_DVB_T);
- if (ret)
- return ret;
-
- /* signal source */
- ret = send_set_req(pd, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &cmd_status);
- if (ret|cmd_status)
- return ret;
-
- return 0;
-}
-
-/* acquire :
- * 1 == open
- * 0 == release
- */
-static int poseidon_ts_bus_ctrl(struct dvb_frontend *fe, int acquire)
-{
- struct poseidon *pd = fe->demodulator_priv;
- struct pd_dvb_adapter *pd_dvb;
- int ret = 0;
-
- if (!pd)
- return -ENODEV;
-
- pd_dvb = container_of(fe, struct pd_dvb_adapter, dvb_fe);
- if (acquire) {
- mutex_lock(&pd->lock);
- if (pd->state & POSEIDON_STATE_DISCONNECT) {
- ret = -ENODEV;
- goto open_out;
- }
-
- if (pd->state && !(pd->state & POSEIDON_STATE_DVBT)) {
- ret = -EBUSY;
- goto open_out;
- }
-
- usb_autopm_get_interface(pd->interface);
- if (0 == pd->state) {
- ret = poseidon_check_mode_dvbt(pd);
- if (ret < 0) {
- usb_autopm_put_interface(pd->interface);
- goto open_out;
- }
- pd->state |= POSEIDON_STATE_DVBT;
- pd_dvb->bandwidth = 0;
- pd_dvb->prev_freq = 0;
- }
- atomic_inc(&pd_dvb->users);
- kref_get(&pd->kref);
-open_out:
- mutex_unlock(&pd->lock);
- } else {
- dvb_stop_streaming(pd_dvb);
-
- if (atomic_dec_and_test(&pd_dvb->users)) {
- mutex_lock(&pd->lock);
- pd->state &= ~POSEIDON_STATE_DVBT;
- mutex_unlock(&pd->lock);
- }
- kref_put(&pd->kref, poseidon_delete);
- usb_autopm_put_interface(pd->interface);
- }
- return ret;
-}
-
-#ifdef CONFIG_PM
-static void poseidon_fe_release(struct dvb_frontend *fe)
-{
- struct poseidon *pd = fe->demodulator_priv;
-
- pd->pm_suspend = NULL;
- pd->pm_resume = NULL;
-}
-#else
-#define poseidon_fe_release NULL
-#endif
-
-static s32 poseidon_fe_sleep(struct dvb_frontend *fe)
-{
- return 0;
-}
-
-/*
- * return true if we can satisfy the conditions, else return false.
- */
-static bool check_scan_ok(__u32 freq, int bandwidth,
- struct pd_dvb_adapter *adapter)
-{
- if (bandwidth < 0)
- return false;
-
- if (adapter->prev_freq == freq
- && adapter->bandwidth == bandwidth) {
- long nl = jiffies - adapter->last_jiffies;
- unsigned int msec ;
-
- msec = jiffies_to_msecs(abs(nl));
- return msec > 15000 ? true : false;
- }
- return true;
-}
-
-/*
- * Check if the firmware delays too long for an invalid frequency.
- */
-static int fw_delay_overflow(struct pd_dvb_adapter *adapter)
-{
- long nl = jiffies - adapter->last_jiffies;
- unsigned int msec ;
-
- msec = jiffies_to_msecs(abs(nl));
- return msec > 800 ? true : false;
-}
-
-static int poseidon_set_fe(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
- s32 ret = 0, cmd_status = 0;
- s32 i, bandwidth = -1;
- struct poseidon *pd = fe->demodulator_priv;
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
-
- if (in_hibernation(pd))
- return -EBUSY;
-
- mutex_lock(&pd->lock);
- for (i = 0; i < dvb_bandwidth_length; i++)
- if (fep->bandwidth_hz == dvb_bandwidth[i][1])
- bandwidth = dvb_bandwidth[i][0];
-
- if (check_scan_ok(fep->frequency, bandwidth, pd_dvb)) {
- ret = send_set_req(pd, TUNE_FREQ_SELECT,
- fep->frequency / 1000, &cmd_status);
- if (ret | cmd_status) {
- log("error line");
- goto front_out;
- }
-
- ret = send_set_req(pd, DVBT_BANDW_SEL,
- bandwidth, &cmd_status);
- if (ret | cmd_status) {
- log("error line");
- goto front_out;
- }
-
- ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
- if (ret | cmd_status) {
- log("error line");
- goto front_out;
- }
-
- /* save the context for future */
- memcpy(&pd_dvb->fe_param, fep, sizeof(*fep));
- pd_dvb->bandwidth = bandwidth;
- pd_dvb->prev_freq = fep->frequency;
- pd_dvb->last_jiffies = jiffies;
- }
-front_out:
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int pm_dvb_suspend(struct poseidon *pd)
-{
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
- dvb_stop_streaming(pd_dvb);
- dvb_urb_cleanup(pd_dvb);
- msleep(500);
- return 0;
-}
-
-static int pm_dvb_resume(struct poseidon *pd)
-{
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
-
- poseidon_check_mode_dvbt(pd);
- msleep(300);
- poseidon_set_fe(&pd_dvb->dvb_fe);
-
- dvb_start_streaming(pd_dvb);
- return 0;
-}
-#endif
-
-static s32 poseidon_fe_init(struct dvb_frontend *fe)
-{
- struct poseidon *pd = fe->demodulator_priv;
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
-
-#ifdef CONFIG_PM
- pd->pm_suspend = pm_dvb_suspend;
- pd->pm_resume = pm_dvb_resume;
-#endif
- memset(&pd_dvb->fe_param, 0,
- sizeof(struct dtv_frontend_properties));
- return 0;
-}
-
-static int poseidon_get_fe(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
- struct poseidon *pd = fe->demodulator_priv;
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
-
- memcpy(fep, &pd_dvb->fe_param, sizeof(*fep));
- return 0;
-}
-
-static int poseidon_fe_get_tune_settings(struct dvb_frontend *fe,
- struct dvb_frontend_tune_settings *tune)
-{
- tune->min_delay_ms = 1000;
- return 0;
-}
-
-static int poseidon_read_status(struct dvb_frontend *fe, fe_status_t *stat)
-{
- struct poseidon *pd = fe->demodulator_priv;
- s32 ret = -1, cmd_status;
- struct tuner_dtv_sig_stat_s status = {};
-
- if (in_hibernation(pd))
- return -EBUSY;
- mutex_lock(&pd->lock);
-
- ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
- &status, &cmd_status, sizeof(status));
- if (ret | cmd_status) {
- log("get tuner status error");
- goto out;
- }
-
- if (debug_mode)
- log("P : %d, L %d, LB :%d", status.sig_present,
- status.sig_locked, status.sig_lock_busy);
-
- if (status.sig_lock_busy) {
- goto out;
- } else if (status.sig_present || status.sig_locked) {
- *stat |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER
- | FE_HAS_SYNC | FE_HAS_VITERBI;
- } else {
- if (fw_delay_overflow(&pd->dvb_data))
- *stat |= FE_TIMEDOUT;
- }
-out:
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static int poseidon_read_ber(struct dvb_frontend *fe, u32 *ber)
-{
- struct poseidon *pd = fe->demodulator_priv;
- struct tuner_ber_rate_s tlg_ber = {};
- s32 ret = -1, cmd_status;
-
- mutex_lock(&pd->lock);
- ret = send_get_req(pd, TUNER_BER_RATE, 0,
- &tlg_ber, &cmd_status, sizeof(tlg_ber));
- if (ret | cmd_status)
- goto out;
- *ber = tlg_ber.ber_rate;
-out:
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static s32 poseidon_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
-{
- struct poseidon *pd = fe->demodulator_priv;
- struct tuner_dtv_sig_stat_s status = {};
- s32 ret = 0, cmd_status;
-
- mutex_lock(&pd->lock);
- ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_DVB_T,
- &status, &cmd_status, sizeof(status));
- if (ret | cmd_status)
- goto out;
- if ((status.sig_present || status.sig_locked) && !status.sig_strength)
- *strength = 0xFFFF;
- else
- *strength = status.sig_strength;
-out:
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static int poseidon_read_snr(struct dvb_frontend *fe, u16 *snr)
-{
- return 0;
-}
-
-static int poseidon_read_unc_blocks(struct dvb_frontend *fe, u32 *unc)
-{
- *unc = 0;
- return 0;
-}
-
-static struct dvb_frontend_ops poseidon_frontend_ops = {
- .delsys = { SYS_DVBT },
- .info = {
- .name = "Poseidon DVB-T",
- .frequency_min = 174000000,
- .frequency_max = 862000000,
- .frequency_stepsize = 62500,/* FIXME */
- .caps = FE_CAN_INVERSION_AUTO |
- 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_64 |
- FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
- FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_RECOVER |
- FE_CAN_HIERARCHY_AUTO,
- },
-
- .release = poseidon_fe_release,
-
- .init = poseidon_fe_init,
- .sleep = poseidon_fe_sleep,
-
- .set_frontend = poseidon_set_fe,
- .get_frontend = poseidon_get_fe,
- .get_tune_settings = poseidon_fe_get_tune_settings,
-
- .read_status = poseidon_read_status,
- .read_ber = poseidon_read_ber,
- .read_signal_strength = poseidon_read_signal_strength,
- .read_snr = poseidon_read_snr,
- .read_ucblocks = poseidon_read_unc_blocks,
-
- .ts_bus_ctrl = poseidon_ts_bus_ctrl,
-};
-
-static void dvb_urb_irq(struct urb *urb)
-{
- struct pd_dvb_adapter *pd_dvb = urb->context;
- int len = urb->transfer_buffer_length;
- struct dvb_demux *demux = &pd_dvb->demux;
- s32 ret;
-
- if (!pd_dvb->is_streaming || urb->status) {
- if (urb->status == -EPROTO)
- goto resend;
- return;
- }
-
- if (urb->actual_length == len)
- dvb_dmx_swfilter(demux, urb->transfer_buffer, len);
- else if (urb->actual_length == len - 4) {
- int offset;
- u8 *buf = urb->transfer_buffer;
-
- /*
- * The packet size is 512,
- * last packet contains 456 bytes tsp data
- */
- for (offset = 456; offset < len; offset += 512) {
- if (!strncmp(buf + offset, "DVHS", 4)) {
- dvb_dmx_swfilter(demux, buf, offset);
- if (len > offset + 52 + 4) {
- /*16 bytes trailer + 36 bytes padding */
- buf += offset + 52;
- len -= offset + 52 + 4;
- dvb_dmx_swfilter(demux, buf, len);
- }
- break;
- }
- }
- }
-
-resend:
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- log(" usb_submit_urb failed: error %d", ret);
-}
-
-static int dvb_urb_init(struct pd_dvb_adapter *pd_dvb)
-{
- if (pd_dvb->urb_array[0])
- return 0;
-
- alloc_bulk_urbs_generic(pd_dvb->urb_array, DVB_SBUF_NUM,
- pd_dvb->pd_device->udev, pd_dvb->ep_addr,
- DVB_URB_BUF_SIZE, GFP_KERNEL,
- dvb_urb_irq, pd_dvb);
- return 0;
-}
-
-static void dvb_urb_cleanup(struct pd_dvb_adapter *pd_dvb)
-{
- free_all_urb_generic(pd_dvb->urb_array, DVB_SBUF_NUM);
-}
-
-static s32 dvb_start_streaming(struct pd_dvb_adapter *pd_dvb)
-{
- struct poseidon *pd = pd_dvb->pd_device;
- int ret = 0;
-
- if (pd->state & POSEIDON_STATE_DISCONNECT)
- return -ENODEV;
-
- mutex_lock(&pd->lock);
- if (!pd_dvb->is_streaming) {
- s32 i, cmd_status = 0;
- /*
- * Once upon a time, there was a difficult bug lying here.
- * ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
- */
-
- ret = send_set_req(pd, PLAY_SERVICE, 1, &cmd_status);
- if (ret | cmd_status)
- goto out;
-
- ret = dvb_urb_init(pd_dvb);
- if (ret < 0)
- goto out;
-
- pd_dvb->is_streaming = 1;
- for (i = 0; i < DVB_SBUF_NUM; i++) {
- ret = usb_submit_urb(pd_dvb->urb_array[i],
- GFP_KERNEL);
- if (ret) {
- log(" submit urb error %d", ret);
- goto out;
- }
- }
- }
-out:
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-void dvb_stop_streaming(struct pd_dvb_adapter *pd_dvb)
-{
- struct poseidon *pd = pd_dvb->pd_device;
-
- mutex_lock(&pd->lock);
- if (pd_dvb->is_streaming) {
- s32 i, ret, cmd_status = 0;
-
- pd_dvb->is_streaming = 0;
-
- for (i = 0; i < DVB_SBUF_NUM; i++)
- if (pd_dvb->urb_array[i])
- usb_kill_urb(pd_dvb->urb_array[i]);
-
- ret = send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
- &cmd_status);
- if (ret | cmd_status)
- log("error");
- }
- mutex_unlock(&pd->lock);
-}
-
-static int pd_start_feed(struct dvb_demux_feed *feed)
-{
- struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
- int ret = 0;
-
- if (!pd_dvb)
- return -1;
- if (atomic_inc_return(&pd_dvb->active_feed) == 1)
- ret = dvb_start_streaming(pd_dvb);
- return ret;
-}
-
-static int pd_stop_feed(struct dvb_demux_feed *feed)
-{
- struct pd_dvb_adapter *pd_dvb = feed->demux->priv;
-
- if (!pd_dvb)
- return -1;
- if (atomic_dec_and_test(&pd_dvb->active_feed))
- dvb_stop_streaming(pd_dvb);
- return 0;
-}
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-int pd_dvb_usb_device_init(struct poseidon *pd)
-{
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
- struct dvb_demux *dvbdemux;
- int ret = 0;
-
- pd_dvb->ep_addr = 0x82;
- atomic_set(&pd_dvb->users, 0);
- atomic_set(&pd_dvb->active_feed, 0);
- pd_dvb->pd_device = pd;
-
- ret = dvb_register_adapter(&pd_dvb->dvb_adap,
- "Poseidon dvbt adapter",
- THIS_MODULE,
- NULL /* for hibernation correctly*/,
- adapter_nr);
- if (ret < 0)
- goto error1;
-
- /* register frontend */
- pd_dvb->dvb_fe.demodulator_priv = pd;
- memcpy(&pd_dvb->dvb_fe.ops, &poseidon_frontend_ops,
- sizeof(struct dvb_frontend_ops));
- ret = dvb_register_frontend(&pd_dvb->dvb_adap, &pd_dvb->dvb_fe);
- if (ret < 0)
- goto error2;
-
- /* register demux device */
- dvbdemux = &pd_dvb->demux;
- dvbdemux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
- dvbdemux->priv = pd_dvb;
- dvbdemux->feednum = dvbdemux->filternum = 64;
- dvbdemux->start_feed = pd_start_feed;
- dvbdemux->stop_feed = pd_stop_feed;
- dvbdemux->write_to_decoder = NULL;
-
- ret = dvb_dmx_init(dvbdemux);
- if (ret < 0)
- goto error3;
-
- pd_dvb->dmxdev.filternum = pd_dvb->demux.filternum;
- pd_dvb->dmxdev.demux = &pd_dvb->demux.dmx;
- pd_dvb->dmxdev.capabilities = 0;
-
- ret = dvb_dmxdev_init(&pd_dvb->dmxdev, &pd_dvb->dvb_adap);
- if (ret < 0)
- goto error3;
- return 0;
-
-error3:
- dvb_unregister_frontend(&pd_dvb->dvb_fe);
-error2:
- dvb_unregister_adapter(&pd_dvb->dvb_adap);
-error1:
- return ret;
-}
-
-void pd_dvb_usb_device_exit(struct poseidon *pd)
-{
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
-
- while (atomic_read(&pd_dvb->users) != 0
- || atomic_read(&pd_dvb->active_feed) != 0) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
- }
- dvb_dmxdev_release(&pd_dvb->dmxdev);
- dvb_unregister_frontend(&pd_dvb->dvb_fe);
- dvb_unregister_adapter(&pd_dvb->dvb_adap);
- pd_dvb_usb_device_cleanup(pd);
-}
-
-void pd_dvb_usb_device_cleanup(struct poseidon *pd)
-{
- struct pd_dvb_adapter *pd_dvb = &pd->dvb_data;
-
- dvb_urb_cleanup(pd_dvb);
-}
-
-int pd_dvb_get_adapter_num(struct pd_dvb_adapter *pd_dvb)
-{
- return pd_dvb->dvb_adap.num;
-}
diff --git a/drivers/staging/media/tlg2300/pd-main.c b/drivers/staging/media/tlg2300/pd-main.c
deleted file mode 100644
index b31f4791b8ff..000000000000
--- a/drivers/staging/media/tlg2300/pd-main.c
+++ /dev/null
@@ -1,553 +0,0 @@
-/*
- * device driver for Telegent tlg2300 based TV cards
- *
- * Author :
- * Kang Yong <kangyong@telegent.com>
- * Zhang Xiaobing <xbzhang@telegent.com>
- * Huang Shijie <zyziii@telegent.com> or <shijie8@gmail.com>
- *
- * (c) 2009 Telegent Systems
- * (c) 2010 Telegent Systems
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU 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., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/errno.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/kref.h>
-#include <linux/suspend.h>
-#include <linux/usb/quirks.h>
-#include <linux/ctype.h>
-#include <linux/string.h>
-#include <linux/types.h>
-#include <linux/firmware.h>
-
-#include "vendorcmds.h"
-#include "pd-common.h"
-
-#define VENDOR_ID 0x1B24
-#define PRODUCT_ID 0x4001
-static struct usb_device_id id_table[] = {
- { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 0) },
- { USB_DEVICE_AND_INTERFACE_INFO(VENDOR_ID, PRODUCT_ID, 255, 1, 1) },
- { },
-};
-MODULE_DEVICE_TABLE(usb, id_table);
-
-int debug_mode;
-module_param(debug_mode, int, 0644);
-MODULE_PARM_DESC(debug_mode, "0 = disable, 1 = enable, 2 = verbose");
-
-#define TLG2300_FIRMWARE "tlg2300_firmware.bin"
-static const char *firmware_name = TLG2300_FIRMWARE;
-static LIST_HEAD(pd_device_list);
-
-/*
- * send set request to USB firmware.
- */
-s32 send_set_req(struct poseidon *pd, u8 cmdid, s32 param, s32 *cmd_status)
-{
- s32 ret;
- s8 data[32] = {};
- u16 lower_16, upper_16;
-
- if (pd->state & POSEIDON_STATE_DISCONNECT)
- return -ENODEV;
-
- mdelay(30);
-
- if (param == 0) {
- upper_16 = lower_16 = 0;
- } else {
- /* send 32 bit param as two 16 bit param,little endian */
- lower_16 = (unsigned short)(param & 0xffff);
- upper_16 = (unsigned short)((param >> 16) & 0xffff);
- }
- ret = usb_control_msg(pd->udev,
- usb_rcvctrlpipe(pd->udev, 0),
- REQ_SET_CMD | cmdid,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- lower_16,
- upper_16,
- &data,
- sizeof(*cmd_status),
- USB_CTRL_GET_TIMEOUT);
-
- if (!ret) {
- return -ENXIO;
- } else {
- /* 1st 4 bytes into cmd_status */
- memcpy((char *)cmd_status, &(data[0]), sizeof(*cmd_status));
- }
- return 0;
-}
-
-/*
- * send get request to Poseidon firmware.
- */
-s32 send_get_req(struct poseidon *pd, u8 cmdid, s32 param,
- void *buf, s32 *cmd_status, s32 datalen)
-{
- s32 ret;
- s8 data[128] = {};
- u16 lower_16, upper_16;
-
- if (pd->state & POSEIDON_STATE_DISCONNECT)
- return -ENODEV;
-
- mdelay(30);
- if (param == 0) {
- upper_16 = lower_16 = 0;
- } else {
- /*send 32 bit param as two 16 bit param, little endian */
- lower_16 = (unsigned short)(param & 0xffff);
- upper_16 = (unsigned short)((param >> 16) & 0xffff);
- }
- ret = usb_control_msg(pd->udev,
- usb_rcvctrlpipe(pd->udev, 0),
- REQ_GET_CMD | cmdid,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- lower_16,
- upper_16,
- &data,
- (datalen + sizeof(*cmd_status)),
- USB_CTRL_GET_TIMEOUT);
-
- if (ret < 0) {
- return -ENXIO;
- } else {
- /* 1st 4 bytes into cmd_status, remaining data into cmd_data */
- memcpy((char *)cmd_status, &data[0], sizeof(*cmd_status));
- memcpy((char *)buf, &data[sizeof(*cmd_status)], datalen);
- }
- return 0;
-}
-
-static int pm_notifier_block(struct notifier_block *nb,
- unsigned long event, void *dummy)
-{
- struct poseidon *pd = NULL;
- struct list_head *node, *next;
-
- switch (event) {
- case PM_POST_HIBERNATION:
- list_for_each_safe(node, next, &pd_device_list) {
- struct usb_device *udev;
- struct usb_interface *iface;
- int rc = 0;
-
- pd = container_of(node, struct poseidon, device_list);
- udev = pd->udev;
- iface = pd->interface;
-
- /* It will cause the system to reload the firmware */
- rc = usb_lock_device_for_reset(udev, iface);
- if (rc >= 0) {
- usb_reset_device(udev);
- usb_unlock_device(udev);
- }
- }
- break;
- default:
- break;
- }
- log("event :%ld\n", event);
- return 0;
-}
-
-static struct notifier_block pm_notifer = {
- .notifier_call = pm_notifier_block,
-};
-
-int set_tuner_mode(struct poseidon *pd, unsigned char mode)
-{
- s32 ret, cmd_status;
-
- if (pd->state & POSEIDON_STATE_DISCONNECT)
- return -ENODEV;
-
- ret = send_set_req(pd, TUNE_MODE_SELECT, mode, &cmd_status);
- if (ret || cmd_status)
- return -ENXIO;
- return 0;
-}
-
-void poseidon_delete(struct kref *kref)
-{
- struct poseidon *pd = container_of(kref, struct poseidon, kref);
-
- if (!pd)
- return;
- list_del_init(&pd->device_list);
-
- pd_dvb_usb_device_cleanup(pd);
- /* clean_audio_data(&pd->audio_data);*/
-
- if (pd->udev) {
- usb_put_dev(pd->udev);
- pd->udev = NULL;
- }
- if (pd->interface) {
- usb_put_intf(pd->interface);
- pd->interface = NULL;
- }
- kfree(pd);
- log();
-}
-
-static int firmware_download(struct usb_device *udev)
-{
- int ret = 0, actual_length;
- const struct firmware *fw = NULL;
- void *fwbuf = NULL;
- size_t fwlength = 0, offset;
- size_t max_packet_size;
-
- ret = request_firmware(&fw, firmware_name, &udev->dev);
- if (ret) {
- log("download err : %d", ret);
- return ret;
- }
-
- fwlength = fw->size;
-
- fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL);
- if (!fwbuf) {
- ret = -ENOMEM;
- goto out;
- }
-
- max_packet_size = le16_to_cpu(udev->ep_out[0x1]->desc.wMaxPacketSize);
- log("\t\t download size : %d", (int)max_packet_size);
-
- for (offset = 0; offset < fwlength; offset += max_packet_size) {
- actual_length = 0;
- ret = usb_bulk_msg(udev,
- usb_sndbulkpipe(udev, 0x01), /* ep 1 */
- fwbuf + offset,
- min(max_packet_size, fwlength - offset),
- &actual_length,
- HZ * 10);
- if (ret)
- break;
- }
- kfree(fwbuf);
-out:
- release_firmware(fw);
- return ret;
-}
-
-static inline struct poseidon *get_pd(struct usb_interface *intf)
-{
- return usb_get_intfdata(intf);
-}
-
-#ifdef CONFIG_PM
-/* one-to-one map : poseidon{} <----> usb_device{}'s port */
-static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
-{
- pd->portnum = udev->portnum;
-}
-
-static inline int get_autopm_ref(struct poseidon *pd)
-{
- return pd->video_data.users + pd->vbi_data.users + pd->audio.users
- + atomic_read(&pd->dvb_data.users) +
- !list_empty(&pd->radio_data.fm_dev.fh_list);
-}
-
-/* fixup something for poseidon */
-static inline struct poseidon *fixup(struct poseidon *pd)
-{
- int count;
-
- /* old udev and interface have gone, so put back reference . */
- count = get_autopm_ref(pd);
- log("count : %d, ref count : %d", count, get_pm_count(pd));
- while (count--)
- usb_autopm_put_interface(pd->interface);
- /*usb_autopm_set_interface(pd->interface); */
-
- usb_put_dev(pd->udev);
- usb_put_intf(pd->interface);
- log("event : %d\n", pd->msg.event);
- return pd;
-}
-
-static struct poseidon *find_old_poseidon(struct usb_device *udev)
-{
- struct poseidon *pd;
-
- list_for_each_entry(pd, &pd_device_list, device_list) {
- if (pd->portnum == udev->portnum && in_hibernation(pd))
- return fixup(pd);
- }
- return NULL;
-}
-
-/* Is the card working now ? */
-static inline int is_working(struct poseidon *pd)
-{
- return get_pm_count(pd) > 0;
-}
-
-static int poseidon_suspend(struct usb_interface *intf, pm_message_t msg)
-{
- struct poseidon *pd = get_pd(intf);
-
- if (!pd)
- return 0;
- if (!is_working(pd)) {
- if (get_pm_count(pd) <= 0 && !in_hibernation(pd)) {
- pd->msg.event = PM_EVENT_AUTO_SUSPEND;
- pd->pm_resume = NULL; /* a good guard */
- printk(KERN_DEBUG "TLG2300 auto suspend\n");
- }
- return 0;
- }
- pd->msg = msg; /* save it here */
- logpm(pd);
- return pd->pm_suspend ? pd->pm_suspend(pd) : 0;
-}
-
-static int poseidon_resume(struct usb_interface *intf)
-{
- struct poseidon *pd = get_pd(intf);
-
- if (!pd)
- return 0;
- printk(KERN_DEBUG "TLG2300 resume\n");
-
- if (!is_working(pd)) {
- if (PM_EVENT_AUTO_SUSPEND == pd->msg.event)
- pd->msg = PMSG_ON;
- return 0;
- }
- if (in_hibernation(pd)) {
- logpm(pd);
- return 0;
- }
- logpm(pd);
- return pd->pm_resume ? pd->pm_resume(pd) : 0;
-}
-
-static void hibernation_resume(struct work_struct *w)
-{
- struct poseidon *pd = container_of(w, struct poseidon, pm_work);
- int count;
-
- pd->msg.event = 0; /* clear it here */
- pd->state &= ~POSEIDON_STATE_DISCONNECT;
-
- /* set the new interface's reference */
- count = get_autopm_ref(pd);
- while (count--)
- usb_autopm_get_interface(pd->interface);
-
- /* resume the context */
- logpm(pd);
- if (pd->pm_resume)
- pd->pm_resume(pd);
-}
-#else /* CONFIG_PM is not enabled: */
-static inline struct poseidon *find_old_poseidon(struct usb_device *udev)
-{
- return NULL;
-}
-
-static inline void set_map_flags(struct poseidon *pd, struct usb_device *udev)
-{
-}
-#endif
-
-static int check_firmware(struct usb_device *udev)
-{
- void *buf;
- int ret;
- struct cmd_firmware_vers_s *cmd_firm;
-
- buf = kzalloc(sizeof(*cmd_firm) + sizeof(u32), GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- ret = usb_control_msg(udev,
- usb_rcvctrlpipe(udev, 0),
- REQ_GET_CMD | GET_FW_ID,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0,
- 0,
- buf,
- sizeof(*cmd_firm) + sizeof(u32),
- USB_CTRL_GET_TIMEOUT);
- kfree(buf);
-
- if (ret < 0)
- return firmware_download(udev);
- return 0;
-}
-
-static int poseidon_probe(struct usb_interface *interface,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(interface);
- struct poseidon *pd = NULL;
- int ret = 0;
- int new_one = 0;
-
- /* download firmware */
- ret = check_firmware(udev);
- if (ret)
- return ret;
-
- /* Do I recovery from the hibernate ? */
- pd = find_old_poseidon(udev);
- if (!pd) {
- pd = kzalloc(sizeof(*pd), GFP_KERNEL);
- if (!pd)
- return -ENOMEM;
- kref_init(&pd->kref);
- set_map_flags(pd, udev);
- new_one = 1;
- }
-
- pd->udev = usb_get_dev(udev);
- pd->interface = usb_get_intf(interface);
- usb_set_intfdata(interface, pd);
-
- if (new_one) {
- logpm(pd);
- mutex_init(&pd->lock);
-
- /* register v4l2 device */
- ret = v4l2_device_register(&interface->dev, &pd->v4l2_dev);
- if (ret)
- goto err_v4l2;
-
- /* register devices in directory /dev */
- ret = pd_video_init(pd);
- if (ret)
- goto err_video;
- ret = poseidon_audio_init(pd);
- if (ret)
- goto err_audio;
- ret = poseidon_fm_init(pd);
- if (ret)
- goto err_fm;
- ret = pd_dvb_usb_device_init(pd);
- if (ret)
- goto err_dvb;
-
- INIT_LIST_HEAD(&pd->device_list);
- list_add_tail(&pd->device_list, &pd_device_list);
- }
-
- device_init_wakeup(&udev->dev, 1);
-#ifdef CONFIG_PM
- pm_runtime_set_autosuspend_delay(&pd->udev->dev,
- 1000 * PM_SUSPEND_DELAY);
- usb_enable_autosuspend(pd->udev);
-
- if (in_hibernation(pd)) {
- INIT_WORK(&pd->pm_work, hibernation_resume);
- schedule_work(&pd->pm_work);
- }
-#endif
- return 0;
-err_dvb:
- poseidon_fm_exit(pd);
-err_fm:
- poseidon_audio_free(pd);
-err_audio:
- pd_video_exit(pd);
-err_video:
- v4l2_device_unregister(&pd->v4l2_dev);
-err_v4l2:
- usb_put_intf(pd->interface);
- usb_put_dev(pd->udev);
- kfree(pd);
- return ret;
-}
-
-static void poseidon_disconnect(struct usb_interface *interface)
-{
- struct poseidon *pd = get_pd(interface);
-
- if (!pd)
- return;
- logpm(pd);
- if (in_hibernation(pd))
- return;
-
- mutex_lock(&pd->lock);
- pd->state |= POSEIDON_STATE_DISCONNECT;
- mutex_unlock(&pd->lock);
-
- /* stop urb transferring */
- stop_all_video_stream(pd);
- dvb_stop_streaming(&pd->dvb_data);
-
- /*unregister v4l2 device */
- v4l2_device_unregister(&pd->v4l2_dev);
-
- pd_dvb_usb_device_exit(pd);
- poseidon_fm_exit(pd);
-
- poseidon_audio_free(pd);
- pd_video_exit(pd);
-
- usb_set_intfdata(interface, NULL);
- kref_put(&pd->kref, poseidon_delete);
-}
-
-static struct usb_driver poseidon_driver = {
- .name = "poseidon",
- .probe = poseidon_probe,
- .disconnect = poseidon_disconnect,
- .id_table = id_table,
-#ifdef CONFIG_PM
- .suspend = poseidon_suspend,
- .resume = poseidon_resume,
-#endif
- .supports_autosuspend = 1,
-};
-
-static int __init poseidon_init(void)
-{
- int ret;
-
- ret = usb_register(&poseidon_driver);
- if (ret)
- return ret;
- register_pm_notifier(&pm_notifer);
- return ret;
-}
-
-static void __exit poseidon_exit(void)
-{
- log();
- unregister_pm_notifier(&pm_notifer);
- usb_deregister(&poseidon_driver);
-}
-
-module_init(poseidon_init);
-module_exit(poseidon_exit);
-
-MODULE_AUTHOR("Telegent Systems");
-MODULE_DESCRIPTION("For tlg2300-based USB device");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("0.0.2");
-MODULE_FIRMWARE(TLG2300_FIRMWARE);
diff --git a/drivers/staging/media/tlg2300/pd-radio.c b/drivers/staging/media/tlg2300/pd-radio.c
deleted file mode 100644
index b391194a840c..000000000000
--- a/drivers/staging/media/tlg2300/pd-radio.c
+++ /dev/null
@@ -1,339 +0,0 @@
-#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 <media/v4l2-dev.h>
-#include <linux/mm.h>
-#include <linux/mutex.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-event.h>
-#include <media/v4l2-fh.h>
-#include <linux/sched.h>
-
-#include "pd-common.h"
-#include "vendorcmds.h"
-
-static int set_frequency(struct poseidon *p, __u32 frequency);
-static int poseidon_fm_close(struct file *filp);
-static int poseidon_fm_open(struct file *filp);
-
-#define TUNER_FREQ_MIN_FM 76000000U
-#define TUNER_FREQ_MAX_FM 108000000U
-
-#define MAX_PREEMPHASIS (V4L2_PREEMPHASIS_75_uS + 1)
-static int preemphasis[MAX_PREEMPHASIS] = {
- TLG_TUNE_ASTD_NONE, /* V4L2_PREEMPHASIS_DISABLED */
- TLG_TUNE_ASTD_FM_EUR, /* V4L2_PREEMPHASIS_50_uS */
- TLG_TUNE_ASTD_FM_US, /* V4L2_PREEMPHASIS_75_uS */
-};
-
-static int poseidon_check_mode_radio(struct poseidon *p)
-{
- int ret;
- u32 status;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/2);
- ret = usb_set_interface(p->udev, 0, BULK_ALTERNATE_IFACE);
- if (ret < 0)
- goto out;
-
- ret = set_tuner_mode(p, TLG_MODE_FM_RADIO);
- if (ret != 0)
- goto out;
-
- ret = send_set_req(p, SGNL_SRC_SEL, TLG_SIG_SRC_ANTENNA, &status);
- ret = send_set_req(p, TUNER_AUD_ANA_STD,
- p->radio_data.pre_emphasis, &status);
- ret |= send_set_req(p, TUNER_AUD_MODE,
- TLG_TUNE_TVAUDIO_MODE_STEREO, &status);
- ret |= send_set_req(p, AUDIO_SAMPLE_RATE_SEL,
- ATV_AUDIO_RATE_48K, &status);
- ret |= send_set_req(p, TUNE_FREQ_SELECT, TUNER_FREQ_MIN_FM, &status);
-out:
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int pm_fm_suspend(struct poseidon *p)
-{
- logpm(p);
- pm_alsa_suspend(p);
- usb_set_interface(p->udev, 0, 0);
- msleep(300);
- return 0;
-}
-
-static int pm_fm_resume(struct poseidon *p)
-{
- logpm(p);
- poseidon_check_mode_radio(p);
- set_frequency(p, p->radio_data.fm_freq);
- pm_alsa_resume(p);
- return 0;
-}
-#endif
-
-static int poseidon_fm_open(struct file *filp)
-{
- struct poseidon *p = video_drvdata(filp);
- int ret = 0;
-
- mutex_lock(&p->lock);
- if (p->state & POSEIDON_STATE_DISCONNECT) {
- ret = -ENODEV;
- goto out;
- }
-
- if (p->state && !(p->state & POSEIDON_STATE_FM)) {
- ret = -EBUSY;
- goto out;
- }
- ret = v4l2_fh_open(filp);
- if (ret)
- goto out;
-
- usb_autopm_get_interface(p->interface);
- if (0 == p->state) {
- struct video_device *vfd = &p->radio_data.fm_dev;
-
- /* default pre-emphasis */
- if (p->radio_data.pre_emphasis == 0)
- p->radio_data.pre_emphasis = TLG_TUNE_ASTD_FM_EUR;
- set_debug_mode(vfd, debug_mode);
-
- ret = poseidon_check_mode_radio(p);
- if (ret < 0) {
- usb_autopm_put_interface(p->interface);
- goto out;
- }
- p->state |= POSEIDON_STATE_FM;
- }
- kref_get(&p->kref);
-out:
- mutex_unlock(&p->lock);
- return ret;
-}
-
-static int poseidon_fm_close(struct file *filp)
-{
- struct poseidon *p = video_drvdata(filp);
- struct radio_data *fm = &p->radio_data;
- uint32_t status;
-
- mutex_lock(&p->lock);
- if (v4l2_fh_is_singular_file(filp))
- p->state &= ~POSEIDON_STATE_FM;
-
- if (fm->is_radio_streaming && filp == p->file_for_stream) {
- fm->is_radio_streaming = 0;
- send_set_req(p, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP, &status);
- }
- usb_autopm_put_interface(p->interface);
- mutex_unlock(&p->lock);
-
- kref_put(&p->kref, poseidon_delete);
- return v4l2_fh_release(filp);
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- struct poseidon *p = video_drvdata(file);
-
- strlcpy(v->driver, "tele-radio", sizeof(v->driver));
- strlcpy(v->card, "Telegent Poseidon", sizeof(v->card));
- usb_make_path(p->udev, v->bus_info, sizeof(v->bus_info));
- v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
- /* Report all capabilities of the USB device */
- v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_AUDIO | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
- return 0;
-}
-
-static const struct v4l2_file_operations poseidon_fm_fops = {
- .owner = THIS_MODULE,
- .open = poseidon_fm_open,
- .release = poseidon_fm_close,
- .poll = v4l2_ctrl_poll,
- .unlocked_ioctl = video_ioctl2,
-};
-
-static int tlg_fm_vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *vt)
-{
- struct poseidon *p = video_drvdata(file);
- struct tuner_fm_sig_stat_s fm_stat = {};
- int ret, status, count = 5;
-
- if (vt->index != 0)
- return -EINVAL;
-
- vt->type = V4L2_TUNER_RADIO;
- vt->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW;
- vt->rangelow = TUNER_FREQ_MIN_FM * 2 / 125;
- vt->rangehigh = TUNER_FREQ_MAX_FM * 2 / 125;
- vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
- vt->audmode = V4L2_TUNER_MODE_STEREO;
- vt->signal = 0;
- vt->afc = 0;
- strlcpy(vt->name, "Radio", sizeof(vt->name));
-
- mutex_lock(&p->lock);
- ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
- &fm_stat, &status, sizeof(fm_stat));
-
- while (fm_stat.sig_lock_busy && count-- && !ret) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
-
- ret = send_get_req(p, TUNER_STATUS, TLG_MODE_FM_RADIO,
- &fm_stat, &status, sizeof(fm_stat));
- }
- mutex_unlock(&p->lock);
-
- if (ret || status) {
- vt->signal = 0;
- } else if ((fm_stat.sig_present || fm_stat.sig_locked)
- && fm_stat.sig_strength == 0) {
- vt->signal = 0xffff;
- } else
- vt->signal = (fm_stat.sig_strength * 255 / 10) << 8;
-
- return 0;
-}
-
-static int fm_get_freq(struct file *file, void *priv,
- struct v4l2_frequency *argp)
-{
- struct poseidon *p = video_drvdata(file);
-
- if (argp->tuner)
- return -EINVAL;
- argp->frequency = p->radio_data.fm_freq;
- return 0;
-}
-
-static int set_frequency(struct poseidon *p, __u32 frequency)
-{
- __u32 freq ;
- int ret, status;
-
- mutex_lock(&p->lock);
-
- ret = send_set_req(p, TUNER_AUD_ANA_STD,
- p->radio_data.pre_emphasis, &status);
-
- freq = (frequency * 125) / 2; /* Hz */
- freq = clamp(freq, TUNER_FREQ_MIN_FM, TUNER_FREQ_MAX_FM);
-
- ret = send_set_req(p, TUNE_FREQ_SELECT, freq, &status);
- if (ret < 0)
- goto error ;
- ret = send_set_req(p, TAKE_REQUEST, 0, &status);
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/4);
- if (!p->radio_data.is_radio_streaming) {
- ret = send_set_req(p, TAKE_REQUEST, 0, &status);
- ret = send_set_req(p, PLAY_SERVICE,
- TLG_TUNE_PLAY_SVC_START, &status);
- p->radio_data.is_radio_streaming = 1;
- }
- p->radio_data.fm_freq = freq * 2 / 125;
-error:
- mutex_unlock(&p->lock);
- return ret;
-}
-
-static int fm_set_freq(struct file *file, void *priv,
- const struct v4l2_frequency *argp)
-{
- struct poseidon *p = video_drvdata(file);
-
- if (argp->tuner)
- return -EINVAL;
- p->file_for_stream = file;
-#ifdef CONFIG_PM
- p->pm_suspend = pm_fm_suspend;
- p->pm_resume = pm_fm_resume;
-#endif
- return set_frequency(p, argp->frequency);
-}
-
-static int tlg_fm_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct poseidon *p = container_of(ctrl->handler, struct poseidon,
- radio_data.ctrl_handler);
- int pre_emphasis;
- u32 status;
-
- switch (ctrl->id) {
- case V4L2_CID_TUNE_PREEMPHASIS:
- pre_emphasis = preemphasis[ctrl->val];
- send_set_req(p, TUNER_AUD_ANA_STD, pre_emphasis, &status);
- p->radio_data.pre_emphasis = pre_emphasis;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv, const struct v4l2_tuner *vt)
-{
- return vt->index > 0 ? -EINVAL : 0;
-}
-
-static const struct v4l2_ctrl_ops tlg_fm_ctrl_ops = {
- .s_ctrl = tlg_fm_s_ctrl,
-};
-
-static const struct v4l2_ioctl_ops poseidon_fm_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_tuner = tlg_fm_vidioc_g_tuner,
- .vidioc_g_frequency = fm_get_freq,
- .vidioc_s_frequency = fm_set_freq,
- .vidioc_subscribe_event = v4l2_ctrl_subscribe_event,
- .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
-};
-
-static struct video_device poseidon_fm_template = {
- .name = "Telegent-Radio",
- .fops = &poseidon_fm_fops,
- .minor = -1,
- .release = video_device_release_empty,
- .ioctl_ops = &poseidon_fm_ioctl_ops,
-};
-
-int poseidon_fm_init(struct poseidon *p)
-{
- struct video_device *vfd = &p->radio_data.fm_dev;
- struct v4l2_ctrl_handler *hdl = &p->radio_data.ctrl_handler;
-
- *vfd = poseidon_fm_template;
-
- set_frequency(p, TUNER_FREQ_MIN_FM);
- v4l2_ctrl_handler_init(hdl, 1);
- v4l2_ctrl_new_std_menu(hdl, &tlg_fm_ctrl_ops, V4L2_CID_TUNE_PREEMPHASIS,
- V4L2_PREEMPHASIS_75_uS, 0, V4L2_PREEMPHASIS_50_uS);
- if (hdl->error) {
- v4l2_ctrl_handler_free(hdl);
- return hdl->error;
- }
- vfd->v4l2_dev = &p->v4l2_dev;
- vfd->ctrl_handler = hdl;
- video_set_drvdata(vfd, p);
- return video_register_device(vfd, VFL_TYPE_RADIO, -1);
-}
-
-int poseidon_fm_exit(struct poseidon *p)
-{
- video_unregister_device(&p->radio_data.fm_dev);
- v4l2_ctrl_handler_free(&p->radio_data.ctrl_handler);
- return 0;
-}
diff --git a/drivers/staging/media/tlg2300/pd-video.c b/drivers/staging/media/tlg2300/pd-video.c
deleted file mode 100644
index 8cd7f02fcf9f..000000000000
--- a/drivers/staging/media/tlg2300/pd-video.c
+++ /dev/null
@@ -1,1570 +0,0 @@
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev2.h>
-#include <linux/usb.h>
-#include <linux/mm.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-dev.h>
-#include <media/v4l2-ctrls.h>
-
-#include "pd-common.h"
-#include "vendorcmds.h"
-
-#ifdef CONFIG_PM
-static int pm_video_suspend(struct poseidon *pd);
-static int pm_video_resume(struct poseidon *pd);
-#endif
-static void iso_bubble_handler(struct work_struct *w);
-
-static int usb_transfer_mode;
-module_param(usb_transfer_mode, int, 0644);
-MODULE_PARM_DESC(usb_transfer_mode, "0 = Bulk, 1 = Isochronous");
-
-static const struct poseidon_format poseidon_formats[] = {
- { "YUV 422", V4L2_PIX_FMT_YUYV, 16, 0},
- { "RGB565", V4L2_PIX_FMT_RGB565, 16, 0},
-};
-
-static const struct poseidon_tvnorm poseidon_tvnorms[] = {
- { V4L2_STD_PAL_D, "PAL-D", TLG_TUNE_VSTD_PAL_D },
- { V4L2_STD_PAL_B, "PAL-B", TLG_TUNE_VSTD_PAL_B },
- { V4L2_STD_PAL_G, "PAL-G", TLG_TUNE_VSTD_PAL_G },
- { V4L2_STD_PAL_H, "PAL-H", TLG_TUNE_VSTD_PAL_H },
- { V4L2_STD_PAL_I, "PAL-I", TLG_TUNE_VSTD_PAL_I },
- { V4L2_STD_PAL_M, "PAL-M", TLG_TUNE_VSTD_PAL_M },
- { V4L2_STD_PAL_N, "PAL-N", TLG_TUNE_VSTD_PAL_N_COMBO },
- { V4L2_STD_PAL_Nc, "PAL-Nc", TLG_TUNE_VSTD_PAL_N_COMBO },
- { V4L2_STD_NTSC_M, "NTSC-M", TLG_TUNE_VSTD_NTSC_M },
- { V4L2_STD_NTSC_M_JP, "NTSC-JP", TLG_TUNE_VSTD_NTSC_M_J },
- { V4L2_STD_SECAM_B, "SECAM-B", TLG_TUNE_VSTD_SECAM_B },
- { V4L2_STD_SECAM_D, "SECAM-D", TLG_TUNE_VSTD_SECAM_D },
- { V4L2_STD_SECAM_G, "SECAM-G", TLG_TUNE_VSTD_SECAM_G },
- { V4L2_STD_SECAM_H, "SECAM-H", TLG_TUNE_VSTD_SECAM_H },
- { V4L2_STD_SECAM_K, "SECAM-K", TLG_TUNE_VSTD_SECAM_K },
- { V4L2_STD_SECAM_K1, "SECAM-K1", TLG_TUNE_VSTD_SECAM_K1 },
- { V4L2_STD_SECAM_L, "SECAM-L", TLG_TUNE_VSTD_SECAM_L },
- { V4L2_STD_SECAM_LC, "SECAM-LC", TLG_TUNE_VSTD_SECAM_L1 },
-};
-static const unsigned int POSEIDON_TVNORMS = ARRAY_SIZE(poseidon_tvnorms);
-
-struct pd_audio_mode {
- u32 tlg_audio_mode;
- u32 v4l2_audio_sub;
- u32 v4l2_audio_mode;
-};
-
-static const struct pd_audio_mode pd_audio_modes[] = {
- { TLG_TUNE_TVAUDIO_MODE_MONO, V4L2_TUNER_SUB_MONO,
- V4L2_TUNER_MODE_MONO },
- { TLG_TUNE_TVAUDIO_MODE_STEREO, V4L2_TUNER_SUB_STEREO,
- V4L2_TUNER_MODE_STEREO },
- { TLG_TUNE_TVAUDIO_MODE_LANG_A, V4L2_TUNER_SUB_LANG1,
- V4L2_TUNER_MODE_LANG1 },
- { TLG_TUNE_TVAUDIO_MODE_LANG_B, V4L2_TUNER_SUB_LANG2,
- V4L2_TUNER_MODE_LANG2 },
- { TLG_TUNE_TVAUDIO_MODE_LANG_C, V4L2_TUNER_SUB_LANG1,
- V4L2_TUNER_MODE_LANG1_LANG2 }
-};
-static const unsigned int POSEIDON_AUDIOMODS = ARRAY_SIZE(pd_audio_modes);
-
-struct pd_input {
- char *name;
- uint32_t tlg_src;
-};
-
-static const struct pd_input pd_inputs[] = {
- { "TV Antenna", TLG_SIG_SRC_ANTENNA },
- { "TV Cable", TLG_SIG_SRC_CABLE },
- { "TV SVideo", TLG_SIG_SRC_SVIDEO },
- { "TV Composite", TLG_SIG_SRC_COMPOSITE }
-};
-static const unsigned int POSEIDON_INPUTS = ARRAY_SIZE(pd_inputs);
-
-struct video_std_to_audio_std {
- v4l2_std_id video_std;
- int audio_std;
-};
-
-static const struct video_std_to_audio_std video_to_audio_map[] = {
- /* country : { 27, 32, 33, 34, 36, 44, 45, 46, 47, 48, 64,
- 65, 86, 351, 352, 353, 354, 358, 372, 852, 972 } */
- { (V4L2_STD_PAL_I | V4L2_STD_PAL_B | V4L2_STD_PAL_D |
- V4L2_STD_SECAM_L | V4L2_STD_SECAM_D), TLG_TUNE_ASTD_NICAM },
-
- /* country : { 1, 52, 54, 55, 886 } */
- {V4L2_STD_NTSC_M | V4L2_STD_PAL_N | V4L2_STD_PAL_M, TLG_TUNE_ASTD_BTSC},
-
- /* country : { 81 } */
- { V4L2_STD_NTSC_M_JP, TLG_TUNE_ASTD_EIAJ },
-
- /* other country : TLG_TUNE_ASTD_A2 */
-};
-static const unsigned int map_size = ARRAY_SIZE(video_to_audio_map);
-
-static int get_audio_std(v4l2_std_id v4l2_std)
-{
- int i = 0;
-
- for (; i < map_size; i++) {
- if (v4l2_std & video_to_audio_map[i].video_std)
- return video_to_audio_map[i].audio_std;
- }
- return TLG_TUNE_ASTD_A2;
-}
-
-static int vidioc_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
-{
- struct video_device *vdev = video_devdata(file);
- struct poseidon *p = video_get_drvdata(vdev);
-
- strcpy(cap->driver, "tele-video");
- strcpy(cap->card, "Telegent Poseidon");
- usb_make_path(p->udev, cap->bus_info, sizeof(cap->bus_info));
- cap->device_caps = V4L2_CAP_TUNER | V4L2_CAP_AUDIO |
- V4L2_CAP_STREAMING | V4L2_CAP_READWRITE;
- if (vdev->vfl_type == VFL_TYPE_VBI)
- cap->device_caps |= V4L2_CAP_VBI_CAPTURE;
- else
- cap->device_caps |= V4L2_CAP_VIDEO_CAPTURE;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS |
- V4L2_CAP_RADIO | V4L2_CAP_VBI_CAPTURE | V4L2_CAP_VIDEO_CAPTURE;
- return 0;
-}
-
-/*====================================================================*/
-static void init_copy(struct video_data *video, bool index)
-{
- struct front_face *front = video->front;
-
- video->field_count = index;
- video->lines_copied = 0;
- video->prev_left = 0 ;
- video->dst = (char *)videobuf_to_vmalloc(front->curr_frame)
- + index * video->lines_size;
- video->vbi->copied = 0; /* set it here */
-}
-
-static bool get_frame(struct front_face *front, int *need_init)
-{
- struct videobuf_buffer *vb = front->curr_frame;
-
- if (vb)
- return true;
-
- spin_lock(&front->queue_lock);
- if (!list_empty(&front->active)) {
- vb = list_entry(front->active.next,
- struct videobuf_buffer, queue);
- if (need_init)
- *need_init = 1;
- front->curr_frame = vb;
- list_del_init(&vb->queue);
- }
- spin_unlock(&front->queue_lock);
-
- return !!vb;
-}
-
-/* check if the video's buffer is ready */
-static bool get_video_frame(struct front_face *front, struct video_data *video)
-{
- int need_init = 0;
- bool ret = true;
-
- ret = get_frame(front, &need_init);
- if (ret && need_init)
- init_copy(video, 0);
- return ret;
-}
-
-static void submit_frame(struct front_face *front)
-{
- struct videobuf_buffer *vb = front->curr_frame;
-
- if (vb == NULL)
- return;
-
- front->curr_frame = NULL;
- vb->state = VIDEOBUF_DONE;
- vb->field_count++;
- v4l2_get_timestamp(&vb->ts);
-
- wake_up(&vb->done);
-}
-
-/*
- * A frame is composed of two fields. If we receive all the two fields,
- * call the submit_frame() to submit the whole frame to applications.
- */
-static void end_field(struct video_data *video)
-{
- if (1 == video->field_count)
- submit_frame(video->front);
- else
- init_copy(video, 1);
-}
-
-static void copy_video_data(struct video_data *video, char *src,
- unsigned int count)
-{
-#define copy_data(len) \
- do { \
- if (++video->lines_copied > video->lines_per_field) \
- goto overflow; \
- memcpy(video->dst, src, len);\
- video->dst += len + video->lines_size; \
- src += len; \
- count -= len; \
- } while (0)
-
- while (count && count >= video->lines_size) {
- if (video->prev_left) {
- copy_data(video->prev_left);
- video->prev_left = 0;
- continue;
- }
- copy_data(video->lines_size);
- }
- if (count && count < video->lines_size) {
- memcpy(video->dst, src, count);
-
- video->prev_left = video->lines_size - count;
- video->dst += count;
- }
- return;
-
-overflow:
- end_field(video);
-}
-
-static void check_trailer(struct video_data *video, char *src, int count)
-{
- struct vbi_data *vbi = video->vbi;
- int offset; /* trailer's offset */
- char *buf;
-
- offset = (video->context.pix.sizeimage / 2 + vbi->vbi_size / 2)
- - (vbi->copied + video->lines_size * video->lines_copied);
- if (video->prev_left)
- offset -= (video->lines_size - video->prev_left);
-
- if (offset > count || offset <= 0)
- goto short_package;
-
- buf = src + offset;
-
- /* trailer : (VFHS) + U32 + U32 + field_num */
- if (!strncmp(buf, "VFHS", 4)) {
- int field_num = *((u32 *)(buf + 12));
-
- if ((field_num & 1) ^ video->field_count) {
- init_copy(video, video->field_count);
- return;
- }
- copy_video_data(video, src, offset);
- }
-short_package:
- end_field(video);
-}
-
-/* ========== Check this more carefully! =========== */
-static inline void copy_vbi_data(struct vbi_data *vbi,
- char *src, unsigned int count)
-{
- struct front_face *front = vbi->front;
-
- if (front && get_frame(front, NULL)) {
- char *buf = videobuf_to_vmalloc(front->curr_frame);
-
- if (vbi->video->field_count)
- buf += (vbi->vbi_size / 2);
- memcpy(buf + vbi->copied, src, count);
- }
- vbi->copied += count;
-}
-
-/*
- * Copy the normal data (VBI or VIDEO) without the trailer.
- * VBI is not interlaced, while VIDEO is interlaced.
- */
-static inline void copy_vbi_video_data(struct video_data *video,
- char *src, unsigned int count)
-{
- struct vbi_data *vbi = video->vbi;
- unsigned int vbi_delta = (vbi->vbi_size / 2) - vbi->copied;
-
- if (vbi_delta >= count) {
- copy_vbi_data(vbi, src, count);
- } else {
- if (vbi_delta) {
- copy_vbi_data(vbi, src, vbi_delta);
-
- /* we receive the two fields of the VBI*/
- if (vbi->front && video->field_count)
- submit_frame(vbi->front);
- }
- copy_video_data(video, src + vbi_delta, count - vbi_delta);
- }
-}
-
-static void urb_complete_bulk(struct urb *urb)
-{
- struct front_face *front = urb->context;
- struct video_data *video = &front->pd->video_data;
- char *src = (char *)urb->transfer_buffer;
- int count = urb->actual_length;
- int ret = 0;
-
- if (!video->is_streaming || urb->status) {
- if (urb->status == -EPROTO)
- goto resend_it;
- return;
- }
- if (!get_video_frame(front, video))
- goto resend_it;
-
- if (count == urb->transfer_buffer_length)
- copy_vbi_video_data(video, src, count);
- else
- check_trailer(video, src, count);
-
-resend_it:
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- log(" submit failed: error %d", ret);
-}
-
-/************************* for ISO *********************/
-#define GET_SUCCESS (0)
-#define GET_TRAILER (1)
-#define GET_TOO_MUCH_BUBBLE (2)
-#define GET_NONE (3)
-static int get_chunk(int start, struct urb *urb,
- int *head, int *tail, int *bubble_err)
-{
- struct usb_iso_packet_descriptor *pkt = NULL;
- int ret = GET_SUCCESS;
-
- for (*head = *tail = -1; start < urb->number_of_packets; start++) {
- pkt = &urb->iso_frame_desc[start];
-
- /* handle the bubble of the Hub */
- if (-EOVERFLOW == pkt->status) {
- if (++*bubble_err > urb->number_of_packets / 3)
- return GET_TOO_MUCH_BUBBLE;
- continue;
- }
-
- /* This is the gap */
- if (pkt->status || pkt->actual_length <= 0
- || pkt->actual_length > ISO_PKT_SIZE) {
- if (*head != -1)
- break;
- continue;
- }
-
- /* a good isochronous packet */
- if (pkt->actual_length == ISO_PKT_SIZE) {
- if (*head == -1)
- *head = start;
- *tail = start;
- continue;
- }
-
- /* trailer is here */
- if (pkt->actual_length < ISO_PKT_SIZE) {
- if (*head == -1) {
- *head = start;
- *tail = start;
- return GET_TRAILER;
- }
- break;
- }
- }
-
- if (*head == -1 && *tail == -1)
- ret = GET_NONE;
- return ret;
-}
-
-/*
- * |__|------|___|-----|_______|
- * ^ ^
- * | |
- * gap gap
- */
-static void urb_complete_iso(struct urb *urb)
-{
- struct front_face *front = urb->context;
- struct video_data *video = &front->pd->video_data;
- int bubble_err = 0, head = 0, tail = 0;
- char *src = (char *)urb->transfer_buffer;
- int ret = 0;
-
- if (!video->is_streaming)
- return;
-
- do {
- if (!get_video_frame(front, video))
- goto out;
-
- switch (get_chunk(head, urb, &head, &tail, &bubble_err)) {
- case GET_SUCCESS:
- copy_vbi_video_data(video, src + (head * ISO_PKT_SIZE),
- (tail - head + 1) * ISO_PKT_SIZE);
- break;
- case GET_TRAILER:
- check_trailer(video, src + (head * ISO_PKT_SIZE),
- ISO_PKT_SIZE);
- break;
- case GET_NONE:
- goto out;
- case GET_TOO_MUCH_BUBBLE:
- log("\t We got too much bubble");
- schedule_work(&video->bubble_work);
- return;
- }
- } while (head = tail + 1, head < urb->number_of_packets);
-
-out:
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- log("usb_submit_urb err : %d", ret);
-}
-/*============================= [ end ] =====================*/
-
-static int prepare_iso_urb(struct video_data *video)
-{
- struct usb_device *udev = video->pd->udev;
- int i;
-
- if (video->urb_array[0])
- return 0;
-
- for (i = 0; i < SBUF_NUM; i++) {
- struct urb *urb;
- void *mem;
- int j;
-
- urb = usb_alloc_urb(PK_PER_URB, GFP_KERNEL);
- if (urb == NULL)
- goto out;
-
- video->urb_array[i] = urb;
- mem = usb_alloc_coherent(udev,
- ISO_PKT_SIZE * PK_PER_URB,
- GFP_KERNEL,
- &urb->transfer_dma);
-
- urb->complete = urb_complete_iso; /* handler */
- urb->dev = udev;
- urb->context = video->front;
- urb->pipe = usb_rcvisocpipe(udev,
- video->endpoint_addr);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->number_of_packets = PK_PER_URB;
- urb->transfer_buffer = mem;
- urb->transfer_buffer_length = PK_PER_URB * ISO_PKT_SIZE;
-
- for (j = 0; j < PK_PER_URB; j++) {
- urb->iso_frame_desc[j].offset = ISO_PKT_SIZE * j;
- urb->iso_frame_desc[j].length = ISO_PKT_SIZE;
- }
- }
- return 0;
-out:
- for (; i > 0; i--)
- ;
- return -ENOMEM;
-}
-
-/* return the succeeded number of the allocation */
-int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
- struct usb_device *udev, u8 ep_addr,
- int buf_size, gfp_t gfp_flags,
- usb_complete_t complete_fn, void *context)
-{
- int i = 0;
-
- for (; i < num; i++) {
- void *mem;
- struct urb *urb = usb_alloc_urb(0, gfp_flags);
- if (urb == NULL)
- return i;
-
- mem = usb_alloc_coherent(udev, buf_size, gfp_flags,
- &urb->transfer_dma);
- if (mem == NULL) {
- usb_free_urb(urb);
- return i;
- }
-
- usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr),
- mem, buf_size, complete_fn, context);
- urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
- urb_array[i] = urb;
- }
- return i;
-}
-
-void free_all_urb_generic(struct urb **urb_array, int num)
-{
- int i;
- struct urb *urb;
-
- for (i = 0; i < num; i++) {
- urb = urb_array[i];
- if (urb) {
- usb_free_coherent(urb->dev,
- urb->transfer_buffer_length,
- urb->transfer_buffer,
- urb->transfer_dma);
- usb_free_urb(urb);
- urb_array[i] = NULL;
- }
- }
-}
-
-static int prepare_bulk_urb(struct video_data *video)
-{
- if (video->urb_array[0])
- return 0;
-
- alloc_bulk_urbs_generic(video->urb_array, SBUF_NUM,
- video->pd->udev, video->endpoint_addr,
- 0x2000, GFP_KERNEL,
- urb_complete_bulk, video->front);
- return 0;
-}
-
-/* free the URBs */
-static void free_all_urb(struct video_data *video)
-{
- free_all_urb_generic(video->urb_array, SBUF_NUM);
-}
-
-static void pd_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
- videobuf_vmalloc_free(vb);
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-static void pd_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
-{
- struct front_face *front = q->priv_data;
- vb->state = VIDEOBUF_QUEUED;
- list_add_tail(&vb->queue, &front->active);
-}
-
-static int pd_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct front_face *front = q->priv_data;
- int rc;
-
- switch (front->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- struct v4l2_pix_format *pix;
-
- pix = &front->pd->video_data.context.pix;
- vb->size = pix->sizeimage; /* real frame size */
- vb->width = pix->width;
- vb->height = pix->height;
- rc = videobuf_iolock(q, vb, NULL);
- if (rc < 0)
- return rc;
- }
- break;
- case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (VIDEOBUF_NEEDS_INIT == vb->state) {
- vb->size = front->pd->vbi_data.vbi_size;
- rc = videobuf_iolock(q, vb, NULL);
- if (rc < 0)
- return rc;
- }
- break;
- default:
- return -EINVAL;
- }
- vb->field = field;
- vb->state = VIDEOBUF_PREPARED;
- return 0;
-}
-
-static int fire_all_urb(struct video_data *video)
-{
- int i, ret;
-
- video->is_streaming = 1;
-
- for (i = 0; i < SBUF_NUM; i++) {
- ret = usb_submit_urb(video->urb_array[i], GFP_KERNEL);
- if (ret)
- log("(%d) failed: error %d", i, ret);
- }
- return ret;
-}
-
-static int start_video_stream(struct poseidon *pd)
-{
- struct video_data *video = &pd->video_data;
- s32 cmd_status;
-
- send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
- send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_START, &cmd_status);
-
- if (pd->cur_transfer_mode) {
- prepare_iso_urb(video);
- INIT_WORK(&video->bubble_work, iso_bubble_handler);
- } else {
- /* The bulk mode does not need a bubble handler */
- prepare_bulk_urb(video);
- }
- fire_all_urb(video);
- return 0;
-}
-
-static int pd_buf_setup(struct videobuf_queue *q, unsigned int *count,
- unsigned int *size)
-{
- struct front_face *front = q->priv_data;
- struct poseidon *pd = front->pd;
-
- switch (front->type) {
- default:
- return -EINVAL;
- case V4L2_BUF_TYPE_VIDEO_CAPTURE: {
- struct video_data *video = &pd->video_data;
- struct v4l2_pix_format *pix = &video->context.pix;
-
- *size = PAGE_ALIGN(pix->sizeimage);/* page aligned frame size */
- if (*count < 4)
- *count = 4;
- if (1) {
- /* same in different altersetting */
- video->endpoint_addr = 0x82;
- video->vbi = &pd->vbi_data;
- video->vbi->video = video;
- video->pd = pd;
- video->lines_per_field = pix->height / 2;
- video->lines_size = pix->width * 2;
- video->front = front;
- }
- return start_video_stream(pd);
- }
-
- case V4L2_BUF_TYPE_VBI_CAPTURE: {
- struct vbi_data *vbi = &pd->vbi_data;
-
- *size = PAGE_ALIGN(vbi->vbi_size);
- log("size : %d", *size);
- if (*count == 0)
- *count = 4;
- }
- break;
- }
- return 0;
-}
-
-static struct videobuf_queue_ops pd_video_qops = {
- .buf_setup = pd_buf_setup,
- .buf_prepare = pd_buf_prepare,
- .buf_queue = pd_buf_queue,
- .buf_release = pd_buf_release,
-};
-
-static int vidioc_enum_fmt(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
-{
- if (ARRAY_SIZE(poseidon_formats) <= f->index)
- return -EINVAL;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->flags = 0;
- f->pixelformat = poseidon_formats[f->index].fourcc;
- strcpy(f->description, poseidon_formats[f->index].name);
- return 0;
-}
-
-static int vidioc_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
-
- f->fmt.pix = pd->video_data.context.pix;
- return 0;
-}
-
-/*
- * VLC calls VIDIOC_S_STD before VIDIOC_S_FMT, while
- * Mplayer calls them in the reverse order.
- */
-static int pd_vidioc_s_fmt(struct poseidon *pd, struct v4l2_pix_format *pix)
-{
- struct video_data *video = &pd->video_data;
- struct running_context *context = &video->context;
- struct v4l2_pix_format *pix_def = &context->pix;
- s32 ret = 0, cmd_status = 0, vid_resol;
-
- /* set the pixel format to firmware */
- if (pix->pixelformat == V4L2_PIX_FMT_RGB565) {
- vid_resol = TLG_TUNER_VID_FORMAT_RGB_565;
- } else {
- pix->pixelformat = V4L2_PIX_FMT_YUYV;
- vid_resol = TLG_TUNER_VID_FORMAT_YUV;
- }
- ret = send_set_req(pd, VIDEO_STREAM_FMT_SEL,
- vid_resol, &cmd_status);
-
- /* set the resolution to firmware */
- vid_resol = TLG_TUNE_VID_RES_720;
- switch (pix->width) {
- case 704:
- vid_resol = TLG_TUNE_VID_RES_704;
- break;
- default:
- pix->width = 720;
- case 720:
- break;
- }
- ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
- vid_resol, &cmd_status);
- if (ret || cmd_status)
- return -EBUSY;
-
- pix_def->pixelformat = pix->pixelformat; /* save it */
- pix->height = (context->tvnormid & V4L2_STD_525_60) ? 480 : 576;
-
- /* Compare with the default setting */
- if ((pix_def->width != pix->width)
- || (pix_def->height != pix->height)) {
- pix_def->width = pix->width;
- pix_def->height = pix->height;
- pix_def->bytesperline = pix->width * 2;
- pix_def->sizeimage = pix->width * pix->height * 2;
- }
- *pix = *pix_def;
-
- return 0;
-}
-
-static int vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
-
- /* stop VBI here */
- if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
- return -EINVAL;
-
- mutex_lock(&pd->lock);
- if (pd->file_for_stream == NULL)
- pd->file_for_stream = file;
- else if (file != pd->file_for_stream) {
- mutex_unlock(&pd->lock);
- return -EINVAL;
- }
-
- pd_vidioc_s_fmt(pd, &f->fmt.pix);
- mutex_unlock(&pd->lock);
- return 0;
-}
-
-static int vidioc_g_fmt_vbi(struct file *file, void *fh,
- struct v4l2_format *v4l2_f)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- struct v4l2_vbi_format *vbi_fmt = &v4l2_f->fmt.vbi;
-
- vbi_fmt->samples_per_line = 720 * 2;
- vbi_fmt->sampling_rate = 6750000 * 4;
- vbi_fmt->sample_format = V4L2_PIX_FMT_GREY;
- vbi_fmt->offset = 64 * 4; /*FIXME: why offset */
- if (pd->video_data.context.tvnormid & V4L2_STD_525_60) {
- vbi_fmt->start[0] = 10;
- vbi_fmt->start[1] = 264;
- vbi_fmt->count[0] = V4L_NTSC_VBI_LINES;
- vbi_fmt->count[1] = V4L_NTSC_VBI_LINES;
- } else {
- vbi_fmt->start[0] = 6;
- vbi_fmt->start[1] = 314;
- vbi_fmt->count[0] = V4L_PAL_VBI_LINES;
- vbi_fmt->count[1] = V4L_PAL_VBI_LINES;
- }
- vbi_fmt->flags = V4L2_VBI_UNSYNC;
- return 0;
-}
-
-static int set_std(struct poseidon *pd, v4l2_std_id norm)
-{
- struct video_data *video = &pd->video_data;
- struct vbi_data *vbi = &pd->vbi_data;
- struct running_context *context;
- struct v4l2_pix_format *pix;
- s32 i, ret = 0, cmd_status, param;
- int height;
-
- for (i = 0; i < POSEIDON_TVNORMS; i++) {
- if (norm & poseidon_tvnorms[i].v4l2_id) {
- param = poseidon_tvnorms[i].tlg_tvnorm;
- log("name : %s", poseidon_tvnorms[i].name);
- goto found;
- }
- }
- return -EINVAL;
-found:
- mutex_lock(&pd->lock);
- ret = send_set_req(pd, VIDEO_STD_SEL, param, &cmd_status);
- if (ret || cmd_status)
- goto out;
-
- /* Set vbi size and check the height of the frame */
- context = &video->context;
- context->tvnormid = poseidon_tvnorms[i].v4l2_id;
- if (context->tvnormid & V4L2_STD_525_60) {
- vbi->vbi_size = V4L_NTSC_VBI_FRAMESIZE;
- height = 480;
- } else {
- vbi->vbi_size = V4L_PAL_VBI_FRAMESIZE;
- height = 576;
- }
-
- pix = &context->pix;
- if (pix->height != height) {
- pix->height = height;
- pix->sizeimage = pix->width * pix->height * 2;
- }
-
-out:
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id norm)
-{
- struct front_face *front = fh;
-
- return set_std(front->pd, norm);
-}
-
-static int vidioc_g_std(struct file *file, void *fh, v4l2_std_id *norm)
-{
- struct front_face *front = fh;
-
- *norm = front->pd->video_data.context.tvnormid;
- return 0;
-}
-
-static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *in)
-{
- if (in->index >= POSEIDON_INPUTS)
- return -EINVAL;
- strcpy(in->name, pd_inputs[in->index].name);
- in->type = V4L2_INPUT_TYPE_TUNER;
-
- /*
- * the audio input index mixed with this video input,
- * Poseidon only have one audio/video, set to "0"
- */
- in->audioset = 1;
- in->tuner = 0;
- in->std = V4L2_STD_ALL;
- in->status = 0;
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- struct running_context *context = &pd->video_data.context;
-
- *i = context->sig_index;
- return 0;
-}
-
-/* We can support several inputs */
-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- s32 ret, cmd_status;
-
- if (i >= POSEIDON_INPUTS)
- return -EINVAL;
- ret = send_set_req(pd, SGNL_SRC_SEL,
- pd_inputs[i].tlg_src, &cmd_status);
- if (ret)
- return ret;
-
- pd->video_data.context.sig_index = i;
- return 0;
-}
-
-static int tlg_s_ctrl(struct v4l2_ctrl *c)
-{
- struct poseidon *pd = container_of(c->handler, struct poseidon,
- video_data.ctrl_handler);
- struct tuner_custom_parameter_s param = {0};
- s32 ret = 0, cmd_status, params;
-
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- param.param_id = CUST_PARM_ID_BRIGHTNESS_CTRL;
- break;
- case V4L2_CID_CONTRAST:
- param.param_id = CUST_PARM_ID_CONTRAST_CTRL;
- break;
- case V4L2_CID_HUE:
- param.param_id = CUST_PARM_ID_HUE_CTRL;
- break;
- case V4L2_CID_SATURATION:
- param.param_id = CUST_PARM_ID_SATURATION_CTRL;
- break;
- }
- param.param_value = c->val;
- params = *(s32 *)&param; /* temp code */
-
- mutex_lock(&pd->lock);
- ret = send_set_req(pd, TUNER_CUSTOM_PARAMETER, params, &cmd_status);
- ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
- mutex_unlock(&pd->lock);
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/4);
- return ret;
-}
-
-/* Audio ioctls */
-static int vidioc_enumaudio(struct file *file, void *fh, struct v4l2_audio *a)
-{
- if (0 != a->index)
- return -EINVAL;
- a->capability = V4L2_AUDCAP_STEREO;
- strcpy(a->name, "USB audio in");
- /*Poseidon have no AVL function.*/
- a->mode = 0;
- return 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *fh, struct v4l2_audio *a)
-{
- a->index = 0;
- a->capability = V4L2_AUDCAP_STEREO;
- strcpy(a->name, "USB audio in");
- a->mode = 0;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *a)
-{
- return (0 == a->index) ? 0 : -EINVAL;
-}
-
-/* Tuner ioctls */
-static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *tuner)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- struct tuner_atv_sig_stat_s atv_stat;
- s32 count = 5, ret, cmd_status;
- int index;
-
- if (0 != tuner->index)
- return -EINVAL;
-
- mutex_lock(&pd->lock);
- ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV,
- &atv_stat, &cmd_status, sizeof(atv_stat));
-
- while (atv_stat.sig_lock_busy && count-- && !ret) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ);
-
- ret = send_get_req(pd, TUNER_STATUS, TLG_MODE_ANALOG_TV,
- &atv_stat, &cmd_status, sizeof(atv_stat));
- }
- mutex_unlock(&pd->lock);
-
- if (debug_mode)
- log("P:%d,S:%d", atv_stat.sig_present, atv_stat.sig_strength);
-
- if (ret || cmd_status)
- tuner->signal = 0;
- else if (atv_stat.sig_present && !atv_stat.sig_strength)
- tuner->signal = 0xFFFF;
- else
- tuner->signal = (atv_stat.sig_strength * 255 / 10) << 8;
-
- strcpy(tuner->name, "Telegent Systems");
- tuner->type = V4L2_TUNER_ANALOG_TV;
- tuner->rangelow = TUNER_FREQ_MIN / 62500;
- tuner->rangehigh = TUNER_FREQ_MAX / 62500;
- tuner->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_LANG1 | V4L2_TUNER_CAP_LANG2;
- index = pd->video_data.context.audio_idx;
- tuner->rxsubchans = pd_audio_modes[index].v4l2_audio_sub;
- tuner->audmode = pd_audio_modes[index].v4l2_audio_mode;
- tuner->afc = 0;
- return 0;
-}
-
-static int pd_vidioc_s_tuner(struct poseidon *pd, int index)
-{
- s32 ret = 0, cmd_status, param, audiomode;
-
- mutex_lock(&pd->lock);
- param = pd_audio_modes[index].tlg_audio_mode;
- ret = send_set_req(pd, TUNER_AUD_MODE, param, &cmd_status);
- audiomode = get_audio_std(pd->video_data.context.tvnormid);
- ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode,
- &cmd_status);
- if (!ret)
- pd->video_data.context.audio_idx = index;
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *a)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- int index;
-
- if (0 != a->index)
- return -EINVAL;
- for (index = 0; index < POSEIDON_AUDIOMODS; index++)
- if (a->audmode == pd_audio_modes[index].v4l2_audio_mode)
- return pd_vidioc_s_tuner(pd, index);
- return -EINVAL;
-}
-
-static int vidioc_g_frequency(struct file *file, void *fh,
- struct v4l2_frequency *freq)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- struct running_context *context = &pd->video_data.context;
-
- if (0 != freq->tuner)
- return -EINVAL;
- freq->frequency = context->freq;
- freq->type = V4L2_TUNER_ANALOG_TV;
- return 0;
-}
-
-static int set_frequency(struct poseidon *pd, u32 *frequency)
-{
- s32 ret = 0, param, cmd_status;
- struct running_context *context = &pd->video_data.context;
-
- *frequency = clamp(*frequency,
- TUNER_FREQ_MIN / 62500, TUNER_FREQ_MAX / 62500);
- param = (*frequency) * 62500 / 1000;
-
- mutex_lock(&pd->lock);
- ret = send_set_req(pd, TUNE_FREQ_SELECT, param, &cmd_status);
- ret = send_set_req(pd, TAKE_REQUEST, 0, &cmd_status);
-
- msleep(250); /* wait for a while until the hardware is ready. */
- context->freq = *frequency;
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static int vidioc_s_frequency(struct file *file, void *fh,
- const struct v4l2_frequency *freq)
-{
- struct front_face *front = fh;
- struct poseidon *pd = front->pd;
- u32 frequency = freq->frequency;
-
- if (freq->tuner)
- return -EINVAL;
-#ifdef CONFIG_PM
- pd->pm_suspend = pm_video_suspend;
- pd->pm_resume = pm_video_resume;
-#endif
- return set_frequency(pd, &frequency);
-}
-
-static int vidioc_reqbufs(struct file *file, void *fh,
- struct v4l2_requestbuffers *b)
-{
- struct front_face *front = file->private_data;
- return videobuf_reqbufs(&front->q, b);
-}
-
-static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct front_face *front = file->private_data;
- return videobuf_querybuf(&front->q, b);
-}
-
-static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct front_face *front = file->private_data;
- return videobuf_qbuf(&front->q, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct front_face *front = file->private_data;
- return videobuf_dqbuf(&front->q, b, file->f_flags & O_NONBLOCK);
-}
-
-/* Just stop the URBs, do not free the URBs */
-static int usb_transfer_stop(struct video_data *video)
-{
- if (video->is_streaming) {
- int i;
- s32 cmd_status;
- struct poseidon *pd = video->pd;
-
- video->is_streaming = 0;
- for (i = 0; i < SBUF_NUM; ++i) {
- if (video->urb_array[i])
- usb_kill_urb(video->urb_array[i]);
- }
-
- send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
- &cmd_status);
- }
- return 0;
-}
-
-int stop_all_video_stream(struct poseidon *pd)
-{
- struct video_data *video = &pd->video_data;
- struct vbi_data *vbi = &pd->vbi_data;
-
- mutex_lock(&pd->lock);
- if (video->is_streaming) {
- struct front_face *front = video->front;
-
- /* stop the URBs */
- usb_transfer_stop(video);
- free_all_urb(video);
-
- /* stop the host side of VIDEO */
- videobuf_stop(&front->q);
- videobuf_mmap_free(&front->q);
-
- /* stop the host side of VBI */
- front = vbi->front;
- if (front) {
- videobuf_stop(&front->q);
- videobuf_mmap_free(&front->q);
- }
- }
- mutex_unlock(&pd->lock);
- return 0;
-}
-
-/*
- * The bubbles can seriously damage the video's quality,
- * though it occurs in very rare situation.
- */
-static void iso_bubble_handler(struct work_struct *w)
-{
- struct video_data *video;
- struct poseidon *pd;
-
- video = container_of(w, struct video_data, bubble_work);
- pd = video->pd;
-
- mutex_lock(&pd->lock);
- usb_transfer_stop(video);
- msleep(500);
- start_video_stream(pd);
- mutex_unlock(&pd->lock);
-}
-
-
-static int vidioc_streamon(struct file *file, void *fh,
- enum v4l2_buf_type type)
-{
- struct front_face *front = fh;
-
- if (unlikely(type != front->type))
- return -EINVAL;
- return videobuf_streamon(&front->q);
-}
-
-static int vidioc_streamoff(struct file *file, void *fh,
- enum v4l2_buf_type type)
-{
- struct front_face *front = file->private_data;
-
- if (unlikely(type != front->type))
- return -EINVAL;
- return videobuf_streamoff(&front->q);
-}
-
-/* Set the firmware's default values : need altersetting */
-static int pd_video_checkmode(struct poseidon *pd)
-{
- s32 ret = 0, cmd_status, audiomode;
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ/2);
-
- /* choose the altersetting */
- ret = usb_set_interface(pd->udev, 0,
- (pd->cur_transfer_mode ?
- ISO_3K_BULK_ALTERNATE_IFACE :
- BULK_ALTERNATE_IFACE));
- if (ret < 0)
- goto error;
-
- /* set default parameters for PAL-D , with the VBI enabled*/
- ret = set_tuner_mode(pd, TLG_MODE_ANALOG_TV);
- ret |= send_set_req(pd, SGNL_SRC_SEL,
- TLG_SIG_SRC_ANTENNA, &cmd_status);
- ret |= send_set_req(pd, VIDEO_STD_SEL,
- TLG_TUNE_VSTD_PAL_D, &cmd_status);
- ret |= send_set_req(pd, VIDEO_STREAM_FMT_SEL,
- TLG_TUNER_VID_FORMAT_YUV, &cmd_status);
- ret |= send_set_req(pd, VIDEO_ROSOLU_SEL,
- TLG_TUNE_VID_RES_720, &cmd_status);
- ret |= send_set_req(pd, TUNE_FREQ_SELECT, TUNER_FREQ_MIN, &cmd_status);
- ret |= send_set_req(pd, VBI_DATA_SEL, 1, &cmd_status);/* enable vbi */
-
- /* set the audio */
- audiomode = get_audio_std(pd->video_data.context.tvnormid);
- ret |= send_set_req(pd, TUNER_AUD_ANA_STD, audiomode, &cmd_status);
- ret |= send_set_req(pd, TUNER_AUD_MODE,
- TLG_TUNE_TVAUDIO_MODE_STEREO, &cmd_status);
- ret |= send_set_req(pd, AUDIO_SAMPLE_RATE_SEL,
- ATV_AUDIO_RATE_48K, &cmd_status);
-error:
- return ret;
-}
-
-#ifdef CONFIG_PM
-static int pm_video_suspend(struct poseidon *pd)
-{
- /* stop audio */
- pm_alsa_suspend(pd);
-
- /* stop and free all the URBs */
- usb_transfer_stop(&pd->video_data);
- free_all_urb(&pd->video_data);
-
- /* reset the interface */
- usb_set_interface(pd->udev, 0, 0);
- msleep(300);
- return 0;
-}
-
-static int restore_v4l2_context(struct poseidon *pd,
- struct running_context *context)
-{
- struct front_face *front = pd->video_data.front;
-
- pd_video_checkmode(pd);
-
- set_std(pd, context->tvnormid);
- vidioc_s_input(NULL, front, context->sig_index);
- pd_vidioc_s_tuner(pd, context->audio_idx);
- pd_vidioc_s_fmt(pd, &context->pix);
- set_frequency(pd, &context->freq);
- return 0;
-}
-
-static int pm_video_resume(struct poseidon *pd)
-{
- struct video_data *video = &pd->video_data;
-
- /* resume the video */
- /* [1] restore the origin V4L2 parameters */
- restore_v4l2_context(pd, &video->context);
-
- /* [2] initiate video copy variables */
- if (video->front->curr_frame)
- init_copy(video, 0);
-
- /* [3] fire urbs */
- start_video_stream(pd);
-
- /* resume the audio */
- pm_alsa_resume(pd);
- return 0;
-}
-#endif
-
-void set_debug_mode(struct video_device *vfd, int debug_mode)
-{
- vfd->debug = 0;
- if (debug_mode & 0x1)
- vfd->debug = V4L2_DEBUG_IOCTL;
- if (debug_mode & 0x2)
- vfd->debug = V4L2_DEBUG_IOCTL | V4L2_DEBUG_IOCTL_ARG;
-}
-
-static void init_video_context(struct running_context *context)
-{
- context->sig_index = 0;
- context->audio_idx = 1; /* stereo */
- context->tvnormid = V4L2_STD_PAL_D;
- context->pix = (struct v4l2_pix_format) {
- .width = 720,
- .height = 576,
- .pixelformat = V4L2_PIX_FMT_YUYV,
- .field = V4L2_FIELD_INTERLACED,
- .bytesperline = 720 * 2,
- .sizeimage = 720 * 576 * 2,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
- };
-}
-
-static int pd_video_open(struct file *file)
-{
- struct video_device *vfd = video_devdata(file);
- struct poseidon *pd = video_get_drvdata(vfd);
- struct front_face *front = NULL;
- int ret = -ENOMEM;
-
- mutex_lock(&pd->lock);
- usb_autopm_get_interface(pd->interface);
-
- if (pd->state && !(pd->state & POSEIDON_STATE_ANALOG)) {
- ret = -EBUSY;
- goto out;
- }
- front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
- if (!front)
- goto out;
- if (vfd->vfl_type == VFL_TYPE_GRABBER) {
- pd->cur_transfer_mode = usb_transfer_mode;/* bulk or iso */
- init_video_context(&pd->video_data.context);
-
- ret = pd_video_checkmode(pd);
- if (ret < 0) {
- kfree(front);
- ret = -1;
- goto out;
- }
-
- front->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- pd->video_data.users++;
- set_debug_mode(vfd, debug_mode);
-
- videobuf_queue_vmalloc_init(&front->q, &pd_video_qops,
- NULL, &front->queue_lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,/* video is interlacd */
- sizeof(struct videobuf_buffer),/*it's enough*/
- front, NULL);
- } else {
- front->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- pd->vbi_data.front = front;
- pd->vbi_data.users++;
-
- videobuf_queue_vmalloc_init(&front->q, &pd_video_qops,
- NULL, &front->queue_lock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_NONE, /* vbi is NONE mode */
- sizeof(struct videobuf_buffer),
- front, NULL);
- }
-
- pd->state |= POSEIDON_STATE_ANALOG;
- front->pd = pd;
- front->curr_frame = NULL;
- INIT_LIST_HEAD(&front->active);
- spin_lock_init(&front->queue_lock);
-
- file->private_data = front;
- kref_get(&pd->kref);
-
- mutex_unlock(&pd->lock);
- return 0;
-out:
- usb_autopm_put_interface(pd->interface);
- mutex_unlock(&pd->lock);
- return ret;
-}
-
-static int pd_video_release(struct file *file)
-{
- struct front_face *front = file->private_data;
- struct poseidon *pd = front->pd;
- s32 cmd_status = 0;
-
- mutex_lock(&pd->lock);
-
- if (front->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- /* stop the device, and free the URBs */
- usb_transfer_stop(&pd->video_data);
- free_all_urb(&pd->video_data);
-
- /* stop the firmware */
- send_set_req(pd, PLAY_SERVICE, TLG_TUNE_PLAY_SVC_STOP,
- &cmd_status);
-
- pd->file_for_stream = NULL;
- pd->video_data.users--;
- } else if (front->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- pd->vbi_data.front = NULL;
- pd->vbi_data.users--;
- }
- if (!pd->vbi_data.users && !pd->video_data.users)
- pd->state &= ~POSEIDON_STATE_ANALOG;
- videobuf_stop(&front->q);
- videobuf_mmap_free(&front->q);
-
- usb_autopm_put_interface(pd->interface);
- mutex_unlock(&pd->lock);
-
- kfree(front);
- file->private_data = NULL;
- kref_put(&pd->kref, poseidon_delete);
- return 0;
-}
-
-static int pd_video_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct front_face *front = file->private_data;
- return videobuf_mmap_mapper(&front->q, vma);
-}
-
-static unsigned int pd_video_poll(struct file *file, poll_table *table)
-{
- struct front_face *front = file->private_data;
- return videobuf_poll_stream(file, &front->q, table);
-}
-
-static ssize_t pd_video_read(struct file *file, char __user *buffer,
- size_t count, loff_t *ppos)
-{
- struct front_face *front = file->private_data;
- return videobuf_read_stream(&front->q, buffer, count, ppos,
- 0, file->f_flags & O_NONBLOCK);
-}
-
-/* This struct works for both VIDEO and VBI */
-static const struct v4l2_file_operations pd_video_fops = {
- .owner = THIS_MODULE,
- .open = pd_video_open,
- .release = pd_video_release,
- .read = pd_video_read,
- .poll = pd_video_poll,
- .mmap = pd_video_mmap,
- .ioctl = video_ioctl2, /* maybe changed in future */
-};
-
-static const struct v4l2_ioctl_ops pd_video_ioctl_ops = {
- .vidioc_querycap = vidioc_querycap,
-
- /* Video format */
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt,
- .vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi, /* VBI */
-
- /* Input */
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_enum_input = vidioc_enum_input,
-
- /* Audio ioctls */
- .vidioc_enumaudio = vidioc_enumaudio,
- .vidioc_g_audio = vidioc_g_audio,
- .vidioc_s_audio = vidioc_s_audio,
-
- /* Tuner ioctls */
- .vidioc_g_tuner = vidioc_g_tuner,
- .vidioc_s_tuner = vidioc_s_tuner,
- .vidioc_g_std = vidioc_g_std,
- .vidioc_s_std = vidioc_s_std,
- .vidioc_g_frequency = vidioc_g_frequency,
- .vidioc_s_frequency = vidioc_s_frequency,
-
- /* Buffer handlers */
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
-
- /* Stream on/off */
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
-};
-
-static struct video_device pd_video_template = {
- .name = "Telegent-Video",
- .fops = &pd_video_fops,
- .minor = -1,
- .release = video_device_release_empty,
- .tvnorms = V4L2_STD_ALL,
- .ioctl_ops = &pd_video_ioctl_ops,
-};
-
-static const struct v4l2_ctrl_ops tlg_ctrl_ops = {
- .s_ctrl = tlg_s_ctrl,
-};
-
-void pd_video_exit(struct poseidon *pd)
-{
- struct video_data *video = &pd->video_data;
- struct vbi_data *vbi = &pd->vbi_data;
-
- video_unregister_device(&video->v_dev);
- video_unregister_device(&vbi->v_dev);
- v4l2_ctrl_handler_free(&video->ctrl_handler);
- log();
-}
-
-int pd_video_init(struct poseidon *pd)
-{
- struct video_data *video = &pd->video_data;
- struct vbi_data *vbi = &pd->vbi_data;
- struct v4l2_ctrl_handler *hdl = &video->ctrl_handler;
- u32 freq = TUNER_FREQ_MIN / 62500;
- int ret = -ENOMEM;
-
- v4l2_ctrl_handler_init(hdl, 4);
- v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_BRIGHTNESS,
- 0, 10000, 1, 100);
- v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_CONTRAST,
- 0, 10000, 1, 100);
- v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_HUE,
- 0, 10000, 1, 100);
- v4l2_ctrl_new_std(hdl, &tlg_ctrl_ops, V4L2_CID_SATURATION,
- 0, 10000, 1, 100);
- if (hdl->error) {
- v4l2_ctrl_handler_free(hdl);
- return hdl->error;
- }
- set_frequency(pd, &freq);
- video->v_dev = pd_video_template;
- video->v_dev.v4l2_dev = &pd->v4l2_dev;
- video->v_dev.ctrl_handler = hdl;
- video_set_drvdata(&video->v_dev, pd);
-
- ret = video_register_device(&video->v_dev, VFL_TYPE_GRABBER, -1);
- if (ret != 0)
- goto out;
-
- /* VBI uses the same template as video */
- vbi->v_dev = pd_video_template;
- vbi->v_dev.v4l2_dev = &pd->v4l2_dev;
- vbi->v_dev.ctrl_handler = hdl;
- video_set_drvdata(&vbi->v_dev, pd);
- ret = video_register_device(&vbi->v_dev, VFL_TYPE_VBI, -1);
- if (ret != 0)
- goto out;
- log("register VIDEO/VBI devices");
- return 0;
-out:
- log("VIDEO/VBI devices register failed, : %d", ret);
- pd_video_exit(pd);
- return ret;
-}
diff --git a/drivers/staging/media/tlg2300/vendorcmds.h b/drivers/staging/media/tlg2300/vendorcmds.h
deleted file mode 100644
index ba6f4ae3b2c2..000000000000
--- a/drivers/staging/media/tlg2300/vendorcmds.h
+++ /dev/null
@@ -1,243 +0,0 @@
-#ifndef VENDOR_CMD_H_
-#define VENDOR_CMD_H_
-
-#define BULK_ALTERNATE_IFACE (2)
-#define ISO_3K_BULK_ALTERNATE_IFACE (1)
-#define REQ_SET_CMD (0X00)
-#define REQ_GET_CMD (0X80)
-
-enum tlg__analog_audio_standard {
- TLG_TUNE_ASTD_NONE = 0x00000000,
- TLG_TUNE_ASTD_A2 = 0x00000001,
- TLG_TUNE_ASTD_NICAM = 0x00000002,
- TLG_TUNE_ASTD_EIAJ = 0x00000004,
- TLG_TUNE_ASTD_BTSC = 0x00000008,
- TLG_TUNE_ASTD_FM_US = 0x00000010,
- TLG_TUNE_ASTD_FM_EUR = 0x00000020,
- TLG_TUNE_ASTD_ALL = 0x0000003f
-};
-
-/*
- * identifiers for Custom Parameter messages.
- * @typedef cmd_custom_param_id_t
- */
-enum cmd_custom_param_id {
- CUST_PARM_ID_NONE = 0x00,
- CUST_PARM_ID_BRIGHTNESS_CTRL = 0x01,
- CUST_PARM_ID_CONTRAST_CTRL = 0x02,
- CUST_PARM_ID_HUE_CTRL = 0x03,
- CUST_PARM_ID_SATURATION_CTRL = 0x04,
- CUST_PARM_ID_AUDIO_SNR_THRESHOLD = 0x10,
- CUST_PARM_ID_AUDIO_AGC_THRESHOLD = 0x11,
- CUST_PARM_ID_MAX
-};
-
-struct tuner_custom_parameter_s {
- uint16_t param_id; /* Parameter identifier */
- uint16_t param_value; /* Parameter value */
-};
-
-struct tuner_ber_rate_s {
- uint32_t ber_rate; /* BER sample rate in seconds */
-};
-
-struct tuner_atv_sig_stat_s {
- uint32_t sig_present;
- uint32_t sig_locked;
- uint32_t sig_lock_busy;
- uint32_t sig_strength; /* milliDb */
- uint32_t tv_audio_chan; /* mono/stereo/sap*/
- uint32_t mvision_stat; /* macrovision status */
-};
-
-struct tuner_dtv_sig_stat_s {
- uint32_t sig_present; /* Boolean*/
- uint32_t sig_locked; /* Boolean */
- uint32_t sig_lock_busy; /* Boolean (Can this time-out?) */
- uint32_t sig_strength; /* milliDb*/
-};
-
-struct tuner_fm_sig_stat_s {
- uint32_t sig_present; /* Boolean*/
- uint32_t sig_locked; /* Boolean */
- uint32_t sig_lock_busy; /* Boolean */
- uint32_t sig_stereo_mono;/* TBD*/
- uint32_t sig_strength; /* milliDb*/
-};
-
-enum _tag_tlg_tune_srv_cmd {
- TLG_TUNE_PLAY_SVC_START = 1,
- TLG_TUNE_PLAY_SVC_STOP
-};
-
-enum _tag_tune_atv_audio_mode_caps {
- TLG_TUNE_TVAUDIO_MODE_MONO = 0x00000001,
- TLG_TUNE_TVAUDIO_MODE_STEREO = 0x00000002,
- TLG_TUNE_TVAUDIO_MODE_LANG_A = 0x00000010,/* Primary language*/
- TLG_TUNE_TVAUDIO_MODE_LANG_B = 0x00000020,/* 2nd avail language*/
- TLG_TUNE_TVAUDIO_MODE_LANG_C = 0x00000040
-};
-
-
-enum _tag_tuner_atv_audio_rates {
- ATV_AUDIO_RATE_NONE = 0x00,/* Audio not supported*/
- ATV_AUDIO_RATE_32K = 0x01,/* Audio rate = 32 KHz*/
- ATV_AUDIO_RATE_48K = 0x02, /* Audio rate = 48 KHz*/
- ATV_AUDIO_RATE_31_25K = 0x04 /* Audio rate = 31.25KHz */
-};
-
-enum _tag_tune_atv_vid_res_caps {
- TLG_TUNE_VID_RES_NONE = 0x00000000,
- TLG_TUNE_VID_RES_720 = 0x00000001,
- TLG_TUNE_VID_RES_704 = 0x00000002,
- TLG_TUNE_VID_RES_360 = 0x00000004
-};
-
-enum _tag_tuner_analog_video_format {
- TLG_TUNER_VID_FORMAT_YUV = 0x00000001,
- TLG_TUNER_VID_FORMAT_YCRCB = 0x00000002,
- TLG_TUNER_VID_FORMAT_RGB_565 = 0x00000004,
-};
-
-enum tlg_ext_audio_support {
- TLG_EXT_AUDIO_NONE = 0x00,/* No external audio input supported */
- TLG_EXT_AUDIO_LR = 0x01/* LR external audio inputs supported*/
-};
-
-enum {
- TLG_MODE_NONE = 0x00, /* No Mode specified*/
- TLG_MODE_ANALOG_TV = 0x01, /* Analog Television mode*/
- TLG_MODE_ANALOG_TV_UNCOMP = 0x01, /* Analog Television mode*/
- TLG_MODE_ANALOG_TV_COMP = 0x02, /* Analog TV mode (compressed)*/
- TLG_MODE_FM_RADIO = 0x04, /* FM Radio mode*/
- TLG_MODE_DVB_T = 0x08, /* Digital TV (DVB-T)*/
-};
-
-enum tlg_signal_sources_t {
- TLG_SIG_SRC_NONE = 0x00,/* Signal source not specified */
- TLG_SIG_SRC_ANTENNA = 0x01,/* Signal src is: Antenna */
- TLG_SIG_SRC_CABLE = 0x02,/* Signal src is: Coax Cable*/
- TLG_SIG_SRC_SVIDEO = 0x04,/* Signal src is: S_VIDEO */
- TLG_SIG_SRC_COMPOSITE = 0x08 /* Signal src is: Composite Video */
-};
-
-enum tuner_analog_video_standard {
- TLG_TUNE_VSTD_NONE = 0x00000000,
- TLG_TUNE_VSTD_NTSC_M = 0x00000001,
- TLG_TUNE_VSTD_NTSC_M_J = 0x00000002,/* Japan */
- TLG_TUNE_VSTD_PAL_B = 0x00000010,
- TLG_TUNE_VSTD_PAL_D = 0x00000020,
- TLG_TUNE_VSTD_PAL_G = 0x00000040,
- TLG_TUNE_VSTD_PAL_H = 0x00000080,
- TLG_TUNE_VSTD_PAL_I = 0x00000100,
- TLG_TUNE_VSTD_PAL_M = 0x00000200,
- TLG_TUNE_VSTD_PAL_N = 0x00000400,
- TLG_TUNE_VSTD_SECAM_B = 0x00001000,
- TLG_TUNE_VSTD_SECAM_D = 0x00002000,
- TLG_TUNE_VSTD_SECAM_G = 0x00004000,
- TLG_TUNE_VSTD_SECAM_H = 0x00008000,
- TLG_TUNE_VSTD_SECAM_K = 0x00010000,
- TLG_TUNE_VSTD_SECAM_K1 = 0x00020000,
- TLG_TUNE_VSTD_SECAM_L = 0x00040000,
- TLG_TUNE_VSTD_SECAM_L1 = 0x00080000,
- TLG_TUNE_VSTD_PAL_N_COMBO = 0x00100000
-};
-
-enum tlg_mode_caps {
- TLG_MODE_CAPS_NONE = 0x00, /* No Mode specified */
- TLG_MODE_CAPS_ANALOG_TV_UNCOMP = 0x01, /* Analog TV mode */
- TLG_MODE_CAPS_ANALOG_TV_COMP = 0x02, /* Analog TV (compressed)*/
- TLG_MODE_CAPS_FM_RADIO = 0x04, /* FM Radio mode */
- TLG_MODE_CAPS_DVB_T = 0x08, /* Digital TV (DVB-T) */
-};
-
-enum poseidon_vendor_cmds {
- LAST_CMD_STAT = 0x00,
- GET_CHIP_ID = 0x01,
- GET_FW_ID = 0x02,
- PRODUCT_CAPS = 0x03,
-
- TUNE_MODE_CAP_ATV = 0x10,
- TUNE_MODE_CAP_ATVCOMP = 0X10,
- TUNE_MODE_CAP_DVBT = 0x10,
- TUNE_MODE_CAP_FM = 0x10,
- TUNE_MODE_SELECT = 0x11,
- TUNE_FREQ_SELECT = 0x12,
- SGNL_SRC_SEL = 0x13,
-
- VIDEO_STD_SEL = 0x14,
- VIDEO_STREAM_FMT_SEL = 0x15,
- VIDEO_ROSOLU_AVAIL = 0x16,
- VIDEO_ROSOLU_SEL = 0x17,
- VIDEO_CONT_PROTECT = 0x20,
-
- VCR_TIMING_MODSEL = 0x21,
- EXT_AUDIO_CAP = 0x22,
- EXT_AUDIO_SEL = 0x23,
- TEST_PATTERN_SEL = 0x24,
- VBI_DATA_SEL = 0x25,
- AUDIO_SAMPLE_RATE_CAP = 0x28,
- AUDIO_SAMPLE_RATE_SEL = 0x29,
- TUNER_AUD_MODE = 0x2a,
- TUNER_AUD_MODE_AVAIL = 0x2b,
- TUNER_AUD_ANA_STD = 0x2c,
- TUNER_CUSTOM_PARAMETER = 0x2f,
-
- DVBT_TUNE_MODE_SEL = 0x30,
- DVBT_BANDW_CAP = 0x31,
- DVBT_BANDW_SEL = 0x32,
- DVBT_GUARD_INTERV_CAP = 0x33,
- DVBT_GUARD_INTERV_SEL = 0x34,
- DVBT_MODULATION_CAP = 0x35,
- DVBT_MODULATION_SEL = 0x36,
- DVBT_INNER_FEC_RATE_CAP = 0x37,
- DVBT_INNER_FEC_RATE_SEL = 0x38,
- DVBT_TRANS_MODE_CAP = 0x39,
- DVBT_TRANS_MODE_SEL = 0x3a,
- DVBT_SEARCH_RANG = 0x3c,
-
- TUNER_SETUP_ANALOG = 0x40,
- TUNER_SETUP_DIGITAL = 0x41,
- TUNER_SETUP_FM_RADIO = 0x42,
- TAKE_REQUEST = 0x43, /* Take effect of the command */
- PLAY_SERVICE = 0x44, /* Play start or Play stop */
- TUNER_STATUS = 0x45,
- TUNE_PROP_DVBT = 0x46,
- ERR_RATE_STATS = 0x47,
- TUNER_BER_RATE = 0x48,
-
- SCAN_CAPS = 0x50,
- SCAN_SETUP = 0x51,
- SCAN_SERVICE = 0x52,
- SCAN_STATS = 0x53,
-
- PID_SET = 0x58,
- PID_UNSET = 0x59,
- PID_LIST = 0x5a,
-
- IRD_CAP = 0x60,
- IRD_MODE_SEL = 0x61,
- IRD_SETUP = 0x62,
-
- PTM_MODE_CAP = 0x70,
- PTM_MODE_SEL = 0x71,
- PTM_SERVICE = 0x72,
- TUNER_REG_SCRIPT = 0x73,
- CMD_CHIP_RST = 0x74,
-};
-
-enum tlg_bw {
- TLG_BW_5 = 5,
- TLG_BW_6 = 6,
- TLG_BW_7 = 7,
- TLG_BW_8 = 8,
- TLG_BW_12 = 12,
- TLG_BW_15 = 15
-};
-
-struct cmd_firmware_vers_s {
- uint8_t fw_rev_major;
- uint8_t fw_rev_minor;
- uint16_t fw_patch;
-};
-#endif /* VENDOR_CMD_H_ */
diff --git a/drivers/staging/media/vino/Kconfig b/drivers/staging/media/vino/Kconfig
deleted file mode 100644
index 03700dadafd8..000000000000
--- a/drivers/staging/media/vino/Kconfig
+++ /dev/null
@@ -1,24 +0,0 @@
-config VIDEO_VINO
- tristate "SGI Vino Video For Linux (Deprecated)"
- depends on I2C && SGI_IP22 && VIDEO_V4L2
- select VIDEO_SAA7191 if MEDIA_SUBDRV_AUTOSELECT
- help
- Say Y here to build in support for the Vino video input system found
- on SGI Indy machines.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-
-config VIDEO_SAA7191
- tristate "Philips SAA7191 video decoder (Deprecated)"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for the Philips SAA7191 video decoder.
-
- This driver is deprecated and will be removed soon. If you have
- hardware for this and you want to work on this driver, then contact
- the linux-media mailinglist.
-
- To compile this driver as a module, choose M here: the
- module will be called saa7191.
diff --git a/drivers/staging/media/vino/Makefile b/drivers/staging/media/vino/Makefile
deleted file mode 100644
index 914c2513687c..000000000000
--- a/drivers/staging/media/vino/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-obj-$(CONFIG_VIDEO_VINO) += indycam.o
-obj-$(CONFIG_VIDEO_VINO) += vino.o
-obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
diff --git a/drivers/staging/media/vino/indycam.c b/drivers/staging/media/vino/indycam.c
deleted file mode 100644
index f1d192bbcb4c..000000000000
--- a/drivers/staging/media/vino/indycam.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * indycam.c - Silicon Graphics IndyCam digital camera driver
- *
- * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-/* IndyCam decodes stream of photons into digital image representation ;-) */
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <media/v4l2-device.h>
-
-#include "indycam.h"
-
-#define INDYCAM_MODULE_VERSION "0.0.5"
-
-MODULE_DESCRIPTION("SGI IndyCam driver");
-MODULE_VERSION(INDYCAM_MODULE_VERSION);
-MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
-MODULE_LICENSE("GPL");
-
-
-// #define INDYCAM_DEBUG
-
-#ifdef INDYCAM_DEBUG
-#define dprintk(x...) printk("IndyCam: " x);
-#define indycam_regdump(client) indycam_regdump_debug(client)
-#else
-#define dprintk(x...)
-#define indycam_regdump(client)
-#endif
-
-struct indycam {
- struct v4l2_subdev sd;
- u8 version;
-};
-
-static inline struct indycam *to_indycam(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct indycam, sd);
-}
-
-static const u8 initseq[] = {
- INDYCAM_CONTROL_AGCENA, /* INDYCAM_CONTROL */
- INDYCAM_SHUTTER_60, /* INDYCAM_SHUTTER */
- INDYCAM_GAIN_DEFAULT, /* INDYCAM_GAIN */
- 0x00, /* INDYCAM_BRIGHTNESS (read-only) */
- INDYCAM_RED_BALANCE_DEFAULT, /* INDYCAM_RED_BALANCE */
- INDYCAM_BLUE_BALANCE_DEFAULT, /* INDYCAM_BLUE_BALANCE */
- INDYCAM_RED_SATURATION_DEFAULT, /* INDYCAM_RED_SATURATION */
- INDYCAM_BLUE_SATURATION_DEFAULT,/* INDYCAM_BLUE_SATURATION */
-};
-
-/* IndyCam register handling */
-
-static int indycam_read_reg(struct v4l2_subdev *sd, u8 reg, u8 *value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- if (reg == INDYCAM_REG_RESET) {
- dprintk("indycam_read_reg(): "
- "skipping write-only register %d\n", reg);
- *value = 0;
- return 0;
- }
-
- ret = i2c_smbus_read_byte_data(client, reg);
-
- if (ret < 0) {
- printk(KERN_ERR "IndyCam: indycam_read_reg(): read failed, "
- "register = 0x%02x\n", reg);
- return ret;
- }
-
- *value = (u8)ret;
-
- return 0;
-}
-
-static int indycam_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int err;
-
- if (reg == INDYCAM_REG_BRIGHTNESS || reg == INDYCAM_REG_VERSION) {
- dprintk("indycam_write_reg(): "
- "skipping read-only register %d\n", reg);
- return 0;
- }
-
- dprintk("Writing Reg %d = 0x%02x\n", reg, value);
- err = i2c_smbus_write_byte_data(client, reg, value);
-
- if (err) {
- printk(KERN_ERR "IndyCam: indycam_write_reg(): write failed, "
- "register = 0x%02x, value = 0x%02x\n", reg, value);
- }
- return err;
-}
-
-static int indycam_write_block(struct v4l2_subdev *sd, u8 reg,
- u8 length, u8 *data)
-{
- int i, err;
-
- for (i = 0; i < length; i++) {
- err = indycam_write_reg(sd, reg + i, data[i]);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-/* Helper functions */
-
-#ifdef INDYCAM_DEBUG
-static void indycam_regdump_debug(struct v4l2_subdev *sd)
-{
- int i;
- u8 val;
-
- for (i = 0; i < 9; i++) {
- indycam_read_reg(sd, i, &val);
- dprintk("Reg %d = 0x%02x\n", i, val);
- }
-}
-#endif
-
-static int indycam_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct indycam *camera = to_indycam(sd);
- u8 reg;
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTOGAIN:
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
- if (ret)
- return -EIO;
- if (ctrl->id == V4L2_CID_AUTOGAIN)
- ctrl->value = (reg & INDYCAM_CONTROL_AGCENA)
- ? 1 : 0;
- else
- ctrl->value = (reg & INDYCAM_CONTROL_AWBCTL)
- ? 1 : 0;
- break;
- case V4L2_CID_EXPOSURE:
- ret = indycam_read_reg(sd, INDYCAM_REG_SHUTTER, &reg);
- if (ret)
- return -EIO;
- ctrl->value = ((s32)reg == 0x00) ? 0xff : ((s32)reg - 1);
- break;
- case V4L2_CID_GAIN:
- ret = indycam_read_reg(sd, INDYCAM_REG_GAIN, &reg);
- if (ret)
- return -EIO;
- ctrl->value = (s32)reg;
- break;
- case V4L2_CID_RED_BALANCE:
- ret = indycam_read_reg(sd, INDYCAM_REG_RED_BALANCE, &reg);
- if (ret)
- return -EIO;
- ctrl->value = (s32)reg;
- break;
- case V4L2_CID_BLUE_BALANCE:
- ret = indycam_read_reg(sd, INDYCAM_REG_BLUE_BALANCE, &reg);
- if (ret)
- return -EIO;
- ctrl->value = (s32)reg;
- break;
- case INDYCAM_CONTROL_RED_SATURATION:
- ret = indycam_read_reg(sd,
- INDYCAM_REG_RED_SATURATION, &reg);
- if (ret)
- return -EIO;
- ctrl->value = (s32)reg;
- break;
- case INDYCAM_CONTROL_BLUE_SATURATION:
- ret = indycam_read_reg(sd,
- INDYCAM_REG_BLUE_SATURATION, &reg);
- if (ret)
- return -EIO;
- ctrl->value = (s32)reg;
- break;
- case V4L2_CID_GAMMA:
- if (camera->version == CAMERA_VERSION_MOOSE) {
- ret = indycam_read_reg(sd,
- INDYCAM_REG_GAMMA, &reg);
- if (ret)
- return -EIO;
- ctrl->value = (s32)reg;
- } else {
- ctrl->value = INDYCAM_GAMMA_DEFAULT;
- }
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int indycam_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct indycam *camera = to_indycam(sd);
- u8 reg;
- int ret = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_AUTOGAIN:
- case V4L2_CID_AUTO_WHITE_BALANCE:
- ret = indycam_read_reg(sd, INDYCAM_REG_CONTROL, &reg);
- if (ret)
- break;
-
- if (ctrl->id == V4L2_CID_AUTOGAIN) {
- if (ctrl->value)
- reg |= INDYCAM_CONTROL_AGCENA;
- else
- reg &= ~INDYCAM_CONTROL_AGCENA;
- } else {
- if (ctrl->value)
- reg |= INDYCAM_CONTROL_AWBCTL;
- else
- reg &= ~INDYCAM_CONTROL_AWBCTL;
- }
-
- ret = indycam_write_reg(sd, INDYCAM_REG_CONTROL, reg);
- break;
- case V4L2_CID_EXPOSURE:
- reg = (ctrl->value == 0xff) ? 0x00 : (ctrl->value + 1);
- ret = indycam_write_reg(sd, INDYCAM_REG_SHUTTER, reg);
- break;
- case V4L2_CID_GAIN:
- ret = indycam_write_reg(sd, INDYCAM_REG_GAIN, ctrl->value);
- break;
- case V4L2_CID_RED_BALANCE:
- ret = indycam_write_reg(sd, INDYCAM_REG_RED_BALANCE,
- ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_BALANCE,
- ctrl->value);
- break;
- case INDYCAM_CONTROL_RED_SATURATION:
- ret = indycam_write_reg(sd, INDYCAM_REG_RED_SATURATION,
- ctrl->value);
- break;
- case INDYCAM_CONTROL_BLUE_SATURATION:
- ret = indycam_write_reg(sd, INDYCAM_REG_BLUE_SATURATION,
- ctrl->value);
- break;
- case V4L2_CID_GAMMA:
- if (camera->version == CAMERA_VERSION_MOOSE) {
- ret = indycam_write_reg(sd, INDYCAM_REG_GAMMA,
- ctrl->value);
- }
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/* I2C-interface */
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops indycam_core_ops = {
- .g_ctrl = indycam_g_ctrl,
- .s_ctrl = indycam_s_ctrl,
-};
-
-static const struct v4l2_subdev_ops indycam_ops = {
- .core = &indycam_core_ops,
-};
-
-static int indycam_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int err = 0;
- struct indycam *camera;
- struct v4l2_subdev *sd;
-
- v4l_info(client, "chip found @ 0x%x (%s)\n",
- client->addr << 1, client->adapter->name);
-
- camera = kzalloc(sizeof(struct indycam), GFP_KERNEL);
- if (!camera)
- return -ENOMEM;
-
- sd = &camera->sd;
- v4l2_i2c_subdev_init(sd, client, &indycam_ops);
-
- camera->version = i2c_smbus_read_byte_data(client,
- INDYCAM_REG_VERSION);
- if (camera->version != CAMERA_VERSION_INDY &&
- camera->version != CAMERA_VERSION_MOOSE) {
- kfree(camera);
- return -ENODEV;
- }
-
- printk(KERN_INFO "IndyCam v%d.%d detected\n",
- INDYCAM_VERSION_MAJOR(camera->version),
- INDYCAM_VERSION_MINOR(camera->version));
-
- indycam_regdump(sd);
-
- // initialize
- err = indycam_write_block(sd, 0, sizeof(initseq), (u8 *)&initseq);
- if (err) {
- printk(KERN_ERR "IndyCam initialization failed\n");
- kfree(camera);
- return -EIO;
- }
-
- indycam_regdump(sd);
-
- // white balance
- err = indycam_write_reg(sd, INDYCAM_REG_CONTROL,
- INDYCAM_CONTROL_AGCENA | INDYCAM_CONTROL_AWBCTL);
- if (err) {
- printk(KERN_ERR "IndyCam: White balancing camera failed\n");
- kfree(camera);
- return -EIO;
- }
-
- indycam_regdump(sd);
-
- printk(KERN_INFO "IndyCam initialized\n");
-
- return 0;
-}
-
-static int indycam_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- kfree(to_indycam(sd));
- return 0;
-}
-
-static const struct i2c_device_id indycam_id[] = {
- { "indycam", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, indycam_id);
-
-static struct i2c_driver indycam_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "indycam",
- },
- .probe = indycam_probe,
- .remove = indycam_remove,
- .id_table = indycam_id,
-};
-
-module_i2c_driver(indycam_driver);
diff --git a/drivers/staging/media/vino/indycam.h b/drivers/staging/media/vino/indycam.h
deleted file mode 100644
index 881f21c474c4..000000000000
--- a/drivers/staging/media/vino/indycam.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * indycam.h - Silicon Graphics IndyCam digital camera driver
- *
- * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
- *
- * This program is free software; you can 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 _INDYCAM_H_
-#define _INDYCAM_H_
-
-/* I2C address for the Guinness Camera */
-#define INDYCAM_ADDR 0x56
-
-/* Camera version */
-#define CAMERA_VERSION_INDY 0x10 /* v1.0 */
-#define CAMERA_VERSION_MOOSE 0x12 /* v1.2 */
-#define INDYCAM_VERSION_MAJOR(x) (((x) & 0xf0) >> 4)
-#define INDYCAM_VERSION_MINOR(x) ((x) & 0x0f)
-
-/* Register bus addresses */
-#define INDYCAM_REG_CONTROL 0x00
-#define INDYCAM_REG_SHUTTER 0x01
-#define INDYCAM_REG_GAIN 0x02
-#define INDYCAM_REG_BRIGHTNESS 0x03 /* read-only */
-#define INDYCAM_REG_RED_BALANCE 0x04
-#define INDYCAM_REG_BLUE_BALANCE 0x05
-#define INDYCAM_REG_RED_SATURATION 0x06
-#define INDYCAM_REG_BLUE_SATURATION 0x07
-#define INDYCAM_REG_GAMMA 0x08
-#define INDYCAM_REG_VERSION 0x0e /* read-only */
-#define INDYCAM_REG_RESET 0x0f /* write-only */
-
-#define INDYCAM_REG_LED 0x46
-#define INDYCAM_REG_ORIENTATION 0x47
-#define INDYCAM_REG_BUTTON 0x48
-
-/* Field definitions of registers */
-#define INDYCAM_CONTROL_AGCENA (1<<0) /* automatic gain control */
-#define INDYCAM_CONTROL_AWBCTL (1<<1) /* automatic white balance */
- /* 2-3 are reserved */
-#define INDYCAM_CONTROL_EVNFLD (1<<4) /* read-only */
-
-#define INDYCAM_SHUTTER_10000 0x02 /* 1/10000 second */
-#define INDYCAM_SHUTTER_4000 0x04 /* 1/4000 second */
-#define INDYCAM_SHUTTER_2000 0x08 /* 1/2000 second */
-#define INDYCAM_SHUTTER_1000 0x10 /* 1/1000 second */
-#define INDYCAM_SHUTTER_500 0x20 /* 1/500 second */
-#define INDYCAM_SHUTTER_250 0x3f /* 1/250 second */
-#define INDYCAM_SHUTTER_125 0x7e /* 1/125 second */
-#define INDYCAM_SHUTTER_100 0x9e /* 1/100 second */
-#define INDYCAM_SHUTTER_60 0x00 /* 1/60 second */
-
-#define INDYCAM_LED_ACTIVE 0x10
-#define INDYCAM_LED_INACTIVE 0x30
-#define INDYCAM_ORIENTATION_BOTTOM_TO_TOP 0x40
-#define INDYCAM_BUTTON_RELEASED 0x10
-
-/* Values for controls */
-#define INDYCAM_SHUTTER_MIN 0x00
-#define INDYCAM_SHUTTER_MAX 0xff
-#define INDYCAM_GAIN_MIN 0x00
-#define INDYCAM_GAIN_MAX 0xff
-#define INDYCAM_RED_BALANCE_MIN 0x00
-#define INDYCAM_RED_BALANCE_MAX 0xff
-#define INDYCAM_BLUE_BALANCE_MIN 0x00
-#define INDYCAM_BLUE_BALANCE_MAX 0xff
-#define INDYCAM_RED_SATURATION_MIN 0x00
-#define INDYCAM_RED_SATURATION_MAX 0xff
-#define INDYCAM_BLUE_SATURATION_MIN 0x00
-#define INDYCAM_BLUE_SATURATION_MAX 0xff
-#define INDYCAM_GAMMA_MIN 0x00
-#define INDYCAM_GAMMA_MAX 0xff
-
-#define INDYCAM_AGC_DEFAULT 1
-#define INDYCAM_AWB_DEFAULT 0
-#define INDYCAM_SHUTTER_DEFAULT 0xff
-#define INDYCAM_GAIN_DEFAULT 0x80
-#define INDYCAM_RED_BALANCE_DEFAULT 0x18
-#define INDYCAM_BLUE_BALANCE_DEFAULT 0xa4
-#define INDYCAM_RED_SATURATION_DEFAULT 0x80
-#define INDYCAM_BLUE_SATURATION_DEFAULT 0xc0
-#define INDYCAM_GAMMA_DEFAULT 0x80
-
-/* Driver interface definitions */
-
-#define INDYCAM_CONTROL_RED_SATURATION (V4L2_CID_PRIVATE_BASE + 0)
-#define INDYCAM_CONTROL_BLUE_SATURATION (V4L2_CID_PRIVATE_BASE + 1)
-
-#endif
diff --git a/drivers/staging/media/vino/saa7191.c b/drivers/staging/media/vino/saa7191.c
deleted file mode 100644
index 8e9699268a63..000000000000
--- a/drivers/staging/media/vino/saa7191.c
+++ /dev/null
@@ -1,649 +0,0 @@
-/*
- * saa7191.c - Philips SAA7191 video decoder driver
- *
- * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-
-#include <linux/videodev2.h>
-#include <linux/i2c.h>
-#include <media/v4l2-device.h>
-
-#include "saa7191.h"
-
-#define SAA7191_MODULE_VERSION "0.0.5"
-
-MODULE_DESCRIPTION("Philips SAA7191 video decoder driver");
-MODULE_VERSION(SAA7191_MODULE_VERSION);
-MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
-MODULE_LICENSE("GPL");
-
-
-// #define SAA7191_DEBUG
-
-#ifdef SAA7191_DEBUG
-#define dprintk(x...) printk("SAA7191: " x);
-#else
-#define dprintk(x...)
-#endif
-
-#define SAA7191_SYNC_COUNT 30
-#define SAA7191_SYNC_DELAY 100 /* milliseconds */
-
-struct saa7191 {
- struct v4l2_subdev sd;
-
- /* the register values are stored here as the actual
- * I2C-registers are write-only */
- u8 reg[25];
-
- int input;
- v4l2_std_id norm;
-};
-
-static inline struct saa7191 *to_saa7191(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct saa7191, sd);
-}
-
-static const u8 initseq[] = {
- 0, /* Subaddress */
-
- 0x50, /* (0x50) SAA7191_REG_IDEL */
-
- /* 50 Hz signal timing */
- 0x30, /* (0x30) SAA7191_REG_HSYB */
- 0x00, /* (0x00) SAA7191_REG_HSYS */
- 0xe8, /* (0xe8) SAA7191_REG_HCLB */
- 0xb6, /* (0xb6) SAA7191_REG_HCLS */
- 0xf4, /* (0xf4) SAA7191_REG_HPHI */
-
- /* control */
- SAA7191_LUMA_APER_1, /* (0x01) SAA7191_REG_LUMA - CVBS mode */
- 0x00, /* (0x00) SAA7191_REG_HUEC */
- 0xf8, /* (0xf8) SAA7191_REG_CKTQ */
- 0xf8, /* (0xf8) SAA7191_REG_CKTS */
- 0x90, /* (0x90) SAA7191_REG_PLSE */
- 0x90, /* (0x90) SAA7191_REG_SESE */
- 0x00, /* (0x00) SAA7191_REG_GAIN */
- SAA7191_STDC_NFEN | SAA7191_STDC_HRMV, /* (0x0c) SAA7191_REG_STDC
- * - not SECAM,
- * slow time constant */
- SAA7191_IOCK_OEDC | SAA7191_IOCK_OEHS | SAA7191_IOCK_OEVS
- | SAA7191_IOCK_OEDY, /* (0x78) SAA7191_REG_IOCK
- * - chroma from CVBS, GPSW1 & 2 off */
- SAA7191_CTL3_AUFD | SAA7191_CTL3_SCEN | SAA7191_CTL3_OFTS
- | SAA7191_CTL3_YDEL0, /* (0x99) SAA7191_REG_CTL3
- * - automatic field detection */
- 0x00, /* (0x00) SAA7191_REG_CTL4 */
- 0x2c, /* (0x2c) SAA7191_REG_CHCV - PAL nominal value */
- 0x00, /* unused */
- 0x00, /* unused */
-
- /* 60 Hz signal timing */
- 0x34, /* (0x34) SAA7191_REG_HS6B */
- 0x0a, /* (0x0a) SAA7191_REG_HS6S */
- 0xf4, /* (0xf4) SAA7191_REG_HC6B */
- 0xce, /* (0xce) SAA7191_REG_HC6S */
- 0xf4, /* (0xf4) SAA7191_REG_HP6I */
-};
-
-/* SAA7191 register handling */
-
-static u8 saa7191_read_reg(struct v4l2_subdev *sd, u8 reg)
-{
- return to_saa7191(sd)->reg[reg];
-}
-
-static int saa7191_read_status(struct v4l2_subdev *sd, u8 *value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
-
- ret = i2c_master_recv(client, value, 1);
- if (ret < 0) {
- printk(KERN_ERR "SAA7191: saa7191_read_status(): read failed\n");
- return ret;
- }
-
- return 0;
-}
-
-
-static int saa7191_write_reg(struct v4l2_subdev *sd, u8 reg, u8 value)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- to_saa7191(sd)->reg[reg] = value;
- return i2c_smbus_write_byte_data(client, reg, value);
-}
-
-/* the first byte of data must be the first subaddress number (register) */
-static int saa7191_write_block(struct v4l2_subdev *sd,
- u8 length, const u8 *data)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct saa7191 *decoder = to_saa7191(sd);
- int i;
- int ret;
-
- for (i = 0; i < (length - 1); i++) {
- decoder->reg[data[0] + i] = data[i + 1];
- }
-
- ret = i2c_master_send(client, data, length);
- if (ret < 0) {
- printk(KERN_ERR "SAA7191: saa7191_write_block(): "
- "write failed\n");
- return ret;
- }
-
- return 0;
-}
-
-/* Helper functions */
-
-static int saa7191_s_routing(struct v4l2_subdev *sd,
- u32 input, u32 output, u32 config)
-{
- struct saa7191 *decoder = to_saa7191(sd);
- u8 luma = saa7191_read_reg(sd, SAA7191_REG_LUMA);
- u8 iock = saa7191_read_reg(sd, SAA7191_REG_IOCK);
- int err;
-
- switch (input) {
- case SAA7191_INPUT_COMPOSITE: /* Set Composite input */
- iock &= ~(SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW1
- | SAA7191_IOCK_GPSW2);
- /* Chrominance trap active */
- luma &= ~SAA7191_LUMA_BYPS;
- break;
- case SAA7191_INPUT_SVIDEO: /* Set S-Video input */
- iock |= SAA7191_IOCK_CHRS | SAA7191_IOCK_GPSW2;
- /* Chrominance trap bypassed */
- luma |= SAA7191_LUMA_BYPS;
- break;
- default:
- return -EINVAL;
- }
-
- err = saa7191_write_reg(sd, SAA7191_REG_LUMA, luma);
- if (err)
- return -EIO;
- err = saa7191_write_reg(sd, SAA7191_REG_IOCK, iock);
- if (err)
- return -EIO;
-
- decoder->input = input;
-
- return 0;
-}
-
-static int saa7191_s_std(struct v4l2_subdev *sd, v4l2_std_id norm)
-{
- struct saa7191 *decoder = to_saa7191(sd);
- u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
- u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
- u8 chcv = saa7191_read_reg(sd, SAA7191_REG_CHCV);
- int err;
-
- if (norm & V4L2_STD_PAL) {
- stdc &= ~SAA7191_STDC_SECS;
- ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
- chcv = SAA7191_CHCV_PAL;
- } else if (norm & V4L2_STD_NTSC) {
- stdc &= ~SAA7191_STDC_SECS;
- ctl3 &= ~SAA7191_CTL3_AUFD;
- ctl3 |= SAA7191_CTL3_FSEL;
- chcv = SAA7191_CHCV_NTSC;
- } else if (norm & V4L2_STD_SECAM) {
- stdc |= SAA7191_STDC_SECS;
- ctl3 &= ~(SAA7191_CTL3_AUFD | SAA7191_CTL3_FSEL);
- chcv = SAA7191_CHCV_PAL;
- } else {
- return -EINVAL;
- }
-
- err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
- if (err)
- return -EIO;
- err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
- if (err)
- return -EIO;
- err = saa7191_write_reg(sd, SAA7191_REG_CHCV, chcv);
- if (err)
- return -EIO;
-
- decoder->norm = norm;
-
- dprintk("ctl3: %02x stdc: %02x chcv: %02x\n", ctl3,
- stdc, chcv);
- dprintk("norm: %llx\n", norm);
-
- return 0;
-}
-
-static int saa7191_wait_for_signal(struct v4l2_subdev *sd, u8 *status)
-{
- int i = 0;
-
- dprintk("Checking for signal...\n");
-
- for (i = 0; i < SAA7191_SYNC_COUNT; i++) {
- if (saa7191_read_status(sd, status))
- return -EIO;
-
- if (((*status) & SAA7191_STATUS_HLCK) == 0) {
- dprintk("Signal found\n");
- return 0;
- }
-
- msleep(SAA7191_SYNC_DELAY);
- }
-
- dprintk("No signal\n");
-
- return -EBUSY;
-}
-
-static int saa7191_querystd(struct v4l2_subdev *sd, v4l2_std_id *norm)
-{
- struct saa7191 *decoder = to_saa7191(sd);
- u8 stdc = saa7191_read_reg(sd, SAA7191_REG_STDC);
- u8 ctl3 = saa7191_read_reg(sd, SAA7191_REG_CTL3);
- u8 status;
- v4l2_std_id old_norm = decoder->norm;
- int err = 0;
-
- dprintk("SAA7191 extended signal auto-detection...\n");
-
- *norm &= V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
- stdc &= ~SAA7191_STDC_SECS;
- ctl3 &= ~(SAA7191_CTL3_FSEL);
-
- err = saa7191_write_reg(sd, SAA7191_REG_STDC, stdc);
- if (err) {
- err = -EIO;
- goto out;
- }
- err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
- if (err) {
- err = -EIO;
- goto out;
- }
-
- ctl3 |= SAA7191_CTL3_AUFD;
- err = saa7191_write_reg(sd, SAA7191_REG_CTL3, ctl3);
- if (err) {
- err = -EIO;
- goto out;
- }
-
- msleep(SAA7191_SYNC_DELAY);
-
- err = saa7191_wait_for_signal(sd, &status);
- if (err)
- goto out;
-
- if (status & SAA7191_STATUS_FIDT) {
- /* 60Hz signal -> NTSC */
- dprintk("60Hz signal: NTSC\n");
- *norm &= V4L2_STD_NTSC;
- return 0;
- }
-
- /* 50Hz signal */
- dprintk("50Hz signal: Trying PAL...\n");
-
- /* try PAL first */
- err = saa7191_s_std(sd, V4L2_STD_PAL);
- if (err)
- goto out;
-
- msleep(SAA7191_SYNC_DELAY);
-
- err = saa7191_wait_for_signal(sd, &status);
- if (err)
- goto out;
-
- /* not 50Hz ? */
- if (status & SAA7191_STATUS_FIDT) {
- dprintk("No 50Hz signal\n");
- saa7191_s_std(sd, old_norm);
- *norm = V4L2_STD_UNKNOWN;
- return 0;
- }
-
- if (status & SAA7191_STATUS_CODE) {
- dprintk("PAL\n");
- *norm &= V4L2_STD_PAL;
- return saa7191_s_std(sd, old_norm);
- }
-
- dprintk("No color detected with PAL - Trying SECAM...\n");
-
- /* no color detected ? -> try SECAM */
- err = saa7191_s_std(sd, V4L2_STD_SECAM);
- if (err)
- goto out;
-
- msleep(SAA7191_SYNC_DELAY);
-
- err = saa7191_wait_for_signal(sd, &status);
- if (err)
- goto out;
-
- /* not 50Hz ? */
- if (status & SAA7191_STATUS_FIDT) {
- dprintk("No 50Hz signal\n");
- *norm = V4L2_STD_UNKNOWN;
- goto out;
- }
-
- if (status & SAA7191_STATUS_CODE) {
- /* Color detected -> SECAM */
- dprintk("SECAM\n");
- *norm &= V4L2_STD_SECAM;
- return saa7191_s_std(sd, old_norm);
- }
-
- dprintk("No color detected with SECAM - Going back to PAL.\n");
- *norm = V4L2_STD_UNKNOWN;
-
-out:
- return saa7191_s_std(sd, old_norm);
-}
-
-static int saa7191_autodetect_norm(struct v4l2_subdev *sd)
-{
- u8 status;
-
- dprintk("SAA7191 signal auto-detection...\n");
-
- dprintk("Reading status...\n");
-
- if (saa7191_read_status(sd, &status))
- return -EIO;
-
- dprintk("Checking for signal...\n");
-
- /* no signal ? */
- if (status & SAA7191_STATUS_HLCK) {
- dprintk("No signal\n");
- return -EBUSY;
- }
-
- dprintk("Signal found\n");
-
- if (status & SAA7191_STATUS_FIDT) {
- /* 60hz signal -> NTSC */
- dprintk("NTSC\n");
- return saa7191_s_std(sd, V4L2_STD_NTSC);
- } else {
- /* 50hz signal -> PAL */
- dprintk("PAL\n");
- return saa7191_s_std(sd, V4L2_STD_PAL);
- }
-}
-
-static int saa7191_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- u8 reg;
- int ret = 0;
-
- switch (ctrl->id) {
- case SAA7191_CONTROL_BANDPASS:
- case SAA7191_CONTROL_BANDPASS_WEIGHT:
- case SAA7191_CONTROL_CORING:
- reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
- switch (ctrl->id) {
- case SAA7191_CONTROL_BANDPASS:
- ctrl->value = ((s32)reg & SAA7191_LUMA_BPSS_MASK)
- >> SAA7191_LUMA_BPSS_SHIFT;
- break;
- case SAA7191_CONTROL_BANDPASS_WEIGHT:
- ctrl->value = ((s32)reg & SAA7191_LUMA_APER_MASK)
- >> SAA7191_LUMA_APER_SHIFT;
- break;
- case SAA7191_CONTROL_CORING:
- ctrl->value = ((s32)reg & SAA7191_LUMA_CORI_MASK)
- >> SAA7191_LUMA_CORI_SHIFT;
- break;
- }
- break;
- case SAA7191_CONTROL_FORCE_COLOUR:
- case SAA7191_CONTROL_CHROMA_GAIN:
- reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
- if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR)
- ctrl->value = ((s32)reg & SAA7191_GAIN_COLO) ? 1 : 0;
- else
- ctrl->value = ((s32)reg & SAA7191_GAIN_LFIS_MASK)
- >> SAA7191_GAIN_LFIS_SHIFT;
- break;
- case V4L2_CID_HUE:
- reg = saa7191_read_reg(sd, SAA7191_REG_HUEC);
- if (reg < 0x80)
- reg += 0x80;
- else
- reg -= 0x80;
- ctrl->value = (s32)reg;
- break;
- case SAA7191_CONTROL_VTRC:
- reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
- ctrl->value = ((s32)reg & SAA7191_STDC_VTRC) ? 1 : 0;
- break;
- case SAA7191_CONTROL_LUMA_DELAY:
- reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
- ctrl->value = ((s32)reg & SAA7191_CTL3_YDEL_MASK)
- >> SAA7191_CTL3_YDEL_SHIFT;
- if (ctrl->value >= 4)
- ctrl->value -= 8;
- break;
- case SAA7191_CONTROL_VNR:
- reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
- ctrl->value = ((s32)reg & SAA7191_CTL4_VNOI_MASK)
- >> SAA7191_CTL4_VNOI_SHIFT;
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-static int saa7191_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- u8 reg;
- int ret = 0;
-
- switch (ctrl->id) {
- case SAA7191_CONTROL_BANDPASS:
- case SAA7191_CONTROL_BANDPASS_WEIGHT:
- case SAA7191_CONTROL_CORING:
- reg = saa7191_read_reg(sd, SAA7191_REG_LUMA);
- switch (ctrl->id) {
- case SAA7191_CONTROL_BANDPASS:
- reg &= ~SAA7191_LUMA_BPSS_MASK;
- reg |= (ctrl->value << SAA7191_LUMA_BPSS_SHIFT)
- & SAA7191_LUMA_BPSS_MASK;
- break;
- case SAA7191_CONTROL_BANDPASS_WEIGHT:
- reg &= ~SAA7191_LUMA_APER_MASK;
- reg |= (ctrl->value << SAA7191_LUMA_APER_SHIFT)
- & SAA7191_LUMA_APER_MASK;
- break;
- case SAA7191_CONTROL_CORING:
- reg &= ~SAA7191_LUMA_CORI_MASK;
- reg |= (ctrl->value << SAA7191_LUMA_CORI_SHIFT)
- & SAA7191_LUMA_CORI_MASK;
- break;
- }
- ret = saa7191_write_reg(sd, SAA7191_REG_LUMA, reg);
- break;
- case SAA7191_CONTROL_FORCE_COLOUR:
- case SAA7191_CONTROL_CHROMA_GAIN:
- reg = saa7191_read_reg(sd, SAA7191_REG_GAIN);
- if (ctrl->id == SAA7191_CONTROL_FORCE_COLOUR) {
- if (ctrl->value)
- reg |= SAA7191_GAIN_COLO;
- else
- reg &= ~SAA7191_GAIN_COLO;
- } else {
- reg &= ~SAA7191_GAIN_LFIS_MASK;
- reg |= (ctrl->value << SAA7191_GAIN_LFIS_SHIFT)
- & SAA7191_GAIN_LFIS_MASK;
- }
- ret = saa7191_write_reg(sd, SAA7191_REG_GAIN, reg);
- break;
- case V4L2_CID_HUE:
- reg = ctrl->value & 0xff;
- if (reg < 0x80)
- reg += 0x80;
- else
- reg -= 0x80;
- ret = saa7191_write_reg(sd, SAA7191_REG_HUEC, reg);
- break;
- case SAA7191_CONTROL_VTRC:
- reg = saa7191_read_reg(sd, SAA7191_REG_STDC);
- if (ctrl->value)
- reg |= SAA7191_STDC_VTRC;
- else
- reg &= ~SAA7191_STDC_VTRC;
- ret = saa7191_write_reg(sd, SAA7191_REG_STDC, reg);
- break;
- case SAA7191_CONTROL_LUMA_DELAY: {
- s32 value = ctrl->value;
- if (value < 0)
- value += 8;
- reg = saa7191_read_reg(sd, SAA7191_REG_CTL3);
- reg &= ~SAA7191_CTL3_YDEL_MASK;
- reg |= (value << SAA7191_CTL3_YDEL_SHIFT)
- & SAA7191_CTL3_YDEL_MASK;
- ret = saa7191_write_reg(sd, SAA7191_REG_CTL3, reg);
- break;
- }
- case SAA7191_CONTROL_VNR:
- reg = saa7191_read_reg(sd, SAA7191_REG_CTL4);
- reg &= ~SAA7191_CTL4_VNOI_MASK;
- reg |= (ctrl->value << SAA7191_CTL4_VNOI_SHIFT)
- & SAA7191_CTL4_VNOI_MASK;
- ret = saa7191_write_reg(sd, SAA7191_REG_CTL4, reg);
- break;
- default:
- ret = -EINVAL;
- }
-
- return ret;
-}
-
-/* I2C-interface */
-
-static int saa7191_g_input_status(struct v4l2_subdev *sd, u32 *status)
-{
- u8 status_reg;
- int res = V4L2_IN_ST_NO_SIGNAL;
-
- if (saa7191_read_status(sd, &status_reg))
- return -EIO;
- if ((status_reg & SAA7191_STATUS_HLCK) == 0)
- res = 0;
- if (!(status_reg & SAA7191_STATUS_CODE))
- res |= V4L2_IN_ST_NO_COLOR;
- *status = res;
- return 0;
-}
-
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops saa7191_core_ops = {
- .g_ctrl = saa7191_g_ctrl,
- .s_ctrl = saa7191_s_ctrl,
-};
-
-static const struct v4l2_subdev_video_ops saa7191_video_ops = {
- .s_std = saa7191_s_std,
- .s_routing = saa7191_s_routing,
- .querystd = saa7191_querystd,
- .g_input_status = saa7191_g_input_status,
-};
-
-static const struct v4l2_subdev_ops saa7191_ops = {
- .core = &saa7191_core_ops,
- .video = &saa7191_video_ops,
-};
-
-static int saa7191_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int err = 0;
- struct saa7191 *decoder;
- struct v4l2_subdev *sd;
-
- v4l_info(client, "chip found @ 0x%x (%s)\n",
- client->addr << 1, client->adapter->name);
-
- decoder = devm_kzalloc(&client->dev, sizeof(*decoder), GFP_KERNEL);
- if (!decoder)
- return -ENOMEM;
-
- sd = &decoder->sd;
- v4l2_i2c_subdev_init(sd, client, &saa7191_ops);
-
- err = saa7191_write_block(sd, sizeof(initseq), initseq);
- if (err) {
- printk(KERN_ERR "SAA7191 initialization failed\n");
- return err;
- }
-
- printk(KERN_INFO "SAA7191 initialized\n");
-
- decoder->input = SAA7191_INPUT_COMPOSITE;
- decoder->norm = V4L2_STD_PAL;
-
- err = saa7191_autodetect_norm(sd);
- if (err && (err != -EBUSY))
- printk(KERN_ERR "SAA7191: Signal auto-detection failed\n");
-
- return 0;
-}
-
-static int saa7191_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- v4l2_device_unregister_subdev(sd);
- return 0;
-}
-
-static const struct i2c_device_id saa7191_id[] = {
- { "saa7191", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, saa7191_id);
-
-static struct i2c_driver saa7191_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = "saa7191",
- },
- .probe = saa7191_probe,
- .remove = saa7191_remove,
- .id_table = saa7191_id,
-};
-
-module_i2c_driver(saa7191_driver);
diff --git a/drivers/staging/media/vino/saa7191.h b/drivers/staging/media/vino/saa7191.h
deleted file mode 100644
index 803c74d6066f..000000000000
--- a/drivers/staging/media/vino/saa7191.h
+++ /dev/null
@@ -1,245 +0,0 @@
-/*
- * saa7191.h - Philips SAA7191 video decoder driver
- *
- * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
- *
- * This program is free software; you can 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 _SAA7191_H_
-#define _SAA7191_H_
-
-/* Philips SAA7191 DMSD I2C bus address */
-#define SAA7191_ADDR 0x8a
-
-/* Register subaddresses. */
-#define SAA7191_REG_IDEL 0x00
-#define SAA7191_REG_HSYB 0x01
-#define SAA7191_REG_HSYS 0x02
-#define SAA7191_REG_HCLB 0x03
-#define SAA7191_REG_HCLS 0x04
-#define SAA7191_REG_HPHI 0x05
-#define SAA7191_REG_LUMA 0x06
-#define SAA7191_REG_HUEC 0x07
-#define SAA7191_REG_CKTQ 0x08 /* bits 3-7 */
-#define SAA7191_REG_CKTS 0x09 /* bits 3-7 */
-#define SAA7191_REG_PLSE 0x0a
-#define SAA7191_REG_SESE 0x0b
-#define SAA7191_REG_GAIN 0x0c
-#define SAA7191_REG_STDC 0x0d
-#define SAA7191_REG_IOCK 0x0e
-#define SAA7191_REG_CTL3 0x0f
-#define SAA7191_REG_CTL4 0x10
-#define SAA7191_REG_CHCV 0x11
-#define SAA7191_REG_HS6B 0x14
-#define SAA7191_REG_HS6S 0x15
-#define SAA7191_REG_HC6B 0x16
-#define SAA7191_REG_HC6S 0x17
-#define SAA7191_REG_HP6I 0x18
-#define SAA7191_REG_STATUS 0xff /* not really a subaddress */
-
-/* Status Register definitions */
-#define SAA7191_STATUS_CODE 0x01 /* color detected flag */
-#define SAA7191_STATUS_FIDT 0x20 /* signal type 50/60 Hz */
-#define SAA7191_STATUS_HLCK 0x40 /* PLL unlocked(1)/locked(0) */
-#define SAA7191_STATUS_STTC 0x80 /* tv/vtr time constant */
-
-/* Luminance Control Register definitions */
-/* input mode select bit:
- * 0=CVBS (chrominance trap active), 1=S-Video (trap bypassed) */
-#define SAA7191_LUMA_BYPS 0x80
-/* pre-filter (only when chrominance trap is active) */
-#define SAA7191_LUMA_PREF 0x40
-/* aperture bandpass to select different characteristics with maximums
- * (bits 4-5) */
-#define SAA7191_LUMA_BPSS_MASK 0x30
-#define SAA7191_LUMA_BPSS_SHIFT 4
-#define SAA7191_LUMA_BPSS_3 0x30
-#define SAA7191_LUMA_BPSS_2 0x20
-#define SAA7191_LUMA_BPSS_1 0x10
-#define SAA7191_LUMA_BPSS_0 0x00
-/* coring range for high frequency components according to 8-bit luminance
- * (bits 2-3)
- * 0=coring off, n= (+-)n LSB */
-#define SAA7191_LUMA_CORI_MASK 0x0c
-#define SAA7191_LUMA_CORI_SHIFT 2
-#define SAA7191_LUMA_CORI_3 0x0c
-#define SAA7191_LUMA_CORI_2 0x08
-#define SAA7191_LUMA_CORI_1 0x04
-#define SAA7191_LUMA_CORI_0 0x00
-/* aperture bandpass filter weights high frequency components of luminance
- * signal (bits 0-1)
- * 0=factor 0, 1=0.25, 2=0.5, 3=1 */
-#define SAA7191_LUMA_APER_MASK 0x03
-#define SAA7191_LUMA_APER_SHIFT 0
-#define SAA7191_LUMA_APER_3 0x03
-#define SAA7191_LUMA_APER_2 0x02
-#define SAA7191_LUMA_APER_1 0x01
-#define SAA7191_LUMA_APER_0 0x00
-
-/* Chrominance Gain Control Settings Register definitions */
-/* colour on: 0=automatic colour-killer enabled, 1=forced colour on */
-#define SAA7191_GAIN_COLO 0x80
-/* chrominance gain control (AGC filter)
- * 0=loop filter time constant slow, 1=medium, 2=fast, 3=actual gain */
-#define SAA7191_GAIN_LFIS_MASK 0x60
-#define SAA7191_GAIN_LFIS_SHIFT 5
-#define SAA7191_GAIN_LFIS_3 0x60
-#define SAA7191_GAIN_LFIS_2 0x40
-#define SAA7191_GAIN_LFIS_1 0x20
-#define SAA7191_GAIN_LFIS_0 0x00
-
-/* Standard/Mode Control Register definitions */
-/* tv/vtr mode bit: 0=TV mode (slow time constant),
- * 1=VTR mode (fast time constant) */
-#define SAA7191_STDC_VTRC 0x80
-/* SAA7191B-specific functions enable (RTCO, ODD and GPSW0 outputs)
- * 0=outputs set to high-impedance (circuit equals SAA7191), 1=enabled */
-#define SAA7191_STDC_NFEN 0x08
-/* HREF generation: 0=like SAA7191, 1=HREF is 8xLLC2 clocks earlier */
-#define SAA7191_STDC_HRMV 0x04
-/* general purpose switch 0
- * (not used with VINO afaik) */
-#define SAA7191_STDC_GPSW0 0x02
-/* SECAM mode bit: 0=other standards, 1=SECAM */
-#define SAA7191_STDC_SECS 0x01
-
-/* I/O and Clock Control Register definitions */
-/* horizontal clock PLL: 0=PLL closed,
- * 1=PLL circuit open and horizontal freq fixed */
-#define SAA7191_IOCK_HPLL 0x80
-/* colour-difference output enable (outputs UV0-UV7) */
-#define SAA7191_IOCK_OEDC 0x40
-/* H-sync output enable */
-#define SAA7191_IOCK_OEHS 0x20
-/* V-sync output enable */
-#define SAA7191_IOCK_OEVS 0x10
-/* luminance output enable (outputs Y0-Y7) */
-#define SAA7191_IOCK_OEDY 0x08
-/* S-VHS bit (chrominance from CVBS or from chrominance input):
- * 0=controlled by BYPS-bit, 1=from chrominance input */
-#define SAA7191_IOCK_CHRS 0x04
-/* general purpose switch 2
- * VINO-specific: 0=used with CVBS, 1=used with S-Video */
-#define SAA7191_IOCK_GPSW2 0x02
-/* general purpose switch 1 */
-/* VINO-specific: 0=always, 1=not used!*/
-#define SAA7191_IOCK_GPSW1 0x01
-
-/* Miscellaneous Control #1 Register definitions */
-/* automatic field detection (50/60Hz standard) */
-#define SAA7191_CTL3_AUFD 0x80
-/* field select: (if AUFD=0)
- * 0=50Hz (625 lines), 1=60Hz (525 lines) */
-#define SAA7191_CTL3_FSEL 0x40
-/* SECAM cross-colour reduction enable */
-#define SAA7191_CTL3_SXCR 0x20
-/* sync and clamping pulse enable (HCL and HSY outputs) */
-#define SAA7191_CTL3_SCEN 0x10
-/* output format: 0=4:1:1, 1=4:2:2 (4:2:2 for VINO) */
-#define SAA7191_CTL3_OFTS 0x08
-/* luminance delay compensation
- * 0=0*2/LLC, 1=+1*2/LLC, 2=+2*2/LLC, 3=+3*2/LLC,
- * 4=-4*2/LLC, 5=-3*2/LLC, 6=-2*2/LLC, 7=-1*2/LLC
- * step size = 2/LLC = 67.8ns for 50Hz, 81.5ns for 60Hz */
-#define SAA7191_CTL3_YDEL_MASK 0x07
-#define SAA7191_CTL3_YDEL_SHIFT 0
-#define SAA7191_CTL3_YDEL2 0x04
-#define SAA7191_CTL3_YDEL1 0x02
-#define SAA7191_CTL3_YDEL0 0x01
-
-/* Miscellaneous Control #2 Register definitions */
-/* select HREF position
- * 0=normal, HREF is matched to YUV output port,
- * 1=HREF is matched to CVBS input port */
-#define SAA7191_CTL4_HRFS 0x04
-/* vertical noise reduction
- * 0=normal, 1=searching window, 2=auto-deflection, 3=reduction bypassed */
-#define SAA7191_CTL4_VNOI_MASK 0x03
-#define SAA7191_CTL4_VNOI_SHIFT 0
-#define SAA7191_CTL4_VNOI_3 0x03
-#define SAA7191_CTL4_VNOI_2 0x02
-#define SAA7191_CTL4_VNOI_1 0x01
-#define SAA7191_CTL4_VNOI_0 0x00
-
-/* Chrominance Gain Control Register definitions
- * - for QAM-modulated input signals, effects output amplitude
- * (SECAM gain fixed)
- * (nominal values for UV CCIR level) */
-#define SAA7191_CHCV_NTSC 0x2c
-#define SAA7191_CHCV_PAL 0x59
-
-/* Driver interface definitions */
-#define SAA7191_INPUT_COMPOSITE 0
-#define SAA7191_INPUT_SVIDEO 1
-
-#define SAA7191_NORM_PAL 1
-#define SAA7191_NORM_NTSC 2
-#define SAA7191_NORM_SECAM 3
-
-struct saa7191_status {
- /* 0=no signal, 1=signal detected */
- int signal;
- /* 0=50hz (pal) signal, 1=60hz (ntsc) signal */
- int signal_60hz;
- /* 0=no color detected, 1=color detected */
- int color;
-
- /* current SAA7191_INPUT_ */
- int input;
- /* current SAA7191_NORM_ */
- int norm;
-};
-
-#define SAA7191_BANDPASS_MIN 0x00
-#define SAA7191_BANDPASS_MAX 0x03
-#define SAA7191_BANDPASS_DEFAULT 0x00
-
-#define SAA7191_BANDPASS_WEIGHT_MIN 0x00
-#define SAA7191_BANDPASS_WEIGHT_MAX 0x03
-#define SAA7191_BANDPASS_WEIGHT_DEFAULT 0x01
-
-#define SAA7191_CORING_MIN 0x00
-#define SAA7191_CORING_MAX 0x03
-#define SAA7191_CORING_DEFAULT 0x00
-
-#define SAA7191_HUE_MIN 0x00
-#define SAA7191_HUE_MAX 0xff
-#define SAA7191_HUE_DEFAULT 0x80
-
-#define SAA7191_VTRC_MIN 0x00
-#define SAA7191_VTRC_MAX 0x01
-#define SAA7191_VTRC_DEFAULT 0x00
-
-#define SAA7191_FORCE_COLOUR_MIN 0x00
-#define SAA7191_FORCE_COLOUR_MAX 0x01
-#define SAA7191_FORCE_COLOUR_DEFAULT 0x00
-
-#define SAA7191_CHROMA_GAIN_MIN 0x00
-#define SAA7191_CHROMA_GAIN_MAX 0x03
-#define SAA7191_CHROMA_GAIN_DEFAULT 0x00
-
-#define SAA7191_LUMA_DELAY_MIN -0x04
-#define SAA7191_LUMA_DELAY_MAX 0x03
-#define SAA7191_LUMA_DELAY_DEFAULT 0x01
-
-#define SAA7191_VNR_MIN 0x00
-#define SAA7191_VNR_MAX 0x03
-#define SAA7191_VNR_DEFAULT 0x00
-
-#define SAA7191_CONTROL_BANDPASS (V4L2_CID_PRIVATE_BASE + 0)
-#define SAA7191_CONTROL_BANDPASS_WEIGHT (V4L2_CID_PRIVATE_BASE + 1)
-#define SAA7191_CONTROL_CORING (V4L2_CID_PRIVATE_BASE + 2)
-#define SAA7191_CONTROL_FORCE_COLOUR (V4L2_CID_PRIVATE_BASE + 3)
-#define SAA7191_CONTROL_CHROMA_GAIN (V4L2_CID_PRIVATE_BASE + 4)
-#define SAA7191_CONTROL_VTRC (V4L2_CID_PRIVATE_BASE + 5)
-#define SAA7191_CONTROL_LUMA_DELAY (V4L2_CID_PRIVATE_BASE + 6)
-#define SAA7191_CONTROL_VNR (V4L2_CID_PRIVATE_BASE + 7)
-
-#define DECODER_SAA7191_GET_STATUS _IOR('d', 195, struct saa7191_status)
-#define DECODER_SAA7191_SET_NORM _IOW('d', 196, int)
-
-#endif
diff --git a/drivers/staging/media/vino/vino.c b/drivers/staging/media/vino/vino.c
deleted file mode 100644
index 2c85357f774d..000000000000
--- a/drivers/staging/media/vino/vino.c
+++ /dev/null
@@ -1,4345 +0,0 @@
-/*
- * Driver for the VINO (Video In No Out) system found in SGI Indys.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * Copyright (C) 2004,2005 Mikael Nousiainen <tmnousia@cc.hut.fi>
- *
- * Based on the previous version of the driver for 2.4 kernels by:
- * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
- *
- * v4l2_device/v4l2_subdev conversion by:
- * Copyright (C) 2009 Hans Verkuil <hverkuil@xs4all.nl>
- *
- * Note: this conversion is untested! Please contact the linux-media
- * mailinglist if you can test this, together with the test results.
- */
-
-/*
- * TODO:
- * - remove "mark pages reserved-hacks" from memory allocation code
- * and implement fault()
- * - check decimation, calculating and reporting image size when
- * using decimation
- * - implement read(), user mode buffers and overlay (?)
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/dma-mapping.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/interrupt.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/time.h>
-#include <linux/kmod.h>
-
-#include <linux/i2c.h>
-
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
-
-#include <asm/paccess.h>
-#include <asm/io.h>
-#include <asm/sgi/ip22.h>
-#include <asm/sgi/mc.h>
-
-#include "vino.h"
-#include "saa7191.h"
-#include "indycam.h"
-
-/* Uncomment the following line to get lots and lots of (mostly useless)
- * debug info.
- * Note that the debug output also slows down the driver significantly */
-// #define VINO_DEBUG
-// #define VINO_DEBUG_INT
-
-#define VINO_MODULE_VERSION "0.0.7"
-
-MODULE_DESCRIPTION("SGI VINO Video4Linux2 driver");
-MODULE_VERSION(VINO_MODULE_VERSION);
-MODULE_AUTHOR("Mikael Nousiainen <tmnousia@cc.hut.fi>");
-MODULE_LICENSE("GPL");
-
-#ifdef VINO_DEBUG
-#define dprintk(x...) printk("VINO: " x);
-#else
-#define dprintk(x...)
-#endif
-
-#define VINO_NO_CHANNEL 0
-#define VINO_CHANNEL_A 1
-#define VINO_CHANNEL_B 2
-
-#define VINO_PAL_WIDTH 768
-#define VINO_PAL_HEIGHT 576
-#define VINO_NTSC_WIDTH 640
-#define VINO_NTSC_HEIGHT 480
-
-#define VINO_MIN_WIDTH 32
-#define VINO_MIN_HEIGHT 32
-
-#define VINO_CLIPPING_START_ODD_D1 1
-#define VINO_CLIPPING_START_ODD_PAL 15
-#define VINO_CLIPPING_START_ODD_NTSC 12
-
-#define VINO_CLIPPING_START_EVEN_D1 2
-#define VINO_CLIPPING_START_EVEN_PAL 15
-#define VINO_CLIPPING_START_EVEN_NTSC 12
-
-#define VINO_INPUT_CHANNEL_COUNT 3
-
-/* the number is the index for vino_inputs */
-#define VINO_INPUT_NONE -1
-#define VINO_INPUT_COMPOSITE 0
-#define VINO_INPUT_SVIDEO 1
-#define VINO_INPUT_D1 2
-
-#define VINO_PAGE_RATIO (PAGE_SIZE / VINO_PAGE_SIZE)
-
-#define VINO_FIFO_THRESHOLD_DEFAULT 16
-
-#define VINO_FRAMEBUFFER_SIZE ((VINO_PAL_WIDTH \
- * VINO_PAL_HEIGHT * 4 \
- + 3 * PAGE_SIZE) & ~(PAGE_SIZE - 1))
-
-#define VINO_FRAMEBUFFER_COUNT_MAX 8
-
-#define VINO_FRAMEBUFFER_UNUSED 0
-#define VINO_FRAMEBUFFER_IN_USE 1
-#define VINO_FRAMEBUFFER_READY 2
-
-#define VINO_QUEUE_ERROR -1
-#define VINO_QUEUE_MAGIC 0x20050125
-
-#define VINO_MEMORY_NONE 0
-#define VINO_MEMORY_MMAP 1
-#define VINO_MEMORY_USERPTR 2
-
-#define VINO_DUMMY_DESC_COUNT 4
-#define VINO_DESC_FETCH_DELAY 5 /* microseconds */
-
-#define VINO_MAX_FRAME_SKIP_COUNT 128
-
-/* the number is the index for vino_data_formats */
-#define VINO_DATA_FMT_NONE -1
-#define VINO_DATA_FMT_GREY 0
-#define VINO_DATA_FMT_RGB332 1
-#define VINO_DATA_FMT_RGB32 2
-#define VINO_DATA_FMT_YUV 3
-
-#define VINO_DATA_FMT_COUNT 4
-
-/* the number is the index for vino_data_norms */
-#define VINO_DATA_NORM_NONE -1
-#define VINO_DATA_NORM_NTSC 0
-#define VINO_DATA_NORM_PAL 1
-#define VINO_DATA_NORM_SECAM 2
-#define VINO_DATA_NORM_D1 3
-
-#define VINO_DATA_NORM_COUNT 4
-
-/* I2C controller flags */
-#define SGI_I2C_FORCE_IDLE (0 << 0)
-#define SGI_I2C_NOT_IDLE (1 << 0)
-#define SGI_I2C_WRITE (0 << 1)
-#define SGI_I2C_READ (1 << 1)
-#define SGI_I2C_RELEASE_BUS (0 << 2)
-#define SGI_I2C_HOLD_BUS (1 << 2)
-#define SGI_I2C_XFER_DONE (0 << 4)
-#define SGI_I2C_XFER_BUSY (1 << 4)
-#define SGI_I2C_ACK (0 << 5)
-#define SGI_I2C_NACK (1 << 5)
-#define SGI_I2C_BUS_OK (0 << 7)
-#define SGI_I2C_BUS_ERR (1 << 7)
-
-/* Internal data structure definitions */
-
-struct vino_input {
- char *name;
- v4l2_std_id std;
-};
-
-struct vino_clipping {
- unsigned int left, right, top, bottom;
-};
-
-struct vino_data_format {
- /* the description */
- char *description;
- /* bytes per pixel */
- unsigned int bpp;
- /* V4L2 fourcc code */
- __u32 pixelformat;
- /* V4L2 colorspace (duh!) */
- enum v4l2_colorspace colorspace;
-};
-
-struct vino_data_norm {
- char *description;
- unsigned int width, height;
- struct vino_clipping odd;
- struct vino_clipping even;
-
- v4l2_std_id std;
- unsigned int fps_min, fps_max;
- __u32 framelines;
-};
-
-struct vino_descriptor_table {
- /* the number of PAGE_SIZE sized pages in the buffer */
- unsigned int page_count;
- /* virtual (kmalloc'd) pointers to the actual data
- * (in PAGE_SIZE chunks, used with mmap streaming) */
- unsigned long *virtual;
-
- /* cpu address for the VINO descriptor table
- * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
- unsigned long *dma_cpu;
- /* dma address for the VINO descriptor table
- * (contains DMA addresses, VINO_PAGE_SIZE chunks) */
- dma_addr_t dma;
-};
-
-struct vino_framebuffer {
- /* identifier nubmer */
- unsigned int id;
- /* the length of the whole buffer */
- unsigned int size;
- /* the length of actual data in buffer */
- unsigned int data_size;
- /* the data format */
- unsigned int data_format;
- /* the state of buffer data */
- unsigned int state;
- /* is the buffer mapped in user space? */
- unsigned int map_count;
- /* memory offset for mmap() */
- unsigned int offset;
- /* frame counter */
- unsigned int frame_counter;
- /* timestamp (written when image capture finishes) */
- struct timeval timestamp;
-
- struct vino_descriptor_table desc_table;
-
- spinlock_t state_lock;
-};
-
-struct vino_framebuffer_fifo {
- unsigned int length;
-
- unsigned int used;
- unsigned int head;
- unsigned int tail;
-
- unsigned int data[VINO_FRAMEBUFFER_COUNT_MAX];
-};
-
-struct vino_framebuffer_queue {
- unsigned int magic;
-
- /* VINO_MEMORY_NONE, VINO_MEMORY_MMAP or VINO_MEMORY_USERPTR */
- unsigned int type;
- unsigned int length;
-
- /* data field of in and out contain index numbers for buffer */
- struct vino_framebuffer_fifo in;
- struct vino_framebuffer_fifo out;
-
- struct vino_framebuffer *buffer[VINO_FRAMEBUFFER_COUNT_MAX];
-
- spinlock_t queue_lock;
- struct mutex queue_mutex;
- wait_queue_head_t frame_wait_queue;
-};
-
-struct vino_interrupt_data {
- struct timeval timestamp;
- unsigned int frame_counter;
- unsigned int skip_count;
- unsigned int skip;
-};
-
-struct vino_channel_settings {
- unsigned int channel;
-
- int input;
- unsigned int data_format;
- unsigned int data_norm;
- struct vino_clipping clipping;
- unsigned int decimation;
- unsigned int line_size;
- unsigned int alpha;
- unsigned int fps;
- unsigned int framert_reg;
-
- unsigned int fifo_threshold;
-
- struct vino_framebuffer_queue fb_queue;
-
- /* number of the current field */
- unsigned int field;
-
- /* read in progress */
- int reading;
- /* streaming is active */
- int streaming;
- /* the driver is currently processing the queue */
- int capturing;
-
- struct mutex mutex;
- spinlock_t capture_lock;
-
- unsigned int users;
-
- struct vino_interrupt_data int_data;
-
- /* V4L support */
- struct video_device *vdev;
-};
-
-struct vino_settings {
- struct v4l2_device v4l2_dev;
- struct vino_channel_settings a;
- struct vino_channel_settings b;
-
- /* the channel which owns this client:
- * VINO_NO_CHANNEL, VINO_CHANNEL_A or VINO_CHANNEL_B */
- unsigned int decoder_owner;
- struct v4l2_subdev *decoder;
- unsigned int camera_owner;
- struct v4l2_subdev *camera;
-
- /* a lock for vino register access */
- spinlock_t vino_lock;
- /* a lock for channel input changes */
- spinlock_t input_lock;
-
- unsigned long dummy_page;
- struct vino_descriptor_table dummy_desc_table;
-};
-
-/* Module parameters */
-
-/*
- * Using vino_pixel_conversion the ABGR32-format pixels supplied
- * by the VINO chip can be converted to more common formats
- * like RGBA32 (or probably RGB24 in the future). This way we
- * can give out data that can be specified correctly with
- * the V4L2-definitions.
- *
- * The pixel format is specified as RGBA32 when no conversion
- * is used.
- *
- * Note that this only affects the 32-bit bit depth.
- *
- * Use non-zero value to enable conversion.
- */
-static int vino_pixel_conversion;
-
-module_param_named(pixelconv, vino_pixel_conversion, int, 0);
-
-MODULE_PARM_DESC(pixelconv,
- "enable pixel conversion (non-zero value enables)");
-
-/* Internal data structures */
-
-static struct sgi_vino *vino;
-
-static struct vino_settings *vino_drvdata;
-
-#define camera_call(o, f, args...) \
- v4l2_subdev_call(vino_drvdata->camera, o, f, ##args)
-#define decoder_call(o, f, args...) \
- v4l2_subdev_call(vino_drvdata->decoder, o, f, ##args)
-
-static const char *vino_driver_name = "vino";
-static const char *vino_driver_description = "SGI VINO";
-static const char *vino_bus_name = "GIO64 bus";
-static const char *vino_vdev_name_a = "SGI VINO Channel A";
-static const char *vino_vdev_name_b = "SGI VINO Channel B";
-
-static void vino_capture_tasklet(unsigned long channel);
-
-DECLARE_TASKLET(vino_tasklet_a, vino_capture_tasklet, VINO_CHANNEL_A);
-DECLARE_TASKLET(vino_tasklet_b, vino_capture_tasklet, VINO_CHANNEL_B);
-
-static const struct vino_input vino_inputs[] = {
- {
- .name = "Composite",
- .std = V4L2_STD_NTSC | V4L2_STD_PAL
- | V4L2_STD_SECAM,
- }, {
- .name = "S-Video",
- .std = V4L2_STD_NTSC | V4L2_STD_PAL
- | V4L2_STD_SECAM,
- }, {
- .name = "D1/IndyCam",
- .std = V4L2_STD_NTSC,
- }
-};
-
-static const struct vino_data_format vino_data_formats[] = {
- {
- .description = "8-bit greyscale",
- .bpp = 1,
- .pixelformat = V4L2_PIX_FMT_GREY,
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
- }, {
- .description = "8-bit dithered RGB 3-3-2",
- .bpp = 1,
- .pixelformat = V4L2_PIX_FMT_RGB332,
- .colorspace = V4L2_COLORSPACE_SRGB,
- }, {
- .description = "32-bit RGB",
- .bpp = 4,
- .pixelformat = V4L2_PIX_FMT_RGB32,
- .colorspace = V4L2_COLORSPACE_SRGB,
- }, {
- .description = "YUV 4:2:2",
- .bpp = 2,
- .pixelformat = V4L2_PIX_FMT_YUYV, // XXX: swapped?
- .colorspace = V4L2_COLORSPACE_SMPTE170M,
- }
-};
-
-static const struct vino_data_norm vino_data_norms[] = {
- {
- .description = "NTSC",
- .std = V4L2_STD_NTSC,
- .fps_min = 6,
- .fps_max = 30,
- .framelines = 525,
- .width = VINO_NTSC_WIDTH,
- .height = VINO_NTSC_HEIGHT,
- .odd = {
- .top = VINO_CLIPPING_START_ODD_NTSC,
- .left = 0,
- .bottom = VINO_CLIPPING_START_ODD_NTSC
- + VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
- },
- .even = {
- .top = VINO_CLIPPING_START_EVEN_NTSC,
- .left = 0,
- .bottom = VINO_CLIPPING_START_EVEN_NTSC
- + VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
- },
- }, {
- .description = "PAL",
- .std = V4L2_STD_PAL,
- .fps_min = 5,
- .fps_max = 25,
- .framelines = 625,
- .width = VINO_PAL_WIDTH,
- .height = VINO_PAL_HEIGHT,
- .odd = {
- .top = VINO_CLIPPING_START_ODD_PAL,
- .left = 0,
- .bottom = VINO_CLIPPING_START_ODD_PAL
- + VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
- },
- .even = {
- .top = VINO_CLIPPING_START_EVEN_PAL,
- .left = 0,
- .bottom = VINO_CLIPPING_START_EVEN_PAL
- + VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
- },
- }, {
- .description = "SECAM",
- .std = V4L2_STD_SECAM,
- .fps_min = 5,
- .fps_max = 25,
- .framelines = 625,
- .width = VINO_PAL_WIDTH,
- .height = VINO_PAL_HEIGHT,
- .odd = {
- .top = VINO_CLIPPING_START_ODD_PAL,
- .left = 0,
- .bottom = VINO_CLIPPING_START_ODD_PAL
- + VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
- },
- .even = {
- .top = VINO_CLIPPING_START_EVEN_PAL,
- .left = 0,
- .bottom = VINO_CLIPPING_START_EVEN_PAL
- + VINO_PAL_HEIGHT / 2 - 1,
- .right = VINO_PAL_WIDTH,
- },
- }, {
- .description = "NTSC/D1",
- .std = V4L2_STD_NTSC,
- .fps_min = 6,
- .fps_max = 30,
- .framelines = 525,
- .width = VINO_NTSC_WIDTH,
- .height = VINO_NTSC_HEIGHT,
- .odd = {
- .top = VINO_CLIPPING_START_ODD_D1,
- .left = 0,
- .bottom = VINO_CLIPPING_START_ODD_D1
- + VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
- },
- .even = {
- .top = VINO_CLIPPING_START_EVEN_D1,
- .left = 0,
- .bottom = VINO_CLIPPING_START_EVEN_D1
- + VINO_NTSC_HEIGHT / 2 - 1,
- .right = VINO_NTSC_WIDTH,
- },
- }
-};
-
-#define VINO_INDYCAM_V4L2_CONTROL_COUNT 9
-
-struct v4l2_queryctrl vino_indycam_v4l2_controls[] = {
- {
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Automatic Gain Control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = INDYCAM_AGC_DEFAULT,
- }, {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Automatic White Balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = INDYCAM_AWB_DEFAULT,
- }, {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = INDYCAM_GAIN_MIN,
- .maximum = INDYCAM_GAIN_MAX,
- .step = 1,
- .default_value = INDYCAM_GAIN_DEFAULT,
- }, {
- .id = INDYCAM_CONTROL_RED_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Saturation",
- .minimum = INDYCAM_RED_SATURATION_MIN,
- .maximum = INDYCAM_RED_SATURATION_MAX,
- .step = 1,
- .default_value = INDYCAM_RED_SATURATION_DEFAULT,
- }, {
- .id = INDYCAM_CONTROL_BLUE_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Saturation",
- .minimum = INDYCAM_BLUE_SATURATION_MIN,
- .maximum = INDYCAM_BLUE_SATURATION_MAX,
- .step = 1,
- .default_value = INDYCAM_BLUE_SATURATION_DEFAULT,
- }, {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = INDYCAM_RED_BALANCE_MIN,
- .maximum = INDYCAM_RED_BALANCE_MAX,
- .step = 1,
- .default_value = INDYCAM_RED_BALANCE_DEFAULT,
- }, {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = INDYCAM_BLUE_BALANCE_MIN,
- .maximum = INDYCAM_BLUE_BALANCE_MAX,
- .step = 1,
- .default_value = INDYCAM_BLUE_BALANCE_DEFAULT,
- }, {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Shutter Control",
- .minimum = INDYCAM_SHUTTER_MIN,
- .maximum = INDYCAM_SHUTTER_MAX,
- .step = 1,
- .default_value = INDYCAM_SHUTTER_DEFAULT,
- }, {
- .id = V4L2_CID_GAMMA,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gamma",
- .minimum = INDYCAM_GAMMA_MIN,
- .maximum = INDYCAM_GAMMA_MAX,
- .step = 1,
- .default_value = INDYCAM_GAMMA_DEFAULT,
- }
-};
-
-#define VINO_SAA7191_V4L2_CONTROL_COUNT 9
-
-struct v4l2_queryctrl vino_saa7191_v4l2_controls[] = {
- {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = SAA7191_HUE_MIN,
- .maximum = SAA7191_HUE_MAX,
- .step = 1,
- .default_value = SAA7191_HUE_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_BANDPASS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Luminance Bandpass",
- .minimum = SAA7191_BANDPASS_MIN,
- .maximum = SAA7191_BANDPASS_MAX,
- .step = 1,
- .default_value = SAA7191_BANDPASS_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_BANDPASS_WEIGHT,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Luminance Bandpass Weight",
- .minimum = SAA7191_BANDPASS_WEIGHT_MIN,
- .maximum = SAA7191_BANDPASS_WEIGHT_MAX,
- .step = 1,
- .default_value = SAA7191_BANDPASS_WEIGHT_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_CORING,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "HF Luminance Coring",
- .minimum = SAA7191_CORING_MIN,
- .maximum = SAA7191_CORING_MAX,
- .step = 1,
- .default_value = SAA7191_CORING_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_FORCE_COLOUR,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Force Colour",
- .minimum = SAA7191_FORCE_COLOUR_MIN,
- .maximum = SAA7191_FORCE_COLOUR_MAX,
- .step = 1,
- .default_value = SAA7191_FORCE_COLOUR_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_CHROMA_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Chrominance Gain Control",
- .minimum = SAA7191_CHROMA_GAIN_MIN,
- .maximum = SAA7191_CHROMA_GAIN_MAX,
- .step = 1,
- .default_value = SAA7191_CHROMA_GAIN_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_VTRC,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "VTR Time Constant",
- .minimum = SAA7191_VTRC_MIN,
- .maximum = SAA7191_VTRC_MAX,
- .step = 1,
- .default_value = SAA7191_VTRC_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_LUMA_DELAY,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Luminance Delay Compensation",
- .minimum = SAA7191_LUMA_DELAY_MIN,
- .maximum = SAA7191_LUMA_DELAY_MAX,
- .step = 1,
- .default_value = SAA7191_LUMA_DELAY_DEFAULT,
- }, {
- .id = SAA7191_CONTROL_VNR,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Vertical Noise Reduction",
- .minimum = SAA7191_VNR_MIN,
- .maximum = SAA7191_VNR_MAX,
- .step = 1,
- .default_value = SAA7191_VNR_DEFAULT,
- }
-};
-
-/* VINO framebuffer/DMA descriptor management */
-
-static void vino_free_buffer_with_count(struct vino_framebuffer *fb,
- unsigned int count)
-{
- unsigned int i;
-
- dprintk("vino_free_buffer_with_count(): count = %d\n", count);
-
- for (i = 0; i < count; i++) {
- ClearPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
- dma_unmap_single(NULL,
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
- PAGE_SIZE, DMA_FROM_DEVICE);
- free_page(fb->desc_table.virtual[i]);
- }
-
- dma_free_coherent(NULL,
- VINO_PAGE_RATIO * (fb->desc_table.page_count + 4) *
- sizeof(dma_addr_t), (void *)fb->desc_table.dma_cpu,
- fb->desc_table.dma);
- kfree(fb->desc_table.virtual);
-
- memset(fb, 0, sizeof(struct vino_framebuffer));
-}
-
-static void vino_free_buffer(struct vino_framebuffer *fb)
-{
- vino_free_buffer_with_count(fb, fb->desc_table.page_count);
-}
-
-static int vino_allocate_buffer(struct vino_framebuffer *fb,
- unsigned int size)
-{
- unsigned int count, i, j;
- int ret = 0;
-
- dprintk("vino_allocate_buffer():\n");
-
- if (size < 1)
- return -EINVAL;
-
- memset(fb, 0, sizeof(struct vino_framebuffer));
-
- count = ((size / PAGE_SIZE) + 4) & ~3;
-
- dprintk("vino_allocate_buffer(): size = %d, count = %d\n",
- size, count);
-
- /* allocate memory for table with virtual (page) addresses */
- fb->desc_table.virtual =
- kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
- if (!fb->desc_table.virtual)
- return -ENOMEM;
-
- /* allocate memory for table with dma addresses
- * (has space for four extra descriptors) */
- fb->desc_table.dma_cpu =
- dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
- sizeof(dma_addr_t), &fb->desc_table.dma,
- GFP_KERNEL | GFP_DMA);
- if (!fb->desc_table.dma_cpu) {
- ret = -ENOMEM;
- goto out_free_virtual;
- }
-
- /* allocate pages for the buffer and acquire the according
- * dma addresses */
- for (i = 0; i < count; i++) {
- dma_addr_t dma_data_addr;
-
- fb->desc_table.virtual[i] =
- get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!fb->desc_table.virtual[i]) {
- ret = -ENOBUFS;
- break;
- }
-
- dma_data_addr =
- dma_map_single(NULL,
- (void *)fb->desc_table.virtual[i],
- PAGE_SIZE, DMA_FROM_DEVICE);
-
- for (j = 0; j < VINO_PAGE_RATIO; j++) {
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
- dma_data_addr + VINO_PAGE_SIZE * j;
- }
-
- SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
- }
-
- /* page_count needs to be set anyway, because the descriptor table has
- * been allocated according to this number */
- fb->desc_table.page_count = count;
-
- if (ret) {
- /* the descriptor with index i doesn't contain
- * a valid address yet */
- vino_free_buffer_with_count(fb, i);
- return ret;
- }
-
- //fb->size = size;
- fb->size = count * PAGE_SIZE;
- fb->data_format = VINO_DATA_FMT_NONE;
-
- /* set the dma stop-bit for the last (count+1)th descriptor */
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
- return 0;
-
- out_free_virtual:
- kfree(fb->desc_table.virtual);
- return ret;
-}
-
-#if 0
-/* user buffers not fully implemented yet */
-static int vino_prepare_user_buffer(struct vino_framebuffer *fb,
- void *user,
- unsigned int size)
-{
- unsigned int count, i, j;
- int ret = 0;
-
- dprintk("vino_prepare_user_buffer():\n");
-
- if (size < 1)
- return -EINVAL;
-
- memset(fb, 0, sizeof(struct vino_framebuffer));
-
- count = ((size / PAGE_SIZE)) & ~3;
-
- dprintk("vino_prepare_user_buffer(): size = %d, count = %d\n",
- size, count);
-
- /* allocate memory for table with virtual (page) addresses */
- fb->desc_table.virtual = (unsigned long *)
- kmalloc(count * sizeof(unsigned long), GFP_KERNEL);
- if (!fb->desc_table.virtual)
- return -ENOMEM;
-
- /* allocate memory for table with dma addresses
- * (has space for four extra descriptors) */
- fb->desc_table.dma_cpu =
- dma_alloc_coherent(NULL, VINO_PAGE_RATIO * (count + 4) *
- sizeof(dma_addr_t), &fb->desc_table.dma,
- GFP_KERNEL | GFP_DMA);
- if (!fb->desc_table.dma_cpu) {
- ret = -ENOMEM;
- goto out_free_virtual;
- }
-
- /* allocate pages for the buffer and acquire the according
- * dma addresses */
- for (i = 0; i < count; i++) {
- dma_addr_t dma_data_addr;
-
- fb->desc_table.virtual[i] =
- get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!fb->desc_table.virtual[i]) {
- ret = -ENOBUFS;
- break;
- }
-
- dma_data_addr =
- dma_map_single(NULL,
- (void *)fb->desc_table.virtual[i],
- PAGE_SIZE, DMA_FROM_DEVICE);
-
- for (j = 0; j < VINO_PAGE_RATIO; j++) {
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i + j] =
- dma_data_addr + VINO_PAGE_SIZE * j;
- }
-
- SetPageReserved(virt_to_page((void *)fb->desc_table.virtual[i]));
- }
-
- /* page_count needs to be set anyway, because the descriptor table has
- * been allocated according to this number */
- fb->desc_table.page_count = count;
-
- if (ret) {
- /* the descriptor with index i doesn't contain
- * a valid address yet */
- vino_free_buffer_with_count(fb, i);
- return ret;
- }
-
- //fb->size = size;
- fb->size = count * PAGE_SIZE;
-
- /* set the dma stop-bit for the last (count+1)th descriptor */
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * count] = VINO_DESC_STOP;
- return 0;
-
- out_free_virtual:
- kfree(fb->desc_table.virtual);
- return ret;
-}
-#endif
-
-static void vino_sync_buffer(struct vino_framebuffer *fb)
-{
- int i;
-
- dprintk("vino_sync_buffer():\n");
-
- for (i = 0; i < fb->desc_table.page_count; i++)
- dma_sync_single_for_cpu(NULL,
- fb->desc_table.dma_cpu[VINO_PAGE_RATIO * i],
- PAGE_SIZE, DMA_FROM_DEVICE);
-}
-
-/* Framebuffer fifo functions (need to be locked externally) */
-
-static inline void vino_fifo_init(struct vino_framebuffer_fifo *f,
- unsigned int length)
-{
- f->length = 0;
- f->used = 0;
- f->head = 0;
- f->tail = 0;
-
- if (length > VINO_FRAMEBUFFER_COUNT_MAX)
- length = VINO_FRAMEBUFFER_COUNT_MAX;
-
- f->length = length;
-}
-
-/* returns true/false */
-static inline int vino_fifo_has_id(struct vino_framebuffer_fifo *f,
- unsigned int id)
-{
- unsigned int i;
-
- for (i = f->head; i == (f->tail - 1); i = (i + 1) % f->length) {
- if (f->data[i] == id)
- return 1;
- }
-
- return 0;
-}
-
-#if 0
-/* returns true/false */
-static inline int vino_fifo_full(struct vino_framebuffer_fifo *f)
-{
- return (f->used == f->length);
-}
-#endif
-
-static inline unsigned int vino_fifo_get_used(struct vino_framebuffer_fifo *f)
-{
- return f->used;
-}
-
-static int vino_fifo_enqueue(struct vino_framebuffer_fifo *f, unsigned int id)
-{
- if (id >= f->length) {
- return VINO_QUEUE_ERROR;
- }
-
- if (vino_fifo_has_id(f, id)) {
- return VINO_QUEUE_ERROR;
- }
-
- if (f->used < f->length) {
- f->data[f->tail] = id;
- f->tail = (f->tail + 1) % f->length;
- f->used++;
- } else {
- return VINO_QUEUE_ERROR;
- }
-
- return 0;
-}
-
-static int vino_fifo_peek(struct vino_framebuffer_fifo *f, unsigned int *id)
-{
- if (f->used > 0) {
- *id = f->data[f->head];
- } else {
- return VINO_QUEUE_ERROR;
- }
-
- return 0;
-}
-
-static int vino_fifo_dequeue(struct vino_framebuffer_fifo *f, unsigned int *id)
-{
- if (f->used > 0) {
- *id = f->data[f->head];
- f->head = (f->head + 1) % f->length;
- f->used--;
- } else {
- return VINO_QUEUE_ERROR;
- }
-
- return 0;
-}
-
-/* Framebuffer queue functions */
-
-/* execute with queue_lock locked */
-static void vino_queue_free_with_count(struct vino_framebuffer_queue *q,
- unsigned int length)
-{
- unsigned int i;
-
- q->length = 0;
- memset(&q->in, 0, sizeof(struct vino_framebuffer_fifo));
- memset(&q->out, 0, sizeof(struct vino_framebuffer_fifo));
- for (i = 0; i < length; i++) {
- dprintk("vino_queue_free_with_count(): freeing buffer %d\n",
- i);
- vino_free_buffer(q->buffer[i]);
- kfree(q->buffer[i]);
- }
-
- q->type = VINO_MEMORY_NONE;
- q->magic = 0;
-}
-
-static void vino_queue_free(struct vino_framebuffer_queue *q)
-{
- dprintk("vino_queue_free():\n");
-
- if (q->magic != VINO_QUEUE_MAGIC)
- return;
- if (q->type != VINO_MEMORY_MMAP)
- return;
-
- mutex_lock(&q->queue_mutex);
-
- vino_queue_free_with_count(q, q->length);
-
- mutex_unlock(&q->queue_mutex);
-}
-
-static int vino_queue_init(struct vino_framebuffer_queue *q,
- unsigned int *length)
-{
- unsigned int i;
- int ret = 0;
-
- dprintk("vino_queue_init(): length = %d\n", *length);
-
- if (q->magic == VINO_QUEUE_MAGIC) {
- dprintk("vino_queue_init(): queue already initialized!\n");
- return -EINVAL;
- }
-
- if (q->type != VINO_MEMORY_NONE) {
- dprintk("vino_queue_init(): queue already initialized!\n");
- return -EINVAL;
- }
-
- if (*length < 1)
- return -EINVAL;
-
- mutex_lock(&q->queue_mutex);
-
- if (*length > VINO_FRAMEBUFFER_COUNT_MAX)
- *length = VINO_FRAMEBUFFER_COUNT_MAX;
-
- q->length = 0;
-
- for (i = 0; i < *length; i++) {
- dprintk("vino_queue_init(): allocating buffer %d\n", i);
- q->buffer[i] = kmalloc(sizeof(struct vino_framebuffer),
- GFP_KERNEL);
- if (!q->buffer[i]) {
- dprintk("vino_queue_init(): kmalloc() failed\n");
- ret = -ENOMEM;
- break;
- }
-
- ret = vino_allocate_buffer(q->buffer[i],
- VINO_FRAMEBUFFER_SIZE);
- if (ret) {
- kfree(q->buffer[i]);
- dprintk("vino_queue_init(): "
- "vino_allocate_buffer() failed\n");
- break;
- }
-
- q->buffer[i]->id = i;
- if (i > 0) {
- q->buffer[i]->offset = q->buffer[i - 1]->offset +
- q->buffer[i - 1]->size;
- } else {
- q->buffer[i]->offset = 0;
- }
-
- spin_lock_init(&q->buffer[i]->state_lock);
-
- dprintk("vino_queue_init(): buffer = %d, offset = %d, "
- "size = %d\n", i, q->buffer[i]->offset,
- q->buffer[i]->size);
- }
-
- if (ret) {
- vino_queue_free_with_count(q, i);
- *length = 0;
- } else {
- q->length = *length;
- vino_fifo_init(&q->in, q->length);
- vino_fifo_init(&q->out, q->length);
- q->type = VINO_MEMORY_MMAP;
- q->magic = VINO_QUEUE_MAGIC;
- }
-
- mutex_unlock(&q->queue_mutex);
-
- return ret;
-}
-
-static struct vino_framebuffer *vino_queue_add(struct
- vino_framebuffer_queue *q,
- unsigned int id)
-{
- struct vino_framebuffer *ret = NULL;
- unsigned int total;
- unsigned long flags;
-
- dprintk("vino_queue_add(): id = %d\n", id);
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- if (id >= q->length)
- goto out;
-
- /* not needed?: if (vino_fifo_full(&q->out)) {
- goto out;
- }*/
- /* check that outgoing queue isn't already full
- * (or that it won't become full) */
- total = vino_fifo_get_used(&q->in) +
- vino_fifo_get_used(&q->out);
- if (total >= q->length)
- goto out;
-
- if (vino_fifo_enqueue(&q->in, id))
- goto out;
-
- ret = q->buffer[id];
-
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-static struct vino_framebuffer *vino_queue_transfer(struct
- vino_framebuffer_queue *q)
-{
- struct vino_framebuffer *ret = NULL;
- struct vino_framebuffer *fb;
- int id;
- unsigned long flags;
-
- dprintk("vino_queue_transfer():\n");
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- // now this actually removes an entry from the incoming queue
- if (vino_fifo_dequeue(&q->in, &id)) {
- goto out;
- }
-
- dprintk("vino_queue_transfer(): id = %d\n", id);
- fb = q->buffer[id];
-
- // we have already checked that the outgoing queue is not full, but...
- if (vino_fifo_enqueue(&q->out, id)) {
- printk(KERN_ERR "vino_queue_transfer(): "
- "outgoing queue is full, this shouldn't happen!\n");
- goto out;
- }
-
- ret = fb;
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-/* returns true/false */
-static int vino_queue_incoming_contains(struct vino_framebuffer_queue *q,
- unsigned int id)
-{
- int ret = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- ret = vino_fifo_has_id(&q->in, id);
-
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-/* returns true/false */
-static int vino_queue_outgoing_contains(struct vino_framebuffer_queue *q,
- unsigned int id)
-{
- int ret = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- ret = vino_fifo_has_id(&q->out, id);
-
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-static int vino_queue_get_incoming(struct vino_framebuffer_queue *q,
- unsigned int *used)
-{
- int ret = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return VINO_QUEUE_ERROR;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0) {
- ret = VINO_QUEUE_ERROR;
- goto out;
- }
-
- *used = vino_fifo_get_used(&q->in);
-
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-static int vino_queue_get_outgoing(struct vino_framebuffer_queue *q,
- unsigned int *used)
-{
- int ret = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return VINO_QUEUE_ERROR;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0) {
- ret = VINO_QUEUE_ERROR;
- goto out;
- }
-
- *used = vino_fifo_get_used(&q->out);
-
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-#if 0
-static int vino_queue_get_total(struct vino_framebuffer_queue *q,
- unsigned int *total)
-{
- int ret = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return VINO_QUEUE_ERROR;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0) {
- ret = VINO_QUEUE_ERROR;
- goto out;
- }
-
- *total = vino_fifo_get_used(&q->in) +
- vino_fifo_get_used(&q->out);
-
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-#endif
-
-static struct vino_framebuffer *vino_queue_peek(struct
- vino_framebuffer_queue *q,
- unsigned int *id)
-{
- struct vino_framebuffer *ret = NULL;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- if (vino_fifo_peek(&q->in, id)) {
- goto out;
- }
-
- ret = q->buffer[*id];
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-static struct vino_framebuffer *vino_queue_remove(struct
- vino_framebuffer_queue *q,
- unsigned int *id)
-{
- struct vino_framebuffer *ret = NULL;
- unsigned long flags;
- dprintk("vino_queue_remove():\n");
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- if (vino_fifo_dequeue(&q->out, id)) {
- goto out;
- }
-
- dprintk("vino_queue_remove(): id = %d\n", *id);
- ret = q->buffer[*id];
-out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-static struct
-vino_framebuffer *vino_queue_get_buffer(struct vino_framebuffer_queue *q,
- unsigned int id)
-{
- struct vino_framebuffer *ret = NULL;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
-
- if (q->length == 0)
- goto out;
-
- if (id >= q->length)
- goto out;
-
- ret = q->buffer[id];
- out:
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-static unsigned int vino_queue_get_length(struct vino_framebuffer_queue *q)
-{
- unsigned int length = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return length;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
- length = q->length;
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return length;
-}
-
-static int vino_queue_has_mapped_buffers(struct vino_framebuffer_queue *q)
-{
- unsigned int i;
- int ret = 0;
- unsigned long flags;
-
- if (q->magic != VINO_QUEUE_MAGIC) {
- return ret;
- }
-
- spin_lock_irqsave(&q->queue_lock, flags);
- for (i = 0; i < q->length; i++) {
- if (q->buffer[i]->map_count > 0) {
- ret = 1;
- break;
- }
- }
- spin_unlock_irqrestore(&q->queue_lock, flags);
-
- return ret;
-}
-
-/* VINO functions */
-
-/* execute with input_lock locked */
-static void vino_update_line_size(struct vino_channel_settings *vcs)
-{
- unsigned int w = vcs->clipping.right - vcs->clipping.left;
- unsigned int d = vcs->decimation;
- unsigned int bpp = vino_data_formats[vcs->data_format].bpp;
- unsigned int lsize;
-
- dprintk("update_line_size(): before: w = %d, d = %d, "
- "line_size = %d\n", w, d, vcs->line_size);
-
- /* line size must be multiple of 8 bytes */
- lsize = (bpp * (w / d)) & ~7;
- w = (lsize / bpp) * d;
-
- vcs->clipping.right = vcs->clipping.left + w;
- vcs->line_size = lsize;
-
- dprintk("update_line_size(): after: w = %d, d = %d, "
- "line_size = %d\n", w, d, vcs->line_size);
-}
-
-/* execute with input_lock locked */
-static void vino_set_clipping(struct vino_channel_settings *vcs,
- unsigned int x, unsigned int y,
- unsigned int w, unsigned int h)
-{
- unsigned int maxwidth, maxheight;
- unsigned int d;
-
- maxwidth = vino_data_norms[vcs->data_norm].width;
- maxheight = vino_data_norms[vcs->data_norm].height;
- d = vcs->decimation;
-
- y &= ~1; /* odd/even fields */
-
- if (x > maxwidth) {
- x = 0;
- }
- if (y > maxheight) {
- y = 0;
- }
-
- if (((w / d) < VINO_MIN_WIDTH)
- || ((h / d) < VINO_MIN_HEIGHT)) {
- w = VINO_MIN_WIDTH * d;
- h = VINO_MIN_HEIGHT * d;
- }
-
- if ((x + w) > maxwidth) {
- w = maxwidth - x;
- if ((w / d) < VINO_MIN_WIDTH)
- x = maxwidth - VINO_MIN_WIDTH * d;
- }
- if ((y + h) > maxheight) {
- h = maxheight - y;
- if ((h / d) < VINO_MIN_HEIGHT)
- y = maxheight - VINO_MIN_HEIGHT * d;
- }
-
- vcs->clipping.left = x;
- vcs->clipping.top = y;
- vcs->clipping.right = x + w;
- vcs->clipping.bottom = y + h;
-
- vino_update_line_size(vcs);
-
- dprintk("clipping %d, %d, %d, %d / %d - %d\n",
- vcs->clipping.left, vcs->clipping.top, vcs->clipping.right,
- vcs->clipping.bottom, vcs->decimation, vcs->line_size);
-}
-
-/* execute with input_lock locked */
-static inline void vino_set_default_clipping(struct vino_channel_settings *vcs)
-{
- vino_set_clipping(vcs, 0, 0, vino_data_norms[vcs->data_norm].width,
- vino_data_norms[vcs->data_norm].height);
-}
-
-/* execute with input_lock locked */
-static void vino_set_scaling(struct vino_channel_settings *vcs,
- unsigned int w, unsigned int h)
-{
- unsigned int x, y, curw, curh, d;
-
- x = vcs->clipping.left;
- y = vcs->clipping.top;
- curw = vcs->clipping.right - vcs->clipping.left;
- curh = vcs->clipping.bottom - vcs->clipping.top;
-
- d = max(curw / w, curh / h);
-
- dprintk("scaling w: %d, h: %d, curw: %d, curh: %d, d: %d\n",
- w, h, curw, curh, d);
-
- if (d < 1) {
- d = 1;
- } else if (d > 8) {
- d = 8;
- }
-
- vcs->decimation = d;
- vino_set_clipping(vcs, x, y, w * d, h * d);
-
- dprintk("scaling %d, %d, %d, %d / %d - %d\n", vcs->clipping.left,
- vcs->clipping.top, vcs->clipping.right, vcs->clipping.bottom,
- vcs->decimation, vcs->line_size);
-}
-
-/* execute with input_lock locked */
-static inline void vino_set_default_scaling(struct vino_channel_settings *vcs)
-{
- vino_set_scaling(vcs, vcs->clipping.right - vcs->clipping.left,
- vcs->clipping.bottom - vcs->clipping.top);
-}
-
-/* execute with input_lock locked */
-static void vino_set_framerate(struct vino_channel_settings *vcs,
- unsigned int fps)
-{
- unsigned int mask;
-
- switch (vcs->data_norm) {
- case VINO_DATA_NORM_NTSC:
- case VINO_DATA_NORM_D1:
- fps = (unsigned int)(fps / 6) * 6; // FIXME: round!
-
- if (fps < vino_data_norms[vcs->data_norm].fps_min)
- fps = vino_data_norms[vcs->data_norm].fps_min;
- if (fps > vino_data_norms[vcs->data_norm].fps_max)
- fps = vino_data_norms[vcs->data_norm].fps_max;
-
- switch (fps) {
- case 6:
- mask = 0x003;
- break;
- case 12:
- mask = 0x0c3;
- break;
- case 18:
- mask = 0x333;
- break;
- case 24:
- mask = 0x3ff;
- break;
- case 30:
- mask = 0xfff;
- break;
- default:
- mask = VINO_FRAMERT_FULL;
- }
- vcs->framert_reg = VINO_FRAMERT_RT(mask);
- break;
- case VINO_DATA_NORM_PAL:
- case VINO_DATA_NORM_SECAM:
- fps = (unsigned int)(fps / 5) * 5; // FIXME: round!
-
- if (fps < vino_data_norms[vcs->data_norm].fps_min)
- fps = vino_data_norms[vcs->data_norm].fps_min;
- if (fps > vino_data_norms[vcs->data_norm].fps_max)
- fps = vino_data_norms[vcs->data_norm].fps_max;
-
- switch (fps) {
- case 5:
- mask = 0x003;
- break;
- case 10:
- mask = 0x0c3;
- break;
- case 15:
- mask = 0x333;
- break;
- case 20:
- mask = 0x0ff;
- break;
- case 25:
- mask = 0x3ff;
- break;
- default:
- mask = VINO_FRAMERT_FULL;
- }
- vcs->framert_reg = VINO_FRAMERT_RT(mask) | VINO_FRAMERT_PAL;
- break;
- }
-
- vcs->fps = fps;
-}
-
-/* execute with input_lock locked */
-static inline void vino_set_default_framerate(struct
- vino_channel_settings *vcs)
-{
- vino_set_framerate(vcs, vino_data_norms[vcs->data_norm].fps_max);
-}
-
-/* VINO I2C bus functions */
-
-struct i2c_algo_sgi_data {
- void *data; /* private data for lowlevel routines */
- unsigned (*getctrl)(void *data);
- void (*setctrl)(void *data, unsigned val);
- unsigned (*rdata)(void *data);
- void (*wdata)(void *data, unsigned val);
-
- int xfer_timeout;
- int ack_timeout;
-};
-
-static int wait_xfer_done(struct i2c_algo_sgi_data *adap)
-{
- int i;
-
- for (i = 0; i < adap->xfer_timeout; i++) {
- if ((adap->getctrl(adap->data) & SGI_I2C_XFER_BUSY) == 0)
- return 0;
- udelay(1);
- }
-
- return -ETIMEDOUT;
-}
-
-static int wait_ack(struct i2c_algo_sgi_data *adap)
-{
- int i;
-
- if (wait_xfer_done(adap))
- return -ETIMEDOUT;
- for (i = 0; i < adap->ack_timeout; i++) {
- if ((adap->getctrl(adap->data) & SGI_I2C_NACK) == 0)
- return 0;
- udelay(1);
- }
-
- return -ETIMEDOUT;
-}
-
-static int force_idle(struct i2c_algo_sgi_data *adap)
-{
- int i;
-
- adap->setctrl(adap->data, SGI_I2C_FORCE_IDLE);
- for (i = 0; i < adap->xfer_timeout; i++) {
- if ((adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE) == 0)
- goto out;
- udelay(1);
- }
- return -ETIMEDOUT;
-out:
- if (adap->getctrl(adap->data) & SGI_I2C_BUS_ERR)
- return -EIO;
- return 0;
-}
-
-static int do_address(struct i2c_algo_sgi_data *adap, unsigned int addr,
- int rd)
-{
- if (rd)
- adap->setctrl(adap->data, SGI_I2C_NOT_IDLE);
- /* Check if bus is idle, eventually force it to do so */
- if (adap->getctrl(adap->data) & SGI_I2C_NOT_IDLE)
- if (force_idle(adap))
- return -EIO;
- /* Write out the i2c chip address and specify operation */
- adap->setctrl(adap->data,
- SGI_I2C_HOLD_BUS | SGI_I2C_WRITE | SGI_I2C_NOT_IDLE);
- if (rd)
- addr |= 1;
- adap->wdata(adap->data, addr);
- if (wait_ack(adap))
- return -EIO;
- return 0;
-}
-
-static int i2c_read(struct i2c_algo_sgi_data *adap, unsigned char *buf,
- unsigned int len)
-{
- int i;
-
- adap->setctrl(adap->data,
- SGI_I2C_HOLD_BUS | SGI_I2C_READ | SGI_I2C_NOT_IDLE);
- for (i = 0; i < len; i++) {
- if (wait_xfer_done(adap))
- return -EIO;
- buf[i] = adap->rdata(adap->data);
- }
- adap->setctrl(adap->data, SGI_I2C_RELEASE_BUS | SGI_I2C_FORCE_IDLE);
-
- return 0;
-
-}
-
-static int i2c_write(struct i2c_algo_sgi_data *adap, unsigned char *buf,
- unsigned int len)
-{
- int i;
-
- /* We are already in write state */
- for (i = 0; i < len; i++) {
- adap->wdata(adap->data, buf[i]);
- if (wait_ack(adap))
- return -EIO;
- }
- return 0;
-}
-
-static int sgi_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs,
- int num)
-{
- struct i2c_algo_sgi_data *adap = i2c_adap->algo_data;
- struct i2c_msg *p;
- int i, err = 0;
-
- for (i = 0; !err && i < num; i++) {
- p = &msgs[i];
- err = do_address(adap, p->addr, p->flags & I2C_M_RD);
- if (err || !p->len)
- continue;
- if (p->flags & I2C_M_RD)
- err = i2c_read(adap, p->buf, p->len);
- else
- err = i2c_write(adap, p->buf, p->len);
- }
-
- return (err < 0) ? err : i;
-}
-
-static u32 sgi_func(struct i2c_adapter *adap)
-{
- return I2C_FUNC_SMBUS_EMUL;
-}
-
-static const struct i2c_algorithm sgi_algo = {
- .master_xfer = sgi_xfer,
- .functionality = sgi_func,
-};
-
-static unsigned i2c_vino_getctrl(void *data)
-{
- return vino->i2c_control;
-}
-
-static void i2c_vino_setctrl(void *data, unsigned val)
-{
- vino->i2c_control = val;
-}
-
-static unsigned i2c_vino_rdata(void *data)
-{
- return vino->i2c_data;
-}
-
-static void i2c_vino_wdata(void *data, unsigned val)
-{
- vino->i2c_data = val;
-}
-
-static struct i2c_algo_sgi_data i2c_sgi_vino_data = {
- .getctrl = &i2c_vino_getctrl,
- .setctrl = &i2c_vino_setctrl,
- .rdata = &i2c_vino_rdata,
- .wdata = &i2c_vino_wdata,
- .xfer_timeout = 200,
- .ack_timeout = 1000,
-};
-
-static struct i2c_adapter vino_i2c_adapter = {
- .name = "VINO I2C bus",
- .algo = &sgi_algo,
- .algo_data = &i2c_sgi_vino_data,
- .owner = THIS_MODULE,
-};
-
-/*
- * Prepare VINO for DMA transfer...
- * (execute only with vino_lock and input_lock locked)
- */
-static int vino_dma_setup(struct vino_channel_settings *vcs,
- struct vino_framebuffer *fb)
-{
- u32 ctrl, intr;
- struct sgi_vino_channel *ch;
- const struct vino_data_norm *norm;
-
- dprintk("vino_dma_setup():\n");
-
- vcs->field = 0;
- fb->frame_counter = 0;
-
- ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
- norm = &vino_data_norms[vcs->data_norm];
-
- ch->page_index = 0;
- ch->line_count = 0;
-
- /* VINO line size register is set 8 bytes less than actual */
- ch->line_size = vcs->line_size - 8;
-
- /* let VINO know where to transfer data */
- ch->start_desc_tbl = fb->desc_table.dma;
- ch->next_4_desc = fb->desc_table.dma;
-
- /* give vino time to fetch the first four descriptors, 5 usec
- * should be more than enough time */
- udelay(VINO_DESC_FETCH_DELAY);
-
- dprintk("vino_dma_setup(): start desc = %08x, next 4 desc = %08x\n",
- ch->start_desc_tbl, ch->next_4_desc);
-
- /* set the alpha register */
- ch->alpha = vcs->alpha;
-
- /* set clipping registers */
- ch->clip_start = VINO_CLIP_ODD(norm->odd.top + vcs->clipping.top / 2) |
- VINO_CLIP_EVEN(norm->even.top +
- vcs->clipping.top / 2) |
- VINO_CLIP_X(vcs->clipping.left);
- ch->clip_end = VINO_CLIP_ODD(norm->odd.top +
- vcs->clipping.bottom / 2 - 1) |
- VINO_CLIP_EVEN(norm->even.top +
- vcs->clipping.bottom / 2 - 1) |
- VINO_CLIP_X(vcs->clipping.right);
-
- /* set the size of actual content in the buffer (DECIMATION !) */
- fb->data_size = ((vcs->clipping.right - vcs->clipping.left) /
- vcs->decimation) *
- ((vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation) *
- vino_data_formats[vcs->data_format].bpp;
-
- ch->frame_rate = vcs->framert_reg;
-
- ctrl = vino->control;
- intr = vino->intr_status;
-
- if (vcs->channel == VINO_CHANNEL_A) {
- /* All interrupt conditions for this channel was cleared
- * so clear the interrupt status register and enable
- * interrupts */
- intr &= ~VINO_INTSTAT_A;
- ctrl |= VINO_CTRL_A_INT;
-
- /* enable synchronization */
- ctrl |= VINO_CTRL_A_SYNC_ENBL;
-
- /* enable frame assembly */
- ctrl |= VINO_CTRL_A_INTERLEAVE_ENBL;
-
- /* set decimation used */
- if (vcs->decimation < 2)
- ctrl &= ~VINO_CTRL_A_DEC_ENBL;
- else {
- ctrl |= VINO_CTRL_A_DEC_ENBL;
- ctrl &= ~VINO_CTRL_A_DEC_SCALE_MASK;
- ctrl |= (vcs->decimation - 1) <<
- VINO_CTRL_A_DEC_SCALE_SHIFT;
- }
-
- /* select input interface */
- if (vcs->input == VINO_INPUT_D1)
- ctrl |= VINO_CTRL_A_SELECT;
- else
- ctrl &= ~VINO_CTRL_A_SELECT;
-
- /* palette */
- ctrl &= ~(VINO_CTRL_A_LUMA_ONLY | VINO_CTRL_A_RGB |
- VINO_CTRL_A_DITHER);
- } else {
- intr &= ~VINO_INTSTAT_B;
- ctrl |= VINO_CTRL_B_INT;
-
- ctrl |= VINO_CTRL_B_SYNC_ENBL;
- ctrl |= VINO_CTRL_B_INTERLEAVE_ENBL;
-
- if (vcs->decimation < 2)
- ctrl &= ~VINO_CTRL_B_DEC_ENBL;
- else {
- ctrl |= VINO_CTRL_B_DEC_ENBL;
- ctrl &= ~VINO_CTRL_B_DEC_SCALE_MASK;
- ctrl |= (vcs->decimation - 1) <<
- VINO_CTRL_B_DEC_SCALE_SHIFT;
-
- }
- if (vcs->input == VINO_INPUT_D1)
- ctrl |= VINO_CTRL_B_SELECT;
- else
- ctrl &= ~VINO_CTRL_B_SELECT;
-
- ctrl &= ~(VINO_CTRL_B_LUMA_ONLY | VINO_CTRL_B_RGB |
- VINO_CTRL_B_DITHER);
- }
-
- /* set palette */
- fb->data_format = vcs->data_format;
-
- switch (vcs->data_format) {
- case VINO_DATA_FMT_GREY:
- ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
- VINO_CTRL_A_LUMA_ONLY : VINO_CTRL_B_LUMA_ONLY;
- break;
- case VINO_DATA_FMT_RGB32:
- ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
- VINO_CTRL_A_RGB : VINO_CTRL_B_RGB;
- break;
- case VINO_DATA_FMT_YUV:
- /* nothing needs to be done */
- break;
- case VINO_DATA_FMT_RGB332:
- ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
- VINO_CTRL_A_RGB | VINO_CTRL_A_DITHER :
- VINO_CTRL_B_RGB | VINO_CTRL_B_DITHER;
- break;
- }
-
- vino->intr_status = intr;
- vino->control = ctrl;
-
- return 0;
-}
-
-/* (execute only with vino_lock locked) */
-static inline void vino_dma_start(struct vino_channel_settings *vcs)
-{
- u32 ctrl = vino->control;
-
- dprintk("vino_dma_start():\n");
- ctrl |= (vcs->channel == VINO_CHANNEL_A) ?
- VINO_CTRL_A_DMA_ENBL : VINO_CTRL_B_DMA_ENBL;
- vino->control = ctrl;
-}
-
-/* (execute only with vino_lock locked) */
-static inline void vino_dma_stop(struct vino_channel_settings *vcs)
-{
- u32 ctrl = vino->control;
-
- ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
- ~VINO_CTRL_A_DMA_ENBL : ~VINO_CTRL_B_DMA_ENBL;
- ctrl &= (vcs->channel == VINO_CHANNEL_A) ?
- ~VINO_CTRL_A_INT : ~VINO_CTRL_B_INT;
- vino->control = ctrl;
- dprintk("vino_dma_stop():\n");
-}
-
-/*
- * Load dummy page to descriptor registers. This prevents generating of
- * spurious interrupts. (execute only with vino_lock locked)
- */
-static void vino_clear_interrupt(struct vino_channel_settings *vcs)
-{
- struct sgi_vino_channel *ch;
-
- ch = (vcs->channel == VINO_CHANNEL_A) ? &vino->a : &vino->b;
-
- ch->page_index = 0;
- ch->line_count = 0;
-
- ch->start_desc_tbl = vino_drvdata->dummy_desc_table.dma;
- ch->next_4_desc = vino_drvdata->dummy_desc_table.dma;
-
- udelay(VINO_DESC_FETCH_DELAY);
- dprintk("channel %c clear interrupt condition\n",
- (vcs->channel == VINO_CHANNEL_A) ? 'A':'B');
-}
-
-static int vino_capture(struct vino_channel_settings *vcs,
- struct vino_framebuffer *fb)
-{
- int err = 0;
- unsigned long flags, flags2;
-
- spin_lock_irqsave(&fb->state_lock, flags);
-
- if (fb->state == VINO_FRAMEBUFFER_IN_USE)
- err = -EBUSY;
- fb->state = VINO_FRAMEBUFFER_IN_USE;
-
- spin_unlock_irqrestore(&fb->state_lock, flags);
-
- if (err)
- return err;
-
- spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
- spin_lock_irqsave(&vino_drvdata->input_lock, flags2);
-
- vino_dma_setup(vcs, fb);
- vino_dma_start(vcs);
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags2);
- spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
-
- return err;
-}
-
-static
-struct vino_framebuffer *vino_capture_enqueue(struct
- vino_channel_settings *vcs,
- unsigned int index)
-{
- struct vino_framebuffer *fb;
- unsigned long flags;
-
- dprintk("vino_capture_enqueue():\n");
-
- spin_lock_irqsave(&vcs->capture_lock, flags);
-
- fb = vino_queue_add(&vcs->fb_queue, index);
- if (fb == NULL) {
- dprintk("vino_capture_enqueue(): vino_queue_add() failed, "
- "queue full?\n");
- goto out;
- }
-out:
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-
- return fb;
-}
-
-static int vino_capture_next(struct vino_channel_settings *vcs, int start)
-{
- struct vino_framebuffer *fb;
- unsigned int incoming, id;
- int err = 0;
- unsigned long flags;
-
- dprintk("vino_capture_next():\n");
-
- spin_lock_irqsave(&vcs->capture_lock, flags);
-
- if (start) {
- /* start capture only if capture isn't in progress already */
- if (vcs->capturing) {
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
- return 0;
- }
-
- } else {
- /* capture next frame:
- * stop capture if capturing is not set */
- if (!vcs->capturing) {
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
- return 0;
- }
- }
-
- err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
- if (err) {
- dprintk("vino_capture_next(): vino_queue_get_incoming() "
- "failed\n");
- err = -EINVAL;
- goto out;
- }
- if (incoming == 0) {
- dprintk("vino_capture_next(): no buffers available\n");
- goto out;
- }
-
- fb = vino_queue_peek(&vcs->fb_queue, &id);
- if (fb == NULL) {
- dprintk("vino_capture_next(): vino_queue_peek() failed\n");
- err = -EINVAL;
- goto out;
- }
-
- if (start) {
- vcs->capturing = 1;
- }
-
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-
- err = vino_capture(vcs, fb);
-
- return err;
-
-out:
- vcs->capturing = 0;
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-
- return err;
-}
-
-static inline int vino_is_capturing(struct vino_channel_settings *vcs)
-{
- int ret;
- unsigned long flags;
-
- spin_lock_irqsave(&vcs->capture_lock, flags);
-
- ret = vcs->capturing;
-
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-
- return ret;
-}
-
-/* waits until a frame is captured */
-static int vino_wait_for_frame(struct vino_channel_settings *vcs)
-{
- wait_queue_t wait;
- int err = 0;
-
- dprintk("vino_wait_for_frame():\n");
-
- init_waitqueue_entry(&wait, current);
- /* add ourselves into wait queue */
- add_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
-
- /* to ensure that schedule_timeout will return immediately
- * if VINO interrupt was triggered meanwhile */
- schedule_timeout_interruptible(msecs_to_jiffies(100));
-
- if (signal_pending(current))
- err = -EINTR;
-
- remove_wait_queue(&vcs->fb_queue.frame_wait_queue, &wait);
-
- dprintk("vino_wait_for_frame(): waiting for frame %s\n",
- err ? "failed" : "ok");
-
- return err;
-}
-
-/* the function assumes that PAGE_SIZE % 4 == 0 */
-static void vino_convert_to_rgba(struct vino_framebuffer *fb) {
- unsigned char *pageptr;
- unsigned int page, i;
- unsigned char a;
-
- for (page = 0; page < fb->desc_table.page_count; page++) {
- pageptr = (unsigned char *)fb->desc_table.virtual[page];
-
- for (i = 0; i < PAGE_SIZE; i += 4) {
- a = pageptr[0];
- pageptr[0] = pageptr[3];
- pageptr[1] = pageptr[2];
- pageptr[2] = pageptr[1];
- pageptr[3] = a;
- pageptr += 4;
- }
- }
-}
-
-/* checks if the buffer is in correct state and syncs data */
-static int vino_check_buffer(struct vino_channel_settings *vcs,
- struct vino_framebuffer *fb)
-{
- int err = 0;
- unsigned long flags;
-
- dprintk("vino_check_buffer():\n");
-
- spin_lock_irqsave(&fb->state_lock, flags);
- switch (fb->state) {
- case VINO_FRAMEBUFFER_IN_USE:
- err = -EIO;
- break;
- case VINO_FRAMEBUFFER_READY:
- vino_sync_buffer(fb);
- fb->state = VINO_FRAMEBUFFER_UNUSED;
- break;
- default:
- err = -EINVAL;
- }
- spin_unlock_irqrestore(&fb->state_lock, flags);
-
- if (!err) {
- if (vino_pixel_conversion
- && (fb->data_format == VINO_DATA_FMT_RGB32)) {
- vino_convert_to_rgba(fb);
- }
- } else if (err && (err != -EINVAL)) {
- dprintk("vino_check_buffer(): buffer not ready\n");
-
- spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
- vino_dma_stop(vcs);
- vino_clear_interrupt(vcs);
- spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
- }
-
- return err;
-}
-
-/* forcefully terminates capture */
-static void vino_capture_stop(struct vino_channel_settings *vcs)
-{
- unsigned int incoming = 0, outgoing = 0, id;
- unsigned long flags, flags2;
-
- dprintk("vino_capture_stop():\n");
-
- spin_lock_irqsave(&vcs->capture_lock, flags);
-
- /* unset capturing to stop queue processing */
- vcs->capturing = 0;
-
- spin_lock_irqsave(&vino_drvdata->vino_lock, flags2);
-
- vino_dma_stop(vcs);
- vino_clear_interrupt(vcs);
-
- spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags2);
-
- /* remove all items from the queue */
- if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
- dprintk("vino_capture_stop(): "
- "vino_queue_get_incoming() failed\n");
- goto out;
- }
- while (incoming > 0) {
- vino_queue_transfer(&vcs->fb_queue);
-
- if (vino_queue_get_incoming(&vcs->fb_queue, &incoming)) {
- dprintk("vino_capture_stop(): "
- "vino_queue_get_incoming() failed\n");
- goto out;
- }
- }
-
- if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
- dprintk("vino_capture_stop(): "
- "vino_queue_get_outgoing() failed\n");
- goto out;
- }
- while (outgoing > 0) {
- vino_queue_remove(&vcs->fb_queue, &id);
-
- if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
- dprintk("vino_capture_stop(): "
- "vino_queue_get_outgoing() failed\n");
- goto out;
- }
- }
-
-out:
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-}
-
-#if 0
-static int vino_capture_failed(struct vino_channel_settings *vcs)
-{
- struct vino_framebuffer *fb;
- unsigned long flags;
- unsigned int i;
- int ret;
-
- dprintk("vino_capture_failed():\n");
-
- spin_lock_irqsave(&vino_drvdata->vino_lock, flags);
-
- vino_dma_stop(vcs);
- vino_clear_interrupt(vcs);
-
- spin_unlock_irqrestore(&vino_drvdata->vino_lock, flags);
-
- ret = vino_queue_get_incoming(&vcs->fb_queue, &i);
- if (ret == VINO_QUEUE_ERROR) {
- dprintk("vino_queue_get_incoming() failed\n");
- return -EINVAL;
- }
- if (i == 0) {
- /* no buffers to process */
- return 0;
- }
-
- fb = vino_queue_peek(&vcs->fb_queue, &i);
- if (fb == NULL) {
- dprintk("vino_queue_peek() failed\n");
- return -EINVAL;
- }
-
- spin_lock_irqsave(&fb->state_lock, flags);
- if (fb->state == VINO_FRAMEBUFFER_IN_USE) {
- fb->state = VINO_FRAMEBUFFER_UNUSED;
- vino_queue_transfer(&vcs->fb_queue);
- vino_queue_remove(&vcs->fb_queue, &i);
- /* we should actually discard the newest frame,
- * but who cares ... */
- }
- spin_unlock_irqrestore(&fb->state_lock, flags);
-
- return 0;
-}
-#endif
-
-static void vino_skip_frame(struct vino_channel_settings *vcs)
-{
- struct vino_framebuffer *fb;
- unsigned long flags;
- unsigned int id;
-
- spin_lock_irqsave(&vcs->capture_lock, flags);
- fb = vino_queue_peek(&vcs->fb_queue, &id);
- if (!fb) {
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
- dprintk("vino_skip_frame(): vino_queue_peek() failed!\n");
- return;
- }
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-
- spin_lock_irqsave(&fb->state_lock, flags);
- fb->state = VINO_FRAMEBUFFER_UNUSED;
- spin_unlock_irqrestore(&fb->state_lock, flags);
-
- vino_capture_next(vcs, 0);
-}
-
-static void vino_frame_done(struct vino_channel_settings *vcs)
-{
- struct vino_framebuffer *fb;
- unsigned long flags;
-
- spin_lock_irqsave(&vcs->capture_lock, flags);
- fb = vino_queue_transfer(&vcs->fb_queue);
- if (!fb) {
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
- dprintk("vino_frame_done(): vino_queue_transfer() failed!\n");
- return;
- }
- spin_unlock_irqrestore(&vcs->capture_lock, flags);
-
- fb->frame_counter = vcs->int_data.frame_counter;
- memcpy(&fb->timestamp, &vcs->int_data.timestamp,
- sizeof(struct timeval));
-
- spin_lock_irqsave(&fb->state_lock, flags);
- if (fb->state == VINO_FRAMEBUFFER_IN_USE)
- fb->state = VINO_FRAMEBUFFER_READY;
- spin_unlock_irqrestore(&fb->state_lock, flags);
-
- wake_up(&vcs->fb_queue.frame_wait_queue);
-
- vino_capture_next(vcs, 0);
-}
-
-static void vino_capture_tasklet(unsigned long channel) {
- struct vino_channel_settings *vcs;
-
- vcs = (channel == VINO_CHANNEL_A)
- ? &vino_drvdata->a : &vino_drvdata->b;
-
- if (vcs->int_data.skip)
- vcs->int_data.skip_count++;
-
- if (vcs->int_data.skip && (vcs->int_data.skip_count
- <= VINO_MAX_FRAME_SKIP_COUNT)) {
- vino_skip_frame(vcs);
- } else {
- vcs->int_data.skip_count = 0;
- vino_frame_done(vcs);
- }
-}
-
-static irqreturn_t vino_interrupt(int irq, void *dev_id)
-{
- u32 ctrl, intr;
- unsigned int fc_a, fc_b;
- int handled_a = 0, skip_a = 0, done_a = 0;
- int handled_b = 0, skip_b = 0, done_b = 0;
-
-#ifdef VINO_DEBUG_INT
- int loop = 0;
- unsigned int line_count = vino->a.line_count,
- page_index = vino->a.page_index,
- field_counter = vino->a.field_counter,
- start_desc_tbl = vino->a.start_desc_tbl,
- next_4_desc = vino->a.next_4_desc;
- unsigned int line_count_2,
- page_index_2,
- field_counter_2,
- start_desc_tbl_2,
- next_4_desc_2;
-#endif
-
- spin_lock(&vino_drvdata->vino_lock);
-
- while ((intr = vino->intr_status)) {
- fc_a = vino->a.field_counter >> 1;
- fc_b = vino->b.field_counter >> 1;
-
- /* handle error-interrupts in some special way ?
- * --> skips frames */
- if (intr & VINO_INTSTAT_A) {
- if (intr & VINO_INTSTAT_A_EOF) {
- vino_drvdata->a.field++;
- if (vino_drvdata->a.field > 1) {
- vino_dma_stop(&vino_drvdata->a);
- vino_clear_interrupt(&vino_drvdata->a);
- vino_drvdata->a.field = 0;
- done_a = 1;
- } else {
- if (vino->a.page_index
- != vino_drvdata->a.line_size) {
- vino->a.line_count = 0;
- vino->a.page_index =
- vino_drvdata->
- a.line_size;
- vino->a.next_4_desc =
- vino->a.start_desc_tbl;
- }
- }
- dprintk("channel A end-of-field "
- "interrupt: %04x\n", intr);
- } else {
- vino_dma_stop(&vino_drvdata->a);
- vino_clear_interrupt(&vino_drvdata->a);
- vino_drvdata->a.field = 0;
- skip_a = 1;
- dprintk("channel A error interrupt: %04x\n",
- intr);
- }
-
-#ifdef VINO_DEBUG_INT
- line_count_2 = vino->a.line_count;
- page_index_2 = vino->a.page_index;
- field_counter_2 = vino->a.field_counter;
- start_desc_tbl_2 = vino->a.start_desc_tbl;
- next_4_desc_2 = vino->a.next_4_desc;
-
- printk("intr = %04x, loop = %d, field = %d\n",
- intr, loop, vino_drvdata->a.field);
- printk("1- line count = %04d, page index = %04d, "
- "start = %08x, next = %08x\n"
- " fieldc = %d, framec = %d\n",
- line_count, page_index, start_desc_tbl,
- next_4_desc, field_counter, fc_a);
- printk("12-line count = %04d, page index = %04d, "
- " start = %08x, next = %08x\n",
- line_count_2, page_index_2, start_desc_tbl_2,
- next_4_desc_2);
-
- if (done_a)
- printk("\n");
-#endif
- }
-
- if (intr & VINO_INTSTAT_B) {
- if (intr & VINO_INTSTAT_B_EOF) {
- vino_drvdata->b.field++;
- if (vino_drvdata->b.field > 1) {
- vino_dma_stop(&vino_drvdata->b);
- vino_clear_interrupt(&vino_drvdata->b);
- vino_drvdata->b.field = 0;
- done_b = 1;
- }
- dprintk("channel B end-of-field "
- "interrupt: %04x\n", intr);
- } else {
- vino_dma_stop(&vino_drvdata->b);
- vino_clear_interrupt(&vino_drvdata->b);
- vino_drvdata->b.field = 0;
- skip_b = 1;
- dprintk("channel B error interrupt: %04x\n",
- intr);
- }
- }
-
- /* Always remember to clear interrupt status.
- * Disable VINO interrupts while we do this. */
- ctrl = vino->control;
- vino->control = ctrl & ~(VINO_CTRL_A_INT | VINO_CTRL_B_INT);
- vino->intr_status = ~intr;
- vino->control = ctrl;
-
- spin_unlock(&vino_drvdata->vino_lock);
-
- if ((!handled_a) && (done_a || skip_a)) {
- if (!skip_a) {
- v4l2_get_timestamp(
- &vino_drvdata->a.int_data.timestamp);
- vino_drvdata->a.int_data.frame_counter = fc_a;
- }
- vino_drvdata->a.int_data.skip = skip_a;
-
- dprintk("channel A %s, interrupt: %d\n",
- skip_a ? "skipping frame" : "frame done",
- intr);
- tasklet_hi_schedule(&vino_tasklet_a);
- handled_a = 1;
- }
-
- if ((!handled_b) && (done_b || skip_b)) {
- if (!skip_b) {
- v4l2_get_timestamp(
- &vino_drvdata->b.int_data.timestamp);
- vino_drvdata->b.int_data.frame_counter = fc_b;
- }
- vino_drvdata->b.int_data.skip = skip_b;
-
- dprintk("channel B %s, interrupt: %d\n",
- skip_b ? "skipping frame" : "frame done",
- intr);
- tasklet_hi_schedule(&vino_tasklet_b);
- handled_b = 1;
- }
-
-#ifdef VINO_DEBUG_INT
- loop++;
-#endif
- spin_lock(&vino_drvdata->vino_lock);
- }
-
- spin_unlock(&vino_drvdata->vino_lock);
-
- return IRQ_HANDLED;
-}
-
-/* VINO video input management */
-
-static int vino_get_saa7191_input(int input)
-{
- switch (input) {
- case VINO_INPUT_COMPOSITE:
- return SAA7191_INPUT_COMPOSITE;
- case VINO_INPUT_SVIDEO:
- return SAA7191_INPUT_SVIDEO;
- default:
- printk(KERN_ERR "VINO: vino_get_saa7191_input(): "
- "invalid input!\n");
- return -1;
- }
-}
-
-/* execute with input_lock locked */
-static int vino_is_input_owner(struct vino_channel_settings *vcs)
-{
- switch(vcs->input) {
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
- return vino_drvdata->decoder_owner == vcs->channel;
- case VINO_INPUT_D1:
- return vino_drvdata->camera_owner == vcs->channel;
- default:
- return 0;
- }
-}
-
-static int vino_acquire_input(struct vino_channel_settings *vcs)
-{
- unsigned long flags;
- int ret = 0;
-
- dprintk("vino_acquire_input():\n");
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- /* First try D1 and then SAA7191 */
- if (vino_drvdata->camera
- && (vino_drvdata->camera_owner == VINO_NO_CHANNEL)) {
- vino_drvdata->camera_owner = vcs->channel;
- vcs->input = VINO_INPUT_D1;
- vcs->data_norm = VINO_DATA_NORM_D1;
- } else if (vino_drvdata->decoder
- && (vino_drvdata->decoder_owner == VINO_NO_CHANNEL)) {
- int input;
- int data_norm = 0;
- v4l2_std_id norm;
-
- input = VINO_INPUT_COMPOSITE;
-
- ret = decoder_call(video, s_routing,
- vino_get_saa7191_input(input), 0, 0);
- if (ret) {
- ret = -EINVAL;
- goto out;
- }
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- /* Don't hold spinlocks while auto-detecting norm
- * as it may take a while... */
-
- ret = decoder_call(video, querystd, &norm);
- if (!ret) {
- for (data_norm = 0; data_norm < 3; data_norm++) {
- if (vino_data_norms[data_norm].std & norm)
- break;
- }
- if (data_norm == 3)
- data_norm = VINO_DATA_NORM_PAL;
- ret = decoder_call(video, s_std, norm);
- }
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if (ret) {
- ret = -EINVAL;
- goto out;
- }
-
- vino_drvdata->decoder_owner = vcs->channel;
-
- vcs->input = input;
- vcs->data_norm = data_norm;
- } else {
- vcs->input = (vcs->channel == VINO_CHANNEL_A) ?
- vino_drvdata->b.input : vino_drvdata->a.input;
- vcs->data_norm = (vcs->channel == VINO_CHANNEL_A) ?
- vino_drvdata->b.data_norm : vino_drvdata->a.data_norm;
- }
-
- if (vcs->input == VINO_INPUT_NONE) {
- ret = -ENODEV;
- goto out;
- }
-
- vino_set_default_clipping(vcs);
- vino_set_default_scaling(vcs);
- vino_set_default_framerate(vcs);
-
- dprintk("vino_acquire_input(): %s\n", vino_inputs[vcs->input].name);
-
-out:
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return ret;
-}
-
-static int vino_set_input(struct vino_channel_settings *vcs, int input)
-{
- struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
- &vino_drvdata->b : &vino_drvdata->a;
- unsigned long flags;
- int ret = 0;
-
- dprintk("vino_set_input():\n");
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if (vcs->input == input)
- goto out;
-
- switch (input) {
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
- if (!vino_drvdata->decoder) {
- ret = -EINVAL;
- goto out;
- }
-
- if (vino_drvdata->decoder_owner == VINO_NO_CHANNEL) {
- vino_drvdata->decoder_owner = vcs->channel;
- }
-
- if (vino_drvdata->decoder_owner == vcs->channel) {
- int data_norm = 0;
- v4l2_std_id norm;
-
- ret = decoder_call(video, s_routing,
- vino_get_saa7191_input(input), 0, 0);
- if (ret) {
- vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
- ret = -EINVAL;
- goto out;
- }
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- /* Don't hold spinlocks while auto-detecting norm
- * as it may take a while... */
-
- ret = decoder_call(video, querystd, &norm);
- if (!ret) {
- for (data_norm = 0; data_norm < 3; data_norm++) {
- if (vino_data_norms[data_norm].std & norm)
- break;
- }
- if (data_norm == 3)
- data_norm = VINO_DATA_NORM_PAL;
- ret = decoder_call(video, s_std, norm);
- }
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if (ret) {
- vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
- ret = -EINVAL;
- goto out;
- }
-
- vcs->input = input;
- vcs->data_norm = data_norm;
- } else {
- if (input != vcs2->input) {
- ret = -EBUSY;
- goto out;
- }
-
- vcs->input = input;
- vcs->data_norm = vcs2->data_norm;
- }
-
- if (vino_drvdata->camera_owner == vcs->channel) {
- /* Transfer the ownership or release the input */
- if (vcs2->input == VINO_INPUT_D1) {
- vino_drvdata->camera_owner = vcs2->channel;
- } else {
- vino_drvdata->camera_owner = VINO_NO_CHANNEL;
- }
- }
- break;
- case VINO_INPUT_D1:
- if (!vino_drvdata->camera) {
- ret = -EINVAL;
- goto out;
- }
-
- if (vino_drvdata->camera_owner == VINO_NO_CHANNEL)
- vino_drvdata->camera_owner = vcs->channel;
-
- if (vino_drvdata->decoder_owner == vcs->channel) {
- /* Transfer the ownership or release the input */
- if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
- (vcs2->input == VINO_INPUT_SVIDEO)) {
- vino_drvdata->decoder_owner = vcs2->channel;
- } else {
- vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
- }
- }
-
- vcs->input = input;
- vcs->data_norm = VINO_DATA_NORM_D1;
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
-
- vino_set_default_clipping(vcs);
- vino_set_default_scaling(vcs);
- vino_set_default_framerate(vcs);
-
- dprintk("vino_set_input(): %s\n", vino_inputs[vcs->input].name);
-
-out:
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return ret;
-}
-
-static void vino_release_input(struct vino_channel_settings *vcs)
-{
- struct vino_channel_settings *vcs2 = (vcs->channel == VINO_CHANNEL_A) ?
- &vino_drvdata->b : &vino_drvdata->a;
- unsigned long flags;
-
- dprintk("vino_release_input():\n");
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- /* Release ownership of the channel
- * and if the other channel takes input from
- * the same source, transfer the ownership */
- if (vino_drvdata->camera_owner == vcs->channel) {
- if (vcs2->input == VINO_INPUT_D1) {
- vino_drvdata->camera_owner = vcs2->channel;
- } else {
- vino_drvdata->camera_owner = VINO_NO_CHANNEL;
- }
- } else if (vino_drvdata->decoder_owner == vcs->channel) {
- if ((vcs2->input == VINO_INPUT_COMPOSITE) ||
- (vcs2->input == VINO_INPUT_SVIDEO)) {
- vino_drvdata->decoder_owner = vcs2->channel;
- } else {
- vino_drvdata->decoder_owner = VINO_NO_CHANNEL;
- }
- }
- vcs->input = VINO_INPUT_NONE;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-}
-
-/* execute with input_lock locked */
-static int vino_set_data_norm(struct vino_channel_settings *vcs,
- unsigned int data_norm,
- unsigned long *flags)
-{
- int err = 0;
-
- if (data_norm == vcs->data_norm)
- return 0;
-
- switch (vcs->input) {
- case VINO_INPUT_D1:
- /* only one "norm" supported */
- if (data_norm != VINO_DATA_NORM_D1)
- return -EINVAL;
- break;
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO: {
- v4l2_std_id norm;
-
- if ((data_norm != VINO_DATA_NORM_PAL)
- && (data_norm != VINO_DATA_NORM_NTSC)
- && (data_norm != VINO_DATA_NORM_SECAM))
- return -EINVAL;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, *flags);
-
- /* Don't hold spinlocks while setting norm
- * as it may take a while... */
-
- norm = vino_data_norms[data_norm].std;
- err = decoder_call(video, s_std, norm);
-
- spin_lock_irqsave(&vino_drvdata->input_lock, *flags);
-
- if (err)
- goto out;
-
- vcs->data_norm = data_norm;
-
- vino_set_default_clipping(vcs);
- vino_set_default_scaling(vcs);
- vino_set_default_framerate(vcs);
- break;
- }
- default:
- return -EINVAL;
- }
-
-out:
- return err;
-}
-
-/* V4L2 helper functions */
-
-static int vino_find_data_format(__u32 pixelformat)
-{
- int i;
-
- for (i = 0; i < VINO_DATA_FMT_COUNT; i++) {
- if (vino_data_formats[i].pixelformat == pixelformat)
- return i;
- }
-
- return VINO_DATA_FMT_NONE;
-}
-
-static int vino_int_enum_input(struct vino_channel_settings *vcs, __u32 index)
-{
- int input = VINO_INPUT_NONE;
- unsigned long flags;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- if (vino_drvdata->decoder && vino_drvdata->camera) {
- switch (index) {
- case 0:
- input = VINO_INPUT_COMPOSITE;
- break;
- case 1:
- input = VINO_INPUT_SVIDEO;
- break;
- case 2:
- input = VINO_INPUT_D1;
- break;
- }
- } else if (vino_drvdata->decoder) {
- switch (index) {
- case 0:
- input = VINO_INPUT_COMPOSITE;
- break;
- case 1:
- input = VINO_INPUT_SVIDEO;
- break;
- }
- } else if (vino_drvdata->camera) {
- switch (index) {
- case 0:
- input = VINO_INPUT_D1;
- break;
- }
- }
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return input;
-}
-
-/* execute with input_lock locked */
-static __u32 vino_find_input_index(struct vino_channel_settings *vcs)
-{
- __u32 index = 0;
- // FIXME: detect when no inputs available
-
- if (vino_drvdata->decoder && vino_drvdata->camera) {
- switch (vcs->input) {
- case VINO_INPUT_COMPOSITE:
- index = 0;
- break;
- case VINO_INPUT_SVIDEO:
- index = 1;
- break;
- case VINO_INPUT_D1:
- index = 2;
- break;
- }
- } else if (vino_drvdata->decoder) {
- switch (vcs->input) {
- case VINO_INPUT_COMPOSITE:
- index = 0;
- break;
- case VINO_INPUT_SVIDEO:
- index = 1;
- break;
- }
- } else if (vino_drvdata->camera) {
- switch (vcs->input) {
- case VINO_INPUT_D1:
- index = 0;
- break;
- }
- }
-
- return index;
-}
-
-/* V4L2 ioctls */
-
-static int vino_querycap(struct file *file, void *__fh,
- struct v4l2_capability *cap)
-{
- memset(cap, 0, sizeof(struct v4l2_capability));
-
- strcpy(cap->driver, vino_driver_name);
- strcpy(cap->card, vino_driver_description);
- strcpy(cap->bus_info, vino_bus_name);
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
- cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
- return 0;
-}
-
-static int vino_enum_input(struct file *file, void *__fh,
- struct v4l2_input *i)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- __u32 index = i->index;
- int input;
- dprintk("requested index = %d\n", index);
-
- input = vino_int_enum_input(vcs, index);
- if (input == VINO_INPUT_NONE)
- return -EINVAL;
-
- i->type = V4L2_INPUT_TYPE_CAMERA;
- i->std = vino_inputs[input].std;
- strcpy(i->name, vino_inputs[input].name);
-
- if (input == VINO_INPUT_COMPOSITE || input == VINO_INPUT_SVIDEO)
- decoder_call(video, g_input_status, &i->status);
- return 0;
-}
-
-static int vino_g_input(struct file *file, void *__fh,
- unsigned int *i)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- __u32 index;
- int input;
- unsigned long flags;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- input = vcs->input;
- index = vino_find_input_index(vcs);
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- dprintk("input = %d\n", input);
-
- if (input == VINO_INPUT_NONE) {
- return -EINVAL;
- }
-
- *i = index;
-
- return 0;
-}
-
-static int vino_s_input(struct file *file, void *__fh,
- unsigned int i)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- int input;
- dprintk("requested input = %d\n", i);
-
- input = vino_int_enum_input(vcs, i);
- if (input == VINO_INPUT_NONE)
- return -EINVAL;
-
- return vino_set_input(vcs, input);
-}
-
-static int vino_querystd(struct file *file, void *__fh,
- v4l2_std_id *std)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- int err = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- switch (vcs->input) {
- case VINO_INPUT_D1:
- *std = vino_inputs[vcs->input].std;
- break;
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO: {
- decoder_call(video, querystd, std);
- break;
- }
- default:
- err = -EINVAL;
- }
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return err;
-}
-
-static int vino_g_std(struct file *file, void *__fh,
- v4l2_std_id *std)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- *std = vino_data_norms[vcs->data_norm].std;
- dprintk("current standard = %d\n", vcs->data_norm);
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return 0;
-}
-
-static int vino_s_std(struct file *file, void *__fh,
- v4l2_std_id std)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- int ret = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if (!vino_is_input_owner(vcs)) {
- ret = -EBUSY;
- goto out;
- }
-
- /* check if the standard is valid for the current input */
- if (std & vino_inputs[vcs->input].std) {
- dprintk("standard accepted\n");
-
- /* change the video norm for SAA7191
- * and accept NTSC for D1 (do nothing) */
-
- if (vcs->input == VINO_INPUT_D1)
- goto out;
-
- if (std & V4L2_STD_PAL) {
- ret = vino_set_data_norm(vcs, VINO_DATA_NORM_PAL,
- &flags);
- } else if (std & V4L2_STD_NTSC) {
- ret = vino_set_data_norm(vcs, VINO_DATA_NORM_NTSC,
- &flags);
- } else if (std & V4L2_STD_SECAM) {
- ret = vino_set_data_norm(vcs, VINO_DATA_NORM_SECAM,
- &flags);
- } else {
- ret = -EINVAL;
- }
-
- if (ret) {
- ret = -EINVAL;
- }
- } else {
- ret = -EINVAL;
- }
-
-out:
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return ret;
-}
-
-static int vino_enum_fmt_vid_cap(struct file *file, void *__fh,
- struct v4l2_fmtdesc *fd)
-{
- dprintk("format index = %d\n", fd->index);
-
- if (fd->index >= VINO_DATA_FMT_COUNT)
- return -EINVAL;
- dprintk("format name = %s\n", vino_data_formats[fd->index].description);
-
- fd->pixelformat = vino_data_formats[fd->index].pixelformat;
- strcpy(fd->description, vino_data_formats[fd->index].description);
- return 0;
-}
-
-static int vino_try_fmt_vid_cap(struct file *file, void *__fh,
- struct v4l2_format *f)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- struct vino_channel_settings tempvcs;
- unsigned long flags;
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- dprintk("requested: w = %d, h = %d\n",
- pf->width, pf->height);
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
- memcpy(&tempvcs, vcs, sizeof(struct vino_channel_settings));
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- tempvcs.data_format = vino_find_data_format(pf->pixelformat);
- if (tempvcs.data_format == VINO_DATA_FMT_NONE) {
- tempvcs.data_format = VINO_DATA_FMT_GREY;
- pf->pixelformat =
- vino_data_formats[tempvcs.data_format].
- pixelformat;
- }
-
- /* data format must be set before clipping/scaling */
- vino_set_scaling(&tempvcs, pf->width, pf->height);
-
- dprintk("data format = %s\n",
- vino_data_formats[tempvcs.data_format].description);
-
- pf->width = (tempvcs.clipping.right - tempvcs.clipping.left) /
- tempvcs.decimation;
- pf->height = (tempvcs.clipping.bottom - tempvcs.clipping.top) /
- tempvcs.decimation;
-
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = tempvcs.line_size;
- pf->sizeimage = tempvcs.line_size *
- (tempvcs.clipping.bottom - tempvcs.clipping.top) /
- tempvcs.decimation;
- pf->colorspace =
- vino_data_formats[tempvcs.data_format].colorspace;
-
- return 0;
-}
-
-static int vino_g_fmt_vid_cap(struct file *file, void *__fh,
- struct v4l2_format *f)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- pf->width = (vcs->clipping.right - vcs->clipping.left) /
- vcs->decimation;
- pf->height = (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->pixelformat =
- vino_data_formats[vcs->data_format].pixelformat;
-
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = vcs->line_size;
- pf->sizeimage = vcs->line_size *
- (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->colorspace =
- vino_data_formats[vcs->data_format].colorspace;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- return 0;
-}
-
-static int vino_s_fmt_vid_cap(struct file *file, void *__fh,
- struct v4l2_format *f)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- int data_format;
- unsigned long flags;
- struct v4l2_pix_format *pf = &f->fmt.pix;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- data_format = vino_find_data_format(pf->pixelformat);
-
- if (data_format == VINO_DATA_FMT_NONE) {
- vcs->data_format = VINO_DATA_FMT_GREY;
- pf->pixelformat =
- vino_data_formats[vcs->data_format].
- pixelformat;
- } else {
- vcs->data_format = data_format;
- }
-
- /* data format must be set before clipping/scaling */
- vino_set_scaling(vcs, pf->width, pf->height);
-
- dprintk("data format = %s\n",
- vino_data_formats[vcs->data_format].description);
-
- pf->width = vcs->clipping.right - vcs->clipping.left;
- pf->height = vcs->clipping.bottom - vcs->clipping.top;
-
- pf->field = V4L2_FIELD_INTERLACED;
- pf->bytesperline = vcs->line_size;
- pf->sizeimage = vcs->line_size *
- (vcs->clipping.bottom - vcs->clipping.top) /
- vcs->decimation;
- pf->colorspace =
- vino_data_formats[vcs->data_format].colorspace;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- return 0;
-}
-
-static int vino_cropcap(struct file *file, void *__fh,
- struct v4l2_cropcap *ccap)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- const struct vino_data_norm *norm;
- unsigned long flags;
-
- switch (ccap->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- norm = &vino_data_norms[vcs->data_norm];
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- ccap->bounds.left = 0;
- ccap->bounds.top = 0;
- ccap->bounds.width = norm->width;
- ccap->bounds.height = norm->height;
- memcpy(&ccap->defrect, &ccap->bounds,
- sizeof(struct v4l2_rect));
-
- ccap->pixelaspect.numerator = 1;
- ccap->pixelaspect.denominator = 1;
- break;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vino_g_crop(struct file *file, void *__fh,
- struct v4l2_crop *c)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
-
- switch (c->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- c->c.left = vcs->clipping.left;
- c->c.top = vcs->clipping.top;
- c->c.width = vcs->clipping.right - vcs->clipping.left;
- c->c.height = vcs->clipping.bottom - vcs->clipping.top;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- break;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vino_s_crop(struct file *file, void *__fh,
- const struct v4l2_crop *c)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
-
- switch (c->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- vino_set_clipping(vcs, c->c.left, c->c.top,
- c->c.width, c->c.height);
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
- break;
- case V4L2_BUF_TYPE_VIDEO_OVERLAY:
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int vino_g_parm(struct file *file, void *__fh,
- struct v4l2_streamparm *sp)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- struct v4l2_captureparm *cp = &sp->parm.capture;
-
- cp->capability = V4L2_CAP_TIMEPERFRAME;
- cp->timeperframe.numerator = 1;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- cp->timeperframe.denominator = vcs->fps;
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- /* TODO: cp->readbuffers = xxx; */
-
- return 0;
-}
-
-static int vino_s_parm(struct file *file, void *__fh,
- struct v4l2_streamparm *sp)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- struct v4l2_captureparm *cp = &sp->parm.capture;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if ((cp->timeperframe.numerator == 0) ||
- (cp->timeperframe.denominator == 0)) {
- /* reset framerate */
- vino_set_default_framerate(vcs);
- } else {
- vino_set_framerate(vcs, cp->timeperframe.denominator /
- cp->timeperframe.numerator);
- }
-
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return 0;
-}
-
-static int vino_reqbufs(struct file *file, void *__fh,
- struct v4l2_requestbuffers *rb)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
-
- if (vcs->reading)
- return -EBUSY;
-
- /* TODO: check queue type */
- if (rb->memory != V4L2_MEMORY_MMAP) {
- dprintk("type not mmap\n");
- return -EINVAL;
- }
-
- dprintk("count = %d\n", rb->count);
- if (rb->count > 0) {
- if (vino_is_capturing(vcs)) {
- dprintk("busy, capturing\n");
- return -EBUSY;
- }
-
- if (vino_queue_has_mapped_buffers(&vcs->fb_queue)) {
- dprintk("busy, buffers still mapped\n");
- return -EBUSY;
- } else {
- vcs->streaming = 0;
- vino_queue_free(&vcs->fb_queue);
- vino_queue_init(&vcs->fb_queue, &rb->count);
- }
- } else {
- vcs->streaming = 0;
- vino_capture_stop(vcs);
- vino_queue_free(&vcs->fb_queue);
- }
-
- return 0;
-}
-
-static void vino_v4l2_get_buffer_status(struct vino_channel_settings *vcs,
- struct vino_framebuffer *fb,
- struct v4l2_buffer *b)
-{
- if (vino_queue_outgoing_contains(&vcs->fb_queue,
- fb->id)) {
- b->flags &= ~V4L2_BUF_FLAG_QUEUED;
- b->flags |= V4L2_BUF_FLAG_DONE;
- } else if (vino_queue_incoming_contains(&vcs->fb_queue,
- fb->id)) {
- b->flags &= ~V4L2_BUF_FLAG_DONE;
- b->flags |= V4L2_BUF_FLAG_QUEUED;
- } else {
- b->flags &= ~(V4L2_BUF_FLAG_DONE |
- V4L2_BUF_FLAG_QUEUED);
- }
-
- b->flags &= ~(V4L2_BUF_FLAG_TIMECODE);
-
- if (fb->map_count > 0)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
-
- b->flags &= ~V4L2_BUF_FLAG_TIMESTAMP_MASK;
- b->flags |= V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
-
- b->index = fb->id;
- b->memory = (vcs->fb_queue.type == VINO_MEMORY_MMAP) ?
- V4L2_MEMORY_MMAP : V4L2_MEMORY_USERPTR;
- b->m.offset = fb->offset;
- b->bytesused = fb->data_size;
- b->length = fb->size;
- b->field = V4L2_FIELD_INTERLACED;
- b->sequence = fb->frame_counter;
- memcpy(&b->timestamp, &fb->timestamp,
- sizeof(struct timeval));
- // b->input ?
-
- dprintk("buffer %d: length = %d, bytesused = %d, offset = %d\n",
- fb->id, fb->size, fb->data_size, fb->offset);
-}
-
-static int vino_querybuf(struct file *file, void *__fh,
- struct v4l2_buffer *b)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- struct vino_framebuffer *fb;
-
- if (vcs->reading)
- return -EBUSY;
-
- /* TODO: check queue type */
- if (b->index >= vino_queue_get_length(&vcs->fb_queue)) {
- dprintk("invalid index = %d\n",
- b->index);
- return -EINVAL;
- }
-
- fb = vino_queue_get_buffer(&vcs->fb_queue,
- b->index);
- if (fb == NULL) {
- dprintk("vino_queue_get_buffer() failed");
- return -EINVAL;
- }
-
- vino_v4l2_get_buffer_status(vcs, fb, b);
-
- return 0;
-}
-
-static int vino_qbuf(struct file *file, void *__fh,
- struct v4l2_buffer *b)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- struct vino_framebuffer *fb;
- int ret;
-
- if (vcs->reading)
- return -EBUSY;
-
- /* TODO: check queue type */
- if (b->memory != V4L2_MEMORY_MMAP) {
- dprintk("type not mmap\n");
- return -EINVAL;
- }
-
- fb = vino_capture_enqueue(vcs, b->index);
- if (fb == NULL)
- return -EINVAL;
-
- vino_v4l2_get_buffer_status(vcs, fb, b);
-
- if (vcs->streaming) {
- ret = vino_capture_next(vcs, 1);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
-static int vino_dqbuf(struct file *file, void *__fh,
- struct v4l2_buffer *b)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned int nonblocking = file->f_flags & O_NONBLOCK;
- struct vino_framebuffer *fb;
- unsigned int incoming, outgoing;
- int err;
-
- if (vcs->reading)
- return -EBUSY;
-
- /* TODO: check queue type */
-
- err = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
- if (err) {
- dprintk("vino_queue_get_incoming() failed\n");
- return -EINVAL;
- }
- err = vino_queue_get_outgoing(&vcs->fb_queue, &outgoing);
- if (err) {
- dprintk("vino_queue_get_outgoing() failed\n");
- return -EINVAL;
- }
-
- dprintk("incoming = %d, outgoing = %d\n", incoming, outgoing);
-
- if (outgoing == 0) {
- if (incoming == 0) {
- dprintk("no incoming or outgoing buffers\n");
- return -EINVAL;
- }
- if (nonblocking) {
- dprintk("non-blocking I/O was selected and "
- "there are no buffers to dequeue\n");
- return -EAGAIN;
- }
-
- err = vino_wait_for_frame(vcs);
- if (err) {
- err = vino_wait_for_frame(vcs);
- if (err) {
- /* interrupted or no frames captured because of
- * frame skipping */
- /* vino_capture_failed(vcs); */
- return -EIO;
- }
- }
- }
-
- fb = vino_queue_remove(&vcs->fb_queue, &b->index);
- if (fb == NULL) {
- dprintk("vino_queue_remove() failed\n");
- return -EINVAL;
- }
-
- err = vino_check_buffer(vcs, fb);
-
- vino_v4l2_get_buffer_status(vcs, fb, b);
-
- if (err)
- return -EIO;
-
- return 0;
-}
-
-static int vino_streamon(struct file *file, void *__fh,
- enum v4l2_buf_type i)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned int incoming;
- int ret;
- if (vcs->reading)
- return -EBUSY;
-
- if (vcs->streaming)
- return 0;
-
- // TODO: check queue type
-
- if (vino_queue_get_length(&vcs->fb_queue) < 1) {
- dprintk("no buffers allocated\n");
- return -EINVAL;
- }
-
- ret = vino_queue_get_incoming(&vcs->fb_queue, &incoming);
- if (ret) {
- dprintk("vino_queue_get_incoming() failed\n");
- return -EINVAL;
- }
-
- vcs->streaming = 1;
-
- if (incoming > 0) {
- ret = vino_capture_next(vcs, 1);
- if (ret) {
- vcs->streaming = 0;
-
- dprintk("couldn't start capture\n");
- return -EINVAL;
- }
- }
-
- return 0;
-}
-
-static int vino_streamoff(struct file *file, void *__fh,
- enum v4l2_buf_type i)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- if (vcs->reading)
- return -EBUSY;
-
- if (!vcs->streaming)
- return 0;
-
- vcs->streaming = 0;
- vino_capture_stop(vcs);
-
- return 0;
-}
-
-static int vino_queryctrl(struct file *file, void *__fh,
- struct v4l2_queryctrl *queryctrl)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- int i;
- int err = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- switch (vcs->input) {
- case VINO_INPUT_D1:
- for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id ==
- queryctrl->id) {
- memcpy(queryctrl,
- &vino_indycam_v4l2_controls[i],
- sizeof(struct v4l2_queryctrl));
- queryctrl->reserved[0] = 0;
- goto found;
- }
- }
-
- err = -EINVAL;
- break;
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO:
- for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id ==
- queryctrl->id) {
- memcpy(queryctrl,
- &vino_saa7191_v4l2_controls[i],
- sizeof(struct v4l2_queryctrl));
- queryctrl->reserved[0] = 0;
- goto found;
- }
- }
-
- err = -EINVAL;
- break;
- default:
- err = -EINVAL;
- }
-
- found:
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return err;
-}
-
-static int vino_g_ctrl(struct file *file, void *__fh,
- struct v4l2_control *control)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- int i;
- int err = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- switch (vcs->input) {
- case VINO_INPUT_D1: {
- err = -EINVAL;
- for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id == control->id) {
- err = 0;
- break;
- }
- }
-
- if (err)
- goto out;
-
- err = camera_call(core, g_ctrl, control);
- if (err)
- err = -EINVAL;
- break;
- }
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO: {
- err = -EINVAL;
- for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id == control->id) {
- err = 0;
- break;
- }
- }
-
- if (err)
- goto out;
-
- err = decoder_call(core, g_ctrl, control);
- if (err)
- err = -EINVAL;
- break;
- }
- default:
- err = -EINVAL;
- }
-
-out:
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return err;
-}
-
-static int vino_s_ctrl(struct file *file, void *__fh,
- struct v4l2_control *control)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned long flags;
- int i;
- int err = 0;
-
- spin_lock_irqsave(&vino_drvdata->input_lock, flags);
-
- if (!vino_is_input_owner(vcs)) {
- err = -EBUSY;
- goto out;
- }
-
- switch (vcs->input) {
- case VINO_INPUT_D1: {
- err = -EINVAL;
- for (i = 0; i < VINO_INDYCAM_V4L2_CONTROL_COUNT; i++) {
- if (vino_indycam_v4l2_controls[i].id == control->id) {
- err = 0;
- break;
- }
- }
- if (err)
- goto out;
- if (control->value < vino_indycam_v4l2_controls[i].minimum ||
- control->value > vino_indycam_v4l2_controls[i].maximum) {
- err = -ERANGE;
- goto out;
- }
- err = camera_call(core, s_ctrl, control);
- if (err)
- err = -EINVAL;
- break;
- }
- case VINO_INPUT_COMPOSITE:
- case VINO_INPUT_SVIDEO: {
- err = -EINVAL;
- for (i = 0; i < VINO_SAA7191_V4L2_CONTROL_COUNT; i++) {
- if (vino_saa7191_v4l2_controls[i].id == control->id) {
- err = 0;
- break;
- }
- }
- if (err)
- goto out;
- if (control->value < vino_saa7191_v4l2_controls[i].minimum ||
- control->value > vino_saa7191_v4l2_controls[i].maximum) {
- err = -ERANGE;
- goto out;
- }
-
- err = decoder_call(core, s_ctrl, control);
- if (err)
- err = -EINVAL;
- break;
- }
- default:
- err = -EINVAL;
- }
-
-out:
- spin_unlock_irqrestore(&vino_drvdata->input_lock, flags);
-
- return err;
-}
-
-/* File operations */
-
-static int vino_open(struct file *file)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- int ret = 0;
- dprintk("open(): channel = %c\n",
- (vcs->channel == VINO_CHANNEL_A) ? 'A' : 'B');
-
- mutex_lock(&vcs->mutex);
-
- if (vcs->users) {
- dprintk("open(): driver busy\n");
- ret = -EBUSY;
- goto out;
- }
-
- ret = vino_acquire_input(vcs);
- if (ret) {
- dprintk("open(): vino_acquire_input() failed\n");
- goto out;
- }
-
- vcs->users++;
-
- out:
- mutex_unlock(&vcs->mutex);
-
- dprintk("open(): %s!\n", ret ? "failed" : "complete");
-
- return ret;
-}
-
-static int vino_close(struct file *file)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- dprintk("close():\n");
-
- mutex_lock(&vcs->mutex);
-
- vcs->users--;
-
- if (!vcs->users) {
- vino_release_input(vcs);
-
- /* stop DMA and free buffers */
- vino_capture_stop(vcs);
- vino_queue_free(&vcs->fb_queue);
- }
-
- mutex_unlock(&vcs->mutex);
-
- return 0;
-}
-
-static void vino_vm_open(struct vm_area_struct *vma)
-{
- struct vino_framebuffer *fb = vma->vm_private_data;
-
- fb->map_count++;
- dprintk("vino_vm_open(): count = %d\n", fb->map_count);
-}
-
-static void vino_vm_close(struct vm_area_struct *vma)
-{
- struct vino_framebuffer *fb = vma->vm_private_data;
-
- fb->map_count--;
- dprintk("vino_vm_close(): count = %d\n", fb->map_count);
-}
-
-static const struct vm_operations_struct vino_vm_ops = {
- .open = vino_vm_open,
- .close = vino_vm_close,
-};
-
-static int vino_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
-
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
-
- struct vino_framebuffer *fb = NULL;
- unsigned int i, length;
- int ret = 0;
-
- dprintk("mmap():\n");
-
- // TODO: reject mmap if already mapped
-
- if (mutex_lock_interruptible(&vcs->mutex))
- return -EINTR;
-
- if (vcs->reading) {
- ret = -EBUSY;
- goto out;
- }
-
- // TODO: check queue type
-
- if (!(vma->vm_flags & VM_WRITE)) {
- dprintk("mmap(): app bug: PROT_WRITE please\n");
- ret = -EINVAL;
- goto out;
- }
- if (!(vma->vm_flags & VM_SHARED)) {
- dprintk("mmap(): app bug: MAP_SHARED please\n");
- ret = -EINVAL;
- goto out;
- }
-
- /* find the correct buffer using offset */
- length = vino_queue_get_length(&vcs->fb_queue);
- if (length == 0) {
- dprintk("mmap(): queue not initialized\n");
- ret = -EINVAL;
- goto out;
- }
-
- for (i = 0; i < length; i++) {
- fb = vino_queue_get_buffer(&vcs->fb_queue, i);
- if (fb == NULL) {
- dprintk("mmap(): vino_queue_get_buffer() failed\n");
- ret = -EINVAL;
- goto out;
- }
-
- if (fb->offset == offset)
- goto found;
- }
-
- dprintk("mmap(): invalid offset = %lu\n", offset);
- ret = -EINVAL;
- goto out;
-
-found:
- dprintk("mmap(): buffer = %d\n", i);
-
- if (size > (fb->desc_table.page_count * PAGE_SIZE)) {
- dprintk("mmap(): failed: size = %lu > %lu\n",
- size, fb->desc_table.page_count * PAGE_SIZE);
- ret = -EINVAL;
- goto out;
- }
-
- for (i = 0; i < fb->desc_table.page_count; i++) {
- unsigned long pfn =
- virt_to_phys((void *)fb->desc_table.virtual[i]) >>
- PAGE_SHIFT;
-
- if (size < PAGE_SIZE)
- break;
-
- // protection was: PAGE_READONLY
- if (remap_pfn_range(vma, start, pfn, PAGE_SIZE,
- vma->vm_page_prot)) {
- dprintk("mmap(): remap_pfn_range() failed\n");
- ret = -EAGAIN;
- goto out;
- }
-
- start += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- fb->map_count = 1;
-
- vma->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
- vma->vm_flags &= ~VM_IO;
- vma->vm_private_data = fb;
- vma->vm_file = file;
- vma->vm_ops = &vino_vm_ops;
-
-out:
- mutex_unlock(&vcs->mutex);
-
- return ret;
-}
-
-static unsigned int vino_poll(struct file *file, poll_table *pt)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- unsigned int outgoing;
- unsigned int ret = 0;
-
- // lock mutex (?)
- // TODO: this has to be corrected for different read modes
-
- dprintk("poll():\n");
-
- if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
- dprintk("poll(): vino_queue_get_outgoing() failed\n");
- ret = POLLERR;
- goto error;
- }
- if (outgoing > 0)
- goto over;
-
- poll_wait(file, &vcs->fb_queue.frame_wait_queue, pt);
-
- if (vino_queue_get_outgoing(&vcs->fb_queue, &outgoing)) {
- dprintk("poll(): vino_queue_get_outgoing() failed\n");
- ret = POLLERR;
- goto error;
- }
-
-over:
- dprintk("poll(): data %savailable\n",
- (outgoing > 0) ? "" : "not ");
-
- if (outgoing > 0)
- ret = POLLIN | POLLRDNORM;
-
-error:
- return ret;
-}
-
-static long vino_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct vino_channel_settings *vcs = video_drvdata(file);
- long ret;
-
- if (mutex_lock_interruptible(&vcs->mutex))
- return -EINTR;
-
- ret = video_ioctl2(file, cmd, arg);
-
- mutex_unlock(&vcs->mutex);
-
- return ret;
-}
-
-/* Initialization and cleanup */
-
-/* __initdata */
-static int vino_init_stage;
-
-const struct v4l2_ioctl_ops vino_ioctl_ops = {
- .vidioc_enum_fmt_vid_cap = vino_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vino_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vino_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vino_try_fmt_vid_cap,
- .vidioc_querycap = vino_querycap,
- .vidioc_enum_input = vino_enum_input,
- .vidioc_g_input = vino_g_input,
- .vidioc_s_input = vino_s_input,
- .vidioc_g_std = vino_g_std,
- .vidioc_s_std = vino_s_std,
- .vidioc_querystd = vino_querystd,
- .vidioc_cropcap = vino_cropcap,
- .vidioc_s_crop = vino_s_crop,
- .vidioc_g_crop = vino_g_crop,
- .vidioc_s_parm = vino_s_parm,
- .vidioc_g_parm = vino_g_parm,
- .vidioc_reqbufs = vino_reqbufs,
- .vidioc_querybuf = vino_querybuf,
- .vidioc_qbuf = vino_qbuf,
- .vidioc_dqbuf = vino_dqbuf,
- .vidioc_streamon = vino_streamon,
- .vidioc_streamoff = vino_streamoff,
- .vidioc_queryctrl = vino_queryctrl,
- .vidioc_g_ctrl = vino_g_ctrl,
- .vidioc_s_ctrl = vino_s_ctrl,
-};
-
-static const struct v4l2_file_operations vino_fops = {
- .owner = THIS_MODULE,
- .open = vino_open,
- .release = vino_close,
- .unlocked_ioctl = vino_ioctl,
- .mmap = vino_mmap,
- .poll = vino_poll,
-};
-
-static struct video_device vdev_template = {
- .name = "NOT SET",
- .fops = &vino_fops,
- .ioctl_ops = &vino_ioctl_ops,
- .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
-};
-
-static void vino_module_cleanup(int stage)
-{
- switch(stage) {
- case 11:
- video_unregister_device(vino_drvdata->b.vdev);
- vino_drvdata->b.vdev = NULL;
- case 10:
- video_unregister_device(vino_drvdata->a.vdev);
- vino_drvdata->a.vdev = NULL;
- case 9:
- i2c_del_adapter(&vino_i2c_adapter);
- case 8:
- free_irq(SGI_VINO_IRQ, NULL);
- case 7:
- if (vino_drvdata->b.vdev) {
- video_device_release(vino_drvdata->b.vdev);
- vino_drvdata->b.vdev = NULL;
- }
- case 6:
- if (vino_drvdata->a.vdev) {
- video_device_release(vino_drvdata->a.vdev);
- vino_drvdata->a.vdev = NULL;
- }
- case 5:
- /* all entries in dma_cpu dummy table have the same address */
- dma_unmap_single(NULL,
- vino_drvdata->dummy_desc_table.dma_cpu[0],
- PAGE_SIZE, DMA_FROM_DEVICE);
- dma_free_coherent(NULL, VINO_DUMMY_DESC_COUNT
- * sizeof(dma_addr_t),
- (void *)vino_drvdata->
- dummy_desc_table.dma_cpu,
- vino_drvdata->dummy_desc_table.dma);
- case 4:
- free_page(vino_drvdata->dummy_page);
- case 3:
- v4l2_device_unregister(&vino_drvdata->v4l2_dev);
- case 2:
- kfree(vino_drvdata);
- case 1:
- iounmap(vino);
- case 0:
- break;
- default:
- dprintk("vino_module_cleanup(): invalid cleanup stage = %d\n",
- stage);
- }
-}
-
-static int vino_probe(void)
-{
- unsigned long rev_id;
-
- if (ip22_is_fullhouse()) {
- printk(KERN_ERR "VINO doesn't exist in IP22 Fullhouse\n");
- return -ENODEV;
- }
-
- if (!(sgimc->systemid & SGIMC_SYSID_EPRESENT)) {
- printk(KERN_ERR "VINO is not found (EISA BUS not present)\n");
- return -ENODEV;
- }
-
- vino = (struct sgi_vino *)ioremap(VINO_BASE, sizeof(struct sgi_vino));
- if (!vino) {
- printk(KERN_ERR "VINO: ioremap() failed\n");
- return -EIO;
- }
- vino_init_stage++;
-
- if (get_dbe(rev_id, &(vino->rev_id))) {
- printk(KERN_ERR "Failed to read VINO revision register\n");
- vino_module_cleanup(vino_init_stage);
- return -ENODEV;
- }
-
- if (VINO_ID_VALUE(rev_id) != VINO_CHIP_ID) {
- printk(KERN_ERR "Unknown VINO chip ID (Rev/ID: 0x%02lx)\n",
- rev_id);
- vino_module_cleanup(vino_init_stage);
- return -ENODEV;
- }
-
- printk(KERN_INFO "VINO revision %ld found\n", VINO_REV_NUM(rev_id));
-
- return 0;
-}
-
-static int vino_init(void)
-{
- dma_addr_t dma_dummy_address;
- int err;
- int i;
-
- vino_drvdata = kzalloc(sizeof(struct vino_settings), GFP_KERNEL);
- if (!vino_drvdata) {
- vino_module_cleanup(vino_init_stage);
- return -ENOMEM;
- }
- vino_init_stage++;
- strlcpy(vino_drvdata->v4l2_dev.name, "vino",
- sizeof(vino_drvdata->v4l2_dev.name));
- err = v4l2_device_register(NULL, &vino_drvdata->v4l2_dev);
- if (err)
- return err;
- vino_init_stage++;
-
- /* create a dummy dma descriptor */
- vino_drvdata->dummy_page = get_zeroed_page(GFP_KERNEL | GFP_DMA);
- if (!vino_drvdata->dummy_page) {
- vino_module_cleanup(vino_init_stage);
- return -ENOMEM;
- }
- vino_init_stage++;
-
- // TODO: use page_count in dummy_desc_table
-
- vino_drvdata->dummy_desc_table.dma_cpu =
- dma_alloc_coherent(NULL,
- VINO_DUMMY_DESC_COUNT * sizeof(dma_addr_t),
- &vino_drvdata->dummy_desc_table.dma,
- GFP_KERNEL | GFP_DMA);
- if (!vino_drvdata->dummy_desc_table.dma_cpu) {
- vino_module_cleanup(vino_init_stage);
- return -ENOMEM;
- }
- vino_init_stage++;
-
- dma_dummy_address = dma_map_single(NULL,
- (void *)vino_drvdata->dummy_page,
- PAGE_SIZE, DMA_FROM_DEVICE);
- for (i = 0; i < VINO_DUMMY_DESC_COUNT; i++) {
- vino_drvdata->dummy_desc_table.dma_cpu[i] = dma_dummy_address;
- }
-
- /* initialize VINO */
-
- vino->control = 0;
- vino->a.next_4_desc = vino_drvdata->dummy_desc_table.dma;
- vino->b.next_4_desc = vino_drvdata->dummy_desc_table.dma;
- udelay(VINO_DESC_FETCH_DELAY);
-
- vino->intr_status = 0;
-
- vino->a.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
- vino->b.fifo_thres = VINO_FIFO_THRESHOLD_DEFAULT;
-
- return 0;
-}
-
-static int vino_init_channel_settings(struct vino_channel_settings *vcs,
- unsigned int channel, const char *name)
-{
- vcs->channel = channel;
- vcs->input = VINO_INPUT_NONE;
- vcs->alpha = 0;
- vcs->users = 0;
- vcs->data_format = VINO_DATA_FMT_GREY;
- vcs->data_norm = VINO_DATA_NORM_NTSC;
- vcs->decimation = 1;
- vino_set_default_clipping(vcs);
- vino_set_default_framerate(vcs);
-
- vcs->capturing = 0;
-
- mutex_init(&vcs->mutex);
- spin_lock_init(&vcs->capture_lock);
-
- mutex_init(&vcs->fb_queue.queue_mutex);
- spin_lock_init(&vcs->fb_queue.queue_lock);
- init_waitqueue_head(&vcs->fb_queue.frame_wait_queue);
-
- vcs->vdev = video_device_alloc();
- if (!vcs->vdev) {
- vino_module_cleanup(vino_init_stage);
- return -ENOMEM;
- }
- vino_init_stage++;
-
- memcpy(vcs->vdev, &vdev_template,
- sizeof(struct video_device));
- strcpy(vcs->vdev->name, name);
- vcs->vdev->release = video_device_release;
- vcs->vdev->v4l2_dev = &vino_drvdata->v4l2_dev;
-
- video_set_drvdata(vcs->vdev, vcs);
-
- return 0;
-}
-
-static int __init vino_module_init(void)
-{
- int ret;
-
- printk(KERN_INFO "SGI VINO driver version %s\n",
- VINO_MODULE_VERSION);
-
- ret = vino_probe();
- if (ret)
- return ret;
-
- ret = vino_init();
- if (ret)
- return ret;
-
- /* initialize data structures */
-
- spin_lock_init(&vino_drvdata->vino_lock);
- spin_lock_init(&vino_drvdata->input_lock);
-
- ret = vino_init_channel_settings(&vino_drvdata->a, VINO_CHANNEL_A,
- vino_vdev_name_a);
- if (ret)
- return ret;
-
- ret = vino_init_channel_settings(&vino_drvdata->b, VINO_CHANNEL_B,
- vino_vdev_name_b);
- if (ret)
- return ret;
-
- /* initialize hardware and register V4L devices */
-
- ret = request_irq(SGI_VINO_IRQ, vino_interrupt, 0,
- vino_driver_description, NULL);
- if (ret) {
- printk(KERN_ERR "VINO: requesting IRQ %02d failed\n",
- SGI_VINO_IRQ);
- vino_module_cleanup(vino_init_stage);
- return -EAGAIN;
- }
- vino_init_stage++;
-
- ret = i2c_add_adapter(&vino_i2c_adapter);
- if (ret) {
- printk(KERN_ERR "VINO I2C bus registration failed\n");
- vino_module_cleanup(vino_init_stage);
- return ret;
- }
- i2c_set_adapdata(&vino_i2c_adapter, &vino_drvdata->v4l2_dev);
- vino_init_stage++;
-
- ret = video_register_device(vino_drvdata->a.vdev,
- VFL_TYPE_GRABBER, -1);
- if (ret < 0) {
- printk(KERN_ERR "VINO channel A Video4Linux-device "
- "registration failed\n");
- vino_module_cleanup(vino_init_stage);
- return -EINVAL;
- }
- vino_init_stage++;
-
- ret = video_register_device(vino_drvdata->b.vdev,
- VFL_TYPE_GRABBER, -1);
- if (ret < 0) {
- printk(KERN_ERR "VINO channel B Video4Linux-device "
- "registration failed\n");
- vino_module_cleanup(vino_init_stage);
- return -EINVAL;
- }
- vino_init_stage++;
-
- vino_drvdata->decoder =
- v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- "saa7191", 0, I2C_ADDRS(0x45));
- vino_drvdata->camera =
- v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- "indycam", 0, I2C_ADDRS(0x2b));
-
- dprintk("init complete!\n");
-
- return 0;
-}
-
-static void __exit vino_module_exit(void)
-{
- dprintk("exiting, stage = %d ...\n", vino_init_stage);
- vino_module_cleanup(vino_init_stage);
- dprintk("cleanup complete, exit!\n");
-}
-
-module_init(vino_module_init);
-module_exit(vino_module_exit);
diff --git a/drivers/staging/media/vino/vino.h b/drivers/staging/media/vino/vino.h
deleted file mode 100644
index de2d615ae7c9..000000000000
--- a/drivers/staging/media/vino/vino.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Driver for the VINO (Video In No Out) system found in SGI Indys.
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License version 2 as published by the Free Software Foundation.
- *
- * Copyright (C) 1999 Ulf Karlsson <ulfc@bun.falkenberg.se>
- * Copyright (C) 2003 Ladislav Michl <ladis@linux-mips.org>
- */
-
-#ifndef _VINO_H_
-#define _VINO_H_
-
-#define VINO_BASE 0x00080000 /* Vino is in the EISA address space,
- * but it is not an EISA bus card */
-#define VINO_PAGE_SIZE 4096
-
-struct sgi_vino_channel {
- u32 _pad_alpha;
- volatile u32 alpha;
-
-#define VINO_CLIP_X(x) ((x) & 0x3ff) /* bits 0:9 */
-#define VINO_CLIP_ODD(x) (((x) & 0x1ff) << 10) /* bits 10:18 */
-#define VINO_CLIP_EVEN(x) (((x) & 0x1ff) << 19) /* bits 19:27 */
- u32 _pad_clip_start;
- volatile u32 clip_start;
- u32 _pad_clip_end;
- volatile u32 clip_end;
-
-#define VINO_FRAMERT_FULL 0xfff
-#define VINO_FRAMERT_PAL (1<<0) /* 0=NTSC 1=PAL */
-#define VINO_FRAMERT_RT(x) (((x) & 0xfff) << 1) /* bits 1:12 */
- u32 _pad_frame_rate;
- volatile u32 frame_rate;
-
- u32 _pad_field_counter;
- volatile u32 field_counter;
- u32 _pad_line_size;
- volatile u32 line_size;
- u32 _pad_line_count;
- volatile u32 line_count;
- u32 _pad_page_index;
- volatile u32 page_index;
- u32 _pad_next_4_desc;
- volatile u32 next_4_desc;
- u32 _pad_start_desc_tbl;
- volatile u32 start_desc_tbl;
-
-#define VINO_DESC_JUMP (1<<30)
-#define VINO_DESC_STOP (1<<31)
-#define VINO_DESC_VALID (1<<32)
- u32 _pad_desc_0;
- volatile u32 desc_0;
- u32 _pad_desc_1;
- volatile u32 desc_1;
- u32 _pad_desc_2;
- volatile u32 desc_2;
- u32 _pad_Bdesc_3;
- volatile u32 desc_3;
-
- u32 _pad_fifo_thres;
- volatile u32 fifo_thres;
- u32 _pad_fifo_read;
- volatile u32 fifo_read;
- u32 _pad_fifo_write;
- volatile u32 fifo_write;
-};
-
-struct sgi_vino {
-#define VINO_CHIP_ID 0xb
-#define VINO_REV_NUM(x) ((x) & 0x0f)
-#define VINO_ID_VALUE(x) (((x) & 0xf0) >> 4)
- u32 _pad_rev_id;
- volatile u32 rev_id;
-
-#define VINO_CTRL_LITTLE_ENDIAN (1<<0)
-#define VINO_CTRL_A_EOF_INT (1<<1) /* Field transferred int */
-#define VINO_CTRL_A_FIFO_INT (1<<2) /* FIFO overflow int */
-#define VINO_CTRL_A_EOD_INT (1<<3) /* End of desc table int */
-#define VINO_CTRL_A_INT (VINO_CTRL_A_EOF_INT | \
- VINO_CTRL_A_FIFO_INT | \
- VINO_CTRL_A_EOD_INT)
-#define VINO_CTRL_B_EOF_INT (1<<4) /* Field transferred int */
-#define VINO_CTRL_B_FIFO_INT (1<<5) /* FIFO overflow int */
-#define VINO_CTRL_B_EOD_INT (1<<6) /* End of desc table int */
-#define VINO_CTRL_B_INT (VINO_CTRL_B_EOF_INT | \
- VINO_CTRL_B_FIFO_INT | \
- VINO_CTRL_B_EOD_INT)
-#define VINO_CTRL_A_DMA_ENBL (1<<7)
-#define VINO_CTRL_A_INTERLEAVE_ENBL (1<<8)
-#define VINO_CTRL_A_SYNC_ENBL (1<<9)
-#define VINO_CTRL_A_SELECT (1<<10) /* 1=D1 0=Philips */
-#define VINO_CTRL_A_RGB (1<<11) /* 1=RGB 0=YUV */
-#define VINO_CTRL_A_LUMA_ONLY (1<<12)
-#define VINO_CTRL_A_DEC_ENBL (1<<13) /* Decimation */
-#define VINO_CTRL_A_DEC_SCALE_MASK 0x1c000 /* bits 14:17 */
-#define VINO_CTRL_A_DEC_SCALE_SHIFT (14)
-#define VINO_CTRL_A_DEC_HOR_ONLY (1<<17) /* Horizontal only */
-#define VINO_CTRL_A_DITHER (1<<18) /* 24 -> 8 bit dither */
-#define VINO_CTRL_B_DMA_ENBL (1<<19)
-#define VINO_CTRL_B_INTERLEAVE_ENBL (1<<20)
-#define VINO_CTRL_B_SYNC_ENBL (1<<21)
-#define VINO_CTRL_B_SELECT (1<<22) /* 1=D1 0=Philips */
-#define VINO_CTRL_B_RGB (1<<23) /* 1=RGB 0=YUV */
-#define VINO_CTRL_B_LUMA_ONLY (1<<24)
-#define VINO_CTRL_B_DEC_ENBL (1<<25) /* Decimation */
-#define VINO_CTRL_B_DEC_SCALE_MASK 0x1c000000 /* bits 26:28 */
-#define VINO_CTRL_B_DEC_SCALE_SHIFT (26)
-#define VINO_CTRL_B_DEC_HOR_ONLY (1<<29) /* Decimation horizontal only */
-#define VINO_CTRL_B_DITHER (1<<30) /* ChanB 24 -> 8 bit dither */
- u32 _pad_control;
- volatile u32 control;
-
-#define VINO_INTSTAT_A_EOF (1<<0) /* Field transferred int */
-#define VINO_INTSTAT_A_FIFO (1<<1) /* FIFO overflow int */
-#define VINO_INTSTAT_A_EOD (1<<2) /* End of desc table int */
-#define VINO_INTSTAT_A (VINO_INTSTAT_A_EOF | \
- VINO_INTSTAT_A_FIFO | \
- VINO_INTSTAT_A_EOD)
-#define VINO_INTSTAT_B_EOF (1<<3) /* Field transferred int */
-#define VINO_INTSTAT_B_FIFO (1<<4) /* FIFO overflow int */
-#define VINO_INTSTAT_B_EOD (1<<5) /* End of desc table int */
-#define VINO_INTSTAT_B (VINO_INTSTAT_B_EOF | \
- VINO_INTSTAT_B_FIFO | \
- VINO_INTSTAT_B_EOD)
- u32 _pad_intr_status;
- volatile u32 intr_status;
-
- u32 _pad_i2c_control;
- volatile u32 i2c_control;
- u32 _pad_i2c_data;
- volatile u32 i2c_data;
-
- struct sgi_vino_channel a;
- struct sgi_vino_channel b;
-};
-
-#endif
diff --git a/drivers/staging/mt29f_spinand/Kconfig b/drivers/staging/mt29f_spinand/Kconfig
index 403174817be7..f3f9cb3b5c35 100644
--- a/drivers/staging/mt29f_spinand/Kconfig
+++ b/drivers/staging/mt29f_spinand/Kconfig
@@ -12,5 +12,5 @@ config MTD_SPINAND_ONDIEECC
bool "Use SPINAND internal ECC"
depends on MTD_SPINAND_MT29F
help
- Internel ECC.
+ Internal ECC.
Enables Hardware ECC support for Micron SPI NAND.
diff --git a/drivers/staging/mt29f_spinand/mt29f_spinand.c b/drivers/staging/mt29f_spinand/mt29f_spinand.c
index 3628bcb840c3..3b191fce45ec 100644
--- a/drivers/staging/mt29f_spinand/mt29f_spinand.c
+++ b/drivers/staging/mt29f_spinand/mt29f_spinand.c
@@ -626,7 +626,8 @@ static int spinand_write_page_hwecc(struct mtd_info *mtd,
static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
uint8_t *buf, int oob_required, int page)
{
- u8 retval, status;
+ int retval;
+ u8 status;
uint8_t *p = buf;
int eccsize = chip->ecc.size;
int eccsteps = chip->ecc.steps;
@@ -640,6 +641,13 @@ static int spinand_read_page_hwecc(struct mtd_info *mtd, struct nand_chip *chip,
while (1) {
retval = spinand_read_status(info->spi, &status);
+ if (retval < 0) {
+ dev_err(&mtd->dev,
+ "error %d reading status register\n",
+ retval);
+ return retval;
+ }
+
if ((status & STATUS_OIP_MASK) == STATUS_READY) {
if ((status & STATUS_ECC_MASK) == STATUS_ECC_ERROR) {
pr_info("spinand: ECC error\n");
@@ -685,6 +693,13 @@ static int spinand_wait(struct mtd_info *mtd, struct nand_chip *chip)
while (time_before(jiffies, timeo)) {
retval = spinand_read_status(info->spi, &status);
+ if (retval < 0) {
+ dev_err(&mtd->dev,
+ "error %d reading status register\n",
+ retval);
+ return retval;
+ }
+
if ((status & STATUS_OIP_MASK) == STATUS_READY)
return 0;
diff --git a/drivers/staging/netlogic/xlr_net.c b/drivers/staging/netlogic/xlr_net.c
index 5ecb3e6a5bb3..e8aae09d1624 100644
--- a/drivers/staging/netlogic/xlr_net.c
+++ b/drivers/staging/netlogic/xlr_net.c
@@ -788,7 +788,7 @@ void xlr_set_gmac_speed(struct xlr_net_priv *priv)
xlr_nae_wreg(priv->base_addr, R_MAC_CONFIG_2, 0x7117);
priv->phy_speed = speed;
}
- /* Set SGMII speed in Interface controll reg */
+ /* Set SGMII speed in Interface control reg */
if (phydev->interface == PHY_INTERFACE_MODE_SGMII) {
if (speed == SPEED_10)
xlr_nae_wreg(priv->base_addr,
diff --git a/drivers/staging/nvec/nvec.c b/drivers/staging/nvec/nvec.c
index 093535c6217b..5868ebb8389e 100644
--- a/drivers/staging/nvec/nvec.c
+++ b/drivers/staging/nvec/nvec.c
@@ -85,23 +85,20 @@ static struct nvec_chip *nvec_power_handle;
static const struct mfd_cell nvec_devices[] = {
{
.name = "nvec-kbd",
- .id = 1,
},
{
.name = "nvec-mouse",
- .id = 1,
},
{
.name = "nvec-power",
- .id = 1,
+ .id = 0,
},
{
.name = "nvec-power",
- .id = 2,
+ .id = 1,
},
{
.name = "nvec-paz00",
- .id = 1,
},
};
@@ -259,7 +256,7 @@ static void nvec_gpio_set_value(struct nvec_chip *nvec, int value)
* and return immediately.
*
* Returns: 0 on success, a negative error code on failure. If a failure
- * occured, the nvec driver may print an error.
+ * occurred, the nvec driver may print an error.
*/
int nvec_write_async(struct nvec_chip *nvec, const unsigned char *data,
short size)
@@ -891,7 +888,7 @@ static int tegra_nvec_probe(struct platform_device *pdev)
nvec_msg_free(nvec, msg);
}
- ret = mfd_add_devices(nvec->dev, -1, nvec_devices,
+ ret = mfd_add_devices(nvec->dev, 0, nvec_devices,
ARRAY_SIZE(nvec_devices), NULL, 0, NULL);
if (ret)
dev_err(nvec->dev, "error adding subdevices\n");
diff --git a/drivers/staging/octeon-usb/octeon-hcd.c b/drivers/staging/octeon-usb/octeon-hcd.c
index 6b8b108c4e6d..1daeb3125a1f 100644
--- a/drivers/staging/octeon-usb/octeon-hcd.c
+++ b/drivers/staging/octeon-usb/octeon-hcd.c
@@ -2687,7 +2687,7 @@ static int __cvmx_usb_poll_channel(struct cvmx_usb_state *usb, int channel)
/*
* Read the channel config info so we can figure out how much data
- * transfered
+ * transferred
*/
usbc_hcchar.u32 = __cvmx_usb_read_csr32(usb,
CVMX_USBCX_HCCHARX(channel, usb->index));
diff --git a/drivers/staging/octeon/ethernet-rx.c b/drivers/staging/octeon/ethernet-rx.c
index fcbe836aa997..22667dbb10d8 100644
--- a/drivers/staging/octeon/ethernet-rx.c
+++ b/drivers/staging/octeon/ethernet-rx.c
@@ -109,6 +109,7 @@ static inline int cvm_oct_check_rcv_error(cvmx_wqe_t *work)
int interface = cvmx_helper_get_interface_num(work->ipprt);
int index = cvmx_helper_get_interface_index_num(work->ipprt);
union cvmx_gmxx_rxx_frm_ctl gmxx_rxx_frm_ctl;
+
gmxx_rxx_frm_ctl.u64 =
cvmx_read_csr(CVMX_GMXX_RXX_FRM_CTL(index, interface));
if (gmxx_rxx_frm_ctl.s.pre_chk == 0) {
@@ -214,6 +215,7 @@ static int cvm_oct_napi_poll(struct napi_struct *napi, int budget)
did_work_request = 0;
if (work == NULL) {
union cvmx_pow_wq_int wq_int;
+
wq_int.u64 = 0;
wq_int.s.iq_dis = 1 << pow_receive_group;
wq_int.s.wq_int = 1 << pow_receive_group;
diff --git a/drivers/staging/octeon/ethernet.c b/drivers/staging/octeon/ethernet.c
index ee321496dcdd..460e8545904f 100644
--- a/drivers/staging/octeon/ethernet.c
+++ b/drivers/staging/octeon/ethernet.c
@@ -798,7 +798,7 @@ static int cvm_oct_probe(struct platform_device *pdev)
cvm_oct_rx_initialize();
/*
- * 150 uS: about 10 1500-byte packtes at 1GE.
+ * 150 uS: about 10 1500-byte packets at 1GE.
*/
cvm_oct_tx_poll_interval = 150 * (octeon_get_clock_rate() / 1000000);
diff --git a/drivers/staging/olpc_dcon/olpc_dcon.c b/drivers/staging/olpc_dcon/olpc_dcon.c
index 6a9a8815477c..bc7e664cc8a7 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon.c
@@ -780,7 +780,7 @@ static const struct i2c_device_id dcon_idtable[] = {
};
MODULE_DEVICE_TABLE(i2c, dcon_idtable);
-struct i2c_driver dcon_driver = {
+static struct i2c_driver dcon_driver = {
.driver = {
.name = "olpc_dcon",
.pm = &dcon_pm_ops,
diff --git a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
index 77e8eb5a5abd..0c5a10c69401 100644
--- a/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
+++ b/drivers/staging/olpc_dcon/olpc_dcon_xo_1.c
@@ -52,7 +52,7 @@ static int dcon_init_xo_1(struct dcon_priv *dcon)
* Determine the current state by reading the GPIO bit; earlier
* stages of the boot process have established the state.
*
- * Note that we read GPIO_OUPUT_VAL rather than GPIO_READ_BACK here;
+ * Note that we read GPIO_OUTPUT_VAL rather than GPIO_READ_BACK here;
* this is because OFW will disable input for the pin and set a value..
* READ_BACK will only contain a valid value if input is enabled and
* then a value is set. So, future readings of the pin can use
diff --git a/drivers/staging/panel/panel.c b/drivers/staging/panel/panel.c
index 98325b7b4462..6ed35b6ecf0d 100644
--- a/drivers/staging/panel/panel.c
+++ b/drivers/staging/panel/panel.c
@@ -130,6 +130,30 @@
#define LCD_FLAG_N 0x0040 /* 2-rows mode */
#define LCD_FLAG_L 0x0080 /* backlight enabled */
+/* LCD commands */
+#define LCD_CMD_DISPLAY_CLEAR 0x01 /* Clear entire display */
+
+#define LCD_CMD_ENTRY_MODE 0x04 /* Set entry mode */
+#define LCD_CMD_CURSOR_INC 0x02 /* Increment cursor */
+
+#define LCD_CMD_DISPLAY_CTRL 0x08 /* Display control */
+#define LCD_CMD_DISPLAY_ON 0x04 /* Set display on */
+#define LCD_CMD_CURSOR_ON 0x02 /* Set cursor on */
+#define LCD_CMD_BLINK_ON 0x01 /* Set blink on */
+
+#define LCD_CMD_SHIFT 0x10 /* Shift cursor/display */
+#define LCD_CMD_DISPLAY_SHIFT 0x08 /* Shift display instead of cursor */
+#define LCD_CMD_SHIFT_RIGHT 0x04 /* Shift display/cursor to the right */
+
+#define LCD_CMD_FUNCTION_SET 0x20 /* Set function */
+#define LCD_CMD_DATA_LEN_8BITS 0x10 /* Set data length to 8 bits */
+#define LCD_CMD_TWO_LINES 0x08 /* Set to two display lines */
+#define LCD_CMD_FONT_5X10_DOTS 0x04 /* Set char font to 5x10 dots */
+
+#define LCD_CMD_SET_CGRAM_ADDR 0x40 /* Set char generator RAM address */
+
+#define LCD_CMD_SET_DDRAM_ADDR 0x80 /* Set display data RAM address */
+
#define LCD_ESCAPE_LEN 24 /* max chars for LCD escape command */
#define LCD_ESCAPE_CHAR 27 /* use char 27 for escape command */
@@ -228,9 +252,6 @@ static struct {
bool initialized;
bool must_clear;
- /* TODO: use bool here? */
- char left_shift;
-
int height;
int width;
int bwidth;
@@ -759,7 +780,7 @@ static void long_sleep(int ms)
if (in_interrupt()) {
mdelay(ms);
} else {
- current->state = TASK_INTERRUPTIBLE;
+ __set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout((ms * HZ + 999) / 1000);
}
}
@@ -886,7 +907,7 @@ static void lcd_write_data_tilcd(int data)
static void lcd_gotoxy(void)
{
- lcd_write_cmd(0x80 /* set DDRAM address */
+ lcd_write_cmd(LCD_CMD_SET_DDRAM_ADDR
| (lcd.addr.y ? lcd.hwidth : 0)
/* we force the cursor to stay at the end of the
line if it wants to go farther */
@@ -994,7 +1015,7 @@ static void lcd_clear_fast_tilcd(void)
/* clears the display and resets X/Y */
static void lcd_clear_display(void)
{
- lcd_write_cmd(0x01); /* clear display */
+ lcd_write_cmd(LCD_CMD_DISPLAY_CLEAR);
lcd.addr.x = 0;
lcd.addr.y = 0;
/* we must wait a few milliseconds (15) */
@@ -1008,26 +1029,29 @@ static void lcd_init_display(void)
long_sleep(20); /* wait 20 ms after power-up for the paranoid */
- lcd_write_cmd(0x30); /* 8bits, 1 line, small fonts */
+ /* 8bits, 1 line, small fonts; let's do it 3 times */
+ lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
long_sleep(10);
- lcd_write_cmd(0x30); /* 8bits, 1 line, small fonts */
+ lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
long_sleep(10);
- lcd_write_cmd(0x30); /* 8bits, 1 line, small fonts */
+ lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS);
long_sleep(10);
- lcd_write_cmd(0x30 /* set font height and lines number */
- | ((lcd.flags & LCD_FLAG_F) ? 4 : 0)
- | ((lcd.flags & LCD_FLAG_N) ? 8 : 0)
+ /* set font height and lines number */
+ lcd_write_cmd(LCD_CMD_FUNCTION_SET | LCD_CMD_DATA_LEN_8BITS
+ | ((lcd.flags & LCD_FLAG_F) ? LCD_CMD_FONT_5X10_DOTS : 0)
+ | ((lcd.flags & LCD_FLAG_N) ? LCD_CMD_TWO_LINES : 0)
);
long_sleep(10);
- lcd_write_cmd(0x08); /* display off, cursor off, blink off */
+ /* display off, cursor off, blink off */
+ lcd_write_cmd(LCD_CMD_DISPLAY_CTRL);
long_sleep(10);
- lcd_write_cmd(0x08 /* set display mode */
- | ((lcd.flags & LCD_FLAG_D) ? 4 : 0)
- | ((lcd.flags & LCD_FLAG_C) ? 2 : 0)
- | ((lcd.flags & LCD_FLAG_B) ? 1 : 0)
+ lcd_write_cmd(LCD_CMD_DISPLAY_CTRL /* set display mode */
+ | ((lcd.flags & LCD_FLAG_D) ? LCD_CMD_DISPLAY_ON : 0)
+ | ((lcd.flags & LCD_FLAG_C) ? LCD_CMD_CURSOR_ON : 0)
+ | ((lcd.flags & LCD_FLAG_B) ? LCD_CMD_BLINK_ON : 0)
);
lcd_backlight((lcd.flags & LCD_FLAG_L) ? 1 : 0);
@@ -1035,7 +1059,7 @@ static void lcd_init_display(void)
long_sleep(10);
/* entry mode set : increment, cursor shifting */
- lcd_write_cmd(0x06);
+ lcd_write_cmd(LCD_CMD_ENTRY_MODE | LCD_CMD_CURSOR_INC);
lcd_clear_display();
}
@@ -1119,7 +1143,7 @@ static inline int handle_lcd_special_code(void)
if (lcd.addr.x > 0) {
/* back one char if not at end of line */
if (lcd.addr.x < lcd.bwidth)
- lcd_write_cmd(0x10);
+ lcd_write_cmd(LCD_CMD_SHIFT);
lcd.addr.x--;
}
processed = 1;
@@ -1127,21 +1151,20 @@ static inline int handle_lcd_special_code(void)
case 'r': /* shift cursor right */
if (lcd.addr.x < lcd.width) {
/* allow the cursor to pass the end of the line */
- if (lcd.addr.x <
- (lcd.bwidth - 1))
- lcd_write_cmd(0x14);
+ if (lcd.addr.x < (lcd.bwidth - 1))
+ lcd_write_cmd(LCD_CMD_SHIFT |
+ LCD_CMD_SHIFT_RIGHT);
lcd.addr.x++;
}
processed = 1;
break;
case 'L': /* shift display left */
- lcd.left_shift++;
- lcd_write_cmd(0x18);
+ lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT);
processed = 1;
break;
case 'R': /* shift display right */
- lcd.left_shift--;
- lcd_write_cmd(0x1C);
+ lcd_write_cmd(LCD_CMD_SHIFT | LCD_CMD_DISPLAY_SHIFT |
+ LCD_CMD_SHIFT_RIGHT);
processed = 1;
break;
case 'k': { /* kill end of line */
@@ -1157,7 +1180,6 @@ static inline int handle_lcd_special_code(void)
}
case 'I': /* reinitialize display */
lcd_init_display();
- lcd.left_shift = 0;
processed = 1;
break;
case 'G': {
@@ -1211,7 +1233,7 @@ static inline int handle_lcd_special_code(void)
esc++;
}
- lcd_write_cmd(0x40 | (cgaddr * 8));
+ lcd_write_cmd(LCD_CMD_SET_CGRAM_ADDR | (cgaddr * 8));
for (addr = 0; addr < cgoffset; addr++)
lcd_write_data(cgbytes[addr]);
@@ -1244,21 +1266,29 @@ static inline int handle_lcd_special_code(void)
break;
}
+ /* TODO: This indent party here got ugly, clean it! */
/* Check whether one flag was changed */
if (oldflags != lcd.flags) {
/* check whether one of B,C,D flags were changed */
if ((oldflags ^ lcd.flags) &
(LCD_FLAG_B | LCD_FLAG_C | LCD_FLAG_D))
/* set display mode */
- lcd_write_cmd(0x08
- | ((lcd.flags & LCD_FLAG_D) ? 4 : 0)
- | ((lcd.flags & LCD_FLAG_C) ? 2 : 0)
- | ((lcd.flags & LCD_FLAG_B) ? 1 : 0));
+ lcd_write_cmd(LCD_CMD_DISPLAY_CTRL
+ | ((lcd.flags & LCD_FLAG_D)
+ ? LCD_CMD_DISPLAY_ON : 0)
+ | ((lcd.flags & LCD_FLAG_C)
+ ? LCD_CMD_CURSOR_ON : 0)
+ | ((lcd.flags & LCD_FLAG_B)
+ ? LCD_CMD_BLINK_ON : 0));
/* check whether one of F,N flags was changed */
else if ((oldflags ^ lcd.flags) & (LCD_FLAG_F | LCD_FLAG_N))
- lcd_write_cmd(0x30
- | ((lcd.flags & LCD_FLAG_F) ? 4 : 0)
- | ((lcd.flags & LCD_FLAG_N) ? 8 : 0));
+ lcd_write_cmd(LCD_CMD_FUNCTION_SET
+ | LCD_CMD_DATA_LEN_8BITS
+ | ((lcd.flags & LCD_FLAG_F)
+ ? LCD_CMD_TWO_LINES : 0)
+ | ((lcd.flags & LCD_FLAG_N)
+ ? LCD_CMD_FONT_5X10_DOTS
+ : 0));
/* check whether L flag was changed */
else if ((oldflags ^ lcd.flags) & (LCD_FLAG_L)) {
if (lcd.flags & (LCD_FLAG_L))
@@ -1297,13 +1327,13 @@ static void lcd_write_char(char c)
end of the line */
if (lcd.addr.x < lcd.bwidth)
/* back one char */
- lcd_write_cmd(0x10);
+ lcd_write_cmd(LCD_CMD_SHIFT);
lcd.addr.x--;
}
/* replace with a space */
lcd_write_data(' ');
/* back one char again */
- lcd_write_cmd(0x10);
+ lcd_write_cmd(LCD_CMD_SHIFT);
break;
case '\014':
/* quickly clear the display */
diff --git a/drivers/staging/rtl8188eu/core/rtw_ap.c b/drivers/staging/rtl8188eu/core/rtw_ap.c
index d61842ed673e..da19145c49c5 100644
--- a/drivers/staging/rtl8188eu/core/rtw_ap.c
+++ b/drivers/staging/rtl8188eu/core/rtw_ap.c
@@ -509,7 +509,7 @@ void add_RATid(struct adapter *padapter, struct sta_info *psta, u8 rssi_level)
tx_ra_bitmap |= ((raid<<28)&0xf0000000);
DBG_88E("%s => mac_id:%d , raid:%d , bitmap = 0x%x, arg = 0x%x\n",
- __func__ , psta->mac_id, raid , tx_ra_bitmap, arg);
+ __func__, psta->mac_id, raid, tx_ra_bitmap, arg);
/* bitmap[0:27] = tx_rate_bitmap */
/* bitmap[28:31]= Rate Adaptive id */
diff --git a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
index e4b7ee4c99d5..cd12dd70dd88 100644
--- a/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
+++ b/drivers/staging/rtl8188eu/core/rtw_mlme_ext.c
@@ -484,17 +484,8 @@ void mgt_dispatcher(struct adapter *padapter, struct recv_frame *precv_frame)
/* fall through */
case WIFI_ASSOCREQ:
case WIFI_REASSOCREQ:
- _mgt_dispatcher(padapter, ptable, precv_frame);
- break;
case WIFI_PROBEREQ:
- if (check_fwstate(pmlmepriv, WIFI_AP_STATE))
- _mgt_dispatcher(padapter, ptable, precv_frame);
- else
- _mgt_dispatcher(padapter, ptable, precv_frame);
- break;
case WIFI_BEACON:
- _mgt_dispatcher(padapter, ptable, precv_frame);
- break;
case WIFI_ACTION:
_mgt_dispatcher(padapter, ptable, precv_frame);
break;
@@ -577,13 +568,14 @@ unsigned int OnBeacon(struct adapter *padapter, struct recv_frame *precv_frame)
uint len = precv_frame->len;
struct wlan_bssid_ex *pbss;
int ret = _SUCCESS;
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
if (pmlmeext->sitesurvey_res.state == SCAN_PROCESS) {
report_survey_event(padapter, precv_frame);
return _SUCCESS;
}
- if (!memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network), ETH_ALEN)) {
+ if (!memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN)) {
if (pmlmeinfo->state & WIFI_FW_AUTH_NULL) {
/* we should update current network before auth, or some IE is wrong */
pbss = (struct wlan_bssid_ex *)rtw_malloc(sizeof(struct wlan_bssid_ex));
@@ -1445,10 +1437,10 @@ unsigned int OnDeAuth(struct adapter *padapter, struct recv_frame *precv_frame)
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
u8 *pframe = precv_frame->rx_data;
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* check A3 */
- if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network),
- ETH_ALEN))
+ if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN))
return _SUCCESS;
reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
@@ -1499,10 +1491,10 @@ unsigned int OnDisassoc(struct adapter *padapter, struct recv_frame *precv_frame
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
u8 *pframe = precv_frame->rx_data;
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* check A3 */
- if (memcmp(GetAddr3Ptr(pframe), get_my_bssid(&pmlmeinfo->network),
- ETH_ALEN))
+ if (memcmp(GetAddr3Ptr(pframe), pnetwork->MacAddress, ETH_ALEN))
return _SUCCESS;
reason = le16_to_cpu(*(__le16 *)(pframe + WLAN_HDR_A3_LEN));
@@ -2018,7 +2010,7 @@ void issue_beacon(struct adapter *padapter, int timeout_ms)
memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
/* pmlmeext->mgnt_seq++; */
@@ -2422,6 +2414,7 @@ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
@@ -2487,9 +2480,9 @@ void issue_auth(struct adapter *padapter, struct sta_info *psta, unsigned short
} else {
__le32 le_tmp32;
__le16 le_tmp16;
- memcpy(pwlanhdr->addr1, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+ memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&padapter->eeprompriv), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&pmlmeinfo->network), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
/* setting auth algo number */
val16 = (pmlmeinfo->auth_algo == dot11AuthAlgrthm_Shared) ? 1 : 0;/* 0:OPEN System, 1:Shared key */
@@ -2582,7 +2575,7 @@ void issue_asocrsp(struct adapter *padapter, unsigned short status, struct sta_i
memcpy((void *)GetAddr1Ptr(pwlanhdr), pstat->hwaddr, ETH_ALEN);
memcpy((void *)GetAddr2Ptr(pwlanhdr), myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy((void *)GetAddr3Ptr(pwlanhdr), get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy((void *)GetAddr3Ptr(pwlanhdr), pnetwork->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
@@ -2687,6 +2680,7 @@ void issue_assocreq(struct adapter *padapter)
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
int bssrate_len = 0, sta_bssrate_len = 0;
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
@@ -2702,9 +2696,9 @@ void issue_assocreq(struct adapter *padapter)
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
- memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
@@ -2879,6 +2873,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned
struct xmit_priv *pxmitpriv;
struct mlme_ext_priv *pmlmeext;
struct mlme_ext_info *pmlmeinfo;
+ struct wlan_bssid_ex *pnetwork;
if (!padapter)
goto exit;
@@ -2886,6 +2881,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned
pxmitpriv = &(padapter->xmitpriv);
pmlmeext = &(padapter->mlmeextpriv);
pmlmeinfo = &(pmlmeext->mlmext_info);
+ pnetwork = &(pmlmeinfo->network);
pmgntframe = alloc_mgtxmitframe(pxmitpriv);
if (pmgntframe == NULL)
@@ -2914,7 +2910,7 @@ static int _issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned
memcpy(pwlanhdr->addr1, da, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
@@ -2946,10 +2942,11 @@ int issue_nulldata(struct adapter *padapter, unsigned char *da, unsigned int pow
u32 start = jiffies;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* da == NULL, assume it's null data for sta to ap*/
if (da == NULL)
- da = get_my_bssid(&(pmlmeinfo->network));
+ da = pnetwork->MacAddress;
do {
ret = _issue_nulldata(padapter, da, power_mode, wait_ms > 0 ? true : false);
@@ -2995,6 +2992,7 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
DBG_88E("%s\n", __func__);
@@ -3038,7 +3036,7 @@ static int _issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16
memcpy(pwlanhdr->addr1, da, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
@@ -3069,10 +3067,11 @@ int issue_qos_nulldata(struct adapter *padapter, unsigned char *da, u16 tid, int
u32 start = jiffies;
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* da == NULL, assume it's null data for sta to ap*/
if (da == NULL)
- da = get_my_bssid(&(pmlmeinfo->network));
+ da = pnetwork->MacAddress;
do {
ret = _issue_qos_nulldata(padapter, da, tid, wait_ms > 0 ? true : false);
@@ -3115,6 +3114,7 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned s
struct xmit_priv *pxmitpriv = &(padapter->xmitpriv);
struct mlme_ext_priv *pmlmeext = &(padapter->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
int ret = _FAIL;
__le16 le_tmp;
@@ -3137,7 +3137,7 @@ static int _issue_deauth(struct adapter *padapter, unsigned char *da, unsigned s
memcpy(pwlanhdr->addr1, da, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
@@ -3288,6 +3288,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
struct sta_info *psta;
struct sta_priv *pstapriv = &padapter->stapriv;
struct registry_priv *pregpriv = &padapter->registrypriv;
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
DBG_88E("%s, category=%d, action=%d, status=%d\n", __func__, category, action, status);
@@ -3310,7 +3311,7 @@ void issue_action_BA(struct adapter *padapter, unsigned char *raddr, unsigned ch
/* memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN); */
memcpy(pwlanhdr->addr1, raddr, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
@@ -3420,6 +3421,8 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
struct __queue *queue = &(pmlmepriv->scanned_queue);
u8 InfoContent[16] = {0};
u8 ICS[8][15];
+ struct wlan_bssid_ex *cur_network = &(pmlmeinfo->network);
+
if ((pmlmepriv->num_FortyMHzIntolerant == 0) || (pmlmepriv->num_sta_no_ht == 0))
return;
@@ -3449,9 +3452,9 @@ static void issue_action_BSSCoexistPacket(struct adapter *padapter)
fctrl = &(pwlanhdr->frame_ctl);
*(fctrl) = 0;
- memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr1, cur_network->MacAddress, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(padapter->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, pmlmeext->mgnt_seq);
pmlmeext->mgnt_seq++;
@@ -4042,9 +4045,10 @@ unsigned int receive_disconnect(struct adapter *padapter, unsigned char *MacAddr
{
struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv;
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
/* check A3 */
- if (memcmp(MacAddr, get_my_bssid(&pmlmeinfo->network), ETH_ALEN))
+ if (memcmp(MacAddr, pnetwork->MacAddress, ETH_ALEN))
return _SUCCESS;
DBG_88E("%s\n", __func__);
@@ -4924,11 +4928,6 @@ void addba_timer_hdl(void *function_context)
}
}
-u8 NULL_hdl(struct adapter *padapter, u8 *pbuf)
-{
- return H2C_SUCCESS;
-}
-
u8 setopmode_hdl(struct adapter *padapter, u8 *pbuf)
{
u8 type;
diff --git a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
index 324c1a7fd0bc..a3ffc691be9a 100644
--- a/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
+++ b/drivers/staging/rtl8188eu/core/rtw_wlan_util.c
@@ -405,11 +405,6 @@ int get_bsstype(unsigned short capability)
return 0;
}
-__inline u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork)
-{
- return pnetwork->MacAddress;
-}
-
u16 get_beacon_interval(struct wlan_bssid_ex *bss)
{
__le16 val;
@@ -936,6 +931,8 @@ int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len)
}
bssid = kzalloc(sizeof(struct wlan_bssid_ex), GFP_ATOMIC);
+ if (!bssid)
+ return _FAIL;
subtype = GetFrameSubType(pframe) >> 4;
diff --git a/drivers/staging/rtl8188eu/hal/odm.c b/drivers/staging/rtl8188eu/hal/odm.c
index 9873998011d2..06477e834653 100644
--- a/drivers/staging/rtl8188eu/hal/odm.c
+++ b/drivers/staging/rtl8188eu/hal/odm.c
@@ -534,13 +534,8 @@ void odm_DIGInit(struct odm_dm_struct *pDM_Odm)
pDM_DigTable->RssiHighThresh = DM_DIG_THRESH_HIGH;
pDM_DigTable->FALowThresh = DM_false_ALARM_THRESH_LOW;
pDM_DigTable->FAHighThresh = DM_false_ALARM_THRESH_HIGH;
- if (pDM_Odm->BoardType == ODM_BOARD_HIGHPWR) {
- pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
- pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
- } else {
- pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
- pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
- }
+ pDM_DigTable->rx_gain_range_max = DM_DIG_MAX_NIC;
+ pDM_DigTable->rx_gain_range_min = DM_DIG_MIN_NIC;
pDM_DigTable->BackoffVal = DM_DIG_BACKOFF_DEFAULT;
pDM_DigTable->BackoffVal_range_max = DM_DIG_BACKOFF_MAX;
pDM_DigTable->BackoffVal_range_min = DM_DIG_BACKOFF_MIN;
@@ -1138,16 +1133,9 @@ static void FindMinimumRSSI(struct adapter *pAdapter)
{
struct hal_data_8188e *pHalData = GET_HAL_DATA(pAdapter);
struct dm_priv *pdmpriv = &pHalData->dmpriv;
- struct mlme_priv *pmlmepriv = &pAdapter->mlmepriv;
-
- /* 1 1.Determine the minimum RSSI */
- if ((check_fwstate(pmlmepriv, _FW_LINKED) == false) &&
- (pdmpriv->EntryMinUndecoratedSmoothedPWDB == 0))
- pdmpriv->MinUndecoratedPWDBForDM = 0;
- if (check_fwstate(pmlmepriv, _FW_LINKED) == true) /* Default port */
- pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
- else /* associated entry pwdb */
- pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
+
+ /* 1 1.Unconditionally set RSSI */
+ pdmpriv->MinUndecoratedPWDBForDM = pdmpriv->EntryMinUndecoratedSmoothedPWDB;
}
void odm_RSSIMonitorCheckCE(struct odm_dm_struct *pDM_Odm)
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
index 7f30dea1b53b..86347f2ccdfd 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_cmd.c
@@ -127,22 +127,6 @@ exit:
return ret;
}
-u8 rtl8188e_set_rssi_cmd(struct adapter *adapt, u8 *param)
-{
- u8 res = _SUCCESS;
- struct hal_data_8188e *haldata = GET_HAL_DATA(adapt);
-
- if (haldata->fw_ractrl) {
- ;
- } else {
- DBG_88E("==>%s fw dont support RA\n", __func__);
- res = _FAIL;
- }
-
-
- return res;
-}
-
u8 rtl8188e_set_raid_cmd(struct adapter *adapt, u32 mask)
{
u8 buf[3];
@@ -276,7 +260,7 @@ static void ConstructBeacon(struct adapter *adapt, u8 *pframe, u32 *pLength)
memcpy(pwlanhdr->addr1, bc_addr, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(cur_network), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, cur_network->MacAddress, ETH_ALEN);
SetSeqNum(pwlanhdr, 0/*pmlmeext->mgnt_seq*/);
SetFrameSubType(pframe, WIFI_BEACON);
@@ -350,6 +334,7 @@ static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength)
struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
__le16 *fctrl;
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
@@ -363,7 +348,7 @@ static void ConstructPSPoll(struct adapter *adapt, u8 *pframe, u32 *pLength)
SetDuration(pframe, (pmlmeinfo->aid | 0xc000));
/* BSSID. */
- memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
/* TA. */
memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
@@ -386,6 +371,7 @@ static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
struct wlan_network *cur_network = &pmlmepriv->cur_network;
struct mlme_ext_priv *pmlmeext = &(adapt->mlmeextpriv);
struct mlme_ext_info *pmlmeinfo = &(pmlmeext->mlmext_info);
+ struct wlan_bssid_ex *pnetwork = &(pmlmeinfo->network);
pwlanhdr = (struct rtw_ieee80211_hdr *)pframe;
@@ -397,21 +383,21 @@ static void ConstructNullFunctionData(struct adapter *adapt, u8 *pframe,
switch (cur_network->network.InfrastructureMode) {
case Ndis802_11Infrastructure:
SetToDs(fctrl);
- memcpy(pwlanhdr->addr1, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr1, pnetwork->MacAddress, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
memcpy(pwlanhdr->addr3, StaAddr, ETH_ALEN);
break;
case Ndis802_11APMode:
SetFrDs(fctrl);
memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
- memcpy(pwlanhdr->addr2, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr2, pnetwork->MacAddress, ETH_ALEN);
memcpy(pwlanhdr->addr3, myid(&(adapt->eeprompriv)), ETH_ALEN);
break;
case Ndis802_11IBSS:
default:
memcpy(pwlanhdr->addr1, StaAddr, ETH_ALEN);
memcpy(pwlanhdr->addr2, myid(&(adapt->eeprompriv)), ETH_ALEN);
- memcpy(pwlanhdr->addr3, get_my_bssid(&(pmlmeinfo->network)), ETH_ALEN);
+ memcpy(pwlanhdr->addr3, pnetwork->MacAddress, ETH_ALEN);
break;
}
@@ -498,6 +484,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
u16 BufIndex;
u32 TotalPacketLen;
struct rsvdpage_loc RsvdPageLoc;
+ struct wlan_bssid_ex *pnetwork;
DBG_88E("%s\n", __func__);
ReservedPagePacket = kzalloc(1000, GFP_KERNEL);
@@ -510,6 +497,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
pxmitpriv = &adapt->xmitpriv;
pmlmeext = &adapt->mlmeextpriv;
pmlmeinfo = &pmlmeext->mlmext_info;
+ pnetwork = &(pmlmeinfo->network);
TxDescLen = TXDESC_SIZE;
PageNum = 0;
@@ -541,7 +529,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
/* 3 (3) null data * 1 page */
RsvdPageLoc.LocNullData = PageNum;
- ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, get_my_bssid(&pmlmeinfo->network), false, 0, 0, false);
+ ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex], &NullDataLength, pnetwork->MacAddress, false, 0, 0, false);
rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], NullDataLength, false, false);
PageNeed = (u8)PageNum_128(TxDescLen + NullDataLength);
@@ -551,7 +539,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
/* 3 (4) probe response * 1page */
RsvdPageLoc.LocProbeRsp = PageNum;
- ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, get_my_bssid(&pmlmeinfo->network), false);
+ ConstructProbeRsp(adapt, &ReservedPagePacket[BufIndex], &ProbeRspLength, pnetwork->MacAddress, false);
rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], ProbeRspLength, false, false);
PageNeed = (u8)PageNum_128(TxDescLen + ProbeRspLength);
@@ -562,7 +550,7 @@ static void SetFwRsvdPagePkt(struct adapter *adapt, bool bDLFinished)
/* 3 (5) Qos null data */
RsvdPageLoc.LocQosNull = PageNum;
ConstructNullFunctionData(adapt, &ReservedPagePacket[BufIndex],
- &QosNullLength, get_my_bssid(&pmlmeinfo->network), true, 0, 0, false);
+ &QosNullLength, pnetwork->MacAddress, true, 0, 0, false);
rtl8188e_fill_fake_txdesc(adapt, &ReservedPagePacket[BufIndex-TxDescLen], QosNullLength, false, false);
PageNeed = (u8)PageNum_128(TxDescLen + QosNullLength);
diff --git a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
index 7d460eaafa35..3222d8d08b5b 100644
--- a/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
+++ b/drivers/staging/rtl8188eu/hal/rtl8188e_hal_init.c
@@ -242,20 +242,6 @@ void rtl8188e_set_hal_ops(struct hal_ops *pHalFunc)
pHalFunc->hal_notch_filter = &hal_notch_filter_8188e;
}
-u8 GetEEPROMSize8188E(struct adapter *padapter)
-{
- u8 size = 0;
- u32 cr;
-
- cr = usb_read16(padapter, REG_9346CR);
- /* 6: EEPROM used is 93C46, 4: boot from E-Fuse. */
- size = (cr & BOOT_FROM_EEPROM) ? 6 : 4;
-
- MSG_88E("EEPROM type is %s\n", size == 4 ? "E-FUSE" : "93C46");
-
- return size;
-}
-
/* */
/* */
/* LLT R/W/Init function */
diff --git a/drivers/staging/rtl8188eu/include/osdep_service.h b/drivers/staging/rtl8188eu/include/osdep_service.h
index 82f58f87656a..3a274770364b 100644
--- a/drivers/staging/rtl8188eu/include/osdep_service.h
+++ b/drivers/staging/rtl8188eu/include/osdep_service.h
@@ -87,7 +87,7 @@ static inline void _init_timer(struct timer_list *ptimer,
static inline void _set_timer(struct timer_list *ptimer, u32 delay_time)
{
- mod_timer(ptimer , (jiffies+(delay_time*HZ/1000)));
+ mod_timer(ptimer , (jiffies+msecs_to_jiffies(delay_time)));
}
#define RTW_TIMER_HDL_ARGS void *FunctionContext
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
index 0e78e2a357bd..42b1f22424eb 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_cmd.h
@@ -107,7 +107,6 @@ struct P2P_PS_CTWPeriod_t {
/* host message to firmware cmd */
void rtl8188e_set_FwPwrMode_cmd(struct adapter *padapter, u8 Mode);
void rtl8188e_set_FwJoinBssReport_cmd(struct adapter *padapter, u8 mstatus);
-u8 rtl8188e_set_rssi_cmd(struct adapter *padapter, u8 *param);
u8 rtl8188e_set_raid_cmd(struct adapter *padapter, u32 mask);
void rtl8188e_Add_RateATid(struct adapter *padapter, u32 bitmap, u8 arg,
u8 rssi_level);
diff --git a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
index 42ab1d288bdc..b8c42eed98c4 100644
--- a/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
+++ b/drivers/staging/rtl8188eu/include/rtl8188e_hal.h
@@ -391,7 +391,6 @@ void rtl8188e_InitializeFirmwareVars(struct adapter *padapter);
s32 InitLLTTable(struct adapter *padapter, u8 txpktbuf_bndy);
/* EFuse */
-u8 GetEEPROMSize8188E(struct adapter *padapter);
void Hal_InitPGData88E(struct adapter *padapter);
void Hal_EfuseParseIDCode88E(struct adapter *padapter, u8 *hwinfo);
void Hal_ReadTxPowerInfo88E(struct adapter *padapter, u8 *hwinfo,
diff --git a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
index 8d72ccf5f2a0..4f05aee93c9c 100644
--- a/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8188eu/include/rtw_mlme_ext.h
@@ -496,7 +496,6 @@ void update_network(struct wlan_bssid_ex *dst, struct wlan_bssid_ex *src,
struct adapter *adapter, bool update_ie);
int get_bsstype(unsigned short capability);
-u8 *get_my_bssid(struct wlan_bssid_ex *pnetwork);
u16 get_beacon_interval(struct wlan_bssid_ex *bss);
int is_client_associated_to_ap(struct adapter *padapter);
@@ -516,7 +515,7 @@ void ERP_IE_handler(struct adapter *padapter, struct ndis_802_11_var_ie *pIE);
void VCS_update(struct adapter *padapter, struct sta_info *psta);
void update_beacon_info(struct adapter *padapter, u8 *pframe, uint len,
- struct sta_info *psta);
+ struct sta_info *psta);
int rtw_check_bcn_info(struct adapter *Adapter, u8 *pframe, u32 packet_len);
void update_IOT_info(struct adapter *padapter);
void update_capinfo(struct adapter *adapter, u16 updatecap);
@@ -679,7 +678,6 @@ u8 read_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
u8 write_bbreg_hdl(struct adapter *padapter, u8 *pbuf);
u8 read_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
u8 write_rfreg_hdl(struct adapter *padapter, u8 *pbuf);
-u8 NULL_hdl(struct adapter *padapter, u8 *pbuf);
u8 join_cmd_hdl(struct adapter *padapter, u8 *pbuf);
u8 disconnect_hdl(struct adapter *padapter, u8 *pbuf);
u8 createbss_hdl(struct adapter *padapter, u8 *pbuf);
diff --git a/drivers/staging/rtl8188eu/include/usb_ops_linux.h b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
index 01b3810379ec..4fdc536cba79 100644
--- a/drivers/staging/rtl8188eu/include/usb_ops_linux.h
+++ b/drivers/staging/rtl8188eu/include/usb_ops_linux.h
@@ -79,7 +79,6 @@ void usb_read_port_cancel(struct adapter *adapter);
int usb_write8(struct adapter *adapter, u32 addr, u8 val);
int usb_write16(struct adapter *adapter, u32 addr, u16 val);
int usb_write32(struct adapter *adapter, u32 addr, u32 val);
-int usb_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata);
u32 usb_write_port(struct adapter *adapter, u32 addr, u32 cnt, u8 *pmem);
void usb_write_port_cancel(struct adapter *adapter);
diff --git a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
index d2efa9dfc8c0..80e7ef96d807 100644
--- a/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
+++ b/drivers/staging/rtl8188eu/os_dep/usb_ops_linux.c
@@ -615,33 +615,6 @@ int usb_write32(struct adapter *adapter, u32 addr, u32 val)
return ret;
}
-int usb_writeN(struct adapter *adapter, u32 addr, u32 length, u8 *pdata)
-{
- u8 request;
- u8 requesttype;
- u16 wvalue;
- u16 index;
- u16 len;
- u8 buf[VENDOR_CMD_MAX_DATA_LEN] = {0};
- int ret;
-
-
- request = 0x05;
- requesttype = 0x00;/* write_out */
- index = 0;/* n/a */
-
- wvalue = (u16)(addr&0x0000ffff);
- len = length;
- memcpy(buf, pdata, len);
-
- ret = usbctrl_vendorreq(adapter, request, wvalue, index, buf, len, requesttype);
-
-
- return RTW_STATUS_CODE(ret);
-}
-
-
-
static void usb_write_port_complete(struct urb *purb, struct pt_regs *regs)
{
struct xmit_buf *pxmitbuf = (struct xmit_buf *)purb->context;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
index 6c64e0899ffd..89ea70b0d3aa 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.c
@@ -167,35 +167,6 @@ void setKey(struct net_device *dev, u8 EntryNo, u8 KeyIndex, u16 KeyType,
RT_TRACE(COMP_SEC, "=========>after set key, usconfig:%x\n", usConfig);
}
-void CAM_read_entry(struct net_device *dev, u32 iIndex)
-{
- u32 target_command = 0;
- u32 target_content = 0;
- u8 entry_i = 0;
- u32 ulStatus;
- s32 i = 100;
-
- for (entry_i = 0; entry_i < CAM_CONTENT_COUNT; entry_i++) {
- target_command = entry_i+CAM_CONTENT_COUNT*iIndex;
- target_command = target_command | BIT31;
-
- while ((i--) >= 0) {
- ulStatus = read_nic_dword(dev, RWCAM);
- if (ulStatus & BIT31)
- continue;
- else
- break;
- }
- write_nic_dword(dev, RWCAM, target_command);
- RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A0: %x\n",
- target_command);
- target_content = read_nic_dword(dev, RCAMO);
- RT_TRACE(COMP_SEC, "CAM_read_entry(): WRITE A8: %x\n",
- target_content);
- }
- printk(KERN_INFO "\n");
-}
-
void CamRestoreAllEntry(struct net_device *dev)
{
u8 EntryId = 0;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
index 7d075d3cbe62..3c4c0e61c181 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_cam.h
@@ -41,6 +41,4 @@ void write_cam(struct net_device *dev, u8 addr, u32 data);
void CamRestoreAllEntry(struct net_device *dev);
-void CAM_read_entry(struct net_device *dev, u32 iIndex);
-
#endif
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
index 885315cac3a4..b8891c62af3e 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_dm.c
@@ -1661,8 +1661,8 @@ void dm_change_dynamic_initgain_thresh(struct net_device *dev,
dm_digtable.rssi_low_thresh = dm_value;
} else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
dm_digtable.rssi_high_power_highthresh = dm_value;
- } else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
- dm_digtable.rssi_high_power_highthresh = dm_value;
+ } else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_LOW) {
+ dm_digtable.rssi_high_power_lowthresh = dm_value;
} else if (dm_type == DIG_TYPE_ENABLE) {
dm_digtable.dig_state = DM_STA_DIG_MAX;
dm_digtable.dig_enable_flag = true;
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
index 8e1a5d55dce8..0b4f76481bf4 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.c
@@ -22,12 +22,6 @@
#include "r8190P_rtl8256.h"
#include "rtl_pm.h"
-int rtl8192E_save_state(struct pci_dev *dev, pm_message_t state)
-{
- printk(KERN_NOTICE "r8192E save state call (state %u).\n", state.event);
- return -EAGAIN;
-}
-
int rtl8192E_suspend(struct pci_dev *pdev, pm_message_t state)
{
@@ -124,11 +118,3 @@ out:
return 0;
}
-
-int rtl8192E_enable_wake(struct pci_dev *dev, pm_message_t state, int enable)
-{
- printk(KERN_NOTICE "r8192E enable wake call (state %u, enable %d).\n",
- state.event, enable);
- return -EAGAIN;
-}
-
diff --git a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
index e5299fc3b34a..7bfe44817f23 100644
--- a/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
+++ b/drivers/staging/rtl8192e/rtl8192e/rtl_pm.h
@@ -23,9 +23,7 @@
#include <linux/types.h>
#include <linux/pci.h>
-int rtl8192E_save_state(struct pci_dev *dev, pm_message_t state);
int rtl8192E_suspend(struct pci_dev *dev, pm_message_t state);
int rtl8192E_resume(struct pci_dev *dev);
-int rtl8192E_enable_wake(struct pci_dev *dev, pm_message_t state, int enable);
#endif
diff --git a/drivers/staging/rtl8192e/rtl819x_HTProc.c b/drivers/staging/rtl8192e/rtl819x_HTProc.c
index c7f45080061f..1ea426b7b7ac 100644
--- a/drivers/staging/rtl8192e/rtl819x_HTProc.c
+++ b/drivers/staging/rtl8192e/rtl819x_HTProc.c
@@ -34,13 +34,13 @@ u16 MCS_DATA_RATE[2][2][77] = {
468, 520, 0, 78, 104, 130, 117, 156, 195, 104, 130, 130, 156, 182,
182, 208, 156, 195, 195, 234, 273, 273, 312, 130, 156, 181, 156,
181, 208, 234, 208, 234, 260, 260, 286, 195, 234, 273, 234, 273,
- 312, 351, 312, 351, 390, 390, 429} ,
+ 312, 351, 312, 351, 390, 390, 429},
{14, 29, 43, 58, 87, 116, 130, 144, 29, 58, 87, 116, 173, 231, 260, 289,
43, 87, 130, 173, 260, 347, 390, 433, 58, 116, 173, 231, 347, 462, 520,
578, 0, 87, 116, 144, 130, 173, 217, 116, 144, 144, 173, 202, 202, 231,
173, 217, 217, 260, 303, 303, 347, 144, 173, 202, 173, 202, 231, 260,
231, 260, 289, 289, 318, 217, 260, 303, 260, 303, 347, 390, 347, 390,
- 433, 433, 477} } ,
+ 433, 433, 477} },
{{27, 54, 81, 108, 162, 216, 243, 270, 54, 108, 162, 216, 324, 432, 486,
540, 81, 162, 243, 324, 486, 648, 729, 810, 108, 216, 324, 432, 648,
864, 972, 1080, 12, 162, 216, 270, 243, 324, 405, 216, 270, 270, 324,
diff --git a/drivers/staging/rtl8192e/rtllib_module.c b/drivers/staging/rtl8192e/rtllib_module.c
index 91e98e8e5bfc..0cf38091f8c5 100644
--- a/drivers/staging/rtl8192e/rtllib_module.c
+++ b/drivers/staging/rtl8192e/rtllib_module.c
@@ -202,9 +202,7 @@ void free_rtllib(struct net_device *dev)
EXPORT_SYMBOL(free_rtllib);
u32 rtllib_debug_level;
-static int debug = \
- RTLLIB_DL_ERR
- ;
+static int debug = RTLLIB_DL_ERR;
static struct proc_dir_entry *rtllib_proc;
static int show_debug_level(struct seq_file *m, void *v)
diff --git a/drivers/staging/rtl8192e/rtllib_rx.c b/drivers/staging/rtl8192e/rtllib_rx.c
index cf11b042b93a..1664040efdab 100644
--- a/drivers/staging/rtl8192e/rtllib_rx.c
+++ b/drivers/staging/rtl8192e/rtllib_rx.c
@@ -70,8 +70,7 @@ rtllib_frag_cache_find(struct rtllib_device *ieee, unsigned int seq,
if (entry->skb != NULL &&
time_after(jiffies, entry->first_frag_time + 2 * HZ)) {
RTLLIB_DEBUG_FRAG(
- "expiring fragment cache entry "
- "seq=%u last_frag=%u\n",
+ "expiring fragment cache entry seq=%u last_frag=%u\n",
entry->seq, entry->last_frag);
dev_kfree_skb_any(entry->skb);
entry->skb = NULL;
@@ -188,8 +187,7 @@ static int rtllib_frag_cache_invalidate(struct rtllib_device *ieee,
if (entry == NULL) {
RTLLIB_DEBUG_FRAG(
- "could not invalidate fragment cache "
- "entry (seq=%u)\n", seq);
+ "could not invalidate fragment cache entry (seq=%u)\n", seq);
return -1;
}
@@ -305,11 +303,9 @@ rtllib_rx_frame_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
atomic_dec(&crypt->refcnt);
if (res < 0) {
RTLLIB_DEBUG_DROP(
- "decryption failed (SA= %pM"
- ") res=%d\n", hdr->addr2, res);
+ "decryption failed (SA= %pM) res=%d\n", hdr->addr2, res);
if (res == -2)
- RTLLIB_DEBUG_DROP("Decryption failed ICV "
- "mismatch (key %d)\n",
+ RTLLIB_DEBUG_DROP("Decryption failed ICV mismatch (key %d)\n",
skb->data[hdrlen + 3] >> 6);
ieee->ieee_stats.rx_discards_undecryptable++;
return -1;
@@ -345,8 +341,7 @@ rtllib_rx_frame_decrypt_msdu(struct rtllib_device *ieee, struct sk_buff *skb,
res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
atomic_dec(&crypt->refcnt);
if (res < 0) {
- printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed"
- " (SA= %pM keyidx=%d)\n",
+ printk(KERN_DEBUG "%s: MSDU decryption/MIC verification failed (SA= %pM keyidx=%d)\n",
ieee->dev->name, hdr->addr2, keyidx);
return -1;
}
@@ -559,8 +554,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
bool bMatchWinStart = false, bPktInBuf = false;
unsigned long flags;
- RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Seq is %d, pTS->RxIndicateSeq"
- " is %d, WinSize is %d\n", __func__, SeqNum,
+ RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Seq is %d, pTS->RxIndicateSeq is %d, WinSize is %d\n", __func__, SeqNum,
pTS->RxIndicateSeq, WinSize);
spin_lock_irqsave(&(ieee->reorder_spinlock), flags);
@@ -600,8 +594,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
pTS->RxIndicateSeq = SeqNum + 1 - WinSize;
else
pTS->RxIndicateSeq = 4095 - (WinSize - (SeqNum + 1)) + 1;
- RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Window Shift! IndicateSeq: %d,"
- " NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum);
+ RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Window Shift! IndicateSeq: %d, NewSeq: %d\n", pTS->RxIndicateSeq, SeqNum);
}
/*
@@ -617,8 +610,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
*/
if (bMatchWinStart) {
/* Current packet is going to be indicated.*/
- RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Packets indication!! "
- "IndicateSeq: %d, NewSeq: %d\n",
+ RTLLIB_DEBUG(RTLLIB_DL_REORDER, "Packets indication!! IndicateSeq: %d, NewSeq: %d\n",
pTS->RxIndicateSeq, SeqNum);
ieee->prxbIndicateArray[0] = prxb;
index = 1;
@@ -636,9 +628,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
if (!AddReorderEntry(pTS, pReorderEntry)) {
RTLLIB_DEBUG(RTLLIB_DL_REORDER,
- "%s(): Duplicate packet is "
- "dropped!! IndicateSeq: %d, "
- "NewSeq: %d\n",
+ "%s(): Duplicate packet is dropped!! IndicateSeq: %d, NewSeq: %d\n",
__func__, pTS->RxIndicateSeq,
SeqNum);
list_add_tail(&pReorderEntry->List,
@@ -652,8 +642,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
}
} else {
RTLLIB_DEBUG(RTLLIB_DL_REORDER,
- "Pkt insert into struct buffer!! "
- "IndicateSeq: %d, NewSeq: %d\n",
+ "Pkt insert into struct buffer!! IndicateSeq: %d, NewSeq: %d\n",
pTS->RxIndicateSeq, SeqNum);
}
} else {
@@ -663,9 +652,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
* indicate all the packets in struct buffer and get
* reorder entries.
*/
- RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket():"
- " There is no reorder entry!! Packet is "
- "dropped!!\n");
+ RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): There is no reorder entry!! Packet is dropped!!\n");
{
int i;
@@ -687,8 +674,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
SN_EQUAL(pReorderEntry->SeqNum, pTS->RxIndicateSeq)) {
/* This protect struct buffer from overflow. */
if (index >= REORDER_WIN_SIZE) {
- RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicate"
- "Packet(): Buffer overflow!!\n");
+ RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): Buffer overflow!!\n");
bPktInBuf = true;
break;
}
@@ -699,8 +685,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
pTS->RxIndicateSeq = (pTS->RxIndicateSeq + 1) % 4096;
ieee->prxbIndicateArray[index] = pReorderEntry->prxb;
- RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Indicate SeqNum"
- " %d!\n", __func__, pReorderEntry->SeqNum);
+ RTLLIB_DEBUG(RTLLIB_DL_REORDER, "%s(): Indicate SeqNum %d!\n", __func__, pReorderEntry->SeqNum);
index++;
list_add_tail(&pReorderEntry->List,
@@ -719,8 +704,7 @@ static void RxReorderIndicatePacket(struct rtllib_device *ieee,
pTS->RxTimeoutIndicateSeq = 0xffff;
if (index > REORDER_WIN_SIZE) {
- RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket():"
- " Rx Reorder struct buffer full!!\n");
+ RTLLIB_DEBUG(RTLLIB_DL_ERR, "RxReorderIndicatePacket(): Rx Reorder struct buffer full!!\n");
spin_unlock_irqrestore(&(ieee->reorder_spinlock),
flags);
return;
@@ -809,14 +793,11 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
(nSubframe_Length << 8);
if (skb->len < (ETHERNET_HEADER_SIZE + nSubframe_Length)) {
- printk(KERN_INFO "%s: A-MSDU parse error!! "
- "pRfd->nTotalSubframe : %d\n",\
+ printk(KERN_INFO "%s: A-MSDU parse error!! pRfd->nTotalSubframe : %d\n",\
__func__, rxb->nr_subframes);
- printk(KERN_INFO "%s: A-MSDU parse error!! "
- "Subframe Length: %d\n", __func__,
+ printk(KERN_INFO "%s: A-MSDU parse error!! Subframe Length: %d\n", __func__,
nSubframe_Length);
- printk(KERN_INFO "nRemain_Length is %d and "
- "nSubframe_Length is : %d\n", skb->len,
+ printk(KERN_INFO "nRemain_Length is %d and nSubframe_Length is : %d\n", skb->len,
nSubframe_Length);
printk(KERN_INFO "The Packet SeqNum is %d\n", SeqNum);
return 0;
@@ -844,8 +825,7 @@ static u8 parse_subframe(struct rtllib_device *ieee, struct sk_buff *skb,
sub_skb->dev = ieee->dev;
rxb->subframes[rxb->nr_subframes++] = sub_skb;
if (rxb->nr_subframes >= MAX_SUBFRAME_COUNT) {
- RTLLIB_DEBUG_RX("ParseSubframe(): Too many "
- "Subframes! Packets dropped!\n");
+ RTLLIB_DEBUG_RX("ParseSubframe(): Too many Subframes! Packets dropped!\n");
break;
}
skb_pull(skb, nSubframe_Length);
@@ -922,8 +902,7 @@ static int rtllib_rx_check_duplicate(struct rtllib_device *ieee,
pRxTS->RxLastFragNum = frag;
pRxTS->RxLastSeqNum = WLAN_GET_SEQ_SEQ(sc);
} else {
- RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR!!%s(): No TS!! Skip"
- " the check!!\n", __func__);
+ RTLLIB_DEBUG(RTLLIB_DL_ERR, "ERR!!%s(): No TS!! Skip the check!!\n", __func__);
return -1;
}
}
@@ -996,9 +975,7 @@ static int rtllib_rx_data_filter(struct rtllib_device *ieee, u16 fc,
stype != RTLLIB_STYPE_QOS_DATA) {
if (stype != RTLLIB_STYPE_NULLFUNC)
RTLLIB_DEBUG_DROP(
- "RX: dropped data frame "
- "with no data (type=0x%02x, "
- "subtype=0x%02x)\n",
+ "RX: dropped data frame with no data (type=0x%02x, subtype=0x%02x)\n",
type, stype);
return -1;
}
@@ -1041,8 +1018,7 @@ static int rtllib_rx_get_crypt(struct rtllib_device *ieee, struct sk_buff *skb,
* frames from other than current BSS, so just drop the
* frames silently instead of filling system log with
* these reports. */
- RTLLIB_DEBUG_DROP("Decryption failed (not set)"
- " (SA= %pM)\n",
+ RTLLIB_DEBUG_DROP("Decryption failed (not set) (SA= %pM)\n",
hdr->addr2);
ieee->ieee_stats.rx_discards_undecryptable++;
return -1;
@@ -1086,8 +1062,7 @@ static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
if (!frag_skb) {
RTLLIB_DEBUG(RTLLIB_DL_RX | RTLLIB_DL_FRAG,
- "Rx cannot get skb from fragment "
- "cache (morefrag=%d seq=%u frag=%u)\n",
+ "Rx cannot get skb from fragment cache (morefrag=%d seq=%u frag=%u)\n",
(fc & RTLLIB_FCTL_MOREFRAGS) != 0,
WLAN_GET_SEQ_SEQ(sc), frag);
return -1;
@@ -1097,8 +1072,7 @@ static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
flen -= hdrlen;
if (frag_skb->tail + flen > frag_skb->end) {
- printk(KERN_WARNING "%s: host decrypted and "
- "reassembled frame did not fit skb\n",
+ printk(KERN_WARNING "%s: host decrypted and reassembled frame did not fit skb\n",
__func__);
rtllib_frag_cache_invalidate(ieee, hdr);
return -1;
@@ -1152,8 +1126,7 @@ static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
eap_get_type(eap->type));
} else {
RTLLIB_DEBUG_DROP(
- "encryption configured, but RX "
- "frame not encrypted (SA= %pM)\n",
+ "encryption configured, but RX frame not encrypted (SA= %pM)\n",
hdr->addr2);
return -1;
}
@@ -1170,9 +1143,7 @@ static int rtllib_rx_decrypt(struct rtllib_device *ieee, struct sk_buff *skb,
if (crypt && !(fc & RTLLIB_FCTL_WEP) && !ieee->open_wep &&
!rtllib_is_eapol_frame(ieee, skb, hdrlen)) {
RTLLIB_DEBUG_DROP(
- "dropped unencrypted RX data "
- "frame from %pM"
- " (drop_unencrypted=1)\n",
+ "dropped unencrypted RX data frame from %pM (drop_unencrypted=1)\n",
hdr->addr2);
return -1;
}
@@ -1762,9 +1733,7 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
while (length >= sizeof(*info_element)) {
if (sizeof(*info_element) + info_element->len > length) {
- RTLLIB_DEBUG_MGMT("Info elem: parse failed: "
- "info_element->len + 2 > left : "
- "info_element->len+2=%zd left=%d, id=%d.\n",
+ RTLLIB_DEBUG_MGMT("Info elem: parse failed: info_element->len + 2 > left : info_element->len+2=%zd left=%d, id=%d.\n",
info_element->len +
sizeof(*info_element),
length, info_element->id);
@@ -2207,34 +2176,6 @@ int rtllib_parse_info_param(struct rtllib_device *ieee,
return 0;
}
-static inline u8 rtllib_SignalStrengthTranslate(u8 CurrSS)
-{
- u8 RetSS;
-
- if (CurrSS >= 71 && CurrSS <= 100)
- RetSS = 90 + ((CurrSS - 70) / 3);
- else if (CurrSS >= 41 && CurrSS <= 70)
- RetSS = 78 + ((CurrSS - 40) / 3);
- else if (CurrSS >= 31 && CurrSS <= 40)
- RetSS = 66 + (CurrSS - 30);
- else if (CurrSS >= 21 && CurrSS <= 30)
- RetSS = 54 + (CurrSS - 20);
- else if (CurrSS >= 5 && CurrSS <= 20)
- RetSS = 42 + (((CurrSS - 5) * 2) / 3);
- else if (CurrSS == 4)
- RetSS = 36;
- else if (CurrSS == 3)
- RetSS = 27;
- else if (CurrSS == 2)
- RetSS = 18;
- else if (CurrSS == 1)
- RetSS = 9;
- else
- RetSS = CurrSS;
-
- return RetSS;
-}
-
static long rtllib_translate_todbm(u8 signal_strength_index)
{
long signal_power;
@@ -2321,8 +2262,7 @@ static inline int rtllib_network_init(
}
if (network->mode == 0) {
- RTLLIB_DEBUG_SCAN("Filtered out '%s (%pM)' "
- "network.\n",
+ RTLLIB_DEBUG_SCAN("Filtered out '%s (%pM)' network.\n",
escape_essid(network->ssid,
network->ssid_len),
network->bssid);
@@ -2363,13 +2303,6 @@ static inline int is_same_network(struct rtllib_network *src,
(dst->capability & WLAN_CAPABILITY_ESS)));
}
-static inline void update_ibss_network(struct rtllib_network *dst,
- struct rtllib_network *src)
-{
- memcpy(&dst->stats, &src->stats, sizeof(struct rtllib_rx_stats));
- dst->last_scanned = jiffies;
-}
-
static inline void update_network(struct rtllib_network *dst,
struct rtllib_network *src)
@@ -2568,8 +2501,7 @@ static inline void rtllib_process_probe_response(
if (WLAN_FC_GET_STYPE(le16_to_cpu(beacon->header.frame_ctl)) ==
RTLLIB_STYPE_PROBE_RESP) {
if (IsPassiveChannel(ieee, network->channel)) {
- printk(KERN_INFO "GetScanInfo(): For Global Domain, "
- "filter probe response at channel(%d).\n",
+ printk(KERN_INFO "GetScanInfo(): For Global Domain, filter probe response at channel(%d).\n",
network->channel);
goto free_network;
}
@@ -2618,8 +2550,7 @@ static inline void rtllib_process_probe_response(
/* If there are no more slots, expire the oldest */
list_del(&oldest->list);
target = oldest;
- RTLLIB_DEBUG_SCAN("Expired '%s' ( %pM) from "
- "network list.\n",
+ RTLLIB_DEBUG_SCAN("Expired '%s' ( %pM) from network list.\n",
escape_essid(target->ssid,
target->ssid_len),
target->bssid);
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
index cd196cec0dd9..1b4623c3f95e 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_BAProc.c
@@ -4,6 +4,8 @@
* ADDBAREQ ADDBARSP and DELBA packet is still on consideration. Temporarily use MANAGE QUEUE instead of Normal Queue.
* WB 2008-05-27
* *****************************************************************************************************************************/
+#include <asm/byteorder.h>
+#include <asm/unaligned.h>
#include "ieee80211.h"
#include "rtl819x_BA.h"
@@ -110,13 +112,12 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P
struct sk_buff *skb = NULL;
struct ieee80211_hdr_3addr *BAReq = NULL;
u8 *tag = NULL;
- __le16 tmp = 0;
u16 len = ieee->tx_headroom + 9;
//category(1) + action field(1) + Dialog Token(1) + BA Parameter Set(2) + BA Timeout Value(2) + BA Start SeqCtrl(2)(or StatusCode(2))
IEEE80211_DEBUG(IEEE80211_DL_TRACE | IEEE80211_DL_BA, "========>%s(), frame(%d) sentd to:%pM, ieee->dev:%p\n", __func__, type, Dst, ieee->dev);
- if (pBA == NULL||ieee == NULL)
+ if (pBA == NULL)
{
- IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA(%p) is NULL or ieee(%p) is NULL\n", pBA, ieee);
+ IEEE80211_DEBUG(IEEE80211_DL_ERR, "pBA is NULL\n");
return NULL;
}
skb = dev_alloc_skb(len + sizeof( struct ieee80211_hdr_3addr)); //need to add something others? FIXME
@@ -149,17 +150,17 @@ static struct sk_buff *ieee80211_ADDBA(struct ieee80211_device *ieee, u8 *Dst, P
{
// Status Code
printk("=====>to send ADDBARSP\n");
- tmp = cpu_to_le16(StatusCode);
- memcpy(tag, (u8 *)&tmp, 2);
+
+ put_unaligned_le16(StatusCode, tag);
tag += 2;
}
// BA Parameter Set
- tmp = cpu_to_le16(pBA->BaParamSet.shortData);
- memcpy(tag, (u8 *)&tmp, 2);
+
+ put_unaligned_le16(pBA->BaParamSet.shortData, tag);
tag += 2;
// BA Timeout Value
- tmp = cpu_to_le16(pBA->BaTimeoutValue);
- memcpy(tag, (u8 *)&tmp, 2);
+
+ put_unaligned_le16(pBA->BaTimeoutValue, tag);
tag += 2;
if (ACT_ADDBAREQ == type)
@@ -196,7 +197,6 @@ static struct sk_buff *ieee80211_DELBA(
struct sk_buff *skb = NULL;
struct ieee80211_hdr_3addr *Delba = NULL;
u8 *tag = NULL;
- __le16 tmp = 0;
//len = head len + DELBA Parameter Set(2) + Reason Code(2)
u16 len = 6 + ieee->tx_headroom;
@@ -230,12 +230,12 @@ static struct sk_buff *ieee80211_DELBA(
*tag ++= ACT_DELBA;
// DELBA Parameter Set
- tmp = cpu_to_le16(DelbaParamSet.shortData);
- memcpy(tag, (u8 *)&tmp, 2);
+
+ put_unaligned_le16(DelbaParamSet.shortData, tag);
tag += 2;
// Reason Code
- tmp = cpu_to_le16(ReasonCode);
- memcpy(tag, (u8 *)&tmp, 2);
+
+ put_unaligned_le16(ReasonCode, tag);
tag += 2;
IEEE80211_DEBUG_DATA(IEEE80211_DL_DATA|IEEE80211_DL_BA, skb->data, skb->len);
diff --git a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
index c4514109d0ee..acaa723817e7 100644
--- a/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
+++ b/drivers/staging/rtl8192u/ieee80211/rtl819x_TSProc.c
@@ -241,7 +241,7 @@ static PTS_COMMON_INFO SearchAdmitTRStream(struct ieee80211_device *ieee,
{
//DIRECTION_VALUE dir;
u8 dir;
- bool search_dir[4] = {0, 0, 0, 0};
+ bool search_dir[4] = {0};
struct list_head *psearch_list; //FIXME
PTS_COMMON_INFO pRet = NULL;
if(ieee->iw_mode == IW_MODE_MASTER) //ap mode
diff --git a/drivers/staging/rtl8192u/r8190_rtl8256.c b/drivers/staging/rtl8192u/r8190_rtl8256.c
index 45514aa97698..1868352d3789 100644
--- a/drivers/staging/rtl8192u/r8190_rtl8256.c
+++ b/drivers/staging/rtl8192u/r8190_rtl8256.c
@@ -23,7 +23,7 @@
* Return: NONE
* Note: 8226 support both 20M and 40 MHz
*---------------------------------------------------------------------------*/
-void PHY_SetRF8256Bandwidth(struct net_device *dev , HT_CHANNEL_WIDTH Bandwidth)
+void PHY_SetRF8256Bandwidth(struct net_device *dev, HT_CHANNEL_WIDTH Bandwidth)
{
u8 eRFPath;
struct r8192_priv *priv = ieee80211_priv(dev);
diff --git a/drivers/staging/rtl8192u/r8192U_dm.c b/drivers/staging/rtl8192u/r8192U_dm.c
index 936565d46014..ee6b936efef2 100644
--- a/drivers/staging/rtl8192u/r8192U_dm.c
+++ b/drivers/staging/rtl8192u/r8192U_dm.c
@@ -21,14 +21,13 @@ Major Change History:
#include "r8190_rtl8256.h"
#include "r819xU_cmdpkt.h"
/*---------------------------Define Local Constant---------------------------*/
-//
-// Indicate different AP vendor for IOT issue.
-//
-static u32 edca_setting_DL[HT_IOT_PEER_MAX] =
- { 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0xa44f, 0x5ea44f};
-static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
- { 0x5e4322, 0xa44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f};
-
+/* Indicate different AP vendor for IOT issue. */
+static u32 edca_setting_DL[HT_IOT_PEER_MAX] = {
+ 0x5e4322, 0x5e4322, 0x5e4322, 0x604322, 0x00a44f, 0x5ea44f
+};
+static u32 edca_setting_UL[HT_IOT_PEER_MAX] = {
+ 0x5e4322, 0x00a44f, 0x5e4322, 0x604322, 0x5ea44f, 0x5ea44f
+};
#define RTK_UL_EDCA 0xa44f
#define RTK_DL_EDCA 0x5e4322
@@ -36,11 +35,11 @@ static u32 edca_setting_UL[HT_IOT_PEER_MAX] =
/*------------------------Define global variable-----------------------------*/
-// Debug variable ?
+/* Debug variable ? */
dig_t dm_digtable;
-// Store current software write register content for MAC PHY.
-u8 dm_shadow[16][256] = {{0}};
-// For Dynamic Rx Path Selection by Signal Strength
+/* Store current software write register content for MAC PHY. */
+u8 dm_shadow[16][256] = { {0} };
+/* For Dynamic Rx Path Selection by Signal Strength */
DRxPathSel DM_RxPathSelTable;
/*------------------------Define global variable-----------------------------*/
@@ -56,24 +55,21 @@ extern void dm_check_fsync(struct net_device *dev);
/*---------------------Define local function prototype-----------------------*/
-// DM --> Rate Adaptive
+/* DM --> Rate Adaptive */
static void dm_check_rate_adaptive(struct net_device *dev);
-// DM --> Bandwidth switch
+/* DM --> Bandwidth switch */
static void dm_init_bandwidth_autoswitch(struct net_device *dev);
static void dm_bandwidth_autoswitch(struct net_device *dev);
-// DM --> TX power control
-//static void dm_initialize_txpower_tracking(struct net_device *dev);
+/* DM --> TX power control */
+/*static void dm_initialize_txpower_tracking(struct net_device *dev);*/
static void dm_check_txpower_tracking(struct net_device *dev);
+/*static void dm_txpower_reset_recovery(struct net_device *dev);*/
-
-//static void dm_txpower_reset_recovery(struct net_device *dev);
-
-
-// DM --> Dynamic Init Gain by RSSI
+/* DM --> Dynamic Init Gain by RSSI */
static void dm_dig_init(struct net_device *dev);
static void dm_ctrl_initgain_byrssi(struct net_device *dev);
static void dm_ctrl_initgain_byrssi_highpwr(struct net_device *dev);
@@ -84,61 +80,58 @@ static void dm_pd_th(struct net_device *dev);
static void dm_cs_ratio(struct net_device *dev);
static void dm_init_ctstoself(struct net_device *dev);
-// DM --> EDCA turbo mode control
+/* DM --> EDCA turbo mode control */
static void dm_check_edca_turbo(struct net_device *dev);
-//static void dm_gpio_change_rf(struct net_device *dev);
-// DM --> Check PBC
+/*static void dm_gpio_change_rf(struct net_device *dev);*/
+/* DM --> Check PBC */
static void dm_check_pbc_gpio(struct net_device *dev);
-
-// DM --> Check current RX RF path state
+/* DM --> Check current RX RF path state */
static void dm_check_rx_path_selection(struct net_device *dev);
static void dm_init_rxpath_selection(struct net_device *dev);
static void dm_rxpath_sel_byrssi(struct net_device *dev);
-
-// DM --> Fsync for broadcom ap
+/* DM --> Fsync for broadcom ap */
static void dm_init_fsync(struct net_device *dev);
static void dm_deInit_fsync(struct net_device *dev);
-//Added by vivi, 20080522
+/* Added by vivi, 20080522 */
static void dm_check_txrateandretrycount(struct net_device *dev);
/*---------------------Define local function prototype-----------------------*/
-/*---------------------Define of Tx Power Control For Near/Far Range --------*/ //Add by Jacken 2008/02/18
+/*---------------------Define of Tx Power Control For Near/Far Range --------*/ /*Add by Jacken 2008/02/18 */
static void dm_init_dynamic_txpower(struct net_device *dev);
static void dm_dynamic_txpower(struct net_device *dev);
-
-// DM --> For rate adaptive and DIG, we must send RSSI to firmware
+/* DM --> For rate adaptive and DIG, we must send RSSI to firmware */
static void dm_send_rssi_tofw(struct net_device *dev);
static void dm_ctstoself(struct net_device *dev);
/*---------------------------Define function prototype------------------------*/
-//================================================================================
-// HW Dynamic mechanism interface.
-//================================================================================
-
-//
-// Description:
-// Prepare SW resource for HW dynamic mechanism.
-//
-// Assumption:
-// This function is only invoked at driver intialization once.
-//
-//
+/*
+ * ================================================================================
+ * HW Dynamic mechanism interface.
+ * ================================================================================
+ *
+ *
+ * Description:
+ * Prepare SW resource for HW dynamic mechanism.
+ *
+ * Assumption:
+ * This function is only invoked at driver intialization once.
+ */
void init_hal_dm(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- // Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism.
+ /* Undecorated Smoothed Signal Strength, it can utilized to dynamic mechanism. */
priv->undecorated_smoothed_pwdb = -1;
- //Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code.
+ /* Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. */
dm_init_dynamic_txpower(dev);
init_rate_adaptive(dev);
- //dm_initialize_txpower_tracking(dev);
+ /*dm_initialize_txpower_tracking(dev);*/
dm_dig_init(dev);
dm_init_edca_turbo(dev);
dm_init_bandwidth_autoswitch(dev);
@@ -146,18 +139,16 @@ void init_hal_dm(struct net_device *dev)
dm_init_rxpath_selection(dev);
dm_init_ctstoself(dev);
-} // InitHalDm
+} /* InitHalDm */
void deinit_hal_dm(struct net_device *dev)
{
-
dm_deInit_fsync(dev);
-
}
-
#ifdef USB_RX_AGGREGATION_SUPPORT
-void dm_CheckRxAggregation(struct net_device *dev) {
+void dm_CheckRxAggregation(struct net_device *dev)
+{
struct r8192_priv *priv = ieee80211_priv((struct net_device *)dev);
PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
static unsigned long lastTxOkCnt;
@@ -186,14 +177,15 @@ void dm_CheckRxAggregation(struct net_device *dev) {
if ((curTxOkCnt + curRxOkCnt) < 15000000)
return;
- if(curTxOkCnt > 4*curRxOkCnt) {
+ if (curTxOkCnt > 4*curRxOkCnt) {
if (priv->bCurrentRxAggrEnable) {
write_nic_dword(dev, 0x1a8, 0);
priv->bCurrentRxAggrEnable = false;
}
- }else{
+ } else {
if (!priv->bCurrentRxAggrEnable && !pHTInfo->bCurrentRT2RTAggregation) {
u32 ulValue;
+
ulValue = (pHTInfo->UsbRxFwAggrEn<<24) | (pHTInfo->UsbRxFwAggrPageNum<<16) |
(pHTInfo->UsbRxFwAggrPacketNum<<8) | (pHTInfo->UsbRxFwAggrTimeout);
/*
@@ -208,16 +200,14 @@ void dm_CheckRxAggregation(struct net_device *dev) {
lastTxOkCnt = priv->stats.txbytesunicast;
lastRxOkCnt = priv->stats.rxbytesunicast;
-} // dm_CheckEdcaTurbo
+} /* dm_CheckEdcaTurbo */
#endif
-
-
void hal_dm_watchdog(struct net_device *dev)
{
- //struct r8192_priv *priv = ieee80211_priv(dev);
+ /*struct r8192_priv *priv = ieee80211_priv(dev);*/
- //static u8 previous_bssid[6] ={0};
+ /*static u8 previous_bssid[6] ={0};*/
/*Add by amy 2008/05/15 ,porting from windows code.*/
dm_check_rate_adaptive(dev);
@@ -230,25 +220,23 @@ void hal_dm_watchdog(struct net_device *dev)
dm_check_rx_path_selection(dev);
dm_check_fsync(dev);
- // Add by amy 2008-05-15 porting from windows code.
+ /* Add by amy 2008-05-15 porting from windows code. */
dm_check_pbc_gpio(dev);
dm_send_rssi_tofw(dev);
dm_ctstoself(dev);
#ifdef USB_RX_AGGREGATION_SUPPORT
dm_CheckRxAggregation(dev);
#endif
-} //HalDmWatchDog
-
+} /* HalDmWatchDog */
/*
- * Decide Rate Adaptive Set according to distance (signal strength)
- * 01/11/2008 MHC Modify input arguments and RATR table level.
- * 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call
- * the function after making sure RF_Type.
- */
+ * Decide Rate Adaptive Set according to distance (signal strength)
+ * 01/11/2008 MHC Modify input arguments and RATR table level.
+ * 01/16/2008 MHC RF_Type is assigned in ReadAdapterInfo(). We must call
+ * the function after making sure RF_Type.
+ */
void init_rate_adaptive(struct net_device *dev)
{
-
struct r8192_priv *priv = ieee80211_priv(dev);
prate_adaptive pra = (prate_adaptive)&priv->rate_adaptive;
@@ -261,36 +249,33 @@ void init_rate_adaptive(struct net_device *dev)
pra->low_rssi_thresh_for_ra20M = RateAdaptiveTH_Low_20M;
pra->low_rssi_thresh_for_ra40M = RateAdaptiveTH_Low_40M;
- if(priv->CustomerID == RT_CID_819x_Netcore)
+ if (priv->CustomerID == RT_CID_819x_Netcore)
pra->ping_rssi_enable = 1;
else
pra->ping_rssi_enable = 0;
pra->ping_rssi_thresh_for_ra = 15;
-
- if (priv->rf_type == RF_2T4R)
- {
- // 07/10/08 MH Modify for RA smooth scheme.
- /* 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.*/
+ if (priv->rf_type == RF_2T4R) {
+ /*
+ * 07/10/08 MH Modify for RA smooth scheme.
+ * 2008/01/11 MH Modify 2T RATR table for different RSSI. 080515 porting by amy from windows code.
+ */
pra->upper_rssi_threshold_ratr = 0x8f0f0000;
pra->middle_rssi_threshold_ratr = 0x8f0ff000;
pra->low_rssi_threshold_ratr = 0x8f0ff001;
pra->low_rssi_threshold_ratr_40M = 0x8f0ff005;
pra->low_rssi_threshold_ratr_20M = 0x8f0ff001;
- pra->ping_rssi_ratr = 0x0000000d;//cosa add for test
- }
- else if (priv->rf_type == RF_1T2R)
- {
+ pra->ping_rssi_ratr = 0x0000000d;/* cosa add for test */
+ } else if (priv->rf_type == RF_1T2R) {
pra->upper_rssi_threshold_ratr = 0x000f0000;
pra->middle_rssi_threshold_ratr = 0x000ff000;
pra->low_rssi_threshold_ratr = 0x000ff001;
pra->low_rssi_threshold_ratr_40M = 0x000ff005;
pra->low_rssi_threshold_ratr_20M = 0x000ff001;
- pra->ping_rssi_ratr = 0x0000000d;//cosa add for test
+ pra->ping_rssi_ratr = 0x0000000d;/* cosa add for test */
}
-} // InitRateAdaptive
-
+} /* InitRateAdaptive */
/*-----------------------------------------------------------------------------
* Function: dm_check_rate_adaptive()
@@ -318,149 +303,122 @@ static void dm_check_rate_adaptive(struct net_device *dev)
bool bshort_gi_enabled = false;
static u8 ping_rssi_state;
-
- if(!priv->up)
- {
+ if (!priv->up) {
RT_TRACE(COMP_RATE, "<---- dm_check_rate_adaptive(): driver is going to unload\n");
return;
}
- if(pra->rate_adaptive_disabled)//this variable is set by ioctl.
+ if (pra->rate_adaptive_disabled) /* this variable is set by ioctl. */
return;
- // TODO: Only 11n mode is implemented currently,
- if(!(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
- priv->ieee80211->mode == WIRELESS_MODE_N_5G))
- return;
+ /* TODO: Only 11n mode is implemented currently, */
+ if (!(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
+ priv->ieee80211->mode == WIRELESS_MODE_N_5G))
+ return;
- if(priv->ieee80211->state == IEEE80211_LINKED)
- {
- // RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t");
+ if (priv->ieee80211->state == IEEE80211_LINKED) {
+ /*RT_TRACE(COMP_RATE, "dm_CheckRateAdaptive(): \t");*/
- //
- // Check whether Short GI is enabled
- //
+ /* Check whether Short GI is enabled */
bshort_gi_enabled = (pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI40MHz) ||
(!pHTInfo->bCurTxBW40MHz && pHTInfo->bCurShortGI20MHz);
-
pra->upper_rssi_threshold_ratr =
- (pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+ (pra->upper_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
pra->middle_rssi_threshold_ratr =
- (pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+ (pra->middle_rssi_threshold_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
pra->low_rssi_threshold_ratr =
- (pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
- }
- else
- {
+ (pra->low_rssi_threshold_ratr_40M & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
+ } else {
pra->low_rssi_threshold_ratr =
- (pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+ (pra->low_rssi_threshold_ratr_20M & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
}
- //cosa add for test
+ /* cosa add for test */
pra->ping_rssi_ratr =
- (pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled)? BIT31:0) ;
+ (pra->ping_rssi_ratr & (~BIT31)) | ((bshort_gi_enabled) ? BIT31:0);
/* 2007/10/08 MH We support RA smooth scheme now. When it is the first
time to link with AP. We will not change upper/lower threshold. If
STA stay in high or low level, we must change two different threshold
to prevent jumping frequently. */
- if (pra->ratr_state == DM_RATR_STA_HIGH)
- {
+ if (pra->ratr_state == DM_RATR_STA_HIGH) {
HighRSSIThreshForRA = pra->high2low_rssi_thresh_for_ra;
- LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
+ LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
(pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M);
- }
- else if (pra->ratr_state == DM_RATR_STA_LOW)
- {
+ } else if (pra->ratr_state == DM_RATR_STA_LOW) {
HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra;
- LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
+ LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
(pra->low2high_rssi_thresh_for_ra40M):(pra->low2high_rssi_thresh_for_ra20M);
- }
- else
- {
+ } else {
HighRSSIThreshForRA = pra->high_rssi_thresh_for_ra;
- LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)?
+ LowRSSIThreshForRA = (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) ?
(pra->low_rssi_thresh_for_ra40M):(pra->low_rssi_thresh_for_ra20M);
}
- //DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA);
- if(priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA)
- {
- //DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB);
+ /*DbgPrint("[DM] THresh H/L=%d/%d\n\r", RATR.HighRSSIThreshForRA, RATR.LowRSSIThreshForRA);*/
+ if (priv->undecorated_smoothed_pwdb >= (long)HighRSSIThreshForRA) {
+ /*DbgPrint("[DM] RSSI=%d STA=HIGH\n\r", pHalData->UndecoratedSmoothedPWDB);*/
pra->ratr_state = DM_RATR_STA_HIGH;
targetRATR = pra->upper_rssi_threshold_ratr;
- }else if(priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA)
- {
- //DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB);
+ } else if (priv->undecorated_smoothed_pwdb >= (long)LowRSSIThreshForRA) {
+ /*DbgPrint("[DM] RSSI=%d STA=Middle\n\r", pHalData->UndecoratedSmoothedPWDB);*/
pra->ratr_state = DM_RATR_STA_MIDDLE;
targetRATR = pra->middle_rssi_threshold_ratr;
- }else
- {
- //DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB);
+ } else {
+ /*DbgPrint("[DM] RSSI=%d STA=LOW\n\r", pHalData->UndecoratedSmoothedPWDB);*/
pra->ratr_state = DM_RATR_STA_LOW;
targetRATR = pra->low_rssi_threshold_ratr;
}
- //cosa add for test
- if(pra->ping_rssi_enable)
- {
- //pHalData->UndecoratedSmoothedPWDB = 19;
- if(priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5))
- {
- if((priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) ||
- ping_rssi_state)
- {
- //DbgPrint("TestRSSI = %d, set RATR to 0x%x \n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR);
+ /* cosa add for test */
+ if (pra->ping_rssi_enable) {
+ /*pHalData->UndecoratedSmoothedPWDB = 19;*/
+ if (priv->undecorated_smoothed_pwdb < (long)(pra->ping_rssi_thresh_for_ra+5)) {
+ if ((priv->undecorated_smoothed_pwdb < (long)pra->ping_rssi_thresh_for_ra) ||
+ ping_rssi_state) {
+ /*DbgPrint("TestRSSI = %d, set RATR to 0x%x\n", pHalData->UndecoratedSmoothedPWDB, pRA->TestRSSIRATR);*/
pra->ratr_state = DM_RATR_STA_LOW;
targetRATR = pra->ping_rssi_ratr;
ping_rssi_state = 1;
}
- //else
- // DbgPrint("TestRSSI is between the range. \n");
- }
- else
- {
- //DbgPrint("TestRSSI Recover to 0x%x \n", targetRATR);
+ /*else
+ DbgPrint("TestRSSI is between the range.\n");*/
+ } else {
+ /*DbgPrint("TestRSSI Recover to 0x%x\n", targetRATR);*/
ping_rssi_state = 0;
}
}
- // 2008.04.01
- // For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
- if(priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev))
- targetRATR &= 0xf00fffff;
+ /*
+ * 2008.04.01
+ * For RTL819X, if pairwisekey = wep/tkip, we support only MCS0~7.
+ */
+ if (priv->ieee80211->GetHalfNmodeSupportByAPsHandler(dev))
+ targetRATR &= 0xf00fffff;
- //
- // Check whether updating of RATR0 is required
- //
+ /* Check whether updating of RATR0 is required */
read_nic_dword(dev, RATR0, &currentRATR);
- if(targetRATR != currentRATR)
- {
+ if (targetRATR != currentRATR) {
u32 ratr_value;
+
ratr_value = targetRATR;
- RT_TRACE(COMP_RATE,"currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR);
- if(priv->rf_type == RF_1T2R)
- {
+ RT_TRACE(COMP_RATE, "currentRATR = %x, targetRATR = %x\n", currentRATR, targetRATR);
+ if (priv->rf_type == RF_1T2R)
ratr_value &= ~(RATE_ALL_OFDM_2SS);
- }
write_nic_dword(dev, RATR0, ratr_value);
write_nic_byte(dev, UFWP, 1);
pra->last_ratr = targetRATR;
}
- }
- else
- {
+ } else {
pra->ratr_state = DM_RATR_STA_MAX;
}
-} // dm_CheckRateAdaptive
-
+} /* dm_CheckRateAdaptive */
static void dm_init_bandwidth_autoswitch(struct net_device *dev)
{
@@ -471,78 +429,74 @@ static void dm_init_bandwidth_autoswitch(struct net_device *dev)
priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable = false;
-} // dm_init_bandwidth_autoswitch
-
+} /* dm_init_bandwidth_autoswitch */
static void dm_bandwidth_autoswitch(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 ||!priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable){
+ if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20 || !priv->ieee80211->bandwidth_auto_switch.bautoswitch_enable)
return;
- }else{
- if(priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false){//If send packets in 40 Mhz in 20/40
- if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz)
- priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true;
- }else{//in force send packets in 20 Mhz in 20/40
- if(priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz)
- priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
-
- }
+ if (priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz == false) { /* If send packets in 40 Mhz in 20/40 */
+ if (priv->undecorated_smoothed_pwdb <= priv->ieee80211->bandwidth_auto_switch.threshold_40Mhzto20Mhz)
+ priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = true;
+ } else { /* in force send packets in 20 Mhz in 20/40 */
+ if (priv->undecorated_smoothed_pwdb >= priv->ieee80211->bandwidth_auto_switch.threshold_20Mhzto40Mhz)
+ priv->ieee80211->bandwidth_auto_switch.bforced_tx20Mhz = false;
}
-} // dm_BandwidthAutoSwitch
+} /* dm_BandwidthAutoSwitch */
-//OFDM default at 0db, index=6.
+/* OFDM default at 0db, index=6. */
static u32 OFDMSwingTable[OFDM_Table_Length] = {
- 0x7f8001fe, // 0, +6db
- 0x71c001c7, // 1, +5db
- 0x65400195, // 2, +4db
- 0x5a400169, // 3, +3db
- 0x50800142, // 4, +2db
- 0x47c0011f, // 5, +1db
- 0x40000100, // 6, +0db ===> default, upper for higher temperature, lower for low temperature
- 0x390000e4, // 7, -1db
- 0x32c000cb, // 8, -2db
- 0x2d4000b5, // 9, -3db
- 0x288000a2, // 10, -4db
- 0x24000090, // 11, -5db
- 0x20000080, // 12, -6db
- 0x1c800072, // 13, -7db
- 0x19800066, // 14, -8db
- 0x26c0005b, // 15, -9db
- 0x24400051, // 16, -10db
- 0x12000048, // 17, -11db
- 0x10000040 // 18, -12db
+ 0x7f8001fe, /* 0, +6db */
+ 0x71c001c7, /* 1, +5db */
+ 0x65400195, /* 2, +4db */
+ 0x5a400169, /* 3, +3db */
+ 0x50800142, /* 4, +2db */
+ 0x47c0011f, /* 5, +1db */
+ 0x40000100, /* 6, +0db ===> default, upper for higher temperature, lower for low temperature */
+ 0x390000e4, /* 7, -1db */
+ 0x32c000cb, /* 8, -2db */
+ 0x2d4000b5, /* 9, -3db */
+ 0x288000a2, /* 10, -4db */
+ 0x24000090, /* 11, -5db */
+ 0x20000080, /* 12, -6db */
+ 0x1c800072, /* 13, -7db */
+ 0x19800066, /* 14, -8db */
+ 0x26c0005b, /* 15, -9db */
+ 0x24400051, /* 16, -10db */
+ 0x12000048, /* 17, -11db */
+ 0x10000040 /* 18, -12db */
};
static u8 CCKSwingTable_Ch1_Ch13[CCK_Table_length][8] = {
- {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, // 0, +0db ===> CCK40M default
- {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, // 1, -1db
- {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, // 2, -2db
- {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, // 3, -3db
- {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, // 4, -4db
- {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, // 5, -5db
- {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, // 6, -6db ===> CCK20M default
- {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, // 7, -7db
- {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, // 8, -8db
- {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, // 9, -9db
- {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, // 10, -10db
- {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} // 11, -11db
+ {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04}, /* 0, +0db ===> CCK40M default */
+ {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03}, /* 1, -1db */
+ {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03}, /* 2, -2db */
+ {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03}, /* 3, -3db */
+ {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02}, /* 4, -4db */
+ {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02}, /* 5, -5db */
+ {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02}, /* 6, -6db ===> CCK20M default */
+ {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02}, /* 7, -7db */
+ {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01}, /* 8, -8db */
+ {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01}, /* 9, -9db */
+ {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01}, /* 10, -10db */
+ {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01} /* 11, -11db */
};
static u8 CCKSwingTable_Ch14[CCK_Table_length][8] = {
- {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, // 0, +0db ===> CCK40M default
- {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, // 1, -1db
- {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, // 2, -2db
- {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, // 3, -3db
- {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, // 4, -4db
- {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, // 5, -5db
- {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, // 6, -6db ===> CCK20M default
- {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, // 7, -7db
- {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, // 8, -8db
- {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, // 9, -9db
- {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, // 10, -10db
- {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} // 11, -11db
+ {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00}, /* 0, +0db ===> CCK40M default */
+ {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00}, /* 1, -1db */
+ {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00}, /* 2, -2db */
+ {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00}, /* 3, -3db */
+ {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00}, /* 4, -4db */
+ {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00}, /* 5, -5db */
+ {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00}, /* 6, -6db ===> CCK20M default */
+ {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00}, /* 7, -7db */
+ {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00}, /* 8, -8db */
+ {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00}, /* 9, -9db */
+ {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00}, /* 10, -10db */
+ {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00} /* 11, -11db */
};
static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
@@ -551,14 +505,14 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
bool bHighpowerstate, viviflag = FALSE;
DCMD_TXCMD_T tx_cmd;
u8 powerlevelOFDM24G;
- int i =0, j = 0, k = 0;
- u8 RF_Type, tmp_report[5]={0, 0, 0, 0, 0};
+ int i = 0, j = 0, k = 0;
+ u8 RF_Type, tmp_report[5] = {0, 0, 0, 0, 0};
u32 Value;
u8 Pwr_Flag;
- u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver=0;
- //RT_STATUS rtStatus = RT_STATUS_SUCCESS;
+ u16 Avg_TSSI_Meas, TSSI_13dBm, Avg_TSSI_Meas_from_driver = 0;
+ /*RT_STATUS rtStatus = RT_STATUS_SUCCESS;*/
bool rtStatus = true;
- u32 delta=0;
+ u32 delta = 0;
write_nic_byte(dev, 0x1ba, 0);
@@ -571,109 +525,87 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
RT_TRACE(COMP_POWER_TRACKING, "powerlevelOFDM24G = %x\n", powerlevelOFDM24G);
- for(j = 0; j<=30; j++)
-{ //fill tx_cmd
-
- tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING;
- tx_cmd.Length = 4;
- tx_cmd.Value = Value;
- rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12);
- if (rtStatus == RT_STATUS_FAILURE)
- {
- RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n");
- }
- mdelay(1);
- //DbgPrint("hi, vivi, strange\n");
- for(i = 0;i <= 30; i++)
- {
- read_nic_byte(dev, 0x1ba, &Pwr_Flag);
-
- if (Pwr_Flag == 0)
- {
- mdelay(1);
- continue;
- }
- read_nic_word(dev, 0x13c, &Avg_TSSI_Meas);
- if(Avg_TSSI_Meas == 0)
- {
- write_nic_byte(dev, 0x1ba, 0);
- break;
- }
+ for (j = 0; j <= 30; j++) { /* fill tx_cmd */
+ tx_cmd.Op = TXCMD_SET_TX_PWR_TRACKING;
+ tx_cmd.Length = 4;
+ tx_cmd.Value = Value;
+ rtStatus = SendTxCommandPacket(dev, &tx_cmd, 12);
+ if (rtStatus == RT_STATUS_FAILURE)
+ RT_TRACE(COMP_POWER_TRACKING, "Set configuration with tx cmd queue fail!\n");
+ mdelay(1);
+ /*DbgPrint("hi, vivi, strange\n");*/
+ for (i = 0; i <= 30; i++) {
+ read_nic_byte(dev, 0x1ba, &Pwr_Flag);
+
+ if (Pwr_Flag == 0) {
+ mdelay(1);
+ continue;
+ }
+ read_nic_word(dev, 0x13c, &Avg_TSSI_Meas);
+ if (Avg_TSSI_Meas == 0) {
+ write_nic_byte(dev, 0x1ba, 0);
+ break;
+ }
- for(k = 0;k < 5; k++)
- {
- if(k !=4)
- read_nic_byte(dev, 0x134+k, &tmp_report[k]);
- else
- read_nic_byte(dev, 0x13e, &tmp_report[k]);
- RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]);
- }
+ for (k = 0; k < 5; k++) {
+ if (k != 4)
+ read_nic_byte(dev, 0x134+k, &tmp_report[k]);
+ else
+ read_nic_byte(dev, 0x13e, &tmp_report[k]);
+ RT_TRACE(COMP_POWER_TRACKING, "TSSI_report_value = %d\n", tmp_report[k]);
+ }
- //check if the report value is right
- for(k = 0;k < 5; k++)
- {
- if(tmp_report[k] <= 20)
- {
- viviflag =TRUE;
+ /* check if the report value is right */
+ for (k = 0; k < 5; k++) {
+ if (tmp_report[k] <= 20) {
+ viviflag = TRUE;
+ break;
+ }
+ }
+ if (viviflag == TRUE) {
+ write_nic_byte(dev, 0x1ba, 0);
+ viviflag = FALSE;
+ RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
+ for (k = 0; k < 5; k++)
+ tmp_report[k] = 0;
break;
}
- }
- if(viviflag ==TRUE)
- {
- write_nic_byte(dev, 0x1ba, 0);
- viviflag = FALSE;
- RT_TRACE(COMP_POWER_TRACKING, "we filtered the data\n");
- for(k = 0;k < 5; k++)
- tmp_report[k] = 0;
- break;
- }
- for(k = 0;k < 5; k++)
- {
- Avg_TSSI_Meas_from_driver += tmp_report[k];
- }
-
- Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5;
- RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver);
- TSSI_13dBm = priv->TSSI_13dBm;
- RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm);
+ for (k = 0; k < 5; k++)
+ Avg_TSSI_Meas_from_driver += tmp_report[k];
- //if(abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK)
- // For MacOS-compatible
- if(Avg_TSSI_Meas_from_driver > TSSI_13dBm)
- delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm;
- else
- delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver;
+ Avg_TSSI_Meas_from_driver = Avg_TSSI_Meas_from_driver*100/5;
+ RT_TRACE(COMP_POWER_TRACKING, "Avg_TSSI_Meas_from_driver = %d\n", Avg_TSSI_Meas_from_driver);
+ TSSI_13dBm = priv->TSSI_13dBm;
+ RT_TRACE(COMP_POWER_TRACKING, "TSSI_13dBm = %d\n", TSSI_13dBm);
- if(delta <= E_FOR_TX_POWER_TRACK)
- {
- priv->ieee80211->bdynamic_txpower_enable = TRUE;
- write_nic_byte(dev, 0x1ba, 0);
- RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n");
- RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
- RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
- RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
- RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
- return;
- }
- else
- {
- if(Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK)
- {
- if (priv->rfa_txpowertrackingindex > 0)
- {
+ /*if (abs(Avg_TSSI_Meas_from_driver - TSSI_13dBm) <= E_FOR_TX_POWER_TRACK)*/
+ /* For MacOS-compatible */
+ if (Avg_TSSI_Meas_from_driver > TSSI_13dBm)
+ delta = Avg_TSSI_Meas_from_driver - TSSI_13dBm;
+ else
+ delta = TSSI_13dBm - Avg_TSSI_Meas_from_driver;
+
+ if (delta <= E_FOR_TX_POWER_TRACK) {
+ priv->ieee80211->bdynamic_txpower_enable = TRUE;
+ write_nic_byte(dev, 0x1ba, 0);
+ RT_TRACE(COMP_POWER_TRACKING, "tx power track is done\n");
+ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
+ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
+ RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
+ RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
+ return;
+ }
+ if (Avg_TSSI_Meas_from_driver < TSSI_13dBm - E_FOR_TX_POWER_TRACK) {
+ if (priv->rfa_txpowertrackingindex > 0) {
priv->rfa_txpowertrackingindex--;
- if(priv->rfa_txpowertrackingindex_real > 4)
- {
+ if (priv->rfa_txpowertrackingindex_real > 4) {
priv->rfa_txpowertrackingindex_real--;
rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value);
}
}
- }
- else
- {
- if (priv->rfa_txpowertrackingindex < 36)
- {
+ } else {
+ if (priv->rfa_txpowertrackingindex < 36) {
priv->rfa_txpowertrackingindex++;
priv->rfa_txpowertrackingindex_real++;
rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex_real].txbbgain_value);
@@ -683,52 +615,44 @@ static void dm_TXPowerTrackingCallback_TSSI(struct net_device *dev)
priv->cck_present_attentuation_difference
= priv->rfa_txpowertrackingindex - priv->rfa_txpowertracking_default;
- if(priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
+ if (priv->CurrentChannelBW == HT_CHANNEL_WIDTH_20)
priv->cck_present_attentuation
- = priv->cck_present_attentuation_20Mdefault + priv->cck_present_attentuation_difference;
+ = priv->cck_present_attentuation_20Mdefault + priv->cck_present_attentuation_difference;
else
priv->cck_present_attentuation
- = priv->cck_present_attentuation_40Mdefault + priv->cck_present_attentuation_difference;
+ = priv->cck_present_attentuation_40Mdefault + priv->cck_present_attentuation_difference;
- if(priv->cck_present_attentuation > -1&&priv->cck_present_attentuation <23)
- {
- if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
- {
+ if (priv->cck_present_attentuation > -1 && priv->cck_present_attentuation < 23) {
+ if (priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) {
priv->bcck_in_ch14 = TRUE;
- dm_cck_txpower_adjust(dev,priv->bcck_in_ch14);
- }
- else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
- {
+ dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
+ } else if (priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) {
priv->bcck_in_ch14 = FALSE;
- dm_cck_txpower_adjust(dev,priv->bcck_in_ch14);
- }
- else
- dm_cck_txpower_adjust(dev,priv->bcck_in_ch14);
+ dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
+ } else
+ dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
}
- RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
- RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
- RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
- RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
-
- if (priv->cck_present_attentuation_difference <= -12||priv->cck_present_attentuation_difference >= 24)
- {
- priv->ieee80211->bdynamic_txpower_enable = TRUE;
- write_nic_byte(dev, 0x1ba, 0);
- RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n");
- return;
- }
+ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex = %d\n", priv->rfa_txpowertrackingindex);
+ RT_TRACE(COMP_POWER_TRACKING, "priv->rfa_txpowertrackingindex_real = %d\n", priv->rfa_txpowertrackingindex_real);
+ RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation_difference = %d\n", priv->cck_present_attentuation_difference);
+ RT_TRACE(COMP_POWER_TRACKING, "priv->cck_present_attentuation = %d\n", priv->cck_present_attentuation);
+ if (priv->cck_present_attentuation_difference <= -12 || priv->cck_present_attentuation_difference >= 24) {
+ priv->ieee80211->bdynamic_txpower_enable = TRUE;
+ write_nic_byte(dev, 0x1ba, 0);
+ RT_TRACE(COMP_POWER_TRACKING, "tx power track--->limited\n");
+ return;
+ }
+ write_nic_byte(dev, 0x1ba, 0);
+ Avg_TSSI_Meas_from_driver = 0;
+ for (k = 0; k < 5; k++)
+ tmp_report[k] = 0;
+ break;
+ }
}
- write_nic_byte(dev, 0x1ba, 0);
- Avg_TSSI_Meas_from_driver = 0;
- for(k = 0;k < 5; k++)
- tmp_report[k] = 0;
- break;
- }
-}
- priv->ieee80211->bdynamic_txpower_enable = TRUE;
- write_nic_byte(dev, 0x1ba, 0);
+ priv->ieee80211->bdynamic_txpower_enable = TRUE;
+ write_nic_byte(dev, 0x1ba, 0);
}
static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
@@ -737,107 +661,96 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
struct r8192_priv *priv = ieee80211_priv(dev);
u32 tmpRegA, TempCCk;
u8 tmpOFDMindex, tmpCCKindex, tmpCCK20Mindex, tmpCCK40Mindex, tmpval;
- int i =0, CCKSwingNeedUpdate=0;
-
- if(!priv->btxpower_trackingInit)
- {
- //Query OFDM default setting
- tmpRegA= rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord);
- for(i=0; i<OFDM_Table_Length; i++) //find the index
- {
- if(tmpRegA == OFDMSwingTable[i])
- {
- priv->OFDM_index= (u8)i;
+ int i = 0, CCKSwingNeedUpdate = 0;
+
+ if (!priv->btxpower_trackingInit) {
+ /* Query OFDM default setting */
+ tmpRegA = rtl8192_QueryBBReg(dev, rOFDM0_XATxIQImbalance, bMaskDWord);
+ for (i = 0; i < OFDM_Table_Length; i++) { /* find the index */
+ if (tmpRegA == OFDMSwingTable[i]) {
+ priv->OFDM_index = (u8)i;
RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, OFDM_index=0x%x\n",
rOFDM0_XATxIQImbalance, tmpRegA, priv->OFDM_index);
}
}
- //Query CCK default setting From 0xa22
+ /* Query CCK default setting From 0xa22 */
TempCCk = rtl8192_QueryBBReg(dev, rCCK0_TxFilter1, bMaskByte2);
- for(i=0 ; i<CCK_Table_length ; i++)
- {
- if(TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0])
- {
- priv->CCK_index =(u8) i;
+ for (i = 0; i < CCK_Table_length; i++) {
+ if (TempCCk == (u32)CCKSwingTable_Ch1_Ch13[i][0]) {
+ priv->CCK_index = (u8) i;
RT_TRACE(COMP_POWER_TRACKING, "Initial reg0x%x = 0x%x, CCK_index=0x%x\n",
rCCK0_TxFilter1, TempCCk, priv->CCK_index);
break;
}
}
priv->btxpower_trackingInit = TRUE;
- //pHalData->TXPowercount = 0;
+ /*pHalData->TXPowercount = 0;*/
return;
}
- //==========================
- // this is only for test, should be masked
- //==========================
-
- // read and filter out unreasonable value
- tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078); // 0x12: RF Reg[10:7]
- RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d \n", tmpRegA);
- if(tmpRegA < 3 || tmpRegA > 13)
+ /*
+ * ==========================
+ * this is only for test, should be masked
+ * ==========================
+ */
+
+ /* read and filter out unreasonable value */
+ tmpRegA = rtl8192_phy_QueryRFReg(dev, RF90_PATH_A, 0x12, 0x078); /* 0x12: RF Reg[10:7] */
+ RT_TRACE(COMP_POWER_TRACKING, "Readback ThermalMeterA = %d\n", tmpRegA);
+ if (tmpRegA < 3 || tmpRegA > 13)
return;
- if(tmpRegA >= 12) // if over 12, TP will be bad when high temperature
+ if (tmpRegA >= 12) /* if over 12, TP will be bad when high temperature */
tmpRegA = 12;
- RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d \n", tmpRegA);
- priv->ThermalMeter[0] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
- priv->ThermalMeter[1] = ThermalMeterVal; //We use fixed value by Bryant's suggestion
+ RT_TRACE(COMP_POWER_TRACKING, "Valid ThermalMeterA = %d\n", tmpRegA);
+ priv->ThermalMeter[0] = ThermalMeterVal; /* We use fixed value by Bryant's suggestion */
+ priv->ThermalMeter[1] = ThermalMeterVal; /* We use fixed value by Bryant's suggestion */
- //Get current RF-A temperature index
- if(priv->ThermalMeter[0] >= (u8)tmpRegA) //lower temperature
- {
+ /* Get current RF-A temperature index */
+ if (priv->ThermalMeter[0] >= (u8)tmpRegA) { /* lower temperature */
tmpOFDMindex = tmpCCK20Mindex = 6+(priv->ThermalMeter[0]-(u8)tmpRegA);
tmpCCK40Mindex = tmpCCK20Mindex - 6;
- if(tmpOFDMindex >= OFDM_Table_Length)
+ if (tmpOFDMindex >= OFDM_Table_Length)
tmpOFDMindex = OFDM_Table_Length-1;
- if(tmpCCK20Mindex >= CCK_Table_length)
+ if (tmpCCK20Mindex >= CCK_Table_length)
tmpCCK20Mindex = CCK_Table_length-1;
- if(tmpCCK40Mindex >= CCK_Table_length)
+ if (tmpCCK40Mindex >= CCK_Table_length)
tmpCCK40Mindex = CCK_Table_length-1;
- }
- else
- {
+ } else {
tmpval = ((u8)tmpRegA - priv->ThermalMeter[0]);
- if(tmpval >= 6) // higher temperature
- tmpOFDMindex = tmpCCK20Mindex = 0; // max to +6dB
+
+ if (tmpval >= 6) /* higher temperature */
+ tmpOFDMindex = tmpCCK20Mindex = 0; /* max to +6dB */
else
tmpOFDMindex = tmpCCK20Mindex = 6 - tmpval;
tmpCCK40Mindex = 0;
}
- //DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d",
- //((u1Byte)tmpRegA - pHalData->ThermalMeter[0]),
- //tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex);
- if(priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) //40M
+ /*DbgPrint("%ddb, tmpOFDMindex = %d, tmpCCK20Mindex = %d, tmpCCK40Mindex = %d",
+ ((u1Byte)tmpRegA - pHalData->ThermalMeter[0]),
+ tmpOFDMindex, tmpCCK20Mindex, tmpCCK40Mindex);*/
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) /* 40M */
tmpCCKindex = tmpCCK40Mindex;
else
tmpCCKindex = tmpCCK20Mindex;
- if(priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14)
- {
+ if (priv->ieee80211->current_network.channel == 14 && !priv->bcck_in_ch14) {
priv->bcck_in_ch14 = TRUE;
CCKSwingNeedUpdate = 1;
- }
- else if(priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14)
- {
+ } else if (priv->ieee80211->current_network.channel != 14 && priv->bcck_in_ch14) {
priv->bcck_in_ch14 = FALSE;
CCKSwingNeedUpdate = 1;
}
- if(priv->CCK_index != tmpCCKindex)
- {
+ if (priv->CCK_index != tmpCCKindex) {
priv->CCK_index = tmpCCKindex;
CCKSwingNeedUpdate = 1;
}
- if(CCKSwingNeedUpdate)
- {
- //DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index);
+ if (CCKSwingNeedUpdate) {
+ /*DbgPrint("Update CCK Swing, CCK_index = %d\n", pHalData->CCK_index);*/
dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
}
- if(priv->OFDM_index != tmpOFDMindex)
- {
+ if (priv->OFDM_index != tmpOFDMindex) {
priv->OFDM_index = tmpOFDMindex;
rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, OFDMSwingTable[priv->OFDM_index]);
RT_TRACE(COMP_POWER_TRACKING, "Update OFDMSwing[%d] = 0x%x\n",
@@ -848,100 +761,100 @@ static void dm_TXPowerTrackingCallback_ThermalMeter(struct net_device *dev)
void dm_txpower_trackingcallback(struct work_struct *work)
{
- struct delayed_work *dwork = container_of(work,struct delayed_work,work);
- struct r8192_priv *priv = container_of(dwork,struct r8192_priv,txpower_tracking_wq);
- struct net_device *dev = priv->ieee80211->dev;
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct r8192_priv *priv = container_of(dwork, struct r8192_priv, txpower_tracking_wq);
+ struct net_device *dev = priv->ieee80211->dev;
- if(priv->bDcut == TRUE)
+ if (priv->bDcut == TRUE)
dm_TXPowerTrackingCallback_TSSI(dev);
else
dm_TXPowerTrackingCallback_ThermalMeter(dev);
}
-
static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
{
-
struct r8192_priv *priv = ieee80211_priv(dev);
- //Initial the Tx BB index and mapping value
+ /* Initial the Tx BB index and mapping value */
priv->txbbgain_table[0].txbb_iq_amplifygain = 12;
- priv->txbbgain_table[0].txbbgain_value=0x7f8001fe;
+ priv->txbbgain_table[0].txbbgain_value = 0x7f8001fe;
priv->txbbgain_table[1].txbb_iq_amplifygain = 11;
- priv->txbbgain_table[1].txbbgain_value=0x788001e2;
+ priv->txbbgain_table[1].txbbgain_value = 0x788001e2;
priv->txbbgain_table[2].txbb_iq_amplifygain = 10;
- priv->txbbgain_table[2].txbbgain_value=0x71c001c7;
+ priv->txbbgain_table[2].txbbgain_value = 0x71c001c7;
priv->txbbgain_table[3].txbb_iq_amplifygain = 9;
- priv->txbbgain_table[3].txbbgain_value=0x6b8001ae;
+ priv->txbbgain_table[3].txbbgain_value = 0x6b8001ae;
priv->txbbgain_table[4].txbb_iq_amplifygain = 8;
- priv->txbbgain_table[4].txbbgain_value=0x65400195;
+ priv->txbbgain_table[4].txbbgain_value = 0x65400195;
priv->txbbgain_table[5].txbb_iq_amplifygain = 7;
- priv->txbbgain_table[5].txbbgain_value=0x5fc0017f;
+ priv->txbbgain_table[5].txbbgain_value = 0x5fc0017f;
priv->txbbgain_table[6].txbb_iq_amplifygain = 6;
- priv->txbbgain_table[6].txbbgain_value=0x5a400169;
+ priv->txbbgain_table[6].txbbgain_value = 0x5a400169;
priv->txbbgain_table[7].txbb_iq_amplifygain = 5;
- priv->txbbgain_table[7].txbbgain_value=0x55400155;
+ priv->txbbgain_table[7].txbbgain_value = 0x55400155;
priv->txbbgain_table[8].txbb_iq_amplifygain = 4;
- priv->txbbgain_table[8].txbbgain_value=0x50800142;
+ priv->txbbgain_table[8].txbbgain_value = 0x50800142;
priv->txbbgain_table[9].txbb_iq_amplifygain = 3;
- priv->txbbgain_table[9].txbbgain_value=0x4c000130;
+ priv->txbbgain_table[9].txbbgain_value = 0x4c000130;
priv->txbbgain_table[10].txbb_iq_amplifygain = 2;
- priv->txbbgain_table[10].txbbgain_value=0x47c0011f;
+ priv->txbbgain_table[10].txbbgain_value = 0x47c0011f;
priv->txbbgain_table[11].txbb_iq_amplifygain = 1;
- priv->txbbgain_table[11].txbbgain_value=0x43c0010f;
+ priv->txbbgain_table[11].txbbgain_value = 0x43c0010f;
priv->txbbgain_table[12].txbb_iq_amplifygain = 0;
- priv->txbbgain_table[12].txbbgain_value=0x40000100;
+ priv->txbbgain_table[12].txbbgain_value = 0x40000100;
priv->txbbgain_table[13].txbb_iq_amplifygain = -1;
- priv->txbbgain_table[13].txbbgain_value=0x3c8000f2;
+ priv->txbbgain_table[13].txbbgain_value = 0x3c8000f2;
priv->txbbgain_table[14].txbb_iq_amplifygain = -2;
- priv->txbbgain_table[14].txbbgain_value=0x390000e4;
+ priv->txbbgain_table[14].txbbgain_value = 0x390000e4;
priv->txbbgain_table[15].txbb_iq_amplifygain = -3;
- priv->txbbgain_table[15].txbbgain_value=0x35c000d7;
+ priv->txbbgain_table[15].txbbgain_value = 0x35c000d7;
priv->txbbgain_table[16].txbb_iq_amplifygain = -4;
- priv->txbbgain_table[16].txbbgain_value=0x32c000cb;
+ priv->txbbgain_table[16].txbbgain_value = 0x32c000cb;
priv->txbbgain_table[17].txbb_iq_amplifygain = -5;
- priv->txbbgain_table[17].txbbgain_value=0x300000c0;
+ priv->txbbgain_table[17].txbbgain_value = 0x300000c0;
priv->txbbgain_table[18].txbb_iq_amplifygain = -6;
- priv->txbbgain_table[18].txbbgain_value=0x2d4000b5;
+ priv->txbbgain_table[18].txbbgain_value = 0x2d4000b5;
priv->txbbgain_table[19].txbb_iq_amplifygain = -7;
- priv->txbbgain_table[19].txbbgain_value=0x2ac000ab;
+ priv->txbbgain_table[19].txbbgain_value = 0x2ac000ab;
priv->txbbgain_table[20].txbb_iq_amplifygain = -8;
- priv->txbbgain_table[20].txbbgain_value=0x288000a2;
+ priv->txbbgain_table[20].txbbgain_value = 0x288000a2;
priv->txbbgain_table[21].txbb_iq_amplifygain = -9;
- priv->txbbgain_table[21].txbbgain_value=0x26000098;
+ priv->txbbgain_table[21].txbbgain_value = 0x26000098;
priv->txbbgain_table[22].txbb_iq_amplifygain = -10;
- priv->txbbgain_table[22].txbbgain_value=0x24000090;
+ priv->txbbgain_table[22].txbbgain_value = 0x24000090;
priv->txbbgain_table[23].txbb_iq_amplifygain = -11;
- priv->txbbgain_table[23].txbbgain_value=0x22000088;
+ priv->txbbgain_table[23].txbbgain_value = 0x22000088;
priv->txbbgain_table[24].txbb_iq_amplifygain = -12;
- priv->txbbgain_table[24].txbbgain_value=0x20000080;
+ priv->txbbgain_table[24].txbbgain_value = 0x20000080;
priv->txbbgain_table[25].txbb_iq_amplifygain = -13;
- priv->txbbgain_table[25].txbbgain_value=0x1a00006c;
+ priv->txbbgain_table[25].txbbgain_value = 0x1a00006c;
priv->txbbgain_table[26].txbb_iq_amplifygain = -14;
- priv->txbbgain_table[26].txbbgain_value=0x1c800072;
+ priv->txbbgain_table[26].txbbgain_value = 0x1c800072;
priv->txbbgain_table[27].txbb_iq_amplifygain = -15;
- priv->txbbgain_table[27].txbbgain_value=0x18000060;
+ priv->txbbgain_table[27].txbbgain_value = 0x18000060;
priv->txbbgain_table[28].txbb_iq_amplifygain = -16;
- priv->txbbgain_table[28].txbbgain_value=0x19800066;
+ priv->txbbgain_table[28].txbbgain_value = 0x19800066;
priv->txbbgain_table[29].txbb_iq_amplifygain = -17;
- priv->txbbgain_table[29].txbbgain_value=0x15800056;
+ priv->txbbgain_table[29].txbbgain_value = 0x15800056;
priv->txbbgain_table[30].txbb_iq_amplifygain = -18;
- priv->txbbgain_table[30].txbbgain_value=0x26c0005b;
+ priv->txbbgain_table[30].txbbgain_value = 0x26c0005b;
priv->txbbgain_table[31].txbb_iq_amplifygain = -19;
- priv->txbbgain_table[31].txbbgain_value=0x14400051;
+ priv->txbbgain_table[31].txbbgain_value = 0x14400051;
priv->txbbgain_table[32].txbb_iq_amplifygain = -20;
- priv->txbbgain_table[32].txbbgain_value=0x24400051;
+ priv->txbbgain_table[32].txbbgain_value = 0x24400051;
priv->txbbgain_table[33].txbb_iq_amplifygain = -21;
- priv->txbbgain_table[33].txbbgain_value=0x1300004c;
+ priv->txbbgain_table[33].txbbgain_value = 0x1300004c;
priv->txbbgain_table[34].txbb_iq_amplifygain = -22;
- priv->txbbgain_table[34].txbbgain_value=0x12000048;
+ priv->txbbgain_table[34].txbbgain_value = 0x12000048;
priv->txbbgain_table[35].txbb_iq_amplifygain = -23;
- priv->txbbgain_table[35].txbbgain_value=0x11000044;
+ priv->txbbgain_table[35].txbbgain_value = 0x11000044;
priv->txbbgain_table[36].txbb_iq_amplifygain = -24;
- priv->txbbgain_table[36].txbbgain_value=0x10000040;
+ priv->txbbgain_table[36].txbbgain_value = 0x10000040;
- //ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
- //This Table is for CH1~CH13
+ /*
+ * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+ * This Table is for CH1~CH13
+ */
priv->cck_txbbgain_table[0].ccktxbb_valuearray[0] = 0x36;
priv->cck_txbbgain_table[0].ccktxbb_valuearray[1] = 0x35;
priv->cck_txbbgain_table[0].ccktxbb_valuearray[2] = 0x2e;
@@ -1149,8 +1062,10 @@ static void dm_InitializeTXPowerTracking_TSSI(struct net_device *dev)
priv->cck_txbbgain_table[22].ccktxbb_valuearray[6] = 0x03;
priv->cck_txbbgain_table[22].ccktxbb_valuearray[7] = 0x01;
- //ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
- //This Table is for CH14
+ /*
+ * ccktxbb_valuearray[0] is 0xA22 [1] is 0xA24 ...[7] is 0xA29
+ * This Table is for CH14
+ */
priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[0] = 0x36;
priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[1] = 0x35;
priv->cck_txbbgain_ch14_table[0].ccktxbb_valuearray[2] = 0x2e;
@@ -1368,10 +1283,12 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- // Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
- // can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
- // 3-wire by driver causes RF to go into a wrong state.
- if(priv->ieee80211->FwRWRF)
+ /*
+ * Tx Power tracking by Thermal Meter requires Firmware R/W 3-wire. This mechanism
+ * can be enabled only when Firmware R/W 3-wire is enabled. Otherwise, frequent r/w
+ * 3-wire by driver causes RF to go into a wrong state.
+ */
+ if (priv->ieee80211->FwRWRF)
priv->btxpower_tracking = TRUE;
else
priv->btxpower_tracking = FALSE;
@@ -1379,57 +1296,46 @@ static void dm_InitializeTXPowerTracking_ThermalMeter(struct net_device *dev)
priv->btxpower_trackingInit = FALSE;
}
-
void dm_initialize_txpower_tracking(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- if(priv->bDcut == TRUE)
+
+ if (priv->bDcut == TRUE)
dm_InitializeTXPowerTracking_TSSI(dev);
else
dm_InitializeTXPowerTracking_ThermalMeter(dev);
-}// dm_InitializeTXPowerTracking
-
+} /* dm_InitializeTXPowerTracking */
static void dm_CheckTXPowerTracking_TSSI(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
static u32 tx_power_track_counter;
- if(!priv->btxpower_tracking)
+ if (!priv->btxpower_tracking)
return;
- else
- {
- if((tx_power_track_counter % 30 == 0)&&(tx_power_track_counter != 0))
- {
- queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0);
- }
- tx_power_track_counter++;
- }
-
+ if ((tx_power_track_counter % 30 == 0) && (tx_power_track_counter != 0))
+ queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0);
+ tx_power_track_counter++;
}
-
static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
static u8 TM_Trigger;
- //DbgPrint("dm_CheckTXPowerTracking() \n");
- if(!priv->btxpower_tracking)
+ /*DbgPrint("dm_CheckTXPowerTracking()\n");*/
+ if (!priv->btxpower_tracking)
+ return;
+ if (priv->txpower_count <= 2) {
+ priv->txpower_count++;
return;
- else
- {
- if(priv->txpower_count <= 2)
- {
- priv->txpower_count++;
- return;
- }
}
- if(!TM_Trigger)
- {
- //Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
- //actually write reg0x02 bit1=0, then bit1=1.
- //DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
+ if (!TM_Trigger) {
+ /*
+ * Attention!! You have to write all 12bits of data to RF, or it may cause RF to crash
+ * actually write reg0x02 bit1=0, then bit1=1.
+ * DbgPrint("Trigger ThermalMeter, write RF reg0x2 = 0x4d to 0x4f\n");
+ */
rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4f);
rtl8192_phy_SetRFReg(dev, RF90_PATH_A, 0x02, bMask12Bits, 0x4d);
@@ -1437,93 +1343,84 @@ static void dm_CheckTXPowerTracking_ThermalMeter(struct net_device *dev)
TM_Trigger = 1;
return;
}
- else
- {
- //DbgPrint("Schedule TxPowerTrackingWorkItem\n");
- queue_delayed_work(priv->priv_wq,&priv->txpower_tracking_wq,0);
- TM_Trigger = 0;
- }
+ /*DbgPrint("Schedule TxPowerTrackingWorkItem\n");*/
+ queue_delayed_work(priv->priv_wq, &priv->txpower_tracking_wq, 0);
+ TM_Trigger = 0;
}
-
static void dm_check_txpower_tracking(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //static u32 tx_power_track_counter = 0;
+ /*static u32 tx_power_track_counter = 0;*/
-#ifdef RTL8190P
+#ifdef RTL8190P
dm_CheckTXPowerTracking_TSSI(dev);
#else
- if(priv->bDcut == TRUE)
+ if (priv->bDcut == TRUE)
dm_CheckTXPowerTracking_TSSI(dev);
else
dm_CheckTXPowerTracking_ThermalMeter(dev);
#endif
-} // dm_CheckTXPowerTracking
-
+} /* dm_CheckTXPowerTracking */
static void dm_CCKTxPowerAdjust_TSSI(struct net_device *dev, bool bInCH14)
{
u32 TempVal;
struct r8192_priv *priv = ieee80211_priv(dev);
- //Write 0xa22 0xa23
+
+ /* Write 0xa22 0xa23 */
TempVal = 0;
- if(!bInCH14){
- //Write 0xa22 0xa23
+ if (!bInCH14) {
+ /* Write 0xa22 0xa23 */
TempVal = priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[0] +
- (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8) ;
+ (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8);
rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- //Write 0xa24 ~ 0xa27
+ /* Write 0xa24 ~ 0xa27 */
TempVal = priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[2] +
(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[3]<<8) +
(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[4]<<16)+
(priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[5]<<24);
rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- //Write 0xa28 0xa29
+ /* Write 0xa28 0xa29 */
TempVal = priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[6] +
- (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8) ;
+ (priv->cck_txbbgain_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8);
rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
- }
- else
- {
+ } else {
TempVal = priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[0] +
- (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8) ;
+ (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[1]<<8);
rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
- //Write 0xa24 ~ 0xa27
+ /* Write 0xa24 ~ 0xa27 */
TempVal = priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[2] +
(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[3]<<8) +
(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[4]<<16)+
(priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[5]<<24);
rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
- //Write 0xa28 0xa29
+ /* Write 0xa28 0xa29 */
TempVal = priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[6] +
- (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8) ;
+ (priv->cck_txbbgain_ch14_table[priv->cck_present_attentuation].ccktxbb_valuearray[7]<<8);
rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
}
-
-
}
-static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH14)
+static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH14)
{
u32 TempVal;
struct r8192_priv *priv = ieee80211_priv(dev);
TempVal = 0;
- if(!bInCH14)
- {
- //Write 0xa22 0xa23
+ if (!bInCH14) {
+ /* Write 0xa22 0xa23 */
TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][0] +
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8) ;
+ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][1]<<8);
rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter1, TempVal);
- //Write 0xa24 ~ 0xa27
+ /* Write 0xa24 ~ 0xa27 */
TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][2] +
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][3]<<8) +
(CCKSwingTable_Ch1_Ch13[priv->CCK_index][4]<<16)+
@@ -1531,25 +1428,23 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH
rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter2, TempVal);
- //Write 0xa28 0xa29
+ /* Write 0xa28 0xa29 */
TempVal = CCKSwingTable_Ch1_Ch13[priv->CCK_index][6] +
- (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8) ;
+ (CCKSwingTable_Ch1_Ch13[priv->CCK_index][7]<<8);
rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK not chnl 14, reg 0x%x = 0x%x\n",
rCCK0_DebugPort, TempVal);
- }
- else
- {
-// priv->CCKTxPowerAdjustCntNotCh14++; //cosa add for debug.
- //Write 0xa22 0xa23
+ } else {
+ /*priv->CCKTxPowerAdjustCntNotCh14++; cosa add for debug.*/
+ /* Write 0xa22 0xa23 */
TempVal = CCKSwingTable_Ch14[priv->CCK_index][0] +
- (CCKSwingTable_Ch14[priv->CCK_index][1]<<8) ;
+ (CCKSwingTable_Ch14[priv->CCK_index][1]<<8);
rtl8192_setBBreg(dev, rCCK0_TxFilter1, bMaskHWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter1, TempVal);
- //Write 0xa24 ~ 0xa27
+ /* Write 0xa24 ~ 0xa27 */
TempVal = CCKSwingTable_Ch14[priv->CCK_index][2] +
(CCKSwingTable_Ch14[priv->CCK_index][3]<<8) +
(CCKSwingTable_Ch14[priv->CCK_index][4]<<16)+
@@ -1557,9 +1452,9 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH
rtl8192_setBBreg(dev, rCCK0_TxFilter2, bMaskDWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
rCCK0_TxFilter2, TempVal);
- //Write 0xa28 0xa29
+ /* Write 0xa28 0xa29 */
TempVal = CCKSwingTable_Ch14[priv->CCK_index][6] +
- (CCKSwingTable_Ch14[priv->CCK_index][7]<<8) ;
+ (CCKSwingTable_Ch14[priv->CCK_index][7]<<8);
rtl8192_setBBreg(dev, rCCK0_DebugPort, bMaskLWord, TempVal);
RT_TRACE(COMP_POWER_TRACKING, "CCK chnl 14, reg 0x%x = 0x%x\n",
@@ -1567,20 +1462,17 @@ static void dm_CCKTxPowerAdjust_ThermalMeter(struct net_device *dev, bool bInCH
}
}
-
-
void dm_cck_txpower_adjust(struct net_device *dev, bool binch14)
-{ // dm_CCKTxPowerAdjust
-
+{ /* dm_CCKTxPowerAdjust */
struct r8192_priv *priv = ieee80211_priv(dev);
- if(priv->bDcut == TRUE)
+
+ if (priv->bDcut == TRUE)
dm_CCKTxPowerAdjust_TSSI(dev, binch14);
else
dm_CCKTxPowerAdjust_ThermalMeter(dev, binch14);
}
-
-#ifndef RTL8192U
+#ifndef RTL8192U
static void dm_txpower_reset_recovery(
struct net_device *dev
)
@@ -1589,75 +1481,71 @@ static void dm_txpower_reset_recovery(
RT_TRACE(COMP_POWER_TRACKING, "Start Reset Recovery ==>\n");
rtl8192_setBBreg(dev, rOFDM0_XATxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n",priv->rfa_txpowertrackingindex);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n",priv->cck_present_attentuation);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc80 is %08x\n", priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbbgain_value);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFA_txPowerTrackingIndex is %x\n", priv->rfa_txpowertrackingindex);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF A I/Q Amplify Gain is %ld\n", priv->txbbgain_table[priv->rfa_txpowertrackingindex].txbb_iq_amplifygain);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: CCK Attenuation is %d dB\n", priv->cck_present_attentuation);
dm_cck_txpower_adjust(dev, priv->bcck_in_ch14);
rtl8192_setBBreg(dev, rOFDM0_XCTxIQImbalance, bMaskDWord, priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n",priv->rfc_txpowertrackingindex);
- RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n",priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in 0xc90 is %08x\n", priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbbgain_value);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery: Fill in RFC_txPowerTrackingIndex is %x\n", priv->rfc_txpowertrackingindex);
+ RT_TRACE(COMP_POWER_TRACKING, "Reset Recovery : RF C I/Q Amplify Gain is %ld\n", priv->txbbgain_table[priv->rfc_txpowertrackingindex].txbb_iq_amplifygain);
-} // dm_TXPowerResetRecovery
+} /* dm_TXPowerResetRecovery */
void dm_restore_dynamic_mechanism_state(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
u32 reg_ratr = priv->rate_adaptive.last_ratr;
- if(!priv->up)
- {
+ if (!priv->up) {
RT_TRACE(COMP_RATE, "<---- dm_restore_dynamic_mechanism_state(): driver is going to unload\n");
return;
}
- //
- // Restore previous state for rate adaptive
- //
- if(priv->rate_adaptive.rate_adaptive_disabled)
+ /* Restore previous state for rate adaptive */
+ if (priv->rate_adaptive.rate_adaptive_disabled)
return;
- // TODO: Only 11n mode is implemented currently,
- if(!(priv->ieee80211->mode==WIRELESS_MODE_N_24G ||
- priv->ieee80211->mode==WIRELESS_MODE_N_5G))
- return;
+ /* TODO: Only 11n mode is implemented currently, */
+ if (!(priv->ieee80211->mode == WIRELESS_MODE_N_24G ||
+ priv->ieee80211->mode == WIRELESS_MODE_N_5G))
+ return;
+
{
/* 2007/11/15 MH Copy from 8190PCI. */
u32 ratr_value;
+
ratr_value = reg_ratr;
- if(priv->rf_type == RF_1T2R) // 1T2R, Spatial Stream 2 should be disabled
- {
+ if (priv->rf_type == RF_1T2R) { /* 1T2R, Spatial Stream 2 should be disabled */
ratr_value &= ~(RATE_ALL_OFDM_2SS);
- //DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value);
+ /*DbgPrint("HW_VAR_TATR_0 from 0x%x ==> 0x%x\n", ((pu4Byte)(val))[0], ratr_value);*/
}
- //DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value);
- //cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]);
+ /*DbgPrint("set HW_VAR_TATR_0 = 0x%x\n", ratr_value);*/
+ /*cosa PlatformEFIOWrite4Byte(Adapter, RATR0, ((pu4Byte)(val))[0]);*/
write_nic_dword(dev, RATR0, ratr_value);
write_nic_byte(dev, UFWP, 1);
}
- //Restore TX Power Tracking Index
+ /* Restore TX Power Tracking Index */
if (priv->btxpower_trackingInit && priv->btxpower_tracking)
dm_txpower_reset_recovery(dev);
- //
- //Restore BB Initial Gain
- //
+ /* Restore BB Initial Gain */
dm_bb_initialgain_restore(dev);
-} // DM_RestoreDynamicMechanismState
+} /* DM_RestoreDynamicMechanismState */
static void dm_bb_initialgain_restore(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- u32 bit_mask = 0x7f; //Bit0~ Bit6
+ u32 bit_mask = 0x7f; /* Bit0~ Bit6 */
- if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
+ if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
return;
- //Disable Initial Gain
- //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite.
+ /* Disable Initial Gain */
+ /*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);*/
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); /* Only clear byte 1 and rewrite. */
rtl8192_setBBreg(dev, rOFDM0_XAAGCCore1, bit_mask, (u32)priv->initgain_backup.xaagccore1);
rtl8192_setBBreg(dev, rOFDM0_XBAGCCore1, bit_mask, (u32)priv->initgain_backup.xbagccore1);
rtl8192_setBBreg(dev, rOFDM0_XCAGCCore1, bit_mask, (u32)priv->initgain_backup.xcagccore1);
@@ -1665,41 +1553,39 @@ static void dm_bb_initialgain_restore(struct net_device *dev)
bit_mask = bMaskByte2;
rtl8192_setBBreg(dev, rCCK0_CCA, bit_mask, (u32)priv->initgain_backup.cca);
- RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n",priv->initgain_backup.xaagccore1);
- RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n",priv->initgain_backup.xbagccore1);
- RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n",priv->initgain_backup.xcagccore1);
- RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n",priv->initgain_backup.xdagccore1);
- RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n",priv->initgain_backup.cca);
- //Enable Initial Gain
- //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100);
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite.
-
-} // dm_BBInitialGainRestore
+ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc50 is %x\n", priv->initgain_backup.xaagccore1);
+ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc58 is %x\n", priv->initgain_backup.xbagccore1);
+ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc60 is %x\n", priv->initgain_backup.xcagccore1);
+ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xc68 is %x\n", priv->initgain_backup.xdagccore1);
+ RT_TRACE(COMP_DIG, "dm_BBInitialGainRestore 0xa0a is %x\n", priv->initgain_backup.cca);
+ /* Enable Initial Gain */
+ /*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x100);*/
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); /* Only clear byte 1 and rewrite. */
+} /* dm_BBInitialGainRestore */
void dm_backup_dynamic_mechanism_state(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- // Fsync to avoid reset
+ /* Fsync to avoid reset */
priv->bswitch_fsync = false;
priv->bfsync_processing = false;
- //Backup BB InitialGain
+ /* Backup BB InitialGain */
dm_bb_initialgain_backup(dev);
-} // DM_BackupDynamicMechanismState
-
+} /* DM_BackupDynamicMechanismState */
static void dm_bb_initialgain_backup(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- u32 bit_mask = bMaskByte0; //Bit0~ Bit6
+ u32 bit_mask = bMaskByte0; /* Bit0~ Bit6 */
- if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
+ if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
return;
- //PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite.
+ /*PHY_SetBBReg(Adapter, UFWP, bMaskLWord, 0x800);*/
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); /* Only clear byte 1 and rewrite. */
priv->initgain_backup.xaagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XAAGCCore1, bit_mask);
priv->initgain_backup.xbagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XBAGCCore1, bit_mask);
priv->initgain_backup.xcagccore1 = (u8)rtl8192_QueryBBReg(dev, rOFDM0_XCAGCCore1, bit_mask);
@@ -1707,13 +1593,13 @@ static void dm_bb_initialgain_backup(struct net_device *dev)
bit_mask = bMaskByte2;
priv->initgain_backup.cca = (u8)rtl8192_QueryBBReg(dev, rCCK0_CCA, bit_mask);
- RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n",priv->initgain_backup.xaagccore1);
- RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n",priv->initgain_backup.xbagccore1);
- RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n",priv->initgain_backup.xcagccore1);
- RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n",priv->initgain_backup.xdagccore1);
- RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n",priv->initgain_backup.cca);
+ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc50 is %x\n", priv->initgain_backup.xaagccore1);
+ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc58 is %x\n", priv->initgain_backup.xbagccore1);
+ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc60 is %x\n", priv->initgain_backup.xcagccore1);
+ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xc68 is %x\n", priv->initgain_backup.xdagccore1);
+ RT_TRACE(COMP_DIG, "BBInitialGainBackup 0xa0a is %x\n", priv->initgain_backup.cca);
-} // dm_BBInitialGainBakcup
+} /* dm_BBInitialGainBakcup */
#endif
/*-----------------------------------------------------------------------------
@@ -1736,67 +1622,44 @@ static void dm_bb_initialgain_backup(struct net_device *dev)
void dm_change_dynamic_initgain_thresh(struct net_device *dev, u32 dm_type,
u32 dm_value)
{
- if (dm_type == DIG_TYPE_THRESH_HIGH)
- {
+ if (dm_type == DIG_TYPE_THRESH_HIGH) {
dm_digtable.rssi_high_thresh = dm_value;
- }
- else if (dm_type == DIG_TYPE_THRESH_LOW)
- {
+ } else if (dm_type == DIG_TYPE_THRESH_LOW) {
dm_digtable.rssi_low_thresh = dm_value;
- }
- else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH)
- {
+ } else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
dm_digtable.rssi_high_power_highthresh = dm_value;
- }
- else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH)
- {
+ } else if (dm_type == DIG_TYPE_THRESH_HIGHPWR_HIGH) {
dm_digtable.rssi_high_power_highthresh = dm_value;
- }
- else if (dm_type == DIG_TYPE_ENABLE)
- {
+ } else if (dm_type == DIG_TYPE_ENABLE) {
dm_digtable.dig_state = DM_STA_DIG_MAX;
dm_digtable.dig_enable_flag = true;
- }
- else if (dm_type == DIG_TYPE_DISABLE)
- {
+ } else if (dm_type == DIG_TYPE_DISABLE) {
dm_digtable.dig_state = DM_STA_DIG_MAX;
dm_digtable.dig_enable_flag = false;
- }
- else if (dm_type == DIG_TYPE_DBG_MODE)
- {
- if(dm_value >= DM_DBG_MAX)
+ } else if (dm_type == DIG_TYPE_DBG_MODE) {
+ if (dm_value >= DM_DBG_MAX)
dm_value = DM_DBG_OFF;
dm_digtable.dbg_mode = (u8)dm_value;
- }
- else if (dm_type == DIG_TYPE_RSSI)
- {
- if(dm_value > 100)
+ } else if (dm_type == DIG_TYPE_RSSI) {
+ if (dm_value > 100)
dm_value = 30;
dm_digtable.rssi_val = (long)dm_value;
- }
- else if (dm_type == DIG_TYPE_ALGORITHM)
- {
+ } else if (dm_type == DIG_TYPE_ALGORITHM) {
if (dm_value >= DIG_ALGO_MAX)
dm_value = DIG_ALGO_BY_FALSE_ALARM;
- if(dm_digtable.dig_algorithm != (u8)dm_value)
+ if (dm_digtable.dig_algorithm != (u8)dm_value)
dm_digtable.dig_algorithm_switch = 1;
dm_digtable.dig_algorithm = (u8)dm_value;
- }
- else if (dm_type == DIG_TYPE_BACKOFF)
- {
- if(dm_value > 30)
+ } else if (dm_type == DIG_TYPE_BACKOFF) {
+ if (dm_value > 30)
dm_value = 30;
dm_digtable.backoff_val = (u8)dm_value;
- }
- else if(dm_type == DIG_TYPE_RX_GAIN_MIN)
- {
- if(dm_value == 0)
+ } else if (dm_type == DIG_TYPE_RX_GAIN_MIN) {
+ if (dm_value == 0)
dm_value = 0x1;
dm_digtable.rx_gain_range_min = (u8)dm_value;
- }
- else if(dm_type == DIG_TYPE_RX_GAIN_MAX)
- {
- if(dm_value > 0x50)
+ } else if (dm_type == DIG_TYPE_RX_GAIN_MAX) {
+ if (dm_value > 0x50)
dm_value = 0x50;
dm_digtable.rx_gain_range_max = (u8)dm_value;
}
@@ -1824,7 +1687,7 @@ static void dm_dig_init(struct net_device *dev)
/* 2007/10/05 MH Disable DIG scheme now. Not tested. */
dm_digtable.dig_enable_flag = true;
dm_digtable.dig_algorithm = DIG_ALGO_BY_RSSI;
- dm_digtable.dbg_mode = DM_DBG_OFF; //off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig
+ dm_digtable.dbg_mode = DM_DBG_OFF; /* off=by real rssi value, on=by DM_DigTable.Rssi_val for new dig */
dm_digtable.dig_algorithm_switch = 0;
/* 2007/10/04 MH Define init gain threshold. */
@@ -1838,17 +1701,16 @@ static void dm_dig_init(struct net_device *dev)
dm_digtable.rssi_high_power_lowthresh = DM_DIG_HIGH_PWR_THRESH_LOW;
dm_digtable.rssi_high_power_highthresh = DM_DIG_HIGH_PWR_THRESH_HIGH;
- dm_digtable.rssi_val = 50; //for new dig debug rssi value
+ dm_digtable.rssi_val = 50; /* for new dig debug rssi value */
dm_digtable.backoff_val = DM_DIG_BACKOFF;
dm_digtable.rx_gain_range_max = DM_DIG_MAX;
- if(priv->CustomerID == RT_CID_819x_Netcore)
+ if (priv->CustomerID == RT_CID_819x_Netcore)
dm_digtable.rx_gain_range_min = DM_DIG_MIN_Netcore;
else
dm_digtable.rx_gain_range_min = DM_DIG_MIN;
} /* dm_dig_init */
-
/*-----------------------------------------------------------------------------
* Function: dm_ctrl_initgain_byrssi()
*
@@ -1868,20 +1730,18 @@ static void dm_dig_init(struct net_device *dev)
*---------------------------------------------------------------------------*/
static void dm_ctrl_initgain_byrssi(struct net_device *dev)
{
-
if (dm_digtable.dig_enable_flag == false)
return;
- if(dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
+ if (dm_digtable.dig_algorithm == DIG_ALGO_BY_FALSE_ALARM)
dm_ctrl_initgain_byrssi_by_fwfalse_alarm(dev);
- else if(dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
+ else if (dm_digtable.dig_algorithm == DIG_ALGO_BY_RSSI)
dm_ctrl_initgain_byrssi_by_driverrssi(dev);
-// ;
+ /* ; */
else
return;
}
-
static void dm_ctrl_initgain_byrssi_by_driverrssi(
struct net_device *dev)
{
@@ -1892,32 +1752,33 @@ static void dm_ctrl_initgain_byrssi_by_driverrssi(
if (dm_digtable.dig_enable_flag == false)
return;
- //DbgPrint("Dig by Sw Rssi \n");
- if(dm_digtable.dig_algorithm_switch) // if switched algorithm, we have to disable FW Dig.
+ /*DbgPrint("Dig by Sw Rssi\n");*/
+ if (dm_digtable.dig_algorithm_switch) /* if switched algorithm, we have to disable FW Dig. */
fw_dig = 0;
- if(fw_dig <= 3) // execute several times to make sure the FW Dig is disabled
- {// FW DIG Off
- for(i=0; i<3; i++)
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite.
+
+ if (fw_dig <= 3) { /* execute several times to make sure the FW Dig is disabled */
+ /* FW DIG Off */
+ for (i = 0; i < 3; i++)
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); /* Only clear byte 1 and rewrite. */
fw_dig++;
- dm_digtable.dig_state = DM_STA_DIG_OFF; //fw dig off.
+ dm_digtable.dig_state = DM_STA_DIG_OFF; /* fw dig off. */
}
- if(priv->ieee80211->state == IEEE80211_LINKED)
+ if (priv->ieee80211->state == IEEE80211_LINKED)
dm_digtable.cur_connect_state = DIG_CONNECT;
else
dm_digtable.cur_connect_state = DIG_DISCONNECT;
- //DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d \n",
- //DM_DigTable.PreConnectState, DM_DigTable.CurConnectState);
+ /*DbgPrint("DM_DigTable.PreConnectState = %d, DM_DigTable.CurConnectState = %d\n",
+ DM_DigTable.PreConnectState, DM_DigTable.CurConnectState);*/
- if(dm_digtable.dbg_mode == DM_DBG_OFF)
+ if (dm_digtable.dbg_mode == DM_DBG_OFF)
dm_digtable.rssi_val = priv->undecorated_smoothed_pwdb;
- //DbgPrint("DM_DigTable.Rssi_val = %d \n", DM_DigTable.Rssi_val);
+ /*DbgPrint("DM_DigTable.Rssi_val = %d\n", DM_DigTable.Rssi_val);*/
dm_initial_gain(dev);
dm_pd_th(dev);
dm_cs_ratio(dev);
- if(dm_digtable.dig_algorithm_switch)
+ if (dm_digtable.dig_algorithm_switch)
dm_digtable.dig_algorithm_switch = 0;
dm_digtable.pre_connect_state = dm_digtable.cur_connect_state;
@@ -1933,152 +1794,138 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
if (dm_digtable.dig_enable_flag == false)
return;
- if(dm_digtable.dig_algorithm_switch)
- {
+ if (dm_digtable.dig_algorithm_switch) {
dm_digtable.dig_state = DM_STA_DIG_MAX;
- // Fw DIG On.
- for(i=0; i<3; i++)
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite.
+ /* Fw DIG On. */
+ for (i = 0; i < 3; i++)
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); /* Only clear byte 1 and rewrite.*/
dm_digtable.dig_algorithm_switch = 0;
}
if (priv->ieee80211->state != IEEE80211_LINKED)
return;
- // For smooth, we can not change DIG state.
+ /* For smooth, we can not change DIG state. */
if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_low_thresh) &&
(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_thresh))
- {
return;
- }
- //DbgPrint("Dig by Fw False Alarm\n");
- //if (DM_DigTable.Dig_State == DM_STA_DIG_OFF)
+
+ /*DbgPrint("Dig by Fw False Alarm\n");*/
+ /*if (DM_DigTable.Dig_State == DM_STA_DIG_OFF)*/
/*DbgPrint("DIG Check\n\r RSSI=%d LOW=%d HIGH=%d STATE=%d",
pHalData->UndecoratedSmoothedPWDB, DM_DigTable.RssiLowThresh,
DM_DigTable.RssiHighThresh, DM_DigTable.Dig_State);*/
/* 1. When RSSI decrease, We have to judge if it is smaller than a threshold
and then execute the step below. */
- if ((priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh))
- {
+ if (priv->undecorated_smoothed_pwdb <= dm_digtable.rssi_low_thresh) {
/* 2008/02/05 MH When we execute silent reset, the DIG PHY parameters
will be reset to init value. We must prevent the condition. */
if (dm_digtable.dig_state == DM_STA_DIG_OFF &&
- (priv->reset_count == reset_cnt))
- {
+ (priv->reset_count == reset_cnt)) {
return;
}
- else
- {
- reset_cnt = priv->reset_count;
- }
+ reset_cnt = priv->reset_count;
- // If DIG is off, DIG high power state must reset.
+ /* If DIG is off, DIG high power state must reset. */
dm_digtable.dig_highpwr_state = DM_STA_DIG_MAX;
dm_digtable.dig_state = DM_STA_DIG_OFF;
- // 1.1 DIG Off.
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); // Only clear byte 1 and rewrite.
+ /* 1.1 DIG Off. */
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x8); /* Only clear byte 1 and rewrite. */
- // 1.2 Set initial gain.
+ /* 1.2 Set initial gain. */
write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x17);
write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x17);
write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x17);
write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x17);
- // 1.3 Lower PD_TH for OFDM.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
- /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
- // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ /* 1.3 Lower PD_TH for OFDM. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+ /*
+ * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ */
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(pAdapter, rOFDM0_RxDetector1, 0x40);
+ else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
+ else
+ PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40);
*/
- //else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
-
-
- //else
- //PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x40);
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
- // 1.4 Lower CS ratio for CCK.
+ /* 1.4 Lower CS ratio for CCK. */
write_nic_byte(dev, 0xa0a, 0x08);
- // 1.5 Higher EDCCA.
- //PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325);
+ /* 1.5 Higher EDCCA. */
+ /*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x325);*/
return;
}
/* 2. When RSSI increase, We have to judge if it is larger than a threshold
and then execute the step below. */
- if ((priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh))
- {
+ if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) {
u8 reset_flag = 0;
if (dm_digtable.dig_state == DM_STA_DIG_ON &&
- (priv->reset_count == reset_cnt))
- {
+ (priv->reset_count == reset_cnt)) {
dm_ctrl_initgain_byrssi_highpwr(dev);
return;
}
- else
- {
- if (priv->reset_count != reset_cnt)
- reset_flag = 1;
+ if (priv->reset_count != reset_cnt)
+ reset_flag = 1;
- reset_cnt = priv->reset_count;
- }
+ reset_cnt = priv->reset_count;
dm_digtable.dig_state = DM_STA_DIG_ON;
- //DbgPrint("DIG ON\n\r");
+ /*DbgPrint("DIG ON\n\r");*/
- // 2.1 Set initial gain.
- // 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
- if (reset_flag == 1)
- {
+ /*
+ * 2.1 Set initial gain.
+ * 2008/02/26 MH SD3-Jerry suggest to prevent dirty environment.
+ */
+ if (reset_flag == 1) {
write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x2c);
write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x2c);
write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x2c);
write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x2c);
- }
- else
- {
+ } else {
write_nic_byte(dev, rOFDM0_XAAGCCore1, 0x20);
write_nic_byte(dev, rOFDM0_XBAGCCore1, 0x20);
write_nic_byte(dev, rOFDM0_XCAGCCore1, 0x20);
write_nic_byte(dev, rOFDM0_XDAGCCore1, 0x20);
}
- // 2.2 Higher PD_TH for OFDM.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
- /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
- // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ /* 2.2 Higher PD_TH for OFDM. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+ /*
+ * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ */
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
/*
else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
+ else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
+ else
+ PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42);
*/
- //else if (pAdapter->HardwareType == HARDWARE_TYPE_RTL8192E)
-
- //else
- //PlatformEFIOWrite1Byte(pAdapter, rOFDM0_RxDetector1, 0x42);
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x44);
- // 2.3 Higher CS ratio for CCK.
+ /* 2.3 Higher CS ratio for CCK. */
write_nic_byte(dev, 0xa0a, 0xcd);
- // 2.4 Lower EDCCA.
- /* 2008/01/11 MH 90/92 series are the same. */
- //PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);
+ /*
+ * 2.4 Lower EDCCA.
+ * 2008/01/11 MH 90/92 series are the same.
+ */
+ /*PlatformEFIOWrite4Byte(pAdapter, rOFDM0_ECCAThreshold, 0x346);*/
- // 2.5 DIG On.
- rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); // Only clear byte 1 and rewrite.
+ /* 2.5 DIG On. */
+ rtl8192_setBBreg(dev, UFWP, bMaskByte1, 0x1); /* Only clear byte 1 and rewrite. */
}
@@ -2086,7 +1933,6 @@ static void dm_ctrl_initgain_byrssi_by_fwfalse_alarm(
} /* dm_CtrlInitGainByRssi */
-
/*-----------------------------------------------------------------------------
* Function: dm_ctrl_initgain_byrssi_highpwr()
*
@@ -2109,58 +1955,49 @@ static void dm_ctrl_initgain_byrssi_highpwr(
struct r8192_priv *priv = ieee80211_priv(dev);
static u32 reset_cnt_highpwr;
- // For smooth, we can not change high power DIG state in the range.
+ /* For smooth, we can not change high power DIG state in the range. */
if ((priv->undecorated_smoothed_pwdb > dm_digtable.rssi_high_power_lowthresh) &&
(priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_highthresh))
- {
return;
- }
- /* 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
- it is larger than a threshold and then execute the step below. */
- // 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
- if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh)
- {
+ /*
+ * 3. When RSSI >75% or <70%, it is a high power issue. We have to judge if
+ * it is larger than a threshold and then execute the step below.
+ *
+ * 2008/02/05 MH SD3-Jerry Modify PD_TH for high power issue.
+ */
+ if (priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_power_highthresh) {
if (dm_digtable.dig_highpwr_state == DM_STA_DIG_ON &&
(priv->reset_count == reset_cnt_highpwr))
return;
- else
- dm_digtable.dig_highpwr_state = DM_STA_DIG_ON;
+ dm_digtable.dig_highpwr_state = DM_STA_DIG_ON;
- // 3.1 Higher PD_TH for OFDM for high power state.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
+ /* 3.1 Higher PD_TH for OFDM for high power state. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10);
/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(dev, rOFDM0_RxDetector1, 0x41);
*/
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x43);
- }
- else
- {
- if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF&&
+ } else {
+ if (dm_digtable.dig_highpwr_state == DM_STA_DIG_OFF &&
(priv->reset_count == reset_cnt_highpwr))
return;
- else
- dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF;
+ dm_digtable.dig_highpwr_state = DM_STA_DIG_OFF;
if (priv->undecorated_smoothed_pwdb < dm_digtable.rssi_high_power_lowthresh &&
- priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh)
- {
- // 3.2 Recover PD_TH for OFDM for normal power region.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
+ priv->undecorated_smoothed_pwdb >= dm_digtable.rssi_high_thresh) {
+ /* 3.2 Recover PD_TH for OFDM for normal power region. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
*/
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x44);
}
}
@@ -2169,51 +2006,42 @@ static void dm_ctrl_initgain_byrssi_highpwr(
} /* dm_CtrlInitGainByRssiHighPwr */
-
static void dm_initial_gain(
struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- u8 initial_gain=0;
+ u8 initial_gain = 0;
static u8 initialized, force_write;
static u32 reset_cnt;
u8 tmp;
- if(dm_digtable.dig_algorithm_switch)
- {
+ if (dm_digtable.dig_algorithm_switch) {
initialized = 0;
reset_cnt = 0;
}
- if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
- {
- if(dm_digtable.cur_connect_state == DIG_CONNECT)
- {
- if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max)
+ if (dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) {
+ if (dm_digtable.cur_connect_state == DIG_CONNECT) {
+ if ((dm_digtable.rssi_val+10-dm_digtable.backoff_val) > dm_digtable.rx_gain_range_max)
dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_max;
- else if((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min)
+ else if ((dm_digtable.rssi_val+10-dm_digtable.backoff_val) < dm_digtable.rx_gain_range_min)
dm_digtable.cur_ig_value = dm_digtable.rx_gain_range_min;
else
dm_digtable.cur_ig_value = dm_digtable.rssi_val+10-dm_digtable.backoff_val;
- }
- else //current state is disconnected
- {
- if(dm_digtable.cur_ig_value == 0)
+ } else { /* current state is disconnected */
+ if (dm_digtable.cur_ig_value == 0)
dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
else
dm_digtable.cur_ig_value = dm_digtable.pre_ig_value;
}
- }
- else // disconnected -> connected or connected -> disconnected
- {
+ } else { /* disconnected -> connected or connected -> disconnected */
dm_digtable.cur_ig_value = priv->DefaultInitialGain[0];
dm_digtable.pre_ig_value = 0;
}
- //DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue);
+ /*DbgPrint("DM_DigTable.CurIGValue = 0x%x, DM_DigTable.PreIGValue = 0x%x\n", DM_DigTable.CurIGValue, DM_DigTable.PreIGValue);*/
- // if silent reset happened, we should rewrite the values back
- if(priv->reset_count != reset_cnt)
- {
+ /* if silent reset happened, we should rewrite the values back */
+ if (priv->reset_count != reset_cnt) {
force_write = 1;
reset_cnt = priv->reset_count;
}
@@ -2223,12 +2051,11 @@ static void dm_initial_gain(
force_write = 1;
{
- if((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value)
- || !initialized || force_write)
- {
+ if ((dm_digtable.pre_ig_value != dm_digtable.cur_ig_value)
+ || !initialized || force_write) {
initial_gain = (u8)dm_digtable.cur_ig_value;
- //DbgPrint("Write initial gain = 0x%x\n", initial_gain);
- // Set initial gain.
+ /*DbgPrint("Write initial gain = 0x%x\n", initial_gain);*/
+ /* Set initial gain. */
write_nic_byte(dev, rOFDM0_XAAGCCore1, initial_gain);
write_nic_byte(dev, rOFDM0_XBAGCCore1, initial_gain);
write_nic_byte(dev, rOFDM0_XCAGCCore1, initial_gain);
@@ -2247,93 +2074,77 @@ static void dm_pd_th(
static u8 initialized, force_write;
static u32 reset_cnt;
- if(dm_digtable.dig_algorithm_switch)
- {
+ if (dm_digtable.dig_algorithm_switch) {
initialized = 0;
reset_cnt = 0;
}
- if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
- {
- if(dm_digtable.cur_connect_state == DIG_CONNECT)
- {
+ if (dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) {
+ if (dm_digtable.cur_connect_state == DIG_CONNECT) {
if (dm_digtable.rssi_val >= dm_digtable.rssi_high_power_highthresh)
dm_digtable.curpd_thstate = DIG_PD_AT_HIGH_POWER;
- else if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh))
+ else if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)
dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh) &&
(dm_digtable.rssi_val < dm_digtable.rssi_high_power_lowthresh))
dm_digtable.curpd_thstate = DIG_PD_AT_NORMAL_POWER;
else
dm_digtable.curpd_thstate = dm_digtable.prepd_thstate;
- }
- else
- {
+ } else {
dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
}
- }
- else // disconnected -> connected or connected -> disconnected
- {
+ } else { /* disconnected -> connected or connected -> disconnected */
dm_digtable.curpd_thstate = DIG_PD_AT_LOW_POWER;
}
- // if silent reset happened, we should rewrite the values back
- if(priv->reset_count != reset_cnt)
- {
+ /* if silent reset happened, we should rewrite the values back */
+ if (priv->reset_count != reset_cnt) {
force_write = 1;
reset_cnt = priv->reset_count;
}
{
- if((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
- (initialized<=3) || force_write)
- {
- //DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState);
- if(dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER)
- {
- // Lower PD_TH for OFDM.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
- /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
- // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ if ((dm_digtable.prepd_thstate != dm_digtable.curpd_thstate) ||
+ (initialized <= 3) || force_write) {
+ /*DbgPrint("Write PD_TH state = %d\n", DM_DigTable.CurPD_THState);*/
+ if (dm_digtable.curpd_thstate == DIG_PD_AT_LOW_POWER) {
+ /* Lower PD_TH for OFDM. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+ /*
+ * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ */
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x00);
/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(dev, rOFDM0_RxDetector1, 0x40);
*/
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
- }
- else if(dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER)
- {
- // Higher PD_TH for OFDM.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
- /* 2008/01/11 MH 40MHZ 90/92 register are not the same. */
- // 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ } else if (dm_digtable.curpd_thstate == DIG_PD_AT_NORMAL_POWER) {
+ /* Higher PD_TH for OFDM. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
+ /*
+ * 2008/01/11 MH 40MHZ 90/92 register are not the same.
+ * 2008/02/05 MH SD3-Jerry 92U/92E PD_TH are the same.
+ */
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x20);
/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(dev, rOFDM0_RxDetector1, 0x42);
*/
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x44);
- }
- else if(dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER)
- {
- // Higher PD_TH for OFDM for high power state.
- if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20)
- {
+ } else if (dm_digtable.curpd_thstate == DIG_PD_AT_HIGH_POWER) {
+ /* Higher PD_TH for OFDM for high power state. */
+ if (priv->CurrentChannelBW != HT_CHANNEL_WIDTH_20) {
write_nic_byte(dev, (rOFDM0_XATxAFE+3), 0x10);
/*else if (priv->card_8192 == HARDWARE_TYPE_RTL8190P)
write_nic_byte(dev, rOFDM0_RxDetector1, 0x41);
*/
- }
- else
+ } else
write_nic_byte(dev, rOFDM0_RxDetector1, 0x43);
}
dm_digtable.prepd_thstate = dm_digtable.curpd_thstate;
- if(initialized <= 3)
+ if (initialized <= 3)
initialized++;
force_write = 0;
}
@@ -2347,54 +2158,40 @@ static void dm_cs_ratio(
static u8 initialized, force_write;
static u32 reset_cnt;
- if(dm_digtable.dig_algorithm_switch)
- {
+ if (dm_digtable.dig_algorithm_switch) {
initialized = 0;
reset_cnt = 0;
}
- if(dm_digtable.pre_connect_state == dm_digtable.cur_connect_state)
- {
- if(dm_digtable.cur_connect_state == DIG_CONNECT)
- {
- if ((dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh))
+ if (dm_digtable.pre_connect_state == dm_digtable.cur_connect_state) {
+ if (dm_digtable.cur_connect_state == DIG_CONNECT) {
+ if (dm_digtable.rssi_val <= dm_digtable.rssi_low_thresh)
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
- else if ((dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh))
+ else if (dm_digtable.rssi_val >= dm_digtable.rssi_high_thresh)
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_HIGHER;
else
dm_digtable.curcs_ratio_state = dm_digtable.precs_ratio_state;
- }
- else
- {
+ } else {
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
}
- }
- else // disconnected -> connected or connected -> disconnected
- {
+ } else /* disconnected -> connected or connected -> disconnected */
dm_digtable.curcs_ratio_state = DIG_CS_RATIO_LOWER;
- }
- // if silent reset happened, we should rewrite the values back
- if(priv->reset_count != reset_cnt)
- {
+ /* if silent reset happened, we should rewrite the values back */
+ if (priv->reset_count != reset_cnt) {
force_write = 1;
reset_cnt = priv->reset_count;
}
-
{
- if((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) ||
- !initialized || force_write)
- {
- //DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState);
- if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER)
- {
- // Lower CS ratio for CCK.
+ if ((dm_digtable.precs_ratio_state != dm_digtable.curcs_ratio_state) ||
+ !initialized || force_write) {
+ /*DbgPrint("Write CS_ratio state = %d\n", DM_DigTable.CurCS_ratioState);*/
+ if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_LOWER) {
+ /* Lower CS ratio for CCK. */
write_nic_byte(dev, 0xa0a, 0x08);
- }
- else if(dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER)
- {
- // Higher CS ratio for CCK.
+ } else if (dm_digtable.curcs_ratio_state == DIG_CS_RATIO_HIGHER) {
+ /* Higher CS ratio for CCK. */
write_nic_byte(dev, 0xa0a, 0xcd);
}
dm_digtable.precs_ratio_state = dm_digtable.curcs_ratio_state;
@@ -2411,53 +2208,46 @@ void dm_init_edca_turbo(struct net_device *dev)
priv->bcurrent_turbo_EDCA = false;
priv->ieee80211->bis_any_nonbepkts = false;
priv->bis_cur_rdlstate = false;
-} // dm_init_edca_turbo
+} /* dm_init_edca_turbo */
static void dm_check_edca_turbo(
struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
PRT_HIGH_THROUGHPUT pHTInfo = priv->ieee80211->pHTInfo;
- //PSTA_QOS pStaQos = pMgntInfo->pStaQos;
+ /*PSTA_QOS pStaQos = pMgntInfo->pStaQos;*/
- // Keep past Tx/Rx packet count for RT-to-RT EDCA turbo.
+ /* Keep past Tx/Rx packet count for RT-to-RT EDCA turbo. */
static unsigned long lastTxOkCnt;
static unsigned long lastRxOkCnt;
unsigned long curTxOkCnt = 0;
unsigned long curRxOkCnt = 0;
- //
- // Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
- // should follow the settings from QAP. By Bruce, 2007-12-07.
- //
- if(priv->ieee80211->state != IEEE80211_LINKED)
+ /*
+ * Do not be Turbo if it's under WiFi config and Qos Enabled, because the EDCA parameters
+ * should follow the settings from QAP. By Bruce, 2007-12-07.
+ */
+ if (priv->ieee80211->state != IEEE80211_LINKED)
goto dm_CheckEdcaTurbo_EXIT;
- // We do not turn on EDCA turbo mode for some AP that has IOT issue
- if(priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO)
+ /* We do not turn on EDCA turbo mode for some AP that has IOT issue */
+ if (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_DISABLE_EDCA_TURBO)
goto dm_CheckEdcaTurbo_EXIT;
-// printk("========>%s():bis_any_nonbepkts is %d\n",__func__,priv->bis_any_nonbepkts);
- // Check the status for current condition.
- if(!priv->ieee80211->bis_any_nonbepkts)
- {
+ /*printk("========>%s():bis_any_nonbepkts is %d\n", __func__, priv->bis_any_nonbepkts);*/
+ /* Check the status for current condition. */
+ if (!priv->ieee80211->bis_any_nonbepkts) {
curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
- // For RT-AP, we needs to turn it on when Rx>Tx
- if(curRxOkCnt > 4*curTxOkCnt)
- {
- //printk("%s():curRxOkCnt > 4*curTxOkCnt\n");
- if(!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
- {
+ /* For RT-AP, we needs to turn it on when Rx>Tx */
+ if (curRxOkCnt > 4*curTxOkCnt) {
+ /*printk("%s():curRxOkCnt > 4*curTxOkCnt\n");*/
+ if (!priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) {
write_nic_dword(dev, EDCAPARA_BE, edca_setting_DL[pHTInfo->IOTPeer]);
priv->bis_cur_rdlstate = true;
}
- }
- else
- {
-
- //printk("%s():curRxOkCnt < 4*curTxOkCnt\n");
- if(priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA)
- {
+ } else {
+ /*printk("%s():curRxOkCnt < 4*curTxOkCnt\n");*/
+ if (priv->bis_cur_rdlstate || !priv->bcurrent_turbo_EDCA) {
write_nic_dword(dev, EDCAPARA_BE, edca_setting_UL[pHTInfo->IOTPeer]);
priv->bis_cur_rdlstate = false;
}
@@ -2465,50 +2255,47 @@ static void dm_check_edca_turbo(
}
priv->bcurrent_turbo_EDCA = true;
- }
- else
- {
- //
- // Turn Off EDCA turbo here.
- // Restore original EDCA according to the declaration of AP.
- //
- if(priv->bcurrent_turbo_EDCA)
- {
-
+ } else {
+ /*
+ * Turn Off EDCA turbo here.
+ * Restore original EDCA according to the declaration of AP.
+ */
+ if (priv->bcurrent_turbo_EDCA) {
{
u8 u1bAIFS;
u32 u4bAcParam;
struct ieee80211_qos_parameters *qos_parameters = &priv->ieee80211->current_network.qos_data.parameters;
u8 mode = priv->ieee80211->mode;
- // For Each time updating EDCA parameter, reset EDCA turbo mode status.
+ /* For Each time updating EDCA parameter, reset EDCA turbo mode status. */
dm_init_edca_turbo(dev);
- u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ?9:20) + aSifsTime;
- u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0]))<< AC_PARAM_TXOP_LIMIT_OFFSET)|
- (((u32)(qos_parameters->cw_max[0]))<< AC_PARAM_ECW_MAX_OFFSET)|
- (((u32)(qos_parameters->cw_min[0]))<< AC_PARAM_ECW_MIN_OFFSET)|
+ u1bAIFS = qos_parameters->aifs[0] * ((mode&(IEEE_G|IEEE_N_24G)) ? 9 : 20) + aSifsTime;
+ u4bAcParam = ((((u32)(qos_parameters->tx_op_limit[0])) << AC_PARAM_TXOP_LIMIT_OFFSET)|
+ (((u32)(qos_parameters->cw_max[0])) << AC_PARAM_ECW_MAX_OFFSET)|
+ (((u32)(qos_parameters->cw_min[0])) << AC_PARAM_ECW_MIN_OFFSET)|
((u32)u1bAIFS << AC_PARAM_AIFS_OFFSET));
- //write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);
+ /*write_nic_dword(dev, WDCAPARA_ADD[i], u4bAcParam);*/
write_nic_dword(dev, EDCAPARA_BE, u4bAcParam);
- // Check ACM bit.
- // If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
+ /*
+ * Check ACM bit.
+ * If it is set, immediately set ACM control bit to downgrading AC for passing WMM testplan. Annie, 2005-12-13.
+ */
{
- // TODO: Modified this part and try to set acm control in only 1 IO processing!!
+ /* TODO: Modified this part and try to set acm control in only 1 IO processing!! */
PACI_AIFSN pAciAifsn = (PACI_AIFSN)&(qos_parameters->aifs[0]);
u8 AcmCtrl;
+
read_nic_byte(dev, AcmHwCtrl, &AcmCtrl);
- if(pAciAifsn->f.ACM)
- { // ACM bit is 1.
+
+ if (pAciAifsn->f.ACM) { /* ACM bit is 1. */
AcmCtrl |= AcmHw_BeqEn;
- }
- else
- { // ACM bit is 0.
+ } else { /* ACM bit is 0. */
AcmCtrl &= (~AcmHw_BeqEn);
}
- RT_TRACE(COMP_QOS,"SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl) ;
+ RT_TRACE(COMP_QOS, "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n", AcmCtrl);
write_nic_byte(dev, AcmHwCtrl, AcmCtrl);
}
}
@@ -2516,13 +2303,12 @@ static void dm_check_edca_turbo(
}
}
-
dm_CheckEdcaTurbo_EXIT:
- // Set variables for next time.
+ /* Set variables for next time. */
priv->ieee80211->bis_any_nonbepkts = false;
lastTxOkCnt = priv->stats.txbytesunicast;
lastRxOkCnt = priv->stats.rxbytesunicast;
-} // dm_CheckEdcaTurbo
+} /* dm_CheckEdcaTurbo */
static void dm_init_ctstoself(struct net_device *dev)
{
@@ -2541,8 +2327,7 @@ static void dm_ctstoself(struct net_device *dev)
unsigned long curTxOkCnt = 0;
unsigned long curRxOkCnt = 0;
- if(priv->ieee80211->bCTSToSelfEnable != TRUE)
- {
+ if (priv->ieee80211->bCTSToSelfEnable != TRUE) {
pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
return;
}
@@ -2552,17 +2337,13 @@ static void dm_ctstoself(struct net_device *dev)
3. <50 disable, >55 enable
*/
- if(pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM)
- {
+ if (pHTInfo->IOTPeer == HT_IOT_PEER_BROADCOM) {
curTxOkCnt = priv->stats.txbytesunicast - lastTxOkCnt;
curRxOkCnt = priv->stats.rxbytesunicast - lastRxOkCnt;
- if(curRxOkCnt > 4*curTxOkCnt) //downlink, disable CTS to self
- {
+ if (curRxOkCnt > 4*curTxOkCnt) { /* downlink, disable CTS to self */
pHTInfo->IOTAction &= ~HT_IOT_ACT_FORCED_CTS2SELF;
- //DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n");
- }
- else //uplink
- {
+ /*DbgPrint("dm_CTSToSelf() ==> CTS to self disabled -- downlink\n");*/
+ } else { /* uplink */
pHTInfo->IOTAction |= HT_IOT_ACT_FORCED_CTS2SELF;
}
@@ -2592,15 +2373,15 @@ static void dm_check_pbc_gpio(struct net_device *dev)
struct r8192_priv *priv = ieee80211_priv(dev);
u8 tmp1byte;
-
read_nic_byte(dev, GPI, &tmp1byte);
- if(tmp1byte == 0xff)
+ if (tmp1byte == 0xff)
return;
- if (tmp1byte&BIT6 || tmp1byte&BIT0)
- {
- // Here we only set bPbcPressed to TRUE
- // After trigger PBC, the variable will be set to FALSE
+ if (tmp1byte&BIT6 || tmp1byte&BIT0) {
+ /*
+ * Here we only set bPbcPressed to TRUE
+ * After trigger PBC, the variable will be set to FALSE
+ */
RT_TRACE(COMP_IO, "CheckPbcGPIO - PBC is pressed\n");
priv->bpbc_pressed = true;
}
@@ -2625,26 +2406,24 @@ static void dm_check_pbc_gpio(struct net_device *dev)
*---------------------------------------------------------------------------*/
void dm_rf_pathcheck_workitemcallback(struct work_struct *work)
{
- struct delayed_work *dwork = container_of(work,struct delayed_work,work);
- struct r8192_priv *priv = container_of(dwork,struct r8192_priv,rfpath_check_wq);
- struct net_device *dev =priv->ieee80211->dev;
- //bool bactually_set = false;
+ struct delayed_work *dwork = container_of(work, struct delayed_work, work);
+ struct r8192_priv *priv = container_of(dwork, struct r8192_priv, rfpath_check_wq);
+ struct net_device *dev = priv->ieee80211->dev;
+ /*bool bactually_set = false;*/
u8 rfpath = 0, i;
-
/* 2008/01/30 MH After discussing with SD3 Jerry, 0xc04/0xd04 register will
always be the same. We only read 0xc04 now. */
read_nic_byte(dev, 0xc04, &rfpath);
- // Check Bit 0-3, it means if RF A-D is enabled.
- for (i = 0; i < RF90_PATH_MAX; i++)
- {
+ /* Check Bit 0-3, it means if RF A-D is enabled. */
+ for (i = 0; i < RF90_PATH_MAX; i++) {
if (rfpath & (0x01<<i))
priv->brfpath_rxenable[i] = 1;
else
priv->brfpath_rxenable[i] = 0;
}
- if(!DM_RxPathSelTable.Enable)
+ if (!DM_RxPathSelTable.Enable)
return;
dm_rxpath_sel_byrssi(dev);
@@ -2654,17 +2433,17 @@ static void dm_init_rxpath_selection(struct net_device *dev)
{
u8 i;
struct r8192_priv *priv = ieee80211_priv(dev);
- DM_RxPathSelTable.Enable = 1; //default enabled
+
+ DM_RxPathSelTable.Enable = 1; /* default enabled */
DM_RxPathSelTable.SS_TH_low = RxPathSelection_SS_TH_low;
DM_RxPathSelTable.diff_TH = RxPathSelection_diff_TH;
- if(priv->CustomerID == RT_CID_819x_Netcore)
+ if (priv->CustomerID == RT_CID_819x_Netcore)
DM_RxPathSelTable.cck_method = CCK_Rx_Version_2;
else
DM_RxPathSelTable.cck_method = CCK_Rx_Version_1;
DM_RxPathSelTable.DbgMode = DM_DBG_OFF;
DM_RxPathSelTable.disabledRF = 0;
- for(i=0; i<4; i++)
- {
+ for (i = 0; i < 4; i++) {
DM_RxPathSelTable.rf_rssi[i] = 50;
DM_RxPathSelTable.cck_pwdb_sta[i] = -64;
DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
@@ -2674,22 +2453,21 @@ static void dm_init_rxpath_selection(struct net_device *dev)
static void dm_rxpath_sel_byrssi(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- u8 i, max_rssi_index=0, min_rssi_index=0, sec_rssi_index=0, rf_num=0;
- u8 tmp_max_rssi=0, tmp_min_rssi=0, tmp_sec_rssi=0;
- u8 cck_default_Rx=0x2; //RF-C
- u8 cck_optional_Rx=0x3;//RF-D
- long tmp_cck_max_pwdb=0, tmp_cck_min_pwdb=0, tmp_cck_sec_pwdb=0;
- u8 cck_rx_ver2_max_index=0, cck_rx_ver2_min_index=0, cck_rx_ver2_sec_index=0;
+ u8 i, max_rssi_index = 0, min_rssi_index = 0, sec_rssi_index = 0, rf_num = 0;
+ u8 tmp_max_rssi = 0, tmp_min_rssi = 0, tmp_sec_rssi = 0;
+ u8 cck_default_Rx = 0x2; /* RF-C */
+ u8 cck_optional_Rx = 0x3; /* RF-D */
+ long tmp_cck_max_pwdb = 0, tmp_cck_min_pwdb = 0, tmp_cck_sec_pwdb = 0;
+ u8 cck_rx_ver2_max_index = 0, cck_rx_ver2_min_index = 0, cck_rx_ver2_sec_index = 0;
u8 cur_rf_rssi;
long cur_cck_pwdb;
static u8 disabled_rf_cnt, cck_Rx_Path_initialized;
u8 update_cck_rx_path;
- if(priv->rf_type != RF_2T4R)
+ if (priv->rf_type != RF_2T4R)
return;
- if(!cck_Rx_Path_initialized)
- {
+ if (!cck_Rx_Path_initialized) {
read_nic_byte(dev, 0xa07, &DM_RxPathSelTable.cck_Rx_path);
DM_RxPathSelTable.cck_Rx_path &= 0xf;
cck_Rx_Path_initialized = 1;
@@ -2698,90 +2476,63 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev)
read_nic_byte(dev, 0xc04, &DM_RxPathSelTable.disabledRF);
DM_RxPathSelTable.disabledRF = ~DM_RxPathSelTable.disabledRF & 0xf;
- if(priv->ieee80211->mode == WIRELESS_MODE_B)
- {
- DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; //pure B mode, fixed cck version2
- //DbgPrint("Pure B mode, use cck rx version2 \n");
+ if (priv->ieee80211->mode == WIRELESS_MODE_B) {
+ DM_RxPathSelTable.cck_method = CCK_Rx_Version_2; /* pure B mode, fixed cck version2 */
+ /*DbgPrint("Pure B mode, use cck rx version2\n");*/
}
- //decide max/sec/min rssi index
- for (i=0; i<RF90_PATH_MAX; i++)
- {
- if(!DM_RxPathSelTable.DbgMode)
+ /* decide max/sec/min rssi index */
+ for (i = 0; i < RF90_PATH_MAX; i++) {
+ if (!DM_RxPathSelTable.DbgMode)
DM_RxPathSelTable.rf_rssi[i] = priv->stats.rx_rssi_percentage[i];
- if(priv->brfpath_rxenable[i])
- {
+ if (priv->brfpath_rxenable[i]) {
rf_num++;
cur_rf_rssi = DM_RxPathSelTable.rf_rssi[i];
- if(rf_num == 1) // find first enabled rf path and the rssi values
- { //initialize, set all rssi index to the same one
+ if (rf_num == 1) { /* find first enabled rf path and the rssi values */
+ /* initialize, set all rssi index to the same one */
max_rssi_index = min_rssi_index = sec_rssi_index = i;
tmp_max_rssi = tmp_min_rssi = tmp_sec_rssi = cur_rf_rssi;
- }
- else if(rf_num == 2)
- { // we pick up the max index first, and let sec and min to be the same one
- if(cur_rf_rssi >= tmp_max_rssi)
- {
+ } else if (rf_num == 2) { /* we pick up the max index first, and let sec and min to be the same one */
+ if (cur_rf_rssi >= tmp_max_rssi) {
tmp_max_rssi = cur_rf_rssi;
max_rssi_index = i;
- }
- else
- {
+ } else {
tmp_sec_rssi = tmp_min_rssi = cur_rf_rssi;
sec_rssi_index = min_rssi_index = i;
}
- }
- else
- {
- if(cur_rf_rssi > tmp_max_rssi)
- {
+ } else {
+ if (cur_rf_rssi > tmp_max_rssi) {
tmp_sec_rssi = tmp_max_rssi;
sec_rssi_index = max_rssi_index;
tmp_max_rssi = cur_rf_rssi;
max_rssi_index = i;
- }
- else if(cur_rf_rssi == tmp_max_rssi)
- { // let sec and min point to the different index
+ } else if (cur_rf_rssi == tmp_max_rssi) { /* let sec and min point to the different index */
tmp_sec_rssi = cur_rf_rssi;
sec_rssi_index = i;
- }
- else if((cur_rf_rssi < tmp_max_rssi) &&(cur_rf_rssi > tmp_sec_rssi))
- {
+ } else if ((cur_rf_rssi < tmp_max_rssi) && (cur_rf_rssi > tmp_sec_rssi)) {
tmp_sec_rssi = cur_rf_rssi;
sec_rssi_index = i;
- }
- else if(cur_rf_rssi == tmp_sec_rssi)
- {
- if(tmp_sec_rssi == tmp_min_rssi)
- { // let sec and min point to the different index
+ } else if (cur_rf_rssi == tmp_sec_rssi) {
+ if (tmp_sec_rssi == tmp_min_rssi) {
+ /* let sec and min point to the different index */
tmp_sec_rssi = cur_rf_rssi;
sec_rssi_index = i;
+ } else {
+ /* This case we don't need to set any index */
}
- else
- {
- // This case we don't need to set any index
- }
- }
- else if((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi))
- {
- // This case we don't need to set any index
- }
- else if(cur_rf_rssi == tmp_min_rssi)
- {
- if(tmp_sec_rssi == tmp_min_rssi)
- { // let sec and min point to the different index
+ } else if ((cur_rf_rssi < tmp_sec_rssi) && (cur_rf_rssi > tmp_min_rssi)) {
+ /* This case we don't need to set any index */
+ } else if (cur_rf_rssi == tmp_min_rssi) {
+ if (tmp_sec_rssi == tmp_min_rssi) {
+ /* let sec and min point to the different index */
tmp_min_rssi = cur_rf_rssi;
min_rssi_index = i;
+ } else {
+ /* This case we don't need to set any index */
}
- else
- {
- // This case we don't need to set any index
- }
- }
- else if(cur_rf_rssi < tmp_min_rssi)
- {
+ } else if (cur_rf_rssi < tmp_min_rssi) {
tmp_min_rssi = cur_rf_rssi;
min_rssi_index = i;
}
@@ -2790,83 +2541,51 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev)
}
rf_num = 0;
- // decide max/sec/min cck pwdb index
- if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2)
- {
- for (i=0; i<RF90_PATH_MAX; i++)
- {
- if(priv->brfpath_rxenable[i])
- {
+ /* decide max/sec/min cck pwdb index */
+ if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) {
+ for (i = 0; i < RF90_PATH_MAX; i++) {
+ if (priv->brfpath_rxenable[i]) {
rf_num++;
cur_cck_pwdb = DM_RxPathSelTable.cck_pwdb_sta[i];
- if(rf_num == 1) // find first enabled rf path and the rssi values
- { //initialize, set all rssi index to the same one
+ if (rf_num == 1) { /* find first enabled rf path and the rssi values */
+ /* initialize, set all rssi index to the same one */
cck_rx_ver2_max_index = cck_rx_ver2_min_index = cck_rx_ver2_sec_index = i;
tmp_cck_max_pwdb = tmp_cck_min_pwdb = tmp_cck_sec_pwdb = cur_cck_pwdb;
- }
- else if(rf_num == 2)
- { // we pick up the max index first, and let sec and min to be the same one
- if(cur_cck_pwdb >= tmp_cck_max_pwdb)
- {
+ } else if (rf_num == 2) { /* we pick up the max index first, and let sec and min to be the same one */
+ if (cur_cck_pwdb >= tmp_cck_max_pwdb) {
tmp_cck_max_pwdb = cur_cck_pwdb;
cck_rx_ver2_max_index = i;
- }
- else
- {
+ } else {
tmp_cck_sec_pwdb = tmp_cck_min_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = cck_rx_ver2_min_index = i;
}
- }
- else
- {
- if(cur_cck_pwdb > tmp_cck_max_pwdb)
- {
+ } else {
+ if (cur_cck_pwdb > tmp_cck_max_pwdb) {
tmp_cck_sec_pwdb = tmp_cck_max_pwdb;
cck_rx_ver2_sec_index = cck_rx_ver2_max_index;
tmp_cck_max_pwdb = cur_cck_pwdb;
cck_rx_ver2_max_index = i;
- }
- else if(cur_cck_pwdb == tmp_cck_max_pwdb)
- { // let sec and min point to the different index
+ } else if (cur_cck_pwdb == tmp_cck_max_pwdb) {
+ /* let sec and min point to the different index */
tmp_cck_sec_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = i;
- }
- else if((cur_cck_pwdb < tmp_cck_max_pwdb) &&(cur_cck_pwdb > tmp_cck_sec_pwdb))
- {
+ } else if ((cur_cck_pwdb < tmp_cck_max_pwdb) && (cur_cck_pwdb > tmp_cck_sec_pwdb)) {
tmp_cck_sec_pwdb = cur_cck_pwdb;
cck_rx_ver2_sec_index = i;
- }
- else if(cur_cck_pwdb == tmp_cck_sec_pwdb)
- {
- if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
- { // let sec and min point to the different index
- tmp_cck_sec_pwdb = cur_cck_pwdb;
- cck_rx_ver2_sec_index = i;
- }
- else
- {
- // This case we don't need to set any index
- }
- }
- else if((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb))
- {
- // This case we don't need to set any index
- }
- else if(cur_cck_pwdb == tmp_cck_min_pwdb)
- {
- if(tmp_cck_sec_pwdb == tmp_cck_min_pwdb)
- { // let sec and min point to the different index
- tmp_cck_min_pwdb = cur_cck_pwdb;
- cck_rx_ver2_min_index = i;
- }
- else
- {
- // This case we don't need to set any index
- }
- }
- else if(cur_cck_pwdb < tmp_cck_min_pwdb)
- {
+ } else if (cur_cck_pwdb == tmp_cck_sec_pwdb && tmp_cck_sec_pwdb == tmp_cck_min_pwdb) {
+ /* let sec and min point to the different index */
+ tmp_cck_sec_pwdb = cur_cck_pwdb;
+ cck_rx_ver2_sec_index = i;
+ /* otherwise we don't need to set any index */
+ } else if ((cur_cck_pwdb < tmp_cck_sec_pwdb) && (cur_cck_pwdb > tmp_cck_min_pwdb)) {
+ /* This case we don't need to set any index */
+ } else if (cur_cck_pwdb == tmp_cck_min_pwdb && tmp_cck_sec_pwdb == tmp_cck_min_pwdb) {
+ /* let sec and min point to the different index */
+ tmp_cck_min_pwdb = cur_cck_pwdb;
+ cck_rx_ver2_min_index = i;
+ /* otherwise we don't need to set any index */
+ } else if (cur_cck_pwdb < tmp_cck_min_pwdb) {
tmp_cck_min_pwdb = cur_cck_pwdb;
cck_rx_ver2_min_index = i;
}
@@ -2876,56 +2595,48 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev)
}
}
-
- // Set CCK Rx path
- // reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
+ /*
+ * Set CCK Rx path
+ * reg0xA07[3:2]=cck default rx path, reg0xa07[1:0]=cck optional rx path.
+ */
update_cck_rx_path = 0;
- if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_2)
- {
+ if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_2) {
cck_default_Rx = cck_rx_ver2_max_index;
cck_optional_Rx = cck_rx_ver2_sec_index;
- if(tmp_cck_max_pwdb != -64)
+ if (tmp_cck_max_pwdb != -64)
update_cck_rx_path = 1;
}
- if(tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2)
- {
- if((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH)
- {
- //record the enabled rssi threshold
+ if (tmp_min_rssi < DM_RxPathSelTable.SS_TH_low && disabled_rf_cnt < 2) {
+ if ((tmp_max_rssi - tmp_min_rssi) >= DM_RxPathSelTable.diff_TH) {
+ /* record the enabled rssi threshold */
DM_RxPathSelTable.rf_enable_rssi_th[min_rssi_index] = tmp_max_rssi+5;
- //disable the BB Rx path, OFDM
- rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<min_rssi_index, 0x0); // 0xc04[3:0]
- rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<min_rssi_index, 0x0); // 0xd04[3:0]
+ /* disable the BB Rx path, OFDM */
+ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<min_rssi_index, 0x0); /* 0xc04[3:0] */
+ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<min_rssi_index, 0x0); /* 0xd04[3:0] */
disabled_rf_cnt++;
}
- if(DM_RxPathSelTable.cck_method == CCK_Rx_Version_1)
- {
+ if (DM_RxPathSelTable.cck_method == CCK_Rx_Version_1) {
cck_default_Rx = max_rssi_index;
cck_optional_Rx = sec_rssi_index;
- if(tmp_max_rssi)
+ if (tmp_max_rssi)
update_cck_rx_path = 1;
}
}
- if(update_cck_rx_path)
- {
+ if (update_cck_rx_path) {
DM_RxPathSelTable.cck_Rx_path = (cck_default_Rx<<2)|(cck_optional_Rx);
rtl8192_setBBreg(dev, rCCK0_AFESetting, 0x0f000000, DM_RxPathSelTable.cck_Rx_path);
}
- if(DM_RxPathSelTable.disabledRF)
- {
- for(i=0; i<4; i++)
- {
- if((DM_RxPathSelTable.disabledRF>>i) & 0x1) //disabled rf
- {
- if(tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i])
- {
- //enable the BB Rx path
- //DbgPrint("RF-%d is enabled. \n", 0x1<<i);
- rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<i, 0x1); // 0xc04[3:0]
- rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<i, 0x1); // 0xd04[3:0]
+ if (DM_RxPathSelTable.disabledRF) {
+ for (i = 0; i < 4; i++) {
+ if ((DM_RxPathSelTable.disabledRF>>i) & 0x1) { /* disabled rf */
+ if (tmp_max_rssi >= DM_RxPathSelTable.rf_enable_rssi_th[i]) {
+ /* enable the BB Rx path */
+ /*DbgPrint("RF-%d is enabled.\n", 0x1<<i);*/
+ rtl8192_setBBreg(dev, rOFDM0_TRxPathEnable, 0x1<<i, 0x1); /* 0xc04[3:0] */
+ rtl8192_setBBreg(dev, rOFDM1_TRxPathEnable, 0x1<<i, 0x1); /* 0xd04[3:0] */
DM_RxPathSelTable.rf_enable_rssi_th[i] = 100;
disabled_rf_cnt--;
}
@@ -2950,14 +2661,14 @@ static void dm_rxpath_sel_byrssi(struct net_device *dev)
* 05/28/2008 amy Create Version 0 porting from windows code.
*
*---------------------------------------------------------------------------*/
-static void dm_check_rx_path_selection(struct net_device *dev)
+static void dm_check_rx_path_selection(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- queue_delayed_work(priv->priv_wq,&priv->rfpath_check_wq,0);
-} /* dm_CheckRxRFPath */
+ queue_delayed_work(priv->priv_wq, &priv->rfpath_check_wq, 0);
+} /* dm_CheckRxRFPath */
-static void dm_init_fsync (struct net_device *dev)
+static void dm_init_fsync(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
@@ -2966,20 +2677,20 @@ static void dm_init_fsync (struct net_device *dev)
priv->ieee80211->fsync_rssi_threshold = 30;
priv->ieee80211->bfsync_enable = false;
priv->ieee80211->fsync_multiple_timeinterval = 3;
- priv->ieee80211->fsync_firstdiff_ratethreshold= 100;
- priv->ieee80211->fsync_seconddiff_ratethreshold= 200;
+ priv->ieee80211->fsync_firstdiff_ratethreshold = 100;
+ priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
priv->ieee80211->fsync_state = Default_Fsync;
- priv->framesyncMonitor = 1; // current default 0xc38 monitor on
+ priv->framesyncMonitor = 1; /* current default 0xc38 monitor on */
init_timer(&priv->fsync_timer);
priv->fsync_timer.data = (unsigned long)dev;
priv->fsync_timer.function = dm_fsync_timer_callback;
}
-
static void dm_deInit_fsync(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
+
del_timer_sync(&priv->fsync_timer);
}
@@ -2987,102 +2698,84 @@ void dm_fsync_timer_callback(unsigned long data)
{
struct net_device *dev = (struct net_device *)data;
struct r8192_priv *priv = ieee80211_priv((struct net_device *)data);
- u32 rate_index, rate_count = 0, rate_count_diff=0;
+ u32 rate_index, rate_count = 0, rate_count_diff = 0;
bool bSwitchFromCountDiff = false;
bool bDoubleTimeInterval = false;
- if(priv->ieee80211->state == IEEE80211_LINKED &&
+ if (priv->ieee80211->state == IEEE80211_LINKED &&
priv->ieee80211->bfsync_enable &&
- (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC))
- {
- // Count rate 54, MCS [7], [12, 13, 14, 15]
+ (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) {
+ /* Count rate 54, MCS [7], [12, 13, 14, 15] */
u32 rate_bitmap;
- for(rate_index = 0; rate_index <= 27; rate_index++)
- {
+
+ for (rate_index = 0; rate_index <= 27; rate_index++) {
rate_bitmap = 1 << rate_index;
- if(priv->ieee80211->fsync_rate_bitmap & rate_bitmap)
- rate_count+= priv->stats.received_rate_histogram[1][rate_index];
+ if (priv->ieee80211->fsync_rate_bitmap & rate_bitmap)
+ rate_count += priv->stats.received_rate_histogram[1][rate_index];
}
- if(rate_count < priv->rate_record)
+ if (rate_count < priv->rate_record)
rate_count_diff = 0xffffffff - rate_count + priv->rate_record;
else
rate_count_diff = rate_count - priv->rate_record;
- if(rate_count_diff < priv->rateCountDiffRecord)
- {
-
+ if (rate_count_diff < priv->rateCountDiffRecord) {
u32 DiffNum = priv->rateCountDiffRecord - rate_count_diff;
- // Continue count
- if(DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
+ /* Continue count */
+ if (DiffNum >= priv->ieee80211->fsync_seconddiff_ratethreshold)
priv->ContinueDiffCount++;
else
priv->ContinueDiffCount = 0;
- // Continue count over
- if(priv->ContinueDiffCount >=2)
- {
+ /* Continue count over */
+ if (priv->ContinueDiffCount >= 2) {
bSwitchFromCountDiff = true;
priv->ContinueDiffCount = 0;
}
- }
- else
- {
- // Stop the continued count
+ } else {
+ /* Stop the continued count */
priv->ContinueDiffCount = 0;
}
- //If Count diff <= FsyncRateCountThreshold
- if(rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold)
- {
+ /* If Count diff <= FsyncRateCountThreshold */
+ if (rate_count_diff <= priv->ieee80211->fsync_firstdiff_ratethreshold) {
bSwitchFromCountDiff = true;
priv->ContinueDiffCount = 0;
}
priv->rate_record = rate_count;
priv->rateCountDiffRecord = rate_count_diff;
- RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
- // if we never receive those mcs rate and rssi > 30 % then switch fsyn
- if(priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff)
- {
+ RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff, priv->bswitch_fsync);
+ /* if we never receive those mcs rate and rssi > 30 % then switch fsyn */
+ if (priv->undecorated_smoothed_pwdb > priv->ieee80211->fsync_rssi_threshold && bSwitchFromCountDiff) {
bDoubleTimeInterval = true;
priv->bswitch_fsync = !priv->bswitch_fsync;
- if(priv->bswitch_fsync)
- {
+ if (priv->bswitch_fsync) {
write_nic_byte(dev, 0xC36, 0x1c);
write_nic_byte(dev, 0xC3e, 0x90);
- }
- else
- {
+ } else {
write_nic_byte(dev, 0xC36, 0x5c);
write_nic_byte(dev, 0xC3e, 0x96);
}
- }
- else if(priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold)
- {
- if(priv->bswitch_fsync)
- {
+ } else if (priv->undecorated_smoothed_pwdb <= priv->ieee80211->fsync_rssi_threshold) {
+ if (priv->bswitch_fsync) {
priv->bswitch_fsync = false;
write_nic_byte(dev, 0xC36, 0x5c);
write_nic_byte(dev, 0xC3e, 0x96);
}
}
- if(bDoubleTimeInterval){
- if(timer_pending(&priv->fsync_timer))
+ if (bDoubleTimeInterval) {
+ if (timer_pending(&priv->fsync_timer))
del_timer_sync(&priv->fsync_timer);
priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval*priv->ieee80211->fsync_multiple_timeinterval);
add_timer(&priv->fsync_timer);
- }
- else{
- if(timer_pending(&priv->fsync_timer))
+ } else {
+ if (timer_pending(&priv->fsync_timer))
del_timer_sync(&priv->fsync_timer);
priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval);
add_timer(&priv->fsync_timer);
}
- }
- else
- {
- // Let Register return to default value;
- if(priv->bswitch_fsync)
- {
+ } else {
+ /* Let Register return to default value; */
+ if (priv->bswitch_fsync) {
priv->bswitch_fsync = false;
write_nic_byte(dev, 0xC36, 0x5c);
write_nic_byte(dev, 0xC3e, 0x96);
@@ -3091,7 +2784,7 @@ void dm_fsync_timer_callback(unsigned long data)
write_nic_dword(dev, rOFDM0_RxDetector2, 0x465c52cd);
}
RT_TRACE(COMP_HALDM, "ContinueDiffCount %d\n", priv->ContinueDiffCount);
- RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff , priv->bswitch_fsync);
+ RT_TRACE(COMP_HALDM, "rateRecord %d rateCount %d, rateCountdiff %d bSwitchFsync %d\n", priv->rate_record, rate_count, rate_count_diff, priv->bswitch_fsync);
}
static void dm_StartHWFsync(struct net_device *dev)
@@ -3108,9 +2801,8 @@ static void dm_EndSWFsync(struct net_device *dev)
RT_TRACE(COMP_HALDM, "%s\n", __func__);
del_timer_sync(&(priv->fsync_timer));
- // Let Register return to default value;
- if(priv->bswitch_fsync)
- {
+ /* Let Register return to default value; */
+ if (priv->bswitch_fsync) {
priv->bswitch_fsync = false;
write_nic_byte(dev, 0xC36, 0x5c);
@@ -3130,30 +2822,26 @@ static void dm_StartSWFsync(struct net_device *dev)
u32 rateBitmap;
RT_TRACE(COMP_HALDM, "%s\n", __func__);
- // Initial rate record to zero, start to record.
+ /* Initial rate record to zero, start to record. */
priv->rate_record = 0;
- // Initialize continue diff count to zero, start to record.
+ /* Initialize continue diff count to zero, start to record. */
priv->ContinueDiffCount = 0;
priv->rateCountDiffRecord = 0;
priv->bswitch_fsync = false;
- if(priv->ieee80211->mode == WIRELESS_MODE_N_24G)
- {
- priv->ieee80211->fsync_firstdiff_ratethreshold= 600;
+ if (priv->ieee80211->mode == WIRELESS_MODE_N_24G) {
+ priv->ieee80211->fsync_firstdiff_ratethreshold = 600;
priv->ieee80211->fsync_seconddiff_ratethreshold = 0xffff;
- }
- else
- {
- priv->ieee80211->fsync_firstdiff_ratethreshold= 200;
+ } else {
+ priv->ieee80211->fsync_firstdiff_ratethreshold = 200;
priv->ieee80211->fsync_seconddiff_ratethreshold = 200;
}
- for(rateIndex = 0; rateIndex <= 27; rateIndex++)
- {
- rateBitmap = 1 << rateIndex;
- if(priv->ieee80211->fsync_rate_bitmap & rateBitmap)
+ for (rateIndex = 0; rateIndex <= 27; rateIndex++) {
+ rateBitmap = 1 << rateIndex;
+ if (priv->ieee80211->fsync_rate_bitmap & rateBitmap)
priv->rate_record += priv->stats.received_rate_histogram[1][rateIndex];
}
- if(timer_pending(&priv->fsync_timer))
+ if (timer_pending(&priv->fsync_timer))
del_timer_sync(&priv->fsync_timer);
priv->fsync_timer.expires = jiffies + MSECS(priv->ieee80211->fsync_time_interval);
add_timer(&priv->fsync_timer);
@@ -3173,139 +2861,112 @@ static void dm_EndHWFsync(struct net_device *dev)
void dm_check_fsync(struct net_device *dev)
{
#define RegC38_Default 0
-#define RegC38_NonFsync_Other_AP 1
-#define RegC38_Fsync_AP_BCM 2
+#define RegC38_NonFsync_Other_AP 1
+#define RegC38_Fsync_AP_BCM 2
struct r8192_priv *priv = ieee80211_priv(dev);
- //u32 framesyncC34;
- static u8 reg_c38_State=RegC38_Default;
+ /*u32 framesyncC34;*/
+ static u8 reg_c38_State = RegC38_Default;
static u32 reset_cnt;
RT_TRACE(COMP_HALDM, "RSSI %d TimeInterval %d MultipleTimeInterval %d\n", priv->ieee80211->fsync_rssi_threshold, priv->ieee80211->fsync_time_interval, priv->ieee80211->fsync_multiple_timeinterval);
RT_TRACE(COMP_HALDM, "RateBitmap 0x%x FirstDiffRateThreshold %d SecondDiffRateThreshold %d\n", priv->ieee80211->fsync_rate_bitmap, priv->ieee80211->fsync_firstdiff_ratethreshold, priv->ieee80211->fsync_seconddiff_ratethreshold);
- if(priv->ieee80211->state == IEEE80211_LINKED &&
- (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC))
- {
- if(priv->ieee80211->bfsync_enable == 0)
- {
- switch (priv->ieee80211->fsync_state)
- {
- case Default_Fsync:
- dm_StartHWFsync(dev);
- priv->ieee80211->fsync_state = HW_Fsync;
- break;
- case SW_Fsync:
- dm_EndSWFsync(dev);
- dm_StartHWFsync(dev);
- priv->ieee80211->fsync_state = HW_Fsync;
- break;
- case HW_Fsync:
- default:
- break;
+ if (priv->ieee80211->state == IEEE80211_LINKED &&
+ (priv->ieee80211->pHTInfo->IOTAction & HT_IOT_ACT_CDD_FSYNC)) {
+ if (priv->ieee80211->bfsync_enable == 0) {
+ switch (priv->ieee80211->fsync_state) {
+ case Default_Fsync:
+ dm_StartHWFsync(dev);
+ priv->ieee80211->fsync_state = HW_Fsync;
+ break;
+ case SW_Fsync:
+ dm_EndSWFsync(dev);
+ dm_StartHWFsync(dev);
+ priv->ieee80211->fsync_state = HW_Fsync;
+ break;
+ case HW_Fsync:
+ default:
+ break;
}
- }
- else
- {
- switch (priv->ieee80211->fsync_state)
- {
- case Default_Fsync:
- dm_StartSWFsync(dev);
- priv->ieee80211->fsync_state = SW_Fsync;
- break;
- case HW_Fsync:
- dm_EndHWFsync(dev);
- dm_StartSWFsync(dev);
- priv->ieee80211->fsync_state = SW_Fsync;
- break;
- case SW_Fsync:
- default:
- break;
-
+ } else {
+ switch (priv->ieee80211->fsync_state) {
+ case Default_Fsync:
+ dm_StartSWFsync(dev);
+ priv->ieee80211->fsync_state = SW_Fsync;
+ break;
+ case HW_Fsync:
+ dm_EndHWFsync(dev);
+ dm_StartSWFsync(dev);
+ priv->ieee80211->fsync_state = SW_Fsync;
+ break;
+ case SW_Fsync:
+ default:
+ break;
}
}
- if(priv->framesyncMonitor)
- {
- if(reg_c38_State != RegC38_Fsync_AP_BCM)
- { //For broadcom AP we write different default value
+ if (priv->framesyncMonitor) {
+ if (reg_c38_State != RegC38_Fsync_AP_BCM) {
+ /* For broadcom AP we write different default value */
write_nic_byte(dev, rOFDM0_RxDetector3, 0x95);
reg_c38_State = RegC38_Fsync_AP_BCM;
}
}
- }
- else
- {
- switch (priv->ieee80211->fsync_state)
- {
- case HW_Fsync:
- dm_EndHWFsync(dev);
- priv->ieee80211->fsync_state = Default_Fsync;
- break;
- case SW_Fsync:
- dm_EndSWFsync(dev);
- priv->ieee80211->fsync_state = Default_Fsync;
- break;
- case Default_Fsync:
- default:
- break;
+ } else {
+ switch (priv->ieee80211->fsync_state) {
+ case HW_Fsync:
+ dm_EndHWFsync(dev);
+ priv->ieee80211->fsync_state = Default_Fsync;
+ break;
+ case SW_Fsync:
+ dm_EndSWFsync(dev);
+ priv->ieee80211->fsync_state = Default_Fsync;
+ break;
+ case Default_Fsync:
+ default:
+ break;
}
- if(priv->framesyncMonitor)
- {
- if(priv->ieee80211->state == IEEE80211_LINKED)
- {
- if(priv->undecorated_smoothed_pwdb <= RegC38_TH)
- {
- if(reg_c38_State != RegC38_NonFsync_Other_AP)
- {
+ if (priv->framesyncMonitor) {
+ if (priv->ieee80211->state == IEEE80211_LINKED) {
+ if (priv->undecorated_smoothed_pwdb <= RegC38_TH) {
+ if (reg_c38_State != RegC38_NonFsync_Other_AP) {
write_nic_byte(dev, rOFDM0_RxDetector3, 0x90);
reg_c38_State = RegC38_NonFsync_Other_AP;
}
- }
- else if(priv->undecorated_smoothed_pwdb >= (RegC38_TH+5))
- {
- if(reg_c38_State)
- {
+ } else if (priv->undecorated_smoothed_pwdb >= (RegC38_TH+5)) {
+ if (reg_c38_State) {
write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
- //DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x \n", pHalData->framesync);
+ /*DbgPrint("Fsync is idle, rssi>=40, write 0xc38 = 0x%x\n", pHalData->framesync);*/
}
}
- }
- else
- {
- if(reg_c38_State)
- {
+ } else {
+ if (reg_c38_State) {
write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
- //DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x \n", pHalData->framesync);
+ /*DbgPrint("Fsync is idle, not connected, write 0xc38 = 0x%x\n", pHalData->framesync);*/
}
}
}
}
- if(priv->framesyncMonitor)
- {
- if(priv->reset_count != reset_cnt)
- { //After silent reset, the reg_c38_State will be returned to default value
+ if (priv->framesyncMonitor) {
+ if (priv->reset_count != reset_cnt) { /* After silent reset, the reg_c38_State will be returned to default value */
write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
reset_cnt = priv->reset_count;
- //DbgPrint("reg_c38_State = 0 for silent reset. \n");
+ /*DbgPrint("reg_c38_State = 0 for silent reset.\n");*/
}
- }
- else
- {
- if(reg_c38_State)
- {
+ } else {
+ if (reg_c38_State) {
write_nic_byte(dev, rOFDM0_RxDetector3, priv->framesync);
reg_c38_State = RegC38_Default;
- //DbgPrint("framesync no monitor, write 0xc38 = 0x%x \n", pHalData->framesync);
+ /*DbgPrint("framesync no monitor, write 0xc38 = 0x%x\n", pHalData->framesync);*/
}
}
}
-
/*-----------------------------------------------------------------------------
* Function: dm_shadow_init()
*
@@ -3328,10 +2989,9 @@ void dm_shadow_init(struct net_device *dev)
u16 offset;
for (page = 0; page < 5; page++)
- for (offset = 0; offset < 256; offset++)
- {
+ for (offset = 0; offset < 256; offset++) {
read_nic_byte(dev, offset+page*256, &dm_shadow[page][offset]);
- //DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]);
+ /*DbgPrint("P-%d/O-%02x=%02x\r\n", page, offset, DM_Shadow[page][offset]);*/
}
for (page = 8; page < 11; page++)
@@ -3366,8 +3026,8 @@ static void dm_init_dynamic_txpower(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- //Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code.
- priv->ieee80211->bdynamic_txpower_enable = true; //Default to enable Tx Power Control
+ /* Initial TX Power Control for near/far range , add by amy 2008/05/15, porting from windows code. */
+ priv->ieee80211->bdynamic_txpower_enable = true; /* Default to enable Tx Power Control */
priv->bLastDTPFlag_High = false;
priv->bLastDTPFlag_Low = false;
priv->bDynamicTxHighPower = false;
@@ -3377,91 +3037,77 @@ static void dm_init_dynamic_txpower(struct net_device *dev)
static void dm_dynamic_txpower(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- unsigned int txhipower_threshhold=0;
- unsigned int txlowpower_threshold=0;
- if(priv->ieee80211->bdynamic_txpower_enable != true)
- {
+ unsigned int txhipower_threshhold = 0;
+ unsigned int txlowpower_threshold = 0;
+
+ if (priv->ieee80211->bdynamic_txpower_enable != true) {
priv->bDynamicTxHighPower = false;
priv->bDynamicTxLowPower = false;
return;
}
- //printk("priv->ieee80211->current_network.unknown_cap_exist is %d ,priv->ieee80211->current_network.broadcom_cap_exist is %d\n",priv->ieee80211->current_network.unknown_cap_exist,priv->ieee80211->current_network.broadcom_cap_exist);
- if((priv->ieee80211->current_network.atheros_cap_exist) && (priv->ieee80211->mode == IEEE_G)){
+ /*printk("priv->ieee80211->current_network.unknown_cap_exist is %d , priv->ieee80211->current_network.broadcom_cap_exist is %d\n", priv->ieee80211->current_network.unknown_cap_exist, priv->ieee80211->current_network.broadcom_cap_exist);*/
+ if ((priv->ieee80211->current_network.atheros_cap_exist) && (priv->ieee80211->mode == IEEE_G)) {
txhipower_threshhold = TX_POWER_ATHEROAP_THRESH_HIGH;
txlowpower_threshold = TX_POWER_ATHEROAP_THRESH_LOW;
- }
- else
- {
+ } else {
txhipower_threshhold = TX_POWER_NEAR_FIELD_THRESH_HIGH;
txlowpower_threshold = TX_POWER_NEAR_FIELD_THRESH_LOW;
}
-// printk("=======>%s(): txhipower_threshhold is %d,txlowpower_threshold is %d\n",__func__,txhipower_threshhold,txlowpower_threshold);
- RT_TRACE(COMP_TXAGC,"priv->undecorated_smoothed_pwdb = %ld \n" , priv->undecorated_smoothed_pwdb);
+ /*printk("=======>%s(): txhipower_threshhold is %d, txlowpower_threshold is %d\n", __func__, txhipower_threshhold, txlowpower_threshold);*/
+ RT_TRACE(COMP_TXAGC, "priv->undecorated_smoothed_pwdb = %ld\n", priv->undecorated_smoothed_pwdb);
- if(priv->ieee80211->state == IEEE80211_LINKED)
- {
- if(priv->undecorated_smoothed_pwdb >= txhipower_threshhold)
- {
+ if (priv->ieee80211->state == IEEE80211_LINKED) {
+ if (priv->undecorated_smoothed_pwdb >= txhipower_threshhold) {
priv->bDynamicTxHighPower = true;
priv->bDynamicTxLowPower = false;
- }
- else
- {
- // high power state check
- if(priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true)
- {
+ } else {
+ /* high power state check */
+ if (priv->undecorated_smoothed_pwdb < txlowpower_threshold && priv->bDynamicTxHighPower == true)
priv->bDynamicTxHighPower = false;
- }
- // low power state check
- if(priv->undecorated_smoothed_pwdb < 35)
- {
+
+ /* low power state check */
+ if (priv->undecorated_smoothed_pwdb < 35)
priv->bDynamicTxLowPower = true;
- }
- else if(priv->undecorated_smoothed_pwdb >= 40)
- {
+ else if (priv->undecorated_smoothed_pwdb >= 40)
priv->bDynamicTxLowPower = false;
- }
}
- }
- else
- {
- //pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange;
+ } else {
+ /*pHalData->bTXPowerCtrlforNearFarRange = !pHalData->bTXPowerCtrlforNearFarRange;*/
priv->bDynamicTxHighPower = false;
priv->bDynamicTxLowPower = false;
}
- if((priv->bDynamicTxHighPower != priv->bLastDTPFlag_High) ||
- (priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low))
- {
- RT_TRACE(COMP_TXAGC,"SetTxPowerLevel8190() channel = %d \n" , priv->ieee80211->current_network.channel);
+ if ((priv->bDynamicTxHighPower != priv->bLastDTPFlag_High) ||
+ (priv->bDynamicTxLowPower != priv->bLastDTPFlag_Low)) {
+ RT_TRACE(COMP_TXAGC, "SetTxPowerLevel8190() channel = %d\n", priv->ieee80211->current_network.channel);
#if defined(RTL8190P) || defined(RTL8192E)
- SetTxPowerLevel8190(Adapter,pHalData->CurrentChannel);
+ SetTxPowerLevel8190(Adapter, pHalData->CurrentChannel);
#endif
- rtl8192_phy_setTxPower(dev,priv->ieee80211->current_network.channel);
- //pHalData->bStartTxCtrlByTPCNFR = FALSE; //Clear th flag of Set TX Power from Sitesurvey
+ rtl8192_phy_setTxPower(dev, priv->ieee80211->current_network.channel);
+ /*pHalData->bStartTxCtrlByTPCNFR = FALSE; Clear th flag of Set TX Power from Sitesurvey*/
}
priv->bLastDTPFlag_High = priv->bDynamicTxHighPower;
priv->bLastDTPFlag_Low = priv->bDynamicTxLowPower;
} /* dm_dynamic_txpower */
-//added by vivi, for read tx rate and retrycount
+/* added by vivi, for read tx rate and retrycount */
static void dm_check_txrateandretrycount(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
struct ieee80211_device *ieee = priv->ieee80211;
- //for 11n tx rate
-// priv->stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg);
+ /* for 11n tx rate */
+ /*priv->stats.CurrentShowTxate = read_nic_byte(dev, Current_Tx_Rate_Reg);*/
read_nic_byte(dev, Current_Tx_Rate_Reg, &ieee->softmac_stats.CurrentShowTxate);
- //printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate);
- //for initial tx rate
-// priv->stats.last_packet_rate = read_nic_byte(dev, Initial_Tx_Rate_Reg);
+ /*printk("=============>tx_rate_reg:%x\n", ieee->softmac_stats.CurrentShowTxate);*/
+ /* for initial tx rate */
+ /*priv->stats.last_packet_rate = read_nic_byte(dev, Initial_Tx_Rate_Reg);*/
read_nic_byte(dev, Initial_Tx_Rate_Reg, &ieee->softmac_stats.last_packet_rate);
- //for tx tx retry count
-// priv->stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg);
+ /* for tx tx retry count */
+ /*priv->stats.txretrycount = read_nic_dword(dev, Tx_Retry_Count_Reg);*/
read_nic_dword(dev, Tx_Retry_Count_Reg, &ieee->softmac_stats.txretrycount);
}
@@ -3469,11 +3115,12 @@ static void dm_send_rssi_tofw(struct net_device *dev)
{
struct r8192_priv *priv = ieee80211_priv(dev);
- // If we test chariot, we should stop the TX command ?
- // Because 92E will always silent reset when we send tx command. We use register
- // 0x1e0(byte) to notify driver.
+ /*
+ * If we test chariot, we should stop the TX command ?
+ * Because 92E will always silent reset when we send tx command. We use register
+ * 0x1e0(byte) to notify driver.
+ */
write_nic_byte(dev, DRIVER_RSSI, (u8)priv->undecorated_smoothed_pwdb);
- return;
}
/*---------------------------Define function prototype------------------------*/
diff --git a/drivers/staging/rtl8712/drv_types.h b/drivers/staging/rtl8712/drv_types.h
index 3d0a98b6d8e5..e62543d22b86 100644
--- a/drivers/staging/rtl8712/drv_types.h
+++ b/drivers/staging/rtl8712/drv_types.h
@@ -129,8 +129,8 @@ struct dvobj_priv {
struct _adapter *padapter;
u32 nr_endpoint;
u8 ishighspeed;
- uint(*inirp_init)(struct _adapter *adapter);
- uint(*inirp_deinit)(struct _adapter *adapter);
+ uint (*inirp_init)(struct _adapter *adapter);
+ uint (*inirp_deinit)(struct _adapter *adapter);
struct usb_device *pusbdev;
};
@@ -166,7 +166,7 @@ struct _adapter {
pid_t evtThread;
struct task_struct *xmitThread;
pid_t recvThread;
- uint(*dvobj_init)(struct _adapter *adapter);
+ uint (*dvobj_init)(struct _adapter *adapter);
void (*dvobj_deinit)(struct _adapter *adapter);
struct net_device *pnetdev;
int bup;
diff --git a/drivers/staging/rtl8712/osdep_service.h b/drivers/staging/rtl8712/osdep_service.h
index 5153ad9c2c75..36348d900d34 100644
--- a/drivers/staging/rtl8712/osdep_service.h
+++ b/drivers/staging/rtl8712/osdep_service.h
@@ -71,7 +71,7 @@ static inline void _init_timer(struct timer_list *ptimer,
static inline void _set_timer(struct timer_list *ptimer, u32 delay_time)
{
- mod_timer(ptimer, (jiffies+(delay_time*HZ/1000)));
+ mod_timer(ptimer, (jiffies+msecs_to_jiffies(delay_time)));
}
static inline void _cancel_timer(struct timer_list *ptimer, u8 *bcancelled)
@@ -101,12 +101,9 @@ static inline void sleep_schedulable(int ms)
{
u32 delta;
- delta = (ms * HZ) / 1000;/*(ms)*/
- if (delta == 0)
- delta = 1;/* 1 ms */
+ delta = msecs_to_jiffies(ms);/*(ms)*/
set_current_state(TASK_INTERRUPTIBLE);
- if (schedule_timeout(delta) != 0)
- return;
+ schedule_timeout(delta);
}
static inline unsigned char _cancel_timer_ex(struct timer_list *ptimer)
diff --git a/drivers/staging/rtl8712/recv_linux.c b/drivers/staging/rtl8712/recv_linux.c
index 0631f3638257..409c8c897256 100644
--- a/drivers/staging/rtl8712/recv_linux.c
+++ b/drivers/staging/rtl8712/recv_linux.c
@@ -137,20 +137,6 @@ _recv_indicatepkt_drop:
precvpriv->rx_drop++;
}
-void r8712_os_read_port(struct _adapter *padapter, struct recv_buf *precvbuf)
-{
- struct recv_priv *precvpriv = &padapter->recvpriv;
-
- precvbuf->ref_cnt--;
- /*free skb in recv_buf*/
- dev_kfree_skb_any(precvbuf->pskb);
- precvbuf->pskb = NULL;
- precvbuf->reuse = false;
- if (!precvbuf->irp_pending)
- r8712_read_port(padapter, precvpriv->ff_hwaddr, 0,
- (unsigned char *)precvbuf);
-}
-
static void _r8712_reordering_ctrl_timeout_handler (void *FunctionContext)
{
struct recv_reorder_ctrl *preorder_ctrl =
diff --git a/drivers/staging/rtl8712/recv_osdep.h b/drivers/staging/rtl8712/recv_osdep.h
index f4384ef00868..1f4986e940a3 100644
--- a/drivers/staging/rtl8712/recv_osdep.h
+++ b/drivers/staging/rtl8712/recv_osdep.h
@@ -46,7 +46,6 @@ int r8712_os_recvbuf_resource_alloc(struct _adapter *padapter,
struct recv_buf *precvbuf);
int r8712_os_recvbuf_resource_free(struct _adapter *padapter,
struct recv_buf *precvbuf);
-void r8712_os_read_port(struct _adapter *padapter, struct recv_buf *precvbuf);
void r8712_init_recv_timer(struct recv_reorder_ctrl *preorder_ctrl);
#endif
diff --git a/drivers/staging/rtl8712/rtl8712_cmd.h b/drivers/staging/rtl8712/rtl8712_cmd.h
index 039ab3e97172..67e9e910aef9 100644
--- a/drivers/staging/rtl8712/rtl8712_cmd.h
+++ b/drivers/staging/rtl8712/rtl8712_cmd.h
@@ -109,16 +109,16 @@ enum rtl8712_h2c_cmd {
GEN_CMD_CODE(_DisconnectCtrlEx), /*61*/
/* To do, modify these h2c cmd, add or delete */
- GEN_CMD_CODE(_GetH2cLbk) ,
+ GEN_CMD_CODE(_GetH2cLbk),
/* WPS extra IE */
- GEN_CMD_CODE(_SetProbeReqExtraIE) ,
- GEN_CMD_CODE(_SetAssocReqExtraIE) ,
- GEN_CMD_CODE(_SetProbeRspExtraIE) ,
- GEN_CMD_CODE(_SetAssocRspExtraIE) ,
+ GEN_CMD_CODE(_SetProbeReqExtraIE),
+ GEN_CMD_CODE(_SetAssocReqExtraIE),
+ GEN_CMD_CODE(_SetProbeRspExtraIE),
+ GEN_CMD_CODE(_SetAssocRspExtraIE),
/* the following is driver will do */
- GEN_CMD_CODE(_GetCurDataRate) ,
+ GEN_CMD_CODE(_GetCurDataRate),
GEN_CMD_CODE(_GetTxRetrycnt), /* to record times that Tx retry to
* transmit packet after association
diff --git a/drivers/staging/rtl8712/rtl8712_event.h b/drivers/staging/rtl8712/rtl8712_event.h
index 3d7f79efa2c1..29a4c23a0d23 100644
--- a/drivers/staging/rtl8712/rtl8712_event.h
+++ b/drivers/staging/rtl8712/rtl8712_event.h
@@ -27,7 +27,7 @@
#define _RTL8712_EVENT_H_
void r8712_event_handle(struct _adapter *padapter, uint *peventbuf);
-void r8712_got_addbareq_event_callback(struct _adapter *adapter , u8 *pbuf);
+void r8712_got_addbareq_event_callback(struct _adapter *adapter, u8 *pbuf);
enum rtl8712_c2h_event {
GEN_EVT_CODE(_Read_MACREG) = 0, /*0*/
diff --git a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
index 73b7d864ccbd..9bb364f04fd4 100644
--- a/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
+++ b/drivers/staging/rtl8712/rtl871x_ioctl_linux.c
@@ -196,7 +196,7 @@ static inline char *translate_scan(struct _adapter *padapter,
if (p && ht_ielen > 0) {
ht_cap = true;
pht_capie = (struct ieee80211_ht_cap *)(p + 2);
- memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
+ memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
}
/* Add the protocol name */
iwe.cmd = SIOCGIWNAME;
@@ -1436,7 +1436,7 @@ static int r8711_wx_get_rate(struct net_device *dev,
if (p && ht_ielen > 0) {
ht_cap = true;
pht_capie = (struct ieee80211_ht_cap *)(p + 2);
- memcpy(&mcs_rate , pht_capie->supp_mcs_set, 2);
+ memcpy(&mcs_rate, pht_capie->supp_mcs_set, 2);
bw_40MHz = (pht_capie->cap_info &
IEEE80211_HT_CAP_SUP_WIDTH) ? 1 : 0;
short_GI = (pht_capie->cap_info &
diff --git a/drivers/staging/rtl8712/rtl871x_mlme.c b/drivers/staging/rtl8712/rtl871x_mlme.c
index b7462e8145d6..977a83358056 100644
--- a/drivers/staging/rtl8712/rtl871x_mlme.c
+++ b/drivers/staging/rtl8712/rtl871x_mlme.c
@@ -93,7 +93,7 @@ struct wlan_network *_r8712_alloc_network(struct mlme_priv *pmlmepriv)
return NULL;
spin_lock_irqsave(&free_queue->lock, irqL);
plist = free_queue->queue.next;
- pnetwork = LIST_CONTAINOR(plist , struct wlan_network, list);
+ pnetwork = LIST_CONTAINOR(plist, struct wlan_network, list);
list_del_init(&pnetwork->list);
pnetwork->last_scanned = jiffies;
pmlmepriv->num_of_scanned++;
@@ -499,7 +499,7 @@ static int is_desired_network(struct _adapter *adapter,
}
/* TODO: Perry : For Power Management */
-void r8712_atimdone_event_callback(struct _adapter *adapter , u8 *pbuf)
+void r8712_atimdone_event_callback(struct _adapter *adapter, u8 *pbuf)
{
}
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
index a16f15e91992..0b5461208eb9 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.c
@@ -575,26 +575,6 @@ uint oid_rt_pro_set_single_tone_tx_hdl(struct oid_par_priv
return RNDIS_STATUS_SUCCESS;
}
-uint oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
- struct ndis_802_11_ssid *pssid;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- *poid_par_priv->bytes_needed = (u32)sizeof(struct ndis_802_11_ssid);
- *poid_par_priv->bytes_rw = 0;
- if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
- return RNDIS_STATUS_INVALID_LENGTH;
- pssid = (struct ndis_802_11_ssid *)poid_par_priv->information_buf;
- if (mp_start_joinbss(Adapter, pssid) == _FAIL)
- status = RNDIS_STATUS_NOT_ACCEPTED;
- *poid_par_priv->bytes_rw = sizeof(struct ndis_802_11_ssid);
- return status;
-}
-
uint oid_rt_pro_read_register_hdl(struct oid_par_priv
*poid_par_priv)
{
@@ -696,172 +676,6 @@ uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv)
return status;
}
-uint oid_rt_pro_burst_read_register_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- struct burst_rw_reg *pBstRwReg;
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- pBstRwReg = (struct burst_rw_reg *)poid_par_priv->information_buf;
- r8712_read_mem(Adapter, pBstRwReg->offset, (u32)pBstRwReg->len,
- pBstRwReg->Data);
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_burst_write_register_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- struct burst_rw_reg *pBstRwReg;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- pBstRwReg = (struct burst_rw_reg *)poid_par_priv->information_buf;
- r8712_write_mem(Adapter, pBstRwReg->offset, (u32)pBstRwReg->len,
- pBstRwReg->Data);
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv)
-{
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- struct eeprom_rw_param *pEEPROM;
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- pEEPROM = (struct eeprom_rw_param *)poid_par_priv->information_buf;
- pEEPROM->value = r8712_eeprom_read16(Adapter,
- (u16)(pEEPROM->offset >> 1));
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- struct eeprom_rw_param *pEEPROM;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- pEEPROM = (struct eeprom_rw_param *)poid_par_priv->information_buf;
- r8712_eeprom_write16(Adapter, (u16)(pEEPROM->offset >> 1),
- pEEPROM->value);
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- struct mp_wiparam *pwi_param;
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (poid_par_priv->information_buf_len < sizeof(struct mp_wiparam))
- return RNDIS_STATUS_INVALID_LENGTH;
- if (Adapter->mppriv.workparam.bcompleted == false)
- return RNDIS_STATUS_NOT_ACCEPTED;
- pwi_param = (struct mp_wiparam *)poid_par_priv->information_buf;
- memcpy(pwi_param, &Adapter->mppriv.workparam,
- sizeof(struct mp_wiparam));
- Adapter->mppriv.act_in_progress = false;
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (poid_par_priv->information_buf_len < sizeof(uint) * 2)
- return RNDIS_STATUS_INVALID_LENGTH;
- if (*(uint *)poid_par_priv->information_buf == 1)
- Adapter->mppriv.rx_pktloss = 0;
- *((uint *)poid_par_priv->information_buf+1) =
- Adapter->mppriv.rx_pktloss;
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv)
-{
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_wr_attrib_mem_hdl(struct oid_par_priv *poid_par_priv)
-{
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (r8712_setrfintfs_cmd(Adapter, *(unsigned char *)
- poid_par_priv->information_buf) == _FAIL)
- status = RNDIS_STATUS_NOT_ACCEPTED;
- return status;
-}
-
-uint oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- memcpy(poid_par_priv->information_buf,
- (unsigned char *)&Adapter->mppriv.rxstat,
- sizeof(struct recv_stat));
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_cfg_debug_message_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_data_rate_ex_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (r8712_setdatarate_cmd(Adapter,
- poid_par_priv->information_buf) != _SUCCESS)
- status = RNDIS_STATUS_NOT_ACCEPTED;
- return status;
-}
-
uint oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv)
{
struct _adapter *Adapter = (struct _adapter *)
@@ -890,251 +704,6 @@ uint oid_rt_get_thermal_meter_hdl(struct oid_par_priv *poid_par_priv)
return RNDIS_STATUS_SUCCESS;
}
-uint oid_rt_pro_set_power_tracking_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (poid_par_priv->information_buf_len < sizeof(u8))
- return RNDIS_STATUS_INVALID_LENGTH;
- if (!r8712_setptm_cmd(Adapter, *((u8 *)poid_par_priv->information_buf)))
- status = RNDIS_STATUS_NOT_ACCEPTED;
- return status;
-}
-
-uint oid_rt_pro_set_basic_rate_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- u8 mpdatarate[NumRates] = {11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0, 0xff};
- uint status = RNDIS_STATUS_SUCCESS;
- u32 ratevalue;
- u8 datarates[NumRates];
- int i;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- ratevalue = *((u32 *)poid_par_priv->information_buf);
- for (i = 0; i < NumRates; i++) {
- if (ratevalue == mpdatarate[i])
- datarates[i] = mpdatarate[i];
- else
- datarates[i] = 0xff;
- }
- if (r8712_setbasicrate_cmd(Adapter, datarates) != _SUCCESS)
- status = RNDIS_STATUS_NOT_ACCEPTED;
- return status;
-}
-
-uint oid_rt_pro_qry_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (poid_par_priv->information_buf_len < 8)
- return RNDIS_STATUS_INVALID_LENGTH;
- *poid_par_priv->bytes_rw = 8;
- memcpy(poid_par_priv->information_buf,
- &(Adapter->pwrctrlpriv.pwr_mode), 8);
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_pwrstate_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint pwr_mode, smart_ps;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- *poid_par_priv->bytes_rw = 0;
- *poid_par_priv->bytes_needed = 8;
- if (poid_par_priv->information_buf_len < 8)
- return RNDIS_STATUS_INVALID_LENGTH;
- pwr_mode = *(uint *)(poid_par_priv->information_buf);
- smart_ps = *(uint *)((addr_t)poid_par_priv->information_buf + 4);
- if (pwr_mode != Adapter->pwrctrlpriv.pwr_mode || smart_ps !=
- Adapter->pwrctrlpriv.smart_ps)
- r8712_set_ps_mode(Adapter, pwr_mode, smart_ps);
- *poid_par_priv->bytes_rw = 8;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_h2c_set_rate_table_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
- struct setratable_parm *prate_table;
- u8 res;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- *poid_par_priv->bytes_needed = sizeof(struct setratable_parm);
- if (poid_par_priv->information_buf_len <
- sizeof(struct setratable_parm))
- return RNDIS_STATUS_INVALID_LENGTH;
- prate_table = (struct setratable_parm *)poid_par_priv->information_buf;
- res = r8712_setrttbl_cmd(Adapter, prate_table);
- if (res == _FAIL)
- status = RNDIS_STATUS_FAILURE;
- return status;
-}
-
-uint oid_rt_pro_h2c_get_rate_table_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- struct security_priv *psecuritypriv = &Adapter->securitypriv;
- enum ENCRY_CTRL_STATE encry_mode = 0;
-
- *poid_par_priv->bytes_needed = sizeof(u8);
- if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
- return RNDIS_STATUS_INVALID_LENGTH;
-
- if (poid_par_priv->type_of_oid == SET_OID) {
- encry_mode = *((u8 *)poid_par_priv->information_buf);
- switch (encry_mode) {
- case HW_CONTROL:
- psecuritypriv->sw_decrypt = false;
- psecuritypriv->sw_encrypt = false;
- break;
- case SW_CONTROL:
- psecuritypriv->sw_decrypt = true;
- psecuritypriv->sw_encrypt = true;
- break;
- case HW_ENCRY_SW_DECRY:
- psecuritypriv->sw_decrypt = true;
- psecuritypriv->sw_encrypt = false;
- break;
- case SW_ENCRY_HW_DECRY:
- psecuritypriv->sw_decrypt = false;
- psecuritypriv->sw_encrypt = true;
- break;
- }
- } else {
- if ((psecuritypriv->sw_encrypt == false) &&
- (psecuritypriv->sw_decrypt == false))
- encry_mode = HW_CONTROL;
- else if ((psecuritypriv->sw_encrypt == false) &&
- (psecuritypriv->sw_decrypt == true))
- encry_mode = HW_ENCRY_SW_DECRY;
- else if ((psecuritypriv->sw_encrypt == true) &&
- (psecuritypriv->sw_decrypt == false))
- encry_mode = SW_ENCRY_HW_DECRY;
- else if ((psecuritypriv->sw_encrypt == true) &&
- (psecuritypriv->sw_decrypt == true))
- encry_mode = SW_CONTROL;
- *(u8 *)poid_par_priv->information_buf = encry_mode;
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- }
- return RNDIS_STATUS_SUCCESS;
-}
-/*----------------------------------------------------------------------*/
-uint oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
-
- uint status = RNDIS_STATUS_SUCCESS;
-
- struct sta_info *psta = NULL;
- u8 *macaddr;
-
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
-
- *poid_par_priv->bytes_needed = ETH_ALEN;
- if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
- return RNDIS_STATUS_INVALID_LENGTH;
- macaddr = (u8 *) poid_par_priv->information_buf;
- psta = r8712_get_stainfo(&Adapter->stapriv, macaddr);
- if (psta == NULL) { /* the sta in sta_info_queue => do nothing*/
- psta = r8712_alloc_stainfo(&Adapter->stapriv, macaddr);
- if (psta == NULL)
- status = RNDIS_STATUS_FAILURE;
- }
- return status;
-}
-/*-------------------------------------------------------------------------*/
-uint oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
-
- unsigned long irqL;
-
- struct sta_info *psta = NULL;
- u8 *macaddr;
-
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
-
- *poid_par_priv->bytes_needed = ETH_ALEN;
- if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
- return RNDIS_STATUS_INVALID_LENGTH;
-
- macaddr = (u8 *)poid_par_priv->information_buf;
-
- psta = r8712_get_stainfo(&Adapter->stapriv, macaddr);
- if (psta != NULL) {
- spin_lock_irqsave(&(Adapter->stapriv.sta_hash_lock), irqL);
- r8712_free_stainfo(Adapter, psta);
- spin_unlock_irqrestore(&(Adapter->stapriv.sta_hash_lock), irqL);
- }
-
- return RNDIS_STATUS_SUCCESS;
-}
-/*--------------------------------------------------------------------------*/
-static u32 mp_query_drv_var(struct _adapter *padapter, u8 offset, u32 var)
-{
- return var;
-}
-
-uint oid_rt_pro_query_dr_variable_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
-
- struct DR_VARIABLE_STRUCT *pdrv_var;
-
- if (poid_par_priv->type_of_oid != QUERY_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- *poid_par_priv->bytes_needed = sizeof(struct DR_VARIABLE_STRUCT);
- if (poid_par_priv->information_buf_len < *poid_par_priv->bytes_needed)
- return RNDIS_STATUS_INVALID_LENGTH;
- pdrv_var = (struct DR_VARIABLE_STRUCT *)poid_par_priv->information_buf;
- pdrv_var->variable = mp_query_drv_var(Adapter, pdrv_var->offset,
- pdrv_var->variable);
- *poid_par_priv->bytes_rw = poid_par_priv->information_buf_len;
- return RNDIS_STATUS_SUCCESS;
-}
-
-/*--------------------------------------------------------------------------*/
-uint oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv)
-{
- return RNDIS_STATUS_SUCCESS;
-}
-/*------------------------------------------------------------------------*/
uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv)
{
struct _adapter *Adapter = (struct _adapter *)
@@ -1192,38 +761,6 @@ uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv)
return status;
}
/*----------------------------------------------------------------------*/
-uint oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
- struct PGPKT_STRUCT *ppgpkt;
-
- *poid_par_priv->bytes_rw = 0;
- if (poid_par_priv->information_buf_len < sizeof(struct PGPKT_STRUCT))
- return RNDIS_STATUS_INVALID_LENGTH;
- ppgpkt = (struct PGPKT_STRUCT *)poid_par_priv->information_buf;
- if (poid_par_priv->type_of_oid == QUERY_OID) {
- if (r8712_efuse_pg_packet_read(Adapter, ppgpkt->offset,
- ppgpkt->data) == true)
- *poid_par_priv->bytes_rw =
- poid_par_priv->information_buf_len;
- else
- status = RNDIS_STATUS_FAILURE;
- } else {
- if (r8712_efuse_reg_init(Adapter) == true) {
- if (r8712_efuse_pg_packet_write(Adapter, ppgpkt->offset,
- ppgpkt->word_en, ppgpkt->data) == true)
- *poid_par_priv->bytes_rw =
- poid_par_priv->information_buf_len;
- else
- status = RNDIS_STATUS_FAILURE;
- r8712_efuse_reg_uninit(Adapter);
- } else
- status = RNDIS_STATUS_FAILURE;
- }
- return status;
-}
uint oid_rt_get_efuse_current_size_hdl(struct oid_par_priv
*poid_par_priv)
@@ -1319,24 +856,6 @@ uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv)
return RNDIS_STATUS_SUCCESS;
}
-uint oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- u32 crystal_cap = 0;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (poid_par_priv->information_buf_len < sizeof(u32))
- return RNDIS_STATUS_INVALID_LENGTH;
- crystal_cap = *((u32 *)poid_par_priv->information_buf);/*4*/
- if (crystal_cap > 0xf)
- return RNDIS_STATUS_NOT_ACCEPTED;
- Adapter->mppriv.curr_crystalcap = crystal_cap;
- r8712_SetCrystalCap(Adapter);
- return RNDIS_STATUS_SUCCESS;
-}
-
uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv
*poid_par_priv)
{
@@ -1378,50 +897,6 @@ uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv
return RNDIS_STATUS_SUCCESS;
}
-uint oid_rt_pro_set_tx_agc_offset_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- u32 txagc;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
- if (poid_par_priv->information_buf_len < sizeof(u32))
- return RNDIS_STATUS_INVALID_LENGTH;
- txagc = *(u32 *)poid_par_priv->information_buf;
- r8712_SetTxAGCOffset(Adapter, txagc);
- return RNDIS_STATUS_SUCCESS;
-}
-
-uint oid_rt_pro_set_pkt_test_mode_hdl(struct oid_par_priv
- *poid_par_priv)
-{
- struct _adapter *Adapter = (struct _adapter *)
- (poid_par_priv->adapter_context);
- uint status = RNDIS_STATUS_SUCCESS;
- struct mlme_priv *pmlmepriv = &Adapter->mlmepriv;
- struct mp_priv *pmppriv = &Adapter->mppriv;
- u32 type;
-
- if (poid_par_priv->type_of_oid != SET_OID)
- return RNDIS_STATUS_NOT_ACCEPTED;
-
- if (poid_par_priv->information_buf_len < sizeof(u32))
- return RNDIS_STATUS_INVALID_LENGTH;
-
- type = *(u32 *)poid_par_priv->information_buf;
-
- if (_LOOPBOOK_MODE_ == type) {
- pmppriv->mode = type;
- set_fwstate(pmlmepriv, WIFI_MP_LPBK_STATE); /*append txdesc*/
- } else if (_2MAC_MODE_ == type) {
- pmppriv->mode = type;
- _clr_fwstate_(pmlmepriv, WIFI_MP_LPBK_STATE);
- } else
- status = RNDIS_STATUS_NOT_ACCEPTED;
- return status;
-}
/*--------------------------------------------------------------------------*/
/*Linux*/
unsigned int mp_ioctl_xmit_packet_hdl(struct oid_par_priv *poid_par_priv)
diff --git a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
index 850143d5dee3..8e7c7f8b69f9 100644
--- a/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
+++ b/drivers/staging/rtl8712/rtl871x_mp_ioctl.h
@@ -86,41 +86,8 @@ struct DR_VARIABLE_STRUCT {
int mp_start_joinbss(struct _adapter *padapter, struct ndis_802_11_ssid *pssid);
/* oid_rtl_seg_87_11_00 */
-uint oid_rt_pro8711_join_bss_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_read_register_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_write_register_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_burst_read_register_hdl(struct oid_par_priv*
- poid_par_priv);
-uint oid_rt_pro_burst_write_register_hdl(struct oid_par_priv*
- poid_par_priv);
-uint oid_rt_pro_write_txcmd_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_read16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_write16_eeprom_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro8711_wi_poll_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro8711_pkt_loss_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_rd_attrib_mem_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_wr_attrib_mem_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_rf_intfs_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_poll_rx_status_hdl(struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_11_20 */
-uint oid_rt_pro_cfg_debug_message_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_data_rate_ex_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_basic_rate_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_power_tracking_hdl(
- struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_11_50 */
-uint oid_rt_pro_qry_pwrstate_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_pwrstate_hdl(
- struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_11_F0 */
-uint oid_rt_pro_h2c_set_rate_table_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_h2c_get_rate_table_hdl(
- struct oid_par_priv *poid_par_priv);
/* oid_rtl_seg_81_80_00 */
uint oid_rt_pro_set_data_rate_hdl(
struct oid_par_priv *poid_par_priv);
@@ -159,28 +126,15 @@ uint oid_rt_pro_write_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_read_rf_reg_hdl(struct oid_par_priv *poid_par_priv);
/* oid_rtl_seg_81_85 */
uint oid_rt_wireless_mode_hdl(struct oid_par_priv *poid_par_priv);
-/* oid_rtl_seg_87_12_00 */
-uint oid_rt_pro_encryption_ctrl_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_add_sta_info_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_dele_sta_info_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_query_dr_variable_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_read_efuse_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_write_efuse_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_rw_efuse_pgpkt_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_get_efuse_current_size_hdl(
struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_efuse_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_pro_efuse_map_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_set_bandwidth_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_set_crystal_cap_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_set_rx_packet_type_hdl(struct oid_par_priv *poid_par_priv);
uint oid_rt_get_efuse_max_size_hdl(struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_tx_agc_offset_hdl(
- struct oid_par_priv *poid_par_priv);
-uint oid_rt_pro_set_pkt_test_mode_hdl(
- struct oid_par_priv *poid_par_priv);
uint oid_rt_get_thermal_meter_hdl(
struct oid_par_priv *poid_par_priv);
uint oid_rt_reset_phy_rx_packet_count_hdl(
diff --git a/drivers/staging/rtl8712/rtl871x_pwrctrl.h b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
index 0526ba077bfc..dbfb55523545 100644
--- a/drivers/staging/rtl8712/rtl871x_pwrctrl.h
+++ b/drivers/staging/rtl8712/rtl871x_pwrctrl.h
@@ -33,17 +33,17 @@
#define CMD_ALIVE BIT(2)
enum Power_Mgnt {
- PS_MODE_ACTIVE = 0 ,
- PS_MODE_MIN ,
- PS_MODE_MAX ,
- PS_MODE_DTIM ,
- PS_MODE_VOIP ,
- PS_MODE_UAPSD_WMM ,
- PS_MODE_UAPSD ,
- PS_MODE_IBSS ,
- PS_MODE_WWLAN ,
- PM_Radio_Off ,
- PM_Card_Disable ,
+ PS_MODE_ACTIVE = 0,
+ PS_MODE_MIN,
+ PS_MODE_MAX,
+ PS_MODE_DTIM,
+ PS_MODE_VOIP,
+ PS_MODE_UAPSD_WMM,
+ PS_MODE_UAPSD,
+ PS_MODE_IBSS,
+ PS_MODE_WWLAN,
+ PM_Radio_Off,
+ PM_Card_Disable,
PS_MODE_NUM
};
diff --git a/drivers/staging/rtl8712/rtl871x_sta_mgt.c b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
index 4c9b98e8210e..1752121ff494 100644
--- a/drivers/staging/rtl8712/rtl871x_sta_mgt.c
+++ b/drivers/staging/rtl8712/rtl871x_sta_mgt.c
@@ -83,9 +83,8 @@ static void mfree_all_stainfo(struct sta_priv *pstapriv)
spin_lock_irqsave(&pstapriv->sta_hash_lock, irqL);
phead = &pstapriv->free_sta_queue.queue;
plist = phead->next;
- while ((end_of_queue_search(phead, plist)) == false) {
+ while ((end_of_queue_search(phead, plist)) == false)
plist = plist->next;
- }
spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL);
}
@@ -228,7 +227,7 @@ void r8712_free_all_stainfo(struct _adapter *padapter)
struct sta_info, hash_list);
plist = plist->next;
if (pbcmc_stainfo != psta)
- r8712_free_stainfo(padapter , psta);
+ r8712_free_stainfo(padapter, psta);
}
}
spin_unlock_irqrestore(&pstapriv->sta_hash_lock, irqL);
diff --git a/drivers/staging/rtl8712/rtl871x_xmit.c b/drivers/staging/rtl8712/rtl871x_xmit.c
index 62a377e7fdc7..a28af03c9d8a 100644
--- a/drivers/staging/rtl8712/rtl871x_xmit.c
+++ b/drivers/staging/rtl8712/rtl871x_xmit.c
@@ -471,7 +471,7 @@ static sint xmitframe_swencrypt(struct _adapter *padapter,
return _SUCCESS;
}
-static sint make_wlanhdr(struct _adapter *padapter , u8 *hdr,
+static sint make_wlanhdr(struct _adapter *padapter, u8 *hdr,
struct pkt_attrib *pattrib)
{
u16 *qc;
diff --git a/drivers/staging/rtl8712/sta_info.h b/drivers/staging/rtl8712/sta_info.h
index c4e0ef2f52c6..742dfa0ca817 100644
--- a/drivers/staging/rtl8712/sta_info.h
+++ b/drivers/staging/rtl8712/sta_info.h
@@ -135,7 +135,7 @@ u32 _r8712_init_sta_priv(struct sta_priv *pstapriv);
u32 _r8712_free_sta_priv(struct sta_priv *pstapriv);
struct sta_info *r8712_alloc_stainfo(struct sta_priv *pstapriv,
u8 *hwaddr);
-void r8712_free_stainfo(struct _adapter *padapter , struct sta_info *psta);
+void r8712_free_stainfo(struct _adapter *padapter, struct sta_info *psta);
void r8712_free_all_stainfo(struct _adapter *padapter);
struct sta_info *r8712_get_stainfo(struct sta_priv *pstapriv, u8 *hwaddr);
void r8712_init_bcmc_stainfo(struct _adapter *padapter);
diff --git a/drivers/staging/rtl8712/usb_intf.c b/drivers/staging/rtl8712/usb_intf.c
index 7d0d1719b136..f8b5b332e7c3 100644
--- a/drivers/staging/rtl8712/usb_intf.c
+++ b/drivers/staging/rtl8712/usb_intf.c
@@ -366,7 +366,6 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
struct net_device *pnetdev;
struct usb_device *udev;
- printk(KERN_INFO "r8712u: Staging version\n");
/* In this probe function, O.S. will provide the usb interface pointer
* to driver. We have to increase the reference count of the usb device
* structure by using the usb_get_dev function.
@@ -463,7 +462,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
/* Use the mac address stored in the Efuse
* offset = 0x12 for usb in efuse
*/
- memcpy(mac, &pdata[0x12], ETH_ALEN);
+ ether_addr_copy(mac, &pdata[0x12]);
}
eeprom_CustomerID = pdata[0x52];
switch (eeprom_CustomerID) {
@@ -580,7 +579,7 @@ static int r871xu_drv_init(struct usb_interface *pusb_intf,
} else
dev_info(&udev->dev,
"r8712u: MAC Address from efuse = %pM\n", mac);
- memcpy(pnetdev->dev_addr, mac, ETH_ALEN);
+ ether_addr_copy(pnetdev->dev_addr, mac);
}
/* step 6. Load the firmware asynchronously */
if (rtl871x_load_fw(padapter))
diff --git a/drivers/staging/rtl8723au/core/rtw_ap.c b/drivers/staging/rtl8723au/core/rtw_ap.c
index e394d12c36b0..c6327c072918 100644
--- a/drivers/staging/rtl8723au/core/rtw_ap.c
+++ b/drivers/staging/rtl8723au/core/rtw_ap.c
@@ -456,8 +456,8 @@ static void update_bmc_sta(struct rtw_adapter *padapter)
sizeof(struct stainfo_stats));
/* prepare for add_RATid23a */
- supportRateNum = rtw_get_rateset_len23a((u8*)&pcur_network->SupportedRates);
- network_type = rtw_check_network_type23a((u8*)&pcur_network->SupportedRates, supportRateNum, 1);
+ supportRateNum = rtw_get_rateset_len23a((u8 *)&pcur_network->SupportedRates);
+ network_type = rtw_check_network_type23a((u8 *)&pcur_network->SupportedRates, supportRateNum, 1);
memcpy(psta->bssrateset, &pcur_network->SupportedRates, supportRateNum);
psta->bssratelen = supportRateNum;
@@ -897,7 +897,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter,
pairwise_cipher = 0;
psecuritypriv->wpa_group_cipher = 0;
psecuritypriv->wpa_pairwise_cipher = 0;
- for (p = ie; ;p += (ie_len + 2)) {
+ for (p = ie; ; p += (ie_len + 2)) {
p = rtw_get_ie23a(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len,
pbss_network->IELength - (ie_len + 2));
if ((p) && (!memcmp(p+2, RTW_WPA_OUI23A_TYPE, 4))) {
@@ -924,7 +924,7 @@ int rtw_check_beacon_data23a(struct rtw_adapter *padapter,
ie_len = 0;
pmlmepriv->qos_option = 0;
if (pregistrypriv->wmm_enable) {
- for (p = ie; ;p += (ie_len + 2)) {
+ for (p = ie; ; p += (ie_len + 2)) {
p = rtw_get_ie23a(p, WLAN_EID_VENDOR_SPECIFIC, &ie_len,
(pbss_network->IELength -
(ie_len + 2)));
@@ -1204,7 +1204,7 @@ static void update_bcn_p2p_ie(struct rtw_adapter *padapter)
{
}
-static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8*oui)
+static void update_bcn_vendor_spec_ie(struct rtw_adapter *padapter, u8 *oui)
{
DBG_8723A("%s\n", __func__);
diff --git a/drivers/staging/rtl8723au/core/rtw_cmd.c b/drivers/staging/rtl8723au/core/rtw_cmd.c
index 60e0ded8ae02..2447a56df838 100644
--- a/drivers/staging/rtl8723au/core/rtw_cmd.c
+++ b/drivers/staging/rtl8723au/core/rtw_cmd.c
@@ -245,11 +245,6 @@ exit:
return res;
}
-void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv)
-{
- pcmdpriv->cmd_done_cnt++;
-}
-
void rtw_free_cmd_obj23a(struct cmd_obj *pcmd)
{
@@ -852,62 +847,6 @@ exit:
return res;
}
-/*
- * This is only ever called from on_action_spct23a_ch_switch () which isn't
- * called from anywhere itself
- */
-int rtw_set_ch_cmd23a(struct rtw_adapter *padapter, u8 ch, u8 bw, u8 ch_offset,
- u8 enqueue)
-{
- struct cmd_obj *pcmdobj;
- struct set_ch_parm *set_ch_parm;
- struct cmd_priv *pcmdpriv = &padapter->cmdpriv;
- int res = _SUCCESS;
-
- DBG_8723A("%s(%s): ch:%u, bw:%u, ch_offset:%u\n", __func__,
- padapter->pnetdev->name, ch, bw, ch_offset);
-
- /* check input parameter */
-
- /* prepare cmd parameter */
- set_ch_parm = kzalloc(sizeof(*set_ch_parm), GFP_KERNEL);
- if (!set_ch_parm) {
- res = _FAIL;
- goto exit;
- }
- set_ch_parm->ch = ch;
- set_ch_parm->bw = bw;
- set_ch_parm->ch_offset = ch_offset;
-
- if (enqueue) {
- /* need enqueue, prepare cmd_obj and enqueue */
- pcmdobj = kzalloc(sizeof(struct cmd_obj), GFP_KERNEL);
- if (!pcmdobj) {
- kfree(set_ch_parm);
- res = _FAIL;
- goto exit;
- }
-
- init_h2fwcmd_w_parm_no_rsp(pcmdobj, set_ch_parm,
- GEN_CMD_CODE(_SetChannel));
- res = rtw_enqueue_cmd23a(pcmdpriv, pcmdobj);
- } else {
- /* no need to enqueue, do the cmd hdl directly and
- free cmd parameter */
- if (H2C_SUCCESS != set_ch_hdl23a(padapter, (u8 *)set_ch_parm))
- res = _FAIL;
-
- kfree(set_ch_parm);
- }
-
- /* do something based on res... */
-exit:
-
- DBG_8723A("%s(%s): res:%u\n", __func__, padapter->pnetdev->name, res);
-
- return res;
-}
-
static void traffic_status_watchdog(struct rtw_adapter *padapter)
{
u8 bEnterPS;
diff --git a/drivers/staging/rtl8723au/core/rtw_efuse.c b/drivers/staging/rtl8723au/core/rtw_efuse.c
index 81960e788f89..a6deddc02291 100644
--- a/drivers/staging/rtl8723au/core/rtw_efuse.c
+++ b/drivers/staging/rtl8723au/core/rtw_efuse.c
@@ -327,15 +327,9 @@ EFUSE_Read1Byte23a(struct rtw_adapter *Adapter, u16 Address)
*---------------------------------------------------------------------------*/
void
-EFUSE_Write1Byte(
- struct rtw_adapter * Adapter,
- u16 Address,
- u8 Value);
+EFUSE_Write1Byte(struct rtw_adapter *Adapter, u16 Address, u8 Value);
void
-EFUSE_Write1Byte(
- struct rtw_adapter * Adapter,
- u16 Address,
- u8 Value)
+EFUSE_Write1Byte(struct rtw_adapter *Adapter, u16 Address, u8 Value)
{
u8 Bytetemp = {0x00};
u8 temp = {0x00};
@@ -635,10 +629,7 @@ Efuse_ReadAllMap(struct rtw_adapter *pAdapter, u8 efuseType, u8 *Efuse)
*
*---------------------------------------------------------------------------*/
static void
-efuse_ShadowRead1Byte(
- struct rtw_adapter * pAdapter,
- u16 Offset,
- u8 *Value)
+efuse_ShadowRead1Byte(struct rtw_adapter *pAdapter, u16 Offset, u8 *Value)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
@@ -647,10 +638,7 @@ efuse_ShadowRead1Byte(
/* Read Two Bytes */
static void
-efuse_ShadowRead2Byte(
- struct rtw_adapter * pAdapter,
- u16 Offset,
- u16 *Value)
+efuse_ShadowRead2Byte(struct rtw_adapter *pAdapter, u16 Offset, u16 *Value)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
@@ -660,10 +648,7 @@ efuse_ShadowRead2Byte(
/* Read Four Bytes */
static void
-efuse_ShadowRead4Byte(
- struct rtw_adapter * pAdapter,
- u16 Offset,
- u32 *Value)
+efuse_ShadowRead4Byte(struct rtw_adapter *pAdapter, u16 Offset, u32 *Value)
{
struct eeprom_priv *pEEPROM = GET_EEPROM_EFUSE_PRIV(pAdapter);
@@ -722,11 +707,8 @@ void EFUSE_ShadowMapUpdate23a(struct rtw_adapter *pAdapter, u8 efuseType)
*
*---------------------------------------------------------------------------*/
void
-EFUSE_ShadowRead23a(
- struct rtw_adapter * pAdapter,
- u8 Type,
- u16 Offset,
- u32 *Value)
+EFUSE_ShadowRead23a(struct rtw_adapter *pAdapter,
+ u8 Type, u16 Offset, u32 *Value)
{
if (Type == 1)
efuse_ShadowRead1Byte(pAdapter, Offset, (u8 *)Value);
diff --git a/drivers/staging/rtl8723au/core/rtw_xmit.c b/drivers/staging/rtl8723au/core/rtw_xmit.c
index 7a5e6bf0d1ae..1c82dffcf596 100644
--- a/drivers/staging/rtl8723au/core/rtw_xmit.c
+++ b/drivers/staging/rtl8723au/core/rtw_xmit.c
@@ -2372,12 +2372,3 @@ int rtw_ack_tx_wait23a(struct xmit_priv *pxmitpriv, u32 timeout_ms)
return rtw_sctx_wait23a(pack_tx_ops);
}
-void rtw_ack_tx_done23a(struct xmit_priv *pxmitpriv, int status)
-{
- struct submit_ctx *pack_tx_ops = &pxmitpriv->ack_tx_ops;
-
- if (pxmitpriv->ack_tx)
- rtw23a_sctx_done_err(&pack_tx_ops, status);
- else
- DBG_8723A("%s ack_tx not set\n", __func__);
-}
diff --git a/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
index 1da4eece6f9a..33777d2852f4 100644
--- a/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
+++ b/drivers/staging/rtl8723au/hal/HalPwrSeqCmd.c
@@ -47,11 +47,11 @@ u8 HalPwrSeqCmdParsing23a(struct rtw_adapter *padapter, u8 CutVersion,
u8 FabVersion, u8 InterfaceType,
struct wlan_pwr_cfg PwrSeqCmd[])
{
- struct wlan_pwr_cfg PwrCfgCmd = { 0 };
- u8 bPollingBit = false;
+ struct wlan_pwr_cfg PwrCfgCmd;
+ u8 bPollingBit;
u32 AryIdx = 0;
- u8 value = 0;
- u32 offset = 0;
+ u8 value;
+ u32 offset;
u32 pollingCount = 0; /* polling autoload done. */
u32 maxPollingCnt = 5000;
diff --git a/drivers/staging/rtl8723au/hal/odm.c b/drivers/staging/rtl8723au/hal/odm.c
index 1c0f106d5996..5269b46445f4 100644
--- a/drivers/staging/rtl8723au/hal/odm.c
+++ b/drivers/staging/rtl8723au/hal/odm.c
@@ -187,24 +187,13 @@ void odm23a_DynBBPSInit(struct dm_odm_t *pDM_Odm);
void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm);
-void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm);
/* END---------BB POWER SAVE----------------------- */
-void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm);
-
void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm);
-void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm);
-
void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm);
-void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm);
-
-void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm);
-
void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm);
-void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm);
-
void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm);
void odm_DynamicTxPower23a(struct dm_odm_t *pDM_Odm);
@@ -212,16 +201,12 @@ void odm_RefreshRateAdaptiveMask23a(struct dm_odm_t *pDM_Odm);
void ODM_TXPowerTrackingCheck23a(struct dm_odm_t *pDM_Odm);
-void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm);
-
void odm_RateAdaptiveMaskInit23a(struct dm_odm_t *pDM_Odm);
void odm_TXPowerTrackingThermalMeterInit23a(struct dm_odm_t *pDM_Odm);
void odm_TXPowerTrackingInit23a(struct dm_odm_t *pDM_Odm);
-void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm);
-
void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm);
static void odm_EdcaTurboCheck23a(struct dm_odm_t *pDM_Odm);
@@ -946,47 +931,13 @@ void odm_DynamicBBPowerSaving23a(struct dm_odm_t *pDM_Odm)
return;
}
-void odm_1R_CCA23a(struct dm_odm_t *pDM_Odm)
-{
- struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
-
- if (pDM_Odm->RSSI_Min != 0xFF) {
- if (pDM_PSTable->PreCCAState == CCA_2R) {
- if (pDM_Odm->RSSI_Min >= 35)
- pDM_PSTable->CurCCAState = CCA_1R;
- else
- pDM_PSTable->CurCCAState = CCA_2R;
- } else {
- if (pDM_Odm->RSSI_Min <= 30)
- pDM_PSTable->CurCCAState = CCA_2R;
- else
- pDM_PSTable->CurCCAState = CCA_1R;
- }
- } else {
- pDM_PSTable->CurCCAState = CCA_MAX;
- }
-
- if (pDM_PSTable->PreCCAState != pDM_PSTable->CurCCAState) {
- if (pDM_PSTable->CurCCAState == CCA_1R) {
- if (pDM_Odm->RFType == ODM_2T2R)
- ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x13);
- else
- ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x23);
- } else {
- ODM_SetBBReg(pDM_Odm, 0xc04, bMaskByte0, 0x33);
- /* PHY_SetBBReg(pAdapter, 0xe70, bMaskByte3, 0x63); */
- }
- pDM_PSTable->PreCCAState = pDM_PSTable->CurCCAState;
- }
-}
-
void ODM_RF_Saving23a(struct dm_odm_t *pDM_Odm, u8 bForceInNormal)
{
struct dynamic_pwr_sav *pDM_PSTable = &pDM_Odm->DM_PSTable;
- u8 Rssi_Up_bound = 30 ;
+ u8 Rssi_Up_bound = 30;
u8 Rssi_Low_bound = 25;
if (pDM_Odm->PatchID == 40) { /* RT_CID_819x_FUNAI_TV */
- Rssi_Up_bound = 50 ;
+ Rssi_Up_bound = 50;
Rssi_Low_bound = 45;
}
if (pDM_PSTable->initialize == 0) {
@@ -1177,10 +1128,6 @@ void odm_RefreshRateAdaptiveMask23a(struct dm_odm_t *pDM_Odm)
odm_RefreshRateAdaptiveMask23aCE23a(pDM_Odm);
}
-void odm_RefreshRateAdaptiveMask23aMP23a(struct dm_odm_t *pDM_Odm)
-{
-}
-
void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm)
{
u8 i;
@@ -1216,10 +1163,6 @@ void odm_RefreshRateAdaptiveMask23aCE23a(struct dm_odm_t *pDM_Odm)
}
-void odm_RefreshRateAdaptiveMask23aAPADSL23a(struct dm_odm_t *pDM_Odm)
-{
-}
-
/* Return Value: bool */
/* - true: RATRState is changed. */
bool ODM_RAStateCheck23a(struct dm_odm_t *pDM_Odm, s32 RSSI, bool bForceUpdate,
@@ -1284,14 +1227,6 @@ void odm_DynamicTxPower23aInit(struct dm_odm_t *pDM_Odm)
pdmpriv->DynamicTxHighPowerLvl = TxHighPwrLevel_Normal;
}
-/* 3 ============================================================ */
-/* 3 RSSI Monitor */
-/* 3 ============================================================ */
-
-void odm_RSSIMonitorInit(struct dm_odm_t *pDM_Odm)
-{
-}
-
void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm)
{
/* For AP/ADSL use struct rtl8723a_priv * */
@@ -1306,10 +1241,6 @@ void odm_RSSIMonitorCheck23a(struct dm_odm_t *pDM_Odm)
odm_RSSIMonitorCheck23aCE(pDM_Odm);
} /* odm_RSSIMonitorCheck23a */
-void odm_RSSIMonitorCheck23aMP(struct dm_odm_t *pDM_Odm)
-{
-}
-
static void
FindMinimumRSSI(
struct rtw_adapter *pAdapter
@@ -1378,10 +1309,6 @@ void odm_RSSIMonitorCheck23aCE(struct dm_odm_t *pDM_Odm)
ODM_CmnInfoUpdate23a(&pHalData->odmpriv, ODM_CMNINFO_RSSI_MIN, pdmpriv->MinUndecoratedPWDBForDM);
}
-void odm_RSSIMonitorCheck23aAP(struct dm_odm_t *pDM_Odm)
-{
-}
-
/* endif */
/* 3 ============================================================ */
/* 3 Tx Power Tracking */
@@ -1422,19 +1349,12 @@ void odm_TXPowerTrackingCheckCE23a(struct dm_odm_t *pDM_Odm)
{
}
-void odm_TXPowerTrackingCheckMP(struct dm_odm_t *pDM_Odm)
-{
-}
-
-void odm_TXPowerTrackingCheckAP(struct dm_odm_t *pDM_Odm)
-{
-}
-
/* EDCA Turbo */
static void ODM_EdcaTurboInit23a(struct dm_odm_t *pDM_Odm)
{
struct rtw_adapter *Adapter = pDM_Odm->Adapter;
+
pDM_Odm->DM_EDCA_Table.bCurrentTurboEDCA = false;
pDM_Odm->DM_EDCA_Table.bIsCurRDLState = false;
Adapter->recvpriv.bIsAnyNonBEPkts = false;
@@ -1591,6 +1511,7 @@ ConvertTo_dB23a(
void ODM_SingleDualAntennaDefaultSetting(struct dm_odm_t *pDM_Odm)
{
struct sw_ant_sw *pDM_SWAT_Table = &pDM_Odm->DM_SWAT_Table;
+
pDM_SWAT_Table->ANTA_ON = true;
pDM_SWAT_Table->ANTB_ON = true;
}
diff --git a/drivers/staging/rtl8723au/hal/odm_HWConfig.c b/drivers/staging/rtl8723au/hal/odm_HWConfig.c
index fb3cc872f205..33aafa01f900 100644
--- a/drivers/staging/rtl8723au/hal/odm_HWConfig.c
+++ b/drivers/staging/rtl8723au/hal/odm_HWConfig.c
@@ -113,7 +113,7 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct dm_odm_t *pDM_Odm,
cck_highpwr = pDM_Odm->bCckHighPower;
- cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a ;
+ cck_agc_rpt = pPhyStaRpt->cck_agc_rpt_ofdm_cfosho_a;
/* The RSSI formula should be modified according to the gain table */
if (!cck_highpwr) {
@@ -138,16 +138,16 @@ static void odm_RxPhyStatus92CSeries_Parsing(struct dm_odm_t *pDM_Odm,
report = (cck_agc_rpt & 0x60)>>5;
switch (report) {
case 0x3:
- rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1) ;
+ rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f)<<1);
break;
case 0x2:
rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f)<<1);
break;
case 0x1:
- rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1) ;
+ rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f)<<1);
break;
case 0x0:
- rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1) ;
+ rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f)<<1);
break;
}
}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
index 86a83975f4f0..73cfddd6df9a 100644
--- a/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
+++ b/drivers/staging/rtl8723au/hal/rtl8723a_bt-coexist.c
@@ -7255,63 +7255,19 @@ btdm_2AntTdmaDurationAdjust(struct rtw_adapter *padapter, u8 bScoHid,
RTPRINT(FBT, BT_TRACE, ("[BTCoex], first run TdmaDurationAdjust()!!\n"));
if (bScoHid) {
if (bTxPause) {
- if (maxInterval == 1) {
- btdm_2AntPsTdma(padapter, true, 15);
- pBtdm8723->psTdmaDuAdjType = 15;
- } else if (maxInterval == 2) {
- btdm_2AntPsTdma(padapter, true, 15);
- pBtdm8723->psTdmaDuAdjType = 15;
- } else if (maxInterval == 3) {
- btdm_2AntPsTdma(padapter, true, 15);
- pBtdm8723->psTdmaDuAdjType = 15;
- } else {
- btdm_2AntPsTdma(padapter, true, 15);
- pBtdm8723->psTdmaDuAdjType = 15;
- }
+ btdm_2AntPsTdma(padapter, true, 15);
+ pBtdm8723->psTdmaDuAdjType = 15;
} else {
- if (maxInterval == 1) {
- btdm_2AntPsTdma(padapter, true, 11);
- pBtdm8723->psTdmaDuAdjType = 11;
- } else if (maxInterval == 2) {
- btdm_2AntPsTdma(padapter, true, 11);
- pBtdm8723->psTdmaDuAdjType = 11;
- } else if (maxInterval == 3) {
- btdm_2AntPsTdma(padapter, true, 11);
- pBtdm8723->psTdmaDuAdjType = 11;
- } else {
- btdm_2AntPsTdma(padapter, true, 11);
- pBtdm8723->psTdmaDuAdjType = 11;
- }
+ btdm_2AntPsTdma(padapter, true, 11);
+ pBtdm8723->psTdmaDuAdjType = 11;
}
} else {
if (bTxPause) {
- if (maxInterval == 1) {
- btdm_2AntPsTdma(padapter, true, 7);
- pBtdm8723->psTdmaDuAdjType = 7;
- } else if (maxInterval == 2) {
- btdm_2AntPsTdma(padapter, true, 7);
- pBtdm8723->psTdmaDuAdjType = 7;
- } else if (maxInterval == 3) {
- btdm_2AntPsTdma(padapter, true, 7);
- pBtdm8723->psTdmaDuAdjType = 7;
- } else {
- btdm_2AntPsTdma(padapter, true, 7);
- pBtdm8723->psTdmaDuAdjType = 7;
- }
+ btdm_2AntPsTdma(padapter, true, 7);
+ pBtdm8723->psTdmaDuAdjType = 7;
} else {
- if (maxInterval == 1) {
- btdm_2AntPsTdma(padapter, true, 3);
- pBtdm8723->psTdmaDuAdjType = 3;
- } else if (maxInterval == 2) {
- btdm_2AntPsTdma(padapter, true, 3);
- pBtdm8723->psTdmaDuAdjType = 3;
- } else if (maxInterval == 3) {
- btdm_2AntPsTdma(padapter, true, 3);
- pBtdm8723->psTdmaDuAdjType = 3;
- } else {
- btdm_2AntPsTdma(padapter, true, 3);
- pBtdm8723->psTdmaDuAdjType = 3;
- }
+ btdm_2AntPsTdma(padapter, true, 3);
+ pBtdm8723->psTdmaDuAdjType = 3;
}
}
up = 0;
@@ -9145,7 +9101,7 @@ u32 BTDM_BtTxRxCounterL(struct rtw_adapter *padapter)
u32 counters = 0;
counters = pHalData->bt_coexist.halCoex8723.lowPriorityTx+
- pHalData->bt_coexist.halCoex8723.lowPriorityRx ;
+ pHalData->bt_coexist.halCoex8723.lowPriorityRx;
return counters;
}
diff --git a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
index 88e91cd8ebb9..19dc5e3b2e2e 100644
--- a/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
+++ b/drivers/staging/rtl8723au/hal/rtl8723a_phycfg.c
@@ -698,7 +698,7 @@ storePwrIndexDiffRateOffset(struct rtw_adapter *Adapter, u32 RegAddr,
* 11/10/2008 tynli Modify to mew files.
*---------------------------------------------------------------------------*/
static int
-phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter, u8 ConfigType)
+phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter)
{
int i;
u32 *Rtl819XPHY_REGArray_Table_PG;
@@ -707,17 +707,15 @@ phy_ConfigBBWithPgHeaderFile(struct rtw_adapter *Adapter, u8 ConfigType)
PHY_REGArrayPGLen = Rtl8723_PHY_REG_Array_PGLength;
Rtl819XPHY_REGArray_Table_PG = (u32 *)Rtl8723_PHY_REG_Array_PG;
- if (ConfigType == BaseBand_Config_PHY_REG) {
- for (i = 0; i < PHY_REGArrayPGLen; i = i + 3) {
- storePwrIndexDiffRateOffset(Adapter,
- Rtl819XPHY_REGArray_Table_PG[i],
- Rtl819XPHY_REGArray_Table_PG[i+1],
- Rtl819XPHY_REGArray_Table_PG[i+2]);
- }
+ for (i = 0; i < PHY_REGArrayPGLen; i = i + 3) {
+ storePwrIndexDiffRateOffset(Adapter,
+ Rtl819XPHY_REGArray_Table_PG[i],
+ Rtl819XPHY_REGArray_Table_PG[i+1],
+ Rtl819XPHY_REGArray_Table_PG[i+2]);
}
return _SUCCESS;
-} /* phy_ConfigBBWithPgHeaderFile */
+}
static void
phy_BB8192C_Config_1T(struct rtw_adapter *Adapter)
@@ -768,8 +766,7 @@ phy_BB8723a_Config_ParaFile(struct rtw_adapter *Adapter)
if (pEEPROM->bautoload_fail_flag == false) {
pHalData->pwrGroupCnt = 0;
- rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter,
- BaseBand_Config_PHY_REG);
+ rtStatus = phy_ConfigBBWithPgHeaderFile(Adapter);
}
if (rtStatus != _SUCCESS)
@@ -923,9 +920,6 @@ _PHY_SetBWMode23a92C(struct rtw_adapter *Adapter)
u8 regBwOpMode;
u8 regRRSR_RSC;
- if (pHalData->rf_chip == RF_PSEUDO_11N)
- return;
-
/* There is no 40MHz mode in RF_8225. */
if (pHalData->rf_chip == RF_8225)
return;
@@ -1021,10 +1015,6 @@ _PHY_SetBWMode23a92C(struct rtw_adapter *Adapter)
/* PHY_SetRF8258Bandwidth(); */
break;
- case RF_PSEUDO_11N:
- /* Do Nothing */
- break;
-
case RF_6052:
rtl8723a_phy_rf6052set_bw(Adapter, pHalData->CurrentChannelBW);
break;
@@ -1074,7 +1064,7 @@ PHY_SetBWMode23a8723A(struct rtw_adapter *Adapter,
static void _PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel)
{
- u8 eRFPath;
+ enum RF_RADIO_PATH eRFPath;
u32 param1, param2;
struct hal_data_8723a *pHalData = GET_HAL_DATA(Adapter);
@@ -1088,7 +1078,7 @@ static void _PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel)
for (eRFPath = 0; eRFPath < pHalData->NumTotalRFPath; eRFPath++) {
pHalData->RfRegChnlVal[eRFPath] =
(pHalData->RfRegChnlVal[eRFPath] & 0xfffffc00) | param2;
- PHY_SetRFReg(Adapter, (enum RF_RADIO_PATH)eRFPath, param1,
+ PHY_SetRFReg(Adapter, eRFPath, param1,
bRFRegOffsetMask, pHalData->RfRegChnlVal[eRFPath]);
}
@@ -1101,11 +1091,6 @@ void PHY_SwChnl8723A(struct rtw_adapter *Adapter, u8 channel)
u8 tmpchannel = pHalData->CurrentChannel;
bool result = true;
- if (pHalData->rf_chip == RF_PSEUDO_11N) {
- /* return immediately if it is peudo-phy */
- return;
- }
-
if (channel == 0)
channel = 1;
diff --git a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
index 6070510bb470..1759487329ab 100644
--- a/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
+++ b/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c
@@ -79,7 +79,7 @@ static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxd
}
}
-static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw)
+static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw)
{
/* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */
@@ -114,7 +114,7 @@ static void fill_txdesc_vcs(struct pkt_attrib *pattrib, u32 *pdw)
}
}
-static void fill_txdesc_phy(struct pkt_attrib *pattrib, u32 *pdw)
+static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw)
{
if (pattrib->ht_en) {
*pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0;
diff --git a/drivers/staging/rtl8723au/hal/usb_halinit.c b/drivers/staging/rtl8723au/hal/usb_halinit.c
index febe5cedef8f..adbf1c2dd383 100644
--- a/drivers/staging/rtl8723au/hal/usb_halinit.c
+++ b/drivers/staging/rtl8723au/hal/usb_halinit.c
@@ -625,10 +625,10 @@ int rtl8723au_hal_init(struct rtw_adapter *Adapter)
}
/* reducing 80M spur */
- PHY_SetBBReg(Adapter, RF_T_METER, bMaskDWord, 0x0381808d);
- PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83);
- PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff82);
- PHY_SetBBReg(Adapter, RF_SYN_G4, bMaskDWord, 0xf2ffff83);
+ PHY_SetBBReg(Adapter, REG_AFE_XTAL_CTRL, bMaskDWord, 0x0381808d);
+ PHY_SetBBReg(Adapter, REG_AFE_PLL_CTRL, bMaskDWord, 0xf0ffff83);
+ PHY_SetBBReg(Adapter, REG_AFE_PLL_CTRL, bMaskDWord, 0xf0ffff82);
+ PHY_SetBBReg(Adapter, REG_AFE_PLL_CTRL, bMaskDWord, 0xf0ffff83);
/* RFSW Control */
PHY_SetBBReg(Adapter, rFPGA0_TxInfo, bMaskDWord, 0x00000003); /* 0x804[14]= 0 */
@@ -640,8 +640,10 @@ int rtl8723au_hal_init(struct rtw_adapter *Adapter)
/* */
/* Joseph Note: Keep RfRegChnlVal for later use. */
/* */
- pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)0, RF_CHNLBW, bRFRegOffsetMask);
- pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, (enum RF_RADIO_PATH)1, RF_CHNLBW, bRFRegOffsetMask);
+ pHalData->RfRegChnlVal[0] = PHY_QueryRFReg(Adapter, RF_PATH_A,
+ RF_CHNLBW, bRFRegOffsetMask);
+ pHalData->RfRegChnlVal[1] = PHY_QueryRFReg(Adapter, RF_PATH_B,
+ RF_CHNLBW, bRFRegOffsetMask);
if (!mac_on) {
_InitQueueReservedPage(Adapter);
diff --git a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
index 688f20412bca..2247d9874719 100644
--- a/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
+++ b/drivers/staging/rtl8723au/include/Hal8723APhyCfg.h
@@ -17,46 +17,9 @@
#define __INC_HAL8723PHYCFG_H__
/*--------------------------Define Parameters-------------------------------*/
-#define LOOP_LIMIT 5
-#define MAX_STALL_TIME 50 /* us */
-#define AntennaDiversityValue 0x80
-#define MAX_TXPWR_IDX_NMODE_92S 63
-#define Reset_Cnt_Limit 3
-
-
#define MAX_AGGR_NUM 0x0909
-/*--------------------------Define Parameters-------------------------------*/
-
-
/*------------------------------Define structure----------------------------*/
-enum swchnlcmdid {
- CmdID_End,
- CmdID_SetTxPowerLevel,
- CmdID_BBRegWrite10,
- CmdID_WritePortUlong,
- CmdID_WritePortUshort,
- CmdID_WritePortUchar,
- CmdID_RF_WriteReg,
-};
-
-
-/* 1. Switch channel related */
-struct swchnlcmd {
- enum swchnlcmdid CmdID;
- u32 Para1;
- u32 Para2;
- u32 msDelay;
-};
-
-enum HW90_BLOCK {
- HW90_BLOCK_MAC = 0,
- HW90_BLOCK_PHY0 = 1,
- HW90_BLOCK_PHY1 = 2,
- HW90_BLOCK_RF = 3,
- HW90_BLOCK_MAXIMUM = 4, /* Never use this */
-};
-
enum RF_RADIO_PATH {
RF_PATH_A = 0, /* Radio Path A */
RF_PATH_B = 1, /* Radio Path B */
@@ -64,7 +27,6 @@ enum RF_RADIO_PATH {
};
#define CHANNEL_MAX_NUMBER 14 /* 14 is the max channel number */
-#define CHANNEL_GROUP_MAX 3 /* ch1~3, ch4~9, ch10~14 total three groups */
enum WIRELESS_MODE {
WIRELESS_MODE_UNKNOWN = 0x00,
@@ -77,22 +39,6 @@ enum WIRELESS_MODE {
WIRELESS_MODE_AC = BIT(6)
};
-enum baseband_config_type {
- BaseBand_Config_PHY_REG = 0, /* Radio Path A */
- BaseBand_Config_AGC_TAB = 1, /* Radio Path B */
-};
-
-enum ra_offset_area {
- RA_OFFSET_LEGACY_OFDM1,
- RA_OFFSET_LEGACY_OFDM2,
- RA_OFFSET_HT_OFDM1,
- RA_OFFSET_HT_OFDM2,
- RA_OFFSET_HT_OFDM3,
- RA_OFFSET_HT_OFDM4,
- RA_OFFSET_HT_CCK,
-};
-
-
/* BB/RF related */
enum rf_type_8190p {
RF_TYPE_MIN, /* 0 */
@@ -100,7 +46,6 @@ enum rf_type_8190p {
RF_8256 = 2, /* 2 11b/g/n */
RF_8258 = 3, /* 3 11a/b/g/n RF */
RF_6052 = 4, /* 4 11b/g/n RF */
- RF_PSEUDO_11N = 5, /* 5, It is a temporality RF. */
};
struct bb_reg_define {
diff --git a/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
index 4a1f58f2982c..3771d6bb5774 100644
--- a/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
+++ b/drivers/staging/rtl8723au/include/Hal8723PwrSeq.h
@@ -39,10 +39,10 @@
* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, comments here
*/
#define RTL8723A_TRANS_CARDEMU_TO_ACT \
- {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \
- {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \
- {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \
- {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/ \
+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x20[0] = 1b'1 enable LDOA12 MACRO block for all interface*/ \
+ {0x0067, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x67[0] = 0 to disable BT_GPS_SEL pins*/ \
+ {0x0001, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 1, PWRSEQ_DELAY_MS},/*Delay 1ms*/ \
+ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), 0}, /*0x00[5] = 1b'0 release analog Ips to digital , 1:isolation*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), 0},/* disable SW LPS 0x04[10]= 0*/ \
{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},/* wait till 0x04[17] = 1 power ready*/ \
{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},/* release WLON reset 0x04[16]= 1*/ \
@@ -57,48 +57,28 @@
{0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/*0x4C[23] = 0x4E[7] = 0, switch DPDT_SEL_P output from register 0x65[2] */\
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)}, /*0x04[9] = 1 turn off MAC by HW state machine*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}, /*wait till 0x04[9] = 0 polling until return 0 to disable*/ \
- {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/ \
- {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \
+ {0x0000, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}, /*0x00[5] = 1b'1 analog Ips to digital , 1:isolation*/ \
+ {0x0020, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, /*0x20[0] = 1b'0 disable LDOA12 MACRO block*/ \
#define RTL8723A_TRANS_CARDEMU_TO_SUS \
- {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3), (BIT(4)|BIT(3))}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \
- {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \
- {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \
- {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SDIO SOP option to disable BG/MB/ACK/SWR*/ \
- {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)}, /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*Set SDIO suspend local register*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/
#define RTL8723A_TRANS_SUS_TO_CARDEMU \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, /*clear suspend enable and power down enable*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
- {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS \
- {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07 = 0x20 , SOP option to disable BG/MB*/ \
- {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \
- {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)}, /*0x04[10] = 1, enable SW LPS*/ \
- {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 1}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/ \
- {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*Set SDIO suspend local register*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}, /*wait power state to suspend*/
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)}, /*0x04[12:11] = 2b'01 enable WL suspend*/ \
+ {0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)}, /*0x48[16] = 1 to enable GPIO9 as EXT WAKEUP*/
#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU \
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3) | BIT(7), 0}, /*clear suspend enable and power down enable*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0}, /*Set SDIO suspend local register*/ \
- {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)}, /*wait power state to suspend*/\
{0x004A, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0}, /*0x48[16] = 0 to disable GPIO9 as EXT WAKEUP*/ \
- {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/\
- {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*0x23[4] = 1b'0 12H LDO enter normal mode*/ \
- {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},/*PCIe DMA start*/
-
+ {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}, /*0x04[12:11] = 2b'01enable WL suspend*/
#define RTL8723A_TRANS_CARDEMU_TO_PDN \
- {0x0023, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), BIT(4)}, /*0x23[4] = 1b'1 12H LDO enter sleep mode*/ \
- {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK|PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \
+ {0x0007, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x20}, /*0x07[7:0] = 0x20 SOP option to disable BG/MB/ACK/SWR*/ \
{0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},/* 0x04[16] = 0*/\
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)},/* 0x04[15] = 1*/
@@ -106,7 +86,6 @@
{0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},/* 0x04[15] = 0*/
#define RTL8723A_TRANS_ACT_TO_LPS \
- {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*PCIe DMA stop*/ \
{0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},/*Tx Pause*/ \
{0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \
{0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},/*Should be zero if no packet is transmitting*/ \
@@ -117,13 +96,10 @@
{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},/*Whole BB is reset*/ \
{0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x03},/*Reset MAC TRX*/ \
{0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},/*check if removed later*/ \
- {0x0093, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x00},/*When driver enter Sus/ Disable, enable LOP for BT*/ \
{0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)},/*Respond TxOK to scheduler*/
#define RTL8723A_TRANS_LPS_TO_ACT \
- {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK, PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84}, /*SDIO RPWM*/\
{0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*USB RPWM*/\
- {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84}, /*PCIe RPWM*/\
{0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS}, /*Delay*/\
{0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0}, /*. 0x08[4] = 0 switch TSF to 40M*/\
{0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK, PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0}, /*Polling 0x109[7]= 0 TSF in 40M*/\
diff --git a/drivers/staging/rtl8723au/include/osdep_intf.h b/drivers/staging/rtl8723au/include/osdep_intf.h
index 33afa62f31b1..a157eb2e78df 100644
--- a/drivers/staging/rtl8723au/include/osdep_intf.h
+++ b/drivers/staging/rtl8723au/include/osdep_intf.h
@@ -19,9 +19,6 @@
#include <osdep_service.h>
#include <drv_types.h>
-int rtw_hw_suspend23a(struct rtw_adapter *padapter);
-int rtw_hw_resume23a(struct rtw_adapter *padapter);
-
int rtw_init_drv_sw23a(struct rtw_adapter *padapter);
int rtw_free_drv_sw23a(struct rtw_adapter *padapter);
int rtw_reset_drv_sw23a(struct rtw_adapter *padapter);
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
index 05069652bae1..7add5dfe015f 100644
--- a/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
+++ b/drivers/staging/rtl8723au/include/rtl8723a_bt-coexist.h
@@ -31,8 +31,8 @@ enum rt_media_status {
void BT_SignalCompensation(struct rtw_adapter *padapter,
u8 *rssi_wifi, u8 *rssi_bt);
-void BT_HaltProcess(struct rtw_adapter * padapter);
-void BT_LpsLeave(struct rtw_adapter * padapter);
+void BT_HaltProcess(struct rtw_adapter *padapter);
+void BT_LpsLeave(struct rtw_adapter *padapter);
#define BT_HsConnectionEstablished(Adapter) false
@@ -1092,17 +1092,20 @@ enum hci_ext_bp_operation {
BTHCI_StateMachine(_Adapter, _StateToEnter, _StateCmd, _EntryNum);\
}
-void BTHCI_EventParse(struct rtw_adapter * padapter, void *pEvntData, u32 dataLen);
+void BTHCI_EventParse(struct rtw_adapter *padapter, void *pEvntData,
+ u32 dataLen);
#define BT_EventParse BTHCI_EventParse
-u8 BTHCI_HsConnectionEstablished(struct rtw_adapter * padapter);
-void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter * padapter);
-void BTHCI_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType);
-void BTHCI_StateMachine(struct rtw_adapter * padapter, u8 StateToEnter, enum hci_state_with_cmd StateCmd, u8 EntryNum);
-void BTHCI_DisconnectPeer(struct rtw_adapter * padapter, u8 EntryNum);
-void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter * padapter);
-void BTHCI_EventAMPStatusChange(struct rtw_adapter * padapter, u8 AMP_Status);
-void BTHCI_DisconnectAll(struct rtw_adapter * padapter);
-enum hci_status BTHCI_HandleHCICMD(struct rtw_adapter * padapter, struct packet_irp_hcicmd_data *pHciCmd);
+u8 BTHCI_HsConnectionEstablished(struct rtw_adapter *padapter);
+void BTHCI_UpdateBTProfileRTKToMoto(struct rtw_adapter *padapter);
+void BTHCI_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType);
+void BTHCI_StateMachine(struct rtw_adapter *padapter, u8 StateToEnter,
+ enum hci_state_with_cmd StateCmd, u8 EntryNum);
+void BTHCI_DisconnectPeer(struct rtw_adapter *padapter, u8 EntryNum);
+void BTHCI_EventNumOfCompletedDataBlocks(struct rtw_adapter *padapter);
+void BTHCI_EventAMPStatusChange(struct rtw_adapter *padapter, u8 AMP_Status);
+void BTHCI_DisconnectAll(struct rtw_adapter *padapter);
+enum hci_status BTHCI_HandleHCICMD(struct rtw_adapter *padapter,
+ struct packet_irp_hcicmd_data *pHciCmd);
/* ===== End of sync from SD7 driver COMMON/bt_hci.h ===== */
@@ -1157,9 +1160,10 @@ struct btdm_8723a_1ant {
u8 bRAChanged;
};
-void BTDM_1AntSignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt);
-void BTDM_1AntForDhcp(struct rtw_adapter * padapter);
-void BTDM_1AntBtCoexist8723A(struct rtw_adapter * padapter);
+void BTDM_1AntSignalCompensation(struct rtw_adapter *padapter,
+ u8 *rssi_wifi, u8 *rssi_bt);
+void BTDM_1AntForDhcp(struct rtw_adapter *padapter);
+void BTDM_1AntBtCoexist8723A(struct rtw_adapter *padapter);
/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87231Ant.h ===== */
@@ -1241,7 +1245,7 @@ struct btdm_8723a_2ant {
u8 btStatus;
};
-void BTDM_2AntBtCoexist8723A(struct rtw_adapter * padapter);
+void BTDM_2AntBtCoexist8723A(struct rtw_adapter *padapter);
/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc87232Ant.h ===== */
/* ===== Below this line is sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */
@@ -1310,15 +1314,17 @@ struct bt_coexist_8723a {
struct btdm_8723a_1ant btdm1Ant;
};
-void BTDM_SetFwChnlInfo(struct rtw_adapter * padapter, enum rt_media_status mstatus);
-u8 BTDM_IsWifiConnectionExist(struct rtw_adapter * padapter);
-void BTDM_SetFw3a(struct rtw_adapter * padapter, u8 byte1, u8 byte2, u8 byte3, u8 byte4, u8 byte5);
-void BTDM_QueryBtInformation(struct rtw_adapter * padapter);
-void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter * padapter, u8 type);
-void BTDM_SetSwPenaltyTxRateAdaptive(struct rtw_adapter * padapter, u8 raType);
-void BTDM_SetFwDecBtPwr(struct rtw_adapter * padapter, u8 bDecBtPwr);
-u8 BTDM_BtProfileSupport(struct rtw_adapter * padapter);
-void BTDM_LpsLeave(struct rtw_adapter * padapter);
+void BTDM_SetFwChnlInfo(struct rtw_adapter *padapter,
+ enum rt_media_status mstatus);
+u8 BTDM_IsWifiConnectionExist(struct rtw_adapter *padapter);
+void BTDM_SetFw3a(struct rtw_adapter *padapter, u8 byte1, u8 byte2, u8 byte3,
+ u8 byte4, u8 byte5);
+void BTDM_QueryBtInformation(struct rtw_adapter *padapter);
+void BTDM_SetSwRfRxLpfCorner(struct rtw_adapter *padapter, u8 type);
+void BTDM_SetSwPenaltyTxRateAdaptive(struct rtw_adapter *padapter, u8 raType);
+void BTDM_SetFwDecBtPwr(struct rtw_adapter *padapter, u8 bDecBtPwr);
+u8 BTDM_BtProfileSupport(struct rtw_adapter *padapter);
+void BTDM_LpsLeave(struct rtw_adapter *padapter);
/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtc8723.h ===== */
@@ -1340,8 +1346,9 @@ enum BT_A2DP_INDEX{
#define BTDM_ANT_BT 2
-void BTDM_SingleAnt(struct rtw_adapter * padapter, u8 bSingleAntOn, u8 bInterruptOn, u8 bMultiNAVOn);
-void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter * padapter);
+void BTDM_SingleAnt(struct rtw_adapter *padapter, u8 bSingleAntOn,
+ u8 bInterruptOn, u8 bMultiNAVOn);
+void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter *padapter);
/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr1Ant.h ===== */
@@ -1361,7 +1368,8 @@ void BTDM_CheckBTIdleChange1Ant(struct rtw_adapter * padapter);
#define BT_DACSWING_M7 2
#define BT_DACSWING_M10 3
-void BTDM_DiminishWiFi(struct rtw_adapter * Adapter, u8 bDACOn, u8 bInterruptOn, u8 DACSwingLevel, u8 bNAVOn);
+void BTDM_DiminishWiFi(struct rtw_adapter *Adapter, u8 bDACOn, u8 bInterruptOn,
+ u8 DACSwingLevel, u8 bNAVOn);
/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtcCsr2Ant.h ===== */
@@ -1534,58 +1542,63 @@ struct bt_coexist_str {
u8 fw3aVal[5];
};
-void BTDM_CheckAntSelMode(struct rtw_adapter * padapter);
-void BTDM_FwC2hBtRssi(struct rtw_adapter * padapter, u8 *tmpBuf);
+void BTDM_CheckAntSelMode(struct rtw_adapter *padapter);
+void BTDM_FwC2hBtRssi(struct rtw_adapter *padapter, u8 *tmpBuf);
#define BT_FwC2hBtRssi BTDM_FwC2hBtRssi
-void BTDM_DisplayBtCoexInfo(struct rtw_adapter * padapter);
+void BTDM_DisplayBtCoexInfo(struct rtw_adapter *padapter);
#define BT_DisplayBtCoexInfo BTDM_DisplayBtCoexInfo
-void BTDM_RejectAPAggregatedPacket(struct rtw_adapter * padapter, u8 bReject);
-u8 BTDM_IsHT40(struct rtw_adapter * padapter);
-u8 BTDM_Legacy(struct rtw_adapter * padapter);
-void BTDM_CheckWiFiState(struct rtw_adapter * padapter);
-s32 BTDM_GetRxSS(struct rtw_adapter * padapter);
-u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
-u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
-u8 BTDM_CheckCoexRSSIState(struct rtw_adapter * padapter, u8 levelNum, u8 RssiThresh, u8 RssiThresh1);
-void BTDM_Balance(struct rtw_adapter * padapter, u8 bBalanceOn, u8 ms0, u8 ms1);
-void BTDM_AGCTable(struct rtw_adapter * padapter, u8 type);
-void BTDM_BBBackOffLevel(struct rtw_adapter * padapter, u8 type);
-void BTDM_FWCoexAllOff(struct rtw_adapter * padapter);
-void BTDM_SWCoexAllOff(struct rtw_adapter * padapter);
-void BTDM_HWCoexAllOff(struct rtw_adapter * padapter);
-void BTDM_CoexAllOff(struct rtw_adapter * padapter);
-void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter * padapter);
-void BTDM_SignalCompensation(struct rtw_adapter * padapter, u8 *rssi_wifi, u8 *rssi_bt);
-void BTDM_UpdateCoexState(struct rtw_adapter * padapter);
-u8 BTDM_IsSameCoexistState(struct rtw_adapter * padapter);
-void BTDM_PWDBMonitor(struct rtw_adapter * padapter);
-u8 BTDM_IsBTBusy(struct rtw_adapter * padapter);
+void BTDM_RejectAPAggregatedPacket(struct rtw_adapter *padapter, u8 bReject);
+u8 BTDM_IsHT40(struct rtw_adapter *padapter);
+u8 BTDM_Legacy(struct rtw_adapter *padapter);
+void BTDM_CheckWiFiState(struct rtw_adapter *padapter);
+s32 BTDM_GetRxSS(struct rtw_adapter *padapter);
+u8 BTDM_CheckCoexBcnRssiState(struct rtw_adapter *padapter, u8 levelNum,
+ u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_CheckCoexRSSIState1(struct rtw_adapter *padapter, u8 levelNum,
+ u8 RssiThresh, u8 RssiThresh1);
+u8 BTDM_CheckCoexRSSIState(struct rtw_adapter *padapter, u8 levelNum,
+ u8 RssiThresh, u8 RssiThresh1);
+void BTDM_Balance(struct rtw_adapter *padapter, u8 bBalanceOn, u8 ms0, u8 ms1);
+void BTDM_AGCTable(struct rtw_adapter *padapter, u8 type);
+void BTDM_BBBackOffLevel(struct rtw_adapter *padapter, u8 type);
+void BTDM_FWCoexAllOff(struct rtw_adapter *padapter);
+void BTDM_SWCoexAllOff(struct rtw_adapter *padapter);
+void BTDM_HWCoexAllOff(struct rtw_adapter *padapter);
+void BTDM_CoexAllOff(struct rtw_adapter *padapter);
+void BTDM_TurnOffBtCoexistBeforeEnterIPS(struct rtw_adapter *padapter);
+void BTDM_SignalCompensation(struct rtw_adapter *padapter, u8 *rssi_wifi,
+ u8 *rssi_bt);
+void BTDM_UpdateCoexState(struct rtw_adapter *padapter);
+u8 BTDM_IsSameCoexistState(struct rtw_adapter *padapter);
+void BTDM_PWDBMonitor(struct rtw_adapter *padapter);
+u8 BTDM_IsBTBusy(struct rtw_adapter *padapter);
#define BT_IsBtBusy BTDM_IsBTBusy
-u8 BTDM_IsWifiBusy(struct rtw_adapter * padapter);
-u8 BTDM_IsCoexistStateChanged(struct rtw_adapter * padapter);
-u8 BTDM_IsWifiUplink(struct rtw_adapter * padapter);
-u8 BTDM_IsWifiDownlink(struct rtw_adapter * padapter);
-u8 BTDM_IsBTHSMode(struct rtw_adapter * padapter);
-u8 BTDM_IsBTUplink(struct rtw_adapter * padapter);
-u8 BTDM_IsBTDownlink(struct rtw_adapter * padapter);
-void BTDM_AdjustForBtOperation(struct rtw_adapter * padapter);
-void BTDM_ForHalt(struct rtw_adapter * padapter);
-void BTDM_WifiScanNotify(struct rtw_adapter * padapter, u8 scanType);
-void BTDM_WifiAssociateNotify(struct rtw_adapter * padapter, u8 action);
-void BTDM_MediaStatusNotify(struct rtw_adapter * padapter, enum rt_media_status mstatus);
-void BTDM_ForDhcp(struct rtw_adapter * padapter);
-void BTDM_ResetActionProfileState(struct rtw_adapter * padapter);
-void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter * padapter, u8 antNum);
+u8 BTDM_IsWifiBusy(struct rtw_adapter *padapter);
+u8 BTDM_IsCoexistStateChanged(struct rtw_adapter *padapter);
+u8 BTDM_IsWifiUplink(struct rtw_adapter *padapter);
+u8 BTDM_IsWifiDownlink(struct rtw_adapter *padapter);
+u8 BTDM_IsBTHSMode(struct rtw_adapter *padapter);
+u8 BTDM_IsBTUplink(struct rtw_adapter *padapter);
+u8 BTDM_IsBTDownlink(struct rtw_adapter *padapter);
+void BTDM_AdjustForBtOperation(struct rtw_adapter *padapter);
+void BTDM_ForHalt(struct rtw_adapter *padapter);
+void BTDM_WifiScanNotify(struct rtw_adapter *padapter, u8 scanType);
+void BTDM_WifiAssociateNotify(struct rtw_adapter *padapter, u8 action);
+void BTDM_MediaStatusNotify(struct rtw_adapter *padapter,
+ enum rt_media_status mstatus);
+void BTDM_ForDhcp(struct rtw_adapter *padapter);
+void BTDM_ResetActionProfileState(struct rtw_adapter *padapter);
+void BTDM_SetBtCoexCurrAntNum(struct rtw_adapter *padapter, u8 antNum);
#define BT_SetBtCoexCurrAntNum BTDM_SetBtCoexCurrAntNum
-u8 BTDM_IsActionSCO(struct rtw_adapter * padapter);
-u8 BTDM_IsActionHID(struct rtw_adapter * padapter);
-u8 BTDM_IsActionA2DP(struct rtw_adapter * padapter);
-u8 BTDM_IsActionPAN(struct rtw_adapter * padapter);
-u8 BTDM_IsActionHIDA2DP(struct rtw_adapter * padapter);
-u8 BTDM_IsActionHIDPAN(struct rtw_adapter * padapter);
-u8 BTDM_IsActionPANA2DP(struct rtw_adapter * padapter);
-u32 BTDM_BtTxRxCounterH(struct rtw_adapter * padapter);
-u32 BTDM_BtTxRxCounterL(struct rtw_adapter * padapter);
+u8 BTDM_IsActionSCO(struct rtw_adapter *padapter);
+u8 BTDM_IsActionHID(struct rtw_adapter *padapter);
+u8 BTDM_IsActionA2DP(struct rtw_adapter *padapter);
+u8 BTDM_IsActionPAN(struct rtw_adapter *padapter);
+u8 BTDM_IsActionHIDA2DP(struct rtw_adapter *padapter);
+u8 BTDM_IsActionHIDPAN(struct rtw_adapter *padapter);
+u8 BTDM_IsActionPANA2DP(struct rtw_adapter *padapter);
+u32 BTDM_BtTxRxCounterH(struct rtw_adapter *padapter);
+u32 BTDM_BtTxRxCounterL(struct rtw_adapter *padapter);
/* ===== End of sync from SD7 driver HAL/BTCoexist/HalBtCoexist.h ===== */
@@ -1593,14 +1606,14 @@ u32 BTDM_BtTxRxCounterL(struct rtw_adapter * padapter);
#define RTS_CTS_NO_LEN_LIMIT 0
-u8 HALBT_GetPGAntNum(struct rtw_adapter * padapter);
+u8 HALBT_GetPGAntNum(struct rtw_adapter *padapter);
#define BT_GetPGAntNum HALBT_GetPGAntNum
-void HALBT_SetKey(struct rtw_adapter * padapter, u8 EntryNum);
-void HALBT_RemoveKey(struct rtw_adapter * padapter, u8 EntryNum);
-u8 HALBT_IsBTExist(struct rtw_adapter * padapter);
+void HALBT_SetKey(struct rtw_adapter *padapter, u8 EntryNum);
+void HALBT_RemoveKey(struct rtw_adapter *padapter, u8 EntryNum);
+u8 HALBT_IsBTExist(struct rtw_adapter *padapter);
#define BT_IsBtExist HALBT_IsBTExist
-u8 HALBT_BTChipType(struct rtw_adapter * padapter);
-void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter * padapter);
+u8 HALBT_BTChipType(struct rtw_adapter *padapter);
+void HALBT_SetRtsCtsNoLenLimit(struct rtw_adapter *padapter);
/* ===== End of sync from SD7 driver HAL/HalBT.c ===== */
diff --git a/drivers/staging/rtl8723au/include/rtl8723a_recv.h b/drivers/staging/rtl8723au/include/rtl8723a_recv.h
index 0177bbc1c1cf..875d37b3b94c 100644
--- a/drivers/staging/rtl8723au/include/rtl8723a_recv.h
+++ b/drivers/staging/rtl8723au/include/rtl8723a_recv.h
@@ -56,8 +56,8 @@ struct interrupt_msg_format {
unsigned int MSG_EX;
};
-int rtl8723au_init_recv_priv(struct rtw_adapter * padapter);
-void rtl8723au_free_recv_priv(struct rtw_adapter * padapter);
+int rtl8723au_init_recv_priv(struct rtw_adapter *padapter);
+void rtl8723au_free_recv_priv(struct rtw_adapter *padapter);
void rtl8723a_process_phy_info(struct rtw_adapter *padapter, void *prframe);
void update_recvframe_attrib(struct recv_frame *precvframe, struct recv_stat *prxstat);
void update_recvframe_phyinfo(struct recv_frame *precvframe, struct phy_stat *pphy_info);
diff --git a/drivers/staging/rtl8723au/include/rtw_cmd.h b/drivers/staging/rtl8723au/include/rtw_cmd.h
index 71044107d13b..775dcdc1e7b9 100644
--- a/drivers/staging/rtl8723au/include/rtw_cmd.h
+++ b/drivers/staging/rtl8723au/include/rtw_cmd.h
@@ -99,7 +99,6 @@ int rtw_init_cmd_priv23a(struct cmd_priv *pcmdpriv);
u32 rtw_init_evt_priv23a (struct evt_priv *pevtpriv);
void rtw_free_evt_priv23a (struct evt_priv *pevtpriv);
-void rtw_cmd_clr_isr23a(struct cmd_priv *pcmdpriv);
void rtw_evt_notify_isr(struct evt_priv *pevtpriv);
enum rtw_drvextra_cmd_id
@@ -689,10 +688,10 @@ int rtw_disassoc_cmd23a(struct rtw_adapter *padapter, u32 deauth_timeout_ms, boo
int rtw_setopmode_cmd23a(struct rtw_adapter *padapter, enum nl80211_iftype ifmode);
int rtw_setdatarate_cmd(struct rtw_adapter *padapter, u8 *rateset);
int rtw_setbasicrate_cmd(struct rtw_adapter *padapter, u8 *rateset);
-int rtw_setbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 val);
-int rtw_setrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u32 val);
-int rtw_getbbreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval);
-int rtw_getrfreg_cmd(struct rtw_adapter * padapter, u8 offset, u8 * pval);
+int rtw_setbbreg_cmd(struct rtw_adapter *padapter, u8 offset, u8 val);
+int rtw_setrfreg_cmd(struct rtw_adapter *padapter, u8 offset, u32 val);
+int rtw_getbbreg_cmd(struct rtw_adapter *padapter, u8 offset, u8 *pval);
+int rtw_getrfreg_cmd(struct rtw_adapter *padapter, u8 offset, u8 *pval);
int rtw_setrfintfs_cmd(struct rtw_adapter *padapter, u8 mode);
int rtw_setrttbl_cmd(struct rtw_adapter *padapter, struct setratable_parm *prate_table);
int rtw_getrttbl_cmd(struct rtw_adapter *padapter, struct getratable_rsp *pval);
@@ -713,7 +712,6 @@ int rtw_ps_cmd23a(struct rtw_adapter*padapter);
int rtw_chk_hi_queue_cmd23a(struct rtw_adapter*padapter);
#endif
-int rtw_set_ch_cmd23a(struct rtw_adapter*padapter, u8 ch, u8 bw, u8 ch_offset, u8 enqueue);
int rtw_set_chplan_cmd(struct rtw_adapter*padapter, u8 chplan, u8 enqueue);
int rtw_led_blink_cmd(struct rtw_adapter*padapter, struct led_8723a *pLed);
int rtw_set_csa_cmd(struct rtw_adapter*padapter, u8 new_ch_no);
diff --git a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
index 51dba1fa4c5d..ffb37b252fc1 100644
--- a/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
+++ b/drivers/staging/rtl8723au/include/rtw_mlme_ext.h
@@ -509,7 +509,7 @@ int rtw_check_bcn_info23a(struct rtw_adapter *Adapter,
struct ieee80211_mgmt *mgmt, u32 packet_len);
void update_IOT_info23a(struct rtw_adapter *padapter);
void update_capinfo23a(struct rtw_adapter *Adapter, u16 updateCap);
-void update_wireless_mode23a(struct rtw_adapter * padapter);
+void update_wireless_mode23a(struct rtw_adapter *padapter);
void update_tx_basic_rate23a(struct rtw_adapter *padapter, u8 modulation);
void update_bmc_sta_support_rate23a(struct rtw_adapter *padapter, u32 mac_id);
int update_sta_support_rate23a(struct rtw_adapter *padapter, u8 *pvar_ie,
diff --git a/drivers/staging/rtl8723au/include/wifi.h b/drivers/staging/rtl8723au/include/wifi.h
index fd3da3b5cf31..25d573c3e232 100644
--- a/drivers/staging/rtl8723au/include/wifi.h
+++ b/drivers/staging/rtl8723au/include/wifi.h
@@ -26,9 +26,9 @@
------------------------------------------------------------------------------*/
struct AC_param {
- unsigned char ACI_AIFSN;
- unsigned char CW;
- unsigned short TXOP_limit;
+ u8 ACI_AIFSN;
+ u8 CW;
+ __le16 TXOP_limit;
} __packed;
struct WMM_para_element {
@@ -38,10 +38,10 @@ struct WMM_para_element {
} __packed;
struct ADDBA_request {
- unsigned char dialog_token;
- unsigned short BA_para_set;
- unsigned short BA_timeout_value;
- unsigned short BA_starting_seqctrl;
+ u8 dialog_token;
+ __le16 BA_para_set;
+ __le16 BA_timeout_value;
+ __le16 BA_starting_seqctrl;
} __packed;
diff --git a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
index 82a8c06ab347..537bd8214efe 100644
--- a/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
+++ b/drivers/staging/rtl8723au/os_dep/ioctl_cfg80211.c
@@ -1091,17 +1091,17 @@ static int cfg80211_rtw_get_station(struct wiphy *wiphy,
goto exit;
}
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
sinfo->signal = translate_percentage_to_dbm(padapter->recvpriv.
signal_strength);
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
sinfo->txrate.legacy = rtw_get_cur_max_rate(padapter);
- sinfo->filled |= STATION_INFO_RX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_RX_PACKETS);
sinfo->rx_packets = sta_rx_data_pkts(psta);
- sinfo->filled |= STATION_INFO_TX_PACKETS;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_PACKETS);
sinfo->tx_packets = psta->sta_stats.tx_pkts;
}
@@ -1468,9 +1468,8 @@ static int rtw_cfg80211_set_wpa_version(struct security_priv *psecuritypriv,
return 0;
}
- if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2)) {
+ if (wpa_version & (NL80211_WPA_VERSION_1 | NL80211_WPA_VERSION_2))
psecuritypriv->ndisauthtype = Ndis802_11AuthModeWPAPSK;
- }
/*
if (wpa_version & NL80211_WPA_VERSION_2)
@@ -2363,7 +2362,7 @@ void rtw_cfg80211_indicate_sta_assoc(struct rtw_adapter *padapter,
ie_offset = offsetof(struct ieee80211_mgmt,
u.reassoc_req.variable);
- sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
+ sinfo.filled = 0;
sinfo.assoc_req_ies = pmgmt_frame + ie_offset;
sinfo.assoc_req_ies_len = frame_len - ie_offset;
cfg80211_new_sta(ndev, hdr->addr2, &sinfo, GFP_ATOMIC);
diff --git a/drivers/staging/rtl8723au/os_dep/os_intfs.c b/drivers/staging/rtl8723au/os_dep/os_intfs.c
index 9966d16342b3..1b23eb13222b 100644
--- a/drivers/staging/rtl8723au/os_dep/os_intfs.c
+++ b/drivers/staging/rtl8723au/os_dep/os_intfs.c
@@ -91,7 +91,7 @@ static int rtw_bt_iso = 2;/* 0:Low, 1:High, 2:From Efuse */
/* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter, 4.Busy, 5.OtherBusy */
static int rtw_bt_sco = 3;
/* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
-static int rtw_bt_ampdu = 1 ;
+static int rtw_bt_ampdu = 1;
#endif
/* 0:Reject AP's Add BA req, 1:Accept AP's Add BA req. */
diff --git a/drivers/staging/rtl8723au/os_dep/usb_intf.c b/drivers/staging/rtl8723au/os_dep/usb_intf.c
index 373a617ace54..05755b870a5f 100644
--- a/drivers/staging/rtl8723au/os_dep/usb_intf.c
+++ b/drivers/staging/rtl8723au/os_dep/usb_intf.c
@@ -80,11 +80,9 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
struct usb_config_descriptor *pconf_desc;
struct usb_host_interface *phost_iface;
struct usb_interface_descriptor *piface_desc;
- struct usb_host_endpoint *phost_endp;
struct usb_endpoint_descriptor *pendp_desc;
- struct usb_device *pusbd;
- int i;
- int status = _FAIL;
+ struct usb_device *pusbd;
+ int i, status = _FAIL;
pdvobjpriv = kzalloc(sizeof(*pdvobjpriv), GFP_KERNEL);
if (!pdvobjpriv)
@@ -114,42 +112,38 @@ static struct dvobj_priv *usb_dvobj_init(struct usb_interface *usb_intf)
pdvobjpriv->nr_endpoint = piface_desc->bNumEndpoints;
for (i = 0; i < pdvobjpriv->nr_endpoint; i++) {
- phost_endp = phost_iface->endpoint + i;
- if (phost_endp) {
- pendp_desc = &phost_endp->desc;
-
- DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i);
- DBG_8723A("bLength =%x\n", pendp_desc->bLength);
- DBG_8723A("bDescriptorType =%x\n",
- pendp_desc->bDescriptorType);
- DBG_8723A("bEndpointAddress =%x\n",
- pendp_desc->bEndpointAddress);
- DBG_8723A("wMaxPacketSize =%d\n",
- le16_to_cpu(pendp_desc->wMaxPacketSize));
- DBG_8723A("bInterval =%x\n", pendp_desc->bInterval);
-
- if (usb_endpoint_is_bulk_in(pendp_desc)) {
- DBG_8723A("usb_endpoint_is_bulk_in = %x\n",
- usb_endpoint_num(pendp_desc));
- pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
- usb_endpoint_num(pendp_desc);
- pdvobjpriv->RtNumInPipes++;
- } else if (usb_endpoint_is_int_in(pendp_desc)) {
- DBG_8723A("usb_endpoint_is_int_in = %x, Interval = %x\n",
- usb_endpoint_num(pendp_desc),
- pendp_desc->bInterval);
- pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
- usb_endpoint_num(pendp_desc);
- pdvobjpriv->RtNumInPipes++;
- } else if (usb_endpoint_is_bulk_out(pendp_desc)) {
- DBG_8723A("usb_endpoint_is_bulk_out = %x\n",
- usb_endpoint_num(pendp_desc));
- pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] =
- usb_endpoint_num(pendp_desc);
- pdvobjpriv->RtNumOutPipes++;
- }
- pdvobjpriv->ep_num[i] = usb_endpoint_num(pendp_desc);
+ pendp_desc = &phost_iface->endpoint[i].desc;
+
+ DBG_8723A("\nusb_endpoint_descriptor(%d):\n", i);
+ DBG_8723A("bLength =%x\n", pendp_desc->bLength);
+ DBG_8723A("bDescriptorType =%x\n", pendp_desc->bDescriptorType);
+ DBG_8723A("bEndpointAddress =%x\n",
+ pendp_desc->bEndpointAddress);
+ DBG_8723A("wMaxPacketSize =%d\n",
+ le16_to_cpu(pendp_desc->wMaxPacketSize));
+ DBG_8723A("bInterval =%x\n", pendp_desc->bInterval);
+
+ if (usb_endpoint_is_bulk_in(pendp_desc)) {
+ DBG_8723A("usb_endpoint_is_bulk_in = %x\n",
+ usb_endpoint_num(pendp_desc));
+ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
+ usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumInPipes++;
+ } else if (usb_endpoint_is_int_in(pendp_desc)) {
+ DBG_8723A("usb_endpoint_is_int_in = %x, Interval = "
+ "%x\n", usb_endpoint_num(pendp_desc),
+ pendp_desc->bInterval);
+ pdvobjpriv->RtInPipe[pdvobjpriv->RtNumInPipes] =
+ usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumInPipes++;
+ } else if (usb_endpoint_is_bulk_out(pendp_desc)) {
+ DBG_8723A("usb_endpoint_is_bulk_out = %x\n",
+ usb_endpoint_num(pendp_desc));
+ pdvobjpriv->RtOutPipe[pdvobjpriv->RtNumOutPipes] =
+ usb_endpoint_num(pendp_desc);
+ pdvobjpriv->RtNumOutPipes++;
}
+ pdvobjpriv->ep_num[i] = usb_endpoint_num(pendp_desc);
}
DBG_8723A("nr_endpoint =%d, in_num =%d, out_num =%d\n\n",
pdvobjpriv->nr_endpoint, pdvobjpriv->RtNumInPipes,
@@ -273,104 +267,6 @@ static void rtw_dev_unload(struct rtw_adapter *padapter)
RT_TRACE(_module_hci_intfs_c_, _drv_err_, ("-rtw_dev_unload\n"));
}
-int rtw_hw_suspend23a(struct rtw_adapter *padapter)
-{
- struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- struct net_device *pnetdev = padapter->pnetdev;
- struct mlme_priv *pmlmepriv = &padapter->mlmepriv;
-
- if ((!padapter->bup) || (padapter->bDriverStopped) ||
- (padapter->bSurpriseRemoved)) {
- DBG_8723A("padapter->bup =%d bDriverStopped =%d bSurpriseRemoved = %d\n",
- padapter->bup, padapter->bDriverStopped,
- padapter->bSurpriseRemoved);
- goto error_exit;
- }
-
- if (padapter) { /* system suspend */
- LeaveAllPowerSaveMode23a(padapter);
-
- DBG_8723A("==> rtw_hw_suspend23a\n");
- down(&pwrpriv->lock);
- pwrpriv->bips_processing = true;
- /* padapter->net_closed = true; */
- /* s1. */
- if (pnetdev) {
- netif_carrier_off(pnetdev);
- netif_tx_stop_all_queues(pnetdev);
- }
-
- /* s2. */
- rtw_disassoc_cmd23a(padapter, 500, false);
-
- /* s2-2. indicate disconnect to os */
- /* rtw_indicate_disconnect23a(padapter); */
- if (check_fwstate(pmlmepriv, _FW_LINKED)) {
- _clr_fwstate_(pmlmepriv, _FW_LINKED);
-
- rtw_os_indicate_disconnect23a(padapter);
-
- /* donnot enqueue cmd */
- rtw_lps_ctrl_wk_cmd23a(padapter,
- LPS_CTRL_DISCONNECT, 0);
- }
- /* s2-3. */
- rtw_free_assoc_resources23a(padapter, 1);
-
- /* s2-4. */
- rtw_free_network_queue23a(padapter);
- rtw_ips_dev_unload23a(padapter);
- pwrpriv->rf_pwrstate = rf_off;
- pwrpriv->bips_processing = false;
- up(&pwrpriv->lock);
- } else {
- goto error_exit;
- }
- return 0;
-error_exit:
- DBG_8723A("%s, failed\n", __func__);
- return -1;
-}
-
-int rtw_hw_resume23a(struct rtw_adapter *padapter)
-{
- struct pwrctrl_priv *pwrpriv = &padapter->pwrctrlpriv;
- struct net_device *pnetdev = padapter->pnetdev;
-
- if (padapter) { /* system resume */
- DBG_8723A("==> rtw_hw_resume23a\n");
- down(&pwrpriv->lock);
- pwrpriv->bips_processing = true;
- rtw_reset_drv_sw23a(padapter);
-
- if (pm_netdev_open23a(pnetdev, false)) {
- up(&pwrpriv->lock);
- goto error_exit;
- }
-
- netif_device_attach(pnetdev);
- netif_carrier_on(pnetdev);
-
- if (!rtw_netif_queue_stopped(pnetdev))
- netif_tx_start_all_queues(pnetdev);
- else
- netif_tx_wake_all_queues(pnetdev);
-
- pwrpriv->bkeepfwalive = false;
-
- pwrpriv->rf_pwrstate = rf_on;
- pwrpriv->bips_processing = false;
-
- up(&pwrpriv->lock);
- } else {
- goto error_exit;
- }
- return 0;
-error_exit:
- DBG_8723A("%s, Open net dev failed\n", __func__);
- return -1;
-}
-
static int rtw_suspend(struct usb_interface *pusb_intf, pm_message_t message)
{
struct dvobj_priv *dvobj = usb_get_intfdata(pusb_intf);
diff --git a/drivers/staging/rts5208/ms.c b/drivers/staging/rts5208/ms.c
index b4612fb615f6..a47a19135d49 100644
--- a/drivers/staging/rts5208/ms.c
+++ b/drivers/staging/rts5208/ms.c
@@ -781,7 +781,7 @@ static int msxc_change_power(struct rtsx_chip *chip, u8 mode)
buf[4] = 0;
buf[5] = 0;
- retval = ms_write_bytes(chip, PRO_WRITE_REG , 6, NO_WAIT_INT, buf, 6);
+ retval = ms_write_bytes(chip, PRO_WRITE_REG, 6, NO_WAIT_INT, buf, 6);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
@@ -1291,7 +1291,7 @@ static int ms_write_extra_data(struct rtsx_chip *chip,
for (i = 6; i < MS_EXTRA_SIZE + 6; i++)
data[i] = buf[i - 6];
- retval = ms_write_bytes(chip, WRITE_REG , (6+MS_EXTRA_SIZE),
+ retval = ms_write_bytes(chip, WRITE_REG, (6 + MS_EXTRA_SIZE),
NO_WAIT_INT, data, 16);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
@@ -1342,7 +1342,7 @@ static int ms_read_page(struct rtsx_chip *chip, u16 block_addr, u8 page_num)
data[4] = 0x20;
data[5] = page_num;
- retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT, data, 6);
+ retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT, data, 6);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
@@ -1619,7 +1619,7 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
data[4] = 0x20;
data[5] = i;
- retval = ms_write_bytes(chip, WRITE_REG , 6, NO_WAIT_INT,
+ retval = ms_write_bytes(chip, WRITE_REG, 6, NO_WAIT_INT,
data, 6);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
@@ -1695,7 +1695,7 @@ static int ms_copy_page(struct rtsx_chip *chip, u16 old_blk, u16 new_blk,
}
retval = ms_set_rw_reg_addr(chip, OverwriteFlag,
- MS_EXTRA_SIZE, SystemParm, (6+MS_EXTRA_SIZE));
+ MS_EXTRA_SIZE, SystemParm, (6 + MS_EXTRA_SIZE));
ms_set_err_code(chip, MS_NO_ERROR);
@@ -1988,7 +1988,7 @@ RE_SEARCH:
RTSX_WRITE_REG(chip, PPBUF_BASE2, 0xFF, 0x88);
RTSX_WRITE_REG(chip, PPBUF_BASE2 + 1, 0xFF, 0);
- retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG , 1,
+ retval = ms_transfer_tpc(chip, MS_TM_WRITE_BYTES, WRITE_REG, 1,
NO_WAIT_INT);
if (retval != STATUS_SUCCESS)
TRACE_RET(chip, STATUS_FAIL);
diff --git a/drivers/staging/rts5208/rtsx_transport.c b/drivers/staging/rts5208/rtsx_transport.c
index 756a9687c293..dab1995d1a6a 100644
--- a/drivers/staging/rts5208/rtsx_transport.c
+++ b/drivers/staging/rts5208/rtsx_transport.c
@@ -271,7 +271,7 @@ int rtsx_send_cmd(struct rtsx_chip *chip, u8 card, int timeout)
/* Wait for TRANS_OK_INT */
timeleft = wait_for_completion_interruptible_timeout(
- &trans_done, timeout * HZ / 1000);
+ &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
dev_dbg(rtsx_dev(chip), "chip->int_reg = 0x%x\n",
chip->int_reg);
@@ -431,7 +431,7 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card,
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
- &trans_done, timeout * HZ / 1000);
+ &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
__func__, __LINE__);
@@ -455,7 +455,7 @@ static int rtsx_transfer_sglist_adma_partial(struct rtsx_chip *chip, u8 card,
init_completion(&trans_done);
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
- &trans_done, timeout * HZ / 1000);
+ &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
__func__, __LINE__);
@@ -575,7 +575,7 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card,
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
- &trans_done, timeout * HZ / 1000);
+ &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
__func__, __LINE__);
@@ -602,7 +602,7 @@ static int rtsx_transfer_sglist_adma(struct rtsx_chip *chip, u8 card,
init_completion(&trans_done);
spin_unlock_irq(&rtsx->reg_lock);
timeleft = wait_for_completion_interruptible_timeout(
- &trans_done, timeout * HZ / 1000);
+ &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
__func__, __LINE__);
@@ -688,7 +688,7 @@ static int rtsx_transfer_buf(struct rtsx_chip *chip, u8 card, void *buf,
/* Wait for TRANS_OK_INT */
timeleft = wait_for_completion_interruptible_timeout(
- &trans_done, timeout * HZ / 1000);
+ &trans_done, msecs_to_jiffies(timeout));
if (timeleft <= 0) {
dev_dbg(rtsx_dev(chip), "Timeout (%s %d)\n",
__func__, __LINE__);
diff --git a/drivers/staging/skein/skein_block.c b/drivers/staging/skein/skein_block.c
index 66261ab25c88..9bd69ce3be00 100644
--- a/drivers/staging/skein/skein_block.c
+++ b/drivers/staging/skein/skein_block.c
@@ -82,10 +82,7 @@ do { \
} while (0)
#else
/* looping version */
-#define R256(p0, p1, p2, p3, ROT, r_num) \
-do { \
- ROUND256(p0, p1, p2, p3, ROT, r_num); \
-} while (0)
+#define R256(p0, p1, p2, p3, ROT, r_num) ROUND256(p0, p1, p2, p3, ROT, r_num)
#define I256(R) \
do { \
@@ -174,9 +171,7 @@ do { \
#else /* looping version */
#define R512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \
-do { \
- ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num); \
-} while (0)
+ ROUND512(p0, p1, p2, p3, p4, p5, p6, p7, ROT, r_num) \
#define I512(R) \
do { \
@@ -263,10 +258,8 @@ do { \
#if SKEIN_UNROLL_1024 == 0
#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \
ROT, rn) \
-do { \
ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \
- pF, ROT, rn); \
-} while (0)
+ pF, ROT, rn) \
#define I1024(R) \
do { \
@@ -291,10 +284,8 @@ do { \
#else /* looping version */
#define R1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, pF, \
ROT, rn) \
-do { \
ROUND1024(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, pA, pB, pC, pD, pE, \
- pF, ROT, rn); \
-} while (0)
+ pF, ROT, rn) \
#define I1024(R) \
do { \
diff --git a/drivers/staging/skein/skein_generic.c b/drivers/staging/skein/skein_generic.c
index 85bd7d0168b0..899078f1b8bc 100644
--- a/drivers/staging/skein/skein_generic.c
+++ b/drivers/staging/skein/skein_generic.c
@@ -191,7 +191,6 @@ static int __init skein_generic_init(void)
return 0;
-
unreg512:
crypto_unregister_shash(&alg512);
unreg256:
diff --git a/drivers/staging/sm7xxfb/Kconfig b/drivers/staging/sm7xxfb/Kconfig
new file mode 100644
index 000000000000..e2922ae3a3ee
--- /dev/null
+++ b/drivers/staging/sm7xxfb/Kconfig
@@ -0,0 +1,13 @@
+config FB_SM7XX
+ tristate "Silicon Motion SM7XX framebuffer support"
+ depends on FB && PCI
+ select FB_CFB_FILLRECT
+ select FB_CFB_COPYAREA
+ select FB_CFB_IMAGEBLIT
+ help
+ Frame buffer driver for the Silicon Motion SM710, SM712, SM721
+ and SM722 chips.
+
+ This driver is also available as a module. The module will be
+ called sm7xxfb. If you want to compile it as a module, say M
+ here and read <file:Documentation/kbuild/modules.txt>.
diff --git a/drivers/staging/sm7xxfb/Makefile b/drivers/staging/sm7xxfb/Makefile
new file mode 100644
index 000000000000..48f471cf9f36
--- /dev/null
+++ b/drivers/staging/sm7xxfb/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_FB_SM7XX) += sm7xxfb.o
diff --git a/drivers/staging/sm7xxfb/TODO b/drivers/staging/sm7xxfb/TODO
new file mode 100644
index 000000000000..7cb0b242f204
--- /dev/null
+++ b/drivers/staging/sm7xxfb/TODO
@@ -0,0 +1,12 @@
+TODO:
+- Dual head support
+- 2D acceleration support
+- use kernel coding style
+- refine the code and remove unused code
+- move it to drivers/video/fbdev/sm7xxfb.c
+
+Please send any patches to
+ Greg Kroah-Hartman <greg@kroah.com>
+ Sudip Mukherjee <sudipm.mukherjee@gmail.com>
+ Teddy Wang <teddy.wang@siliconmotion.com>
+ Sudip Mukherjee <sudip@vectorindia.org>
diff --git a/drivers/staging/sm7xxfb/sm7xx.h b/drivers/staging/sm7xxfb/sm7xx.h
new file mode 100644
index 000000000000..7cc1896938b6
--- /dev/null
+++ b/drivers/staging/sm7xxfb/sm7xx.h
@@ -0,0 +1,779 @@
+/*
+ * Silicon Motion SM712 frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ * Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@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.
+ */
+
+#define NR_PALETTE 256
+
+#define FB_ACCEL_SMI_LYNX 88
+
+#define SCREEN_X_RES 1024
+#define SCREEN_Y_RES 600
+#define SCREEN_BPP 16
+
+/*Assume SM712 graphics chip has 4MB VRAM */
+#define SM712_VIDEOMEMORYSIZE 0x00400000
+/*Assume SM722 graphics chip has 8MB VRAM */
+#define SM722_VIDEOMEMORYSIZE 0x00800000
+
+#define dac_reg (0x3c8)
+#define dac_val (0x3c9)
+
+extern void __iomem *smtc_regbaseaddress;
+#define smtc_mmiowb(dat, reg) writeb(dat, smtc_regbaseaddress + reg)
+#define smtc_mmioww(dat, reg) writew(dat, smtc_regbaseaddress + reg)
+#define smtc_mmiowl(dat, reg) writel(dat, smtc_regbaseaddress + reg)
+
+#define smtc_mmiorb(reg) readb(smtc_regbaseaddress + reg)
+#define smtc_mmiorw(reg) readw(smtc_regbaseaddress + reg)
+#define smtc_mmiorl(reg) readl(smtc_regbaseaddress + reg)
+
+#define SIZE_SR00_SR04 (0x04 - 0x00 + 1)
+#define SIZE_SR10_SR24 (0x24 - 0x10 + 1)
+#define SIZE_SR30_SR75 (0x75 - 0x30 + 1)
+#define SIZE_SR80_SR93 (0x93 - 0x80 + 1)
+#define SIZE_SRA0_SRAF (0xAF - 0xA0 + 1)
+#define SIZE_GR00_GR08 (0x08 - 0x00 + 1)
+#define SIZE_AR00_AR14 (0x14 - 0x00 + 1)
+#define SIZE_CR00_CR18 (0x18 - 0x00 + 1)
+#define SIZE_CR30_CR4D (0x4D - 0x30 + 1)
+#define SIZE_CR90_CRA7 (0xA7 - 0x90 + 1)
+#define SIZE_VPR (0x6C + 1)
+#define SIZE_DPR (0x44 + 1)
+
+static inline void smtc_crtcw(int reg, int val)
+{
+ smtc_mmiowb(reg, 0x3d4);
+ smtc_mmiowb(val, 0x3d5);
+}
+
+static inline unsigned int smtc_crtcr(int reg)
+{
+ smtc_mmiowb(reg, 0x3d4);
+ return smtc_mmiorb(0x3d5);
+}
+
+static inline void smtc_grphw(int reg, int val)
+{
+ smtc_mmiowb(reg, 0x3ce);
+ smtc_mmiowb(val, 0x3cf);
+}
+
+static inline unsigned int smtc_grphr(int reg)
+{
+ smtc_mmiowb(reg, 0x3ce);
+ return smtc_mmiorb(0x3cf);
+}
+
+static inline void smtc_attrw(int reg, int val)
+{
+ smtc_mmiorb(0x3da);
+ smtc_mmiowb(reg, 0x3c0);
+ smtc_mmiorb(0x3c1);
+ smtc_mmiowb(val, 0x3c0);
+}
+
+static inline void smtc_seqw(int reg, int val)
+{
+ smtc_mmiowb(reg, 0x3c4);
+ smtc_mmiowb(val, 0x3c5);
+}
+
+static inline unsigned int smtc_seqr(int reg)
+{
+ smtc_mmiowb(reg, 0x3c4);
+ return smtc_mmiorb(0x3c5);
+}
+
+/* The next structure holds all information relevant for a specific video mode.
+ */
+
+struct ModeInit {
+ int mmsizex;
+ int mmsizey;
+ int bpp;
+ int hz;
+ unsigned char init_misc;
+ unsigned char init_sr00_sr04[SIZE_SR00_SR04];
+ unsigned char init_sr10_sr24[SIZE_SR10_SR24];
+ unsigned char init_sr30_sr75[SIZE_SR30_SR75];
+ unsigned char init_sr80_sr93[SIZE_SR80_SR93];
+ unsigned char init_sra0_sraf[SIZE_SRA0_SRAF];
+ unsigned char init_gr00_gr08[SIZE_GR00_GR08];
+ unsigned char init_ar00_ar14[SIZE_AR00_AR14];
+ unsigned char init_cr00_cr18[SIZE_CR00_CR18];
+ unsigned char init_cr30_cr4d[SIZE_CR30_CR4D];
+ unsigned char init_cr90_cra7[SIZE_CR90_CRA7];
+};
+
+/**********************************************************************
+ SM712 Mode table.
+ **********************************************************************/
+struct ModeInit vgamode[] = {
+ {
+ /* mode#0: 640 x 480 16Bpp 60Hz */
+ 640, 480, 16, 60,
+ /* Init_MISC */
+ 0xE3,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+ },
+ },
+ {
+ /* mode#1: 640 x 480 24Bpp 60Hz */
+ 640, 480, 24, 60,
+ /* Init_MISC */
+ 0xE3,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+ },
+ },
+ {
+ /* mode#0: 640 x 480 32Bpp 60Hz */
+ 640, 480, 32, 60,
+ /* Init_MISC */
+ 0xE3,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEF, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x32, 0x03, 0xA0, 0x09, 0xC0, 0x32, 0x32, 0x32,
+ 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x32, 0x32, 0x32,
+ 0x04, 0x24, 0x63, 0x4F, 0x52, 0x0B, 0xDF, 0xEA,
+ 0x04, 0x50, 0x19, 0x32, 0x32, 0x00, 0x00, 0x32,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x07, 0x82, 0x07, 0x04,
+ 0x00, 0x45, 0x30, 0x30, 0x40, 0x30,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x32,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x32, 0x32,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xFF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x5F, 0x4F, 0x4F, 0x00, 0x53, 0x1F, 0x0B, 0x3E,
+ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xEA, 0x0C, 0xDF, 0x50, 0x40, 0xDF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xFF, 0xFD,
+ 0x5F, 0x4F, 0x00, 0x54, 0x00, 0x0B, 0xDF, 0x00,
+ 0xEA, 0x0C, 0x2E, 0x00, 0x4F, 0xDF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0xDD, 0x5E, 0xEA, 0x87, 0x44, 0x8F, 0x55,
+ 0x0A, 0x8F, 0x55, 0x0A, 0x00, 0x00, 0x18, 0x00,
+ 0x11, 0x10, 0x0B, 0x0A, 0x0A, 0x0A, 0x0A, 0x00,
+ },
+ },
+
+ { /* mode#2: 800 x 600 16Bpp 60Hz */
+ 800, 600, 16, 60,
+ /* Init_MISC */
+ 0x2B,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+ },
+ },
+ { /* mode#3: 800 x 600 24Bpp 60Hz */
+ 800, 600, 24, 60,
+ 0x2B,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x36, 0x03, 0x20, 0x09, 0xC0, 0x36, 0x36, 0x36,
+ 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x36, 0x36, 0x36,
+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+ 0x04, 0x55, 0x59, 0x36, 0x36, 0x00, 0x00, 0x36,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+ 0x02, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x36,
+ 0xF7, 0x00, 0x00, 0x00, 0xEF, 0xFF, 0x36, 0x36,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+ },
+ },
+ { /* mode#7: 800 x 600 32Bpp 60Hz */
+ 800, 600, 32, 60,
+ /* Init_MISC */
+ 0x2B,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xFF, 0xBE, 0xEE, 0xFF, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x34, 0x03, 0x20, 0x09, 0xC0, 0x24, 0x24, 0x24,
+ 0x24, 0x24, 0x24, 0x24, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x38, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x24, 0x24, 0x24,
+ 0x04, 0x48, 0x83, 0x63, 0x68, 0x72, 0x57, 0x58,
+ 0x04, 0x55, 0x59, 0x24, 0x24, 0x00, 0x00, 0x24,
+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x1C, 0x85, 0x35, 0x13,
+ 0x02, 0x45, 0x30, 0x35, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0x00, 0x00, 0x00, 0x6F, 0x7F, 0x7F, 0xFF, 0x24,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x24, 0x24,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFF, 0xBF, 0xFF, 0xFF, 0xED, 0xED, 0xED,
+ 0x7B, 0xFF, 0xFF, 0xFF, 0xBF, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0x7F, 0x63, 0x63, 0x00, 0x68, 0x18, 0x72, 0xF0,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x58, 0x0C, 0x57, 0x64, 0x40, 0x57, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x03, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xE7, 0xBF, 0xFD,
+ 0x7F, 0x63, 0x00, 0x69, 0x18, 0x72, 0x57, 0x00,
+ 0x58, 0x0C, 0xE0, 0x20, 0x63, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x56, 0x4B, 0x5E, 0x55, 0x86, 0x9D, 0x8E, 0xAA,
+ 0xDB, 0x2A, 0xDF, 0x33, 0x00, 0x00, 0x18, 0x00,
+ 0x20, 0x1F, 0x1A, 0x19, 0x0F, 0x0F, 0x0F, 0x00,
+ },
+ },
+ /* We use 1024x768 table to light 1024x600 panel for lemote */
+ { /* mode#4: 1024 x 600 16Bpp 60Hz */
+ 1024, 600, 16, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x00, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xC8, 0x40, 0x14, 0x60, 0x00, 0x0A, 0x17, 0x20,
+ 0x51, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x00, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x22, 0x03, 0x24, 0x09, 0xC0, 0x22, 0x22, 0x22,
+ 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x22, 0x22, 0x22,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x22, 0x22, 0x00, 0x00, 0x22,
+ 0x01, 0x80, 0x7A, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x16, 0x02, 0x0D, 0x82, 0x09, 0x02,
+ 0x04, 0x45, 0x3F, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0xA3, 0x7F, 0x00, 0x82, 0x0b, 0x6f, 0x57, 0x00,
+ 0x5c, 0x0f, 0xE0, 0xe0, 0x7F, 0x57,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+ { /* mode#5: 1024 x 768 24Bpp 60Hz */
+ 1024, 768, 24, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x30, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+ { /* mode#4: 1024 x 768 32Bpp 60Hz */
+ 1024, 768, 32, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x32, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x3B, 0x0D, 0x09, 0x02,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x00, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0xA3, 0x7F, 0x00, 0x86, 0x15, 0x24, 0xFF, 0x00,
+ 0x01, 0x07, 0xE5, 0x20, 0x7F, 0xFF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+ { /* mode#6: 320 x 240 16Bpp 60Hz */
+ 320, 240, 16, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x32, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+
+ { /* mode#8: 320 x 240 32Bpp 60Hz */
+ 320, 240, 32, 60,
+ /* Init_MISC */
+ 0xEB,
+ { /* Init_SR0_SR4 */
+ 0x03, 0x01, 0x0F, 0x03, 0x0E,
+ },
+ { /* Init_SR10_SR24 */
+ 0xF3, 0xB6, 0xC0, 0xDD, 0x00, 0x0E, 0x17, 0x2C,
+ 0x99, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xC4, 0x32, 0x02, 0x01, 0x01,
+ },
+ { /* Init_SR30_SR75 */
+ 0x38, 0x03, 0x20, 0x09, 0xC0, 0x3A, 0x3A, 0x3A,
+ 0x3A, 0x3A, 0x3A, 0x3A, 0x00, 0x00, 0x03, 0xFF,
+ 0x00, 0xFC, 0x00, 0x00, 0x20, 0x18, 0x00, 0xFC,
+ 0x20, 0x0C, 0x44, 0x20, 0x00, 0x00, 0x00, 0x3A,
+ 0x06, 0x68, 0xA7, 0x7F, 0x83, 0x24, 0xFF, 0x03,
+ 0x00, 0x60, 0x59, 0x3A, 0x3A, 0x00, 0x00, 0x3A,
+ 0x01, 0x80, 0x7E, 0x1A, 0x1A, 0x00, 0x00, 0x00,
+ 0x50, 0x03, 0x74, 0x14, 0x08, 0x43, 0x08, 0x43,
+ 0x04, 0x45, 0x30, 0x30, 0x40, 0x20,
+ },
+ { /* Init_SR80_SR93 */
+ 0xFF, 0x07, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x3A,
+ 0xF7, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x3A, 0x3A,
+ 0x00, 0x00, 0x00, 0x00,
+ },
+ { /* Init_SRA0_SRAF */
+ 0x00, 0xFB, 0x9F, 0x01, 0x00, 0xED, 0xED, 0xED,
+ 0x7B, 0xFB, 0xFF, 0xFF, 0x97, 0xEF, 0xBF, 0xDF,
+ },
+ { /* Init_GR00_GR08 */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x05, 0x0F,
+ 0xFF,
+ },
+ { /* Init_AR00_AR14 */
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x41, 0x00, 0x0F, 0x00, 0x00,
+ },
+ { /* Init_CR00_CR18 */
+ 0xA3, 0x7F, 0x7F, 0x00, 0x85, 0x16, 0x24, 0xF5,
+ 0x00, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x03, 0x09, 0xFF, 0x80, 0x40, 0xFF, 0x00, 0xE3,
+ 0xFF,
+ },
+ { /* Init_CR30_CR4D */
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x02, 0x20,
+ 0x00, 0x00, 0x30, 0x40, 0x00, 0xFF, 0xBF, 0xFF,
+ 0x2E, 0x27, 0x00, 0x2b, 0x0c, 0x0F, 0xEF, 0x00,
+ 0xFe, 0x0f, 0x01, 0xC0, 0x27, 0xEF,
+ },
+ { /* Init_CR90_CRA7 */
+ 0x55, 0xD9, 0x5D, 0xE1, 0x86, 0x1B, 0x8E, 0x26,
+ 0xDA, 0x8D, 0xDE, 0x94, 0x00, 0x00, 0x18, 0x00,
+ 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x15, 0x03,
+ },
+ },
+};
+
+#define numvgamodes ARRAY_SIZE(vgamode)
diff --git a/drivers/staging/sm7xxfb/sm7xxfb.c b/drivers/staging/sm7xxfb/sm7xxfb.c
new file mode 100644
index 000000000000..ebd95365ffae
--- /dev/null
+++ b/drivers/staging/sm7xxfb/sm7xxfb.c
@@ -0,0 +1,1024 @@
+/*
+ * Silicon Motion SM7XX frame buffer device
+ *
+ * Copyright (C) 2006 Silicon Motion Technology Corp.
+ * Authors: Ge Wang, gewang@siliconmotion.com
+ * Boyod boyod.yang@siliconmotion.com.cn
+ *
+ * Copyright (C) 2009 Lemote, Inc.
+ * Author: Wu Zhangjin, wuzhangjin@gmail.com
+ *
+ * Copyright (C) 2011 Igalia, S.L.
+ * Author: Javier M. Mellid <jmunhoz@igalia.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.
+ *
+ * Framebuffer driver for Silicon Motion SM710, SM712, SM721 and SM722 chips
+ */
+
+#include <linux/io.h>
+#include <linux/fb.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/module.h>
+#include <linux/console.h>
+#include <linux/screen_info.h>
+
+#ifdef CONFIG_PM
+#include <linux/pm.h>
+#endif
+
+#include "sm7xx.h"
+
+/*
+* Private structure
+*/
+struct smtcfb_info {
+ struct pci_dev *pdev;
+ struct fb_info fb;
+ u16 chip_id;
+ u8 chip_rev_id;
+
+ void __iomem *lfb; /* linear frame buffer */
+ void __iomem *dp_regs; /* drawing processor control regs */
+ void __iomem *vp_regs; /* video processor control regs */
+ void __iomem *cp_regs; /* capture processor control regs */
+ void __iomem *mmio; /* memory map IO port */
+
+ u_int width;
+ u_int height;
+ u_int hz;
+
+ u32 colreg[17];
+};
+
+void __iomem *smtc_regbaseaddress; /* Memory Map IO starting address */
+
+static struct fb_var_screeninfo smtcfb_var = {
+ .xres = 1024,
+ .yres = 600,
+ .xres_virtual = 1024,
+ .yres_virtual = 600,
+ .bits_per_pixel = 16,
+ .red = {16, 8, 0},
+ .green = {8, 8, 0},
+ .blue = {0, 8, 0},
+ .activate = FB_ACTIVATE_NOW,
+ .height = -1,
+ .width = -1,
+ .vmode = FB_VMODE_NONINTERLACED,
+ .nonstd = 0,
+ .accel_flags = FB_ACCELF_TEXT,
+};
+
+static struct fb_fix_screeninfo smtcfb_fix = {
+ .id = "smXXXfb",
+ .type = FB_TYPE_PACKED_PIXELS,
+ .visual = FB_VISUAL_TRUECOLOR,
+ .line_length = 800 * 3,
+ .accel = FB_ACCEL_SMI_LYNX,
+ .type_aux = 0,
+ .xpanstep = 0,
+ .ypanstep = 0,
+ .ywrapstep = 0,
+};
+
+struct vesa_mode {
+ char index[6];
+ u16 lfb_width;
+ u16 lfb_height;
+ u16 lfb_depth;
+};
+
+static struct vesa_mode vesa_mode_table[] = {
+ {"0x301", 640, 480, 8},
+ {"0x303", 800, 600, 8},
+ {"0x305", 1024, 768, 8},
+ {"0x307", 1280, 1024, 8},
+
+ {"0x311", 640, 480, 16},
+ {"0x314", 800, 600, 16},
+ {"0x317", 1024, 768, 16},
+ {"0x31A", 1280, 1024, 16},
+
+ {"0x312", 640, 480, 24},
+ {"0x315", 800, 600, 24},
+ {"0x318", 1024, 768, 24},
+ {"0x31B", 1280, 1024, 24},
+};
+
+static struct screen_info smtc_scr_info;
+
+/* process command line options, get vga parameter */
+static int __init sm7xx_vga_setup(char *options)
+{
+ int i;
+
+ if (!options || !*options)
+ return -EINVAL;
+
+ smtc_scr_info.lfb_width = 0;
+ smtc_scr_info.lfb_height = 0;
+ smtc_scr_info.lfb_depth = 0;
+
+ pr_debug("sm7xx_vga_setup = %s\n", options);
+
+ for (i = 0; i < ARRAY_SIZE(vesa_mode_table); i++) {
+ if (strstr(options, vesa_mode_table[i].index)) {
+ smtc_scr_info.lfb_width = vesa_mode_table[i].lfb_width;
+ smtc_scr_info.lfb_height =
+ vesa_mode_table[i].lfb_height;
+ smtc_scr_info.lfb_depth = vesa_mode_table[i].lfb_depth;
+ return 0;
+ }
+ }
+
+ return -1;
+}
+__setup("vga=", sm7xx_vga_setup);
+
+static void sm712_setpalette(int regno, unsigned red, unsigned green,
+ unsigned blue, struct fb_info *info)
+{
+ /* set bit 5:4 = 01 (write LCD RAM only) */
+ smtc_seqw(0x66, (smtc_seqr(0x66) & 0xC3) | 0x10);
+
+ smtc_mmiowb(regno, dac_reg);
+ smtc_mmiowb(red >> 10, dac_val);
+ smtc_mmiowb(green >> 10, dac_val);
+ smtc_mmiowb(blue >> 10, dac_val);
+}
+
+/* chan_to_field
+ *
+ * convert a colour value into a field position
+ *
+ * from pxafb.c
+ */
+
+static inline unsigned int chan_to_field(unsigned int chan,
+ struct fb_bitfield *bf)
+{
+ chan &= 0xffff;
+ chan >>= 16 - bf->length;
+ return chan << bf->offset;
+}
+
+static int smtc_blank(int blank_mode, struct fb_info *info)
+{
+ /* clear DPMS setting */
+ switch (blank_mode) {
+ case FB_BLANK_UNBLANK:
+ /* Screen On: HSync: On, VSync : On */
+ smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) & 0x77));
+ smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+ smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+ smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+ smtc_seqw(0x31, (smtc_seqr(0x31) | 0x03));
+ break;
+ case FB_BLANK_NORMAL:
+ /* Screen Off: HSync: On, VSync : On Soft blank */
+ smtc_seqw(0x01, (smtc_seqr(0x01) & (~0x20)));
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x22, (smtc_seqr(0x22) & (~0x30)));
+ smtc_seqw(0x23, (smtc_seqr(0x23) & (~0xc0)));
+ smtc_seqw(0x24, (smtc_seqr(0x24) | 0x01));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ break;
+ case FB_BLANK_VSYNC_SUSPEND:
+ /* Screen On: HSync: On, VSync : Off */
+ smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+ smtc_seqw(0x6a, 0x0c);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+ smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x20));
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0x20));
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+ break;
+ case FB_BLANK_HSYNC_SUSPEND:
+ /* Screen On: HSync: Off, VSync : On */
+ smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+ smtc_seqw(0x6a, 0x0c);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+ smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x10));
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+ break;
+ case FB_BLANK_POWERDOWN:
+ /* Screen On: HSync: Off, VSync : Off */
+ smtc_seqw(0x01, (smtc_seqr(0x01) | 0x20));
+ smtc_seqw(0x20, (smtc_seqr(0x20) & (~0xB0)));
+ smtc_seqw(0x6a, 0x0c);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x21, (smtc_seqr(0x21) | 0x88));
+ smtc_seqw(0x22, ((smtc_seqr(0x22) & (~0x30)) | 0x30));
+ smtc_seqw(0x23, ((smtc_seqr(0x23) & (~0xc0)) | 0xD8));
+ smtc_seqw(0x24, (smtc_seqr(0x24) & (~0x01)));
+ smtc_seqw(0x31, ((smtc_seqr(0x31) & (~0x07)) | 0x00));
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0x80));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int smtc_setcolreg(unsigned regno, unsigned red, unsigned green,
+ unsigned blue, unsigned trans, struct fb_info *info)
+{
+ struct smtcfb_info *sfb;
+ u32 val;
+
+ sfb = info->par;
+
+ if (regno > 255)
+ return 1;
+
+ switch (sfb->fb.fix.visual) {
+ case FB_VISUAL_DIRECTCOLOR:
+ case FB_VISUAL_TRUECOLOR:
+ /*
+ * 16/32 bit true-colour, use pseudo-palette for 16 base color
+ */
+ if (regno < 16) {
+ if (sfb->fb.var.bits_per_pixel == 16) {
+ u32 *pal = sfb->fb.pseudo_palette;
+
+ val = chan_to_field(red, &sfb->fb.var.red);
+ val |= chan_to_field(green, &sfb->fb.var.green);
+ val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+ pal[regno] =
+ ((red & 0xf800) >> 8) |
+ ((green & 0xe000) >> 13) |
+ ((green & 0x1c00) << 3) |
+ ((blue & 0xf800) >> 3);
+#else
+ pal[regno] = val;
+#endif
+ } else {
+ u32 *pal = sfb->fb.pseudo_palette;
+
+ val = chan_to_field(red, &sfb->fb.var.red);
+ val |= chan_to_field(green, &sfb->fb.var.green);
+ val |= chan_to_field(blue, &sfb->fb.var.blue);
+#ifdef __BIG_ENDIAN
+ val =
+ (val & 0xff00ff00 >> 8) |
+ (val & 0x00ff00ff << 8);
+#endif
+ pal[regno] = val;
+ }
+ }
+ break;
+
+ case FB_VISUAL_PSEUDOCOLOR:
+ /* color depth 8 bit */
+ sm712_setpalette(regno, red, green, blue, info);
+ break;
+
+ default:
+ return 1; /* unknown type */
+ }
+
+ return 0;
+}
+
+#ifdef __BIG_ENDIAN
+static ssize_t smtcfb_read(struct fb_info *info, char __user *buf, size_t
+ count, loff_t *ppos)
+{
+ unsigned long p = *ppos;
+
+ u32 *buffer, *dst;
+ u32 __iomem *src;
+ int c, i, cnt = 0, err = 0;
+ unsigned long total_size;
+
+ if (!info || !info->screen_base)
+ return -ENODEV;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p >= total_size)
+ return 0;
+
+ if (count >= total_size)
+ count = total_size;
+
+ if (count + p > total_size)
+ count = total_size - p;
+
+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ src = (u32 __iomem *) (info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ while (count) {
+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ dst = buffer;
+ for (i = c >> 2; i--;) {
+ *dst = fb_readl(src++);
+ *dst =
+ (*dst & 0xff00ff00 >> 8) |
+ (*dst & 0x00ff00ff << 8);
+ dst++;
+ }
+ if (c & 3) {
+ u8 *dst8 = (u8 *)dst;
+ u8 __iomem *src8 = (u8 __iomem *)src;
+
+ for (i = c & 3; i--;) {
+ if (i & 1) {
+ *dst8++ = fb_readb(++src8);
+ } else {
+ *dst8++ = fb_readb(--src8);
+ src8 += 2;
+ }
+ }
+ src = (u32 __iomem *)src8;
+ }
+
+ if (copy_to_user(buf, buffer, c)) {
+ err = -EFAULT;
+ break;
+ }
+ *ppos += c;
+ buf += c;
+ cnt += c;
+ count -= c;
+ }
+
+ kfree(buffer);
+
+ return (err) ? err : cnt;
+}
+
+static ssize_t
+smtcfb_write(struct fb_info *info, const char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ unsigned long p = *ppos;
+
+ u32 *buffer, *src;
+ u32 __iomem *dst;
+ int c, i, cnt = 0, err = 0;
+ unsigned long total_size;
+
+ if (!info || !info->screen_base)
+ return -ENODEV;
+
+ if (info->state != FBINFO_STATE_RUNNING)
+ return -EPERM;
+
+ total_size = info->screen_size;
+
+ if (total_size == 0)
+ total_size = info->fix.smem_len;
+
+ if (p > total_size)
+ return -EFBIG;
+
+ if (count > total_size) {
+ err = -EFBIG;
+ count = total_size;
+ }
+
+ if (count + p > total_size) {
+ if (!err)
+ err = -ENOSPC;
+
+ count = total_size - p;
+ }
+
+ buffer = kmalloc((count > PAGE_SIZE) ? PAGE_SIZE : count, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ dst = (u32 __iomem *) (info->screen_base + p);
+
+ if (info->fbops->fb_sync)
+ info->fbops->fb_sync(info);
+
+ while (count) {
+ c = (count > PAGE_SIZE) ? PAGE_SIZE : count;
+ src = buffer;
+
+ if (copy_from_user(src, buf, c)) {
+ err = -EFAULT;
+ break;
+ }
+
+ for (i = c >> 2; i--;) {
+ fb_writel((*src & 0xff00ff00 >> 8) |
+ (*src & 0x00ff00ff << 8), dst++);
+ src++;
+ }
+ if (c & 3) {
+ u8 *src8 = (u8 *)src;
+ u8 __iomem *dst8 = (u8 __iomem *)dst;
+
+ for (i = c & 3; i--;) {
+ if (i & 1) {
+ fb_writeb(*src8++, ++dst8);
+ } else {
+ fb_writeb(*src8++, --dst8);
+ dst8 += 2;
+ }
+ }
+ dst = (u32 __iomem *)dst8;
+ }
+
+ *ppos += c;
+ buf += c;
+ cnt += c;
+ count -= c;
+ }
+
+ kfree(buffer);
+
+ return (cnt) ? cnt : err;
+}
+#endif /* ! __BIG_ENDIAN */
+
+static void sm7xx_set_timing(struct smtcfb_info *sfb)
+{
+ int i = 0, j = 0;
+ u32 m_nscreenstride;
+
+ dev_dbg(&sfb->pdev->dev,
+ "sfb->width=%d sfb->height=%d sfb->fb.var.bits_per_pixel=%d sfb->hz=%d\n",
+ sfb->width, sfb->height, sfb->fb.var.bits_per_pixel, sfb->hz);
+
+ for (j = 0; j < numvgamodes; j++) {
+ if (vgamode[j].mmsizex == sfb->width &&
+ vgamode[j].mmsizey == sfb->height &&
+ vgamode[j].bpp == sfb->fb.var.bits_per_pixel &&
+ vgamode[j].hz == sfb->hz) {
+ dev_dbg(&sfb->pdev->dev,
+ "vgamode[j].mmsizex=%d vgamode[j].mmSizeY=%d vgamode[j].bpp=%d vgamode[j].hz=%d\n",
+ vgamode[j].mmsizex, vgamode[j].mmsizey,
+ vgamode[j].bpp, vgamode[j].hz);
+
+ dev_dbg(&sfb->pdev->dev, "vgamode index=%d\n", j);
+
+ smtc_mmiowb(0x0, 0x3c6);
+
+ smtc_seqw(0, 0x1);
+
+ smtc_mmiowb(vgamode[j].init_misc, 0x3c2);
+
+ /* init SEQ register SR00 - SR04 */
+ for (i = 0; i < SIZE_SR00_SR04; i++)
+ smtc_seqw(i, vgamode[j].init_sr00_sr04[i]);
+
+ /* init SEQ register SR10 - SR24 */
+ for (i = 0; i < SIZE_SR10_SR24; i++)
+ smtc_seqw(i + 0x10,
+ vgamode[j].init_sr10_sr24[i]);
+
+ /* init SEQ register SR30 - SR75 */
+ for (i = 0; i < SIZE_SR30_SR75; i++)
+ if ((i + 0x30) != 0x62 &&
+ (i + 0x30) != 0x6a &&
+ (i + 0x30) != 0x6b)
+ smtc_seqw(i + 0x30,
+ vgamode[j].init_sr30_sr75[i]);
+
+ /* init SEQ register SR80 - SR93 */
+ for (i = 0; i < SIZE_SR80_SR93; i++)
+ smtc_seqw(i + 0x80,
+ vgamode[j].init_sr80_sr93[i]);
+
+ /* init SEQ register SRA0 - SRAF */
+ for (i = 0; i < SIZE_SRA0_SRAF; i++)
+ smtc_seqw(i + 0xa0,
+ vgamode[j].init_sra0_sraf[i]);
+
+ /* init Graphic register GR00 - GR08 */
+ for (i = 0; i < SIZE_GR00_GR08; i++)
+ smtc_grphw(i, vgamode[j].init_gr00_gr08[i]);
+
+ /* init Attribute register AR00 - AR14 */
+ for (i = 0; i < SIZE_AR00_AR14; i++)
+ smtc_attrw(i, vgamode[j].init_ar00_ar14[i]);
+
+ /* init CRTC register CR00 - CR18 */
+ for (i = 0; i < SIZE_CR00_CR18; i++)
+ smtc_crtcw(i, vgamode[j].init_cr00_cr18[i]);
+
+ /* init CRTC register CR30 - CR4D */
+ for (i = 0; i < SIZE_CR30_CR4D; i++)
+ smtc_crtcw(i + 0x30,
+ vgamode[j].init_cr30_cr4d[i]);
+
+ /* init CRTC register CR90 - CRA7 */
+ for (i = 0; i < SIZE_CR90_CRA7; i++)
+ smtc_crtcw(i + 0x90,
+ vgamode[j].init_cr90_cra7[i]);
+ }
+ }
+ smtc_mmiowb(0x67, 0x3c2);
+
+ /* set VPR registers */
+ writel(0x0, sfb->vp_regs + 0x0C);
+ writel(0x0, sfb->vp_regs + 0x40);
+
+ /* set data width */
+ m_nscreenstride =
+ (sfb->width * sfb->fb.var.bits_per_pixel) / 64;
+ switch (sfb->fb.var.bits_per_pixel) {
+ case 8:
+ writel(0x0, sfb->vp_regs + 0x0);
+ break;
+ case 16:
+ writel(0x00020000, sfb->vp_regs + 0x0);
+ break;
+ case 24:
+ writel(0x00040000, sfb->vp_regs + 0x0);
+ break;
+ case 32:
+ writel(0x00030000, sfb->vp_regs + 0x0);
+ break;
+ }
+ writel((u32) (((m_nscreenstride + 2) << 16) | m_nscreenstride),
+ sfb->vp_regs + 0x10);
+}
+
+static void smtc_set_timing(struct smtcfb_info *sfb)
+{
+ switch (sfb->chip_id) {
+ case 0x710:
+ case 0x712:
+ case 0x720:
+ sm7xx_set_timing(sfb);
+ break;
+ }
+}
+
+static void smtcfb_setmode(struct smtcfb_info *sfb)
+{
+ switch (sfb->fb.var.bits_per_pixel) {
+ case 32:
+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres * 4;
+ sfb->fb.var.red.length = 8;
+ sfb->fb.var.green.length = 8;
+ sfb->fb.var.blue.length = 8;
+ sfb->fb.var.red.offset = 16;
+ sfb->fb.var.green.offset = 8;
+ sfb->fb.var.blue.offset = 0;
+ break;
+ case 24:
+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres * 3;
+ sfb->fb.var.red.length = 8;
+ sfb->fb.var.green.length = 8;
+ sfb->fb.var.blue.length = 8;
+ sfb->fb.var.red.offset = 16;
+ sfb->fb.var.green.offset = 8;
+ sfb->fb.var.blue.offset = 0;
+ break;
+ case 8:
+ sfb->fb.fix.visual = FB_VISUAL_PSEUDOCOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres;
+ sfb->fb.var.red.length = 3;
+ sfb->fb.var.green.length = 3;
+ sfb->fb.var.blue.length = 2;
+ sfb->fb.var.red.offset = 5;
+ sfb->fb.var.green.offset = 2;
+ sfb->fb.var.blue.offset = 0;
+ break;
+ case 16:
+ default:
+ sfb->fb.fix.visual = FB_VISUAL_TRUECOLOR;
+ sfb->fb.fix.line_length = sfb->fb.var.xres * 2;
+ sfb->fb.var.red.length = 5;
+ sfb->fb.var.green.length = 6;
+ sfb->fb.var.blue.length = 5;
+ sfb->fb.var.red.offset = 11;
+ sfb->fb.var.green.offset = 5;
+ sfb->fb.var.blue.offset = 0;
+ break;
+ }
+
+ sfb->width = sfb->fb.var.xres;
+ sfb->height = sfb->fb.var.yres;
+ sfb->hz = 60;
+ smtc_set_timing(sfb);
+}
+
+static int smtc_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+{
+ /* sanity checks */
+ if (var->xres_virtual < var->xres)
+ var->xres_virtual = var->xres;
+
+ if (var->yres_virtual < var->yres)
+ var->yres_virtual = var->yres;
+
+ /* set valid default bpp */
+ if ((var->bits_per_pixel != 8) && (var->bits_per_pixel != 16) &&
+ (var->bits_per_pixel != 24) && (var->bits_per_pixel != 32))
+ var->bits_per_pixel = 16;
+
+ return 0;
+}
+
+static int smtc_set_par(struct fb_info *info)
+{
+ smtcfb_setmode(info->par);
+
+ return 0;
+}
+
+static struct fb_ops smtcfb_ops = {
+ .owner = THIS_MODULE,
+ .fb_check_var = smtc_check_var,
+ .fb_set_par = smtc_set_par,
+ .fb_setcolreg = smtc_setcolreg,
+ .fb_blank = smtc_blank,
+ .fb_fillrect = cfb_fillrect,
+ .fb_imageblit = cfb_imageblit,
+ .fb_copyarea = cfb_copyarea,
+#ifdef __BIG_ENDIAN
+ .fb_read = smtcfb_read,
+ .fb_write = smtcfb_write,
+#endif
+};
+
+/*
+ * alloc struct smtcfb_info and assign default values
+ */
+static struct smtcfb_info *smtc_alloc_fb_info(struct pci_dev *pdev)
+{
+ struct smtcfb_info *sfb;
+
+ sfb = kzalloc(sizeof(*sfb), GFP_KERNEL);
+
+ if (!sfb)
+ return NULL;
+
+ sfb->pdev = pdev;
+
+ sfb->fb.flags = FBINFO_FLAG_DEFAULT;
+ sfb->fb.fbops = &smtcfb_ops;
+ sfb->fb.fix = smtcfb_fix;
+ sfb->fb.var = smtcfb_var;
+ sfb->fb.pseudo_palette = sfb->colreg;
+ sfb->fb.par = sfb;
+
+ return sfb;
+}
+
+/*
+ * free struct smtcfb_info
+ */
+static void smtc_free_fb_info(struct smtcfb_info *sfb)
+{
+ kfree(sfb);
+}
+
+/*
+ * Unmap in the memory mapped IO registers
+ */
+
+static void smtc_unmap_mmio(struct smtcfb_info *sfb)
+{
+ if (sfb && smtc_regbaseaddress)
+ smtc_regbaseaddress = NULL;
+}
+
+/*
+ * Map in the screen memory
+ */
+
+static int smtc_map_smem(struct smtcfb_info *sfb,
+ struct pci_dev *pdev, u_long smem_len)
+{
+ sfb->fb.fix.smem_start = pci_resource_start(pdev, 0);
+
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32)
+ sfb->fb.fix.smem_start += 0x800000;
+#endif
+
+ sfb->fb.fix.smem_len = smem_len;
+
+ sfb->fb.screen_base = sfb->lfb;
+
+ if (!sfb->fb.screen_base) {
+ dev_err(&pdev->dev,
+ "%s: unable to map screen memory\n", sfb->fb.fix.id);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+/*
+ * Unmap in the screen memory
+ *
+ */
+static void smtc_unmap_smem(struct smtcfb_info *sfb)
+{
+ if (sfb && sfb->fb.screen_base) {
+ iounmap(sfb->fb.screen_base);
+ sfb->fb.screen_base = NULL;
+ }
+}
+
+/*
+ * We need to wake up the device and make sure its in linear memory mode.
+ */
+static inline void sm7xx_init_hw(void)
+{
+ outb_p(0x18, 0x3c4);
+ outb_p(0x11, 0x3c5);
+}
+
+static int smtcfb_pci_probe(struct pci_dev *pdev,
+ const struct pci_device_id *ent)
+{
+ struct smtcfb_info *sfb;
+ u_long smem_size = 0x00800000; /* default 8MB */
+ int err;
+ unsigned long mmio_base;
+
+ dev_info(&pdev->dev, "Silicon Motion display driver.");
+
+ err = pci_enable_device(pdev); /* enable SMTC chip */
+ if (err)
+ return err;
+
+ sprintf(smtcfb_fix.id, "sm%Xfb", ent->device);
+
+ sfb = smtc_alloc_fb_info(pdev);
+
+ if (!sfb) {
+ err = -ENOMEM;
+ goto failed_free;
+ }
+
+ sfb->chip_id = ent->device;
+
+ pci_set_drvdata(pdev, sfb);
+
+ sm7xx_init_hw();
+
+ /* get mode parameter from smtc_scr_info */
+ if (smtc_scr_info.lfb_width != 0) {
+ sfb->fb.var.xres = smtc_scr_info.lfb_width;
+ sfb->fb.var.yres = smtc_scr_info.lfb_height;
+ sfb->fb.var.bits_per_pixel = smtc_scr_info.lfb_depth;
+ } else {
+ /* default resolution 1024x600 16bit mode */
+ sfb->fb.var.xres = SCREEN_X_RES;
+ sfb->fb.var.yres = SCREEN_Y_RES;
+ sfb->fb.var.bits_per_pixel = SCREEN_BPP;
+ }
+
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 24)
+ sfb->fb.var.bits_per_pixel = (smtc_scr_info.lfb_depth = 32);
+#endif
+ /* Map address and memory detection */
+ mmio_base = pci_resource_start(pdev, 0);
+ pci_read_config_byte(pdev, PCI_REVISION_ID, &sfb->chip_rev_id);
+
+ switch (sfb->chip_id) {
+ case 0x710:
+ case 0x712:
+ sfb->fb.fix.mmio_start = mmio_base + 0x00400000;
+ sfb->fb.fix.mmio_len = 0x00400000;
+ smem_size = SM712_VIDEOMEMORYSIZE;
+#ifdef __BIG_ENDIAN
+ sfb->lfb = ioremap(mmio_base, 0x00c00000);
+#else
+ sfb->lfb = ioremap(mmio_base, 0x00800000);
+#endif
+ sfb->mmio = (smtc_regbaseaddress =
+ sfb->lfb + 0x00700000);
+ sfb->dp_regs = sfb->lfb + 0x00408000;
+ sfb->vp_regs = sfb->lfb + 0x0040c000;
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32) {
+ sfb->lfb += 0x800000;
+ dev_info(&pdev->dev, "sfb->lfb=%p", sfb->lfb);
+ }
+#endif
+ if (!smtc_regbaseaddress) {
+ dev_err(&pdev->dev,
+ "%s: unable to map memory mapped IO!",
+ sfb->fb.fix.id);
+ err = -ENOMEM;
+ goto failed_fb;
+ }
+
+ /* set MCLK = 14.31818 * (0x16 / 0x2) */
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x62, 0x3e);
+ /* enable PCI burst */
+ smtc_seqw(0x17, 0x20);
+ /* enable word swap */
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32)
+ smtc_seqw(0x17, 0x30);
+#endif
+ break;
+ case 0x720:
+ sfb->fb.fix.mmio_start = mmio_base;
+ sfb->fb.fix.mmio_len = 0x00200000;
+ smem_size = SM722_VIDEOMEMORYSIZE;
+ sfb->dp_regs = ioremap(mmio_base, 0x00a00000);
+ sfb->lfb = sfb->dp_regs + 0x00200000;
+ sfb->mmio = (smtc_regbaseaddress =
+ sfb->dp_regs + 0x000c0000);
+ sfb->vp_regs = sfb->dp_regs + 0x800;
+
+ smtc_seqw(0x62, 0xff);
+ smtc_seqw(0x6a, 0x0d);
+ smtc_seqw(0x6b, 0x02);
+ break;
+ default:
+ dev_err(&pdev->dev,
+ "No valid Silicon Motion display chip was detected!");
+
+ goto failed_fb;
+ }
+
+ /* can support 32 bpp */
+ if (15 == sfb->fb.var.bits_per_pixel)
+ sfb->fb.var.bits_per_pixel = 16;
+
+ sfb->fb.var.xres_virtual = sfb->fb.var.xres;
+ sfb->fb.var.yres_virtual = sfb->fb.var.yres;
+ err = smtc_map_smem(sfb, pdev, smem_size);
+ if (err)
+ goto failed;
+
+ smtcfb_setmode(sfb);
+
+ err = register_framebuffer(&sfb->fb);
+ if (err < 0)
+ goto failed;
+
+ dev_info(&pdev->dev,
+ "Silicon Motion SM%X Rev%X primary display mode %dx%d-%d Init Complete.",
+ sfb->chip_id, sfb->chip_rev_id, sfb->fb.var.xres,
+ sfb->fb.var.yres, sfb->fb.var.bits_per_pixel);
+
+ return 0;
+
+failed:
+ dev_err(&pdev->dev, "Silicon Motion, Inc. primary display init fail.");
+
+ smtc_unmap_smem(sfb);
+ smtc_unmap_mmio(sfb);
+failed_fb:
+ smtc_free_fb_info(sfb);
+
+failed_free:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+/*
+ * 0x710 (LynxEM)
+ * 0x712 (LynxEM+)
+ * 0x720 (Lynx3DM, Lynx3DM+)
+ */
+static const struct pci_device_id smtcfb_pci_table[] = {
+ { PCI_DEVICE(0x126f, 0x710), },
+ { PCI_DEVICE(0x126f, 0x712), },
+ { PCI_DEVICE(0x126f, 0x720), },
+ {0,}
+};
+
+static void smtcfb_pci_remove(struct pci_dev *pdev)
+{
+ struct smtcfb_info *sfb;
+
+ sfb = pci_get_drvdata(pdev);
+ smtc_unmap_smem(sfb);
+ smtc_unmap_mmio(sfb);
+ unregister_framebuffer(&sfb->fb);
+ smtc_free_fb_info(sfb);
+}
+
+#ifdef CONFIG_PM
+static int smtcfb_pci_suspend(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct smtcfb_info *sfb;
+
+ sfb = pci_get_drvdata(pdev);
+
+ /* set the hw in sleep mode use external clock and self memory refresh
+ * so that we can turn off internal PLLs later on
+ */
+ smtc_seqw(0x20, (smtc_seqr(0x20) | 0xc0));
+ smtc_seqw(0x69, (smtc_seqr(0x69) & 0xf7));
+
+ console_lock();
+ fb_set_suspend(&sfb->fb, 1);
+ console_unlock();
+
+ /* additionally turn off all function blocks including internal PLLs */
+ smtc_seqw(0x21, 0xff);
+
+ return 0;
+}
+
+static int smtcfb_pci_resume(struct device *device)
+{
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct smtcfb_info *sfb;
+
+ sfb = pci_get_drvdata(pdev);
+
+ /* reinit hardware */
+ sm7xx_init_hw();
+ switch (sfb->chip_id) {
+ case 0x710:
+ case 0x712:
+ /* set MCLK = 14.31818 * (0x16 / 0x2) */
+ smtc_seqw(0x6a, 0x16);
+ smtc_seqw(0x6b, 0x02);
+ smtc_seqw(0x62, 0x3e);
+ /* enable PCI burst */
+ smtc_seqw(0x17, 0x20);
+#ifdef __BIG_ENDIAN
+ if (sfb->fb.var.bits_per_pixel == 32)
+ smtc_seqw(0x17, 0x30);
+#endif
+ break;
+ case 0x720:
+ smtc_seqw(0x62, 0xff);
+ smtc_seqw(0x6a, 0x0d);
+ smtc_seqw(0x6b, 0x02);
+ break;
+ }
+
+ smtc_seqw(0x34, (smtc_seqr(0x34) | 0xc0));
+ smtc_seqw(0x33, ((smtc_seqr(0x33) | 0x08) & 0xfb));
+
+ smtcfb_setmode(sfb);
+
+ console_lock();
+ fb_set_suspend(&sfb->fb, 0);
+ console_unlock();
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sm7xx_pm_ops, smtcfb_pci_suspend, smtcfb_pci_resume);
+#define SM7XX_PM_OPS (&sm7xx_pm_ops)
+
+#else /* !CONFIG_PM */
+
+#define SM7XX_PM_OPS NULL
+
+#endif /* !CONFIG_PM */
+
+static struct pci_driver smtcfb_driver = {
+ .name = "smtcfb",
+ .id_table = smtcfb_pci_table,
+ .probe = smtcfb_pci_probe,
+ .remove = smtcfb_pci_remove,
+ .driver.pm = SM7XX_PM_OPS,
+};
+
+module_pci_driver(smtcfb_driver);
+
+MODULE_AUTHOR("Siliconmotion ");
+MODULE_DESCRIPTION("Framebuffer driver for SMI Graphic Cards");
+MODULE_LICENSE("GPL");
diff --git a/drivers/staging/speakup/i18n.h b/drivers/staging/speakup/i18n.h
index 16a0871373d9..326d086f9d5a 100644
--- a/drivers/staging/speakup/i18n.h
+++ b/drivers/staging/speakup/i18n.h
@@ -3,7 +3,7 @@
/* Internationalization declarations */
enum msg_index_t {
- MSG_FIRST_INDEX ,
+ MSG_FIRST_INDEX,
MSG_ANNOUNCEMENTS_START = MSG_FIRST_INDEX,
MSG_BLANK = MSG_ANNOUNCEMENTS_START,
MSG_IAM_ALIVE,
diff --git a/drivers/staging/speakup/kobjects.c b/drivers/staging/speakup/kobjects.c
index b12c76de60b0..3708bc13ae86 100644
--- a/drivers/staging/speakup/kobjects.c
+++ b/drivers/staging/speakup/kobjects.c
@@ -566,7 +566,7 @@ ssize_t spk_var_show(struct kobject *kobj, struct kobj_attribute *attr,
if (ch >= ' ' && ch < '~')
*cp1++ = ch;
else
- cp1 += sprintf(cp1, "\\""x%02x", ch);
+ cp1 += sprintf(cp1, "\\x%02x", ch);
}
*cp1++ = '"';
*cp1++ = '\n';
diff --git a/drivers/staging/speakup/selection.c b/drivers/staging/speakup/selection.c
index 507fc9a1776e..a0315701c7d9 100644
--- a/drivers/staging/speakup/selection.c
+++ b/drivers/staging/speakup/selection.c
@@ -157,7 +157,7 @@ static void __speakup_paste_selection(struct work_struct *work)
pasted += count;
}
remove_wait_queue(&vc->paste_wait, &wait);
- current->state = TASK_RUNNING;
+ __set_current_state(TASK_RUNNING);
tty_buffer_unlock_exclusive(&vc->port);
tty_ldisc_deref(ld);
diff --git a/drivers/staging/speakup/speakup_dtlk.c b/drivers/staging/speakup/speakup_dtlk.c
index 4e059ea78d4c..89592c0b9151 100644
--- a/drivers/staging/speakup/speakup_dtlk.c
+++ b/drivers/staging/speakup/speakup_dtlk.c
@@ -325,7 +325,7 @@ static struct synth_settings *synth_interrogate(struct spk_synth *synth)
static int synth_probe(struct spk_synth *synth)
{
- unsigned int port_val = 0;
+ unsigned int port_val = 0;
int i = 0;
struct synth_settings *sp;
@@ -361,7 +361,8 @@ static int synth_probe(struct spk_synth *synth)
port_val &= 0xfbff;
if (port_val != 0x107f) {
pr_info("DoubleTalk PC: not found\n");
- synth_release_region(synth_lpc, SYNTH_IO_EXTENT);
+ if (synth_lpc)
+ synth_release_region(synth_lpc, SYNTH_IO_EXTENT);
return -ENODEV;
}
while (inw_p(synth_lpc) != 0x147f)
@@ -369,7 +370,7 @@ static int synth_probe(struct spk_synth *synth)
sp = synth_interrogate(synth);
pr_info("%s: %03x-%03x, ROM ver %s, s/n %u, driver: %s\n",
synth->long_name, synth_lpc, synth_lpc+SYNTH_IO_EXTENT - 1,
- sp->rom_version, sp->serial_number, synth->version);
+ sp->rom_version, sp->serial_number, synth->version);
synth->alive = 1;
return 0;
}
diff --git a/drivers/staging/speakup/synth.c b/drivers/staging/speakup/synth.c
index f3aa4239dc68..01eddab93c66 100644
--- a/drivers/staging/speakup/synth.c
+++ b/drivers/staging/speakup/synth.c
@@ -30,9 +30,9 @@ struct speakup_info_t speakup_info = {
* must be taken at each kernel->speakup transition and released at
* each corresponding speakup->kernel transition.
*
- * The progression thread only interferes with the speakup machinery through
- * the synth buffer, so only needs to take the lock while tinkering with
- * the buffer.
+ * The progression thread only interferes with the speakup machinery
+ * through the synth buffer, so only needs to take the lock
+ * while tinkering with the buffer.
*
* We use spin_lock/trylock_irqsave and spin_unlock_irqrestore with this
* spinlock because speakup needs to disable the keyboard IRQ.
diff --git a/drivers/staging/unisys/Kconfig b/drivers/staging/unisys/Kconfig
index ac080c9dcf46..19fcb3465509 100644
--- a/drivers/staging/unisys/Kconfig
+++ b/drivers/staging/unisys/Kconfig
@@ -12,7 +12,6 @@ if UNISYSSPAR
source "drivers/staging/unisys/visorutil/Kconfig"
source "drivers/staging/unisys/visorchannel/Kconfig"
source "drivers/staging/unisys/visorchipset/Kconfig"
-source "drivers/staging/unisys/channels/Kconfig"
source "drivers/staging/unisys/uislib/Kconfig"
source "drivers/staging/unisys/virtpci/Kconfig"
source "drivers/staging/unisys/virthba/Kconfig"
diff --git a/drivers/staging/unisys/Makefile b/drivers/staging/unisys/Makefile
index b988d6940aae..68b9925e7d5e 100644
--- a/drivers/staging/unisys/Makefile
+++ b/drivers/staging/unisys/Makefile
@@ -4,7 +4,6 @@
obj-$(CONFIG_UNISYS_VISORUTIL) += visorutil/
obj-$(CONFIG_UNISYS_VISORCHANNEL) += visorchannel/
obj-$(CONFIG_UNISYS_VISORCHIPSET) += visorchipset/
-obj-$(CONFIG_UNISYS_CHANNELSTUB) += channels/
obj-$(CONFIG_UNISYS_UISLIB) += uislib/
obj-$(CONFIG_UNISYS_VIRTPCI) += virtpci/
obj-$(CONFIG_UNISYS_VIRTHBA) += virthba/
diff --git a/drivers/staging/unisys/channels/Kconfig b/drivers/staging/unisys/channels/Kconfig
deleted file mode 100644
index 179c6cea2824..000000000000
--- a/drivers/staging/unisys/channels/Kconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-#
-# Unisys channels configuration
-#
-
-config UNISYS_CHANNELSTUB
- tristate "Unisys channelstub driver"
- depends on UNISYSSPAR && UNISYS_VISORUTIL
- ---help---
- If you say Y here, you will enable the Unisys channels driver.
-
diff --git a/drivers/staging/unisys/channels/Makefile b/drivers/staging/unisys/channels/Makefile
deleted file mode 100644
index adc184206035..000000000000
--- a/drivers/staging/unisys/channels/Makefile
+++ /dev/null
@@ -1,11 +0,0 @@
-#
-# Makefile for Unisys channelstub
-#
-
-obj-$(CONFIG_UNISYS_CHANNELSTUB) += visorchannelstub.o
-
-visorchannelstub-y := channel.o chanstub.o
-
-ccflags-y += -Idrivers/staging/unisys/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include
-ccflags-y += -Idrivers/staging/unisys/common-spar/include/channels
diff --git a/drivers/staging/unisys/channels/channel.c b/drivers/staging/unisys/channels/channel.c
deleted file mode 100644
index 74cc4d6b515f..000000000000
--- a/drivers/staging/unisys/channels/channel.c
+++ /dev/null
@@ -1,219 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#include <linux/kernel.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/init.h> /* for module_init and module_exit */
-#include <linux/slab.h> /* for memcpy */
-#include <linux/types.h>
-
-/* Implementation of exported functions for Supervisor channels */
-#include "channel.h"
-
-/*
- * Routine Description:
- * Tries to insert the prebuilt signal pointed to by pSignal into the nth
- * Queue of the Channel pointed to by pChannel
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to the signal
- *
- * Assumptions:
- * - pChannel, Queue and pSignal are valid.
- * - If insertion fails due to a full queue, the caller will determine the
- * retry policy (e.g. wait & try again, report an error, etc.).
- *
- * Return value:
- * 1 if the insertion succeeds, 0 if the queue was full.
- */
-unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue,
- void *sig)
-{
- void __iomem *psignal;
- unsigned int head, tail, nof;
-
- struct signal_queue_header __iomem *pqhdr =
- (struct signal_queue_header __iomem *)
- ((char __iomem *)ch + readq(&ch->ch_space_offset))
- + queue;
-
- /* capture current head and tail */
- head = readl(&pqhdr->head);
- tail = readl(&pqhdr->tail);
-
- /* queue is full if (head + 1) % n equals tail */
- if (((head + 1) % readl(&pqhdr->max_slots)) == tail) {
- nof = readq(&pqhdr->num_overflows) + 1;
- writeq(nof, &pqhdr->num_overflows);
- return 0;
- }
-
- /* increment the head index */
- head = (head + 1) % readl(&pqhdr->max_slots);
-
- /* copy signal to the head location from the area pointed to
- * by pSignal
- */
- psignal = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
- (head * readl(&pqhdr->signal_size));
- memcpy_toio(psignal, sig, readl(&pqhdr->signal_size));
-
- mb(); /* channel synch */
- writel(head, &pqhdr->head);
-
- writeq(readq(&pqhdr->num_sent) + 1, &pqhdr->num_sent);
- return 1;
-}
-EXPORT_SYMBOL_GPL(spar_signal_insert);
-
-/*
- * Routine Description:
- * Removes one signal from Channel pChannel's nth Queue at the
- * time of the call and copies it into the memory pointed to by
- * pSignal.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to where the signals are to be copied
- *
- * Assumptions:
- * - pChannel and Queue are valid.
- * - pSignal points to a memory area large enough to hold queue's SignalSize
- *
- * Return value:
- * 1 if the removal succeeds, 0 if the queue was empty.
- */
-unsigned char
-spar_signal_remove(struct channel_header __iomem *ch, u32 queue, void *sig)
-{
- void __iomem *psource;
- unsigned int head, tail;
- struct signal_queue_header __iomem *pqhdr =
- (struct signal_queue_header __iomem *)((char __iomem *)ch +
- readq(&ch->ch_space_offset)) + queue;
-
- /* capture current head and tail */
- head = readl(&pqhdr->head);
- tail = readl(&pqhdr->tail);
-
- /* queue is empty if the head index equals the tail index */
- if (head == tail) {
- writeq(readq(&pqhdr->num_empty) + 1, &pqhdr->num_empty);
- return 0;
- }
-
- /* advance past the 'empty' front slot */
- tail = (tail + 1) % readl(&pqhdr->max_slots);
-
- /* copy signal from tail location to the area pointed to by pSignal */
- psource = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
- (tail * readl(&pqhdr->signal_size));
- memcpy_fromio(sig, psource, readl(&pqhdr->signal_size));
-
- mb(); /* channel synch */
- writel(tail, &pqhdr->tail);
-
- writeq(readq(&pqhdr->num_received) + 1,
- &pqhdr->num_received);
- return 1;
-}
-EXPORT_SYMBOL_GPL(spar_signal_remove);
-
-/*
- * Routine Description:
- * Removes all signals present in Channel pChannel's nth Queue at the
- * time of the call and copies them into the memory pointed to by
- * pSignal. Returns the # of signals copied as the value of the routine.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- * pSignal: (IN) pointer to where the signals are to be copied
- *
- * Assumptions:
- * - pChannel and Queue are valid.
- * - pSignal points to a memory area large enough to hold Queue's MaxSignals
- * # of signals, each of which is Queue's SignalSize.
- *
- * Return value:
- * # of signals copied.
- */
-unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
- void *sig)
-{
- void *psource;
- unsigned int head, tail, count = 0;
- struct signal_queue_header *pqhdr =
- (struct signal_queue_header *)((char *)ch +
- ch->ch_space_offset) + queue;
-
- /* capture current head and tail */
- head = pqhdr->head;
- tail = pqhdr->tail;
-
- /* queue is empty if the head index equals the tail index */
- if (head == tail)
- return 0;
-
- while (head != tail) {
- /* advance past the 'empty' front slot */
- tail = (tail + 1) % pqhdr->max_slots;
-
- /* copy signal from tail location to the area pointed
- * to by pSignal
- */
- psource =
- (char *)pqhdr + pqhdr->sig_base_offset +
- (tail * pqhdr->signal_size);
- memcpy((char *)sig + (pqhdr->signal_size * count),
- psource, pqhdr->signal_size);
-
- mb(); /* channel synch */
- pqhdr->tail = tail;
-
- count++;
- pqhdr->num_received++;
- }
-
- return count;
-}
-
-/*
- * Routine Description:
- * Determine whether a signal queue is empty.
- *
- * Parameters:
- * pChannel: (IN) points to the IO Channel
- * Queue: (IN) nth Queue of the IO Channel
- *
- * Return value:
- * 1 if the signal queue is empty, 0 otherwise.
- */
-unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
- u32 queue)
-{
- struct signal_queue_header __iomem *pqhdr =
- (struct signal_queue_header __iomem *)((char __iomem *)ch +
- readq(&ch->ch_space_offset)) + queue;
- return readl(&pqhdr->head) == readl(&pqhdr->tail);
-}
-EXPORT_SYMBOL_GPL(spar_signalqueue_empty);
-
diff --git a/drivers/staging/unisys/channels/chanstub.c b/drivers/staging/unisys/channels/chanstub.c
deleted file mode 100644
index b6fd126f16f1..000000000000
--- a/drivers/staging/unisys/channels/chanstub.c
+++ /dev/null
@@ -1,75 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#define EXPORT_SYMTAB
-#include <linux/kernel.h>
-#ifdef CONFIG_MODVERSIONS
-#include <config/modversions.h>
-#endif
-#include <linux/module.h>
-#include <linux/init.h> /* for module_init and module_exit */
-#include <linux/slab.h> /* for memcpy */
-#include <linux/types.h>
-
-#include "channel.h"
-#include "chanstub.h"
-#include "timskmod.h"
-#include "version.h"
-
-static __init int
-channel_mod_init(void)
-{
- if (!unisys_spar_platform)
- return -ENODEV;
- return 0;
-}
-
-static __exit void
-channel_mod_exit(void)
-{
-}
-
-unsigned char
-SignalInsert_withLock(struct channel_header __iomem *pChannel, u32 Queue,
- void *pSignal, spinlock_t *lock)
-{
- unsigned char result;
- unsigned long flags;
-
- spin_lock_irqsave(lock, flags);
- result = spar_signal_insert(pChannel, Queue, pSignal);
- spin_unlock_irqrestore(lock, flags);
- return result;
-}
-
-unsigned char
-SignalRemove_withLock(struct channel_header __iomem *pChannel, u32 Queue,
- void *pSignal, spinlock_t *lock)
-{
- unsigned char result;
-
- spin_lock(lock);
- result = spar_signal_remove(pChannel, Queue, pSignal);
- spin_unlock(lock);
- return result;
-}
-
-module_init(channel_mod_init);
-module_exit(channel_mod_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Bryan Glaudel");
-MODULE_ALIAS("uischan");
- /* this is extracted during depmod and kept in modules.dep */
diff --git a/drivers/staging/unisys/channels/chanstub.h b/drivers/staging/unisys/channels/chanstub.h
deleted file mode 100644
index 1531759a1b31..000000000000
--- a/drivers/staging/unisys/channels/chanstub.h
+++ /dev/null
@@ -1,23 +0,0 @@
-/* Copyright (C) 2010 - 2013 UNISYS 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __CHANSTUB_H__
-#define __CHANSTUB_H__
-unsigned char SignalInsert_withLock(struct channel_header __iomem *pChannel,
- u32 Queue, void *pSignal, spinlock_t *lock);
-unsigned char SignalRemove_withLock(struct channel_header __iomem *pChannel,
- u32 Queue, void *pSignal, spinlock_t *lock);
-
-#endif
diff --git a/drivers/staging/unisys/common-spar/include/version.h b/drivers/staging/unisys/common-spar/include/version.h
index f25208fc3ed1..83d1da7a2f81 100644
--- a/drivers/staging/unisys/common-spar/include/version.h
+++ b/drivers/staging/unisys/common-spar/include/version.h
@@ -30,7 +30,6 @@
#define SPARVER4 "0"
#define VERSION SPARVER1 "." SPARVER2 "." SPARVER3 "." SPARVER4
-#define VERSIONDATE __DATE__
/* Here are various version forms needed in Windows environments.
*/
diff --git a/drivers/staging/unisys/include/timskmod.h b/drivers/staging/unisys/include/timskmod.h
index cff7983dab85..4019a0d63645 100644
--- a/drivers/staging/unisys/include/timskmod.h
+++ b/drivers/staging/unisys/include/timskmod.h
@@ -133,7 +133,7 @@
* x - the number of seconds to sleep.
*/
#define SLEEP(x) \
- do { current->state = TASK_INTERRUPTIBLE; \
+ do { __set_current_state(TASK_INTERRUPTIBLE); \
schedule_timeout((x)*HZ); \
} while (0)
@@ -141,7 +141,7 @@
* x - the number of jiffies to sleep.
*/
#define SLEEPJIFFIES(x) \
- do { current->state = TASK_INTERRUPTIBLE; \
+ do { __set_current_state(TASK_INTERRUPTIBLE); \
schedule_timeout(x); \
} while (0)
diff --git a/drivers/staging/unisys/uislib/Kconfig b/drivers/staging/unisys/uislib/Kconfig
index 6b134e267904..a712eb82224a 100644
--- a/drivers/staging/unisys/uislib/Kconfig
+++ b/drivers/staging/unisys/uislib/Kconfig
@@ -4,7 +4,7 @@
config UNISYS_UISLIB
tristate "Unisys uislib driver"
- depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB && HAS_IOMEM
+ depends on UNISYSSPAR && UNISYS_VISORCHIPSET && HAS_IOMEM
---help---
If you say Y here, you will enable the Unisys uislib driver.
diff --git a/drivers/staging/unisys/uislib/uislib.c b/drivers/staging/unisys/uislib/uislib.c
index 7c87452a9f14..a9eeddeba735 100644
--- a/drivers/staging/unisys/uislib/uislib.c
+++ b/drivers/staging/unisys/uislib/uislib.c
@@ -41,7 +41,6 @@
#include "sparstop.h"
#include "visorchipset.h"
-#include "chanstub.h"
#include "version.h"
#include "guestlinuxdebug.h"
@@ -59,8 +58,8 @@
/* global function pointers that act as callback functions into virtpcimod */
int (*virt_control_chan_func)(struct guest_msgs *);
-static int ProcReadBufferValid;
-static char *ProcReadBuffer; /* Note this MUST be global,
+static int debug_buf_valid;
+static char *debug_buf; /* Note this MUST be global,
* because the contents must */
static unsigned int chipset_inited;
@@ -71,24 +70,24 @@ static unsigned int chipset_inited;
UIS_THREAD_WAIT; \
} while (1)
-static struct bus_info *BusListHead;
-static rwlock_t BusListLock;
-static int BusListCount; /* number of buses in the list */
-static int MaxBusCount; /* maximum number of buses expected */
-static u64 PhysicalDataChan;
-static int PlatformNumber;
+static struct bus_info *bus_list;
+static rwlock_t bus_list_lock;
+static int bus_list_count; /* number of buses in the list */
+static int max_bus_count; /* maximum number of buses expected */
+static u64 phys_data_chan;
+static int platform_no;
-static struct uisthread_info Incoming_ThreadInfo;
-static BOOL Incoming_Thread_Started = FALSE;
-static LIST_HEAD(List_Polling_Device_Channels);
+static struct uisthread_info incoming_ti;
+static BOOL incoming_started = FALSE;
+static LIST_HEAD(poll_dev_chan);
static unsigned long long tot_moved_to_tail_cnt;
static unsigned long long tot_wait_cnt;
static unsigned long long tot_wakeup_cnt;
static unsigned long long tot_schedule_cnt;
static int en_smart_wakeup = 1;
-static DEFINE_SEMAPHORE(Lock_Polling_Device_Channels); /* unlocked */
-static DECLARE_WAIT_QUEUE_HEAD(Wakeup_Polling_Device_Channels);
-static int Go_Polling_Device_Channels;
+static DEFINE_SEMAPHORE(poll_dev_lock); /* unlocked */
+static DECLARE_WAIT_QUEUE_HEAD(poll_dev_wake_q);
+static int poll_dev_start;
#define CALLHOME_PROC_ENTRY_FN "callhome"
#define CALLHOME_THROTTLED_PROC_ENTRY_FN "callhome_throttled"
@@ -115,7 +114,7 @@ static unsigned long long cycles_before_wait, wait_cycles;
/*****************************************************/
static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset);
+ size_t len, loff_t *offset);
static const struct file_operations debugfs_info_fops = {
.read = info_debugfs_read,
};
@@ -129,58 +128,52 @@ init_msg_header(struct controlvm_message *msg, u32 id, uint rsp, uint svr)
msg->hdr.flags.server = svr;
}
-static __iomem void *
-init_vbus_channel(u64 channelAddr, u32 channelBytes)
+static __iomem void *init_vbus_channel(u64 ch_addr, u32 ch_bytes)
{
- void __iomem *rc = NULL;
- void __iomem *pChan = uislib_ioremap_cache(channelAddr, channelBytes);
+ void __iomem *ch = uislib_ioremap_cache(ch_addr, ch_bytes);
- if (!pChan) {
+ if (!ch) {
LOGERR("CONTROLVM_BUS_CREATE error: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
- (unsigned long long) channelAddr,
- (unsigned long long) channelBytes);
- rc = NULL;
- goto Away;
+ (unsigned long long)ch_addr,
+ (unsigned long long)ch_bytes);
+ return NULL;
}
- if (!SPAR_VBUS_CHANNEL_OK_CLIENT(pChan)) {
+ if (!SPAR_VBUS_CHANNEL_OK_CLIENT(ch)) {
ERRDRV("%s channel cannot be used", __func__);
- uislib_iounmap(pChan);
- rc = NULL;
- goto Away;
+ uislib_iounmap(ch);
+ return NULL;
}
- rc = pChan;
-Away:
- return rc;
+ return ch;
}
static int
create_bus(struct controlvm_message *msg, char *buf)
{
- u32 busNo, deviceCount;
+ u32 bus_no, dev_count;
struct bus_info *tmp, *bus;
size_t size;
- if (MaxBusCount == BusListCount) {
+ if (max_bus_count == bus_list_count) {
LOGERR("CONTROLVM_BUS_CREATE Failed: max buses:%d already created\n",
- MaxBusCount);
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, MaxBusCount,
+ max_bus_count);
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, max_bus_count,
POSTCODE_SEVERITY_ERR);
return CONTROLVM_RESP_ERROR_MAX_BUSES;
}
- busNo = msg->cmd.create_bus.bus_no;
- deviceCount = msg->cmd.create_bus.dev_count;
+ bus_no = msg->cmd.create_bus.bus_no;
+ dev_count = msg->cmd.create_bus.dev_count;
- POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, busNo, deviceCount,
+ POSTCODE_LINUX_4(BUS_CREATE_ENTRY_PC, bus_no, dev_count,
POSTCODE_SEVERITY_INFO);
size =
sizeof(struct bus_info) +
- (deviceCount * sizeof(struct device_info *));
+ (dev_count * sizeof(struct device_info *));
bus = kzalloc(size, GFP_ATOMIC);
if (!bus) {
LOGERR("CONTROLVM_BUS_CREATE Failed: kmalloc for bus failed.\n");
- POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, busNo,
+ POSTCODE_LINUX_3(BUS_CREATE_FAILURE_PC, bus_no,
POSTCODE_SEVERITY_ERR);
return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
}
@@ -191,27 +184,29 @@ create_bus(struct controlvm_message *msg, char *buf)
if (msg->hdr.flags.test_message) {
/* This implies we're the IOVM so set guest handle to 0... */
bus->guest_handle = 0;
- bus->bus_no = busNo;
+ bus->bus_no = bus_no;
bus->local_vnic = 1;
- } else
- bus->bus_no = bus->guest_handle = busNo;
- sprintf(bus->name, "%d", (int) bus->bus_no);
- bus->device_count = deviceCount;
+ } else {
+ bus->bus_no = bus_no;
+ bus->guest_handle = bus_no;
+ }
+ sprintf(bus->name, "%d", (int)bus->bus_no);
+ bus->device_count = dev_count;
bus->device =
- (struct device_info **) ((char *) bus + sizeof(struct bus_info));
+ (struct device_info **)((char *)bus + sizeof(struct bus_info));
bus->bus_inst_uuid = msg->cmd.create_bus.bus_inst_uuid;
bus->bus_channel_bytes = 0;
bus->bus_channel = NULL;
/* add bus to our bus list - but check for duplicates first */
- read_lock(&BusListLock);
- for (tmp = BusListHead; tmp; tmp = tmp->next) {
+ read_lock(&bus_list_lock);
+ for (tmp = bus_list; tmp; tmp = tmp->next) {
if (tmp->bus_no == bus->bus_no)
break;
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
if (tmp) {
- /* found a bus already in the list with same busNo -
+ /* found a bus already in the list with same bus_no -
* reject add
*/
LOGERR("CONTROLVM_BUS_CREATE Failed: bus %d already exists.\n",
@@ -221,8 +216,8 @@ create_bus(struct controlvm_message *msg, char *buf)
kfree(bus);
return CONTROLVM_RESP_ERROR_ALREADY_DONE;
}
- if ((msg->cmd.create_bus.channel_addr != 0)
- && (msg->cmd.create_bus.channel_bytes != 0)) {
+ if ((msg->cmd.create_bus.channel_addr != 0) &&
+ (msg->cmd.create_bus.channel_bytes != 0)) {
bus->bus_channel_bytes = msg->cmd.create_bus.channel_bytes;
bus->bus_channel =
init_vbus_channel(msg->cmd.create_bus.channel_addr,
@@ -233,9 +228,9 @@ create_bus(struct controlvm_message *msg, char *buf)
struct guest_msgs cmd;
cmd.msgtype = GUEST_ADD_VBUS;
- cmd.add_vbus.bus_no = busNo;
+ cmd.add_vbus.bus_no = bus_no;
cmd.add_vbus.chanptr = bus->bus_channel;
- cmd.add_vbus.dev_count = deviceCount;
+ cmd.add_vbus.dev_count = dev_count;
cmd.add_vbus.bus_uuid = msg->cmd.create_bus.bus_data_type_uuid;
cmd.add_vbus.instance_uuid = msg->cmd.create_bus.bus_inst_uuid;
if (!virt_control_chan_func) {
@@ -256,15 +251,15 @@ create_bus(struct controlvm_message *msg, char *buf)
}
/* add bus at the head of our list */
- write_lock(&BusListLock);
- if (!BusListHead)
- BusListHead = bus;
- else {
- bus->next = BusListHead;
- BusListHead = bus;
+ write_lock(&bus_list_lock);
+ if (!bus_list) {
+ bus_list = bus;
+ } else {
+ bus->next = bus_list;
+ bus_list = bus;
}
- BusListCount++;
- write_unlock(&BusListLock);
+ bus_list_count++;
+ write_unlock(&bus_list_lock);
POSTCODE_LINUX_3(BUS_CREATE_EXIT_PC, bus->bus_no,
POSTCODE_SEVERITY_INFO);
@@ -277,15 +272,15 @@ destroy_bus(struct controlvm_message *msg, char *buf)
int i;
struct bus_info *bus, *prev = NULL;
struct guest_msgs cmd;
- u32 busNo;
+ u32 bus_no;
- busNo = msg->cmd.destroy_bus.bus_no;
+ bus_no = msg->cmd.destroy_bus.bus_no;
- read_lock(&BusListLock);
+ read_lock(&bus_list_lock);
- bus = BusListHead;
+ bus = bus_list;
while (bus) {
- if (bus->bus_no == busNo)
+ if (bus->bus_no == bus_no)
break;
prev = bus;
bus = bus->next;
@@ -293,8 +288,8 @@ destroy_bus(struct controlvm_message *msg, char *buf)
if (!bus) {
LOGERR("CONTROLVM_BUS_DESTROY Failed: failed to find bus %d.\n",
- busNo);
- read_unlock(&BusListLock);
+ bus_no);
+ read_unlock(&bus_list_lock);
return CONTROLVM_RESP_ERROR_ALREADY_DONE;
}
@@ -302,12 +297,12 @@ destroy_bus(struct controlvm_message *msg, char *buf)
for (i = 0; i < bus->device_count; i++) {
if (bus->device[i] != NULL) {
LOGERR("CONTROLVM_BUS_DESTROY Failed: device %i attached to bus %d.",
- i, busNo);
- read_unlock(&BusListLock);
+ i, bus_no);
+ read_unlock(&bus_list_lock);
return CONTROLVM_RESP_ERROR_BUS_DEVICE_ATTACHED;
}
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
if (msg->hdr.flags.server)
goto remove;
@@ -315,7 +310,7 @@ destroy_bus(struct controlvm_message *msg, char *buf)
/* client messages require us to call the virtpci callback associated
with this bus. */
cmd.msgtype = GUEST_DEL_VBUS;
- cmd.del_vbus.bus_no = busNo;
+ cmd.del_vbus.bus_no = bus_no;
if (!virt_control_chan_func) {
LOGERR("CONTROLVM_BUS_DESTROY Failed: virtpci callback not registered.");
return CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
@@ -327,13 +322,13 @@ destroy_bus(struct controlvm_message *msg, char *buf)
/* finally, remove the bus from the list */
remove:
- write_lock(&BusListLock);
+ write_lock(&bus_list_lock);
if (prev) /* not at head */
prev->next = bus->next;
else
- BusListHead = bus->next;
- BusListCount--;
- write_unlock(&BusListLock);
+ bus_list = bus->next;
+ bus_list_count--;
+ write_unlock(&bus_list_lock);
if (bus->bus_channel) {
uislib_iounmap(bus->bus_channel);
@@ -344,26 +339,26 @@ remove:
return CONTROLVM_RESP_SUCCESS;
}
-static int
-create_device(struct controlvm_message *msg, char *buf)
+static int create_device(struct controlvm_message *msg, char *buf)
{
struct device_info *dev;
struct bus_info *bus;
- u32 busNo, devNo;
+ struct guest_msgs cmd;
+ u32 bus_no, dev_no;
int result = CONTROLVM_RESP_SUCCESS;
- u64 minSize = MIN_IO_CHANNEL_SIZE;
- struct req_handler_info *pReqHandler;
+ u64 min_size = MIN_IO_CHANNEL_SIZE;
+ struct req_handler_info *req_handler;
- busNo = msg->cmd.create_device.bus_no;
- devNo = msg->cmd.create_device.dev_no;
+ bus_no = msg->cmd.create_device.bus_no;
+ dev_no = msg->cmd.create_device.dev_no;
- POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, devNo, busNo,
+ POSTCODE_LINUX_4(DEVICE_CREATE_ENTRY_PC, dev_no, bus_no,
POSTCODE_SEVERITY_INFO);
- dev = kzalloc(sizeof(struct device_info), GFP_ATOMIC);
+ dev = kzalloc(sizeof(*dev), GFP_ATOMIC);
if (!dev) {
LOGERR("CONTROLVM_DEVICE_CREATE Failed: kmalloc for dev failed.\n");
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
return CONTROLVM_RESP_ERROR_KMALLOC_FAILED;
}
@@ -371,169 +366,157 @@ create_device(struct controlvm_message *msg, char *buf)
dev->channel_uuid = msg->cmd.create_device.data_type_uuid;
dev->intr = msg->cmd.create_device.intr;
dev->channel_addr = msg->cmd.create_device.channel_addr;
- dev->bus_no = busNo;
- dev->dev_no = devNo;
+ dev->bus_no = bus_no;
+ dev->dev_no = dev_no;
sema_init(&dev->interrupt_callback_lock, 1); /* unlocked */
- sprintf(dev->devid, "vbus%u:dev%u", (unsigned) busNo, (unsigned) devNo);
+ sprintf(dev->devid, "vbus%u:dev%u", (unsigned)bus_no, (unsigned)dev_no);
/* map the channel memory for the device. */
- if (msg->hdr.flags.test_message)
+ if (msg->hdr.flags.test_message) {
dev->chanptr = (void __iomem *)__va(dev->channel_addr);
- else {
- pReqHandler = req_handler_find(dev->channel_uuid);
- if (pReqHandler)
+ } else {
+ req_handler = req_handler_find(dev->channel_uuid);
+ if (req_handler)
/* generic service handler registered for this
* channel
*/
- minSize = pReqHandler->min_channel_bytes;
- if (minSize > msg->cmd.create_device.channel_bytes) {
+ min_size = req_handler->min_channel_bytes;
+ if (min_size > msg->cmd.create_device.channel_bytes) {
LOGERR("CONTROLVM_DEVICE_CREATE Failed: channel size is too small, channel size:0x%lx, required size:0x%lx",
- (ulong) msg->cmd.create_device.channel_bytes,
- (ulong) minSize);
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
- POSTCODE_SEVERITY_ERR);
+ (ulong)msg->cmd.create_device.channel_bytes,
+ (ulong)min_size);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_ERR);
result = CONTROLVM_RESP_ERROR_CHANNEL_SIZE_TOO_SMALL;
- goto Away;
+ goto cleanup;
}
dev->chanptr =
uislib_ioremap_cache(dev->channel_addr,
msg->cmd.create_device.channel_bytes);
if (!dev->chanptr) {
LOGERR("CONTROLVM_DEVICE_CREATE Failed: ioremap_cache of channelAddr:%Lx for channelBytes:%llu failed",
- dev->channel_addr,
- msg->cmd.create_device.channel_bytes);
+ dev->channel_addr,
+ msg->cmd.create_device.channel_bytes);
result = CONTROLVM_RESP_ERROR_IOREMAP_FAILED;
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
- POSTCODE_SEVERITY_ERR);
- goto Away;
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_ERR);
+ goto cleanup;
}
}
dev->instance_uuid = msg->cmd.create_device.dev_inst_uuid;
dev->channel_bytes = msg->cmd.create_device.channel_bytes;
- read_lock(&BusListLock);
- for (bus = BusListHead; bus; bus = bus->next) {
- if (bus->bus_no == busNo) {
- /* make sure the device number is valid */
- if (devNo >= bus->device_count) {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).",
- devNo, bus->device_count);
- result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
+ read_lock(&bus_list_lock);
+ for (bus = bus_list; bus; bus = bus->next) {
+ if (bus->bus_no != bus_no)
+ continue;
+ /* make sure the device number is valid */
+ if (dev_no >= bus->device_count) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: device (%d) >= deviceCount (%d).",
+ dev_no, bus->device_count);
+ result = CONTROLVM_RESP_ERROR_MAX_DEVICES;
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_ERR);
+ read_unlock(&bus_list_lock);
+ goto cleanup;
+ }
+ /* make sure this device is not already set */
+ if (bus->device[dev_no]) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.",
+ dev_no);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
+ dev_no, bus_no,
+ POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
+ read_unlock(&bus_list_lock);
+ goto cleanup;
+ }
+ read_unlock(&bus_list_lock);
+ /* the msg is bound for virtpci; send
+ * guest_msgs struct to callback
+ */
+ if (msg->hdr.flags.server) {
+ bus->device[dev_no] = dev;
+ POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_INFO);
+ return CONTROLVM_RESP_SUCCESS;
+ }
+ if (uuid_le_cmp(dev->channel_uuid,
+ spar_vhba_channel_protocol_uuid) == 0) {
+ wait_for_valid_guid(&((struct channel_header __iomem *)
+ (dev->chanptr))->chtype);
+ if (!SPAR_VHBA_CHANNEL_OK_CLIENT(dev->chanptr)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.",
+ dev_no);
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
- devNo, busNo,
+ dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
- read_unlock(&BusListLock);
- goto Away;
+ result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+ goto cleanup;
}
- /* make sure this device is not already set */
- if (bus->device[devNo]) {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: device %d is already exists.",
- devNo);
+ cmd.msgtype = GUEST_ADD_VHBA;
+ cmd.add_vhba.chanptr = dev->chanptr;
+ cmd.add_vhba.bus_no = bus_no;
+ cmd.add_vhba.device_no = dev_no;
+ cmd.add_vhba.instance_uuid = dev->instance_uuid;
+ cmd.add_vhba.intr = dev->intr;
+ } else if (uuid_le_cmp(dev->channel_uuid,
+ spar_vnic_channel_protocol_uuid) == 0) {
+ wait_for_valid_guid(&((struct channel_header __iomem *)
+ (dev->chanptr))->chtype);
+ if (!SPAR_VNIC_CHANNEL_OK_CLIENT(dev->chanptr)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.",
+ dev_no);
POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC,
- devNo, busNo,
+ dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_ALREADY_DONE;
- read_unlock(&BusListLock);
- goto Away;
+ result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
+ goto cleanup;
}
- read_unlock(&BusListLock);
- /* the msg is bound for virtpci; send
- * guest_msgs struct to callback
- */
- if (!msg->hdr.flags.server) {
- struct guest_msgs cmd;
-
- if (!uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid)) {
- wait_for_valid_guid(&((
- struct channel_header
- __iomem *) (dev->
- chanptr))->
- chtype);
- if (!SPAR_VHBA_CHANNEL_OK_CLIENT
- (dev->chanptr)) {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed:[CLIENT]VHBA dev %d chan invalid.",
- devNo);
- POSTCODE_LINUX_4
- (DEVICE_CREATE_FAILURE_PC,
- devNo, busNo,
- POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
- goto Away;
- }
- cmd.msgtype = GUEST_ADD_VHBA;
- cmd.add_vhba.chanptr = dev->chanptr;
- cmd.add_vhba.bus_no = busNo;
- cmd.add_vhba.device_no = devNo;
- cmd.add_vhba.instance_uuid =
- dev->instance_uuid;
- cmd.add_vhba.intr = dev->intr;
- } else
- if (!uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid)) {
- wait_for_valid_guid(&((
- struct channel_header
- __iomem *) (dev->
- chanptr))->
- chtype);
- if (!SPAR_VNIC_CHANNEL_OK_CLIENT
- (dev->chanptr)) {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: VNIC[CLIENT] dev %d chan invalid.",
- devNo);
- POSTCODE_LINUX_4
- (DEVICE_CREATE_FAILURE_PC,
- devNo, busNo,
- POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_INVALID;
- goto Away;
- }
- cmd.msgtype = GUEST_ADD_VNIC;
- cmd.add_vnic.chanptr = dev->chanptr;
- cmd.add_vnic.bus_no = busNo;
- cmd.add_vnic.device_no = devNo;
- cmd.add_vnic.instance_uuid =
- dev->instance_uuid;
- cmd.add_vhba.intr = dev->intr;
- } else {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n");
- POSTCODE_LINUX_4
- (DEVICE_CREATE_FAILURE_PC, devNo,
- busNo, POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
- goto Away;
- }
+ cmd.msgtype = GUEST_ADD_VNIC;
+ cmd.add_vnic.chanptr = dev->chanptr;
+ cmd.add_vnic.bus_no = bus_no;
+ cmd.add_vnic.device_no = dev_no;
+ cmd.add_vnic.instance_uuid = dev->instance_uuid;
+ cmd.add_vhba.intr = dev->intr;
+ } else {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: unknown channelTypeGuid.\n");
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
+ goto cleanup;
+ }
- if (!virt_control_chan_func) {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered.");
- POSTCODE_LINUX_4
- (DEVICE_CREATE_FAILURE_PC, devNo,
- busNo, POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
- goto Away;
- }
+ if (!virt_control_chan_func) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci callback not registered.");
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_ERR);
+ result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
+ goto cleanup;
+ }
- if (!virt_control_chan_func(&cmd)) {
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error.");
- POSTCODE_LINUX_4
- (DEVICE_CREATE_FAILURE_PC, devNo,
- busNo, POSTCODE_SEVERITY_ERR);
- result = CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
- goto Away;
- }
- }
- bus->device[devNo] = dev;
- POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, devNo, busNo,
- POSTCODE_SEVERITY_INFO);
- return CONTROLVM_RESP_SUCCESS;
+ if (!virt_control_chan_func(&cmd)) {
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: virtpci GUEST_ADD_[VHBA||VNIC] returned error.");
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_ERR);
+ result =
+ CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_CALLBACK_ERROR;
+ goto cleanup;
}
+
+ bus->device[dev_no] = dev;
+ POSTCODE_LINUX_4(DEVICE_CREATE_SUCCESS_PC, dev_no,
+ bus_no, POSTCODE_SEVERITY_INFO);
+ return CONTROLVM_RESP_SUCCESS;
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
- LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.", busNo);
- POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, devNo, busNo,
+ LOGERR("CONTROLVM_DEVICE_CREATE Failed: failed to find bus %d.",
+ bus_no);
+ POSTCODE_LINUX_4(DEVICE_CREATE_FAILURE_PC, dev_no, bus_no,
POSTCODE_SEVERITY_ERR);
result = CONTROLVM_RESP_ERROR_BUS_INVALID;
-Away:
+cleanup:
if (!msg->hdr.flags.test_message) {
uislib_iounmap(dev->chanptr);
dev->chanptr = NULL;
@@ -543,32 +526,31 @@ Away:
return result;
}
-static int
-pause_device(struct controlvm_message *msg)
+static int pause_device(struct controlvm_message *msg)
{
- u32 busNo, devNo;
+ u32 bus_no, dev_no;
struct bus_info *bus;
struct device_info *dev;
struct guest_msgs cmd;
int retval = CONTROLVM_RESP_SUCCESS;
- busNo = msg->cmd.device_change_state.bus_no;
- devNo = msg->cmd.device_change_state.dev_no;
+ bus_no = msg->cmd.device_change_state.bus_no;
+ dev_no = msg->cmd.device_change_state.dev_no;
- read_lock(&BusListLock);
- for (bus = BusListHead; bus; bus = bus->next) {
- if (bus->bus_no == busNo) {
+ read_lock(&bus_list_lock);
+ for (bus = bus_list; bus; bus = bus->next) {
+ if (bus->bus_no == bus_no) {
/* make sure the device number is valid */
- if (devNo >= bus->device_count) {
+ if (dev_no >= bus->device_count) {
LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device(%d) >= deviceCount(%d).",
- devNo, bus->device_count);
+ dev_no, bus->device_count);
retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
} else {
/* make sure this device exists */
- dev = bus->device[devNo];
+ dev = bus->device[dev_no];
if (!dev) {
LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: device %d does not exist.",
- devNo);
+ dev_no);
retval =
CONTROLVM_RESP_ERROR_ALREADY_DONE;
}
@@ -578,20 +560,20 @@ pause_device(struct controlvm_message *msg)
}
if (!bus) {
LOGERR("CONTROLVM_DEVICE_CHANGESTATE:pause Failed: bus %d does not exist",
- busNo);
+ bus_no);
retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
if (retval == CONTROLVM_RESP_SUCCESS) {
/* the msg is bound for virtpci; send
* guest_msgs struct to callback
*/
- if (!uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid)) {
+ if (uuid_le_cmp(dev->channel_uuid,
+ spar_vhba_channel_protocol_uuid) == 0) {
cmd.msgtype = GUEST_PAUSE_VHBA;
cmd.pause_vhba.chanptr = dev->chanptr;
- } else if (!uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid)) {
+ } else if (uuid_le_cmp(dev->channel_uuid,
+ spar_vnic_channel_protocol_uuid) == 0) {
cmd.msgtype = GUEST_PAUSE_VNIC;
cmd.pause_vnic.chanptr = dev->chanptr;
} else {
@@ -611,32 +593,31 @@ pause_device(struct controlvm_message *msg)
return retval;
}
-static int
-resume_device(struct controlvm_message *msg)
+static int resume_device(struct controlvm_message *msg)
{
- u32 busNo, devNo;
+ u32 bus_no, dev_no;
struct bus_info *bus;
struct device_info *dev;
struct guest_msgs cmd;
int retval = CONTROLVM_RESP_SUCCESS;
- busNo = msg->cmd.device_change_state.bus_no;
- devNo = msg->cmd.device_change_state.dev_no;
+ bus_no = msg->cmd.device_change_state.bus_no;
+ dev_no = msg->cmd.device_change_state.dev_no;
- read_lock(&BusListLock);
- for (bus = BusListHead; bus; bus = bus->next) {
- if (bus->bus_no == busNo) {
+ read_lock(&bus_list_lock);
+ for (bus = bus_list; bus; bus = bus->next) {
+ if (bus->bus_no == bus_no) {
/* make sure the device number is valid */
- if (devNo >= bus->device_count) {
+ if (dev_no >= bus->device_count) {
LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device(%d) >= deviceCount(%d).",
- devNo, bus->device_count);
+ dev_no, bus->device_count);
retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
} else {
/* make sure this device exists */
- dev = bus->device[devNo];
+ dev = bus->device[dev_no];
if (!dev) {
LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: device %d does not exist.",
- devNo);
+ dev_no);
retval =
CONTROLVM_RESP_ERROR_ALREADY_DONE;
}
@@ -647,20 +628,20 @@ resume_device(struct controlvm_message *msg)
if (!bus) {
LOGERR("CONTROLVM_DEVICE_CHANGESTATE:resume Failed: bus %d does not exist",
- busNo);
+ bus_no);
retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
/* the msg is bound for virtpci; send
* guest_msgs struct to callback
*/
if (retval == CONTROLVM_RESP_SUCCESS) {
- if (!uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid)) {
+ if (uuid_le_cmp(dev->channel_uuid,
+ spar_vhba_channel_protocol_uuid) == 0) {
cmd.msgtype = GUEST_RESUME_VHBA;
cmd.resume_vhba.chanptr = dev->chanptr;
- } else if (!uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid)) {
+ } else if (uuid_le_cmp(dev->channel_uuid,
+ spar_vnic_channel_protocol_uuid) == 0) {
cmd.msgtype = GUEST_RESUME_VNIC;
cmd.resume_vnic.chanptr = dev->chanptr;
} else {
@@ -680,33 +661,33 @@ resume_device(struct controlvm_message *msg)
return retval;
}
-static int
-destroy_device(struct controlvm_message *msg, char *buf)
+static int destroy_device(struct controlvm_message *msg, char *buf)
{
- u32 busNo, devNo;
+ u32 bus_no, dev_no;
struct bus_info *bus;
struct device_info *dev;
struct guest_msgs cmd;
int retval = CONTROLVM_RESP_SUCCESS;
- busNo = msg->cmd.destroy_device.bus_no;
- devNo = msg->cmd.destroy_device.bus_no;
+ bus_no = msg->cmd.destroy_device.bus_no;
+ dev_no = msg->cmd.destroy_device.bus_no;
- read_lock(&BusListLock);
- LOGINF("destroy_device called for busNo=%u, devNo=%u", busNo, devNo);
- for (bus = BusListHead; bus; bus = bus->next) {
- if (bus->bus_no == busNo) {
+ read_lock(&bus_list_lock);
+ LOGINF("destroy_device called for bus_no=%u, dev_no=%u", bus_no,
+ dev_no);
+ for (bus = bus_list; bus; bus = bus->next) {
+ if (bus->bus_no == bus_no) {
/* make sure the device number is valid */
- if (devNo >= bus->device_count) {
- LOGERR("CONTROLVM_DEVICE_DESTORY Failed: device(%d) >= deviceCount(%d).",
- devNo, bus->device_count);
+ if (dev_no >= bus->device_count) {
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device(%d) >= device_count(%d).",
+ dev_no, bus->device_count);
retval = CONTROLVM_RESP_ERROR_DEVICE_INVALID;
} else {
/* make sure this device exists */
- dev = bus->device[devNo];
+ dev = bus->device[dev_no];
if (!dev) {
LOGERR("CONTROLVM_DEVICE_DESTROY Failed: device %d does not exist.",
- devNo);
+ dev_no);
retval =
CONTROLVM_RESP_ERROR_ALREADY_DONE;
}
@@ -717,20 +698,20 @@ destroy_device(struct controlvm_message *msg, char *buf)
if (!bus) {
LOGERR("CONTROLVM_DEVICE_DESTROY Failed: bus %d does not exist",
- busNo);
+ bus_no);
retval = CONTROLVM_RESP_ERROR_BUS_INVALID;
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
if (retval == CONTROLVM_RESP_SUCCESS) {
/* the msg is bound for virtpci; send
* guest_msgs struct to callback
*/
- if (!uuid_le_cmp(dev->channel_uuid,
- spar_vhba_channel_protocol_uuid)) {
+ if (uuid_le_cmp(dev->channel_uuid,
+ spar_vhba_channel_protocol_uuid) == 0) {
cmd.msgtype = GUEST_DEL_VHBA;
cmd.del_vhba.chanptr = dev->chanptr;
- } else if (!uuid_le_cmp(dev->channel_uuid,
- spar_vnic_channel_protocol_uuid)) {
+ } else if (uuid_le_cmp(dev->channel_uuid,
+ spar_vnic_channel_protocol_uuid) == 0) {
cmd.msgtype = GUEST_DEL_VNIC;
cmd.del_vnic.chanptr = dev->chanptr;
} else {
@@ -739,7 +720,7 @@ destroy_device(struct controlvm_message *msg, char *buf)
CONTROLVM_RESP_ERROR_CHANNEL_TYPE_UNKNOWN;
}
if (!virt_control_chan_func) {
- LOGERR("CONTROLVM_DEVICE_DESTORY Failed: virtpci callback not registered.");
+ LOGERR("CONTROLVM_DEVICE_DESTROY Failed: virtpci callback not registered.");
return
CONTROLVM_RESP_ERROR_VIRTPCI_DRIVER_FAILURE;
}
@@ -755,7 +736,7 @@ destroy_device(struct controlvm_message *msg, char *buf)
*/
if (dev->polling) {
LOGINF("calling uislib_disable_channel_interrupts");
- uislib_disable_channel_interrupts(busNo, devNo);
+ uislib_disable_channel_interrupts(bus_no, dev_no);
}
/* unmap the channel memory for the device. */
if (!msg->hdr.flags.test_message) {
@@ -763,7 +744,7 @@ destroy_device(struct controlvm_message *msg, char *buf)
uislib_iounmap(dev->chanptr);
}
kfree(dev);
- bus->device[devNo] = NULL;
+ bus->device[dev_no] = NULL;
}
return retval;
}
@@ -773,9 +754,9 @@ init_chipset(struct controlvm_message *msg, char *buf)
{
POSTCODE_LINUX_2(CHIPSET_INIT_ENTRY_PC, POSTCODE_SEVERITY_INFO);
- MaxBusCount = msg->cmd.init_chipset.bus_count;
- PlatformNumber = msg->cmd.init_chipset.platform_number;
- PhysicalDataChan = 0;
+ max_bus_count = msg->cmd.init_chipset.bus_count;
+ platform_no = msg->cmd.init_chipset.platform_number;
+ phys_data_chan = 0;
/* We need to make sure we have our functions registered
* before processing messages. If we are a test vehicle the
@@ -793,31 +774,29 @@ init_chipset(struct controlvm_message *msg, char *buf)
return CONTROLVM_RESP_SUCCESS;
}
-static int
-delete_bus_glue(u32 busNo)
+static int delete_bus_glue(u32 bus_no)
{
struct controlvm_message msg;
init_msg_header(&msg, CONTROLVM_BUS_DESTROY, 0, 0);
- msg.cmd.destroy_bus.bus_no = busNo;
+ msg.cmd.destroy_bus.bus_no = bus_no;
if (destroy_bus(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
- LOGERR("destroy_bus failed. busNo=0x%x\n", busNo);
+ LOGERR("destroy_bus failed. bus_no=0x%x\n", bus_no);
return 0;
}
return 1;
}
-static int
-delete_device_glue(u32 busNo, u32 devNo)
+static int delete_device_glue(u32 bus_no, u32 dev_no)
{
struct controlvm_message msg;
init_msg_header(&msg, CONTROLVM_DEVICE_DESTROY, 0, 0);
- msg.cmd.destroy_device.bus_no = busNo;
- msg.cmd.destroy_device.dev_no = devNo;
+ msg.cmd.destroy_device.bus_no = bus_no;
+ msg.cmd.destroy_device.dev_no = dev_no;
if (destroy_device(&msg, NULL) != CONTROLVM_RESP_SUCCESS) {
- LOGERR("destroy_device failed. busNo=0x%x devNo=0x%x\n", busNo,
- devNo);
+ LOGERR("destroy_device failed. bus_no=0x%x dev_no=0x%x\n",
+ bus_no, dev_no);
return 0;
}
return 1;
@@ -874,7 +853,6 @@ uislib_client_inject_add_bus(u32 bus_no, uuid_le inst_uuid,
}
EXPORT_SYMBOL_GPL(uislib_client_inject_add_bus);
-
int
uislib_client_inject_del_bus(u32 bus_no)
{
@@ -919,7 +897,6 @@ uislib_client_inject_resume_vhba(u32 bus_no, u32 dev_no)
return rc;
}
return 0;
-
}
EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vhba);
@@ -956,7 +933,7 @@ uislib_client_inject_add_vhba(u32 bus_no, u32 dev_no,
msg.cmd.create_device.channel_addr = phys_chan_addr;
if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
- chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+ chan_bytes, (unsigned int)MIN_IO_CHANNEL_SIZE);
POSTCODE_LINUX_4(VHBA_CREATE_FAILURE_PC, chan_bytes,
MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
return 0;
@@ -1015,7 +992,7 @@ uislib_client_inject_add_vnic(u32 bus_no, u32 dev_no,
msg.cmd.create_device.channel_addr = phys_chan_addr;
if (chan_bytes < MIN_IO_CHANNEL_SIZE) {
LOGERR("wrong channel size.chan_bytes = 0x%x IO_CHANNEL_SIZE= 0x%x\n",
- chan_bytes, (unsigned int) MIN_IO_CHANNEL_SIZE);
+ chan_bytes, (unsigned int)MIN_IO_CHANNEL_SIZE);
POSTCODE_LINUX_4(VNIC_CREATE_FAILURE_PC, chan_bytes,
MIN_IO_CHANNEL_SIZE, POSTCODE_SEVERITY_ERR);
return 0;
@@ -1072,7 +1049,6 @@ uislib_client_inject_resume_vnic(u32 bus_no, u32 dev_no)
return -1;
}
return 0;
-
}
EXPORT_SYMBOL_GPL(uislib_client_inject_resume_vnic);
@@ -1129,14 +1105,12 @@ info_debugfs_read_helper(char **buff, int *buff_len)
if (PLINE("\nBuses:\n") < 0)
goto err_done;
- read_lock(&BusListLock);
- for (bus = BusListHead; bus; bus = bus->next) {
-
+ read_lock(&bus_list_lock);
+ for (bus = bus_list; bus; bus = bus->next) {
if (PLINE(" bus=0x%p, busNo=%d, deviceCount=%d\n",
bus, bus->bus_no, bus->device_count) < 0)
goto err_done_unlock;
-
if (PLINE(" Devices:\n") < 0)
goto err_done_unlock;
@@ -1156,7 +1130,7 @@ info_debugfs_read_helper(char **buff, int *buff_len)
}
}
}
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
if (PLINE("UisUtils_Registered_Services: %d\n",
atomic_read(&uisutils_registered_services)) < 0)
@@ -1175,70 +1149,68 @@ info_debugfs_read_helper(char **buff, int *buff_len)
return tot;
err_done_unlock:
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
err_done:
return -1;
}
-static ssize_t
-info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset)
+static ssize_t info_debugfs_read(struct file *file, char __user *buf,
+ size_t len, loff_t *offset)
{
char *temp;
- int totalBytes = 0;
+ int total_bytes = 0;
int remaining_bytes = PROC_READ_BUFFER_SIZE;
/* *start = buf; */
- if (ProcReadBuffer == NULL) {
- DBGINF("ProcReadBuffer == NULL; allocating buffer.\n.");
- ProcReadBuffer = vmalloc(PROC_READ_BUFFER_SIZE);
+ if (debug_buf == NULL) {
+ DBGINF("debug_buf == NULL; allocating buffer.\n.");
+ debug_buf = vmalloc(PROC_READ_BUFFER_SIZE);
- if (ProcReadBuffer == NULL) {
+ if (debug_buf == NULL) {
LOGERR("failed to allocate buffer to provide proc data.\n");
return -ENOMEM;
}
}
- temp = ProcReadBuffer;
+ temp = debug_buf;
- if ((*offset == 0) || (!ProcReadBufferValid)) {
+ if ((*offset == 0) || (!debug_buf_valid)) {
DBGINF("calling info_debugfs_read_helper.\n");
/* if the read fails, then -1 will be returned */
- totalBytes = info_debugfs_read_helper(&temp, &remaining_bytes);
- ProcReadBufferValid = 1;
- } else
- totalBytes = strlen(ProcReadBuffer);
+ total_bytes = info_debugfs_read_helper(&temp, &remaining_bytes);
+ debug_buf_valid = 1;
+ } else {
+ total_bytes = strlen(debug_buf);
+ }
return simple_read_from_buffer(buf, len, offset,
- ProcReadBuffer, totalBytes);
+ debug_buf, total_bytes);
}
-static struct device_info *
-find_dev(u32 busNo, u32 devNo)
+static struct device_info *find_dev(u32 bus_no, u32 dev_no)
{
struct bus_info *bus;
struct device_info *dev = NULL;
- read_lock(&BusListLock);
- for (bus = BusListHead; bus; bus = bus->next) {
- if (bus->bus_no == busNo) {
+ read_lock(&bus_list_lock);
+ for (bus = bus_list; bus; bus = bus->next) {
+ if (bus->bus_no == bus_no) {
/* make sure the device number is valid */
- if (devNo >= bus->device_count) {
- LOGERR("%s bad busNo, devNo=%d,%d",
+ if (dev_no >= bus->device_count) {
+ LOGERR("%s bad bus_no, dev_no=%d,%d",
__func__,
- (int) (busNo), (int) (devNo));
- goto Away;
+ (int)bus_no, (int)dev_no);
+ break;
}
- dev = bus->device[devNo];
+ dev = bus->device[dev_no];
if (!dev)
- LOGERR("%s bad busNo, devNo=%d,%d",
+ LOGERR("%s bad bus_no, dev_no=%d,%d",
__func__,
- (int) (busNo), (int) (devNo));
- goto Away;
+ (int)bus_no, (int)dev_no);
+ break;
}
}
-Away:
- read_unlock(&BusListLock);
+ read_unlock(&bus_list_lock);
return dev;
}
@@ -1262,8 +1234,7 @@ Away:
* less-busy ones.
*
*/
-static int
-Process_Incoming(void *v)
+static int process_incoming(void *v)
{
unsigned long long cur_cycles, old_cycles, idle_cycles, delta_cycles;
struct list_head *new_tail = NULL;
@@ -1272,7 +1243,7 @@ Process_Incoming(void *v)
UIS_DAEMONIZE("dev_incoming");
for (i = 0; i < 16; i++) {
old_cycles = get_cycles();
- wait_event_timeout(Wakeup_Polling_Device_Channels,
+ wait_event_timeout(poll_dev_wake_q,
0, POLLJIFFIES_NORMAL);
cur_cycles = get_cycles();
if (wait_cycles == 0) {
@@ -1285,15 +1256,15 @@ Process_Incoming(void *v)
LOGINF("wait_cycles=%llu", wait_cycles);
cycles_before_wait = wait_cycles;
idle_cycles = 0;
- Go_Polling_Device_Channels = 0;
+ poll_dev_start = 0;
while (1) {
struct list_head *lelt, *tmp;
struct device_info *dev = NULL;
/* poll each channel for input */
- down(&Lock_Polling_Device_Channels);
+ down(&poll_dev_lock);
new_tail = NULL;
- list_for_each_safe(lelt, tmp, &List_Polling_Device_Channels) {
+ list_for_each_safe(lelt, tmp, &poll_dev_chan) {
int rc = 0;
dev = list_entry(lelt, struct device_info,
@@ -1315,22 +1286,22 @@ Process_Incoming(void *v)
if (!
(list_is_last
(lelt,
- &List_Polling_Device_Channels))) {
+ &poll_dev_chan))) {
new_tail = lelt;
dev->moved_to_tail_cnt++;
- } else
+ } else {
dev->last_on_list_cnt++;
+ }
}
-
}
- if (Incoming_ThreadInfo.should_stop)
+ if (incoming_ti.should_stop)
break;
}
if (new_tail != NULL) {
tot_moved_to_tail_cnt++;
- list_move_tail(new_tail, &List_Polling_Device_Channels);
+ list_move_tail(new_tail, &poll_dev_chan);
}
- up(&Lock_Polling_Device_Channels);
+ up(&poll_dev_lock);
cur_cycles = get_cycles();
delta_cycles = cur_cycles - old_cycles;
old_cycles = cur_cycles;
@@ -1340,24 +1311,24 @@ Process_Incoming(void *v)
* - there is no input waiting on any of the channels
* - we have received a signal to stop this thread
*/
- if (Incoming_ThreadInfo.should_stop)
+ if (incoming_ti.should_stop)
break;
if (en_smart_wakeup == 0xFF) {
LOGINF("en_smart_wakeup set to 0xff, to force exiting process_incoming");
break;
}
/* wait for POLLJIFFIES_NORMAL jiffies, or until
- * someone wakes up Wakeup_Polling_Device_Channels,
+ * someone wakes up poll_dev_wake_q,
* whichever comes first only do a wait when we have
* been idle for cycles_before_wait cycles.
*/
if (idle_cycles > cycles_before_wait) {
- Go_Polling_Device_Channels = 0;
+ poll_dev_start = 0;
tot_wait_cnt++;
- wait_event_timeout(Wakeup_Polling_Device_Channels,
- Go_Polling_Device_Channels,
+ wait_event_timeout(poll_dev_wake_q,
+ poll_dev_start,
POLLJIFFIES_NORMAL);
- Go_Polling_Device_Channels = 1;
+ poll_dev_start = 1;
} else {
tot_schedule_cnt++;
schedule();
@@ -1365,25 +1336,25 @@ Process_Incoming(void *v)
}
}
DBGINF("exiting.\n");
- complete_and_exit(&Incoming_ThreadInfo.has_stopped, 0);
+ complete_and_exit(&incoming_ti.has_stopped, 0);
}
static BOOL
-Initialize_incoming_thread(void)
+initialize_incoming_thread(void)
{
- if (Incoming_Thread_Started)
+ if (incoming_started)
return TRUE;
- if (!uisthread_start(&Incoming_ThreadInfo,
- &Process_Incoming, NULL, "dev_incoming")) {
- LOGERR("uisthread_start Initialize_incoming_thread ****FAILED");
+ if (!uisthread_start(&incoming_ti,
+ &process_incoming, NULL, "dev_incoming")) {
+ LOGERR("uisthread_start initialize_incoming_thread ****FAILED");
return FALSE;
}
- Incoming_Thread_Started = TRUE;
+ incoming_started = TRUE;
return TRUE;
}
/* Add a new device/channel to the list being processed by
- * Process_Incoming().
+ * process_incoming().
* <interrupt> - indicates the function to call periodically.
* <interrupt_context> - indicates the data to pass to the <interrupt>
* function.
@@ -1397,23 +1368,23 @@ uislib_enable_channel_interrupts(u32 bus_no, u32 dev_no,
dev = find_dev(bus_no, dev_no);
if (!dev) {
- LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (bus_no),
- (int) (dev_no));
+ LOGERR("%s busNo=%d, devNo=%d", __func__, (int)(bus_no),
+ (int)(dev_no));
return;
}
- down(&Lock_Polling_Device_Channels);
- Initialize_incoming_thread();
+ down(&poll_dev_lock);
+ initialize_incoming_thread();
dev->interrupt = interrupt;
dev->interrupt_context = interrupt_context;
dev->polling = TRUE;
- list_add_tail(&(dev->list_polling_device_channels),
- &List_Polling_Device_Channels);
- up(&Lock_Polling_Device_Channels);
+ list_add_tail(&dev->list_polling_device_channels,
+ &poll_dev_chan);
+ up(&poll_dev_lock);
}
EXPORT_SYMBOL_GPL(uislib_enable_channel_interrupts);
/* Remove a device/channel from the list being processed by
- * Process_Incoming().
+ * process_incoming().
*/
void
uislib_disable_channel_interrupts(u32 bus_no, u32 dev_no)
@@ -1422,31 +1393,31 @@ uislib_disable_channel_interrupts(u32 bus_no, u32 dev_no)
dev = find_dev(bus_no, dev_no);
if (!dev) {
- LOGERR("%s busNo=%d, devNo=%d", __func__, (int) (bus_no),
- (int) (dev_no));
+ LOGERR("%s busNo=%d, devNo=%d", __func__, (int)(bus_no),
+ (int)(dev_no));
return;
}
- down(&Lock_Polling_Device_Channels);
+ down(&poll_dev_lock);
list_del(&dev->list_polling_device_channels);
dev->polling = FALSE;
dev->interrupt = NULL;
- up(&Lock_Polling_Device_Channels);
+ up(&poll_dev_lock);
}
EXPORT_SYMBOL_GPL(uislib_disable_channel_interrupts);
static void
do_wakeup_polling_device_channels(struct work_struct *dummy)
{
- if (!Go_Polling_Device_Channels) {
- Go_Polling_Device_Channels = 1;
- wake_up(&Wakeup_Polling_Device_Channels);
+ if (!poll_dev_start) {
+ poll_dev_start = 1;
+ wake_up(&poll_dev_wake_q);
}
}
-static DECLARE_WORK(Work_wakeup_polling_device_channels,
+static DECLARE_WORK(work_wakeup_polling_device_channels,
do_wakeup_polling_device_channels);
-/* Call this function when you want to send a hint to Process_Incoming() that
+/* Call this function when you want to send a hint to process_incoming() that
* your device might have more requests.
*/
void
@@ -1454,14 +1425,14 @@ uislib_force_channel_interrupt(u32 bus_no, u32 dev_no)
{
if (en_smart_wakeup == 0)
return;
- if (Go_Polling_Device_Channels)
+ if (poll_dev_start)
return;
/* The point of using schedule_work() instead of just doing
* the work inline is to force a slight delay before waking up
- * the Process_Incoming() thread.
+ * the process_incoming() thread.
*/
tot_wakeup_cnt++;
- schedule_work(&Work_wakeup_polling_device_channels);
+ schedule_work(&work_wakeup_polling_device_channels);
}
EXPORT_SYMBOL_GPL(uislib_force_channel_interrupt);
@@ -1472,35 +1443,35 @@ EXPORT_SYMBOL_GPL(uislib_force_channel_interrupt);
static int __init
uislib_mod_init(void)
{
-
if (!unisys_spar_platform)
return -ENODEV;
LOGINF("MONITORAPIS");
LOGINF("sizeof(struct uiscmdrsp):%lu bytes\n",
- (ulong) sizeof(struct uiscmdrsp));
+ (ulong)sizeof(struct uiscmdrsp));
LOGINF("sizeof(struct phys_info):%lu\n",
- (ulong) sizeof(struct phys_info));
+ (ulong)sizeof(struct phys_info));
LOGINF("sizeof(uiscmdrsp_scsi):%lu\n",
- (ulong) sizeof(struct uiscmdrsp_scsi));
+ (ulong)sizeof(struct uiscmdrsp_scsi));
LOGINF("sizeof(uiscmdrsp_net):%lu\n",
- (ulong) sizeof(struct uiscmdrsp_net));
+ (ulong)sizeof(struct uiscmdrsp_net));
LOGINF("sizeof(CONTROLVM_MESSAGE):%lu bytes\n",
- (ulong) sizeof(struct controlvm_message));
+ (ulong)sizeof(struct controlvm_message));
LOGINF("sizeof(struct spar_controlvm_channel_protocol):%lu bytes\n",
- (ulong) sizeof(struct spar_controlvm_channel_protocol));
+ (ulong)sizeof(struct spar_controlvm_channel_protocol));
LOGINF("sizeof(CHANNEL_HEADER):%lu bytes\n",
- (ulong) sizeof(struct channel_header));
+ (ulong)sizeof(struct channel_header));
LOGINF("sizeof(struct spar_io_channel_protocol):%lu bytes\n",
- (ulong) sizeof(struct spar_io_channel_protocol));
+ (ulong)sizeof(struct spar_io_channel_protocol));
LOGINF("SIZEOF_CMDRSP:%lu bytes\n", SIZEOF_CMDRSP);
LOGINF("SIZEOF_PROTOCOL:%lu bytes\n", SIZEOF_PROTOCOL);
/* initialize global pointers to NULL */
- BusListHead = NULL;
- BusListCount = MaxBusCount = 0;
- rwlock_init(&BusListLock);
+ bus_list = NULL;
+ bus_list_count = 0;
+ max_bus_count = 0;
+ rwlock_init(&bus_list_lock);
virt_control_chan_func = NULL;
/* Issue VMCALL_GET_CONTROLVM_ADDR to get CtrlChanPhysAddr and
@@ -1515,7 +1486,7 @@ uislib_mod_init(void)
platformnumber_debugfs_read = debugfs_create_u32(
PLATFORMNUMBER_DEBUGFS_ENTRY_FN, 0444, dir_debugfs,
- &PlatformNumber);
+ &platform_no);
cycles_before_wait_debugfs_read = debugfs_create_u64(
CYCLES_BEFORE_WAIT_DEBUGFS_ENTRY_FN, 0666, dir_debugfs,
@@ -1533,9 +1504,9 @@ uislib_mod_init(void)
static void __exit
uislib_mod_exit(void)
{
- if (ProcReadBuffer) {
- vfree(ProcReadBuffer);
- ProcReadBuffer = NULL;
+ if (debug_buf) {
+ vfree(debug_buf);
+ debug_buf = NULL;
}
debugfs_remove(info_debugfs_entry);
diff --git a/drivers/staging/unisys/uislib/uisqueue.c b/drivers/staging/unisys/uislib/uisqueue.c
index f9f8442d58c5..71bb7b608e9a 100644
--- a/drivers/staging/unisys/uislib/uisqueue.c
+++ b/drivers/staging/unisys/uislib/uisqueue.c
@@ -21,8 +21,6 @@
#include "uisutils.h"
-#include "chanstub.h"
-
/* this is shorter than using __FILE__ (full path name) in
* debug/info/error messages */
#define CURRENT_FILE_PC UISLIB_PC_uisqueue_c
@@ -33,9 +31,202 @@
/*****************************************************/
/* Exported functions */
/*****************************************************/
+
+/*
+ * Routine Description:
+ * Tries to insert the prebuilt signal pointed to by pSignal into the nth
+ * Queue of the Channel pointed to by pChannel
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to the signal
+ *
+ * Assumptions:
+ * - pChannel, Queue and pSignal are valid.
+ * - If insertion fails due to a full queue, the caller will determine the
+ * retry policy (e.g. wait & try again, report an error, etc.).
+ *
+ * Return value:
+ * 1 if the insertion succeeds, 0 if the queue was full.
+ */
+unsigned char spar_signal_insert(struct channel_header __iomem *ch, u32 queue,
+ void *sig)
+{
+ void __iomem *psignal;
+ unsigned int head, tail, nof;
+
+ struct signal_queue_header __iomem *pqhdr =
+ (struct signal_queue_header __iomem *)
+ ((char __iomem *)ch + readq(&ch->ch_space_offset))
+ + queue;
+
+ /* capture current head and tail */
+ head = readl(&pqhdr->head);
+ tail = readl(&pqhdr->tail);
+
+ /* queue is full if (head + 1) % n equals tail */
+ if (((head + 1) % readl(&pqhdr->max_slots)) == tail) {
+ nof = readq(&pqhdr->num_overflows) + 1;
+ writeq(nof, &pqhdr->num_overflows);
+ return 0;
+ }
+
+ /* increment the head index */
+ head = (head + 1) % readl(&pqhdr->max_slots);
+
+ /* copy signal to the head location from the area pointed to
+ * by pSignal
+ */
+ psignal = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
+ (head * readl(&pqhdr->signal_size));
+ memcpy_toio(psignal, sig, readl(&pqhdr->signal_size));
+
+ mb(); /* channel synch */
+ writel(head, &pqhdr->head);
+
+ writeq(readq(&pqhdr->num_sent) + 1, &pqhdr->num_sent);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(spar_signal_insert);
+
+/*
+ * Routine Description:
+ * Removes one signal from Channel pChannel's nth Queue at the
+ * time of the call and copies it into the memory pointed to by
+ * pSignal.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold queue's SignalSize
+ *
+ * Return value:
+ * 1 if the removal succeeds, 0 if the queue was empty.
+ */
+unsigned char
+spar_signal_remove(struct channel_header __iomem *ch, u32 queue, void *sig)
+{
+ void __iomem *psource;
+ unsigned int head, tail;
+ struct signal_queue_header __iomem *pqhdr =
+ (struct signal_queue_header __iomem *)((char __iomem *)ch +
+ readq(&ch->ch_space_offset)) + queue;
+
+ /* capture current head and tail */
+ head = readl(&pqhdr->head);
+ tail = readl(&pqhdr->tail);
+
+ /* queue is empty if the head index equals the tail index */
+ if (head == tail) {
+ writeq(readq(&pqhdr->num_empty) + 1, &pqhdr->num_empty);
+ return 0;
+ }
+
+ /* advance past the 'empty' front slot */
+ tail = (tail + 1) % readl(&pqhdr->max_slots);
+
+ /* copy signal from tail location to the area pointed to by pSignal */
+ psource = (char __iomem *)pqhdr + readq(&pqhdr->sig_base_offset) +
+ (tail * readl(&pqhdr->signal_size));
+ memcpy_fromio(sig, psource, readl(&pqhdr->signal_size));
+
+ mb(); /* channel synch */
+ writel(tail, &pqhdr->tail);
+
+ writeq(readq(&pqhdr->num_received) + 1,
+ &pqhdr->num_received);
+ return 1;
+}
+EXPORT_SYMBOL_GPL(spar_signal_remove);
+
+/*
+ * Routine Description:
+ * Removes all signals present in Channel pChannel's nth Queue at the
+ * time of the call and copies them into the memory pointed to by
+ * pSignal. Returns the # of signals copied as the value of the routine.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ * pSignal: (IN) pointer to where the signals are to be copied
+ *
+ * Assumptions:
+ * - pChannel and Queue are valid.
+ * - pSignal points to a memory area large enough to hold Queue's MaxSignals
+ * # of signals, each of which is Queue's SignalSize.
+ *
+ * Return value:
+ * # of signals copied.
+ */
+unsigned int spar_signal_remove_all(struct channel_header *ch, u32 queue,
+ void *sig)
+{
+ void *psource;
+ unsigned int head, tail, count = 0;
+ struct signal_queue_header *pqhdr =
+ (struct signal_queue_header *)((char *)ch +
+ ch->ch_space_offset) + queue;
+
+ /* capture current head and tail */
+ head = pqhdr->head;
+ tail = pqhdr->tail;
+
+ /* queue is empty if the head index equals the tail index */
+ if (head == tail)
+ return 0;
+
+ while (head != tail) {
+ /* advance past the 'empty' front slot */
+ tail = (tail + 1) % pqhdr->max_slots;
+
+ /* copy signal from tail location to the area pointed
+ * to by pSignal
+ */
+ psource =
+ (char *)pqhdr + pqhdr->sig_base_offset +
+ (tail * pqhdr->signal_size);
+ memcpy((char *)sig + (pqhdr->signal_size * count),
+ psource, pqhdr->signal_size);
+
+ mb(); /* channel synch */
+ pqhdr->tail = tail;
+
+ count++;
+ pqhdr->num_received++;
+ }
+
+ return count;
+}
+
+/*
+ * Routine Description:
+ * Determine whether a signal queue is empty.
+ *
+ * Parameters:
+ * pChannel: (IN) points to the IO Channel
+ * Queue: (IN) nth Queue of the IO Channel
+ *
+ * Return value:
+ * 1 if the signal queue is empty, 0 otherwise.
+ */
+unsigned char spar_signalqueue_empty(struct channel_header __iomem *ch,
+ u32 queue)
+{
+ struct signal_queue_header __iomem *pqhdr =
+ (struct signal_queue_header __iomem *)((char __iomem *)ch +
+ readq(&ch->ch_space_offset)) + queue;
+ return readl(&pqhdr->head) == readl(&pqhdr->tail);
+}
+EXPORT_SYMBOL_GPL(spar_signalqueue_empty);
+
unsigned long long
uisqueue_interlocked_or(unsigned long long __iomem *tgt,
- unsigned long long set)
+ unsigned long long set)
{
unsigned long long i;
unsigned long long j;
@@ -53,7 +244,7 @@ EXPORT_SYMBOL_GPL(uisqueue_interlocked_or);
unsigned long long
uisqueue_interlocked_and(unsigned long long __iomem *tgt,
- unsigned long long set)
+ unsigned long long set)
{
unsigned long long i;
unsigned long long j;
@@ -72,22 +263,21 @@ EXPORT_SYMBOL_GPL(uisqueue_interlocked_and);
static u8
do_locked_client_insert(struct uisqueue_info *queueinfo,
unsigned int whichqueue,
- void *pSignal,
+ void *signal,
spinlock_t *lock,
- unsigned char issueInterruptIfEmpty,
- u64 interruptHandle, u8 *channelId)
+ u8 *channel_id)
{
unsigned long flags;
u8 rc = 0;
spin_lock_irqsave(lock, flags);
- if (!spar_channel_client_acquire_os(queueinfo->chan, channelId))
+ if (!spar_channel_client_acquire_os(queueinfo->chan, channel_id))
goto unlock;
- if (spar_signal_insert(queueinfo->chan, whichqueue, pSignal)) {
+ if (spar_signal_insert(queueinfo->chan, whichqueue, signal)) {
queueinfo->packets_sent++;
rc = 1;
}
- spar_channel_client_release_os(queueinfo->chan, channelId);
+ spar_channel_client_release_os(queueinfo->chan, channel_id);
unlock:
spin_unlock_irqrestore((spinlock_t *)lock, flags);
return rc;
@@ -103,9 +293,8 @@ uisqueue_put_cmdrsp_with_lock_client(struct uisqueue_info *queueinfo,
char oktowait, u8 *channel_id)
{
while (!do_locked_client_insert(queueinfo, whichqueue, cmdrsp,
- (spinlock_t *) insertlock,
- issue_irq_if_empty,
- irq_handle, channel_id)) {
+ (spinlock_t *)insertlock,
+ channel_id)) {
if (oktowait != OK_TO_WAIT) {
LOGERR("****FAILED visor_signal_insert failed; cannot wait; insert aborted\n");
return 0; /* failed to queue */
diff --git a/drivers/staging/unisys/uislib/uisthread.c b/drivers/staging/unisys/uislib/uisthread.c
index c0fc812f751e..25adf1a7307c 100644
--- a/drivers/staging/unisys/uislib/uisthread.c
+++ b/drivers/staging/unisys/uislib/uisthread.c
@@ -53,7 +53,6 @@ uisthread_start(struct uisthread_info *thrinfo,
wake_up_process(thrinfo->task);
LOGINF("started thread pid:%d\n", thrinfo->id);
return 1;
-
}
EXPORT_SYMBOL_GPL(uisthread_start);
diff --git a/drivers/staging/unisys/uislib/uisutils.c b/drivers/staging/unisys/uislib/uisutils.c
index 4a5b86773927..31318d246252 100644
--- a/drivers/staging/unisys/uislib/uisutils.c
+++ b/drivers/staging/unisys/uislib/uisutils.c
@@ -42,14 +42,13 @@ atomic_t uisutils_registered_services = ATOMIC_INIT(0);
* uisctrl_register_req_handler() or
* uisctrl_register_req_handler_ex() */
-
/*****************************************************/
/* Utility functions */
/*****************************************************/
int
uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
- char *format, ...)
+ char *format, ...)
{
va_list args;
int len;
@@ -57,6 +56,7 @@ uisutil_add_proc_line_ex(int *total, char **buffer, int *buffer_remaining,
DBGINF("buffer = 0x%p : *buffer = 0x%p.\n", buffer, *buffer);
va_start(args, format);
len = vsnprintf(*buffer, *buffer_remaining, format, args);
+ va_end(args);
if (len >= *buffer_remaining) {
*buffer += *buffer_remaining;
*total += *buffer_remaining;
@@ -96,7 +96,7 @@ uisctrl_register_req_handler(int type, void *fptr,
}
if (chipset_driver_info)
bus_device_info_init(chipset_driver_info, "chipset", "uislib",
- VERSION, NULL);
+ VERSION, NULL);
return 1;
}
@@ -113,66 +113,57 @@ uisctrl_register_req_handler_ex(uuid_le switch_uuid,
u32 client_str_len, u64 bytes),
struct ultra_vbus_deviceinfo *chipset_driver_info)
{
- struct req_handler_info *pReqHandlerInfo;
- int rc = 0; /* assume failure */
+ struct req_handler_info *req_handler;
LOGINF("type=%pUL, controlfunc=0x%p.\n",
&switch_uuid, controlfunc);
if (!controlfunc) {
LOGERR("%pUL: controlfunc must be supplied\n", &switch_uuid);
- goto Away;
+ return 0;
}
if (!server_channel_ok) {
LOGERR("%pUL: Server_Channel_Ok must be supplied\n",
&switch_uuid);
- goto Away;
+ return 0;
}
if (!server_channel_init) {
LOGERR("%pUL: Server_Channel_Init must be supplied\n",
&switch_uuid);
- goto Away;
+ return 0;
}
- pReqHandlerInfo = req_handler_add(switch_uuid,
- switch_type_name,
- controlfunc,
- min_channel_bytes,
- server_channel_ok, server_channel_init);
- if (!pReqHandlerInfo) {
+ req_handler = req_handler_add(switch_uuid,
+ switch_type_name,
+ controlfunc,
+ min_channel_bytes,
+ server_channel_ok, server_channel_init);
+ if (!req_handler) {
LOGERR("failed to add %pUL to server list\n", &switch_uuid);
- goto Away;
+ return 0;
}
atomic_inc(&uisutils_registered_services);
- rc = 1; /* success */
-Away:
- if (rc) {
- if (chipset_driver_info)
- bus_device_info_init(chipset_driver_info, "chipset",
- "uislib", VERSION, NULL);
- } else
- LOGERR("failed to register type %pUL.\n", &switch_uuid);
+ if (chipset_driver_info) {
+ bus_device_info_init(chipset_driver_info, "chipset",
+ "uislib", VERSION, NULL);
+ return 1;
+ }
- return rc;
+ LOGERR("failed to register type %pUL.\n", &switch_uuid);
+ return 0;
}
EXPORT_SYMBOL_GPL(uisctrl_register_req_handler_ex);
int
uisctrl_unregister_req_handler_ex(uuid_le switch_uuid)
{
- int rc = 0; /* assume failure */
-
LOGINF("type=%pUL.\n", &switch_uuid);
if (req_handler_del(switch_uuid) < 0) {
LOGERR("failed to remove %pUL from server list\n",
- &switch_uuid);
- goto Away;
+ &switch_uuid);
+ return 0;
}
atomic_dec(&uisutils_registered_services);
- rc = 1; /* success */
-Away:
- if (!rc)
- LOGERR("failed to unregister type %pUL.\n", &switch_uuid);
- return rc;
+ return 1;
}
EXPORT_SYMBOL_GPL(uisctrl_unregister_req_handler_ex);
@@ -214,10 +205,10 @@ uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
frags[count].pi_pfn =
page_to_pfn(virt_to_page(skb->data + offset));
frags[count].pi_off =
- (unsigned long) (skb->data + offset) & PI_PAGE_MASK;
+ (unsigned long)(skb->data + offset) & PI_PAGE_MASK;
size =
min(firstfraglen,
- (unsigned int) (PI_PAGE_SIZE - frags[count].pi_off));
+ (unsigned int)(PI_PAGE_SIZE - frags[count].pi_off));
/* can take smallest of firstfraglen(what's left) OR
* bytes left in the page
*/
@@ -231,7 +222,7 @@ uisutil_copy_fragsinfo_from_skb(unsigned char *calling_ctx, void *skb_in,
if ((count + numfrags) > frags_max) {
LOGERR("**** FAILED %s frags array too small: max:%d count+nr_frags:%d\n",
- calling_ctx, frags_max, count + numfrags);
+ calling_ctx, frags_max, count + numfrags);
return -1; /* failure */
}
@@ -255,7 +246,6 @@ dolist: if (skb_shinfo(skb)->frag_list) {
for (skbinlist = skb_shinfo(skb)->frag_list; skbinlist;
skbinlist = skbinlist->next) {
-
c = uisutil_copy_fragsinfo_from_skb("recursive",
skbinlist,
skbinlist->len - skbinlist->data_len,
@@ -272,17 +262,18 @@ dolist: if (skb_shinfo(skb)->frag_list) {
}
EXPORT_SYMBOL_GPL(uisutil_copy_fragsinfo_from_skb);
-static LIST_HEAD(ReqHandlerInfo_list); /* list of struct req_handler_info */
-static DEFINE_SPINLOCK(ReqHandlerInfo_list_lock);
+static LIST_HEAD(req_handler_info_list); /* list of struct req_handler_info */
+static DEFINE_SPINLOCK(req_handler_info_list_lock);
struct req_handler_info *
req_handler_add(uuid_le switch_uuid,
const char *switch_type_name,
int (*controlfunc)(struct io_msgs *),
unsigned long min_channel_bytes,
- int (*Server_Channel_Ok)(unsigned long channelBytes),
- int (*Server_Channel_Init)
- (void *x, unsigned char *clientStr, u32 clientStrLen, u64 bytes))
+ int (*server_channel_ok)(unsigned long channel_bytes),
+ int (*server_channel_init)
+ (void *x, unsigned char *clientstr, u32 clientstr_len,
+ u64 bytes))
{
struct req_handler_info *rc = NULL;
@@ -292,14 +283,14 @@ req_handler_add(uuid_le switch_uuid,
rc->switch_uuid = switch_uuid;
rc->controlfunc = controlfunc;
rc->min_channel_bytes = min_channel_bytes;
- rc->server_channel_ok = Server_Channel_Ok;
- rc->server_channel_init = Server_Channel_Init;
+ rc->server_channel_ok = server_channel_ok;
+ rc->server_channel_init = server_channel_init;
if (switch_type_name)
strncpy(rc->switch_type_name, switch_type_name,
sizeof(rc->switch_type_name) - 1);
- spin_lock(&ReqHandlerInfo_list_lock);
- list_add_tail(&(rc->list_link), &ReqHandlerInfo_list);
- spin_unlock(&ReqHandlerInfo_list_lock);
+ spin_lock(&req_handler_info_list_lock);
+ list_add_tail(&rc->list_link, &req_handler_info_list);
+ spin_unlock(&req_handler_info_list_lock);
return rc;
}
@@ -310,15 +301,15 @@ req_handler_find(uuid_le switch_uuid)
struct list_head *lelt, *tmp;
struct req_handler_info *entry = NULL;
- spin_lock(&ReqHandlerInfo_list_lock);
- list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+ spin_lock(&req_handler_info_list_lock);
+ list_for_each_safe(lelt, tmp, &req_handler_info_list) {
entry = list_entry(lelt, struct req_handler_info, list_link);
if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
- spin_unlock(&ReqHandlerInfo_list_lock);
+ spin_unlock(&req_handler_info_list_lock);
return entry;
}
}
- spin_unlock(&ReqHandlerInfo_list_lock);
+ spin_unlock(&req_handler_info_list_lock);
return NULL;
}
@@ -329,8 +320,8 @@ req_handler_del(uuid_le switch_uuid)
struct req_handler_info *entry = NULL;
int rc = -1;
- spin_lock(&ReqHandlerInfo_list_lock);
- list_for_each_safe(lelt, tmp, &ReqHandlerInfo_list) {
+ spin_lock(&req_handler_info_list_lock);
+ list_for_each_safe(lelt, tmp, &req_handler_info_list) {
entry = list_entry(lelt, struct req_handler_info, list_link);
if (uuid_le_cmp(entry->switch_uuid, switch_uuid) == 0) {
list_del(lelt);
@@ -338,6 +329,6 @@ req_handler_del(uuid_le switch_uuid)
rc++;
}
}
- spin_unlock(&ReqHandlerInfo_list_lock);
+ spin_unlock(&req_handler_info_list_lock);
return rc;
}
diff --git a/drivers/staging/unisys/virthba/Kconfig b/drivers/staging/unisys/virthba/Kconfig
index c0d7986e78cb..9af98fc7acbc 100644
--- a/drivers/staging/unisys/virthba/Kconfig
+++ b/drivers/staging/unisys/virthba/Kconfig
@@ -4,7 +4,7 @@
config UNISYS_VIRTHBA
tristate "Unisys virthba driver"
- depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_CHANNELSTUB && UNISYS_UISLIB && UNISYS_VIRTPCI && SCSI
+ depends on UNISYSSPAR && UNISYS_VISORCHIPSET && UNISYS_UISLIB && UNISYS_VIRTPCI && SCSI
---help---
If you say Y here, you will enable the Unisys virthba driver.
diff --git a/drivers/staging/unisys/virthba/virthba.c b/drivers/staging/unisys/virthba/virthba.c
index d7a629b5f111..e6ecea560495 100644
--- a/drivers/staging/unisys/virthba/virthba.c
+++ b/drivers/staging/unisys/virthba/virthba.c
@@ -85,7 +85,8 @@ static int virthba_host_reset_handler(struct scsi_cmnd *scsicmd);
static const char *virthba_get_info(struct Scsi_Host *shp);
static int virthba_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
static int virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
- void (*virthba_cmnd_done)(struct scsi_cmnd *));
+ void (*virthba_cmnd_done)
+ (struct scsi_cmnd *));
static const struct x86_cpu_id unisys_spar_ids[] = {
{ X86_VENDOR_INTEL, 6, 62, X86_FEATURE_ANY },
@@ -107,19 +108,20 @@ static void virthba_slave_destroy(struct scsi_device *scsidev);
static int process_incoming_rsps(void *);
static int virthba_serverup(struct virtpci_dev *virtpcidev);
static int virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state);
-static void doDiskAddRemove(struct work_struct *work);
+static void do_disk_add_remove(struct work_struct *work);
static void virthba_serverdown_complete(struct work_struct *work);
static ssize_t info_debugfs_read(struct file *file, char __user *buf,
- size_t len, loff_t *offset);
+ size_t len, loff_t *offset);
static ssize_t enable_ints_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *ppos);
+ const char __user *buffer, size_t count,
+ loff_t *ppos);
/*****************************************************/
/* Globals */
/*****************************************************/
static int rsltq_wait_usecs = 4000; /* Default 4ms */
-static unsigned int MaxBuffLen;
+static unsigned int max_buff_len;
/* Module options */
static char *virthba_options = "NONE";
@@ -165,6 +167,7 @@ struct virtdisk_info {
atomic_t error_count;
struct virtdisk_info *next;
};
+
/* Each Scsi_Host has a host_data area that contains this struct. */
struct virthba_info {
struct Scsi_Host *scsihost;
@@ -193,7 +196,7 @@ struct virthba_info {
struct virtdisk_info head;
};
-/* Work Data for DARWorkQ */
+/* Work Data for dar_work_queue */
struct diskaddremove {
u8 add; /* 0-remove, 1-add */
struct Scsi_Host *shost; /* Scsi Host for this virthba instance */
@@ -244,7 +247,7 @@ static const struct file_operations debugfs_enable_ints_fops = {
#define VIRTHBASOPENMAX 1
/* array of open devices maintained by open() and close(); */
-static struct virthba_devices_open VirtHbasOpen[VIRTHBASOPENMAX];
+static struct virthba_devices_open virthbas_open[VIRTHBASOPENMAX];
static struct dentry *virthba_debugfs_dir;
/*****************************************************/
@@ -260,7 +263,7 @@ add_scsipending_entry(struct virthba_info *vhbainfo, char cmdtype, void *new)
insert_location = vhbainfo->nextinsert;
while (vhbainfo->pending[insert_location].sent != NULL) {
insert_location = (insert_location + 1) % MAX_PENDING_REQUESTS;
- if (insert_location == (int) vhbainfo->nextinsert) {
+ if (insert_location == (int)vhbainfo->nextinsert) {
LOGERR("Queue should be full. insert_location<<%d>> Unable to find open slot for pending commands.\n",
insert_location);
spin_unlock_irqrestore(&vhbainfo->privlock, flags);
@@ -289,7 +292,7 @@ add_scsipending_entry_with_wait(struct virthba_info *vhbainfo, char cmdtype,
insert_location = add_scsipending_entry(vhbainfo, cmdtype, new);
}
- return (unsigned int) insert_location;
+ return (unsigned int)insert_location;
}
static void *
@@ -300,13 +303,13 @@ del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del)
if (del >= MAX_PENDING_REQUESTS) {
LOGERR("Invalid queue position <<%lu>> given to delete. MAX_PENDING_REQUESTS <<%d>>\n",
- (unsigned long) del, MAX_PENDING_REQUESTS);
+ (unsigned long)del, MAX_PENDING_REQUESTS);
} else {
spin_lock_irqsave(&vhbainfo->privlock, flags);
if (vhbainfo->pending[del].sent == NULL)
LOGERR("Deleting already cleared queue entry at <<%lu>>.\n",
- (unsigned long) del);
+ (unsigned long)del);
sent = vhbainfo->pending[del].sent;
@@ -318,30 +321,30 @@ del_scsipending_entry(struct virthba_info *vhbainfo, uintptr_t del)
return sent;
}
-/* DARWorkQ (Disk Add/Remove) */
-static struct work_struct DARWorkQ;
-static struct diskaddremove *DARWorkQHead;
-static spinlock_t DARWorkQLock;
-static unsigned short DARWorkQSched;
+/* dar_work_queue (Disk Add/Remove) */
+static struct work_struct dar_work_queue;
+static struct diskaddremove *dar_work_queue_head;
+static spinlock_t dar_work_queue_lock;
+static unsigned short dar_work_queue_sched;
#define QUEUE_DISKADDREMOVE(dar) { \
- spin_lock_irqsave(&DARWorkQLock, flags); \
- if (!DARWorkQHead) { \
- DARWorkQHead = dar; \
+ spin_lock_irqsave(&dar_work_queue_lock, flags); \
+ if (!dar_work_queue_head) { \
+ dar_work_queue_head = dar; \
dar->next = NULL; \
} \
else { \
- dar->next = DARWorkQHead; \
- DARWorkQHead = dar; \
+ dar->next = dar_work_queue_head; \
+ dar_work_queue_head = dar; \
} \
- if (!DARWorkQSched) { \
- schedule_work(&DARWorkQ); \
- DARWorkQSched = 1; \
+ if (!dar_work_queue_sched) { \
+ schedule_work(&dar_work_queue); \
+ dar_work_queue_sched = 1; \
} \
- spin_unlock_irqrestore(&DARWorkQLock, flags); \
+ spin_unlock_irqrestore(&dar_work_queue_lock, flags); \
}
static inline void
-SendDiskAddRemove(struct diskaddremove *dar)
+send_disk_add_remove(struct diskaddremove *dar)
{
struct scsi_device *sdev;
int error;
@@ -365,31 +368,31 @@ SendDiskAddRemove(struct diskaddremove *dar)
}
/*****************************************************/
-/* DARWorkQ Handler Thread */
+/* dar_work_queue Handler Thread */
/*****************************************************/
static void
-doDiskAddRemove(struct work_struct *work)
+do_disk_add_remove(struct work_struct *work)
{
struct diskaddremove *dar;
struct diskaddremove *tmphead;
int i = 0;
unsigned long flags;
- spin_lock_irqsave(&DARWorkQLock, flags);
- tmphead = DARWorkQHead;
- DARWorkQHead = NULL;
- DARWorkQSched = 0;
- spin_unlock_irqrestore(&DARWorkQLock, flags);
+ spin_lock_irqsave(&dar_work_queue_lock, flags);
+ tmphead = dar_work_queue_head;
+ dar_work_queue_head = NULL;
+ dar_work_queue_sched = 0;
+ spin_unlock_irqrestore(&dar_work_queue_lock, flags);
while (tmphead) {
dar = tmphead;
tmphead = dar->next;
- SendDiskAddRemove(dar);
+ send_disk_add_remove(dar);
i++;
}
}
/*****************************************************/
-/* Routine to add entry to DARWorkQ */
+/* Routine to add entry to dar_work_queue */
/*****************************************************/
static void
process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
@@ -397,7 +400,7 @@ process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
struct diskaddremove *dar;
unsigned long flags;
- dar = kzalloc(sizeof(struct diskaddremove), GFP_ATOMIC);
+ dar = kzalloc(sizeof(*dar), GFP_ATOMIC);
if (dar) {
dar->add = cmdrsp->disknotify.add;
dar->shost = shost;
@@ -416,10 +419,10 @@ process_disk_notify(struct Scsi_Host *shost, struct uiscmdrsp *cmdrsp)
/* Probe Remove Functions */
/*****************************************************/
static irqreturn_t
-virthba_ISR(int irq, void *dev_id)
+virthba_isr(int irq, void *dev_id)
{
- struct virthba_info *virthbainfo = (struct virthba_info *) dev_id;
- struct channel_header __iomem *pChannelHeader;
+ struct virthba_info *virthbainfo = (struct virthba_info *)dev_id;
+ struct channel_header __iomem *channel_header;
struct signal_queue_header __iomem *pqhdr;
u64 mask;
unsigned long long rc1;
@@ -427,23 +430,23 @@ virthba_ISR(int irq, void *dev_id)
if (virthbainfo == NULL)
return IRQ_NONE;
virthbainfo->interrupts_rcvd++;
- pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
- if (((readq(&pChannelHeader->features)
- & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0)
- && ((readq(&pChannelHeader->features) &
+ channel_header = virthbainfo->chinfo.queueinfo->chan;
+ if (((readq(&channel_header->features)
+ & ULTRA_IO_IOVM_IS_OK_WITH_DRIVER_DISABLING_INTS) != 0) &&
+ ((readq(&channel_header->features) &
ULTRA_IO_DRIVER_DISABLES_INTS) !=
0)) {
virthbainfo->interrupts_disabled++;
mask = ~ULTRA_CHANNEL_ENABLE_INTS;
rc1 = uisqueue_interlocked_and(virthbainfo->flags_addr, mask);
}
- if (spar_signalqueue_empty(pChannelHeader, IOCHAN_FROM_IOPART)) {
+ if (spar_signalqueue_empty(channel_header, IOCHAN_FROM_IOPART)) {
virthbainfo->interrupts_notme++;
return IRQ_NONE;
}
pqhdr = (struct signal_queue_header __iomem *)
- ((char __iomem *) pChannelHeader +
- readq(&pChannelHeader->ch_space_offset)) + IOCHAN_FROM_IOPART;
+ ((char __iomem *)channel_header +
+ readq(&channel_header->ch_space_offset)) + IOCHAN_FROM_IOPART;
writeq(readq(&pqhdr->num_irq_received) + 1,
&pqhdr->num_irq_received);
atomic_set(&virthbainfo->interrupt_rcvd, 1);
@@ -459,8 +462,8 @@ virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
struct virthba_info *virthbainfo;
int rsp;
int i;
- irq_handler_t handler = virthba_ISR;
- struct channel_header __iomem *pChannelHeader;
+ irq_handler_t handler = virthba_isr;
+ struct channel_header __iomem *channel_header;
struct signal_queue_header __iomem *pqhdr;
u64 mask;
@@ -476,7 +479,7 @@ virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
* instance - this virthba that has just been created is an
* instance of a scsi host adapter. This scsi_host_alloc
* function allocates a new Scsi_Host struct & performs basic
- * initializatoin. The host is not published to the scsi
+ * initialization. The host is not published to the scsi
* midlayer until scsi_add_host is called.
*/
DBGINF("calling scsi_host_alloc.\n");
@@ -501,19 +504,19 @@ virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
* the max-channel value.
*/
LOGINF("virtpcidev->scsi.max.max_channel=%u, max_id=%u, max_lun=%u, cmd_per_lun=%u, max_io_size=%u\n",
- (unsigned) virtpcidev->scsi.max.max_channel - 1,
- (unsigned) virtpcidev->scsi.max.max_id,
- (unsigned) virtpcidev->scsi.max.max_lun,
- (unsigned) virtpcidev->scsi.max.cmd_per_lun,
- (unsigned) virtpcidev->scsi.max.max_io_size);
- scsihost->max_channel = (unsigned) virtpcidev->scsi.max.max_channel;
- scsihost->max_id = (unsigned) virtpcidev->scsi.max.max_id;
- scsihost->max_lun = (unsigned) virtpcidev->scsi.max.max_lun;
- scsihost->cmd_per_lun = (unsigned) virtpcidev->scsi.max.cmd_per_lun;
+ (unsigned)virtpcidev->scsi.max.max_channel - 1,
+ (unsigned)virtpcidev->scsi.max.max_id,
+ (unsigned)virtpcidev->scsi.max.max_lun,
+ (unsigned)virtpcidev->scsi.max.cmd_per_lun,
+ (unsigned)virtpcidev->scsi.max.max_io_size);
+ scsihost->max_channel = (unsigned)virtpcidev->scsi.max.max_channel;
+ scsihost->max_id = (unsigned)virtpcidev->scsi.max.max_id;
+ scsihost->max_lun = (unsigned)virtpcidev->scsi.max.max_lun;
+ scsihost->cmd_per_lun = (unsigned)virtpcidev->scsi.max.cmd_per_lun;
scsihost->max_sectors =
- (unsigned short) (virtpcidev->scsi.max.max_io_size >> 9);
+ (unsigned short)(virtpcidev->scsi.max.max_io_size >> 9);
scsihost->sg_tablesize =
- (unsigned short) (virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
+ (unsigned short)(virtpcidev->scsi.max.max_io_size / PAGE_SIZE);
if (scsihost->sg_tablesize > MAX_PHYS_INFO)
scsihost->sg_tablesize = MAX_PHYS_INFO;
LOGINF("scsihost->max_channel=%u, max_id=%u, max_lun=%llu, cmd_per_lun=%u, max_sectors=%hu, sg_tablesize=%hu\n",
@@ -544,11 +547,11 @@ virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
return -ENODEV;
}
- virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ virthbainfo = (struct virthba_info *)scsihost->hostdata;
memset(virthbainfo, 0, sizeof(struct virthba_info));
for (i = 0; i < VIRTHBASOPENMAX; i++) {
- if (VirtHbasOpen[i].virthbainfo == NULL) {
- VirtHbasOpen[i].virthbainfo = virthbainfo;
+ if (virthbas_open[i].virthbainfo == NULL) {
+ virthbas_open[i].virthbainfo = virthbainfo;
break;
}
}
@@ -584,10 +587,10 @@ virthba_probe(struct virtpci_dev *virtpcidev, const struct pci_device_id *id)
DBGINF("starting rsp thread -- queueinfo: 0x%p, threadinfo: 0x%p.\n",
virthbainfo->chinfo.queueinfo, &virthbainfo->chinfo.threadinfo);
- pChannelHeader = virthbainfo->chinfo.queueinfo->chan;
+ channel_header = virthbainfo->chinfo.queueinfo->chan;
pqhdr = (struct signal_queue_header __iomem *)
- ((char __iomem *)pChannelHeader +
- readq(&pChannelHeader->ch_space_offset)) + IOCHAN_FROM_IOPART;
+ ((char __iomem *)channel_header +
+ readq(&channel_header->ch_space_offset)) + IOCHAN_FROM_IOPART;
virthbainfo->flags_addr = &pqhdr->features;
if (!uisthread_start(&virthbainfo->chinfo.threadinfo,
@@ -646,11 +649,11 @@ virthba_remove(struct virtpci_dev *virtpcidev)
{
struct virthba_info *virthbainfo;
struct Scsi_Host *scsihost =
- (struct Scsi_Host *) virtpcidev->scsi.scsihost;
+ (struct Scsi_Host *)virtpcidev->scsi.scsihost;
LOGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
virtpcidev->device_no);
- virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ virthbainfo = (struct virthba_info *)scsihost->hostdata;
if (virthbainfo->interrupt_vector != -1)
free_irq(virthbainfo->interrupt_vector, virthbainfo);
LOGINF("Removing virtpcidev: 0x%p, virthbainfo: 0x%p\n", virtpcidev,
@@ -679,7 +682,7 @@ forward_vdiskmgmt_command(enum vdisk_mgmt_types vdiskcmdtype,
{
struct uiscmdrsp *cmdrsp;
struct virthba_info *virthbainfo =
- (struct virthba_info *) scsihost->hostdata;
+ (struct virthba_info *)scsihost->hostdata;
int notifyresult = 0xffff;
wait_queue_head_t notifyevent;
@@ -706,8 +709,8 @@ forward_vdiskmgmt_command(enum vdisk_mgmt_types vdiskcmdtype,
/* specify the event that has to be triggered when this cmd is
* complete
*/
- cmdrsp->vdiskmgmt.notify = (void *) &notifyevent;
- cmdrsp->vdiskmgmt.notifyresult = (void *) &notifyresult;
+ cmdrsp->vdiskmgmt.notify = (void *)&notifyevent;
+ cmdrsp->vdiskmgmt.notifyresult = (void *)&notifyresult;
/* save destination */
cmdrsp->vdiskmgmt.vdisktype = vdiskcmdtype;
@@ -715,14 +718,14 @@ forward_vdiskmgmt_command(enum vdisk_mgmt_types vdiskcmdtype,
cmdrsp->vdiskmgmt.vdest.id = vdest->id;
cmdrsp->vdiskmgmt.vdest.lun = vdest->lun;
cmdrsp->vdiskmgmt.scsicmd =
- (void *) (uintptr_t)
+ (void *)(uintptr_t)
add_scsipending_entry_with_wait(virthbainfo, CMD_VDISKMGMT_TYPE,
- (void *) cmdrsp);
+ (void *)cmdrsp);
uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
cmdrsp, IOCHAN_TO_IOPART,
&virthbainfo->chinfo.insertlock,
- DONT_ISSUE_INTERRUPT, (u64) NULL,
+ DONT_ISSUE_INTERRUPT, (u64)NULL,
OK_TO_WAIT, "vhba");
LOGINF("VdiskMgmt waiting on event notifyevent=0x%p\n",
cmdrsp->scsitaskmgmt.notify);
@@ -742,7 +745,7 @@ forward_taskmgmt_command(enum task_mgmt_types tasktype,
{
struct uiscmdrsp *cmdrsp;
struct virthba_info *virthbainfo =
- (struct virthba_info *) scsidev->host->hostdata;
+ (struct virthba_info *)scsidev->host->hostdata;
int notifyresult = 0xffff;
wait_queue_head_t notifyevent;
@@ -767,8 +770,8 @@ forward_taskmgmt_command(enum task_mgmt_types tasktype,
cmdrsp->cmdtype = CMD_SCSITASKMGMT_TYPE;
/* specify the event that has to be triggered when this */
/* cmd is complete */
- cmdrsp->scsitaskmgmt.notify = (void *) &notifyevent;
- cmdrsp->scsitaskmgmt.notifyresult = (void *) &notifyresult;
+ cmdrsp->scsitaskmgmt.notify = (void *)&notifyevent;
+ cmdrsp->scsitaskmgmt.notifyresult = (void *)&notifyresult;
/* save destination */
cmdrsp->scsitaskmgmt.tasktype = tasktype;
@@ -776,15 +779,15 @@ forward_taskmgmt_command(enum task_mgmt_types tasktype,
cmdrsp->scsitaskmgmt.vdest.id = scsidev->id;
cmdrsp->scsitaskmgmt.vdest.lun = scsidev->lun;
cmdrsp->scsitaskmgmt.scsicmd =
- (void *) (uintptr_t)
+ (void *)(uintptr_t)
add_scsipending_entry_with_wait(virthbainfo,
CMD_SCSITASKMGMT_TYPE,
- (void *) cmdrsp);
+ (void *)cmdrsp);
uisqueue_put_cmdrsp_with_lock_client(virthbainfo->chinfo.queueinfo,
cmdrsp, IOCHAN_TO_IOPART,
&virthbainfo->chinfo.insertlock,
- DONT_ISSUE_INTERRUPT, (u64) NULL,
+ DONT_ISSUE_INTERRUPT, (u64)NULL,
OK_TO_WAIT, "vhba");
LOGINF("TaskMgmt waiting on event notifyevent=0x%p\n",
cmdrsp->scsitaskmgmt.notify);
@@ -805,11 +808,11 @@ virthba_abort_handler(struct scsi_cmnd *scsicmd)
struct virtdisk_info *vdisk;
scsidev = scsicmd->device;
- for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel == vdisk->channel)
- && (scsidev->id == vdisk->id)
- && (scsidev->lun == vdisk->lun)) {
+ if ((scsidev->channel == vdisk->channel) &&
+ (scsidev->id == vdisk->id) &&
+ (scsidev->lun == vdisk->lun)) {
if (atomic_read(&vdisk->error_count) <
VIRTHBA_ERROR_COUNT) {
atomic_inc(&vdisk->error_count);
@@ -831,11 +834,11 @@ virthba_bus_reset_handler(struct scsi_cmnd *scsicmd)
struct virtdisk_info *vdisk;
scsidev = scsicmd->device;
- for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel == vdisk->channel)
- && (scsidev->id == vdisk->id)
- && (scsidev->lun == vdisk->lun)) {
+ if ((scsidev->channel == vdisk->channel) &&
+ (scsidev->id == vdisk->id) &&
+ (scsidev->lun == vdisk->lun)) {
if (atomic_read(&vdisk->error_count) <
VIRTHBA_ERROR_COUNT) {
atomic_inc(&vdisk->error_count);
@@ -857,11 +860,11 @@ virthba_device_reset_handler(struct scsi_cmnd *scsicmd)
struct virtdisk_info *vdisk;
scsidev = scsicmd->device;
- for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel == vdisk->channel)
- && (scsidev->id == vdisk->id)
- && (scsidev->lun == vdisk->lun)) {
+ if ((scsidev->channel == vdisk->channel) &&
+ (scsidev->id == vdisk->id) &&
+ (scsidev->lun == vdisk->lun)) {
if (atomic_read(&vdisk->error_count) <
VIRTHBA_ERROR_COUNT) {
atomic_inc(&vdisk->error_count);
@@ -915,7 +918,7 @@ virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
struct uiscmdrsp *cmdrsp;
unsigned int i;
struct virthba_info *virthbainfo =
- (struct virthba_info *) scsihost->hostdata;
+ (struct virthba_info *)scsihost->hostdata;
struct scatterlist *sg = NULL;
struct scatterlist *sgl = NULL;
int sg_failed = 0;
@@ -940,9 +943,9 @@ virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
* will return the scsicmd pointer for completion
*/
insert_location =
- add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *) scsicmd);
+ add_scsipending_entry(virthbainfo, CMD_SCSI_TYPE, (void *)scsicmd);
if (insert_location != -1) {
- cmdrsp->scsi.scsicmd = (void *) (uintptr_t) insert_location;
+ cmdrsp->scsi.scsicmd = (void *)(uintptr_t)insert_location;
} else {
LOGERR("Queue is full. Returning busy.\n");
kfree(cmdrsp);
@@ -961,13 +964,13 @@ virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
cmdrsp->scsi.bufflen = scsi_bufflen(scsicmd);
/* keep track of the max buffer length so far. */
- if (cmdrsp->scsi.bufflen > MaxBuffLen)
- MaxBuffLen = cmdrsp->scsi.bufflen;
+ if (cmdrsp->scsi.bufflen > max_buff_len)
+ max_buff_len = cmdrsp->scsi.bufflen;
if (scsi_sg_count(scsicmd) > MAX_PHYS_INFO) {
LOGERR("scsicmd use_sg:%d greater than MAX:%d\n",
scsi_sg_count(scsicmd), MAX_PHYS_INFO);
- del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
+ del_scsipending_entry(virthbainfo, (uintptr_t)insert_location);
kfree(cmdrsp);
return 1; /* reject the command */
}
@@ -989,22 +992,21 @@ virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
sgl = scsi_sglist(scsicmd);
for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
-
cmdrsp->scsi.gpi_list[i].address = sg_phys(sg);
cmdrsp->scsi.gpi_list[i].length = sg->length;
if ((i != 0) && (sg->offset != 0))
LOGINF("Offset on a sg_entry other than zero =<<%d>>.\n",
- sg->offset);
+ sg->offset);
}
if (sg_failed) {
LOGERR("Start sg_list dump (entries %d, bufflen %d)...\n",
- scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen);
+ scsi_sg_count(scsicmd), cmdrsp->scsi.bufflen);
for_each_sg(sgl, sg, scsi_sg_count(scsicmd), i) {
LOGERR(" Entry(%d): page->[0x%p], phys->[0x%Lx], off(%d), len(%d)\n",
- i, sg_page(sg),
- (unsigned long long) sg_phys(sg),
- sg->offset, sg->length);
+ i, sg_page(sg),
+ (unsigned long long)sg_phys(sg),
+ sg->offset, sg->length);
}
LOGERR("Done sg_list dump.\n");
/* BUG(); ***** For now, let it fail in uissd
@@ -1022,12 +1024,12 @@ virthba_queue_command_lck(struct scsi_cmnd *scsicmd,
&virthbainfo->chinfo.
insertlock,
DONT_ISSUE_INTERRUPT,
- (u64) NULL, DONT_WAIT, "vhba");
+ (u64)NULL, DONT_WAIT, "vhba");
if (i == 0) {
/* queue must be full - and we said don't wait - return busy */
LOGERR("uisqueue_put_cmdrsp_with_lock ****FAILED\n");
kfree(cmdrsp);
- del_scsipending_entry(virthbainfo, (uintptr_t) insert_location);
+ del_scsipending_entry(virthbainfo, (uintptr_t)insert_location);
return SCSI_MLQUEUE_DEVICE_BUSY;
}
@@ -1047,9 +1049,9 @@ virthba_slave_alloc(struct scsi_device *scsidev)
struct virtdisk_info *vdisk;
struct virtdisk_info *tmpvdisk;
struct virthba_info *virthbainfo;
- struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
+ struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host;
- virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ virthbainfo = (struct virthba_info *)scsihost->hostdata;
if (!virthbainfo) {
LOGERR("Could not find virthba_info for scsihost\n");
return 0; /* even though we errored, treat as success */
@@ -1061,7 +1063,7 @@ virthba_slave_alloc(struct scsi_device *scsidev)
(vdisk->next->lun == scsidev->lun))
return 0;
}
- tmpvdisk = kzalloc(sizeof(struct virtdisk_info), GFP_ATOMIC);
+ tmpvdisk = kzalloc(sizeof(*tmpvdisk), GFP_ATOMIC);
if (!tmpvdisk) { /* error allocating */
LOGERR("Could not allocate memory for disk\n");
return 0;
@@ -1089,9 +1091,9 @@ virthba_slave_destroy(struct scsi_device *scsidev)
*/
struct virtdisk_info *vdisk, *delvdisk;
struct virthba_info *virthbainfo;
- struct Scsi_Host *scsihost = (struct Scsi_Host *) scsidev->host;
+ struct Scsi_Host *scsihost = (struct Scsi_Host *)scsidev->host;
- virthbainfo = (struct virthba_info *) scsihost->hostdata;
+ virthbainfo = (struct virthba_info *)scsihost->hostdata;
if (!virthbainfo)
LOGERR("Could not find virthba_info for scsihost\n");
for (vdisk = &virthbainfo->head; vdisk->next; vdisk = vdisk->next) {
@@ -1120,7 +1122,7 @@ do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
scsidev = scsicmd->device;
memcpy(scsicmd->sense_buffer, cmdrsp->scsi.sensebuf, MAX_SENSE_SIZE);
- sd = (struct sense_data *) scsicmd->sense_buffer;
+ sd = (struct sense_data *)scsicmd->sense_buffer;
/* Do not log errors for disk-not-present inquiries */
if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
@@ -1129,11 +1131,11 @@ do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
return;
/* Okay see what our error_count is here.... */
- for (vdisk = &((struct virthba_info *) scsidev->host->hostdata)->head;
+ for (vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel != vdisk->channel)
- || (scsidev->id != vdisk->id)
- || (scsidev->lun != vdisk->lun))
+ if ((scsidev->channel != vdisk->channel) ||
+ (scsidev->id != vdisk->id) ||
+ (scsidev->lun != vdisk->lun))
continue;
if (atomic_read(&vdisk->error_count) < VIRTHBA_ERROR_COUNT) {
@@ -1148,8 +1150,8 @@ do_scsi_linuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
if (atomic_read(&vdisk->error_count) ==
VIRTHBA_ERROR_COUNT) {
LOGERR("Throtling SCSICMD errors disk <%d:%d:%d:%llu>\n",
- scsidev->host->host_no, scsidev->id,
- scsidev->channel, scsidev->lun);
+ scsidev->host->host_no, scsidev->id,
+ scsidev->channel, scsidev->lun);
}
atomic_set(&vdisk->ios_threshold, IOS_ERROR_THRESHOLD);
}
@@ -1169,8 +1171,8 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
struct virtdisk_info *vdisk;
scsidev = scsicmd->device;
- if ((cmdrsp->scsi.cmnd[0] == INQUIRY)
- && (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
+ if ((cmdrsp->scsi.cmnd[0] == INQUIRY) &&
+ (cmdrsp->scsi.bufflen >= MIN_INQUIRY_RESULT_LEN)) {
if (cmdrsp->scsi.no_disk_result == 0)
return;
@@ -1198,21 +1200,20 @@ do_scsi_nolinuxstat(struct uiscmdrsp *cmdrsp, struct scsi_cmnd *scsicmd)
sg = scsi_sglist(scsicmd);
for (i = 0; i < scsi_sg_count(scsicmd); i++) {
DBGVER("copying OUT OF buf into 0x%p %d\n",
- sg_page(sg + i), sg[i].length);
+ sg_page(sg + i), sg[i].length);
thispage_orig = kmap_atomic(sg_page(sg + i));
- thispage = (void *) ((unsigned long)thispage_orig |
+ thispage = (void *)((unsigned long)thispage_orig |
sg[i].offset);
memcpy(thispage, buf + bufind, sg[i].length);
kunmap_atomic(thispage_orig);
bufind += sg[i].length;
}
} else {
-
vdisk = &((struct virthba_info *)scsidev->host->hostdata)->head;
for ( ; vdisk->next; vdisk = vdisk->next) {
- if ((scsidev->channel != vdisk->channel)
- || (scsidev->id != vdisk->id)
- || (scsidev->lun != vdisk->lun))
+ if ((scsidev->channel != vdisk->channel) ||
+ (scsidev->id != vdisk->id) ||
+ (scsidev->lun != vdisk->lun))
continue;
if (atomic_read(&vdisk->ios_threshold) > 0) {
@@ -1249,8 +1250,8 @@ complete_vdiskmgmt_command(struct uiscmdrsp *cmdrsp)
{
/* copy the result of the taskmgmt and */
/* wake up the error handler that is waiting for this */
- *(int *) cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
- wake_up_all((wait_queue_head_t *) cmdrsp->vdiskmgmt.notify);
+ *(int *)cmdrsp->vdiskmgmt.notifyresult = cmdrsp->vdiskmgmt.result;
+ wake_up_all((wait_queue_head_t *)cmdrsp->vdiskmgmt.notify);
LOGINF("set notify result to %d\n", cmdrsp->vdiskmgmt.result);
}
@@ -1259,15 +1260,15 @@ complete_taskmgmt_command(struct uiscmdrsp *cmdrsp)
{
/* copy the result of the taskmgmt and */
/* wake up the error handler that is waiting for this */
- *(int *) cmdrsp->scsitaskmgmt.notifyresult =
+ *(int *)cmdrsp->scsitaskmgmt.notifyresult =
cmdrsp->scsitaskmgmt.result;
- wake_up_all((wait_queue_head_t *) cmdrsp->scsitaskmgmt.notify);
+ wake_up_all((wait_queue_head_t *)cmdrsp->scsitaskmgmt.notify);
LOGINF("set notify result to %d\n", cmdrsp->scsitaskmgmt.result);
}
static void
drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
- struct uiscmdrsp *cmdrsp)
+ struct uiscmdrsp *cmdrsp)
{
unsigned long flags;
int qrslt = 0;
@@ -1277,7 +1278,7 @@ drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
while (1) {
spin_lock_irqsave(&virthbainfo->chinfo.insertlock, flags);
if (!spar_channel_client_acquire_os(dc->queueinfo->chan,
- "vhba")) {
+ "vhba")) {
spin_unlock_irqrestore(&virthbainfo->chinfo.insertlock,
flags);
virthbainfo->acquire_failed_cnt++;
@@ -1294,14 +1295,15 @@ drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
* deletion
*/
scsicmd = del_scsipending_entry(virthbainfo,
- (uintptr_t) cmdrsp->scsi.scsicmd);
+ (uintptr_t)
+ cmdrsp->scsi.scsicmd);
if (!scsicmd)
break;
/* complete the orig cmd */
complete_scsi_command(cmdrsp, scsicmd);
} else if (cmdrsp->cmdtype == CMD_SCSITASKMGMT_TYPE) {
if (!del_scsipending_entry(virthbainfo,
- (uintptr_t) cmdrsp->scsitaskmgmt.scsicmd))
+ (uintptr_t)cmdrsp->scsitaskmgmt.scsicmd))
break;
complete_taskmgmt_command(cmdrsp);
} else if (cmdrsp->cmdtype == CMD_NOTIFYGUEST_TYPE) {
@@ -1313,7 +1315,8 @@ drain_queue(struct virthba_info *virthbainfo, struct chaninfo *dc,
process_disk_notify(shost, cmdrsp);
} else if (cmdrsp->cmdtype == CMD_VDISKMGMT_TYPE) {
if (!del_scsipending_entry(virthbainfo,
- (uintptr_t) cmdrsp->vdiskmgmt.scsicmd))
+ (uintptr_t)
+ cmdrsp->vdiskmgmt.scsicmd))
break;
complete_vdiskmgmt_command(cmdrsp);
} else
@@ -1347,7 +1350,7 @@ process_incoming_rsps(void *v)
while (1) {
wait_event_interruptible_timeout(virthbainfo->rsp_queue,
(atomic_read(&virthbainfo->interrupt_rcvd) == 1),
- usecs_to_jiffies(rsltq_wait_usecs));
+ usecs_to_jiffies(rsltq_wait_usecs));
atomic_set(&virthbainfo->interrupt_rcvd, 0);
/* drain queue */
drain_queue(virthbainfo, dc, cmdrsp);
@@ -1367,7 +1370,7 @@ process_incoming_rsps(void *v)
/*****************************************************/
static ssize_t info_debugfs_read(struct file *file,
- char __user *buf, size_t len, loff_t *offset)
+ char __user *buf, size_t len, loff_t *offset)
{
ssize_t bytes_read = 0;
int str_pos = 0;
@@ -1383,13 +1386,14 @@ static ssize_t info_debugfs_read(struct file *file,
return -ENOMEM;
for (i = 0; i < VIRTHBASOPENMAX; i++) {
- if (VirtHbasOpen[i].virthbainfo == NULL)
+ if (virthbas_open[i].virthbainfo == NULL)
continue;
- virthbainfo = VirtHbasOpen[i].virthbainfo;
+ virthbainfo = virthbas_open[i].virthbainfo;
str_pos += scnprintf(vbuf + str_pos,
- len - str_pos, "MaxBuffLen:%u\n", MaxBuffLen);
+ len - str_pos, "max_buff_len:%u\n",
+ max_buff_len);
str_pos += scnprintf(vbuf + str_pos, len - str_pos,
"\nvirthba result queue poll wait:%d usecs.\n",
@@ -1418,14 +1422,14 @@ static ssize_t info_debugfs_read(struct file *file,
return bytes_read;
}
-static ssize_t enable_ints_write(struct file *file,
- const char __user *buffer, size_t count, loff_t *ppos)
+static ssize_t enable_ints_write(struct file *file, const char __user *buffer,
+ size_t count, loff_t *ppos)
{
char buf[4];
int i, new_value;
struct virthba_info *virthbainfo;
- u64 __iomem *Features_addr;
+ u64 __iomem *features_addr;
u64 mask;
if (count >= ARRAY_SIZE(buf))
@@ -1434,37 +1438,37 @@ static ssize_t enable_ints_write(struct file *file,
buf[count] = '\0';
if (copy_from_user(buf, buffer, count)) {
LOGERR("copy_from_user failed. buf<<%.*s>> count<<%lu>>\n",
- (int) count, buf, count);
+ (int)count, buf, count);
return -EFAULT;
}
- i = kstrtoint(buf, 10 , &new_value);
+ i = kstrtoint(buf, 10, &new_value);
if (i != 0) {
LOGERR("Failed to scan value for enable_ints, buf<<%.*s>>",
- (int) count, buf);
+ (int)count, buf);
return -EFAULT;
}
/* set all counts to new_value usually 0 */
for (i = 0; i < VIRTHBASOPENMAX; i++) {
- if (VirtHbasOpen[i].virthbainfo != NULL) {
- virthbainfo = VirtHbasOpen[i].virthbainfo;
- Features_addr =
+ if (virthbas_open[i].virthbainfo != NULL) {
+ virthbainfo = virthbas_open[i].virthbainfo;
+ features_addr =
&virthbainfo->chinfo.queueinfo->chan->features;
if (new_value == 1) {
mask = ~(ULTRA_IO_CHANNEL_IS_POLLING |
ULTRA_IO_DRIVER_DISABLES_INTS);
- uisqueue_interlocked_and(Features_addr, mask);
+ uisqueue_interlocked_and(features_addr, mask);
mask = ULTRA_IO_DRIVER_ENABLES_INTS;
- uisqueue_interlocked_or(Features_addr, mask);
+ uisqueue_interlocked_or(features_addr, mask);
rsltq_wait_usecs = 4000000;
} else {
mask = ~(ULTRA_IO_DRIVER_ENABLES_INTS |
ULTRA_IO_DRIVER_DISABLES_INTS);
- uisqueue_interlocked_and(Features_addr, mask);
+ uisqueue_interlocked_and(features_addr, mask);
mask = ULTRA_IO_CHANNEL_IS_POLLING;
- uisqueue_interlocked_or(Features_addr, mask);
+ uisqueue_interlocked_or(features_addr, mask);
rsltq_wait_usecs = 4000;
}
}
@@ -1477,7 +1481,7 @@ static int
virthba_serverup(struct virtpci_dev *virtpcidev)
{
struct virthba_info *virthbainfo =
- (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
+ (struct virthba_info *)((struct Scsi_Host *)virtpcidev->scsi.
scsihost)->hostdata;
DBGINF("virtpcidev bus_no<<%d>>devNo<<%d>>", virtpcidev->bus_no,
@@ -1535,26 +1539,26 @@ virthba_serverdown_complete(struct work_struct *work)
/* Fail Commands that weren't completed */
spin_lock_irqsave(&virthbainfo->privlock, flags);
for (i = 0; i < MAX_PENDING_REQUESTS; i++) {
- pendingdel = &(virthbainfo->pending[i]);
+ pendingdel = &virthbainfo->pending[i];
switch (pendingdel->cmdtype) {
case CMD_SCSI_TYPE:
- scsicmd = (struct scsi_cmnd *) pendingdel->sent;
+ scsicmd = (struct scsi_cmnd *)pendingdel->sent;
scsicmd->result = (DID_RESET << 16);
if (scsicmd->scsi_done)
scsicmd->scsi_done(scsicmd);
break;
case CMD_SCSITASKMGMT_TYPE:
- cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
+ cmdrsp = (struct uiscmdrsp *)pendingdel->sent;
DBGINF("cmdrsp=0x%x, notify=0x%x\n", cmdrsp,
cmdrsp->scsitaskmgmt.notify);
- *(int *) cmdrsp->scsitaskmgmt.notifyresult =
+ *(int *)cmdrsp->scsitaskmgmt.notifyresult =
TASK_MGMT_FAILED;
wake_up_all((wait_queue_head_t *)
cmdrsp->scsitaskmgmt.notify);
break;
case CMD_VDISKMGMT_TYPE:
- cmdrsp = (struct uiscmdrsp *) pendingdel->sent;
- *(int *) cmdrsp->vdiskmgmt.notifyresult =
+ cmdrsp = (struct uiscmdrsp *)pendingdel->sent;
+ *(int *)cmdrsp->vdiskmgmt.notifyresult =
VDISK_MGMT_FAILED;
wake_up_all((wait_queue_head_t *)
cmdrsp->vdiskmgmt.notify);
@@ -1584,8 +1588,10 @@ virthba_serverdown_complete(struct work_struct *work)
static int
virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
{
+ int stat = 1;
+
struct virthba_info *virthbainfo =
- (struct virthba_info *) ((struct Scsi_Host *) virtpcidev->scsi.
+ (struct virthba_info *)((struct Scsi_Host *)virtpcidev->scsi.
scsihost)->hostdata;
DBGINF("virthba_serverdown");
@@ -1598,11 +1604,12 @@ virthba_serverdown(struct virtpci_dev *virtpcidev, u32 state)
&virthbainfo->serverdown_completion);
} else if (virthbainfo->serverchangingstate) {
LOGERR("Server already processing change state message\n");
- return 0;
- } else
+ stat = 0;
+ } else {
LOGERR("Server already down, but another server down message received.");
+ }
- return 1;
+ return stat;
}
/*****************************************************/
@@ -1655,23 +1662,22 @@ virthba_mod_init(void)
POSTCODE_LINUX_3(VHBA_CREATE_FAILURE_PC, error,
POSTCODE_SEVERITY_ERR);
} else {
-
/* create the debugfs directories and entries */
virthba_debugfs_dir = debugfs_create_dir("virthba", NULL);
debugfs_create_file("info", S_IRUSR, virthba_debugfs_dir,
- NULL, &debugfs_info_fops);
+ NULL, &debugfs_info_fops);
debugfs_create_u32("rqwait_usecs", S_IRUSR | S_IWUSR,
- virthba_debugfs_dir, &rsltq_wait_usecs);
+ virthba_debugfs_dir, &rsltq_wait_usecs);
debugfs_create_file("enable_ints", S_IWUSR,
- virthba_debugfs_dir, NULL,
- &debugfs_enable_ints_fops);
- /* Initialize DARWorkQ */
- INIT_WORK(&DARWorkQ, doDiskAddRemove);
- spin_lock_init(&DARWorkQLock);
+ virthba_debugfs_dir, NULL,
+ &debugfs_enable_ints_fops);
+ /* Initialize dar_work_queue */
+ INIT_WORK(&dar_work_queue, do_disk_add_remove);
+ spin_lock_init(&dar_work_queue_lock);
/* clear out array */
for (i = 0; i < VIRTHBASOPENMAX; i++)
- VirtHbasOpen[i].virthbainfo = NULL;
+ virthbas_open[i].virthbainfo = NULL;
/* Initialize the serverdown workqueue */
virthba_serverdown_workqueue =
create_singlethread_workqueue("virthba_serverdown");
@@ -1746,7 +1752,6 @@ virthba_mod_exit(void)
debugfs_remove_recursive(virthba_debugfs_dir);
LOGINF("Leaving virthba_mod_exit\n");
-
}
/* specify function to be run at module insertion time */
diff --git a/drivers/staging/unisys/virtpci/virtpci.c b/drivers/staging/unisys/virtpci/virtpci.c
index 39b828dce503..8fdfd6f3605f 100644
--- a/drivers/staging/unisys/virtpci/virtpci.c
+++ b/drivers/staging/unisys/virtpci/virtpci.c
@@ -104,8 +104,6 @@ static ssize_t virtpci_driver_attr_store(struct kobject *kobj,
const char *buf, size_t count);
static int virtpci_bus_match(struct device *dev, struct device_driver *drv);
static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env);
-static int virtpci_device_suspend(struct device *dev, pm_message_t state);
-static int virtpci_device_resume(struct device *dev);
static int virtpci_device_probe(struct device *dev);
static int virtpci_device_remove(struct device *dev);
@@ -128,8 +126,6 @@ static struct bus_type virtpci_bus_type = {
.name = "uisvirtpci",
.match = virtpci_bus_match,
.uevent = virtpci_uevent,
- .suspend = virtpci_device_suspend,
- .resume = virtpci_device_resume,
};
static struct device virtpci_rootbus_device = {
@@ -279,9 +275,9 @@ static int add_vbus(struct add_vbus_guestpart *addparams)
POSTCODE_LINUX_2(VPCI_CREATE_FAILURE_PC, POSTCODE_SEVERITY_ERR);
return 0;
}
- write_vbus_chp_info(vbus->platform_data /* chanptr */ ,
+ write_vbus_chp_info(vbus->platform_data /* chanptr */,
&chipset_driver_info);
- write_vbus_bus_info(vbus->platform_data /* chanptr */ ,
+ write_vbus_bus_info(vbus->platform_data /* chanptr */,
&bus_driver_info);
LOGINF("Added vbus %d; device %s created successfully\n",
addparams->bus_no, BUS_ID(vbus));
@@ -466,7 +462,7 @@ static int pause_vhba(struct pause_virt_guestpart *pauseparams)
GET_SCSIADAPINFO_FROM_CHANPTR(pauseparams->chanptr);
LOGINF("Pausing vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
- i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTHBA_TYPE,
+ i = virtpci_device_serverdown(NULL /*no parent bus */, VIRTHBA_TYPE,
&scsi.wwnn, NULL);
if (i)
LOGINF("Paused vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
@@ -487,7 +483,7 @@ static int pause_vnic(struct pause_virt_guestpart *pauseparams)
LOGINF("Pausing vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
- i = virtpci_device_serverdown(NULL /*no parent bus */ , VIRTNIC_TYPE,
+ i = virtpci_device_serverdown(NULL /*no parent bus */, VIRTNIC_TYPE,
NULL, net.mac_addr);
if (i) {
LOGINF(" Paused vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -508,7 +504,7 @@ static int resume_vhba(struct resume_virt_guestpart *resumeparams)
GET_SCSIADAPINFO_FROM_CHANPTR(resumeparams->chanptr);
LOGINF("Resuming vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
- i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTHBA_TYPE,
+ i = virtpci_device_serverup(NULL /*no parent bus */, VIRTHBA_TYPE,
&scsi.wwnn, NULL);
if (i)
LOGINF("Resumed vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
@@ -530,7 +526,7 @@ resume_vnic(struct resume_virt_guestpart *resumeparams)
LOGINF("Resuming vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
- i = virtpci_device_serverup(NULL /*no parent bus */ , VIRTNIC_TYPE,
+ i = virtpci_device_serverup(NULL /*no parent bus */, VIRTNIC_TYPE,
NULL, net.mac_addr);
if (i) {
LOGINF(" Resumed vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -551,7 +547,7 @@ static int delete_vhba(struct del_virt_guestpart *delparams)
GET_SCSIADAPINFO_FROM_CHANPTR(delparams->chanptr);
LOGINF("Deleting vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1, scsi.wwnn.wwnn2);
- i = virtpci_device_del(NULL /*no parent bus */ , VIRTHBA_TYPE,
+ i = virtpci_device_del(NULL /*no parent bus */, VIRTHBA_TYPE,
&scsi.wwnn, NULL);
if (i) {
LOGINF("Deleted vhba wwnn:%x:%x\n", scsi.wwnn.wwnn1,
@@ -574,7 +570,7 @@ static int delete_vnic(struct del_virt_guestpart *delparams)
LOGINF("Deleting vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
net.mac_addr[0], net.mac_addr[1], net.mac_addr[2],
net.mac_addr[3], net.mac_addr[4], net.mac_addr[5]);
- i = virtpci_device_del(NULL /*no parent bus */ , VIRTNIC_TYPE, NULL,
+ i = virtpci_device_del(NULL /*no parent bus */, VIRTNIC_TYPE, NULL,
net.mac_addr);
if (i) {
LOGINF("Deleted vnic macaddr:%02x:%02x:%02x:%02x:%02x:%02x\n",
@@ -757,18 +753,6 @@ static int virtpci_uevent(struct device *dev, struct kobj_uevent_env *env)
return 0;
}
-static int virtpci_device_suspend(struct device *dev, pm_message_t state)
-{
- DBGINF("In virtpci_device_suspend -NYI ****\n");
- return 0;
-}
-
-static int virtpci_device_resume(struct device *dev)
-{
- DBGINF("In virtpci_device_resume -NYI ****\n");
- return 0;
-}
-
/* For a child device just created on a client bus, fill in
* information about the driver that is controlling this device into
* the appropriate slot within the vbus channel of the bus
@@ -1338,18 +1322,13 @@ static ssize_t virtpci_driver_attr_show(struct kobject *kobj,
ssize_t ret = 0;
struct driver_private *dprivate = to_driver(kobj);
- struct device_driver *driver;
+ struct device_driver *driver = dprivate->driver;
- if (dprivate != NULL)
- driver = dprivate->driver;
- else
- driver = NULL;
+ DBGINF("In virtpci_driver_attr_show driver->name:%s\n", driver->name);
+
+ if (dattr->show)
+ ret = dattr->show(driver, buf);
- DBGINF("In virtpci_driver_attr_show driver->name:%s\n", driver->name);
- if (driver) {
- if (dattr->show)
- ret = dattr->show(driver, buf);
- }
return ret;
}
@@ -1361,19 +1340,13 @@ static ssize_t virtpci_driver_attr_store(struct kobject *kobj,
ssize_t ret = 0;
struct driver_private *dprivate = to_driver(kobj);
- struct device_driver *driver;
-
- if (dprivate != NULL)
- driver = dprivate->driver;
- else
- driver = NULL;
+ struct device_driver *driver = dprivate->driver;
DBGINF("In virtpci_driver_attr_store driver->name:%s\n", driver->name);
- if (driver) {
- if (dattr->store)
- ret = dattr->store(driver, buf, count);
- }
+ if (dattr->store)
+ ret = dattr->store(driver, buf, count);
+
return ret;
}
diff --git a/drivers/staging/unisys/visorchannel/visorchannel.h b/drivers/staging/unisys/visorchannel/visorchannel.h
index 5061edff959a..63f1b9760373 100644
--- a/drivers/staging/unisys/visorchannel/visorchannel.h
+++ b/drivers/staging/unisys/visorchannel/visorchannel.h
@@ -29,49 +29,48 @@
#define BOOL int
#endif
-/* VISORCHANNEL is an opaque structure to users.
- * Fields are declared only in the implementation .c files.
- */
-typedef struct VISORCHANNEL_Tag VISORCHANNEL;
-
/* Note that for visorchannel_create() and visorchannel_create_overlapped(),
- * <channelBytes> and <guid> arguments may be 0 if we are a channel CLIENT.
+ * <channel_bytes> and <guid> arguments may be 0 if we are a channel CLIENT.
* In this case, the values can simply be read from the channel header.
*/
-VISORCHANNEL *visorchannel_create(HOSTADDRESS physaddr,
- ulong channelBytes, uuid_le guid);
-VISORCHANNEL *visorchannel_create_overlapped(ulong channelBytes,
- VISORCHANNEL *parent, ulong off,
- uuid_le guid);
-VISORCHANNEL *visorchannel_create_with_lock(HOSTADDRESS physaddr,
- ulong channelBytes, uuid_le guid);
-VISORCHANNEL *visorchannel_create_overlapped_with_lock(ulong channelBytes,
- VISORCHANNEL *parent,
- ulong off, uuid_le guid);
-void visorchannel_destroy(VISORCHANNEL *channel);
-int visorchannel_read(VISORCHANNEL *channel, ulong offset,
+struct visorchannel *visorchannel_create(HOSTADDRESS physaddr,
+ ulong channel_bytes, uuid_le guid);
+struct visorchannel *visorchannel_create_overlapped(ulong channel_bytes,
+ struct visorchannel *parent,
+ ulong off, uuid_le guid);
+struct visorchannel *visorchannel_create_with_lock(HOSTADDRESS physaddr,
+ ulong channel_bytes,
+ uuid_le guid);
+struct visorchannel *visorchannel_create_overlapped_with_lock(
+ ulong channel_bytes,
+ struct visorchannel *parent,
+ ulong off, uuid_le guid);
+void visorchannel_destroy(struct visorchannel *channel);
+int visorchannel_read(struct visorchannel *channel, ulong offset,
void *local, ulong nbytes);
-int visorchannel_write(VISORCHANNEL *channel, ulong offset,
+int visorchannel_write(struct visorchannel *channel, ulong offset,
void *local, ulong nbytes);
-int visorchannel_clear(VISORCHANNEL *channel, ulong offset,
+int visorchannel_clear(struct visorchannel *channel, ulong offset,
u8 ch, ulong nbytes);
-BOOL visorchannel_signalremove(VISORCHANNEL *channel, u32 queue, void *msg);
-BOOL visorchannel_signalinsert(VISORCHANNEL *channel, u32 queue, void *msg);
-int visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, u32 queue);
-int visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, u32 queue);
-
-HOSTADDRESS visorchannel_get_physaddr(VISORCHANNEL *channel);
-ulong visorchannel_get_nbytes(VISORCHANNEL *channel);
-char *visorchannel_id(VISORCHANNEL *channel, char *s);
-char *visorchannel_zoneid(VISORCHANNEL *channel, char *s);
-u64 visorchannel_get_clientpartition(VISORCHANNEL *channel);
-uuid_le visorchannel_get_uuid(VISORCHANNEL *channel);
-struct memregion *visorchannel_get_memregion(VISORCHANNEL *channel);
+BOOL visorchannel_signalremove(struct visorchannel *channel, u32 queue,
+ void *msg);
+BOOL visorchannel_signalinsert(struct visorchannel *channel, u32 queue,
+ void *msg);
+int visorchannel_signalqueue_slots_avail(struct visorchannel *channel,
+ u32 queue);
+int visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue);
+HOSTADDRESS visorchannel_get_physaddr(struct visorchannel *channel);
+ulong visorchannel_get_nbytes(struct visorchannel *channel);
+char *visorchannel_id(struct visorchannel *channel, char *s);
+char *visorchannel_zoneid(struct visorchannel *channel, char *s);
+u64 visorchannel_get_clientpartition(struct visorchannel *channel);
+uuid_le visorchannel_get_uuid(struct visorchannel *channel);
+struct memregion *visorchannel_get_memregion(struct visorchannel *channel);
char *visorchannel_uuid_id(uuid_le *guid, char *s);
-void visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+void visorchannel_debug(struct visorchannel *channel, int num_queues,
struct seq_file *seq, u32 off);
-void visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+void visorchannel_dump_section(struct visorchannel *chan, char *s,
int off, int len, struct seq_file *seq);
-void __iomem *visorchannel_get_header(VISORCHANNEL *channel);
+void __iomem *visorchannel_get_header(struct visorchannel *channel);
#endif
diff --git a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
index 36559d5fa673..0188ef866fdd 100644
--- a/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
+++ b/drivers/staging/unisys/visorchannel/visorchannel_funcs.c
@@ -28,14 +28,15 @@
#define MYDRVNAME "visorchannel"
-struct VISORCHANNEL_Tag {
+struct visorchannel {
struct memregion *memregion; /* from visor_memregion_create() */
struct channel_header chan_hdr;
uuid_le guid;
ulong size;
- BOOL needs_lock;
- spinlock_t insert_lock;
- spinlock_t remove_lock;
+ BOOL needs_lock; /* channel creator knows if more than one
+ * thread will be inserting or removing */
+ spinlock_t insert_lock; /* protect head writes in chan_hdr */
+ spinlock_t remove_lock; /* protect tail writes in chan_hdr */
struct {
struct signal_queue_header req_queue;
@@ -45,18 +46,18 @@ struct VISORCHANNEL_Tag {
} safe_uis_queue;
};
-/* Creates the VISORCHANNEL abstraction for a data area in memory, but does
- * NOT modify this data area.
+/* Creates the struct visorchannel abstraction for a data area in memory,
+ * but does NOT modify this data area.
*/
-static VISORCHANNEL *
-visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
- VISORCHANNEL *parent, ulong off, uuid_le guid,
+static struct visorchannel *
+visorchannel_create_guts(HOSTADDRESS physaddr, ulong channel_bytes,
+ struct visorchannel *parent, ulong off, uuid_le guid,
BOOL needs_lock)
{
- VISORCHANNEL *p = NULL;
+ struct visorchannel *p = NULL;
void *rc = NULL;
- p = kmalloc(sizeof(VISORCHANNEL), GFP_KERNEL|__GFP_NORETRY);
+ p = kmalloc(sizeof(*p), GFP_KERNEL|__GFP_NORETRY);
if (p == NULL) {
ERRDRV("allocation failed: (status=0)\n");
rc = NULL;
@@ -87,18 +88,18 @@ visorchannel_create_guts(HOSTADDRESS physaddr, ulong channelBytes,
rc = NULL;
goto cleanup;
}
- if (channelBytes == 0)
+ if (channel_bytes == 0)
/* we had better be a CLIENT of this channel */
- channelBytes = (ulong)p->chan_hdr.size;
+ channel_bytes = (ulong)p->chan_hdr.size;
if (uuid_le_cmp(guid, NULL_UUID_LE) == 0)
/* we had better be a CLIENT of this channel */
guid = p->chan_hdr.chtype;
- if (visor_memregion_resize(p->memregion, channelBytes) < 0) {
+ if (visor_memregion_resize(p->memregion, channel_bytes) < 0) {
ERRDRV("visor_memregion_resize failed: (status=0)\n");
rc = NULL;
goto cleanup;
}
- p->size = channelBytes;
+ p->size = channel_bytes;
p->guid = guid;
rc = p;
@@ -113,44 +114,45 @@ cleanup:
return rc;
}
-VISORCHANNEL *
-visorchannel_create(HOSTADDRESS physaddr, ulong channelBytes, uuid_le guid)
+struct visorchannel *
+visorchannel_create(HOSTADDRESS physaddr, ulong channel_bytes, uuid_le guid)
{
- return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+ return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid,
FALSE);
}
EXPORT_SYMBOL_GPL(visorchannel_create);
-VISORCHANNEL *
-visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channelBytes,
+struct visorchannel *
+visorchannel_create_with_lock(HOSTADDRESS physaddr, ulong channel_bytes,
uuid_le guid)
{
- return visorchannel_create_guts(physaddr, channelBytes, NULL, 0, guid,
+ return visorchannel_create_guts(physaddr, channel_bytes, NULL, 0, guid,
TRUE);
}
EXPORT_SYMBOL_GPL(visorchannel_create_with_lock);
-VISORCHANNEL *
-visorchannel_create_overlapped(ulong channelBytes,
- VISORCHANNEL *parent, ulong off, uuid_le guid)
+struct visorchannel *
+visorchannel_create_overlapped(ulong channel_bytes,
+ struct visorchannel *parent, ulong off,
+ uuid_le guid)
{
- return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+ return visorchannel_create_guts(0, channel_bytes, parent, off, guid,
FALSE);
}
EXPORT_SYMBOL_GPL(visorchannel_create_overlapped);
-VISORCHANNEL *
-visorchannel_create_overlapped_with_lock(ulong channelBytes,
- VISORCHANNEL *parent, ulong off,
+struct visorchannel *
+visorchannel_create_overlapped_with_lock(ulong channel_bytes,
+ struct visorchannel *parent, ulong off,
uuid_le guid)
{
- return visorchannel_create_guts(0, channelBytes, parent, off, guid,
+ return visorchannel_create_guts(0, channel_bytes, parent, off, guid,
TRUE);
}
EXPORT_SYMBOL_GPL(visorchannel_create_overlapped_with_lock);
void
-visorchannel_destroy(VISORCHANNEL *channel)
+visorchannel_destroy(struct visorchannel *channel)
{
if (channel == NULL)
return;
@@ -163,14 +165,14 @@ visorchannel_destroy(VISORCHANNEL *channel)
EXPORT_SYMBOL_GPL(visorchannel_destroy);
HOSTADDRESS
-visorchannel_get_physaddr(VISORCHANNEL *channel)
+visorchannel_get_physaddr(struct visorchannel *channel)
{
return visor_memregion_get_physaddr(channel->memregion);
}
EXPORT_SYMBOL_GPL(visorchannel_get_physaddr);
ulong
-visorchannel_get_nbytes(VISORCHANNEL *channel)
+visorchannel_get_nbytes(struct visorchannel *channel)
{
return channel->size;
}
@@ -185,42 +187,42 @@ visorchannel_uuid_id(uuid_le *guid, char *s)
EXPORT_SYMBOL_GPL(visorchannel_uuid_id);
char *
-visorchannel_id(VISORCHANNEL *channel, char *s)
+visorchannel_id(struct visorchannel *channel, char *s)
{
return visorchannel_uuid_id(&channel->guid, s);
}
EXPORT_SYMBOL_GPL(visorchannel_id);
char *
-visorchannel_zoneid(VISORCHANNEL *channel, char *s)
+visorchannel_zoneid(struct visorchannel *channel, char *s)
{
return visorchannel_uuid_id(&channel->chan_hdr.zone_uuid, s);
}
EXPORT_SYMBOL_GPL(visorchannel_zoneid);
HOSTADDRESS
-visorchannel_get_clientpartition(VISORCHANNEL *channel)
+visorchannel_get_clientpartition(struct visorchannel *channel)
{
return channel->chan_hdr.partition_handle;
}
EXPORT_SYMBOL_GPL(visorchannel_get_clientpartition);
uuid_le
-visorchannel_get_uuid(VISORCHANNEL *channel)
+visorchannel_get_uuid(struct visorchannel *channel)
{
return channel->guid;
}
EXPORT_SYMBOL_GPL(visorchannel_get_uuid);
struct memregion *
-visorchannel_get_memregion(VISORCHANNEL *channel)
+visorchannel_get_memregion(struct visorchannel *channel)
{
return channel->memregion;
}
EXPORT_SYMBOL_GPL(visorchannel_get_memregion);
int
-visorchannel_read(VISORCHANNEL *channel, ulong offset,
+visorchannel_read(struct visorchannel *channel, ulong offset,
void *local, ulong nbytes)
{
int rc = visor_memregion_read(channel->memregion, offset,
@@ -235,7 +237,7 @@ visorchannel_read(VISORCHANNEL *channel, ulong offset,
EXPORT_SYMBOL_GPL(visorchannel_read);
int
-visorchannel_write(VISORCHANNEL *channel, ulong offset,
+visorchannel_write(struct visorchannel *channel, ulong offset,
void *local, ulong nbytes)
{
if (offset == 0 && nbytes >= sizeof(struct channel_header))
@@ -246,7 +248,8 @@ visorchannel_write(VISORCHANNEL *channel, ulong offset,
EXPORT_SYMBOL_GPL(visorchannel_write);
int
-visorchannel_clear(VISORCHANNEL *channel, ulong offset, u8 ch, ulong nbytes)
+visorchannel_clear(struct visorchannel *channel, ulong offset, u8 ch,
+ ulong nbytes)
{
int rc = -1;
int bufsize = 65536;
@@ -285,7 +288,7 @@ cleanup:
EXPORT_SYMBOL_GPL(visorchannel_clear);
void __iomem *
-visorchannel_get_header(VISORCHANNEL *channel)
+visorchannel_get_header(struct visorchannel *channel)
{
return (void __iomem *)&channel->chan_hdr;
}
@@ -316,7 +319,7 @@ EXPORT_SYMBOL_GPL(visorchannel_get_header);
sizeof((sig_hdr)->FIELD)) >= 0)
static BOOL
-sig_read_header(VISORCHANNEL *channel, u32 queue,
+sig_read_header(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr)
{
BOOL rc = FALSE;
@@ -344,7 +347,7 @@ cleanup:
}
static BOOL
-sig_do_data(VISORCHANNEL *channel, u32 queue,
+sig_do_data(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr, u32 slot, void *data,
BOOL is_write)
{
@@ -373,14 +376,14 @@ cleanup:
}
static inline BOOL
-sig_read_data(VISORCHANNEL *channel, u32 queue,
+sig_read_data(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr, u32 slot, void *data)
{
return sig_do_data(channel, queue, sig_hdr, slot, data, FALSE);
}
static inline BOOL
-sig_write_data(VISORCHANNEL *channel, u32 queue,
+sig_write_data(struct visorchannel *channel, u32 queue,
struct signal_queue_header *sig_hdr, u32 slot, void *data)
{
return sig_do_data(channel, queue, sig_hdr, slot, data, TRUE);
@@ -408,27 +411,21 @@ safe_sig_queue_validate(struct signal_queue_header *psafe_sqh,
return 1;
} /* end safe_sig_queue_validate */
-BOOL
-visorchannel_signalremove(VISORCHANNEL *channel, u32 queue, void *msg)
+static BOOL
+signalremove_inner(struct visorchannel *channel, u32 queue, void *msg)
{
- BOOL rc = FALSE;
struct signal_queue_header sig_hdr;
- if (channel->needs_lock)
- spin_lock(&channel->remove_lock);
-
if (!sig_read_header(channel, queue, &sig_hdr)) {
- rc = FALSE;
- goto cleanup;
- }
- if (sig_hdr.head == sig_hdr.tail) {
- rc = FALSE; /* no signals to remove */
- goto cleanup;
+ return FALSE;
}
+ if (sig_hdr.head == sig_hdr.tail)
+ return FALSE; /* no signals to remove */
+
sig_hdr.tail = (sig_hdr.tail + 1) % sig_hdr.max_slots;
if (!sig_read_data(channel, queue, &sig_hdr, sig_hdr.tail, msg)) {
- ERRDRV("sig_read_data failed: (status=%d)\n", rc);
- goto cleanup;
+ ERRDRV("sig_read_data failed\n");
+ return FALSE;
}
sig_hdr.num_received++;
@@ -437,53 +434,54 @@ visorchannel_signalremove(VISORCHANNEL *channel, u32 queue, void *msg)
*/
mb(); /* required for channel synch */
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, tail)) {
- ERRDRV("visor_memregion_write of Tail failed: (status=%d)\n",
- rc);
- goto cleanup;
+ ERRDRV("visor_memregion_write of Tail failed\n");
+ return FALSE;
}
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_received)) {
- ERRDRV("visor_memregion_write of NumSignalsReceived failed: (status=%d)\n",
- rc);
- goto cleanup;
+ ERRDRV("visor_memregion_write of NumSignalsReceived failed\n");
+ return FALSE;
}
- rc = TRUE;
-cleanup:
- if (channel->needs_lock)
+ return TRUE;
+}
+
+BOOL
+visorchannel_signalremove(struct visorchannel *channel, u32 queue, void *msg)
+{
+ BOOL rc;
+
+ if (channel->needs_lock) {
+ spin_lock(&channel->remove_lock);
+ rc = signalremove_inner(channel, queue, msg);
spin_unlock(&channel->remove_lock);
+ } else {
+ rc = signalremove_inner(channel, queue, msg);
+ }
return rc;
}
EXPORT_SYMBOL_GPL(visorchannel_signalremove);
-BOOL
-visorchannel_signalinsert(VISORCHANNEL *channel, u32 queue, void *msg)
+static BOOL
+signalinsert_inner(struct visorchannel *channel, u32 queue, void *msg)
{
- BOOL rc = FALSE;
struct signal_queue_header sig_hdr;
- if (channel->needs_lock)
- spin_lock(&channel->insert_lock);
-
if (!sig_read_header(channel, queue, &sig_hdr)) {
- rc = FALSE;
- goto cleanup;
+ return FALSE;
}
sig_hdr.head = ((sig_hdr.head + 1) % sig_hdr.max_slots);
if (sig_hdr.head == sig_hdr.tail) {
sig_hdr.num_overflows++;
- if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows)) {
- ERRDRV("visor_memregion_write of NumOverflows failed: (status=%d)\n",
- rc);
- goto cleanup;
- }
- rc = FALSE;
- goto cleanup;
+ if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_overflows))
+ ERRDRV("visor_memregion_write of NumOverflows failed\n");
+
+ return FALSE;
}
if (!sig_write_data(channel, queue, &sig_hdr, sig_hdr.head, msg)) {
- ERRDRV("sig_write_data failed: (status=%d)\n", rc);
- goto cleanup;
+ ERRDRV("sig_write_data failed\n");
+ return FALSE;
}
sig_hdr.num_sent++;
@@ -492,26 +490,36 @@ visorchannel_signalinsert(VISORCHANNEL *channel, u32 queue, void *msg)
*/
mb(); /* required for channel synch */
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, head)) {
- ERRDRV("visor_memregion_write of Head failed: (status=%d)\n",
- rc);
- goto cleanup;
+ ERRDRV("visor_memregion_write of Head failed\n");
+ return FALSE;
}
if (!SIG_WRITE_FIELD(channel, queue, &sig_hdr, num_sent)) {
- ERRDRV("visor_memregion_write of NumSignalsSent failed: (status=%d)\n",
- rc);
- goto cleanup;
+ ERRDRV("visor_memregion_write of NumSignalsSent failed\n");
+ return FALSE;
}
- rc = TRUE;
-cleanup:
- if (channel->needs_lock)
+
+ return TRUE;
+}
+
+BOOL
+visorchannel_signalinsert(struct visorchannel *channel, u32 queue, void *msg)
+{
+ BOOL rc;
+
+ if (channel->needs_lock) {
+ spin_lock(&channel->insert_lock);
+ rc = signalinsert_inner(channel, queue, msg);
spin_unlock(&channel->insert_lock);
+ } else {
+ rc = signalinsert_inner(channel, queue, msg);
+ }
return rc;
}
EXPORT_SYMBOL_GPL(visorchannel_signalinsert);
int
-visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, u32 queue)
+visorchannel_signalqueue_slots_avail(struct visorchannel *channel, u32 queue)
{
struct signal_queue_header sig_hdr;
u32 slots_avail, slots_used;
@@ -530,7 +538,7 @@ visorchannel_signalqueue_slots_avail(VISORCHANNEL *channel, u32 queue)
EXPORT_SYMBOL_GPL(visorchannel_signalqueue_slots_avail);
int
-visorchannel_signalqueue_max_slots(VISORCHANNEL *channel, u32 queue)
+visorchannel_signalqueue_max_slots(struct visorchannel *channel, u32 queue)
{
struct signal_queue_header sig_hdr;
@@ -565,7 +573,7 @@ sigqueue_debug(struct signal_queue_header *q, int which, struct seq_file *seq)
}
void
-visorchannel_debug(VISORCHANNEL *channel, int nQueues,
+visorchannel_debug(struct visorchannel *channel, int num_queues,
struct seq_file *seq, u32 off)
{
HOSTADDRESS addr = 0;
@@ -625,7 +633,7 @@ visorchannel_debug(VISORCHANNEL *channel, int nQueues,
if ((phdr->ch_space_offset == 0) || (errcode < 0))
;
else
- for (i = 0; i < nQueues; i++) {
+ for (i = 0; i < num_queues; i++) {
struct signal_queue_header q;
errcode = visorchannel_read(channel,
@@ -647,7 +655,7 @@ visorchannel_debug(VISORCHANNEL *channel, int nQueues,
EXPORT_SYMBOL_GPL(visorchannel_debug);
void
-visorchannel_dump_section(VISORCHANNEL *chan, char *s,
+visorchannel_dump_section(struct visorchannel *chan, char *s,
int off, int len, struct seq_file *seq)
{
char *buf, *tbuf, *fmtbuf;
diff --git a/drivers/staging/unisys/visorchipset/file.c b/drivers/staging/unisys/visorchipset/file.c
index 373fa36b7119..e51fd4e3fa2d 100644
--- a/drivers/staging/unisys/visorchipset/file.c
+++ b/drivers/staging/unisys/visorchipset/file.c
@@ -28,85 +28,75 @@
#define CURRENT_FILE_PC VISOR_CHIPSET_PC_file_c
-static struct cdev Cdev;
-static VISORCHANNEL **PControlVm_channel;
-static dev_t MajorDev = -1; /**< indicates major num for device */
-static BOOL Registered = FALSE;
+static struct cdev file_cdev;
+static struct visorchannel **file_controlvm_channel;
+static dev_t majordev = -1; /**< indicates major num for device */
+static BOOL registered = FALSE;
static int visorchipset_open(struct inode *inode, struct file *file);
static int visorchipset_release(struct inode *inode, struct file *file);
static int visorchipset_mmap(struct file *file, struct vm_area_struct *vma);
-#ifdef HAVE_UNLOCKED_IOCTL
long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
-#else
-int visorchipset_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg);
-#endif
static const struct file_operations visorchipset_fops = {
.owner = THIS_MODULE,
.open = visorchipset_open,
.read = NULL,
.write = NULL,
-#ifdef HAVE_UNLOCKED_IOCTL
.unlocked_ioctl = visorchipset_ioctl,
-#else
- .ioctl = visorchipset_ioctl,
-#endif
.release = visorchipset_release,
.mmap = visorchipset_mmap,
};
int
-visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel)
+visorchipset_file_init(dev_t major_dev, struct visorchannel **controlvm_channel)
{
- int rc = -1;
+ int rc = 0;
- PControlVm_channel = pControlVm_channel;
- MajorDev = majorDev;
- cdev_init(&Cdev, &visorchipset_fops);
- Cdev.owner = THIS_MODULE;
- if (MAJOR(MajorDev) == 0) {
+ file_controlvm_channel = controlvm_channel;
+ majordev = major_dev;
+ cdev_init(&file_cdev, &visorchipset_fops);
+ file_cdev.owner = THIS_MODULE;
+ if (MAJOR(majordev) == 0) {
/* dynamic major device number registration required */
- if (alloc_chrdev_region(&MajorDev, 0, 1, MYDRVNAME) < 0) {
+ if (alloc_chrdev_region(&majordev, 0, 1, MYDRVNAME) < 0) {
ERRDRV("Unable to allocate+register char device %s",
MYDRVNAME);
- goto Away;
+ return -1;
}
- Registered = TRUE;
- INFODRV("New major number %d registered\n", MAJOR(MajorDev));
+ registered = TRUE;
+ INFODRV("New major number %d registered\n", MAJOR(majordev));
} else {
/* static major device number registration required */
- if (register_chrdev_region(MajorDev, 1, MYDRVNAME) < 0) {
+ if (register_chrdev_region(majordev, 1, MYDRVNAME) < 0) {
ERRDRV("Unable to register char device %s", MYDRVNAME);
- goto Away;
+ return -1;
}
- Registered = TRUE;
- INFODRV("Static major number %d registered\n", MAJOR(MajorDev));
+ registered = TRUE;
+ INFODRV("Static major number %d registered\n", MAJOR(majordev));
}
- if (cdev_add(&Cdev, MKDEV(MAJOR(MajorDev), 0), 1) < 0) {
+ rc = cdev_add(&file_cdev, MKDEV(MAJOR(majordev), 0), 1);
+ if (rc < 0) {
ERRDRV("failed to create char device: (status=%d)\n", rc);
- goto Away;
+ return -1;
}
INFODRV("Registered char device for %s (major=%d)",
- MYDRVNAME, MAJOR(MajorDev));
- rc = 0;
-Away:
- return rc;
+ MYDRVNAME, MAJOR(majordev));
+ return 0;
}
void
visorchipset_file_cleanup(void)
{
- if (Cdev.ops != NULL)
- cdev_del(&Cdev);
- Cdev.ops = NULL;
- if (Registered) {
- if (MAJOR(MajorDev) >= 0) {
- unregister_chrdev_region(MajorDev, 1);
- MajorDev = MKDEV(0, 0);
+ if (file_cdev.ops != NULL)
+ cdev_del(&file_cdev);
+ file_cdev.ops = NULL;
+ if (registered) {
+ if (MAJOR(majordev) >= 0) {
+ unregister_chrdev_region(majordev, 1);
+ majordev = MKDEV(0, 0);
}
- Registered = FALSE;
+ registered = FALSE;
}
}
@@ -114,17 +104,12 @@ static int
visorchipset_open(struct inode *inode, struct file *file)
{
unsigned minor_number = iminor(inode);
- int rc = -ENODEV;
DEBUGDRV("%s", __func__);
if (minor_number != 0)
- goto Away;
+ return -ENODEV;
file->private_data = NULL;
- rc = 0;
-Away:
- if (rc < 0)
- ERRDRV("%s minor=%d failed", __func__, minor_number);
- return rc;
+ return 0;
}
static int
@@ -137,7 +122,7 @@ visorchipset_release(struct inode *inode, struct file *file)
static int
visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
{
- ulong physAddr = 0;
+ ulong physaddr = 0;
ulong offset = vma->vm_pgoff << PAGE_SHIFT;
GUEST_PHYSICAL_ADDRESS addr = 0;
@@ -150,11 +135,11 @@ visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
switch (offset) {
case VISORCHIPSET_MMAP_CONTROLCHANOFFSET:
vma->vm_flags |= VM_IO;
- if (*PControlVm_channel == NULL) {
+ if (*file_controlvm_channel == NULL) {
ERRDRV("%s no controlvm channel yet", __func__);
return -ENXIO;
}
- visorchannel_read(*PControlVm_channel,
+ visorchannel_read(*file_controlvm_channel,
offsetof(struct spar_controlvm_channel_protocol,
gp_control_channel),
&addr, sizeof(addr));
@@ -162,10 +147,10 @@ visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
ERRDRV("%s control channel address is 0", __func__);
return -ENXIO;
}
- physAddr = (ulong) (addr);
- DEBUGDRV("mapping physical address = 0x%lx", physAddr);
+ physaddr = (ulong)addr;
+ DEBUGDRV("mapping physical address = 0x%lx", physaddr);
if (remap_pfn_range(vma, vma->vm_start,
- physAddr >> PAGE_SHIFT,
+ physaddr >> PAGE_SHIFT,
vma->vm_end - vma->vm_start,
/*pgprot_noncached */
(vma->vm_page_prot))) {
@@ -180,16 +165,8 @@ visorchipset_mmap(struct file *file, struct vm_area_struct *vma)
return 0;
}
-#ifdef HAVE_UNLOCKED_IOCTL
-long
-visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
-#else
-int
-visorchipset_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-#endif
+long visorchipset_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- int rc = SUCCESS;
s64 adjustment;
s64 vrtc_offset;
@@ -200,28 +177,21 @@ visorchipset_ioctl(struct inode *inode, struct file *file,
vrtc_offset = issue_vmcall_query_guest_virtual_time_offset();
if (copy_to_user
((void __user *)arg, &vrtc_offset, sizeof(vrtc_offset))) {
- rc = -EFAULT;
- goto Away;
+ return -EFAULT;
}
DBGINF("insde visorchipset_ioctl, cmd=%d, vrtc_offset=%lld",
cmd, vrtc_offset);
- break;
+ return SUCCESS;
case VMCALL_UPDATE_PHYSICAL_TIME:
if (copy_from_user
(&adjustment, (void __user *)arg, sizeof(adjustment))) {
- rc = -EFAULT;
- goto Away;
+ return -EFAULT;
}
DBGINF("insde visorchipset_ioctl, cmd=%d, adjustment=%lld", cmd,
adjustment);
- rc = issue_vmcall_update_physical_time(adjustment);
- break;
+ return issue_vmcall_update_physical_time(adjustment);
default:
LOGERR("visorchipset_ioctl received invalid command");
- rc = -EFAULT;
- break;
+ return -EFAULT;
}
-Away:
- DBGINF("exiting %d!", rc);
- return rc;
}
diff --git a/drivers/staging/unisys/visorchipset/file.h b/drivers/staging/unisys/visorchipset/file.h
index 21bb906242e1..dc7a19556b3f 100644
--- a/drivers/staging/unisys/visorchipset/file.h
+++ b/drivers/staging/unisys/visorchipset/file.h
@@ -20,7 +20,8 @@
#include "globals.h"
-int visorchipset_file_init(dev_t majorDev, VISORCHANNEL **pControlVm_channel);
+int visorchipset_file_init(dev_t majorDev,
+ struct visorchannel **pControlVm_channel);
void visorchipset_file_cleanup(void);
#endif
diff --git a/drivers/staging/unisys/visorchipset/globals.h b/drivers/staging/unisys/visorchipset/globals.h
index 0fe14599f185..a1d35d4bef2e 100644
--- a/drivers/staging/unisys/visorchipset/globals.h
+++ b/drivers/staging/unisys/visorchipset/globals.h
@@ -15,7 +15,6 @@
* details.
*/
-
#ifndef __VISORCHIPSET_GLOBALS_H__
#define __VISORCHIPSET_GLOBALS_H__
@@ -28,7 +27,6 @@
#define MYDRVNAME "visorchipset"
-
/* module parameters */
extern int visorchipset_testvnic;
diff --git a/drivers/staging/unisys/visorchipset/testing.h b/drivers/staging/unisys/visorchipset/testing.h
deleted file mode 100644
index 573aa8b5ba6a..000000000000
--- a/drivers/staging/unisys/visorchipset/testing.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* testing.h
- *
- * Copyright (C) 2010 - 2013 UNISYS 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, GOOD TITLE or
- * NON INFRINGEMENT. See the GNU General Public License for more
- * details.
- */
-
-#ifndef __VISORCHIPSET_TESTING_H__
-#define __VISORCHIPSET_TESTING_H__
-
-#define VISORCHIPSET_TEST_PROC
-#include <linux/uuid.h>
-#include "globals.h"
-#include "controlvmchannel.h"
-
-void test_produce_test_message(struct controlvm_message *msg,
- int isLocalTestAddr);
-BOOL test_consume_test_message(struct controlvm_message *msg);
-void test_manufacture_vnic_client_add(void *p);
-void test_manufacture_vnic_client_add_phys(HOSTADDRESS addr);
-void test_manufacture_preamble_messages(void);
-void test_manufacture_device_attach(ulong busNo, ulong devNo);
-void test_manufacture_device_add(ulong busNo, ulong devNo, uuid_le dataTypeGuid,
- void *pChannel);
-void test_manufacture_add_bus(ulong busNo, ulong maxDevices,
- uuid_le id, u8 *name, BOOL isServer);
-void test_manufacture_device_destroy(ulong busNo, ulong devNo);
-void test_manufacture_bus_destroy(ulong busNo);
-void test_manufacture_detach_externalPort(ulong switchNo, ulong externalPortNo);
-void test_manufacture_detach_internalPort(ulong switchNo, ulong internalPortNo);
-void test_cleanup(void);
-
-#endif
diff --git a/drivers/staging/unisys/visorchipset/visorchipset.h b/drivers/staging/unisys/visorchipset/visorchipset.h
index 46dad63fa2c8..98f3ba4c13ac 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset.h
+++ b/drivers/staging/unisys/visorchipset/visorchipset.h
@@ -158,61 +158,6 @@ findbus(struct list_head *list, u32 bus_no)
return NULL;
}
-/** Attributes for a particular Supervisor switch.
- */
-struct visorchipset_switch_info {
- u32 switch_no;
- struct visorchipset_state state;
- uuid_le switch_type_uuid;
- u8 *authservice1;
- u8 *authservice2;
- u8 *authservice3;
- u8 *security_context;
- u64 reserved;
- u32 reserved2; /* control_vm_id */
- struct device dev;
- BOOL dev_exists;
- struct controlvm_message_header pending_msg_hdr;
-};
-
-/** Attributes for a particular Supervisor external port, which is connected
- * to a specific switch.
- */
-struct visorchipset_externalport_info {
- u32 switch_no;
- u32 external_port_no;
- struct visorchipset_state state;
- uuid_le network_zone_uuid;
- int pd_port;
- u8 *ip;
- u8 *ip_netmask;
- u8 *ip_broadcast;
- u8 *ip_network;
- u8 *ip_gateway;
- u8 *ip_dns;
- u64 reserved1;
- u32 reserved2; /* control_vm_id */
- struct device dev;
- BOOL dev_exists;
- struct controlvm_message_header pending_msg_hdr;
-};
-
-/** Attributes for a particular Supervisor internal port, which is how a
- * device connects to a particular switch.
- */
-struct visorchipset_internalport_info {
- u32 switch_no;
- u32 internal_port_no;
- struct visorchipset_state state;
- u32 bus_no; /* valid only when state.attached == 1 */
- u32 dev_no; /* valid only when state.attached == 1 */
- u64 reserved1;
- u32 reserved2; /* CONTROLVM_ID */
- struct controlvm_message_header pending_msg_hdr;
- MYPROCOBJECT *proc_object;
-
-};
-
/* These functions will be called from within visorchipset when certain
* events happen. (The implementation of these functions is outside of
* visorchipset.)
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_main.c b/drivers/staging/unisys/visorchipset/visorchipset_main.c
index 7e6be32cf7bb..f606ee9e0de9 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset_main.c
+++ b/drivers/staging/unisys/visorchipset/visorchipset_main.c
@@ -20,7 +20,6 @@
#include "procobjecttree.h"
#include "visorchannel.h"
#include "periodic_work.h"
-#include "testing.h"
#include "file.h"
#include "parser.h"
#include "uniklog.h"
@@ -102,7 +101,7 @@ static struct controlvm_message_packet g_DeviceChangeStatePacket;
static LIST_HEAD(BusInfoList);
static LIST_HEAD(DevInfoList);
-static VISORCHANNEL *ControlVm_channel;
+static struct visorchannel *ControlVm_channel;
typedef struct {
u8 __iomem *ptr; /* pointer to base address of payload pool */
@@ -1595,7 +1594,7 @@ parahotplug_next_id(void)
static unsigned long
parahotplug_next_expiration(void)
{
- return jiffies + PARAHOTPLUG_TIMEOUT_MS * HZ / 1000;
+ return jiffies + msecs_to_jiffies(PARAHOTPLUG_TIMEOUT_MS);
}
/*
diff --git a/drivers/staging/unisys/visorchipset/visorchipset_umode.h b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
index 06ba5b7e4254..6cf6eccb3f4a 100644
--- a/drivers/staging/unisys/visorchipset/visorchipset_umode.h
+++ b/drivers/staging/unisys/visorchipset/visorchipset_umode.h
@@ -26,8 +26,6 @@
#ifndef __VISORCHIPSET_UMODE_H
#define __VISORCHIPSET_UMODE_H
-
-
/** The user-mode program can access the control channel buffer directly
* via this memory map.
*/
diff --git a/drivers/staging/unisys/visorutil/charqueue.c b/drivers/staging/unisys/visorutil/charqueue.c
index 1ce7003c3a90..ac7acb7c5b79 100644
--- a/drivers/staging/unisys/visorutil/charqueue.c
+++ b/drivers/staging/unisys/visorutil/charqueue.c
@@ -28,7 +28,7 @@
struct charqueue {
int alloc_size;
int nslots;
- spinlock_t lock;
+ spinlock_t lock; /* read/write lock for this structure */
int head, tail;
unsigned char buf[0];
};
diff --git a/drivers/staging/unisys/visorutil/procobjecttree.c b/drivers/staging/unisys/visorutil/procobjecttree.c
index 195772d22c9e..82279ca5fbe1 100644
--- a/drivers/staging/unisys/visorutil/procobjecttree.c
+++ b/drivers/staging/unisys/visorutil/procobjecttree.c
@@ -25,12 +25,12 @@
* need in order to call the callback function that supplies the /proc read
* info for that file.
*/
-typedef struct {
+struct proc_dir_entry_context {
void (*show_property)(struct seq_file *, void *, int);
MYPROCOBJECT *procObject;
int propertyIndex;
-} PROCDIRENTRYCONTEXT;
+};
/** This describes the attributes of a tree rooted at
* <procDirRoot>/<name[0]>/<name[1]>/...
@@ -86,7 +86,7 @@ struct MYPROCOBJECT_Tag {
/** this is a holding area for the context information that is needed
* to run the /proc callback function */
- PROCDIRENTRYCONTEXT *procDirPropertyContexts;
+ struct proc_dir_entry_context *procDirPropertyContexts;
};
@@ -254,15 +254,16 @@ MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
goto Away;
}
obj->procDirPropertyContexts =
- kzalloc((type->nProperties + 1) * sizeof(PROCDIRENTRYCONTEXT),
+ kzalloc((type->nProperties + 1) *
+ sizeof(struct proc_dir_entry_context),
GFP_KERNEL | __GFP_NORETRY);
if (obj->procDirPropertyContexts == NULL) {
ERRDRV("out of memory\n");
goto Away;
}
- obj->procDirProperties =
- kzalloc((type->nProperties + 1) * sizeof(struct proc_dir_entry *),
- GFP_KERNEL | __GFP_NORETRY);
+ obj->procDirProperties = kzalloc((type->nProperties + 1) *
+ sizeof(struct proc_dir_entry *),
+ GFP_KERNEL | __GFP_NORETRY);
if (obj->procDirProperties == NULL) {
ERRDRV("out of memory\n");
goto Away;
@@ -276,8 +277,8 @@ MYPROCOBJECT *visor_proc_CreateObject(MYPROCTYPE *type,
/* only create properties that have names */
obj->procDirProperties[i] =
createProcFile(type->propertyNames[i],
- obj->procDir, &proc_fops,
- &obj->procDirPropertyContexts[i]);
+ obj->procDir, &proc_fops,
+ &obj->procDirPropertyContexts[i]);
if (obj->procDirProperties[i] == NULL) {
rc = NULL;
goto Away;
@@ -340,7 +341,7 @@ EXPORT_SYMBOL_GPL(visor_proc_DestroyObject);
static int seq_show(struct seq_file *seq, void *offset)
{
- PROCDIRENTRYCONTEXT *ctx = (PROCDIRENTRYCONTEXT *)(seq->private);
+ struct proc_dir_entry_context *ctx = seq->private;
if (ctx == NULL) {
ERRDRV("I don't have a freakin' clue...");
diff --git a/drivers/staging/vt6655/baseband.c b/drivers/staging/vt6655/baseband.c
index f8c5fc371c4c..565ba189afb2 100644
--- a/drivers/staging/vt6655/baseband.c
+++ b/drivers/staging/vt6655/baseband.c
@@ -27,7 +27,8 @@
*
* Functions:
* BBuGetFrameTime - Calculate data frame transmitting time
- * BBvCaculateParameter - Caculate PhyLength, PhyService and Phy Signal parameter for baseband Tx
+ * BBvCaculateParameter - Caculate PhyLength, PhyService and Phy Signal
+ * parameter for baseband Tx
* BBbReadEmbedded - Embedded read baseband register via MAC
* BBbWriteEmbedded - Embedded write baseband register via MAC
* BBbVT3253Init - VIA VT3253 baseband chip init code
@@ -1698,46 +1699,6 @@ static const unsigned short awcFrameTime[MAX_RATE] = {
10, 20, 55, 110, 24, 36, 48, 72, 96, 144, 192, 216
};
-/*--------------------- Static Functions --------------------------*/
-
-static
-unsigned long
-s_ulGetRatio(struct vnt_private *priv);
-
-static
-void
-s_vChangeAntenna(
- struct vnt_private *priv
-);
-
-static
-void
-s_vChangeAntenna(
- struct vnt_private *priv
-)
-{
- if (priv->dwRxAntennaSel == 0) {
- priv->dwRxAntennaSel = 1;
- if (priv->bTxRxAntInv == true)
- BBvSetRxAntennaMode(priv, ANT_A);
- else
- BBvSetRxAntennaMode(priv, ANT_B);
- } else {
- priv->dwRxAntennaSel = 0;
- if (priv->bTxRxAntInv == true)
- BBvSetRxAntennaMode(priv, ANT_B);
- else
- BBvSetRxAntennaMode(priv, ANT_A);
- }
- if (priv->dwTxAntennaSel == 0) {
- priv->dwTxAntennaSel = 1;
- BBvSetTxAntennaMode(priv, ANT_B);
- } else {
- priv->dwTxAntennaSel = 0;
- BBvSetTxAntennaMode(priv, ANT_A);
- }
-}
-
/*--------------------- Export Variables --------------------------*/
/*
* Description: Calculate data frame transmitting time
@@ -2412,303 +2373,3 @@ BBvExitDeepSleep(struct vnt_private *priv, unsigned char byLocalID)
BBbWriteEmbedded(priv, 0x0C, 0x00); /* CR12 */
BBbWriteEmbedded(priv, 0x0D, 0x01); /* CR13 */
}
-
-static
-unsigned long
-s_ulGetRatio(struct vnt_private *priv)
-{
- unsigned long ulRatio = 0;
- unsigned long ulMaxPacket;
- unsigned long ulPacketNum;
-
- /* This is a thousand-ratio */
- ulMaxPacket = priv->uNumSQ3[RATE_54M];
- if (priv->uNumSQ3[RATE_54M] != 0) {
- ulPacketNum = priv->uNumSQ3[RATE_54M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_54M;
- }
- if (priv->uNumSQ3[RATE_48M] > ulMaxPacket) {
- ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_48M;
- ulMaxPacket = priv->uNumSQ3[RATE_48M];
- }
- if (priv->uNumSQ3[RATE_36M] > ulMaxPacket) {
- ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
- priv->uNumSQ3[RATE_36M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_36M;
- ulMaxPacket = priv->uNumSQ3[RATE_36M];
- }
- if (priv->uNumSQ3[RATE_24M] > ulMaxPacket) {
- ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
- priv->uNumSQ3[RATE_36M] + priv->uNumSQ3[RATE_24M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_24M;
- ulMaxPacket = priv->uNumSQ3[RATE_24M];
- }
- if (priv->uNumSQ3[RATE_18M] > ulMaxPacket) {
- ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
- priv->uNumSQ3[RATE_36M] + priv->uNumSQ3[RATE_24M] +
- priv->uNumSQ3[RATE_18M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_18M;
- ulMaxPacket = priv->uNumSQ3[RATE_18M];
- }
- if (priv->uNumSQ3[RATE_12M] > ulMaxPacket) {
- ulPacketNum = priv->uNumSQ3[RATE_54M] + priv->uNumSQ3[RATE_48M] +
- priv->uNumSQ3[RATE_36M] + priv->uNumSQ3[RATE_24M] +
- priv->uNumSQ3[RATE_18M] + priv->uNumSQ3[RATE_12M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_12M;
- ulMaxPacket = priv->uNumSQ3[RATE_12M];
- }
- if (priv->uNumSQ3[RATE_11M] > ulMaxPacket) {
- ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
- priv->uNumSQ3[RATE_2M] - priv->uNumSQ3[RATE_5M] -
- priv->uNumSQ3[RATE_6M] - priv->uNumSQ3[RATE_9M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_11M;
- ulMaxPacket = priv->uNumSQ3[RATE_11M];
- }
- if (priv->uNumSQ3[RATE_9M] > ulMaxPacket) {
- ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
- priv->uNumSQ3[RATE_2M] - priv->uNumSQ3[RATE_5M] -
- priv->uNumSQ3[RATE_6M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_9M;
- ulMaxPacket = priv->uNumSQ3[RATE_9M];
- }
- if (priv->uNumSQ3[RATE_6M] > ulMaxPacket) {
- ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
- priv->uNumSQ3[RATE_2M] - priv->uNumSQ3[RATE_5M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_6M;
- ulMaxPacket = priv->uNumSQ3[RATE_6M];
- }
- if (priv->uNumSQ3[RATE_5M] > ulMaxPacket) {
- ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M] -
- priv->uNumSQ3[RATE_2M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_55M;
- ulMaxPacket = priv->uNumSQ3[RATE_5M];
- }
- if (priv->uNumSQ3[RATE_2M] > ulMaxPacket) {
- ulPacketNum = priv->uDiversityCnt - priv->uNumSQ3[RATE_1M];
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_2M;
- ulMaxPacket = priv->uNumSQ3[RATE_2M];
- }
- if (priv->uNumSQ3[RATE_1M] > ulMaxPacket) {
- ulPacketNum = priv->uDiversityCnt;
- ulRatio = (ulPacketNum * 1000 / priv->uDiversityCnt);
- ulRatio += TOP_RATE_1M;
- }
-
- return ulRatio;
-}
-
-void
-BBvClearAntDivSQ3Value(struct vnt_private *priv)
-{
- unsigned int ii;
-
- priv->uDiversityCnt = 0;
- for (ii = 0; ii < MAX_RATE; ii++)
- priv->uNumSQ3[ii] = 0;
-}
-
-/*
- * Description: Antenna Diversity
- *
- * Parameters:
- * In:
- * priv - Device Structure
- * byRSR - RSR from received packet
- * bySQ3 - SQ3 value from received packet
- * Out:
- * none
- *
- * Return Value: none
- *
- */
-
-void BBvAntennaDiversity(struct vnt_private *priv,
- unsigned char byRxRate, unsigned char bySQ3)
-{
- if ((byRxRate >= MAX_RATE) || (priv->wAntDiversityMaxRate >= MAX_RATE))
- return;
-
- priv->uDiversityCnt++;
-
- priv->uNumSQ3[byRxRate]++;
-
- if (priv->byAntennaState == 0) {
- if (priv->uDiversityCnt > priv->ulDiversityNValue) {
- pr_debug("ulDiversityNValue=[%d],54M-[%d]\n",
- (int)priv->ulDiversityNValue,
- (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate]);
-
- if (priv->uNumSQ3[priv->wAntDiversityMaxRate] < priv->uDiversityCnt/2) {
- priv->ulRatio_State0 = s_ulGetRatio(priv);
- pr_debug("SQ3_State0, rate = [%08x]\n",
- (int)priv->ulRatio_State0);
-
- if (priv->byTMax == 0)
- return;
- pr_debug("1.[%08x], uNumSQ3[%d]=%d, %d\n",
- (int)priv->ulRatio_State0,
- (int)priv->wAntDiversityMaxRate,
- (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate],
- (int)priv->uDiversityCnt);
-
- s_vChangeAntenna(priv);
- priv->byAntennaState = 1;
- del_timer(&priv->TimerSQ3Tmax3);
- del_timer(&priv->TimerSQ3Tmax2);
- priv->TimerSQ3Tmax1.expires = RUN_AT(priv->byTMax * HZ);
- add_timer(&priv->TimerSQ3Tmax1);
-
- } else {
- priv->TimerSQ3Tmax3.expires = RUN_AT(priv->byTMax3 * HZ);
- add_timer(&priv->TimerSQ3Tmax3);
- }
- BBvClearAntDivSQ3Value(priv);
-
- }
- } else { /* byAntennaState == 1 */
-
- if (priv->uDiversityCnt > priv->ulDiversityMValue) {
- del_timer(&priv->TimerSQ3Tmax1);
-
- priv->ulRatio_State1 = s_ulGetRatio(priv);
- pr_debug("RX:SQ3_State1, rate0 = %08x,rate1 = %08x\n",
- (int)priv->ulRatio_State0,
- (int)priv->ulRatio_State1);
-
- if (priv->ulRatio_State1 < priv->ulRatio_State0) {
- pr_debug("2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
- (int)priv->ulRatio_State0,
- (int)priv->ulRatio_State1,
- (int)priv->wAntDiversityMaxRate,
- (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate],
- (int)priv->uDiversityCnt);
-
- s_vChangeAntenna(priv);
- priv->TimerSQ3Tmax3.expires = RUN_AT(priv->byTMax3 * HZ);
- priv->TimerSQ3Tmax2.expires = RUN_AT(priv->byTMax2 * HZ);
- add_timer(&priv->TimerSQ3Tmax3);
- add_timer(&priv->TimerSQ3Tmax2);
- }
- priv->byAntennaState = 0;
- BBvClearAntDivSQ3Value(priv);
- }
- } /* byAntennaState */
-}
-
-/*+
- *
- * Description:
- * Timer for SQ3 antenna diversity
- *
- * Parameters:
- * In:
- * Out:
- * none
- *
- * Return Value: none
- *
- -*/
-
-void
-TimerSQ3CallBack(
- unsigned long data
-)
-{
- struct vnt_private *priv = (struct vnt_private *)data;
- unsigned long flags;
-
- pr_debug("TimerSQ3CallBack...\n");
-
- spin_lock_irqsave(&priv->lock, flags);
-
- pr_debug("3.[%08x][%08x], %d\n",
- (int)priv->ulRatio_State0, (int)priv->ulRatio_State1,
- (int)priv->uDiversityCnt);
-
- s_vChangeAntenna(priv);
- priv->byAntennaState = 0;
- BBvClearAntDivSQ3Value(priv);
-
- priv->TimerSQ3Tmax3.expires = RUN_AT(priv->byTMax3 * HZ);
- priv->TimerSQ3Tmax2.expires = RUN_AT(priv->byTMax2 * HZ);
- add_timer(&priv->TimerSQ3Tmax3);
- add_timer(&priv->TimerSQ3Tmax2);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
-
-/*+
- *
- * Description:
- * Timer for SQ3 antenna diversity
- *
- * Parameters:
- * In:
- * pvSysSpec1
- * hDeviceContext - Pointer to the adapter
- * pvSysSpec2
- * pvSysSpec3
- * Out:
- * none
- *
- * Return Value: none
- *
- -*/
-
-void
-TimerState1CallBack(
- unsigned long data
-)
-{
- struct vnt_private *priv = (struct vnt_private *)data;
- unsigned long flags;
-
- pr_debug("TimerState1CallBack...\n");
-
- spin_lock_irqsave(&priv->lock, flags);
-
- if (priv->uDiversityCnt < priv->ulDiversityMValue/100) {
- s_vChangeAntenna(priv);
- priv->TimerSQ3Tmax3.expires = RUN_AT(priv->byTMax3 * HZ);
- priv->TimerSQ3Tmax2.expires = RUN_AT(priv->byTMax2 * HZ);
- add_timer(&priv->TimerSQ3Tmax3);
- add_timer(&priv->TimerSQ3Tmax2);
- } else {
- priv->ulRatio_State1 = s_ulGetRatio(priv);
- pr_debug("SQ3_State1, rate0 = %08x,rate1 = %08x\n",
- (int)priv->ulRatio_State0,
- (int)priv->ulRatio_State1);
-
- if (priv->ulRatio_State1 < priv->ulRatio_State0) {
- pr_debug("2.[%08x][%08x], uNumSQ3[%d]=%d, %d\n",
- (int)priv->ulRatio_State0,
- (int)priv->ulRatio_State1,
- (int)priv->wAntDiversityMaxRate,
- (int)priv->uNumSQ3[(int)priv->wAntDiversityMaxRate],
- (int)priv->uDiversityCnt);
-
- s_vChangeAntenna(priv);
-
- priv->TimerSQ3Tmax3.expires = RUN_AT(priv->byTMax3 * HZ);
- priv->TimerSQ3Tmax2.expires = RUN_AT(priv->byTMax2 * HZ);
- add_timer(&priv->TimerSQ3Tmax3);
- add_timer(&priv->TimerSQ3Tmax2);
- }
- }
- priv->byAntennaState = 0;
- BBvClearAntDivSQ3Value(priv);
-
- spin_unlock_irqrestore(&priv->lock, flags);
-}
diff --git a/drivers/staging/vt6655/baseband.h b/drivers/staging/vt6655/baseband.h
index d9f6d63e4ab7..43a4fb1f3570 100644
--- a/drivers/staging/vt6655/baseband.h
+++ b/drivers/staging/vt6655/baseband.h
@@ -93,21 +93,4 @@ void BBvSetRxAntennaMode(struct vnt_private *, unsigned char byAntennaMode);
void BBvSetDeepSleep(struct vnt_private *, unsigned char byLocalID);
void BBvExitDeepSleep(struct vnt_private *, unsigned char byLocalID);
-/* timer for antenna diversity */
-
-void
-TimerSQ3CallBack(
- unsigned long
-);
-
-void
-TimerState1CallBack(
- unsigned long
-);
-
-void BBvAntennaDiversity(struct vnt_private *,
- unsigned char byRxRate, unsigned char bySQ3);
-void
-BBvClearAntDivSQ3Value(struct vnt_private *);
-
#endif /* __BASEBAND_H__ */
diff --git a/drivers/staging/vt6655/card.c b/drivers/staging/vt6655/card.c
index a0796405c308..1cdcf49b2445 100644
--- a/drivers/staging/vt6655/card.c
+++ b/drivers/staging/vt6655/card.c
@@ -68,8 +68,8 @@
/*--------------------- Static Variables --------------------------*/
-static const unsigned short cwRXBCNTSFOff[MAX_RATE] =
-{17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3};
+static const unsigned short cwRXBCNTSFOff[MAX_RATE] = {
+ 17, 17, 17, 17, 34, 23, 17, 11, 8, 5, 4, 3};
/*--------------------- Static Functions --------------------------*/
@@ -670,6 +670,9 @@ void CARDvSetRSPINF(struct vnt_private *pDevice, u8 bb_type)
{
union vnt_phy_field_swap phy;
unsigned char byTxRate, byRsvTime; /* For OFDM */
+ unsigned long flags;
+
+ spin_lock_irqsave(&pDevice->lock, flags);
/* Set to Page1 */
MACvSelectPage1(pDevice->PortOffset);
@@ -767,6 +770,8 @@ void CARDvSetRSPINF(struct vnt_private *pDevice, u8 bb_type)
VNSvOutPortW(pDevice->PortOffset + MAC_REG_RSPINF_A_72, MAKEWORD(byTxRate, byRsvTime));
/* Set to Page0 */
MACvSelectPage0(pDevice->PortOffset);
+
+ spin_unlock_irqrestore(&pDevice->lock, flags);
}
void CARDvUpdateBasicTopRate(struct vnt_private *pDevice)
diff --git a/drivers/staging/vt6655/channel.c b/drivers/staging/vt6655/channel.c
index 70f870541f92..3c17725d5910 100644
--- a/drivers/staging/vt6655/channel.c
+++ b/drivers/staging/vt6655/channel.c
@@ -174,12 +174,12 @@ void vnt_init_bands(struct vnt_private *priv)
* Return Value: true if succeeded; false if failed.
*
*/
-bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel)
+bool set_channel(void *pDeviceHandler, struct ieee80211_channel *ch)
{
struct vnt_private *pDevice = pDeviceHandler;
bool bResult = true;
- if (pDevice->byCurrentCh == uConnectionChannel)
+ if (pDevice->byCurrentCh == ch->hw_value)
return bResult;
/* Set VGA to max sensitivity */
@@ -197,19 +197,23 @@ bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel)
if (pDevice->byRFType == RF_AIROHA7230)
RFbAL7230SelectChannelPostProcess(pDevice, pDevice->byCurrentCh,
- (unsigned char)uConnectionChannel);
+ ch->hw_value);
- pDevice->byCurrentCh = (unsigned char)uConnectionChannel;
+ pDevice->byCurrentCh = ch->hw_value;
bResult &= RFbSelectChannel(pDevice, pDevice->byRFType,
- (unsigned char)uConnectionChannel);
+ ch->hw_value);
/* Init Synthesizer Table */
if (pDevice->bEnablePSMode)
- RFvWriteWakeProgSyn(pDevice, pDevice->byRFType, uConnectionChannel);
+ RFvWriteWakeProgSyn(pDevice, pDevice->byRFType, ch->hw_value);
BBvSoftwareReset(pDevice);
if (pDevice->byLocalID > REV_ID_VT3253_B1) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&pDevice->lock, flags);
+
/* set HW default power register */
MACvSelectPage1(pDevice->PortOffset);
RFbSetPower(pDevice, RATE_1M, pDevice->byCurrentCh);
@@ -217,6 +221,8 @@ bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel)
RFbSetPower(pDevice, RATE_6M, pDevice->byCurrentCh);
VNSvOutPortB(pDevice->PortOffset + MAC_REG_PWROFDM, pDevice->byCurPwr);
MACvSelectPage0(pDevice->PortOffset);
+
+ spin_unlock_irqrestore(&pDevice->lock, flags);
}
if (pDevice->byBBType == BB_TYPE_11B)
diff --git a/drivers/staging/vt6655/channel.h b/drivers/staging/vt6655/channel.h
index 4f4264e23462..e2be6fca5f26 100644
--- a/drivers/staging/vt6655/channel.h
+++ b/drivers/staging/vt6655/channel.h
@@ -27,6 +27,6 @@
void vnt_init_bands(struct vnt_private *);
-bool set_channel(void *pDeviceHandler, unsigned int uConnectionChannel);
+bool set_channel(void *pDeviceHandler, struct ieee80211_channel *);
#endif /* _CHANNEL_H_ */
diff --git a/drivers/staging/vt6655/device.h b/drivers/staging/vt6655/device.h
index 83efbfb57c79..440537e47121 100644
--- a/drivers/staging/vt6655/device.h
+++ b/drivers/staging/vt6655/device.h
@@ -367,7 +367,7 @@ struct vnt_private {
bool bIsBeaconBufReadySet;
unsigned int cbBeaconBufReadySetCnt;
bool bFixRate;
- unsigned char byCurrentCh;
+ u16 byCurrentCh;
bool bAES;
@@ -407,29 +407,6 @@ struct vnt_private {
unsigned char byBBCR88;
unsigned char byBBCR09;
- bool bDiversityRegCtlON;
- bool bDiversityEnable;
- unsigned long ulDiversityNValue;
- unsigned long ulDiversityMValue;
- unsigned char byTMax;
- unsigned char byTMax2;
- unsigned char byTMax3;
- unsigned long ulSQ3TH;
-
- /* ANT diversity */
- unsigned long uDiversityCnt;
- unsigned char byAntennaState;
- unsigned long ulRatio_State0;
- unsigned long ulRatio_State1;
-
- /* SQ3 functions for antenna diversity */
- struct timer_list TimerSQ3Tmax1;
- struct timer_list TimerSQ3Tmax2;
- struct timer_list TimerSQ3Tmax3;
-
- unsigned long uNumSQ3[MAX_RATE];
- unsigned short wAntDiversityMaxRate;
-
unsigned char abyEEPROM[EEP_MAX_CONTEXT_SIZE]; /* unsigned long alignment */
unsigned short wBeaconInterval;
diff --git a/drivers/staging/vt6655/device_main.c b/drivers/staging/vt6655/device_main.c
index cd1a277d853b..4324282afe49 100644
--- a/drivers/staging/vt6655/device_main.c
+++ b/drivers/staging/vt6655/device_main.c
@@ -126,10 +126,6 @@ DEVICE_PARAM(LongRetryLimit, "long frame retry limits");
DEVICE_PARAM(BasebandType, "baseband type");
-#define DIVERSITY_ANT_DEF 0
-
-DEVICE_PARAM(bDiversityANTEnable, "ANT diversity mode");
-
//
// Static vars definitions
//
@@ -152,7 +148,6 @@ static void vt6655_init_info(struct pci_dev *pcid,
static void device_free_info(struct vnt_private *pDevice);
static bool device_get_pci_info(struct vnt_private *, struct pci_dev *pcid);
static void device_print_info(struct vnt_private *pDevice);
-static void device_init_diversity_timer(struct vnt_private *pDevice);
static irqreturn_t device_intr(int irq, void *dev_instance);
#ifdef CONFIG_PM
@@ -216,7 +211,6 @@ static void device_get_options(struct vnt_private *pDevice)
pOpts->short_retry = SHORT_RETRY_DEF;
pOpts->long_retry = LONG_RETRY_DEF;
pOpts->bbp_type = BBP_TYPE_DEF;
- pOpts->flags |= DEVICE_FLAGS_DiversityANT;
}
static void
@@ -224,7 +218,6 @@ device_set_options(struct vnt_private *pDevice)
{
pDevice->byShortRetryLimit = pDevice->sOpts.short_retry;
pDevice->byLongRetryLimit = pDevice->sOpts.long_retry;
- pDevice->bDiversityRegCtlON = (pDevice->sOpts.flags & DEVICE_FLAGS_DiversityANT) ? 1 : 0;
pDevice->byBBType = pDevice->sOpts.bbp_type;
pDevice->byPacketType = pDevice->byBBType;
pDevice->byAutoFBCtrl = AUTO_FB_0;
@@ -236,8 +229,6 @@ device_set_options(struct vnt_private *pDevice)
pr_debug(" byPreambleType= %d\n", (int)pDevice->byPreambleType);
pr_debug(" byShortPreamble= %d\n", (int)pDevice->byShortPreamble);
pr_debug(" byBBType= %d\n", (int)pDevice->byBBType);
- pr_debug(" pDevice->bDiversityRegCtlON= %d\n",
- (int)pDevice->bDiversityRegCtlON);
}
//
@@ -249,7 +240,6 @@ static void device_init_registers(struct vnt_private *pDevice)
unsigned long flags;
unsigned int ii;
unsigned char byValue;
- unsigned char byValue1;
unsigned char byCCKPwrdBm = 0;
unsigned char byOFDMPwrdBm = 0;
@@ -301,13 +291,6 @@ static void device_init_registers(struct vnt_private *pDevice)
if (byValue == 0)
byValue = (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN);
- pDevice->ulDiversityNValue = 100*260;
- pDevice->ulDiversityMValue = 100*16;
- pDevice->byTMax = 1;
- pDevice->byTMax2 = 4;
- pDevice->ulSQ3TH = 0;
- pDevice->byTMax3 = 64;
-
if (byValue == (EEP_ANTENNA_AUX | EEP_ANTENNA_MAIN)) {
pDevice->byAntennaCount = 2;
pDevice->byTxAntennaMode = ANT_B;
@@ -318,16 +301,7 @@ static void device_init_registers(struct vnt_private *pDevice)
pDevice->byRxAntennaMode = ANT_A;
else
pDevice->byRxAntennaMode = ANT_B;
-
- byValue1 = SROMbyReadEmbedded(pDevice->PortOffset,
- EEP_OFS_ANTENNA);
-
- if ((byValue1 & 0x08) == 0)
- pDevice->bDiversityEnable = false;
- else
- pDevice->bDiversityEnable = true;
} else {
- pDevice->bDiversityEnable = false;
pDevice->byAntennaCount = 1;
pDevice->dwTxAntennaSel = 0;
pDevice->dwRxAntennaSel = 0;
@@ -349,10 +323,9 @@ static void device_init_registers(struct vnt_private *pDevice)
}
}
- pr_debug("bDiversityEnable=[%d],NValue=[%d],MValue=[%d],TMax=[%d],TMax2=[%d]\n",
- pDevice->bDiversityEnable, (int)pDevice->ulDiversityNValue,
- (int)pDevice->ulDiversityMValue, pDevice->byTMax,
- pDevice->byTMax2);
+ /* Set initial antenna mode */
+ BBvSetTxAntennaMode(pDevice, pDevice->byTxAntennaMode);
+ BBvSetRxAntennaMode(pDevice, pDevice->byRxAntennaMode);
/* zonetype initial */
pDevice->byOriginalZonetype = pDevice->abyEEPROM[EEP_OFS_ZONETYPE];
@@ -493,24 +466,6 @@ static void device_init_registers(struct vnt_private *pDevice)
MACvStart(pDevice->PortOffset);
}
-static void device_init_diversity_timer(struct vnt_private *pDevice)
-{
- init_timer(&pDevice->TimerSQ3Tmax1);
- pDevice->TimerSQ3Tmax1.data = (unsigned long) pDevice;
- pDevice->TimerSQ3Tmax1.function = TimerSQ3CallBack;
- pDevice->TimerSQ3Tmax1.expires = RUN_AT(HZ);
-
- init_timer(&pDevice->TimerSQ3Tmax2);
- pDevice->TimerSQ3Tmax2.data = (unsigned long) pDevice;
- pDevice->TimerSQ3Tmax2.function = TimerSQ3CallBack;
- pDevice->TimerSQ3Tmax2.expires = RUN_AT(HZ);
-
- init_timer(&pDevice->TimerSQ3Tmax3);
- pDevice->TimerSQ3Tmax3.data = (unsigned long) pDevice;
- pDevice->TimerSQ3Tmax3.function = TimerState1CallBack;
- pDevice->TimerSQ3Tmax3.expires = RUN_AT(HZ);
-}
-
static void device_print_info(struct vnt_private *pDevice)
{
dev_info(&pDevice->pcid->dev, "%s\n", get_chip_name(pDevice->chip_id));
@@ -1053,6 +1008,58 @@ static void device_free_tx_buf(struct vnt_private *pDevice, PSTxDesc pDesc)
pTDInfo->byFlags = 0;
}
+static void vnt_check_bb_vga(struct vnt_private *priv)
+{
+ long dbm;
+ int i;
+
+ if (!priv->bUpdateBBVGA)
+ return;
+
+ if (priv->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)
+ return;
+
+ if (!(priv->vif->bss_conf.assoc && priv->uCurrRSSI))
+ return;
+
+ RFvRSSITodBm(priv, (u8)priv->uCurrRSSI, &dbm);
+
+ for (i = 0; i < BB_VGA_LEVEL; i++) {
+ if (dbm < priv->ldBmThreshold[i]) {
+ priv->byBBVGANew = priv->abyBBVGA[i];
+ break;
+ }
+ }
+
+ if (priv->byBBVGANew == priv->byBBVGACurrent) {
+ priv->uBBVGADiffCount = 1;
+ return;
+ }
+
+ priv->uBBVGADiffCount++;
+
+ if (priv->uBBVGADiffCount == 1) {
+ /* first VGA diff gain */
+ BBvSetVGAGainOffset(priv, priv->byBBVGANew);
+
+ dev_dbg(&priv->pcid->dev,
+ "First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
+ (int)dbm, priv->byBBVGANew,
+ priv->byBBVGACurrent,
+ (int)priv->uBBVGADiffCount);
+ }
+
+ if (priv->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
+ dev_dbg(&priv->pcid->dev,
+ "RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
+ (int)dbm, priv->byBBVGANew,
+ priv->byBBVGACurrent,
+ (int)priv->uBBVGADiffCount);
+
+ BBvSetVGAGainOffset(priv, priv->byBBVGANew);
+ }
+}
+
static irqreturn_t device_intr(int irq, void *dev_instance)
{
struct vnt_private *pDevice = dev_instance;
@@ -1060,7 +1067,6 @@ static irqreturn_t device_intr(int irq, void *dev_instance)
unsigned long dwMIBCounter = 0;
unsigned char byOrgPageSel = 0;
int handled = 0;
- int ii = 0;
unsigned long flags;
MACvReadISR(pDevice->PortOffset, &pDevice->dwIsr);
@@ -1090,7 +1096,7 @@ static irqreturn_t device_intr(int irq, void *dev_instance)
// Must do this after doing rx/tx, cause ISR bit is slow
// than RD/TD write back
// update ISR counter
- STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic , dwMIBCounter);
+ STAvUpdate802_11Counter(&pDevice->s802_11Counter, &pDevice->scStatistic, dwMIBCounter);
while (pDevice->dwIsr != 0) {
STAvUpdateIsrStatCounter(&pDevice->scStatistic, pDevice->dwIsr);
MACvWriteISR(pDevice->PortOffset, pDevice->dwIsr);
@@ -1104,44 +1110,8 @@ static irqreturn_t device_intr(int irq, void *dev_instance)
if (pDevice->dwIsr & ISR_TBTT) {
if (pDevice->vif &&
- pDevice->op_mode != NL80211_IFTYPE_ADHOC) {
- if (pDevice->bUpdateBBVGA &&
- !(pDevice->hw->conf.flags & IEEE80211_CONF_OFFCHANNEL) &&
- pDevice->vif->bss_conf.assoc &&
- pDevice->uCurrRSSI) {
- long ldBm;
-
- RFvRSSITodBm(pDevice, (unsigned char) pDevice->uCurrRSSI, &ldBm);
- for (ii = 0; ii < BB_VGA_LEVEL; ii++) {
- if (ldBm < pDevice->ldBmThreshold[ii]) {
- pDevice->byBBVGANew = pDevice->abyBBVGA[ii];
- break;
- }
- }
- if (pDevice->byBBVGANew != pDevice->byBBVGACurrent) {
- pDevice->uBBVGADiffCount++;
- if (pDevice->uBBVGADiffCount == 1) {
- // first VGA diff gain
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
- pr_debug("First RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
- (int)ldBm,
- pDevice->byBBVGANew,
- pDevice->byBBVGACurrent,
- (int)pDevice->uBBVGADiffCount);
- }
- if (pDevice->uBBVGADiffCount >= BB_VGA_CHANGE_THRESHOLD) {
- pr_debug("RSSI[%d] NewGain[%d] OldGain[%d] Count[%d]\n",
- (int)ldBm,
- pDevice->byBBVGANew,
- pDevice->byBBVGACurrent,
- (int)pDevice->uBBVGADiffCount);
- BBvSetVGAGainOffset(pDevice, pDevice->byBBVGANew);
- }
- } else {
- pDevice->uBBVGADiffCount = 1;
- }
- }
- }
+ pDevice->op_mode != NL80211_IFTYPE_ADHOC)
+ vnt_check_bb_vga(pDevice);
pDevice->bBeaconSent = false;
if (pDevice->bEnablePSMode)
@@ -1262,12 +1232,15 @@ static int vnt_tx_packet(struct vnt_private *priv, struct sk_buff *skb)
head_td->m_td1TD1.wReqCount =
cpu_to_le16((u16)head_td->pTDInfo->dwReqCount);
- head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
+ head_td->buff_addr = cpu_to_le32(head_td->pTDInfo->skb_dma);
+
+ if (dma_idx == TYPE_AC0DMA) {
+ head_td->pTDInfo->byFlags = TD_FLAGS_NETIF_SKB;
- if (dma_idx == TYPE_AC0DMA)
MACvTransmitAC0(priv->PortOffset);
- else
+ } else {
MACvTransmit0(priv->PortOffset);
+ }
spin_unlock_irqrestore(&priv->lock, flags);
@@ -1348,8 +1321,6 @@ static int vnt_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- if (priv->bDiversityRegCtlON)
- device_init_diversity_timer(priv);
break;
case NL80211_IFTYPE_ADHOC:
MACvRegBitsOff(priv->PortOffset, MAC_REG_RCR, RCR_UNICAST);
@@ -1379,11 +1350,6 @@ static void vnt_remove_interface(struct ieee80211_hw *hw,
switch (vif->type) {
case NL80211_IFTYPE_STATION:
- if (priv->bDiversityRegCtlON) {
- del_timer(&priv->TimerSQ3Tmax1);
- del_timer(&priv->TimerSQ3Tmax2);
- del_timer(&priv->TimerSQ3Tmax3);
- }
break;
case NL80211_IFTYPE_ADHOC:
MACvRegBitsOff(priv->PortOffset, MAC_REG_TCR, TCR_AUTOBCNTX);
@@ -1420,7 +1386,7 @@ static int vnt_config(struct ieee80211_hw *hw, u32 changed)
if ((changed & IEEE80211_CONF_CHANGE_CHANNEL) ||
(conf->flags & IEEE80211_CONF_OFFCHANNEL)) {
- set_channel(priv, conf->chandef.chan->hw_value);
+ set_channel(priv, conf->chandef.chan);
if (conf->chandef.chan->band == IEEE80211_BAND_5GHZ)
bb_type = BB_TYPE_11A;
@@ -1572,6 +1538,10 @@ static void vnt_configure(struct ieee80211_hw *hw,
if (changed_flags & FIF_ALLMULTI) {
if (*total_flags & FIF_ALLMULTI) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&priv->lock, flags);
+
if (priv->mc_list_count > 2) {
MACvSelectPage1(priv->PortOffset);
@@ -1593,6 +1563,8 @@ static void vnt_configure(struct ieee80211_hw *hw,
MACvSelectPage0(priv->PortOffset);
}
+ spin_unlock_irqrestore(&priv->lock, flags);
+
rx_mode |= RCR_MULTICAST | RCR_BROADCAST;
} else {
rx_mode &= ~(RCR_MULTICAST | RCR_BROADCAST);
@@ -1676,7 +1648,7 @@ static const struct ieee80211_ops vnt_mac_ops = {
.reset_tsf = vnt_reset_tsf,
};
-int vnt_init(struct vnt_private *priv)
+static int vnt_init(struct vnt_private *priv)
{
SET_IEEE80211_PERM_ADDR(priv->hw, priv->abyCurrentNetAddr);
diff --git a/drivers/staging/vt6655/dpc.c b/drivers/staging/vt6655/dpc.c
index 977683cb7391..3c5b87ffdcac 100644
--- a/drivers/staging/vt6655/dpc.c
+++ b/drivers/staging/vt6655/dpc.c
@@ -91,6 +91,8 @@ static bool vnt_rx_data(struct vnt_private *priv, struct sk_buff *skb,
new_rsr = skb_data + bytes_received - 3;
rssi = skb_data + bytes_received - 2;
rsr = skb_data + bytes_received - 1;
+ if (*rsr & (RSR_IVLDTYP | RSR_IVLDLEN))
+ return false;
RFvRSSITodBm(priv, *rssi, &rx_dbm);
@@ -106,6 +108,9 @@ static bool vnt_rx_data(struct vnt_private *priv, struct sk_buff *skb,
rx_status.flag = 0;
rx_status.freq = hw->conf.chandef.chan->center_freq;
+ if (!(*rsr & RSR_CRCOK))
+ rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
+
hdr = (struct ieee80211_hdr *)(skb->data);
fc = hdr->frame_control;
@@ -113,13 +118,11 @@ static bool vnt_rx_data(struct vnt_private *priv, struct sk_buff *skb,
if (ieee80211_has_protected(fc)) {
if (priv->byLocalID > REV_ID_VT3253_A1)
- rx_status.flag = RX_FLAG_DECRYPTED;
- }
+ rx_status.flag |= RX_FLAG_DECRYPTED;
- if (priv->vif && priv->bDiversityEnable) {
- if (ieee80211_is_data(fc) &&
- (frame_size > 50) && priv->vif->bss_conf.assoc)
- BBvAntennaDiversity(priv, priv->rx_rate, 0);
+ /* Drop packet */
+ if (!(*new_rsr & NEWRSR_DECRYPTOK))
+ return false;
}
memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
diff --git a/drivers/staging/vt6655/mac.c b/drivers/staging/vt6655/mac.c
index 8f0d652fea7c..3653a2bd1e36 100644
--- a/drivers/staging/vt6655/mac.c
+++ b/drivers/staging/vt6655/mac.c
@@ -30,7 +30,6 @@
* MACbIsRegBitsOff - Test if All test Bits Off
* MACbIsIntDisable - Test if MAC interrupt disable
* MACvSetShortRetryLimit - Set 802.11 Short Retry limit
- * MACvGetShortRetryLimit - Get 802.11 Short Retry limit
* MACvSetLongRetryLimit - Set 802.11 Long Retry limit
* MACvSetLoopbackMode - Set MAC Loopback Mode
* MACvSaveContext - Save Context of MAC Registers
@@ -146,24 +145,6 @@ void MACvSetShortRetryLimit(void __iomem *dwIoBase, unsigned char byRetryLimit)
VNSvOutPortB(dwIoBase + MAC_REG_SRT, byRetryLimit);
}
-/*
- * Description:
- * Get 802.11 Short Retry Limit
- *
- * Parameters:
- * In:
- * dwIoBase - Base Address for MAC
- * Out:
- * pbyRetryLimit - Retry Limit Get
- *
- * Return Value: none
- *
- */
-void MACvGetShortRetryLimit(void __iomem *dwIoBase, unsigned char *pbyRetryLimit)
-{
- // get SRT
- VNSvInPortB(dwIoBase + MAC_REG_SRT, pbyRetryLimit);
-}
/*
* Description:
@@ -356,7 +337,7 @@ bool MACbSafeSoftwareReset(void __iomem *dwIoBase)
/*
* Description:
- * Trun Off MAC Rx
+ * Turn Off MAC Rx
*
* Parameters:
* In:
@@ -417,7 +398,7 @@ bool MACbSafeRxOff(void __iomem *dwIoBase)
/*
* Description:
- * Trun Off MAC Tx
+ * Turn Off MAC Tx
*
* Parameters:
* In:
@@ -808,7 +789,7 @@ bool MACbPSWakeup(void __iomem *dwIoBase)
// Check if SyncFlushOK
for (ww = 0; ww < W_MAX_TIMEOUT; ww++) {
- VNSvInPortB(dwIoBase + MAC_REG_PSCTL , &byOrgValue);
+ VNSvInPortB(dwIoBase + MAC_REG_PSCTL, &byOrgValue);
if (byOrgValue & PSCTL_WAKEDONE)
break;
}
diff --git a/drivers/staging/vt6655/mac.h b/drivers/staging/vt6655/mac.h
index e1e7e10435f6..8e0200a78b19 100644
--- a/drivers/staging/vt6655/mac.h
+++ b/drivers/staging/vt6655/mac.h
@@ -38,13 +38,11 @@
#include "upc.h"
/*--------------------- Export Definitions -------------------------*/
-//
-// Registers in the MAC
-//
+/* Registers in the MAC */
#define MAC_MAX_CONTEXT_SIZE_PAGE0 256
#define MAC_MAX_CONTEXT_SIZE_PAGE1 128
-// Registers not related to 802.11b
+/* Registers not related to 802.11b */
#define MAC_REG_BCFG0 0x00
#define MAC_REG_BCFG1 0x01
#define MAC_REG_FCR0 0x02
@@ -69,15 +67,16 @@
#define MAC_REG_TMCTL0 0x18
#define MAC_REG_TMCTL1 0x19
#define MAC_REG_TMDATA0 0x1C
-// MAC Parameter related
-#define MAC_REG_LRT 0x20 //
-#define MAC_REG_SRT 0x21 //
-#define MAC_REG_SIFS 0x22 //
-#define MAC_REG_DIFS 0x23 //
-#define MAC_REG_EIFS 0x24 //
-#define MAC_REG_SLOT 0x25 //
-#define MAC_REG_BI 0x26 //
-#define MAC_REG_CWMAXMIN0 0x28 //
+
+/* MAC Parameter related */
+#define MAC_REG_LRT 0x20
+#define MAC_REG_SRT 0x21
+#define MAC_REG_SIFS 0x22
+#define MAC_REG_DIFS 0x23
+#define MAC_REG_EIFS 0x24
+#define MAC_REG_SLOT 0x25
+#define MAC_REG_BI 0x26
+#define MAC_REG_CWMAXMIN0 0x28
#define MAC_REG_LINKOFFTOTM 0x2A
#define MAC_REG_SWTMOT 0x2B
#define MAC_REG_MIBCNTR 0x2C
@@ -85,26 +84,29 @@
#define MAC_REG_RTSFAILCNT 0x2D
#define MAC_REG_ACKFAILCNT 0x2E
#define MAC_REG_FCSERRCNT 0x2F
-// TSF Related
-#define MAC_REG_TSFCNTR 0x30 //
-#define MAC_REG_NEXTTBTT 0x38 //
-#define MAC_REG_TSFOFST 0x40 //
-#define MAC_REG_TFTCTL 0x48 //
-// WMAC Control/Status Related
-#define MAC_REG_ENCFG 0x4C //
-#define MAC_REG_PAGE1SEL 0x4F //
-#define MAC_REG_CFG 0x50 //
-#define MAC_REG_TEST 0x52 //
-#define MAC_REG_HOSTCR 0x54 //
-#define MAC_REG_MACCR 0x55 //
-#define MAC_REG_RCR 0x56 //
-#define MAC_REG_TCR 0x57 //
-#define MAC_REG_IMR 0x58 //
+
+/* TSF Related */
+#define MAC_REG_TSFCNTR 0x30
+#define MAC_REG_NEXTTBTT 0x38
+#define MAC_REG_TSFOFST 0x40
+#define MAC_REG_TFTCTL 0x48
+
+/* WMAC Control/Status Related */
+#define MAC_REG_ENCFG 0x4C
+#define MAC_REG_PAGE1SEL 0x4F
+#define MAC_REG_CFG 0x50
+#define MAC_REG_TEST 0x52
+#define MAC_REG_HOSTCR 0x54
+#define MAC_REG_MACCR 0x55
+#define MAC_REG_RCR 0x56
+#define MAC_REG_TCR 0x57
+#define MAC_REG_IMR 0x58
#define MAC_REG_ISR 0x5C
-// Power Saving Related
-#define MAC_REG_PSCFG 0x60 //
-#define MAC_REG_PSCTL 0x61 //
-#define MAC_REG_PSPWRSIG 0x62 //
+
+/* Power Saving Related */
+#define MAC_REG_PSCFG 0x60
+#define MAC_REG_PSCTL 0x61
+#define MAC_REG_PSPWRSIG 0x62
#define MAC_REG_BBCR13 0x63
#define MAC_REG_AIDATIM 0x64
#define MAC_REG_PWBT 0x66
@@ -112,41 +114,45 @@
#define MAC_REG_CALTMR 0x69
#define MAC_REG_SYNSPACCNT 0x6A
#define MAC_REG_WAKSYNOPT 0x6B
-// Baseband/IF Control Group
-#define MAC_REG_BBREGCTL 0x6C //
+
+/* Baseband/IF Control Group */
+#define MAC_REG_BBREGCTL 0x6C
#define MAC_REG_CHANNEL 0x6D
#define MAC_REG_BBREGADR 0x6E
#define MAC_REG_BBREGDATA 0x6F
-#define MAC_REG_IFREGCTL 0x70 //
-#define MAC_REG_IFDATA 0x71 //
-#define MAC_REG_ITRTMSET 0x74 //
+#define MAC_REG_IFREGCTL 0x70
+#define MAC_REG_IFDATA 0x71
+#define MAC_REG_ITRTMSET 0x74
#define MAC_REG_PAPEDELAY 0x77
-#define MAC_REG_SOFTPWRCTL 0x78 //
-#define MAC_REG_GPIOCTL0 0x7A //
-#define MAC_REG_GPIOCTL1 0x7B //
-
-// MAC DMA Related Group
-#define MAC_REG_TXDMACTL0 0x7C //
-#define MAC_REG_TXDMAPTR0 0x80 //
-#define MAC_REG_AC0DMACTL 0x84 //
-#define MAC_REG_AC0DMAPTR 0x88 //
-#define MAC_REG_BCNDMACTL 0x8C //
-#define MAC_REG_BCNDMAPTR 0x90 //
-#define MAC_REG_RXDMACTL0 0x94 //
-#define MAC_REG_RXDMAPTR0 0x98 //
-#define MAC_REG_RXDMACTL1 0x9C //
-#define MAC_REG_RXDMAPTR1 0xA0 //
-#define MAC_REG_SYNCDMACTL 0xA4 //
+#define MAC_REG_SOFTPWRCTL 0x78
+#define MAC_REG_GPIOCTL0 0x7A
+#define MAC_REG_GPIOCTL1 0x7B
+
+/* MAC DMA Related Group */
+#define MAC_REG_TXDMACTL0 0x7C
+#define MAC_REG_TXDMAPTR0 0x80
+#define MAC_REG_AC0DMACTL 0x84
+#define MAC_REG_AC0DMAPTR 0x88
+#define MAC_REG_BCNDMACTL 0x8C
+#define MAC_REG_BCNDMAPTR 0x90
+#define MAC_REG_RXDMACTL0 0x94
+#define MAC_REG_RXDMAPTR0 0x98
+#define MAC_REG_RXDMACTL1 0x9C
+#define MAC_REG_RXDMAPTR1 0xA0
+#define MAC_REG_SYNCDMACTL 0xA4
#define MAC_REG_SYNCDMAPTR 0xA8
#define MAC_REG_ATIMDMACTL 0xAC
#define MAC_REG_ATIMDMAPTR 0xB0
-// MiscFF PIO related
+
+/* MiscFF PIO related */
#define MAC_REG_MISCFFNDEX 0xB4
#define MAC_REG_MISCFFCTL 0xB6
#define MAC_REG_MISCFFDATA 0xB8
-// Extend SW Timer
+
+/* Extend SW Timer */
#define MAC_REG_TMDATA1 0xBC
-// WOW Related Group
+
+/* WOW Related Group */
#define MAC_REG_WAKEUPEN0 0xC0
#define MAC_REG_WAKEUPEN1 0xC1
#define MAC_REG_WAKEUPSR0 0xC2
@@ -156,19 +162,21 @@
#define MAC_REG_WAKE128_2 0xE4
#define MAC_REG_WAKE128_3 0xF4
-/////////////// Page 1 ///////////////////
+/************** Page 1 ******************/
#define MAC_REG_CRC_128_0 0x04
#define MAC_REG_CRC_128_1 0x06
#define MAC_REG_CRC_128_2 0x08
#define MAC_REG_CRC_128_3 0x0A
-// MAC Configuration Group
+
+/* MAC Configuration Group */
#define MAC_REG_PAR0 0x0C
#define MAC_REG_PAR4 0x10
#define MAC_REG_BSSID0 0x14
#define MAC_REG_BSSID4 0x18
#define MAC_REG_MAR0 0x1C
#define MAC_REG_MAR4 0x20
-// MAC RSPPKT INFO Group
+
+/* MAC RSPPKT INFO Group */
#define MAC_REG_RSPINF_B_1 0x24
#define MAC_REG_RSPINF_B_2 0x28
#define MAC_REG_RSPINF_B_5 0x2C
@@ -183,7 +191,7 @@
#define MAC_REG_RSPINF_A_54 0x42
#define MAC_REG_RSPINF_A_72 0x44
-// 802.11h relative
+/* 802.11h relative */
#define MAC_REG_QUIETINIT 0x60
#define MAC_REG_QUIETGAP 0x62
#define MAC_REG_QUIETDUR 0x64
@@ -195,9 +203,7 @@
#define MAC_REG_PWRCCK 0x73
#define MAC_REG_PWROFDM 0x7C
-//
-// Bits in the BCFG0 register
-//
+/* Bits in the BCFG0 register */
#define BCFG0_PERROFF 0x40
#define BCFG0_MRDMDIS 0x20
#define BCFG0_MRDLDIS 0x10
@@ -205,9 +211,7 @@
#define BCFG0_VSERREN 0x02
#define BCFG0_LATMEN 0x01
-//
-// Bits in the BCFG1 register
-//
+/* Bits in the BCFG1 register */
#define BCFG1_CFUNOPT 0x80
#define BCFG1_CREQOPT 0x40
#define BCFG1_DMA8 0x10
@@ -216,25 +220,23 @@
#define BCFG1_MIOEN 0x02
#define BCFG1_CISDLYEN 0x01
-// Bits in RAMBIST registers
-#define BISTCMD_TSTPAT5 0x00 //
-#define BISTCMD_TSTPATA 0x80 //
-#define BISTCMD_TSTERR 0x20 //
-#define BISTCMD_TSTPATF 0x18 //
-#define BISTCMD_TSTPAT0 0x10 //
-#define BISTCMD_TSTMODE 0x04 //
-#define BISTCMD_TSTITTX 0x03 //
-#define BISTCMD_TSTATRX 0x02 //
-#define BISTCMD_TSTATTX 0x01 //
-#define BISTCMD_TSTRX 0x00 //
-#define BISTSR0_BISTGO 0x01 //
-#define BISTSR1_TSTSR 0x01 //
-#define BISTSR2_CMDPRTEN 0x02 //
-#define BISTSR2_RAMTSTEN 0x01 //
-
-//
-// Bits in the I2MCFG EEPROM register
-//
+/* Bits in RAMBIST registers */
+#define BISTCMD_TSTPAT5 0x00
+#define BISTCMD_TSTPATA 0x80
+#define BISTCMD_TSTERR 0x20
+#define BISTCMD_TSTPATF 0x18
+#define BISTCMD_TSTPAT0 0x10
+#define BISTCMD_TSTMODE 0x04
+#define BISTCMD_TSTITTX 0x03
+#define BISTCMD_TSTATRX 0x02
+#define BISTCMD_TSTATTX 0x01
+#define BISTCMD_TSTRX 0x00
+#define BISTSR0_BISTGO 0x01
+#define BISTSR1_TSTSR 0x01
+#define BISTSR2_CMDPRTEN 0x02
+#define BISTSR2_RAMTSTEN 0x01
+
+/* Bits in the I2MCFG EEPROM register */
#define I2MCFG_BOUNDCTL 0x80
#define I2MCFG_WAITCTL 0x20
#define I2MCFG_SCLOECTL 0x10
@@ -243,50 +245,38 @@
#define I2MCFG_I2MLDSEQ 0x02
#define I2MCFG_I2CMFAST 0x01
-//
-// Bits in the I2MCSR EEPROM register
-//
+/* Bits in the I2MCSR EEPROM register */
#define I2MCSR_EEMW 0x80
#define I2MCSR_EEMR 0x40
#define I2MCSR_AUTOLD 0x08
#define I2MCSR_NACK 0x02
#define I2MCSR_DONE 0x01
-//
-// Bits in the PMC1 register
-//
+/* Bits in the PMC1 register */
#define SPS_RST 0x80
#define PCISTIKY 0x40
#define PME_OVR 0x02
-//
-// Bits in the STICKYHW register
-//
+/* Bits in the STICKYHW register */
#define STICKHW_DS1_SHADOW 0x02
#define STICKHW_DS0_SHADOW 0x01
-//
-// Bits in the TMCTL register
-//
+/* Bits in the TMCTL register */
#define TMCTL_TSUSP 0x04
#define TMCTL_TMD 0x02
#define TMCTL_TE 0x01
-//
-// Bits in the TFTCTL register
-//
-#define TFTCTL_HWUTSF 0x80 //
+/* Bits in the TFTCTL register */
+#define TFTCTL_HWUTSF 0x80
#define TFTCTL_TBTTSYNC 0x40
#define TFTCTL_HWUTSFEN 0x20
-#define TFTCTL_TSFCNTRRD 0x10 //
-#define TFTCTL_TBTTSYNCEN 0x08 //
-#define TFTCTL_TSFSYNCEN 0x04 //
-#define TFTCTL_TSFCNTRST 0x02 //
-#define TFTCTL_TSFCNTREN 0x01 //
-
-//
-// Bits in the EnhanceCFG register
-//
+#define TFTCTL_TSFCNTRRD 0x10
+#define TFTCTL_TBTTSYNCEN 0x08
+#define TFTCTL_TSFSYNCEN 0x04
+#define TFTCTL_TSFCNTRST 0x02
+#define TFTCTL_TSFCNTREN 0x01
+
+/* Bits in the EnhanceCFG register */
#define EnCFG_BarkerPream 0x00020000
#define EnCFG_NXTBTTCFPSTR 0x00010000
#define EnCFG_BcnSusClr 0x00000200
@@ -300,14 +290,10 @@
#define EnCFG_BBType_b 0x00000001
#define EnCFG_BBType_a 0x00000000
-//
-// Bits in the Page1Sel register
-//
+/* Bits in the Page1Sel register */
#define PAGE1_SEL 0x01
-//
-// Bits in the CFG register
-//
+/* Bits in the CFG register */
#define CFG_TKIPOPT 0x80
#define CFG_RXDMAOPT 0x40
#define CFG_TMOT_SW 0x20
@@ -318,242 +304,196 @@
#define CFG_NOTXTIMEOUT 0x02
#define CFG_NOBUFOPT 0x01
-//
-// Bits in the TEST register
-//
-#define TEST_LBEXT 0x80 //
-#define TEST_LBINT 0x40 //
-#define TEST_LBNONE 0x00 //
-#define TEST_SOFTINT 0x20 //
-#define TEST_CONTTX 0x10 //
-#define TEST_TXPE 0x08 //
-#define TEST_NAVDIS 0x04 //
-#define TEST_NOCTS 0x02 //
-#define TEST_NOACK 0x01 //
-
-//
-// Bits in the HOSTCR register
-//
-#define HOSTCR_TXONST 0x80 //
-#define HOSTCR_RXONST 0x40 //
-#define HOSTCR_ADHOC 0x20 // Network Type 1 = Ad-hoc
-#define HOSTCR_AP 0x10 // Port Type 1 = AP
-#define HOSTCR_TXON 0x08 //0000 1000
-#define HOSTCR_RXON 0x04 //0000 0100
-#define HOSTCR_MACEN 0x02 //0000 0010
-#define HOSTCR_SOFTRST 0x01 //0000 0001
-
-//
-// Bits in the MACCR register
-//
-#define MACCR_SYNCFLUSHOK 0x04 //
-#define MACCR_SYNCFLUSH 0x02 //
-#define MACCR_CLRNAV 0x01 //
-
-// Bits in the MAC_REG_GPIOCTL0 register
-//
-#define LED_ACTSET 0x01 //
-#define LED_RFOFF 0x02 //
-#define LED_NOCONNECT 0x04 //
-//
-// Bits in the RCR register
-//
+/* Bits in the TEST register */
+#define TEST_LBEXT 0x80
+#define TEST_LBINT 0x40
+#define TEST_LBNONE 0x00
+#define TEST_SOFTINT 0x20
+#define TEST_CONTTX 0x10
+#define TEST_TXPE 0x08
+#define TEST_NAVDIS 0x04
+#define TEST_NOCTS 0x02
+#define TEST_NOACK 0x01
+
+/* Bits in the HOSTCR register */
+#define HOSTCR_TXONST 0x80
+#define HOSTCR_RXONST 0x40
+#define HOSTCR_ADHOC 0x20 /* Network Type 1 = Ad-hoc */
+#define HOSTCR_AP 0x10 /* Port Type 1 = AP */
+#define HOSTCR_TXON 0x08 /* 0000 1000 */
+#define HOSTCR_RXON 0x04 /* 0000 0100 */
+#define HOSTCR_MACEN 0x02 /* 0000 0010 */
+#define HOSTCR_SOFTRST 0x01 /* 0000 0001 */
+
+/* Bits in the MACCR register */
+#define MACCR_SYNCFLUSHOK 0x04
+#define MACCR_SYNCFLUSH 0x02
+#define MACCR_CLRNAV 0x01
+
+/* Bits in the MAC_REG_GPIOCTL0 register */
+#define LED_ACTSET 0x01
+#define LED_RFOFF 0x02
+#define LED_NOCONNECT 0x04
+
+/* Bits in the RCR register */
#define RCR_SSID 0x80
-#define RCR_RXALLTYPE 0x40 //
-#define RCR_UNICAST 0x20 //
-#define RCR_BROADCAST 0x10 //
-#define RCR_MULTICAST 0x08 //
-#define RCR_WPAERR 0x04 //
-#define RCR_ERRCRC 0x02 //
-#define RCR_BSSID 0x01 //
-
-//
-// Bits in the TCR register
-//
-#define TCR_SYNCDCFOPT 0x02 //
-#define TCR_AUTOBCNTX 0x01 // Beacon automatically transmit enable
-
-//
-// Bits in the IMR register
-//
-#define IMR_MEASURESTART 0x80000000 //
-#define IMR_QUIETSTART 0x20000000 //
-#define IMR_RADARDETECT 0x10000000 //
-#define IMR_MEASUREEND 0x08000000 //
-#define IMR_SOFTTIMER1 0x00200000 //
-#define IMR_RXDMA1 0x00001000 //0000 0000 0001 0000 0000 0000
-#define IMR_RXNOBUF 0x00000800 //
-#define IMR_MIBNEARFULL 0x00000400 //
-#define IMR_SOFTINT 0x00000200 //
-#define IMR_FETALERR 0x00000100 //
-#define IMR_WATCHDOG 0x00000080 //
-#define IMR_SOFTTIMER 0x00000040 //
-#define IMR_GPIO 0x00000020 //
-#define IMR_TBTT 0x00000010 //
-#define IMR_RXDMA0 0x00000008 //
-#define IMR_BNTX 0x00000004 //
-#define IMR_AC0DMA 0x00000002 //
-#define IMR_TXDMA0 0x00000001 //
-
-//
-// Bits in the ISR register
-//
-
-#define ISR_MEASURESTART 0x80000000 //
-#define ISR_QUIETSTART 0x20000000 //
-#define ISR_RADARDETECT 0x10000000 //
-#define ISR_MEASUREEND 0x08000000 //
-#define ISR_SOFTTIMER1 0x00200000 //
-#define ISR_RXDMA1 0x00001000 //0000 0000 0001 0000 0000 0000
-#define ISR_RXNOBUF 0x00000800 //0000 0000 0000 1000 0000 0000
-#define ISR_MIBNEARFULL 0x00000400 //0000 0000 0000 0100 0000 0000
-#define ISR_SOFTINT 0x00000200 //
-#define ISR_FETALERR 0x00000100 //
-#define ISR_WATCHDOG 0x00000080 //
-#define ISR_SOFTTIMER 0x00000040 //
-#define ISR_GPIO 0x00000020 //
-#define ISR_TBTT 0x00000010 //
-#define ISR_RXDMA0 0x00000008 //
-#define ISR_BNTX 0x00000004 //
-#define ISR_AC0DMA 0x00000002 //
-#define ISR_TXDMA0 0x00000001 //
-
-//
-// Bits in the PSCFG register
-//
-#define PSCFG_PHILIPMD 0x40 //
-#define PSCFG_WAKECALEN 0x20 //
-#define PSCFG_WAKETMREN 0x10 //
-#define PSCFG_BBPSPROG 0x08 //
-#define PSCFG_WAKESYN 0x04 //
-#define PSCFG_SLEEPSYN 0x02 //
-#define PSCFG_AUTOSLEEP 0x01 //
-
-//
-// Bits in the PSCTL register
-//
-#define PSCTL_WAKEDONE 0x20 //
-#define PSCTL_PS 0x10 //
-#define PSCTL_GO2DOZE 0x08 //
-#define PSCTL_LNBCN 0x04 //
-#define PSCTL_ALBCN 0x02 //
-#define PSCTL_PSEN 0x01 //
-
-//
-// Bits in the PSPWSIG register
-//
-#define PSSIG_WPE3 0x80 //
-#define PSSIG_WPE2 0x40 //
-#define PSSIG_WPE1 0x20 //
-#define PSSIG_WRADIOPE 0x10 //
-#define PSSIG_SPE3 0x08 //
-#define PSSIG_SPE2 0x04 //
-#define PSSIG_SPE1 0x02 //
-#define PSSIG_SRADIOPE 0x01 //
-
-//
-// Bits in the BBREGCTL register
-//
-#define BBREGCTL_DONE 0x04 //
-#define BBREGCTL_REGR 0x02 //
-#define BBREGCTL_REGW 0x01 //
-
-//
-// Bits in the IFREGCTL register
-//
-#define IFREGCTL_DONE 0x04 //
-#define IFREGCTL_IFRF 0x02 //
-#define IFREGCTL_REGW 0x01 //
-
-//
-// Bits in the SOFTPWRCTL register
-//
-#define SOFTPWRCTL_RFLEOPT 0x0800 //
-#define SOFTPWRCTL_TXPEINV 0x0200 //
-#define SOFTPWRCTL_SWPECTI 0x0100 //
-#define SOFTPWRCTL_SWPAPE 0x0020 //
-#define SOFTPWRCTL_SWCALEN 0x0010 //
-#define SOFTPWRCTL_SWRADIO_PE 0x0008 //
-#define SOFTPWRCTL_SWPE2 0x0004 //
-#define SOFTPWRCTL_SWPE1 0x0002 //
-#define SOFTPWRCTL_SWPE3 0x0001 //
-
-//
-// Bits in the GPIOCTL1 register
-//
-#define GPIO1_DATA1 0x20 //
-#define GPIO1_MD1 0x10 //
-#define GPIO1_DATA0 0x02 //
-#define GPIO1_MD0 0x01 //
-
-//
-// Bits in the DMACTL register
-//
-#define DMACTL_CLRRUN 0x00080000 //
-#define DMACTL_RUN 0x00000008 //
-#define DMACTL_WAKE 0x00000004 //
-#define DMACTL_DEAD 0x00000002 //
-#define DMACTL_ACTIVE 0x00000001 //
-//
-// Bits in the RXDMACTL0 register
-//
-#define RX_PERPKT 0x00000100 //
-#define RX_PERPKTCLR 0x01000000 //
-//
-// Bits in the BCNDMACTL register
-//
-#define BEACON_READY 0x01 //
-//
-// Bits in the MISCFFCTL register
-//
-#define MISCFFCTL_WRITE 0x0001 //
-
-//
-// Bits in WAKEUPEN0
-//
+#define RCR_RXALLTYPE 0x40
+#define RCR_UNICAST 0x20
+#define RCR_BROADCAST 0x10
+#define RCR_MULTICAST 0x08
+#define RCR_WPAERR 0x04
+#define RCR_ERRCRC 0x02
+#define RCR_BSSID 0x01
+
+/* Bits in the TCR register */
+#define TCR_SYNCDCFOPT 0x02
+#define TCR_AUTOBCNTX 0x01 /* Beacon automatically transmit enable */
+
+/* Bits in the IMR register */
+#define IMR_MEASURESTART 0x80000000
+#define IMR_QUIETSTART 0x20000000
+#define IMR_RADARDETECT 0x10000000
+#define IMR_MEASUREEND 0x08000000
+#define IMR_SOFTTIMER1 0x00200000
+#define IMR_RXDMA1 0x00001000 /* 0000 0000 0001 0000 0000 0000 */
+#define IMR_RXNOBUF 0x00000800
+#define IMR_MIBNEARFULL 0x00000400
+#define IMR_SOFTINT 0x00000200
+#define IMR_FETALERR 0x00000100
+#define IMR_WATCHDOG 0x00000080
+#define IMR_SOFTTIMER 0x00000040
+#define IMR_GPIO 0x00000020
+#define IMR_TBTT 0x00000010
+#define IMR_RXDMA0 0x00000008
+#define IMR_BNTX 0x00000004
+#define IMR_AC0DMA 0x00000002
+#define IMR_TXDMA0 0x00000001
+
+/* Bits in the ISR register */
+#define ISR_MEASURESTART 0x80000000
+#define ISR_QUIETSTART 0x20000000
+#define ISR_RADARDETECT 0x10000000
+#define ISR_MEASUREEND 0x08000000
+#define ISR_SOFTTIMER1 0x00200000
+#define ISR_RXDMA1 0x00001000 /* 0000 0000 0001 0000 0000 0000 */
+#define ISR_RXNOBUF 0x00000800 /* 0000 0000 0000 1000 0000 0000 */
+#define ISR_MIBNEARFULL 0x00000400 /* 0000 0000 0000 0100 0000 0000 */
+#define ISR_SOFTINT 0x00000200
+#define ISR_FETALERR 0x00000100
+#define ISR_WATCHDOG 0x00000080
+#define ISR_SOFTTIMER 0x00000040
+#define ISR_GPIO 0x00000020
+#define ISR_TBTT 0x00000010
+#define ISR_RXDMA0 0x00000008
+#define ISR_BNTX 0x00000004
+#define ISR_AC0DMA 0x00000002
+#define ISR_TXDMA0 0x00000001
+
+/* Bits in the PSCFG register */
+#define PSCFG_PHILIPMD 0x40
+#define PSCFG_WAKECALEN 0x20
+#define PSCFG_WAKETMREN 0x10
+#define PSCFG_BBPSPROG 0x08
+#define PSCFG_WAKESYN 0x04
+#define PSCFG_SLEEPSYN 0x02
+#define PSCFG_AUTOSLEEP 0x01
+
+/* Bits in the PSCTL register */
+#define PSCTL_WAKEDONE 0x20
+#define PSCTL_PS 0x10
+#define PSCTL_GO2DOZE 0x08
+#define PSCTL_LNBCN 0x04
+#define PSCTL_ALBCN 0x02
+#define PSCTL_PSEN 0x01
+
+/* Bits in the PSPWSIG register */
+#define PSSIG_WPE3 0x80
+#define PSSIG_WPE2 0x40
+#define PSSIG_WPE1 0x20
+#define PSSIG_WRADIOPE 0x10
+#define PSSIG_SPE3 0x08
+#define PSSIG_SPE2 0x04
+#define PSSIG_SPE1 0x02
+#define PSSIG_SRADIOPE 0x01
+
+/* Bits in the BBREGCTL register */
+#define BBREGCTL_DONE 0x04
+#define BBREGCTL_REGR 0x02
+#define BBREGCTL_REGW 0x01
+
+/* Bits in the IFREGCTL register */
+#define IFREGCTL_DONE 0x04
+#define IFREGCTL_IFRF 0x02
+#define IFREGCTL_REGW 0x01
+
+/* Bits in the SOFTPWRCTL register */
+#define SOFTPWRCTL_RFLEOPT 0x0800
+#define SOFTPWRCTL_TXPEINV 0x0200
+#define SOFTPWRCTL_SWPECTI 0x0100
+#define SOFTPWRCTL_SWPAPE 0x0020
+#define SOFTPWRCTL_SWCALEN 0x0010
+#define SOFTPWRCTL_SWRADIO_PE 0x0008
+#define SOFTPWRCTL_SWPE2 0x0004
+#define SOFTPWRCTL_SWPE1 0x0002
+#define SOFTPWRCTL_SWPE3 0x0001
+
+/* Bits in the GPIOCTL1 register */
+#define GPIO1_DATA1 0x20
+#define GPIO1_MD1 0x10
+#define GPIO1_DATA0 0x02
+#define GPIO1_MD0 0x01
+
+/* Bits in the DMACTL register */
+#define DMACTL_CLRRUN 0x00080000
+#define DMACTL_RUN 0x00000008
+#define DMACTL_WAKE 0x00000004
+#define DMACTL_DEAD 0x00000002
+#define DMACTL_ACTIVE 0x00000001
+
+/* Bits in the RXDMACTL0 register */
+#define RX_PERPKT 0x00000100
+#define RX_PERPKTCLR 0x01000000
+
+/* Bits in the BCNDMACTL register */
+#define BEACON_READY 0x01
+
+/* Bits in the MISCFFCTL register */
+#define MISCFFCTL_WRITE 0x0001
+
+/* Bits in WAKEUPEN0 */
#define WAKEUPEN0_DIRPKT 0x10
#define WAKEUPEN0_LINKOFF 0x08
#define WAKEUPEN0_ATIMEN 0x04
#define WAKEUPEN0_TIMEN 0x02
#define WAKEUPEN0_MAGICEN 0x01
-//
-// Bits in WAKEUPEN1
-//
+/* Bits in WAKEUPEN1 */
#define WAKEUPEN1_128_3 0x08
#define WAKEUPEN1_128_2 0x04
#define WAKEUPEN1_128_1 0x02
#define WAKEUPEN1_128_0 0x01
-//
-// Bits in WAKEUPSR0
-//
+/* Bits in WAKEUPSR0 */
#define WAKEUPSR0_DIRPKT 0x10
#define WAKEUPSR0_LINKOFF 0x08
#define WAKEUPSR0_ATIMEN 0x04
#define WAKEUPSR0_TIMEN 0x02
#define WAKEUPSR0_MAGICEN 0x01
-//
-// Bits in WAKEUPSR1
-//
+/* Bits in WAKEUPSR1 */
#define WAKEUPSR1_128_3 0x08
#define WAKEUPSR1_128_2 0x04
#define WAKEUPSR1_128_1 0x02
#define WAKEUPSR1_128_0 0x01
-//
-// Bits in the MAC_REG_GPIOCTL register
-//
-#define GPIO0_MD 0x01 //
-#define GPIO0_DATA 0x02 //
-#define GPIO0_INTMD 0x04 //
-#define GPIO1_MD 0x10 //
-#define GPIO1_DATA 0x20 //
-
-//
-// Bits in the MSRCTL register
-//
+/* Bits in the MAC_REG_GPIOCTL register */
+#define GPIO0_MD 0x01
+#define GPIO0_DATA 0x02
+#define GPIO0_INTMD 0x04
+#define GPIO1_MD 0x10
+#define GPIO1_DATA 0x20
+
+/* Bits in the MSRCTL register */
#define MSRCTL_FINISH 0x80
#define MSRCTL_READY 0x40
#define MSRCTL_RADARDETECT 0x20
@@ -562,28 +502,27 @@
#define MSRCTL_QUIETRPT 0x04
#define MSRCTL_QUIETINT 0x02
#define MSRCTL_QUIETEN 0x01
-//
-// Bits in the MSRCTL1 register
-//
+
+/* Bits in the MSRCTL1 register */
#define MSRCTL1_TXPWR 0x08
#define MSRCTL1_CSAPAREN 0x04
#define MSRCTL1_TXPAUSE 0x01
-// Loopback mode
-#define MAC_LB_EXT 0x02 //
-#define MAC_LB_INTERNAL 0x01 //
-#define MAC_LB_NONE 0x00 //
+/* Loopback mode */
+#define MAC_LB_EXT 0x02
+#define MAC_LB_INTERNAL 0x01
+#define MAC_LB_NONE 0x00
#define Default_BI 0x200
-// MiscFIFO Offset
+/* MiscFIFO Offset */
#define MISCFIFO_KEYETRY0 32
#define MISCFIFO_KEYENTRYSIZE 22
#define MISCFIFO_SYNINFO_IDX 10
#define MISCFIFO_SYNDATA_IDX 11
#define MISCFIFO_SYNDATASIZE 21
-// enabled mask value of irq
+/* enabled mask value of irq */
#define IMR_MASK_VALUE (IMR_SOFTTIMER1 | \
IMR_RXDMA1 | \
IMR_RXNOBUF | \
@@ -599,15 +538,13 @@
IMR_AC0DMA | \
IMR_TXDMA0)
-// max time out delay time
-#define W_MAX_TIMEOUT 0xFFF0U //
+/* max time out delay time */
+#define W_MAX_TIMEOUT 0xFFF0U
-// wait time within loop
-#define CB_DELAY_LOOP_WAIT 10 // 10ms
+/* wait time within loop */
+#define CB_DELAY_LOOP_WAIT 10 /* 10ms */
-//
-// revision id
-//
+/* revision id */
#define REV_ID_VT3253_A0 0x00
#define REV_ID_VT3253_A1 0x01
#define REV_ID_VT3253_B0 0x08
@@ -691,12 +628,12 @@ do { \
VNSvInPortD(dwIoBase + MAC_REG_ATIMDMAPTR, \
(unsigned long *)pdwCurrDescAddr)
-// set the chip with current BCN tx descriptor address
+/* set the chip with current BCN tx descriptor address */
#define MACvSetCurrBCNTxDescAddr(dwIoBase, dwCurrDescAddr) \
VNSvOutPortD(dwIoBase + MAC_REG_BCNDMAPTR, \
dwCurrDescAddr)
-// set the chip with current BCN length
+/* set the chip with current BCN length */
#define MACvSetCurrBCNLength(dwIoBase, wCurrBCNLength) \
VNSvOutPortW(dwIoBase + MAC_REG_BCNDMACTL+2, \
wCurrBCNLength)
@@ -888,7 +825,7 @@ do { \
VNSvOutPortB(dwIoBase + MAC_REG_PAGE1SEL, 1)
#define MACvReadMIBCounter(dwIoBase, pdwCounter) \
- VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR , pdwCounter)
+ VNSvInPortD(dwIoBase + MAC_REG_MIBCNTR, pdwCounter)
#define MACvPwrEvntDisable(dwIoBase) \
VNSvOutPortW(dwIoBase + MAC_REG_WAKEUPEN0, 0x0000)
@@ -896,7 +833,7 @@ do { \
#define MACvEnableProtectMD(dwIoBase) \
do { \
unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue); \
dwOrgValue = dwOrgValue | EnCFG_ProtectMd; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
} while (0)
@@ -904,7 +841,7 @@ do { \
#define MACvDisableProtectMD(dwIoBase) \
do { \
unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue); \
dwOrgValue = dwOrgValue & ~EnCFG_ProtectMd; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
} while (0)
@@ -912,7 +849,7 @@ do { \
#define MACvEnableBarkerPreambleMd(dwIoBase) \
do { \
unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue); \
dwOrgValue = dwOrgValue | EnCFG_BarkerPream; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
} while (0)
@@ -920,7 +857,7 @@ do { \
#define MACvDisableBarkerPreambleMd(dwIoBase) \
do { \
unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue); \
dwOrgValue = dwOrgValue & ~EnCFG_BarkerPream; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
} while (0)
@@ -928,7 +865,7 @@ do { \
#define MACvSetBBType(dwIoBase, byTyp) \
do { \
unsigned long dwOrgValue; \
- VNSvInPortD(dwIoBase + MAC_REG_ENCFG , &dwOrgValue); \
+ VNSvInPortD(dwIoBase + MAC_REG_ENCFG, &dwOrgValue); \
dwOrgValue = dwOrgValue & ~EnCFG_BBType_MASK; \
dwOrgValue = dwOrgValue | (unsigned long)byTyp; \
VNSvOutPortD(dwIoBase + MAC_REG_ENCFG, dwOrgValue); \
@@ -953,15 +890,18 @@ do { \
#define MACvSetRFLE_LatchBase(dwIoBase) \
MACvWordRegBitsOn(dwIoBase, MAC_REG_SOFTPWRCTL, SOFTPWRCTL_RFLEOPT)
-bool MACbIsRegBitsOn(void __iomem *dwIoBase, unsigned char byRegOfs, unsigned char byTestBits);
-bool MACbIsRegBitsOff(void __iomem *dwIoBase, unsigned char byRegOfs, unsigned char byTestBits);
+bool MACbIsRegBitsOn(void __iomem *dwIoBase, unsigned char byRegOfs,
+ unsigned char byTestBits);
+bool MACbIsRegBitsOff(void __iomem *dwIoBase, unsigned char byRegOfs,
+ unsigned char byTestBits);
bool MACbIsIntDisable(void __iomem *dwIoBase);
void MACvSetShortRetryLimit(void __iomem *dwIoBase, unsigned char byRetryLimit);
void MACvSetLongRetryLimit(void __iomem *dwIoBase, unsigned char byRetryLimit);
-void MACvGetLongRetryLimit(void __iomem *dwIoBase, unsigned char *pbyRetryLimit);
+void MACvGetLongRetryLimit(void __iomem *dwIoBase,
+ unsigned char *pbyRetryLimit);
void MACvSetLoopbackMode(void __iomem *dwIoBase, unsigned char byLoopbackMode);
@@ -975,22 +915,32 @@ bool MACbSafeTxOff(void __iomem *dwIoBase);
bool MACbSafeStop(void __iomem *dwIoBase);
bool MACbShutdown(void __iomem *dwIoBase);
void MACvInitialize(void __iomem *dwIoBase);
-void MACvSetCurrRx0DescAddr(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrRx1DescAddr(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrTXDescAddr(int iTxType, void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrTx0DescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrAC0DescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrSyncDescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
-void MACvSetCurrATIMDescAddrEx(void __iomem *dwIoBase, unsigned long dwCurrDescAddr);
+void MACvSetCurrRx0DescAddr(void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
+void MACvSetCurrRx1DescAddr(void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
+void MACvSetCurrTXDescAddr(int iTxType, void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
+void MACvSetCurrTx0DescAddrEx(void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
+void MACvSetCurrAC0DescAddrEx(void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
+void MACvSetCurrSyncDescAddrEx(void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
+void MACvSetCurrATIMDescAddrEx(void __iomem *dwIoBase,
+ unsigned long dwCurrDescAddr);
void MACvTimer0MicroSDelay(void __iomem *dwIoBase, unsigned int uDelay);
void MACvOneShotTimer1MicroSec(void __iomem *dwIoBase, unsigned int uDelayTime);
-void MACvSetMISCFifo(void __iomem *dwIoBase, unsigned short wOffset, unsigned long dwData);
+void MACvSetMISCFifo(void __iomem *dwIoBase, unsigned short wOffset,
+ unsigned long dwData);
bool MACbPSWakeup(void __iomem *dwIoBase);
-void MACvSetKeyEntry(void __iomem *dwIoBase, unsigned short wKeyCtl, unsigned int uEntryIdx,
- unsigned int uKeyIdx, unsigned char *pbyAddr, u32 *pdwKey, unsigned char byLocalID);
+void MACvSetKeyEntry(void __iomem *dwIoBase, unsigned short wKeyCtl,
+ unsigned int uEntryIdx, unsigned int uKeyIdx,
+ unsigned char *pbyAddr, u32 *pdwKey,
+ unsigned char byLocalID);
void MACvDisableKeyEntry(void __iomem *dwIoBase, unsigned int uEntryIdx);
-#endif // __MAC_H__
+#endif /* __MAC_H__ */
diff --git a/drivers/staging/vt6655/power.c b/drivers/staging/vt6655/power.c
index e826f07e91c0..be3c4e949b6a 100644
--- a/drivers/staging/vt6655/power.c
+++ b/drivers/staging/vt6655/power.c
@@ -71,33 +71,33 @@ PSvEnablePowerSaving(
struct vnt_private *pDevice = hDeviceContext;
u16 wAID = pDevice->current_aid | BIT(14) | BIT(15);
- // set period of power up before TBTT
+ /* set period of power up before TBTT */
VNSvOutPortW(pDevice->PortOffset + MAC_REG_PWBT, C_PWBT);
if (pDevice->op_mode != NL80211_IFTYPE_ADHOC) {
- // set AID
+ /* set AID */
VNSvOutPortW(pDevice->PortOffset + MAC_REG_AIDATIM, wAID);
} else {
- // set ATIM Window
+ /* set ATIM Window */
#if 0 /* TODO atim window */
MACvWriteATIMW(pDevice->PortOffset, pMgmt->wCurrATIMWindow);
#endif
}
- // Set AutoSleep
+ /* Set AutoSleep */
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
- // Set HWUTSF
+ /* Set HWUTSF */
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
if (wListenInterval >= 2) {
- // clear always listen beacon
+ /* clear always listen beacon */
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
- // first time set listen next beacon
+ /* first time set listen next beacon */
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_LNBCN);
} else {
- // always listen beacon
+ /* always listen beacon */
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
}
- // enable power saving hw function
+ /* enable power saving hw function */
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_PSEN);
pDevice->bEnablePSMode = true;
@@ -122,13 +122,13 @@ PSvDisablePowerSaving(
{
struct vnt_private *pDevice = hDeviceContext;
- // disable power saving hw function
+ /* disable power saving hw function */
MACbPSWakeup(pDevice->PortOffset);
- //clear AutoSleep
+ /* clear AutoSleep */
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_PSCFG, PSCFG_AUTOSLEEP);
- //clear HWUTSF
+ /* clear HWUTSF */
MACvRegBitsOff(pDevice->PortOffset, MAC_REG_TFTCTL, TFTCTL_HWUTSF);
- // set always listen beacon
+ /* set always listen beacon */
MACvRegBitsOn(pDevice->PortOffset, MAC_REG_PSCTL, PSCTL_ALBCN);
pDevice->bEnablePSMode = false;
diff --git a/drivers/staging/vt6655/rf.c b/drivers/staging/vt6655/rf.c
index 32ef99341e20..941b2adca95a 100644
--- a/drivers/staging/vt6655/rf.c
+++ b/drivers/staging/vt6655/rf.c
@@ -651,7 +651,8 @@ bool RFbInit(
* Return Value: true if succeeded; false if failed.
*
*/
-bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType, unsigned char byChannel)
+bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType,
+ u16 byChannel)
{
bool bResult = true;
@@ -687,7 +688,8 @@ bool RFbSelectChannel(struct vnt_private *priv, unsigned char byRFType, unsigned
* Return Value: None.
*
*/
-bool RFvWriteWakeProgSyn(struct vnt_private *priv, unsigned char byRFType, unsigned int uChannel)
+bool RFvWriteWakeProgSyn(struct vnt_private *priv, unsigned char byRFType,
+ u16 uChannel)
{
void __iomem *dwIoBase = priv->PortOffset;
int ii;
@@ -767,13 +769,12 @@ bool RFvWriteWakeProgSyn(struct vnt_private *priv, unsigned char byRFType, unsig
bool RFbSetPower(
struct vnt_private *priv,
unsigned int uRATE,
- unsigned int uCH
+ u16 uCH
)
{
bool bResult = true;
unsigned char byPwr = 0;
unsigned char byDec = 0;
- unsigned char byPwrdBm = 0;
if (priv->dwDiagRefCount != 0)
return true;
@@ -786,8 +787,10 @@ bool RFbSetPower(
case RATE_2M:
case RATE_5M:
case RATE_11M:
+ if (uCH > CB_MAX_CHANNEL_24G)
+ return false;
+
byPwr = priv->abyCCKPwrTbl[uCH];
- byPwrdBm = priv->abyCCKDefaultPwr[uCH];
break;
case RATE_6M:
case RATE_9M:
@@ -801,15 +804,6 @@ bool RFbSetPower(
if (byDec >= priv->byMaxPwrLevel)
byDec = priv->byMaxPwrLevel-1;
- if (priv->byRFType == RF_UW2452) {
- byPwrdBm = byDec - byPwr;
- byPwrdBm /= 3;
- } else {
- byPwrdBm = byDec - byPwr;
- byPwrdBm >>= 1;
- }
-
- byPwrdBm += priv->abyOFDMDefaultPwr[uCH];
byPwr = byDec;
break;
case RATE_24M:
@@ -817,7 +811,6 @@ bool RFbSetPower(
case RATE_48M:
case RATE_54M:
byPwr = priv->abyOFDMPwrTbl[uCH];
- byPwrdBm = priv->abyOFDMDefaultPwr[uCH];
break;
}
@@ -937,8 +930,8 @@ RFvRSSITodBm(
/* Post processing for the 11b/g and 11a.
* for save time on changing Reg2,3,5,7,10,12,15 */
bool RFbAL7230SelectChannelPostProcess(struct vnt_private *priv,
- unsigned char byOldChannel,
- unsigned char byNewChannel)
+ u16 byOldChannel,
+ u16 byNewChannel)
{
bool bResult;
diff --git a/drivers/staging/vt6655/rf.h b/drivers/staging/vt6655/rf.h
index 8a6e2cfedaa5..2ea21e2b00f2 100644
--- a/drivers/staging/vt6655/rf.h
+++ b/drivers/staging/vt6655/rf.h
@@ -74,12 +74,12 @@
/*--------------------- Export Functions --------------------------*/
bool IFRFbWriteEmbedded(struct vnt_private *, unsigned long dwData);
-bool RFbSelectChannel(struct vnt_private *, unsigned char byRFType, unsigned char byChannel);
+bool RFbSelectChannel(struct vnt_private *, unsigned char byRFType, u16);
bool RFbInit(
struct vnt_private *
);
-bool RFvWriteWakeProgSyn(struct vnt_private *, unsigned char byRFType, unsigned int uChannel);
-bool RFbSetPower(struct vnt_private *, unsigned int uRATE, unsigned int uCH);
+bool RFvWriteWakeProgSyn(struct vnt_private *, unsigned char byRFType, u16);
+bool RFbSetPower(struct vnt_private *, unsigned int uRATE, u16);
bool RFbRawSetPower(
struct vnt_private *,
unsigned char byPwr,
@@ -94,7 +94,7 @@ RFvRSSITodBm(
);
//{{ RobertYu: 20050104
-bool RFbAL7230SelectChannelPostProcess(struct vnt_private *, unsigned char byOldChannel, unsigned char byNewChannel);
+bool RFbAL7230SelectChannelPostProcess(struct vnt_private *, u16, u16);
//}} RobertYu
#endif // __RF_H__
diff --git a/drivers/staging/vt6655/rxtx.c b/drivers/staging/vt6655/rxtx.c
index b5b0155961f2..07ce3fd88e70 100644
--- a/drivers/staging/vt6655/rxtx.c
+++ b/drivers/staging/vt6655/rxtx.c
@@ -205,7 +205,7 @@ s_uGetRTSCTSRsvTime(
unsigned short wCurrentRate
)
{
- unsigned int uRrvTime , uRTSTime, uCTSTime, uAckTime, uDataTime;
+ unsigned int uRrvTime, uRTSTime, uCTSTime, uAckTime, uDataTime;
uRrvTime = uRTSTime = uCTSTime = uAckTime = uDataTime = 0;
@@ -1207,7 +1207,6 @@ s_cbFillTxBufHead(struct vnt_private *pDevice, unsigned char byPktType,
ptdCurr->pTDInfo->dwReqCount = cbReqCount;
ptdCurr->pTDInfo->dwHeaderLength = cbHeaderLength;
ptdCurr->pTDInfo->skb_dma = ptdCurr->pTDInfo->buf_dma;
- ptdCurr->buff_addr = cpu_to_le32(ptdCurr->pTDInfo->skb_dma);
return cbHeaderLength;
}
diff --git a/drivers/staging/vt6655/upc.h b/drivers/staging/vt6655/upc.h
index c53703a772f5..cc63dc8d47f7 100644
--- a/drivers/staging/vt6655/upc.h
+++ b/drivers/staging/vt6655/upc.h
@@ -33,9 +33,9 @@
/*--------------------- Export Definitions -------------------------*/
-//
-// For memory mapped IO
-//
+
+/* For memory mapped IO */
+
#define VNSvInPortB(dwIOAddress, pbyData) \
do { \
@@ -86,4 +86,4 @@ do { \
/*--------------------- Export Functions --------------------------*/
-#endif // __UPC_H__
+#endif /* __UPC_H__ */
diff --git a/drivers/staging/vt6656/card.c b/drivers/staging/vt6656/card.c
index 9340f1508cff..67ff13f4f731 100644
--- a/drivers/staging/vt6656/card.c
+++ b/drivers/staging/vt6656/card.c
@@ -78,7 +78,7 @@ void vnt_set_channel(struct vnt_private *priv, u32 connection_channel)
/* Set Channel[7] = 0 to tell H/W channel is changing now. */
vnt_mac_reg_bits_off(priv, MAC_REG_CHANNEL, 0xb0);
- vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNLE,
+ vnt_control_out(priv, MESSAGE_TYPE_SELECT_CHANNEL,
connection_channel, 0, 0, NULL);
vnt_control_out_u8(priv, MESSAGE_REQUEST_MACREG, MAC_REG_CHANNEL,
diff --git a/drivers/staging/vt6656/device.h b/drivers/staging/vt6656/device.h
index 5a7ca527106e..f71d59fa3b21 100644
--- a/drivers/staging/vt6656/device.h
+++ b/drivers/staging/vt6656/device.h
@@ -160,7 +160,7 @@
#define MESSAGE_TYPE_CLRKEYENTRY 0x9
#define MESSAGE_TYPE_WRITE_MISCFF 0xa
#define MESSAGE_TYPE_SET_ANTMD 0xb
-#define MESSAGE_TYPE_SELECT_CHANNLE 0xc
+#define MESSAGE_TYPE_SELECT_CHANNEL 0xc
#define MESSAGE_TYPE_SET_TSFTBTT 0xd
#define MESSAGE_TYPE_SET_SSTIFS 0xe
#define MESSAGE_TYPE_CHANGE_BBTYPE 0xf
@@ -307,8 +307,8 @@ struct vnt_private {
struct vnt_cmd_card_init init_command;
struct vnt_rsp_card_init init_response;
- u8 current_net_addr[ETH_ALEN];
- u8 permanent_net_addr[ETH_ALEN];
+ u8 current_net_addr[ETH_ALEN] __aligned(2);
+ u8 permanent_net_addr[ETH_ALEN] __aligned(2);
u8 exist_sw_net_addr;
diff --git a/drivers/staging/vt6656/dpc.h b/drivers/staging/vt6656/dpc.h
index fab195f8c3f5..95e0e83a487e 100644
--- a/drivers/staging/vt6656/dpc.h
+++ b/drivers/staging/vt6656/dpc.h
@@ -32,6 +32,6 @@
#include "device.h"
int vnt_rx_data(struct vnt_private *, struct vnt_rcb *,
- unsigned long bytes_recieved);
+ unsigned long bytes_received);
#endif /* __RXTX_H__ */
diff --git a/drivers/staging/vt6656/main_usb.c b/drivers/staging/vt6656/main_usb.c
index b95d5b1efcc7..71adc1f61838 100644
--- a/drivers/staging/vt6656/main_usb.c
+++ b/drivers/staging/vt6656/main_usb.c
@@ -34,6 +34,7 @@
*/
#undef __NO_VERSION__
+#include <linux/etherdevice.h>
#include <linux/file.h>
#include "device.h"
#include "card.h"
@@ -319,7 +320,7 @@ static int vnt_init_registers(struct vnt_private *priv)
/* get permanent network address */
memcpy(priv->permanent_net_addr, init_rsp->net_addr, 6);
- memcpy(priv->current_net_addr, priv->permanent_net_addr, ETH_ALEN);
+ ether_addr_copy(priv->current_net_addr, priv->permanent_net_addr);
/* if exist SW network address, use it */
dev_dbg(&priv->usb->dev, "Network address = %pM\n",
diff --git a/drivers/staging/vt6656/rxtx.c b/drivers/staging/vt6656/rxtx.c
index ea5140ab2b41..33baf26de4b5 100644
--- a/drivers/staging/vt6656/rxtx.c
+++ b/drivers/staging/vt6656/rxtx.c
@@ -36,6 +36,7 @@
*
*/
+#include <linux/etherdevice.h>
#include "device.h"
#include "rxtx.h"
#include "card.h"
@@ -55,7 +56,7 @@ static const u16 vnt_fb_opt0[2][5] = {
static const u16 vnt_fb_opt1[2][5] = {
{RATE_12M, RATE_18M, RATE_24M, RATE_24M, RATE_36M}, /* fallback_rate0 */
- {RATE_6M , RATE_6M, RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */
+ {RATE_6M, RATE_6M, RATE_12M, RATE_12M, RATE_18M}, /* fallback_rate1 */
};
#define RTSDUR_BB 0
@@ -392,8 +393,8 @@ static int vnt_fill_ieee80211_rts(struct vnt_usb_send_context *tx_context,
rts->frame_control =
cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_RTS);
- memcpy(rts->ra, hdr->addr1, ETH_ALEN);
- memcpy(rts->ta, hdr->addr2, ETH_ALEN);
+ ether_addr_copy(rts->ra, hdr->addr1);
+ ether_addr_copy(rts->ta, hdr->addr2);
return 0;
}
@@ -517,65 +518,66 @@ static u16 vnt_rxtx_rts_a_fb_head(struct vnt_usb_send_context *tx_context,
return vnt_rxtx_datahead_a_fb(tx_context, &buf->data_head);
}
-static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context,
- union vnt_tx_data_head *head)
+static u16 vnt_fill_cts_fb_head(struct vnt_usb_send_context *tx_context,
+ union vnt_tx_data_head *head)
{
struct vnt_private *priv = tx_context->priv;
+ struct vnt_cts_fb *buf = &head->cts_g_fb;
u32 cts_frame_len = 14;
u16 current_rate = tx_context->tx_rate;
- if (!head)
- return 0;
+ /* Get SignalField,ServiceField,Length */
+ vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate,
+ PK_TYPE_11B, &buf->b);
- if (tx_context->fb_option) {
- /* Auto Fall back */
- struct vnt_cts_fb *buf = &head->cts_g_fb;
- /* Get SignalField,ServiceField,Length */
- vnt_get_phy_field(priv, cts_frame_len,
- priv->top_cck_basic_rate, PK_TYPE_11B, &buf->b);
- buf->duration_ba =
- vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
- tx_context->pkt_type,
- current_rate);
- /* Get CTSDuration_ba_f0 */
- buf->cts_duration_ba_f0 =
- vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F0,
- tx_context->pkt_type,
- priv->tx_rate_fb0);
- /* Get CTSDuration_ba_f1 */
- buf->cts_duration_ba_f1 =
- vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F1,
- tx_context->pkt_type,
- priv->tx_rate_fb1);
- /* Get CTS Frame body */
- buf->data.duration = buf->duration_ba;
- buf->data.frame_control =
- cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
+ buf->duration_ba =
+ vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
+ tx_context->pkt_type,
+ current_rate);
+ /* Get CTSDuration_ba_f0 */
+ buf->cts_duration_ba_f0 =
+ vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F0,
+ tx_context->pkt_type,
+ priv->tx_rate_fb0);
+ /* Get CTSDuration_ba_f1 */
+ buf->cts_duration_ba_f1 =
+ vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA_F1,
+ tx_context->pkt_type,
+ priv->tx_rate_fb1);
+ /* Get CTS Frame body */
+ buf->data.duration = buf->duration_ba;
+ buf->data.frame_control =
+ cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
- memcpy(buf->data.ra, priv->current_net_addr, ETH_ALEN);
+ ether_addr_copy(buf->data.ra, priv->current_net_addr);
- return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head);
- } else {
- struct vnt_cts *buf = &head->cts_g;
- /* Get SignalField,ServiceField,Length */
- vnt_get_phy_field(priv, cts_frame_len,
- priv->top_cck_basic_rate, PK_TYPE_11B, &buf->b);
- /* Get CTSDuration_ba */
- buf->duration_ba =
- vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
- tx_context->pkt_type,
- current_rate);
- /*Get CTS Frame body*/
- buf->data.duration = buf->duration_ba;
- buf->data.frame_control =
- cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
+ return vnt_rxtx_datahead_g_fb(tx_context, &buf->data_head);
+}
+
+static u16 vnt_fill_cts_head(struct vnt_usb_send_context *tx_context,
+ union vnt_tx_data_head *head)
+{
+ struct vnt_private *priv = tx_context->priv;
+ struct vnt_cts *buf = &head->cts_g;
+ u32 cts_frame_len = 14;
+ u16 current_rate = tx_context->tx_rate;
- memcpy(buf->data.ra, priv->current_net_addr, ETH_ALEN);
+ /* Get SignalField,ServiceField,Length */
+ vnt_get_phy_field(priv, cts_frame_len, priv->top_cck_basic_rate,
+ PK_TYPE_11B, &buf->b);
+ /* Get CTSDuration_ba */
+ buf->duration_ba =
+ vnt_get_rtscts_duration_le(tx_context, CTSDUR_BA,
+ tx_context->pkt_type,
+ current_rate);
+ /*Get CTS Frame body*/
+ buf->data.duration = buf->duration_ba;
+ buf->data.frame_control =
+ cpu_to_le16(IEEE80211_FTYPE_CTL | IEEE80211_STYPE_CTS);
- return vnt_rxtx_datahead_g(tx_context, &buf->data_head);
- }
+ ether_addr_copy(buf->data.ra, priv->current_net_addr);
- return 0;
+ return vnt_rxtx_datahead_g(tx_context, &buf->data_head);
}
static u16 vnt_rxtx_rts(struct vnt_usb_send_context *tx_context,
@@ -632,6 +634,9 @@ static u16 vnt_rxtx_cts(struct vnt_usb_send_context *tx_context,
head = &tx_head->tx_cts.tx.mic.head;
/* Fill CTS */
+ if (tx_context->fb_option)
+ return vnt_fill_cts_fb_head(tx_context, head);
+
return vnt_fill_cts_head(tx_context, head);
}
@@ -739,7 +744,7 @@ static void vnt_fill_txkey(struct vnt_usb_send_context *tx_context,
mic_hdr->id = 0x59;
mic_hdr->payload_len = cpu_to_be16(payload_len);
- memcpy(mic_hdr->mic_addr2, hdr->addr2, ETH_ALEN);
+ ether_addr_copy(mic_hdr->mic_addr2, hdr->addr2);
ieee80211_get_key_tx_seq(tx_key, &seq);
diff --git a/drivers/staging/wlan-ng/cfg80211.c b/drivers/staging/wlan-ng/cfg80211.c
index 8942dcb44180..7c87aecf4744 100644
--- a/drivers/staging/wlan-ng/cfg80211.c
+++ b/drivers/staging/wlan-ng/cfg80211.c
@@ -325,9 +325,9 @@ static int prism2_get_station(struct wiphy *wiphy, struct net_device *dev,
if (result == 0) {
sinfo->txrate.legacy = quality.txrate.data;
- sinfo->filled |= STATION_INFO_TX_BITRATE;
+ sinfo->filled |= BIT(NL80211_STA_INFO_TX_BITRATE);
sinfo->signal = quality.level.data;
- sinfo->filled |= STATION_INFO_SIGNAL;
+ sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL);
}
return result;
diff --git a/drivers/staging/wlan-ng/hfa384x.h b/drivers/staging/wlan-ng/hfa384x.h
index 20d146b61ba7..8f2091070491 100644
--- a/drivers/staging/wlan-ng/hfa384x.h
+++ b/drivers/staging/wlan-ng/hfa384x.h
@@ -879,7 +879,7 @@ typedef struct hfa384x_usb_error {
/* Unions for packaging all the known packet types together */
typedef union hfa384x_usbout {
- u16 type;
+ __le16 type;
hfa384x_usb_txfrm_t txfrm;
hfa384x_usb_cmdreq_t cmdreq;
hfa384x_usb_wridreq_t wridreq;
@@ -889,7 +889,7 @@ typedef union hfa384x_usbout {
} __packed hfa384x_usbout_t;
typedef union hfa384x_usbin {
- u16 type;
+ __le16 type;
hfa384x_usb_rxfrm_t rxfrm;
hfa384x_usb_txfrm_t txfrm;
hfa384x_usb_infofrm_t infofrm;
@@ -1268,7 +1268,7 @@ typedef struct hfa384x {
hfa384x_downloadbuffer_t bufinfo;
u16 dltimeout;
- int scanflag; /* to signal scan comlete */
+ int scanflag; /* to signal scan complete */
int join_ap; /* are we joined to a specific ap */
int join_retries; /* number of join retries till we fail */
hfa384x_JoinRequest_data_t joinreq; /* join request saved data */
diff --git a/drivers/staging/wlan-ng/hfa384x_usb.c b/drivers/staging/wlan-ng/hfa384x_usb.c
index 55d2f563e308..28cd1c4c02c8 100644
--- a/drivers/staging/wlan-ng/hfa384x_usb.c
+++ b/drivers/staging/wlan-ng/hfa384x_usb.c
@@ -382,7 +382,7 @@ done:
*
* Arguments:
* hw device struct
-* tx_urb URB of data for tranmission
+* tx_urb URB of data for transmission
* memflags memory allocation flags
*
* Returns:
@@ -2391,7 +2391,7 @@ int hfa384x_drvr_ramdl_write(hfa384x_t *hw, u32 daddr, void *buf, u32 len)
* 0 success
* >0 f/w reported error - f/w status code
* <0 driver reported error
-* -ETIMEDOUT timout waiting for the cmd regs to become
+* -ETIMEDOUT timeout waiting for the cmd regs to become
* available, or waiting for the control reg
* to indicate the Aux port is enabled.
* -ENODATA the buffer does NOT contain a valid PDA.
@@ -3346,7 +3346,7 @@ retry:
if (unlocked_usbctlx_cancel_async(hw, ctlx) == 0)
run_queue = 1;
} else {
- const u16 intype = (usbin->type & ~cpu_to_le16(0x8000));
+ const __le16 intype = (usbin->type & ~cpu_to_le16(0x8000));
/*
* Check that our message is what we're expecting ...
@@ -4123,12 +4123,11 @@ static int hfa384x_isgood_pdrcode(u16 pdrcode)
pr_debug("Encountered unknown PDR#=0x%04x, assuming it's ok.\n",
pdrcode);
return 1;
- } else {
- /* bad code */
- pr_debug("Encountered unknown PDR#=0x%04x, (>=0x1000), assuming it's bad.\n",
- pdrcode);
- return 0;
}
+ break;
}
- return 0; /* avoid compiler warnings */
+ /* bad code */
+ pr_debug("Encountered unknown PDR#=0x%04x, (>=0x1000), assuming it's bad.\n",
+ pdrcode);
+ return 0;
}
diff --git a/drivers/staging/wlan-ng/p80211conv.c b/drivers/staging/wlan-ng/p80211conv.c
index 7eaaf9a63503..bd69e8cf200f 100644
--- a/drivers/staging/wlan-ng/p80211conv.c
+++ b/drivers/staging/wlan-ng/p80211conv.c
@@ -511,7 +511,7 @@ int skb_p80211_to_ether(wlandevice_t *wlandev, u32 ethconv,
* protocol.
*
* Arguments:
-* proto protocl number (in host order) to search for.
+* proto protocol number (in host order) to search for.
*
* Returns:
* 1 - if the table is empty or a match is found.
diff --git a/drivers/staging/wlan-ng/p80211req.c b/drivers/staging/wlan-ng/p80211req.c
index 7221379c9742..4b84b568f6ca 100644
--- a/drivers/staging/wlan-ng/p80211req.c
+++ b/drivers/staging/wlan-ng/p80211req.c
@@ -80,7 +80,7 @@ static void p80211req_mibset_mibget(wlandevice_t *wlandev,
/*----------------------------------------------------------------
* p80211req_dorequest
*
-* Handles an MLME reqest/confirm message.
+* Handles an MLME request/confirm message.
*
* Arguments:
* wlandev WLAN device struct
diff --git a/drivers/staging/wlan-ng/prism2mgmt.h b/drivers/staging/wlan-ng/prism2mgmt.h
index b62fdcba94e6..16f123959104 100644
--- a/drivers/staging/wlan-ng/prism2mgmt.h
+++ b/drivers/staging/wlan-ng/prism2mgmt.h
@@ -45,7 +45,7 @@
* --------------------------------------------------------------------
*
* This file contains the constants and data structures for interaction
-* with the hfa384x Wireless LAN (WLAN) Media Access Contoller (MAC).
+* with the hfa384x Wireless LAN (WLAN) Media Access Controller (MAC).
* The hfa384x is a portion of the Harris PRISM(tm) WLAN chipset.
*
* [Implementation and usage notes]
diff --git a/drivers/staging/wlan-ng/prism2sta.c b/drivers/staging/wlan-ng/prism2sta.c
index df577dfe7ffb..10ad24a89ddd 100644
--- a/drivers/staging/wlan-ng/prism2sta.c
+++ b/drivers/staging/wlan-ng/prism2sta.c
@@ -199,7 +199,7 @@ static int prism2sta_close(wlandevice_t *wlandev)
/*----------------------------------------------------------------
* prism2sta_reset
*
-* Not currently implented.
+* Currently not implemented.
*
* Arguments:
* wlandev wlan device structure
@@ -662,7 +662,7 @@ static int prism2sta_getcardinfo(wlandevice_t *wlandev)
"ident: ap f/w: id=0x%02x %d.%d.%d\n",
hw->ident_sta_fw.id, hw->ident_sta_fw.major,
hw->ident_sta_fw.minor, hw->ident_sta_fw.variant);
- netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmeare loaded!\n");
+ netdev_err(wlandev->netdev, "Unsupported Tertiary AP firmware loaded!\n");
goto failed;
}
diff --git a/drivers/staging/xgifb/XGI_main_26.c b/drivers/staging/xgifb/XGI_main_26.c
index 709d49e7f3c9..935c714f592a 100644
--- a/drivers/staging/xgifb/XGI_main_26.c
+++ b/drivers/staging/xgifb/XGI_main_26.c
@@ -930,7 +930,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
+ var->hsync_len;
unsigned int vtotal = var->upper_margin + var->yres + var->lower_margin
+ var->vsync_len;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
u8 cr_data;
#endif
unsigned int drate = 0, hrate = 0;
@@ -952,7 +952,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
} pr_debug("var->pixclock=%d, htotal=%d, vtotal=%d\n",
var->pixclock, htotal, vtotal);
- if (var->pixclock && htotal && vtotal) {
+ if (var->pixclock) {
drate = 1000000000 / var->pixclock;
hrate = (drate * 1000) / htotal;
xgifb_info->refresh_rate = (unsigned int) (hrate * 2
@@ -1044,7 +1044,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
xgifb_info->DstColor = 0x0000;
xgifb_info->XGI310_AccelDepth = 0x00000000;
xgifb_info->video_cmap_len = 256;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
cr_data = xgifb_reg_get(XGICR, 0x4D);
xgifb_reg_set(XGICR, 0x4D, (cr_data & 0xE0));
#endif
@@ -1052,7 +1052,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
case 16:
xgifb_info->DstColor = 0x8000;
xgifb_info->XGI310_AccelDepth = 0x00010000;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
cr_data = xgifb_reg_get(XGICR, 0x4D);
xgifb_reg_set(XGICR, 0x4D, ((cr_data & 0xE0) | 0x0B));
#endif
@@ -1062,7 +1062,7 @@ static int XGIfb_do_set_var(struct fb_var_screeninfo *var, int isactive,
xgifb_info->DstColor = 0xC000;
xgifb_info->XGI310_AccelDepth = 0x00020000;
xgifb_info->video_cmap_len = 16;
-#if defined(__powerpc__)
+#if defined(__BIG_ENDIAN)
cr_data = xgifb_reg_get(XGICR, 0x4D);
xgifb_reg_set(XGICR, 0x4D, ((cr_data & 0xE0) | 0x15));
#endif
diff --git a/drivers/target/iscsi/iscsi_target.c b/drivers/target/iscsi/iscsi_target.c
index aebde3289c50..50bad55a0c42 100644
--- a/drivers/target/iscsi/iscsi_target.c
+++ b/drivers/target/iscsi/iscsi_target.c
@@ -30,7 +30,7 @@
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h"
@@ -45,7 +45,7 @@
#include "iscsi_target_util.h"
#include "iscsi_target.h"
#include "iscsi_target_device.h"
-#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_target_stat.h>
#include <target/iscsi/iscsi_transport.h>
@@ -968,11 +968,7 @@ int iscsit_setup_scsi_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt;
if (hdr->flags & ISCSI_FLAG_CMD_READ) {
- spin_lock_bh(&conn->sess->ttt_lock);
- cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- if (cmd->targ_xfer_tag == 0xFFFFFFFF)
- cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- spin_unlock_bh(&conn->sess->ttt_lock);
+ cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
} else if (hdr->flags & ISCSI_FLAG_CMD_WRITE)
cmd->targ_xfer_tag = 0xFFFFFFFF;
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
@@ -1998,6 +1994,7 @@ iscsit_setup_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
cmd->cmd_sn = be32_to_cpu(hdr->cmdsn);
cmd->exp_stat_sn = be32_to_cpu(hdr->exp_statsn);
cmd->data_direction = DMA_NONE;
+ cmd->text_in_ptr = NULL;
return 0;
}
@@ -2011,9 +2008,13 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
int cmdsn_ret;
if (!text_in) {
- pr_err("Unable to locate text_in buffer for sendtargets"
- " discovery\n");
- goto reject;
+ cmd->targ_xfer_tag = be32_to_cpu(hdr->ttt);
+ if (cmd->targ_xfer_tag == 0xFFFFFFFF) {
+ pr_err("Unable to locate text_in buffer for sendtargets"
+ " discovery\n");
+ goto reject;
+ }
+ goto empty_sendtargets;
}
if (strncmp("SendTargets", text_in, 11) != 0) {
pr_err("Received Text Data that is not"
@@ -2040,6 +2041,7 @@ iscsit_process_text_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
+empty_sendtargets:
iscsit_ack_from_expstatsn(conn, be32_to_cpu(hdr->exp_statsn));
if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) {
@@ -3047,11 +3049,7 @@ static int iscsit_send_r2t(
int_to_scsilun(cmd->se_cmd.orig_fe_lun,
(struct scsi_lun *)&hdr->lun);
hdr->itt = cmd->init_task_tag;
- spin_lock_bh(&conn->sess->ttt_lock);
- r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- if (r2t->targ_xfer_tag == 0xFFFFFFFF)
- r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- spin_unlock_bh(&conn->sess->ttt_lock);
+ r2t->targ_xfer_tag = session_get_next_ttt(conn->sess);
hdr->ttt = cpu_to_be32(r2t->targ_xfer_tag);
hdr->statsn = cpu_to_be32(conn->stat_sn);
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
@@ -3393,7 +3391,8 @@ static bool iscsit_check_inaddr_any(struct iscsi_np *np)
static int
iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
- enum iscsit_transport_type network_transport)
+ enum iscsit_transport_type network_transport,
+ int skip_bytes, bool *completed)
{
char *payload = NULL;
struct iscsi_conn *conn = cmd->conn;
@@ -3405,7 +3404,7 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
unsigned char buf[ISCSI_IQN_LEN+12]; /* iqn + "TargetName=" + \0 */
unsigned char *text_in = cmd->text_in_ptr, *text_ptr = NULL;
- buffer_len = max(conn->conn_ops->MaxRecvDataSegmentLength,
+ buffer_len = min(conn->conn_ops->MaxRecvDataSegmentLength,
SENDTARGETS_BUF_LIMIT);
payload = kzalloc(buffer_len, GFP_KERNEL);
@@ -3484,9 +3483,16 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
end_of_buf = 1;
goto eob;
}
- memcpy(payload + payload_len, buf, len);
- payload_len += len;
- target_name_printed = 1;
+
+ if (skip_bytes && len <= skip_bytes) {
+ skip_bytes -= len;
+ } else {
+ memcpy(payload + payload_len, buf, len);
+ payload_len += len;
+ target_name_printed = 1;
+ if (len > skip_bytes)
+ skip_bytes = 0;
+ }
}
len = sprintf(buf, "TargetAddress="
@@ -3502,15 +3508,24 @@ iscsit_build_sendtargets_response(struct iscsi_cmd *cmd,
end_of_buf = 1;
goto eob;
}
- memcpy(payload + payload_len, buf, len);
- payload_len += len;
+
+ if (skip_bytes && len <= skip_bytes) {
+ skip_bytes -= len;
+ } else {
+ memcpy(payload + payload_len, buf, len);
+ payload_len += len;
+ if (len > skip_bytes)
+ skip_bytes = 0;
+ }
}
spin_unlock(&tpg->tpg_np_lock);
}
spin_unlock(&tiqn->tiqn_tpg_lock);
eob:
- if (end_of_buf)
+ if (end_of_buf) {
+ *completed = false;
break;
+ }
if (cmd->cmd_flags & ICF_SENDTARGETS_SINGLE)
break;
@@ -3528,13 +3543,23 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
enum iscsit_transport_type network_transport)
{
int text_length, padding;
+ bool completed = true;
- text_length = iscsit_build_sendtargets_response(cmd, network_transport);
+ text_length = iscsit_build_sendtargets_response(cmd, network_transport,
+ cmd->read_data_done,
+ &completed);
if (text_length < 0)
return text_length;
+ if (completed) {
+ hdr->flags |= ISCSI_FLAG_CMD_FINAL;
+ } else {
+ hdr->flags |= ISCSI_FLAG_TEXT_CONTINUE;
+ cmd->read_data_done += text_length;
+ if (cmd->targ_xfer_tag == 0xFFFFFFFF)
+ cmd->targ_xfer_tag = session_get_next_ttt(conn->sess);
+ }
hdr->opcode = ISCSI_OP_TEXT_RSP;
- hdr->flags |= ISCSI_FLAG_CMD_FINAL;
padding = ((-text_length) & 3);
hton24(hdr->dlength, text_length);
hdr->itt = cmd->init_task_tag;
@@ -3543,21 +3568,25 @@ iscsit_build_text_rsp(struct iscsi_cmd *cmd, struct iscsi_conn *conn,
hdr->statsn = cpu_to_be32(cmd->stat_sn);
iscsit_increment_maxcmdsn(cmd, conn->sess);
+ /*
+ * Reset maxcmdsn_inc in multi-part text payload exchanges to
+ * correctly increment MaxCmdSN for each response answering a
+ * non immediate text request with a valid CmdSN.
+ */
+ cmd->maxcmdsn_inc = 0;
hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn);
hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn);
- pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x,"
- " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn,
- text_length, conn->cid);
+ pr_debug("Built Text Response: ITT: 0x%08x, TTT: 0x%08x, StatSN: 0x%08x,"
+ " Length: %u, CID: %hu F: %d C: %d\n", cmd->init_task_tag,
+ cmd->targ_xfer_tag, cmd->stat_sn, text_length, conn->cid,
+ !!(hdr->flags & ISCSI_FLAG_CMD_FINAL),
+ !!(hdr->flags & ISCSI_FLAG_TEXT_CONTINUE));
return text_length + padding;
}
EXPORT_SYMBOL(iscsit_build_text_rsp);
-/*
- * FIXME: Add support for F_BIT and C_BIT when the length is longer than
- * MaxRecvDataSegmentLength.
- */
static int iscsit_send_text_rsp(
struct iscsi_cmd *cmd,
struct iscsi_conn *conn)
@@ -4021,9 +4050,15 @@ static int iscsi_target_rx_opcode(struct iscsi_conn *conn, unsigned char *buf)
ret = iscsit_handle_task_mgt_cmd(conn, cmd, buf);
break;
case ISCSI_OP_TEXT:
- cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
- if (!cmd)
- goto reject;
+ if (hdr->ttt != cpu_to_be32(0xFFFFFFFF)) {
+ cmd = iscsit_find_cmd_from_itt(conn, hdr->itt);
+ if (!cmd)
+ goto reject;
+ } else {
+ cmd = iscsit_allocate_cmd(conn, TASK_INTERRUPTIBLE);
+ if (!cmd)
+ goto reject;
+ }
ret = iscsit_handle_text_cmd(conn, cmd, buf);
break;
diff --git a/drivers/target/iscsi/iscsi_target_auth.c b/drivers/target/iscsi/iscsi_target_auth.c
index ab4915c0d933..47e249dccb5f 100644
--- a/drivers/target/iscsi/iscsi_target_auth.c
+++ b/drivers/target/iscsi/iscsi_target_auth.c
@@ -22,7 +22,7 @@
#include <linux/err.h>
#include <linux/scatterlist.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_nego.h"
#include "iscsi_target_auth.h"
diff --git a/drivers/target/iscsi/iscsi_target_configfs.c b/drivers/target/iscsi/iscsi_target_configfs.c
index 9059c1e0b26e..48384b675e62 100644
--- a/drivers/target/iscsi/iscsi_target_configfs.c
+++ b/drivers/target/iscsi/iscsi_target_configfs.c
@@ -28,7 +28,7 @@
#include <target/configfs_macros.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_device.h"
#include "iscsi_target_erl0.h"
@@ -36,7 +36,7 @@
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
#include "iscsi_target.h"
-#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_configfs.h"
struct target_fabric_configfs *lio_target_fabric_configfs;
@@ -674,12 +674,9 @@ static ssize_t lio_target_nacl_show_info(
rb += sprintf(page+rb, "InitiatorAlias: %s\n",
sess->sess_ops->InitiatorAlias);
- rb += sprintf(page+rb, "LIO Session ID: %u "
- "ISID: 0x%02x %02x %02x %02x %02x %02x "
- "TSIH: %hu ", sess->sid,
- sess->isid[0], sess->isid[1], sess->isid[2],
- sess->isid[3], sess->isid[4], sess->isid[5],
- sess->tsih);
+ rb += sprintf(page+rb,
+ "LIO Session ID: %u ISID: 0x%6ph TSIH: %hu ",
+ sess->sid, sess->isid, sess->tsih);
rb += sprintf(page+rb, "SessionType: %s\n",
(sess->sess_ops->SessionType) ?
"Discovery" : "Normal");
@@ -1758,9 +1755,7 @@ static u32 lio_sess_get_initiator_sid(
/*
* iSCSI Initiator Session Identifier from RFC-3720.
*/
- return snprintf(buf, size, "%02x%02x%02x%02x%02x%02x",
- sess->isid[0], sess->isid[1], sess->isid[2],
- sess->isid[3], sess->isid[4], sess->isid[5]);
+ return snprintf(buf, size, "%6phN", sess->isid);
}
static int lio_queue_data_in(struct se_cmd *se_cmd)
diff --git a/drivers/target/iscsi/iscsi_target_core.h b/drivers/target/iscsi/iscsi_target_core.h
deleted file mode 100644
index cbcff38ac9b7..000000000000
--- a/drivers/target/iscsi/iscsi_target_core.h
+++ /dev/null
@@ -1,883 +0,0 @@
-#ifndef ISCSI_TARGET_CORE_H
-#define ISCSI_TARGET_CORE_H
-
-#include <linux/in.h>
-#include <linux/configfs.h>
-#include <net/sock.h>
-#include <net/tcp.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/iscsi_proto.h>
-#include <target/target_core_base.h>
-
-#define ISCSIT_VERSION "v4.1.0"
-#define ISCSI_MAX_DATASN_MISSING_COUNT 16
-#define ISCSI_TX_THREAD_TCP_TIMEOUT 2
-#define ISCSI_RX_THREAD_TCP_TIMEOUT 2
-#define SECONDS_FOR_ASYNC_LOGOUT 10
-#define SECONDS_FOR_ASYNC_TEXT 10
-#define SECONDS_FOR_LOGOUT_COMP 15
-#define WHITE_SPACE " \t\v\f\n\r"
-#define ISCSIT_MIN_TAGS 16
-#define ISCSIT_EXTRA_TAGS 8
-#define ISCSIT_TCP_BACKLOG 256
-
-/* struct iscsi_node_attrib sanity values */
-#define NA_DATAOUT_TIMEOUT 3
-#define NA_DATAOUT_TIMEOUT_MAX 60
-#define NA_DATAOUT_TIMEOUT_MIX 2
-#define NA_DATAOUT_TIMEOUT_RETRIES 5
-#define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15
-#define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1
-#define NA_NOPIN_TIMEOUT 15
-#define NA_NOPIN_TIMEOUT_MAX 60
-#define NA_NOPIN_TIMEOUT_MIN 3
-#define NA_NOPIN_RESPONSE_TIMEOUT 30
-#define NA_NOPIN_RESPONSE_TIMEOUT_MAX 60
-#define NA_NOPIN_RESPONSE_TIMEOUT_MIN 3
-#define NA_RANDOM_DATAIN_PDU_OFFSETS 0
-#define NA_RANDOM_DATAIN_SEQ_OFFSETS 0
-#define NA_RANDOM_R2T_OFFSETS 0
-
-/* struct iscsi_tpg_attrib sanity values */
-#define TA_AUTHENTICATION 1
-#define TA_LOGIN_TIMEOUT 15
-#define TA_LOGIN_TIMEOUT_MAX 30
-#define TA_LOGIN_TIMEOUT_MIN 5
-#define TA_NETIF_TIMEOUT 2
-#define TA_NETIF_TIMEOUT_MAX 15
-#define TA_NETIF_TIMEOUT_MIN 2
-#define TA_GENERATE_NODE_ACLS 0
-#define TA_DEFAULT_CMDSN_DEPTH 64
-#define TA_DEFAULT_CMDSN_DEPTH_MAX 512
-#define TA_DEFAULT_CMDSN_DEPTH_MIN 1
-#define TA_CACHE_DYNAMIC_ACLS 0
-/* Enabled by default in demo mode (generic_node_acls=1) */
-#define TA_DEMO_MODE_WRITE_PROTECT 1
-/* Disabled by default in production mode w/ explict ACLs */
-#define TA_PROD_MODE_WRITE_PROTECT 0
-#define TA_DEMO_MODE_DISCOVERY 1
-#define TA_DEFAULT_ERL 0
-#define TA_CACHE_CORE_NPS 0
-/* T10 protection information disabled by default */
-#define TA_DEFAULT_T10_PI 0
-
-#define ISCSI_IOV_DATA_BUFFER 5
-
-enum iscsit_transport_type {
- ISCSI_TCP = 0,
- ISCSI_SCTP_TCP = 1,
- ISCSI_SCTP_UDP = 2,
- ISCSI_IWARP_TCP = 3,
- ISCSI_IWARP_SCTP = 4,
- ISCSI_INFINIBAND = 5,
-};
-
-/* RFC-3720 7.1.4 Standard Connection State Diagram for a Target */
-enum target_conn_state_table {
- TARG_CONN_STATE_FREE = 0x1,
- TARG_CONN_STATE_XPT_UP = 0x3,
- TARG_CONN_STATE_IN_LOGIN = 0x4,
- TARG_CONN_STATE_LOGGED_IN = 0x5,
- TARG_CONN_STATE_IN_LOGOUT = 0x6,
- TARG_CONN_STATE_LOGOUT_REQUESTED = 0x7,
- TARG_CONN_STATE_CLEANUP_WAIT = 0x8,
-};
-
-/* RFC-3720 7.3.2 Session State Diagram for a Target */
-enum target_sess_state_table {
- TARG_SESS_STATE_FREE = 0x1,
- TARG_SESS_STATE_ACTIVE = 0x2,
- TARG_SESS_STATE_LOGGED_IN = 0x3,
- TARG_SESS_STATE_FAILED = 0x4,
- TARG_SESS_STATE_IN_CONTINUE = 0x5,
-};
-
-/* struct iscsi_data_count->type */
-enum data_count_type {
- ISCSI_RX_DATA = 1,
- ISCSI_TX_DATA = 2,
-};
-
-/* struct iscsi_datain_req->dr_complete */
-enum datain_req_comp_table {
- DATAIN_COMPLETE_NORMAL = 1,
- DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY = 2,
- DATAIN_COMPLETE_CONNECTION_RECOVERY = 3,
-};
-
-/* struct iscsi_datain_req->recovery */
-enum datain_req_rec_table {
- DATAIN_WITHIN_COMMAND_RECOVERY = 1,
- DATAIN_CONNECTION_RECOVERY = 2,
-};
-
-/* struct iscsi_portal_group->state */
-enum tpg_state_table {
- TPG_STATE_FREE = 0,
- TPG_STATE_ACTIVE = 1,
- TPG_STATE_INACTIVE = 2,
- TPG_STATE_COLD_RESET = 3,
-};
-
-/* struct iscsi_tiqn->tiqn_state */
-enum tiqn_state_table {
- TIQN_STATE_ACTIVE = 1,
- TIQN_STATE_SHUTDOWN = 2,
-};
-
-/* struct iscsi_cmd->cmd_flags */
-enum cmd_flags_table {
- ICF_GOT_LAST_DATAOUT = 0x00000001,
- ICF_GOT_DATACK_SNACK = 0x00000002,
- ICF_NON_IMMEDIATE_UNSOLICITED_DATA = 0x00000004,
- ICF_SENT_LAST_R2T = 0x00000008,
- ICF_WITHIN_COMMAND_RECOVERY = 0x00000010,
- ICF_CONTIG_MEMORY = 0x00000020,
- ICF_ATTACHED_TO_RQUEUE = 0x00000040,
- ICF_OOO_CMDSN = 0x00000080,
- ICF_SENDTARGETS_ALL = 0x00000100,
- ICF_SENDTARGETS_SINGLE = 0x00000200,
-};
-
-/* struct iscsi_cmd->i_state */
-enum cmd_i_state_table {
- ISTATE_NO_STATE = 0,
- ISTATE_NEW_CMD = 1,
- ISTATE_DEFERRED_CMD = 2,
- ISTATE_UNSOLICITED_DATA = 3,
- ISTATE_RECEIVE_DATAOUT = 4,
- ISTATE_RECEIVE_DATAOUT_RECOVERY = 5,
- ISTATE_RECEIVED_LAST_DATAOUT = 6,
- ISTATE_WITHIN_DATAOUT_RECOVERY = 7,
- ISTATE_IN_CONNECTION_RECOVERY = 8,
- ISTATE_RECEIVED_TASKMGT = 9,
- ISTATE_SEND_ASYNCMSG = 10,
- ISTATE_SENT_ASYNCMSG = 11,
- ISTATE_SEND_DATAIN = 12,
- ISTATE_SEND_LAST_DATAIN = 13,
- ISTATE_SENT_LAST_DATAIN = 14,
- ISTATE_SEND_LOGOUTRSP = 15,
- ISTATE_SENT_LOGOUTRSP = 16,
- ISTATE_SEND_NOPIN = 17,
- ISTATE_SENT_NOPIN = 18,
- ISTATE_SEND_REJECT = 19,
- ISTATE_SENT_REJECT = 20,
- ISTATE_SEND_R2T = 21,
- ISTATE_SENT_R2T = 22,
- ISTATE_SEND_R2T_RECOVERY = 23,
- ISTATE_SENT_R2T_RECOVERY = 24,
- ISTATE_SEND_LAST_R2T = 25,
- ISTATE_SENT_LAST_R2T = 26,
- ISTATE_SEND_LAST_R2T_RECOVERY = 27,
- ISTATE_SENT_LAST_R2T_RECOVERY = 28,
- ISTATE_SEND_STATUS = 29,
- ISTATE_SEND_STATUS_BROKEN_PC = 30,
- ISTATE_SENT_STATUS = 31,
- ISTATE_SEND_STATUS_RECOVERY = 32,
- ISTATE_SENT_STATUS_RECOVERY = 33,
- ISTATE_SEND_TASKMGTRSP = 34,
- ISTATE_SENT_TASKMGTRSP = 35,
- ISTATE_SEND_TEXTRSP = 36,
- ISTATE_SENT_TEXTRSP = 37,
- ISTATE_SEND_NOPIN_WANT_RESPONSE = 38,
- ISTATE_SENT_NOPIN_WANT_RESPONSE = 39,
- ISTATE_SEND_NOPIN_NO_RESPONSE = 40,
- ISTATE_REMOVE = 41,
- ISTATE_FREE = 42,
-};
-
-/* Used for iscsi_recover_cmdsn() return values */
-enum recover_cmdsn_ret_table {
- CMDSN_ERROR_CANNOT_RECOVER = -1,
- CMDSN_NORMAL_OPERATION = 0,
- CMDSN_LOWER_THAN_EXP = 1,
- CMDSN_HIGHER_THAN_EXP = 2,
- CMDSN_MAXCMDSN_OVERRUN = 3,
-};
-
-/* Used for iscsi_handle_immediate_data() return values */
-enum immedate_data_ret_table {
- IMMEDIATE_DATA_CANNOT_RECOVER = -1,
- IMMEDIATE_DATA_NORMAL_OPERATION = 0,
- IMMEDIATE_DATA_ERL1_CRC_FAILURE = 1,
-};
-
-/* Used for iscsi_decide_dataout_action() return values */
-enum dataout_action_ret_table {
- DATAOUT_CANNOT_RECOVER = -1,
- DATAOUT_NORMAL = 0,
- DATAOUT_SEND_R2T = 1,
- DATAOUT_SEND_TO_TRANSPORT = 2,
- DATAOUT_WITHIN_COMMAND_RECOVERY = 3,
-};
-
-/* Used for struct iscsi_node_auth->naf_flags */
-enum naf_flags_table {
- NAF_USERID_SET = 0x01,
- NAF_PASSWORD_SET = 0x02,
- NAF_USERID_IN_SET = 0x04,
- NAF_PASSWORD_IN_SET = 0x08,
-};
-
-/* Used by various struct timer_list to manage iSCSI specific state */
-enum iscsi_timer_flags_table {
- ISCSI_TF_RUNNING = 0x01,
- ISCSI_TF_STOP = 0x02,
- ISCSI_TF_EXPIRED = 0x04,
-};
-
-/* Used for struct iscsi_np->np_flags */
-enum np_flags_table {
- NPF_IP_NETWORK = 0x00,
-};
-
-/* Used for struct iscsi_np->np_thread_state */
-enum np_thread_state_table {
- ISCSI_NP_THREAD_ACTIVE = 1,
- ISCSI_NP_THREAD_INACTIVE = 2,
- ISCSI_NP_THREAD_RESET = 3,
- ISCSI_NP_THREAD_SHUTDOWN = 4,
- ISCSI_NP_THREAD_EXIT = 5,
-};
-
-struct iscsi_conn_ops {
- u8 HeaderDigest; /* [0,1] == [None,CRC32C] */
- u8 DataDigest; /* [0,1] == [None,CRC32C] */
- u32 MaxRecvDataSegmentLength; /* [512..2**24-1] */
- u32 MaxXmitDataSegmentLength; /* [512..2**24-1] */
- u8 OFMarker; /* [0,1] == [No,Yes] */
- u8 IFMarker; /* [0,1] == [No,Yes] */
- u32 OFMarkInt; /* [1..65535] */
- u32 IFMarkInt; /* [1..65535] */
- /*
- * iSER specific connection parameters
- */
- u32 InitiatorRecvDataSegmentLength; /* [512..2**24-1] */
- u32 TargetRecvDataSegmentLength; /* [512..2**24-1] */
-};
-
-struct iscsi_sess_ops {
- char InitiatorName[224];
- char InitiatorAlias[256];
- char TargetName[224];
- char TargetAlias[256];
- char TargetAddress[256];
- u16 TargetPortalGroupTag; /* [0..65535] */
- u16 MaxConnections; /* [1..65535] */
- u8 InitialR2T; /* [0,1] == [No,Yes] */
- u8 ImmediateData; /* [0,1] == [No,Yes] */
- u32 MaxBurstLength; /* [512..2**24-1] */
- u32 FirstBurstLength; /* [512..2**24-1] */
- u16 DefaultTime2Wait; /* [0..3600] */
- u16 DefaultTime2Retain; /* [0..3600] */
- u16 MaxOutstandingR2T; /* [1..65535] */
- u8 DataPDUInOrder; /* [0,1] == [No,Yes] */
- u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */
- u8 ErrorRecoveryLevel; /* [0..2] */
- u8 SessionType; /* [0,1] == [Normal,Discovery]*/
- /*
- * iSER specific session parameters
- */
- u8 RDMAExtensions; /* [0,1] == [No,Yes] */
-};
-
-struct iscsi_queue_req {
- int state;
- struct iscsi_cmd *cmd;
- struct list_head qr_list;
-};
-
-struct iscsi_data_count {
- int data_length;
- int sync_and_steering;
- enum data_count_type type;
- u32 iov_count;
- u32 ss_iov_count;
- u32 ss_marker_count;
- struct kvec *iov;
-};
-
-struct iscsi_param_list {
- bool iser;
- struct list_head param_list;
- struct list_head extra_response_list;
-};
-
-struct iscsi_datain_req {
- enum datain_req_comp_table dr_complete;
- int generate_recovery_values;
- enum datain_req_rec_table recovery;
- u32 begrun;
- u32 runlength;
- u32 data_length;
- u32 data_offset;
- u32 data_sn;
- u32 next_burst_len;
- u32 read_data_done;
- u32 seq_send_order;
- struct list_head cmd_datain_node;
-} ____cacheline_aligned;
-
-struct iscsi_ooo_cmdsn {
- u16 cid;
- u32 batch_count;
- u32 cmdsn;
- u32 exp_cmdsn;
- struct iscsi_cmd *cmd;
- struct list_head ooo_list;
-} ____cacheline_aligned;
-
-struct iscsi_datain {
- u8 flags;
- u32 data_sn;
- u32 length;
- u32 offset;
-} ____cacheline_aligned;
-
-struct iscsi_r2t {
- int seq_complete;
- int recovery_r2t;
- int sent_r2t;
- u32 r2t_sn;
- u32 offset;
- u32 targ_xfer_tag;
- u32 xfer_len;
- struct list_head r2t_list;
-} ____cacheline_aligned;
-
-struct iscsi_cmd {
- enum iscsi_timer_flags_table dataout_timer_flags;
- /* DataOUT timeout retries */
- u8 dataout_timeout_retries;
- /* Within command recovery count */
- u8 error_recovery_count;
- /* iSCSI dependent state for out or order CmdSNs */
- enum cmd_i_state_table deferred_i_state;
- /* iSCSI dependent state */
- enum cmd_i_state_table i_state;
- /* Command is an immediate command (ISCSI_OP_IMMEDIATE set) */
- u8 immediate_cmd;
- /* Immediate data present */
- u8 immediate_data;
- /* iSCSI Opcode */
- u8 iscsi_opcode;
- /* iSCSI Response Code */
- u8 iscsi_response;
- /* Logout reason when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */
- u8 logout_reason;
- /* Logout response code when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */
- u8 logout_response;
- /* MaxCmdSN has been incremented */
- u8 maxcmdsn_inc;
- /* Immediate Unsolicited Dataout */
- u8 unsolicited_data;
- /* Reject reason code */
- u8 reject_reason;
- /* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */
- u16 logout_cid;
- /* Command flags */
- enum cmd_flags_table cmd_flags;
- /* Initiator Task Tag assigned from Initiator */
- itt_t init_task_tag;
- /* Target Transfer Tag assigned from Target */
- u32 targ_xfer_tag;
- /* CmdSN assigned from Initiator */
- u32 cmd_sn;
- /* ExpStatSN assigned from Initiator */
- u32 exp_stat_sn;
- /* StatSN assigned to this ITT */
- u32 stat_sn;
- /* DataSN Counter */
- u32 data_sn;
- /* R2TSN Counter */
- u32 r2t_sn;
- /* Last DataSN acknowledged via DataAck SNACK */
- u32 acked_data_sn;
- /* Used for echoing NOPOUT ping data */
- u32 buf_ptr_size;
- /* Used to store DataDigest */
- u32 data_crc;
- /* Counter for MaxOutstandingR2T */
- u32 outstanding_r2ts;
- /* Next R2T Offset when DataSequenceInOrder=Yes */
- u32 r2t_offset;
- /* Iovec current and orig count for iscsi_cmd->iov_data */
- u32 iov_data_count;
- u32 orig_iov_data_count;
- /* Number of miscellaneous iovecs used for IP stack calls */
- u32 iov_misc_count;
- /* Number of struct iscsi_pdu in struct iscsi_cmd->pdu_list */
- u32 pdu_count;
- /* Next struct iscsi_pdu to send in struct iscsi_cmd->pdu_list */
- u32 pdu_send_order;
- /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */
- u32 pdu_start;
- /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */
- u32 seq_send_order;
- /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */
- u32 seq_count;
- /* Current struct iscsi_seq in struct iscsi_cmd->seq_list */
- u32 seq_no;
- /* Lowest offset in current DataOUT sequence */
- u32 seq_start_offset;
- /* Highest offset in current DataOUT sequence */
- u32 seq_end_offset;
- /* Total size in bytes received so far of READ data */
- u32 read_data_done;
- /* Total size in bytes received so far of WRITE data */
- u32 write_data_done;
- /* Counter for FirstBurstLength key */
- u32 first_burst_len;
- /* Counter for MaxBurstLength key */
- u32 next_burst_len;
- /* Transfer size used for IP stack calls */
- u32 tx_size;
- /* Buffer used for various purposes */
- void *buf_ptr;
- /* Used by SendTargets=[iqn.,eui.] discovery */
- void *text_in_ptr;
- /* See include/linux/dma-mapping.h */
- enum dma_data_direction data_direction;
- /* iSCSI PDU Header + CRC */
- unsigned char pdu[ISCSI_HDR_LEN + ISCSI_CRC_LEN];
- /* Number of times struct iscsi_cmd is present in immediate queue */
- atomic_t immed_queue_count;
- atomic_t response_queue_count;
- spinlock_t datain_lock;
- spinlock_t dataout_timeout_lock;
- /* spinlock for protecting struct iscsi_cmd->i_state */
- spinlock_t istate_lock;
- /* spinlock for adding within command recovery entries */
- spinlock_t error_lock;
- /* spinlock for adding R2Ts */
- spinlock_t r2t_lock;
- /* DataIN List */
- struct list_head datain_list;
- /* R2T List */
- struct list_head cmd_r2t_list;
- /* Timer for DataOUT */
- struct timer_list dataout_timer;
- /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */
- struct kvec *iov_data;
- /* Iovecs for miscellaneous purposes */
-#define ISCSI_MISC_IOVECS 5
- struct kvec iov_misc[ISCSI_MISC_IOVECS];
- /* Array of struct iscsi_pdu used for DataPDUInOrder=No */
- struct iscsi_pdu *pdu_list;
- /* Current struct iscsi_pdu used for DataPDUInOrder=No */
- struct iscsi_pdu *pdu_ptr;
- /* Array of struct iscsi_seq used for DataSequenceInOrder=No */
- struct iscsi_seq *seq_list;
- /* Current struct iscsi_seq used for DataSequenceInOrder=No */
- struct iscsi_seq *seq_ptr;
- /* TMR Request when iscsi_opcode == ISCSI_OP_SCSI_TMFUNC */
- struct iscsi_tmr_req *tmr_req;
- /* Connection this command is alligient to */
- struct iscsi_conn *conn;
- /* Pointer to connection recovery entry */
- struct iscsi_conn_recovery *cr;
- /* Session the command is part of, used for connection recovery */
- struct iscsi_session *sess;
- /* list_head for connection list */
- struct list_head i_conn_node;
- /* The TCM I/O descriptor that is accessed via container_of() */
- struct se_cmd se_cmd;
- /* Sense buffer that will be mapped into outgoing status */
-#define ISCSI_SENSE_BUFFER_LEN (TRANSPORT_SENSE_BUFFER + 2)
- unsigned char sense_buffer[ISCSI_SENSE_BUFFER_LEN];
-
- u32 padding;
- u8 pad_bytes[4];
-
- struct scatterlist *first_data_sg;
- u32 first_data_sg_off;
- u32 kmapped_nents;
- sense_reason_t sense_reason;
-} ____cacheline_aligned;
-
-struct iscsi_tmr_req {
- bool task_reassign:1;
- u32 exp_data_sn;
- struct iscsi_cmd *ref_cmd;
- struct iscsi_conn_recovery *conn_recovery;
- struct se_tmr_req *se_tmr_req;
-};
-
-struct iscsi_conn {
- wait_queue_head_t queues_wq;
- /* Authentication Successful for this connection */
- u8 auth_complete;
- /* State connection is currently in */
- u8 conn_state;
- u8 conn_logout_reason;
- u8 network_transport;
- enum iscsi_timer_flags_table nopin_timer_flags;
- enum iscsi_timer_flags_table nopin_response_timer_flags;
- /* Used to know what thread encountered a transport failure */
- u8 which_thread;
- /* connection id assigned by the Initiator */
- u16 cid;
- /* Remote TCP Port */
- u16 login_port;
- u16 local_port;
- int net_size;
- int login_family;
- u32 auth_id;
- u32 conn_flags;
- /* Used for iscsi_tx_login_rsp() */
- itt_t login_itt;
- u32 exp_statsn;
- /* Per connection status sequence number */
- u32 stat_sn;
- /* IFMarkInt's Current Value */
- u32 if_marker;
- /* OFMarkInt's Current Value */
- u32 of_marker;
- /* Used for calculating OFMarker offset to next PDU */
- u32 of_marker_offset;
-#define IPV6_ADDRESS_SPACE 48
- unsigned char login_ip[IPV6_ADDRESS_SPACE];
- unsigned char local_ip[IPV6_ADDRESS_SPACE];
- int conn_usage_count;
- int conn_waiting_on_uc;
- atomic_t check_immediate_queue;
- atomic_t conn_logout_remove;
- atomic_t connection_exit;
- atomic_t connection_recovery;
- atomic_t connection_reinstatement;
- atomic_t connection_wait_rcfr;
- atomic_t sleep_on_conn_wait_comp;
- atomic_t transport_failed;
- struct completion conn_post_wait_comp;
- struct completion conn_wait_comp;
- struct completion conn_wait_rcfr_comp;
- struct completion conn_waiting_on_uc_comp;
- struct completion conn_logout_comp;
- struct completion tx_half_close_comp;
- struct completion rx_half_close_comp;
- /* socket used by this connection */
- struct socket *sock;
- void (*orig_data_ready)(struct sock *);
- void (*orig_state_change)(struct sock *);
-#define LOGIN_FLAGS_READ_ACTIVE 1
-#define LOGIN_FLAGS_CLOSED 2
-#define LOGIN_FLAGS_READY 4
- unsigned long login_flags;
- struct delayed_work login_work;
- struct delayed_work login_cleanup_work;
- struct iscsi_login *login;
- struct timer_list nopin_timer;
- struct timer_list nopin_response_timer;
- struct timer_list transport_timer;
- struct task_struct *login_kworker;
- /* Spinlock used for add/deleting cmd's from conn_cmd_list */
- spinlock_t cmd_lock;
- spinlock_t conn_usage_lock;
- spinlock_t immed_queue_lock;
- spinlock_t nopin_timer_lock;
- spinlock_t response_queue_lock;
- spinlock_t state_lock;
- /* libcrypto RX and TX contexts for crc32c */
- struct hash_desc conn_rx_hash;
- struct hash_desc conn_tx_hash;
- /* Used for scheduling TX and RX connection kthreads */
- cpumask_var_t conn_cpumask;
- unsigned int conn_rx_reset_cpumask:1;
- unsigned int conn_tx_reset_cpumask:1;
- /* list_head of struct iscsi_cmd for this connection */
- struct list_head conn_cmd_list;
- struct list_head immed_queue_list;
- struct list_head response_queue_list;
- struct iscsi_conn_ops *conn_ops;
- struct iscsi_login *conn_login;
- struct iscsit_transport *conn_transport;
- struct iscsi_param_list *param_list;
- /* Used for per connection auth state machine */
- void *auth_protocol;
- void *context;
- struct iscsi_login_thread_s *login_thread;
- struct iscsi_portal_group *tpg;
- struct iscsi_tpg_np *tpg_np;
- /* Pointer to parent session */
- struct iscsi_session *sess;
- /* Pointer to thread_set in use for this conn's threads */
- struct iscsi_thread_set *thread_set;
- /* list_head for session connection list */
- struct list_head conn_list;
-} ____cacheline_aligned;
-
-struct iscsi_conn_recovery {
- u16 cid;
- u32 cmd_count;
- u32 maxrecvdatasegmentlength;
- u32 maxxmitdatasegmentlength;
- int ready_for_reallegiance;
- struct list_head conn_recovery_cmd_list;
- spinlock_t conn_recovery_cmd_lock;
- struct timer_list time2retain_timer;
- struct iscsi_session *sess;
- struct list_head cr_list;
-} ____cacheline_aligned;
-
-struct iscsi_session {
- u8 initiator_vendor;
- u8 isid[6];
- enum iscsi_timer_flags_table time2retain_timer_flags;
- u8 version_active;
- u16 cid_called;
- u16 conn_recovery_count;
- u16 tsih;
- /* state session is currently in */
- u32 session_state;
- /* session wide counter: initiator assigned task tag */
- itt_t init_task_tag;
- /* session wide counter: target assigned task tag */
- u32 targ_xfer_tag;
- u32 cmdsn_window;
-
- /* protects cmdsn values */
- struct mutex cmdsn_mutex;
- /* session wide counter: expected command sequence number */
- u32 exp_cmd_sn;
- /* session wide counter: maximum allowed command sequence number */
- u32 max_cmd_sn;
- struct list_head sess_ooo_cmdsn_list;
-
- /* LIO specific session ID */
- u32 sid;
- char auth_type[8];
- /* unique within the target */
- int session_index;
- /* Used for session reference counting */
- int session_usage_count;
- int session_waiting_on_uc;
- atomic_long_t cmd_pdus;
- atomic_long_t rsp_pdus;
- atomic_long_t tx_data_octets;
- atomic_long_t rx_data_octets;
- atomic_long_t conn_digest_errors;
- atomic_long_t conn_timeout_errors;
- u64 creation_time;
- /* Number of active connections */
- atomic_t nconn;
- atomic_t session_continuation;
- atomic_t session_fall_back_to_erl0;
- atomic_t session_logout;
- atomic_t session_reinstatement;
- atomic_t session_stop_active;
- atomic_t sleep_on_sess_wait_comp;
- /* connection list */
- struct list_head sess_conn_list;
- struct list_head cr_active_list;
- struct list_head cr_inactive_list;
- spinlock_t conn_lock;
- spinlock_t cr_a_lock;
- spinlock_t cr_i_lock;
- spinlock_t session_usage_lock;
- spinlock_t ttt_lock;
- struct completion async_msg_comp;
- struct completion reinstatement_comp;
- struct completion session_wait_comp;
- struct completion session_waiting_on_uc_comp;
- struct timer_list time2retain_timer;
- struct iscsi_sess_ops *sess_ops;
- struct se_session *se_sess;
- struct iscsi_portal_group *tpg;
-} ____cacheline_aligned;
-
-struct iscsi_login {
- u8 auth_complete;
- u8 checked_for_existing;
- u8 current_stage;
- u8 leading_connection;
- u8 first_request;
- u8 version_min;
- u8 version_max;
- u8 login_complete;
- u8 login_failed;
- bool zero_tsih;
- char isid[6];
- u32 cmd_sn;
- itt_t init_task_tag;
- u32 initial_exp_statsn;
- u32 rsp_length;
- u16 cid;
- u16 tsih;
- char req[ISCSI_HDR_LEN];
- char rsp[ISCSI_HDR_LEN];
- char *req_buf;
- char *rsp_buf;
- struct iscsi_conn *conn;
- struct iscsi_np *np;
-} ____cacheline_aligned;
-
-struct iscsi_node_attrib {
- u32 dataout_timeout;
- u32 dataout_timeout_retries;
- u32 default_erl;
- u32 nopin_timeout;
- u32 nopin_response_timeout;
- u32 random_datain_pdu_offsets;
- u32 random_datain_seq_offsets;
- u32 random_r2t_offsets;
- u32 tmr_cold_reset;
- u32 tmr_warm_reset;
- struct iscsi_node_acl *nacl;
-};
-
-struct se_dev_entry_s;
-
-struct iscsi_node_auth {
- enum naf_flags_table naf_flags;
- int authenticate_target;
- /* Used for iscsit_global->discovery_auth,
- * set to zero (auth disabled) by default */
- int enforce_discovery_auth;
-#define MAX_USER_LEN 256
-#define MAX_PASS_LEN 256
- char userid[MAX_USER_LEN];
- char password[MAX_PASS_LEN];
- char userid_mutual[MAX_USER_LEN];
- char password_mutual[MAX_PASS_LEN];
-};
-
-#include "iscsi_target_stat.h"
-
-struct iscsi_node_stat_grps {
- struct config_group iscsi_sess_stats_group;
- struct config_group iscsi_conn_stats_group;
-};
-
-struct iscsi_node_acl {
- struct iscsi_node_attrib node_attrib;
- struct iscsi_node_auth node_auth;
- struct iscsi_node_stat_grps node_stat_grps;
- struct se_node_acl se_node_acl;
-};
-
-struct iscsi_tpg_attrib {
- u32 authentication;
- u32 login_timeout;
- u32 netif_timeout;
- u32 generate_node_acls;
- u32 cache_dynamic_acls;
- u32 default_cmdsn_depth;
- u32 demo_mode_write_protect;
- u32 prod_mode_write_protect;
- u32 demo_mode_discovery;
- u32 default_erl;
- u8 t10_pi;
- struct iscsi_portal_group *tpg;
-};
-
-struct iscsi_np {
- int np_network_transport;
- int np_ip_proto;
- int np_sock_type;
- enum np_thread_state_table np_thread_state;
- bool enabled;
- enum iscsi_timer_flags_table np_login_timer_flags;
- u32 np_exports;
- enum np_flags_table np_flags;
- unsigned char np_ip[IPV6_ADDRESS_SPACE];
- u16 np_port;
- spinlock_t np_thread_lock;
- struct completion np_restart_comp;
- struct socket *np_socket;
- struct __kernel_sockaddr_storage np_sockaddr;
- struct task_struct *np_thread;
- struct timer_list np_login_timer;
- void *np_context;
- struct iscsit_transport *np_transport;
- struct list_head np_list;
-} ____cacheline_aligned;
-
-struct iscsi_tpg_np {
- struct iscsi_np *tpg_np;
- struct iscsi_portal_group *tpg;
- struct iscsi_tpg_np *tpg_np_parent;
- struct list_head tpg_np_list;
- struct list_head tpg_np_child_list;
- struct list_head tpg_np_parent_list;
- struct se_tpg_np se_tpg_np;
- spinlock_t tpg_np_parent_lock;
- struct completion tpg_np_comp;
- struct kref tpg_np_kref;
-};
-
-struct iscsi_portal_group {
- unsigned char tpg_chap_id;
- /* TPG State */
- enum tpg_state_table tpg_state;
- /* Target Portal Group Tag */
- u16 tpgt;
- /* Id assigned to target sessions */
- u16 ntsih;
- /* Number of active sessions */
- u32 nsessions;
- /* Number of Network Portals available for this TPG */
- u32 num_tpg_nps;
- /* Per TPG LIO specific session ID. */
- u32 sid;
- /* Spinlock for adding/removing Network Portals */
- spinlock_t tpg_np_lock;
- spinlock_t tpg_state_lock;
- struct se_portal_group tpg_se_tpg;
- struct mutex tpg_access_lock;
- struct semaphore np_login_sem;
- struct iscsi_tpg_attrib tpg_attrib;
- struct iscsi_node_auth tpg_demo_auth;
- /* Pointer to default list of iSCSI parameters for TPG */
- struct iscsi_param_list *param_list;
- struct iscsi_tiqn *tpg_tiqn;
- struct list_head tpg_gnp_list;
- struct list_head tpg_list;
-} ____cacheline_aligned;
-
-struct iscsi_wwn_stat_grps {
- struct config_group iscsi_stat_group;
- struct config_group iscsi_instance_group;
- struct config_group iscsi_sess_err_group;
- struct config_group iscsi_tgt_attr_group;
- struct config_group iscsi_login_stats_group;
- struct config_group iscsi_logout_stats_group;
-};
-
-struct iscsi_tiqn {
-#define ISCSI_IQN_LEN 224
- unsigned char tiqn[ISCSI_IQN_LEN];
- enum tiqn_state_table tiqn_state;
- int tiqn_access_count;
- u32 tiqn_active_tpgs;
- u32 tiqn_ntpgs;
- u32 tiqn_num_tpg_nps;
- u32 tiqn_nsessions;
- struct list_head tiqn_list;
- struct list_head tiqn_tpg_list;
- spinlock_t tiqn_state_lock;
- spinlock_t tiqn_tpg_lock;
- struct se_wwn tiqn_wwn;
- struct iscsi_wwn_stat_grps tiqn_stat_grps;
- int tiqn_index;
- struct iscsi_sess_err_stats sess_err_stats;
- struct iscsi_login_stats login_stats;
- struct iscsi_logout_stats logout_stats;
-} ____cacheline_aligned;
-
-struct iscsit_global {
- /* In core shutdown */
- u32 in_shutdown;
- u32 active_ts;
- /* Unique identifier used for the authentication daemon */
- u32 auth_id;
- u32 inactive_ts;
- /* Thread Set bitmap count */
- int ts_bitmap_count;
- /* Thread Set bitmap pointer */
- unsigned long *ts_bitmap;
- /* Used for iSCSI discovery session authentication */
- struct iscsi_node_acl discovery_acl;
- struct iscsi_portal_group *discovery_tpg;
-};
-
-#endif /* ISCSI_TARGET_CORE_H */
diff --git a/drivers/target/iscsi/iscsi_target_datain_values.c b/drivers/target/iscsi/iscsi_target_datain_values.c
index e93d5a7a3f81..fb3b52b124ac 100644
--- a/drivers/target/iscsi/iscsi_target_datain_values.c
+++ b/drivers/target/iscsi/iscsi_target_datain_values.c
@@ -18,7 +18,7 @@
#include <scsi/iscsi_proto.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_erl1.h"
#include "iscsi_target_util.h"
diff --git a/drivers/target/iscsi/iscsi_target_device.c b/drivers/target/iscsi/iscsi_target_device.c
index 7087c736daa5..34c3cd1b05ce 100644
--- a/drivers/target/iscsi/iscsi_target_device.c
+++ b/drivers/target/iscsi/iscsi_target_device.c
@@ -21,7 +21,7 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_device.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
diff --git a/drivers/target/iscsi/iscsi_target_erl0.c b/drivers/target/iscsi/iscsi_target_erl0.c
index a0ae5fc0ad75..1c197bad6132 100644
--- a/drivers/target/iscsi/iscsi_target_erl0.c
+++ b/drivers/target/iscsi/iscsi_target_erl0.c
@@ -21,7 +21,8 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
+#include <target/iscsi/iscsi_transport.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_tq.h"
#include "iscsi_target_erl0.h"
@@ -939,7 +940,8 @@ void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn)
if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) {
spin_unlock_bh(&conn->state_lock);
- iscsit_close_connection(conn);
+ if (conn->conn_transport->transport_type == ISCSI_TCP)
+ iscsit_close_connection(conn);
return;
}
diff --git a/drivers/target/iscsi/iscsi_target_erl1.c b/drivers/target/iscsi/iscsi_target_erl1.c
index cda4d80cfaef..2e561deb30a2 100644
--- a/drivers/target/iscsi/iscsi_target_erl1.c
+++ b/drivers/target/iscsi/iscsi_target_erl1.c
@@ -22,7 +22,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_datain_values.h"
#include "iscsi_target_device.h"
diff --git a/drivers/target/iscsi/iscsi_target_erl2.c b/drivers/target/iscsi/iscsi_target_erl2.c
index 4ca8fd2a70db..e24f1c7c5862 100644
--- a/drivers/target/iscsi/iscsi_target_erl2.c
+++ b/drivers/target/iscsi/iscsi_target_erl2.c
@@ -21,7 +21,7 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_datain_values.h"
#include "iscsi_target_util.h"
#include "iscsi_target_erl0.h"
diff --git a/drivers/target/iscsi/iscsi_target_login.c b/drivers/target/iscsi/iscsi_target_login.c
index 713c0c1877ab..153fb66ac1b8 100644
--- a/drivers/target/iscsi/iscsi_target_login.c
+++ b/drivers/target/iscsi/iscsi_target_login.c
@@ -24,14 +24,14 @@
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
+#include <target/iscsi/iscsi_target_stat.h>
#include "iscsi_target_tq.h"
#include "iscsi_target_device.h"
#include "iscsi_target_nego.h"
#include "iscsi_target_erl0.h"
#include "iscsi_target_erl2.h"
#include "iscsi_target_login.h"
-#include "iscsi_target_stat.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
#include "iscsi_target.h"
diff --git a/drivers/target/iscsi/iscsi_target_nego.c b/drivers/target/iscsi/iscsi_target_nego.c
index 62a095f36bf2..8c02fa34716f 100644
--- a/drivers/target/iscsi/iscsi_target_nego.c
+++ b/drivers/target/iscsi/iscsi_target_nego.c
@@ -22,7 +22,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_login.h"
#include "iscsi_target_nego.h"
diff --git a/drivers/target/iscsi/iscsi_target_nodeattrib.c b/drivers/target/iscsi/iscsi_target_nodeattrib.c
index 16454a922e2b..208cca8a363c 100644
--- a/drivers/target/iscsi/iscsi_target_nodeattrib.c
+++ b/drivers/target/iscsi/iscsi_target_nodeattrib.c
@@ -18,7 +18,7 @@
#include <target/target_core_base.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_device.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index 18c29260b4a2..d4f9e9645697 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -18,7 +18,7 @@
#include <linux/slab.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_util.h"
#include "iscsi_target_parameters.h"
diff --git a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
index ca41b583f2f6..e446a09c886b 100644
--- a/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
+++ b/drivers/target/iscsi/iscsi_target_seq_pdu_list.c
@@ -20,7 +20,7 @@
#include <linux/slab.h>
#include <linux/random.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_util.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_seq_pdu_list.h"
diff --git a/drivers/target/iscsi/iscsi_target_stat.c b/drivers/target/iscsi/iscsi_target_stat.c
index 103395510307..5e1349a3b143 100644
--- a/drivers/target/iscsi/iscsi_target_stat.c
+++ b/drivers/target/iscsi/iscsi_target_stat.c
@@ -23,12 +23,12 @@
#include <target/target_core_base.h>
#include <target/configfs_macros.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_device.h"
#include "iscsi_target_tpg.h"
#include "iscsi_target_util.h"
-#include "iscsi_target_stat.h"
+#include <target/iscsi/iscsi_target_stat.h>
#ifndef INITIAL_JIFFIES
#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ))
diff --git a/drivers/target/iscsi/iscsi_target_stat.h b/drivers/target/iscsi/iscsi_target_stat.h
deleted file mode 100644
index 3ff76b4faad3..000000000000
--- a/drivers/target/iscsi/iscsi_target_stat.h
+++ /dev/null
@@ -1,64 +0,0 @@
-#ifndef ISCSI_TARGET_STAT_H
-#define ISCSI_TARGET_STAT_H
-
-/*
- * For struct iscsi_tiqn->tiqn_wwn default groups
- */
-extern struct config_item_type iscsi_stat_instance_cit;
-extern struct config_item_type iscsi_stat_sess_err_cit;
-extern struct config_item_type iscsi_stat_tgt_attr_cit;
-extern struct config_item_type iscsi_stat_login_cit;
-extern struct config_item_type iscsi_stat_logout_cit;
-
-/*
- * For struct iscsi_session->se_sess default groups
- */
-extern struct config_item_type iscsi_stat_sess_cit;
-
-/* iSCSI session error types */
-#define ISCSI_SESS_ERR_UNKNOWN 0
-#define ISCSI_SESS_ERR_DIGEST 1
-#define ISCSI_SESS_ERR_CXN_TIMEOUT 2
-#define ISCSI_SESS_ERR_PDU_FORMAT 3
-
-/* iSCSI session error stats */
-struct iscsi_sess_err_stats {
- spinlock_t lock;
- u32 digest_errors;
- u32 cxn_timeout_errors;
- u32 pdu_format_errors;
- u32 last_sess_failure_type;
- char last_sess_fail_rem_name[224];
-} ____cacheline_aligned;
-
-/* iSCSI login failure types (sub oids) */
-#define ISCSI_LOGIN_FAIL_OTHER 2
-#define ISCSI_LOGIN_FAIL_REDIRECT 3
-#define ISCSI_LOGIN_FAIL_AUTHORIZE 4
-#define ISCSI_LOGIN_FAIL_AUTHENTICATE 5
-#define ISCSI_LOGIN_FAIL_NEGOTIATE 6
-
-/* iSCSI login stats */
-struct iscsi_login_stats {
- spinlock_t lock;
- u32 accepts;
- u32 other_fails;
- u32 redirects;
- u32 authorize_fails;
- u32 authenticate_fails;
- u32 negotiate_fails; /* used for notifications */
- u64 last_fail_time; /* time stamp (jiffies) */
- u32 last_fail_type;
- int last_intr_fail_ip_family;
- unsigned char last_intr_fail_ip_addr[IPV6_ADDRESS_SPACE];
- char last_intr_fail_name[224];
-} ____cacheline_aligned;
-
-/* iSCSI logout stats */
-struct iscsi_logout_stats {
- spinlock_t lock;
- u32 normal_logouts;
- u32 abnormal_logouts;
-} ____cacheline_aligned;
-
-#endif /*** ISCSI_TARGET_STAT_H ***/
diff --git a/drivers/target/iscsi/iscsi_target_tmr.c b/drivers/target/iscsi/iscsi_target_tmr.c
index 78404b1cc0bf..b0224a77e26d 100644
--- a/drivers/target/iscsi/iscsi_target_tmr.c
+++ b/drivers/target/iscsi/iscsi_target_tmr.c
@@ -23,7 +23,7 @@
#include <target/target_core_fabric.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_datain_values.h"
#include "iscsi_target_device.h"
diff --git a/drivers/target/iscsi/iscsi_target_tpg.c b/drivers/target/iscsi/iscsi_target_tpg.c
index 9053a3c0c6e5..bdd127c0e3ae 100644
--- a/drivers/target/iscsi/iscsi_target_tpg.c
+++ b/drivers/target/iscsi/iscsi_target_tpg.c
@@ -20,7 +20,7 @@
#include <target/target_core_fabric.h>
#include <target/target_core_configfs.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_erl0.h"
#include "iscsi_target_login.h"
#include "iscsi_target_nodeattrib.h"
diff --git a/drivers/target/iscsi/iscsi_target_tq.c b/drivers/target/iscsi/iscsi_target_tq.c
index 601e9cc61e98..26aa50996473 100644
--- a/drivers/target/iscsi/iscsi_target_tq.c
+++ b/drivers/target/iscsi/iscsi_target_tq.c
@@ -20,40 +20,26 @@
#include <linux/list.h>
#include <linux/bitmap.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_tq.h"
#include "iscsi_target.h"
-static LIST_HEAD(active_ts_list);
static LIST_HEAD(inactive_ts_list);
-static DEFINE_SPINLOCK(active_ts_lock);
static DEFINE_SPINLOCK(inactive_ts_lock);
static DEFINE_SPINLOCK(ts_bitmap_lock);
-static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts)
-{
- spin_lock(&active_ts_lock);
- list_add_tail(&ts->ts_list, &active_ts_list);
- iscsit_global->active_ts++;
- spin_unlock(&active_ts_lock);
-}
-
static void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts)
{
+ if (!list_empty(&ts->ts_list)) {
+ WARN_ON(1);
+ return;
+ }
spin_lock(&inactive_ts_lock);
list_add_tail(&ts->ts_list, &inactive_ts_list);
iscsit_global->inactive_ts++;
spin_unlock(&inactive_ts_lock);
}
-static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts)
-{
- spin_lock(&active_ts_lock);
- list_del(&ts->ts_list);
- iscsit_global->active_ts--;
- spin_unlock(&active_ts_lock);
-}
-
static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
{
struct iscsi_thread_set *ts;
@@ -66,7 +52,7 @@ static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void)
ts = list_first_entry(&inactive_ts_list, struct iscsi_thread_set, ts_list);
- list_del(&ts->ts_list);
+ list_del_init(&ts->ts_list);
iscsit_global->inactive_ts--;
spin_unlock(&inactive_ts_lock);
@@ -204,8 +190,6 @@ static void iscsi_deallocate_extra_thread_sets(void)
void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts)
{
- iscsi_add_ts_to_active_list(ts);
-
spin_lock_bh(&ts->ts_state_lock);
conn->thread_set = ts;
ts->conn = conn;
@@ -397,7 +381,6 @@ struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts)
if (ts->delay_inactive && (--ts->thread_count == 0)) {
spin_unlock_bh(&ts->ts_state_lock);
- iscsi_del_ts_from_active_list(ts);
if (!iscsit_global->in_shutdown)
iscsi_deallocate_extra_thread_sets();
@@ -452,7 +435,6 @@ struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts)
if (ts->delay_inactive && (--ts->thread_count == 0)) {
spin_unlock_bh(&ts->ts_state_lock);
- iscsi_del_ts_from_active_list(ts);
if (!iscsit_global->in_shutdown)
iscsi_deallocate_extra_thread_sets();
diff --git a/drivers/target/iscsi/iscsi_target_util.c b/drivers/target/iscsi/iscsi_target_util.c
index bcd88ec99793..390df8ed72b2 100644
--- a/drivers/target/iscsi/iscsi_target_util.c
+++ b/drivers/target/iscsi/iscsi_target_util.c
@@ -25,7 +25,7 @@
#include <target/target_core_configfs.h>
#include <target/iscsi/iscsi_transport.h>
-#include "iscsi_target_core.h"
+#include <target/iscsi/iscsi_target_core.h>
#include "iscsi_target_parameters.h"
#include "iscsi_target_seq_pdu_list.h"
#include "iscsi_target_datain_values.h"
@@ -390,6 +390,7 @@ struct iscsi_cmd *iscsit_find_cmd_from_itt(
init_task_tag, conn->cid);
return NULL;
}
+EXPORT_SYMBOL(iscsit_find_cmd_from_itt);
struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(
struct iscsi_conn *conn,
@@ -939,13 +940,8 @@ static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response)
state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE :
ISTATE_SEND_NOPIN_NO_RESPONSE;
cmd->init_task_tag = RESERVED_ITT;
- spin_lock_bh(&conn->sess->ttt_lock);
- cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ :
- 0xFFFFFFFF;
- if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF))
- cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++;
- spin_unlock_bh(&conn->sess->ttt_lock);
-
+ cmd->targ_xfer_tag = (want_response) ?
+ session_get_next_ttt(conn->sess) : 0xFFFFFFFF;
spin_lock_bh(&conn->cmd_lock);
list_add_tail(&cmd->i_conn_node, &conn->conn_cmd_list);
spin_unlock_bh(&conn->cmd_lock);
diff --git a/drivers/target/iscsi/iscsi_target_util.h b/drivers/target/iscsi/iscsi_target_util.h
index a68508c4fec8..1ab754a671ff 100644
--- a/drivers/target/iscsi/iscsi_target_util.h
+++ b/drivers/target/iscsi/iscsi_target_util.h
@@ -16,7 +16,6 @@ extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32);
extern int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd,
unsigned char * ,__be32 cmdsn);
extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *);
-extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, itt_t);
extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *,
itt_t, u32);
extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32);
diff --git a/drivers/target/target_core_file.c b/drivers/target/target_core_file.c
index d836de200a03..44620fb6bd45 100644
--- a/drivers/target/target_core_file.c
+++ b/drivers/target/target_core_file.c
@@ -494,6 +494,11 @@ fd_execute_write_same(struct se_cmd *cmd)
target_complete_cmd(cmd, SAM_STAT_GOOD);
return 0;
}
+ if (cmd->prot_op) {
+ pr_err("WRITE_SAME: Protection information with FILEIO"
+ " backends not supported\n");
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
sg = &cmd->t_data_sg[0];
if (cmd->t_data_nents > 1 ||
diff --git a/drivers/target/target_core_iblock.c b/drivers/target/target_core_iblock.c
index 78346b850968..d4a4b0fb444a 100644
--- a/drivers/target/target_core_iblock.c
+++ b/drivers/target/target_core_iblock.c
@@ -464,6 +464,11 @@ iblock_execute_write_same(struct se_cmd *cmd)
sector_t block_lba = cmd->t_task_lba;
sector_t sectors = sbc_get_write_same_sectors(cmd);
+ if (cmd->prot_op) {
+ pr_err("WRITE_SAME: Protection information with IBLOCK"
+ " backends not supported\n");
+ return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
+ }
sg = &cmd->t_data_sg[0];
if (cmd->t_data_nents > 1 ||
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 283cf786ef98..2de6fb8cee8d 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -1874,8 +1874,8 @@ static int core_scsi3_update_aptpl_buf(
}
if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
- pr_err("Unable to update renaming"
- " APTPL metadata\n");
+ pr_err("Unable to update renaming APTPL metadata,"
+ " reallocating larger buffer\n");
ret = -EMSGSIZE;
goto out;
}
@@ -1892,8 +1892,8 @@ static int core_scsi3_update_aptpl_buf(
lun->lun_sep->sep_rtpi, lun->unpacked_lun, reg_count);
if ((len + strlen(tmp) >= pr_aptpl_buf_len)) {
- pr_err("Unable to update renaming"
- " APTPL metadata\n");
+ pr_err("Unable to update renaming APTPL metadata,"
+ " reallocating larger buffer\n");
ret = -EMSGSIZE;
goto out;
}
@@ -1956,7 +1956,7 @@ static int __core_scsi3_write_aptpl_to_file(
static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, bool aptpl)
{
unsigned char *buf;
- int rc;
+ int rc, len = PR_APTPL_BUF_LEN;
if (!aptpl) {
char *null_buf = "No Registrations or Reservations\n";
@@ -1970,25 +1970,26 @@ static sense_reason_t core_scsi3_update_and_write_aptpl(struct se_device *dev, b
return 0;
}
-
- buf = kzalloc(PR_APTPL_BUF_LEN, GFP_KERNEL);
+retry:
+ buf = vzalloc(len);
if (!buf)
return TCM_OUT_OF_RESOURCES;
- rc = core_scsi3_update_aptpl_buf(dev, buf, PR_APTPL_BUF_LEN);
+ rc = core_scsi3_update_aptpl_buf(dev, buf, len);
if (rc < 0) {
- kfree(buf);
- return TCM_OUT_OF_RESOURCES;
+ vfree(buf);
+ len *= 2;
+ goto retry;
}
rc = __core_scsi3_write_aptpl_to_file(dev, buf);
if (rc != 0) {
pr_err("SPC-3 PR: Could not update APTPL\n");
- kfree(buf);
+ vfree(buf);
return TCM_LOGICAL_UNIT_COMMUNICATION_FAILURE;
}
dev->t10_pr.pr_aptpl_active = 1;
- kfree(buf);
+ vfree(buf);
pr_debug("SPC-3 PR: Set APTPL Bit Activated\n");
return 0;
}
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index cd4bed7b2757..9a2f9d3a6e70 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -37,6 +37,9 @@
#include "target_core_alua.h"
static sense_reason_t
+sbc_check_prot(struct se_device *, struct se_cmd *, unsigned char *, u32, bool);
+
+static sense_reason_t
sbc_emulate_readcapacity(struct se_cmd *cmd)
{
struct se_device *dev = cmd->se_dev;
@@ -251,7 +254,10 @@ static inline unsigned long long transport_lba_64_ext(unsigned char *cdb)
static sense_reason_t
sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *ops)
{
+ struct se_device *dev = cmd->se_dev;
+ sector_t end_lba = dev->transport->get_blocks(dev) + 1;
unsigned int sectors = sbc_get_write_same_sectors(cmd);
+ sense_reason_t ret;
if ((flags[0] & 0x04) || (flags[0] & 0x02)) {
pr_err("WRITE_SAME PBDATA and LBDATA"
@@ -264,6 +270,16 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
sectors, cmd->se_dev->dev_attrib.max_write_same_len);
return TCM_INVALID_CDB_FIELD;
}
+ /*
+ * Sanity check for LBA wrap and request past end of device.
+ */
+ if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) ||
+ ((cmd->t_task_lba + sectors) > end_lba)) {
+ pr_err("WRITE_SAME exceeds last lba %llu (lba %llu, sectors %u)\n",
+ (unsigned long long)end_lba, cmd->t_task_lba, sectors);
+ return TCM_ADDRESS_OUT_OF_RANGE;
+ }
+
/* We always have ANC_SUP == 0 so setting ANCHOR is always an error */
if (flags[0] & 0x10) {
pr_warn("WRITE SAME with ANCHOR not supported\n");
@@ -277,12 +293,21 @@ sbc_setup_write_same(struct se_cmd *cmd, unsigned char *flags, struct sbc_ops *o
if (!ops->execute_write_same_unmap)
return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (!dev->dev_attrib.emulate_tpws) {
+ pr_err("Got WRITE_SAME w/ UNMAP=1, but backend device"
+ " has emulate_tpws disabled\n");
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
cmd->execute_cmd = ops->execute_write_same_unmap;
return 0;
}
if (!ops->execute_write_same)
return TCM_UNSUPPORTED_SCSI_OPCODE;
+ ret = sbc_check_prot(dev, cmd, &cmd->t_task_cdb[0], sectors, true);
+ if (ret)
+ return ret;
+
cmd->execute_cmd = ops->execute_write_same;
return 0;
}
@@ -614,14 +639,21 @@ sbc_set_prot_op_checks(u8 protect, enum target_prot_type prot_type,
return 0;
}
-static bool
+static sense_reason_t
sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
u32 sectors, bool is_write)
{
u8 protect = cdb[1] >> 5;
- if ((!cmd->t_prot_sg || !cmd->t_prot_nents) && cmd->prot_pto)
- return true;
+ if (!cmd->t_prot_sg || !cmd->t_prot_nents) {
+ if (protect && !dev->dev_attrib.pi_prot_type) {
+ pr_err("CDB contains protect bit, but device does not"
+ " advertise PROTECT=1 feature bit\n");
+ return TCM_INVALID_CDB_FIELD;
+ }
+ if (cmd->prot_pto)
+ return TCM_NO_SENSE;
+ }
switch (dev->dev_attrib.pi_prot_type) {
case TARGET_DIF_TYPE3_PROT:
@@ -629,7 +661,7 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
break;
case TARGET_DIF_TYPE2_PROT:
if (protect)
- return false;
+ return TCM_INVALID_CDB_FIELD;
cmd->reftag_seed = cmd->t_task_lba;
break;
@@ -638,12 +670,12 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
break;
case TARGET_DIF_TYPE0_PROT:
default:
- return true;
+ return TCM_NO_SENSE;
}
if (sbc_set_prot_op_checks(protect, dev->dev_attrib.pi_prot_type,
is_write, cmd))
- return false;
+ return TCM_INVALID_CDB_FIELD;
cmd->prot_type = dev->dev_attrib.pi_prot_type;
cmd->prot_length = dev->prot_length * sectors;
@@ -662,7 +694,30 @@ sbc_check_prot(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb,
__func__, cmd->prot_type, cmd->data_length, cmd->prot_length,
cmd->prot_op, cmd->prot_checks);
- return true;
+ return TCM_NO_SENSE;
+}
+
+static int
+sbc_check_dpofua(struct se_device *dev, struct se_cmd *cmd, unsigned char *cdb)
+{
+ if (cdb[1] & 0x10) {
+ if (!dev->dev_attrib.emulate_dpo) {
+ pr_err("Got CDB: 0x%02x with DPO bit set, but device"
+ " does not advertise support for DPO\n", cdb[0]);
+ return -EINVAL;
+ }
+ }
+ if (cdb[1] & 0x8) {
+ if (!dev->dev_attrib.emulate_fua_write ||
+ !dev->dev_attrib.emulate_write_cache) {
+ pr_err("Got CDB: 0x%02x with FUA bit set, but device"
+ " does not advertise support for FUA write\n",
+ cdb[0]);
+ return -EINVAL;
+ }
+ cmd->se_cmd_flags |= SCF_FUA;
+ }
+ return 0;
}
sense_reason_t
@@ -686,8 +741,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
+ if (ret)
+ return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
@@ -697,8 +756,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
+ if (ret)
+ return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
@@ -708,8 +771,12 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, false))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, false);
+ if (ret)
+ return ret;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
@@ -727,11 +794,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_10(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
+ if (ret)
+ return ret;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
@@ -740,11 +809,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_12(cdb);
cmd->t_task_lba = transport_lba_32(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
+ if (ret)
+ return ret;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
@@ -753,11 +824,13 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
sectors = transport_get_sectors_16(cdb);
cmd->t_task_lba = transport_lba_64(cdb);
- if (!sbc_check_prot(dev, cmd, cdb, sectors, true))
- return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
+ ret = sbc_check_prot(dev, cmd, cdb, sectors, true);
+ if (ret)
+ return ret;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
@@ -768,6 +841,9 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
return TCM_INVALID_CDB_FIELD;
sectors = transport_get_sectors_10(cdb);
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
+
cmd->t_task_lba = transport_lba_32(cdb);
cmd->se_cmd_flags |= SCF_SCSI_DATA_CDB;
@@ -777,8 +853,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
cmd->transport_complete_callback = &xdreadwrite_callback;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
break;
case VARIABLE_LENGTH_CMD:
{
@@ -787,6 +861,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
case XDWRITEREAD_32:
sectors = transport_get_sectors_32(cdb);
+ if (sbc_check_dpofua(dev, cmd, cdb))
+ return TCM_INVALID_CDB_FIELD;
/*
* Use WRITE_32 and READ_32 opcodes for the emulated
* XDWRITE_READ_32 logic.
@@ -801,8 +877,6 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
cmd->execute_rw = ops->execute_rw;
cmd->execute_cmd = sbc_execute_rw;
cmd->transport_complete_callback = &xdreadwrite_callback;
- if (cdb[1] & 0x8)
- cmd->se_cmd_flags |= SCF_FUA;
break;
case WRITE_SAME_32:
sectors = transport_get_sectors_32(cdb);
@@ -888,6 +962,11 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
if (!ops->execute_unmap)
return TCM_UNSUPPORTED_SCSI_OPCODE;
+ if (!dev->dev_attrib.emulate_tpu) {
+ pr_err("Got UNMAP, but backend device has"
+ " emulate_tpu disabled\n");
+ return TCM_UNSUPPORTED_SCSI_OPCODE;
+ }
size = get_unaligned_be16(&cdb[7]);
cmd->execute_cmd = ops->execute_unmap;
break;
@@ -955,7 +1034,8 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
unsigned long long end_lba;
check_lba:
end_lba = dev->transport->get_blocks(dev) + 1;
- if (cmd->t_task_lba + sectors > end_lba) {
+ if (((cmd->t_task_lba + sectors) < cmd->t_task_lba) ||
+ ((cmd->t_task_lba + sectors) > end_lba)) {
pr_err("cmd exceeds last lba %llu "
"(lba %llu, sectors %u)\n",
end_lba, cmd->t_task_lba, sectors);
diff --git a/drivers/target/target_core_spc.c b/drivers/target/target_core_spc.c
index 4c71657da56a..460e93109473 100644
--- a/drivers/target/target_core_spc.c
+++ b/drivers/target/target_core_spc.c
@@ -647,7 +647,7 @@ spc_emulate_evpd_b2(struct se_cmd *cmd, unsigned char *buf)
* support the use of the WRITE SAME (16) command to unmap LBAs.
*/
if (dev->dev_attrib.emulate_tpws != 0)
- buf[5] |= 0x40;
+ buf[5] |= 0x40 | 0x20;
return 0;
}
diff --git a/drivers/target/target_core_user.c b/drivers/target/target_core_user.c
index 1157b559683b..1a1bcf71ec9d 100644
--- a/drivers/target/target_core_user.c
+++ b/drivers/target/target_core_user.c
@@ -784,9 +784,7 @@ static int tcmu_netlink_event(enum tcmu_genl_cmd cmd, const char *name, int mino
if (ret < 0)
goto free_skb;
- ret = genlmsg_end(skb, msg_header);
- if (ret < 0)
- goto free_skb;
+ genlmsg_end(skb, msg_header);
ret = genlmsg_multicast(&tcmu_genl_family, skb, 0,
TCMU_MCGRP_CONFIG, GFP_KERNEL);
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile
index d4413698a85f..ba77a34f659f 100644
--- a/drivers/thermal/int340x_thermal/Makefile
+++ b/drivers/thermal/int340x_thermal/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o
+obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
index 65a98a97df07..25d244cbbe8f 100644
--- a/drivers/thermal/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -18,19 +18,15 @@
enum int3400_thermal_uuid {
INT3400_THERMAL_PASSIVE_1,
- INT3400_THERMAL_PASSIVE_2,
INT3400_THERMAL_ACTIVE,
INT3400_THERMAL_CRITICAL,
- INT3400_THERMAL_COOLING_MODE,
INT3400_THERMAL_MAXIMUM_UUID,
};
static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
- "9E04115A-AE87-4D1C-9500-0F3E340BFE75",
"3A95C389-E4B8-4629-A526-C52C88626BAE",
"97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
- "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531",
};
struct int3400_thermal_priv {
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c
index c5cbc3af3a05..69df3d960303 100644
--- a/drivers/thermal/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3402_thermal.c
@@ -14,152 +14,39 @@
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
+#include "int340x_thermal_zone.h"
-#define ACPI_ACTIVE_COOLING_MAX_NR 10
-
-struct active_trip {
- unsigned long temp;
- int id;
- bool valid;
-};
+#define INT3402_PERF_CHANGED_EVENT 0x80
+#define INT3402_THERMAL_EVENT 0x90
struct int3402_thermal_data {
- unsigned long *aux_trips;
- int aux_trip_nr;
- unsigned long psv_temp;
- int psv_trip_id;
- unsigned long crt_temp;
- int crt_trip_id;
- unsigned long hot_temp;
- int hot_trip_id;
- struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR];
acpi_handle *handle;
+ struct int34x_thermal_zone *int340x_zone;
};
-static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone,
- unsigned long *temp)
-{
- struct int3402_thermal_data *d = zone->devdata;
- unsigned long long tmp;
- acpi_status status;
-
- status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp);
- if (ACPI_FAILURE(status))
- return -ENODEV;
-
- /* _TMP returns the temperature in tenths of degrees Kelvin */
- *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
-
- return 0;
-}
-
-static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone,
- int trip, unsigned long *temp)
+static void int3402_notify(acpi_handle handle, u32 event, void *data)
{
- struct int3402_thermal_data *d = zone->devdata;
- int i;
-
- if (trip < d->aux_trip_nr)
- *temp = d->aux_trips[trip];
- else if (trip == d->crt_trip_id)
- *temp = d->crt_temp;
- else if (trip == d->psv_trip_id)
- *temp = d->psv_temp;
- else if (trip == d->hot_trip_id)
- *temp = d->hot_temp;
- else {
- for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
- if (d->act_trips[i].valid &&
- d->act_trips[i].id == trip) {
- *temp = d->act_trips[i].temp;
- break;
- }
- }
- if (i == ACPI_ACTIVE_COOLING_MAX_NR)
- return -EINVAL;
+ struct int3402_thermal_data *priv = data;
+
+ if (!priv)
+ return;
+
+ switch (event) {
+ case INT3402_PERF_CHANGED_EVENT:
+ break;
+ case INT3402_THERMAL_EVENT:
+ int340x_thermal_zone_device_update(priv->int340x_zone);
+ break;
+ default:
+ break;
}
- return 0;
-}
-
-static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone,
- int trip, enum thermal_trip_type *type)
-{
- struct int3402_thermal_data *d = zone->devdata;
- int i;
-
- if (trip < d->aux_trip_nr)
- *type = THERMAL_TRIP_PASSIVE;
- else if (trip == d->crt_trip_id)
- *type = THERMAL_TRIP_CRITICAL;
- else if (trip == d->hot_trip_id)
- *type = THERMAL_TRIP_HOT;
- else if (trip == d->psv_trip_id)
- *type = THERMAL_TRIP_PASSIVE;
- else {
- for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
- if (d->act_trips[i].valid &&
- d->act_trips[i].id == trip) {
- *type = THERMAL_TRIP_ACTIVE;
- break;
- }
- }
- if (i == ACPI_ACTIVE_COOLING_MAX_NR)
- return -EINVAL;
- }
- return 0;
-}
-
-static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip,
- unsigned long temp)
-{
- struct int3402_thermal_data *d = zone->devdata;
- acpi_status status;
- char name[10];
-
- snprintf(name, sizeof(name), "PAT%d", trip);
- status = acpi_execute_simple_method(d->handle, name,
- MILLICELSIUS_TO_DECI_KELVIN(temp));
- if (ACPI_FAILURE(status))
- return -EIO;
-
- d->aux_trips[trip] = temp;
- return 0;
-}
-
-static struct thermal_zone_device_ops int3402_thermal_zone_ops = {
- .get_temp = int3402_thermal_get_zone_temp,
- .get_trip_temp = int3402_thermal_get_trip_temp,
- .get_trip_type = int3402_thermal_get_trip_type,
- .set_trip_temp = int3402_thermal_set_trip_temp,
-};
-
-static struct thermal_zone_params int3402_thermal_params = {
- .governor_name = "user_space",
- .no_hwmon = true,
-};
-
-static int int3402_thermal_get_temp(acpi_handle handle, char *name,
- unsigned long *temp)
-{
- unsigned long long r;
- acpi_status status;
-
- status = acpi_evaluate_integer(handle, name, NULL, &r);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- *temp = DECI_KELVIN_TO_MILLICELSIUS(r);
- return 0;
}
static int int3402_thermal_probe(struct platform_device *pdev)
{
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
struct int3402_thermal_data *d;
- struct thermal_zone_device *zone;
- acpi_status status;
- unsigned long long trip_cnt;
- int trip_mask = 0, i;
+ int ret;
if (!acpi_has_method(adev->handle, "_TMP"))
return -ENODEV;
@@ -168,54 +55,33 @@ static int int3402_thermal_probe(struct platform_device *pdev)
if (!d)
return -ENOMEM;
- status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
- if (ACPI_FAILURE(status))
- trip_cnt = 0;
- else {
- d->aux_trips = devm_kzalloc(&pdev->dev,
- sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL);
- if (!d->aux_trips)
- return -ENOMEM;
- trip_mask = trip_cnt - 1;
- d->handle = adev->handle;
- d->aux_trip_nr = trip_cnt;
- }
-
- d->crt_trip_id = -1;
- if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp))
- d->crt_trip_id = trip_cnt++;
- d->hot_trip_id = -1;
- if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp))
- d->hot_trip_id = trip_cnt++;
- d->psv_trip_id = -1;
- if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp))
- d->psv_trip_id = trip_cnt++;
- for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
- char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
- if (int3402_thermal_get_temp(adev->handle, name,
- &d->act_trips[i].temp))
- break;
- d->act_trips[i].id = trip_cnt++;
- d->act_trips[i].valid = true;
+ d->int340x_zone = int340x_thermal_zone_add(adev, NULL);
+ if (IS_ERR(d->int340x_zone))
+ return PTR_ERR(d->int340x_zone);
+
+ ret = acpi_install_notify_handler(adev->handle,
+ ACPI_DEVICE_NOTIFY,
+ int3402_notify,
+ d);
+ if (ret) {
+ int340x_thermal_zone_remove(d->int340x_zone);
+ return ret;
}
- zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt,
- trip_mask, d,
- &int3402_thermal_zone_ops,
- &int3402_thermal_params,
- 0, 0);
- if (IS_ERR(zone))
- return PTR_ERR(zone);
- platform_set_drvdata(pdev, zone);
+ d->handle = adev->handle;
+ platform_set_drvdata(pdev, d);
return 0;
}
static int int3402_thermal_remove(struct platform_device *pdev)
{
- struct thermal_zone_device *zone = platform_get_drvdata(pdev);
+ struct int3402_thermal_data *d = platform_get_drvdata(pdev);
+
+ acpi_remove_notify_handler(d->handle,
+ ACPI_DEVICE_NOTIFY, int3402_notify);
+ int340x_thermal_zone_remove(d->int340x_zone);
- thermal_zone_device_unregister(zone);
return 0;
}
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c
index 0faf500d8a77..50a7a08e3a15 100644
--- a/drivers/thermal/int340x_thermal/int3403_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3403_thermal.c
@@ -19,6 +19,7 @@
#include <linux/acpi.h>
#include <linux/thermal.h>
#include <linux/platform_device.h>
+#include "int340x_thermal_zone.h"
#define INT3403_TYPE_SENSOR 0x03
#define INT3403_TYPE_CHARGER 0x0B
@@ -26,18 +27,9 @@
#define INT3403_PERF_CHANGED_EVENT 0x80
#define INT3403_THERMAL_EVENT 0x90
-#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100)
-#define KELVIN_OFFSET 2732
-#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
-
+/* Preserved structure for future expandbility */
struct int3403_sensor {
- struct thermal_zone_device *tzone;
- unsigned long *thresholds;
- unsigned long crit_temp;
- int crit_trip_id;
- unsigned long psv_temp;
- int psv_trip_id;
-
+ struct int34x_thermal_zone *int340x_zone;
};
struct int3403_performance_state {
@@ -63,126 +55,6 @@ struct int3403_priv {
void *priv;
};
-static int sys_get_curr_temp(struct thermal_zone_device *tzone,
- unsigned long *temp)
-{
- struct int3403_priv *priv = tzone->devdata;
- struct acpi_device *device = priv->adev;
- unsigned long long tmp;
- acpi_status status;
-
- status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET);
-
- return 0;
-}
-
-static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
- int trip, unsigned long *temp)
-{
- struct int3403_priv *priv = tzone->devdata;
- struct acpi_device *device = priv->adev;
- unsigned long long hyst;
- acpi_status status;
-
- status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- /*
- * Thermal hysteresis represents a temperature difference.
- * Kelvin and Celsius have same degree size. So the
- * conversion here between tenths of degree Kelvin unit
- * and Milli-Celsius unit is just to multiply 100.
- */
- *temp = hyst * 100;
-
- return 0;
-}
-
-static int sys_get_trip_temp(struct thermal_zone_device *tzone,
- int trip, unsigned long *temp)
-{
- struct int3403_priv *priv = tzone->devdata;
- struct int3403_sensor *obj = priv->priv;
-
- if (priv->type != INT3403_TYPE_SENSOR || !obj)
- return -EINVAL;
-
- if (trip == obj->crit_trip_id)
- *temp = obj->crit_temp;
- else if (trip == obj->psv_trip_id)
- *temp = obj->psv_temp;
- else {
- /*
- * get_trip_temp is a mandatory callback but
- * PATx method doesn't return any value, so return
- * cached value, which was last set from user space
- */
- *temp = obj->thresholds[trip];
- }
-
- return 0;
-}
-
-static int sys_get_trip_type(struct thermal_zone_device *thermal,
- int trip, enum thermal_trip_type *type)
-{
- struct int3403_priv *priv = thermal->devdata;
- struct int3403_sensor *obj = priv->priv;
-
- /* Mandatory callback, may not mean much here */
- if (trip == obj->crit_trip_id)
- *type = THERMAL_TRIP_CRITICAL;
- else
- *type = THERMAL_TRIP_PASSIVE;
-
- return 0;
-}
-
-int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
- unsigned long temp)
-{
- struct int3403_priv *priv = tzone->devdata;
- struct acpi_device *device = priv->adev;
- struct int3403_sensor *obj = priv->priv;
- acpi_status status;
- char name[10];
- int ret = 0;
-
- snprintf(name, sizeof(name), "PAT%d", trip);
- if (acpi_has_method(device->handle, name)) {
- status = acpi_execute_simple_method(device->handle, name,
- MILLI_CELSIUS_TO_DECI_KELVIN(temp,
- KELVIN_OFFSET));
- if (ACPI_FAILURE(status))
- ret = -EIO;
- else
- obj->thresholds[trip] = temp;
- } else {
- ret = -EIO;
- dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
- }
-
- return ret;
-}
-
-static struct thermal_zone_device_ops tzone_ops = {
- .get_temp = sys_get_curr_temp,
- .get_trip_temp = sys_get_trip_temp,
- .get_trip_type = sys_get_trip_type,
- .set_trip_temp = sys_set_trip_temp,
- .get_trip_hyst = sys_get_trip_hyst,
-};
-
-static struct thermal_zone_params int3403_thermal_params = {
- .governor_name = "user_space",
- .no_hwmon = true,
-};
-
static void int3403_notify(acpi_handle handle,
u32 event, void *data)
{
@@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle,
case INT3403_PERF_CHANGED_EVENT:
break;
case INT3403_THERMAL_EVENT:
- thermal_zone_device_update(obj->tzone);
+ int340x_thermal_zone_device_update(obj->int340x_zone);
break;
default:
dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event);
@@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle,
}
}
-static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp)
-{
- unsigned long long crt;
- acpi_status status;
-
- status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET);
-
- return 0;
-}
-
-static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
-{
- unsigned long long psv;
- acpi_status status;
-
- status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv);
- if (ACPI_FAILURE(status))
- return -EIO;
-
- *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET);
-
- return 0;
-}
-
static int int3403_sensor_add(struct int3403_priv *priv)
{
int result = 0;
- acpi_status status;
struct int3403_sensor *obj;
- unsigned long long trip_cnt;
- int trip_mask = 0;
obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
if (!obj)
@@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv)
priv->priv = obj;
- status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL,
- &trip_cnt);
- if (ACPI_FAILURE(status))
- trip_cnt = 0;
-
- if (trip_cnt) {
- /* We have to cache, thresholds can't be readback */
- obj->thresholds = devm_kzalloc(&priv->pdev->dev,
- sizeof(*obj->thresholds) * trip_cnt,
- GFP_KERNEL);
- if (!obj->thresholds) {
- result = -ENOMEM;
- goto err_free_obj;
- }
- trip_mask = BIT(trip_cnt) - 1;
- }
-
- obj->psv_trip_id = -1;
- if (!sys_get_trip_psv(priv->adev, &obj->psv_temp))
- obj->psv_trip_id = trip_cnt++;
-
- obj->crit_trip_id = -1;
- if (!sys_get_trip_crt(priv->adev, &obj->crit_temp))
- obj->crit_trip_id = trip_cnt++;
-
- obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev),
- trip_cnt, trip_mask, priv, &tzone_ops,
- &int3403_thermal_params, 0, 0);
- if (IS_ERR(obj->tzone)) {
- result = PTR_ERR(obj->tzone);
- obj->tzone = NULL;
- goto err_free_obj;
- }
+ obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL);
+ if (IS_ERR(obj->int340x_zone))
+ return PTR_ERR(obj->int340x_zone);
result = acpi_install_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY, int3403_notify,
@@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv)
return 0;
err_free_obj:
- thermal_zone_device_unregister(obj->tzone);
+ int340x_thermal_zone_remove(obj->int340x_zone);
return result;
}
@@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv)
acpi_remove_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY, int3403_notify);
- thermal_zone_device_unregister(obj->tzone);
+ int340x_thermal_zone_remove(obj->int340x_zone);
+
return 0;
}
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
new file mode 100644
index 000000000000..f88b08877025
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
@@ -0,0 +1,276 @@
+/*
+ * int340x_thermal_zone.c
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/acpi.h>
+#include <linux/thermal.h>
+#include "int340x_thermal_zone.h"
+
+static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
+ unsigned long *temp)
+{
+ struct int34x_thermal_zone *d = zone->devdata;
+ unsigned long long tmp;
+ acpi_status status;
+
+ if (d->override_ops && d->override_ops->get_temp)
+ return d->override_ops->get_temp(zone, temp);
+
+ status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ if (d->lpat_table) {
+ int conv_temp;
+
+ conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
+ if (conv_temp < 0)
+ return conv_temp;
+
+ *temp = (unsigned long)conv_temp * 10;
+ } else
+ /* _TMP returns the temperature in tenths of degrees Kelvin */
+ *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
+
+ return 0;
+}
+
+static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
+ int trip, unsigned long *temp)
+{
+ struct int34x_thermal_zone *d = zone->devdata;
+ int i;
+
+ if (d->override_ops && d->override_ops->get_trip_temp)
+ return d->override_ops->get_trip_temp(zone, trip, temp);
+
+ if (trip < d->aux_trip_nr)
+ *temp = d->aux_trips[trip];
+ else if (trip == d->crt_trip_id)
+ *temp = d->crt_temp;
+ else if (trip == d->psv_trip_id)
+ *temp = d->psv_temp;
+ else if (trip == d->hot_trip_id)
+ *temp = d->hot_temp;
+ else {
+ for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
+ if (d->act_trips[i].valid &&
+ d->act_trips[i].id == trip) {
+ *temp = d->act_trips[i].temp;
+ break;
+ }
+ }
+ if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
+ int trip,
+ enum thermal_trip_type *type)
+{
+ struct int34x_thermal_zone *d = zone->devdata;
+ int i;
+
+ if (d->override_ops && d->override_ops->get_trip_type)
+ return d->override_ops->get_trip_type(zone, trip, type);
+
+ if (trip < d->aux_trip_nr)
+ *type = THERMAL_TRIP_PASSIVE;
+ else if (trip == d->crt_trip_id)
+ *type = THERMAL_TRIP_CRITICAL;
+ else if (trip == d->hot_trip_id)
+ *type = THERMAL_TRIP_HOT;
+ else if (trip == d->psv_trip_id)
+ *type = THERMAL_TRIP_PASSIVE;
+ else {
+ for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
+ if (d->act_trips[i].valid &&
+ d->act_trips[i].id == trip) {
+ *type = THERMAL_TRIP_ACTIVE;
+ break;
+ }
+ }
+ if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
+ int trip, unsigned long temp)
+{
+ struct int34x_thermal_zone *d = zone->devdata;
+ acpi_status status;
+ char name[10];
+
+ if (d->override_ops && d->override_ops->set_trip_temp)
+ return d->override_ops->set_trip_temp(zone, trip, temp);
+
+ snprintf(name, sizeof(name), "PAT%d", trip);
+ status = acpi_execute_simple_method(d->adev->handle, name,
+ MILLICELSIUS_TO_DECI_KELVIN(temp));
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ d->aux_trips[trip] = temp;
+
+ return 0;
+}
+
+
+static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
+ int trip, unsigned long *temp)
+{
+ struct int34x_thermal_zone *d = zone->devdata;
+ acpi_status status;
+ unsigned long long hyst;
+
+ if (d->override_ops && d->override_ops->get_trip_hyst)
+ return d->override_ops->get_trip_hyst(zone, trip, temp);
+
+ status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ *temp = hyst * 100;
+
+ return 0;
+}
+
+static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
+ .get_temp = int340x_thermal_get_zone_temp,
+ .get_trip_temp = int340x_thermal_get_trip_temp,
+ .get_trip_type = int340x_thermal_get_trip_type,
+ .set_trip_temp = int340x_thermal_set_trip_temp,
+ .get_trip_hyst = int340x_thermal_get_trip_hyst,
+};
+
+static int int340x_thermal_get_trip_config(acpi_handle handle, char *name,
+ unsigned long *temp)
+{
+ unsigned long long r;
+ acpi_status status;
+
+ status = acpi_evaluate_integer(handle, name, NULL, &r);
+ if (ACPI_FAILURE(status))
+ return -EIO;
+
+ *temp = DECI_KELVIN_TO_MILLICELSIUS(r);
+
+ return 0;
+}
+
+static struct thermal_zone_params int340x_thermal_params = {
+ .governor_name = "user_space",
+ .no_hwmon = true,
+};
+
+struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
+ struct thermal_zone_device_ops *override_ops)
+{
+ struct int34x_thermal_zone *int34x_thermal_zone;
+ acpi_status status;
+ unsigned long long trip_cnt;
+ int trip_mask = 0, i;
+ int ret;
+
+ int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone),
+ GFP_KERNEL);
+ if (!int34x_thermal_zone)
+ return ERR_PTR(-ENOMEM);
+
+ int34x_thermal_zone->adev = adev;
+ int34x_thermal_zone->override_ops = override_ops;
+
+ status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
+ if (ACPI_FAILURE(status))
+ trip_cnt = 0;
+ else {
+ int34x_thermal_zone->aux_trips = kzalloc(
+ sizeof(*int34x_thermal_zone->aux_trips) *
+ trip_cnt, GFP_KERNEL);
+ if (!int34x_thermal_zone->aux_trips) {
+ ret = -ENOMEM;
+ goto free_mem;
+ }
+ trip_mask = BIT(trip_cnt) - 1;
+ int34x_thermal_zone->aux_trip_nr = trip_cnt;
+ }
+
+ int34x_thermal_zone->crt_trip_id = -1;
+ if (!int340x_thermal_get_trip_config(adev->handle, "_CRT",
+ &int34x_thermal_zone->crt_temp))
+ int34x_thermal_zone->crt_trip_id = trip_cnt++;
+ int34x_thermal_zone->hot_trip_id = -1;
+ if (!int340x_thermal_get_trip_config(adev->handle, "_HOT",
+ &int34x_thermal_zone->hot_temp))
+ int34x_thermal_zone->hot_trip_id = trip_cnt++;
+ int34x_thermal_zone->psv_trip_id = -1;
+ if (!int340x_thermal_get_trip_config(adev->handle, "_PSV",
+ &int34x_thermal_zone->psv_temp))
+ int34x_thermal_zone->psv_trip_id = trip_cnt++;
+ for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
+ char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
+
+ if (int340x_thermal_get_trip_config(adev->handle, name,
+ &int34x_thermal_zone->act_trips[i].temp))
+ break;
+
+ int34x_thermal_zone->act_trips[i].id = trip_cnt++;
+ int34x_thermal_zone->act_trips[i].valid = true;
+ }
+ int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table(
+ adev->handle);
+
+ int34x_thermal_zone->zone = thermal_zone_device_register(
+ acpi_device_bid(adev),
+ trip_cnt,
+ trip_mask, int34x_thermal_zone,
+ &int340x_thermal_zone_ops,
+ &int340x_thermal_params,
+ 0, 0);
+ if (IS_ERR(int34x_thermal_zone->zone)) {
+ ret = PTR_ERR(int34x_thermal_zone->zone);
+ goto free_lpat;
+ }
+
+ return int34x_thermal_zone;
+
+free_lpat:
+ acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
+free_mem:
+ kfree(int34x_thermal_zone);
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
+
+void int340x_thermal_zone_remove(struct int34x_thermal_zone
+ *int34x_thermal_zone)
+{
+ thermal_zone_device_unregister(int34x_thermal_zone->zone);
+ acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
+ kfree(int34x_thermal_zone);
+}
+EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
+
+MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
+MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
new file mode 100644
index 000000000000..9f38ab72c4bf
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
@@ -0,0 +1,68 @@
+/*
+ * int340x_thermal_zone.h
+ * Copyright (c) 2015, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __INT340X_THERMAL_ZONE_H__
+#define __INT340X_THERMAL_ZONE_H__
+
+#include <acpi/acpi_lpat.h>
+
+#define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10
+
+struct active_trip {
+ unsigned long temp;
+ int id;
+ bool valid;
+};
+
+struct int34x_thermal_zone {
+ struct acpi_device *adev;
+ struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT];
+ unsigned long *aux_trips;
+ int aux_trip_nr;
+ unsigned long psv_temp;
+ int psv_trip_id;
+ unsigned long crt_temp;
+ int crt_trip_id;
+ unsigned long hot_temp;
+ int hot_trip_id;
+ struct thermal_zone_device *zone;
+ struct thermal_zone_device_ops *override_ops;
+ void *priv_data;
+ struct acpi_lpat_conversion_table *lpat_table;
+};
+
+struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,
+ struct thermal_zone_device_ops *override_ops);
+void int340x_thermal_zone_remove(struct int34x_thermal_zone *);
+
+static inline void int340x_thermal_zone_set_priv_data(
+ struct int34x_thermal_zone *tzone, void *priv_data)
+{
+ tzone->priv_data = priv_data;
+}
+
+static inline void *int340x_thermal_zone_get_priv_data(
+ struct int34x_thermal_zone *tzone)
+{
+ return tzone->priv_data;
+}
+
+static inline void int340x_thermal_zone_device_update(
+ struct int34x_thermal_zone *tzone)
+{
+ thermal_zone_device_update(tzone->zone);
+}
+
+#endif
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
index 0fe5dbbea968..5e8d8e91ea6d 100644
--- a/drivers/thermal/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c
@@ -18,6 +18,8 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
#include <linux/acpi.h>
+#include <linux/thermal.h>
+#include "int340x_thermal_zone.h"
/* Broadwell-U/HSB thermal reporting device */
#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603
@@ -39,6 +41,7 @@ struct proc_thermal_device {
struct device *dev;
struct acpi_device *adev;
struct power_config power_limits[2];
+ struct int34x_thermal_zone *int340x_zone;
};
enum proc_thermal_emum_mode_type {
@@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = {
.name = "power_limits"
};
+static int stored_tjmax; /* since it is fixed, we can have local storage */
+
+static int get_tjmax(void)
+{
+ u32 eax, edx;
+ u32 val;
+ int err;
+
+ err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
+ if (err)
+ return err;
+
+ val = (eax >> 16) & 0xff;
+ if (val)
+ return val;
+
+ return -EINVAL;
+}
+
+static int read_temp_msr(unsigned long *temp)
+{
+ int cpu;
+ u32 eax, edx;
+ int err;
+ unsigned long curr_temp_off = 0;
+
+ *temp = 0;
+
+ for_each_online_cpu(cpu) {
+ err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax,
+ &edx);
+ if (err)
+ goto err_ret;
+ else {
+ if (eax & 0x80000000) {
+ curr_temp_off = (eax >> 16) & 0x7f;
+ if (!*temp || curr_temp_off < *temp)
+ *temp = curr_temp_off;
+ } else {
+ err = -EINVAL;
+ goto err_ret;
+ }
+ }
+ }
+
+ return 0;
+err_ret:
+ return err;
+}
+
+static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,
+ unsigned long *temp)
+{
+ int ret;
+
+ ret = read_temp_msr(temp);
+ if (!ret)
+ *temp = (stored_tjmax - *temp) * 1000;
+
+ return ret;
+}
+
+static struct thermal_zone_device_ops proc_thermal_local_ops = {
+ .get_temp = proc_thermal_get_zone_temp,
+};
+
static int proc_thermal_add(struct device *dev,
struct proc_thermal_device **priv)
{
@@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev,
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *elements, *ppcc;
union acpi_object *p;
+ unsigned long long tmp;
+ struct thermal_zone_device_ops *ops = NULL;
int i;
int ret;
@@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev,
ret = sysfs_create_group(&dev->kobj,
&power_limit_attribute_group);
+ if (ret)
+ goto free_buffer;
+
+ status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);
+ if (ACPI_FAILURE(status)) {
+ /* there is no _TMP method, add local method */
+ stored_tjmax = get_tjmax();
+ if (stored_tjmax > 0)
+ ops = &proc_thermal_local_ops;
+ }
+
+ proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops);
+ if (IS_ERR(proc_priv->int340x_zone)) {
+ sysfs_remove_group(&proc_priv->dev->kobj,
+ &power_limit_attribute_group);
+ ret = PTR_ERR(proc_priv->int340x_zone);
+ } else
+ ret = 0;
free_buffer:
kfree(buf.pointer);
@@ -185,8 +274,9 @@ free_buffer:
return ret;
}
-void proc_thermal_remove(struct proc_thermal_device *proc_priv)
+static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
{
+ int340x_thermal_zone_remove(proc_priv->int340x_zone);
sysfs_remove_group(&proc_priv->dev->kobj,
&power_limit_attribute_group);
}
diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c
index 5580f5b24eb9..9013505e43b7 100644
--- a/drivers/thermal/intel_soc_dts_thermal.c
+++ b/drivers/thermal/intel_soc_dts_thermal.c
@@ -309,10 +309,13 @@ static int soc_dts_enable(int id)
return ret;
}
-static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max)
+static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max,
+ bool notification_support)
{
struct soc_sensor_entry *aux_entry;
char name[10];
+ int trip_count = 0;
+ int trip_mask = 0;
int err;
aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL);
@@ -332,11 +335,16 @@ static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max)
aux_entry->tj_max = tj_max;
aux_entry->temp_mask = 0x00FF << (id * 8);
aux_entry->temp_shift = id * 8;
+ if (notification_support) {
+ trip_count = SOC_MAX_DTS_TRIPS;
+ trip_mask = 0x02;
+ }
snprintf(name, sizeof(name), "soc_dts%d", id);
aux_entry->tzone = thermal_zone_device_register(name,
- SOC_MAX_DTS_TRIPS,
- 0x02,
- aux_entry, &tzone_ops, NULL, 0, 0);
+ trip_count,
+ trip_mask,
+ aux_entry, &tzone_ops,
+ NULL, 0, 0);
if (IS_ERR(aux_entry->tzone)) {
err = PTR_ERR(aux_entry->tzone);
goto err_ret;
@@ -402,6 +410,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data)
static const struct x86_cpu_id soc_thermal_ids[] = {
{ X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ},
+ { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x4c, 0, 0},
{}
};
MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids);
@@ -420,8 +429,11 @@ static int __init intel_soc_thermal_init(void)
if (get_tj_max(&tj_max))
return -EINVAL;
+ soc_dts_thres_irq = (int)match_cpu->driver_data;
+
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
- soc_dts[i] = alloc_soc_dts(i, tj_max);
+ soc_dts[i] = alloc_soc_dts(i, tj_max,
+ soc_dts_thres_irq ? true : false);
if (IS_ERR(soc_dts[i])) {
err = PTR_ERR(soc_dts[i]);
goto err_free;
@@ -430,15 +442,15 @@ static int __init intel_soc_thermal_init(void)
spin_lock_init(&intr_notify_lock);
- soc_dts_thres_irq = (int)match_cpu->driver_data;
-
- err = request_threaded_irq(soc_dts_thres_irq, NULL,
- soc_irq_thread_fn,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT,
- "soc_dts", soc_dts);
- if (err) {
- pr_err("request_threaded_irq ret %d\n", err);
- goto err_free;
+ if (soc_dts_thres_irq) {
+ err = request_threaded_irq(soc_dts_thres_irq, NULL,
+ soc_irq_thread_fn,
+ IRQF_TRIGGER_RISING | IRQF_ONESHOT,
+ "soc_dts", soc_dts);
+ if (err) {
+ pr_err("request_threaded_irq ret %d\n", err);
+ goto err_free;
+ }
}
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
@@ -451,7 +463,8 @@ static int __init intel_soc_thermal_init(void)
err_trip_temp:
i = SOC_MAX_DTS_SENSORS;
- free_irq(soc_dts_thres_irq, soc_dts);
+ if (soc_dts_thres_irq)
+ free_irq(soc_dts_thres_irq, soc_dts);
err_free:
while (--i >= 0)
free_soc_dts(soc_dts[i]);
@@ -466,7 +479,8 @@ static void __exit intel_soc_thermal_exit(void)
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
update_trip_temp(soc_dts[i], 0, 0);
- free_irq(soc_dts_thres_irq, soc_dts);
+ if (soc_dts_thres_irq)
+ free_irq(soc_dts_thres_irq, soc_dts);
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
free_soc_dts(soc_dts[i]);
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index d717f3dab6f1..668fb1bdea9e 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -497,6 +497,9 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id, void *data,
if (sensor_specs.np == sensor_np && id == sensor_id) {
tzd = thermal_zone_of_add_sensor(child, sensor_np,
data, ops);
+ if (!IS_ERR(tzd))
+ tzd->ops->set_mode(tzd, THERMAL_DEVICE_ENABLED);
+
of_node_put(sensor_specs.np);
of_node_put(child);
goto exit;
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 9c6ce548e363..3aa46ac7cdbc 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -193,19 +193,20 @@ static u32 rk_tsadcv2_temp_to_code(long temp)
static long rk_tsadcv2_code_to_temp(u32 code)
{
- int high, low, mid;
-
- low = 0;
- high = ARRAY_SIZE(v2_code_table) - 1;
- mid = (high + low) / 2;
-
- if (code > v2_code_table[low].code || code < v2_code_table[high].code)
- return 125000; /* No code available, return max temperature */
+ unsigned int low = 0;
+ unsigned int high = ARRAY_SIZE(v2_code_table) - 1;
+ unsigned int mid = (low + high) / 2;
+ unsigned int num;
+ unsigned long denom;
+
+ /* Invalid code, return -EAGAIN */
+ if (code > TSADCV2_DATA_MASK)
+ return -EAGAIN;
- while (low <= high) {
- if (code >= v2_code_table[mid].code && code <
- v2_code_table[mid - 1].code)
- return v2_code_table[mid].temp;
+ while (low <= high && mid) {
+ if (code >= v2_code_table[mid].code &&
+ code < v2_code_table[mid - 1].code)
+ break;
else if (code < v2_code_table[mid].code)
low = mid + 1;
else
@@ -213,7 +214,16 @@ static long rk_tsadcv2_code_to_temp(u32 code)
mid = (low + high) / 2;
}
- return 125000;
+ /*
+ * The 5C granularity provided by the table is too much. Let's
+ * assume that the relationship between sensor readings and
+ * temperature between 2 table entries is linear and interpolate
+ * to produce less granular result.
+ */
+ num = v2_code_table[mid].temp - v2_code_table[mid - 1].temp;
+ num *= v2_code_table[mid - 1].code - code;
+ denom = v2_code_table[mid - 1].code - v2_code_table[mid].code;
+ return v2_code_table[mid - 1].temp + (num / denom);
}
/**
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig
index c43306ecc0ab..c8e35c1a43dc 100644
--- a/drivers/thermal/samsung/Kconfig
+++ b/drivers/thermal/samsung/Kconfig
@@ -7,12 +7,3 @@ config EXYNOS_THERMAL
the TMU, reports temperature and handles cooling action if defined.
This driver uses the Exynos core thermal APIs and TMU configuration
data from the supported SoCs.
-
-config EXYNOS_THERMAL_CORE
- bool "Core thermal framework support for EXYNOS SOCs"
- depends on EXYNOS_THERMAL
- help
- If you say yes here you get support for EXYNOS TMU
- (Thermal Management Unit) common registration/unregistration
- functions to the core thermal layer and also to use the generic
- CPU cooling APIs.
diff --git a/drivers/thermal/samsung/Makefile b/drivers/thermal/samsung/Makefile
index c09d83095dc2..1e47d0d89ce0 100644
--- a/drivers/thermal/samsung/Makefile
+++ b/drivers/thermal/samsung/Makefile
@@ -3,5 +3,3 @@
#
obj-$(CONFIG_EXYNOS_THERMAL) += exynos_thermal.o
exynos_thermal-y := exynos_tmu.o
-exynos_thermal-y += exynos_tmu_data.o
-exynos_thermal-$(CONFIG_EXYNOS_THERMAL_CORE) += exynos_thermal_common.o
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c
deleted file mode 100644
index 6dc3815cc73f..000000000000
--- a/drivers/thermal/samsung/exynos_thermal_common.c
+++ /dev/null
@@ -1,427 +0,0 @@
-/*
- * exynos_thermal_common.c - Samsung EXYNOS common thermal file
- *
- * Copyright (C) 2013 Samsung Electronics
- * Amit Daniel Kachhap <amit.daniel@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.
- *
- * 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/cpu_cooling.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-#include <linux/thermal.h>
-
-#include "exynos_thermal_common.h"
-
-struct exynos_thermal_zone {
- enum thermal_device_mode mode;
- struct thermal_zone_device *therm_dev;
- struct thermal_cooling_device *cool_dev[MAX_COOLING_DEVICE];
- unsigned int cool_dev_size;
- struct platform_device *exynos4_dev;
- struct thermal_sensor_conf *sensor_conf;
- bool bind;
-};
-
-/* Get mode callback functions for thermal zone */
-static int exynos_get_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode *mode)
-{
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- if (th_zone)
- *mode = th_zone->mode;
- return 0;
-}
-
-/* Set mode callback functions for thermal zone */
-static int exynos_set_mode(struct thermal_zone_device *thermal,
- enum thermal_device_mode mode)
-{
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- if (!th_zone) {
- dev_err(&thermal->device,
- "thermal zone not registered\n");
- return 0;
- }
-
- mutex_lock(&thermal->lock);
-
- if (mode == THERMAL_DEVICE_ENABLED &&
- !th_zone->sensor_conf->trip_data.trigger_falling)
- thermal->polling_delay = IDLE_INTERVAL;
- else
- thermal->polling_delay = 0;
-
- mutex_unlock(&thermal->lock);
-
- th_zone->mode = mode;
- thermal_zone_device_update(thermal);
- dev_dbg(th_zone->sensor_conf->dev,
- "thermal polling set for duration=%d msec\n",
- thermal->polling_delay);
- return 0;
-}
-
-
-/* Get trip type callback functions for thermal zone */
-static int exynos_get_trip_type(struct thermal_zone_device *thermal, int trip,
- enum thermal_trip_type *type)
-{
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- int max_trip = th_zone->sensor_conf->trip_data.trip_count;
- int trip_type;
-
- if (trip < 0 || trip >= max_trip)
- return -EINVAL;
-
- trip_type = th_zone->sensor_conf->trip_data.trip_type[trip];
-
- if (trip_type == SW_TRIP)
- *type = THERMAL_TRIP_CRITICAL;
- else if (trip_type == THROTTLE_ACTIVE)
- *type = THERMAL_TRIP_ACTIVE;
- else if (trip_type == THROTTLE_PASSIVE)
- *type = THERMAL_TRIP_PASSIVE;
- else
- return -EINVAL;
-
- return 0;
-}
-
-/* Get trip temperature callback functions for thermal zone */
-static int exynos_get_trip_temp(struct thermal_zone_device *thermal, int trip,
- unsigned long *temp)
-{
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- int max_trip = th_zone->sensor_conf->trip_data.trip_count;
-
- if (trip < 0 || trip >= max_trip)
- return -EINVAL;
-
- *temp = th_zone->sensor_conf->trip_data.trip_val[trip];
- /* convert the temperature into millicelsius */
- *temp = *temp * MCELSIUS;
-
- return 0;
-}
-
-/* Get critical temperature callback functions for thermal zone */
-static int exynos_get_crit_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- int max_trip = th_zone->sensor_conf->trip_data.trip_count;
- /* Get the temp of highest trip*/
- return exynos_get_trip_temp(thermal, max_trip - 1, temp);
-}
-
-/* Bind callback functions for thermal zone */
-static int exynos_bind(struct thermal_zone_device *thermal,
- struct thermal_cooling_device *cdev)
-{
- int ret = 0, i, tab_size, level;
- struct freq_clip_table *tab_ptr, *clip_data;
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- struct thermal_sensor_conf *data = th_zone->sensor_conf;
-
- tab_ptr = (struct freq_clip_table *)data->cooling_data.freq_data;
- tab_size = data->cooling_data.freq_clip_count;
-
- if (tab_ptr == NULL || tab_size == 0)
- return 0;
-
- /* find the cooling device registered*/
- for (i = 0; i < th_zone->cool_dev_size; i++)
- if (cdev == th_zone->cool_dev[i])
- break;
-
- /* No matching cooling device */
- if (i == th_zone->cool_dev_size)
- return 0;
-
- /* Bind the thermal zone to the cpufreq cooling device */
- for (i = 0; i < tab_size; i++) {
- clip_data = (struct freq_clip_table *)&(tab_ptr[i]);
- level = cpufreq_cooling_get_level(0, clip_data->freq_clip_max);
- if (level == THERMAL_CSTATE_INVALID)
- return 0;
- switch (GET_ZONE(i)) {
- case MONITOR_ZONE:
- case WARN_ZONE:
- if (thermal_zone_bind_cooling_device(thermal, i, cdev,
- level, 0)) {
- dev_err(data->dev,
- "error unbinding cdev inst=%d\n", i);
- ret = -EINVAL;
- }
- th_zone->bind = true;
- break;
- default:
- ret = -EINVAL;
- }
- }
-
- return ret;
-}
-
-/* Unbind callback functions for thermal zone */
-static int exynos_unbind(struct thermal_zone_device *thermal,
- struct thermal_cooling_device *cdev)
-{
- int ret = 0, i, tab_size;
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- struct thermal_sensor_conf *data = th_zone->sensor_conf;
-
- if (th_zone->bind == false)
- return 0;
-
- tab_size = data->cooling_data.freq_clip_count;
-
- if (tab_size == 0)
- return 0;
-
- /* find the cooling device registered*/
- for (i = 0; i < th_zone->cool_dev_size; i++)
- if (cdev == th_zone->cool_dev[i])
- break;
-
- /* No matching cooling device */
- if (i == th_zone->cool_dev_size)
- return 0;
-
- /* Bind the thermal zone to the cpufreq cooling device */
- for (i = 0; i < tab_size; i++) {
- switch (GET_ZONE(i)) {
- case MONITOR_ZONE:
- case WARN_ZONE:
- if (thermal_zone_unbind_cooling_device(thermal, i,
- cdev)) {
- dev_err(data->dev,
- "error unbinding cdev inst=%d\n", i);
- ret = -EINVAL;
- }
- th_zone->bind = false;
- break;
- default:
- ret = -EINVAL;
- }
- }
- return ret;
-}
-
-/* Get temperature callback functions for thermal zone */
-static int exynos_get_temp(struct thermal_zone_device *thermal,
- unsigned long *temp)
-{
- struct exynos_thermal_zone *th_zone = thermal->devdata;
- void *data;
-
- if (!th_zone->sensor_conf) {
- dev_err(&thermal->device,
- "Temperature sensor not initialised\n");
- return -EINVAL;
- }
- data = th_zone->sensor_conf->driver_data;
- *temp = th_zone->sensor_conf->read_temperature(data);
- /* convert the temperature into millicelsius */
- *temp = *temp * MCELSIUS;
- return 0;
-}
-
-/* Get temperature callback functions for thermal zone */
-static int exynos_set_emul_temp(struct thermal_zone_device *thermal,
- unsigned long temp)
-{
- void *data;
- int ret = -EINVAL;
- struct exynos_thermal_zone *th_zone = thermal->devdata;
-
- if (!th_zone->sensor_conf) {
- dev_err(&thermal->device,
- "Temperature sensor not initialised\n");
- return -EINVAL;
- }
- data = th_zone->sensor_conf->driver_data;
- if (th_zone->sensor_conf->write_emul_temp)
- ret = th_zone->sensor_conf->write_emul_temp(data, temp);
- return ret;
-}
-
-/* Get the temperature trend */
-static int exynos_get_trend(struct thermal_zone_device *thermal,
- int trip, enum thermal_trend *trend)
-{
- int ret;
- unsigned long trip_temp;
-
- ret = exynos_get_trip_temp(thermal, trip, &trip_temp);
- if (ret < 0)
- return ret;
-
- if (thermal->temperature >= trip_temp)
- *trend = THERMAL_TREND_RAISE_FULL;
- else
- *trend = THERMAL_TREND_DROP_FULL;
-
- return 0;
-}
-/* Operation callback functions for thermal zone */
-static struct thermal_zone_device_ops exynos_dev_ops = {
- .bind = exynos_bind,
- .unbind = exynos_unbind,
- .get_temp = exynos_get_temp,
- .set_emul_temp = exynos_set_emul_temp,
- .get_trend = exynos_get_trend,
- .get_mode = exynos_get_mode,
- .set_mode = exynos_set_mode,
- .get_trip_type = exynos_get_trip_type,
- .get_trip_temp = exynos_get_trip_temp,
- .get_crit_temp = exynos_get_crit_temp,
-};
-
-/*
- * This function may be called from interrupt based temperature sensor
- * when threshold is changed.
- */
-void exynos_report_trigger(struct thermal_sensor_conf *conf)
-{
- unsigned int i;
- char data[10];
- char *envp[] = { data, NULL };
- struct exynos_thermal_zone *th_zone;
-
- if (!conf || !conf->pzone_data) {
- pr_err("Invalid temperature sensor configuration data\n");
- return;
- }
-
- th_zone = conf->pzone_data;
-
- if (th_zone->bind == false) {
- for (i = 0; i < th_zone->cool_dev_size; i++) {
- if (!th_zone->cool_dev[i])
- continue;
- exynos_bind(th_zone->therm_dev,
- th_zone->cool_dev[i]);
- }
- }
-
- thermal_zone_device_update(th_zone->therm_dev);
-
- mutex_lock(&th_zone->therm_dev->lock);
- /* Find the level for which trip happened */
- for (i = 0; i < th_zone->sensor_conf->trip_data.trip_count; i++) {
- if (th_zone->therm_dev->last_temperature <
- th_zone->sensor_conf->trip_data.trip_val[i] * MCELSIUS)
- break;
- }
-
- if (th_zone->mode == THERMAL_DEVICE_ENABLED &&
- !th_zone->sensor_conf->trip_data.trigger_falling) {
- if (i > 0)
- th_zone->therm_dev->polling_delay = ACTIVE_INTERVAL;
- else
- th_zone->therm_dev->polling_delay = IDLE_INTERVAL;
- }
-
- snprintf(data, sizeof(data), "%u", i);
- kobject_uevent_env(&th_zone->therm_dev->device.kobj, KOBJ_CHANGE, envp);
- mutex_unlock(&th_zone->therm_dev->lock);
-}
-
-/* Register with the in-kernel thermal management */
-int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf)
-{
- int ret;
- struct exynos_thermal_zone *th_zone;
-
- if (!sensor_conf || !sensor_conf->read_temperature) {
- pr_err("Temperature sensor not initialised\n");
- return -EINVAL;
- }
-
- th_zone = devm_kzalloc(sensor_conf->dev,
- sizeof(struct exynos_thermal_zone), GFP_KERNEL);
- if (!th_zone)
- return -ENOMEM;
-
- th_zone->sensor_conf = sensor_conf;
- /*
- * TODO: 1) Handle multiple cooling devices in a thermal zone
- * 2) Add a flag/name in cooling info to map to specific
- * sensor
- */
- if (sensor_conf->cooling_data.freq_clip_count > 0) {
- th_zone->cool_dev[th_zone->cool_dev_size] =
- cpufreq_cooling_register(cpu_present_mask);
- if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) {
- ret = PTR_ERR(th_zone->cool_dev[th_zone->cool_dev_size]);
- if (ret != -EPROBE_DEFER)
- dev_err(sensor_conf->dev,
- "Failed to register cpufreq cooling device: %d\n",
- ret);
- goto err_unregister;
- }
- th_zone->cool_dev_size++;
- }
-
- th_zone->therm_dev = thermal_zone_device_register(
- sensor_conf->name, sensor_conf->trip_data.trip_count,
- 0, th_zone, &exynos_dev_ops, NULL, 0,
- sensor_conf->trip_data.trigger_falling ? 0 :
- IDLE_INTERVAL);
-
- if (IS_ERR(th_zone->therm_dev)) {
- dev_err(sensor_conf->dev,
- "Failed to register thermal zone device\n");
- ret = PTR_ERR(th_zone->therm_dev);
- goto err_unregister;
- }
- th_zone->mode = THERMAL_DEVICE_ENABLED;
- sensor_conf->pzone_data = th_zone;
-
- dev_info(sensor_conf->dev,
- "Exynos: Thermal zone(%s) registered\n", sensor_conf->name);
-
- return 0;
-
-err_unregister:
- exynos_unregister_thermal(sensor_conf);
- return ret;
-}
-
-/* Un-Register with the in-kernel thermal management */
-void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf)
-{
- int i;
- struct exynos_thermal_zone *th_zone;
-
- if (!sensor_conf || !sensor_conf->pzone_data) {
- pr_err("Invalid temperature sensor configuration data\n");
- return;
- }
-
- th_zone = sensor_conf->pzone_data;
-
- thermal_zone_device_unregister(th_zone->therm_dev);
-
- for (i = 0; i < th_zone->cool_dev_size; ++i)
- cpufreq_cooling_unregister(th_zone->cool_dev[i]);
-
- dev_info(sensor_conf->dev,
- "Exynos: Kernel Thermal management unregistered\n");
-}
diff --git a/drivers/thermal/samsung/exynos_thermal_common.h b/drivers/thermal/samsung/exynos_thermal_common.h
deleted file mode 100644
index cd4471925cdd..000000000000
--- a/drivers/thermal/samsung/exynos_thermal_common.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * exynos_thermal_common.h - Samsung EXYNOS common header file
- *
- * Copyright (C) 2013 Samsung Electronics
- * Amit Daniel Kachhap <amit.daniel@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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#ifndef _EXYNOS_THERMAL_COMMON_H
-#define _EXYNOS_THERMAL_COMMON_H
-
-/* In-kernel thermal framework related macros & definations */
-#define SENSOR_NAME_LEN 16
-#define MAX_TRIP_COUNT 8
-#define MAX_COOLING_DEVICE 4
-
-#define ACTIVE_INTERVAL 500
-#define IDLE_INTERVAL 10000
-#define MCELSIUS 1000
-
-/* CPU Zone information */
-#define PANIC_ZONE 4
-#define WARN_ZONE 3
-#define MONITOR_ZONE 2
-#define SAFE_ZONE 1
-
-#define GET_ZONE(trip) (trip + 2)
-#define GET_TRIP(zone) (zone - 2)
-
-enum trigger_type {
- THROTTLE_ACTIVE = 1,
- THROTTLE_PASSIVE,
- SW_TRIP,
- HW_TRIP,
-};
-
-/**
- * struct freq_clip_table
- * @freq_clip_max: maximum frequency allowed for this cooling state.
- * @temp_level: Temperature level at which the temperature clipping will
- * happen.
- * @mask_val: cpumask of the allowed cpu's where the clipping will take place.
- *
- * This structure is required to be filled and passed to the
- * cpufreq_cooling_unregister function.
- */
-struct freq_clip_table {
- unsigned int freq_clip_max;
- unsigned int temp_level;
- const struct cpumask *mask_val;
-};
-
-struct thermal_trip_point_conf {
- int trip_val[MAX_TRIP_COUNT];
- int trip_type[MAX_TRIP_COUNT];
- int trip_count;
- unsigned char trigger_falling;
-};
-
-struct thermal_cooling_conf {
- struct freq_clip_table freq_data[MAX_TRIP_COUNT];
- int freq_clip_count;
-};
-
-struct thermal_sensor_conf {
- char name[SENSOR_NAME_LEN];
- int (*read_temperature)(void *data);
- int (*write_emul_temp)(void *drv_data, unsigned long temp);
- struct thermal_trip_point_conf trip_data;
- struct thermal_cooling_conf cooling_data;
- void *driver_data;
- void *pzone_data;
- struct device *dev;
-};
-
-/*Functions used exynos based thermal sensor driver*/
-#ifdef CONFIG_EXYNOS_THERMAL_CORE
-void exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf);
-int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf);
-void exynos_report_trigger(struct thermal_sensor_conf *sensor_conf);
-#else
-static inline void
-exynos_unregister_thermal(struct thermal_sensor_conf *sensor_conf) { return; }
-
-static inline int
-exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) { return 0; }
-
-static inline void
-exynos_report_trigger(struct thermal_sensor_conf *sensor_conf) { return; }
-
-#endif /* CONFIG_EXYNOS_THERMAL_CORE */
-#endif /* _EXYNOS_THERMAL_COMMON_H */
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c
index d2f1e62a4232..933cd80a6bc5 100644
--- a/drivers/thermal/samsung/exynos_tmu.c
+++ b/drivers/thermal/samsung/exynos_tmu.c
@@ -1,6 +1,10 @@
/*
* exynos_tmu.c - Samsung EXYNOS TMU (Thermal Management Unit)
*
+ * Copyright (C) 2014 Samsung Electronics
+ * Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+ * Lukasz Majewski <l.majewski@samsung.com>
+ *
* Copyright (C) 2011 Samsung Electronics
* Donggeun Kim <dg77.kim@samsung.com>
* Amit Daniel Kachhap <amit.kachhap@linaro.org>
@@ -31,8 +35,8 @@
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
-#include "exynos_thermal_common.h"
#include "exynos_tmu.h"
+#include "../thermal_core.h"
/* Exynos generic registers */
#define EXYNOS_TMU_REG_TRIMINFO 0x0
@@ -115,6 +119,27 @@
#define EXYNOS5440_TMU_TH_RISE4_SHIFT 24
#define EXYNOS5440_EFUSE_SWAP_OFFSET 8
+/* Exynos7 specific registers */
+#define EXYNOS7_THD_TEMP_RISE7_6 0x50
+#define EXYNOS7_THD_TEMP_FALL7_6 0x60
+#define EXYNOS7_TMU_REG_INTEN 0x110
+#define EXYNOS7_TMU_REG_INTPEND 0x118
+#define EXYNOS7_TMU_REG_EMUL_CON 0x160
+
+#define EXYNOS7_TMU_TEMP_MASK 0x1ff
+#define EXYNOS7_PD_DET_EN_SHIFT 23
+#define EXYNOS7_TMU_INTEN_RISE0_SHIFT 0
+#define EXYNOS7_TMU_INTEN_RISE1_SHIFT 1
+#define EXYNOS7_TMU_INTEN_RISE2_SHIFT 2
+#define EXYNOS7_TMU_INTEN_RISE3_SHIFT 3
+#define EXYNOS7_TMU_INTEN_RISE4_SHIFT 4
+#define EXYNOS7_TMU_INTEN_RISE5_SHIFT 5
+#define EXYNOS7_TMU_INTEN_RISE6_SHIFT 6
+#define EXYNOS7_TMU_INTEN_RISE7_SHIFT 7
+#define EXYNOS7_EMUL_DATA_SHIFT 7
+#define EXYNOS7_EMUL_DATA_MASK 0x1ff
+
+#define MCELSIUS 1000
/**
* struct exynos_tmu_data : A structure to hold the private data of the TMU
driver
@@ -128,6 +153,7 @@
* @lock: lock to implement synchronization.
* @clk: pointer to the clock structure.
* @clk_sec: pointer to the clock structure for accessing the base_second.
+ * @sclk: pointer to the clock structure for accessing the tmu special clk.
* @temp_error1: fused value of the first point trim.
* @temp_error2: fused value of the second point trim.
* @regulator: pointer to the TMU regulator structure.
@@ -147,10 +173,11 @@ struct exynos_tmu_data {
enum soc_type soc;
struct work_struct irq_work;
struct mutex lock;
- struct clk *clk, *clk_sec;
- u8 temp_error1, temp_error2;
+ struct clk *clk, *clk_sec, *sclk;
+ u16 temp_error1, temp_error2;
struct regulator *regulator;
- struct thermal_sensor_conf *reg_conf;
+ struct thermal_zone_device *tzd;
+
int (*tmu_initialize)(struct platform_device *pdev);
void (*tmu_control)(struct platform_device *pdev, bool on);
int (*tmu_read)(struct exynos_tmu_data *data);
@@ -159,6 +186,33 @@ struct exynos_tmu_data {
void (*tmu_clear_irqs)(struct exynos_tmu_data *data);
};
+static void exynos_report_trigger(struct exynos_tmu_data *p)
+{
+ char data[10], *envp[] = { data, NULL };
+ struct thermal_zone_device *tz = p->tzd;
+ unsigned long temp;
+ unsigned int i;
+
+ if (!tz) {
+ pr_err("No thermal zone device defined\n");
+ return;
+ }
+
+ thermal_zone_device_update(tz);
+
+ mutex_lock(&tz->lock);
+ /* Find the level for which trip happened */
+ for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
+ tz->ops->get_trip_temp(tz, i, &temp);
+ if (tz->last_temperature < temp)
+ break;
+ }
+
+ snprintf(data, sizeof(data), "%u", i);
+ kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, envp);
+ mutex_unlock(&tz->lock);
+}
+
/*
* TMU treats temperature as a mapped temperature code.
* The temperature is converted differently depending on the calibration type.
@@ -190,7 +244,7 @@ static int temp_to_code(struct exynos_tmu_data *data, u8 temp)
* Calculate a temperature value from a temperature code.
* The unit of the temperature is degree Celsius.
*/
-static int code_to_temp(struct exynos_tmu_data *data, u8 temp_code)
+static int code_to_temp(struct exynos_tmu_data *data, u16 temp_code)
{
struct exynos_tmu_platform_data *pdata = data->pdata;
int temp;
@@ -234,14 +288,25 @@ static void sanitize_temp_error(struct exynos_tmu_data *data, u32 trim_info)
static u32 get_th_reg(struct exynos_tmu_data *data, u32 threshold, bool falling)
{
- struct exynos_tmu_platform_data *pdata = data->pdata;
+ struct thermal_zone_device *tz = data->tzd;
+ const struct thermal_trip * const trips =
+ of_thermal_get_trip_points(tz);
+ unsigned long temp;
int i;
- for (i = 0; i < pdata->non_hw_trigger_levels; i++) {
- u8 temp = pdata->trigger_levels[i];
+ if (!trips) {
+ pr_err("%s: Cannot get trip points from of-thermal.c!\n",
+ __func__);
+ return 0;
+ }
+
+ for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
+ if (trips[i].type == THERMAL_TRIP_CRITICAL)
+ continue;
+ temp = trips[i].temperature / MCELSIUS;
if (falling)
- temp -= pdata->threshold_falling;
+ temp -= (trips[i].hysteresis / MCELSIUS);
else
threshold &= ~(0xff << 8 * i);
@@ -305,9 +370,19 @@ static void exynos_tmu_control(struct platform_device *pdev, bool on)
static int exynos4210_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos_tmu_platform_data *pdata = data->pdata;
- unsigned int status;
+ struct thermal_zone_device *tz = data->tzd;
+ const struct thermal_trip * const trips =
+ of_thermal_get_trip_points(tz);
int ret = 0, threshold_code, i;
+ unsigned long reference, temp;
+ unsigned int status;
+
+ if (!trips) {
+ pr_err("%s: Cannot get trip points from of-thermal.c!\n",
+ __func__);
+ ret = -ENODEV;
+ goto out;
+ }
status = readb(data->base + EXYNOS_TMU_REG_STATUS);
if (!status) {
@@ -318,12 +393,19 @@ static int exynos4210_tmu_initialize(struct platform_device *pdev)
sanitize_temp_error(data, readl(data->base + EXYNOS_TMU_REG_TRIMINFO));
/* Write temperature code for threshold */
- threshold_code = temp_to_code(data, pdata->threshold);
+ reference = trips[0].temperature / MCELSIUS;
+ threshold_code = temp_to_code(data, reference);
+ if (threshold_code < 0) {
+ ret = threshold_code;
+ goto out;
+ }
writeb(threshold_code, data->base + EXYNOS4210_TMU_REG_THRESHOLD_TEMP);
- for (i = 0; i < pdata->non_hw_trigger_levels; i++)
- writeb(pdata->trigger_levels[i], data->base +
+ for (i = 0; i < of_thermal_get_ntrips(tz); i++) {
+ temp = trips[i].temperature / MCELSIUS;
+ writeb(temp - reference, data->base +
EXYNOS4210_TMU_REG_TRIG_LEVEL0 + i * 4);
+ }
data->tmu_clear_irqs(data);
out:
@@ -333,9 +415,11 @@ out:
static int exynos4412_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos_tmu_platform_data *pdata = data->pdata;
+ const struct thermal_trip * const trips =
+ of_thermal_get_trip_points(data->tzd);
unsigned int status, trim_info, con, ctrl, rising_threshold;
int ret = 0, threshold_code, i;
+ unsigned long crit_temp = 0;
status = readb(data->base + EXYNOS_TMU_REG_STATUS);
if (!status) {
@@ -373,17 +457,29 @@ static int exynos4412_tmu_initialize(struct platform_device *pdev)
data->tmu_clear_irqs(data);
/* if last threshold limit is also present */
- i = pdata->max_trigger_level - 1;
- if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
- threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
- /* 1-4 level to be assigned in th0 reg */
- rising_threshold &= ~(0xff << 8 * i);
- rising_threshold |= threshold_code << 8 * i;
- writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
- con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
- con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
- writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+ for (i = 0; i < of_thermal_get_ntrips(data->tzd); i++) {
+ if (trips[i].type == THERMAL_TRIP_CRITICAL) {
+ crit_temp = trips[i].temperature;
+ break;
+ }
}
+
+ if (i == of_thermal_get_ntrips(data->tzd)) {
+ pr_err("%s: No CRITICAL trip point defined at of-thermal.c!\n",
+ __func__);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
+ /* 1-4 level to be assigned in th0 reg */
+ rising_threshold &= ~(0xff << 8 * i);
+ rising_threshold |= threshold_code << 8 * i;
+ writel(rising_threshold, data->base + EXYNOS_THD_TEMP_RISE);
+ con = readl(data->base + EXYNOS_TMU_REG_CONTROL);
+ con |= (1 << EXYNOS_TMU_THERM_TRIP_EN_SHIFT);
+ writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+
out:
return ret;
}
@@ -391,9 +487,9 @@ out:
static int exynos5440_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos_tmu_platform_data *pdata = data->pdata;
unsigned int trim_info = 0, con, rising_threshold;
- int ret = 0, threshold_code, i;
+ int ret = 0, threshold_code;
+ unsigned long crit_temp = 0;
/*
* For exynos5440 soc triminfo value is swapped between TMU0 and
@@ -422,9 +518,8 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
data->tmu_clear_irqs(data);
/* if last threshold limit is also present */
- i = pdata->max_trigger_level - 1;
- if (pdata->trigger_levels[i] && pdata->trigger_type[i] == HW_TRIP) {
- threshold_code = temp_to_code(data, pdata->trigger_levels[i]);
+ if (!data->tzd->ops->get_crit_temp(data->tzd, &crit_temp)) {
+ threshold_code = temp_to_code(data, crit_temp / MCELSIUS);
/* 5th level to be assigned in th2 reg */
rising_threshold =
threshold_code << EXYNOS5440_TMU_TH_RISE4_SHIFT;
@@ -439,10 +534,88 @@ static int exynos5440_tmu_initialize(struct platform_device *pdev)
return ret;
}
-static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
+static int exynos7_tmu_initialize(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ struct thermal_zone_device *tz = data->tzd;
struct exynos_tmu_platform_data *pdata = data->pdata;
+ unsigned int status, trim_info;
+ unsigned int rising_threshold = 0, falling_threshold = 0;
+ int ret = 0, threshold_code, i;
+ unsigned long temp, temp_hist;
+ unsigned int reg_off, bit_off;
+
+ status = readb(data->base + EXYNOS_TMU_REG_STATUS);
+ if (!status) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ trim_info = readl(data->base + EXYNOS_TMU_REG_TRIMINFO);
+
+ data->temp_error1 = trim_info & EXYNOS7_TMU_TEMP_MASK;
+ if (!data->temp_error1 ||
+ (pdata->min_efuse_value > data->temp_error1) ||
+ (data->temp_error1 > pdata->max_efuse_value))
+ data->temp_error1 = pdata->efuse_value & EXYNOS_TMU_TEMP_MASK;
+
+ /* Write temperature code for rising and falling threshold */
+ for (i = (of_thermal_get_ntrips(tz) - 1); i >= 0; i--) {
+ /*
+ * On exynos7 there are 4 rising and 4 falling threshold
+ * registers (0x50-0x5c and 0x60-0x6c respectively). Each
+ * register holds the value of two threshold levels (at bit
+ * offsets 0 and 16). Based on the fact that there are atmost
+ * eight possible trigger levels, calculate the register and
+ * bit offsets where the threshold levels are to be written.
+ *
+ * e.g. EXYNOS7_THD_TEMP_RISE7_6 (0x50)
+ * [24:16] - Threshold level 7
+ * [8:0] - Threshold level 6
+ * e.g. EXYNOS7_THD_TEMP_RISE5_4 (0x54)
+ * [24:16] - Threshold level 5
+ * [8:0] - Threshold level 4
+ *
+ * and similarly for falling thresholds.
+ *
+ * Based on the above, calculate the register and bit offsets
+ * for rising/falling threshold levels and populate them.
+ */
+ reg_off = ((7 - i) / 2) * 4;
+ bit_off = ((8 - i) % 2);
+
+ tz->ops->get_trip_temp(tz, i, &temp);
+ temp /= MCELSIUS;
+
+ tz->ops->get_trip_hyst(tz, i, &temp_hist);
+ temp_hist = temp - (temp_hist / MCELSIUS);
+
+ /* Set 9-bit temperature code for rising threshold levels */
+ threshold_code = temp_to_code(data, temp);
+ rising_threshold = readl(data->base +
+ EXYNOS7_THD_TEMP_RISE7_6 + reg_off);
+ rising_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off));
+ rising_threshold |= threshold_code << (16 * bit_off);
+ writel(rising_threshold,
+ data->base + EXYNOS7_THD_TEMP_RISE7_6 + reg_off);
+
+ /* Set 9-bit temperature code for falling threshold levels */
+ threshold_code = temp_to_code(data, temp_hist);
+ falling_threshold &= ~(EXYNOS7_TMU_TEMP_MASK << (16 * bit_off));
+ falling_threshold |= threshold_code << (16 * bit_off);
+ writel(falling_threshold,
+ data->base + EXYNOS7_THD_TEMP_FALL7_6 + reg_off);
+ }
+
+ data->tmu_clear_irqs(data);
+out:
+ return ret;
+}
+
+static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
+{
+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ struct thermal_zone_device *tz = data->tzd;
unsigned int con, interrupt_en;
con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
@@ -450,10 +623,15 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
if (on) {
con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
interrupt_en =
- pdata->trigger_enable[3] << EXYNOS_TMU_INTEN_RISE3_SHIFT |
- pdata->trigger_enable[2] << EXYNOS_TMU_INTEN_RISE2_SHIFT |
- pdata->trigger_enable[1] << EXYNOS_TMU_INTEN_RISE1_SHIFT |
- pdata->trigger_enable[0] << EXYNOS_TMU_INTEN_RISE0_SHIFT;
+ (of_thermal_is_trip_valid(tz, 3)
+ << EXYNOS_TMU_INTEN_RISE3_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 2)
+ << EXYNOS_TMU_INTEN_RISE2_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 1)
+ << EXYNOS_TMU_INTEN_RISE1_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 0)
+ << EXYNOS_TMU_INTEN_RISE0_SHIFT);
+
if (data->soc != SOC_ARCH_EXYNOS4210)
interrupt_en |=
interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
@@ -468,7 +646,7 @@ static void exynos4210_tmu_control(struct platform_device *pdev, bool on)
static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
- struct exynos_tmu_platform_data *pdata = data->pdata;
+ struct thermal_zone_device *tz = data->tzd;
unsigned int con, interrupt_en;
con = get_con_reg(data, readl(data->base + EXYNOS5440_TMU_S0_7_CTRL));
@@ -476,11 +654,16 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
if (on) {
con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
interrupt_en =
- pdata->trigger_enable[3] << EXYNOS5440_TMU_INTEN_RISE3_SHIFT |
- pdata->trigger_enable[2] << EXYNOS5440_TMU_INTEN_RISE2_SHIFT |
- pdata->trigger_enable[1] << EXYNOS5440_TMU_INTEN_RISE1_SHIFT |
- pdata->trigger_enable[0] << EXYNOS5440_TMU_INTEN_RISE0_SHIFT;
- interrupt_en |= interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
+ (of_thermal_is_trip_valid(tz, 3)
+ << EXYNOS5440_TMU_INTEN_RISE3_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 2)
+ << EXYNOS5440_TMU_INTEN_RISE2_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 1)
+ << EXYNOS5440_TMU_INTEN_RISE1_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 0)
+ << EXYNOS5440_TMU_INTEN_RISE0_SHIFT);
+ interrupt_en |=
+ interrupt_en << EXYNOS5440_TMU_INTEN_FALL0_SHIFT;
} else {
con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
interrupt_en = 0; /* Disable all interrupts */
@@ -489,19 +672,62 @@ static void exynos5440_tmu_control(struct platform_device *pdev, bool on)
writel(con, data->base + EXYNOS5440_TMU_S0_7_CTRL);
}
-static int exynos_tmu_read(struct exynos_tmu_data *data)
+static void exynos7_tmu_control(struct platform_device *pdev, bool on)
{
- int ret;
+ struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ struct thermal_zone_device *tz = data->tzd;
+ unsigned int con, interrupt_en;
+
+ con = get_con_reg(data, readl(data->base + EXYNOS_TMU_REG_CONTROL));
+
+ if (on) {
+ con |= (1 << EXYNOS_TMU_CORE_EN_SHIFT);
+ interrupt_en =
+ (of_thermal_is_trip_valid(tz, 7)
+ << EXYNOS7_TMU_INTEN_RISE7_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 6)
+ << EXYNOS7_TMU_INTEN_RISE6_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 5)
+ << EXYNOS7_TMU_INTEN_RISE5_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 4)
+ << EXYNOS7_TMU_INTEN_RISE4_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 3)
+ << EXYNOS7_TMU_INTEN_RISE3_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 2)
+ << EXYNOS7_TMU_INTEN_RISE2_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 1)
+ << EXYNOS7_TMU_INTEN_RISE1_SHIFT) |
+ (of_thermal_is_trip_valid(tz, 0)
+ << EXYNOS7_TMU_INTEN_RISE0_SHIFT);
+
+ interrupt_en |=
+ interrupt_en << EXYNOS_TMU_INTEN_FALL0_SHIFT;
+ } else {
+ con &= ~(1 << EXYNOS_TMU_CORE_EN_SHIFT);
+ interrupt_en = 0; /* Disable all interrupts */
+ }
+ con |= 1 << EXYNOS7_PD_DET_EN_SHIFT;
+
+ writel(interrupt_en, data->base + EXYNOS7_TMU_REG_INTEN);
+ writel(con, data->base + EXYNOS_TMU_REG_CONTROL);
+}
+
+static int exynos_get_temp(void *p, long *temp)
+{
+ struct exynos_tmu_data *data = p;
+
+ if (!data || !data->tmu_read)
+ return -EINVAL;
mutex_lock(&data->lock);
clk_enable(data->clk);
- ret = data->tmu_read(data);
- if (ret >= 0)
- ret = code_to_temp(data, ret);
+
+ *temp = code_to_temp(data, data->tmu_read(data)) * MCELSIUS;
+
clk_disable(data->clk);
mutex_unlock(&data->lock);
- return ret;
+ return 0;
}
#ifdef CONFIG_THERMAL_EMULATION
@@ -515,9 +741,19 @@ static u32 get_emul_con_reg(struct exynos_tmu_data *data, unsigned int val,
val &= ~(EXYNOS_EMUL_TIME_MASK << EXYNOS_EMUL_TIME_SHIFT);
val |= (EXYNOS_EMUL_TIME << EXYNOS_EMUL_TIME_SHIFT);
}
- val &= ~(EXYNOS_EMUL_DATA_MASK << EXYNOS_EMUL_DATA_SHIFT);
- val |= (temp_to_code(data, temp) << EXYNOS_EMUL_DATA_SHIFT) |
- EXYNOS_EMUL_ENABLE;
+ if (data->soc == SOC_ARCH_EXYNOS7) {
+ val &= ~(EXYNOS7_EMUL_DATA_MASK <<
+ EXYNOS7_EMUL_DATA_SHIFT);
+ val |= (temp_to_code(data, temp) <<
+ EXYNOS7_EMUL_DATA_SHIFT) |
+ EXYNOS_EMUL_ENABLE;
+ } else {
+ val &= ~(EXYNOS_EMUL_DATA_MASK <<
+ EXYNOS_EMUL_DATA_SHIFT);
+ val |= (temp_to_code(data, temp) <<
+ EXYNOS_EMUL_DATA_SHIFT) |
+ EXYNOS_EMUL_ENABLE;
+ }
} else {
val &= ~EXYNOS_EMUL_ENABLE;
}
@@ -533,6 +769,8 @@ static void exynos4412_tmu_set_emulation(struct exynos_tmu_data *data,
if (data->soc == SOC_ARCH_EXYNOS5260)
emul_con = EXYNOS5260_EMUL_CON;
+ else if (data->soc == SOC_ARCH_EXYNOS7)
+ emul_con = EXYNOS7_TMU_REG_EMUL_CON;
else
emul_con = EXYNOS_EMUL_CON;
@@ -576,7 +814,7 @@ out:
#define exynos5440_tmu_set_emulation NULL
static int exynos_tmu_set_emulation(void *drv_data, unsigned long temp)
{ return -EINVAL; }
-#endif/*CONFIG_THERMAL_EMULATION*/
+#endif /* CONFIG_THERMAL_EMULATION */
static int exynos4210_tmu_read(struct exynos_tmu_data *data)
{
@@ -596,6 +834,12 @@ static int exynos5440_tmu_read(struct exynos_tmu_data *data)
return readb(data->base + EXYNOS5440_TMU_S0_7_TEMP);
}
+static int exynos7_tmu_read(struct exynos_tmu_data *data)
+{
+ return readw(data->base + EXYNOS_TMU_REG_CURRENT_TEMP) &
+ EXYNOS7_TMU_TEMP_MASK;
+}
+
static void exynos_tmu_work(struct work_struct *work)
{
struct exynos_tmu_data *data = container_of(work,
@@ -613,7 +857,7 @@ static void exynos_tmu_work(struct work_struct *work)
if (!IS_ERR(data->clk_sec))
clk_disable(data->clk_sec);
- exynos_report_trigger(data->reg_conf);
+ exynos_report_trigger(data);
mutex_lock(&data->lock);
clk_enable(data->clk);
@@ -634,6 +878,9 @@ static void exynos4210_tmu_clear_irqs(struct exynos_tmu_data *data)
if (data->soc == SOC_ARCH_EXYNOS5260) {
tmu_intstat = EXYNOS5260_TMU_REG_INTSTAT;
tmu_intclear = EXYNOS5260_TMU_REG_INTCLEAR;
+ } else if (data->soc == SOC_ARCH_EXYNOS7) {
+ tmu_intstat = EXYNOS7_TMU_REG_INTPEND;
+ tmu_intclear = EXYNOS7_TMU_REG_INTPEND;
} else {
tmu_intstat = EXYNOS_TMU_REG_INTSTAT;
tmu_intclear = EXYNOS_TMU_REG_INTCLEAR;
@@ -673,55 +920,94 @@ static irqreturn_t exynos_tmu_irq(int irq, void *id)
static const struct of_device_id exynos_tmu_match[] = {
{
.compatible = "samsung,exynos3250-tmu",
- .data = &exynos3250_default_tmu_data,
},
{
.compatible = "samsung,exynos4210-tmu",
- .data = &exynos4210_default_tmu_data,
},
{
.compatible = "samsung,exynos4412-tmu",
- .data = &exynos4412_default_tmu_data,
},
{
.compatible = "samsung,exynos5250-tmu",
- .data = &exynos5250_default_tmu_data,
},
{
.compatible = "samsung,exynos5260-tmu",
- .data = &exynos5260_default_tmu_data,
},
{
.compatible = "samsung,exynos5420-tmu",
- .data = &exynos5420_default_tmu_data,
},
{
.compatible = "samsung,exynos5420-tmu-ext-triminfo",
- .data = &exynos5420_default_tmu_data,
},
{
.compatible = "samsung,exynos5440-tmu",
- .data = &exynos5440_default_tmu_data,
+ },
+ {
+ .compatible = "samsung,exynos7-tmu",
},
{},
};
MODULE_DEVICE_TABLE(of, exynos_tmu_match);
-static inline struct exynos_tmu_platform_data *exynos_get_driver_data(
- struct platform_device *pdev, int id)
+static int exynos_of_get_soc_type(struct device_node *np)
+{
+ if (of_device_is_compatible(np, "samsung,exynos3250-tmu"))
+ return SOC_ARCH_EXYNOS3250;
+ else if (of_device_is_compatible(np, "samsung,exynos4210-tmu"))
+ return SOC_ARCH_EXYNOS4210;
+ else if (of_device_is_compatible(np, "samsung,exynos4412-tmu"))
+ return SOC_ARCH_EXYNOS4412;
+ else if (of_device_is_compatible(np, "samsung,exynos5250-tmu"))
+ return SOC_ARCH_EXYNOS5250;
+ else if (of_device_is_compatible(np, "samsung,exynos5260-tmu"))
+ return SOC_ARCH_EXYNOS5260;
+ else if (of_device_is_compatible(np, "samsung,exynos5420-tmu"))
+ return SOC_ARCH_EXYNOS5420;
+ else if (of_device_is_compatible(np,
+ "samsung,exynos5420-tmu-ext-triminfo"))
+ return SOC_ARCH_EXYNOS5420_TRIMINFO;
+ else if (of_device_is_compatible(np, "samsung,exynos5440-tmu"))
+ return SOC_ARCH_EXYNOS5440;
+ else if (of_device_is_compatible(np, "samsung,exynos7-tmu"))
+ return SOC_ARCH_EXYNOS7;
+
+ return -EINVAL;
+}
+
+static int exynos_of_sensor_conf(struct device_node *np,
+ struct exynos_tmu_platform_data *pdata)
{
- struct exynos_tmu_init_data *data_table;
- struct exynos_tmu_platform_data *tmu_data;
- const struct of_device_id *match;
+ u32 value;
+ int ret;
- match = of_match_node(exynos_tmu_match, pdev->dev.of_node);
- if (!match)
- return NULL;
- data_table = (struct exynos_tmu_init_data *) match->data;
- if (!data_table || id >= data_table->tmu_count)
- return NULL;
- tmu_data = data_table->tmu_data;
- return (struct exynos_tmu_platform_data *) (tmu_data + id);
+ of_node_get(np);
+
+ ret = of_property_read_u32(np, "samsung,tmu_gain", &value);
+ pdata->gain = (u8)value;
+ of_property_read_u32(np, "samsung,tmu_reference_voltage", &value);
+ pdata->reference_voltage = (u8)value;
+ of_property_read_u32(np, "samsung,tmu_noise_cancel_mode", &value);
+ pdata->noise_cancel_mode = (u8)value;
+
+ of_property_read_u32(np, "samsung,tmu_efuse_value",
+ &pdata->efuse_value);
+ of_property_read_u32(np, "samsung,tmu_min_efuse_value",
+ &pdata->min_efuse_value);
+ of_property_read_u32(np, "samsung,tmu_max_efuse_value",
+ &pdata->max_efuse_value);
+
+ of_property_read_u32(np, "samsung,tmu_first_point_trim", &value);
+ pdata->first_point_trim = (u8)value;
+ of_property_read_u32(np, "samsung,tmu_second_point_trim", &value);
+ pdata->second_point_trim = (u8)value;
+ of_property_read_u32(np, "samsung,tmu_default_temp_offset", &value);
+ pdata->default_temp_offset = (u8)value;
+
+ of_property_read_u32(np, "samsung,tmu_cal_type", &pdata->cal_type);
+ of_property_read_u32(np, "samsung,tmu_cal_mode", &pdata->cal_mode);
+
+ of_node_put(np);
+ return 0;
}
static int exynos_map_dt_data(struct platform_device *pdev)
@@ -771,14 +1057,15 @@ static int exynos_map_dt_data(struct platform_device *pdev)
return -EADDRNOTAVAIL;
}
- pdata = exynos_get_driver_data(pdev, data->id);
- if (!pdata) {
- dev_err(&pdev->dev, "No platform init data supplied.\n");
- return -ENODEV;
- }
+ pdata = devm_kzalloc(&pdev->dev,
+ sizeof(struct exynos_tmu_platform_data),
+ GFP_KERNEL);
+ if (!pdata)
+ return -ENOMEM;
+ exynos_of_sensor_conf(pdev->dev.of_node, pdata);
data->pdata = pdata;
- data->soc = pdata->type;
+ data->soc = exynos_of_get_soc_type(pdev->dev.of_node);
switch (data->soc) {
case SOC_ARCH_EXYNOS4210:
@@ -806,6 +1093,13 @@ static int exynos_map_dt_data(struct platform_device *pdev)
data->tmu_set_emulation = exynos5440_tmu_set_emulation;
data->tmu_clear_irqs = exynos5440_tmu_clear_irqs;
break;
+ case SOC_ARCH_EXYNOS7:
+ data->tmu_initialize = exynos7_tmu_initialize;
+ data->tmu_control = exynos7_tmu_control;
+ data->tmu_read = exynos7_tmu_read;
+ data->tmu_set_emulation = exynos4412_tmu_set_emulation;
+ data->tmu_clear_irqs = exynos4210_tmu_clear_irqs;
+ break;
default:
dev_err(&pdev->dev, "Platform not supported\n");
return -EINVAL;
@@ -834,12 +1128,16 @@ static int exynos_map_dt_data(struct platform_device *pdev)
return 0;
}
+static struct thermal_zone_of_device_ops exynos_sensor_ops = {
+ .get_temp = exynos_get_temp,
+ .set_emul_temp = exynos_tmu_set_emulation,
+};
+
static int exynos_tmu_probe(struct platform_device *pdev)
{
- struct exynos_tmu_data *data;
struct exynos_tmu_platform_data *pdata;
- struct thermal_sensor_conf *sensor_conf;
- int ret, i;
+ struct exynos_tmu_data *data;
+ int ret;
data = devm_kzalloc(&pdev->dev, sizeof(struct exynos_tmu_data),
GFP_KERNEL);
@@ -849,9 +1147,15 @@ static int exynos_tmu_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
mutex_init(&data->lock);
+ data->tzd = thermal_zone_of_sensor_register(&pdev->dev, 0, data,
+ &exynos_sensor_ops);
+ if (IS_ERR(data->tzd)) {
+ pr_err("thermal: tz: %p ERROR\n", data->tzd);
+ return PTR_ERR(data->tzd);
+ }
ret = exynos_map_dt_data(pdev);
if (ret)
- return ret;
+ goto err_sensor;
pdata = data->pdata;
@@ -860,20 +1164,22 @@ static int exynos_tmu_probe(struct platform_device *pdev)
data->clk = devm_clk_get(&pdev->dev, "tmu_apbif");
if (IS_ERR(data->clk)) {
dev_err(&pdev->dev, "Failed to get clock\n");
- return PTR_ERR(data->clk);
+ ret = PTR_ERR(data->clk);
+ goto err_sensor;
}
data->clk_sec = devm_clk_get(&pdev->dev, "tmu_triminfo_apbif");
if (IS_ERR(data->clk_sec)) {
if (data->soc == SOC_ARCH_EXYNOS5420_TRIMINFO) {
dev_err(&pdev->dev, "Failed to get triminfo clock\n");
- return PTR_ERR(data->clk_sec);
+ ret = PTR_ERR(data->clk_sec);
+ goto err_sensor;
}
} else {
ret = clk_prepare(data->clk_sec);
if (ret) {
dev_err(&pdev->dev, "Failed to get clock\n");
- return ret;
+ goto err_sensor;
}
}
@@ -883,82 +1189,57 @@ static int exynos_tmu_probe(struct platform_device *pdev)
goto err_clk_sec;
}
- ret = exynos_tmu_initialize(pdev);
- if (ret) {
- dev_err(&pdev->dev, "Failed to initialize TMU\n");
- goto err_clk;
+ if (data->soc == SOC_ARCH_EXYNOS7) {
+ data->sclk = devm_clk_get(&pdev->dev, "tmu_sclk");
+ if (IS_ERR(data->sclk)) {
+ dev_err(&pdev->dev, "Failed to get sclk\n");
+ goto err_clk;
+ } else {
+ ret = clk_prepare_enable(data->sclk);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to enable sclk\n");
+ goto err_clk;
+ }
+ }
}
- exynos_tmu_control(pdev, true);
-
- /* Allocate a structure to register with the exynos core thermal */
- sensor_conf = devm_kzalloc(&pdev->dev,
- sizeof(struct thermal_sensor_conf), GFP_KERNEL);
- if (!sensor_conf) {
- ret = -ENOMEM;
- goto err_clk;
- }
- sprintf(sensor_conf->name, "therm_zone%d", data->id);
- sensor_conf->read_temperature = (int (*)(void *))exynos_tmu_read;
- sensor_conf->write_emul_temp =
- (int (*)(void *, unsigned long))exynos_tmu_set_emulation;
- sensor_conf->driver_data = data;
- sensor_conf->trip_data.trip_count = pdata->trigger_enable[0] +
- pdata->trigger_enable[1] + pdata->trigger_enable[2]+
- pdata->trigger_enable[3];
-
- for (i = 0; i < sensor_conf->trip_data.trip_count; i++) {
- sensor_conf->trip_data.trip_val[i] =
- pdata->threshold + pdata->trigger_levels[i];
- sensor_conf->trip_data.trip_type[i] =
- pdata->trigger_type[i];
- }
-
- sensor_conf->trip_data.trigger_falling = pdata->threshold_falling;
-
- sensor_conf->cooling_data.freq_clip_count = pdata->freq_tab_count;
- for (i = 0; i < pdata->freq_tab_count; i++) {
- sensor_conf->cooling_data.freq_data[i].freq_clip_max =
- pdata->freq_tab[i].freq_clip_max;
- sensor_conf->cooling_data.freq_data[i].temp_level =
- pdata->freq_tab[i].temp_level;
- }
- sensor_conf->dev = &pdev->dev;
- /* Register the sensor with thermal management interface */
- ret = exynos_register_thermal(sensor_conf);
+ ret = exynos_tmu_initialize(pdev);
if (ret) {
- if (ret != -EPROBE_DEFER)
- dev_err(&pdev->dev,
- "Failed to register thermal interface: %d\n",
- ret);
- goto err_clk;
+ dev_err(&pdev->dev, "Failed to initialize TMU\n");
+ goto err_sclk;
}
- data->reg_conf = sensor_conf;
ret = devm_request_irq(&pdev->dev, data->irq, exynos_tmu_irq,
IRQF_TRIGGER_RISING | IRQF_SHARED, dev_name(&pdev->dev), data);
if (ret) {
dev_err(&pdev->dev, "Failed to request irq: %d\n", data->irq);
- goto err_clk;
+ goto err_sclk;
}
+ exynos_tmu_control(pdev, true);
return 0;
+err_sclk:
+ clk_disable_unprepare(data->sclk);
err_clk:
clk_unprepare(data->clk);
err_clk_sec:
if (!IS_ERR(data->clk_sec))
clk_unprepare(data->clk_sec);
+err_sensor:
+ thermal_zone_of_sensor_unregister(&pdev->dev, data->tzd);
+
return ret;
}
static int exynos_tmu_remove(struct platform_device *pdev)
{
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
+ struct thermal_zone_device *tzd = data->tzd;
- exynos_unregister_thermal(data->reg_conf);
-
+ thermal_zone_of_sensor_unregister(&pdev->dev, tzd);
exynos_tmu_control(pdev, false);
+ clk_disable_unprepare(data->sclk);
clk_unprepare(data->clk);
if (!IS_ERR(data->clk_sec))
clk_unprepare(data->clk_sec);
diff --git a/drivers/thermal/samsung/exynos_tmu.h b/drivers/thermal/samsung/exynos_tmu.h
index da3009bff6c4..4d71ec6c9aa0 100644
--- a/drivers/thermal/samsung/exynos_tmu.h
+++ b/drivers/thermal/samsung/exynos_tmu.h
@@ -23,16 +23,7 @@
#ifndef _EXYNOS_TMU_H
#define _EXYNOS_TMU_H
#include <linux/cpu_cooling.h>
-
-#include "exynos_thermal_common.h"
-
-enum calibration_type {
- TYPE_ONE_POINT_TRIMMING,
- TYPE_ONE_POINT_TRIMMING_25,
- TYPE_ONE_POINT_TRIMMING_85,
- TYPE_TWO_POINT_TRIMMING,
- TYPE_NONE,
-};
+#include <dt-bindings/thermal/thermal_exynos.h>
enum soc_type {
SOC_ARCH_EXYNOS3250 = 1,
@@ -43,38 +34,11 @@ enum soc_type {
SOC_ARCH_EXYNOS5420,
SOC_ARCH_EXYNOS5420_TRIMINFO,
SOC_ARCH_EXYNOS5440,
+ SOC_ARCH_EXYNOS7,
};
/**
* struct exynos_tmu_platform_data
- * @threshold: basic temperature for generating interrupt
- * 25 <= threshold <= 125 [unit: degree Celsius]
- * @threshold_falling: differntial value for setting threshold
- * of temperature falling interrupt.
- * @trigger_levels: array for each interrupt levels
- * [unit: degree Celsius]
- * 0: temperature for trigger_level0 interrupt
- * condition for trigger_level0 interrupt:
- * current temperature > threshold + trigger_levels[0]
- * 1: temperature for trigger_level1 interrupt
- * condition for trigger_level1 interrupt:
- * current temperature > threshold + trigger_levels[1]
- * 2: temperature for trigger_level2 interrupt
- * condition for trigger_level2 interrupt:
- * current temperature > threshold + trigger_levels[2]
- * 3: temperature for trigger_level3 interrupt
- * condition for trigger_level3 interrupt:
- * current temperature > threshold + trigger_levels[3]
- * @trigger_type: defines the type of trigger. Possible values are,
- * THROTTLE_ACTIVE trigger type
- * THROTTLE_PASSIVE trigger type
- * SW_TRIP trigger type
- * HW_TRIP
- * @trigger_enable[]: array to denote which trigger levels are enabled.
- * 1 = enable trigger_level[] interrupt,
- * 0 = disable trigger_level[] interrupt
- * @max_trigger_level: max trigger level supported by the TMU
- * @non_hw_trigger_levels: number of defined non-hardware trigger levels
* @gain: gain of amplifier in the positive-TC generator block
* 0 < gain <= 15
* @reference_voltage: reference voltage of amplifier
@@ -86,24 +50,12 @@ enum soc_type {
* @efuse_value: platform defined fuse value
* @min_efuse_value: minimum valid trimming data
* @max_efuse_value: maximum valid trimming data
- * @first_point_trim: temp value of the first point trimming
- * @second_point_trim: temp value of the second point trimming
* @default_temp_offset: default temperature offset in case of no trimming
* @cal_type: calibration type for temperature
- * @freq_clip_table: Table representing frequency reduction percentage.
- * @freq_tab_count: Count of the above table as frequency reduction may
- * applicable to only some of the trigger levels.
*
* This structure is required for configuration of exynos_tmu driver.
*/
struct exynos_tmu_platform_data {
- u8 threshold;
- u8 threshold_falling;
- u8 trigger_levels[MAX_TRIP_COUNT];
- enum trigger_type trigger_type[MAX_TRIP_COUNT];
- bool trigger_enable[MAX_TRIP_COUNT];
- u8 max_trigger_level;
- u8 non_hw_trigger_levels;
u8 gain;
u8 reference_voltage;
u8 noise_cancel_mode;
@@ -115,30 +67,9 @@ struct exynos_tmu_platform_data {
u8 second_point_trim;
u8 default_temp_offset;
- enum calibration_type cal_type;
enum soc_type type;
- struct freq_clip_table freq_tab[4];
- unsigned int freq_tab_count;
-};
-
-/**
- * struct exynos_tmu_init_data
- * @tmu_count: number of TMU instances.
- * @tmu_data: platform data of all TMU instances.
- * This structure is required to store data for multi-instance exynos tmu
- * driver.
- */
-struct exynos_tmu_init_data {
- int tmu_count;
- struct exynos_tmu_platform_data tmu_data[];
+ u32 cal_type;
+ u32 cal_mode;
};
-extern struct exynos_tmu_init_data const exynos3250_default_tmu_data;
-extern struct exynos_tmu_init_data const exynos4210_default_tmu_data;
-extern struct exynos_tmu_init_data const exynos4412_default_tmu_data;
-extern struct exynos_tmu_init_data const exynos5250_default_tmu_data;
-extern struct exynos_tmu_init_data const exynos5260_default_tmu_data;
-extern struct exynos_tmu_init_data const exynos5420_default_tmu_data;
-extern struct exynos_tmu_init_data const exynos5440_default_tmu_data;
-
#endif /* _EXYNOS_TMU_H */
diff --git a/drivers/thermal/samsung/exynos_tmu_data.c b/drivers/thermal/samsung/exynos_tmu_data.c
deleted file mode 100644
index b23910069f68..000000000000
--- a/drivers/thermal/samsung/exynos_tmu_data.c
+++ /dev/null
@@ -1,264 +0,0 @@
-/*
- * exynos_tmu_data.c - Samsung EXYNOS tmu data file
- *
- * Copyright (C) 2013 Samsung Electronics
- * Amit Daniel Kachhap <amit.daniel@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.
- *
- * 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 "exynos_thermal_common.h"
-#include "exynos_tmu.h"
-
-struct exynos_tmu_init_data const exynos4210_default_tmu_data = {
- .tmu_data = {
- {
- .threshold = 80,
- .trigger_levels[0] = 5,
- .trigger_levels[1] = 20,
- .trigger_levels[2] = 30,
- .trigger_enable[0] = true,
- .trigger_enable[1] = true,
- .trigger_enable[2] = true,
- .trigger_enable[3] = false,
- .trigger_type[0] = THROTTLE_ACTIVE,
- .trigger_type[1] = THROTTLE_ACTIVE,
- .trigger_type[2] = SW_TRIP,
- .max_trigger_level = 4,
- .non_hw_trigger_levels = 3,
- .gain = 15,
- .reference_voltage = 7,
- .cal_type = TYPE_ONE_POINT_TRIMMING,
- .min_efuse_value = 40,
- .max_efuse_value = 100,
- .first_point_trim = 25,
- .second_point_trim = 85,
- .default_temp_offset = 50,
- .freq_tab[0] = {
- .freq_clip_max = 800 * 1000,
- .temp_level = 85,
- },
- .freq_tab[1] = {
- .freq_clip_max = 200 * 1000,
- .temp_level = 100,
- },
- .freq_tab_count = 2,
- .type = SOC_ARCH_EXYNOS4210,
- },
- },
- .tmu_count = 1,
-};
-
-#define EXYNOS3250_TMU_DATA \
- .threshold_falling = 10, \
- .trigger_levels[0] = 70, \
- .trigger_levels[1] = 95, \
- .trigger_levels[2] = 110, \
- .trigger_levels[3] = 120, \
- .trigger_enable[0] = true, \
- .trigger_enable[1] = true, \
- .trigger_enable[2] = true, \
- .trigger_enable[3] = false, \
- .trigger_type[0] = THROTTLE_ACTIVE, \
- .trigger_type[1] = THROTTLE_ACTIVE, \
- .trigger_type[2] = SW_TRIP, \
- .trigger_type[3] = HW_TRIP, \
- .max_trigger_level = 4, \
- .non_hw_trigger_levels = 3, \
- .gain = 8, \
- .reference_voltage = 16, \
- .noise_cancel_mode = 4, \
- .cal_type = TYPE_TWO_POINT_TRIMMING, \
- .efuse_value = 55, \
- .min_efuse_value = 40, \
- .max_efuse_value = 100, \
- .first_point_trim = 25, \
- .second_point_trim = 85, \
- .default_temp_offset = 50, \
- .freq_tab[0] = { \
- .freq_clip_max = 800 * 1000, \
- .temp_level = 70, \
- }, \
- .freq_tab[1] = { \
- .freq_clip_max = 400 * 1000, \
- .temp_level = 95, \
- }, \
- .freq_tab_count = 2
-
-struct exynos_tmu_init_data const exynos3250_default_tmu_data = {
- .tmu_data = {
- {
- EXYNOS3250_TMU_DATA,
- .type = SOC_ARCH_EXYNOS3250,
- },
- },
- .tmu_count = 1,
-};
-
-#define EXYNOS4412_TMU_DATA \
- .threshold_falling = 10, \
- .trigger_levels[0] = 70, \
- .trigger_levels[1] = 95, \
- .trigger_levels[2] = 110, \
- .trigger_levels[3] = 120, \
- .trigger_enable[0] = true, \
- .trigger_enable[1] = true, \
- .trigger_enable[2] = true, \
- .trigger_enable[3] = false, \
- .trigger_type[0] = THROTTLE_ACTIVE, \
- .trigger_type[1] = THROTTLE_ACTIVE, \
- .trigger_type[2] = SW_TRIP, \
- .trigger_type[3] = HW_TRIP, \
- .max_trigger_level = 4, \
- .non_hw_trigger_levels = 3, \
- .gain = 8, \
- .reference_voltage = 16, \
- .noise_cancel_mode = 4, \
- .cal_type = TYPE_ONE_POINT_TRIMMING, \
- .efuse_value = 55, \
- .min_efuse_value = 40, \
- .max_efuse_value = 100, \
- .first_point_trim = 25, \
- .second_point_trim = 85, \
- .default_temp_offset = 50, \
- .freq_tab[0] = { \
- .freq_clip_max = 1400 * 1000, \
- .temp_level = 70, \
- }, \
- .freq_tab[1] = { \
- .freq_clip_max = 400 * 1000, \
- .temp_level = 95, \
- }, \
- .freq_tab_count = 2
-
-struct exynos_tmu_init_data const exynos4412_default_tmu_data = {
- .tmu_data = {
- {
- EXYNOS4412_TMU_DATA,
- .type = SOC_ARCH_EXYNOS4412,
- },
- },
- .tmu_count = 1,
-};
-
-struct exynos_tmu_init_data const exynos5250_default_tmu_data = {
- .tmu_data = {
- {
- EXYNOS4412_TMU_DATA,
- .type = SOC_ARCH_EXYNOS5250,
- },
- },
- .tmu_count = 1,
-};
-
-#define __EXYNOS5260_TMU_DATA \
- .threshold_falling = 10, \
- .trigger_levels[0] = 85, \
- .trigger_levels[1] = 103, \
- .trigger_levels[2] = 110, \
- .trigger_levels[3] = 120, \
- .trigger_enable[0] = true, \
- .trigger_enable[1] = true, \
- .trigger_enable[2] = true, \
- .trigger_enable[3] = false, \
- .trigger_type[0] = THROTTLE_ACTIVE, \
- .trigger_type[1] = THROTTLE_ACTIVE, \
- .trigger_type[2] = SW_TRIP, \
- .trigger_type[3] = HW_TRIP, \
- .max_trigger_level = 4, \
- .non_hw_trigger_levels = 3, \
- .gain = 8, \
- .reference_voltage = 16, \
- .noise_cancel_mode = 4, \
- .cal_type = TYPE_ONE_POINT_TRIMMING, \
- .efuse_value = 55, \
- .min_efuse_value = 40, \
- .max_efuse_value = 100, \
- .first_point_trim = 25, \
- .second_point_trim = 85, \
- .default_temp_offset = 50, \
- .freq_tab[0] = { \
- .freq_clip_max = 800 * 1000, \
- .temp_level = 85, \
- }, \
- .freq_tab[1] = { \
- .freq_clip_max = 200 * 1000, \
- .temp_level = 103, \
- }, \
- .freq_tab_count = 2, \
-
-#define EXYNOS5260_TMU_DATA \
- __EXYNOS5260_TMU_DATA \
- .type = SOC_ARCH_EXYNOS5260
-
-struct exynos_tmu_init_data const exynos5260_default_tmu_data = {
- .tmu_data = {
- { EXYNOS5260_TMU_DATA },
- { EXYNOS5260_TMU_DATA },
- { EXYNOS5260_TMU_DATA },
- { EXYNOS5260_TMU_DATA },
- { EXYNOS5260_TMU_DATA },
- },
- .tmu_count = 5,
-};
-
-#define EXYNOS5420_TMU_DATA \
- __EXYNOS5260_TMU_DATA \
- .type = SOC_ARCH_EXYNOS5420
-
-#define EXYNOS5420_TMU_DATA_SHARED \
- __EXYNOS5260_TMU_DATA \
- .type = SOC_ARCH_EXYNOS5420_TRIMINFO
-
-struct exynos_tmu_init_data const exynos5420_default_tmu_data = {
- .tmu_data = {
- { EXYNOS5420_TMU_DATA },
- { EXYNOS5420_TMU_DATA },
- { EXYNOS5420_TMU_DATA_SHARED },
- { EXYNOS5420_TMU_DATA_SHARED },
- { EXYNOS5420_TMU_DATA_SHARED },
- },
- .tmu_count = 5,
-};
-
-#define EXYNOS5440_TMU_DATA \
- .trigger_levels[0] = 100, \
- .trigger_levels[4] = 105, \
- .trigger_enable[0] = 1, \
- .trigger_type[0] = SW_TRIP, \
- .trigger_type[4] = HW_TRIP, \
- .max_trigger_level = 5, \
- .non_hw_trigger_levels = 1, \
- .gain = 5, \
- .reference_voltage = 16, \
- .noise_cancel_mode = 4, \
- .cal_type = TYPE_ONE_POINT_TRIMMING, \
- .efuse_value = 0x5b2d, \
- .min_efuse_value = 16, \
- .max_efuse_value = 76, \
- .first_point_trim = 25, \
- .second_point_trim = 70, \
- .default_temp_offset = 25, \
- .type = SOC_ARCH_EXYNOS5440
-
-struct exynos_tmu_init_data const exynos5440_default_tmu_data = {
- .tmu_data = {
- { EXYNOS5440_TMU_DATA } ,
- { EXYNOS5440_TMU_DATA } ,
- { EXYNOS5440_TMU_DATA } ,
- },
- .tmu_count = 3,
-};
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index fdd1f523a1ed..5a0f12d08e8b 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -45,7 +45,7 @@
* c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing
* d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit,
* if the cooling state already equals lower limit,
- * deactive the thermal instance
+ * deactivate the thermal instance
*/
static unsigned long get_target_state(struct thermal_instance *instance,
enum thermal_trend trend, bool throttle)
@@ -169,7 +169,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
}
/**
- * step_wise_throttle - throttles devices asscciated with the given zone
+ * step_wise_throttle - throttles devices associated with the given zone
* @tz - thermal_zone_device
* @trip - the trip point
* @trip_type - type of the trip point
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 87e0b0782023..48491d1a81d6 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -1759,11 +1759,7 @@ int thermal_generate_netlink_event(struct thermal_zone_device *tz,
thermal_event->event = event;
/* send multicast genetlink message */
- result = genlmsg_end(skb, msg_header);
- if (result < 0) {
- nlmsg_free(skb);
- return result;
- }
+ genlmsg_end(skb, msg_header);
result = genlmsg_multicast(&thermal_event_genl_family, skb, 0,
0, GFP_ATOMIC);
diff --git a/drivers/tty/amiserial.c b/drivers/tty/amiserial.c
index d9f85f95eb2a..b2d760055952 100644
--- a/drivers/tty/amiserial.c
+++ b/drivers/tty/amiserial.c
@@ -931,7 +931,7 @@ static void rs_send_xchar(struct tty_struct *tty, char ch)
struct serial_state *info = tty->driver_data;
unsigned long flags;
- if (serial_paranoia_check(info, tty->name, "rs_send_char"))
+ if (serial_paranoia_check(info, tty->name, "rs_send_xchar"))
return;
info->x_char = ch;
diff --git a/drivers/tty/ehv_bytechan.c b/drivers/tty/ehv_bytechan.c
index 3c60923b0957..342b36b9ad35 100644
--- a/drivers/tty/ehv_bytechan.c
+++ b/drivers/tty/ehv_bytechan.c
@@ -112,7 +112,6 @@ static void disable_tx_interrupt(struct ehv_bc_data *bc)
static int find_console_handle(void)
{
struct device_node *np = of_stdout;
- const char *sprop = NULL;
const uint32_t *iprop;
/* We don't care what the aliased node is actually called. We only
diff --git a/drivers/tty/hvc/hvc_iucv.c b/drivers/tty/hvc/hvc_iucv.c
index ea74460f3638..f78a87b07872 100644
--- a/drivers/tty/hvc/hvc_iucv.c
+++ b/drivers/tty/hvc/hvc_iucv.c
@@ -1,10 +1,10 @@
/*
- * hvc_iucv.c - z/VM IUCV hypervisor console (HVC) device driver
+ * z/VM IUCV hypervisor console (HVC) device driver
*
* This HVC device driver provides terminal access using
* z/VM IUCV communication paths.
*
- * Copyright IBM Corp. 2008, 2009
+ * Copyright IBM Corp. 2008, 2013
*
* Author(s): Hendrik Brueckner <brueckner@linux.vnet.ibm.com>
*/
@@ -102,6 +102,7 @@ static struct hvc_iucv_private *hvc_iucv_table[MAX_HVC_IUCV_LINES];
#define IUCV_HVC_CON_IDX (0)
/* List of z/VM user ID filter entries (struct iucv_vmid_filter) */
#define MAX_VMID_FILTER (500)
+#define FILTER_WILDCARD_CHAR '*'
static size_t hvc_iucv_filter_size;
static void *hvc_iucv_filter;
static const char *hvc_iucv_filter_string;
@@ -734,20 +735,31 @@ static void hvc_iucv_notifier_del(struct hvc_struct *hp, int id)
* hvc_iucv_filter_connreq() - Filter connection request based on z/VM user ID
* @ipvmid: Originating z/VM user ID (right padded with blanks)
*
- * Returns 0 if the z/VM user ID @ipvmid is allowed to connection, otherwise
- * non-zero.
+ * Returns 0 if the z/VM user ID that is specified with @ipvmid is permitted to
+ * connect, otherwise non-zero.
*/
static int hvc_iucv_filter_connreq(u8 ipvmid[8])
{
- size_t i;
+ const char *wildcard, *filter_entry;
+ size_t i, len;
/* Note: default policy is ACCEPT if no filter is set */
if (!hvc_iucv_filter_size)
return 0;
- for (i = 0; i < hvc_iucv_filter_size; i++)
- if (0 == memcmp(ipvmid, hvc_iucv_filter + (8 * i), 8))
+ for (i = 0; i < hvc_iucv_filter_size; i++) {
+ filter_entry = hvc_iucv_filter + (8 * i);
+
+ /* If a filter entry contains the filter wildcard character,
+ * reduce the length to match the leading portion of the user
+ * ID only (wildcard match). Characters following the wildcard
+ * are ignored.
+ */
+ wildcard = strnchr(filter_entry, 8, FILTER_WILDCARD_CHAR);
+ len = (wildcard) ? wildcard - filter_entry : 8;
+ if (0 == memcmp(ipvmid, filter_entry, len))
return 0;
+ }
return 1;
}
@@ -1166,6 +1178,7 @@ static void __init hvc_iucv_destroy(struct hvc_iucv_private *priv)
/**
* hvc_iucv_parse_filter() - Parse filter for a single z/VM user ID
* @filter: String containing a comma-separated list of z/VM user IDs
+ * @dest: Location where to store the parsed z/VM user ID
*/
static const char *hvc_iucv_parse_filter(const char *filter, char *dest)
{
@@ -1188,6 +1201,10 @@ static const char *hvc_iucv_parse_filter(const char *filter, char *dest)
if (filter[len - 1] == '\n')
len--;
+ /* prohibit filter entries containing the wildcard character only */
+ if (len == 1 && *filter == FILTER_WILDCARD_CHAR)
+ return ERR_PTR(-EINVAL);
+
if (len > 8)
return ERR_PTR(-EINVAL);
diff --git a/drivers/tty/isicom.c b/drivers/tty/isicom.c
index 59ed783c4bcd..2054427992e0 100644
--- a/drivers/tty/isicom.c
+++ b/drivers/tty/isicom.c
@@ -1055,7 +1055,7 @@ static int isicom_send_break(struct tty_struct *tty, int length)
outw(0x8000 | ((port->channel) << (card->shift_count)) | 0x3, base);
outw((length & 0xff) << 8 | 0x00, base);
- outw((length & 0xff00), base);
+ outw((length & 0xff00u), base);
InterruptTheCard(base);
unlock_card(card);
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 4ddfa60c9222..cf6e0f2e1331 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -90,6 +90,7 @@
struct n_tty_data {
/* producer-published */
size_t read_head;
+ size_t commit_head;
size_t canon_head;
size_t echo_head;
size_t echo_commit;
@@ -161,36 +162,11 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
return put_user(x, ptr);
}
-static int receive_room(struct tty_struct *tty)
-{
- struct n_tty_data *ldata = tty->disc_data;
- int left;
-
- if (I_PARMRK(tty)) {
- /* Multiply read_cnt by 3, since each byte might take up to
- * three times as many spaces when PARMRK is set (depending on
- * its flags, e.g. parity error). */
- left = N_TTY_BUF_SIZE - read_cnt(ldata) * 3 - 1;
- } else
- left = N_TTY_BUF_SIZE - read_cnt(ldata) - 1;
-
- /*
- * If we are doing input canonicalization, and there are no
- * pending newlines, let characters through without limit, so
- * that erase characters will be handled. Other excess
- * characters will be beeped.
- */
- if (left <= 0)
- left = ldata->icanon && ldata->canon_head == ldata->read_tail;
-
- return left;
-}
-
/**
- * n_tty_set_room - receive space
+ * n_tty_kick_worker - start input worker (if required)
* @tty: terminal
*
- * Re-schedules the flip buffer work if space just became available.
+ * Re-schedules the flip buffer work if it may have stopped
*
* Caller holds exclusive termios_rwsem
* or
@@ -198,12 +174,12 @@ static int receive_room(struct tty_struct *tty)
* holds non-exclusive termios_rwsem
*/
-static void n_tty_set_room(struct tty_struct *tty)
+static void n_tty_kick_worker(struct tty_struct *tty)
{
struct n_tty_data *ldata = tty->disc_data;
- /* Did this open up the receive buffer? We may need to flip */
- if (unlikely(ldata->no_room) && receive_room(tty)) {
+ /* Did the input worker stop? Restart it */
+ if (unlikely(ldata->no_room)) {
ldata->no_room = 0;
WARN_RATELIMIT(tty->port->itty == NULL,
@@ -224,7 +200,7 @@ static ssize_t chars_in_buffer(struct tty_struct *tty)
ssize_t n = 0;
if (!ldata->icanon)
- n = read_cnt(ldata);
+ n = ldata->commit_head - ldata->read_tail;
else
n = ldata->canon_head - ldata->read_tail;
return n;
@@ -247,17 +223,20 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
static void n_tty_check_throttle(struct tty_struct *tty)
{
- if (tty->driver->type == TTY_DRIVER_TYPE_PTY)
- return;
+ struct n_tty_data *ldata = tty->disc_data;
+
/*
* Check the remaining room for the input canonicalization
* mode. We don't want to throttle the driver if we're in
* canonical mode and don't have a newline yet!
*/
+ if (ldata->icanon && ldata->canon_head == ldata->read_tail)
+ return;
+
while (1) {
int throttled;
tty_set_flow_change(tty, TTY_THROTTLE_SAFE);
- if (receive_room(tty) >= TTY_THRESHOLD_THROTTLE)
+ if (N_TTY_BUF_SIZE - read_cnt(ldata) >= TTY_THRESHOLD_THROTTLE)
break;
throttled = tty_throttle_safe(tty);
if (!throttled)
@@ -274,7 +253,7 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
return;
if (!tty->count)
return;
- n_tty_set_room(tty);
+ n_tty_kick_worker(tty);
n_tty_write_wakeup(tty->link);
if (waitqueue_active(&tty->link->write_wait))
wake_up_interruptible_poll(&tty->link->write_wait, POLLOUT);
@@ -296,7 +275,7 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
break;
if (!tty->count)
break;
- n_tty_set_room(tty);
+ n_tty_kick_worker(tty);
unthrottled = tty_unthrottle_safe(tty);
if (!unthrottled)
break;
@@ -313,10 +292,6 @@ static void n_tty_check_unthrottle(struct tty_struct *tty)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
- * modifies read_head
- *
- * read_head is only considered 'published' if canonical mode is
- * not active.
*/
static inline void put_tty_queue(unsigned char c, struct n_tty_data *ldata)
@@ -340,6 +315,7 @@ static void reset_buffer_flags(struct n_tty_data *ldata)
{
ldata->read_head = ldata->canon_head = ldata->read_tail = 0;
ldata->echo_head = ldata->echo_tail = ldata->echo_commit = 0;
+ ldata->commit_head = 0;
ldata->echo_mark = 0;
ldata->line_start = 0;
@@ -379,7 +355,7 @@ static void n_tty_flush_buffer(struct tty_struct *tty)
{
down_write(&tty->termios_rwsem);
reset_buffer_flags(tty->disc_data);
- n_tty_set_room(tty);
+ n_tty_kick_worker(tty);
if (tty->link)
n_tty_packet_mode_flush(tty);
@@ -987,10 +963,6 @@ static inline void finish_erasing(struct n_tty_data *ldata)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
- * modifies read_head
- *
- * Modifying the read_head is not considered a publish in this context
- * because canonical mode is active -- only canon_head publishes
*/
static void eraser(unsigned char c, struct tty_struct *tty)
@@ -1118,16 +1090,45 @@ static void eraser(unsigned char c, struct tty_struct *tty)
* Called when a signal is being sent due to terminal input.
* Called from the driver receive_buf path so serialized.
*
+ * Performs input and output flush if !NOFLSH. In this context, the echo
+ * buffer is 'output'. The signal is processed first to alert any current
+ * readers or writers to discontinue and exit their i/o loops.
+ *
* Locking: ctrl_lock
*/
static void isig(int sig, struct tty_struct *tty)
{
+ struct n_tty_data *ldata = tty->disc_data;
struct pid *tty_pgrp = tty_get_pgrp(tty);
if (tty_pgrp) {
kill_pgrp(tty_pgrp, sig, 1);
put_pid(tty_pgrp);
}
+
+ if (!L_NOFLSH(tty)) {
+ up_read(&tty->termios_rwsem);
+ down_write(&tty->termios_rwsem);
+
+ /* clear echo buffer */
+ mutex_lock(&ldata->output_lock);
+ ldata->echo_head = ldata->echo_tail = 0;
+ ldata->echo_mark = ldata->echo_commit = 0;
+ mutex_unlock(&ldata->output_lock);
+
+ /* clear output buffer */
+ tty_driver_flush_buffer(tty);
+
+ /* clear input buffer */
+ reset_buffer_flags(tty->disc_data);
+
+ /* notify pty master of flush */
+ if (tty->link)
+ n_tty_packet_mode_flush(tty);
+
+ up_write(&tty->termios_rwsem);
+ down_read(&tty->termios_rwsem);
+ }
}
/**
@@ -1139,7 +1140,6 @@ static void isig(int sig, struct tty_struct *tty)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
- * publishes read_head via put_tty_queue()
*
* Note: may get exclusive termios_rwsem if flushing input buffer
*/
@@ -1152,13 +1152,6 @@ static void n_tty_receive_break(struct tty_struct *tty)
return;
if (I_BRKINT(tty)) {
isig(SIGINT, tty);
- if (!L_NOFLSH(tty)) {
- /* flushing needs exclusive termios_rwsem */
- up_read(&tty->termios_rwsem);
- n_tty_flush_buffer(tty);
- tty_driver_flush_buffer(tty);
- down_read(&tty->termios_rwsem);
- }
return;
}
if (I_PARMRK(tty)) {
@@ -1209,7 +1202,6 @@ static void n_tty_receive_overrun(struct tty_struct *tty)
*
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
- * publishes read_head via put_tty_queue()
*/
static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
{
@@ -1233,13 +1225,7 @@ static void n_tty_receive_parity_error(struct tty_struct *tty, unsigned char c)
static void
n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
{
- if (!L_NOFLSH(tty)) {
- /* flushing needs exclusive termios_rwsem */
- up_read(&tty->termios_rwsem);
- n_tty_flush_buffer(tty);
- tty_driver_flush_buffer(tty);
- down_read(&tty->termios_rwsem);
- }
+ isig(signal, tty);
if (I_IXON(tty))
start_tty(tty);
if (L_ECHO(tty)) {
@@ -1247,7 +1233,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
commit_echoes(tty);
} else
process_echoes(tty);
- isig(signal, tty);
return;
}
@@ -1263,7 +1248,6 @@ n_tty_receive_signal_char(struct tty_struct *tty, int signal, unsigned char c)
* n_tty_receive_buf()/producer path:
* caller holds non-exclusive termios_rwsem
* publishes canon_head if canonical mode is active
- * otherwise, publishes read_head via put_tty_queue()
*
* Returns 1 if LNEXT was received, else returns 0
*/
@@ -1376,7 +1360,7 @@ n_tty_receive_char_special(struct tty_struct *tty, unsigned char c)
handle_newline:
set_bit(ldata->read_head & (N_TTY_BUF_SIZE - 1), ldata->read_flags);
put_tty_queue(c, ldata);
- ldata->canon_head = ldata->read_head;
+ smp_store_release(&ldata->canon_head, ldata->read_head);
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
@@ -1512,23 +1496,6 @@ n_tty_receive_char_lnext(struct tty_struct *tty, unsigned char c, char flag)
n_tty_receive_char_flagged(tty, c, flag);
}
-/**
- * n_tty_receive_buf - data receive
- * @tty: terminal device
- * @cp: buffer
- * @fp: flag buffer
- * @count: characters
- *
- * Called by the terminal driver when a block of characters has
- * been received. This function must be called from soft contexts
- * not from interrupt context. The driver is responsible for making
- * calls one at a time and in order (or using flush_to_ldisc)
- *
- * n_tty_receive_buf()/producer path:
- * claims non-exclusive termios_rwsem
- * publishes read_head and canon_head
- */
-
static void
n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count)
@@ -1537,16 +1504,14 @@ n_tty_receive_buf_real_raw(struct tty_struct *tty, const unsigned char *cp,
size_t n, head;
head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
- n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
- n = min_t(size_t, count, n);
+ n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
memcpy(read_buf_addr(ldata, head), cp, n);
ldata->read_head += n;
cp += n;
count -= n;
head = ldata->read_head & (N_TTY_BUF_SIZE - 1);
- n = N_TTY_BUF_SIZE - max(read_cnt(ldata), head);
- n = min_t(size_t, count, n);
+ n = min_t(size_t, count, N_TTY_BUF_SIZE - head);
memcpy(read_buf_addr(ldata, head), cp, n);
ldata->read_head += n;
}
@@ -1676,32 +1641,98 @@ static void __receive_buf(struct tty_struct *tty, const unsigned char *cp,
tty->ops->flush_chars(tty);
}
- if ((!ldata->icanon && (read_cnt(ldata) >= ldata->minimum_to_wake)) ||
- L_EXTPROC(tty)) {
+ if (ldata->icanon && !L_EXTPROC(tty))
+ return;
+
+ /* publish read_head to consumer */
+ smp_store_release(&ldata->commit_head, ldata->read_head);
+
+ if ((read_cnt(ldata) >= ldata->minimum_to_wake) || L_EXTPROC(tty)) {
kill_fasync(&tty->fasync, SIGIO, POLL_IN);
if (waitqueue_active(&tty->read_wait))
wake_up_interruptible_poll(&tty->read_wait, POLLIN);
}
}
+/**
+ * n_tty_receive_buf_common - process input
+ * @tty: device to receive input
+ * @cp: input chars
+ * @fp: flags for each char (if NULL, all chars are TTY_NORMAL)
+ * @count: number of input chars in @cp
+ *
+ * Called by the terminal driver when a block of characters has
+ * been received. This function must be called from soft contexts
+ * not from interrupt context. The driver is responsible for making
+ * calls one at a time and in order (or using flush_to_ldisc)
+ *
+ * Returns the # of input chars from @cp which were processed.
+ *
+ * In canonical mode, the maximum line length is 4096 chars (including
+ * the line termination char); lines longer than 4096 chars are
+ * truncated. After 4095 chars, input data is still processed but
+ * not stored. Overflow processing ensures the tty can always
+ * receive more input until at least one line can be read.
+ *
+ * In non-canonical mode, the read buffer will only accept 4095 chars;
+ * this provides the necessary space for a newline char if the input
+ * mode is switched to canonical.
+ *
+ * Note it is possible for the read buffer to _contain_ 4096 chars
+ * in non-canonical mode: the read buffer could already contain the
+ * maximum canon line of 4096 chars when the mode is switched to
+ * non-canonical.
+ *
+ * n_tty_receive_buf()/producer path:
+ * claims non-exclusive termios_rwsem
+ * publishes commit_head or canon_head
+ */
static int
n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
char *fp, int count, int flow)
{
struct n_tty_data *ldata = tty->disc_data;
- int room, n, rcvd = 0;
+ int room, n, rcvd = 0, overflow;
down_read(&tty->termios_rwsem);
while (1) {
- room = receive_room(tty);
+ /*
+ * When PARMRK is set, each input char may take up to 3 chars
+ * in the read buf; reduce the buffer space avail by 3x
+ *
+ * If we are doing input canonicalization, and there are no
+ * pending newlines, let characters through without limit, so
+ * that erase characters will be handled. Other excess
+ * characters will be beeped.
+ *
+ * paired with store in *_copy_from_read_buf() -- guarantees
+ * the consumer has loaded the data in read_buf up to the new
+ * read_tail (so this producer will not overwrite unread data)
+ */
+ size_t tail = smp_load_acquire(&ldata->read_tail);
+
+ room = N_TTY_BUF_SIZE - (ldata->read_head - tail);
+ if (I_PARMRK(tty))
+ room = (room + 2) / 3;
+ room--;
+ if (room <= 0) {
+ overflow = ldata->icanon && ldata->canon_head == tail;
+ if (overflow && room < 0)
+ ldata->read_head--;
+ room = overflow;
+ ldata->no_room = flow && !room;
+ } else
+ overflow = 0;
+
n = min(count, room);
- if (!n) {
- if (flow && !room)
- ldata->no_room = 1;
+ if (!n)
break;
- }
- __receive_buf(tty, cp, fp, n);
+
+ /* ignore parity errors if handling overflow */
+ if (!overflow || !fp || *fp != TTY_PARITY)
+ __receive_buf(tty, cp, fp, n);
+
cp += n;
if (fp)
fp += n;
@@ -1710,7 +1741,17 @@ n_tty_receive_buf_common(struct tty_struct *tty, const unsigned char *cp,
}
tty->receive_room = room;
- n_tty_check_throttle(tty);
+
+ /* Unthrottle if handling overflow on pty */
+ if (tty->driver->type == TTY_DRIVER_TYPE_PTY) {
+ if (overflow) {
+ tty_set_flow_change(tty, TTY_UNTHROTTLE_SAFE);
+ tty_unthrottle_safe(tty);
+ __tty_set_flow_change(tty, 0);
+ }
+ } else
+ n_tty_check_throttle(tty);
+
up_read(&tty->termios_rwsem);
return rcvd;
@@ -1764,6 +1805,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
ldata->canon_head = ldata->read_head;
ldata->push = 1;
}
+ ldata->commit_head = ldata->read_head;
ldata->erasing = 0;
ldata->lnext = 0;
}
@@ -1817,7 +1859,6 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
else
ldata->real_raw = 0;
}
- n_tty_set_room(tty);
/*
* Fix tty hang when I_IXON(tty) is cleared, but the tty
* been stopped by STOP_CHAR(tty) before it.
@@ -1905,7 +1946,7 @@ static inline int input_available_p(struct tty_struct *tty, int poll)
if (ldata->icanon && !L_EXTPROC(tty))
return ldata->canon_head != ldata->read_tail;
else
- return read_cnt(ldata) >= amt;
+ return ldata->commit_head - ldata->read_tail >= amt;
}
/**
@@ -1937,10 +1978,11 @@ static int copy_from_read_buf(struct tty_struct *tty,
int retval;
size_t n;
bool is_eof;
+ size_t head = smp_load_acquire(&ldata->commit_head);
size_t tail = ldata->read_tail & (N_TTY_BUF_SIZE - 1);
retval = 0;
- n = min(read_cnt(ldata), N_TTY_BUF_SIZE - tail);
+ n = min(head - ldata->read_tail, N_TTY_BUF_SIZE - tail);
n = min(*nr, n);
if (n) {
retval = copy_to_user(*b, read_buf_addr(ldata, tail), n);
@@ -1948,9 +1990,10 @@ static int copy_from_read_buf(struct tty_struct *tty,
is_eof = n == 1 && read_buf(ldata, tail) == EOF_CHAR(tty);
tty_audit_add_data(tty, read_buf_addr(ldata, tail), n,
ldata->icanon);
- ldata->read_tail += n;
+ smp_store_release(&ldata->read_tail, ldata->read_tail + n);
/* Turn single EOF into zero-length read */
- if (L_EXTPROC(tty) && ldata->icanon && is_eof && !read_cnt(ldata))
+ if (L_EXTPROC(tty) && ldata->icanon && is_eof &&
+ (head == ldata->read_tail))
n = 0;
*b += n;
*nr -= n;
@@ -1993,7 +2036,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
bool eof_push = 0;
/* N.B. avoid overrun if nr == 0 */
- n = min(*nr, read_cnt(ldata));
+ n = min(*nr, smp_load_acquire(&ldata->canon_head) - ldata->read_tail);
if (!n)
return 0;
@@ -2043,8 +2086,7 @@ static int canon_copy_from_read_buf(struct tty_struct *tty,
if (found)
clear_bit(eol, ldata->read_flags);
- smp_mb__after_atomic();
- ldata->read_tail += c;
+ smp_store_release(&ldata->read_tail, ldata->read_tail + c);
if (found) {
if (!ldata->push)
@@ -2130,6 +2172,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
ssize_t retval = 0;
long timeout;
int packet;
+ size_t tail;
c = job_control(tty, file);
if (c < 0)
@@ -2166,6 +2209,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
}
packet = tty->packet;
+ tail = ldata->read_tail;
add_wait_queue(&tty->read_wait, &wait);
while (nr) {
@@ -2208,7 +2252,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
retval = -ERESTARTSYS;
break;
}
- n_tty_set_room(tty);
up_read(&tty->termios_rwsem);
timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
@@ -2253,7 +2296,8 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
if (time)
timeout = time;
}
- n_tty_set_room(tty);
+ if (tail != ldata->read_tail)
+ n_tty_kick_worker(tty);
up_read(&tty->termios_rwsem);
remove_wait_queue(&tty->read_wait, &wait);
diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c
index a9d256d6e909..e72ee629cead 100644
--- a/drivers/tty/pty.c
+++ b/drivers/tty/pty.c
@@ -88,19 +88,6 @@ static void pty_unthrottle(struct tty_struct *tty)
}
/**
- * pty_space - report space left for writing
- * @to: tty we are writing into
- *
- * Limit the buffer space used by ptys to 8k.
- */
-
-static int pty_space(struct tty_struct *to)
-{
- int n = tty_buffer_space_avail(to->port);
- return min(n, 8192);
-}
-
-/**
* pty_write - write to a pty
* @tty: the tty we write from
* @buf: kernel buffer of data
@@ -141,7 +128,7 @@ static int pty_write_room(struct tty_struct *tty)
{
if (tty->stopped)
return 0;
- return pty_space(tty->link);
+ return tty_buffer_space_avail(tty->link->port);
}
/**
@@ -210,6 +197,9 @@ static int pty_signal(struct tty_struct *tty, int sig)
{
struct pid *pgrp;
+ if (sig != SIGINT && sig != SIGQUIT && sig != SIGTSTP)
+ return -EINVAL;
+
if (tty->link) {
pgrp = tty_get_pgrp(tty->link);
if (pgrp)
@@ -222,10 +212,16 @@ static int pty_signal(struct tty_struct *tty, int sig)
static void pty_flush_buffer(struct tty_struct *tty)
{
struct tty_struct *to = tty->link;
+ struct tty_ldisc *ld;
if (!to)
return;
- /* tty_buffer_flush(to); FIXME */
+
+ ld = tty_ldisc_ref(to);
+ tty_buffer_flush(to, ld);
+ if (ld)
+ tty_ldisc_deref(ld);
+
if (to->packet) {
spin_lock_irq(&tty->ctrl_lock);
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
@@ -399,6 +395,7 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
goto err_put_module;
tty_set_lock_subclass(o_tty);
+ lockdep_set_subclass(&o_tty->termios_rwsem, TTY_LOCK_SLAVE);
if (legacy) {
/* We always use new tty termios data so we can do this
@@ -429,10 +426,14 @@ static int pty_common_install(struct tty_driver *driver, struct tty_struct *tty,
o_tty->link = tty;
tty_port_init(ports[0]);
tty_port_init(ports[1]);
+ tty_buffer_set_limit(ports[0], 8192);
+ tty_buffer_set_limit(ports[1], 8192);
o_tty->port = ports[0];
tty->port = ports[1];
o_tty->port->itty = o_tty;
+ tty_buffer_set_lock_subclass(o_tty->port);
+
tty_driver_kref_get(driver);
tty->count++;
o_tty->count++;
diff --git a/drivers/tty/rocket.c b/drivers/tty/rocket.c
index 383c4c796637..c8dd8dc31086 100644
--- a/drivers/tty/rocket.c
+++ b/drivers/tty/rocket.c
@@ -1390,7 +1390,7 @@ static void rp_unthrottle(struct tty_struct *tty)
tty->ldisc.chars_in_buffer(tty));
#endif
- if (rocket_paranoia_check(info, "rp_throttle"))
+ if (rocket_paranoia_check(info, "rp_unthrottle"))
return;
if (I_IXOFF(tty))
@@ -1458,7 +1458,7 @@ static void rp_wait_until_sent(struct tty_struct *tty, int timeout)
orig_jiffies = jiffies;
#ifdef ROCKET_DEBUG_WAIT_UNTIL_SENT
- printk(KERN_INFO "In RP_wait_until_sent(%d) (jiff=%lu)...\n", timeout,
+ printk(KERN_INFO "In %s(%d) (jiff=%lu)...\n", __func__, timeout,
jiffies);
printk(KERN_INFO "cps=%d...\n", info->cps);
#endif
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index 11c66856ba2f..e3b9570a1eff 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -329,6 +329,17 @@ static const struct serial8250_config uart_config[] = {
.fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10,
.flags = UART_CAP_FIFO | UART_CAP_AFE,
},
+/* tx_loadsz is set to 63-bytes instead of 64-bytes to implement
+workaround of errata A-008006 which states that tx_loadsz should be
+configured less than Maximum supported fifo bytes */
+ [PORT_16550A_FSL64] = {
+ .name = "16550A_FSL64",
+ .fifo_size = 64,
+ .tx_loadsz = 63,
+ .fcr = UART_FCR_ENABLE_FIFO | UART_FCR_R_TRIG_10 |
+ UART_FCR7_64BYTE,
+ .flags = UART_CAP_FIFO,
+ },
};
/* Uart divisor latch read */
@@ -956,7 +967,17 @@ static void autoconfig_16550a(struct uart_8250_port *up)
up->port.type = PORT_16650;
up->capabilities |= UART_CAP_EFR | UART_CAP_SLEEP;
} else {
- DEBUG_AUTOCONF("Motorola 8xxx DUART ");
+ serial_out(up, UART_LCR, 0);
+ serial_out(up, UART_FCR, UART_FCR_ENABLE_FIFO |
+ UART_FCR7_64BYTE);
+ status1 = serial_in(up, UART_IIR) >> 5;
+ serial_out(up, UART_FCR, 0);
+ serial_out(up, UART_LCR, 0);
+
+ if (status1 == 7)
+ up->port.type = PORT_16550A_FSL64;
+ else
+ DEBUG_AUTOCONF("Motorola 8xxx DUART ");
}
serial_out(up, UART_EFR, 0);
return;
@@ -1355,9 +1376,11 @@ static void serial8250_start_tx(struct uart_port *port)
struct uart_8250_port *up = up_to_u8250p(port);
serial8250_rpm_get_tx(up);
- if (up->dma && !up->dma->tx_dma(up)) {
+
+ if (up->dma && !up->dma->tx_dma(up))
return;
- } else if (!(up->ier & UART_IER_THRI)) {
+
+ if (!(up->ier & UART_IER_THRI)) {
up->ier |= UART_IER_THRI;
serial_port_out(port, UART_IER, up->ier);
@@ -1365,7 +1388,7 @@ static void serial8250_start_tx(struct uart_port *port)
unsigned char lsr;
lsr = serial_in(up, UART_LSR);
up->lsr_saved_flags |= lsr & LSR_SAVE_FLAGS;
- if (lsr & UART_LSR_TEMT)
+ if (lsr & UART_LSR_THRE)
serial8250_tx_chars(up);
}
}
@@ -1924,7 +1947,7 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port)
return ret;
}
-static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_8250_port *up = up_to_u8250p(port);
unsigned char mcr = 0;
@@ -1944,6 +1967,14 @@ static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
serial_port_out(port, UART_MCR, mcr);
}
+EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl);
+
+static void serial8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ if (port->set_mctrl)
+ return port->set_mctrl(port, mctrl);
+ return serial8250_do_set_mctrl(port, mctrl);
+}
static void serial8250_break_ctl(struct uart_port *port, int break_state)
{
@@ -2382,13 +2413,34 @@ static void serial8250_shutdown(struct uart_port *port)
serial8250_do_shutdown(port);
}
-static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int baud)
+/*
+ * XR17V35x UARTs have an extra fractional divisor register (DLD)
+ * Calculate divisor with extra 4-bit fractional portion
+ */
+static unsigned int xr17v35x_get_divisor(struct uart_8250_port *up,
+ unsigned int baud,
+ unsigned int *frac)
+{
+ struct uart_port *port = &up->port;
+ unsigned int quot_16;
+
+ quot_16 = DIV_ROUND_CLOSEST(port->uartclk, baud);
+ *frac = quot_16 & 0x0f;
+
+ return quot_16 >> 4;
+}
+
+static unsigned int serial8250_get_divisor(struct uart_8250_port *up,
+ unsigned int baud,
+ unsigned int *frac)
{
+ struct uart_port *port = &up->port;
unsigned int quot;
/*
* Handle magic divisors for baud rates above baud_base on
* SMSC SuperIO chips.
+ *
*/
if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/4))
@@ -2396,22 +2448,26 @@ static unsigned int serial8250_get_divisor(struct uart_port *port, unsigned int
else if ((port->flags & UPF_MAGIC_MULTIPLIER) &&
baud == (port->uartclk/8))
quot = 0x8002;
+ else if (up->port.type == PORT_XR17V35X)
+ quot = xr17v35x_get_divisor(up, baud, frac);
else
quot = uart_get_divisor(port, baud);
+ /*
+ * Oxford Semi 952 rev B workaround
+ */
+ if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
+ quot++;
+
return quot;
}
-void
-serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
+static unsigned char serial8250_compute_lcr(struct uart_8250_port *up,
+ tcflag_t c_cflag)
{
- struct uart_8250_port *up = up_to_u8250p(port);
unsigned char cval;
- unsigned long flags;
- unsigned int baud, quot;
- switch (termios->c_cflag & CSIZE) {
+ switch (c_cflag & CSIZE) {
case CS5:
cval = UART_LCR_WLEN5;
break;
@@ -2427,33 +2483,80 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
break;
}
- if (termios->c_cflag & CSTOPB)
+ if (c_cflag & CSTOPB)
cval |= UART_LCR_STOP;
- if (termios->c_cflag & PARENB) {
+ if (c_cflag & PARENB) {
cval |= UART_LCR_PARITY;
if (up->bugs & UART_BUG_PARITY)
up->fifo_bug = true;
}
- if (!(termios->c_cflag & PARODD))
+ if (!(c_cflag & PARODD))
cval |= UART_LCR_EPAR;
#ifdef CMSPAR
- if (termios->c_cflag & CMSPAR)
+ if (c_cflag & CMSPAR)
cval |= UART_LCR_SPAR;
#endif
+ return cval;
+}
+
+static void serial8250_set_divisor(struct uart_port *port, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+
+ /* Workaround to enable 115200 baud on OMAP1510 internal ports */
+ if (is_omap1510_8250(up)) {
+ if (baud == 115200) {
+ quot = 1;
+ serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
+ } else
+ serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
+ }
+
+ /*
+ * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
+ * otherwise just set DLAB
+ */
+ if (up->capabilities & UART_NATSEMI)
+ serial_port_out(port, UART_LCR, 0xe0);
+ else
+ serial_port_out(port, UART_LCR, up->lcr | UART_LCR_DLAB);
+
+ serial_dl_write(up, quot);
+
+ /* XR17V35x UARTs have an extra fractional divisor register (DLD) */
+ if (up->port.type == PORT_XR17V35X)
+ serial_port_out(port, 0x2, quot_frac);
+}
+
+void
+serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ unsigned char cval;
+ unsigned long flags;
+ unsigned int baud, quot, frac = 0;
+
+ cval = serial8250_compute_lcr(up, termios->c_cflag);
+
/*
* Ask the core to calculate the divisor for us.
*/
baud = uart_get_baud_rate(port, termios, old,
port->uartclk / 16 / 0xffff,
port->uartclk / 16);
- quot = serial8250_get_divisor(port, baud);
+ quot = serial8250_get_divisor(up, baud, &frac);
/*
- * Oxford Semi 952 rev B workaround
+ * Ok, we're now changing the port state. Do it with
+ * interrupts disabled.
*/
- if (up->bugs & UART_BUG_QUOT && (quot & 0xff) == 0)
- quot++;
+ serial8250_rpm_get(up);
+ spin_lock_irqsave(&port->lock, flags);
+
+ up->lcr = cval; /* Save computed LCR */
if (up->capabilities & UART_CAP_FIFO && port->fifosize > 1) {
/* NOTE: If fifo_bug is not set, a user can set RX_trigger. */
@@ -2478,13 +2581,6 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
}
/*
- * Ok, we're now changing the port state. Do it with
- * interrupts disabled.
- */
- serial8250_rpm_get(up);
- spin_lock_irqsave(&port->lock, flags);
-
- /*
* Update the per-port timeout.
*/
uart_update_timeout(port, termios->c_cflag, baud);
@@ -2548,43 +2644,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial_port_out(port, UART_EFR, efr);
}
- /* Workaround to enable 115200 baud on OMAP1510 internal ports */
- if (is_omap1510_8250(up)) {
- if (baud == 115200) {
- quot = 1;
- serial_port_out(port, UART_OMAP_OSC_12M_SEL, 1);
- } else
- serial_port_out(port, UART_OMAP_OSC_12M_SEL, 0);
- }
-
- /*
- * For NatSemi, switch to bank 2 not bank 1, to avoid resetting EXCR2,
- * otherwise just set DLAB
- */
- if (up->capabilities & UART_NATSEMI)
- serial_port_out(port, UART_LCR, 0xe0);
- else
- serial_port_out(port, UART_LCR, cval | UART_LCR_DLAB);
-
- serial_dl_write(up, quot);
-
- /*
- * XR17V35x UARTs have an extra fractional divisor register (DLD)
- *
- * We need to recalculate all of the registers, because DLM and DLL
- * are already rounded to a whole integer.
- *
- * When recalculating we use a 32x clock instead of a 16x clock to
- * allow 1-bit for rounding in the fractional part.
- */
- if (up->port.type == PORT_XR17V35X) {
- unsigned int baud_x32 = (port->uartclk * 2) / baud;
- u16 quot = baud_x32 / 32;
- u8 quot_frac = DIV_ROUND_CLOSEST(baud_x32 % 32, 2);
-
- serial_dl_write(up, quot);
- serial_port_out(port, 0x2, quot_frac & 0xf);
- }
+ serial8250_set_divisor(port, baud, quot, frac);
/*
* LCR DLAB must be set to enable 64-byte FIFO mode. If the FCR
@@ -2593,8 +2653,7 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
if (port->type == PORT_16750)
serial_port_out(port, UART_FCR, up->fcr);
- serial_port_out(port, UART_LCR, cval); /* reset DLAB */
- up->lcr = cval; /* Save LCR */
+ serial_port_out(port, UART_LCR, up->lcr); /* reset DLAB */
if (port->type != PORT_16750) {
/* emulated UARTs (Lucent Venus 167x) need two steps */
if (up->fcr & UART_FCR_ENABLE_FIFO)
@@ -3208,6 +3267,27 @@ serial8250_console_write(struct console *co, const char *s, unsigned int count)
else
serial_port_out(port, UART_IER, 0);
+ /* check scratch reg to see if port powered off during system sleep */
+ if (up->canary && (up->canary != serial_port_in(port, UART_SCR))) {
+ struct ktermios termios;
+ unsigned int baud, quot, frac = 0;
+
+ termios.c_cflag = port->cons->cflag;
+ if (port->state->port.tty && termios.c_cflag == 0)
+ termios.c_cflag = port->state->port.tty->termios.c_cflag;
+
+ baud = uart_get_baud_rate(port, &termios, NULL,
+ port->uartclk / 16 / 0xffff,
+ port->uartclk / 16);
+ quot = serial8250_get_divisor(up, baud, &frac);
+
+ serial8250_set_divisor(port, baud, quot, frac);
+ serial_port_out(port, UART_LCR, up->lcr);
+ serial_port_out(port, UART_MCR, UART_MCR_DTR | UART_MCR_RTS);
+
+ up->canary = 0;
+ }
+
uart_console_write(port, s, count, serial8250_console_putchar);
/*
@@ -3358,7 +3438,17 @@ int __init early_serial_setup(struct uart_port *port)
*/
void serial8250_suspend_port(int line)
{
- uart_suspend_port(&serial8250_reg, &serial8250_ports[line].port);
+ struct uart_8250_port *up = &serial8250_ports[line];
+ struct uart_port *port = &up->port;
+
+ if (!console_suspend_enabled && uart_console(port) &&
+ port->type != PORT_8250) {
+ unsigned char canary = 0xa5;
+ serial_out(up, UART_SCR, canary);
+ up->canary = canary;
+ }
+
+ uart_suspend_port(&serial8250_reg, port);
}
/**
@@ -3372,6 +3462,8 @@ void serial8250_resume_port(int line)
struct uart_8250_port *up = &serial8250_ports[line];
struct uart_port *port = &up->port;
+ up->canary = 0;
+
if (up->capabilities & UART_NATSEMI) {
/* Ensure it's still in high speed mode */
serial_port_out(port, UART_LCR, 0xE0);
@@ -3605,6 +3697,8 @@ int serial8250_register_8250_port(struct uart_8250_port *up)
/* Possibly override set_termios call */
if (up->port.set_termios)
uart->port.set_termios = up->port.set_termios;
+ if (up->port.set_mctrl)
+ uart->port.set_mctrl = up->port.set_mctrl;
if (up->port.startup)
uart->port.startup = up->port.startup;
if (up->port.shutdown)
diff --git a/drivers/tty/serial/8250/8250_dma.c b/drivers/tty/serial/8250/8250_dma.c
index fcd7ac6af2fc..21d01a491405 100644
--- a/drivers/tty/serial/8250/8250_dma.c
+++ b/drivers/tty/serial/8250/8250_dma.c
@@ -59,7 +59,6 @@ static void __dma_rx_complete(void *param)
dma->rx_running = 0;
dmaengine_tx_status(dma->rxchan, dma->rx_cookie, &state);
- dmaengine_terminate_all(dma->rxchan);
count = dma->rx_size - state.residue;
@@ -81,6 +80,10 @@ int serial8250_tx_dma(struct uart_8250_port *p)
return 0;
dma->tx_size = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+ if (dma->tx_size < p->port.fifosize) {
+ ret = -EINVAL;
+ goto err;
+ }
desc = dmaengine_prep_slave_single(dma->txchan,
dma->tx_addr + xmit->tail,
@@ -131,6 +134,7 @@ int serial8250_rx_dma(struct uart_8250_port *p, unsigned int iir)
if (dma->rx_running) {
dmaengine_pause(dma->rxchan);
__dma_rx_complete(p);
+ dmaengine_terminate_all(dma->rxchan);
}
return -ETIMEDOUT;
default:
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 555de07db593..e60116235836 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -351,10 +351,20 @@ static int dw8250_probe_of(struct uart_port *p,
static int dw8250_probe_acpi(struct uart_8250_port *up,
struct dw8250_data *data)
{
+ const struct acpi_device_id *id;
struct uart_port *p = &up->port;
dw8250_setup_port(up);
+ id = acpi_match_device(p->dev->driver->acpi_match_table, p->dev);
+ if (!id)
+ return -ENODEV;
+
+ if (!p->uartclk)
+ if (device_property_read_u32(p->dev, "clock-frequency",
+ &p->uartclk))
+ return -EINVAL;
+
p->iotype = UPIO_MEM32;
p->serial_in = dw8250_serial_in32;
p->serial_out = dw8250_serial_out32;
@@ -577,6 +587,7 @@ static const struct acpi_device_id dw8250_acpi_match[] = {
{ "INT3435", 0 },
{ "80860F0A", 0 },
{ "8086228A", 0 },
+ { "APMC0D08", 0},
{ },
};
MODULE_DEVICE_TABLE(acpi, dw8250_acpi_match);
diff --git a/drivers/tty/serial/8250/8250_early.c b/drivers/tty/serial/8250/8250_early.c
index 4858b8a99d3b..c31a22b4f845 100644
--- a/drivers/tty/serial/8250/8250_early.c
+++ b/drivers/tty/serial/8250/8250_early.c
@@ -93,15 +93,18 @@ static void __init early_serial8250_write(struct console *console,
struct uart_port *port = &early_device->port;
unsigned int ier;
- /* Save the IER and disable interrupts */
+ /* Save the IER and disable interrupts preserving the UUE bit */
ier = serial8250_early_in(port, UART_IER);
- serial8250_early_out(port, UART_IER, 0);
+ if (ier)
+ serial8250_early_out(port, UART_IER, ier & UART_IER_UUE);
uart_console_write(port, s, count, serial_putc);
/* Wait for transmitter to become empty and restore the IER */
wait_for_xmitr(port);
- serial8250_early_out(port, UART_IER, ier);
+
+ if (ier)
+ serial8250_early_out(port, UART_IER, ier);
}
static unsigned int __init probe_baud(struct uart_port *port)
@@ -124,9 +127,11 @@ static void __init init_port(struct earlycon_device *device)
struct uart_port *port = &device->port;
unsigned int divisor;
unsigned char c;
+ unsigned int ier;
serial8250_early_out(port, UART_LCR, 0x3); /* 8n1 */
- serial8250_early_out(port, UART_IER, 0); /* no interrupt */
+ ier = serial8250_early_in(port, UART_IER);
+ serial8250_early_out(port, UART_IER, ier & UART_IER_UUE); /* no interrupt */
serial8250_early_out(port, UART_FCR, 0); /* no fifo */
serial8250_early_out(port, UART_MCR, 0x3); /* DTR + RTS */
diff --git a/drivers/tty/serial/8250/8250_omap.c b/drivers/tty/serial/8250/8250_omap.c
index 96b69bfd773f..fe6d2e51da09 100644
--- a/drivers/tty/serial/8250/8250_omap.c
+++ b/drivers/tty/serial/8250/8250_omap.c
@@ -106,6 +106,28 @@ static u32 uart_read(struct uart_8250_port *up, u32 reg)
return readl(up->port.membase + (reg << up->port.regshift));
}
+static void omap8250_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_8250_port *up = up_to_u8250p(port);
+ struct omap8250_priv *priv = up->port.private_data;
+ u8 lcr;
+
+ serial8250_do_set_mctrl(port, mctrl);
+
+ /*
+ * Turn off autoRTS if RTS is lowered and restore autoRTS setting
+ * if RTS is raised
+ */
+ lcr = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+ priv->efr |= UART_EFR_RTS;
+ else
+ priv->efr &= ~UART_EFR_RTS;
+ serial_out(up, UART_EFR, priv->efr);
+ serial_out(up, UART_LCR, lcr);
+}
+
/*
* Work Around for Errata i202 (2430, 3430, 3630, 4430 and 4460)
* The access to uart register after MDR1 Access
@@ -397,12 +419,12 @@ static void omap_8250_set_termios(struct uart_port *port,
priv->efr = 0;
up->mcr &= ~(UART_MCR_RTS | UART_MCR_XONANY);
- if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
- /* Enable AUTORTS and AUTOCTS */
- priv->efr |= UART_EFR_CTS | UART_EFR_RTS;
+ up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
- /* Ensure MCR RTS is asserted */
- up->mcr |= UART_MCR_RTS;
+ if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+ /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
+ up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+ priv->efr |= UART_EFR_CTS;
} else if (up->port.flags & UPF_SOFT_FLOW) {
/*
* IXON Flag:
@@ -417,8 +439,10 @@ static void omap_8250_set_termios(struct uart_port *port,
* Enable XON/XOFF flow control on output.
* Transmit XON1, XOFF1
*/
- if (termios->c_iflag & IXOFF)
+ if (termios->c_iflag & IXOFF) {
+ up->port.status |= UPSTAT_AUTOXOFF;
priv->efr |= OMAP_UART_SW_TX;
+ }
/*
* IXANY Flag:
@@ -450,18 +474,18 @@ static void omap_8250_set_termios(struct uart_port *port,
static void omap_8250_pm(struct uart_port *port, unsigned int state,
unsigned int oldstate)
{
- struct uart_8250_port *up =
- container_of(port, struct uart_8250_port, port);
- struct omap8250_priv *priv = up->port.private_data;
+ struct uart_8250_port *up = up_to_u8250p(port);
+ u8 efr;
pm_runtime_get_sync(port->dev);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, priv->efr | UART_EFR_ECB);
+ efr = serial_in(up, UART_EFR);
+ serial_out(up, UART_EFR, efr | UART_EFR_ECB);
serial_out(up, UART_LCR, 0);
serial_out(up, UART_IER, (state != 0) ? UART_IERX_SLEEP : 0);
serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
- serial_out(up, UART_EFR, priv->efr);
+ serial_out(up, UART_EFR, efr);
serial_out(up, UART_LCR, 0);
pm_runtime_mark_last_busy(port->dev);
@@ -1007,6 +1031,7 @@ static int omap8250_probe(struct platform_device *pdev)
up.capabilities |= UART_CAP_RPM;
#endif
up.port.set_termios = omap_8250_set_termios;
+ up.port.set_mctrl = omap8250_set_mctrl;
up.port.pm = omap_8250_pm;
up.port.startup = omap_8250_startup;
up.port.shutdown = omap_8250_shutdown;
@@ -1248,6 +1273,46 @@ static int omap8250_runtime_resume(struct device *dev)
}
#endif
+#ifdef CONFIG_SERIAL_8250_OMAP_TTYO_FIXUP
+static int __init omap8250_console_fixup(void)
+{
+ char *omap_str;
+ char *options;
+ u8 idx;
+
+ if (strstr(boot_command_line, "console=ttyS"))
+ /* user set a ttyS based name for the console */
+ return 0;
+
+ omap_str = strstr(boot_command_line, "console=ttyO");
+ if (!omap_str)
+ /* user did not set ttyO based console, so we don't care */
+ return 0;
+
+ omap_str += 12;
+ if ('0' <= *omap_str && *omap_str <= '9')
+ idx = *omap_str - '0';
+ else
+ return 0;
+
+ omap_str++;
+ if (omap_str[0] == ',') {
+ omap_str++;
+ options = omap_str;
+ } else {
+ options = NULL;
+ }
+
+ add_preferred_console("ttyS", idx, options);
+ pr_err("WARNING: Your 'console=ttyO%d' has been replaced by 'ttyS%d'\n",
+ idx, idx);
+ pr_err("This ensures that you still see kernel messages. Please\n");
+ pr_err("update your kernel commandline.\n");
+ return 0;
+}
+console_initcall(omap8250_console_fixup);
+#endif
+
static const struct dev_pm_ops omap8250_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(omap8250_suspend, omap8250_resume)
SET_RUNTIME_PM_OPS(omap8250_runtime_suspend,
@@ -1269,7 +1334,6 @@ static struct platform_driver omap8250_platform_driver = {
.name = "omap8250",
.pm = &omap8250_dev_pm_ops,
.of_match_table = omap8250_dt_ids,
- .owner = THIS_MODULE,
},
.probe = omap8250_probe,
.remove = omap8250_remove,
diff --git a/drivers/tty/serial/8250/8250_pci.c b/drivers/tty/serial/8250/8250_pci.c
index d1f8dc6aabcb..daf2c82984e9 100644
--- a/drivers/tty/serial/8250/8250_pci.c
+++ b/drivers/tty/serial/8250/8250_pci.c
@@ -221,13 +221,13 @@ pci_hp_diva_setup(struct serial_private *priv,
*/
static int pci_inteli960ni_init(struct pci_dev *dev)
{
- unsigned long oldval;
+ u32 oldval;
if (!(dev->subsystem_device & 0x1000))
return -ENODEV;
/* is firmware started? */
- pci_read_config_dword(dev, 0x44, (void *)&oldval);
+ pci_read_config_dword(dev, 0x44, &oldval);
if (oldval == 0x00001000L) { /* RESET value */
dev_dbg(&dev->dev, "Local i960 firmware missing\n");
return -ENODEV;
diff --git a/drivers/tty/serial/8250/8250_pnp.c b/drivers/tty/serial/8250/8250_pnp.c
index 682a2fbe5c06..50a09cd76d50 100644
--- a/drivers/tty/serial/8250/8250_pnp.c
+++ b/drivers/tty/serial/8250/8250_pnp.c
@@ -426,7 +426,7 @@ static int serial_pnp_guess_board(struct pnp_dev *dev)
static int
serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
{
- struct uart_8250_port uart;
+ struct uart_8250_port uart, *port;
int ret, line, flags = dev_id->driver_data;
if (flags & UNKNOWN_DEV) {
@@ -471,6 +471,10 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
if (line < 0 || (flags & CIR_PORT))
return -ENODEV;
+ port = serial8250_get_port(line);
+ if (uart_console(&port->port))
+ dev->capabilities |= PNP_CONSOLE;
+
pnp_set_drvdata(dev, (void *)((long)line + 1));
return 0;
}
@@ -478,6 +482,8 @@ serial_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id)
static void serial_pnp_remove(struct pnp_dev *dev)
{
long line = (long)pnp_get_drvdata(dev);
+
+ dev->capabilities &= ~PNP_CONSOLE;
if (line)
serial8250_unregister_port(line - 1);
}
diff --git a/drivers/tty/serial/8250/Kconfig b/drivers/tty/serial/8250/Kconfig
index 0fcbcd29502f..6f7f2d753def 100644
--- a/drivers/tty/serial/8250/Kconfig
+++ b/drivers/tty/serial/8250/Kconfig
@@ -308,6 +308,25 @@ config SERIAL_8250_OMAP
This driver uses ttyS instead of ttyO.
+config SERIAL_8250_OMAP_TTYO_FIXUP
+ bool "Replace ttyO with ttyS"
+ depends on SERIAL_8250_OMAP=y && SERIAL_8250_CONSOLE
+ default y
+ help
+ This option replaces the "console=ttyO" argument with the matching
+ ttyS argument if the user did not specified it on the command line.
+ This ensures that the user can see the kernel output during boot
+ which he wouldn't see otherwise. The getty has still to be configured
+ for ttyS instead of ttyO regardless of this option.
+ This option is intended for people who "automatically" enable this
+ driver without knowing that this driver requires a different console=
+ argument. If you read this, please keep this option disabled and
+ instead update your kernel command line. If you prepare a kernel for a
+ distribution or other kind of larger user base then you probably want
+ to keep this option enabled. Otherwise people might complain about a
+ not booting kernel because the serial console remains silent in case
+ they forgot to update the command line.
+
config SERIAL_8250_FINTEK
tristate "Support for Fintek F81216A LPC to 4 UART"
depends on SERIAL_8250 && PNP
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index c79b43cd6014..d2501f01cd03 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -241,6 +241,7 @@ config SERIAL_SAMSUNG
tristate "Samsung SoC serial support"
depends on PLAT_SAMSUNG || ARCH_EXYNOS
select SERIAL_CORE
+ select SERIAL_EARLYCON
help
Support for the on-chip UARTs on the Samsung S3C24XX series CPUs,
providing /dev/ttySAC0, 1 and 2 (note, some machines may not
@@ -482,23 +483,13 @@ config SERIAL_SA1100_CONSOLE
your boot loader (lilo or loadlin) about how to pass options to the
kernel at boot time.)
-config SERIAL_MRST_MAX3110
- tristate "SPI UART driver for Max3110"
- depends on SPI_DW_PCI
- select SERIAL_CORE
- select SERIAL_CORE_CONSOLE
- help
- This is the UART protocol driver for the MAX3110 device on
- the Intel Moorestown platform. On other systems use the max3100
- driver.
-
config SERIAL_MFD_HSU
tristate "Medfield High Speed UART support"
depends on PCI
select SERIAL_CORE
config SERIAL_MFD_HSU_CONSOLE
- boolean "Medfile HSU serial console support"
+ bool "Medfile HSU serial console support"
depends on SERIAL_MFD_HSU=y
select SERIAL_CORE_CONSOLE
@@ -1094,6 +1085,16 @@ config SERIAL_VT8500_CONSOLE
depends on SERIAL_VT8500=y
select SERIAL_CORE_CONSOLE
+config SERIAL_ETRAXFS
+ bool "ETRAX FS serial port support"
+ depends on ETRAX_ARCH_V32 && OF
+ select SERIAL_CORE
+
+config SERIAL_ETRAXFS_CONSOLE
+ bool "ETRAX FS serial console support"
+ depends on SERIAL_ETRAXFS
+ select SERIAL_CORE_CONSOLE
+
config SERIAL_NETX
tristate "NetX serial port support"
depends on ARCH_NETX
@@ -1549,6 +1550,21 @@ config SERIAL_FSL_LPUART_CONSOLE
If you have enabled the lpuart serial port on the Freescale SoCs,
you can make it the console by answering Y to this option.
+config SERIAL_CONEXANT_DIGICOLOR
+ tristate "Conexant Digicolor CX92xxx USART serial port support"
+ depends on OF
+ select SERIAL_CORE
+ help
+ Support for the on-chip USART on Conexant Digicolor SoCs.
+
+config SERIAL_CONEXANT_DIGICOLOR_CONSOLE
+ bool "Console on Conexant Digicolor serial port"
+ depends on SERIAL_CONEXANT_DIGICOLOR=y
+ select SERIAL_CORE_CONSOLE
+ help
+ If you have enabled the USART serial port on Conexant Digicolor
+ SoCs, you can make it the console by answering Y to this option.
+
config SERIAL_ST_ASC
tristate "ST ASC serial port support"
select SERIAL_CORE
@@ -1577,6 +1593,24 @@ config SERIAL_MEN_Z135
This driver can also be build as a module. If so, the module will be called
men_z135_uart.ko
+config SERIAL_SPRD
+ tristate "Support for Spreadtrum serial"
+ depends on ARCH_SPRD
+ select SERIAL_CORE
+ help
+ This enables the driver for the Spreadtrum's serial.
+
+config SERIAL_SPRD_CONSOLE
+ bool "Spreadtrum UART console support"
+ depends on SERIAL_SPRD=y
+ select SERIAL_CORE_CONSOLE
+ select SERIAL_EARLYCON
+ help
+ Support for early debug console using Spreadtrum's serial. This enables
+ the console before standard serial driver is probed. This is enabled
+ with "earlycon" on the kernel command line. The console is
+ enabled when early_param is processed.
+
endmenu
config SERIAL_MCTRL_GPIO
diff --git a/drivers/tty/serial/Makefile b/drivers/tty/serial/Makefile
index 9a548acf5fdc..599be4b05a26 100644
--- a/drivers/tty/serial/Makefile
+++ b/drivers/tty/serial/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_SERIAL_MPSC) += mpsc.o
obj-$(CONFIG_SERIAL_MESON) += meson_uart.o
obj-$(CONFIG_SERIAL_SB1250_DUART) += sb1250-duart.o
obj-$(CONFIG_ETRAX_SERIAL) += crisv10.o
+obj-$(CONFIG_SERIAL_ETRAXFS) += etraxfs-uart.o
obj-$(CONFIG_SERIAL_SCCNXP) += sccnxp.o
obj-$(CONFIG_SERIAL_SC16IS7XX) += sc16is7xx.o
obj-$(CONFIG_SERIAL_JSM) += jsm/
@@ -77,7 +78,6 @@ obj-$(CONFIG_SERIAL_TIMBERDALE) += timbuart.o
obj-$(CONFIG_SERIAL_GRLIB_GAISLER_APBUART) += apbuart.o
obj-$(CONFIG_SERIAL_ALTERA_JTAGUART) += altera_jtaguart.o
obj-$(CONFIG_SERIAL_VT8500) += vt8500_serial.o
-obj-$(CONFIG_SERIAL_MRST_MAX3110) += mrst_max3110.o
obj-$(CONFIG_SERIAL_MFD_HSU) += mfd.o
obj-$(CONFIG_SERIAL_IFX6X60) += ifx6x60.o
obj-$(CONFIG_SERIAL_PCH_UART) += pch_uart.o
@@ -92,7 +92,9 @@ obj-$(CONFIG_SERIAL_EFM32_UART) += efm32-uart.o
obj-$(CONFIG_SERIAL_ARC) += arc_uart.o
obj-$(CONFIG_SERIAL_RP2) += rp2.o
obj-$(CONFIG_SERIAL_FSL_LPUART) += fsl_lpuart.o
+obj-$(CONFIG_SERIAL_CONEXANT_DIGICOLOR) += digicolor-usart.o
obj-$(CONFIG_SERIAL_MEN_Z135) += men_z135_uart.o
+obj-$(CONFIG_SERIAL_SPRD) += sprd_serial.o
# GPIOLIB helpers for modem control lines
obj-$(CONFIG_SERIAL_MCTRL_GPIO) += serial_mctrl_gpio.o
diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
index 192d0435bb86..0fefdd8931a2 100644
--- a/drivers/tty/serial/altera_jtaguart.c
+++ b/drivers/tty/serial/altera_jtaguart.c
@@ -441,6 +441,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
port->iotype = SERIAL_IO_MEM;
port->ops = &altera_jtaguart_ops;
port->flags = UPF_BOOT_AUTOCONF;
+ port->dev = &pdev->dev;
uart_add_one_port(&altera_jtaguart_driver, port);
diff --git a/drivers/tty/serial/altera_uart.c b/drivers/tty/serial/altera_uart.c
index eb15a50623cb..b2859fe07e14 100644
--- a/drivers/tty/serial/altera_uart.c
+++ b/drivers/tty/serial/altera_uart.c
@@ -589,6 +589,7 @@ static int altera_uart_probe(struct platform_device *pdev)
port->iotype = SERIAL_IO_MEM;
port->ops = &altera_uart_ops;
port->flags = UPF_BOOT_AUTOCONF;
+ port->dev = &pdev->dev;
platform_set_drvdata(pdev, port);
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 4d848a29e223..846552bff67d 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -341,13 +341,37 @@ static u_int atmel_tx_empty(struct uart_port *port)
static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
{
unsigned int control = 0;
- unsigned int mode;
+ unsigned int mode = UART_GET_MR(port);
+ unsigned int rts_paused, rts_ready;
struct atmel_uart_port *atmel_port = to_atmel_uart_port(port);
+ /* override mode to RS485 if needed, otherwise keep the current mode */
+ if (port->rs485.flags & SER_RS485_ENABLED) {
+ if ((port->rs485.delay_rts_after_send) > 0)
+ UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
+ mode &= ~ATMEL_US_USMODE;
+ mode |= ATMEL_US_USMODE_RS485;
+ }
+
+ /* set the RTS line state according to the mode */
+ if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+ /* force RTS line to high level */
+ rts_paused = ATMEL_US_RTSEN;
+
+ /* give the control of the RTS line back to the hardware */
+ rts_ready = ATMEL_US_RTSDIS;
+ } else {
+ /* force RTS line to high level */
+ rts_paused = ATMEL_US_RTSDIS;
+
+ /* force RTS line to low level */
+ rts_ready = ATMEL_US_RTSEN;
+ }
+
if (mctrl & TIOCM_RTS)
- control |= ATMEL_US_RTSEN;
+ control |= rts_ready;
else
- control |= ATMEL_US_RTSDIS;
+ control |= rts_paused;
if (mctrl & TIOCM_DTR)
control |= ATMEL_US_DTREN;
@@ -359,23 +383,12 @@ static void atmel_set_mctrl(struct uart_port *port, u_int mctrl)
mctrl_gpio_set(atmel_port->gpios, mctrl);
/* Local loopback mode? */
- mode = UART_GET_MR(port) & ~ATMEL_US_CHMODE;
+ mode &= ~ATMEL_US_CHMODE;
if (mctrl & TIOCM_LOOP)
mode |= ATMEL_US_CHMODE_LOC_LOOP;
else
mode |= ATMEL_US_CHMODE_NORMAL;
- /* Resetting serial mode to RS232 (0x0) */
- mode &= ~ATMEL_US_USMODE;
-
- if (port->rs485.flags & SER_RS485_ENABLED) {
- dev_dbg(port->dev, "Setting UART to RS485\n");
- if ((port->rs485.delay_rts_after_send) > 0)
- UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
- mode |= ATMEL_US_USMODE_RS485;
- } else {
- dev_dbg(port->dev, "Setting UART to RS232\n");
- }
UART_PUT_MR(port, mode);
}
@@ -725,7 +738,11 @@ static void atmel_complete_tx_dma(void *arg)
if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
uart_write_wakeup(port);
- /* Do we really need this? */
+ /*
+ * xmit is a circular buffer so, if we have just send data from
+ * xmit->tail to the end of xmit->buf, now we have to transmit the
+ * remaining data from the beginning of xmit->buf to xmit->head.
+ */
if (!uart_circ_empty(xmit))
tasklet_schedule(&atmel_port->tasklet);
@@ -784,17 +801,17 @@ static void atmel_tx_dma(struct uart_port *port)
BUG_ON(!sg_dma_len(sg));
desc = dmaengine_prep_slave_sg(chan,
- sg,
- 1,
- DMA_MEM_TO_DEV,
- DMA_PREP_INTERRUPT |
- DMA_CTRL_ACK);
+ sg,
+ 1,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT |
+ DMA_CTRL_ACK);
if (!desc) {
dev_err(port->dev, "Failed to send via dma!\n");
return;
}
- dma_sync_sg_for_device(port->dev, sg, 1, DMA_MEM_TO_DEV);
+ dma_sync_sg_for_device(port->dev, sg, 1, DMA_TO_DEVICE);
atmel_port->desc_tx = desc;
desc->callback = atmel_complete_tx_dma;
@@ -927,7 +944,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
dma_sync_sg_for_cpu(port->dev,
&atmel_port->sg_rx,
1,
- DMA_DEV_TO_MEM);
+ DMA_FROM_DEVICE);
/*
* ring->head points to the end of data already written by the DMA.
@@ -974,7 +991,7 @@ static void atmel_rx_from_dma(struct uart_port *port)
dma_sync_sg_for_device(port->dev,
&atmel_port->sg_rx,
1,
- DMA_DEV_TO_MEM);
+ DMA_FROM_DEVICE);
/*
* Drop the lock here since it might end up calling
@@ -1012,13 +1029,13 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
/* UART circular rx buffer is an aligned page. */
BUG_ON((int)port->state->xmit.buf & ~PAGE_MASK);
sg_set_page(&atmel_port->sg_rx,
- virt_to_page(ring->buf),
- ATMEL_SERIAL_RINGSIZE,
- (int)ring->buf & ~PAGE_MASK);
- nent = dma_map_sg(port->dev,
- &atmel_port->sg_rx,
- 1,
- DMA_FROM_DEVICE);
+ virt_to_page(ring->buf),
+ ATMEL_SERIAL_RINGSIZE,
+ (int)ring->buf & ~PAGE_MASK);
+ nent = dma_map_sg(port->dev,
+ &atmel_port->sg_rx,
+ 1,
+ DMA_FROM_DEVICE);
if (!nent) {
dev_dbg(port->dev, "need to release resource of dma\n");
@@ -1047,11 +1064,11 @@ static int atmel_prepare_rx_dma(struct uart_port *port)
* each one is half ring buffer size
*/
desc = dmaengine_prep_dma_cyclic(atmel_port->chan_rx,
- sg_dma_address(&atmel_port->sg_rx),
- sg_dma_len(&atmel_port->sg_rx),
- sg_dma_len(&atmel_port->sg_rx)/2,
- DMA_DEV_TO_MEM,
- DMA_PREP_INTERRUPT);
+ sg_dma_address(&atmel_port->sg_rx),
+ sg_dma_len(&atmel_port->sg_rx),
+ sg_dma_len(&atmel_port->sg_rx)/2,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
desc->callback = atmel_complete_rx_dma;
desc->callback_param = port;
atmel_port->desc_rx = desc;
@@ -1921,12 +1938,14 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
unsigned long flags;
- unsigned int mode, imr, quot, baud;
+ unsigned int old_mode, mode, imr, quot, baud;
- /* Get current mode register */
- mode = UART_GET_MR(port) & ~(ATMEL_US_USCLKS | ATMEL_US_CHRL
- | ATMEL_US_NBSTOP | ATMEL_US_PAR
- | ATMEL_US_USMODE);
+ /* save the current mode register */
+ mode = old_mode = UART_GET_MR(port);
+
+ /* reset the mode, clock divisor, parity, stop bits and data size */
+ mode &= ~(ATMEL_US_USCLKS | ATMEL_US_CHRL | ATMEL_US_NBSTOP |
+ ATMEL_US_PAR | ATMEL_US_USMODE);
baud = uart_get_baud_rate(port, termios, old, 0, port->uartclk / 16);
quot = uart_get_divisor(port, baud);
@@ -1971,12 +1990,6 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
} else
mode |= ATMEL_US_PAR_NONE;
- /* hardware handshake (RTS/CTS) */
- if (termios->c_cflag & CRTSCTS)
- mode |= ATMEL_US_USMODE_HWHS;
- else
- mode |= ATMEL_US_USMODE_NORMAL;
-
spin_lock_irqsave(&port->lock, flags);
port->read_status_mask = ATMEL_US_OVRE;
@@ -2020,18 +2033,40 @@ static void atmel_set_termios(struct uart_port *port, struct ktermios *termios,
/* disable receiver and transmitter */
UART_PUT_CR(port, ATMEL_US_TXDIS | ATMEL_US_RXDIS);
- /* Resetting serial mode to RS232 (0x0) */
- mode &= ~ATMEL_US_USMODE;
-
+ /* mode */
if (port->rs485.flags & SER_RS485_ENABLED) {
if ((port->rs485.delay_rts_after_send) > 0)
UART_PUT_TTGR(port, port->rs485.delay_rts_after_send);
mode |= ATMEL_US_USMODE_RS485;
+ } else if (termios->c_cflag & CRTSCTS) {
+ /* RS232 with hardware handshake (RTS/CTS) */
+ mode |= ATMEL_US_USMODE_HWHS;
+ } else {
+ /* RS232 without hadware handshake */
+ mode |= ATMEL_US_USMODE_NORMAL;
}
- /* set the parity, stop bits and data size */
+ /* set the mode, clock divisor, parity, stop bits and data size */
UART_PUT_MR(port, mode);
+ /*
+ * when switching the mode, set the RTS line state according to the
+ * new mode, otherwise keep the former state
+ */
+ if ((old_mode & ATMEL_US_USMODE) != (mode & ATMEL_US_USMODE)) {
+ unsigned int rts_state;
+
+ if ((mode & ATMEL_US_USMODE) == ATMEL_US_USMODE_HWHS) {
+ /* let the hardware control the RTS line */
+ rts_state = ATMEL_US_RTSDIS;
+ } else {
+ /* force RTS line to low level */
+ rts_state = ATMEL_US_RTSEN;
+ }
+
+ UART_PUT_CR(port, rts_state);
+ }
+
/* set the baud rate */
UART_PUT_BRGR(port, quot);
UART_PUT_CR(port, ATMEL_US_RSTSTA | ATMEL_US_RSTRX);
@@ -2565,7 +2600,7 @@ static int atmel_serial_probe(struct platform_device *pdev)
ret = atmel_init_port(port, pdev);
if (ret)
- goto err;
+ goto err_clear_bit;
if (!atmel_use_pdc_rx(&port->uart)) {
ret = -ENOMEM;
@@ -2596,6 +2631,12 @@ static int atmel_serial_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, port);
+ /*
+ * The peripheral clock has been disabled by atmel_init_port():
+ * enable it before accessing I/O registers
+ */
+ clk_prepare_enable(port->clk);
+
if (rs485_enabled) {
UART_PUT_MR(&port->uart, ATMEL_US_USMODE_NORMAL);
UART_PUT_CR(&port->uart, ATMEL_US_RTSEN);
@@ -2606,6 +2647,12 @@ static int atmel_serial_probe(struct platform_device *pdev)
*/
atmel_get_ip_name(&port->uart);
+ /*
+ * The peripheral clock can now safely be disabled till the port
+ * is used
+ */
+ clk_disable_unprepare(port->clk);
+
return 0;
err_add_port:
@@ -2616,6 +2663,8 @@ err_alloc_ring:
clk_put(port->clk);
port->clk = NULL;
}
+err_clear_bit:
+ clear_bit(port->uart.line, atmel_ports_in_use);
err:
return ret;
}
diff --git a/drivers/tty/serial/digicolor-usart.c b/drivers/tty/serial/digicolor-usart.c
new file mode 100644
index 000000000000..a80cdad114f3
--- /dev/null
+++ b/drivers/tty/serial/digicolor-usart.c
@@ -0,0 +1,560 @@
+/*
+ * Driver for Conexant Digicolor serial ports (USART)
+ *
+ * Author: Baruch Siach <baruch@tkos.co.il>
+ *
+ * Copyright (C) 2014 Paradox Innovation 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/module.h>
+#include <linux/console.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/workqueue.h>
+
+#define UA_ENABLE 0x00
+#define UA_ENABLE_ENABLE BIT(0)
+
+#define UA_CONTROL 0x01
+#define UA_CONTROL_RX_ENABLE BIT(0)
+#define UA_CONTROL_TX_ENABLE BIT(1)
+#define UA_CONTROL_SOFT_RESET BIT(2)
+
+#define UA_STATUS 0x02
+#define UA_STATUS_PARITY_ERR BIT(0)
+#define UA_STATUS_FRAME_ERR BIT(1)
+#define UA_STATUS_OVERRUN_ERR BIT(2)
+#define UA_STATUS_TX_READY BIT(6)
+
+#define UA_CONFIG 0x03
+#define UA_CONFIG_CHAR_LEN BIT(0)
+#define UA_CONFIG_STOP_BITS BIT(1)
+#define UA_CONFIG_PARITY BIT(2)
+#define UA_CONFIG_ODD_PARITY BIT(4)
+
+#define UA_EMI_REC 0x04
+
+#define UA_HBAUD_LO 0x08
+#define UA_HBAUD_HI 0x09
+
+#define UA_STATUS_FIFO 0x0a
+#define UA_STATUS_FIFO_RX_EMPTY BIT(2)
+#define UA_STATUS_FIFO_RX_INT_ALMOST BIT(3)
+#define UA_STATUS_FIFO_TX_FULL BIT(4)
+#define UA_STATUS_FIFO_TX_INT_ALMOST BIT(7)
+
+#define UA_CONFIG_FIFO 0x0b
+#define UA_CONFIG_FIFO_RX_THRESH 7
+#define UA_CONFIG_FIFO_RX_FIFO_MODE BIT(3)
+#define UA_CONFIG_FIFO_TX_FIFO_MODE BIT(7)
+
+#define UA_INTFLAG_CLEAR 0x1c
+#define UA_INTFLAG_SET 0x1d
+#define UA_INT_ENABLE 0x1e
+#define UA_INT_STATUS 0x1f
+
+#define UA_INT_TX BIT(0)
+#define UA_INT_RX BIT(1)
+
+#define DIGICOLOR_USART_NR 3
+
+/*
+ * We use the 16 bytes hardware FIFO to buffer Rx traffic. Rx interrupt is
+ * only produced when the FIFO is filled more than a certain configurable
+ * threshold. Unfortunately, there is no way to set this threshold below half
+ * FIFO. This means that we must periodically poll the FIFO status register to
+ * see whether there are waiting Rx bytes.
+ */
+
+struct digicolor_port {
+ struct uart_port port;
+ struct delayed_work rx_poll_work;
+};
+
+static struct uart_port *digicolor_ports[DIGICOLOR_USART_NR];
+
+static bool digicolor_uart_tx_full(struct uart_port *port)
+{
+ return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
+ UA_STATUS_FIFO_TX_FULL);
+}
+
+static bool digicolor_uart_rx_empty(struct uart_port *port)
+{
+ return !!(readb_relaxed(port->membase + UA_STATUS_FIFO) &
+ UA_STATUS_FIFO_RX_EMPTY);
+}
+
+static void digicolor_uart_stop_tx(struct uart_port *port)
+{
+ u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+ int_enable &= ~UA_INT_TX;
+ writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_uart_start_tx(struct uart_port *port)
+{
+ u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+ int_enable |= UA_INT_TX;
+ writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_uart_stop_rx(struct uart_port *port)
+{
+ u8 int_enable = readb_relaxed(port->membase + UA_INT_ENABLE);
+
+ int_enable &= ~UA_INT_RX;
+ writeb_relaxed(int_enable, port->membase + UA_INT_ENABLE);
+}
+
+static void digicolor_rx_poll(struct work_struct *work)
+{
+ struct digicolor_port *dp =
+ container_of(to_delayed_work(work),
+ struct digicolor_port, rx_poll_work);
+
+ if (!digicolor_uart_rx_empty(&dp->port))
+ /* force RX interrupt */
+ writeb_relaxed(UA_INT_RX, dp->port.membase + UA_INTFLAG_SET);
+
+ schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
+}
+
+static void digicolor_uart_rx(struct uart_port *port)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ while (1) {
+ u8 status, ch;
+ unsigned int ch_flag;
+
+ if (digicolor_uart_rx_empty(port))
+ break;
+
+ ch = readb_relaxed(port->membase + UA_EMI_REC);
+ status = readb_relaxed(port->membase + UA_STATUS);
+
+ port->icount.rx++;
+ ch_flag = TTY_NORMAL;
+
+ if (status) {
+ if (status & UA_STATUS_PARITY_ERR)
+ port->icount.parity++;
+ else if (status & UA_STATUS_FRAME_ERR)
+ port->icount.frame++;
+ else if (status & UA_STATUS_OVERRUN_ERR)
+ port->icount.overrun++;
+
+ status &= port->read_status_mask;
+
+ if (status & UA_STATUS_PARITY_ERR)
+ ch_flag = TTY_PARITY;
+ else if (status & UA_STATUS_FRAME_ERR)
+ ch_flag = TTY_FRAME;
+ else if (status & UA_STATUS_OVERRUN_ERR)
+ ch_flag = TTY_OVERRUN;
+ }
+
+ if (status & port->ignore_status_mask)
+ continue;
+
+ uart_insert_char(port, status, UA_STATUS_OVERRUN_ERR, ch,
+ ch_flag);
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ tty_flip_buffer_push(&port->state->port);
+}
+
+static void digicolor_uart_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long flags;
+
+ if (digicolor_uart_tx_full(port))
+ return;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (port->x_char) {
+ writeb_relaxed(port->x_char, port->membase + UA_EMI_REC);
+ port->icount.tx++;
+ port->x_char = 0;
+ goto out;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ digicolor_uart_stop_tx(port);
+ goto out;
+ }
+
+ while (!uart_circ_empty(xmit)) {
+ writeb(xmit->buf[xmit->tail], port->membase + UA_EMI_REC);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+
+ if (digicolor_uart_tx_full(port))
+ break;
+ }
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+out:
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static irqreturn_t digicolor_uart_int(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ u8 int_status = readb_relaxed(port->membase + UA_INT_STATUS);
+
+ writeb_relaxed(UA_INT_RX | UA_INT_TX,
+ port->membase + UA_INTFLAG_CLEAR);
+
+ if (int_status & UA_INT_RX)
+ digicolor_uart_rx(port);
+ if (int_status & UA_INT_TX)
+ digicolor_uart_tx(port);
+
+ return IRQ_HANDLED;
+}
+
+static unsigned int digicolor_uart_tx_empty(struct uart_port *port)
+{
+ u8 status = readb_relaxed(port->membase + UA_STATUS);
+
+ return (status & UA_STATUS_TX_READY) ? TIOCSER_TEMT : 0;
+}
+
+static unsigned int digicolor_uart_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_CTS;
+}
+
+static void digicolor_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+}
+
+static void digicolor_uart_break_ctl(struct uart_port *port, int state)
+{
+}
+
+static int digicolor_uart_startup(struct uart_port *port)
+{
+ struct digicolor_port *dp =
+ container_of(port, struct digicolor_port, port);
+
+ writeb_relaxed(UA_ENABLE_ENABLE, port->membase + UA_ENABLE);
+ writeb_relaxed(UA_CONTROL_SOFT_RESET, port->membase + UA_CONTROL);
+ writeb_relaxed(0, port->membase + UA_CONTROL);
+
+ writeb_relaxed(UA_CONFIG_FIFO_RX_FIFO_MODE
+ | UA_CONFIG_FIFO_TX_FIFO_MODE | UA_CONFIG_FIFO_RX_THRESH,
+ port->membase + UA_CONFIG_FIFO);
+ writeb_relaxed(UA_STATUS_FIFO_RX_INT_ALMOST,
+ port->membase + UA_STATUS_FIFO);
+ writeb_relaxed(UA_CONTROL_RX_ENABLE | UA_CONTROL_TX_ENABLE,
+ port->membase + UA_CONTROL);
+ writeb_relaxed(UA_INT_TX | UA_INT_RX,
+ port->membase + UA_INT_ENABLE);
+
+ schedule_delayed_work(&dp->rx_poll_work, msecs_to_jiffies(100));
+
+ return 0;
+}
+
+static void digicolor_uart_shutdown(struct uart_port *port)
+{
+ struct digicolor_port *dp =
+ container_of(port, struct digicolor_port, port);
+
+ writeb_relaxed(0, port->membase + UA_ENABLE);
+ cancel_delayed_work_sync(&dp->rx_poll_work);
+}
+
+static void digicolor_uart_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud, divisor;
+ u8 config = 0;
+ unsigned long flags;
+
+ /* Mask termios capabilities we don't support */
+ termios->c_cflag &= ~CMSPAR;
+ termios->c_iflag &= ~(BRKINT | IGNBRK);
+
+ /* Limit baud rates so that we don't need the fractional divider */
+ baud = uart_get_baud_rate(port, termios, old,
+ port->uartclk / (0x10000*16),
+ port->uartclk / 256);
+ divisor = uart_get_divisor(port, baud) - 1;
+
+ switch (termios->c_cflag & CSIZE) {
+ case CS7:
+ break;
+ case CS8:
+ default:
+ config |= UA_CONFIG_CHAR_LEN;
+ break;
+ }
+
+ if (termios->c_cflag & CSTOPB)
+ config |= UA_CONFIG_STOP_BITS;
+
+ if (termios->c_cflag & PARENB) {
+ config |= UA_CONFIG_PARITY;
+ if (termios->c_cflag & PARODD)
+ config |= UA_CONFIG_ODD_PARITY;
+ }
+
+ /* Set read status mask */
+ port->read_status_mask = UA_STATUS_OVERRUN_ERR;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= UA_STATUS_PARITY_ERR
+ | UA_STATUS_FRAME_ERR;
+
+ /* Set status ignore mask */
+ port->ignore_status_mask = 0;
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= UA_STATUS_OVERRUN_ERR
+ | UA_STATUS_PARITY_ERR | UA_STATUS_FRAME_ERR;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ writeb_relaxed(config, port->membase + UA_CONFIG);
+ writeb_relaxed(divisor & 0xff, port->membase + UA_HBAUD_LO);
+ writeb_relaxed(divisor >> 8, port->membase + UA_HBAUD_HI);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static const char *digicolor_uart_type(struct uart_port *port)
+{
+ return (port->type == PORT_DIGICOLOR) ? "DIGICOLOR USART" : NULL;
+}
+
+static void digicolor_uart_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_DIGICOLOR;
+}
+
+static void digicolor_uart_release_port(struct uart_port *port)
+{
+}
+
+static int digicolor_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static const struct uart_ops digicolor_uart_ops = {
+ .tx_empty = digicolor_uart_tx_empty,
+ .set_mctrl = digicolor_uart_set_mctrl,
+ .get_mctrl = digicolor_uart_get_mctrl,
+ .stop_tx = digicolor_uart_stop_tx,
+ .start_tx = digicolor_uart_start_tx,
+ .stop_rx = digicolor_uart_stop_rx,
+ .break_ctl = digicolor_uart_break_ctl,
+ .startup = digicolor_uart_startup,
+ .shutdown = digicolor_uart_shutdown,
+ .set_termios = digicolor_uart_set_termios,
+ .type = digicolor_uart_type,
+ .config_port = digicolor_uart_config_port,
+ .release_port = digicolor_uart_release_port,
+ .request_port = digicolor_uart_request_port,
+};
+
+static void digicolor_uart_console_putchar(struct uart_port *port, int ch)
+{
+ while (digicolor_uart_tx_full(port))
+ cpu_relax();
+
+ writeb_relaxed(ch, port->membase + UA_EMI_REC);
+}
+
+static void digicolor_uart_console_write(struct console *co, const char *c,
+ unsigned n)
+{
+ struct uart_port *port = digicolor_ports[co->index];
+ u8 status;
+ unsigned long flags;
+ int locked = 1;
+
+ if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ uart_console_write(port, c, n, digicolor_uart_console_putchar);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* Wait for transmitter to become empty */
+ do {
+ status = readb_relaxed(port->membase + UA_STATUS);
+ } while ((status & UA_STATUS_TX_READY) == 0);
+}
+
+static int digicolor_uart_console_setup(struct console *co, char *options)
+{
+ int baud = 115200, bits = 8, parity = 'n', flow = 'n';
+ struct uart_port *port;
+
+ if (co->index < 0 || co->index >= DIGICOLOR_USART_NR)
+ return -EINVAL;
+
+ port = digicolor_ports[co->index];
+ if (!port)
+ return -ENODEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct console digicolor_console = {
+ .name = "ttyS",
+ .device = uart_console_device,
+ .write = digicolor_uart_console_write,
+ .setup = digicolor_uart_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+};
+
+static struct uart_driver digicolor_uart = {
+ .driver_name = "digicolor-usart",
+ .dev_name = "ttyS",
+ .nr = DIGICOLOR_USART_NR,
+};
+
+static int digicolor_uart_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ int ret, index;
+ struct digicolor_port *dp;
+ struct resource *res;
+ struct clk *uart_clk;
+
+ if (!np) {
+ dev_err(&pdev->dev, "Missing device tree node\n");
+ return -ENXIO;
+ }
+
+ index = of_alias_get_id(np, "serial");
+ if (index < 0 || index >= DIGICOLOR_USART_NR)
+ return -EINVAL;
+
+ dp = devm_kzalloc(&pdev->dev, sizeof(*dp), GFP_KERNEL);
+ if (!dp)
+ return -ENOMEM;
+
+ uart_clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(uart_clk))
+ return PTR_ERR(uart_clk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dp->port.mapbase = res->start;
+ dp->port.membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dp->port.membase))
+ return PTR_ERR(dp->port.membase);
+
+ dp->port.irq = platform_get_irq(pdev, 0);
+ if (IS_ERR_VALUE(dp->port.irq))
+ return dp->port.irq;
+
+ dp->port.iotype = UPIO_MEM;
+ dp->port.uartclk = clk_get_rate(uart_clk);
+ dp->port.fifosize = 16;
+ dp->port.dev = &pdev->dev;
+ dp->port.ops = &digicolor_uart_ops;
+ dp->port.line = index;
+ dp->port.type = PORT_DIGICOLOR;
+ spin_lock_init(&dp->port.lock);
+
+ digicolor_ports[index] = &dp->port;
+ platform_set_drvdata(pdev, &dp->port);
+
+ INIT_DELAYED_WORK(&dp->rx_poll_work, digicolor_rx_poll);
+
+ ret = devm_request_irq(&pdev->dev, dp->port.irq, digicolor_uart_int, 0,
+ dev_name(&pdev->dev), &dp->port);
+ if (ret)
+ return ret;
+
+ return uart_add_one_port(&digicolor_uart, &dp->port);
+}
+
+static int digicolor_uart_remove(struct platform_device *pdev)
+{
+ struct uart_port *port = platform_get_drvdata(pdev);
+
+ uart_remove_one_port(&digicolor_uart, port);
+
+ return 0;
+}
+
+static const struct of_device_id digicolor_uart_dt_ids[] = {
+ { .compatible = "cnxt,cx92755-usart", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, digicolor_uart_dt_ids);
+
+static struct platform_driver digicolor_uart_platform = {
+ .driver = {
+ .name = "digicolor-usart",
+ .of_match_table = of_match_ptr(digicolor_uart_dt_ids),
+ },
+ .probe = digicolor_uart_probe,
+ .remove = digicolor_uart_remove,
+};
+
+static int __init digicolor_uart_init(void)
+{
+ int ret;
+
+ if (IS_ENABLED(CONFIG_SERIAL_CONEXANT_DIGICOLOR_CONSOLE)) {
+ digicolor_uart.cons = &digicolor_console;
+ digicolor_console.data = &digicolor_uart;
+ }
+
+ ret = uart_register_driver(&digicolor_uart);
+ if (ret)
+ return ret;
+
+ return platform_driver_register(&digicolor_uart_platform);
+}
+module_init(digicolor_uart_init);
+
+static void __exit digicolor_uart_exit(void)
+{
+ platform_driver_unregister(&digicolor_uart_platform);
+ uart_unregister_driver(&digicolor_uart);
+}
+module_exit(digicolor_uart_exit);
+
+MODULE_AUTHOR("Baruch Siach <baruch@tkos.co.il>");
+MODULE_DESCRIPTION("Conexant Digicolor USART serial driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/tty/serial/etraxfs-uart.c b/drivers/tty/serial/etraxfs-uart.c
new file mode 100644
index 000000000000..a57301a6fe42
--- /dev/null
+++ b/drivers/tty/serial/etraxfs-uart.c
@@ -0,0 +1,996 @@
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/console.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/tty_flip.h>
+#include <linux/of.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <hwregs/ser_defs.h>
+
+#define DRV_NAME "etraxfs-uart"
+#define UART_NR CONFIG_ETRAX_SERIAL_PORTS
+
+#define MODIFY_REG(instance, reg, var) \
+ do { \
+ if (REG_RD_INT(ser, instance, reg) != \
+ REG_TYPE_CONV(int, reg_ser_##reg, var)) \
+ REG_WR(ser, instance, reg, var); \
+ } while (0)
+
+struct uart_cris_port {
+ struct uart_port port;
+
+ int initialized;
+ int irq;
+
+ void __iomem *regi_ser;
+
+ struct gpio_desc *dtr_pin;
+ struct gpio_desc *dsr_pin;
+ struct gpio_desc *ri_pin;
+ struct gpio_desc *cd_pin;
+
+ int write_ongoing;
+};
+
+static struct uart_driver etraxfs_uart_driver;
+static struct uart_port *console_port;
+static int console_baud = 115200;
+static struct uart_cris_port *etraxfs_uart_ports[UART_NR];
+
+static void cris_serial_port_init(struct uart_port *port, int line);
+static void etraxfs_uart_stop_rx(struct uart_port *port);
+static inline void etraxfs_uart_start_tx_bottom(struct uart_port *port);
+
+#ifdef CONFIG_SERIAL_ETRAXFS_CONSOLE
+static void
+cris_console_write(struct console *co, const char *s, unsigned int count)
+{
+ struct uart_cris_port *up;
+ int i;
+ reg_ser_r_stat_din stat;
+ reg_ser_rw_tr_dma_en tr_dma_en, old;
+
+ up = etraxfs_uart_ports[co->index];
+
+ if (!up)
+ return;
+
+ /* Switch to manual mode. */
+ tr_dma_en = old = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
+ if (tr_dma_en.en == regk_ser_yes) {
+ tr_dma_en.en = regk_ser_no;
+ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
+ }
+
+ /* Send data. */
+ for (i = 0; i < count; i++) {
+ /* LF -> CRLF */
+ if (s[i] == '\n') {
+ do {
+ stat = REG_RD(ser, up->regi_ser, r_stat_din);
+ } while (!stat.tr_rdy);
+ REG_WR_INT(ser, up->regi_ser, rw_dout, '\r');
+ }
+ /* Wait until transmitter is ready and send. */
+ do {
+ stat = REG_RD(ser, up->regi_ser, r_stat_din);
+ } while (!stat.tr_rdy);
+ REG_WR_INT(ser, up->regi_ser, rw_dout, s[i]);
+ }
+
+ /* Restore mode. */
+ if (tr_dma_en.en != old.en)
+ REG_WR(ser, up->regi_ser, rw_tr_dma_en, old);
+}
+
+static int __init
+cris_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index < 0 || co->index >= UART_NR)
+ co->index = 0;
+ port = &etraxfs_uart_ports[co->index]->port;
+ console_port = port;
+
+ co->flags |= CON_CONSDEV;
+
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+ console_baud = baud;
+ cris_serial_port_init(port, co->index);
+ uart_set_options(port, co, baud, parity, bits, flow);
+
+ return 0;
+}
+
+static struct tty_driver *cris_console_device(struct console *co, int *index)
+{
+ struct uart_driver *p = co->data;
+ *index = co->index;
+ return p->tty_driver;
+}
+
+static struct console cris_console = {
+ .name = "ttyS",
+ .write = cris_console_write,
+ .device = cris_console_device,
+ .setup = cris_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &etraxfs_uart_driver,
+};
+#endif /* CONFIG_SERIAL_ETRAXFS_CONSOLE */
+
+static struct uart_driver etraxfs_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "serial",
+ .dev_name = "ttyS",
+ .major = TTY_MAJOR,
+ .minor = 64,
+ .nr = UART_NR,
+#ifdef CONFIG_SERIAL_ETRAXFS_CONSOLE
+ .cons = &cris_console,
+#endif /* CONFIG_SERIAL_ETRAXFS_CONSOLE */
+};
+
+static inline int crisv32_serial_get_rts(struct uart_cris_port *up)
+{
+ void __iomem *regi_ser = up->regi_ser;
+ /*
+ * Return what the user has controlled rts to or
+ * what the pin is? (if auto_rts is used it differs during tx)
+ */
+ reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
+
+ return !(rstat.rts_n == regk_ser_active);
+}
+
+/*
+ * A set = 0 means 3.3V on the pin, bitvalue: 0=active, 1=inactive
+ * 0=0V , 1=3.3V
+ */
+static inline void crisv32_serial_set_rts(struct uart_cris_port *up,
+ int set, int force)
+{
+ void __iomem *regi_ser = up->regi_ser;
+
+ unsigned long flags;
+ reg_ser_rw_rec_ctrl rec_ctrl;
+
+ local_irq_save(flags);
+ rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
+
+ if (set)
+ rec_ctrl.rts_n = regk_ser_active;
+ else
+ rec_ctrl.rts_n = regk_ser_inactive;
+ REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
+ local_irq_restore(flags);
+}
+
+static inline int crisv32_serial_get_cts(struct uart_cris_port *up)
+{
+ void __iomem *regi_ser = up->regi_ser;
+ reg_ser_r_stat_din rstat = REG_RD(ser, regi_ser, r_stat_din);
+
+ return (rstat.cts_n == regk_ser_active);
+}
+
+/*
+ * Send a single character for XON/XOFF purposes. We do it in this separate
+ * function instead of the alternative support port.x_char, in the ...start_tx
+ * function, so we don't mix up this case with possibly enabling transmission
+ * of queued-up data (in case that's disabled after *receiving* an XOFF or
+ * negative CTS). This function is used for both DMA and non-DMA case; see HW
+ * docs specifically blessing sending characters manually when DMA for
+ * transmission is enabled and running. We may be asked to transmit despite
+ * the transmitter being disabled by a ..._stop_tx call so we need to enable
+ * it temporarily but restore the state afterwards.
+ */
+static void etraxfs_uart_send_xchar(struct uart_port *port, char ch)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ reg_ser_rw_dout dout = { .data = ch };
+ reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
+ reg_ser_r_stat_din rstat;
+ reg_ser_rw_tr_ctrl prev_tr_ctrl, tr_ctrl;
+ void __iomem *regi_ser = up->regi_ser;
+ unsigned long flags;
+
+ /*
+ * Wait for tr_rdy in case a character is already being output. Make
+ * sure we have integrity between the register reads and the writes
+ * below, but don't busy-wait with interrupts off and the port lock
+ * taken.
+ */
+ spin_lock_irqsave(&port->lock, flags);
+ do {
+ spin_unlock_irqrestore(&port->lock, flags);
+ spin_lock_irqsave(&port->lock, flags);
+ prev_tr_ctrl = tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+ rstat = REG_RD(ser, regi_ser, r_stat_din);
+ } while (!rstat.tr_rdy);
+
+ /*
+ * Ack an interrupt if one was just issued for the previous character
+ * that was output. This is required for non-DMA as the interrupt is
+ * used as the only indicator that the transmitter is ready and it
+ * isn't while this x_char is being transmitted.
+ */
+ REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
+
+ /* Enable the transmitter in case it was disabled. */
+ tr_ctrl.stop = 0;
+ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+
+ /*
+ * Finally, send the blessed character; nothing should stop it now,
+ * except for an xoff-detected state, which we'll handle below.
+ */
+ REG_WR(ser, regi_ser, rw_dout, dout);
+ up->port.icount.tx++;
+
+ /* There might be an xoff state to clear. */
+ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+
+ /*
+ * Clear any xoff state that *may* have been there to
+ * inhibit transmission of the character.
+ */
+ if (rstat.xoff_detect) {
+ reg_ser_rw_xoff_clr xoff_clr = { .clr = 1 };
+ reg_ser_rw_tr_dma_en tr_dma_en;
+
+ REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
+ tr_dma_en = REG_RD(ser, regi_ser, rw_tr_dma_en);
+
+ /*
+ * If we had an xoff state but cleared it, instead sneak in a
+ * disabled state for the transmitter, after the character we
+ * sent. Thus we keep the port disabled, just as if the xoff
+ * state was still in effect (or actually, as if stop_tx had
+ * been called, as we stop DMA too).
+ */
+ prev_tr_ctrl.stop = 1;
+
+ tr_dma_en.en = 0;
+ REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
+ }
+
+ /* Restore "previous" enabled/disabled state of the transmitter. */
+ REG_WR(ser, regi_ser, rw_tr_ctrl, prev_tr_ctrl);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+/*
+ * Do not spin_lock_irqsave or disable interrupts by other means here; it's
+ * already done by the caller.
+ */
+static void etraxfs_uart_start_tx(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+ /* we have already done below if a write is ongoing */
+ if (up->write_ongoing)
+ return;
+
+ /* Signal that write is ongoing */
+ up->write_ongoing = 1;
+
+ etraxfs_uart_start_tx_bottom(port);
+}
+
+static inline void etraxfs_uart_start_tx_bottom(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ void __iomem *regi_ser = up->regi_ser;
+ reg_ser_rw_tr_ctrl tr_ctrl;
+ reg_ser_rw_intr_mask intr_mask;
+
+ tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+ tr_ctrl.stop = regk_ser_no;
+ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+ intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
+ intr_mask.tr_rdy = regk_ser_yes;
+ REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
+}
+
+/*
+ * This function handles both the DMA and non-DMA case by ordering the
+ * transmitter to stop of after the current character. We don't need to wait
+ * for any such character to be completely transmitted; we do that where it
+ * matters, like in etraxfs_uart_set_termios. Don't busy-wait here; see
+ * Documentation/serial/driver: this function is called within
+ * spin_lock_irq{,save} and thus separate ones would be disastrous (when SMP).
+ * There's no documented need to set the txd pin to any particular value;
+ * break setting is controlled solely by etraxfs_uart_break_ctl.
+ */
+static void etraxfs_uart_stop_tx(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ void __iomem *regi_ser = up->regi_ser;
+ reg_ser_rw_tr_ctrl tr_ctrl;
+ reg_ser_rw_intr_mask intr_mask;
+ reg_ser_rw_tr_dma_en tr_dma_en = {0};
+ reg_ser_rw_xoff_clr xoff_clr = {0};
+
+ /*
+ * For the non-DMA case, we'd get a tr_rdy interrupt that we're not
+ * interested in as we're not transmitting any characters. For the
+ * DMA case, that interrupt is already turned off, but no reason to
+ * waste code on conditionals here.
+ */
+ intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
+ intr_mask.tr_rdy = regk_ser_no;
+ REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
+
+ tr_ctrl = REG_RD(ser, regi_ser, rw_tr_ctrl);
+ tr_ctrl.stop = 1;
+ REG_WR(ser, regi_ser, rw_tr_ctrl, tr_ctrl);
+
+ /*
+ * Always clear possible hardware xoff-detected state here, no need to
+ * unnecessary consider mctrl settings and when they change. We clear
+ * it here rather than in start_tx: both functions are called as the
+ * effect of XOFF processing, but start_tx is also called when upper
+ * levels tell the driver that there are more characters to send, so
+ * avoid adding code there.
+ */
+ xoff_clr.clr = 1;
+ REG_WR(ser, regi_ser, rw_xoff_clr, xoff_clr);
+
+ /*
+ * Disable transmitter DMA, so that if we're in XON/XOFF, we can send
+ * those single characters without also giving go-ahead for queued up
+ * DMA data.
+ */
+ tr_dma_en.en = 0;
+ REG_WR(ser, regi_ser, rw_tr_dma_en, tr_dma_en);
+
+ /*
+ * Make sure that write_ongoing is reset when stopping tx.
+ */
+ up->write_ongoing = 0;
+}
+
+static void etraxfs_uart_stop_rx(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ void __iomem *regi_ser = up->regi_ser;
+ reg_ser_rw_rec_ctrl rec_ctrl = REG_RD(ser, regi_ser, rw_rec_ctrl);
+
+ rec_ctrl.en = regk_ser_no;
+ REG_WR(ser, regi_ser, rw_rec_ctrl, rec_ctrl);
+}
+
+static void etraxfs_uart_enable_ms(struct uart_port *port)
+{
+}
+
+static void check_modem_status(struct uart_cris_port *up)
+{
+}
+
+static unsigned int etraxfs_uart_tx_empty(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ unsigned long flags;
+ unsigned int ret;
+ reg_ser_r_stat_din rstat = {0};
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+ ret = rstat.tr_empty ? TIOCSER_TEMT : 0;
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+ return ret;
+}
+static unsigned int etraxfs_uart_get_mctrl(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ unsigned int ret;
+
+ ret = 0;
+ if (crisv32_serial_get_rts(up))
+ ret |= TIOCM_RTS;
+ /* DTR is active low */
+ if (up->dtr_pin && !gpiod_get_raw_value(up->dtr_pin))
+ ret |= TIOCM_DTR;
+ /* CD is active low */
+ if (up->cd_pin && !gpiod_get_raw_value(up->cd_pin))
+ ret |= TIOCM_CD;
+ /* RI is active low */
+ if (up->ri_pin && !gpiod_get_raw_value(up->ri_pin))
+ ret |= TIOCM_RI;
+ /* DSR is active low */
+ if (up->dsr_pin && !gpiod_get_raw_value(up->dsr_pin))
+ ret |= TIOCM_DSR;
+ if (crisv32_serial_get_cts(up))
+ ret |= TIOCM_CTS;
+ return ret;
+}
+
+static void etraxfs_uart_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+ crisv32_serial_set_rts(up, mctrl & TIOCM_RTS ? 1 : 0, 0);
+ /* DTR is active low */
+ if (up->dtr_pin)
+ gpiod_set_raw_value(up->dtr_pin, mctrl & TIOCM_DTR ? 0 : 1);
+ /* RI is active low */
+ if (up->ri_pin)
+ gpiod_set_raw_value(up->ri_pin, mctrl & TIOCM_RNG ? 0 : 1);
+ /* CD is active low */
+ if (up->cd_pin)
+ gpiod_set_raw_value(up->cd_pin, mctrl & TIOCM_CD ? 0 : 1);
+}
+
+static void etraxfs_uart_break_ctl(struct uart_port *port, int break_state)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ unsigned long flags;
+ reg_ser_rw_tr_ctrl tr_ctrl;
+ reg_ser_rw_tr_dma_en tr_dma_en;
+ reg_ser_rw_intr_mask intr_mask;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+ tr_ctrl = REG_RD(ser, up->regi_ser, rw_tr_ctrl);
+ tr_dma_en = REG_RD(ser, up->regi_ser, rw_tr_dma_en);
+ intr_mask = REG_RD(ser, up->regi_ser, rw_intr_mask);
+
+ if (break_state != 0) { /* Send break */
+ /*
+ * We need to disable DMA (if used) or tr_rdy interrupts if no
+ * DMA. No need to make this conditional on use of DMA;
+ * disabling will be a no-op for the other mode.
+ */
+ intr_mask.tr_rdy = regk_ser_no;
+ tr_dma_en.en = 0;
+
+ /*
+ * Stop transmission and set the txd pin to 0 after the
+ * current character. The txd setting will take effect after
+ * any current transmission has completed.
+ */
+ tr_ctrl.stop = 1;
+ tr_ctrl.txd = 0;
+ } else {
+ /* Re-enable the serial interrupt. */
+ intr_mask.tr_rdy = regk_ser_yes;
+
+ tr_ctrl.stop = 0;
+ tr_ctrl.txd = 1;
+ }
+ REG_WR(ser, up->regi_ser, rw_tr_ctrl, tr_ctrl);
+ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tr_dma_en);
+ REG_WR(ser, up->regi_ser, rw_intr_mask, intr_mask);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static void
+transmit_chars_no_dma(struct uart_cris_port *up)
+{
+ int max_count;
+ struct circ_buf *xmit = &up->port.state->xmit;
+
+ void __iomem *regi_ser = up->regi_ser;
+ reg_ser_r_stat_din rstat;
+ reg_ser_rw_ack_intr ack_intr = { .tr_rdy = regk_ser_yes };
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(&up->port)) {
+ /* No more to send, so disable the interrupt. */
+ reg_ser_rw_intr_mask intr_mask;
+
+ intr_mask = REG_RD(ser, regi_ser, rw_intr_mask);
+ intr_mask.tr_rdy = 0;
+ intr_mask.tr_empty = 0;
+ REG_WR(ser, regi_ser, rw_intr_mask, intr_mask);
+ up->write_ongoing = 0;
+ return;
+ }
+
+ /* If the serport is fast, we send up to max_count bytes before
+ exiting the loop. */
+ max_count = 64;
+ do {
+ reg_ser_rw_dout dout = { .data = xmit->buf[xmit->tail] };
+
+ REG_WR(ser, regi_ser, rw_dout, dout);
+ REG_WR(ser, regi_ser, rw_ack_intr, ack_intr);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE-1);
+ up->port.icount.tx++;
+ if (xmit->head == xmit->tail)
+ break;
+ rstat = REG_RD(ser, regi_ser, r_stat_din);
+ } while ((--max_count > 0) && rstat.tr_rdy);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&up->port);
+}
+
+static void receive_chars_no_dma(struct uart_cris_port *up)
+{
+ reg_ser_rs_stat_din stat_din;
+ reg_ser_r_stat_din rstat;
+ struct tty_port *port;
+ struct uart_icount *icount;
+ int max_count = 16;
+ char flag;
+ reg_ser_rw_ack_intr ack_intr = { 0 };
+
+ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+ icount = &up->port.icount;
+ port = &up->port.state->port;
+
+ do {
+ stat_din = REG_RD(ser, up->regi_ser, rs_stat_din);
+
+ flag = TTY_NORMAL;
+ ack_intr.dav = 1;
+ REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
+ icount->rx++;
+
+ if (stat_din.framing_err | stat_din.par_err | stat_din.orun) {
+ if (stat_din.data == 0x00 &&
+ stat_din.framing_err) {
+ /* Most likely a break. */
+ flag = TTY_BREAK;
+ icount->brk++;
+ } else if (stat_din.par_err) {
+ flag = TTY_PARITY;
+ icount->parity++;
+ } else if (stat_din.orun) {
+ flag = TTY_OVERRUN;
+ icount->overrun++;
+ } else if (stat_din.framing_err) {
+ flag = TTY_FRAME;
+ icount->frame++;
+ }
+ }
+
+ /*
+ * If this becomes important, we probably *could* handle this
+ * gracefully by keeping track of the unhandled character.
+ */
+ if (!tty_insert_flip_char(port, stat_din.data, flag))
+ panic("%s: No tty buffer space", __func__);
+ rstat = REG_RD(ser, up->regi_ser, r_stat_din);
+ } while (rstat.dav && (max_count-- > 0));
+ spin_unlock(&up->port.lock);
+ tty_flip_buffer_push(port);
+ spin_lock(&up->port.lock);
+}
+
+static irqreturn_t
+ser_interrupt(int irq, void *dev_id)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)dev_id;
+ void __iomem *regi_ser;
+ int handled = 0;
+
+ spin_lock(&up->port.lock);
+
+ regi_ser = up->regi_ser;
+
+ if (regi_ser) {
+ reg_ser_r_masked_intr masked_intr;
+
+ masked_intr = REG_RD(ser, regi_ser, r_masked_intr);
+ /*
+ * Check what interrupts are active before taking
+ * actions. If DMA is used the interrupt shouldn't
+ * be enabled.
+ */
+ if (masked_intr.dav) {
+ receive_chars_no_dma(up);
+ handled = 1;
+ }
+ check_modem_status(up);
+
+ if (masked_intr.tr_rdy) {
+ transmit_chars_no_dma(up);
+ handled = 1;
+ }
+ }
+ spin_unlock(&up->port.lock);
+ return IRQ_RETVAL(handled);
+}
+
+#ifdef CONFIG_CONSOLE_POLL
+static int etraxfs_uart_get_poll_char(struct uart_port *port)
+{
+ reg_ser_rs_stat_din stat;
+ reg_ser_rw_ack_intr ack_intr = { 0 };
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+ do {
+ stat = REG_RD(ser, up->regi_ser, rs_stat_din);
+ } while (!stat.dav);
+
+ /* Ack the data_avail interrupt. */
+ ack_intr.dav = 1;
+ REG_WR(ser, up->regi_ser, rw_ack_intr, ack_intr);
+
+ return stat.data;
+}
+
+static void etraxfs_uart_put_poll_char(struct uart_port *port,
+ unsigned char c)
+{
+ reg_ser_r_stat_din stat;
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+ do {
+ stat = REG_RD(ser, up->regi_ser, r_stat_din);
+ } while (!stat.tr_rdy);
+ REG_WR_INT(ser, up->regi_ser, rw_dout, c);
+}
+#endif /* CONFIG_CONSOLE_POLL */
+
+static int etraxfs_uart_startup(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ unsigned long flags;
+ reg_ser_rw_intr_mask ser_intr_mask = {0};
+
+ ser_intr_mask.dav = regk_ser_yes;
+
+ if (request_irq(etraxfs_uart_ports[port->line]->irq, ser_interrupt,
+ 0, DRV_NAME, etraxfs_uart_ports[port->line]))
+ panic("irq ser%d", port->line);
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ REG_WR(ser, up->regi_ser, rw_intr_mask, ser_intr_mask);
+
+ etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+ return 0;
+}
+
+static void etraxfs_uart_shutdown(struct uart_port *port)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ unsigned long flags;
+
+ spin_lock_irqsave(&up->port.lock, flags);
+
+ etraxfs_uart_stop_tx(port);
+ etraxfs_uart_stop_rx(port);
+
+ free_irq(etraxfs_uart_ports[port->line]->irq,
+ etraxfs_uart_ports[port->line]);
+
+ etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
+
+ spin_unlock_irqrestore(&up->port.lock, flags);
+
+}
+
+static void
+etraxfs_uart_set_termios(struct uart_port *port, struct ktermios *termios,
+ struct ktermios *old)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+ unsigned long flags;
+ reg_ser_rw_xoff xoff;
+ reg_ser_rw_xoff_clr xoff_clr = {0};
+ reg_ser_rw_tr_ctrl tx_ctrl = {0};
+ reg_ser_rw_tr_dma_en tx_dma_en = {0};
+ reg_ser_rw_rec_ctrl rx_ctrl = {0};
+ reg_ser_rw_tr_baud_div tx_baud_div = {0};
+ reg_ser_rw_rec_baud_div rx_baud_div = {0};
+ int baud;
+
+ if (old &&
+ termios->c_cflag == old->c_cflag &&
+ termios->c_iflag == old->c_iflag)
+ return;
+
+ /* Tx: 8 bit, no/even parity, 1 stop bit, no cts. */
+ tx_ctrl.base_freq = regk_ser_f29_493;
+ tx_ctrl.en = 0;
+ tx_ctrl.stop = 0;
+ tx_ctrl.auto_rts = regk_ser_no;
+ tx_ctrl.txd = 1;
+ tx_ctrl.auto_cts = 0;
+ /* Rx: 8 bit, no/even parity. */
+ rx_ctrl.dma_err = regk_ser_stop;
+ rx_ctrl.sampling = regk_ser_majority;
+ rx_ctrl.timeout = 1;
+
+ rx_ctrl.rts_n = regk_ser_inactive;
+
+ /* Common for tx and rx: 8N1. */
+ tx_ctrl.data_bits = regk_ser_bits8;
+ rx_ctrl.data_bits = regk_ser_bits8;
+ tx_ctrl.par = regk_ser_even;
+ rx_ctrl.par = regk_ser_even;
+ tx_ctrl.par_en = regk_ser_no;
+ rx_ctrl.par_en = regk_ser_no;
+
+ tx_ctrl.stop_bits = regk_ser_bits1;
+
+ /*
+ * Change baud-rate and write it to the hardware.
+ *
+ * baud_clock = base_freq / (divisor*8)
+ * divisor = base_freq / (baud_clock * 8)
+ * base_freq is either:
+ * off, ext, 29.493MHz, 32.000 MHz, 32.768 MHz or 100 MHz
+ * 20.493MHz is used for standard baudrates
+ */
+
+ /*
+ * For the console port we keep the original baudrate here. Not very
+ * beautiful.
+ */
+ if ((port != console_port) || old)
+ baud = uart_get_baud_rate(port, termios, old, 0,
+ port->uartclk / 8);
+ else
+ baud = console_baud;
+
+ tx_baud_div.div = 29493000 / (8 * baud);
+ /* Rx uses same as tx. */
+ rx_baud_div.div = tx_baud_div.div;
+ rx_ctrl.base_freq = tx_ctrl.base_freq;
+
+ if ((termios->c_cflag & CSIZE) == CS7) {
+ /* Set 7 bit mode. */
+ tx_ctrl.data_bits = regk_ser_bits7;
+ rx_ctrl.data_bits = regk_ser_bits7;
+ }
+
+ if (termios->c_cflag & CSTOPB) {
+ /* Set 2 stop bit mode. */
+ tx_ctrl.stop_bits = regk_ser_bits2;
+ }
+
+ if (termios->c_cflag & PARENB) {
+ /* Enable parity. */
+ tx_ctrl.par_en = regk_ser_yes;
+ rx_ctrl.par_en = regk_ser_yes;
+ }
+
+ if (termios->c_cflag & CMSPAR) {
+ if (termios->c_cflag & PARODD) {
+ /* Set mark parity if PARODD and CMSPAR. */
+ tx_ctrl.par = regk_ser_mark;
+ rx_ctrl.par = regk_ser_mark;
+ } else {
+ tx_ctrl.par = regk_ser_space;
+ rx_ctrl.par = regk_ser_space;
+ }
+ } else {
+ if (termios->c_cflag & PARODD) {
+ /* Set odd parity. */
+ tx_ctrl.par = regk_ser_odd;
+ rx_ctrl.par = regk_ser_odd;
+ }
+ }
+
+ if (termios->c_cflag & CRTSCTS) {
+ /* Enable automatic CTS handling. */
+ tx_ctrl.auto_cts = regk_ser_yes;
+ }
+
+ /* Make sure the tx and rx are enabled. */
+ tx_ctrl.en = regk_ser_yes;
+ rx_ctrl.en = regk_ser_yes;
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ tx_dma_en.en = 0;
+ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
+
+ /* Actually write the control regs (if modified) to the hardware. */
+ uart_update_timeout(port, termios->c_cflag, port->uartclk/8);
+ MODIFY_REG(up->regi_ser, rw_rec_baud_div, rx_baud_div);
+ MODIFY_REG(up->regi_ser, rw_rec_ctrl, rx_ctrl);
+
+ MODIFY_REG(up->regi_ser, rw_tr_baud_div, tx_baud_div);
+ MODIFY_REG(up->regi_ser, rw_tr_ctrl, tx_ctrl);
+
+ tx_dma_en.en = 0;
+ REG_WR(ser, up->regi_ser, rw_tr_dma_en, tx_dma_en);
+
+ xoff = REG_RD(ser, up->regi_ser, rw_xoff);
+
+ if (up->port.state && up->port.state->port.tty &&
+ (up->port.state->port.tty->termios.c_iflag & IXON)) {
+ xoff.chr = STOP_CHAR(up->port.state->port.tty);
+ xoff.automatic = regk_ser_yes;
+ } else
+ xoff.automatic = regk_ser_no;
+
+ MODIFY_REG(up->regi_ser, rw_xoff, xoff);
+
+ /*
+ * Make sure we don't start in an automatically shut-off state due to
+ * a previous early exit.
+ */
+ xoff_clr.clr = 1;
+ REG_WR(ser, up->regi_ser, rw_xoff_clr, xoff_clr);
+
+ etraxfs_uart_set_mctrl(&up->port, up->port.mctrl);
+ spin_unlock_irqrestore(&up->port.lock, flags);
+}
+
+static const char *
+etraxfs_uart_type(struct uart_port *port)
+{
+ return "CRISv32";
+}
+
+static void etraxfs_uart_release_port(struct uart_port *port)
+{
+}
+
+static int etraxfs_uart_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void etraxfs_uart_config_port(struct uart_port *port, int flags)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+ up->port.type = PORT_CRIS;
+}
+
+static const struct uart_ops etraxfs_uart_pops = {
+ .tx_empty = etraxfs_uart_tx_empty,
+ .set_mctrl = etraxfs_uart_set_mctrl,
+ .get_mctrl = etraxfs_uart_get_mctrl,
+ .stop_tx = etraxfs_uart_stop_tx,
+ .start_tx = etraxfs_uart_start_tx,
+ .send_xchar = etraxfs_uart_send_xchar,
+ .stop_rx = etraxfs_uart_stop_rx,
+ .enable_ms = etraxfs_uart_enable_ms,
+ .break_ctl = etraxfs_uart_break_ctl,
+ .startup = etraxfs_uart_startup,
+ .shutdown = etraxfs_uart_shutdown,
+ .set_termios = etraxfs_uart_set_termios,
+ .type = etraxfs_uart_type,
+ .release_port = etraxfs_uart_release_port,
+ .request_port = etraxfs_uart_request_port,
+ .config_port = etraxfs_uart_config_port,
+#ifdef CONFIG_CONSOLE_POLL
+ .poll_get_char = etraxfs_uart_get_poll_char,
+ .poll_put_char = etraxfs_uart_put_poll_char,
+#endif
+};
+
+static void cris_serial_port_init(struct uart_port *port, int line)
+{
+ struct uart_cris_port *up = (struct uart_cris_port *)port;
+
+ if (up->initialized)
+ return;
+ up->initialized = 1;
+ port->line = line;
+ spin_lock_init(&port->lock);
+ port->ops = &etraxfs_uart_pops;
+ port->irq = up->irq;
+ port->iobase = (unsigned long) up->regi_ser;
+ port->uartclk = 29493000;
+
+ /*
+ * We can't fit any more than 255 here (unsigned char), though
+ * actually UART_XMIT_SIZE characters could be pending output.
+ * At time of this writing, the definition of "fifosize" is here the
+ * amount of characters that can be pending output after a start_tx call
+ * until tx_empty returns 1: see serial_core.c:uart_wait_until_sent.
+ * This matters for timeout calculations unfortunately, but keeping
+ * larger amounts at the DMA wouldn't win much so let's just play nice.
+ */
+ port->fifosize = 255;
+ port->flags = UPF_BOOT_AUTOCONF;
+}
+
+static int etraxfs_uart_probe(struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct uart_cris_port *up;
+ int dev_id;
+
+ if (!np)
+ return -ENODEV;
+
+ dev_id = of_alias_get_id(np, "serial");
+ if (dev_id < 0)
+ dev_id = 0;
+
+ if (dev_id >= UART_NR)
+ return -EINVAL;
+
+ if (etraxfs_uart_ports[dev_id])
+ return -EBUSY;
+
+ up = devm_kzalloc(&pdev->dev, sizeof(struct uart_cris_port),
+ GFP_KERNEL);
+ if (!up)
+ return -ENOMEM;
+
+ up->irq = irq_of_parse_and_map(np, 0);
+ up->regi_ser = of_iomap(np, 0);
+ up->dtr_pin = devm_gpiod_get_optional(&pdev->dev, "dtr");
+ up->dsr_pin = devm_gpiod_get_optional(&pdev->dev, "dsr");
+ up->ri_pin = devm_gpiod_get_optional(&pdev->dev, "ri");
+ up->cd_pin = devm_gpiod_get_optional(&pdev->dev, "cd");
+ up->port.dev = &pdev->dev;
+ cris_serial_port_init(&up->port, dev_id);
+
+ etraxfs_uart_ports[dev_id] = up;
+ platform_set_drvdata(pdev, &up->port);
+ uart_add_one_port(&etraxfs_uart_driver, &up->port);
+
+ return 0;
+}
+
+static int etraxfs_uart_remove(struct platform_device *pdev)
+{
+ struct uart_port *port;
+
+ port = platform_get_drvdata(pdev);
+ uart_remove_one_port(&etraxfs_uart_driver, port);
+ etraxfs_uart_ports[pdev->id] = NULL;
+
+ return 0;
+}
+
+static const struct of_device_id etraxfs_uart_dt_ids[] = {
+ { .compatible = "axis,etraxfs-uart" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, etraxfs_uart_dt_ids);
+
+static struct platform_driver etraxfs_uart_platform_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = of_match_ptr(etraxfs_uart_dt_ids),
+ },
+ .probe = etraxfs_uart_probe,
+ .remove = etraxfs_uart_remove,
+};
+
+static int __init etraxfs_uart_init(void)
+{
+ int ret;
+
+ ret = uart_register_driver(&etraxfs_uart_driver);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&etraxfs_uart_platform_driver);
+ if (ret)
+ uart_unregister_driver(&etraxfs_uart_driver);
+
+ return ret;
+}
+
+static void __exit etraxfs_uart_exit(void)
+{
+ platform_driver_unregister(&etraxfs_uart_platform_driver);
+ uart_unregister_driver(&etraxfs_uart_driver);
+}
+
+module_init(etraxfs_uart_init);
+module_exit(etraxfs_uart_exit);
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index e7cde3a9566d..b1893f3f88f1 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -237,7 +237,8 @@ struct lpuart_port {
unsigned int rxfifo_size;
bool lpuart32;
- bool lpuart_dma_use;
+ bool lpuart_dma_tx_use;
+ bool lpuart_dma_rx_use;
struct dma_chan *dma_tx_chan;
struct dma_chan *dma_rx_chan;
struct dma_async_tx_descriptor *dma_tx_desc;
@@ -454,6 +455,15 @@ static int lpuart_dma_rx(struct lpuart_port *sport)
return 0;
}
+static void lpuart_flush_buffer(struct uart_port *port)
+{
+ struct lpuart_port *sport = container_of(port, struct lpuart_port, port);
+ if (sport->lpuart_dma_tx_use) {
+ dmaengine_terminate_all(sport->dma_tx_chan);
+ sport->dma_tx_in_progress = 0;
+ }
+}
+
static void lpuart_dma_rx_complete(void *arg)
{
struct lpuart_port *sport = arg;
@@ -461,6 +471,7 @@ static void lpuart_dma_rx_complete(void *arg)
unsigned long flags;
async_tx_ack(sport->dma_rx_desc);
+ mod_timer(&sport->lpuart_timer, jiffies + sport->dma_rx_timeout);
spin_lock_irqsave(&sport->port.lock, flags);
@@ -506,9 +517,6 @@ static inline void lpuart_prepare_rx(struct lpuart_port *sport)
spin_lock_irqsave(&sport->port.lock, flags);
- init_timer(&sport->lpuart_timer);
- sport->lpuart_timer.function = lpuart_timer_func;
- sport->lpuart_timer.data = (unsigned long)sport;
sport->lpuart_timer.expires = jiffies + sport->dma_rx_timeout;
add_timer(&sport->lpuart_timer);
@@ -571,7 +579,7 @@ static void lpuart_start_tx(struct uart_port *port)
temp = readb(port->membase + UARTCR2);
writeb(temp | UARTCR2_TIE, port->membase + UARTCR2);
- if (sport->lpuart_dma_use) {
+ if (sport->lpuart_dma_tx_use) {
if (!uart_circ_empty(xmit) && !sport->dma_tx_in_progress)
lpuart_prepare_tx(sport);
} else {
@@ -758,19 +766,19 @@ out:
static irqreturn_t lpuart_int(int irq, void *dev_id)
{
struct lpuart_port *sport = dev_id;
- unsigned char sts;
+ unsigned char sts, crdma;
sts = readb(sport->port.membase + UARTSR1);
+ crdma = readb(sport->port.membase + UARTCR5);
- if (sts & UARTSR1_RDRF) {
- if (sport->lpuart_dma_use)
+ if (sts & UARTSR1_RDRF && !(crdma & UARTCR5_RDMAS)) {
+ if (sport->lpuart_dma_rx_use)
lpuart_prepare_rx(sport);
else
lpuart_rxint(irq, dev_id);
}
- if (sts & UARTSR1_TDRE &&
- !(readb(sport->port.membase + UARTCR5) & UARTCR5_TDMAS)) {
- if (sport->lpuart_dma_use)
+ if (sts & UARTSR1_TDRE && !(crdma & UARTCR5_TDMAS)) {
+ if (sport->lpuart_dma_tx_use)
lpuart_pio_tx(sport);
else
lpuart_txint(irq, dev_id);
@@ -953,26 +961,17 @@ static int lpuart_dma_tx_request(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- struct dma_chan *tx_chan;
struct dma_slave_config dma_tx_sconfig;
dma_addr_t dma_bus;
unsigned char *dma_buf;
int ret;
- tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
-
- if (!tx_chan) {
- dev_err(sport->port.dev, "Dma tx channel request failed!\n");
- return -ENODEV;
- }
-
- dma_bus = dma_map_single(tx_chan->device->dev,
+ dma_bus = dma_map_single(sport->dma_tx_chan->device->dev,
sport->port.state->xmit.buf,
UART_XMIT_SIZE, DMA_TO_DEVICE);
- if (dma_mapping_error(tx_chan->device->dev, dma_bus)) {
+ if (dma_mapping_error(sport->dma_tx_chan->device->dev, dma_bus)) {
dev_err(sport->port.dev, "dma_map_single tx failed\n");
- dma_release_channel(tx_chan);
return -ENOMEM;
}
@@ -981,16 +980,14 @@ static int lpuart_dma_tx_request(struct uart_port *port)
dma_tx_sconfig.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_tx_sconfig.dst_maxburst = sport->txfifo_size;
dma_tx_sconfig.direction = DMA_MEM_TO_DEV;
- ret = dmaengine_slave_config(tx_chan, &dma_tx_sconfig);
+ ret = dmaengine_slave_config(sport->dma_tx_chan, &dma_tx_sconfig);
if (ret < 0) {
dev_err(sport->port.dev,
"Dma slave config failed, err = %d\n", ret);
- dma_release_channel(tx_chan);
return ret;
}
- sport->dma_tx_chan = tx_chan;
sport->dma_tx_buf_virt = dma_buf;
sport->dma_tx_buf_bus = dma_bus;
sport->dma_tx_in_progress = 0;
@@ -1002,34 +999,24 @@ static int lpuart_dma_rx_request(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- struct dma_chan *rx_chan;
struct dma_slave_config dma_rx_sconfig;
dma_addr_t dma_bus;
unsigned char *dma_buf;
int ret;
- rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
-
- if (!rx_chan) {
- dev_err(sport->port.dev, "Dma rx channel request failed!\n");
- return -ENODEV;
- }
-
dma_buf = devm_kzalloc(sport->port.dev,
FSL_UART_RX_DMA_BUFFER_SIZE, GFP_KERNEL);
if (!dma_buf) {
dev_err(sport->port.dev, "Dma rx alloc failed\n");
- dma_release_channel(rx_chan);
return -ENOMEM;
}
- dma_bus = dma_map_single(rx_chan->device->dev, dma_buf,
+ dma_bus = dma_map_single(sport->dma_rx_chan->device->dev, dma_buf,
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
- if (dma_mapping_error(rx_chan->device->dev, dma_bus)) {
+ if (dma_mapping_error(sport->dma_rx_chan->device->dev, dma_bus)) {
dev_err(sport->port.dev, "dma_map_single rx failed\n");
- dma_release_channel(rx_chan);
return -ENOMEM;
}
@@ -1037,16 +1024,14 @@ static int lpuart_dma_rx_request(struct uart_port *port)
dma_rx_sconfig.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
dma_rx_sconfig.src_maxburst = 1;
dma_rx_sconfig.direction = DMA_DEV_TO_MEM;
- ret = dmaengine_slave_config(rx_chan, &dma_rx_sconfig);
+ ret = dmaengine_slave_config(sport->dma_rx_chan, &dma_rx_sconfig);
if (ret < 0) {
dev_err(sport->port.dev,
"Dma slave config failed, err = %d\n", ret);
- dma_release_channel(rx_chan);
return ret;
}
- sport->dma_rx_chan = rx_chan;
sport->dma_rx_buf_virt = dma_buf;
sport->dma_rx_buf_bus = dma_bus;
sport->dma_rx_in_progress = 0;
@@ -1058,31 +1043,24 @@ static void lpuart_dma_tx_free(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- struct dma_chan *dma_chan;
dma_unmap_single(sport->port.dev, sport->dma_tx_buf_bus,
UART_XMIT_SIZE, DMA_TO_DEVICE);
- dma_chan = sport->dma_tx_chan;
- sport->dma_tx_chan = NULL;
+
sport->dma_tx_buf_bus = 0;
sport->dma_tx_buf_virt = NULL;
- dma_release_channel(dma_chan);
}
static void lpuart_dma_rx_free(struct uart_port *port)
{
struct lpuart_port *sport = container_of(port,
struct lpuart_port, port);
- struct dma_chan *dma_chan;
dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus,
FSL_UART_RX_DMA_BUFFER_SIZE, DMA_FROM_DEVICE);
- dma_chan = sport->dma_rx_chan;
- sport->dma_rx_chan = NULL;
sport->dma_rx_buf_bus = 0;
sport->dma_rx_buf_virt = NULL;
- dma_release_channel(dma_chan);
}
static int lpuart_startup(struct uart_port *port)
@@ -1101,14 +1079,21 @@ static int lpuart_startup(struct uart_port *port)
sport->rxfifo_size = 0x1 << (((temp >> UARTPFIFO_RXSIZE_OFF) &
UARTPFIFO_FIFOSIZE_MASK) + 1);
- /* Whether use dma support by dma request results */
- if (lpuart_dma_tx_request(port) || lpuart_dma_rx_request(port)) {
- sport->lpuart_dma_use = false;
- } else {
- sport->lpuart_dma_use = true;
+ if (sport->dma_rx_chan && !lpuart_dma_rx_request(port)) {
+ sport->lpuart_dma_rx_use = true;
+ setup_timer(&sport->lpuart_timer, lpuart_timer_func,
+ (unsigned long)sport);
+ } else
+ sport->lpuart_dma_rx_use = false;
+
+
+ if (sport->dma_tx_chan && !lpuart_dma_tx_request(port)) {
+ sport->lpuart_dma_tx_use = true;
temp = readb(port->membase + UARTCR5);
+ temp &= ~UARTCR5_RDMAS;
writeb(temp | UARTCR5_TDMAS, port->membase + UARTCR5);
- }
+ } else
+ sport->lpuart_dma_tx_use = false;
ret = devm_request_irq(port->dev, port->irq, lpuart_int, 0,
DRIVER_NAME, sport);
@@ -1179,10 +1164,13 @@ static void lpuart_shutdown(struct uart_port *port)
devm_free_irq(port->dev, port->irq, sport);
- if (sport->lpuart_dma_use) {
- lpuart_dma_tx_free(port);
- lpuart_dma_rx_free(port);
+ if (sport->lpuart_dma_rx_use) {
+ lpuart_dma_rx_free(&sport->port);
+ del_timer_sync(&sport->lpuart_timer);
}
+
+ if (sport->lpuart_dma_tx_use)
+ lpuart_dma_tx_free(&sport->port);
}
static void lpuart32_shutdown(struct uart_port *port)
@@ -1304,7 +1292,7 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
- if (sport->lpuart_dma_use) {
+ if (sport->lpuart_dma_rx_use) {
/* Calculate delay for 1.5 DMA buffers */
sport->dma_rx_timeout = (sport->port.timeout - HZ / 50) *
FSL_UART_RX_DMA_BUFFER_SIZE * 3 /
@@ -1517,6 +1505,7 @@ static struct uart_ops lpuart_pops = {
.release_port = lpuart_release_port,
.config_port = lpuart_config_port,
.verify_port = lpuart_verify_port,
+ .flush_buffer = lpuart_flush_buffer,
};
static struct uart_ops lpuart32_pops = {
@@ -1535,6 +1524,7 @@ static struct uart_ops lpuart32_pops = {
.release_port = lpuart_release_port,
.config_port = lpuart_config_port,
.verify_port = lpuart_verify_port,
+ .flush_buffer = lpuart_flush_buffer,
};
static struct lpuart_port *lpuart_ports[UART_NR];
@@ -1833,6 +1823,16 @@ static int lpuart_probe(struct platform_device *pdev)
return ret;
}
+ sport->dma_tx_chan = dma_request_slave_channel(sport->port.dev, "tx");
+ if (!sport->dma_tx_chan)
+ dev_info(sport->port.dev, "DMA tx channel request failed, "
+ "operating without tx DMA\n");
+
+ sport->dma_rx_chan = dma_request_slave_channel(sport->port.dev, "rx");
+ if (!sport->dma_rx_chan)
+ dev_info(sport->port.dev, "DMA rx channel request failed, "
+ "operating without rx DMA\n");
+
return 0;
}
@@ -1844,6 +1844,12 @@ static int lpuart_remove(struct platform_device *pdev)
clk_disable_unprepare(sport->clk);
+ if (sport->dma_tx_chan)
+ dma_release_channel(sport->dma_tx_chan);
+
+ if (sport->dma_rx_chan)
+ dma_release_channel(sport->dma_rx_chan);
+
return 0;
}
@@ -1851,6 +1857,19 @@ static int lpuart_remove(struct platform_device *pdev)
static int lpuart_suspend(struct device *dev)
{
struct lpuart_port *sport = dev_get_drvdata(dev);
+ unsigned long temp;
+
+ if (sport->lpuart32) {
+ /* disable Rx/Tx and interrupts */
+ temp = lpuart32_read(sport->port.membase + UARTCTRL);
+ temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE);
+ lpuart32_write(temp, sport->port.membase + UARTCTRL);
+ } else {
+ /* disable Rx/Tx and interrupts */
+ temp = readb(sport->port.membase + UARTCR2);
+ temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE);
+ writeb(temp, sport->port.membase + UARTCR2);
+ }
uart_suspend_port(&lpuart_reg, &sport->port);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 4c5e9092e2d7..0eb29b1c47ac 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -74,6 +74,7 @@
#define IMX21_UTS 0xb4 /* UART Test Register on all other i.mx*/
/* UART Control Register Bit Fields.*/
+#define URXD_DUMMY_READ (1<<16)
#define URXD_CHARRDY (1<<15)
#define URXD_ERR (1<<14)
#define URXD_OVRRUN (1<<13)
@@ -463,13 +464,17 @@ static void imx_enable_ms(struct uart_port *port)
mod_timer(&sport->timer, jiffies);
}
+static void imx_dma_tx(struct imx_port *sport);
static inline void imx_transmit_buffer(struct imx_port *sport)
{
struct circ_buf *xmit = &sport->port.state->xmit;
+ unsigned long temp;
if (sport->port.x_char) {
/* Send next char */
writel(sport->port.x_char, sport->port.membase + URTX0);
+ sport->port.icount.tx++;
+ sport->port.x_char = 0;
return;
}
@@ -478,6 +483,22 @@ static inline void imx_transmit_buffer(struct imx_port *sport)
return;
}
+ if (sport->dma_is_enabled) {
+ /*
+ * We've just sent a X-char Ensure the TX DMA is enabled
+ * and the TX IRQ is disabled.
+ **/
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~UCR1_TXMPTYEN;
+ if (sport->dma_is_txing) {
+ temp |= UCR1_TDMAEN;
+ writel(temp, sport->port.membase + UCR1);
+ } else {
+ writel(temp, sport->port.membase + UCR1);
+ imx_dma_tx(sport);
+ }
+ }
+
while (!uart_circ_empty(xmit) &&
!(readl(sport->port.membase + uts_reg(sport)) & UTS_TXFULL)) {
/* send xmit->buf[xmit->tail]
@@ -500,26 +521,39 @@ static void dma_tx_callback(void *data)
struct scatterlist *sgl = &sport->tx_sgl[0];
struct circ_buf *xmit = &sport->port.state->xmit;
unsigned long flags;
+ unsigned long temp;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
- sport->dma_is_txing = 0;
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~UCR1_TDMAEN;
+ writel(temp, sport->port.membase + UCR1);
/* update the stat */
- spin_lock_irqsave(&sport->port.lock, flags);
xmit->tail = (xmit->tail + sport->tx_bytes) & (UART_XMIT_SIZE - 1);
sport->port.icount.tx += sport->tx_bytes;
- spin_unlock_irqrestore(&sport->port.lock, flags);
dev_dbg(sport->port.dev, "we finish the TX DMA.\n");
- uart_write_wakeup(&sport->port);
+ sport->dma_is_txing = 0;
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(&sport->port);
if (waitqueue_active(&sport->dma_wait)) {
wake_up(&sport->dma_wait);
dev_dbg(sport->port.dev, "exit in %s.\n", __func__);
return;
}
+
+ spin_lock_irqsave(&sport->port.lock, flags);
+ if (!uart_circ_empty(xmit) && !uart_tx_stopped(&sport->port))
+ imx_dma_tx(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static void imx_dma_tx(struct imx_port *sport)
@@ -529,24 +563,23 @@ static void imx_dma_tx(struct imx_port *sport)
struct dma_async_tx_descriptor *desc;
struct dma_chan *chan = sport->dma_chan_tx;
struct device *dev = sport->port.dev;
- enum dma_status status;
+ unsigned long temp;
int ret;
- status = dmaengine_tx_status(chan, (dma_cookie_t)0, NULL);
- if (DMA_IN_PROGRESS == status)
+ if (sport->dma_is_txing)
return;
sport->tx_bytes = uart_circ_chars_pending(xmit);
- if (xmit->tail > xmit->head && xmit->head > 0) {
+ if (xmit->tail < xmit->head) {
+ sport->dma_tx_nents = 1;
+ sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
+ } else {
sport->dma_tx_nents = 2;
sg_init_table(sgl, 2);
sg_set_buf(sgl, xmit->buf + xmit->tail,
UART_XMIT_SIZE - xmit->tail);
sg_set_buf(sgl + 1, xmit->buf, xmit->head);
- } else {
- sport->dma_tx_nents = 1;
- sg_init_one(sgl, xmit->buf + xmit->tail, sport->tx_bytes);
}
ret = dma_map_sg(dev, sgl, sport->dma_tx_nents, DMA_TO_DEVICE);
@@ -557,6 +590,8 @@ static void imx_dma_tx(struct imx_port *sport)
desc = dmaengine_prep_slave_sg(chan, sgl, sport->dma_tx_nents,
DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
if (!desc) {
+ dma_unmap_sg(dev, sgl, sport->dma_tx_nents,
+ DMA_TO_DEVICE);
dev_err(dev, "We cannot prepare for the TX slave dma!\n");
return;
}
@@ -565,6 +600,11 @@ static void imx_dma_tx(struct imx_port *sport)
dev_dbg(dev, "TX: prepare to send %lu bytes by DMA.\n",
uart_circ_chars_pending(xmit));
+
+ temp = readl(sport->port.membase + UCR1);
+ temp |= UCR1_TDMAEN;
+ writel(temp, sport->port.membase + UCR1);
+
/* fire it */
sport->dma_is_txing = 1;
dmaengine_submit(desc);
@@ -590,13 +630,6 @@ static void imx_start_tx(struct uart_port *port)
temp &= ~(UCR1_RRDYEN);
writel(temp, sport->port.membase + UCR1);
}
- /* Clear any pending ORE flag before enabling interrupt */
- temp = readl(sport->port.membase + USR2);
- writel(temp | USR2_ORE, sport->port.membase + USR2);
-
- temp = readl(sport->port.membase + UCR4);
- temp |= UCR4_OREN;
- writel(temp, sport->port.membase + UCR4);
if (!sport->dma_is_enabled) {
temp = readl(sport->port.membase + UCR1);
@@ -614,15 +647,21 @@ static void imx_start_tx(struct uart_port *port)
}
if (sport->dma_is_enabled) {
- /* FIXME: port->x_char must be transmitted if != 0 */
+ if (sport->port.x_char) {
+ /* We have X-char to send, so enable TX IRQ and
+ * disable TX DMA to let TX interrupt to send X-char */
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~UCR1_TDMAEN;
+ temp |= UCR1_TXMPTYEN;
+ writel(temp, sport->port.membase + UCR1);
+ return;
+ }
+
if (!uart_circ_empty(&port->state->xmit) &&
!uart_tx_stopped(port))
imx_dma_tx(sport);
return;
}
-
- if (readl(sport->port.membase + uts_reg(sport)) & UTS_TXEMPTY)
- imx_transmit_buffer(sport);
}
static irqreturn_t imx_rtsint(int irq, void *dev_id)
@@ -694,7 +733,7 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
continue;
}
- rx &= sport->port.read_status_mask;
+ rx &= (sport->port.read_status_mask | 0xFF);
if (rx & URXD_BRK)
flg = TTY_BREAK;
@@ -710,6 +749,9 @@ static irqreturn_t imx_rxint(int irq, void *dev_id)
#endif
}
+ if (sport->port.ignore_status_mask & URXD_DUMMY_READ)
+ goto out;
+
tty_insert_flip_char(port, rx, flg);
}
@@ -727,6 +769,9 @@ static int start_rx_dma(struct imx_port *sport);
static void imx_dma_rxint(struct imx_port *sport)
{
unsigned long temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
temp = readl(sport->port.membase + USR2);
if ((temp & USR2_RDR) && !sport->dma_is_rxing) {
@@ -740,6 +785,8 @@ static void imx_dma_rxint(struct imx_port *sport)
/* tell the DMA to receive the data. */
start_rx_dma(sport);
}
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
static irqreturn_t imx_int(int irq, void *dev_id)
@@ -869,6 +916,9 @@ static int imx_setup_ufcr(struct imx_port *sport, unsigned int mode)
static void imx_rx_dma_done(struct imx_port *sport)
{
unsigned long temp;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sport->port.lock, flags);
/* Enable this interrupt when the RXFIFO is empty. */
temp = readl(sport->port.membase + UCR1);
@@ -880,6 +930,8 @@ static void imx_rx_dma_done(struct imx_port *sport)
/* Is the shutdown waiting for us? */
if (waitqueue_active(&sport->dma_wait))
wake_up(&sport->dma_wait);
+
+ spin_unlock_irqrestore(&sport->port.lock, flags);
}
/*
@@ -910,12 +962,26 @@ static void dma_rx_callback(void *data)
dev_dbg(sport->port.dev, "We get %d bytes.\n", count);
if (count) {
- tty_insert_flip_string(port, sport->rx_buf, count);
+ if (!(sport->port.ignore_status_mask & URXD_DUMMY_READ))
+ tty_insert_flip_string(port, sport->rx_buf, count);
tty_flip_buffer_push(port);
start_rx_dma(sport);
- } else
+ } else if (readl(sport->port.membase + USR2) & USR2_RDR) {
+ /*
+ * start rx_dma directly once data in RXFIFO, more efficient
+ * than before:
+ * 1. call imx_rx_dma_done to stop dma if no data received
+ * 2. wait next RDR interrupt to start dma transfer.
+ */
+ start_rx_dma(sport);
+ } else {
+ /*
+ * stop dma to prevent too many IDLE event trigged if no data
+ * in RXFIFO
+ */
imx_rx_dma_done(sport);
+ }
}
static int start_rx_dma(struct imx_port *sport)
@@ -935,6 +1001,7 @@ static int start_rx_dma(struct imx_port *sport)
desc = dmaengine_prep_slave_sg(chan, sgl, 1, DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT);
if (!desc) {
+ dma_unmap_sg(dev, sgl, 1, DMA_FROM_DEVICE);
dev_err(dev, "We cannot prepare for the RX slave dma!\n");
return -EINVAL;
}
@@ -1108,12 +1175,20 @@ static int imx_startup(struct uart_port *port)
while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
udelay(1);
+ /* Can we enable the DMA support? */
+ if (is_imx6q_uart(sport) && !uart_console(port) &&
+ !sport->dma_is_inited)
+ imx_uart_dma_init(sport);
+
spin_lock_irqsave(&sport->port.lock, flags);
/*
* Finally, clear and enable interrupts
*/
writel(USR1_RTSD, sport->port.membase + USR1);
+ if (sport->dma_is_inited && !sport->dma_is_enabled)
+ imx_enable_dma(sport);
+
temp = readl(sport->port.membase + UCR1);
temp |= UCR1_RRDYEN | UCR1_RTSDEN | UCR1_UARTEN;
@@ -1124,6 +1199,14 @@ static int imx_startup(struct uart_port *port)
writel(temp, sport->port.membase + UCR1);
+ /* Clear any pending ORE flag before enabling interrupt */
+ temp = readl(sport->port.membase + USR2);
+ writel(temp | USR2_ORE, sport->port.membase + USR2);
+
+ temp = readl(sport->port.membase + UCR4);
+ temp |= UCR4_OREN;
+ writel(temp, sport->port.membase + UCR4);
+
temp = readl(sport->port.membase + UCR2);
temp |= (UCR2_RXEN | UCR2_TXEN);
if (!sport->have_rtscts)
@@ -1189,9 +1272,11 @@ static void imx_shutdown(struct uart_port *port)
dmaengine_terminate_all(sport->dma_chan_tx);
dmaengine_terminate_all(sport->dma_chan_rx);
}
+ spin_lock_irqsave(&sport->port.lock, flags);
imx_stop_tx(port);
imx_stop_rx(port);
imx_disable_dma(sport);
+ spin_unlock_irqrestore(&sport->port.lock, flags);
imx_uart_dma_exit(sport);
}
@@ -1233,11 +1318,48 @@ static void imx_shutdown(struct uart_port *port)
static void imx_flush_buffer(struct uart_port *port)
{
struct imx_port *sport = (struct imx_port *)port;
+ struct scatterlist *sgl = &sport->tx_sgl[0];
+ unsigned long temp;
+ int i = 100, ubir, ubmr, ubrc, uts;
- if (sport->dma_is_enabled) {
- sport->tx_bytes = 0;
- dmaengine_terminate_all(sport->dma_chan_tx);
+ if (!sport->dma_chan_tx)
+ return;
+
+ sport->tx_bytes = 0;
+ dmaengine_terminate_all(sport->dma_chan_tx);
+ if (sport->dma_is_txing) {
+ dma_unmap_sg(sport->port.dev, sgl, sport->dma_tx_nents,
+ DMA_TO_DEVICE);
+ temp = readl(sport->port.membase + UCR1);
+ temp &= ~UCR1_TDMAEN;
+ writel(temp, sport->port.membase + UCR1);
+ sport->dma_is_txing = false;
}
+
+ /*
+ * According to the Reference Manual description of the UART SRST bit:
+ * "Reset the transmit and receive state machines,
+ * all FIFOs and register USR1, USR2, UBIR, UBMR, UBRC, URXD, UTXD
+ * and UTS[6-3]". As we don't need to restore the old values from
+ * USR1, USR2, URXD, UTXD, only save/restore the other four registers
+ */
+ ubir = readl(sport->port.membase + UBIR);
+ ubmr = readl(sport->port.membase + UBMR);
+ ubrc = readl(sport->port.membase + UBRC);
+ uts = readl(sport->port.membase + IMX21_UTS);
+
+ temp = readl(sport->port.membase + UCR2);
+ temp &= ~UCR2_SRST;
+ writel(temp, sport->port.membase + UCR2);
+
+ while (!(readl(sport->port.membase + UCR2) & UCR2_SRST) && (--i > 0))
+ udelay(1);
+
+ /* Restore the registers */
+ writel(ubir, sport->port.membase + UBIR);
+ writel(ubmr, sport->port.membase + UBMR);
+ writel(ubrc, sport->port.membase + UBRC);
+ writel(uts, sport->port.membase + IMX21_UTS);
}
static void
@@ -1280,11 +1402,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (sport->have_rtscts) {
ucr2 &= ~UCR2_IRTS;
ucr2 |= UCR2_CTSC;
-
- /* Can we enable the DMA support? */
- if (is_imx6q_uart(sport) && !uart_console(port)
- && !sport->dma_is_inited)
- imx_uart_dma_init(sport);
} else {
termios->c_cflag &= ~CRTSCTS;
}
@@ -1319,7 +1436,7 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
*/
sport->port.ignore_status_mask = 0;
if (termios->c_iflag & IGNPAR)
- sport->port.ignore_status_mask |= URXD_PRERR;
+ sport->port.ignore_status_mask |= URXD_PRERR | URXD_FRMERR;
if (termios->c_iflag & IGNBRK) {
sport->port.ignore_status_mask |= URXD_BRK;
/*
@@ -1330,6 +1447,9 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
sport->port.ignore_status_mask |= URXD_OVRRUN;
}
+ if ((termios->c_cflag & CREAD) == 0)
+ sport->port.ignore_status_mask |= URXD_DUMMY_READ;
+
/*
* Update the per-port timeout.
*/
@@ -1403,8 +1523,6 @@ imx_set_termios(struct uart_port *port, struct ktermios *termios,
if (UART_ENABLE_MS(&sport->port, termios->c_cflag))
imx_enable_ms(&sport->port);
- if (sport->dma_is_inited && !sport->dma_is_enabled)
- imx_enable_dma(sport);
spin_unlock_irqrestore(&sport->port.lock, flags);
}
diff --git a/drivers/tty/serial/mcf.c b/drivers/tty/serial/mcf.c
index 10496672dfdb..a9b0ab38a68c 100644
--- a/drivers/tty/serial/mcf.c
+++ b/drivers/tty/serial/mcf.c
@@ -3,7 +3,7 @@
/*
* mcf.c -- Freescale ColdFire UART driver
*
- * (C) Copyright 2003-2007, Greg Ungerer <gerg@snapgear.com>
+ * (C) Copyright 2003-2007, Greg Ungerer <gerg@uclinux.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
@@ -198,7 +198,6 @@ static void mcf_shutdown(struct uart_port *port)
static void mcf_set_termios(struct uart_port *port, struct ktermios *termios,
struct ktermios *old)
{
- struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned long flags;
unsigned int baud, baudclk;
#if defined(CONFIG_M5272)
@@ -441,7 +440,6 @@ static int mcf_verify_port(struct uart_port *port, struct serial_struct *ser)
/* Enable or disable the RS485 support */
static int mcf_config_rs485(struct uart_port *port, struct serial_rs485 *rs485)
{
- struct mcf_uart *pp = container_of(port, struct mcf_uart, port);
unsigned char mr1, mr2;
/* Get mode registers */
@@ -631,6 +629,7 @@ static int mcf_probe(struct platform_device *pdev)
port->mapbase = platp[i].mapbase;
port->membase = (platp[i].membase) ? platp[i].membase :
(unsigned char __iomem *) platp[i].mapbase;
+ port->dev = &pdev->dev;
port->iotype = SERIAL_IO_MEM;
port->irq = platp[i].irq;
port->uartclk = MCF_BUSCLK;
@@ -702,7 +701,7 @@ static void __exit mcf_exit(void)
module_init(mcf_init);
module_exit(mcf_exit);
-MODULE_AUTHOR("Greg Ungerer <gerg@snapgear.com>");
+MODULE_AUTHOR("Greg Ungerer <gerg@uclinux.org>");
MODULE_DESCRIPTION("Freescale ColdFire UART driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:mcfuart");
diff --git a/drivers/tty/serial/men_z135_uart.c b/drivers/tty/serial/men_z135_uart.c
index 517cd073dc08..35c55505b3eb 100644
--- a/drivers/tty/serial/men_z135_uart.c
+++ b/drivers/tty/serial/men_z135_uart.c
@@ -23,7 +23,6 @@
#define MEN_Z135_MAX_PORTS 12
#define MEN_Z135_BASECLK 29491200
#define MEN_Z135_FIFO_SIZE 1024
-#define MEN_Z135_NUM_MSI_VECTORS 2
#define MEN_Z135_FIFO_WATERMARK 1020
#define MEN_Z135_STAT_REG 0x0
@@ -34,12 +33,11 @@
#define MEN_Z135_CONF_REG 0x808
#define MEN_Z135_UART_FREQ 0x80c
#define MEN_Z135_BAUD_REG 0x810
-#define MENZ135_TIMEOUT 0x814
+#define MEN_Z135_TIMEOUT 0x814
#define MEN_Z135_MEM_SIZE 0x818
-#define IS_IRQ(x) ((x) & 1)
-#define IRQ_ID(x) (((x) >> 1) & 7)
+#define IRQ_ID(x) ((x) & 0x1f)
#define MEN_Z135_IER_RXCIEN BIT(0) /* RX Space IRQ */
#define MEN_Z135_IER_TXCIEN BIT(1) /* TX Space IRQ */
@@ -94,11 +92,11 @@
#define MEN_Z135_LSR_TEXP BIT(6)
#define MEN_Z135_LSR_RXFIFOERR BIT(7)
-#define MEN_Z135_IRQ_ID_MST 0
-#define MEN_Z135_IRQ_ID_TSA 1
-#define MEN_Z135_IRQ_ID_RDA 2
-#define MEN_Z135_IRQ_ID_RLS 3
-#define MEN_Z135_IRQ_ID_CTI 6
+#define MEN_Z135_IRQ_ID_RLS BIT(0)
+#define MEN_Z135_IRQ_ID_RDA BIT(1)
+#define MEN_Z135_IRQ_ID_CTI BIT(2)
+#define MEN_Z135_IRQ_ID_TSA BIT(3)
+#define MEN_Z135_IRQ_ID_MST BIT(4)
#define LCR(x) (((x) >> MEN_Z135_LCR_SHIFT) & 0xff)
@@ -118,12 +116,18 @@ static int align;
module_param(align, int, S_IRUGO);
MODULE_PARM_DESC(align, "Keep hardware FIFO write pointer aligned, default 0");
+static uint rx_timeout;
+module_param(rx_timeout, uint, S_IRUGO);
+MODULE_PARM_DESC(rx_timeout, "RX timeout. "
+ "Timeout in seconds = (timeout_reg * baud_reg * 4) / freq_reg");
+
struct men_z135_port {
struct uart_port port;
struct mcb_device *mdev;
unsigned char *rxbuf;
u32 stat_reg;
spinlock_t lock;
+ bool automode;
};
#define to_men_z135(port) container_of((port), struct men_z135_port, port)
@@ -180,12 +184,16 @@ static inline void men_z135_reg_clr(struct men_z135_port *uart,
*/
static void men_z135_handle_modem_status(struct men_z135_port *uart)
{
- if (uart->stat_reg & MEN_Z135_MSR_DDCD)
+ u8 msr;
+
+ msr = (uart->stat_reg >> 8) & 0xff;
+
+ if (msr & MEN_Z135_MSR_DDCD)
uart_handle_dcd_change(&uart->port,
- uart->stat_reg & ~MEN_Z135_MSR_DCD);
- if (uart->stat_reg & MEN_Z135_MSR_DCTS)
+ msr & MEN_Z135_MSR_DCD);
+ if (msr & MEN_Z135_MSR_DCTS)
uart_handle_cts_change(&uart->port,
- uart->stat_reg & ~MEN_Z135_MSR_CTS);
+ msr & MEN_Z135_MSR_CTS);
}
static void men_z135_handle_lsr(struct men_z135_port *uart)
@@ -322,7 +330,8 @@ static void men_z135_handle_tx(struct men_z135_port *uart)
txfree = MEN_Z135_FIFO_WATERMARK - txc;
if (txfree <= 0) {
- pr_err("Not enough room in TX FIFO have %d, need %d\n",
+ dev_err(&uart->mdev->dev,
+ "Not enough room in TX FIFO have %d, need %d\n",
txfree, qlen);
goto irq_en;
}
@@ -373,43 +382,54 @@ out:
* @irq: The IRQ number
* @data: Pointer to UART port
*
- * Check IIR register to see which tasklet to start.
+ * Check IIR register to find the cause of the interrupt and handle it.
+ * It is possible that multiple interrupts reason bits are set and reading
+ * the IIR is a destructive read, so we always need to check for all possible
+ * interrupts and handle them.
*/
static irqreturn_t men_z135_intr(int irq, void *data)
{
struct men_z135_port *uart = (struct men_z135_port *)data;
struct uart_port *port = &uart->port;
+ bool handled = false;
+ unsigned long flags;
int irq_id;
uart->stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
- /* IRQ pending is low active */
- if (IS_IRQ(uart->stat_reg))
- return IRQ_NONE;
-
irq_id = IRQ_ID(uart->stat_reg);
- switch (irq_id) {
- case MEN_Z135_IRQ_ID_MST:
- men_z135_handle_modem_status(uart);
- break;
- case MEN_Z135_IRQ_ID_TSA:
- men_z135_handle_tx(uart);
- break;
- case MEN_Z135_IRQ_ID_CTI:
- dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
- /* Fallthrough */
- case MEN_Z135_IRQ_ID_RDA:
- /* Reading data clears RX IRQ */
- men_z135_handle_rx(uart);
- break;
- case MEN_Z135_IRQ_ID_RLS:
+
+ if (!irq_id)
+ goto out;
+
+ spin_lock_irqsave(&port->lock, flags);
+ /* It's save to write to IIR[7:6] RXC[9:8] */
+ iowrite8(irq_id, port->membase + MEN_Z135_STAT_REG);
+
+ if (irq_id & MEN_Z135_IRQ_ID_RLS) {
men_z135_handle_lsr(uart);
- break;
- default:
- dev_warn(&uart->mdev->dev, "Unknown IRQ id %d\n", irq_id);
- return IRQ_NONE;
+ handled = true;
+ }
+
+ if (irq_id & (MEN_Z135_IRQ_ID_RDA | MEN_Z135_IRQ_ID_CTI)) {
+ if (irq_id & MEN_Z135_IRQ_ID_CTI)
+ dev_dbg(&uart->mdev->dev, "Character Timeout Indication\n");
+ men_z135_handle_rx(uart);
+ handled = true;
+ }
+
+ if (irq_id & MEN_Z135_IRQ_ID_TSA) {
+ men_z135_handle_tx(uart);
+ handled = true;
}
- return IRQ_HANDLED;
+ if (irq_id & MEN_Z135_IRQ_ID_MST) {
+ men_z135_handle_modem_status(uart);
+ handled = true;
+ }
+
+ spin_unlock_irqrestore(&port->lock, flags);
+out:
+ return IRQ_RETVAL(handled);
}
/**
@@ -464,21 +484,37 @@ static unsigned int men_z135_tx_empty(struct uart_port *port)
*/
static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
- struct men_z135_port *uart = to_men_z135(port);
- u32 conf_reg = 0;
+ u32 old;
+ u32 conf_reg;
+ conf_reg = old = ioread32(port->membase + MEN_Z135_CONF_REG);
if (mctrl & TIOCM_RTS)
conf_reg |= MEN_Z135_MCR_RTS;
+ else
+ conf_reg &= ~MEN_Z135_MCR_RTS;
+
if (mctrl & TIOCM_DTR)
conf_reg |= MEN_Z135_MCR_DTR;
+ else
+ conf_reg &= ~MEN_Z135_MCR_DTR;
+
if (mctrl & TIOCM_OUT1)
conf_reg |= MEN_Z135_MCR_OUT1;
+ else
+ conf_reg &= ~MEN_Z135_MCR_OUT1;
+
if (mctrl & TIOCM_OUT2)
conf_reg |= MEN_Z135_MCR_OUT2;
+ else
+ conf_reg &= ~MEN_Z135_MCR_OUT2;
+
if (mctrl & TIOCM_LOOP)
conf_reg |= MEN_Z135_MCR_LOOP;
+ else
+ conf_reg &= ~MEN_Z135_MCR_LOOP;
- men_z135_reg_set(uart, MEN_Z135_CONF_REG, conf_reg);
+ if (conf_reg != old)
+ iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
}
/**
@@ -490,12 +526,9 @@ static void men_z135_set_mctrl(struct uart_port *port, unsigned int mctrl)
static unsigned int men_z135_get_mctrl(struct uart_port *port)
{
unsigned int mctrl = 0;
- u32 stat_reg;
u8 msr;
- stat_reg = ioread32(port->membase + MEN_Z135_STAT_REG);
-
- msr = ~((stat_reg >> 8) & 0xff);
+ msr = ioread8(port->membase + MEN_Z135_STAT_REG + 1);
if (msr & MEN_Z135_MSR_CTS)
mctrl |= TIOCM_CTS;
@@ -524,6 +557,19 @@ static void men_z135_stop_tx(struct uart_port *port)
men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_TXCIEN);
}
+/*
+ * men_z135_disable_ms() - Disable Modem Status
+ * port: The UART port
+ *
+ * Enable Modem Status IRQ.
+ */
+static void men_z135_disable_ms(struct uart_port *port)
+{
+ struct men_z135_port *uart = to_men_z135(port);
+
+ men_z135_reg_clr(uart, MEN_Z135_CONF_REG, MEN_Z135_IER_MSIEN);
+}
+
/**
* men_z135_start_tx() - Start transmitting characters
* @port: The UART port
@@ -535,6 +581,9 @@ static void men_z135_start_tx(struct uart_port *port)
{
struct men_z135_port *uart = to_men_z135(port);
+ if (uart->automode)
+ men_z135_disable_ms(port);
+
men_z135_handle_tx(uart);
}
@@ -584,6 +633,9 @@ static int men_z135_startup(struct uart_port *port)
iowrite32(conf_reg, port->membase + MEN_Z135_CONF_REG);
+ if (rx_timeout)
+ iowrite32(rx_timeout, port->membase + MEN_Z135_TIMEOUT);
+
return 0;
}
@@ -603,6 +655,7 @@ static void men_z135_set_termios(struct uart_port *port,
struct ktermios *termios,
struct ktermios *old)
{
+ struct men_z135_port *uart = to_men_z135(port);
unsigned int baud;
u32 conf_reg;
u32 bd_reg;
@@ -643,6 +696,16 @@ static void men_z135_set_termios(struct uart_port *port,
} else
lcr |= MEN_Z135_PAR_DIS << MEN_Z135_PEN_SHIFT;
+ conf_reg |= MEN_Z135_IER_MSIEN;
+ if (termios->c_cflag & CRTSCTS) {
+ conf_reg |= MEN_Z135_MCR_RCFC;
+ uart->automode = true;
+ termios->c_cflag &= ~CLOCAL;
+ } else {
+ conf_reg &= ~MEN_Z135_MCR_RCFC;
+ uart->automode = false;
+ }
+
termios->c_cflag &= ~CMSPAR; /* Mark/Space parity is not supported */
conf_reg |= lcr << MEN_Z135_LCR_SHIFT;
diff --git a/drivers/tty/serial/mrst_max3110.c b/drivers/tty/serial/mrst_max3110.c
deleted file mode 100644
index 77239d5e620d..000000000000
--- a/drivers/tty/serial/mrst_max3110.c
+++ /dev/null
@@ -1,909 +0,0 @@
-/*
- * mrst_max3110.c - spi uart protocol driver for Maxim 3110
- *
- * Copyright (c) 2008-2010, 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.
- *
- * 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.
- */
-
-/*
- * Note:
- * 1. From Max3110 spec, the Rx FIFO has 8 words, while the Tx FIFO only has
- * 1 word. If SPI master controller doesn't support sclk frequency change,
- * then the char need be sent out one by one with some delay
- *
- * 2. Currently only RX available interrupt is used, no need for waiting TXE
- * interrupt for a low speed UART device
- */
-
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#ifdef CONFIG_MAGIC_SYSRQ
-#define SUPPORT_SYSRQ
-#endif
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/irq.h>
-#include <linux/init.h>
-#include <linux/console.h>
-#include <linux/tty.h>
-#include <linux/tty_flip.h>
-#include <linux/serial_core.h>
-#include <linux/serial_reg.h>
-
-#include <linux/kthread.h>
-#include <linux/spi/spi.h>
-#include <linux/pm.h>
-
-#include "mrst_max3110.h"
-
-#define UART_TX_NEEDED 1
-#define CON_TX_NEEDED 2
-#define BIT_IRQ_PENDING 3
-
-struct uart_max3110 {
- struct uart_port port;
- struct spi_device *spi;
- char name[SPI_NAME_SIZE];
-
- wait_queue_head_t wq;
- struct task_struct *main_thread;
- struct task_struct *read_thread;
- struct mutex thread_mutex;
- struct mutex io_mutex;
-
- u32 baud;
- u16 cur_conf;
- u8 clock;
- u8 parity, word_7bits;
- u16 irq;
-
- unsigned long uart_flags;
-
- /* console related */
- struct circ_buf con_xmit;
-};
-
-/* global data structure, may need be removed */
-static struct uart_max3110 *pmax;
-
-static int receive_chars(struct uart_max3110 *max,
- unsigned short *str, int len);
-static int max3110_read_multi(struct uart_max3110 *max);
-static void max3110_con_receive(struct uart_max3110 *max);
-
-static int max3110_write_then_read(struct uart_max3110 *max,
- const void *txbuf, void *rxbuf, unsigned len, int always_fast)
-{
- struct spi_device *spi = max->spi;
- struct spi_message message;
- struct spi_transfer x;
- int ret;
-
- mutex_lock(&max->io_mutex);
- spi_message_init(&message);
- memset(&x, 0, sizeof x);
- x.len = len;
- x.tx_buf = txbuf;
- x.rx_buf = rxbuf;
- spi_message_add_tail(&x, &message);
-
- if (always_fast)
- x.speed_hz = spi->max_speed_hz;
- else if (max->baud)
- x.speed_hz = max->baud;
-
- /* Do the i/o */
- ret = spi_sync(spi, &message);
- mutex_unlock(&max->io_mutex);
- return ret;
-}
-
-/* Write a 16b word to the device */
-static int max3110_out(struct uart_max3110 *max, const u16 out)
-{
- void *buf;
- u16 *obuf, *ibuf;
- int ret;
-
- buf = kzalloc(8, GFP_KERNEL | GFP_DMA);
- if (!buf)
- return -ENOMEM;
-
- obuf = buf;
- ibuf = buf + 4;
- *obuf = out;
- ret = max3110_write_then_read(max, obuf, ibuf, 2, 1);
- if (ret) {
- pr_warn("%s: get err msg %d when sending 0x%x\n",
- __func__, ret, out);
- goto exit;
- }
-
- receive_chars(max, ibuf, 1);
-
-exit:
- kfree(buf);
- return ret;
-}
-
-/*
- * This is usually used to read data from SPIC RX FIFO, which doesn't
- * need any delay like flushing character out.
- *
- * Return how many valide bytes are read back
- */
-static int max3110_read_multi(struct uart_max3110 *max)
-{
- void *buf;
- u16 *obuf, *ibuf;
- int ret, blen;
-
- blen = M3110_RX_FIFO_DEPTH * sizeof(u16);
- buf = kzalloc(blen * 2, GFP_KERNEL | GFP_DMA);
- if (!buf)
- return 0;
-
- /* tx/rx always have the same length */
- obuf = buf;
- ibuf = buf + blen;
-
- if (max3110_write_then_read(max, obuf, ibuf, blen, 1)) {
- kfree(buf);
- return 0;
- }
-
- ret = receive_chars(max, ibuf, M3110_RX_FIFO_DEPTH);
-
- kfree(buf);
- return ret;
-}
-
-static void serial_m3110_con_putchar(struct uart_port *port, int ch)
-{
- struct uart_max3110 *max =
- container_of(port, struct uart_max3110, port);
- struct circ_buf *xmit = &max->con_xmit;
-
- if (uart_circ_chars_free(xmit)) {
- xmit->buf[xmit->head] = (char)ch;
- xmit->head = (xmit->head + 1) & (PAGE_SIZE - 1);
- }
-}
-
-/*
- * Print a string to the serial port trying not to disturb
- * any possible real use of the port...
- *
- * The console_lock must be held when we get here.
- */
-static void serial_m3110_con_write(struct console *co,
- const char *s, unsigned int count)
-{
- if (!pmax)
- return;
-
- uart_console_write(&pmax->port, s, count, serial_m3110_con_putchar);
-
- if (!test_and_set_bit(CON_TX_NEEDED, &pmax->uart_flags))
- wake_up(&pmax->wq);
-}
-
-static int __init
-serial_m3110_con_setup(struct console *co, char *options)
-{
- struct uart_max3110 *max = pmax;
- int baud = 115200;
- int bits = 8;
- int parity = 'n';
- int flow = 'n';
-
- pr_info("setting up console\n");
-
- if (co->index == -1)
- co->index = 0;
-
- if (!max) {
- pr_err("pmax is NULL, return\n");
- return -ENODEV;
- }
-
- if (options)
- uart_parse_options(options, &baud, &parity, &bits, &flow);
-
- return uart_set_options(&max->port, co, baud, parity, bits, flow);
-}
-
-static struct tty_driver *serial_m3110_con_device(struct console *co,
- int *index)
-{
- struct uart_driver *p = co->data;
- *index = co->index;
- return p->tty_driver;
-}
-
-static struct uart_driver serial_m3110_reg;
-static struct console serial_m3110_console = {
- .name = "ttyS",
- .write = serial_m3110_con_write,
- .device = serial_m3110_con_device,
- .setup = serial_m3110_con_setup,
- .flags = CON_PRINTBUFFER,
- .index = -1,
- .data = &serial_m3110_reg,
-};
-
-static unsigned int serial_m3110_tx_empty(struct uart_port *port)
-{
- return 1;
-}
-
-static void serial_m3110_stop_tx(struct uart_port *port)
-{
- return;
-}
-
-/* stop_rx will be called in spin_lock env */
-static void serial_m3110_stop_rx(struct uart_port *port)
-{
- return;
-}
-
-#define WORDS_PER_XFER 128
-static void send_circ_buf(struct uart_max3110 *max,
- struct circ_buf *xmit)
-{
- void *buf;
- u16 *obuf, *ibuf;
- int i, len, blen, dma_size, left, ret = 0;
-
-
- dma_size = WORDS_PER_XFER * sizeof(u16) * 2;
- buf = kzalloc(dma_size, GFP_KERNEL | GFP_DMA);
- if (!buf)
- return;
- obuf = buf;
- ibuf = buf + dma_size/2;
-
- while (!uart_circ_empty(xmit)) {
- left = uart_circ_chars_pending(xmit);
- while (left) {
- len = min(left, WORDS_PER_XFER);
- blen = len * sizeof(u16);
- memset(ibuf, 0, blen);
-
- for (i = 0; i < len; i++) {
- obuf[i] = (u8)xmit->buf[xmit->tail] | WD_TAG;
- xmit->tail = (xmit->tail + 1) &
- (UART_XMIT_SIZE - 1);
- }
-
- /* Fail to send msg to console is not very critical */
-
- ret = max3110_write_then_read(max, obuf, ibuf, blen, 0);
- if (ret)
- pr_warn("%s: get err msg %d\n", __func__, ret);
-
- receive_chars(max, ibuf, len);
-
- max->port.icount.tx += len;
- left -= len;
- }
- }
-
- kfree(buf);
-}
-
-static void transmit_char(struct uart_max3110 *max)
-{
- struct uart_port *port = &max->port;
- struct circ_buf *xmit = &port->state->xmit;
-
- if (uart_circ_empty(xmit) || uart_tx_stopped(port))
- return;
-
- send_circ_buf(max, xmit);
-
- if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
- uart_write_wakeup(port);
-
- if (uart_circ_empty(xmit))
- serial_m3110_stop_tx(port);
-}
-
-/*
- * This will be called by uart_write() and tty_write, can't
- * go to sleep
- */
-static void serial_m3110_start_tx(struct uart_port *port)
-{
- struct uart_max3110 *max =
- container_of(port, struct uart_max3110, port);
-
- if (!test_and_set_bit(UART_TX_NEEDED, &max->uart_flags))
- wake_up(&max->wq);
-}
-
-static int
-receive_chars(struct uart_max3110 *max, unsigned short *str, int len)
-{
- struct uart_port *port = &max->port;
- struct tty_port *tport;
- char buf[M3110_RX_FIFO_DEPTH];
- int r, w, usable;
-
- /* If uart is not opened, just return */
- if (!port->state)
- return 0;
-
- tport = &port->state->port;
-
- for (r = 0, w = 0; r < len; r++) {
- if (str[r] & MAX3110_BREAK &&
- uart_handle_break(port))
- continue;
-
- if (str[r] & MAX3110_READ_DATA_AVAILABLE) {
- if (uart_handle_sysrq_char(port, str[r] & 0xff))
- continue;
-
- buf[w++] = str[r] & 0xff;
- }
- }
-
- if (!w)
- return 0;
-
- for (r = 0; w; r += usable, w -= usable) {
- usable = tty_buffer_request_room(tport, w);
- if (usable) {
- tty_insert_flip_string(tport, buf + r, usable);
- port->icount.rx += usable;
- }
- }
- tty_flip_buffer_push(tport);
-
- return r;
-}
-
-/*
- * This routine will be used in read_thread or RX IRQ handling,
- * it will first do one round buffer read(8 words), if there is some
- * valid RX data, will try to read 5 more rounds till all data
- * is read out.
- *
- * Use stack space as data buffer to save some system load, and chose
- * 504 Btyes as a threadhold to do a bulk push to upper tty layer when
- * receiving bulk data, a much bigger buffer may cause stack overflow
- */
-static void max3110_con_receive(struct uart_max3110 *max)
-{
- int loop = 1, num;
-
- do {
- num = max3110_read_multi(max);
-
- if (num) {
- loop = 5;
- }
- } while (--loop);
-}
-
-static int max3110_main_thread(void *_max)
-{
- struct uart_max3110 *max = _max;
- wait_queue_head_t *wq = &max->wq;
- int ret = 0;
- struct circ_buf *xmit = &max->con_xmit;
-
- pr_info("start main thread\n");
-
- do {
- wait_event_interruptible(*wq,
- max->uart_flags || kthread_should_stop());
-
- mutex_lock(&max->thread_mutex);
-
- if (test_and_clear_bit(BIT_IRQ_PENDING, &max->uart_flags))
- max3110_con_receive(max);
-
- /* first handle console output */
- if (test_and_clear_bit(CON_TX_NEEDED, &max->uart_flags))
- send_circ_buf(max, xmit);
-
- /* handle uart output */
- if (test_and_clear_bit(UART_TX_NEEDED, &max->uart_flags))
- transmit_char(max);
-
- mutex_unlock(&max->thread_mutex);
-
- } while (!kthread_should_stop());
-
- return ret;
-}
-
-static irqreturn_t serial_m3110_irq(int irq, void *dev_id)
-{
- struct uart_max3110 *max = dev_id;
-
- /* max3110's irq is a falling edge, not level triggered,
- * so no need to disable the irq */
-
- if (!test_and_set_bit(BIT_IRQ_PENDING, &max->uart_flags))
- wake_up(&max->wq);
-
- return IRQ_HANDLED;
-}
-
-/* if don't use RX IRQ, then need a thread to polling read */
-static int max3110_read_thread(void *_max)
-{
- struct uart_max3110 *max = _max;
-
- pr_info("start read thread\n");
- do {
- /*
- * If can't acquire the mutex, it means the main thread
- * is running which will also perform the rx job
- */
- if (mutex_trylock(&max->thread_mutex)) {
- max3110_con_receive(max);
- mutex_unlock(&max->thread_mutex);
- }
-
- set_current_state(TASK_INTERRUPTIBLE);
- schedule_timeout(HZ / 20);
- } while (!kthread_should_stop());
-
- return 0;
-}
-
-static int serial_m3110_startup(struct uart_port *port)
-{
- struct uart_max3110 *max =
- container_of(port, struct uart_max3110, port);
- u16 config = 0;
- int ret = 0;
-
- if (port->line != 0) {
- pr_err("uart port startup failed\n");
- return -1;
- }
-
- /* Disable all IRQ and config it to 115200, 8n1 */
- config = WC_TAG | WC_FIFO_ENABLE
- | WC_1_STOPBITS
- | WC_8BIT_WORD
- | WC_BAUD_DR2;
-
- /* as we use thread to handle tx/rx, need set low latency */
- port->state->port.low_latency = 1;
-
- if (max->irq) {
- /* Enable RX IRQ only */
- config |= WC_RXA_IRQ_ENABLE;
- } else {
- /* If IRQ is disabled, start a read thread for input data */
- max->read_thread =
- kthread_run(max3110_read_thread, max, "max3110_read");
- if (IS_ERR(max->read_thread)) {
- ret = PTR_ERR(max->read_thread);
- max->read_thread = NULL;
- pr_err("Can't create read thread!\n");
- return ret;
- }
- }
-
- ret = max3110_out(max, config);
- if (ret) {
- if (max->read_thread)
- kthread_stop(max->read_thread);
- max->read_thread = NULL;
- return ret;
- }
-
- max->cur_conf = config;
- return 0;
-}
-
-static void serial_m3110_shutdown(struct uart_port *port)
-{
- struct uart_max3110 *max =
- container_of(port, struct uart_max3110, port);
- u16 config;
-
- if (max->read_thread) {
- kthread_stop(max->read_thread);
- max->read_thread = NULL;
- }
-
- /* Disable interrupts from this port */
- config = WC_TAG | WC_SW_SHDI;
- max3110_out(max, config);
-}
-
-static void serial_m3110_release_port(struct uart_port *port)
-{
-}
-
-static int serial_m3110_request_port(struct uart_port *port)
-{
- return 0;
-}
-
-static void serial_m3110_config_port(struct uart_port *port, int flags)
-{
- port->type = PORT_MAX3100;
-}
-
-static int
-serial_m3110_verify_port(struct uart_port *port, struct serial_struct *ser)
-{
- /* we don't want the core code to modify any port params */
- return -EINVAL;
-}
-
-
-static const char *serial_m3110_type(struct uart_port *port)
-{
- struct uart_max3110 *max =
- container_of(port, struct uart_max3110, port);
- return max->name;
-}
-
-static void
-serial_m3110_set_termios(struct uart_port *port, struct ktermios *termios,
- struct ktermios *old)
-{
- struct uart_max3110 *max =
- container_of(port, struct uart_max3110, port);
- unsigned char cval;
- unsigned int baud, parity = 0;
- int clk_div = -1;
- u16 new_conf = max->cur_conf;
-
- switch (termios->c_cflag & CSIZE) {
- case CS7:
- cval = UART_LCR_WLEN7;
- new_conf |= WC_7BIT_WORD;
- break;
- default:
- /* We only support CS7 & CS8 */
- termios->c_cflag &= ~CSIZE;
- termios->c_cflag |= CS8;
- case CS8:
- cval = UART_LCR_WLEN8;
- new_conf |= WC_8BIT_WORD;
- break;
- }
-
- baud = uart_get_baud_rate(port, termios, old, 0, 230400);
-
- /* First calc the div for 1.8MHZ clock case */
- switch (baud) {
- case 300:
- clk_div = WC_BAUD_DR384;
- break;
- case 600:
- clk_div = WC_BAUD_DR192;
- break;
- case 1200:
- clk_div = WC_BAUD_DR96;
- break;
- case 2400:
- clk_div = WC_BAUD_DR48;
- break;
- case 4800:
- clk_div = WC_BAUD_DR24;
- break;
- case 9600:
- clk_div = WC_BAUD_DR12;
- break;
- case 19200:
- clk_div = WC_BAUD_DR6;
- break;
- case 38400:
- clk_div = WC_BAUD_DR3;
- break;
- case 57600:
- clk_div = WC_BAUD_DR2;
- break;
- case 115200:
- clk_div = WC_BAUD_DR1;
- break;
- case 230400:
- if (max->clock & MAX3110_HIGH_CLK)
- break;
- default:
- /* Pick the previous baud rate */
- baud = max->baud;
- clk_div = max->cur_conf & WC_BAUD_DIV_MASK;
- tty_termios_encode_baud_rate(termios, baud, baud);
- }
-
- if (max->clock & MAX3110_HIGH_CLK) {
- clk_div += 1;
- /* High clk version max3110 doesn't support B300 */
- if (baud == 300) {
- baud = 600;
- clk_div = WC_BAUD_DR384;
- }
- if (baud == 230400)
- clk_div = WC_BAUD_DR1;
- tty_termios_encode_baud_rate(termios, baud, baud);
- }
-
- new_conf = (new_conf & ~WC_BAUD_DIV_MASK) | clk_div;
-
- if (unlikely(termios->c_cflag & CMSPAR))
- termios->c_cflag &= ~CMSPAR;
-
- if (termios->c_cflag & CSTOPB)
- new_conf |= WC_2_STOPBITS;
- else
- new_conf &= ~WC_2_STOPBITS;
-
- if (termios->c_cflag & PARENB) {
- new_conf |= WC_PARITY_ENABLE;
- parity |= UART_LCR_PARITY;
- } else
- new_conf &= ~WC_PARITY_ENABLE;
-
- if (!(termios->c_cflag & PARODD))
- parity |= UART_LCR_EPAR;
- max->parity = parity;
-
- uart_update_timeout(port, termios->c_cflag, baud);
-
- new_conf |= WC_TAG;
- if (new_conf != max->cur_conf) {
- if (!max3110_out(max, new_conf)) {
- max->cur_conf = new_conf;
- max->baud = baud;
- }
- }
-}
-
-/* Don't handle hw handshaking */
-static unsigned int serial_m3110_get_mctrl(struct uart_port *port)
-{
- return TIOCM_DSR | TIOCM_CAR | TIOCM_DSR;
-}
-
-static void serial_m3110_set_mctrl(struct uart_port *port, unsigned int mctrl)
-{
-}
-
-static void serial_m3110_break_ctl(struct uart_port *port, int break_state)
-{
-}
-
-static void serial_m3110_pm(struct uart_port *port, unsigned int state,
- unsigned int oldstate)
-{
-}
-
-static struct uart_ops serial_m3110_ops = {
- .tx_empty = serial_m3110_tx_empty,
- .set_mctrl = serial_m3110_set_mctrl,
- .get_mctrl = serial_m3110_get_mctrl,
- .stop_tx = serial_m3110_stop_tx,
- .start_tx = serial_m3110_start_tx,
- .stop_rx = serial_m3110_stop_rx,
- .break_ctl = serial_m3110_break_ctl,
- .startup = serial_m3110_startup,
- .shutdown = serial_m3110_shutdown,
- .set_termios = serial_m3110_set_termios,
- .pm = serial_m3110_pm,
- .type = serial_m3110_type,
- .release_port = serial_m3110_release_port,
- .request_port = serial_m3110_request_port,
- .config_port = serial_m3110_config_port,
- .verify_port = serial_m3110_verify_port,
-};
-
-static struct uart_driver serial_m3110_reg = {
- .owner = THIS_MODULE,
- .driver_name = "MRST serial",
- .dev_name = "ttyS",
- .major = TTY_MAJOR,
- .minor = 64,
- .nr = 1,
- .cons = &serial_m3110_console,
-};
-
-#ifdef CONFIG_PM_SLEEP
-static int serial_m3110_suspend(struct device *dev)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct uart_max3110 *max = spi_get_drvdata(spi);
-
- if (max->irq > 0)
- disable_irq(max->irq);
- uart_suspend_port(&serial_m3110_reg, &max->port);
- max3110_out(max, max->cur_conf | WC_SW_SHDI);
- return 0;
-}
-
-static int serial_m3110_resume(struct device *dev)
-{
- struct spi_device *spi = to_spi_device(dev);
- struct uart_max3110 *max = spi_get_drvdata(spi);
-
- max3110_out(max, max->cur_conf);
- uart_resume_port(&serial_m3110_reg, &max->port);
- if (max->irq > 0)
- enable_irq(max->irq);
- return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(serial_m3110_pm_ops, serial_m3110_suspend,
- serial_m3110_resume);
-#define SERIAL_M3110_PM_OPS (&serial_m3110_pm_ops)
-
-#else
-#define SERIAL_M3110_PM_OPS NULL
-#endif
-
-static int serial_m3110_probe(struct spi_device *spi)
-{
- struct uart_max3110 *max;
- void *buffer;
- u16 res;
- int ret = 0;
-
- max = kzalloc(sizeof(*max), GFP_KERNEL);
- if (!max)
- return -ENOMEM;
-
- /* Set spi info */
- spi->bits_per_word = 16;
- max->clock = MAX3110_HIGH_CLK;
-
- spi_setup(spi);
-
- max->port.type = PORT_MAX3100;
- max->port.fifosize = 2; /* Only have 16b buffer */
- max->port.ops = &serial_m3110_ops;
- max->port.line = 0;
- max->port.dev = &spi->dev;
- max->port.uartclk = 115200;
-
- max->spi = spi;
- strcpy(max->name, spi->modalias);
- max->irq = (u16)spi->irq;
-
- mutex_init(&max->thread_mutex);
- mutex_init(&max->io_mutex);
-
- max->word_7bits = 0;
- max->parity = 0;
- max->baud = 0;
-
- max->cur_conf = 0;
- max->uart_flags = 0;
-
- /* Check if reading configuration register returns something sane */
-
- res = RC_TAG;
- ret = max3110_write_then_read(max, (u8 *)&res, (u8 *)&res, 2, 0);
- if (ret < 0 || res == 0 || res == 0xffff) {
- dev_dbg(&spi->dev, "MAX3111 deemed not present (conf reg %04x)",
- res);
- ret = -ENODEV;
- goto err_get_page;
- }
-
- buffer = (void *)__get_free_page(GFP_KERNEL);
- if (!buffer) {
- ret = -ENOMEM;
- goto err_get_page;
- }
- max->con_xmit.buf = buffer;
- max->con_xmit.head = 0;
- max->con_xmit.tail = 0;
-
- init_waitqueue_head(&max->wq);
-
- max->main_thread = kthread_run(max3110_main_thread,
- max, "max3110_main");
- if (IS_ERR(max->main_thread)) {
- ret = PTR_ERR(max->main_thread);
- goto err_kthread;
- }
-
- if (max->irq) {
- ret = request_irq(max->irq, serial_m3110_irq,
- IRQ_TYPE_EDGE_FALLING, "max3110", max);
- if (ret) {
- max->irq = 0;
- dev_warn(&spi->dev,
- "unable to allocate IRQ, will use polling method\n");
- }
- }
-
- spi_set_drvdata(spi, max);
- pmax = max;
-
- /* Give membase a psudo value to pass serial_core's check */
- max->port.membase = (unsigned char __iomem *)0xff110000;
- uart_add_one_port(&serial_m3110_reg, &max->port);
-
- return 0;
-
-err_kthread:
- free_page((unsigned long)buffer);
-err_get_page:
- kfree(max);
- return ret;
-}
-
-static int serial_m3110_remove(struct spi_device *dev)
-{
- struct uart_max3110 *max = spi_get_drvdata(dev);
-
- if (!max)
- return 0;
-
- uart_remove_one_port(&serial_m3110_reg, &max->port);
-
- free_page((unsigned long)max->con_xmit.buf);
-
- if (max->irq)
- free_irq(max->irq, max);
-
- if (max->main_thread)
- kthread_stop(max->main_thread);
-
- kfree(max);
- return 0;
-}
-
-static struct spi_driver uart_max3110_driver = {
- .driver = {
- .name = "spi_max3111",
- .owner = THIS_MODULE,
- .pm = SERIAL_M3110_PM_OPS,
- },
- .probe = serial_m3110_probe,
- .remove = serial_m3110_remove,
-};
-
-static int __init serial_m3110_init(void)
-{
- int ret = 0;
-
- ret = uart_register_driver(&serial_m3110_reg);
- if (ret)
- return ret;
-
- ret = spi_register_driver(&uart_max3110_driver);
- if (ret)
- uart_unregister_driver(&serial_m3110_reg);
-
- return ret;
-}
-
-static void __exit serial_m3110_exit(void)
-{
- spi_unregister_driver(&uart_max3110_driver);
- uart_unregister_driver(&serial_m3110_reg);
-}
-
-module_init(serial_m3110_init);
-module_exit(serial_m3110_exit);
-
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("spi:max3110-uart");
diff --git a/drivers/tty/serial/mrst_max3110.h b/drivers/tty/serial/mrst_max3110.h
deleted file mode 100644
index 35af0739513b..000000000000
--- a/drivers/tty/serial/mrst_max3110.h
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef _MRST_MAX3110_H
-#define _MRST_MAX3110_H
-
-#define MAX3110_HIGH_CLK 0x1 /* 3.6864 MHZ */
-#define MAX3110_LOW_CLK 0x0 /* 1.8432 MHZ */
-
-/* status bits for all 4 MAX3110 operate modes */
-#define MAX3110_READ_DATA_AVAILABLE (1 << 15)
-#define MAX3110_WRITE_BUF_EMPTY (1 << 14)
-#define MAX3110_BREAK (1 << 10)
-
-#define WC_TAG (3 << 14)
-#define RC_TAG (1 << 14)
-#define WD_TAG (2 << 14)
-#define RD_TAG (0 << 14)
-
-/* bits def for write configuration */
-#define WC_FIFO_ENABLE_MASK (1 << 13)
-#define WC_FIFO_ENABLE (0 << 13)
-
-#define WC_SW_SHDI (1 << 12)
-
-#define WC_IRQ_MASK (0xF << 8)
-#define WC_TXE_IRQ_ENABLE (1 << 11) /* TX empty irq */
-#define WC_RXA_IRQ_ENABLE (1 << 10) /* RX available irq */
-#define WC_PAR_HIGH_IRQ_ENABLE (1 << 9)
-#define WC_REC_ACT_IRQ_ENABLE (1 << 8)
-
-#define WC_IRDA_ENABLE (1 << 7)
-
-#define WC_STOPBITS_MASK (1 << 6)
-#define WC_2_STOPBITS (1 << 6)
-#define WC_1_STOPBITS (0 << 6)
-
-#define WC_PARITY_ENABLE_MASK (1 << 5)
-#define WC_PARITY_ENABLE (1 << 5)
-
-#define WC_WORDLEN_MASK (1 << 4)
-#define WC_7BIT_WORD (1 << 4)
-#define WC_8BIT_WORD (0 << 4)
-
-#define WC_BAUD_DIV_MASK (0xF)
-#define WC_BAUD_DR1 (0x0)
-#define WC_BAUD_DR2 (0x1)
-#define WC_BAUD_DR4 (0x2)
-#define WC_BAUD_DR8 (0x3)
-#define WC_BAUD_DR16 (0x4)
-#define WC_BAUD_DR32 (0x5)
-#define WC_BAUD_DR64 (0x6)
-#define WC_BAUD_DR128 (0x7)
-#define WC_BAUD_DR3 (0x8)
-#define WC_BAUD_DR6 (0x9)
-#define WC_BAUD_DR12 (0xA)
-#define WC_BAUD_DR24 (0xB)
-#define WC_BAUD_DR48 (0xC)
-#define WC_BAUD_DR96 (0xD)
-#define WC_BAUD_DR192 (0xE)
-#define WC_BAUD_DR384 (0xF)
-
-#define M3110_RX_FIFO_DEPTH 8
-#endif
diff --git a/drivers/tty/serial/msm_serial.c b/drivers/tty/serial/msm_serial.c
index c88b522ccd73..b73889c8ed4b 100644
--- a/drivers/tty/serial/msm_serial.c
+++ b/drivers/tty/serial/msm_serial.c
@@ -920,14 +920,15 @@ static void msm_console_write(struct console *co, const char *s,
static int __init msm_console_setup(struct console *co, char *options)
{
struct uart_port *port;
- struct msm_port *msm_port;
- int baud = 0, flow, bits, parity;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
if (unlikely(co->index >= UART_NR || co->index < 0))
return -ENXIO;
port = get_port_from_line(co->index);
- msm_port = UART_TO_MSM(port);
if (unlikely(!port->membase))
return -ENXIO;
@@ -937,23 +938,6 @@ static int __init msm_console_setup(struct console *co, char *options)
if (options)
uart_parse_options(options, &baud, &parity, &bits, &flow);
- bits = 8;
- parity = 'n';
- flow = 'n';
- msm_write(port, UART_MR2_BITS_PER_CHAR_8 | UART_MR2_STOP_BIT_LEN_ONE,
- UART_MR2); /* 8N1 */
-
- if (baud < 300 || baud > 115200)
- baud = 115200;
- msm_set_baud_rate(port, baud);
-
- msm_reset(port);
-
- if (msm_port->is_uartdm) {
- msm_write(port, UART_CR_CMD_PROTECTION_EN, UART_CR);
- msm_write(port, UART_CR_TX_ENABLE, UART_CR);
- }
-
pr_info("msm_serial: console setup on port #%d\n", port->line);
return uart_set_options(port, co, baud, parity, bits, flow);
@@ -1142,9 +1126,6 @@ static int __init msm_serial_init(void)
static void __exit msm_serial_exit(void)
{
-#ifdef CONFIG_SERIAL_MSM_CONSOLE
- unregister_console(&msm_console);
-#endif
platform_driver_unregister(&msm_platform_driver);
uart_unregister_driver(&msm_uart_driver);
}
diff --git a/drivers/tty/serial/mxs-auart.c b/drivers/tty/serial/mxs-auart.c
index ec553f8eb218..d1298b6cc68e 100644
--- a/drivers/tty/serial/mxs-auart.c
+++ b/drivers/tty/serial/mxs-auart.c
@@ -152,8 +152,6 @@ struct mxs_auart_port {
unsigned int mctrl_prev;
enum mxs_auart_type devtype;
- unsigned int irq;
-
struct clk *clk;
struct device *dev;
@@ -1228,37 +1226,32 @@ static int mxs_auart_probe(struct platform_device *pdev)
of_match_device(mxs_auart_dt_ids, &pdev->dev);
struct mxs_auart_port *s;
u32 version;
- int ret = 0;
+ int ret, irq;
struct resource *r;
- s = kzalloc(sizeof(struct mxs_auart_port), GFP_KERNEL);
- if (!s) {
- ret = -ENOMEM;
- goto out;
- }
+ s = devm_kzalloc(&pdev->dev, sizeof(*s), GFP_KERNEL);
+ if (!s)
+ return -ENOMEM;
ret = serial_mxs_probe_dt(s, pdev);
if (ret > 0)
s->port.line = pdev->id < 0 ? 0 : pdev->id;
else if (ret < 0)
- goto out_free;
+ return ret;
if (of_id) {
pdev->id_entry = of_id->data;
s->devtype = pdev->id_entry->driver_data;
}
- s->clk = clk_get(&pdev->dev, NULL);
- if (IS_ERR(s->clk)) {
- ret = PTR_ERR(s->clk);
- goto out_free;
- }
+ s->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(s->clk))
+ return PTR_ERR(s->clk);
r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!r) {
- ret = -ENXIO;
- goto out_free_clk;
- }
+ if (!r)
+ return -ENXIO;
+
s->port.mapbase = r->start;
s->port.membase = ioremap(r->start, resource_size(r));
@@ -1271,11 +1264,15 @@ static int mxs_auart_probe(struct platform_device *pdev)
s->mctrl_prev = 0;
- s->irq = platform_get_irq(pdev, 0);
- s->port.irq = s->irq;
- ret = request_irq(s->irq, mxs_auart_irq_handle, 0, dev_name(&pdev->dev), s);
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ s->port.irq = irq;
+ ret = devm_request_irq(&pdev->dev, irq, mxs_auart_irq_handle, 0,
+ dev_name(&pdev->dev), s);
if (ret)
- goto out_free_clk;
+ return ret;
platform_set_drvdata(pdev, s);
@@ -1288,7 +1285,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
*/
ret = mxs_auart_request_gpio_irq(s);
if (ret)
- goto out_free_irq;
+ return ret;
auart_port[s->port.line] = s;
@@ -1307,14 +1304,7 @@ static int mxs_auart_probe(struct platform_device *pdev)
out_free_gpio_irq:
mxs_auart_free_gpio_irq(s);
-out_free_irq:
auart_port[pdev->id] = NULL;
- free_irq(s->irq, s);
-out_free_clk:
- clk_put(s->clk);
-out_free:
- kfree(s);
-out:
return ret;
}
@@ -1323,13 +1313,8 @@ static int mxs_auart_remove(struct platform_device *pdev)
struct mxs_auart_port *s = platform_get_drvdata(pdev);
uart_remove_one_port(&auart_driver, &s->port);
-
auart_port[pdev->id] = NULL;
-
mxs_auart_free_gpio_irq(s);
- clk_put(s->clk);
- free_irq(s->irq, s);
- kfree(s);
return 0;
}
diff --git a/drivers/tty/serial/of_serial.c b/drivers/tty/serial/of_serial.c
index 64f1bab7e9d7..7ff61e24a195 100644
--- a/drivers/tty/serial/of_serial.c
+++ b/drivers/tty/serial/of_serial.c
@@ -102,6 +102,11 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_property_read_u32(np, "fifo-size", &prop) == 0)
port->fifosize = prop;
+ /* Check for a fixed line number */
+ ret = of_alias_get_id(np, "serial");
+ if (ret >= 0)
+ port->line = ret;
+
port->irq = irq_of_parse_and_map(np, 0);
port->iotype = UPIO_MEM;
if (of_property_read_u32(np, "reg-io-width", &prop) == 0) {
@@ -128,6 +133,10 @@ static int of_platform_serial_setup(struct platform_device *ofdev,
if (of_find_property(np, "no-loopback-test", NULL))
port->flags |= UPF_SKIP_TEST;
+ ret = of_alias_get_id(np, "serial");
+ if (ret >= 0)
+ port->line = ret;
+
port->dev = &ofdev->dev;
switch (type) {
@@ -331,6 +340,10 @@ static struct of_device_id of_platform_serial_table[] = {
.data = (void *)PORT_ALTR_16550_F64, },
{ .compatible = "altr,16550-FIFO128",
.data = (void *)PORT_ALTR_16550_F128, },
+ { .compatible = "mrvl,mmp-uart",
+ .data = (void *)PORT_XSCALE, },
+ { .compatible = "mrvl,pxa-uart",
+ .data = (void *)PORT_XSCALE, },
#ifdef CONFIG_SERIAL_OF_PLATFORM_NWPSERIAL
{ .compatible = "ibm,qpace-nwp-serial",
.data = (void *)PORT_NWPSERIAL, },
diff --git a/drivers/tty/serial/omap-serial.c b/drivers/tty/serial/omap-serial.c
index 2e1073da6719..10256fa04b40 100644
--- a/drivers/tty/serial/omap-serial.c
+++ b/drivers/tty/serial/omap-serial.c
@@ -63,7 +63,7 @@
#define UART_ERRATA_i202_MDR1_ACCESS BIT(0)
#define UART_ERRATA_i291_DMA_FORCEIDLE BIT(1)
-#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz*/
+#define DEFAULT_CLK_SPEED 48000000 /* 48Mhz */
/* SCR register bitmasks */
#define OMAP_UART_SCR_RX_TRIG_GRANU1_MASK (1 << 7)
@@ -93,7 +93,7 @@
/* WER = 0x7F
* Enable module level wakeup in WER reg
*/
-#define OMAP_UART_WER_MOD_WKUP 0X7F
+#define OMAP_UART_WER_MOD_WKUP 0x7F
/* Enable XON/XOFF flow control on output */
#define OMAP_UART_SW_TX 0x08
@@ -114,7 +114,7 @@ struct uart_omap_dma {
dma_addr_t tx_buf_dma_phys;
unsigned int uart_base;
/*
- * Buffer for rx dma.It is not required for tx because the buffer
+ * Buffer for rx dma. It is not required for tx because the buffer
* comes from port structure.
*/
unsigned char *rx_buf;
@@ -151,7 +151,7 @@ struct uart_omap_port {
int use_dma;
/*
* Some bits in registers are cleared on a read, so they must
- * be saved whenever the register is read but the bits will not
+ * be saved whenever the register is read, but the bits will not
* be immediately processed.
*/
unsigned int lsr_break_flag;
@@ -681,7 +681,7 @@ static unsigned int serial_omap_get_mctrl(struct uart_port *port)
static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
{
struct uart_omap_port *up = to_uart_omap_port(port);
- unsigned char mcr = 0, old_mcr;
+ unsigned char mcr = 0, old_mcr, lcr;
dev_dbg(up->port.dev, "serial_omap_set_mctrl+%d\n", up->port.line);
if (mctrl & TIOCM_RTS)
@@ -701,6 +701,17 @@ static void serial_omap_set_mctrl(struct uart_port *port, unsigned int mctrl)
UART_MCR_DTR | UART_MCR_RTS);
up->mcr = old_mcr | mcr;
serial_out(up, UART_MCR, up->mcr);
+
+ /* Turn off autoRTS if RTS is lowered; restore autoRTS if RTS raised */
+ lcr = serial_in(up, UART_LCR);
+ serial_out(up, UART_LCR, UART_LCR_CONF_MODE_B);
+ if ((mctrl & TIOCM_RTS) && (port->status & UPSTAT_AUTORTS))
+ up->efr |= UART_EFR_RTS;
+ else
+ up->efr &= UART_EFR_RTS;
+ serial_out(up, UART_EFR, up->efr);
+ serial_out(up, UART_LCR, lcr);
+
pm_runtime_mark_last_busy(up->dev);
pm_runtime_put_autosuspend(up->dev);
}
@@ -756,8 +767,6 @@ static int serial_omap_startup(struct uart_port *port)
* (they will be reenabled in set_termios())
*/
serial_omap_clear_fifos(up);
- /* For Hardware flow control */
- serial_out(up, UART_MCR, UART_MCR_RTS);
/*
* Clear the interrupt registers.
@@ -1053,12 +1062,12 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
serial_out(up, UART_TI752_TCR, OMAP_UART_TCR_TRIG);
- if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
- /* Enable AUTORTS and AUTOCTS */
- up->efr |= UART_EFR_CTS | UART_EFR_RTS;
+ up->port.status &= ~(UPSTAT_AUTOCTS | UPSTAT_AUTORTS | UPSTAT_AUTOXOFF);
- /* Ensure MCR RTS is asserted */
- up->mcr |= UART_MCR_RTS;
+ if (termios->c_cflag & CRTSCTS && up->port.flags & UPF_HARD_FLOW) {
+ /* Enable AUTOCTS (autoRTS is enabled when RTS is raised) */
+ up->port.status |= UPSTAT_AUTOCTS | UPSTAT_AUTORTS;
+ up->efr |= UART_EFR_CTS;
} else {
/* Disable AUTORTS and AUTOCTS */
up->efr &= ~(UART_EFR_CTS | UART_EFR_RTS);
@@ -1081,8 +1090,10 @@ serial_omap_set_termios(struct uart_port *port, struct ktermios *termios,
* Enable XON/XOFF flow control on output.
* Transmit XON1, XOFF1
*/
- if (termios->c_iflag & IXOFF)
+ if (termios->c_iflag & IXOFF) {
+ up->port.status |= UPSTAT_AUTOXOFF;
up->efr |= OMAP_UART_SW_TX;
+ }
/*
* IXANY Flag:
diff --git a/drivers/tty/serial/samsung.c b/drivers/tty/serial/samsung.c
index 107e80722575..af821a908720 100644
--- a/drivers/tty/serial/samsung.c
+++ b/drivers/tty/serial/samsung.c
@@ -28,6 +28,9 @@
#define SUPPORT_SYSRQ
#endif
+#include <linux/dmaengine.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
@@ -78,6 +81,10 @@ static void dbg(const char *fmt, ...)
#define S3C24XX_SERIAL_MAJOR 204
#define S3C24XX_SERIAL_MINOR 64
+#define S3C24XX_TX_PIO 1
+#define S3C24XX_TX_DMA 2
+#define S3C24XX_RX_PIO 1
+#define S3C24XX_RX_DMA 2
/* macros to change one thing to another */
#define tx_enabled(port) ((port)->unused[0])
@@ -154,39 +161,272 @@ static void s3c24xx_serial_rx_disable(struct uart_port *port)
static void s3c24xx_serial_stop_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct dma_tx_state state;
+ int count;
- if (tx_enabled(port)) {
- if (s3c24xx_serial_has_interrupt_mask(port))
- __set_bit(S3C64XX_UINTM_TXD,
- portaddrl(port, S3C64XX_UINTM));
- else
- disable_irq_nosync(ourport->tx_irq);
- tx_enabled(port) = 0;
- if (port->flags & UPF_CONS_FLOW)
- s3c24xx_serial_rx_enable(port);
+ if (!tx_enabled(port))
+ return;
+
+ if (s3c24xx_serial_has_interrupt_mask(port))
+ __set_bit(S3C64XX_UINTM_TXD,
+ portaddrl(port, S3C64XX_UINTM));
+ else
+ disable_irq_nosync(ourport->tx_irq);
+
+ if (dma && dma->tx_chan && ourport->tx_in_progress == S3C24XX_TX_DMA) {
+ dmaengine_pause(dma->tx_chan);
+ dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+ dmaengine_terminate_all(dma->tx_chan);
+ dma_sync_single_for_cpu(ourport->port.dev,
+ dma->tx_transfer_addr, dma->tx_size, DMA_TO_DEVICE);
+ async_tx_ack(dma->tx_desc);
+ count = dma->tx_bytes_requested - state.residue;
+ xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+ port->icount.tx += count;
}
+
+ tx_enabled(port) = 0;
+ ourport->tx_in_progress = 0;
+
+ if (port->flags & UPF_CONS_FLOW)
+ s3c24xx_serial_rx_enable(port);
+
+ ourport->tx_mode = 0;
}
-static void s3c24xx_serial_start_tx(struct uart_port *port)
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport);
+
+static void s3c24xx_serial_tx_dma_complete(void *args)
+{
+ struct s3c24xx_uart_port *ourport = args;
+ struct uart_port *port = &ourport->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+ struct dma_tx_state state;
+ unsigned long flags;
+ int count;
+
+
+ dmaengine_tx_status(dma->tx_chan, dma->tx_cookie, &state);
+ count = dma->tx_bytes_requested - state.residue;
+ async_tx_ack(dma->tx_desc);
+
+ dma_sync_single_for_cpu(ourport->port.dev, dma->tx_transfer_addr,
+ dma->tx_size, DMA_TO_DEVICE);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ xmit->tail = (xmit->tail + count) & (UART_XMIT_SIZE - 1);
+ port->icount.tx += count;
+ ourport->tx_in_progress = 0;
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ s3c24xx_serial_start_next_tx(ourport);
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void enable_tx_dma(struct s3c24xx_uart_port *ourport)
+{
+ struct uart_port *port = &ourport->port;
+ u32 ucon;
+
+ /* Mask Tx interrupt */
+ if (s3c24xx_serial_has_interrupt_mask(port))
+ __set_bit(S3C64XX_UINTM_TXD,
+ portaddrl(port, S3C64XX_UINTM));
+ else
+ disable_irq_nosync(ourport->tx_irq);
+
+ /* Enable tx dma mode */
+ ucon = rd_regl(port, S3C2410_UCON);
+ ucon &= ~(S3C64XX_UCON_TXBURST_MASK | S3C64XX_UCON_TXMODE_MASK);
+ ucon |= (dma_get_cache_alignment() >= 16) ?
+ S3C64XX_UCON_TXBURST_16 : S3C64XX_UCON_TXBURST_1;
+ ucon |= S3C64XX_UCON_TXMODE_DMA;
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ ourport->tx_mode = S3C24XX_TX_DMA;
+}
+
+static void enable_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+ struct uart_port *port = &ourport->port;
+ u32 ucon, ufcon;
+
+ /* Set ufcon txtrig */
+ ourport->tx_in_progress = S3C24XX_TX_PIO;
+ ufcon = rd_regl(port, S3C2410_UFCON);
+ wr_regl(port, S3C2410_UFCON, ufcon);
+
+ /* Enable tx pio mode */
+ ucon = rd_regl(port, S3C2410_UCON);
+ ucon &= ~(S3C64XX_UCON_TXMODE_MASK);
+ ucon |= S3C64XX_UCON_TXMODE_CPU;
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ /* Unmask Tx interrupt */
+ if (s3c24xx_serial_has_interrupt_mask(port))
+ __clear_bit(S3C64XX_UINTM_TXD,
+ portaddrl(port, S3C64XX_UINTM));
+ else
+ enable_irq(ourport->tx_irq);
+
+ ourport->tx_mode = S3C24XX_TX_PIO;
+}
+
+static void s3c24xx_serial_start_tx_pio(struct s3c24xx_uart_port *ourport)
+{
+ if (ourport->tx_mode != S3C24XX_TX_PIO)
+ enable_tx_pio(ourport);
+}
+
+static int s3c24xx_serial_start_tx_dma(struct s3c24xx_uart_port *ourport,
+ unsigned int count)
+{
+ struct uart_port *port = &ourport->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+
+
+ if (ourport->tx_mode != S3C24XX_TX_DMA)
+ enable_tx_dma(ourport);
+
+ while (xmit->tail & (dma_get_cache_alignment() - 1)) {
+ if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
+ return 0;
+ wr_regb(port, S3C2410_UTXH, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ count--;
+ }
+
+ dma->tx_size = count & ~(dma_get_cache_alignment() - 1);
+ dma->tx_transfer_addr = dma->tx_addr + xmit->tail;
+
+ dma_sync_single_for_device(ourport->port.dev, dma->tx_transfer_addr,
+ dma->tx_size, DMA_TO_DEVICE);
+
+ dma->tx_desc = dmaengine_prep_slave_single(dma->tx_chan,
+ dma->tx_transfer_addr, dma->tx_size,
+ DMA_MEM_TO_DEV, DMA_PREP_INTERRUPT);
+ if (!dma->tx_desc) {
+ dev_err(ourport->port.dev, "Unable to get desc for Tx\n");
+ return -EIO;
+ }
+
+ dma->tx_desc->callback = s3c24xx_serial_tx_dma_complete;
+ dma->tx_desc->callback_param = ourport;
+ dma->tx_bytes_requested = dma->tx_size;
+
+ ourport->tx_in_progress = S3C24XX_TX_DMA;
+ dma->tx_cookie = dmaengine_submit(dma->tx_desc);
+ dma_async_issue_pending(dma->tx_chan);
+ return 0;
+}
+
+static void s3c24xx_serial_start_next_tx(struct s3c24xx_uart_port *ourport)
+{
+ struct uart_port *port = &ourport->port;
+ struct circ_buf *xmit = &port->state->xmit;
+ unsigned long count;
+
+ /* Get data size up to the end of buffer */
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+ if (!count) {
+ s3c24xx_serial_stop_tx(port);
+ return;
+ }
+
+ if (!ourport->dma || !ourport->dma->tx_chan || count < port->fifosize)
+ s3c24xx_serial_start_tx_pio(ourport);
+ else
+ s3c24xx_serial_start_tx_dma(ourport, count);
+}
+
+void s3c24xx_serial_start_tx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+ struct circ_buf *xmit = &port->state->xmit;
if (!tx_enabled(port)) {
if (port->flags & UPF_CONS_FLOW)
s3c24xx_serial_rx_disable(port);
- if (s3c24xx_serial_has_interrupt_mask(port))
- __clear_bit(S3C64XX_UINTM_TXD,
- portaddrl(port, S3C64XX_UINTM));
- else
- enable_irq(ourport->tx_irq);
tx_enabled(port) = 1;
+ if (!ourport->dma || !ourport->dma->tx_chan)
+ s3c24xx_serial_start_tx_pio(ourport);
+ }
+
+ if (ourport->dma && ourport->dma->tx_chan) {
+ if (!uart_circ_empty(xmit) && !ourport->tx_in_progress)
+ s3c24xx_serial_start_next_tx(ourport);
+ }
+}
+
+static void s3c24xx_uart_copy_rx_to_tty(struct s3c24xx_uart_port *ourport,
+ struct tty_port *tty, int count)
+{
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+ int copied;
+
+ if (!count)
+ return;
+
+ dma_sync_single_for_cpu(ourport->port.dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
+
+ ourport->port.icount.rx += count;
+ if (!tty) {
+ dev_err(ourport->port.dev, "No tty port\n");
+ return;
+ }
+ copied = tty_insert_flip_string(tty,
+ ((unsigned char *)(ourport->dma->rx_buf)), count);
+ if (copied != count) {
+ WARN_ON(1);
+ dev_err(ourport->port.dev, "RxData copy to tty layer failed\n");
+ }
+}
+
+static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
+ unsigned long ufstat);
+
+static void uart_rx_drain_fifo(struct s3c24xx_uart_port *ourport)
+{
+ struct uart_port *port = &ourport->port;
+ struct tty_port *tty = &port->state->port;
+ unsigned int ch, ufstat;
+ unsigned int count;
+
+ ufstat = rd_regl(port, S3C2410_UFSTAT);
+ count = s3c24xx_serial_rx_fifocnt(ourport, ufstat);
+
+ if (!count)
+ return;
+
+ while (count-- > 0) {
+ ch = rd_regb(port, S3C2410_URXH);
+
+ ourport->port.icount.rx++;
+ tty_insert_flip_char(tty, ch, TTY_NORMAL);
}
+
+ tty_flip_buffer_push(tty);
}
static void s3c24xx_serial_stop_rx(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+ struct tty_port *t = &port->state->port;
+ struct dma_tx_state state;
+ enum dma_status dma_status;
+ unsigned int received;
if (rx_enabled(port)) {
dbg("s3c24xx_serial_stop_rx: port=%p\n", port);
@@ -197,6 +437,17 @@ static void s3c24xx_serial_stop_rx(struct uart_port *port)
disable_irq_nosync(ourport->rx_irq);
rx_enabled(port) = 0;
}
+ if (dma && dma->rx_chan) {
+ dmaengine_pause(dma->tx_chan);
+ dma_status = dmaengine_tx_status(dma->rx_chan,
+ dma->rx_cookie, &state);
+ if (dma_status == DMA_IN_PROGRESS ||
+ dma_status == DMA_PAUSED) {
+ received = dma->rx_bytes_requested - state.residue;
+ dmaengine_terminate_all(dma->rx_chan);
+ s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+ }
+ }
}
static inline struct s3c24xx_uart_info
@@ -228,12 +479,157 @@ static int s3c24xx_serial_rx_fifocnt(struct s3c24xx_uart_port *ourport,
return (ufstat & info->rx_fifomask) >> info->rx_fifoshift;
}
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport);
+static void s3c24xx_serial_rx_dma_complete(void *args)
+{
+ struct s3c24xx_uart_port *ourport = args;
+ struct uart_port *port = &ourport->port;
+
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+ struct tty_port *t = &port->state->port;
+ struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+
+ struct dma_tx_state state;
+ unsigned long flags;
+ int received;
+
+ dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
+ received = dma->rx_bytes_requested - state.residue;
+ async_tx_ack(dma->rx_desc);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (received)
+ s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+ if (tty) {
+ tty_flip_buffer_push(t);
+ tty_kref_put(tty);
+ }
+
+ s3c64xx_start_rx_dma(ourport);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static void s3c64xx_start_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+
+ dma_sync_single_for_device(ourport->port.dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
+
+ dma->rx_desc = dmaengine_prep_slave_single(dma->rx_chan,
+ dma->rx_addr, dma->rx_size, DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!dma->rx_desc) {
+ dev_err(ourport->port.dev, "Unable to get desc for Rx\n");
+ return;
+ }
+
+ dma->rx_desc->callback = s3c24xx_serial_rx_dma_complete;
+ dma->rx_desc->callback_param = ourport;
+ dma->rx_bytes_requested = dma->rx_size;
+
+ dma->rx_cookie = dmaengine_submit(dma->rx_desc);
+ dma_async_issue_pending(dma->rx_chan);
+}
/* ? - where has parity gone?? */
#define S3C2410_UERSTAT_PARITY (0x1000)
-static irqreturn_t
-s3c24xx_serial_rx_chars(int irq, void *dev_id)
+static void enable_rx_dma(struct s3c24xx_uart_port *ourport)
+{
+ struct uart_port *port = &ourport->port;
+ unsigned int ucon;
+
+ /* set Rx mode to DMA mode */
+ ucon = rd_regl(port, S3C2410_UCON);
+ ucon &= ~(S3C64XX_UCON_RXBURST_MASK |
+ S3C64XX_UCON_TIMEOUT_MASK |
+ S3C64XX_UCON_EMPTYINT_EN |
+ S3C64XX_UCON_DMASUS_EN |
+ S3C64XX_UCON_TIMEOUT_EN |
+ S3C64XX_UCON_RXMODE_MASK);
+ ucon |= S3C64XX_UCON_RXBURST_16 |
+ 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+ S3C64XX_UCON_EMPTYINT_EN |
+ S3C64XX_UCON_TIMEOUT_EN |
+ S3C64XX_UCON_RXMODE_DMA;
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ ourport->rx_mode = S3C24XX_RX_DMA;
+}
+
+static void enable_rx_pio(struct s3c24xx_uart_port *ourport)
+{
+ struct uart_port *port = &ourport->port;
+ unsigned int ucon;
+
+ /* set Rx mode to DMA mode */
+ ucon = rd_regl(port, S3C2410_UCON);
+ ucon &= ~(S3C64XX_UCON_TIMEOUT_MASK |
+ S3C64XX_UCON_EMPTYINT_EN |
+ S3C64XX_UCON_DMASUS_EN |
+ S3C64XX_UCON_TIMEOUT_EN |
+ S3C64XX_UCON_RXMODE_MASK);
+ ucon |= 0xf << S3C64XX_UCON_TIMEOUT_SHIFT |
+ S3C64XX_UCON_TIMEOUT_EN |
+ S3C64XX_UCON_RXMODE_CPU;
+ wr_regl(port, S3C2410_UCON, ucon);
+
+ ourport->rx_mode = S3C24XX_RX_PIO;
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_dma(int irq, void *dev_id)
+{
+ unsigned int utrstat, ufstat, received;
+ struct s3c24xx_uart_port *ourport = dev_id;
+ struct uart_port *port = &ourport->port;
+ struct s3c24xx_uart_dma *dma = ourport->dma;
+ struct tty_struct *tty = tty_port_tty_get(&ourport->port.state->port);
+ struct tty_port *t = &port->state->port;
+ unsigned long flags;
+ struct dma_tx_state state;
+
+ utrstat = rd_regl(port, S3C2410_UTRSTAT);
+ ufstat = rd_regl(port, S3C2410_UFSTAT);
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ if (!(utrstat & S3C2410_UTRSTAT_TIMEOUT)) {
+ s3c64xx_start_rx_dma(ourport);
+ if (ourport->rx_mode == S3C24XX_RX_PIO)
+ enable_rx_dma(ourport);
+ goto finish;
+ }
+
+ if (ourport->rx_mode == S3C24XX_RX_DMA) {
+ dmaengine_pause(dma->rx_chan);
+ dmaengine_tx_status(dma->rx_chan, dma->rx_cookie, &state);
+ dmaengine_terminate_all(dma->rx_chan);
+ received = dma->rx_bytes_requested - state.residue;
+ s3c24xx_uart_copy_rx_to_tty(ourport, t, received);
+
+ enable_rx_pio(ourport);
+ }
+
+ uart_rx_drain_fifo(ourport);
+
+ if (tty) {
+ tty_flip_buffer_push(t);
+ tty_kref_put(tty);
+ }
+
+ wr_regl(port, S3C2410_UTRSTAT, S3C2410_UTRSTAT_TIMEOUT);
+
+finish:
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t s3c24xx_serial_rx_chars_pio(int irq, void *dev_id)
{
struct s3c24xx_uart_port *ourport = dev_id;
struct uart_port *port = &ourport->port;
@@ -324,16 +720,33 @@ out:
return IRQ_HANDLED;
}
+
+static irqreturn_t s3c24xx_serial_rx_chars(int irq, void *dev_id)
+{
+ struct s3c24xx_uart_port *ourport = dev_id;
+
+ if (ourport->dma && ourport->dma->rx_chan)
+ return s3c24xx_serial_rx_chars_dma(irq, dev_id);
+ return s3c24xx_serial_rx_chars_pio(irq, dev_id);
+}
+
static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
{
struct s3c24xx_uart_port *ourport = id;
struct uart_port *port = &ourport->port;
struct circ_buf *xmit = &port->state->xmit;
unsigned long flags;
- int count = port->fifosize;
+ int count;
spin_lock_irqsave(&port->lock, flags);
+ count = CIRC_CNT_TO_END(xmit->head, xmit->tail, UART_XMIT_SIZE);
+
+ if (ourport->dma && ourport->dma->tx_chan && count >= port->fifosize) {
+ s3c24xx_serial_start_tx_dma(ourport, count);
+ goto out;
+ }
+
if (port->x_char) {
wr_regb(port, S3C2410_UTXH, port->x_char);
port->icount.tx++;
@@ -352,6 +765,7 @@ static irqreturn_t s3c24xx_serial_tx_chars(int irq, void *id)
/* try and drain the buffer... */
+ count = port->fifosize;
while (!uart_circ_empty(xmit) && count-- > 0) {
if (rd_regl(port, S3C2410_UFSTAT) & ourport->info->tx_fifofull)
break;
@@ -453,6 +867,93 @@ static void s3c24xx_serial_break_ctl(struct uart_port *port, int break_state)
spin_unlock_irqrestore(&port->lock, flags);
}
+static int s3c24xx_serial_request_dma(struct s3c24xx_uart_port *p)
+{
+ struct s3c24xx_uart_dma *dma = p->dma;
+ dma_cap_mask_t mask;
+ unsigned long flags;
+
+ /* Default slave configuration parameters */
+ dma->rx_conf.direction = DMA_DEV_TO_MEM;
+ dma->rx_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma->rx_conf.src_addr = p->port.mapbase + S3C2410_URXH;
+ dma->rx_conf.src_maxburst = 16;
+
+ dma->tx_conf.direction = DMA_MEM_TO_DEV;
+ dma->tx_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_1_BYTE;
+ dma->tx_conf.dst_addr = p->port.mapbase + S3C2410_UTXH;
+ if (dma_get_cache_alignment() >= 16)
+ dma->tx_conf.dst_maxburst = 16;
+ else
+ dma->tx_conf.dst_maxburst = 1;
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+
+ dma->rx_chan = dma_request_slave_channel_compat(mask, dma->fn,
+ dma->rx_param, p->port.dev, "rx");
+ if (!dma->rx_chan)
+ return -ENODEV;
+
+ dmaengine_slave_config(dma->rx_chan, &dma->rx_conf);
+
+ dma->tx_chan = dma_request_slave_channel_compat(mask, dma->fn,
+ dma->tx_param, p->port.dev, "tx");
+ if (!dma->tx_chan) {
+ dma_release_channel(dma->rx_chan);
+ return -ENODEV;
+ }
+
+ dmaengine_slave_config(dma->tx_chan, &dma->tx_conf);
+
+ /* RX buffer */
+ dma->rx_size = PAGE_SIZE;
+
+ dma->rx_buf = kmalloc(dma->rx_size, GFP_KERNEL);
+
+ if (!dma->rx_buf) {
+ dma_release_channel(dma->rx_chan);
+ dma_release_channel(dma->tx_chan);
+ return -ENOMEM;
+ }
+
+ dma->rx_addr = dma_map_single(dma->rx_chan->device->dev, dma->rx_buf,
+ dma->rx_size, DMA_FROM_DEVICE);
+
+ spin_lock_irqsave(&p->port.lock, flags);
+
+ /* TX buffer */
+ dma->tx_addr = dma_map_single(dma->tx_chan->device->dev,
+ p->port.state->xmit.buf,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+
+ spin_unlock_irqrestore(&p->port.lock, flags);
+
+ return 0;
+}
+
+static void s3c24xx_serial_release_dma(struct s3c24xx_uart_port *p)
+{
+ struct s3c24xx_uart_dma *dma = p->dma;
+
+ if (dma->rx_chan) {
+ dmaengine_terminate_all(dma->rx_chan);
+ dma_unmap_single(dma->rx_chan->device->dev, dma->rx_addr,
+ dma->rx_size, DMA_FROM_DEVICE);
+ kfree(dma->rx_buf);
+ dma_release_channel(dma->rx_chan);
+ dma->rx_chan = NULL;
+ }
+
+ if (dma->tx_chan) {
+ dmaengine_terminate_all(dma->tx_chan);
+ dma_unmap_single(dma->tx_chan->device->dev, dma->tx_addr,
+ UART_XMIT_SIZE, DMA_TO_DEVICE);
+ dma_release_channel(dma->tx_chan);
+ dma->tx_chan = NULL;
+ }
+}
+
static void s3c24xx_serial_shutdown(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
@@ -478,6 +979,11 @@ static void s3c24xx_serial_shutdown(struct uart_port *port)
wr_regl(port, S3C64XX_UINTP, 0xf);
wr_regl(port, S3C64XX_UINTM, 0xf);
}
+
+ if (ourport->dma)
+ s3c24xx_serial_release_dma(ourport);
+
+ ourport->tx_in_progress = 0;
}
static int s3c24xx_serial_startup(struct uart_port *port)
@@ -529,12 +1035,21 @@ err:
static int s3c64xx_serial_startup(struct uart_port *port)
{
struct s3c24xx_uart_port *ourport = to_ourport(port);
+ unsigned long flags;
+ unsigned int ufcon;
int ret;
dbg("s3c64xx_serial_startup: port=%p (%08llx,%p)\n",
port, (unsigned long long)port->mapbase, port->membase);
wr_regl(port, S3C64XX_UINTM, 0xf);
+ if (ourport->dma) {
+ ret = s3c24xx_serial_request_dma(ourport);
+ if (ret < 0) {
+ dev_warn(port->dev, "DMA request failed\n");
+ return ret;
+ }
+ }
ret = request_irq(port->irq, s3c64xx_serial_handle_irq, IRQF_SHARED,
s3c24xx_serial_portname(port), ourport);
@@ -549,8 +1064,20 @@ static int s3c64xx_serial_startup(struct uart_port *port)
tx_enabled(port) = 0;
ourport->tx_claimed = 1;
+ spin_lock_irqsave(&port->lock, flags);
+
+ ufcon = rd_regl(port, S3C2410_UFCON);
+ ufcon |= S3C2410_UFCON_RESETRX | S3C2410_UFCON_RESETTX |
+ S5PV210_UFCON_RXTRIG8;
+ wr_regl(port, S3C2410_UFCON, ufcon);
+
+ enable_rx_pio(ourport);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
/* Enable Rx Interrupt */
__clear_bit(S3C64XX_UINTM_RXD, portaddrl(port, S3C64XX_UINTM));
+
dbg("s3c64xx_serial_startup ok\n");
return ret;
}
@@ -1209,6 +1736,18 @@ static int s3c24xx_serial_init_port(struct s3c24xx_uart_port *ourport,
ret = platform_get_irq(platdev, 1);
if (ret > 0)
ourport->tx_irq = ret;
+ /*
+ * DMA is currently supported only on DT platforms, if DMA properties
+ * are specified.
+ */
+ if (platdev->dev.of_node && of_find_property(platdev->dev.of_node,
+ "dmas", NULL)) {
+ ourport->dma = devm_kzalloc(port->dev,
+ sizeof(*ourport->dma),
+ GFP_KERNEL);
+ if (!ourport->dma)
+ return -ENOMEM;
+ }
ourport->clk = clk_get(&platdev->dev, "uart");
if (IS_ERR(ourport->clk)) {
@@ -1857,6 +2396,111 @@ static struct platform_driver samsung_serial_driver = {
module_platform_driver(samsung_serial_driver);
+#ifdef CONFIG_SERIAL_SAMSUNG_CONSOLE
+/*
+ * Early console.
+ */
+
+struct samsung_early_console_data {
+ u32 txfull_mask;
+};
+
+static void samsung_early_busyuart(struct uart_port *port)
+{
+ while (!(readl(port->membase + S3C2410_UTRSTAT) & S3C2410_UTRSTAT_TXFE))
+ ;
+}
+
+static void samsung_early_busyuart_fifo(struct uart_port *port)
+{
+ struct samsung_early_console_data *data = port->private_data;
+
+ while (readl(port->membase + S3C2410_UFSTAT) & data->txfull_mask)
+ ;
+}
+
+static void samsung_early_putc(struct uart_port *port, int c)
+{
+ if (readl(port->membase + S3C2410_UFCON) & S3C2410_UFCON_FIFOMODE)
+ samsung_early_busyuart_fifo(port);
+ else
+ samsung_early_busyuart(port);
+
+ writeb(c, port->membase + S3C2410_UTXH);
+}
+
+static void samsung_early_write(struct console *con, const char *s, unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, samsung_early_putc);
+}
+
+static int __init samsung_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = samsung_early_write;
+ return 0;
+}
+
+/* S3C2410 */
+static struct samsung_early_console_data s3c2410_early_console_data = {
+ .txfull_mask = S3C2410_UFSTAT_TXFULL,
+};
+
+static int __init s3c2410_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ device->port.private_data = &s3c2410_early_console_data;
+ return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2410, "samsung,s3c2410-uart",
+ s3c2410_early_console_setup);
+EARLYCON_DECLARE(s3c2410, s3c2410_early_console_setup);
+
+/* S3C2412, S3C2440, S3C64xx */
+static struct samsung_early_console_data s3c2440_early_console_data = {
+ .txfull_mask = S3C2440_UFSTAT_TXFULL,
+};
+
+static int __init s3c2440_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ device->port.private_data = &s3c2440_early_console_data;
+ return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s3c2412, "samsung,s3c2412-uart",
+ s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c2440, "samsung,s3c2440-uart",
+ s3c2440_early_console_setup);
+OF_EARLYCON_DECLARE(s3c6400, "samsung,s3c6400-uart",
+ s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c2412, s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c2440, s3c2440_early_console_setup);
+EARLYCON_DECLARE(s3c6400, s3c2440_early_console_setup);
+
+/* S5PV210, EXYNOS */
+static struct samsung_early_console_data s5pv210_early_console_data = {
+ .txfull_mask = S5PV210_UFSTAT_TXFULL,
+};
+
+static int __init s5pv210_early_console_setup(struct earlycon_device *device,
+ const char *opt)
+{
+ device->port.private_data = &s5pv210_early_console_data;
+ return samsung_early_console_setup(device, opt);
+}
+OF_EARLYCON_DECLARE(s5pv210, "samsung,s5pv210-uart",
+ s5pv210_early_console_setup);
+OF_EARLYCON_DECLARE(exynos4210, "samsung,exynos4210-uart",
+ s5pv210_early_console_setup);
+EARLYCON_DECLARE(s5pv210, s5pv210_early_console_setup);
+EARLYCON_DECLARE(exynos4210, s5pv210_early_console_setup);
+#endif
+
MODULE_ALIAS("platform:samsung-uart");
MODULE_DESCRIPTION("Samsung SoC Serial port driver");
MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>");
diff --git a/drivers/tty/serial/samsung.h b/drivers/tty/serial/samsung.h
index eb071dd19b2d..d275032aa68d 100644
--- a/drivers/tty/serial/samsung.h
+++ b/drivers/tty/serial/samsung.h
@@ -12,6 +12,8 @@
* published by the Free Software Foundation.
*/
+#include <linux/dmaengine.h>
+
struct s3c24xx_uart_info {
char *name;
unsigned int type;
@@ -41,6 +43,40 @@ struct s3c24xx_serial_drv_data {
unsigned int fifosize[CONFIG_SERIAL_SAMSUNG_UARTS];
};
+struct s3c24xx_uart_dma {
+ dma_filter_fn fn;
+ void *rx_param;
+ void *tx_param;
+
+ unsigned int rx_chan_id;
+ unsigned int tx_chan_id;
+
+ struct dma_slave_config rx_conf;
+ struct dma_slave_config tx_conf;
+
+ struct dma_chan *rx_chan;
+ struct dma_chan *tx_chan;
+
+ dma_addr_t rx_addr;
+ dma_addr_t tx_addr;
+
+ dma_cookie_t rx_cookie;
+ dma_cookie_t tx_cookie;
+
+ char *rx_buf;
+
+ dma_addr_t tx_transfer_addr;
+
+ size_t rx_size;
+ size_t tx_size;
+
+ struct dma_async_tx_descriptor *tx_desc;
+ struct dma_async_tx_descriptor *rx_desc;
+
+ int tx_bytes_requested;
+ int rx_bytes_requested;
+};
+
struct s3c24xx_uart_port {
unsigned char rx_claimed;
unsigned char tx_claimed;
@@ -50,6 +86,10 @@ struct s3c24xx_uart_port {
unsigned int rx_irq;
unsigned int tx_irq;
+ unsigned int tx_in_progress;
+ unsigned int tx_mode;
+ unsigned int rx_mode;
+
struct s3c24xx_uart_info *info;
struct clk *clk;
struct clk *baudclk;
@@ -59,6 +99,8 @@ struct s3c24xx_uart_port {
/* reference to platform data */
struct s3c2410_uartcfg *cfg;
+ struct s3c24xx_uart_dma *dma;
+
#ifdef CONFIG_CPU_FREQ
struct notifier_block freq_transition;
#endif
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 984605bb5bf1..6a1055ae3437 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -179,14 +179,6 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
if (tty->termios.c_cflag & CBAUD)
uart_set_mctrl(uport, TIOCM_RTS | TIOCM_DTR);
}
-
- spin_lock_irq(&uport->lock);
- if (uart_cts_enabled(uport) &&
- !(uport->ops->get_mctrl(uport) & TIOCM_CTS))
- uport->hw_stopped = 1;
- else
- uport->hw_stopped = 0;
- spin_unlock_irq(&uport->lock);
}
/*
@@ -442,6 +434,7 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
{
struct uart_port *uport = state->uart_port;
struct ktermios *termios;
+ int hw_stopped;
/*
* If we have no tty, termios, or the port does not exist,
@@ -466,6 +459,18 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
uport->status &= ~UPSTAT_DCD_ENABLE;
else
uport->status |= UPSTAT_DCD_ENABLE;
+
+ /* reset sw-assisted CTS flow control based on (possibly) new mode */
+ hw_stopped = uport->hw_stopped;
+ uport->hw_stopped = uart_softcts_mode(uport) &&
+ !(uport->ops->get_mctrl(uport) & TIOCM_CTS);
+ if (uport->hw_stopped) {
+ if (!hw_stopped)
+ uport->ops->stop_tx(uport);
+ } else {
+ if (hw_stopped)
+ __uart_start(tty);
+ }
spin_unlock_irq(&uport->lock);
}
@@ -619,22 +624,22 @@ static void uart_throttle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
- upf_t mask = 0;
+ upstat_t mask = 0;
if (I_IXOFF(tty))
- mask |= UPF_SOFT_FLOW;
+ mask |= UPSTAT_AUTOXOFF;
if (tty->termios.c_cflag & CRTSCTS)
- mask |= UPF_HARD_FLOW;
+ mask |= UPSTAT_AUTORTS;
- if (port->flags & mask) {
+ if (port->status & mask) {
port->ops->throttle(port);
- mask &= ~port->flags;
+ mask &= ~port->status;
}
- if (mask & UPF_SOFT_FLOW)
+ if (mask & UPSTAT_AUTOXOFF)
uart_send_xchar(tty, STOP_CHAR(tty));
- if (mask & UPF_HARD_FLOW)
+ if (mask & UPSTAT_AUTORTS)
uart_clear_mctrl(port, TIOCM_RTS);
}
@@ -642,22 +647,22 @@ static void uart_unthrottle(struct tty_struct *tty)
{
struct uart_state *state = tty->driver_data;
struct uart_port *port = state->uart_port;
- upf_t mask = 0;
+ upstat_t mask = 0;
if (I_IXOFF(tty))
- mask |= UPF_SOFT_FLOW;
+ mask |= UPSTAT_AUTOXOFF;
if (tty->termios.c_cflag & CRTSCTS)
- mask |= UPF_HARD_FLOW;
+ mask |= UPSTAT_AUTORTS;
- if (port->flags & mask) {
+ if (port->status & mask) {
port->ops->unthrottle(port);
- mask &= ~port->flags;
+ mask &= ~port->status;
}
- if (mask & UPF_SOFT_FLOW)
+ if (mask & UPSTAT_AUTOXOFF)
uart_send_xchar(tty, START_CHAR(tty));
- if (mask & UPF_HARD_FLOW)
+ if (mask & UPSTAT_AUTORTS)
uart_set_mctrl(port, TIOCM_RTS);
}
@@ -1351,30 +1356,6 @@ static void uart_set_termios(struct tty_struct *tty,
mask |= TIOCM_RTS;
uart_set_mctrl(uport, mask);
}
-
- /*
- * If the port is doing h/w assisted flow control, do nothing.
- * We assume that port->hw_stopped has never been set.
- */
- if (uport->flags & UPF_HARD_FLOW)
- return;
-
- /* Handle turning off CRTSCTS */
- if ((old_termios->c_cflag & CRTSCTS) && !(cflag & CRTSCTS)) {
- spin_lock_irq(&uport->lock);
- uport->hw_stopped = 0;
- __uart_start(tty);
- spin_unlock_irq(&uport->lock);
- }
- /* Handle turning on CRTSCTS */
- else if (!(old_termios->c_cflag & CRTSCTS) && (cflag & CRTSCTS)) {
- spin_lock_irq(&uport->lock);
- if (!(uport->ops->get_mctrl(uport) & TIOCM_CTS)) {
- uport->hw_stopped = 1;
- uport->ops->stop_tx(uport);
- }
- spin_unlock_irq(&uport->lock);
- }
}
/*
@@ -2008,23 +1989,24 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
}
put_device(tty_dev);
- if (console_suspend_enabled || !uart_console(uport))
- uport->suspended = 1;
+ /* Nothing to do if the console is not suspending */
+ if (!console_suspend_enabled && uart_console(uport))
+ goto unlock;
+
+ uport->suspended = 1;
if (port->flags & ASYNC_INITIALIZED) {
const struct uart_ops *ops = uport->ops;
int tries;
- if (console_suspend_enabled || !uart_console(uport)) {
- set_bit(ASYNCB_SUSPENDED, &port->flags);
- clear_bit(ASYNCB_INITIALIZED, &port->flags);
-
- spin_lock_irq(&uport->lock);
- ops->stop_tx(uport);
- ops->set_mctrl(uport, 0);
- ops->stop_rx(uport);
- spin_unlock_irq(&uport->lock);
- }
+ set_bit(ASYNCB_SUSPENDED, &port->flags);
+ clear_bit(ASYNCB_INITIALIZED, &port->flags);
+
+ spin_lock_irq(&uport->lock);
+ ops->stop_tx(uport);
+ ops->set_mctrl(uport, 0);
+ ops->stop_rx(uport);
+ spin_unlock_irq(&uport->lock);
/*
* Wait for the transmitter to empty.
@@ -2036,19 +2018,17 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
drv->dev_name,
drv->tty_driver->name_base + uport->line);
- if (console_suspend_enabled || !uart_console(uport))
- ops->shutdown(uport);
+ ops->shutdown(uport);
}
/*
* Disable the console device before suspending.
*/
- if (console_suspend_enabled && uart_console(uport))
+ if (uart_console(uport))
console_stop(uport->cons);
- if (console_suspend_enabled || !uart_console(uport))
- uart_change_pm(state, UART_PM_STATE_OFF);
-
+ uart_change_pm(state, UART_PM_STATE_OFF);
+unlock:
mutex_unlock(&port->mutex);
return 0;
@@ -2856,7 +2836,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
- if (uart_cts_enabled(uport)) {
+ if (uart_softcts_mode(uport)) {
if (uport->hw_stopped) {
if (status) {
uport->hw_stopped = 0;
@@ -2869,6 +2849,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->ops->stop_tx(uport);
}
}
+
}
}
EXPORT_SYMBOL_GPL(uart_handle_cts_change);
diff --git a/drivers/tty/serial/sh-sci.c b/drivers/tty/serial/sh-sci.c
index e032963989fc..5b50c792ad5f 100644
--- a/drivers/tty/serial/sh-sci.c
+++ b/drivers/tty/serial/sh-sci.c
@@ -858,7 +858,7 @@ static int sci_handle_fifo_overrun(struct uart_port *port)
tty_insert_flip_char(tport, 0, TTY_OVERRUN);
tty_flip_buffer_push(tport);
- dev_notice(port->dev, "overrun error\n");
+ dev_dbg(port->dev, "overrun error\n");
copied++;
}
@@ -997,12 +997,15 @@ static inline unsigned long port_rx_irq_mask(struct uart_port *port)
static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
{
unsigned short ssr_status, scr_status, err_enabled;
+ unsigned short slr_status = 0;
struct uart_port *port = ptr;
struct sci_port *s = to_sci_port(port);
irqreturn_t ret = IRQ_NONE;
ssr_status = serial_port_in(port, SCxSR);
scr_status = serial_port_in(port, SCSCR);
+ if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
+ slr_status = serial_port_in(port, SCLSR);
err_enabled = scr_status & port_rx_irq_mask(port);
/* Tx Interrupt */
@@ -1015,8 +1018,11 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
* DR flags
*/
if (((ssr_status & SCxSR_RDxF(port)) || s->chan_rx) &&
- (scr_status & SCSCR_RIE))
+ (scr_status & SCSCR_RIE)) {
+ if (port->type == PORT_SCIF || port->type == PORT_HSCIF)
+ sci_handle_fifo_overrun(port);
ret = sci_rx_interrupt(irq, ptr);
+ }
/* Error Interrupt */
if ((ssr_status & SCxSR_ERRORS(port)) && err_enabled)
@@ -1026,6 +1032,12 @@ static irqreturn_t sci_mpxed_interrupt(int irq, void *ptr)
if ((ssr_status & SCxSR_BRK(port)) && err_enabled)
ret = sci_br_interrupt(irq, ptr);
+ /* Overrun Interrupt */
+ if (port->type == PORT_SCIF || port->type == PORT_HSCIF) {
+ if (slr_status & 0x01)
+ sci_handle_fifo_overrun(port);
+ }
+
return ret;
}
@@ -2605,7 +2617,7 @@ static int sci_probe(struct platform_device *dev)
return 0;
}
-static int sci_suspend(struct device *dev)
+static __maybe_unused int sci_suspend(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
@@ -2615,7 +2627,7 @@ static int sci_suspend(struct device *dev)
return 0;
}
-static int sci_resume(struct device *dev)
+static __maybe_unused int sci_resume(struct device *dev)
{
struct sci_port *sport = dev_get_drvdata(dev);
@@ -2625,10 +2637,7 @@ static int sci_resume(struct device *dev)
return 0;
}
-static const struct dev_pm_ops sci_dev_pm_ops = {
- .suspend = sci_suspend,
- .resume = sci_resume,
-};
+static SIMPLE_DEV_PM_OPS(sci_dev_pm_ops, sci_suspend, sci_resume);
static struct platform_driver sci_driver = {
.probe = sci_probe,
diff --git a/drivers/tty/serial/sirfsoc_uart.c b/drivers/tty/serial/sirfsoc_uart.c
index b269f6bd16d6..27ed0e960880 100644
--- a/drivers/tty/serial/sirfsoc_uart.c
+++ b/drivers/tty/serial/sirfsoc_uart.c
@@ -177,7 +177,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
dmaengine_pause(sirfport->tx_dma_chan);
sirfport->tx_dma_state = TX_DMA_PAUSE;
} else {
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
@@ -186,7 +186,7 @@ static void sirfsoc_uart_stop_tx(struct uart_port *port)
uint_en->sirfsoc_txfifo_empty_en);
}
} else {
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~uint_en->sirfsoc_txfifo_empty_en);
@@ -217,7 +217,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
}
if (sirfport->tx_dma_state == TX_DMA_RUNNING)
return;
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~(uint_en->sirfsoc_txfifo_empty_en));
@@ -244,7 +244,7 @@ static void sirfsoc_uart_tx_with_dma(struct sirfsoc_uart_port *sirfport)
}
if (tran_size < 4)
sirfsoc_uart_pio_tx_chars(sirfport, tran_size);
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)|
uint_en->sirfsoc_txfifo_empty_en);
@@ -293,7 +293,7 @@ static void sirfsoc_uart_start_tx(struct uart_port *port)
sirfsoc_uart_pio_tx_chars(sirfport,
SIRFSOC_UART_IO_TX_REASONABLE_CNT);
wr_regl(port, ureg->sirfsoc_tx_fifo_op, SIRFUART_FIFO_START);
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)|
uint_en->sirfsoc_txfifo_empty_en);
@@ -311,7 +311,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_rx_fifo_op, 0);
if (sirfport->rx_dma_chan) {
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(SIRFUART_RX_DMA_INT_EN(port, uint_en) |
@@ -322,7 +322,7 @@ static void sirfsoc_uart_stop_rx(struct uart_port *port)
uint_en->sirfsoc_rx_done_en);
dmaengine_terminate_all(sirfport->rx_dma_chan);
} else {
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~(SIRFUART_RX_IO_INT_EN(port, uint_en)));
@@ -344,7 +344,7 @@ static void sirfsoc_uart_disable_ms(struct uart_port *port)
if (sirfport->uart_reg->uart_type == SIRF_REAL_UART) {
wr_regl(port, ureg->sirfsoc_afc_ctrl,
rd_regl(port, ureg->sirfsoc_afc_ctrl) & ~0x3FF);
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)&
~uint_en->sirfsoc_cts_en);
@@ -380,7 +380,7 @@ static void sirfsoc_uart_enable_ms(struct uart_port *port)
wr_regl(port, ureg->sirfsoc_afc_ctrl,
rd_regl(port, ureg->sirfsoc_afc_ctrl) |
SIRFUART_AFC_TX_EN | SIRFUART_AFC_RX_EN);
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg)
| uint_en->sirfsoc_cts_en);
@@ -544,7 +544,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
sirfport->rx_io_count = 0;
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(uint_en->sirfsoc_rx_done_en));
@@ -555,7 +555,7 @@ static void sirfsoc_rx_tmo_process_tl(unsigned long param)
} else {
wr_regl(port, ureg->sirfsoc_int_st_reg,
uint_st->sirfsoc_rx_done);
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
(uint_en->sirfsoc_rx_done_en));
@@ -578,7 +578,7 @@ static void sirfsoc_uart_handle_rx_tmo(struct sirfsoc_uart_port *sirfport)
dmaengine_terminate_all(sirfport->rx_dma_chan);
sirfport->rx_dma_items[sirfport->rx_issued].xmit.head =
SIRFSOC_RX_DMA_BUF_SIZE - tx_state.residue;
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(uint_en->sirfsoc_rx_timeout_en));
@@ -598,7 +598,7 @@ static void sirfsoc_uart_handle_rx_done(struct sirfsoc_uart_port *sirfport)
sirfsoc_uart_pio_rx_chars(port, 4 - sirfport->rx_io_count);
if (sirfport->rx_io_count == 4) {
sirfport->rx_io_count = 0;
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) &
~(uint_en->sirfsoc_rx_done_en));
@@ -748,7 +748,7 @@ static void sirfsoc_uart_start_next_rx_dma(struct uart_port *port)
for (i = 0; i < SIRFSOC_RX_LOOP_BUF_CNT; i++)
sirfsoc_rx_submit_one_dma_desc(port, i);
sirfport->rx_completed = sirfport->rx_issued = 0;
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
SIRFUART_RX_DMA_INT_EN(port, uint_en));
@@ -770,7 +770,7 @@ static void sirfsoc_uart_start_rx(struct uart_port *port)
if (sirfport->rx_dma_chan)
sirfsoc_uart_start_next_rx_dma(port);
else {
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg,
rd_regl(port, ureg->sirfsoc_int_en_reg) |
SIRFUART_RX_IO_INT_EN(port, uint_en));
@@ -1124,7 +1124,7 @@ static void sirfsoc_uart_shutdown(struct uart_port *port)
{
struct sirfsoc_uart_port *sirfport = to_sirfport(port);
struct sirfsoc_register *ureg = &sirfport->uart_reg->uart_reg;
- if (!sirfport->is_marco)
+ if (!sirfport->is_atlas7)
wr_regl(port, ureg->sirfsoc_int_en_reg, 0);
else
wr_regl(port, SIRFUART_INT_EN_CLR, ~0UL);
@@ -1271,7 +1271,7 @@ static struct uart_driver sirfsoc_uart_drv = {
static struct of_device_id sirfsoc_uart_ids[] = {
{ .compatible = "sirf,prima2-uart", .data = &sirfsoc_uart,},
- { .compatible = "sirf,marco-uart", .data = &sirfsoc_uart},
+ { .compatible = "sirf,atlas7-uart", .data = &sirfsoc_uart},
{ .compatible = "sirf,prima2-usp-uart", .data = &sirfsoc_usp},
{}
};
@@ -1350,8 +1350,8 @@ static int sirfsoc_uart_probe(struct platform_device *pdev)
gpio_direction_output(sirfport->rts_gpio, 1);
}
usp_no_flow_control:
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-uart"))
- sirfport->is_marco = true;
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-uart"))
+ sirfport->is_atlas7 = true;
if (of_property_read_u32(pdev->dev.of_node,
"fifosize",
@@ -1393,7 +1393,7 @@ usp_no_flow_control:
goto err;
}
port->uartclk = clk_get_rate(sirfport->clk);
- if (of_device_is_compatible(pdev->dev.of_node, "sirf,marco-bt-uart")) {
+ if (of_device_is_compatible(pdev->dev.of_node, "sirf,atlas7-bt-uart")) {
sirfport->clk_general = devm_clk_get(&pdev->dev, "general");
if (IS_ERR(sirfport->clk_general)) {
ret = PTR_ERR(sirfport->clk_general);
diff --git a/drivers/tty/serial/sirfsoc_uart.h b/drivers/tty/serial/sirfsoc_uart.h
index 275d03893990..727eb6b88fff 100644
--- a/drivers/tty/serial/sirfsoc_uart.h
+++ b/drivers/tty/serial/sirfsoc_uart.h
@@ -421,8 +421,8 @@ struct sirfsoc_uart_port {
bool is_bt_uart;
struct clk *clk_general;
struct clk *clk_noc;
- /* for SiRFmarco, there are SET/CLR for UART_INT_EN */
- bool is_marco;
+ /* for SiRFatlas7, there are SET/CLR for UART_INT_EN */
+ bool is_atlas7;
struct sirfsoc_uart_register *uart_reg;
struct dma_chan *rx_dma_chan;
struct dma_chan *tx_dma_chan;
diff --git a/drivers/tty/serial/sprd_serial.c b/drivers/tty/serial/sprd_serial.c
new file mode 100644
index 000000000000..594b63331ef4
--- /dev/null
+++ b/drivers/tty/serial/sprd_serial.c
@@ -0,0 +1,793 @@
+/*
+ * Copyright (C) 2012-2015 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#if defined(CONFIG_SERIAL_SPRD_CONSOLE) && defined(CONFIG_MAGIC_SYSRQ)
+#define SUPPORT_SYSRQ
+#endif
+
+#include <linux/clk.h>
+#include <linux/console.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/serial_core.h>
+#include <linux/serial.h>
+#include <linux/slab.h>
+#include <linux/tty.h>
+#include <linux/tty_flip.h>
+
+/* device name */
+#define UART_NR_MAX 8
+#define SPRD_TTY_NAME "ttyS"
+#define SPRD_FIFO_SIZE 128
+#define SPRD_DEF_RATE 26000000
+#define SPRD_BAUD_IO_LIMIT 3000000
+#define SPRD_TIMEOUT 256
+
+/* the offset of serial registers and BITs for them */
+/* data registers */
+#define SPRD_TXD 0x0000
+#define SPRD_RXD 0x0004
+
+/* line status register and its BITs */
+#define SPRD_LSR 0x0008
+#define SPRD_LSR_OE BIT(4)
+#define SPRD_LSR_FE BIT(3)
+#define SPRD_LSR_PE BIT(2)
+#define SPRD_LSR_BI BIT(7)
+#define SPRD_LSR_TX_OVER BIT(15)
+
+/* data number in TX and RX fifo */
+#define SPRD_STS1 0x000C
+
+/* interrupt enable register and its BITs */
+#define SPRD_IEN 0x0010
+#define SPRD_IEN_RX_FULL BIT(0)
+#define SPRD_IEN_TX_EMPTY BIT(1)
+#define SPRD_IEN_BREAK_DETECT BIT(7)
+#define SPRD_IEN_TIMEOUT BIT(13)
+
+/* interrupt clear register */
+#define SPRD_ICLR 0x0014
+
+/* line control register */
+#define SPRD_LCR 0x0018
+#define SPRD_LCR_STOP_1BIT 0x10
+#define SPRD_LCR_STOP_2BIT 0x30
+#define SPRD_LCR_DATA_LEN (BIT(2) | BIT(3))
+#define SPRD_LCR_DATA_LEN5 0x0
+#define SPRD_LCR_DATA_LEN6 0x4
+#define SPRD_LCR_DATA_LEN7 0x8
+#define SPRD_LCR_DATA_LEN8 0xc
+#define SPRD_LCR_PARITY (BIT(0) | BIT(1))
+#define SPRD_LCR_PARITY_EN 0x2
+#define SPRD_LCR_EVEN_PAR 0x0
+#define SPRD_LCR_ODD_PAR 0x1
+
+/* control register 1 */
+#define SPRD_CTL1 0x001C
+#define RX_HW_FLOW_CTL_THLD BIT(6)
+#define RX_HW_FLOW_CTL_EN BIT(7)
+#define TX_HW_FLOW_CTL_EN BIT(8)
+#define RX_TOUT_THLD_DEF 0x3E00
+#define RX_HFC_THLD_DEF 0x40
+
+/* fifo threshold register */
+#define SPRD_CTL2 0x0020
+#define THLD_TX_EMPTY 0x40
+#define THLD_RX_FULL 0x40
+
+/* config baud rate register */
+#define SPRD_CLKD0 0x0024
+#define SPRD_CLKD1 0x0028
+
+/* interrupt mask status register */
+#define SPRD_IMSR 0x002C
+#define SPRD_IMSR_RX_FIFO_FULL BIT(0)
+#define SPRD_IMSR_TX_FIFO_EMPTY BIT(1)
+#define SPRD_IMSR_BREAK_DETECT BIT(7)
+#define SPRD_IMSR_TIMEOUT BIT(13)
+
+struct reg_backup {
+ u32 ien;
+ u32 ctrl0;
+ u32 ctrl1;
+ u32 ctrl2;
+ u32 clkd0;
+ u32 clkd1;
+ u32 dspwait;
+};
+
+struct sprd_uart_port {
+ struct uart_port port;
+ struct reg_backup reg_bak;
+ char name[16];
+};
+
+static struct sprd_uart_port *sprd_port[UART_NR_MAX];
+static int sprd_ports_num;
+
+static inline unsigned int serial_in(struct uart_port *port, int offset)
+{
+ return readl_relaxed(port->membase + offset);
+}
+
+static inline void serial_out(struct uart_port *port, int offset, int value)
+{
+ writel_relaxed(value, port->membase + offset);
+}
+
+static unsigned int sprd_tx_empty(struct uart_port *port)
+{
+ if (serial_in(port, SPRD_STS1) & 0xff00)
+ return 0;
+ else
+ return TIOCSER_TEMT;
+}
+
+static unsigned int sprd_get_mctrl(struct uart_port *port)
+{
+ return TIOCM_DSR | TIOCM_CTS;
+}
+
+static void sprd_set_mctrl(struct uart_port *port, unsigned int mctrl)
+{
+ /* nothing to do */
+}
+
+static void sprd_stop_tx(struct uart_port *port)
+{
+ unsigned int ien, iclr;
+
+ iclr = serial_in(port, SPRD_ICLR);
+ ien = serial_in(port, SPRD_IEN);
+
+ iclr |= SPRD_IEN_TX_EMPTY;
+ ien &= ~SPRD_IEN_TX_EMPTY;
+
+ serial_out(port, SPRD_ICLR, iclr);
+ serial_out(port, SPRD_IEN, ien);
+}
+
+static void sprd_start_tx(struct uart_port *port)
+{
+ unsigned int ien;
+
+ ien = serial_in(port, SPRD_IEN);
+ if (!(ien & SPRD_IEN_TX_EMPTY)) {
+ ien |= SPRD_IEN_TX_EMPTY;
+ serial_out(port, SPRD_IEN, ien);
+ }
+}
+
+static void sprd_stop_rx(struct uart_port *port)
+{
+ unsigned int ien, iclr;
+
+ iclr = serial_in(port, SPRD_ICLR);
+ ien = serial_in(port, SPRD_IEN);
+
+ ien &= ~(SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT);
+ iclr |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT;
+
+ serial_out(port, SPRD_IEN, ien);
+ serial_out(port, SPRD_ICLR, iclr);
+}
+
+/* The Sprd serial does not support this function. */
+static void sprd_break_ctl(struct uart_port *port, int break_state)
+{
+ /* nothing to do */
+}
+
+static int handle_lsr_errors(struct uart_port *port,
+ unsigned int *flag,
+ unsigned int *lsr)
+{
+ int ret = 0;
+
+ /* statistics */
+ if (*lsr & SPRD_LSR_BI) {
+ *lsr &= ~(SPRD_LSR_FE | SPRD_LSR_PE);
+ port->icount.brk++;
+ ret = uart_handle_break(port);
+ if (ret)
+ return ret;
+ } else if (*lsr & SPRD_LSR_PE)
+ port->icount.parity++;
+ else if (*lsr & SPRD_LSR_FE)
+ port->icount.frame++;
+ if (*lsr & SPRD_LSR_OE)
+ port->icount.overrun++;
+
+ /* mask off conditions which should be ignored */
+ *lsr &= port->read_status_mask;
+ if (*lsr & SPRD_LSR_BI)
+ *flag = TTY_BREAK;
+ else if (*lsr & SPRD_LSR_PE)
+ *flag = TTY_PARITY;
+ else if (*lsr & SPRD_LSR_FE)
+ *flag = TTY_FRAME;
+
+ return ret;
+}
+
+static inline void sprd_rx(struct uart_port *port)
+{
+ struct tty_port *tty = &port->state->port;
+ unsigned int ch, flag, lsr, max_count = SPRD_TIMEOUT;
+
+ while ((serial_in(port, SPRD_STS1) & 0x00ff) && max_count--) {
+ lsr = serial_in(port, SPRD_LSR);
+ ch = serial_in(port, SPRD_RXD);
+ flag = TTY_NORMAL;
+ port->icount.rx++;
+
+ if (lsr & (SPRD_LSR_BI | SPRD_LSR_PE |
+ SPRD_LSR_FE | SPRD_LSR_OE))
+ if (handle_lsr_errors(port, &lsr, &flag))
+ continue;
+ if (uart_handle_sysrq_char(port, ch))
+ continue;
+
+ uart_insert_char(port, lsr, SPRD_LSR_OE, ch, flag);
+ }
+
+ tty_flip_buffer_push(tty);
+}
+
+static inline void sprd_tx(struct uart_port *port)
+{
+ struct circ_buf *xmit = &port->state->xmit;
+ int count;
+
+ if (port->x_char) {
+ serial_out(port, SPRD_TXD, port->x_char);
+ port->icount.tx++;
+ port->x_char = 0;
+ return;
+ }
+
+ if (uart_circ_empty(xmit) || uart_tx_stopped(port)) {
+ sprd_stop_tx(port);
+ return;
+ }
+
+ count = THLD_TX_EMPTY;
+ do {
+ serial_out(port, SPRD_TXD, xmit->buf[xmit->tail]);
+ xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+ port->icount.tx++;
+ if (uart_circ_empty(xmit))
+ break;
+ } while (--count > 0);
+
+ if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+ uart_write_wakeup(port);
+
+ if (uart_circ_empty(xmit))
+ sprd_stop_tx(port);
+}
+
+/* this handles the interrupt from one port */
+static irqreturn_t sprd_handle_irq(int irq, void *dev_id)
+{
+ struct uart_port *port = dev_id;
+ unsigned int ims;
+
+ spin_lock(&port->lock);
+
+ ims = serial_in(port, SPRD_IMSR);
+
+ if (!ims)
+ return IRQ_NONE;
+
+ serial_out(port, SPRD_ICLR, ~0);
+
+ if (ims & (SPRD_IMSR_RX_FIFO_FULL |
+ SPRD_IMSR_BREAK_DETECT | SPRD_IMSR_TIMEOUT))
+ sprd_rx(port);
+
+ if (ims & SPRD_IMSR_TX_FIFO_EMPTY)
+ sprd_tx(port);
+
+ spin_unlock(&port->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int sprd_startup(struct uart_port *port)
+{
+ int ret = 0;
+ unsigned int ien, fc;
+ unsigned int timeout;
+ struct sprd_uart_port *sp;
+ unsigned long flags;
+
+ serial_out(port, SPRD_CTL2, ((THLD_TX_EMPTY << 8) | THLD_RX_FULL));
+
+ /* clear rx fifo */
+ timeout = SPRD_TIMEOUT;
+ while (timeout-- && serial_in(port, SPRD_STS1) & 0x00ff)
+ serial_in(port, SPRD_RXD);
+
+ /* clear tx fifo */
+ timeout = SPRD_TIMEOUT;
+ while (timeout-- && serial_in(port, SPRD_STS1) & 0xff00)
+ cpu_relax();
+
+ /* clear interrupt */
+ serial_out(port, SPRD_IEN, 0);
+ serial_out(port, SPRD_ICLR, ~0);
+
+ /* allocate irq */
+ sp = container_of(port, struct sprd_uart_port, port);
+ snprintf(sp->name, sizeof(sp->name), "sprd_serial%d", port->line);
+ ret = devm_request_irq(port->dev, port->irq, sprd_handle_irq,
+ IRQF_SHARED, sp->name, port);
+ if (ret) {
+ dev_err(port->dev, "fail to request serial irq %d, ret=%d\n",
+ port->irq, ret);
+ return ret;
+ }
+ fc = serial_in(port, SPRD_CTL1);
+ fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
+ serial_out(port, SPRD_CTL1, fc);
+
+ /* enable interrupt */
+ spin_lock_irqsave(&port->lock, flags);
+ ien = serial_in(port, SPRD_IEN);
+ ien |= SPRD_IEN_RX_FULL | SPRD_IEN_BREAK_DETECT | SPRD_IEN_TIMEOUT;
+ serial_out(port, SPRD_IEN, ien);
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ return 0;
+}
+
+static void sprd_shutdown(struct uart_port *port)
+{
+ serial_out(port, SPRD_IEN, 0);
+ serial_out(port, SPRD_ICLR, ~0);
+ devm_free_irq(port->dev, port->irq, port);
+}
+
+static void sprd_set_termios(struct uart_port *port,
+ struct ktermios *termios,
+ struct ktermios *old)
+{
+ unsigned int baud, quot;
+ unsigned int lcr = 0, fc;
+ unsigned long flags;
+
+ /* ask the core to calculate the divisor for us */
+ baud = uart_get_baud_rate(port, termios, old, 0, SPRD_BAUD_IO_LIMIT);
+
+ quot = (unsigned int)((port->uartclk + baud / 2) / baud);
+
+ /* set data length */
+ switch (termios->c_cflag & CSIZE) {
+ case CS5:
+ lcr |= SPRD_LCR_DATA_LEN5;
+ break;
+ case CS6:
+ lcr |= SPRD_LCR_DATA_LEN6;
+ break;
+ case CS7:
+ lcr |= SPRD_LCR_DATA_LEN7;
+ break;
+ case CS8:
+ default:
+ lcr |= SPRD_LCR_DATA_LEN8;
+ break;
+ }
+
+ /* calculate stop bits */
+ lcr &= ~(SPRD_LCR_STOP_1BIT | SPRD_LCR_STOP_2BIT);
+ if (termios->c_cflag & CSTOPB)
+ lcr |= SPRD_LCR_STOP_2BIT;
+ else
+ lcr |= SPRD_LCR_STOP_1BIT;
+
+ /* calculate parity */
+ lcr &= ~SPRD_LCR_PARITY;
+ termios->c_cflag &= ~CMSPAR; /* no support mark/space */
+ if (termios->c_cflag & PARENB) {
+ lcr |= SPRD_LCR_PARITY_EN;
+ if (termios->c_cflag & PARODD)
+ lcr |= SPRD_LCR_ODD_PAR;
+ else
+ lcr |= SPRD_LCR_EVEN_PAR;
+ }
+
+ spin_lock_irqsave(&port->lock, flags);
+
+ /* update the per-port timeout */
+ uart_update_timeout(port, termios->c_cflag, baud);
+
+ port->read_status_mask = SPRD_LSR_OE;
+ if (termios->c_iflag & INPCK)
+ port->read_status_mask |= SPRD_LSR_FE | SPRD_LSR_PE;
+ if (termios->c_iflag & (IGNBRK | BRKINT | PARMRK))
+ port->read_status_mask |= SPRD_LSR_BI;
+
+ /* characters to ignore */
+ port->ignore_status_mask = 0;
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= SPRD_LSR_PE | SPRD_LSR_FE;
+ if (termios->c_iflag & IGNBRK) {
+ port->ignore_status_mask |= SPRD_LSR_BI;
+ /*
+ * If we're ignoring parity and break indicators,
+ * ignore overruns too (for real raw support).
+ */
+ if (termios->c_iflag & IGNPAR)
+ port->ignore_status_mask |= SPRD_LSR_OE;
+ }
+
+ /* flow control */
+ fc = serial_in(port, SPRD_CTL1);
+ fc &= ~(RX_HW_FLOW_CTL_THLD | RX_HW_FLOW_CTL_EN | TX_HW_FLOW_CTL_EN);
+ if (termios->c_cflag & CRTSCTS) {
+ fc |= RX_HW_FLOW_CTL_THLD;
+ fc |= RX_HW_FLOW_CTL_EN;
+ fc |= TX_HW_FLOW_CTL_EN;
+ }
+
+ /* clock divider bit0~bit15 */
+ serial_out(port, SPRD_CLKD0, quot & 0xffff);
+
+ /* clock divider bit16~bit20 */
+ serial_out(port, SPRD_CLKD1, (quot & 0x1f0000) >> 16);
+ serial_out(port, SPRD_LCR, lcr);
+ fc |= RX_TOUT_THLD_DEF | RX_HFC_THLD_DEF;
+ serial_out(port, SPRD_CTL1, fc);
+
+ spin_unlock_irqrestore(&port->lock, flags);
+
+ /* Don't rewrite B0 */
+ if (tty_termios_baud_rate(termios))
+ tty_termios_encode_baud_rate(termios, baud, baud);
+}
+
+static const char *sprd_type(struct uart_port *port)
+{
+ return "SPX";
+}
+
+static void sprd_release_port(struct uart_port *port)
+{
+ /* nothing to do */
+}
+
+static int sprd_request_port(struct uart_port *port)
+{
+ return 0;
+}
+
+static void sprd_config_port(struct uart_port *port, int flags)
+{
+ if (flags & UART_CONFIG_TYPE)
+ port->type = PORT_SPRD;
+}
+
+static int sprd_verify_port(struct uart_port *port,
+ struct serial_struct *ser)
+{
+ if (ser->type != PORT_SPRD)
+ return -EINVAL;
+ if (port->irq != ser->irq)
+ return -EINVAL;
+ return 0;
+}
+
+static struct uart_ops serial_sprd_ops = {
+ .tx_empty = sprd_tx_empty,
+ .get_mctrl = sprd_get_mctrl,
+ .set_mctrl = sprd_set_mctrl,
+ .stop_tx = sprd_stop_tx,
+ .start_tx = sprd_start_tx,
+ .stop_rx = sprd_stop_rx,
+ .break_ctl = sprd_break_ctl,
+ .startup = sprd_startup,
+ .shutdown = sprd_shutdown,
+ .set_termios = sprd_set_termios,
+ .type = sprd_type,
+ .release_port = sprd_release_port,
+ .request_port = sprd_request_port,
+ .config_port = sprd_config_port,
+ .verify_port = sprd_verify_port,
+};
+
+#ifdef CONFIG_SERIAL_SPRD_CONSOLE
+static inline void wait_for_xmitr(struct uart_port *port)
+{
+ unsigned int status, tmout = 10000;
+
+ /* wait up to 10ms for the character(s) to be sent */
+ do {
+ status = serial_in(port, SPRD_STS1);
+ if (--tmout == 0)
+ break;
+ udelay(1);
+ } while (status & 0xff00);
+}
+
+static void sprd_console_putchar(struct uart_port *port, int ch)
+{
+ wait_for_xmitr(port);
+ serial_out(port, SPRD_TXD, ch);
+}
+
+static void sprd_console_write(struct console *co, const char *s,
+ unsigned int count)
+{
+ struct uart_port *port = &sprd_port[co->index]->port;
+ int locked = 1;
+ unsigned long flags;
+
+ if (port->sysrq)
+ locked = 0;
+ else if (oops_in_progress)
+ locked = spin_trylock_irqsave(&port->lock, flags);
+ else
+ spin_lock_irqsave(&port->lock, flags);
+
+ uart_console_write(port, s, count, sprd_console_putchar);
+
+ /* wait for transmitter to become empty */
+ wait_for_xmitr(port);
+
+ if (locked)
+ spin_unlock_irqrestore(&port->lock, flags);
+}
+
+static int __init sprd_console_setup(struct console *co, char *options)
+{
+ struct uart_port *port;
+ int baud = 115200;
+ int bits = 8;
+ int parity = 'n';
+ int flow = 'n';
+
+ if (co->index >= UART_NR_MAX || co->index < 0)
+ co->index = 0;
+
+ port = &sprd_port[co->index]->port;
+ if (port == NULL) {
+ pr_info("serial port %d not yet initialized\n", co->index);
+ return -ENODEV;
+ }
+ if (options)
+ uart_parse_options(options, &baud, &parity, &bits, &flow);
+
+ return uart_set_options(port, co, baud, parity, bits, flow);
+}
+
+static struct uart_driver sprd_uart_driver;
+static struct console sprd_console = {
+ .name = SPRD_TTY_NAME,
+ .write = sprd_console_write,
+ .device = uart_console_device,
+ .setup = sprd_console_setup,
+ .flags = CON_PRINTBUFFER,
+ .index = -1,
+ .data = &sprd_uart_driver,
+};
+
+#define SPRD_CONSOLE (&sprd_console)
+
+/* Support for earlycon */
+static void sprd_putc(struct uart_port *port, int c)
+{
+ unsigned int timeout = SPRD_TIMEOUT;
+
+ while (timeout-- &&
+ !(readl(port->membase + SPRD_LSR) & SPRD_LSR_TX_OVER))
+ cpu_relax();
+
+ writeb(c, port->membase + SPRD_TXD);
+}
+
+static void sprd_early_write(struct console *con, const char *s,
+ unsigned n)
+{
+ struct earlycon_device *dev = con->data;
+
+ uart_console_write(&dev->port, s, n, sprd_putc);
+}
+
+static int __init sprd_early_console_setup(
+ struct earlycon_device *device,
+ const char *opt)
+{
+ if (!device->port.membase)
+ return -ENODEV;
+
+ device->con->write = sprd_early_write;
+ return 0;
+}
+
+EARLYCON_DECLARE(sprd_serial, sprd_early_console_setup);
+OF_EARLYCON_DECLARE(sprd_serial, "sprd,sc9836-uart",
+ sprd_early_console_setup);
+
+#else /* !CONFIG_SERIAL_SPRD_CONSOLE */
+#define SPRD_CONSOLE NULL
+#endif
+
+static struct uart_driver sprd_uart_driver = {
+ .owner = THIS_MODULE,
+ .driver_name = "sprd_serial",
+ .dev_name = SPRD_TTY_NAME,
+ .major = 0,
+ .minor = 0,
+ .nr = UART_NR_MAX,
+ .cons = SPRD_CONSOLE,
+};
+
+static int sprd_probe_dt_alias(int index, struct device *dev)
+{
+ struct device_node *np;
+ int ret = index;
+
+ if (!IS_ENABLED(CONFIG_OF))
+ return ret;
+
+ np = dev->of_node;
+ if (!np)
+ return ret;
+
+ ret = of_alias_get_id(np, "serial");
+ if (IS_ERR_VALUE(ret))
+ ret = index;
+ else if (ret >= ARRAY_SIZE(sprd_port) || sprd_port[ret] != NULL) {
+ dev_warn(dev, "requested serial port %d not available.\n", ret);
+ ret = index;
+ }
+
+ return ret;
+}
+
+static int sprd_remove(struct platform_device *dev)
+{
+ struct sprd_uart_port *sup = platform_get_drvdata(dev);
+
+ if (sup) {
+ uart_remove_one_port(&sprd_uart_driver, &sup->port);
+ sprd_port[sup->port.line] = NULL;
+ sprd_ports_num--;
+ }
+
+ if (!sprd_ports_num)
+ uart_unregister_driver(&sprd_uart_driver);
+
+ return 0;
+}
+
+static int sprd_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ struct uart_port *up;
+ struct clk *clk;
+ int irq;
+ int index;
+ int ret;
+
+ for (index = 0; index < ARRAY_SIZE(sprd_port); index++)
+ if (sprd_port[index] == NULL)
+ break;
+
+ if (index == ARRAY_SIZE(sprd_port))
+ return -EBUSY;
+
+ index = sprd_probe_dt_alias(index, &pdev->dev);
+
+ sprd_port[index] = devm_kzalloc(&pdev->dev,
+ sizeof(*sprd_port[index]), GFP_KERNEL);
+ if (!sprd_port[index])
+ return -ENOMEM;
+
+ up = &sprd_port[index]->port;
+ up->dev = &pdev->dev;
+ up->line = index;
+ up->type = PORT_SPRD;
+ up->iotype = SERIAL_IO_PORT;
+ up->uartclk = SPRD_DEF_RATE;
+ up->fifosize = SPRD_FIFO_SIZE;
+ up->ops = &serial_sprd_ops;
+ up->flags = UPF_BOOT_AUTOCONF;
+
+ clk = devm_clk_get(&pdev->dev, NULL);
+ if (!IS_ERR(clk))
+ up->uartclk = clk_get_rate(clk);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "not provide mem resource\n");
+ return -ENODEV;
+ }
+ up->mapbase = res->start;
+ up->membase = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(up->membase))
+ return PTR_ERR(up->membase);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "not provide irq resource\n");
+ return -ENODEV;
+ }
+ up->irq = irq;
+
+ if (!sprd_ports_num) {
+ ret = uart_register_driver(&sprd_uart_driver);
+ if (ret < 0) {
+ pr_err("Failed to register SPRD-UART driver\n");
+ return ret;
+ }
+ }
+ sprd_ports_num++;
+
+ ret = uart_add_one_port(&sprd_uart_driver, up);
+ if (ret) {
+ sprd_port[index] = NULL;
+ sprd_remove(pdev);
+ }
+
+ platform_set_drvdata(pdev, up);
+
+ return ret;
+}
+
+static int sprd_suspend(struct device *dev)
+{
+ struct sprd_uart_port *sup = dev_get_drvdata(dev);
+
+ uart_suspend_port(&sprd_uart_driver, &sup->port);
+
+ return 0;
+}
+
+static int sprd_resume(struct device *dev)
+{
+ struct sprd_uart_port *sup = dev_get_drvdata(dev);
+
+ uart_resume_port(&sprd_uart_driver, &sup->port);
+
+ return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(sprd_pm_ops, sprd_suspend, sprd_resume);
+
+static const struct of_device_id serial_ids[] = {
+ {.compatible = "sprd,sc9836-uart",},
+ {}
+};
+
+static struct platform_driver sprd_platform_driver = {
+ .probe = sprd_probe,
+ .remove = sprd_remove,
+ .driver = {
+ .name = "sprd_serial",
+ .of_match_table = of_match_ptr(serial_ids),
+ .pm = &sprd_pm_ops,
+ },
+};
+
+module_platform_driver(sprd_platform_driver);
+
+MODULE_LICENSE("GPL v2");
+MODULE_DESCRIPTION("Spreadtrum SoC serial driver series");
diff --git a/drivers/tty/serial/xilinx_uartps.c b/drivers/tty/serial/xilinx_uartps.c
index 542bab37e502..cff531a51a78 100644
--- a/drivers/tty/serial/xilinx_uartps.c
+++ b/drivers/tty/serial/xilinx_uartps.c
@@ -637,10 +637,12 @@ static void cdns_uart_set_termios(struct uart_port *port,
spin_lock_irqsave(&port->lock, flags);
- /* Empty the receive FIFO 1st before making changes */
- while ((cdns_uart_readl(CDNS_UART_SR_OFFSET) &
- CDNS_UART_SR_RXEMPTY) != CDNS_UART_SR_RXEMPTY) {
- cdns_uart_readl(CDNS_UART_FIFO_OFFSET);
+ /* Wait for the transmit FIFO to empty before making changes */
+ if (!(cdns_uart_readl(CDNS_UART_CR_OFFSET) & CDNS_UART_CR_TX_DIS)) {
+ while (!(cdns_uart_readl(CDNS_UART_SR_OFFSET) &
+ CDNS_UART_SR_TXEMPTY)) {
+ cpu_relax();
+ }
}
/* Disable the TX and RX to set baud rate */
diff --git a/drivers/tty/sysrq.c b/drivers/tty/sysrq.c
index 42bad18c66c9..259a4d5a4e8f 100644
--- a/drivers/tty/sysrq.c
+++ b/drivers/tty/sysrq.c
@@ -90,7 +90,7 @@ static void sysrq_handle_loglevel(int key)
i = key - '0';
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
- printk("Loglevel set to %d\n", i);
+ pr_info("Loglevel set to %d\n", i);
console_loglevel = i;
}
static struct sysrq_key_op sysrq_loglevel_op = {
@@ -220,7 +220,7 @@ static void showacpu(void *dummy)
return;
spin_lock_irqsave(&show_lock, flags);
- printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+ pr_info("CPU%d:\n", smp_processor_id());
show_stack(NULL, NULL);
spin_unlock_irqrestore(&show_lock, flags);
}
@@ -243,7 +243,7 @@ static void sysrq_handle_showallcpus(int key)
struct pt_regs *regs = get_irq_regs();
if (regs) {
- printk(KERN_INFO "CPU%d:\n", smp_processor_id());
+ pr_info("CPU%d:\n", smp_processor_id());
show_regs(regs);
}
schedule_work(&sysrq_showallcpus);
@@ -355,8 +355,9 @@ static struct sysrq_key_op sysrq_term_op = {
static void moom_callback(struct work_struct *ignored)
{
- out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL), GFP_KERNEL,
- 0, NULL, true);
+ if (!out_of_memory(node_zonelist(first_memory_node, GFP_KERNEL),
+ GFP_KERNEL, 0, NULL, true))
+ pr_info("OOM request ignored because killer is disabled\n");
}
static DECLARE_WORK(moom_work, moom_callback);
@@ -522,7 +523,7 @@ void __handle_sysrq(int key, bool check_mask)
*/
orig_log_level = console_loglevel;
console_loglevel = CONSOLE_LOGLEVEL_DEFAULT;
- printk(KERN_INFO "SysRq : ");
+ pr_info("SysRq : ");
op_p = __sysrq_get_key_op(key);
if (op_p) {
@@ -531,14 +532,14 @@ void __handle_sysrq(int key, bool check_mask)
* should not) and is the invoked operation enabled?
*/
if (!check_mask || sysrq_on_mask(op_p->enable_mask)) {
- printk("%s\n", op_p->action_msg);
+ pr_cont("%s\n", op_p->action_msg);
console_loglevel = orig_log_level;
op_p->handler(key);
} else {
- printk("This sysrq operation is disabled.\n");
+ pr_cont("This sysrq operation is disabled.\n");
}
} else {
- printk("HELP : ");
+ pr_cont("HELP : ");
/* Only print the help msg once per handler */
for (i = 0; i < ARRAY_SIZE(sysrq_key_table); i++) {
if (sysrq_key_table[i]) {
@@ -549,10 +550,10 @@ void __handle_sysrq(int key, bool check_mask)
;
if (j != i)
continue;
- printk("%s ", sysrq_key_table[i]->help_msg);
+ pr_cont("%s ", sysrq_key_table[i]->help_msg);
}
}
- printk("\n");
+ pr_cont("\n");
console_loglevel = orig_log_level;
}
rcu_read_unlock();
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 3605103fc1ac..75661641f5fe 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -557,3 +557,9 @@ int tty_buffer_set_limit(struct tty_port *port, int limit)
return 0;
}
EXPORT_SYMBOL_GPL(tty_buffer_set_limit);
+
+/* slave ptys can claim nested buffer lock when handling BRK and INTR */
+void tty_buffer_set_lock_subclass(struct tty_port *port)
+{
+ lockdep_set_subclass(&port->buf.lock, TTY_LOCK_SLAVE);
+}
diff --git a/drivers/tty/tty_ioctl.c b/drivers/tty/tty_ioctl.c
index 1787fa4d9448..a5cf253b2544 100644
--- a/drivers/tty/tty_ioctl.c
+++ b/drivers/tty/tty_ioctl.c
@@ -530,7 +530,7 @@ EXPORT_SYMBOL(tty_termios_hw_change);
* Locking: termios_rwsem
*/
-int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
+static int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
{
struct ktermios old_termios;
struct tty_ldisc *ld;
@@ -563,7 +563,6 @@ int tty_set_termios(struct tty_struct *tty, struct ktermios *new_termios)
up_write(&tty->termios_rwsem);
return 0;
}
-EXPORT_SYMBOL_GPL(tty_set_termios);
/**
* set_termios - set termios values for a tty
diff --git a/drivers/tty/tty_mutex.c b/drivers/tty/tty_mutex.c
index 4486741190c4..0efcf713b756 100644
--- a/drivers/tty/tty_mutex.c
+++ b/drivers/tty/tty_mutex.c
@@ -4,18 +4,8 @@
#include <linux/semaphore.h>
#include <linux/sched.h>
-/*
- * Nested tty locks are necessary for releasing pty pairs.
- * The stable lock order is master pty first, then slave pty.
- */
-
/* Legacy tty mutex glue */
-enum {
- TTY_MUTEX_NORMAL,
- TTY_MUTEX_SLAVE,
-};
-
/*
* Getting the big tty mutex.
*/
@@ -46,12 +36,8 @@ EXPORT_SYMBOL(tty_unlock);
void __lockfunc tty_lock_slave(struct tty_struct *tty)
{
- if (tty && tty != tty->link) {
- WARN_ON(!mutex_is_locked(&tty->link->legacy_mutex) ||
- !tty->driver->type == TTY_DRIVER_TYPE_PTY ||
- !tty->driver->type == PTY_TYPE_SLAVE);
+ if (tty && tty != tty->link)
tty_lock(tty);
- }
}
void __lockfunc tty_unlock_slave(struct tty_struct *tty)
@@ -62,5 +48,5 @@ void __lockfunc tty_unlock_slave(struct tty_struct *tty)
void tty_set_lock_subclass(struct tty_struct *tty)
{
- lockdep_set_subclass(&tty->legacy_mutex, TTY_MUTEX_SLAVE);
+ lockdep_set_subclass(&tty->legacy_mutex, TTY_LOCK_SLAVE);
}
diff --git a/drivers/tty/vt/vt.c b/drivers/tty/vt/vt.c
index f3fbbbca9bde..6e00572cbeb9 100644
--- a/drivers/tty/vt/vt.c
+++ b/drivers/tty/vt/vt.c
@@ -500,6 +500,7 @@ void invert_screen(struct vc_data *vc, int offset, int count, int viewed)
#endif
if (DO_UPDATE(vc))
do_update_region(vc, (unsigned long) p, count);
+ notify_update(vc);
}
/* used by selection: complement pointer position */
@@ -516,6 +517,7 @@ void complement_pos(struct vc_data *vc, int offset)
scr_writew(old, screenpos(vc, old_offset, 1));
if (DO_UPDATE(vc))
vc->vc_sw->con_putc(vc, old, oldy, oldx);
+ notify_update(vc);
}
old_offset = offset;
@@ -533,8 +535,8 @@ void complement_pos(struct vc_data *vc, int offset)
oldy = (offset >> 1) / vc->vc_cols;
vc->vc_sw->con_putc(vc, new, oldy, oldx);
}
+ notify_update(vc);
}
-
}
static void insert_char(struct vc_data *vc, unsigned int nr)
@@ -3318,11 +3320,8 @@ static int vt_bind(struct con_driver *con)
if (first == 0 && last == MAX_NR_CONSOLES -1)
deflt = 1;
- if (first != -1) {
- console_lock();
+ if (first != -1)
do_bind_con_driver(csw, first, last, deflt);
- console_unlock();
- }
first = -1;
last = -1;
@@ -3362,9 +3361,7 @@ static int vt_unbind(struct con_driver *con)
deflt = 1;
if (first != -1) {
- console_lock();
ret = do_unbind_con_driver(csw, first, last, deflt);
- console_unlock();
if (ret != 0)
return ret;
}
@@ -3394,11 +3391,15 @@ static ssize_t store_bind(struct device *dev, struct device_attribute *attr,
struct con_driver *con = dev_get_drvdata(dev);
int bind = simple_strtoul(buf, NULL, 0);
+ console_lock();
+
if (bind)
vt_bind(con);
else
vt_unbind(con);
+ console_unlock();
+
return count;
}
@@ -3665,8 +3666,7 @@ int do_unregister_con_driver(const struct consw *csw)
for (i = 0; i < MAX_NR_CON_DRIVER; i++) {
struct con_driver *con_driver = &registered_con_driver[i];
- if (con_driver->con == csw &&
- con_driver->flag & CON_DRIVER_FLAG_INIT) {
+ if (con_driver->con == csw) {
vtconsole_deinit_device(con_driver);
device_destroy(vtconsole_class,
MKDEV(0, con_driver->node));
diff --git a/drivers/uio/Kconfig b/drivers/uio/Kconfig
index 5a90914d856d..8a15c323c030 100644
--- a/drivers/uio/Kconfig
+++ b/drivers/uio/Kconfig
@@ -104,6 +104,26 @@ config UIO_NETX
To compile this driver as a module, choose M here; the module
will be called uio_netx.
+config UIO_FSL_ELBC_GPCM
+ tristate "eLBC/GPCM driver"
+ depends on FSL_LBC
+ help
+ Generic driver for accessing a peripheral connected to an eLBC port
+ that is running in GPCM mode. GPCM is an interface for simple lower
+ performance memories and memory-mapped devices. For devices using
+ FCM or UPM eLBC modes, other device-specific drivers are available.
+
+config UIO_FSL_ELBC_GPCM_NETX5152
+ bool "eLBC/GPCM netX 51/52 support"
+ depends on UIO_FSL_ELBC_GPCM
+ help
+ This will add support for netX 51/52 devices connected via eLBC/GPCM.
+ In particular, it implements interrupt handling. This can be used
+ together with the userspace netX stack from Hilscher.
+
+ Information about this hardware can be found at:
+ http://www.hilscher.com/netx
+
config UIO_PRUSS
tristate "Texas Instruments PRUSS driver"
depends on ARCH_DAVINCI_DA850
diff --git a/drivers/uio/Makefile b/drivers/uio/Makefile
index d3218bde3aeb..8560dad52d0f 100644
--- a/drivers/uio/Makefile
+++ b/drivers/uio/Makefile
@@ -8,3 +8,4 @@ obj-$(CONFIG_UIO_PCI_GENERIC) += uio_pci_generic.o
obj-$(CONFIG_UIO_NETX) += uio_netx.o
obj-$(CONFIG_UIO_PRUSS) += uio_pruss.o
obj-$(CONFIG_UIO_MF624) += uio_mf624.o
+obj-$(CONFIG_UIO_FSL_ELBC_GPCM) += uio_fsl_elbc_gpcm.o
diff --git a/drivers/uio/uio_fsl_elbc_gpcm.c b/drivers/uio/uio_fsl_elbc_gpcm.c
new file mode 100644
index 000000000000..b6cac91c2ced
--- /dev/null
+++ b/drivers/uio/uio_fsl_elbc_gpcm.c
@@ -0,0 +1,499 @@
+/* uio_fsl_elbc_gpcm: UIO driver for eLBC/GPCM peripherals
+
+ Copyright (C) 2014 Linutronix GmbH
+ Author: John Ogness <john.ogness@linutronix.de>
+
+ This driver provides UIO access to memory of a peripheral connected
+ to the Freescale enhanced local bus controller (eLBC) interface
+ using the general purpose chip-select mode (GPCM).
+
+ Here is an example of the device tree entries:
+
+ localbus@ffe05000 {
+ ranges = <0x2 0x0 0x0 0xff810000 0x10000>;
+
+ dpm@2,0 {
+ compatible = "fsl,elbc-gpcm-uio";
+ reg = <0x2 0x0 0x10000>;
+ elbc-gpcm-br = <0xff810800>;
+ elbc-gpcm-or = <0xffff09f7>;
+ interrupt-parent = <&mpic>;
+ interrupts = <4 1>;
+ device_type = "netx5152";
+ uio_name = "netx_custom";
+ netx5152,init-win0-offset = <0x0>;
+ };
+ };
+
+ Only the entries reg (to identify bank) and elbc-gpcm-* (initial BR/OR
+ values) are required. The entries interrupt*, device_type, and uio_name
+ are optional (as well as any type-specific options such as
+ netx5152,init-win0-offset). As long as no interrupt handler is needed,
+ this driver can be used without any type-specific implementation.
+
+ The netx5152 type has been tested to work with the netX 51/52 hardware
+ from Hilscher using the Hilscher userspace netX stack.
+
+ The netx5152 type should serve as a model to add new type-specific
+ devices as needed.
+*/
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/platform_device.h>
+#include <linux/uio_driver.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+
+#include <asm/fsl_lbc.h>
+
+#define MAX_BANKS 8
+
+struct fsl_elbc_gpcm {
+ struct device *dev;
+ struct fsl_lbc_regs __iomem *lbc;
+ u32 bank;
+ const char *name;
+
+ void (*init)(struct uio_info *info);
+ void (*shutdown)(struct uio_info *info, bool init_err);
+ irqreturn_t (*irq_handler)(int irq, struct uio_info *info);
+};
+
+static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
+ char *buf);
+static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count);
+
+DEVICE_ATTR(reg_br, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store);
+DEVICE_ATTR(reg_or, S_IRUGO|S_IWUSR|S_IWGRP, reg_show, reg_store);
+
+static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uio_info *info = platform_get_drvdata(pdev);
+ struct fsl_elbc_gpcm *priv = info->priv;
+ struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
+
+ if (attr == &dev_attr_reg_br) {
+ return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+ in_be32(&bank->br));
+
+ } else if (attr == &dev_attr_reg_or) {
+ return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
+ in_be32(&bank->or));
+ }
+
+ return 0;
+}
+
+static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct uio_info *info = platform_get_drvdata(pdev);
+ struct fsl_elbc_gpcm *priv = info->priv;
+ struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
+ unsigned long val;
+ u32 reg_br_cur;
+ u32 reg_or_cur;
+ u32 reg_new;
+
+ /* parse use input */
+ if (kstrtoul(buf, 0, &val) != 0)
+ return -EINVAL;
+ reg_new = (u32)val;
+
+ /* read current values */
+ reg_br_cur = in_be32(&bank->br);
+ reg_or_cur = in_be32(&bank->or);
+
+ if (attr == &dev_attr_reg_br) {
+ /* not allowed to change effective base address */
+ if ((reg_br_cur & reg_or_cur & BR_BA) !=
+ (reg_new & reg_or_cur & BR_BA)) {
+ return -EINVAL;
+ }
+
+ /* not allowed to change mode */
+ if ((reg_new & BR_MSEL) != BR_MS_GPCM)
+ return -EINVAL;
+
+ /* write new value (force valid) */
+ out_be32(&bank->br, reg_new | BR_V);
+
+ } else if (attr == &dev_attr_reg_or) {
+ /* not allowed to change access mask */
+ if ((reg_or_cur & OR_GPCM_AM) != (reg_new & OR_GPCM_AM))
+ return -EINVAL;
+
+ /* write new value */
+ out_be32(&bank->or, reg_new);
+
+ } else {
+ return -EINVAL;
+ }
+
+ return count;
+}
+
+#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
+#define DPM_HOST_WIN0_OFFSET 0xff00
+#define DPM_HOST_INT_STAT0 0xe0
+#define DPM_HOST_INT_EN0 0xf0
+#define DPM_HOST_INT_MASK 0xe600ffff
+#define DPM_HOST_INT_GLOBAL_EN 0x80000000
+
+static irqreturn_t netx5152_irq_handler(int irq, struct uio_info *info)
+{
+ void __iomem *reg_int_en = info->mem[0].internal_addr +
+ DPM_HOST_WIN0_OFFSET +
+ DPM_HOST_INT_EN0;
+ void __iomem *reg_int_stat = info->mem[0].internal_addr +
+ DPM_HOST_WIN0_OFFSET +
+ DPM_HOST_INT_STAT0;
+
+ /* check if an interrupt is enabled and active */
+ if ((ioread32(reg_int_en) & ioread32(reg_int_stat) &
+ DPM_HOST_INT_MASK) == 0) {
+ return IRQ_NONE;
+ }
+
+ /* disable interrupts */
+ iowrite32(ioread32(reg_int_en) & ~DPM_HOST_INT_GLOBAL_EN, reg_int_en);
+
+ return IRQ_HANDLED;
+}
+
+static void netx5152_init(struct uio_info *info)
+{
+ unsigned long win0_offset = DPM_HOST_WIN0_OFFSET;
+ struct fsl_elbc_gpcm *priv = info->priv;
+ const void *prop;
+
+ /* get an optional initial win0 offset */
+ prop = of_get_property(priv->dev->of_node,
+ "netx5152,init-win0-offset", NULL);
+ if (prop)
+ win0_offset = of_read_ulong(prop, 1);
+
+ /* disable interrupts */
+ iowrite32(0, info->mem[0].internal_addr + win0_offset +
+ DPM_HOST_INT_EN0);
+}
+
+static void netx5152_shutdown(struct uio_info *info, bool init_err)
+{
+ if (init_err)
+ return;
+
+ /* disable interrupts */
+ iowrite32(0, info->mem[0].internal_addr + DPM_HOST_WIN0_OFFSET +
+ DPM_HOST_INT_EN0);
+}
+#endif
+
+static void setup_periph(struct fsl_elbc_gpcm *priv,
+ const char *type)
+{
+#ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
+ if (strcmp(type, "netx5152") == 0) {
+ priv->irq_handler = netx5152_irq_handler;
+ priv->init = netx5152_init;
+ priv->shutdown = netx5152_shutdown;
+ priv->name = "netX 51/52";
+ return;
+ }
+#endif
+}
+
+static int check_of_data(struct fsl_elbc_gpcm *priv,
+ struct resource *res,
+ u32 reg_br, u32 reg_or)
+{
+ /* check specified bank */
+ if (priv->bank >= MAX_BANKS) {
+ dev_err(priv->dev, "invalid bank\n");
+ return -ENODEV;
+ }
+
+ /* check specified mode (BR_MS_GPCM is 0) */
+ if ((reg_br & BR_MSEL) != BR_MS_GPCM) {
+ dev_err(priv->dev, "unsupported mode\n");
+ return -ENODEV;
+ }
+
+ /* check specified mask vs. resource size */
+ if ((~(reg_or & OR_GPCM_AM) + 1) != resource_size(res)) {
+ dev_err(priv->dev, "address mask / size mismatch\n");
+ return -ENODEV;
+ }
+
+ /* check specified address */
+ if ((reg_br & reg_or & BR_BA) != fsl_lbc_addr(res->start)) {
+ dev_err(priv->dev, "base address mismatch\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int get_of_data(struct fsl_elbc_gpcm *priv, struct device_node *node,
+ struct resource *res, u32 *reg_br,
+ u32 *reg_or, unsigned int *irq, char **name)
+{
+ const char *dt_name;
+ const char *type;
+ int ret;
+
+ /* get the memory resource */
+ ret = of_address_to_resource(node, 0, res);
+ if (ret) {
+ dev_err(priv->dev, "failed to get resource\n");
+ return ret;
+ }
+
+ /* get the bank number */
+ ret = of_property_read_u32(node, "reg", &priv->bank);
+ if (ret) {
+ dev_err(priv->dev, "failed to get bank number\n");
+ return ret;
+ }
+
+ /* get BR value to set */
+ ret = of_property_read_u32(node, "elbc-gpcm-br", reg_br);
+ if (ret) {
+ dev_err(priv->dev, "missing elbc-gpcm-br value\n");
+ return ret;
+ }
+
+ /* get OR value to set */
+ ret = of_property_read_u32(node, "elbc-gpcm-or", reg_or);
+ if (ret) {
+ dev_err(priv->dev, "missing elbc-gpcm-or value\n");
+ return ret;
+ }
+
+ /* get optional peripheral type */
+ priv->name = "generic";
+ if (of_property_read_string(node, "device_type", &type) == 0)
+ setup_periph(priv, type);
+
+ /* get optional irq value */
+ *irq = irq_of_parse_and_map(node, 0);
+
+ /* sanity check device tree data */
+ ret = check_of_data(priv, res, *reg_br, *reg_or);
+ if (ret)
+ return ret;
+
+ /* get optional uio name */
+ if (of_property_read_string(node, "uio_name", &dt_name) != 0)
+ dt_name = "eLBC_GPCM";
+ *name = kstrdup(dt_name, GFP_KERNEL);
+ if (!*name)
+ return -ENOMEM;
+
+ return 0;
+}
+
+static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct fsl_elbc_gpcm *priv;
+ struct uio_info *info;
+ char *uio_name = NULL;
+ struct resource res;
+ unsigned int irq;
+ u32 reg_br_cur;
+ u32 reg_or_cur;
+ u32 reg_br_new;
+ u32 reg_or_new;
+ int ret;
+
+ if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
+ return -ENODEV;
+
+ /* allocate private data */
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->dev = &pdev->dev;
+ priv->lbc = fsl_lbc_ctrl_dev->regs;
+
+ /* get device tree data */
+ ret = get_of_data(priv, node, &res, &reg_br_new, &reg_or_new,
+ &irq, &uio_name);
+ if (ret)
+ goto out_err0;
+
+ /* allocate UIO structure */
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ ret = -ENOMEM;
+ goto out_err0;
+ }
+
+ /* get current BR/OR values */
+ reg_br_cur = in_be32(&priv->lbc->bank[priv->bank].br);
+ reg_or_cur = in_be32(&priv->lbc->bank[priv->bank].or);
+
+ /* if bank already configured, make sure it matches */
+ if ((reg_br_cur & BR_V)) {
+ if ((reg_br_cur & BR_MSEL) != BR_MS_GPCM ||
+ (reg_br_cur & reg_or_cur & BR_BA)
+ != fsl_lbc_addr(res.start)) {
+ dev_err(priv->dev,
+ "bank in use by another peripheral\n");
+ ret = -ENODEV;
+ goto out_err1;
+ }
+
+ /* warn if behavior settings changing */
+ if ((reg_br_cur & ~(BR_BA | BR_V)) !=
+ (reg_br_new & ~(BR_BA | BR_V))) {
+ dev_warn(priv->dev,
+ "modifying BR settings: 0x%08x -> 0x%08x",
+ reg_br_cur, reg_br_new);
+ }
+ if ((reg_or_cur & ~OR_GPCM_AM) != (reg_or_new & ~OR_GPCM_AM)) {
+ dev_warn(priv->dev,
+ "modifying OR settings: 0x%08x -> 0x%08x",
+ reg_or_cur, reg_or_new);
+ }
+ }
+
+ /* configure the bank (force base address and GPCM) */
+ reg_br_new &= ~(BR_BA | BR_MSEL);
+ reg_br_new |= fsl_lbc_addr(res.start) | BR_MS_GPCM | BR_V;
+ out_be32(&priv->lbc->bank[priv->bank].or, reg_or_new);
+ out_be32(&priv->lbc->bank[priv->bank].br, reg_br_new);
+
+ /* map the memory resource */
+ info->mem[0].internal_addr = ioremap(res.start, resource_size(&res));
+ if (!info->mem[0].internal_addr) {
+ dev_err(priv->dev, "failed to map chip region\n");
+ ret = -ENODEV;
+ goto out_err1;
+ }
+
+ /* set all UIO data */
+ if (node->name)
+ info->mem[0].name = kstrdup(node->name, GFP_KERNEL);
+ info->mem[0].addr = res.start;
+ info->mem[0].size = resource_size(&res);
+ info->mem[0].memtype = UIO_MEM_PHYS;
+ info->priv = priv;
+ info->name = uio_name;
+ info->version = "0.0.1";
+ if (irq != NO_IRQ) {
+ if (priv->irq_handler) {
+ info->irq = irq;
+ info->irq_flags = IRQF_SHARED;
+ info->handler = priv->irq_handler;
+ } else {
+ irq = NO_IRQ;
+ dev_warn(priv->dev, "ignoring irq, no handler\n");
+ }
+ }
+
+ if (priv->init)
+ priv->init(info);
+
+ /* register UIO device */
+ if (uio_register_device(priv->dev, info) != 0) {
+ dev_err(priv->dev, "UIO registration failed\n");
+ ret = -ENODEV;
+ goto out_err2;
+ }
+
+ /* store private data */
+ platform_set_drvdata(pdev, info);
+
+ /* create sysfs files */
+ ret = device_create_file(priv->dev, &dev_attr_reg_br);
+ if (ret)
+ goto out_err3;
+ ret = device_create_file(priv->dev, &dev_attr_reg_or);
+ if (ret)
+ goto out_err4;
+
+ dev_info(priv->dev,
+ "eLBC/GPCM device (%s) at 0x%llx, bank %d, irq=%d\n",
+ priv->name, (unsigned long long)res.start, priv->bank,
+ irq != NO_IRQ ? irq : -1);
+
+ return 0;
+out_err4:
+ device_remove_file(priv->dev, &dev_attr_reg_br);
+out_err3:
+ platform_set_drvdata(pdev, NULL);
+ uio_unregister_device(info);
+out_err2:
+ if (priv->shutdown)
+ priv->shutdown(info, true);
+ iounmap(info->mem[0].internal_addr);
+out_err1:
+ kfree(info->mem[0].name);
+ kfree(info);
+out_err0:
+ kfree(uio_name);
+ kfree(priv);
+ return ret;
+}
+
+static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev)
+{
+ struct uio_info *info = platform_get_drvdata(pdev);
+ struct fsl_elbc_gpcm *priv = info->priv;
+
+ device_remove_file(priv->dev, &dev_attr_reg_or);
+ device_remove_file(priv->dev, &dev_attr_reg_br);
+ platform_set_drvdata(pdev, NULL);
+ uio_unregister_device(info);
+ if (priv->shutdown)
+ priv->shutdown(info, false);
+ iounmap(info->mem[0].internal_addr);
+ kfree(info->mem[0].name);
+ kfree(info->name);
+ kfree(info);
+ kfree(priv);
+
+ return 0;
+
+}
+
+static const struct of_device_id uio_fsl_elbc_gpcm_match[] = {
+ { .compatible = "fsl,elbc-gpcm-uio", },
+ {}
+};
+
+static struct platform_driver uio_fsl_elbc_gpcm_driver = {
+ .driver = {
+ .name = "fsl,elbc-gpcm-uio",
+ .owner = THIS_MODULE,
+ .of_match_table = uio_fsl_elbc_gpcm_match,
+ },
+ .probe = uio_fsl_elbc_gpcm_probe,
+ .remove = uio_fsl_elbc_gpcm_remove,
+};
+
+static int __init uio_fsl_elbc_gpcm_init(void)
+{
+ return platform_driver_register(&uio_fsl_elbc_gpcm_driver);
+}
+
+static void __exit uio_fsl_elbc_gpcm_exit(void)
+{
+ platform_driver_unregister(&uio_fsl_elbc_gpcm_driver);
+}
+
+module_init(uio_fsl_elbc_gpcm_init);
+module_exit(uio_fsl_elbc_gpcm_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>");
+MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller GPCM driver");
diff --git a/drivers/uio/uio_pci_generic.c b/drivers/uio/uio_pci_generic.c
index 077ae12269ce..d0b508b68f3c 100644
--- a/drivers/uio/uio_pci_generic.c
+++ b/drivers/uio/uio_pci_generic.c
@@ -91,7 +91,8 @@ static int probe(struct pci_dev *pdev,
gdev->info.handler = irqhandler;
gdev->pdev = pdev;
- if (uio_register_device(&pdev->dev, &gdev->info))
+ err = uio_register_device(&pdev->dev, &gdev->info);
+ if (err)
goto err_register;
pci_set_drvdata(pdev, gdev);
diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
index ae481c37a208..8ed451dd651e 100644
--- a/drivers/usb/Kconfig
+++ b/drivers/usb/Kconfig
@@ -104,6 +104,8 @@ source "drivers/usb/dwc2/Kconfig"
source "drivers/usb/chipidea/Kconfig"
+source "drivers/usb/isp1760/Kconfig"
+
comment "USB port drivers"
if USB
diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile
index d7be71778059..2f1e2aa42b44 100644
--- a/drivers/usb/Makefile
+++ b/drivers/usb/Makefile
@@ -8,6 +8,7 @@ obj-$(CONFIG_USB) += core/
obj-$(CONFIG_USB_DWC3) += dwc3/
obj-$(CONFIG_USB_DWC2) += dwc2/
+obj-$(CONFIG_USB_ISP1760) += isp1760/
obj-$(CONFIG_USB_MON) += mon/
@@ -23,7 +24,6 @@ obj-$(CONFIG_USB_ISP1362_HCD) += host/
obj-$(CONFIG_USB_U132_HCD) += host/
obj-$(CONFIG_USB_R8A66597_HCD) += host/
obj-$(CONFIG_USB_HWA_HCD) += host/
-obj-$(CONFIG_USB_ISP1760_HCD) += host/
obj-$(CONFIG_USB_IMX21_HCD) += host/
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += host/
obj-$(CONFIG_USB_FUSBH200_HCD) += host/
diff --git a/drivers/usb/chipidea/ci_hdrc_pci.c b/drivers/usb/chipidea/ci_hdrc_pci.c
index 241ae3444fde..4df669437211 100644
--- a/drivers/usb/chipidea/ci_hdrc_pci.c
+++ b/drivers/usb/chipidea/ci_hdrc_pci.c
@@ -111,6 +111,9 @@ static void ci_hdrc_pci_remove(struct pci_dev *pdev)
* PCI device structure
*
* Check "pci.h" for details
+ *
+ * Note: ehci-pci driver may try to probe the device first. You have to add an
+ * ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
*/
static const struct pci_device_id ci_hdrc_pci_id_table[] = {
{
diff --git a/drivers/usb/chipidea/udc.c b/drivers/usb/chipidea/udc.c
index 4fe18ce3bd5a..ff451048c1ac 100644
--- a/drivers/usb/chipidea/udc.c
+++ b/drivers/usb/chipidea/udc.c
@@ -819,8 +819,8 @@ __acquires(hwep->lock)
}
if ((setup->bRequestType & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
- /* Assume that device is bus powered for now. */
- *(u16 *)req->buf = ci->remote_wakeup << 1;
+ *(u16 *)req->buf = (ci->remote_wakeup << 1) |
+ ci->gadget.is_selfpowered;
} else if ((setup->bRequestType & USB_RECIP_MASK) \
== USB_RECIP_ENDPOINT) {
dir = (le16_to_cpu(setup->wIndex) & USB_ENDPOINT_DIR_MASK) ?
@@ -1520,6 +1520,19 @@ static int ci_udc_vbus_draw(struct usb_gadget *_gadget, unsigned ma)
return -ENOTSUPP;
}
+static int ci_udc_selfpowered(struct usb_gadget *_gadget, int is_on)
+{
+ struct ci_hdrc *ci = container_of(_gadget, struct ci_hdrc, gadget);
+ struct ci_hw_ep *hwep = ci->ep0in;
+ unsigned long flags;
+
+ spin_lock_irqsave(hwep->lock, flags);
+ _gadget->is_selfpowered = (is_on != 0);
+ spin_unlock_irqrestore(hwep->lock, flags);
+
+ return 0;
+}
+
/* Change Data+ pullup status
* this func is used by usb_gadget_connect/disconnet
*/
@@ -1549,6 +1562,7 @@ static int ci_udc_stop(struct usb_gadget *gadget);
static const struct usb_gadget_ops usb_gadget_ops = {
.vbus_session = ci_udc_vbus_session,
.wakeup = ci_udc_wakeup,
+ .set_selfpowered = ci_udc_selfpowered,
.pullup = ci_udc_pullup,
.vbus_draw = ci_udc_vbus_draw,
.udc_start = ci_udc_start,
diff --git a/drivers/usb/class/cdc-acm.c b/drivers/usb/class/cdc-acm.c
index 546a17e8ad5b..e78720b59d67 100644
--- a/drivers/usb/class/cdc-acm.c
+++ b/drivers/usb/class/cdc-acm.c
@@ -1091,6 +1091,7 @@ static int acm_probe(struct usb_interface *intf,
unsigned long quirks;
int num_rx_buf;
int i;
+ unsigned int elength = 0;
int combined_interfaces = 0;
struct device *tty_dev;
int rv = -ENOMEM;
@@ -1136,9 +1137,12 @@ static int acm_probe(struct usb_interface *intf,
dev_err(&intf->dev, "skipping garbage\n");
goto next_desc;
}
+ elength = buffer[0];
switch (buffer[2]) {
case USB_CDC_UNION_TYPE: /* we've found it */
+ if (elength < sizeof(struct usb_cdc_union_desc))
+ goto next_desc;
if (union_header) {
dev_err(&intf->dev, "More than one "
"union descriptor, skipping ...\n");
@@ -1147,29 +1151,36 @@ static int acm_probe(struct usb_interface *intf,
union_header = (struct usb_cdc_union_desc *)buffer;
break;
case USB_CDC_COUNTRY_TYPE: /* export through sysfs*/
+ if (elength < sizeof(struct usb_cdc_country_functional_desc))
+ goto next_desc;
cfd = (struct usb_cdc_country_functional_desc *)buffer;
break;
case USB_CDC_HEADER_TYPE: /* maybe check version */
break; /* for now we ignore it */
case USB_CDC_ACM_TYPE:
+ if (elength < 4)
+ goto next_desc;
ac_management_function = buffer[3];
break;
case USB_CDC_CALL_MANAGEMENT_TYPE:
+ if (elength < 5)
+ goto next_desc;
call_management_function = buffer[3];
call_interface_num = buffer[4];
break;
default:
- /* there are LOTS more CDC descriptors that
+ /*
+ * there are LOTS more CDC descriptors that
* could legitimately be found here.
*/
dev_dbg(&intf->dev, "Ignoring descriptor: "
- "type %02x, length %d\n",
- buffer[2], buffer[0]);
+ "type %02x, length %ud\n",
+ buffer[2], elength);
break;
}
next_desc:
- buflen -= buffer[0];
- buffer += buffer[0];
+ buflen -= elength;
+ buffer += elength;
}
if (!union_header) {
@@ -1287,10 +1298,8 @@ made_compressed_probe:
dev_dbg(&intf->dev, "interfaces are valid\n");
acm = kzalloc(sizeof(struct acm), GFP_KERNEL);
- if (acm == NULL) {
- dev_err(&intf->dev, "out of memory (acm kzalloc)\n");
+ if (acm == NULL)
goto alloc_fail;
- }
minor = acm_alloc_minor(acm);
if (minor == ACM_TTY_MINORS) {
@@ -1329,42 +1338,32 @@ made_compressed_probe:
acm->quirks = quirks;
buf = usb_alloc_coherent(usb_dev, ctrlsize, GFP_KERNEL, &acm->ctrl_dma);
- if (!buf) {
- dev_err(&intf->dev, "out of memory (ctrl buffer alloc)\n");
+ if (!buf)
goto alloc_fail2;
- }
acm->ctrl_buffer = buf;
- if (acm_write_buffers_alloc(acm) < 0) {
- dev_err(&intf->dev, "out of memory (write buffer alloc)\n");
+ if (acm_write_buffers_alloc(acm) < 0)
goto alloc_fail4;
- }
acm->ctrlurb = usb_alloc_urb(0, GFP_KERNEL);
- if (!acm->ctrlurb) {
- dev_err(&intf->dev, "out of memory (ctrlurb kmalloc)\n");
+ if (!acm->ctrlurb)
goto alloc_fail5;
- }
+
for (i = 0; i < num_rx_buf; i++) {
struct acm_rb *rb = &(acm->read_buffers[i]);
struct urb *urb;
rb->base = usb_alloc_coherent(acm->dev, readsize, GFP_KERNEL,
&rb->dma);
- if (!rb->base) {
- dev_err(&intf->dev, "out of memory "
- "(read bufs usb_alloc_coherent)\n");
+ if (!rb->base)
goto alloc_fail6;
- }
rb->index = i;
rb->instance = acm;
urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- dev_err(&intf->dev,
- "out of memory (read urbs usb_alloc_urb)\n");
+ if (!urb)
goto alloc_fail6;
- }
+
urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
urb->transfer_dma = rb->dma;
if (acm->is_int_ep) {
@@ -1389,11 +1388,8 @@ made_compressed_probe:
struct acm_wb *snd = &(acm->wb[i]);
snd->urb = usb_alloc_urb(0, GFP_KERNEL);
- if (snd->urb == NULL) {
- dev_err(&intf->dev,
- "out of memory (write urbs usb_alloc_urb)\n");
+ if (snd->urb == NULL)
goto alloc_fail7;
- }
if (usb_endpoint_xfer_int(epwrite))
usb_fill_int_urb(snd->urb, usb_dev,
diff --git a/drivers/usb/core/buffer.c b/drivers/usb/core/buffer.c
index 684ef70dc09d..506b969ea7fd 100644
--- a/drivers/usb/core/buffer.c
+++ b/drivers/usb/core/buffer.c
@@ -22,17 +22,25 @@
*/
/* FIXME tune these based on pool statistics ... */
-static const size_t pool_max[HCD_BUFFER_POOLS] = {
- /* platforms without dma-friendly caches might need to
- * prevent cacheline sharing...
- */
- 32,
- 128,
- 512,
- PAGE_SIZE / 2
- /* bigger --> allocate pages */
+static size_t pool_max[HCD_BUFFER_POOLS] = {
+ 32, 128, 512, 2048,
};
+void __init usb_init_pool_max(void)
+{
+ /*
+ * The pool_max values must never be smaller than
+ * ARCH_KMALLOC_MINALIGN.
+ */
+ if (ARCH_KMALLOC_MINALIGN <= 32)
+ ; /* Original value is okay */
+ else if (ARCH_KMALLOC_MINALIGN <= 64)
+ pool_max[0] = 64;
+ else if (ARCH_KMALLOC_MINALIGN <= 128)
+ pool_max[0] = 0; /* Don't use this pool */
+ else
+ BUILD_BUG(); /* We don't allow this */
+}
/* SETUP primitives */
diff --git a/drivers/usb/core/devio.c b/drivers/usb/core/devio.c
index 0b59731c3021..66abdbcfbfa5 100644
--- a/drivers/usb/core/devio.c
+++ b/drivers/usb/core/devio.c
@@ -1689,7 +1689,7 @@ static struct async *reap_as(struct usb_dev_state *ps)
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
as = async_getcompleted(ps);
- if (as)
+ if (as || !connected(ps))
break;
if (signal_pending(current))
break;
@@ -1712,7 +1712,7 @@ static int proc_reapurb(struct usb_dev_state *ps, void __user *arg)
}
if (signal_pending(current))
return -EINTR;
- return -EIO;
+ return -ENODEV;
}
static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
@@ -1721,10 +1721,11 @@ static int proc_reapurbnonblock(struct usb_dev_state *ps, void __user *arg)
struct async *as;
as = async_getcompleted(ps);
- retval = -EAGAIN;
if (as) {
retval = processcompl(as, (void __user * __user *)arg);
free_async(as);
+ } else {
+ retval = (connected(ps) ? -EAGAIN : -ENODEV);
}
return retval;
}
@@ -1854,7 +1855,7 @@ static int proc_reapurb_compat(struct usb_dev_state *ps, void __user *arg)
}
if (signal_pending(current))
return -EINTR;
- return -EIO;
+ return -ENODEV;
}
static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *arg)
@@ -1862,11 +1863,12 @@ static int proc_reapurbnonblock_compat(struct usb_dev_state *ps, void __user *ar
int retval;
struct async *as;
- retval = -EAGAIN;
as = async_getcompleted(ps);
if (as) {
retval = processcompl_compat(as, (void __user * __user *)arg);
free_async(as);
+ } else {
+ retval = (connected(ps) ? -EAGAIN : -ENODEV);
}
return retval;
}
@@ -2038,7 +2040,8 @@ static int proc_get_capabilities(struct usb_dev_state *ps, void __user *arg)
{
__u32 caps;
- caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM;
+ caps = USBDEVFS_CAP_ZERO_PACKET | USBDEVFS_CAP_NO_PACKET_SIZE_LIM |
+ USBDEVFS_CAP_REAP_AFTER_DISCONNECT;
if (!ps->dev->bus->no_stop_on_short)
caps |= USBDEVFS_CAP_BULK_CONTINUATION;
if (ps->dev->bus->sg_tablesize)
@@ -2138,6 +2141,32 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
return -EPERM;
usb_lock_device(dev);
+
+ /* Reap operations are allowed even after disconnection */
+ switch (cmd) {
+ case USBDEVFS_REAPURB:
+ snoop(&dev->dev, "%s: REAPURB\n", __func__);
+ ret = proc_reapurb(ps, p);
+ goto done;
+
+ case USBDEVFS_REAPURBNDELAY:
+ snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
+ ret = proc_reapurbnonblock(ps, p);
+ goto done;
+
+#ifdef CONFIG_COMPAT
+ case USBDEVFS_REAPURB32:
+ snoop(&dev->dev, "%s: REAPURB32\n", __func__);
+ ret = proc_reapurb_compat(ps, p);
+ goto done;
+
+ case USBDEVFS_REAPURBNDELAY32:
+ snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
+ ret = proc_reapurbnonblock_compat(ps, p);
+ goto done;
+#endif
+ }
+
if (!connected(ps)) {
usb_unlock_device(dev);
return -ENODEV;
@@ -2231,16 +2260,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
inode->i_mtime = CURRENT_TIME;
break;
- case USBDEVFS_REAPURB32:
- snoop(&dev->dev, "%s: REAPURB32\n", __func__);
- ret = proc_reapurb_compat(ps, p);
- break;
-
- case USBDEVFS_REAPURBNDELAY32:
- snoop(&dev->dev, "%s: REAPURBNDELAY32\n", __func__);
- ret = proc_reapurbnonblock_compat(ps, p);
- break;
-
case USBDEVFS_IOCTL32:
snoop(&dev->dev, "%s: IOCTL32\n", __func__);
ret = proc_ioctl_compat(ps, ptr_to_compat(p));
@@ -2252,16 +2271,6 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
ret = proc_unlinkurb(ps, p);
break;
- case USBDEVFS_REAPURB:
- snoop(&dev->dev, "%s: REAPURB\n", __func__);
- ret = proc_reapurb(ps, p);
- break;
-
- case USBDEVFS_REAPURBNDELAY:
- snoop(&dev->dev, "%s: REAPURBNDELAY\n", __func__);
- ret = proc_reapurbnonblock(ps, p);
- break;
-
case USBDEVFS_DISCSIGNAL:
snoop(&dev->dev, "%s: DISCSIGNAL\n", __func__);
ret = proc_disconnectsignal(ps, p);
@@ -2304,6 +2313,8 @@ static long usbdev_do_ioctl(struct file *file, unsigned int cmd,
ret = proc_free_streams(ps, p);
break;
}
+
+ done:
usb_unlock_device(dev);
if (ret >= 0)
inode->i_atime = CURRENT_TIME;
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 874dec31a111..818369afff63 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -275,21 +275,6 @@ static int usb_unbind_device(struct device *dev)
return 0;
}
-/*
- * Cancel any pending scheduled resets
- *
- * [see usb_queue_reset_device()]
- *
- * Called after unconfiguring / when releasing interfaces. See
- * comments in __usb_queue_reset_device() regarding
- * udev->reset_running.
- */
-static void usb_cancel_queued_reset(struct usb_interface *iface)
-{
- if (iface->reset_running == 0)
- cancel_work_sync(&iface->reset_ws);
-}
-
/* called from driver core with dev locked */
static int usb_probe_interface(struct device *dev)
{
@@ -380,7 +365,6 @@ static int usb_probe_interface(struct device *dev)
usb_set_intfdata(intf, NULL);
intf->needs_remote_wakeup = 0;
intf->condition = USB_INTERFACE_UNBOUND;
- usb_cancel_queued_reset(intf);
/* If the LPM disable succeeded, balance the ref counts. */
if (!lpm_disable_error)
@@ -425,7 +409,6 @@ static int usb_unbind_interface(struct device *dev)
usb_disable_interface(udev, intf, false);
driver->disconnect(intf);
- usb_cancel_queued_reset(intf);
/* Free streams */
for (i = 0, j = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
@@ -1797,6 +1780,18 @@ static int autosuspend_check(struct usb_device *udev)
dev_dbg(&udev->dev, "remote wakeup needed for autosuspend\n");
return -EOPNOTSUPP;
}
+
+ /*
+ * If the device is a direct child of the root hub and the HCD
+ * doesn't handle wakeup requests, don't allow autosuspend when
+ * wakeup is needed.
+ */
+ if (w && udev->parent == udev->bus->root_hub &&
+ bus_to_hcd(udev->bus)->cant_recv_wakeups) {
+ dev_dbg(&udev->dev, "HCD doesn't handle wakeup requests\n");
+ return -EOPNOTSUPP;
+ }
+
udev->do_remote_wakeup = w;
return 0;
}
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index 11cee55ae397..45a915ccd71c 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -1618,6 +1618,7 @@ static int unlink1(struct usb_hcd *hcd, struct urb *urb, int status)
int usb_hcd_unlink_urb (struct urb *urb, int status)
{
struct usb_hcd *hcd;
+ struct usb_device *udev = urb->dev;
int retval = -EIDRM;
unsigned long flags;
@@ -1629,20 +1630,19 @@ int usb_hcd_unlink_urb (struct urb *urb, int status)
spin_lock_irqsave(&hcd_urb_unlink_lock, flags);
if (atomic_read(&urb->use_count) > 0) {
retval = 0;
- usb_get_dev(urb->dev);
+ usb_get_dev(udev);
}
spin_unlock_irqrestore(&hcd_urb_unlink_lock, flags);
if (retval == 0) {
hcd = bus_to_hcd(urb->dev->bus);
retval = unlink1(hcd, urb, status);
- usb_put_dev(urb->dev);
+ if (retval == 0)
+ retval = -EINPROGRESS;
+ else if (retval != -EIDRM && retval != -EBUSY)
+ dev_dbg(&udev->dev, "hcd_unlink_urb %p fail %d\n",
+ urb, retval);
+ usb_put_dev(udev);
}
-
- if (retval == 0)
- retval = -EINPROGRESS;
- else if (retval != -EIDRM && retval != -EBUSY)
- dev_dbg(&urb->dev->dev, "hcd_unlink_urb %p fail %d\n",
- urb, retval);
return retval;
}
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index aeb50bb6ba9c..d7c3d5a35946 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -2896,10 +2896,12 @@ static int port_is_suspended(struct usb_hub *hub, unsigned portstatus)
*/
static int check_port_resume_type(struct usb_device *udev,
struct usb_hub *hub, int port1,
- int status, unsigned portchange, unsigned portstatus)
+ int status, u16 portchange, u16 portstatus)
{
struct usb_port *port_dev = hub->ports[port1 - 1];
+ int retries = 3;
+ retry:
/* Is a warm reset needed to recover the connection? */
if (status == 0 && udev->reset_resume
&& hub_port_warm_reset_required(hub, port1, portstatus)) {
@@ -2907,10 +2909,17 @@ static int check_port_resume_type(struct usb_device *udev,
}
/* Is the device still present? */
else if (status || port_is_suspended(hub, portstatus) ||
- !port_is_power_on(hub, portstatus) ||
- !(portstatus & USB_PORT_STAT_CONNECTION)) {
+ !port_is_power_on(hub, portstatus)) {
if (status >= 0)
status = -ENODEV;
+ } else if (!(portstatus & USB_PORT_STAT_CONNECTION)) {
+ if (retries--) {
+ usleep_range(200, 300);
+ status = hub_port_status(hub, port1, &portstatus,
+ &portchange);
+ goto retry;
+ }
+ status = -ENODEV;
}
/* Can't do a normal resume if the port isn't enabled,
@@ -3452,8 +3461,6 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
-#ifdef CONFIG_PM
-
int usb_remote_wakeup(struct usb_device *udev)
{
int status = 0;
@@ -3512,16 +3519,6 @@ static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
return connect_change;
}
-#else
-
-static int hub_handle_remote_wakeup(struct usb_hub *hub, unsigned int port,
- u16 portstatus, u16 portchange)
-{
- return 0;
-}
-
-#endif
-
static int check_ports_changed(struct usb_hub *hub)
{
int port1;
@@ -4655,9 +4652,13 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus,
if (!(portstatus & USB_PORT_STAT_CONNECTION) ||
test_bit(port1, hub->removed_bits)) {
- /* maybe switch power back on (e.g. root hub was reset) */
+ /*
+ * maybe switch power back on (e.g. root hub was reset)
+ * but only if the port isn't owned by someone else.
+ */
if (hub_is_port_power_switchable(hub)
- && !port_is_power_on(hub, portstatus))
+ && !port_is_power_on(hub, portstatus)
+ && !port_dev->port_owner)
set_port_feature(hdev, port1, USB_PORT_FEAT_POWER);
if (portstatus & USB_PORT_STAT_ENABLE)
@@ -4882,7 +4883,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
static void port_event(struct usb_hub *hub, int port1)
__must_hold(&port_dev->status_lock)
{
- int connect_change, reset_device = 0;
+ int connect_change;
struct usb_port *port_dev = hub->ports[port1 - 1];
struct usb_device *udev = port_dev->child;
struct usb_device *hdev = hub->hdev;
@@ -4970,30 +4971,14 @@ static void port_event(struct usb_hub *hub, int port1)
if (hub_port_reset(hub, port1, NULL,
HUB_BH_RESET_TIME, true) < 0)
hub_port_disable(hub, port1, 1);
- } else
- reset_device = 1;
- }
-
- /*
- * On disconnect USB3 protocol ports transit from U0 to
- * SS.Inactive to Rx.Detect. If this happens a warm-
- * reset is not needed, but a (re)connect may happen
- * before hub_wq runs and sees the disconnect, and the
- * device may be an unknown state.
- *
- * If the port went through SS.Inactive without hub_wq
- * seeing it the C_LINK_STATE change flag will be set,
- * and we reset the dev to put it in a known state.
- */
- if (reset_device || (udev && hub_is_superspeed(hub->hdev)
- && (portchange & USB_PORT_STAT_C_LINK_STATE)
- && (portstatus & USB_PORT_STAT_CONNECTION))) {
- usb_unlock_port(port_dev);
- usb_lock_device(udev);
- usb_reset_device(udev);
- usb_unlock_device(udev);
- usb_lock_port(port_dev);
- connect_change = 0;
+ } else {
+ usb_unlock_port(port_dev);
+ usb_lock_device(udev);
+ usb_reset_device(udev);
+ usb_unlock_device(udev);
+ usb_lock_port(port_dev);
+ connect_change = 0;
+ }
}
if (connect_change)
@@ -5589,26 +5574,19 @@ EXPORT_SYMBOL_GPL(usb_reset_device);
* possible; depending on how the driver attached to each interface
* handles ->pre_reset(), the second reset might happen or not.
*
- * - If a driver is unbound and it had a pending reset, the reset will
- * be cancelled.
- *
- * - This function can be called during .probe() or .disconnect()
- * times. On return from .disconnect(), any pending resets will be
- * cancelled.
- *
- * There is no no need to lock/unlock the @reset_ws as schedule_work()
- * does its own.
+ * - If the reset is delayed so long that the interface is unbound from
+ * its driver, the reset will be skipped.
*
- * NOTE: We don't do any reference count tracking because it is not
- * needed. The lifecycle of the work_struct is tied to the
- * usb_interface. Before destroying the interface we cancel the
- * work_struct, so the fact that work_struct is queued and or
- * running means the interface (and thus, the device) exist and
- * are referenced.
+ * - This function can be called during .probe(). It can also be called
+ * during .disconnect(), but doing so is pointless because the reset
+ * will not occur. If you really want to reset the device during
+ * .disconnect(), call usb_reset_device() directly -- but watch out
+ * for nested unbinding issues!
*/
void usb_queue_reset_device(struct usb_interface *iface)
{
- schedule_work(&iface->reset_ws);
+ if (schedule_work(&iface->reset_ws))
+ usb_get_intf(iface);
}
EXPORT_SYMBOL_GPL(usb_queue_reset_device);
diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c
index f7b7713cfb2a..f368d2053da5 100644
--- a/drivers/usb/core/message.c
+++ b/drivers/usb/core/message.c
@@ -1551,6 +1551,7 @@ static void usb_release_interface(struct device *dev)
altsetting_to_usb_interface_cache(intf->altsetting);
kref_put(&intfc->ref, usb_release_interface_cache);
+ usb_put_dev(interface_to_usbdev(intf));
kfree(intf);
}
@@ -1626,24 +1627,6 @@ static struct usb_interface_assoc_descriptor *find_iad(struct usb_device *dev,
/*
* Internal function to queue a device reset
- *
- * This is initialized into the workstruct in 'struct
- * usb_device->reset_ws' that is launched by
- * message.c:usb_set_configuration() when initializing each 'struct
- * usb_interface'.
- *
- * It is safe to get the USB device without reference counts because
- * the life cycle of @iface is bound to the life cycle of @udev. Then,
- * this function will be ran only if @iface is alive (and before
- * freeing it any scheduled instances of it will have been cancelled).
- *
- * We need to set a flag (usb_dev->reset_running) because when we call
- * the reset, the interfaces might be unbound. The current interface
- * cannot try to remove the queued work as it would cause a deadlock
- * (you cannot remove your work from within your executing
- * workqueue). This flag lets it know, so that
- * usb_cancel_queued_reset() doesn't try to do it.
- *
* See usb_queue_reset_device() for more details
*/
static void __usb_queue_reset_device(struct work_struct *ws)
@@ -1655,11 +1638,10 @@ static void __usb_queue_reset_device(struct work_struct *ws)
rc = usb_lock_device_for_reset(udev, iface);
if (rc >= 0) {
- iface->reset_running = 1;
usb_reset_device(udev);
- iface->reset_running = 0;
usb_unlock_device(udev);
}
+ usb_put_intf(iface); /* Undo _get_ in usb_queue_reset_device() */
}
@@ -1854,6 +1836,7 @@ free_interfaces:
dev_set_name(&intf->dev, "%d-%s:%d.%d",
dev->bus->busnum, dev->devpath,
configuration, alt->desc.bInterfaceNumber);
+ usb_get_dev(dev);
}
kfree(new_interfaces);
diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h
index de0c9c9d7091..a6315abe7b7c 100644
--- a/drivers/usb/core/otg_whitelist.h
+++ b/drivers/usb/core/otg_whitelist.h
@@ -55,6 +55,11 @@ static int is_targeted(struct usb_device *dev)
le16_to_cpu(dev->descriptor.idProduct) == 0xbadd))
return 0;
+ /* OTG PET device is always targeted (see OTG 2.0 ECN 6.4.2) */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1a0a &&
+ le16_to_cpu(dev->descriptor.idProduct) == 0x0200))
+ return 1;
+
/* NOTE: can't use usb_match_id() since interface caches
* aren't set up yet. this is cut/paste from that code.
*/
diff --git a/drivers/usb/core/quirks.c b/drivers/usb/core/quirks.c
index 0ffb4ed0a945..41e510ae8c83 100644
--- a/drivers/usb/core/quirks.c
+++ b/drivers/usb/core/quirks.c
@@ -179,6 +179,10 @@ static const struct usb_device_id usb_quirk_list[] = {
{ USB_DEVICE(0x0b05, 0x17e0), .driver_info =
USB_QUIRK_IGNORE_REMOTE_WAKEUP },
+ /* Protocol and OTG Electrical Test Device */
+ { USB_DEVICE(0x1a0a, 0x0200), .driver_info =
+ USB_QUIRK_LINEAR_UFRAME_INTR_BINTERVAL },
+
{ } /* terminating entry must be last */
};
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2a92b97f0144..b1fb9aef0f5b 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -1049,6 +1049,7 @@ static int __init usb_init(void)
pr_info("%s: USB support disabled\n", usbcore_name);
return 0;
}
+ usb_init_pool_max();
retval = usb_debugfs_init();
if (retval)
diff --git a/drivers/usb/dwc2/Kconfig b/drivers/usb/dwc2/Kconfig
index b323c4c11b0a..76b9ba4dc925 100644
--- a/drivers/usb/dwc2/Kconfig
+++ b/drivers/usb/dwc2/Kconfig
@@ -23,7 +23,7 @@ choice
config USB_DWC2_HOST
bool "Host only mode"
- depends on USB
+ depends on USB=y || (USB_DWC2=m && USB)
help
The Designware USB2.0 high-speed host controller
integrated into many SoCs. Select this option if you want the
@@ -42,7 +42,7 @@ config USB_DWC2_PERIPHERAL
config USB_DWC2_DUAL_ROLE
bool "Dual Role mode"
- depends on (USB=y || USB=USB_DWC2) && (USB_GADGET=y || USB_GADGET=USB_DWC2)
+ depends on (USB=y && USB_GADGET=y) || (USB_DWC2=m && USB && USB_GADGET)
help
Select this option if you want the driver to work in a dual-role
mode. In this mode both host and gadget features are enabled, and
diff --git a/drivers/usb/dwc2/core.c b/drivers/usb/dwc2/core.c
index 7605850b7a9c..d5197d492e21 100644
--- a/drivers/usb/dwc2/core.c
+++ b/drivers/usb/dwc2/core.c
@@ -462,7 +462,7 @@ int dwc2_core_init(struct dwc2_hsotg *hsotg, bool select_phy, int irq)
dwc2_enable_common_interrupts(hsotg);
/*
- * Do device or host intialization based on mode during PCD and
+ * Do device or host initialization based on mode during PCD and
* HCD initialization
*/
if (dwc2_is_host_mode(hsotg)) {
diff --git a/drivers/usb/dwc2/core.h b/drivers/usb/dwc2/core.h
index 7a70a1349334..f74304b12652 100644
--- a/drivers/usb/dwc2/core.h
+++ b/drivers/usb/dwc2/core.h
@@ -108,7 +108,7 @@ struct s3c_hsotg_req;
* @halted: Set if the endpoint has been halted.
* @periodic: Set if this is a periodic ep, such as Interrupt
* @isochronous: Set if this is a isochronous ep
- * @sent_zlp: Set if we've sent a zero-length packet.
+ * @send_zlp: Set if we need to send a zero-length packet.
* @total_data: The total number of data bytes done.
* @fifo_size: The size of the FIFO (for periodic IN endpoints)
* @fifo_load: The amount of data loaded into the FIFO (periodic IN)
@@ -149,7 +149,7 @@ struct s3c_hsotg_ep {
unsigned int halted:1;
unsigned int periodic:1;
unsigned int isochronous:1;
- unsigned int sent_zlp:1;
+ unsigned int send_zlp:1;
char name[10];
};
@@ -158,14 +158,12 @@ struct s3c_hsotg_ep {
* struct s3c_hsotg_req - data transfer request
* @req: The USB gadget request
* @queue: The list of requests for the endpoint this is queued for.
- * @in_progress: Has already had size/packets written to core
- * @mapped: DMA buffer for this request has been mapped via dma_map_single().
+ * @saved_req_buf: variable to save req.buf when bounce buffers are used.
*/
struct s3c_hsotg_req {
struct usb_request req;
struct list_head queue;
- unsigned char in_progress;
- unsigned char mapped;
+ void *saved_req_buf;
};
#if IS_ENABLED(CONFIG_USB_DWC2_PERIPHERAL) || IS_ENABLED(CONFIG_USB_DWC2_DUAL_ROLE)
@@ -193,6 +191,22 @@ enum dwc2_lx_state {
DWC2_L3, /* Off state */
};
+/*
+ * Gadget periodic tx fifo sizes as used by legacy driver
+ * EP0 is not included
+ */
+#define DWC2_G_P_LEGACY_TX_FIFO_SIZE {256, 256, 256, 256, 768, 768, 768, \
+ 768, 0, 0, 0, 0, 0, 0, 0}
+
+/* Gadget ep0 states */
+enum dwc2_ep0_state {
+ DWC2_EP0_SETUP,
+ DWC2_EP0_DATA_IN,
+ DWC2_EP0_DATA_OUT,
+ DWC2_EP0_STATUS_IN,
+ DWC2_EP0_STATUS_OUT,
+};
+
/**
* struct dwc2_core_params - Parameters for configuring the core
*
@@ -381,7 +395,7 @@ struct dwc2_core_params {
* @power_optimized Are power optimizations enabled?
* @num_dev_ep Number of device endpoints available
* @num_dev_perio_in_ep Number of device periodic IN endpoints
- * avaialable
+ * available
* @dev_token_q_depth Device Mode IN Token Sequence Learning Queue
* Depth
* 0 to 30
@@ -434,6 +448,9 @@ struct dwc2_hw_params {
u32 snpsid;
};
+/* Size of control and EP0 buffers */
+#define DWC2_CTRL_BUFF_SIZE 8
+
/**
* struct dwc2_hsotg - Holds the state of the driver, including the non-periodic
* and periodic schedules
@@ -552,14 +569,20 @@ struct dwc2_hw_params {
* @num_of_eps: Number of available EPs (excluding EP0)
* @debug_root: Root directrory for debugfs.
* @debug_file: Main status file for debugfs.
+ * @debug_testmode: Testmode status file for debugfs.
* @debug_fifo: FIFO status file for debugfs.
* @ep0_reply: Request used for ep0 reply.
* @ep0_buff: Buffer for EP0 reply data, if needed.
* @ctrl_buff: Buffer for EP0 control requests.
* @ctrl_req: Request for EP0 control packets.
- * @setup: NAK management for EP0 SETUP
+ * @ep0_state: EP0 control transfers state
+ * @test_mode: USB test mode requested by the host
* @last_rst: Time of last reset
* @eps: The endpoints being supplied to the gadget framework
+ * @g_using_dma: Indicate if dma usage is enabled
+ * @g_rx_fifo_sz: Contains rx fifo size value
+ * @g_np_g_tx_fifo_sz: Contains Non-Periodic tx fifo size value
+ * @g_tx_fifo_sz: Contains tx fifo size value per endpoints
*/
struct dwc2_hsotg {
struct device *dev;
@@ -591,6 +614,7 @@ struct dwc2_hsotg {
struct dentry *debug_root;
struct dentry *debug_file;
+ struct dentry *debug_testmode;
struct dentry *debug_fifo;
/* DWC OTG HW Release versions */
@@ -684,15 +708,21 @@ struct dwc2_hsotg {
struct usb_request *ep0_reply;
struct usb_request *ctrl_req;
- u8 ep0_buff[8];
- u8 ctrl_buff[8];
+ void *ep0_buff;
+ void *ctrl_buff;
+ enum dwc2_ep0_state ep0_state;
+ u8 test_mode;
struct usb_gadget gadget;
unsigned int enabled:1;
unsigned int connected:1;
- unsigned int setup:1;
unsigned long last_rst;
- struct s3c_hsotg_ep *eps;
+ struct s3c_hsotg_ep *eps_in[MAX_EPS_CHANNELS];
+ struct s3c_hsotg_ep *eps_out[MAX_EPS_CHANNELS];
+ u32 g_using_dma;
+ u32 g_rx_fifo_sz;
+ u32 g_np_g_tx_fifo_sz;
+ u32 g_tx_fifo_sz[MAX_EPS_CHANNELS];
#endif /* CONFIG_USB_DWC2_PERIPHERAL || CONFIG_USB_DWC2_DUAL_ROLE */
};
@@ -969,7 +999,8 @@ extern int s3c_hsotg_remove(struct dwc2_hsotg *hsotg);
extern int s3c_hsotg_suspend(struct dwc2_hsotg *dwc2);
extern int s3c_hsotg_resume(struct dwc2_hsotg *dwc2);
extern int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq);
-extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2);
+extern void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
+ bool reset);
extern void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg);
extern void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2);
#else
@@ -981,7 +1012,8 @@ static inline int s3c_hsotg_resume(struct dwc2_hsotg *dwc2)
{ return 0; }
static inline int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
{ return 0; }
-static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2) {}
+static inline void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *dwc2,
+ bool reset) {}
static inline void s3c_hsotg_core_connect(struct dwc2_hsotg *hsotg) {}
static inline void s3c_hsotg_disconnect(struct dwc2_hsotg *dwc2) {}
#endif
diff --git a/drivers/usb/dwc2/core_intr.c b/drivers/usb/dwc2/core_intr.c
index ad43c5bc1ef1..02e3e2d4ea56 100644
--- a/drivers/usb/dwc2/core_intr.c
+++ b/drivers/usb/dwc2/core_intr.c
@@ -476,13 +476,13 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
u32 gintsts;
irqreturn_t retval = IRQ_NONE;
+ spin_lock(&hsotg->lock);
+
if (!dwc2_is_controller_alive(hsotg)) {
dev_warn(hsotg->dev, "Controller is dead\n");
goto out;
}
- spin_lock(&hsotg->lock);
-
gintsts = dwc2_read_common_intr(hsotg);
if (gintsts & ~GINTSTS_PRTINT)
retval = IRQ_HANDLED;
@@ -515,8 +515,8 @@ irqreturn_t dwc2_handle_common_intr(int irq, void *dev)
}
}
- spin_unlock(&hsotg->lock);
out:
+ spin_unlock(&hsotg->lock);
return retval;
}
EXPORT_SYMBOL_GPL(dwc2_handle_common_intr);
diff --git a/drivers/usb/dwc2/gadget.c b/drivers/usb/dwc2/gadget.c
index 79242008085b..6a30887082cd 100644
--- a/drivers/usb/dwc2/gadget.c
+++ b/drivers/usb/dwc2/gadget.c
@@ -35,6 +35,7 @@
#include <linux/usb/gadget.h>
#include <linux/usb/phy.h>
#include <linux/platform_data/s3c-hsotg.h>
+#include <linux/uaccess.h>
#include "core.h"
#include "hw.h"
@@ -65,7 +66,16 @@ static inline void __bic32(void __iomem *ptr, u32 val)
writel(readl(ptr) & ~val, ptr);
}
-/* forward decleration of functions */
+static inline struct s3c_hsotg_ep *index_to_ep(struct dwc2_hsotg *hsotg,
+ u32 ep_index, u32 dir_in)
+{
+ if (dir_in)
+ return hsotg->eps_in[ep_index];
+ else
+ return hsotg->eps_out[ep_index];
+}
+
+/* forward declaration of functions */
static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg);
/**
@@ -85,11 +95,11 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg);
* a core reset. This means we either need to fix the gadgets to take
* account of DMA alignment, or add bounce buffers (yuerk).
*
- * Until this issue is sorted out, we always return 'false'.
+ * g_using_dma is set depending on dts flag.
*/
static inline bool using_dma(struct dwc2_hsotg *hsotg)
{
- return false; /* support is not complete */
+ return hsotg->g_using_dma;
}
/**
@@ -165,15 +175,18 @@ static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
{
unsigned int ep;
unsigned int addr;
- unsigned int size;
int timeout;
u32 val;
- /* set FIFO sizes to 2048/1024 */
+ /* Reset fifo map if not correctly cleared during previous session */
+ WARN_ON(hsotg->fifo_map);
+ hsotg->fifo_map = 0;
- writel(2048, hsotg->regs + GRXFSIZ);
- writel((2048 << FIFOSIZE_STARTADDR_SHIFT) |
- (1024 << FIFOSIZE_DEPTH_SHIFT), hsotg->regs + GNPTXFSIZ);
+ /* set RX/NPTX FIFO sizes */
+ writel(hsotg->g_rx_fifo_sz, hsotg->regs + GRXFSIZ);
+ writel((hsotg->g_rx_fifo_sz << FIFOSIZE_STARTADDR_SHIFT) |
+ (hsotg->g_np_g_tx_fifo_sz << FIFOSIZE_DEPTH_SHIFT),
+ hsotg->regs + GNPTXFSIZ);
/*
* arange all the rest of the TX FIFOs, as some versions of this
@@ -183,35 +196,21 @@ static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
*/
/* start at the end of the GNPTXFSIZ, rounded up */
- addr = 2048 + 1024;
+ addr = hsotg->g_rx_fifo_sz + hsotg->g_np_g_tx_fifo_sz;
/*
- * Because we have not enough memory to have each TX FIFO of size at
- * least 3072 bytes (the maximum single packet size), we create four
- * FIFOs of lenght 1024, and four of length 3072 bytes, and assing
+ * Configure fifos sizes from provided configuration and assign
* them to endpoints dynamically according to maxpacket size value of
* given endpoint.
*/
-
- /* 256*4=1024 bytes FIFO length */
- size = 256;
- for (ep = 1; ep <= 4; ep++) {
- val = addr;
- val |= size << FIFOSIZE_DEPTH_SHIFT;
- WARN_ONCE(addr + size > hsotg->fifo_mem,
- "insufficient fifo memory");
- addr += size;
-
- writel(val, hsotg->regs + DPTXFSIZN(ep));
- }
- /* 768*4=3072 bytes FIFO length */
- size = 768;
- for (ep = 5; ep <= 8; ep++) {
+ for (ep = 1; ep < MAX_EPS_CHANNELS; ep++) {
+ if (!hsotg->g_tx_fifo_sz[ep])
+ continue;
val = addr;
- val |= size << FIFOSIZE_DEPTH_SHIFT;
- WARN_ONCE(addr + size > hsotg->fifo_mem,
+ val |= hsotg->g_tx_fifo_sz[ep] << FIFOSIZE_DEPTH_SHIFT;
+ WARN_ONCE(addr + hsotg->g_tx_fifo_sz[ep] > hsotg->fifo_mem,
"insufficient fifo memory");
- addr += size;
+ addr += hsotg->g_tx_fifo_sz[ep];
writel(val, hsotg->regs + DPTXFSIZN(ep));
}
@@ -236,6 +235,7 @@ static void s3c_hsotg_init_fifo(struct dwc2_hsotg *hsotg)
dev_err(hsotg->dev,
"%s: timeout flushing fifos (GRSTCTL=%08x)\n",
__func__, val);
+ break;
}
udelay(1);
@@ -566,11 +566,6 @@ static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
length = ureq->length - ureq->actual;
dev_dbg(hsotg->dev, "ureq->length:%d ureq->actual:%d\n",
ureq->length, ureq->actual);
- if (0)
- dev_dbg(hsotg->dev,
- "REQ buf %p len %d dma %pad noi=%d zp=%d snok=%d\n",
- ureq->buf, length, &ureq->dma,
- ureq->no_interrupt, ureq->zero, ureq->short_not_ok);
maxreq = get_ep_limit(hs_ep);
if (length > maxreq) {
@@ -604,14 +599,15 @@ static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
else
epsize = 0;
- if (index != 0 && ureq->zero) {
- /*
- * test for the packets being exactly right for the
- * transfer
- */
-
- if (length == (packets * hs_ep->ep.maxpacket))
- packets++;
+ /*
+ * zero length packet should be programmed on its own and should not
+ * be counted in DIEPTSIZ.PktCnt with other packets.
+ */
+ if (dir_in && ureq->zero && !continuing) {
+ /* Test if zlp is actually required. */
+ if ((ureq->length >= hs_ep->ep.maxpacket) &&
+ !(ureq->length % hs_ep->ep.maxpacket))
+ hs_ep->send_zlp = 1;
}
epsize |= DXEPTSIZ_PKTCNT(packets);
@@ -644,15 +640,12 @@ static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
ctrl |= DXEPCTL_USBACTEP;
- dev_dbg(hsotg->dev, "setup req:%d\n", hsotg->setup);
+ dev_dbg(hsotg->dev, "ep0 state:%d\n", hsotg->ep0_state);
/* For Setup request do not clear NAK */
- if (hsotg->setup && index == 0)
- hsotg->setup = 0;
- else
+ if (!(index == 0 && hsotg->ep0_state == DWC2_EP0_SETUP))
ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */
-
dev_dbg(hsotg->dev, "%s: DxEPCTL=0x%08x\n", __func__, ctrl);
writel(ctrl, hsotg->regs + epctrl_reg);
@@ -686,7 +679,7 @@ static void s3c_hsotg_start_req(struct dwc2_hsotg *hsotg,
/* check ep is enabled */
if (!(readl(hsotg->regs + epctrl_reg) & DXEPCTL_EPENA))
- dev_warn(hsotg->dev,
+ dev_dbg(hsotg->dev,
"ep%d: failed to become enabled (DXEPCTL=0x%08x)?\n",
index, readl(hsotg->regs + epctrl_reg));
@@ -733,6 +726,59 @@ dma_error:
return -EIO;
}
+static int s3c_hsotg_handle_unaligned_buf_start(struct dwc2_hsotg *hsotg,
+ struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req)
+{
+ void *req_buf = hs_req->req.buf;
+
+ /* If dma is not being used or buffer is aligned */
+ if (!using_dma(hsotg) || !((long)req_buf & 3))
+ return 0;
+
+ WARN_ON(hs_req->saved_req_buf);
+
+ dev_dbg(hsotg->dev, "%s: %s: buf=%p length=%d\n", __func__,
+ hs_ep->ep.name, req_buf, hs_req->req.length);
+
+ hs_req->req.buf = kmalloc(hs_req->req.length, GFP_ATOMIC);
+ if (!hs_req->req.buf) {
+ hs_req->req.buf = req_buf;
+ dev_err(hsotg->dev,
+ "%s: unable to allocate memory for bounce buffer\n",
+ __func__);
+ return -ENOMEM;
+ }
+
+ /* Save actual buffer */
+ hs_req->saved_req_buf = req_buf;
+
+ if (hs_ep->dir_in)
+ memcpy(hs_req->req.buf, req_buf, hs_req->req.length);
+ return 0;
+}
+
+static void s3c_hsotg_handle_unaligned_buf_complete(struct dwc2_hsotg *hsotg,
+ struct s3c_hsotg_ep *hs_ep, struct s3c_hsotg_req *hs_req)
+{
+ /* If dma is not being used or buffer was aligned */
+ if (!using_dma(hsotg) || !hs_req->saved_req_buf)
+ return;
+
+ dev_dbg(hsotg->dev, "%s: %s: status=%d actual-length=%d\n", __func__,
+ hs_ep->ep.name, hs_req->req.status, hs_req->req.actual);
+
+ /* Copy data from bounce buffer on successful out transfer */
+ if (!hs_ep->dir_in && !hs_req->req.status)
+ memcpy(hs_req->saved_req_buf, hs_req->req.buf,
+ hs_req->req.actual);
+
+ /* Free bounce buffer */
+ kfree(hs_req->req.buf);
+
+ hs_req->req.buf = hs_req->saved_req_buf;
+ hs_req->saved_req_buf = NULL;
+}
+
static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
gfp_t gfp_flags)
{
@@ -740,6 +786,7 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hs = hs_ep->parent;
bool first;
+ int ret;
dev_dbg(hs->dev, "%s: req %p: %d@%p, noi=%d, zero=%d, snok=%d\n",
ep->name, req, req->length, req->buf, req->no_interrupt,
@@ -750,9 +797,13 @@ static int s3c_hsotg_ep_queue(struct usb_ep *ep, struct usb_request *req,
req->actual = 0;
req->status = -EINPROGRESS;
+ ret = s3c_hsotg_handle_unaligned_buf_start(hs, hs_ep, hs_req);
+ if (ret)
+ return ret;
+
/* if we're using DMA, sync the buffers as necessary */
if (using_dma(hs)) {
- int ret = s3c_hsotg_map_dma(hs, hs_ep, req);
+ ret = s3c_hsotg_map_dma(hs, hs_ep, req);
if (ret)
return ret;
}
@@ -819,7 +870,7 @@ static void s3c_hsotg_complete_oursetup(struct usb_ep *ep,
static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
u32 windex)
{
- struct s3c_hsotg_ep *ep = &hsotg->eps[windex & 0x7F];
+ struct s3c_hsotg_ep *ep;
int dir = (windex & USB_DIR_IN) ? 1 : 0;
int idx = windex & 0x7F;
@@ -829,6 +880,8 @@ static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
if (idx > hsotg->num_of_eps)
return NULL;
+ ep = index_to_ep(hsotg, idx, dir);
+
if (idx && ep->dir_in != dir)
return NULL;
@@ -836,6 +889,32 @@ static struct s3c_hsotg_ep *ep_from_windex(struct dwc2_hsotg *hsotg,
}
/**
+ * s3c_hsotg_set_test_mode - Enable usb Test Modes
+ * @hsotg: The driver state.
+ * @testmode: requested usb test mode
+ * Enable usb Test Mode requested by the Host.
+ */
+static int s3c_hsotg_set_test_mode(struct dwc2_hsotg *hsotg, int testmode)
+{
+ int dctl = readl(hsotg->regs + DCTL);
+
+ dctl &= ~DCTL_TSTCTL_MASK;
+ switch (testmode) {
+ case TEST_J:
+ case TEST_K:
+ case TEST_SE0_NAK:
+ case TEST_PACKET:
+ case TEST_FORCE_EN:
+ dctl |= testmode << DCTL_TSTCTL_SHIFT;
+ break;
+ default:
+ return -EINVAL;
+ }
+ writel(dctl, hsotg->regs + DCTL);
+ return 0;
+}
+
+/**
* s3c_hsotg_send_reply - send reply to control request
* @hsotg: The device state
* @ep: Endpoint 0
@@ -864,13 +943,15 @@ static int s3c_hsotg_send_reply(struct dwc2_hsotg *hsotg,
req->buf = hsotg->ep0_buff;
req->length = length;
- req->zero = 1; /* always do zero-length final transfer */
+ /*
+ * zero flag is for sending zlp in DATA IN stage. It has no impact on
+ * STATUS stage.
+ */
+ req->zero = 0;
req->complete = s3c_hsotg_complete_oursetup;
if (length)
memcpy(req->buf, buff, length);
- else
- ep->sent_zlp = 1;
ret = s3c_hsotg_ep_queue(&ep->ep, req, GFP_ATOMIC);
if (ret) {
@@ -889,7 +970,7 @@ static int s3c_hsotg_send_reply(struct dwc2_hsotg *hsotg,
static int s3c_hsotg_process_req_status(struct dwc2_hsotg *hsotg,
struct usb_ctrlrequest *ctrl)
{
- struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+ struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
struct s3c_hsotg_ep *ep;
__le16 reply;
int ret;
@@ -953,33 +1034,62 @@ static struct s3c_hsotg_req *get_ep_head(struct s3c_hsotg_ep *hs_ep)
}
/**
- * s3c_hsotg_process_req_featire - process request {SET,CLEAR}_FEATURE
+ * s3c_hsotg_process_req_feature - process request {SET,CLEAR}_FEATURE
* @hsotg: The device state
* @ctrl: USB control request
*/
static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
struct usb_ctrlrequest *ctrl)
{
- struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+ struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
struct s3c_hsotg_req *hs_req;
bool restart;
bool set = (ctrl->bRequest == USB_REQ_SET_FEATURE);
struct s3c_hsotg_ep *ep;
int ret;
bool halted;
+ u32 recip;
+ u32 wValue;
+ u32 wIndex;
dev_dbg(hsotg->dev, "%s: %s_FEATURE\n",
__func__, set ? "SET" : "CLEAR");
- if (ctrl->bRequestType == USB_RECIP_ENDPOINT) {
- ep = ep_from_windex(hsotg, le16_to_cpu(ctrl->wIndex));
+ wValue = le16_to_cpu(ctrl->wValue);
+ wIndex = le16_to_cpu(ctrl->wIndex);
+ recip = ctrl->bRequestType & USB_RECIP_MASK;
+
+ switch (recip) {
+ case USB_RECIP_DEVICE:
+ switch (wValue) {
+ case USB_DEVICE_TEST_MODE:
+ if ((wIndex & 0xff) != 0)
+ return -EINVAL;
+ if (!set)
+ return -EINVAL;
+
+ hsotg->test_mode = wIndex >> 8;
+ ret = s3c_hsotg_send_reply(hsotg, ep0, NULL, 0);
+ if (ret) {
+ dev_err(hsotg->dev,
+ "%s: failed to send reply\n", __func__);
+ return ret;
+ }
+ break;
+ default:
+ return -ENOENT;
+ }
+ break;
+
+ case USB_RECIP_ENDPOINT:
+ ep = ep_from_windex(hsotg, wIndex);
if (!ep) {
dev_dbg(hsotg->dev, "%s: no endpoint for 0x%04x\n",
- __func__, le16_to_cpu(ctrl->wIndex));
+ __func__, wIndex);
return -ENOENT;
}
- switch (le16_to_cpu(ctrl->wValue)) {
+ switch (wValue) {
case USB_ENDPOINT_HALT:
halted = ep->halted;
@@ -1006,16 +1116,22 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
hs_req = ep->req;
ep->req = NULL;
list_del_init(&hs_req->queue);
- usb_gadget_giveback_request(&ep->ep,
- &hs_req->req);
+ if (hs_req->req.complete) {
+ spin_unlock(&hsotg->lock);
+ usb_gadget_giveback_request(
+ &ep->ep, &hs_req->req);
+ spin_lock(&hsotg->lock);
+ }
}
/* If we have pending request, then start it */
- restart = !list_empty(&ep->queue);
- if (restart) {
- hs_req = get_ep_head(ep);
- s3c_hsotg_start_req(hsotg, ep,
- hs_req, false);
+ if (!ep->req) {
+ restart = !list_empty(&ep->queue);
+ if (restart) {
+ hs_req = get_ep_head(ep);
+ s3c_hsotg_start_req(hsotg, ep,
+ hs_req, false);
+ }
}
}
@@ -1024,9 +1140,10 @@ static int s3c_hsotg_process_req_feature(struct dwc2_hsotg *hsotg,
default:
return -ENOENT;
}
- } else
- return -ENOENT; /* currently only deal with endpoint */
-
+ break;
+ default:
+ return -ENOENT;
+ }
return 1;
}
@@ -1040,7 +1157,7 @@ static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg);
*/
static void s3c_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
{
- struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+ struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
u32 reg;
u32 ctrl;
@@ -1080,34 +1197,29 @@ static void s3c_hsotg_stall_ep0(struct dwc2_hsotg *hsotg)
static void s3c_hsotg_process_control(struct dwc2_hsotg *hsotg,
struct usb_ctrlrequest *ctrl)
{
- struct s3c_hsotg_ep *ep0 = &hsotg->eps[0];
+ struct s3c_hsotg_ep *ep0 = hsotg->eps_out[0];
int ret = 0;
u32 dcfg;
- ep0->sent_zlp = 0;
-
dev_dbg(hsotg->dev, "ctrl Req=%02x, Type=%02x, V=%04x, L=%04x\n",
ctrl->bRequest, ctrl->bRequestType,
ctrl->wValue, ctrl->wLength);
- /*
- * record the direction of the request, for later use when enquing
- * packets onto EP0.
- */
-
- ep0->dir_in = (ctrl->bRequestType & USB_DIR_IN) ? 1 : 0;
- dev_dbg(hsotg->dev, "ctrl: dir_in=%d\n", ep0->dir_in);
-
- /*
- * if we've no data with this request, then the last part of the
- * transaction is going to implicitly be IN.
- */
- if (ctrl->wLength == 0)
+ if (ctrl->wLength == 0) {
ep0->dir_in = 1;
+ hsotg->ep0_state = DWC2_EP0_STATUS_IN;
+ } else if (ctrl->bRequestType & USB_DIR_IN) {
+ ep0->dir_in = 1;
+ hsotg->ep0_state = DWC2_EP0_DATA_IN;
+ } else {
+ ep0->dir_in = 0;
+ hsotg->ep0_state = DWC2_EP0_DATA_OUT;
+ }
if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD) {
switch (ctrl->bRequest) {
case USB_REQ_SET_ADDRESS:
+ hsotg->connected = 1;
dcfg = readl(hsotg->regs + DCFG);
dcfg &= ~DCFG_DEVADDR_MASK;
dcfg |= (le16_to_cpu(ctrl->wValue) <<
@@ -1201,9 +1313,11 @@ static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg)
return;
}
- hsotg->eps[0].dir_in = 0;
+ hsotg->eps_out[0]->dir_in = 0;
+ hsotg->eps_out[0]->send_zlp = 0;
+ hsotg->ep0_state = DWC2_EP0_SETUP;
- ret = s3c_hsotg_ep_queue(&hsotg->eps[0].ep, req, GFP_ATOMIC);
+ ret = s3c_hsotg_ep_queue(&hsotg->eps_out[0]->ep, req, GFP_ATOMIC);
if (ret < 0) {
dev_err(hsotg->dev, "%s: failed queue (%d)\n", __func__, ret);
/*
@@ -1213,6 +1327,32 @@ static void s3c_hsotg_enqueue_setup(struct dwc2_hsotg *hsotg)
}
}
+static void s3c_hsotg_program_zlp(struct dwc2_hsotg *hsotg,
+ struct s3c_hsotg_ep *hs_ep)
+{
+ u32 ctrl;
+ u8 index = hs_ep->index;
+ u32 epctl_reg = hs_ep->dir_in ? DIEPCTL(index) : DOEPCTL(index);
+ u32 epsiz_reg = hs_ep->dir_in ? DIEPTSIZ(index) : DOEPTSIZ(index);
+
+ if (hs_ep->dir_in)
+ dev_dbg(hsotg->dev, "Sending zero-length packet on ep%d\n",
+ index);
+ else
+ dev_dbg(hsotg->dev, "Receiving zero-length packet on ep%d\n",
+ index);
+
+ writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
+ DXEPTSIZ_XFERSIZE(0), hsotg->regs +
+ epsiz_reg);
+
+ ctrl = readl(hsotg->regs + epctl_reg);
+ ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */
+ ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
+ ctrl |= DXEPCTL_USBACTEP;
+ writel(ctrl, hsotg->regs + epctl_reg);
+}
+
/**
* s3c_hsotg_complete_request - complete a request given to us
* @hsotg: The device state.
@@ -1249,6 +1389,8 @@ static void s3c_hsotg_complete_request(struct dwc2_hsotg *hsotg,
if (hs_req->req.status == -EINPROGRESS)
hs_req->req.status = result;
+ s3c_hsotg_handle_unaligned_buf_complete(hsotg, hs_ep, hs_req);
+
hs_ep->req = NULL;
list_del_init(&hs_req->queue);
@@ -1293,7 +1435,7 @@ static void s3c_hsotg_complete_request(struct dwc2_hsotg *hsotg,
*/
static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
{
- struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep_idx];
+ struct s3c_hsotg_ep *hs_ep = hsotg->eps_out[ep_idx];
struct s3c_hsotg_req *hs_req = hs_ep->req;
void __iomem *fifo = hsotg->regs + EPFIFO(ep_idx);
int to_read;
@@ -1305,7 +1447,7 @@ static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
u32 epctl = readl(hsotg->regs + DOEPCTL(ep_idx));
int ptr;
- dev_warn(hsotg->dev,
+ dev_dbg(hsotg->dev,
"%s: FIFO %d bytes on ep%d but no req (DXEPCTl=0x%08x)\n",
__func__, size, ep_idx, epctl);
@@ -1345,9 +1487,9 @@ static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
}
/**
- * s3c_hsotg_send_zlp - send zero-length packet on control endpoint
+ * s3c_hsotg_ep0_zlp - send/receive zero-length packet on control endpoint
* @hsotg: The device instance
- * @req: The request currently on this endpoint
+ * @dir_in: If IN zlp
*
* Generate a zero-length IN packet request for terminating a SETUP
* transaction.
@@ -1356,53 +1498,28 @@ static void s3c_hsotg_rx_data(struct dwc2_hsotg *hsotg, int ep_idx, int size)
* currently believed that we do not need to wait for any space in
* the TxFIFO.
*/
-static void s3c_hsotg_send_zlp(struct dwc2_hsotg *hsotg,
- struct s3c_hsotg_req *req)
+static void s3c_hsotg_ep0_zlp(struct dwc2_hsotg *hsotg, bool dir_in)
{
- u32 ctrl;
+ /* eps_out[0] is used in both directions */
+ hsotg->eps_out[0]->dir_in = dir_in;
+ hsotg->ep0_state = dir_in ? DWC2_EP0_STATUS_IN : DWC2_EP0_STATUS_OUT;
- if (!req) {
- dev_warn(hsotg->dev, "%s: no request?\n", __func__);
- return;
- }
-
- if (req->req.length == 0) {
- hsotg->eps[0].sent_zlp = 1;
- s3c_hsotg_enqueue_setup(hsotg);
- return;
- }
-
- hsotg->eps[0].dir_in = 1;
- hsotg->eps[0].sent_zlp = 1;
-
- dev_dbg(hsotg->dev, "sending zero-length packet\n");
-
- /* issue a zero-sized packet to terminate this */
- writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
- DXEPTSIZ_XFERSIZE(0), hsotg->regs + DIEPTSIZ(0));
-
- ctrl = readl(hsotg->regs + DIEPCTL0);
- ctrl |= DXEPCTL_CNAK; /* clear NAK set by core */
- ctrl |= DXEPCTL_EPENA; /* ensure ep enabled */
- ctrl |= DXEPCTL_USBACTEP;
- writel(ctrl, hsotg->regs + DIEPCTL0);
+ s3c_hsotg_program_zlp(hsotg, hsotg->eps_out[0]);
}
/**
* s3c_hsotg_handle_outdone - handle receiving OutDone/SetupDone from RXFIFO
* @hsotg: The device instance
* @epnum: The endpoint received from
- * @was_setup: Set if processing a SetupDone event.
*
* The RXFIFO has delivered an OutDone event, which means that the data
* transfer for an OUT endpoint has been completed, either by a short
* packet or by the finish of a transfer.
*/
-static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg,
- int epnum, bool was_setup)
+static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg, int epnum)
{
u32 epsize = readl(hsotg->regs + DOEPTSIZ(epnum));
- struct s3c_hsotg_ep *hs_ep = &hsotg->eps[epnum];
+ struct s3c_hsotg_ep *hs_ep = hsotg->eps_out[epnum];
struct s3c_hsotg_req *hs_req = hs_ep->req;
struct usb_request *req = &hs_req->req;
unsigned size_left = DXEPTSIZ_XFERSIZE_GET(epsize);
@@ -1413,6 +1530,13 @@ static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg,
return;
}
+ if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_OUT) {
+ dev_dbg(hsotg->dev, "zlp packet received\n");
+ s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+ s3c_hsotg_enqueue_setup(hsotg);
+ return;
+ }
+
if (using_dma(hsotg)) {
unsigned size_done;
@@ -1435,12 +1559,6 @@ static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg,
if (req->actual < req->length && size_left == 0) {
s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
return;
- } else if (epnum == 0) {
- /*
- * After was_setup = 1 =>
- * set CNAK for non Setup requests
- */
- hsotg->setup = was_setup ? 0 : 1;
}
if (req->actual < req->length && req->short_not_ok) {
@@ -1453,13 +1571,10 @@ static void s3c_hsotg_handle_outdone(struct dwc2_hsotg *hsotg,
*/
}
- if (epnum == 0) {
- /*
- * Condition req->complete != s3c_hsotg_complete_setup says:
- * send ZLP when we have an asynchronous request from gadget
- */
- if (!was_setup && req->complete != s3c_hsotg_complete_setup)
- s3c_hsotg_send_zlp(hsotg, hs_req);
+ if (epnum == 0 && hsotg->ep0_state == DWC2_EP0_DATA_OUT) {
+ /* Move to STATUS IN */
+ s3c_hsotg_ep0_zlp(hsotg, true);
+ return;
}
s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, result);
@@ -1511,8 +1626,7 @@ static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
size = grxstsr & GRXSTS_BYTECNT_MASK;
size >>= GRXSTS_BYTECNT_SHIFT;
- if (1)
- dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
+ dev_dbg(hsotg->dev, "%s: GRXSTSP=0x%08x (%d@%d)\n",
__func__, grxstsr, size, epnum);
switch ((status & GRXSTS_PKTSTS_MASK) >> GRXSTS_PKTSTS_SHIFT) {
@@ -1525,7 +1639,7 @@ static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
s3c_hsotg_read_frameno(hsotg));
if (!using_dma(hsotg))
- s3c_hsotg_handle_outdone(hsotg, epnum, false);
+ s3c_hsotg_handle_outdone(hsotg, epnum);
break;
case GRXSTS_PKTSTS_SETUPDONE:
@@ -1533,8 +1647,13 @@ static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
"SetupDone (Frame=0x%08x, DOPEPCTL=0x%08x)\n",
s3c_hsotg_read_frameno(hsotg),
readl(hsotg->regs + DOEPCTL(0)));
-
- s3c_hsotg_handle_outdone(hsotg, epnum, true);
+ /*
+ * Call s3c_hsotg_handle_outdone here if it was not called from
+ * GRXSTS_PKTSTS_OUTDONE. That is, if the core didn't
+ * generate GRXSTS_PKTSTS_OUTDONE for setup packet.
+ */
+ if (hsotg->ep0_state == DWC2_EP0_SETUP)
+ s3c_hsotg_handle_outdone(hsotg, epnum);
break;
case GRXSTS_PKTSTS_OUTRX:
@@ -1547,6 +1666,8 @@ static void s3c_hsotg_handle_rx(struct dwc2_hsotg *hsotg)
s3c_hsotg_read_frameno(hsotg),
readl(hsotg->regs + DOEPCTL(0)));
+ WARN_ON(hsotg->ep0_state != DWC2_EP0_SETUP);
+
s3c_hsotg_rx_data(hsotg, epnum, size);
break;
@@ -1591,14 +1712,18 @@ static u32 s3c_hsotg_ep0_mps(unsigned int mps)
* the hardware control registers to reflect this.
*/
static void s3c_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
- unsigned int ep, unsigned int mps)
+ unsigned int ep, unsigned int mps, unsigned int dir_in)
{
- struct s3c_hsotg_ep *hs_ep = &hsotg->eps[ep];
+ struct s3c_hsotg_ep *hs_ep;
void __iomem *regs = hsotg->regs;
u32 mpsval;
u32 mcval;
u32 reg;
+ hs_ep = index_to_ep(hsotg, ep, dir_in);
+ if (!hs_ep)
+ return;
+
if (ep == 0) {
/* EP0 is a special case */
mpsval = s3c_hsotg_ep0_mps(mps);
@@ -1617,17 +1742,12 @@ static void s3c_hsotg_set_ep_maxpacket(struct dwc2_hsotg *hsotg,
hs_ep->ep.maxpacket = mpsval;
}
- /*
- * update both the in and out endpoint controldir_ registers, even
- * if one of the directions may not be in use.
- */
-
- reg = readl(regs + DIEPCTL(ep));
- reg &= ~DXEPCTL_MPS_MASK;
- reg |= mpsval;
- writel(reg, regs + DIEPCTL(ep));
-
- if (ep) {
+ if (dir_in) {
+ reg = readl(regs + DIEPCTL(ep));
+ reg &= ~DXEPCTL_MPS_MASK;
+ reg |= mpsval;
+ writel(reg, regs + DIEPCTL(ep));
+ } else {
reg = readl(regs + DOEPCTL(ep));
reg &= ~DXEPCTL_MPS_MASK;
reg |= mpsval;
@@ -1727,9 +1847,21 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
}
/* Finish ZLP handling for IN EP0 transactions */
- if (hsotg->eps[0].sent_zlp) {
- dev_dbg(hsotg->dev, "zlp packet received\n");
+ if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_STATUS_IN) {
+ dev_dbg(hsotg->dev, "zlp packet sent\n");
s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+ if (hsotg->test_mode) {
+ int ret;
+
+ ret = s3c_hsotg_set_test_mode(hsotg, hsotg->test_mode);
+ if (ret < 0) {
+ dev_dbg(hsotg->dev, "Invalid Test #%d\n",
+ hsotg->test_mode);
+ s3c_hsotg_stall_ep0(hsotg);
+ return;
+ }
+ }
+ s3c_hsotg_enqueue_setup(hsotg);
return;
}
@@ -1756,31 +1888,27 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
dev_dbg(hsotg->dev, "req->length:%d req->actual:%d req->zero:%d\n",
hs_req->req.length, hs_req->req.actual, hs_req->req.zero);
- /*
- * Check if dealing with Maximum Packet Size(MPS) IN transfer at EP0
- * When sent data is a multiple MPS size (e.g. 64B ,128B ,192B
- * ,256B ... ), after last MPS sized packet send IN ZLP packet to
- * inform the host that no more data is available.
- * The state of req.zero member is checked to be sure that the value to
- * send is smaller than wValue expected from host.
- * Check req.length to NOT send another ZLP when the current one is
- * under completion (the one for which this completion has been called).
- */
- if (hs_req->req.length && hs_ep->index == 0 && hs_req->req.zero &&
- hs_req->req.length == hs_req->req.actual &&
- !(hs_req->req.length % hs_ep->ep.maxpacket)) {
+ if (!size_left && hs_req->req.actual < hs_req->req.length) {
+ dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
+ s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
+ return;
+ }
- dev_dbg(hsotg->dev, "ep0 zlp IN packet sent\n");
- s3c_hsotg_send_zlp(hsotg, hs_req);
+ /* Zlp for all endpoints, for ep0 only in DATA IN stage */
+ if (hs_ep->send_zlp) {
+ s3c_hsotg_program_zlp(hsotg, hs_ep);
+ hs_ep->send_zlp = 0;
+ /* transfer will be completed on next complete interrupt */
+ return;
+ }
+ if (hs_ep->index == 0 && hsotg->ep0_state == DWC2_EP0_DATA_IN) {
+ /* Move to STATUS OUT */
+ s3c_hsotg_ep0_zlp(hsotg, false);
return;
}
- if (!size_left && hs_req->req.actual < hs_req->req.length) {
- dev_dbg(hsotg->dev, "%s trying more for req...\n", __func__);
- s3c_hsotg_start_req(hsotg, hs_ep, hs_req, true);
- } else
- s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
+ s3c_hsotg_complete_request(hsotg, hs_ep, hs_req, 0);
}
/**
@@ -1794,7 +1922,7 @@ static void s3c_hsotg_complete_in(struct dwc2_hsotg *hsotg,
static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
int dir_in)
{
- struct s3c_hsotg_ep *hs_ep = &hsotg->eps[idx];
+ struct s3c_hsotg_ep *hs_ep = index_to_ep(hsotg, idx, dir_in);
u32 epint_reg = dir_in ? DIEPINT(idx) : DOEPINT(idx);
u32 epctl_reg = dir_in ? DIEPCTL(idx) : DOEPCTL(idx);
u32 epsiz_reg = dir_in ? DIEPTSIZ(idx) : DOEPTSIZ(idx);
@@ -1807,9 +1935,19 @@ static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
/* Clear endpoint interrupts */
writel(ints, hsotg->regs + epint_reg);
+ if (!hs_ep) {
+ dev_err(hsotg->dev, "%s:Interrupt for unconfigured ep%d(%s)\n",
+ __func__, idx, dir_in ? "in" : "out");
+ return;
+ }
+
dev_dbg(hsotg->dev, "%s: ep%d(%s) DxEPINT=0x%08x\n",
__func__, idx, dir_in ? "in" : "out", ints);
+ /* Don't process XferCompl interrupt if it is a setup packet */
+ if (idx == 0 && (ints & (DXEPINT_SETUP | DXEPINT_SETUP_RCVD)))
+ ints &= ~DXEPINT_XFERCOMPL;
+
if (ints & DXEPINT_XFERCOMPL) {
if (hs_ep->isochronous && hs_ep->interval == 1) {
if (ctrl & DXEPCTL_EOFRNUM)
@@ -1839,7 +1977,7 @@ static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
* as we ignore the RXFIFO.
*/
- s3c_hsotg_handle_outdone(hsotg, idx, false);
+ s3c_hsotg_handle_outdone(hsotg, idx);
}
}
@@ -1878,7 +2016,7 @@ static void s3c_hsotg_epint(struct dwc2_hsotg *hsotg, unsigned int idx,
if (dir_in)
WARN_ON_ONCE(1);
else
- s3c_hsotg_handle_outdone(hsotg, 0, true);
+ s3c_hsotg_handle_outdone(hsotg, 0);
}
}
@@ -1969,9 +2107,15 @@ static void s3c_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
if (ep0_mps) {
int i;
- s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps);
- for (i = 1; i < hsotg->num_of_eps; i++)
- s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps);
+ /* Initialize ep0 for both in and out directions */
+ s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 1);
+ s3c_hsotg_set_ep_maxpacket(hsotg, 0, ep0_mps, 0);
+ for (i = 1; i < hsotg->num_of_eps; i++) {
+ if (hsotg->eps_in[i])
+ s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 1);
+ if (hsotg->eps_out[i])
+ s3c_hsotg_set_ep_maxpacket(hsotg, i, ep_mps, 0);
+ }
}
/* ensure after enumeration our EP0 is active */
@@ -1988,30 +2132,23 @@ static void s3c_hsotg_irq_enumdone(struct dwc2_hsotg *hsotg)
* @hsotg: The device state.
* @ep: The endpoint the requests may be on.
* @result: The result code to use.
- * @force: Force removal of any current requests
*
* Go through the requests on the given endpoint and mark them
* completed with the given result code.
*/
static void kill_all_requests(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *ep,
- int result, bool force)
+ int result)
{
struct s3c_hsotg_req *req, *treq;
unsigned size;
- list_for_each_entry_safe(req, treq, &ep->queue, queue) {
- /*
- * currently, we can't do much about an already
- * running request on an in endpoint
- */
-
- if (ep->req == req && ep->dir_in && !force)
- continue;
+ ep->req = NULL;
+ list_for_each_entry_safe(req, treq, &ep->queue, queue)
s3c_hsotg_complete_request(hsotg, ep, req,
result);
- }
+
if (!hsotg->dedicated_fifos)
return;
size = (readl(hsotg->regs + DTXFSTS(ep->index)) & 0xffff) * 4;
@@ -2035,8 +2172,16 @@ void s3c_hsotg_disconnect(struct dwc2_hsotg *hsotg)
return;
hsotg->connected = 0;
- for (ep = 0; ep < hsotg->num_of_eps; ep++)
- kill_all_requests(hsotg, &hsotg->eps[ep], -ESHUTDOWN, true);
+ hsotg->test_mode = 0;
+
+ for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+ if (hsotg->eps_in[ep])
+ kill_all_requests(hsotg, hsotg->eps_in[ep],
+ -ESHUTDOWN);
+ if (hsotg->eps_out[ep])
+ kill_all_requests(hsotg, hsotg->eps_out[ep],
+ -ESHUTDOWN);
+ }
call_gadget(hsotg, disconnect);
}
@@ -2053,9 +2198,11 @@ static void s3c_hsotg_irq_fifoempty(struct dwc2_hsotg *hsotg, bool periodic)
int epno, ret;
/* look through for any more data to transmit */
-
for (epno = 0; epno < hsotg->num_of_eps; epno++) {
- ep = &hsotg->eps[epno];
+ ep = index_to_ep(hsotg, epno, 1);
+
+ if (!ep)
+ continue;
if (!ep->dir_in)
continue;
@@ -2129,9 +2276,13 @@ static int s3c_hsotg_corereset(struct dwc2_hsotg *hsotg)
*
* Issue a soft reset to the core, and await the core finishing it.
*/
-void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
+void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg,
+ bool is_usb_reset)
{
- s3c_hsotg_corereset(hsotg);
+ u32 val;
+
+ if (!is_usb_reset)
+ s3c_hsotg_corereset(hsotg);
/*
* we must now enable ep0 ready for host detection and then
@@ -2139,14 +2290,16 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
*/
/* set the PLL on, remove the HNP/SRP and set the PHY */
+ val = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |
- (0x5 << 10), hsotg->regs + GUSBCFG);
+ (val << GUSBCFG_USBTRDTIM_SHIFT), hsotg->regs + GUSBCFG);
s3c_hsotg_init_fifo(hsotg);
- __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
+ if (!is_usb_reset)
+ __orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
- writel(1 << 18 | DCFG_DEVSPD_HS, hsotg->regs + DCFG);
+ writel(DCFG_EPMISCNT(1) | DCFG_DEVSPD_HS, hsotg->regs + DCFG);
/* Clear any pending OTG interrupts */
writel(0xffffffff, hsotg->regs + GOTGINT);
@@ -2163,7 +2316,7 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
if (using_dma(hsotg))
writel(GAHBCFG_GLBL_INTR_EN | GAHBCFG_DMA_EN |
- GAHBCFG_HBSTLEN_INCR4,
+ (GAHBCFG_HBSTLEN_INCR4 << GAHBCFG_HBSTLEN_SHIFT),
hsotg->regs + GAHBCFG);
else
writel(((hsotg->dedicated_fifos) ? (GAHBCFG_NP_TXF_EMP_LVL |
@@ -2177,8 +2330,8 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
* interrupts.
*/
- writel(((hsotg->dedicated_fifos) ? DIEPMSK_TXFIFOEMPTY |
- DIEPMSK_INTKNTXFEMPMSK : 0) |
+ writel(((hsotg->dedicated_fifos && !using_dma(hsotg)) ?
+ DIEPMSK_TXFIFOEMPTY | DIEPMSK_INTKNTXFEMPMSK : 0) |
DIEPMSK_EPDISBLDMSK | DIEPMSK_XFERCOMPLMSK |
DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
DIEPMSK_INTKNEPMISMSK,
@@ -2215,9 +2368,11 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
s3c_hsotg_ctrl_epint(hsotg, 0, 0, 1);
s3c_hsotg_ctrl_epint(hsotg, 0, 1, 1);
- __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
- udelay(10); /* see openiboot */
- __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+ if (!is_usb_reset) {
+ __orr32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+ udelay(10); /* see openiboot */
+ __bic32(hsotg->regs + DCTL, DCTL_PWRONPRGDONE);
+ }
dev_dbg(hsotg->dev, "DCTL=0x%08x\n", readl(hsotg->regs + DCTL));
@@ -2230,13 +2385,13 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
writel(DXEPTSIZ_MC(1) | DXEPTSIZ_PKTCNT(1) |
DXEPTSIZ_XFERSIZE(8), hsotg->regs + DOEPTSIZ0);
- writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+ writel(s3c_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
DXEPCTL_CNAK | DXEPCTL_EPENA |
DXEPCTL_USBACTEP,
hsotg->regs + DOEPCTL0);
/* enable, but don't activate EP0in */
- writel(s3c_hsotg_ep0_mps(hsotg->eps[0].ep.maxpacket) |
+ writel(s3c_hsotg_ep0_mps(hsotg->eps_out[0]->ep.maxpacket) |
DXEPCTL_USBACTEP, hsotg->regs + DIEPCTL0);
s3c_hsotg_enqueue_setup(hsotg);
@@ -2246,8 +2401,10 @@ void s3c_hsotg_core_init_disconnected(struct dwc2_hsotg *hsotg)
readl(hsotg->regs + DOEPCTL0));
/* clear global NAKs */
- writel(DCTL_CGOUTNAK | DCTL_CGNPINNAK | DCTL_SFTDISCON,
- hsotg->regs + DCTL);
+ val = DCTL_CGOUTNAK | DCTL_CGNPINNAK;
+ if (!is_usb_reset)
+ val |= DCTL_SFTDISCON;
+ __orr32(hsotg->regs + DCTL, val);
/* must be at-least 3ms to allow bus to see disconnect */
mdelay(3);
@@ -2293,7 +2450,6 @@ irq_retry:
writel(GINTSTS_ENUMDONE, hsotg->regs + GINTSTS);
s3c_hsotg_irq_enumdone(hsotg);
- hsotg->connected = 1;
}
if (gintsts & (GINTSTS_OEPINT | GINTSTS_IEPINT)) {
@@ -2308,12 +2464,14 @@ irq_retry:
dev_dbg(hsotg->dev, "%s: daint=%08x\n", __func__, daint);
- for (ep = 0; ep < 15 && daint_out; ep++, daint_out >>= 1) {
+ for (ep = 0; ep < hsotg->num_of_eps && daint_out;
+ ep++, daint_out >>= 1) {
if (daint_out & 1)
s3c_hsotg_epint(hsotg, ep, 0);
}
- for (ep = 0; ep < 15 && daint_in; ep++, daint_in >>= 1) {
+ for (ep = 0; ep < hsotg->num_of_eps && daint_in;
+ ep++, daint_in >>= 1) {
if (daint_in & 1)
s3c_hsotg_epint(hsotg, ep, 1);
}
@@ -2329,15 +2487,17 @@ irq_retry:
writel(GINTSTS_USBRST, hsotg->regs + GINTSTS);
+ /* Report disconnection if it is not already done. */
+ s3c_hsotg_disconnect(hsotg);
+
if (usb_status & GOTGCTL_BSESVLD) {
if (time_after(jiffies, hsotg->last_rst +
msecs_to_jiffies(200))) {
- kill_all_requests(hsotg, &hsotg->eps[0],
- -ECONNRESET, true);
+ kill_all_requests(hsotg, hsotg->eps_out[0],
+ -ECONNRESET);
- s3c_hsotg_core_init_disconnected(hsotg);
- s3c_hsotg_core_connect(hsotg);
+ s3c_hsotg_core_init_disconnected(hsotg, true);
}
}
}
@@ -2429,12 +2589,12 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
struct s3c_hsotg_ep *hs_ep = our_ep(ep);
struct dwc2_hsotg *hsotg = hs_ep->parent;
unsigned long flags;
- int index = hs_ep->index;
+ unsigned int index = hs_ep->index;
u32 epctrl_reg;
u32 epctrl;
u32 mps;
- int dir_in;
- int i, val, size;
+ unsigned int dir_in;
+ unsigned int i, val, size;
int ret = 0;
dev_dbg(hsotg->dev,
@@ -2482,7 +2642,7 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
epctrl |= DXEPCTL_SNAK;
/* update the endpoint state */
- s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps);
+ s3c_hsotg_set_ep_maxpacket(hsotg, hs_ep->index, mps, dir_in);
/* default, set to non-periodic */
hs_ep->isochronous = 0;
@@ -2518,30 +2678,48 @@ static int s3c_hsotg_ep_enable(struct usb_ep *ep,
break;
}
+ /* If fifo is already allocated for this ep */
+ if (hs_ep->fifo_index) {
+ size = hs_ep->ep.maxpacket * hs_ep->mc;
+ /* If bigger fifo is required deallocate current one */
+ if (size > hs_ep->fifo_size) {
+ hsotg->fifo_map &= ~(1 << hs_ep->fifo_index);
+ hs_ep->fifo_index = 0;
+ hs_ep->fifo_size = 0;
+ }
+ }
+
/*
* if the hardware has dedicated fifos, we must give each IN EP
* a unique tx-fifo even if it is non-periodic.
*/
- if (dir_in && hsotg->dedicated_fifos) {
+ if (dir_in && hsotg->dedicated_fifos && !hs_ep->fifo_index) {
+ u32 fifo_index = 0;
+ u32 fifo_size = UINT_MAX;
size = hs_ep->ep.maxpacket*hs_ep->mc;
- for (i = 1; i <= 8; ++i) {
+ for (i = 1; i < hsotg->num_of_eps; ++i) {
if (hsotg->fifo_map & (1<<i))
continue;
val = readl(hsotg->regs + DPTXFSIZN(i));
val = (val >> FIFOSIZE_DEPTH_SHIFT)*4;
if (val < size)
continue;
- hsotg->fifo_map |= 1<<i;
-
- epctrl |= DXEPCTL_TXFNUM(i);
- hs_ep->fifo_index = i;
- hs_ep->fifo_size = val;
- break;
+ /* Search for smallest acceptable fifo */
+ if (val < fifo_size) {
+ fifo_size = val;
+ fifo_index = i;
+ }
}
- if (i == 8) {
+ if (!fifo_index) {
+ dev_err(hsotg->dev,
+ "%s: No suitable fifo found\n", __func__);
ret = -ENOMEM;
goto error;
}
+ hsotg->fifo_map |= 1 << fifo_index;
+ epctrl |= DXEPCTL_TXFNUM(fifo_index);
+ hs_ep->fifo_index = fifo_index;
+ hs_ep->fifo_size = fifo_size;
}
/* for non control endpoints, set PID to D0 */
@@ -2579,7 +2757,7 @@ static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
dev_dbg(hsotg->dev, "%s(ep %p)\n", __func__, ep);
- if (ep == &hsotg->eps[0].ep) {
+ if (ep == &hsotg->eps_out[0]->ep) {
dev_err(hsotg->dev, "%s: called for ep0\n", __func__);
return -EINVAL;
}
@@ -2587,8 +2765,6 @@ static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
epctrl_reg = dir_in ? DIEPCTL(index) : DOEPCTL(index);
spin_lock_irqsave(&hsotg->lock, flags);
- /* terminate all requests with shutdown */
- kill_all_requests(hsotg, hs_ep, -ESHUTDOWN, force);
hsotg->fifo_map &= ~(1<<hs_ep->fifo_index);
hs_ep->fifo_index = 0;
@@ -2605,6 +2781,9 @@ static int s3c_hsotg_ep_disable_force(struct usb_ep *ep, bool force)
/* disable endpoint interrupts */
s3c_hsotg_ctrl_epint(hsotg, hs_ep->index, hs_ep->dir_in, 0);
+ /* terminate all requests with shutdown */
+ kill_all_requests(hsotg, hs_ep, -ESHUTDOWN);
+
spin_unlock_irqrestore(&hsotg->lock, flags);
return 0;
}
@@ -2682,40 +2861,39 @@ static int s3c_hsotg_ep_sethalt(struct usb_ep *ep, int value)
return 0;
}
- /* write both IN and OUT control registers */
-
- epreg = DIEPCTL(index);
- epctl = readl(hs->regs + epreg);
-
- if (value) {
- epctl |= DXEPCTL_STALL + DXEPCTL_SNAK;
- if (epctl & DXEPCTL_EPENA)
- epctl |= DXEPCTL_EPDIS;
+ if (hs_ep->dir_in) {
+ epreg = DIEPCTL(index);
+ epctl = readl(hs->regs + epreg);
+
+ if (value) {
+ epctl |= DXEPCTL_STALL + DXEPCTL_SNAK;
+ if (epctl & DXEPCTL_EPENA)
+ epctl |= DXEPCTL_EPDIS;
+ } else {
+ epctl &= ~DXEPCTL_STALL;
+ xfertype = epctl & DXEPCTL_EPTYPE_MASK;
+ if (xfertype == DXEPCTL_EPTYPE_BULK ||
+ xfertype == DXEPCTL_EPTYPE_INTERRUPT)
+ epctl |= DXEPCTL_SETD0PID;
+ }
+ writel(epctl, hs->regs + epreg);
} else {
- epctl &= ~DXEPCTL_STALL;
- xfertype = epctl & DXEPCTL_EPTYPE_MASK;
- if (xfertype == DXEPCTL_EPTYPE_BULK ||
- xfertype == DXEPCTL_EPTYPE_INTERRUPT)
- epctl |= DXEPCTL_SETD0PID;
- }
-
- writel(epctl, hs->regs + epreg);
- epreg = DOEPCTL(index);
- epctl = readl(hs->regs + epreg);
+ epreg = DOEPCTL(index);
+ epctl = readl(hs->regs + epreg);
- if (value)
- epctl |= DXEPCTL_STALL;
- else {
- epctl &= ~DXEPCTL_STALL;
- xfertype = epctl & DXEPCTL_EPTYPE_MASK;
- if (xfertype == DXEPCTL_EPTYPE_BULK ||
- xfertype == DXEPCTL_EPTYPE_INTERRUPT)
- epctl |= DXEPCTL_SETD0PID;
+ if (value)
+ epctl |= DXEPCTL_STALL;
+ else {
+ epctl &= ~DXEPCTL_STALL;
+ xfertype = epctl & DXEPCTL_EPTYPE_MASK;
+ if (xfertype == DXEPCTL_EPTYPE_BULK ||
+ xfertype == DXEPCTL_EPTYPE_INTERRUPT)
+ epctl |= DXEPCTL_SETD0PID;
+ }
+ writel(epctl, hs->regs + epreg);
}
- writel(epctl, hs->regs + epreg);
-
hs_ep->halted = value;
return 0;
@@ -2801,6 +2979,7 @@ static void s3c_hsotg_phy_disable(struct dwc2_hsotg *hsotg)
*/
static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
{
+ u32 trdtim;
/* unmask subset of endpoint interrupts */
writel(DIEPMSK_TIMEOUTMSK | DIEPMSK_AHBERRMSK |
@@ -2816,12 +2995,6 @@ static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
/* Be in disconnected state until gadget is registered */
__orr32(hsotg->regs + DCTL, DCTL_SFTDISCON);
- if (0) {
- /* post global nak until we're ready */
- writel(DCTL_SGNPINNAK | DCTL_SGOUTNAK,
- hsotg->regs + DCTL);
- }
-
/* setup fifos */
dev_dbg(hsotg->dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
@@ -2831,11 +3004,13 @@ static void s3c_hsotg_init(struct dwc2_hsotg *hsotg)
s3c_hsotg_init_fifo(hsotg);
/* set the PLL on, remove the HNP/SRP and set the PHY */
- writel(GUSBCFG_PHYIF16 | GUSBCFG_TOUTCAL(7) | (0x5 << 10),
- hsotg->regs + GUSBCFG);
+ trdtim = (hsotg->phyif == GUSBCFG_PHYIF8) ? 9 : 5;
+ writel(hsotg->phyif | GUSBCFG_TOUTCAL(7) |
+ (trdtim << GUSBCFG_USBTRDTIM_SHIFT),
+ hsotg->regs + GUSBCFG);
- writel(using_dma(hsotg) ? GAHBCFG_DMA_EN : 0x0,
- hsotg->regs + GAHBCFG);
+ if (using_dma(hsotg))
+ __orr32(hsotg->regs + GAHBCFG, GAHBCFG_DMA_EN);
}
/**
@@ -2889,10 +3064,12 @@ static int s3c_hsotg_udc_start(struct usb_gadget *gadget,
}
s3c_hsotg_phy_enable(hsotg);
+ if (!IS_ERR_OR_NULL(hsotg->uphy))
+ otg_set_peripheral(hsotg->uphy->otg, &hsotg->gadget);
spin_lock_irqsave(&hsotg->lock, flags);
s3c_hsotg_init(hsotg);
- s3c_hsotg_core_init_disconnected(hsotg);
+ s3c_hsotg_core_init_disconnected(hsotg, false);
hsotg->enabled = 0;
spin_unlock_irqrestore(&hsotg->lock, flags);
@@ -2927,8 +3104,12 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget)
mutex_lock(&hsotg->init_mutex);
/* all endpoints should be shutdown */
- for (ep = 1; ep < hsotg->num_of_eps; ep++)
- s3c_hsotg_ep_disable_force(&hsotg->eps[ep].ep, true);
+ for (ep = 1; ep < hsotg->num_of_eps; ep++) {
+ if (hsotg->eps_in[ep])
+ s3c_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ if (hsotg->eps_out[ep])
+ s3c_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ }
spin_lock_irqsave(&hsotg->lock, flags);
@@ -2938,6 +3119,8 @@ static int s3c_hsotg_udc_stop(struct usb_gadget *gadget)
spin_unlock_irqrestore(&hsotg->lock, flags);
+ if (!IS_ERR_OR_NULL(hsotg->uphy))
+ otg_set_peripheral(hsotg->uphy->otg, NULL);
s3c_hsotg_phy_disable(hsotg);
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies), hsotg->supplies);
@@ -2979,9 +3162,11 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
if (is_on) {
clk_enable(hsotg->clk);
hsotg->enabled = 1;
+ s3c_hsotg_core_init_disconnected(hsotg, false);
s3c_hsotg_core_connect(hsotg);
} else {
s3c_hsotg_core_disconnect(hsotg);
+ s3c_hsotg_disconnect(hsotg);
hsotg->enabled = 0;
clk_disable(hsotg->clk);
}
@@ -2993,11 +3178,52 @@ static int s3c_hsotg_pullup(struct usb_gadget *gadget, int is_on)
return 0;
}
+static int s3c_hsotg_vbus_session(struct usb_gadget *gadget, int is_active)
+{
+ struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+ unsigned long flags;
+
+ dev_dbg(hsotg->dev, "%s: is_active: %d\n", __func__, is_active);
+ spin_lock_irqsave(&hsotg->lock, flags);
+
+ if (is_active) {
+ /* Kill any ep0 requests as controller will be reinitialized */
+ kill_all_requests(hsotg, hsotg->eps_out[0], -ECONNRESET);
+ s3c_hsotg_core_init_disconnected(hsotg, false);
+ if (hsotg->enabled)
+ s3c_hsotg_core_connect(hsotg);
+ } else {
+ s3c_hsotg_core_disconnect(hsotg);
+ s3c_hsotg_disconnect(hsotg);
+ }
+
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return 0;
+}
+
+/**
+ * s3c_hsotg_vbus_draw - report bMaxPower field
+ * @gadget: The usb gadget state
+ * @mA: Amount of current
+ *
+ * Report how much power the device may consume to the phy.
+ */
+static int s3c_hsotg_vbus_draw(struct usb_gadget *gadget, unsigned mA)
+{
+ struct dwc2_hsotg *hsotg = to_hsotg(gadget);
+
+ if (IS_ERR_OR_NULL(hsotg->uphy))
+ return -ENOTSUPP;
+ return usb_phy_set_power(hsotg->uphy, mA);
+}
+
static const struct usb_gadget_ops s3c_hsotg_gadget_ops = {
.get_frame = s3c_hsotg_gadget_getframe,
.udc_start = s3c_hsotg_udc_start,
.udc_stop = s3c_hsotg_udc_stop,
.pullup = s3c_hsotg_pullup,
+ .vbus_session = s3c_hsotg_vbus_session,
+ .vbus_draw = s3c_hsotg_vbus_draw,
};
/**
@@ -3012,19 +3238,19 @@ static const struct usb_gadget_ops s3c_hsotg_gadget_ops = {
*/
static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
struct s3c_hsotg_ep *hs_ep,
- int epnum)
+ int epnum,
+ bool dir_in)
{
char *dir;
if (epnum == 0)
dir = "";
- else if ((epnum % 2) == 0) {
- dir = "out";
- } else {
+ else if (dir_in)
dir = "in";
- hs_ep->dir_in = 1;
- }
+ else
+ dir = "out";
+ hs_ep->dir_in = dir_in;
hs_ep->index = epnum;
snprintf(hs_ep->name, sizeof(hs_ep->name), "ep%d%s", epnum, dir);
@@ -3048,8 +3274,10 @@ static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
if (using_dma(hsotg)) {
u32 next = DXEPCTL_NEXTEP((epnum + 1) % 15);
- writel(next, hsotg->regs + DIEPCTL(epnum));
- writel(next, hsotg->regs + DOEPCTL(epnum));
+ if (dir_in)
+ writel(next, hsotg->regs + DIEPCTL(epnum));
+ else
+ writel(next, hsotg->regs + DOEPCTL(epnum));
}
}
@@ -3059,24 +3287,56 @@ static void s3c_hsotg_initep(struct dwc2_hsotg *hsotg,
*
* Read the USB core HW configuration registers
*/
-static void s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
+static int s3c_hsotg_hw_cfg(struct dwc2_hsotg *hsotg)
{
- u32 cfg2, cfg3, cfg4;
+ u32 cfg;
+ u32 ep_type;
+ u32 i;
+
/* check hardware configuration */
- cfg2 = readl(hsotg->regs + 0x48);
- hsotg->num_of_eps = (cfg2 >> 10) & 0xF;
+ cfg = readl(hsotg->regs + GHWCFG2);
+ hsotg->num_of_eps = (cfg >> GHWCFG2_NUM_DEV_EP_SHIFT) & 0xF;
+ /* Add ep0 */
+ hsotg->num_of_eps++;
+
+ hsotg->eps_in[0] = devm_kzalloc(hsotg->dev, sizeof(struct s3c_hsotg_ep),
+ GFP_KERNEL);
+ if (!hsotg->eps_in[0])
+ return -ENOMEM;
+ /* Same s3c_hsotg_ep is used in both directions for ep0 */
+ hsotg->eps_out[0] = hsotg->eps_in[0];
+
+ cfg = readl(hsotg->regs + GHWCFG1);
+ for (i = 1, cfg >>= 2; i < hsotg->num_of_eps; i++, cfg >>= 2) {
+ ep_type = cfg & 3;
+ /* Direction in or both */
+ if (!(ep_type & 2)) {
+ hsotg->eps_in[i] = devm_kzalloc(hsotg->dev,
+ sizeof(struct s3c_hsotg_ep), GFP_KERNEL);
+ if (!hsotg->eps_in[i])
+ return -ENOMEM;
+ }
+ /* Direction out or both */
+ if (!(ep_type & 1)) {
+ hsotg->eps_out[i] = devm_kzalloc(hsotg->dev,
+ sizeof(struct s3c_hsotg_ep), GFP_KERNEL);
+ if (!hsotg->eps_out[i])
+ return -ENOMEM;
+ }
+ }
- cfg3 = readl(hsotg->regs + 0x4C);
- hsotg->fifo_mem = (cfg3 >> 16);
+ cfg = readl(hsotg->regs + GHWCFG3);
+ hsotg->fifo_mem = (cfg >> GHWCFG3_DFIFO_DEPTH_SHIFT);
- cfg4 = readl(hsotg->regs + 0x50);
- hsotg->dedicated_fifos = (cfg4 >> 25) & 1;
+ cfg = readl(hsotg->regs + GHWCFG4);
+ hsotg->dedicated_fifos = (cfg >> GHWCFG4_DED_FIFO_SHIFT) & 1;
dev_info(hsotg->dev, "EPs: %d, %s fifos, %d entries in SPRAM\n",
hsotg->num_of_eps,
hsotg->dedicated_fifos ? "dedicated" : "shared",
hsotg->fifo_mem);
+ return 0;
}
/**
@@ -3095,22 +3355,22 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
readl(regs + DCFG), readl(regs + DCTL),
readl(regs + DIEPMSK));
- dev_info(dev, "GAHBCFG=0x%08x, 0x44=0x%08x\n",
- readl(regs + GAHBCFG), readl(regs + 0x44));
+ dev_info(dev, "GAHBCFG=0x%08x, GHWCFG1=0x%08x\n",
+ readl(regs + GAHBCFG), readl(regs + GHWCFG1));
dev_info(dev, "GRXFSIZ=0x%08x, GNPTXFSIZ=0x%08x\n",
readl(regs + GRXFSIZ), readl(regs + GNPTXFSIZ));
/* show periodic fifo settings */
- for (idx = 1; idx <= 15; idx++) {
+ for (idx = 1; idx < hsotg->num_of_eps; idx++) {
val = readl(regs + DPTXFSIZN(idx));
dev_info(dev, "DPTx[%d] FSize=%d, StAddr=0x%08x\n", idx,
val >> FIFOSIZE_DEPTH_SHIFT,
val & FIFOSIZE_STARTADDR_MASK);
}
- for (idx = 0; idx < 15; idx++) {
+ for (idx = 0; idx < hsotg->num_of_eps; idx++) {
dev_info(dev,
"ep%d-in: EPCTL=0x%08x, SIZ=0x%08x, DMA=0x%08x\n", idx,
readl(regs + DIEPCTL(idx)),
@@ -3132,6 +3392,103 @@ static void s3c_hsotg_dump(struct dwc2_hsotg *hsotg)
}
/**
+ * testmode_write - debugfs: change usb test mode
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry modify the current usb test mode.
+ */
+static ssize_t testmode_write(struct file *file, const char __user *ubuf, size_t
+ count, loff_t *ppos)
+{
+ struct seq_file *s = file->private_data;
+ struct dwc2_hsotg *hsotg = s->private;
+ unsigned long flags;
+ u32 testmode = 0;
+ char buf[32];
+
+ if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ return -EFAULT;
+
+ if (!strncmp(buf, "test_j", 6))
+ testmode = TEST_J;
+ else if (!strncmp(buf, "test_k", 6))
+ testmode = TEST_K;
+ else if (!strncmp(buf, "test_se0_nak", 12))
+ testmode = TEST_SE0_NAK;
+ else if (!strncmp(buf, "test_packet", 11))
+ testmode = TEST_PACKET;
+ else if (!strncmp(buf, "test_force_enable", 17))
+ testmode = TEST_FORCE_EN;
+ else
+ testmode = 0;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ s3c_hsotg_set_test_mode(hsotg, testmode);
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+ return count;
+}
+
+/**
+ * testmode_show - debugfs: show usb test mode state
+ * @seq: The seq file to write to.
+ * @v: Unused parameter.
+ *
+ * This debugfs entry shows which usb test mode is currently enabled.
+ */
+static int testmode_show(struct seq_file *s, void *unused)
+{
+ struct dwc2_hsotg *hsotg = s->private;
+ unsigned long flags;
+ int dctl;
+
+ spin_lock_irqsave(&hsotg->lock, flags);
+ dctl = readl(hsotg->regs + DCTL);
+ dctl &= DCTL_TSTCTL_MASK;
+ dctl >>= DCTL_TSTCTL_SHIFT;
+ spin_unlock_irqrestore(&hsotg->lock, flags);
+
+ switch (dctl) {
+ case 0:
+ seq_puts(s, "no test\n");
+ break;
+ case TEST_J:
+ seq_puts(s, "test_j\n");
+ break;
+ case TEST_K:
+ seq_puts(s, "test_k\n");
+ break;
+ case TEST_SE0_NAK:
+ seq_puts(s, "test_se0_nak\n");
+ break;
+ case TEST_PACKET:
+ seq_puts(s, "test_packet\n");
+ break;
+ case TEST_FORCE_EN:
+ seq_puts(s, "test_force_enable\n");
+ break;
+ default:
+ seq_printf(s, "UNKNOWN %d\n", dctl);
+ }
+
+ return 0;
+}
+
+static int testmode_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, testmode_show, inode->i_private);
+}
+
+static const struct file_operations testmode_fops = {
+ .owner = THIS_MODULE,
+ .open = testmode_open,
+ .write = testmode_write,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+/**
* state_show - debugfs: show overall driver and device state.
* @seq: The seq file to write to.
* @v: Unused parameter.
@@ -3168,7 +3525,7 @@ static int state_show(struct seq_file *seq, void *v)
seq_puts(seq, "\nEndpoint status:\n");
- for (idx = 0; idx < 15; idx++) {
+ for (idx = 0; idx < hsotg->num_of_eps; idx++) {
u32 in, out;
in = readl(regs + DIEPCTL(idx));
@@ -3227,7 +3584,7 @@ static int fifo_show(struct seq_file *seq, void *v)
seq_puts(seq, "\nPeriodic TXFIFOs:\n");
- for (idx = 1; idx <= 15; idx++) {
+ for (idx = 1; idx < hsotg->num_of_eps; idx++) {
val = readl(regs + DPTXFSIZN(idx));
seq_printf(seq, "\tDPTXFIFO%2d: Size %d, Start 0x%08x\n", idx,
@@ -3359,29 +3716,53 @@ static void s3c_hsotg_create_debug(struct dwc2_hsotg *hsotg)
/* create general state file */
- hsotg->debug_file = debugfs_create_file("state", 0444, root,
+ hsotg->debug_file = debugfs_create_file("state", S_IRUGO, root,
hsotg, &state_fops);
if (IS_ERR(hsotg->debug_file))
dev_err(hsotg->dev, "%s: failed to create state\n", __func__);
- hsotg->debug_fifo = debugfs_create_file("fifo", 0444, root,
+ hsotg->debug_testmode = debugfs_create_file("testmode",
+ S_IRUGO | S_IWUSR, root,
+ hsotg, &testmode_fops);
+
+ if (IS_ERR(hsotg->debug_testmode))
+ dev_err(hsotg->dev, "%s: failed to create testmode\n",
+ __func__);
+
+ hsotg->debug_fifo = debugfs_create_file("fifo", S_IRUGO, root,
hsotg, &fifo_fops);
if (IS_ERR(hsotg->debug_fifo))
dev_err(hsotg->dev, "%s: failed to create fifo\n", __func__);
- /* create one file for each endpoint */
-
+ /* Create one file for each out endpoint */
for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
- struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
+ struct s3c_hsotg_ep *ep;
- ep->debugfs = debugfs_create_file(ep->name, 0444,
- root, ep, &ep_fops);
+ ep = hsotg->eps_out[epidx];
+ if (ep) {
+ ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
+ root, ep, &ep_fops);
- if (IS_ERR(ep->debugfs))
- dev_err(hsotg->dev, "failed to create %s debug file\n",
- ep->name);
+ if (IS_ERR(ep->debugfs))
+ dev_err(hsotg->dev, "failed to create %s debug file\n",
+ ep->name);
+ }
+ }
+ /* Create one file for each in endpoint. EP0 is handled with out eps */
+ for (epidx = 1; epidx < hsotg->num_of_eps; epidx++) {
+ struct s3c_hsotg_ep *ep;
+
+ ep = hsotg->eps_in[epidx];
+ if (ep) {
+ ep->debugfs = debugfs_create_file(ep->name, S_IRUGO,
+ root, ep, &ep_fops);
+
+ if (IS_ERR(ep->debugfs))
+ dev_err(hsotg->dev, "failed to create %s debug file\n",
+ ep->name);
+ }
}
}
@@ -3396,15 +3777,63 @@ static void s3c_hsotg_delete_debug(struct dwc2_hsotg *hsotg)
unsigned epidx;
for (epidx = 0; epidx < hsotg->num_of_eps; epidx++) {
- struct s3c_hsotg_ep *ep = &hsotg->eps[epidx];
- debugfs_remove(ep->debugfs);
+ if (hsotg->eps_in[epidx])
+ debugfs_remove(hsotg->eps_in[epidx]->debugfs);
+ if (hsotg->eps_out[epidx])
+ debugfs_remove(hsotg->eps_out[epidx]->debugfs);
}
debugfs_remove(hsotg->debug_file);
+ debugfs_remove(hsotg->debug_testmode);
debugfs_remove(hsotg->debug_fifo);
debugfs_remove(hsotg->debug_root);
}
+#ifdef CONFIG_OF
+static void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg)
+{
+ struct device_node *np = hsotg->dev->of_node;
+ u32 len = 0;
+ u32 i = 0;
+
+ /* Enable dma if requested in device tree */
+ hsotg->g_using_dma = of_property_read_bool(np, "g-use-dma");
+
+ /*
+ * Register TX periodic fifo size per endpoint.
+ * EP0 is excluded since it has no fifo configuration.
+ */
+ if (!of_find_property(np, "g-tx-fifo-size", &len))
+ goto rx_fifo;
+
+ len /= sizeof(u32);
+
+ /* Read tx fifo sizes other than ep0 */
+ if (of_property_read_u32_array(np, "g-tx-fifo-size",
+ &hsotg->g_tx_fifo_sz[1], len))
+ goto rx_fifo;
+
+ /* Add ep0 */
+ len++;
+
+ /* Make remaining TX fifos unavailable */
+ if (len < MAX_EPS_CHANNELS) {
+ for (i = len; i < MAX_EPS_CHANNELS; i++)
+ hsotg->g_tx_fifo_sz[i] = 0;
+ }
+
+rx_fifo:
+ /* Register RX fifo size */
+ of_property_read_u32(np, "g-rx-fifo-size", &hsotg->g_rx_fifo_sz);
+
+ /* Register NPTX fifo size */
+ of_property_read_u32(np, "g-np-tx-fifo-size",
+ &hsotg->g_np_g_tx_fifo_sz);
+}
+#else
+static inline void s3c_hsotg_of_probe(struct dwc2_hsotg *hsotg) { }
+#endif
+
/**
* dwc2_gadget_init - init function for gadget
* @dwc2: The data structure for the DWC2 driver.
@@ -3414,41 +3843,47 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
{
struct device *dev = hsotg->dev;
struct s3c_hsotg_plat *plat = dev->platform_data;
- struct phy *phy;
- struct usb_phy *uphy;
- struct s3c_hsotg_ep *eps;
int epnum;
int ret;
int i;
+ u32 p_tx_fifo[] = DWC2_G_P_LEGACY_TX_FIFO_SIZE;
/* Set default UTMI width */
hsotg->phyif = GUSBCFG_PHYIF16;
+ s3c_hsotg_of_probe(hsotg);
+
+ /* Initialize to legacy fifo configuration values */
+ hsotg->g_rx_fifo_sz = 2048;
+ hsotg->g_np_g_tx_fifo_sz = 1024;
+ memcpy(&hsotg->g_tx_fifo_sz[1], p_tx_fifo, sizeof(p_tx_fifo));
+ /* Device tree specific probe */
+ s3c_hsotg_of_probe(hsotg);
+ /* Dump fifo information */
+ dev_dbg(dev, "NonPeriodic TXFIFO size: %d\n",
+ hsotg->g_np_g_tx_fifo_sz);
+ dev_dbg(dev, "RXFIFO size: %d\n", hsotg->g_rx_fifo_sz);
+ for (i = 0; i < MAX_EPS_CHANNELS; i++)
+ dev_dbg(dev, "Periodic TXFIFO%2d size: %d\n", i,
+ hsotg->g_tx_fifo_sz[i]);
/*
- * Attempt to find a generic PHY, then look for an old style
- * USB PHY, finally fall back to pdata
+ * If platform probe couldn't find a generic PHY or an old style
+ * USB PHY, fall back to pdata
*/
- phy = devm_phy_get(dev, "usb2-phy");
- if (IS_ERR(phy)) {
- uphy = devm_usb_get_phy(dev, USB_PHY_TYPE_USB2);
- if (IS_ERR(uphy)) {
- /* Fallback for pdata */
- plat = dev_get_platdata(dev);
- if (!plat) {
- dev_err(dev,
- "no platform data or transceiver defined\n");
- return -EPROBE_DEFER;
- }
- hsotg->plat = plat;
- } else
- hsotg->uphy = uphy;
- } else {
- hsotg->phy = phy;
+ if (IS_ERR_OR_NULL(hsotg->phy) && IS_ERR_OR_NULL(hsotg->uphy)) {
+ plat = dev_get_platdata(dev);
+ if (!plat) {
+ dev_err(dev,
+ "no platform data or transceiver defined\n");
+ return -EPROBE_DEFER;
+ }
+ hsotg->plat = plat;
+ } else if (hsotg->phy) {
/*
* If using the generic PHY framework, check if the PHY bus
* width is 8-bit and set the phyif appropriately.
*/
- if (phy_get_bus_width(phy) == 8)
+ if (phy_get_bus_width(hsotg->phy) == 8)
hsotg->phyif = GUSBCFG_PHYIF8;
}
@@ -3488,16 +3923,53 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
if (ret) {
dev_err(dev, "failed to enable supplies: %d\n", ret);
- goto err_supplies;
+ goto err_clk;
}
/* usb phy enable */
s3c_hsotg_phy_enable(hsotg);
+ /*
+ * Force Device mode before initialization.
+ * This allows correctly configuring fifo for device mode.
+ */
+ __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEHOSTMODE);
+ __orr32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
+
+ /*
+ * According to Synopsys databook, this sleep is needed for the force
+ * device mode to take effect.
+ */
+ msleep(25);
+
s3c_hsotg_corereset(hsotg);
- s3c_hsotg_hw_cfg(hsotg);
+ ret = s3c_hsotg_hw_cfg(hsotg);
+ if (ret) {
+ dev_err(hsotg->dev, "Hardware configuration failed: %d\n", ret);
+ goto err_clk;
+ }
+
s3c_hsotg_init(hsotg);
+ /* Switch back to default configuration */
+ __bic32(hsotg->regs + GUSBCFG, GUSBCFG_FORCEDEVMODE);
+
+ hsotg->ctrl_buff = devm_kzalloc(hsotg->dev,
+ DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
+ if (!hsotg->ctrl_buff) {
+ dev_err(dev, "failed to allocate ctrl request buff\n");
+ ret = -ENOMEM;
+ goto err_supplies;
+ }
+
+ hsotg->ep0_buff = devm_kzalloc(hsotg->dev,
+ DWC2_CTRL_BUFF_SIZE, GFP_KERNEL);
+ if (!hsotg->ep0_buff) {
+ dev_err(dev, "failed to allocate ctrl reply buff\n");
+ ret = -ENOMEM;
+ goto err_supplies;
+ }
+
ret = devm_request_irq(hsotg->dev, irq, s3c_hsotg_irq, IRQF_SHARED,
dev_name(hsotg->dev), hsotg);
if (ret < 0) {
@@ -3506,7 +3978,7 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
dev_err(dev, "cannot claim IRQ for gadget\n");
- goto err_clk;
+ goto err_supplies;
}
/* hsotg->num_of_eps holds number of EPs other than ep0 */
@@ -3517,33 +3989,30 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
goto err_supplies;
}
- eps = kcalloc(hsotg->num_of_eps + 1, sizeof(struct s3c_hsotg_ep),
- GFP_KERNEL);
- if (!eps) {
- ret = -ENOMEM;
- goto err_supplies;
- }
-
- hsotg->eps = eps;
-
/* setup endpoint information */
INIT_LIST_HEAD(&hsotg->gadget.ep_list);
- hsotg->gadget.ep0 = &hsotg->eps[0].ep;
+ hsotg->gadget.ep0 = &hsotg->eps_out[0]->ep;
/* allocate EP0 request */
- hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps[0].ep,
+ hsotg->ctrl_req = s3c_hsotg_ep_alloc_request(&hsotg->eps_out[0]->ep,
GFP_KERNEL);
if (!hsotg->ctrl_req) {
dev_err(dev, "failed to allocate ctrl req\n");
ret = -ENOMEM;
- goto err_ep_mem;
+ goto err_supplies;
}
/* initialise the endpoints now the core has been initialised */
- for (epnum = 0; epnum < hsotg->num_of_eps; epnum++)
- s3c_hsotg_initep(hsotg, &hsotg->eps[epnum], epnum);
+ for (epnum = 0; epnum < hsotg->num_of_eps; epnum++) {
+ if (hsotg->eps_in[epnum])
+ s3c_hsotg_initep(hsotg, hsotg->eps_in[epnum],
+ epnum, 1);
+ if (hsotg->eps_out[epnum])
+ s3c_hsotg_initep(hsotg, hsotg->eps_out[epnum],
+ epnum, 0);
+ }
/* disable power and clock */
s3c_hsotg_phy_disable(hsotg);
@@ -3552,12 +4021,12 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
hsotg->supplies);
if (ret) {
dev_err(dev, "failed to disable supplies: %d\n", ret);
- goto err_ep_mem;
+ goto err_supplies;
}
ret = usb_add_gadget_udc(dev, &hsotg->gadget);
if (ret)
- goto err_ep_mem;
+ goto err_supplies;
s3c_hsotg_create_debug(hsotg);
@@ -3565,8 +4034,6 @@ int dwc2_gadget_init(struct dwc2_hsotg *hsotg, int irq)
return 0;
-err_ep_mem:
- kfree(eps);
err_supplies:
s3c_hsotg_phy_disable(hsotg);
err_clk:
@@ -3612,8 +4079,12 @@ int s3c_hsotg_suspend(struct dwc2_hsotg *hsotg)
s3c_hsotg_phy_disable(hsotg);
- for (ep = 0; ep < hsotg->num_of_eps; ep++)
- s3c_hsotg_ep_disable(&hsotg->eps[ep].ep);
+ for (ep = 0; ep < hsotg->num_of_eps; ep++) {
+ if (hsotg->eps_in[ep])
+ s3c_hsotg_ep_disable(&hsotg->eps_in[ep]->ep);
+ if (hsotg->eps_out[ep])
+ s3c_hsotg_ep_disable(&hsotg->eps_out[ep]->ep);
+ }
ret = regulator_bulk_disable(ARRAY_SIZE(hsotg->supplies),
hsotg->supplies);
@@ -3644,7 +4115,7 @@ int s3c_hsotg_resume(struct dwc2_hsotg *hsotg)
s3c_hsotg_phy_enable(hsotg);
spin_lock_irqsave(&hsotg->lock, flags);
- s3c_hsotg_core_init_disconnected(hsotg);
+ s3c_hsotg_core_init_disconnected(hsotg, false);
if (hsotg->enabled)
s3c_hsotg_core_connect(hsotg);
spin_unlock_irqrestore(&hsotg->lock, flags);
diff --git a/drivers/usb/dwc2/hcd.c b/drivers/usb/dwc2/hcd.c
index a0cd9db6f4cd..c78c8740db1d 100644
--- a/drivers/usb/dwc2/hcd.c
+++ b/drivers/usb/dwc2/hcd.c
@@ -316,10 +316,12 @@ void dwc2_hcd_disconnect(struct dwc2_hsotg *hsotg)
*/
static void dwc2_hcd_rem_wakeup(struct dwc2_hsotg *hsotg)
{
- if (hsotg->lx_state == DWC2_L2)
+ if (hsotg->lx_state == DWC2_L2) {
hsotg->flags.b.port_suspend_change = 1;
- else
+ usb_hcd_resume_root_hub(hsotg->priv);
+ } else {
hsotg->flags.b.port_l1_change = 1;
+ }
}
/**
@@ -1371,7 +1373,7 @@ static void dwc2_conn_id_status_change(struct work_struct *work)
hsotg->op_state = OTG_STATE_B_PERIPHERAL;
dwc2_core_init(hsotg, false, -1);
dwc2_enable_global_interrupts(hsotg);
- s3c_hsotg_core_init_disconnected(hsotg);
+ s3c_hsotg_core_init_disconnected(hsotg, false);
s3c_hsotg_core_connect(hsotg);
} else {
/* A-Device connector (Host Mode) */
@@ -1473,30 +1475,6 @@ static void dwc2_port_suspend(struct dwc2_hsotg *hsotg, u16 windex)
}
}
-static void dwc2_port_resume(struct dwc2_hsotg *hsotg)
-{
- u32 hprt0;
-
- /* After clear the Stop PHY clock bit, we should wait for a moment
- * for PLL work stable with clock output.
- */
- writel(0, hsotg->regs + PCGCTL);
- usleep_range(2000, 4000);
-
- hprt0 = dwc2_read_hprt0(hsotg);
- hprt0 |= HPRT0_RES;
- writel(hprt0, hsotg->regs + HPRT0);
- hprt0 &= ~HPRT0_SUSP;
- /* according to USB2.0 Spec 7.1.7.7, the host must send the resume
- * signal for at least 20ms
- */
- usleep_range(20000, 25000);
-
- hprt0 &= ~HPRT0_RES;
- writel(hprt0, hsotg->regs + HPRT0);
- hsotg->lx_state = DWC2_L0;
-}
-
/* Handles hub class-specific requests */
static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
u16 wvalue, u16 windex, char *buf, u16 wlength)
@@ -1542,7 +1520,17 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
case USB_PORT_FEAT_SUSPEND:
dev_dbg(hsotg->dev,
"ClearPortFeature USB_PORT_FEAT_SUSPEND\n");
- dwc2_port_resume(hsotg);
+ writel(0, hsotg->regs + PCGCTL);
+ usleep_range(20000, 40000);
+
+ hprt0 = dwc2_read_hprt0(hsotg);
+ hprt0 |= HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
+ hprt0 &= ~HPRT0_SUSP;
+ usleep_range(100000, 150000);
+
+ hprt0 &= ~HPRT0_RES;
+ writel(hprt0, hsotg->regs + HPRT0);
break;
case USB_PORT_FEAT_POWER:
@@ -1622,7 +1610,9 @@ static int dwc2_hcd_hub_control(struct dwc2_hsotg *hsotg, u16 typereq,
hub_desc->bDescLength = 9;
hub_desc->bDescriptorType = 0x29;
hub_desc->bNbrPorts = 1;
- hub_desc->wHubCharacteristics = cpu_to_le16(0x08);
+ hub_desc->wHubCharacteristics =
+ cpu_to_le16(HUB_CHAR_COMMON_LPSM |
+ HUB_CHAR_INDV_PORT_OCPM);
hub_desc->bPwrOn2PwrGood = 1;
hub_desc->bHubContrCurrent = 0;
hub_desc->u.hs.DeviceRemovable[0] = 0;
@@ -2315,55 +2305,6 @@ static void _dwc2_hcd_stop(struct usb_hcd *hcd)
usleep_range(1000, 3000);
}
-static int _dwc2_hcd_suspend(struct usb_hcd *hcd)
-{
- struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
- u32 hprt0;
-
- if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
- (hsotg->op_state == OTG_STATE_A_HOST)))
- return 0;
-
- /* TODO: We get into suspend from 'on' state, maybe we need to do
- * something if we get here from DWC2_L1(LPM sleep) state one day.
- */
- if (hsotg->lx_state != DWC2_L0)
- return 0;
-
- hprt0 = dwc2_read_hprt0(hsotg);
- if (hprt0 & HPRT0_CONNSTS) {
- dwc2_port_suspend(hsotg, 1);
- } else {
- u32 pcgctl = readl(hsotg->regs + PCGCTL);
-
- pcgctl |= PCGCTL_STOPPCLK;
- writel(pcgctl, hsotg->regs + PCGCTL);
- }
-
- return 0;
-}
-
-static int _dwc2_hcd_resume(struct usb_hcd *hcd)
-{
- struct dwc2_hsotg *hsotg = dwc2_hcd_to_hsotg(hcd);
- u32 hprt0;
-
- if (!((hsotg->op_state == OTG_STATE_B_HOST) ||
- (hsotg->op_state == OTG_STATE_A_HOST)))
- return 0;
-
- if (hsotg->lx_state != DWC2_L2)
- return 0;
-
- hprt0 = dwc2_read_hprt0(hsotg);
- if ((hprt0 & HPRT0_CONNSTS) && (hprt0 & HPRT0_SUSP))
- dwc2_port_resume(hsotg);
- else
- writel(0, hsotg->regs + PCGCTL);
-
- return 0;
-}
-
/* Returns the current frame number */
static int _dwc2_hcd_get_frame_number(struct usb_hcd *hcd)
{
@@ -2734,9 +2675,6 @@ static struct hc_driver dwc2_hc_driver = {
.hub_status_data = _dwc2_hcd_hub_status_data,
.hub_control = _dwc2_hcd_hub_control,
.clear_tt_buffer_complete = _dwc2_hcd_clear_tt_buffer_complete,
-
- .bus_suspend = _dwc2_hcd_suspend,
- .bus_resume = _dwc2_hcd_resume,
};
/*
diff --git a/drivers/usb/dwc2/hw.h b/drivers/usb/dwc2/hw.h
index 51248b935493..d0a5ed8fa15a 100644
--- a/drivers/usb/dwc2/hw.h
+++ b/drivers/usb/dwc2/hw.h
@@ -294,6 +294,7 @@
#define GHWCFG4_NUM_IN_EPS_MASK (0xf << 26)
#define GHWCFG4_NUM_IN_EPS_SHIFT 26
#define GHWCFG4_DED_FIFO_EN (1 << 25)
+#define GHWCFG4_DED_FIFO_SHIFT 25
#define GHWCFG4_SESSION_END_FILT_EN (1 << 24)
#define GHWCFG4_B_VALID_FILT_EN (1 << 23)
#define GHWCFG4_A_VALID_FILT_EN (1 << 22)
@@ -541,6 +542,7 @@
#define DIEPINT(_a) HSOTG_REG(0x908 + ((_a) * 0x20))
#define DOEPINT(_a) HSOTG_REG(0xB08 + ((_a) * 0x20))
+#define DXEPINT_SETUP_RCVD (1 << 15)
#define DXEPINT_INEPNAKEFF (1 << 6)
#define DXEPINT_BACK2BACKSETUP (1 << 6)
#define DXEPINT_INTKNEPMIS (1 << 5)
diff --git a/drivers/usb/dwc2/platform.c b/drivers/usb/dwc2/platform.c
index 6a795aa2ff05..ae095f009b4f 100644
--- a/drivers/usb/dwc2/platform.c
+++ b/drivers/usb/dwc2/platform.c
@@ -155,6 +155,8 @@ static int dwc2_driver_probe(struct platform_device *dev)
struct dwc2_core_params defparams;
struct dwc2_hsotg *hsotg;
struct resource *res;
+ struct phy *phy;
+ struct usb_phy *uphy;
int retval;
int irq;
@@ -212,6 +214,24 @@ static int dwc2_driver_probe(struct platform_device *dev)
hsotg->dr_mode = of_usb_get_dr_mode(dev->dev.of_node);
+ /*
+ * Attempt to find a generic PHY, then look for an old style
+ * USB PHY
+ */
+ phy = devm_phy_get(&dev->dev, "usb2-phy");
+ if (IS_ERR(phy)) {
+ hsotg->phy = NULL;
+ uphy = devm_usb_get_phy(&dev->dev, USB_PHY_TYPE_USB2);
+ if (IS_ERR(uphy))
+ hsotg->uphy = NULL;
+ else
+ hsotg->uphy = uphy;
+ } else {
+ hsotg->phy = phy;
+ phy_power_on(hsotg->phy);
+ phy_init(hsotg->phy);
+ }
+
spin_lock_init(&hsotg->lock);
mutex_init(&hsotg->init_mutex);
retval = dwc2_gadget_init(hsotg, irq);
@@ -231,8 +251,15 @@ static int __maybe_unused dwc2_suspend(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
- if (dwc2_is_device_mode(dwc2))
+ if (dwc2_is_device_mode(dwc2)) {
ret = s3c_hsotg_suspend(dwc2);
+ } else {
+ if (dwc2->lx_state == DWC2_L0)
+ return 0;
+ phy_exit(dwc2->phy);
+ phy_power_off(dwc2->phy);
+
+ }
return ret;
}
@@ -241,8 +268,13 @@ static int __maybe_unused dwc2_resume(struct device *dev)
struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
int ret = 0;
- if (dwc2_is_device_mode(dwc2))
+ if (dwc2_is_device_mode(dwc2)) {
ret = s3c_hsotg_resume(dwc2);
+ } else {
+ phy_power_on(dwc2->phy);
+ phy_init(dwc2->phy);
+
+ }
return ret;
}
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index 58b5b2cde4c5..edbf9c85af7e 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -104,12 +104,6 @@ config USB_DWC3_DEBUG
help
Say Y here to enable debugging messages on DWC3 Driver.
-config USB_DWC3_VERBOSE
- bool "Enable Verbose Debugging Messages"
- depends on USB_DWC3_DEBUG
- help
- Say Y here to enable verbose debugging messages on DWC3 Driver.
-
config DWC3_HOST_USB3_LPM_ENABLE
bool "Enable USB3 LPM Capability"
depends on USB_DWC3_HOST=y || USB_DWC3_DUAL_ROLE=y
diff --git a/drivers/usb/dwc3/Makefile b/drivers/usb/dwc3/Makefile
index bb34fbcfeab3..46172f47f02d 100644
--- a/drivers/usb/dwc3/Makefile
+++ b/drivers/usb/dwc3/Makefile
@@ -2,7 +2,6 @@
CFLAGS_trace.o := -I$(src)
ccflags-$(CONFIG_USB_DWC3_DEBUG) := -DDEBUG
-ccflags-$(CONFIG_USB_DWC3_VERBOSE) += -DVERBOSE_DEBUG
obj-$(CONFIG_USB_DWC3) += dwc3.o
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 25ddc39efad8..9f0e209b8f6c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -345,7 +345,7 @@ static void dwc3_core_num_eps(struct dwc3 *dwc)
dwc->num_in_eps = DWC3_NUM_IN_EPS(parms);
dwc->num_out_eps = DWC3_NUM_EPS(parms) - dwc->num_in_eps;
- dev_vdbg(dwc->dev, "found %d IN and %d OUT endpoints\n",
+ dwc3_trace(trace_dwc3_core, "found %d IN and %d OUT endpoints",
dwc->num_in_eps, dwc->num_out_eps);
}
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 4bb9aa696ede..d201910b892f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -431,7 +431,6 @@ struct dwc3_event_buffer {
* @dwc: pointer to DWC controller
* @saved_state: ep state saved during hibernation
* @flags: endpoint flags (wedged, stalled, ...)
- * @current_trb: index of current used trb
* @number: endpoint number (1 - 15)
* @type: set to bmAttributes & USB_ENDPOINT_XFERTYPE_MASK
* @resource_index: Resource transfer index
@@ -464,8 +463,6 @@ struct dwc3_ep {
/* This last one is specific to EP0 */
#define DWC3_EP0_DIR_IN (1 << 31)
- unsigned current_trb;
-
u8 number;
u8 type;
u8 resource_index;
@@ -685,7 +682,6 @@ struct dwc3_scratchpad_array {
* @is_utmi_l1_suspend: the core asserts output signal
* 0 - utmi_sleep_n
* 1 - utmi_l1_suspend_n
- * @is_selfpowered: true when we are selfpowered
* @is_fpga: true when we are using the FPGA board
* @needs_fifo_resize: not all users might want fifo resizing, flag it
* @pullups_connected: true when Run/Stop bit is set
@@ -809,7 +805,6 @@ struct dwc3 {
unsigned has_hibernation:1;
unsigned has_lpm_erratum:1;
unsigned is_utmi_l1_suspend:1;
- unsigned is_selfpowered:1;
unsigned is_fpga:1;
unsigned needs_fifo_resize:1;
unsigned pullups_connected:1;
diff --git a/drivers/usb/dwc3/dwc3-pci.c b/drivers/usb/dwc3/dwc3-pci.c
index b642a2f998f9..8d950569d557 100644
--- a/drivers/usb/dwc3/dwc3-pci.c
+++ b/drivers/usb/dwc3/dwc3-pci.c
@@ -22,9 +22,6 @@
#include <linux/pci.h>
#include <linux/platform_device.h>
-#include <linux/usb/otg.h>
-#include <linux/usb/usb_phy_generic.h>
-
#include "platform_data.h"
/* FIXME define these in <linux/pci_ids.h> */
@@ -36,66 +33,41 @@
#define PCI_DEVICE_ID_INTEL_SPTLP 0x9d30
#define PCI_DEVICE_ID_INTEL_SPTH 0xa130
-struct dwc3_pci {
- struct device *dev;
- struct platform_device *dwc3;
- struct platform_device *usb2_phy;
- struct platform_device *usb3_phy;
-};
-
-static int dwc3_pci_register_phys(struct dwc3_pci *glue)
+static int dwc3_pci_quirks(struct pci_dev *pdev)
{
- struct usb_phy_generic_platform_data pdata;
- struct platform_device *pdev;
- int ret;
+ if (pdev->vendor == PCI_VENDOR_ID_AMD &&
+ pdev->device == PCI_DEVICE_ID_AMD_NL_USB) {
+ struct dwc3_platform_data pdata;
- memset(&pdata, 0x00, sizeof(pdata));
+ memset(&pdata, 0, sizeof(pdata));
- pdev = platform_device_alloc("usb_phy_generic", 0);
- if (!pdev)
- return -ENOMEM;
-
- glue->usb2_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB2;
- pdata.gpio_reset = -1;
+ pdata.has_lpm_erratum = true;
+ pdata.lpm_nyet_threshold = 0xf;
- ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err1;
+ pdata.u2exit_lfps_quirk = true;
+ pdata.u2ss_inp3_quirk = true;
+ pdata.req_p1p2p3_quirk = true;
+ pdata.del_p1p2p3_quirk = true;
+ pdata.del_phy_power_chg_quirk = true;
+ pdata.lfps_filter_quirk = true;
+ pdata.rx_detect_poll_quirk = true;
- pdev = platform_device_alloc("usb_phy_generic", 1);
- if (!pdev) {
- ret = -ENOMEM;
- goto err1;
- }
+ pdata.tx_de_emphasis_quirk = true;
+ pdata.tx_de_emphasis = 1;
- glue->usb3_phy = pdev;
- pdata.type = USB_PHY_TYPE_USB3;
-
- ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
- if (ret)
- goto err2;
-
- ret = platform_device_add(glue->usb2_phy);
- if (ret)
- goto err2;
+ /*
+ * FIXME these quirks should be removed when AMD NL
+ * taps out
+ */
+ pdata.disable_scramble_quirk = true;
+ pdata.dis_u3_susphy_quirk = true;
+ pdata.dis_u2_susphy_quirk = true;
- ret = platform_device_add(glue->usb3_phy);
- if (ret)
- goto err3;
+ return platform_device_add_data(pci_get_drvdata(pdev), &pdata,
+ sizeof(pdata));
+ }
return 0;
-
-err3:
- platform_device_del(glue->usb2_phy);
-
-err2:
- platform_device_put(glue->usb3_phy);
-
-err1:
- platform_device_put(glue->usb2_phy);
-
- return ret;
}
static int dwc3_pci_probe(struct pci_dev *pci,
@@ -103,18 +75,8 @@ static int dwc3_pci_probe(struct pci_dev *pci,
{
struct resource res[2];
struct platform_device *dwc3;
- struct dwc3_pci *glue;
int ret;
struct device *dev = &pci->dev;
- struct dwc3_platform_data dwc3_pdata;
-
- memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
-
- glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
- if (!glue)
- return -ENOMEM;
-
- glue->dev = dev;
ret = pcim_enable_device(pci);
if (ret) {
@@ -124,12 +86,6 @@ static int dwc3_pci_probe(struct pci_dev *pci,
pci_set_master(pci);
- ret = dwc3_pci_register_phys(glue);
- if (ret) {
- dev_err(dev, "couldn't register PHYs\n");
- return ret;
- }
-
dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
if (!dwc3) {
dev_err(dev, "couldn't allocate dwc3 device\n");
@@ -147,70 +103,34 @@ static int dwc3_pci_probe(struct pci_dev *pci,
res[1].name = "dwc_usb3";
res[1].flags = IORESOURCE_IRQ;
- if (pci->vendor == PCI_VENDOR_ID_AMD &&
- pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
- dwc3_pdata.has_lpm_erratum = true;
- dwc3_pdata.lpm_nyet_threshold = 0xf;
-
- dwc3_pdata.u2exit_lfps_quirk = true;
- dwc3_pdata.u2ss_inp3_quirk = true;
- dwc3_pdata.req_p1p2p3_quirk = true;
- dwc3_pdata.del_p1p2p3_quirk = true;
- dwc3_pdata.del_phy_power_chg_quirk = true;
- dwc3_pdata.lfps_filter_quirk = true;
- dwc3_pdata.rx_detect_poll_quirk = true;
-
- dwc3_pdata.tx_de_emphasis_quirk = true;
- dwc3_pdata.tx_de_emphasis = 1;
-
- /*
- * FIXME these quirks should be removed when AMD NL
- * taps out
- */
- dwc3_pdata.disable_scramble_quirk = true;
- dwc3_pdata.dis_u3_susphy_quirk = true;
- dwc3_pdata.dis_u2_susphy_quirk = true;
- }
-
ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
if (ret) {
dev_err(dev, "couldn't add resources to dwc3 device\n");
return ret;
}
- pci_set_drvdata(pci, glue);
-
- ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
+ pci_set_drvdata(pci, dwc3);
+ ret = dwc3_pci_quirks(pci);
if (ret)
- goto err3;
-
- dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
+ goto err;
- dwc3->dev.dma_mask = dev->dma_mask;
- dwc3->dev.dma_parms = dev->dma_parms;
dwc3->dev.parent = dev;
- glue->dwc3 = dwc3;
ret = platform_device_add(dwc3);
if (ret) {
dev_err(dev, "failed to register dwc3 device\n");
- goto err3;
+ goto err;
}
return 0;
-
-err3:
+err:
platform_device_put(dwc3);
return ret;
}
static void dwc3_pci_remove(struct pci_dev *pci)
{
- struct dwc3_pci *glue = pci_get_drvdata(pci);
-
- platform_device_unregister(glue->dwc3);
- platform_device_unregister(glue->usb2_phy);
- platform_device_unregister(glue->usb3_phy);
+ platform_device_unregister(pci_get_drvdata(pci));
}
static const struct pci_device_id dwc3_pci_id_table[] = {
@@ -228,45 +148,11 @@ static const struct pci_device_id dwc3_pci_id_table[] = {
};
MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
-#ifdef CONFIG_PM_SLEEP
-static int dwc3_pci_suspend(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
-
- pci_disable_device(pci);
-
- return 0;
-}
-
-static int dwc3_pci_resume(struct device *dev)
-{
- struct pci_dev *pci = to_pci_dev(dev);
- int ret;
-
- ret = pci_enable_device(pci);
- if (ret) {
- dev_err(dev, "can't re-enable device --> %d\n", ret);
- return ret;
- }
-
- pci_set_master(pci);
-
- return 0;
-}
-#endif /* CONFIG_PM_SLEEP */
-
-static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
-};
-
static struct pci_driver dwc3_pci_driver = {
.name = "dwc3-pci",
.id_table = dwc3_pci_id_table,
.probe = dwc3_pci_probe,
.remove = dwc3_pci_remove,
- .driver = {
- .pm = &dwc3_pci_dev_pm_ops,
- },
};
MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c
index 1bc77a3b4997..2ef3c8d6a9db 100644
--- a/drivers/usb/dwc3/ep0.c
+++ b/drivers/usb/dwc3/ep0.c
@@ -344,7 +344,7 @@ static int dwc3_ep0_handle_status(struct dwc3 *dwc,
/*
* LTM will be set once we know how to set this in HW.
*/
- usb_status |= dwc->is_selfpowered << USB_DEVICE_SELF_POWERED;
+ usb_status |= dwc->gadget.is_selfpowered;
if (dwc->speed == DWC3_DSTS_SUPERSPEED) {
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 8f65ab3a3b92..a03a485205c7 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -139,7 +139,8 @@ int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
udelay(5);
}
- dev_vdbg(dwc->dev, "link state change request timed out\n");
+ dwc3_trace(trace_dwc3_gadget,
+ "link state change request timed out");
return -ETIMEDOUT;
}
@@ -219,7 +220,7 @@ int dwc3_gadget_resize_tx_fifos(struct dwc3 *dwc)
fifo_size |= (last_fifo_depth << 16);
- dev_vdbg(dwc->dev, "%s: Fifo Addr %04x Size %d\n",
+ dwc3_trace(trace_dwc3_gadget, "%s: Fifo Addr %04x Size %d",
dep->name, last_fifo_depth, fifo_size & 0xffff);
dwc3_writel(dwc->regs, DWC3_GTXFIFOSIZ(num), fifo_size);
@@ -287,7 +288,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
do {
reg = dwc3_readl(dwc->regs, DWC3_DGCMD);
if (!(reg & DWC3_DGCMD_CMDACT)) {
- dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "Command Complete --> %d",
DWC3_DGCMD_STATUS(reg));
return 0;
}
@@ -297,8 +299,11 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
* interrupt context.
*/
timeout--;
- if (!timeout)
+ if (!timeout) {
+ dwc3_trace(trace_dwc3_gadget,
+ "Command Timed Out");
return -ETIMEDOUT;
+ }
udelay(1);
} while (1);
}
@@ -320,7 +325,8 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
do {
reg = dwc3_readl(dwc->regs, DWC3_DEPCMD(ep));
if (!(reg & DWC3_DEPCMD_CMDACT)) {
- dev_vdbg(dwc->dev, "Command Complete --> %d\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "Command Complete --> %d",
DWC3_DEPCMD_STATUS(reg));
return 0;
}
@@ -330,8 +336,11 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
* interrupt context.
*/
timeout--;
- if (!timeout)
+ if (!timeout) {
+ dwc3_trace(trace_dwc3_gadget,
+ "Command Timed Out");
return -ETIMEDOUT;
+ }
udelay(1);
} while (1);
@@ -352,9 +361,6 @@ static int dwc3_alloc_trb_pool(struct dwc3_ep *dep)
if (dep->trb_pool)
return 0;
- if (dep->number == 0 || dep->number == 1)
- return 0;
-
dep->trb_pool = dma_alloc_coherent(dwc->dev,
sizeof(struct dwc3_trb) * DWC3_TRB_NUM,
&dep->trb_pool_dma, GFP_KERNEL);
@@ -492,7 +498,7 @@ static int __dwc3_gadget_ep_enable(struct dwc3_ep *dep,
u32 reg;
int ret;
- dev_vdbg(dwc->dev, "Enabling %s\n", dep->name);
+ dwc3_trace(trace_dwc3_gadget, "Enabling %s", dep->name);
if (!(dep->flags & DWC3_EP_ENABLED)) {
ret = dwc3_gadget_start_config(dwc, dep);
@@ -729,10 +735,9 @@ static void dwc3_prepare_one_trb(struct dwc3_ep *dep,
struct dwc3_request *req, dma_addr_t dma,
unsigned length, unsigned last, unsigned chain, unsigned node)
{
- struct dwc3 *dwc = dep->dwc;
struct dwc3_trb *trb;
- dev_vdbg(dwc->dev, "%s: req %p dma %08llx length %d%s%s\n",
+ dwc3_trace(trace_dwc3_gadget, "%s: req %p dma %08llx length %d%s%s",
dep->name, req, (unsigned long long) dma,
length, last ? " last" : "",
chain ? " chain" : "");
@@ -934,7 +939,7 @@ static int __dwc3_gadget_kick_transfer(struct dwc3_ep *dep, u16 cmd_param,
u32 cmd;
if (start_new && (dep->flags & DWC3_EP_BUSY)) {
- dev_vdbg(dwc->dev, "%s: endpoint busy\n", dep->name);
+ dwc3_trace(trace_dwc3_gadget, "%s: endpoint busy", dep->name);
return -EBUSY;
}
dep->flags &= ~DWC3_EP_PENDING_REQUEST;
@@ -1005,8 +1010,9 @@ static void __dwc3_gadget_start_isoc(struct dwc3 *dwc,
u32 uf;
if (list_empty(&dep->request_list)) {
- dev_vdbg(dwc->dev, "ISOC ep %s run out for requests.\n",
- dep->name);
+ dwc3_trace(trace_dwc3_gadget,
+ "ISOC ep %s run out for requests",
+ dep->name);
dep->flags |= DWC3_EP_PENDING_REQUEST;
return;
}
@@ -1113,15 +1119,10 @@ static int __dwc3_gadget_ep_queue(struct dwc3_ep *dep, struct dwc3_request *req)
* handled.
*/
if (dep->stream_capable) {
- int ret;
-
ret = __dwc3_gadget_kick_transfer(dep, 0, true);
- if (ret && ret != -EBUSY) {
- struct dwc3 *dwc = dep->dwc;
-
+ if (ret && ret != -EBUSY)
dev_dbg(dwc->dev, "%s: failed to kick transfers\n",
dep->name);
- }
}
return 0;
@@ -1152,8 +1153,6 @@ static int dwc3_gadget_ep_queue(struct usb_ep *ep, struct usb_request *request,
goto out;
}
- dev_vdbg(dwc->dev, "queing request %p to %s length %d\n",
- request, ep->name, request->length);
trace_dwc3_ep_queue(req);
ret = __dwc3_gadget_ep_queue(dep, req);
@@ -1416,7 +1415,7 @@ static int dwc3_gadget_set_selfpowered(struct usb_gadget *g,
unsigned long flags;
spin_lock_irqsave(&dwc->lock, flags);
- dwc->is_selfpowered = !!is_selfpowered;
+ g->is_selfpowered = !!is_selfpowered;
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
@@ -1468,7 +1467,7 @@ static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
udelay(1);
} while (1);
- dev_vdbg(dwc->dev, "gadget %s data soft-%s\n",
+ dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
dwc->gadget_driver
? dwc->gadget_driver->function : "no-function",
is_on ? "connect" : "disconnect");
@@ -1688,7 +1687,7 @@ static int dwc3_gadget_init_hw_endpoints(struct dwc3 *dwc,
dep->endpoint.name = dep->name;
- dev_vdbg(dwc->dev, "initializing %s\n", dep->name);
+ dwc3_trace(trace_dwc3_gadget, "initializing %s", dep->name);
if (epnum == 0 || epnum == 1) {
usb_ep_set_maxpacket_limit(&dep->endpoint, 512);
@@ -1725,13 +1724,15 @@ static int dwc3_gadget_init_endpoints(struct dwc3 *dwc)
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_out_eps, 0);
if (ret < 0) {
- dev_vdbg(dwc->dev, "failed to allocate OUT endpoints\n");
+ dwc3_trace(trace_dwc3_gadget,
+ "failed to allocate OUT endpoints");
return ret;
}
ret = dwc3_gadget_init_hw_endpoints(dwc, dwc->num_in_eps, 1);
if (ret < 0) {
- dev_vdbg(dwc->dev, "failed to allocate IN endpoints\n");
+ dwc3_trace(trace_dwc3_gadget,
+ "failed to allocate IN endpoints");
return ret;
}
@@ -1977,7 +1978,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
} else {
int ret;
- dev_vdbg(dwc->dev, "%s: reason %s\n",
+ dwc3_trace(trace_dwc3_gadget, "%s: reason %s",
dep->name, event->status &
DEPEVT_STATUS_TRANSFER_ACTIVE
? "Transfer Active"
@@ -2001,7 +2002,8 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
switch (event->status) {
case DEPEVT_STREAMEVT_FOUND:
- dev_vdbg(dwc->dev, "Stream %d found and started\n",
+ dwc3_trace(trace_dwc3_gadget,
+ "Stream %d found and started",
event->parameters);
break;
@@ -2015,7 +2017,7 @@ static void dwc3_endpoint_interrupt(struct dwc3 *dwc,
dev_dbg(dwc->dev, "%s FIFO Overrun\n", dep->name);
break;
case DWC3_DEPEVT_EPCMDCMPLT:
- dev_vdbg(dwc->dev, "Endpoint Command Complete\n");
+ dwc3_trace(trace_dwc3_gadget, "Endpoint Command Complete");
break;
}
}
@@ -2043,6 +2045,7 @@ static void dwc3_resume_gadget(struct dwc3 *dwc)
if (dwc->gadget_driver && dwc->gadget_driver->resume) {
spin_unlock(&dwc->lock);
dwc->gadget_driver->resume(&dwc->gadget);
+ spin_lock(&dwc->lock);
}
}
@@ -2079,7 +2082,7 @@ static void dwc3_stop_active_transfer(struct dwc3 *dwc, u32 epnum, bool force)
* We have discussed this with the IP Provider and it was
* suggested to giveback all requests here, but give HW some
* extra time to synchronize with the interconnect. We're using
- * an arbitraty 100us delay for that.
+ * an arbitrary 100us delay for that.
*
* Note also that a similar handling was tested by Synopsys
* (thanks a lot Paul) and nothing bad has come out of it.
@@ -2389,7 +2392,8 @@ static void dwc3_gadget_linksts_change_interrupt(struct dwc3 *dwc,
(pwropt != DWC3_GHWPARAMS1_EN_PWROPT_HIB)) {
if ((dwc->link_state == DWC3_LINK_STATE_U3) &&
(next == DWC3_LINK_STATE_RESUME)) {
- dev_vdbg(dwc->dev, "ignoring transition U3 -> Resume\n");
+ dwc3_trace(trace_dwc3_gadget,
+ "ignoring transition U3 -> Resume");
return;
}
}
@@ -2511,22 +2515,22 @@ static void dwc3_gadget_interrupt(struct dwc3 *dwc,
dwc3_gadget_linksts_change_interrupt(dwc, event->event_info);
break;
case DWC3_DEVICE_EVENT_EOPF:
- dev_vdbg(dwc->dev, "End of Periodic Frame\n");
+ dwc3_trace(trace_dwc3_gadget, "End of Periodic Frame");
break;
case DWC3_DEVICE_EVENT_SOF:
- dev_vdbg(dwc->dev, "Start of Periodic Frame\n");
+ dwc3_trace(trace_dwc3_gadget, "Start of Periodic Frame");
break;
case DWC3_DEVICE_EVENT_ERRATIC_ERROR:
- dev_vdbg(dwc->dev, "Erratic Error\n");
+ dwc3_trace(trace_dwc3_gadget, "Erratic Error");
break;
case DWC3_DEVICE_EVENT_CMD_CMPL:
- dev_vdbg(dwc->dev, "Command Complete\n");
+ dwc3_trace(trace_dwc3_gadget, "Command Complete");
break;
case DWC3_DEVICE_EVENT_OVERFLOW:
- dev_vdbg(dwc->dev, "Overflow\n");
+ dwc3_trace(trace_dwc3_gadget, "Overflow");
break;
default:
- dev_dbg(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
+ dev_WARN(dwc->dev, "UNKNOWN IRQ %d\n", event->type);
}
}
diff --git a/drivers/usb/dwc3/trace.h b/drivers/usb/dwc3/trace.h
index 9fc20b33dd8e..9c10669ab91f 100644
--- a/drivers/usb/dwc3/trace.h
+++ b/drivers/usb/dwc3/trace.h
@@ -47,6 +47,16 @@ DEFINE_EVENT(dwc3_log_msg, dwc3_writel,
TP_ARGS(vaf)
);
+DEFINE_EVENT(dwc3_log_msg, dwc3_gadget,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(dwc3_log_msg, dwc3_core,
+ TP_PROTO(struct va_format *vaf),
+ TP_ARGS(vaf)
+);
+
DEFINE_EVENT(dwc3_log_msg, dwc3_ep0,
TP_PROTO(struct va_format *vaf),
TP_ARGS(vaf)
diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
index 747ef53bda14..b454d05be583 100644
--- a/drivers/usb/gadget/Kconfig
+++ b/drivers/usb/gadget/Kconfig
@@ -45,7 +45,7 @@ menuconfig USB_GADGET
if USB_GADGET
config USB_GADGET_DEBUG
- boolean "Debugging messages (DEVELOPMENT)"
+ bool "Debugging messages (DEVELOPMENT)"
depends on DEBUG_KERNEL
help
Many controller and gadget drivers will print some debugging
@@ -73,7 +73,7 @@ config USB_GADGET_VERBOSE
production build.
config USB_GADGET_DEBUG_FILES
- boolean "Debugging information files (DEVELOPMENT)"
+ bool "Debugging information files (DEVELOPMENT)"
depends on PROC_FS
help
Some of the drivers in the "gadget" framework can expose
@@ -84,7 +84,7 @@ config USB_GADGET_DEBUG_FILES
here. If in doubt, or to conserve kernel memory, say "N".
config USB_GADGET_DEBUG_FS
- boolean "Debugging information files in debugfs (DEVELOPMENT)"
+ bool "Debugging information files in debugfs (DEVELOPMENT)"
depends on DEBUG_FS
help
Some of the drivers in the "gadget" framework can expose
@@ -230,7 +230,7 @@ config USB_CONFIGFS
For more information see Documentation/usb/gadget_configfs.txt.
config USB_CONFIGFS_SERIAL
- boolean "Generic serial bulk in/out"
+ bool "Generic serial bulk in/out"
depends on USB_CONFIGFS
depends on TTY
select USB_U_SERIAL
@@ -239,7 +239,7 @@ config USB_CONFIGFS_SERIAL
The function talks to the Linux-USB generic serial driver.
config USB_CONFIGFS_ACM
- boolean "Abstract Control Model (CDC ACM)"
+ bool "Abstract Control Model (CDC ACM)"
depends on USB_CONFIGFS
depends on TTY
select USB_U_SERIAL
@@ -249,7 +249,7 @@ config USB_CONFIGFS_ACM
MS-Windows hosts or with the Linux-USB "cdc-acm" driver.
config USB_CONFIGFS_OBEX
- boolean "Object Exchange Model (CDC OBEX)"
+ bool "Object Exchange Model (CDC OBEX)"
depends on USB_CONFIGFS
depends on TTY
select USB_U_SERIAL
@@ -259,7 +259,7 @@ config USB_CONFIGFS_OBEX
since the kernel itself doesn't implement the OBEX protocol.
config USB_CONFIGFS_NCM
- boolean "Network Control Model (CDC NCM)"
+ bool "Network Control Model (CDC NCM)"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
@@ -270,7 +270,7 @@ config USB_CONFIGFS_NCM
different alignment possibilities.
config USB_CONFIGFS_ECM
- boolean "Ethernet Control Model (CDC ECM)"
+ bool "Ethernet Control Model (CDC ECM)"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
@@ -282,7 +282,7 @@ config USB_CONFIGFS_ECM
supported by firmware for smart network devices.
config USB_CONFIGFS_ECM_SUBSET
- boolean "Ethernet Control Model (CDC ECM) subset"
+ bool "Ethernet Control Model (CDC ECM) subset"
depends on USB_CONFIGFS
depends on NET
select USB_U_ETHER
@@ -323,7 +323,7 @@ config USB_CONFIGFS_EEM
the host is the same (a usbX device), so the differences are minimal.
config USB_CONFIGFS_PHONET
- boolean "Phonet protocol"
+ bool "Phonet protocol"
depends on USB_CONFIGFS
depends on NET
depends on PHONET
@@ -333,7 +333,7 @@ config USB_CONFIGFS_PHONET
The Phonet protocol implementation for USB device.
config USB_CONFIGFS_MASS_STORAGE
- boolean "Mass storage"
+ bool "Mass storage"
depends on USB_CONFIGFS
depends on BLOCK
select USB_F_MASS_STORAGE
@@ -344,7 +344,7 @@ config USB_CONFIGFS_MASS_STORAGE
specified as a module parameter or sysfs option.
config USB_CONFIGFS_F_LB_SS
- boolean "Loopback and sourcesink function (for testing)"
+ bool "Loopback and sourcesink function (for testing)"
depends on USB_CONFIGFS
select USB_F_SS_LB
help
@@ -357,7 +357,7 @@ config USB_CONFIGFS_F_LB_SS
and its driver through a basic set of functional tests.
config USB_CONFIGFS_F_FS
- boolean "Function filesystem (FunctionFS)"
+ bool "Function filesystem (FunctionFS)"
depends on USB_CONFIGFS
select USB_F_FS
help
@@ -369,7 +369,7 @@ config USB_CONFIGFS_F_FS
mass storage) and other are implemented in user space.
config USB_CONFIGFS_F_UAC1
- boolean "Audio Class 1.0"
+ bool "Audio Class 1.0"
depends on USB_CONFIGFS
depends on SND
select USB_LIBCOMPOSITE
@@ -382,7 +382,7 @@ config USB_CONFIGFS_F_UAC1
on the device.
config USB_CONFIGFS_F_UAC2
- boolean "Audio Class 2.0"
+ bool "Audio Class 2.0"
depends on USB_CONFIGFS
depends on SND
select USB_LIBCOMPOSITE
@@ -400,7 +400,7 @@ config USB_CONFIGFS_F_UAC2
wants as audio data to the USB Host.
config USB_CONFIGFS_F_MIDI
- boolean "MIDI function"
+ bool "MIDI function"
depends on USB_CONFIGFS
depends on SND
select USB_LIBCOMPOSITE
@@ -414,7 +414,7 @@ config USB_CONFIGFS_F_MIDI
ALSA's aconnect utility etc.
config USB_CONFIGFS_F_HID
- boolean "HID function"
+ bool "HID function"
depends on USB_CONFIGFS
select USB_F_HID
help
@@ -423,6 +423,17 @@ config USB_CONFIGFS_F_HID
For more information, see Documentation/usb/gadget_hid.txt.
+config USB_CONFIGFS_F_UVC
+ bool "USB Webcam function"
+ depends on USB_CONFIGFS
+ depends on VIDEO_DEV
+ select VIDEOBUF2_VMALLOC
+ select USB_F_UVC
+ help
+ The Webcam function acts as a composite USB Audio and Video Class
+ device. It provides a userspace API to process UVC control requests
+ and stream video data to the host.
+
source "drivers/usb/gadget/legacy/Kconfig"
endchoice
diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index 617835348569..13adfd1a3f54 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1655,7 +1655,7 @@ unknown:
* OS descriptors handling
*/
if (cdev->use_os_string && cdev->os_desc_config &&
- (ctrl->bRequest & USB_TYPE_VENDOR) &&
+ (ctrl->bRequestType & USB_TYPE_VENDOR) &&
ctrl->bRequest == cdev->b_vendor_code) {
struct usb_request *req;
struct usb_configuration *os_desc_cfg;
diff --git a/drivers/usb/gadget/function/Makefile b/drivers/usb/gadget/function/Makefile
index dd68091d92f0..f71b1aaa0edf 100644
--- a/drivers/usb/gadget/function/Makefile
+++ b/drivers/usb/gadget/function/Makefile
@@ -36,7 +36,7 @@ usb_f_uac1-y := f_uac1.o u_uac1.o
obj-$(CONFIG_USB_F_UAC1) += usb_f_uac1.o
usb_f_uac2-y := f_uac2.o
obj-$(CONFIG_USB_F_UAC2) += usb_f_uac2.o
-usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o
+usb_f_uvc-y := f_uvc.o uvc_queue.o uvc_v4l2.o uvc_video.o uvc_configfs.o
obj-$(CONFIG_USB_F_UVC) += usb_f_uvc.o
usb_f_midi-y := f_midi.o
obj-$(CONFIG_USB_F_MIDI) += usb_f_midi.o
diff --git a/drivers/usb/gadget/function/f_fs.c b/drivers/usb/gadget/function/f_fs.c
index 63314ede7ba6..af98b096af2f 100644
--- a/drivers/usb/gadget/function/f_fs.c
+++ b/drivers/usb/gadget/function/f_fs.c
@@ -31,6 +31,7 @@
#include <linux/aio.h>
#include <linux/mmu_context.h>
#include <linux/poll.h>
+#include <linux/eventfd.h>
#include "u_fs.h"
#include "u_f.h"
@@ -153,6 +154,8 @@ struct ffs_io_data {
struct usb_ep *ep;
struct usb_request *req;
+
+ struct ffs_data *ffs;
};
struct ffs_desc_helper {
@@ -390,17 +393,20 @@ done_spin:
return ret;
}
+/* Called with ffs->ev.waitq.lock and ffs->mutex held, both released on exit. */
static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
size_t n)
{
/*
- * We are holding ffs->ev.waitq.lock and ffs->mutex and we need
- * to release them.
+ * n cannot be bigger than ffs->ev.count, which cannot be bigger than
+ * size of ffs->ev.types array (which is four) so that's how much space
+ * we reserve.
*/
- struct usb_functionfs_event events[n];
+ struct usb_functionfs_event events[ARRAY_SIZE(ffs->ev.types)];
+ const size_t size = n * sizeof *events;
unsigned i = 0;
- memset(events, 0, sizeof events);
+ memset(events, 0, size);
do {
events[i].type = ffs->ev.types[i];
@@ -410,19 +416,15 @@ static ssize_t __ffs_ep0_read_events(struct ffs_data *ffs, char __user *buf,
}
} while (++i < n);
- if (n < ffs->ev.count) {
- ffs->ev.count -= n;
+ ffs->ev.count -= n;
+ if (ffs->ev.count)
memmove(ffs->ev.types, ffs->ev.types + n,
ffs->ev.count * sizeof *ffs->ev.types);
- } else {
- ffs->ev.count = 0;
- }
spin_unlock_irq(&ffs->ev.waitq.lock);
mutex_unlock(&ffs->mutex);
- return unlikely(__copy_to_user(buf, events, sizeof events))
- ? -EFAULT : sizeof events;
+ return unlikely(__copy_to_user(buf, events, size)) ? -EFAULT : size;
}
static ssize_t ffs_ep0_read(struct file *file, char __user *buf,
@@ -606,6 +608,8 @@ static unsigned int ffs_ep0_poll(struct file *file, poll_table *wait)
}
case FFS_CLOSING:
break;
+ case FFS_DEACTIVATED:
+ break;
}
mutex_unlock(&ffs->mutex);
@@ -673,6 +677,9 @@ static void ffs_user_copy_worker(struct work_struct *work)
aio_complete(io_data->kiocb, ret, ret);
+ if (io_data->ffs->ffs_eventfd && !io_data->kiocb->ki_eventfd)
+ eventfd_signal(io_data->ffs->ffs_eventfd, 1);
+
usb_ep_free_request(io_data->ep, io_data->req);
io_data->kiocb->private = NULL;
@@ -826,6 +833,7 @@ static ssize_t ffs_epfile_io(struct file *file, struct ffs_io_data *io_data)
io_data->buf = data;
io_data->ep = ep->ep;
io_data->req = req;
+ io_data->ffs = epfile->ffs;
req->context = io_data;
req->complete = ffs_epfile_async_io_complete;
@@ -1180,6 +1188,7 @@ struct ffs_sb_fill_data {
struct ffs_file_perms perms;
umode_t root_mode;
const char *dev_name;
+ bool no_disconnect;
struct ffs_data *ffs_data;
};
@@ -1250,6 +1259,12 @@ static int ffs_fs_parse_opts(struct ffs_sb_fill_data *data, char *opts)
/* Interpret option */
switch (eq - opts) {
+ case 13:
+ if (!memcmp(opts, "no_disconnect", 13))
+ data->no_disconnect = !!value;
+ else
+ goto invalid;
+ break;
case 5:
if (!memcmp(opts, "rmode", 5))
data->root_mode = (value & 0555) | S_IFDIR;
@@ -1314,6 +1329,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
.gid = GLOBAL_ROOT_GID,
},
.root_mode = S_IFDIR | 0500,
+ .no_disconnect = false,
};
struct dentry *rv;
int ret;
@@ -1330,6 +1346,7 @@ ffs_fs_mount(struct file_system_type *t, int flags,
if (unlikely(!ffs))
return ERR_PTR(-ENOMEM);
ffs->file_perms = data.perms;
+ ffs->no_disconnect = data.no_disconnect;
ffs->dev_name = kstrdup(dev_name, GFP_KERNEL);
if (unlikely(!ffs->dev_name)) {
@@ -1361,6 +1378,7 @@ ffs_fs_kill_sb(struct super_block *sb)
kill_litter_super(sb);
if (sb->s_fs_info) {
ffs_release_dev(sb->s_fs_info);
+ ffs_data_closed(sb->s_fs_info);
ffs_data_put(sb->s_fs_info);
}
}
@@ -1417,7 +1435,11 @@ static void ffs_data_opened(struct ffs_data *ffs)
ENTER();
atomic_inc(&ffs->ref);
- atomic_inc(&ffs->opened);
+ if (atomic_add_return(1, &ffs->opened) == 1 &&
+ ffs->state == FFS_DEACTIVATED) {
+ ffs->state = FFS_CLOSING;
+ ffs_data_reset(ffs);
+ }
}
static void ffs_data_put(struct ffs_data *ffs)
@@ -1439,6 +1461,21 @@ static void ffs_data_closed(struct ffs_data *ffs)
ENTER();
if (atomic_dec_and_test(&ffs->opened)) {
+ if (ffs->no_disconnect) {
+ ffs->state = FFS_DEACTIVATED;
+ if (ffs->epfiles) {
+ ffs_epfiles_destroy(ffs->epfiles,
+ ffs->eps_count);
+ ffs->epfiles = NULL;
+ }
+ if (ffs->setup_state == FFS_SETUP_PENDING)
+ __ffs_ep0_stall(ffs);
+ } else {
+ ffs->state = FFS_CLOSING;
+ ffs_data_reset(ffs);
+ }
+ }
+ if (atomic_read(&ffs->opened) < 0) {
ffs->state = FFS_CLOSING;
ffs_data_reset(ffs);
}
@@ -1480,6 +1517,9 @@ static void ffs_data_clear(struct ffs_data *ffs)
if (ffs->epfiles)
ffs_epfiles_destroy(ffs->epfiles, ffs->eps_count);
+ if (ffs->ffs_eventfd)
+ eventfd_ctx_put(ffs->ffs_eventfd);
+
kfree(ffs->raw_descs_data);
kfree(ffs->raw_strings);
kfree(ffs->stringtabs);
@@ -1581,10 +1621,10 @@ static int ffs_epfiles_create(struct ffs_data *ffs)
mutex_init(&epfile->mutex);
init_waitqueue_head(&epfile->wait);
if (ffs->user_flags & FUNCTIONFS_VIRTUAL_ADDR)
- sprintf(epfiles->name, "ep%02x", ffs->eps_addrmap[i]);
+ sprintf(epfile->name, "ep%02x", ffs->eps_addrmap[i]);
else
- sprintf(epfiles->name, "ep%u", i);
- epfile->dentry = ffs_sb_create_file(ffs->sb, epfiles->name,
+ sprintf(epfile->name, "ep%u", i);
+ epfile->dentry = ffs_sb_create_file(ffs->sb, epfile->name,
epfile,
&ffs_epfile_operations);
if (unlikely(!epfile->dentry)) {
@@ -1616,7 +1656,6 @@ static void ffs_epfiles_destroy(struct ffs_epfile *epfiles, unsigned count)
kfree(epfiles);
}
-
static void ffs_func_eps_disable(struct ffs_function *func)
{
struct ffs_ep *ep = func->eps;
@@ -1629,10 +1668,12 @@ static void ffs_func_eps_disable(struct ffs_function *func)
/* pending requests get nuked */
if (likely(ep->ep))
usb_ep_disable(ep->ep);
- epfile->ep = NULL;
-
++ep;
- ++epfile;
+
+ if (epfile) {
+ epfile->ep = NULL;
+ ++epfile;
+ }
} while (--count);
spin_unlock_irqrestore(&func->ffs->eps_lock, flags);
}
@@ -2138,7 +2179,8 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
FUNCTIONFS_HAS_HS_DESC |
FUNCTIONFS_HAS_SS_DESC |
FUNCTIONFS_HAS_MS_OS_DESC |
- FUNCTIONFS_VIRTUAL_ADDR)) {
+ FUNCTIONFS_VIRTUAL_ADDR |
+ FUNCTIONFS_EVENTFD)) {
ret = -ENOSYS;
goto error;
}
@@ -2149,6 +2191,20 @@ static int __ffs_data_got_descs(struct ffs_data *ffs,
goto error;
}
+ if (flags & FUNCTIONFS_EVENTFD) {
+ if (len < 4)
+ goto error;
+ ffs->ffs_eventfd =
+ eventfd_ctx_fdget((int)get_unaligned_le32(data));
+ if (IS_ERR(ffs->ffs_eventfd)) {
+ ret = PTR_ERR(ffs->ffs_eventfd);
+ ffs->ffs_eventfd = NULL;
+ goto error;
+ }
+ data += 4;
+ len -= 4;
+ }
+
/* Read fs_count, hs_count and ss_count (if present) */
for (i = 0; i < 3; ++i) {
if (!(flags & (1 << i))) {
@@ -2377,6 +2433,13 @@ static void __ffs_event_add(struct ffs_data *ffs,
if (ffs->setup_state == FFS_SETUP_PENDING)
ffs->setup_state = FFS_SETUP_CANCELLED;
+ /*
+ * Logic of this function guarantees that there are at most four pending
+ * evens on ffs->ev.types queue. This is important because the queue
+ * has space for four elements only and __ffs_ep0_read_events function
+ * depends on that limit as well. If more event types are added, those
+ * limits have to be revisited or guaranteed to still hold.
+ */
switch (type) {
case FUNCTIONFS_RESUME:
rem_type2 = FUNCTIONFS_SUSPEND;
@@ -2416,6 +2479,8 @@ static void __ffs_event_add(struct ffs_data *ffs,
pr_vdebug("adding event %d\n", type);
ffs->ev.types[ffs->ev.count++] = type;
wake_up_locked(&ffs->ev.waitq);
+ if (ffs->ffs_eventfd)
+ eventfd_signal(ffs->ffs_eventfd, 1);
}
static void ffs_event_add(struct ffs_data *ffs,
@@ -2888,6 +2953,13 @@ static int ffs_func_bind(struct usb_configuration *c,
/* Other USB function hooks *************************************************/
+static void ffs_reset_work(struct work_struct *work)
+{
+ struct ffs_data *ffs = container_of(work,
+ struct ffs_data, reset_work);
+ ffs_data_reset(ffs);
+}
+
static int ffs_func_set_alt(struct usb_function *f,
unsigned interface, unsigned alt)
{
@@ -2904,6 +2976,13 @@ static int ffs_func_set_alt(struct usb_function *f,
if (ffs->func)
ffs_func_eps_disable(ffs->func);
+ if (ffs->state == FFS_DEACTIVATED) {
+ ffs->state = FFS_CLOSING;
+ INIT_WORK(&ffs->reset_work, ffs_reset_work);
+ schedule_work(&ffs->reset_work);
+ return -ENODEV;
+ }
+
if (ffs->state != FFS_ACTIVE)
return -ENODEV;
diff --git a/drivers/usb/gadget/function/f_hid.c b/drivers/usb/gadget/function/f_hid.c
index a1bc3e3a0b09..426d69a9c018 100644
--- a/drivers/usb/gadget/function/f_hid.c
+++ b/drivers/usb/gadget/function/f_hid.c
@@ -759,7 +759,7 @@ static struct f_hid_opts_attribute f_hid_opts_##name = \
F_HID_OPT(subclass, 8, 255);
F_HID_OPT(protocol, 8, 255);
-F_HID_OPT(report_length, 16, 65536);
+F_HID_OPT(report_length, 16, 65535);
static ssize_t f_hid_opts_report_desc_show(struct f_hid_opts *opts, char *page)
{
diff --git a/drivers/usb/gadget/function/f_sourcesink.c b/drivers/usb/gadget/function/f_sourcesink.c
index 80be25b32cd7..e07c50ced64d 100644
--- a/drivers/usb/gadget/function/f_sourcesink.c
+++ b/drivers/usb/gadget/function/f_sourcesink.c
@@ -1214,7 +1214,7 @@ static ssize_t f_ss_opts_pattern_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->pattern);
+ result = sprintf(page, "%u", opts->pattern);
mutex_unlock(&opts->lock);
return result;
@@ -1258,7 +1258,7 @@ static ssize_t f_ss_opts_isoc_interval_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->isoc_interval);
+ result = sprintf(page, "%u", opts->isoc_interval);
mutex_unlock(&opts->lock);
return result;
@@ -1302,7 +1302,7 @@ static ssize_t f_ss_opts_isoc_maxpacket_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->isoc_maxpacket);
+ result = sprintf(page, "%u", opts->isoc_maxpacket);
mutex_unlock(&opts->lock);
return result;
@@ -1346,7 +1346,7 @@ static ssize_t f_ss_opts_isoc_mult_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->isoc_mult);
+ result = sprintf(page, "%u", opts->isoc_mult);
mutex_unlock(&opts->lock);
return result;
@@ -1390,7 +1390,7 @@ static ssize_t f_ss_opts_isoc_maxburst_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->isoc_maxburst);
+ result = sprintf(page, "%u", opts->isoc_maxburst);
mutex_unlock(&opts->lock);
return result;
@@ -1434,7 +1434,7 @@ static ssize_t f_ss_opts_bulk_buflen_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->bulk_buflen);
+ result = sprintf(page, "%u", opts->bulk_buflen);
mutex_unlock(&opts->lock);
return result;
@@ -1473,7 +1473,7 @@ static ssize_t f_ss_opts_int_interval_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->int_interval);
+ result = sprintf(page, "%u", opts->int_interval);
mutex_unlock(&opts->lock);
return result;
@@ -1517,7 +1517,7 @@ static ssize_t f_ss_opts_int_maxpacket_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->int_maxpacket);
+ result = sprintf(page, "%u", opts->int_maxpacket);
mutex_unlock(&opts->lock);
return result;
@@ -1561,7 +1561,7 @@ static ssize_t f_ss_opts_int_mult_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->int_mult);
+ result = sprintf(page, "%u", opts->int_mult);
mutex_unlock(&opts->lock);
return result;
@@ -1605,7 +1605,7 @@ static ssize_t f_ss_opts_int_maxburst_show(struct f_ss_opts *opts, char *page)
int result;
mutex_lock(&opts->lock);
- result = sprintf(page, "%d", opts->int_maxburst);
+ result = sprintf(page, "%u", opts->int_maxburst);
mutex_unlock(&opts->lock);
return result;
diff --git a/drivers/usb/gadget/function/f_uac1.c b/drivers/usb/gadget/function/f_uac1.c
index e9715845f82e..9719abfb6145 100644
--- a/drivers/usb/gadget/function/f_uac1.c
+++ b/drivers/usb/gadget/function/f_uac1.c
@@ -31,7 +31,7 @@ static int generic_get_cmd(struct usb_audio_control *con, u8 cmd);
*/
#define F_AUDIO_AC_INTERFACE 0
#define F_AUDIO_AS_INTERFACE 1
-#define F_AUDIO_NUM_INTERFACES 2
+#define F_AUDIO_NUM_INTERFACES 1
/* B.3.1 Standard AC Interface Descriptor */
static struct usb_interface_descriptor ac_interface_desc = {
@@ -42,14 +42,18 @@ static struct usb_interface_descriptor ac_interface_desc = {
.bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
};
-DECLARE_UAC_AC_HEADER_DESCRIPTOR(2);
+/*
+ * The number of AudioStreaming and MIDIStreaming interfaces
+ * in the Audio Interface Collection
+ */
+DECLARE_UAC_AC_HEADER_DESCRIPTOR(1);
#define UAC_DT_AC_HEADER_LENGTH UAC_DT_AC_HEADER_SIZE(F_AUDIO_NUM_INTERFACES)
/* 1 input terminal, 1 output terminal and 1 feature unit */
#define UAC_DT_TOTAL_LENGTH (UAC_DT_AC_HEADER_LENGTH + UAC_DT_INPUT_TERMINAL_SIZE \
+ UAC_DT_OUTPUT_TERMINAL_SIZE + UAC_DT_FEATURE_UNIT_SIZE(0))
/* B.3.2 Class-Specific AC Interface Descriptor */
-static struct uac1_ac_header_descriptor_2 ac_header_desc = {
+static struct uac1_ac_header_descriptor_1 ac_header_desc = {
.bLength = UAC_DT_AC_HEADER_LENGTH,
.bDescriptorType = USB_DT_CS_INTERFACE,
.bDescriptorSubtype = UAC_HEADER,
@@ -57,8 +61,8 @@ static struct uac1_ac_header_descriptor_2 ac_header_desc = {
.wTotalLength = __constant_cpu_to_le16(UAC_DT_TOTAL_LENGTH),
.bInCollection = F_AUDIO_NUM_INTERFACES,
.baInterfaceNr = {
- [0] = F_AUDIO_AC_INTERFACE,
- [1] = F_AUDIO_AS_INTERFACE,
+ /* Interface number of the first AudioStream interface */
+ [0] = 1,
}
};
@@ -584,6 +588,7 @@ static int f_audio_set_alt(struct usb_function *f, unsigned intf, unsigned alt)
if (intf == 1) {
if (alt == 1) {
+ config_ep_by_speed(cdev->gadget, f, out_ep);
usb_ep_enable(out_ep);
out_ep->driver_data = audio;
audio->copy_buf = f_audio_buffer_alloc(audio_buf_size);
@@ -669,7 +674,6 @@ f_audio_bind(struct usb_configuration *c, struct usb_function *f)
audio_opts = container_of(f->fi, struct f_uac1_opts, func_inst);
audio->card.gadget = c->cdev->gadget;
- audio_opts->card = &audio->card;
/* set up ASLA audio devices */
if (!audio_opts->bound) {
status = gaudio_setup(&audio->card);
diff --git a/drivers/usb/gadget/function/f_uvc.c b/drivers/usb/gadget/function/f_uvc.c
index 945b3bd2ca98..76891adfba7a 100644
--- a/drivers/usb/gadget/function/f_uvc.c
+++ b/drivers/usb/gadget/function/f_uvc.c
@@ -27,10 +27,11 @@
#include <media/v4l2-dev.h>
#include <media/v4l2-event.h>
+#include "u_uvc.h"
#include "uvc.h"
+#include "uvc_configfs.h"
#include "uvc_v4l2.h"
#include "uvc_video.h"
-#include "u_uvc.h"
unsigned int uvc_gadget_trace_param;
@@ -509,6 +510,9 @@ uvc_copy_descriptors(struct uvc_device *uvc, enum usb_device_speed speed)
break;
}
+ if (!uvc_control_desc || !uvc_streaming_cls)
+ return ERR_PTR(-ENODEV);
+
/* Descriptors layout
*
* uvc_iad
@@ -605,7 +609,7 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
INFO(cdev, "uvc_function_bind\n");
- opts = to_f_uvc_opts(f->fi);
+ opts = fi_to_f_uvc_opts(f->fi);
/* Sanity check the streaming endpoint module parameters.
*/
opts->streaming_interval = clamp(opts->streaming_interval, 1U, 16U);
@@ -700,10 +704,27 @@ uvc_function_bind(struct usb_configuration *c, struct usb_function *f)
/* Copy descriptors */
f->fs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_FULL);
- if (gadget_is_dualspeed(cdev->gadget))
+ if (IS_ERR(f->fs_descriptors)) {
+ ret = PTR_ERR(f->fs_descriptors);
+ f->fs_descriptors = NULL;
+ goto error;
+ }
+ if (gadget_is_dualspeed(cdev->gadget)) {
f->hs_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_HIGH);
- if (gadget_is_superspeed(c->cdev->gadget))
+ if (IS_ERR(f->hs_descriptors)) {
+ ret = PTR_ERR(f->hs_descriptors);
+ f->hs_descriptors = NULL;
+ goto error;
+ }
+ }
+ if (gadget_is_superspeed(c->cdev->gadget)) {
f->ss_descriptors = uvc_copy_descriptors(uvc, USB_SPEED_SUPER);
+ if (IS_ERR(f->ss_descriptors)) {
+ ret = PTR_ERR(f->ss_descriptors);
+ f->ss_descriptors = NULL;
+ goto error;
+ }
+ }
/* Preallocate control endpoint request. */
uvc->control_req = usb_ep_alloc_request(cdev->gadget->ep0, GFP_KERNEL);
@@ -766,27 +787,106 @@ error:
static void uvc_free_inst(struct usb_function_instance *f)
{
- struct f_uvc_opts *opts = to_f_uvc_opts(f);
+ struct f_uvc_opts *opts = fi_to_f_uvc_opts(f);
+ mutex_destroy(&opts->lock);
kfree(opts);
}
static struct usb_function_instance *uvc_alloc_inst(void)
{
struct f_uvc_opts *opts;
+ struct uvc_camera_terminal_descriptor *cd;
+ struct uvc_processing_unit_descriptor *pd;
+ struct uvc_output_terminal_descriptor *od;
+ struct uvc_color_matching_descriptor *md;
+ struct uvc_descriptor_header **ctl_cls;
opts = kzalloc(sizeof(*opts), GFP_KERNEL);
if (!opts)
return ERR_PTR(-ENOMEM);
opts->func_inst.free_func_inst = uvc_free_inst;
-
+ mutex_init(&opts->lock);
+
+ cd = &opts->uvc_camera_terminal;
+ cd->bLength = UVC_DT_CAMERA_TERMINAL_SIZE(3);
+ cd->bDescriptorType = USB_DT_CS_INTERFACE;
+ cd->bDescriptorSubType = UVC_VC_INPUT_TERMINAL;
+ cd->bTerminalID = 1;
+ cd->wTerminalType = cpu_to_le16(0x0201);
+ cd->bAssocTerminal = 0;
+ cd->iTerminal = 0;
+ cd->wObjectiveFocalLengthMin = cpu_to_le16(0);
+ cd->wObjectiveFocalLengthMax = cpu_to_le16(0);
+ cd->wOcularFocalLength = cpu_to_le16(0);
+ cd->bControlSize = 3;
+ cd->bmControls[0] = 2;
+ cd->bmControls[1] = 0;
+ cd->bmControls[2] = 0;
+
+ pd = &opts->uvc_processing;
+ pd->bLength = UVC_DT_PROCESSING_UNIT_SIZE(2);
+ pd->bDescriptorType = USB_DT_CS_INTERFACE;
+ pd->bDescriptorSubType = UVC_VC_PROCESSING_UNIT;
+ pd->bUnitID = 2;
+ pd->bSourceID = 1;
+ pd->wMaxMultiplier = cpu_to_le16(16*1024);
+ pd->bControlSize = 2;
+ pd->bmControls[0] = 1;
+ pd->bmControls[1] = 0;
+ pd->iProcessing = 0;
+
+ od = &opts->uvc_output_terminal;
+ od->bLength = UVC_DT_OUTPUT_TERMINAL_SIZE;
+ od->bDescriptorType = USB_DT_CS_INTERFACE;
+ od->bDescriptorSubType = UVC_VC_OUTPUT_TERMINAL;
+ od->bTerminalID = 3;
+ od->wTerminalType = cpu_to_le16(0x0101);
+ od->bAssocTerminal = 0;
+ od->bSourceID = 2;
+ od->iTerminal = 0;
+
+ md = &opts->uvc_color_matching;
+ md->bLength = UVC_DT_COLOR_MATCHING_SIZE;
+ md->bDescriptorType = USB_DT_CS_INTERFACE;
+ md->bDescriptorSubType = UVC_VS_COLORFORMAT;
+ md->bColorPrimaries = 1;
+ md->bTransferCharacteristics = 1;
+ md->bMatrixCoefficients = 4;
+
+ /* Prepare fs control class descriptors for configfs-based gadgets */
+ ctl_cls = opts->uvc_fs_control_cls;
+ ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
+ ctl_cls[1] = (struct uvc_descriptor_header *)cd;
+ ctl_cls[2] = (struct uvc_descriptor_header *)pd;
+ ctl_cls[3] = (struct uvc_descriptor_header *)od;
+ ctl_cls[4] = NULL; /* NULL-terminate */
+ opts->fs_control =
+ (const struct uvc_descriptor_header * const *)ctl_cls;
+
+ /* Prepare hs control class descriptors for configfs-based gadgets */
+ ctl_cls = opts->uvc_ss_control_cls;
+ ctl_cls[0] = NULL; /* assigned elsewhere by configfs */
+ ctl_cls[1] = (struct uvc_descriptor_header *)cd;
+ ctl_cls[2] = (struct uvc_descriptor_header *)pd;
+ ctl_cls[3] = (struct uvc_descriptor_header *)od;
+ ctl_cls[4] = NULL; /* NULL-terminate */
+ opts->ss_control =
+ (const struct uvc_descriptor_header * const *)ctl_cls;
+
+ opts->streaming_interval = 1;
+ opts->streaming_maxpacket = 1024;
+
+ uvcg_attach_configfs(opts);
return &opts->func_inst;
}
static void uvc_free(struct usb_function *f)
{
struct uvc_device *uvc = to_uvc(f);
-
+ struct f_uvc_opts *opts = container_of(f->fi, struct f_uvc_opts,
+ func_inst);
+ --opts->refcnt;
kfree(uvc);
}
@@ -812,19 +912,39 @@ static struct usb_function *uvc_alloc(struct usb_function_instance *fi)
{
struct uvc_device *uvc;
struct f_uvc_opts *opts;
+ struct uvc_descriptor_header **strm_cls;
uvc = kzalloc(sizeof(*uvc), GFP_KERNEL);
if (uvc == NULL)
return ERR_PTR(-ENOMEM);
uvc->state = UVC_STATE_DISCONNECTED;
- opts = to_f_uvc_opts(fi);
+ opts = fi_to_f_uvc_opts(fi);
+
+ mutex_lock(&opts->lock);
+ if (opts->uvc_fs_streaming_cls) {
+ strm_cls = opts->uvc_fs_streaming_cls;
+ opts->fs_streaming =
+ (const struct uvc_descriptor_header * const *)strm_cls;
+ }
+ if (opts->uvc_hs_streaming_cls) {
+ strm_cls = opts->uvc_hs_streaming_cls;
+ opts->hs_streaming =
+ (const struct uvc_descriptor_header * const *)strm_cls;
+ }
+ if (opts->uvc_ss_streaming_cls) {
+ strm_cls = opts->uvc_ss_streaming_cls;
+ opts->ss_streaming =
+ (const struct uvc_descriptor_header * const *)strm_cls;
+ }
uvc->desc.fs_control = opts->fs_control;
uvc->desc.ss_control = opts->ss_control;
uvc->desc.fs_streaming = opts->fs_streaming;
uvc->desc.hs_streaming = opts->hs_streaming;
uvc->desc.ss_streaming = opts->ss_streaming;
+ ++opts->refcnt;
+ mutex_unlock(&opts->lock);
/* Register the function. */
uvc->func.name = "uvc";
diff --git a/drivers/usb/gadget/function/u_ether.c b/drivers/usb/gadget/function/u_ether.c
index 6e6f87656e7b..f1fd777ef4ec 100644
--- a/drivers/usb/gadget/function/u_ether.c
+++ b/drivers/usb/gadget/function/u_ether.c
@@ -729,9 +729,7 @@ static int get_ether_addr_str(u8 dev_addr[ETH_ALEN], char *str, int len)
if (len < 18)
return -EINVAL;
- snprintf(str, len, "%02x:%02x:%02x:%02x:%02x:%02x",
- dev_addr[0], dev_addr[1], dev_addr[2],
- dev_addr[3], dev_addr[4], dev_addr[5]);
+ snprintf(str, len, "%pM", dev_addr);
return 18;
}
diff --git a/drivers/usb/gadget/function/u_fs.h b/drivers/usb/gadget/function/u_fs.h
index cd128e31f808..60139854e0b1 100644
--- a/drivers/usb/gadget/function/u_fs.h
+++ b/drivers/usb/gadget/function/u_fs.h
@@ -19,6 +19,7 @@
#include <linux/usb/composite.h>
#include <linux/list.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#ifdef VERBOSE_DEBUG
#ifndef pr_vdebug
@@ -93,6 +94,26 @@ enum ffs_state {
FFS_ACTIVE,
/*
+ * Function is visible to host, but it's not functional. All
+ * setup requests are stalled and transfers on another endpoints
+ * are refused. All epfiles, except ep0, are deleted so there
+ * is no way to perform any operations on them.
+ *
+ * This state is set after closing all functionfs files, when
+ * mount parameter "no_disconnect=1" has been set. Function will
+ * remain in deactivated state until filesystem is umounted or
+ * ep0 is opened again. In the second case functionfs state will
+ * be reset, and it will be ready for descriptors and strings
+ * writing.
+ *
+ * This is useful only when functionfs is composed to gadget
+ * with another function which can perform some critical
+ * operations, and it's strongly desired to have this operations
+ * completed, even after functionfs files closure.
+ */
+ FFS_DEACTIVATED,
+
+ /*
* All endpoints have been closed. This state is also set if
* we encounter an unrecoverable error. The only
* unrecoverable error is situation when after reading strings
@@ -251,6 +272,10 @@ struct ffs_data {
kgid_t gid;
} file_perms;
+ struct eventfd_ctx *ffs_eventfd;
+ bool no_disconnect;
+ struct work_struct reset_work;
+
/*
* The endpoint files, filled by ffs_epfiles_create(),
* destroyed by ffs_epfiles_destroy().
diff --git a/drivers/usb/gadget/function/u_uac1.c b/drivers/usb/gadget/function/u_uac1.c
index 53842a1b947f..c78c84138a28 100644
--- a/drivers/usb/gadget/function/u_uac1.c
+++ b/drivers/usb/gadget/function/u_uac1.c
@@ -308,8 +308,7 @@ int gaudio_setup(struct gaudio *card)
*/
void gaudio_cleanup(struct gaudio *the_card)
{
- if (the_card) {
+ if (the_card)
gaudio_close_snd_dev(the_card);
- }
}
diff --git a/drivers/usb/gadget/function/u_uac1.h b/drivers/usb/gadget/function/u_uac1.h
index f8b17fe82efe..fe386df6dd3e 100644
--- a/drivers/usb/gadget/function/u_uac1.h
+++ b/drivers/usb/gadget/function/u_uac1.h
@@ -70,7 +70,6 @@ struct f_uac1_opts {
unsigned fn_play_alloc:1;
unsigned fn_cap_alloc:1;
unsigned fn_cntl_alloc:1;
- struct gaudio *card;
struct mutex lock;
int refcnt;
};
diff --git a/drivers/usb/gadget/function/u_uvc.h b/drivers/usb/gadget/function/u_uvc.h
index 2a8dfdff0332..4676b60a5063 100644
--- a/drivers/usb/gadget/function/u_uvc.h
+++ b/drivers/usb/gadget/function/u_uvc.h
@@ -17,8 +17,9 @@
#define U_UVC_H
#include <linux/usb/composite.h>
+#include <linux/usb/video.h>
-#define to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
+#define fi_to_f_uvc_opts(f) container_of(f, struct f_uvc_opts, func_inst)
struct f_uvc_opts {
struct usb_function_instance func_inst;
@@ -26,11 +27,60 @@ struct f_uvc_opts {
unsigned int streaming_interval;
unsigned int streaming_maxpacket;
unsigned int streaming_maxburst;
+
+ /*
+ * Control descriptors array pointers for full-/high-speed and
+ * super-speed. They point by default to the uvc_fs_control_cls and
+ * uvc_ss_control_cls arrays respectively. Legacy gadgets must
+ * override them in their gadget bind callback.
+ */
const struct uvc_descriptor_header * const *fs_control;
const struct uvc_descriptor_header * const *ss_control;
+
+ /*
+ * Streaming descriptors array pointers for full-speed, high-speed and
+ * super-speed. They will point to the uvc_[fhs]s_streaming_cls arrays
+ * for configfs-based gadgets. Legacy gadgets must initialize them in
+ * their gadget bind callback.
+ */
const struct uvc_descriptor_header * const *fs_streaming;
const struct uvc_descriptor_header * const *hs_streaming;
const struct uvc_descriptor_header * const *ss_streaming;
+
+ /* Default control descriptors for configfs-based gadgets. */
+ struct uvc_camera_terminal_descriptor uvc_camera_terminal;
+ struct uvc_processing_unit_descriptor uvc_processing;
+ struct uvc_output_terminal_descriptor uvc_output_terminal;
+ struct uvc_color_matching_descriptor uvc_color_matching;
+
+ /*
+ * Control descriptors pointers arrays for full-/high-speed and
+ * super-speed. The first element is a configurable control header
+ * descriptor, the other elements point to the fixed default control
+ * descriptors. Used by configfs only, must not be touched by legacy
+ * gadgets.
+ */
+ struct uvc_descriptor_header *uvc_fs_control_cls[5];
+ struct uvc_descriptor_header *uvc_ss_control_cls[5];
+
+ /*
+ * Streaming descriptors for full-speed, high-speed and super-speed.
+ * Used by configfs only, must not be touched by legacy gadgets. The
+ * arrays are allocated at runtime as the number of descriptors isn't
+ * known in advance.
+ */
+ struct uvc_descriptor_header **uvc_fs_streaming_cls;
+ struct uvc_descriptor_header **uvc_hs_streaming_cls;
+ struct uvc_descriptor_header **uvc_ss_streaming_cls;
+
+ /*
+ * Read/write access to configfs attributes is handled by configfs.
+ *
+ * This lock protects the descriptors from concurrent access by
+ * read/write and symlink creation/removal.
+ */
+ struct mutex lock;
+ int refcnt;
};
void uvc_set_trace_param(unsigned int trace);
diff --git a/drivers/usb/gadget/function/uvc_configfs.c b/drivers/usb/gadget/function/uvc_configfs.c
new file mode 100644
index 000000000000..3c0467bcb14f
--- /dev/null
+++ b/drivers/usb/gadget/function/uvc_configfs.c
@@ -0,0 +1,2468 @@
+/*
+ * uvc_configfs.c
+ *
+ * Configfs support for the uvc function.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include "u_uvc.h"
+#include "uvc_configfs.h"
+
+#define UVCG_STREAMING_CONTROL_SIZE 1
+
+#define CONFIGFS_ATTR_OPS_RO(_item) \
+static ssize_t _item##_attr_show(struct config_item *item, \
+ struct configfs_attribute *attr, \
+ char *page) \
+{ \
+ struct _item *_item = to_##_item(item); \
+ struct _item##_attribute *_item##_attr = \
+ container_of(attr, struct _item##_attribute, attr); \
+ ssize_t ret = 0; \
+ \
+ if (_item##_attr->show) \
+ ret = _item##_attr->show(_item, page); \
+ return ret; \
+}
+
+static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item);
+
+/* control/header/<NAME> */
+DECLARE_UVC_HEADER_DESCRIPTOR(1);
+
+struct uvcg_control_header {
+ struct config_item item;
+ struct UVC_HEADER_DESCRIPTOR(1) desc;
+ unsigned linked;
+};
+
+static struct uvcg_control_header *to_uvcg_control_header(struct config_item *item)
+{
+ return container_of(item, struct uvcg_control_header, item);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_control_header);
+CONFIGFS_ATTR_OPS(uvcg_control_header);
+
+static struct configfs_item_operations uvcg_control_header_item_ops = {
+ .show_attribute = uvcg_control_header_attr_show,
+ .store_attribute = uvcg_control_header_attr_store,
+};
+
+#define UVCG_CTRL_HDR_ATTR(cname, aname, conv, str2u, uxx, vnoc, limit) \
+static ssize_t uvcg_control_header_##cname##_show( \
+ struct uvcg_control_header *ch, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = ch->item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(ch->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t \
+uvcg_control_header_##cname##_store(struct uvcg_control_header *ch, \
+ const char *page, size_t len) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;\
+ int ret; \
+ uxx num; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = ch->item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ if (ch->linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = str2u(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > limit) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ ch->desc.aname = vnoc(num); \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+static struct uvcg_control_header_attribute \
+ uvcg_control_header_##cname = \
+ __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
+ uvcg_control_header_##cname##_show, \
+ uvcg_control_header_##cname##_store)
+
+UVCG_CTRL_HDR_ATTR(bcd_uvc, bcdUVC, le16_to_cpu, kstrtou16, u16, cpu_to_le16,
+ 0xffff);
+
+UVCG_CTRL_HDR_ATTR(dw_clock_frequency, dwClockFrequency, le32_to_cpu, kstrtou32,
+ u32, cpu_to_le32, 0x7fffffff);
+
+#undef UVCG_CTRL_HDR_ATTR
+
+static struct configfs_attribute *uvcg_control_header_attrs[] = {
+ &uvcg_control_header_bcd_uvc.attr,
+ &uvcg_control_header_dw_clock_frequency.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_control_header_type = {
+ .ct_item_ops = &uvcg_control_header_item_ops,
+ .ct_attrs = uvcg_control_header_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *uvcg_control_header_make(struct config_group *group,
+ const char *name)
+{
+ struct uvcg_control_header *h;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->desc.bLength = UVC_DT_HEADER_SIZE(1);
+ h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ h->desc.bDescriptorSubType = UVC_VC_HEADER;
+ h->desc.bcdUVC = cpu_to_le16(0x0100);
+ h->desc.dwClockFrequency = cpu_to_le32(48000000);
+
+ config_item_init_type_name(&h->item, name, &uvcg_control_header_type);
+
+ return &h->item;
+}
+
+static void uvcg_control_header_drop(struct config_group *group,
+ struct config_item *item)
+{
+ struct uvcg_control_header *h = to_uvcg_control_header(item);
+
+ kfree(h);
+}
+
+/* control/header */
+static struct uvcg_control_header_grp {
+ struct config_group group;
+} uvcg_control_header_grp;
+
+static struct configfs_group_operations uvcg_control_header_grp_ops = {
+ .make_item = uvcg_control_header_make,
+ .drop_item = uvcg_control_header_drop,
+};
+
+static struct config_item_type uvcg_control_header_grp_type = {
+ .ct_group_ops = &uvcg_control_header_grp_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* control/processing/default */
+static struct uvcg_default_processing {
+ struct config_group group;
+} uvcg_default_processing;
+
+static inline struct uvcg_default_processing
+*to_uvcg_default_processing(struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct uvcg_default_processing, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_processing);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_processing);
+
+static struct configfs_item_operations uvcg_default_processing_item_ops = {
+ .show_attribute = uvcg_default_processing_attr_show,
+};
+
+#define UVCG_DEFAULT_PROCESSING_ATTR(cname, aname, conv) \
+static ssize_t uvcg_default_processing_##cname##_show( \
+ struct uvcg_default_processing *dp, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex; \
+ struct uvc_processing_unit_descriptor *pd; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ pd = &opts->uvc_processing; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(pd->aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static struct uvcg_default_processing_attribute \
+ uvcg_default_processing_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_default_processing_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_PROCESSING_ATTR(b_unit_id, bUnitID, identity_conv);
+UVCG_DEFAULT_PROCESSING_ATTR(b_source_id, bSourceID, identity_conv);
+UVCG_DEFAULT_PROCESSING_ATTR(w_max_multiplier, wMaxMultiplier, le16_to_cpu);
+UVCG_DEFAULT_PROCESSING_ATTR(i_processing, iProcessing, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_PROCESSING_ATTR
+
+static ssize_t uvcg_default_processing_bm_controls_show(
+ struct uvcg_default_processing *dp, char *page)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &dp->group.cg_subsys->su_mutex;
+ struct uvc_processing_unit_descriptor *pd;
+ int result, i;
+ char *pg = page;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = dp->group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ pd = &opts->uvc_processing;
+
+ mutex_lock(&opts->lock);
+ for (result = 0, i = 0; i < pd->bControlSize; ++i) {
+ result += sprintf(pg, "%d\n", pd->bmControls[i]);
+ pg = page + result;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return result;
+}
+
+static struct uvcg_default_processing_attribute
+ uvcg_default_processing_bm_controls =
+ __CONFIGFS_ATTR_RO(bmControls,
+ uvcg_default_processing_bm_controls_show);
+
+static struct configfs_attribute *uvcg_default_processing_attrs[] = {
+ &uvcg_default_processing_b_unit_id.attr,
+ &uvcg_default_processing_b_source_id.attr,
+ &uvcg_default_processing_w_max_multiplier.attr,
+ &uvcg_default_processing_bm_controls.attr,
+ &uvcg_default_processing_i_processing.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_default_processing_type = {
+ .ct_item_ops = &uvcg_default_processing_item_ops,
+ .ct_attrs = uvcg_default_processing_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* struct uvcg_processing {}; */
+
+static struct config_group *uvcg_processing_default_groups[] = {
+ &uvcg_default_processing.group,
+ NULL,
+};
+
+/* control/processing */
+static struct uvcg_processing_grp {
+ struct config_group group;
+} uvcg_processing_grp;
+
+static struct config_item_type uvcg_processing_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* control/terminal/camera/default */
+static struct uvcg_default_camera {
+ struct config_group group;
+} uvcg_default_camera;
+
+static inline struct uvcg_default_camera
+*to_uvcg_default_camera(struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct uvcg_default_camera, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_camera);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_camera);
+
+static struct configfs_item_operations uvcg_default_camera_item_ops = {
+ .show_attribute = uvcg_default_camera_attr_show,
+};
+
+#define UVCG_DEFAULT_CAMERA_ATTR(cname, aname, conv) \
+static ssize_t uvcg_default_camera_##cname##_show( \
+ struct uvcg_default_camera *dc, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
+ struct uvc_camera_terminal_descriptor *cd; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent-> \
+ ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ cd = &opts->uvc_camera_terminal; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(cd->aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ \
+ return result; \
+} \
+ \
+static struct uvcg_default_camera_attribute \
+ uvcg_default_camera_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_default_camera_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_CAMERA_ATTR(b_terminal_id, bTerminalID, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
+UVCG_DEFAULT_CAMERA_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(i_terminal, iTerminal, identity_conv);
+UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_min, wObjectiveFocalLengthMin,
+ le16_to_cpu);
+UVCG_DEFAULT_CAMERA_ATTR(w_objective_focal_length_max, wObjectiveFocalLengthMax,
+ le16_to_cpu);
+UVCG_DEFAULT_CAMERA_ATTR(w_ocular_focal_length, wOcularFocalLength,
+ le16_to_cpu);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_CAMERA_ATTR
+
+static ssize_t uvcg_default_camera_bm_controls_show(
+ struct uvcg_default_camera *dc, char *page)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex;
+ struct uvc_camera_terminal_descriptor *cd;
+ int result, i;
+ char *pg = page;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent->
+ ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ cd = &opts->uvc_camera_terminal;
+
+ mutex_lock(&opts->lock);
+ for (result = 0, i = 0; i < cd->bControlSize; ++i) {
+ result += sprintf(pg, "%d\n", cd->bmControls[i]);
+ pg = page + result;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+ return result;
+}
+
+static struct uvcg_default_camera_attribute
+ uvcg_default_camera_bm_controls =
+ __CONFIGFS_ATTR_RO(bmControls, uvcg_default_camera_bm_controls_show);
+
+static struct configfs_attribute *uvcg_default_camera_attrs[] = {
+ &uvcg_default_camera_b_terminal_id.attr,
+ &uvcg_default_camera_w_terminal_type.attr,
+ &uvcg_default_camera_b_assoc_terminal.attr,
+ &uvcg_default_camera_i_terminal.attr,
+ &uvcg_default_camera_w_objective_focal_length_min.attr,
+ &uvcg_default_camera_w_objective_focal_length_max.attr,
+ &uvcg_default_camera_w_ocular_focal_length.attr,
+ &uvcg_default_camera_bm_controls.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_default_camera_type = {
+ .ct_item_ops = &uvcg_default_camera_item_ops,
+ .ct_attrs = uvcg_default_camera_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* struct uvcg_camera {}; */
+
+static struct config_group *uvcg_camera_default_groups[] = {
+ &uvcg_default_camera.group,
+ NULL,
+};
+
+/* control/terminal/camera */
+static struct uvcg_camera_grp {
+ struct config_group group;
+} uvcg_camera_grp;
+
+static struct config_item_type uvcg_camera_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* control/terminal/output/default */
+static struct uvcg_default_output {
+ struct config_group group;
+} uvcg_default_output;
+
+static inline struct uvcg_default_output
+*to_uvcg_default_output(struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct uvcg_default_output, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_output);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_output);
+
+static struct configfs_item_operations uvcg_default_output_item_ops = {
+ .show_attribute = uvcg_default_output_attr_show,
+};
+
+#define UVCG_DEFAULT_OUTPUT_ATTR(cname, aname, conv) \
+static ssize_t uvcg_default_output_##cname##_show( \
+ struct uvcg_default_output *dout, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &dout->group.cg_subsys->su_mutex; \
+ struct uvc_output_terminal_descriptor *cd; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = dout->group.cg_item.ci_parent->ci_parent-> \
+ ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ cd = &opts->uvc_output_terminal; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(cd->aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ \
+ return result; \
+} \
+ \
+static struct uvcg_default_output_attribute \
+ uvcg_default_output_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_default_output_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_OUTPUT_ATTR(b_terminal_id, bTerminalID, identity_conv);
+UVCG_DEFAULT_OUTPUT_ATTR(w_terminal_type, wTerminalType, le16_to_cpu);
+UVCG_DEFAULT_OUTPUT_ATTR(b_assoc_terminal, bAssocTerminal, identity_conv);
+UVCG_DEFAULT_OUTPUT_ATTR(b_source_id, bSourceID, identity_conv);
+UVCG_DEFAULT_OUTPUT_ATTR(i_terminal, iTerminal, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_OUTPUT_ATTR
+
+static struct configfs_attribute *uvcg_default_output_attrs[] = {
+ &uvcg_default_output_b_terminal_id.attr,
+ &uvcg_default_output_w_terminal_type.attr,
+ &uvcg_default_output_b_assoc_terminal.attr,
+ &uvcg_default_output_b_source_id.attr,
+ &uvcg_default_output_i_terminal.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_default_output_type = {
+ .ct_item_ops = &uvcg_default_output_item_ops,
+ .ct_attrs = uvcg_default_output_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* struct uvcg_output {}; */
+
+static struct config_group *uvcg_output_default_groups[] = {
+ &uvcg_default_output.group,
+ NULL,
+};
+
+/* control/terminal/output */
+static struct uvcg_output_grp {
+ struct config_group group;
+} uvcg_output_grp;
+
+static struct config_item_type uvcg_output_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_terminal_default_groups[] = {
+ &uvcg_camera_grp.group,
+ &uvcg_output_grp.group,
+ NULL,
+};
+
+/* control/terminal */
+static struct uvcg_terminal_grp {
+ struct config_group group;
+} uvcg_terminal_grp;
+
+static struct config_item_type uvcg_terminal_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* control/class/{fs} */
+static struct uvcg_control_class {
+ struct config_group group;
+} uvcg_control_class_fs, uvcg_control_class_ss;
+
+
+static inline struct uvc_descriptor_header
+**uvcg_get_ctl_class_arr(struct config_item *i, struct f_uvc_opts *o)
+{
+ struct uvcg_control_class *cl = container_of(to_config_group(i),
+ struct uvcg_control_class, group);
+
+ if (cl == &uvcg_control_class_fs)
+ return o->uvc_fs_control_cls;
+
+ if (cl == &uvcg_control_class_ss)
+ return o->uvc_ss_control_cls;
+
+ return NULL;
+}
+
+static int uvcg_control_class_allow_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct config_item *control, *header;
+ struct f_uvc_opts *opts;
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvc_descriptor_header **class_array;
+ struct uvcg_control_header *target_hdr;
+ int ret = -EINVAL;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ control = src->ci_parent->ci_parent;
+ header = config_group_find_item(to_config_group(control), "header");
+ if (!header || target->ci_parent != header)
+ goto out;
+
+ opts = to_f_uvc_opts(control->ci_parent);
+
+ mutex_lock(&opts->lock);
+
+ class_array = uvcg_get_ctl_class_arr(src, opts);
+ if (!class_array)
+ goto unlock;
+ if (opts->refcnt || class_array[0]) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ target_hdr = to_uvcg_control_header(target);
+ ++target_hdr->linked;
+ class_array[0] = (struct uvc_descriptor_header *)&target_hdr->desc;
+ ret = 0;
+
+unlock:
+ mutex_unlock(&opts->lock);
+out:
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static int uvcg_control_class_drop_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct config_item *control, *header;
+ struct f_uvc_opts *opts;
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvc_descriptor_header **class_array;
+ struct uvcg_control_header *target_hdr;
+ int ret = -EINVAL;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ control = src->ci_parent->ci_parent;
+ header = config_group_find_item(to_config_group(control), "header");
+ if (!header || target->ci_parent != header)
+ goto out;
+
+ opts = to_f_uvc_opts(control->ci_parent);
+
+ mutex_lock(&opts->lock);
+
+ class_array = uvcg_get_ctl_class_arr(src, opts);
+ if (!class_array)
+ goto unlock;
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ target_hdr = to_uvcg_control_header(target);
+ --target_hdr->linked;
+ class_array[0] = NULL;
+ ret = 0;
+
+unlock:
+ mutex_unlock(&opts->lock);
+out:
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static struct configfs_item_operations uvcg_control_class_item_ops = {
+ .allow_link = uvcg_control_class_allow_link,
+ .drop_link = uvcg_control_class_drop_link,
+};
+
+static struct config_item_type uvcg_control_class_type = {
+ .ct_item_ops = &uvcg_control_class_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_control_class_default_groups[] = {
+ &uvcg_control_class_fs.group,
+ &uvcg_control_class_ss.group,
+ NULL,
+};
+
+/* control/class */
+static struct uvcg_control_class_grp {
+ struct config_group group;
+} uvcg_control_class_grp;
+
+static struct config_item_type uvcg_control_class_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_control_default_groups[] = {
+ &uvcg_control_header_grp.group,
+ &uvcg_processing_grp.group,
+ &uvcg_terminal_grp.group,
+ &uvcg_control_class_grp.group,
+ NULL,
+};
+
+/* control */
+static struct uvcg_control_grp {
+ struct config_group group;
+} uvcg_control_grp;
+
+static struct config_item_type uvcg_control_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* streaming/uncompressed */
+static struct uvcg_uncompressed_grp {
+ struct config_group group;
+} uvcg_uncompressed_grp;
+
+/* streaming/mjpeg */
+static struct uvcg_mjpeg_grp {
+ struct config_group group;
+} uvcg_mjpeg_grp;
+
+static struct config_item *fmt_parent[] = {
+ &uvcg_uncompressed_grp.group.cg_item,
+ &uvcg_mjpeg_grp.group.cg_item,
+};
+
+enum uvcg_format_type {
+ UVCG_UNCOMPRESSED = 0,
+ UVCG_MJPEG,
+};
+
+struct uvcg_format {
+ struct config_group group;
+ enum uvcg_format_type type;
+ unsigned linked;
+ unsigned num_frames;
+ __u8 bmaControls[UVCG_STREAMING_CONTROL_SIZE];
+};
+
+static struct uvcg_format *to_uvcg_format(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct uvcg_format, group);
+}
+
+static ssize_t uvcg_format_bma_controls_show(struct uvcg_format *f, char *page)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &f->group.cg_subsys->su_mutex;
+ int result, i;
+ char *pg = page;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = f->group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ result = sprintf(pg, "0x");
+ pg += result;
+ for (i = 0; i < UVCG_STREAMING_CONTROL_SIZE; ++i) {
+ result += sprintf(pg, "%x\n", f->bmaControls[i]);
+ pg = page + result;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+ return result;
+}
+
+static ssize_t uvcg_format_bma_controls_store(struct uvcg_format *ch,
+ const char *page, size_t len)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &ch->group.cg_subsys->su_mutex;
+ int ret = -EINVAL;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ if (ch->linked || opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ if (len < 4 || *page != '0' ||
+ (*(page + 1) != 'x' && *(page + 1) != 'X'))
+ goto end;
+ ret = hex2bin(ch->bmaControls, page + 2, 1);
+ if (ret < 0)
+ goto end;
+ ret = len;
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+struct uvcg_format_ptr {
+ struct uvcg_format *fmt;
+ struct list_head entry;
+};
+
+/* streaming/header/<NAME> */
+struct uvcg_streaming_header {
+ struct config_item item;
+ struct uvc_input_header_descriptor desc;
+ unsigned linked;
+ struct list_head formats;
+ unsigned num_fmt;
+};
+
+static struct uvcg_streaming_header *to_uvcg_streaming_header(struct config_item *item)
+{
+ return container_of(item, struct uvcg_streaming_header, item);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_streaming_header);
+CONFIGFS_ATTR_OPS(uvcg_streaming_header);
+
+static int uvcg_streaming_header_allow_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ struct uvcg_streaming_header *src_hdr;
+ struct uvcg_format *target_fmt = NULL;
+ struct uvcg_format_ptr *format_ptr;
+ int i, ret = -EINVAL;
+
+ src_hdr = to_uvcg_streaming_header(src);
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = src->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+
+ if (src_hdr->linked) {
+ ret = -EBUSY;
+ goto out;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(fmt_parent); ++i)
+ if (target->ci_parent == fmt_parent[i])
+ break;
+ if (i == ARRAY_SIZE(fmt_parent))
+ goto out;
+
+ target_fmt = container_of(to_config_group(target), struct uvcg_format,
+ group);
+ if (!target_fmt)
+ goto out;
+
+ format_ptr = kzalloc(sizeof(*format_ptr), GFP_KERNEL);
+ if (!format_ptr) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ ret = 0;
+ format_ptr->fmt = target_fmt;
+ list_add_tail(&format_ptr->entry, &src_hdr->formats);
+ ++src_hdr->num_fmt;
+
+out:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static int uvcg_streaming_header_drop_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct config_item *opts_item;
+ struct f_uvc_opts *opts;
+ struct uvcg_streaming_header *src_hdr;
+ struct uvcg_format *target_fmt = NULL;
+ struct uvcg_format_ptr *format_ptr, *tmp;
+ int ret = -EINVAL;
+
+ src_hdr = to_uvcg_streaming_header(src);
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = src->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ target_fmt = container_of(to_config_group(target), struct uvcg_format,
+ group);
+ if (!target_fmt)
+ goto out;
+
+ list_for_each_entry_safe(format_ptr, tmp, &src_hdr->formats, entry)
+ if (format_ptr->fmt == target_fmt) {
+ list_del(&format_ptr->entry);
+ kfree(format_ptr);
+ --src_hdr->num_fmt;
+ break;
+ }
+
+out:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+
+}
+
+static struct configfs_item_operations uvcg_streaming_header_item_ops = {
+ .show_attribute = uvcg_streaming_header_attr_show,
+ .store_attribute = uvcg_streaming_header_attr_store,
+ .allow_link = uvcg_streaming_header_allow_link,
+ .drop_link = uvcg_streaming_header_drop_link,
+};
+
+#define UVCG_STREAMING_HEADER_ATTR(cname, aname, conv) \
+static ssize_t uvcg_streaming_header_##cname##_show( \
+ struct uvcg_streaming_header *sh, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &sh->item.ci_group->cg_subsys->su_mutex;\
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = sh->item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(sh->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static struct uvcg_streaming_header_attribute \
+ uvcg_streaming_header_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_streaming_header_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_STREAMING_HEADER_ATTR(bm_info, bmInfo, identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_terminal_link, bTerminalLink, identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_still_capture_method, bStillCaptureMethod,
+ identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_trigger_support, bTriggerSupport, identity_conv);
+UVCG_STREAMING_HEADER_ATTR(b_trigger_usage, bTriggerUsage, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_STREAMING_HEADER_ATTR
+
+static struct configfs_attribute *uvcg_streaming_header_attrs[] = {
+ &uvcg_streaming_header_bm_info.attr,
+ &uvcg_streaming_header_b_terminal_link.attr,
+ &uvcg_streaming_header_b_still_capture_method.attr,
+ &uvcg_streaming_header_b_trigger_support.attr,
+ &uvcg_streaming_header_b_trigger_usage.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_streaming_header_type = {
+ .ct_item_ops = &uvcg_streaming_header_item_ops,
+ .ct_attrs = uvcg_streaming_header_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item
+*uvcg_streaming_header_make(struct config_group *group, const char *name)
+{
+ struct uvcg_streaming_header *h;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ INIT_LIST_HEAD(&h->formats);
+ h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ h->desc.bDescriptorSubType = UVC_VS_INPUT_HEADER;
+ h->desc.bTerminalLink = 3;
+ h->desc.bControlSize = UVCG_STREAMING_CONTROL_SIZE;
+
+ config_item_init_type_name(&h->item, name, &uvcg_streaming_header_type);
+
+ return &h->item;
+}
+
+static void uvcg_streaming_header_drop(struct config_group *group,
+ struct config_item *item)
+{
+ struct uvcg_streaming_header *h = to_uvcg_streaming_header(item);
+
+ kfree(h);
+}
+
+/* streaming/header */
+static struct uvcg_streaming_header_grp {
+ struct config_group group;
+} uvcg_streaming_header_grp;
+
+static struct configfs_group_operations uvcg_streaming_header_grp_ops = {
+ .make_item = uvcg_streaming_header_make,
+ .drop_item = uvcg_streaming_header_drop,
+};
+
+static struct config_item_type uvcg_streaming_header_grp_type = {
+ .ct_group_ops = &uvcg_streaming_header_grp_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* streaming/<mode>/<format>/<NAME> */
+struct uvcg_frame {
+ struct {
+ u8 b_length;
+ u8 b_descriptor_type;
+ u8 b_descriptor_subtype;
+ u8 b_frame_index;
+ u8 bm_capabilities;
+ u16 w_width;
+ u16 w_height;
+ u32 dw_min_bit_rate;
+ u32 dw_max_bit_rate;
+ u32 dw_max_video_frame_buffer_size;
+ u32 dw_default_frame_interval;
+ u8 b_frame_interval_type;
+ } __attribute__((packed)) frame;
+ u32 *dw_frame_interval;
+ enum uvcg_format_type fmt_type;
+ struct config_item item;
+};
+
+static struct uvcg_frame *to_uvcg_frame(struct config_item *item)
+{
+ return container_of(item, struct uvcg_frame, item);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_frame);
+CONFIGFS_ATTR_OPS(uvcg_frame);
+
+static struct configfs_item_operations uvcg_frame_item_ops = {
+ .show_attribute = uvcg_frame_attr_show,
+ .store_attribute = uvcg_frame_attr_store,
+};
+
+#define UVCG_FRAME_ATTR(cname, aname, to_cpu_endian, to_little_endian, bits) \
+static ssize_t uvcg_frame_##cname##_show(struct uvcg_frame *f, char *page)\
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", to_cpu_endian(f->frame.cname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t uvcg_frame_##cname##_store(struct uvcg_frame *f, \
+ const char *page, size_t len)\
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct uvcg_format *fmt; \
+ struct mutex *su_mutex = &f->item.ci_group->cg_subsys->su_mutex;\
+ int ret; \
+ u##bits num; \
+ \
+ ret = kstrtou##bits(page, 0, &num); \
+ if (ret) \
+ return ret; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = f->item.ci_parent->ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ fmt = to_uvcg_format(f->item.ci_parent); \
+ \
+ mutex_lock(&opts->lock); \
+ if (fmt->linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ f->frame.cname = to_little_endian(num); \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+static struct uvcg_frame_attribute \
+ uvcg_frame_##cname = \
+ __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
+ uvcg_frame_##cname##_show, \
+ uvcg_frame_##cname##_store)
+
+#define noop_conversion(x) (x)
+
+UVCG_FRAME_ATTR(bm_capabilities, bmCapabilities, noop_conversion,
+ noop_conversion, 8);
+UVCG_FRAME_ATTR(w_width, wWidth, le16_to_cpu, cpu_to_le16, 16);
+UVCG_FRAME_ATTR(w_height, wHeight, le16_to_cpu, cpu_to_le16, 16);
+UVCG_FRAME_ATTR(dw_min_bit_rate, dwMinBitRate, le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_ATTR(dw_max_bit_rate, dwMaxBitRate, le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_ATTR(dw_max_video_frame_buffer_size, dwMaxVideoFrameBufferSize,
+ le32_to_cpu, cpu_to_le32, 32);
+UVCG_FRAME_ATTR(dw_default_frame_interval, dwDefaultFrameInterval,
+ le32_to_cpu, cpu_to_le32, 32);
+
+#undef noop_conversion
+
+#undef UVCG_FRAME_ATTR
+
+static ssize_t uvcg_frame_dw_frame_interval_show(struct uvcg_frame *frm,
+ char *page)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &frm->item.ci_group->cg_subsys->su_mutex;
+ int result, i;
+ char *pg = page;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = frm->item.ci_parent->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ for (result = 0, i = 0; i < frm->frame.b_frame_interval_type; ++i) {
+ result += sprintf(pg, "%d\n",
+ le32_to_cpu(frm->dw_frame_interval[i]));
+ pg = page + result;
+ }
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+ return result;
+}
+
+static inline int __uvcg_count_frm_intrv(char *buf, void *priv)
+{
+ ++*((int *)priv);
+ return 0;
+}
+
+static inline int __uvcg_fill_frm_intrv(char *buf, void *priv)
+{
+ u32 num, **interv;
+ int ret;
+
+ ret = kstrtou32(buf, 0, &num);
+ if (ret)
+ return ret;
+
+ interv = priv;
+ **interv = cpu_to_le32(num);
+ ++*interv;
+
+ return 0;
+}
+
+static int __uvcg_iter_frm_intrv(const char *page, size_t len,
+ int (*fun)(char *, void *), void *priv)
+{
+ /* sign, base 2 representation, newline, terminator */
+ char buf[1 + sizeof(u32) * 8 + 1 + 1];
+ const char *pg = page;
+ int i, ret;
+
+ if (!fun)
+ return -EINVAL;
+
+ while (pg - page < len) {
+ i = 0;
+ while (i < sizeof(buf) && (pg - page < len) &&
+ *pg != '\0' && *pg != '\n')
+ buf[i++] = *pg++;
+ if (i == sizeof(buf))
+ return -EINVAL;
+ while ((pg - page < len) && (*pg == '\0' || *pg == '\n'))
+ ++pg;
+ buf[i] = '\0';
+ ret = fun(buf, priv);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static ssize_t uvcg_frame_dw_frame_interval_store(struct uvcg_frame *ch,
+ const char *page, size_t len)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct uvcg_format *fmt;
+ struct mutex *su_mutex = &ch->item.ci_group->cg_subsys->su_mutex;
+ int ret = 0, n = 0;
+ u32 *frm_intrv, *tmp;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->item.ci_parent->ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+ fmt = to_uvcg_format(ch->item.ci_parent);
+
+ mutex_lock(&opts->lock);
+ if (fmt->linked || opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ ret = __uvcg_iter_frm_intrv(page, len, __uvcg_count_frm_intrv, &n);
+ if (ret)
+ goto end;
+
+ tmp = frm_intrv = kcalloc(n, sizeof(u32), GFP_KERNEL);
+ if (!frm_intrv) {
+ ret = -ENOMEM;
+ goto end;
+ }
+
+ ret = __uvcg_iter_frm_intrv(page, len, __uvcg_fill_frm_intrv, &tmp);
+ if (ret) {
+ kfree(frm_intrv);
+ goto end;
+ }
+
+ kfree(ch->dw_frame_interval);
+ ch->dw_frame_interval = frm_intrv;
+ ch->frame.b_frame_interval_type = n;
+ ret = len;
+
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static struct uvcg_frame_attribute
+ uvcg_frame_dw_frame_interval =
+ __CONFIGFS_ATTR(dwFrameInterval, S_IRUGO | S_IWUSR,
+ uvcg_frame_dw_frame_interval_show,
+ uvcg_frame_dw_frame_interval_store);
+
+static struct configfs_attribute *uvcg_frame_attrs[] = {
+ &uvcg_frame_bm_capabilities.attr,
+ &uvcg_frame_w_width.attr,
+ &uvcg_frame_w_height.attr,
+ &uvcg_frame_dw_min_bit_rate.attr,
+ &uvcg_frame_dw_max_bit_rate.attr,
+ &uvcg_frame_dw_max_video_frame_buffer_size.attr,
+ &uvcg_frame_dw_default_frame_interval.attr,
+ &uvcg_frame_dw_frame_interval.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_frame_type = {
+ .ct_item_ops = &uvcg_frame_item_ops,
+ .ct_attrs = uvcg_frame_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *uvcg_frame_make(struct config_group *group,
+ const char *name)
+{
+ struct uvcg_frame *h;
+ struct uvcg_format *fmt;
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->frame.b_descriptor_type = USB_DT_CS_INTERFACE;
+ h->frame.b_frame_index = 1;
+ h->frame.w_width = cpu_to_le16(640);
+ h->frame.w_height = cpu_to_le16(360);
+ h->frame.dw_min_bit_rate = cpu_to_le32(18432000);
+ h->frame.dw_max_bit_rate = cpu_to_le32(55296000);
+ h->frame.dw_max_video_frame_buffer_size = cpu_to_le32(460800);
+ h->frame.dw_default_frame_interval = cpu_to_le32(666666);
+
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ fmt = to_uvcg_format(&group->cg_item);
+ if (fmt->type == UVCG_UNCOMPRESSED) {
+ h->frame.b_descriptor_subtype = UVC_VS_FRAME_UNCOMPRESSED;
+ h->fmt_type = UVCG_UNCOMPRESSED;
+ } else if (fmt->type == UVCG_MJPEG) {
+ h->frame.b_descriptor_subtype = UVC_VS_FRAME_MJPEG;
+ h->fmt_type = UVCG_MJPEG;
+ } else {
+ mutex_unlock(&opts->lock);
+ kfree(h);
+ return ERR_PTR(-EINVAL);
+ }
+ ++fmt->num_frames;
+ mutex_unlock(&opts->lock);
+
+ config_item_init_type_name(&h->item, name, &uvcg_frame_type);
+
+ return &h->item;
+}
+
+static void uvcg_frame_drop(struct config_group *group, struct config_item *item)
+{
+ struct uvcg_frame *h = to_uvcg_frame(item);
+ struct uvcg_format *fmt;
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+
+ opts_item = group->cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ fmt = to_uvcg_format(&group->cg_item);
+ --fmt->num_frames;
+ kfree(h);
+ mutex_unlock(&opts->lock);
+}
+
+/* streaming/uncompressed/<NAME> */
+struct uvcg_uncompressed {
+ struct uvcg_format fmt;
+ struct uvc_format_uncompressed desc;
+};
+
+static struct uvcg_uncompressed *to_uvcg_uncompressed(struct config_item *item)
+{
+ return container_of(
+ container_of(to_config_group(item), struct uvcg_format, group),
+ struct uvcg_uncompressed, fmt);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_uncompressed);
+CONFIGFS_ATTR_OPS(uvcg_uncompressed);
+
+static struct configfs_item_operations uvcg_uncompressed_item_ops = {
+ .show_attribute = uvcg_uncompressed_attr_show,
+ .store_attribute = uvcg_uncompressed_attr_store,
+};
+
+static struct configfs_group_operations uvcg_uncompressed_group_ops = {
+ .make_item = uvcg_frame_make,
+ .drop_item = uvcg_frame_drop,
+};
+
+static ssize_t uvcg_uncompressed_guid_format_show(struct uvcg_uncompressed *ch,
+ char *page)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ memcpy(page, ch->desc.guidFormat, sizeof(ch->desc.guidFormat));
+ mutex_unlock(&opts->lock);
+
+ mutex_unlock(su_mutex);
+
+ return sizeof(ch->desc.guidFormat);
+}
+
+static ssize_t uvcg_uncompressed_guid_format_store(struct uvcg_uncompressed *ch,
+ const char *page, size_t len)
+{
+ struct f_uvc_opts *opts;
+ struct config_item *opts_item;
+ struct mutex *su_mutex = &ch->fmt.group.cg_subsys->su_mutex;
+ int ret;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ opts_item = ch->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;
+ opts = to_f_uvc_opts(opts_item);
+
+ mutex_lock(&opts->lock);
+ if (ch->fmt.linked || opts->refcnt) {
+ ret = -EBUSY;
+ goto end;
+ }
+
+ memcpy(ch->desc.guidFormat, page,
+ min(sizeof(ch->desc.guidFormat), len));
+ ret = sizeof(ch->desc.guidFormat);
+
+end:
+ mutex_unlock(&opts->lock);
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static struct uvcg_uncompressed_attribute uvcg_uncompressed_guid_format =
+ __CONFIGFS_ATTR(guidFormat, S_IRUGO | S_IWUSR,
+ uvcg_uncompressed_guid_format_show,
+ uvcg_uncompressed_guid_format_store);
+
+
+#define UVCG_UNCOMPRESSED_ATTR_RO(cname, aname, conv) \
+static ssize_t uvcg_uncompressed_##cname##_show( \
+ struct uvcg_uncompressed *u, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static struct uvcg_uncompressed_attribute \
+ uvcg_uncompressed_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_uncompressed_##cname##_show)
+
+#define UVCG_UNCOMPRESSED_ATTR(cname, aname, conv) \
+static ssize_t uvcg_uncompressed_##cname##_show( \
+ struct uvcg_uncompressed *u, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t \
+uvcg_uncompressed_##cname##_store(struct uvcg_uncompressed *u, \
+ const char *page, size_t len) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int ret; \
+ u8 num; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ if (u->fmt.linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtou8(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > 255) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ u->desc.aname = num; \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+static struct uvcg_uncompressed_attribute \
+ uvcg_uncompressed_##cname = \
+ __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
+ uvcg_uncompressed_##cname##_show, \
+ uvcg_uncompressed_##cname##_store)
+
+#define identity_conv(x) (x)
+
+UVCG_UNCOMPRESSED_ATTR(b_bits_per_pixel, bBitsPerPixel, identity_conv);
+UVCG_UNCOMPRESSED_ATTR(b_default_frame_index, bDefaultFrameIndex,
+ identity_conv);
+UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
+UVCG_UNCOMPRESSED_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
+UVCG_UNCOMPRESSED_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_UNCOMPRESSED_ATTR
+#undef UVCG_UNCOMPRESSED_ATTR_RO
+
+static inline ssize_t
+uvcg_uncompressed_bma_controls_show(struct uvcg_uncompressed *unc, char *page)
+{
+ return uvcg_format_bma_controls_show(&unc->fmt, page);
+}
+
+static inline ssize_t
+uvcg_uncompressed_bma_controls_store(struct uvcg_uncompressed *ch,
+ const char *page, size_t len)
+{
+ return uvcg_format_bma_controls_store(&ch->fmt, page, len);
+}
+
+static struct uvcg_uncompressed_attribute uvcg_uncompressed_bma_controls =
+ __CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR,
+ uvcg_uncompressed_bma_controls_show,
+ uvcg_uncompressed_bma_controls_store);
+
+static struct configfs_attribute *uvcg_uncompressed_attrs[] = {
+ &uvcg_uncompressed_guid_format.attr,
+ &uvcg_uncompressed_b_bits_per_pixel.attr,
+ &uvcg_uncompressed_b_default_frame_index.attr,
+ &uvcg_uncompressed_b_aspect_ratio_x.attr,
+ &uvcg_uncompressed_b_aspect_ratio_y.attr,
+ &uvcg_uncompressed_bm_interface_flags.attr,
+ &uvcg_uncompressed_bma_controls.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_uncompressed_type = {
+ .ct_item_ops = &uvcg_uncompressed_item_ops,
+ .ct_group_ops = &uvcg_uncompressed_group_ops,
+ .ct_attrs = uvcg_uncompressed_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_uncompressed_make(struct config_group *group,
+ const char *name)
+{
+ static char guid[] = {
+ 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00,
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
+ };
+ struct uvcg_uncompressed *h;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->desc.bLength = UVC_DT_FORMAT_UNCOMPRESSED_SIZE;
+ h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ h->desc.bDescriptorSubType = UVC_VS_FORMAT_UNCOMPRESSED;
+ memcpy(h->desc.guidFormat, guid, sizeof(guid));
+ h->desc.bBitsPerPixel = 16;
+ h->desc.bDefaultFrameIndex = 1;
+ h->desc.bAspectRatioX = 0;
+ h->desc.bAspectRatioY = 0;
+ h->desc.bmInterfaceFlags = 0;
+ h->desc.bCopyProtect = 0;
+
+ h->fmt.type = UVCG_UNCOMPRESSED;
+ config_group_init_type_name(&h->fmt.group, name,
+ &uvcg_uncompressed_type);
+
+ return &h->fmt.group;
+}
+
+static void uvcg_uncompressed_drop(struct config_group *group,
+ struct config_item *item)
+{
+ struct uvcg_uncompressed *h = to_uvcg_uncompressed(item);
+
+ kfree(h);
+}
+
+static struct configfs_group_operations uvcg_uncompressed_grp_ops = {
+ .make_group = uvcg_uncompressed_make,
+ .drop_item = uvcg_uncompressed_drop,
+};
+
+static struct config_item_type uvcg_uncompressed_grp_type = {
+ .ct_group_ops = &uvcg_uncompressed_grp_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* streaming/mjpeg/<NAME> */
+struct uvcg_mjpeg {
+ struct uvcg_format fmt;
+ struct uvc_format_mjpeg desc;
+};
+
+static struct uvcg_mjpeg *to_uvcg_mjpeg(struct config_item *item)
+{
+ return container_of(
+ container_of(to_config_group(item), struct uvcg_format, group),
+ struct uvcg_mjpeg, fmt);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_mjpeg);
+CONFIGFS_ATTR_OPS(uvcg_mjpeg);
+
+static struct configfs_item_operations uvcg_mjpeg_item_ops = {
+ .show_attribute = uvcg_mjpeg_attr_show,
+ .store_attribute = uvcg_mjpeg_attr_store,
+};
+
+static struct configfs_group_operations uvcg_mjpeg_group_ops = {
+ .make_item = uvcg_frame_make,
+ .drop_item = uvcg_frame_drop,
+};
+
+#define UVCG_MJPEG_ATTR_RO(cname, aname, conv) \
+static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static struct uvcg_mjpeg_attribute \
+ uvcg_mjpeg_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_mjpeg_##cname##_show)
+
+#define UVCG_MJPEG_ATTR(cname, aname, conv) \
+static ssize_t uvcg_mjpeg_##cname##_show(struct uvcg_mjpeg *u, char *page)\
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(u->desc.aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static ssize_t \
+uvcg_mjpeg_##cname##_store(struct uvcg_mjpeg *u, \
+ const char *page, size_t len) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &u->fmt.group.cg_subsys->su_mutex; \
+ int ret; \
+ u8 num; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = u->fmt.group.cg_item.ci_parent->ci_parent->ci_parent;\
+ opts = to_f_uvc_opts(opts_item); \
+ \
+ mutex_lock(&opts->lock); \
+ if (u->fmt.linked || opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = kstrtou8(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > 255) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ u->desc.aname = num; \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ mutex_unlock(su_mutex); \
+ return ret; \
+} \
+ \
+static struct uvcg_mjpeg_attribute \
+ uvcg_mjpeg_##cname = \
+ __CONFIGFS_ATTR(aname, S_IRUGO | S_IWUSR, \
+ uvcg_mjpeg_##cname##_show, \
+ uvcg_mjpeg_##cname##_store)
+
+#define identity_conv(x) (x)
+
+UVCG_MJPEG_ATTR(b_default_frame_index, bDefaultFrameIndex,
+ identity_conv);
+UVCG_MJPEG_ATTR_RO(bm_flags, bmFlags, identity_conv);
+UVCG_MJPEG_ATTR_RO(b_aspect_ratio_x, bAspectRatioX, identity_conv);
+UVCG_MJPEG_ATTR_RO(b_aspect_ratio_y, bAspectRatioY, identity_conv);
+UVCG_MJPEG_ATTR_RO(bm_interface_flags, bmInterfaceFlags, identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_MJPEG_ATTR
+#undef UVCG_MJPEG_ATTR_RO
+
+static inline ssize_t
+uvcg_mjpeg_bma_controls_show(struct uvcg_mjpeg *unc, char *page)
+{
+ return uvcg_format_bma_controls_show(&unc->fmt, page);
+}
+
+static inline ssize_t
+uvcg_mjpeg_bma_controls_store(struct uvcg_mjpeg *ch,
+ const char *page, size_t len)
+{
+ return uvcg_format_bma_controls_store(&ch->fmt, page, len);
+}
+
+static struct uvcg_mjpeg_attribute uvcg_mjpeg_bma_controls =
+ __CONFIGFS_ATTR(bmaControls, S_IRUGO | S_IWUSR,
+ uvcg_mjpeg_bma_controls_show,
+ uvcg_mjpeg_bma_controls_store);
+
+static struct configfs_attribute *uvcg_mjpeg_attrs[] = {
+ &uvcg_mjpeg_b_default_frame_index.attr,
+ &uvcg_mjpeg_bm_flags.attr,
+ &uvcg_mjpeg_b_aspect_ratio_x.attr,
+ &uvcg_mjpeg_b_aspect_ratio_y.attr,
+ &uvcg_mjpeg_bm_interface_flags.attr,
+ &uvcg_mjpeg_bma_controls.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_mjpeg_type = {
+ .ct_item_ops = &uvcg_mjpeg_item_ops,
+ .ct_group_ops = &uvcg_mjpeg_group_ops,
+ .ct_attrs = uvcg_mjpeg_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_mjpeg_make(struct config_group *group,
+ const char *name)
+{
+ struct uvcg_mjpeg *h;
+
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
+
+ h->desc.bLength = UVC_DT_FORMAT_MJPEG_SIZE;
+ h->desc.bDescriptorType = USB_DT_CS_INTERFACE;
+ h->desc.bDescriptorSubType = UVC_VS_FORMAT_MJPEG;
+ h->desc.bDefaultFrameIndex = 1;
+ h->desc.bAspectRatioX = 0;
+ h->desc.bAspectRatioY = 0;
+ h->desc.bmInterfaceFlags = 0;
+ h->desc.bCopyProtect = 0;
+
+ h->fmt.type = UVCG_MJPEG;
+ config_group_init_type_name(&h->fmt.group, name,
+ &uvcg_mjpeg_type);
+
+ return &h->fmt.group;
+}
+
+static void uvcg_mjpeg_drop(struct config_group *group,
+ struct config_item *item)
+{
+ struct uvcg_mjpeg *h = to_uvcg_mjpeg(item);
+
+ kfree(h);
+}
+
+static struct configfs_group_operations uvcg_mjpeg_grp_ops = {
+ .make_group = uvcg_mjpeg_make,
+ .drop_item = uvcg_mjpeg_drop,
+};
+
+static struct config_item_type uvcg_mjpeg_grp_type = {
+ .ct_group_ops = &uvcg_mjpeg_grp_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+/* streaming/color_matching/default */
+static struct uvcg_default_color_matching {
+ struct config_group group;
+} uvcg_default_color_matching;
+
+static inline struct uvcg_default_color_matching
+*to_uvcg_default_color_matching(struct config_item *item)
+{
+ return container_of(to_config_group(item),
+ struct uvcg_default_color_matching, group);
+}
+
+CONFIGFS_ATTR_STRUCT(uvcg_default_color_matching);
+CONFIGFS_ATTR_OPS_RO(uvcg_default_color_matching);
+
+static struct configfs_item_operations uvcg_default_color_matching_item_ops = {
+ .show_attribute = uvcg_default_color_matching_attr_show,
+};
+
+#define UVCG_DEFAULT_COLOR_MATCHING_ATTR(cname, aname, conv) \
+static ssize_t uvcg_default_color_matching_##cname##_show( \
+ struct uvcg_default_color_matching *dc, char *page) \
+{ \
+ struct f_uvc_opts *opts; \
+ struct config_item *opts_item; \
+ struct mutex *su_mutex = &dc->group.cg_subsys->su_mutex; \
+ struct uvc_color_matching_descriptor *cd; \
+ int result; \
+ \
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */ \
+ \
+ opts_item = dc->group.cg_item.ci_parent->ci_parent->ci_parent; \
+ opts = to_f_uvc_opts(opts_item); \
+ cd = &opts->uvc_color_matching; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(cd->aname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ mutex_unlock(su_mutex); \
+ return result; \
+} \
+ \
+static struct uvcg_default_color_matching_attribute \
+ uvcg_default_color_matching_##cname = \
+ __CONFIGFS_ATTR_RO(aname, uvcg_default_color_matching_##cname##_show)
+
+#define identity_conv(x) (x)
+
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_color_primaries, bColorPrimaries,
+ identity_conv);
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_transfer_characteristics,
+ bTransferCharacteristics, identity_conv);
+UVCG_DEFAULT_COLOR_MATCHING_ATTR(b_matrix_coefficients, bMatrixCoefficients,
+ identity_conv);
+
+#undef identity_conv
+
+#undef UVCG_DEFAULT_COLOR_MATCHING_ATTR
+
+static struct configfs_attribute *uvcg_default_color_matching_attrs[] = {
+ &uvcg_default_color_matching_b_color_primaries.attr,
+ &uvcg_default_color_matching_b_transfer_characteristics.attr,
+ &uvcg_default_color_matching_b_matrix_coefficients.attr,
+ NULL,
+};
+
+static struct config_item_type uvcg_default_color_matching_type = {
+ .ct_item_ops = &uvcg_default_color_matching_item_ops,
+ .ct_attrs = uvcg_default_color_matching_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+/* struct uvcg_color_matching {}; */
+
+static struct config_group *uvcg_color_matching_default_groups[] = {
+ &uvcg_default_color_matching.group,
+ NULL,
+};
+
+/* streaming/color_matching */
+static struct uvcg_color_matching_grp {
+ struct config_group group;
+} uvcg_color_matching_grp;
+
+static struct config_item_type uvcg_color_matching_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+/* streaming/class/{fs|hs|ss} */
+static struct uvcg_streaming_class {
+ struct config_group group;
+} uvcg_streaming_class_fs, uvcg_streaming_class_hs, uvcg_streaming_class_ss;
+
+
+static inline struct uvc_descriptor_header
+***__uvcg_get_stream_class_arr(struct config_item *i, struct f_uvc_opts *o)
+{
+ struct uvcg_streaming_class *cl = container_of(to_config_group(i),
+ struct uvcg_streaming_class, group);
+
+ if (cl == &uvcg_streaming_class_fs)
+ return &o->uvc_fs_streaming_cls;
+
+ if (cl == &uvcg_streaming_class_hs)
+ return &o->uvc_hs_streaming_cls;
+
+ if (cl == &uvcg_streaming_class_ss)
+ return &o->uvc_ss_streaming_cls;
+
+ return NULL;
+}
+
+enum uvcg_strm_type {
+ UVCG_HEADER = 0,
+ UVCG_FORMAT,
+ UVCG_FRAME
+};
+
+/*
+ * Iterate over a hierarchy of streaming descriptors' config items.
+ * The items are created by the user with configfs.
+ *
+ * It "processes" the header pointed to by @priv1, then for each format
+ * that follows the header "processes" the format itself and then for
+ * each frame inside a format "processes" the frame.
+ *
+ * As a "processing" function the @fun is used.
+ *
+ * __uvcg_iter_strm_cls() is used in two context: first, to calculate
+ * the amount of memory needed for an array of streaming descriptors
+ * and second, to actually fill the array.
+ *
+ * @h: streaming header pointer
+ * @priv2: an "inout" parameter (the caller might want to see the changes to it)
+ * @priv3: an "inout" parameter (the caller might want to see the changes to it)
+ * @fun: callback function for processing each level of the hierarchy
+ */
+static int __uvcg_iter_strm_cls(struct uvcg_streaming_header *h,
+ void *priv2, void *priv3,
+ int (*fun)(void *, void *, void *, int, enum uvcg_strm_type type))
+{
+ struct uvcg_format_ptr *f;
+ struct config_group *grp;
+ struct config_item *item;
+ struct uvcg_frame *frm;
+ int ret, i, j;
+
+ if (!fun)
+ return -EINVAL;
+
+ i = j = 0;
+ ret = fun(h, priv2, priv3, 0, UVCG_HEADER);
+ if (ret)
+ return ret;
+ list_for_each_entry(f, &h->formats, entry) {
+ ret = fun(f->fmt, priv2, priv3, i++, UVCG_FORMAT);
+ if (ret)
+ return ret;
+ grp = &f->fmt->group;
+ list_for_each_entry(item, &grp->cg_children, ci_entry) {
+ frm = to_uvcg_frame(item);
+ ret = fun(frm, priv2, priv3, j++, UVCG_FRAME);
+ if (ret)
+ return ret;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Count how many bytes are needed for an array of streaming descriptors.
+ *
+ * @priv1: pointer to a header, format or frame
+ * @priv2: inout parameter, accumulated size of the array
+ * @priv3: inout parameter, accumulated number of the array elements
+ * @n: unused, this function's prototype must match @fun in __uvcg_iter_strm_cls
+ */
+static int __uvcg_cnt_strm(void *priv1, void *priv2, void *priv3, int n,
+ enum uvcg_strm_type type)
+{
+ size_t *size = priv2;
+ size_t *count = priv3;
+
+ switch (type) {
+ case UVCG_HEADER: {
+ struct uvcg_streaming_header *h = priv1;
+
+ *size += sizeof(h->desc);
+ /* bmaControls */
+ *size += h->num_fmt * UVCG_STREAMING_CONTROL_SIZE;
+ }
+ break;
+ case UVCG_FORMAT: {
+ struct uvcg_format *fmt = priv1;
+
+ if (fmt->type == UVCG_UNCOMPRESSED) {
+ struct uvcg_uncompressed *u =
+ container_of(fmt, struct uvcg_uncompressed,
+ fmt);
+
+ *size += sizeof(u->desc);
+ } else if (fmt->type == UVCG_MJPEG) {
+ struct uvcg_mjpeg *m =
+ container_of(fmt, struct uvcg_mjpeg, fmt);
+
+ *size += sizeof(m->desc);
+ } else {
+ return -EINVAL;
+ }
+ }
+ break;
+ case UVCG_FRAME: {
+ struct uvcg_frame *frm = priv1;
+ int sz = sizeof(frm->dw_frame_interval);
+
+ *size += sizeof(frm->frame);
+ *size += frm->frame.b_frame_interval_type * sz;
+ }
+ break;
+ }
+
+ ++*count;
+
+ return 0;
+}
+
+/*
+ * Fill an array of streaming descriptors.
+ *
+ * @priv1: pointer to a header, format or frame
+ * @priv2: inout parameter, pointer into a block of memory
+ * @priv3: inout parameter, pointer to a 2-dimensional array
+ */
+static int __uvcg_fill_strm(void *priv1, void *priv2, void *priv3, int n,
+ enum uvcg_strm_type type)
+{
+ void **dest = priv2;
+ struct uvc_descriptor_header ***array = priv3;
+ size_t sz;
+
+ **array = *dest;
+ ++*array;
+
+ switch (type) {
+ case UVCG_HEADER: {
+ struct uvc_input_header_descriptor *ihdr = *dest;
+ struct uvcg_streaming_header *h = priv1;
+ struct uvcg_format_ptr *f;
+
+ memcpy(*dest, &h->desc, sizeof(h->desc));
+ *dest += sizeof(h->desc);
+ sz = UVCG_STREAMING_CONTROL_SIZE;
+ list_for_each_entry(f, &h->formats, entry) {
+ memcpy(*dest, f->fmt->bmaControls, sz);
+ *dest += sz;
+ }
+ ihdr->bLength = sizeof(h->desc) + h->num_fmt * sz;
+ ihdr->bNumFormats = h->num_fmt;
+ }
+ break;
+ case UVCG_FORMAT: {
+ struct uvcg_format *fmt = priv1;
+
+ if (fmt->type == UVCG_UNCOMPRESSED) {
+ struct uvc_format_uncompressed *unc = *dest;
+ struct uvcg_uncompressed *u =
+ container_of(fmt, struct uvcg_uncompressed,
+ fmt);
+
+ memcpy(*dest, &u->desc, sizeof(u->desc));
+ *dest += sizeof(u->desc);
+ unc->bNumFrameDescriptors = fmt->num_frames;
+ unc->bFormatIndex = n + 1;
+ } else if (fmt->type == UVCG_MJPEG) {
+ struct uvc_format_mjpeg *mjp = *dest;
+ struct uvcg_mjpeg *m =
+ container_of(fmt, struct uvcg_mjpeg, fmt);
+
+ memcpy(*dest, &m->desc, sizeof(m->desc));
+ *dest += sizeof(m->desc);
+ mjp->bNumFrameDescriptors = fmt->num_frames;
+ mjp->bFormatIndex = n + 1;
+ } else {
+ return -EINVAL;
+ }
+ }
+ break;
+ case UVCG_FRAME: {
+ struct uvcg_frame *frm = priv1;
+ struct uvc_descriptor_header *h = *dest;
+
+ sz = sizeof(frm->frame);
+ memcpy(*dest, &frm->frame, sz);
+ *dest += sz;
+ sz = frm->frame.b_frame_interval_type *
+ sizeof(*frm->dw_frame_interval);
+ memcpy(*dest, frm->dw_frame_interval, sz);
+ *dest += sz;
+ if (frm->fmt_type == UVCG_UNCOMPRESSED)
+ h->bLength = UVC_DT_FRAME_UNCOMPRESSED_SIZE(
+ frm->frame.b_frame_interval_type);
+ else if (frm->fmt_type == UVCG_MJPEG)
+ h->bLength = UVC_DT_FRAME_MJPEG_SIZE(
+ frm->frame.b_frame_interval_type);
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static int uvcg_streaming_class_allow_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct config_item *streaming, *header;
+ struct f_uvc_opts *opts;
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvc_descriptor_header ***class_array, **cl_arr;
+ struct uvcg_streaming_header *target_hdr;
+ void *data, *data_save;
+ size_t size = 0, count = 0;
+ int ret = -EINVAL;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ streaming = src->ci_parent->ci_parent;
+ header = config_group_find_item(to_config_group(streaming), "header");
+ if (!header || target->ci_parent != header)
+ goto out;
+
+ opts = to_f_uvc_opts(streaming->ci_parent);
+
+ mutex_lock(&opts->lock);
+
+ class_array = __uvcg_get_stream_class_arr(src, opts);
+ if (!class_array || *class_array || opts->refcnt) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ target_hdr = to_uvcg_streaming_header(target);
+ ret = __uvcg_iter_strm_cls(target_hdr, &size, &count, __uvcg_cnt_strm);
+ if (ret)
+ goto unlock;
+
+ count += 2; /* color_matching, NULL */
+ *class_array = kcalloc(count, sizeof(void *), GFP_KERNEL);
+ if (!*class_array) {
+ ret = -ENOMEM;
+ goto unlock;
+ }
+
+ data = data_save = kzalloc(size, GFP_KERNEL);
+ if (!data) {
+ kfree(*class_array);
+ *class_array = NULL;
+ ret = PTR_ERR(data);
+ goto unlock;
+ }
+ cl_arr = *class_array;
+ ret = __uvcg_iter_strm_cls(target_hdr, &data, &cl_arr,
+ __uvcg_fill_strm);
+ if (ret) {
+ kfree(*class_array);
+ *class_array = NULL;
+ /*
+ * __uvcg_fill_strm() called from __uvcg_iter_stream_cls()
+ * might have advanced the "data", so use a backup copy
+ */
+ kfree(data_save);
+ goto unlock;
+ }
+ *cl_arr = (struct uvc_descriptor_header *)&opts->uvc_color_matching;
+
+ ++target_hdr->linked;
+ ret = 0;
+
+unlock:
+ mutex_unlock(&opts->lock);
+out:
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static int uvcg_streaming_class_drop_link(struct config_item *src,
+ struct config_item *target)
+{
+ struct config_item *streaming, *header;
+ struct f_uvc_opts *opts;
+ struct mutex *su_mutex = &src->ci_group->cg_subsys->su_mutex;
+ struct uvc_descriptor_header ***class_array;
+ struct uvcg_streaming_header *target_hdr;
+ int ret = -EINVAL;
+
+ mutex_lock(su_mutex); /* for navigating configfs hierarchy */
+
+ streaming = src->ci_parent->ci_parent;
+ header = config_group_find_item(to_config_group(streaming), "header");
+ if (!header || target->ci_parent != header)
+ goto out;
+
+ opts = to_f_uvc_opts(streaming->ci_parent);
+
+ mutex_lock(&opts->lock);
+
+ class_array = __uvcg_get_stream_class_arr(src, opts);
+ if (!class_array || !*class_array)
+ goto unlock;
+
+ if (opts->refcnt) {
+ ret = -EBUSY;
+ goto unlock;
+ }
+
+ target_hdr = to_uvcg_streaming_header(target);
+ --target_hdr->linked;
+ kfree(**class_array);
+ kfree(*class_array);
+ *class_array = NULL;
+ ret = 0;
+
+unlock:
+ mutex_unlock(&opts->lock);
+out:
+ mutex_unlock(su_mutex);
+ return ret;
+}
+
+static struct configfs_item_operations uvcg_streaming_class_item_ops = {
+ .allow_link = uvcg_streaming_class_allow_link,
+ .drop_link = uvcg_streaming_class_drop_link,
+};
+
+static struct config_item_type uvcg_streaming_class_type = {
+ .ct_item_ops = &uvcg_streaming_class_item_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_streaming_class_default_groups[] = {
+ &uvcg_streaming_class_fs.group,
+ &uvcg_streaming_class_hs.group,
+ &uvcg_streaming_class_ss.group,
+ NULL,
+};
+
+/* streaming/class */
+static struct uvcg_streaming_class_grp {
+ struct config_group group;
+} uvcg_streaming_class_grp;
+
+static struct config_item_type uvcg_streaming_class_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_streaming_default_groups[] = {
+ &uvcg_streaming_header_grp.group,
+ &uvcg_uncompressed_grp.group,
+ &uvcg_mjpeg_grp.group,
+ &uvcg_color_matching_grp.group,
+ &uvcg_streaming_class_grp.group,
+ NULL,
+};
+
+/* streaming */
+static struct uvcg_streaming_grp {
+ struct config_group group;
+} uvcg_streaming_grp;
+
+static struct config_item_type uvcg_streaming_grp_type = {
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_group *uvcg_default_groups[] = {
+ &uvcg_control_grp.group,
+ &uvcg_streaming_grp.group,
+ NULL,
+};
+
+static inline struct f_uvc_opts *to_f_uvc_opts(struct config_item *item)
+{
+ return container_of(to_config_group(item), struct f_uvc_opts,
+ func_inst.group);
+}
+
+CONFIGFS_ATTR_STRUCT(f_uvc_opts);
+CONFIGFS_ATTR_OPS(f_uvc_opts);
+
+static void uvc_attr_release(struct config_item *item)
+{
+ struct f_uvc_opts *opts = to_f_uvc_opts(item);
+
+ usb_put_function_instance(&opts->func_inst);
+}
+
+static struct configfs_item_operations uvc_item_ops = {
+ .release = uvc_attr_release,
+ .show_attribute = f_uvc_opts_attr_show,
+ .store_attribute = f_uvc_opts_attr_store,
+};
+
+#define UVCG_OPTS_ATTR(cname, conv, str2u, uxx, vnoc, limit) \
+static ssize_t f_uvc_opts_##cname##_show( \
+ struct f_uvc_opts *opts, char *page) \
+{ \
+ int result; \
+ \
+ mutex_lock(&opts->lock); \
+ result = sprintf(page, "%d\n", conv(opts->cname)); \
+ mutex_unlock(&opts->lock); \
+ \
+ return result; \
+} \
+ \
+static ssize_t \
+f_uvc_opts_##cname##_store(struct f_uvc_opts *opts, \
+ const char *page, size_t len) \
+{ \
+ int ret; \
+ uxx num; \
+ \
+ mutex_lock(&opts->lock); \
+ if (opts->refcnt) { \
+ ret = -EBUSY; \
+ goto end; \
+ } \
+ \
+ ret = str2u(page, 0, &num); \
+ if (ret) \
+ goto end; \
+ \
+ if (num > limit) { \
+ ret = -EINVAL; \
+ goto end; \
+ } \
+ opts->cname = vnoc(num); \
+ ret = len; \
+end: \
+ mutex_unlock(&opts->lock); \
+ return ret; \
+} \
+ \
+static struct f_uvc_opts_attribute \
+ f_uvc_opts_attribute_##cname = \
+ __CONFIGFS_ATTR(cname, S_IRUGO | S_IWUSR, \
+ f_uvc_opts_##cname##_show, \
+ f_uvc_opts_##cname##_store)
+
+#define identity_conv(x) (x)
+
+UVCG_OPTS_ATTR(streaming_interval, identity_conv, kstrtou8, u8, identity_conv,
+ 16);
+UVCG_OPTS_ATTR(streaming_maxpacket, le16_to_cpu, kstrtou16, u16, le16_to_cpu,
+ 3072);
+UVCG_OPTS_ATTR(streaming_maxburst, identity_conv, kstrtou8, u8, identity_conv,
+ 15);
+
+#undef identity_conv
+
+#undef UVCG_OPTS_ATTR
+
+static struct configfs_attribute *uvc_attrs[] = {
+ &f_uvc_opts_attribute_streaming_interval.attr,
+ &f_uvc_opts_attribute_streaming_maxpacket.attr,
+ &f_uvc_opts_attribute_streaming_maxburst.attr,
+ NULL,
+};
+
+static struct config_item_type uvc_func_type = {
+ .ct_item_ops = &uvc_item_ops,
+ .ct_attrs = uvc_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static inline void uvcg_init_group(struct config_group *g,
+ struct config_group **default_groups,
+ const char *name,
+ struct config_item_type *type)
+{
+ g->default_groups = default_groups;
+ config_group_init_type_name(g, name, type);
+}
+
+int uvcg_attach_configfs(struct f_uvc_opts *opts)
+{
+ config_group_init_type_name(&uvcg_control_header_grp.group,
+ "header",
+ &uvcg_control_header_grp_type);
+ config_group_init_type_name(&uvcg_default_processing.group,
+ "default",
+ &uvcg_default_processing_type);
+ uvcg_init_group(&uvcg_processing_grp.group,
+ uvcg_processing_default_groups,
+ "processing",
+ &uvcg_processing_grp_type);
+ config_group_init_type_name(&uvcg_default_camera.group,
+ "default",
+ &uvcg_default_camera_type);
+ uvcg_init_group(&uvcg_camera_grp.group,
+ uvcg_camera_default_groups,
+ "camera",
+ &uvcg_camera_grp_type);
+ config_group_init_type_name(&uvcg_default_output.group,
+ "default",
+ &uvcg_default_output_type);
+ uvcg_init_group(&uvcg_output_grp.group,
+ uvcg_output_default_groups,
+ "output",
+ &uvcg_output_grp_type);
+ uvcg_init_group(&uvcg_terminal_grp.group,
+ uvcg_terminal_default_groups,
+ "terminal",
+ &uvcg_terminal_grp_type);
+ config_group_init_type_name(&uvcg_control_class_fs.group,
+ "fs",
+ &uvcg_control_class_type);
+ config_group_init_type_name(&uvcg_control_class_ss.group,
+ "ss",
+ &uvcg_control_class_type);
+ uvcg_init_group(&uvcg_control_class_grp.group,
+ uvcg_control_class_default_groups,
+ "class",
+ &uvcg_control_class_grp_type);
+ uvcg_init_group(&uvcg_control_grp.group,
+ uvcg_control_default_groups,
+ "control",
+ &uvcg_control_grp_type);
+ config_group_init_type_name(&uvcg_streaming_header_grp.group,
+ "header",
+ &uvcg_streaming_header_grp_type);
+ config_group_init_type_name(&uvcg_uncompressed_grp.group,
+ "uncompressed",
+ &uvcg_uncompressed_grp_type);
+ config_group_init_type_name(&uvcg_mjpeg_grp.group,
+ "mjpeg",
+ &uvcg_mjpeg_grp_type);
+ config_group_init_type_name(&uvcg_default_color_matching.group,
+ "default",
+ &uvcg_default_color_matching_type);
+ uvcg_init_group(&uvcg_color_matching_grp.group,
+ uvcg_color_matching_default_groups,
+ "color_matching",
+ &uvcg_color_matching_grp_type);
+ config_group_init_type_name(&uvcg_streaming_class_fs.group,
+ "fs",
+ &uvcg_streaming_class_type);
+ config_group_init_type_name(&uvcg_streaming_class_hs.group,
+ "hs",
+ &uvcg_streaming_class_type);
+ config_group_init_type_name(&uvcg_streaming_class_ss.group,
+ "ss",
+ &uvcg_streaming_class_type);
+ uvcg_init_group(&uvcg_streaming_class_grp.group,
+ uvcg_streaming_class_default_groups,
+ "class",
+ &uvcg_streaming_class_grp_type);
+ uvcg_init_group(&uvcg_streaming_grp.group,
+ uvcg_streaming_default_groups,
+ "streaming",
+ &uvcg_streaming_grp_type);
+ uvcg_init_group(&opts->func_inst.group,
+ uvcg_default_groups,
+ "",
+ &uvc_func_type);
+ return 0;
+}
diff --git a/drivers/usb/gadget/function/uvc_configfs.h b/drivers/usb/gadget/function/uvc_configfs.h
new file mode 100644
index 000000000000..085e67be7c71
--- /dev/null
+++ b/drivers/usb/gadget/function/uvc_configfs.h
@@ -0,0 +1,22 @@
+/*
+ * uvc_configfs.h
+ *
+ * Configfs support for the uvc function.
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Author: Andrzej Pietrasiewicz <andrzej.p@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef UVC_CONFIGFS_H
+#define UVC_CONFIGFS_H
+
+struct f_uvc_opts;
+
+int uvcg_attach_configfs(struct f_uvc_opts *opts);
+
+#endif /* UVC_CONFIGFS_H */
diff --git a/drivers/usb/gadget/legacy/Kconfig b/drivers/usb/gadget/legacy/Kconfig
index fd48ef3af4eb..113c87e22117 100644
--- a/drivers/usb/gadget/legacy/Kconfig
+++ b/drivers/usb/gadget/legacy/Kconfig
@@ -40,7 +40,7 @@ config USB_ZERO
dynamically linked module called "g_zero".
config USB_ZERO_HNPTEST
- boolean "HNP Test Device"
+ bool "HNP Test Device"
depends on USB_ZERO && USB_OTG
help
You can configure this device to enumerate using the device
diff --git a/drivers/usb/gadget/udc/Kconfig b/drivers/usb/gadget/udc/Kconfig
index b8e213eb36cc..9a3a6b00391a 100644
--- a/drivers/usb/gadget/udc/Kconfig
+++ b/drivers/usb/gadget/udc/Kconfig
@@ -32,6 +32,7 @@ menu "USB Peripheral Controller"
config USB_AT91
tristate "Atmel AT91 USB Device Port"
depends on ARCH_AT91
+ depends on OF || COMPILE_TEST
help
Many Atmel AT91 processors (such as the AT91RM2000) have a
full speed USB Device Port with support for five configurable
@@ -198,7 +199,7 @@ config USB_S3C2410
S3C2440 processors.
config USB_S3C2410_DEBUG
- boolean "S3C2410 udc debug messages"
+ bool "S3C2410 udc debug messages"
depends on USB_S3C2410
config USB_S3C_HSUDC
@@ -287,7 +288,7 @@ config USB_NET2272
gadget drivers to also be dynamically linked.
config USB_NET2272_DMA
- boolean "Support external DMA controller"
+ bool "Support external DMA controller"
depends on USB_NET2272 && HAS_DMA
help
The NET2272 part can optionally support an external DMA
diff --git a/drivers/usb/gadget/udc/at91_udc.c b/drivers/usb/gadget/udc/at91_udc.c
index c862656d18b8..2fbedca3c2b4 100644
--- a/drivers/usb/gadget/udc/at91_udc.c
+++ b/drivers/usb/gadget/udc/at91_udc.c
@@ -31,16 +31,9 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_data/atmel.h>
-
-#include <asm/byteorder.h>
-#include <mach/hardware.h>
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/gpio.h>
-
-#include <mach/cpu.h>
-#include <mach/at91sam9261_matrix.h>
-#include <mach/at91_matrix.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/atmel-matrix.h>
#include "at91_udc.h"
@@ -66,7 +59,15 @@
#define DRIVER_VERSION "3 May 2006"
static const char driver_name [] = "at91_udc";
-static const char ep0name[] = "ep0";
+static const char * const ep_names[] = {
+ "ep0",
+ "ep1",
+ "ep2",
+ "ep3-int",
+ "ep4",
+ "ep5",
+};
+#define ep0name ep_names[0]
#define VBUS_POLL_TIMEOUT msecs_to_jiffies(1000)
@@ -176,7 +177,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
udc->enabled
? (udc->vbus ? "active" : "enabled")
: "disabled",
- udc->selfpowered ? "self" : "VBUS",
+ udc->gadget.is_selfpowered ? "self" : "VBUS",
udc->suspended ? ", suspended" : "",
udc->driver ? udc->driver->driver.name : "(none)");
@@ -895,8 +896,6 @@ static void clk_on(struct at91_udc *udc)
return;
udc->clocked = 1;
- if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_enable(udc->uclk);
clk_enable(udc->iclk);
clk_enable(udc->fclk);
}
@@ -909,8 +908,6 @@ static void clk_off(struct at91_udc *udc)
udc->gadget.speed = USB_SPEED_UNKNOWN;
clk_disable(udc->fclk);
clk_disable(udc->iclk);
- if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_disable(udc->uclk);
}
/*
@@ -919,8 +916,6 @@ static void clk_off(struct at91_udc *udc)
*/
static void pullup(struct at91_udc *udc, int is_on)
{
- int active = !udc->board.pullup_active_low;
-
if (!udc->enabled || !udc->vbus)
is_on = 0;
DBG("%sactive\n", is_on ? "" : "in");
@@ -929,40 +924,15 @@ static void pullup(struct at91_udc *udc, int is_on)
clk_on(udc);
at91_udp_write(udc, AT91_UDP_ICR, AT91_UDP_RXRSM);
at91_udp_write(udc, AT91_UDP_TXVC, 0);
- if (cpu_is_at91rm9200())
- gpio_set_value(udc->board.pullup_pin, active);
- else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
- u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
-
- txvc |= AT91_UDP_TXVC_PUON;
- at91_udp_write(udc, AT91_UDP_TXVC, txvc);
- } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
- u32 usbpucr;
-
- usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
- usbpucr |= AT91_MATRIX_USBPUCR_PUON;
- at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
- }
} else {
stop_activity(udc);
at91_udp_write(udc, AT91_UDP_IDR, AT91_UDP_RXRSM);
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
- if (cpu_is_at91rm9200())
- gpio_set_value(udc->board.pullup_pin, !active);
- else if (cpu_is_at91sam9260() || cpu_is_at91sam9263() || cpu_is_at91sam9g20()) {
- u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
-
- txvc &= ~AT91_UDP_TXVC_PUON;
- at91_udp_write(udc, AT91_UDP_TXVC, txvc);
- } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
- u32 usbpucr;
-
- usbpucr = at91_matrix_read(AT91_MATRIX_USBPUCR);
- usbpucr &= ~AT91_MATRIX_USBPUCR_PUON;
- at91_matrix_write(AT91_MATRIX_USBPUCR, usbpucr);
- }
clk_off(udc);
}
+
+ if (udc->caps && udc->caps->pullup)
+ udc->caps->pullup(udc, is_on);
}
/* vbus is here! turn everything on that's ready */
@@ -1000,7 +970,7 @@ static int at91_set_selfpowered(struct usb_gadget *gadget, int is_on)
unsigned long flags;
spin_lock_irqsave(&udc->lock, flags);
- udc->selfpowered = (is_on != 0);
+ gadget->is_selfpowered = (is_on != 0);
spin_unlock_irqrestore(&udc->lock, flags);
return 0;
}
@@ -1149,7 +1119,7 @@ static void handle_setup(struct at91_udc *udc, struct at91_ep *ep, u32 csr)
*/
case ((USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE) << 8)
| USB_REQ_GET_STATUS:
- tmp = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+ tmp = (udc->gadget.is_selfpowered << USB_DEVICE_SELF_POWERED);
if (at91_udp_read(udc, AT91_UDP_GLB_STAT) & AT91_UDP_ESR)
tmp |= (1 << USB_DEVICE_REMOTE_WAKEUP);
PACKET("get device status\n");
@@ -1535,74 +1505,6 @@ static irqreturn_t at91_udc_irq (int irq, void *_udc)
/*-------------------------------------------------------------------------*/
-static struct at91_udc controller = {
- .gadget = {
- .ops = &at91_udc_ops,
- .ep0 = &controller.ep[0].ep,
- .name = driver_name,
- },
- .ep[0] = {
- .ep = {
- .name = ep0name,
- .ops = &at91_ep_ops,
- },
- .udc = &controller,
- .maxpacket = 8,
- .int_mask = 1 << 0,
- },
- .ep[1] = {
- .ep = {
- .name = "ep1",
- .ops = &at91_ep_ops,
- },
- .udc = &controller,
- .is_pingpong = 1,
- .maxpacket = 64,
- .int_mask = 1 << 1,
- },
- .ep[2] = {
- .ep = {
- .name = "ep2",
- .ops = &at91_ep_ops,
- },
- .udc = &controller,
- .is_pingpong = 1,
- .maxpacket = 64,
- .int_mask = 1 << 2,
- },
- .ep[3] = {
- .ep = {
- /* could actually do bulk too */
- .name = "ep3-int",
- .ops = &at91_ep_ops,
- },
- .udc = &controller,
- .maxpacket = 8,
- .int_mask = 1 << 3,
- },
- .ep[4] = {
- .ep = {
- .name = "ep4",
- .ops = &at91_ep_ops,
- },
- .udc = &controller,
- .is_pingpong = 1,
- .maxpacket = 256,
- .int_mask = 1 << 4,
- },
- .ep[5] = {
- .ep = {
- .name = "ep5",
- .ops = &at91_ep_ops,
- },
- .udc = &controller,
- .is_pingpong = 1,
- .maxpacket = 256,
- .int_mask = 1 << 5,
- },
- /* ep6 and ep7 are also reserved (custom silicon might use them) */
-};
-
static void at91_vbus_update(struct at91_udc *udc, unsigned value)
{
value ^= udc->board.vbus_active_low;
@@ -1653,7 +1555,7 @@ static int at91_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.of_node = udc->pdev->dev.of_node;
udc->enabled = 1;
- udc->selfpowered = 1;
+ udc->gadget.is_selfpowered = 1;
return 0;
}
@@ -1687,12 +1589,202 @@ static void at91udc_shutdown(struct platform_device *dev)
spin_unlock_irqrestore(&udc->lock, flags);
}
-static void at91udc_of_init(struct at91_udc *udc,
- struct device_node *np)
+static int at91rm9200_udc_init(struct at91_udc *udc)
+{
+ struct at91_ep *ep;
+ int ret;
+ int i;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ ep = &udc->ep[i];
+
+ switch (i) {
+ case 0:
+ case 3:
+ ep->maxpacket = 8;
+ break;
+ case 1 ... 2:
+ ep->maxpacket = 64;
+ break;
+ case 4 ... 5:
+ ep->maxpacket = 256;
+ break;
+ }
+ }
+
+ if (!gpio_is_valid(udc->board.pullup_pin)) {
+ DBG("no D+ pullup?\n");
+ return -ENODEV;
+ }
+
+ ret = devm_gpio_request(&udc->pdev->dev, udc->board.pullup_pin,
+ "udc_pullup");
+ if (ret) {
+ DBG("D+ pullup is busy\n");
+ return ret;
+ }
+
+ gpio_direction_output(udc->board.pullup_pin,
+ udc->board.pullup_active_low);
+
+ return 0;
+}
+
+static void at91rm9200_udc_pullup(struct at91_udc *udc, int is_on)
+{
+ int active = !udc->board.pullup_active_low;
+
+ if (is_on)
+ gpio_set_value(udc->board.pullup_pin, active);
+ else
+ gpio_set_value(udc->board.pullup_pin, !active);
+}
+
+static const struct at91_udc_caps at91rm9200_udc_caps = {
+ .init = at91rm9200_udc_init,
+ .pullup = at91rm9200_udc_pullup,
+};
+
+static int at91sam9260_udc_init(struct at91_udc *udc)
+{
+ struct at91_ep *ep;
+ int i;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ ep = &udc->ep[i];
+
+ switch (i) {
+ case 0 ... 3:
+ ep->maxpacket = 64;
+ break;
+ case 4 ... 5:
+ ep->maxpacket = 512;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static void at91sam9260_udc_pullup(struct at91_udc *udc, int is_on)
+{
+ u32 txvc = at91_udp_read(udc, AT91_UDP_TXVC);
+
+ if (is_on)
+ txvc |= AT91_UDP_TXVC_PUON;
+ else
+ txvc &= ~AT91_UDP_TXVC_PUON;
+
+ at91_udp_write(udc, AT91_UDP_TXVC, txvc);
+}
+
+static const struct at91_udc_caps at91sam9260_udc_caps = {
+ .init = at91sam9260_udc_init,
+ .pullup = at91sam9260_udc_pullup,
+};
+
+static int at91sam9261_udc_init(struct at91_udc *udc)
+{
+ struct at91_ep *ep;
+ int i;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ ep = &udc->ep[i];
+
+ switch (i) {
+ case 0:
+ ep->maxpacket = 8;
+ break;
+ case 1 ... 3:
+ ep->maxpacket = 64;
+ break;
+ case 4 ... 5:
+ ep->maxpacket = 256;
+ break;
+ }
+ }
+
+ udc->matrix = syscon_regmap_lookup_by_phandle(udc->pdev->dev.of_node,
+ "atmel,matrix");
+ if (IS_ERR(udc->matrix))
+ return PTR_ERR(udc->matrix);
+
+ return 0;
+}
+
+static void at91sam9261_udc_pullup(struct at91_udc *udc, int is_on)
+{
+ u32 usbpucr = 0;
+
+ if (is_on)
+ usbpucr = AT91_MATRIX_USBPUCR_PUON;
+
+ regmap_update_bits(udc->matrix, AT91SAM9261_MATRIX_USBPUCR,
+ AT91_MATRIX_USBPUCR_PUON, usbpucr);
+}
+
+static const struct at91_udc_caps at91sam9261_udc_caps = {
+ .init = at91sam9261_udc_init,
+ .pullup = at91sam9261_udc_pullup,
+};
+
+static int at91sam9263_udc_init(struct at91_udc *udc)
+{
+ struct at91_ep *ep;
+ int i;
+
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ ep = &udc->ep[i];
+
+ switch (i) {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ ep->maxpacket = 64;
+ break;
+ case 4:
+ case 5:
+ ep->maxpacket = 256;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static const struct at91_udc_caps at91sam9263_udc_caps = {
+ .init = at91sam9263_udc_init,
+ .pullup = at91sam9260_udc_pullup,
+};
+
+static const struct of_device_id at91_udc_dt_ids[] = {
+ {
+ .compatible = "atmel,at91rm9200-udc",
+ .data = &at91rm9200_udc_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9260-udc",
+ .data = &at91sam9260_udc_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9261-udc",
+ .data = &at91sam9261_udc_caps,
+ },
+ {
+ .compatible = "atmel,at91sam9263-udc",
+ .data = &at91sam9263_udc_caps,
+ },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
+
+static void at91udc_of_init(struct at91_udc *udc, struct device_node *np)
{
struct at91_udc_data *board = &udc->board;
- u32 val;
+ const struct of_device_id *match;
enum of_gpio_flags flags;
+ u32 val;
if (of_property_read_u32(np, "atmel,vbus-polled", &val) == 0)
board->vbus_polled = 1;
@@ -1705,6 +1797,10 @@ static void at91udc_of_init(struct at91_udc *udc,
&flags);
board->pullup_active_low = (flags & OF_GPIO_ACTIVE_LOW) ? 1 : 0;
+
+ match = of_match_node(at91_udc_dt_ids, np);
+ if (match)
+ udc->caps = match->data;
}
static int at91udc_probe(struct platform_device *pdev)
@@ -1713,97 +1809,67 @@ static int at91udc_probe(struct platform_device *pdev)
struct at91_udc *udc;
int retval;
struct resource *res;
+ struct at91_ep *ep;
+ int i;
- if (!dev_get_platdata(dev) && !pdev->dev.of_node) {
- /* small (so we copy it) but critical! */
- DBG("missing platform_data\n");
- return -ENODEV;
- }
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res)
- return -ENXIO;
-
- if (!request_mem_region(res->start, resource_size(res), driver_name)) {
- DBG("someone's using UDC memory\n");
- return -EBUSY;
- }
+ udc = devm_kzalloc(dev, sizeof(*udc), GFP_KERNEL);
+ if (!udc)
+ return -ENOMEM;
/* init software state */
- udc = &controller;
udc->gadget.dev.parent = dev;
- if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node)
- at91udc_of_init(udc, pdev->dev.of_node);
- else
- memcpy(&udc->board, dev_get_platdata(dev),
- sizeof(struct at91_udc_data));
+ at91udc_of_init(udc, pdev->dev.of_node);
udc->pdev = pdev;
udc->enabled = 0;
spin_lock_init(&udc->lock);
- /* rm9200 needs manual D+ pullup; off by default */
- if (cpu_is_at91rm9200()) {
- if (!gpio_is_valid(udc->board.pullup_pin)) {
- DBG("no D+ pullup?\n");
- retval = -ENODEV;
- goto fail0;
- }
- retval = gpio_request(udc->board.pullup_pin, "udc_pullup");
- if (retval) {
- DBG("D+ pullup is busy\n");
- goto fail0;
- }
- gpio_direction_output(udc->board.pullup_pin,
- udc->board.pullup_active_low);
- }
+ udc->gadget.ops = &at91_udc_ops;
+ udc->gadget.ep0 = &udc->ep[0].ep;
+ udc->gadget.name = driver_name;
+ udc->gadget.dev.init_name = "gadget";
- /* newer chips have more FIFO memory than rm9200 */
- if (cpu_is_at91sam9260() || cpu_is_at91sam9g20()) {
- udc->ep[0].maxpacket = 64;
- udc->ep[3].maxpacket = 64;
- udc->ep[4].maxpacket = 512;
- udc->ep[5].maxpacket = 512;
- } else if (cpu_is_at91sam9261() || cpu_is_at91sam9g10()) {
- udc->ep[3].maxpacket = 64;
- } else if (cpu_is_at91sam9263()) {
- udc->ep[0].maxpacket = 64;
- udc->ep[3].maxpacket = 64;
+ for (i = 0; i < NUM_ENDPOINTS; i++) {
+ ep = &udc->ep[i];
+ ep->ep.name = ep_names[i];
+ ep->ep.ops = &at91_ep_ops;
+ ep->udc = udc;
+ ep->int_mask = BIT(i);
+ if (i != 0 && i != 3)
+ ep->is_pingpong = 1;
}
- udc->udp_baseaddr = ioremap(res->start, resource_size(res));
- if (!udc->udp_baseaddr) {
- retval = -ENOMEM;
- goto fail0a;
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ udc->udp_baseaddr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(udc->udp_baseaddr))
+ return PTR_ERR(udc->udp_baseaddr);
+
+ if (udc->caps && udc->caps->init) {
+ retval = udc->caps->init(udc);
+ if (retval)
+ return retval;
}
udc_reinit(udc);
/* get interface and function clocks */
- udc->iclk = clk_get(dev, "udc_clk");
- udc->fclk = clk_get(dev, "udpck");
- if (IS_ENABLED(CONFIG_COMMON_CLK))
- udc->uclk = clk_get(dev, "usb_clk");
- if (IS_ERR(udc->iclk) || IS_ERR(udc->fclk) ||
- (IS_ENABLED(CONFIG_COMMON_CLK) && IS_ERR(udc->uclk))) {
- DBG("clocks missing\n");
- retval = -ENODEV;
- goto fail1;
- }
+ udc->iclk = devm_clk_get(dev, "pclk");
+ if (IS_ERR(udc->iclk))
+ return PTR_ERR(udc->iclk);
+
+ udc->fclk = devm_clk_get(dev, "hclk");
+ if (IS_ERR(udc->fclk))
+ return PTR_ERR(udc->fclk);
/* don't do anything until we have both gadget driver and VBUS */
- if (IS_ENABLED(CONFIG_COMMON_CLK)) {
- clk_set_rate(udc->uclk, 48000000);
- retval = clk_prepare(udc->uclk);
- if (retval)
- goto fail1;
- }
+ clk_set_rate(udc->fclk, 48000000);
retval = clk_prepare(udc->fclk);
if (retval)
- goto fail1a;
+ return retval;
retval = clk_prepare_enable(udc->iclk);
if (retval)
- goto fail1b;
+ goto err_unprepare_fclk;
+
at91_udp_write(udc, AT91_UDP_TXVC, AT91_UDP_TXVC_TXVDIS);
at91_udp_write(udc, AT91_UDP_IDR, 0xffffffff);
/* Clear all pending interrupts - UDP may be used by bootloader. */
@@ -1812,18 +1878,21 @@ static int at91udc_probe(struct platform_device *pdev)
/* request UDC and maybe VBUS irqs */
udc->udp_irq = platform_get_irq(pdev, 0);
- retval = request_irq(udc->udp_irq, at91_udc_irq,
- 0, driver_name, udc);
- if (retval < 0) {
+ retval = devm_request_irq(dev, udc->udp_irq, at91_udc_irq, 0,
+ driver_name, udc);
+ if (retval) {
DBG("request irq %d failed\n", udc->udp_irq);
- goto fail1c;
+ goto err_unprepare_iclk;
}
+
if (gpio_is_valid(udc->board.vbus_pin)) {
- retval = gpio_request(udc->board.vbus_pin, "udc_vbus");
- if (retval < 0) {
+ retval = devm_gpio_request(dev, udc->board.vbus_pin,
+ "udc_vbus");
+ if (retval) {
DBG("request vbus pin failed\n");
- goto fail2;
+ goto err_unprepare_iclk;
}
+
gpio_direction_input(udc->board.vbus_pin);
/*
@@ -1840,12 +1909,13 @@ static int at91udc_probe(struct platform_device *pdev)
mod_timer(&udc->vbus_timer,
jiffies + VBUS_POLL_TIMEOUT);
} else {
- if (request_irq(gpio_to_irq(udc->board.vbus_pin),
- at91_vbus_irq, 0, driver_name, udc)) {
+ retval = devm_request_irq(dev,
+ gpio_to_irq(udc->board.vbus_pin),
+ at91_vbus_irq, 0, driver_name, udc);
+ if (retval) {
DBG("request vbus irq %d failed\n",
udc->board.vbus_pin);
- retval = -EBUSY;
- goto fail3;
+ goto err_unprepare_iclk;
}
}
} else {
@@ -1854,49 +1924,27 @@ static int at91udc_probe(struct platform_device *pdev)
}
retval = usb_add_gadget_udc(dev, &udc->gadget);
if (retval)
- goto fail4;
+ goto err_unprepare_iclk;
dev_set_drvdata(dev, udc);
device_init_wakeup(dev, 1);
create_debug_file(udc);
INFO("%s version %s\n", driver_name, DRIVER_VERSION);
return 0;
-fail4:
- if (gpio_is_valid(udc->board.vbus_pin) && !udc->board.vbus_polled)
- free_irq(gpio_to_irq(udc->board.vbus_pin), udc);
-fail3:
- if (gpio_is_valid(udc->board.vbus_pin))
- gpio_free(udc->board.vbus_pin);
-fail2:
- free_irq(udc->udp_irq, udc);
-fail1c:
+
+err_unprepare_iclk:
clk_unprepare(udc->iclk);
-fail1b:
+err_unprepare_fclk:
clk_unprepare(udc->fclk);
-fail1a:
- if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_unprepare(udc->uclk);
-fail1:
- if (IS_ENABLED(CONFIG_COMMON_CLK) && !IS_ERR(udc->uclk))
- clk_put(udc->uclk);
- if (!IS_ERR(udc->fclk))
- clk_put(udc->fclk);
- if (!IS_ERR(udc->iclk))
- clk_put(udc->iclk);
- iounmap(udc->udp_baseaddr);
-fail0a:
- if (cpu_is_at91rm9200())
- gpio_free(udc->board.pullup_pin);
-fail0:
- release_mem_region(res->start, resource_size(res));
+
DBG("%s probe failed, %d\n", driver_name, retval);
+
return retval;
}
static int __exit at91udc_remove(struct platform_device *pdev)
{
struct at91_udc *udc = platform_get_drvdata(pdev);
- struct resource *res;
unsigned long flags;
DBG("remove\n");
@@ -1911,29 +1959,9 @@ static int __exit at91udc_remove(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 0);
remove_debug_file(udc);
- if (gpio_is_valid(udc->board.vbus_pin)) {
- free_irq(gpio_to_irq(udc->board.vbus_pin), udc);
- gpio_free(udc->board.vbus_pin);
- }
- free_irq(udc->udp_irq, udc);
- iounmap(udc->udp_baseaddr);
-
- if (cpu_is_at91rm9200())
- gpio_free(udc->board.pullup_pin);
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- release_mem_region(res->start, resource_size(res));
-
- if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_unprepare(udc->uclk);
clk_unprepare(udc->fclk);
clk_unprepare(udc->iclk);
- clk_put(udc->iclk);
- clk_put(udc->fclk);
- if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_put(udc->uclk);
-
return 0;
}
@@ -1989,15 +2017,6 @@ static int at91udc_resume(struct platform_device *pdev)
#define at91udc_resume NULL
#endif
-#if defined(CONFIG_OF)
-static const struct of_device_id at91_udc_dt_ids[] = {
- { .compatible = "atmel,at91rm9200-udc" },
- { /* sentinel */ }
-};
-
-MODULE_DEVICE_TABLE(of, at91_udc_dt_ids);
-#endif
-
static struct platform_driver at91_udc_driver = {
.remove = __exit_p(at91udc_remove),
.shutdown = at91udc_shutdown,
@@ -2005,7 +2024,7 @@ static struct platform_driver at91_udc_driver = {
.resume = at91udc_resume,
.driver = {
.name = (char *) driver_name,
- .of_match_table = of_match_ptr(at91_udc_dt_ids),
+ .of_match_table = at91_udc_dt_ids,
},
};
diff --git a/drivers/usb/gadget/udc/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h
index 017524663381..2679c8b217cc 100644
--- a/drivers/usb/gadget/udc/at91_udc.h
+++ b/drivers/usb/gadget/udc/at91_udc.h
@@ -107,6 +107,11 @@ struct at91_ep {
unsigned fifo_bank:1;
};
+struct at91_udc_caps {
+ int (*init)(struct at91_udc *udc);
+ void (*pullup)(struct at91_udc *udc, int is_on);
+};
+
/*
* driver is non-SMP, and just blocks IRQs whenever it needs
* access protection for chip registers or driver state
@@ -115,6 +120,7 @@ struct at91_udc {
struct usb_gadget gadget;
struct at91_ep ep[NUM_ENDPOINTS];
struct usb_gadget_driver *driver;
+ const struct at91_udc_caps *caps;
unsigned vbus:1;
unsigned enabled:1;
unsigned clocked:1;
@@ -122,11 +128,10 @@ struct at91_udc {
unsigned req_pending:1;
unsigned wait_for_addr_ack:1;
unsigned wait_for_config_ack:1;
- unsigned selfpowered:1;
unsigned active_suspend:1;
u8 addr;
struct at91_udc_data board;
- struct clk *iclk, *fclk, *uclk;
+ struct clk *iclk, *fclk;
struct platform_device *pdev;
struct proc_dir_entry *pde;
void __iomem *udp_baseaddr;
@@ -134,6 +139,7 @@ struct at91_udc {
spinlock_t lock;
struct timer_list vbus_timer;
struct work_struct vbus_timer_work;
+ struct regmap *matrix;
};
static inline struct at91_udc *to_udc(struct usb_gadget *g)
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 9f93bed42052..d79cb35dbf8a 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -8,6 +8,7 @@
* published by the Free Software Foundation.
*/
#include <linux/clk.h>
+#include <linux/clk/at91_pmc.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
@@ -264,14 +265,17 @@ static void usba_init_debugfs(struct usba_udc *udc)
goto err_root;
udc->debugfs_root = root;
- regs = debugfs_create_file("regs", 0400, root, udc, &regs_dbg_fops);
- if (!regs)
- goto err_regs;
-
regs_resource = platform_get_resource(udc->pdev, IORESOURCE_MEM,
CTRL_IOMEM_ID);
- regs->d_inode->i_size = resource_size(regs_resource);
- udc->debugfs_regs = regs;
+
+ if (regs_resource) {
+ regs = debugfs_create_file_size("regs", 0400, root, udc,
+ &regs_dbg_fops,
+ resource_size(regs_resource));
+ if (!regs)
+ goto err_regs;
+ udc->debugfs_regs = regs;
+ }
usba_ep_init_debugfs(udc, to_usba_ep(udc->gadget.ep0));
@@ -315,6 +319,17 @@ static inline void usba_cleanup_debugfs(struct usba_udc *udc)
}
#endif
+static inline u32 usba_int_enb_get(struct usba_udc *udc)
+{
+ return udc->int_enb_cache;
+}
+
+static inline void usba_int_enb_set(struct usba_udc *udc, u32 val)
+{
+ usba_writel(udc, INT_ENB, val);
+ udc->int_enb_cache = val;
+}
+
static int vbus_is_present(struct usba_udc *udc)
{
if (gpio_is_valid(udc->vbus_pin))
@@ -324,27 +339,22 @@ static int vbus_is_present(struct usba_udc *udc)
return 1;
}
-#if defined(CONFIG_ARCH_AT91SAM9RL)
-
-#include <linux/clk/at91_pmc.h>
-
-static void toggle_bias(int is_on)
+static void toggle_bias(struct usba_udc *udc, int is_on)
{
- unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
-
- if (is_on)
- at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
- else
- at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+ if (udc->errata && udc->errata->toggle_bias)
+ udc->errata->toggle_bias(udc, is_on);
}
-#else
-
-static void toggle_bias(int is_on)
+static void generate_bias_pulse(struct usba_udc *udc)
{
-}
+ if (!udc->bias_pulse_needed)
+ return;
-#endif /* CONFIG_ARCH_AT91SAM9RL */
+ if (udc->errata && udc->errata->pulse_bias)
+ udc->errata->pulse_bias(udc);
+
+ udc->bias_pulse_needed = false;
+}
static void next_fifo_transaction(struct usba_ep *ep, struct usba_request *req)
{
@@ -601,16 +611,14 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
if (ep->can_dma) {
u32 ctrl;
- usba_writel(udc, INT_ENB,
- (usba_readl(udc, INT_ENB)
- | USBA_BF(EPT_INT, 1 << ep->index)
- | USBA_BF(DMA_INT, 1 << ep->index)));
+ usba_int_enb_set(udc, usba_int_enb_get(udc) |
+ USBA_BF(EPT_INT, 1 << ep->index) |
+ USBA_BF(DMA_INT, 1 << ep->index));
ctrl = USBA_AUTO_VALID | USBA_INTDIS_DMA;
usba_ep_writel(ep, CTL_ENB, ctrl);
} else {
- usba_writel(udc, INT_ENB,
- (usba_readl(udc, INT_ENB)
- | USBA_BF(EPT_INT, 1 << ep->index)));
+ usba_int_enb_set(udc, usba_int_enb_get(udc) |
+ USBA_BF(EPT_INT, 1 << ep->index));
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -618,7 +626,7 @@ usba_ep_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
DBG(DBG_HW, "EPT_CFG%d after init: %#08lx\n", ep->index,
(unsigned long)usba_ep_readl(ep, CFG));
DBG(DBG_HW, "INT_ENB after init: %#08lx\n",
- (unsigned long)usba_readl(udc, INT_ENB));
+ (unsigned long)usba_int_enb_get(udc));
return 0;
}
@@ -654,9 +662,8 @@ static int usba_ep_disable(struct usb_ep *_ep)
usba_dma_readl(ep, STATUS);
}
usba_ep_writel(ep, CTL_DIS, USBA_EPT_ENABLE);
- usba_writel(udc, INT_ENB,
- usba_readl(udc, INT_ENB)
- & ~USBA_BF(EPT_INT, 1 << ep->index));
+ usba_int_enb_set(udc, usba_int_enb_get(udc) &
+ ~USBA_BF(EPT_INT, 1 << ep->index));
request_complete_list(ep, &req_list, -ESHUTDOWN);
@@ -985,6 +992,7 @@ usba_udc_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
struct usba_udc *udc = to_usba_udc(gadget);
unsigned long flags;
+ gadget->is_selfpowered = (is_selfpowered != 0);
spin_lock_irqsave(&udc->lock, flags);
if (is_selfpowered)
udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
@@ -1619,18 +1627,21 @@ static void usba_dma_irq(struct usba_udc *udc, struct usba_ep *ep)
static irqreturn_t usba_udc_irq(int irq, void *devid)
{
struct usba_udc *udc = devid;
- u32 status;
+ u32 status, int_enb;
u32 dma_status;
u32 ep_status;
spin_lock(&udc->lock);
- status = usba_readl(udc, INT_STA);
+ int_enb = usba_int_enb_get(udc);
+ status = usba_readl(udc, INT_STA) & int_enb;
DBG(DBG_INT, "irq, status=%#08x\n", status);
if (status & USBA_DET_SUSPEND) {
- toggle_bias(0);
+ toggle_bias(udc, 0);
usba_writel(udc, INT_CLR, USBA_DET_SUSPEND);
+ usba_int_enb_set(udc, int_enb | USBA_WAKE_UP);
+ udc->bias_pulse_needed = true;
DBG(DBG_BUS, "Suspend detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->suspend) {
@@ -1641,13 +1652,15 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
}
if (status & USBA_WAKE_UP) {
- toggle_bias(1);
+ toggle_bias(udc, 1);
usba_writel(udc, INT_CLR, USBA_WAKE_UP);
+ usba_int_enb_set(udc, int_enb & ~USBA_WAKE_UP);
DBG(DBG_BUS, "Wake Up CPU detected\n");
}
if (status & USBA_END_OF_RESUME) {
usba_writel(udc, INT_CLR, USBA_END_OF_RESUME);
+ generate_bias_pulse(udc);
DBG(DBG_BUS, "Resume detected\n");
if (udc->gadget.speed != USB_SPEED_UNKNOWN
&& udc->driver && udc->driver->resume) {
@@ -1683,6 +1696,7 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
struct usba_ep *ep0;
usba_writel(udc, INT_CLR, USBA_END_OF_RESET);
+ generate_bias_pulse(udc);
reset_all_endpoints(udc);
if (udc->gadget.speed != USB_SPEED_UNKNOWN && udc->driver) {
@@ -1708,11 +1722,8 @@ static irqreturn_t usba_udc_irq(int irq, void *devid)
| USBA_BF(BK_NUMBER, USBA_BK_NUMBER_ONE)));
usba_ep_writel(ep0, CTL_ENB,
USBA_EPT_ENABLE | USBA_RX_SETUP);
- usba_writel(udc, INT_ENB,
- (usba_readl(udc, INT_ENB)
- | USBA_BF(EPT_INT, 1)
- | USBA_DET_SUSPEND
- | USBA_END_OF_RESUME));
+ usba_int_enb_set(udc, int_enb | USBA_BF(EPT_INT, 1) |
+ USBA_DET_SUSPEND | USBA_END_OF_RESUME);
/*
* Unclear why we hit this irregularly, e.g. in usbtest,
@@ -1745,13 +1756,13 @@ static irqreturn_t usba_vbus_irq(int irq, void *devid)
vbus = vbus_is_present(udc);
if (vbus != udc->vbus_prev) {
if (vbus) {
- toggle_bias(1);
+ toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
- usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ usba_int_enb_set(udc, USBA_END_OF_RESET);
} else {
udc->gadget.speed = USB_SPEED_UNKNOWN;
reset_all_endpoints(udc);
- toggle_bias(0);
+ toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
if (udc->driver->disconnect) {
spin_unlock(&udc->lock);
@@ -1797,9 +1808,9 @@ static int atmel_usba_start(struct usb_gadget *gadget,
/* If Vbus is present, enable the controller and wait for reset */
spin_lock_irqsave(&udc->lock, flags);
if (vbus_is_present(udc) && udc->vbus_prev == 0) {
- toggle_bias(1);
+ toggle_bias(udc, 1);
usba_writel(udc, CTRL, USBA_ENABLE_MASK);
- usba_writel(udc, INT_ENB, USBA_END_OF_RESET);
+ usba_int_enb_set(udc, USBA_END_OF_RESET);
}
spin_unlock_irqrestore(&udc->lock, flags);
@@ -1820,7 +1831,7 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
spin_unlock_irqrestore(&udc->lock, flags);
/* This will also disable the DP pullup */
- toggle_bias(0);
+ toggle_bias(udc, 0);
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(udc->hclk);
@@ -1832,6 +1843,41 @@ static int atmel_usba_stop(struct usb_gadget *gadget)
}
#ifdef CONFIG_OF
+static void at91sam9rl_toggle_bias(struct usba_udc *udc, int is_on)
+{
+ unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
+
+ if (is_on)
+ at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+ else
+ at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+}
+
+static void at91sam9g45_pulse_bias(struct usba_udc *udc)
+{
+ unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
+
+ at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(AT91_PMC_BIASEN));
+ at91_pmc_write(AT91_CKGR_UCKR, uckr | AT91_PMC_BIASEN);
+}
+
+static const struct usba_udc_errata at91sam9rl_errata = {
+ .toggle_bias = at91sam9rl_toggle_bias,
+};
+
+static const struct usba_udc_errata at91sam9g45_errata = {
+ .pulse_bias = at91sam9g45_pulse_bias,
+};
+
+static const struct of_device_id atmel_udc_dt_ids[] = {
+ { .compatible = "atmel,at91sam9rl-udc", .data = &at91sam9rl_errata },
+ { .compatible = "atmel,at91sam9g45-udc", .data = &at91sam9g45_errata },
+ { .compatible = "atmel,sama5d3-udc" },
+ { /* sentinel */ }
+};
+
+MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
+
static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
struct usba_udc *udc)
{
@@ -1839,10 +1885,17 @@ static struct usba_ep * atmel_udc_of_init(struct platform_device *pdev,
const char *name;
enum of_gpio_flags flags;
struct device_node *np = pdev->dev.of_node;
+ const struct of_device_id *match;
struct device_node *pp;
int i, ret;
struct usba_ep *eps, *ep;
+ match = of_match_node(atmel_udc_dt_ids, np);
+ if (!match)
+ return ERR_PTR(-EINVAL);
+
+ udc->errata = match->data;
+
udc->num_ep = 0;
udc->vbus_pin = of_get_named_gpio_flags(np, "atmel,vbus-gpio", 0,
@@ -2033,7 +2086,7 @@ static int usba_udc_probe(struct platform_device *pdev)
dev_err(&pdev->dev, "Unable to enable pclk, aborting.\n");
return ret;
}
- toggle_bias(0);
+
usba_writel(udc, CTRL, USBA_DISABLE_MASK);
clk_disable_unprepare(pclk);
@@ -2042,6 +2095,8 @@ static int usba_udc_probe(struct platform_device *pdev)
else
udc->usba_ep = usba_udc_pdata(pdev, udc);
+ toggle_bias(udc, 0);
+
if (IS_ERR(udc->usba_ep))
return PTR_ERR(udc->usba_ep);
@@ -2101,15 +2156,6 @@ static int __exit usba_udc_remove(struct platform_device *pdev)
return 0;
}
-#if defined(CONFIG_OF)
-static const struct of_device_id atmel_udc_dt_ids[] = {
- { .compatible = "atmel,at91sam9rl-udc" },
- { /* sentinel */ }
-};
-
-MODULE_DEVICE_TABLE(of, atmel_udc_dt_ids);
-#endif
-
static struct platform_driver udc_driver = {
.remove = __exit_p(usba_udc_remove),
.driver = {
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.h b/drivers/usb/gadget/udc/atmel_usba_udc.h
index a70706e8cb02..497cd18836f3 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.h
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.h
@@ -304,6 +304,11 @@ struct usba_request {
unsigned int mapped:1;
};
+struct usba_udc_errata {
+ void (*toggle_bias)(struct usba_udc *udc, int is_on);
+ void (*pulse_bias)(struct usba_udc *udc);
+};
+
struct usba_udc {
/* Protect hw registers from concurrent modifications */
spinlock_t lock;
@@ -314,6 +319,7 @@ struct usba_udc {
struct usb_gadget gadget;
struct usb_gadget_driver *driver;
struct platform_device *pdev;
+ const struct usba_udc_errata *errata;
int irq;
int vbus_pin;
int vbus_pin_inverted;
@@ -321,12 +327,15 @@ struct usba_udc {
struct clk *pclk;
struct clk *hclk;
struct usba_ep *usba_ep;
+ bool bias_pulse_needed;
u16 devstatus;
u16 test_mode;
int vbus_prev;
+ u32 int_enb_cache;
+
#ifdef CONFIG_USB_GADGET_DEBUG_FS
struct dentry *debugfs_root;
struct dentry *debugfs_regs;
diff --git a/drivers/usb/gadget/udc/bdc/bdc_core.c b/drivers/usb/gadget/udc/bdc/bdc_core.c
index c6dfef8c7bbc..5c8f4effb62a 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_core.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_core.c
@@ -521,7 +521,6 @@ static int bdc_remove(struct platform_device *pdev)
static struct platform_driver bdc_driver = {
.driver = {
.name = BRCM_BDC_NAME,
- .owner = THIS_MODULE
},
.probe = bdc_probe,
.remove = bdc_remove,
diff --git a/drivers/usb/gadget/udc/bdc/bdc_ep.c b/drivers/usb/gadget/udc/bdc/bdc_ep.c
index d4fe8d769bd6..b04980cf6dc4 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_ep.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_ep.c
@@ -718,7 +718,7 @@ static int ep_queue(struct bdc_ep *ep, struct bdc_req *req)
struct bdc *bdc;
int ret = 0;
- if (!req || !ep || !ep->usb_ep.desc)
+ if (!req || !ep->usb_ep.desc)
return -EINVAL;
bdc = ep->bdc;
@@ -882,8 +882,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
ret = bdc_ep_set_stall(bdc, ep->ep_num);
if (ret)
- dev_err(bdc->dev, "failed to %s STALL on %s\n",
- value ? "set" : "clear", ep->name);
+ dev_err(bdc->dev, "failed to set STALL on %s\n",
+ ep->name);
else
ep->flags |= BDC_EP_STALL;
} else {
@@ -891,8 +891,8 @@ static int ep_set_halt(struct bdc_ep *ep, u32 value)
dev_dbg(bdc->dev, "Before Clear\n");
ret = bdc_ep_clear_stall(bdc, ep->ep_num);
if (ret)
- dev_err(bdc->dev, "failed to %s STALL on %s\n",
- value ? "set" : "clear", ep->name);
+ dev_err(bdc->dev, "failed to clear STALL on %s\n",
+ ep->name);
else
ep->flags &= ~BDC_EP_STALL;
dev_dbg(bdc->dev, "After Clear\n");
diff --git a/drivers/usb/gadget/udc/bdc/bdc_udc.c b/drivers/usb/gadget/udc/bdc/bdc_udc.c
index 3700ce70b0be..7f77db5d1278 100644
--- a/drivers/usb/gadget/udc/bdc/bdc_udc.c
+++ b/drivers/usb/gadget/udc/bdc/bdc_udc.c
@@ -454,6 +454,7 @@ static int bdc_udc_set_selfpowered(struct usb_gadget *gadget,
unsigned long flags;
dev_dbg(bdc->dev, "%s()\n", __func__);
+ gadget->is_selfpowered = (is_self != 0);
spin_lock_irqsave(&bdc->lock, flags);
if (!is_self)
bdc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
diff --git a/drivers/usb/gadget/udc/dummy_hcd.c b/drivers/usb/gadget/udc/dummy_hcd.c
index 9c598801404c..8dda48445f6f 100644
--- a/drivers/usb/gadget/udc/dummy_hcd.c
+++ b/drivers/usb/gadget/udc/dummy_hcd.c
@@ -802,6 +802,7 @@ static int dummy_set_selfpowered(struct usb_gadget *_gadget, int value)
{
struct dummy *dum;
+ _gadget->is_selfpowered = (value != 0);
dum = gadget_to_dummy_hcd(_gadget)->dum;
if (value)
dum->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
@@ -1924,7 +1925,9 @@ ss_hub_descriptor(struct usb_hub_descriptor *desc)
memset(desc, 0, sizeof *desc);
desc->bDescriptorType = 0x2a;
desc->bDescLength = 12;
- desc->wHubCharacteristics = cpu_to_le16(0x0001);
+ desc->wHubCharacteristics = cpu_to_le16(
+ HUB_CHAR_INDV_PORT_LPSM |
+ HUB_CHAR_COMMON_OCPM);
desc->bNbrPorts = 1;
desc->u.ss.bHubHdrDecLat = 0x04; /* Worst case: 0.4 micro sec*/
desc->u.ss.DeviceRemovable = 0xffff;
@@ -1935,7 +1938,9 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
memset(desc, 0, sizeof *desc);
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
- desc->wHubCharacteristics = cpu_to_le16(0x0001);
+ desc->wHubCharacteristics = cpu_to_le16(
+ HUB_CHAR_INDV_PORT_LPSM |
+ HUB_CHAR_COMMON_OCPM);
desc->bNbrPorts = 1;
desc->u.hs.DeviceRemovable[0] = 0xff;
desc->u.hs.DeviceRemovable[1] = 0xff;
diff --git a/drivers/usb/gadget/udc/fsl_qe_udc.c b/drivers/usb/gadget/udc/fsl_qe_udc.c
index 795c99c77697..e0822f1b6639 100644
--- a/drivers/usb/gadget/udc/fsl_qe_udc.c
+++ b/drivers/usb/gadget/udc/fsl_qe_udc.c
@@ -2630,7 +2630,7 @@ static int qe_udc_remove(struct platform_device *ofdev)
struct qe_udc *udc = platform_get_drvdata(ofdev);
struct qe_ep *ep;
unsigned int size;
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
usb_del_gadget_udc(&udc->gadget);
diff --git a/drivers/usb/gadget/udc/fsl_udc_core.c b/drivers/usb/gadget/udc/fsl_udc_core.c
index 2df807403f22..55fcb930f92e 100644
--- a/drivers/usb/gadget/udc/fsl_udc_core.c
+++ b/drivers/usb/gadget/udc/fsl_udc_core.c
@@ -1337,7 +1337,7 @@ static void ch9getstatus(struct fsl_udc *udc, u8 request_type, u16 value,
if ((request_type & USB_RECIP_MASK) == USB_RECIP_DEVICE) {
/* Get device status */
- tmp = 1 << USB_DEVICE_SELF_POWERED;
+ tmp = udc->gadget.is_selfpowered;
tmp |= udc->remote_wakeup << USB_DEVICE_REMOTE_WAKEUP;
} else if ((request_type & USB_RECIP_MASK) == USB_RECIP_INTERFACE) {
/* Get interface status */
@@ -1948,6 +1948,7 @@ static int fsl_udc_start(struct usb_gadget *g,
/* hook up the driver */
udc_controller->driver = driver;
spin_unlock_irqrestore(&udc_controller->lock, flags);
+ g->is_selfpowered = 1;
if (!IS_ERR_OR_NULL(udc_controller->transceiver)) {
/* Suspend the controller until OTG enable it */
@@ -2529,7 +2530,7 @@ static int __exit fsl_udc_remove(struct platform_device *pdev)
struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
struct fsl_usb2_platform_data *pdata = dev_get_platdata(&pdev->dev);
- DECLARE_COMPLETION(done);
+ DECLARE_COMPLETION_ONSTACK(done);
if (!udc_controller)
return -ENODEV;
diff --git a/drivers/usb/gadget/udc/lpc32xx_udc.c b/drivers/usb/gadget/udc/lpc32xx_udc.c
index 34d9b7b831b3..27fd41333f71 100644
--- a/drivers/usb/gadget/udc/lpc32xx_udc.c
+++ b/drivers/usb/gadget/udc/lpc32xx_udc.c
@@ -191,7 +191,6 @@ struct lpc32xx_udc {
bool enabled;
bool clocked;
bool suspended;
- bool selfpowered;
int ep0state;
atomic_t enabled_ep_cnt;
wait_queue_head_t ep_disable_wait_queue;
@@ -547,7 +546,7 @@ static int proc_udc_show(struct seq_file *s, void *unused)
udc->vbus ? "present" : "off",
udc->enabled ? (udc->vbus ? "active" : "enabled") :
"disabled",
- udc->selfpowered ? "self" : "VBUS",
+ udc->gadget.is_selfpowered ? "self" : "VBUS",
udc->suspended ? ", suspended" : "",
udc->driver ? udc->driver->driver.name : "(none)");
@@ -2212,7 +2211,7 @@ static int udc_get_status(struct lpc32xx_udc *udc, u16 reqtype, u16 wIndex)
break; /* Not supported */
case USB_RECIP_DEVICE:
- ep0buff = (udc->selfpowered << USB_DEVICE_SELF_POWERED);
+ ep0buff = udc->gadget.is_selfpowered;
if (udc->dev_status & (1 << USB_DEVICE_REMOTE_WAKEUP))
ep0buff |= (1 << USB_DEVICE_REMOTE_WAKEUP);
break;
@@ -2498,10 +2497,7 @@ static int lpc32xx_wakeup(struct usb_gadget *gadget)
static int lpc32xx_set_selfpowered(struct usb_gadget *gadget, int is_on)
{
- struct lpc32xx_udc *udc = to_udc(gadget);
-
- /* Always self-powered */
- udc->selfpowered = (is_on != 0);
+ gadget->is_selfpowered = (is_on != 0);
return 0;
}
@@ -2946,7 +2942,7 @@ static int lpc32xx_start(struct usb_gadget *gadget,
udc->driver = driver;
udc->gadget.dev.of_node = udc->dev->of_node;
udc->enabled = 1;
- udc->selfpowered = 1;
+ udc->gadget.is_selfpowered = 1;
udc->vbus = 0;
/* Force VBUS process once to check for cable insertion */
diff --git a/drivers/usb/gadget/udc/mv_udc_core.c b/drivers/usb/gadget/udc/mv_udc_core.c
index 253f3df8326a..d32160d6463f 100644
--- a/drivers/usb/gadget/udc/mv_udc_core.c
+++ b/drivers/usb/gadget/udc/mv_udc_core.c
@@ -1378,9 +1378,6 @@ static int mv_udc_start(struct usb_gadget *gadget,
}
}
- /* pullup is always on */
- mv_udc_pullup(&udc->gadget, 1);
-
/* When boot with cable attached, there will be no vbus irq occurred */
if (udc->qwork)
queue_work(udc->qwork, &udc->vbus_work);
diff --git a/drivers/usb/gadget/udc/net2272.c b/drivers/usb/gadget/udc/net2272.c
index d20de1fab08e..195baf3e1fcd 100644
--- a/drivers/usb/gadget/udc/net2272.c
+++ b/drivers/usb/gadget/udc/net2272.c
@@ -1132,13 +1132,10 @@ net2272_wakeup(struct usb_gadget *_gadget)
static int
net2272_set_selfpowered(struct usb_gadget *_gadget, int value)
{
- struct net2272 *dev;
-
if (!_gadget)
return -ENODEV;
- dev = container_of(_gadget, struct net2272, gadget);
- dev->is_selfpowered = value;
+ _gadget->is_selfpowered = (value != 0);
return 0;
}
@@ -1844,7 +1841,7 @@ net2272_handle_stat0_irqs(struct net2272 *dev, u8 stat)
case USB_RECIP_DEVICE:
if (u.r.wLength > 2)
goto do_stall;
- if (dev->is_selfpowered)
+ if (dev->gadget.is_selfpowered)
status = (1 << USB_DEVICE_SELF_POWERED);
/* don't bother with a request object! */
diff --git a/drivers/usb/gadget/udc/net2272.h b/drivers/usb/gadget/udc/net2272.h
index e59505789359..127ab03fcde3 100644
--- a/drivers/usb/gadget/udc/net2272.h
+++ b/drivers/usb/gadget/udc/net2272.h
@@ -458,7 +458,6 @@ struct net2272 {
struct usb_gadget_driver *driver;
unsigned protocol_stall:1,
softconnect:1,
- is_selfpowered:1,
wakeup:1,
dma_eot_polarity:1,
dma_dack_polarity:1,
diff --git a/drivers/usb/gadget/udc/net2280.c b/drivers/usb/gadget/udc/net2280.c
index d6411e0a8e03..d2c0bf65e345 100644
--- a/drivers/usb/gadget/udc/net2280.c
+++ b/drivers/usb/gadget/udc/net2280.c
@@ -12,11 +12,7 @@
* the Mass Storage, Serial, and Ethernet/RNDIS gadget drivers
* as well as Gadget Zero and Gadgetfs.
*
- * DMA is enabled by default. Drivers using transfer queues might use
- * DMA chaining to remove IRQ latencies between transfers. (Except when
- * short OUT transfers happen.) Drivers can use the req->no_interrupt
- * hint to completely eliminate some IRQs, if a later IRQ is guaranteed
- * and DMA chaining is enabled.
+ * DMA is enabled by default.
*
* MSI is enabled by default. The legacy IRQ is used if MSI couldn't
* be enabled.
@@ -84,23 +80,6 @@ static const char *const ep_name[] = {
"ep-e", "ep-f", "ep-g", "ep-h",
};
-/* use_dma -- general goodness, fewer interrupts, less cpu load (vs PIO)
- * use_dma_chaining -- dma descriptor queueing gives even more irq reduction
- *
- * The net2280 DMA engines are not tightly integrated with their FIFOs;
- * not all cases are (yet) handled well in this driver or the silicon.
- * Some gadget drivers work better with the dma support here than others.
- * These two parameters let you use PIO or more aggressive DMA.
- */
-static bool use_dma = true;
-static bool use_dma_chaining;
-static bool use_msi = true;
-
-/* "modprobe net2280 use_dma=n" etc */
-module_param(use_dma, bool, 0444);
-module_param(use_dma_chaining, bool, 0444);
-module_param(use_msi, bool, 0444);
-
/* mode 0 == ep-{a,b,c,d} 1K fifo each
* mode 1 == ep-{a,b} 2K fifo each, ep-{c,d} unavailable
* mode 2 == ep-a 2K fifo, ep-{b,c} 1K each, ep-d unavailable
@@ -120,11 +99,6 @@ static bool enable_suspend;
/* "modprobe net2280 enable_suspend=1" etc */
module_param(enable_suspend, bool, 0444);
-/* force full-speed operation */
-static bool full_speed;
-module_param(full_speed, bool, 0444);
-MODULE_PARM_DESC(full_speed, "force full-speed mode -- for testing only!");
-
#define DIR_STRING(bAddress) (((bAddress) & USB_DIR_IN) ? "in" : "out")
static char *type_string(u8 bmAttributes)
@@ -202,15 +176,6 @@ net2280_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
/* set speed-dependent max packet; may kick in high bandwidth */
set_max_speed(ep, max);
- /* FIFO lines can't go to different packets. PIO is ok, so
- * use it instead of troublesome (non-bulk) multi-packet DMA.
- */
- if (ep->dma && (max % 4) != 0 && use_dma_chaining) {
- ep_dbg(ep->dev, "%s, no dma for maxpacket %d\n",
- ep->ep.name, ep->ep.maxpacket);
- ep->dma = NULL;
- }
-
/* set type, direction, address; reset fifo counters */
writel(BIT(FIFO_FLUSH), &ep->regs->ep_stat);
tmp = (desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
@@ -478,7 +443,7 @@ static int net2280_disable(struct usb_ep *_ep)
/* synch memory views with the device */
(void)readl(&ep->cfg->ep_cfg);
- if (use_dma && !ep->dma && ep->num >= 1 && ep->num <= 4)
+ if (!ep->dma && ep->num >= 1 && ep->num <= 4)
ep->dma = &ep->dev->dma[ep->num - 1];
spin_unlock_irqrestore(&ep->dev->lock, flags);
@@ -610,9 +575,15 @@ static void out_flush(struct net2280_ep *ep)
u32 __iomem *statp;
u32 tmp;
- ASSERT_OUT_NAKING(ep);
-
statp = &ep->regs->ep_stat;
+
+ tmp = readl(statp);
+ if (tmp & BIT(NAK_OUT_PACKETS)) {
+ ep_dbg(ep->dev, "%s %s %08x !NAK\n",
+ ep->ep.name, __func__, tmp);
+ writel(BIT(SET_NAK_OUT_PACKETS), &ep->regs->ep_rsp);
+ }
+
writel(BIT(DATA_OUT_PING_TOKEN_INTERRUPT) |
BIT(DATA_PACKET_RECEIVED_INTERRUPT),
statp);
@@ -747,8 +718,7 @@ static void fill_dma_desc(struct net2280_ep *ep,
req->valid = valid;
if (valid)
dmacount |= BIT(VALID_BIT);
- if (likely(!req->req.no_interrupt || !use_dma_chaining))
- dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
+ dmacount |= BIT(DMA_DONE_INTERRUPT_ENABLE);
/* td->dmadesc = previously set by caller */
td->dmaaddr = cpu_to_le32 (req->req.dma);
@@ -862,27 +832,11 @@ static void start_dma(struct net2280_ep *ep, struct net2280_request *req)
req->td->dmadesc = cpu_to_le32 (ep->td_dma);
fill_dma_desc(ep, req, 1);
- if (!use_dma_chaining)
- req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
+ req->td->dmacount |= cpu_to_le32(BIT(END_OF_CHAIN));
start_queue(ep, tmp, req->td_dma);
}
-static inline void resume_dma(struct net2280_ep *ep)
-{
- writel(readl(&ep->dma->dmactl) | BIT(DMA_ENABLE), &ep->dma->dmactl);
-
- ep->dma_started = true;
-}
-
-static inline void ep_stop_dma(struct net2280_ep *ep)
-{
- writel(readl(&ep->dma->dmactl) & ~BIT(DMA_ENABLE), &ep->dma->dmactl);
- spin_stop_dma(ep->dma);
-
- ep->dma_started = false;
-}
-
static inline void
queue_dma(struct net2280_ep *ep, struct net2280_request *req, int valid)
{
@@ -973,10 +927,8 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
return ret;
}
-#if 0
ep_vdbg(dev, "%s queue req %p, len %d buf %p\n",
_ep->name, _req, _req->length, _req->buf);
-#endif
spin_lock_irqsave(&dev->lock, flags);
@@ -984,24 +936,12 @@ net2280_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
_req->actual = 0;
/* kickstart this i/o queue? */
- if (list_empty(&ep->queue) && !ep->stopped) {
- /* DMA request while EP halted */
- if (ep->dma &&
- (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)) &&
- (dev->quirks & PLX_SUPERSPEED)) {
- int valid = 1;
- if (ep->is_in) {
- int expect;
- expect = likely(req->req.zero ||
- ((req->req.length %
- ep->ep.maxpacket) != 0));
- if (expect != ep->in_fifo_validate)
- valid = 0;
- }
- queue_dma(ep, req, valid);
- }
+ if (list_empty(&ep->queue) && !ep->stopped &&
+ !((dev->quirks & PLX_SUPERSPEED) && ep->dma &&
+ (readl(&ep->regs->ep_rsp) & BIT(CLEAR_ENDPOINT_HALT)))) {
+
/* use DMA if the endpoint supports it, else pio */
- else if (ep->dma)
+ if (ep->dma)
start_dma(ep, req);
else {
/* maybe there's no control data, just status ack */
@@ -1084,8 +1024,6 @@ dma_done(struct net2280_ep *ep, struct net2280_request *req, u32 dmacount,
done(ep, req, status);
}
-static void restart_dma(struct net2280_ep *ep);
-
static void scan_dma_completions(struct net2280_ep *ep)
{
/* only look at descriptors that were "naturally" retired,
@@ -1117,9 +1055,8 @@ static void scan_dma_completions(struct net2280_ep *ep)
dma_done(ep, req, tmp, 0);
break;
} else if (!ep->is_in &&
- (req->req.length % ep->ep.maxpacket) != 0) {
- if (ep->dev->quirks & PLX_SUPERSPEED)
- return dma_done(ep, req, tmp, 0);
+ (req->req.length % ep->ep.maxpacket) &&
+ !(ep->dev->quirks & PLX_SUPERSPEED)) {
tmp = readl(&ep->regs->ep_stat);
/* AVOID TROUBLE HERE by not issuing short reads from
@@ -1150,67 +1087,15 @@ static void scan_dma_completions(struct net2280_ep *ep)
static void restart_dma(struct net2280_ep *ep)
{
struct net2280_request *req;
- u32 dmactl = dmactl_default;
if (ep->stopped)
return;
req = list_entry(ep->queue.next, struct net2280_request, queue);
- if (!use_dma_chaining) {
- start_dma(ep, req);
- return;
- }
-
- /* the 2280 will be processing the queue unless queue hiccups after
- * the previous transfer:
- * IN: wanted automagic zlp, head doesn't (or vice versa)
- * DMA_FIFO_VALIDATE doesn't init from dma descriptors.
- * OUT: was "usb-short", we must restart.
- */
- if (ep->is_in && !req->valid) {
- struct net2280_request *entry, *prev = NULL;
- int reqmode, done = 0;
-
- ep_dbg(ep->dev, "%s dma hiccup td %p\n", ep->ep.name, req->td);
- ep->in_fifo_validate = likely(req->req.zero ||
- (req->req.length % ep->ep.maxpacket) != 0);
- if (ep->in_fifo_validate)
- dmactl |= BIT(DMA_FIFO_VALIDATE);
- list_for_each_entry(entry, &ep->queue, queue) {
- __le32 dmacount;
-
- if (entry == req)
- continue;
- dmacount = entry->td->dmacount;
- if (!done) {
- reqmode = likely(entry->req.zero ||
- (entry->req.length % ep->ep.maxpacket));
- if (reqmode == ep->in_fifo_validate) {
- entry->valid = 1;
- dmacount |= valid_bit;
- entry->td->dmacount = dmacount;
- prev = entry;
- continue;
- } else {
- /* force a hiccup */
- prev->td->dmacount |= dma_done_ie;
- done = 1;
- }
- }
-
- /* walk the rest of the queue so unlinks behave */
- entry->valid = 0;
- dmacount &= ~valid_bit;
- entry->td->dmacount = dmacount;
- prev = entry;
- }
- }
-
- writel(0, &ep->dma->dmactl);
- start_queue(ep, dmactl, req->td_dma);
+ start_dma(ep, req);
}
-static void abort_dma_228x(struct net2280_ep *ep)
+static void abort_dma(struct net2280_ep *ep)
{
/* abort the current transfer */
if (likely(!list_empty(&ep->queue))) {
@@ -1222,19 +1107,6 @@ static void abort_dma_228x(struct net2280_ep *ep)
scan_dma_completions(ep);
}
-static void abort_dma_338x(struct net2280_ep *ep)
-{
- writel(BIT(DMA_ABORT), &ep->dma->dmastat);
- spin_stop_dma(ep->dma);
-}
-
-static void abort_dma(struct net2280_ep *ep)
-{
- if (ep->dev->quirks & PLX_LEGACY)
- return abort_dma_228x(ep);
- return abort_dma_338x(ep);
-}
-
/* dequeue ALL requests */
static void nuke(struct net2280_ep *ep)
{
@@ -1306,25 +1178,6 @@ static int net2280_dequeue(struct usb_ep *_ep, struct usb_request *_req)
done(ep, req, -ECONNRESET);
}
req = NULL;
-
- /* patch up hardware chaining data */
- } else if (ep->dma && use_dma_chaining) {
- if (req->queue.prev == ep->queue.next) {
- writel(le32_to_cpu(req->td->dmadesc),
- &ep->dma->dmadesc);
- if (req->td->dmacount & dma_done_ie)
- writel(readl(&ep->dma->dmacount) |
- le32_to_cpu(dma_done_ie),
- &ep->dma->dmacount);
- } else {
- struct net2280_request *prev;
-
- prev = list_entry(req->queue.prev,
- struct net2280_request, queue);
- prev->td->dmadesc = req->td->dmadesc;
- if (req->td->dmacount & dma_done_ie)
- prev->td->dmacount |= dma_done_ie;
- }
}
if (req)
@@ -1512,10 +1365,10 @@ static int net2280_set_selfpowered(struct usb_gadget *_gadget, int value)
tmp = readl(&dev->usb->usbctl);
if (value) {
tmp |= BIT(SELF_POWERED_STATUS);
- dev->selfpowered = 1;
+ _gadget->is_selfpowered = 1;
} else {
tmp &= ~BIT(SELF_POWERED_STATUS);
- dev->selfpowered = 0;
+ _gadget->is_selfpowered = 0;
}
writel(tmp, &dev->usb->usbctl);
spin_unlock_irqrestore(&dev->lock, flags);
@@ -1604,14 +1457,11 @@ static ssize_t registers_show(struct device *_dev,
/* Main Control Registers */
t = scnprintf(next, size, "%s version " DRIVER_VERSION
- ", chiprev %04x, dma %s\n\n"
+ ", chiprev %04x\n\n"
"devinit %03x fifoctl %08x gadget '%s'\n"
"pci irqenb0 %02x irqenb1 %08x "
"irqstat0 %04x irqstat1 %08x\n",
driver_name, dev->chiprev,
- use_dma
- ? (use_dma_chaining ? "chaining" : "enabled")
- : "disabled",
readl(&dev->regs->devinit),
readl(&dev->regs->fifoctl),
s,
@@ -1913,76 +1763,73 @@ static void defect7374_disable_data_eps(struct net2280 *dev)
static void defect7374_enable_data_eps_zero(struct net2280 *dev)
{
u32 tmp = 0, tmp_reg;
- u32 fsmvalue, scratch;
+ u32 scratch;
int i;
unsigned char ep_sel;
scratch = get_idx_reg(dev->regs, SCRATCH);
- fsmvalue = scratch & (0xf << DEFECT7374_FSM_FIELD);
+
+ WARN_ON((scratch & (0xf << DEFECT7374_FSM_FIELD))
+ == DEFECT7374_FSM_SS_CONTROL_READ);
+
scratch &= ~(0xf << DEFECT7374_FSM_FIELD);
- /*See if firmware needs to set up for workaround*/
- if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
- ep_warn(dev, "Operate Defect 7374 workaround soft this time");
- ep_warn(dev, "It will operate on cold-reboot and SS connect");
-
- /*GPEPs:*/
- tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
- (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
- ((dev->enhanced_mode) ?
- BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
- BIT(IN_ENDPOINT_ENABLE));
-
- for (i = 1; i < 5; i++)
- writel(tmp, &dev->ep[i].cfg->ep_cfg);
-
- /* CSRIN, PCIIN, STATIN, RCIN*/
- tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
- writel(tmp, &dev->dep[1].dep_cfg);
- writel(tmp, &dev->dep[3].dep_cfg);
- writel(tmp, &dev->dep[4].dep_cfg);
- writel(tmp, &dev->dep[5].dep_cfg);
-
- /*Implemented for development and debug.
- * Can be refined/tuned later.*/
- for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
- /* Select an endpoint for subsequent operations: */
- tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
- writel(((tmp_reg & ~0x1f) | ep_sel),
- &dev->plregs->pl_ep_ctrl);
-
- if (ep_sel == 1) {
- tmp =
- (readl(&dev->plregs->pl_ep_ctrl) |
- BIT(CLEAR_ACK_ERROR_CODE) | 0);
- writel(tmp, &dev->plregs->pl_ep_ctrl);
- continue;
- }
+ ep_warn(dev, "Operate Defect 7374 workaround soft this time");
+ ep_warn(dev, "It will operate on cold-reboot and SS connect");
- if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
- ep_sel == 18 || ep_sel == 20)
- continue;
+ /*GPEPs:*/
+ tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_DIRECTION) |
+ (2 << OUT_ENDPOINT_TYPE) | (2 << IN_ENDPOINT_TYPE) |
+ ((dev->enhanced_mode) ?
+ BIT(OUT_ENDPOINT_ENABLE) : BIT(ENDPOINT_ENABLE)) |
+ BIT(IN_ENDPOINT_ENABLE));
- tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
- BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
- writel(tmp, &dev->plregs->pl_ep_cfg_4);
+ for (i = 1; i < 5; i++)
+ writel(tmp, &dev->ep[i].cfg->ep_cfg);
- tmp = readl(&dev->plregs->pl_ep_ctrl) &
- ~BIT(EP_INITIALIZED);
- writel(tmp, &dev->plregs->pl_ep_ctrl);
+ /* CSRIN, PCIIN, STATIN, RCIN*/
+ tmp = ((0 << ENDPOINT_NUMBER) | BIT(ENDPOINT_ENABLE));
+ writel(tmp, &dev->dep[1].dep_cfg);
+ writel(tmp, &dev->dep[3].dep_cfg);
+ writel(tmp, &dev->dep[4].dep_cfg);
+ writel(tmp, &dev->dep[5].dep_cfg);
+
+ /*Implemented for development and debug.
+ * Can be refined/tuned later.*/
+ for (ep_sel = 0; ep_sel <= 21; ep_sel++) {
+ /* Select an endpoint for subsequent operations: */
+ tmp_reg = readl(&dev->plregs->pl_ep_ctrl);
+ writel(((tmp_reg & ~0x1f) | ep_sel),
+ &dev->plregs->pl_ep_ctrl);
+ if (ep_sel == 1) {
+ tmp =
+ (readl(&dev->plregs->pl_ep_ctrl) |
+ BIT(CLEAR_ACK_ERROR_CODE) | 0);
+ writel(tmp, &dev->plregs->pl_ep_ctrl);
+ continue;
}
- /* Set FSM to focus on the first Control Read:
- * - Tip: Connection speed is known upon the first
- * setup request.*/
- scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
- set_idx_reg(dev->regs, SCRATCH, scratch);
+ if (ep_sel == 0 || (ep_sel > 9 && ep_sel < 14) ||
+ ep_sel == 18 || ep_sel == 20)
+ continue;
+
+ tmp = (readl(&dev->plregs->pl_ep_cfg_4) |
+ BIT(NON_CTRL_IN_TOLERATE_BAD_DIR) | 0);
+ writel(tmp, &dev->plregs->pl_ep_cfg_4);
+
+ tmp = readl(&dev->plregs->pl_ep_ctrl) &
+ ~BIT(EP_INITIALIZED);
+ writel(tmp, &dev->plregs->pl_ep_ctrl);
- } else{
- ep_warn(dev, "Defect 7374 workaround soft will NOT operate");
- ep_warn(dev, "It will operate on cold-reboot and SS connect");
}
+
+ /* Set FSM to focus on the first Control Read:
+ * - Tip: Connection speed is known upon the first
+ * setup request.*/
+ scratch |= DEFECT7374_FSM_WAITING_FOR_CONTROL_READ;
+ set_idx_reg(dev->regs, SCRATCH, scratch);
+
}
/* keeping it simple:
@@ -2033,21 +1880,13 @@ static void usb_reset_228x(struct net2280 *dev)
static void usb_reset_338x(struct net2280 *dev)
{
u32 tmp;
- u32 fsmvalue;
dev->gadget.speed = USB_SPEED_UNKNOWN;
(void)readl(&dev->usb->usbctl);
net2280_led_init(dev);
- fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
- (0xf << DEFECT7374_FSM_FIELD);
-
- /* See if firmware needs to set up for workaround: */
- if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ) {
- ep_info(dev, "%s: Defect 7374 FsmValue 0x%08x\n", __func__,
- fsmvalue);
- } else {
+ if (dev->bug7734_patched) {
/* disable automatic responses, and irqs */
writel(0, &dev->usb->stdrsp);
writel(0, &dev->regs->pciirqenb0);
@@ -2064,7 +1903,7 @@ static void usb_reset_338x(struct net2280 *dev)
writel(~0, &dev->regs->irqstat0), writel(~0, &dev->regs->irqstat1);
- if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
+ if (dev->bug7734_patched) {
/* reset, and enable pci */
tmp = readl(&dev->regs->devinit) |
BIT(PCI_ENABLE) |
@@ -2093,10 +1932,6 @@ static void usb_reset(struct net2280 *dev)
static void usb_reinit_228x(struct net2280 *dev)
{
u32 tmp;
- int init_dma;
-
- /* use_dma changes are ignored till next device re-init */
- init_dma = use_dma;
/* basic endpoint init */
for (tmp = 0; tmp < 7; tmp++) {
@@ -2108,8 +1943,7 @@ static void usb_reinit_228x(struct net2280 *dev)
if (tmp > 0 && tmp <= 4) {
ep->fifo_size = 1024;
- if (init_dma)
- ep->dma = &dev->dma[tmp - 1];
+ ep->dma = &dev->dma[tmp - 1];
} else
ep->fifo_size = 64;
ep->regs = &dev->epregs[tmp];
@@ -2133,17 +1967,12 @@ static void usb_reinit_228x(struct net2280 *dev)
static void usb_reinit_338x(struct net2280 *dev)
{
- int init_dma;
int i;
u32 tmp, val;
- u32 fsmvalue;
static const u32 ne[9] = { 0, 1, 2, 3, 4, 1, 2, 3, 4 };
static const u32 ep_reg_addr[9] = { 0x00, 0xC0, 0x00, 0xC0, 0x00,
0x00, 0xC0, 0x00, 0xC0 };
- /* use_dma changes are ignored till next device re-init */
- init_dma = use_dma;
-
/* basic endpoint init */
for (i = 0; i < dev->n_ep; i++) {
struct net2280_ep *ep = &dev->ep[i];
@@ -2152,7 +1981,7 @@ static void usb_reinit_338x(struct net2280 *dev)
ep->dev = dev;
ep->num = i;
- if (i > 0 && i <= 4 && init_dma)
+ if (i > 0 && i <= 4)
ep->dma = &dev->dma[i - 1];
if (dev->enhanced_mode) {
@@ -2177,14 +2006,7 @@ static void usb_reinit_338x(struct net2280 *dev)
dev->ep[0].stopped = 0;
/* Link layer set up */
- fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
- (0xf << DEFECT7374_FSM_FIELD);
-
- /* See if driver needs to set up for workaround: */
- if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
- ep_info(dev, "%s: Defect 7374 FsmValue %08x\n",
- __func__, fsmvalue);
- else {
+ if (dev->bug7734_patched) {
tmp = readl(&dev->usb_ext->usbctl2) &
~(BIT(U1_ENABLE) | BIT(U2_ENABLE) | BIT(LTM_ENABLE));
writel(tmp, &dev->usb_ext->usbctl2);
@@ -2291,15 +2113,8 @@ static void ep0_start_228x(struct net2280 *dev)
static void ep0_start_338x(struct net2280 *dev)
{
- u32 fsmvalue;
-
- fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
- (0xf << DEFECT7374_FSM_FIELD);
- if (fsmvalue != DEFECT7374_FSM_SS_CONTROL_READ)
- ep_info(dev, "%s: Defect 7374 FsmValue %08x\n", __func__,
- fsmvalue);
- else
+ if (dev->bug7734_patched)
writel(BIT(CLEAR_NAK_OUT_PACKETS_MODE) |
BIT(SET_EP_HIDE_STATUS_PHASE),
&dev->epregs[0].ep_rsp);
@@ -2382,16 +2197,12 @@ static int net2280_start(struct usb_gadget *_gadget,
if (retval)
goto err_func;
- /* Enable force-full-speed testing mode, if desired */
- if (full_speed && (dev->quirks & PLX_LEGACY))
- writel(BIT(FORCE_FULL_SPEED_MODE), &dev->usb->xcvrdiag);
-
- /* ... then enable host detection and ep0; and we're ready
+ /* enable host detection and ep0; and we're ready
* for set_configuration as well as eventual disconnect.
*/
net2280_led_active(dev, 1);
- if (dev->quirks & PLX_SUPERSPEED)
+ if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
defect7374_enable_data_eps_zero(dev);
ep0_start(dev);
@@ -2444,10 +2255,6 @@ static int net2280_stop(struct usb_gadget *_gadget)
net2280_led_active(dev, 0);
- /* Disable full-speed test mode */
- if (dev->quirks & PLX_LEGACY)
- writel(0, &dev->usb->xcvrdiag);
-
device_remove_file(&dev->pdev->dev, &dev_attr_function);
device_remove_file(&dev->pdev->dev, &dev_attr_queues);
@@ -2478,10 +2285,10 @@ static void handle_ep_small(struct net2280_ep *ep)
/* ack all, and handle what we care about */
t = readl(&ep->regs->ep_stat);
ep->irqs++;
-#if 0
+
ep_vdbg(ep->dev, "%s ack ep_stat %08x, req %p\n",
- ep->ep.name, t, req ? &req->req : 0);
-#endif
+ ep->ep.name, t, req ? &req->req : NULL);
+
if (!ep->is_in || (ep->dev->quirks & PLX_2280))
writel(t & ~BIT(NAK_OUT_PACKETS), &ep->regs->ep_stat);
else
@@ -2717,6 +2524,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
* run after the next USB connection.
*/
scratch |= DEFECT7374_FSM_NON_SS_CONTROL_READ;
+ dev->bug7734_patched = 1;
goto restore_data_eps;
}
@@ -2730,6 +2538,7 @@ static void defect7374_workaround(struct net2280 *dev, struct usb_ctrlrequest r)
if ((state >= (ACK_GOOD_NORMAL << STATE)) &&
(state <= (ACK_GOOD_MORE_ACKS_TO_COME << STATE))) {
scratch |= DEFECT7374_FSM_SS_CONTROL_READ;
+ dev->bug7734_patched = 1;
break;
}
@@ -2766,80 +2575,19 @@ restore_data_eps:
return;
}
-static void ep_stall(struct net2280_ep *ep, int stall)
+static void ep_clear_seqnum(struct net2280_ep *ep)
{
struct net2280 *dev = ep->dev;
u32 val;
static const u32 ep_pl[9] = { 0, 3, 4, 7, 8, 2, 5, 6, 9 };
- if (stall) {
- writel(BIT(SET_ENDPOINT_HALT) |
- /* BIT(SET_NAK_PACKETS) | */
- BIT(CLEAR_CONTROL_STATUS_PHASE_HANDSHAKE),
- &ep->regs->ep_rsp);
- ep->is_halt = 1;
- } else {
- if (dev->gadget.speed == USB_SPEED_SUPER) {
- /*
- * Workaround for SS SeqNum not cleared via
- * Endpoint Halt (Clear) bit. select endpoint
- */
- val = readl(&dev->plregs->pl_ep_ctrl);
- val = (val & ~0x1f) | ep_pl[ep->num];
- writel(val, &dev->plregs->pl_ep_ctrl);
-
- val |= BIT(SEQUENCE_NUMBER_RESET);
- writel(val, &dev->plregs->pl_ep_ctrl);
- }
- val = readl(&ep->regs->ep_rsp);
- val |= BIT(CLEAR_ENDPOINT_HALT) |
- BIT(CLEAR_ENDPOINT_TOGGLE);
- writel(val,
- /* | BIT(CLEAR_NAK_PACKETS),*/
- &ep->regs->ep_rsp);
- ep->is_halt = 0;
- val = readl(&ep->regs->ep_rsp);
- }
-}
-
-static void ep_stdrsp(struct net2280_ep *ep, int value, int wedged)
-{
- /* set/clear, then synch memory views with the device */
- if (value) {
- ep->stopped = 1;
- if (ep->num == 0)
- ep->dev->protocol_stall = 1;
- else {
- if (ep->dma)
- ep_stop_dma(ep);
- ep_stall(ep, true);
- }
-
- if (wedged)
- ep->wedged = 1;
- } else {
- ep->stopped = 0;
- ep->wedged = 0;
-
- ep_stall(ep, false);
+ val = readl(&dev->plregs->pl_ep_ctrl) & ~0x1f;
+ val |= ep_pl[ep->num];
+ writel(val, &dev->plregs->pl_ep_ctrl);
+ val |= BIT(SEQUENCE_NUMBER_RESET);
+ writel(val, &dev->plregs->pl_ep_ctrl);
- /* Flush the queue */
- if (!list_empty(&ep->queue)) {
- struct net2280_request *req =
- list_entry(ep->queue.next, struct net2280_request,
- queue);
- if (ep->dma)
- resume_dma(ep);
- else {
- if (ep->is_in)
- write_fifo(ep, &req->req);
- else {
- if (read_fifo(ep, req))
- done(ep, req, 0);
- }
- }
- }
- }
+ return;
}
static void handle_stat0_irqs_superspeed(struct net2280 *dev,
@@ -2863,7 +2611,7 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
switch (r.bRequestType) {
case (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE):
status = dev->wakeup_enable ? 0x02 : 0x00;
- if (dev->selfpowered)
+ if (dev->gadget.is_selfpowered)
status |= BIT(0);
status |= (dev->u1_enable << 2 | dev->u2_enable << 3 |
dev->ltm_enable << 4);
@@ -2940,7 +2688,12 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
if (w_value != USB_ENDPOINT_HALT)
goto do_stall3;
ep_vdbg(dev, "%s clear halt\n", e->ep.name);
- ep_stall(e, false);
+ /*
+ * Workaround for SS SeqNum not cleared via
+ * Endpoint Halt (Clear) bit. select endpoint
+ */
+ ep_clear_seqnum(e);
+ clear_halt(e);
if (!list_empty(&e->queue) && e->td_dma)
restart_dma(e);
allow_status(ep);
@@ -2998,7 +2751,14 @@ static void handle_stat0_irqs_superspeed(struct net2280 *dev,
e = get_ep_by_addr(dev, w_index);
if (!e || (w_value != USB_ENDPOINT_HALT))
goto do_stall3;
- ep_stdrsp(e, true, false);
+ ep->stopped = 1;
+ if (ep->num == 0)
+ ep->dev->protocol_stall = 1;
+ else {
+ if (ep->dma)
+ abort_dma(ep);
+ set_halt(ep);
+ }
allow_status_338x(ep);
break;
@@ -3026,7 +2786,7 @@ do_stall3:
r.bRequestType, r.bRequest, tmp);
dev->protocol_stall = 1;
/* TD 9.9 Halt Endpoint test. TD 9.22 Set feature test */
- ep_stall(ep, true);
+ set_halt(ep);
}
next_endpoints3:
@@ -3091,9 +2851,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
}
ep->stopped = 0;
dev->protocol_stall = 0;
- if (dev->quirks & PLX_SUPERSPEED)
- ep->is_halt = 0;
- else{
+ if (!(dev->quirks & PLX_SUPERSPEED)) {
if (ep->dev->quirks & PLX_2280)
tmp = BIT(FIFO_OVERFLOW) |
BIT(FIFO_UNDERFLOW);
@@ -3120,7 +2878,7 @@ static void handle_stat0_irqs(struct net2280 *dev, u32 stat)
cpu_to_le32s(&u.raw[0]);
cpu_to_le32s(&u.raw[1]);
- if (dev->quirks & PLX_SUPERSPEED)
+ if ((dev->quirks & PLX_SUPERSPEED) && !dev->bug7734_patched)
defect7374_workaround(dev, u.r);
tmp = 0;
@@ -3423,17 +3181,12 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
continue;
}
- /* chaining should stop on abort, short OUT from fifo,
- * or (stat0 codepath) short OUT transfer.
- */
- if (!use_dma_chaining) {
- if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
- ep_dbg(ep->dev, "%s no xact done? %08x\n",
- ep->ep.name, tmp);
- continue;
- }
- stop_dma(ep->dma);
+ if (!(tmp & BIT(DMA_TRANSACTION_DONE_INTERRUPT))) {
+ ep_dbg(ep->dev, "%s no xact done? %08x\n",
+ ep->ep.name, tmp);
+ continue;
}
+ stop_dma(ep->dma);
/* OUT transfers terminate when the data from the
* host is in our memory. Process whatever's done.
@@ -3448,30 +3201,9 @@ static void handle_stat1_irqs(struct net2280 *dev, u32 stat)
scan_dma_completions(ep);
/* disable dma on inactive queues; else maybe restart */
- if (list_empty(&ep->queue)) {
- if (use_dma_chaining)
- stop_dma(ep->dma);
- } else {
+ if (!list_empty(&ep->queue)) {
tmp = readl(&dma->dmactl);
- if (!use_dma_chaining || (tmp & BIT(DMA_ENABLE)) == 0)
- restart_dma(ep);
- else if (ep->is_in && use_dma_chaining) {
- struct net2280_request *req;
- __le32 dmacount;
-
- /* the descriptor at the head of the chain
- * may still have VALID_BIT clear; that's
- * used to trigger changing DMA_FIFO_VALIDATE
- * (affects automagic zlp writes).
- */
- req = list_entry(ep->queue.next,
- struct net2280_request, queue);
- dmacount = req->td->dmacount;
- dmacount &= cpu_to_le32(BIT(VALID_BIT) |
- DMA_BYTE_COUNT_MASK);
- if (dmacount && (dmacount & valid_bit) == 0)
- restart_dma(ep);
- }
+ restart_dma(ep);
}
ep->irqs++;
}
@@ -3556,7 +3288,7 @@ static void net2280_remove(struct pci_dev *pdev)
}
if (dev->got_irq)
free_irq(pdev->irq, dev);
- if (use_msi && dev->quirks & PLX_SUPERSPEED)
+ if (dev->quirks & PLX_SUPERSPEED)
pci_disable_msi(pdev);
if (dev->regs)
iounmap(dev->regs);
@@ -3581,9 +3313,6 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
void __iomem *base = NULL;
int retval, i;
- if (!use_dma)
- use_dma_chaining = 0;
-
/* alloc, and start init */
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
@@ -3663,9 +3392,12 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
fsmvalue = get_idx_reg(dev->regs, SCRATCH) &
(0xf << DEFECT7374_FSM_FIELD);
/* See if firmware needs to set up for workaround: */
- if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ)
+ if (fsmvalue == DEFECT7374_FSM_SS_CONTROL_READ) {
+ dev->bug7734_patched = 1;
writel(0, &dev->usb->usbctl);
- } else{
+ } else
+ dev->bug7734_patched = 0;
+ } else {
dev->enhanced_mode = 0;
dev->n_ep = 7;
/* put into initial config, link up all endpoints */
@@ -3682,7 +3414,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto done;
}
- if (use_msi && (dev->quirks & PLX_SUPERSPEED))
+ if (dev->quirks & PLX_SUPERSPEED)
if (pci_enable_msi(pdev))
ep_err(dev, "Failed to enable MSI mode\n");
@@ -3741,9 +3473,7 @@ static int net2280_probe(struct pci_dev *pdev, const struct pci_device_id *id)
ep_info(dev, "%s\n", driver_desc);
ep_info(dev, "irq %d, pci mem %p, chip rev %04x\n",
pdev->irq, base, dev->chiprev);
- ep_info(dev, "version: " DRIVER_VERSION "; dma %s %s\n",
- use_dma ? (use_dma_chaining ? "chaining" : "enabled")
- : "disabled",
+ ep_info(dev, "version: " DRIVER_VERSION "; %s\n",
dev->enhanced_mode ? "enhanced mode" : "legacy mode");
retval = device_create_file(&pdev->dev, &dev_attr_registers);
if (retval)
@@ -3776,9 +3506,6 @@ static void net2280_shutdown(struct pci_dev *pdev)
/* disable the pullup so the host will think we're gone */
writel(0, &dev->usb->usbctl);
- /* Disable full-speed test mode */
- if (dev->quirks & PLX_LEGACY)
- writel(0, &dev->usb->xcvrdiag);
}
diff --git a/drivers/usb/gadget/udc/net2280.h b/drivers/usb/gadget/udc/net2280.h
index 03f15242d794..ac8d5a20a378 100644
--- a/drivers/usb/gadget/udc/net2280.h
+++ b/drivers/usb/gadget/udc/net2280.h
@@ -100,7 +100,6 @@ struct net2280_ep {
dma_addr_t td_dma; /* of dummy */
struct net2280 *dev;
unsigned long irqs;
- unsigned is_halt:1, dma_started:1;
/* analogous to a host-side qh */
struct list_head queue;
@@ -126,7 +125,7 @@ static inline void allow_status(struct net2280_ep *ep)
ep->stopped = 1;
}
-static void allow_status_338x(struct net2280_ep *ep)
+static inline void allow_status_338x(struct net2280_ep *ep)
{
/*
* Control Status Phase Handshake was set by the chip when the setup
@@ -165,8 +164,8 @@ struct net2280 {
u2_enable:1,
ltm_enable:1,
wakeup_enable:1,
- selfpowered:1,
- addressed_state:1;
+ addressed_state:1,
+ bug7734_patched:1;
u16 chiprev;
int enhanced_mode;
int n_ep;
@@ -356,23 +355,6 @@ static inline void start_out_naking(struct net2280_ep *ep)
readl(&ep->regs->ep_rsp);
}
-#ifdef DEBUG
-static inline void assert_out_naking(struct net2280_ep *ep, const char *where)
-{
- u32 tmp = readl(&ep->regs->ep_stat);
-
- if ((tmp & BIT(NAK_OUT_PACKETS)) == 0) {
- ep_dbg(ep->dev, "%s %s %08x !NAK\n",
- ep->ep.name, where, tmp);
- writel(BIT(SET_NAK_OUT_PACKETS),
- &ep->regs->ep_rsp);
- }
-}
-#define ASSERT_OUT_NAKING(ep) assert_out_naking(ep, __func__)
-#else
-#define ASSERT_OUT_NAKING(ep) do {} while (0)
-#endif
-
static inline void stop_out_naking(struct net2280_ep *ep)
{
u32 tmp;
diff --git a/drivers/usb/gadget/udc/omap_udc.c b/drivers/usb/gadget/udc/omap_udc.c
index 288c087220a8..e2fcdb8e5596 100644
--- a/drivers/usb/gadget/udc/omap_udc.c
+++ b/drivers/usb/gadget/udc/omap_udc.c
@@ -1171,6 +1171,7 @@ omap_set_selfpowered(struct usb_gadget *gadget, int is_selfpowered)
unsigned long flags;
u16 syscon1;
+ gadget->is_selfpowered = (is_selfpowered != 0);
udc = container_of(gadget, struct omap_udc, gadget);
spin_lock_irqsave(&udc->lock, flags);
syscon1 = omap_readw(UDC_SYSCON1);
diff --git a/drivers/usb/gadget/udc/pch_udc.c b/drivers/usb/gadget/udc/pch_udc.c
index 1c7379ac2379..613547f07828 100644
--- a/drivers/usb/gadget/udc/pch_udc.c
+++ b/drivers/usb/gadget/udc/pch_udc.c
@@ -1161,6 +1161,7 @@ static int pch_udc_pcd_selfpowered(struct usb_gadget *gadget, int value)
if (!gadget)
return -EINVAL;
+ gadget->is_selfpowered = (value != 0);
dev = container_of(gadget, struct pch_udc_dev, gadget);
if (value)
pch_udc_set_selfpowered(dev);
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.c b/drivers/usb/gadget/udc/pxa25x_udc.c
index 8550b2d5db32..f6cbe667ce39 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.c
+++ b/drivers/usb/gadget/udc/pxa25x_udc.c
@@ -1272,7 +1272,6 @@ static int pxa25x_udc_start(struct usb_gadget *g,
goto bind_fail;
}
- pullup(dev);
dump_state(dev);
return 0;
bind_fail:
@@ -1339,7 +1338,6 @@ static int pxa25x_udc_stop(struct usb_gadget*g)
local_irq_disable();
dev->pullup = 0;
- pullup(dev);
stop_activity(dev, NULL);
local_irq_enable();
diff --git a/drivers/usb/gadget/udc/pxa27x_udc.c b/drivers/usb/gadget/udc/pxa27x_udc.c
index c61a896061fa..6a855fc9bd84 100644
--- a/drivers/usb/gadget/udc/pxa27x_udc.c
+++ b/drivers/usb/gadget/udc/pxa27x_udc.c
@@ -1809,7 +1809,6 @@ static int pxa27x_udc_start(struct usb_gadget *g,
/* first hook up the driver ... */
udc->driver = driver;
- dplus_pullup(udc, 1);
if (!IS_ERR_OR_NULL(udc->transceiver)) {
retval = otg_set_peripheral(udc->transceiver->otg,
@@ -1862,7 +1861,6 @@ static int pxa27x_udc_stop(struct usb_gadget *g)
stop_activity(udc, NULL);
udc_disable(udc);
- dplus_pullup(udc, 0);
udc->driver = NULL;
diff --git a/drivers/usb/gadget/udc/r8a66597-udc.c b/drivers/usb/gadget/udc/r8a66597-udc.c
index 06870da0b988..2495fe9c95c5 100644
--- a/drivers/usb/gadget/udc/r8a66597-udc.c
+++ b/drivers/usb/gadget/udc/r8a66597-udc.c
@@ -1803,6 +1803,7 @@ static int r8a66597_set_selfpowered(struct usb_gadget *gadget, int is_self)
{
struct r8a66597 *r8a66597 = gadget_to_r8a66597(gadget);
+ gadget->is_selfpowered = (is_self != 0);
if (is_self)
r8a66597->device_status |= 1 << USB_DEVICE_SELF_POWERED;
else
diff --git a/drivers/usb/gadget/udc/s3c2410_udc.c b/drivers/usb/gadget/udc/s3c2410_udc.c
index 824cf12e9add..b808951491cc 100644
--- a/drivers/usb/gadget/udc/s3c2410_udc.c
+++ b/drivers/usb/gadget/udc/s3c2410_udc.c
@@ -238,14 +238,6 @@ static inline void s3c2410_udc_set_ep0_de_out(void __iomem *base)
S3C2410_UDC_EP0_CSR_REG);
}
-static inline void s3c2410_udc_set_ep0_sse_out(void __iomem *base)
-{
- udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
- udc_writeb(base, (S3C2410_UDC_EP0_CSR_SOPKTRDY
- | S3C2410_UDC_EP0_CSR_SSE),
- S3C2410_UDC_EP0_CSR_REG);
-}
-
static inline void s3c2410_udc_set_ep0_de_in(void __iomem *base)
{
udc_writeb(base, S3C2410_UDC_INDEX_EP0, S3C2410_UDC_INDEX_REG);
@@ -291,18 +283,6 @@ static void s3c2410_udc_nuke(struct s3c2410_udc *udc,
}
}
-static inline void s3c2410_udc_clear_ep_state(struct s3c2410_udc *dev)
-{
- unsigned i;
-
- /* hardware SET_{CONFIGURATION,INTERFACE} automagic resets endpoint
- * fifos, and pending transactions mustn't be continued in any case.
- */
-
- for (i = 1; i < S3C2410_ENDPOINTS; i++)
- s3c2410_udc_nuke(dev, &dev->ep[i], -ECONNABORTED);
-}
-
static inline int s3c2410_udc_fifo_count_out(void)
{
int tmp;
@@ -1454,6 +1434,7 @@ static int s3c2410_udc_set_selfpowered(struct usb_gadget *gadget, int value)
dprintk(DEBUG_NORMAL, "%s()\n", __func__);
+ gadget->is_selfpowered = (value != 0);
if (value)
udc->devstatus |= (1 << USB_DEVICE_SELF_POWERED);
else
diff --git a/drivers/usb/gadget/udc/udc-core.c b/drivers/usb/gadget/udc/udc-core.c
index e31d574d8860..5a81cb086b99 100644
--- a/drivers/usb/gadget/udc/udc-core.c
+++ b/drivers/usb/gadget/udc/udc-core.c
@@ -564,6 +564,7 @@ static USB_UDC_ATTR(is_a_peripheral);
static USB_UDC_ATTR(b_hnp_enable);
static USB_UDC_ATTR(a_hnp_support);
static USB_UDC_ATTR(a_alt_hnp_support);
+static USB_UDC_ATTR(is_selfpowered);
static struct attribute *usb_udc_attrs[] = {
&dev_attr_srp.attr,
@@ -577,6 +578,7 @@ static struct attribute *usb_udc_attrs[] = {
&dev_attr_b_hnp_enable.attr,
&dev_attr_a_hnp_support.attr,
&dev_attr_a_alt_hnp_support.attr,
+ &dev_attr_is_selfpowered.attr,
NULL,
};
diff --git a/drivers/usb/gadget/udc/udc-xilinx.c b/drivers/usb/gadget/udc/udc-xilinx.c
index 1eac56fc384d..dd3e9fd31b80 100644
--- a/drivers/usb/gadget/udc/udc-xilinx.c
+++ b/drivers/usb/gadget/udc/udc-xilinx.c
@@ -2131,8 +2131,8 @@ static int xudc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, udc);
- dev_vdbg(&pdev->dev, "%s at 0x%08X mapped to 0x%08X %s\n",
- driver_name, (u32)res->start, (u32 __force)udc->addr,
+ dev_vdbg(&pdev->dev, "%s at 0x%08X mapped to %p %s\n",
+ driver_name, (u32)res->start, udc->addr,
udc->dma_enabled ? "with DMA" : "without DMA");
return 0;
diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
index fafc628480e0..5ad60e46dc2b 100644
--- a/drivers/usb/host/Kconfig
+++ b/drivers/usb/host/Kconfig
@@ -219,7 +219,7 @@ config USB_EHCI_TEGRA
config USB_EHCI_HCD_PPC_OF
bool "EHCI support for PPC USB controller on OF platform bus"
- depends on PPC_OF
+ depends on PPC
default y
---help---
Enables support for the USB controller present on the PowerPC
@@ -331,20 +331,6 @@ config USB_ISP116X_HCD
To compile this driver as a module, choose M here: the
module will be called isp116x-hcd.
-config USB_ISP1760_HCD
- tristate "ISP 1760 HCD support"
- ---help---
- The ISP1760 chip is a USB 2.0 host controller.
-
- This driver does not support isochronous transfers or OTG.
- This USB controller is usually attached to a non-DMA-Master
- capable bus. NXP's eval kit brings this chip on PCI card
- where the chip itself is behind a PLB to simulate such
- a bus.
-
- To compile this driver as a module, choose M here: the
- module will be called isp1760.
-
config USB_ISP1362_HCD
tristate "ISP1362 HCD support"
---help---
@@ -494,7 +480,7 @@ config USB_OHCI_ATH79
config USB_OHCI_HCD_PPC_OF_BE
bool "OHCI support for OF platform bus (big endian)"
- depends on PPC_OF
+ depends on PPC
select USB_OHCI_BIG_ENDIAN_DESC
select USB_OHCI_BIG_ENDIAN_MMIO
---help---
@@ -503,7 +489,7 @@ config USB_OHCI_HCD_PPC_OF_BE
config USB_OHCI_HCD_PPC_OF_LE
bool "OHCI support for OF platform bus (little endian)"
- depends on PPC_OF
+ depends on PPC
select USB_OHCI_LITTLE_ENDIAN
---help---
Enables support for little-endian USB controllers present on the
@@ -511,7 +497,7 @@ config USB_OHCI_HCD_PPC_OF_LE
config USB_OHCI_HCD_PPC_OF
bool
- depends on PPC_OF
+ depends on PPC
default USB_OHCI_HCD_PPC_OF_BE || USB_OHCI_HCD_PPC_OF_LE
config USB_OHCI_HCD_PCI
diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile
index d6216a493bab..65b0b6a58599 100644
--- a/drivers/usb/host/Makefile
+++ b/drivers/usb/host/Makefile
@@ -5,8 +5,6 @@
# tell define_trace.h where to find the xhci trace header
CFLAGS_xhci-trace.o := -I$(src)
-isp1760-y := isp1760-hcd.o isp1760-if.o
-
fhci-y := fhci-hcd.o fhci-hub.o fhci-q.o
fhci-y += fhci-mem.o fhci-tds.o fhci-sched.o
@@ -69,7 +67,6 @@ obj-$(CONFIG_USB_SL811_HCD) += sl811-hcd.o
obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o
obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o
obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o
-obj-$(CONFIG_USB_ISP1760_HCD) += isp1760.o
obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o
obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o
obj-$(CONFIG_USB_FSL_MPH_DR_OF) += fsl-mph-dr-of.o
diff --git a/drivers/usb/host/bcma-hcd.c b/drivers/usb/host/bcma-hcd.c
index cd6d0afb6b8f..526cfab41d5f 100644
--- a/drivers/usb/host/bcma-hcd.c
+++ b/drivers/usb/host/bcma-hcd.c
@@ -306,7 +306,7 @@ static int bcma_hcd_resume(struct bcma_device *dev)
static const struct bcma_device_id bcma_hcd_table[] = {
BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_USB20_HOST, BCMA_ANY_REV, BCMA_ANY_CLASS),
- BCMA_CORETABLE_END
+ {},
};
MODULE_DEVICE_TABLE(bcma, bcma_hcd_table);
diff --git a/drivers/usb/host/ehci-atmel.c b/drivers/usb/host/ehci-atmel.c
index 56a88506febe..663f7908b15c 100644
--- a/drivers/usb/host/ehci-atmel.c
+++ b/drivers/usb/host/ehci-atmel.c
@@ -27,44 +27,66 @@
#define DRIVER_DESC "EHCI Atmel driver"
static const char hcd_name[] = "ehci-atmel";
-static struct hc_driver __read_mostly ehci_atmel_hc_driver;
/* interface and function clocks */
-static struct clk *iclk, *fclk, *uclk;
-static int clocked;
+#define hcd_to_atmel_ehci_priv(h) \
+ ((struct atmel_ehci_priv *)hcd_to_ehci(h)->priv)
+
+struct atmel_ehci_priv {
+ struct clk *iclk;
+ struct clk *fclk;
+ struct clk *uclk;
+ bool clocked;
+};
+
+static struct hc_driver __read_mostly ehci_atmel_hc_driver;
+
+static const struct ehci_driver_overrides ehci_atmel_drv_overrides __initconst = {
+ .extra_priv_size = sizeof(struct atmel_ehci_priv),
+};
/*-------------------------------------------------------------------------*/
-static void atmel_start_clock(void)
+static void atmel_start_clock(struct atmel_ehci_priv *atmel_ehci)
{
+ if (atmel_ehci->clocked)
+ return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
- clk_set_rate(uclk, 48000000);
- clk_prepare_enable(uclk);
+ clk_set_rate(atmel_ehci->uclk, 48000000);
+ clk_prepare_enable(atmel_ehci->uclk);
}
- clk_prepare_enable(iclk);
- clk_prepare_enable(fclk);
- clocked = 1;
+ clk_prepare_enable(atmel_ehci->iclk);
+ clk_prepare_enable(atmel_ehci->fclk);
+ atmel_ehci->clocked = true;
}
-static void atmel_stop_clock(void)
+static void atmel_stop_clock(struct atmel_ehci_priv *atmel_ehci)
{
- clk_disable_unprepare(fclk);
- clk_disable_unprepare(iclk);
+ if (!atmel_ehci->clocked)
+ return;
+ clk_disable_unprepare(atmel_ehci->fclk);
+ clk_disable_unprepare(atmel_ehci->iclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_disable_unprepare(uclk);
- clocked = 0;
+ clk_disable_unprepare(atmel_ehci->uclk);
+ atmel_ehci->clocked = false;
}
static void atmel_start_ehci(struct platform_device *pdev)
{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(&pdev->dev, "start\n");
- atmel_start_clock();
+ atmel_start_clock(atmel_ehci);
}
static void atmel_stop_ehci(struct platform_device *pdev)
{
+ struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
dev_dbg(&pdev->dev, "stop\n");
- atmel_stop_clock();
+ atmel_stop_clock(atmel_ehci);
}
/*-------------------------------------------------------------------------*/
@@ -75,6 +97,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
const struct hc_driver *driver = &ehci_atmel_hc_driver;
struct resource *res;
struct ehci_hcd *ehci;
+ struct atmel_ehci_priv *atmel_ehci;
int irq;
int retval;
@@ -105,6 +128,7 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
retval = -ENOMEM;
goto fail_create_hcd;
}
+ atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(&pdev->dev, res);
@@ -116,23 +140,23 @@ static int ehci_atmel_drv_probe(struct platform_device *pdev)
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- iclk = devm_clk_get(&pdev->dev, "ehci_clk");
- if (IS_ERR(iclk)) {
+ atmel_ehci->iclk = devm_clk_get(&pdev->dev, "ehci_clk");
+ if (IS_ERR(atmel_ehci->iclk)) {
dev_err(&pdev->dev, "Error getting interface clock\n");
retval = -ENOENT;
goto fail_request_resource;
}
- fclk = devm_clk_get(&pdev->dev, "uhpck");
- if (IS_ERR(fclk)) {
+ atmel_ehci->fclk = devm_clk_get(&pdev->dev, "uhpck");
+ if (IS_ERR(atmel_ehci->fclk)) {
dev_err(&pdev->dev, "Error getting function clock\n");
retval = -ENOENT;
goto fail_request_resource;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
- uclk = devm_clk_get(&pdev->dev, "usb_clk");
- if (IS_ERR(uclk)) {
+ atmel_ehci->uclk = devm_clk_get(&pdev->dev, "usb_clk");
+ if (IS_ERR(atmel_ehci->uclk)) {
dev_err(&pdev->dev, "failed to get uclk\n");
- retval = PTR_ERR(uclk);
+ retval = PTR_ERR(atmel_ehci->uclk);
goto fail_request_resource;
}
}
@@ -169,11 +193,35 @@ static int ehci_atmel_drv_remove(struct platform_device *pdev)
usb_put_hcd(hcd);
atmel_stop_ehci(pdev);
- fclk = iclk = NULL;
return 0;
}
+#ifdef CONFIG_PM
+static int ehci_atmel_drv_suspend(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+ int ret;
+
+ ret = ehci_suspend(hcd, false);
+ if (ret)
+ return ret;
+
+ atmel_stop_clock(atmel_ehci);
+ return 0;
+}
+
+static int ehci_atmel_drv_resume(struct device *dev)
+{
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct atmel_ehci_priv *atmel_ehci = hcd_to_atmel_ehci_priv(hcd);
+
+ atmel_start_clock(atmel_ehci);
+ return ehci_resume(hcd, false);
+}
+#endif
+
#ifdef CONFIG_OF
static const struct of_device_id atmel_ehci_dt_ids[] = {
{ .compatible = "atmel,at91sam9g45-ehci" },
@@ -183,12 +231,16 @@ static const struct of_device_id atmel_ehci_dt_ids[] = {
MODULE_DEVICE_TABLE(of, atmel_ehci_dt_ids);
#endif
+static SIMPLE_DEV_PM_OPS(ehci_atmel_pm_ops, ehci_atmel_drv_suspend,
+ ehci_atmel_drv_resume);
+
static struct platform_driver ehci_atmel_driver = {
.probe = ehci_atmel_drv_probe,
.remove = ehci_atmel_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "atmel-ehci",
+ .pm = &ehci_atmel_pm_ops,
.of_match_table = of_match_ptr(atmel_ehci_dt_ids),
},
};
@@ -199,7 +251,7 @@ static int __init ehci_atmel_init(void)
return -ENODEV;
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
- ehci_init_driver(&ehci_atmel_hc_driver, NULL);
+ ehci_init_driver(&ehci_atmel_hc_driver, &ehci_atmel_drv_overrides);
return platform_driver_register(&ehci_atmel_driver);
}
module_init(ehci_atmel_init);
diff --git a/drivers/usb/host/ehci-fsl.c b/drivers/usb/host/ehci-fsl.c
index fb7bd0c7dc15..ab4eee3df97a 100644
--- a/drivers/usb/host/ehci-fsl.c
+++ b/drivers/usb/host/ehci-fsl.c
@@ -709,7 +709,6 @@ static struct platform_driver ehci_fsl_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "fsl-ehci",
- .owner = THIS_MODULE,
.pm = EHCI_FSL_PM_OPS,
},
};
diff --git a/drivers/usb/host/ehci-grlib.c b/drivers/usb/host/ehci-grlib.c
index 495b6fbcbcd9..21650044b09e 100644
--- a/drivers/usb/host/ehci-grlib.c
+++ b/drivers/usb/host/ehci-grlib.c
@@ -187,7 +187,6 @@ static struct platform_driver ehci_grlib_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "grlib-ehci",
- .owner = THIS_MODULE,
.of_match_table = ehci_hcd_grlib_of_match,
},
};
diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c
index 38bfeedae1d0..85e56d1abd23 100644
--- a/drivers/usb/host/ehci-hcd.c
+++ b/drivers/usb/host/ehci-hcd.c
@@ -1110,7 +1110,7 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup)
EXPORT_SYMBOL_GPL(ehci_suspend);
/* Returns 0 if power was preserved, 1 if power was lost */
-int ehci_resume(struct usb_hcd *hcd, bool hibernated)
+int ehci_resume(struct usb_hcd *hcd, bool force_reset)
{
struct ehci_hcd *ehci = hcd_to_ehci(hcd);
@@ -1124,12 +1124,12 @@ int ehci_resume(struct usb_hcd *hcd, bool hibernated)
return 0; /* Controller is dead */
/*
- * If CF is still set and we aren't resuming from hibernation
+ * If CF is still set and reset isn't forced
* then we maintained suspend power.
* Just undo the effect of ehci_suspend().
*/
if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF &&
- !hibernated) {
+ !force_reset) {
int mask = INTR_MASK;
ehci_prepare_ports_for_controller_resume(ehci);
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 118edb7bdca2..87cf86f38b36 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -700,15 +700,15 @@ ehci_hub_descriptor (
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
- temp = 0x0008; /* per-port overcurrent reporting */
+ temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
if (HCS_PPC (ehci->hcs_params))
- temp |= 0x0001; /* per-port power control */
+ temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
else
- temp |= 0x0002; /* no power switching */
+ temp |= HUB_CHAR_NO_LPSM; /* no power switching */
#if 0
// re-enable when we support USB_PORT_FEAT_INDICATOR below.
if (HCS_INDICATOR (ehci->hcs_params))
- temp |= 0x0080; /* per-port indicators (LEDs) */
+ temp |= HUB_CHAR_PORTIND; /* per-port indicators (LEDs) */
#endif
desc->wHubCharacteristics = cpu_to_le16(temp);
}
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index 851006a0d97b..2a5d2fd76040 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -43,6 +43,24 @@ static inline bool is_intel_quark_x1000(struct pci_dev *pdev)
}
/*
+ * This is the list of PCI IDs for the devices that have EHCI USB class and
+ * specific drivers for that. One of the example is a ChipIdea device installed
+ * on some Intel MID platforms.
+ */
+static const struct pci_device_id bypass_pci_id_table[] = {
+ /* ChipIdea on Intel MID platform */
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0811), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0x0829), },
+ { PCI_DEVICE(PCI_VENDOR_ID_INTEL, 0xe006), },
+ {}
+};
+
+static inline bool is_bypassed_id(struct pci_dev *pdev)
+{
+ return !!pci_match_id(bypass_pci_id_table, pdev);
+}
+
+/*
* 0x84 is the offset of in/out threshold register,
* and it is the same offset as the register of 'hostpc'.
*/
@@ -352,6 +370,13 @@ static const struct ehci_driver_overrides pci_overrides __initconst = {
/*-------------------------------------------------------------------------*/
+static int ehci_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ if (is_bypassed_id(pdev))
+ return -ENODEV;
+ return usb_hcd_pci_probe(pdev, id);
+}
+
/* PCI driver selection metadata; PCI hotplugging uses this */
static const struct pci_device_id pci_ids [] = { {
/* handle any USB 2.0 EHCI controller */
@@ -370,7 +395,7 @@ static struct pci_driver ehci_pci_driver = {
.name = (char *) hcd_name,
.id_table = pci_ids,
- .probe = usb_hcd_pci_probe,
+ .probe = ehci_pci_probe,
.remove = usb_hcd_pci_remove,
.shutdown = usb_hcd_pci_shutdown,
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 8557803e6154..d8a75a51d6d4 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -43,7 +43,8 @@
struct ehci_platform_priv {
struct clk *clks[EHCI_MAX_CLKS];
struct reset_control *rst;
- struct phy *phy;
+ struct phy **phys;
+ int num_phys;
};
static const char hcd_name[] = "ehci-platform";
@@ -78,7 +79,7 @@ static int ehci_platform_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
- int clk, ret;
+ int clk, ret, phy_num;
for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
ret = clk_prepare_enable(priv->clks[clk]);
@@ -86,20 +87,28 @@ static int ehci_platform_power_on(struct platform_device *dev)
goto err_disable_clks;
}
- if (priv->phy) {
- ret = phy_init(priv->phy);
- if (ret)
- goto err_disable_clks;
-
- ret = phy_power_on(priv->phy);
- if (ret)
- goto err_exit_phy;
+ for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+ if (priv->phys[phy_num]) {
+ ret = phy_init(priv->phys[phy_num]);
+ if (ret)
+ goto err_exit_phy;
+ ret = phy_power_on(priv->phys[phy_num]);
+ if (ret) {
+ phy_exit(priv->phys[phy_num]);
+ goto err_exit_phy;
+ }
+ }
}
return 0;
err_exit_phy:
- phy_exit(priv->phy);
+ while (--phy_num >= 0) {
+ if (priv->phys[phy_num]) {
+ phy_power_off(priv->phys[phy_num]);
+ phy_exit(priv->phys[phy_num]);
+ }
+ }
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
@@ -111,11 +120,13 @@ static void ehci_platform_power_off(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
- int clk;
+ int clk, phy_num;
- if (priv->phy) {
- phy_power_off(priv->phy);
- phy_exit(priv->phy);
+ for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+ if (priv->phys[phy_num]) {
+ phy_power_off(priv->phys[phy_num]);
+ phy_exit(priv->phys[phy_num]);
+ }
}
for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -143,7 +154,8 @@ static int ehci_platform_probe(struct platform_device *dev)
struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ehci_platform_priv *priv;
struct ehci_hcd *ehci;
- int err, irq, clk = 0;
+ const char *phy_name;
+ int err, irq, phy_num, clk = 0;
if (usb_disabled())
return -ENODEV;
@@ -155,7 +167,8 @@ static int ehci_platform_probe(struct platform_device *dev)
if (!pdata)
pdata = &ehci_platform_defaults;
- err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32));
+ err = dma_coerce_mask_and_coherent(&dev->dev,
+ pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32));
if (err)
return err;
@@ -185,12 +198,42 @@ static int ehci_platform_probe(struct platform_device *dev)
if (of_property_read_bool(dev->dev.of_node, "big-endian"))
ehci->big_endian_mmio = ehci->big_endian_desc = 1;
- priv->phy = devm_phy_get(&dev->dev, "usb");
- if (IS_ERR(priv->phy)) {
- err = PTR_ERR(priv->phy);
- if (err == -EPROBE_DEFER)
- goto err_put_hcd;
- priv->phy = NULL;
+ if (of_property_read_bool(dev->dev.of_node,
+ "needs-reset-on-resume"))
+ pdata->reset_on_resume = 1;
+
+ priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
+ "phys", "#phy-cells");
+ priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
+
+ priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+ sizeof(struct phy *), GFP_KERNEL);
+ if (!priv->phys)
+ return -ENOMEM;
+
+ for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+ err = of_property_read_string_index(
+ dev->dev.of_node,
+ "phy-names", phy_num,
+ &phy_name);
+
+ if (err < 0) {
+ if (priv->num_phys > 1) {
+ dev_err(&dev->dev, "phy-names not provided");
+ goto err_put_hcd;
+ } else
+ phy_name = "usb";
+ }
+
+ priv->phys[phy_num] = devm_phy_get(&dev->dev,
+ phy_name);
+ if (IS_ERR(priv->phys[phy_num])) {
+ err = PTR_ERR(priv->phys[phy_num]);
+ if ((priv->num_phys > 1) ||
+ (err == -EPROBE_DEFER))
+ goto err_put_hcd;
+ priv->phys[phy_num] = NULL;
+ }
}
for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {
@@ -340,7 +383,7 @@ static int ehci_platform_resume(struct device *dev)
return err;
}
- ehci_resume(hcd, false);
+ ehci_resume(hcd, pdata->reset_on_resume);
return 0;
}
#endif /* CONFIG_PM_SLEEP */
@@ -349,6 +392,7 @@ static const struct of_device_id vt8500_ehci_ids[] = {
{ .compatible = "via,vt8500-ehci", },
{ .compatible = "wm,prizm-ehci", },
{ .compatible = "generic-ehci", },
+ { .compatible = "cavium,octeon-6335-ehci", },
{}
};
MODULE_DEVICE_TABLE(of, vt8500_ehci_ids);
diff --git a/drivers/usb/host/ehci-pmcmsp.c b/drivers/usb/host/ehci-pmcmsp.c
index 7d75465d97c7..342816a7f8b1 100644
--- a/drivers/usb/host/ehci-pmcmsp.c
+++ b/drivers/usb/host/ehci-pmcmsp.c
@@ -325,6 +325,5 @@ static struct platform_driver ehci_hcd_msp_driver = {
.remove = ehci_hcd_msp_drv_remove,
.driver = {
.name = "pmcmsp-ehci",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/host/ehci-ppc-of.c b/drivers/usb/host/ehci-ppc-of.c
index 547924796d29..1a10c8d542ca 100644
--- a/drivers/usb/host/ehci-ppc-of.c
+++ b/drivers/usb/host/ehci-ppc-of.c
@@ -234,7 +234,6 @@ static struct platform_driver ehci_hcd_ppc_of_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-of-ehci",
- .owner = THIS_MODULE,
.of_match_table = ehci_hcd_ppc_of_match,
},
};
diff --git a/drivers/usb/host/ehci-sead3.c b/drivers/usb/host/ehci-sead3.c
index 9b6e8d0eac43..3d86cc2ffe68 100644
--- a/drivers/usb/host/ehci-sead3.c
+++ b/drivers/usb/host/ehci-sead3.c
@@ -178,7 +178,6 @@ static struct platform_driver ehci_hcd_sead3_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "sead3-ehci",
- .owner = THIS_MODULE,
.pm = SEAD3_EHCI_PMOPS,
}
};
diff --git a/drivers/usb/host/ehci-sh.c b/drivers/usb/host/ehci-sh.c
index 0e0ce684aff3..5caf88d679e4 100644
--- a/drivers/usb/host/ehci-sh.c
+++ b/drivers/usb/host/ehci-sh.c
@@ -189,7 +189,6 @@ static struct platform_driver ehci_hcd_sh_driver = {
.shutdown = ehci_hcd_sh_shutdown,
.driver = {
.name = "sh_ehci",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/host/ehci-tilegx.c b/drivers/usb/host/ehci-tilegx.c
index 0d247673c3ca..bdb93b6a356f 100644
--- a/drivers/usb/host/ehci-tilegx.c
+++ b/drivers/usb/host/ehci-tilegx.c
@@ -210,7 +210,6 @@ static struct platform_driver ehci_hcd_tilegx_driver = {
.shutdown = ehci_hcd_tilegx_drv_shutdown,
.driver = {
.name = "tilegx-ehci",
- .owner = THIS_MODULE,
}
};
diff --git a/drivers/usb/host/ehci-xilinx-of.c b/drivers/usb/host/ehci-xilinx-of.c
index a2328361dc80..f54480850bb8 100644
--- a/drivers/usb/host/ehci-xilinx-of.c
+++ b/drivers/usb/host/ehci-xilinx-of.c
@@ -236,7 +236,6 @@ static struct platform_driver ehci_hcd_xilinx_of_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "xilinx-of-ehci",
- .owner = THIS_MODULE,
.of_match_table = ehci_hcd_xilinx_of_match,
},
};
diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h
index 6f0577b0a5ae..52ef0844a180 100644
--- a/drivers/usb/host/ehci.h
+++ b/drivers/usb/host/ehci.h
@@ -871,7 +871,7 @@ extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr,
#ifdef CONFIG_PM
extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup);
-extern int ehci_resume(struct usb_hcd *hcd, bool hibernated);
+extern int ehci_resume(struct usb_hcd *hcd, bool force_reset);
#endif /* CONFIG_PM */
extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
diff --git a/drivers/usb/host/fhci-hub.c b/drivers/usb/host/fhci-hub.c
index 6af2512f8378..70116a65262c 100644
--- a/drivers/usb/host/fhci-hub.c
+++ b/drivers/usb/host/fhci-hub.c
@@ -32,8 +32,8 @@ static u8 root_hub_des[] = {
0x09, /* blength */
0x29, /* bDescriptorType;hub-descriptor */
0x01, /* bNbrPorts */
- 0x00, /* wHubCharacteristics */
- 0x00,
+ HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM, /* wHubCharacteristics */
+ 0x00, /* per-port power, no overcurrent */
0x01, /* bPwrOn2pwrGood;2ms */
0x00, /* bHubContrCurrent;0mA */
0x00, /* DeviceRemoveable */
@@ -208,7 +208,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
{
struct fhci_hcd *fhci = hcd_to_fhci(hcd);
int retval = 0;
- int len = 0;
struct usb_hub_status *hub_status;
struct usb_port_status *port_status;
unsigned long flags;
@@ -272,8 +271,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
break;
case GetHubDescriptor:
memcpy(buf, root_hub_des, sizeof(root_hub_des));
- buf[3] = 0x11; /* per-port power, no ovrcrnt */
- len = (buf[0] < wLength) ? buf[0] : wLength;
break;
case GetHubStatus:
hub_status = (struct usb_hub_status *)buf;
@@ -281,7 +278,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
cpu_to_le16(fhci->vroot_hub->hub.wHubStatus);
hub_status->wHubChange =
cpu_to_le16(fhci->vroot_hub->hub.wHubChange);
- len = 4;
break;
case GetPortStatus:
port_status = (struct usb_port_status *)buf;
@@ -289,7 +285,6 @@ int fhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
cpu_to_le16(fhci->vroot_hub->port.wPortStatus);
port_status->wPortChange =
cpu_to_le16(fhci->vroot_hub->port.wPortChange);
- len = 4;
break;
case SetHubFeature:
switch (wValue) {
diff --git a/drivers/usb/host/fotg210-hcd.c b/drivers/usb/host/fotg210-hcd.c
index ecf02b2623e8..475b21fd373b 100644
--- a/drivers/usb/host/fotg210-hcd.c
+++ b/drivers/usb/host/fotg210-hcd.c
@@ -1521,8 +1521,8 @@ fotg210_hub_descriptor(
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
- temp = 0x0008; /* per-port overcurrent reporting */
- temp |= 0x0002; /* no power switching */
+ temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
+ temp |= HUB_CHAR_NO_LPSM; /* no power switching */
desc->wHubCharacteristics = cpu_to_le16(temp);
}
diff --git a/drivers/usb/host/fusbh200-hcd.c b/drivers/usb/host/fusbh200-hcd.c
index 664d2aa1239c..a83eefefffda 100644
--- a/drivers/usb/host/fusbh200-hcd.c
+++ b/drivers/usb/host/fusbh200-hcd.c
@@ -1479,8 +1479,8 @@ fusbh200_hub_descriptor (
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
- temp = 0x0008; /* per-port overcurrent reporting */
- temp |= 0x0002; /* no power switching */
+ temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
+ temp |= HUB_CHAR_NO_LPSM; /* no power switching */
desc->wHubCharacteristics = cpu_to_le16(temp);
}
diff --git a/drivers/usb/host/imx21-hcd.c b/drivers/usb/host/imx21-hcd.c
index eb4efba9f1ad..6a2ad550b120 100644
--- a/drivers/usb/host/imx21-hcd.c
+++ b/drivers/usb/host/imx21-hcd.c
@@ -1482,9 +1482,8 @@ static int get_hub_descriptor(struct usb_hcd *hcd,
desc->bDescLength = 9;
desc->bPwrOn2PwrGood = 0;
desc->wHubCharacteristics = (__force __u16) cpu_to_le16(
- 0x0002 | /* No power switching */
- 0x0010 | /* No over current protection */
- 0);
+ HUB_CHAR_NO_LPSM | /* No power switching */
+ HUB_CHAR_NO_OCPM); /* No over current protection */
desc->u.hs.DeviceRemovable[0] = 1 << 1;
desc->u.hs.DeviceRemovable[1] = ~0;
diff --git a/drivers/usb/host/isp116x-hcd.c b/drivers/usb/host/isp116x-hcd.c
index 31c9c4d0fa0b..113d0cc6cc43 100644
--- a/drivers/usb/host/isp116x-hcd.c
+++ b/drivers/usb/host/isp116x-hcd.c
@@ -948,7 +948,10 @@ static void isp116x_hub_descriptor(struct isp116x *isp116x,
desc->bHubContrCurrent = 0;
desc->bNbrPorts = (u8) (reg & 0x3);
/* Power switching, device type, overcurrent. */
- desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) & 0x1f));
+ desc->wHubCharacteristics = cpu_to_le16((u16) ((reg >> 8) &
+ (HUB_CHAR_LPSM |
+ HUB_CHAR_COMPOUND |
+ HUB_CHAR_OCPM)));
desc->bPwrOn2PwrGood = (u8) ((reg >> 24) & 0xff);
/* ports removable, and legacy PortPwrCtrlMask */
desc->u.hs.DeviceRemovable[0] = 0;
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 75e5876f9d7c..b32ab60cad1e 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -1543,8 +1543,12 @@ static void isp1362_hub_descriptor(struct isp1362_hcd *isp1362_hcd,
desc->bHubContrCurrent = 0;
desc->bNbrPorts = reg & 0x3;
/* Power switching, device type, overcurrent. */
- desc->wHubCharacteristics = cpu_to_le16((reg >> 8) & 0x1f);
- DBG(0, "%s: hubcharacteristics = %02x\n", __func__, cpu_to_le16((reg >> 8) & 0x1f));
+ desc->wHubCharacteristics = cpu_to_le16((reg >> 8) &
+ (HUB_CHAR_LPSM |
+ HUB_CHAR_COMPOUND |
+ HUB_CHAR_OCPM));
+ DBG(0, "%s: hubcharacteristics = %02x\n", __func__,
+ desc->wHubCharacteristics);
desc->bPwrOn2PwrGood = (reg >> 24) & 0xff;
/* ports removable, and legacy PortPwrCtrlMask */
desc->u.hs.DeviceRemovable[0] = desc->bNbrPorts == 1 ? 1 << 1 : 3 << 1;
diff --git a/drivers/usb/host/isp1760-hcd.c b/drivers/usb/host/isp1760-hcd.c
deleted file mode 100644
index 395649f357aa..000000000000
--- a/drivers/usb/host/isp1760-hcd.c
+++ /dev/null
@@ -1,2268 +0,0 @@
-/*
- * Driver for the NXP ISP1760 chip
- *
- * However, the code might contain some bugs. What doesn't work for sure is:
- * - ISO
- * - OTG
- e The interrupt line is configured as active low, level.
- *
- * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
- *
- * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
- *
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/usb.h>
-#include <linux/usb/hcd.h>
-#include <linux/debugfs.h>
-#include <linux/uaccess.h>
-#include <linux/io.h>
-#include <linux/mm.h>
-#include <linux/timer.h>
-#include <asm/unaligned.h>
-#include <asm/cacheflush.h>
-#include <linux/gpio.h>
-
-#include "isp1760-hcd.h"
-
-static struct kmem_cache *qtd_cachep;
-static struct kmem_cache *qh_cachep;
-static struct kmem_cache *urb_listitem_cachep;
-
-enum queue_head_types {
- QH_CONTROL,
- QH_BULK,
- QH_INTERRUPT,
- QH_END
-};
-
-struct isp1760_hcd {
- u32 hcs_params;
- spinlock_t lock;
- struct slotinfo atl_slots[32];
- int atl_done_map;
- struct slotinfo int_slots[32];
- int int_done_map;
- struct memory_chunk memory_pool[BLOCKS];
- struct list_head qh_list[QH_END];
-
- /* periodic schedule support */
-#define DEFAULT_I_TDPS 1024
- unsigned periodic_size;
- unsigned i_thresh;
- unsigned long reset_done;
- unsigned long next_statechange;
- unsigned int devflags;
-
- int rst_gpio;
-};
-
-static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
-{
- return (struct isp1760_hcd *) (hcd->hcd_priv);
-}
-
-/* Section 2.2 Host Controller Capability Registers */
-#define HC_LENGTH(p) (((p)>>00)&0x00ff) /* bits 7:0 */
-#define HC_VERSION(p) (((p)>>16)&0xffff) /* bits 31:16 */
-#define HCS_INDICATOR(p) ((p)&(1 << 16)) /* true: has port indicators */
-#define HCS_PPC(p) ((p)&(1 << 4)) /* true: port power control */
-#define HCS_N_PORTS(p) (((p)>>0)&0xf) /* bits 3:0, ports on HC */
-#define HCC_ISOC_CACHE(p) ((p)&(1 << 7)) /* true: can cache isoc frame */
-#define HCC_ISOC_THRES(p) (((p)>>4)&0x7) /* bits 6:4, uframes cached */
-
-/* Section 2.3 Host Controller Operational Registers */
-#define CMD_LRESET (1<<7) /* partial reset (no ports, etc) */
-#define CMD_RESET (1<<1) /* reset HC not bus */
-#define CMD_RUN (1<<0) /* start/stop HC */
-#define STS_PCD (1<<2) /* port change detect */
-#define FLAG_CF (1<<0) /* true: we'll support "high speed" */
-
-#define PORT_OWNER (1<<13) /* true: companion hc owns this port */
-#define PORT_POWER (1<<12) /* true: has power (see PPC) */
-#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
-#define PORT_RESET (1<<8) /* reset port */
-#define PORT_SUSPEND (1<<7) /* suspend port */
-#define PORT_RESUME (1<<6) /* resume it */
-#define PORT_PE (1<<2) /* port enable */
-#define PORT_CSC (1<<1) /* connect status change */
-#define PORT_CONNECT (1<<0) /* device connected */
-#define PORT_RWC_BITS (PORT_CSC)
-
-struct isp1760_qtd {
- u8 packet_type;
- void *data_buffer;
- u32 payload_addr;
-
- /* the rest is HCD-private */
- struct list_head qtd_list;
- struct urb *urb;
- size_t length;
- size_t actual_length;
-
- /* QTD_ENQUEUED: waiting for transfer (inactive) */
- /* QTD_PAYLOAD_ALLOC: chip mem has been allocated for payload */
- /* QTD_XFER_STARTED: valid ptd has been written to isp176x - only
- interrupt handler may touch this qtd! */
- /* QTD_XFER_COMPLETE: payload has been transferred successfully */
- /* QTD_RETIRE: transfer error/abort qtd */
-#define QTD_ENQUEUED 0
-#define QTD_PAYLOAD_ALLOC 1
-#define QTD_XFER_STARTED 2
-#define QTD_XFER_COMPLETE 3
-#define QTD_RETIRE 4
- u32 status;
-};
-
-/* Queue head, one for each active endpoint */
-struct isp1760_qh {
- struct list_head qh_list;
- struct list_head qtd_list;
- u32 toggle;
- u32 ping;
- int slot;
- int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */
-};
-
-struct urb_listitem {
- struct list_head urb_list;
- struct urb *urb;
-};
-
-/*
- * Access functions for isp176x registers (addresses 0..0x03FF).
- */
-static u32 reg_read32(void __iomem *base, u32 reg)
-{
- return readl(base + reg);
-}
-
-static void reg_write32(void __iomem *base, u32 reg, u32 val)
-{
- writel(val, base + reg);
-}
-
-/*
- * Access functions for isp176x memory (offset >= 0x0400).
- *
- * bank_reads8() reads memory locations prefetched by an earlier write to
- * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
- * bank optimizations, you should use the more generic mem_reads8() below.
- *
- * For access to ptd memory, use the specialized ptd_read() and ptd_write()
- * below.
- *
- * These functions copy via MMIO data to/from the device. memcpy_{to|from}io()
- * doesn't quite work because some people have to enforce 32-bit access
- */
-static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
- __u32 *dst, u32 bytes)
-{
- __u32 __iomem *src;
- u32 val;
- __u8 *src_byteptr;
- __u8 *dst_byteptr;
-
- src = src_base + (bank_addr | src_offset);
-
- if (src_offset < PAYLOAD_OFFSET) {
- while (bytes >= 4) {
- *dst = le32_to_cpu(__raw_readl(src));
- bytes -= 4;
- src++;
- dst++;
- }
- } else {
- while (bytes >= 4) {
- *dst = __raw_readl(src);
- bytes -= 4;
- src++;
- dst++;
- }
- }
-
- if (!bytes)
- return;
-
- /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
- * allocated.
- */
- if (src_offset < PAYLOAD_OFFSET)
- val = le32_to_cpu(__raw_readl(src));
- else
- val = __raw_readl(src);
-
- dst_byteptr = (void *) dst;
- src_byteptr = (void *) &val;
- while (bytes > 0) {
- *dst_byteptr = *src_byteptr;
- dst_byteptr++;
- src_byteptr++;
- bytes--;
- }
-}
-
-static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
- u32 bytes)
-{
- reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
- ndelay(90);
- bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
-}
-
-static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
- __u32 const *src, u32 bytes)
-{
- __u32 __iomem *dst;
-
- dst = dst_base + dst_offset;
-
- if (dst_offset < PAYLOAD_OFFSET) {
- while (bytes >= 4) {
- __raw_writel(cpu_to_le32(*src), dst);
- bytes -= 4;
- src++;
- dst++;
- }
- } else {
- while (bytes >= 4) {
- __raw_writel(*src, dst);
- bytes -= 4;
- src++;
- dst++;
- }
- }
-
- if (!bytes)
- return;
- /* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the
- * extra bytes should not be read by the HW.
- */
-
- if (dst_offset < PAYLOAD_OFFSET)
- __raw_writel(cpu_to_le32(*src), dst);
- else
- __raw_writel(*src, dst);
-}
-
-/*
- * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
- * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
- */
-static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
- struct ptd *ptd)
-{
- reg_write32(base, HC_MEMORY_REG,
- ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
- ndelay(90);
- bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
- (void *) ptd, sizeof(*ptd));
-}
-
-static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
- struct ptd *ptd)
-{
- mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
- &ptd->dw1, 7*sizeof(ptd->dw1));
- /* Make sure dw0 gets written last (after other dw's and after payload)
- since it contains the enable bit */
- wmb();
- mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
- sizeof(ptd->dw0));
-}
-
-
-/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
-static void init_memory(struct isp1760_hcd *priv)
-{
- int i, curr;
- u32 payload_addr;
-
- payload_addr = PAYLOAD_OFFSET;
- for (i = 0; i < BLOCK_1_NUM; i++) {
- priv->memory_pool[i].start = payload_addr;
- priv->memory_pool[i].size = BLOCK_1_SIZE;
- priv->memory_pool[i].free = 1;
- payload_addr += priv->memory_pool[i].size;
- }
-
- curr = i;
- for (i = 0; i < BLOCK_2_NUM; i++) {
- priv->memory_pool[curr + i].start = payload_addr;
- priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
- priv->memory_pool[curr + i].free = 1;
- payload_addr += priv->memory_pool[curr + i].size;
- }
-
- curr = i;
- for (i = 0; i < BLOCK_3_NUM; i++) {
- priv->memory_pool[curr + i].start = payload_addr;
- priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
- priv->memory_pool[curr + i].free = 1;
- payload_addr += priv->memory_pool[curr + i].size;
- }
-
- WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
-}
-
-static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int i;
-
- WARN_ON(qtd->payload_addr);
-
- if (!qtd->length)
- return;
-
- for (i = 0; i < BLOCKS; i++) {
- if (priv->memory_pool[i].size >= qtd->length &&
- priv->memory_pool[i].free) {
- priv->memory_pool[i].free = 0;
- qtd->payload_addr = priv->memory_pool[i].start;
- return;
- }
- }
-}
-
-static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int i;
-
- if (!qtd->payload_addr)
- return;
-
- for (i = 0; i < BLOCKS; i++) {
- if (priv->memory_pool[i].start == qtd->payload_addr) {
- WARN_ON(priv->memory_pool[i].free);
- priv->memory_pool[i].free = 1;
- qtd->payload_addr = 0;
- return;
- }
- }
-
- dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",
- __func__, qtd->payload_addr);
- WARN_ON(1);
- qtd->payload_addr = 0;
-}
-
-static int handshake(struct usb_hcd *hcd, u32 reg,
- u32 mask, u32 done, int usec)
-{
- u32 result;
-
- do {
- result = reg_read32(hcd->regs, reg);
- if (result == ~0)
- return -ENODEV;
- result &= mask;
- if (result == done)
- return 0;
- udelay(1);
- usec--;
- } while (usec > 0);
- return -ETIMEDOUT;
-}
-
-/* reset a non-running (STS_HALT == 1) controller */
-static int ehci_reset(struct usb_hcd *hcd)
-{
- int retval;
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
-
- u32 command = reg_read32(hcd->regs, HC_USBCMD);
-
- command |= CMD_RESET;
- reg_write32(hcd->regs, HC_USBCMD, command);
- hcd->state = HC_STATE_HALT;
- priv->next_statechange = jiffies;
- retval = handshake(hcd, HC_USBCMD,
- CMD_RESET, 0, 250 * 1000);
- return retval;
-}
-
-static struct isp1760_qh *qh_alloc(gfp_t flags)
-{
- struct isp1760_qh *qh;
-
- qh = kmem_cache_zalloc(qh_cachep, flags);
- if (!qh)
- return NULL;
-
- INIT_LIST_HEAD(&qh->qh_list);
- INIT_LIST_HEAD(&qh->qtd_list);
- qh->slot = -1;
-
- return qh;
-}
-
-static void qh_free(struct isp1760_qh *qh)
-{
- WARN_ON(!list_empty(&qh->qtd_list));
- WARN_ON(qh->slot > -1);
- kmem_cache_free(qh_cachep, qh);
-}
-
-/* one-time init, only for memory state */
-static int priv_init(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 hcc_params;
- int i;
-
- spin_lock_init(&priv->lock);
-
- for (i = 0; i < QH_END; i++)
- INIT_LIST_HEAD(&priv->qh_list[i]);
-
- /*
- * hw default: 1K periodic list heads, one per frame.
- * periodic_size can shrink by USBCMD update if hcc_params allows.
- */
- priv->periodic_size = DEFAULT_I_TDPS;
-
- /* controllers may cache some of the periodic schedule ... */
- hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
- /* full frame cache */
- if (HCC_ISOC_CACHE(hcc_params))
- priv->i_thresh = 8;
- else /* N microframes cached */
- priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
-
- return 0;
-}
-
-static int isp1760_hc_setup(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int result;
- u32 scratch, hwmode;
-
- /* low-level chip reset */
- if (gpio_is_valid(priv->rst_gpio)) {
- unsigned int rst_lvl;
-
- rst_lvl = (priv->devflags &
- ISP1760_FLAG_RESET_ACTIVE_HIGH) ? 1 : 0;
-
- gpio_set_value(priv->rst_gpio, rst_lvl);
- mdelay(50);
- gpio_set_value(priv->rst_gpio, !rst_lvl);
- }
-
- /* Setup HW Mode Control: This assumes a level active-low interrupt */
- hwmode = HW_DATA_BUS_32BIT;
-
- if (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16)
- hwmode &= ~HW_DATA_BUS_32BIT;
- if (priv->devflags & ISP1760_FLAG_ANALOG_OC)
- hwmode |= HW_ANA_DIGI_OC;
- if (priv->devflags & ISP1760_FLAG_DACK_POL_HIGH)
- hwmode |= HW_DACK_POL_HIGH;
- if (priv->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
- hwmode |= HW_DREQ_POL_HIGH;
- if (priv->devflags & ISP1760_FLAG_INTR_POL_HIGH)
- hwmode |= HW_INTR_HIGH_ACT;
- if (priv->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
- hwmode |= HW_INTR_EDGE_TRIG;
-
- /*
- * We have to set this first in case we're in 16-bit mode.
- * Write it twice to ensure correct upper bits if switching
- * to 16-bit mode.
- */
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-
- reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
- /* Change bus pattern */
- scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
- if (scratch != 0xdeadbabe) {
- dev_err(hcd->self.controller, "Scratch test failed.\n");
- return -ENODEV;
- }
-
- /* pre reset */
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
-
- /* reset */
- reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
- mdelay(100);
-
- reg_write32(hcd->regs, HC_RESET_REG, SW_RESET_RESET_HC);
- mdelay(100);
-
- result = ehci_reset(hcd);
- if (result)
- return result;
-
- /* Step 11 passed */
-
- dev_info(hcd->self.controller, "bus width: %d, oc: %s\n",
- (priv->devflags & ISP1760_FLAG_BUS_WIDTH_16) ?
- 16 : 32, (priv->devflags & ISP1760_FLAG_ANALOG_OC) ?
- "analog" : "digital");
-
- /* ATL reset */
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
- mdelay(10);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
-
- reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
-
- /*
- * PORT 1 Control register of the ISP1760 is the OTG control
- * register on ISP1761. Since there is no OTG or device controller
- * support in this driver, we use port 1 as a "normal" USB host port on
- * both chips.
- */
- reg_write32(hcd->regs, HC_PORT1_CTRL, PORT1_POWER | PORT1_INIT2);
- mdelay(10);
-
- priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
-
- return priv_init(hcd);
-}
-
-static u32 base_to_chip(u32 base)
-{
- return ((base - 0x400) >> 3);
-}
-
-static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
-{
- struct urb *urb;
-
- if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
- return 1;
-
- urb = qtd->urb;
- qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list);
- return (qtd->urb != urb);
-}
-
-/* magic numbers that can affect system performance */
-#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
-#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
-#define EHCI_TUNE_RL_TT 0
-#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
-#define EHCI_TUNE_MULT_TT 1
-#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
-
-static void create_ptd_atl(struct isp1760_qh *qh,
- struct isp1760_qtd *qtd, struct ptd *ptd)
-{
- u32 maxpacket;
- u32 multi;
- u32 rl = RL_COUNTER;
- u32 nak = NAK_COUNTER;
-
- memset(ptd, 0, sizeof(*ptd));
-
- /* according to 3.6.2, max packet len can not be > 0x400 */
- maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe,
- usb_pipeout(qtd->urb->pipe));
- multi = 1 + ((maxpacket >> 11) & 0x3);
- maxpacket &= 0x7ff;
-
- /* DW0 */
- ptd->dw0 = DW0_VALID_BIT;
- ptd->dw0 |= TO_DW0_LENGTH(qtd->length);
- ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket);
- ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
-
- /* DW1 */
- ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
- ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
- ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
-
- if (usb_pipebulk(qtd->urb->pipe))
- ptd->dw1 |= DW1_TRANS_BULK;
- else if (usb_pipeint(qtd->urb->pipe))
- ptd->dw1 |= DW1_TRANS_INT;
-
- if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
- /* split transaction */
-
- ptd->dw1 |= DW1_TRANS_SPLIT;
- if (qtd->urb->dev->speed == USB_SPEED_LOW)
- ptd->dw1 |= DW1_SE_USB_LOSPEED;
-
- ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport);
- ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
-
- /* SE bit for Split INT transfers */
- if (usb_pipeint(qtd->urb->pipe) &&
- (qtd->urb->dev->speed == USB_SPEED_LOW))
- ptd->dw1 |= 2 << 16;
-
- rl = 0;
- nak = 0;
- } else {
- ptd->dw0 |= TO_DW0_MULTI(multi);
- if (usb_pipecontrol(qtd->urb->pipe) ||
- usb_pipebulk(qtd->urb->pipe))
- ptd->dw3 |= TO_DW3_PING(qh->ping);
- }
- /* DW2 */
- ptd->dw2 = 0;
- ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
- ptd->dw2 |= TO_DW2_RL(rl);
-
- /* DW3 */
- ptd->dw3 |= TO_DW3_NAKCOUNT(nak);
- ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);
- if (usb_pipecontrol(qtd->urb->pipe)) {
- if (qtd->data_buffer == qtd->urb->setup_packet)
- ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);
- else if (last_qtd_of_urb(qtd, qh))
- ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);
- }
-
- ptd->dw3 |= DW3_ACTIVE_BIT;
- /* Cerr */
- ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);
-}
-
-static void transform_add_int(struct isp1760_qh *qh,
- struct isp1760_qtd *qtd, struct ptd *ptd)
-{
- u32 usof;
- u32 period;
-
- /*
- * Most of this is guessing. ISP1761 datasheet is quite unclear, and
- * the algorithm from the original Philips driver code, which was
- * pretty much used in this driver before as well, is quite horrendous
- * and, i believe, incorrect. The code below follows the datasheet and
- * USB2.0 spec as far as I can tell, and plug/unplug seems to be much
- * more reliable this way (fingers crossed...).
- */
-
- if (qtd->urb->dev->speed == USB_SPEED_HIGH) {
- /* urb->interval is in units of microframes (1/8 ms) */
- period = qtd->urb->interval >> 3;
-
- if (qtd->urb->interval > 4)
- usof = 0x01; /* One bit set =>
- interval 1 ms * uFrame-match */
- else if (qtd->urb->interval > 2)
- usof = 0x22; /* Two bits set => interval 1/2 ms */
- else if (qtd->urb->interval > 1)
- usof = 0x55; /* Four bits set => interval 1/4 ms */
- else
- usof = 0xff; /* All bits set => interval 1/8 ms */
- } else {
- /* urb->interval is in units of frames (1 ms) */
- period = qtd->urb->interval;
- usof = 0x0f; /* Execute Start Split on any of the
- four first uFrames */
-
- /*
- * First 8 bits in dw5 is uSCS and "specifies which uSOF the
- * complete split needs to be sent. Valid only for IN." Also,
- * "All bits can be set to one for every transfer." (p 82,
- * ISP1761 data sheet.) 0x1c is from Philips driver. Where did
- * that number come from? 0xff seems to work fine...
- */
- /* ptd->dw5 = 0x1c; */
- ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
- }
-
- period = period >> 1;/* Ensure equal or shorter period than requested */
- period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
-
- ptd->dw2 |= period;
- ptd->dw4 = usof;
-}
-
-static void create_ptd_int(struct isp1760_qh *qh,
- struct isp1760_qtd *qtd, struct ptd *ptd)
-{
- create_ptd_atl(qh, qtd, ptd);
- transform_add_int(qh, qtd, ptd);
-}
-
-static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
-__releases(priv->lock)
-__acquires(priv->lock)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
-
- if (!urb->unlinked) {
- if (urb->status == -EINPROGRESS)
- urb->status = 0;
- }
-
- if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
- void *ptr;
- for (ptr = urb->transfer_buffer;
- ptr < urb->transfer_buffer + urb->transfer_buffer_length;
- ptr += PAGE_SIZE)
- flush_dcache_page(virt_to_page(ptr));
- }
-
- /* complete() can reenter this HCD */
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- spin_unlock(&priv->lock);
- usb_hcd_giveback_urb(hcd, urb, urb->status);
- spin_lock(&priv->lock);
-}
-
-static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
- u8 packet_type)
-{
- struct isp1760_qtd *qtd;
-
- qtd = kmem_cache_zalloc(qtd_cachep, flags);
- if (!qtd)
- return NULL;
-
- INIT_LIST_HEAD(&qtd->qtd_list);
- qtd->urb = urb;
- qtd->packet_type = packet_type;
- qtd->status = QTD_ENQUEUED;
- qtd->actual_length = 0;
-
- return qtd;
-}
-
-static void qtd_free(struct isp1760_qtd *qtd)
-{
- WARN_ON(qtd->payload_addr);
- kmem_cache_free(qtd_cachep, qtd);
-}
-
-static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
- struct slotinfo *slots, struct isp1760_qtd *qtd,
- struct isp1760_qh *qh, struct ptd *ptd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int skip_map;
-
- WARN_ON((slot < 0) || (slot > 31));
- WARN_ON(qtd->length && !qtd->payload_addr);
- WARN_ON(slots[slot].qtd);
- WARN_ON(slots[slot].qh);
- WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
-
- /* Make sure done map has not triggered from some unlinked transfer */
- if (ptd_offset == ATL_PTD_OFFSET) {
- priv->atl_done_map |= reg_read32(hcd->regs,
- HC_ATL_PTD_DONEMAP_REG);
- priv->atl_done_map &= ~(1 << slot);
- } else {
- priv->int_done_map |= reg_read32(hcd->regs,
- HC_INT_PTD_DONEMAP_REG);
- priv->int_done_map &= ~(1 << slot);
- }
-
- qh->slot = slot;
- qtd->status = QTD_XFER_STARTED;
- slots[slot].timestamp = jiffies;
- slots[slot].qtd = qtd;
- slots[slot].qh = qh;
- ptd_write(hcd->regs, ptd_offset, slot, ptd);
-
- if (ptd_offset == ATL_PTD_OFFSET) {
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
- skip_map &= ~(1 << qh->slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
- } else {
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
- skip_map &= ~(1 << qh->slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
- }
-}
-
-static int is_short_bulk(struct isp1760_qtd *qtd)
-{
- return (usb_pipebulk(qtd->urb->pipe) &&
- (qtd->actual_length < qtd->length));
-}
-
-static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
- struct list_head *urb_list)
-{
- int last_qtd;
- struct isp1760_qtd *qtd, *qtd_next;
- struct urb_listitem *urb_listitem;
-
- list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
- if (qtd->status < QTD_XFER_COMPLETE)
- break;
-
- last_qtd = last_qtd_of_urb(qtd, qh);
-
- if ((!last_qtd) && (qtd->status == QTD_RETIRE))
- qtd_next->status = QTD_RETIRE;
-
- if (qtd->status == QTD_XFER_COMPLETE) {
- if (qtd->actual_length) {
- switch (qtd->packet_type) {
- case IN_PID:
- mem_reads8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer,
- qtd->actual_length);
- /* Fall through (?) */
- case OUT_PID:
- qtd->urb->actual_length +=
- qtd->actual_length;
- /* Fall through ... */
- case SETUP_PID:
- break;
- }
- }
-
- if (is_short_bulk(qtd)) {
- if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
- qtd->urb->status = -EREMOTEIO;
- if (!last_qtd)
- qtd_next->status = QTD_RETIRE;
- }
- }
-
- if (qtd->payload_addr)
- free_mem(hcd, qtd);
-
- if (last_qtd) {
- if ((qtd->status == QTD_RETIRE) &&
- (qtd->urb->status == -EINPROGRESS))
- qtd->urb->status = -EPIPE;
- /* Defer calling of urb_done() since it releases lock */
- urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
- GFP_ATOMIC);
- if (unlikely(!urb_listitem))
- break; /* Try again on next call */
- urb_listitem->urb = qtd->urb;
- list_add_tail(&urb_listitem->urb_list, urb_list);
- }
-
- list_del(&qtd->qtd_list);
- qtd_free(qtd);
- }
-}
-
-#define ENQUEUE_DEPTH 2
-static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int ptd_offset;
- struct slotinfo *slots;
- int curr_slot, free_slot;
- int n;
- struct ptd ptd;
- struct isp1760_qtd *qtd;
-
- if (unlikely(list_empty(&qh->qtd_list))) {
- WARN_ON(1);
- return;
- }
-
- /* Make sure this endpoint's TT buffer is clean before queueing ptds */
- if (qh->tt_buffer_dirty)
- return;
-
- if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
- qtd_list)->urb->pipe)) {
- ptd_offset = INT_PTD_OFFSET;
- slots = priv->int_slots;
- } else {
- ptd_offset = ATL_PTD_OFFSET;
- slots = priv->atl_slots;
- }
-
- free_slot = -1;
- for (curr_slot = 0; curr_slot < 32; curr_slot++) {
- if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
- free_slot = curr_slot;
- if (slots[curr_slot].qh == qh)
- break;
- }
-
- n = 0;
- list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
- if (qtd->status == QTD_ENQUEUED) {
- WARN_ON(qtd->payload_addr);
- alloc_mem(hcd, qtd);
- if ((qtd->length) && (!qtd->payload_addr))
- break;
-
- if ((qtd->length) &&
- ((qtd->packet_type == SETUP_PID) ||
- (qtd->packet_type == OUT_PID))) {
- mem_writes8(hcd->regs, qtd->payload_addr,
- qtd->data_buffer, qtd->length);
- }
-
- qtd->status = QTD_PAYLOAD_ALLOC;
- }
-
- if (qtd->status == QTD_PAYLOAD_ALLOC) {
-/*
- if ((curr_slot > 31) && (free_slot == -1))
- dev_dbg(hcd->self.controller, "%s: No slot "
- "available for transfer\n", __func__);
-*/
- /* Start xfer for this endpoint if not already done */
- if ((curr_slot > 31) && (free_slot > -1)) {
- if (usb_pipeint(qtd->urb->pipe))
- create_ptd_int(qh, qtd, &ptd);
- else
- create_ptd_atl(qh, qtd, &ptd);
-
- start_bus_transfer(hcd, ptd_offset, free_slot,
- slots, qtd, qh, &ptd);
- curr_slot = free_slot;
- }
-
- n++;
- if (n >= ENQUEUE_DEPTH)
- break;
- }
- }
-}
-
-static void schedule_ptds(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv;
- struct isp1760_qh *qh, *qh_next;
- struct list_head *ep_queue;
- LIST_HEAD(urb_list);
- struct urb_listitem *urb_listitem, *urb_listitem_next;
- int i;
-
- if (!hcd) {
- WARN_ON(1);
- return;
- }
-
- priv = hcd_to_priv(hcd);
-
- /*
- * check finished/retired xfers, transfer payloads, call urb_done()
- */
- for (i = 0; i < QH_END; i++) {
- ep_queue = &priv->qh_list[i];
- list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
- collect_qtds(hcd, qh, &urb_list);
- if (list_empty(&qh->qtd_list))
- list_del(&qh->qh_list);
- }
- }
-
- list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
- urb_list) {
- isp1760_urb_done(hcd, urb_listitem->urb);
- kmem_cache_free(urb_listitem_cachep, urb_listitem);
- }
-
- /*
- * Schedule packets for transfer.
- *
- * According to USB2.0 specification:
- *
- * 1st prio: interrupt xfers, up to 80 % of bandwidth
- * 2nd prio: control xfers
- * 3rd prio: bulk xfers
- *
- * ... but let's use a simpler scheme here (mostly because ISP1761 doc
- * is very unclear on how to prioritize traffic):
- *
- * 1) Enqueue any queued control transfers, as long as payload chip mem
- * and PTD ATL slots are available.
- * 2) Enqueue any queued INT transfers, as long as payload chip mem
- * and PTD INT slots are available.
- * 3) Enqueue any queued bulk transfers, as long as payload chip mem
- * and PTD ATL slots are available.
- *
- * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between
- * conservation of chip mem and performance.
- *
- * I'm sure this scheme could be improved upon!
- */
- for (i = 0; i < QH_END; i++) {
- ep_queue = &priv->qh_list[i];
- list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
- enqueue_qtds(hcd, qh);
- }
-}
-
-#define PTD_STATE_QTD_DONE 1
-#define PTD_STATE_QTD_RELOAD 2
-#define PTD_STATE_URB_RETIRE 3
-
-static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
- struct urb *urb)
-{
- __dw dw4;
- int i;
-
- dw4 = ptd->dw4;
- dw4 >>= 8;
-
- /* FIXME: ISP1761 datasheet does not say what to do with these. Do we
- need to handle these errors? Is it done in hardware? */
-
- if (ptd->dw3 & DW3_HALT_BIT) {
-
- urb->status = -EPROTO; /* Default unknown error */
-
- for (i = 0; i < 8; i++) {
- switch (dw4 & 0x7) {
- case INT_UNDERRUN:
- dev_dbg(hcd->self.controller, "%s: underrun "
- "during uFrame %d\n",
- __func__, i);
- urb->status = -ECOMM; /* Could not write data */
- break;
- case INT_EXACT:
- dev_dbg(hcd->self.controller, "%s: transaction "
- "error during uFrame %d\n",
- __func__, i);
- urb->status = -EPROTO; /* timeout, bad CRC, PID
- error etc. */
- break;
- case INT_BABBLE:
- dev_dbg(hcd->self.controller, "%s: babble "
- "error during uFrame %d\n",
- __func__, i);
- urb->status = -EOVERFLOW;
- break;
- }
- dw4 >>= 3;
- }
-
- return PTD_STATE_URB_RETIRE;
- }
-
- return PTD_STATE_QTD_DONE;
-}
-
-static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
- struct urb *urb)
-{
- WARN_ON(!ptd);
- if (ptd->dw3 & DW3_HALT_BIT) {
- if (ptd->dw3 & DW3_BABBLE_BIT)
- urb->status = -EOVERFLOW;
- else if (FROM_DW3_CERR(ptd->dw3))
- urb->status = -EPIPE; /* Stall */
- else if (ptd->dw3 & DW3_ERROR_BIT)
- urb->status = -EPROTO; /* XactErr */
- else
- urb->status = -EPROTO; /* Unknown */
-/*
- dev_dbg(hcd->self.controller, "%s: ptd error:\n"
- " dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n"
- " dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n",
- __func__,
- ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3,
- ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7);
-*/
- return PTD_STATE_URB_RETIRE;
- }
-
- if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
- /* Transfer Error, *but* active and no HALT -> reload */
- dev_dbg(hcd->self.controller, "PID error; reloading ptd\n");
- return PTD_STATE_QTD_RELOAD;
- }
-
- if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
- /*
- * NAKs are handled in HW by the chip. Usually if the
- * device is not able to send data fast enough.
- * This happens mostly on slower hardware.
- */
- return PTD_STATE_QTD_RELOAD;
- }
-
- return PTD_STATE_QTD_DONE;
-}
-
-static void handle_done_ptds(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct ptd ptd;
- struct isp1760_qh *qh;
- int slot;
- int state;
- struct slotinfo *slots;
- u32 ptd_offset;
- struct isp1760_qtd *qtd;
- int modified;
- int skip_map;
-
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
- priv->int_done_map &= ~skip_map;
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
- priv->atl_done_map &= ~skip_map;
-
- modified = priv->int_done_map || priv->atl_done_map;
-
- while (priv->int_done_map || priv->atl_done_map) {
- if (priv->int_done_map) {
- /* INT ptd */
- slot = __ffs(priv->int_done_map);
- priv->int_done_map &= ~(1 << slot);
- slots = priv->int_slots;
- /* This should not trigger, and could be removed if
- noone have any problems with it triggering: */
- if (!slots[slot].qh) {
- WARN_ON(1);
- continue;
- }
- ptd_offset = INT_PTD_OFFSET;
- ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
- state = check_int_transfer(hcd, &ptd,
- slots[slot].qtd->urb);
- } else {
- /* ATL ptd */
- slot = __ffs(priv->atl_done_map);
- priv->atl_done_map &= ~(1 << slot);
- slots = priv->atl_slots;
- /* This should not trigger, and could be removed if
- noone have any problems with it triggering: */
- if (!slots[slot].qh) {
- WARN_ON(1);
- continue;
- }
- ptd_offset = ATL_PTD_OFFSET;
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
- state = check_atl_transfer(hcd, &ptd,
- slots[slot].qtd->urb);
- }
-
- qtd = slots[slot].qtd;
- slots[slot].qtd = NULL;
- qh = slots[slot].qh;
- slots[slot].qh = NULL;
- qh->slot = -1;
-
- WARN_ON(qtd->status != QTD_XFER_STARTED);
-
- switch (state) {
- case PTD_STATE_QTD_DONE:
- if ((usb_pipeint(qtd->urb->pipe)) &&
- (qtd->urb->dev->speed != USB_SPEED_HIGH))
- qtd->actual_length =
- FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3);
- else
- qtd->actual_length =
- FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3);
-
- qtd->status = QTD_XFER_COMPLETE;
- if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
- is_short_bulk(qtd))
- qtd = NULL;
- else
- qtd = list_entry(qtd->qtd_list.next,
- typeof(*qtd), qtd_list);
-
- qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
- qh->ping = FROM_DW3_PING(ptd.dw3);
- break;
-
- case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */
- qtd->status = QTD_PAYLOAD_ALLOC;
- ptd.dw0 |= DW0_VALID_BIT;
- /* RL counter = ERR counter */
- ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf);
- ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2));
- ptd.dw3 &= ~TO_DW3_CERR(3);
- ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER);
- qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
- qh->ping = FROM_DW3_PING(ptd.dw3);
- break;
-
- case PTD_STATE_URB_RETIRE:
- qtd->status = QTD_RETIRE;
- if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
- (qtd->urb->status != -EPIPE) &&
- (qtd->urb->status != -EREMOTEIO)) {
- qh->tt_buffer_dirty = 1;
- if (usb_hub_clear_tt_buffer(qtd->urb))
- /* Clear failed; let's hope things work
- anyway */
- qh->tt_buffer_dirty = 0;
- }
- qtd = NULL;
- qh->toggle = 0;
- qh->ping = 0;
- break;
-
- default:
- WARN_ON(1);
- continue;
- }
-
- if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) {
- if (slots == priv->int_slots) {
- if (state == PTD_STATE_QTD_RELOAD)
- dev_err(hcd->self.controller,
- "%s: PTD_STATE_QTD_RELOAD on "
- "interrupt packet\n", __func__);
- if (state != PTD_STATE_QTD_RELOAD)
- create_ptd_int(qh, qtd, &ptd);
- } else {
- if (state != PTD_STATE_QTD_RELOAD)
- create_ptd_atl(qh, qtd, &ptd);
- }
-
- start_bus_transfer(hcd, ptd_offset, slot, slots, qtd,
- qh, &ptd);
- }
- }
-
- if (modified)
- schedule_ptds(hcd);
-}
-
-static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 imask;
- irqreturn_t irqret = IRQ_NONE;
-
- spin_lock(&priv->lock);
-
- if (!(hcd->state & HC_STATE_RUNNING))
- goto leave;
-
- imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
- if (unlikely(!imask))
- goto leave;
- reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
-
- priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
- priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
-
- handle_done_ptds(hcd);
-
- irqret = IRQ_HANDLED;
-leave:
- spin_unlock(&priv->lock);
-
- return irqret;
-}
-
-/*
- * Workaround for problem described in chip errata 2:
- *
- * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
- * One solution suggested in the errata is to use SOF interrupts _instead_of_
- * ATL done interrupts (the "instead of" might be important since it seems
- * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
- * to set the PTD's done bit in addition to not generating an interrupt!).
- *
- * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
- * done bit is not being set. This is bad - it blocks the endpoint until reboot.
- *
- * If we use SOF interrupts only, we get latency between ptd completion and the
- * actual handling. This is very noticeable in testusb runs which takes several
- * minutes longer without ATL interrupts.
- *
- * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
- * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
- * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
- * completed and its done map bit is set.
- *
- * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
- * not to cause too much lag when this HW bug occurs, while still hopefully
- * ensuring that the check does not falsely trigger.
- */
-#define SLOT_TIMEOUT 300
-#define SLOT_CHECK_PERIOD 200
-static struct timer_list errata2_timer;
-
-static void errata2_function(unsigned long data)
-{
- struct usb_hcd *hcd = (struct usb_hcd *) data;
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int slot;
- struct ptd ptd;
- unsigned long spinflags;
-
- spin_lock_irqsave(&priv->lock, spinflags);
-
- for (slot = 0; slot < 32; slot++)
- if (priv->atl_slots[slot].qh && time_after(jiffies,
- priv->atl_slots[slot].timestamp +
- SLOT_TIMEOUT * HZ / 1000)) {
- ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
- if (!FROM_DW0_VALID(ptd.dw0) &&
- !FROM_DW3_ACTIVE(ptd.dw3))
- priv->atl_done_map |= 1 << slot;
- }
-
- if (priv->atl_done_map)
- handle_done_ptds(hcd);
-
- spin_unlock_irqrestore(&priv->lock, spinflags);
-
- errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
- add_timer(&errata2_timer);
-}
-
-static int isp1760_run(struct usb_hcd *hcd)
-{
- int retval;
- u32 temp;
- u32 command;
- u32 chipid;
-
- hcd->uses_new_polling = 1;
-
- hcd->state = HC_STATE_RUNNING;
-
- /* Set PTD interrupt AND & OR maps */
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
- reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
- /* step 23 passed */
-
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
-
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~(CMD_LRESET|CMD_RESET);
- command |= CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
-
- retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
- if (retval)
- return retval;
-
- /*
- * XXX
- * Spec says to write FLAG_CF as last config action, priv code grabs
- * the semaphore while doing so.
- */
- down_write(&ehci_cf_port_reset_rwsem);
- reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
-
- retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
- up_write(&ehci_cf_port_reset_rwsem);
- if (retval)
- return retval;
-
- init_timer(&errata2_timer);
- errata2_timer.function = errata2_function;
- errata2_timer.data = (unsigned long) hcd;
- errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
- add_timer(&errata2_timer);
-
- chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
- dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
- chipid & 0xffff, chipid >> 16);
-
- /* PTD Register Init Part 2, Step 28 */
-
- /* Setup registers controlling PTD checking */
- reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
- reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
- reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
- ATL_BUF_FILL | INT_BUF_FILL);
-
- /* GRR this is run-once init(), being done every time the HC starts.
- * So long as they're part of class devices, we can't do it init()
- * since the class device isn't created that early.
- */
- return 0;
-}
-
-static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
-{
- qtd->data_buffer = databuffer;
-
- if (len > MAX_PAYLOAD_SIZE)
- len = MAX_PAYLOAD_SIZE;
- qtd->length = len;
-
- return qtd->length;
-}
-
-static void qtd_list_free(struct list_head *qtd_list)
-{
- struct isp1760_qtd *qtd, *qtd_next;
-
- list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
- list_del(&qtd->qtd_list);
- qtd_free(qtd);
- }
-}
-
-/*
- * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
- * Also calculate the PID type (SETUP/IN/OUT) for each packet.
- */
-#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
-static void packetize_urb(struct usb_hcd *hcd,
- struct urb *urb, struct list_head *head, gfp_t flags)
-{
- struct isp1760_qtd *qtd;
- void *buf;
- int len, maxpacketsize;
- u8 packet_type;
-
- /*
- * URBs map to sequences of QTDs: one logical transaction
- */
-
- if (!urb->transfer_buffer && urb->transfer_buffer_length) {
- /* XXX This looks like usb storage / SCSI bug */
- dev_err(hcd->self.controller,
- "buf is null, dma is %08lx len is %d\n",
- (long unsigned)urb->transfer_dma,
- urb->transfer_buffer_length);
- WARN_ON(1);
- }
-
- if (usb_pipein(urb->pipe))
- packet_type = IN_PID;
- else
- packet_type = OUT_PID;
-
- if (usb_pipecontrol(urb->pipe)) {
- qtd = qtd_alloc(flags, urb, SETUP_PID);
- if (!qtd)
- goto cleanup;
- qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
- list_add_tail(&qtd->qtd_list, head);
-
- /* for zero length DATA stages, STATUS is always IN */
- if (urb->transfer_buffer_length == 0)
- packet_type = IN_PID;
- }
-
- maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe,
- usb_pipeout(urb->pipe)));
-
- /*
- * buffer gets wrapped in one or more qtds;
- * last one may be "short" (including zero len)
- * and may serve as a control status ack
- */
- buf = urb->transfer_buffer;
- len = urb->transfer_buffer_length;
-
- for (;;) {
- int this_qtd_len;
-
- qtd = qtd_alloc(flags, urb, packet_type);
- if (!qtd)
- goto cleanup;
- this_qtd_len = qtd_fill(qtd, buf, len);
- list_add_tail(&qtd->qtd_list, head);
-
- len -= this_qtd_len;
- buf += this_qtd_len;
-
- if (len <= 0)
- break;
- }
-
- /*
- * control requests may need a terminating data "status" ack;
- * bulk ones may need a terminating short packet (zero length).
- */
- if (urb->transfer_buffer_length != 0) {
- int one_more = 0;
-
- if (usb_pipecontrol(urb->pipe)) {
- one_more = 1;
- if (packet_type == IN_PID)
- packet_type = OUT_PID;
- else
- packet_type = IN_PID;
- } else if (usb_pipebulk(urb->pipe)
- && (urb->transfer_flags & URB_ZERO_PACKET)
- && !(urb->transfer_buffer_length %
- maxpacketsize)) {
- one_more = 1;
- }
- if (one_more) {
- qtd = qtd_alloc(flags, urb, packet_type);
- if (!qtd)
- goto cleanup;
-
- /* never any data in such packets */
- qtd_fill(qtd, NULL, 0);
- list_add_tail(&qtd->qtd_list, head);
- }
- }
-
- return;
-
-cleanup:
- qtd_list_free(head);
-}
-
-static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
- gfp_t mem_flags)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct list_head *ep_queue;
- struct isp1760_qh *qh, *qhit;
- unsigned long spinflags;
- LIST_HEAD(new_qtds);
- int retval;
- int qh_in_queue;
-
- switch (usb_pipetype(urb->pipe)) {
- case PIPE_CONTROL:
- ep_queue = &priv->qh_list[QH_CONTROL];
- break;
- case PIPE_BULK:
- ep_queue = &priv->qh_list[QH_BULK];
- break;
- case PIPE_INTERRUPT:
- if (urb->interval < 0)
- return -EINVAL;
- /* FIXME: Check bandwidth */
- ep_queue = &priv->qh_list[QH_INTERRUPT];
- break;
- case PIPE_ISOCHRONOUS:
- dev_err(hcd->self.controller, "%s: isochronous USB packets "
- "not yet supported\n",
- __func__);
- return -EPIPE;
- default:
- dev_err(hcd->self.controller, "%s: unknown pipe type\n",
- __func__);
- return -EPIPE;
- }
-
- if (usb_pipein(urb->pipe))
- urb->actual_length = 0;
-
- packetize_urb(hcd, urb, &new_qtds, mem_flags);
- if (list_empty(&new_qtds))
- return -ENOMEM;
-
- retval = 0;
- spin_lock_irqsave(&priv->lock, spinflags);
-
- if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
- retval = -ESHUTDOWN;
- qtd_list_free(&new_qtds);
- goto out;
- }
- retval = usb_hcd_link_urb_to_ep(hcd, urb);
- if (retval) {
- qtd_list_free(&new_qtds);
- goto out;
- }
-
- qh = urb->ep->hcpriv;
- if (qh) {
- qh_in_queue = 0;
- list_for_each_entry(qhit, ep_queue, qh_list) {
- if (qhit == qh) {
- qh_in_queue = 1;
- break;
- }
- }
- if (!qh_in_queue)
- list_add_tail(&qh->qh_list, ep_queue);
- } else {
- qh = qh_alloc(GFP_ATOMIC);
- if (!qh) {
- retval = -ENOMEM;
- usb_hcd_unlink_urb_from_ep(hcd, urb);
- qtd_list_free(&new_qtds);
- goto out;
- }
- list_add_tail(&qh->qh_list, ep_queue);
- urb->ep->hcpriv = qh;
- }
-
- list_splice_tail(&new_qtds, &qh->qtd_list);
- schedule_ptds(hcd);
-
-out:
- spin_unlock_irqrestore(&priv->lock, spinflags);
- return retval;
-}
-
-static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
- struct isp1760_qh *qh)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int skip_map;
-
- WARN_ON(qh->slot == -1);
-
- /* We need to forcefully reclaim the slot since some transfers never
- return, e.g. interrupt transfers and NAKed bulk transfers. */
- if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
- skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
- skip_map |= (1 << qh->slot);
- reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
- priv->atl_slots[qh->slot].qh = NULL;
- priv->atl_slots[qh->slot].qtd = NULL;
- } else {
- skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
- skip_map |= (1 << qh->slot);
- reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
- priv->int_slots[qh->slot].qh = NULL;
- priv->int_slots[qh->slot].qtd = NULL;
- }
-
- qh->slot = -1;
-}
-
-/*
- * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
- * any active transfer belonging to the urb in the process.
- */
-static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
- struct isp1760_qtd *qtd)
-{
- struct urb *urb;
- int urb_was_running;
-
- urb = qtd->urb;
- urb_was_running = 0;
- list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
- if (qtd->urb != urb)
- break;
-
- if (qtd->status >= QTD_XFER_STARTED)
- urb_was_running = 1;
- if (last_qtd_of_urb(qtd, qh) &&
- (qtd->status >= QTD_XFER_COMPLETE))
- urb_was_running = 0;
-
- if (qtd->status == QTD_XFER_STARTED)
- kill_transfer(hcd, urb, qh);
- qtd->status = QTD_RETIRE;
- }
-
- if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
- qh->tt_buffer_dirty = 1;
- if (usb_hub_clear_tt_buffer(urb))
- /* Clear failed; let's hope things work anyway */
- qh->tt_buffer_dirty = 0;
- }
-}
-
-static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
- int status)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- unsigned long spinflags;
- struct isp1760_qh *qh;
- struct isp1760_qtd *qtd;
- int retval = 0;
-
- spin_lock_irqsave(&priv->lock, spinflags);
- retval = usb_hcd_check_unlink_urb(hcd, urb, status);
- if (retval)
- goto out;
-
- qh = urb->ep->hcpriv;
- if (!qh) {
- retval = -EINVAL;
- goto out;
- }
-
- list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
- if (qtd->urb == urb) {
- dequeue_urb_from_qtd(hcd, qh, qtd);
- list_move(&qtd->qtd_list, &qh->qtd_list);
- break;
- }
-
- urb->status = status;
- schedule_ptds(hcd);
-
-out:
- spin_unlock_irqrestore(&priv->lock, spinflags);
- return retval;
-}
-
-static void isp1760_endpoint_disable(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- unsigned long spinflags;
- struct isp1760_qh *qh, *qh_iter;
- int i;
-
- spin_lock_irqsave(&priv->lock, spinflags);
-
- qh = ep->hcpriv;
- if (!qh)
- goto out;
-
- WARN_ON(!list_empty(&qh->qtd_list));
-
- for (i = 0; i < QH_END; i++)
- list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
- if (qh_iter == qh) {
- list_del(&qh_iter->qh_list);
- i = QH_END;
- break;
- }
- qh_free(qh);
- ep->hcpriv = NULL;
-
- schedule_ptds(hcd);
-
-out:
- spin_unlock_irqrestore(&priv->lock, spinflags);
-}
-
-static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 temp, status = 0;
- u32 mask;
- int retval = 1;
- unsigned long flags;
-
- /* if !PM, root hub timers won't get shut down ... */
- if (!HC_IS_RUNNING(hcd->state))
- return 0;
-
- /* init status to no-changes */
- buf[0] = 0;
- mask = PORT_CSC;
-
- spin_lock_irqsave(&priv->lock, flags);
- temp = reg_read32(hcd->regs, HC_PORTSC1);
-
- if (temp & PORT_OWNER) {
- if (temp & PORT_CSC) {
- temp &= ~PORT_CSC;
- reg_write32(hcd->regs, HC_PORTSC1, temp);
- goto done;
- }
- }
-
- /*
- * Return status information even for ports with OWNER set.
- * Otherwise hub_wq wouldn't see the disconnect event when a
- * high-speed device is switched over to the companion
- * controller by the user.
- */
-
- if ((temp & mask) != 0
- || ((temp & PORT_RESUME) != 0
- && time_after_eq(jiffies,
- priv->reset_done))) {
- buf [0] |= 1 << (0 + 1);
- status = STS_PCD;
- }
- /* FIXME autosuspend idle root hubs */
-done:
- spin_unlock_irqrestore(&priv->lock, flags);
- return status ? retval : 0;
-}
-
-static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
- struct usb_hub_descriptor *desc)
-{
- int ports = HCS_N_PORTS(priv->hcs_params);
- u16 temp;
-
- desc->bDescriptorType = 0x29;
- /* priv 1.0, 2.3.9 says 20ms max */
- desc->bPwrOn2PwrGood = 10;
- desc->bHubContrCurrent = 0;
-
- desc->bNbrPorts = ports;
- temp = 1 + (ports / 8);
- desc->bDescLength = 7 + 2 * temp;
-
- /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
- memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
- memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
-
- /* per-port overcurrent reporting */
- temp = 0x0008;
- if (HCS_PPC(priv->hcs_params))
- /* per-port power control */
- temp |= 0x0001;
- else
- /* no power switching */
- temp |= 0x0002;
- desc->wHubCharacteristics = cpu_to_le16(temp);
-}
-
-#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
-
-static int check_reset_complete(struct usb_hcd *hcd, int index,
- int port_status)
-{
- if (!(port_status & PORT_CONNECT))
- return port_status;
-
- /* if reset finished and it's still not enabled -- handoff */
- if (!(port_status & PORT_PE)) {
-
- dev_info(hcd->self.controller,
- "port %d full speed --> companion\n",
- index + 1);
-
- port_status |= PORT_OWNER;
- port_status &= ~PORT_RWC_BITS;
- reg_write32(hcd->regs, HC_PORTSC1, port_status);
-
- } else
- dev_info(hcd->self.controller, "port %d high speed\n",
- index + 1);
-
- return port_status;
-}
-
-static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
- u16 wValue, u16 wIndex, char *buf, u16 wLength)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- int ports = HCS_N_PORTS(priv->hcs_params);
- u32 temp, status;
- unsigned long flags;
- int retval = 0;
- unsigned selector;
-
- /*
- * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
- * HCS_INDICATOR may say we can change LEDs to off/amber/green.
- * (track current state ourselves) ... blink for diagnostics,
- * power, "this is the one", etc. EHCI spec supports this.
- */
-
- spin_lock_irqsave(&priv->lock, flags);
- switch (typeReq) {
- case ClearHubFeature:
- switch (wValue) {
- case C_HUB_LOCAL_POWER:
- case C_HUB_OVER_CURRENT:
- /* no hub-wide feature/status flags */
- break;
- default:
- goto error;
- }
- break;
- case ClearPortFeature:
- if (!wIndex || wIndex > ports)
- goto error;
- wIndex--;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
-
- /*
- * Even if OWNER is set, so the port is owned by the
- * companion controller, hub_wq needs to be able to clear
- * the port-change status bits (especially
- * USB_PORT_STAT_C_CONNECTION).
- */
-
- switch (wValue) {
- case USB_PORT_FEAT_ENABLE:
- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
- break;
- case USB_PORT_FEAT_C_ENABLE:
- /* XXX error? */
- break;
- case USB_PORT_FEAT_SUSPEND:
- if (temp & PORT_RESET)
- goto error;
-
- if (temp & PORT_SUSPEND) {
- if ((temp & PORT_PE) == 0)
- goto error;
- /* resume signaling for 20 msec */
- temp &= ~(PORT_RWC_BITS);
- reg_write32(hcd->regs, HC_PORTSC1,
- temp | PORT_RESUME);
- priv->reset_done = jiffies +
- msecs_to_jiffies(20);
- }
- break;
- case USB_PORT_FEAT_C_SUSPEND:
- /* we auto-clear this feature */
- break;
- case USB_PORT_FEAT_POWER:
- if (HCS_PPC(priv->hcs_params))
- reg_write32(hcd->regs, HC_PORTSC1,
- temp & ~PORT_POWER);
- break;
- case USB_PORT_FEAT_C_CONNECTION:
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
- break;
- case USB_PORT_FEAT_C_OVER_CURRENT:
- /* XXX error ?*/
- break;
- case USB_PORT_FEAT_C_RESET:
- /* GetPortStatus clears reset */
- break;
- default:
- goto error;
- }
- reg_read32(hcd->regs, HC_USBCMD);
- break;
- case GetHubDescriptor:
- isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
- buf);
- break;
- case GetHubStatus:
- /* no hub-wide feature/status flags */
- memset(buf, 0, 4);
- break;
- case GetPortStatus:
- if (!wIndex || wIndex > ports)
- goto error;
- wIndex--;
- status = 0;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
-
- /* wPortChange bits */
- if (temp & PORT_CSC)
- status |= USB_PORT_STAT_C_CONNECTION << 16;
-
-
- /* whoever resumes must GetPortStatus to complete it!! */
- if (temp & PORT_RESUME) {
- dev_err(hcd->self.controller, "Port resume should be skipped.\n");
-
- /* Remote Wakeup received? */
- if (!priv->reset_done) {
- /* resume signaling for 20 msec */
- priv->reset_done = jiffies
- + msecs_to_jiffies(20);
- /* check the port again */
- mod_timer(&hcd->rh_timer, priv->reset_done);
- }
-
- /* resume completed? */
- else if (time_after_eq(jiffies,
- priv->reset_done)) {
- status |= USB_PORT_STAT_C_SUSPEND << 16;
- priv->reset_done = 0;
-
- /* stop resume signaling */
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- reg_write32(hcd->regs, HC_PORTSC1,
- temp & ~(PORT_RWC_BITS | PORT_RESUME));
- retval = handshake(hcd, HC_PORTSC1,
- PORT_RESUME, 0, 2000 /* 2msec */);
- if (retval != 0) {
- dev_err(hcd->self.controller,
- "port %d resume error %d\n",
- wIndex + 1, retval);
- goto error;
- }
- temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
- }
- }
-
- /* whoever resets must GetPortStatus to complete it!! */
- if ((temp & PORT_RESET)
- && time_after_eq(jiffies,
- priv->reset_done)) {
- status |= USB_PORT_STAT_C_RESET << 16;
- priv->reset_done = 0;
-
- /* force reset to complete */
- reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
- /* REVISIT: some hardware needs 550+ usec to clear
- * this bit; seems too long to spin routinely...
- */
- retval = handshake(hcd, HC_PORTSC1,
- PORT_RESET, 0, 750);
- if (retval != 0) {
- dev_err(hcd->self.controller, "port %d reset error %d\n",
- wIndex + 1, retval);
- goto error;
- }
-
- /* see what we found out */
- temp = check_reset_complete(hcd, wIndex,
- reg_read32(hcd->regs, HC_PORTSC1));
- }
- /*
- * Even if OWNER is set, there's no harm letting hub_wq
- * see the wPortStatus values (they should all be 0 except
- * for PORT_POWER anyway).
- */
-
- if (temp & PORT_OWNER)
- dev_err(hcd->self.controller, "PORT_OWNER is set\n");
-
- if (temp & PORT_CONNECT) {
- status |= USB_PORT_STAT_CONNECTION;
- /* status may be from integrated TT */
- status |= USB_PORT_STAT_HIGH_SPEED;
- }
- if (temp & PORT_PE)
- status |= USB_PORT_STAT_ENABLE;
- if (temp & (PORT_SUSPEND|PORT_RESUME))
- status |= USB_PORT_STAT_SUSPEND;
- if (temp & PORT_RESET)
- status |= USB_PORT_STAT_RESET;
- if (temp & PORT_POWER)
- status |= USB_PORT_STAT_POWER;
-
- put_unaligned(cpu_to_le32(status), (__le32 *) buf);
- break;
- case SetHubFeature:
- switch (wValue) {
- case C_HUB_LOCAL_POWER:
- case C_HUB_OVER_CURRENT:
- /* no hub-wide feature/status flags */
- break;
- default:
- goto error;
- }
- break;
- case SetPortFeature:
- selector = wIndex >> 8;
- wIndex &= 0xff;
- if (!wIndex || wIndex > ports)
- goto error;
- wIndex--;
- temp = reg_read32(hcd->regs, HC_PORTSC1);
- if (temp & PORT_OWNER)
- break;
-
-/* temp &= ~PORT_RWC_BITS; */
- switch (wValue) {
- case USB_PORT_FEAT_ENABLE:
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
- break;
-
- case USB_PORT_FEAT_SUSPEND:
- if ((temp & PORT_PE) == 0
- || (temp & PORT_RESET) != 0)
- goto error;
-
- reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
- break;
- case USB_PORT_FEAT_POWER:
- if (HCS_PPC(priv->hcs_params))
- reg_write32(hcd->regs, HC_PORTSC1,
- temp | PORT_POWER);
- break;
- case USB_PORT_FEAT_RESET:
- if (temp & PORT_RESUME)
- goto error;
- /* line status bits may report this as low speed,
- * which can be fine if this root hub has a
- * transaction translator built in.
- */
- if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
- && PORT_USB11(temp)) {
- temp |= PORT_OWNER;
- } else {
- temp |= PORT_RESET;
- temp &= ~PORT_PE;
-
- /*
- * caller must wait, then call GetPortStatus
- * usb 2.0 spec says 50 ms resets on root
- */
- priv->reset_done = jiffies +
- msecs_to_jiffies(50);
- }
- reg_write32(hcd->regs, HC_PORTSC1, temp);
- break;
- default:
- goto error;
- }
- reg_read32(hcd->regs, HC_USBCMD);
- break;
-
- default:
-error:
- /* "stall" on error */
- retval = -EPIPE;
- }
- spin_unlock_irqrestore(&priv->lock, flags);
- return retval;
-}
-
-static int isp1760_get_frame(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 fr;
-
- fr = reg_read32(hcd->regs, HC_FRINDEX);
- return (fr >> 3) % priv->periodic_size;
-}
-
-static void isp1760_stop(struct usb_hcd *hcd)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- u32 temp;
-
- del_timer(&errata2_timer);
-
- isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
- NULL, 0);
- mdelay(20);
-
- spin_lock_irq(&priv->lock);
- ehci_reset(hcd);
- /* Disable IRQ */
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
- spin_unlock_irq(&priv->lock);
-
- reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
-}
-
-static void isp1760_shutdown(struct usb_hcd *hcd)
-{
- u32 command, temp;
-
- isp1760_stop(hcd);
- temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
- reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
-
- command = reg_read32(hcd->regs, HC_USBCMD);
- command &= ~CMD_RUN;
- reg_write32(hcd->regs, HC_USBCMD, command);
-}
-
-static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
- struct usb_host_endpoint *ep)
-{
- struct isp1760_hcd *priv = hcd_to_priv(hcd);
- struct isp1760_qh *qh = ep->hcpriv;
- unsigned long spinflags;
-
- if (!qh)
- return;
-
- spin_lock_irqsave(&priv->lock, spinflags);
- qh->tt_buffer_dirty = 0;
- schedule_ptds(hcd);
- spin_unlock_irqrestore(&priv->lock, spinflags);
-}
-
-
-static const struct hc_driver isp1760_hc_driver = {
- .description = "isp1760-hcd",
- .product_desc = "NXP ISP1760 USB Host Controller",
- .hcd_priv_size = sizeof(struct isp1760_hcd),
- .irq = isp1760_irq,
- .flags = HCD_MEMORY | HCD_USB2,
- .reset = isp1760_hc_setup,
- .start = isp1760_run,
- .stop = isp1760_stop,
- .shutdown = isp1760_shutdown,
- .urb_enqueue = isp1760_urb_enqueue,
- .urb_dequeue = isp1760_urb_dequeue,
- .endpoint_disable = isp1760_endpoint_disable,
- .get_frame_number = isp1760_get_frame,
- .hub_status_data = isp1760_hub_status_data,
- .hub_control = isp1760_hub_control,
- .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
-};
-
-int __init init_kmem_once(void)
-{
- urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
- sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
- SLAB_MEM_SPREAD, NULL);
-
- if (!urb_listitem_cachep)
- return -ENOMEM;
-
- qtd_cachep = kmem_cache_create("isp1760_qtd",
- sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
- SLAB_MEM_SPREAD, NULL);
-
- if (!qtd_cachep)
- return -ENOMEM;
-
- qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
- 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
-
- if (!qh_cachep) {
- kmem_cache_destroy(qtd_cachep);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-void deinit_kmem_cache(void)
-{
- kmem_cache_destroy(qtd_cachep);
- kmem_cache_destroy(qh_cachep);
- kmem_cache_destroy(urb_listitem_cachep);
-}
-
-struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
- int irq, unsigned long irqflags,
- int rst_gpio,
- struct device *dev, const char *busname,
- unsigned int devflags)
-{
- struct usb_hcd *hcd;
- struct isp1760_hcd *priv;
- int ret;
-
- if (usb_disabled())
- return ERR_PTR(-ENODEV);
-
- /* prevent usb-core allocating DMA pages */
- dev->dma_mask = NULL;
-
- hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
- if (!hcd)
- return ERR_PTR(-ENOMEM);
-
- priv = hcd_to_priv(hcd);
- priv->devflags = devflags;
- priv->rst_gpio = rst_gpio;
- init_memory(priv);
- hcd->regs = ioremap(res_start, res_len);
- if (!hcd->regs) {
- ret = -EIO;
- goto err_put;
- }
-
- hcd->irq = irq;
- hcd->rsrc_start = res_start;
- hcd->rsrc_len = res_len;
-
- ret = usb_add_hcd(hcd, irq, irqflags);
- if (ret)
- goto err_unmap;
- device_wakeup_enable(hcd->self.controller);
-
- return hcd;
-
-err_unmap:
- iounmap(hcd->regs);
-
-err_put:
- usb_put_hcd(hcd);
-
- return ERR_PTR(ret);
-}
-
-MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
-MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
-MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/host/isp1760-hcd.h b/drivers/usb/host/isp1760-hcd.h
deleted file mode 100644
index 33dc79ccaa6b..000000000000
--- a/drivers/usb/host/isp1760-hcd.h
+++ /dev/null
@@ -1,208 +0,0 @@
-#ifndef _ISP1760_HCD_H_
-#define _ISP1760_HCD_H_
-
-/* exports for if */
-struct usb_hcd *isp1760_register(phys_addr_t res_start, resource_size_t res_len,
- int irq, unsigned long irqflags,
- int rst_gpio,
- struct device *dev, const char *busname,
- unsigned int devflags);
-int init_kmem_once(void);
-void deinit_kmem_cache(void);
-
-/* EHCI capability registers */
-#define HC_CAPLENGTH 0x00
-#define HC_HCSPARAMS 0x04
-#define HC_HCCPARAMS 0x08
-
-/* EHCI operational registers */
-#define HC_USBCMD 0x20
-#define HC_USBSTS 0x24
-#define HC_FRINDEX 0x2c
-#define HC_CONFIGFLAG 0x60
-#define HC_PORTSC1 0x64
-#define HC_ISO_PTD_DONEMAP_REG 0x130
-#define HC_ISO_PTD_SKIPMAP_REG 0x134
-#define HC_ISO_PTD_LASTPTD_REG 0x138
-#define HC_INT_PTD_DONEMAP_REG 0x140
-#define HC_INT_PTD_SKIPMAP_REG 0x144
-#define HC_INT_PTD_LASTPTD_REG 0x148
-#define HC_ATL_PTD_DONEMAP_REG 0x150
-#define HC_ATL_PTD_SKIPMAP_REG 0x154
-#define HC_ATL_PTD_LASTPTD_REG 0x158
-
-/* Configuration Register */
-#define HC_HW_MODE_CTRL 0x300
-#define ALL_ATX_RESET (1 << 31)
-#define HW_ANA_DIGI_OC (1 << 15)
-#define HW_DATA_BUS_32BIT (1 << 8)
-#define HW_DACK_POL_HIGH (1 << 6)
-#define HW_DREQ_POL_HIGH (1 << 5)
-#define HW_INTR_HIGH_ACT (1 << 2)
-#define HW_INTR_EDGE_TRIG (1 << 1)
-#define HW_GLOBAL_INTR_EN (1 << 0)
-
-#define HC_CHIP_ID_REG 0x304
-#define HC_SCRATCH_REG 0x308
-
-#define HC_RESET_REG 0x30c
-#define SW_RESET_RESET_HC (1 << 1)
-#define SW_RESET_RESET_ALL (1 << 0)
-
-#define HC_BUFFER_STATUS_REG 0x334
-#define ISO_BUF_FILL (1 << 2)
-#define INT_BUF_FILL (1 << 1)
-#define ATL_BUF_FILL (1 << 0)
-
-#define HC_MEMORY_REG 0x33c
-#define ISP_BANK(x) ((x) << 16)
-
-#define HC_PORT1_CTRL 0x374
-#define PORT1_POWER (3 << 3)
-#define PORT1_INIT1 (1 << 7)
-#define PORT1_INIT2 (1 << 23)
-#define HW_OTG_CTRL_SET 0x374
-#define HW_OTG_CTRL_CLR 0x376
-
-/* Interrupt Register */
-#define HC_INTERRUPT_REG 0x310
-
-#define HC_INTERRUPT_ENABLE 0x314
-#define HC_ISO_INT (1 << 9)
-#define HC_ATL_INT (1 << 8)
-#define HC_INTL_INT (1 << 7)
-#define HC_EOT_INT (1 << 3)
-#define HC_SOT_INT (1 << 1)
-#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
-
-#define HC_ISO_IRQ_MASK_OR_REG 0x318
-#define HC_INT_IRQ_MASK_OR_REG 0x31C
-#define HC_ATL_IRQ_MASK_OR_REG 0x320
-#define HC_ISO_IRQ_MASK_AND_REG 0x324
-#define HC_INT_IRQ_MASK_AND_REG 0x328
-#define HC_ATL_IRQ_MASK_AND_REG 0x32C
-
-/* urb state*/
-#define DELETE_URB (0x0008)
-#define NO_TRANSFER_ACTIVE (0xffffffff)
-
-/* Philips Proprietary Transfer Descriptor (PTD) */
-typedef __u32 __bitwise __dw;
-struct ptd {
- __dw dw0;
- __dw dw1;
- __dw dw2;
- __dw dw3;
- __dw dw4;
- __dw dw5;
- __dw dw6;
- __dw dw7;
-};
-#define PTD_OFFSET 0x0400
-#define ISO_PTD_OFFSET 0x0400
-#define INT_PTD_OFFSET 0x0800
-#define ATL_PTD_OFFSET 0x0c00
-#define PAYLOAD_OFFSET 0x1000
-
-struct slotinfo {
- struct isp1760_qh *qh;
- struct isp1760_qtd *qtd;
- unsigned long timestamp;
-};
-
-
-typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
- struct isp1760_qtd *qtd);
-
-/*
- * Device flags that can vary from board to board. All of these
- * indicate the most "atypical" case, so that a devflags of 0 is
- * a sane default configuration.
- */
-#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
-#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
-#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
-#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
-#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
-#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
-#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
-#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
-#define ISP1760_FLAG_RESET_ACTIVE_HIGH 0x80000000 /* RESET GPIO active high */
-
-/* chip memory management */
-struct memory_chunk {
- unsigned int start;
- unsigned int size;
- unsigned int free;
-};
-
-/*
- * 60kb divided in:
- * - 32 blocks @ 256 bytes
- * - 20 blocks @ 1024 bytes
- * - 4 blocks @ 8192 bytes
- */
-
-#define BLOCK_1_NUM 32
-#define BLOCK_2_NUM 20
-#define BLOCK_3_NUM 4
-
-#define BLOCK_1_SIZE 256
-#define BLOCK_2_SIZE 1024
-#define BLOCK_3_SIZE 8192
-#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
-#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
-#define PAYLOAD_AREA_SIZE 0xf000
-
-/* ATL */
-/* DW0 */
-#define DW0_VALID_BIT 1
-#define FROM_DW0_VALID(x) ((x) & 0x01)
-#define TO_DW0_LENGTH(x) (((u32) x) << 3)
-#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
-#define TO_DW0_MULTI(x) (((u32) x) << 29)
-#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
-/* DW1 */
-#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
-#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
-#define DW1_TRANS_BULK ((u32) 2 << 12)
-#define DW1_TRANS_INT ((u32) 3 << 12)
-#define DW1_TRANS_SPLIT ((u32) 1 << 14)
-#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
-#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
-#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
-/* DW2 */
-#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
-#define TO_DW2_RL(x) ((x) << 25)
-#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
-/* DW3 */
-#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
-#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
-#define TO_DW3_NAKCOUNT(x) ((x) << 19)
-#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
-#define TO_DW3_CERR(x) ((x) << 23)
-#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
-#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
-#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
-#define TO_DW3_PING(x) ((x) << 26)
-#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
-#define DW3_ERROR_BIT (1 << 28)
-#define DW3_BABBLE_BIT (1 << 29)
-#define DW3_HALT_BIT (1 << 30)
-#define DW3_ACTIVE_BIT (1 << 31)
-#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
-
-#define INT_UNDERRUN (1 << 2)
-#define INT_BABBLE (1 << 1)
-#define INT_EXACT (1 << 0)
-
-#define SETUP_PID (2)
-#define IN_PID (1)
-#define OUT_PID (0)
-
-/* Errata 1 */
-#define RL_COUNTER (0)
-#define NAK_COUNTER (0)
-#define ERR_COUNTER (2)
-
-#endif /* _ISP1760_HCD_H_ */
diff --git a/drivers/usb/host/isp1760-if.c b/drivers/usb/host/isp1760-if.c
deleted file mode 100644
index 09254a43bc01..000000000000
--- a/drivers/usb/host/isp1760-if.c
+++ /dev/null
@@ -1,477 +0,0 @@
-/*
- * Glue code for the ISP1760 driver and bus
- * Currently there is support for
- * - OpenFirmware
- * - PCI
- * - PDEV (generic platform device centralized driver model)
- *
- * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
- *
- */
-
-#include <linux/usb.h>
-#include <linux/io.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/usb/isp1760.h>
-#include <linux/usb/hcd.h>
-
-#include "isp1760-hcd.h"
-
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
-#include <linux/slab.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/of_gpio.h>
-#endif
-
-#ifdef CONFIG_PCI
-#include <linux/pci.h>
-#endif
-
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
-struct isp1760 {
- struct usb_hcd *hcd;
- int rst_gpio;
-};
-
-static int of_isp1760_probe(struct platform_device *dev)
-{
- struct isp1760 *drvdata;
- struct device_node *dp = dev->dev.of_node;
- struct resource *res;
- struct resource memory;
- int virq;
- resource_size_t res_len;
- int ret;
- unsigned int devflags = 0;
- enum of_gpio_flags gpio_flags;
- u32 bus_width = 0;
-
- drvdata = kzalloc(sizeof(*drvdata), GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
-
- ret = of_address_to_resource(dp, 0, &memory);
- if (ret) {
- ret = -ENXIO;
- goto free_data;
- }
-
- res_len = resource_size(&memory);
-
- res = request_mem_region(memory.start, res_len, dev_name(&dev->dev));
- if (!res) {
- ret = -EBUSY;
- goto free_data;
- }
-
- virq = irq_of_parse_and_map(dp, 0);
- if (!virq) {
- ret = -ENODEV;
- goto release_reg;
- }
-
- if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
- devflags |= ISP1760_FLAG_ISP1761;
-
- /* Some systems wire up only 16 of the 32 data lines */
- of_property_read_u32(dp, "bus-width", &bus_width);
- if (bus_width == 16)
- devflags |= ISP1760_FLAG_BUS_WIDTH_16;
-
- if (of_get_property(dp, "port1-otg", NULL) != NULL)
- devflags |= ISP1760_FLAG_OTG_EN;
-
- if (of_get_property(dp, "analog-oc", NULL) != NULL)
- devflags |= ISP1760_FLAG_ANALOG_OC;
-
- if (of_get_property(dp, "dack-polarity", NULL) != NULL)
- devflags |= ISP1760_FLAG_DACK_POL_HIGH;
-
- if (of_get_property(dp, "dreq-polarity", NULL) != NULL)
- devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
-
- drvdata->rst_gpio = of_get_gpio_flags(dp, 0, &gpio_flags);
- if (gpio_is_valid(drvdata->rst_gpio)) {
- ret = gpio_request(drvdata->rst_gpio, dev_name(&dev->dev));
- if (!ret) {
- if (!(gpio_flags & OF_GPIO_ACTIVE_LOW)) {
- devflags |= ISP1760_FLAG_RESET_ACTIVE_HIGH;
- gpio_direction_output(drvdata->rst_gpio, 0);
- } else {
- gpio_direction_output(drvdata->rst_gpio, 1);
- }
- } else {
- drvdata->rst_gpio = ret;
- }
- }
-
- drvdata->hcd = isp1760_register(memory.start, res_len, virq,
- IRQF_SHARED, drvdata->rst_gpio,
- &dev->dev, dev_name(&dev->dev),
- devflags);
- if (IS_ERR(drvdata->hcd)) {
- ret = PTR_ERR(drvdata->hcd);
- goto free_gpio;
- }
-
- platform_set_drvdata(dev, drvdata);
- return ret;
-
-free_gpio:
- if (gpio_is_valid(drvdata->rst_gpio))
- gpio_free(drvdata->rst_gpio);
-release_reg:
- release_mem_region(memory.start, res_len);
-free_data:
- kfree(drvdata);
- return ret;
-}
-
-static int of_isp1760_remove(struct platform_device *dev)
-{
- struct isp1760 *drvdata = platform_get_drvdata(dev);
-
- usb_remove_hcd(drvdata->hcd);
- iounmap(drvdata->hcd->regs);
- release_mem_region(drvdata->hcd->rsrc_start, drvdata->hcd->rsrc_len);
- usb_put_hcd(drvdata->hcd);
-
- if (gpio_is_valid(drvdata->rst_gpio))
- gpio_free(drvdata->rst_gpio);
-
- kfree(drvdata);
- return 0;
-}
-
-static const struct of_device_id of_isp1760_match[] = {
- {
- .compatible = "nxp,usb-isp1760",
- },
- {
- .compatible = "nxp,usb-isp1761",
- },
- { },
-};
-MODULE_DEVICE_TABLE(of, of_isp1760_match);
-
-static struct platform_driver isp1760_of_driver = {
- .driver = {
- .name = "nxp-isp1760",
- .of_match_table = of_isp1760_match,
- },
- .probe = of_isp1760_probe,
- .remove = of_isp1760_remove,
-};
-#endif
-
-#ifdef CONFIG_PCI
-static int isp1761_pci_probe(struct pci_dev *dev,
- const struct pci_device_id *id)
-{
- u8 latency, limit;
- __u32 reg_data;
- int retry_count;
- struct usb_hcd *hcd;
- unsigned int devflags = 0;
- int ret_status = 0;
-
- resource_size_t pci_mem_phy0;
- resource_size_t memlength;
-
- u8 __iomem *chip_addr;
- u8 __iomem *iobase;
- resource_size_t nxp_pci_io_base;
- resource_size_t iolength;
-
- if (usb_disabled())
- return -ENODEV;
-
- if (pci_enable_device(dev) < 0)
- return -ENODEV;
-
- if (!dev->irq)
- return -ENODEV;
-
- /* Grab the PLX PCI mem maped port start address we need */
- nxp_pci_io_base = pci_resource_start(dev, 0);
- iolength = pci_resource_len(dev, 0);
-
- if (!request_mem_region(nxp_pci_io_base, iolength, "ISP1761 IO MEM")) {
- printk(KERN_ERR "request region #1\n");
- return -EBUSY;
- }
-
- iobase = ioremap_nocache(nxp_pci_io_base, iolength);
- if (!iobase) {
- printk(KERN_ERR "ioremap #1\n");
- ret_status = -ENOMEM;
- goto cleanup1;
- }
- /* Grab the PLX PCI shared memory of the ISP 1761 we need */
- pci_mem_phy0 = pci_resource_start(dev, 3);
- memlength = pci_resource_len(dev, 3);
- if (memlength < 0xffff) {
- printk(KERN_ERR "memory length for this resource is wrong\n");
- ret_status = -ENOMEM;
- goto cleanup2;
- }
-
- if (!request_mem_region(pci_mem_phy0, memlength, "ISP-PCI")) {
- printk(KERN_ERR "host controller already in use\n");
- ret_status = -EBUSY;
- goto cleanup2;
- }
-
- /* map available memory */
- chip_addr = ioremap_nocache(pci_mem_phy0,memlength);
- if (!chip_addr) {
- printk(KERN_ERR "Error ioremap failed\n");
- ret_status = -ENOMEM;
- goto cleanup3;
- }
-
- /* bad pci latencies can contribute to overruns */
- pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
- if (latency) {
- pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
- if (limit && limit < latency)
- pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
- }
-
- /* Try to check whether we can access Scratch Register of
- * Host Controller or not. The initial PCI access is retried until
- * local init for the PCI bridge is completed
- */
- retry_count = 20;
- reg_data = 0;
- while ((reg_data != 0xFACE) && retry_count) {
- /*by default host is in 16bit mode, so
- * io operations at this stage must be 16 bit
- * */
- writel(0xface, chip_addr + HC_SCRATCH_REG);
- udelay(100);
- reg_data = readl(chip_addr + HC_SCRATCH_REG) & 0x0000ffff;
- retry_count--;
- }
-
- iounmap(chip_addr);
-
- /* Host Controller presence is detected by writing to scratch register
- * and reading back and checking the contents are same or not
- */
- if (reg_data != 0xFACE) {
- dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
- ret_status = -ENOMEM;
- goto cleanup3;
- }
-
- pci_set_master(dev);
-
- /* configure PLX PCI chip to pass interrupts */
-#define PLX_INT_CSR_REG 0x68
- reg_data = readl(iobase + PLX_INT_CSR_REG);
- reg_data |= 0x900;
- writel(reg_data, iobase + PLX_INT_CSR_REG);
-
- dev->dev.dma_mask = NULL;
- hcd = isp1760_register(pci_mem_phy0, memlength, dev->irq,
- IRQF_SHARED, -ENOENT, &dev->dev, dev_name(&dev->dev),
- devflags);
- if (IS_ERR(hcd)) {
- ret_status = -ENODEV;
- goto cleanup3;
- }
-
- /* done with PLX IO access */
- iounmap(iobase);
- release_mem_region(nxp_pci_io_base, iolength);
-
- pci_set_drvdata(dev, hcd);
- return 0;
-
-cleanup3:
- release_mem_region(pci_mem_phy0, memlength);
-cleanup2:
- iounmap(iobase);
-cleanup1:
- release_mem_region(nxp_pci_io_base, iolength);
- return ret_status;
-}
-
-static void isp1761_pci_remove(struct pci_dev *dev)
-{
- struct usb_hcd *hcd;
-
- hcd = pci_get_drvdata(dev);
-
- usb_remove_hcd(hcd);
- iounmap(hcd->regs);
- release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
- usb_put_hcd(hcd);
-
- pci_disable_device(dev);
-}
-
-static void isp1761_pci_shutdown(struct pci_dev *dev)
-{
- printk(KERN_ERR "ips1761_pci_shutdown\n");
-}
-
-static const struct pci_device_id isp1760_plx [] = {
- {
- .class = PCI_CLASS_BRIDGE_OTHER << 8,
- .class_mask = ~0,
- .vendor = PCI_VENDOR_ID_PLX,
- .device = 0x5406,
- .subvendor = PCI_VENDOR_ID_PLX,
- .subdevice = 0x9054,
- },
- { }
-};
-MODULE_DEVICE_TABLE(pci, isp1760_plx);
-
-static struct pci_driver isp1761_pci_driver = {
- .name = "isp1760",
- .id_table = isp1760_plx,
- .probe = isp1761_pci_probe,
- .remove = isp1761_pci_remove,
- .shutdown = isp1761_pci_shutdown,
-};
-#endif
-
-static int isp1760_plat_probe(struct platform_device *pdev)
-{
- int ret = 0;
- struct usb_hcd *hcd;
- struct resource *mem_res;
- struct resource *irq_res;
- resource_size_t mem_size;
- struct isp1760_platform_data *priv = dev_get_platdata(&pdev->dev);
- unsigned int devflags = 0;
- unsigned long irqflags = IRQF_SHARED;
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem_res) {
- pr_warning("isp1760: Memory resource not available\n");
- ret = -ENODEV;
- goto out;
- }
- mem_size = resource_size(mem_res);
- if (!request_mem_region(mem_res->start, mem_size, "isp1760")) {
- pr_warning("isp1760: Cannot reserve the memory resource\n");
- ret = -EBUSY;
- goto out;
- }
-
- irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq_res) {
- pr_warning("isp1760: IRQ resource not available\n");
- ret = -ENODEV;
- goto cleanup;
- }
-
- irqflags |= irq_res->flags & IRQF_TRIGGER_MASK;
-
- if (priv) {
- if (priv->is_isp1761)
- devflags |= ISP1760_FLAG_ISP1761;
- if (priv->bus_width_16)
- devflags |= ISP1760_FLAG_BUS_WIDTH_16;
- if (priv->port1_otg)
- devflags |= ISP1760_FLAG_OTG_EN;
- if (priv->analog_oc)
- devflags |= ISP1760_FLAG_ANALOG_OC;
- if (priv->dack_polarity_high)
- devflags |= ISP1760_FLAG_DACK_POL_HIGH;
- if (priv->dreq_polarity_high)
- devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
- }
-
- hcd = isp1760_register(mem_res->start, mem_size, irq_res->start,
- irqflags, -ENOENT,
- &pdev->dev, dev_name(&pdev->dev), devflags);
-
- platform_set_drvdata(pdev, hcd);
-
- if (IS_ERR(hcd)) {
- pr_warning("isp1760: Failed to register the HCD device\n");
- ret = -ENODEV;
- goto cleanup;
- }
-
- pr_info("ISP1760 USB device initialised\n");
- return ret;
-
-cleanup:
- release_mem_region(mem_res->start, mem_size);
-out:
- return ret;
-}
-
-static int isp1760_plat_remove(struct platform_device *pdev)
-{
- struct resource *mem_res;
- resource_size_t mem_size;
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
-
- usb_remove_hcd(hcd);
-
- mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- mem_size = resource_size(mem_res);
- release_mem_region(mem_res->start, mem_size);
-
- usb_put_hcd(hcd);
-
- return 0;
-}
-
-static struct platform_driver isp1760_plat_driver = {
- .probe = isp1760_plat_probe,
- .remove = isp1760_plat_remove,
- .driver = {
- .name = "isp1760",
- },
-};
-
-static int __init isp1760_init(void)
-{
- int ret, any_ret = -ENODEV;
-
- init_kmem_once();
-
- ret = platform_driver_register(&isp1760_plat_driver);
- if (!ret)
- any_ret = 0;
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
- ret = platform_driver_register(&isp1760_of_driver);
- if (!ret)
- any_ret = 0;
-#endif
-#ifdef CONFIG_PCI
- ret = pci_register_driver(&isp1761_pci_driver);
- if (!ret)
- any_ret = 0;
-#endif
-
- if (any_ret)
- deinit_kmem_cache();
- return any_ret;
-}
-module_init(isp1760_init);
-
-static void __exit isp1760_exit(void)
-{
- platform_driver_unregister(&isp1760_plat_driver);
-#if defined(CONFIG_OF) && defined(CONFIG_OF_IRQ)
- platform_driver_unregister(&isp1760_of_driver);
-#endif
-#ifdef CONFIG_PCI
- pci_unregister_driver(&isp1761_pci_driver);
-#endif
- deinit_kmem_cache();
-}
-module_exit(isp1760_exit);
diff --git a/drivers/usb/host/max3421-hcd.c b/drivers/usb/host/max3421-hcd.c
index 6234c75da33f..a98833cbfcf3 100644
--- a/drivers/usb/host/max3421-hcd.c
+++ b/drivers/usb/host/max3421-hcd.c
@@ -55,6 +55,7 @@
* single thread (max3421_spi_thread).
*/
+#include <linux/jiffies.h>
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/usb.h>
@@ -1291,7 +1292,7 @@ max3421_handle_irqs(struct usb_hcd *hcd)
char sbuf[16 * 16], *dp, *end;
int i;
- if (jiffies - last_time > 5*HZ) {
+ if (time_after(jiffies, last_time + 5*HZ)) {
dp = sbuf;
end = sbuf + sizeof(sbuf);
*dp = '\0';
@@ -1660,7 +1661,8 @@ hub_descriptor(struct usb_hub_descriptor *desc)
*/
desc->bDescriptorType = 0x29; /* hub descriptor */
desc->bDescLength = 9;
- desc->wHubCharacteristics = cpu_to_le16(0x0001);
+ desc->wHubCharacteristics = cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM |
+ HUB_CHAR_COMMON_OCPM);
desc->bNbrPorts = 1;
}
diff --git a/drivers/usb/host/ohci-at91.c b/drivers/usb/host/ohci-at91.c
index dc9e4e61f1c8..7cce85a1f7dc 100644
--- a/drivers/usb/host/ohci-at91.c
+++ b/drivers/usb/host/ohci-at91.c
@@ -33,7 +33,17 @@
for ((index) = 0; (index) < AT91_MAX_USBH_PORTS; (index)++)
/* interface, function and usb clocks; sometimes also an AHB clock */
-static struct clk *iclk, *fclk, *uclk, *hclk;
+#define hcd_to_ohci_at91_priv(h) \
+ ((struct ohci_at91_priv *)hcd_to_ohci(h)->priv)
+
+struct ohci_at91_priv {
+ struct clk *iclk;
+ struct clk *fclk;
+ struct clk *uclk;
+ struct clk *hclk;
+ bool clocked;
+ bool wakeup; /* Saved wake-up state for resume */
+};
/* interface and function clocks; sometimes also an AHB clock */
#define DRIVER_DESC "OHCI Atmel driver"
@@ -41,45 +51,53 @@ static struct clk *iclk, *fclk, *uclk, *hclk;
static const char hcd_name[] = "ohci-atmel";
static struct hc_driver __read_mostly ohci_at91_hc_driver;
-static int clocked;
+
+static const struct ohci_driver_overrides ohci_at91_drv_overrides __initconst = {
+ .extra_priv_size = sizeof(struct ohci_at91_priv),
+};
extern int usb_disabled(void);
/*-------------------------------------------------------------------------*/
-static void at91_start_clock(void)
+static void at91_start_clock(struct ohci_at91_priv *ohci_at91)
{
+ if (ohci_at91->clocked)
+ return;
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
- clk_set_rate(uclk, 48000000);
- clk_prepare_enable(uclk);
+ clk_set_rate(ohci_at91->uclk, 48000000);
+ clk_prepare_enable(ohci_at91->uclk);
}
- clk_prepare_enable(hclk);
- clk_prepare_enable(iclk);
- clk_prepare_enable(fclk);
- clocked = 1;
+ clk_prepare_enable(ohci_at91->hclk);
+ clk_prepare_enable(ohci_at91->iclk);
+ clk_prepare_enable(ohci_at91->fclk);
+ ohci_at91->clocked = true;
}
-static void at91_stop_clock(void)
+static void at91_stop_clock(struct ohci_at91_priv *ohci_at91)
{
- clk_disable_unprepare(fclk);
- clk_disable_unprepare(iclk);
- clk_disable_unprepare(hclk);
+ if (!ohci_at91->clocked)
+ return;
+ clk_disable_unprepare(ohci_at91->fclk);
+ clk_disable_unprepare(ohci_at91->iclk);
+ clk_disable_unprepare(ohci_at91->hclk);
if (IS_ENABLED(CONFIG_COMMON_CLK))
- clk_disable_unprepare(uclk);
- clocked = 0;
+ clk_disable_unprepare(ohci_at91->uclk);
+ ohci_at91->clocked = false;
}
static void at91_start_hc(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd->regs;
+ struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
dev_dbg(&pdev->dev, "start\n");
/*
* Start the USB clocks.
*/
- at91_start_clock();
+ at91_start_clock(ohci_at91);
/*
* The USB host controller must remain in reset.
@@ -91,6 +109,7 @@ static void at91_stop_hc(struct platform_device *pdev)
{
struct usb_hcd *hcd = platform_get_drvdata(pdev);
struct ohci_regs __iomem *regs = hcd->regs;
+ struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
dev_dbg(&pdev->dev, "stop\n");
@@ -102,7 +121,7 @@ static void at91_stop_hc(struct platform_device *pdev)
/*
* Stop the USB clocks.
*/
- at91_stop_clock();
+ at91_stop_clock(ohci_at91);
}
@@ -128,7 +147,8 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
struct at91_usbh_data *board;
struct ohci_hcd *ohci;
int retval;
- struct usb_hcd *hcd = NULL;
+ struct usb_hcd *hcd;
+ struct ohci_at91_priv *ohci_at91;
struct device *dev = &pdev->dev;
struct resource *res;
int irq;
@@ -142,6 +162,7 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
hcd = usb_create_hcd(driver, dev, "at91");
if (!hcd)
return -ENOMEM;
+ ohci_at91 = hcd_to_ohci_at91_priv(hcd);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
hcd->regs = devm_ioremap_resource(dev, res);
@@ -152,29 +173,29 @@ static int usb_hcd_at91_probe(const struct hc_driver *driver,
hcd->rsrc_start = res->start;
hcd->rsrc_len = resource_size(res);
- iclk = devm_clk_get(dev, "ohci_clk");
- if (IS_ERR(iclk)) {
+ ohci_at91->iclk = devm_clk_get(dev, "ohci_clk");
+ if (IS_ERR(ohci_at91->iclk)) {
dev_err(dev, "failed to get ohci_clk\n");
- retval = PTR_ERR(iclk);
+ retval = PTR_ERR(ohci_at91->iclk);
goto err;
}
- fclk = devm_clk_get(dev, "uhpck");
- if (IS_ERR(fclk)) {
+ ohci_at91->fclk = devm_clk_get(dev, "uhpck");
+ if (IS_ERR(ohci_at91->fclk)) {
dev_err(dev, "failed to get uhpck\n");
- retval = PTR_ERR(fclk);
+ retval = PTR_ERR(ohci_at91->fclk);
goto err;
}
- hclk = devm_clk_get(dev, "hclk");
- if (IS_ERR(hclk)) {
+ ohci_at91->hclk = devm_clk_get(dev, "hclk");
+ if (IS_ERR(ohci_at91->hclk)) {
dev_err(dev, "failed to get hclk\n");
- retval = PTR_ERR(hclk);
+ retval = PTR_ERR(ohci_at91->hclk);
goto err;
}
if (IS_ENABLED(CONFIG_COMMON_CLK)) {
- uclk = devm_clk_get(dev, "usb_clk");
- if (IS_ERR(uclk)) {
+ ohci_at91->uclk = devm_clk_get(dev, "usb_clk");
+ if (IS_ERR(ohci_at91->uclk)) {
dev_err(dev, "failed to get uclk\n");
- retval = PTR_ERR(uclk);
+ retval = PTR_ERR(ohci_at91->uclk);
goto err;
}
}
@@ -347,11 +368,13 @@ static int ohci_at91_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
*/
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0001);
+ desc->wHubCharacteristics |=
+ cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM);
if (pdata->overcurrent_supported) {
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_OCPM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0008|0x0001);
+ desc->wHubCharacteristics |=
+ cpu_to_le16(HUB_CHAR_INDV_PORT_OCPM);
}
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
@@ -593,19 +616,27 @@ static int ohci_hcd_at91_drv_remove(struct platform_device *pdev)
#ifdef CONFIG_PM
static int
-ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
+ohci_hcd_at91_drv_suspend(struct device *dev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
struct ohci_hcd *ohci = hcd_to_ohci(hcd);
- bool do_wakeup = device_may_wakeup(&pdev->dev);
+ struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
int ret;
- if (do_wakeup)
+ /*
+ * Disable wakeup if we are going to sleep with slow clock mode
+ * enabled.
+ */
+ ohci_at91->wakeup = device_may_wakeup(dev)
+ && !at91_suspend_entering_slow_clock();
+
+ if (ohci_at91->wakeup)
enable_irq_wake(hcd->irq);
- ret = ohci_suspend(hcd, do_wakeup);
+ ret = ohci_suspend(hcd, ohci_at91->wakeup);
if (ret) {
- disable_irq_wake(hcd->irq);
+ if (ohci_at91->wakeup)
+ disable_irq_wake(hcd->irq);
return ret;
}
/*
@@ -615,7 +646,7 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
*
* REVISIT: some boards will be able to turn VBUS off...
*/
- if (at91_suspend_entering_slow_clock()) {
+ if (!ohci_at91->wakeup) {
ohci->hc_control = ohci_readl(ohci, &ohci->regs->control);
ohci->hc_control &= OHCI_CTRL_RWC;
ohci_writel(ohci, ohci->hc_control, &ohci->regs->control);
@@ -623,38 +654,37 @@ ohci_hcd_at91_drv_suspend(struct platform_device *pdev, pm_message_t mesg)
/* flush the writes */
(void) ohci_readl (ohci, &ohci->regs->control);
- at91_stop_clock();
+ at91_stop_clock(ohci_at91);
}
return ret;
}
-static int ohci_hcd_at91_drv_resume(struct platform_device *pdev)
+static int ohci_hcd_at91_drv_resume(struct device *dev)
{
- struct usb_hcd *hcd = platform_get_drvdata(pdev);
+ struct usb_hcd *hcd = dev_get_drvdata(dev);
+ struct ohci_at91_priv *ohci_at91 = hcd_to_ohci_at91_priv(hcd);
- if (device_may_wakeup(&pdev->dev))
+ if (ohci_at91->wakeup)
disable_irq_wake(hcd->irq);
- if (!clocked)
- at91_start_clock();
+ at91_start_clock(ohci_at91);
ohci_resume(hcd, false);
return 0;
}
-#else
-#define ohci_hcd_at91_drv_suspend NULL
-#define ohci_hcd_at91_drv_resume NULL
#endif
+static SIMPLE_DEV_PM_OPS(ohci_hcd_at91_pm_ops, ohci_hcd_at91_drv_suspend,
+ ohci_hcd_at91_drv_resume);
+
static struct platform_driver ohci_hcd_at91_driver = {
.probe = ohci_hcd_at91_drv_probe,
.remove = ohci_hcd_at91_drv_remove,
.shutdown = usb_hcd_platform_shutdown,
- .suspend = ohci_hcd_at91_drv_suspend,
- .resume = ohci_hcd_at91_drv_resume,
.driver = {
.name = "at91_ohci",
+ .pm = &ohci_hcd_at91_pm_ops,
.of_match_table = of_match_ptr(at91_ohci_dt_ids),
},
};
@@ -665,7 +695,7 @@ static int __init ohci_at91_init(void)
return -ENODEV;
pr_info("%s: " DRIVER_DESC "\n", hcd_name);
- ohci_init_driver(&ohci_at91_hc_driver, NULL);
+ ohci_init_driver(&ohci_at91_hc_driver, &ohci_at91_drv_overrides);
/*
* The Atmel HW has some unusual quirks, which require Atmel-specific
diff --git a/drivers/usb/host/ohci-da8xx.c b/drivers/usb/host/ohci-da8xx.c
index 1c76999b2184..e5c33bc98ea4 100644
--- a/drivers/usb/host/ohci-da8xx.c
+++ b/drivers/usb/host/ohci-da8xx.c
@@ -431,7 +431,6 @@ static struct platform_driver ohci_hcd_da8xx_driver = {
.resume = ohci_da8xx_resume,
#endif
.driver = {
- .owner = THIS_MODULE,
.name = "ohci",
},
};
diff --git a/drivers/usb/host/ohci-hub.c b/drivers/usb/host/ohci-hub.c
index 0aa17c937115..fe2aedd8a54d 100644
--- a/drivers/usb/host/ohci-hub.c
+++ b/drivers/usb/host/ohci-hub.c
@@ -544,15 +544,15 @@ ohci_hub_descriptor (
temp = 1 + (ohci->num_ports / 8);
desc->bDescLength = 7 + 2 * temp;
- temp = 0;
+ temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
if (rh & RH_A_NPS) /* no power switching? */
- temp |= 0x0002;
+ temp |= HUB_CHAR_NO_LPSM;
if (rh & RH_A_PSM) /* per-port power switching? */
- temp |= 0x0001;
+ temp |= HUB_CHAR_INDV_PORT_LPSM;
if (rh & RH_A_NOCP) /* no overcurrent reporting? */
- temp |= 0x0010;
+ temp |= HUB_CHAR_NO_OCPM;
else if (rh & RH_A_OCPM) /* per-port overcurrent reporting? */
- temp |= 0x0008;
+ temp |= HUB_CHAR_INDV_PORT_OCPM;
desc->wHubCharacteristics = cpu_to_le16(temp);
/* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
diff --git a/drivers/usb/host/ohci-jz4740.c b/drivers/usb/host/ohci-jz4740.c
index 8ddd8f5470cb..4db78f169256 100644
--- a/drivers/usb/host/ohci-jz4740.c
+++ b/drivers/usb/host/ohci-jz4740.c
@@ -239,7 +239,6 @@ static struct platform_driver ohci_hcd_jz4740_driver = {
.remove = jz4740_ohci_remove,
.driver = {
.name = "jz4740-ohci",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index b81d202b15a2..185ceee52d47 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -38,7 +38,8 @@
struct ohci_platform_priv {
struct clk *clks[OHCI_MAX_CLKS];
struct reset_control *rst;
- struct phy *phy;
+ struct phy **phys;
+ int num_phys;
};
static const char hcd_name[] = "ohci-platform";
@@ -47,7 +48,7 @@ static int ohci_platform_power_on(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk, ret;
+ int clk, ret, phy_num;
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
ret = clk_prepare_enable(priv->clks[clk]);
@@ -55,20 +56,28 @@ static int ohci_platform_power_on(struct platform_device *dev)
goto err_disable_clks;
}
- if (priv->phy) {
- ret = phy_init(priv->phy);
- if (ret)
- goto err_disable_clks;
-
- ret = phy_power_on(priv->phy);
- if (ret)
- goto err_exit_phy;
+ for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+ if (priv->phys[phy_num]) {
+ ret = phy_init(priv->phys[phy_num]);
+ if (ret)
+ goto err_exit_phy;
+ ret = phy_power_on(priv->phys[phy_num]);
+ if (ret) {
+ phy_exit(priv->phys[phy_num]);
+ goto err_exit_phy;
+ }
+ }
}
return 0;
err_exit_phy:
- phy_exit(priv->phy);
+ while (--phy_num >= 0) {
+ if (priv->phys[phy_num]) {
+ phy_power_off(priv->phys[phy_num]);
+ phy_exit(priv->phys[phy_num]);
+ }
+ }
err_disable_clks:
while (--clk >= 0)
clk_disable_unprepare(priv->clks[clk]);
@@ -80,11 +89,13 @@ static void ohci_platform_power_off(struct platform_device *dev)
{
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk;
+ int clk, phy_num;
- if (priv->phy) {
- phy_power_off(priv->phy);
- phy_exit(priv->phy);
+ for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+ if (priv->phys[phy_num]) {
+ phy_power_off(priv->phys[phy_num]);
+ phy_exit(priv->phys[phy_num]);
+ }
}
for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -112,7 +123,8 @@ static int ohci_platform_probe(struct platform_device *dev)
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ohci_platform_priv *priv;
struct ohci_hcd *ohci;
- int err, irq, clk = 0;
+ const char *phy_name;
+ int err, irq, phy_num, clk = 0;
if (usb_disabled())
return -ENODEV;
@@ -160,12 +172,38 @@ static int ohci_platform_probe(struct platform_device *dev)
of_property_read_u32(dev->dev.of_node, "num-ports",
&ohci->num_ports);
- priv->phy = devm_phy_get(&dev->dev, "usb");
- if (IS_ERR(priv->phy)) {
- err = PTR_ERR(priv->phy);
- if (err == -EPROBE_DEFER)
- goto err_put_hcd;
- priv->phy = NULL;
+ priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
+ "phys", "#phy-cells");
+ priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
+
+ priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
+ sizeof(struct phy *), GFP_KERNEL);
+ if (!priv->phys)
+ return -ENOMEM;
+
+ for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
+ err = of_property_read_string_index(
+ dev->dev.of_node,
+ "phy-names", phy_num,
+ &phy_name);
+
+ if (err < 0) {
+ if (priv->num_phys > 1) {
+ dev_err(&dev->dev, "phy-names not provided");
+ goto err_put_hcd;
+ } else
+ phy_name = "usb";
+ }
+
+ priv->phys[phy_num] = devm_phy_get(&dev->dev,
+ phy_name);
+ if (IS_ERR(priv->phys[phy_num])) {
+ err = PTR_ERR(priv->phys[phy_num]);
+ if ((priv->num_phys > 1) ||
+ (err == -EPROBE_DEFER))
+ goto err_put_hcd;
+ priv->phys[phy_num] = NULL;
+ }
}
for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {
@@ -328,6 +366,7 @@ static int ohci_platform_resume(struct device *dev)
static const struct of_device_id ohci_platform_ids[] = {
{ .compatible = "generic-ohci", },
+ { .compatible = "cavium,octeon-6335-ohci", },
{ }
};
MODULE_DEVICE_TABLE(of, ohci_platform_ids);
diff --git a/drivers/usb/host/ohci-ppc-of.c b/drivers/usb/host/ohci-ppc-of.c
index 965e3e9e688a..4f87a5c61b08 100644
--- a/drivers/usb/host/ohci-ppc-of.c
+++ b/drivers/usb/host/ohci-ppc-of.c
@@ -229,7 +229,6 @@ static struct platform_driver ohci_hcd_ppc_of_driver = {
.shutdown = usb_hcd_platform_shutdown,
.driver = {
.name = "ppc-of-ohci",
- .owner = THIS_MODULE,
.of_match_table = ohci_hcd_ppc_of_match,
},
};
diff --git a/drivers/usb/host/ohci-s3c2410.c b/drivers/usb/host/ohci-s3c2410.c
index 095113ea1fcb..7a1919ca543a 100644
--- a/drivers/usb/host/ohci-s3c2410.c
+++ b/drivers/usb/host/ohci-s3c2410.c
@@ -249,14 +249,14 @@ static int ohci_s3c2410_hub_control(
*/
desc->wHubCharacteristics &= ~cpu_to_le16(HUB_CHAR_LPSM);
- desc->wHubCharacteristics |= cpu_to_le16(0x0001);
+ desc->wHubCharacteristics |= cpu_to_le16(
+ HUB_CHAR_INDV_PORT_LPSM);
if (info->enable_oc) {
desc->wHubCharacteristics &= ~cpu_to_le16(
HUB_CHAR_OCPM);
desc->wHubCharacteristics |= cpu_to_le16(
- 0x0008 |
- 0x0001);
+ HUB_CHAR_INDV_PORT_OCPM);
}
dev_dbg(hcd->self.controller, "wHubCharacteristics after 0x%04x\n",
diff --git a/drivers/usb/host/ohci-sm501.c b/drivers/usb/host/ohci-sm501.c
index 4e81c804c73e..a8b8d8b8d9f3 100644
--- a/drivers/usb/host/ohci-sm501.c
+++ b/drivers/usb/host/ohci-sm501.c
@@ -265,7 +265,6 @@ static struct platform_driver ohci_hcd_sm501_driver = {
.suspend = ohci_sm501_suspend,
.resume = ohci_sm501_resume,
.driver = {
- .owner = THIS_MODULE,
.name = "sm501-usb",
},
};
diff --git a/drivers/usb/host/ohci-tilegx.c b/drivers/usb/host/ohci-tilegx.c
index bef6dfb0405a..e1b208da460a 100644
--- a/drivers/usb/host/ohci-tilegx.c
+++ b/drivers/usb/host/ohci-tilegx.c
@@ -199,7 +199,6 @@ static struct platform_driver ohci_hcd_tilegx_driver = {
.shutdown = ohci_hcd_tilegx_drv_shutdown,
.driver = {
.name = "tilegx-ohci",
- .owner = THIS_MODULE,
}
};
diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
index bb409588d39c..e9a6eec39142 100644
--- a/drivers/usb/host/ohci-tmio.c
+++ b/drivers/usb/host/ohci-tmio.c
@@ -368,6 +368,5 @@ static struct platform_driver ohci_hcd_tmio_driver = {
.resume = ohci_hcd_tmio_drv_resume,
.driver = {
.name = "tmio-ohci",
- .owner = THIS_MODULE,
},
};
diff --git a/drivers/usb/host/oxu210hp-hcd.c b/drivers/usb/host/oxu210hp-hcd.c
index 036924e640f5..ef7efb278b15 100644
--- a/drivers/usb/host/oxu210hp-hcd.c
+++ b/drivers/usb/host/oxu210hp-hcd.c
@@ -457,11 +457,11 @@ static void ehci_hub_descriptor(struct oxu_hcd *oxu,
memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
- temp = 0x0008; /* per-port overcurrent reporting */
+ temp = HUB_CHAR_INDV_PORT_OCPM; /* per-port overcurrent reporting */
if (HCS_PPC(oxu->hcs_params))
- temp |= 0x0001; /* per-port power control */
+ temp |= HUB_CHAR_INDV_PORT_LPSM; /* per-port power control */
else
- temp |= 0x0002; /* no power switching */
+ temp |= HUB_CHAR_NO_LPSM; /* no power switching */
desc->wHubCharacteristics = (__force __u16)cpu_to_le16(temp);
}
@@ -2598,9 +2598,7 @@ static int oxu_hcd_init(struct usb_hcd *hcd)
spin_lock_init(&oxu->lock);
- init_timer(&oxu->watchdog);
- oxu->watchdog.function = oxu_watchdog;
- oxu->watchdog.data = (unsigned long) oxu;
+ setup_timer(&oxu->watchdog, oxu_watchdog, (unsigned long)oxu);
/*
* hw default: 1K periodic list heads, one per frame.
diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index ce636466edb7..f9400564cb72 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -603,9 +603,9 @@ static void quirk_usb_handoff_ohci(struct pci_dev *pdev)
msleep(10);
}
if (wait_time <= 0)
- dev_warn(&pdev->dev, "OHCI: BIOS handoff failed"
- " (BIOS bug?) %08x\n",
- readl(base + OHCI_CONTROL));
+ dev_warn(&pdev->dev,
+ "OHCI: BIOS handoff failed (BIOS bug?) %08x\n",
+ readl(base + OHCI_CONTROL));
}
#endif
@@ -733,8 +733,9 @@ static void ehci_bios_handoff(struct pci_dev *pdev,
* and hope nothing goes too wrong
*/
if (try_handoff)
- dev_warn(&pdev->dev, "EHCI: BIOS handoff failed"
- " (BIOS bug?) %08x\n", cap);
+ dev_warn(&pdev->dev,
+ "EHCI: BIOS handoff failed (BIOS bug?) %08x\n",
+ cap);
pci_write_config_byte(pdev, offset + 2, 0);
}
@@ -781,8 +782,9 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev)
case 0: /* Illegal reserved cap, set cap=0 so we exit */
cap = 0; /* then fallthrough... */
default:
- dev_warn(&pdev->dev, "EHCI: unrecognized capability "
- "%02x\n", cap & 0xff);
+ dev_warn(&pdev->dev,
+ "EHCI: unrecognized capability %02x\n",
+ cap & 0xff);
}
offset = (cap >> 8) & 0xff;
}
@@ -893,8 +895,7 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
*/
if (!IS_ENABLED(CONFIG_USB_XHCI_HCD)) {
dev_warn(&xhci_pdev->dev,
- "CONFIG_USB_XHCI_HCD is turned off, "
- "defaulting to EHCI.\n");
+ "CONFIG_USB_XHCI_HCD is turned off, defaulting to EHCI.\n");
dev_warn(&xhci_pdev->dev,
"USB 3.0 devices will work at USB 2.0 speeds.\n");
usb_disable_xhci_ports(xhci_pdev);
@@ -919,8 +920,9 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
pci_read_config_dword(xhci_pdev, USB_INTEL_USB3_PSSEN,
&ports_available);
- dev_dbg(&xhci_pdev->dev, "USB 3.0 ports that are now enabled "
- "under xHCI: 0x%x\n", ports_available);
+ dev_dbg(&xhci_pdev->dev,
+ "USB 3.0 ports that are now enabled under xHCI: 0x%x\n",
+ ports_available);
/* Read XUSB2PRM, xHCI USB 2.0 Port Routing Mask Register
* Indicate the USB 2.0 ports to be controlled by the xHCI host.
@@ -941,8 +943,9 @@ void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev)
pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
&ports_available);
- dev_dbg(&xhci_pdev->dev, "USB 2.0 ports that are now switched over "
- "to xHCI: 0x%x\n", ports_available);
+ dev_dbg(&xhci_pdev->dev,
+ "USB 2.0 ports that are now switched over to xHCI: 0x%x\n",
+ ports_available);
}
EXPORT_SYMBOL_GPL(usb_enable_intel_xhci_ports);
@@ -1010,8 +1013,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
/* Assume a buggy BIOS and take HC ownership anyway */
if (timeout) {
- dev_warn(&pdev->dev, "xHCI BIOS handoff failed"
- " (BIOS bug ?) %08x\n", val);
+ dev_warn(&pdev->dev,
+ "xHCI BIOS handoff failed (BIOS bug ?) %08x\n",
+ val);
writel(val & ~XHCI_HC_BIOS_OWNED, base + ext_cap_offset);
}
}
@@ -1039,8 +1043,8 @@ hc_init:
if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET);
dev_warn(&pdev->dev,
- "xHCI HW not ready after 5 sec (HC bug?) "
- "status = 0x%x\n", val);
+ "xHCI HW not ready after 5 sec (HC bug?) status = 0x%x\n",
+ val);
}
/* Send the halt and disable interrupts command */
@@ -1054,8 +1058,8 @@ hc_init:
if (timeout) {
val = readl(op_reg_base + XHCI_STS_OFFSET);
dev_warn(&pdev->dev,
- "xHCI HW did not halt within %d usec "
- "status = 0x%x\n", XHCI_MAX_HALT_USEC, val);
+ "xHCI HW did not halt within %d usec status = 0x%x\n",
+ XHCI_MAX_HALT_USEC, val);
}
iounmap(base);
@@ -1075,8 +1079,8 @@ static void quirk_usb_early_handoff(struct pci_dev *pdev)
return;
if (pci_enable_device(pdev) < 0) {
- dev_warn(&pdev->dev, "Can't enable PCI device, "
- "BIOS handoff failed.\n");
+ dev_warn(&pdev->dev,
+ "Can't enable PCI device, BIOS handoff failed.\n");
return;
}
if (pdev->class == PCI_CLASS_SERIAL_USB_UHCI)
diff --git a/drivers/usb/host/r8a66597-hcd.c b/drivers/usb/host/r8a66597-hcd.c
index c4bcfaedeec9..bdc82fea0a1f 100644
--- a/drivers/usb/host/r8a66597-hcd.c
+++ b/drivers/usb/host/r8a66597-hcd.c
@@ -2141,7 +2141,8 @@ static void r8a66597_hub_descriptor(struct r8a66597 *r8a66597,
desc->bNbrPorts = r8a66597->max_root_hub;
desc->bDescLength = 9;
desc->bPwrOn2PwrGood = 0;
- desc->wHubCharacteristics = cpu_to_le16(0x0011);
+ desc->wHubCharacteristics =
+ cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM);
desc->u.hs.DeviceRemovable[0] =
((1 << r8a66597->max_root_hub) - 1) << 1;
desc->u.hs.DeviceRemovable[1] = ~0;
@@ -2483,9 +2484,8 @@ static int r8a66597_probe(struct platform_device *pdev)
r8a66597->max_root_hub = 2;
spin_lock_init(&r8a66597->lock);
- init_timer(&r8a66597->rh_timer);
- r8a66597->rh_timer.function = r8a66597_timer;
- r8a66597->rh_timer.data = (unsigned long)r8a66597;
+ setup_timer(&r8a66597->rh_timer, r8a66597_timer,
+ (unsigned long)r8a66597);
r8a66597->reg = reg;
/* make sure no interrupts are pending */
@@ -2496,9 +2496,8 @@ static int r8a66597_probe(struct platform_device *pdev)
for (i = 0; i < R8A66597_MAX_NUM_PIPE; i++) {
INIT_LIST_HEAD(&r8a66597->pipe_queue[i]);
- init_timer(&r8a66597->td_timer[i]);
- r8a66597->td_timer[i].function = r8a66597_td_timer;
- r8a66597->td_timer[i].data = (unsigned long)r8a66597;
+ setup_timer(&r8a66597->td_timer[i], r8a66597_td_timer,
+ (unsigned long)r8a66597);
setup_timer(&r8a66597->interval_timer[i],
r8a66597_interval_timer,
(unsigned long)r8a66597);
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index 25fb1da8d3d7..4f4ba1ea9e9b 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -1103,12 +1103,12 @@ sl811h_hub_descriptor (
desc->bPwrOn2PwrGood = sl811->board->potpg;
if (!desc->bPwrOn2PwrGood)
desc->bPwrOn2PwrGood = 10;
- temp = 0x0001;
+ temp = HUB_CHAR_INDV_PORT_LPSM;
} else
- temp = 0x0002;
+ temp = HUB_CHAR_NO_LPSM;
/* no overcurrent errors detection/handling */
- temp |= 0x0010;
+ temp |= HUB_CHAR_NO_OCPM;
desc->wHubCharacteristics = cpu_to_le16(temp);
@@ -1691,9 +1691,7 @@ sl811h_probe(struct platform_device *dev)
spin_lock_init(&sl811->lock);
INIT_LIST_HEAD(&sl811->async);
sl811->board = dev_get_platdata(&dev->dev);
- init_timer(&sl811->timer);
- sl811->timer.function = sl811h_timer;
- sl811->timer.data = (unsigned long) sl811;
+ setup_timer(&sl811->timer, sl811h_timer, (unsigned long)sl811);
sl811->addr_reg = addr_reg;
sl811->data_reg = data_reg;
diff --git a/drivers/usb/host/ssb-hcd.c b/drivers/usb/host/ssb-hcd.c
index 0196f766df73..ffc32f4b1b1b 100644
--- a/drivers/usb/host/ssb-hcd.c
+++ b/drivers/usb/host/ssb-hcd.c
@@ -251,7 +251,7 @@ static const struct ssb_device_id ssb_hcd_table[] = {
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOSTDEV, SSB_ANY_REV),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB11_HOST, SSB_ANY_REV),
SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_USB20_HOST, SSB_ANY_REV),
- SSB_DEVTABLE_END
+ {},
};
MODULE_DEVICE_TABLE(ssb, ssb_hcd_table);
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index 2894e54e5b9c..ad97e8a1ad1c 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -2590,15 +2590,15 @@ static int u132_roothub_descriptor(struct u132 *u132,
desc->bNbrPorts = u132->num_ports;
temp = 1 + (u132->num_ports / 8);
desc->bDescLength = 7 + 2 * temp;
- temp = 0;
+ temp = HUB_CHAR_COMMON_LPSM | HUB_CHAR_COMMON_OCPM;
if (rh_a & RH_A_NPS)
- temp |= 0x0002;
+ temp |= HUB_CHAR_NO_LPSM;
if (rh_a & RH_A_PSM)
- temp |= 0x0001;
+ temp |= HUB_CHAR_INDV_PORT_LPSM;
if (rh_a & RH_A_NOCP)
- temp |= 0x0010;
+ temp |= HUB_CHAR_NO_OCPM;
else if (rh_a & RH_A_OCPM)
- temp |= 0x0008;
+ temp |= HUB_CHAR_INDV_PORT_OCPM;
desc->wHubCharacteristics = cpu_to_le16(temp);
retval = u132_read_pcimem(u132, roothub.b, &rh_b);
if (retval)
diff --git a/drivers/usb/host/uhci-grlib.c b/drivers/usb/host/uhci-grlib.c
index 05f57ffdf9ab..0342991c9507 100644
--- a/drivers/usb/host/uhci-grlib.c
+++ b/drivers/usb/host/uhci-grlib.c
@@ -188,7 +188,6 @@ static struct platform_driver uhci_grlib_driver = {
.shutdown = uhci_hcd_grlib_shutdown,
.driver = {
.name = "grlib-uhci",
- .owner = THIS_MODULE,
.of_match_table = uhci_hcd_grlib_of_match,
},
};
diff --git a/drivers/usb/host/uhci-hub.c b/drivers/usb/host/uhci-hub.c
index 93e17b12fb33..19ba5eafb31e 100644
--- a/drivers/usb/host/uhci-hub.c
+++ b/drivers/usb/host/uhci-hub.c
@@ -17,8 +17,9 @@ static const __u8 root_hub_hub_des[] =
0x09, /* __u8 bLength; */
0x29, /* __u8 bDescriptorType; Hub-descriptor */
0x02, /* __u8 bNbrPorts; */
- 0x0a, /* __u16 wHubCharacteristics; */
- 0x00, /* (per-port OC, no power switching) */
+ HUB_CHAR_NO_LPSM | /* __u16 wHubCharacteristics; */
+ HUB_CHAR_INDV_PORT_OCPM, /* (per-port OC, no power switching) */
+ 0x00,
0x01, /* __u8 bPwrOn2pwrGood; 2ms */
0x00, /* __u8 bHubContrCurrent; 0 mA */
0x00, /* __u8 DeviceRemovable; *** 7 Ports max */
diff --git a/drivers/usb/host/uhci-platform.c b/drivers/usb/host/uhci-platform.c
index cf8f46003f62..3a3e3eeba291 100644
--- a/drivers/usb/host/uhci-platform.c
+++ b/drivers/usb/host/uhci-platform.c
@@ -147,7 +147,6 @@ static struct platform_driver uhci_platform_driver = {
.shutdown = uhci_hcd_platform_shutdown,
.driver = {
.name = "platform-uhci",
- .owner = THIS_MODULE,
.of_match_table = platform_uhci_ids,
},
};
diff --git a/drivers/usb/host/whci/debug.c b/drivers/usb/host/whci/debug.c
index ba61dae9e4d2..774b89d28fae 100644
--- a/drivers/usb/host/whci/debug.c
+++ b/drivers/usb/host/whci/debug.c
@@ -86,17 +86,14 @@ static void qset_print(struct seq_file *s, struct whc_qset *qset)
static int di_print(struct seq_file *s, void *p)
{
struct whc *whc = s->private;
- char buf[72];
int d;
for (d = 0; d < whc->n_devices; d++) {
struct di_buf_entry *di = &whc->di_buf[d];
- bitmap_scnprintf(buf, sizeof(buf),
- (unsigned long *)di->availability_info, UWB_NUM_MAS);
-
seq_printf(s, "DI[%d]\n", d);
- seq_printf(s, " availability: %s\n", buf);
+ seq_printf(s, " availability: %*pb\n",
+ UWB_NUM_MAS, (unsigned long *)di->availability_info);
seq_printf(s, " %c%c key idx: %d dev addr: %d\n",
(di->addr_sec_info & WHC_DI_SECURE) ? 'S' : ' ',
(di->addr_sec_info & WHC_DI_DISABLE) ? 'D' : ' ',
diff --git a/drivers/usb/host/xhci-dbg.c b/drivers/usb/host/xhci-dbg.c
index bb89175ca6e5..745717ec9c89 100644
--- a/drivers/usb/host/xhci-dbg.c
+++ b/drivers/usb/host/xhci-dbg.c
@@ -552,7 +552,7 @@ void xhci_dbg_ctx(struct xhci_hcd *xhci,
if (ctx->type == XHCI_CTX_TYPE_INPUT) {
struct xhci_input_control_ctx *ctrl_ctx =
- xhci_get_input_control_ctx(xhci, ctx);
+ xhci_get_input_control_ctx(ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "Could not get input context, bad type.\n");
return;
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index 5cb3d7a10017..f8336408ef07 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -535,7 +535,7 @@ static void xhci_free_container_ctx(struct xhci_hcd *xhci,
kfree(ctx);
}
-struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci,
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(
struct xhci_container_ctx *ctx)
{
if (ctx->type != XHCI_CTX_TYPE_INPUT)
@@ -784,8 +784,7 @@ void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
* Reinstalls the "normal" endpoint ring (at its previous dequeue mark,
* not at the beginning of the ring).
*/
-void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
- struct xhci_ep_ctx *ep_ctx,
+void xhci_setup_no_streams_ep_input_ctx(struct xhci_ep_ctx *ep_ctx,
struct xhci_virt_ep *ep)
{
dma_addr_t addr;
@@ -833,9 +832,8 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
static void xhci_init_endpoint_timer(struct xhci_hcd *xhci,
struct xhci_virt_ep *ep)
{
- init_timer(&ep->stop_cmd_timer);
- ep->stop_cmd_timer.data = (unsigned long) ep;
- ep->stop_cmd_timer.function = xhci_stop_endpoint_command_watchdog;
+ setup_timer(&ep->stop_cmd_timer, xhci_stop_endpoint_command_watchdog,
+ (unsigned long)ep);
ep->xhci = xhci;
}
@@ -1342,8 +1340,7 @@ static u32 xhci_get_endpoint_mult(struct usb_device *udev,
return ep->ss_ep_comp.bmAttributes;
}
-static u32 xhci_get_endpoint_type(struct usb_device *udev,
- struct usb_host_endpoint *ep)
+static u32 xhci_get_endpoint_type(struct usb_host_endpoint *ep)
{
int in;
u32 type;
@@ -1376,8 +1373,7 @@ static u32 xhci_get_endpoint_type(struct usb_device *udev,
* Basically, this is the maxpacket size, multiplied by the burst size
* and mult size.
*/
-static u32 xhci_get_max_esit_payload(struct xhci_hcd *xhci,
- struct usb_device *udev,
+static u32 xhci_get_max_esit_payload(struct usb_device *udev,
struct usb_host_endpoint *ep)
{
int max_burst;
@@ -1418,7 +1414,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
ep_index = xhci_get_endpoint_index(&ep->desc);
ep_ctx = xhci_get_ep_ctx(xhci, virt_dev->in_ctx, ep_index);
- endpoint_type = xhci_get_endpoint_type(udev, ep);
+ endpoint_type = xhci_get_endpoint_type(ep);
if (!endpoint_type)
return -EINVAL;
ep_ctx->ep_info2 = cpu_to_le32(endpoint_type);
@@ -1484,7 +1480,7 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
}
ep_ctx->ep_info2 |= cpu_to_le32(MAX_PACKET(max_packet) |
MAX_BURST(max_burst));
- max_esit_payload = xhci_get_max_esit_payload(xhci, udev, ep);
+ max_esit_payload = xhci_get_max_esit_payload(udev, ep);
ep_ctx->tx_info = cpu_to_le32(MAX_ESIT_PAYLOAD_FOR_EP(max_esit_payload));
/*
@@ -1773,7 +1769,7 @@ struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
return command;
}
-void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv)
+void xhci_urb_free_priv(struct urb_priv *urb_priv)
{
if (urb_priv) {
kfree(urb_priv->td[0]);
@@ -1926,7 +1922,7 @@ static int xhci_test_trb_in_td(struct xhci_hcd *xhci,
}
/* TRB math checks for xhci_trb_in_td(), using the command and event rings. */
-static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci, gfp_t mem_flags)
+static int xhci_check_trb_in_td_math(struct xhci_hcd *xhci)
{
struct {
dma_addr_t input_dma;
@@ -2452,7 +2448,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
flags);
if (!xhci->event_ring)
goto fail;
- if (xhci_check_trb_in_td_math(xhci, flags) < 0)
+ if (xhci_check_trb_in_td_math(xhci) < 0)
goto fail;
xhci->erst.entries = dma_alloc_coherent(dev,
@@ -2509,9 +2505,8 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
xhci_print_ir_set(xhci, 0);
/* init command timeout timer */
- init_timer(&xhci->cmd_timer);
- xhci->cmd_timer.data = (unsigned long) xhci;
- xhci->cmd_timer.function = xhci_handle_command_timeout;
+ setup_timer(&xhci->cmd_timer, xhci_handle_command_timeout,
+ (unsigned long)xhci);
/*
* XXX: Might need to set the Interrupter Moderation Register to
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index e692e769c50c..88da8d629820 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -299,7 +299,7 @@ static int xhci_abort_cmd_ring(struct xhci_hcd *xhci)
* seconds), then it should assume that the there are
* larger problems with the xHC and assert HCRST.
*/
- ret = xhci_handshake(xhci, &xhci->op_regs->cmd_ring,
+ ret = xhci_handshake(&xhci->op_regs->cmd_ring,
CMD_RING_RUNNING, 0, 5 * 1000 * 1000);
if (ret < 0) {
xhci_err(xhci, "Stopped the command ring failed, "
@@ -609,7 +609,7 @@ static void xhci_giveback_urb_in_irq(struct xhci_hcd *xhci,
spin_unlock(&xhci->lock);
usb_hcd_giveback_urb(hcd, urb, status);
- xhci_urb_free_priv(xhci, urb_priv);
+ xhci_urb_free_priv(urb_priv);
spin_lock(&xhci->lock);
}
}
@@ -1110,7 +1110,7 @@ static void xhci_handle_cmd_config_ep(struct xhci_hcd *xhci, int slot_id,
* is not waiting on the configure endpoint command.
*/
virt_dev = xhci->devs[slot_id];
- ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "Could not get input context, bad type.\n");
return;
@@ -2354,8 +2354,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
status = 0;
break;
}
- xhci_warn(xhci, "ERROR Unknown event condition, HC probably "
- "busted\n");
+ xhci_warn(xhci, "ERROR Unknown event condition %u, HC probably busted\n",
+ trb_comp_code);
goto cleanup;
}
@@ -2497,7 +2497,7 @@ cleanup:
urb = td->urb;
urb_priv = urb->hcpriv;
- xhci_urb_free_priv(xhci, urb_priv);
+ xhci_urb_free_priv(urb_priv);
usb_hcd_unlink_urb_from_ep(bus_to_hcd(urb->dev->bus), urb);
if ((urb->actual_length != urb->transfer_buffer_length &&
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index c50d8d202618..ec8ac1674854 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -60,8 +60,7 @@ MODULE_PARM_DESC(quirks, "Bit flags for quirks to be enabled as default");
* handshake done). There are two failure modes: "usec" have passed (major
* hardware flakeout), or the register reads as all-ones (hardware removed).
*/
-int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr,
- u32 mask, u32 done, int usec)
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec)
{
u32 result;
@@ -111,7 +110,7 @@ int xhci_halt(struct xhci_hcd *xhci)
xhci_dbg_trace(xhci, trace_xhci_dbg_init, "// Halt the HC");
xhci_quiesce(xhci);
- ret = xhci_handshake(xhci, &xhci->op_regs->status,
+ ret = xhci_handshake(&xhci->op_regs->status,
STS_HALT, STS_HALT, XHCI_MAX_HALT_USEC);
if (!ret) {
xhci->xhc_state |= XHCI_STATE_HALTED;
@@ -140,7 +139,7 @@ static int xhci_start(struct xhci_hcd *xhci)
* Wait for the HCHalted Status bit to be 0 to indicate the host is
* running.
*/
- ret = xhci_handshake(xhci, &xhci->op_regs->status,
+ ret = xhci_handshake(&xhci->op_regs->status,
STS_HALT, 0, XHCI_MAX_HALT_USEC);
if (ret == -ETIMEDOUT)
xhci_err(xhci, "Host took too long to start, "
@@ -175,7 +174,7 @@ int xhci_reset(struct xhci_hcd *xhci)
command |= CMD_RESET;
writel(command, &xhci->op_regs->command);
- ret = xhci_handshake(xhci, &xhci->op_regs->command,
+ ret = xhci_handshake(&xhci->op_regs->command,
CMD_RESET, 0, 10 * 1000 * 1000);
if (ret)
return ret;
@@ -186,7 +185,7 @@ int xhci_reset(struct xhci_hcd *xhci)
* xHCI cannot write to any doorbells or operational registers other
* than status until the "Controller Not Ready" flag is cleared.
*/
- ret = xhci_handshake(xhci, &xhci->op_regs->status,
+ ret = xhci_handshake(&xhci->op_regs->status,
STS_CNR, 0, 10 * 1000 * 1000);
for (i = 0; i < 2; ++i) {
@@ -473,10 +472,8 @@ static void compliance_mode_recovery(unsigned long arg)
static void compliance_mode_recovery_timer_init(struct xhci_hcd *xhci)
{
xhci->port_status_u0 = 0;
- init_timer(&xhci->comp_mode_recovery_timer);
-
- xhci->comp_mode_recovery_timer.data = (unsigned long) xhci;
- xhci->comp_mode_recovery_timer.function = compliance_mode_recovery;
+ setup_timer(&xhci->comp_mode_recovery_timer,
+ compliance_mode_recovery, (unsigned long)xhci);
xhci->comp_mode_recovery_timer.expires = jiffies +
msecs_to_jiffies(COMP_MODE_RCVRY_MSECS);
@@ -929,7 +926,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
/* Some chips from Fresco Logic need an extraordinary delay */
delay *= (xhci->quirks & XHCI_SLOW_SUSPEND) ? 10 : 1;
- if (xhci_handshake(xhci, &xhci->op_regs->status,
+ if (xhci_handshake(&xhci->op_regs->status,
STS_HALT, STS_HALT, delay)) {
xhci_warn(xhci, "WARN: xHC CMD_RUN timeout\n");
spin_unlock_irq(&xhci->lock);
@@ -944,7 +941,7 @@ int xhci_suspend(struct xhci_hcd *xhci, bool do_wakeup)
command = readl(&xhci->op_regs->command);
command |= CMD_CSS;
writel(command, &xhci->op_regs->command);
- if (xhci_handshake(xhci, &xhci->op_regs->status,
+ if (xhci_handshake(&xhci->op_regs->status,
STS_SAVE, 0, 10 * 1000)) {
xhci_warn(xhci, "WARN: xHC save state timeout\n");
spin_unlock_irq(&xhci->lock);
@@ -1011,7 +1008,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
command = readl(&xhci->op_regs->command);
command |= CMD_CRS;
writel(command, &xhci->op_regs->command);
- if (xhci_handshake(xhci, &xhci->op_regs->status,
+ if (xhci_handshake(&xhci->op_regs->status,
STS_RESTORE, 0, 10 * 1000)) {
xhci_warn(xhci, "WARN: xHC restore state timeout\n");
spin_unlock_irq(&xhci->lock);
@@ -1082,7 +1079,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool hibernated)
command = readl(&xhci->op_regs->command);
command |= CMD_RUN;
writel(command, &xhci->op_regs->command);
- xhci_handshake(xhci, &xhci->op_regs->status, STS_HALT,
+ xhci_handshake(&xhci->op_regs->status, STS_HALT,
0, 250 * 1000);
/* step 5: walk topology and initialize portsc,
@@ -1276,7 +1273,7 @@ static int xhci_check_maxpacket(struct xhci_hcd *xhci, unsigned int slot_id,
return -ENOMEM;
command->in_ctx = xhci->devs[slot_id]->in_ctx;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -1374,7 +1371,7 @@ int xhci_urb_enqueue(struct usb_hcd *hcd, struct urb *urb, gfp_t mem_flags)
ret = xhci_check_maxpacket(xhci, slot_id,
ep_index, urb);
if (ret < 0) {
- xhci_urb_free_priv(xhci, urb_priv);
+ xhci_urb_free_priv(urb_priv);
urb->hcpriv = NULL;
return ret;
}
@@ -1440,7 +1437,7 @@ dying:
urb->ep->desc.bEndpointAddress, urb);
ret = -ESHUTDOWN;
free_priv:
- xhci_urb_free_priv(xhci, urb_priv);
+ xhci_urb_free_priv(urb_priv);
urb->hcpriv = NULL;
spin_unlock_irqrestore(&xhci->lock, flags);
return ret;
@@ -1553,7 +1550,7 @@ int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
usb_hcd_unlink_urb_from_ep(hcd, urb);
spin_unlock_irqrestore(&xhci->lock, flags);
usb_hcd_giveback_urb(hcd, urb, -ESHUTDOWN);
- xhci_urb_free_priv(xhci, urb_priv);
+ xhci_urb_free_priv(urb_priv);
return ret;
}
if ((xhci->xhc_state & XHCI_STATE_DYING) ||
@@ -1660,7 +1657,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
in_ctx = xhci->devs[udev->slot_id]->in_ctx;
out_ctx = xhci->devs[udev->slot_id]->out_ctx;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -1676,8 +1673,10 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
cpu_to_le32(EP_STATE_DISABLED)) ||
le32_to_cpu(ctrl_ctx->drop_flags) &
xhci_get_endpoint_flag(&ep->desc)) {
- xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
- __func__, ep);
+ /* Do not warn when called after a usb_device_reset */
+ if (xhci->devs[udev->slot_id]->eps[ep_index].ring != NULL)
+ xhci_warn(xhci, "xHCI %s called with disabled ep %p\n",
+ __func__, ep);
return 0;
}
@@ -1714,7 +1713,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
struct usb_host_endpoint *ep)
{
struct xhci_hcd *xhci;
- struct xhci_container_ctx *in_ctx, *out_ctx;
+ struct xhci_container_ctx *in_ctx;
unsigned int ep_index;
struct xhci_input_control_ctx *ctrl_ctx;
u32 added_ctxs;
@@ -1745,8 +1744,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
virt_dev = xhci->devs[udev->slot_id];
in_ctx = virt_dev->in_ctx;
- out_ctx = virt_dev->out_ctx;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -1758,8 +1756,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
* to add it again without dropping it, reject the addition.
*/
if (virt_dev->eps[ep_index].ring &&
- !(le32_to_cpu(ctrl_ctx->drop_flags) &
- xhci_get_endpoint_flag(&ep->desc))) {
+ !(le32_to_cpu(ctrl_ctx->drop_flags) & added_ctxs)) {
xhci_warn(xhci, "Trying to add endpoint 0x%x "
"without dropping it.\n",
(unsigned int) ep->desc.bEndpointAddress);
@@ -1769,8 +1766,7 @@ int xhci_add_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
/* If the HCD has already noted the endpoint is enabled,
* ignore this request.
*/
- if (le32_to_cpu(ctrl_ctx->add_flags) &
- xhci_get_endpoint_flag(&ep->desc)) {
+ if (le32_to_cpu(ctrl_ctx->add_flags) & added_ctxs) {
xhci_warn(xhci, "xHCI %s called with enabled ep %p\n",
__func__, ep);
return 0;
@@ -1816,7 +1812,7 @@ static void xhci_zero_in_ctx(struct xhci_hcd *xhci, struct xhci_virt_device *vir
struct xhci_slot_ctx *slot_ctx;
int i;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -2542,7 +2538,7 @@ static int xhci_reserve_bandwidth(struct xhci_hcd *xhci,
if (virt_dev->tt_info)
old_active_eps = virt_dev->tt_info->active_eps;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -2639,7 +2635,7 @@ static int xhci_configure_endpoint(struct xhci_hcd *xhci,
spin_lock_irqsave(&xhci->lock, flags);
virt_dev = xhci->devs[udev->slot_id];
- ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
@@ -2758,7 +2754,7 @@ int xhci_check_bandwidth(struct usb_hcd *hcd, struct usb_device *udev)
command->in_ctx = virt_dev->in_ctx;
/* See section 4.6.6 - A0 = 1; A1 = D0 = D1 = 0 */
- ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -2883,7 +2879,7 @@ static void xhci_setup_input_ctx_for_quirk(struct xhci_hcd *xhci,
dma_addr_t addr;
in_ctx = xhci->devs[slot_id]->in_ctx;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -3173,7 +3169,7 @@ int xhci_alloc_streams(struct usb_hcd *hcd, struct usb_device *udev,
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
return -ENOMEM;
}
- ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(config_cmd->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -3328,7 +3324,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
*/
ep_index = xhci_get_endpoint_index(&eps[0]->desc);
command = vdev->eps[ep_index].stream_info->free_streams_command;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
@@ -3346,7 +3342,7 @@ int xhci_free_streams(struct usb_hcd *hcd, struct usb_device *udev,
xhci_endpoint_copy(xhci, command->in_ctx,
vdev->out_ctx, ep_index);
- xhci_setup_no_streams_ep_input_ctx(xhci, ep_ctx,
+ xhci_setup_no_streams_ep_input_ctx(ep_ctx,
&vdev->eps[ep_index]);
}
xhci_setup_input_ctx_for_config_ep(xhci, command->in_ctx,
@@ -3820,7 +3816,7 @@ static int xhci_setup_device(struct usb_hcd *hcd, struct usb_device *udev,
command->completion = &xhci->addr_dev;
slot_ctx = xhci_get_slot_ctx(xhci, virt_dev->in_ctx);
- ctrl_ctx = xhci_get_input_control_ctx(xhci, virt_dev->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(virt_dev->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -4003,7 +3999,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
/* Attempt to issue an Evaluate Context command to change the MEL. */
command = xhci->lpm_command;
- ctrl_ctx = xhci_get_input_control_ctx(xhci, command->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(command->in_ctx);
if (!ctrl_ctx) {
spin_unlock_irqrestore(&xhci->lock, flags);
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
@@ -4741,7 +4737,7 @@ int xhci_update_hub_device(struct usb_hcd *hcd, struct usb_device *hdev,
xhci_dbg(xhci, "Could not allocate xHCI command structure.\n");
return -ENOMEM;
}
- ctrl_ctx = xhci_get_input_control_ctx(xhci, config_cmd->in_ctx);
+ ctrl_ctx = xhci_get_input_control_ctx(config_cmd->in_ctx);
if (!ctrl_ctx) {
xhci_warn(xhci, "%s: Could not get input context, bad type.\n",
__func__);
@@ -4910,6 +4906,10 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks)
if (retval)
goto error;
xhci_dbg(xhci, "Called HCD init\n");
+
+ xhci_info(xhci, "hcc params 0x%08x hci version 0x%x quirks 0x%08x\n",
+ xhci->hcc_params, xhci->hci_version, xhci->quirks);
+
return 0;
error:
kfree(xhci);
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index cc7c5bb7cbcf..974514762a14 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -1605,6 +1605,8 @@ static inline struct usb_hcd *xhci_to_hcd(struct xhci_hcd *xhci)
dev_warn(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
#define xhci_warn_ratelimited(xhci, fmt, args...) \
dev_warn_ratelimited(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
+#define xhci_info(xhci, fmt, args...) \
+ dev_info(xhci_to_hcd(xhci)->self.controller , fmt , ## args)
/*
* Registers should always be accessed with double word or quad word accesses.
@@ -1712,8 +1714,7 @@ void xhci_free_stream_info(struct xhci_hcd *xhci,
void xhci_setup_streams_ep_input_ctx(struct xhci_hcd *xhci,
struct xhci_ep_ctx *ep_ctx,
struct xhci_stream_info *stream_info);
-void xhci_setup_no_streams_ep_input_ctx(struct xhci_hcd *xhci,
- struct xhci_ep_ctx *ep_ctx,
+void xhci_setup_no_streams_ep_input_ctx(struct xhci_ep_ctx *ep_ctx,
struct xhci_virt_ep *ep);
void xhci_free_device_endpoint_resources(struct xhci_hcd *xhci,
struct xhci_virt_device *virt_dev, bool drop_control_ep);
@@ -1727,14 +1728,13 @@ struct xhci_ring *xhci_stream_id_to_ring(
struct xhci_command *xhci_alloc_command(struct xhci_hcd *xhci,
bool allocate_in_ctx, bool allocate_completion,
gfp_t mem_flags);
-void xhci_urb_free_priv(struct xhci_hcd *xhci, struct urb_priv *urb_priv);
+void xhci_urb_free_priv(struct urb_priv *urb_priv);
void xhci_free_command(struct xhci_hcd *xhci,
struct xhci_command *command);
/* xHCI host controller glue */
typedef void (*xhci_get_quirks_t)(struct device *, struct xhci_hcd *);
-int xhci_handshake(struct xhci_hcd *xhci, void __iomem *ptr,
- u32 mask, u32 done, int usec);
+int xhci_handshake(void __iomem *ptr, u32 mask, u32 done, int usec);
void xhci_quiesce(struct xhci_hcd *xhci);
int xhci_halt(struct xhci_hcd *xhci);
int xhci_reset(struct xhci_hcd *xhci);
@@ -1864,7 +1864,7 @@ int xhci_find_slot_id_by_port(struct usb_hcd *hcd, struct xhci_hcd *xhci,
void xhci_ring_device(struct xhci_hcd *xhci, int slot_id);
/* xHCI contexts */
-struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
+struct xhci_input_control_ctx *xhci_get_input_control_ctx(struct xhci_container_ctx *ctx);
struct xhci_slot_ctx *xhci_get_slot_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx);
struct xhci_ep_ctx *xhci_get_ep_ctx(struct xhci_hcd *xhci, struct xhci_container_ctx *ctx, unsigned int ep_index);
diff --git a/drivers/usb/image/microtek.c b/drivers/usb/image/microtek.c
index 37b44b04a701..6431d08c8d9d 100644
--- a/drivers/usb/image/microtek.c
+++ b/drivers/usb/image/microtek.c
@@ -299,9 +299,7 @@ static inline void mts_show_command(struct scsi_cmnd *srb)
MTS_DEBUG( "Command %s (%d bytes)\n", what, srb->cmd_len);
out:
- MTS_DEBUG( " %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x\n",
- srb->cmnd[0], srb->cmnd[1], srb->cmnd[2], srb->cmnd[3], srb->cmnd[4], srb->cmnd[5],
- srb->cmnd[6], srb->cmnd[7], srb->cmnd[8], srb->cmnd[9]);
+ MTS_DEBUG( " %10ph\n", srb->cmnd);
}
#else
diff --git a/drivers/usb/isp1760/Kconfig b/drivers/usb/isp1760/Kconfig
new file mode 100644
index 000000000000..c94b7d953399
--- /dev/null
+++ b/drivers/usb/isp1760/Kconfig
@@ -0,0 +1,59 @@
+config USB_ISP1760
+ tristate "NXP ISP 1760/1761 support"
+ depends on USB || USB_GADGET
+ help
+ Say Y or M here if your system as an ISP1760 USB host controller
+ or an ISP1761 USB dual-role controller.
+
+ This driver does not support isochronous transfers or OTG.
+ This USB controller is usually attached to a non-DMA-Master
+ capable bus. NXP's eval kit brings this chip on PCI card
+ where the chip itself is behind a PLB to simulate such
+ a bus.
+
+ To compile this driver as a module, choose M here: the
+ module will be called isp1760.
+
+config USB_ISP1760_HCD
+ bool
+
+config USB_ISP1761_UDC
+ bool
+
+if USB_ISP1760
+
+choice
+ bool "ISP1760 Mode Selection"
+ default USB_ISP1760_DUAL_ROLE if (USB && USB_GADGET)
+ default USB_ISP1760_HOST_ROLE if (USB && !USB_GADGET)
+ default USB_ISP1760_GADGET_ROLE if (!USB && USB_GADGET)
+
+config USB_ISP1760_HOST_ROLE
+ bool "Host only mode"
+ depends on USB=y || USB=USB_ISP1760
+ select USB_ISP1760_HCD
+ help
+ Select this if you want to use the ISP1760 in host mode only. The
+ gadget function will be disabled.
+
+config USB_ISP1760_GADGET_ROLE
+ bool "Gadget only mode"
+ depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
+ select USB_ISP1761_UDC
+ help
+ Select this if you want to use the ISP1760 in peripheral mode only.
+ The host function will be disabled.
+
+config USB_ISP1760_DUAL_ROLE
+ bool "Dual Role mode"
+ depends on USB=y || USB=USB_ISP1760
+ depends on USB_GADGET=y || USB_GADGET=USB_ISP1760
+ select USB_ISP1760_HCD
+ select USB_ISP1761_UDC
+ help
+ Select this if you want to use the ISP1760 in both host and
+ peripheral modes.
+
+endchoice
+
+endif
diff --git a/drivers/usb/isp1760/Makefile b/drivers/usb/isp1760/Makefile
new file mode 100644
index 000000000000..2b741074ad2b
--- /dev/null
+++ b/drivers/usb/isp1760/Makefile
@@ -0,0 +1,5 @@
+isp1760-y := isp1760-core.o isp1760-if.o
+isp1760-$(CONFIG_USB_ISP1760_HCD) += isp1760-hcd.o
+isp1760-$(CONFIG_USB_ISP1761_UDC) += isp1760-udc.o
+
+obj-$(CONFIG_USB_ISP1760) += isp1760.o
diff --git a/drivers/usb/isp1760/isp1760-core.c b/drivers/usb/isp1760/isp1760-core.c
new file mode 100644
index 000000000000..b9827556455f
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-core.c
@@ -0,0 +1,177 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ * Sebastian Siewior <bigeasy@linutronix.de>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "isp1760-core.h"
+#include "isp1760-hcd.h"
+#include "isp1760-regs.h"
+#include "isp1760-udc.h"
+
+static void isp1760_init_core(struct isp1760_device *isp)
+{
+ u32 otgctrl;
+ u32 hwmode;
+
+ /* Low-level chip reset */
+ if (isp->rst_gpio) {
+ gpiod_set_value_cansleep(isp->rst_gpio, 1);
+ mdelay(50);
+ gpiod_set_value_cansleep(isp->rst_gpio, 0);
+ }
+
+ /*
+ * Reset the host controller, including the CPU interface
+ * configuration.
+ */
+ isp1760_write32(isp->regs, HC_RESET_REG, SW_RESET_RESET_ALL);
+ msleep(100);
+
+ /* Setup HW Mode Control: This assumes a level active-low interrupt */
+ hwmode = HW_DATA_BUS_32BIT;
+
+ if (isp->devflags & ISP1760_FLAG_BUS_WIDTH_16)
+ hwmode &= ~HW_DATA_BUS_32BIT;
+ if (isp->devflags & ISP1760_FLAG_ANALOG_OC)
+ hwmode |= HW_ANA_DIGI_OC;
+ if (isp->devflags & ISP1760_FLAG_DACK_POL_HIGH)
+ hwmode |= HW_DACK_POL_HIGH;
+ if (isp->devflags & ISP1760_FLAG_DREQ_POL_HIGH)
+ hwmode |= HW_DREQ_POL_HIGH;
+ if (isp->devflags & ISP1760_FLAG_INTR_POL_HIGH)
+ hwmode |= HW_INTR_HIGH_ACT;
+ if (isp->devflags & ISP1760_FLAG_INTR_EDGE_TRIG)
+ hwmode |= HW_INTR_EDGE_TRIG;
+
+ /*
+ * The ISP1761 has a dedicated DC IRQ line but supports sharing the HC
+ * IRQ line for both the host and device controllers. Hardcode IRQ
+ * sharing for now and disable the DC interrupts globally to avoid
+ * spurious interrupts during HCD registration.
+ */
+ if (isp->devflags & ISP1760_FLAG_ISP1761) {
+ isp1760_write32(isp->regs, DC_MODE, 0);
+ hwmode |= HW_COMN_IRQ;
+ }
+
+ /*
+ * We have to set this first in case we're in 16-bit mode.
+ * Write it twice to ensure correct upper bits if switching
+ * to 16-bit mode.
+ */
+ isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
+ isp1760_write32(isp->regs, HC_HW_MODE_CTRL, hwmode);
+
+ /*
+ * PORT 1 Control register of the ISP1760 is the OTG control register
+ * on ISP1761.
+ *
+ * TODO: Really support OTG. For now we configure port 1 in device mode
+ * when OTG is requested.
+ */
+ if ((isp->devflags & ISP1760_FLAG_ISP1761) &&
+ (isp->devflags & ISP1760_FLAG_OTG_EN))
+ otgctrl = ((HW_DM_PULLDOWN | HW_DP_PULLDOWN) << 16)
+ | HW_OTG_DISABLE;
+ else
+ otgctrl = (HW_SW_SEL_HC_DC << 16)
+ | (HW_VBUS_DRV | HW_SEL_CP_EXT);
+
+ isp1760_write32(isp->regs, HC_PORT1_CTRL, otgctrl);
+
+ dev_info(isp->dev, "bus width: %u, oc: %s\n",
+ isp->devflags & ISP1760_FLAG_BUS_WIDTH_16 ? 16 : 32,
+ isp->devflags & ISP1760_FLAG_ANALOG_OC ? "analog" : "digital");
+}
+
+void isp1760_set_pullup(struct isp1760_device *isp, bool enable)
+{
+ isp1760_write32(isp->regs, HW_OTG_CTRL_SET,
+ enable ? HW_DP_PULLUP : HW_DP_PULLUP << 16);
+}
+
+int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ struct device *dev, unsigned int devflags)
+{
+ struct isp1760_device *isp;
+ bool udc_disabled = !(devflags & ISP1760_FLAG_ISP1761);
+ int ret;
+
+ /*
+ * If neither the HCD not the UDC is enabled return an error, as no
+ * device would be registered.
+ */
+ if ((!IS_ENABLED(CONFIG_USB_ISP1760_HCD) || usb_disabled()) &&
+ (!IS_ENABLED(CONFIG_USB_ISP1761_UDC) || udc_disabled))
+ return -ENODEV;
+
+ /* prevent usb-core allocating DMA pages */
+ dev->dma_mask = NULL;
+
+ isp = devm_kzalloc(dev, sizeof(*isp), GFP_KERNEL);
+ if (!isp)
+ return -ENOMEM;
+
+ isp->dev = dev;
+ isp->devflags = devflags;
+
+ isp->rst_gpio = devm_gpiod_get_optional(dev, NULL, GPIOD_OUT_HIGH);
+ if (IS_ERR(isp->rst_gpio))
+ return PTR_ERR(isp->rst_gpio);
+
+ isp->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(isp->regs))
+ return PTR_ERR(isp->regs);
+
+ isp1760_init_core(isp);
+
+ if (IS_ENABLED(CONFIG_USB_ISP1760_HCD) && !usb_disabled()) {
+ ret = isp1760_hcd_register(&isp->hcd, isp->regs, mem, irq,
+ irqflags | IRQF_SHARED, dev);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (IS_ENABLED(CONFIG_USB_ISP1761_UDC) && !udc_disabled) {
+ ret = isp1760_udc_register(isp, irq, irqflags | IRQF_SHARED |
+ IRQF_DISABLED);
+ if (ret < 0) {
+ isp1760_hcd_unregister(&isp->hcd);
+ return ret;
+ }
+ }
+
+ dev_set_drvdata(dev, isp);
+
+ return 0;
+}
+
+void isp1760_unregister(struct device *dev)
+{
+ struct isp1760_device *isp = dev_get_drvdata(dev);
+
+ isp1760_udc_unregister(isp);
+ isp1760_hcd_unregister(&isp->hcd);
+}
+
+MODULE_DESCRIPTION("Driver for the ISP1760 USB-controller from NXP");
+MODULE_AUTHOR("Sebastian Siewior <bigeasy@linuxtronix.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/usb/isp1760/isp1760-core.h b/drivers/usb/isp1760/isp1760-core.h
new file mode 100644
index 000000000000..c70f8368a794
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-core.h
@@ -0,0 +1,68 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ * Sebastian Siewior <bigeasy@linutronix.de>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _ISP1760_CORE_H_
+#define _ISP1760_CORE_H_
+
+#include <linux/ioport.h>
+
+#include "isp1760-hcd.h"
+#include "isp1760-udc.h"
+
+struct device;
+struct gpio_desc;
+
+/*
+ * Device flags that can vary from board to board. All of these
+ * indicate the most "atypical" case, so that a devflags of 0 is
+ * a sane default configuration.
+ */
+#define ISP1760_FLAG_BUS_WIDTH_16 0x00000002 /* 16-bit data bus width */
+#define ISP1760_FLAG_OTG_EN 0x00000004 /* Port 1 supports OTG */
+#define ISP1760_FLAG_ANALOG_OC 0x00000008 /* Analog overcurrent */
+#define ISP1760_FLAG_DACK_POL_HIGH 0x00000010 /* DACK active high */
+#define ISP1760_FLAG_DREQ_POL_HIGH 0x00000020 /* DREQ active high */
+#define ISP1760_FLAG_ISP1761 0x00000040 /* Chip is ISP1761 */
+#define ISP1760_FLAG_INTR_POL_HIGH 0x00000080 /* Interrupt polarity active high */
+#define ISP1760_FLAG_INTR_EDGE_TRIG 0x00000100 /* Interrupt edge triggered */
+
+struct isp1760_device {
+ struct device *dev;
+
+ void __iomem *regs;
+ unsigned int devflags;
+ struct gpio_desc *rst_gpio;
+
+ struct isp1760_hcd hcd;
+ struct isp1760_udc udc;
+};
+
+int isp1760_register(struct resource *mem, int irq, unsigned long irqflags,
+ struct device *dev, unsigned int devflags);
+void isp1760_unregister(struct device *dev);
+
+void isp1760_set_pullup(struct isp1760_device *isp, bool enable);
+
+static inline u32 isp1760_read32(void __iomem *base, u32 reg)
+{
+ return readl(base + reg);
+}
+
+static inline void isp1760_write32(void __iomem *base, u32 reg, u32 val)
+{
+ writel(val, base + reg);
+}
+
+#endif
diff --git a/drivers/usb/isp1760/isp1760-hcd.c b/drivers/usb/isp1760/isp1760-hcd.c
new file mode 100644
index 000000000000..eba9b82e2d70
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-hcd.c
@@ -0,0 +1,2235 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * However, the code might contain some bugs. What doesn't work for sure is:
+ * - ISO
+ * - OTG
+ e The interrupt line is configured as active low, level.
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ * (c) 2011 Arvid Brodin <arvid.brodin@enea.com>
+ *
+ */
+#include <linux/gpio/consumer.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/usb/hcd.h>
+#include <linux/debugfs.h>
+#include <linux/uaccess.h>
+#include <linux/io.h>
+#include <linux/mm.h>
+#include <linux/timer.h>
+#include <asm/unaligned.h>
+#include <asm/cacheflush.h>
+
+#include "isp1760-core.h"
+#include "isp1760-hcd.h"
+#include "isp1760-regs.h"
+
+static struct kmem_cache *qtd_cachep;
+static struct kmem_cache *qh_cachep;
+static struct kmem_cache *urb_listitem_cachep;
+
+typedef void (packet_enqueue)(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd);
+
+static inline struct isp1760_hcd *hcd_to_priv(struct usb_hcd *hcd)
+{
+ return *(struct isp1760_hcd **)hcd->hcd_priv;
+}
+
+/* urb state*/
+#define DELETE_URB (0x0008)
+#define NO_TRANSFER_ACTIVE (0xffffffff)
+
+/* Philips Proprietary Transfer Descriptor (PTD) */
+typedef __u32 __bitwise __dw;
+struct ptd {
+ __dw dw0;
+ __dw dw1;
+ __dw dw2;
+ __dw dw3;
+ __dw dw4;
+ __dw dw5;
+ __dw dw6;
+ __dw dw7;
+};
+#define PTD_OFFSET 0x0400
+#define ISO_PTD_OFFSET 0x0400
+#define INT_PTD_OFFSET 0x0800
+#define ATL_PTD_OFFSET 0x0c00
+#define PAYLOAD_OFFSET 0x1000
+
+
+/* ATL */
+/* DW0 */
+#define DW0_VALID_BIT 1
+#define FROM_DW0_VALID(x) ((x) & 0x01)
+#define TO_DW0_LENGTH(x) (((u32) x) << 3)
+#define TO_DW0_MAXPACKET(x) (((u32) x) << 18)
+#define TO_DW0_MULTI(x) (((u32) x) << 29)
+#define TO_DW0_ENDPOINT(x) (((u32) x) << 31)
+/* DW1 */
+#define TO_DW1_DEVICE_ADDR(x) (((u32) x) << 3)
+#define TO_DW1_PID_TOKEN(x) (((u32) x) << 10)
+#define DW1_TRANS_BULK ((u32) 2 << 12)
+#define DW1_TRANS_INT ((u32) 3 << 12)
+#define DW1_TRANS_SPLIT ((u32) 1 << 14)
+#define DW1_SE_USB_LOSPEED ((u32) 2 << 16)
+#define TO_DW1_PORT_NUM(x) (((u32) x) << 18)
+#define TO_DW1_HUB_NUM(x) (((u32) x) << 25)
+/* DW2 */
+#define TO_DW2_DATA_START_ADDR(x) (((u32) x) << 8)
+#define TO_DW2_RL(x) ((x) << 25)
+#define FROM_DW2_RL(x) (((x) >> 25) & 0xf)
+/* DW3 */
+#define FROM_DW3_NRBYTESTRANSFERRED(x) ((x) & 0x7fff)
+#define FROM_DW3_SCS_NRBYTESTRANSFERRED(x) ((x) & 0x07ff)
+#define TO_DW3_NAKCOUNT(x) ((x) << 19)
+#define FROM_DW3_NAKCOUNT(x) (((x) >> 19) & 0xf)
+#define TO_DW3_CERR(x) ((x) << 23)
+#define FROM_DW3_CERR(x) (((x) >> 23) & 0x3)
+#define TO_DW3_DATA_TOGGLE(x) ((x) << 25)
+#define FROM_DW3_DATA_TOGGLE(x) (((x) >> 25) & 0x1)
+#define TO_DW3_PING(x) ((x) << 26)
+#define FROM_DW3_PING(x) (((x) >> 26) & 0x1)
+#define DW3_ERROR_BIT (1 << 28)
+#define DW3_BABBLE_BIT (1 << 29)
+#define DW3_HALT_BIT (1 << 30)
+#define DW3_ACTIVE_BIT (1 << 31)
+#define FROM_DW3_ACTIVE(x) (((x) >> 31) & 0x01)
+
+#define INT_UNDERRUN (1 << 2)
+#define INT_BABBLE (1 << 1)
+#define INT_EXACT (1 << 0)
+
+#define SETUP_PID (2)
+#define IN_PID (1)
+#define OUT_PID (0)
+
+/* Errata 1 */
+#define RL_COUNTER (0)
+#define NAK_COUNTER (0)
+#define ERR_COUNTER (2)
+
+struct isp1760_qtd {
+ u8 packet_type;
+ void *data_buffer;
+ u32 payload_addr;
+
+ /* the rest is HCD-private */
+ struct list_head qtd_list;
+ struct urb *urb;
+ size_t length;
+ size_t actual_length;
+
+ /* QTD_ENQUEUED: waiting for transfer (inactive) */
+ /* QTD_PAYLOAD_ALLOC: chip mem has been allocated for payload */
+ /* QTD_XFER_STARTED: valid ptd has been written to isp176x - only
+ interrupt handler may touch this qtd! */
+ /* QTD_XFER_COMPLETE: payload has been transferred successfully */
+ /* QTD_RETIRE: transfer error/abort qtd */
+#define QTD_ENQUEUED 0
+#define QTD_PAYLOAD_ALLOC 1
+#define QTD_XFER_STARTED 2
+#define QTD_XFER_COMPLETE 3
+#define QTD_RETIRE 4
+ u32 status;
+};
+
+/* Queue head, one for each active endpoint */
+struct isp1760_qh {
+ struct list_head qh_list;
+ struct list_head qtd_list;
+ u32 toggle;
+ u32 ping;
+ int slot;
+ int tt_buffer_dirty; /* See USB2.0 spec section 11.17.5 */
+};
+
+struct urb_listitem {
+ struct list_head urb_list;
+ struct urb *urb;
+};
+
+/*
+ * Access functions for isp176x registers (addresses 0..0x03FF).
+ */
+static u32 reg_read32(void __iomem *base, u32 reg)
+{
+ return isp1760_read32(base, reg);
+}
+
+static void reg_write32(void __iomem *base, u32 reg, u32 val)
+{
+ isp1760_write32(base, reg, val);
+}
+
+/*
+ * Access functions for isp176x memory (offset >= 0x0400).
+ *
+ * bank_reads8() reads memory locations prefetched by an earlier write to
+ * HC_MEMORY_REG (see isp176x datasheet). Unless you want to do fancy multi-
+ * bank optimizations, you should use the more generic mem_reads8() below.
+ *
+ * For access to ptd memory, use the specialized ptd_read() and ptd_write()
+ * below.
+ *
+ * These functions copy via MMIO data to/from the device. memcpy_{to|from}io()
+ * doesn't quite work because some people have to enforce 32-bit access
+ */
+static void bank_reads8(void __iomem *src_base, u32 src_offset, u32 bank_addr,
+ __u32 *dst, u32 bytes)
+{
+ __u32 __iomem *src;
+ u32 val;
+ __u8 *src_byteptr;
+ __u8 *dst_byteptr;
+
+ src = src_base + (bank_addr | src_offset);
+
+ if (src_offset < PAYLOAD_OFFSET) {
+ while (bytes >= 4) {
+ *dst = le32_to_cpu(__raw_readl(src));
+ bytes -= 4;
+ src++;
+ dst++;
+ }
+ } else {
+ while (bytes >= 4) {
+ *dst = __raw_readl(src);
+ bytes -= 4;
+ src++;
+ dst++;
+ }
+ }
+
+ if (!bytes)
+ return;
+
+ /* in case we have 3, 2 or 1 by left. The dst buffer may not be fully
+ * allocated.
+ */
+ if (src_offset < PAYLOAD_OFFSET)
+ val = le32_to_cpu(__raw_readl(src));
+ else
+ val = __raw_readl(src);
+
+ dst_byteptr = (void *) dst;
+ src_byteptr = (void *) &val;
+ while (bytes > 0) {
+ *dst_byteptr = *src_byteptr;
+ dst_byteptr++;
+ src_byteptr++;
+ bytes--;
+ }
+}
+
+static void mem_reads8(void __iomem *src_base, u32 src_offset, void *dst,
+ u32 bytes)
+{
+ reg_write32(src_base, HC_MEMORY_REG, src_offset + ISP_BANK(0));
+ ndelay(90);
+ bank_reads8(src_base, src_offset, ISP_BANK(0), dst, bytes);
+}
+
+static void mem_writes8(void __iomem *dst_base, u32 dst_offset,
+ __u32 const *src, u32 bytes)
+{
+ __u32 __iomem *dst;
+
+ dst = dst_base + dst_offset;
+
+ if (dst_offset < PAYLOAD_OFFSET) {
+ while (bytes >= 4) {
+ __raw_writel(cpu_to_le32(*src), dst);
+ bytes -= 4;
+ src++;
+ dst++;
+ }
+ } else {
+ while (bytes >= 4) {
+ __raw_writel(*src, dst);
+ bytes -= 4;
+ src++;
+ dst++;
+ }
+ }
+
+ if (!bytes)
+ return;
+ /* in case we have 3, 2 or 1 bytes left. The buffer is allocated and the
+ * extra bytes should not be read by the HW.
+ */
+
+ if (dst_offset < PAYLOAD_OFFSET)
+ __raw_writel(cpu_to_le32(*src), dst);
+ else
+ __raw_writel(*src, dst);
+}
+
+/*
+ * Read and write ptds. 'ptd_offset' should be one of ISO_PTD_OFFSET,
+ * INT_PTD_OFFSET, and ATL_PTD_OFFSET. 'slot' should be less than 32.
+ */
+static void ptd_read(void __iomem *base, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ reg_write32(base, HC_MEMORY_REG,
+ ISP_BANK(0) + ptd_offset + slot*sizeof(*ptd));
+ ndelay(90);
+ bank_reads8(base, ptd_offset + slot*sizeof(*ptd), ISP_BANK(0),
+ (void *) ptd, sizeof(*ptd));
+}
+
+static void ptd_write(void __iomem *base, u32 ptd_offset, u32 slot,
+ struct ptd *ptd)
+{
+ mem_writes8(base, ptd_offset + slot*sizeof(*ptd) + sizeof(ptd->dw0),
+ &ptd->dw1, 7*sizeof(ptd->dw1));
+ /* Make sure dw0 gets written last (after other dw's and after payload)
+ since it contains the enable bit */
+ wmb();
+ mem_writes8(base, ptd_offset + slot*sizeof(*ptd), &ptd->dw0,
+ sizeof(ptd->dw0));
+}
+
+
+/* memory management of the 60kb on the chip from 0x1000 to 0xffff */
+static void init_memory(struct isp1760_hcd *priv)
+{
+ int i, curr;
+ u32 payload_addr;
+
+ payload_addr = PAYLOAD_OFFSET;
+ for (i = 0; i < BLOCK_1_NUM; i++) {
+ priv->memory_pool[i].start = payload_addr;
+ priv->memory_pool[i].size = BLOCK_1_SIZE;
+ priv->memory_pool[i].free = 1;
+ payload_addr += priv->memory_pool[i].size;
+ }
+
+ curr = i;
+ for (i = 0; i < BLOCK_2_NUM; i++) {
+ priv->memory_pool[curr + i].start = payload_addr;
+ priv->memory_pool[curr + i].size = BLOCK_2_SIZE;
+ priv->memory_pool[curr + i].free = 1;
+ payload_addr += priv->memory_pool[curr + i].size;
+ }
+
+ curr = i;
+ for (i = 0; i < BLOCK_3_NUM; i++) {
+ priv->memory_pool[curr + i].start = payload_addr;
+ priv->memory_pool[curr + i].size = BLOCK_3_SIZE;
+ priv->memory_pool[curr + i].free = 1;
+ payload_addr += priv->memory_pool[curr + i].size;
+ }
+
+ WARN_ON(payload_addr - priv->memory_pool[0].start > PAYLOAD_AREA_SIZE);
+}
+
+static void alloc_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int i;
+
+ WARN_ON(qtd->payload_addr);
+
+ if (!qtd->length)
+ return;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].size >= qtd->length &&
+ priv->memory_pool[i].free) {
+ priv->memory_pool[i].free = 0;
+ qtd->payload_addr = priv->memory_pool[i].start;
+ return;
+ }
+ }
+}
+
+static void free_mem(struct usb_hcd *hcd, struct isp1760_qtd *qtd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int i;
+
+ if (!qtd->payload_addr)
+ return;
+
+ for (i = 0; i < BLOCKS; i++) {
+ if (priv->memory_pool[i].start == qtd->payload_addr) {
+ WARN_ON(priv->memory_pool[i].free);
+ priv->memory_pool[i].free = 1;
+ qtd->payload_addr = 0;
+ return;
+ }
+ }
+
+ dev_err(hcd->self.controller, "%s: Invalid pointer: %08x\n",
+ __func__, qtd->payload_addr);
+ WARN_ON(1);
+ qtd->payload_addr = 0;
+}
+
+static int handshake(struct usb_hcd *hcd, u32 reg,
+ u32 mask, u32 done, int usec)
+{
+ u32 result;
+
+ do {
+ result = reg_read32(hcd->regs, reg);
+ if (result == ~0)
+ return -ENODEV;
+ result &= mask;
+ if (result == done)
+ return 0;
+ udelay(1);
+ usec--;
+ } while (usec > 0);
+ return -ETIMEDOUT;
+}
+
+/* reset a non-running (STS_HALT == 1) controller */
+static int ehci_reset(struct usb_hcd *hcd)
+{
+ int retval;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ u32 command = reg_read32(hcd->regs, HC_USBCMD);
+
+ command |= CMD_RESET;
+ reg_write32(hcd->regs, HC_USBCMD, command);
+ hcd->state = HC_STATE_HALT;
+ priv->next_statechange = jiffies;
+ retval = handshake(hcd, HC_USBCMD,
+ CMD_RESET, 0, 250 * 1000);
+ return retval;
+}
+
+static struct isp1760_qh *qh_alloc(gfp_t flags)
+{
+ struct isp1760_qh *qh;
+
+ qh = kmem_cache_zalloc(qh_cachep, flags);
+ if (!qh)
+ return NULL;
+
+ INIT_LIST_HEAD(&qh->qh_list);
+ INIT_LIST_HEAD(&qh->qtd_list);
+ qh->slot = -1;
+
+ return qh;
+}
+
+static void qh_free(struct isp1760_qh *qh)
+{
+ WARN_ON(!list_empty(&qh->qtd_list));
+ WARN_ON(qh->slot > -1);
+ kmem_cache_free(qh_cachep, qh);
+}
+
+/* one-time init, only for memory state */
+static int priv_init(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 hcc_params;
+ int i;
+
+ spin_lock_init(&priv->lock);
+
+ for (i = 0; i < QH_END; i++)
+ INIT_LIST_HEAD(&priv->qh_list[i]);
+
+ /*
+ * hw default: 1K periodic list heads, one per frame.
+ * periodic_size can shrink by USBCMD update if hcc_params allows.
+ */
+ priv->periodic_size = DEFAULT_I_TDPS;
+
+ /* controllers may cache some of the periodic schedule ... */
+ hcc_params = reg_read32(hcd->regs, HC_HCCPARAMS);
+ /* full frame cache */
+ if (HCC_ISOC_CACHE(hcc_params))
+ priv->i_thresh = 8;
+ else /* N microframes cached */
+ priv->i_thresh = 2 + HCC_ISOC_THRES(hcc_params);
+
+ return 0;
+}
+
+static int isp1760_hc_setup(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int result;
+ u32 scratch, hwmode;
+
+ reg_write32(hcd->regs, HC_SCRATCH_REG, 0xdeadbabe);
+ /* Change bus pattern */
+ scratch = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+ scratch = reg_read32(hcd->regs, HC_SCRATCH_REG);
+ if (scratch != 0xdeadbabe) {
+ dev_err(hcd->self.controller, "Scratch test failed.\n");
+ return -ENODEV;
+ }
+
+ /*
+ * The RESET_HC bit in the SW_RESET register is supposed to reset the
+ * host controller without touching the CPU interface registers, but at
+ * least on the ISP1761 it seems to behave as the RESET_ALL bit and
+ * reset the whole device. We thus can't use it here, so let's reset
+ * the host controller through the EHCI USB Command register. The device
+ * has been reset in core code anyway, so this shouldn't matter.
+ */
+ reg_write32(hcd->regs, HC_BUFFER_STATUS_REG, 0);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+ reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, NO_TRANSFER_ACTIVE);
+
+ result = ehci_reset(hcd);
+ if (result)
+ return result;
+
+ /* Step 11 passed */
+
+ /* ATL reset */
+ hwmode = reg_read32(hcd->regs, HC_HW_MODE_CTRL) & ~ALL_ATX_RESET;
+ reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode | ALL_ATX_RESET);
+ mdelay(10);
+ reg_write32(hcd->regs, HC_HW_MODE_CTRL, hwmode);
+
+ reg_write32(hcd->regs, HC_INTERRUPT_ENABLE, INTERRUPT_ENABLE_MASK);
+
+ priv->hcs_params = reg_read32(hcd->regs, HC_HCSPARAMS);
+
+ return priv_init(hcd);
+}
+
+static u32 base_to_chip(u32 base)
+{
+ return ((base - 0x400) >> 3);
+}
+
+static int last_qtd_of_urb(struct isp1760_qtd *qtd, struct isp1760_qh *qh)
+{
+ struct urb *urb;
+
+ if (list_is_last(&qtd->qtd_list, &qh->qtd_list))
+ return 1;
+
+ urb = qtd->urb;
+ qtd = list_entry(qtd->qtd_list.next, typeof(*qtd), qtd_list);
+ return (qtd->urb != urb);
+}
+
+/* magic numbers that can affect system performance */
+#define EHCI_TUNE_CERR 3 /* 0-3 qtd retries; 0 == don't stop */
+#define EHCI_TUNE_RL_HS 4 /* nak throttle; see 4.9 */
+#define EHCI_TUNE_RL_TT 0
+#define EHCI_TUNE_MULT_HS 1 /* 1-3 transactions/uframe; 4.10.3 */
+#define EHCI_TUNE_MULT_TT 1
+#define EHCI_TUNE_FLS 2 /* (small) 256 frame schedule */
+
+static void create_ptd_atl(struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct ptd *ptd)
+{
+ u32 maxpacket;
+ u32 multi;
+ u32 rl = RL_COUNTER;
+ u32 nak = NAK_COUNTER;
+
+ memset(ptd, 0, sizeof(*ptd));
+
+ /* according to 3.6.2, max packet len can not be > 0x400 */
+ maxpacket = usb_maxpacket(qtd->urb->dev, qtd->urb->pipe,
+ usb_pipeout(qtd->urb->pipe));
+ multi = 1 + ((maxpacket >> 11) & 0x3);
+ maxpacket &= 0x7ff;
+
+ /* DW0 */
+ ptd->dw0 = DW0_VALID_BIT;
+ ptd->dw0 |= TO_DW0_LENGTH(qtd->length);
+ ptd->dw0 |= TO_DW0_MAXPACKET(maxpacket);
+ ptd->dw0 |= TO_DW0_ENDPOINT(usb_pipeendpoint(qtd->urb->pipe));
+
+ /* DW1 */
+ ptd->dw1 = usb_pipeendpoint(qtd->urb->pipe) >> 1;
+ ptd->dw1 |= TO_DW1_DEVICE_ADDR(usb_pipedevice(qtd->urb->pipe));
+ ptd->dw1 |= TO_DW1_PID_TOKEN(qtd->packet_type);
+
+ if (usb_pipebulk(qtd->urb->pipe))
+ ptd->dw1 |= DW1_TRANS_BULK;
+ else if (usb_pipeint(qtd->urb->pipe))
+ ptd->dw1 |= DW1_TRANS_INT;
+
+ if (qtd->urb->dev->speed != USB_SPEED_HIGH) {
+ /* split transaction */
+
+ ptd->dw1 |= DW1_TRANS_SPLIT;
+ if (qtd->urb->dev->speed == USB_SPEED_LOW)
+ ptd->dw1 |= DW1_SE_USB_LOSPEED;
+
+ ptd->dw1 |= TO_DW1_PORT_NUM(qtd->urb->dev->ttport);
+ ptd->dw1 |= TO_DW1_HUB_NUM(qtd->urb->dev->tt->hub->devnum);
+
+ /* SE bit for Split INT transfers */
+ if (usb_pipeint(qtd->urb->pipe) &&
+ (qtd->urb->dev->speed == USB_SPEED_LOW))
+ ptd->dw1 |= 2 << 16;
+
+ rl = 0;
+ nak = 0;
+ } else {
+ ptd->dw0 |= TO_DW0_MULTI(multi);
+ if (usb_pipecontrol(qtd->urb->pipe) ||
+ usb_pipebulk(qtd->urb->pipe))
+ ptd->dw3 |= TO_DW3_PING(qh->ping);
+ }
+ /* DW2 */
+ ptd->dw2 = 0;
+ ptd->dw2 |= TO_DW2_DATA_START_ADDR(base_to_chip(qtd->payload_addr));
+ ptd->dw2 |= TO_DW2_RL(rl);
+
+ /* DW3 */
+ ptd->dw3 |= TO_DW3_NAKCOUNT(nak);
+ ptd->dw3 |= TO_DW3_DATA_TOGGLE(qh->toggle);
+ if (usb_pipecontrol(qtd->urb->pipe)) {
+ if (qtd->data_buffer == qtd->urb->setup_packet)
+ ptd->dw3 &= ~TO_DW3_DATA_TOGGLE(1);
+ else if (last_qtd_of_urb(qtd, qh))
+ ptd->dw3 |= TO_DW3_DATA_TOGGLE(1);
+ }
+
+ ptd->dw3 |= DW3_ACTIVE_BIT;
+ /* Cerr */
+ ptd->dw3 |= TO_DW3_CERR(ERR_COUNTER);
+}
+
+static void transform_add_int(struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct ptd *ptd)
+{
+ u32 usof;
+ u32 period;
+
+ /*
+ * Most of this is guessing. ISP1761 datasheet is quite unclear, and
+ * the algorithm from the original Philips driver code, which was
+ * pretty much used in this driver before as well, is quite horrendous
+ * and, i believe, incorrect. The code below follows the datasheet and
+ * USB2.0 spec as far as I can tell, and plug/unplug seems to be much
+ * more reliable this way (fingers crossed...).
+ */
+
+ if (qtd->urb->dev->speed == USB_SPEED_HIGH) {
+ /* urb->interval is in units of microframes (1/8 ms) */
+ period = qtd->urb->interval >> 3;
+
+ if (qtd->urb->interval > 4)
+ usof = 0x01; /* One bit set =>
+ interval 1 ms * uFrame-match */
+ else if (qtd->urb->interval > 2)
+ usof = 0x22; /* Two bits set => interval 1/2 ms */
+ else if (qtd->urb->interval > 1)
+ usof = 0x55; /* Four bits set => interval 1/4 ms */
+ else
+ usof = 0xff; /* All bits set => interval 1/8 ms */
+ } else {
+ /* urb->interval is in units of frames (1 ms) */
+ period = qtd->urb->interval;
+ usof = 0x0f; /* Execute Start Split on any of the
+ four first uFrames */
+
+ /*
+ * First 8 bits in dw5 is uSCS and "specifies which uSOF the
+ * complete split needs to be sent. Valid only for IN." Also,
+ * "All bits can be set to one for every transfer." (p 82,
+ * ISP1761 data sheet.) 0x1c is from Philips driver. Where did
+ * that number come from? 0xff seems to work fine...
+ */
+ /* ptd->dw5 = 0x1c; */
+ ptd->dw5 = 0xff; /* Execute Complete Split on any uFrame */
+ }
+
+ period = period >> 1;/* Ensure equal or shorter period than requested */
+ period &= 0xf8; /* Mask off too large values and lowest unused 3 bits */
+
+ ptd->dw2 |= period;
+ ptd->dw4 = usof;
+}
+
+static void create_ptd_int(struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd, struct ptd *ptd)
+{
+ create_ptd_atl(qh, qtd, ptd);
+ transform_add_int(qh, qtd, ptd);
+}
+
+static void isp1760_urb_done(struct usb_hcd *hcd, struct urb *urb)
+__releases(priv->lock)
+__acquires(priv->lock)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+
+ if (!urb->unlinked) {
+ if (urb->status == -EINPROGRESS)
+ urb->status = 0;
+ }
+
+ if (usb_pipein(urb->pipe) && usb_pipetype(urb->pipe) != PIPE_CONTROL) {
+ void *ptr;
+ for (ptr = urb->transfer_buffer;
+ ptr < urb->transfer_buffer + urb->transfer_buffer_length;
+ ptr += PAGE_SIZE)
+ flush_dcache_page(virt_to_page(ptr));
+ }
+
+ /* complete() can reenter this HCD */
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ spin_unlock(&priv->lock);
+ usb_hcd_giveback_urb(hcd, urb, urb->status);
+ spin_lock(&priv->lock);
+}
+
+static struct isp1760_qtd *qtd_alloc(gfp_t flags, struct urb *urb,
+ u8 packet_type)
+{
+ struct isp1760_qtd *qtd;
+
+ qtd = kmem_cache_zalloc(qtd_cachep, flags);
+ if (!qtd)
+ return NULL;
+
+ INIT_LIST_HEAD(&qtd->qtd_list);
+ qtd->urb = urb;
+ qtd->packet_type = packet_type;
+ qtd->status = QTD_ENQUEUED;
+ qtd->actual_length = 0;
+
+ return qtd;
+}
+
+static void qtd_free(struct isp1760_qtd *qtd)
+{
+ WARN_ON(qtd->payload_addr);
+ kmem_cache_free(qtd_cachep, qtd);
+}
+
+static void start_bus_transfer(struct usb_hcd *hcd, u32 ptd_offset, int slot,
+ struct isp1760_slotinfo *slots,
+ struct isp1760_qtd *qtd, struct isp1760_qh *qh,
+ struct ptd *ptd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int skip_map;
+
+ WARN_ON((slot < 0) || (slot > 31));
+ WARN_ON(qtd->length && !qtd->payload_addr);
+ WARN_ON(slots[slot].qtd);
+ WARN_ON(slots[slot].qh);
+ WARN_ON(qtd->status != QTD_PAYLOAD_ALLOC);
+
+ /* Make sure done map has not triggered from some unlinked transfer */
+ if (ptd_offset == ATL_PTD_OFFSET) {
+ priv->atl_done_map |= reg_read32(hcd->regs,
+ HC_ATL_PTD_DONEMAP_REG);
+ priv->atl_done_map &= ~(1 << slot);
+ } else {
+ priv->int_done_map |= reg_read32(hcd->regs,
+ HC_INT_PTD_DONEMAP_REG);
+ priv->int_done_map &= ~(1 << slot);
+ }
+
+ qh->slot = slot;
+ qtd->status = QTD_XFER_STARTED;
+ slots[slot].timestamp = jiffies;
+ slots[slot].qtd = qtd;
+ slots[slot].qh = qh;
+ ptd_write(hcd->regs, ptd_offset, slot, ptd);
+
+ if (ptd_offset == ATL_PTD_OFFSET) {
+ skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map &= ~(1 << qh->slot);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ } else {
+ skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map &= ~(1 << qh->slot);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+ }
+}
+
+static int is_short_bulk(struct isp1760_qtd *qtd)
+{
+ return (usb_pipebulk(qtd->urb->pipe) &&
+ (qtd->actual_length < qtd->length));
+}
+
+static void collect_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct list_head *urb_list)
+{
+ int last_qtd;
+ struct isp1760_qtd *qtd, *qtd_next;
+ struct urb_listitem *urb_listitem;
+
+ list_for_each_entry_safe(qtd, qtd_next, &qh->qtd_list, qtd_list) {
+ if (qtd->status < QTD_XFER_COMPLETE)
+ break;
+
+ last_qtd = last_qtd_of_urb(qtd, qh);
+
+ if ((!last_qtd) && (qtd->status == QTD_RETIRE))
+ qtd_next->status = QTD_RETIRE;
+
+ if (qtd->status == QTD_XFER_COMPLETE) {
+ if (qtd->actual_length) {
+ switch (qtd->packet_type) {
+ case IN_PID:
+ mem_reads8(hcd->regs, qtd->payload_addr,
+ qtd->data_buffer,
+ qtd->actual_length);
+ /* Fall through (?) */
+ case OUT_PID:
+ qtd->urb->actual_length +=
+ qtd->actual_length;
+ /* Fall through ... */
+ case SETUP_PID:
+ break;
+ }
+ }
+
+ if (is_short_bulk(qtd)) {
+ if (qtd->urb->transfer_flags & URB_SHORT_NOT_OK)
+ qtd->urb->status = -EREMOTEIO;
+ if (!last_qtd)
+ qtd_next->status = QTD_RETIRE;
+ }
+ }
+
+ if (qtd->payload_addr)
+ free_mem(hcd, qtd);
+
+ if (last_qtd) {
+ if ((qtd->status == QTD_RETIRE) &&
+ (qtd->urb->status == -EINPROGRESS))
+ qtd->urb->status = -EPIPE;
+ /* Defer calling of urb_done() since it releases lock */
+ urb_listitem = kmem_cache_zalloc(urb_listitem_cachep,
+ GFP_ATOMIC);
+ if (unlikely(!urb_listitem))
+ break; /* Try again on next call */
+ urb_listitem->urb = qtd->urb;
+ list_add_tail(&urb_listitem->urb_list, urb_list);
+ }
+
+ list_del(&qtd->qtd_list);
+ qtd_free(qtd);
+ }
+}
+
+#define ENQUEUE_DEPTH 2
+static void enqueue_qtds(struct usb_hcd *hcd, struct isp1760_qh *qh)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int ptd_offset;
+ struct isp1760_slotinfo *slots;
+ int curr_slot, free_slot;
+ int n;
+ struct ptd ptd;
+ struct isp1760_qtd *qtd;
+
+ if (unlikely(list_empty(&qh->qtd_list))) {
+ WARN_ON(1);
+ return;
+ }
+
+ /* Make sure this endpoint's TT buffer is clean before queueing ptds */
+ if (qh->tt_buffer_dirty)
+ return;
+
+ if (usb_pipeint(list_entry(qh->qtd_list.next, struct isp1760_qtd,
+ qtd_list)->urb->pipe)) {
+ ptd_offset = INT_PTD_OFFSET;
+ slots = priv->int_slots;
+ } else {
+ ptd_offset = ATL_PTD_OFFSET;
+ slots = priv->atl_slots;
+ }
+
+ free_slot = -1;
+ for (curr_slot = 0; curr_slot < 32; curr_slot++) {
+ if ((free_slot == -1) && (slots[curr_slot].qtd == NULL))
+ free_slot = curr_slot;
+ if (slots[curr_slot].qh == qh)
+ break;
+ }
+
+ n = 0;
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list) {
+ if (qtd->status == QTD_ENQUEUED) {
+ WARN_ON(qtd->payload_addr);
+ alloc_mem(hcd, qtd);
+ if ((qtd->length) && (!qtd->payload_addr))
+ break;
+
+ if ((qtd->length) &&
+ ((qtd->packet_type == SETUP_PID) ||
+ (qtd->packet_type == OUT_PID))) {
+ mem_writes8(hcd->regs, qtd->payload_addr,
+ qtd->data_buffer, qtd->length);
+ }
+
+ qtd->status = QTD_PAYLOAD_ALLOC;
+ }
+
+ if (qtd->status == QTD_PAYLOAD_ALLOC) {
+/*
+ if ((curr_slot > 31) && (free_slot == -1))
+ dev_dbg(hcd->self.controller, "%s: No slot "
+ "available for transfer\n", __func__);
+*/
+ /* Start xfer for this endpoint if not already done */
+ if ((curr_slot > 31) && (free_slot > -1)) {
+ if (usb_pipeint(qtd->urb->pipe))
+ create_ptd_int(qh, qtd, &ptd);
+ else
+ create_ptd_atl(qh, qtd, &ptd);
+
+ start_bus_transfer(hcd, ptd_offset, free_slot,
+ slots, qtd, qh, &ptd);
+ curr_slot = free_slot;
+ }
+
+ n++;
+ if (n >= ENQUEUE_DEPTH)
+ break;
+ }
+ }
+}
+
+static void schedule_ptds(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv;
+ struct isp1760_qh *qh, *qh_next;
+ struct list_head *ep_queue;
+ LIST_HEAD(urb_list);
+ struct urb_listitem *urb_listitem, *urb_listitem_next;
+ int i;
+
+ if (!hcd) {
+ WARN_ON(1);
+ return;
+ }
+
+ priv = hcd_to_priv(hcd);
+
+ /*
+ * check finished/retired xfers, transfer payloads, call urb_done()
+ */
+ for (i = 0; i < QH_END; i++) {
+ ep_queue = &priv->qh_list[i];
+ list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list) {
+ collect_qtds(hcd, qh, &urb_list);
+ if (list_empty(&qh->qtd_list))
+ list_del(&qh->qh_list);
+ }
+ }
+
+ list_for_each_entry_safe(urb_listitem, urb_listitem_next, &urb_list,
+ urb_list) {
+ isp1760_urb_done(hcd, urb_listitem->urb);
+ kmem_cache_free(urb_listitem_cachep, urb_listitem);
+ }
+
+ /*
+ * Schedule packets for transfer.
+ *
+ * According to USB2.0 specification:
+ *
+ * 1st prio: interrupt xfers, up to 80 % of bandwidth
+ * 2nd prio: control xfers
+ * 3rd prio: bulk xfers
+ *
+ * ... but let's use a simpler scheme here (mostly because ISP1761 doc
+ * is very unclear on how to prioritize traffic):
+ *
+ * 1) Enqueue any queued control transfers, as long as payload chip mem
+ * and PTD ATL slots are available.
+ * 2) Enqueue any queued INT transfers, as long as payload chip mem
+ * and PTD INT slots are available.
+ * 3) Enqueue any queued bulk transfers, as long as payload chip mem
+ * and PTD ATL slots are available.
+ *
+ * Use double buffering (ENQUEUE_DEPTH==2) as a compromise between
+ * conservation of chip mem and performance.
+ *
+ * I'm sure this scheme could be improved upon!
+ */
+ for (i = 0; i < QH_END; i++) {
+ ep_queue = &priv->qh_list[i];
+ list_for_each_entry_safe(qh, qh_next, ep_queue, qh_list)
+ enqueue_qtds(hcd, qh);
+ }
+}
+
+#define PTD_STATE_QTD_DONE 1
+#define PTD_STATE_QTD_RELOAD 2
+#define PTD_STATE_URB_RETIRE 3
+
+static int check_int_transfer(struct usb_hcd *hcd, struct ptd *ptd,
+ struct urb *urb)
+{
+ __dw dw4;
+ int i;
+
+ dw4 = ptd->dw4;
+ dw4 >>= 8;
+
+ /* FIXME: ISP1761 datasheet does not say what to do with these. Do we
+ need to handle these errors? Is it done in hardware? */
+
+ if (ptd->dw3 & DW3_HALT_BIT) {
+
+ urb->status = -EPROTO; /* Default unknown error */
+
+ for (i = 0; i < 8; i++) {
+ switch (dw4 & 0x7) {
+ case INT_UNDERRUN:
+ dev_dbg(hcd->self.controller, "%s: underrun "
+ "during uFrame %d\n",
+ __func__, i);
+ urb->status = -ECOMM; /* Could not write data */
+ break;
+ case INT_EXACT:
+ dev_dbg(hcd->self.controller, "%s: transaction "
+ "error during uFrame %d\n",
+ __func__, i);
+ urb->status = -EPROTO; /* timeout, bad CRC, PID
+ error etc. */
+ break;
+ case INT_BABBLE:
+ dev_dbg(hcd->self.controller, "%s: babble "
+ "error during uFrame %d\n",
+ __func__, i);
+ urb->status = -EOVERFLOW;
+ break;
+ }
+ dw4 >>= 3;
+ }
+
+ return PTD_STATE_URB_RETIRE;
+ }
+
+ return PTD_STATE_QTD_DONE;
+}
+
+static int check_atl_transfer(struct usb_hcd *hcd, struct ptd *ptd,
+ struct urb *urb)
+{
+ WARN_ON(!ptd);
+ if (ptd->dw3 & DW3_HALT_BIT) {
+ if (ptd->dw3 & DW3_BABBLE_BIT)
+ urb->status = -EOVERFLOW;
+ else if (FROM_DW3_CERR(ptd->dw3))
+ urb->status = -EPIPE; /* Stall */
+ else if (ptd->dw3 & DW3_ERROR_BIT)
+ urb->status = -EPROTO; /* XactErr */
+ else
+ urb->status = -EPROTO; /* Unknown */
+/*
+ dev_dbg(hcd->self.controller, "%s: ptd error:\n"
+ " dw0: %08x dw1: %08x dw2: %08x dw3: %08x\n"
+ " dw4: %08x dw5: %08x dw6: %08x dw7: %08x\n",
+ __func__,
+ ptd->dw0, ptd->dw1, ptd->dw2, ptd->dw3,
+ ptd->dw4, ptd->dw5, ptd->dw6, ptd->dw7);
+*/
+ return PTD_STATE_URB_RETIRE;
+ }
+
+ if ((ptd->dw3 & DW3_ERROR_BIT) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
+ /* Transfer Error, *but* active and no HALT -> reload */
+ dev_dbg(hcd->self.controller, "PID error; reloading ptd\n");
+ return PTD_STATE_QTD_RELOAD;
+ }
+
+ if (!FROM_DW3_NAKCOUNT(ptd->dw3) && (ptd->dw3 & DW3_ACTIVE_BIT)) {
+ /*
+ * NAKs are handled in HW by the chip. Usually if the
+ * device is not able to send data fast enough.
+ * This happens mostly on slower hardware.
+ */
+ return PTD_STATE_QTD_RELOAD;
+ }
+
+ return PTD_STATE_QTD_DONE;
+}
+
+static void handle_done_ptds(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct ptd ptd;
+ struct isp1760_qh *qh;
+ int slot;
+ int state;
+ struct isp1760_slotinfo *slots;
+ u32 ptd_offset;
+ struct isp1760_qtd *qtd;
+ int modified;
+ int skip_map;
+
+ skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ priv->int_done_map &= ~skip_map;
+ skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ priv->atl_done_map &= ~skip_map;
+
+ modified = priv->int_done_map || priv->atl_done_map;
+
+ while (priv->int_done_map || priv->atl_done_map) {
+ if (priv->int_done_map) {
+ /* INT ptd */
+ slot = __ffs(priv->int_done_map);
+ priv->int_done_map &= ~(1 << slot);
+ slots = priv->int_slots;
+ /* This should not trigger, and could be removed if
+ noone have any problems with it triggering: */
+ if (!slots[slot].qh) {
+ WARN_ON(1);
+ continue;
+ }
+ ptd_offset = INT_PTD_OFFSET;
+ ptd_read(hcd->regs, INT_PTD_OFFSET, slot, &ptd);
+ state = check_int_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
+ } else {
+ /* ATL ptd */
+ slot = __ffs(priv->atl_done_map);
+ priv->atl_done_map &= ~(1 << slot);
+ slots = priv->atl_slots;
+ /* This should not trigger, and could be removed if
+ noone have any problems with it triggering: */
+ if (!slots[slot].qh) {
+ WARN_ON(1);
+ continue;
+ }
+ ptd_offset = ATL_PTD_OFFSET;
+ ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ state = check_atl_transfer(hcd, &ptd,
+ slots[slot].qtd->urb);
+ }
+
+ qtd = slots[slot].qtd;
+ slots[slot].qtd = NULL;
+ qh = slots[slot].qh;
+ slots[slot].qh = NULL;
+ qh->slot = -1;
+
+ WARN_ON(qtd->status != QTD_XFER_STARTED);
+
+ switch (state) {
+ case PTD_STATE_QTD_DONE:
+ if ((usb_pipeint(qtd->urb->pipe)) &&
+ (qtd->urb->dev->speed != USB_SPEED_HIGH))
+ qtd->actual_length =
+ FROM_DW3_SCS_NRBYTESTRANSFERRED(ptd.dw3);
+ else
+ qtd->actual_length =
+ FROM_DW3_NRBYTESTRANSFERRED(ptd.dw3);
+
+ qtd->status = QTD_XFER_COMPLETE;
+ if (list_is_last(&qtd->qtd_list, &qh->qtd_list) ||
+ is_short_bulk(qtd))
+ qtd = NULL;
+ else
+ qtd = list_entry(qtd->qtd_list.next,
+ typeof(*qtd), qtd_list);
+
+ qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
+ qh->ping = FROM_DW3_PING(ptd.dw3);
+ break;
+
+ case PTD_STATE_QTD_RELOAD: /* QTD_RETRY, for atls only */
+ qtd->status = QTD_PAYLOAD_ALLOC;
+ ptd.dw0 |= DW0_VALID_BIT;
+ /* RL counter = ERR counter */
+ ptd.dw3 &= ~TO_DW3_NAKCOUNT(0xf);
+ ptd.dw3 |= TO_DW3_NAKCOUNT(FROM_DW2_RL(ptd.dw2));
+ ptd.dw3 &= ~TO_DW3_CERR(3);
+ ptd.dw3 |= TO_DW3_CERR(ERR_COUNTER);
+ qh->toggle = FROM_DW3_DATA_TOGGLE(ptd.dw3);
+ qh->ping = FROM_DW3_PING(ptd.dw3);
+ break;
+
+ case PTD_STATE_URB_RETIRE:
+ qtd->status = QTD_RETIRE;
+ if ((qtd->urb->dev->speed != USB_SPEED_HIGH) &&
+ (qtd->urb->status != -EPIPE) &&
+ (qtd->urb->status != -EREMOTEIO)) {
+ qh->tt_buffer_dirty = 1;
+ if (usb_hub_clear_tt_buffer(qtd->urb))
+ /* Clear failed; let's hope things work
+ anyway */
+ qh->tt_buffer_dirty = 0;
+ }
+ qtd = NULL;
+ qh->toggle = 0;
+ qh->ping = 0;
+ break;
+
+ default:
+ WARN_ON(1);
+ continue;
+ }
+
+ if (qtd && (qtd->status == QTD_PAYLOAD_ALLOC)) {
+ if (slots == priv->int_slots) {
+ if (state == PTD_STATE_QTD_RELOAD)
+ dev_err(hcd->self.controller,
+ "%s: PTD_STATE_QTD_RELOAD on "
+ "interrupt packet\n", __func__);
+ if (state != PTD_STATE_QTD_RELOAD)
+ create_ptd_int(qh, qtd, &ptd);
+ } else {
+ if (state != PTD_STATE_QTD_RELOAD)
+ create_ptd_atl(qh, qtd, &ptd);
+ }
+
+ start_bus_transfer(hcd, ptd_offset, slot, slots, qtd,
+ qh, &ptd);
+ }
+ }
+
+ if (modified)
+ schedule_ptds(hcd);
+}
+
+static irqreturn_t isp1760_irq(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 imask;
+ irqreturn_t irqret = IRQ_NONE;
+
+ spin_lock(&priv->lock);
+
+ if (!(hcd->state & HC_STATE_RUNNING))
+ goto leave;
+
+ imask = reg_read32(hcd->regs, HC_INTERRUPT_REG);
+ if (unlikely(!imask))
+ goto leave;
+ reg_write32(hcd->regs, HC_INTERRUPT_REG, imask); /* Clear */
+
+ priv->int_done_map |= reg_read32(hcd->regs, HC_INT_PTD_DONEMAP_REG);
+ priv->atl_done_map |= reg_read32(hcd->regs, HC_ATL_PTD_DONEMAP_REG);
+
+ handle_done_ptds(hcd);
+
+ irqret = IRQ_HANDLED;
+leave:
+ spin_unlock(&priv->lock);
+
+ return irqret;
+}
+
+/*
+ * Workaround for problem described in chip errata 2:
+ *
+ * Sometimes interrupts are not generated when ATL (not INT?) completion occurs.
+ * One solution suggested in the errata is to use SOF interrupts _instead_of_
+ * ATL done interrupts (the "instead of" might be important since it seems
+ * enabling ATL interrupts also causes the chip to sometimes - rarely - "forget"
+ * to set the PTD's done bit in addition to not generating an interrupt!).
+ *
+ * So if we use SOF + ATL interrupts, we sometimes get stale PTDs since their
+ * done bit is not being set. This is bad - it blocks the endpoint until reboot.
+ *
+ * If we use SOF interrupts only, we get latency between ptd completion and the
+ * actual handling. This is very noticeable in testusb runs which takes several
+ * minutes longer without ATL interrupts.
+ *
+ * A better solution is to run the code below every SLOT_CHECK_PERIOD ms. If it
+ * finds active ATL slots which are older than SLOT_TIMEOUT ms, it checks the
+ * slot's ACTIVE and VALID bits. If these are not set, the ptd is considered
+ * completed and its done map bit is set.
+ *
+ * The values of SLOT_TIMEOUT and SLOT_CHECK_PERIOD have been arbitrarily chosen
+ * not to cause too much lag when this HW bug occurs, while still hopefully
+ * ensuring that the check does not falsely trigger.
+ */
+#define SLOT_TIMEOUT 300
+#define SLOT_CHECK_PERIOD 200
+static struct timer_list errata2_timer;
+
+static void errata2_function(unsigned long data)
+{
+ struct usb_hcd *hcd = (struct usb_hcd *) data;
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int slot;
+ struct ptd ptd;
+ unsigned long spinflags;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+
+ for (slot = 0; slot < 32; slot++)
+ if (priv->atl_slots[slot].qh && time_after(jiffies,
+ priv->atl_slots[slot].timestamp +
+ SLOT_TIMEOUT * HZ / 1000)) {
+ ptd_read(hcd->regs, ATL_PTD_OFFSET, slot, &ptd);
+ if (!FROM_DW0_VALID(ptd.dw0) &&
+ !FROM_DW3_ACTIVE(ptd.dw3))
+ priv->atl_done_map |= 1 << slot;
+ }
+
+ if (priv->atl_done_map)
+ handle_done_ptds(hcd);
+
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+
+ errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+ add_timer(&errata2_timer);
+}
+
+static int isp1760_run(struct usb_hcd *hcd)
+{
+ int retval;
+ u32 temp;
+ u32 command;
+ u32 chipid;
+
+ hcd->uses_new_polling = 1;
+
+ hcd->state = HC_STATE_RUNNING;
+
+ /* Set PTD interrupt AND & OR maps */
+ reg_write32(hcd->regs, HC_ATL_IRQ_MASK_AND_REG, 0);
+ reg_write32(hcd->regs, HC_ATL_IRQ_MASK_OR_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_INT_IRQ_MASK_AND_REG, 0);
+ reg_write32(hcd->regs, HC_INT_IRQ_MASK_OR_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_ISO_IRQ_MASK_AND_REG, 0);
+ reg_write32(hcd->regs, HC_ISO_IRQ_MASK_OR_REG, 0xffffffff);
+ /* step 23 passed */
+
+ temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+ reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp | HW_GLOBAL_INTR_EN);
+
+ command = reg_read32(hcd->regs, HC_USBCMD);
+ command &= ~(CMD_LRESET|CMD_RESET);
+ command |= CMD_RUN;
+ reg_write32(hcd->regs, HC_USBCMD, command);
+
+ retval = handshake(hcd, HC_USBCMD, CMD_RUN, CMD_RUN, 250 * 1000);
+ if (retval)
+ return retval;
+
+ /*
+ * XXX
+ * Spec says to write FLAG_CF as last config action, priv code grabs
+ * the semaphore while doing so.
+ */
+ down_write(&ehci_cf_port_reset_rwsem);
+ reg_write32(hcd->regs, HC_CONFIGFLAG, FLAG_CF);
+
+ retval = handshake(hcd, HC_CONFIGFLAG, FLAG_CF, FLAG_CF, 250 * 1000);
+ up_write(&ehci_cf_port_reset_rwsem);
+ if (retval)
+ return retval;
+
+ setup_timer(&errata2_timer, errata2_function, (unsigned long)hcd);
+ errata2_timer.expires = jiffies + SLOT_CHECK_PERIOD * HZ / 1000;
+ add_timer(&errata2_timer);
+
+ chipid = reg_read32(hcd->regs, HC_CHIP_ID_REG);
+ dev_info(hcd->self.controller, "USB ISP %04x HW rev. %d started\n",
+ chipid & 0xffff, chipid >> 16);
+
+ /* PTD Register Init Part 2, Step 28 */
+
+ /* Setup registers controlling PTD checking */
+ reg_write32(hcd->regs, HC_ATL_PTD_LASTPTD_REG, 0x80000000);
+ reg_write32(hcd->regs, HC_INT_PTD_LASTPTD_REG, 0x80000000);
+ reg_write32(hcd->regs, HC_ISO_PTD_LASTPTD_REG, 0x00000001);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_ISO_PTD_SKIPMAP_REG, 0xffffffff);
+ reg_write32(hcd->regs, HC_BUFFER_STATUS_REG,
+ ATL_BUF_FILL | INT_BUF_FILL);
+
+ /* GRR this is run-once init(), being done every time the HC starts.
+ * So long as they're part of class devices, we can't do it init()
+ * since the class device isn't created that early.
+ */
+ return 0;
+}
+
+static int qtd_fill(struct isp1760_qtd *qtd, void *databuffer, size_t len)
+{
+ qtd->data_buffer = databuffer;
+
+ if (len > MAX_PAYLOAD_SIZE)
+ len = MAX_PAYLOAD_SIZE;
+ qtd->length = len;
+
+ return qtd->length;
+}
+
+static void qtd_list_free(struct list_head *qtd_list)
+{
+ struct isp1760_qtd *qtd, *qtd_next;
+
+ list_for_each_entry_safe(qtd, qtd_next, qtd_list, qtd_list) {
+ list_del(&qtd->qtd_list);
+ qtd_free(qtd);
+ }
+}
+
+/*
+ * Packetize urb->transfer_buffer into list of packets of size wMaxPacketSize.
+ * Also calculate the PID type (SETUP/IN/OUT) for each packet.
+ */
+#define max_packet(wMaxPacketSize) ((wMaxPacketSize) & 0x07ff)
+static void packetize_urb(struct usb_hcd *hcd,
+ struct urb *urb, struct list_head *head, gfp_t flags)
+{
+ struct isp1760_qtd *qtd;
+ void *buf;
+ int len, maxpacketsize;
+ u8 packet_type;
+
+ /*
+ * URBs map to sequences of QTDs: one logical transaction
+ */
+
+ if (!urb->transfer_buffer && urb->transfer_buffer_length) {
+ /* XXX This looks like usb storage / SCSI bug */
+ dev_err(hcd->self.controller,
+ "buf is null, dma is %08lx len is %d\n",
+ (long unsigned)urb->transfer_dma,
+ urb->transfer_buffer_length);
+ WARN_ON(1);
+ }
+
+ if (usb_pipein(urb->pipe))
+ packet_type = IN_PID;
+ else
+ packet_type = OUT_PID;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ qtd = qtd_alloc(flags, urb, SETUP_PID);
+ if (!qtd)
+ goto cleanup;
+ qtd_fill(qtd, urb->setup_packet, sizeof(struct usb_ctrlrequest));
+ list_add_tail(&qtd->qtd_list, head);
+
+ /* for zero length DATA stages, STATUS is always IN */
+ if (urb->transfer_buffer_length == 0)
+ packet_type = IN_PID;
+ }
+
+ maxpacketsize = max_packet(usb_maxpacket(urb->dev, urb->pipe,
+ usb_pipeout(urb->pipe)));
+
+ /*
+ * buffer gets wrapped in one or more qtds;
+ * last one may be "short" (including zero len)
+ * and may serve as a control status ack
+ */
+ buf = urb->transfer_buffer;
+ len = urb->transfer_buffer_length;
+
+ for (;;) {
+ int this_qtd_len;
+
+ qtd = qtd_alloc(flags, urb, packet_type);
+ if (!qtd)
+ goto cleanup;
+ this_qtd_len = qtd_fill(qtd, buf, len);
+ list_add_tail(&qtd->qtd_list, head);
+
+ len -= this_qtd_len;
+ buf += this_qtd_len;
+
+ if (len <= 0)
+ break;
+ }
+
+ /*
+ * control requests may need a terminating data "status" ack;
+ * bulk ones may need a terminating short packet (zero length).
+ */
+ if (urb->transfer_buffer_length != 0) {
+ int one_more = 0;
+
+ if (usb_pipecontrol(urb->pipe)) {
+ one_more = 1;
+ if (packet_type == IN_PID)
+ packet_type = OUT_PID;
+ else
+ packet_type = IN_PID;
+ } else if (usb_pipebulk(urb->pipe)
+ && (urb->transfer_flags & URB_ZERO_PACKET)
+ && !(urb->transfer_buffer_length %
+ maxpacketsize)) {
+ one_more = 1;
+ }
+ if (one_more) {
+ qtd = qtd_alloc(flags, urb, packet_type);
+ if (!qtd)
+ goto cleanup;
+
+ /* never any data in such packets */
+ qtd_fill(qtd, NULL, 0);
+ list_add_tail(&qtd->qtd_list, head);
+ }
+ }
+
+ return;
+
+cleanup:
+ qtd_list_free(head);
+}
+
+static int isp1760_urb_enqueue(struct usb_hcd *hcd, struct urb *urb,
+ gfp_t mem_flags)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct list_head *ep_queue;
+ struct isp1760_qh *qh, *qhit;
+ unsigned long spinflags;
+ LIST_HEAD(new_qtds);
+ int retval;
+ int qh_in_queue;
+
+ switch (usb_pipetype(urb->pipe)) {
+ case PIPE_CONTROL:
+ ep_queue = &priv->qh_list[QH_CONTROL];
+ break;
+ case PIPE_BULK:
+ ep_queue = &priv->qh_list[QH_BULK];
+ break;
+ case PIPE_INTERRUPT:
+ if (urb->interval < 0)
+ return -EINVAL;
+ /* FIXME: Check bandwidth */
+ ep_queue = &priv->qh_list[QH_INTERRUPT];
+ break;
+ case PIPE_ISOCHRONOUS:
+ dev_err(hcd->self.controller, "%s: isochronous USB packets "
+ "not yet supported\n",
+ __func__);
+ return -EPIPE;
+ default:
+ dev_err(hcd->self.controller, "%s: unknown pipe type\n",
+ __func__);
+ return -EPIPE;
+ }
+
+ if (usb_pipein(urb->pipe))
+ urb->actual_length = 0;
+
+ packetize_urb(hcd, urb, &new_qtds, mem_flags);
+ if (list_empty(&new_qtds))
+ return -ENOMEM;
+
+ retval = 0;
+ spin_lock_irqsave(&priv->lock, spinflags);
+
+ if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) {
+ retval = -ESHUTDOWN;
+ qtd_list_free(&new_qtds);
+ goto out;
+ }
+ retval = usb_hcd_link_urb_to_ep(hcd, urb);
+ if (retval) {
+ qtd_list_free(&new_qtds);
+ goto out;
+ }
+
+ qh = urb->ep->hcpriv;
+ if (qh) {
+ qh_in_queue = 0;
+ list_for_each_entry(qhit, ep_queue, qh_list) {
+ if (qhit == qh) {
+ qh_in_queue = 1;
+ break;
+ }
+ }
+ if (!qh_in_queue)
+ list_add_tail(&qh->qh_list, ep_queue);
+ } else {
+ qh = qh_alloc(GFP_ATOMIC);
+ if (!qh) {
+ retval = -ENOMEM;
+ usb_hcd_unlink_urb_from_ep(hcd, urb);
+ qtd_list_free(&new_qtds);
+ goto out;
+ }
+ list_add_tail(&qh->qh_list, ep_queue);
+ urb->ep->hcpriv = qh;
+ }
+
+ list_splice_tail(&new_qtds, &qh->qtd_list);
+ schedule_ptds(hcd);
+
+out:
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+ return retval;
+}
+
+static void kill_transfer(struct usb_hcd *hcd, struct urb *urb,
+ struct isp1760_qh *qh)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int skip_map;
+
+ WARN_ON(qh->slot == -1);
+
+ /* We need to forcefully reclaim the slot since some transfers never
+ return, e.g. interrupt transfers and NAKed bulk transfers. */
+ if (usb_pipecontrol(urb->pipe) || usb_pipebulk(urb->pipe)) {
+ skip_map = reg_read32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG);
+ skip_map |= (1 << qh->slot);
+ reg_write32(hcd->regs, HC_ATL_PTD_SKIPMAP_REG, skip_map);
+ priv->atl_slots[qh->slot].qh = NULL;
+ priv->atl_slots[qh->slot].qtd = NULL;
+ } else {
+ skip_map = reg_read32(hcd->regs, HC_INT_PTD_SKIPMAP_REG);
+ skip_map |= (1 << qh->slot);
+ reg_write32(hcd->regs, HC_INT_PTD_SKIPMAP_REG, skip_map);
+ priv->int_slots[qh->slot].qh = NULL;
+ priv->int_slots[qh->slot].qtd = NULL;
+ }
+
+ qh->slot = -1;
+}
+
+/*
+ * Retire the qtds beginning at 'qtd' and belonging all to the same urb, killing
+ * any active transfer belonging to the urb in the process.
+ */
+static void dequeue_urb_from_qtd(struct usb_hcd *hcd, struct isp1760_qh *qh,
+ struct isp1760_qtd *qtd)
+{
+ struct urb *urb;
+ int urb_was_running;
+
+ urb = qtd->urb;
+ urb_was_running = 0;
+ list_for_each_entry_from(qtd, &qh->qtd_list, qtd_list) {
+ if (qtd->urb != urb)
+ break;
+
+ if (qtd->status >= QTD_XFER_STARTED)
+ urb_was_running = 1;
+ if (last_qtd_of_urb(qtd, qh) &&
+ (qtd->status >= QTD_XFER_COMPLETE))
+ urb_was_running = 0;
+
+ if (qtd->status == QTD_XFER_STARTED)
+ kill_transfer(hcd, urb, qh);
+ qtd->status = QTD_RETIRE;
+ }
+
+ if ((urb->dev->speed != USB_SPEED_HIGH) && urb_was_running) {
+ qh->tt_buffer_dirty = 1;
+ if (usb_hub_clear_tt_buffer(urb))
+ /* Clear failed; let's hope things work anyway */
+ qh->tt_buffer_dirty = 0;
+ }
+}
+
+static int isp1760_urb_dequeue(struct usb_hcd *hcd, struct urb *urb,
+ int status)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ unsigned long spinflags;
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ int retval = 0;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+ retval = usb_hcd_check_unlink_urb(hcd, urb, status);
+ if (retval)
+ goto out;
+
+ qh = urb->ep->hcpriv;
+ if (!qh) {
+ retval = -EINVAL;
+ goto out;
+ }
+
+ list_for_each_entry(qtd, &qh->qtd_list, qtd_list)
+ if (qtd->urb == urb) {
+ dequeue_urb_from_qtd(hcd, qh, qtd);
+ list_move(&qtd->qtd_list, &qh->qtd_list);
+ break;
+ }
+
+ urb->status = status;
+ schedule_ptds(hcd);
+
+out:
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+ return retval;
+}
+
+static void isp1760_endpoint_disable(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ unsigned long spinflags;
+ struct isp1760_qh *qh, *qh_iter;
+ int i;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+
+ qh = ep->hcpriv;
+ if (!qh)
+ goto out;
+
+ WARN_ON(!list_empty(&qh->qtd_list));
+
+ for (i = 0; i < QH_END; i++)
+ list_for_each_entry(qh_iter, &priv->qh_list[i], qh_list)
+ if (qh_iter == qh) {
+ list_del(&qh_iter->qh_list);
+ i = QH_END;
+ break;
+ }
+ qh_free(qh);
+ ep->hcpriv = NULL;
+
+ schedule_ptds(hcd);
+
+out:
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+}
+
+static int isp1760_hub_status_data(struct usb_hcd *hcd, char *buf)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 temp, status = 0;
+ u32 mask;
+ int retval = 1;
+ unsigned long flags;
+
+ /* if !PM, root hub timers won't get shut down ... */
+ if (!HC_IS_RUNNING(hcd->state))
+ return 0;
+
+ /* init status to no-changes */
+ buf[0] = 0;
+ mask = PORT_CSC;
+
+ spin_lock_irqsave(&priv->lock, flags);
+ temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+ if (temp & PORT_OWNER) {
+ if (temp & PORT_CSC) {
+ temp &= ~PORT_CSC;
+ reg_write32(hcd->regs, HC_PORTSC1, temp);
+ goto done;
+ }
+ }
+
+ /*
+ * Return status information even for ports with OWNER set.
+ * Otherwise hub_wq wouldn't see the disconnect event when a
+ * high-speed device is switched over to the companion
+ * controller by the user.
+ */
+
+ if ((temp & mask) != 0
+ || ((temp & PORT_RESUME) != 0
+ && time_after_eq(jiffies,
+ priv->reset_done))) {
+ buf [0] |= 1 << (0 + 1);
+ status = STS_PCD;
+ }
+ /* FIXME autosuspend idle root hubs */
+done:
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return status ? retval : 0;
+}
+
+static void isp1760_hub_descriptor(struct isp1760_hcd *priv,
+ struct usb_hub_descriptor *desc)
+{
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u16 temp;
+
+ desc->bDescriptorType = 0x29;
+ /* priv 1.0, 2.3.9 says 20ms max */
+ desc->bPwrOn2PwrGood = 10;
+ desc->bHubContrCurrent = 0;
+
+ desc->bNbrPorts = ports;
+ temp = 1 + (ports / 8);
+ desc->bDescLength = 7 + 2 * temp;
+
+ /* ports removable, and usb 1.0 legacy PortPwrCtrlMask */
+ memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
+ memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
+
+ /* per-port overcurrent reporting */
+ temp = HUB_CHAR_INDV_PORT_OCPM;
+ if (HCS_PPC(priv->hcs_params))
+ /* per-port power control */
+ temp |= HUB_CHAR_INDV_PORT_LPSM;
+ else
+ /* no power switching */
+ temp |= HUB_CHAR_NO_LPSM;
+ desc->wHubCharacteristics = cpu_to_le16(temp);
+}
+
+#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
+
+static int check_reset_complete(struct usb_hcd *hcd, int index,
+ int port_status)
+{
+ if (!(port_status & PORT_CONNECT))
+ return port_status;
+
+ /* if reset finished and it's still not enabled -- handoff */
+ if (!(port_status & PORT_PE)) {
+
+ dev_info(hcd->self.controller,
+ "port %d full speed --> companion\n",
+ index + 1);
+
+ port_status |= PORT_OWNER;
+ port_status &= ~PORT_RWC_BITS;
+ reg_write32(hcd->regs, HC_PORTSC1, port_status);
+
+ } else
+ dev_info(hcd->self.controller, "port %d high speed\n",
+ index + 1);
+
+ return port_status;
+}
+
+static int isp1760_hub_control(struct usb_hcd *hcd, u16 typeReq,
+ u16 wValue, u16 wIndex, char *buf, u16 wLength)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ int ports = HCS_N_PORTS(priv->hcs_params);
+ u32 temp, status;
+ unsigned long flags;
+ int retval = 0;
+ unsigned selector;
+
+ /*
+ * FIXME: support SetPortFeatures USB_PORT_FEAT_INDICATOR.
+ * HCS_INDICATOR may say we can change LEDs to off/amber/green.
+ * (track current state ourselves) ... blink for diagnostics,
+ * power, "this is the one", etc. EHCI spec supports this.
+ */
+
+ spin_lock_irqsave(&priv->lock, flags);
+ switch (typeReq) {
+ case ClearHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case ClearPortFeature:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+ /*
+ * Even if OWNER is set, so the port is owned by the
+ * companion controller, hub_wq needs to be able to clear
+ * the port-change status bits (especially
+ * USB_PORT_STAT_C_CONNECTION).
+ */
+
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_PE);
+ break;
+ case USB_PORT_FEAT_C_ENABLE:
+ /* XXX error? */
+ break;
+ case USB_PORT_FEAT_SUSPEND:
+ if (temp & PORT_RESET)
+ goto error;
+
+ if (temp & PORT_SUSPEND) {
+ if ((temp & PORT_PE) == 0)
+ goto error;
+ /* resume signaling for 20 msec */
+ temp &= ~(PORT_RWC_BITS);
+ reg_write32(hcd->regs, HC_PORTSC1,
+ temp | PORT_RESUME);
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(20);
+ }
+ break;
+ case USB_PORT_FEAT_C_SUSPEND:
+ /* we auto-clear this feature */
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ reg_write32(hcd->regs, HC_PORTSC1,
+ temp & ~PORT_POWER);
+ break;
+ case USB_PORT_FEAT_C_CONNECTION:
+ reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_CSC);
+ break;
+ case USB_PORT_FEAT_C_OVER_CURRENT:
+ /* XXX error ?*/
+ break;
+ case USB_PORT_FEAT_C_RESET:
+ /* GetPortStatus clears reset */
+ break;
+ default:
+ goto error;
+ }
+ reg_read32(hcd->regs, HC_USBCMD);
+ break;
+ case GetHubDescriptor:
+ isp1760_hub_descriptor(priv, (struct usb_hub_descriptor *)
+ buf);
+ break;
+ case GetHubStatus:
+ /* no hub-wide feature/status flags */
+ memset(buf, 0, 4);
+ break;
+ case GetPortStatus:
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ status = 0;
+ temp = reg_read32(hcd->regs, HC_PORTSC1);
+
+ /* wPortChange bits */
+ if (temp & PORT_CSC)
+ status |= USB_PORT_STAT_C_CONNECTION << 16;
+
+
+ /* whoever resumes must GetPortStatus to complete it!! */
+ if (temp & PORT_RESUME) {
+ dev_err(hcd->self.controller, "Port resume should be skipped.\n");
+
+ /* Remote Wakeup received? */
+ if (!priv->reset_done) {
+ /* resume signaling for 20 msec */
+ priv->reset_done = jiffies
+ + msecs_to_jiffies(20);
+ /* check the port again */
+ mod_timer(&hcd->rh_timer, priv->reset_done);
+ }
+
+ /* resume completed? */
+ else if (time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= USB_PORT_STAT_C_SUSPEND << 16;
+ priv->reset_done = 0;
+
+ /* stop resume signaling */
+ temp = reg_read32(hcd->regs, HC_PORTSC1);
+ reg_write32(hcd->regs, HC_PORTSC1,
+ temp & ~(PORT_RWC_BITS | PORT_RESUME));
+ retval = handshake(hcd, HC_PORTSC1,
+ PORT_RESUME, 0, 2000 /* 2msec */);
+ if (retval != 0) {
+ dev_err(hcd->self.controller,
+ "port %d resume error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+ temp &= ~(PORT_SUSPEND|PORT_RESUME|(3<<10));
+ }
+ }
+
+ /* whoever resets must GetPortStatus to complete it!! */
+ if ((temp & PORT_RESET)
+ && time_after_eq(jiffies,
+ priv->reset_done)) {
+ status |= USB_PORT_STAT_C_RESET << 16;
+ priv->reset_done = 0;
+
+ /* force reset to complete */
+ reg_write32(hcd->regs, HC_PORTSC1, temp & ~PORT_RESET);
+ /* REVISIT: some hardware needs 550+ usec to clear
+ * this bit; seems too long to spin routinely...
+ */
+ retval = handshake(hcd, HC_PORTSC1,
+ PORT_RESET, 0, 750);
+ if (retval != 0) {
+ dev_err(hcd->self.controller, "port %d reset error %d\n",
+ wIndex + 1, retval);
+ goto error;
+ }
+
+ /* see what we found out */
+ temp = check_reset_complete(hcd, wIndex,
+ reg_read32(hcd->regs, HC_PORTSC1));
+ }
+ /*
+ * Even if OWNER is set, there's no harm letting hub_wq
+ * see the wPortStatus values (they should all be 0 except
+ * for PORT_POWER anyway).
+ */
+
+ if (temp & PORT_OWNER)
+ dev_err(hcd->self.controller, "PORT_OWNER is set\n");
+
+ if (temp & PORT_CONNECT) {
+ status |= USB_PORT_STAT_CONNECTION;
+ /* status may be from integrated TT */
+ status |= USB_PORT_STAT_HIGH_SPEED;
+ }
+ if (temp & PORT_PE)
+ status |= USB_PORT_STAT_ENABLE;
+ if (temp & (PORT_SUSPEND|PORT_RESUME))
+ status |= USB_PORT_STAT_SUSPEND;
+ if (temp & PORT_RESET)
+ status |= USB_PORT_STAT_RESET;
+ if (temp & PORT_POWER)
+ status |= USB_PORT_STAT_POWER;
+
+ put_unaligned(cpu_to_le32(status), (__le32 *) buf);
+ break;
+ case SetHubFeature:
+ switch (wValue) {
+ case C_HUB_LOCAL_POWER:
+ case C_HUB_OVER_CURRENT:
+ /* no hub-wide feature/status flags */
+ break;
+ default:
+ goto error;
+ }
+ break;
+ case SetPortFeature:
+ selector = wIndex >> 8;
+ wIndex &= 0xff;
+ if (!wIndex || wIndex > ports)
+ goto error;
+ wIndex--;
+ temp = reg_read32(hcd->regs, HC_PORTSC1);
+ if (temp & PORT_OWNER)
+ break;
+
+/* temp &= ~PORT_RWC_BITS; */
+ switch (wValue) {
+ case USB_PORT_FEAT_ENABLE:
+ reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_PE);
+ break;
+
+ case USB_PORT_FEAT_SUSPEND:
+ if ((temp & PORT_PE) == 0
+ || (temp & PORT_RESET) != 0)
+ goto error;
+
+ reg_write32(hcd->regs, HC_PORTSC1, temp | PORT_SUSPEND);
+ break;
+ case USB_PORT_FEAT_POWER:
+ if (HCS_PPC(priv->hcs_params))
+ reg_write32(hcd->regs, HC_PORTSC1,
+ temp | PORT_POWER);
+ break;
+ case USB_PORT_FEAT_RESET:
+ if (temp & PORT_RESUME)
+ goto error;
+ /* line status bits may report this as low speed,
+ * which can be fine if this root hub has a
+ * transaction translator built in.
+ */
+ if ((temp & (PORT_PE|PORT_CONNECT)) == PORT_CONNECT
+ && PORT_USB11(temp)) {
+ temp |= PORT_OWNER;
+ } else {
+ temp |= PORT_RESET;
+ temp &= ~PORT_PE;
+
+ /*
+ * caller must wait, then call GetPortStatus
+ * usb 2.0 spec says 50 ms resets on root
+ */
+ priv->reset_done = jiffies +
+ msecs_to_jiffies(50);
+ }
+ reg_write32(hcd->regs, HC_PORTSC1, temp);
+ break;
+ default:
+ goto error;
+ }
+ reg_read32(hcd->regs, HC_USBCMD);
+ break;
+
+ default:
+error:
+ /* "stall" on error */
+ retval = -EPIPE;
+ }
+ spin_unlock_irqrestore(&priv->lock, flags);
+ return retval;
+}
+
+static int isp1760_get_frame(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 fr;
+
+ fr = reg_read32(hcd->regs, HC_FRINDEX);
+ return (fr >> 3) % priv->periodic_size;
+}
+
+static void isp1760_stop(struct usb_hcd *hcd)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ u32 temp;
+
+ del_timer(&errata2_timer);
+
+ isp1760_hub_control(hcd, ClearPortFeature, USB_PORT_FEAT_POWER, 1,
+ NULL, 0);
+ mdelay(20);
+
+ spin_lock_irq(&priv->lock);
+ ehci_reset(hcd);
+ /* Disable IRQ */
+ temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+ reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+ spin_unlock_irq(&priv->lock);
+
+ reg_write32(hcd->regs, HC_CONFIGFLAG, 0);
+}
+
+static void isp1760_shutdown(struct usb_hcd *hcd)
+{
+ u32 command, temp;
+
+ isp1760_stop(hcd);
+ temp = reg_read32(hcd->regs, HC_HW_MODE_CTRL);
+ reg_write32(hcd->regs, HC_HW_MODE_CTRL, temp &= ~HW_GLOBAL_INTR_EN);
+
+ command = reg_read32(hcd->regs, HC_USBCMD);
+ command &= ~CMD_RUN;
+ reg_write32(hcd->regs, HC_USBCMD, command);
+}
+
+static void isp1760_clear_tt_buffer_complete(struct usb_hcd *hcd,
+ struct usb_host_endpoint *ep)
+{
+ struct isp1760_hcd *priv = hcd_to_priv(hcd);
+ struct isp1760_qh *qh = ep->hcpriv;
+ unsigned long spinflags;
+
+ if (!qh)
+ return;
+
+ spin_lock_irqsave(&priv->lock, spinflags);
+ qh->tt_buffer_dirty = 0;
+ schedule_ptds(hcd);
+ spin_unlock_irqrestore(&priv->lock, spinflags);
+}
+
+
+static const struct hc_driver isp1760_hc_driver = {
+ .description = "isp1760-hcd",
+ .product_desc = "NXP ISP1760 USB Host Controller",
+ .hcd_priv_size = sizeof(struct isp1760_hcd *),
+ .irq = isp1760_irq,
+ .flags = HCD_MEMORY | HCD_USB2,
+ .reset = isp1760_hc_setup,
+ .start = isp1760_run,
+ .stop = isp1760_stop,
+ .shutdown = isp1760_shutdown,
+ .urb_enqueue = isp1760_urb_enqueue,
+ .urb_dequeue = isp1760_urb_dequeue,
+ .endpoint_disable = isp1760_endpoint_disable,
+ .get_frame_number = isp1760_get_frame,
+ .hub_status_data = isp1760_hub_status_data,
+ .hub_control = isp1760_hub_control,
+ .clear_tt_buffer_complete = isp1760_clear_tt_buffer_complete,
+};
+
+int __init isp1760_init_kmem_once(void)
+{
+ urb_listitem_cachep = kmem_cache_create("isp1760_urb_listitem",
+ sizeof(struct urb_listitem), 0, SLAB_TEMPORARY |
+ SLAB_MEM_SPREAD, NULL);
+
+ if (!urb_listitem_cachep)
+ return -ENOMEM;
+
+ qtd_cachep = kmem_cache_create("isp1760_qtd",
+ sizeof(struct isp1760_qtd), 0, SLAB_TEMPORARY |
+ SLAB_MEM_SPREAD, NULL);
+
+ if (!qtd_cachep)
+ return -ENOMEM;
+
+ qh_cachep = kmem_cache_create("isp1760_qh", sizeof(struct isp1760_qh),
+ 0, SLAB_TEMPORARY | SLAB_MEM_SPREAD, NULL);
+
+ if (!qh_cachep) {
+ kmem_cache_destroy(qtd_cachep);
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void isp1760_deinit_kmem_cache(void)
+{
+ kmem_cache_destroy(qtd_cachep);
+ kmem_cache_destroy(qh_cachep);
+ kmem_cache_destroy(urb_listitem_cachep);
+}
+
+int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+ struct resource *mem, int irq, unsigned long irqflags,
+ struct device *dev)
+{
+ struct usb_hcd *hcd;
+ int ret;
+
+ hcd = usb_create_hcd(&isp1760_hc_driver, dev, dev_name(dev));
+ if (!hcd)
+ return -ENOMEM;
+
+ *(struct isp1760_hcd **)hcd->hcd_priv = priv;
+
+ priv->hcd = hcd;
+
+ init_memory(priv);
+
+ hcd->irq = irq;
+ hcd->regs = regs;
+ hcd->rsrc_start = mem->start;
+ hcd->rsrc_len = resource_size(mem);
+
+ /* This driver doesn't support wakeup requests */
+ hcd->cant_recv_wakeups = 1;
+
+ ret = usb_add_hcd(hcd, irq, irqflags);
+ if (ret)
+ goto error;
+
+ device_wakeup_enable(hcd->self.controller);
+
+ return 0;
+
+error:
+ usb_put_hcd(hcd);
+ return ret;
+}
+
+void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+{
+ if (!priv->hcd)
+ return;
+
+ usb_remove_hcd(priv->hcd);
+ usb_put_hcd(priv->hcd);
+}
diff --git a/drivers/usb/isp1760/isp1760-hcd.h b/drivers/usb/isp1760/isp1760-hcd.h
new file mode 100644
index 000000000000..0c1c98d6ea08
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-hcd.h
@@ -0,0 +1,102 @@
+#ifndef _ISP1760_HCD_H_
+#define _ISP1760_HCD_H_
+
+#include <linux/spinlock.h>
+
+struct isp1760_qh;
+struct isp1760_qtd;
+struct resource;
+struct usb_hcd;
+
+/*
+ * 60kb divided in:
+ * - 32 blocks @ 256 bytes
+ * - 20 blocks @ 1024 bytes
+ * - 4 blocks @ 8192 bytes
+ */
+
+#define BLOCK_1_NUM 32
+#define BLOCK_2_NUM 20
+#define BLOCK_3_NUM 4
+
+#define BLOCK_1_SIZE 256
+#define BLOCK_2_SIZE 1024
+#define BLOCK_3_SIZE 8192
+#define BLOCKS (BLOCK_1_NUM + BLOCK_2_NUM + BLOCK_3_NUM)
+#define MAX_PAYLOAD_SIZE BLOCK_3_SIZE
+#define PAYLOAD_AREA_SIZE 0xf000
+
+struct isp1760_slotinfo {
+ struct isp1760_qh *qh;
+ struct isp1760_qtd *qtd;
+ unsigned long timestamp;
+};
+
+/* chip memory management */
+struct isp1760_memory_chunk {
+ unsigned int start;
+ unsigned int size;
+ unsigned int free;
+};
+
+enum isp1760_queue_head_types {
+ QH_CONTROL,
+ QH_BULK,
+ QH_INTERRUPT,
+ QH_END
+};
+
+struct isp1760_hcd {
+#ifdef CONFIG_USB_ISP1760_HCD
+ struct usb_hcd *hcd;
+
+ u32 hcs_params;
+ spinlock_t lock;
+ struct isp1760_slotinfo atl_slots[32];
+ int atl_done_map;
+ struct isp1760_slotinfo int_slots[32];
+ int int_done_map;
+ struct isp1760_memory_chunk memory_pool[BLOCKS];
+ struct list_head qh_list[QH_END];
+
+ /* periodic schedule support */
+#define DEFAULT_I_TDPS 1024
+ unsigned periodic_size;
+ unsigned i_thresh;
+ unsigned long reset_done;
+ unsigned long next_statechange;
+#endif
+};
+
+#ifdef CONFIG_USB_ISP1760_HCD
+int isp1760_hcd_register(struct isp1760_hcd *priv, void __iomem *regs,
+ struct resource *mem, int irq, unsigned long irqflags,
+ struct device *dev);
+void isp1760_hcd_unregister(struct isp1760_hcd *priv);
+
+int isp1760_init_kmem_once(void);
+void isp1760_deinit_kmem_cache(void);
+#else
+static inline int isp1760_hcd_register(struct isp1760_hcd *priv,
+ void __iomem *regs, struct resource *mem,
+ int irq, unsigned long irqflags,
+ struct device *dev)
+{
+ return 0;
+}
+
+static inline void isp1760_hcd_unregister(struct isp1760_hcd *priv)
+{
+}
+
+static inline int isp1760_init_kmem_once(void)
+{
+ return 0;
+}
+
+static inline void isp1760_deinit_kmem_cache(void)
+{
+}
+#endif
+
+#endif /* _ISP1760_HCD_H_ */
diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
new file mode 100644
index 000000000000..264be4d21706
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-if.c
@@ -0,0 +1,309 @@
+/*
+ * Glue code for the ISP1760 driver and bus
+ * Currently there is support for
+ * - OpenFirmware
+ * - PCI
+ * - PDEV (generic platform device centralized driver model)
+ *
+ * (c) 2007 Sebastian Siewior <bigeasy@linutronix.de>
+ *
+ */
+
+#include <linux/usb.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/usb/isp1760.h>
+#include <linux/usb/hcd.h>
+
+#include "isp1760-core.h"
+#include "isp1760-regs.h"
+
+#ifdef CONFIG_PCI
+#include <linux/pci.h>
+#endif
+
+#ifdef CONFIG_PCI
+static int isp1761_pci_init(struct pci_dev *dev)
+{
+ resource_size_t mem_start;
+ resource_size_t mem_length;
+ u8 __iomem *iobase;
+ u8 latency, limit;
+ int retry_count;
+ u32 reg_data;
+
+ /* Grab the PLX PCI shared memory of the ISP 1761 we need */
+ mem_start = pci_resource_start(dev, 3);
+ mem_length = pci_resource_len(dev, 3);
+ if (mem_length < 0xffff) {
+ printk(KERN_ERR "memory length for this resource is wrong\n");
+ return -ENOMEM;
+ }
+
+ if (!request_mem_region(mem_start, mem_length, "ISP-PCI")) {
+ printk(KERN_ERR "host controller already in use\n");
+ return -EBUSY;
+ }
+
+ /* map available memory */
+ iobase = ioremap_nocache(mem_start, mem_length);
+ if (!iobase) {
+ printk(KERN_ERR "Error ioremap failed\n");
+ release_mem_region(mem_start, mem_length);
+ return -ENOMEM;
+ }
+
+ /* bad pci latencies can contribute to overruns */
+ pci_read_config_byte(dev, PCI_LATENCY_TIMER, &latency);
+ if (latency) {
+ pci_read_config_byte(dev, PCI_MAX_LAT, &limit);
+ if (limit && limit < latency)
+ pci_write_config_byte(dev, PCI_LATENCY_TIMER, limit);
+ }
+
+ /* Try to check whether we can access Scratch Register of
+ * Host Controller or not. The initial PCI access is retried until
+ * local init for the PCI bridge is completed
+ */
+ retry_count = 20;
+ reg_data = 0;
+ while ((reg_data != 0xFACE) && retry_count) {
+ /*by default host is in 16bit mode, so
+ * io operations at this stage must be 16 bit
+ * */
+ writel(0xface, iobase + HC_SCRATCH_REG);
+ udelay(100);
+ reg_data = readl(iobase + HC_SCRATCH_REG) & 0x0000ffff;
+ retry_count--;
+ }
+
+ iounmap(iobase);
+ release_mem_region(mem_start, mem_length);
+
+ /* Host Controller presence is detected by writing to scratch register
+ * and reading back and checking the contents are same or not
+ */
+ if (reg_data != 0xFACE) {
+ dev_err(&dev->dev, "scratch register mismatch %x\n", reg_data);
+ return -ENOMEM;
+ }
+
+ /* Grab the PLX PCI mem maped port start address we need */
+ mem_start = pci_resource_start(dev, 0);
+ mem_length = pci_resource_len(dev, 0);
+
+ if (!request_mem_region(mem_start, mem_length, "ISP1761 IO MEM")) {
+ printk(KERN_ERR "request region #1\n");
+ return -EBUSY;
+ }
+
+ iobase = ioremap_nocache(mem_start, mem_length);
+ if (!iobase) {
+ printk(KERN_ERR "ioremap #1\n");
+ release_mem_region(mem_start, mem_length);
+ return -ENOMEM;
+ }
+
+ /* configure PLX PCI chip to pass interrupts */
+#define PLX_INT_CSR_REG 0x68
+ reg_data = readl(iobase + PLX_INT_CSR_REG);
+ reg_data |= 0x900;
+ writel(reg_data, iobase + PLX_INT_CSR_REG);
+
+ /* done with PLX IO access */
+ iounmap(iobase);
+ release_mem_region(mem_start, mem_length);
+
+ return 0;
+}
+
+static int isp1761_pci_probe(struct pci_dev *dev,
+ const struct pci_device_id *id)
+{
+ unsigned int devflags = 0;
+ int ret;
+
+ if (!dev->irq)
+ return -ENODEV;
+
+ if (pci_enable_device(dev) < 0)
+ return -ENODEV;
+
+ ret = isp1761_pci_init(dev);
+ if (ret < 0)
+ goto error;
+
+ pci_set_master(dev);
+
+ dev->dev.dma_mask = NULL;
+ ret = isp1760_register(&dev->resource[3], dev->irq, 0, &dev->dev,
+ devflags);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ pci_disable_device(dev);
+ return ret;
+}
+
+static void isp1761_pci_remove(struct pci_dev *dev)
+{
+ isp1760_unregister(&dev->dev);
+
+ pci_disable_device(dev);
+}
+
+static void isp1761_pci_shutdown(struct pci_dev *dev)
+{
+ printk(KERN_ERR "ips1761_pci_shutdown\n");
+}
+
+static const struct pci_device_id isp1760_plx [] = {
+ {
+ .class = PCI_CLASS_BRIDGE_OTHER << 8,
+ .class_mask = ~0,
+ .vendor = PCI_VENDOR_ID_PLX,
+ .device = 0x5406,
+ .subvendor = PCI_VENDOR_ID_PLX,
+ .subdevice = 0x9054,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, isp1760_plx);
+
+static struct pci_driver isp1761_pci_driver = {
+ .name = "isp1760",
+ .id_table = isp1760_plx,
+ .probe = isp1761_pci_probe,
+ .remove = isp1761_pci_remove,
+ .shutdown = isp1761_pci_shutdown,
+};
+#endif
+
+static int isp1760_plat_probe(struct platform_device *pdev)
+{
+ unsigned long irqflags;
+ unsigned int devflags = 0;
+ struct resource *mem_res;
+ struct resource *irq_res;
+ int ret;
+
+ mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq_res) {
+ pr_warning("isp1760: IRQ resource not available\n");
+ return -ENODEV;
+ }
+ irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
+
+ if (IS_ENABLED(CONFIG_OF) && pdev->dev.of_node) {
+ struct device_node *dp = pdev->dev.of_node;
+ u32 bus_width = 0;
+
+ if (of_device_is_compatible(dp, "nxp,usb-isp1761"))
+ devflags |= ISP1760_FLAG_ISP1761;
+
+ /* Some systems wire up only 16 of the 32 data lines */
+ of_property_read_u32(dp, "bus-width", &bus_width);
+ if (bus_width == 16)
+ devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+
+ if (of_property_read_bool(dp, "port1-otg"))
+ devflags |= ISP1760_FLAG_OTG_EN;
+
+ if (of_property_read_bool(dp, "analog-oc"))
+ devflags |= ISP1760_FLAG_ANALOG_OC;
+
+ if (of_property_read_bool(dp, "dack-polarity"))
+ devflags |= ISP1760_FLAG_DACK_POL_HIGH;
+
+ if (of_property_read_bool(dp, "dreq-polarity"))
+ devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+ } else if (dev_get_platdata(&pdev->dev)) {
+ struct isp1760_platform_data *pdata =
+ dev_get_platdata(&pdev->dev);
+
+ if (pdata->is_isp1761)
+ devflags |= ISP1760_FLAG_ISP1761;
+ if (pdata->bus_width_16)
+ devflags |= ISP1760_FLAG_BUS_WIDTH_16;
+ if (pdata->port1_otg)
+ devflags |= ISP1760_FLAG_OTG_EN;
+ if (pdata->analog_oc)
+ devflags |= ISP1760_FLAG_ANALOG_OC;
+ if (pdata->dack_polarity_high)
+ devflags |= ISP1760_FLAG_DACK_POL_HIGH;
+ if (pdata->dreq_polarity_high)
+ devflags |= ISP1760_FLAG_DREQ_POL_HIGH;
+ }
+
+ ret = isp1760_register(mem_res, irq_res->start, irqflags, &pdev->dev,
+ devflags);
+ if (ret < 0)
+ return ret;
+
+ pr_info("ISP1760 USB device initialised\n");
+ return 0;
+}
+
+static int isp1760_plat_remove(struct platform_device *pdev)
+{
+ isp1760_unregister(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_OF
+static const struct of_device_id isp1760_of_match[] = {
+ { .compatible = "nxp,usb-isp1760", },
+ { .compatible = "nxp,usb-isp1761", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, isp1760_of_match);
+#endif
+
+static struct platform_driver isp1760_plat_driver = {
+ .probe = isp1760_plat_probe,
+ .remove = isp1760_plat_remove,
+ .driver = {
+ .name = "isp1760",
+ .of_match_table = of_match_ptr(isp1760_of_match),
+ },
+};
+
+static int __init isp1760_init(void)
+{
+ int ret, any_ret = -ENODEV;
+
+ isp1760_init_kmem_once();
+
+ ret = platform_driver_register(&isp1760_plat_driver);
+ if (!ret)
+ any_ret = 0;
+#ifdef CONFIG_PCI
+ ret = pci_register_driver(&isp1761_pci_driver);
+ if (!ret)
+ any_ret = 0;
+#endif
+
+ if (any_ret)
+ isp1760_deinit_kmem_cache();
+ return any_ret;
+}
+module_init(isp1760_init);
+
+static void __exit isp1760_exit(void)
+{
+ platform_driver_unregister(&isp1760_plat_driver);
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&isp1761_pci_driver);
+#endif
+ isp1760_deinit_kmem_cache();
+}
+module_exit(isp1760_exit);
diff --git a/drivers/usb/isp1760/isp1760-regs.h b/drivers/usb/isp1760/isp1760-regs.h
new file mode 100644
index 000000000000..b67095c9a9d4
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-regs.h
@@ -0,0 +1,230 @@
+/*
+ * Driver for the NXP ISP1760 chip
+ *
+ * Copyright 2014 Laurent Pinchart
+ * Copyright 2007 Sebastian Siewior
+ *
+ * Contacts:
+ * Sebastian Siewior <bigeasy@linutronix.de>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _ISP1760_REGS_H_
+#define _ISP1760_REGS_H_
+
+/* -----------------------------------------------------------------------------
+ * Host Controller
+ */
+
+/* EHCI capability registers */
+#define HC_CAPLENGTH 0x000
+#define HC_LENGTH(p) (((p) >> 00) & 0x00ff) /* bits 7:0 */
+#define HC_VERSION(p) (((p) >> 16) & 0xffff) /* bits 31:16 */
+
+#define HC_HCSPARAMS 0x004
+#define HCS_INDICATOR(p) ((p) & (1 << 16)) /* true: has port indicators */
+#define HCS_PPC(p) ((p) & (1 << 4)) /* true: port power control */
+#define HCS_N_PORTS(p) (((p) >> 0) & 0xf) /* bits 3:0, ports on HC */
+
+#define HC_HCCPARAMS 0x008
+#define HCC_ISOC_CACHE(p) ((p) & (1 << 7)) /* true: can cache isoc frame */
+#define HCC_ISOC_THRES(p) (((p) >> 4) & 0x7) /* bits 6:4, uframes cached */
+
+/* EHCI operational registers */
+#define HC_USBCMD 0x020
+#define CMD_LRESET (1 << 7) /* partial reset (no ports, etc) */
+#define CMD_RESET (1 << 1) /* reset HC not bus */
+#define CMD_RUN (1 << 0) /* start/stop HC */
+
+#define HC_USBSTS 0x024
+#define STS_PCD (1 << 2) /* port change detect */
+
+#define HC_FRINDEX 0x02c
+
+#define HC_CONFIGFLAG 0x060
+#define FLAG_CF (1 << 0) /* true: we'll support "high speed" */
+
+#define HC_PORTSC1 0x064
+#define PORT_OWNER (1 << 13) /* true: companion hc owns this port */
+#define PORT_POWER (1 << 12) /* true: has power (see PPC) */
+#define PORT_USB11(x) (((x) & (3 << 10)) == (1 << 10)) /* USB 1.1 device */
+#define PORT_RESET (1 << 8) /* reset port */
+#define PORT_SUSPEND (1 << 7) /* suspend port */
+#define PORT_RESUME (1 << 6) /* resume it */
+#define PORT_PE (1 << 2) /* port enable */
+#define PORT_CSC (1 << 1) /* connect status change */
+#define PORT_CONNECT (1 << 0) /* device connected */
+#define PORT_RWC_BITS (PORT_CSC)
+
+#define HC_ISO_PTD_DONEMAP_REG 0x130
+#define HC_ISO_PTD_SKIPMAP_REG 0x134
+#define HC_ISO_PTD_LASTPTD_REG 0x138
+#define HC_INT_PTD_DONEMAP_REG 0x140
+#define HC_INT_PTD_SKIPMAP_REG 0x144
+#define HC_INT_PTD_LASTPTD_REG 0x148
+#define HC_ATL_PTD_DONEMAP_REG 0x150
+#define HC_ATL_PTD_SKIPMAP_REG 0x154
+#define HC_ATL_PTD_LASTPTD_REG 0x158
+
+/* Configuration Register */
+#define HC_HW_MODE_CTRL 0x300
+#define ALL_ATX_RESET (1 << 31)
+#define HW_ANA_DIGI_OC (1 << 15)
+#define HW_DEV_DMA (1 << 11)
+#define HW_COMN_IRQ (1 << 10)
+#define HW_COMN_DMA (1 << 9)
+#define HW_DATA_BUS_32BIT (1 << 8)
+#define HW_DACK_POL_HIGH (1 << 6)
+#define HW_DREQ_POL_HIGH (1 << 5)
+#define HW_INTR_HIGH_ACT (1 << 2)
+#define HW_INTR_EDGE_TRIG (1 << 1)
+#define HW_GLOBAL_INTR_EN (1 << 0)
+
+#define HC_CHIP_ID_REG 0x304
+#define HC_SCRATCH_REG 0x308
+
+#define HC_RESET_REG 0x30c
+#define SW_RESET_RESET_HC (1 << 1)
+#define SW_RESET_RESET_ALL (1 << 0)
+
+#define HC_BUFFER_STATUS_REG 0x334
+#define ISO_BUF_FILL (1 << 2)
+#define INT_BUF_FILL (1 << 1)
+#define ATL_BUF_FILL (1 << 0)
+
+#define HC_MEMORY_REG 0x33c
+#define ISP_BANK(x) ((x) << 16)
+
+#define HC_PORT1_CTRL 0x374
+#define PORT1_POWER (3 << 3)
+#define PORT1_INIT1 (1 << 7)
+#define PORT1_INIT2 (1 << 23)
+#define HW_OTG_CTRL_SET 0x374
+#define HW_OTG_CTRL_CLR 0x376
+#define HW_OTG_DISABLE (1 << 10)
+#define HW_OTG_SE0_EN (1 << 9)
+#define HW_BDIS_ACON_EN (1 << 8)
+#define HW_SW_SEL_HC_DC (1 << 7)
+#define HW_VBUS_CHRG (1 << 6)
+#define HW_VBUS_DISCHRG (1 << 5)
+#define HW_VBUS_DRV (1 << 4)
+#define HW_SEL_CP_EXT (1 << 3)
+#define HW_DM_PULLDOWN (1 << 2)
+#define HW_DP_PULLDOWN (1 << 1)
+#define HW_DP_PULLUP (1 << 0)
+
+/* Interrupt Register */
+#define HC_INTERRUPT_REG 0x310
+
+#define HC_INTERRUPT_ENABLE 0x314
+#define HC_ISO_INT (1 << 9)
+#define HC_ATL_INT (1 << 8)
+#define HC_INTL_INT (1 << 7)
+#define HC_EOT_INT (1 << 3)
+#define HC_SOT_INT (1 << 1)
+#define INTERRUPT_ENABLE_MASK (HC_INTL_INT | HC_ATL_INT)
+
+#define HC_ISO_IRQ_MASK_OR_REG 0x318
+#define HC_INT_IRQ_MASK_OR_REG 0x31c
+#define HC_ATL_IRQ_MASK_OR_REG 0x320
+#define HC_ISO_IRQ_MASK_AND_REG 0x324
+#define HC_INT_IRQ_MASK_AND_REG 0x328
+#define HC_ATL_IRQ_MASK_AND_REG 0x32c
+
+/* -----------------------------------------------------------------------------
+ * Peripheral Controller
+ */
+
+/* Initialization Registers */
+#define DC_ADDRESS 0x0200
+#define DC_DEVEN (1 << 7)
+
+#define DC_MODE 0x020c
+#define DC_DMACLKON (1 << 9)
+#define DC_VBUSSTAT (1 << 8)
+#define DC_CLKAON (1 << 7)
+#define DC_SNDRSU (1 << 6)
+#define DC_GOSUSP (1 << 5)
+#define DC_SFRESET (1 << 4)
+#define DC_GLINTENA (1 << 3)
+#define DC_WKUPCS (1 << 2)
+
+#define DC_INTCONF 0x0210
+#define DC_CDBGMOD_ACK_NAK (0 << 6)
+#define DC_CDBGMOD_ACK (1 << 6)
+#define DC_CDBGMOD_ACK_1NAK (2 << 6)
+#define DC_DDBGMODIN_ACK_NAK (0 << 4)
+#define DC_DDBGMODIN_ACK (1 << 4)
+#define DC_DDBGMODIN_ACK_1NAK (2 << 4)
+#define DC_DDBGMODOUT_ACK_NYET_NAK (0 << 2)
+#define DC_DDBGMODOUT_ACK_NYET (1 << 2)
+#define DC_DDBGMODOUT_ACK_NYET_1NAK (2 << 2)
+#define DC_INTLVL (1 << 1)
+#define DC_INTPOL (1 << 0)
+
+#define DC_DEBUG 0x0212
+#define DC_INTENABLE 0x0214
+#define DC_IEPTX(n) (1 << (11 + 2 * (n)))
+#define DC_IEPRX(n) (1 << (10 + 2 * (n)))
+#define DC_IEPRXTX(n) (3 << (10 + 2 * (n)))
+#define DC_IEP0SETUP (1 << 8)
+#define DC_IEVBUS (1 << 7)
+#define DC_IEDMA (1 << 6)
+#define DC_IEHS_STA (1 << 5)
+#define DC_IERESM (1 << 4)
+#define DC_IESUSP (1 << 3)
+#define DC_IEPSOF (1 << 2)
+#define DC_IESOF (1 << 1)
+#define DC_IEBRST (1 << 0)
+
+/* Data Flow Registers */
+#define DC_EPINDEX 0x022c
+#define DC_EP0SETUP (1 << 5)
+#define DC_ENDPIDX(n) ((n) << 1)
+#define DC_EPDIR (1 << 0)
+
+#define DC_CTRLFUNC 0x0228
+#define DC_CLBUF (1 << 4)
+#define DC_VENDP (1 << 3)
+#define DC_DSEN (1 << 2)
+#define DC_STATUS (1 << 1)
+#define DC_STALL (1 << 0)
+
+#define DC_DATAPORT 0x0220
+#define DC_BUFLEN 0x021c
+#define DC_DATACOUNT_MASK 0xffff
+#define DC_BUFSTAT 0x021e
+#define DC_EPMAXPKTSZ 0x0204
+
+#define DC_EPTYPE 0x0208
+#define DC_NOEMPKT (1 << 4)
+#define DC_EPENABLE (1 << 3)
+#define DC_DBLBUF (1 << 2)
+#define DC_ENDPTYP_ISOC (1 << 0)
+#define DC_ENDPTYP_BULK (2 << 0)
+#define DC_ENDPTYP_INTERRUPT (3 << 0)
+
+/* DMA Registers */
+#define DC_DMACMD 0x0230
+#define DC_DMATXCOUNT 0x0234
+#define DC_DMACONF 0x0238
+#define DC_DMAHW 0x023c
+#define DC_DMAINTREASON 0x0250
+#define DC_DMAINTEN 0x0254
+#define DC_DMAEP 0x0258
+#define DC_DMABURSTCOUNT 0x0264
+
+/* General Registers */
+#define DC_INTERRUPT 0x0218
+#define DC_CHIPID 0x0270
+#define DC_FRAMENUM 0x0274
+#define DC_SCRATCH 0x0278
+#define DC_UNLOCKDEV 0x027c
+#define DC_INTPULSEWIDTH 0x0280
+#define DC_TESTMODE 0x0284
+
+#endif
diff --git a/drivers/usb/isp1760/isp1760-udc.c b/drivers/usb/isp1760/isp1760-udc.c
new file mode 100644
index 000000000000..9612d7990565
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-udc.c
@@ -0,0 +1,1498 @@
+/*
+ * Driver for the NXP ISP1761 device controller
+ *
+ * Copyright 2014 Ideas on Board Oy
+ *
+ * Contacts:
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/timer.h>
+#include <linux/usb.h>
+
+#include "isp1760-core.h"
+#include "isp1760-regs.h"
+#include "isp1760-udc.h"
+
+#define ISP1760_VBUS_POLL_INTERVAL msecs_to_jiffies(500)
+
+struct isp1760_request {
+ struct usb_request req;
+ struct list_head queue;
+ struct isp1760_ep *ep;
+ unsigned int packet_size;
+};
+
+static inline struct isp1760_udc *gadget_to_udc(struct usb_gadget *gadget)
+{
+ return container_of(gadget, struct isp1760_udc, gadget);
+}
+
+static inline struct isp1760_ep *ep_to_udc_ep(struct usb_ep *ep)
+{
+ return container_of(ep, struct isp1760_ep, ep);
+}
+
+static inline struct isp1760_request *req_to_udc_req(struct usb_request *req)
+{
+ return container_of(req, struct isp1760_request, req);
+}
+
+static inline u32 isp1760_udc_read(struct isp1760_udc *udc, u16 reg)
+{
+ return isp1760_read32(udc->regs, reg);
+}
+
+static inline void isp1760_udc_write(struct isp1760_udc *udc, u16 reg, u32 val)
+{
+ isp1760_write32(udc->regs, reg, val);
+}
+
+/* -----------------------------------------------------------------------------
+ * Endpoint Management
+ */
+
+static struct isp1760_ep *isp1760_udc_find_ep(struct isp1760_udc *udc,
+ u16 index)
+{
+ unsigned int i;
+
+ if (index == 0)
+ return &udc->ep[0];
+
+ for (i = 1; i < ARRAY_SIZE(udc->ep); ++i) {
+ if (udc->ep[i].addr == index)
+ return udc->ep[i].desc ? &udc->ep[i] : NULL;
+ }
+
+ return NULL;
+}
+
+static void __isp1760_udc_select_ep(struct isp1760_ep *ep, int dir)
+{
+ isp1760_udc_write(ep->udc, DC_EPINDEX,
+ DC_ENDPIDX(ep->addr & USB_ENDPOINT_NUMBER_MASK) |
+ (dir == USB_DIR_IN ? DC_EPDIR : 0));
+}
+
+/**
+ * isp1760_udc_select_ep - Select an endpoint for register access
+ * @ep: The endpoint
+ *
+ * The ISP1761 endpoint registers are banked. This function selects the target
+ * endpoint for banked register access. The selection remains valid until the
+ * next call to this function, the next direct access to the EPINDEX register
+ * or the next reset, whichever comes first.
+ *
+ * Called with the UDC spinlock held.
+ */
+static void isp1760_udc_select_ep(struct isp1760_ep *ep)
+{
+ __isp1760_udc_select_ep(ep, ep->addr & USB_ENDPOINT_DIR_MASK);
+}
+
+/* Called with the UDC spinlock held. */
+static void isp1760_udc_ctrl_send_status(struct isp1760_ep *ep, int dir)
+{
+ struct isp1760_udc *udc = ep->udc;
+
+ /*
+ * Proceed to the status stage. The status stage data packet flows in
+ * the direction opposite to the data stage data packets, we thus need
+ * to select the OUT/IN endpoint for IN/OUT transfers.
+ */
+ isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) |
+ (dir == USB_DIR_IN ? 0 : DC_EPDIR));
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_STATUS);
+
+ /*
+ * The hardware will terminate the request automatically and go back to
+ * the setup stage without notifying us.
+ */
+ udc->ep0_state = ISP1760_CTRL_SETUP;
+}
+
+/* Called without the UDC spinlock held. */
+static void isp1760_udc_request_complete(struct isp1760_ep *ep,
+ struct isp1760_request *req,
+ int status)
+{
+ struct isp1760_udc *udc = ep->udc;
+ unsigned long flags;
+
+ dev_dbg(ep->udc->isp->dev, "completing request %p with status %d\n",
+ req, status);
+
+ req->ep = NULL;
+ req->req.status = status;
+ req->req.complete(&ep->ep, &req->req);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*
+ * When completing control OUT requests, move to the status stage after
+ * calling the request complete callback. This gives the gadget an
+ * opportunity to stall the control transfer if needed.
+ */
+ if (status == 0 && ep->addr == 0 && udc->ep0_dir == USB_DIR_OUT)
+ isp1760_udc_ctrl_send_status(ep, USB_DIR_OUT);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static void isp1760_udc_ctrl_send_stall(struct isp1760_ep *ep)
+{
+ struct isp1760_udc *udc = ep->udc;
+ unsigned long flags;
+
+ dev_dbg(ep->udc->isp->dev, "%s(ep%02x)\n", __func__, ep->addr);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /* Stall both the IN and OUT endpoints. */
+ __isp1760_udc_select_ep(ep, USB_DIR_OUT);
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+ __isp1760_udc_select_ep(ep, USB_DIR_IN);
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_STALL);
+
+ /* A protocol stall completes the control transaction. */
+ udc->ep0_state = ISP1760_CTRL_SETUP;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Data Endpoints
+ */
+
+/* Called with the UDC spinlock held. */
+static bool isp1760_udc_receive(struct isp1760_ep *ep,
+ struct isp1760_request *req)
+{
+ struct isp1760_udc *udc = ep->udc;
+ unsigned int len;
+ u32 *buf;
+ int i;
+
+ isp1760_udc_select_ep(ep);
+ len = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+
+ dev_dbg(udc->isp->dev, "%s: received %u bytes (%u/%u done)\n",
+ __func__, len, req->req.actual, req->req.length);
+
+ len = min(len, req->req.length - req->req.actual);
+
+ if (!len) {
+ /*
+ * There's no data to be read from the FIFO, acknowledge the RX
+ * interrupt by clearing the buffer.
+ *
+ * TODO: What if another packet arrives in the meantime ? The
+ * datasheet doesn't clearly document how this should be
+ * handled.
+ */
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+ return false;
+ }
+
+ buf = req->req.buf + req->req.actual;
+
+ /*
+ * Make sure not to read more than one extra byte, otherwise data from
+ * the next packet might be removed from the FIFO.
+ */
+ for (i = len; i > 2; i -= 4, ++buf)
+ *buf = le32_to_cpu(isp1760_udc_read(udc, DC_DATAPORT));
+ if (i > 0)
+ *(u16 *)buf = le16_to_cpu(readw(udc->regs + DC_DATAPORT));
+
+ req->req.actual += len;
+
+ /*
+ * TODO: The short_not_ok flag isn't supported yet, but isn't used by
+ * any gadget driver either.
+ */
+
+ dev_dbg(udc->isp->dev,
+ "%s: req %p actual/length %u/%u maxpacket %u packet size %u\n",
+ __func__, req, req->req.actual, req->req.length, ep->maxpacket,
+ len);
+
+ ep->rx_pending = false;
+
+ /*
+ * Complete the request if all data has been received or if a short
+ * packet has been received.
+ */
+ if (req->req.actual == req->req.length || len < ep->maxpacket) {
+ list_del(&req->queue);
+ return true;
+ }
+
+ return false;
+}
+
+static void isp1760_udc_transmit(struct isp1760_ep *ep,
+ struct isp1760_request *req)
+{
+ struct isp1760_udc *udc = ep->udc;
+ u32 *buf = req->req.buf + req->req.actual;
+ int i;
+
+ req->packet_size = min(req->req.length - req->req.actual,
+ ep->maxpacket);
+
+ dev_dbg(udc->isp->dev, "%s: transferring %u bytes (%u/%u done)\n",
+ __func__, req->packet_size, req->req.actual,
+ req->req.length);
+
+ __isp1760_udc_select_ep(ep, USB_DIR_IN);
+
+ if (req->packet_size)
+ isp1760_udc_write(udc, DC_BUFLEN, req->packet_size);
+
+ /*
+ * Make sure not to write more than one extra byte, otherwise extra data
+ * will stay in the FIFO and will be transmitted during the next control
+ * request. The endpoint control CLBUF bit is supposed to allow flushing
+ * the FIFO for this kind of conditions, but doesn't seem to work.
+ */
+ for (i = req->packet_size; i > 2; i -= 4, ++buf)
+ isp1760_udc_write(udc, DC_DATAPORT, cpu_to_le32(*buf));
+ if (i > 0)
+ writew(cpu_to_le16(*(u16 *)buf), udc->regs + DC_DATAPORT);
+
+ if (ep->addr == 0)
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ if (!req->packet_size)
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_VENDP);
+}
+
+static void isp1760_ep_rx_ready(struct isp1760_ep *ep)
+{
+ struct isp1760_udc *udc = ep->udc;
+ struct isp1760_request *req;
+ bool complete;
+
+ spin_lock(&udc->lock);
+
+ if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_OUT) {
+ spin_unlock(&udc->lock);
+ dev_dbg(udc->isp->dev, "%s: invalid ep0 state %u\n", __func__,
+ udc->ep0_state);
+ return;
+ }
+
+ if (ep->addr != 0 && !ep->desc) {
+ spin_unlock(&udc->lock);
+ dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
+ ep->addr);
+ return;
+ }
+
+ if (list_empty(&ep->queue)) {
+ ep->rx_pending = true;
+ spin_unlock(&udc->lock);
+ dev_dbg(udc->isp->dev, "%s: ep%02x (%p) has no request queued\n",
+ __func__, ep->addr, ep);
+ return;
+ }
+
+ req = list_first_entry(&ep->queue, struct isp1760_request,
+ queue);
+ complete = isp1760_udc_receive(ep, req);
+
+ spin_unlock(&udc->lock);
+
+ if (complete)
+ isp1760_udc_request_complete(ep, req, 0);
+}
+
+static void isp1760_ep_tx_complete(struct isp1760_ep *ep)
+{
+ struct isp1760_udc *udc = ep->udc;
+ struct isp1760_request *complete = NULL;
+ struct isp1760_request *req;
+ bool need_zlp;
+
+ spin_lock(&udc->lock);
+
+ if (ep->addr == 0 && udc->ep0_state != ISP1760_CTRL_DATA_IN) {
+ spin_unlock(&udc->lock);
+ dev_dbg(udc->isp->dev, "TX IRQ: invalid endpoint state %u\n",
+ udc->ep0_state);
+ return;
+ }
+
+ if (list_empty(&ep->queue)) {
+ /*
+ * This can happen for the control endpoint when the reply to
+ * the GET_STATUS IN control request is sent directly by the
+ * setup IRQ handler. Just proceed to the status stage.
+ */
+ if (ep->addr == 0) {
+ isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
+ spin_unlock(&udc->lock);
+ return;
+ }
+
+ spin_unlock(&udc->lock);
+ dev_dbg(udc->isp->dev, "%s: ep%02x has no request queued\n",
+ __func__, ep->addr);
+ return;
+ }
+
+ req = list_first_entry(&ep->queue, struct isp1760_request,
+ queue);
+ req->req.actual += req->packet_size;
+
+ need_zlp = req->req.actual == req->req.length &&
+ !(req->req.length % ep->maxpacket) &&
+ req->packet_size && req->req.zero;
+
+ dev_dbg(udc->isp->dev,
+ "TX IRQ: req %p actual/length %u/%u maxpacket %u packet size %u zero %u need zlp %u\n",
+ req, req->req.actual, req->req.length, ep->maxpacket,
+ req->packet_size, req->req.zero, need_zlp);
+
+ /*
+ * Complete the request if all data has been sent and we don't need to
+ * transmit a zero length packet.
+ */
+ if (req->req.actual == req->req.length && !need_zlp) {
+ complete = req;
+ list_del(&req->queue);
+
+ if (ep->addr == 0)
+ isp1760_udc_ctrl_send_status(ep, USB_DIR_IN);
+
+ if (!list_empty(&ep->queue))
+ req = list_first_entry(&ep->queue,
+ struct isp1760_request, queue);
+ else
+ req = NULL;
+ }
+
+ /*
+ * Transmit the next packet or start the next request, if any.
+ *
+ * TODO: If the endpoint is stalled the next request shouldn't be
+ * started, but what about the next packet ?
+ */
+ if (req)
+ isp1760_udc_transmit(ep, req);
+
+ spin_unlock(&udc->lock);
+
+ if (complete)
+ isp1760_udc_request_complete(ep, complete, 0);
+}
+
+static int __isp1760_udc_set_halt(struct isp1760_ep *ep, bool halt)
+{
+ struct isp1760_udc *udc = ep->udc;
+
+ dev_dbg(udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
+ halt ? "set" : "clear", ep->addr);
+
+ if (ep->desc && usb_endpoint_xfer_isoc(ep->desc)) {
+ dev_dbg(udc->isp->dev, "%s: ep%02x is isochronous\n", __func__,
+ ep->addr);
+ return -EINVAL;
+ }
+
+ isp1760_udc_select_ep(ep);
+ isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+
+ if (ep->addr == 0) {
+ /* When halting the control endpoint, stall both IN and OUT. */
+ __isp1760_udc_select_ep(ep, USB_DIR_IN);
+ isp1760_udc_write(udc, DC_CTRLFUNC, halt ? DC_STALL : 0);
+ } else if (!halt) {
+ /* Reset the data PID by cycling the endpoint enable bit. */
+ u16 eptype = isp1760_udc_read(udc, DC_EPTYPE);
+
+ isp1760_udc_write(udc, DC_EPTYPE, eptype & ~DC_EPENABLE);
+ isp1760_udc_write(udc, DC_EPTYPE, eptype);
+
+ /*
+ * Disabling the endpoint emptied the transmit FIFO, fill it
+ * again if a request is pending.
+ *
+ * TODO: Does the gadget framework require synchronizatino with
+ * the TX IRQ handler ?
+ */
+ if ((ep->addr & USB_DIR_IN) && !list_empty(&ep->queue)) {
+ struct isp1760_request *req;
+
+ req = list_first_entry(&ep->queue,
+ struct isp1760_request, queue);
+ isp1760_udc_transmit(ep, req);
+ }
+ }
+
+ ep->halted = halt;
+
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * Control Endpoint
+ */
+
+static int isp1760_udc_get_status(struct isp1760_udc *udc,
+ const struct usb_ctrlrequest *req)
+{
+ struct isp1760_ep *ep;
+ u16 status;
+
+ if (req->wLength != cpu_to_le16(2) || req->wValue != cpu_to_le16(0))
+ return -EINVAL;
+
+ switch (req->bRequestType) {
+ case USB_DIR_IN | USB_RECIP_DEVICE:
+ status = udc->devstatus;
+ break;
+
+ case USB_DIR_IN | USB_RECIP_INTERFACE:
+ status = 0;
+ break;
+
+ case USB_DIR_IN | USB_RECIP_ENDPOINT:
+ ep = isp1760_udc_find_ep(udc, le16_to_cpu(req->wIndex));
+ if (!ep)
+ return -EINVAL;
+
+ status = 0;
+ if (ep->halted)
+ status |= 1 << USB_ENDPOINT_HALT;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ isp1760_udc_write(udc, DC_EPINDEX, DC_ENDPIDX(0) | DC_EPDIR);
+ isp1760_udc_write(udc, DC_BUFLEN, 2);
+
+ writew(cpu_to_le16(status), udc->regs + DC_DATAPORT);
+
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+
+ dev_dbg(udc->isp->dev, "%s: status 0x%04x\n", __func__, status);
+
+ return 0;
+}
+
+static int isp1760_udc_set_address(struct isp1760_udc *udc, u16 addr)
+{
+ if (addr > 127) {
+ dev_dbg(udc->isp->dev, "invalid device address %u\n", addr);
+ return -EINVAL;
+ }
+
+ if (udc->gadget.state != USB_STATE_DEFAULT &&
+ udc->gadget.state != USB_STATE_ADDRESS) {
+ dev_dbg(udc->isp->dev, "can't set address in state %u\n",
+ udc->gadget.state);
+ return -EINVAL;
+ }
+
+ usb_gadget_set_state(&udc->gadget, addr ? USB_STATE_ADDRESS :
+ USB_STATE_DEFAULT);
+
+ isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN | addr);
+
+ spin_lock(&udc->lock);
+ isp1760_udc_ctrl_send_status(&udc->ep[0], USB_DIR_OUT);
+ spin_unlock(&udc->lock);
+
+ return 0;
+}
+
+static bool isp1760_ep0_setup_standard(struct isp1760_udc *udc,
+ struct usb_ctrlrequest *req)
+{
+ bool stall;
+
+ switch (req->bRequest) {
+ case USB_REQ_GET_STATUS:
+ return isp1760_udc_get_status(udc, req);
+
+ case USB_REQ_CLEAR_FEATURE:
+ switch (req->bRequestType) {
+ case USB_DIR_OUT | USB_RECIP_DEVICE: {
+ /* TODO: Handle remote wakeup feature. */
+ return true;
+ }
+
+ case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
+ u16 index = le16_to_cpu(req->wIndex);
+ struct isp1760_ep *ep;
+
+ if (req->wLength != cpu_to_le16(0) ||
+ req->wValue != cpu_to_le16(USB_ENDPOINT_HALT))
+ return true;
+
+ ep = isp1760_udc_find_ep(udc, index);
+ if (!ep)
+ return true;
+
+ spin_lock(&udc->lock);
+
+ /*
+ * If the endpoint is wedged only the gadget can clear
+ * the halt feature. Pretend success in that case, but
+ * keep the endpoint halted.
+ */
+ if (!ep->wedged)
+ stall = __isp1760_udc_set_halt(ep, false);
+ else
+ stall = false;
+
+ if (!stall)
+ isp1760_udc_ctrl_send_status(&udc->ep[0],
+ USB_DIR_OUT);
+
+ spin_unlock(&udc->lock);
+ return stall;
+ }
+
+ default:
+ return true;
+ }
+ break;
+
+ case USB_REQ_SET_FEATURE:
+ switch (req->bRequestType) {
+ case USB_DIR_OUT | USB_RECIP_DEVICE: {
+ /* TODO: Handle remote wakeup and test mode features */
+ return true;
+ }
+
+ case USB_DIR_OUT | USB_RECIP_ENDPOINT: {
+ u16 index = le16_to_cpu(req->wIndex);
+ struct isp1760_ep *ep;
+
+ if (req->wLength != cpu_to_le16(0) ||
+ req->wValue != cpu_to_le16(USB_ENDPOINT_HALT))
+ return true;
+
+ ep = isp1760_udc_find_ep(udc, index);
+ if (!ep)
+ return true;
+
+ spin_lock(&udc->lock);
+
+ stall = __isp1760_udc_set_halt(ep, true);
+ if (!stall)
+ isp1760_udc_ctrl_send_status(&udc->ep[0],
+ USB_DIR_OUT);
+
+ spin_unlock(&udc->lock);
+ return stall;
+ }
+
+ default:
+ return true;
+ }
+ break;
+
+ case USB_REQ_SET_ADDRESS:
+ if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+ return true;
+
+ return isp1760_udc_set_address(udc, le16_to_cpu(req->wValue));
+
+ case USB_REQ_SET_CONFIGURATION:
+ if (req->bRequestType != (USB_DIR_OUT | USB_RECIP_DEVICE))
+ return true;
+
+ if (udc->gadget.state != USB_STATE_ADDRESS &&
+ udc->gadget.state != USB_STATE_CONFIGURED)
+ return true;
+
+ stall = udc->driver->setup(&udc->gadget, req) < 0;
+ if (stall)
+ return true;
+
+ usb_gadget_set_state(&udc->gadget, req->wValue ?
+ USB_STATE_CONFIGURED : USB_STATE_ADDRESS);
+
+ /*
+ * SET_CONFIGURATION (and SET_INTERFACE) must reset the halt
+ * feature on all endpoints. There is however no need to do so
+ * explicitly here as the gadget driver will disable and
+ * reenable endpoints, clearing the halt feature.
+ */
+ return false;
+
+ default:
+ return udc->driver->setup(&udc->gadget, req) < 0;
+ }
+}
+
+static void isp1760_ep0_setup(struct isp1760_udc *udc)
+{
+ union {
+ struct usb_ctrlrequest r;
+ u32 data[2];
+ } req;
+ unsigned int count;
+ bool stall = false;
+
+ spin_lock(&udc->lock);
+
+ isp1760_udc_write(udc, DC_EPINDEX, DC_EP0SETUP);
+
+ count = isp1760_udc_read(udc, DC_BUFLEN) & DC_DATACOUNT_MASK;
+ if (count != sizeof(req)) {
+ spin_unlock(&udc->lock);
+
+ dev_err(udc->isp->dev, "invalid length %u for setup packet\n",
+ count);
+
+ isp1760_udc_ctrl_send_stall(&udc->ep[0]);
+ return;
+ }
+
+ req.data[0] = isp1760_udc_read(udc, DC_DATAPORT);
+ req.data[1] = isp1760_udc_read(udc, DC_DATAPORT);
+
+ if (udc->ep0_state != ISP1760_CTRL_SETUP) {
+ spin_unlock(&udc->lock);
+ dev_dbg(udc->isp->dev, "unexpected SETUP packet\n");
+ return;
+ }
+
+ /* Move to the data stage. */
+ if (!req.r.wLength)
+ udc->ep0_state = ISP1760_CTRL_STATUS;
+ else if (req.r.bRequestType & USB_DIR_IN)
+ udc->ep0_state = ISP1760_CTRL_DATA_IN;
+ else
+ udc->ep0_state = ISP1760_CTRL_DATA_OUT;
+
+ udc->ep0_dir = req.r.bRequestType & USB_DIR_IN;
+ udc->ep0_length = le16_to_cpu(req.r.wLength);
+
+ spin_unlock(&udc->lock);
+
+ dev_dbg(udc->isp->dev,
+ "%s: bRequestType 0x%02x bRequest 0x%02x wValue 0x%04x wIndex 0x%04x wLength 0x%04x\n",
+ __func__, req.r.bRequestType, req.r.bRequest,
+ le16_to_cpu(req.r.wValue), le16_to_cpu(req.r.wIndex),
+ le16_to_cpu(req.r.wLength));
+
+ if ((req.r.bRequestType & USB_TYPE_MASK) == USB_TYPE_STANDARD)
+ stall = isp1760_ep0_setup_standard(udc, &req.r);
+ else
+ stall = udc->driver->setup(&udc->gadget, &req.r) < 0;
+
+ if (stall)
+ isp1760_udc_ctrl_send_stall(&udc->ep[0]);
+}
+
+/* -----------------------------------------------------------------------------
+ * Gadget Endpoint Operations
+ */
+
+static int isp1760_ep_enable(struct usb_ep *ep,
+ const struct usb_endpoint_descriptor *desc)
+{
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ struct isp1760_udc *udc = uep->udc;
+ unsigned long flags;
+ unsigned int type;
+
+ dev_dbg(uep->udc->isp->dev, "%s\n", __func__);
+
+ /*
+ * Validate the descriptor. The control endpoint can't be enabled
+ * manually.
+ */
+ if (desc->bDescriptorType != USB_DT_ENDPOINT ||
+ desc->bEndpointAddress == 0 ||
+ desc->bEndpointAddress != uep->addr ||
+ le16_to_cpu(desc->wMaxPacketSize) > ep->maxpacket) {
+ dev_dbg(udc->isp->dev,
+ "%s: invalid descriptor type %u addr %02x ep addr %02x max packet size %u/%u\n",
+ __func__, desc->bDescriptorType,
+ desc->bEndpointAddress, uep->addr,
+ le16_to_cpu(desc->wMaxPacketSize), ep->maxpacket);
+ return -EINVAL;
+ }
+
+ switch (usb_endpoint_type(desc)) {
+ case USB_ENDPOINT_XFER_ISOC:
+ type = DC_ENDPTYP_ISOC;
+ break;
+ case USB_ENDPOINT_XFER_BULK:
+ type = DC_ENDPTYP_BULK;
+ break;
+ case USB_ENDPOINT_XFER_INT:
+ type = DC_ENDPTYP_INTERRUPT;
+ break;
+ case USB_ENDPOINT_XFER_CONTROL:
+ default:
+ dev_dbg(udc->isp->dev, "%s: control endpoints unsupported\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ uep->desc = desc;
+ uep->maxpacket = le16_to_cpu(desc->wMaxPacketSize);
+ uep->rx_pending = false;
+ uep->halted = false;
+ uep->wedged = false;
+
+ isp1760_udc_select_ep(uep);
+ isp1760_udc_write(udc, DC_EPMAXPKTSZ, uep->maxpacket);
+ isp1760_udc_write(udc, DC_BUFLEN, uep->maxpacket);
+ isp1760_udc_write(udc, DC_EPTYPE, DC_EPENABLE | type);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ return 0;
+}
+
+static int isp1760_ep_disable(struct usb_ep *ep)
+{
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ struct isp1760_udc *udc = uep->udc;
+ struct isp1760_request *req, *nreq;
+ LIST_HEAD(req_list);
+ unsigned long flags;
+
+ dev_dbg(udc->isp->dev, "%s\n", __func__);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!uep->desc) {
+ dev_dbg(udc->isp->dev, "%s: endpoint not enabled\n", __func__);
+ spin_unlock_irqrestore(&udc->lock, flags);
+ return -EINVAL;
+ }
+
+ uep->desc = NULL;
+ uep->maxpacket = 0;
+
+ isp1760_udc_select_ep(uep);
+ isp1760_udc_write(udc, DC_EPTYPE, 0);
+
+ /* TODO Synchronize with the IRQ handler */
+
+ list_splice_init(&uep->queue, &req_list);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ list_for_each_entry_safe(req, nreq, &req_list, queue) {
+ list_del(&req->queue);
+ isp1760_udc_request_complete(uep, req, -ESHUTDOWN);
+ }
+
+ return 0;
+}
+
+static struct usb_request *isp1760_ep_alloc_request(struct usb_ep *ep,
+ gfp_t gfp_flags)
+{
+ struct isp1760_request *req;
+
+ req = kzalloc(sizeof(*req), gfp_flags);
+
+ return &req->req;
+}
+
+static void isp1760_ep_free_request(struct usb_ep *ep, struct usb_request *_req)
+{
+ struct isp1760_request *req = req_to_udc_req(_req);
+
+ kfree(req);
+}
+
+static int isp1760_ep_queue(struct usb_ep *ep, struct usb_request *_req,
+ gfp_t gfp_flags)
+{
+ struct isp1760_request *req = req_to_udc_req(_req);
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ struct isp1760_udc *udc = uep->udc;
+ bool complete = false;
+ unsigned long flags;
+ int ret = 0;
+
+ _req->status = -EINPROGRESS;
+ _req->actual = 0;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ dev_dbg(udc->isp->dev,
+ "%s: req %p (%u bytes%s) ep %p(0x%02x)\n", __func__, _req,
+ _req->length, _req->zero ? " (zlp)" : "", uep, uep->addr);
+
+ req->ep = uep;
+
+ if (uep->addr == 0) {
+ if (_req->length != udc->ep0_length &&
+ udc->ep0_state != ISP1760_CTRL_DATA_IN) {
+ dev_dbg(udc->isp->dev,
+ "%s: invalid length %u for req %p\n",
+ __func__, _req->length, req);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ switch (udc->ep0_state) {
+ case ISP1760_CTRL_DATA_IN:
+ dev_dbg(udc->isp->dev, "%s: transmitting req %p\n",
+ __func__, req);
+
+ list_add_tail(&req->queue, &uep->queue);
+ isp1760_udc_transmit(uep, req);
+ break;
+
+ case ISP1760_CTRL_DATA_OUT:
+ list_add_tail(&req->queue, &uep->queue);
+ __isp1760_udc_select_ep(uep, USB_DIR_OUT);
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_DSEN);
+ break;
+
+ case ISP1760_CTRL_STATUS:
+ complete = true;
+ break;
+
+ default:
+ dev_dbg(udc->isp->dev, "%s: invalid ep0 state\n",
+ __func__);
+ ret = -EINVAL;
+ break;
+ }
+ } else if (uep->desc) {
+ bool empty = list_empty(&uep->queue);
+
+ list_add_tail(&req->queue, &uep->queue);
+ if ((uep->addr & USB_DIR_IN) && !uep->halted && empty)
+ isp1760_udc_transmit(uep, req);
+ else if (!(uep->addr & USB_DIR_IN) && uep->rx_pending)
+ complete = isp1760_udc_receive(uep, req);
+ } else {
+ dev_dbg(udc->isp->dev,
+ "%s: can't queue request to disabled ep%02x\n",
+ __func__, uep->addr);
+ ret = -ESHUTDOWN;
+ }
+
+done:
+ if (ret < 0)
+ req->ep = NULL;
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (complete)
+ isp1760_udc_request_complete(uep, req, 0);
+
+ return ret;
+}
+
+static int isp1760_ep_dequeue(struct usb_ep *ep, struct usb_request *_req)
+{
+ struct isp1760_request *req = req_to_udc_req(_req);
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ struct isp1760_udc *udc = uep->udc;
+ unsigned long flags;
+
+ dev_dbg(uep->udc->isp->dev, "%s(ep%02x)\n", __func__, uep->addr);
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (req->ep != uep)
+ req = NULL;
+ else
+ list_del(&req->queue);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+
+ if (!req)
+ return -EINVAL;
+
+ isp1760_udc_request_complete(uep, req, -ECONNRESET);
+ return 0;
+}
+
+static int __isp1760_ep_set_halt(struct isp1760_ep *uep, bool stall, bool wedge)
+{
+ struct isp1760_udc *udc = uep->udc;
+ int ret;
+
+ if (!uep->addr) {
+ /*
+ * Halting the control endpoint is only valid as a delayed error
+ * response to a SETUP packet. Make sure EP0 is in the right
+ * stage and that the gadget isn't trying to clear the halt
+ * condition.
+ */
+ if (WARN_ON(udc->ep0_state == ISP1760_CTRL_SETUP || !stall ||
+ wedge)) {
+ return -EINVAL;
+ }
+ }
+
+ if (uep->addr && !uep->desc) {
+ dev_dbg(udc->isp->dev, "%s: ep%02x is disabled\n", __func__,
+ uep->addr);
+ return -EINVAL;
+ }
+
+ if (uep->addr & USB_DIR_IN) {
+ /* Refuse to halt IN endpoints with active transfers. */
+ if (!list_empty(&uep->queue)) {
+ dev_dbg(udc->isp->dev,
+ "%s: ep%02x has request pending\n", __func__,
+ uep->addr);
+ return -EAGAIN;
+ }
+ }
+
+ ret = __isp1760_udc_set_halt(uep, stall);
+ if (ret < 0)
+ return ret;
+
+ if (!uep->addr) {
+ /*
+ * Stalling EP0 completes the control transaction, move back to
+ * the SETUP state.
+ */
+ udc->ep0_state = ISP1760_CTRL_SETUP;
+ return 0;
+ }
+
+ if (wedge)
+ uep->wedged = true;
+ else if (!stall)
+ uep->wedged = false;
+
+ return 0;
+}
+
+static int isp1760_ep_set_halt(struct usb_ep *ep, int value)
+{
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ unsigned long flags;
+ int ret;
+
+ dev_dbg(uep->udc->isp->dev, "%s: %s halt on ep%02x\n", __func__,
+ value ? "set" : "clear", uep->addr);
+
+ spin_lock_irqsave(&uep->udc->lock, flags);
+ ret = __isp1760_ep_set_halt(uep, value, false);
+ spin_unlock_irqrestore(&uep->udc->lock, flags);
+
+ return ret;
+}
+
+static int isp1760_ep_set_wedge(struct usb_ep *ep)
+{
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ unsigned long flags;
+ int ret;
+
+ dev_dbg(uep->udc->isp->dev, "%s: set wedge on ep%02x)\n", __func__,
+ uep->addr);
+
+ spin_lock_irqsave(&uep->udc->lock, flags);
+ ret = __isp1760_ep_set_halt(uep, true, true);
+ spin_unlock_irqrestore(&uep->udc->lock, flags);
+
+ return ret;
+}
+
+static void isp1760_ep_fifo_flush(struct usb_ep *ep)
+{
+ struct isp1760_ep *uep = ep_to_udc_ep(ep);
+ struct isp1760_udc *udc = uep->udc;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ isp1760_udc_select_ep(uep);
+
+ /*
+ * Set the CLBUF bit twice to flush both buffers in case double
+ * buffering is enabled.
+ */
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+ isp1760_udc_write(udc, DC_CTRLFUNC, DC_CLBUF);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static const struct usb_ep_ops isp1760_ep_ops = {
+ .enable = isp1760_ep_enable,
+ .disable = isp1760_ep_disable,
+ .alloc_request = isp1760_ep_alloc_request,
+ .free_request = isp1760_ep_free_request,
+ .queue = isp1760_ep_queue,
+ .dequeue = isp1760_ep_dequeue,
+ .set_halt = isp1760_ep_set_halt,
+ .set_wedge = isp1760_ep_set_wedge,
+ .fifo_flush = isp1760_ep_fifo_flush,
+};
+
+/* -----------------------------------------------------------------------------
+ * Device States
+ */
+
+/* Called with the UDC spinlock held. */
+static void isp1760_udc_connect(struct isp1760_udc *udc)
+{
+ usb_gadget_set_state(&udc->gadget, USB_STATE_POWERED);
+ mod_timer(&udc->vbus_timer, jiffies + ISP1760_VBUS_POLL_INTERVAL);
+}
+
+/* Called with the UDC spinlock held. */
+static void isp1760_udc_disconnect(struct isp1760_udc *udc)
+{
+ if (udc->gadget.state < USB_STATE_POWERED)
+ return;
+
+ dev_dbg(udc->isp->dev, "Device disconnected in state %u\n",
+ udc->gadget.state);
+
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
+
+ if (udc->driver->disconnect)
+ udc->driver->disconnect(&udc->gadget);
+
+ del_timer(&udc->vbus_timer);
+
+ /* TODO Reset all endpoints ? */
+}
+
+static void isp1760_udc_init_hw(struct isp1760_udc *udc)
+{
+ /*
+ * The device controller currently shares its interrupt with the host
+ * controller, the DC_IRQ polarity and signaling mode are ignored. Set
+ * the to active-low level-triggered.
+ *
+ * Configure the control, in and out pipes to generate interrupts on
+ * ACK tokens only (and NYET for the out pipe). The default
+ * configuration also generates an interrupt on the first NACK token.
+ */
+ isp1760_udc_write(udc, DC_INTCONF, DC_CDBGMOD_ACK | DC_DDBGMODIN_ACK |
+ DC_DDBGMODOUT_ACK_NYET);
+
+ isp1760_udc_write(udc, DC_INTENABLE, DC_IEPRXTX(7) | DC_IEPRXTX(6) |
+ DC_IEPRXTX(5) | DC_IEPRXTX(4) | DC_IEPRXTX(3) |
+ DC_IEPRXTX(2) | DC_IEPRXTX(1) | DC_IEPRXTX(0) |
+ DC_IEP0SETUP | DC_IEVBUS | DC_IERESM | DC_IESUSP |
+ DC_IEHS_STA | DC_IEBRST);
+
+ if (udc->connected)
+ isp1760_set_pullup(udc->isp, true);
+
+ isp1760_udc_write(udc, DC_ADDRESS, DC_DEVEN);
+}
+
+static void isp1760_udc_reset(struct isp1760_udc *udc)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ /*
+ * The bus reset has reset most registers to their default value,
+ * reinitialize the UDC hardware.
+ */
+ isp1760_udc_init_hw(udc);
+
+ udc->ep0_state = ISP1760_CTRL_SETUP;
+ udc->gadget.speed = USB_SPEED_FULL;
+
+ usb_gadget_udc_reset(&udc->gadget, udc->driver);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+static void isp1760_udc_suspend(struct isp1760_udc *udc)
+{
+ if (udc->gadget.state < USB_STATE_DEFAULT)
+ return;
+
+ if (udc->driver->suspend)
+ udc->driver->suspend(&udc->gadget);
+}
+
+static void isp1760_udc_resume(struct isp1760_udc *udc)
+{
+ if (udc->gadget.state < USB_STATE_DEFAULT)
+ return;
+
+ if (udc->driver->resume)
+ udc->driver->resume(&udc->gadget);
+}
+
+/* -----------------------------------------------------------------------------
+ * Gadget Operations
+ */
+
+static int isp1760_udc_get_frame(struct usb_gadget *gadget)
+{
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+ return isp1760_udc_read(udc, DC_FRAMENUM) & ((1 << 11) - 1);
+}
+
+static int isp1760_udc_wakeup(struct usb_gadget *gadget)
+{
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+ dev_dbg(udc->isp->dev, "%s\n", __func__);
+ return -ENOTSUPP;
+}
+
+static int isp1760_udc_set_selfpowered(struct usb_gadget *gadget,
+ int is_selfpowered)
+{
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+ if (is_selfpowered)
+ udc->devstatus |= 1 << USB_DEVICE_SELF_POWERED;
+ else
+ udc->devstatus &= ~(1 << USB_DEVICE_SELF_POWERED);
+
+ return 0;
+}
+
+static int isp1760_udc_pullup(struct usb_gadget *gadget, int is_on)
+{
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+ isp1760_set_pullup(udc->isp, is_on);
+ udc->connected = is_on;
+
+ return 0;
+}
+
+static int isp1760_udc_start(struct usb_gadget *gadget,
+ struct usb_gadget_driver *driver)
+{
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+ /* The hardware doesn't support low speed. */
+ if (driver->max_speed < USB_SPEED_FULL) {
+ dev_err(udc->isp->dev, "Invalid gadget driver\n");
+ return -EINVAL;
+ }
+
+ spin_lock(&udc->lock);
+
+ if (udc->driver) {
+ dev_err(udc->isp->dev, "UDC already has a gadget driver\n");
+ spin_unlock(&udc->lock);
+ return -EBUSY;
+ }
+
+ udc->driver = driver;
+
+ spin_unlock(&udc->lock);
+
+ dev_dbg(udc->isp->dev, "starting UDC with driver %s\n",
+ driver->function);
+
+ udc->devstatus = 0;
+ udc->connected = true;
+
+ usb_gadget_set_state(&udc->gadget, USB_STATE_ATTACHED);
+
+ /* DMA isn't supported yet, don't enable the DMA clock. */
+ isp1760_udc_write(udc, DC_MODE, DC_GLINTENA);
+
+ isp1760_udc_init_hw(udc);
+
+ dev_dbg(udc->isp->dev, "UDC started with driver %s\n",
+ driver->function);
+
+ return 0;
+}
+
+static int isp1760_udc_stop(struct usb_gadget *gadget)
+{
+ struct isp1760_udc *udc = gadget_to_udc(gadget);
+
+ dev_dbg(udc->isp->dev, "%s\n", __func__);
+
+ del_timer_sync(&udc->vbus_timer);
+
+ isp1760_udc_write(udc, DC_MODE, 0);
+
+ spin_lock(&udc->lock);
+ udc->driver = NULL;
+ spin_unlock(&udc->lock);
+
+ return 0;
+}
+
+static struct usb_gadget_ops isp1760_udc_ops = {
+ .get_frame = isp1760_udc_get_frame,
+ .wakeup = isp1760_udc_wakeup,
+ .set_selfpowered = isp1760_udc_set_selfpowered,
+ .pullup = isp1760_udc_pullup,
+ .udc_start = isp1760_udc_start,
+ .udc_stop = isp1760_udc_stop,
+};
+
+/* -----------------------------------------------------------------------------
+ * Interrupt Handling
+ */
+
+static irqreturn_t isp1760_udc_irq(int irq, void *dev)
+{
+ struct isp1760_udc *udc = dev;
+ unsigned int i;
+ u32 status;
+
+ status = isp1760_udc_read(udc, DC_INTERRUPT)
+ & isp1760_udc_read(udc, DC_INTENABLE);
+ isp1760_udc_write(udc, DC_INTERRUPT, status);
+
+ if (status & DC_IEVBUS) {
+ dev_dbg(udc->isp->dev, "%s(VBUS)\n", __func__);
+ /* The VBUS interrupt is only triggered when VBUS appears. */
+ spin_lock(&udc->lock);
+ isp1760_udc_connect(udc);
+ spin_unlock(&udc->lock);
+ }
+
+ if (status & DC_IEBRST) {
+ dev_dbg(udc->isp->dev, "%s(BRST)\n", __func__);
+
+ isp1760_udc_reset(udc);
+ }
+
+ for (i = 0; i <= 7; ++i) {
+ struct isp1760_ep *ep = &udc->ep[i*2];
+
+ if (status & DC_IEPTX(i)) {
+ dev_dbg(udc->isp->dev, "%s(EPTX%u)\n", __func__, i);
+ isp1760_ep_tx_complete(ep);
+ }
+
+ if (status & DC_IEPRX(i)) {
+ dev_dbg(udc->isp->dev, "%s(EPRX%u)\n", __func__, i);
+ isp1760_ep_rx_ready(i ? ep - 1 : ep);
+ }
+ }
+
+ if (status & DC_IEP0SETUP) {
+ dev_dbg(udc->isp->dev, "%s(EP0SETUP)\n", __func__);
+
+ isp1760_ep0_setup(udc);
+ }
+
+ if (status & DC_IERESM) {
+ dev_dbg(udc->isp->dev, "%s(RESM)\n", __func__);
+ isp1760_udc_resume(udc);
+ }
+
+ if (status & DC_IESUSP) {
+ dev_dbg(udc->isp->dev, "%s(SUSP)\n", __func__);
+
+ spin_lock(&udc->lock);
+ if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+ isp1760_udc_disconnect(udc);
+ else
+ isp1760_udc_suspend(udc);
+ spin_unlock(&udc->lock);
+ }
+
+ if (status & DC_IEHS_STA) {
+ dev_dbg(udc->isp->dev, "%s(HS_STA)\n", __func__);
+ udc->gadget.speed = USB_SPEED_HIGH;
+ }
+
+ return status ? IRQ_HANDLED : IRQ_NONE;
+}
+
+static void isp1760_udc_vbus_poll(unsigned long data)
+{
+ struct isp1760_udc *udc = (struct isp1760_udc *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&udc->lock, flags);
+
+ if (!(isp1760_udc_read(udc, DC_MODE) & DC_VBUSSTAT))
+ isp1760_udc_disconnect(udc);
+ else if (udc->gadget.state >= USB_STATE_POWERED)
+ mod_timer(&udc->vbus_timer,
+ jiffies + ISP1760_VBUS_POLL_INTERVAL);
+
+ spin_unlock_irqrestore(&udc->lock, flags);
+}
+
+/* -----------------------------------------------------------------------------
+ * Registration
+ */
+
+static void isp1760_udc_init_eps(struct isp1760_udc *udc)
+{
+ unsigned int i;
+
+ INIT_LIST_HEAD(&udc->gadget.ep_list);
+
+ for (i = 0; i < ARRAY_SIZE(udc->ep); ++i) {
+ struct isp1760_ep *ep = &udc->ep[i];
+ unsigned int ep_num = (i + 1) / 2;
+ bool is_in = !(i & 1);
+
+ ep->udc = udc;
+
+ INIT_LIST_HEAD(&ep->queue);
+
+ ep->addr = (ep_num && is_in ? USB_DIR_IN : USB_DIR_OUT)
+ | ep_num;
+ ep->desc = NULL;
+
+ sprintf(ep->name, "ep%u%s", ep_num,
+ ep_num ? (is_in ? "in" : "out") : "");
+
+ ep->ep.ops = &isp1760_ep_ops;
+ ep->ep.name = ep->name;
+
+ /*
+ * Hardcode the maximum packet sizes for now, to 64 bytes for
+ * the control endpoint and 512 bytes for all other endpoints.
+ * This fits in the 8kB FIFO without double-buffering.
+ */
+ if (ep_num == 0) {
+ ep->ep.maxpacket = 64;
+ ep->maxpacket = 64;
+ udc->gadget.ep0 = &ep->ep;
+ } else {
+ ep->ep.maxpacket = 512;
+ ep->maxpacket = 0;
+ list_add_tail(&ep->ep.ep_list, &udc->gadget.ep_list);
+ }
+ }
+}
+
+static int isp1760_udc_init(struct isp1760_udc *udc)
+{
+ u16 scratch;
+ u32 chipid;
+
+ /*
+ * Check that the controller is present by writing to the scratch
+ * register, modifying the bus pattern by reading from the chip ID
+ * register, and reading the scratch register value back. The chip ID
+ * and scratch register contents must match the expected values.
+ */
+ isp1760_udc_write(udc, DC_SCRATCH, 0xbabe);
+ chipid = isp1760_udc_read(udc, DC_CHIPID);
+ scratch = isp1760_udc_read(udc, DC_SCRATCH);
+
+ if (scratch != 0xbabe) {
+ dev_err(udc->isp->dev,
+ "udc: scratch test failed (0x%04x/0x%08x)\n",
+ scratch, chipid);
+ return -ENODEV;
+ }
+
+ if (chipid != 0x00011582) {
+ dev_err(udc->isp->dev, "udc: invalid chip ID 0x%08x\n", chipid);
+ return -ENODEV;
+ }
+
+ /* Reset the device controller. */
+ isp1760_udc_write(udc, DC_MODE, DC_SFRESET);
+ usleep_range(10000, 11000);
+ isp1760_udc_write(udc, DC_MODE, 0);
+ usleep_range(10000, 11000);
+
+ return 0;
+}
+
+int isp1760_udc_register(struct isp1760_device *isp, int irq,
+ unsigned long irqflags)
+{
+ struct isp1760_udc *udc = &isp->udc;
+ const char *devname;
+ int ret;
+
+ udc->irq = -1;
+ udc->isp = isp;
+ udc->regs = isp->regs;
+
+ spin_lock_init(&udc->lock);
+ setup_timer(&udc->vbus_timer, isp1760_udc_vbus_poll,
+ (unsigned long)udc);
+
+ ret = isp1760_udc_init(udc);
+ if (ret < 0)
+ return ret;
+
+ devname = dev_name(isp->dev);
+ udc->irqname = kmalloc(strlen(devname) + 7, GFP_KERNEL);
+ if (!udc->irqname)
+ return -ENOMEM;
+
+ sprintf(udc->irqname, "%s (udc)", devname);
+
+ ret = request_irq(irq, isp1760_udc_irq, IRQF_SHARED | IRQF_DISABLED |
+ irqflags, udc->irqname, udc);
+ if (ret < 0)
+ goto error;
+
+ udc->irq = irq;
+
+ /*
+ * Initialize the gadget static fields and register its device. Gadget
+ * fields that vary during the life time of the gadget are initialized
+ * by the UDC core.
+ */
+ udc->gadget.ops = &isp1760_udc_ops;
+ udc->gadget.speed = USB_SPEED_UNKNOWN;
+ udc->gadget.max_speed = USB_SPEED_HIGH;
+ udc->gadget.name = "isp1761_udc";
+
+ isp1760_udc_init_eps(udc);
+
+ ret = usb_add_gadget_udc(isp->dev, &udc->gadget);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ if (udc->irq >= 0)
+ free_irq(udc->irq, udc);
+ kfree(udc->irqname);
+
+ return ret;
+}
+
+void isp1760_udc_unregister(struct isp1760_device *isp)
+{
+ struct isp1760_udc *udc = &isp->udc;
+
+ if (!udc->isp)
+ return;
+
+ usb_del_gadget_udc(&udc->gadget);
+
+ free_irq(udc->irq, udc);
+ kfree(udc->irqname);
+}
diff --git a/drivers/usb/isp1760/isp1760-udc.h b/drivers/usb/isp1760/isp1760-udc.h
new file mode 100644
index 000000000000..26899ed81145
--- /dev/null
+++ b/drivers/usb/isp1760/isp1760-udc.h
@@ -0,0 +1,106 @@
+/*
+ * Driver for the NXP ISP1761 device controller
+ *
+ * Copyright 2014 Ideas on Board Oy
+ *
+ * Contacts:
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+
+#ifndef _ISP1760_UDC_H_
+#define _ISP1760_UDC_H_
+
+#include <linux/ioport.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/timer.h>
+#include <linux/usb/gadget.h>
+
+struct isp1760_device;
+struct isp1760_udc;
+
+enum isp1760_ctrl_state {
+ ISP1760_CTRL_SETUP, /* Waiting for a SETUP transaction */
+ ISP1760_CTRL_DATA_IN, /* Setup received, data IN stage */
+ ISP1760_CTRL_DATA_OUT, /* Setup received, data OUT stage */
+ ISP1760_CTRL_STATUS, /* 0-length request in status stage */
+};
+
+struct isp1760_ep {
+ struct isp1760_udc *udc;
+ struct usb_ep ep;
+
+ struct list_head queue;
+
+ unsigned int addr;
+ unsigned int maxpacket;
+ char name[7];
+
+ const struct usb_endpoint_descriptor *desc;
+
+ bool rx_pending;
+ bool halted;
+ bool wedged;
+};
+
+/**
+ * struct isp1760_udc - UDC state information
+ * irq: IRQ number
+ * irqname: IRQ name (as passed to request_irq)
+ * regs: Base address of the UDC registers
+ * driver: Gadget driver
+ * gadget: Gadget device
+ * lock: Protects driver, vbus_timer, ep, ep0_*, DC_EPINDEX register
+ * ep: Array of endpoints
+ * ep0_state: Control request state for endpoint 0
+ * ep0_dir: Direction of the current control request
+ * ep0_length: Length of the current control request
+ * connected: Tracks gadget driver bus connection state
+ */
+struct isp1760_udc {
+#ifdef CONFIG_USB_ISP1761_UDC
+ struct isp1760_device *isp;
+
+ int irq;
+ char *irqname;
+ void __iomem *regs;
+
+ struct usb_gadget_driver *driver;
+ struct usb_gadget gadget;
+
+ spinlock_t lock;
+ struct timer_list vbus_timer;
+
+ struct isp1760_ep ep[15];
+
+ enum isp1760_ctrl_state ep0_state;
+ u8 ep0_dir;
+ u16 ep0_length;
+
+ bool connected;
+
+ unsigned int devstatus;
+#endif
+};
+
+#ifdef CONFIG_USB_ISP1761_UDC
+int isp1760_udc_register(struct isp1760_device *isp, int irq,
+ unsigned long irqflags);
+void isp1760_udc_unregister(struct isp1760_device *isp);
+#else
+static inline int isp1760_udc_register(struct isp1760_device *isp, int irq,
+ unsigned long irqflags)
+{
+ return 0;
+}
+
+static inline void isp1760_udc_unregister(struct isp1760_device *isp)
+{
+}
+#endif
+
+#endif
diff --git a/drivers/usb/misc/uss720.c b/drivers/usb/misc/uss720.c
index 40ef40affe83..588d62a73e1a 100644
--- a/drivers/usb/misc/uss720.c
+++ b/drivers/usb/misc/uss720.c
@@ -124,12 +124,8 @@ static void async_complete(struct urb *urb)
} else if (rq->dr->bRequest == 3) {
memcpy(priv->reg, rq->reg, sizeof(priv->reg));
#if 0
- dev_dbg(&priv->usbdev->dev,
- "async_complete regs %02x %02x %02x %02x %02x %02x %02x\n",
- (unsigned int)priv->reg[0], (unsigned int)priv->reg[1],
- (unsigned int)priv->reg[2], (unsigned int)priv->reg[3],
- (unsigned int)priv->reg[4], (unsigned int)priv->reg[5],
- (unsigned int)priv->reg[6]);
+ dev_dbg(&priv->usbdev->dev, "async_complete regs %7ph\n",
+ priv->reg);
#endif
/* if nAck interrupts are enabled and we have an interrupt, call the interrupt procedure */
if (rq->reg[2] & rq->reg[1] & 0x10 && pp)
@@ -742,9 +738,7 @@ static int uss720_probe(struct usb_interface *intf,
set_1284_register(pp, 2, 0x0c, GFP_KERNEL);
/* debugging */
get_1284_register(pp, 0, &reg, GFP_KERNEL);
- dev_dbg(&intf->dev, "reg: %02x %02x %02x %02x %02x %02x %02x\n",
- priv->reg[0], priv->reg[1], priv->reg[2], priv->reg[3],
- priv->reg[4], priv->reg[5], priv->reg[6]);
+ dev_dbg(&intf->dev, "reg: %7ph\n", priv->reg);
endpoint = &interface->endpoint[2];
dev_dbg(&intf->dev, "epaddr %d interval %d\n",
diff --git a/drivers/usb/musb/Kconfig b/drivers/usb/musb/Kconfig
index b005010240e5..14e1628483d9 100644
--- a/drivers/usb/musb/Kconfig
+++ b/drivers/usb/musb/Kconfig
@@ -63,11 +63,13 @@ comment "Platform Glue Layer"
config USB_MUSB_DAVINCI
tristate "DaVinci"
depends on ARCH_DAVINCI_DMx
+ depends on NOP_USB_XCEIV
depends on BROKEN
config USB_MUSB_DA8XX
tristate "DA8xx/OMAP-L1x"
depends on ARCH_DAVINCI_DA8XX
+ depends on NOP_USB_XCEIV
depends on BROKEN
config USB_MUSB_TUSB6010
@@ -77,12 +79,13 @@ config USB_MUSB_TUSB6010
config USB_MUSB_OMAP2PLUS
tristate "OMAP2430 and onwards"
- depends on ARCH_OMAP2PLUS && USB
+ depends on ARCH_OMAP2PLUS && USB && OMAP_CONTROL_PHY
select GENERIC_PHY
config USB_MUSB_AM35X
tristate "AM35x"
depends on ARCH_OMAP
+ depends on NOP_USB_XCEIV
config USB_MUSB_DSPS
tristate "TI DSPS platforms"
@@ -93,6 +96,7 @@ config USB_MUSB_DSPS
config USB_MUSB_BLACKFIN
tristate "Blackfin"
depends on (BF54x && !BF544) || (BF52x && ! BF522 && !BF523)
+ depends on NOP_USB_XCEIV
config USB_MUSB_UX500
tristate "Ux500 platforms"
@@ -100,6 +104,7 @@ config USB_MUSB_UX500
config USB_MUSB_JZ4740
tristate "JZ4740"
+ depends on NOP_USB_XCEIV
depends on MACH_JZ4740 || COMPILE_TEST
depends on USB_MUSB_GADGET
depends on USB_OTG_BLACKLIST_HUB
diff --git a/drivers/usb/musb/blackfin.c b/drivers/usb/musb/blackfin.c
index 178250145613..6123b748d262 100644
--- a/drivers/usb/musb/blackfin.c
+++ b/drivers/usb/musb/blackfin.c
@@ -608,7 +608,7 @@ static SIMPLE_DEV_PM_OPS(bfin_pm_ops, bfin_suspend, bfin_resume);
static struct platform_driver bfin_driver = {
.probe = bfin_probe,
- .remove = __exit_p(bfin_remove),
+ .remove = bfin_remove,
.driver = {
.name = "musb-blackfin",
.pm = &bfin_pm_ops,
diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index 34cce3e38c49..e6f4cbfeed97 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -567,6 +567,7 @@ static irqreturn_t musb_stage0_irq(struct musb *musb, u8 int_usb,
musb->xceiv->otg->state = OTG_STATE_A_HOST;
musb->is_active = 1;
+ musb_host_resume_root_hub(musb);
break;
case OTG_STATE_B_WAIT_ACON:
musb->xceiv->otg->state = OTG_STATE_B_PERIPHERAL;
@@ -2500,6 +2501,12 @@ static int musb_runtime_resume(struct device *dev)
musb_restore_context(musb);
first = 0;
+ if (musb->need_finish_resume) {
+ musb->need_finish_resume = 0;
+ schedule_delayed_work(&musb->finish_resume_work,
+ msecs_to_jiffies(20));
+ }
+
return 0;
}
diff --git a/drivers/usb/musb/musb_cppi41.c b/drivers/usb/musb/musb_cppi41.c
index c39a16ad7832..be84562d021b 100644
--- a/drivers/usb/musb/musb_cppi41.c
+++ b/drivers/usb/musb/musb_cppi41.c
@@ -9,9 +9,9 @@
#define RNDIS_REG(x) (0x80 + ((x - 1) * 4))
-#define EP_MODE_AUTOREG_NONE 0
-#define EP_MODE_AUTOREG_ALL_NEOP 1
-#define EP_MODE_AUTOREG_ALWAYS 3
+#define EP_MODE_AUTOREQ_NONE 0
+#define EP_MODE_AUTOREQ_ALL_NEOP 1
+#define EP_MODE_AUTOREQ_ALWAYS 3
#define EP_MODE_DMA_TRANSPARENT 0
#define EP_MODE_DMA_RNDIS 1
@@ -404,19 +404,19 @@ static bool cppi41_configure_channel(struct dma_channel *channel,
/* auto req */
cppi41_set_autoreq_mode(cppi41_channel,
- EP_MODE_AUTOREG_ALL_NEOP);
+ EP_MODE_AUTOREQ_ALL_NEOP);
} else {
musb_writel(musb->ctrl_base,
RNDIS_REG(cppi41_channel->port_num), 0);
cppi41_set_dma_mode(cppi41_channel,
EP_MODE_DMA_TRANSPARENT);
cppi41_set_autoreq_mode(cppi41_channel,
- EP_MODE_AUTOREG_NONE);
+ EP_MODE_AUTOREQ_NONE);
}
} else {
/* fallback mode */
cppi41_set_dma_mode(cppi41_channel, EP_MODE_DMA_TRANSPARENT);
- cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREG_NONE);
+ cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
len = min_t(u32, packet_sz, len);
}
cppi41_channel->prog_len = len;
@@ -549,10 +549,15 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
csr &= ~MUSB_TXCSR_DMAENAB;
musb_writew(epio, MUSB_TXCSR, csr);
} else {
+ cppi41_set_autoreq_mode(cppi41_channel, EP_MODE_AUTOREQ_NONE);
+
csr = musb_readw(epio, MUSB_RXCSR);
csr &= ~(MUSB_RXCSR_H_REQPKT | MUSB_RXCSR_DMAENAB);
musb_writew(epio, MUSB_RXCSR, csr);
+ /* wait to drain cppi dma pipe line */
+ udelay(50);
+
csr = musb_readw(epio, MUSB_RXCSR);
if (csr & MUSB_RXCSR_RXPKTRDY) {
csr |= MUSB_RXCSR_FLUSHFIFO;
@@ -566,13 +571,14 @@ static int cppi41_dma_channel_abort(struct dma_channel *channel)
tdbit <<= 16;
do {
- musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+ if (is_tx)
+ musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
ret = dmaengine_terminate_all(cppi41_channel->dc);
} while (ret == -EAGAIN);
- musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
-
if (is_tx) {
+ musb_writel(musb->ctrl_base, USB_TDOWN, tdbit);
+
csr = musb_readw(epio, MUSB_TXCSR);
if (csr & MUSB_TXCSR_TXPKTRDY) {
csr |= MUSB_TXCSR_FLUSHFIFO;
diff --git a/drivers/usb/musb/musb_debugfs.c b/drivers/usb/musb/musb_debugfs.c
index 48131aa8472c..78a283e9ce40 100644
--- a/drivers/usb/musb/musb_debugfs.c
+++ b/drivers/usb/musb/musb_debugfs.c
@@ -196,7 +196,7 @@ static ssize_t musb_test_mode_write(struct file *file,
memset(buf, 0x00, sizeof(buf));
- if (copy_from_user(&buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
+ if (copy_from_user(buf, ubuf, min_t(size_t, sizeof(buf) - 1, count)))
return -EFAULT;
if (strstarts(buf, "force host"))
diff --git a/drivers/usb/musb/musb_gadget.c b/drivers/usb/musb/musb_gadget.c
index 49b04cb6f5ca..b2d9040c7685 100644
--- a/drivers/usb/musb/musb_gadget.c
+++ b/drivers/usb/musb/musb_gadget.c
@@ -1612,9 +1612,7 @@ done:
static int
musb_gadget_set_self_powered(struct usb_gadget *gadget, int is_selfpowered)
{
- struct musb *musb = gadget_to_musb(gadget);
-
- musb->is_self_powered = !!is_selfpowered;
+ gadget->is_selfpowered = !!is_selfpowered;
return 0;
}
diff --git a/drivers/usb/musb/musb_gadget_ep0.c b/drivers/usb/musb/musb_gadget_ep0.c
index 2af45a0c8930..10d30afe4a3c 100644
--- a/drivers/usb/musb/musb_gadget_ep0.c
+++ b/drivers/usb/musb/musb_gadget_ep0.c
@@ -85,7 +85,7 @@ static int service_tx_status_request(
switch (recip) {
case USB_RECIP_DEVICE:
- result[0] = musb->is_self_powered << USB_DEVICE_SELF_POWERED;
+ result[0] = musb->g.is_selfpowered << USB_DEVICE_SELF_POWERED;
result[0] |= musb->may_wakeup << USB_DEVICE_REMOTE_WAKEUP;
if (musb->g.is_otg) {
result[0] |= musb->g.b_hnp_enable
diff --git a/drivers/usb/musb/musb_virthub.c b/drivers/usb/musb/musb_virthub.c
index b072420e44f5..294e159f4afe 100644
--- a/drivers/usb/musb/musb_virthub.c
+++ b/drivers/usb/musb/musb_virthub.c
@@ -72,7 +72,6 @@ void musb_host_finish_resume(struct work_struct *work)
musb->xceiv->otg->state = OTG_STATE_A_HOST;
spin_unlock_irqrestore(&musb->lock, flags);
- musb_host_resume_root_hub(musb);
}
void musb_port_suspend(struct musb *musb, bool do_suspend)
@@ -349,9 +348,9 @@ int musb_hub_control(
desc->bDescriptorType = 0x29;
desc->bNbrPorts = 1;
desc->wHubCharacteristics = cpu_to_le16(
- 0x0001 /* per-port power switching */
- | 0x0010 /* no overcurrent reporting */
- );
+ HUB_CHAR_INDV_PORT_LPSM /* per-port power switching */
+ | HUB_CHAR_NO_OCPM /* no overcurrent reporting */
+ );
desc->bPwrOn2PwrGood = 5; /* msec/2 */
desc->bHubContrCurrent = 0;
diff --git a/drivers/usb/phy/Kconfig b/drivers/usb/phy/Kconfig
index c6d0c8e745b9..52d3d58252e1 100644
--- a/drivers/usb/phy/Kconfig
+++ b/drivers/usb/phy/Kconfig
@@ -119,7 +119,7 @@ config TAHVO_USB
config TAHVO_USB_HOST_BY_DEFAULT
depends on TAHVO_USB
- boolean "Device in USB host mode by default"
+ bool "Device in USB host mode by default"
help
Say Y here, if you want the device to enter USB host mode
by default on bootup.
diff --git a/drivers/usb/phy/phy-fsl-usb.c b/drivers/usb/phy/phy-fsl-usb.c
index ab38aa32a6c1..94eb2923afed 100644
--- a/drivers/usb/phy/phy-fsl-usb.c
+++ b/drivers/usb/phy/phy-fsl-usb.c
@@ -107,19 +107,6 @@ static void (*_fsl_writel)(u32 v, unsigned __iomem *p);
#define fsl_writel(val, addr) writel(val, addr)
#endif /* CONFIG_PPC32 */
-/* Routines to access transceiver ULPI registers */
-u8 view_ulpi(u8 addr)
-{
- u32 temp;
-
- temp = 0x40000000 | (addr << 16);
- fsl_writel(temp, &usb_dr_regs->ulpiview);
- udelay(1000);
- while (temp & 0x40)
- temp = fsl_readl(&usb_dr_regs->ulpiview);
- return (le32_to_cpu(temp) & 0x0000ff00) >> 8;
-}
-
int write_ulpi(u8 addr, u8 data)
{
u32 temp;
@@ -460,28 +447,6 @@ static void fsl_otg_fsm_del_timer(struct otg_fsm *fsm, enum otg_fsm_timer t)
fsl_otg_del_timer(fsm, timer);
}
-/*
- * Reduce timer count by 1, and find timeout conditions.
- * Called by fsl_otg 1ms timer interrupt
- */
-int fsl_otg_tick_timer(void)
-{
- struct fsl_otg_timer *tmp_timer, *del_tmp;
- int expired = 0;
-
- list_for_each_entry_safe(tmp_timer, del_tmp, &active_timers, list) {
- tmp_timer->count--;
- /* check if timer expires */
- if (!tmp_timer->count) {
- list_del(&tmp_timer->list);
- tmp_timer->function(tmp_timer->data);
- expired = 1;
- }
- }
-
- return expired;
-}
-
/* Reset controller, not reset the bus */
void otg_reset_controller(void)
{
diff --git a/drivers/usb/phy/phy-generic.c b/drivers/usb/phy/phy-generic.c
index f1b719b45a53..70be50b734b2 100644
--- a/drivers/usb/phy/phy-generic.c
+++ b/drivers/usb/phy/phy-generic.c
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
+#include <linux/usb/gadget.h>
#include <linux/usb/otg.h>
#include <linux/usb/usb_phy_generic.h>
#include <linux/slab.h>
@@ -39,6 +40,10 @@
#include "phy-generic.h"
+#define VBUS_IRQ_FLAGS \
+ (IRQF_SHARED | IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | \
+ IRQF_ONESHOT)
+
struct platform_device *usb_phy_generic_register(void)
{
return platform_device_register_simple("usb_phy_generic",
@@ -59,19 +64,79 @@ static int nop_set_suspend(struct usb_phy *x, int suspend)
static void nop_reset_set(struct usb_phy_generic *nop, int asserted)
{
- int value;
+ if (!nop->gpiod_reset)
+ return;
+
+ gpiod_direction_output(nop->gpiod_reset, !asserted);
+ usleep_range(10000, 20000);
+ gpiod_set_value(nop->gpiod_reset, asserted);
+}
+
+/* interface to regulator framework */
+static void nop_set_vbus_draw(struct usb_phy_generic *nop, unsigned mA)
+{
+ struct regulator *vbus_draw = nop->vbus_draw;
+ int enabled;
+ int ret;
- if (!gpio_is_valid(nop->gpio_reset))
+ if (!vbus_draw)
return;
- value = asserted;
- if (nop->reset_active_low)
- value = !value;
+ enabled = nop->vbus_draw_enabled;
+ if (mA) {
+ regulator_set_current_limit(vbus_draw, 0, 1000 * mA);
+ if (!enabled) {
+ ret = regulator_enable(vbus_draw);
+ if (ret < 0)
+ return;
+ nop->vbus_draw_enabled = 1;
+ }
+ } else {
+ if (enabled) {
+ ret = regulator_disable(vbus_draw);
+ if (ret < 0)
+ return;
+ nop->vbus_draw_enabled = 0;
+ }
+ }
+ nop->mA = mA;
+}
+
+
+static irqreturn_t nop_gpio_vbus_thread(int irq, void *data)
+{
+ struct usb_phy_generic *nop = data;
+ struct usb_otg *otg = nop->phy.otg;
+ int vbus, status;
+
+ vbus = gpiod_get_value(nop->gpiod_vbus);
+ if ((vbus ^ nop->vbus) == 0)
+ return IRQ_HANDLED;
+ nop->vbus = vbus;
+
+ if (vbus) {
+ status = USB_EVENT_VBUS;
+ otg->state = OTG_STATE_B_PERIPHERAL;
+ nop->phy.last_event = status;
+ usb_gadget_vbus_connect(otg->gadget);
+
+ /* drawing a "unit load" is *always* OK, except for OTG */
+ nop_set_vbus_draw(nop, 100);
+
+ atomic_notifier_call_chain(&nop->phy.notifier, status,
+ otg->gadget);
+ } else {
+ nop_set_vbus_draw(nop, 0);
- gpio_set_value_cansleep(nop->gpio_reset, value);
+ usb_gadget_vbus_disconnect(otg->gadget);
+ status = USB_EVENT_NONE;
+ otg->state = OTG_STATE_B_IDLE;
+ nop->phy.last_event = status;
- if (!asserted)
- usleep_range(10000, 20000);
+ atomic_notifier_call_chain(&nop->phy.notifier, status,
+ otg->gadget);
+ }
+ return IRQ_HANDLED;
}
int usb_gen_phy_init(struct usb_phy *phy)
@@ -143,36 +208,47 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
struct usb_phy_generic_platform_data *pdata)
{
enum usb_phy_type type = USB_PHY_TYPE_USB2;
- int err;
+ int err = 0;
u32 clk_rate = 0;
bool needs_vcc = false;
- nop->reset_active_low = true; /* default behaviour */
-
if (dev->of_node) {
struct device_node *node = dev->of_node;
- enum of_gpio_flags flags = 0;
if (of_property_read_u32(node, "clock-frequency", &clk_rate))
clk_rate = 0;
needs_vcc = of_property_read_bool(node, "vcc-supply");
- nop->gpio_reset = of_get_named_gpio_flags(node, "reset-gpios",
- 0, &flags);
- if (nop->gpio_reset == -EPROBE_DEFER)
- return -EPROBE_DEFER;
-
- nop->reset_active_low = flags & OF_GPIO_ACTIVE_LOW;
-
+ nop->gpiod_reset = devm_gpiod_get_optional(dev, "reset");
+ err = PTR_ERR_OR_ZERO(nop->gpiod_reset);
+ if (!err) {
+ nop->gpiod_vbus = devm_gpiod_get_optional(dev,
+ "vbus-detect");
+ err = PTR_ERR_OR_ZERO(nop->gpiod_vbus);
+ }
} else if (pdata) {
type = pdata->type;
clk_rate = pdata->clk_rate;
needs_vcc = pdata->needs_vcc;
- nop->gpio_reset = pdata->gpio_reset;
- } else {
- nop->gpio_reset = -1;
+ if (gpio_is_valid(pdata->gpio_reset)) {
+ err = devm_gpio_request_one(dev, pdata->gpio_reset, 0,
+ dev_name(dev));
+ if (!err)
+ nop->gpiod_reset =
+ gpio_to_desc(pdata->gpio_reset);
+ }
+ nop->gpiod_vbus = pdata->gpiod_vbus;
+ }
+
+ if (err == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ if (err) {
+ dev_err(dev, "Error requesting RESET or VBUS GPIO\n");
+ return err;
}
+ if (nop->gpiod_reset)
+ gpiod_direction_output(nop->gpiod_reset, 1);
nop->phy.otg = devm_kzalloc(dev, sizeof(*nop->phy.otg),
GFP_KERNEL);
@@ -201,24 +277,6 @@ int usb_phy_gen_create_phy(struct device *dev, struct usb_phy_generic *nop,
return -EPROBE_DEFER;
}
- if (gpio_is_valid(nop->gpio_reset)) {
- unsigned long gpio_flags;
-
- /* Assert RESET */
- if (nop->reset_active_low)
- gpio_flags = GPIOF_OUT_INIT_LOW;
- else
- gpio_flags = GPIOF_OUT_INIT_HIGH;
-
- err = devm_gpio_request_one(dev, nop->gpio_reset,
- gpio_flags, dev_name(dev));
- if (err) {
- dev_err(dev, "Error requesting RESET GPIO %d\n",
- nop->gpio_reset);
- return err;
- }
- }
-
nop->dev = dev;
nop->phy.dev = nop->dev;
nop->phy.label = "nop-xceiv";
@@ -247,6 +305,18 @@ static int usb_phy_generic_probe(struct platform_device *pdev)
err = usb_phy_gen_create_phy(dev, nop, dev_get_platdata(&pdev->dev));
if (err)
return err;
+ if (nop->gpiod_vbus) {
+ err = devm_request_threaded_irq(&pdev->dev,
+ gpiod_to_irq(nop->gpiod_vbus),
+ NULL, nop_gpio_vbus_thread,
+ VBUS_IRQ_FLAGS, "vbus_detect",
+ nop);
+ if (err) {
+ dev_err(&pdev->dev, "can't request irq %i, err: %d\n",
+ gpiod_to_irq(nop->gpiod_vbus), err);
+ return err;
+ }
+ }
nop->phy.init = usb_gen_phy_init;
nop->phy.shutdown = usb_gen_phy_shutdown;
diff --git a/drivers/usb/phy/phy-generic.h b/drivers/usb/phy/phy-generic.h
index d8feacc0b7fb..0d0eadd54ed9 100644
--- a/drivers/usb/phy/phy-generic.h
+++ b/drivers/usb/phy/phy-generic.h
@@ -2,14 +2,20 @@
#define _PHY_GENERIC_H_
#include <linux/usb/usb_phy_generic.h>
+#include <linux/gpio/consumer.h>
+#include <linux/regulator/consumer.h>
struct usb_phy_generic {
struct usb_phy phy;
struct device *dev;
struct clk *clk;
struct regulator *vcc;
- int gpio_reset;
- bool reset_active_low;
+ struct gpio_desc *gpiod_reset;
+ struct gpio_desc *gpiod_vbus;
+ struct regulator *vbus_draw;
+ bool vbus_draw_enabled;
+ unsigned long mA;
+ unsigned int vbus;
};
int usb_gen_phy_init(struct usb_phy *phy);
diff --git a/drivers/usb/phy/phy-mxs-usb.c b/drivers/usb/phy/phy-mxs-usb.c
index b9589f663683..8f7cb068d29b 100644
--- a/drivers/usb/phy/phy-mxs-usb.c
+++ b/drivers/usb/phy/phy-mxs-usb.c
@@ -40,6 +40,7 @@
#define BM_USBPHY_CTRL_SFTRST BIT(31)
#define BM_USBPHY_CTRL_CLKGATE BIT(30)
+#define BM_USBPHY_CTRL_OTG_ID_VALUE BIT(27)
#define BM_USBPHY_CTRL_ENAUTOSET_USBCLKS BIT(26)
#define BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE BIT(25)
#define BM_USBPHY_CTRL_ENVBUSCHG_WKUP BIT(23)
@@ -69,6 +70,9 @@
#define ANADIG_USB2_LOOPBACK_SET 0x244
#define ANADIG_USB2_LOOPBACK_CLR 0x248
+#define ANADIG_USB1_MISC 0x1f0
+#define ANADIG_USB2_MISC 0x250
+
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG BIT(12)
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG_SL BIT(11)
@@ -80,6 +84,11 @@
#define BM_ANADIG_USB2_LOOPBACK_UTMI_DIG_TST1 BIT(2)
#define BM_ANADIG_USB2_LOOPBACK_TSTI_TX_EN BIT(5)
+#define BM_ANADIG_USB1_MISC_RX_VPIN_FS BIT(29)
+#define BM_ANADIG_USB1_MISC_RX_VMIN_FS BIT(28)
+#define BM_ANADIG_USB2_MISC_RX_VPIN_FS BIT(29)
+#define BM_ANADIG_USB2_MISC_RX_VMIN_FS BIT(28)
+
#define to_mxs_phy(p) container_of((p), struct mxs_phy, phy)
/* Do disconnection between PHY and controller without vbus */
@@ -131,8 +140,7 @@ static const struct mxs_phy_data vf610_phy_data = {
};
static const struct mxs_phy_data imx6sx_phy_data = {
- .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS |
- MXS_PHY_NEED_IP_FIX,
+ .flags = MXS_PHY_DISCONNECT_LINE_WITHOUT_VBUS,
};
static const struct of_device_id mxs_phy_dt_ids[] = {
@@ -256,6 +264,18 @@ static void __mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool disconnect)
usleep_range(500, 1000);
}
+static bool mxs_phy_is_otg_host(struct mxs_phy *mxs_phy)
+{
+ void __iomem *base = mxs_phy->phy.io_priv;
+ u32 phyctrl = readl(base + HW_USBPHY_CTRL);
+
+ if (IS_ENABLED(CONFIG_USB_OTG) &&
+ !(phyctrl & BM_USBPHY_CTRL_OTG_ID_VALUE))
+ return true;
+
+ return false;
+}
+
static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
{
bool vbus_is_on = false;
@@ -270,7 +290,7 @@ static void mxs_phy_disconnect_line(struct mxs_phy *mxs_phy, bool on)
vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
- if (on && !vbus_is_on)
+ if (on && !vbus_is_on && !mxs_phy_is_otg_host(mxs_phy))
__mxs_phy_disconnect_line(mxs_phy, true);
else
__mxs_phy_disconnect_line(mxs_phy, false);
@@ -293,6 +313,17 @@ static int mxs_phy_init(struct usb_phy *phy)
static void mxs_phy_shutdown(struct usb_phy *phy)
{
struct mxs_phy *mxs_phy = to_mxs_phy(phy);
+ u32 value = BM_USBPHY_CTRL_ENVBUSCHG_WKUP |
+ BM_USBPHY_CTRL_ENDPDMCHG_WKUP |
+ BM_USBPHY_CTRL_ENIDCHG_WKUP |
+ BM_USBPHY_CTRL_ENAUTOSET_USBCLKS |
+ BM_USBPHY_CTRL_ENAUTOCLR_USBCLKGATE |
+ BM_USBPHY_CTRL_ENAUTOCLR_PHY_PWD |
+ BM_USBPHY_CTRL_ENAUTOCLR_CLKGATE |
+ BM_USBPHY_CTRL_ENAUTO_PWRON_PLL;
+
+ writel(value, phy->io_priv + HW_USBPHY_CTRL_CLR);
+ writel(0xffffffff, phy->io_priv + HW_USBPHY_PWD);
writel(BM_USBPHY_CTRL_CLKGATE,
phy->io_priv + HW_USBPHY_CTRL_SET);
@@ -300,13 +331,56 @@ static void mxs_phy_shutdown(struct usb_phy *phy)
clk_disable_unprepare(mxs_phy->clk);
}
+static bool mxs_phy_is_low_speed_connection(struct mxs_phy *mxs_phy)
+{
+ unsigned int line_state;
+ /* bit definition is the same for all controllers */
+ unsigned int dp_bit = BM_ANADIG_USB1_MISC_RX_VPIN_FS,
+ dm_bit = BM_ANADIG_USB1_MISC_RX_VMIN_FS;
+ unsigned int reg = ANADIG_USB1_MISC;
+
+ /* If the SoCs don't have anatop, quit */
+ if (!mxs_phy->regmap_anatop)
+ return false;
+
+ if (mxs_phy->port_id == 0)
+ reg = ANADIG_USB1_MISC;
+ else if (mxs_phy->port_id == 1)
+ reg = ANADIG_USB2_MISC;
+
+ regmap_read(mxs_phy->regmap_anatop, reg, &line_state);
+
+ if ((line_state & (dp_bit | dm_bit)) == dm_bit)
+ return true;
+ else
+ return false;
+}
+
static int mxs_phy_suspend(struct usb_phy *x, int suspend)
{
int ret;
struct mxs_phy *mxs_phy = to_mxs_phy(x);
+ bool low_speed_connection, vbus_is_on;
+
+ low_speed_connection = mxs_phy_is_low_speed_connection(mxs_phy);
+ vbus_is_on = mxs_phy_get_vbus_status(mxs_phy);
if (suspend) {
- writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+ /*
+ * FIXME: Do not power down RXPWD1PT1 bit for low speed
+ * connect. The low speed connection will have problem at
+ * very rare cases during usb suspend and resume process.
+ */
+ if (low_speed_connection & vbus_is_on) {
+ /*
+ * If value to be set as pwd value is not 0xffffffff,
+ * several 32Khz cycles are needed.
+ */
+ mxs_phy_clock_switch_delay();
+ writel(0xffbfffff, x->io_priv + HW_USBPHY_PWD);
+ } else {
+ writel(0xffffffff, x->io_priv + HW_USBPHY_PWD);
+ }
writel(BM_USBPHY_CTRL_CLKGATE,
x->io_priv + HW_USBPHY_CTRL_SET);
clk_disable_unprepare(mxs_phy->clk);
@@ -359,7 +433,9 @@ static int mxs_phy_on_disconnect(struct usb_phy *phy,
dev_dbg(phy->dev, "%s device has disconnected\n",
(speed == USB_SPEED_HIGH) ? "HS" : "FS/LS");
- if (speed == USB_SPEED_HIGH)
+ /* Sometimes, the speed is not high speed when the error occurs */
+ if (readl(phy->io_priv + HW_USBPHY_CTRL) &
+ BM_USBPHY_CTRL_ENHOSTDISCONDETECT)
writel(BM_USBPHY_CTRL_ENHOSTDISCONDETECT,
phy->io_priv + HW_USBPHY_CTRL_CLR);
diff --git a/drivers/usb/phy/phy.c b/drivers/usb/phy/phy.c
index ccfdfb24b240..2f9735b35338 100644
--- a/drivers/usb/phy/phy.c
+++ b/drivers/usb/phy/phy.c
@@ -34,7 +34,7 @@ static struct usb_phy *__usb_find_phy(struct list_head *list,
return phy;
}
- return ERR_PTR(-EPROBE_DEFER);
+ return ERR_PTR(-ENODEV);
}
static struct usb_phy *__usb_find_phy_dev(struct device *dev,
diff --git a/drivers/usb/renesas_usbhs/common.c b/drivers/usb/renesas_usbhs/common.c
index 371478704899..4cf77d3c3bd2 100644
--- a/drivers/usb/renesas_usbhs/common.c
+++ b/drivers/usb/renesas_usbhs/common.c
@@ -363,6 +363,7 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
struct usbhs_mod *mod = usbhs_mod_get_current(priv);
int id;
int enable;
+ int cable;
int ret;
/*
@@ -376,6 +377,16 @@ static void usbhsc_hotplug(struct usbhs_priv *priv)
id = usbhs_platform_call(priv, get_id, pdev);
if (enable && !mod) {
+ if (priv->edev) {
+ cable = extcon_get_cable_state(priv->edev, "USB-HOST");
+ if ((cable > 0 && id != USBHS_HOST) ||
+ (!cable && id != USBHS_GADGET)) {
+ dev_info(&pdev->dev,
+ "USB cable plugged in doesn't match the selected role!\n");
+ return;
+ }
+ }
+
ret = usbhs_mod_change(priv, id);
if (ret < 0)
return;
@@ -514,6 +525,12 @@ static int usbhs_probe(struct platform_device *pdev)
if (IS_ERR(priv->base))
return PTR_ERR(priv->base);
+ if (of_property_read_bool(pdev->dev.of_node, "extcon")) {
+ priv->edev = extcon_get_edev_by_phandle(&pdev->dev, 0);
+ if (IS_ERR(priv->edev))
+ return PTR_ERR(priv->edev);
+ }
+
/*
* care platform info
*/
@@ -615,7 +632,7 @@ static int usbhs_probe(struct platform_device *pdev)
*/
ret = usbhs_platform_call(priv, hardware_init, pdev);
if (ret < 0) {
- dev_err(&pdev->dev, "platform prove failed.\n");
+ dev_err(&pdev->dev, "platform init failed.\n");
goto probe_end_mod_exit;
}
@@ -632,16 +649,12 @@ static int usbhs_probe(struct platform_device *pdev)
/*
* manual call notify_hotplug for cold plug
*/
- ret = usbhsc_drvcllbck_notify_hotplug(pdev);
- if (ret < 0)
- goto probe_end_call_remove;
+ usbhsc_drvcllbck_notify_hotplug(pdev);
dev_info(&pdev->dev, "probed\n");
return ret;
-probe_end_call_remove:
- usbhs_platform_call(priv, hardware_exit, pdev);
probe_end_mod_exit:
usbhs_mod_remove(priv);
probe_end_fifo_exit:
diff --git a/drivers/usb/renesas_usbhs/common.h b/drivers/usb/renesas_usbhs/common.h
index 0427cdd1a483..fc96e924edc4 100644
--- a/drivers/usb/renesas_usbhs/common.h
+++ b/drivers/usb/renesas_usbhs/common.h
@@ -17,6 +17,7 @@
#ifndef RENESAS_USB_DRIVER_H
#define RENESAS_USB_DRIVER_H
+#include <linux/extcon.h>
#include <linux/platform_device.h>
#include <linux/usb/renesas_usbhs.h>
@@ -254,6 +255,8 @@ struct usbhs_priv {
struct delayed_work notify_hotplug_work;
struct platform_device *pdev;
+ struct extcon_dev *edev;
+
spinlock_t lock;
u32 flags;
diff --git a/drivers/usb/renesas_usbhs/fifo.c b/drivers/usb/renesas_usbhs/fifo.c
index f46271ce1b15..d891bff39d66 100644
--- a/drivers/usb/renesas_usbhs/fifo.c
+++ b/drivers/usb/renesas_usbhs/fifo.c
@@ -1054,10 +1054,8 @@ static void usbhsf_dma_quit(struct usbhs_priv *priv, struct usbhs_fifo *fifo)
fifo->rx_chan = NULL;
}
-static void usbhsf_dma_init(struct usbhs_priv *priv,
- struct usbhs_fifo *fifo)
+static void usbhsf_dma_init_pdev(struct usbhs_fifo *fifo)
{
- struct device *dev = usbhs_priv_to_dev(priv);
dma_cap_mask_t mask;
dma_cap_zero(mask);
@@ -1069,6 +1067,27 @@ static void usbhsf_dma_init(struct usbhs_priv *priv,
dma_cap_set(DMA_SLAVE, mask);
fifo->rx_chan = dma_request_channel(mask, usbhsf_dma_filter,
&fifo->rx_slave);
+}
+
+static void usbhsf_dma_init_dt(struct device *dev, struct usbhs_fifo *fifo)
+{
+ fifo->tx_chan = dma_request_slave_channel_reason(dev, "tx");
+ if (IS_ERR(fifo->tx_chan))
+ fifo->tx_chan = NULL;
+ fifo->rx_chan = dma_request_slave_channel_reason(dev, "rx");
+ if (IS_ERR(fifo->rx_chan))
+ fifo->rx_chan = NULL;
+}
+
+static void usbhsf_dma_init(struct usbhs_priv *priv,
+ struct usbhs_fifo *fifo)
+{
+ struct device *dev = usbhs_priv_to_dev(priv);
+
+ if (dev->of_node)
+ usbhsf_dma_init_dt(dev, fifo);
+ else
+ usbhsf_dma_init_pdev(fifo);
if (fifo->tx_chan || fifo->rx_chan)
dev_dbg(dev, "enable DMAEngine (%s%s%s)\n",
diff --git a/drivers/usb/renesas_usbhs/mod_gadget.c b/drivers/usb/renesas_usbhs/mod_gadget.c
index 8697e6efcabf..e0384af77e56 100644
--- a/drivers/usb/renesas_usbhs/mod_gadget.c
+++ b/drivers/usb/renesas_usbhs/mod_gadget.c
@@ -926,6 +926,8 @@ static int usbhsg_set_selfpowered(struct usb_gadget *gadget, int is_self)
else
usbhsg_status_clr(gpriv, USBHSG_STATUS_SELF_POWERED);
+ gadget->is_selfpowered = (is_self != 0);
+
return 0;
}
diff --git a/drivers/usb/renesas_usbhs/mod_host.c b/drivers/usb/renesas_usbhs/mod_host.c
index f0d323125871..96eead619282 100644
--- a/drivers/usb/renesas_usbhs/mod_host.c
+++ b/drivers/usb/renesas_usbhs/mod_host.c
@@ -1234,7 +1234,8 @@ static int __usbhsh_hub_get_status(struct usbhsh_hpriv *hpriv,
desc->bNbrPorts = roothub_id;
desc->bDescLength = 9;
desc->bPwrOn2PwrGood = 0;
- desc->wHubCharacteristics = cpu_to_le16(0x0011);
+ desc->wHubCharacteristics =
+ cpu_to_le16(HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_NO_OCPM);
desc->u.hs.DeviceRemovable[0] = (roothub_id << 1);
desc->u.hs.DeviceRemovable[1] = ~0;
dev_dbg(dev, "%s :: GetHubDescriptor\n", __func__);
diff --git a/drivers/usb/serial/cp210x.c b/drivers/usb/serial/cp210x.c
index f4c56fc1a9f6..f40c856ff758 100644
--- a/drivers/usb/serial/cp210x.c
+++ b/drivers/usb/serial/cp210x.c
@@ -56,6 +56,7 @@ static const struct usb_device_id id_table[] = {
{ USB_DEVICE(0x0846, 0x1100) }, /* NetGear Managed Switch M4100 series, M5300 series, M7100 series */
{ USB_DEVICE(0x08e6, 0x5501) }, /* Gemalto Prox-PU/CU contactless smartcard reader */
{ USB_DEVICE(0x08FD, 0x000A) }, /* Digianswer A/S , ZigBee/802.15.4 MAC Device */
+ { USB_DEVICE(0x0908, 0x01FF) }, /* Siemens RUGGEDCOM USB Serial Console */
{ USB_DEVICE(0x0BED, 0x1100) }, /* MEI (TM) Cashflow-SC Bill/Voucher Acceptor */
{ USB_DEVICE(0x0BED, 0x1101) }, /* MEI series 2000 Combo Acceptor */
{ USB_DEVICE(0x0FCF, 0x1003) }, /* Dynastream ANT development board */
diff --git a/drivers/usb/serial/mos7840.c b/drivers/usb/serial/mos7840.c
index 220b4be89641..e4473a9109cf 100644
--- a/drivers/usb/serial/mos7840.c
+++ b/drivers/usb/serial/mos7840.c
@@ -1309,35 +1309,6 @@ static int mos7840_write(struct tty_struct *tty, struct usb_serial_port *port,
const unsigned char *current_position = data;
unsigned char *data1;
-#ifdef NOTMOS7840
- Data = 0x00;
- status = mos7840_get_uart_reg(port, LINE_CONTROL_REGISTER, &Data);
- mos7840_port->shadowLCR = Data;
- dev_dbg(&port->dev, "%s: LINE_CONTROL_REGISTER is %x\n", __func__, Data);
- dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
-
- /* Data = 0x03; */
- /* status = mos7840_set_uart_reg(port,LINE_CONTROL_REGISTER,Data); */
- /* mos7840_port->shadowLCR=Data;//Need to add later */
-
- Data |= SERIAL_LCR_DLAB; /* data latch enable in LCR 0x80 */
- status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-
- /* Data = 0x0c; */
- /* status = mos7840_set_uart_reg(port,DIVISOR_LATCH_LSB,Data); */
- Data = 0x00;
- status = mos7840_get_uart_reg(port, DIVISOR_LATCH_LSB, &Data);
- dev_dbg(&port->dev, "%s: DLL value is %x\n", __func__, Data);
-
- Data = 0x0;
- status = mos7840_get_uart_reg(port, DIVISOR_LATCH_MSB, &Data);
- dev_dbg(&port->dev, "%s: DLM value is %x\n", __func__, Data);
-
- Data = Data & ~SERIAL_LCR_DLAB;
- dev_dbg(&port->dev, "%s: mos7840_port->shadowLCR is %x\n", __func__, mos7840_port->shadowLCR);
- status = mos7840_set_uart_reg(port, LINE_CONTROL_REGISTER, Data);
-#endif
-
if (mos7840_port_paranoia_check(port, __func__))
return -1;
@@ -1614,37 +1585,6 @@ static int mos7840_calc_baud_rate_divisor(struct usb_serial_port *port,
*clk_sel_val = 0x70;
}
return 0;
-
-#ifdef NOTMCS7840
-
- for (i = 0; i < ARRAY_SIZE(mos7840_divisor_table); i++) {
- if (mos7840_divisor_table[i].BaudRate == baudrate) {
- *divisor = mos7840_divisor_table[i].Divisor;
- return 0;
- }
- }
-
- /* After trying for all the standard baud rates *
- * Try calculating the divisor for this baud rate */
-
- if (baudrate > 75 && baudrate < 230400) {
- /* get the divisor */
- custom = (__u16) (230400L / baudrate);
-
- /* Check for round off */
- round1 = (__u16) (2304000L / baudrate);
- round = (__u16) (round1 - (custom * 10));
- if (round > 4)
- custom++;
- *divisor = custom;
-
- dev_dbg(&port->dev, " Baud %d = %d\n", baudrate, custom);
- return 0;
- }
-
- dev_dbg(&port->dev, "%s", " Baud calculation Failed...\n");
- return -1;
-#endif
}
/*****************************************************************************
diff --git a/drivers/usb/serial/option.c b/drivers/usb/serial/option.c
index efdcee15b520..f0c0c53359ad 100644
--- a/drivers/usb/serial/option.c
+++ b/drivers/usb/serial/option.c
@@ -507,18 +507,10 @@ static void option_instat_callback(struct urb *urb);
#define VIATELECOM_VENDOR_ID 0x15eb
#define VIATELECOM_PRODUCT_CDS7 0x0001
-/* some devices interfaces need special handling due to a number of reasons */
-enum option_blacklist_reason {
- OPTION_BLACKLIST_NONE = 0,
- OPTION_BLACKLIST_SENDSETUP = 1,
- OPTION_BLACKLIST_RESERVED_IF = 2
-};
-
-#define MAX_BL_NUM 11
struct option_blacklist_info {
- /* bitfield of interface numbers for OPTION_BLACKLIST_SENDSETUP */
+ /* bitmask of interface numbers blacklisted for send_setup */
const unsigned long sendsetup;
- /* bitfield of interface numbers for OPTION_BLACKLIST_RESERVED_IF */
+ /* bitmask of interface numbers that are reserved */
const unsigned long reserved;
};
@@ -1822,36 +1814,13 @@ struct option_private {
module_usb_serial_driver(serial_drivers, option_ids);
-static bool is_blacklisted(const u8 ifnum, enum option_blacklist_reason reason,
- const struct option_blacklist_info *blacklist)
-{
- unsigned long num;
- const unsigned long *intf_list;
-
- if (blacklist) {
- if (reason == OPTION_BLACKLIST_SENDSETUP)
- intf_list = &blacklist->sendsetup;
- else if (reason == OPTION_BLACKLIST_RESERVED_IF)
- intf_list = &blacklist->reserved;
- else {
- BUG_ON(reason);
- return false;
- }
-
- for_each_set_bit(num, intf_list, MAX_BL_NUM + 1) {
- if (num == ifnum)
- return true;
- }
- }
- return false;
-}
-
static int option_probe(struct usb_serial *serial,
const struct usb_device_id *id)
{
struct usb_interface_descriptor *iface_desc =
&serial->interface->cur_altsetting->desc;
struct usb_device_descriptor *dev_desc = &serial->dev->descriptor;
+ const struct option_blacklist_info *blacklist;
/* Never bind to the CD-Rom emulation interface */
if (iface_desc->bInterfaceClass == 0x08)
@@ -1862,10 +1831,9 @@ static int option_probe(struct usb_serial *serial,
* the same class/subclass/protocol as the serial interfaces. Look at
* the Windows driver .INF files for reserved interface numbers.
*/
- if (is_blacklisted(
- iface_desc->bInterfaceNumber,
- OPTION_BLACKLIST_RESERVED_IF,
- (const struct option_blacklist_info *) id->driver_info))
+ blacklist = (void *)id->driver_info;
+ if (blacklist && test_bit(iface_desc->bInterfaceNumber,
+ &blacklist->reserved))
return -ENODEV;
/*
* Don't bind network interface on Samsung GT-B3730, it is handled by
@@ -1876,8 +1844,8 @@ static int option_probe(struct usb_serial *serial,
iface_desc->bInterfaceClass != USB_CLASS_CDC_DATA)
return -ENODEV;
- /* Store device id so we can use it during attach. */
- usb_set_serial_data(serial, (void *)id);
+ /* Store the blacklist info so we can use it during attach. */
+ usb_set_serial_data(serial, (void *)blacklist);
return 0;
}
@@ -1885,7 +1853,7 @@ static int option_probe(struct usb_serial *serial,
static int option_attach(struct usb_serial *serial)
{
struct usb_interface_descriptor *iface_desc;
- const struct usb_device_id *id;
+ const struct option_blacklist_info *blacklist;
struct usb_wwan_intf_private *data;
struct option_private *priv;
@@ -1899,16 +1867,16 @@ static int option_attach(struct usb_serial *serial)
return -ENOMEM;
}
- /* Retrieve device id stored at probe. */
- id = usb_get_serial_data(serial);
+ /* Retrieve blacklist info stored at probe. */
+ blacklist = usb_get_serial_data(serial);
+
iface_desc = &serial->interface->cur_altsetting->desc;
priv->bInterfaceNumber = iface_desc->bInterfaceNumber;
data->private = priv;
- if (!is_blacklisted(iface_desc->bInterfaceNumber,
- OPTION_BLACKLIST_SENDSETUP,
- (struct option_blacklist_info *)id->driver_info)) {
+ if (!blacklist || !test_bit(iface_desc->bInterfaceNumber,
+ &blacklist->sendsetup)) {
data->send_setup = option_send_setup;
}
spin_lock_init(&data->susp_lock);
diff --git a/drivers/usb/storage/unusual_devs.h b/drivers/usb/storage/unusual_devs.h
index 11c7a9676441..d684b4b8108f 100644
--- a/drivers/usb/storage/unusual_devs.h
+++ b/drivers/usb/storage/unusual_devs.h
@@ -507,7 +507,7 @@ UNUSUAL_DEV( 0x04e6, 0x000c, 0x0100, 0x0100,
UNUSUAL_DEV( 0x04e6, 0x000f, 0x0000, 0x9999,
"SCM Microsystems",
"eUSB SCSI Adapter (Bus Powered)",
- USB_SC_DEVICE, USB_PR_DEVICE, usb_stor_euscsi_init,
+ USB_SC_SCSI, USB_PR_BULK, usb_stor_euscsi_init,
US_FL_SCM_MULT_TARG ),
UNUSUAL_DEV( 0x04e6, 0x0101, 0x0200, 0x0200,
@@ -1995,6 +1995,13 @@ UNUSUAL_DEV( 0x152d, 0x2329, 0x0100, 0x0100,
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_RESIDUE | US_FL_SANE_SENSE ),
+/* Reported by Dmitry Nezhevenko <dion@dion.org.ua> */
+UNUSUAL_DEV( 0x152d, 0x2566, 0x0114, 0x0114,
+ "JMicron",
+ "USB to ATA/ATAPI Bridge",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_BROKEN_FUA ),
+
/* Entrega Technologies U1-SC25 (later Xircom PortGear PGSCSI)
* and Mac USB Dock USB-SCSI */
UNUSUAL_DEV( 0x1645, 0x0007, 0x0100, 0x0133,
diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h
index 6df4357d9ee3..dbc00e56c7f5 100644
--- a/drivers/usb/storage/unusual_uas.h
+++ b/drivers/usb/storage/unusual_uas.h
@@ -140,3 +140,10 @@ UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999,
"External HDD",
USB_SC_DEVICE, USB_PR_DEVICE, NULL,
US_FL_IGNORE_UAS),
+
+/* Reported-by: Richard Henderson <rth@redhat.com> */
+UNUSUAL_DEV(0x4971, 0x8017, 0x0000, 0x9999,
+ "SimpleTech",
+ "External HDD",
+ USB_SC_DEVICE, USB_PR_DEVICE, NULL,
+ US_FL_NO_REPORT_OPCODES),
diff --git a/drivers/usb/usbip/vhci_hcd.c b/drivers/usb/usbip/vhci_hcd.c
index 1ae9d40f96bf..11f6f61c2381 100644
--- a/drivers/usb/usbip/vhci_hcd.c
+++ b/drivers/usb/usbip/vhci_hcd.c
@@ -218,7 +218,8 @@ static inline void hub_descriptor(struct usb_hub_descriptor *desc)
memset(desc, 0, sizeof(*desc));
desc->bDescriptorType = 0x29;
desc->bDescLength = 9;
- desc->wHubCharacteristics = (__constant_cpu_to_le16(0x0001));
+ desc->wHubCharacteristics = __constant_cpu_to_le16(
+ HUB_CHAR_INDV_PORT_LPSM | HUB_CHAR_COMMON_OCPM);
desc->bNbrPorts = VHCI_NPORTS;
desc->u.hs.DeviceRemovable[0] = 0xff;
desc->u.hs.DeviceRemovable[1] = 0xff;
diff --git a/drivers/usb/wusbcore/reservation.c b/drivers/usb/wusbcore/reservation.c
index d5efd0f07d2b..7b1b2e2fb673 100644
--- a/drivers/usb/wusbcore/reservation.c
+++ b/drivers/usb/wusbcore/reservation.c
@@ -49,14 +49,13 @@ static void wusbhc_rsv_complete_cb(struct uwb_rsv *rsv)
struct wusbhc *wusbhc = rsv->pal_priv;
struct device *dev = wusbhc->dev;
struct uwb_mas_bm mas;
- char buf[72];
dev_dbg(dev, "%s: state = %d\n", __func__, rsv->state);
switch (rsv->state) {
case UWB_RSV_STATE_O_ESTABLISHED:
uwb_rsv_get_usable_mas(rsv, &mas);
- bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS);
- dev_dbg(dev, "established reservation: %s\n", buf);
+ dev_dbg(dev, "established reservation: %*pb\n",
+ UWB_NUM_MAS, mas.bm);
wusbhc_bwa_set(wusbhc, rsv->stream, &mas);
break;
case UWB_RSV_STATE_NONE:
diff --git a/drivers/usb/wusbcore/rh.c b/drivers/usb/wusbcore/rh.c
index fe8bc777ab88..aa5af817f31c 100644
--- a/drivers/usb/wusbcore/rh.c
+++ b/drivers/usb/wusbcore/rh.c
@@ -185,9 +185,9 @@ static int wusbhc_rh_get_hub_descr(struct wusbhc *wusbhc, u16 wValue,
descr->bDescriptorType = 0x29; /* HUB type */
descr->bNbrPorts = wusbhc->ports_max;
descr->wHubCharacteristics = cpu_to_le16(
- 0x00 /* All ports power at once */
+ HUB_CHAR_COMMON_LPSM /* All ports power at once */
| 0x00 /* not part of compound device */
- | 0x10 /* No overcurrent protection */
+ | HUB_CHAR_NO_OCPM /* No overcurrent protection */
| 0x00 /* 8 FS think time FIXME ?? */
| 0x00); /* No port indicators */
descr->bPwrOn2PwrGood = 0;
diff --git a/drivers/usb/wusbcore/wa-rpipe.c b/drivers/usb/wusbcore/wa-rpipe.c
index a80c5d284b59..c7ecdbe19a32 100644
--- a/drivers/usb/wusbcore/wa-rpipe.c
+++ b/drivers/usb/wusbcore/wa-rpipe.c
@@ -496,10 +496,9 @@ void wa_rpipes_destroy(struct wahc *wa)
struct device *dev = &wa->usb_iface->dev;
if (!bitmap_empty(wa->rpipe_bm, wa->rpipes)) {
- char buf[256];
WARN_ON(1);
- bitmap_scnprintf(buf, sizeof(buf), wa->rpipe_bm, wa->rpipes);
- dev_err(dev, "BUG: pipes not released on exit: %s\n", buf);
+ dev_err(dev, "BUG: pipes not released on exit: %*pb\n",
+ wa->rpipes, wa->rpipe_bm);
}
kfree(wa->rpipe_bm);
}
diff --git a/drivers/usb/wusbcore/wusbhc.c b/drivers/usb/wusbcore/wusbhc.c
index 3e1ba51d1a43..94f401ab859f 100644
--- a/drivers/usb/wusbcore/wusbhc.c
+++ b/drivers/usb/wusbcore/wusbhc.c
@@ -496,11 +496,8 @@ static void __exit wusbcore_exit(void)
{
clear_bit(0, wusb_cluster_id_table);
if (!bitmap_empty(wusb_cluster_id_table, CLUSTER_IDS)) {
- char buf[256];
- bitmap_scnprintf(buf, sizeof(buf), wusb_cluster_id_table,
- CLUSTER_IDS);
- printk(KERN_ERR "BUG: WUSB Cluster IDs not released "
- "on exit: %s\n", buf);
+ printk(KERN_ERR "BUG: WUSB Cluster IDs not released on exit: %*pb\n",
+ CLUSTER_IDS, wusb_cluster_id_table);
WARN_ON(1);
}
usb_unregister_notify(&wusb_usb_notifier);
diff --git a/drivers/uwb/drp.c b/drivers/uwb/drp.c
index 05b7bd762254..8fc1b787dced 100644
--- a/drivers/uwb/drp.c
+++ b/drivers/uwb/drp.c
@@ -619,11 +619,9 @@ static void uwb_drp_handle_alien_drp(struct uwb_rc *rc, struct uwb_ie_drp *drp_i
struct device *dev = &rc->uwb_dev.dev;
struct uwb_mas_bm mas;
struct uwb_cnflt_alien *cnflt;
- char buf[72];
unsigned long delay_us = UWB_MAS_LENGTH_US * UWB_MAS_PER_ZONE;
uwb_drp_ie_to_bm(&mas, drp_ie);
- bitmap_scnprintf(buf, sizeof(buf), mas.bm, UWB_NUM_MAS);
list_for_each_entry(cnflt, &rc->cnflt_alien_list, rc_node) {
if (bitmap_equal(cnflt->mas.bm, mas.bm, UWB_NUM_MAS)) {
diff --git a/drivers/uwb/lc-dev.c b/drivers/uwb/lc-dev.c
index 8c7cfab5cee3..72033589db19 100644
--- a/drivers/uwb/lc-dev.c
+++ b/drivers/uwb/lc-dev.c
@@ -43,13 +43,6 @@ static inline void uwb_mac_addr_init(struct uwb_mac_addr *addr)
memset(&addr->data, 0xff, sizeof(addr->data));
}
-/* @returns !0 if a device @addr is a broadcast address */
-static inline int uwb_dev_addr_bcast(const struct uwb_dev_addr *addr)
-{
- static const struct uwb_dev_addr bcast = { .data = { 0xff, 0xff } };
- return !uwb_dev_addr_cmp(addr, &bcast);
-}
-
/*
* Add callback @new to be called when an event occurs in @rc.
*/
diff --git a/drivers/uwb/uwb-debug.c b/drivers/uwb/uwb-debug.c
index 6ec45beb7af5..0b1e5a9449b5 100644
--- a/drivers/uwb/uwb-debug.c
+++ b/drivers/uwb/uwb-debug.c
@@ -217,7 +217,6 @@ static int reservations_print(struct seq_file *s, void *p)
struct uwb_dev_addr devaddr;
char owner[UWB_ADDR_STRSIZE], target[UWB_ADDR_STRSIZE];
bool is_owner;
- char buf[72];
uwb_dev_addr_print(owner, sizeof(owner), &rsv->owner->dev_addr);
if (rsv->target.type == UWB_RSV_TARGET_DEV) {
@@ -234,8 +233,7 @@ static int reservations_print(struct seq_file *s, void *p)
owner, target, uwb_rsv_state_str(rsv->state));
seq_printf(s, " stream: %d type: %s\n",
rsv->stream, uwb_rsv_type_str(rsv->type));
- bitmap_scnprintf(buf, sizeof(buf), rsv->mas.bm, UWB_NUM_MAS);
- seq_printf(s, " %s\n", buf);
+ seq_printf(s, " %*pb\n", UWB_NUM_MAS, rsv->mas.bm);
}
mutex_unlock(&rc->rsvs_mutex);
@@ -259,14 +257,10 @@ static const struct file_operations reservations_fops = {
static int drp_avail_print(struct seq_file *s, void *p)
{
struct uwb_rc *rc = s->private;
- char buf[72];
-
- bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.global, UWB_NUM_MAS);
- seq_printf(s, "global: %s\n", buf);
- bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.local, UWB_NUM_MAS);
- seq_printf(s, "local: %s\n", buf);
- bitmap_scnprintf(buf, sizeof(buf), rc->drp_avail.pending, UWB_NUM_MAS);
- seq_printf(s, "pending: %s\n", buf);
+
+ seq_printf(s, "global: %*pb\n", UWB_NUM_MAS, rc->drp_avail.global);
+ seq_printf(s, "local: %*pb\n", UWB_NUM_MAS, rc->drp_avail.local);
+ seq_printf(s, "pending: %*pb\n", UWB_NUM_MAS, rc->drp_avail.pending);
return 0;
}
diff --git a/drivers/vfio/pci/vfio_pci.c b/drivers/vfio/pci/vfio_pci.c
index 7cc0122a18ce..f8a186381ae8 100644
--- a/drivers/vfio/pci/vfio_pci.c
+++ b/drivers/vfio/pci/vfio_pci.c
@@ -239,9 +239,12 @@ static int vfio_pci_get_irq_count(struct vfio_pci_device *vdev, int irq_type)
return (flags & PCI_MSIX_FLAGS_QSIZE) + 1;
}
- } else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX)
+ } else if (irq_type == VFIO_PCI_ERR_IRQ_INDEX) {
if (pci_is_pcie(vdev->pdev))
return 1;
+ } else if (irq_type == VFIO_PCI_REQ_IRQ_INDEX) {
+ return 1;
+ }
return 0;
}
@@ -464,6 +467,7 @@ static long vfio_pci_ioctl(void *device_data,
switch (info.index) {
case VFIO_PCI_INTX_IRQ_INDEX ... VFIO_PCI_MSIX_IRQ_INDEX:
+ case VFIO_PCI_REQ_IRQ_INDEX:
break;
case VFIO_PCI_ERR_IRQ_INDEX:
if (pci_is_pcie(vdev->pdev))
@@ -828,6 +832,20 @@ static int vfio_pci_mmap(void *device_data, struct vm_area_struct *vma)
req_len, vma->vm_page_prot);
}
+static void vfio_pci_request(void *device_data, unsigned int count)
+{
+ struct vfio_pci_device *vdev = device_data;
+
+ mutex_lock(&vdev->igate);
+
+ if (vdev->req_trigger) {
+ dev_dbg(&vdev->pdev->dev, "Requesting device from user\n");
+ eventfd_signal(vdev->req_trigger, 1);
+ }
+
+ mutex_unlock(&vdev->igate);
+}
+
static const struct vfio_device_ops vfio_pci_ops = {
.name = "vfio-pci",
.open = vfio_pci_open,
@@ -836,6 +854,7 @@ static const struct vfio_device_ops vfio_pci_ops = {
.read = vfio_pci_read,
.write = vfio_pci_write,
.mmap = vfio_pci_mmap,
+ .request = vfio_pci_request,
};
static int vfio_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index e8d695b3f54e..f88bfdf5b6a0 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -763,46 +763,70 @@ static int vfio_pci_set_msi_trigger(struct vfio_pci_device *vdev,
return 0;
}
-static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
- unsigned index, unsigned start,
- unsigned count, uint32_t flags, void *data)
+static int vfio_pci_set_ctx_trigger_single(struct eventfd_ctx **ctx,
+ uint32_t flags, void *data)
{
int32_t fd = *(int32_t *)data;
- if ((index != VFIO_PCI_ERR_IRQ_INDEX) ||
- !(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
+ if (!(flags & VFIO_IRQ_SET_DATA_TYPE_MASK))
return -EINVAL;
/* DATA_NONE/DATA_BOOL enables loopback testing */
if (flags & VFIO_IRQ_SET_DATA_NONE) {
- if (vdev->err_trigger)
- eventfd_signal(vdev->err_trigger, 1);
+ if (*ctx)
+ eventfd_signal(*ctx, 1);
return 0;
} else if (flags & VFIO_IRQ_SET_DATA_BOOL) {
uint8_t trigger = *(uint8_t *)data;
- if (trigger && vdev->err_trigger)
- eventfd_signal(vdev->err_trigger, 1);
+ if (trigger && *ctx)
+ eventfd_signal(*ctx, 1);
return 0;
}
/* Handle SET_DATA_EVENTFD */
if (fd == -1) {
- if (vdev->err_trigger)
- eventfd_ctx_put(vdev->err_trigger);
- vdev->err_trigger = NULL;
+ if (*ctx)
+ eventfd_ctx_put(*ctx);
+ *ctx = NULL;
return 0;
} else if (fd >= 0) {
struct eventfd_ctx *efdctx;
efdctx = eventfd_ctx_fdget(fd);
if (IS_ERR(efdctx))
return PTR_ERR(efdctx);
- if (vdev->err_trigger)
- eventfd_ctx_put(vdev->err_trigger);
- vdev->err_trigger = efdctx;
+ if (*ctx)
+ eventfd_ctx_put(*ctx);
+ *ctx = efdctx;
return 0;
} else
return -EINVAL;
}
+
+static int vfio_pci_set_err_trigger(struct vfio_pci_device *vdev,
+ unsigned index, unsigned start,
+ unsigned count, uint32_t flags, void *data)
+{
+ if (index != VFIO_PCI_ERR_IRQ_INDEX)
+ return -EINVAL;
+
+ /*
+ * We should sanitize start & count, but that wasn't caught
+ * originally, so this IRQ index must forever ignore them :-(
+ */
+
+ return vfio_pci_set_ctx_trigger_single(&vdev->err_trigger, flags, data);
+}
+
+static int vfio_pci_set_req_trigger(struct vfio_pci_device *vdev,
+ unsigned index, unsigned start,
+ unsigned count, uint32_t flags, void *data)
+{
+ if (index != VFIO_PCI_REQ_IRQ_INDEX || start != 0 || count != 1)
+ return -EINVAL;
+
+ return vfio_pci_set_ctx_trigger_single(&vdev->req_trigger, flags, data);
+}
+
int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
unsigned index, unsigned start, unsigned count,
void *data)
@@ -844,6 +868,12 @@ int vfio_pci_set_irqs_ioctl(struct vfio_pci_device *vdev, uint32_t flags,
func = vfio_pci_set_err_trigger;
break;
}
+ case VFIO_PCI_REQ_IRQ_INDEX:
+ switch (flags & VFIO_IRQ_SET_ACTION_TYPE_MASK) {
+ case VFIO_IRQ_SET_ACTION_TRIGGER:
+ func = vfio_pci_set_req_trigger;
+ break;
+ }
}
if (!func)
diff --git a/drivers/vfio/pci/vfio_pci_private.h b/drivers/vfio/pci/vfio_pci_private.h
index 671c17a6e6d0..c9f9b323f152 100644
--- a/drivers/vfio/pci/vfio_pci_private.h
+++ b/drivers/vfio/pci/vfio_pci_private.h
@@ -58,6 +58,7 @@ struct vfio_pci_device {
struct pci_saved_state *pci_saved_state;
int refcnt;
struct eventfd_ctx *err_trigger;
+ struct eventfd_ctx *req_trigger;
};
#define is_intx(vdev) (vdev->irq_type == VFIO_PCI_INTX_IRQ_INDEX)
diff --git a/drivers/vfio/vfio.c b/drivers/vfio/vfio.c
index f018d8d0f975..4cde85501444 100644
--- a/drivers/vfio/vfio.c
+++ b/drivers/vfio/vfio.c
@@ -63,6 +63,11 @@ struct vfio_container {
void *iommu_data;
};
+struct vfio_unbound_dev {
+ struct device *dev;
+ struct list_head unbound_next;
+};
+
struct vfio_group {
struct kref kref;
int minor;
@@ -75,6 +80,8 @@ struct vfio_group {
struct notifier_block nb;
struct list_head vfio_next;
struct list_head container_next;
+ struct list_head unbound_list;
+ struct mutex unbound_lock;
atomic_t opened;
};
@@ -204,6 +211,8 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
kref_init(&group->kref);
INIT_LIST_HEAD(&group->device_list);
mutex_init(&group->device_lock);
+ INIT_LIST_HEAD(&group->unbound_list);
+ mutex_init(&group->unbound_lock);
atomic_set(&group->container_users, 0);
atomic_set(&group->opened, 0);
group->iommu_group = iommu_group;
@@ -264,13 +273,22 @@ static struct vfio_group *vfio_create_group(struct iommu_group *iommu_group)
static void vfio_group_release(struct kref *kref)
{
struct vfio_group *group = container_of(kref, struct vfio_group, kref);
+ struct vfio_unbound_dev *unbound, *tmp;
+ struct iommu_group *iommu_group = group->iommu_group;
WARN_ON(!list_empty(&group->device_list));
+ list_for_each_entry_safe(unbound, tmp,
+ &group->unbound_list, unbound_next) {
+ list_del(&unbound->unbound_next);
+ kfree(unbound);
+ }
+
device_destroy(vfio.class, MKDEV(MAJOR(vfio.group_devt), group->minor));
list_del(&group->vfio_next);
vfio_free_group_minor(group->minor);
vfio_group_unlock_and_free(group);
+ iommu_group_put(iommu_group);
}
static void vfio_group_put(struct vfio_group *group)
@@ -440,17 +458,36 @@ static bool vfio_whitelisted_driver(struct device_driver *drv)
}
/*
- * A vfio group is viable for use by userspace if all devices are either
- * driver-less or bound to a vfio or whitelisted driver. We test the
- * latter by the existence of a struct vfio_device matching the dev.
+ * A vfio group is viable for use by userspace if all devices are in
+ * one of the following states:
+ * - driver-less
+ * - bound to a vfio driver
+ * - bound to a whitelisted driver
+ *
+ * We use two methods to determine whether a device is bound to a vfio
+ * driver. The first is to test whether the device exists in the vfio
+ * group. The second is to test if the device exists on the group
+ * unbound_list, indicating it's in the middle of transitioning from
+ * a vfio driver to driver-less.
*/
static int vfio_dev_viable(struct device *dev, void *data)
{
struct vfio_group *group = data;
struct vfio_device *device;
struct device_driver *drv = ACCESS_ONCE(dev->driver);
+ struct vfio_unbound_dev *unbound;
+ int ret = -EINVAL;
- if (!drv || vfio_whitelisted_driver(drv))
+ mutex_lock(&group->unbound_lock);
+ list_for_each_entry(unbound, &group->unbound_list, unbound_next) {
+ if (dev == unbound->dev) {
+ ret = 0;
+ break;
+ }
+ }
+ mutex_unlock(&group->unbound_lock);
+
+ if (!ret || !drv || vfio_whitelisted_driver(drv))
return 0;
device = vfio_group_get_device(group, dev);
@@ -459,7 +496,7 @@ static int vfio_dev_viable(struct device *dev, void *data)
return 0;
}
- return -EINVAL;
+ return ret;
}
/**
@@ -501,6 +538,7 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
{
struct vfio_group *group = container_of(nb, struct vfio_group, nb);
struct device *dev = data;
+ struct vfio_unbound_dev *unbound;
/*
* Need to go through a group_lock lookup to get a reference or we
@@ -550,6 +588,17 @@ static int vfio_iommu_group_notifier(struct notifier_block *nb,
* stop the system to maintain isolation. At a minimum, we'd
* want a toggle to disable driver auto probe for this device.
*/
+
+ mutex_lock(&group->unbound_lock);
+ list_for_each_entry(unbound,
+ &group->unbound_list, unbound_next) {
+ if (dev == unbound->dev) {
+ list_del(&unbound->unbound_next);
+ kfree(unbound);
+ break;
+ }
+ }
+ mutex_unlock(&group->unbound_lock);
break;
}
@@ -578,6 +627,12 @@ int vfio_add_group_dev(struct device *dev,
iommu_group_put(iommu_group);
return PTR_ERR(group);
}
+ } else {
+ /*
+ * A found vfio_group already holds a reference to the
+ * iommu_group. A created vfio_group keeps the reference.
+ */
+ iommu_group_put(iommu_group);
}
device = vfio_group_get_device(group, dev);
@@ -586,21 +641,19 @@ int vfio_add_group_dev(struct device *dev,
dev_name(dev), iommu_group_id(iommu_group));
vfio_device_put(device);
vfio_group_put(group);
- iommu_group_put(iommu_group);
return -EBUSY;
}
device = vfio_group_create_device(group, dev, ops, device_data);
if (IS_ERR(device)) {
vfio_group_put(group);
- iommu_group_put(iommu_group);
return PTR_ERR(device);
}
/*
- * Added device holds reference to iommu_group and vfio_device
- * (which in turn holds reference to vfio_group). Drop extra
- * group reference used while acquiring device.
+ * Drop all but the vfio_device reference. The vfio_device holds
+ * a reference to the vfio_group, which holds a reference to the
+ * iommu_group.
*/
vfio_group_put(group);
@@ -655,8 +708,9 @@ void *vfio_del_group_dev(struct device *dev)
{
struct vfio_device *device = dev_get_drvdata(dev);
struct vfio_group *group = device->group;
- struct iommu_group *iommu_group = group->iommu_group;
void *device_data = device->device_data;
+ struct vfio_unbound_dev *unbound;
+ unsigned int i = 0;
/*
* The group exists so long as we have a device reference. Get
@@ -664,14 +718,49 @@ void *vfio_del_group_dev(struct device *dev)
*/
vfio_group_get(group);
+ /*
+ * When the device is removed from the group, the group suddenly
+ * becomes non-viable; the device has a driver (until the unbind
+ * completes), but it's not present in the group. This is bad news
+ * for any external users that need to re-acquire a group reference
+ * in order to match and release their existing reference. To
+ * solve this, we track such devices on the unbound_list to bridge
+ * the gap until they're fully unbound.
+ */
+ unbound = kzalloc(sizeof(*unbound), GFP_KERNEL);
+ if (unbound) {
+ unbound->dev = dev;
+ mutex_lock(&group->unbound_lock);
+ list_add(&unbound->unbound_next, &group->unbound_list);
+ mutex_unlock(&group->unbound_lock);
+ }
+ WARN_ON(!unbound);
+
vfio_device_put(device);
- /* TODO send a signal to encourage this to be released */
- wait_event(vfio.release_q, !vfio_dev_present(group, dev));
+ /*
+ * If the device is still present in the group after the above
+ * 'put', then it is in use and we need to request it from the
+ * bus driver. The driver may in turn need to request the
+ * device from the user. We send the request on an arbitrary
+ * interval with counter to allow the driver to take escalating
+ * measures to release the device if it has the ability to do so.
+ */
+ do {
+ device = vfio_group_get_device(group, dev);
+ if (!device)
+ break;
- vfio_group_put(group);
+ if (device->ops->request)
+ device->ops->request(device_data, i++);
- iommu_group_put(iommu_group);
+ vfio_device_put(device);
+
+ } while (wait_event_interruptible_timeout(vfio.release_q,
+ !vfio_dev_present(group, dev),
+ HZ * 10) <= 0);
+
+ vfio_group_put(group);
return device_data;
}
diff --git a/drivers/vfio/vfio_iommu_type1.c b/drivers/vfio/vfio_iommu_type1.c
index 4a9d666f1e91..57d8c37a002b 100644
--- a/drivers/vfio/vfio_iommu_type1.c
+++ b/drivers/vfio/vfio_iommu_type1.c
@@ -66,6 +66,7 @@ struct vfio_domain {
struct list_head next;
struct list_head group_list;
int prot; /* IOMMU_CACHE */
+ bool fgsp; /* Fine-grained super pages */
};
struct vfio_dma {
@@ -264,6 +265,7 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
unsigned long limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT;
bool lock_cap = capable(CAP_IPC_LOCK);
long ret, i;
+ bool rsvd;
if (!current->mm)
return -ENODEV;
@@ -272,10 +274,9 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
if (ret)
return ret;
- if (is_invalid_reserved_pfn(*pfn_base))
- return 1;
+ rsvd = is_invalid_reserved_pfn(*pfn_base);
- if (!lock_cap && current->mm->locked_vm + 1 > limit) {
+ if (!rsvd && !lock_cap && current->mm->locked_vm + 1 > limit) {
put_pfn(*pfn_base, prot);
pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n", __func__,
limit << PAGE_SHIFT);
@@ -283,7 +284,8 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
}
if (unlikely(disable_hugepages)) {
- vfio_lock_acct(1);
+ if (!rsvd)
+ vfio_lock_acct(1);
return 1;
}
@@ -295,12 +297,14 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
if (ret)
break;
- if (pfn != *pfn_base + i || is_invalid_reserved_pfn(pfn)) {
+ if (pfn != *pfn_base + i ||
+ rsvd != is_invalid_reserved_pfn(pfn)) {
put_pfn(pfn, prot);
break;
}
- if (!lock_cap && current->mm->locked_vm + i + 1 > limit) {
+ if (!rsvd && !lock_cap &&
+ current->mm->locked_vm + i + 1 > limit) {
put_pfn(pfn, prot);
pr_warn("%s: RLIMIT_MEMLOCK (%ld) exceeded\n",
__func__, limit << PAGE_SHIFT);
@@ -308,7 +312,8 @@ static long vfio_pin_pages(unsigned long vaddr, long npage,
}
}
- vfio_lock_acct(i);
+ if (!rsvd)
+ vfio_lock_acct(i);
return i;
}
@@ -346,12 +351,14 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
domain = d = list_first_entry(&iommu->domain_list,
struct vfio_domain, next);
- list_for_each_entry_continue(d, &iommu->domain_list, next)
+ list_for_each_entry_continue(d, &iommu->domain_list, next) {
iommu_unmap(d->domain, dma->iova, dma->size);
+ cond_resched();
+ }
while (iova < end) {
- size_t unmapped;
- phys_addr_t phys;
+ size_t unmapped, len;
+ phys_addr_t phys, next;
phys = iommu_iova_to_phys(domain->domain, iova);
if (WARN_ON(!phys)) {
@@ -359,7 +366,19 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
continue;
}
- unmapped = iommu_unmap(domain->domain, iova, PAGE_SIZE);
+ /*
+ * To optimize for fewer iommu_unmap() calls, each of which
+ * may require hardware cache flushing, try to find the
+ * largest contiguous physical memory chunk to unmap.
+ */
+ for (len = PAGE_SIZE;
+ !domain->fgsp && iova + len < end; len += PAGE_SIZE) {
+ next = iommu_iova_to_phys(domain->domain, iova + len);
+ if (next != phys + len)
+ break;
+ }
+
+ unmapped = iommu_unmap(domain->domain, iova, len);
if (WARN_ON(!unmapped))
break;
@@ -367,6 +386,8 @@ static void vfio_unmap_unpin(struct vfio_iommu *iommu, struct vfio_dma *dma)
unmapped >> PAGE_SHIFT,
dma->prot, false);
iova += unmapped;
+
+ cond_resched();
}
vfio_lock_acct(-unlocked);
@@ -511,6 +532,8 @@ static int vfio_iommu_map(struct vfio_iommu *iommu, dma_addr_t iova,
map_try_harder(d, iova, pfn, npage, prot))
goto unwind;
}
+
+ cond_resched();
}
return 0;
@@ -665,6 +688,39 @@ static int vfio_iommu_replay(struct vfio_iommu *iommu,
return 0;
}
+/*
+ * We change our unmap behavior slightly depending on whether the IOMMU
+ * supports fine-grained superpages. IOMMUs like AMD-Vi will use a superpage
+ * for practically any contiguous power-of-two mapping we give it. This means
+ * we don't need to look for contiguous chunks ourselves to make unmapping
+ * more efficient. On IOMMUs with coarse-grained super pages, like Intel VT-d
+ * with discrete 2M/1G/512G/1T superpages, identifying contiguous chunks
+ * significantly boosts non-hugetlbfs mappings and doesn't seem to hurt when
+ * hugetlbfs is in use.
+ */
+static void vfio_test_domain_fgsp(struct vfio_domain *domain)
+{
+ struct page *pages;
+ int ret, order = get_order(PAGE_SIZE * 2);
+
+ pages = alloc_pages(GFP_KERNEL | __GFP_ZERO, order);
+ if (!pages)
+ return;
+
+ ret = iommu_map(domain->domain, 0, page_to_phys(pages), PAGE_SIZE * 2,
+ IOMMU_READ | IOMMU_WRITE | domain->prot);
+ if (!ret) {
+ size_t unmapped = iommu_unmap(domain->domain, 0, PAGE_SIZE);
+
+ if (unmapped == PAGE_SIZE)
+ iommu_unmap(domain->domain, PAGE_SIZE, PAGE_SIZE);
+ else
+ domain->fgsp = true;
+ }
+
+ __free_pages(pages, order);
+}
+
static int vfio_iommu_type1_attach_group(void *iommu_data,
struct iommu_group *iommu_group)
{
@@ -758,6 +814,8 @@ static int vfio_iommu_type1_attach_group(void *iommu_data,
}
}
+ vfio_test_domain_fgsp(domain);
+
/* replay mappings on new domains */
ret = vfio_iommu_replay(iommu, domain);
if (ret)
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index d415d69dc237..afa06d28725d 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -84,10 +84,6 @@ struct vhost_net_ubuf_ref {
struct vhost_net_virtqueue {
struct vhost_virtqueue vq;
- /* hdr is used to store the virtio header.
- * Since each iovec has >= 1 byte length, we never need more than
- * header length entries to store the header. */
- struct iovec hdr[sizeof(struct virtio_net_hdr_mrg_rxbuf)];
size_t vhost_hlen;
size_t sock_hlen;
/* vhost zerocopy support fields below: */
@@ -235,44 +231,6 @@ static bool vhost_sock_zcopy(struct socket *sock)
sock_flag(sock->sk, SOCK_ZEROCOPY);
}
-/* Pop first len bytes from iovec. Return number of segments used. */
-static int move_iovec_hdr(struct iovec *from, struct iovec *to,
- size_t len, int iov_count)
-{
- int seg = 0;
- size_t size;
-
- while (len && seg < iov_count) {
- size = min(from->iov_len, len);
- to->iov_base = from->iov_base;
- to->iov_len = size;
- from->iov_len -= size;
- from->iov_base += size;
- len -= size;
- ++from;
- ++to;
- ++seg;
- }
- return seg;
-}
-/* Copy iovec entries for len bytes from iovec. */
-static void copy_iovec_hdr(const struct iovec *from, struct iovec *to,
- size_t len, int iovcount)
-{
- int seg = 0;
- size_t size;
-
- while (len && seg < iovcount) {
- size = min(from->iov_len, len);
- to->iov_base = from->iov_base;
- to->iov_len = size;
- len -= size;
- ++from;
- ++to;
- ++seg;
- }
-}
-
/* In case of DMA done not in order in lower device driver for some reason.
* upend_idx is used to track end of used idx, done_idx is used to track head
* of used idx. Once lower device DMA done contiguously, we will signal KVM
@@ -336,7 +294,7 @@ static void handle_tx(struct vhost_net *net)
{
struct vhost_net_virtqueue *nvq = &net->vqs[VHOST_NET_VQ_TX];
struct vhost_virtqueue *vq = &nvq->vq;
- unsigned out, in, s;
+ unsigned out, in;
int head;
struct msghdr msg = {
.msg_name = NULL,
@@ -395,16 +353,17 @@ static void handle_tx(struct vhost_net *net)
break;
}
/* Skip header. TODO: support TSO. */
- s = move_iovec_hdr(vq->iov, nvq->hdr, hdr_size, out);
len = iov_length(vq->iov, out);
iov_iter_init(&msg.msg_iter, WRITE, vq->iov, out, len);
+ iov_iter_advance(&msg.msg_iter, hdr_size);
/* Sanity check */
- if (!len) {
+ if (!iov_iter_count(&msg.msg_iter)) {
vq_err(vq, "Unexpected header len for TX: "
"%zd expected %zd\n",
- iov_length(nvq->hdr, s), hdr_size);
+ len, hdr_size);
break;
}
+ len = iov_iter_count(&msg.msg_iter);
zcopy_used = zcopy && len >= VHOST_GOODCOPY_LEN
&& (nvq->upend_idx + 1) % UIO_MAXIOV !=
@@ -469,7 +428,7 @@ static int peek_head_len(struct sock *sk)
head = skb_peek(&sk->sk_receive_queue);
if (likely(head)) {
len = head->len;
- if (vlan_tx_tag_present(head))
+ if (skb_vlan_tag_present(head))
len += VLAN_HLEN;
}
@@ -569,9 +528,9 @@ static void handle_rx(struct vhost_net *net)
.msg_controllen = 0,
.msg_flags = MSG_DONTWAIT,
};
- struct virtio_net_hdr_mrg_rxbuf hdr = {
- .hdr.flags = 0,
- .hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE
+ struct virtio_net_hdr hdr = {
+ .flags = 0,
+ .gso_type = VIRTIO_NET_HDR_GSO_NONE
};
size_t total_len = 0;
int err, mergeable;
@@ -579,6 +538,8 @@ static void handle_rx(struct vhost_net *net)
size_t vhost_hlen, sock_hlen;
size_t vhost_len, sock_len;
struct socket *sock;
+ struct iov_iter fixup;
+ __virtio16 num_buffers;
mutex_lock(&vq->mutex);
sock = vq->private_data;
@@ -623,14 +584,19 @@ static void handle_rx(struct vhost_net *net)
break;
}
/* We don't need to be notified again. */
- if (unlikely((vhost_hlen)))
- /* Skip header. TODO: support TSO. */
- move_iovec_hdr(vq->iov, nvq->hdr, vhost_hlen, in);
- else
- /* Copy the header for use in VIRTIO_NET_F_MRG_RXBUF:
- * needed because recvmsg can modify msg_iov. */
- copy_iovec_hdr(vq->iov, nvq->hdr, sock_hlen, in);
- iov_iter_init(&msg.msg_iter, READ, vq->iov, in, sock_len);
+ iov_iter_init(&msg.msg_iter, READ, vq->iov, in, vhost_len);
+ fixup = msg.msg_iter;
+ if (unlikely((vhost_hlen))) {
+ /* We will supply the header ourselves
+ * TODO: support TSO.
+ */
+ iov_iter_advance(&msg.msg_iter, vhost_hlen);
+ } else {
+ /* It'll come from socket; we'll need to patch
+ * ->num_buffers over if VIRTIO_NET_F_MRG_RXBUF
+ */
+ iov_iter_advance(&fixup, sizeof(hdr));
+ }
err = sock->ops->recvmsg(NULL, sock, &msg,
sock_len, MSG_DONTWAIT | MSG_TRUNC);
/* Userspace might have consumed the packet meanwhile:
@@ -642,18 +608,18 @@ static void handle_rx(struct vhost_net *net)
vhost_discard_vq_desc(vq, headcount);
continue;
}
+ /* Supply virtio_net_hdr if VHOST_NET_F_VIRTIO_NET_HDR */
if (unlikely(vhost_hlen) &&
- memcpy_toiovecend(nvq->hdr, (unsigned char *)&hdr, 0,
- vhost_hlen)) {
+ copy_to_iter(&hdr, sizeof(hdr), &fixup) != sizeof(hdr)) {
vq_err(vq, "Unable to write vnet_hdr at addr %p\n",
vq->iov->iov_base);
break;
}
/* TODO: Should check and handle checksum. */
+
+ num_buffers = cpu_to_vhost16(vq, headcount);
if (likely(mergeable) &&
- memcpy_toiovecend(nvq->hdr, (unsigned char *)&headcount,
- offsetof(typeof(hdr), num_buffers),
- sizeof hdr.num_buffers)) {
+ copy_to_iter(&num_buffers, 2, &fixup) != 2) {
vq_err(vq, "Failed num_buffers write");
vhost_discard_vq_desc(vq, headcount);
break;
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index d695b1673ae5..8d4f3f1ff799 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -38,7 +38,6 @@
#include <linux/miscdevice.h>
#include <asm/unaligned.h>
#include <scsi/scsi.h>
-#include <scsi/scsi_tcq.h>
#include <target/target_core_base.h>
#include <target/target_core_fabric.h>
#include <target/target_core_fabric_configfs.h>
@@ -52,13 +51,13 @@
#include "vhost.h"
-#define TCM_VHOST_VERSION "v0.1"
-#define TCM_VHOST_NAMELEN 256
-#define TCM_VHOST_MAX_CDB_SIZE 32
-#define TCM_VHOST_DEFAULT_TAGS 256
-#define TCM_VHOST_PREALLOC_SGLS 2048
-#define TCM_VHOST_PREALLOC_UPAGES 2048
-#define TCM_VHOST_PREALLOC_PROT_SGLS 512
+#define VHOST_SCSI_VERSION "v0.1"
+#define VHOST_SCSI_NAMELEN 256
+#define VHOST_SCSI_MAX_CDB_SIZE 32
+#define VHOST_SCSI_DEFAULT_TAGS 256
+#define VHOST_SCSI_PREALLOC_SGLS 2048
+#define VHOST_SCSI_PREALLOC_UPAGES 2048
+#define VHOST_SCSI_PREALLOC_PROT_SGLS 512
struct vhost_scsi_inflight {
/* Wait for the flush operation to finish */
@@ -67,11 +66,13 @@ struct vhost_scsi_inflight {
struct kref kref;
};
-struct tcm_vhost_cmd {
+struct vhost_scsi_cmd {
/* Descriptor from vhost_get_vq_desc() for virt_queue segment */
int tvc_vq_desc;
/* virtio-scsi initiator task attribute */
int tvc_task_attr;
+ /* virtio-scsi response incoming iovecs */
+ int tvc_in_iovs;
/* virtio-scsi initiator data direction */
enum dma_data_direction tvc_data_direction;
/* Expected data transfer length from virtio-scsi header */
@@ -81,26 +82,26 @@ struct tcm_vhost_cmd {
/* The number of scatterlists associated with this cmd */
u32 tvc_sgl_count;
u32 tvc_prot_sgl_count;
- /* Saved unpacked SCSI LUN for tcm_vhost_submission_work() */
+ /* Saved unpacked SCSI LUN for vhost_scsi_submission_work() */
u32 tvc_lun;
/* Pointer to the SGL formatted memory from virtio-scsi */
struct scatterlist *tvc_sgl;
struct scatterlist *tvc_prot_sgl;
struct page **tvc_upages;
- /* Pointer to response */
- struct virtio_scsi_cmd_resp __user *tvc_resp;
+ /* Pointer to response header iovec */
+ struct iovec *tvc_resp_iov;
/* Pointer to vhost_scsi for our device */
struct vhost_scsi *tvc_vhost;
/* Pointer to vhost_virtqueue for the cmd */
struct vhost_virtqueue *tvc_vq;
/* Pointer to vhost nexus memory */
- struct tcm_vhost_nexus *tvc_nexus;
+ struct vhost_scsi_nexus *tvc_nexus;
/* The TCM I/O descriptor that is accessed via container_of() */
struct se_cmd tvc_se_cmd;
- /* work item used for cmwq dispatch to tcm_vhost_submission_work() */
+ /* work item used for cmwq dispatch to vhost_scsi_submission_work() */
struct work_struct work;
/* Copy of the incoming SCSI command descriptor block (CDB) */
- unsigned char tvc_cdb[TCM_VHOST_MAX_CDB_SIZE];
+ unsigned char tvc_cdb[VHOST_SCSI_MAX_CDB_SIZE];
/* Sense buffer that will be mapped into outgoing status */
unsigned char tvc_sense_buf[TRANSPORT_SENSE_BUFFER];
/* Completed commands list, serviced from vhost worker thread */
@@ -109,53 +110,53 @@ struct tcm_vhost_cmd {
struct vhost_scsi_inflight *inflight;
};
-struct tcm_vhost_nexus {
+struct vhost_scsi_nexus {
/* Pointer to TCM session for I_T Nexus */
struct se_session *tvn_se_sess;
};
-struct tcm_vhost_nacl {
+struct vhost_scsi_nacl {
/* Binary World Wide unique Port Name for Vhost Initiator port */
u64 iport_wwpn;
/* ASCII formatted WWPN for Sas Initiator port */
- char iport_name[TCM_VHOST_NAMELEN];
- /* Returned by tcm_vhost_make_nodeacl() */
+ char iport_name[VHOST_SCSI_NAMELEN];
+ /* Returned by vhost_scsi_make_nodeacl() */
struct se_node_acl se_node_acl;
};
-struct tcm_vhost_tpg {
+struct vhost_scsi_tpg {
/* Vhost port target portal group tag for TCM */
u16 tport_tpgt;
/* Used to track number of TPG Port/Lun Links wrt to explict I_T Nexus shutdown */
int tv_tpg_port_count;
/* Used for vhost_scsi device reference to tpg_nexus, protected by tv_tpg_mutex */
int tv_tpg_vhost_count;
- /* list for tcm_vhost_list */
+ /* list for vhost_scsi_list */
struct list_head tv_tpg_list;
/* Used to protect access for tpg_nexus */
struct mutex tv_tpg_mutex;
/* Pointer to the TCM VHost I_T Nexus for this TPG endpoint */
- struct tcm_vhost_nexus *tpg_nexus;
- /* Pointer back to tcm_vhost_tport */
- struct tcm_vhost_tport *tport;
- /* Returned by tcm_vhost_make_tpg() */
+ struct vhost_scsi_nexus *tpg_nexus;
+ /* Pointer back to vhost_scsi_tport */
+ struct vhost_scsi_tport *tport;
+ /* Returned by vhost_scsi_make_tpg() */
struct se_portal_group se_tpg;
/* Pointer back to vhost_scsi, protected by tv_tpg_mutex */
struct vhost_scsi *vhost_scsi;
};
-struct tcm_vhost_tport {
+struct vhost_scsi_tport {
/* SCSI protocol the tport is providing */
u8 tport_proto_id;
/* Binary World Wide unique Port Name for Vhost Target port */
u64 tport_wwpn;
/* ASCII formatted WWPN for Vhost Target port */
- char tport_name[TCM_VHOST_NAMELEN];
- /* Returned by tcm_vhost_make_tport() */
+ char tport_name[VHOST_SCSI_NAMELEN];
+ /* Returned by vhost_scsi_make_tport() */
struct se_wwn tport_wwn;
};
-struct tcm_vhost_evt {
+struct vhost_scsi_evt {
/* event to be sent to guest */
struct virtio_scsi_event event;
/* event list, serviced from vhost worker thread */
@@ -171,7 +172,9 @@ enum {
/* 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)
+ (1ULL << VIRTIO_SCSI_F_T10_PI) |
+ (1ULL << VIRTIO_F_ANY_LAYOUT) |
+ (1ULL << VIRTIO_F_VERSION_1)
};
#define VHOST_SCSI_MAX_TARGET 256
@@ -195,7 +198,7 @@ struct vhost_scsi_virtqueue {
struct vhost_scsi {
/* Protected by vhost_scsi->dev.mutex */
- struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_scsi_tpg **vs_tpg;
char vs_vhost_wwpn[TRANSPORT_IQN_LEN];
struct vhost_dev dev;
@@ -212,21 +215,21 @@ struct vhost_scsi {
};
/* Local pointer to allocated TCM configfs fabric module */
-static struct target_fabric_configfs *tcm_vhost_fabric_configfs;
+static struct target_fabric_configfs *vhost_scsi_fabric_configfs;
-static struct workqueue_struct *tcm_vhost_workqueue;
+static struct workqueue_struct *vhost_scsi_workqueue;
-/* Global spinlock to protect tcm_vhost TPG list for vhost IOCTL access */
-static DEFINE_MUTEX(tcm_vhost_mutex);
-static LIST_HEAD(tcm_vhost_list);
+/* Global spinlock to protect vhost_scsi TPG list for vhost IOCTL access */
+static DEFINE_MUTEX(vhost_scsi_mutex);
+static LIST_HEAD(vhost_scsi_list);
-static int iov_num_pages(struct iovec *iov)
+static int iov_num_pages(void __user *iov_base, size_t iov_len)
{
- return (PAGE_ALIGN((unsigned long)iov->iov_base + iov->iov_len) -
- ((unsigned long)iov->iov_base & PAGE_MASK)) >> PAGE_SHIFT;
+ return (PAGE_ALIGN((unsigned long)iov_base + iov_len) -
+ ((unsigned long)iov_base & PAGE_MASK)) >> PAGE_SHIFT;
}
-static void tcm_vhost_done_inflight(struct kref *kref)
+static void vhost_scsi_done_inflight(struct kref *kref)
{
struct vhost_scsi_inflight *inflight;
@@ -234,7 +237,7 @@ static void tcm_vhost_done_inflight(struct kref *kref)
complete(&inflight->comp);
}
-static void tcm_vhost_init_inflight(struct vhost_scsi *vs,
+static void vhost_scsi_init_inflight(struct vhost_scsi *vs,
struct vhost_scsi_inflight *old_inflight[])
{
struct vhost_scsi_inflight *new_inflight;
@@ -262,7 +265,7 @@ static void tcm_vhost_init_inflight(struct vhost_scsi *vs,
}
static struct vhost_scsi_inflight *
-tcm_vhost_get_inflight(struct vhost_virtqueue *vq)
+vhost_scsi_get_inflight(struct vhost_virtqueue *vq)
{
struct vhost_scsi_inflight *inflight;
struct vhost_scsi_virtqueue *svq;
@@ -274,31 +277,31 @@ tcm_vhost_get_inflight(struct vhost_virtqueue *vq)
return inflight;
}
-static void tcm_vhost_put_inflight(struct vhost_scsi_inflight *inflight)
+static void vhost_scsi_put_inflight(struct vhost_scsi_inflight *inflight)
{
- kref_put(&inflight->kref, tcm_vhost_done_inflight);
+ kref_put(&inflight->kref, vhost_scsi_done_inflight);
}
-static int tcm_vhost_check_true(struct se_portal_group *se_tpg)
+static int vhost_scsi_check_true(struct se_portal_group *se_tpg)
{
return 1;
}
-static int tcm_vhost_check_false(struct se_portal_group *se_tpg)
+static int vhost_scsi_check_false(struct se_portal_group *se_tpg)
{
return 0;
}
-static char *tcm_vhost_get_fabric_name(void)
+static char *vhost_scsi_get_fabric_name(void)
{
return "vhost";
}
-static u8 tcm_vhost_get_fabric_proto_ident(struct se_portal_group *se_tpg)
+static u8 vhost_scsi_get_fabric_proto_ident(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -316,37 +319,37 @@ static u8 tcm_vhost_get_fabric_proto_ident(struct se_portal_group *se_tpg)
return sas_get_fabric_proto_ident(se_tpg);
}
-static char *tcm_vhost_get_fabric_wwn(struct se_portal_group *se_tpg)
+static char *vhost_scsi_get_fabric_wwn(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
return &tport->tport_name[0];
}
-static u16 tcm_vhost_get_tag(struct se_portal_group *se_tpg)
+static u16 vhost_scsi_get_tpgt(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
return tpg->tport_tpgt;
}
-static u32 tcm_vhost_get_default_depth(struct se_portal_group *se_tpg)
+static u32 vhost_scsi_get_default_depth(struct se_portal_group *se_tpg)
{
return 1;
}
static u32
-tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
+vhost_scsi_get_pr_transport_id(struct se_portal_group *se_tpg,
struct se_node_acl *se_nacl,
struct t10_pr_registration *pr_reg,
int *format_code,
unsigned char *buf)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -369,14 +372,14 @@ tcm_vhost_get_pr_transport_id(struct se_portal_group *se_tpg,
}
static u32
-tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
+vhost_scsi_get_pr_transport_id_len(struct se_portal_group *se_tpg,
struct se_node_acl *se_nacl,
struct t10_pr_registration *pr_reg,
int *format_code)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -399,14 +402,14 @@ tcm_vhost_get_pr_transport_id_len(struct se_portal_group *se_tpg,
}
static char *
-tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
+vhost_scsi_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
const char *buf,
u32 *out_tid_len,
char **port_nexus_ptr)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport = tpg->tport;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport = tpg->tport;
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -429,13 +432,13 @@ tcm_vhost_parse_pr_out_transport_id(struct se_portal_group *se_tpg,
}
static struct se_node_acl *
-tcm_vhost_alloc_fabric_acl(struct se_portal_group *se_tpg)
+vhost_scsi_alloc_fabric_acl(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_nacl *nacl;
+ struct vhost_scsi_nacl *nacl;
- nacl = kzalloc(sizeof(struct tcm_vhost_nacl), GFP_KERNEL);
+ nacl = kzalloc(sizeof(struct vhost_scsi_nacl), GFP_KERNEL);
if (!nacl) {
- pr_err("Unable to allocate struct tcm_vhost_nacl\n");
+ pr_err("Unable to allocate struct vhost_scsi_nacl\n");
return NULL;
}
@@ -443,24 +446,24 @@ tcm_vhost_alloc_fabric_acl(struct se_portal_group *se_tpg)
}
static void
-tcm_vhost_release_fabric_acl(struct se_portal_group *se_tpg,
+vhost_scsi_release_fabric_acl(struct se_portal_group *se_tpg,
struct se_node_acl *se_nacl)
{
- struct tcm_vhost_nacl *nacl = container_of(se_nacl,
- struct tcm_vhost_nacl, se_node_acl);
+ struct vhost_scsi_nacl *nacl = container_of(se_nacl,
+ struct vhost_scsi_nacl, se_node_acl);
kfree(nacl);
}
-static u32 tcm_vhost_tpg_get_inst_index(struct se_portal_group *se_tpg)
+static u32 vhost_scsi_tpg_get_inst_index(struct se_portal_group *se_tpg)
{
return 1;
}
-static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
+static void vhost_scsi_release_cmd(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *tv_cmd = container_of(se_cmd,
- struct tcm_vhost_cmd, tvc_se_cmd);
- struct se_session *se_sess = se_cmd->se_sess;
+ struct vhost_scsi_cmd *tv_cmd = container_of(se_cmd,
+ struct vhost_scsi_cmd, tvc_se_cmd);
+ struct se_session *se_sess = tv_cmd->tvc_nexus->tvn_se_sess;
int i;
if (tv_cmd->tvc_sgl_count) {
@@ -472,53 +475,53 @@ static void tcm_vhost_release_cmd(struct se_cmd *se_cmd)
put_page(sg_page(&tv_cmd->tvc_prot_sgl[i]));
}
- tcm_vhost_put_inflight(tv_cmd->inflight);
+ vhost_scsi_put_inflight(tv_cmd->inflight);
percpu_ida_free(&se_sess->sess_tag_pool, se_cmd->map_tag);
}
-static int tcm_vhost_shutdown_session(struct se_session *se_sess)
+static int vhost_scsi_shutdown_session(struct se_session *se_sess)
{
return 0;
}
-static void tcm_vhost_close_session(struct se_session *se_sess)
+static void vhost_scsi_close_session(struct se_session *se_sess)
{
return;
}
-static u32 tcm_vhost_sess_get_index(struct se_session *se_sess)
+static u32 vhost_scsi_sess_get_index(struct se_session *se_sess)
{
return 0;
}
-static int tcm_vhost_write_pending(struct se_cmd *se_cmd)
+static int vhost_scsi_write_pending(struct se_cmd *se_cmd)
{
/* Go ahead and process the write immediately */
target_execute_cmd(se_cmd);
return 0;
}
-static int tcm_vhost_write_pending_status(struct se_cmd *se_cmd)
+static int vhost_scsi_write_pending_status(struct se_cmd *se_cmd)
{
return 0;
}
-static void tcm_vhost_set_default_node_attrs(struct se_node_acl *nacl)
+static void vhost_scsi_set_default_node_attrs(struct se_node_acl *nacl)
{
return;
}
-static u32 tcm_vhost_get_task_tag(struct se_cmd *se_cmd)
+static u32 vhost_scsi_get_task_tag(struct se_cmd *se_cmd)
{
return 0;
}
-static int tcm_vhost_get_cmd_state(struct se_cmd *se_cmd)
+static int vhost_scsi_get_cmd_state(struct se_cmd *se_cmd)
{
return 0;
}
-static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *cmd)
+static void vhost_scsi_complete_cmd(struct vhost_scsi_cmd *cmd)
{
struct vhost_scsi *vs = cmd->tvc_vhost;
@@ -527,44 +530,44 @@ static void vhost_scsi_complete_cmd(struct tcm_vhost_cmd *cmd)
vhost_work_queue(&vs->dev, &vs->vs_completion_work);
}
-static int tcm_vhost_queue_data_in(struct se_cmd *se_cmd)
+static int vhost_scsi_queue_data_in(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *cmd = container_of(se_cmd,
- struct tcm_vhost_cmd, tvc_se_cmd);
+ struct vhost_scsi_cmd *cmd = container_of(se_cmd,
+ struct vhost_scsi_cmd, tvc_se_cmd);
vhost_scsi_complete_cmd(cmd);
return 0;
}
-static int tcm_vhost_queue_status(struct se_cmd *se_cmd)
+static int vhost_scsi_queue_status(struct se_cmd *se_cmd)
{
- struct tcm_vhost_cmd *cmd = container_of(se_cmd,
- struct tcm_vhost_cmd, tvc_se_cmd);
+ struct vhost_scsi_cmd *cmd = container_of(se_cmd,
+ struct vhost_scsi_cmd, tvc_se_cmd);
vhost_scsi_complete_cmd(cmd);
return 0;
}
-static void tcm_vhost_queue_tm_rsp(struct se_cmd *se_cmd)
+static void vhost_scsi_queue_tm_rsp(struct se_cmd *se_cmd)
{
return;
}
-static void tcm_vhost_aborted_task(struct se_cmd *se_cmd)
+static void vhost_scsi_aborted_task(struct se_cmd *se_cmd)
{
return;
}
-static void tcm_vhost_free_evt(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
+static void vhost_scsi_free_evt(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
{
vs->vs_events_nr--;
kfree(evt);
}
-static struct tcm_vhost_evt *
-tcm_vhost_allocate_evt(struct vhost_scsi *vs,
+static struct vhost_scsi_evt *
+vhost_scsi_allocate_evt(struct vhost_scsi *vs,
u32 event, u32 reason)
{
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
- struct tcm_vhost_evt *evt;
+ struct vhost_scsi_evt *evt;
if (vs->vs_events_nr > VHOST_SCSI_MAX_EVENT) {
vs->vs_events_missed = true;
@@ -573,7 +576,7 @@ tcm_vhost_allocate_evt(struct vhost_scsi *vs,
evt = kzalloc(sizeof(*evt), GFP_KERNEL);
if (!evt) {
- vq_err(vq, "Failed to allocate tcm_vhost_evt\n");
+ vq_err(vq, "Failed to allocate vhost_scsi_evt\n");
vs->vs_events_missed = true;
return NULL;
}
@@ -585,7 +588,7 @@ tcm_vhost_allocate_evt(struct vhost_scsi *vs,
return evt;
}
-static void vhost_scsi_free_cmd(struct tcm_vhost_cmd *cmd)
+static void vhost_scsi_free_cmd(struct vhost_scsi_cmd *cmd)
{
struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
@@ -600,7 +603,7 @@ static int vhost_scsi_check_stop_free(struct se_cmd *se_cmd)
}
static void
-tcm_vhost_do_evt_work(struct vhost_scsi *vs, struct tcm_vhost_evt *evt)
+vhost_scsi_do_evt_work(struct vhost_scsi *vs, struct vhost_scsi_evt *evt)
{
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
struct virtio_scsi_event *event = &evt->event;
@@ -646,24 +649,24 @@ again:
if (!ret)
vhost_add_used_and_signal(&vs->dev, vq, head, 0);
else
- vq_err(vq, "Faulted on tcm_vhost_send_event\n");
+ vq_err(vq, "Faulted on vhost_scsi_send_event\n");
}
-static void tcm_vhost_evt_work(struct vhost_work *work)
+static void vhost_scsi_evt_work(struct vhost_work *work)
{
struct vhost_scsi *vs = container_of(work, struct vhost_scsi,
vs_event_work);
struct vhost_virtqueue *vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
- struct tcm_vhost_evt *evt;
+ struct vhost_scsi_evt *evt;
struct llist_node *llnode;
mutex_lock(&vq->mutex);
llnode = llist_del_all(&vs->vs_event_list);
while (llnode) {
- evt = llist_entry(llnode, struct tcm_vhost_evt, list);
+ evt = llist_entry(llnode, struct vhost_scsi_evt, list);
llnode = llist_next(llnode);
- tcm_vhost_do_evt_work(vs, evt);
- tcm_vhost_free_evt(vs, evt);
+ vhost_scsi_do_evt_work(vs, evt);
+ vhost_scsi_free_evt(vs, evt);
}
mutex_unlock(&vq->mutex);
}
@@ -679,15 +682,16 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
vs_completion_work);
DECLARE_BITMAP(signal, VHOST_SCSI_MAX_VQ);
struct virtio_scsi_cmd_resp v_rsp;
- struct tcm_vhost_cmd *cmd;
+ struct vhost_scsi_cmd *cmd;
struct llist_node *llnode;
struct se_cmd *se_cmd;
+ struct iov_iter iov_iter;
int ret, vq;
bitmap_zero(signal, VHOST_SCSI_MAX_VQ);
llnode = llist_del_all(&vs->vs_completion_list);
while (llnode) {
- cmd = llist_entry(llnode, struct tcm_vhost_cmd,
+ cmd = llist_entry(llnode, struct vhost_scsi_cmd,
tvc_completion_list);
llnode = llist_next(llnode);
se_cmd = &cmd->tvc_se_cmd;
@@ -703,8 +707,11 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
se_cmd->scsi_sense_length);
memcpy(v_rsp.sense, cmd->tvc_sense_buf,
se_cmd->scsi_sense_length);
- ret = copy_to_user(cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
- if (likely(ret == 0)) {
+
+ iov_iter_init(&iov_iter, READ, cmd->tvc_resp_iov,
+ cmd->tvc_in_iovs, sizeof(v_rsp));
+ ret = copy_to_iter(&v_rsp, sizeof(v_rsp), &iov_iter);
+ if (likely(ret == sizeof(v_rsp))) {
struct vhost_scsi_virtqueue *q;
vhost_add_used(cmd->tvc_vq, cmd->tvc_vq_desc, 0);
q = container_of(cmd->tvc_vq, struct vhost_scsi_virtqueue, vq);
@@ -722,13 +729,13 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
vhost_signal(&vs->dev, &vs->vqs[vq].vq);
}
-static struct tcm_vhost_cmd *
-vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
+static struct vhost_scsi_cmd *
+vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct vhost_scsi_tpg *tpg,
unsigned char *cdb, u64 scsi_tag, u16 lun, u8 task_attr,
u32 exp_data_len, int data_direction)
{
- struct tcm_vhost_cmd *cmd;
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_cmd *cmd;
+ struct vhost_scsi_nexus *tv_nexus;
struct se_session *se_sess;
struct scatterlist *sg, *prot_sg;
struct page **pages;
@@ -736,22 +743,22 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
tv_nexus = tpg->tpg_nexus;
if (!tv_nexus) {
- pr_err("Unable to locate active struct tcm_vhost_nexus\n");
+ pr_err("Unable to locate active struct vhost_scsi_nexus\n");
return ERR_PTR(-EIO);
}
se_sess = tv_nexus->tvn_se_sess;
tag = percpu_ida_alloc(&se_sess->sess_tag_pool, TASK_RUNNING);
if (tag < 0) {
- pr_err("Unable to obtain tag for tcm_vhost_cmd\n");
+ pr_err("Unable to obtain tag for vhost_scsi_cmd\n");
return ERR_PTR(-ENOMEM);
}
- cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[tag];
+ cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[tag];
sg = cmd->tvc_sgl;
prot_sg = cmd->tvc_prot_sgl;
pages = cmd->tvc_upages;
- memset(cmd, 0, sizeof(struct tcm_vhost_cmd));
+ memset(cmd, 0, sizeof(struct vhost_scsi_cmd));
cmd->tvc_sgl = sg;
cmd->tvc_prot_sgl = prot_sg;
@@ -763,9 +770,9 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
cmd->tvc_exp_data_len = exp_data_len;
cmd->tvc_data_direction = data_direction;
cmd->tvc_nexus = tv_nexus;
- cmd->inflight = tcm_vhost_get_inflight(vq);
+ cmd->inflight = vhost_scsi_get_inflight(vq);
- memcpy(cmd->tvc_cdb, cdb, TCM_VHOST_MAX_CDB_SIZE);
+ memcpy(cmd->tvc_cdb, cdb, VHOST_SCSI_MAX_CDB_SIZE);
return cmd;
}
@@ -776,29 +783,22 @@ vhost_scsi_get_tag(struct vhost_virtqueue *vq, struct tcm_vhost_tpg *tpg,
* Returns the number of scatterlist entries used or -errno on error.
*/
static int
-vhost_scsi_map_to_sgl(struct tcm_vhost_cmd *tv_cmd,
+vhost_scsi_map_to_sgl(struct vhost_scsi_cmd *cmd,
+ void __user *ptr,
+ size_t len,
struct scatterlist *sgl,
- unsigned int sgl_count,
- struct iovec *iov,
- struct page **pages,
bool write)
{
- unsigned int npages = 0, pages_nr, offset, nbytes;
+ unsigned int npages = 0, offset, nbytes;
+ unsigned int pages_nr = iov_num_pages(ptr, len);
struct scatterlist *sg = sgl;
- void __user *ptr = iov->iov_base;
- size_t len = iov->iov_len;
+ struct page **pages = cmd->tvc_upages;
int ret, i;
- pages_nr = iov_num_pages(iov);
- if (pages_nr > sgl_count) {
- pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
- " sgl_count: %u\n", pages_nr, sgl_count);
- return -ENOBUFS;
- }
- if (pages_nr > TCM_VHOST_PREALLOC_UPAGES) {
+ if (pages_nr > VHOST_SCSI_PREALLOC_UPAGES) {
pr_err("vhost_scsi_map_to_sgl() pages_nr: %u greater than"
- " preallocated TCM_VHOST_PREALLOC_UPAGES: %u\n",
- pages_nr, TCM_VHOST_PREALLOC_UPAGES);
+ " preallocated VHOST_SCSI_PREALLOC_UPAGES: %u\n",
+ pages_nr, VHOST_SCSI_PREALLOC_UPAGES);
return -ENOBUFS;
}
@@ -829,84 +829,94 @@ out:
}
static int
-vhost_scsi_map_iov_to_sgl(struct tcm_vhost_cmd *cmd,
- struct iovec *iov,
- int niov,
- bool write)
+vhost_scsi_calc_sgls(struct iov_iter *iter, size_t bytes, int max_sgls)
{
- struct scatterlist *sg = cmd->tvc_sgl;
- unsigned int sgl_count = 0;
- int ret, i;
+ int sgl_count = 0;
- for (i = 0; i < niov; i++)
- sgl_count += iov_num_pages(&iov[i]);
+ if (!iter || !iter->iov) {
+ pr_err("%s: iter->iov is NULL, but expected bytes: %zu"
+ " present\n", __func__, bytes);
+ return -EINVAL;
+ }
- if (sgl_count > TCM_VHOST_PREALLOC_SGLS) {
- pr_err("vhost_scsi_map_iov_to_sgl() sgl_count: %u greater than"
- " preallocated TCM_VHOST_PREALLOC_SGLS: %u\n",
- sgl_count, TCM_VHOST_PREALLOC_SGLS);
- return -ENOBUFS;
+ sgl_count = iov_iter_npages(iter, 0xffff);
+ if (sgl_count > max_sgls) {
+ pr_err("%s: requested sgl_count: %d exceeds pre-allocated"
+ " max_sgls: %d\n", __func__, sgl_count, max_sgls);
+ return -EINVAL;
}
+ return sgl_count;
+}
- pr_debug("%s sg %p sgl_count %u\n", __func__, sg, sgl_count);
- sg_init_table(sg, sgl_count);
- cmd->tvc_sgl_count = sgl_count;
+static int
+vhost_scsi_iov_to_sgl(struct vhost_scsi_cmd *cmd, bool write,
+ struct iov_iter *iter,
+ struct scatterlist *sg, int sg_count)
+{
+ size_t off = iter->iov_offset;
+ int i, ret;
- pr_debug("Mapping iovec %p for %u pages\n", &iov[0], sgl_count);
+ for (i = 0; i < iter->nr_segs; i++) {
+ void __user *base = iter->iov[i].iov_base + off;
+ size_t len = iter->iov[i].iov_len - off;
- for (i = 0; i < niov; i++) {
- ret = vhost_scsi_map_to_sgl(cmd, sg, sgl_count, &iov[i],
- cmd->tvc_upages, write);
+ ret = vhost_scsi_map_to_sgl(cmd, base, len, sg, write);
if (ret < 0) {
- for (i = 0; i < cmd->tvc_sgl_count; i++)
- put_page(sg_page(&cmd->tvc_sgl[i]));
-
- cmd->tvc_sgl_count = 0;
+ for (i = 0; i < sg_count; i++) {
+ struct page *page = sg_page(&sg[i]);
+ if (page)
+ put_page(page);
+ }
return ret;
}
sg += ret;
- sgl_count -= ret;
+ off = 0;
}
return 0;
}
static int
-vhost_scsi_map_iov_to_prot(struct tcm_vhost_cmd *cmd,
- struct iovec *iov,
- int niov,
- bool write)
-{
- struct scatterlist *prot_sg = cmd->tvc_prot_sgl;
- unsigned int prot_sgl_count = 0;
- int ret, i;
-
- for (i = 0; i < niov; i++)
- prot_sgl_count += iov_num_pages(&iov[i]);
-
- if (prot_sgl_count > TCM_VHOST_PREALLOC_PROT_SGLS) {
- pr_err("vhost_scsi_map_iov_to_prot() sgl_count: %u greater than"
- " preallocated TCM_VHOST_PREALLOC_PROT_SGLS: %u\n",
- prot_sgl_count, TCM_VHOST_PREALLOC_PROT_SGLS);
- return -ENOBUFS;
- }
-
- pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
- prot_sg, prot_sgl_count);
- sg_init_table(prot_sg, prot_sgl_count);
- cmd->tvc_prot_sgl_count = prot_sgl_count;
-
- for (i = 0; i < niov; i++) {
- ret = vhost_scsi_map_to_sgl(cmd, prot_sg, prot_sgl_count, &iov[i],
- cmd->tvc_upages, write);
+vhost_scsi_mapal(struct vhost_scsi_cmd *cmd,
+ size_t prot_bytes, struct iov_iter *prot_iter,
+ size_t data_bytes, struct iov_iter *data_iter)
+{
+ int sgl_count, ret;
+ bool write = (cmd->tvc_data_direction == DMA_FROM_DEVICE);
+
+ if (prot_bytes) {
+ sgl_count = vhost_scsi_calc_sgls(prot_iter, prot_bytes,
+ VHOST_SCSI_PREALLOC_PROT_SGLS);
+ if (sgl_count < 0)
+ return sgl_count;
+
+ sg_init_table(cmd->tvc_prot_sgl, sgl_count);
+ cmd->tvc_prot_sgl_count = sgl_count;
+ pr_debug("%s prot_sg %p prot_sgl_count %u\n", __func__,
+ cmd->tvc_prot_sgl, cmd->tvc_prot_sgl_count);
+
+ ret = vhost_scsi_iov_to_sgl(cmd, write, prot_iter,
+ cmd->tvc_prot_sgl,
+ cmd->tvc_prot_sgl_count);
if (ret < 0) {
- for (i = 0; i < cmd->tvc_prot_sgl_count; i++)
- put_page(sg_page(&cmd->tvc_prot_sgl[i]));
-
cmd->tvc_prot_sgl_count = 0;
return ret;
}
- prot_sg += ret;
- prot_sgl_count -= ret;
+ }
+ sgl_count = vhost_scsi_calc_sgls(data_iter, data_bytes,
+ VHOST_SCSI_PREALLOC_SGLS);
+ if (sgl_count < 0)
+ return sgl_count;
+
+ sg_init_table(cmd->tvc_sgl, sgl_count);
+ cmd->tvc_sgl_count = sgl_count;
+ pr_debug("%s data_sg %p data_sgl_count %u\n", __func__,
+ cmd->tvc_sgl, cmd->tvc_sgl_count);
+
+ ret = vhost_scsi_iov_to_sgl(cmd, write, data_iter,
+ cmd->tvc_sgl, cmd->tvc_sgl_count);
+ if (ret < 0) {
+ cmd->tvc_sgl_count = 0;
+ return ret;
}
return 0;
}
@@ -928,11 +938,11 @@ static int vhost_scsi_to_tcm_attr(int attr)
return TCM_SIMPLE_TAG;
}
-static void tcm_vhost_submission_work(struct work_struct *work)
+static void vhost_scsi_submission_work(struct work_struct *work)
{
- struct tcm_vhost_cmd *cmd =
- container_of(work, struct tcm_vhost_cmd, work);
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_cmd *cmd =
+ container_of(work, struct vhost_scsi_cmd, work);
+ struct vhost_scsi_nexus *tv_nexus;
struct se_cmd *se_cmd = &cmd->tvc_se_cmd;
struct scatterlist *sg_ptr, *sg_prot_ptr = NULL;
int rc;
@@ -986,19 +996,20 @@ vhost_scsi_send_bad_target(struct vhost_scsi *vs,
static void
vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
{
- struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_scsi_tpg **vs_tpg, *tpg;
struct virtio_scsi_cmd_req v_req;
struct virtio_scsi_cmd_req_pi v_req_pi;
- struct tcm_vhost_tpg *tpg;
- struct tcm_vhost_cmd *cmd;
+ struct vhost_scsi_cmd *cmd;
+ struct iov_iter out_iter, in_iter, prot_iter, data_iter;
u64 tag;
- u32 exp_data_len, data_first, data_num, data_direction, prot_first;
- unsigned out, in, i;
- int head, ret, data_niov, prot_niov, prot_bytes;
- size_t req_size;
+ u32 exp_data_len, data_direction;
+ unsigned out, in;
+ int head, ret, prot_bytes;
+ size_t req_size, rsp_size = sizeof(struct virtio_scsi_cmd_resp);
+ size_t out_size, in_size;
u16 lun;
u8 *target, *lunp, task_attr;
- bool hdr_pi;
+ bool t10_pi = vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI);
void *req, *cdb;
mutex_lock(&vq->mutex);
@@ -1014,10 +1025,10 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
for (;;) {
head = vhost_get_vq_desc(vq, vq->iov,
- ARRAY_SIZE(vq->iov), &out, &in,
- NULL, NULL);
+ ARRAY_SIZE(vq->iov), &out, &in,
+ NULL, NULL);
pr_debug("vhost_get_vq_desc: head: %d, out: %u in: %u\n",
- head, out, in);
+ head, out, in);
/* On error, stop handling until the next kick. */
if (unlikely(head < 0))
break;
@@ -1029,113 +1040,134 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
}
break;
}
-
- /* FIXME: BIDI operation */
- if (out == 1 && in == 1) {
- data_direction = DMA_NONE;
- data_first = 0;
- data_num = 0;
- } else if (out == 1 && in > 1) {
- data_direction = DMA_FROM_DEVICE;
- data_first = out + 1;
- data_num = in - 1;
- } else if (out > 1 && in == 1) {
- data_direction = DMA_TO_DEVICE;
- data_first = 1;
- data_num = out - 1;
- } else {
- vq_err(vq, "Invalid buffer layout out: %u in: %u\n",
- out, in);
- break;
- }
-
/*
- * Check for a sane resp buffer so we can report errors to
- * the guest.
+ * Check for a sane response buffer so we can report early
+ * errors back to the guest.
*/
- if (unlikely(vq->iov[out].iov_len !=
- sizeof(struct virtio_scsi_cmd_resp))) {
- vq_err(vq, "Expecting virtio_scsi_cmd_resp, got %zu"
- " bytes\n", vq->iov[out].iov_len);
+ if (unlikely(vq->iov[out].iov_len < rsp_size)) {
+ vq_err(vq, "Expecting at least virtio_scsi_cmd_resp"
+ " size, got %zu bytes\n", vq->iov[out].iov_len);
break;
}
-
- if (vhost_has_feature(vq, VIRTIO_SCSI_F_T10_PI)) {
+ /*
+ * Setup pointers and values based upon different virtio-scsi
+ * request header if T10_PI is enabled in KVM guest.
+ */
+ if (t10_pi) {
req = &v_req_pi;
+ req_size = sizeof(v_req_pi);
lunp = &v_req_pi.lun[0];
target = &v_req_pi.lun[1];
- req_size = sizeof(v_req_pi);
- hdr_pi = true;
} else {
req = &v_req;
+ req_size = sizeof(v_req);
lunp = &v_req.lun[0];
target = &v_req.lun[1];
- req_size = sizeof(v_req);
- hdr_pi = false;
}
+ /*
+ * FIXME: Not correct for BIDI operation
+ */
+ out_size = iov_length(vq->iov, out);
+ in_size = iov_length(&vq->iov[out], in);
- if (unlikely(vq->iov[0].iov_len < req_size)) {
- pr_err("Expecting virtio-scsi header: %zu, got %zu\n",
- req_size, vq->iov[0].iov_len);
- break;
- }
- ret = memcpy_fromiovecend(req, &vq->iov[0], 0, req_size);
- if (unlikely(ret)) {
- vq_err(vq, "Faulted on virtio_scsi_cmd_req\n");
- break;
- }
+ /*
+ * Copy over the virtio-scsi request header, which for a
+ * ANY_LAYOUT enabled guest may span multiple iovecs, or a
+ * single iovec may contain both the header + outgoing
+ * WRITE payloads.
+ *
+ * copy_from_iter() will advance out_iter, so that it will
+ * point at the start of the outgoing WRITE payload, if
+ * DMA_TO_DEVICE is set.
+ */
+ iov_iter_init(&out_iter, WRITE, vq->iov, out, out_size);
+ ret = copy_from_iter(req, req_size, &out_iter);
+ if (unlikely(ret != req_size)) {
+ vq_err(vq, "Faulted on copy_from_iter\n");
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
+ }
/* virtio-scsi spec requires byte 0 of the lun to be 1 */
if (unlikely(*lunp != 1)) {
+ vq_err(vq, "Illegal virtio-scsi lun: %u\n", *lunp);
vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
}
tpg = ACCESS_ONCE(vs_tpg[*target]);
-
- /* Target does not exist, fail the request */
if (unlikely(!tpg)) {
+ /* Target does not exist, fail the request */
vhost_scsi_send_bad_target(vs, vq, head, out);
continue;
}
-
- data_niov = data_num;
- prot_niov = prot_first = prot_bytes = 0;
/*
- * Determine if any protection information iovecs are preceeding
- * the actual data payload, and adjust data_first + data_niov
- * values accordingly for vhost_scsi_map_iov_to_sgl() below.
+ * Determine data_direction by calculating the total outgoing
+ * iovec sizes + incoming iovec sizes vs. virtio-scsi request +
+ * response headers respectively.
*
- * Also extract virtio_scsi header bits for vhost_scsi_get_tag()
+ * For DMA_TO_DEVICE this is out_iter, which is already pointing
+ * to the right place.
+ *
+ * For DMA_FROM_DEVICE, the iovec will be just past the end
+ * of the virtio-scsi response header in either the same
+ * or immediately following iovec.
+ *
+ * Any associated T10_PI bytes for the outgoing / incoming
+ * payloads are included in calculation of exp_data_len here.
*/
- if (hdr_pi) {
+ prot_bytes = 0;
+
+ if (out_size > req_size) {
+ data_direction = DMA_TO_DEVICE;
+ exp_data_len = out_size - req_size;
+ data_iter = out_iter;
+ } else if (in_size > rsp_size) {
+ data_direction = DMA_FROM_DEVICE;
+ exp_data_len = in_size - rsp_size;
+
+ iov_iter_init(&in_iter, READ, &vq->iov[out], in,
+ rsp_size + exp_data_len);
+ iov_iter_advance(&in_iter, rsp_size);
+ data_iter = in_iter;
+ } else {
+ data_direction = DMA_NONE;
+ exp_data_len = 0;
+ }
+ /*
+ * If T10_PI header + payload is present, setup prot_iter values
+ * and recalculate data_iter for vhost_scsi_mapal() mapping to
+ * host scatterlists via get_user_pages_fast().
+ */
+ if (t10_pi) {
if (v_req_pi.pi_bytesout) {
if (data_direction != DMA_TO_DEVICE) {
- vq_err(vq, "Received non zero do_pi_niov"
- ", but wrong data_direction\n");
- goto err_cmd;
+ vq_err(vq, "Received non zero pi_bytesout,"
+ " but wrong data_direction\n");
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
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;
+ vq_err(vq, "Received non zero pi_bytesin,"
+ " but wrong data_direction\n");
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
}
+ /*
+ * Set prot_iter to data_iter, and advance past any
+ * preceeding prot_bytes that may be present.
+ *
+ * Also fix up the exp_data_len to reflect only the
+ * actual data payload length.
+ */
if (prot_bytes) {
- int tmp = 0;
-
- for (i = 0; i < data_num; i++) {
- tmp += vq->iov[data_first + i].iov_len;
- prot_niov++;
- if (tmp >= prot_bytes)
- break;
- }
- prot_first = data_first;
- data_first += prot_niov;
- data_niov = data_num - prot_niov;
+ exp_data_len -= prot_bytes;
+ prot_iter = data_iter;
+ iov_iter_advance(&data_iter, prot_bytes);
}
tag = vhost64_to_cpu(vq, v_req_pi.tag);
task_attr = v_req_pi.task_attr;
@@ -1147,83 +1179,65 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
cdb = &v_req.cdb[0];
lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
}
- exp_data_len = 0;
- for (i = 0; i < data_niov; i++)
- exp_data_len += vq->iov[data_first + i].iov_len;
/*
- * Check that the recieved CDB size does not exceeded our
- * hardcoded max for vhost-scsi
+ * Check that the received CDB size does not exceeded our
+ * hardcoded max for vhost-scsi, then get a pre-allocated
+ * cmd descriptor for the new virtio-scsi tag.
*
* TODO what if cdb was too small for varlen cdb header?
*/
- if (unlikely(scsi_command_size(cdb) > TCM_VHOST_MAX_CDB_SIZE)) {
+ if (unlikely(scsi_command_size(cdb) > VHOST_SCSI_MAX_CDB_SIZE)) {
vq_err(vq, "Received SCSI CDB with command_size: %d that"
" exceeds SCSI_MAX_VARLEN_CDB_SIZE: %d\n",
- scsi_command_size(cdb), TCM_VHOST_MAX_CDB_SIZE);
- goto err_cmd;
+ scsi_command_size(cdb), VHOST_SCSI_MAX_CDB_SIZE);
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
-
cmd = vhost_scsi_get_tag(vq, tpg, cdb, tag, lun, task_attr,
exp_data_len + prot_bytes,
data_direction);
if (IS_ERR(cmd)) {
vq_err(vq, "vhost_scsi_get_tag failed %ld\n",
- PTR_ERR(cmd));
- goto err_cmd;
+ PTR_ERR(cmd));
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
-
- pr_debug("Allocated tv_cmd: %p exp_data_len: %d, data_direction"
- ": %d\n", cmd, exp_data_len, data_direction);
-
cmd->tvc_vhost = vs;
cmd->tvc_vq = vq;
- cmd->tvc_resp = vq->iov[out].iov_base;
+ cmd->tvc_resp_iov = &vq->iov[out];
+ cmd->tvc_in_iovs = in;
pr_debug("vhost_scsi got command opcode: %#02x, lun: %d\n",
- cmd->tvc_cdb[0], cmd->tvc_lun);
+ cmd->tvc_cdb[0], cmd->tvc_lun);
+ pr_debug("cmd: %p exp_data_len: %d, prot_bytes: %d data_direction:"
+ " %d\n", cmd, exp_data_len, prot_bytes, data_direction);
- if (prot_niov) {
- ret = vhost_scsi_map_iov_to_prot(cmd,
- &vq->iov[prot_first], prot_niov,
- data_direction == DMA_FROM_DEVICE);
- if (unlikely(ret)) {
- vq_err(vq, "Failed to map iov to"
- " prot_sgl\n");
- goto err_free;
- }
- }
if (data_direction != DMA_NONE) {
- ret = vhost_scsi_map_iov_to_sgl(cmd,
- &vq->iov[data_first], data_niov,
- data_direction == DMA_FROM_DEVICE);
+ ret = vhost_scsi_mapal(cmd,
+ prot_bytes, &prot_iter,
+ exp_data_len, &data_iter);
if (unlikely(ret)) {
vq_err(vq, "Failed to map iov to sgl\n");
- goto err_free;
+ vhost_scsi_release_cmd(&cmd->tvc_se_cmd);
+ vhost_scsi_send_bad_target(vs, vq, head, out);
+ continue;
}
}
/*
* Save the descriptor from vhost_get_vq_desc() to be used to
* complete the virtio-scsi request in TCM callback context via
- * tcm_vhost_queue_data_in() and tcm_vhost_queue_status()
+ * vhost_scsi_queue_data_in() and vhost_scsi_queue_status()
*/
cmd->tvc_vq_desc = head;
/*
- * Dispatch tv_cmd descriptor for cmwq execution in process
- * context provided by tcm_vhost_workqueue. This also ensures
- * tv_cmd is executed on the same kworker CPU as this vhost
- * thread to gain positive L2 cache locality effects..
+ * Dispatch cmd descriptor for cmwq execution in process
+ * context provided by vhost_scsi_workqueue. This also ensures
+ * cmd is executed on the same kworker CPU as this vhost
+ * thread to gain positive L2 cache locality effects.
*/
- INIT_WORK(&cmd->work, tcm_vhost_submission_work);
- queue_work(tcm_vhost_workqueue, &cmd->work);
+ INIT_WORK(&cmd->work, vhost_scsi_submission_work);
+ queue_work(vhost_scsi_workqueue, &cmd->work);
}
-
- mutex_unlock(&vq->mutex);
- return;
-
-err_free:
- vhost_scsi_free_cmd(cmd);
-err_cmd:
- vhost_scsi_send_bad_target(vs, vq, head, out);
out:
mutex_unlock(&vq->mutex);
}
@@ -1234,15 +1248,15 @@ static void vhost_scsi_ctl_handle_kick(struct vhost_work *work)
}
static void
-tcm_vhost_send_evt(struct vhost_scsi *vs,
- struct tcm_vhost_tpg *tpg,
+vhost_scsi_send_evt(struct vhost_scsi *vs,
+ struct vhost_scsi_tpg *tpg,
struct se_lun *lun,
u32 event,
u32 reason)
{
- struct tcm_vhost_evt *evt;
+ struct vhost_scsi_evt *evt;
- evt = tcm_vhost_allocate_evt(vs, event, reason);
+ evt = vhost_scsi_allocate_evt(vs, event, reason);
if (!evt)
return;
@@ -1253,7 +1267,7 @@ tcm_vhost_send_evt(struct vhost_scsi *vs,
* lun[4-7] need to be zero according to virtio-scsi spec.
*/
evt->event.lun[0] = 0x01;
- evt->event.lun[1] = tpg->tport_tpgt & 0xFF;
+ evt->event.lun[1] = tpg->tport_tpgt;
if (lun->unpacked_lun >= 256)
evt->event.lun[2] = lun->unpacked_lun >> 8 | 0x40 ;
evt->event.lun[3] = lun->unpacked_lun & 0xFF;
@@ -1274,7 +1288,7 @@ static void vhost_scsi_evt_handle_kick(struct vhost_work *work)
goto out;
if (vs->vs_events_missed)
- tcm_vhost_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
+ vhost_scsi_send_evt(vs, NULL, NULL, VIRTIO_SCSI_T_NO_EVENT, 0);
out:
mutex_unlock(&vq->mutex);
}
@@ -1300,7 +1314,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
int i;
/* Init new inflight and remember the old inflight */
- tcm_vhost_init_inflight(vs, old_inflight);
+ vhost_scsi_init_inflight(vs, old_inflight);
/*
* The inflight->kref was initialized to 1. We decrement it here to
@@ -1308,7 +1322,7 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
* when all the reqs are finished.
*/
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
- kref_put(&old_inflight[i]->kref, tcm_vhost_done_inflight);
+ kref_put(&old_inflight[i]->kref, vhost_scsi_done_inflight);
/* Flush both the vhost poll and vhost work */
for (i = 0; i < VHOST_SCSI_MAX_VQ; i++)
@@ -1323,24 +1337,24 @@ static void vhost_scsi_flush(struct vhost_scsi *vs)
/*
* Called from vhost_scsi_ioctl() context to walk the list of available
- * tcm_vhost_tpg with an active struct tcm_vhost_nexus
+ * vhost_scsi_tpg with an active struct vhost_scsi_nexus
*
* The lock nesting rule is:
- * tcm_vhost_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
+ * vhost_scsi_mutex -> vs->dev.mutex -> tpg->tv_tpg_mutex -> vq->mutex
*/
static int
vhost_scsi_set_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
struct se_portal_group *se_tpg;
- struct tcm_vhost_tport *tv_tport;
- struct tcm_vhost_tpg *tpg;
- struct tcm_vhost_tpg **vs_tpg;
+ struct vhost_scsi_tport *tv_tport;
+ struct vhost_scsi_tpg *tpg;
+ struct vhost_scsi_tpg **vs_tpg;
struct vhost_virtqueue *vq;
int index, ret, i, len;
bool match = false;
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&vs->dev.mutex);
/* Verify that ring has been setup correctly. */
@@ -1361,7 +1375,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
if (vs->vs_tpg)
memcpy(vs_tpg, vs->vs_tpg, len);
- list_for_each_entry(tpg, &tcm_vhost_list, tv_tpg_list) {
+ list_for_each_entry(tpg, &vhost_scsi_list, tv_tpg_list) {
mutex_lock(&tpg->tv_tpg_mutex);
if (!tpg->tpg_nexus) {
mutex_unlock(&tpg->tv_tpg_mutex);
@@ -1429,7 +1443,7 @@ vhost_scsi_set_endpoint(struct vhost_scsi *vs,
out:
mutex_unlock(&vs->dev.mutex);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return ret;
}
@@ -1438,14 +1452,14 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
struct vhost_scsi_target *t)
{
struct se_portal_group *se_tpg;
- struct tcm_vhost_tport *tv_tport;
- struct tcm_vhost_tpg *tpg;
+ struct vhost_scsi_tport *tv_tport;
+ struct vhost_scsi_tpg *tpg;
struct vhost_virtqueue *vq;
bool match = false;
int index, ret, i;
u8 target;
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&vs->dev.mutex);
/* Verify that ring has been setup correctly. */
for (index = 0; index < vs->dev.nvqs; ++index) {
@@ -1511,14 +1525,14 @@ vhost_scsi_clear_endpoint(struct vhost_scsi *vs,
vs->vs_tpg = NULL;
WARN_ON(vs->vs_events_nr);
mutex_unlock(&vs->dev.mutex);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return 0;
err_tpg:
mutex_unlock(&tpg->tv_tpg_mutex);
err_dev:
mutex_unlock(&vs->dev.mutex);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return ret;
}
@@ -1565,7 +1579,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
goto err_vqs;
vhost_work_init(&vs->vs_completion_work, vhost_scsi_complete_cmd_work);
- vhost_work_init(&vs->vs_event_work, tcm_vhost_evt_work);
+ vhost_work_init(&vs->vs_event_work, vhost_scsi_evt_work);
vs->vs_events_nr = 0;
vs->vs_events_missed = false;
@@ -1580,7 +1594,7 @@ static int vhost_scsi_open(struct inode *inode, struct file *f)
}
vhost_dev_init(&vs->dev, vqs, VHOST_SCSI_MAX_VQ);
- tcm_vhost_init_inflight(vs, NULL);
+ vhost_scsi_init_inflight(vs, NULL);
f->private_data = vs;
return 0;
@@ -1712,7 +1726,7 @@ static int vhost_scsi_deregister(void)
return misc_deregister(&vhost_scsi_misc);
}
-static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
+static char *vhost_scsi_dump_proto_id(struct vhost_scsi_tport *tport)
{
switch (tport->tport_proto_id) {
case SCSI_PROTOCOL_SAS:
@@ -1729,7 +1743,7 @@ static char *tcm_vhost_dump_proto_id(struct tcm_vhost_tport *tport)
}
static void
-tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
+vhost_scsi_do_plug(struct vhost_scsi_tpg *tpg,
struct se_lun *lun, bool plug)
{
@@ -1750,71 +1764,71 @@ tcm_vhost_do_plug(struct tcm_vhost_tpg *tpg,
vq = &vs->vqs[VHOST_SCSI_VQ_EVT].vq;
mutex_lock(&vq->mutex);
if (vhost_has_feature(vq, VIRTIO_SCSI_F_HOTPLUG))
- tcm_vhost_send_evt(vs, tpg, lun,
+ vhost_scsi_send_evt(vs, tpg, lun,
VIRTIO_SCSI_T_TRANSPORT_RESET, reason);
mutex_unlock(&vq->mutex);
mutex_unlock(&vs->dev.mutex);
}
-static void tcm_vhost_hotplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
+static void vhost_scsi_hotplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
{
- tcm_vhost_do_plug(tpg, lun, true);
+ vhost_scsi_do_plug(tpg, lun, true);
}
-static void tcm_vhost_hotunplug(struct tcm_vhost_tpg *tpg, struct se_lun *lun)
+static void vhost_scsi_hotunplug(struct vhost_scsi_tpg *tpg, struct se_lun *lun)
{
- tcm_vhost_do_plug(tpg, lun, false);
+ vhost_scsi_do_plug(tpg, lun, false);
}
-static int tcm_vhost_port_link(struct se_portal_group *se_tpg,
+static int vhost_scsi_port_link(struct se_portal_group *se_tpg,
struct se_lun *lun)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&tpg->tv_tpg_mutex);
tpg->tv_tpg_port_count++;
mutex_unlock(&tpg->tv_tpg_mutex);
- tcm_vhost_hotplug(tpg, lun);
+ vhost_scsi_hotplug(tpg, lun);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
return 0;
}
-static void tcm_vhost_port_unlink(struct se_portal_group *se_tpg,
+static void vhost_scsi_port_unlink(struct se_portal_group *se_tpg,
struct se_lun *lun)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
mutex_lock(&tpg->tv_tpg_mutex);
tpg->tv_tpg_port_count--;
mutex_unlock(&tpg->tv_tpg_mutex);
- tcm_vhost_hotunplug(tpg, lun);
+ vhost_scsi_hotunplug(tpg, lun);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
}
static struct se_node_acl *
-tcm_vhost_make_nodeacl(struct se_portal_group *se_tpg,
+vhost_scsi_make_nodeacl(struct se_portal_group *se_tpg,
struct config_group *group,
const char *name)
{
struct se_node_acl *se_nacl, *se_nacl_new;
- struct tcm_vhost_nacl *nacl;
+ struct vhost_scsi_nacl *nacl;
u64 wwpn = 0;
u32 nexus_depth;
- /* tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+ /* vhost_scsi_parse_wwn(name, &wwpn, 1) < 0)
return ERR_PTR(-EINVAL); */
- se_nacl_new = tcm_vhost_alloc_fabric_acl(se_tpg);
+ se_nacl_new = vhost_scsi_alloc_fabric_acl(se_tpg);
if (!se_nacl_new)
return ERR_PTR(-ENOMEM);
@@ -1826,37 +1840,37 @@ tcm_vhost_make_nodeacl(struct se_portal_group *se_tpg,
se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new,
name, nexus_depth);
if (IS_ERR(se_nacl)) {
- tcm_vhost_release_fabric_acl(se_tpg, se_nacl_new);
+ vhost_scsi_release_fabric_acl(se_tpg, se_nacl_new);
return se_nacl;
}
/*
- * Locate our struct tcm_vhost_nacl and set the FC Nport WWPN
+ * Locate our struct vhost_scsi_nacl and set the FC Nport WWPN
*/
- nacl = container_of(se_nacl, struct tcm_vhost_nacl, se_node_acl);
+ nacl = container_of(se_nacl, struct vhost_scsi_nacl, se_node_acl);
nacl->iport_wwpn = wwpn;
return se_nacl;
}
-static void tcm_vhost_drop_nodeacl(struct se_node_acl *se_acl)
+static void vhost_scsi_drop_nodeacl(struct se_node_acl *se_acl)
{
- struct tcm_vhost_nacl *nacl = container_of(se_acl,
- struct tcm_vhost_nacl, se_node_acl);
+ struct vhost_scsi_nacl *nacl = container_of(se_acl,
+ struct vhost_scsi_nacl, se_node_acl);
core_tpg_del_initiator_node_acl(se_acl->se_tpg, se_acl, 1);
kfree(nacl);
}
-static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus,
+static void vhost_scsi_free_cmd_map_res(struct vhost_scsi_nexus *nexus,
struct se_session *se_sess)
{
- struct tcm_vhost_cmd *tv_cmd;
+ struct vhost_scsi_cmd *tv_cmd;
unsigned int i;
if (!se_sess->sess_cmd_map)
return;
- for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
- tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
+ for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) {
+ tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i];
kfree(tv_cmd->tvc_sgl);
kfree(tv_cmd->tvc_prot_sgl);
@@ -1864,13 +1878,13 @@ static void tcm_vhost_free_cmd_map_res(struct tcm_vhost_nexus *nexus,
}
}
-static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
+static int vhost_scsi_make_nexus(struct vhost_scsi_tpg *tpg,
const char *name)
{
struct se_portal_group *se_tpg;
struct se_session *se_sess;
- struct tcm_vhost_nexus *tv_nexus;
- struct tcm_vhost_cmd *tv_cmd;
+ struct vhost_scsi_nexus *tv_nexus;
+ struct vhost_scsi_cmd *tv_cmd;
unsigned int i;
mutex_lock(&tpg->tv_tpg_mutex);
@@ -1881,19 +1895,19 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
}
se_tpg = &tpg->se_tpg;
- tv_nexus = kzalloc(sizeof(struct tcm_vhost_nexus), GFP_KERNEL);
+ tv_nexus = kzalloc(sizeof(struct vhost_scsi_nexus), GFP_KERNEL);
if (!tv_nexus) {
mutex_unlock(&tpg->tv_tpg_mutex);
- pr_err("Unable to allocate struct tcm_vhost_nexus\n");
+ pr_err("Unable to allocate struct vhost_scsi_nexus\n");
return -ENOMEM;
}
/*
* Initialize the struct se_session pointer and setup tagpool
- * for struct tcm_vhost_cmd descriptors
+ * for struct vhost_scsi_cmd descriptors
*/
tv_nexus->tvn_se_sess = transport_init_session_tags(
- TCM_VHOST_DEFAULT_TAGS,
- sizeof(struct tcm_vhost_cmd),
+ VHOST_SCSI_DEFAULT_TAGS,
+ sizeof(struct vhost_scsi_cmd),
TARGET_PROT_DIN_PASS | TARGET_PROT_DOUT_PASS);
if (IS_ERR(tv_nexus->tvn_se_sess)) {
mutex_unlock(&tpg->tv_tpg_mutex);
@@ -1901,11 +1915,11 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
return -ENOMEM;
}
se_sess = tv_nexus->tvn_se_sess;
- for (i = 0; i < TCM_VHOST_DEFAULT_TAGS; i++) {
- tv_cmd = &((struct tcm_vhost_cmd *)se_sess->sess_cmd_map)[i];
+ for (i = 0; i < VHOST_SCSI_DEFAULT_TAGS; i++) {
+ tv_cmd = &((struct vhost_scsi_cmd *)se_sess->sess_cmd_map)[i];
tv_cmd->tvc_sgl = kzalloc(sizeof(struct scatterlist) *
- TCM_VHOST_PREALLOC_SGLS, GFP_KERNEL);
+ VHOST_SCSI_PREALLOC_SGLS, GFP_KERNEL);
if (!tv_cmd->tvc_sgl) {
mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate tv_cmd->tvc_sgl\n");
@@ -1913,7 +1927,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
}
tv_cmd->tvc_upages = kzalloc(sizeof(struct page *) *
- TCM_VHOST_PREALLOC_UPAGES, GFP_KERNEL);
+ VHOST_SCSI_PREALLOC_UPAGES, GFP_KERNEL);
if (!tv_cmd->tvc_upages) {
mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate tv_cmd->tvc_upages\n");
@@ -1921,7 +1935,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
}
tv_cmd->tvc_prot_sgl = kzalloc(sizeof(struct scatterlist) *
- TCM_VHOST_PREALLOC_PROT_SGLS, GFP_KERNEL);
+ VHOST_SCSI_PREALLOC_PROT_SGLS, GFP_KERNEL);
if (!tv_cmd->tvc_prot_sgl) {
mutex_unlock(&tpg->tv_tpg_mutex);
pr_err("Unable to allocate tv_cmd->tvc_prot_sgl\n");
@@ -1930,7 +1944,7 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
}
/*
* Since we are running in 'demo mode' this call with generate a
- * struct se_node_acl for the tcm_vhost struct se_portal_group with
+ * struct se_node_acl for the vhost_scsi struct se_portal_group with
* the SCSI Initiator port name of the passed configfs group 'name'.
*/
tv_nexus->tvn_se_sess->se_node_acl = core_tpg_check_initiator_node_acl(
@@ -1953,16 +1967,16 @@ static int tcm_vhost_make_nexus(struct tcm_vhost_tpg *tpg,
return 0;
out:
- tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
+ vhost_scsi_free_cmd_map_res(tv_nexus, se_sess);
transport_free_session(se_sess);
kfree(tv_nexus);
return -ENOMEM;
}
-static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
+static int vhost_scsi_drop_nexus(struct vhost_scsi_tpg *tpg)
{
struct se_session *se_sess;
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_nexus *tv_nexus;
mutex_lock(&tpg->tv_tpg_mutex);
tv_nexus = tpg->tpg_nexus;
@@ -1994,10 +2008,10 @@ static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
}
pr_debug("TCM_vhost_ConfigFS: Removing I_T Nexus to emulated"
- " %s Initiator Port: %s\n", tcm_vhost_dump_proto_id(tpg->tport),
+ " %s Initiator Port: %s\n", vhost_scsi_dump_proto_id(tpg->tport),
tv_nexus->tvn_se_sess->se_node_acl->initiatorname);
- tcm_vhost_free_cmd_map_res(tv_nexus, se_sess);
+ vhost_scsi_free_cmd_map_res(tv_nexus, se_sess);
/*
* Release the SCSI I_T Nexus to the emulated vhost Target Port
*/
@@ -2009,12 +2023,12 @@ static int tcm_vhost_drop_nexus(struct tcm_vhost_tpg *tpg)
return 0;
}
-static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg,
+static ssize_t vhost_scsi_tpg_show_nexus(struct se_portal_group *se_tpg,
char *page)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_nexus *tv_nexus;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_nexus *tv_nexus;
ssize_t ret;
mutex_lock(&tpg->tv_tpg_mutex);
@@ -2030,40 +2044,40 @@ static ssize_t tcm_vhost_tpg_show_nexus(struct se_portal_group *se_tpg,
return ret;
}
-static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
+static ssize_t vhost_scsi_tpg_store_nexus(struct se_portal_group *se_tpg,
const char *page,
size_t count)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
- struct tcm_vhost_tport *tport_wwn = tpg->tport;
- unsigned char i_port[TCM_VHOST_NAMELEN], *ptr, *port_ptr;
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
+ struct vhost_scsi_tport *tport_wwn = tpg->tport;
+ unsigned char i_port[VHOST_SCSI_NAMELEN], *ptr, *port_ptr;
int ret;
/*
* Shutdown the active I_T nexus if 'NULL' is passed..
*/
if (!strncmp(page, "NULL", 4)) {
- ret = tcm_vhost_drop_nexus(tpg);
+ ret = vhost_scsi_drop_nexus(tpg);
return (!ret) ? count : ret;
}
/*
* Otherwise make sure the passed virtual Initiator port WWN matches
- * the fabric protocol_id set in tcm_vhost_make_tport(), and call
- * tcm_vhost_make_nexus().
+ * the fabric protocol_id set in vhost_scsi_make_tport(), and call
+ * vhost_scsi_make_nexus().
*/
- if (strlen(page) >= TCM_VHOST_NAMELEN) {
+ if (strlen(page) >= VHOST_SCSI_NAMELEN) {
pr_err("Emulated NAA Sas Address: %s, exceeds"
- " max: %d\n", page, TCM_VHOST_NAMELEN);
+ " max: %d\n", page, VHOST_SCSI_NAMELEN);
return -EINVAL;
}
- snprintf(&i_port[0], TCM_VHOST_NAMELEN, "%s", page);
+ snprintf(&i_port[0], VHOST_SCSI_NAMELEN, "%s", page);
ptr = strstr(i_port, "naa.");
if (ptr) {
if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_SAS) {
pr_err("Passed SAS Initiator Port %s does not"
" match target port protoid: %s\n", i_port,
- tcm_vhost_dump_proto_id(tport_wwn));
+ vhost_scsi_dump_proto_id(tport_wwn));
return -EINVAL;
}
port_ptr = &i_port[0];
@@ -2074,7 +2088,7 @@ static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_FCP) {
pr_err("Passed FCP Initiator Port %s does not"
" match target port protoid: %s\n", i_port,
- tcm_vhost_dump_proto_id(tport_wwn));
+ vhost_scsi_dump_proto_id(tport_wwn));
return -EINVAL;
}
port_ptr = &i_port[3]; /* Skip over "fc." */
@@ -2085,7 +2099,7 @@ static ssize_t tcm_vhost_tpg_store_nexus(struct se_portal_group *se_tpg,
if (tport_wwn->tport_proto_id != SCSI_PROTOCOL_ISCSI) {
pr_err("Passed iSCSI Initiator Port %s does not"
" match target port protoid: %s\n", i_port,
- tcm_vhost_dump_proto_id(tport_wwn));
+ vhost_scsi_dump_proto_id(tport_wwn));
return -EINVAL;
}
port_ptr = &i_port[0];
@@ -2101,40 +2115,40 @@ check_newline:
if (i_port[strlen(i_port)-1] == '\n')
i_port[strlen(i_port)-1] = '\0';
- ret = tcm_vhost_make_nexus(tpg, port_ptr);
+ ret = vhost_scsi_make_nexus(tpg, port_ptr);
if (ret < 0)
return ret;
return count;
}
-TF_TPG_BASE_ATTR(tcm_vhost, nexus, S_IRUGO | S_IWUSR);
+TF_TPG_BASE_ATTR(vhost_scsi, nexus, S_IRUGO | S_IWUSR);
-static struct configfs_attribute *tcm_vhost_tpg_attrs[] = {
- &tcm_vhost_tpg_nexus.attr,
+static struct configfs_attribute *vhost_scsi_tpg_attrs[] = {
+ &vhost_scsi_tpg_nexus.attr,
NULL,
};
static struct se_portal_group *
-tcm_vhost_make_tpg(struct se_wwn *wwn,
+vhost_scsi_make_tpg(struct se_wwn *wwn,
struct config_group *group,
const char *name)
{
- struct tcm_vhost_tport *tport = container_of(wwn,
- struct tcm_vhost_tport, tport_wwn);
+ struct vhost_scsi_tport *tport = container_of(wwn,
+ struct vhost_scsi_tport, tport_wwn);
- struct tcm_vhost_tpg *tpg;
- unsigned long tpgt;
+ struct vhost_scsi_tpg *tpg;
+ u16 tpgt;
int ret;
if (strstr(name, "tpgt_") != name)
return ERR_PTR(-EINVAL);
- if (kstrtoul(name + 5, 10, &tpgt) || tpgt > UINT_MAX)
+ if (kstrtou16(name + 5, 10, &tpgt) || tpgt >= VHOST_SCSI_MAX_TARGET)
return ERR_PTR(-EINVAL);
- tpg = kzalloc(sizeof(struct tcm_vhost_tpg), GFP_KERNEL);
+ tpg = kzalloc(sizeof(struct vhost_scsi_tpg), GFP_KERNEL);
if (!tpg) {
- pr_err("Unable to allocate struct tcm_vhost_tpg");
+ pr_err("Unable to allocate struct vhost_scsi_tpg");
return ERR_PTR(-ENOMEM);
}
mutex_init(&tpg->tv_tpg_mutex);
@@ -2142,31 +2156,31 @@ tcm_vhost_make_tpg(struct se_wwn *wwn,
tpg->tport = tport;
tpg->tport_tpgt = tpgt;
- ret = core_tpg_register(&tcm_vhost_fabric_configfs->tf_ops, wwn,
+ ret = core_tpg_register(&vhost_scsi_fabric_configfs->tf_ops, wwn,
&tpg->se_tpg, tpg, TRANSPORT_TPG_TYPE_NORMAL);
if (ret < 0) {
kfree(tpg);
return NULL;
}
- mutex_lock(&tcm_vhost_mutex);
- list_add_tail(&tpg->tv_tpg_list, &tcm_vhost_list);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
+ list_add_tail(&tpg->tv_tpg_list, &vhost_scsi_list);
+ mutex_unlock(&vhost_scsi_mutex);
return &tpg->se_tpg;
}
-static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
+static void vhost_scsi_drop_tpg(struct se_portal_group *se_tpg)
{
- struct tcm_vhost_tpg *tpg = container_of(se_tpg,
- struct tcm_vhost_tpg, se_tpg);
+ struct vhost_scsi_tpg *tpg = container_of(se_tpg,
+ struct vhost_scsi_tpg, se_tpg);
- mutex_lock(&tcm_vhost_mutex);
+ mutex_lock(&vhost_scsi_mutex);
list_del(&tpg->tv_tpg_list);
- mutex_unlock(&tcm_vhost_mutex);
+ mutex_unlock(&vhost_scsi_mutex);
/*
* Release the virtual I_T Nexus for this vhost TPG
*/
- tcm_vhost_drop_nexus(tpg);
+ vhost_scsi_drop_nexus(tpg);
/*
* Deregister the se_tpg from TCM..
*/
@@ -2175,21 +2189,21 @@ static void tcm_vhost_drop_tpg(struct se_portal_group *se_tpg)
}
static struct se_wwn *
-tcm_vhost_make_tport(struct target_fabric_configfs *tf,
+vhost_scsi_make_tport(struct target_fabric_configfs *tf,
struct config_group *group,
const char *name)
{
- struct tcm_vhost_tport *tport;
+ struct vhost_scsi_tport *tport;
char *ptr;
u64 wwpn = 0;
int off = 0;
- /* if (tcm_vhost_parse_wwn(name, &wwpn, 1) < 0)
+ /* if (vhost_scsi_parse_wwn(name, &wwpn, 1) < 0)
return ERR_PTR(-EINVAL); */
- tport = kzalloc(sizeof(struct tcm_vhost_tport), GFP_KERNEL);
+ tport = kzalloc(sizeof(struct vhost_scsi_tport), GFP_KERNEL);
if (!tport) {
- pr_err("Unable to allocate struct tcm_vhost_tport");
+ pr_err("Unable to allocate struct vhost_scsi_tport");
return ERR_PTR(-ENOMEM);
}
tport->tport_wwpn = wwpn;
@@ -2220,102 +2234,102 @@ tcm_vhost_make_tport(struct target_fabric_configfs *tf,
return ERR_PTR(-EINVAL);
check_len:
- if (strlen(name) >= TCM_VHOST_NAMELEN) {
+ if (strlen(name) >= VHOST_SCSI_NAMELEN) {
pr_err("Emulated %s Address: %s, exceeds"
- " max: %d\n", name, tcm_vhost_dump_proto_id(tport),
- TCM_VHOST_NAMELEN);
+ " max: %d\n", name, vhost_scsi_dump_proto_id(tport),
+ VHOST_SCSI_NAMELEN);
kfree(tport);
return ERR_PTR(-EINVAL);
}
- snprintf(&tport->tport_name[0], TCM_VHOST_NAMELEN, "%s", &name[off]);
+ snprintf(&tport->tport_name[0], VHOST_SCSI_NAMELEN, "%s", &name[off]);
pr_debug("TCM_VHost_ConfigFS: Allocated emulated Target"
- " %s Address: %s\n", tcm_vhost_dump_proto_id(tport), name);
+ " %s Address: %s\n", vhost_scsi_dump_proto_id(tport), name);
return &tport->tport_wwn;
}
-static void tcm_vhost_drop_tport(struct se_wwn *wwn)
+static void vhost_scsi_drop_tport(struct se_wwn *wwn)
{
- struct tcm_vhost_tport *tport = container_of(wwn,
- struct tcm_vhost_tport, tport_wwn);
+ struct vhost_scsi_tport *tport = container_of(wwn,
+ struct vhost_scsi_tport, tport_wwn);
pr_debug("TCM_VHost_ConfigFS: Deallocating emulated Target"
- " %s Address: %s\n", tcm_vhost_dump_proto_id(tport),
+ " %s Address: %s\n", vhost_scsi_dump_proto_id(tport),
tport->tport_name);
kfree(tport);
}
static ssize_t
-tcm_vhost_wwn_show_attr_version(struct target_fabric_configfs *tf,
+vhost_scsi_wwn_show_attr_version(struct target_fabric_configfs *tf,
char *page)
{
return sprintf(page, "TCM_VHOST fabric module %s on %s/%s"
- "on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+ "on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
}
-TF_WWN_ATTR_RO(tcm_vhost, version);
+TF_WWN_ATTR_RO(vhost_scsi, version);
-static struct configfs_attribute *tcm_vhost_wwn_attrs[] = {
- &tcm_vhost_wwn_version.attr,
+static struct configfs_attribute *vhost_scsi_wwn_attrs[] = {
+ &vhost_scsi_wwn_version.attr,
NULL,
};
-static struct target_core_fabric_ops tcm_vhost_ops = {
- .get_fabric_name = tcm_vhost_get_fabric_name,
- .get_fabric_proto_ident = tcm_vhost_get_fabric_proto_ident,
- .tpg_get_wwn = tcm_vhost_get_fabric_wwn,
- .tpg_get_tag = tcm_vhost_get_tag,
- .tpg_get_default_depth = tcm_vhost_get_default_depth,
- .tpg_get_pr_transport_id = tcm_vhost_get_pr_transport_id,
- .tpg_get_pr_transport_id_len = tcm_vhost_get_pr_transport_id_len,
- .tpg_parse_pr_out_transport_id = tcm_vhost_parse_pr_out_transport_id,
- .tpg_check_demo_mode = tcm_vhost_check_true,
- .tpg_check_demo_mode_cache = tcm_vhost_check_true,
- .tpg_check_demo_mode_write_protect = tcm_vhost_check_false,
- .tpg_check_prod_mode_write_protect = tcm_vhost_check_false,
- .tpg_alloc_fabric_acl = tcm_vhost_alloc_fabric_acl,
- .tpg_release_fabric_acl = tcm_vhost_release_fabric_acl,
- .tpg_get_inst_index = tcm_vhost_tpg_get_inst_index,
- .release_cmd = tcm_vhost_release_cmd,
+static struct target_core_fabric_ops vhost_scsi_ops = {
+ .get_fabric_name = vhost_scsi_get_fabric_name,
+ .get_fabric_proto_ident = vhost_scsi_get_fabric_proto_ident,
+ .tpg_get_wwn = vhost_scsi_get_fabric_wwn,
+ .tpg_get_tag = vhost_scsi_get_tpgt,
+ .tpg_get_default_depth = vhost_scsi_get_default_depth,
+ .tpg_get_pr_transport_id = vhost_scsi_get_pr_transport_id,
+ .tpg_get_pr_transport_id_len = vhost_scsi_get_pr_transport_id_len,
+ .tpg_parse_pr_out_transport_id = vhost_scsi_parse_pr_out_transport_id,
+ .tpg_check_demo_mode = vhost_scsi_check_true,
+ .tpg_check_demo_mode_cache = vhost_scsi_check_true,
+ .tpg_check_demo_mode_write_protect = vhost_scsi_check_false,
+ .tpg_check_prod_mode_write_protect = vhost_scsi_check_false,
+ .tpg_alloc_fabric_acl = vhost_scsi_alloc_fabric_acl,
+ .tpg_release_fabric_acl = vhost_scsi_release_fabric_acl,
+ .tpg_get_inst_index = vhost_scsi_tpg_get_inst_index,
+ .release_cmd = vhost_scsi_release_cmd,
.check_stop_free = vhost_scsi_check_stop_free,
- .shutdown_session = tcm_vhost_shutdown_session,
- .close_session = tcm_vhost_close_session,
- .sess_get_index = tcm_vhost_sess_get_index,
+ .shutdown_session = vhost_scsi_shutdown_session,
+ .close_session = vhost_scsi_close_session,
+ .sess_get_index = vhost_scsi_sess_get_index,
.sess_get_initiator_sid = NULL,
- .write_pending = tcm_vhost_write_pending,
- .write_pending_status = tcm_vhost_write_pending_status,
- .set_default_node_attributes = tcm_vhost_set_default_node_attrs,
- .get_task_tag = tcm_vhost_get_task_tag,
- .get_cmd_state = tcm_vhost_get_cmd_state,
- .queue_data_in = tcm_vhost_queue_data_in,
- .queue_status = tcm_vhost_queue_status,
- .queue_tm_rsp = tcm_vhost_queue_tm_rsp,
- .aborted_task = tcm_vhost_aborted_task,
+ .write_pending = vhost_scsi_write_pending,
+ .write_pending_status = vhost_scsi_write_pending_status,
+ .set_default_node_attributes = vhost_scsi_set_default_node_attrs,
+ .get_task_tag = vhost_scsi_get_task_tag,
+ .get_cmd_state = vhost_scsi_get_cmd_state,
+ .queue_data_in = vhost_scsi_queue_data_in,
+ .queue_status = vhost_scsi_queue_status,
+ .queue_tm_rsp = vhost_scsi_queue_tm_rsp,
+ .aborted_task = vhost_scsi_aborted_task,
/*
* Setup callers for generic logic in target_core_fabric_configfs.c
*/
- .fabric_make_wwn = tcm_vhost_make_tport,
- .fabric_drop_wwn = tcm_vhost_drop_tport,
- .fabric_make_tpg = tcm_vhost_make_tpg,
- .fabric_drop_tpg = tcm_vhost_drop_tpg,
- .fabric_post_link = tcm_vhost_port_link,
- .fabric_pre_unlink = tcm_vhost_port_unlink,
+ .fabric_make_wwn = vhost_scsi_make_tport,
+ .fabric_drop_wwn = vhost_scsi_drop_tport,
+ .fabric_make_tpg = vhost_scsi_make_tpg,
+ .fabric_drop_tpg = vhost_scsi_drop_tpg,
+ .fabric_post_link = vhost_scsi_port_link,
+ .fabric_pre_unlink = vhost_scsi_port_unlink,
.fabric_make_np = NULL,
.fabric_drop_np = NULL,
- .fabric_make_nodeacl = tcm_vhost_make_nodeacl,
- .fabric_drop_nodeacl = tcm_vhost_drop_nodeacl,
+ .fabric_make_nodeacl = vhost_scsi_make_nodeacl,
+ .fabric_drop_nodeacl = vhost_scsi_drop_nodeacl,
};
-static int tcm_vhost_register_configfs(void)
+static int vhost_scsi_register_configfs(void)
{
struct target_fabric_configfs *fabric;
int ret;
- pr_debug("TCM_VHOST fabric module %s on %s/%s"
- " on "UTS_RELEASE"\n", TCM_VHOST_VERSION, utsname()->sysname,
+ pr_debug("vhost-scsi fabric module %s on %s/%s"
+ " on "UTS_RELEASE"\n", VHOST_SCSI_VERSION, utsname()->sysname,
utsname()->machine);
/*
* Register the top level struct config_item_type with TCM core
@@ -2326,14 +2340,14 @@ static int tcm_vhost_register_configfs(void)
return PTR_ERR(fabric);
}
/*
- * Setup fabric->tf_ops from our local tcm_vhost_ops
+ * Setup fabric->tf_ops from our local vhost_scsi_ops
*/
- fabric->tf_ops = tcm_vhost_ops;
+ fabric->tf_ops = vhost_scsi_ops;
/*
* Setup default attribute lists for various fabric->tf_cit_tmpl
*/
- fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = tcm_vhost_wwn_attrs;
- fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = tcm_vhost_tpg_attrs;
+ fabric->tf_cit_tmpl.tfc_wwn_cit.ct_attrs = vhost_scsi_wwn_attrs;
+ fabric->tf_cit_tmpl.tfc_tpg_base_cit.ct_attrs = vhost_scsi_tpg_attrs;
fabric->tf_cit_tmpl.tfc_tpg_attrib_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_param_cit.ct_attrs = NULL;
fabric->tf_cit_tmpl.tfc_tpg_np_base_cit.ct_attrs = NULL;
@@ -2353,37 +2367,37 @@ static int tcm_vhost_register_configfs(void)
/*
* Setup our local pointer to *fabric
*/
- tcm_vhost_fabric_configfs = fabric;
- pr_debug("TCM_VHOST[0] - Set fabric -> tcm_vhost_fabric_configfs\n");
+ vhost_scsi_fabric_configfs = fabric;
+ pr_debug("TCM_VHOST[0] - Set fabric -> vhost_scsi_fabric_configfs\n");
return 0;
};
-static void tcm_vhost_deregister_configfs(void)
+static void vhost_scsi_deregister_configfs(void)
{
- if (!tcm_vhost_fabric_configfs)
+ if (!vhost_scsi_fabric_configfs)
return;
- target_fabric_configfs_deregister(tcm_vhost_fabric_configfs);
- tcm_vhost_fabric_configfs = NULL;
- pr_debug("TCM_VHOST[0] - Cleared tcm_vhost_fabric_configfs\n");
+ target_fabric_configfs_deregister(vhost_scsi_fabric_configfs);
+ vhost_scsi_fabric_configfs = NULL;
+ pr_debug("TCM_VHOST[0] - Cleared vhost_scsi_fabric_configfs\n");
};
-static int __init tcm_vhost_init(void)
+static int __init vhost_scsi_init(void)
{
int ret = -ENOMEM;
/*
* Use our own dedicated workqueue for submitting I/O into
* target core to avoid contention within system_wq.
*/
- tcm_vhost_workqueue = alloc_workqueue("tcm_vhost", 0, 0);
- if (!tcm_vhost_workqueue)
+ vhost_scsi_workqueue = alloc_workqueue("vhost_scsi", 0, 0);
+ if (!vhost_scsi_workqueue)
goto out;
ret = vhost_scsi_register();
if (ret < 0)
goto out_destroy_workqueue;
- ret = tcm_vhost_register_configfs();
+ ret = vhost_scsi_register_configfs();
if (ret < 0)
goto out_vhost_scsi_deregister;
@@ -2392,20 +2406,20 @@ static int __init tcm_vhost_init(void)
out_vhost_scsi_deregister:
vhost_scsi_deregister();
out_destroy_workqueue:
- destroy_workqueue(tcm_vhost_workqueue);
+ destroy_workqueue(vhost_scsi_workqueue);
out:
return ret;
};
-static void tcm_vhost_exit(void)
+static void vhost_scsi_exit(void)
{
- tcm_vhost_deregister_configfs();
+ vhost_scsi_deregister_configfs();
vhost_scsi_deregister();
- destroy_workqueue(tcm_vhost_workqueue);
+ destroy_workqueue(vhost_scsi_workqueue);
};
MODULE_DESCRIPTION("VHOST_SCSI series fabric driver");
MODULE_ALIAS("tcm_vhost");
MODULE_LICENSE("GPL");
-module_init(tcm_vhost_init);
-module_exit(tcm_vhost_exit);
+module_init(vhost_scsi_init);
+module_exit(vhost_scsi_exit);
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index cb807d0ea498..2ee28266fd07 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -1125,6 +1125,7 @@ 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);
+ struct iov_iter from;
int ret;
/* Sanity check */
@@ -1142,6 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
vq_err(vq, "Translation failure %d in indirect.\n", ret);
return ret;
}
+ iov_iter_init(&from, READ, vq->indirect, ret, len);
/* We will use the result as an address to read from, so most
* architectures only need a compiler barrier here. */
@@ -1164,8 +1166,8 @@ static int get_indirect(struct vhost_virtqueue *vq,
i, count);
return -EINVAL;
}
- if (unlikely(memcpy_fromiovec((unsigned char *)&desc,
- vq->indirect, sizeof desc))) {
+ if (unlikely(copy_from_iter(&desc, sizeof(desc), &from) !=
+ sizeof(desc))) {
vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc);
return -EINVAL;
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index fe1cd0148e13..ba97efc3bf70 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -77,18 +77,22 @@ config DUMMY_CONSOLE
config DUMMY_CONSOLE_COLUMNS
int "Initial number of console screen columns"
- depends on PARISC && DUMMY_CONSOLE
- default "160"
+ depends on DUMMY_CONSOLE && !ARM
+ default 160 if PARISC
+ default 80
help
- The default value is 160, which should fit a 1280x1024 monitor.
+ On PA-RISC, the default value is 160, which should fit a 1280x1024
+ monitor.
Select 80 if you use a 640x480 resolution by default.
config DUMMY_CONSOLE_ROWS
int "Initial number of console screen rows"
- depends on PARISC && DUMMY_CONSOLE
- default "64"
+ depends on DUMMY_CONSOLE && !ARM
+ default 64 if PARISC
+ default 25
help
- The default value is 64, which should fit a 1280x1024 monitor.
+ On PA-RISC, the default value is 64, which should fit a 1280x1024
+ monitor.
Select 25 if you use a 640x480 resolution by default.
config FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
index 40bec8d64b0a..0efc52f11ad0 100644
--- a/drivers/video/console/dummycon.c
+++ b/drivers/video/console/dummycon.c
@@ -20,13 +20,10 @@
#if defined(__arm__)
#define DUMMY_COLUMNS screen_info.orig_video_cols
#define DUMMY_ROWS screen_info.orig_video_lines
-#elif defined(__hppa__)
+#else
/* set by Kconfig. Use 80x25 for 640x480 and 160x64 for 1280x1024 */
#define DUMMY_COLUMNS CONFIG_DUMMY_CONSOLE_COLUMNS
#define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
-#else
-#define DUMMY_COLUMNS 80
-#define DUMMY_ROWS 25
#endif
static const char *dummycon_startup(void)
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index ea437245562e..b97210671a81 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -146,9 +146,6 @@ static const struct consw fb_con;
static int fbcon_set_origin(struct vc_data *);
-#define CURSOR_DRAW_DELAY (1)
-
-static int vbl_cursor_cnt;
static int fbcon_cursor_noblink;
#define divides(a, b) ((!(a) || (b)%(a)) ? 0 : 1)
@@ -1329,7 +1326,6 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
ops->cursor(vc, info, mode, y, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
- vbl_cursor_cnt = CURSOR_DRAW_DELAY;
}
static int scrollback_phys_max = 0;
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index 4916c97216f8..b3dd417b4719 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -1530,13 +1530,11 @@ config FB_SIS_315
config FB_VIA
tristate "VIA UniChrome (Pro) and Chrome9 display support"
- depends on FB && PCI && X86
+ depends on FB && PCI && X86 && GPIOLIB && I2C
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
select I2C_ALGOBIT
- select I2C
- select GPIOLIB
help
This is the frame buffer device driver for Graphics chips of VIA
UniChrome (Pro) Family (CLE266,PM800/CN400,P4M800CE/P4M800Pro/
@@ -2151,7 +2149,6 @@ config FB_PS3
select FB_SYS_COPYAREA
select FB_SYS_IMAGEBLIT
select FB_SYS_FOPS
- select VT_HW_CONSOLE_BINDING if FRAMEBUFFER_CONSOLE
---help---
Include support for the virtual frame buffer in the PS3 platform.
diff --git a/drivers/video/fbdev/atafb.c b/drivers/video/fbdev/atafb.c
index 4953b657635e..cb9ee2556850 100644
--- a/drivers/video/fbdev/atafb.c
+++ b/drivers/video/fbdev/atafb.c
@@ -3118,8 +3118,7 @@ int __init atafb_init(void)
printk("atafb_init: initializing Falcon hw\n");
fbhw = &falcon_switch;
atafb_ops.fb_setcolreg = &falcon_setcolreg;
- error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher,
- IRQ_TYPE_PRIO,
+ error = request_irq(IRQ_AUTO_4, falcon_vbl_switcher, 0,
"framebuffer:modeswitch",
falcon_vbl_switcher);
if (error)
diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index 37ec09b3fffd..8789e487b96e 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -3948,7 +3948,7 @@ static struct notifier_block atyfb_reboot_notifier = {
.notifier_call = atyfb_reboot_notify,
};
-static const struct dmi_system_id atyfb_reboot_ids[] = {
+static const struct dmi_system_id atyfb_reboot_ids[] __initconst = {
{
.ident = "HP OmniBook 500",
.matches = {
@@ -3960,6 +3960,7 @@ static const struct dmi_system_id atyfb_reboot_ids[] = {
{ }
};
+static bool registered_notifier = false;
static int __init atyfb_init(void)
{
@@ -3982,15 +3983,17 @@ static int __init atyfb_init(void)
if (err1 && err2)
return -ENODEV;
- if (dmi_check_system(atyfb_reboot_ids))
+ if (dmi_check_system(atyfb_reboot_ids)) {
register_reboot_notifier(&atyfb_reboot_notifier);
+ registered_notifier = true;
+ }
return 0;
}
static void __exit atyfb_exit(void)
{
- if (dmi_check_system(atyfb_reboot_ids))
+ if (registered_notifier)
unregister_reboot_notifier(&atyfb_reboot_notifier);
#ifdef CONFIG_PCI
diff --git a/drivers/video/fbdev/core/fbcvt.c b/drivers/video/fbdev/core/fbcvt.c
index 7cb715dfc0e1..55d2bd0ce5c0 100644
--- a/drivers/video/fbdev/core/fbcvt.c
+++ b/drivers/video/fbdev/core/fbcvt.c
@@ -369,9 +369,9 @@ int fb_find_mode_cvt(struct fb_videomode *mode, int margins, int rb)
cvt.h_back_porch = cvt.hblank/2 + cvt.h_margin;
cvt.h_front_porch = cvt.hblank - cvt.hsync - cvt.h_back_porch +
2 * cvt.h_margin;
- cvt.v_back_porch = 3 + cvt.v_margin;
- cvt.v_front_porch = cvt.vtotal - cvt.yres/cvt.interlace -
- cvt.v_back_porch - cvt.vsync;
+ cvt.v_front_porch = 3 + cvt.v_margin;
+ cvt.v_back_porch = cvt.vtotal - cvt.yres/cvt.interlace -
+ cvt.v_front_porch - cvt.vsync;
fb_cvt_print_name(&cvt);
fb_cvt_convert_to_mode(&cvt, mode);
diff --git a/drivers/video/fbdev/core/fbmon.c b/drivers/video/fbdev/core/fbmon.c
index 5b0e313849bd..95338593ebf4 100644
--- a/drivers/video/fbdev/core/fbmon.c
+++ b/drivers/video/fbdev/core/fbmon.c
@@ -496,56 +496,71 @@ static int get_est_timing(unsigned char *block, struct fb_videomode *mode)
}
static int get_std_timing(unsigned char *block, struct fb_videomode *mode,
- int ver, int rev)
+ int ver, int rev, const struct fb_monspecs *specs)
{
- int xres, yres = 0, refresh, ratio, i;
-
- xres = (block[0] + 31) * 8;
- if (xres <= 256)
- return 0;
+ int i;
- ratio = (block[1] & 0xc0) >> 6;
- switch (ratio) {
- case 0:
- /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
- if (ver < 1 || (ver == 1 && rev < 3))
- yres = xres;
- else
- yres = (xres * 10)/16;
- break;
- case 1:
- yres = (xres * 3)/4;
- break;
- case 2:
- yres = (xres * 4)/5;
- break;
- case 3:
- yres = (xres * 9)/16;
- break;
+ for (i = 0; i < DMT_SIZE; i++) {
+ u32 std_2byte_code = block[0] << 8 | block[1];
+ if (std_2byte_code == dmt_modes[i].std_2byte_code)
+ break;
}
- refresh = (block[1] & 0x3f) + 60;
-
- DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
- for (i = 0; i < VESA_MODEDB_SIZE; i++) {
- if (vesa_modes[i].xres == xres &&
- vesa_modes[i].yres == yres &&
- vesa_modes[i].refresh == refresh) {
- *mode = vesa_modes[i];
- mode->flag |= FB_MODE_IS_STANDARD;
- return 1;
+
+ if (i < DMT_SIZE && dmt_modes[i].mode) {
+ /* DMT mode found */
+ *mode = *dmt_modes[i].mode;
+ mode->flag |= FB_MODE_IS_STANDARD;
+ DPRINTK(" DMT id=%d\n", dmt_modes[i].dmt_id);
+
+ } else {
+ int xres, yres = 0, refresh, ratio;
+
+ xres = (block[0] + 31) * 8;
+ if (xres <= 256)
+ return 0;
+
+ ratio = (block[1] & 0xc0) >> 6;
+ switch (ratio) {
+ case 0:
+ /* in EDID 1.3 the meaning of 0 changed to 16:10 (prior 1:1) */
+ if (ver < 1 || (ver == 1 && rev < 3))
+ yres = xres;
+ else
+ yres = (xres * 10)/16;
+ break;
+ case 1:
+ yres = (xres * 3)/4;
+ break;
+ case 2:
+ yres = (xres * 4)/5;
+ break;
+ case 3:
+ yres = (xres * 9)/16;
+ break;
}
+ refresh = (block[1] & 0x3f) + 60;
+ DPRINTK(" %dx%d@%dHz\n", xres, yres, refresh);
+
+ calc_mode_timings(xres, yres, refresh, mode);
}
- calc_mode_timings(xres, yres, refresh, mode);
+
+ /* Check the mode we got is within valid spec of the monitor */
+ if (specs && specs->dclkmax
+ && PICOS2KHZ(mode->pixclock) * 1000 > specs->dclkmax) {
+ DPRINTK(" mode exceed max DCLK\n");
+ return 0;
+ }
+
return 1;
}
-static int get_dst_timing(unsigned char *block,
- struct fb_videomode *mode, int ver, int rev)
+static int get_dst_timing(unsigned char *block, struct fb_videomode *mode,
+ int ver, int rev, const struct fb_monspecs *specs)
{
int j, num = 0;
for (j = 0; j < 6; j++, block += STD_TIMING_DESCRIPTION_SIZE)
- num += get_std_timing(block, &mode[num], ver, rev);
+ num += get_std_timing(block, &mode[num], ver, rev, specs);
return num;
}
@@ -601,7 +616,8 @@ static void get_detailed_timing(unsigned char *block,
* This function builds a mode database using the contents of the EDID
* data
*/
-static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
+static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize,
+ const struct fb_monspecs *specs)
{
struct fb_videomode *mode, *m;
unsigned char *block;
@@ -643,12 +659,13 @@ static struct fb_videomode *fb_create_modedb(unsigned char *edid, int *dbsize)
DPRINTK(" Standard Timings\n");
block = edid + STD_TIMING_DESCRIPTIONS_START;
for (i = 0; i < STD_TIMING; i++, block += STD_TIMING_DESCRIPTION_SIZE)
- num += get_std_timing(block, &mode[num], ver, rev);
+ num += get_std_timing(block, &mode[num], ver, rev, specs);
block = edid + DETAILED_TIMING_DESCRIPTIONS_START;
for (i = 0; i < 4; i++, block+= DETAILED_TIMING_DESCRIPTION_SIZE) {
if (block[0] == 0x00 && block[1] == 0x00 && block[3] == 0xfa)
- num += get_dst_timing(block + 5, &mode[num], ver, rev);
+ num += get_dst_timing(block + 5, &mode[num],
+ ver, rev, specs);
}
/* Yikes, EDID data is totally useless */
@@ -707,7 +724,7 @@ static int fb_get_monitor_limits(unsigned char *edid, struct fb_monspecs *specs)
int num_modes, hz, hscan, pixclock;
int vtotal, htotal;
- modes = fb_create_modedb(edid, &num_modes);
+ modes = fb_create_modedb(edid, &num_modes, specs);
if (!modes) {
DPRINTK("None Available\n");
return 1;
@@ -964,7 +981,7 @@ void fb_edid_to_monspecs(unsigned char *edid, struct fb_monspecs *specs)
DPRINTK(" Display Characteristics:\n");
get_monspecs(edid, specs);
- specs->modedb = fb_create_modedb(edid, &specs->modedb_len);
+ specs->modedb = fb_create_modedb(edid, &specs->modedb_len, specs);
/*
* Workaround for buggy EDIDs that sets that the first
diff --git a/drivers/video/fbdev/core/modedb.c b/drivers/video/fbdev/core/modedb.c
index 388f7971494b..7d07cf824b64 100644
--- a/drivers/video/fbdev/core/modedb.c
+++ b/drivers/video/fbdev/core/modedb.c
@@ -468,8 +468,119 @@ const struct fb_videomode vesa_modes[] = {
/* 33 1920x1440-75 VESA */
{ NULL, 75, 1920, 1440, 3367, 352, 144, 56, 1, 224, 3,
FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 34 1920x1200-60 RB VESA */
+ { NULL, 60, 1920, 1200, 6493, 80, 48, 26, 3, 32, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 35 1920x1200-60 VESA */
+ { NULL, 60, 1920, 1200, 5174, 336, 136, 36, 3, 200, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 36 1920x1200-75 VESA */
+ { NULL, 75, 1920, 1200, 4077, 344, 136, 46, 3, 208, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 37 1920x1200-85 VESA */
+ { NULL, 85, 1920, 1200, 3555, 352, 144, 53, 3, 208, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 38 2560x1600-60 RB VESA */
+ { NULL, 60, 2560, 1600, 3724, 80, 48, 37, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 39 2560x1600-60 VESA */
+ { NULL, 60, 2560, 1600, 2869, 472, 192, 49, 3, 280, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 40 2560x1600-75 VESA */
+ { NULL, 75, 2560, 1600, 2256, 488, 208, 63, 3, 280, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 41 2560x1600-85 VESA */
+ { NULL, 85, 2560, 1600, 1979, 488, 208, 73, 3, 280, 6,
+ FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
+ /* 42 2560x1600-120 RB VESA */
+ { NULL, 120, 2560, 1600, 1809, 80, 48, 85, 3, 32, 6,
+ FB_SYNC_HOR_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_VESA },
};
EXPORT_SYMBOL(vesa_modes);
+
+const struct dmt_videomode dmt_modes[DMT_SIZE] = {
+ { 0x01, 0x0000, 0x000000, &vesa_modes[0] },
+ { 0x02, 0x3119, 0x000000, &vesa_modes[1] },
+ { 0x03, 0x0000, 0x000000, &vesa_modes[2] },
+ { 0x04, 0x3140, 0x000000, &vesa_modes[3] },
+ { 0x05, 0x314c, 0x000000, &vesa_modes[4] },
+ { 0x06, 0x314f, 0x000000, &vesa_modes[5] },
+ { 0x07, 0x3159, 0x000000, &vesa_modes[6] },
+ { 0x08, 0x0000, 0x000000, &vesa_modes[7] },
+ { 0x09, 0x4540, 0x000000, &vesa_modes[8] },
+ { 0x0a, 0x454c, 0x000000, &vesa_modes[9] },
+ { 0x0b, 0x454f, 0x000000, &vesa_modes[10] },
+ { 0x0c, 0x4559, 0x000000, &vesa_modes[11] },
+ { 0x0d, 0x0000, 0x000000, NULL },
+ { 0x0e, 0x0000, 0x000000, NULL },
+ { 0x0f, 0x0000, 0x000000, &vesa_modes[12] },
+ { 0x10, 0x6140, 0x000000, &vesa_modes[13] },
+ { 0x11, 0x614a, 0x000000, &vesa_modes[14] },
+ { 0x12, 0x614f, 0x000000, &vesa_modes[15] },
+ { 0x13, 0x6159, 0x000000, &vesa_modes[16] },
+ { 0x14, 0x0000, 0x000000, NULL },
+ { 0x15, 0x714f, 0x000000, &vesa_modes[17] },
+ { 0x16, 0x0000, 0x7f1c21, NULL },
+ { 0x17, 0x0000, 0x7f1c28, NULL },
+ { 0x18, 0x0000, 0x7f1c44, NULL },
+ { 0x19, 0x0000, 0x7f1c62, NULL },
+ { 0x1a, 0x0000, 0x000000, NULL },
+ { 0x1b, 0x0000, 0x8f1821, NULL },
+ { 0x1c, 0x8100, 0x8f1828, NULL },
+ { 0x1d, 0x810f, 0x8f1844, NULL },
+ { 0x1e, 0x8119, 0x8f1862, NULL },
+ { 0x1f, 0x0000, 0x000000, NULL },
+ { 0x20, 0x8140, 0x000000, &vesa_modes[18] },
+ { 0x21, 0x8159, 0x000000, &vesa_modes[19] },
+ { 0x22, 0x0000, 0x000000, NULL },
+ { 0x23, 0x8180, 0x000000, &vesa_modes[20] },
+ { 0x24, 0x818f, 0x000000, &vesa_modes[21] },
+ { 0x25, 0x8199, 0x000000, &vesa_modes[22] },
+ { 0x26, 0x0000, 0x000000, NULL },
+ { 0x27, 0x0000, 0x000000, NULL },
+ { 0x28, 0x0000, 0x000000, NULL },
+ { 0x29, 0x0000, 0x0c2021, NULL },
+ { 0x2a, 0x9040, 0x0c2028, NULL },
+ { 0x2b, 0x904f, 0x0c2044, NULL },
+ { 0x2c, 0x9059, 0x0c2062, NULL },
+ { 0x2d, 0x0000, 0x000000, NULL },
+ { 0x2e, 0x9500, 0xc11821, NULL },
+ { 0x2f, 0x9500, 0xc11828, NULL },
+ { 0x30, 0x950f, 0xc11844, NULL },
+ { 0x31, 0x9519, 0xc11868, NULL },
+ { 0x32, 0x0000, 0x000000, NULL },
+ { 0x33, 0xa940, 0x000000, &vesa_modes[23] },
+ { 0x34, 0xa945, 0x000000, &vesa_modes[24] },
+ { 0x35, 0xa94a, 0x000000, &vesa_modes[25] },
+ { 0x36, 0xa94f, 0x000000, &vesa_modes[26] },
+ { 0x37, 0xa959, 0x000000, &vesa_modes[27] },
+ { 0x38, 0x0000, 0x000000, NULL },
+ { 0x39, 0x0000, 0x0c2821, NULL },
+ { 0x3a, 0xb300, 0x0c2828, NULL },
+ { 0x3b, 0xb30f, 0x0c2844, NULL },
+ { 0x3c, 0xb319, 0x0c2868, NULL },
+ { 0x3d, 0x0000, 0x000000, NULL },
+ { 0x3e, 0xc140, 0x000000, &vesa_modes[28] },
+ { 0x3f, 0xc14f, 0x000000, &vesa_modes[29] },
+ { 0x40, 0x0000, 0x000000, NULL},
+ { 0x41, 0xc940, 0x000000, &vesa_modes[30] },
+ { 0x42, 0xc94f, 0x000000, &vesa_modes[31] },
+ { 0x43, 0x0000, 0x000000, NULL },
+ { 0x44, 0x0000, 0x572821, &vesa_modes[34] },
+ { 0x45, 0xd100, 0x572828, &vesa_modes[35] },
+ { 0x46, 0xd10f, 0x572844, &vesa_modes[36] },
+ { 0x47, 0xd119, 0x572862, &vesa_modes[37] },
+ { 0x48, 0x0000, 0x000000, NULL },
+ { 0x49, 0xd140, 0x000000, &vesa_modes[32] },
+ { 0x4a, 0xd14f, 0x000000, &vesa_modes[33] },
+ { 0x4b, 0x0000, 0x000000, NULL },
+ { 0x4c, 0x0000, 0x1f3821, &vesa_modes[38] },
+ { 0x4d, 0x0000, 0x1f3828, &vesa_modes[39] },
+ { 0x4e, 0x0000, 0x1f3844, &vesa_modes[40] },
+ { 0x4f, 0x0000, 0x1f3862, &vesa_modes[41] },
+ { 0x50, 0x0000, 0x000000, &vesa_modes[42] },
+};
+EXPORT_SYMBOL(dmt_modes);
#endif /* CONFIG_FB_MODE_HELPERS */
/**
diff --git a/drivers/video/fbdev/core/syscopyarea.c b/drivers/video/fbdev/core/syscopyarea.c
index 844a32fd38ed..c1eda3190968 100644
--- a/drivers/video/fbdev/core/syscopyarea.c
+++ b/drivers/video/fbdev/core/syscopyarea.c
@@ -25,8 +25,8 @@
*/
static void
-bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
- const unsigned long *src, int src_idx, int bits, unsigned n)
+bitcpy(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
+ const unsigned long *src, unsigned src_idx, int bits, unsigned n)
{
unsigned long first, last;
int const shift = dst_idx-src_idx;
@@ -86,15 +86,15 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
first &= last;
if (shift > 0) {
/* Single source word */
- *dst = comp(*src >> right, *dst, first);
+ *dst = comp(*src << left, *dst, first);
} else if (src_idx+n <= bits) {
/* Single source word */
- *dst = comp(*src << left, *dst, first);
+ *dst = comp(*src >> right, *dst, first);
} else {
/* 2 source words */
d0 = *src++;
d1 = *src;
- *dst = comp(d0 << left | d1 >> right, *dst,
+ *dst = comp(d0 >> right | d1 << left, *dst,
first);
}
} else {
@@ -109,13 +109,14 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Leading bits */
if (shift > 0) {
/* Single source word */
- *dst = comp(d0 >> right, *dst, first);
+ *dst = comp(d0 << left, *dst, first);
dst++;
n -= bits - dst_idx;
} else {
/* 2 source words */
d1 = *src++;
- *dst = comp(d0 << left | *dst >> right, *dst, first);
+ *dst = comp(d0 >> right | d1 << left, *dst,
+ first);
d0 = d1;
dst++;
n -= bits - dst_idx;
@@ -126,36 +127,36 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
n /= bits;
while (n >= 4) {
d1 = *src++;
- *dst++ = d0 << left | d1 >> right;
+ *dst++ = d0 >> right | d1 << left;
d0 = d1;
d1 = *src++;
- *dst++ = d0 << left | d1 >> right;
+ *dst++ = d0 >> right | d1 << left;
d0 = d1;
d1 = *src++;
- *dst++ = d0 << left | d1 >> right;
+ *dst++ = d0 >> right | d1 << left;
d0 = d1;
d1 = *src++;
- *dst++ = d0 << left | d1 >> right;
+ *dst++ = d0 >> right | d1 << left;
d0 = d1;
n -= 4;
}
while (n--) {
d1 = *src++;
- *dst++ = d0 << left | d1 >> right;
+ *dst++ = d0 >> right | d1 << left;
d0 = d1;
}
/* Trailing bits */
- if (last) {
- if (m <= right) {
+ if (m) {
+ if (m <= bits - right) {
/* Single source word */
- *dst = comp(d0 << left, *dst, last);
+ d0 >>= right;
} else {
/* 2 source words */
d1 = *src;
- *dst = comp(d0 << left | d1 >> right,
- *dst, last);
+ d0 = d0 >> right | d1 << left;
}
+ *dst = comp(d0, *dst, last);
}
}
}
@@ -166,40 +167,35 @@ bitcpy(struct fb_info *p, unsigned long *dst, int dst_idx,
*/
static void
-bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
- const unsigned long *src, int src_idx, int bits, unsigned n)
+bitcpy_rev(struct fb_info *p, unsigned long *dst, unsigned dst_idx,
+ const unsigned long *src, unsigned src_idx, unsigned bits,
+ unsigned n)
{
unsigned long first, last;
int shift;
- dst += (n-1)/bits;
- src += (n-1)/bits;
- if ((n-1) % bits) {
- dst_idx += (n-1) % bits;
- dst += dst_idx >> (ffs(bits) - 1);
- dst_idx &= bits - 1;
- src_idx += (n-1) % bits;
- src += src_idx >> (ffs(bits) - 1);
- src_idx &= bits - 1;
- }
+ dst += (dst_idx + n - 1) / bits;
+ src += (src_idx + n - 1) / bits;
+ dst_idx = (dst_idx + n - 1) % bits;
+ src_idx = (src_idx + n - 1) % bits;
shift = dst_idx-src_idx;
- first = FB_SHIFT_LOW(p, ~0UL, bits - 1 - dst_idx);
- last = ~(FB_SHIFT_LOW(p, ~0UL, bits - 1 - ((dst_idx-n) % bits)));
+ first = ~FB_SHIFT_HIGH(p, ~0UL, (dst_idx + 1) % bits);
+ last = FB_SHIFT_HIGH(p, ~0UL, (bits + dst_idx + 1 - n) % bits);
if (!shift) {
/* Same alignment for source and dest */
if ((unsigned long)dst_idx+1 >= n) {
/* Single word */
- if (last)
- first &= last;
- *dst = comp(*src, *dst, first);
+ if (first)
+ last &= first;
+ *dst = comp(*src, *dst, last);
} else {
/* Multiple destination words */
/* Leading bits */
- if (first != ~0UL) {
+ if (first) {
*dst = comp(*src, *dst, first);
dst--;
src--;
@@ -222,29 +218,29 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
while (n--)
*dst-- = *src--;
/* Trailing bits */
- if (last)
+ if (last != -1UL)
*dst = comp(*src, *dst, last);
}
} else {
/* Different alignment for source and dest */
- int const left = -shift & (bits-1);
- int const right = shift & (bits-1);
+ int const left = shift & (bits-1);
+ int const right = -shift & (bits-1);
if ((unsigned long)dst_idx+1 >= n) {
/* Single destination word */
- if (last)
- first &= last;
+ if (first)
+ last &= first;
if (shift < 0) {
/* Single source word */
- *dst = comp(*src << left, *dst, first);
+ *dst = comp(*src >> right, *dst, last);
} else if (1+(unsigned long)src_idx >= n) {
/* Single source word */
- *dst = comp(*src >> right, *dst, first);
+ *dst = comp(*src << left, *dst, last);
} else {
/* 2 source words */
- *dst = comp(*src >> right | *(src-1) << left,
- *dst, first);
+ *dst = comp(*src << left | *(src-1) >> right,
+ *dst, last);
}
} else {
/* Multiple destination words */
@@ -261,14 +257,18 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
/* Leading bits */
if (shift < 0) {
/* Single source word */
- *dst = comp(d0 << left, *dst, first);
+ d1 = d0;
+ d0 >>= right;
} else {
/* 2 source words */
d1 = *src--;
- *dst = comp(d0 >> right | d1 << left, *dst,
- first);
- d0 = d1;
+ d0 = d0 << left | d1 >> right;
}
+ if (!first)
+ *dst = d0;
+ else
+ *dst = comp(d0, *dst, first);
+ d0 = d1;
dst--;
n -= dst_idx+1;
@@ -277,36 +277,36 @@ bitcpy_rev(struct fb_info *p, unsigned long *dst, int dst_idx,
n /= bits;
while (n >= 4) {
d1 = *src--;
- *dst-- = d0 >> right | d1 << left;
+ *dst-- = d0 << left | d1 >> right;
d0 = d1;
d1 = *src--;
- *dst-- = d0 >> right | d1 << left;
+ *dst-- = d0 << left | d1 >> right;
d0 = d1;
d1 = *src--;
- *dst-- = d0 >> right | d1 << left;
+ *dst-- = d0 << left | d1 >> right;
d0 = d1;
d1 = *src--;
- *dst-- = d0 >> right | d1 << left;
+ *dst-- = d0 << left | d1 >> right;
d0 = d1;
n -= 4;
}
while (n--) {
d1 = *src--;
- *dst-- = d0 >> right | d1 << left;
+ *dst-- = d0 << left | d1 >> right;
d0 = d1;
}
/* Trailing bits */
- if (last) {
- if (m <= left) {
+ if (m) {
+ if (m <= bits - left) {
/* Single source word */
- *dst = comp(d0 >> right, *dst, last);
+ d0 <<= left;
} else {
/* 2 source words */
d1 = *src;
- *dst = comp(d0 >> right | d1 << left,
- *dst, last);
+ d0 = d0 << left | d1 >> right;
}
+ *dst = comp(d0, *dst, last);
}
}
}
@@ -317,9 +317,9 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
u32 dx = area->dx, dy = area->dy, sx = area->sx, sy = area->sy;
u32 height = area->height, width = area->width;
unsigned long const bits_per_line = p->fix.line_length*8u;
- unsigned long *dst = NULL, *src = NULL;
+ unsigned long *base = NULL;
int bits = BITS_PER_LONG, bytes = bits >> 3;
- int dst_idx = 0, src_idx = 0, rev_copy = 0;
+ unsigned dst_idx = 0, src_idx = 0, rev_copy = 0;
if (p->state != FBINFO_STATE_RUNNING)
return;
@@ -334,8 +334,7 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
/* split the base of the framebuffer into a long-aligned address and
the index of the first bit */
- dst = src = (unsigned long *)((unsigned long)p->screen_base &
- ~(bytes-1));
+ base = (unsigned long *)((unsigned long)p->screen_base & ~(bytes-1));
dst_idx = src_idx = 8*((unsigned long)p->screen_base & (bytes-1));
/* add offset of source and target area */
dst_idx += dy*bits_per_line + dx*p->var.bits_per_pixel;
@@ -348,20 +347,14 @@ void sys_copyarea(struct fb_info *p, const struct fb_copyarea *area)
while (height--) {
dst_idx -= bits_per_line;
src_idx -= bits_per_line;
- dst += dst_idx >> (ffs(bits) - 1);
- dst_idx &= (bytes - 1);
- src += src_idx >> (ffs(bits) - 1);
- src_idx &= (bytes - 1);
- bitcpy_rev(p, dst, dst_idx, src, src_idx, bits,
+ bitcpy_rev(p, base + (dst_idx / bits), dst_idx % bits,
+ base + (src_idx / bits), src_idx % bits, bits,
width*p->var.bits_per_pixel);
}
} else {
while (height--) {
- dst += dst_idx >> (ffs(bits) - 1);
- dst_idx &= (bytes - 1);
- src += src_idx >> (ffs(bits) - 1);
- src_idx &= (bytes - 1);
- bitcpy(p, dst, dst_idx, src, src_idx, bits,
+ bitcpy(p, base + (dst_idx / bits), dst_idx % bits,
+ base + (src_idx / bits), src_idx % bits, bits,
width*p->var.bits_per_pixel);
dst_idx += bits_per_line;
src_idx += bits_per_line;
diff --git a/drivers/video/fbdev/geode/gx1fb_core.c b/drivers/video/fbdev/geode/gx1fb_core.c
index 2794ba11f332..9bee8744c438 100644
--- a/drivers/video/fbdev/geode/gx1fb_core.c
+++ b/drivers/video/fbdev/geode/gx1fb_core.c
@@ -374,10 +374,8 @@ static int gx1fb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
release_mem_region(gx1_gx_base() + 0x8300, 0x100);
}
- if (info) {
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
return ret;
}
diff --git a/drivers/video/fbdev/geode/gxfb_core.c b/drivers/video/fbdev/geode/gxfb_core.c
index 1790f14bab15..124d7c7e2d14 100644
--- a/drivers/video/fbdev/geode/gxfb_core.c
+++ b/drivers/video/fbdev/geode/gxfb_core.c
@@ -444,10 +444,8 @@ static int gxfb_probe(struct pci_dev *pdev, const struct pci_device_id *id)
pci_release_region(pdev, 1);
}
- if (info) {
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
return ret;
}
diff --git a/drivers/video/fbdev/geode/lxfb_core.c b/drivers/video/fbdev/geode/lxfb_core.c
index 9e1d19d673a1..138da6cb6cbc 100644
--- a/drivers/video/fbdev/geode/lxfb_core.c
+++ b/drivers/video/fbdev/geode/lxfb_core.c
@@ -577,10 +577,8 @@ err:
pci_release_region(pdev, 3);
}
- if (info) {
- fb_dealloc_cmap(&info->cmap);
- framebuffer_release(info);
- }
+ fb_dealloc_cmap(&info->cmap);
+ framebuffer_release(info);
return ret;
}
diff --git a/drivers/video/fbdev/hgafb.c b/drivers/video/fbdev/hgafb.c
index 5ff9fe2116a4..15d3ccff2965 100644
--- a/drivers/video/fbdev/hgafb.c
+++ b/drivers/video/fbdev/hgafb.c
@@ -417,8 +417,7 @@ static int hgafb_pan_display(struct fb_var_screeninfo *var,
struct fb_info *info)
{
if (var->vmode & FB_VMODE_YWRAP) {
- if (var->yoffset < 0 ||
- var->yoffset >= info->var.yres_virtual ||
+ if (var->yoffset >= info->var.yres_virtual ||
var->xoffset)
return -EINVAL;
} else {
diff --git a/drivers/video/fbdev/mmp/Makefile b/drivers/video/fbdev/mmp/Makefile
index a014cb358bf8..924dd0930cc7 100644
--- a/drivers/video/fbdev/mmp/Makefile
+++ b/drivers/video/fbdev/mmp/Makefile
@@ -1 +1,3 @@
-obj-y += core.o hw/ panel/ fb/
+obj-$(CONFIG_MMP_DISP) += mmp_disp.o hw/ panel/ fb/
+
+mmp_disp-y += core.o
diff --git a/drivers/video/fbdev/mmp/fb/Kconfig b/drivers/video/fbdev/mmp/fb/Kconfig
index 9b0141f105f5..985e1a7cd254 100644
--- a/drivers/video/fbdev/mmp/fb/Kconfig
+++ b/drivers/video/fbdev/mmp/fb/Kconfig
@@ -1,7 +1,7 @@
if MMP_DISP
config MMP_FB
- bool "fb driver for Marvell MMP Display Subsystem"
+ tristate "fb driver for Marvell MMP Display Subsystem"
depends on FB
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
diff --git a/drivers/video/fbdev/ocfb.c b/drivers/video/fbdev/ocfb.c
index 7f9dc9bec309..de9819660ca0 100644
--- a/drivers/video/fbdev/ocfb.c
+++ b/drivers/video/fbdev/ocfb.c
@@ -61,7 +61,7 @@ struct ocfb_dev {
/* flag indicating whether the regs are little endian accessed */
int little_endian;
/* Physical and virtual addresses of framebuffer */
- phys_addr_t fb_phys;
+ dma_addr_t fb_phys;
void __iomem *fb_virt;
u32 pseudo_palette[PALETTE_SIZE];
};
diff --git a/drivers/video/fbdev/omap2/displays-new/Kconfig b/drivers/video/fbdev/omap2/displays-new/Kconfig
index e6cfc38160d3..574710141a61 100644
--- a/drivers/video/fbdev/omap2/displays-new/Kconfig
+++ b/drivers/video/fbdev/omap2/displays-new/Kconfig
@@ -1,6 +1,12 @@
menu "OMAP Display Device Drivers (new device model)"
depends on OMAP2_DSS
+config DISPLAY_ENCODER_OPA362
+ tristate "OPA362 external analog amplifier"
+ help
+ Driver for OPA362 external analog TV amplifier controlled
+ through a GPIO.
+
config DISPLAY_ENCODER_TFP410
tristate "TFP410 DPI to DVI Encoder"
help
diff --git a/drivers/video/fbdev/omap2/displays-new/Makefile b/drivers/video/fbdev/omap2/displays-new/Makefile
index 0323a8a1c682..9aa176bfbf2e 100644
--- a/drivers/video/fbdev/omap2/displays-new/Makefile
+++ b/drivers/video/fbdev/omap2/displays-new/Makefile
@@ -1,3 +1,4 @@
+obj-$(CONFIG_DISPLAY_ENCODER_OPA362) += encoder-opa362.o
obj-$(CONFIG_DISPLAY_ENCODER_TFP410) += encoder-tfp410.o
obj-$(CONFIG_DISPLAY_ENCODER_TPD12S015) += encoder-tpd12s015.o
obj-$(CONFIG_DISPLAY_CONNECTOR_DVI) += connector-dvi.o
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c b/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c
index 9a2b5ce58545..8511c648a15c 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c
+++ b/drivers/video/fbdev/omap2/displays-new/connector-analog-tv.c
@@ -208,7 +208,7 @@ static int tvc_probe_pdata(struct platform_device *pdev)
ddata->in = in;
ddata->connector_type = pdata->connector_type;
- ddata->invert_polarity = ddata->invert_polarity;
+ ddata->invert_polarity = pdata->invert_polarity;
dssdev = &ddata->dssdev;
dssdev->name = pdata->name;
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
new file mode 100644
index 000000000000..84a6b3367124
--- /dev/null
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-opa362.c
@@ -0,0 +1,285 @@
+/*
+ * OPA362 analog video amplifier with output/power control
+ *
+ * Copyright (C) 2014 Golden Delicious Computers
+ * Author: H. Nikolaus Schaller <hns@goldelico.com>
+ *
+ * based on encoder-tfp410
+ *
+ * Copyright (C) 2013 Texas Instruments
+ * Author: Tomi Valkeinen <tomi.valkeinen@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/of_gpio.h>
+
+#include <video/omapdss.h>
+
+struct panel_drv_data {
+ struct omap_dss_device dssdev;
+ struct omap_dss_device *in;
+
+ struct gpio_desc *enable_gpio;
+
+ struct omap_video_timings timings;
+};
+
+#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
+
+static int opa362_connect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(dssdev->dev, "connect\n");
+
+ if (omapdss_device_is_connected(dssdev))
+ return -EBUSY;
+
+ r = in->ops.atv->connect(in, dssdev);
+ if (r)
+ return r;
+
+ dst->src = dssdev;
+ dssdev->dst = dst;
+
+ return 0;
+}
+
+static void opa362_disconnect(struct omap_dss_device *dssdev,
+ struct omap_dss_device *dst)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "disconnect\n");
+
+ WARN_ON(!omapdss_device_is_connected(dssdev));
+ if (!omapdss_device_is_connected(dssdev))
+ return;
+
+ WARN_ON(dst != dssdev->dst);
+ if (dst != dssdev->dst)
+ return;
+
+ dst->src = NULL;
+ dssdev->dst = NULL;
+
+ in->ops.atv->disconnect(in, &ddata->dssdev);
+}
+
+static int opa362_enable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+ int r;
+
+ dev_dbg(dssdev->dev, "enable\n");
+
+ if (!omapdss_device_is_connected(dssdev))
+ return -ENODEV;
+
+ if (omapdss_device_is_enabled(dssdev))
+ return 0;
+
+ in->ops.atv->set_timings(in, &ddata->timings);
+
+ r = in->ops.atv->enable(in);
+ if (r)
+ return r;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 1);
+
+ dssdev->state = OMAP_DSS_DISPLAY_ACTIVE;
+
+ return 0;
+}
+
+static void opa362_disable(struct omap_dss_device *dssdev)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "disable\n");
+
+ if (!omapdss_device_is_enabled(dssdev))
+ return;
+
+ if (ddata->enable_gpio)
+ gpiod_set_value_cansleep(ddata->enable_gpio, 0);
+
+ in->ops.atv->disable(in);
+
+ dssdev->state = OMAP_DSS_DISPLAY_DISABLED;
+}
+
+static void opa362_set_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "set_timings\n");
+
+ ddata->timings = *timings;
+ dssdev->panel.timings = *timings;
+
+ in->ops.atv->set_timings(in, timings);
+}
+
+static void opa362_get_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+
+ dev_dbg(dssdev->dev, "get_timings\n");
+
+ *timings = ddata->timings;
+}
+
+static int opa362_check_timings(struct omap_dss_device *dssdev,
+ struct omap_video_timings *timings)
+{
+ struct panel_drv_data *ddata = to_panel_data(dssdev);
+ struct omap_dss_device *in = ddata->in;
+
+ dev_dbg(dssdev->dev, "check_timings\n");
+
+ return in->ops.atv->check_timings(in, timings);
+}
+
+static void opa362_set_type(struct omap_dss_device *dssdev,
+ enum omap_dss_venc_type type)
+{
+ /* we can only drive a COMPOSITE output */
+ WARN_ON(type != OMAP_DSS_VENC_TYPE_COMPOSITE);
+
+}
+
+static const struct omapdss_atv_ops opa362_atv_ops = {
+ .connect = opa362_connect,
+ .disconnect = opa362_disconnect,
+
+ .enable = opa362_enable,
+ .disable = opa362_disable,
+
+ .check_timings = opa362_check_timings,
+ .set_timings = opa362_set_timings,
+ .get_timings = opa362_get_timings,
+
+ .set_type = opa362_set_type,
+};
+
+static int opa362_probe(struct platform_device *pdev)
+{
+ struct device_node *node = pdev->dev.of_node;
+ struct panel_drv_data *ddata;
+ struct omap_dss_device *dssdev, *in;
+ struct gpio_desc *gpio;
+ int r;
+
+ dev_dbg(&pdev->dev, "probe\n");
+
+ if (node == NULL) {
+ dev_err(&pdev->dev, "Unable to find device tree\n");
+ return -EINVAL;
+ }
+
+ ddata = devm_kzalloc(&pdev->dev, sizeof(*ddata), GFP_KERNEL);
+ if (!ddata)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, ddata);
+
+ gpio = devm_gpiod_get(&pdev->dev, "enable");
+ if (IS_ERR(gpio)) {
+ if (PTR_ERR(gpio) != -ENOENT)
+ return PTR_ERR(gpio);
+
+ gpio = NULL;
+ } else {
+ gpiod_direction_output(gpio, 0);
+ }
+
+ ddata->enable_gpio = gpio;
+
+ in = omapdss_of_find_source_for_first_ep(node);
+ if (IS_ERR(in)) {
+ dev_err(&pdev->dev, "failed to find video source\n");
+ return PTR_ERR(in);
+ }
+
+ ddata->in = in;
+
+ dssdev = &ddata->dssdev;
+ dssdev->ops.atv = &opa362_atv_ops;
+ dssdev->dev = &pdev->dev;
+ dssdev->type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->output_type = OMAP_DISPLAY_TYPE_VENC;
+ dssdev->owner = THIS_MODULE;
+
+ r = omapdss_register_output(dssdev);
+ if (r) {
+ dev_err(&pdev->dev, "Failed to register output\n");
+ goto err_reg;
+ }
+
+ return 0;
+err_reg:
+ omap_dss_put_device(ddata->in);
+ return r;
+}
+
+static int __exit opa362_remove(struct platform_device *pdev)
+{
+ struct panel_drv_data *ddata = platform_get_drvdata(pdev);
+ struct omap_dss_device *dssdev = &ddata->dssdev;
+ struct omap_dss_device *in = ddata->in;
+
+ omapdss_unregister_output(&ddata->dssdev);
+
+ WARN_ON(omapdss_device_is_enabled(dssdev));
+ if (omapdss_device_is_enabled(dssdev))
+ opa362_disable(dssdev);
+
+ WARN_ON(omapdss_device_is_connected(dssdev));
+ if (omapdss_device_is_connected(dssdev))
+ opa362_disconnect(dssdev, dssdev->dst);
+
+ omap_dss_put_device(in);
+
+ return 0;
+}
+
+static const struct of_device_id opa362_of_match[] = {
+ { .compatible = "omapdss,ti,opa362", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, opa362_of_match);
+
+static struct platform_driver opa362_driver = {
+ .probe = opa362_probe,
+ .remove = __exit_p(opa362_remove),
+ .driver = {
+ .name = "amplifier-opa362",
+ .owner = THIS_MODULE,
+ .of_match_table = opa362_of_match,
+ .suppress_bind_attrs = true,
+ },
+};
+
+module_platform_driver(opa362_driver);
+
+MODULE_AUTHOR("H. Nikolaus Schaller <hns@goldelico.com>");
+MODULE_DESCRIPTION("OPA362 analog video amplifier with output/power control");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
index 7f3e11b16c86..990af6baeb0f 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
@@ -29,33 +29,10 @@ struct panel_drv_data {
int hpd_gpio;
struct omap_video_timings timings;
-
- struct completion hpd_completion;
};
#define to_panel_data(x) container_of(x, struct panel_drv_data, dssdev)
-static irqreturn_t tpd_hpd_irq_handler(int irq, void *data)
-{
- struct panel_drv_data *ddata = data;
- bool hpd;
-
- hpd = gpio_get_value_cansleep(ddata->hpd_gpio);
-
- dev_dbg(ddata->dssdev.dev, "hpd %d\n", hpd);
-
- if (gpio_is_valid(ddata->ls_oe_gpio)) {
- if (hpd)
- gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
- else
- gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
- }
-
- complete_all(&ddata->hpd_completion);
-
- return IRQ_HANDLED;
-}
-
static int tpd_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
@@ -70,23 +47,10 @@ static int tpd_connect(struct omap_dss_device *dssdev,
dst->src = dssdev;
dssdev->dst = dst;
- reinit_completion(&ddata->hpd_completion);
-
gpio_set_value_cansleep(ddata->ct_cp_hpd_gpio, 1);
/* DC-DC converter needs at max 300us to get to 90% of 5V */
udelay(300);
- /*
- * If there's a cable connected, wait for the hpd irq to trigger,
- * which turns on the level shifters.
- */
- if (gpio_get_value_cansleep(ddata->hpd_gpio)) {
- unsigned long to;
- to = wait_for_completion_timeout(&ddata->hpd_completion,
- msecs_to_jiffies(250));
- WARN_ON_ONCE(to == 0);
- }
-
return 0;
}
@@ -179,11 +143,20 @@ static int tpd_read_edid(struct omap_dss_device *dssdev,
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
struct omap_dss_device *in = ddata->in;
+ int r;
if (!gpio_get_value_cansleep(ddata->hpd_gpio))
return -ENODEV;
- return in->ops.hdmi->read_edid(in, edid, len);
+ if (gpio_is_valid(ddata->ls_oe_gpio))
+ gpio_set_value_cansleep(ddata->ls_oe_gpio, 1);
+
+ r = in->ops.hdmi->read_edid(in, edid, len);
+
+ if (gpio_is_valid(ddata->ls_oe_gpio))
+ gpio_set_value_cansleep(ddata->ls_oe_gpio, 0);
+
+ return r;
}
static bool tpd_detect(struct omap_dss_device *dssdev)
@@ -309,8 +282,6 @@ static int tpd_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, ddata);
- init_completion(&ddata->hpd_completion);
-
if (dev_get_platdata(&pdev->dev)) {
r = tpd_probe_pdata(pdev);
if (r)
@@ -340,13 +311,6 @@ static int tpd_probe(struct platform_device *pdev)
if (r)
goto err_gpio;
- r = devm_request_threaded_irq(&pdev->dev, gpio_to_irq(ddata->hpd_gpio),
- NULL, tpd_hpd_irq_handler,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING |
- IRQF_ONESHOT, "hpd", ddata);
- if (r)
- goto err_irq;
-
dssdev = &ddata->dssdev;
dssdev->ops.hdmi = &tpd_hdmi_ops;
dssdev->dev = &pdev->dev;
@@ -365,7 +329,6 @@ static int tpd_probe(struct platform_device *pdev)
return 0;
err_reg:
-err_irq:
err_gpio:
omap_dss_put_device(ddata->in);
return r;
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile
index 2ea9d382354c..b5136d3d4b77 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 pll.o
+ output.o dss-of.o pll.o video-pll.o
# DSS compat layer files
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c
index 9850d9ef9a9d..31b743c70272 100644
--- a/drivers/video/fbdev/omap2/dss/dispc.c
+++ b/drivers/video/fbdev/omap2/dss/dispc.c
@@ -36,6 +36,9 @@
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/sizes.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
#include <video/omapdss.h>
@@ -117,6 +120,9 @@ static struct {
const struct dispc_features *feat;
bool is_enabled;
+
+ struct regmap *syscon_pol;
+ u32 syscon_pol_offset;
} dispc;
enum omap_color_component {
@@ -2958,6 +2964,25 @@ static void _dispc_mgr_set_lcd_timings(enum omap_channel channel, int hsw,
FLD_VAL(vsync_level, 12, 12);
dispc_write_reg(DISPC_POL_FREQ(channel), l);
+
+ if (dispc.syscon_pol) {
+ const int shifts[] = {
+ [OMAP_DSS_CHANNEL_LCD] = 0,
+ [OMAP_DSS_CHANNEL_LCD2] = 1,
+ [OMAP_DSS_CHANNEL_LCD3] = 2,
+ };
+
+ u32 mask, val;
+
+ mask = (1 << 0) | (1 << 3) | (1 << 6);
+ val = (rf << 0) | (ipc << 3) | (onoff << 6);
+
+ mask <<= 16 + shifts[channel];
+ val <<= 16 + shifts[channel];
+
+ regmap_update_bits(dispc.syscon_pol, dispc.syscon_pol_offset,
+ mask, val);
+ }
}
/* change name to mode? */
@@ -3037,10 +3062,16 @@ unsigned long dispc_fclk_rate(void)
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi0");
+ if (!pll)
+ pll = dss_pll_find("video0");
+
r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi1");
+ if (!pll)
+ pll = dss_pll_find("video1");
+
r = pll->cinfo.clkout[0];
break;
default:
@@ -3069,10 +3100,16 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi0");
+ if (!pll)
+ pll = dss_pll_find("video0");
+
r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
pll = dss_pll_find("dsi1");
+ if (!pll)
+ pll = dss_pll_find("video1");
+
r = pll->cinfo.clkout[0];
break;
default:
@@ -3668,6 +3705,7 @@ static int __init dispc_init_features(struct platform_device *pdev)
break;
case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
src = &omap54xx_dispc_feats;
break;
@@ -3728,6 +3766,7 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
u32 rev;
int r = 0;
struct resource *dispc_mem;
+ struct device_node *np = pdev->dev.of_node;
dispc.pdev = pdev;
@@ -3754,6 +3793,20 @@ static int __init omap_dispchw_probe(struct platform_device *pdev)
return -ENODEV;
}
+ if (np && of_property_read_bool(np, "syscon-pol")) {
+ dispc.syscon_pol = syscon_regmap_lookup_by_phandle(np, "syscon-pol");
+ if (IS_ERR(dispc.syscon_pol)) {
+ dev_err(&pdev->dev, "failed to get syscon-pol regmap\n");
+ return PTR_ERR(dispc.syscon_pol);
+ }
+
+ if (of_property_read_u32_index(np, "syscon-pol", 1,
+ &dispc.syscon_pol_offset)) {
+ dev_err(&pdev->dev, "failed to get syscon-pol offset\n");
+ return -EINVAL;
+ }
+ }
+
pm_runtime_enable(&pdev->dev);
r = dispc_runtime_get();
@@ -3832,6 +3885,7 @@ static const struct of_device_id dispc_of_match[] = {
{ .compatible = "ti,omap3-dispc", },
{ .compatible = "ti,omap4-dispc", },
{ .compatible = "ti,omap5-dispc", },
+ { .compatible = "ti,dra7-dispc", },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c
index 9a2f8c3b102d..f83e7b030249 100644
--- a/drivers/video/fbdev/omap2/dss/dpi.c
+++ b/drivers/video/fbdev/omap2/dss/dpi.c
@@ -106,6 +106,17 @@ static struct dss_pll *dpi_get_pll(enum omap_channel channel)
return NULL;
}
+ case OMAPDSS_VER_DRA7xx:
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ case OMAP_DSS_CHANNEL_LCD2:
+ return dss_pll_find("video0");
+ case OMAP_DSS_CHANNEL_LCD3:
+ return dss_pll_find("video1");
+ default:
+ return NULL;
+ }
+
default:
return NULL;
}
@@ -590,6 +601,10 @@ static void dpi_init_pll(struct dpi_data *dpi)
if (!pll)
return;
+ /* On DRA7 we need to set a mux to use the PLL */
+ if (omapdss_get_version() == OMAPDSS_VER_DRA7xx)
+ dss_ctrl_pll_set_control_mux(pll->id, dpi->output.dispc_channel);
+
if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n");
return;
@@ -615,6 +630,17 @@ static enum omap_channel dpi_get_channel(int port_num)
case OMAPDSS_VER_AM43xx:
return OMAP_DSS_CHANNEL_LCD;
+ case OMAPDSS_VER_DRA7xx:
+ switch (port_num) {
+ case 2:
+ return OMAP_DSS_CHANNEL_LCD3;
+ case 1:
+ return OMAP_DSS_CHANNEL_LCD2;
+ case 0:
+ default:
+ return OMAP_DSS_CHANNEL_LCD;
+ }
+
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c
index 3e44c580b1f8..5081f6fb1737 100644
--- a/drivers/video/fbdev/omap2/dss/dsi.c
+++ b/drivers/video/fbdev/omap2/dss/dsi.c
@@ -5238,6 +5238,7 @@ static int dsi_init_pll_data(struct platform_device *dsidev)
}
pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
+ pll->id = dsi->module_id == 0 ? DSS_PLL_DSI1 : DSS_PLL_DSI2;
pll->clkin = clk;
pll->base = dsi->pll_base;
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
index 9987154d50b4..a6d10d4279f3 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -34,7 +34,10 @@
#include <linux/pm_runtime.h>
#include <linux/gfp.h>
#include <linux/sizes.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
#include <linux/of.h>
+#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
@@ -63,14 +66,11 @@ struct dss_reg {
#define REG_FLD_MOD(idx, val, start, end) \
dss_write_reg(idx, FLD_MOD(dss_read_reg(idx), val, start, end))
-static int dss_runtime_get(void);
-static void dss_runtime_put(void);
-
struct dss_features {
u8 fck_div_max;
u8 dss_fck_multiplier;
const char *parent_clk_name;
- enum omap_display_type *ports;
+ const enum omap_display_type *ports;
int num_ports;
int (*dpi_select_source)(int port, enum omap_channel channel);
};
@@ -78,6 +78,8 @@ struct dss_features {
static struct {
struct platform_device *pdev;
void __iomem *base;
+ struct regmap *syscon_pll_ctrl;
+ u32 syscon_pll_ctrl_offset;
struct clk *parent_clk;
struct clk *dss_clk;
@@ -95,6 +97,9 @@ static struct {
u32 ctx[DSS_SZ_REGS / sizeof(u32)];
const struct dss_features *feat;
+
+ struct dss_pll *video1_pll;
+ struct dss_pll *video2_pll;
} dss;
static const char * const dss_generic_clk_source_names[] = {
@@ -158,6 +163,99 @@ static void dss_restore_context(void)
#undef SR
#undef RR
+void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable)
+{
+ unsigned shift;
+ unsigned val;
+
+ if (!dss.syscon_pll_ctrl)
+ return;
+
+ val = !enable;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ shift = 0;
+ break;
+ case DSS_PLL_VIDEO2:
+ shift = 1;
+ break;
+ case DSS_PLL_HDMI:
+ shift = 2;
+ break;
+ default:
+ DSSERR("illegal DSS PLL ID %d\n", pll_id);
+ return;
+ }
+
+ regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
+ 1 << shift, val << shift);
+}
+
+void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
+ enum omap_channel channel)
+{
+ unsigned shift, val;
+
+ if (!dss.syscon_pll_ctrl)
+ return;
+
+ switch (channel) {
+ case OMAP_DSS_CHANNEL_LCD:
+ shift = 3;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ val = 0; break;
+ case DSS_PLL_HDMI:
+ val = 1; break;
+ default:
+ DSSERR("error in PLL mux config for LCD\n");
+ return;
+ }
+
+ break;
+ case OMAP_DSS_CHANNEL_LCD2:
+ shift = 5;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ val = 0; break;
+ case DSS_PLL_VIDEO2:
+ val = 1; break;
+ case DSS_PLL_HDMI:
+ val = 2; break;
+ default:
+ DSSERR("error in PLL mux config for LCD2\n");
+ return;
+ }
+
+ break;
+ case OMAP_DSS_CHANNEL_LCD3:
+ shift = 7;
+
+ switch (pll_id) {
+ case DSS_PLL_VIDEO1:
+ val = 1; break;
+ case DSS_PLL_VIDEO2:
+ val = 0; break;
+ case DSS_PLL_HDMI:
+ val = 2; break;
+ default:
+ DSSERR("error in PLL mux config for LCD3\n");
+ return;
+ }
+
+ break;
+ default:
+ DSSERR("error in PLL mux config\n");
+ return;
+ }
+
+ regmap_update_bits(dss.syscon_pll_ctrl, dss.syscon_pll_ctrl_offset,
+ 0x3 << shift, val << shift);
+}
+
void dss_sdi_init(int datapairs)
{
u32 l;
@@ -605,6 +703,26 @@ static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
return 0;
}
+static int dss_dpi_select_source_dra7xx(int port, enum omap_channel channel)
+{
+ switch (port) {
+ case 0:
+ return dss_dpi_select_source_omap5(port, channel);
+ case 1:
+ if (channel != OMAP_DSS_CHANNEL_LCD2)
+ return -EINVAL;
+ break;
+ case 2:
+ if (channel != OMAP_DSS_CHANNEL_LCD3)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
int dss_dpi_select_source(int port, enum omap_channel channel)
{
return dss.feat->dpi_select_source(port, channel);
@@ -643,7 +761,7 @@ static void dss_put_clocks(void)
clk_put(dss.parent_clk);
}
-static int dss_runtime_get(void)
+int dss_runtime_get(void)
{
int r;
@@ -654,7 +772,7 @@ static int dss_runtime_get(void)
return r < 0 ? r : 0;
}
-static void dss_runtime_put(void)
+void dss_runtime_put(void)
{
int r;
@@ -677,15 +795,21 @@ void dss_debug_dump_clocks(struct seq_file *s)
#endif
-static enum omap_display_type omap2plus_ports[] = {
+static const enum omap_display_type omap2plus_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
};
-static enum omap_display_type omap34xx_ports[] = {
+static const enum omap_display_type omap34xx_ports[] = {
OMAP_DISPLAY_TYPE_DPI,
OMAP_DISPLAY_TYPE_SDI,
};
+static const enum omap_display_type dra7xx_ports[] = {
+ OMAP_DISPLAY_TYPE_DPI,
+ OMAP_DISPLAY_TYPE_DPI,
+ OMAP_DISPLAY_TYPE_DPI,
+};
+
static const struct dss_features omap24xx_dss_feats __initconst = {
/*
* fck div max is really 16, but the divider range has gaps. The range
@@ -744,6 +868,15 @@ static const struct dss_features am43xx_dss_feats __initconst = {
.num_ports = ARRAY_SIZE(omap2plus_ports),
};
+static const struct dss_features dra7xx_dss_feats __initconst = {
+ .fck_div_max = 64,
+ .dss_fck_multiplier = 1,
+ .parent_clk_name = "dpll_per_x2_ck",
+ .dpi_select_source = &dss_dpi_select_source_dra7xx,
+ .ports = dra7xx_ports,
+ .num_ports = ARRAY_SIZE(dra7xx_ports),
+};
+
static int __init dss_init_features(struct platform_device *pdev)
{
const struct dss_features *src;
@@ -784,6 +917,10 @@ static int __init dss_init_features(struct platform_device *pdev)
src = &am43xx_dss_feats;
break;
+ case OMAPDSS_VER_DRA7xx:
+ src = &dra7xx_dss_feats;
+ break;
+
default:
return -ENODEV;
}
@@ -884,8 +1021,10 @@ static void __exit dss_uninit_ports(struct platform_device *pdev)
static int __init omap_dsshw_probe(struct platform_device *pdev)
{
struct resource *dss_mem;
+ struct device_node *np = pdev->dev.of_node;
u32 rev;
int r;
+ struct regulator *pll_regulator;
dss.pdev = pdev;
@@ -940,6 +1079,57 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
dss_init_ports(pdev);
+ if (np && of_property_read_bool(np, "syscon-pll-ctrl")) {
+ dss.syscon_pll_ctrl = syscon_regmap_lookup_by_phandle(np,
+ "syscon-pll-ctrl");
+ if (IS_ERR(dss.syscon_pll_ctrl)) {
+ dev_err(&pdev->dev,
+ "failed to get syscon-pll-ctrl regmap\n");
+ return PTR_ERR(dss.syscon_pll_ctrl);
+ }
+
+ if (of_property_read_u32_index(np, "syscon-pll-ctrl", 1,
+ &dss.syscon_pll_ctrl_offset)) {
+ dev_err(&pdev->dev,
+ "failed to get syscon-pll-ctrl offset\n");
+ return -EINVAL;
+ }
+ }
+
+ pll_regulator = devm_regulator_get(&pdev->dev, "vdda_video");
+ if (IS_ERR(pll_regulator)) {
+ r = PTR_ERR(pll_regulator);
+
+ switch (r) {
+ case -ENOENT:
+ pll_regulator = NULL;
+ break;
+
+ case -EPROBE_DEFER:
+ return -EPROBE_DEFER;
+
+ default:
+ DSSERR("can't get DPLL VDDA regulator\n");
+ return r;
+ }
+ }
+
+ if (of_property_match_string(np, "reg-names", "pll1") >= 0) {
+ dss.video1_pll = dss_video_pll_init(pdev, 0, pll_regulator);
+ if (IS_ERR(dss.video1_pll)) {
+ r = PTR_ERR(dss.video1_pll);
+ goto err_pll_init;
+ }
+ }
+
+ if (of_property_match_string(np, "reg-names", "pll2") >= 0) {
+ dss.video2_pll = dss_video_pll_init(pdev, 1, pll_regulator);
+ if (IS_ERR(dss.video2_pll)) {
+ r = PTR_ERR(dss.video2_pll);
+ goto err_pll_init;
+ }
+ }
+
rev = dss_read_reg(DSS_REVISION);
printk(KERN_INFO "OMAP DSS rev %d.%d\n",
FLD_GET(rev, 7, 4), FLD_GET(rev, 3, 0));
@@ -950,6 +1140,12 @@ static int __init omap_dsshw_probe(struct platform_device *pdev)
return 0;
+err_pll_init:
+ if (dss.video1_pll)
+ dss_video_pll_uninit(dss.video1_pll);
+
+ if (dss.video2_pll)
+ dss_video_pll_uninit(dss.video2_pll);
err_runtime_get:
pm_runtime_disable(&pdev->dev);
err_setup_clocks:
@@ -959,6 +1155,12 @@ err_setup_clocks:
static int __exit omap_dsshw_remove(struct platform_device *pdev)
{
+ if (dss.video1_pll)
+ dss_video_pll_uninit(dss.video1_pll);
+
+ if (dss.video2_pll)
+ dss_video_pll_uninit(dss.video2_pll);
+
dss_uninit_ports(pdev);
pm_runtime_disable(&pdev->dev);
@@ -1003,6 +1205,7 @@ static const struct of_device_id dss_of_match[] = {
{ .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-dss", },
+ { .compatible = "ti,dra7-dss", },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h
index 14fb0c23f4a2..4812eee2622a 100644
--- a/drivers/video/fbdev/omap2/dss/dss.h
+++ b/drivers/video/fbdev/omap2/dss/dss.h
@@ -100,6 +100,14 @@ enum dss_writeback_channel {
DSS_WB_LCD3_MGR = 7,
};
+enum dss_pll_id {
+ DSS_PLL_DSI1,
+ DSS_PLL_DSI2,
+ DSS_PLL_HDMI,
+ DSS_PLL_VIDEO1,
+ DSS_PLL_VIDEO2,
+};
+
struct dss_pll;
#define DSS_PLL_MAX_HSDIVS 4
@@ -150,6 +158,7 @@ struct dss_pll_hw {
struct dss_pll {
const char *name;
+ enum dss_pll_id id;
struct clk *clkin;
struct regulator *regulator;
@@ -250,6 +259,9 @@ void dss_overlay_kobj_uninit(struct omap_overlay *ovl);
int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
+int dss_runtime_get(void);
+void dss_runtime_put(void);
+
unsigned long dss_get_dispc_clk_rate(void);
int dss_dpi_select_source(int port, enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
@@ -257,6 +269,11 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s);
+/* DSS VIDEO PLL */
+struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
+ struct regulator *regulator);
+void dss_video_pll_uninit(struct dss_pll *pll);
+
/* dss-of */
struct device_node *dss_of_port_get_parent_device(struct device_node *port);
u32 dss_of_port_get_port_number(struct device_node *port);
@@ -265,6 +282,10 @@ u32 dss_of_port_get_port_number(struct device_node *port);
void dss_debug_dump_clocks(struct seq_file *s);
#endif
+void dss_ctrl_pll_enable(enum dss_pll_id pll_id, bool enable);
+void dss_ctrl_pll_set_control_mux(enum dss_pll_id pll_id,
+ enum omap_channel channel);
+
void dss_sdi_init(int datapairs);
int dss_sdi_enable(void);
void dss_sdi_disable(void);
@@ -446,5 +467,6 @@ int dss_pll_write_config_type_a(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
int dss_pll_write_config_type_b(struct dss_pll *pll,
const struct dss_pll_clock_info *cinfo);
+int dss_pll_wait_reset_done(struct dss_pll *pll);
#endif
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c
index 0e3da809473c..376270b777f8 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.c
+++ b/drivers/video/fbdev/omap2/dss/dss_features.c
@@ -223,7 +223,7 @@ static const enum omap_dss_output_id omap5_dss_supported_outputs[] = {
OMAP_DSS_OUTPUT_DSI1 | OMAP_DSS_OUTPUT_DSI2,
/* OMAP_DSS_CHANNEL_DIGIT */
- OMAP_DSS_OUTPUT_HDMI | OMAP_DSS_OUTPUT_DPI,
+ OMAP_DSS_OUTPUT_HDMI,
/* OMAP_DSS_CHANNEL_LCD2 */
OMAP_DSS_OUTPUT_DPI | OMAP_DSS_OUTPUT_DBI |
@@ -943,6 +943,7 @@ void dss_features_init(enum omapdss_version version)
break;
case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
omap_current_dss_features = &omap5_dss_features;
break;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c
index 39aae3aa7136..3f0b34a7031a 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5.c
@@ -787,6 +787,7 @@ static const struct dev_pm_ops hdmi_pm_ops = {
static const struct of_device_id hdmi_of_match[] = {
{ .compatible = "ti,omap5-hdmi", },
+ { .compatible = "ti,dra7-hdmi", },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
index bc9e07d2afbe..1f5d19c119ce 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
@@ -208,6 +208,7 @@ static int hdmi_phy_init_features(struct platform_device *pdev)
break;
case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
src = &omap54xx_phy_feats;
break;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index ac83ef5cfd7d..06e23a7c432c 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -104,6 +104,8 @@ static int hdmi_pll_enable(struct dss_pll *dsspll)
struct hdmi_wp_data *wp = pll->wp;
u16 r = 0;
+ dss_ctrl_pll_enable(DSS_PLL_HDMI, true);
+
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
if (r)
return r;
@@ -117,6 +119,8 @@ static void hdmi_pll_disable(struct dss_pll *dsspll)
struct hdmi_wp_data *wp = pll->wp;
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
+
+ dss_ctrl_pll_enable(DSS_PLL_HDMI, false);
}
static const struct dss_pll_ops dsi_pll_ops = {
@@ -185,6 +189,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
}
pll->name = "hdmi";
+ pll->id = DSS_PLL_HDMI;
pll->base = hpll->base;
pll->clkin = clk;
@@ -196,6 +201,7 @@ static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data
break;
case OMAPDSS_VER_OMAP5:
+ case OMAPDSS_VER_DRA7xx:
pll->hw = &dss_omap5_hdmi_pll_hw;
break;
diff --git a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
index 2f0822ee3ff9..42b87f95267c 100644
--- a/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
+++ b/drivers/video/fbdev/omap2/dss/omapdss-boot-init.c
@@ -186,6 +186,7 @@ static const struct of_device_id omapdss_of_match[] __initconst = {
{ .compatible = "ti,omap3-dss", },
{ .compatible = "ti,omap4-dss", },
{ .compatible = "ti,omap5-dss", },
+ { .compatible = "ti,dra7-dss", },
{},
};
diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/video/fbdev/omap2/dss/pll.c
index 335ffac224b9..f974ddcd3b6e 100644
--- a/drivers/video/fbdev/omap2/dss/pll.c
+++ b/drivers/video/fbdev/omap2/dss/pll.c
@@ -222,6 +222,16 @@ static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
return !value;
}
+int dss_pll_wait_reset_done(struct dss_pll *pll)
+{
+ void __iomem *base = pll->base;
+
+ if (wait_for_bit_change(base + PLL_STATUS, 0, 1) != 1)
+ return -ETIMEDOUT;
+ else
+ return 0;
+}
+
static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
{
int t = 100;
diff --git a/drivers/video/fbdev/omap2/dss/video-pll.c b/drivers/video/fbdev/omap2/dss/video-pll.c
new file mode 100644
index 000000000000..b1ec59e42940
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/video-pll.c
@@ -0,0 +1,211 @@
+/*
+* Copyright (C) 2014 Texas Instruments Ltd
+*
+* This program is free software; you can redistribute it and/or modify it
+* under the terms of the GNU General Public License version 2 as published by
+* the Free Software Foundation.
+*
+* You should have received a copy of the GNU General Public License along with
+* this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/platform_device.h>
+#include <linux/sched.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+#include "dss_features.h"
+
+struct dss_video_pll {
+ struct dss_pll pll;
+
+ struct device *dev;
+
+ void __iomem *clkctrl_base;
+};
+
+#define REG_MOD(reg, val, start, end) \
+ writel_relaxed(FLD_MOD(readl_relaxed(reg), val, start, end), reg)
+
+static void dss_dpll_enable_scp_clk(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 1, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dss_dpll_disable_scp_clk(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 0, 14, 14); /* CIO_CLK_ICG */
+}
+
+static void dss_dpll_power_enable(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 2, 31, 30); /* PLL_POWER_ON_ALL */
+
+ /*
+ * DRA7x PLL CTRL's PLL_PWR_STATUS seems to always return 0,
+ * so we have to use fixed delay here.
+ */
+ msleep(1);
+}
+
+static void dss_dpll_power_disable(struct dss_video_pll *vpll)
+{
+ REG_MOD(vpll->clkctrl_base, 0, 31, 30); /* PLL_POWER_OFF */
+}
+
+static int dss_video_pll_enable(struct dss_pll *pll)
+{
+ struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
+ int r;
+
+ r = dss_runtime_get();
+ if (r)
+ return r;
+
+ dss_ctrl_pll_enable(pll->id, true);
+
+ dss_dpll_enable_scp_clk(vpll);
+
+ r = dss_pll_wait_reset_done(pll);
+ if (r)
+ goto err_reset;
+
+ dss_dpll_power_enable(vpll);
+
+ return 0;
+
+err_reset:
+ dss_dpll_disable_scp_clk(vpll);
+ dss_ctrl_pll_enable(pll->id, false);
+ dss_runtime_put();
+
+ return r;
+}
+
+static void dss_video_pll_disable(struct dss_pll *pll)
+{
+ struct dss_video_pll *vpll = container_of(pll, struct dss_video_pll, pll);
+
+ dss_dpll_power_disable(vpll);
+
+ dss_dpll_disable_scp_clk(vpll);
+
+ dss_ctrl_pll_enable(pll->id, false);
+
+ dss_runtime_put();
+}
+
+static const struct dss_pll_ops dss_pll_ops = {
+ .enable = dss_video_pll_enable,
+ .disable = dss_video_pll_disable,
+ .set_config = dss_pll_write_config_type_a,
+};
+
+static const struct dss_pll_hw dss_dra7_video_pll_hw = {
+ .n_max = (1 << 8) - 1,
+ .m_max = (1 << 12) - 1,
+ .mX_max = (1 << 5) - 1,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 25,
+ .mX_lsb[0] = 21,
+ .mX_msb[1] = 30,
+ .mX_lsb[1] = 26,
+
+ .has_refsel = true,
+};
+
+struct dss_pll *dss_video_pll_init(struct platform_device *pdev, int id,
+ struct regulator *regulator)
+{
+ const char * const reg_name[] = { "pll1", "pll2" };
+ const char * const clkctrl_name[] = { "pll1_clkctrl", "pll2_clkctrl" };
+ const char * const clkin_name[] = { "video1_clk", "video2_clk" };
+
+ struct resource *res;
+ struct dss_video_pll *vpll;
+ void __iomem *pll_base, *clkctrl_base;
+ struct clk *clk;
+ struct dss_pll *pll;
+ int r;
+
+ /* PLL CONTROL */
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, reg_name[id]);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "missing platform resource data for pll%d\n", id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ pll_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pll_base)) {
+ dev_err(&pdev->dev, "failed to ioremap pll%d reg_name\n", id);
+ return ERR_CAST(pll_base);
+ }
+
+ /* CLOCK CONTROL */
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM,
+ clkctrl_name[id]);
+ if (!res) {
+ dev_err(&pdev->dev,
+ "missing platform resource data for pll%d\n", id);
+ return ERR_PTR(-ENODEV);
+ }
+
+ clkctrl_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(clkctrl_base)) {
+ dev_err(&pdev->dev, "failed to ioremap pll%d clkctrl\n", id);
+ return ERR_CAST(clkctrl_base);
+ }
+
+ /* CLKIN */
+
+ clk = devm_clk_get(&pdev->dev, clkin_name[id]);
+ if (IS_ERR(clk)) {
+ DSSERR("can't get video pll clkin\n");
+ return ERR_CAST(clk);
+ }
+
+ vpll = devm_kzalloc(&pdev->dev, sizeof(*vpll), GFP_KERNEL);
+ if (!vpll)
+ return ERR_PTR(-ENOMEM);
+
+ vpll->dev = &pdev->dev;
+ vpll->clkctrl_base = clkctrl_base;
+
+ pll = &vpll->pll;
+
+ pll->name = id == 0 ? "video0" : "video1";
+ pll->id = id == 0 ? DSS_PLL_VIDEO1 : DSS_PLL_VIDEO2;
+ pll->clkin = clk;
+ pll->regulator = regulator;
+ pll->base = pll_base;
+ pll->hw = &dss_dra7_video_pll_hw;
+ pll->ops = &dss_pll_ops;
+
+ r = dss_pll_register(pll);
+ if (r)
+ return ERR_PTR(r);
+
+ return pll;
+}
+
+void dss_video_pll_uninit(struct dss_pll *pll)
+{
+ dss_pll_unregister(pll);
+}
diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
index 146b6f5428db..9ddfdd63b84c 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-ioctl.c
@@ -137,8 +137,11 @@ static int omapfb_setup_plane(struct fb_info *fbi, struct omapfb_plane_info *pi)
goto undo;
}
- if (ovl->manager)
- ovl->manager->apply(ovl->manager);
+ if (ovl->manager) {
+ r = ovl->manager->apply(ovl->manager);
+ if (r)
+ goto undo;
+ }
if (pi->enabled) {
r = ovl->enable(ovl);
diff --git a/drivers/video/fbdev/pvr2fb.c b/drivers/video/fbdev/pvr2fb.c
index 7c74f58fc101..0e24eb9c219c 100644
--- a/drivers/video/fbdev/pvr2fb.c
+++ b/drivers/video/fbdev/pvr2fb.c
@@ -686,10 +686,8 @@ static ssize_t pvr2fb_write(struct fb_info *info, const char *buf,
if (!pages)
return -ENOMEM;
- down_read(&current->mm->mmap_sem);
- ret = get_user_pages(current, current->mm, (unsigned long)buf,
- nr_pages, WRITE, 0, pages, NULL);
- up_read(&current->mm->mmap_sem);
+ ret = get_user_pages_unlocked(current, current->mm, (unsigned long)buf,
+ nr_pages, WRITE, 0, pages);
if (ret < nr_pages) {
nr_pages = ret;
diff --git a/drivers/video/fbdev/savage/savagefb.h b/drivers/video/fbdev/savage/savagefb.h
index dcaab9012ca2..8ff4ab1cb69b 100644
--- a/drivers/video/fbdev/savage/savagefb.h
+++ b/drivers/video/fbdev/savage/savagefb.h
@@ -351,32 +351,26 @@ static inline void VGAwSEQ(u8 index, u8 val, struct savagefb_par *par)
static inline void VGAenablePalette(struct savagefb_par *par)
{
- u8 tmp;
-
- tmp = vga_in8(0x3da, par);
+ vga_in8(0x3da, par);
vga_out8(0x3c0, 0x00, par);
par->paletteEnabled = 1;
}
static inline void VGAdisablePalette(struct savagefb_par *par)
{
- u8 tmp;
-
- tmp = vga_in8(0x3da, par);
+ vga_in8(0x3da, par);
vga_out8(0x3c0, 0x20, par);
par->paletteEnabled = 0;
}
static inline void VGAwATTR(u8 index, u8 value, struct savagefb_par *par)
{
- u8 tmp;
-
if (par->paletteEnabled)
index &= ~0x20;
else
index |= 0x20;
- tmp = vga_in8(0x3da, par);
+ vga_in8(0x3da, par);
vga_out8(0x3c0, index, par);
vga_out8 (0x3c0, value, par);
}
diff --git a/drivers/video/fbdev/ssd1307fb.c b/drivers/video/fbdev/ssd1307fb.c
index f4daa59f0a80..f7ed6d9016f7 100644
--- a/drivers/video/fbdev/ssd1307fb.c
+++ b/drivers/video/fbdev/ssd1307fb.c
@@ -122,23 +122,6 @@ static inline int ssd1307fb_write_cmd(struct i2c_client *client, u8 cmd)
return ret;
}
-static inline int ssd1307fb_write_data(struct i2c_client *client, u8 data)
-{
- struct ssd1307fb_array *array;
- int ret;
-
- array = ssd1307fb_alloc_array(1, SSD1307FB_DATA);
- if (!array)
- return -ENOMEM;
-
- array->data[0] = data;
-
- ret = ssd1307fb_write_array(client, array, 1);
- kfree(array);
-
- return ret;
-}
-
static void ssd1307fb_update_display(struct ssd1307fb_par *par)
{
struct ssd1307fb_array *array;
@@ -320,7 +303,10 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
/* Set initial contrast */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CONTRAST);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x7f);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x7f);
if (ret < 0)
return ret;
@@ -336,63 +322,99 @@ static int ssd1307fb_ssd1306_init(struct ssd1307fb_par *par)
/* Set multiplex ratio value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_MULTIPLEX_RATIO);
- ret = ret & ssd1307fb_write_cmd(par->client, par->height - 1);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, par->height - 1);
if (ret < 0)
return ret;
/* set display offset value */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_DISPLAY_OFFSET);
+ if (ret < 0)
+ return ret;
+
ret = ssd1307fb_write_cmd(par->client, 0x20);
if (ret < 0)
return ret;
/* Set clock frequency */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_CLOCK_FREQ);
- ret = ret & ssd1307fb_write_cmd(par->client, 0xf0);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0xf0);
if (ret < 0)
return ret;
/* Set precharge period in number of ticks from the internal clock */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PRECHARGE_PERIOD);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x22);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x22);
if (ret < 0)
return ret;
/* Set COM pins configuration */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COM_PINS_CONFIG);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x22);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x22);
if (ret < 0)
return ret;
/* Set VCOMH */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_VCOMH);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x49);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x49);
if (ret < 0)
return ret;
/* Turn on the DC-DC Charge Pump */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_CHARGE_PUMP);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x14);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x14);
if (ret < 0)
return ret;
/* Switch to horizontal addressing mode */
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_ADDRESS_MODE);
- ret = ret & ssd1307fb_write_cmd(par->client,
- SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client,
+ SSD1307FB_SET_ADDRESS_MODE_HORIZONTAL);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_COL_RANGE);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x0);
- ret = ret & ssd1307fb_write_cmd(par->client, par->width - 1);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x0);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, par->width - 1);
if (ret < 0)
return ret;
ret = ssd1307fb_write_cmd(par->client, SSD1307FB_SET_PAGE_RANGE);
- ret = ret & ssd1307fb_write_cmd(par->client, 0x0);
- ret = ret & ssd1307fb_write_cmd(par->client,
- par->page_offset + (par->height / 8) - 1);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client, 0x0);
+ if (ret < 0)
+ return ret;
+
+ ret = ssd1307fb_write_cmd(par->client,
+ par->page_offset + (par->height / 8) - 1);
if (ret < 0)
return ret;
@@ -460,7 +482,7 @@ static int ssd1307fb_probe(struct i2c_client *client,
par->width = 96;
if (of_property_read_u32(node, "solomon,height", &par->height))
- par->width = 16;
+ par->height = 16;
if (of_property_read_u32(node, "solomon,page-offset", &par->page_offset))
par->page_offset = 1;
diff --git a/drivers/video/fbdev/vt8500lcdfb.c b/drivers/video/fbdev/vt8500lcdfb.c
index ffaf29eeaaba..1a1176bf0906 100644
--- a/drivers/video/fbdev/vt8500lcdfb.c
+++ b/drivers/video/fbdev/vt8500lcdfb.c
@@ -113,10 +113,8 @@ static int vt8500lcd_set_par(struct fb_info *info)
}
for (i = 0; i < 8; i++) {
- if (bpp_values[i] == info->var.bits_per_pixel) {
+ if (bpp_values[i] == info->var.bits_per_pixel)
reg_bpp = i;
- continue;
- }
}
control0 = readl(fbi->regbase) & ~0xf;
diff --git a/drivers/video/hdmi.c b/drivers/video/hdmi.c
index 9e758a8f890d..162689227a23 100644
--- a/drivers/video/hdmi.c
+++ b/drivers/video/hdmi.c
@@ -27,10 +27,12 @@
#include <linux/export.h>
#include <linux/hdmi.h>
#include <linux/string.h>
+#include <linux/device.h>
-static void hdmi_infoframe_checksum(void *buffer, size_t size)
+#define hdmi_log(fmt, ...) dev_printk(level, dev, fmt, ##__VA_ARGS__)
+
+static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
{
- u8 *ptr = buffer;
u8 csum = 0;
size_t i;
@@ -38,7 +40,14 @@ static void hdmi_infoframe_checksum(void *buffer, size_t size)
for (i = 0; i < size; i++)
csum += ptr[i];
- ptr[3] = 256 - csum;
+ return 256 - csum;
+}
+
+static void hdmi_infoframe_set_checksum(void *buffer, size_t size)
+{
+ u8 *ptr = buffer;
+
+ ptr[3] = hdmi_infoframe_checksum(buffer, size);
}
/**
@@ -136,7 +145,7 @@ ssize_t hdmi_avi_infoframe_pack(struct hdmi_avi_infoframe *frame, void *buffer,
ptr[11] = frame->right_bar & 0xff;
ptr[12] = (frame->right_bar >> 8) & 0xff;
- hdmi_infoframe_checksum(buffer, length);
+ hdmi_infoframe_set_checksum(buffer, length);
return length;
}
@@ -206,7 +215,7 @@ ssize_t hdmi_spd_infoframe_pack(struct hdmi_spd_infoframe *frame, void *buffer,
ptr[24] = frame->sdi;
- hdmi_infoframe_checksum(buffer, length);
+ hdmi_infoframe_set_checksum(buffer, length);
return length;
}
@@ -281,7 +290,7 @@ ssize_t hdmi_audio_infoframe_pack(struct hdmi_audio_infoframe *frame,
if (frame->downmix_inhibit)
ptr[4] |= BIT(7);
- hdmi_infoframe_checksum(buffer, length);
+ hdmi_infoframe_set_checksum(buffer, length);
return length;
}
@@ -373,7 +382,7 @@ ssize_t hdmi_vendor_infoframe_pack(struct hdmi_vendor_infoframe *frame,
ptr[9] = (frame->s3d_ext_data & 0xf) << 4;
}
- hdmi_infoframe_checksum(buffer, length);
+ hdmi_infoframe_set_checksum(buffer, length);
return length;
}
@@ -434,3 +443,802 @@ hdmi_infoframe_pack(union hdmi_infoframe *frame, void *buffer, size_t size)
return length;
}
EXPORT_SYMBOL(hdmi_infoframe_pack);
+
+static const char *hdmi_infoframe_type_get_name(enum hdmi_infoframe_type type)
+{
+ if (type < 0x80 || type > 0x9f)
+ return "Invalid";
+ switch (type) {
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ return "Vendor";
+ case HDMI_INFOFRAME_TYPE_AVI:
+ return "Auxiliary Video Information (AVI)";
+ case HDMI_INFOFRAME_TYPE_SPD:
+ return "Source Product Description (SPD)";
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ return "Audio";
+ }
+ return "Reserved";
+}
+
+static void hdmi_infoframe_log_header(const char *level,
+ struct device *dev,
+ struct hdmi_any_infoframe *frame)
+{
+ hdmi_log("HDMI infoframe: %s, version %u, length %u\n",
+ hdmi_infoframe_type_get_name(frame->type),
+ frame->version, frame->length);
+}
+
+static const char *hdmi_colorspace_get_name(enum hdmi_colorspace colorspace)
+{
+ switch (colorspace) {
+ case HDMI_COLORSPACE_RGB:
+ return "RGB";
+ case HDMI_COLORSPACE_YUV422:
+ return "YCbCr 4:2:2";
+ case HDMI_COLORSPACE_YUV444:
+ return "YCbCr 4:4:4";
+ case HDMI_COLORSPACE_YUV420:
+ return "YCbCr 4:2:0";
+ case HDMI_COLORSPACE_RESERVED4:
+ return "Reserved (4)";
+ case HDMI_COLORSPACE_RESERVED5:
+ return "Reserved (5)";
+ case HDMI_COLORSPACE_RESERVED6:
+ return "Reserved (6)";
+ case HDMI_COLORSPACE_IDO_DEFINED:
+ return "IDO Defined";
+ }
+ return "Invalid";
+}
+
+static const char *hdmi_scan_mode_get_name(enum hdmi_scan_mode scan_mode)
+{
+ switch (scan_mode) {
+ case HDMI_SCAN_MODE_NONE:
+ return "No Data";
+ case HDMI_SCAN_MODE_OVERSCAN:
+ return "Overscan";
+ case HDMI_SCAN_MODE_UNDERSCAN:
+ return "Underscan";
+ case HDMI_SCAN_MODE_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *hdmi_colorimetry_get_name(enum hdmi_colorimetry colorimetry)
+{
+ switch (colorimetry) {
+ case HDMI_COLORIMETRY_NONE:
+ return "No Data";
+ case HDMI_COLORIMETRY_ITU_601:
+ return "ITU601";
+ case HDMI_COLORIMETRY_ITU_709:
+ return "ITU709";
+ case HDMI_COLORIMETRY_EXTENDED:
+ return "Extended";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_picture_aspect_get_name(enum hdmi_picture_aspect picture_aspect)
+{
+ switch (picture_aspect) {
+ case HDMI_PICTURE_ASPECT_NONE:
+ return "No Data";
+ case HDMI_PICTURE_ASPECT_4_3:
+ return "4:3";
+ case HDMI_PICTURE_ASPECT_16_9:
+ return "16:9";
+ case HDMI_PICTURE_ASPECT_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_active_aspect_get_name(enum hdmi_active_aspect active_aspect)
+{
+ if (active_aspect < 0 || active_aspect > 0xf)
+ return "Invalid";
+
+ switch (active_aspect) {
+ case HDMI_ACTIVE_ASPECT_16_9_TOP:
+ return "16:9 Top";
+ case HDMI_ACTIVE_ASPECT_14_9_TOP:
+ return "14:9 Top";
+ case HDMI_ACTIVE_ASPECT_16_9_CENTER:
+ return "16:9 Center";
+ case HDMI_ACTIVE_ASPECT_PICTURE:
+ return "Same as Picture";
+ case HDMI_ACTIVE_ASPECT_4_3:
+ return "4:3";
+ case HDMI_ACTIVE_ASPECT_16_9:
+ return "16:9";
+ case HDMI_ACTIVE_ASPECT_14_9:
+ return "14:9";
+ case HDMI_ACTIVE_ASPECT_4_3_SP_14_9:
+ return "4:3 SP 14:9";
+ case HDMI_ACTIVE_ASPECT_16_9_SP_14_9:
+ return "16:9 SP 14:9";
+ case HDMI_ACTIVE_ASPECT_16_9_SP_4_3:
+ return "16:9 SP 4:3";
+ }
+ return "Reserved";
+}
+
+static const char *
+hdmi_extended_colorimetry_get_name(enum hdmi_extended_colorimetry ext_col)
+{
+ switch (ext_col) {
+ case HDMI_EXTENDED_COLORIMETRY_XV_YCC_601:
+ return "xvYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_XV_YCC_709:
+ return "xvYCC 709";
+ case HDMI_EXTENDED_COLORIMETRY_S_YCC_601:
+ return "sYCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601:
+ return "Adobe YCC 601";
+ case HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB:
+ return "Adobe RGB";
+ case HDMI_EXTENDED_COLORIMETRY_BT2020_CONST_LUM:
+ return "BT.2020 Constant Luminance";
+ case HDMI_EXTENDED_COLORIMETRY_BT2020:
+ return "BT.2020";
+ case HDMI_EXTENDED_COLORIMETRY_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_quantization_range_get_name(enum hdmi_quantization_range qrange)
+{
+ switch (qrange) {
+ case HDMI_QUANTIZATION_RANGE_DEFAULT:
+ return "Default";
+ case HDMI_QUANTIZATION_RANGE_LIMITED:
+ return "Limited";
+ case HDMI_QUANTIZATION_RANGE_FULL:
+ return "Full";
+ case HDMI_QUANTIZATION_RANGE_RESERVED:
+ return "Reserved";
+ }
+ return "Invalid";
+}
+
+static const char *hdmi_nups_get_name(enum hdmi_nups nups)
+{
+ switch (nups) {
+ case HDMI_NUPS_UNKNOWN:
+ return "Unknown Non-uniform Scaling";
+ case HDMI_NUPS_HORIZONTAL:
+ return "Horizontally Scaled";
+ case HDMI_NUPS_VERTICAL:
+ return "Vertically Scaled";
+ case HDMI_NUPS_BOTH:
+ return "Horizontally and Vertically Scaled";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_ycc_quantization_range_get_name(enum hdmi_ycc_quantization_range qrange)
+{
+ switch (qrange) {
+ case HDMI_YCC_QUANTIZATION_RANGE_LIMITED:
+ return "Limited";
+ case HDMI_YCC_QUANTIZATION_RANGE_FULL:
+ return "Full";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_content_type_get_name(enum hdmi_content_type content_type)
+{
+ switch (content_type) {
+ case HDMI_CONTENT_TYPE_GRAPHICS:
+ return "Graphics";
+ case HDMI_CONTENT_TYPE_PHOTO:
+ return "Photo";
+ case HDMI_CONTENT_TYPE_CINEMA:
+ return "Cinema";
+ case HDMI_CONTENT_TYPE_GAME:
+ return "Game";
+ }
+ return "Invalid";
+}
+
+/**
+ * hdmi_avi_infoframe_log() - log info of HDMI AVI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI AVI infoframe
+ */
+static void hdmi_avi_infoframe_log(const char *level,
+ struct device *dev,
+ struct hdmi_avi_infoframe *frame)
+{
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+
+ hdmi_log(" colorspace: %s\n",
+ hdmi_colorspace_get_name(frame->colorspace));
+ hdmi_log(" scan mode: %s\n",
+ hdmi_scan_mode_get_name(frame->scan_mode));
+ hdmi_log(" colorimetry: %s\n",
+ hdmi_colorimetry_get_name(frame->colorimetry));
+ hdmi_log(" picture aspect: %s\n",
+ hdmi_picture_aspect_get_name(frame->picture_aspect));
+ hdmi_log(" active aspect: %s\n",
+ hdmi_active_aspect_get_name(frame->active_aspect));
+ hdmi_log(" itc: %s\n", frame->itc ? "IT Content" : "No Data");
+ hdmi_log(" extended colorimetry: %s\n",
+ hdmi_extended_colorimetry_get_name(frame->extended_colorimetry));
+ hdmi_log(" quantization range: %s\n",
+ hdmi_quantization_range_get_name(frame->quantization_range));
+ hdmi_log(" nups: %s\n", hdmi_nups_get_name(frame->nups));
+ hdmi_log(" video code: %u\n", frame->video_code);
+ hdmi_log(" ycc quantization range: %s\n",
+ hdmi_ycc_quantization_range_get_name(frame->ycc_quantization_range));
+ hdmi_log(" hdmi content type: %s\n",
+ hdmi_content_type_get_name(frame->content_type));
+ hdmi_log(" pixel repeat: %u\n", frame->pixel_repeat);
+ hdmi_log(" bar top %u, bottom %u, left %u, right %u\n",
+ frame->top_bar, frame->bottom_bar,
+ frame->left_bar, frame->right_bar);
+}
+
+static const char *hdmi_spd_sdi_get_name(enum hdmi_spd_sdi sdi)
+{
+ if (sdi < 0 || sdi > 0xff)
+ return "Invalid";
+ switch (sdi) {
+ case HDMI_SPD_SDI_UNKNOWN:
+ return "Unknown";
+ case HDMI_SPD_SDI_DSTB:
+ return "Digital STB";
+ case HDMI_SPD_SDI_DVDP:
+ return "DVD Player";
+ case HDMI_SPD_SDI_DVHS:
+ return "D-VHS";
+ case HDMI_SPD_SDI_HDDVR:
+ return "HDD Videorecorder";
+ case HDMI_SPD_SDI_DVC:
+ return "DVC";
+ case HDMI_SPD_SDI_DSC:
+ return "DSC";
+ case HDMI_SPD_SDI_VCD:
+ return "Video CD";
+ case HDMI_SPD_SDI_GAME:
+ return "Game";
+ case HDMI_SPD_SDI_PC:
+ return "PC General";
+ case HDMI_SPD_SDI_BD:
+ return "Blu-Ray Disc (BD)";
+ case HDMI_SPD_SDI_SACD:
+ return "Super Audio CD";
+ case HDMI_SPD_SDI_HDDVD:
+ return "HD DVD";
+ case HDMI_SPD_SDI_PMP:
+ return "PMP";
+ }
+ return "Reserved";
+}
+
+/**
+ * hdmi_spd_infoframe_log() - log info of HDMI SPD infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI SPD infoframe
+ */
+static void hdmi_spd_infoframe_log(const char *level,
+ struct device *dev,
+ struct hdmi_spd_infoframe *frame)
+{
+ u8 buf[17];
+
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+
+ memset(buf, 0, sizeof(buf));
+
+ strncpy(buf, frame->vendor, 8);
+ hdmi_log(" vendor: %s\n", buf);
+ strncpy(buf, frame->product, 16);
+ hdmi_log(" product: %s\n", buf);
+ hdmi_log(" source device information: %s (0x%x)\n",
+ hdmi_spd_sdi_get_name(frame->sdi), frame->sdi);
+}
+
+static const char *
+hdmi_audio_coding_type_get_name(enum hdmi_audio_coding_type coding_type)
+{
+ switch (coding_type) {
+ case HDMI_AUDIO_CODING_TYPE_STREAM:
+ return "Refer to Stream Header";
+ case HDMI_AUDIO_CODING_TYPE_PCM:
+ return "PCM";
+ case HDMI_AUDIO_CODING_TYPE_AC3:
+ return "AC-3";
+ case HDMI_AUDIO_CODING_TYPE_MPEG1:
+ return "MPEG1";
+ case HDMI_AUDIO_CODING_TYPE_MP3:
+ return "MP3";
+ case HDMI_AUDIO_CODING_TYPE_MPEG2:
+ return "MPEG2";
+ case HDMI_AUDIO_CODING_TYPE_AAC_LC:
+ return "AAC";
+ case HDMI_AUDIO_CODING_TYPE_DTS:
+ return "DTS";
+ case HDMI_AUDIO_CODING_TYPE_ATRAC:
+ return "ATRAC";
+ case HDMI_AUDIO_CODING_TYPE_DSD:
+ return "One Bit Audio";
+ case HDMI_AUDIO_CODING_TYPE_EAC3:
+ return "Dolby Digital +";
+ case HDMI_AUDIO_CODING_TYPE_DTS_HD:
+ return "DTS-HD";
+ case HDMI_AUDIO_CODING_TYPE_MLP:
+ return "MAT (MLP)";
+ case HDMI_AUDIO_CODING_TYPE_DST:
+ return "DST";
+ case HDMI_AUDIO_CODING_TYPE_WMA_PRO:
+ return "WMA PRO";
+ case HDMI_AUDIO_CODING_TYPE_CXT:
+ return "Refer to CXT";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_audio_sample_size_get_name(enum hdmi_audio_sample_size sample_size)
+{
+ switch (sample_size) {
+ case HDMI_AUDIO_SAMPLE_SIZE_STREAM:
+ return "Refer to Stream Header";
+ case HDMI_AUDIO_SAMPLE_SIZE_16:
+ return "16 bit";
+ case HDMI_AUDIO_SAMPLE_SIZE_20:
+ return "20 bit";
+ case HDMI_AUDIO_SAMPLE_SIZE_24:
+ return "24 bit";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_audio_sample_frequency_get_name(enum hdmi_audio_sample_frequency freq)
+{
+ switch (freq) {
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM:
+ return "Refer to Stream Header";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_32000:
+ return "32 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_44100:
+ return "44.1 kHz (CD)";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_48000:
+ return "48 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_88200:
+ return "88.2 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_96000:
+ return "96 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_176400:
+ return "176.4 kHz";
+ case HDMI_AUDIO_SAMPLE_FREQUENCY_192000:
+ return "192 kHz";
+ }
+ return "Invalid";
+}
+
+static const char *
+hdmi_audio_coding_type_ext_get_name(enum hdmi_audio_coding_type_ext ctx)
+{
+ if (ctx < 0 || ctx > 0x1f)
+ return "Invalid";
+
+ switch (ctx) {
+ case HDMI_AUDIO_CODING_TYPE_EXT_CT:
+ return "Refer to CT";
+ case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC:
+ return "HE AAC";
+ case HDMI_AUDIO_CODING_TYPE_EXT_HE_AAC_V2:
+ return "HE AAC v2";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG_SURROUND:
+ return "MPEG SURROUND";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC:
+ return "MPEG-4 HE AAC";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_V2:
+ return "MPEG-4 HE AAC v2";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC:
+ return "MPEG-4 AAC LC";
+ case HDMI_AUDIO_CODING_TYPE_EXT_DRA:
+ return "DRA";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_HE_AAC_SURROUND:
+ return "MPEG-4 HE AAC + MPEG Surround";
+ case HDMI_AUDIO_CODING_TYPE_EXT_MPEG4_AAC_LC_SURROUND:
+ return "MPEG-4 AAC LC + MPEG Surround";
+ }
+ return "Reserved";
+}
+
+/**
+ * hdmi_audio_infoframe_log() - log info of HDMI AUDIO infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI AUDIO infoframe
+ */
+static void hdmi_audio_infoframe_log(const char *level,
+ struct device *dev,
+ struct hdmi_audio_infoframe *frame)
+{
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+
+ if (frame->channels)
+ hdmi_log(" channels: %u\n", frame->channels - 1);
+ else
+ hdmi_log(" channels: Refer to stream header\n");
+ hdmi_log(" coding type: %s\n",
+ hdmi_audio_coding_type_get_name(frame->coding_type));
+ hdmi_log(" sample size: %s\n",
+ hdmi_audio_sample_size_get_name(frame->sample_size));
+ hdmi_log(" sample frequency: %s\n",
+ hdmi_audio_sample_frequency_get_name(frame->sample_frequency));
+ hdmi_log(" coding type ext: %s\n",
+ hdmi_audio_coding_type_ext_get_name(frame->coding_type_ext));
+ hdmi_log(" channel allocation: 0x%x\n",
+ frame->channel_allocation);
+ hdmi_log(" level shift value: %u dB\n",
+ frame->level_shift_value);
+ hdmi_log(" downmix inhibit: %s\n",
+ frame->downmix_inhibit ? "Yes" : "No");
+}
+
+static const char *
+hdmi_3d_structure_get_name(enum hdmi_3d_structure s3d_struct)
+{
+ if (s3d_struct < 0 || s3d_struct > 0xf)
+ return "Invalid";
+
+ switch (s3d_struct) {
+ case HDMI_3D_STRUCTURE_FRAME_PACKING:
+ return "Frame Packing";
+ case HDMI_3D_STRUCTURE_FIELD_ALTERNATIVE:
+ return "Field Alternative";
+ case HDMI_3D_STRUCTURE_LINE_ALTERNATIVE:
+ return "Line Alternative";
+ case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_FULL:
+ return "Side-by-side (Full)";
+ case HDMI_3D_STRUCTURE_L_DEPTH:
+ return "L + Depth";
+ case HDMI_3D_STRUCTURE_L_DEPTH_GFX_GFX_DEPTH:
+ return "L + Depth + Graphics + Graphics-depth";
+ case HDMI_3D_STRUCTURE_TOP_AND_BOTTOM:
+ return "Top-and-Bottom";
+ case HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF:
+ return "Side-by-side (Half)";
+ default:
+ break;
+ }
+ return "Reserved";
+}
+
+/**
+ * hdmi_vendor_infoframe_log() - log info of HDMI VENDOR infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI VENDOR infoframe
+ */
+static void
+hdmi_vendor_any_infoframe_log(const char *level,
+ struct device *dev,
+ union hdmi_vendor_any_infoframe *frame)
+{
+ struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+
+ hdmi_infoframe_log_header(level, dev,
+ (struct hdmi_any_infoframe *)frame);
+
+ if (frame->any.oui != HDMI_IEEE_OUI) {
+ hdmi_log(" not a HDMI vendor infoframe\n");
+ return;
+ }
+ if (hvf->vic == 0 && hvf->s3d_struct == HDMI_3D_STRUCTURE_INVALID) {
+ hdmi_log(" empty frame\n");
+ return;
+ }
+
+ if (hvf->vic)
+ hdmi_log(" HDMI VIC: %u\n", hvf->vic);
+ if (hvf->s3d_struct != HDMI_3D_STRUCTURE_INVALID) {
+ hdmi_log(" 3D structure: %s\n",
+ hdmi_3d_structure_get_name(hvf->s3d_struct));
+ if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF)
+ hdmi_log(" 3D extension data: %d\n",
+ hvf->s3d_ext_data);
+ }
+}
+
+/**
+ * hdmi_infoframe_log() - log info of HDMI infoframe
+ * @level: logging level
+ * @dev: device
+ * @frame: HDMI infoframe
+ */
+void hdmi_infoframe_log(const char *level,
+ struct device *dev,
+ union hdmi_infoframe *frame)
+{
+ switch (frame->any.type) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ hdmi_avi_infoframe_log(level, dev, &frame->avi);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ hdmi_spd_infoframe_log(level, dev, &frame->spd);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ hdmi_audio_infoframe_log(level, dev, &frame->audio);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ hdmi_vendor_any_infoframe_log(level, dev, &frame->vendor);
+ break;
+ }
+}
+EXPORT_SYMBOL(hdmi_infoframe_log);
+
+/**
+ * hdmi_avi_infoframe_unpack() - unpack binary buffer to a HDMI AVI infoframe
+ * @buffer: source buffer
+ * @frame: HDMI AVI infoframe
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Auxiliary Video (AVI) information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_avi_infoframe_unpack(struct hdmi_avi_infoframe *frame,
+ void *buffer)
+{
+ u8 *ptr = buffer;
+ int ret;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_AVI ||
+ ptr[1] != 2 ||
+ ptr[2] != HDMI_AVI_INFOFRAME_SIZE)
+ return -EINVAL;
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AVI)) != 0)
+ return -EINVAL;
+
+ ret = hdmi_avi_infoframe_init(frame);
+ if (ret)
+ return ret;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ frame->colorspace = (ptr[0] >> 5) & 0x3;
+ if (ptr[0] & 0x10)
+ frame->active_aspect = ptr[1] & 0xf;
+ if (ptr[0] & 0x8) {
+ frame->top_bar = (ptr[5] << 8) + ptr[6];
+ frame->bottom_bar = (ptr[7] << 8) + ptr[8];
+ }
+ if (ptr[0] & 0x4) {
+ frame->left_bar = (ptr[9] << 8) + ptr[10];
+ frame->right_bar = (ptr[11] << 8) + ptr[12];
+ }
+ frame->scan_mode = ptr[0] & 0x3;
+
+ frame->colorimetry = (ptr[1] >> 6) & 0x3;
+ frame->picture_aspect = (ptr[1] >> 4) & 0x3;
+ frame->active_aspect = ptr[1] & 0xf;
+
+ frame->itc = ptr[2] & 0x80 ? true : false;
+ frame->extended_colorimetry = (ptr[2] >> 4) & 0x7;
+ frame->quantization_range = (ptr[2] >> 2) & 0x3;
+ frame->nups = ptr[2] & 0x3;
+
+ frame->video_code = ptr[3] & 0x7f;
+ frame->ycc_quantization_range = (ptr[4] >> 6) & 0x3;
+ frame->content_type = (ptr[4] >> 4) & 0x3;
+
+ frame->pixel_repeat = ptr[4] & 0xf;
+
+ return 0;
+}
+
+/**
+ * hdmi_spd_infoframe_unpack() - unpack binary buffer to a HDMI SPD infoframe
+ * @buffer: source buffer
+ * @frame: HDMI SPD infoframe
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Source Product Description (SPD) information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_spd_infoframe_unpack(struct hdmi_spd_infoframe *frame,
+ void *buffer)
+{
+ u8 *ptr = buffer;
+ int ret;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_SPD ||
+ ptr[1] != 1 ||
+ ptr[2] != HDMI_SPD_INFOFRAME_SIZE) {
+ return -EINVAL;
+ }
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(SPD)) != 0)
+ return -EINVAL;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ ret = hdmi_spd_infoframe_init(frame, ptr, ptr + 8);
+ if (ret)
+ return ret;
+
+ frame->sdi = ptr[24];
+
+ return 0;
+}
+
+/**
+ * hdmi_audio_infoframe_unpack() - unpack binary buffer to a HDMI AUDIO infoframe
+ * @buffer: source buffer
+ * @frame: HDMI Audio infoframe
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Audio information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int hdmi_audio_infoframe_unpack(struct hdmi_audio_infoframe *frame,
+ void *buffer)
+{
+ u8 *ptr = buffer;
+ int ret;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_AUDIO ||
+ ptr[1] != 1 ||
+ ptr[2] != HDMI_AUDIO_INFOFRAME_SIZE) {
+ return -EINVAL;
+ }
+
+ if (hdmi_infoframe_checksum(buffer, HDMI_INFOFRAME_SIZE(AUDIO)) != 0)
+ return -EINVAL;
+
+ ret = hdmi_audio_infoframe_init(frame);
+ if (ret)
+ return ret;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ frame->channels = ptr[0] & 0x7;
+ frame->coding_type = (ptr[0] >> 4) & 0xf;
+ frame->sample_size = ptr[1] & 0x3;
+ frame->sample_frequency = (ptr[1] >> 2) & 0x7;
+ frame->coding_type_ext = ptr[2] & 0x1f;
+ frame->channel_allocation = ptr[3];
+ frame->level_shift_value = (ptr[4] >> 3) & 0xf;
+ frame->downmix_inhibit = ptr[4] & 0x80 ? true : false;
+
+ return 0;
+}
+
+/**
+ * hdmi_vendor_infoframe_unpack() - unpack binary buffer to a HDMI vendor infoframe
+ * @buffer: source buffer
+ * @frame: HDMI Vendor infoframe
+ *
+ * Unpacks the information contained in binary @buffer into a structured
+ * @frame of the HDMI Vendor information frame.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+static int
+hdmi_vendor_any_infoframe_unpack(union hdmi_vendor_any_infoframe *frame,
+ void *buffer)
+{
+ u8 *ptr = buffer;
+ size_t length;
+ int ret;
+ u8 hdmi_video_format;
+ struct hdmi_vendor_infoframe *hvf = &frame->hdmi;
+
+ if (ptr[0] != HDMI_INFOFRAME_TYPE_VENDOR ||
+ ptr[1] != 1 ||
+ (ptr[2] != 5 && ptr[2] != 6))
+ return -EINVAL;
+
+ length = ptr[2];
+
+ if (hdmi_infoframe_checksum(buffer,
+ HDMI_INFOFRAME_HEADER_SIZE + length) != 0)
+ return -EINVAL;
+
+ ptr += HDMI_INFOFRAME_HEADER_SIZE;
+
+ /* HDMI OUI */
+ if ((ptr[0] != 0x03) ||
+ (ptr[1] != 0x0c) ||
+ (ptr[2] != 0x00))
+ return -EINVAL;
+
+ hdmi_video_format = ptr[3] >> 5;
+
+ if (hdmi_video_format > 0x2)
+ return -EINVAL;
+
+ ret = hdmi_vendor_infoframe_init(hvf);
+ if (ret)
+ return ret;
+
+ hvf->length = length;
+
+ if (hdmi_video_format == 0x1) {
+ hvf->vic = ptr[4];
+ } else if (hdmi_video_format == 0x2) {
+ hvf->s3d_struct = ptr[4] >> 4;
+ if (hvf->s3d_struct >= HDMI_3D_STRUCTURE_SIDE_BY_SIDE_HALF) {
+ if (length == 6)
+ hvf->s3d_ext_data = ptr[5] >> 4;
+ else
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * hdmi_infoframe_unpack() - unpack binary buffer to a HDMI infoframe
+ * @buffer: source buffer
+ * @frame: HDMI infoframe
+ *
+ * Unpacks the information contained in binary buffer @buffer into a structured
+ * @frame of a HDMI infoframe.
+ * Also verifies the checksum as required by section 5.3.5 of the HDMI 1.4
+ * specification.
+ *
+ * Returns 0 on success or a negative error code on failure.
+ */
+int hdmi_infoframe_unpack(union hdmi_infoframe *frame, void *buffer)
+{
+ int ret;
+ u8 *ptr = buffer;
+
+ switch (ptr[0]) {
+ case HDMI_INFOFRAME_TYPE_AVI:
+ ret = hdmi_avi_infoframe_unpack(&frame->avi, buffer);
+ break;
+ case HDMI_INFOFRAME_TYPE_SPD:
+ ret = hdmi_spd_infoframe_unpack(&frame->spd, buffer);
+ break;
+ case HDMI_INFOFRAME_TYPE_AUDIO:
+ ret = hdmi_audio_infoframe_unpack(&frame->audio, buffer);
+ break;
+ case HDMI_INFOFRAME_TYPE_VENDOR:
+ ret = hdmi_vendor_any_infoframe_unpack(&frame->vendor, buffer);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(hdmi_infoframe_unpack);
diff --git a/drivers/video/vgastate.c b/drivers/video/vgastate.c
index b91c466225b9..548c751d2415 100644
--- a/drivers/video/vgastate.c
+++ b/drivers/video/vgastate.c
@@ -2,7 +2,7 @@
* linux/drivers/video/vgastate.c -- VGA state save/restore
*
* Copyright 2002 James Simmons
- *
+ *
* Copyright history from vga16fb.c:
* Copyright 1999 Ben Pfaff and Petr Vandrovec
* Based on VGA info at http://www.goodnet.com/~tinara/FreeVGA/home.htm
@@ -10,7 +10,7 @@
*
* 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.
+ * archive for more details.
*
*/
#include <linux/module.h>
@@ -29,16 +29,16 @@ struct regstate {
__u8 *gfx;
__u8 *seq;
__u8 misc;
-};
+};
-static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase,
+static inline unsigned char vga_rcrtcs(void __iomem *regbase, unsigned short iobase,
unsigned char reg)
{
vga_w(regbase, iobase + 0x4, reg);
return vga_r(regbase, iobase + 0x5);
}
-static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase,
+static inline void vga_wcrtcs(void __iomem *regbase, unsigned short iobase,
unsigned char reg, unsigned char val)
{
vga_w(regbase, iobase + 0x4, reg);
@@ -71,7 +71,7 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
gr6 = vga_rgfx(state->vgabase, VGA_GFX_MISC);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
-
+
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -85,7 +85,7 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < 4 * 8192; i++)
+ for (i = 0; i < 4 * 8192; i++)
saved->vga_font0[i] = vga_r(fbbase, i);
}
@@ -96,10 +96,10 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < state->memsize; i++)
+ for (i = 0; i < state->memsize; i++)
saved->vga_font1[i] = vga_r(fbbase, i);
}
-
+
/* save font at plane 0/1 */
if (state->flags & VGA_SAVE_TEXT) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
@@ -107,7 +107,7 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < 8192; i++)
+ for (i = 0; i < 8192; i++)
saved->vga_text[i] = vga_r(fbbase, i);
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
@@ -115,8 +115,8 @@ static void save_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < 8192; i++)
- saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i);
+ for (i = 0; i < 8192; i++)
+ saved->vga_text[8192+i] = vga_r(fbbase + 2 * 8192, i);
}
/* restore regs */
@@ -151,7 +151,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
gr8 = vga_rgfx(state->vgabase, VGA_GFX_BIT_MASK);
seq2 = vga_rseq(state->vgabase, VGA_SEQ_PLANE_WRITE);
seq4 = vga_rseq(state->vgabase, VGA_SEQ_MEMORY_MODE);
-
+
/* blank screen */
seq1 = vga_rseq(state->vgabase, VGA_SEQ_CLOCK_MODE);
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x1);
@@ -163,7 +163,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_BIT_MASK, 0xff);
vga_wgfx(state->vgabase, VGA_GFX_SR_ENABLE, 0x00);
}
-
+
/* restore font at plane 2 */
if (state->flags & VGA_SAVE_FONT0) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x4);
@@ -171,7 +171,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x2);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < 4 * 8192; i++)
+ for (i = 0; i < 4 * 8192; i++)
vga_w(fbbase, i, saved->vga_font0[i]);
}
@@ -182,10 +182,10 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x3);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < state->memsize; i++)
+ for (i = 0; i < state->memsize; i++)
vga_w(fbbase, i, saved->vga_font1[i]);
}
-
+
/* restore font at plane 0/1 */
if (state->flags & VGA_SAVE_TEXT) {
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x1);
@@ -193,16 +193,16 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < 8192; i++)
+ for (i = 0; i < 8192; i++)
vga_w(fbbase, i, saved->vga_text[i]);
-
+
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, 0x2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, 0x6);
vga_wgfx(state->vgabase, VGA_GFX_PLANE_READ, 0x1);
vga_wgfx(state->vgabase, VGA_GFX_MODE, 0x0);
vga_wgfx(state->vgabase, VGA_GFX_MISC, 0x5);
- for (i = 0; i < 8192; i++)
- vga_w(fbbase, i, saved->vga_text[8192+i]);
+ for (i = 0; i < 8192; i++)
+ vga_w(fbbase, i, saved->vga_text[8192+i]);
}
/* unblank screen */
@@ -222,7 +222,7 @@ static void restore_vga_text(struct vgastate *state, void __iomem *fbbase)
vga_wseq(state->vgabase, VGA_SEQ_PLANE_WRITE, seq2);
vga_wseq(state->vgabase, VGA_SEQ_MEMORY_MODE, seq4);
}
-
+
static void save_vga_mode(struct vgastate *state)
{
struct regstate *saved = (struct regstate *) state->vidstate;
@@ -235,10 +235,10 @@ static void save_vga_mode(struct vgastate *state)
else
iobase = 0x3b0;
- for (i = 0; i < state->num_crtc; i++)
+ for (i = 0; i < state->num_crtc; i++)
saved->crtc[i] = vga_rcrtcs(state->vgabase, iobase, i);
-
- vga_r(state->vgabase, iobase + 0xa);
+
+ vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x00);
for (i = 0; i < state->num_attr; i++) {
vga_r(state->vgabase, iobase + 0xa);
@@ -247,10 +247,10 @@ static void save_vga_mode(struct vgastate *state)
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x20);
- for (i = 0; i < state->num_gfx; i++)
+ for (i = 0; i < state->num_gfx; i++)
saved->gfx[i] = vga_rgfx(state->vgabase, i);
- for (i = 0; i < state->num_seq; i++)
+ for (i = 0; i < state->num_seq; i++)
saved->seq[i] = vga_rseq(state->vgabase, i);
}
@@ -268,26 +268,26 @@ static void restore_vga_mode(struct vgastate *state)
iobase = 0x3b0;
/* turn off display */
- vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
+ vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
saved->seq[VGA_SEQ_CLOCK_MODE] | 0x20);
/* disable sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x01);
-
+
/* enable palette addressing */
vga_r(state->vgabase, iobase + 0xa);
vga_w(state->vgabase, VGA_ATT_W, 0x00);
- for (i = 2; i < state->num_seq; i++)
+ for (i = 2; i < state->num_seq; i++)
vga_wseq(state->vgabase, i, saved->seq[i]);
/* unprotect vga regs */
vga_wcrtcs(state->vgabase, iobase, 17, saved->crtc[17] & ~0x80);
- for (i = 0; i < state->num_crtc; i++)
+ for (i = 0; i < state->num_crtc; i++)
vga_wcrtcs(state->vgabase, iobase, i, saved->crtc[i]);
-
- for (i = 0; i < state->num_gfx; i++)
+
+ for (i = 0; i < state->num_gfx; i++)
vga_wgfx(state->vgabase, i, saved->gfx[i]);
for (i = 0; i < state->num_attr; i++) {
@@ -298,7 +298,7 @@ static void restore_vga_mode(struct vgastate *state)
/* reenable sequencer */
vga_wseq(state->vgabase, VGA_SEQ_RESET, 0x03);
/* turn display on */
- vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
+ vga_wseq(state->vgabase, VGA_SEQ_CLOCK_MODE,
saved->seq[VGA_SEQ_CLOCK_MODE] & ~(1 << 5));
/* disable video/palette source */
@@ -312,7 +312,7 @@ static void save_vga_cmap(struct vgastate *state)
int i;
vga_w(state->vgabase, VGA_PEL_MSK, 0xff);
-
+
/* assumes DAC is readable and writable */
vga_w(state->vgabase, VGA_PEL_IR, 0x00);
for (i = 0; i < 768; i++)
@@ -346,7 +346,7 @@ static void vga_cleanup(struct vgastate *state)
state->vidstate = NULL;
}
}
-
+
int save_vga(struct vgastate *state)
{
struct regstate *saved;
@@ -357,7 +357,7 @@ int save_vga(struct vgastate *state)
return 1;
state->vidstate = (void *)saved;
-
+
if (state->flags & VGA_SAVE_CMAP) {
saved->vga_cmap = vmalloc(768);
if (!saved->vga_cmap) {
@@ -403,7 +403,7 @@ int save_vga(struct vgastate *state)
}
if (!state->memsize)
state->memsize = 8 * 8192;
-
+
if (!state->membase)
state->membase = 0xA0000;
@@ -414,7 +414,7 @@ int save_vga(struct vgastate *state)
return 1;
}
- /*
+ /*
* save only first 32K used by vgacon
*/
if (state->flags & VGA_SAVE_FONT0) {
@@ -425,7 +425,7 @@ int save_vga(struct vgastate *state)
return 1;
}
}
- /*
+ /*
* largely unused, but if required by the caller
* we'll just save everything.
*/
@@ -448,7 +448,7 @@ int save_vga(struct vgastate *state)
return 1;
}
}
-
+
save_vga_text(state, fbbase);
iounmap(fbbase);
}
diff --git a/drivers/virtio/Kconfig b/drivers/virtio/Kconfig
index 00b228638274..b546da5d8ea3 100644
--- a/drivers/virtio/Kconfig
+++ b/drivers/virtio/Kconfig
@@ -12,16 +12,32 @@ config VIRTIO_PCI
depends on PCI
select VIRTIO
---help---
- This drivers provides support for virtio based paravirtual device
+ This driver provides support for virtio based paravirtual device
drivers over PCI. This requires that your VMM has appropriate PCI
virtio backends. Most QEMU based VMMs should support these devices
(like KVM or Xen).
- Currently, the ABI is not considered stable so there is no guarantee
- that this version of the driver will work with your VMM.
-
If unsure, say M.
+config VIRTIO_PCI_LEGACY
+ bool "Support for legacy virtio draft 0.9.X and older devices"
+ default y
+ depends on VIRTIO_PCI
+ ---help---
+ Virtio PCI Card 0.9.X Draft (circa 2014) and older device support.
+
+ This option enables building a transitional driver, supporting
+ both devices conforming to Virtio 1 specification, and legacy devices.
+ If disabled, you get a slightly smaller, non-transitional driver,
+ with no legacy compatibility.
+
+ So look out into your driveway. Do you have a flying car? If
+ so, you can happily disable this option and virtio will not
+ break. Otherwise, leave it set. Unless you're testing what
+ life will be like in The Future.
+
+ If unsure, say Y.
+
config VIRTIO_BALLOON
tristate "Virtio balloon driver"
depends on VIRTIO
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index bf5104b56894..d85565b8ea46 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -1,5 +1,6 @@
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
+virtio_pci-y := virtio_pci_modern.o virtio_pci_common.o
+virtio_pci-$(CONFIG_VIRTIO_PCI_LEGACY) += virtio_pci_legacy.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index b9f70dfc4751..5ce2aa48fc6e 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -236,7 +236,10 @@ static int virtio_dev_probe(struct device *_d)
if (err)
goto err;
- add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+ /* If probe didn't do it, mark device DRIVER_OK ourselves. */
+ if (!(dev->config->get_status(dev) & VIRTIO_CONFIG_S_DRIVER_OK))
+ virtio_device_ready(dev);
+
if (drv->scan)
drv->scan(dev);
diff --git a/drivers/virtio/virtio_balloon.c b/drivers/virtio/virtio_balloon.c
index 50c5f42d7a9f..0413157f3b49 100644
--- a/drivers/virtio/virtio_balloon.c
+++ b/drivers/virtio/virtio_balloon.c
@@ -44,8 +44,7 @@ static int oom_pages = OOM_VBALLOON_DEFAULT_PAGES;
module_param(oom_pages, int, S_IRUSR | S_IWUSR);
MODULE_PARM_DESC(oom_pages, "pages to free on OOM");
-struct virtio_balloon
-{
+struct virtio_balloon {
struct virtio_device *vdev;
struct virtqueue *inflate_vq, *deflate_vq, *stats_vq;
@@ -466,6 +465,12 @@ static int virtballoon_probe(struct virtio_device *vdev)
struct virtio_balloon *vb;
int err;
+ if (!vdev->config->get) {
+ dev_err(&vdev->dev, "%s failure: config access disabled\n",
+ __func__);
+ return -EINVAL;
+ }
+
vdev->priv = vb = kmalloc(sizeof(*vb), GFP_KERNEL);
if (!vb) {
err = -ENOMEM;
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index 00d115b22bd8..cad569890908 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -1,7 +1,7 @@
/*
* Virtio memory mapped device driver
*
- * Copyright 2011, ARM Ltd.
+ * Copyright 2011-2014, ARM Ltd.
*
* This module allows virtio devices to be used over a virtual, memory mapped
* platform device.
@@ -50,36 +50,6 @@
*
*
*
- * Registers layout (all 32-bit wide):
- *
- * offset d. name description
- * ------ -- ---------------- -----------------
- *
- * 0x000 R MagicValue Magic value "virt"
- * 0x004 R Version Device version (current max. 1)
- * 0x008 R DeviceID Virtio device ID
- * 0x00c R VendorID Virtio vendor ID
- *
- * 0x010 R HostFeatures Features supported by the host
- * 0x014 W HostFeaturesSel Set of host features to access via HostFeatures
- *
- * 0x020 W GuestFeatures Features activated by the guest
- * 0x024 W GuestFeaturesSel Set of activated features to set via GuestFeatures
- * 0x028 W GuestPageSize Size of guest's memory page in bytes
- *
- * 0x030 W QueueSel Queue selector
- * 0x034 R QueueNumMax Maximum size of the currently selected queue
- * 0x038 W QueueNum Queue size for the currently selected queue
- * 0x03c W QueueAlign Used Ring alignment for the current queue
- * 0x040 RW QueuePFN PFN for the currently selected queue
- *
- * 0x050 W QueueNotify Queue notifier
- * 0x060 R InterruptStatus Interrupt status register
- * 0x064 W InterruptACK Interrupt acknowledge register
- * 0x070 RW Status Device status register
- *
- * 0x100+ RW Device-specific configuration space
- *
* Based on Virtio PCI driver by Anthony Liguori, copyright IBM Corp. 2007
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
@@ -145,11 +115,16 @@ struct virtio_mmio_vq_info {
static u64 vm_get_features(struct virtio_device *vdev)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
+ u64 features;
+
+ writel(1, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
+ features = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES);
+ features <<= 32;
- /* TODO: Features > 32 bits */
- writel(0, vm_dev->base + VIRTIO_MMIO_HOST_FEATURES_SEL);
+ writel(0, vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES_SEL);
+ features |= readl(vm_dev->base + VIRTIO_MMIO_DEVICE_FEATURES);
- return readl(vm_dev->base + VIRTIO_MMIO_HOST_FEATURES);
+ return features;
}
static int vm_finalize_features(struct virtio_device *vdev)
@@ -159,11 +134,20 @@ static int vm_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);
+ /* Make sure there is are no mixed devices */
+ if (vm_dev->version == 2 &&
+ !__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
+ dev_err(&vdev->dev, "New virtio-mmio devices (version 2) must provide VIRTIO_F_VERSION_1 feature!\n");
+ return -EINVAL;
+ }
+
+ writel(1, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
+ writel((u32)(vdev->features >> 32),
+ vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES);
- writel(0, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL);
- writel(vdev->features, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES);
+ writel(0, vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES_SEL);
+ writel((u32)vdev->features,
+ vm_dev->base + VIRTIO_MMIO_DRIVER_FEATURES);
return 0;
}
@@ -275,7 +259,12 @@ static void vm_del_vq(struct virtqueue *vq)
/* Select and deactivate the queue */
writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ if (vm_dev->version == 1) {
+ writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ } else {
+ writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
+ WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY));
+ }
size = PAGE_ALIGN(vring_size(info->num, VIRTIO_MMIO_VRING_ALIGN));
free_pages_exact(info->queue, size);
@@ -312,7 +301,8 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
writel(index, vm_dev->base + VIRTIO_MMIO_QUEUE_SEL);
/* Queue shouldn't already be set up. */
- if (readl(vm_dev->base + VIRTIO_MMIO_QUEUE_PFN)) {
+ if (readl(vm_dev->base + (vm_dev->version == 1 ?
+ VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))) {
err = -ENOENT;
goto error_available;
}
@@ -356,13 +346,6 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
info->num /= 2;
}
- /* Activate the queue */
- writel(info->num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
- writel(VIRTIO_MMIO_VRING_ALIGN,
- vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN);
- writel(virt_to_phys(info->queue) >> PAGE_SHIFT,
- vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
-
/* Create the vring */
vq = vring_new_virtqueue(index, info->num, VIRTIO_MMIO_VRING_ALIGN, vdev,
true, info->queue, vm_notify, callback, name);
@@ -371,6 +354,33 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
goto error_new_virtqueue;
}
+ /* Activate the queue */
+ writel(info->num, vm_dev->base + VIRTIO_MMIO_QUEUE_NUM);
+ if (vm_dev->version == 1) {
+ writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_QUEUE_ALIGN);
+ writel(virt_to_phys(info->queue) >> PAGE_SHIFT,
+ vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ } else {
+ u64 addr;
+
+ addr = virt_to_phys(info->queue);
+ writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_LOW);
+ writel((u32)(addr >> 32),
+ vm_dev->base + VIRTIO_MMIO_QUEUE_DESC_HIGH);
+
+ addr = virt_to_phys(virtqueue_get_avail(vq));
+ writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_LOW);
+ writel((u32)(addr >> 32),
+ vm_dev->base + VIRTIO_MMIO_QUEUE_AVAIL_HIGH);
+
+ addr = virt_to_phys(virtqueue_get_used(vq));
+ writel((u32)addr, vm_dev->base + VIRTIO_MMIO_QUEUE_USED_LOW);
+ writel((u32)(addr >> 32),
+ vm_dev->base + VIRTIO_MMIO_QUEUE_USED_HIGH);
+
+ writel(1, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
+ }
+
vq->priv = info;
info->vq = vq;
@@ -381,7 +391,12 @@ static struct virtqueue *vm_setup_vq(struct virtio_device *vdev, unsigned index,
return vq;
error_new_virtqueue:
- writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ if (vm_dev->version == 1) {
+ writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_PFN);
+ } else {
+ writel(0, vm_dev->base + VIRTIO_MMIO_QUEUE_READY);
+ WARN_ON(readl(vm_dev->base + VIRTIO_MMIO_QUEUE_READY));
+ }
free_pages_exact(info->queue, size);
error_alloc_pages:
kfree(info);
@@ -476,16 +491,32 @@ static int virtio_mmio_probe(struct platform_device *pdev)
/* Check device version */
vm_dev->version = readl(vm_dev->base + VIRTIO_MMIO_VERSION);
- if (vm_dev->version != 1) {
+ if (vm_dev->version < 1 || vm_dev->version > 2) {
dev_err(&pdev->dev, "Version %ld not supported!\n",
vm_dev->version);
return -ENXIO;
}
vm_dev->vdev.id.device = readl(vm_dev->base + VIRTIO_MMIO_DEVICE_ID);
+ if (vm_dev->vdev.id.device == 0) {
+ /*
+ * virtio-mmio device with an ID 0 is a (dummy) placeholder
+ * with no function. End probing now with no error reported.
+ */
+ return -ENODEV;
+ }
vm_dev->vdev.id.vendor = readl(vm_dev->base + VIRTIO_MMIO_VENDOR_ID);
- writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
+ /* Reject legacy-only IDs for version 2 devices */
+ if (vm_dev->version == 2 &&
+ virtio_device_is_legacy_only(vm_dev->vdev.id)) {
+ dev_err(&pdev->dev, "Version 2 not supported for devices %u!\n",
+ vm_dev->vdev.id.device);
+ return -ENODEV;
+ }
+
+ if (vm_dev->version == 1)
+ writel(PAGE_SIZE, vm_dev->base + VIRTIO_MMIO_GUEST_PAGE_SIZE);
platform_set_drvdata(pdev, vm_dev);
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
index 9756f21b809e..e894eb278d83 100644
--- a/drivers/virtio/virtio_pci_common.c
+++ b/drivers/virtio/virtio_pci_common.c
@@ -19,6 +19,14 @@
#include "virtio_pci_common.h"
+static bool force_legacy = false;
+
+#if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY)
+module_param(force_legacy, bool, 0444);
+MODULE_PARM_DESC(force_legacy,
+ "Force legacy mode for transitional virtio 1 devices");
+#endif
+
/* wait for pending irq handlers */
void vp_synchronize_vectors(struct virtio_device *vdev)
{
@@ -464,15 +472,97 @@ static const struct pci_device_id virtio_pci_id_table[] = {
MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
+static void virtio_pci_release_dev(struct device *_d)
+{
+ struct virtio_device *vdev = dev_to_virtio(_d);
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ /* As struct device is a kobject, it's not safe to
+ * free the memory (including the reference counter itself)
+ * until it's release callback. */
+ kfree(vp_dev);
+}
+
static int virtio_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
- return virtio_pci_legacy_probe(pci_dev, id);
+ struct virtio_pci_device *vp_dev;
+ int rc;
+
+ /* allocate our structure and fill it out */
+ vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
+ if (!vp_dev)
+ return -ENOMEM;
+
+ pci_set_drvdata(pci_dev, vp_dev);
+ vp_dev->vdev.dev.parent = &pci_dev->dev;
+ vp_dev->vdev.dev.release = virtio_pci_release_dev;
+ 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 */
+ rc = pci_enable_device(pci_dev);
+ if (rc)
+ goto err_enable_device;
+
+ rc = pci_request_regions(pci_dev, "virtio-pci");
+ if (rc)
+ goto err_request_regions;
+
+ if (force_legacy) {
+ rc = virtio_pci_legacy_probe(vp_dev);
+ /* Also try modern mode if we can't map BAR0 (no IO space). */
+ if (rc == -ENODEV || rc == -ENOMEM)
+ rc = virtio_pci_modern_probe(vp_dev);
+ if (rc)
+ goto err_probe;
+ } else {
+ rc = virtio_pci_modern_probe(vp_dev);
+ if (rc == -ENODEV)
+ rc = virtio_pci_legacy_probe(vp_dev);
+ if (rc)
+ goto err_probe;
+ }
+
+ pci_set_master(pci_dev);
+
+ rc = register_virtio_device(&vp_dev->vdev);
+ if (rc)
+ goto err_register;
+
+ return 0;
+
+err_register:
+ if (vp_dev->ioaddr)
+ virtio_pci_legacy_remove(vp_dev);
+ else
+ virtio_pci_modern_remove(vp_dev);
+err_probe:
+ pci_release_regions(pci_dev);
+err_request_regions:
+ pci_disable_device(pci_dev);
+err_enable_device:
+ kfree(vp_dev);
+ return rc;
}
static void virtio_pci_remove(struct pci_dev *pci_dev)
{
- virtio_pci_legacy_remove(pci_dev);
+ struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+
+ unregister_virtio_device(&vp_dev->vdev);
+
+ if (vp_dev->ioaddr)
+ virtio_pci_legacy_remove(vp_dev);
+ else
+ virtio_pci_modern_remove(vp_dev);
+
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
}
static struct pci_driver virtio_pci_driver = {
diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h
index 5a497289b7e9..28ee4e56badf 100644
--- a/drivers/virtio/virtio_pci_common.h
+++ b/drivers/virtio/virtio_pci_common.h
@@ -53,12 +53,32 @@ struct virtio_pci_device {
struct virtio_device vdev;
struct pci_dev *pci_dev;
+ /* In legacy mode, these two point to within ->legacy. */
+ /* Where to read and clear interrupt */
+ u8 __iomem *isr;
+
+ /* Modern only fields */
+ /* The IO mapping for the PCI config space (non-legacy mode) */
+ struct virtio_pci_common_cfg __iomem *common;
+ /* Device-specific data (non-legacy mode) */
+ void __iomem *device;
+ /* Base of vq notifications (non-legacy mode). */
+ void __iomem *notify_base;
+
+ /* So we can sanity-check accesses. */
+ size_t notify_len;
+ size_t device_len;
+
+ /* Capability for when we need to map notifications per-vq. */
+ int notify_map_cap;
+
+ /* Multiply queue_notify_off by this value. (non-legacy mode). */
+ u32 notify_offset_multiplier;
+
+ /* Legacy only field */
/* 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;
@@ -127,8 +147,19 @@ const char *vp_bus_name(struct virtio_device *vdev);
*/
int vp_set_vq_affinity(struct virtqueue *vq, int cpu);
-int virtio_pci_legacy_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *id);
-void virtio_pci_legacy_remove(struct pci_dev *pci_dev);
+#if IS_ENABLED(CONFIG_VIRTIO_PCI_LEGACY)
+int virtio_pci_legacy_probe(struct virtio_pci_device *);
+void virtio_pci_legacy_remove(struct virtio_pci_device *);
+#else
+static inline int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev)
+{
+ return -ENODEV;
+}
+static inline void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev)
+{
+}
+#endif
+int virtio_pci_modern_probe(struct virtio_pci_device *);
+void virtio_pci_modern_remove(struct virtio_pci_device *);
#endif
diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c
index a5486e65e04b..256a5278a515 100644
--- a/drivers/virtio/virtio_pci_legacy.c
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -211,23 +211,10 @@ static const struct virtio_config_ops virtio_pci_config_ops = {
.set_vq_affinity = vp_set_vq_affinity,
};
-static void virtio_pci_release_dev(struct device *_d)
-{
- struct virtio_device *vdev = dev_to_virtio(_d);
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
- /* As struct device is a kobject, it's not safe to
- * free the memory (including the reference counter itself)
- * until it's release callback. */
- kfree(vp_dev);
-}
-
/* the PCI probing function */
-int virtio_pci_legacy_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *id)
+int virtio_pci_legacy_probe(struct virtio_pci_device *vp_dev)
{
- struct virtio_pci_device *vp_dev;
- int err;
+ struct pci_dev *pci_dev = vp_dev->pci_dev;
/* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)
@@ -239,41 +226,12 @@ int virtio_pci_legacy_probe(struct pci_dev *pci_dev,
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;
- }
+ if (!vp_dev->ioaddr)
+ return -ENOMEM;
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
@@ -281,36 +239,18 @@ int virtio_pci_legacy_probe(struct pci_dev *pci_dev,
vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
vp_dev->vdev.id.device = pci_dev->subsystem_device;
+ vp_dev->vdev.config = &virtio_pci_config_ops;
+
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;
}
-void virtio_pci_legacy_remove(struct pci_dev *pci_dev)
+void virtio_pci_legacy_remove(struct virtio_pci_device *vp_dev)
{
- struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
-
- unregister_virtio_device(&vp_dev->vdev);
+ struct pci_dev *pci_dev = vp_dev->pci_dev;
- vp_del_vqs(&vp_dev->vdev);
pci_iounmap(pci_dev, vp_dev->ioaddr);
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
}
diff --git a/drivers/virtio/virtio_pci_modern.c b/drivers/virtio/virtio_pci_modern.c
new file mode 100644
index 000000000000..2aa38e59db2e
--- /dev/null
+++ b/drivers/virtio/virtio_pci_modern.c
@@ -0,0 +1,695 @@
+/*
+ * Virtio PCI driver - modern (virtio 1.0) 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.
+ *
+ */
+
+#define VIRTIO_PCI_NO_LEGACY
+#include "virtio_pci_common.h"
+
+static void __iomem *map_capability(struct pci_dev *dev, int off,
+ size_t minlen,
+ u32 align,
+ u32 start, u32 size,
+ size_t *len)
+{
+ u8 bar;
+ u32 offset, length;
+ void __iomem *p;
+
+ pci_read_config_byte(dev, off + offsetof(struct virtio_pci_cap,
+ bar),
+ &bar);
+ pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, offset),
+ &offset);
+ pci_read_config_dword(dev, off + offsetof(struct virtio_pci_cap, length),
+ &length);
+
+ if (length <= start) {
+ dev_err(&dev->dev,
+ "virtio_pci: bad capability len %u (>%u expected)\n",
+ length, start);
+ return NULL;
+ }
+
+ if (length - start < minlen) {
+ dev_err(&dev->dev,
+ "virtio_pci: bad capability len %u (>=%zu expected)\n",
+ length, minlen);
+ return NULL;
+ }
+
+ length -= start;
+
+ if (start + offset < offset) {
+ dev_err(&dev->dev,
+ "virtio_pci: map wrap-around %u+%u\n",
+ start, offset);
+ return NULL;
+ }
+
+ offset += start;
+
+ if (offset & (align - 1)) {
+ dev_err(&dev->dev,
+ "virtio_pci: offset %u not aligned to %u\n",
+ offset, align);
+ return NULL;
+ }
+
+ if (length > size)
+ length = size;
+
+ if (len)
+ *len = length;
+
+ if (minlen + offset < minlen ||
+ minlen + offset > pci_resource_len(dev, bar)) {
+ dev_err(&dev->dev,
+ "virtio_pci: map virtio %zu@%u "
+ "out of range on bar %i length %lu\n",
+ minlen, offset,
+ bar, (unsigned long)pci_resource_len(dev, bar));
+ return NULL;
+ }
+
+ p = pci_iomap_range(dev, bar, offset, length);
+ if (!p)
+ dev_err(&dev->dev,
+ "virtio_pci: unable to map virtio %u@%u on bar %i\n",
+ length, offset, bar);
+ return p;
+}
+
+static void iowrite64_twopart(u64 val, __le32 __iomem *lo, __le32 __iomem *hi)
+{
+ iowrite32((u32)val, lo);
+ iowrite32(val >> 32, hi);
+}
+
+/* virtio config->get_features() implementation */
+static u64 vp_get_features(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ u64 features;
+
+ iowrite32(0, &vp_dev->common->device_feature_select);
+ features = ioread32(&vp_dev->common->device_feature);
+ iowrite32(1, &vp_dev->common->device_feature_select);
+ features |= ((u64)ioread32(&vp_dev->common->device_feature) << 32);
+
+ return 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);
+
+ if (!__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
+ dev_err(&vdev->dev, "virtio: device uses modern interface "
+ "but does not have VIRTIO_F_VERSION_1\n");
+ return -EINVAL;
+ }
+
+ iowrite32(0, &vp_dev->common->guest_feature_select);
+ iowrite32((u32)vdev->features, &vp_dev->common->guest_feature);
+ iowrite32(1, &vp_dev->common->guest_feature_select);
+ iowrite32(vdev->features >> 32, &vp_dev->common->guest_feature);
+
+ 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);
+ u8 b;
+ __le16 w;
+ __le32 l;
+
+ BUG_ON(offset + len > vp_dev->device_len);
+
+ switch (len) {
+ case 1:
+ b = ioread8(vp_dev->device + offset);
+ memcpy(buf, &b, sizeof b);
+ break;
+ case 2:
+ w = cpu_to_le16(ioread16(vp_dev->device + offset));
+ memcpy(buf, &w, sizeof w);
+ break;
+ case 4:
+ l = cpu_to_le32(ioread32(vp_dev->device + offset));
+ memcpy(buf, &l, sizeof l);
+ break;
+ case 8:
+ l = cpu_to_le32(ioread32(vp_dev->device + offset));
+ memcpy(buf, &l, sizeof l);
+ l = cpu_to_le32(ioread32(vp_dev->device + offset + sizeof l));
+ memcpy(buf + sizeof l, &l, sizeof l);
+ break;
+ default:
+ BUG();
+ }
+}
+
+/* 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);
+ u8 b;
+ __le16 w;
+ __le32 l;
+
+ BUG_ON(offset + len > vp_dev->device_len);
+
+ switch (len) {
+ case 1:
+ memcpy(&b, buf, sizeof b);
+ iowrite8(b, vp_dev->device + offset);
+ break;
+ case 2:
+ memcpy(&w, buf, sizeof w);
+ iowrite16(le16_to_cpu(w), vp_dev->device + offset);
+ break;
+ case 4:
+ memcpy(&l, buf, sizeof l);
+ iowrite32(le32_to_cpu(l), vp_dev->device + offset);
+ break;
+ case 8:
+ memcpy(&l, buf, sizeof l);
+ iowrite32(le32_to_cpu(l), vp_dev->device + offset);
+ memcpy(&l, buf + sizeof l, sizeof l);
+ iowrite32(le32_to_cpu(l), vp_dev->device + offset + sizeof l);
+ break;
+ default:
+ BUG();
+ }
+}
+
+static u32 vp_generation(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ return ioread8(&vp_dev->common->config_generation);
+}
+
+/* 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->common->device_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->common->device_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->common->device_status);
+ /* Flush out the status write, and flush in device writes,
+ * including MSI-X interrupts, if any. */
+ ioread8(&vp_dev->common->device_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->common->msix_config);
+ /* Verify we had enough resources to assign the vector */
+ /* Will also flush the write out to device */
+ return ioread16(&vp_dev->common->msix_config);
+}
+
+static size_t vring_pci_size(u16 num)
+{
+ /* We only need a cacheline separation. */
+ return PAGE_ALIGN(vring_size(num, SMP_CACHE_BYTES));
+}
+
+static void *alloc_virtqueue_pages(int *num)
+{
+ void *pages;
+
+ /* TODO: allocate each queue chunk individually */
+ for (; *num && vring_pci_size(*num) > PAGE_SIZE; *num /= 2) {
+ pages = alloc_pages_exact(vring_pci_size(*num),
+ GFP_KERNEL|__GFP_ZERO|__GFP_NOWARN);
+ if (pages)
+ return pages;
+ }
+
+ if (!*num)
+ return NULL;
+
+ /* Try to get a single page. You are my only hope! */
+ return alloc_pages_exact(vring_pci_size(*num), GFP_KERNEL|__GFP_ZERO);
+}
+
+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 virtio_pci_common_cfg __iomem *cfg = vp_dev->common;
+ struct virtqueue *vq;
+ u16 num, off;
+ int err;
+
+ if (index >= ioread16(&cfg->num_queues))
+ return ERR_PTR(-ENOENT);
+
+ /* Select the queue we're interested in */
+ iowrite16(index, &cfg->queue_select);
+
+ /* Check if queue is either not available or already active. */
+ num = ioread16(&cfg->queue_size);
+ if (!num || ioread16(&cfg->queue_enable))
+ return ERR_PTR(-ENOENT);
+
+ if (num & (num - 1)) {
+ dev_warn(&vp_dev->pci_dev->dev, "bad queue size %u", num);
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* get offset of notification word for this vq */
+ off = ioread16(&cfg->queue_notify_off);
+
+ info->num = num;
+ info->msix_vector = msix_vec;
+
+ info->queue = alloc_virtqueue_pages(&info->num);
+ if (info->queue == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ /* create the vring */
+ vq = vring_new_virtqueue(index, info->num,
+ SMP_CACHE_BYTES, &vp_dev->vdev,
+ true, info->queue, vp_notify, callback, name);
+ if (!vq) {
+ err = -ENOMEM;
+ goto err_new_queue;
+ }
+
+ /* activate the queue */
+ iowrite16(num, &cfg->queue_size);
+ iowrite64_twopart(virt_to_phys(info->queue),
+ &cfg->queue_desc_lo, &cfg->queue_desc_hi);
+ iowrite64_twopart(virt_to_phys(virtqueue_get_avail(vq)),
+ &cfg->queue_avail_lo, &cfg->queue_avail_hi);
+ iowrite64_twopart(virt_to_phys(virtqueue_get_used(vq)),
+ &cfg->queue_used_lo, &cfg->queue_used_hi);
+
+ if (vp_dev->notify_base) {
+ /* offset should not wrap */
+ if ((u64)off * vp_dev->notify_offset_multiplier + 2
+ > vp_dev->notify_len) {
+ dev_warn(&vp_dev->pci_dev->dev,
+ "bad notification offset %u (x %u) "
+ "for queue %u > %zd",
+ off, vp_dev->notify_offset_multiplier,
+ index, vp_dev->notify_len);
+ err = -EINVAL;
+ goto err_map_notify;
+ }
+ vq->priv = (void __force *)vp_dev->notify_base +
+ off * vp_dev->notify_offset_multiplier;
+ } else {
+ vq->priv = (void __force *)map_capability(vp_dev->pci_dev,
+ vp_dev->notify_map_cap, 2, 2,
+ off * vp_dev->notify_offset_multiplier, 2,
+ NULL);
+ }
+
+ if (!vq->priv) {
+ err = -ENOMEM;
+ goto err_map_notify;
+ }
+
+ if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
+ iowrite16(msix_vec, &cfg->queue_msix_vector);
+ msix_vec = ioread16(&cfg->queue_msix_vector);
+ if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
+ err = -EBUSY;
+ goto err_assign_vector;
+ }
+ }
+
+ return vq;
+
+err_assign_vector:
+ if (!vp_dev->notify_base)
+ pci_iounmap(vp_dev->pci_dev, (void __iomem __force *)vq->priv);
+err_map_notify:
+ vring_del_virtqueue(vq);
+err_new_queue:
+ free_pages_exact(info->queue, vring_pci_size(info->num));
+ return ERR_PTR(err);
+}
+
+static int vp_modern_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[])
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtqueue *vq;
+ int rc = vp_find_vqs(vdev, nvqs, vqs, callbacks, names);
+
+ if (rc)
+ return rc;
+
+ /* Select and activate all queues. Has to be done last: once we do
+ * this, there's no way to go back except reset.
+ */
+ list_for_each_entry(vq, &vdev->vqs, list) {
+ iowrite16(vq->index, &vp_dev->common->queue_select);
+ iowrite16(1, &vp_dev->common->queue_enable);
+ }
+
+ return 0;
+}
+
+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);
+
+ iowrite16(vq->index, &vp_dev->common->queue_select);
+
+ if (vp_dev->msix_enabled) {
+ iowrite16(VIRTIO_MSI_NO_VECTOR,
+ &vp_dev->common->queue_msix_vector);
+ /* Flush the write out to device */
+ ioread16(&vp_dev->common->queue_msix_vector);
+ }
+
+ if (!vp_dev->notify_base)
+ pci_iounmap(vp_dev->pci_dev, (void __force __iomem *)vq->priv);
+
+ vring_del_virtqueue(vq);
+
+ free_pages_exact(info->queue, vring_pci_size(info->num));
+}
+
+static const struct virtio_config_ops virtio_pci_config_nodev_ops = {
+ .get = NULL,
+ .set = NULL,
+ .generation = vp_generation,
+ .get_status = vp_get_status,
+ .set_status = vp_set_status,
+ .reset = vp_reset,
+ .find_vqs = vp_modern_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 const struct virtio_config_ops virtio_pci_config_ops = {
+ .get = vp_get,
+ .set = vp_set,
+ .generation = vp_generation,
+ .get_status = vp_get_status,
+ .set_status = vp_set_status,
+ .reset = vp_reset,
+ .find_vqs = vp_modern_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,
+};
+
+/**
+ * virtio_pci_find_capability - walk capabilities to find device info.
+ * @dev: the pci device
+ * @cfg_type: the VIRTIO_PCI_CAP_* value we seek
+ * @ioresource_types: IORESOURCE_MEM and/or IORESOURCE_IO.
+ *
+ * Returns offset of the capability, or 0.
+ */
+static inline int virtio_pci_find_capability(struct pci_dev *dev, u8 cfg_type,
+ u32 ioresource_types)
+{
+ int pos;
+
+ for (pos = pci_find_capability(dev, PCI_CAP_ID_VNDR);
+ pos > 0;
+ pos = pci_find_next_capability(dev, pos, PCI_CAP_ID_VNDR)) {
+ u8 type, bar;
+ pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
+ cfg_type),
+ &type);
+ pci_read_config_byte(dev, pos + offsetof(struct virtio_pci_cap,
+ bar),
+ &bar);
+
+ /* Ignore structures with reserved BAR values */
+ if (bar > 0x5)
+ continue;
+
+ if (type == cfg_type) {
+ if (pci_resource_len(dev, bar) &&
+ pci_resource_flags(dev, bar) & ioresource_types)
+ return pos;
+ }
+ }
+ return 0;
+}
+
+/* This is part of the ABI. Don't screw with it. */
+static inline void check_offsets(void)
+{
+ /* Note: disk space was harmed in compilation of this function. */
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_VNDR !=
+ offsetof(struct virtio_pci_cap, cap_vndr));
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_NEXT !=
+ offsetof(struct virtio_pci_cap, cap_next));
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_LEN !=
+ offsetof(struct virtio_pci_cap, cap_len));
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_CFG_TYPE !=
+ offsetof(struct virtio_pci_cap, cfg_type));
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_BAR !=
+ offsetof(struct virtio_pci_cap, bar));
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_OFFSET !=
+ offsetof(struct virtio_pci_cap, offset));
+ BUILD_BUG_ON(VIRTIO_PCI_CAP_LENGTH !=
+ offsetof(struct virtio_pci_cap, length));
+ BUILD_BUG_ON(VIRTIO_PCI_NOTIFY_CAP_MULT !=
+ offsetof(struct virtio_pci_notify_cap,
+ notify_off_multiplier));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_DFSELECT !=
+ offsetof(struct virtio_pci_common_cfg,
+ device_feature_select));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_DF !=
+ offsetof(struct virtio_pci_common_cfg, device_feature));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_GFSELECT !=
+ offsetof(struct virtio_pci_common_cfg,
+ guest_feature_select));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_GF !=
+ offsetof(struct virtio_pci_common_cfg, guest_feature));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_MSIX !=
+ offsetof(struct virtio_pci_common_cfg, msix_config));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_NUMQ !=
+ offsetof(struct virtio_pci_common_cfg, num_queues));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_STATUS !=
+ offsetof(struct virtio_pci_common_cfg, device_status));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_CFGGENERATION !=
+ offsetof(struct virtio_pci_common_cfg, config_generation));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_SELECT !=
+ offsetof(struct virtio_pci_common_cfg, queue_select));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_SIZE !=
+ offsetof(struct virtio_pci_common_cfg, queue_size));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_MSIX !=
+ offsetof(struct virtio_pci_common_cfg, queue_msix_vector));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_ENABLE !=
+ offsetof(struct virtio_pci_common_cfg, queue_enable));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_NOFF !=
+ offsetof(struct virtio_pci_common_cfg, queue_notify_off));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_DESCLO !=
+ offsetof(struct virtio_pci_common_cfg, queue_desc_lo));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_DESCHI !=
+ offsetof(struct virtio_pci_common_cfg, queue_desc_hi));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_AVAILLO !=
+ offsetof(struct virtio_pci_common_cfg, queue_avail_lo));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_AVAILHI !=
+ offsetof(struct virtio_pci_common_cfg, queue_avail_hi));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_USEDLO !=
+ offsetof(struct virtio_pci_common_cfg, queue_used_lo));
+ BUILD_BUG_ON(VIRTIO_PCI_COMMON_Q_USEDHI !=
+ offsetof(struct virtio_pci_common_cfg, queue_used_hi));
+}
+
+/* the PCI probing function */
+int virtio_pci_modern_probe(struct virtio_pci_device *vp_dev)
+{
+ struct pci_dev *pci_dev = vp_dev->pci_dev;
+ int err, common, isr, notify, device;
+ u32 notify_length;
+ u32 notify_offset;
+
+ check_offsets();
+
+ /* We only own devices >= 0x1000 and <= 0x107f: leave the rest. */
+ if (pci_dev->device < 0x1000 || pci_dev->device > 0x107f)
+ return -ENODEV;
+
+ if (pci_dev->device < 0x1040) {
+ /* Transitional devices: use the PCI subsystem device id as
+ * virtio device id, same as legacy driver always did.
+ */
+ vp_dev->vdev.id.device = pci_dev->subsystem_device;
+ } else {
+ /* Modern devices: simply use PCI device id, but start from 0x1040. */
+ vp_dev->vdev.id.device = pci_dev->device - 0x1040;
+ }
+ vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
+
+ if (virtio_device_is_legacy_only(vp_dev->vdev.id))
+ return -ENODEV;
+
+ /* check for a common config: if not, use legacy mode (bar 0). */
+ common = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_COMMON_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM);
+ if (!common) {
+ dev_info(&pci_dev->dev,
+ "virtio_pci: leaving for legacy driver\n");
+ return -ENODEV;
+ }
+
+ /* If common is there, these should be too... */
+ isr = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_ISR_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM);
+ notify = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_NOTIFY_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM);
+ if (!isr || !notify) {
+ dev_err(&pci_dev->dev,
+ "virtio_pci: missing capabilities %i/%i/%i\n",
+ common, isr, notify);
+ return -EINVAL;
+ }
+
+ /* Device capability is only mandatory for devices that have
+ * device-specific configuration.
+ */
+ device = virtio_pci_find_capability(pci_dev, VIRTIO_PCI_CAP_DEVICE_CFG,
+ IORESOURCE_IO | IORESOURCE_MEM);
+
+ err = -EINVAL;
+ vp_dev->common = map_capability(pci_dev, common,
+ sizeof(struct virtio_pci_common_cfg), 4,
+ 0, sizeof(struct virtio_pci_common_cfg),
+ NULL);
+ if (!vp_dev->common)
+ goto err_map_common;
+ vp_dev->isr = map_capability(pci_dev, isr, sizeof(u8), 1,
+ 0, 1,
+ NULL);
+ if (!vp_dev->isr)
+ goto err_map_isr;
+
+ /* Read notify_off_multiplier from config space. */
+ pci_read_config_dword(pci_dev,
+ notify + offsetof(struct virtio_pci_notify_cap,
+ notify_off_multiplier),
+ &vp_dev->notify_offset_multiplier);
+ /* Read notify length and offset from config space. */
+ pci_read_config_dword(pci_dev,
+ notify + offsetof(struct virtio_pci_notify_cap,
+ cap.length),
+ &notify_length);
+
+ pci_read_config_dword(pci_dev,
+ notify + offsetof(struct virtio_pci_notify_cap,
+ cap.length),
+ &notify_offset);
+
+ /* We don't know how many VQs we'll map, ahead of the time.
+ * If notify length is small, map it all now.
+ * Otherwise, map each VQ individually later.
+ */
+ if ((u64)notify_length + (notify_offset % PAGE_SIZE) <= PAGE_SIZE) {
+ vp_dev->notify_base = map_capability(pci_dev, notify, 2, 2,
+ 0, notify_length,
+ &vp_dev->notify_len);
+ if (!vp_dev->notify_base)
+ goto err_map_notify;
+ } else {
+ vp_dev->notify_map_cap = notify;
+ }
+
+ /* Again, we don't know how much we should map, but PAGE_SIZE
+ * is more than enough for all existing devices.
+ */
+ if (device) {
+ vp_dev->device = map_capability(pci_dev, device, 0, 4,
+ 0, PAGE_SIZE,
+ &vp_dev->device_len);
+ if (!vp_dev->device)
+ goto err_map_device;
+
+ vp_dev->vdev.config = &virtio_pci_config_ops;
+ } else {
+ vp_dev->vdev.config = &virtio_pci_config_nodev_ops;
+ }
+
+ vp_dev->config_vector = vp_config_vector;
+ vp_dev->setup_vq = setup_vq;
+ vp_dev->del_vq = del_vq;
+
+ return 0;
+
+err_map_device:
+ if (vp_dev->notify_base)
+ pci_iounmap(pci_dev, vp_dev->notify_base);
+err_map_notify:
+ pci_iounmap(pci_dev, vp_dev->isr);
+err_map_isr:
+ pci_iounmap(pci_dev, vp_dev->common);
+err_map_common:
+ return err;
+}
+
+void virtio_pci_modern_remove(struct virtio_pci_device *vp_dev)
+{
+ struct pci_dev *pci_dev = vp_dev->pci_dev;
+
+ if (vp_dev->device)
+ pci_iounmap(pci_dev, vp_dev->device);
+ if (vp_dev->notify_base)
+ pci_iounmap(pci_dev, vp_dev->notify_base);
+ pci_iounmap(pci_dev, vp_dev->isr);
+ pci_iounmap(pci_dev, vp_dev->common);
+}
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 00ec6b3f96b2..096b857e7b75 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -54,8 +54,7 @@
#define END_USE(vq)
#endif
-struct vring_virtqueue
-{
+struct vring_virtqueue {
struct virtqueue vq;
/* Actual memory layout for this queue */
@@ -245,14 +244,14 @@ static inline int virtqueue_add(struct virtqueue *_vq,
vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) + 1);
vq->num_added++;
+ pr_debug("Added buffer head %i to %p\n", head, vq);
+ END_USE(vq);
+
/* This is very unlikely, but theoretically possible. Kick
* just in case. */
if (unlikely(vq->num_added == (1 << 16) - 1))
virtqueue_kick(_vq);
- pr_debug("Added buffer head %i to %p\n", head, vq);
- END_USE(vq);
-
return 0;
}
diff --git a/drivers/vme/vme.c b/drivers/vme/vme.c
index 7516030037a1..d95fb848dd03 100644
--- a/drivers/vme/vme.c
+++ b/drivers/vme/vme.c
@@ -502,7 +502,7 @@ int vme_master_get(struct vme_resource *resource, int *enabled,
image = list_entry(resource->entry, struct vme_master_resource, list);
if (bridge->master_get == NULL) {
- printk(KERN_WARNING "vme_master_set not supported\n");
+ printk(KERN_WARNING "%s not supported\n", __func__);
return -EINVAL;
}
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 08f41add1461..16f202350997 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -505,6 +505,16 @@ config MESON_WATCHDOG
To compile this driver as a module, choose M here: the
module will be called meson_wdt.
+config MEDIATEK_WATCHDOG
+ tristate "Mediatek SoCs watchdog support"
+ depends on ARCH_MEDIATEK
+ select WATCHDOG_CORE
+ help
+ Say Y here to include support for the watchdog timer
+ in Mediatek SoCs.
+ To compile this driver as a module, choose M here: the
+ module will be called mtk_wdt.
+
# AVR32 Architecture
config AT32AP700X_WDT
@@ -1005,6 +1015,8 @@ config W83627HF_WDT
NCT6775
NCT6776
NCT6779
+ NCT6791
+ NCT6792
This watchdog simply watches your kernel to make sure it doesn't
freeze, and if it does, it reboots your computer after a certain
@@ -1101,7 +1113,7 @@ config ATH79_WDT
config BCM47XX_WDT
tristate "Broadcom BCM47xx Watchdog Timer"
- depends on BCM47XX
+ depends on BCM47XX || ARCH_BCM_5301X
select WATCHDOG_CORE
help
Hardware driver for the Broadcom BCM47xx Watchdog Timer.
@@ -1235,6 +1247,17 @@ config BCM_KONA_WDT_DEBUG
If in doubt, say 'N'.
+config IMGPDC_WDT
+ tristate "Imagination Technologies PDC Watchdog Timer"
+ depends on HAS_IOMEM
+ depends on METAG || MIPS || COMPILE_TEST
+ help
+ Driver for Imagination Technologies PowerDown Controller
+ Watchdog Timer.
+
+ To compile this driver as a loadable module, choose M here.
+ The module will be called imgpdc_wdt.
+
config LANTIQ_WDT
tristate "Lantiq SoC watchdog"
depends on LANTIQ
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index c569ec8f8a76..5c19294d1c30 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -63,6 +63,7 @@ obj-$(CONFIG_QCOM_WDT) += qcom-wdt.o
obj-$(CONFIG_BCM_KONA_WDT) += bcm_kona_wdt.o
obj-$(CONFIG_TEGRA_WATCHDOG) += tegra_wdt.o
obj-$(CONFIG_MESON_WATCHDOG) += meson_wdt.o
+obj-$(CONFIG_MEDIATEK_WATCHDOG) += mtk_wdt.o
# AVR32 Architecture
obj-$(CONFIG_AT32AP700X_WDT) += at32ap700x_wdt.o
@@ -142,6 +143,7 @@ obj-$(CONFIG_OCTEON_WDT) += octeon-wdt.o
octeon-wdt-y := octeon-wdt-main.o octeon-wdt-nmi.o
obj-$(CONFIG_LANTIQ_WDT) += lantiq_wdt.o
obj-$(CONFIG_RALINK_WDT) += rt2880_wdt.o
+obj-$(CONFIG_IMGPDC_WDT) += imgpdc_wdt.o
# PARISC Architecture
diff --git a/drivers/watchdog/bcm47xx_wdt.c b/drivers/watchdog/bcm47xx_wdt.c
index 9816485f6825..b28a072abf78 100644
--- a/drivers/watchdog/bcm47xx_wdt.c
+++ b/drivers/watchdog/bcm47xx_wdt.c
@@ -169,6 +169,17 @@ static int bcm47xx_wdt_notify_sys(struct notifier_block *this,
return NOTIFY_DONE;
}
+static int bcm47xx_wdt_restart(struct notifier_block *this, unsigned long mode,
+ void *cmd)
+{
+ struct bcm47xx_wdt *wdt;
+
+ wdt = container_of(this, struct bcm47xx_wdt, restart_handler);
+ wdt->timer_set(wdt, 1);
+
+ return NOTIFY_DONE;
+}
+
static struct watchdog_ops bcm47xx_wdt_soft_ops = {
.owner = THIS_MODULE,
.start = bcm47xx_wdt_soft_start,
@@ -209,15 +220,23 @@ static int bcm47xx_wdt_probe(struct platform_device *pdev)
if (ret)
goto err_timer;
- ret = watchdog_register_device(&wdt->wdd);
+ wdt->restart_handler.notifier_call = &bcm47xx_wdt_restart;
+ wdt->restart_handler.priority = 64;
+ ret = register_restart_handler(&wdt->restart_handler);
if (ret)
goto err_notifier;
+ ret = watchdog_register_device(&wdt->wdd);
+ if (ret)
+ goto err_handler;
+
dev_info(&pdev->dev, "BCM47xx Watchdog Timer enabled (%d seconds%s%s)\n",
timeout, nowayout ? ", nowayout" : "",
soft ? ", Software Timer" : "");
return 0;
+err_handler:
+ unregister_restart_handler(&wdt->restart_handler);
err_notifier:
unregister_reboot_notifier(&wdt->notifier);
err_timer:
diff --git a/drivers/watchdog/da9063_wdt.c b/drivers/watchdog/da9063_wdt.c
index 2cd6b2c2dd2a..e2fe2ebdebd4 100644
--- a/drivers/watchdog/da9063_wdt.c
+++ b/drivers/watchdog/da9063_wdt.c
@@ -20,6 +20,7 @@
#include <linux/delay.h>
#include <linux/mfd/da9063/registers.h>
#include <linux/mfd/da9063/core.h>
+#include <linux/reboot.h>
#include <linux/regmap.h>
/*
@@ -38,6 +39,7 @@ static const unsigned int wdt_timeout[] = { 0, 2, 4, 8, 16, 32, 65, 131 };
struct da9063_watchdog {
struct da9063 *da9063;
struct watchdog_device wdtdev;
+ struct notifier_block restart_handler;
};
static unsigned int da9063_wdt_timeout_to_sel(unsigned int secs)
@@ -119,6 +121,23 @@ static int da9063_wdt_set_timeout(struct watchdog_device *wdd,
return ret;
}
+static int da9063_wdt_restart_handler(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ struct da9063_watchdog *wdt = container_of(this,
+ struct da9063_watchdog,
+ restart_handler);
+ int ret;
+
+ ret = regmap_write(wdt->da9063->regmap, DA9063_REG_CONTROL_F,
+ DA9063_SHUTDOWN);
+ if (ret)
+ dev_alert(wdt->da9063->dev, "Failed to shutdown (err = %d)\n",
+ ret);
+
+ return NOTIFY_DONE;
+}
+
static const struct watchdog_info da9063_watchdog_info = {
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.identity = "DA9063 Watchdog",
@@ -163,14 +182,25 @@ static int da9063_wdt_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, wdt);
ret = watchdog_register_device(&wdt->wdtdev);
+ if (ret)
+ return ret;
- return ret;
+ wdt->restart_handler.notifier_call = da9063_wdt_restart_handler;
+ wdt->restart_handler.priority = 128;
+ ret = register_restart_handler(&wdt->restart_handler);
+ if (ret)
+ dev_err(wdt->da9063->dev,
+ "Failed to register restart handler (err = %d)\n", ret);
+
+ return 0;
}
static int da9063_wdt_remove(struct platform_device *pdev)
{
struct da9063_watchdog *wdt = dev_get_drvdata(&pdev->dev);
+ unregister_restart_handler(&wdt->restart_handler);
+
watchdog_unregister_device(&wdt->wdtdev);
return 0;
diff --git a/drivers/watchdog/dw_wdt.c b/drivers/watchdog/dw_wdt.c
index b34a2e4e4e43..d0bb9499d12c 100644
--- a/drivers/watchdog/dw_wdt.c
+++ b/drivers/watchdog/dw_wdt.c
@@ -51,6 +51,8 @@
/* The maximum TOP (timeout period) value that can be set in the watchdog. */
#define DW_WDT_MAX_TOP 15
+#define DW_WDT_DEFAULT_SECONDS 30
+
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
@@ -96,6 +98,12 @@ static inline void dw_wdt_set_next_heartbeat(void)
dw_wdt.next_heartbeat = jiffies + dw_wdt_get_top() * HZ;
}
+static void dw_wdt_keepalive(void)
+{
+ writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
+ WDOG_COUNTER_RESTART_REG_OFFSET);
+}
+
static int dw_wdt_set_top(unsigned top_s)
{
int i, top_val = DW_WDT_MAX_TOP;
@@ -110,21 +118,27 @@ static int dw_wdt_set_top(unsigned top_s)
break;
}
- /* Set the new value in the watchdog. */
+ /*
+ * Set the new value in the watchdog. Some versions of dw_wdt
+ * have have TOPINIT in the TIMEOUT_RANGE register (as per
+ * CP_WDT_DUAL_TOP in WDT_COMP_PARAMS_1). On those we
+ * effectively get a pat of the watchdog right here.
+ */
writel(top_val | top_val << WDOG_TIMEOUT_RANGE_TOPINIT_SHIFT,
dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
+ /*
+ * Add an explicit pat to handle versions of the watchdog that
+ * don't have TOPINIT. This won't hurt on versions that have
+ * it.
+ */
+ dw_wdt_keepalive();
+
dw_wdt_set_next_heartbeat();
return dw_wdt_top_in_seconds(top_val);
}
-static void dw_wdt_keepalive(void)
-{
- writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
- WDOG_COUNTER_RESTART_REG_OFFSET);
-}
-
static int dw_wdt_restart_handle(struct notifier_block *this,
unsigned long mode, void *cmd)
{
@@ -167,9 +181,9 @@ static int dw_wdt_open(struct inode *inode, struct file *filp)
if (!dw_wdt_is_enabled()) {
/*
* The watchdog is not currently enabled. Set the timeout to
- * the maximum and then start it.
+ * something reasonable and then start it.
*/
- dw_wdt_set_top(DW_WDT_MAX_TOP);
+ dw_wdt_set_top(DW_WDT_DEFAULT_SECONDS);
writel(WDOG_CONTROL_REG_WDT_EN_MASK,
dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
}
diff --git a/drivers/watchdog/gpio_wdt.c b/drivers/watchdog/gpio_wdt.c
index bbdb19b45332..cbc313d37c59 100644
--- a/drivers/watchdog/gpio_wdt.c
+++ b/drivers/watchdog/gpio_wdt.c
@@ -31,6 +31,8 @@ struct gpio_wdt_priv {
int gpio;
bool active_low;
bool state;
+ bool always_running;
+ bool armed;
unsigned int hw_algo;
unsigned int hw_margin;
unsigned long last_jiffies;
@@ -48,14 +50,20 @@ static void gpio_wdt_disable(struct gpio_wdt_priv *priv)
gpio_direction_input(priv->gpio);
}
-static int gpio_wdt_start(struct watchdog_device *wdd)
+static void gpio_wdt_start_impl(struct gpio_wdt_priv *priv)
{
- struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
-
priv->state = priv->active_low;
gpio_direction_output(priv->gpio, priv->state);
priv->last_jiffies = jiffies;
mod_timer(&priv->timer, priv->last_jiffies + priv->hw_margin);
+}
+
+static int gpio_wdt_start(struct watchdog_device *wdd)
+{
+ struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
+
+ gpio_wdt_start_impl(priv);
+ priv->armed = true;
return 0;
}
@@ -64,8 +72,11 @@ static int gpio_wdt_stop(struct watchdog_device *wdd)
{
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
- mod_timer(&priv->timer, 0);
- gpio_wdt_disable(priv);
+ priv->armed = false;
+ if (!priv->always_running) {
+ mod_timer(&priv->timer, 0);
+ gpio_wdt_disable(priv);
+ }
return 0;
}
@@ -91,8 +102,8 @@ static void gpio_wdt_hwping(unsigned long data)
struct watchdog_device *wdd = (struct watchdog_device *)data;
struct gpio_wdt_priv *priv = watchdog_get_drvdata(wdd);
- if (time_after(jiffies, priv->last_jiffies +
- msecs_to_jiffies(wdd->timeout * 1000))) {
+ if (priv->armed && time_after(jiffies, priv->last_jiffies +
+ msecs_to_jiffies(wdd->timeout * 1000))) {
dev_crit(wdd->dev, "Timer expired. System will reboot soon!\n");
return;
}
@@ -197,6 +208,9 @@ static int gpio_wdt_probe(struct platform_device *pdev)
/* Use safe value (1/2 of real timeout) */
priv->hw_margin = msecs_to_jiffies(hw_margin / 2);
+ priv->always_running = of_property_read_bool(pdev->dev.of_node,
+ "always-running");
+
watchdog_set_drvdata(&priv->wdd, priv);
priv->wdd.info = &gpio_wdt_ident;
@@ -216,8 +230,15 @@ static int gpio_wdt_probe(struct platform_device *pdev)
priv->notifier.notifier_call = gpio_wdt_notify_sys;
ret = register_reboot_notifier(&priv->notifier);
if (ret)
- watchdog_unregister_device(&priv->wdd);
+ goto error_unregister;
+ if (priv->always_running)
+ gpio_wdt_start_impl(priv);
+
+ return 0;
+
+error_unregister:
+ watchdog_unregister_device(&priv->wdd);
return ret;
}
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c
index 75d2243b94f5..ada3e44f9932 100644
--- a/drivers/watchdog/hpwdt.c
+++ b/drivers/watchdog/hpwdt.c
@@ -745,7 +745,7 @@ static int hpwdt_init_nmi_decoding(struct pci_dev *dev)
dev_info(&dev->dev,
"HP Watchdog Timer Driver: NMI decoding initialized"
- ", allow kernel dump: %s (default = 0/OFF)\n",
+ ", allow kernel dump: %s (default = 1/ON)\n",
(allow_kdump == 0) ? "OFF" : "ON");
return 0;
diff --git a/drivers/watchdog/imgpdc_wdt.c b/drivers/watchdog/imgpdc_wdt.c
new file mode 100644
index 000000000000..c8def68d9e4c
--- /dev/null
+++ b/drivers/watchdog/imgpdc_wdt.c
@@ -0,0 +1,289 @@
+/*
+ * Imagination Technologies PowerDown Controller Watchdog Timer.
+ *
+ * Copyright (c) 2014 Imagination Technologies Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Based on drivers/watchdog/sunxi_wdt.c Copyright (c) 2013 Carlo Caione
+ * 2012 Henrik Nordstrom
+ */
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/log2.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/watchdog.h>
+
+/* registers */
+#define PDC_WDT_SOFT_RESET 0x00
+#define PDC_WDT_CONFIG 0x04
+ #define PDC_WDT_CONFIG_ENABLE BIT(31)
+ #define PDC_WDT_CONFIG_DELAY_MASK 0x1f
+
+#define PDC_WDT_TICKLE1 0x08
+#define PDC_WDT_TICKLE1_MAGIC 0xabcd1234
+#define PDC_WDT_TICKLE2 0x0c
+#define PDC_WDT_TICKLE2_MAGIC 0x4321dcba
+
+#define PDC_WDT_TICKLE_STATUS_MASK 0x7
+#define PDC_WDT_TICKLE_STATUS_SHIFT 0
+#define PDC_WDT_TICKLE_STATUS_HRESET 0x0 /* Hard reset */
+#define PDC_WDT_TICKLE_STATUS_TIMEOUT 0x1 /* Timeout */
+#define PDC_WDT_TICKLE_STATUS_TICKLE 0x2 /* Tickled incorrectly */
+#define PDC_WDT_TICKLE_STATUS_SRESET 0x3 /* Soft reset */
+#define PDC_WDT_TICKLE_STATUS_USER 0x4 /* User reset */
+
+/* Timeout values are in seconds */
+#define PDC_WDT_MIN_TIMEOUT 1
+#define PDC_WDT_DEF_TIMEOUT 64
+
+static int heartbeat;
+module_param(heartbeat, int, 0);
+MODULE_PARM_DESC(heartbeat, "Watchdog heartbeats in seconds. "
+ "(default = " __MODULE_STRING(PDC_WDT_DEF_TIMEOUT) ")");
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started "
+ "(default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+struct pdc_wdt_dev {
+ struct watchdog_device wdt_dev;
+ struct clk *wdt_clk;
+ struct clk *sys_clk;
+ void __iomem *base;
+};
+
+static int pdc_wdt_keepalive(struct watchdog_device *wdt_dev)
+{
+ struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+
+ writel(PDC_WDT_TICKLE1_MAGIC, wdt->base + PDC_WDT_TICKLE1);
+ writel(PDC_WDT_TICKLE2_MAGIC, wdt->base + PDC_WDT_TICKLE2);
+
+ return 0;
+}
+
+static int pdc_wdt_stop(struct watchdog_device *wdt_dev)
+{
+ unsigned int val;
+ struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+
+ val = readl(wdt->base + PDC_WDT_CONFIG);
+ val &= ~PDC_WDT_CONFIG_ENABLE;
+ writel(val, wdt->base + PDC_WDT_CONFIG);
+
+ /* Must tickle to finish the stop */
+ pdc_wdt_keepalive(wdt_dev);
+
+ return 0;
+}
+
+static int pdc_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int new_timeout)
+{
+ unsigned int val;
+ struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+ unsigned long clk_rate = clk_get_rate(wdt->wdt_clk);
+
+ wdt->wdt_dev.timeout = new_timeout;
+
+ val = readl(wdt->base + PDC_WDT_CONFIG) & ~PDC_WDT_CONFIG_DELAY_MASK;
+ val |= order_base_2(new_timeout * clk_rate) - 1;
+ writel(val, wdt->base + PDC_WDT_CONFIG);
+
+ return 0;
+}
+
+/* Start the watchdog timer (delay should already be set) */
+static int pdc_wdt_start(struct watchdog_device *wdt_dev)
+{
+ unsigned int val;
+ struct pdc_wdt_dev *wdt = watchdog_get_drvdata(wdt_dev);
+
+ val = readl(wdt->base + PDC_WDT_CONFIG);
+ val |= PDC_WDT_CONFIG_ENABLE;
+ writel(val, wdt->base + PDC_WDT_CONFIG);
+
+ return 0;
+}
+
+static struct watchdog_info pdc_wdt_info = {
+ .identity = "IMG PDC Watchdog",
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops pdc_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = pdc_wdt_start,
+ .stop = pdc_wdt_stop,
+ .ping = pdc_wdt_keepalive,
+ .set_timeout = pdc_wdt_set_timeout,
+};
+
+static int pdc_wdt_probe(struct platform_device *pdev)
+{
+ int ret, val;
+ unsigned long clk_rate;
+ struct resource *res;
+ struct pdc_wdt_dev *pdc_wdt;
+
+ pdc_wdt = devm_kzalloc(&pdev->dev, sizeof(*pdc_wdt), GFP_KERNEL);
+ if (!pdc_wdt)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pdc_wdt->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pdc_wdt->base))
+ return PTR_ERR(pdc_wdt->base);
+
+ pdc_wdt->sys_clk = devm_clk_get(&pdev->dev, "sys");
+ if (IS_ERR(pdc_wdt->sys_clk)) {
+ dev_err(&pdev->dev, "failed to get the sys clock\n");
+ return PTR_ERR(pdc_wdt->sys_clk);
+ }
+
+ pdc_wdt->wdt_clk = devm_clk_get(&pdev->dev, "wdt");
+ if (IS_ERR(pdc_wdt->wdt_clk)) {
+ dev_err(&pdev->dev, "failed to get the wdt clock\n");
+ return PTR_ERR(pdc_wdt->wdt_clk);
+ }
+
+ ret = clk_prepare_enable(pdc_wdt->sys_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "could not prepare or enable sys clock\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(pdc_wdt->wdt_clk);
+ if (ret) {
+ dev_err(&pdev->dev, "could not prepare or enable wdt clock\n");
+ goto disable_sys_clk;
+ }
+
+ /* We use the clock rate to calculate the max timeout */
+ clk_rate = clk_get_rate(pdc_wdt->wdt_clk);
+ if (clk_rate == 0) {
+ dev_err(&pdev->dev, "failed to get clock rate\n");
+ ret = -EINVAL;
+ goto disable_wdt_clk;
+ }
+
+ if (order_base_2(clk_rate) > PDC_WDT_CONFIG_DELAY_MASK + 1) {
+ dev_err(&pdev->dev, "invalid clock rate\n");
+ ret = -EINVAL;
+ goto disable_wdt_clk;
+ }
+
+ if (order_base_2(clk_rate) == 0)
+ pdc_wdt->wdt_dev.min_timeout = PDC_WDT_MIN_TIMEOUT + 1;
+ else
+ pdc_wdt->wdt_dev.min_timeout = PDC_WDT_MIN_TIMEOUT;
+
+ pdc_wdt->wdt_dev.info = &pdc_wdt_info;
+ pdc_wdt->wdt_dev.ops = &pdc_wdt_ops;
+ pdc_wdt->wdt_dev.max_timeout = 1 << PDC_WDT_CONFIG_DELAY_MASK;
+ pdc_wdt->wdt_dev.parent = &pdev->dev;
+
+ ret = watchdog_init_timeout(&pdc_wdt->wdt_dev, heartbeat, &pdev->dev);
+ if (ret < 0) {
+ pdc_wdt->wdt_dev.timeout = pdc_wdt->wdt_dev.max_timeout;
+ dev_warn(&pdev->dev,
+ "Initial timeout out of range! setting max timeout\n");
+ }
+
+ pdc_wdt_stop(&pdc_wdt->wdt_dev);
+
+ /* Find what caused the last reset */
+ val = readl(pdc_wdt->base + PDC_WDT_TICKLE1);
+ val = (val & PDC_WDT_TICKLE_STATUS_MASK) >> PDC_WDT_TICKLE_STATUS_SHIFT;
+ switch (val) {
+ case PDC_WDT_TICKLE_STATUS_TICKLE:
+ case PDC_WDT_TICKLE_STATUS_TIMEOUT:
+ pdc_wdt->wdt_dev.bootstatus |= WDIOF_CARDRESET;
+ dev_info(&pdev->dev,
+ "watchdog module last reset due to timeout\n");
+ break;
+ case PDC_WDT_TICKLE_STATUS_HRESET:
+ dev_info(&pdev->dev,
+ "watchdog module last reset due to hard reset\n");
+ break;
+ case PDC_WDT_TICKLE_STATUS_SRESET:
+ dev_info(&pdev->dev,
+ "watchdog module last reset due to soft reset\n");
+ break;
+ case PDC_WDT_TICKLE_STATUS_USER:
+ dev_info(&pdev->dev,
+ "watchdog module last reset due to user reset\n");
+ break;
+ default:
+ dev_info(&pdev->dev,
+ "contains an illegal status code (%08x)\n", val);
+ break;
+ }
+
+ watchdog_set_nowayout(&pdc_wdt->wdt_dev, nowayout);
+
+ platform_set_drvdata(pdev, pdc_wdt);
+ watchdog_set_drvdata(&pdc_wdt->wdt_dev, pdc_wdt);
+
+ ret = watchdog_register_device(&pdc_wdt->wdt_dev);
+ if (ret)
+ goto disable_wdt_clk;
+
+ return 0;
+
+disable_wdt_clk:
+ clk_disable_unprepare(pdc_wdt->wdt_clk);
+disable_sys_clk:
+ clk_disable_unprepare(pdc_wdt->sys_clk);
+ return ret;
+}
+
+static void pdc_wdt_shutdown(struct platform_device *pdev)
+{
+ struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev);
+
+ pdc_wdt_stop(&pdc_wdt->wdt_dev);
+}
+
+static int pdc_wdt_remove(struct platform_device *pdev)
+{
+ struct pdc_wdt_dev *pdc_wdt = platform_get_drvdata(pdev);
+
+ pdc_wdt_stop(&pdc_wdt->wdt_dev);
+ watchdog_unregister_device(&pdc_wdt->wdt_dev);
+ clk_disable_unprepare(pdc_wdt->wdt_clk);
+ clk_disable_unprepare(pdc_wdt->sys_clk);
+
+ return 0;
+}
+
+static const struct of_device_id pdc_wdt_match[] = {
+ { .compatible = "img,pdc-wdt" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, pdc_wdt_match);
+
+static struct platform_driver pdc_wdt_driver = {
+ .driver = {
+ .name = "imgpdc-wdt",
+ .of_match_table = pdc_wdt_match,
+ },
+ .probe = pdc_wdt_probe,
+ .remove = pdc_wdt_remove,
+ .shutdown = pdc_wdt_shutdown,
+};
+module_platform_driver(pdc_wdt_driver);
+
+MODULE_AUTHOR("Jude Abraham <Jude.Abraham@imgtec.com>");
+MODULE_AUTHOR("Naidu Tellapati <Naidu.Tellapati@imgtec.com>");
+MODULE_DESCRIPTION("Imagination Technologies PDC Watchdog Timer Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/watchdog/imx2_wdt.c b/drivers/watchdog/imx2_wdt.c
index 5142bbabe027..5e6d808d358a 100644
--- a/drivers/watchdog/imx2_wdt.c
+++ b/drivers/watchdog/imx2_wdt.c
@@ -205,7 +205,7 @@ static inline void imx2_wdt_ping_if_active(struct watchdog_device *wdog)
}
}
-static struct watchdog_ops imx2_wdt_ops = {
+static const struct watchdog_ops imx2_wdt_ops = {
.owner = THIS_MODULE,
.start = imx2_wdt_start,
.stop = imx2_wdt_stop,
@@ -213,7 +213,7 @@ static struct watchdog_ops imx2_wdt_ops = {
.set_timeout = imx2_wdt_set_timeout,
};
-static struct regmap_config imx2_wdt_regmap_config = {
+static const struct regmap_config imx2_wdt_regmap_config = {
.reg_bits = 16,
.reg_stride = 2,
.val_bits = 16,
diff --git a/drivers/watchdog/it87_wdt.c b/drivers/watchdog/it87_wdt.c
index 0b93739c0106..e54839b12650 100644
--- a/drivers/watchdog/it87_wdt.c
+++ b/drivers/watchdog/it87_wdt.c
@@ -12,8 +12,8 @@
* http://www.ite.com.tw/
*
* Support of the watchdog timers, which are available on
- * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726
- * and IT8728.
+ * IT8702, IT8712, IT8716, IT8718, IT8720, IT8721, IT8726,
+ * IT8728 and IT8783.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -87,6 +87,7 @@
#define IT8721_ID 0x8721
#define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */
#define IT8728_ID 0x8728
+#define IT8783_ID 0x8783
/* GPIO Configuration Registers LDN=0x07 */
#define WDTCTRL 0x71
@@ -633,6 +634,7 @@ static int __init it87_wdt_init(void)
case IT8720_ID:
case IT8721_ID:
case IT8728_ID:
+ case IT8783_ID:
max_units = 65535;
try_gameport = 0;
break;
diff --git a/drivers/watchdog/jz4740_wdt.c b/drivers/watchdog/jz4740_wdt.c
index 18e41afa4da3..4c2cc09c0c57 100644
--- a/drivers/watchdog/jz4740_wdt.c
+++ b/drivers/watchdog/jz4740_wdt.c
@@ -24,6 +24,7 @@
#include <linux/clk.h>
#include <linux/slab.h>
#include <linux/err.h>
+#include <linux/of.h>
#include <asm/mach-jz4740/timer.h>
@@ -142,6 +143,14 @@ static const struct watchdog_ops jz4740_wdt_ops = {
.set_timeout = jz4740_wdt_set_timeout,
};
+#ifdef CONFIG_OF
+static const struct of_device_id jz4740_wdt_of_matches[] = {
+ { .compatible = "ingenic,jz4740-watchdog", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, jz4740_wdt_of_matches)
+#endif
+
static int jz4740_wdt_probe(struct platform_device *pdev)
{
struct jz4740_wdt_drvdata *drvdata;
@@ -211,6 +220,7 @@ static struct platform_driver jz4740_wdt_driver = {
.remove = jz4740_wdt_remove,
.driver = {
.name = "jz4740-wdt",
+ .of_match_table = of_match_ptr(jz4740_wdt_of_matches),
},
};
diff --git a/drivers/watchdog/mtk_wdt.c b/drivers/watchdog/mtk_wdt.c
new file mode 100644
index 000000000000..a87f6df6e85f
--- /dev/null
+++ b/drivers/watchdog/mtk_wdt.c
@@ -0,0 +1,251 @@
+/*
+ * Mediatek Watchdog Driver
+ *
+ * Copyright (C) 2014 Matthias Brugger
+ *
+ * Matthias Brugger <matthias.bgg@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.
+ *
+ * Based on sunxi_wdt.c
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <linux/watchdog.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
+#include <linux/delay.h>
+
+#define WDT_MAX_TIMEOUT 31
+#define WDT_MIN_TIMEOUT 1
+#define WDT_LENGTH_TIMEOUT(n) ((n) << 5)
+
+#define WDT_LENGTH 0x04
+#define WDT_LENGTH_KEY 0x8
+
+#define WDT_RST 0x08
+#define WDT_RST_RELOAD 0x1971
+
+#define WDT_MODE 0x00
+#define WDT_MODE_EN (1 << 0)
+#define WDT_MODE_EXT_POL_LOW (0 << 1)
+#define WDT_MODE_EXT_POL_HIGH (1 << 1)
+#define WDT_MODE_EXRST_EN (1 << 2)
+#define WDT_MODE_IRQ_EN (1 << 3)
+#define WDT_MODE_AUTO_START (1 << 4)
+#define WDT_MODE_DUAL_EN (1 << 6)
+#define WDT_MODE_KEY 0x22000000
+
+#define WDT_SWRST 0x14
+#define WDT_SWRST_KEY 0x1209
+
+#define DRV_NAME "mtk-wdt"
+#define DRV_VERSION "1.0"
+
+static bool nowayout = WATCHDOG_NOWAYOUT;
+static unsigned int timeout = WDT_MAX_TIMEOUT;
+
+struct mtk_wdt_dev {
+ struct watchdog_device wdt_dev;
+ void __iomem *wdt_base;
+ struct notifier_block restart_handler;
+};
+
+static int mtk_reset_handler(struct notifier_block *this, unsigned long mode,
+ void *cmd)
+{
+ struct mtk_wdt_dev *mtk_wdt;
+ void __iomem *wdt_base;
+
+ mtk_wdt = container_of(this, struct mtk_wdt_dev, restart_handler);
+ wdt_base = mtk_wdt->wdt_base;
+
+ while (1) {
+ writel(WDT_SWRST_KEY, wdt_base + WDT_SWRST);
+ mdelay(5);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static int mtk_wdt_ping(struct watchdog_device *wdt_dev)
+{
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+ void __iomem *wdt_base = mtk_wdt->wdt_base;
+
+ iowrite32(WDT_RST_RELOAD, wdt_base + WDT_RST);
+
+ return 0;
+}
+
+static int mtk_wdt_set_timeout(struct watchdog_device *wdt_dev,
+ unsigned int timeout)
+{
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+ void __iomem *wdt_base = mtk_wdt->wdt_base;
+ u32 reg;
+
+ wdt_dev->timeout = timeout;
+
+ /*
+ * One bit is the value of 512 ticks
+ * The clock has 32 KHz
+ */
+ reg = WDT_LENGTH_TIMEOUT(timeout << 6) | WDT_LENGTH_KEY;
+ iowrite32(reg, wdt_base + WDT_LENGTH);
+
+ mtk_wdt_ping(wdt_dev);
+
+ return 0;
+}
+
+static int mtk_wdt_stop(struct watchdog_device *wdt_dev)
+{
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+ void __iomem *wdt_base = mtk_wdt->wdt_base;
+ u32 reg;
+
+ reg = readl(wdt_base + WDT_MODE);
+ reg &= ~WDT_MODE_EN;
+ iowrite32(reg, wdt_base + WDT_MODE);
+
+ return 0;
+}
+
+static int mtk_wdt_start(struct watchdog_device *wdt_dev)
+{
+ u32 reg;
+ struct mtk_wdt_dev *mtk_wdt = watchdog_get_drvdata(wdt_dev);
+ void __iomem *wdt_base = mtk_wdt->wdt_base;
+ u32 ret;
+
+ ret = mtk_wdt_set_timeout(wdt_dev, wdt_dev->timeout);
+ if (ret < 0)
+ return ret;
+
+ reg = ioread32(wdt_base + WDT_MODE);
+ reg &= ~(WDT_MODE_IRQ_EN | WDT_MODE_DUAL_EN);
+ reg |= (WDT_MODE_EN | WDT_MODE_KEY);
+ iowrite32(reg, wdt_base + WDT_MODE);
+
+ return 0;
+}
+
+static const struct watchdog_info mtk_wdt_info = {
+ .identity = DRV_NAME,
+ .options = WDIOF_SETTIMEOUT |
+ WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
+};
+
+static const struct watchdog_ops mtk_wdt_ops = {
+ .owner = THIS_MODULE,
+ .start = mtk_wdt_start,
+ .stop = mtk_wdt_stop,
+ .ping = mtk_wdt_ping,
+ .set_timeout = mtk_wdt_set_timeout,
+};
+
+static int mtk_wdt_probe(struct platform_device *pdev)
+{
+ struct mtk_wdt_dev *mtk_wdt;
+ struct resource *res;
+ int err;
+
+ mtk_wdt = devm_kzalloc(&pdev->dev, sizeof(*mtk_wdt), GFP_KERNEL);
+ if (!mtk_wdt)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mtk_wdt);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mtk_wdt->wdt_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mtk_wdt->wdt_base))
+ return PTR_ERR(mtk_wdt->wdt_base);
+
+ mtk_wdt->wdt_dev.info = &mtk_wdt_info;
+ mtk_wdt->wdt_dev.ops = &mtk_wdt_ops;
+ mtk_wdt->wdt_dev.timeout = WDT_MAX_TIMEOUT;
+ mtk_wdt->wdt_dev.max_timeout = WDT_MAX_TIMEOUT;
+ mtk_wdt->wdt_dev.min_timeout = WDT_MIN_TIMEOUT;
+ mtk_wdt->wdt_dev.parent = &pdev->dev;
+
+ watchdog_init_timeout(&mtk_wdt->wdt_dev, timeout, &pdev->dev);
+ watchdog_set_nowayout(&mtk_wdt->wdt_dev, nowayout);
+
+ watchdog_set_drvdata(&mtk_wdt->wdt_dev, mtk_wdt);
+
+ mtk_wdt_stop(&mtk_wdt->wdt_dev);
+
+ err = watchdog_register_device(&mtk_wdt->wdt_dev);
+ if (unlikely(err))
+ return err;
+
+ mtk_wdt->restart_handler.notifier_call = mtk_reset_handler;
+ mtk_wdt->restart_handler.priority = 128;
+ err = register_restart_handler(&mtk_wdt->restart_handler);
+ if (err)
+ dev_warn(&pdev->dev,
+ "cannot register restart handler (err=%d)\n", err);
+
+ dev_info(&pdev->dev, "Watchdog enabled (timeout=%d sec, nowayout=%d)\n",
+ mtk_wdt->wdt_dev.timeout, nowayout);
+
+ return 0;
+}
+
+static int mtk_wdt_remove(struct platform_device *pdev)
+{
+ struct mtk_wdt_dev *mtk_wdt = platform_get_drvdata(pdev);
+
+ unregister_restart_handler(&mtk_wdt->restart_handler);
+
+ watchdog_unregister_device(&mtk_wdt->wdt_dev);
+
+ return 0;
+}
+
+static const struct of_device_id mtk_wdt_dt_ids[] = {
+ { .compatible = "mediatek,mt6589-wdt" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, mtk_wdt_dt_ids);
+
+static struct platform_driver mtk_wdt_driver = {
+ .probe = mtk_wdt_probe,
+ .remove = mtk_wdt_remove,
+ .driver = {
+ .name = DRV_NAME,
+ .of_match_table = mtk_wdt_dt_ids,
+ },
+};
+
+module_platform_driver(mtk_wdt_driver);
+
+module_param(timeout, uint, 0);
+MODULE_PARM_DESC(timeout, "Watchdog heartbeat in seconds");
+
+module_param(nowayout, bool, 0);
+MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
+ __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Matthias Brugger <matthias.bgg@gmail.com>");
+MODULE_DESCRIPTION("Mediatek WatchDog Timer Driver");
+MODULE_VERSION(DRV_VERSION);
diff --git a/drivers/watchdog/omap_wdt.c b/drivers/watchdog/omap_wdt.c
index 9f2709db61ca..1e6be9e40577 100644
--- a/drivers/watchdog/omap_wdt.c
+++ b/drivers/watchdog/omap_wdt.c
@@ -189,7 +189,7 @@ static int omap_wdt_set_timeout(struct watchdog_device *wdog,
}
static const struct watchdog_info omap_wdt_info = {
- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "OMAP Watchdog",
};
diff --git a/drivers/watchdog/retu_wdt.c b/drivers/watchdog/retu_wdt.c
index a7a0695971e4..b7c68e275aeb 100644
--- a/drivers/watchdog/retu_wdt.c
+++ b/drivers/watchdog/retu_wdt.c
@@ -94,7 +94,7 @@ static int retu_wdt_set_timeout(struct watchdog_device *wdog,
}
static const struct watchdog_info retu_wdt_info = {
- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "Retu watchdog",
};
diff --git a/drivers/watchdog/rt2880_wdt.c b/drivers/watchdog/rt2880_wdt.c
index 11aad5b7aafe..a6f7e2e29beb 100644
--- a/drivers/watchdog/rt2880_wdt.c
+++ b/drivers/watchdog/rt2880_wdt.c
@@ -45,6 +45,7 @@
static struct clk *rt288x_wdt_clk;
static unsigned long rt288x_wdt_freq;
static void __iomem *rt288x_wdt_base;
+static struct reset_control *rt288x_wdt_reset;
static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, 0);
@@ -151,16 +152,18 @@ static int rt288x_wdt_probe(struct platform_device *pdev)
if (IS_ERR(rt288x_wdt_clk))
return PTR_ERR(rt288x_wdt_clk);
- device_reset(&pdev->dev);
+ rt288x_wdt_reset = devm_reset_control_get(&pdev->dev, NULL);
+ if (!IS_ERR(rt288x_wdt_reset))
+ reset_control_deassert(rt288x_wdt_reset);
rt288x_wdt_freq = clk_get_rate(rt288x_wdt_clk) / RALINK_WDT_PRESCALE;
rt288x_wdt_dev.dev = &pdev->dev;
rt288x_wdt_dev.bootstatus = rt288x_wdt_bootcause();
-
rt288x_wdt_dev.max_timeout = (0xfffful / rt288x_wdt_freq);
- rt288x_wdt_dev.timeout = rt288x_wdt_dev.max_timeout;
+ watchdog_init_timeout(&rt288x_wdt_dev, rt288x_wdt_dev.max_timeout,
+ &pdev->dev);
watchdog_set_nowayout(&rt288x_wdt_dev, nowayout);
ret = watchdog_register_device(&rt288x_wdt_dev);
diff --git a/drivers/watchdog/twl4030_wdt.c b/drivers/watchdog/twl4030_wdt.c
index 12c15903d098..2c1db6fa9a27 100644
--- a/drivers/watchdog/twl4030_wdt.c
+++ b/drivers/watchdog/twl4030_wdt.c
@@ -57,7 +57,7 @@ static int twl4030_wdt_set_timeout(struct watchdog_device *wdt,
}
static const struct watchdog_info twl4030_wdt_info = {
- .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
+ .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE | WDIOF_KEEPALIVEPING,
.identity = "TWL4030 Watchdog",
};
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c
index 7165704a3e33..5824e25eebbb 100644
--- a/drivers/watchdog/w83627hf_wdt.c
+++ b/drivers/watchdog/w83627hf_wdt.c
@@ -50,7 +50,7 @@ static int cr_wdt_control; /* WDT control register */
enum chips { w83627hf, w83627s, w83697hf, w83697ug, w83637hf, w83627thf,
w83687thf, w83627ehf, w83627dhg, w83627uhg, w83667hg, w83627dhg_p,
- w83667hg_b, nct6775, nct6776, nct6779 };
+ w83667hg_b, nct6775, nct6776, nct6779, nct6791, nct6792 };
static int timeout; /* in seconds */
module_param(timeout, int, 0);
@@ -95,6 +95,8 @@ MODULE_PARM_DESC(early_disable, "Disable watchdog at boot time (default=0)");
#define NCT6775_ID 0xb4
#define NCT6776_ID 0xc3
#define NCT6779_ID 0xc5
+#define NCT6791_ID 0xc8
+#define NCT6792_ID 0xc9
#define W83627HF_WDT_TIMEOUT 0xf6
#define W83697HF_WDT_TIMEOUT 0xf4
@@ -195,6 +197,8 @@ static int w83627hf_init(struct watchdog_device *wdog, enum chips chip)
case nct6775:
case nct6776:
case nct6779:
+ case nct6791:
+ case nct6792:
/*
* These chips have a fixed WDTO# output pin (W83627UHG),
* or support more than one WDTO# output pin.
@@ -395,6 +399,12 @@ static int wdt_find(int addr)
case NCT6779_ID:
ret = nct6779;
break;
+ case NCT6791_ID:
+ ret = nct6791;
+ break;
+ case NCT6792_ID:
+ ret = nct6792;
+ break;
case 0xff:
ret = -ENODEV;
break;
@@ -428,6 +438,8 @@ static int __init wdt_init(void)
"NCT6775",
"NCT6776",
"NCT6779",
+ "NCT6791",
+ "NCT6792",
};
wdt_io = 0x2e;
diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile
index 2140398a2a8c..2ccd3592d41f 100644
--- a/drivers/xen/Makefile
+++ b/drivers/xen/Makefile
@@ -2,7 +2,7 @@ ifeq ($(filter y, $(CONFIG_ARM) $(CONFIG_ARM64)),)
obj-$(CONFIG_HOTPLUG_CPU) += cpu_hotplug.o
endif
obj-$(CONFIG_X86) += fallback.o
-obj-y += grant-table.o features.o balloon.o manage.o
+obj-y += grant-table.o features.o balloon.o manage.o preempt.o
obj-y += events/
obj-y += xenbus/
diff --git a/drivers/xen/balloon.c b/drivers/xen/balloon.c
index 3860d02729dc..0b52d92cb2e5 100644
--- a/drivers/xen/balloon.c
+++ b/drivers/xen/balloon.c
@@ -92,7 +92,6 @@ EXPORT_SYMBOL_GPL(balloon_stats);
/* We increase/decrease in batches which fit in a page */
static xen_pfn_t frame_list[PAGE_SIZE / sizeof(unsigned long)];
-static DEFINE_PER_CPU(struct page *, balloon_scratch_page);
/* List of ballooned pages, threaded through the mem_map array. */
@@ -423,22 +422,12 @@ static enum bp_state decrease_reservation(unsigned long nr_pages, gfp_t gfp)
page = pfn_to_page(pfn);
#ifdef CONFIG_XEN_HAVE_PVMMU
- /*
- * Ballooned out frames are effectively replaced with
- * a scratch frame. Ensure direct mappings and the
- * p2m are consistent.
- */
if (!xen_feature(XENFEAT_auto_translated_physmap)) {
if (!PageHighMem(page)) {
- struct page *scratch_page = get_balloon_scratch_page();
-
ret = HYPERVISOR_update_va_mapping(
(unsigned long)__va(pfn << PAGE_SHIFT),
- pfn_pte(page_to_pfn(scratch_page),
- PAGE_KERNEL_RO), 0);
+ __pte_ma(0), 0);
BUG_ON(ret);
-
- put_balloon_scratch_page();
}
__set_phys_to_machine(pfn, INVALID_P2M_ENTRY);
}
@@ -500,18 +489,6 @@ static void balloon_process(struct work_struct *work)
mutex_unlock(&balloon_mutex);
}
-struct page *get_balloon_scratch_page(void)
-{
- struct page *ret = get_cpu_var(balloon_scratch_page);
- BUG_ON(ret == NULL);
- return ret;
-}
-
-void put_balloon_scratch_page(void)
-{
- put_cpu_var(balloon_scratch_page);
-}
-
/* Resets the Xen limit, sets new target, and kicks off processing. */
void balloon_set_new_target(unsigned long target)
{
@@ -605,61 +582,13 @@ static void __init balloon_add_region(unsigned long start_pfn,
}
}
-static int alloc_balloon_scratch_page(int cpu)
-{
- if (per_cpu(balloon_scratch_page, cpu) != NULL)
- return 0;
-
- per_cpu(balloon_scratch_page, cpu) = alloc_page(GFP_KERNEL);
- if (per_cpu(balloon_scratch_page, cpu) == NULL) {
- pr_warn("Failed to allocate balloon_scratch_page for cpu %d\n", cpu);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-
-static int balloon_cpu_notify(struct notifier_block *self,
- unsigned long action, void *hcpu)
-{
- int cpu = (long)hcpu;
- switch (action) {
- case CPU_UP_PREPARE:
- if (alloc_balloon_scratch_page(cpu))
- return NOTIFY_BAD;
- break;
- default:
- break;
- }
- return NOTIFY_OK;
-}
-
-static struct notifier_block balloon_cpu_notifier = {
- .notifier_call = balloon_cpu_notify,
-};
-
static int __init balloon_init(void)
{
- int i, cpu;
+ int i;
if (!xen_domain())
return -ENODEV;
- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
- register_cpu_notifier(&balloon_cpu_notifier);
-
- get_online_cpus();
- for_each_online_cpu(cpu) {
- if (alloc_balloon_scratch_page(cpu)) {
- put_online_cpus();
- unregister_cpu_notifier(&balloon_cpu_notifier);
- return -ENOMEM;
- }
- }
- put_online_cpus();
- }
-
pr_info("Initialising balloon driver\n");
balloon_stats.current_pages = xen_pv_domain()
@@ -696,15 +625,4 @@ static int __init balloon_init(void)
subsys_initcall(balloon_init);
-static int __init balloon_clear(void)
-{
- int cpu;
-
- for_each_possible_cpu(cpu)
- per_cpu(balloon_scratch_page, cpu) = NULL;
-
- return 0;
-}
-early_initcall(balloon_clear);
-
MODULE_LICENSE("GPL");
diff --git a/drivers/xen/gntdev.c b/drivers/xen/gntdev.c
index 073b4a19a8b0..d5bb1a33d0a3 100644
--- a/drivers/xen/gntdev.c
+++ b/drivers/xen/gntdev.c
@@ -67,7 +67,7 @@ struct gntdev_priv {
* Only populated if populate_freeable_maps == 1 */
struct list_head freeable_maps;
/* lock protects maps and freeable_maps */
- spinlock_t lock;
+ struct mutex lock;
struct mm_struct *mm;
struct mmu_notifier mn;
};
@@ -91,7 +91,9 @@ struct grant_map {
struct gnttab_map_grant_ref *map_ops;
struct gnttab_unmap_grant_ref *unmap_ops;
struct gnttab_map_grant_ref *kmap_ops;
+ struct gnttab_unmap_grant_ref *kunmap_ops;
struct page **pages;
+ unsigned long pages_vm_start;
};
static int unmap_grant_pages(struct grant_map *map, int offset, int pages);
@@ -118,12 +120,13 @@ static void gntdev_free_map(struct grant_map *map)
return;
if (map->pages)
- free_xenballooned_pages(map->count, map->pages);
+ gnttab_free_pages(map->count, map->pages);
kfree(map->pages);
kfree(map->grants);
kfree(map->map_ops);
kfree(map->unmap_ops);
kfree(map->kmap_ops);
+ kfree(map->kunmap_ops);
kfree(map);
}
@@ -140,21 +143,24 @@ static struct grant_map *gntdev_alloc_map(struct gntdev_priv *priv, int count)
add->map_ops = kcalloc(count, sizeof(add->map_ops[0]), GFP_KERNEL);
add->unmap_ops = kcalloc(count, sizeof(add->unmap_ops[0]), GFP_KERNEL);
add->kmap_ops = kcalloc(count, sizeof(add->kmap_ops[0]), GFP_KERNEL);
+ add->kunmap_ops = kcalloc(count, sizeof(add->kunmap_ops[0]), GFP_KERNEL);
add->pages = kcalloc(count, sizeof(add->pages[0]), GFP_KERNEL);
if (NULL == add->grants ||
NULL == add->map_ops ||
NULL == add->unmap_ops ||
NULL == add->kmap_ops ||
+ NULL == add->kunmap_ops ||
NULL == add->pages)
goto err;
- if (alloc_xenballooned_pages(count, add->pages, false /* lowmem */))
+ if (gnttab_alloc_pages(count, add->pages))
goto err;
for (i = 0; i < count; i++) {
add->map_ops[i].handle = -1;
add->unmap_ops[i].handle = -1;
add->kmap_ops[i].handle = -1;
+ add->kunmap_ops[i].handle = -1;
}
add->index = 0;
@@ -216,9 +222,9 @@ static void gntdev_put_map(struct gntdev_priv *priv, struct grant_map *map)
}
if (populate_freeable_maps && priv) {
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
list_del(&map->next);
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
}
if (map->pages && !use_ptemod)
@@ -239,6 +245,14 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
BUG_ON(pgnr >= map->count);
pte_maddr = arbitrary_virt_to_machine(pte).maddr;
+ /*
+ * Set the PTE as special to force get_user_pages_fast() fall
+ * back to the slow path. If this is not supported as part of
+ * the grant map, it will be done afterwards.
+ */
+ if (xen_feature(XENFEAT_gnttab_map_avail_bits))
+ flags |= (1 << _GNTMAP_guest_avail0);
+
gnttab_set_map_op(&map->map_ops[pgnr], pte_maddr, flags,
map->grants[pgnr].ref,
map->grants[pgnr].domid);
@@ -247,6 +261,15 @@ static int find_grant_ptes(pte_t *pte, pgtable_t token,
return 0;
}
+#ifdef CONFIG_X86
+static int set_grant_ptes_as_special(pte_t *pte, pgtable_t token,
+ unsigned long addr, void *data)
+{
+ set_pte_at(current->mm, addr, pte, pte_mkspecial(*pte));
+ return 0;
+}
+#endif
+
static int map_grant_pages(struct grant_map *map)
{
int i, err = 0;
@@ -280,6 +303,8 @@ static int map_grant_pages(struct grant_map *map)
map->flags | GNTMAP_host_map,
map->grants[i].ref,
map->grants[i].domid);
+ gnttab_set_unmap_op(&map->kunmap_ops[i], address,
+ map->flags | GNTMAP_host_map, -1);
}
}
@@ -290,20 +315,42 @@ static int map_grant_pages(struct grant_map *map)
return err;
for (i = 0; i < map->count; i++) {
- if (map->map_ops[i].status)
+ if (map->map_ops[i].status) {
err = -EINVAL;
- else {
- BUG_ON(map->map_ops[i].handle == -1);
- map->unmap_ops[i].handle = map->map_ops[i].handle;
- pr_debug("map handle=%d\n", map->map_ops[i].handle);
+ continue;
}
+
+ map->unmap_ops[i].handle = map->map_ops[i].handle;
+ if (use_ptemod)
+ map->kunmap_ops[i].handle = map->kmap_ops[i].handle;
}
return err;
}
+struct unmap_grant_pages_callback_data
+{
+ struct completion completion;
+ int result;
+};
+
+static void unmap_grant_callback(int result,
+ struct gntab_unmap_queue_data *data)
+{
+ struct unmap_grant_pages_callback_data* d = data->data;
+
+ d->result = result;
+ complete(&d->completion);
+}
+
static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
{
int i, err = 0;
+ struct gntab_unmap_queue_data unmap_data;
+ struct unmap_grant_pages_callback_data data;
+
+ init_completion(&data.completion);
+ unmap_data.data = &data;
+ unmap_data.done= &unmap_grant_callback;
if (map->notify.flags & UNMAP_NOTIFY_CLEAR_BYTE) {
int pgno = (map->notify.addr >> PAGE_SHIFT);
@@ -315,11 +362,16 @@ static int __unmap_grant_pages(struct grant_map *map, int offset, int pages)
}
}
- err = gnttab_unmap_refs(map->unmap_ops + offset,
- use_ptemod ? map->kmap_ops + offset : NULL, map->pages + offset,
- pages);
- if (err)
- return err;
+ unmap_data.unmap_ops = map->unmap_ops + offset;
+ unmap_data.kunmap_ops = use_ptemod ? map->kunmap_ops + offset : NULL;
+ unmap_data.pages = map->pages + offset;
+ unmap_data.count = pages;
+
+ gnttab_unmap_refs_async(&unmap_data);
+
+ wait_for_completion(&data.completion);
+ if (data.result)
+ return data.result;
for (i = 0; i < pages; i++) {
if (map->unmap_ops[offset+i].status)
@@ -387,17 +439,26 @@ static void gntdev_vma_close(struct vm_area_struct *vma)
* not do any unmapping, since that has been done prior to
* closing the vma, but it may still iterate the unmap_ops list.
*/
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
map->vma = NULL;
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
}
vma->vm_private_data = NULL;
gntdev_put_map(priv, map);
}
+static struct page *gntdev_vma_find_special_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ struct grant_map *map = vma->vm_private_data;
+
+ return map->pages[(addr - map->pages_vm_start) >> PAGE_SHIFT];
+}
+
static struct vm_operations_struct gntdev_vmops = {
.open = gntdev_vma_open,
.close = gntdev_vma_close,
+ .find_special_page = gntdev_vma_find_special_page,
};
/* ------------------------------------------------------------------ */
@@ -433,14 +494,14 @@ static void mn_invl_range_start(struct mmu_notifier *mn,
struct gntdev_priv *priv = container_of(mn, struct gntdev_priv, mn);
struct grant_map *map;
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
list_for_each_entry(map, &priv->maps, next) {
unmap_if_in_range(map, start, end);
}
list_for_each_entry(map, &priv->freeable_maps, next) {
unmap_if_in_range(map, start, end);
}
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
}
static void mn_invl_page(struct mmu_notifier *mn,
@@ -457,7 +518,7 @@ static void mn_release(struct mmu_notifier *mn,
struct grant_map *map;
int err;
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
list_for_each_entry(map, &priv->maps, next) {
if (!map->vma)
continue;
@@ -476,7 +537,7 @@ static void mn_release(struct mmu_notifier *mn,
err = unmap_grant_pages(map, /* offset */ 0, map->count);
WARN_ON(err);
}
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
}
static struct mmu_notifier_ops gntdev_mmu_ops = {
@@ -498,7 +559,7 @@ static int gntdev_open(struct inode *inode, struct file *flip)
INIT_LIST_HEAD(&priv->maps);
INIT_LIST_HEAD(&priv->freeable_maps);
- spin_lock_init(&priv->lock);
+ mutex_init(&priv->lock);
if (use_ptemod) {
priv->mm = get_task_mm(current);
@@ -572,10 +633,10 @@ static long gntdev_ioctl_map_grant_ref(struct gntdev_priv *priv,
return -EFAULT;
}
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
gntdev_add_map(priv, map);
op.index = map->index << PAGE_SHIFT;
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
if (copy_to_user(u, &op, sizeof(op)) != 0)
return -EFAULT;
@@ -594,7 +655,7 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
return -EFAULT;
pr_debug("priv %p, del %d+%d\n", priv, (int)op.index, (int)op.count);
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
map = gntdev_find_map_index(priv, op.index >> PAGE_SHIFT, op.count);
if (map) {
list_del(&map->next);
@@ -602,7 +663,7 @@ static long gntdev_ioctl_unmap_grant_ref(struct gntdev_priv *priv,
list_add_tail(&map->next, &priv->freeable_maps);
err = 0;
}
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
if (map)
gntdev_put_map(priv, map);
return err;
@@ -670,7 +731,7 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
out_flags = op.action;
out_event = op.event_channel_port;
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
list_for_each_entry(map, &priv->maps, next) {
uint64_t begin = map->index << PAGE_SHIFT;
@@ -698,7 +759,7 @@ static long gntdev_ioctl_notify(struct gntdev_priv *priv, void __user *u)
rc = 0;
unlock_out:
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
/* Drop the reference to the event channel we did not save in the map */
if (out_flags & UNMAP_NOTIFY_SEND_EVENT)
@@ -748,7 +809,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
pr_debug("map %d+%d at %lx (pgoff %lx)\n",
index, count, vma->vm_start, vma->vm_pgoff);
- spin_lock(&priv->lock);
+ mutex_lock(&priv->lock);
map = gntdev_find_map_index(priv, index, count);
if (!map)
goto unlock_out;
@@ -783,7 +844,7 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
map->flags |= GNTMAP_readonly;
}
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
if (use_ptemod) {
err = apply_to_page_range(vma->vm_mm, vma->vm_start,
@@ -806,16 +867,34 @@ static int gntdev_mmap(struct file *flip, struct vm_area_struct *vma)
if (err)
goto out_put_map;
}
+ } else {
+#ifdef CONFIG_X86
+ /*
+ * If the PTEs were not made special by the grant map
+ * hypercall, do so here.
+ *
+ * This is racy since the mapping is already visible
+ * to userspace but userspace should be well-behaved
+ * enough to not touch it until the mmap() call
+ * returns.
+ */
+ if (!xen_feature(XENFEAT_gnttab_map_avail_bits)) {
+ apply_to_page_range(vma->vm_mm, vma->vm_start,
+ vma->vm_end - vma->vm_start,
+ set_grant_ptes_as_special, NULL);
+ }
+#endif
+ map->pages_vm_start = vma->vm_start;
}
return 0;
unlock_out:
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
return err;
out_unlock_put:
- spin_unlock(&priv->lock);
+ mutex_unlock(&priv->lock);
out_put_map:
if (use_ptemod)
map->vma = NULL;
diff --git a/drivers/xen/grant-table.c b/drivers/xen/grant-table.c
index 7786291ba229..17972fbacddc 100644
--- a/drivers/xen/grant-table.c
+++ b/drivers/xen/grant-table.c
@@ -42,6 +42,7 @@
#include <linux/io.h>
#include <linux/delay.h>
#include <linux/hardirq.h>
+#include <linux/workqueue.h>
#include <xen/xen.h>
#include <xen/interface/xen.h>
@@ -50,6 +51,7 @@
#include <xen/interface/memory.h>
#include <xen/hvc-console.h>
#include <xen/swiotlb-xen.h>
+#include <xen/balloon.h>
#include <asm/xen/hypercall.h>
#include <asm/xen/interface.h>
@@ -671,6 +673,59 @@ void gnttab_free_auto_xlat_frames(void)
}
EXPORT_SYMBOL_GPL(gnttab_free_auto_xlat_frames);
+/**
+ * gnttab_alloc_pages - alloc pages suitable for grant mapping into
+ * @nr_pages: number of pages to alloc
+ * @pages: returns the pages
+ */
+int gnttab_alloc_pages(int nr_pages, struct page **pages)
+{
+ int i;
+ int ret;
+
+ ret = alloc_xenballooned_pages(nr_pages, pages, false);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < nr_pages; i++) {
+#if BITS_PER_LONG < 64
+ struct xen_page_foreign *foreign;
+
+ foreign = kzalloc(sizeof(*foreign), GFP_KERNEL);
+ if (!foreign) {
+ gnttab_free_pages(nr_pages, pages);
+ return -ENOMEM;
+ }
+ set_page_private(pages[i], (unsigned long)foreign);
+#endif
+ SetPagePrivate(pages[i]);
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(gnttab_alloc_pages);
+
+/**
+ * gnttab_free_pages - free pages allocated by gnttab_alloc_pages()
+ * @nr_pages; number of pages to free
+ * @pages: the pages
+ */
+void gnttab_free_pages(int nr_pages, struct page **pages)
+{
+ int i;
+
+ for (i = 0; i < nr_pages; i++) {
+ if (PagePrivate(pages[i])) {
+#if BITS_PER_LONG < 64
+ kfree((void *)page_private(pages[i]));
+#endif
+ ClearPagePrivate(pages[i]);
+ }
+ }
+ free_xenballooned_pages(nr_pages, pages);
+}
+EXPORT_SYMBOL(gnttab_free_pages);
+
/* Handling of paged out grant targets (GNTST_eagain) */
#define MAX_DELAY 256
static inline void
@@ -727,30 +782,87 @@ int gnttab_map_refs(struct gnttab_map_grant_ref *map_ops,
if (ret)
return ret;
- /* Retry eagain maps */
- for (i = 0; i < count; i++)
+ for (i = 0; i < count; i++) {
+ /* Retry eagain maps */
if (map_ops[i].status == GNTST_eagain)
gnttab_retry_eagain_gop(GNTTABOP_map_grant_ref, map_ops + i,
&map_ops[i].status, __func__);
+ if (map_ops[i].status == GNTST_okay) {
+ struct xen_page_foreign *foreign;
+
+ SetPageForeign(pages[i]);
+ foreign = xen_page_foreign(pages[i]);
+ foreign->domid = map_ops[i].dom;
+ foreign->gref = map_ops[i].ref;
+ }
+ }
+
return set_foreign_p2m_mapping(map_ops, kmap_ops, pages, count);
}
EXPORT_SYMBOL_GPL(gnttab_map_refs);
int gnttab_unmap_refs(struct gnttab_unmap_grant_ref *unmap_ops,
- struct gnttab_map_grant_ref *kmap_ops,
+ struct gnttab_unmap_grant_ref *kunmap_ops,
struct page **pages, unsigned int count)
{
+ unsigned int i;
int ret;
ret = HYPERVISOR_grant_table_op(GNTTABOP_unmap_grant_ref, unmap_ops, count);
if (ret)
return ret;
- return clear_foreign_p2m_mapping(unmap_ops, kmap_ops, pages, count);
+ for (i = 0; i < count; i++)
+ ClearPageForeign(pages[i]);
+
+ return clear_foreign_p2m_mapping(unmap_ops, kunmap_ops, pages, count);
}
EXPORT_SYMBOL_GPL(gnttab_unmap_refs);
+#define GNTTAB_UNMAP_REFS_DELAY 5
+
+static void __gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item);
+
+static void gnttab_unmap_work(struct work_struct *work)
+{
+ struct gntab_unmap_queue_data
+ *unmap_data = container_of(work,
+ struct gntab_unmap_queue_data,
+ gnttab_work.work);
+ if (unmap_data->age != UINT_MAX)
+ unmap_data->age++;
+ __gnttab_unmap_refs_async(unmap_data);
+}
+
+static void __gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
+{
+ int ret;
+ int pc;
+
+ for (pc = 0; pc < item->count; pc++) {
+ if (page_count(item->pages[pc]) > 1) {
+ unsigned long delay = GNTTAB_UNMAP_REFS_DELAY * (item->age + 1);
+ schedule_delayed_work(&item->gnttab_work,
+ msecs_to_jiffies(delay));
+ return;
+ }
+ }
+
+ ret = gnttab_unmap_refs(item->unmap_ops, item->kunmap_ops,
+ item->pages, item->count);
+ item->done(ret, item);
+}
+
+void gnttab_unmap_refs_async(struct gntab_unmap_queue_data* item)
+{
+ INIT_DELAYED_WORK(&item->gnttab_work, gnttab_unmap_work);
+ item->age = 0;
+
+ __gnttab_unmap_refs_async(item);
+}
+EXPORT_SYMBOL_GPL(gnttab_unmap_refs_async);
+
static int gnttab_map_frames_v1(xen_pfn_t *frames, unsigned int nr_gframes)
{
int rc;
diff --git a/drivers/xen/manage.c b/drivers/xen/manage.c
index f8bb36f9d9ce..bf1940706422 100644
--- a/drivers/xen/manage.c
+++ b/drivers/xen/manage.c
@@ -105,10 +105,16 @@ static void do_suspend(void)
err = freeze_processes();
if (err) {
- pr_err("%s: freeze failed %d\n", __func__, err);
+ pr_err("%s: freeze processes failed %d\n", __func__, err);
goto out;
}
+ err = freeze_kernel_threads();
+ if (err) {
+ pr_err("%s: freeze kernel threads failed %d\n", __func__, err);
+ goto out_thaw;
+ }
+
err = dpm_suspend_start(PMSG_FREEZE);
if (err) {
pr_err("%s: dpm_suspend_start %d\n", __func__, err);
diff --git a/drivers/xen/preempt.c b/drivers/xen/preempt.c
new file mode 100644
index 000000000000..a1800c150839
--- /dev/null
+++ b/drivers/xen/preempt.c
@@ -0,0 +1,44 @@
+/*
+ * Preemptible hypercalls
+ *
+ * Copyright (C) 2014 Citrix Systems R&D ltd.
+ *
+ * This source code is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ */
+
+#include <linux/sched.h>
+#include <xen/xen-ops.h>
+
+#ifndef CONFIG_PREEMPT
+
+/*
+ * Some hypercalls issued by the toolstack can take many 10s of
+ * seconds. Allow tasks running hypercalls via the privcmd driver to
+ * be voluntarily preempted even if full kernel preemption is
+ * disabled.
+ *
+ * Such preemptible hypercalls are bracketed by
+ * xen_preemptible_hcall_begin() and xen_preemptible_hcall_end()
+ * calls.
+ */
+
+DEFINE_PER_CPU(bool, xen_in_preemptible_hcall);
+EXPORT_SYMBOL_GPL(xen_in_preemptible_hcall);
+
+asmlinkage __visible void xen_maybe_preempt_hcall(void)
+{
+ if (unlikely(__this_cpu_read(xen_in_preemptible_hcall)
+ && should_resched())) {
+ /*
+ * Clear flag as we may be rescheduled on a different
+ * cpu.
+ */
+ __this_cpu_write(xen_in_preemptible_hcall, false);
+ _cond_resched();
+ __this_cpu_write(xen_in_preemptible_hcall, true);
+ }
+}
+#endif /* CONFIG_PREEMPT */
diff --git a/drivers/xen/privcmd.c b/drivers/xen/privcmd.c
index 569a13b9e856..59ac71c4a043 100644
--- a/drivers/xen/privcmd.c
+++ b/drivers/xen/privcmd.c
@@ -56,10 +56,12 @@ static long privcmd_ioctl_hypercall(void __user *udata)
if (copy_from_user(&hypercall, udata, sizeof(hypercall)))
return -EFAULT;
+ xen_preemptible_hcall_begin();
ret = privcmd_call(hypercall.op,
hypercall.arg[0], hypercall.arg[1],
hypercall.arg[2], hypercall.arg[3],
hypercall.arg[4]);
+ xen_preemptible_hcall_end();
return ret;
}
diff --git a/drivers/xen/tmem.c b/drivers/xen/tmem.c
index 83b5c53bec6b..8a65423bc696 100644
--- a/drivers/xen/tmem.c
+++ b/drivers/xen/tmem.c
@@ -374,7 +374,7 @@ static struct frontswap_ops tmem_frontswap_ops = {
};
#endif
-static int xen_tmem_init(void)
+static int __init xen_tmem_init(void)
{
if (!xen_domain())
return 0;
diff --git a/drivers/xen/xen-acpi-memhotplug.c b/drivers/xen/xen-acpi-memhotplug.c
index 34e40b733f9a..4fc886cd5586 100644
--- a/drivers/xen/xen-acpi-memhotplug.c
+++ b/drivers/xen/xen-acpi-memhotplug.c
@@ -117,8 +117,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
list_for_each_entry(info, &mem_device->res_list, list) {
if ((info->caching == address64.info.mem.caching) &&
(info->write_protect == address64.info.mem.write_protect) &&
- (info->start_addr + info->length == address64.minimum)) {
- info->length += address64.address_length;
+ (info->start_addr + info->length == address64.address.minimum)) {
+ info->length += address64.address.address_length;
return AE_OK;
}
}
@@ -130,8 +130,8 @@ acpi_memory_get_resource(struct acpi_resource *resource, void *context)
INIT_LIST_HEAD(&new->list);
new->caching = address64.info.mem.caching;
new->write_protect = address64.info.mem.write_protect;
- new->start_addr = address64.minimum;
- new->length = address64.address_length;
+ new->start_addr = address64.address.minimum;
+ new->length = address64.address.address_length;
list_add_tail(&new->list, &mem_device->res_list);
return AE_OK;
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index e999496eda3e..9faca6a60bb0 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -47,6 +47,7 @@
#include <generated/utsrelease.h>
+#include <scsi/scsi.h>
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_eh.h>
#include <scsi/scsi_tcq.h>
@@ -227,7 +228,7 @@ static void put_free_pages(struct page **page, int num)
return;
if (i > scsiback_max_buffer_pages) {
n = min(num, i - scsiback_max_buffer_pages);
- free_xenballooned_pages(n, page + num - n);
+ gnttab_free_pages(n, page + num - n);
n = num - n;
}
spin_lock_irqsave(&free_pages_lock, flags);
@@ -244,7 +245,7 @@ static int get_free_page(struct page **page)
spin_lock_irqsave(&free_pages_lock, flags);
if (list_empty(&scsiback_free_pages)) {
spin_unlock_irqrestore(&free_pages_lock, flags);
- return alloc_xenballooned_pages(1, page, false);
+ return gnttab_alloc_pages(1, page);
}
page[0] = list_first_entry(&scsiback_free_pages, struct page, lru);
list_del(&page[0]->lru);
@@ -708,12 +709,11 @@ static int prepare_pending_reqs(struct vscsibk_info *info,
static int scsiback_do_cmd_fn(struct vscsibk_info *info)
{
struct vscsiif_back_ring *ring = &info->ring;
- struct vscsiif_request *ring_req;
+ struct vscsiif_request ring_req;
struct vscsibk_pend *pending_req;
RING_IDX rc, rp;
int err, more_to_do;
uint32_t result;
- uint8_t act;
rc = ring->req_cons;
rp = ring->sring->req_prod;
@@ -734,11 +734,10 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
if (!pending_req)
return 1;
- ring_req = RING_GET_REQUEST(ring, rc);
+ ring_req = *RING_GET_REQUEST(ring, rc);
ring->req_cons = ++rc;
- act = ring_req->act;
- err = prepare_pending_reqs(info, ring_req, pending_req);
+ err = prepare_pending_reqs(info, &ring_req, pending_req);
if (err) {
switch (err) {
case -ENODEV:
@@ -754,9 +753,9 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
return 1;
}
- switch (act) {
+ switch (ring_req.act) {
case VSCSIIF_ACT_SCSI_CDB:
- if (scsiback_gnttab_data_map(ring_req, pending_req)) {
+ if (scsiback_gnttab_data_map(&ring_req, pending_req)) {
scsiback_fast_flush_area(pending_req);
scsiback_do_resp_with_sense(NULL,
DRIVER_ERROR << 24, 0, pending_req);
@@ -767,7 +766,7 @@ static int scsiback_do_cmd_fn(struct vscsibk_info *info)
break;
case VSCSIIF_ACT_SCSI_ABORT:
scsiback_device_action(pending_req, TMR_ABORT_TASK,
- ring_req->ref_rqid);
+ ring_req.ref_rqid);
break;
case VSCSIIF_ACT_SCSI_RESET:
scsiback_device_action(pending_req, TMR_LUN_RESET, 0);
@@ -2106,7 +2105,7 @@ static void __exit scsiback_exit(void)
while (free_pages_num) {
if (get_free_page(&page))
BUG();
- free_xenballooned_pages(1, &page);
+ gnttab_free_pages(1, &page);
}
scsiback_deregister_configfs();
xenbus_unregister_driver(&scsiback_driver);
diff --git a/drivers/xen/xenbus/xenbus_dev_frontend.c b/drivers/xen/xenbus/xenbus_dev_frontend.c
index 85534ea63555..9433e46518c8 100644
--- a/drivers/xen/xenbus/xenbus_dev_frontend.c
+++ b/drivers/xen/xenbus/xenbus_dev_frontend.c
@@ -326,10 +326,13 @@ static int xenbus_write_transaction(unsigned msg_type,
}
if (msg_type == XS_TRANSACTION_START) {
- trans->handle.id = simple_strtoul(reply, NULL, 0);
-
- list_add(&trans->list, &u->transactions);
- } else if (msg_type == XS_TRANSACTION_END) {
+ if (u->u.msg.type == XS_ERROR)
+ kfree(trans);
+ else {
+ trans->handle.id = simple_strtoul(reply, NULL, 0);
+ list_add(&trans->list, &u->transactions);
+ }
+ } else if (u->u.msg.type == XS_TRANSACTION_END) {
list_for_each_entry(trans, &u->transactions, list)
if (trans->handle.id == u->u.msg.tx_id)
break;